summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 16:23:34 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:37:21 +0000
commit38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch)
treec4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/third_party/blink
parente684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff)
downloadqtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink')
-rw-r--r--chromium/third_party/blink/API_OWNERS2
-rw-r--r--chromium/third_party/blink/OWNERS3
-rw-r--r--chromium/third_party/blink/common/BUILD.gn16
-rw-r--r--chromium/third_party/blink/common/DEPS2
-rw-r--r--chromium/third_party/blink/common/client_hints/client_hints.cc6
-rw-r--r--chromium/third_party/blink/common/download/download_stats.cc53
-rw-r--r--chromium/third_party/blink/common/feature_policy/feature_policy.cc20
-rw-r--r--chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.cc1
-rw-r--r--chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.h4
-rw-r--r--chromium/third_party/blink/common/feature_policy/feature_policy_unittest.cc89
-rw-r--r--chromium/third_party/blink/common/features.cc70
-rw-r--r--chromium/third_party/blink/common/font_unique_name_lookup/OWNERS3
-rw-r--r--chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc38
-rw-r--r--chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher_unittest.cc49
-rw-r--r--chromium/third_party/blink/common/indexeddb/indexed_db_default_mojom_traits.cc77
-rw-r--r--chromium/third_party/blink/common/indexeddb/indexeddb_key.cc47
-rw-r--r--chromium/third_party/blink/common/indexeddb/indexeddb_key_path.cc21
-rw-r--r--chromium/third_party/blink/common/indexeddb/indexeddb_key_unittest.cc8
-rw-r--r--chromium/third_party/blink/common/loader/OWNERS5
-rw-r--r--chromium/third_party/blink/common/loader/url_loader_factory_bundle.cc144
-rw-r--r--chromium/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc67
-rw-r--r--chromium/third_party/blink/common/mediastream/OWNERS8
-rw-r--r--chromium/third_party/blink/common/mediastream/media_devices.cc50
-rw-r--r--chromium/third_party/blink/common/mediastream/media_devices_mojom_traits.cc103
-rw-r--r--chromium/third_party/blink/common/mediastream/media_devices_unittest.cc22
-rw-r--r--chromium/third_party/blink/common/mediastream/media_stream_controls.cc28
-rw-r--r--chromium/third_party/blink/common/mediastream/media_stream_mojom_traits.cc247
-rw-r--r--chromium/third_party/blink/common/mediastream/media_stream_request.cc140
-rw-r--r--chromium/third_party/blink/common/mime_util/mime_util.cc13
-rw-r--r--chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc14
-rw-r--r--chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc8
-rw-r--r--chromium/third_party/blink/common/service_worker/service_worker_utils.cc24
-rw-r--r--chromium/third_party/blink/manual_tests/array-out-of-memory.html2
-rw-r--r--chromium/third_party/blink/manual_tests/autoscroll.html2
-rw-r--r--chromium/third_party/blink/manual_tests/harfbuzz-mouse-selection-crash.html2
-rw-r--r--chromium/third_party/blink/manual_tests/input-starved-by-timers.html2
-rw-r--r--chromium/third_party/blink/manual_tests/select_hr.html2
-rw-r--r--chromium/third_party/blink/public/BUILD.gn72
-rw-r--r--chromium/third_party/blink/public/OWNERS1
-rw-r--r--chromium/third_party/blink/public/blink_resources.grd13
-rw-r--r--chromium/third_party/blink/public/blink_typemaps.gni1
-rw-r--r--chromium/third_party/blink/public/common/BUILD.gn19
-rw-r--r--chromium/third_party/blink/public/common/DEPS3
-rw-r--r--chromium/third_party/blink/public/common/download/download_stats.h67
-rw-r--r--chromium/third_party/blink/public/common/feature_policy/feature_policy.h9
-rw-r--r--chromium/third_party/blink/public/common/features.h18
-rw-r--r--chromium/third_party/blink/public/common/fetch/OWNERS9
-rw-r--r--chromium/third_party/blink/public/common/fetch/fetch_api_request_headers.typemap12
-rw-r--r--chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_map.h25
-rw-r--r--chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_mojom_traits.h33
-rw-r--r--chromium/third_party/blink/public/common/font_unique_name_lookup/OWNERS6
-rw-r--r--chromium/third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.proto26
-rw-r--r--chromium/third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h26
-rw-r--r--chromium/third_party/blink/public/common/indexeddb/indexeddb_key.h20
-rw-r--r--chromium/third_party/blink/public/common/indexeddb/indexeddb_key_path.h7
-rw-r--r--chromium/third_party/blink/public/common/indexeddb/indexeddb_key_range.h4
-rw-r--r--chromium/third_party/blink/public/common/indexeddb/web_idb_types.h19
-rw-r--r--chromium/third_party/blink/public/common/loader/OWNERS7
-rw-r--r--chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.h159
-rw-r--r--chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.typemap11
-rw-r--r--chromium/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h47
-rw-r--r--chromium/third_party/blink/public/common/manifest/manifest.h5
-rw-r--r--chromium/third_party/blink/public/common/mediastream/OWNERS10
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_devices.h59
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_devices.typemap20
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_devices_mojom_traits.h50
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_stream.typemap23
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_stream_controls.h60
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h133
-rw-r--r--chromium/third_party/blink/public/common/mediastream/media_stream_request.h167
-rw-r--r--chromium/third_party/blink/public/common/service_worker/service_worker_utils.h29
-rw-r--r--chromium/third_party/blink/public/mojom/BUILD.gn68
-rw-r--r--chromium/third_party/blink/public/mojom/ad_tagging/OWNERS (renamed from chromium/third_party/blink/public/platform/modules/mediastream/OWNERS)0
-rw-r--r--chromium/third_party/blink/public/mojom/ad_tagging/ad_frame.mojom16
-rw-r--r--chromium/third_party/blink/public/mojom/appcache/OWNERS8
-rw-r--r--chromium/third_party/blink/public/mojom/appcache/appcache.mojom141
-rw-r--r--chromium/third_party/blink/public/mojom/appcache/appcache_info.mojom34
-rw-r--r--chromium/third_party/blink/public/mojom/background_fetch/OWNERS7
-rw-r--r--chromium/third_party/blink/public/mojom/background_fetch/background_fetch.mojom (renamed from chromium/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom)18
-rw-r--r--chromium/third_party/blink/public/mojom/cache_storage/OWNERS (renamed from chromium/third_party/blink/public/platform/modules/cache_storage/OWNERS)0
-rw-r--r--chromium/third_party/blink/public/mojom/cache_storage/cache_storage.mojom (renamed from chromium/third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom)9
-rw-r--r--chromium/third_party/blink/public/mojom/contacts/OWNERS8
-rw-r--r--chromium/third_party/blink/public/mojom/contacts/contacts_manager.mojom23
-rw-r--r--chromium/third_party/blink/public/mojom/csp/OWNERS7
-rw-r--r--chromium/third_party/blink/public/mojom/csp/README.md1
-rw-r--r--chromium/third_party/blink/public/mojom/csp/content_security_policy.mojom (renamed from chromium/third_party/blink/public/platform/content_security_policy.mojom)2
-rw-r--r--chromium/third_party/blink/public/mojom/devtools/OWNERS7
-rw-r--r--chromium/third_party/blink/public/mojom/devtools/README.md1
-rw-r--r--chromium/third_party/blink/public/mojom/devtools/console_message.mojom14
-rw-r--r--chromium/third_party/blink/public/mojom/devtools/devtools_agent.mojom (renamed from chromium/third_party/blink/public/web/devtools_agent.mojom)2
-rw-r--r--chromium/third_party/blink/public/mojom/dwrite_font_proxy/OWNERS6
-rw-r--r--chromium/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom77
-rw-r--r--chromium/third_party/blink/public/mojom/feature_policy/feature_policy.mojom5
-rw-r--r--chromium/third_party/blink/public/mojom/fetch/fetch_api_request.mojom (renamed from chromium/third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom)34
-rw-r--r--chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom7
-rw-r--r--chromium/third_party/blink/public/mojom/filesystem/file_system.mojom5
-rw-r--r--chromium/third_party/blink/public/mojom/frame/document_interface_broker.mojom13
-rw-r--r--chromium/third_party/blink/public/mojom/frame/frame_host_test_interface.mojom23
-rw-r--r--chromium/third_party/blink/public/mojom/indexeddb/indexeddb.mojom69
-rw-r--r--chromium/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom39
-rw-r--r--chromium/third_party/blink/public/mojom/manifest/manifest.mojom4
-rw-r--r--chromium/third_party/blink/public/mojom/mediastream/OWNERS8
-rw-r--r--chromium/third_party/blink/public/mojom/mediastream/media_devices.mojom (renamed from chromium/third_party/blink/public/platform/modules/mediastream/media_devices.mojom)0
-rw-r--r--chromium/third_party/blink/public/mojom/mediastream/media_stream.mojom127
-rw-r--r--chromium/third_party/blink/public/mojom/page/page_visibility_state.mojom13
-rw-r--r--chromium/third_party/blink/public/mojom/payments/payment_request.mojom25
-rw-r--r--chromium/third_party/blink/public/mojom/portal/portal.mojom5
-rw-r--r--chromium/third_party/blink/public/mojom/serial/OWNERS6
-rw-r--r--chromium/third_party/blink/public/mojom/serial/serial.mojom34
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom91
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom24
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/service_worker.mojom162
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/service_worker_client.mojom15
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/service_worker_container.mojom148
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom136
-rw-r--r--chromium/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom7
-rw-r--r--chromium/third_party/blink/public/mojom/usb/BUILD.gn4
-rw-r--r--chromium/third_party/blink/public/mojom/usb/web_usb_service.mojom3
-rw-r--r--chromium/third_party/blink/public/mojom/wake_lock/OWNERS (renamed from chromium/third_party/blink/public/platform/modules/wake_lock/OWNERS)0
-rw-r--r--chromium/third_party/blink/public/mojom/wake_lock/wake_lock.mojom18
-rw-r--r--chromium/third_party/blink/public/mojom/worker/OWNERS (renamed from chromium/third_party/blink/public/mojom/shared_worker/OWNERS)0
-rw-r--r--chromium/third_party/blink/public/mojom/worker/README.md1
-rw-r--r--chromium/third_party/blink/public/mojom/worker/dedicated_worker_factory.mojom (renamed from chromium/third_party/blink/public/platform/dedicated_worker_factory.mojom)0
-rw-r--r--chromium/third_party/blink/public/mojom/worker/shared_worker.mojom24
-rw-r--r--chromium/third_party/blink/public/mojom/worker/shared_worker_client.mojom27
-rw-r--r--chromium/third_party/blink/public/mojom/worker/shared_worker_connector.mojom26
-rw-r--r--chromium/third_party/blink/public/mojom/worker/shared_worker_creation_context_type.mojom (renamed from chromium/third_party/blink/public/mojom/shared_worker/shared_worker_creation_context_type.mojom)0
-rw-r--r--chromium/third_party/blink/public/mojom/worker/shared_worker_host.mojom33
-rw-r--r--chromium/third_party/blink/public/mojom/worker/shared_worker_info.mojom21
-rw-r--r--chromium/third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom (renamed from chromium/third_party/blink/public/web/worker_content_settings_proxy.mojom)0
-rw-r--r--chromium/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom (renamed from chromium/third_party/blink/public/mojom/shared_worker/worker_main_script_load_params.mojom)0
-rw-r--r--chromium/third_party/blink/public/platform/OWNERS9
-rw-r--r--chromium/third_party/blink/public/platform/content_security_policy.typemap13
-rw-r--r--chromium/third_party/blink/public/platform/content_security_policy_struct_traits.h46
-rw-r--r--chromium/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h2
-rw-r--r--chromium/third_party/blink/public/platform/modules/badging/badging.mojom17
-rw-r--r--chromium/third_party/blink/public/platform/modules/bluetooth/OWNERS3
-rw-r--r--chromium/third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom39
-rw-r--r--chromium/third_party/blink/public/platform/modules/fetch/OWNERS11
-rw-r--r--chromium/third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom11
-rw-r--r--chromium/third_party/blink/public/platform/modules/idle/OWNERS4
-rw-r--r--chromium/third_party/blink/public/platform/modules/idle/idle_manager.mojom27
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h76
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h74
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key.h176
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h77
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h83
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h20
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h43
-rw-r--r--chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_value.h65
-rw-r--r--chromium/third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom4
-rw-r--r--chromium/third_party/blink/public/platform/modules/locks/lock_manager.mojom10
-rw-r--r--chromium/third_party/blink/public/platform/modules/mediasession/media_session.mojom19
-rw-r--r--chromium/third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h101
-rw-r--r--chromium/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h32
-rw-r--r--chromium/third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h50
-rw-r--r--chromium/third_party/blink/public/platform/modules/notifications/web_notification_data.h10
-rw-r--r--chromium/third_party/blink/public/platform/modules/permissions/permission.mojom1
-rw-r--r--chromium/third_party/blink/public/platform/modules/presentation/OWNERS1
-rw-r--r--chromium/third_party/blink/public/platform/modules/presentation/web_presentation_client.h26
-rw-r--r--chromium/third_party/blink/public/platform/modules/presentation/web_presentation_receiver.h34
-rw-r--r--chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h17
-rw-r--r--chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h3
-rw-r--r--chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h3
-rw-r--r--chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h14
-rw-r--r--chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h5
-rw-r--r--chromium/third_party/blink/public/platform/modules/webmidi/DEPS6
-rw-r--r--chromium/third_party/blink/public/platform/modules/webmidi/OWNERS6
-rw-r--r--chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h56
-rw-r--r--chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor_client.h74
-rw-r--r--chromium/third_party/blink/public/platform/oom_intervention.mojom6
-rw-r--r--chromium/third_party/blink/public/platform/platform.h18
-rw-r--r--chromium/third_party/blink/public/platform/task_type.h14
-rw-r--r--chromium/third_party/blink/public/platform/web_application_cache_host.h41
-rw-r--r--chromium/third_party/blink/public/platform/web_application_cache_host_client.h5
-rw-r--r--chromium/third_party/blink/public/platform/web_color_scheme.h19
-rw-r--r--chromium/third_party/blink/public/platform/web_content_decryption_module_access.h4
-rw-r--r--chromium/third_party/blink/public/platform/web_content_security_policy.h8
-rw-r--r--chromium/third_party/blink/public/platform/web_content_security_policy_struct.h5
-rw-r--r--chromium/third_party/blink/public/platform/web_document_subresource_filter.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_feature.mojom141
-rw-r--r--chromium/third_party/blink/public/platform/web_focus_type.h5
-rw-r--r--chromium/third_party/blink/public/platform/web_font_render_style.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_gesture_event.h5
-rw-r--r--chromium/third_party/blink/public/platform/web_insecure_request_policy.h3
-rw-r--r--chromium/third_party/blink/public/platform/web_isolated_world_info.h45
-rw-r--r--chromium/third_party/blink/public/platform/web_layer_tree_view.h27
-rw-r--r--chromium/third_party/blink/public/platform/web_localized_string.h4
-rw-r--r--chromium/third_party/blink/public/platform/web_media_player.h4
-rw-r--r--chromium/third_party/blink/public/platform/web_media_stream_source.h29
-rw-r--r--chromium/third_party/blink/public/platform/web_media_stream_track.h20
-rw-r--r--chromium/third_party/blink/public/platform/web_navigation_body_loader.h61
-rw-r--r--chromium/third_party/blink/public/platform/web_resource_timing_info.h5
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_certificate_generator.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler.h27
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_rtp_contributing_source.h29
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_rtp_receiver.h7
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_rtp_sender.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_rtp_source.h33
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_rtp_transceiver.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_rtc_void_request.h2
-rw-r--r--chromium/third_party/blink/public/platform/web_runtime_features.h16
-rw-r--r--chromium/third_party/blink/public/platform/web_surface_layer_bridge.h6
-rw-r--r--chromium/third_party/blink/public/platform/web_url_load_timing.h5
-rw-r--r--chromium/third_party/blink/public/platform/web_url_loader_client.h10
-rw-r--r--chromium/third_party/blink/public/platform/web_url_request.h14
-rw-r--r--chromium/third_party/blink/public/platform/web_url_response.h49
-rw-r--r--chromium/third_party/blink/public/platform/web_video_frame_submitter.h28
-rw-r--r--chromium/third_party/blink/public/platform/web_worker_fetch_context.h16
-rw-r--r--chromium/third_party/blink/public/public_typemaps.gni6
-rw-r--r--chromium/third_party/blink/public/web/DEPS2
-rw-r--r--chromium/third_party/blink/public/web/blink.h10
-rw-r--r--chromium/third_party/blink/public/web/console_message.mojom14
-rw-r--r--chromium/third_party/blink/public/web/console_message.typemap13
-rw-r--r--chromium/third_party/blink/public/web/console_message_struct_traits.cc43
-rw-r--r--chromium/third_party/blink/public/web/console_message_struct_traits.h25
-rw-r--r--chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h10
-rw-r--r--chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h2
-rw-r--r--chromium/third_party/blink/public/web/web_associated_url_loader_client.h2
-rw-r--r--chromium/third_party/blink/public/web/web_ax_object.h1
-rw-r--r--chromium/third_party/blink/public/web/web_console_message.h29
-rw-r--r--chromium/third_party/blink/public/web/web_document.h8
-rw-r--r--chromium/third_party/blink/public/web/web_document_loader.h35
-rw-r--r--chromium/third_party/blink/public/web/web_frame.h2
-rw-r--r--chromium/third_party/blink/public/web/web_frame_content_dumper.h2
-rw-r--r--chromium/third_party/blink/public/web/web_frame_widget.h23
-rw-r--r--chromium/third_party/blink/public/web/web_local_frame.h56
-rw-r--r--chromium/third_party/blink/public/web/web_local_frame_client.h27
-rw-r--r--chromium/third_party/blink/public/web/web_navigation_control.h51
-rw-r--r--chromium/third_party/blink/public/web/web_navigation_params.h85
-rw-r--r--chromium/third_party/blink/public/web/web_pepper_socket_client.h2
-rw-r--r--chromium/third_party/blink/public/web/web_performance.h5
-rw-r--r--chromium/third_party/blink/public/web/web_remote_frame.h4
-rw-r--r--chromium/third_party/blink/public/web/web_remote_frame_client.h2
-rw-r--r--chromium/third_party/blink/public/web/web_settings.h16
-rw-r--r--chromium/third_party/blink/public/web/web_shared_worker.h4
-rw-r--r--chromium/third_party/blink/public/web/web_shared_worker_client.h5
-rw-r--r--chromium/third_party/blink/public/web/web_shared_worker_connect_listener.h60
-rw-r--r--chromium/third_party/blink/public/web/web_shared_worker_repository_client.h71
-rw-r--r--chromium/third_party/blink/public/web/web_text_check_client.h4
-rw-r--r--chromium/third_party/blink/public/web/web_user_media_request.h3
-rw-r--r--chromium/third_party/blink/public/web/web_view.h62
-rw-r--r--chromium/third_party/blink/public/web/web_view_client.h7
-rw-r--r--chromium/third_party/blink/public/web/web_widget.h46
-rw-r--r--chromium/third_party/blink/public/web/web_widget_client.h28
-rw-r--r--chromium/third_party/blink/renderer/BUILD.gn28
-rw-r--r--chromium/third_party/blink/renderer/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md81
-rw-r--r--chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt11
-rw-r--r--chromium/third_party/blink/renderer/bindings/bindings.gni65
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/BUILD.gn10
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_message_channel_custom.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc7
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc14
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h12
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc13
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc159
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h34
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc12
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h46
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc31
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.h67
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc48
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc11
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.h44
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc19
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits.h5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc15
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc121
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.h35
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc21
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h7
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc114
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h56
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.cc98
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.h35
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_data.h53
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_event_listener.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc10
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_function.h13
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc76
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_base.cc18
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc17
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h24
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc114
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_source_code.cc3
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_value.cc10
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_value.h4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_wrappable_marking_visitor_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h1
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc78
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h17
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h3
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc29
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc80
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc30
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc20
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc49
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc108
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h64
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc34
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.h3
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc23
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc12
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h37
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h1
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc49
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h122
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/custom/v8_extendable_message_event_custom.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni4
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc12
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc31
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc24
-rwxr-xr-xchromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py15
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py49
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py13
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py5
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py23
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py11
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_types.py8
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py17
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl14
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl12
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl5
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl31
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl28
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl24
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/constants.cc.tmpl6
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/external_reference_table.cc.tmpl2
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/interface.cc.tmpl38
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/interface.h.tmpl22
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl22
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl49
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_core.cc.tmpl6
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_modules.cc.tmpl4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_css_primitive_value_unit_trie.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_css_tokenizer_codepoints.py1
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_id_mappings.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_keywords.py5
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_cssom_types.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_media_feature_names.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_media_features.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/parser/make_atrule_names.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_base.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property.h.tmpl19
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/templates/cssom_types.cc.tmpl7
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.cc.tmpl5
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_initial_values.py4
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl8
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base_constants.h.tmpl2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/gperf.py5
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/make_element_type_helpers.py5
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/run_with_pythonpath.py27
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/scripts.gni32
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/template_expander.py7
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl3
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/internal_runtime_flags.h.tmpl2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/make_names.cc.tmpl3
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/make_qualified_names.cc.tmpl3
-rw-r--r--chromium/third_party/blink/renderer/controller/BUILD.gn10
-rw-r--r--chromium/third_party/blink/renderer/controller/bloated_renderer_detector.cc8
-rw-r--r--chromium/third_party/blink/renderer/controller/bloated_renderer_detector.h14
-rw-r--r--chromium/third_party/blink/renderer/controller/bloated_renderer_detector_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc73
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor.h68
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.cc106
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.h35
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor_android_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor_test.cc67
-rw-r--r--chromium/third_party/blink/renderer/controller/oom_intervention_impl.cc66
-rw-r--r--chromium/third_party/blink/renderer/controller/oom_intervention_impl.h6
-rw-r--r--chromium/third_party/blink/renderer/controller/oom_intervention_impl_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/BUILD.gn45
-rw-r--r--chromium/third_party/blink/renderer/core/DEPS6
-rw-r--r--chromium/third_party/blink/renderer/core/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/README.md24
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animatable/animatable_double.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animatable/animatable_filter_operations.h7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animatable/animatable_transform.h9
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.h7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/element_animation.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolation_effect.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolation_effect_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/invalidatable_interpolation.h28
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe.h7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/length_interpolation_functions.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.cc119
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.h44
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc220
-rw-r--r--chromium/third_party/blink/renderer/core/animation/string_keyframe.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/string_keyframe.h64
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing_calculations.h37
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing_calculations_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/transition_interpolation.h43
-rw-r--r--chromium/third_party/blink/renderer/core/animation/transition_keyframe.h49
-rw-r--r--chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h11
-rw-r--r--chromium/third_party/blink/renderer/core/aom/accessible_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/aom/accessible_node_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/aom/computed_accessible_node.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/aom/computed_accessible_node.h6
-rw-r--r--chromium/third_party/blink/renderer/core/aom/computed_accessible_node.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h5
-rw-r--r--chromium/third_party/blink/renderer/core/context_features/context_feature_settings.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/core_idl_files.gni11
-rw-r--r--chromium/third_party/blink/renderer/core/css/BUILD.gn7
-rw-r--r--chromium/third_party/blink/renderer/core/css/css.dict3
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_face.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_face.h7
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_face_source.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_face_source_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_feature_values_rule.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_gradient_value.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_image_value.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_keyframe_rule.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_keyframes_rule.h7
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_properties.json512
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_name.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_name.h18
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_name_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_quad_value.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_segmented_font_face.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_style_sheet.cc115
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_style_sheet.h26
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_style_sheet.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_style_sheet_test.cc120
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_keywords.json511
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.h15
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h32
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h35
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/css_resource_value_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/css_style_image_value.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/css_style_value.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h57
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/declared_style_property_map.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/inline_style_property_map.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h49
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc165
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h73
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc222
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.cc73
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc84
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.h24
-rw-r--r--chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set.h33
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set_document.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set_document.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set_worker.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set_worker.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.h238
-rw-r--r--chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set_test.cc225
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_feature_names.json52
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_exp.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_list.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_list.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_list_event.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_list_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_cached.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_cached.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_dynamic.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h17
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_outset_custom.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_slice_custom.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_width_custom.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/height_custom.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/transform_custom.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/transform_origin_custom.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/variable.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/width_custom.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/shorthands/animation_custom.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/css/remote_font_face_source.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_feature_set.cc137
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_feature_set.h75
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc254
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_set.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_set.h10
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_checker.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_query.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_query_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/css/style-invalidation.md10
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_attribute_mutation_scope.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_change_reason.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_change_reason.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_engine.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_engine.h7
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_engine_test.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_media.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_property_serializer.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_property_shorthand_custom.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule_import.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_contents.h25
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_list.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_list.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_list.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/BUILD.gn10
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.h58
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc364
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc835
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h244
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context.idl22
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc335
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_options.idl (renamed from chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.idl)4
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.h34
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h42
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h29
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h47
-rw-r--r--chromium/third_party/blink/renderer/core/dom/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/abort_controller.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/abort_controller.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/aria_attributes.idl9
-rw-r--r--chromium/third_party/blink/renderer/core/dom/attr.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/attr.h8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/attr_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/dom/cdata_section.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/cdata_section.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.h6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/child_node_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/child_node_list.h7
-rw-r--r--chromium/third_party/blink/renderer/core/dom/class_collection.h5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/collection_index_cache.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/comment.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/comment.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/container_node.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/container_node.h6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/context_features.h8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/context_features_client_impl.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.h8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/distributed_nodes.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.cc723
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.h183
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.idl36
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_init.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_init.h50
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_lifecycle.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_lifecycle.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_parser.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_parser_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_parser_timing.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_parser_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_test.cc151
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_timing.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_implementation.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_implementation.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_token_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_token_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element.cc155
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element.h37
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_data.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_data.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_data_cache.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_data_cache.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_rare_data.h11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_visibility_observer.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_visibility_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/empty_node_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/empty_node_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/custom_event.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/custom_event.h22
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event.h9
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_listener.h64
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_listener_map.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_listener_map.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_path.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_path.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_queue.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_queue.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_target.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_target.h19
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_target_impl.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_target_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/native_event_listener.h42
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/node_event_context.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/node_event_context.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/window_event_context.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/window_event_context.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_forbidden_scope.h34
-rw-r--r--chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.h6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/global_event_handlers.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/global_event_handlers.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/id_target_observer.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/id_target_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/layout_tree_builder.h6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/dom/live_node_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/live_node_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/live_node_list_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/live_node_list_registry.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/live_node_list_registry.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_observer_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_record.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/dom/mutation_record.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/named_node_map.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/named_node_map.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/names_map.cc117
-rw-r--r--chromium/third_party/blink/renderer/core/dom/names_map.h13
-rw-r--r--chromium/third_party/blink/renderer/core/dom/names_map_test.cc131
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node.h16
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_computed_style.h7
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_iterator.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_iterator.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_iterator_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_iterator_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_lists_node_data.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_lists_node_data.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_rare_data.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_rare_data.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/nth_index_cache.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/nth_index_cache.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/processing_instruction.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/processing_instruction.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/pseudo_element_data.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range_boundary_point.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_animation_controller_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_task_queue.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_task_queue.h18
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/space_split_string.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_node_list.h5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_range.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_range.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/template_content_document_fragment.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope.h13
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_walker.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_walker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/user_action_element_set.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/user_action_element_set.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/visited_link_state.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/visited_link_state.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/weak_identifier_map.h25
-rw-r--r--chromium/third_party/blink/renderer/core/editing/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/caret_display_item_client_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/append_node_command.h6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.h15
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/break_blockquote_command.h5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/create_link_command.h4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/editing_command_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_style.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_utilities.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/element_inner_text.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc354
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h174
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc280
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.cc101
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/inline_box_position.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/editing/inline_box_traversal.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/search_buffer_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/layout_selection.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/editing/link_selection_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/plain_text_range_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_controller.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier_character.cc113
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.h4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/testing/selection_sample.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_position.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_line.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/events/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/core/events/after_print_event.h34
-rw-r--r--chromium/third_party/blink/renderer/core/events/animation_event.h23
-rw-r--r--chromium/third_party/blink/renderer/core/events/animation_playback_event.h16
-rw-r--r--chromium/third_party/blink/renderer/core/events/application_cache_error_event.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/events/application_cache_error_event.h29
-rw-r--r--chromium/third_party/blink/renderer/core/events/before_print_event.h34
-rw-r--r--chromium/third_party/blink/renderer/core/events/before_text_inserted_event.h5
-rw-r--r--chromium/third_party/blink/renderer/core/events/before_unload_event.h14
-rw-r--r--chromium/third_party/blink/renderer/core/events/clipboard_event.h10
-rw-r--r--chromium/third_party/blink/renderer/core/events/composition_event.h15
-rw-r--r--chromium/third_party/blink/renderer/core/events/composition_event.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/events/error_event.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/events/event_type_names.json55
-rw-r--r--chromium/third_party/blink/renderer/core/events/input_event.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/events/message_event.idl16
-rw-r--r--chromium/third_party/blink/renderer/core/events/mouse_event.idl30
-rw-r--r--chromium/third_party/blink/renderer/core/events/mutation_event.idl16
-rw-r--r--chromium/third_party/blink/renderer/core/events/navigator_events.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/events/overscroll_event.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/events/overscroll_event.h42
-rw-r--r--chromium/third_party/blink/renderer/core/events/overscroll_event.idl13
-rw-r--r--chromium/third_party/blink/renderer/core/events/overscroll_event_init.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event.h4
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event_factory.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event_factory.h51
-rw-r--r--chromium/third_party/blink/renderer/core/events/portal_activate_event.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/events/portal_activate_event.h35
-rw-r--r--chromium/third_party/blink/renderer/core/events/portal_activate_event.idl9
-rw-r--r--chromium/third_party/blink/renderer/core/events/text_event.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/events/touch_event_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/events/ui_event.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc85
-rw-r--r--chromium/third_party/blink/renderer/core/events/wheel_event.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/execution_context.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/execution_context.h42
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/pausable_object.cc (renamed from chromium/third_party/blink/renderer/core/dom/pausable_object.cc)13
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/pausable_object.h (renamed from chromium/third_party/blink/renderer/core/dom/pausable_object.h)12
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/pausable_object_test.cc (renamed from chromium/third_party/blink/renderer/core/dom/pausable_object_test.cc)4
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/pause_state.h22
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/security_context.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/security_context.h14
-rw-r--r--chromium/third_party/blink/renderer/core/exported/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.h25
-rw-r--r--chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.cc155
-rw-r--r--chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h75
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h9
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h16
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_test.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc142
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_frame_serializer.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_frame_test.cc801
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_label_element.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_layer_test.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_node_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h12
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_performance.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_settings_impl.h15
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc106
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h10
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_impl.cc522
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_impl.h188
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_test.cc696
-rw-r--r--chromium/third_party/blink/renderer/core/exported/worker_shadow_page.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/document_policy.h4
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc (renamed from chromium/third_party/blink/renderer/core/feature_policy/policy.cc)26
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h (renamed from chromium/third_party/blink/renderer/core/feature_policy/policy.h)20
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy.idl (renamed from chromium/third_party/blink/renderer/core/feature_policy/policy.idl)11
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h17
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.h5
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/policy_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/body.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.cc144
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h69
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer_test.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/bytes_consumer.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test.cc114
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h6
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.h8
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h10
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/global_fetch.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/headers.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/multipart_parser.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/multipart_parser_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/request.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/request.h4
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/request_init.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/request_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/response.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/response_init.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/response_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/blob.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/blob.h7
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/file.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/frame/bar_prop.h5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/browser_controls.h5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc192
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc425
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h89
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc162
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h16
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_source.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc118
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc254
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h62
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dactyloscoper.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dactyloscoper.h33
-rw-r--r--chromium/third_party/blink/renderer/core/frame/deprecation.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/frame/deprecation.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_timer.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_timer.h18
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_timer_coordinator.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_window.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_window.h15
-rw-r--r--chromium/third_party/blink/renderer/core/frame/event_handler_registry.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/event_handler_registry.h12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/external.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_console.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_console.h12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay.cc161
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay.h (renamed from chromium/third_party/blink/renderer/core/page/page_overlay.h)50
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay_test.cc121
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_serializer_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc239
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h102
-rw-r--r--chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/history.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/history.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/link_highlights.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/link_highlights.h12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_dom_window.cc187
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_dom_window.h38
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame.cc183
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame.h57
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_client.h33
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view.cc944
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view.h119
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/frame/location.cc136
-rw-r--r--chromium/third_party/blink/renderer/core/frame/location.h54
-rw-r--r--chromium/third_party/blink/renderer/core/frame/location.idl33
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_device_memory.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_id.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_language.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_language.h20
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_language.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.h8
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_script_executor.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_task.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_task.h12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_timer.cc82
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_timer.h60
-rw-r--r--chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.h20
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_view.h6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/reporting_context.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/frame/reporting_context.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/screen.idl16
-rw-r--r--chromium/third_party/blink/renderer/core/frame/scroll_into_view_options.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings.json543
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings_delegate.h1
-rw-r--r--chromium/third_party/blink/renderer/core/frame/use_counter.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/frame/use_counter.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.cc123
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.h7
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.idl14
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc283
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc138
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h20
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc242
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h75
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h17
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window.idl71
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_event_handlers.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_event_handlers.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.h1
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_point_read_only.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_quad.idl9
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/BUILD.gn24
-rw-r--r--chromium/third_party/blink/renderer/core/html/anchor_element_metrics.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h18
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/text_metrics.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/text_metrics.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/collection_items_cache.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/README.md6
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element.h19
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.h37
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.h36
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.h28
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.cc93
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.h42
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.h28
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.h32
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.cc264
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h51
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h10
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h32
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h26
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h33
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/element_internals.cc186
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/element_internals.h29
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/element_internals.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h12
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/validity_state_flags.idl18
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/button_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/button_input_type.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/clear_button_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/clear_button_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_chooser.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_chooser_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.h14
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_input_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/color_input_type.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_chooser.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_popup_menu_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/file_chooser.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/file_input_type.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/file_input_type.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/file_input_type_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_controller.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_controller.h32
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_controller_test.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_data.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_data.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_data_event.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_data_event.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_data_event.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/form_data_event_init.idl9
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_button_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_button_element.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc272
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.h60
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h30
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_element.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_element.h17
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_input_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_label_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_legend_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_output_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_output_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/input_type.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/input_type.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/input_type_view.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/labelable_element.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/labelable_element.h66
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/labels_node_list.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/listed_element.cc354
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/listed_element.h107
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/password_input_type.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/password_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc288
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/popup_menu.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/range_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/validity_state.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_anchor_element.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_anchor_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_area_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_attribute_names.json54
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_base_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_base_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_bdi_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_body_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_body_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_br_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_collection.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_collection.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_content_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_content_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_dialog_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_directory_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_div_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_dlist_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_document.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_element.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_element.h14
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_embed_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_embed_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_embed_element.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_font_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_element.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_element.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_element_base.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_set_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_head_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_hr_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_html_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element.h17
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element.idl9
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_element.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_element.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_element_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_fallback_helper.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_li_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_link_element.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_link_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_link_element.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_map_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_marquee_element.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_marquee_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_menu_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_meta_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_meter_element.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_meter_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_no_embed_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_no_script_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_object_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_object_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_object_element.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_olist_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_paragraph_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_param_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_picture_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_plugin_element.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_plugin_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_progress_element.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_progress_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_rt_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_ruby_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_script_element.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_script_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_script_element.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_shadow_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_slot_element.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_slot_element.h11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_source_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_source_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_span_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_style_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_style_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_caption_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_col_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_row_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_template_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_template_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_title_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_ulist_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_view_source_document.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_view_source_document.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_wbr_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/image_document.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/html/image_document.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/image_document_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_child.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_child_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_sheets_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/link_import.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/link_import.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_element_loading_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_resource.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_resource.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_style.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_style.h10
-rw-r--r--chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/autoplay_policy.h11
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.h17
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element.h29
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.h39
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element_persistent_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_controls.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_controls.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.h30
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_document.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.h41
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/remote_playback_observer.h30
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/video_wake_lock.cc117
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/video_wake_lock.h83
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc223
-rw-r--r--chromium/third_party/blink/renderer/core/html/media_element_filling_viewport_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_construction_site.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc92
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h9
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_stack_item.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/preload_request.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/preload_request.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder_for_fuzzing.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/xss_auditor.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/plugin_document.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/html/plugin_document.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/document_portals.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/document_portals.h9
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.h22
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h11
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/portal_host.h19
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/portal_host.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/window_portal_host.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/audio_track.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/audio_track.h18
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/audio_track_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/audio_track_list.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/cue_timeline.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/html_track_element.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/html_track_element.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/html_track_element.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/loadable_text_track.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/loadable_text_track.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_container.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_container.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_cue.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_cue.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/text_track_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/track_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/track_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/track_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/track_event.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/track_list_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/video_track.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/video_track.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/video_track_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h2
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h4
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handler.cc142
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handler.h31
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handler_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handling_util.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handling_util.h5
-rw-r--r--chromium/third_party/blink/renderer/core/input/gesture_manager.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h1
-rw-r--r--chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc130
-rw-r--r--chromium/third_party/blink/renderer/core/input/mouse_event_manager.h17
-rw-r--r--chromium/third_party/blink/renderer/core/input/overscroll_behavior_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc218
-rw-r--r--chromium/third_party/blink/renderer/core/input/pointer_event_manager.h75
-rw-r--r--chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/input/scroll_manager.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/input/touch_action_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/input/touch_event_manager.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/input/touch_event_manager_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/InspectorOverlayPage.html511
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.2.json5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.3.json4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/browser_protocol.pdl149
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/console_message.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/console_message.h9
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_host.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/devtools_agent.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/devtools_agent.h6
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/devtools_session.h2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h8
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h10
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_history.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc240
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h25
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_log_agent.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc93
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h30
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc504
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h40
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h9
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_session_state.h2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/network_resources_data.h14
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/resolve_node.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/resolve_node.h3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/worker_devtools_params.h2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h7
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h10
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/invisible_dom/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/core/invisible_dom/activate_invisible_event.h6
-rw-r--r--chromium/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc196
-rw-r--r--chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/BUILD.gn5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/api/line_layout_box.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/floating_objects.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/jank_region.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/jank_tracker.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.cc247
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.h26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.cc159
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.h97
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_fieldset.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.cc166
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_iframe.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc113
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_box.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.cc187
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_media.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.cc431
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.h167
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_test.cc158
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_quote.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_ruby_run.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_row.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_row.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.h19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mobile.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_video.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_box.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.h92
-rw-r--r--chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/README.md13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.cc203
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h151
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator_test.cc274
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc51
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc95
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc256
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h186
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc481
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc505
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc227
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc594
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h63
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc167
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc149
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc95
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc139
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h39
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc92
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h50
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc399
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc284
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc404
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/overflow_model.h87
-rw-r--r--chromium/third_party/blink/renderer/core/layout/overflow_model_test.cc166
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc101
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/loader/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.h25
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache.h9
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc90
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h51
-rw-r--r--chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/loader/base_fetch_context.h9
-rw-r--r--chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.h36
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_loader.cc501
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_loader.h92
-rw-r--r--chromium/third_party/blink/renderer/core/loader/empty_clients.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/loader/empty_clients.h27
-rw-r--r--chromium/third_party/blink/renderer/core/loader/form_submission.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc562
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h85
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc304
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_load_request.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader.cc239
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader.h58
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader_types.h10
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.h81
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc135
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h55
-rw-r--r--chromium/third_party/blink/renderer/core/loader/history_item.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/loader/history_item.h1
-rw-r--r--chromium/third_party/blink/renderer/core/loader/image_loader.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/loader/importance_attribute.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/interactive_detector.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/loader/interactive_detector.h8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_load_parameters.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_load_parameters.h50
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader.cc529
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader.h79
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/loader/long_task_detector.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/long_task_detector.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/long_task_detector_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h1
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h6
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h26
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc160
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h39
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h1
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/navigation_scheduler.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/loader/navigation_scheduler.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/loader/preload_helper.cc531
-rw-r--r--chromium/third_party/blink/renderer/core/loader/preload_helper.h84
-rw-r--r--chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/loader/progress_tracker.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/progress_tracker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/document_resource.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/font_resource.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_info.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/script_resource.h10
-rw-r--r--chromium/third_party/blink/renderer/core/loader/scheduled_navigation.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/scheduled_navigation.h17
-rw-r--r--chromium/third_party/blink/renderer/core/loader/text_resource_decoder_builder.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader.h11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h39
-rw-r--r--chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.h58
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/message_port.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h4
-rw-r--r--chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/page/BUILD.gn10
-rw-r--r--chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/autoscroll_controller.h5
-rw-r--r--chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client.h10
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client_impl.h7
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/page/context_menu_controller.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/page/context_menu_controller.h4
-rw-r--r--chromium/third_party/blink/renderer/core/page/create_window.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/page/create_window.h4
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_controller.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_controller_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/page/focus_controller.cc245
-rw-r--r--chromium/third_party/blink/renderer/core/page/focus_controller.h14
-rw-r--r--chromium/third_party/blink/renderer/core/page/page.cc92
-rw-r--r--chromium/third_party/blink/renderer/core/page/page.h21
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_hidden_state.cc (renamed from chromium/third_party/blink/renderer/core/page/page_visibility_state.cc)19
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_hidden_state.h (renamed from chromium/third_party/blink/renderer/core/page/page_visibility_state.h)9
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_overlay.cc127
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_overlay_test.cc151
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_popup_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_popup_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_widget_delegate.h9
-rw-r--r--chromium/third_party/blink/renderer/core/page/print_context.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/print_context_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc242
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h77
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc555
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc95
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h8
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc551
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h13
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation.cc299
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation.h41
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc407
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h90
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc136
-rw-r--r--chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client.h3
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h7
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h20
-rw-r--r--chromium/third_party/blink/renderer/core/page/viewport_description.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/viewport_description.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/viewport_test.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/paint/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/DEPS4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/README.md20
-rw-r--r--chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_border_painter.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_base.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_base.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/collapsed_border_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc256
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc107
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h29
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc163
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_triggers.h39
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/paint/frame_painter.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/paint/frame_painter.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc165
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h62
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_painter.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc178
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h48
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc188
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc165
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_paint_properties.h7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_painter.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_event.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_info.h10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc155
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_invalidator.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer.cc323
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer.h64
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc121
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc130
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h14
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc265
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc375
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc528
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc163
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing.h19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/replaced_painter.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/stub_chrome_client_for_cap.h (renamed from chromium/third_party/blink/renderer/core/paint/stub_chrome_client_for_spv2.h)8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_cell_painter.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_painter_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_section_painter.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc304
-rw-r--r--chromium/third_party/blink/renderer/core/paint/video_painter.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/video_painter_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/paint/view_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/view_painter_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.h4
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.json57
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.pidl31
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h3
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/scheduler/throttling_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/scheduler/virtual_time_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/script/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_pending_script.cc86
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_pending_script.h29
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_script.h18
-rw-r--r--chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/script/document_modulator_impl.h9
-rw-r--r--chromium/third_party/blink/renderer/core/script/document_write_intervention.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h3
-rwxr-xr-xchromium/third_party/blink/renderer/core/script/generate_lapi_grdp.py101
-rw-r--r--chromium/third_party/blink/renderer/core/script/html_parser_script_runner.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/script/layered_api.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/script/layered_api.h5
-rw-r--r--chromium/third_party/blink/renderer/core/script/layered_api_resources.h54
-rw-r--r--chromium/third_party/blink/renderer/core/script/mock_script_element_base.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator.h29
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator_impl_base.h26
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_map.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_map.h4
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_map_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_pending_script.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_script.h9
-rw-r--r--chromium/third_party/blink/renderer/core/script/pending_script.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/script/pending_script.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/README.md32
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium12
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js253
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/.eslintrc.js337
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/OWNERS5
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/async_iterator.js88
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/idb_utils.js107
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/index.js176
-rw-r--r--chromium/third_party/blink/renderer/core/script/resources/layered_api/resources.grdp20
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_element_base.h1
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_loader.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_loader.h4
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_module_resolver_impl_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_runner.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_runner.h11
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_runner_test.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm2
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h9
-rw-r--r--chromium/third_party/blink/renderer/core/streams/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/CommonOperations.js15
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream.h11
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream.cc210
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream.h57
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc230
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h88
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style.h18
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json56
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json59
-rw-r--r--chromium/third_party/blink/renderer/core/style/content_data.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/style/content_data.h6
-rw-r--r--chromium/third_party/blink/renderer/core/style/filter_operation.h33
-rw-r--r--chromium/third_party/blink/renderer/core/style/filter_operations.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/style/filter_operations.h2
-rw-r--r--chromium/third_party/blink/renderer/core/style/grid_area.h7
-rw-r--r--chromium/third_party/blink/renderer/core/style/grid_positions_resolver.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/style/grid_positions_resolver.h7
-rw-r--r--chromium/third_party/blink/renderer/core/style/shadow_data.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_image.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_reflection.h2
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style.h4
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc100
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc43
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h8
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_a_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_circle_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_defs_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_desc_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_discard_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_element.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_enumeration.h8
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_merge_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_filter_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_g_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_geometry_element.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_image_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_image_element.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_line_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_marker_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_mask_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_metadata_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_path_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_polygon_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_polyline_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_rect_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_script_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_set_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_stop_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_string_list.h7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_svg_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_switch_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_content_element.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_title_element.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_transform.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_transform_list.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_tspan_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_uri_reference.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_use_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_view_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/testing/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/callback_function_test.h4
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/fixed-position-losing-backing.html17
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/test_touch_link_highlight.html21
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/wheel-event-handler.html2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dictionary_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_modulator.h33
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internals.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internals.h10
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internals.idl30
-rw-r--r--chromium/third_party/blink/renderer/core/testing/null_execution_context.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/page_test_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h14
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h27
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_network.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_network.h15
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_request.cc95
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_request.h52
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc51
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_test.h21
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.h41
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.h49
-rw-r--r--chromium/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/event_timing.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/memory_info.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/timing/memory_info.h17
-rw-r--r--chromium/third_party/blink/renderer/core/timing/memory_info.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.cc262
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.h85
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.idl18
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_element_timing.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_element_timing.h7
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_element_timing.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_entry.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_layout_jank.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_layout_jank.h3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_layout_jank.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer.h4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_resource_timing.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_resource_timing.h8
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_resource_timing.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_server_timing.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.h26
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_user_timing.h12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/task_attribution_timing.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.h8
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h14
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc43
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h18
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc91
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h13
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.h14
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h17
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h4
-rw-r--r--chromium/third_party/blink/renderer/core/url/url_search_params.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/BUILD.gn5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/abstract_worker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker.h6
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/task.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.h3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/task_worklet_global_scope.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.h4
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.h4
-rw-r--r--chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h17
-rw-r--r--chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.h6
-rw-r--r--chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_client.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_client.h37
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc125
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.h95
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_repository_client.h68
-rw-r--r--chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc144
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h38
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc150
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_global_scope.h65
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_global_scope.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_module_tree_client.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_navigator.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_navigator.h19
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_navigator.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h6
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_reporting_proxy.h4
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread.h8
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h33
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/xml/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/xml/document_xslt.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/xml/dom_parser.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_functions.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_functions_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_grammar.y70
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc86
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h10
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h3
-rw-r--r--chromium/third_party/blink/renderer/devtools/BUILD.gn121
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.pngbin865 -> 0 bytes
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.svg69
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.pngbin470 -> 0 bytes
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.svg28
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/Images/deleteIcon.pngbin109 -> 0 bytes
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/Images/whatsnew.pngbin12114 -> 12074 bytes
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityModel.js7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/CacheStorageTestRunner.js52
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/IndexedDBTestRunner.js15
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/ServiceWorkersTestRunner.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/category-renderer.js352
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/crc-details-renderer.js13
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/details-renderer.js25
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/dom.js17
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/logger.js81
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/performance-category-renderer.js25
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/psi.js84
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/pwa-category-renderer.js156
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-renderer.js49
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-ui-features.js492
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/util.js24
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/report-styles.css185
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/templates.html353
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2/module.json2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/Audits2Service.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-background.js84205
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-dt-bundle.js59456
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/module.json4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/XHRBreakpointsSidebarPane.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/module.json8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/LogManager.js17
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/module.json1
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/changes/changesView.css5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/brace-fold.js125
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.css370
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.js18446
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/foldcode.js155
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/foldgutter.js162
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/matchbrackets.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm/module.json10
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clike.js124
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clojure.js532
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_modes/markdown.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_modes/python.js8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_modes/shell.js35
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/css.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastDetails.js25
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastInfo.js94
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastOverlay.js69
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js56
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/color_picker/spectrum.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/components/JSPresentationUtils.js17
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console/ConsolePanel.js9
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js88
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js55
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js25
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console/consoleView.css1
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console/module.json3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/cookie_table/CookiesTable.js12
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js67
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js15
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js10
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/devices/devicesView.css8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js142
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js47
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/ColorSwatchPopoverIcon.js8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/DOMLinkifier.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js10
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeElement.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js37
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/InspectElementModeController.js51
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/StylePropertyTreeElement.js19
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js66
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css33
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/metricsSidebarPane.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements/module.json7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/elements_test_runner/ElementsTestRunner.js5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeWrapper.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/GeolocationsSettingsTab.js188
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/SensorsView.js79
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/geolocationsSettingsTab.css94
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/module.json46
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/emulation/sensors.css36
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/extensions/ExtensionView.js7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/externs.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/heap_profiler_test_runner/HeapProfilerTestRunner.js9
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js328
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/help/ReleaseNoteText.js39
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js32
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js20
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js72
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inline_editor/colorSwatch.css1
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inspector_main/InspectorMain.js43
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RenderingOptions.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RequestAppBannerActionDelegate.js23
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inspector_main/module.json8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/main/Main.js8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/NetworkDataGridNode.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/NetworkItemView.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js11
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js12
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js1
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/networkLogView.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/network/networkPanel.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css13
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/performance_test_runner/TimelineTestRunner.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/platform/utilities.js26
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/profiler/ProfilesPanel.js5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/ProtocolMonitor.js30
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/protocolMonitor.css5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js148
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js30
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheModel.js11
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkerCacheViews.js35
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/resources/StorageItemsView.js11
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/screencast/InputModel.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/screencast/ScreencastView.js30
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/Connections.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/ConsoleModel.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js9
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/DebuggerModel.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/HARLog.js16
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js19
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js128
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/ResourceTreeModel.js9
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/RuntimeModel.js11
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerCacheModel.js11
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerManager.js12
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/TargetManager.js5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sdk/module.json18
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/snippets/ScriptSnippetFileSystem.js50
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js30
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js94
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js31
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/NavigatorView.js14
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/ScriptOriginPlugin.js9
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesNavigator.js14
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesPanel.js12
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesSearchScope.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/TabbedEditorContainer.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css27
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/debuggerPausedMessage.css1
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/module.json53
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/sources/watchExpressionsSidebarPane.css35
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js15
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js56
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css99
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js4
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js9
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineProfileTree.js8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/Dialog.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js21
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/Icon.js27
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js3
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js10
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js15
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/TextEditor.js7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/TextPrompt.js7
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js87
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js5
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js300
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/View.js22
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/Widget.js10
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/filter.css6
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css32
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css20
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/radioButton.css8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css8
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/textButton.css43
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/textPrompt.css21
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/toolbar.css13
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js18
-rw-r--r--chromium/third_party/blink/renderer/devtools/readme.md6
-rw-r--r--chromium/third_party/blink/renderer/devtools/scripts/extract_module/extract_module.js2
-rw-r--r--chromium/third_party/blink/renderer/devtools/scripts/npm_test.js4
-rw-r--r--chromium/third_party/blink/renderer/modules/BUILD.gn12
-rw-r--r--chromium/third_party/blink/renderer/modules/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc191
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc144
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc151
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc114
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc98
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc503
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc134
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h60
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/README.md2
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc35
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animator.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animator_definition.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/css_animation_worklet.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc213
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc101
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.h15
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fail_event_init.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.cc23
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.h35
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc33
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.cc29
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc87
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl44
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h23
-rw-r--r--chromium/third_party/blink/renderer/modules/badging/badge.cc33
-rw-r--r--chromium/third_party/blink/renderer/modules/badging/badge.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/badging/experimental_badge.idl (renamed from chromium/third_party/blink/renderer/modules/badging/badge.idl)13
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_manager.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_manager.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_manager.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/README.md4
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc235
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.h43
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.cc100
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.h85
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_attribute_instance_map.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.cc80
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.h49
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_options.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.cc72
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h46
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_server.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.cc68
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/navigator_bluetooth.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/README.md4
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/fuzz_main_run.py10
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/setup.py6
-rw-r--r--chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/OWNERS9
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache.cc218
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/global_cache_storage.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc70
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc29
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc26
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc23
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc161
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/navigator_clipboard.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.cc31
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc128
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h22
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_creation_options.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/crypto.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/crypto_key.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc23
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.idl27
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc38
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/event_target_modules_names.json54
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/event_source.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/indexed_db_key_builder.cc201
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc62
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc143
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_idb_key_range.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_idb_value.cc56
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/BUILD.gn23
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_axis_event.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_button.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_button_event.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.cc237
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h90
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc362
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc299
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.h35
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/coordinates.h26
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/BUILD.gn16
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/DEPS8
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_manager.cc94
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_manager.h56
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_manager.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_options.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_status.cc107
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_status.h88
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_status.idl21
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/navigator_idle.cc79
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/navigator_idle.h27
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/navigator_idle.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/worker_navigator_idle.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/README.md2
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/global_indexed_db.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc33
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h (renamed from chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h)28
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc159
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc35
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_index.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc106
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h87
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc41
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc83
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc141
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc29
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc52
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h34
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink.typemap25
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc376
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h210
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc88
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.cc216
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h82
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc162
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h120
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h33
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h50
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h (renamed from chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h)54
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc212
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h80
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc93
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h35
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc121
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h (renamed from chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h)25
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc198
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h59
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc44
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory.h32
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.cc75
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.h56
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/keyboard/keyboard.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/keyboard/keyboard_lock.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/lock.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/lock.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/lock_manager.cc31
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info_callbacks.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc38
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_metrics.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_toggle_closed_captions_button_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc159
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc89
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.cc110
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css284
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/README.md2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_session.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_session.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_session.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.cc26
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer_list.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/input_device_info.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_device_info.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_device_info.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_devices.h16
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_devices.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/modules_idl_files.gni63
-rw-r--r--chromium/third_party/blink/renderer/modules/modules_initializer.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc26
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h48
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/abort_payment_event.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/abort_payment_event.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/basic_card_helper.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc166
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_address.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_manager.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.cc119
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_response.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_response.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_response.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn15
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc72
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h72
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc118
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h33
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc135
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h43
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc60
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc170
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc380
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h52
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc41
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h80
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc395
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc84
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h56
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc126
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_configuration.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc91
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_error_util.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc174
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc61
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc117
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h34
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl26
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc342
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc270
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h75
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl24
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl30
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc563
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.cc34
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_decoding_parameters.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receive_parameters.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc127
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h26
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc91
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_synchronization_source.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_session_description.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permission_status.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permission_status.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permissions.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc74
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/plugin_array.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_availability.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_availability_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_manager.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_subscription.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.cc37
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc31
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc129
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/README.md2
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/accelerometer.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/accelerometer.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/navigator_serial.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial.cc140
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc151
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc34
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/face_detector.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/text_detector.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/README.md2
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/storage_controller.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/storage_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/storage_event.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/vr/navigator_vr.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/vr/vr_controller.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/vr/vr_display.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/vr/vr_display.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/vr/vr_display.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/analyser_node.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/analyser_node.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc26
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_context.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_destination_node.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_listener.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.cc71
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.h22
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_input_test.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.cc71
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.h22
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc228
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.h51
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc38
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param.h30
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param_map.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc46
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc56
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h52
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/change_version_wrapper.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/database.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/database.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_backend.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc202
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc81
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.h67
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl23
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h34
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.cc99
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h82
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.idl27
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multiview.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_object.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_object.h16
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc256
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h54
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.h49
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_accessor_client.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc182
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h77
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_port.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/share_data.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/close_event.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc45
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/README.md4
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/BUILD.gn22
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr.cc444
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr.h69
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc83
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device.cc274
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device.h89
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc158
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h53
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc33
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_reference_space.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_reference_space_options.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.cc199
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.h44
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_space.cc (renamed from chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc)20
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_space.h (renamed from chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h)25
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_space.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc141
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h34
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_utils.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_utils.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.cc60
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.h16
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.h (renamed from chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h)13
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl (renamed from chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl)8
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h15
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl1
-rw-r--r--chromium/third_party/blink/renderer/platform/BUILD.gn18
-rw-r--r--chromium/third_party/blink/renderer/platform/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/platform/async_method_runner.h24
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_bus.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_bus.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_destination.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_destination.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_io_callback.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc55
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h44
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc59
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc21
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h58
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc87
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc104
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h23
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc119
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h22
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/to_v8.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h24
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_binding.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/blob/blob_data_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/crypto_result.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/platform.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/platform_media_stream_source.cc83
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_crypto_algorithm.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_media_constraints.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_media_stream_source.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_media_stream_track.cc33
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_platform_media_stream_track.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_presentation_receiver.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_rtc_rtp_source.cc (renamed from chromium/third_party/blink/renderer/platform/exported/web_rtc_rtp_contributing_source.cc)4
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc48
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_service_worker_request.cc27
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_service_worker_response.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_load_timing.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_request.cc19
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_response.cc69
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc37
-rw-r--r--chromium/third_party/blink/renderer/platform/feature_policy/DEPS17
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_cache.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_cache.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h22
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_description.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_description.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_selection_types.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc42
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm58
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc149
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc59
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc78
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc69
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc105
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc46
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h40
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc19
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc160
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc60
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc75
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/geometry/length_functions.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/geometry/length_functions.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/OWNERS8
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc223
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h49
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc433
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc31
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc163
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/README.md2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc119
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h29
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc199
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc86
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h34
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc21
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc86
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h33
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc75
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_context.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc119
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h67
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image.cc32
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc54
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image_pattern.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h40
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/link_highlight.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc156
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc30
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/mutator_client.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/README.md28
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h18
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc22
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc38
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc29
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h9
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/path.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/path.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/pattern.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/pattern.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h36
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc31
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h30
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/texture_holder.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc516
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h110
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc343
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md98
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/atomic_entry_flag.h47
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/blink_gc.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/garbage_collected.h139
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap.cc121
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap.h104
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_allocator.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_compact.cc31
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_compact.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_compact_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_page.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_test.cc1093
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h89
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_thread_test.cc269
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/incremental_marking_test.cc142
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc86
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/marking_visitor.h33
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/name_trait_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/name_traits.h39
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/page_memory.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/persistent.h91
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/persistent_node.h155
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/persistent_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/run_all_tests.cc35
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/thread_state.cc43
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/thread_state.h62
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/worklist.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/image-encoders/image_encoder.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/instance_counters.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/instance_counters.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h21
-rw-r--r--chromium/third_party/blink/renderer/platform/lifecycle_context_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/BUILD.gn15
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/DEPS16
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc (renamed from chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc)64
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.h29
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc (renamed from chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc)174
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/cors/cors.cc44
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/cors/cors.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc84
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.cc139
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/console_logger.h54
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc29
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h23
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc100
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h143
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc31
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h50
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc137
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource.h30
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc414
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h101
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h78
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc352
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc108
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc202
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc56
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc92
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_request_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.cc91
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h95
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.cc110
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing_test.cc111
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/link_header.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc103
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h48
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader_test.cc177
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/subresource_integrity.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h68
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc39
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h80
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.h23
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_source.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/memory_coordinator.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/memory_coordinator.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/mhtml/archive_resource.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/mhtml/archive_resource.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/blink_typemaps.gni1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers.typemap16
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers_mojom_traits.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/interface_invalidator_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/network/http_names.json51
-rw-r--r--chromium/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/network/http_parsers_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_state_notifier.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_utils.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_utils.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_void_request.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5213
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn11
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/README.md141
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md178
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/background_scheduler.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/features.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.cc (renamed from chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.cc)19
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h (renamed from chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h)20
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer_unittest.cc (renamed from chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc)23
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/links.md120
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc239
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h31
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc638
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h52
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h37
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc78
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc54
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/shared_buffer.cc23
-rw-r--r--chromium/third_party/blink/renderer/platform/shared_buffer.h31
-rw-r--r--chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/supplementable.h13
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/data/apng19-ref.pngbin2812 -> 2811 bytes
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/shaping_line_breaker_perf_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc221
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h18
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/text/bidi_resolver_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/text/character.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/text/locale_icu.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/text/locale_mac.mm11
-rw-r--r--chromium/third_party/blink/renderer/platform/text/locale_win.cc25
-rw-r--r--chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/text/text_break_iterator.h18
-rw-r--r--chromium/third_party/blink/renderer/platform/text/unicode_utilities_test.cc70
-rw-r--r--chromium/third_party/blink/renderer/platform/timer_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/DEPS9
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transform_operations.cc98
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transform_operations.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc171
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test.cc88
-rw-r--r--chromium/third_party/blink/renderer/platform/web_task_runner.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/web_test_support.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.cc41
-rw-r--r--chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.h18
-rw-r--r--chromium/third_party/blink/renderer/platform/web_vector_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/kurl.cc32
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/kurl.h35
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/BUILD.gn13
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/atomics.h402
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/date_math.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/hash_map.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/terminated_array.h130
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/terminated_array_builder.h87
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/collator.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_view.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_view.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/vector.h20
-rw-r--r--chromium/third_party/blink/tools/apache_config/mime.types2
-rw-r--r--chromium/third_party/blink/tools/apache_config/win-httpd.conf8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer.py20
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py14
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/checkout/diff_parser_unittest.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/checkout/diff_test_data.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/config/builders.json1
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/host_mock.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/buildbot.py63
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py57
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/web.py15
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/web_mock.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/web_test_results.py (renamed from chromium/third_party/blink/tools/blinkpy/common/net/layout_test_results.py)32
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/net/web_test_results_unittest.py (renamed from chromium/third_party/blink/tools/blinkpy/common/net/layout_test_results_unittest.py)22
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/path_finder.py9
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/path_finder_unittest.py12
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/system/executive.py9
-rw-r--r--chromium/third_party/blink/tools/blinkpy/common/unified_diff.py2
-rwxr-xr-xchromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py33
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/README.chromium2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList5
-rwxr-xr-xchromium/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt.config.json1
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/gitignore/gitignore.py204
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py17
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/commands.json3
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/download.py79
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py44
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py403
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py2
-rwxr-xr-xchromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/update.py46
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/utils.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py247
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/__init__.py36
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py741
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/error.py210
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/protocol.py43
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py192
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py176
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/commands.json1
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py15
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/markdown.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py123
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py72
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py32
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/handlers.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py28
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/request.py13
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/__init__.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py22
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py23
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/analyze_baselines_unittest.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/flaky_tests.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/optimize_baselines_unittest.py10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/queries.py6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py28
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py12
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py16
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test_unittest.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py24
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/chromium_commit_mock.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/chromium_finder.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor.py10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/import_notifier.py10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/test_copier.py12
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/test_importer.py26
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py16
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py20
-rw-r--r--chromium/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/breakpad/dump_reader_win.py10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/builder_list.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py17
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/controllers/single_test_runner.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py (renamed from chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py)8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder_unittest.py (renamed from chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder_unittest.py)10
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py (renamed from chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner.py)2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittes.py (renamed from chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner_unittest.py)6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/merge_results.py16
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/merge_results_unittest.py16
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/models/test_run_results.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/android.py18
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/base.py69
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py38
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_driver.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/driver.py6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py50
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py6
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/test.py28
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/port/win.py2
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/print_web_test_times.py (renamed from chromium/third_party/blink/tools/blinkpy/web_tests/print_layout_test_times.py)0
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/print_web_test_times_unittest.py (renamed from chromium/third_party/blink/tools/blinkpy/web_tests/print_layout_test_times_unittest.py)4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py20
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py92
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py12
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py8
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py9
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py40
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/try_flag.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py16
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py4
-rw-r--r--chromium/third_party/blink/tools/blinkpy/web_tests/views/printing.py2
-rwxr-xr-xchromium/third_party/blink/tools/check_testharness_expected_pass.py4
-rwxr-xr-xchromium/third_party/blink/tools/debug_renderer18
-rwxr-xr-xchromium/third_party/blink/tools/print_web_test_times.py4
-rwxr-xr-xchromium/third_party/blink/tools/run_blink_httpd.py8
-rwxr-xr-xchromium/third_party/blink/tools/run_blink_websocketserver.py2
-rwxr-xr-xchromium/third_party/blink/tools/run_blink_wptserve.py2
4094 files changed, 151377 insertions, 141913 deletions
diff --git a/chromium/third_party/blink/API_OWNERS b/chromium/third_party/blink/API_OWNERS
index 6d9b32929b1..30b7d7d0084 100644
--- a/chromium/third_party/blink/API_OWNERS
+++ b/chromium/third_party/blink/API_OWNERS
@@ -12,4 +12,4 @@ ojan@chromium.org
rbyers@chromium.org
slightlyoff@chromium.org
tkent@chromium.org
-yoav@yoav.ws
+yoavweiss@chromium.org
diff --git a/chromium/third_party/blink/OWNERS b/chromium/third_party/blink/OWNERS
index de94b8f70c5..5b809e12698 100644
--- a/chromium/third_party/blink/OWNERS
+++ b/chromium/third_party/blink/OWNERS
@@ -6,10 +6,9 @@ darin@chromium.org
foolip@chromium.org
jochen@chromium.org
mkwst@chromium.org
-ojan@chromium.org
rbyers@chromium.org
tkent@chromium.org
-yoav@yoav.ws
+yoavweiss@chromium.org
# For *.gn* changes only.
dpranke@chromium.org
diff --git a/chromium/third_party/blink/common/BUILD.gn b/chromium/third_party/blink/common/BUILD.gn
index 8be06c3c9ec..7cc97b3eca3 100644
--- a/chromium/third_party/blink/common/BUILD.gn
+++ b/chromium/third_party/blink/common/BUILD.gn
@@ -38,8 +38,15 @@ jumbo_source_set("common") {
"indexeddb/indexeddb_key_path.cc",
"indexeddb/indexeddb_key_range.cc",
"indexeddb/indexeddb_metadata.cc",
+ "loader/url_loader_factory_bundle.cc",
+ "loader/url_loader_factory_bundle_mojom_traits.cc",
"manifest/manifest.cc",
"manifest/manifest_icon_selector.cc",
+ "mediastream/media_devices.cc",
+ "mediastream/media_devices_mojom_traits.cc",
+ "mediastream/media_stream_controls.cc",
+ "mediastream/media_stream_mojom_traits.cc",
+ "mediastream/media_stream_request.cc",
"messaging/cloneable_message.cc",
"messaging/cloneable_message_struct_traits.cc",
"messaging/message_port_channel.cc",
@@ -69,6 +76,7 @@ jumbo_source_set("common") {
"//base",
"//mojo/public/cpp/system",
"//net",
+ "//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp:cpp",
]
@@ -77,7 +85,7 @@ jumbo_source_set("common") {
deps += [ "//media" ]
}
- if (is_android) {
+ if (is_android || is_win) {
sources += [
"font_unique_name_lookup/font_table_matcher.cc",
"font_unique_name_lookup/icu_fold_case_util.cc",
@@ -115,6 +123,7 @@ jumbo_source_set("common_unittests_sources") {
"frame/user_activation_state_unittest.cc",
"indexeddb/indexeddb_key_unittest.cc",
"manifest/manifest_icon_selector_unittest.cc",
+ "mediastream/media_devices_unittest.cc",
"mime_util/mime_util_unittest.cc",
"notifications/notification_struct_traits_unittest.cc",
"origin_policy/origin_policy_unittest.cc",
@@ -142,8 +151,9 @@ jumbo_source_set("common_unittests_sources") {
# they are excluded as they require V8 environment but V8 snapshot is
# not available in the current minimum test setting.
sources += [ "messaging/string_message_codec_unittest.cc" ]
- } else {
- # is_android
+ }
+
+ if (is_android || is_win) {
sources += [
"font_unique_name_lookup/font_table_matcher_unittest.cc",
"font_unique_name_lookup/icu_fold_case_util_unittest.cc",
diff --git a/chromium/third_party/blink/common/DEPS b/chromium/third_party/blink/common/DEPS
index 1063c9cccbb..b64c82e33d7 100644
--- a/chromium/third_party/blink/common/DEPS
+++ b/chromium/third_party/blink/common/DEPS
@@ -9,7 +9,9 @@ include_rules = [
"+base",
"+build",
"+net",
+ "+media",
"+mojo",
+ "+services/metrics/public/cpp",
"+services/network/public/cpp",
"+skia/public/interfaces/bitmap_skbitmap_struct_traits.h",
"+testing/gmock/include/gmock",
diff --git a/chromium/third_party/blink/common/client_hints/client_hints.cc b/chromium/third_party/blink/common/client_hints/client_hints.cc
index a340bd02ea9..a4bc77cdf7c 100644
--- a/chromium/third_party/blink/common/client_hints/client_hints.cc
+++ b/chromium/third_party/blink/common/client_hints/client_hints.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/public/common/client_hints/client_hints.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
namespace blink {
@@ -13,7 +13,7 @@ const char* const kClientHintsHeaderMapping[] = {
"rtt", "downlink", "ect"};
const size_t kClientHintsHeaderMappingCount =
- arraysize(kClientHintsHeaderMapping);
+ base::size(kClientHintsHeaderMapping);
const char* const kWebEffectiveConnectionTypeMapping[] = {
"4g" /* Unknown */, "4g" /* Offline */, "slow-2g" /* Slow 2G */,
@@ -21,6 +21,6 @@ const char* const kWebEffectiveConnectionTypeMapping[] = {
};
const size_t kWebEffectiveConnectionTypeMappingCount =
- arraysize(kWebEffectiveConnectionTypeMapping);
+ base::size(kWebEffectiveConnectionTypeMapping);
} // namespace blink
diff --git a/chromium/third_party/blink/common/download/download_stats.cc b/chromium/third_party/blink/common/download/download_stats.cc
index 01df16406cb..9db43e777e0 100644
--- a/chromium/third_party/blink/common/download/download_stats.cc
+++ b/chromium/third_party/blink/common/download/download_stats.cc
@@ -5,18 +5,59 @@
#include "third_party/blink/public/common/download/download_stats.h"
#include "base/metrics/histogram_macros.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
namespace blink {
-// static
-void DownloadStats::RecordMainFrameHasGesture(bool gesture) {
- UMA_HISTOGRAM_BOOLEAN("Download.MainFrame.HasGesture", gesture);
+unsigned DownloadStats::MainFrameDownloadFlags::ToUmaValue() const {
+ unsigned value = 0;
+ if (has_sandbox)
+ value |= kMainFrameSandboxBit;
+ if (has_gesture)
+ value |= kMainFrameGestureBit;
+ return value;
+}
+
+unsigned DownloadStats::SubframeDownloadFlags::ToUmaValue() const {
+ unsigned value = 0;
+ if (has_sandbox)
+ value |= kSubframeSandboxBit;
+ if (is_cross_origin)
+ value |= kSubframeCrossOriginBit;
+ if (is_ad_frame)
+ value |= kSubframeAdBit;
+ if (has_gesture)
+ value |= kSubframeGestureBit;
+ return value;
+}
+
+void DownloadStats::RecordMainFrameDownloadFlags(
+ const MainFrameDownloadFlags& flags,
+ ukm::SourceId source_id,
+ ukm::UkmRecorder* ukm_recorder) {
+ UMA_HISTOGRAM_ENUMERATION("Download.MainFrame.SandboxGesture",
+ flags.ToUmaValue(), kCountSandboxGesture);
+
+ ukm::builders::MainFrameDownload(source_id)
+ .SetHasSandbox(flags.has_sandbox)
+ .SetHasGesture(flags.has_gesture)
+ .Record(ukm_recorder);
}
// static
-void DownloadStats::RecordSubframeSandboxOriginAdGesture(unsigned value) {
- UMA_HISTOGRAM_ENUMERATION("Download.Subframe.SandboxOriginAdGesture", value,
- kCountSandboxOriginAdGesture);
+void DownloadStats::RecordSubframeDownloadFlags(
+ const SubframeDownloadFlags& flags,
+ ukm::SourceId source_id,
+ ukm::UkmRecorder* ukm_recorder) {
+ UMA_HISTOGRAM_ENUMERATION("Download.Subframe.SandboxOriginAdGesture",
+ flags.ToUmaValue(), kCountSandboxOriginAdGesture);
+
+ ukm::builders::SubframeDownload(source_id)
+ .SetHasSandbox(flags.has_sandbox)
+ .SetIsCrossOrigin(flags.is_cross_origin)
+ .SetIsAdFrame(flags.is_ad_frame)
+ .SetHasGesture(flags.has_gesture)
+ .Record(ukm_recorder);
}
} // namespace blink
diff --git a/chromium/third_party/blink/common/feature_policy/feature_policy.cc b/chromium/third_party/blink/common/feature_policy/feature_policy.cc
index ee6c75224c5..e04a25ca0fc 100644
--- a/chromium/third_party/blink/common/feature_policy/feature_policy.cc
+++ b/chromium/third_party/blink/common/feature_policy/feature_policy.cc
@@ -34,12 +34,10 @@ ParsedFeaturePolicyDeclaration::ParsedFeaturePolicyDeclaration(
mojom::FeaturePolicyFeature feature,
bool matches_all_origins,
bool matches_opaque_src,
- mojom::FeaturePolicyDisposition disposition,
std::vector<url::Origin> origins)
: feature(feature),
matches_all_origins(matches_all_origins),
matches_opaque_src(matches_opaque_src),
- disposition(disposition),
origins(std::move(origins)) {}
ParsedFeaturePolicyDeclaration::ParsedFeaturePolicyDeclaration(
@@ -54,25 +52,11 @@ bool operator==(const ParsedFeaturePolicyDeclaration& lhs,
const ParsedFeaturePolicyDeclaration& rhs) {
if (lhs.feature != rhs.feature)
return false;
- if (lhs.disposition != rhs.disposition)
- return false;
if (lhs.matches_all_origins != rhs.matches_all_origins)
return false;
return lhs.matches_all_origins || (lhs.origins == rhs.origins);
}
-std::unique_ptr<ParsedFeaturePolicy> DirectivesWithDisposition(
- mojom::FeaturePolicyDisposition disposition,
- const ParsedFeaturePolicy& policy) {
- std::unique_ptr<ParsedFeaturePolicy> filtered_policy =
- std::make_unique<ParsedFeaturePolicy>();
- for (const auto& directive : policy) {
- if (directive.disposition == disposition)
- filtered_policy->push_back(directive);
- }
- return filtered_policy;
-}
-
FeaturePolicy::Allowlist::Allowlist() : matches_all_origins_(false) {}
FeaturePolicy::Allowlist::Allowlist(const Allowlist& rhs) = default;
@@ -275,6 +259,8 @@ const FeaturePolicy::FeatureList& FeaturePolicy::GetDefaultFeatureList() {
FeaturePolicy::FeatureDefault::EnableForAll},
{mojom::FeaturePolicyFeature::kEncryptedMedia,
FeaturePolicy::FeatureDefault::EnableForSelf},
+ {mojom::FeaturePolicyFeature::kFontDisplay,
+ FeaturePolicy::FeatureDefault::EnableForAll},
{mojom::FeaturePolicyFeature::kFullscreen,
FeaturePolicy::FeatureDefault::EnableForSelf},
{mojom::FeaturePolicyFeature::kGeolocation,
@@ -313,6 +299,8 @@ const FeaturePolicy::FeatureList& FeaturePolicy::GetDefaultFeatureList() {
FeaturePolicy::FeatureDefault::EnableForSelf},
{mojom::FeaturePolicyFeature::kVerticalScroll,
FeaturePolicy::FeatureDefault::EnableForAll},
+ {mojom::FeaturePolicyFeature::kWakeLock,
+ FeaturePolicy::FeatureDefault::EnableForSelf},
{mojom::FeaturePolicyFeature::kWebVr,
FeaturePolicy::FeatureDefault::EnableForSelf}});
return *default_feature_list;
diff --git a/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.cc b/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.cc
index d96a6b53cf6..468be4cc271 100644
--- a/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.cc
+++ b/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.cc
@@ -13,7 +13,6 @@ bool StructTraits<blink::mojom::ParsedFeaturePolicyDeclarationDataView,
Read(blink::mojom::ParsedFeaturePolicyDeclarationDataView in,
blink::ParsedFeaturePolicyDeclaration* out) {
out->matches_all_origins = in.matches_all_origins();
- out->disposition = in.disposition();
return in.ReadOrigins(&out->origins) && in.ReadFeature(&out->feature);
}
diff --git a/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.h b/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.h
index c0fe8eec215..8f8bfb971f0 100644
--- a/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.h
+++ b/chromium/third_party/blink/common/feature_policy/feature_policy_mojom_traits.h
@@ -83,10 +83,6 @@ class BLINK_COMMON_EXPORT
const blink::ParsedFeaturePolicyDeclaration& policy) {
return policy.matches_all_origins;
}
- static blink::mojom::FeaturePolicyDisposition disposition(
- const blink::ParsedFeaturePolicyDeclaration& policy) {
- return policy.disposition;
- }
static const std::vector<url::Origin>& origins(
const blink::ParsedFeaturePolicyDeclaration& policy) {
return policy.origins;
diff --git a/chromium/third_party/blink/common/feature_policy/feature_policy_unittest.cc b/chromium/third_party/blink/common/feature_policy/feature_policy_unittest.cc
index 1f8294faf2b..ccbfdd96381 100644
--- a/chromium/third_party/blink/common/feature_policy/feature_policy_unittest.cc
+++ b/chromium/third_party/blink/common/feature_policy/feature_policy_unittest.cc
@@ -146,7 +146,6 @@ TEST_F(FeaturePolicyTest, TestCrossOriginChildCannotEnableFeature) {
policy2->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature));
}
@@ -172,7 +171,6 @@ TEST_F(FeaturePolicyTest, TestFrameSelfInheritance) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_a_);
@@ -208,7 +206,6 @@ TEST_F(FeaturePolicyTest, TestReflexiveFrameSelfInheritance) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -239,7 +236,6 @@ TEST_F(FeaturePolicyTest, TestSelectiveFrameInheritance) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -261,7 +257,6 @@ TEST_F(FeaturePolicyTest, TestPolicyCanBlockSelf) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultOnFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
EXPECT_FALSE(policy1->IsFeatureEnabled(kDefaultOnFeature));
}
@@ -279,7 +274,6 @@ TEST_F(FeaturePolicyTest, TestParentPolicyBlocksSameOriginChildPolicy) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultOnFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_a_);
@@ -301,7 +295,6 @@ TEST_F(FeaturePolicyTest, TestChildPolicyCanBlockSelf) {
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
policy2->SetHeaderPolicy({{{kDefaultOnFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature));
}
@@ -328,7 +321,6 @@ TEST_F(FeaturePolicyTest, TestChildPolicyCanBlockChildren) {
policy2->SetHeaderPolicy({{{kDefaultOnFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentPolicy(policy2.get(), origin_c_);
@@ -349,7 +341,6 @@ TEST_F(FeaturePolicyTest, TestParentPolicyBlocksCrossOriginChildPolicy) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultOnFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -373,7 +364,6 @@ TEST_F(FeaturePolicyTest, TestEnableForAllOrigins) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -403,7 +393,6 @@ TEST_F(FeaturePolicyTest, TestDefaultOnEnablesForAllAncestors) {
policy1->SetHeaderPolicy({{{kDefaultOnFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -436,7 +425,6 @@ TEST_F(FeaturePolicyTest, TestDefaultSelfRespectsSameOriginEmbedding) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -469,14 +457,12 @@ TEST_F(FeaturePolicyTest, TestDefaultOffMustBeDelegatedToAllCrossOriginFrames) {
policy1->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
policy2->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentPolicy(policy2.get(), origin_b_);
@@ -485,7 +471,6 @@ TEST_F(FeaturePolicyTest, TestDefaultOffMustBeDelegatedToAllCrossOriginFrames) {
policy4->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_c_}}}});
EXPECT_FALSE(policy1->IsFeatureEnabled(kDefaultOffFeature));
EXPECT_TRUE(policy2->IsFeatureEnabled(kDefaultOffFeature));
@@ -510,12 +495,10 @@ TEST_F(FeaturePolicyTest, TestReenableForAllOrigins) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
policy2->SetHeaderPolicy({{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentPolicy(policy2.get(), origin_a_);
@@ -543,12 +526,10 @@ TEST_F(FeaturePolicyTest, TestBlockedFrameCannotReenable) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
policy2->SetHeaderPolicy({{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentPolicy(policy2.get(), origin_a_);
@@ -579,14 +560,12 @@ TEST_F(FeaturePolicyTest, TestEnabledFrameCanDelegate) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_, origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
policy2->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_, origin_c_}}}});
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentPolicy(policy2.get(), origin_c_);
@@ -614,7 +593,6 @@ TEST_F(FeaturePolicyTest, TestEnabledFrameCanDelegateByDefault) {
policy1->SetHeaderPolicy({{{kDefaultOnFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_, origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -648,7 +626,6 @@ TEST_F(FeaturePolicyTest, TestNonNestedFeaturesDontDelegateByDefault) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_, origin_b_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
@@ -684,21 +661,16 @@ TEST_F(FeaturePolicyTest, TestFeaturesAreIndependent) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_, origin_b_}},
{kDefaultOnFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentPolicy(policy1.get(), origin_b_);
policy2->SetHeaderPolicy(
- {{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce, std::vector<url::Origin>()},
- {kDefaultOnFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
- std::vector<url::Origin>()}}});
+ {{{kDefaultSelfFeature, true, false, std::vector<url::Origin>()},
+ {kDefaultOnFeature, true, false, std::vector<url::Origin>()}}});
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentPolicy(policy2.get(), origin_c_);
EXPECT_TRUE(policy1->IsFeatureEnabled(kDefaultSelfFeature));
@@ -721,7 +693,6 @@ TEST_F(FeaturePolicyTest, TestFeatureEnabledForOrigin) {
policy1->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_, origin_b_}}}});
EXPECT_TRUE(
policy1->IsFeatureEnabledForOrigin(kDefaultOffFeature, origin_a_));
@@ -754,7 +725,6 @@ TEST_F(FeaturePolicyTest, TestSimpleFramePolicy) {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_);
@@ -791,7 +761,6 @@ TEST_F(FeaturePolicyTest, TestAllOriginFramePolicy) {
CreateFromParentPolicy(nullptr, origin_a_);
ParsedFeaturePolicy frame_policy = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_);
@@ -841,7 +810,6 @@ TEST_F(FeaturePolicyTest, TestFramePolicyCanBeFurtherDelegated) {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_);
@@ -849,7 +817,6 @@ TEST_F(FeaturePolicyTest, TestFramePolicyCanBeFurtherDelegated) {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_c_}}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy2.get(), frame_policy2, origin_c_);
@@ -892,13 +859,11 @@ TEST_F(FeaturePolicyTest, TestDefaultOnCanBeDisabledByFramePolicy) {
CreateFromParentPolicy(nullptr, origin_a_);
ParsedFeaturePolicy frame_policy1 = {
{{kDefaultOnFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_a_);
ParsedFeaturePolicy frame_policy2 = {
{{kDefaultOnFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_);
@@ -943,13 +908,11 @@ TEST_F(FeaturePolicyTest, TestDefaultOffMustBeEnabledByChildFrame) {
policy1->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
ParsedFeaturePolicy frame_policy1 = {
{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_a_);
@@ -957,7 +920,6 @@ TEST_F(FeaturePolicyTest, TestDefaultOffMustBeEnabledByChildFrame) {
{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_);
@@ -1006,33 +968,28 @@ TEST_F(FeaturePolicyTest, TestDefaultOffCanBeEnabledByChildFrame) {
policy1->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
ParsedFeaturePolicy frame_policy1 = {
{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_a_);
policy2->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}});
ParsedFeaturePolicy frame_policy2 = {
{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_);
policy3->SetHeaderPolicy({{{kDefaultOffFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
EXPECT_TRUE(
policy1->IsFeatureEnabledForOrigin(kDefaultOffFeature, origin_a_));
@@ -1080,24 +1037,20 @@ TEST_F(FeaturePolicyTest, TestFramePolicyModifiesHeaderPolicy) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_, origin_b_}}}});
ParsedFeaturePolicy frame_policy1 = {
{{kDefaultSelfFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_);
ParsedFeaturePolicy frame_policy2 = {
{{kDefaultSelfFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_);
policy3->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
EXPECT_FALSE(
policy2->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_b_));
@@ -1136,16 +1089,13 @@ TEST_F(FeaturePolicyTest, TestCombineFrameAndHeaderPolicies) {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_);
policy2->SetHeaderPolicy({{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
ParsedFeaturePolicy frame_policy2 = {
{{kDefaultSelfFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy2.get(), frame_policy2, origin_c_);
@@ -1182,19 +1132,16 @@ TEST_F(FeaturePolicyTest, TestFeatureDeclinedAtTopLevel) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultSelfFeature, false, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
ParsedFeaturePolicy frame_policy1 = {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_);
ParsedFeaturePolicy frame_policy2 = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_a_);
@@ -1236,13 +1183,11 @@ TEST_F(FeaturePolicyTest, TestFeatureDelegatedAndAllowed) {
policy1->SetHeaderPolicy({{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}});
ParsedFeaturePolicy frame_policy1 = {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_a_}}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_);
@@ -1250,13 +1195,11 @@ TEST_F(FeaturePolicyTest, TestFeatureDelegatedAndAllowed) {
{{kDefaultSelfFeature,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{origin_b_}}}};
std::unique_ptr<FeaturePolicy> policy3 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_);
ParsedFeaturePolicy frame_policy3 = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy4 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy3, origin_b_);
@@ -1324,7 +1267,6 @@ TEST_F(FeaturePolicyTest, TestSandboxedFramePolicyForAllOrigins) {
url::Origin sandboxed_origin = url::Origin();
ParsedFeaturePolicy frame_policy = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 = CreateFromParentWithFramePolicy(
policy1.get(), frame_policy, sandboxed_origin);
@@ -1357,7 +1299,6 @@ TEST_F(FeaturePolicyTest, TestSandboxedFramePolicyForOpaqueSrcOrigin) {
url::Origin sandboxed_origin = url::Origin();
ParsedFeaturePolicy frame_policy = {
{{kDefaultSelfFeature, false, true,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 = CreateFromParentWithFramePolicy(
policy1.get(), frame_policy, sandboxed_origin);
@@ -1387,12 +1328,10 @@ TEST_F(FeaturePolicyTest, TestSandboxedFrameFromHeaderPolicy) {
std::unique_ptr<FeaturePolicy> policy1 =
CreateFromParentPolicy(nullptr, origin_a_);
policy1->SetHeaderPolicy({{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}});
url::Origin sandboxed_origin = url::Origin();
ParsedFeaturePolicy frame_policy = {
{{kDefaultSelfFeature, false, true,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 = CreateFromParentWithFramePolicy(
policy1.get(), frame_policy, sandboxed_origin);
@@ -1427,7 +1366,6 @@ TEST_F(FeaturePolicyTest, TestSandboxedPolicyIsNotInherited) {
url::Origin sandboxed_origin_2 = url::Origin();
ParsedFeaturePolicy frame_policy = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 = CreateFromParentWithFramePolicy(
policy1.get(), frame_policy, sandboxed_origin_1);
@@ -1473,13 +1411,11 @@ TEST_F(FeaturePolicyTest, TestSandboxedPolicyCanBePropagated) {
url::Origin sandboxed_origin_2 = sandboxed_origin_1.DeriveNewOpaqueOrigin();
ParsedFeaturePolicy frame_policy_1 = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 = CreateFromParentWithFramePolicy(
policy1.get(), frame_policy_1, sandboxed_origin_1);
ParsedFeaturePolicy frame_policy_2 = {
{{kDefaultSelfFeature, true, false,
- mojom::FeaturePolicyDisposition::kEnforce,
std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy3 = CreateFromParentWithFramePolicy(
policy2.get(), frame_policy_2, sandboxed_origin_2);
@@ -1512,10 +1448,8 @@ TEST_F(FeaturePolicyTest, TestUndefinedFeaturesInFramePolicy) {
CreateFromParentPolicy(nullptr, origin_a_);
ParsedFeaturePolicy frame_policy = {
{{mojom::FeaturePolicyFeature::kNotFound, false, true,
- mojom::FeaturePolicyDisposition::kEnforce, std::vector<url::Origin>()},
- {kUnavailableFeature, false, true,
- mojom::FeaturePolicyDisposition::kEnforce,
- std::vector<url::Origin>()}}};
+ std::vector<url::Origin>()},
+ {kUnavailableFeature, false, true, std::vector<url::Origin>()}}};
std::unique_ptr<FeaturePolicy> policy2 =
CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_);
EXPECT_FALSE(PolicyContainsInheritedValue(
@@ -1528,19 +1462,4 @@ TEST_F(FeaturePolicyTest, TestUndefinedFeaturesInFramePolicy) {
PolicyContainsInheritedValue(policy2.get(), kUnavailableFeature));
}
-TEST_F(FeaturePolicyTest, TestReportOnlyFeaturesIncludedInHeader) {
- // +---------------------------------------------------+
- // |(1)Origin A |
- // |Feature-Policy: default-self-report-only 'none' |
- // +---------------------------------------------------+
- // A feature which is tagged as '-report-only' should be included in the
- // reporting policy.
- std::unique_ptr<FeaturePolicy> policy1 =
- CreateFromParentPolicy(nullptr, origin_a_);
- policy1->SetHeaderPolicy({{{kDefaultSelfFeature, false, false,
- mojom::FeaturePolicyDisposition::kReport,
- std::vector<url::Origin>()}}});
- EXPECT_FALSE(policy1->IsFeatureEnabled(kDefaultSelfFeature));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/common/features.cc b/chromium/third_party/blink/common/features.cc
index 01989a42d38..0c0ea5ae8d9 100644
--- a/chromium/third_party/blink/common/features.cc
+++ b/chromium/third_party/blink/common/features.cc
@@ -12,6 +12,10 @@ namespace features {
const base::Feature kAutofillPreviewStyleExperiment{
"AutofillPreviewStyleExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enable defer commits a bit to avoid flash.
+const base::Feature kAvoidFlashBetweenNavigation{
+ "AvoidFlashBetweenNavigation", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable eagerly setting up a CacheStorage interface pointer and
// passing it to service workers on startup as an optimization.
const base::Feature kEagerCacheStorageSetupForServiceWorkers{
@@ -24,6 +28,10 @@ const base::Feature kEnableGpuRasterizationViewportRestriction{
"EnableGpuRasterizationViewportRestriction",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls script streaming.
+const base::Feature kScriptStreaming{"ScriptStreaming",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// Enable FCP++ by experiment. See https://crbug.com/869924
const base::Feature kFirstContentfulPaintPlusPlus{
"FirstContentfulPaintPlusPlus", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -33,6 +41,9 @@ const base::Feature kFirstContentfulPaintPlusPlus{
const base::Feature kJankTracking{"JankTracking",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kJankTrackingSweepLine{"JankTrackingSweepLine",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable a new compositing mode called BlinkGenPropertyTrees where Blink
// generates the compositor property trees. See: https://crbug.com/836884.
const base::Feature kBlinkGenPropertyTrees{"BlinkGenPropertyTrees",
@@ -49,16 +60,30 @@ const base::Feature kMixedContentAutoupgrade{"AutoupgradeMixedContent",
const base::Feature kMojoBlobURLs{"MojoBlobURLs",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Used to control the collection of anchor element metrics (crbug.com/856683).
+// If kNavigationPredictor is enabled, then metrics of anchor elements
+// in the first viewport after the page load and the metrics of the clicked
+// anchor element will be extracted and recorded. Additionally, navigation
+// predictor may preconnect/prefetch to resources/origins to make the
+// future navigations faster.
+const base::Feature kNavigationPredictor{"NavigationPredictor",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Onion souping for all DOMStorage. https://crbug.com/781870
const base::Feature kOnionSoupDOMStorage{"OnionSoupDOMStorage",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enable browser-initiated dedicated worker script loading
+// (PlzDedicatedWorker). https://crbug.com/906991
+const base::Feature kPlzDedicatedWorker{"PlzDedicatedWorker",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable Portals. https://crbug.com/865123.
const base::Feature kPortals{"Portals", base::FEATURE_DISABLED_BY_DEFAULT};
// Enable Implicit Root Scroller. https://crbug.com/903260.
const base::Feature kImplicitRootScroller{"ImplicitRootScroller",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Enables usage of getDisplayMedia() that allows capture of web content, see
// https://crbug.com/865060.
@@ -70,18 +95,21 @@ const base::Feature kRTCGetDisplayMedia{"RTCGetDisplayMedia",
// unless the default is overridden (by passing {sdpSemantics:'plan-b'} as the
// argument).
const base::Feature kRTCUnifiedPlanByDefault{"RTCUnifiedPlanByDefault",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Determines if the SDP attrbute extmap-allow-mixed should be offered by
+// default or not. The default value can be overridden by passing
+// {offerExtmapAllowMixed:true} as an argument to the RTCPeerConnection
+// constructor.
+const base::Feature kRTCOfferExtmapAllowMixed{
+ "RTCOfferExtmapAllowMixed", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables to load the response body through Mojo data pipe passed by
+// WebURLLoaderClient::DidStartLoadingResponseBody() instead of
+// WebURLLoaderClient::DidReceiveData().
+const base::Feature kResourceLoadViaDataPipe{"ResourceLoadViaDataPipe",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Used to control the collection of anchor element metrics (crbug.com/856683).
-// If kRecordAnchorMetricsClicked is enabled, then metrics of anchor elements
-// clicked by the user will be extracted and recorded.
-// If kRecordAnchorMetricsVisible is enabled, then metrics of anchor elements
-// in the first viewport after the page load will be extracted and recorded.
-const base::Feature kRecordAnchorMetricsClicked{
- "RecordAnchorMetricsClicked", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kRecordAnchorMetricsVisible{
- "RecordAnchorMetricsVisible", base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kServiceWorkerImportedScriptUpdateCheck{
"ServiceWorkerImportedScriptUpdateCheck",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -90,6 +118,9 @@ const base::Feature kServiceWorkerImportedScriptUpdateCheck{
const base::Feature kServiceWorkerParallelSideDataReading{
"ServiceWorkerParallelSideDataReading", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kServiceWorkerAggressiveCodeCache{
+ "ServiceWorkerAggressiveCodeCache", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable new service worker glue for NetworkService. Can be
// enabled independently of NetworkService.
const base::Feature kServiceWorkerServicification{
@@ -127,6 +158,10 @@ const base::Feature kWasmCodeCache = {"WasmCodeCache",
const base::Feature kWritableFilesAPI{"WritableFilesAPI",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Allows for synchronous XHR requests during page dismissal
+const base::Feature kForbidSyncXHRInPageDismissal{
+ "ForbidSyncXHRInPageDismissal", base::FEATURE_DISABLED_BY_DEFAULT};
+
const char kAutofillPreviewStyleExperimentBgColorParameterName[] = "bg_color";
const char kAutofillPreviewStyleExperimentColorParameterName[] = "color";
@@ -136,5 +171,18 @@ const char kMixedContentAutoupgradeModeBlockable[] = "blockable";
const char kMixedContentAutoupgradeModeOptionallyBlockable[] =
"optionally-blockable";
+// Decodes lossy WebP images to YUV instead of RGBX and stores in this format
+// in the image decode cache. See crbug.com/900264 for details on the feature.
+const base::Feature kDecodeLossyWebPImagesToYUV{
+ "DecodeLossyWebPImagesToYUV", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Use accelerated canvases whenever possible see https://crbug.com/909937
+const base::Feature kAlwaysAccelerateCanvas{"AlwaysAccelerateCanvas",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables cache-aware WebFonts loading. See https://crbug.com/570205.
+const base::Feature kWebFontsCacheAwareTimeoutAdaption{
+ "WebFontsCacheAwareTimeoutAdaption", base::FEATURE_ENABLED_BY_DEFAULT};
+
} // namespace features
} // namespace blink
diff --git a/chromium/third_party/blink/common/font_unique_name_lookup/OWNERS b/chromium/third_party/blink/common/font_unique_name_lookup/OWNERS
new file mode 100644
index 00000000000..58196726758
--- /dev/null
+++ b/chromium/third_party/blink/common/font_unique_name_lookup/OWNERS
@@ -0,0 +1,3 @@
+drott@chromium.org
+
+# COMPONENT: Blink>Fonts
diff --git a/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc b/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc
index b647d2689ba..556374f746c 100644
--- a/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc
+++ b/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc
@@ -31,32 +31,42 @@ FontTableMatcher::MemoryMappingFromFontUniqueNameTable(
base::Optional<FontTableMatcher::MatchResult> FontTableMatcher::MatchName(
const std::string& name_request) const {
std::string folded_name_request = IcuFoldCase(name_request);
- const auto& font_entries = font_table_.font_entries();
- auto find_result = std::find_if(
- font_entries.begin(), font_entries.end(),
- [&folded_name_request](
- const FontUniqueNameTable_FontUniqueNameEntry& entry) {
- return !entry.postscript_name().compare(folded_name_request) ||
- !entry.full_name().compare(folded_name_request);
+
+ const auto& name_map = font_table_.name_map();
+
+ auto find_result = std::lower_bound(
+ name_map.begin(), name_map.end(), folded_name_request,
+ [](const blink::FontUniqueNameTable_UniqueNameToFontMapping& a,
+ const std::string& b) {
+ // Comp predicate for std::lower_bound needs to return whether a < b,
+ // so that it can find a match for "not less than".
+ return a.font_name() < b;
});
- if (find_result != font_entries.end()) {
- return base::Optional<MatchResult>(
- {find_result->file_path(), find_result->ttc_index()});
+ if (find_result == name_map.end() ||
+ find_result->font_name() != folded_name_request ||
+ static_cast<int>(find_result->font_index()) > font_table_.fonts_size()) {
+ return {};
}
- return {};
+
+ const auto& found_font = font_table_.fonts()[find_result->font_index()];
+
+ if (!found_font.file_path().size())
+ return {};
+ return base::Optional<MatchResult>(
+ {found_font.file_path(), found_font.ttc_index()});
}
size_t FontTableMatcher::AvailableFonts() const {
- return font_table_.font_entries_size();
+ return font_table_.fonts_size();
}
bool FontTableMatcher::FontListIsDisjointFrom(
const FontTableMatcher& other) const {
std::vector<std::string> paths_self, paths_other, intersection_result;
- for (const auto& indexed_font : font_table_.font_entries()) {
+ for (const auto& indexed_font : font_table_.fonts()) {
paths_self.push_back(indexed_font.file_path());
}
- for (const auto& indexed_font_other : other.font_table_.font_entries()) {
+ for (const auto& indexed_font_other : other.font_table_.fonts()) {
paths_other.push_back(indexed_font_other.file_path());
}
std::sort(paths_self.begin(), paths_self.end());
diff --git a/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher_unittest.cc b/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher_unittest.cc
index 6fd6fb9c6b2..a0103f46bed 100644
--- a/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher_unittest.cc
+++ b/chromium/third_party/blink/common/font_unique_name_lookup/font_table_matcher_unittest.cc
@@ -11,15 +11,25 @@ const char kTestFilePath1[] = "tmp/test/font1.ttf";
const char kDummyAndroidBuildFingerPrint[] = "A";
void PopulateFontUniqueNameEntry(
- blink::FontUniqueNameTable_FontUniqueNameEntry* entry,
+ blink::FontUniqueNameTable* font_unique_name_table,
const std::string& path,
int32_t ttc_index,
- const std::string& full_name,
- const std::string& postscript_name) {
- entry->set_file_path(path);
- entry->set_ttc_index(ttc_index);
- entry->set_full_name(blink::IcuFoldCase(full_name));
- entry->set_postscript_name(blink::IcuFoldCase(postscript_name));
+ const std::set<std::string>& names) {
+ auto* font_entry = font_unique_name_table->add_fonts();
+ font_entry->set_file_path(path);
+ font_entry->set_ttc_index(ttc_index);
+
+ std::set<std::string> names_folded;
+ for (auto& name : names) {
+ names_folded.insert(blink::IcuFoldCase(name));
+ }
+
+ // Set iteration will return values in sorted order.
+ for (auto& name : names_folded) {
+ auto* names_entry = font_unique_name_table->add_name_map();
+ names_entry->set_font_name(name);
+ names_entry->set_font_index(0);
+ }
}
} // namespace
@@ -30,11 +40,12 @@ class FontTableMatcherTest : public ::testing::Test {
protected:
void SetUp() override {
FontUniqueNameTable font_unique_name_table;
- font_unique_name_table.set_stored_for_android_build_fp(
+ font_unique_name_table.set_stored_for_platform_version_identifier(
kDummyAndroidBuildFingerPrint);
- PopulateFontUniqueNameEntry(font_unique_name_table.add_font_entries(),
- kTestFilePath1, 0, "FONT NAME UPPERCASE",
- "FONT-NAME-UPPERCASE");
+ PopulateFontUniqueNameEntry(
+ &font_unique_name_table, kTestFilePath1, 0,
+ {u8"FONT NAME UPPERCASE", u8"எழுத்துரு பெயர்", u8"字體名稱",
+ u8"FONT-NAME-UPPERCASE", u8"எழுத்துரு-பெயர்", u8"字體名稱"});
base::ReadOnlySharedMemoryMapping mapping =
FontTableMatcher::MemoryMappingFromFontUniqueNameTable(
std::move(font_unique_name_table));
@@ -59,6 +70,22 @@ TEST_F(FontTableMatcherTest, CaseInsensitiveMatchingBothNames) {
ASSERT_EQ(result->ttc_index, 0u);
}
+TEST_F(FontTableMatcherTest, MatchTamilChinese) {
+ ASSERT_EQ(matcher_->AvailableFonts(), 1u);
+ for (std::string font_name :
+ {u8"எழுத்துரு பெயர்", u8"எழுத்துரு-பெயர்", u8"字體名稱"}) {
+ base::Optional<FontTableMatcher::MatchResult> result =
+ matcher_->MatchName(font_name);
+ ASSERT_TRUE(result.has_value());
+ ASSERT_EQ(result->font_path, kTestFilePath1);
+ ASSERT_EQ(result->ttc_index, 0u);
+
+ base::Optional<FontTableMatcher::MatchResult> result_for_substring =
+ matcher_->MatchName(font_name.substr(0, font_name.size() - 2u));
+ ASSERT_FALSE(result_for_substring.has_value());
+ }
+}
+
TEST_F(FontTableMatcherTest, NoSubStringMatching) {
ASSERT_EQ(matcher_->AvailableFonts(), 1u);
base::Optional<FontTableMatcher::MatchResult> result =
diff --git a/chromium/third_party/blink/common/indexeddb/indexed_db_default_mojom_traits.cc b/chromium/third_party/blink/common/indexeddb/indexed_db_default_mojom_traits.cc
index 0a3ec516995..7dee3092242 100644
--- a/chromium/third_party/blink/common/indexeddb/indexed_db_default_mojom_traits.cc
+++ b/chromium/third_party/blink/common/indexeddb/indexed_db_default_mojom_traits.cc
@@ -26,16 +26,16 @@ bool StructTraits<blink::mojom::IDBDatabaseMetadataDataView,
return false;
out->version = data.version();
out->max_object_store_id = data.max_object_store_id();
- ArrayDataView<blink::mojom::IDBObjectStoreMetadataDataView> object_stores;
+ MapDataView<int64_t, blink::mojom::IDBObjectStoreMetadataDataView>
+ object_stores;
data.GetObjectStoresDataView(&object_stores);
for (size_t i = 0; i < object_stores.size(); ++i) {
- blink::mojom::IDBObjectStoreMetadataDataView object_store;
- object_stores.GetDataView(i, &object_store);
- DCHECK(!base::ContainsKey(out->object_stores, object_store.id()));
- if (!StructTraits<blink::mojom::IDBObjectStoreMetadataDataView,
- blink::IndexedDBObjectStoreMetadata>::
- Read(object_store, &out->object_stores[object_store.id()]))
+ const int64_t key = object_stores.keys()[i];
+ blink::IndexedDBObjectStoreMetadata object_store;
+ if (!object_stores.values().Read(i, &object_store))
return false;
+ DCHECK_EQ(out->object_stores.count(key), 0UL);
+ out->object_stores[key] = object_store;
}
return true;
}
@@ -69,25 +69,26 @@ blink::mojom::IDBKeyDataDataView::Tag
UnionTraits<blink::mojom::IDBKeyDataDataView, blink::IndexedDBKey>::GetTag(
const blink::IndexedDBKey& key) {
switch (key.type()) {
- case blink::kWebIDBKeyTypeArray:
+ case blink::mojom::IDBKeyType::Array:
return blink::mojom::IDBKeyDataDataView::Tag::KEY_ARRAY;
- case blink::kWebIDBKeyTypeBinary:
+ case blink::mojom::IDBKeyType::Binary:
return blink::mojom::IDBKeyDataDataView::Tag::BINARY;
- case blink::kWebIDBKeyTypeString:
+ case blink::mojom::IDBKeyType::String:
return blink::mojom::IDBKeyDataDataView::Tag::STRING;
- case blink::kWebIDBKeyTypeDate:
+ case blink::mojom::IDBKeyType::Date:
return blink::mojom::IDBKeyDataDataView::Tag::DATE;
- case blink::kWebIDBKeyTypeNumber:
+ case blink::mojom::IDBKeyType::Number:
return blink::mojom::IDBKeyDataDataView::Tag::NUMBER;
- case blink::kWebIDBKeyTypeInvalid:
- case blink::kWebIDBKeyTypeNull:
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER;
+ case blink::mojom::IDBKeyType::Invalid:
+ return blink::mojom::IDBKeyDataDataView::Tag::OTHER_INVALID;
+ case blink::mojom::IDBKeyType::Null:
+ return blink::mojom::IDBKeyDataDataView::Tag::OTHER_NULL;
// Not used, fall through to NOTREACHED.
- case blink::kWebIDBKeyTypeMin:;
+ case blink::mojom::IDBKeyType::Min:;
}
NOTREACHED();
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER;
+ return blink::mojom::IDBKeyDataDataView::Tag::OTHER_INVALID;
}
// static
@@ -117,20 +118,18 @@ bool UnionTraits<blink::mojom::IDBKeyDataDataView, blink::IndexedDBKey>::Read(
return true;
}
case blink::mojom::IDBKeyDataDataView::Tag::DATE:
- *out = blink::IndexedDBKey(data.date(), blink::kWebIDBKeyTypeDate);
+ *out = blink::IndexedDBKey(data.date(), blink::mojom::IDBKeyType::Date);
return true;
case blink::mojom::IDBKeyDataDataView::Tag::NUMBER:
- *out = blink::IndexedDBKey(data.number(), blink::kWebIDBKeyTypeNumber);
+ *out =
+ blink::IndexedDBKey(data.number(), blink::mojom::IDBKeyType::Number);
+ return true;
+ case blink::mojom::IDBKeyDataDataView::Tag::OTHER_INVALID:
+ *out = blink::IndexedDBKey(blink::mojom::IDBKeyType::Invalid);
+ return true;
+ case blink::mojom::IDBKeyDataDataView::Tag::OTHER_NULL:
+ *out = blink::IndexedDBKey(blink::mojom::IDBKeyType::Null);
return true;
- case blink::mojom::IDBKeyDataDataView::Tag::OTHER:
- switch (data.other()) {
- case blink::mojom::IDBDatalessKeyType::Invalid:
- *out = blink::IndexedDBKey(blink::kWebIDBKeyTypeInvalid);
- return true;
- case blink::mojom::IDBDatalessKeyType::Null:
- *out = blink::IndexedDBKey(blink::kWebIDBKeyTypeNull);
- return true;
- }
}
return false;
@@ -159,16 +158,16 @@ StructTraits<blink::mojom::IDBKeyPathDataView, blink::IndexedDBKeyPath>::data(
auto data = blink::mojom::IDBKeyPathData::New();
switch (key_path.type()) {
- case blink::kWebIDBKeyPathTypeString:
+ case blink::mojom::IDBKeyPathType::String:
data->set_string(key_path.string());
return data;
- case blink::kWebIDBKeyPathTypeArray:
+ case blink::mojom::IDBKeyPathType::Array:
data->set_string_array(key_path.array());
return data;
// The following key path types are not used.
- case blink::kWebIDBKeyPathTypeNull:; // No-op, fall out of switch block to
- // NOTREACHED().
+ case blink::mojom::IDBKeyPathType::Null:; // No-op, fall out of switch
+ // block to NOTREACHED().
}
NOTREACHED();
return data;
@@ -231,17 +230,15 @@ bool StructTraits<blink::mojom::IDBObjectStoreMetadataDataView,
return false;
out->auto_increment = data.auto_increment();
out->max_index_id = data.max_index_id();
- ArrayDataView<blink::mojom::IDBIndexMetadataDataView> indexes;
+ MapDataView<int64_t, blink::mojom::IDBIndexMetadataDataView> indexes;
data.GetIndexesDataView(&indexes);
for (size_t i = 0; i < indexes.size(); ++i) {
- blink::mojom::IDBIndexMetadataDataView index;
- indexes.GetDataView(i, &index);
- DCHECK(!base::ContainsKey(out->indexes, index.id()));
- if (!StructTraits<
- blink::mojom::IDBIndexMetadataDataView,
- blink::IndexedDBIndexMetadata>::Read(index,
- &out->indexes[index.id()]))
+ const int64_t key = indexes.keys()[i];
+ blink::IndexedDBIndexMetadata index;
+ if (!indexes.values().Read(i, &index))
return false;
+ DCHECK_EQ(out->indexes.count(key), 0UL);
+ out->indexes[key] = index;
}
return true;
}
diff --git a/chromium/third_party/blink/common/indexeddb/indexeddb_key.cc b/chromium/third_party/blink/common/indexeddb/indexeddb_key.cc
index b5c331d0f8c..e2fd1e47534 100644
--- a/chromium/third_party/blink/common/indexeddb/indexeddb_key.cc
+++ b/chromium/third_party/blink/common/indexeddb/indexeddb_key.cc
@@ -9,16 +9,6 @@
namespace blink {
-using blink::WebIDBKeyType;
-using blink::kWebIDBKeyTypeArray;
-using blink::kWebIDBKeyTypeBinary;
-using blink::kWebIDBKeyTypeDate;
-using blink::kWebIDBKeyTypeInvalid;
-using blink::kWebIDBKeyTypeMin;
-using blink::kWebIDBKeyTypeNull;
-using blink::kWebIDBKeyTypeNumber;
-using blink::kWebIDBKeyTypeString;
-
namespace {
// Very rough estimate of minimum key size overhead.
@@ -44,33 +34,34 @@ int Compare(const T& a, const T& b) {
} // namespace
IndexedDBKey::IndexedDBKey()
- : type_(kWebIDBKeyTypeNull), size_estimate_(kOverheadSize) {}
+ : type_(mojom::IDBKeyType::Null), size_estimate_(kOverheadSize) {}
-IndexedDBKey::IndexedDBKey(WebIDBKeyType type)
+IndexedDBKey::IndexedDBKey(mojom::IDBKeyType type)
: type_(type), size_estimate_(kOverheadSize) {
- DCHECK(type == kWebIDBKeyTypeNull || type == kWebIDBKeyTypeInvalid);
+ DCHECK(type == mojom::IDBKeyType::Null || type == mojom::IDBKeyType::Invalid);
}
-IndexedDBKey::IndexedDBKey(double number, WebIDBKeyType type)
+IndexedDBKey::IndexedDBKey(double number, mojom::IDBKeyType type)
: type_(type),
number_(number),
size_estimate_(kOverheadSize + sizeof(number)) {
- DCHECK(type == kWebIDBKeyTypeNumber || type == kWebIDBKeyTypeDate);
+ DCHECK(type == blink::mojom::IDBKeyType::Number ||
+ type == blink::mojom::IDBKeyType::Date);
}
IndexedDBKey::IndexedDBKey(KeyArray array)
- : type_(kWebIDBKeyTypeArray),
+ : type_(blink::mojom::IDBKeyType::Array),
array_(std::move(array)),
size_estimate_(kOverheadSize + CalculateArraySize(array_)) {}
IndexedDBKey::IndexedDBKey(std::string binary)
- : type_(kWebIDBKeyTypeBinary),
+ : type_(blink::mojom::IDBKeyType::Binary),
binary_(std::move(binary)),
size_estimate_(kOverheadSize +
(binary_.length() * sizeof(std::string::value_type))) {}
IndexedDBKey::IndexedDBKey(base::string16 string)
- : type_(kWebIDBKeyTypeString),
+ : type_(mojom::IDBKeyType::String),
string_(std::move(string)),
size_estimate_(kOverheadSize +
(string_.length() * sizeof(base::string16::value_type))) {}
@@ -80,10 +71,10 @@ IndexedDBKey::~IndexedDBKey() = default;
IndexedDBKey& IndexedDBKey::operator=(const IndexedDBKey& other) = default;
bool IndexedDBKey::IsValid() const {
- if (type_ == kWebIDBKeyTypeInvalid || type_ == kWebIDBKeyTypeNull)
+ if (type_ == mojom::IDBKeyType::Invalid || type_ == mojom::IDBKeyType::Null)
return false;
- if (type_ == kWebIDBKeyTypeArray) {
+ if (type_ == blink::mojom::IDBKeyType::Array) {
for (size_t i = 0; i < array_.size(); i++) {
if (!array_[i].IsValid())
return false;
@@ -108,23 +99,23 @@ int IndexedDBKey::CompareTo(const IndexedDBKey& other) const {
return type_ > other.type_ ? -1 : 1;
switch (type_) {
- case kWebIDBKeyTypeArray:
+ case mojom::IDBKeyType::Array:
for (size_t i = 0; i < array_.size() && i < other.array_.size(); ++i) {
int result = array_[i].CompareTo(other.array_[i]);
if (result != 0)
return result;
}
return Compare(array_.size(), other.array_.size());
- case kWebIDBKeyTypeBinary:
+ case mojom::IDBKeyType::Binary:
return binary_.compare(other.binary_);
- case kWebIDBKeyTypeString:
+ case mojom::IDBKeyType::String:
return string_.compare(other.string_);
- case kWebIDBKeyTypeDate:
- case kWebIDBKeyTypeNumber:
+ case mojom::IDBKeyType::Date:
+ case mojom::IDBKeyType::Number:
return Compare(number_, other.number_);
- case kWebIDBKeyTypeInvalid:
- case kWebIDBKeyTypeNull:
- case kWebIDBKeyTypeMin:
+ case mojom::IDBKeyType::Invalid:
+ case mojom::IDBKeyType::Null:
+ case mojom::IDBKeyType::Min:
default:
NOTREACHED();
return 0;
diff --git a/chromium/third_party/blink/common/indexeddb/indexeddb_key_path.cc b/chromium/third_party/blink/common/indexeddb/indexeddb_key_path.cc
index 25699ec9103..552d54179c5 100644
--- a/chromium/third_party/blink/common/indexeddb/indexeddb_key_path.cc
+++ b/chromium/third_party/blink/common/indexeddb/indexeddb_key_path.cc
@@ -5,20 +5,17 @@
#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
#include "base/logging.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
namespace blink {
-using blink::kWebIDBKeyPathTypeArray;
-using blink::kWebIDBKeyPathTypeNull;
-using blink::kWebIDBKeyPathTypeString;
-
-IndexedDBKeyPath::IndexedDBKeyPath() : type_(kWebIDBKeyPathTypeNull) {}
+IndexedDBKeyPath::IndexedDBKeyPath() : type_(mojom::IDBKeyPathType::Null) {}
IndexedDBKeyPath::IndexedDBKeyPath(const base::string16& string)
- : type_(kWebIDBKeyPathTypeString), string_(string) {}
+ : type_(mojom::IDBKeyPathType::String), string_(string) {}
IndexedDBKeyPath::IndexedDBKeyPath(const std::vector<base::string16>& array)
- : type_(kWebIDBKeyPathTypeArray), array_(array) {}
+ : type_(mojom::IDBKeyPathType::Array), array_(array) {}
IndexedDBKeyPath::IndexedDBKeyPath(const IndexedDBKeyPath& other) = default;
IndexedDBKeyPath::IndexedDBKeyPath(IndexedDBKeyPath&& other) = default;
@@ -29,12 +26,12 @@ IndexedDBKeyPath& IndexedDBKeyPath::operator=(IndexedDBKeyPath&& other) =
default;
const std::vector<base::string16>& IndexedDBKeyPath::array() const {
- DCHECK(type_ == blink::kWebIDBKeyPathTypeArray);
+ DCHECK(type_ == blink::mojom::IDBKeyPathType::Array);
return array_;
}
const base::string16& IndexedDBKeyPath::string() const {
- DCHECK(type_ == blink::kWebIDBKeyPathTypeString);
+ DCHECK(type_ == blink::mojom::IDBKeyPathType::String);
return string_;
}
@@ -43,11 +40,11 @@ bool IndexedDBKeyPath::operator==(const IndexedDBKeyPath& other) const {
return false;
switch (type_) {
- case kWebIDBKeyPathTypeNull:
+ case mojom::IDBKeyPathType::Null:
return true;
- case kWebIDBKeyPathTypeString:
+ case mojom::IDBKeyPathType::String:
return string_ == other.string_;
- case kWebIDBKeyPathTypeArray:
+ case mojom::IDBKeyPathType::Array:
return array_ == other.array_;
}
NOTREACHED();
diff --git a/chromium/third_party/blink/common/indexeddb/indexeddb_key_unittest.cc b/chromium/third_party/blink/common/indexeddb/indexeddb_key_unittest.cc
index fa4331b08c5..50a9685b59b 100644
--- a/chromium/third_party/blink/common/indexeddb/indexeddb_key_unittest.cc
+++ b/chromium/third_party/blink/common/indexeddb/indexeddb_key_unittest.cc
@@ -23,15 +23,15 @@ TEST(IndexedDBKeyTest, KeySizeEstimates) {
keys.push_back(IndexedDBKey());
estimates.push_back(16u); // Overhead.
- keys.push_back(IndexedDBKey(blink::kWebIDBKeyTypeNull));
+ keys.push_back(IndexedDBKey(mojom::IDBKeyType::Null));
estimates.push_back(16u);
double number = 3.14159;
- keys.push_back(IndexedDBKey(number, blink::kWebIDBKeyTypeNumber));
+ keys.push_back(IndexedDBKey(number, mojom::IDBKeyType::Number));
estimates.push_back(24u); // Overhead + sizeof(double).
double date = 1370884329.0;
- keys.push_back(IndexedDBKey(date, blink::kWebIDBKeyTypeDate));
+ keys.push_back(IndexedDBKey(date, mojom::IDBKeyType::Date));
estimates.push_back(24u); // Overhead + sizeof(double).
const base::string16 string(1024, static_cast<base::char16>('X'));
@@ -43,7 +43,7 @@ TEST(IndexedDBKeyTest, KeySizeEstimates) {
IndexedDBKey::KeyArray array;
double value = 123.456;
for (size_t i = 0; i < array_size; ++i) {
- array.push_back(IndexedDBKey(value, blink::kWebIDBKeyTypeNumber));
+ array.push_back(IndexedDBKey(value, mojom::IDBKeyType::Number));
}
keys.push_back(IndexedDBKey(std::move(array)));
// Overhead + array length * (Overhead + sizeof(double)).
diff --git a/chromium/third_party/blink/common/loader/OWNERS b/chromium/third_party/blink/common/loader/OWNERS
new file mode 100644
index 00000000000..e4c226c9e60
--- /dev/null
+++ b/chromium/third_party/blink/common/loader/OWNERS
@@ -0,0 +1,5 @@
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+
+# TEAM: loading-dev@chromium.org
+# COMPONENT: Blink>Loader
diff --git a/chromium/third_party/blink/common/loader/url_loader_factory_bundle.cc b/chromium/third_party/blink/common/loader/url_loader_factory_bundle.cc
new file mode 100644
index 00000000000..acab90dda56
--- /dev/null
+++ b/chromium/third_party/blink/common/loader/url_loader_factory_bundle.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 "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "url/gurl.h"
+
+namespace blink {
+
+namespace {
+
+template <typename TKey>
+void BindPtrInfoMapToPtrMap(
+ std::map<TKey, network::mojom::URLLoaderFactoryPtr>* target,
+ std::map<TKey, network::mojom::URLLoaderFactoryPtrInfo> input) {
+ for (auto& it : input) {
+ const TKey& key = it.first;
+ network::mojom::URLLoaderFactoryPtrInfo& factory_info = it.second;
+ (*target)[key].Bind(std::move(factory_info));
+ }
+}
+
+} // namespace
+
+URLLoaderFactoryBundleInfo::URLLoaderFactoryBundleInfo() = default;
+
+URLLoaderFactoryBundleInfo::URLLoaderFactoryBundleInfo(
+ network::mojom::URLLoaderFactoryPtrInfo default_factory_info,
+ SchemeMap scheme_specific_factory_infos,
+ OriginMap initiator_specific_factory_infos,
+ bool bypass_redirect_checks)
+ : default_factory_info_(std::move(default_factory_info)),
+ scheme_specific_factory_infos_(std::move(scheme_specific_factory_infos)),
+ initiator_specific_factory_infos_(
+ std::move(initiator_specific_factory_infos)),
+ bypass_redirect_checks_(bypass_redirect_checks) {}
+
+URLLoaderFactoryBundleInfo::~URLLoaderFactoryBundleInfo() = default;
+
+scoped_refptr<network::SharedURLLoaderFactory>
+URLLoaderFactoryBundleInfo::CreateFactory() {
+ auto other = std::make_unique<URLLoaderFactoryBundleInfo>();
+ other->default_factory_info_ = std::move(default_factory_info_);
+ other->appcache_factory_info_ = std::move(appcache_factory_info_);
+ other->scheme_specific_factory_infos_ =
+ std::move(scheme_specific_factory_infos_);
+ other->initiator_specific_factory_infos_ =
+ std::move(initiator_specific_factory_infos_);
+ other->bypass_redirect_checks_ = bypass_redirect_checks_;
+
+ return base::MakeRefCounted<URLLoaderFactoryBundle>(std::move(other));
+}
+
+// -----------------------------------------------------------------------------
+
+URLLoaderFactoryBundle::URLLoaderFactoryBundle() = default;
+
+URLLoaderFactoryBundle::URLLoaderFactoryBundle(
+ std::unique_ptr<URLLoaderFactoryBundleInfo> info) {
+ Update(std::move(info));
+}
+
+URLLoaderFactoryBundle::~URLLoaderFactoryBundle() = default;
+
+network::mojom::URLLoaderFactory* URLLoaderFactoryBundle::GetFactory(
+ const network::ResourceRequest& request) {
+ auto it = scheme_specific_factories_.find(request.url.scheme());
+ if (it != scheme_specific_factories_.end())
+ return it->second.get();
+
+ if (request.request_initiator.has_value()) {
+ auto it2 =
+ initiator_specific_factories_.find(request.request_initiator.value());
+ if (it2 != initiator_specific_factories_.end())
+ return it2->second.get();
+ }
+
+ // AppCache factory must be used if it's given.
+ if (appcache_factory_)
+ return appcache_factory_.get();
+
+ return default_factory_.get();
+}
+
+void URLLoaderFactoryBundle::CreateLoaderAndStart(
+ network::mojom::URLLoaderRequest loader,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ network::mojom::URLLoaderFactory* factory_ptr = GetFactory(request);
+ factory_ptr->CreateLoaderAndStart(std::move(loader), routing_id, request_id,
+ options, request, std::move(client),
+ traffic_annotation);
+}
+
+void URLLoaderFactoryBundle::Clone(
+ network::mojom::URLLoaderFactoryRequest request) {
+ NOTREACHED();
+}
+
+std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+URLLoaderFactoryBundle::Clone() {
+ network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
+ if (default_factory_)
+ default_factory_->Clone(mojo::MakeRequest(&default_factory_info));
+
+ auto info = std::make_unique<blink::URLLoaderFactoryBundleInfo>(
+ std::move(default_factory_info),
+ ClonePtrMapToPtrInfoMap(scheme_specific_factories_),
+ ClonePtrMapToPtrInfoMap(initiator_specific_factories_),
+ bypass_redirect_checks_);
+
+ if (appcache_factory_)
+ appcache_factory_->Clone(mojo::MakeRequest(&info->appcache_factory_info()));
+
+ return info;
+}
+
+bool URLLoaderFactoryBundle::BypassRedirectChecks() const {
+ return bypass_redirect_checks_;
+}
+
+void URLLoaderFactoryBundle::Update(
+ std::unique_ptr<URLLoaderFactoryBundleInfo> info) {
+ if (info->default_factory_info())
+ default_factory_.Bind(std::move(info->default_factory_info()));
+ if (info->appcache_factory_info())
+ appcache_factory_.Bind(std::move(info->appcache_factory_info()));
+ BindPtrInfoMapToPtrMap(&scheme_specific_factories_,
+ std::move(info->scheme_specific_factory_infos()));
+ BindPtrInfoMapToPtrMap(&initiator_specific_factories_,
+ std::move(info->initiator_specific_factory_infos()));
+ bypass_redirect_checks_ = info->bypass_redirect_checks();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc b/chromium/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc
new file mode 100644
index 00000000000..645d5d46bd8
--- /dev/null
+++ b/chromium/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc
@@ -0,0 +1,67 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h"
+
+#include <memory>
+#include <utility>
+
+#include "url/mojom/origin_mojom_traits.h"
+
+namespace mojo {
+
+using Traits = StructTraits<blink::mojom::URLLoaderFactoryBundleDataView,
+ std::unique_ptr<blink::URLLoaderFactoryBundleInfo>>;
+
+// static
+network::mojom::URLLoaderFactoryPtrInfo Traits::default_factory(
+ BundleInfoType& bundle) {
+ return std::move(bundle->default_factory_info());
+}
+
+// static
+network::mojom::URLLoaderFactoryPtrInfo Traits::appcache_factory(
+ BundleInfoType& bundle) {
+ return std::move(bundle->appcache_factory_info());
+}
+
+// static
+blink::URLLoaderFactoryBundleInfo::SchemeMap Traits::scheme_specific_factories(
+ BundleInfoType& bundle) {
+ return std::move(bundle->scheme_specific_factory_infos());
+}
+
+// static
+blink::URLLoaderFactoryBundleInfo::OriginMap
+Traits::initiator_specific_factories(BundleInfoType& bundle) {
+ return std::move(bundle->initiator_specific_factory_infos());
+}
+
+// static
+bool Traits::bypass_redirect_checks(BundleInfoType& bundle) {
+ return bundle->bypass_redirect_checks();
+}
+
+// static
+bool Traits::Read(blink::mojom::URLLoaderFactoryBundleDataView data,
+ BundleInfoType* out_bundle) {
+ *out_bundle = std::make_unique<blink::URLLoaderFactoryBundleInfo>();
+
+ (*out_bundle)->default_factory_info() =
+ data.TakeDefaultFactory<network::mojom::URLLoaderFactoryPtrInfo>();
+ (*out_bundle)->appcache_factory_info() =
+ data.TakeAppcacheFactory<network::mojom::URLLoaderFactoryPtrInfo>();
+ if (!data.ReadSchemeSpecificFactories(
+ &(*out_bundle)->scheme_specific_factory_infos()))
+ return false;
+ if (!data.ReadInitiatorSpecificFactories(
+ &(*out_bundle)->initiator_specific_factory_infos()))
+ return false;
+
+ (*out_bundle)->set_bypass_redirect_checks(data.bypass_redirect_checks());
+
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/common/mediastream/OWNERS b/chromium/third_party/blink/common/mediastream/OWNERS
new file mode 100644
index 00000000000..ed7be739c25
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/OWNERS
@@ -0,0 +1,8 @@
+guidou@chromium.org
+hbos@chromium.org
+
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
+# COMPONENT: Blink>GetUserMedia
diff --git a/chromium/third_party/blink/common/mediastream/media_devices.cc b/chromium/third_party/blink/common/mediastream/media_devices.cc
new file mode 100644
index 00000000000..3661b4b6587
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/media_devices.cc
@@ -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.
+
+#include "third_party/blink/public/common/mediastream/media_devices.h"
+#include "media/capture/video/video_capture_device_descriptor.h"
+
+namespace blink {
+
+WebMediaDeviceInfo::WebMediaDeviceInfo()
+ : video_facing(media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {}
+
+WebMediaDeviceInfo::WebMediaDeviceInfo(const WebMediaDeviceInfo& other) =
+ default;
+
+WebMediaDeviceInfo::WebMediaDeviceInfo(WebMediaDeviceInfo&& other) = default;
+
+WebMediaDeviceInfo::WebMediaDeviceInfo(const std::string& device_id,
+ const std::string& label,
+ const std::string& group_id,
+ media::VideoFacingMode video_facing)
+ : device_id(device_id),
+ label(label),
+ group_id(group_id),
+ video_facing(video_facing) {}
+
+WebMediaDeviceInfo::WebMediaDeviceInfo(
+ const media::VideoCaptureDeviceDescriptor& descriptor)
+ : device_id(descriptor.device_id),
+ label(descriptor.GetNameAndModel()),
+ video_facing(descriptor.facing) {}
+
+WebMediaDeviceInfo::~WebMediaDeviceInfo() = default;
+
+WebMediaDeviceInfo& WebMediaDeviceInfo::operator=(
+ const WebMediaDeviceInfo& other) = default;
+
+WebMediaDeviceInfo& WebMediaDeviceInfo::operator=(WebMediaDeviceInfo&& other) =
+ default;
+
+bool operator==(const WebMediaDeviceInfo& first,
+ const WebMediaDeviceInfo& second) {
+ // Do not use the |group_id| and |video_facing| fields for equality comparison
+ // since they are currently not fully supported by the video-capture layer.
+ // The modification of those fields by heuristics in upper layers does not
+ // result in a different device.
+ return first.device_id == second.device_id && first.label == second.label;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/mediastream/media_devices_mojom_traits.cc b/chromium/third_party/blink/common/mediastream/media_devices_mojom_traits.cc
new file mode 100644
index 00000000000..494c0307813
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/media_devices_mojom_traits.cc
@@ -0,0 +1,103 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/mediastream/media_devices_mojom_traits.h"
+
+#include "base/logging.h"
+
+namespace mojo {
+
+// static
+blink::mojom::MediaDeviceType
+EnumTraits<blink::mojom::MediaDeviceType, blink::MediaDeviceType>::ToMojom(
+ blink::MediaDeviceType type) {
+ switch (type) {
+ case blink::MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT:
+ return blink::mojom::MediaDeviceType::MEDIA_AUDIO_INPUT;
+ case blink::MediaDeviceType::MEDIA_DEVICE_TYPE_VIDEO_INPUT:
+ return blink::mojom::MediaDeviceType::MEDIA_VIDEO_INPUT;
+ case blink::MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT:
+ return blink::mojom::MediaDeviceType::MEDIA_AUDIO_OUTPUT;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return blink::mojom::MediaDeviceType::NUM_MEDIA_DEVICE_TYPES;
+}
+
+// static
+bool EnumTraits<blink::mojom::MediaDeviceType, blink::MediaDeviceType>::
+ FromMojom(blink::mojom::MediaDeviceType input,
+ blink::MediaDeviceType* out) {
+ switch (input) {
+ case blink::mojom::MediaDeviceType::MEDIA_AUDIO_INPUT:
+ *out = blink::MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT;
+ return true;
+ case blink::mojom::MediaDeviceType::MEDIA_VIDEO_INPUT:
+ *out = blink::MediaDeviceType::MEDIA_DEVICE_TYPE_VIDEO_INPUT;
+ return true;
+ case blink::mojom::MediaDeviceType::MEDIA_AUDIO_OUTPUT:
+ *out = blink::MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT;
+ return true;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+blink::mojom::FacingMode
+EnumTraits<blink::mojom::FacingMode, media::VideoFacingMode>::ToMojom(
+ media::VideoFacingMode facing_mode) {
+ switch (facing_mode) {
+ case media::MEDIA_VIDEO_FACING_NONE:
+ return blink::mojom::FacingMode::NONE;
+ case media::MEDIA_VIDEO_FACING_USER:
+ return blink::mojom::FacingMode::USER;
+ case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
+ return blink::mojom::FacingMode::ENVIRONMENT;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return blink::mojom::FacingMode::NONE;
+}
+
+// static
+bool EnumTraits<blink::mojom::FacingMode, media::VideoFacingMode>::FromMojom(
+ blink::mojom::FacingMode input,
+ media::VideoFacingMode* out) {
+ switch (input) {
+ case blink::mojom::FacingMode::NONE:
+ *out = media::MEDIA_VIDEO_FACING_NONE;
+ return true;
+ case blink::mojom::FacingMode::USER:
+ *out = media::MEDIA_VIDEO_FACING_USER;
+ return true;
+ case blink::mojom::FacingMode::ENVIRONMENT:
+ *out = media::MEDIA_VIDEO_FACING_ENVIRONMENT;
+ return true;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool StructTraits<blink::mojom::MediaDeviceInfoDataView,
+ blink::WebMediaDeviceInfo>::
+ Read(blink::mojom::MediaDeviceInfoDataView input,
+ blink::WebMediaDeviceInfo* out) {
+ if (!input.ReadDeviceId(&out->device_id))
+ return false;
+ if (!input.ReadLabel(&out->label))
+ return false;
+ if (!input.ReadGroupId(&out->group_id))
+ return false;
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/common/mediastream/media_devices_unittest.cc b/chromium/third_party/blink/common/mediastream/media_devices_unittest.cc
new file mode 100644
index 00000000000..143ca9d497f
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/media_devices_unittest.cc
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/mediastream/media_devices.h"
+#include "media/audio/audio_device_description.h"
+#include "media/capture/video/video_capture_device_descriptor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(MediaDevicesTest, MediaDeviceInfoFromVideoDescriptor) {
+ media::VideoCaptureDeviceDescriptor descriptor(
+ "display_name", "device_id", "model_id", media::VideoCaptureApi::UNKNOWN);
+
+ // TODO(guidou): Add test for group ID when supported. See crbug.com/627793.
+ WebMediaDeviceInfo device_info(descriptor);
+ EXPECT_EQ(descriptor.device_id, device_info.device_id);
+ EXPECT_EQ(descriptor.GetNameAndModel(), device_info.label);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/mediastream/media_stream_controls.cc b/chromium/third_party/blink/common/mediastream/media_stream_controls.cc
new file mode 100644
index 00000000000..9637125f682
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/media_stream_controls.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/mediastream/media_stream_controls.h"
+
+namespace blink {
+
+TrackControls::TrackControls() {}
+
+TrackControls::TrackControls(bool request, MediaStreamType type)
+ : requested(request), stream_type(type) {}
+
+TrackControls::TrackControls(const TrackControls& other) = default;
+
+TrackControls::~TrackControls() {}
+
+StreamControls::StreamControls() {}
+
+StreamControls::StreamControls(bool request_audio, bool request_video)
+ : audio(request_audio,
+ request_audio ? MEDIA_DEVICE_AUDIO_CAPTURE : MEDIA_NO_SERVICE),
+ video(request_video,
+ request_video ? MEDIA_DEVICE_VIDEO_CAPTURE : MEDIA_NO_SERVICE) {}
+
+StreamControls::~StreamControls() {}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/mediastream/media_stream_mojom_traits.cc b/chromium/third_party/blink/common/mediastream/media_stream_mojom_traits.cc
new file mode 100644
index 00000000000..3dd5f448434
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/media_stream_mojom_traits.cc
@@ -0,0 +1,247 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/mediastream/media_stream_mojom_traits.h"
+
+#include "base/logging.h"
+#include "media/base/ipc/media_param_traits.h"
+#include "media/capture/mojom/video_capture_types_mojom_traits.h"
+#include "media/mojo/interfaces/display_media_information.mojom.h"
+
+namespace mojo {
+
+// static
+blink::mojom::MediaStreamType
+EnumTraits<blink::mojom::MediaStreamType, blink::MediaStreamType>::ToMojom(
+ blink::MediaStreamType type) {
+ switch (type) {
+ case blink::MediaStreamType::MEDIA_NO_SERVICE:
+ return blink::mojom::MediaStreamType::MEDIA_NO_SERVICE;
+ case blink::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE;
+ case blink::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE;
+ case blink::MediaStreamType::MEDIA_GUM_TAB_AUDIO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_GUM_TAB_AUDIO_CAPTURE;
+ case blink::MediaStreamType::MEDIA_GUM_TAB_VIDEO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_GUM_TAB_VIDEO_CAPTURE;
+ case blink::MediaStreamType::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE;
+ case blink::MediaStreamType::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE;
+ case blink::MediaStreamType::MEDIA_DISPLAY_VIDEO_CAPTURE:
+ return blink::mojom::MediaStreamType::MEDIA_DISPLAY_VIDEO_CAPTURE;
+ case blink::MediaStreamType::NUM_MEDIA_TYPES:
+ return blink::mojom::MediaStreamType::NUM_MEDIA_TYPES;
+ }
+ NOTREACHED();
+ return blink::mojom::MediaStreamType::MEDIA_NO_SERVICE;
+}
+
+// static
+bool EnumTraits<blink::mojom::MediaStreamType, blink::MediaStreamType>::
+ FromMojom(blink::mojom::MediaStreamType input,
+ blink::MediaStreamType* out) {
+ switch (input) {
+ case blink::mojom::MediaStreamType::MEDIA_NO_SERVICE:
+ *out = blink::MediaStreamType::MEDIA_NO_SERVICE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_GUM_TAB_AUDIO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_GUM_TAB_AUDIO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_GUM_TAB_VIDEO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_GUM_TAB_VIDEO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::MEDIA_DISPLAY_VIDEO_CAPTURE:
+ *out = blink::MediaStreamType::MEDIA_DISPLAY_VIDEO_CAPTURE;
+ return true;
+ case blink::mojom::MediaStreamType::NUM_MEDIA_TYPES:
+ *out = blink::MediaStreamType::NUM_MEDIA_TYPES;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+blink::mojom::MediaStreamRequestResult EnumTraits<
+ blink::mojom::MediaStreamRequestResult,
+ blink::MediaStreamRequestResult>::ToMojom(blink::MediaStreamRequestResult
+ result) {
+ switch (result) {
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_OK:
+ return blink::mojom::MediaStreamRequestResult::OK;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_PERMISSION_DENIED:
+ return blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_PERMISSION_DISMISSED:
+ return blink::mojom::MediaStreamRequestResult::PERMISSION_DISMISSED;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_INVALID_STATE:
+ return blink::mojom::MediaStreamRequestResult::INVALID_STATE;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_NO_HARDWARE:
+ return blink::mojom::MediaStreamRequestResult::NO_HARDWARE;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN:
+ return blink::mojom::MediaStreamRequestResult::INVALID_SECURITY_ORIGIN;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_TAB_CAPTURE_FAILURE:
+ return blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE:
+ return blink::mojom::MediaStreamRequestResult::SCREEN_CAPTURE_FAILURE;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_CAPTURE_FAILURE:
+ return blink::mojom::MediaStreamRequestResult::CAPTURE_FAILURE;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED:
+ return blink::mojom::MediaStreamRequestResult::CONSTRAINT_NOT_SATISFIED;
+ case blink::MediaStreamRequestResult::
+ MEDIA_DEVICE_TRACK_START_FAILURE_AUDIO:
+ return blink::mojom::MediaStreamRequestResult::TRACK_START_FAILURE_AUDIO;
+ case blink::MediaStreamRequestResult::
+ MEDIA_DEVICE_TRACK_START_FAILURE_VIDEO:
+ return blink::mojom::MediaStreamRequestResult::TRACK_START_FAILURE_VIDEO;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_NOT_SUPPORTED:
+ return blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN:
+ return blink::mojom::MediaStreamRequestResult::FAILED_DUE_TO_SHUTDOWN;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_KILL_SWITCH_ON:
+ return blink::mojom::MediaStreamRequestResult::KILL_SWITCH_ON;
+ case blink::MediaStreamRequestResult::MEDIA_DEVICE_SYSTEM_PERMISSION_DENIED:
+ return blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return blink::mojom::MediaStreamRequestResult::OK;
+}
+
+// static
+bool EnumTraits<blink::mojom::MediaStreamRequestResult,
+ blink::MediaStreamRequestResult>::
+ FromMojom(blink::mojom::MediaStreamRequestResult input,
+ blink::MediaStreamRequestResult* out) {
+ switch (input) {
+ case blink::mojom::MediaStreamRequestResult::OK:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_OK;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_PERMISSION_DENIED;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::PERMISSION_DISMISSED:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_PERMISSION_DISMISSED;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::INVALID_STATE:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_INVALID_STATE;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::NO_HARDWARE:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_NO_HARDWARE;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::INVALID_SECURITY_ORIGIN:
+ *out =
+ blink::MediaStreamRequestResult::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_TAB_CAPTURE_FAILURE;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::SCREEN_CAPTURE_FAILURE:
+ *out =
+ blink::MediaStreamRequestResult::MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::CAPTURE_FAILURE:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_CAPTURE_FAILURE;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::CONSTRAINT_NOT_SATISFIED:
+ *out = blink::MediaStreamRequestResult::
+ MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::TRACK_START_FAILURE_AUDIO:
+ *out = blink::MediaStreamRequestResult::
+ MEDIA_DEVICE_TRACK_START_FAILURE_AUDIO;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::TRACK_START_FAILURE_VIDEO:
+ *out = blink::MediaStreamRequestResult::
+ MEDIA_DEVICE_TRACK_START_FAILURE_VIDEO;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_NOT_SUPPORTED;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::FAILED_DUE_TO_SHUTDOWN:
+ *out =
+ blink::MediaStreamRequestResult::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::KILL_SWITCH_ON:
+ *out = blink::MediaStreamRequestResult::MEDIA_DEVICE_KILL_SWITCH_ON;
+ return true;
+ case blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED:
+ *out = blink::MediaStreamRequestResult::
+ MEDIA_DEVICE_SYSTEM_PERMISSION_DENIED;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool StructTraits<blink::mojom::MediaStreamDeviceDataView,
+ blink::MediaStreamDevice>::
+ Read(blink::mojom::MediaStreamDeviceDataView input,
+ blink::MediaStreamDevice* out) {
+ if (!input.ReadType(&out->type))
+ return false;
+ if (!input.ReadId(&out->id))
+ return false;
+ if (!input.ReadVideoFacing(&out->video_facing))
+ return false;
+ if (!input.ReadGroupId(&out->group_id))
+ return false;
+ if (!input.ReadMatchedOutputDeviceId(&out->matched_output_device_id))
+ return false;
+ if (!input.ReadName(&out->name))
+ return false;
+ if (!input.ReadInput(&out->input))
+ return false;
+ out->session_id = input.session_id();
+ if (!input.ReadCameraCalibration(&out->camera_calibration))
+ return false;
+ if (!input.ReadDisplayMediaInfo(&out->display_media_info))
+ return false;
+ return true;
+}
+
+// static
+bool StructTraits<blink::mojom::TrackControlsDataView, blink::TrackControls>::
+ Read(blink::mojom::TrackControlsDataView input, blink::TrackControls* out) {
+ out->requested = input.requested();
+ if (!input.ReadStreamType(&out->stream_type))
+ return false;
+ if (!input.ReadDeviceId(&out->device_id))
+ return false;
+ return true;
+}
+
+// static
+bool StructTraits<blink::mojom::StreamControlsDataView, blink::StreamControls>::
+ Read(blink::mojom::StreamControlsDataView input,
+ blink::StreamControls* out) {
+ if (!input.ReadAudio(&out->audio))
+ return false;
+ if (!input.ReadVideo(&out->video))
+ return false;
+#if DCHECK_IS_ON()
+ if (input.hotword_enabled() || input.disable_local_echo())
+ DCHECK(out->audio.requested);
+#endif
+ out->hotword_enabled = input.hotword_enabled();
+ out->disable_local_echo = input.disable_local_echo();
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/common/mediastream/media_stream_request.cc b/chromium/third_party/blink/common/mediastream/media_stream_request.cc
new file mode 100644
index 00000000000..5583e49ad41
--- /dev/null
+++ b/chromium/third_party/blink/common/mediastream/media_stream_request.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/mediastream/media_stream_request.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace blink {
+
+bool IsAudioInputMediaType(MediaStreamType type) {
+ return (type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ type == MEDIA_GUM_TAB_AUDIO_CAPTURE ||
+ type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE);
+}
+
+bool IsVideoInputMediaType(MediaStreamType type) {
+ return (type == MEDIA_DEVICE_VIDEO_CAPTURE ||
+ type == MEDIA_GUM_TAB_VIDEO_CAPTURE ||
+ type == MEDIA_GUM_DESKTOP_VIDEO_CAPTURE ||
+ type == MEDIA_DISPLAY_VIDEO_CAPTURE);
+}
+
+bool IsScreenCaptureMediaType(MediaStreamType type) {
+ return IsDesktopCaptureMediaType(type) || IsTabCaptureMediaType(type);
+}
+
+bool IsVideoScreenCaptureMediaType(MediaStreamType type) {
+ return IsVideoDesktopCaptureMediaType(type) ||
+ type == MEDIA_GUM_TAB_VIDEO_CAPTURE;
+}
+
+bool IsDesktopCaptureMediaType(MediaStreamType type) {
+ return (type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE ||
+ IsVideoDesktopCaptureMediaType(type));
+}
+
+bool IsVideoDesktopCaptureMediaType(MediaStreamType type) {
+ return (type == MEDIA_DISPLAY_VIDEO_CAPTURE ||
+ type == MEDIA_GUM_DESKTOP_VIDEO_CAPTURE);
+}
+
+bool IsTabCaptureMediaType(MediaStreamType type) {
+ return (type == MEDIA_GUM_TAB_AUDIO_CAPTURE ||
+ type == MEDIA_GUM_TAB_VIDEO_CAPTURE);
+}
+
+bool IsDeviceMediaType(MediaStreamType type) {
+ return (type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ type == MEDIA_DEVICE_VIDEO_CAPTURE);
+}
+
+// static
+const int MediaStreamDevice::kNoId = -1;
+
+MediaStreamDevice::MediaStreamDevice()
+ : type(MEDIA_NO_SERVICE), video_facing(media::MEDIA_VIDEO_FACING_NONE) {}
+
+MediaStreamDevice::MediaStreamDevice(MediaStreamType type,
+ const std::string& id,
+ const std::string& name)
+ : type(type),
+ id(id),
+ video_facing(media::MEDIA_VIDEO_FACING_NONE),
+ name(name) {}
+
+MediaStreamDevice::MediaStreamDevice(
+ MediaStreamType type,
+ const std::string& id,
+ const std::string& name,
+ media::VideoFacingMode facing,
+ const base::Optional<std::string>& group_id)
+ : type(type),
+ id(id),
+ video_facing(facing),
+ group_id(group_id),
+ name(name) {}
+
+MediaStreamDevice::MediaStreamDevice(MediaStreamType type,
+ const std::string& id,
+ const std::string& name,
+ int sample_rate,
+ int channel_layout,
+ int frames_per_buffer)
+ : type(type),
+ id(id),
+ video_facing(media::MEDIA_VIDEO_FACING_NONE),
+ name(name),
+ input(media::AudioParameters::AUDIO_FAKE,
+ static_cast<media::ChannelLayout>(channel_layout),
+ sample_rate,
+ frames_per_buffer) {
+ DCHECK(input.IsValid());
+}
+
+MediaStreamDevice::MediaStreamDevice(const MediaStreamDevice& other) {
+ type = other.type;
+ id = other.id;
+ video_facing = other.video_facing;
+ group_id = other.group_id;
+ matched_output_device_id = other.matched_output_device_id;
+ name = other.name;
+ input = other.input;
+ session_id = other.session_id;
+ camera_calibration = other.camera_calibration;
+ if (other.display_media_info.has_value())
+ display_media_info = other.display_media_info->Clone();
+}
+
+MediaStreamDevice::~MediaStreamDevice() {}
+
+MediaStreamDevice& MediaStreamDevice::operator=(
+ const MediaStreamDevice& other) {
+ if (&other == this)
+ return *this;
+ type = other.type;
+ id = other.id;
+ video_facing = other.video_facing;
+ group_id = other.group_id;
+ matched_output_device_id = other.matched_output_device_id;
+ name = other.name;
+ input = other.input;
+ session_id = other.session_id;
+ camera_calibration = other.camera_calibration;
+ if (other.display_media_info.has_value())
+ display_media_info = other.display_media_info->Clone();
+ return *this;
+}
+
+bool MediaStreamDevice::IsSameDevice(
+ const MediaStreamDevice& other_device) const {
+ return type == other_device.type && name == other_device.name &&
+ id == other_device.id &&
+ input.sample_rate() == other_device.input.sample_rate() &&
+ input.channel_layout() == other_device.input.channel_layout() &&
+ session_id == other_device.session_id;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/mime_util/mime_util.cc b/chromium/third_party/blink/common/mime_util/mime_util.cc
index f1667107f2e..c36ddda9500 100644
--- a/chromium/third_party/blink/common/mime_util/mime_util.cc
+++ b/chromium/third_party/blink/common/mime_util/mime_util.cc
@@ -6,9 +6,8 @@
#include <stddef.h>
-#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "net/base/mime_util.h"
@@ -113,7 +112,7 @@ class MimeUtil {
private:
friend struct base::LazyInstanceTraitsBase<MimeUtil>;
- using MimeTypes = base::hash_set<std::string>;
+ using MimeTypes = std::unordered_set<std::string>;
MimeUtil();
@@ -126,13 +125,13 @@ class MimeUtil {
};
MimeUtil::MimeUtil() {
- for (size_t i = 0; i < arraysize(kSupportedNonImageTypes); ++i)
+ for (size_t i = 0; i < base::size(kSupportedNonImageTypes); ++i)
non_image_types_.insert(kSupportedNonImageTypes[i]);
- for (size_t i = 0; i < arraysize(kSupportedImageTypes); ++i)
+ for (size_t i = 0; i < base::size(kSupportedImageTypes); ++i)
image_types_.insert(kSupportedImageTypes[i]);
- for (size_t i = 0; i < arraysize(kUnsupportedTextTypes); ++i)
+ for (size_t i = 0; i < base::size(kUnsupportedTextTypes); ++i)
unsupported_text_types_.insert(kUnsupportedTextTypes[i]);
- for (size_t i = 0; i < arraysize(kSupportedJavascriptTypes); ++i) {
+ for (size_t i = 0; i < base::size(kSupportedJavascriptTypes); ++i) {
javascript_types_.insert(kSupportedJavascriptTypes[i]);
non_image_types_.insert(kSupportedJavascriptTypes[i]);
}
diff --git a/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc b/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc
index 6d585a4e685..a3d7fd24c23 100644
--- a/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc
+++ b/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/test/simple_test_clock.h"
@@ -561,19 +561,19 @@ class TrialTokenTest : public testing::TestWithParam<const char*> {
invalid_timestamp_(base::Time::FromDoubleT(kInvalidTimestamp)),
expected_signature_(
std::string(reinterpret_cast<const char*>(kSampleTokenSignature),
- arraysize(kSampleTokenSignature))),
+ base::size(kSampleTokenSignature))),
expected_subdomain_signature_(std::string(
reinterpret_cast<const char*>(kSampleSubdomainTokenSignature),
- arraysize(kSampleSubdomainTokenSignature))),
+ base::size(kSampleSubdomainTokenSignature))),
expected_nonsubdomain_signature_(std::string(
reinterpret_cast<const char*>(kSampleNonSubdomainTokenSignature),
- arraysize(kSampleNonSubdomainTokenSignature))),
+ base::size(kSampleNonSubdomainTokenSignature))),
correct_public_key_(
base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey),
- arraysize(kTestPublicKey))),
+ base::size(kTestPublicKey))),
incorrect_public_key_(
base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey2),
- arraysize(kTestPublicKey2))) {}
+ base::size(kTestPublicKey2))) {}
protected:
OriginTrialTokenStatus Extract(const std::string& token_text,
@@ -712,7 +712,7 @@ TEST_F(TrialTokenTest, ExtractLargeToken) {
ASSERT_EQ(OriginTrialTokenStatus::kSuccess, status);
std::string expected_signature(
std::string(reinterpret_cast<const char*>(kLargeValidTokenSignature),
- arraysize(kLargeValidTokenSignature)));
+ base::size(kLargeValidTokenSignature)));
EXPECT_EQ(expected_signature, token_signature);
}
diff --git a/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc b/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc
index 2b219e79a4e..c9017607a3a 100644
--- a/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc
+++ b/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc
@@ -9,8 +9,8 @@
#include <string>
#include "base/bind.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
@@ -124,7 +124,7 @@ class TestOriginTrialPolicy : public OriginTrialPolicy {
}
base::StringPiece GetPublicKey() const override {
return base::StringPiece(reinterpret_cast<const char*>(key_),
- arraysize(kTestPublicKey));
+ base::size(kTestPublicKey));
}
bool IsFeatureDisabled(base::StringPiece feature) const override {
return disabled_features_.count(feature.as_string()) > 0;
@@ -158,10 +158,10 @@ class TrialTokenValidatorTest : public testing::Test {
insecure_origin_(url::Origin::Create(GURL(kInsecureOrigin))),
valid_token_signature_(
std::string(reinterpret_cast<const char*>(kSampleTokenSignature),
- arraysize(kSampleTokenSignature))),
+ base::size(kSampleTokenSignature))),
expired_token_signature_(
std::string(reinterpret_cast<const char*>(kExpiredTokenSignature),
- arraysize(kExpiredTokenSignature))),
+ base::size(kExpiredTokenSignature))),
response_headers_(new net::HttpResponseHeaders("")) {
TrialTokenValidator::SetOriginTrialPolicyGetter(
base::BindRepeating([](OriginTrialPolicy* policy) { return policy; },
diff --git a/chromium/third_party/blink/common/service_worker/service_worker_utils.cc b/chromium/third_party/blink/common/service_worker/service_worker_utils.cc
index 46e457a3187..7ec2ae7780e 100644
--- a/chromium/third_party/blink/common/service_worker/service_worker_utils.cc
+++ b/chromium/third_party/blink/common/service_worker/service_worker_utils.cc
@@ -5,11 +5,31 @@
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
#include "services/network/public/cpp/features.h"
#include "third_party/blink/public/common/features.h"
namespace blink {
+const char kServiceWorkerEagerCodeCacheStrategy[] = "sw_cache_strategy";
+
+namespace {
+
+constexpr base::FeatureParam<EagerCodeCacheStrategy>::Option
+ kEagerCodeCacheStrategyOptions[] = {
+ {EagerCodeCacheStrategy::kDontGenerate, "dontgenerate"},
+ {EagerCodeCacheStrategy::kDuringInstallEvent, "installevent"},
+ {EagerCodeCacheStrategy::kOnIdleTask, "idletask"},
+};
+
+constexpr base::FeatureParam<EagerCodeCacheStrategy>
+ kEagerCodeCacheStrategyParam{&features::kServiceWorkerAggressiveCodeCache,
+ "sw_cache_strategy",
+ EagerCodeCacheStrategy::kDuringInstallEvent,
+ &kEagerCodeCacheStrategyOptions};
+
+} // namespace
+
// static
bool ServiceWorkerUtils::IsServicificationEnabled() {
return base::FeatureList::IsEnabled(network::features::kNetworkService) ||
@@ -22,4 +42,8 @@ bool ServiceWorkerUtils::IsImportedScriptUpdateCheckEnabled() {
blink::features::kServiceWorkerImportedScriptUpdateCheck);
}
+EagerCodeCacheStrategy ServiceWorkerUtils::GetEagerCodeCacheStrategy() {
+ return kEagerCodeCacheStrategyParam.Get();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/manual_tests/array-out-of-memory.html b/chromium/third_party/blink/manual_tests/array-out-of-memory.html
index 486e200ddae..a1605b7ee13 100644
--- a/chromium/third_party/blink/manual_tests/array-out-of-memory.html
+++ b/chromium/third_party/blink/manual_tests/array-out-of-memory.html
@@ -15,7 +15,7 @@ function runArrayOOMTest() {
try {
var arr = new Array();
- for (i=0; i < populate; ++i)
+ for (var i=0; i < populate; ++i)
arr[i] = 0;
arr[target] = 0;
} catch(e) {
diff --git a/chromium/third_party/blink/manual_tests/autoscroll.html b/chromium/third_party/blink/manual_tests/autoscroll.html
index db9bd90d9fb..9f60d8cac89 100644
--- a/chromium/third_party/blink/manual_tests/autoscroll.html
+++ b/chromium/third_party/blink/manual_tests/autoscroll.html
@@ -4,7 +4,7 @@ function addFrameText() {
frameDoc = window.frames[0].document;
item = frameDoc.createElement("p");
item.appendChild(frameDoc.createTextNode("Hello, world!"));
- for (i = 0; i < 1000; ++i) {
+ for (var i = 0; i < 1000; ++i) {
frameDoc.body.appendChild(item.cloneNode(true));
}
}
diff --git a/chromium/third_party/blink/manual_tests/harfbuzz-mouse-selection-crash.html b/chromium/third_party/blink/manual_tests/harfbuzz-mouse-selection-crash.html
index a7e85a1ef83..46dfdd05c45 100644
--- a/chromium/third_party/blink/manual_tests/harfbuzz-mouse-selection-crash.html
+++ b/chromium/third_party/blink/manual_tests/harfbuzz-mouse-selection-crash.html
@@ -24,7 +24,7 @@ function mouseSelection() {
if (window.eventSender) {
eventSender.mouseMoveTo(xStart, yStart);
eventSender.mouseDown();
- for(i=0;i<ITERATIONS;i++) {
+ for(var i=0;i<ITERATIONS;i++) {
randomCoord = randomCoordinate();
eventSender.mouseMoveTo(randomCoord.x, randomCoord.y);
}
diff --git a/chromium/third_party/blink/manual_tests/input-starved-by-timers.html b/chromium/third_party/blink/manual_tests/input-starved-by-timers.html
index f26cfa7b925..efee417ee0e 100644
--- a/chromium/third_party/blink/manual_tests/input-starved-by-timers.html
+++ b/chromium/third_party/blink/manual_tests/input-starved-by-timers.html
@@ -21,7 +21,7 @@ function timerCallback(creationTimestamp) {
// Create more timers. Capture the current time so when callbacks are fired,
// we can check how long it actually took (latency caused by a long timer queue).
var timestamp = new Date().getTime();
- for (i = 0; i < multiplyFactor; ++i) {
+ for (var i = 0; i < multiplyFactor; ++i) {
setTimeout(function() { timerCallback(timestamp); }, 0);
++timerCount;
}
diff --git a/chromium/third_party/blink/manual_tests/select_hr.html b/chromium/third_party/blink/manual_tests/select_hr.html
index 957a9958161..afee7747904 100644
--- a/chromium/third_party/blink/manual_tests/select_hr.html
+++ b/chromium/third_party/blink/manual_tests/select_hr.html
@@ -19,7 +19,7 @@
}
function getAllInfo(x) {
- for (i = 1; i < x; i++) {
+ for (var i = 1; i < x; i++) {
var s = "s" + i;
var d = "d" + i;
diff --git a/chromium/third_party/blink/public/BUILD.gn b/chromium/third_party/blink/public/BUILD.gn
index 516058e0ca2..e8fd60eedb8 100644
--- a/chromium/third_party/blink/public/BUILD.gn
+++ b/chromium/third_party/blink/public/BUILD.gn
@@ -128,18 +128,7 @@ source_set("blink_headers") {
"platform/mac/web_sandbox_support.h",
"platform/mac/web_scrollbar_theme.h",
"platform/modules/background_fetch/web_background_fetch_registration.h",
- "platform/modules/indexeddb/indexed_db_key_builder.h",
- "platform/modules/indexeddb/web_idb_callbacks.h",
- "platform/modules/indexeddb/web_idb_database_callbacks.h",
- "platform/modules/indexeddb/web_idb_database_error.h",
"platform/modules/indexeddb/web_idb_database_exception.h",
- "platform/modules/indexeddb/web_idb_key.h",
- "platform/modules/indexeddb/web_idb_key_path.h",
- "platform/modules/indexeddb/web_idb_key_range.h",
- "platform/modules/indexeddb/web_idb_metadata.h",
- "platform/modules/indexeddb/web_idb_name_and_version.h",
- "platform/modules/indexeddb/web_idb_observation.h",
- "platform/modules/indexeddb/web_idb_value.h",
"platform/modules/installedapp/web_related_application.h",
"platform/modules/installedapp/web_related_apps_fetcher.h",
"platform/modules/media_capabilities/web_audio_configuration.h",
@@ -151,6 +140,9 @@ source_set("blink_headers") {
"platform/modules/media_capabilities/web_media_configuration.h",
"platform/modules/media_capabilities/web_media_decoding_configuration.h",
"platform/modules/media_capabilities/web_video_configuration.h",
+ "platform/modules/mediastream/platform_media_stream_source.h",
+ "platform/modules/mediastream/web_media_stream_sink.h",
+ "platform/modules/mediastream/web_platform_media_stream_track.h",
"platform/modules/notifications/web_notification_action.h",
"platform/modules/notifications/web_notification_constants.h",
"platform/modules/notifications/web_notification_data.h",
@@ -178,8 +170,6 @@ source_set("blink_headers") {
"platform/modules/service_worker/web_service_worker_request.h",
"platform/modules/service_worker/web_service_worker_response.h",
"platform/modules/service_worker/web_service_worker_stream_handle.h",
- "platform/modules/webmidi/web_midi_accessor.h",
- "platform/modules/webmidi/web_midi_accessor_client.h",
"platform/platform.h",
"platform/pointer_properties.h",
"platform/scheduler/web_rail_mode_observer.h",
@@ -208,6 +198,7 @@ source_set("blink_headers") {
"platform/web_canvas_capture_handler.h",
"platform/web_client_hints_type.h",
"platform/web_coalesced_input_event.h",
+ "platform/web_color_scheme.h",
"platform/web_common.h",
"platform/web_computed_ax_tree.h",
"platform/web_connection_type.h",
@@ -272,6 +263,7 @@ source_set("blink_headers") {
"platform/web_insecure_request_policy.h",
"platform/web_intrinsic_sizing_info.h",
"platform/web_isolated_world_ids.h",
+ "platform/web_isolated_world_info.h",
"platform/web_keyboard_event.h",
"platform/web_layer_tree_view.h",
"platform/web_loading_behavior_flag.h",
@@ -299,6 +291,7 @@ source_set("blink_headers") {
"platform/web_mouse_event.h",
"platform/web_mouse_wheel_event.h",
"platform/web_native_scroll_behavior.h",
+ "platform/web_navigation_body_loader.h",
"platform/web_network_state_notifier.h",
"platform/web_platform_event_listener.h",
"platform/web_point.h",
@@ -324,9 +317,9 @@ source_set("blink_headers") {
"platform/web_rtc_offer_options.h",
"platform/web_rtc_peer_connection_handler.h",
"platform/web_rtc_peer_connection_handler_client.h",
- "platform/web_rtc_rtp_contributing_source.h",
"platform/web_rtc_rtp_receiver.h",
"platform/web_rtc_rtp_sender.h",
+ "platform/web_rtc_rtp_source.h",
"platform/web_rtc_rtp_transceiver.h",
"platform/web_rtc_session_description.h",
"platform/web_rtc_session_description_request.h",
@@ -499,8 +492,6 @@ source_set("blink_headers") {
"web/web_settings.h",
"web/web_shared_worker.h",
"web/web_shared_worker_client.h",
- "web/web_shared_worker_connect_listener.h",
- "web/web_shared_worker_repository_client.h",
"web/web_storage_event_dispatcher.h",
"web/web_surrounding_text.h",
"web/web_testing_support.h",
@@ -550,7 +541,6 @@ source_set("blink_headers") {
"//cc:cc",
"//cc/paint:paint",
"//components/viz/common",
- "//media/midi:mojo_shared_cpp_sources",
"//mojo/public/cpp/bindings:bindings",
"//mojo/public/cpp/system:system",
"//services/device/public/mojom:mojom_shared_cpp_sources",
@@ -646,20 +636,16 @@ mojom("mojo_bindings") {
[ "//third_party/blink/renderer/platform:blink_platform_public_deps" ]
sources = [
"platform/autoplay.mojom",
- "platform/content_security_policy.mojom",
- "platform/dedicated_worker_factory.mojom",
"platform/media_download_in_product_help.mojom",
"platform/mime_registry.mojom",
"platform/modules/app_banner/app_banner.mojom",
- "platform/modules/background_fetch/background_fetch.mojom",
"platform/modules/background_sync/background_sync.mojom",
"platform/modules/badging/badging.mojom",
"platform/modules/bluetooth/web_bluetooth.mojom",
- "platform/modules/cache_storage/cache_storage.mojom",
"platform/modules/credentialmanager/credential_manager.mojom",
- "platform/modules/fetch/fetch_api_request.mojom",
"platform/modules/geolocation/geolocation_service.mojom",
"platform/modules/hyphenation/hyphenation.mojom",
+ "platform/modules/idle/idle_manager.mojom",
"platform/modules/insecure_input/insecure_input_service.mojom",
"platform/modules/keyboard_lock/keyboard_lock.mojom",
"platform/modules/locks/lock_manager.mojom",
@@ -673,12 +659,9 @@ mojom("mojo_bindings") {
"platform/site_engagement.mojom",
"platform/ukm.mojom",
"web/commit_result.mojom",
- "web/console_message.mojom",
- "web/devtools_agent.mojom",
"web/devtools_frontend.mojom",
"web/selection_menu_behavior.mojom",
"web/window_features.mojom",
- "web/worker_content_settings_proxy.mojom",
]
public_deps = [
":android_mojo_bindings",
@@ -755,22 +738,6 @@ mojom("android_mojo_bindings") {
export_header_blink = "third_party/blink/public/platform/web_common.h"
}
-mojom("media_devices_mojo_bindings") {
- sources = [
- "platform/modules/mediastream/media_devices.mojom",
- ]
-
- public_deps = [
- "//media/capture/mojom:video_capture",
- "//media/mojo/interfaces",
- "//ui/gfx/geometry/mojo",
- ]
-
- export_class_attribute = "CONTENT_EXPORT"
- export_define = "CONTENT_IMPLEMENTATION=1"
- export_header = "content/common/content_export.h"
-}
-
# The embedded_frame_sink_mojo_bindings is separated from the rest of mojom
# files because its deps contain too many files in Chromium that would pollute
# the include paths in generated mojom-blink files for other services.
@@ -837,8 +804,6 @@ group("generate_mojo_bindings") {
":core_mojo_bindings_blink_headers",
":core_mojo_bindings_headers",
":embedded_frame_sink_mojo_bindings_blink_headers",
- ":media_devices_mojo_bindings_blink_headers",
- ":media_devices_mojo_bindings_headers",
":mojo_bindings_blink_headers",
":mojo_bindings_headers",
]
@@ -847,10 +812,13 @@ group("generate_mojo_bindings") {
# The web_feature_mojo_bindings is separated from the rest of the mojom files
# because the chromium typemap for blink mojo_bindings has private content
# dependencies.
-mojom("web_feature_mojo_bindings") {
+mojom_component("web_feature_mojo_bindings") {
sources = [
"platform/web_feature.mojom",
]
+
+ macro_prefix = "WEB_FEATURE_MOJO_BINDINGS_MOJOM"
+ output_prefix = "web_feature_mojo_bindings_mojom"
}
# The web_feature_mojo_bindings is separated from the rest of the mojom files
@@ -861,19 +829,3 @@ mojom("web_client_hints_types_mojo_bindings") {
"platform/web_client_hints_types.mojom",
]
}
-
-# Some mojom typemaps are shared between Chromium and Blink variants and
-# therefore require some shared traits implementation. These definitions are
-# relegated to a separate target to avoid duplication between the variants.
-source_set("shared_typemap_traits") {
- visibility = [ ":*" ]
- sources = [
- "web/console_message_struct_traits.cc",
- "web/console_message_struct_traits.h",
- ]
- deps = [
- ":blink_headers",
- ":mojo_bindings_headers",
- "//mojo/public/cpp/bindings:struct_traits",
- ]
-}
diff --git a/chromium/third_party/blink/public/OWNERS b/chromium/third_party/blink/public/OWNERS
index afff5d326ae..499cd80c660 100644
--- a/chromium/third_party/blink/public/OWNERS
+++ b/chromium/third_party/blink/public/OWNERS
@@ -1,7 +1,6 @@
chrishtr@chromium.org
dcheng@chromium.org
dgozman@chromium.org
-dstockwell@chromium.org
foolip@chromium.org
haraken@chromium.org
japhet@chromium.org
diff --git a/chromium/third_party/blink/public/blink_resources.grd b/chromium/third_party/blink/public/blink_resources.grd
index 42047241c0d..eba70f912a5 100644
--- a/chromium/third_party/blink/public/blink_resources.grd
+++ b/chromium/third_party/blink/public/blink_resources.grd
@@ -48,17 +48,8 @@
</if>
<include name="IDR_AUDIO_SPATIALIZATION_COMPOSITE" file="../renderer/platform/audio/resources/Composite.flac" type="BINDATA"/>
- <!-- Layered API scripts. Should be consistent with kLayeredAPIResources
- in renderer/core/script/layered_api.cc -->
- <include name="IDR_LAYERED_API_ASYNC_LOCAL_STORAGE_INDEX_JS" file="../renderer/core/script/resources/layered_api/async-local-storage/index.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_BLANK_INDEX_JS" file="../renderer/core/script/resources/layered_api/blank/index.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_INDEX_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/index.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_ITEM_SOURCE_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/item-source.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_BASE_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/layouts/layout-1d-base.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_GRID_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/layouts/layout-1d-grid.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/layouts/layout-1d.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_SCROLLER_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/virtual-scroller.js" type="BINDATA" skip_minify="true"/>
- <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_REPEATER_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/virtual-repeater.js" type="BINDATA" skip_minify="true"/>
+ <!-- Layered API scripts. -->
+ <part file="../renderer/core/script/resources/layered_api/resources.grdp" />
</includes>
</release>
diff --git a/chromium/third_party/blink/public/blink_typemaps.gni b/chromium/third_party/blink/public/blink_typemaps.gni
index 97e2b6dba0a..283c715e0d6 100644
--- a/chromium/third_party/blink/public/blink_typemaps.gni
+++ b/chromium/third_party/blink/public/blink_typemaps.gni
@@ -6,6 +6,7 @@ typemaps = [
"//gpu/ipc/common/mailbox_holder_for_blink.typemap",
"//gpu/ipc/common/sync_token.typemap",
"//mojo/public/cpp/base/file_error.typemap",
+ "//mojo/public/cpp/base/time.typemap",
"//services/viz/public/cpp/compositing/begin_frame_args_for_blink.typemap",
"//services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap",
"//services/viz/public/cpp/compositing/frame_sink_id.typemap",
diff --git a/chromium/third_party/blink/public/common/BUILD.gn b/chromium/third_party/blink/public/common/BUILD.gn
index 6071b579b69..466f90a1e48 100644
--- a/chromium/third_party/blink/public/common/BUILD.gn
+++ b/chromium/third_party/blink/public/common/BUILD.gn
@@ -45,6 +45,8 @@ source_set("headers") {
"experiments/memory_ablation_experiment.h",
"feature_policy/feature_policy.h",
"features.h",
+ "fetch/fetch_api_request_headers_map.h",
+ "fetch/fetch_api_request_headers_mojom_traits.h",
"frame/frame_owner_element_type.h",
"frame/frame_policy.h",
"frame/from_ad_state.h",
@@ -58,9 +60,16 @@ source_set("headers") {
"indexeddb/indexeddb_key_range.h",
"indexeddb/indexeddb_metadata.h",
"indexeddb/web_idb_types.h",
+ "loader/url_loader_factory_bundle.h",
+ "loader/url_loader_factory_bundle_mojom_traits.h",
"manifest/manifest.h",
"manifest/manifest_icon_selector.h",
"manifest/web_display_mode.h",
+ "mediastream/media_devices.h",
+ "mediastream/media_devices_mojom_traits.h",
+ "mediastream/media_stream_controls.h",
+ "mediastream/media_stream_mojom_traits.h",
+ "mediastream/media_stream_request.h",
"messaging/cloneable_message.h",
"messaging/cloneable_message_struct_traits.h",
"messaging/message_port_channel.h",
@@ -87,6 +96,7 @@ source_set("headers") {
]
public_deps = [
+ "//services/network/public/cpp:cpp",
"//skia",
"//third_party/blink/public/mojom:mojom_modules_headers",
]
@@ -101,10 +111,13 @@ source_set("headers") {
# iOS doesn't use and must not depend on //media
if (!is_ios) {
- deps += [ "//media" ]
+ deps += [
+ "//media",
+ "//media/capture:capture_base",
+ ]
}
- if (is_android) {
+ if (is_android || is_win) {
sources += [
"font_unique_name_lookup/font_table_matcher.h",
"font_unique_name_lookup/icu_fold_case_util.h",
@@ -125,7 +138,7 @@ source_set("headers") {
public = sources - [ "common_export.h" ]
}
-if (is_android) {
+if (is_android || is_win) {
proto_library("font_unique_name_table_proto") {
sources = [
"font_unique_name_lookup/font_unique_name_table.proto",
diff --git a/chromium/third_party/blink/public/common/DEPS b/chromium/third_party/blink/public/common/DEPS
index c28e08fe4f8..6f3146b3ed7 100644
--- a/chromium/third_party/blink/public/common/DEPS
+++ b/chromium/third_party/blink/public/common/DEPS
@@ -9,7 +9,10 @@ include_rules = [
"+base",
"+build",
"+net",
+ "+media",
"+mojo",
+ "+services/network/public/cpp/shared_url_loader_factory.h",
+ "+services/network/public/mojom/url_loader_factory.mojom.h",
"+skia/public/interfaces",
"+third_party/blink/public/common",
"+third_party/blink/public/mojom",
diff --git a/chromium/third_party/blink/public/common/download/download_stats.h b/chromium/third_party/blink/public/common/download/download_stats.h
index ca9c012a259..e11b2b379bc 100644
--- a/chromium/third_party/blink/public/common/download/download_stats.h
+++ b/chromium/third_party/blink/public/common/download/download_stats.h
@@ -5,26 +5,75 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_DOWNLOAD_DOWNLOAD_STATS_H_
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_DOWNLOAD_DOWNLOAD_STATS_H_
+#include <stdint.h>
+
#include "base/macros.h"
#include "third_party/blink/public/common/common_export.h"
+namespace ukm {
+
+class UkmRecorder;
+
+typedef int64_t SourceId;
+
+} // namespace ukm
+
namespace blink {
class BLINK_COMMON_EXPORT DownloadStats {
public:
- // These values are used to construct an enum in UMA. They should never be
- // changed.
- static constexpr unsigned kGestureBit = 0x1 << 0;
- static constexpr unsigned kAdBit = 0x1 << 1;
- static constexpr unsigned kCrossOriginBit = 0x1 << 2;
- static constexpr unsigned kSandboxBit = 0x1 << 3;
- static constexpr unsigned kCountSandboxOriginAdGesture = 16;
+ struct BLINK_COMMON_EXPORT MainFrameDownloadFlags {
+ bool has_sandbox;
+ bool has_gesture;
+
+ MainFrameDownloadFlags() = default;
+
+ unsigned ToUmaValue() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MainFrameDownloadFlags);
+ };
+
+ struct BLINK_COMMON_EXPORT SubframeDownloadFlags {
+ bool has_sandbox;
+ bool is_cross_origin;
+ bool is_ad_frame;
+ bool has_gesture;
- static void RecordMainFrameHasGesture(bool gesture);
- static void RecordSubframeSandboxOriginAdGesture(unsigned value);
+ SubframeDownloadFlags() = default;
+
+ unsigned ToUmaValue() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SubframeDownloadFlags);
+ };
+
+ // Log the bits in |flags| for a main frame download to UMA and UKM.
+ static void RecordMainFrameDownloadFlags(const MainFrameDownloadFlags& flags,
+ ukm::SourceId source_id,
+ ukm::UkmRecorder* ukm_recorder);
+
+ // Log the bits in |flags| for a subframe download to UMA and UKM.
+ static void RecordSubframeDownloadFlags(const SubframeDownloadFlags& flags,
+ ukm::SourceId source_id,
+ ukm::UkmRecorder* ukm_recorder);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DownloadStats);
+
+ // These values are used to construct an enum in UMA. They should never be
+ // changed.
+ static constexpr unsigned kSubframeGestureBit = 0x1 << 0;
+ static constexpr unsigned kSubframeAdBit = 0x1 << 1;
+ static constexpr unsigned kSubframeCrossOriginBit = 0x1 << 2;
+ static constexpr unsigned kSubframeSandboxBit = 0x1 << 3;
+ static constexpr unsigned kCountSandboxOriginAdGesture = 16;
+
+ // These values are used to construct an enum in UMA. They should never be
+ // changed.
+ static constexpr unsigned kMainFrameGestureBit = 0x1 << 0;
+ static constexpr unsigned kMainFrameSandboxBit = 0x1 << 1;
+ static constexpr unsigned kCountSandboxGesture = 4;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/common/feature_policy/feature_policy.h b/chromium/third_party/blink/public/common/feature_policy/feature_policy.h
index 0359048c071..fbaf0e1384c 100644
--- a/chromium/third_party/blink/public/common/feature_policy/feature_policy.h
+++ b/chromium/third_party/blink/public/common/feature_policy/feature_policy.h
@@ -93,7 +93,6 @@ struct BLINK_COMMON_EXPORT ParsedFeaturePolicyDeclaration {
ParsedFeaturePolicyDeclaration(mojom::FeaturePolicyFeature feature,
bool matches_all_origins,
bool matches_opaque_src,
- mojom::FeaturePolicyDisposition disposition,
std::vector<url::Origin> origins);
ParsedFeaturePolicyDeclaration(const ParsedFeaturePolicyDeclaration& rhs);
ParsedFeaturePolicyDeclaration& operator=(
@@ -108,7 +107,6 @@ struct BLINK_COMMON_EXPORT ParsedFeaturePolicyDeclaration {
// of the iframe to be present in |origins|, but for sandboxed iframes, this
// flag is set instead.
bool matches_opaque_src;
- mojom::FeaturePolicyDisposition disposition;
// An alphabetically sorted list of all the origins allowed.
std::vector<url::Origin> origins;
};
@@ -118,13 +116,6 @@ using ParsedFeaturePolicy = std::vector<ParsedFeaturePolicyDeclaration>;
bool BLINK_COMMON_EXPORT operator==(const ParsedFeaturePolicyDeclaration& lhs,
const ParsedFeaturePolicyDeclaration& rhs);
-// ParsedFeaturePolicy objects can contain directives of both enforcing and
-// report-only dispositions. This utility function will extract just the items
-// of one disposition or the other.
-BLINK_COMMON_EXPORT std::unique_ptr<ParsedFeaturePolicy>
-DirectivesWithDisposition(mojom::FeaturePolicyDisposition disposition,
- const ParsedFeaturePolicy& policy);
-
class BLINK_COMMON_EXPORT FeaturePolicy {
public:
// Represents a collection of origins which make up an allowlist in a feature
diff --git a/chromium/third_party/blink/public/common/features.h b/chromium/third_party/blink/public/common/features.h
index 3d4abd02b5c..7eec8dc5299 100644
--- a/chromium/third_party/blink/public/common/features.h
+++ b/chromium/third_party/blink/public/common/features.h
@@ -12,32 +12,40 @@ namespace blink {
namespace features {
BLINK_COMMON_EXPORT extern const base::Feature kAutofillPreviewStyleExperiment;
+BLINK_COMMON_EXPORT extern const base::Feature kAvoidFlashBetweenNavigation;
BLINK_COMMON_EXPORT extern const base::Feature
kEagerCacheStorageSetupForServiceWorkers;
BLINK_COMMON_EXPORT extern const base::Feature
kEnableGpuRasterizationViewportRestriction;
+BLINK_COMMON_EXPORT extern const base::Feature kScriptStreaming;
BLINK_COMMON_EXPORT extern const base::Feature kFirstContentfulPaintPlusPlus;
BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller;
BLINK_COMMON_EXPORT extern const base::Feature kJankTracking;
+BLINK_COMMON_EXPORT extern const base::Feature kJankTrackingSweepLine;
BLINK_COMMON_EXPORT extern const base::Feature kBlinkGenPropertyTrees;
BLINK_COMMON_EXPORT extern const base::Feature kLayoutNG;
BLINK_COMMON_EXPORT extern const base::Feature kMixedContentAutoupgrade;
BLINK_COMMON_EXPORT extern const base::Feature kMojoBlobURLs;
+BLINK_COMMON_EXPORT extern const base::Feature kNavigationPredictor;
BLINK_COMMON_EXPORT extern const base::Feature kOnionSoupDOMStorage;
+BLINK_COMMON_EXPORT extern const base::Feature kPlzDedicatedWorker;
BLINK_COMMON_EXPORT extern const base::Feature kPortals;
BLINK_COMMON_EXPORT extern const base::Feature kRTCGetDisplayMedia;
BLINK_COMMON_EXPORT extern const base::Feature kRTCUnifiedPlanByDefault;
-BLINK_COMMON_EXPORT extern const base::Feature kRecordAnchorMetricsClicked;
-BLINK_COMMON_EXPORT extern const base::Feature kRecordAnchorMetricsVisible;
+BLINK_COMMON_EXPORT extern const base::Feature kRTCOfferExtmapAllowMixed;
+BLINK_COMMON_EXPORT extern const base::Feature kResourceLoadViaDataPipe;
BLINK_COMMON_EXPORT extern const base::Feature
kServiceWorkerImportedScriptUpdateCheck;
BLINK_COMMON_EXPORT extern const base::Feature
kServiceWorkerParallelSideDataReading;
BLINK_COMMON_EXPORT extern const base::Feature kServiceWorkerServicification;
+BLINK_COMMON_EXPORT extern const base::Feature
+ kServiceWorkerAggressiveCodeCache;
BLINK_COMMON_EXPORT extern const base::Feature kStopInBackground;
BLINK_COMMON_EXPORT extern const base::Feature kStopNonTimersInBackground;
BLINK_COMMON_EXPORT extern const base::Feature kWasmCodeCache;
BLINK_COMMON_EXPORT extern const base::Feature kWritableFilesAPI;
+BLINK_COMMON_EXPORT extern const base::Feature kForbidSyncXHRInPageDismissal;
BLINK_COMMON_EXPORT extern const char
kAutofillPreviewStyleExperimentBgColorParameterName[];
@@ -49,6 +57,12 @@ BLINK_COMMON_EXPORT extern const char kMixedContentAutoupgradeModeBlockable[];
BLINK_COMMON_EXPORT extern const char
kMixedContentAutoupgradeModeOptionallyBlockable[];
+BLINK_COMMON_EXPORT extern const base::Feature kDecodeLossyWebPImagesToYUV;
+BLINK_COMMON_EXPORT extern const base::Feature kAlwaysAccelerateCanvas;
+
+BLINK_COMMON_EXPORT extern const base::Feature
+ kWebFontsCacheAwareTimeoutAdaption;
+
} // namespace features
} // namespace blink
diff --git a/chromium/third_party/blink/public/common/fetch/OWNERS b/chromium/third_party/blink/public/common/fetch/OWNERS
new file mode 100644
index 00000000000..e45714cfce5
--- /dev/null
+++ b/chromium/third_party/blink/public/common/fetch/OWNERS
@@ -0,0 +1,9 @@
+file://third_party/blink/renderer/core/fetch/OWNERS
+
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network>FetchAPI
diff --git a/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers.typemap b/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers.typemap
new file mode 100644
index 00000000000..c7a4348614e
--- /dev/null
+++ b/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers.typemap
@@ -0,0 +1,12 @@
+# 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.
+
+mojom = "//third_party/blink/public/mojom/fetch/fetch_api_request.mojom"
+public_headers = [
+ "//base/containers/flat_map.h",
+ "//base/strings/string_util.h",
+ "//third_party/blink/public/common/fetch/fetch_api_request_headers_map.h",
+]
+traits_headers = [ "//third_party/blink/public/common/fetch/fetch_api_request_headers_mojom_traits.h" ]
+type_mappings = [ "blink.mojom.FetchAPIRequestHeaders=blink::FetchAPIRequestHeadersMap[move_only]" ]
diff --git a/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_map.h b/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_map.h
new file mode 100644
index 00000000000..8f53ffd03de
--- /dev/null
+++ b/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_map.h
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_FETCH_FETCH_API_REQUEST_HEADERS_MAP_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_FETCH_FETCH_API_REQUEST_HEADERS_MAP_H_
+
+#include <string>
+#include "base/containers/flat_map.h"
+#include "base/strings/string_util.h"
+
+namespace blink {
+
+struct FetchAPIRequestHeadersCompare {
+ bool operator()(const std::string& lhs, const std::string& rhs) const {
+ return base::CompareCaseInsensitiveASCII(lhs, rhs) < 0;
+ }
+};
+
+using FetchAPIRequestHeadersMap =
+ base::flat_map<std::string, std::string, FetchAPIRequestHeadersCompare>;
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_FETCH_FETCH_API_REQUEST_HEADERS_MAP_H_
diff --git a/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_mojom_traits.h b/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_mojom_traits.h
new file mode 100644
index 00000000000..9454bd0ab00
--- /dev/null
+++ b/chromium/third_party/blink/public/common/fetch/fetch_api_request_headers_mojom_traits.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_FETCH_FETCH_API_REQUEST_HEADERS_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_FETCH_FETCH_API_REQUEST_HEADERS_MOJOM_TRAITS_H_
+
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/strings/string_util.h"
+#include "third_party/blink/public/common/fetch/fetch_api_request_headers_map.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<blink::mojom::FetchAPIRequestHeadersDataView,
+ blink::FetchAPIRequestHeadersMap> {
+ static base::flat_map<std::string, std::string> headers(
+ const blink::FetchAPIRequestHeadersMap& in_headers) {
+ return {in_headers.begin(), in_headers.end()};
+ }
+
+ static bool Read(blink::mojom::FetchAPIRequestHeadersDataView in,
+ blink::FetchAPIRequestHeadersMap* out) {
+ return in.ReadHeaders(out);
+ }
+};
+
+} // namespace mojo
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_FETCH_FETCH_API_REQUEST_HEADERS_MOJOM_TRAITS_H_
diff --git a/chromium/third_party/blink/public/common/font_unique_name_lookup/OWNERS b/chromium/third_party/blink/public/common/font_unique_name_lookup/OWNERS
new file mode 100644
index 00000000000..9251fa13eea
--- /dev/null
+++ b/chromium/third_party/blink/public/common/font_unique_name_lookup/OWNERS
@@ -0,0 +1,6 @@
+drott@chromium.org
+
+# COMPONENT: Blink>Fonts
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.proto b/chromium/third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.proto
index 4d9ae3c1aef..fa8361c0a59 100644
--- a/chromium/third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.proto
+++ b/chromium/third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.proto
@@ -9,15 +9,29 @@ option optimize_for = LITE_RUNTIME;
package blink;
message FontUniqueNameTable {
- // The Android build fingerprint for which this font list is stored.
- required string stored_for_android_build_fp = 1;
+ // This field is used on Android for persisting and reading the protobuf from
+ // disk. It stores the Android build fingerprint, for which this cached font
+ // lookup structure was build and allows invalidating it when an Android OS
+ // upgrade was detected.
+ required string stored_for_platform_version_identifier = 1;
- message FontUniqueNameEntry {
+ message UniqueFont {
required string file_path = 10;
required uint32 ttc_index = 20;
- optional string full_name = 30;
- optional string postscript_name = 40;
}
- repeated FontUniqueNameEntry font_entries = 10;
+ // Stores a postscript or full font name and
+ // maps it to an entry in the fonts list.
+ message UniqueNameToFontMapping {
+ required string font_name = 10;
+ required uint32 font_index = 20;
+ }
+
+ repeated UniqueFont fonts = 10;
+
+ // The entries of name_map can be used to lookup a full font name or
+ // postscript name and find the index into the fonts list which this name
+ // points to. The entries must be stored ordered by font_name according to
+ // std::basic_string::compare.
+ repeated UniqueNameToFontMapping name_map = 20;
} \ No newline at end of file
diff --git a/chromium/third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h b/chromium/third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h
index 3954fbb0f27..df9910db24c 100644
--- a/chromium/third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h
+++ b/chromium/third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h
@@ -30,9 +30,9 @@ struct BLINK_COMMON_EXPORT
const blink::IndexedDBDatabaseMetadata& metadata) {
return metadata.max_object_store_id;
}
- static MapValuesArrayView<int64_t, blink::IndexedDBObjectStoreMetadata>
- object_stores(const blink::IndexedDBDatabaseMetadata& metadata) {
- return MapValuesToArray(metadata.object_stores);
+ static std::map<int64_t, blink::IndexedDBObjectStoreMetadata> object_stores(
+ const blink::IndexedDBDatabaseMetadata& metadata) {
+ return metadata.object_stores;
}
static bool Read(blink::mojom::IDBDatabaseMetadataDataView data,
blink::IndexedDBDatabaseMetadata* out);
@@ -97,17 +97,11 @@ struct BLINK_COMMON_EXPORT
}
static double date(const blink::IndexedDBKey& key) { return key.date(); }
static double number(const blink::IndexedDBKey& key) { return key.number(); }
- static blink::mojom::IDBDatalessKeyType other(
- const blink::IndexedDBKey& key) {
- switch (key.type()) {
- case blink::kWebIDBKeyTypeInvalid:
- return blink::mojom::IDBDatalessKeyType::Invalid;
- case blink::kWebIDBKeyTypeNull:
- return blink::mojom::IDBDatalessKeyType::Null;
- default:
- NOTREACHED();
- return blink::mojom::IDBDatalessKeyType::Invalid;
- }
+ static bool other_invalid(const blink::IndexedDBKey& key) {
+ return key.type() == blink::mojom::IDBKeyType::Invalid;
+ }
+ static bool other_null(const blink::IndexedDBKey& key) {
+ return key.type() == blink::mojom::IDBKeyType::Null;
}
};
@@ -171,9 +165,9 @@ struct BLINK_COMMON_EXPORT
const blink::IndexedDBObjectStoreMetadata& metadata) {
return metadata.max_index_id;
}
- static MapValuesArrayView<int64_t, blink::IndexedDBIndexMetadata> indexes(
+ static std::map<int64_t, blink::IndexedDBIndexMetadata> indexes(
const blink::IndexedDBObjectStoreMetadata& metadata) {
- return MapValuesToArray(metadata.indexes);
+ return metadata.indexes;
}
static bool Read(blink::mojom::IDBObjectStoreMetadataDataView data,
blink::IndexedDBObjectStoreMetadata* out);
diff --git a/chromium/third_party/blink/public/common/indexeddb/indexeddb_key.h b/chromium/third_party/blink/public/common/indexeddb/indexeddb_key.h
index 1b8dea4ffa9..4f09ae43182 100644
--- a/chromium/third_party/blink/public/common/indexeddb/indexeddb_key.h
+++ b/chromium/third_party/blink/public/common/indexeddb/indexeddb_key.h
@@ -21,13 +21,13 @@ class BLINK_COMMON_EXPORT IndexedDBKey {
public:
typedef std::vector<IndexedDBKey> KeyArray;
- IndexedDBKey(); // Defaults to blink::WebIDBKeyTypeInvalid.
- explicit IndexedDBKey(blink::WebIDBKeyType); // must be Null or Invalid
+ IndexedDBKey(); // Defaults to mojom::IDBKeyType::Invalid.
+ explicit IndexedDBKey(mojom::IDBKeyType); // must be Null or Invalid
explicit IndexedDBKey(KeyArray array);
explicit IndexedDBKey(std::string binary);
explicit IndexedDBKey(base::string16 string);
IndexedDBKey(double number,
- blink::WebIDBKeyType type); // must be date or number
+ mojom::IDBKeyType type); // must be date or number
IndexedDBKey(const IndexedDBKey& other);
~IndexedDBKey();
IndexedDBKey& operator=(const IndexedDBKey& other);
@@ -37,25 +37,25 @@ class BLINK_COMMON_EXPORT IndexedDBKey {
bool IsLessThan(const IndexedDBKey& other) const;
bool Equals(const IndexedDBKey& other) const;
- blink::WebIDBKeyType type() const { return type_; }
+ mojom::IDBKeyType type() const { return type_; }
const std::vector<IndexedDBKey>& array() const {
- DCHECK_EQ(type_, blink::kWebIDBKeyTypeArray);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Array);
return array_;
}
const std::string& binary() const {
- DCHECK_EQ(type_, blink::kWebIDBKeyTypeBinary);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Binary);
return binary_;
}
const base::string16& string() const {
- DCHECK_EQ(type_, blink::kWebIDBKeyTypeString);
+ DCHECK_EQ(type_, mojom::IDBKeyType::String);
return string_;
}
double date() const {
- DCHECK_EQ(type_, blink::kWebIDBKeyTypeDate);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Date);
return number_;
}
double number() const {
- DCHECK_EQ(type_, blink::kWebIDBKeyTypeNumber);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Number);
return number_;
}
@@ -64,7 +64,7 @@ class BLINK_COMMON_EXPORT IndexedDBKey {
private:
int CompareTo(const IndexedDBKey& other) const;
- blink::WebIDBKeyType type_;
+ mojom::IDBKeyType type_;
std::vector<IndexedDBKey> array_;
std::string binary_;
base::string16 string_;
diff --git a/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_path.h b/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_path.h
index e007115e5f5..9f5422c88eb 100644
--- a/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_path.h
+++ b/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_path.h
@@ -12,6 +12,7 @@
#include "base/strings/string16.h"
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
namespace blink {
@@ -26,15 +27,15 @@ class BLINK_COMMON_EXPORT IndexedDBKeyPath {
IndexedDBKeyPath& operator=(const IndexedDBKeyPath& other);
IndexedDBKeyPath& operator=(IndexedDBKeyPath&& other);
- bool IsNull() const { return type_ == blink::kWebIDBKeyPathTypeNull; }
+ bool IsNull() const { return type_ == blink::mojom::IDBKeyPathType::Null; }
bool operator==(const IndexedDBKeyPath& other) const;
- blink::WebIDBKeyPathType type() const { return type_; }
+ mojom::IDBKeyPathType type() const { return type_; }
const std::vector<base::string16>& array() const;
const base::string16& string() const;
private:
- blink::WebIDBKeyPathType type_;
+ mojom::IDBKeyPathType type_;
base::string16 string_;
std::vector<base::string16> array_;
};
diff --git a/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_range.h b/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_range.h
index 4af170f0819..0756d6c98fd 100644
--- a/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_range.h
+++ b/chromium/third_party/blink/public/common/indexeddb/indexeddb_key_range.h
@@ -31,8 +31,8 @@ class BLINK_COMMON_EXPORT IndexedDBKeyRange {
bool IsEmpty() const;
private:
- blink::IndexedDBKey lower_ = blink::IndexedDBKey(blink::kWebIDBKeyTypeNull);
- blink::IndexedDBKey upper_ = blink::IndexedDBKey(blink::kWebIDBKeyTypeNull);
+ blink::IndexedDBKey lower_ = blink::IndexedDBKey(mojom::IDBKeyType::Null);
+ blink::IndexedDBKey upper_ = blink::IndexedDBKey(mojom::IDBKeyType::Null);
bool lower_open_ = false;
bool upper_open_ = false;
};
diff --git a/chromium/third_party/blink/public/common/indexeddb/web_idb_types.h b/chromium/third_party/blink/public/common/indexeddb/web_idb_types.h
index ff2b2fb53f1..9aeadb8805e 100644
--- a/chromium/third_party/blink/public/common/indexeddb/web_idb_types.h
+++ b/chromium/third_party/blink/public/common/indexeddb/web_idb_types.h
@@ -30,25 +30,6 @@
namespace blink {
-// TODO(cmp): Deprecate these in favor of the blink.mojom.IDB* enum types.
-
-enum WebIDBKeyType {
- kWebIDBKeyTypeInvalid = 0,
- kWebIDBKeyTypeArray,
- kWebIDBKeyTypeBinary,
- kWebIDBKeyTypeString,
- kWebIDBKeyTypeDate,
- kWebIDBKeyTypeNumber,
- kWebIDBKeyTypeNull,
- kWebIDBKeyTypeMin,
-};
-
-enum WebIDBKeyPathType {
- kWebIDBKeyPathTypeNull = 0,
- kWebIDBKeyPathTypeString,
- kWebIDBKeyPathTypeArray,
-};
-
// kIDBOperationTypeCount corresponds to the number of mojom::IDBOperationType
// enum values that exist. Mojo provides kMaxValue which corresponds to the
// value of the last item in the enum list. To get the total number, we have
diff --git a/chromium/third_party/blink/public/common/loader/OWNERS b/chromium/third_party/blink/public/common/loader/OWNERS
new file mode 100644
index 00000000000..10f8abcc7b7
--- /dev/null
+++ b/chromium/third_party/blink/public/common/loader/OWNERS
@@ -0,0 +1,7 @@
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+
+# TEAM: loading-dev@chromium.org
+# COMPONENT: Blink>Loader
diff --git a/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.h b/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.h
new file mode 100644
index 00000000000..eb70586e3cc
--- /dev/null
+++ b/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.h
@@ -0,0 +1,159 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_URL_LOADER_FACTORY_BUNDLE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_URL_LOADER_FACTORY_BUNDLE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/macros.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/blink/public/common/common_export.h"
+#include "url/origin.h"
+
+namespace network {
+struct ResourceRequest;
+};
+
+namespace blink {
+
+// Holds the internal state of a URLLoaderFactoryBundle in a form that is safe
+// to pass across sequences.
+class BLINK_COMMON_EXPORT URLLoaderFactoryBundleInfo
+ : public network::SharedURLLoaderFactoryInfo {
+ public:
+ // Map from URL scheme to URLLoaderFactoryPtrInfo for handling URL requests
+ // for schemes not handled by the |default_factory_info|. See also
+ // URLLoaderFactoryBundle::SchemeMap.
+ using SchemeMap =
+ std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo>;
+
+ // Map from origin of request initiator to URLLoaderFactoryPtrInfo for
+ // handling this initiator's requests (e.g. for relaxing CORB for requests
+ // initiated from content scripts).
+ using OriginMap =
+ std::map<url::Origin, network::mojom::URLLoaderFactoryPtrInfo>;
+
+ URLLoaderFactoryBundleInfo();
+ URLLoaderFactoryBundleInfo(
+ network::mojom::URLLoaderFactoryPtrInfo default_factory_info,
+ SchemeMap scheme_specific_factory_infos,
+ OriginMap initiator_specific_factory_infos,
+ bool bypass_redirect_checks);
+ ~URLLoaderFactoryBundleInfo() override;
+
+ network::mojom::URLLoaderFactoryPtrInfo& default_factory_info() {
+ return default_factory_info_;
+ }
+
+ network::mojom::URLLoaderFactoryPtrInfo& appcache_factory_info() {
+ return appcache_factory_info_;
+ }
+
+ SchemeMap& scheme_specific_factory_infos() {
+ return scheme_specific_factory_infos_;
+ }
+ OriginMap& initiator_specific_factory_infos() {
+ return initiator_specific_factory_infos_;
+ }
+
+ bool bypass_redirect_checks() const { return bypass_redirect_checks_; }
+ void set_bypass_redirect_checks(bool bypass_redirect_checks) {
+ bypass_redirect_checks_ = bypass_redirect_checks;
+ }
+
+ protected:
+ // SharedURLLoaderFactoryInfo implementation.
+ scoped_refptr<network::SharedURLLoaderFactory> CreateFactory() override;
+
+ network::mojom::URLLoaderFactoryPtrInfo default_factory_info_;
+ network::mojom::URLLoaderFactoryPtrInfo appcache_factory_info_;
+ SchemeMap scheme_specific_factory_infos_;
+ OriginMap initiator_specific_factory_infos_;
+ bool bypass_redirect_checks_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryBundleInfo);
+};
+
+// Encapsulates a collection of URLLoaderFactoryPtrs which can be usd to acquire
+// loaders for various types of resource requests.
+class BLINK_COMMON_EXPORT URLLoaderFactoryBundle
+ : public network::SharedURLLoaderFactory {
+ public:
+ URLLoaderFactoryBundle();
+
+ explicit URLLoaderFactoryBundle(
+ std::unique_ptr<URLLoaderFactoryBundleInfo> info);
+
+ // SharedURLLoaderFactory implementation.
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override;
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override;
+ std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override;
+ bool BypassRedirectChecks() const override;
+
+ // The |info| contains replacement factories for a subset of the existing
+ // bundle.
+ void Update(std::unique_ptr<URLLoaderFactoryBundleInfo> info);
+
+ protected:
+ ~URLLoaderFactoryBundle() override;
+
+ // Returns a factory which can be used to acquire a loader for |request|.
+ virtual network::mojom::URLLoaderFactory* GetFactory(
+ const network::ResourceRequest& request);
+
+ template <typename TKey>
+ static std::map<TKey, network::mojom::URLLoaderFactoryPtrInfo>
+ ClonePtrMapToPtrInfoMap(
+ const std::map<TKey, network::mojom::URLLoaderFactoryPtr>& input) {
+ std::map<TKey, network::mojom::URLLoaderFactoryPtrInfo> output;
+ for (const auto& it : input) {
+ const TKey& key = it.first;
+ const network::mojom::URLLoaderFactoryPtr& factory = it.second;
+ network::mojom::URLLoaderFactoryPtrInfo factory_info;
+ factory->Clone(mojo::MakeRequest(&factory_info));
+ output.emplace(key, std::move(factory_info));
+ }
+ return output;
+ }
+
+ // |default_factory_| is the default factory used by the bundle. It usually
+ // goes to "network", but it's possible it was overriden in case when the
+ // context should not be given access to the network.
+ network::mojom::URLLoaderFactoryPtr default_factory_;
+
+ // |appcache_factory_| is a special loader factory that intercepts
+ // requests when the context has AppCache. See also
+ // AppCacheSubresourceURLFactory.
+ network::mojom::URLLoaderFactoryPtr appcache_factory_;
+
+ // Map from URL scheme to URLLoaderFactoryPtr for handling URL requests for
+ // schemes not handled by the |default_factory_|. See also
+ // URLLoaderFactoryBundleInfo::SchemeMap and
+ // ContentBrowserClient::SchemeToURLLoaderFactoryMap.
+ using SchemeMap = std::map<std::string, network::mojom::URLLoaderFactoryPtr>;
+ SchemeMap scheme_specific_factories_;
+
+ // Map from origin of request initiator to URLLoaderFactoryPtr for handling
+ // this initiator's requests. See also URLLoaderFactoryBundleInfo::OriginMap.
+ using OriginMap = std::map<url::Origin, network::mojom::URLLoaderFactoryPtr>;
+ OriginMap initiator_specific_factories_;
+
+ bool bypass_redirect_checks_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_URL_LOADER_FACTORY_BUNDLE_H_
diff --git a/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.typemap b/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.typemap
new file mode 100644
index 00000000000..41c980defda
--- /dev/null
+++ b/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle.typemap
@@ -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.
+
+mojom =
+ "//third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom"
+public_headers =
+ [ "//third_party/blink/public/common/loader/url_loader_factory_bundle.h" ]
+traits_headers = [ "//third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h" ]
+
+type_mappings = [ "blink.mojom.URLLoaderFactoryBundle=std::unique_ptr<blink::URLLoaderFactoryBundleInfo>[move_only,nullable_is_same_type]" ]
diff --git a/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h b/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h
new file mode 100644
index 00000000000..4727643fd28
--- /dev/null
+++ b/chromium/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_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 THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_URL_LOADER_FACTORY_BUNDLE_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_URL_LOADER_FACTORY_BUNDLE_MOJOM_TRAITS_H_
+
+#include <memory>
+
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "third_party/blink/public/common/common_export.h"
+#include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
+#include "third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct BLINK_COMMON_EXPORT
+ StructTraits<blink::mojom::URLLoaderFactoryBundleDataView,
+ std::unique_ptr<blink::URLLoaderFactoryBundleInfo>> {
+ using BundleInfoType = std::unique_ptr<blink::URLLoaderFactoryBundleInfo>;
+
+ static bool IsNull(const BundleInfoType& bundle) { return !bundle; }
+
+ static void SetToNull(BundleInfoType* bundle) { bundle->reset(); }
+
+ static network::mojom::URLLoaderFactoryPtrInfo default_factory(
+ BundleInfoType& bundle);
+
+ static network::mojom::URLLoaderFactoryPtrInfo appcache_factory(
+ BundleInfoType& bundle);
+
+ static blink::URLLoaderFactoryBundleInfo::SchemeMap scheme_specific_factories(
+ BundleInfoType& bundle);
+
+ static blink::URLLoaderFactoryBundleInfo::OriginMap
+ initiator_specific_factories(BundleInfoType& bundle);
+
+ static bool bypass_redirect_checks(BundleInfoType& bundle);
+
+ static bool Read(blink::mojom::URLLoaderFactoryBundleDataView data,
+ BundleInfoType* out_bundle);
+};
+
+} // namespace mojo
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_URL_LOADER_FACTORY_BUNDLE_MOJOM_TRAITS_H_
diff --git a/chromium/third_party/blink/public/common/manifest/manifest.h b/chromium/third_party/blink/public/common/manifest/manifest.h
index 01f78a83974..8adecc5cef4 100644
--- a/chromium/third_party/blink/public/common/manifest/manifest.h
+++ b/chromium/third_party/blink/public/common/manifest/manifest.h
@@ -56,9 +56,8 @@ struct BLINK_COMMON_EXPORT Manifest {
// The special value "any" is represented by gfx::Size(0, 0).
std::vector<gfx::Size> sizes;
- // Empty if the field was not present or not of type "string". Defaults to
- // a vector with a single value, IconPurpose::ANY, for all other parsing
- // exceptions.
+ // Never empty. Defaults to a vector with a single value, IconPurpose::ANY,
+ // if not explicitly specified in the manifest.
std::vector<Purpose> purpose;
};
diff --git a/chromium/third_party/blink/public/common/mediastream/OWNERS b/chromium/third_party/blink/public/common/mediastream/OWNERS
new file mode 100644
index 00000000000..155e1a8b7ca
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/OWNERS
@@ -0,0 +1,10 @@
+guidou@chromium.org
+hbos@chromium.org
+
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
+# COMPONENT: Blink>GetUserMedia
diff --git a/chromium/third_party/blink/public/common/mediastream/media_devices.h b/chromium/third_party/blink/public/common/mediastream/media_devices.h
new file mode 100644
index 00000000000..d87affeb087
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_devices.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 THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_DEVICES_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_DEVICES_H_
+
+#include <string>
+#include <vector>
+
+#include "media/base/video_facing.h"
+#include "third_party/blink/public/common/common_export.h"
+
+namespace media {
+struct VideoCaptureDeviceDescriptor;
+} // namespace media
+
+namespace blink {
+
+enum MediaDeviceType {
+ MEDIA_DEVICE_TYPE_AUDIO_INPUT,
+ MEDIA_DEVICE_TYPE_VIDEO_INPUT,
+ MEDIA_DEVICE_TYPE_AUDIO_OUTPUT,
+ NUM_MEDIA_DEVICE_TYPES,
+};
+
+struct BLINK_COMMON_EXPORT WebMediaDeviceInfo {
+ WebMediaDeviceInfo();
+ WebMediaDeviceInfo(const WebMediaDeviceInfo& other);
+ WebMediaDeviceInfo(WebMediaDeviceInfo&& other);
+ WebMediaDeviceInfo(
+ const std::string& device_id,
+ const std::string& label,
+ const std::string& group_id,
+ media::VideoFacingMode video_facing = media::MEDIA_VIDEO_FACING_NONE);
+ explicit WebMediaDeviceInfo(
+ const media::VideoCaptureDeviceDescriptor& descriptor);
+ ~WebMediaDeviceInfo();
+ WebMediaDeviceInfo& operator=(const WebMediaDeviceInfo& other);
+ WebMediaDeviceInfo& operator=(WebMediaDeviceInfo&& other);
+
+ std::string device_id;
+ std::string label;
+ std::string group_id;
+ media::VideoFacingMode video_facing;
+};
+
+using WebMediaDeviceInfoArray = std::vector<WebMediaDeviceInfo>;
+
+BLINK_COMMON_EXPORT bool operator==(const WebMediaDeviceInfo& first,
+ const WebMediaDeviceInfo& second);
+
+inline bool IsValidMediaDeviceType(MediaDeviceType type) {
+ return type >= 0 && type < NUM_MEDIA_DEVICE_TYPES;
+}
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_DEVICES_H_
diff --git a/chromium/third_party/blink/public/common/mediastream/media_devices.typemap b/chromium/third_party/blink/public/common/mediastream/media_devices.typemap
new file mode 100644
index 00000000000..763f9fc703f
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_devices.typemap
@@ -0,0 +1,20 @@
+# 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.
+
+mojom = "//third_party/blink/public/mojom/mediastream/media_devices.mojom"
+
+public_headers = [
+ "//third_party/blink/public/common/mediastream/media_devices.h",
+ "//third_party/blink/public/common/common_export.h",
+]
+
+traits_headers = [
+ "//third_party/blink/public/common/mediastream/media_devices_mojom_traits.h",
+]
+
+type_mappings = [
+ "blink.mojom.MediaDeviceType=blink::MediaDeviceType",
+ "blink.mojom.MediaDeviceInfo=blink::WebMediaDeviceInfo",
+ "blink.mojom.FacingMode=media::VideoFacingMode",
+]
diff --git a/chromium/third_party/blink/public/common/mediastream/media_devices_mojom_traits.h b/chromium/third_party/blink/public/common/mediastream/media_devices_mojom_traits.h
new file mode 100644
index 00000000000..34d0413ee6f
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_devices_mojom_traits.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_DEVICES_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_DEVICES_MOJOM_TRAITS_H_
+
+#include "third_party/blink/public/common/mediastream/media_devices.h"
+#include "third_party/blink/public/mojom/mediastream/media_devices.mojom.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<blink::mojom::MediaDeviceType, blink::MediaDeviceType> {
+ static blink::mojom::MediaDeviceType ToMojom(blink::MediaDeviceType type);
+
+ static bool FromMojom(blink::mojom::MediaDeviceType input,
+ blink::MediaDeviceType* out);
+};
+
+template <>
+struct EnumTraits<blink::mojom::FacingMode, media::VideoFacingMode> {
+ static blink::mojom::FacingMode ToMojom(media::VideoFacingMode facing_mode);
+
+ static bool FromMojom(blink::mojom::FacingMode input,
+ media::VideoFacingMode* out);
+};
+
+template <>
+struct StructTraits<blink::mojom::MediaDeviceInfoDataView,
+ blink::WebMediaDeviceInfo> {
+ static const std::string& device_id(const blink::WebMediaDeviceInfo& info) {
+ return info.device_id;
+ }
+
+ static const std::string& label(const blink::WebMediaDeviceInfo& info) {
+ return info.label;
+ }
+
+ static const std::string& group_id(const blink::WebMediaDeviceInfo& info) {
+ return info.group_id;
+ }
+
+ static bool Read(blink::mojom::MediaDeviceInfoDataView input,
+ blink::WebMediaDeviceInfo* out);
+};
+
+} // namespace mojo
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_DEVICES_MOJOM_TRAITS_H_
diff --git a/chromium/third_party/blink/public/common/mediastream/media_stream.typemap b/chromium/third_party/blink/public/common/mediastream/media_stream.typemap
new file mode 100644
index 00000000000..f18a24dd070
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_stream.typemap
@@ -0,0 +1,23 @@
+# 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.
+
+mojom = "//third_party/blink/public/mojom/mediastream/media_stream.mojom"
+
+public_headers = [
+ "//third_party/blink/public/common/mediastream/media_stream_controls.h",
+ "//third_party/blink/public/common/mediastream/media_stream_request.h",
+ "//third_party/blink/public/common/common_export.h",
+]
+
+traits_headers = [
+ "//third_party/blink/public/common/mediastream/media_stream_mojom_traits.h",
+]
+
+type_mappings = [
+ "blink.mojom.MediaStreamDevice=blink::MediaStreamDevice",
+ "blink.mojom.MediaStreamRequestResult=blink::MediaStreamRequestResult",
+ "blink.mojom.MediaStreamType=blink::MediaStreamType",
+ "blink.mojom.StreamControls=blink::StreamControls",
+ "blink.mojom.TrackControls=blink::TrackControls",
+]
diff --git a/chromium/third_party/blink/public/common/mediastream/media_stream_controls.h b/chromium/third_party/blink/public/common/mediastream/media_stream_controls.h
new file mode 100644
index 00000000000..1c3f1f0fd4b
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_stream_controls.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_CONTROLS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_CONTROLS_H_
+
+#include <string>
+
+#include "third_party/blink/public/common/common_export.h"
+#include "third_party/blink/public/common/mediastream/media_stream_request.h"
+
+namespace blink {
+
+// Names for media stream source capture types.
+// These are values set via the "chromeMediaSource" constraint.
+BLINK_COMMON_EXPORT extern const char kMediaStreamSourceTab[];
+BLINK_COMMON_EXPORT extern const char
+ kMediaStreamSourceScreen[]; /* video only */
+BLINK_COMMON_EXPORT extern const char kMediaStreamSourceDesktop[];
+BLINK_COMMON_EXPORT extern const char
+ kMediaStreamSourceSystem[]; /* audio only */
+
+struct BLINK_COMMON_EXPORT TrackControls {
+ TrackControls();
+ explicit TrackControls(bool request, MediaStreamType type);
+ explicit TrackControls(const TrackControls& other);
+ ~TrackControls();
+
+ bool requested = false;
+
+ // Represents the requested stream type.
+ MediaStreamType stream_type = MEDIA_NO_SERVICE;
+
+ // An empty string represents the default device.
+ // A nonempty string represents a specific device.
+ std::string device_id;
+};
+
+// StreamControls describes what is sent to the browser process
+// from the renderer process in order to control the opening of a device
+// pair. This may result in opening one audio and/or one video device.
+// This has to be a struct with public members in order to allow it to
+// be sent in the mojo IPC.
+struct BLINK_COMMON_EXPORT StreamControls {
+ StreamControls();
+ StreamControls(bool request_audio, bool request_video);
+ ~StreamControls();
+
+ TrackControls audio;
+ TrackControls video;
+ // Hotword functionality (chromeos only)
+ // See crbug.com/564574 for discussion on possibly #ifdef'ing this out.
+ bool hotword_enabled = false;
+ bool disable_local_echo = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_CONTROLS_H_
diff --git a/chromium/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h b/chromium/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h
new file mode 100644
index 00000000000..044a8083382
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h
@@ -0,0 +1,133 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_MOJOM_TRAITS_H_
+
+#include "third_party/blink/public/common/mediastream/media_stream_controls.h"
+#include "third_party/blink/public/common/mediastream/media_stream_request.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<blink::mojom::MediaStreamType, blink::MediaStreamType> {
+ static blink::mojom::MediaStreamType ToMojom(blink::MediaStreamType type);
+
+ static bool FromMojom(blink::mojom::MediaStreamType input,
+ blink::MediaStreamType* out);
+};
+
+template <>
+struct EnumTraits<blink::mojom::MediaStreamRequestResult,
+ blink::MediaStreamRequestResult> {
+ static blink::mojom::MediaStreamRequestResult ToMojom(
+ blink::MediaStreamRequestResult result);
+
+ static bool FromMojom(blink::mojom::MediaStreamRequestResult input,
+ blink::MediaStreamRequestResult* out);
+};
+
+template <>
+struct StructTraits<blink::mojom::MediaStreamDeviceDataView,
+ blink::MediaStreamDevice> {
+ static const blink::MediaStreamType& type(
+ const blink::MediaStreamDevice& device) {
+ return device.type;
+ }
+
+ static const std::string& id(const blink::MediaStreamDevice& device) {
+ return device.id;
+ }
+
+ static const media::VideoFacingMode& video_facing(
+ const blink::MediaStreamDevice& device) {
+ return device.video_facing;
+ }
+
+ static const base::Optional<std::string>& group_id(
+ const blink::MediaStreamDevice& device) {
+ return device.group_id;
+ }
+
+ static const base::Optional<std::string>& matched_output_device_id(
+ const blink::MediaStreamDevice& device) {
+ return device.matched_output_device_id;
+ }
+
+ static const std::string& name(const blink::MediaStreamDevice& device) {
+ return device.name;
+ }
+
+ static const media::AudioParameters& input(
+ const blink::MediaStreamDevice& device) {
+ return device.input;
+ }
+
+ static int session_id(const blink::MediaStreamDevice& device) {
+ return device.session_id;
+ }
+
+ static const base::Optional<
+ media::VideoCaptureDeviceDescriptor::CameraCalibration>&
+ camera_calibration(const blink::MediaStreamDevice& device) {
+ return device.camera_calibration;
+ }
+
+ static const base::Optional<media::mojom::DisplayMediaInformationPtr>&
+ display_media_info(const blink::MediaStreamDevice& device) {
+ return device.display_media_info;
+ }
+
+ static bool Read(blink::mojom::MediaStreamDeviceDataView input,
+ blink::MediaStreamDevice* out);
+};
+
+template <>
+struct StructTraits<blink::mojom::TrackControlsDataView, blink::TrackControls> {
+ static bool requested(const blink::TrackControls& controls) {
+ return controls.requested;
+ }
+
+ static const blink::MediaStreamType& stream_type(
+ const blink::TrackControls& controls) {
+ return controls.stream_type;
+ }
+
+ static const std::string& device_id(const blink::TrackControls& controls) {
+ return controls.device_id;
+ }
+
+ static bool Read(blink::mojom::TrackControlsDataView input,
+ blink::TrackControls* out);
+};
+
+template <>
+struct StructTraits<blink::mojom::StreamControlsDataView,
+ blink::StreamControls> {
+ static const blink::TrackControls& audio(
+ const blink::StreamControls& controls) {
+ return controls.audio;
+ }
+
+ static const blink::TrackControls& video(
+ const blink::StreamControls& controls) {
+ return controls.video;
+ }
+
+ static bool hotword_enabled(const blink::StreamControls& controls) {
+ return controls.hotword_enabled;
+ }
+
+ static bool disable_local_echo(const blink::StreamControls& controls) {
+ return controls.disable_local_echo;
+ }
+
+ static bool Read(blink::mojom::StreamControlsDataView input,
+ blink::StreamControls* out);
+};
+
+} // namespace mojo
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_MOJOM_TRAITS_H_
diff --git a/chromium/third_party/blink/public/common/mediastream/media_stream_request.h b/chromium/third_party/blink/public/common/mediastream/media_stream_request.h
new file mode 100644
index 00000000000..d38d218ea11
--- /dev/null
+++ b/chromium/third_party/blink/public/common/mediastream/media_stream_request.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_REQUEST_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_REQUEST_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/video_facing.h"
+#include "media/capture/video/video_capture_device_descriptor.h"
+#include "media/mojo/interfaces/display_media_information.mojom.h"
+#include "third_party/blink/public/common/common_export.h"
+
+namespace blink {
+
+// Types of media streams. When updating this list, make sure to update the
+// predicates declared below, e.g. IsVideoScreenCaptureMediaType().
+enum MediaStreamType {
+ MEDIA_NO_SERVICE = 0,
+
+ // A device provided by the operating system (e.g., webcam input).
+ MEDIA_DEVICE_AUDIO_CAPTURE,
+ MEDIA_DEVICE_VIDEO_CAPTURE,
+
+ // Below MEDIA_GUM_* types represent the streams generated by
+ // getUserMedia() calls with constraints that are collected with legacy
+ // APIs for desktop and tab capture.
+ // Mirroring of a browser tab.
+ MEDIA_GUM_TAB_AUDIO_CAPTURE,
+ MEDIA_GUM_TAB_VIDEO_CAPTURE,
+ // Desktop media sources.
+ MEDIA_GUM_DESKTOP_VIDEO_CAPTURE,
+ // Capture system audio (post-mix loopback stream).
+ MEDIA_GUM_DESKTOP_AUDIO_CAPTURE,
+
+ // Enables the capture of a user's display, generated by getDisplayMedia()
+ // call.
+ MEDIA_DISPLAY_VIDEO_CAPTURE,
+
+ NUM_MEDIA_TYPES
+};
+
+// Types of media stream requests that can be made to the media controller.
+enum MediaStreamRequestType {
+ MEDIA_DEVICE_ACCESS = 0,
+ MEDIA_DEVICE_UPDATE,
+ MEDIA_GENERATE_STREAM,
+ MEDIA_OPEN_DEVICE_PEPPER_ONLY // Only used in requests made by Pepper.
+};
+
+// Elements in this enum should not be deleted or rearranged; the only
+// permitted operation is to add new elements before NUM_MEDIA_REQUEST_RESULTS.
+enum MediaStreamRequestResult {
+ MEDIA_DEVICE_OK = 0,
+ MEDIA_DEVICE_PERMISSION_DENIED = 1,
+ MEDIA_DEVICE_PERMISSION_DISMISSED = 2,
+ MEDIA_DEVICE_INVALID_STATE = 3,
+ MEDIA_DEVICE_NO_HARDWARE = 4,
+ MEDIA_DEVICE_INVALID_SECURITY_ORIGIN = 5,
+ MEDIA_DEVICE_TAB_CAPTURE_FAILURE = 6,
+ MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE = 7,
+ MEDIA_DEVICE_CAPTURE_FAILURE = 8,
+ MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED = 9,
+ MEDIA_DEVICE_TRACK_START_FAILURE_AUDIO = 10,
+ MEDIA_DEVICE_TRACK_START_FAILURE_VIDEO = 11,
+ MEDIA_DEVICE_NOT_SUPPORTED = 12,
+ MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN = 13,
+ MEDIA_DEVICE_KILL_SWITCH_ON = 14,
+ MEDIA_DEVICE_SYSTEM_PERMISSION_DENIED = 15,
+ NUM_MEDIA_REQUEST_RESULTS
+};
+
+using CameraCalibration =
+ media::VideoCaptureDeviceDescriptor::CameraCalibration;
+
+// Convenience predicates to determine whether the given type represents some
+// audio or some video device.
+BLINK_COMMON_EXPORT bool IsAudioInputMediaType(MediaStreamType type);
+BLINK_COMMON_EXPORT bool IsVideoInputMediaType(MediaStreamType type);
+BLINK_COMMON_EXPORT bool IsScreenCaptureMediaType(MediaStreamType type);
+// Whether the |type| captures anything on the screen.
+BLINK_COMMON_EXPORT bool IsVideoScreenCaptureMediaType(MediaStreamType type);
+BLINK_COMMON_EXPORT bool IsDesktopCaptureMediaType(MediaStreamType type);
+BLINK_COMMON_EXPORT bool IsVideoDesktopCaptureMediaType(MediaStreamType type);
+BLINK_COMMON_EXPORT bool IsTabCaptureMediaType(MediaStreamType type);
+BLINK_COMMON_EXPORT bool IsDeviceMediaType(MediaStreamType type);
+
+// TODO(xians): Change the structs to classes.
+// Represents one device in a request for media stream(s).
+struct BLINK_COMMON_EXPORT MediaStreamDevice {
+ static const int kNoId;
+
+ MediaStreamDevice();
+
+ MediaStreamDevice(MediaStreamType type,
+ const std::string& id,
+ const std::string& name);
+
+ MediaStreamDevice(
+ MediaStreamType type,
+ const std::string& id,
+ const std::string& name,
+ media::VideoFacingMode facing,
+ const base::Optional<std::string>& group_id = base::nullopt);
+
+ MediaStreamDevice(MediaStreamType type,
+ const std::string& id,
+ const std::string& name,
+ int sample_rate,
+ int channel_layout,
+ int frames_per_buffer);
+
+ MediaStreamDevice(const MediaStreamDevice& other);
+
+ ~MediaStreamDevice();
+
+ MediaStreamDevice& operator=(const MediaStreamDevice& other);
+
+ bool IsSameDevice(const MediaStreamDevice& other_device) const;
+
+ // The device's type.
+ MediaStreamType type;
+
+ // The device's unique ID.
+ std::string id;
+
+ // The facing mode for video capture device.
+ media::VideoFacingMode video_facing;
+
+ // The device's group ID.
+ base::Optional<std::string> group_id;
+
+ // The device id of a matched output device if any (otherwise empty).
+ // Only applicable to audio devices.
+ base::Optional<std::string> matched_output_device_id;
+
+ // The device's "friendly" name. Not guaranteed to be unique.
+ std::string name;
+
+ // Contains the device properties of the capture device. It's valid only when
+ // the type of device is audio (i.e. IsAudioInputMediaType returns true).
+ media::AudioParameters input =
+ media::AudioParameters::UnavailableDeviceParams();
+
+ // Id for this capture session. Unique for all sessions of the same type.
+ int session_id = kNoId;
+
+ // This field is optional and available only for some camera models.
+ base::Optional<CameraCalibration> camera_calibration;
+
+ // This field is optional and available only for display media devices.
+ base::Optional<media::mojom::DisplayMediaInformationPtr> display_media_info;
+};
+
+using MediaStreamDevices = std::vector<MediaStreamDevice>;
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_MEDIASTREAM_MEDIA_STREAM_REQUEST_H_
diff --git a/chromium/third_party/blink/public/common/service_worker/service_worker_utils.h b/chromium/third_party/blink/public/common/service_worker/service_worker_utils.h
index 00e5cc1a4d5..fe2d9474662 100644
--- a/chromium/third_party/blink/public/common/service_worker/service_worker_utils.h
+++ b/chromium/third_party/blink/public/common/service_worker/service_worker_utils.h
@@ -9,6 +9,33 @@
namespace blink {
+// Specifies strategy to generate V8 eager code cache when a script is stored
+// into CacheStorage by a service worker. Eager code cache is more exhaustive
+// code cache and generated by specifing v8::ScriptCompiler::kEagerCompile.
+// Refer to https://crbug.com/768705 for more details.
+//
+// The default strategy is |kDuringInstallEvent|.
+//
+// IMPORTANT NOTE: We have some other heuristics/mechanisms to generate
+// (non eager) code cache outside service worker. This does NOT affect other
+// code caching mechanisms.
+enum class EagerCodeCacheStrategy {
+ // Never generate eager code cache.
+ kDontGenerate,
+ // Generate eager code cache when Cache#put() is called in install event
+ // handlers. The promise of Cache#put() is resolved after the code cache is
+ // generated. Don't generate eager code cache outside install event handlers.
+ kDuringInstallEvent,
+ // This specifies the same behavior as |kDuringInstallEvent| but also
+ // schedules an idle task to generate eager code cache if Cache#put()
+ // is called outside install event handlers (e.g. fetch event handlers).
+ // The promise of Cache#put() doesn't wait for cache generation when put()
+ // is called outside install event handlers.
+ kOnIdleTask,
+};
+
+BLINK_COMMON_EXPORT extern const char kServiceWorkerEagerCodeCacheStrategy[];
+
class ServiceWorkerUtils {
public:
// Whether the new service worker glue for NetworkService is enabled (i.e.,
@@ -17,6 +44,8 @@ class ServiceWorkerUtils {
static bool BLINK_COMMON_EXPORT IsServicificationEnabled();
static bool BLINK_COMMON_EXPORT IsImportedScriptUpdateCheckEnabled();
+
+ static EagerCodeCacheStrategy BLINK_COMMON_EXPORT GetEagerCodeCacheStrategy();
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/mojom/BUILD.gn b/chromium/third_party/blink/public/mojom/BUILD.gn
index 65335492728..731da16b5a0 100644
--- a/chromium/third_party/blink/public/mojom/BUILD.gn
+++ b/chromium/third_party/blink/public/mojom/BUILD.gn
@@ -9,40 +9,54 @@ import("//mojo/public/tools/bindings/mojom.gni")
# are typemapped to a type in renderer/core.
mojom("mojom_platform") {
sources = [
+ "ad_tagging/ad_frame.mojom",
+ "appcache/appcache.mojom",
+ "appcache/appcache_info.mojom",
"array_buffer/array_buffer_contents.mojom",
"associated_interfaces/associated_interfaces.mojom",
+ "background_fetch/background_fetch.mojom",
"blob/blob.mojom",
"blob/blob_registry.mojom",
"blob/blob_url_store.mojom",
"blob/data_element.mojom",
"blob/serialized_blob.mojom",
+ "cache_storage/cache_storage.mojom",
"choosers/file_chooser.mojom",
"clipboard/clipboard.mojom",
"color_chooser/color_chooser.mojom",
+ "contacts/contacts_manager.mojom",
"cookie_store/cookie_store.mojom",
"crash/crash_memory_metrics_reporter.mojom",
+ "csp/content_security_policy.mojom",
+ "devtools/console_message.mojom",
+ "devtools/devtools_agent.mojom",
"dom_storage/session_storage_namespace.mojom",
"dom_storage/storage_area.mojom",
"dom_storage/storage_partition_service.mojom",
"feature_policy/feature_policy.mojom",
+ "fetch/fetch_api_request.mojom",
"fetch/fetch_api_response.mojom",
"file/file_utilities.mojom",
"filesystem/file_system.mojom",
"filesystem/file_writer.mojom",
+ "frame/document_interface_broker.mojom",
"frame/find_in_page.mojom",
+ "frame/frame_host_test_interface.mojom",
"frame/navigation_initiator.mojom",
"leak_detector/leak_detector.mojom",
"loader/code_cache.mojom",
"loader/navigation_predictor.mojom",
"loader/pause_subresource_loading_handle.mojom",
"loader/previews_resource_loading_hints.mojom",
+ "loader/url_loader_factory_bundle.mojom",
"manifest/display_mode.mojom",
"manifest/manifest.mojom",
"manifest/manifest_manager.mojom",
+ "mediastream/media_devices.mojom",
+ "mediastream/media_stream.mojom",
"net/ip_address_space.mojom",
"notifications/notification.mojom",
"page/display_cutout.mojom",
- "page/page_visibility_state.mojom",
"payments/payment_app.mojom",
"plugins/plugin_registry.mojom",
"presentation/presentation.mojom",
@@ -50,6 +64,7 @@ mojom("mojom_platform") {
"quota/quota_types.mojom",
"referrer.mojom",
"script/script_type.mojom",
+ "serial/serial.mojom",
"service_worker/dispatch_fetch_event_params.mojom",
"service_worker/navigation_preload_state.mojom",
"service_worker/service_worker_client.mojom",
@@ -60,16 +75,28 @@ mojom("mojom_platform") {
"service_worker/service_worker_provider_type.mojom",
"service_worker/service_worker_state.mojom",
"service_worker/service_worker_stream_handle.mojom",
- "shared_worker/shared_worker_creation_context_type.mojom",
- "shared_worker/worker_main_script_load_params.mojom",
"speech/speech_recognition_error.mojom",
"speech/speech_recognition_grammar.mojom",
"speech/speech_recognition_result.mojom",
"speech/speech_recognizer.mojom",
"use_counter/css_property_id.mojom",
+ "wake_lock/wake_lock.mojom",
"webaudio/audio_context_manager.mojom",
+ "worker/dedicated_worker_factory.mojom",
+ "worker/shared_worker.mojom",
+ "worker/shared_worker_client.mojom",
+ "worker/shared_worker_connector.mojom",
+ "worker/shared_worker_creation_context_type.mojom",
+ "worker/shared_worker_host.mojom",
+ "worker/shared_worker_info.mojom",
+ "worker/worker_content_settings_proxy.mojom",
+ "worker/worker_main_script_load_params.mojom",
]
+ if (is_win) {
+ sources += [ "dwrite_font_proxy/dwrite_font_proxy.mojom" ]
+ }
+
public_deps = [
":android_mojo_bindings",
":speech_recognition_error_code",
@@ -78,13 +105,23 @@ mojom("mojom_platform") {
"//mojo/public/mojom/base",
"//services/device/public/mojom",
"//services/network/public/mojom",
+ "//services/service_manager/public/mojom",
"//skia/public/interfaces",
+ "//third_party/blink/public:web_feature_mojo_bindings",
"//third_party/blink/public/mojom/usb",
"//ui/gfx/geometry/mojo",
"//url/mojom:url_mojom_gurl",
"//url/mojom:url_mojom_origin",
]
+ # iOS doesn't use and must not depend on //media
+ if (!is_ios) {
+ public_deps += [
+ "//media/capture/mojom:video_capture",
+ "//media/mojo/interfaces",
+ ]
+ }
+
export_class_attribute = "BLINK_COMMON_EXPORT"
export_define = "BLINK_COMMON_IMPLEMENTATION=1"
export_header = "third_party/blink/public/common/common_export.h"
@@ -116,19 +153,23 @@ mojom("android_mojo_bindings") {
# Kept separate from "mojom_platform" because the Java bindings are needed by
# Android's implementation of speech recognition.
-mojom("speech_recognition_error_code") {
+mojom_component("speech_recognition_error_code") {
sources = [
"speech/speech_recognition_error_code.mojom",
]
+
+ macro_prefix = "SPEECH_RECOGNITION_ERROR_CODE_MOJOM"
+ output_prefix = "speech_recognition_error_code_mojom"
}
# This target can include mojom interfaces which do use types that are
# typemapped to a type in renderer/core. This also means these interfaces are
# not available from renderer/platform.
# Note that service_worker_object.mojom and service_worker.mojom depend
-# on transferable_message.mojom, and service_worker_registration.mojom depends
-# on service_worker_object.mojom, so we put these three service worker
-# mojom files here rather than mojom_platform target.
+# on transferable_message.mojom, and controller_service_worker.mojom and
+# service_worker_registration.mojom depend on service_worker_object.mojom, so
+# we put these service worker mojom files here rather than mojom_platform
+# target.
# In future we may have a separate mojom target for the things that may have
# modules dependencies if it looks necessary, at that time we can put all of
# those high-level service worker mojom files there.
@@ -138,19 +179,30 @@ mojom("mojom_core") {
"messaging/transferable_message.mojom",
"messaging/user_activation_snapshot.mojom",
"portal/portal.mojom",
+ "service_worker/controller_service_worker.mojom",
"service_worker/service_worker.mojom",
+ "service_worker/service_worker_container.mojom",
"service_worker/service_worker_object.mojom",
+ "service_worker/service_worker_provider.mojom",
"service_worker/service_worker_registration.mojom",
]
public_deps = [
":mojom_platform",
+ "//components/payments/mojom",
"//mojo/public/mojom/base",
+ "//services/network/public/mojom",
+ "//services/service_manager/public/mojom",
"//skia/public/interfaces",
+ "//third_party/blink/public:web_feature_mojo_bindings",
"//url/mojom:url_mojom_gurl",
+ "//url/mojom:url_mojom_origin",
]
- overridden_deps_blink = [ ":mojom_platform" ]
+ overridden_deps_blink = [
+ ":mojom_platform",
+ "//services/network/public/mojom",
+ ]
component_deps_blink = [ "//third_party/blink/renderer/platform" ]
export_class_attribute = "BLINK_COMMON_EXPORT"
diff --git a/chromium/third_party/blink/public/platform/modules/mediastream/OWNERS b/chromium/third_party/blink/public/mojom/ad_tagging/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/third_party/blink/public/platform/modules/mediastream/OWNERS
+++ b/chromium/third_party/blink/public/mojom/ad_tagging/OWNERS
diff --git a/chromium/third_party/blink/public/mojom/ad_tagging/ad_frame.mojom b/chromium/third_party/blink/public/mojom/ad_tagging/ad_frame.mojom
new file mode 100644
index 00000000000..efa9971a6a0
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/ad_tagging/ad_frame.mojom
@@ -0,0 +1,16 @@
+// 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.
+
+module blink.mojom;
+
+// Enumeration of ad frame types.
+enum AdFrameType {
+ // Frame is not an ad.
+ kNonAd,
+ // Frame is an ad whose parent frame is an ad.
+ kChildAd,
+ // Frame is an ad whose parent frame is not an ad.
+ kRootAd
+};
+
diff --git a/chromium/third_party/blink/public/mojom/appcache/OWNERS b/chromium/third_party/blink/public/mojom/appcache/OWNERS
new file mode 100644
index 00000000000..f1cba72f050
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/appcache/OWNERS
@@ -0,0 +1,8 @@
+file://content/browser/appcache/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: storage-dev@chromium.org
+# COMPONENT: Blink>Storage>AppCache
+
diff --git a/chromium/third_party/blink/public/mojom/appcache/appcache.mojom b/chromium/third_party/blink/public/mojom/appcache/appcache.mojom
new file mode 100644
index 00000000000..119396773c7
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/appcache/appcache.mojom
@@ -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.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/appcache/appcache_info.mojom";
+import "url/mojom/url.mojom";
+import "services/network/public/mojom/url_loader_factory.mojom";
+
+const int64 kAppCacheNoHostId = 0;
+
+enum AppCacheEventID {
+ APPCACHE_CHECKING_EVENT = 0,
+ APPCACHE_ERROR_EVENT,
+ APPCACHE_NO_UPDATE_EVENT,
+ APPCACHE_DOWNLOADING_EVENT,
+ APPCACHE_PROGRESS_EVENT,
+ APPCACHE_UPDATE_READY_EVENT,
+ APPCACHE_CACHED_EVENT,
+ APPCACHE_OBSOLETE_EVENT,
+};
+
+enum AppCacheErrorReason {
+ APPCACHE_MANIFEST_ERROR,
+ APPCACHE_SIGNATURE_ERROR,
+ APPCACHE_RESOURCE_ERROR,
+ APPCACHE_CHANGED_ERROR,
+ APPCACHE_ABORT_ERROR,
+ APPCACHE_QUOTA_ERROR,
+ APPCACHE_POLICY_ERROR,
+ APPCACHE_UNKNOWN_ERROR,
+};
+
+struct AppCacheResourceInfo {
+ url.mojom.Url url;
+ int64 size;
+ bool is_master;
+ bool is_manifest;
+ bool is_intercept;
+ bool is_fallback;
+ bool is_foreign;
+ bool is_explicit;
+ int64 response_id;
+};
+
+struct AppCacheErrorDetails {
+ string message;
+ AppCacheErrorReason reason = APPCACHE_UNKNOWN_ERROR;
+ url.mojom.Url url;
+ int32 status;
+ bool is_cross_origin;
+};
+
+
+// AppCache messages sent from the child process to the browser.
+interface AppCacheBackend {
+ // Informs the browser of a new appcache host.
+ RegisterHost(int32 host_id);
+
+ // Informs the browser of an appcache host being destroyed.
+ UnregisterHost(int32 host_id);
+
+ // Informs the browser of which host caused another to be created.
+ // This can influence which appcache should be utilized for the main
+ // resource load into the newly created host, so it should be sent
+ // prior to the main resource request being initiated.
+ SetSpawningHostId(int32 host_id, int32 spawning_host_id);
+
+ // Initiates the cache selection algorithm for the given host.
+ // This is sent prior to any subresource loads. An AppCacheMsg_CacheSelected
+ // message will be sent in response.
+ // 'host_id' indentifies a specific document or worker
+ // 'document_url' the url of the main resource
+ // 'appcache_document_was_loaded_from' the id of the appcache the main
+ // resource was loaded from or kAppCacheNoCacheId
+ // 'opt_manifest_url' the manifest url specified in the <html> tag if any
+ SelectCache(int32 host_id,
+ url.mojom.Url document_url,
+ int64 appcache_document_was_loaded_from,
+ url.mojom.Url opt_manifest_url);
+
+ // Initiates worker specific cache selection algorithm for the given host.
+ SelectCacheForSharedWorker(int32 host_id, int64 appcache_id);
+
+ // Informs the browser of a 'foreign' entry in an appcache.
+ MarkAsForeignEntry(int32 host_id,
+ url.mojom.Url document_url,
+ int64 appcache_document_was_loaded_from);
+
+ // Returns the status of the appcache associated with host_id.
+ [Sync]
+ GetStatus(int32 host_id) => (AppCacheStatus status);
+
+ // Initiates an update of the appcache associated with host_id.
+ [Sync]
+ StartUpdate(int32 host_id) => (bool success);
+
+ // Swaps a new pending appcache, if there is one, into use for host_id.
+ [Sync]
+ SwapCache(int32 host_id) => (bool success);
+
+ // Gets resource list from appcache synchronously.
+ [Sync]
+ GetResourceList(int32 host_id) => (array<AppCacheResourceInfo> resources);
+};
+
+// AppCache messages sent from the browser to the renderer process.
+interface AppCacheFrontend {
+ // Notifies the renderer of the appcache that has been selected for a
+ // a particular host. This is sent in reply to AppCacheHostMsg_SelectCache.
+ CacheSelected(int32 host_id, AppCacheInfo info);
+
+ // Notifies the renderer of an AppCache status change.
+ StatusChanged(array<int32> host_ids, AppCacheStatus status);
+
+ // Notifies the renderer of an AppCache event other than the
+ // progress event which has a seperate message.
+ EventRaised(array<int32> host_ids, AppCacheEventID event_id);
+
+ // Notifies the renderer of an AppCache progress event.
+ ProgressEventRaised(array<int32> host_ids,
+ url.mojom.Url url,
+ int32 total,
+ int32 complete);
+
+ // Notifies the renderer of an AppCache error event.
+ ErrorEventRaised(array<int32> host_ids, AppCacheErrorDetails error_details);
+
+ // Notifies the renderer of an AppCache logging message.
+ LogMessage(int32 host_id, int32 log_level, string message);
+
+ // Notifies the renderer of the fact that AppCache access was blocked.
+ ContentBlocked(int32 host_id, url.mojom.Url manifest_url);
+
+ // In the network service world this message sets the URLLoaderFactory to be
+ // used for subresources.
+ SetSubresourceFactory(int32 host_id,
+ network.mojom.URLLoaderFactory url_loader_factory);
+};
+
diff --git a/chromium/third_party/blink/public/mojom/appcache/appcache_info.mojom b/chromium/third_party/blink/public/mojom/appcache/appcache_info.mojom
new file mode 100644
index 00000000000..8f17fd2dc73
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/appcache/appcache_info.mojom
@@ -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.
+
+module blink.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+import "url/mojom/url.mojom";
+
+const int64 kAppCacheNoCacheId = 0;
+const int64 kAppCacheNoResponseId = 0;
+const int64 kAppCacheUnknownCacheId = -1;
+
+// The AppCacheStatus numeric values are specified in the HTML5 spec.
+enum AppCacheStatus {
+ APPCACHE_STATUS_UNCACHED = 0,
+ APPCACHE_STATUS_IDLE = 1,
+ APPCACHE_STATUS_CHECKING = 2,
+ APPCACHE_STATUS_DOWNLOADING = 3,
+ APPCACHE_STATUS_UPDATE_READY = 4,
+ APPCACHE_STATUS_OBSOLETE = 5,
+};
+
+struct AppCacheInfo {
+ url.mojom.Url manifest_url;
+ mojo_base.mojom.Time creation_time;
+ mojo_base.mojom.Time last_update_time;
+ mojo_base.mojom.Time last_access_time;
+ int64 cache_id;
+ int64 group_id;
+ AppCacheStatus status;
+ int64 size;
+ bool is_complete;
+};
diff --git a/chromium/third_party/blink/public/mojom/background_fetch/OWNERS b/chromium/third_party/blink/public/mojom/background_fetch/OWNERS
new file mode 100644
index 00000000000..f239b900df3
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/background_fetch/OWNERS
@@ -0,0 +1,7 @@
+peter@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: platform-capabilities@chromium.org
+# COMPONENT: Blink>BackgroundFetch
diff --git a/chromium/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom b/chromium/third_party/blink/public/mojom/background_fetch/background_fetch.mojom
index 3e78d8bce36..eca2cf3b0f6 100644
--- a/chromium/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
+++ b/chromium/third_party/blink/public/mojom/background_fetch/background_fetch.mojom
@@ -5,8 +5,8 @@
module blink.mojom;
import "skia/public/interfaces/bitmap.mojom";
-import "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom";
-import "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom";
+import "third_party/blink/public/mojom/cache_storage/cache_storage.mojom";
+import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
import "third_party/blink/public/mojom/fetch/fetch_api_response.mojom";
import "third_party/blink/public/mojom/manifest/manifest.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
@@ -55,8 +55,8 @@ enum BackgroundFetchFailureReason {
// "quota-exceeded":
QUOTA_EXCEEDED = 6,
- // "total-download-exceeded":
- TOTAL_DOWNLOAD_SIZE_EXCEEDED = 7,
+ // "download-total-exceeded":
+ DOWNLOAD_TOTAL_EXCEEDED = 7,
};
// Represents the optional options a developer can provide when starting a new
@@ -84,8 +84,9 @@ struct BackgroundFetchRegistration {
uint64 uploaded;
uint64 download_total;
uint64 downloaded;
- BackgroundFetchResult result;
- BackgroundFetchFailureReason failure_reason;
+ BackgroundFetchResult result = BackgroundFetchResult.UNSET;
+ BackgroundFetchFailureReason failure_reason =
+ BackgroundFetchFailureReason.NONE;
};
// This contains the data we need to record UKM metrics, that isn't needed for
@@ -111,6 +112,11 @@ interface BackgroundFetchRegistrationObserver {
// fetch is no longer available. The mojo connection will be closed after
// this call.
OnRecordsUnavailable();
+
+ // Notifies the BackgroundFetchRegistration that the |request| has completed.
+ // |response| points to the completed response, if any.
+ OnRequestCompleted(FetchAPIRequest request,
+ FetchAPIResponse? response);
};
// Interface for Background Fetch tasks. Lives in the browser process.
diff --git a/chromium/third_party/blink/public/platform/modules/cache_storage/OWNERS b/chromium/third_party/blink/public/mojom/cache_storage/OWNERS
index a227a76b69c..a227a76b69c 100644
--- a/chromium/third_party/blink/public/platform/modules/cache_storage/OWNERS
+++ b/chromium/third_party/blink/public/mojom/cache_storage/OWNERS
diff --git a/chromium/third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom b/chromium/third_party/blink/public/mojom/cache_storage/cache_storage.mojom
index 1b4399809be..db98a3e35fe 100644
--- a/chromium/third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom
+++ b/chromium/third_party/blink/public/mojom/cache_storage/cache_storage.mojom
@@ -4,9 +4,11 @@
module blink.mojom;
+import "mojo/public/mojom/base/time.mojom";
import "third_party/blink/public/mojom/fetch/fetch_api_response.mojom";
-import "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom";
+import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
import "mojo/public/mojom/base/string16.mojom";
+import "url/mojom/url.mojom";
// This enum is used in histograms, so do not change the ordering and always
// append new types to the end.
@@ -111,6 +113,11 @@ interface CacheStorageCache {
// Perform a batch of operations, used for PUT and DELETE operations.
Batch(array<BatchOperation> batch_operations, bool fail_on_duplicates)
=> (CacheStorageVerboseError result);
+
+ // Sets |side_data| if there is an entry of which key is |url| and the entry
+ // has the same |response_time|.
+ SetSideData(url.mojom.Url url, mojo_base.mojom.Time response_time,
+ array<uint8> side_data) => (CacheStorageError result);
};
// Handles global CacheStorage methods, directly relates to methods available on
diff --git a/chromium/third_party/blink/public/mojom/contacts/OWNERS b/chromium/third_party/blink/public/mojom/contacts/OWNERS
new file mode 100644
index 00000000000..5ef10c78cb1
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/contacts/OWNERS
@@ -0,0 +1,8 @@
+finnur@chromium.org
+peter@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: platform-capabilities@chromium.org
+# COMPONENT: Blink>Contacts
diff --git a/chromium/third_party/blink/public/mojom/contacts/contacts_manager.mojom b/chromium/third_party/blink/public/mojom/contacts/contacts_manager.mojom
new file mode 100644
index 00000000000..d0bd9eb36a0
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/contacts/contacts_manager.mojom
@@ -0,0 +1,23 @@
+// 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.
+
+module blink.mojom;
+
+// As per https://github.com/beverloo/contact-api.
+struct ContactInfo {
+ array<string>? name;
+ array<string>? email;
+ array<string>? tel;
+};
+
+// The Contacts Manager lives in the browser process and can be initiated by the
+// renderer via a JS call to navigator.contacts.select.
+interface ContactsManager {
+ // Show a dialog, allowing the user to select which contacts to share with the
+ // website. The array of contacts returned can be null, in case of an error,
+ // for example if the dialog cannot be shown. The array is empty if the user
+ // does not select any contacts (e.g. cancels selection).
+ Select(bool multiple, bool include_names, bool include_emails, bool include_tel)
+ => (array<ContactInfo>? contacts);
+};
diff --git a/chromium/third_party/blink/public/mojom/csp/OWNERS b/chromium/third_party/blink/public/mojom/csp/OWNERS
new file mode 100644
index 00000000000..a575f099c96
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/csp/OWNERS
@@ -0,0 +1,7 @@
+file://third_party/blink/renderer/core/frame/csp/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: security-dev@chromium.org
+# COMPONENT: Blink>SecurityFeature>ContentSecurityPolicy
diff --git a/chromium/third_party/blink/public/mojom/csp/README.md b/chromium/third_party/blink/public/mojom/csp/README.md
new file mode 100644
index 00000000000..e23c05e39ff
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/csp/README.md
@@ -0,0 +1 @@
+Public mojom files that are referenced both from browser-side and renderer-side for [Content Security Policy](https://w3c.github.io/webappsec-csp/).
diff --git a/chromium/third_party/blink/public/platform/content_security_policy.mojom b/chromium/third_party/blink/public/mojom/csp/content_security_policy.mojom
index fc513055386..74114f4eef6 100644
--- a/chromium/third_party/blink/public/platform/content_security_policy.mojom
+++ b/chromium/third_party/blink/public/mojom/csp/content_security_policy.mojom
@@ -4,8 +4,6 @@
module blink.mojom;
-// TODO(darin): Update all WebContentSecurityPolicyType consumers to use this
-// type instead, and remove the typemap.
enum ContentSecurityPolicyType {
kReport,
kEnforce,
diff --git a/chromium/third_party/blink/public/mojom/devtools/OWNERS b/chromium/third_party/blink/public/mojom/devtools/OWNERS
new file mode 100644
index 00000000000..43016bc0432
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/devtools/OWNERS
@@ -0,0 +1,7 @@
+file://third_party/blink/renderer/core/inspector/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: devtools-dev@chromium.org
+# COMPONENT: Platform>DevTools
diff --git a/chromium/third_party/blink/public/mojom/devtools/README.md b/chromium/third_party/blink/public/mojom/devtools/README.md
new file mode 100644
index 00000000000..999c7e22e72
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/devtools/README.md
@@ -0,0 +1 @@
+Public mojom files that are referenced both from browser-side and renderer-side for DevTools.
diff --git a/chromium/third_party/blink/public/mojom/devtools/console_message.mojom b/chromium/third_party/blink/public/mojom/devtools/console_message.mojom
new file mode 100644
index 00000000000..b0b5c8bfa68
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/devtools/console_message.mojom
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module blink.mojom;
+
+// TODO(leonhsl) We can remove blink::MessageLevel and
+// content::ConsoleMessageLevel by using this mojom enum instead.
+enum ConsoleMessageLevel {
+ kVerbose,
+ kInfo,
+ kWarning,
+ kError
+};
diff --git a/chromium/third_party/blink/public/web/devtools_agent.mojom b/chromium/third_party/blink/public/mojom/devtools/devtools_agent.mojom
index b866ac2f5b8..69aae52a42c 100644
--- a/chromium/third_party/blink/public/web/devtools_agent.mojom
+++ b/chromium/third_party/blink/public/mojom/devtools/devtools_agent.mojom
@@ -81,7 +81,7 @@ interface DevToolsAgent {
// |wait_for_debugger| controls whether the worker should be paused
// on start waiting for debugger to connect.
// See ChildWorkerCreated in DevToolsAgentHost for details.
- ReportChildWorkers(bool report, bool wait_for_debugger);
+ ReportChildWorkers(bool report, bool wait_for_debugger) => ();
};
// This interface is implemented in browser and is notified by DevToolsAgent
diff --git a/chromium/third_party/blink/public/mojom/dwrite_font_proxy/OWNERS b/chromium/third_party/blink/public/mojom/dwrite_font_proxy/OWNERS
new file mode 100644
index 00000000000..0573276d3a4
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/dwrite_font_proxy/OWNERS
@@ -0,0 +1,6 @@
+drott@chromium.org
+
+# COMPONENT: Blink>Fonts
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/chromium/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom b/chromium/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom
new file mode 100644
index 00000000000..172a9e5e742
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom
@@ -0,0 +1,77 @@
+// 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.
+
+module blink.mojom;
+
+import "mojo/public/mojom/base/file.mojom";
+import "mojo/public/mojom/base/file_path.mojom";
+import "mojo/public/mojom/base/shared_memory.mojom";
+import "mojo/public/mojom/base/string16.mojom";
+
+struct DWriteStringPair {
+ mojo_base.mojom.String16 first;
+ mojo_base.mojom.String16 second;
+};
+
+struct DWriteFontStyle {
+ uint16 font_weight;
+ uint8 font_slant;
+ uint8 font_stretch;
+};
+
+struct MapCharactersResult {
+ uint32 family_index;
+ mojo_base.mojom.String16 family_name;
+ uint32 mapped_length;
+ float scale;
+ DWriteFontStyle font_style;
+};
+
+interface DWriteFontProxy {
+ // Locates the index of the specified font family within the system
+ // collection.
+ [Sync]
+ FindFamily(mojo_base.mojom.String16 family_name) => (uint32 out_index);
+
+ // Returns the number of font families in the system collection.
+ [Sync]
+ GetFamilyCount() => (uint32 out_count);
+
+ // Returns the list of locale and family name pairs for the font family at the
+ // specified index.
+ [Sync]
+ GetFamilyNames(uint32 family_index)
+ => (array<DWriteStringPair> out_family_names);
+
+ // Returns the list of font file paths in the system font directory that
+ // contain font data for the font family at the specified index.
+ [Sync]
+ GetFontFiles(uint32 family_index)
+ => (array<mojo_base.mojom.FilePath> file_paths,
+ array<mojo_base.mojom.File> file_handles);
+
+ // Returns a protobuf structured lookup list of
+ // (full_font_name|postscript_name) => (font_file + ttc_index) to the
+ // renderer process as a ReadOnlySharedMemoryRegion. The lookup list is built
+ // on the first renderer call to retrieving this list. Use FontTableMatcher
+ // to perform searches in it.
+ [Sync]
+ GetUniqueNameLookupTable() =>
+ (mojo_base.mojom.ReadOnlySharedMemoryRegion font_lookup_table);
+
+ // Locates a font family that is able to render the specified text using the
+ // specified style. If successful, the family_index and family_name will
+ // indicate which family in the system font collection can render the
+ // requested text and the mapped_length will indicate how many characters can
+ // be rendered. If no font exists that can render the text, family_index will
+ // be UINT32_MAX and mapped_length will indicate how many characters cannot be
+ // rendered by any installed font.
+ [Sync]
+ MapCharacters(mojo_base.mojom.String16 text,
+ DWriteFontStyle font_style,
+ mojo_base.mojom.String16 locale_name,
+ uint32 reading_direction,
+ mojo_base.mojom.String16 base_family_name)
+ => (MapCharactersResult out);
+};
diff --git a/chromium/third_party/blink/public/mojom/feature_policy/feature_policy.mojom b/chromium/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
index 63d4b44c4e4..89c4276f888 100644
--- a/chromium/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
+++ b/chromium/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
@@ -99,6 +99,10 @@ enum FeaturePolicyFeature {
kLazyLoad = 29,
// Restricts the usage of layout-causing animations in a document.
kLayoutAnimations = 30,
+ // Controls access to WakeLock
+ kWakeLock = 31,
+ // Controls access to font-display attribute in @font-face CSS rule
+ kFontDisplay = 32,
// Don't change assigned numbers of any item, and don't reuse removed slots.
// Also, run update_feature_policy_enum.py in
@@ -119,6 +123,5 @@ enum FeaturePolicyDisposition {
struct ParsedFeaturePolicyDeclaration {
FeaturePolicyFeature feature;
bool matches_all_origins;
- FeaturePolicyDisposition disposition;
array<url.mojom.Origin> origins;
};
diff --git a/chromium/third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom b/chromium/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
index 15cc955f0fd..31cd8d67e6b 100644
--- a/chromium/third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom
+++ b/chromium/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
@@ -4,8 +4,10 @@
module blink.mojom;
+import "mojo/public/mojom/base/unguessable_token.mojom";
import "services/network/public/mojom/fetch_api.mojom";
import "services/network/public/mojom/request_context_frame_type.mojom";
+import "services/network/public/mojom/url_loader.mojom";
import "third_party/blink/public/mojom/blob/serialized_blob.mojom";
import "third_party/blink/public/mojom/referrer.mojom";
import "url/mojom/url.mojom";
@@ -100,6 +102,21 @@ enum FetchImportanceMode {
kImportanceHigh
};
+// Request headers for FetchAPIRequest. This is typemapped to a container with a
+// case insensitive compare or hash function.
+struct FetchAPIRequestHeaders {
+ map<string, string> headers;
+};
+
+// Struct representing a Request:
+// https://fetch.spec.whatwg.org/#request-class
+// Compared to network.mojom.URLRequest which is kind of internal data in the
+// loading stack, FetchAPIRequest acts as a direct representation of the JS
+// Request object in all API implementations like Background Fetch, Cache
+// Storage and Service Worker, with no need to care how the loading logic
+// happens.
+// Note: When updating this struct, also update
+// content/common/fetch/fetch_request_type_converters.cc.
struct FetchAPIRequest {
network.mojom.FetchRequestMode mode = network.mojom.FetchRequestMode.kNoCors;
bool is_main_resource_load = false;
@@ -108,8 +125,16 @@ struct FetchAPIRequest {
network.mojom.RequestContextFrameType.kNone;
url.mojom.Url url;
string method;
- map<string, string> headers;
+ FetchAPIRequestHeaders headers;
+
+ // Note: |blob| and |body| are mutually exclusive.
+ // |blob| is used in implementing Background Fetch APIs.
+ // |body| is used to represent the FetchEvent#request#body dispatched to
+ // service workers.
+ // TODO(crbug.com/911930): Remove |blob| and use |body| instead everywhere.
SerializedBlob? blob;
+ network.mojom.URLRequestBody? body;
+
Referrer? referrer;
network.mojom.FetchCredentialsMode credentials_mode =
network.mojom.FetchCredentialsMode.kOmit;
@@ -117,8 +142,13 @@ struct FetchAPIRequest {
network.mojom.FetchRedirectMode redirect_mode =
network.mojom.FetchRedirectMode.kFollow;
string? integrity;
+ network.mojom.RequestPriority priority = network.mojom.RequestPriority.kIdle;
+
+ // Id of the original requestor window.
+ // See network::ResourceRequest::fetch_window_id.
+ mojo_base.mojom.UnguessableToken? fetch_window_id;
+
bool keepalive = false;
- string? client_id;
bool is_reload = false;
bool is_history_navigation = false;
};
diff --git a/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom b/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
index 9f2482ebe80..4e023e9c4c3 100644
--- a/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
+++ b/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
@@ -36,6 +36,10 @@ struct FetchAPIResponse {
network.mojom.FetchResponseType response_type =
network.mojom.FetchResponseType.kOpaque;
+ // The source of this response, e.g. network, CacheStorage.
+ network.mojom.FetchResponseSource response_source =
+ network.mojom.FetchResponseSource.kUnspecified;
+
// The response headers. It's case insensitive for header name as key.
map<string, string> headers;
@@ -57,9 +61,6 @@ struct FetchAPIResponse {
// set of headers that should be exposed.
array<string> cors_exposed_header_names;
- // True when the response was retrieved from Cache Storage.
- bool is_in_cache_storage;
-
// Side data is used to pass the metadata of the response (eg. V8 code cache).
SerializedBlob? side_data_blob;
};
diff --git a/chromium/third_party/blink/public/mojom/filesystem/file_system.mojom b/chromium/third_party/blink/public/mojom/filesystem/file_system.mojom
index 1bb86845f8e..1bf3709f201 100644
--- a/chromium/third_party/blink/public/mojom/filesystem/file_system.mojom
+++ b/chromium/third_party/blink/public/mojom/filesystem/file_system.mojom
@@ -5,6 +5,7 @@
module blink.mojom;
import "components/services/filesystem/public/interfaces/types.mojom";
+import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
import "mojo/public/mojom/base/file_error.mojom";
import "mojo/public/mojom/base/file_path.mojom";
@@ -98,9 +99,9 @@ interface FileSystemManager {
// filesystem and a success error code if the operation succeeds. If the
// operation fails, |error_code| indicates the reason for failure.
// TODO(https://crbug.com/873661): Make interface per frame/worker and remove
- // |origin_url|.
+ // |origin|.
[Sync]
- Open(url.mojom.Url origin_url, blink.mojom.FileSystemType file_system_type) =>
+ Open(url.mojom.Origin origin, blink.mojom.FileSystemType file_system_type) =>
(string name,
url.mojom.Url root_url,
mojo_base.mojom.FileError error_code);
diff --git a/chromium/third_party/blink/public/mojom/frame/document_interface_broker.mojom b/chromium/third_party/blink/public/mojom/frame/document_interface_broker.mojom
new file mode 100644
index 00000000000..5afe5ceff2e
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/frame/document_interface_broker.mojom
@@ -0,0 +1,13 @@
+// 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.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/frame/frame_host_test_interface.mojom";
+
+// An interface through which the renderer may request document-scoped
+// interfaces from the browser.
+interface DocumentInterfaceBroker {
+ GetFrameHostTestInterface(blink.mojom.FrameHostTestInterface& request);
+};
diff --git a/chromium/third_party/blink/public/mojom/frame/frame_host_test_interface.mojom b/chromium/third_party/blink/public/mojom/frame/frame_host_test_interface.mojom
new file mode 100644
index 00000000000..19485a18cf1
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/frame/frame_host_test_interface.mojom
@@ -0,0 +1,23 @@
+// 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.
+
+module blink.mojom;
+
+import "url/mojom/url.mojom";
+
+// TODO(crbug.com/718652) This is a copy of
+// content/test/frame_host_test_interface.mojom to be used in parallel while
+// InterfaceProvider->DocumentInterfaceBroker conversion is taking place.
+
+// Test interface used in RenderFrame and RenderFrameHost tests to exercise
+// requesting document-scoped interfaces from the RenderFrameHost through
+// the DocumentInterfaceBroker interface.
+//
+// The `Ping` method is invoked by clients immediately after making the
+// FrameHostTestInterfaceRequest, so as to annotate where the request
+// originates from. This allows verification that the request was delivered /
+// not delivered to a certain DocumentInterfaceBroker implementation.
+interface FrameHostTestInterface {
+ Ping(url.mojom.Url source_url, string source_event);
+};
diff --git a/chromium/third_party/blink/public/mojom/indexeddb/indexeddb.mojom b/chromium/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
index 024a53d6eda..7e639bd27f4 100644
--- a/chromium/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
+++ b/chromium/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
@@ -32,13 +32,18 @@ enum IDBDataLoss {
Total,
};
-// Represents key types that hold no data and so cannot be options in the
-// IDBKeyData union.
-// TODO(jsbell): These types should be cleaned up end-to-end, leaving only the
-// dataful options.
-enum IDBDatalessKeyType {
+// In order of the least to the highest precedent in terms of sort order.
+// These values are written to logs. New enum values can be added, but
+// existing enums must never be renumbered or deleted and reused.
+enum IDBKeyType {
Invalid,
+ Array,
+ Binary,
+ String,
+ Date,
+ Number,
Null,
+ Min,
};
union IDBKeyData {
@@ -47,7 +52,10 @@ union IDBKeyData {
mojo_base.mojom.String16 string;
double date;
double number;
- IDBDatalessKeyType other;
+ // TODO(jsbell): These types should be cleaned up end-to-end, leaving only the
+ // dataful options above.
+ bool other_invalid;
+ bool other_null;
};
// Defined as a structure so that it can by typemapped with StructTraits.
@@ -55,6 +63,15 @@ struct IDBKey {
IDBKeyData data;
};
+// In order of the least to the highest precedent in terms of sort order.
+// These values are written to logs. New enum values can be added, but
+// existing enums must never be renumbered or deleted and reused.
+enum IDBKeyPathType {
+ Null,
+ String,
+ Array,
+};
+
// Represents WebIDBKeyPathTypeString and WebIDBKeyPathTypeArray in a key path.
union IDBKeyPathData {
mojo_base.mojom.String16 string;
@@ -120,7 +137,7 @@ struct IDBObjectStoreMetadata {
IDBKeyPath key_path;
bool auto_increment;
int64 max_index_id;
- array<IDBIndexMetadata> indexes;
+ map<int64, IDBIndexMetadata> indexes;
};
struct IDBDatabaseMetadata {
@@ -128,7 +145,7 @@ struct IDBDatabaseMetadata {
mojo_base.mojom.String16 name;
int64 version;
int64 max_object_store_id;
- array<IDBObjectStoreMetadata> object_stores;
+ map<int64, IDBObjectStoreMetadata> object_stores;
};
struct IDBNameAndVersion {
@@ -252,11 +269,28 @@ interface IDBDatabaseCallbacks {
Changes(IDBObserverChanges changes);
};
+struct IDBError {
+ int32 error_code;
+ mojo_base.mojom.String16 error_message;
+};
+
+struct IDBCursorValue {
+ IDBKey key;
+ IDBKey primary_key;
+ IDBValue value;
+};
+
interface IDBCursor {
- Advance(uint32 count, associated IDBCallbacks callbacks);
+ // Advance() can call its return callback in one of 3 ways:
+ // * with |error| set and |value| unset, if an error occurs
+ // * with |error| unset and |value| set, under normal operation
+ // * with |error| unset and |value| unset, under normal operation when the end
+ // of the source being iterated is reached
+ Advance(uint32 count) => (IDBError? error, IDBCursorValue? value);
+
// Avoid calling the following function "Continue" since the Mojo
// Java bindings generate incorrect Java as a result. We've named
- // the following funciton "CursorContinue" as a workaround.
+ // the following function "CursorContinue" as a workaround.
CursorContinue(IDBKey key,
IDBKey primary_key,
associated IDBCallbacks callbacks);
@@ -349,21 +383,20 @@ interface IDBDatabase {
int64 index_id,
mojo_base.mojom.String16 new_name);
Abort(int64 transaction_id);
- Commit(int64 transaction_id);
+ Commit(int64 transaction_id,
+ int64 num_errors_handled);
};
interface IDBFactory {
- GetDatabaseInfo(associated IDBCallbacks callbacks, url.mojom.Origin origin);
- GetDatabaseNames(associated IDBCallbacks callbacks, url.mojom.Origin origin);
+ GetDatabaseInfo(associated IDBCallbacks callbacks);
+ GetDatabaseNames(associated IDBCallbacks callbacks);
Open(associated IDBCallbacks callbacks,
associated IDBDatabaseCallbacks database_callbacks,
- url.mojom.Origin origin,
mojo_base.mojom.String16 name,
int64 version,
int64 transaction_id);
- DeleteDatabase(associated IDBCallbacks callbacks, url.mojom.Origin origin,
+ DeleteDatabase(associated IDBCallbacks callbacks,
mojo_base.mojom.String16 name, bool force_close);
- AbortTransactionsAndCompactDatabase(url.mojom.Origin origin) =>
- (IDBStatus status);
- AbortTransactionsForDatabase(url.mojom.Origin origin) => (IDBStatus status);
+ AbortTransactionsAndCompactDatabase() => (IDBStatus status);
+ AbortTransactionsForDatabase() => (IDBStatus status);
};
diff --git a/chromium/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom b/chromium/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom
new file mode 100644
index 00000000000..24ac0fcf26b
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom
@@ -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.
+
+module blink.mojom;
+
+import "services/network/public/mojom/url_loader_factory.mojom";
+import "url/mojom/origin.mojom";
+
+// A collection of URLLoaderFactory interfaces.
+//
+// This supports a scenario where URLLoaderFactoryBundle contains only
+// the factories that need to be updated (and allows leaving out factories
+// that should not be updated/cloberred).
+// See also blink::URLLoaderFactoryBundle::Update.
+struct URLLoaderFactoryBundle {
+ // The default factory to be used when no others apply.
+ // This must be non-null for a navigation commit when NetworkService is
+ // enabled. (In other cases all factories including this are optional)
+ //
+ // TODO(jam): https://crbug.com/887109: Remove |default_factory| and put it
+ // inside |scheme_specific_factories| instead.
+ network.mojom.URLLoaderFactory? default_factory;
+
+ // A mapping from URL scheme to factory interface.
+ map<string, network.mojom.URLLoaderFactory> scheme_specific_factories;
+
+ // A mapping from request-initiator-origin to factory interface.
+ map<url.mojom.Origin, network.mojom.URLLoaderFactory>
+ initiator_specific_factories;
+
+ // A special factory that is used for AppCache.
+ // TODO(https://crbug.com/582750): Drop this when AppCache is deprecated.
+ network.mojom.URLLoaderFactory? appcache_factory;
+
+ // Whether redirect checks should be bypassed, since they are happening in the
+ // browser.
+ bool bypass_redirect_checks = false;
+};
diff --git a/chromium/third_party/blink/public/mojom/manifest/manifest.mojom b/chromium/third_party/blink/public/mojom/manifest/manifest.mojom
index 4818501cb7e..0e746a614f4 100644
--- a/chromium/third_party/blink/public/mojom/manifest/manifest.mojom
+++ b/chromium/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -78,8 +78,8 @@ struct ManifestImageResource {
// The special value "any" is represented by gfx::Size(0, 0).
array<gfx.mojom.Size> sizes;
- // Defaults to a vector with a single value, Purpose::ANY, for all other
- // parsing exceptions.
+ // Never empty. Defaults to a vector with a single value, IconPurpose::ANY,
+ // if not explicitly specified in the manifest.
array<Purpose> purpose;
};
diff --git a/chromium/third_party/blink/public/mojom/mediastream/OWNERS b/chromium/third_party/blink/public/mojom/mediastream/OWNERS
new file mode 100644
index 00000000000..ff62c9c4e26
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/mediastream/OWNERS
@@ -0,0 +1,8 @@
+guidou@chromium.org
+hbos@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
+# COMPONENT: Blink>GetUserMedia
diff --git a/chromium/third_party/blink/public/platform/modules/mediastream/media_devices.mojom b/chromium/third_party/blink/public/mojom/mediastream/media_devices.mojom
index 85e82ebbec0..85e82ebbec0 100644
--- a/chromium/third_party/blink/public/platform/modules/mediastream/media_devices.mojom
+++ b/chromium/third_party/blink/public/mojom/mediastream/media_devices.mojom
diff --git a/chromium/third_party/blink/public/mojom/mediastream/media_stream.mojom b/chromium/third_party/blink/public/mojom/mediastream/media_stream.mojom
new file mode 100644
index 00000000000..300ebda5844
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/mediastream/media_stream.mojom
@@ -0,0 +1,127 @@
+// Copyright 2017 The Chromium 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 blink.mojom;
+
+import "media/capture/mojom/video_capture_types.mojom";
+import "media/mojo/interfaces/audio_parameters.mojom";
+import "media/mojo/interfaces/display_media_information.mojom";
+
+// Types of media streams (see public/common/media_stream_request.h).
+enum MediaStreamType {
+ MEDIA_NO_SERVICE,
+ MEDIA_DEVICE_AUDIO_CAPTURE,
+ MEDIA_DEVICE_VIDEO_CAPTURE,
+ MEDIA_GUM_TAB_AUDIO_CAPTURE,
+ MEDIA_GUM_TAB_VIDEO_CAPTURE,
+ MEDIA_GUM_DESKTOP_VIDEO_CAPTURE,
+ MEDIA_GUM_DESKTOP_AUDIO_CAPTURE,
+ MEDIA_DISPLAY_VIDEO_CAPTURE,
+ NUM_MEDIA_TYPES
+};
+
+// See public/common/media_stream_request.h.
+enum MediaStreamRequestResult {
+ OK,
+ PERMISSION_DENIED,
+ PERMISSION_DISMISSED,
+ INVALID_STATE,
+ NO_HARDWARE,
+ INVALID_SECURITY_ORIGIN,
+ TAB_CAPTURE_FAILURE,
+ SCREEN_CAPTURE_FAILURE,
+ CAPTURE_FAILURE,
+ CONSTRAINT_NOT_SATISFIED,
+ TRACK_START_FAILURE_AUDIO,
+ TRACK_START_FAILURE_VIDEO,
+ NOT_SUPPORTED,
+ FAILED_DUE_TO_SHUTDOWN,
+ KILL_SWITCH_ON,
+ SYSTEM_PERMISSION_DENIED
+};
+
+// See public/common/media_stream_request.h.
+struct MediaStreamDevice {
+ MediaStreamType type;
+ string id;
+ media.mojom.VideoFacingMode video_facing;
+ string? group_id;
+ string? matched_output_device_id;
+ string name;
+ media.mojom.AudioParameters input;
+ int32 session_id;
+ media.mojom.VideoCaptureDeviceDescriptorCameraCalibration? camera_calibration;
+ media.mojom.DisplayMediaInformation? display_media_info;
+};
+
+// See common/media/media_stream_controls.h.
+struct TrackControls {
+ bool requested;
+ MediaStreamType stream_type;
+ string device_id;
+};
+
+// See common/media/media_stream_controls.h.
+struct StreamControls {
+ TrackControls audio;
+ TrackControls video;
+ bool hotword_enabled;
+ bool disable_local_echo;
+};
+
+// Per-frame renderer-side interface that receives device stopped/change
+// notifications from the browser process.
+interface MediaStreamDeviceObserver {
+ OnDeviceStopped(string label, MediaStreamDevice device);
+ OnDeviceChanged(string label,
+ MediaStreamDevice old_device,
+ MediaStreamDevice new_device);
+};
+
+// Per-frame browser-side interface that is used by the renderer process to
+// make media stream requests.
+interface MediaStreamDispatcherHost {
+ // Requests a new media stream.
+ GenerateStream(int32 request_id, StreamControls controls, bool user_gesture)
+ => (MediaStreamRequestResult result, string label,
+ array<MediaStreamDevice> audio_devices,
+ array<MediaStreamDevice> video_devices);
+
+ // Cancels the request for a new media stream or opening a device.
+ CancelRequest(int32 request_id);
+
+ // Closes a stream device that has been opened by GenerateStream.
+ StopStreamDevice(string device_id, int32 session_id);
+
+ // Opens a device identified by |device_id|.
+ OpenDevice(int32 request_id, string device_id, MediaStreamType type)
+ => (bool success, string label, MediaStreamDevice device);
+
+ // Cancels an open request identified by |label|.
+ CloseDevice(string label);
+
+ // Tells the browser process if the video capture is secure (i.e., all
+ // connected video sinks meet the requirement of output protection.).
+ // Note: the browser process only trusts the |is_secure| value in this Mojo
+ // message if it's comimg from a trusted, whitelisted extension. Extensions
+ // run in separate render processes. So it shouldn't be possible, for example,
+ // for a user's visit to a malicious web page to compromise a render process
+ // running a trusted extension to make it report falsehood in this Mojo
+ // message.
+ SetCapturingLinkSecured(int32 session_id, MediaStreamType type,
+ bool is_secure);
+
+ // Tells the browser process that the stream has been started successfully.
+ OnStreamStarted(string label);
+};
+
+// Browser-side interface that is used by the renderer process to notify the
+// addition or deletion of tracks.
+interface MediaStreamTrackMetricsHost {
+ // Adds the track with the specified information to the list of tracks.
+ AddTrack(uint64 id, bool is_audio, bool is_remote);
+
+ // Removes the track with the specified ID from the list of tracks.
+ RemoveTrack(uint64 id);
+};
diff --git a/chromium/third_party/blink/public/mojom/page/page_visibility_state.mojom b/chromium/third_party/blink/public/mojom/page/page_visibility_state.mojom
deleted file mode 100644
index fa9b90ce7d4..00000000000
--- a/chromium/third_party/blink/public/mojom/page/page_visibility_state.mojom
+++ /dev/null
@@ -1,13 +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.
-
-module blink.mojom;
-
-// The types for Document#visibilityState and
-// (ServiceWorker)WindowClient#visibilityState
-enum PageVisibilityState {
- kVisible,
- kHidden,
- kPrerender,
-};
diff --git a/chromium/third_party/blink/public/mojom/payments/payment_request.mojom b/chromium/third_party/blink/public/mojom/payments/payment_request.mojom
index d50ed4d3738..fc3151003c6 100644
--- a/chromium/third_party/blink/public/mojom/payments/payment_request.mojom
+++ b/chromium/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -41,12 +41,17 @@ enum PaymentErrorReason {
enum CanMakePaymentQueryResult {
CAN_MAKE_PAYMENT,
CANNOT_MAKE_PAYMENT,
+};
+
+enum HasEnrolledInstrumentQueryResult {
+ HAS_ENROLLED_INSTRUMENT,
+ HAS_NO_ENROLLED_INSTRUMENT,
QUERY_QUOTA_EXCEEDED,
// Used only on localhost and file:// schemes to warn web developer that the
- // query quota has exceeded, but Chrome is returning an answer anyway.
- WARNING_CAN_MAKE_PAYMENT,
- WARNING_CANNOT_MAKE_PAYMENT,
+ // query quota has been exceeded, but Chrome is returning an answer anyway.
+ WARNING_HAS_ENROLLED_INSTRUMENT,
+ WARNING_HAS_NO_ENROLLED_INSTRUMENT,
};
interface PaymentRequestClient {
@@ -58,6 +63,7 @@ interface PaymentRequestClient {
OnComplete();
OnAbort(bool aborted_successfully);
OnCanMakePayment(CanMakePaymentQueryResult result);
+ OnHasEnrolledInstrument(HasEnrolledInstrumentQueryResult result);
WarnNoFavicon();
};
@@ -155,7 +161,8 @@ struct PaymentDetailsModifier {
struct PaymentDetails {
PaymentItem? total;
array<PaymentItem> display_items;
- array<PaymentShippingOption> shipping_options;
+ // Shipping options can be null if updateWith() is called w/o shippingOptions
+ array<PaymentShippingOption>? shipping_options;
array<PaymentDetailsModifier> modifiers;
string error = "";
AddressErrors? shipping_address_errors;
@@ -218,6 +225,14 @@ interface PaymentRequest {
// the payment response.
Retry(PaymentValidationErrors errors);
- // Queries whether the user has a form of payment on file.
+ // Queries whether support for the merchant-specified payment method is
+ // available, either because the user has a registered payment handler for
+ // that method, or because the browser can do just-in-time registration for a
+ // suitable payment handler.
CanMakePayment();
+
+ // Queries whether support for the merchant-specified payment method is
+ // available and the user has an enrolled instrument for that payment method
+ // that is ready to pay.
+ HasEnrolledInstrument();
};
diff --git a/chromium/third_party/blink/public/mojom/portal/portal.mojom b/chromium/third_party/blink/public/mojom/portal/portal.mojom
index 2dff504a80d..d30fb8375ba 100644
--- a/chromium/third_party/blink/public/mojom/portal/portal.mojom
+++ b/chromium/third_party/blink/public/mojom/portal/portal.mojom
@@ -16,11 +16,6 @@ enum PortalActivationStatus {
// The Portal interface is used by the renderer to interact with the Portal.
interface Portal {
- // Initializes a portal. Must be called immediately after creating the
- // interface. |token| is the unique token representing the portal. This token
- // will be used by the content layer when referencing the portal.
- Init() => (mojo_base.mojom.UnguessableToken token);
-
// Navigates the portal to |url|.
Navigate(url.mojom.Url url);
diff --git a/chromium/third_party/blink/public/mojom/serial/OWNERS b/chromium/third_party/blink/public/mojom/serial/OWNERS
new file mode 100644
index 00000000000..c0b9eb36add
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/serial/OWNERS
@@ -0,0 +1,6 @@
+file://content/browser/serial/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: Blink>Serial
diff --git a/chromium/third_party/blink/public/mojom/serial/serial.mojom b/chromium/third_party/blink/public/mojom/serial/serial.mojom
new file mode 100644
index 00000000000..ee8d9ceade8
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/serial/serial.mojom
@@ -0,0 +1,34 @@
+// 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.
+
+module blink.mojom;
+
+import "mojo/public/mojom/base/unguessable_token.mojom";
+
+struct SerialPortInfo {
+ // Opaque identifier for this port.
+ mojo_base.mojom.UnguessableToken token;
+
+ // USB or Bluetooth device vendor and product IDs.
+ uint32 vendor_id;
+ bool has_vendor_id;
+ uint16 product_id;
+ bool has_product_id;
+};
+
+struct SerialPortFilter {
+ // USB or Bluetooth device vendor and product IDs.
+ uint32 vendor_id;
+ bool has_vendor_id;
+ uint16 product_id;
+ bool has_product_id;
+};
+
+interface SerialService {
+ // Retrieves information about all ports available to this client.
+ GetPorts() => (array<SerialPortInfo> ports);
+
+ // Requests permission to access a port.
+ RequestPort(array<SerialPortFilter> filters) => (SerialPortInfo? port);
+};
diff --git a/chromium/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom b/chromium/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom
new file mode 100644
index 00000000000..97f7d703ef7
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom
@@ -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.
+
+module blink.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+import "mojo/public/mojom/base/unguessable_token.mojom";
+import "services/network/public/mojom/url_loader.mojom";
+import "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_fetch_response_callback.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
+
+// S13nServiceWorker:
+// Represents a service worker that is a 'controller'.
+// (https://w3c.github.io/ServiceWorker/#navigator-service-worker-controller)
+// One of its Mojo end points (i.e. the caller end) is passed to the
+// controllee in the renderer process, and used from there. Its other Mojo
+// end point (i.e. the destination of the events) is implemented by
+// ControllerServiceWorkerImpl in the renderer process where the controller
+// service worker runs.
+//
+// The controllees use this interface to directly talk to the controller. This
+// implements a small subset of the ServiceWorker interface, namely dispatch
+// methods for Fetch and PostMessage, because ordering must be preserved
+// between them: controller.postMessage(...), controller.fetch(‘...’); from
+// the page must result in a message event then fetch event dispatched to the
+// service worker. They are believed to be the only events whose ordering
+// guarantee is observable from the page context.
+interface ControllerServiceWorker {
+ // Dispatches Fetch event for sub-resources. (Fetch for main resource is
+ // handled by the ServiceWorker interface, as the fetch is initiated
+ // in the browser-process during the navigation)
+ // The callback is called once the event finishes, which means the event
+ // handler ran and all outstanding respondWith() and waitUntil() promises have
+ // settled. |response_callback| is called once the promise to respondWith()
+ // settles, or when the event handler ran without calling respondWith().
+ DispatchFetchEvent(
+ blink.mojom.DispatchFetchEventParams params,
+ blink.mojom.ServiceWorkerFetchResponseCallback response_callback)
+ => (blink.mojom.ServiceWorkerEventStatus status);
+
+ // TODO(kinuko): Add DispatchExtendableMessageEvent() as well.
+
+ // Connects a new pipe to this controller instance.
+ Clone(ControllerServiceWorker& controller);
+};
+
+// A convenient struct that packs necessary information for a service worker
+// client to talk to and set up its controller. Used to propagate controller
+// information from the browser process to the renderer process on navigation
+// commit, and also as a parameter of ServiceWorkerContainer.SetController().
+struct ControllerServiceWorkerInfo {
+ // Describes whether there is a controller and it has a fetch event handler.
+ blink.mojom.ControllerServiceWorkerMode mode =
+ blink.mojom.ControllerServiceWorkerMode.kNoController;
+
+ // S13nServiceWorker only:
+ // Non-null iff there is a controller and it has a fetch event handler.
+ ControllerServiceWorker? endpoint;
+
+ // S13nServiceWorker:
+ // The client being controlled, used for FetchEvent#clientId. The ID is
+ // issued by the browser process for this receiving client, and would
+ // never change thoughout the lifetime of the client.
+ // TODO(bashi): Consider having a separate struct for passing this kind of
+ // information, as this isn't really a part of controller info.
+ string client_id;
+
+ // This also identifies the client. Used to set |fetch_window_id| on
+ // network::ResourceRequests originating from the client's context. Null if
+ // this client is not a window.
+ mojo_base.mojom.UnguessableToken? fetch_request_window_id;
+
+ // Represents ServiceWorkerContainer#controller.
+ // Null if there is no controller.
+ blink.mojom.ServiceWorkerObjectInfo? object_info;
+};
+
+// A renderer-side interface for talking across threads. The main thread
+// uses this interface to update a ControllerServiceWorkerConnector on a
+// different thread with a new controller service worker.
+// TODO(kinuko): Stop using mojo interface for this, we can just make
+// it work via posting tasks.
+interface ControllerServiceWorkerConnector {
+ // Resets the controller connection with the given |controller|, this
+ // can be called when a new controller is given, e.g. due to claim().
+ // |controller| can be null if it gets no controller.
+ UpdateController(ControllerServiceWorker? controller);
+};
diff --git a/chromium/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom b/chromium/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
index 21cc71518e3..a251d2bdc69 100644
--- a/chromium/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
+++ b/chromium/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
@@ -6,6 +6,7 @@ module blink.mojom;
import "services/network/public/mojom/url_loader.mojom";
import "third_party/blink/public/mojom/blob/blob.mojom";
+import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
// Used for service worker navigation preload, to create
// FetchEvent#preloadResponse.
@@ -17,28 +18,7 @@ struct FetchEventPreloadHandle {
// Parameters used for dispatching a FetchEvent.
struct DispatchFetchEventParams {
// FetchEvent#request.
- network.mojom.URLRequest request;
-
- // The following fields are used to create FetchEvent#request#body, depending
- // on whether S13nServiceWorker/NetworkService are enabled.
-
- // (A) S13nServiceWorker with NetworkService on:
- // All information about the request body is provided in
- // |request.request_body|.
-
- // (B) S13nServiceWorker with NetworkService off:
- // All information about the request body except for BlobPtrs is provided in
- // |request.request_body|. These BlobPtrs need to be passed separately.
- // Once the NetworkService is enabled, this will be no longer used since all
- // Blobs are passed as data pipes which can live in |request.request_body|.
- array<Blob> request_body_blob_ptrs;
-
- // (C) non-S13nServiceWorker:
- // All information to create the request body are packed into a blob. These
- // params are for passing the blob.
- string request_body_blob_uuid;
- uint64 request_body_blob_size;
- Blob? request_body_blob;
+ FetchAPIRequest request;
// FetchEvent#clientId.
string client_id;
diff --git a/chromium/third_party/blink/public/mojom/service_worker/service_worker.mojom b/chromium/third_party/blink/public/mojom/service_worker/service_worker.mojom
index 31951624114..ea0fa99f70f 100644
--- a/chromium/third_party/blink/public/mojom/service_worker/service_worker.mojom
+++ b/chromium/third_party/blink/public/mojom/service_worker/service_worker.mojom
@@ -4,9 +4,22 @@
module blink.mojom;
+import "mojo/public/mojom/base/string16.mojom";
+import "mojo/public/mojom/base/time.mojom";
+import "services/network/public/mojom/cookie_manager.mojom";
+import "third_party/blink/public/mojom/background_fetch/background_fetch.mojom";
+import "third_party/blink/public/mojom/fetch/fetch_api_response.mojom";
import "third_party/blink/public/mojom/messaging/transferable_message.mojom";
-import "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom";
+import "third_party/blink/public/mojom/notifications/notification.mojom";
+import "third_party/blink/public/mojom/payments/payment_app.mojom";
+import "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom";
import "third_party/blink/public/mojom/service_worker/service_worker_client.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_fetch_response_callback.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
+import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
// Host for a running service worker execution context. Implemented in the
@@ -91,3 +104,150 @@ interface ServiceWorkerHost {
// Otherwise, |error| and |error_msg| describe the failure.
ClaimClients() => (ServiceWorkerErrorType error, string? error_msg);
};
+
+struct ExtendableMessageEvent {
+ TransferableMessage message;
+ url.mojom.Origin source_origin;
+ // Exactly one of |source_info_for_client| and
+ // |source_info_for_service_worker| should be non-null.
+ ServiceWorkerClientInfo? source_info_for_client;
+ ServiceWorkerObjectInfo? source_info_for_service_worker;
+};
+
+// The number of seconds for which a 'push' event should be allowed to run.
+// This is not in the spec but for a Chrome-specific timeout. Each
+// event dispatched to service workers has a 5 minute timeout in the Chrome
+// implementation, but this makes the timeout for push events shorter.
+const int32 kPushEventTimeoutSeconds = 90;
+
+// An interface for talking to a running service worker thread. The browser
+// process uses this interface to request the renderer to do things like
+// dispatch events to the service worker. This interface is bound on the
+// service worker thread and is implemented by ServiceWorkerContextClient.
+//
+// This is the master interface for the Mojo message pipe between the browser
+// process and the service worker thread in the renderer process. Other service
+// worker-related interfaces bound on the service worker thread are associated
+// with this interface. These include:
+// - ServiceWorkerHost for this service worker.
+// - ServiceWorkerRegistrationObject(Host) for this service worker's
+// self.registration property.
+// - ServiceWorkerObjects(Host) for that registration's properties.
+//
+// A similar (but non-associated) interface is ControllerServiceWorker. That
+// interface is used by service worker clients (inside renderer processes) to
+// talk directly to their controller service worker, without going through the
+// browser.
+//
+// USAGE TIP: Those DispatchEvent* messages expecting a
+// (ServiceWorkerEventStatus, mojo_base.mojom.TimeTicks) callback
+// are considered 'simple events'.
+// ServiceWorkerVersion::CreateSimpleEventCallback can be used to create the
+// callback for these.
+interface ServiceWorker {
+ // The first message sent on this interface. It is used to associate service
+ // worker-related interfaces together on the service worker thread, as
+ // ServiceWorker is the first interface available on the
+ // service worker thread. It establishes the |service_worker_host| connection
+ // and passes information used to populate
+ // ServiceWorkerGlobalScope#registration object. JavaScript execution of the
+ // service worker does not start until this message is received.
+ InitializeGlobalScope(
+ associated ServiceWorkerHost service_worker_host,
+ ServiceWorkerRegistrationObjectInfo registration_info);
+
+ DispatchInstallEvent()
+ => (ServiceWorkerEventStatus status, bool has_fetch_handler);
+ DispatchActivateEvent()
+ => (ServiceWorkerEventStatus status);
+
+ // These methods dispatch to the ServiceWorkerGlobalScope the events listed on
+ // https://wicg.github.io/background-fetch/#service-worker-global-events.
+ // The callbacks are called once the event handler has run and waitUntil()
+ // promise has settled. |developer_id| and |unique_id| are documented in
+ // content::BackgroundFetchRegistrationId.
+ DispatchBackgroundFetchAbortEvent(
+ BackgroundFetchRegistration registration)
+ => (ServiceWorkerEventStatus status);
+ DispatchBackgroundFetchClickEvent(
+ BackgroundFetchRegistration registration)
+ => (ServiceWorkerEventStatus status);
+ DispatchBackgroundFetchFailEvent(
+ BackgroundFetchRegistration registration)
+ => (ServiceWorkerEventStatus status);
+ DispatchBackgroundFetchSuccessEvent(
+ BackgroundFetchRegistration registration)
+ => (ServiceWorkerEventStatus status);
+
+ // Dispatches the cookie change events in the Async Cookie API specification.
+ // https://github.com/WICG/cookie-store/
+ // The callback is called once the event handler has run and the waitUntil()
+ // promise has settled.
+ DispatchCookieChangeEvent(
+ network.mojom.CanonicalCookie cookie,
+ network.mojom.CookieChangeCause cause)
+ => (ServiceWorkerEventStatus status);
+
+ // The Dispatch*FetchEvent() callback is called once the event finishes,
+ // which means the event handler ran and all outstanding respondWith() and
+ // waitUntil() promises have settled. |response_callback| is called once the
+ // promise to respondWith() settles, or when the event handler ran without
+ // calling respondWith().
+ DispatchFetchEvent(
+ DispatchFetchEventParams params,
+ ServiceWorkerFetchResponseCallback response_callback)
+ => (ServiceWorkerEventStatus status);
+
+ DispatchNotificationClickEvent(
+ string notification_id,
+ NotificationData notification_data,
+ int32 action_index,
+ mojo_base.mojom.String16? reply)
+ => (ServiceWorkerEventStatus status);
+ DispatchNotificationCloseEvent(
+ string notification_id,
+ NotificationData notification_data)
+ => (ServiceWorkerEventStatus status);
+ // The payload of a push message can be valid with content, valid with empty
+ // content, or null.
+ DispatchPushEvent(string? payload)
+ => (ServiceWorkerEventStatus status);
+ // Arguments are passed to the event handler as parameters of SyncEvent.
+ // Ref: https://wicg.github.io/BackgroundSync/spec/#sync-event
+ // S13nServiceWorker: |timeout| is the amount of time to allow this event to
+ // finish.
+ // Non-S13nServiceWorker: |timeout| is just ignored.
+ DispatchSyncEvent(string id,
+ bool last_chance,
+ mojo_base.mojom.TimeDelta timeout)
+ => (ServiceWorkerEventStatus status);
+ DispatchAbortPaymentEvent(
+ payments.mojom.PaymentHandlerResponseCallback result_of_abort_payment)
+ => (ServiceWorkerEventStatus status);
+ DispatchCanMakePaymentEvent(
+ payments.mojom.CanMakePaymentEventData event_data,
+ payments.mojom.PaymentHandlerResponseCallback result_of_can_make_payment)
+ => (ServiceWorkerEventStatus status);
+ DispatchPaymentRequestEvent(
+ payments.mojom.PaymentRequestEventData request_data,
+ payments.mojom.PaymentHandlerResponseCallback response_callback)
+ => (ServiceWorkerEventStatus status);
+ DispatchExtendableMessageEvent(ExtendableMessageEvent event)
+ => (ServiceWorkerEventStatus status);
+
+ // TODO(crbug.com/869714): Remove this code for long living service workers
+ // when Android Messages no longer requires it.
+ DispatchExtendableMessageEventWithCustomTimeout(ExtendableMessageEvent event,
+ mojo_base.mojom.TimeDelta timeout)
+ => (ServiceWorkerEventStatus status);
+
+ // Pings the service worker to check if it is responsive. If the callback is
+ // not called within a certain period of time, the browser will terminate the
+ // worker.
+ Ping() => ();
+
+ // S13nServiceWorker:
+ // Lets the idle timer request termination immediately after all inflight
+ // events are handled without delay.
+ SetIdleTimerDelayToZero();
+};
diff --git a/chromium/third_party/blink/public/mojom/service_worker/service_worker_client.mojom b/chromium/third_party/blink/public/mojom/service_worker/service_worker_client.mojom
index f43f0610b56..355ebe0f97f 100644
--- a/chromium/third_party/blink/public/mojom/service_worker/service_worker_client.mojom
+++ b/chromium/third_party/blink/public/mojom/service_worker/service_worker_client.mojom
@@ -6,7 +6,6 @@ module blink.mojom;
import "mojo/public/mojom/base/time.mojom";
import "services/network/public/mojom/request_context_frame_type.mojom";
-import "third_party/blink/public/mojom/page/page_visibility_state.mojom";
import "url/mojom/url.mojom";
// Indicates the service worker client type.
@@ -31,13 +30,16 @@ struct ServiceWorkerClientQueryOptions {
// Holds the information related to a service worker client.
// https://w3c.github.io/ServiceWorker/#client
//
-// An invalid client info can be indicated by setting the client_uuid to the
+// An invalid client info can be indicated by setting the |client_uuid| to the
// empty string. Sometimes this is needed when the browser process couldn't
// find a client.
struct ServiceWorkerClientInfo {
// Client#url
url.mojom.Url url;
+ // Client#frameType.
+ network.mojom.RequestContextFrameType frame_type = network.mojom.RequestContextFrameType.kNone;
+
// Client#id
string client_uuid;
@@ -45,16 +47,13 @@ struct ServiceWorkerClientInfo {
ServiceWorkerClientType client_type;
// WindowClient#visibilityState
- // Set to |kHidden| if it's a non-window client.
- PageVisibilityState page_visibility_state = PageVisibilityState.kHidden;
+ // Set to |true| if it's a non-window client.
+ bool page_hidden = true;
// WindowClient#focused
- // Set to false if it's a non-window client.
+ // Set to |false| if it's a non-window client.
bool is_focused = false;
- // Set to |kNone| if it's a non-window client.
- network.mojom.RequestContextFrameType frame_type = network.mojom.RequestContextFrameType.kNone;
-
// The time this window was last focused. Set to base::TimeTicks() if it's
// a non-window client.
mojo_base.mojom.TimeTicks last_focus_time;
diff --git a/chromium/third_party/blink/public/mojom/service_worker/service_worker_container.mojom b/chromium/third_party/blink/public/mojom/service_worker/service_worker_container.mojom
new file mode 100644
index 00000000000..e625c65fdbe
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/service_worker/service_worker_container.mojom
@@ -0,0 +1,148 @@
+// Copyright 2017 The Chromium 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 blink.mojom;
+
+import "mojo/public/mojom/base/string16.mojom";
+import "third_party/blink/public/mojom/messaging/transferable_message.mojom";
+import "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
+import "third_party/blink/public/platform/web_feature.mojom";
+import "url/mojom/url.mojom";
+
+// Used for EnsureControllerServiceWorker() to indicate why a controllee needs
+// a controller ServiceWorker.
+enum ControllerServiceWorkerPurpose {
+ FETCH_SUB_RESOURCE
+};
+
+// ServiceWorkerContainerHost is an interface implemented by the browser
+// process. The renderer process uses this interface to request the browser
+// process to do operations involving service worker registrations.
+//
+// This interface is associated with its counterpart ServiceWorkerContainer.
+// The message pipe it's used on depends on the container type.
+// - For service workers:
+// Associated with EmbeddedWorkerInstanceClient, which is on a dedicated
+// message pipe.
+// - For shared workers (S13nSW):
+// Associated with SharedWorkerFactory, which is on a dedicated message
+// pipe.
+// - For shared workers (non-S13nSW):
+// Associated with ServiceWorkerDispatcherHost, which is on the
+// channel-associated interface to the renderer process.
+// - For documents:
+// Associated with ServiceWorkerDispatcherHost, which is on the
+// channel-associated interface to the renderer process.
+interface ServiceWorkerContainerHost {
+ // Corresponds to navigator.serviceWorker.register().
+ // Registers a service worker from |script_url| with |options|.
+ // On success, |error| is kNone with |registration| set.
+ // Otherwise, |error| and |error_msg| describe the failure.
+ Register(url.mojom.Url script_url,
+ ServiceWorkerRegistrationOptions options)
+ => (ServiceWorkerErrorType error,
+ string? error_msg,
+ ServiceWorkerRegistrationObjectInfo? registration);
+
+ // Corresponds to navigator.serviceWorker.getRegistration().
+ // Gets the service worker registration for the |client_url|.
+ // On success, |error| is kNone with |registration| set.
+ // In case there is no registration at |client_url|, or the registration is
+ // uninstalling, |error| is still kNone but with null |registration|.
+ // Otherwise, |error| and |error_msg| describe the failure.
+ GetRegistration(url.mojom.Url client_url)
+ => (ServiceWorkerErrorType error,
+ string? error_msg,
+ ServiceWorkerRegistrationObjectInfo? registration);
+
+ // Corresponds to navigator.serviceWorker.getRegistrations().
+ // Gets all service worker registrations which have the same origin with
+ // the ServiceWorkerContainer that this interface hosts.
+ // On success, |error| is kNone with |infos| set. Otherwise, |error| and
+ // |error_msg| describe the failure.
+ GetRegistrations()
+ => (ServiceWorkerErrorType error,
+ string? error_msg,
+ array<ServiceWorkerRegistrationObjectInfo>? infos);
+
+ // Corresponds to navigator.serviceWorker.ready.
+ // Returns the service worker registration for the ServiceWorkerContainer that
+ // this interface hosts, once such a registration exists and has an active
+ // service worker.
+ GetRegistrationForReady()
+ => (ServiceWorkerRegistrationObjectInfo? registration);
+
+ // S13nServiceWorker:
+ // Returns a Mojo end point to the controller ServiceWorker. This may start a
+ // service worker instance in a renderer process if the corresponding
+ // instance is not alive.
+ // This method must be called only by the controllees.
+ // If the browser fails to start the service worker it is propagated as a
+ // connection error of the returned pipe. The detailed error reasons are not
+ // reported to the controllees, but the browser process is responsible for
+ // properly handling the failure and recording the reasons.
+ // |purpose| is used for UMA.
+ EnsureControllerServiceWorker(ControllerServiceWorker& controller,
+ ControllerServiceWorkerPurpose purpose);
+
+ // S13nServiceWorker:
+ // Makes a new endpoint to this ServiceWorkerContainerHost.
+ CloneContainerHost(ServiceWorkerContainerHost& container_host);
+
+ // Does nothing but calls the callback. Useful for pumping the message pipe
+ // for this interface and associated interfaces: when the callback is called,
+ // you know all incoming messages up to the Ping() call have been received.
+ Ping() => ();
+
+ // S13nServiceWorker:
+ // Gives a hint to the browser process to update the service worker after a
+ // controlled page load. This message is meant to be sent at a time when page
+ // load is no longer busy, so update doesn't adversely affect performance.
+ // The browser process can possibly coalesce hints for the same service
+ // worker into a single update.
+ HintToUpdateServiceWorker();
+};
+
+// ServiceWorkerContainer is an interface implemented by the renderer process.
+// The browser process uses this interface to send messages to documents or the
+// service worker.
+//
+// Roughly corresponds to the web-exposed ServiceWorkerContainer interface,
+// i.e., navigator.serviceWorker. Actually, the plan is for this interface to be
+// used for anything that could access a ServiceWorkerRegistration or
+// ServiceWorker object. For example, ServiceWorkerGlobalScope needs to be
+// connected to this, since it has self.registration, even though we don’t
+// implement navigator.serviceWorker for Worker yet. But eventually anything
+// that can touch these objects should be a ServiceWorkerContainer, so it’s OK
+// to use this name.
+//
+// This interface is associated with its counterpart,
+// ServiceWorkerContainerHost, as they are sent on the same master interface
+// together. See ServiceWorkerContainerHost for documentation about the message
+// pipe they live on.
+interface ServiceWorkerContainer {
+ // Corresponds to setting ServiceWorkerContainer#controller.
+ // If |controller_info| is invalid (its |object_info| is null), then
+ // ServiceWorkerContainer#controller is cleared.
+ // If |controller_info| is valid, |used_features| is the set of
+ // features the controller has used, for UseCounter purposes.
+ // If |should_notify_controllerchange| is true, dispatch a 'controllerchange'
+ // event.
+ SetController(ControllerServiceWorkerInfo controller_info,
+ array<WebFeature> used_features,
+ bool should_notify_controllerchange);
+
+ // Corresponds to Client#postMessage().
+ // Sends |message| from the service worker |source| to this service worker
+ // client.
+ PostMessageToClient(ServiceWorkerObjectInfo source,
+ TransferableMessage message);
+
+ // Notifies this service worker client that its controller used a |feature|,
+ // for UseCounter purposes.
+ CountFeature(WebFeature feature);
+};
diff --git a/chromium/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom b/chromium/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
new file mode 100644
index 00000000000..3dd466586d3
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
@@ -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.
+
+module blink.mojom;
+
+import "services/network/public/mojom/url_loader_factory.mojom";
+import "services/service_manager/public/mojom/interface_provider.mojom";
+import "third_party/blink/public/mojom/cache_storage/cache_storage.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_container.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom";
+import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
+
+// The name of the InterfaceProviderSpec in service manifests used by the
+// frame tree to expose service-worker-specific interfaces between renderer
+// and browser.
+const string kNavigation_ServiceWorkerSpec = "navigation:service_worker";
+
+// S13nServiceWorker:
+// Sent from the browser process to the renderer. Contains parameteres for the
+// constructor of ServiceWorkerNetworkProvider used for starting a shared
+// worker.
+struct ServiceWorkerProviderInfoForSharedWorker {
+ int32 provider_id;
+ associated ServiceWorkerContainerHost host_ptr_info;
+ associated ServiceWorkerContainer& client_request;
+};
+
+// Sent from the browser process to the renderer. Contains parameters for the
+// constructor of ServiceWorkerNetworkProvider used for starting a service
+// worker.
+struct ServiceWorkerProviderInfoForStartWorker {
+ int32 provider_id;
+
+ associated ServiceWorkerContainerHost host_ptr_info;
+ associated ServiceWorkerContainer& client_request;
+
+ // S13nServiceWorker:
+ // The loader to use for loading the worker's main script and
+ // importScripts().
+ associated network.mojom.URLLoaderFactory? script_loader_factory_ptr_info;
+
+ // |cache_storage| is an optional optimization so the service worker can use
+ // the Cache Storage API immediately without using InterfaceProvider. May be
+ // null for service workers created for update checks, as the optimization
+ // would be wasteful because these workers usually are aborted after the
+ // byte-to-byte update check before running.
+ CacheStorage? cache_storage;
+
+ service_manager.mojom.InterfaceProvider interface_provider;
+};
+
+// Describes a browser-side provider host. See
+// content::ServiceWorkerProviderHost.
+struct ServiceWorkerProviderHostInfo {
+ // |provider_id| may be browser-assigned or renderer-assigned.
+ // Browser-assigned ids are unique among all providers. Renderer-assigned ids
+ // are unique among providers in a given renderer process. Most providers have
+ // browser-assigned ids. The exceptions are about:blank iframes, and shared
+ // workers (in the non-S13nServiceWorker case).
+ int32 provider_id;
+
+ // When this provider is created for a document, |route_id| is the frame ID of
+ // it. Otherwise |route_id| is MSG_ROUTING_NONE.
+ int32 route_id;
+
+ // This identifies whether this provider is for a service worker or for a
+ // service worker client (Documents and Shared Workers).
+ ServiceWorkerProviderType type;
+
+ // |is_parent_frame_secure| is false if the provider is created for a document
+ // whose parent frame is not secure from the point of view of the document;
+ // that is, blink::WebFrame::canHaveSecureChild() returns false. This doesn't
+ // mean the document is necessarily an insecure context, because the document
+ // may have a URL whose scheme is granted an exception that allows bypassing
+ // the ancestor secure context check. See the comment in
+ // blink::Document::isSecureContextImpl for more details. If the provider is
+ // not created for a document, or the document does not have a parent frame,
+ // is_parent_frame_secure| is true.
+ bool is_parent_frame_secure;
+
+ // Mojo endpoint to send a message from the renderer to the browser. This
+ // will be associated with ServiceWorkerDisptacherHost. |host_request| should
+ // be valid when ServiceWorkerProviderHostInfo is passed to any Mojo method.
+ // After used to create the ServiceWorkerProviderHost, this will be invalid.
+ associated ServiceWorkerContainerHost& host_request;
+
+ // Mojo endpoint to send a message from the browser to the renderer. This
+ // will be associated with ServiceWorkerDispatcherHost. |client_ptr_info|
+ // should be valid when ServiceWorkerProviderHostInfo is passed to any Mojo
+ // method.
+ // After used to create the ServiceWorkerProviderHost, this will be invalid.
+ associated ServiceWorkerContainer client_ptr_info;
+};
+
+// ServiceWorkerWorkerClient represents a service worker client that is a worker
+// (i.e., a shared worker or dedicated worker). The main thread of
+// the renderer process uses this interface to tell the worker thread
+// when the controller service worker changes.
+interface ServiceWorkerWorkerClient {
+ // Called when the worker is controlled by a new service worker. This is only
+ // used to let the worker know that we now have a service worker (while there
+ // may or may not have been one previously), but not the other way around.
+ OnControllerChanged(ControllerServiceWorkerMode mode);
+};
+
+// ServiceWorkerWorkerClientRegistry is a mojo interface for hosting and
+// registering ServiceWorkerWorkerClients. An instance of this interface is
+// implemented by ServiceWorkerProviderContext and lives in the same renderer
+// process as the worker clients.
+// This interface is useful when one needs to register a new worker client
+// for an existing ServiceWorkerProviderContext on non-main thread, i.e. for
+// nested workers.
+interface ServiceWorkerWorkerClientRegistry {
+ // Adds a new ServiceWorkerWorkerClient.
+ RegisterWorkerClient(ServiceWorkerWorkerClient client);
+
+ // Clones this host.
+ CloneWorkerClientRegistry(ServiceWorkerWorkerClientRegistry& host);
+};
+
+// An interface implemented by the browser process, with one implementation per
+// renderer process. The renderer uses this interface to tell the browser when
+// potential service worker clients are created.
+//
+// This interface is on the channel-associated interface to the renderer
+// process.
+interface ServiceWorkerDispatcherHost {
+ // Creates a content::ServiceWorkerProviderHost on the browser
+ // process. |provider_info| has Mojo endpoints to connect the container host
+ // and the container on the renderer together. The lifetime of
+ // ServiceWorkerProviderHost will be tied to the
+ // blink::mojom::ServiceWorkerContainerHost interface.
+ OnProviderCreated(ServiceWorkerProviderHostInfo provider_info);
+};
diff --git a/chromium/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom b/chromium/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom
index ec05b660f29..42ef27f7f73 100644
--- a/chromium/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom
+++ b/chromium/third_party/blink/public/mojom/service_worker/service_worker_registration.mojom
@@ -40,9 +40,10 @@ struct ServiceWorkerRegistrationObjectInfo {
// The globally unique identifier of a service worker registration entity.
int64 registration_id = kInvalidServiceWorkerRegistrationId;
- // The registration options attached with this registration object, including
- // some information such as scope of this registration.
- ServiceWorkerRegistrationOptions options;
+ // Corresponds to ServiceWorkerRegistration#scope.
+ url.mojom.Url scope;
+ // Corresponds to ServiceWorkerRegistration#updateViaCache.
+ ServiceWorkerUpdateViaCache update_via_cache;
// Holds one mojo connection to browser process, acts as a reference count to
// control lifetime of ServiceWorkerRegistration in the browser process.
diff --git a/chromium/third_party/blink/public/mojom/usb/BUILD.gn b/chromium/third_party/blink/public/mojom/usb/BUILD.gn
index cfa109c1f96..9629b38c513 100644
--- a/chromium/third_party/blink/public/mojom/usb/BUILD.gn
+++ b/chromium/third_party/blink/public/mojom/usb/BUILD.gn
@@ -7,7 +7,7 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("usb") {
# Ideally, this mojom file should be compiled directly in "mojom_platform"
# target in the parent directory. But as we need |scramble_message_ids| to
- # be "false" for its mojom JS file will be used in external WPT layout tests.
+ # be "false" for its mojom JS file will be used in external WPT tests.
# To limit this option's influence scope, we make it a separate target.
sources = [
"web_usb_service.mojom",
@@ -21,7 +21,7 @@ mojom("usb") {
"//device/usb/public/mojom",
]
- # USB Mojom interfaces are exposed publicly to layout tests which use
+ # USB Mojom interfaces are exposed publicly to web tests which use
# prepackaged redistributable JS bindings. It is therefore not desirable to
# scramble these messages.
scramble_message_ids = false
diff --git a/chromium/third_party/blink/public/mojom/usb/web_usb_service.mojom b/chromium/third_party/blink/public/mojom/usb/web_usb_service.mojom
index b92b48a6929..05c8e68954d 100644
--- a/chromium/third_party/blink/public/mojom/usb/web_usb_service.mojom
+++ b/chromium/third_party/blink/public/mojom/usb/web_usb_service.mojom
@@ -5,7 +5,8 @@
module blink.mojom;
import "device/usb/public/mojom/device.mojom";
-import "device/usb/public/mojom/device_manager.mojom";
+import "device/usb/public/mojom/device_enumeration_options.mojom";
+import "device/usb/public/mojom/device_manager_client.mojom";
// This is a parallel interface with UsbDeviceManager aimed to handle extra work
// such as permission checking, chooser showing, etc. in browser.
diff --git a/chromium/third_party/blink/public/platform/modules/wake_lock/OWNERS b/chromium/third_party/blink/public/mojom/wake_lock/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/third_party/blink/public/platform/modules/wake_lock/OWNERS
+++ b/chromium/third_party/blink/public/mojom/wake_lock/OWNERS
diff --git a/chromium/third_party/blink/public/mojom/wake_lock/wake_lock.mojom b/chromium/third_party/blink/public/mojom/wake_lock/wake_lock.mojom
new file mode 100644
index 00000000000..f12ad674bd5
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/wake_lock/wake_lock.mojom
@@ -0,0 +1,18 @@
+// 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.
+
+module blink.mojom;
+
+import "services/device/public/mojom/wake_lock.mojom";
+
+// The Blink WakeLock service allows the creation of WakeLocks without using a
+// WakeLockContext or a WakeLockProvider, instead using the associated frame's
+// context. This allows Blink to create WakeLocks using the context id
+// associated with the window the frame is running in.
+interface WakeLockService {
+ GetWakeLock(device.mojom.WakeLockType type,
+ device.mojom.WakeLockReason reason,
+ string description,
+ device.mojom.WakeLock& wake_lock);
+};
diff --git a/chromium/third_party/blink/public/mojom/shared_worker/OWNERS b/chromium/third_party/blink/public/mojom/worker/OWNERS
index e1abbf3d0d8..e1abbf3d0d8 100644
--- a/chromium/third_party/blink/public/mojom/shared_worker/OWNERS
+++ b/chromium/third_party/blink/public/mojom/worker/OWNERS
diff --git a/chromium/third_party/blink/public/mojom/worker/README.md b/chromium/third_party/blink/public/mojom/worker/README.md
new file mode 100644
index 00000000000..3a2db4726a2
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/worker/README.md
@@ -0,0 +1 @@
+Public mojom files that are referenced both from browser-side and renderer-side for [Web Workers](https://html.spec.whatwg.org/multipage/workers.html#workers).
diff --git a/chromium/third_party/blink/public/platform/dedicated_worker_factory.mojom b/chromium/third_party/blink/public/mojom/worker/dedicated_worker_factory.mojom
index 75288af1c1b..75288af1c1b 100644
--- a/chromium/third_party/blink/public/platform/dedicated_worker_factory.mojom
+++ b/chromium/third_party/blink/public/mojom/worker/dedicated_worker_factory.mojom
diff --git a/chromium/third_party/blink/public/mojom/worker/shared_worker.mojom b/chromium/third_party/blink/public/mojom/worker/shared_worker.mojom
new file mode 100644
index 00000000000..8a2a20c4f66
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/worker/shared_worker.mojom
@@ -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.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/devtools/devtools_agent.mojom";
+
+// Interface used by the host to control the shared worker.
+interface SharedWorker {
+ // Called to establish a new client connection to the shared worker. The
+ // |connection_id| parameter will be echoed back to the host via the
+ // OnConnected method.
+ Connect(int32 connection_id, handle<message_pipe> message_port);
+
+ // Called to terminate the shared worker. This results in the shared worker
+ // closing its end of the mojo connection.
+ Terminate();
+
+ // Binds a DevToolsAgent interface for this shared worker, used for
+ // remote debugging. See DevToolsAgent for details.
+ BindDevToolsAgent(associated DevToolsAgentHost agent_host,
+ associated DevToolsAgent& agent);
+};
diff --git a/chromium/third_party/blink/public/mojom/worker/shared_worker_client.mojom b/chromium/third_party/blink/public/mojom/worker/shared_worker_client.mojom
new file mode 100644
index 00000000000..709ddebc14f
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/worker/shared_worker_client.mojom
@@ -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.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/worker/shared_worker_creation_context_type.mojom";
+import "third_party/blink/public/platform/web_feature.mojom";
+
+// An interface used by clients (e.g., the renderer where "new SharedWorker()"
+// was invoked) to observe events from a shared worker.
+interface SharedWorkerClient {
+ // Indicates that the shared worker process has started (or may have already
+ // been started). The shared worker script is not necessarily loaded yet.
+ // This event will be followed by either OnConnected or OnScriptLoadFailed.
+ OnCreated(SharedWorkerCreationContextType creation_context_type);
+
+ // Indicates that the shared worker process is up and running, script loaded.
+ OnConnected(array<WebFeature> features_used);
+
+ // Indicates that the shared worker script failed to load.
+ OnScriptLoadFailed();
+
+ // Indicates that the shared worker used a feature. This is intended to be
+ // logged by the client-side feature logging infrastructure.
+ OnFeatureUsed(WebFeature feature);
+};
diff --git a/chromium/third_party/blink/public/mojom/worker/shared_worker_connector.mojom b/chromium/third_party/blink/public/mojom/worker/shared_worker_connector.mojom
new file mode 100644
index 00000000000..8feca4f959e
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/worker/shared_worker_connector.mojom
@@ -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.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/blob/blob_url_store.mojom";
+import "third_party/blink/public/mojom/worker/shared_worker_client.mojom";
+import "third_party/blink/public/mojom/worker/shared_worker_creation_context_type.mojom";
+import "third_party/blink/public/mojom/worker/shared_worker_info.mojom";
+
+// This interface is exposed to enable a client to create and connect to a
+// shared worker.
+interface SharedWorkerConnector {
+ // Connect to (and create if necessary) a SharedWorker specified by |info|.
+ // The SharedWorker will be terminated if all clients go away.
+ // |blob_url_token| should be non-null when the worker is loaded from a blob:
+ // URL. The token will then be used to look up the blob associated with the
+ // blob URL. Without this by the time the worker code starts fetching
+ // the URL the blob URL might no longer be valid.
+ Connect(SharedWorkerInfo info,
+ SharedWorkerClient client,
+ SharedWorkerCreationContextType creation_context_type,
+ handle<message_pipe> message_port,
+ BlobURLToken? blob_url_token);
+};
diff --git a/chromium/third_party/blink/public/mojom/shared_worker/shared_worker_creation_context_type.mojom b/chromium/third_party/blink/public/mojom/worker/shared_worker_creation_context_type.mojom
index a6650ab3ac1..a6650ab3ac1 100644
--- a/chromium/third_party/blink/public/mojom/shared_worker/shared_worker_creation_context_type.mojom
+++ b/chromium/third_party/blink/public/mojom/worker/shared_worker_creation_context_type.mojom
diff --git a/chromium/third_party/blink/public/mojom/worker/shared_worker_host.mojom b/chromium/third_party/blink/public/mojom/worker/shared_worker_host.mojom
new file mode 100644
index 00000000000..3227be020f0
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/worker/shared_worker_host.mojom
@@ -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.
+
+module blink.mojom;
+
+import "third_party/blink/public/platform/web_feature.mojom";
+
+// Each shared worker has a corresponding host. The host controls the lifetime
+// of the shared worker. This interface is used by the shared worker to talk to
+// its host.
+interface SharedWorkerHost {
+ // Called in response to SharedWorker's Connect method. The |connection_id|
+ // parameter is the same value passed to the Connect method.
+ OnConnected(int32 connection_id);
+
+ // Indicates that the shared worker self-closed. This should trigger the host
+ // to terminate the shared worker.
+ OnContextClosed();
+
+ // Indicates that the shared worker is ready for inspection.
+ OnReadyForInspection();
+
+ // Indicates that the script successfully loaded.
+ OnScriptLoaded();
+
+ // Indicates that the script failed to load.
+ OnScriptLoadFailed();
+
+ // Indicates that the shared worker used a feature. This is intended to be
+ // logged by the client-side feature logging infrastructure.
+ OnFeatureUsed(WebFeature feature);
+};
diff --git a/chromium/third_party/blink/public/mojom/worker/shared_worker_info.mojom b/chromium/third_party/blink/public/mojom/worker/shared_worker_info.mojom
new file mode 100644
index 00000000000..52c7eb7c292
--- /dev/null
+++ b/chromium/third_party/blink/public/mojom/worker/shared_worker_info.mojom
@@ -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.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/net/ip_address_space.mojom";
+import "third_party/blink/public/mojom/csp/content_security_policy.mojom";
+import "url/mojom/url.mojom";
+
+// Meta data that is necessary to create a new shared worker context. This
+// structure gets populated when a new SharedWorker object is created in the
+// parent context (e.g. Document), and passed onto the destination child
+// process where the shared worker runs.
+struct SharedWorkerInfo {
+ url.mojom.Url url;
+ string name;
+ string content_security_policy;
+ blink.mojom.ContentSecurityPolicyType content_security_policy_type;
+ blink.mojom.IPAddressSpace creation_address_space;
+};
diff --git a/chromium/third_party/blink/public/web/worker_content_settings_proxy.mojom b/chromium/third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom
index 500a16a1e6a..500a16a1e6a 100644
--- a/chromium/third_party/blink/public/web/worker_content_settings_proxy.mojom
+++ b/chromium/third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom
diff --git a/chromium/third_party/blink/public/mojom/shared_worker/worker_main_script_load_params.mojom b/chromium/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
index f88aa4563db..f88aa4563db 100644
--- a/chromium/third_party/blink/public/mojom/shared_worker/worker_main_script_load_params.mojom
+++ b/chromium/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
diff --git a/chromium/third_party/blink/public/platform/OWNERS b/chromium/third_party/blink/public/platform/OWNERS
index 65e1bbf93b9..25ffef5786e 100644
--- a/chromium/third_party/blink/public/platform/OWNERS
+++ b/chromium/third_party/blink/public/platform/OWNERS
@@ -12,5 +12,14 @@ per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
+per-file web_application_cache_*=pwnall@chromium.org
per-file web_rtc_*=hbos@chromium.org
per-file web_media_player*=mlamouri@chromium.org
+
+# Video SurfaceLayer functionality.
+per-file web_video_frame*=file://media/OWNERS
+per-file web_video_frame*=mlamouri@chromium.org
+per-file web_video_frame*=lethalantidote@chromium.org
+per-file web_surface_layer_bridge*=file://media/OWNERS
+per-file web_surface_layer_bridge*=mlamouri@chromium.org
+per-file web_surface_layer_bridge*=lethalantidote@chromium.org
diff --git a/chromium/third_party/blink/public/platform/content_security_policy.typemap b/chromium/third_party/blink/public/platform/content_security_policy.typemap
deleted file mode 100644
index 30344e969d8..00000000000
--- a/chromium/third_party/blink/public/platform/content_security_policy.typemap
+++ /dev/null
@@ -1,13 +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.
-
-mojom = "//third_party/blink/public/platform/content_security_policy.mojom"
-public_headers =
- [ "//third_party/blink/public/platform/web_content_security_policy.h" ]
-traits_headers = [
- "//third_party/blink/public/platform/content_security_policy_struct_traits.h",
-]
-type_mappings = [
- "blink.mojom.ContentSecurityPolicyType=::blink::WebContentSecurityPolicyType",
-]
diff --git a/chromium/third_party/blink/public/platform/content_security_policy_struct_traits.h b/chromium/third_party/blink/public/platform/content_security_policy_struct_traits.h
deleted file mode 100644
index 8c6f16e8aa7..00000000000
--- a/chromium/third_party/blink/public/platform/content_security_policy_struct_traits.h
+++ /dev/null
@@ -1,46 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_CONTENT_SECURITY_POLICY_STRUCT_TRAITS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_CONTENT_SECURITY_POLICY_STRUCT_TRAITS_H_
-
-#include "mojo/public/cpp/bindings/enum_traits.h"
-#include "third_party/blink/public/platform/content_security_policy.mojom-shared.h"
-#include "third_party/blink/public/platform/web_content_security_policy.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<::blink::mojom::ContentSecurityPolicyType,
- ::blink::WebContentSecurityPolicyType> {
- static ::blink::mojom::ContentSecurityPolicyType ToMojom(
- ::blink::WebContentSecurityPolicyType input) {
- switch (input) {
- case ::blink::kWebContentSecurityPolicyTypeReport:
- return ::blink::mojom::ContentSecurityPolicyType::kReport;
- case ::blink::kWebContentSecurityPolicyTypeEnforce:
- return ::blink::mojom::ContentSecurityPolicyType::kEnforce;
- }
- NOTREACHED();
- return ::blink::mojom::ContentSecurityPolicyType::kReport;
- }
-
- static bool FromMojom(::blink::mojom::ContentSecurityPolicyType input,
- ::blink::WebContentSecurityPolicyType* output) {
- switch (input) {
- case ::blink::mojom::ContentSecurityPolicyType::kReport:
- *output = ::blink::kWebContentSecurityPolicyTypeReport;
- return true;
- case ::blink::mojom::ContentSecurityPolicyType::kEnforce:
- *output = ::blink::kWebContentSecurityPolicyTypeEnforce;
- return true;
- }
- NOTREACHED();
- return false;
- }
-};
-
-} // namespace mojo
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_CONTENT_SECURITY_POLICY_STRUCT_TRAITS_H_
diff --git a/chromium/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h b/chromium/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
index 8e99f30d4da..2711865a78a 100644
--- a/chromium/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
+++ b/chromium/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-shared.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_string.h"
diff --git a/chromium/third_party/blink/public/platform/modules/badging/badging.mojom b/chromium/third_party/blink/public/platform/modules/badging/badging.mojom
index 45ce81ce1cd..c230f143b71 100644
--- a/chromium/third_party/blink/public/platform/modules/badging/badging.mojom
+++ b/chromium/third_party/blink/public/platform/modules/badging/badging.mojom
@@ -6,14 +6,15 @@ module blink.mojom;
// Interface for handling badge messages from frames and subframes.
interface BadgeService {
- // Sets a badge for the PWA corresponding to the context sending the request
- // if such a PWA exists.
- // TODO(estevenson): Pass the badge contents from the API. Chrome OS will be
- // the first client and will not show the data anyway so for now this is
- // sufficient.
- SetBadge();
+ // Sets the badge for the PWA corresponding to this request to be a
+ // non-zero, positive integer.
+ SetInteger(uint64 content);
- // Clear badge (if it exists) for the PWA corresponding to the context sending
- // the request if such a PWA exists.
+ // Sets the badge for the PWA corresponding to this request to be a
+ // flag marker.
+ SetFlag();
+
+ // Clears the badge (if it exists) for the PWA corresponding to
+ // this request.
ClearBadge();
};
diff --git a/chromium/third_party/blink/public/platform/modules/bluetooth/OWNERS b/chromium/third_party/blink/public/platform/modules/bluetooth/OWNERS
index f7fb0bd3c8f..0eb4b3b0d9f 100644
--- a/chromium/third_party/blink/public/platform/modules/bluetooth/OWNERS
+++ b/chromium/third_party/blink/public/platform/modules/bluetooth/OWNERS
@@ -1,5 +1,4 @@
-jyasskin@chromium.org
-ortuno@chromium.org
+file://content/browser/bluetooth/OWNERS
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom b/chromium/third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom
index cbcd8ef3c23..4d907a90290 100644
--- a/chromium/third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom
+++ b/chromium/third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom
@@ -109,6 +109,12 @@ struct WebBluetoothRequestDeviceOptions {
bool accept_all_devices;
};
+struct WebBluetoothRequestLEScanOptions {
+ array<WebBluetoothLeScanFilter>? filters;
+ bool keep_repeated_devices;
+ bool accept_all_advertisements;
+};
+
// Indicates if the function will return a single or multiple
// GATT objects.
enum WebBluetoothGATTQueryQuantity {
@@ -140,6 +146,27 @@ struct WebBluetoothRemoteGATTCharacteristic {
uint32 properties;
};
+// On success, |options| contains the values used for the scan request. On
+// error, |result| will indicate the failure type.
+union RequestScanningStartResult {
+ WebBluetoothResult error_result;
+ WebBluetoothRequestLEScanOptions options;
+};
+
+struct WebBluetoothScanResult {
+ WebBluetoothDevice device;
+ string? name;
+ array<bluetooth.mojom.UUID> uuids;
+ bool appearance_is_set;
+ uint16 appearance;
+ bool tx_power_is_set;
+ uint8 tx_power;
+ bool rssi_is_set;
+ uint8 rssi;
+ map<uint16, array<uint8>> manufacturer_data;
+ map<string, array<uint8>> service_data;
+};
+
struct WebBluetoothRemoteGATTDescriptor {
string instance_id; // See Instance ID Note above.
bluetooth.mojom.UUID uuid;
@@ -250,6 +277,11 @@ interface WebBluetoothService {
RemoteDescriptorWriteValue(
string descriptor_instance_id,
array<uint8> value) => (WebBluetoothResult result);
+
+ // Starts scanning for low energy devices.
+ RequestScanningStart(associated WebBluetoothScanClient client,
+ WebBluetoothRequestLEScanOptions options) => (
+ RequestScanningStartResult result);
};
// Classes that implement this interface will be notified of device events.
@@ -264,3 +296,10 @@ interface WebBluetoothCharacteristicClient {
// Called when we receive a notification for the characteristic.
RemoteCharacteristicValueChanged(array<uint8> value);
};
+
+// Classes that implement this interface will be notified of scan
+// events.
+interface WebBluetoothScanClient {
+ // Called when we receive a notification for the characteristic.
+ ScanEvent(WebBluetoothScanResult result);
+};
diff --git a/chromium/third_party/blink/public/platform/modules/fetch/OWNERS b/chromium/third_party/blink/public/platform/modules/fetch/OWNERS
deleted file mode 100644
index 7a628a2c4a9..00000000000
--- a/chromium/third_party/blink/public/platform/modules/fetch/OWNERS
+++ /dev/null
@@ -1,11 +0,0 @@
-hiroshige@chromium.org
-horo@chromium.org
-yhirano@chromium.org
-
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: Blink>Network>FetchAPI
diff --git a/chromium/third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom b/chromium/third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom
index a4ff4c08b91..ec975114857 100644
--- a/chromium/third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom
+++ b/chromium/third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom
@@ -41,14 +41,19 @@ interface EmbeddedFrameSinkProvider {
// calling RegisterEmbeddedFrameSink() for |frame_sink_id|.
CreateCompositorFrameSink(viz.mojom.FrameSinkId frame_sink_id,
viz.mojom.CompositorFrameSinkClient client,
- viz.mojom.CompositorFrameSink& sink,
- SurfaceEmbedder& notifier);
+ viz.mojom.CompositorFrameSink& sink);
- // Ceate CompositorFrameSink directly in a single call (instead of going
+ // Create CompositorFrameSink directly in a single call (instead of going
// through both function above).
CreateSimpleCompositorFrameSink(viz.mojom.FrameSinkId parent_frame_sink_id,
viz.mojom.FrameSinkId frame_sink_id,
EmbeddedFrameSinkClient surface_client,
viz.mojom.CompositorFrameSinkClient client,
viz.mojom.CompositorFrameSink& sink);
+
+ // Establishes a direct connection to the embedder of |frame_sink_id|. This
+ // will allow the client to let the embedder know what LocalSurfaceId it is
+ // using.
+ ConnectToEmbedder(viz.mojom.FrameSinkId frame_sink_id,
+ SurfaceEmbedder& embedder);
};
diff --git a/chromium/third_party/blink/public/platform/modules/idle/OWNERS b/chromium/third_party/blink/public/platform/modules/idle/OWNERS
new file mode 100644
index 00000000000..b0db2625573
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/modules/idle/OWNERS
@@ -0,0 +1,4 @@
+file://content/browser/idle/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/public/platform/modules/idle/idle_manager.mojom b/chromium/third_party/blink/public/platform/modules/idle/idle_manager.mojom
new file mode 100644
index 00000000000..3b36a6a175e
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/modules/idle/idle_manager.mojom
@@ -0,0 +1,27 @@
+// 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.
+
+module blink.mojom;
+
+// Implementation of the proposed "Idle Detection API".
+//
+// Proposal: https://github.com/inexorabletash/idle-detection
+
+enum IdleState {
+ ACTIVE,
+ IDLE,
+ LOCKED
+};
+
+interface IdleMonitor {
+ Update(IdleState state);
+};
+
+interface IdleManager {
+ // Register an IdleMonitor instance. When registered, it will return the
+ // initial state. It will be notified by calls to Update() per the threshold
+ // registered for this instance. It can be unregistered by simply closing
+ // the pipe.
+ AddMonitor(uint32 threshold, IdleMonitor monitor) => (IdleState state);
+};
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h b/chromium/third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h
deleted file mode 100644
index 28a5e8fad19..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_INDEXED_DB_KEY_BUILDER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_INDEXED_DB_KEY_BUILDER_H_
-
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/web_common.h"
-
-namespace blink {
-
-class IndexedDBKeyRange;
-class WebIDBKeyPath;
-class WebIDBKeyRange;
-
-class BLINK_EXPORT IndexedDBKeyBuilder {
- public:
- static IndexedDBKey Build(WebIDBKeyView key);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IndexedDBKeyBuilder);
-};
-
-class BLINK_EXPORT WebIDBKeyBuilder {
- public:
- static WebIDBKey Build(const IndexedDBKey& key);
- static WebIDBKey Build(const WebIDBKeyView& key);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebIDBKeyBuilder);
-};
-
-class BLINK_EXPORT IndexedDBKeyRangeBuilder {
- public:
- static IndexedDBKeyRange Build(const WebIDBKeyRange& key_range);
-
- // Builds a point range (containing a single key).
- static IndexedDBKeyRange Build(WebIDBKeyView key);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IndexedDBKeyRangeBuilder);
-};
-
-class BLINK_EXPORT WebIDBKeyRangeBuilder {
- public:
- static WebIDBKeyRange Build(const IndexedDBKeyRange& key);
-
- // Builds a point range (containing a single key).
- static WebIDBKeyRange Build(WebIDBKeyView key);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebIDBKeyRangeBuilder);
-};
-
-class BLINK_EXPORT IndexedDBKeyPathBuilder {
- public:
- static IndexedDBKeyPath Build(const WebIDBKeyPath& key_path);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IndexedDBKeyPathBuilder);
-};
-
-class BLINK_EXPORT WebIDBKeyPathBuilder {
- public:
- static WebIDBKeyPath Build(const IndexedDBKeyPath& key_path);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebIDBKeyPathBuilder);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_INDEXED_DB_KEY_BUILDER_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h
deleted file mode 100644
index 65d1ff386f5..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_CALLBACKS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_CALLBACKS_H_
-
-#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-class WebIDBCursor;
-class WebIDBDatabase;
-class WebIDBDatabaseError;
-class WebIDBKey;
-struct WebIDBMetadata;
-struct WebIDBNameAndVersion;
-class WebIDBValue;
-
-class WebIDBCallbacks {
- public:
- virtual ~WebIDBCallbacks() = default;
-
- // Pointers transfer ownership.
- virtual void OnError(const WebIDBDatabaseError&) = 0;
- virtual void OnSuccess(const WebVector<WebIDBNameAndVersion>&) = 0;
- virtual void OnSuccess(const WebVector<WebString>&) = 0;
- virtual void OnSuccess(WebIDBCursor*,
- WebIDBKey,
- WebIDBKey primary_key,
- WebIDBValue) = 0;
- virtual void OnSuccess(WebIDBDatabase*, const WebIDBMetadata&) = 0;
- virtual void OnSuccess(WebIDBKey) = 0;
- virtual void OnSuccess(WebIDBValue) = 0;
- virtual void OnSuccess(WebVector<WebIDBValue>) = 0;
- virtual void OnSuccess(long long) = 0;
- virtual void OnSuccess() = 0;
- virtual void OnSuccess(WebIDBKey, WebIDBKey primary_key, WebIDBValue) = 0;
- virtual void OnBlocked(long long old_version) = 0;
- virtual void OnUpgradeNeeded(long long old_version,
- WebIDBDatabase*,
- const WebIDBMetadata&,
- mojom::IDBDataLoss data_loss,
- WebString data_loss_message) = 0;
- virtual void Detach() = 0;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_CALLBACKS_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key.h
deleted file mode 100644
index afd027054f6..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_H_
-
-#include <memory>
-
-#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_private_ptr.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-class IDBKey;
-class WebIDBKeyView;
-
-// Minimal interface for iterating over an IndexedDB array key.
-//
-// See WebIDBKeyView for the rationale behind this class' existence.
-class WebIDBKeyArrayView {
- public:
- BLINK_EXPORT size_t size() const;
-
- BLINK_EXPORT WebIDBKeyView operator[](size_t index) const;
-
- private:
- // Only WebIDBKeyView can vend WebIDBArrayKeyView instances.
- friend class WebIDBKeyView;
- explicit WebIDBKeyArrayView(const IDBKey* idb_key) : private_(idb_key) {}
-
- const IDBKey* const private_;
-};
-
-// Non-owning reference to an IndexedDB key.
-//
-// The Blink object wrapped by WebIDBKey is immutable, so WebIDBKeyView
-// instances are implicitly const references.
-//
-// Having both WebIDBKeyView and WebIDBKey is extra complexity, and we pay this
-// price to avoid unnecessary memory copying. Specifically, WebIDBKeyView is
-// used to issue requests to the IndexedDB backing store.
-//
-// For example, IDBCursor.update() must send the cursor's primary key to the
-// backing store. IDBCursor cannot give up the ownership of its primary key,
-// because it might need to satisfy further update() or delete() calls.
-class WebIDBKeyView {
- public:
- WebIDBKeyView(const WebIDBKeyView&) noexcept = default;
-
- explicit WebIDBKeyView(const IDBKey* idb_key) noexcept : private_(idb_key) {}
-
- BLINK_EXPORT WebIDBKeyType KeyType() const;
-
- BLINK_EXPORT bool IsValid() const;
-
- // Only valid for ArrayType.
- //
- // The caller is responsible for ensuring that the WebIDBKeyView is valid for
- // the lifetime of the returned WeIDBKeyArrayView.
- BLINK_EXPORT const WebIDBKeyArrayView ArrayView() const {
- return WebIDBKeyArrayView(private_);
- }
-
- // Only valid for BinaryType.
- BLINK_EXPORT WebData Binary() const;
-
- // Only valid for StringType.
- BLINK_EXPORT WebString String() const;
-
- // Only valid for DateType.
- BLINK_EXPORT double Date() const;
-
- // Only valid for NumberType.
- BLINK_EXPORT double Number() const;
-
- BLINK_EXPORT size_t SizeEstimate() const;
-
- // TODO(cmp): Ensure |private_| can never be null.
- //
- // SizeEstimate() can be called when |private_| is null. That happens if and
- // only if the |WebIDBKey| instance is created using WebIDBKey::CreateNull().
- //
- // Eventually, WebIDBKey::CreateNull() will change so that case will lead to
- // a non-null |private_|. At that time, this null check can change to a
- // DCHECK that |private_| is not null and the special null case handling can
- // be removed.
- BLINK_EXPORT bool IsNull() const { return !private_; }
-
- private:
- const IDBKey* const private_;
-};
-
-// Move-only handler that owns an IndexedDB key.
-//
-// The wrapped Blink object wrapped is immutable while it is owned by the
-// WebIDBKey.
-//
-// Having both WebIDBKeyView and WebIDBKeyArrayView is extra complexity, and we
-// pay this price to avoid unnecessary memory copying. Specifically, WebIDBKey
-// is used to receive data from the IndexedDB backing store. Once constructed, a
-// WebIDBKey is moved through the layer cake until the underlying Blink object
-// ends up at its final destination.
-class WebIDBKey {
- public:
- BLINK_EXPORT static WebIDBKey CreateArray(WebVector<WebIDBKey>);
- BLINK_EXPORT static WebIDBKey CreateBinary(const WebData&);
- BLINK_EXPORT static WebIDBKey CreateString(const WebString&);
- BLINK_EXPORT static WebIDBKey CreateDate(double);
- BLINK_EXPORT static WebIDBKey CreateNumber(double);
- BLINK_EXPORT static WebIDBKey CreateInvalid();
- BLINK_EXPORT static WebIDBKey CreateNull() noexcept { return WebIDBKey(); }
-
- // The default constructor must not be used explicitly.
- // It is only provided for WebVector and Mojo's use.
- BLINK_EXPORT WebIDBKey() noexcept;
-
- BLINK_EXPORT WebIDBKey(WebIDBKey&&) noexcept;
- BLINK_EXPORT WebIDBKey& operator=(WebIDBKey&&) noexcept;
-
- // TODO(cmp): Remove copy and assignment constructors when Vector<->WebVector
- // conversions are no longer needed.
- BLINK_EXPORT WebIDBKey(const WebIDBKey& rkey);
- BLINK_EXPORT WebIDBKey& operator=(const WebIDBKey& rkey);
-
- BLINK_EXPORT ~WebIDBKey();
-
- BLINK_EXPORT WebIDBKeyView View() const {
- return WebIDBKeyView(private_.get());
- }
-
- BLINK_EXPORT size_t SizeEstimate() const { return View().SizeEstimate(); }
-
-#if INSIDE_BLINK
- explicit WebIDBKey(std::unique_ptr<IDBKey>) noexcept;
- WebIDBKey& operator=(std::unique_ptr<IDBKey>) noexcept;
- operator IDBKey*() const noexcept { return private_.get(); }
-
- std::unique_ptr<IDBKey> ReleaseIdbKey() noexcept;
-#endif // INSIDE_BLINK
-
- private:
-
- std::unique_ptr<IDBKey> private_;
-};
-
-using WebIDBIndexKeys = std::pair<int64_t, WebVector<WebIDBKey>>;
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h
deleted file mode 100644
index 3ceceab17f1..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_PATH_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_PATH_H_
-
-#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-class WebIDBKeyPath {
- public:
- // FIXME: Update callers use constructors directly, and remove these.
- static WebIDBKeyPath Create(const WebString& string) {
- return WebIDBKeyPath(string);
- }
- static WebIDBKeyPath Create(const WebVector<WebString>& array) {
- return WebIDBKeyPath(array);
- }
- static WebIDBKeyPath CreateNull() { return WebIDBKeyPath(); }
-
- WebIDBKeyPath() : type_(kWebIDBKeyPathTypeNull) {}
-
- explicit WebIDBKeyPath(const WebString& string)
- : type_(kWebIDBKeyPathTypeString), string_(string) {}
-
- explicit WebIDBKeyPath(const WebVector<WebString>& array)
- : type_(kWebIDBKeyPathTypeArray), array_(array) {}
-
- WebIDBKeyPath(const WebIDBKeyPath& key_path) = default;
-
- ~WebIDBKeyPath() = default;
-
- WebIDBKeyPath& operator=(const WebIDBKeyPath& key_path) = default;
-
- WebIDBKeyPathType KeyPathType() const { return type_; }
-
- // Only valid for ArrayType.
- const WebVector<WebString>& Array() const { return array_; }
-
- // Only valid for StringType.
- const WebString& String() const { return string_; }
-
- private:
- WebIDBKeyPathType type_;
- WebVector<WebString> array_;
- WebString string_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_PATH_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h
deleted file mode 100644
index 79be20ae4fc..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_RANGE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_RANGE_H_
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_private_ptr.h"
-
-namespace blink {
-
-class IDBKeyRange;
-
-class WebIDBKeyRange {
- public:
- ~WebIDBKeyRange() { Reset(); }
-
- WebIDBKeyRange() = default;
- WebIDBKeyRange(const WebIDBKeyRange& key_range) { Assign(key_range); }
- WebIDBKeyRange(WebIDBKey lower,
- WebIDBKey upper,
- bool lower_open,
- bool upper_open) {
- Assign(std::move(lower), std::move(upper), lower_open, upper_open);
- }
-
- BLINK_EXPORT WebIDBKeyView Lower() const;
- BLINK_EXPORT WebIDBKeyView Upper() const;
- BLINK_EXPORT bool LowerOpen() const;
- BLINK_EXPORT bool UpperOpen() const;
-
- BLINK_EXPORT void Assign(const WebIDBKeyRange&);
- BLINK_EXPORT void Assign(WebIDBKey lower,
- WebIDBKey upper,
- bool lower_open,
- bool upper_open);
-
- WebIDBKeyRange& operator=(const WebIDBKeyRange& e) {
- Assign(e);
- return *this;
- }
-
- BLINK_EXPORT void Reset();
-
-#if INSIDE_BLINK
- WebIDBKeyRange(IDBKeyRange* value) : private_(value) {}
- WebIDBKeyRange& operator=(IDBKeyRange* value) {
- private_ = value;
- return *this;
- }
- operator IDBKeyRange*() const { return private_.Get(); }
-#endif
-
- private:
- WebPrivatePtr<IDBKeyRange> private_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_KEY_RANGE_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h
deleted file mode 100644
index 6368c4aafaf..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_NAME_AND_VERSION_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_NAME_AND_VERSION_H_
-
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-struct WebIDBNameAndVersion {
- enum { kNoVersion = -1 };
- WebString name;
- int64_t version;
-
- WebIDBNameAndVersion() : version(kNoVersion) {}
- WebIDBNameAndVersion(WebString name, int64_t version)
- : name(name), version(version) {}
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_NAME_AND_VERSION_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h
deleted file mode 100644
index 3ba4de6e5dd..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h
+++ /dev/null
@@ -1,43 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_OBSERVATION_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_OBSERVATION_H_
-
-#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
-
-namespace blink {
-
-struct WebIDBObservation {
- int64_t object_store_id;
- mojom::IDBOperationType type;
- WebIDBKeyRange key_range;
- WebIDBValue value;
-
- WebIDBObservation(int64_t object_store_id,
- mojom::IDBOperationType type,
- WebIDBKeyRange key_range,
- WebIDBValue value)
- : object_store_id(object_store_id),
- type(type),
- key_range(key_range),
- value(std::move(value)) {}
-
- WebIDBObservation(WebIDBObservation&&) = default;
- WebIDBObservation& operator=(WebIDBObservation&&) = default;
-
- private:
- // WebIDBObservation has to be move-only, because WebIDBValue is move-only.
- // Making the restriction explicit results in slightly better compilation
- // error messages in code that attempts copying.
- WebIDBObservation(const WebIDBObservation&) = delete;
- WebIDBObservation& operator=(const WebIDBObservation&) = delete;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_OBSERVATION_H_
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_value.h b/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_value.h
deleted file mode 100644
index e090e63106f..00000000000
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_value.h
+++ /dev/null
@@ -1,65 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_VALUE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_VALUE_H_
-
-#include <memory>
-#include <utility>
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/web_blob_info.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-class IDBValue;
-class WebData;
-class WebIDBKeyPath;
-
-// Handle to an IndexedDB Object Store value retrieved from the backing store.
-class WebIDBValue {
- public:
- BLINK_EXPORT WebIDBValue(const WebData&, const WebVector<WebBlobInfo>&);
-
- BLINK_EXPORT WebIDBValue(WebIDBValue&& other) noexcept;
- BLINK_EXPORT WebIDBValue& operator=(WebIDBValue&&) noexcept;
-
- BLINK_EXPORT ~WebIDBValue();
-
- // Used by object stores that store primary keys separately from wire data.
- BLINK_EXPORT void SetInjectedPrimaryKey(
- WebIDBKey primary_key,
- const WebIDBKeyPath& primary_key_path);
-
- // Returns the Blobs associated with this value. Should only be used for
- // testing.
- BLINK_EXPORT WebVector<WebBlobInfo> BlobInfoForTesting() const;
-
-#if INSIDE_BLINK
- // TODO(pwnall): When Onion Soup-ing IndexedDB, ReleaseIDBValue() should
- // take a v8::Isolate, and all the ownership tracking logic
- // can be deleted.
- BLINK_EXPORT std::unique_ptr<IDBValue> ReleaseIdbValue() noexcept;
-#endif // INSIDE_BLINK
-
- private:
- // WebIDBValue has to be move-only, because std::unique_ptr is move-only.
- // Making the restriction explicit results in slightly better compilation
- // error messages in code that attempts copying.
- WebIDBValue(const WebIDBValue&) = delete;
- WebIDBValue& operator=(const WebIDBValue&) = delete;
-
-#if DCHECK_IS_ON()
- // Called when the underlying IDBValue is about to be released.
- BLINK_EXPORT void ReleaseIdbValueOwnership();
-#endif // DCHECK_IS_ON()
-
- std::unique_ptr<IDBValue> private_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_VALUE_H_
diff --git a/chromium/third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom b/chromium/third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom
index 424b8f40d4f..3ee3591c643 100644
--- a/chromium/third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom
+++ b/chromium/third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom
@@ -5,9 +5,7 @@
module blink.mojom;
// InsecureInputService receives per-frame notifications about insecure input
-// operations (display of password fields, editing of any fields) on the page.
+// operations (e.g. editing of any fields) on the page.
interface InsecureInputService {
- PasswordFieldVisibleInInsecureContext();
- AllPasswordFieldsInInsecureContextInvisible();
DidEditFieldInInsecureContext();
};
diff --git a/chromium/third_party/blink/public/platform/modules/locks/lock_manager.mojom b/chromium/third_party/blink/public/platform/modules/locks/lock_manager.mojom
index fa4fa2c9a49..800009a9aa3 100644
--- a/chromium/third_party/blink/public/platform/modules/locks/lock_manager.mojom
+++ b/chromium/third_party/blink/public/platform/modules/locks/lock_manager.mojom
@@ -13,8 +13,9 @@ interface LockHandle {};
// from the lock manager's queue.
interface LockRequest {
- // Request was granted.
- Granted(LockHandle lock_handle);
+ // Request was granted. Associated to maintain ordering within
+ // a LockManager, to match task queue behavior required by spec.
+ Granted(associated LockHandle lock_handle);
// Request failed; e.g. request was only "if available" and it was not.
Failed();
@@ -63,11 +64,12 @@ interface LockManager {
// when the lock is granted or if the request fails. If |request|'s
// channel is closed (e.g. due to terminated process) the request
// is removed from the manager's queues, which can unblock later
- // requests.
+ // requests. Associated to maintain to match task queue behavior
+ // defined by spec.
RequestLock(string name,
LockMode mode,
WaitMode wait,
- LockRequest request);
+ associated LockRequest request);
// Produces a snapshot of the lock manager's state. Web applications
// can use this for diagnostic purposes.
diff --git a/chromium/third_party/blink/public/platform/modules/mediasession/media_session.mojom b/chromium/third_party/blink/public/platform/modules/mediasession/media_session.mojom
index f4261da046d..a1c7453503c 100644
--- a/chromium/third_party/blink/public/platform/modules/mediasession/media_session.mojom
+++ b/chromium/third_party/blink/public/platform/modules/mediasession/media_session.mojom
@@ -15,23 +15,6 @@ enum MediaSessionPlaybackState {
PLAYING,
};
-// Album art in MediaMetadata
-// Spec: https://wicg.github.io/mediasession/
-struct MediaImage {
- url.mojom.Url src;
- mojo_base.mojom.String16 type;
- array<gfx.mojom.Size> sizes;
-};
-
-// MediaMetadata
-// Spec: https://wicg.github.io/mediasession/
-struct MediaMetadata {
- mojo_base.mojom.String16 title;
- mojo_base.mojom.String16 artist;
- mojo_base.mojom.String16 album;
- array<MediaImage> artwork;
-};
-
interface MediaSessionClient {
// Notifies the Blink side that a MediaSessionAction has been fired from the
// UI or the platform.
@@ -48,7 +31,7 @@ interface MediaSessionService {
// Notifies the browser that the metadata is set, |metadata| will be displayed
// on the UI.
- SetMetadata(MediaMetadata? metadata);
+ SetMetadata(media_session.mojom.MediaMetadata? metadata);
// Notifies the browser that the event handler for |action| has been set,
// browser needs to show a media button in the UI or register listeners to the
diff --git a/chromium/third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h b/chromium/third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h
new file mode 100644
index 00000000000..44b2882ea83
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h
@@ -0,0 +1,101 @@
+// 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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_PLATFORM_MEDIA_STREAM_SOURCE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_PLATFORM_MEDIA_STREAM_SOURCE_H_
+
+#include "base/callback.h"
+#include "third_party/blink/public/common/mediastream/media_stream_request.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_media_stream_source.h"
+#include "third_party/blink/public/platform/web_private_ptr.h"
+
+namespace blink {
+
+class MediaStreamSource;
+class WebMediaStreamSource;
+
+// Names for media stream source capture types.
+// These are values set via the "chromeMediaSource" constraint.
+BLINK_PLATFORM_EXPORT extern const char kMediaStreamSourceTab[];
+BLINK_PLATFORM_EXPORT extern const char
+ kMediaStreamSourceScreen[]; /* video only */
+BLINK_PLATFORM_EXPORT extern const char kMediaStreamSourceDesktop[];
+BLINK_PLATFORM_EXPORT extern const char
+ kMediaStreamSourceSystem[]; /* audio only */
+
+class BLINK_PLATFORM_EXPORT WebPlatformMediaStreamSource {
+ public:
+ using SourceStoppedCallback =
+ base::Callback<void(const WebMediaStreamSource& source)>;
+
+ using ConstraintsCallback =
+ base::Callback<void(WebPlatformMediaStreamSource* source,
+ MediaStreamRequestResult result,
+ const WebString& result_name)>;
+
+ // Source constraints key for
+ // https://dev.w3.org/2011/webrtc/editor/getusermedia.html.
+ static const char kSourceId[];
+
+ WebPlatformMediaStreamSource();
+ virtual ~WebPlatformMediaStreamSource();
+
+ // Returns device information about a source that has been created by a
+ // JavaScript call to GetUserMedia, e.g., a camera or microphone.
+ const MediaStreamDevice& device() const { return device_; }
+
+ // Stops the source (by calling DoStopSource()) and runs FinalizeStopSource().
+ void StopSource();
+
+ // Sets the source's state to muted or to live.
+ void SetSourceMuted(bool is_muted);
+
+ // Sets device information about a source that has been created by a
+ // JavaScript call to GetUserMedia. F.E a camera or microphone.
+ void SetDevice(const MediaStreamDevice& device);
+
+ // Sets a callback that will be triggered when StopSource is called.
+ void SetStopCallback(const SourceStoppedCallback& stop_callback);
+
+ // Clears the previously-set SourceStoppedCallback so that it will not be run
+ // in the future.
+ void ResetSourceStoppedCallback();
+
+ // Change the source to the |new_device| by calling DoChangeSource().
+ void ChangeSource(const MediaStreamDevice& new_device);
+
+ WebMediaStreamSource Owner();
+#if INSIDE_BLINK
+ void SetOwner(MediaStreamSource*);
+#endif
+
+ protected:
+ // Called when StopSource is called. It allows derived classes to implement
+ // its own Stop method.
+ virtual void DoStopSource() = 0;
+
+ // Called when ChangeSource is called. It allows derived class to implement
+ // it's own ChangeSource method.
+ virtual void DoChangeSource(const MediaStreamDevice& new_device) = 0;
+
+ // Runs the stop callback (if set) and sets the
+ // WebMediaStreamSource::readyState to ended. This can be used by
+ // implementations to implement custom stop methods.
+ void FinalizeStopSource();
+
+ private:
+ MediaStreamDevice device_;
+ SourceStoppedCallback stop_callback_;
+ blink::WebPrivatePtr<MediaStreamSource,
+ kWebPrivatePtrDestructionSameThread,
+ WebPrivatePtrStrength::kWeak>
+ owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebPlatformMediaStreamSource);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_PLATFORM_MEDIA_STREAM_SOURCE_H_
diff --git a/chromium/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h b/chromium/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h
new file mode 100644
index 00000000000..d7b64758030
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/modules/mediastream/web_media_stream_sink.h
@@ -0,0 +1,32 @@
+// 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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_WEB_MEDIA_STREAM_SINK_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_WEB_MEDIA_STREAM_SINK_H_
+
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_media_stream_source.h"
+#include "third_party/blink/public/platform/web_media_stream_track.h"
+
+namespace blink {
+
+// MediaStreamSink is the base interface for MediaStreamAudioSink and
+// MediaStreamVideoSink. It allows an implementation to receive notifications
+// about state changes on a blink::WebMediaStreamSource object or such an
+// object underlying a blink::WebMediaStreamTrack.
+class BLINK_PLATFORM_EXPORT WebMediaStreamSink {
+ public:
+ virtual void OnReadyStateChanged(
+ blink::WebMediaStreamSource::ReadyState state) {}
+ virtual void OnEnabledChanged(bool enabled) {}
+ virtual void OnContentHintChanged(
+ blink::WebMediaStreamTrack::ContentHintType content_hint) {}
+
+ protected:
+ virtual ~WebMediaStreamSink() {}
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_WEB_MEDIA_STREAM_SINK_H_
diff --git a/chromium/third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h b/chromium/third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h
new file mode 100644
index 00000000000..cb89fb10ae1
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h
@@ -0,0 +1,50 @@
+// 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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_WEB_PLATFORM_MEDIA_STREAM_TRACK_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_WEB_PLATFORM_MEDIA_STREAM_TRACK_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_media_stream_track.h"
+
+namespace blink {
+
+// WebPlatformMediaStreamTrack is a low-level object backing a
+// blink::WebMediaStreamTrack.
+class BLINK_PLATFORM_EXPORT WebPlatformMediaStreamTrack {
+ public:
+ explicit WebPlatformMediaStreamTrack(bool is_local_track);
+ virtual ~WebPlatformMediaStreamTrack();
+
+ static WebPlatformMediaStreamTrack* GetTrack(
+ const blink::WebMediaStreamTrack& track);
+
+ virtual void SetEnabled(bool enabled) = 0;
+
+ virtual void SetContentHint(
+ blink::WebMediaStreamTrack::ContentHintType content_hint) = 0;
+
+ // If |callback| is not null, it is invoked when the track has stopped.
+ virtual void StopAndNotify(base::OnceClosure callback) = 0;
+
+ void Stop() { StopAndNotify(base::OnceClosure()); }
+
+ // TODO(hta): Make method pure virtual when all tracks have the method.
+ virtual void GetSettings(blink::WebMediaStreamTrack::Settings& settings) {}
+
+ bool is_local_track() const { return is_local_track_; }
+
+ private:
+ const bool is_local_track_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebPlatformMediaStreamTrack);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_WEB_PLATFORM_MEDIA_STREAM_TRACK_H_
diff --git a/chromium/third_party/blink/public/platform/modules/notifications/web_notification_data.h b/chromium/third_party/blink/public/platform/modules/notifications/web_notification_data.h
index 6c100ef679b..1ab0e9aac45 100644
--- a/chromium/third_party/blink/public/platform/modules/notifications/web_notification_data.h
+++ b/chromium/third_party/blink/public/platform/modules/notifications/web_notification_data.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_DATA_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_DATA_H_
+#include "third_party/blink/public/mojom/notifications/notification.mojom-shared.h"
#include "third_party/blink/public/platform/modules/notifications/web_notification_action.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
@@ -21,14 +22,9 @@ namespace blink {
// ultimately WebNotificationData will also be replaced by the mojom one there
// via Onion Soup effort.
struct WebNotificationData {
- enum Direction {
- kDirectionLeftToRight,
- kDirectionRightToLeft,
- kDirectionAuto
- };
-
WebString title;
- Direction direction = kDirectionLeftToRight;
+ mojom::NotificationDirection direction =
+ mojom::NotificationDirection::LEFT_TO_RIGHT;
WebString lang;
WebString body;
WebString tag;
diff --git a/chromium/third_party/blink/public/platform/modules/permissions/permission.mojom b/chromium/third_party/blink/public/platform/modules/permissions/permission.mojom
index 0ccecc19b9c..0476935916f 100644
--- a/chromium/third_party/blink/public/platform/modules/permissions/permission.mojom
+++ b/chromium/third_party/blink/public/platform/modules/permissions/permission.mojom
@@ -21,6 +21,7 @@ enum PermissionName {
CLIPBOARD_WRITE,
PAYMENT_HANDLER,
BACKGROUND_FETCH,
+ IDLE_DETECTION,
};
struct MidiPermissionDescriptor {
diff --git a/chromium/third_party/blink/public/platform/modules/presentation/OWNERS b/chromium/third_party/blink/public/platform/modules/presentation/OWNERS
deleted file mode 100644
index 00b27feb53b..00000000000
--- a/chromium/third_party/blink/public/platform/modules/presentation/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/blink/renderer/modules/presentation/OWNERS
diff --git a/chromium/third_party/blink/public/platform/modules/presentation/web_presentation_client.h b/chromium/third_party/blink/public/platform/modules/presentation/web_presentation_client.h
deleted file mode 100644
index 62cb93de8f3..00000000000
--- a/chromium/third_party/blink/public/platform/modules/presentation/web_presentation_client.h
+++ /dev/null
@@ -1,26 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PRESENTATION_WEB_PRESENTATION_CLIENT_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PRESENTATION_WEB_PRESENTATION_CLIENT_H_
-
-namespace blink {
-
-class WebPresentationReceiver;
-
-// The implementation the embedder has to provide for the Presentation API to
-// work.
-// It is expected this class will be removed when Presentation API is fully
-// onion souped (crbug.com/749327).
-class WebPresentationClient {
- public:
- virtual ~WebPresentationClient() = default;
-
- // Passes the Blink-side delegate to the embedder.
- virtual void SetReceiver(WebPresentationReceiver*) = 0;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PRESENTATION_WEB_PRESENTATION_CLIENT_H_
diff --git a/chromium/third_party/blink/public/platform/modules/presentation/web_presentation_receiver.h b/chromium/third_party/blink/public/platform/modules/presentation/web_presentation_receiver.h
deleted file mode 100644
index 28569c48ff8..00000000000
--- a/chromium/third_party/blink/public/platform/modules/presentation/web_presentation_receiver.h
+++ /dev/null
@@ -1,34 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PRESENTATION_WEB_PRESENTATION_RECEIVER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PRESENTATION_WEB_PRESENTATION_RECEIVER_H_
-
-#include "third_party/blink/public/platform/web_common.h"
-
-namespace blink {
-
-// The delegate Blink provides to WebPresentationClient in order to get
-// notified when to initialize the Presentation Receiver API (i.e. when
-// frame is finished loading) or when to terminate all receiver
-// PresentationConnections.
-// TODO(crbug.com/749327): Remove this interface as part of onion soup. Blink
-// should be able to directly listen for the notifications that are used to call
-// these methods.
-class BLINK_PLATFORM_EXPORT WebPresentationReceiver {
- public:
- virtual ~WebPresentationReceiver() = default;
-
- // Initializes the PresentationReceiver object, such as setting up Mojo
- // connections. No-ops if already initialized.
- virtual void Init() = 0;
-
- // Notifies the PresentationReceiver that it is about to be terminated (e.g.,
- // due to frame closing).
- virtual void OnReceiverTerminated() = 0;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PRESENTATION_WEB_PRESENTATION_RECEIVER_H_
diff --git a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h
index d9eb52bddeb..36fe1b1fe04 100644
--- a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h
+++ b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h
@@ -6,7 +6,6 @@
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CLIENTS_INFO_H_
#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-shared.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
@@ -19,19 +18,17 @@ namespace blink {
// TODO(crbug.com/879019): Remove this class once we move
// content.mojom.ServiceWorker impl into Blink.
struct WebServiceWorkerClientInfo {
- WebServiceWorkerClientInfo()
- : page_visibility_state(mojom::PageVisibilityState::kMaxValue),
- is_focused(false),
- frame_type(network::mojom::RequestContextFrameType::kNone),
- client_type(mojom::ServiceWorkerClientType::kWindow) {}
+ WebServiceWorkerClientInfo() = default;
WebString uuid;
- mojom::PageVisibilityState page_visibility_state;
- bool is_focused;
+ bool page_hidden = true;
+ bool is_focused = false;
WebURL url;
- network::mojom::RequestContextFrameType frame_type;
- mojom::ServiceWorkerClientType client_type;
+ network::mojom::RequestContextFrameType frame_type =
+ network::mojom::RequestContextFrameType::kNone;
+ mojom::ServiceWorkerClientType client_type =
+ mojom::ServiceWorkerClientType::kWindow;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h
index 19963c043fe..b1622f217f3 100644
--- a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h
+++ b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h
@@ -57,9 +57,6 @@ class WebServiceWorkerNetworkProvider {
// request made.
virtual void WillSendRequest(WebURLRequest&) {}
- // Returns an identifier of this provider.
- virtual int ProviderID() const { return -1; }
-
// For service worker clients.
virtual blink::mojom::ControllerServiceWorkerMode
IsControlledByServiceWorker() {
diff --git a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h
index cdc2b575963..050a1d4a908 100644
--- a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h
+++ b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h
@@ -27,7 +27,6 @@ struct WebServiceWorkerRegistrationObjectInfo {
WebServiceWorkerRegistrationObjectInfo(
int64_t registration_id,
WebURL scope,
- mojom::ScriptType type,
mojom::ServiceWorkerUpdateViaCache update_via_cache,
mojo::ScopedInterfaceEndpointHandle host_ptr_info,
mojo::ScopedInterfaceEndpointHandle request,
@@ -36,7 +35,6 @@ struct WebServiceWorkerRegistrationObjectInfo {
WebServiceWorkerObjectInfo active)
: registration_id(registration_id),
scope(std::move(scope)),
- type(type),
update_via_cache(update_via_cache),
host_ptr_info(std::move(host_ptr_info)),
request(std::move(request)),
@@ -49,7 +47,6 @@ struct WebServiceWorkerRegistrationObjectInfo {
int64_t registration_id;
WebURL scope;
- mojom::ScriptType type;
mojom::ServiceWorkerUpdateViaCache update_via_cache;
// For blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedPtrInfo.
diff --git a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
index dfa9130a36d..1c8588a0c09 100644
--- a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
+++ b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
@@ -8,7 +8,7 @@
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_private_ptr.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -17,7 +17,6 @@
#if INSIDE_BLINK
#include <utility>
-#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" // nogncheck
#include "third_party/blink/renderer/platform/network/http_header_map.h" // nogncheck
#include "third_party/blink/renderer/platform/weborigin/referrer.h" // nogncheck
#include "third_party/blink/renderer/platform/wtf/forward.h" // nogncheck
@@ -29,7 +28,6 @@ class UnguessableToken;
}
namespace blink {
-class BlobDataHandle;
class WebHTTPHeaderVisitor;
class WebServiceWorkerRequestPrivate;
@@ -69,13 +67,8 @@ class BLINK_PLATFORM_EXPORT WebServiceWorkerRequest {
void VisitHTTPHeaderFields(WebHTTPHeaderVisitor*) const;
- // There are two ways of representing body: WebHTTPBody or Blob. Only one
- // should be used.
void SetBody(const WebHTTPBody&);
WebHTTPBody Body() const;
- void SetBlob(const WebString& uuid,
- long long size,
- mojo::ScopedMessagePipeHandle);
void SetReferrer(const WebString&, network::mojom::ReferrerPolicy);
WebURL ReferrerUrl() const;
@@ -125,12 +118,7 @@ class BLINK_PLATFORM_EXPORT WebServiceWorkerRequest {
#if INSIDE_BLINK
const HTTPHeaderMap& Headers() const;
- void SetBlobDataHandle(scoped_refptr<BlobDataHandle>);
- scoped_refptr<BlobDataHandle> GetBlobDataHandle() const;
const Referrer& GetReferrer() const;
- void SetBlob(const WebString& uuid,
- long long size,
- mojom::blink::BlobPtrInfo);
#endif
private:
diff --git a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h
index 86575f2ccf1..541b05778cb 100644
--- a/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h
+++ b/chromium/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h
@@ -8,8 +8,8 @@
#include "base/time/time.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_private_ptr.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -59,6 +59,9 @@ class BLINK_PLATFORM_EXPORT WebServiceWorkerResponse {
void SetResponseType(network::mojom::FetchResponseType);
network::mojom::FetchResponseType ResponseType() const;
+ void SetResponseSource(network::mojom::FetchResponseSource);
+ network::mojom::FetchResponseSource ResponseSource() const;
+
void SetHeader(const WebString& key, const WebString& value);
// If the key already exists, appends the value to the same key (comma
diff --git a/chromium/third_party/blink/public/platform/modules/webmidi/DEPS b/chromium/third_party/blink/public/platform/modules/webmidi/DEPS
deleted file mode 100644
index dcd5e5b2a3b..00000000000
--- a/chromium/third_party/blink/public/platform/modules/webmidi/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
- # TODO(toyoshim): Remove following media/midi direct dependency in public
- # interface once Web MIDI starts calling the Mojo service inside Blink.
- # http://crbug.com/582327
- "+media/midi/midi_service.mojom-shared.h",
-]
diff --git a/chromium/third_party/blink/public/platform/modules/webmidi/OWNERS b/chromium/third_party/blink/public/platform/modules/webmidi/OWNERS
deleted file mode 100644
index 1a8a48de571..00000000000
--- a/chromium/third_party/blink/public/platform/modules/webmidi/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-kouhei@chromium.org
-toyoshim@chromium.org
-yhirano@chromium.org
-
-# TEAM: midi-dev@chromium.org
-# COMPONENT: Blink>WebMIDI
diff --git a/chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h b/chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h
deleted file mode 100644
index 9707b78a03e..00000000000
--- a/chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_WEBMIDI_WEB_MIDI_ACCESSOR_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_WEBMIDI_WEB_MIDI_ACCESSOR_H_
-
-#include "base/time/time.h"
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-class WebMIDIAccessor {
- public:
- virtual ~WebMIDIAccessor() = default;
-
- virtual void StartSession() {}
- virtual void Open(unsigned port_index) {}
- // |timeStamp| is measured in milliseconds as Web MIDI spec defines.
- virtual void SendMIDIData(unsigned port_index,
- const unsigned char* data,
- size_t length,
- base::TimeTicks time_stamp) {}
- virtual void Clear(unsigned port_index) {}
- virtual void Close(unsigned port_index) {}
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_WEBMIDI_WEB_MIDI_ACCESSOR_H_
diff --git a/chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor_client.h b/chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor_client.h
deleted file mode 100644
index 967969fa73c..00000000000
--- a/chromium/third_party/blink/public/platform/modules/webmidi/web_midi_accessor_client.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_WEBMIDI_WEB_MIDI_ACCESSOR_CLIENT_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_WEBMIDI_WEB_MIDI_ACCESSOR_CLIENT_H_
-
-#include "media/midi/midi_service.mojom-shared.h"
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-class WebMIDIAccessorClient {
- public:
- // didAddInputPort() and didAddOutputPort() can be called before and after
- // didStartSession() is called. But |id| should be unique in each function.
- virtual void DidAddInputPort(const WebString& id,
- const WebString& manufacturer,
- const WebString& name,
- const WebString& version,
- midi::mojom::PortState) = 0;
- virtual void DidAddOutputPort(const WebString& id,
- const WebString& manufacturer,
- const WebString& name,
- const WebString& version,
- midi::mojom::PortState) = 0;
- // didSetInputPortState() and didSetOutputPortState() should not be called
- // until didStartSession() is called.
- virtual void DidSetInputPortState(unsigned port_index,
- midi::mojom::PortState) = 0;
- virtual void DidSetOutputPortState(unsigned port_index,
- midi::mojom::PortState) = 0;
-
- virtual void DidStartSession(midi::mojom::Result) = 0;
-
- // |timeStamp| is in milliseconds according to the Web MIDI API.
- virtual void DidReceiveMIDIData(unsigned port_index,
- const unsigned char* data,
- size_t length,
- base::TimeTicks time_stamp) = 0;
-
- protected:
- virtual ~WebMIDIAccessorClient() = default;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_WEBMIDI_WEB_MIDI_ACCESSOR_CLIENT_H_
diff --git a/chromium/third_party/blink/public/platform/oom_intervention.mojom b/chromium/third_party/blink/public/platform/oom_intervention.mojom
index b6aca16ad34..fd5282b3a52 100644
--- a/chromium/third_party/blink/public/platform/oom_intervention.mojom
+++ b/chromium/third_party/blink/public/platform/oom_intervention.mojom
@@ -46,9 +46,11 @@ interface OomIntervention {
// memory usage exceeds |detection_args| memory thresholds (pmf, swap, virtual
// memory usage and blink memory usage), the renderer calls
// host->OnHighMemoryUsage(). The renderer also triggers OOM intervention when
- // |renderer_pause_enabled| or |navigate_ads_enabled| is true.
+ // |renderer_pause_enabled|, |navigate_ads_enabled| or
+ // |purge_v8_memory_enabled| is true.
StartDetection(OomInterventionHost host,
DetectionArgs detection_args,
bool renderer_pause_enabled,
- bool navigate_ads_enabled);
+ bool navigate_ads_enabled,
+ bool purge_v8_memory_enabled);
};
diff --git a/chromium/third_party/blink/public/platform/platform.h b/chromium/third_party/blink/public/platform/platform.h
index e3f1a22160b..3b36d5710b0 100644
--- a/chromium/third_party/blink/public/platform/platform.h
+++ b/chromium/third_party/blink/public/platform/platform.h
@@ -94,6 +94,7 @@ class Local;
namespace webrtc {
struct RtpCapabilities;
+class AsyncResolverFactory;
}
namespace blink {
@@ -111,8 +112,6 @@ class WebDatabaseObserver;
class WebGraphicsContext3DProvider;
class WebImageCaptureFrameGrabber;
class WebLocalFrame;
-class WebMIDIAccessor;
-class WebMIDIAccessorClient;
class WebMediaCapabilitiesClient;
class WebMediaPlayer;
class WebMediaRecorderHandler;
@@ -222,13 +221,6 @@ class BLINK_PLATFORM_EXPORT Platform {
return nullptr;
}
- // MIDI ----------------------------------------------------------------
-
- // Creates a platform dependent WebMIDIAccessor. MIDIAccessor under platform
- // creates and owns it.
- virtual std::unique_ptr<WebMIDIAccessor> CreateMIDIAccessor(
- WebMIDIAccessorClient*);
-
// Blob ----------------------------------------------------------------
// Must return non-null.
@@ -387,7 +379,7 @@ class BLINK_PLATFORM_EXPORT Platform {
virtual void CacheMetadata(blink::mojom::CodeCacheType cache_type,
const WebURL&,
base::Time response_time,
- const char* data,
+ const uint8_t* data,
size_t data_size) {}
// A request to fetch contents associated with this URL from metadata cache.
@@ -403,7 +395,7 @@ class BLINK_PLATFORM_EXPORT Platform {
virtual void CacheMetadataInCacheStorage(
const WebURL&,
base::Time response_time,
- const char* data,
+ const uint8_t* data,
size_t data_size,
const blink::WebSecurityOrigin& cache_storage_origin,
const WebString& cache_storage_cache_name) {}
@@ -656,6 +648,10 @@ class BLINK_PLATFORM_EXPORT Platform {
virtual std::unique_ptr<cricket::PortAllocator> CreateWebRtcPortAllocator(
WebLocalFrame* frame);
+ // May return null if WebRTC functionality is not implemented.
+ virtual std::unique_ptr<webrtc::AsyncResolverFactory>
+ CreateWebRtcAsyncResolverFactory();
+
// Creates a WebCanvasCaptureHandler to capture Canvas output.
virtual std::unique_ptr<WebCanvasCaptureHandler>
CreateCanvasCaptureHandler(const WebSize&, double, WebMediaStreamTrack*);
diff --git a/chromium/third_party/blink/public/platform/task_type.h b/chromium/third_party/blink/public/platform/task_type.h
index 6589eb11cfc..718031f7ade 100644
--- a/chromium/third_party/blink/public/platform/task_type.h
+++ b/chromium/third_party/blink/public/platform/task_type.h
@@ -131,6 +131,18 @@ enum class TaskType : unsigned {
kExperimentalWebSchedulingUserInteraction = 53,
kExperimentalWebSchedulingBestEffort = 54,
+ // https://drafts.csswg.org/css-font-loading/#task-source
+ kFontLoading = 56,
+
+ // https://w3c.github.io/manifest/#dfn-application-life-cycle-task-source
+ kApplicationLifeCycle = 57,
+
+ // https://wicg.github.io/background-fetch/#infrastructure
+ kBackgroundFetch = 58,
+
+ // https://www.w3.org/TR/permissions/
+ kPermission = 59,
+
///////////////////////////////////////
// Not-speced tasks should use one of the following task types
///////////////////////////////////////
@@ -205,7 +217,7 @@ enum class TaskType : unsigned {
kWorkerThreadTaskQueueV8 = 47,
kWorkerThreadTaskQueueCompositor = 48,
- kCount = 56,
+ kCount = 60,
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/web_application_cache_host.h b/chromium/third_party/blink/public/platform/web_application_cache_host.h
index 50322fc1be1..d6aa1da35d9 100644
--- a/chromium/third_party/blink/public/platform/web_application_cache_host.h
+++ b/chromium/third_party/blink/public/platform/web_application_cache_host.h
@@ -31,6 +31,8 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_APPLICATION_CACHE_HOST_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_APPLICATION_CACHE_HOST_H_
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-shared.h"
+#include "third_party/blink/public/mojom/appcache/appcache_info.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_vector.h"
@@ -46,39 +48,6 @@ class WebURLResponse;
// instances, and calls delete when the instance is no longer needed.
class WebApplicationCacheHost {
public:
- // These values must match blink::ApplicationCacheHost::Status values
- enum Status {
- kUncached,
- kIdle,
- kChecking,
- kDownloading,
- kUpdateReady,
- kObsolete
- };
-
- // These values must match blink::ApplicationCacheHost::EventID values
- enum EventID {
- kCheckingEvent,
- kErrorEvent,
- kNoUpdateEvent,
- kDownloadingEvent,
- kProgressEvent,
- kUpdateReadyEvent,
- kCachedEvent,
- kObsoleteEvent
- };
-
- enum ErrorReason {
- kManifestError,
- kSignatureError,
- kResourceError,
- kChangedError,
- kAbortError,
- kQuotaError,
- kPolicyError,
- kUnknownError
- };
-
static const int kAppCacheNoHostId = 0;
virtual ~WebApplicationCacheHost() = default;
@@ -100,11 +69,11 @@ class WebApplicationCacheHost {
// Called as the main resource is retrieved.
virtual void DidReceiveResponseForMainResource(const WebURLResponse&) {}
- virtual void DidReceiveDataForMainResource(const char* data, size_t len) {}
- virtual void DidFinishLoadingMainResource(bool success) {}
// Called on behalf of the scriptable interface.
- virtual Status GetStatus() { return kUncached; }
+ virtual mojom::AppCacheStatus GetStatus() {
+ return mojom::AppCacheStatus::APPCACHE_STATUS_UNCACHED;
+ }
virtual bool StartUpdate() { return false; }
virtual bool SwapCache() { return false; }
virtual void Abort() {}
diff --git a/chromium/third_party/blink/public/platform/web_application_cache_host_client.h b/chromium/third_party/blink/public/platform/web_application_cache_host_client.h
index 0203f2159c3..321f550d180 100644
--- a/chromium/third_party/blink/public/platform/web_application_cache_host_client.h
+++ b/chromium/third_party/blink/public/platform/web_application_cache_host_client.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_APPLICATION_CACHE_HOST_CLIENT_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_APPLICATION_CACHE_HOST_CLIENT_H_
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-shared.h"
#include "third_party/blink/public/platform/web_application_cache_host.h"
#include "third_party/blink/public/platform/web_common.h"
@@ -44,11 +45,11 @@ class WebApplicationCacheHostClient {
virtual void DidChangeCacheAssociation() = 0;
// Called to fire events in the scriptable interface.
- virtual void NotifyEventListener(WebApplicationCacheHost::EventID) = 0;
+ virtual void NotifyEventListener(mojom::AppCacheEventID) = 0;
virtual void NotifyProgressEventListener(const WebURL&,
int num_total,
int num_complete) = 0;
- virtual void NotifyErrorEventListener(WebApplicationCacheHost::ErrorReason,
+ virtual void NotifyErrorEventListener(mojom::AppCacheErrorReason,
const WebURL&,
int status,
const WebString& message) = 0;
diff --git a/chromium/third_party/blink/public/platform/web_color_scheme.h b/chromium/third_party/blink/public/platform/web_color_scheme.h
new file mode 100644
index 00000000000..f125105d3f7
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/web_color_scheme.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_COLOR_SCHEME_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_COLOR_SCHEME_H_
+
+namespace blink {
+
+// Use for passing preferred color scheme from the OS to the renderer.
+enum class WebColorScheme {
+ kNoPreference,
+ kDark,
+ kLight,
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/public/platform/web_content_decryption_module_access.h b/chromium/third_party/blink/public/platform/web_content_decryption_module_access.h
index 03190db426d..21d8a46aff7 100644
--- a/chromium/third_party/blink/public/platform/web_content_decryption_module_access.h
+++ b/chromium/third_party/blink/public/platform/web_content_decryption_module_access.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_CONTENT_DECRYPTION_MODULE_ACCESS_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_CONTENT_DECRYPTION_MODULE_ACCESS_H_
+#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -17,7 +18,8 @@ class BLINK_PLATFORM_EXPORT WebContentDecryptionModuleAccess {
public:
virtual ~WebContentDecryptionModuleAccess();
virtual void CreateContentDecryptionModule(
- WebContentDecryptionModuleResult) = 0;
+ WebContentDecryptionModuleResult,
+ scoped_refptr<base::SingleThreadTaskRunner>) = 0;
virtual WebMediaKeySystemConfiguration GetConfiguration() = 0;
virtual WebString GetKeySystem() = 0;
};
diff --git a/chromium/third_party/blink/public/platform/web_content_security_policy.h b/chromium/third_party/blink/public/platform/web_content_security_policy.h
index 4d94b012e20..df80a354895 100644
--- a/chromium/third_party/blink/public/platform/web_content_security_policy.h
+++ b/chromium/third_party/blink/public/platform/web_content_security_policy.h
@@ -31,16 +31,8 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_CONTENT_SECURITY_POLICY_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_CONTENT_SECURITY_POLICY_H_
-#include "third_party/blink/public/platform/web_string.h"
-
namespace blink {
-enum WebContentSecurityPolicyType {
- kWebContentSecurityPolicyTypeReport,
- kWebContentSecurityPolicyTypeEnforce,
- kWebContentSecurityPolicyTypeLast = kWebContentSecurityPolicyTypeEnforce
-};
-
enum WebContentSecurityPolicySource {
kWebContentSecurityPolicySourceHTTP,
kWebContentSecurityPolicySourceMeta,
diff --git a/chromium/third_party/blink/public/platform/web_content_security_policy_struct.h b/chromium/third_party/blink/public/platform/web_content_security_policy_struct.h
index eb1acd861ac..f6ad25e39c8 100644
--- a/chromium/third_party/blink/public/platform/web_content_security_policy_struct.h
+++ b/chromium/third_party/blink/public/platform/web_content_security_policy_struct.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_CONTENT_SECURITY_POLICY_STRUCT_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_CONTENT_SECURITY_POLICY_STRUCT_H_
+#include "third_party/blink/public/mojom/csp/content_security_policy.mojom-shared.h"
#include "third_party/blink/public/platform/web_content_security_policy.h"
#include "third_party/blink/public/platform/web_source_location.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -66,7 +67,7 @@ struct WebContentSecurityPolicyDirective {
};
struct WebContentSecurityPolicy {
- WebContentSecurityPolicyType disposition;
+ mojom::ContentSecurityPolicyType disposition;
WebContentSecurityPolicySource source;
WebVector<WebContentSecurityPolicyDirective> directives;
WebVector<WebString> report_endpoints;
@@ -107,7 +108,7 @@ struct WebContentSecurityPolicyViolation {
// Each policy has an associated disposition, which is either "enforce" or
// "report".
- WebContentSecurityPolicyType disposition;
+ mojom::ContentSecurityPolicyType disposition;
// Whether or not the violation happens after a redirect.
bool after_redirect;
diff --git a/chromium/third_party/blink/public/platform/web_document_subresource_filter.h b/chromium/third_party/blink/public/platform/web_document_subresource_filter.h
index 17d20f8dfc4..3d05f8390ba 100644
--- a/chromium/third_party/blink/public/platform/web_document_subresource_filter.h
+++ b/chromium/third_party/blink/public/platform/web_document_subresource_filter.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_DOCUMENT_SUBRESOURCE_FILTER_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_DOCUMENT_SUBRESOURCE_FILTER_H_
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
namespace blink {
diff --git a/chromium/third_party/blink/public/platform/web_feature.mojom b/chromium/third_party/blink/public/platform/web_feature.mojom
index a192b483503..935deec1a64 100644
--- a/chromium/third_party/blink/public/platform/web_feature.mojom
+++ b/chromium/third_party/blink/public/platform/web_feature.mojom
@@ -155,8 +155,6 @@ enum WebFeature {
kFormAssociationByParser = 248,
kSVGSVGElementInDocument = 250,
kSVGDocumentRootElement = 251,
- kWorkerSubjectToCSP = 257,
- kWorkerAllowedByChildBlockedByScript = 258,
kDeprecatedWebKitGradient = 260,
kDeprecatedWebKitLinearGradient = 261,
kDeprecatedWebKitRepeatingLinearGradient = 262,
@@ -1523,11 +1521,6 @@ enum WebFeature {
kReportUriMultipleEndpoints = 2052,
kReportUriSingleEndpoint = 2053,
kV8ConstructorNonUndefinedPrimitiveReturn = 2054,
- kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe = 2055,
- kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe = 2056,
- kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe = 2057,
- kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe = 2058,
- kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe = 2059,
kMediaSourceKeyframeTimeGreaterThanDependant = 2060,
kMediaSourceMuxedSequenceMode = 2061,
kPrepareModuleScript = 2062,
@@ -1789,15 +1782,6 @@ enum WebFeature {
kColorInputTypeChooserByTrustedClick = 2332,
kColorInputTypeChooserByUntrustedClick = 2333,
kCSSTypedOMStylePropertyMap = 2334,
- kScrollToFragmentRequested = 2335,
- kScrollToFragmentSucceedWithRaw = 2336,
- kScrollToFragmentSucceedWithASCII = 2337,
- kScrollToFragmentSucceedWithUTF8 = 2338,
- kScrollToFragmentSucceedWithIsomorphic = 2339,
- kScrollToFragmentFailWithASCII = 2341,
- kScrollToFragmentFailWithUTF8 = 2342,
- kScrollToFragmentFailWithIsomorphic = 2343,
- kScrollToFragmentFailWithInvalidEncoding = 2345,
kRTCPeerConnectionWithActiveCsp = 2346,
// The above items are available as of the M65 branch.
@@ -2037,7 +2021,7 @@ enum WebFeature {
kCSSValueAppearancePushButtonForOthersRendered = 2585,
kCSSValueAppearanceSquareButtonRendered = 2586,
kCSSValueAppearanceSquareButtonForOthersRendered = 2587,
- kGetComputedStyleForWebkitAppearance = 2588,
+ kGetComputedStyleForWebkitAppearanceExcludeDevTools = 2588, // M73
kCursorImageLE32x32 = 2589,
kCursorImageGT32x32 = 2590,
kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics = 2591,
@@ -2097,6 +2081,129 @@ enum WebFeature {
kCSSSelectorNotWithValidList = 2645,
kCSSSelectorNotWithInvalidList = 2646,
kCSSSelectorNotWithPartiallyValidList = 2647,
+ kV8IDBFactory_Databases_Method = 2648,
+ kOpenerNavigationDownloadCrossOriginNoGesture = 2649,
+ kV8RegExpMatchIsTrueishOnNonJSRegExp = 2650,
+ kV8RegExpMatchIsFalseishOnJSRegExp = 2651,
+ kDownloadInAdFrameWithUserGesture = 2652,
+ kDownloadInAdFrameWithoutUserGesture = 2653,
+ kNavigatorAppVersion = 2654,
+ kNavigatorDoNotTrack = 2655,
+ kNavigatorHardwareConcurrency = 2656,
+ kNavigatorLanguage = 2657,
+ kNavigatorLanguages = 2658,
+ kNavigatorMaxTouchPoints = 2659,
+ kNavigatorMimeTypes = 2660,
+ kNavigatorPlatform = 2661,
+ kNavigatorPlugins = 2662,
+ kNavigatorUserAgent = 2663,
+ kWebBluetoothRequestScan = 2664,
+ kV8SVGGeometryElement_IsPointInFill_Method = 2665,
+ kV8SVGGeometryElement_IsPointInStroke_Method = 2666,
+ kV8SVGGeometryElement_GetTotalLength_Method = 2667,
+ kV8SVGGeometryElement_GetPointAtLength_Method = 2668,
+ kOffscreenCanvasTransferToImageBitmap = 2669,
+ kOffscreenCanvasIsPointInPath = 2670,
+ kOffscreenCanvasIsPointInStroke = 2671,
+ kOffscreenCanvasMeasureText = 2672,
+ kOffscreenCanvasGetImageData = 2673,
+ kV8SVGTextContentElement_GetComputedTextLength_Method = 2674,
+ kV8SVGTextContentElement_GetEndPositionOfChar_Method = 2675,
+ kV8SVGTextContentElement_GetExtentOfChar_Method = 2676,
+ kV8SVGTextContentElement_GetStartPositionOfChar_Method = 2677,
+ kV8SVGTextContentElement_GetSubStringLength_Method = 2678,
+ kV8BatteryManager_ChargingTime_AttributeGetter = 2679,
+ kV8BatteryManager_Charging_AttributeGetter = 2680,
+ kV8BatteryManager_DischargingTime_AttributeGetter = 2681,
+ kV8BatteryManager_Level_AttributeGetter = 2682,
+ kV8PaintRenderingContext2D_IsPointInPath_Method = 2683,
+ kV8PaintRenderingContext2D_IsPointInStroke_Method = 2684,
+ kV8PaymentRequest_CanMakePayment_Method = 2685,
+ kV8AnalyserNode_GetByteFrequencyData_Method = 2686,
+ kV8AnalyserNode_GetByteTimeDomainData_Method = 2687,
+ kV8AnalyserNode_GetFloatFrequencyData_Method = 2688,
+ kV8AnalyserNode_GetFloatTimeDomainData_Method = 2689,
+ kV8AudioBuffer_CopyFromChannel_Method = 2690,
+ kV8AudioBuffer_GetChannelData_Method = 2691,
+ kWebGLDebugRendererInfo = 2692,
+ kV8WebGL2ComputeRenderingContext_GetExtension_Method = 2693,
+ kV8WebGL2ComputeRenderingContext_GetSupportedExtensions_Method = 2694,
+ kV8WebGL2RenderingContext_GetExtension_Method = 2695,
+ kV8WebGL2RenderingContext_GetSupportedExtensions_Method = 2696,
+ kV8WebGLRenderingContext_GetExtension_Method = 2697,
+ kV8WebGLRenderingContext_GetSupportedExtensions_Method = 2698,
+ kV8Screen_AvailHeight_AttributeGetter = 2699,
+ kV8Screen_AvailWidth_AttributeGetter = 2700,
+ kV8Screen_ColorDepth_AttributeGetter = 2701,
+ kV8Screen_Height_AttributeGetter = 2702,
+ kV8Screen_PixelDepth_AttributeGetter = 2703,
+ kV8Screen_Width_AttributeGetter = 2704,
+ kWindowInnerWidth = 2705,
+ kWindowInnerHeight = 2706,
+ kV8Window_MatchMedia_Method = 2707,
+ kWindowScrollX = 2708,
+ kWindowScrollY = 2709,
+ kWindowPageXOffset = 2710,
+ kWindowPageYOffset = 2711,
+ kWindowScreenX = 2712,
+ kWindowScreenY = 2713,
+ kWindowOuterHeight = 2714,
+ kWindowOuterWidth = 2715,
+ kWindowDevicePixelRatio = 2716,
+ kCanvasCaptureStream = 2717,
+ kV8HTMLMediaElement_CanPlayType_Method = 2718,
+ kHistoryLength = 2719,
+ kFeaturePolicyReportOnlyHeader = 2720,
+ kV8PaymentRequest_HasEnrolledInstrument_Method = 2721,
+ kTrustedTypesEnabled = 2722,
+ kTrustedTypesCreatePolicy = 2723,
+ kTrustedTypesDefaultPolicyUsed = 2724,
+ kTrustedTypesAssignmentError = 2725,
+ kBadgeSet = 2726,
+ kBadgeClear = 2727,
+ kElementTimingExplicitlyRequested = 2728,
+ kV8HTMLMediaElement_CaptureStream_Method = 2729,
+ kQuirkyLineBoxBackgroundSize = 2730,
+ kDirectlyCompositedImage = 2731,
+ kForbiddenSyncXhrInPageDismissal = 2732,
+ kV8HTMLVideoElement_AutoPictureInPicture_AttributeGetter = 2733,
+ kV8HTMLVideoElement_AutoPictureInPicture_AttributeSetter = 2734,
+ kAutoPictureInPictureAttribute = 2735,
+ kRTCAudioJitterBufferRtxHandling = 2736,
+ kWebShareCanShare = 2737,
+ kPriorityHints = 2738,
+ kTextAutosizedCrossSiteIframe = 2739,
+ kV8RTCQuicTransport_Constructor = 2740,
+ kV8RTCQuicTransport_Transport_AttributeGetter = 2741,
+ kV8RTCQuicTransport_State_AttributeGetter = 2742,
+ kV8RTCQuicTransport_GetKey_Method = 2743,
+ kV8RTCQuicTransport_GetStats_Method = 2744,
+ kV8RTCQuicTransport_Connect_Method = 2745,
+ kV8RTCQuicTransport_Listen_Method = 2746,
+ kV8RTCQuicTransport_Stop_Method = 2747,
+ kV8RTCQuicTransport_CreateStream_Method = 2748,
+ kV8RTCIceTransport_Constructor = 2749,
+ kV8RTCIceTransport_Role_AttributeGetter = 2750,
+ kV8RTCIceTransport_State_AttributeGetter = 2751,
+ kV8RTCIceTransport_GatheringState_AttributeGetter = 2752,
+ kV8RTCIceTransport_GetLocalCandidates_Method = 2753,
+ kV8RTCIceTransport_GetRemoteCandidates_Method = 2754,
+ kV8RTCIceTransport_GetSelectedCandidatePair_Method = 2755,
+ kV8RTCIceTransport_GetLocalParameters_Method = 2756,
+ kV8RTCIceTransport_GetRemoteParameters_Method = 2757,
+ kV8RTCQuicStream_Transport_AttributeGetter = 2758,
+ kV8RTCQuicStream_State_AttributeGetter = 2759,
+ kV8RTCQuicStream_ReadBufferedAmount_AttributeGetter = 2760,
+ kV8RTCQuicStream_MaxReadBufferedAmount_AttributeGetter = 2761,
+ kV8RTCQuicStream_WriteBufferedAmount_AttributeGetter = 2762,
+ kV8RTCQuicStream_MaxWriteBufferedAmount_AttributeGetter = 2763,
+ kV8RTCQuicStream_ReadInto_Method = 2764,
+ kV8RTCQuicStream_Write_Method = 2765,
+ kV8RTCQuicStream_Reset_Method = 2766,
+ kV8RTCQuicStream_WaitForWriteBufferedAmountBelow_Method = 2767,
+ kV8RTCQuicStream_WaitForReadable_Method = 2768,
+ kLayoutJankExplicitlyRequested = 2782,
+ kMediaSessionSkipAd = 2783,
// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.
diff --git a/chromium/third_party/blink/public/platform/web_focus_type.h b/chromium/third_party/blink/public/platform/web_focus_type.h
index 96f57ec61db..7fe423cb926 100644
--- a/chromium/third_party/blink/public/platform/web_focus_type.h
+++ b/chromium/third_party/blink/public/platform/web_focus_type.h
@@ -43,10 +43,7 @@ enum WebFocusType {
kWebFocusTypeForward,
kWebFocusTypeBackward,
// Spatial navigation.
- kWebFocusTypeUp,
- kWebFocusTypeDown,
- kWebFocusTypeLeft,
- kWebFocusTypeRight,
+ kWebFocusTypeSpatialNavigation,
// Mouse press
kWebFocusTypeMouse,
// Re-focus by a page focus
diff --git a/chromium/third_party/blink/public/platform/web_font_render_style.h b/chromium/third_party/blink/public/platform/web_font_render_style.h
index 08e0ec124e0..75853e26e15 100644
--- a/chromium/third_party/blink/public/platform/web_font_render_style.h
+++ b/chromium/third_party/blink/public/platform/web_font_render_style.h
@@ -31,6 +31,7 @@
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FONT_RENDER_STYLE_H_
#include "SkFontStyle.h"
+#include "SkFontTypes.h"
#include "SkPaint.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -72,7 +73,6 @@ struct WebFontRenderStyle {
// kNoPreference in |other|.
void OverrideWith(const WebFontRenderStyle& other);
- void ApplyToSkPaint(SkPaint&, float device_scale_factor) const;
void ApplyToSkFont(SkFont*, float device_scale_factor) const;
// Each of the use* members below can take one of three values:
diff --git a/chromium/third_party/blink/public/platform/web_gesture_event.h b/chromium/third_party/blink/public/platform/web_gesture_event.h
index ee14c58c440..33303f79af7 100644
--- a/chromium/third_party/blink/public/platform/web_gesture_event.h
+++ b/chromium/third_party/blink/public/platform/web_gesture_event.h
@@ -134,6 +134,11 @@ class WebGestureEvent : public WebInputEvent {
// True if this event is generated from a wheel event with synthetic
// phase.
bool synthetic;
+ // True if this event is generated by the fling controller. The GSE
+ // generated at the end of a fling should not get pushed to the
+ // debouncing_deferral_queue_. This attribute is not mojofied and will not
+ // get transferred across since it is only used on the browser.
+ bool generated_by_fling_controller;
} scroll_end;
struct {
diff --git a/chromium/third_party/blink/public/platform/web_insecure_request_policy.h b/chromium/third_party/blink/public/platform/web_insecure_request_policy.h
index 8e22f6a1ff2..f83715de79c 100644
--- a/chromium/third_party/blink/public/platform/web_insecure_request_policy.h
+++ b/chromium/third_party/blink/public/platform/web_insecure_request_policy.h
@@ -9,6 +9,9 @@
namespace blink {
+// The values of
+// https://w3c.github.io/webappsec-upgrade-insecure-requests/#insecure-requests-policy
+//
// TODO(mkwst): In an ideal world, the combined state would be the same as
// "Upgrade". Once we're consistently upgrading all requests, we can replace
// this bitfield-style representation with an enum. Until then, we need to
diff --git a/chromium/third_party/blink/public/platform/web_isolated_world_info.h b/chromium/third_party/blink/public/platform/web_isolated_world_info.h
new file mode 100644
index 00000000000..8cdb4d9cead
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/web_isolated_world_info.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_string.h"
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_ISOLATED_WORLD_INFO_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_ISOLATED_WORLD_INFO_H_
+
+namespace blink {
+
+struct WebIsolatedWorldInfo {
+ // Associates an isolated world with a security origin. XMLHttpRequest
+ // instances used in that world will be considered to come from that origin,
+ // not the frame's.
+ //
+ // Currently the origin shouldn't be aliased, because IsolatedCopy() is
+ // taken before associating it to an isolated world and aliased relationship,
+ // if any, is broken. crbug.com/779730
+ // Note: If this is null, the security origin for the isolated world is
+ // cleared.
+ WebSecurityOrigin security_origin;
+
+ // Associates a content security policy with an isolated world. This policy
+ // should be used when evaluating script in the isolated world, and should
+ // also replace a protected resource's CSP when evaluating resources
+ // injected into the DOM.
+ //
+ // TODO(crbug.com/896041): Setting this simply bypasses the protected
+ // resource's CSP. It doesn't yet restrict the isolated world to the provided
+ // policy.
+ // Note: If this is null, the content security policy for the isolated world
+ // is cleared. Else if this is specified, |security_origin| must also be
+ // specified.
+ WebString content_security_policy;
+
+ // Associates an isolated world with human-readable name which is useful for
+ // extension debugging.
+ WebString human_readable_name;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_ISOLATED_WORLD_INFO_H_
diff --git a/chromium/third_party/blink/public/platform/web_layer_tree_view.h b/chromium/third_party/blink/public/platform/web_layer_tree_view.h
index 3fae14b03cd..08ee91c9760 100644
--- a/chromium/third_party/blink/public/platform/web_layer_tree_view.h
+++ b/chromium/third_party/blink/public/platform/web_layer_tree_view.h
@@ -32,6 +32,7 @@
#include "cc/input/layer_selection_bound.h"
#include "cc/input/overscroll_behavior.h"
#include "cc/layers/layer.h"
+#include "cc/paint/paint_worklet_layer_painter.h"
#include "cc/trees/element_id.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_mutator.h"
@@ -137,13 +138,6 @@ class WebLayerTreeView {
// Flow control and scheduling ---------------------------------------
- // Indicates that blink needs a BeginFrame, but that nothing might actually be
- // dirty.
- virtual void SetNeedsBeginFrame() {}
-
- // Run layout and paint of all pending document changes asynchronously.
- virtual void LayoutAndPaintAsync(base::OnceClosure callback) {}
-
virtual void CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) {}
@@ -179,6 +173,10 @@ class WebLayerTreeView {
// Mutations are plumbed back to the layer tree via the mutator client.
virtual void SetMutatorClient(std::unique_ptr<cc::LayerTreeMutator>) {}
+ // Paints are plumbed back to the layer tree via the painter client.
+ virtual void SetPaintWorkletLayerPainterClient(
+ std::unique_ptr<cc::PaintWorkletLayerPainter>) {}
+
// For when the embedder itself change scales on the page (e.g. devtools)
// and wants all of the content at the new scale to be crisp.
virtual void ForceRecalculateRasterScales() {}
@@ -202,21 +200,6 @@ class WebLayerTreeView {
virtual int LayerTreeId() const { return 0; }
- // Toggles the FPS counter in the HUD layer
- virtual void SetShowFPSCounter(bool) {}
-
- // Toggles the paint rects in the HUD layer
- virtual void SetShowPaintRects(bool) {}
-
- // Toggles the debug borders on layers
- virtual void SetShowDebugBorders(bool) {}
-
- // Toggles scroll bottleneck rects on the HUD layer
- virtual void SetShowScrollBottleneckRects(bool) {}
-
- // Toggles the hit-test borders on layers
- virtual void SetShowHitTestBorders(bool) {}
-
// ReportTimeCallback is a callback that should be fired when the
// corresponding Swap completes (either with DidSwap or DidNotSwap).
virtual void NotifySwapTime(ReportTimeCallback callback) {}
diff --git a/chromium/third_party/blink/public/platform/web_localized_string.h b/chromium/third_party/blink/public/platform/web_localized_string.h
index 8be42ff3dfd..50160f55327 100644
--- a/chromium/third_party/blink/public/platform/web_localized_string.h
+++ b/chromium/third_party/blink/public/platform/web_localized_string.h
@@ -54,14 +54,14 @@ struct WebLocalizedString {
kAXMediaDownloadButton,
kAXMediaEnterFullscreenButton,
kAXMediaExitFullscreenButton,
- kAXMediaHideClosedCaptionsButton,
+ kAXMediaHideClosedCaptionsMenuButton,
kAXMediaMuteButton,
kAXMediaDisplayCutoutFullscreenButton,
kAXMediaOverflowButton,
kAXMediaOverflowButtonHelp,
kAXMediaPauseButton,
kAXMediaPlayButton,
- kAXMediaShowClosedCaptionsButton,
+ kAXMediaShowClosedCaptionsMenuButton,
kAXMediaTimeRemainingDisplay,
kAXMediaTimeRemainingDisplayHelp,
kAXMediaUnMuteButton,
diff --git a/chromium/third_party/blink/public/platform/web_media_player.h b/chromium/third_party/blink/public/platform/web_media_player.h
index f22b491df7d..edfea4cc463 100644
--- a/chromium/third_party/blink/public/platform/web_media_player.h
+++ b/chromium/third_party/blink/public/platform/web_media_player.h
@@ -201,6 +201,8 @@ class WebMediaPlayer {
virtual double Duration() const = 0;
virtual double CurrentTime() const = 0;
+ virtual bool PausedWhenHidden() const { return false; }
+
// Internal states of loading and network.
virtual NetworkState GetNetworkState() const = 0;
virtual ReadyState GetReadyState() const = 0;
@@ -407,6 +409,8 @@ class WebMediaPlayer {
virtual bool DidLazyLoad() const { return false; }
virtual void OnBecameVisible() {}
+
+ virtual bool IsOpaque() const { return false; }
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/web_media_stream_source.h b/chromium/third_party/blink/public/platform/web_media_stream_source.h
index 7d722ead856..773fc1c66aa 100644
--- a/chromium/third_party/blink/public/platform/web_media_stream_source.h
+++ b/chromium/third_party/blink/public/platform/web_media_stream_source.h
@@ -31,6 +31,8 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_STREAM_SOURCE_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_STREAM_SOURCE_H_
+#include <memory>
+
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/blink/public/platform/web_vector.h"
@@ -44,26 +46,11 @@ namespace blink {
class MediaStreamSource;
class WebAudioDestinationConsumer;
+class WebPlatformMediaStreamSource;
class WebString;
class WebMediaStreamSource {
public:
- class ExtraData {
- public:
- ExtraData() : owner_(0) {}
- virtual ~ExtraData() = default;
-
- BLINK_PLATFORM_EXPORT WebMediaStreamSource Owner();
-#if INSIDE_BLINK
- BLINK_PLATFORM_EXPORT void SetOwner(MediaStreamSource*);
-#endif
-
- private:
-#if INSIDE_BLINK
- GC_PLUGIN_IGNORE("http://crbug.com/409526")
-#endif
- MediaStreamSource* owner_;
- };
enum Type { kTypeAudio, kTypeVideo };
@@ -86,6 +73,7 @@ class WebMediaStreamSource {
WebVector<WebString> echo_cancellation_type;
WebVector<bool> auto_gain_control;
WebVector<bool> noise_suppression;
+ WebVector<int32_t> sample_size;
WebMediaStreamTrack::FacingMode facing_mode =
WebMediaStreamTrack::FacingMode::kNone;
@@ -125,12 +113,9 @@ class WebMediaStreamSource {
BLINK_PLATFORM_EXPORT void SetReadyState(ReadyState);
BLINK_PLATFORM_EXPORT ReadyState GetReadyState() const;
- // Extra data associated with this object.
- // If non-null, the extra data pointer will be deleted when the object is
- // destroyed. Setting the extra data pointer will cause any existing non-null
- // extra data pointer to be deleted.
- BLINK_PLATFORM_EXPORT ExtraData* GetExtraData() const;
- BLINK_PLATFORM_EXPORT void SetExtraData(ExtraData*);
+ BLINK_PLATFORM_EXPORT WebPlatformMediaStreamSource* GetPlatformSource() const;
+ BLINK_PLATFORM_EXPORT void SetPlatformSource(
+ std::unique_ptr<WebPlatformMediaStreamSource>);
BLINK_PLATFORM_EXPORT void SetAudioProcessingProperties(
EchoCancellationMode echo_cancellation_mode,
diff --git a/chromium/third_party/blink/public/platform/web_media_stream_track.h b/chromium/third_party/blink/public/platform/web_media_stream_track.h
index 4c56f061b93..8d134fa9b53 100644
--- a/chromium/third_party/blink/public/platform/web_media_stream_track.h
+++ b/chromium/third_party/blink/public/platform/web_media_stream_track.h
@@ -25,6 +25,8 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_STREAM_TRACK_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_STREAM_TRACK_H_
+#include <memory>
+
#include "base/optional.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_private_ptr.h"
@@ -36,8 +38,8 @@ class MediaStreamComponent;
class MediaStreamTrack;
class WebAudioSourceProvider;
class WebMediaConstraints;
-class WebMediaStream;
class WebMediaStreamSource;
+class WebPlatformMediaStreamTrack;
class WebString;
class WebMediaStreamTrack {
@@ -103,13 +105,6 @@ class WebMediaStreamTrack {
base::Optional<CursorCaptureType> cursor;
};
- class TrackData {
- public:
- TrackData() = default;
- virtual ~TrackData() = default;
- virtual void GetSettings(Settings&) = 0;
- };
-
enum class ContentHintType {
kNone,
kAudioSpeech,
@@ -146,12 +141,9 @@ class WebMediaStreamTrack {
BLINK_PLATFORM_EXPORT WebMediaConstraints Constraints() const;
BLINK_PLATFORM_EXPORT void SetConstraints(const WebMediaConstraints&);
- // Extra data associated with this WebMediaStream.
- // If non-null, the extra data pointer will be deleted when the object is
- // destroyed. Setting the track data pointer will cause any existing non-null
- // track data pointer to be deleted.
- BLINK_PLATFORM_EXPORT TrackData* GetTrackData() const;
- BLINK_PLATFORM_EXPORT void SetTrackData(TrackData*);
+ BLINK_PLATFORM_EXPORT WebPlatformMediaStreamTrack* GetPlatformTrack() const;
+ BLINK_PLATFORM_EXPORT void SetPlatformTrack(
+ std::unique_ptr<WebPlatformMediaStreamTrack>);
// The lifetime of the WebAudioSourceProvider should outlive the
// WebMediaStreamTrack, and clients are responsible for calling
diff --git a/chromium/third_party/blink/public/platform/web_navigation_body_loader.h b/chromium/third_party/blink/public/platform/web_navigation_body_loader.h
new file mode 100644
index 00000000000..a79a666c35f
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/web_navigation_body_loader.h
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_NAVIGATION_BODY_LOADER_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_NAVIGATION_BODY_LOADER_H_
+
+#include <memory>
+
+#include "base/containers/span.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+
+namespace blink {
+
+// This class is used to load the body of main resource during navigation.
+// It is provided by the client which commits a navigation.
+// See WebNavigationParams for more details.
+class BLINK_EXPORT WebNavigationBodyLoader {
+ public:
+ class Client {
+ public:
+ virtual ~Client() {}
+
+ // Notifies about code cache if available. This method will
+ // be called zero or one time.
+ virtual void BodyCodeCacheReceived(base::span<const uint8_t>) = 0;
+
+ // Notifies about more data available. Called multiple times.
+ // If main resource is empty, can be not called at all.
+ virtual void BodyDataReceived(base::span<const char> data) = 0;
+
+ // Called once at the end. If something went wrong, |error| will be set.
+ // No more calls are issued after this one.
+ virtual void BodyLoadingFinished(
+ base::TimeTicks completion_time,
+ int64_t total_encoded_data_length,
+ int64_t total_encoded_body_length,
+ int64_t total_decoded_body_length,
+ bool should_report_corb_blocking,
+ const base::Optional<WebURLError>& error) = 0;
+ };
+
+ // It should be safe to destroy WebNavigationBodyLoader at any moment,
+ // including from inside any client notification.
+ virtual ~WebNavigationBodyLoader() {}
+
+ // While deferred, no more data will be read and no notifications
+ // will be called on the client. This method can be called
+ // multiples times, at any moment.
+ virtual void SetDefersLoading(bool defers) = 0;
+
+ // Starts loading the body. Client must be non-null, and will receive
+ // the body, code cache and final result.
+ virtual void StartLoadingBody(Client*, bool use_isolated_code_cache) = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_NAVIGATION_BODY_LOADER_H_
diff --git a/chromium/third_party/blink/public/platform/web_resource_timing_info.h b/chromium/third_party/blink/public/platform/web_resource_timing_info.h
index 84d7cd8a1fd..65e7f2912ad 100644
--- a/chromium/third_party/blink/public/platform/web_resource_timing_info.h
+++ b/chromium/third_party/blink/public/platform/web_resource_timing_info.h
@@ -17,7 +17,7 @@ namespace blink {
// The browser-side equivalent to this struct is content::ServerTimingInfo.
// TODO(dcheng): Migrate this struct over to Mojo so it doesn't need to be
-// duplicated in //content and //third_party/WebKit.
+// duplicated in //content and //third_party/blink.
struct WebServerTimingInfo {
WebServerTimingInfo(const WebString& name,
double duration,
@@ -34,7 +34,7 @@ struct WebServerTimingInfo {
// information about cross-process iframes for window.performance. The
// browser-side equivalent to this struct is content::ResourceTimingInfo.
// TODO(dcheng): Migrate this struct over to Mojo so it doesn't need to be
-// duplicated in //content and //third_party/WebKit.
+// duplicated in //content and //third_party/blink.
struct WebResourceTimingInfo {
// The name to associate with the performance entry. For iframes, this is
// typically the initial URL of the iframe resource.
@@ -53,6 +53,7 @@ struct WebResourceTimingInfo {
uint64_t decoded_body_size;
bool did_reuse_connection;
+ bool is_secure_context;
// TODO(dcheng): The way this code works is fairly confusing: it might seem
// unusual to store policy members like |allow_timing_details| inline, rather
diff --git a/chromium/third_party/blink/public/platform/web_rtc_certificate_generator.h b/chromium/third_party/blink/public/platform/web_rtc_certificate_generator.h
index f5940a3d908..7a9f11124a9 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_certificate_generator.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_certificate_generator.h
@@ -34,7 +34,7 @@
#include "third_party/blink/public/platform/web_callbacks.h"
#include "third_party/blink/public/platform/web_rtc_key_params.h"
#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
#include <memory>
diff --git a/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler.h b/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
index 361665509e0..815b7308191 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
@@ -31,13 +31,16 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_PEER_CONNECTION_HANDLER_H_
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_PEER_CONNECTION_HANDLER_H_
+#include <memory>
+#include <vector>
+
#include "third_party/blink/public/platform/web_rtc_ice_candidate.h"
#include "third_party/blink/public/platform/web_rtc_rtp_transceiver.h"
#include "third_party/blink/public/platform/web_rtc_stats.h"
#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
-#include "third_party/webrtc/api/rtcerror.h"
-#include "third_party/webrtc/api/rtptransceiverinterface.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
+#include "third_party/webrtc/api/rtc_error.h"
+#include "third_party/webrtc/api/rtp_transceiver_interface.h"
namespace webrtc {
enum class RTCErrorType;
@@ -67,10 +70,17 @@ class WebRTCPeerConnectionHandler {
const webrtc::PeerConnectionInterface::RTCConfiguration&,
const WebMediaConstraints&) = 0;
- virtual void CreateOffer(const WebRTCSessionDescriptionRequest&,
- const WebMediaConstraints&) = 0;
- virtual void CreateOffer(const WebRTCSessionDescriptionRequest&,
- const WebRTCOfferOptions&) = 0;
+ // Unified Plan: The list of transceivers after the createOffer() call.
+ // Because of offerToReceive[Audio/Video] it is possible for createOffer() to
+ // create new transceivers or update the direction of existing transceivers.
+ // https://w3c.github.io/webrtc-pc/#legacy-configuration-extensions
+ // Plan B: Returns an empty list.
+ virtual std::vector<std::unique_ptr<WebRTCRtpTransceiver>> CreateOffer(
+ const WebRTCSessionDescriptionRequest&,
+ const WebMediaConstraints&) = 0;
+ virtual std::vector<std::unique_ptr<WebRTCRtpTransceiver>> CreateOffer(
+ const WebRTCSessionDescriptionRequest&,
+ const WebRTCOfferOptions&) = 0;
virtual void CreateAnswer(const WebRTCSessionDescriptionRequest&,
const WebMediaConstraints&) = 0;
virtual void CreateAnswer(const WebRTCSessionDescriptionRequest&,
@@ -131,6 +141,9 @@ class WebRTCPeerConnectionHandler {
// Origin Trial - RtcPeerConnectionId
virtual WebString Id() const = 0;
+
+ // Returns a pointer to the underlying native PeerConnection object.
+ virtual webrtc::PeerConnectionInterface* NativePeerConnection() = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h b/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h
index 767dbf401c8..10940467d79 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h
@@ -35,7 +35,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
namespace blink {
diff --git a/chromium/third_party/blink/public/platform/web_rtc_rtp_contributing_source.h b/chromium/third_party/blink/public/platform/web_rtc_rtp_contributing_source.h
deleted file mode 100644
index 51d1575f7c4..00000000000
--- a/chromium/third_party/blink/public/platform/web_rtc_rtp_contributing_source.h
+++ /dev/null
@@ -1,29 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_CONTRIBUTING_SOURCE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_CONTRIBUTING_SOURCE_H_
-
-#include "third_party/blink/public/platform/web_common.h"
-
-namespace blink {
-
-enum class WebRTCRtpContributingSourceType {
- SSRC,
- CSRC,
-};
-
-// https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource
-class BLINK_PLATFORM_EXPORT WebRTCRtpContributingSource {
- public:
- virtual ~WebRTCRtpContributingSource();
-
- virtual WebRTCRtpContributingSourceType SourceType() const = 0;
- virtual double TimestampMs() const = 0;
- virtual uint32_t Source() const = 0;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_CONTRIBUTING_SOURCE_H_
diff --git a/chromium/third_party/blink/public/platform/web_rtc_rtp_receiver.h b/chromium/third_party/blink/public/platform/web_rtc_rtp_receiver.h
index 72bcd4bfe80..816c99509ad 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_rtp_receiver.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_rtp_receiver.h
@@ -10,11 +10,12 @@
#include "third_party/blink/public/platform/web_rtc_stats.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/webrtc/api/rtp_parameters.h"
namespace blink {
class WebMediaStreamTrack;
-class WebRTCRtpContributingSource;
+class WebRTCRtpSource;
// Implementations of this interface keep the corresponding WebRTC-layer
// receiver alive through reference counting. Multiple |WebRTCRtpReceiver|s
@@ -30,10 +31,10 @@ class BLINK_PLATFORM_EXPORT WebRTCRtpReceiver {
virtual uintptr_t Id() const = 0;
virtual const WebMediaStreamTrack& Track() const = 0;
virtual WebVector<WebString> StreamIds() const = 0;
- virtual WebVector<std::unique_ptr<WebRTCRtpContributingSource>>
- GetSources() = 0;
+ virtual WebVector<std::unique_ptr<WebRTCRtpSource>> GetSources() = 0;
virtual void GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>,
RTCStatsFilter) = 0;
+ virtual std::unique_ptr<webrtc::RtpParameters> GetParameters() const = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/web_rtc_rtp_sender.h b/chromium/third_party/blink/public/platform/web_rtc_rtp_sender.h
index f1112ff6d51..1be1836ac0a 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_rtp_sender.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_rtp_sender.h
@@ -9,7 +9,7 @@
#include "third_party/blink/public/platform/web_rtc_stats.h"
#include "third_party/blink/public/platform/web_rtc_void_request.h"
#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/webrtc/api/rtpparameters.h"
+#include "third_party/webrtc/api/rtp_parameters.h"
namespace blink {
diff --git a/chromium/third_party/blink/public/platform/web_rtc_rtp_source.h b/chromium/third_party/blink/public/platform/web_rtc_rtp_source.h
new file mode 100644
index 00000000000..57eb5bbaf93
--- /dev/null
+++ b/chromium/third_party/blink/public/platform/web_rtc_rtp_source.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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_SOURCE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_SOURCE_H_
+
+#include "base/optional.h"
+#include "third_party/blink/public/platform/web_common.h"
+
+namespace blink {
+
+// Represents both SSRCs and CSRCs.
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtpsynchronizationsource
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource
+class BLINK_PLATFORM_EXPORT WebRTCRtpSource {
+ public:
+ enum class Type {
+ kSSRC,
+ kCSRC,
+ };
+
+ virtual ~WebRTCRtpSource();
+
+ virtual Type SourceType() const = 0;
+ virtual double TimestampMs() const = 0;
+ virtual uint32_t Source() const = 0;
+ virtual base::Optional<double> AudioLevel() const = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_SOURCE_H_
diff --git a/chromium/third_party/blink/public/platform/web_rtc_rtp_transceiver.h b/chromium/third_party/blink/public/platform/web_rtc_rtp_transceiver.h
index 435c1fccb71..0ce9cdc7ad0 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_rtp_transceiver.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_rtp_transceiver.h
@@ -13,7 +13,7 @@
#include "third_party/blink/public/platform/web_rtc_rtp_receiver.h"
#include "third_party/blink/public/platform/web_rtc_rtp_sender.h"
#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/webrtc/api/rtptransceiverinterface.h"
+#include "third_party/webrtc/api/rtp_transceiver_interface.h"
namespace blink {
diff --git a/chromium/third_party/blink/public/platform/web_rtc_void_request.h b/chromium/third_party/blink/public/platform/web_rtc_void_request.h
index fdfdcd5493a..e4f37df14c7 100644
--- a/chromium/third_party/blink/public/platform/web_rtc_void_request.h
+++ b/chromium/third_party/blink/public/platform/web_rtc_void_request.h
@@ -34,7 +34,7 @@
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_private_ptr.h"
#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/webrtc/api/rtcerror.h"
+#include "third_party/webrtc/api/rtc_error.h"
namespace blink {
diff --git a/chromium/third_party/blink/public/platform/web_runtime_features.h b/chromium/third_party/blink/public/platform/web_runtime_features.h
index 5832c4dd38d..65a7715dfad 100644
--- a/chromium/third_party/blink/public/platform/web_runtime_features.h
+++ b/chromium/third_party/blink/public/platform/web_runtime_features.h
@@ -74,7 +74,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableOriginTrials(bool);
BLINK_PLATFORM_EXPORT static bool IsOriginTrialsEnabled();
- BLINK_PLATFORM_EXPORT static bool IsSlimmingPaintV2Enabled();
+ BLINK_PLATFORM_EXPORT static bool IsCompositeAfterPaintEnabled();
BLINK_PLATFORM_EXPORT static void EnableAccelerated2dCanvas(bool);
BLINK_PLATFORM_EXPORT static void EnableAccessibilityObjectModel(bool);
@@ -82,9 +82,6 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableAllowActivationDelegationAttr(bool);
BLINK_PLATFORM_EXPORT static void EnableAudioOutputDevices(bool);
BLINK_PLATFORM_EXPORT static void EnableBackgroundFetch(bool);
- BLINK_PLATFORM_EXPORT static void EnableBackgroundFetchAccessActiveFetches(
- bool);
- BLINK_PLATFORM_EXPORT static void EnableBackgroundFetchUploads(bool);
BLINK_PLATFORM_EXPORT static void EnableBlinkHeapIncrementalMarking(bool);
BLINK_PLATFORM_EXPORT static void EnableBlinkHeapUnifiedGarbageCollection(
bool);
@@ -96,6 +93,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableCSSHexAlphaColor(bool);
BLINK_PLATFORM_EXPORT static void EnableCSSFragmentIdentifiers(bool);
BLINK_PLATFORM_EXPORT static void EnableScrollTopLeftInterop(bool);
+ BLINK_PLATFORM_EXPORT static void EnableKeyboardFocusableScrollers(bool);
BLINK_PLATFORM_EXPORT static void EnableDatabase(bool);
BLINK_PLATFORM_EXPORT static void EnableDecodeToYUV(bool);
BLINK_PLATFORM_EXPORT static void EnableDisplayCutoutAPI(bool);
@@ -103,14 +101,14 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableFileSystem(bool);
BLINK_PLATFORM_EXPORT static void EnableFirstContentfulPaintPlusPlus(bool);
BLINK_PLATFORM_EXPORT static void EnableForceTallerSelectPopup(bool);
- BLINK_PLATFORM_EXPORT static void EnableGamepadExtensions(bool);
BLINK_PLATFORM_EXPORT static void EnableGamepadVibration(bool);
BLINK_PLATFORM_EXPORT static void EnableGenericSensor(bool);
BLINK_PLATFORM_EXPORT static void EnableGenericSensorExtraClasses(bool);
BLINK_PLATFORM_EXPORT static void EnableHeapCompaction(bool);
BLINK_PLATFORM_EXPORT static void EnableImplicitRootScroller(bool);
BLINK_PLATFORM_EXPORT static void EnableInputMultipleFieldsUI(bool);
- BLINK_PLATFORM_EXPORT static void EnableJankTracking(bool);
+ BLINK_PLATFORM_EXPORT static void EnableJankTracking(bool,
+ bool use_sweep_line);
BLINK_PLATFORM_EXPORT static void EnableLayeredAPI(bool);
BLINK_PLATFORM_EXPORT static void EnableLayoutNG(bool);
BLINK_PLATFORM_EXPORT static void EnableLazyFrameLoading(bool);
@@ -133,6 +131,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableOrientationEvent(bool);
BLINK_PLATFORM_EXPORT static void EnableOverflowIconsForMediaControls(bool);
BLINK_PLATFORM_EXPORT static void EnableOverlayScrollbars(bool);
+ BLINK_PLATFORM_EXPORT static void EnableOverscrollCustomization(bool);
BLINK_PLATFORM_EXPORT static void EnableOutOfBlinkCors(bool);
BLINK_PLATFORM_EXPORT static void EnablePageLifecycle(bool);
BLINK_PLATFORM_EXPORT static void EnablePagePopup(bool);
@@ -165,7 +164,6 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableSecMetadata(bool);
BLINK_PLATFORM_EXPORT static void EnableSharedArrayBuffer(bool);
BLINK_PLATFORM_EXPORT static void EnableSharedWorker(bool);
- BLINK_PLATFORM_EXPORT static void EnableSignedHTTPExchange(bool);
BLINK_PLATFORM_EXPORT static void EnableTouchEventFeatureDetection(bool);
BLINK_PLATFORM_EXPORT static void EnableUserActivationSameOriginVisibility(
bool);
@@ -174,6 +172,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableWebAuth(bool);
BLINK_PLATFORM_EXPORT static void EnableWebAuthGetTransports(bool);
BLINK_PLATFORM_EXPORT static void EnableWebBluetooth(bool);
+ BLINK_PLATFORM_EXPORT static void EnableWebBluetoothScanning(bool);
BLINK_PLATFORM_EXPORT static void EnableWebGL2ComputeContext(bool);
BLINK_PLATFORM_EXPORT static void EnableWebGLDraftExtensions(bool);
BLINK_PLATFORM_EXPORT static void EnableWebGLImageChromium(bool);
@@ -209,9 +208,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableLazyInitializeMediaControls(bool);
BLINK_PLATFORM_EXPORT static void EnableMediaEngagementBypassAutoplayPolicies(
bool);
- BLINK_PLATFORM_EXPORT static void EnableV8ContextSnapshot(bool);
BLINK_PLATFORM_EXPORT static void EnableAutomationControlled(bool);
- BLINK_PLATFORM_EXPORT static void EnableWorkStealingInScriptRunner(bool);
BLINK_PLATFORM_EXPORT static void EnableScheduledScriptStreaming(bool);
BLINK_PLATFORM_EXPORT static void EnableScriptStreamingOnPreload(bool);
BLINK_PLATFORM_EXPORT static void EnableExperimentalProductivityFeatures(
@@ -221,6 +218,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableTranslateService(bool);
BLINK_PLATFORM_EXPORT static void EnableMergeBlockingNonBlockingPools(bool);
BLINK_PLATFORM_EXPORT static void EnableGetDisplayMedia(bool);
+ BLINK_PLATFORM_EXPORT static void EnableForbidSyncXHRInPageDismissal(bool);
private:
WebRuntimeFeatures();
diff --git a/chromium/third_party/blink/public/platform/web_surface_layer_bridge.h b/chromium/third_party/blink/public/platform/web_surface_layer_bridge.h
index 91af2d4d858..fc65d1570dd 100644
--- a/chromium/third_party/blink/public/platform/web_surface_layer_bridge.h
+++ b/chromium/third_party/blink/public/platform/web_surface_layer_bridge.h
@@ -21,8 +21,10 @@ class BLINK_PLATFORM_EXPORT WebSurfaceLayerBridgeObserver {
// Triggered by resizing or surface layer creation.
virtual void OnWebLayerUpdated() = 0;
- // Called when new a SurfaceLayer is created.
+ // Called when a new contents cc layer is created.
virtual void RegisterContentsLayer(cc::Layer*) = 0;
+
+ // Called when a contents cc layer will be destroyed.
virtual void UnregisterContentsLayer(cc::Layer*) = 0;
// Called when a SurfaceLayer is activated.
@@ -41,9 +43,9 @@ class BLINK_PLATFORM_EXPORT WebSurfaceLayerBridge {
virtual const viz::FrameSinkId& GetFrameSinkId() const = 0;
virtual const viz::SurfaceId& GetSurfaceId() const = 0;
virtual base::TimeTicks GetLocalSurfaceIdAllocationTime() const = 0;
- virtual void ClearSurfaceId() = 0;
virtual void SetContentsOpaque(bool) = 0;
virtual void CreateSurfaceLayer() = 0;
+ virtual void ClearObserver() = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/web_url_load_timing.h b/chromium/third_party/blink/public/platform/web_url_load_timing.h
index 389a8c6f1bd..6aca8fa4118 100644
--- a/chromium/third_party/blink/public/platform/web_url_load_timing.h
+++ b/chromium/third_party/blink/public/platform/web_url_load_timing.h
@@ -45,7 +45,7 @@ class ResourceLoadTiming;
// The browser-side equivalent to this struct is content::ResourceLoadTiming.
// TODO(dcheng): Migrate this struct over to Mojo so it doesn't need to be
-// duplicated in //content and //third_party/WebKit.
+// duplicated in //content and //third_party/blink.
class WebURLLoadTiming {
public:
~WebURLLoadTiming() { Reset(); }
@@ -96,6 +96,9 @@ class WebURLLoadTiming {
BLINK_PLATFORM_EXPORT base::TimeTicks SendEnd() const;
BLINK_PLATFORM_EXPORT void SetSendEnd(base::TimeTicks);
+ BLINK_PLATFORM_EXPORT base::TimeTicks ReceiveHeadersStart() const;
+ BLINK_PLATFORM_EXPORT void SetReceiveHeadersStart(base::TimeTicks);
+
BLINK_PLATFORM_EXPORT base::TimeTicks ReceiveHeadersEnd() const;
BLINK_PLATFORM_EXPORT void SetReceiveHeadersEnd(base::TimeTicks);
diff --git a/chromium/third_party/blink/public/platform/web_url_loader_client.h b/chromium/third_party/blink/public/platform/web_url_loader_client.h
index 96991bd5446..de1a83b5c4d 100644
--- a/chromium/third_party/blink/public/platform/web_url_loader_client.h
+++ b/chromium/third_party/blink/public/platform/web_url_loader_client.h
@@ -32,6 +32,7 @@
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_URL_LOADER_CLIENT_H_
#include <memory>
+#include "base/callback.h"
#include "base/time/time.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "services/network/public/cpp/cors/preflight_timing_info.h"
@@ -58,6 +59,7 @@ class BLINK_PLATFORM_EXPORT WebURLLoaderClient {
virtual bool WillFollowRedirect(
const WebURL& new_url,
const WebURL& new_site_for_cookies,
+ const base::Optional<WebSecurityOrigin>& new_top_frame_origin,
const WebString& new_referrer,
network::mojom::ReferrerPolicy new_referrer_policy,
const WebString& new_method,
@@ -123,6 +125,14 @@ class BLINK_PLATFORM_EXPORT WebURLLoaderClient {
int64_t total_encoded_body_length,
int64_t total_decoded_body_length) {}
+ // This is a callback set for navigation requests, which should be called
+ // to continue the navigation after starting the main resource request.
+ // This is a workaround for using WebURLLoader machinery for navigation
+ // requests which did already happen in the browser process.
+ // TODO(dgozman): remove this once we no longer use WebURLLoader for
+ // the main resource and instead pass the data directly to CommitNavigation.
+ virtual void SetContinueNavigationRequestCallback(base::OnceClosure) {}
+
// Value passed to DidFinishLoading when total encoded data length isn't
// known.
static const int64_t kUnknownEncodedDataLength = -1;
diff --git a/chromium/third_party/blink/public/platform/web_url_request.h b/chromium/third_party/blink/public/platform/web_url_request.h
index c19a945016d..771bfd0c4c3 100644
--- a/chromium/third_party/blink/public/platform/web_url_request.h
+++ b/chromium/third_party/blink/public/platform/web_url_request.h
@@ -36,7 +36,7 @@
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
namespace network {
@@ -61,7 +61,6 @@ class WebHTTPHeaderVisitor;
class WebSecurityOrigin;
class WebString;
class WebURL;
-struct WebContentSecurityPolicyList;
class WebURLRequest {
public:
@@ -130,6 +129,10 @@ class WebURLRequest {
BLINK_PLATFORM_EXPORT WebURL SiteForCookies() const;
BLINK_PLATFORM_EXPORT void SetSiteForCookies(const WebURL&);
+ BLINK_PLATFORM_EXPORT base::Optional<WebSecurityOrigin> TopFrameOrigin()
+ const;
+ BLINK_PLATFORM_EXPORT void SetTopFrameOrigin(const WebSecurityOrigin&);
+
// https://fetch.spec.whatwg.org/#concept-request-origin
BLINK_PLATFORM_EXPORT WebSecurityOrigin RequestorOrigin() const;
BLINK_PLATFORM_EXPORT void SetRequestorOrigin(const WebSecurityOrigin&);
@@ -287,8 +290,6 @@ class WebURLRequest {
BLINK_PLATFORM_EXPORT network::mojom::CorsPreflightPolicy
GetCorsPreflightPolicy() const;
- BLINK_PLATFORM_EXPORT void SetNavigationStartTime(base::TimeTicks);
-
// If this request was created from an anchor with a download attribute, this
// is the value provided there.
BLINK_PLATFORM_EXPORT base::Optional<WebString> GetSuggestedFilename() const;
@@ -297,11 +298,6 @@ class WebURLRequest {
// heuristics so it is not expected to be 100% accurate.
BLINK_PLATFORM_EXPORT bool IsAdResource() const;
- // This is the navigation relevant CSP to be used during request and response
- // checks.
- BLINK_PLATFORM_EXPORT const WebContentSecurityPolicyList& GetInitiatorCSP()
- const;
-
// Should be set to true if this request (including redirects) should be
// upgraded to HTTPS due to an Upgrade-Insecure-Requests requirement.
BLINK_PLATFORM_EXPORT void SetUpgradeIfInsecure(bool);
diff --git a/chromium/third_party/blink/public/platform/web_url_response.h b/chromium/third_party/blink/public/platform/web_url_response.h
index 490b030d3dc..07a284aac8f 100644
--- a/chromium/third_party/blink/public/platform/web_url_response.h
+++ b/chromium/third_party/blink/public/platform/web_url_response.h
@@ -37,7 +37,7 @@
#include "net/cert/ct_policy_status.h"
#include "net/http/http_response_info.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_security_style.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -138,22 +138,31 @@ class WebURLResponse {
SignedCertificateTimestampList sct_list;
};
- class ExtraData {
- public:
- virtual ~ExtraData() = default;
- };
-
BLINK_PLATFORM_EXPORT ~WebURLResponse();
BLINK_PLATFORM_EXPORT WebURLResponse();
BLINK_PLATFORM_EXPORT WebURLResponse(const WebURLResponse&);
- BLINK_PLATFORM_EXPORT explicit WebURLResponse(const WebURL&);
+ BLINK_PLATFORM_EXPORT explicit WebURLResponse(
+ const WebURL& current_request_url);
BLINK_PLATFORM_EXPORT WebURLResponse& operator=(const WebURLResponse&);
BLINK_PLATFORM_EXPORT bool IsNull() const;
- BLINK_PLATFORM_EXPORT WebURL Url() const;
- BLINK_PLATFORM_EXPORT void SetURL(const WebURL&);
+ // The current request URL for this resource (the URL after redirects).
+ // Corresponds to:
+ // https://fetch.spec.whatwg.org/#concept-request-current-url
+ //
+ // It is usually wrong to use this for security checks. See detailed
+ // documentation at blink::ResourceResponse::CurrentRequestUrl().
+ BLINK_PLATFORM_EXPORT WebURL CurrentRequestUrl() const;
+ BLINK_PLATFORM_EXPORT void SetCurrentRequestUrl(const WebURL&);
+
+ // The response URL of this resource. Corresponds to:
+ // https://fetch.spec.whatwg.org/#concept-response-url
+ //
+ // This may be the empty URL. See detailed documentation at
+ // blink::ResourceResponse::ResponseUrl().
+ BLINK_PLATFORM_EXPORT WebURL ResponseUrl() const;
BLINK_PLATFORM_EXPORT void SetConnectionID(unsigned);
@@ -242,15 +251,8 @@ class WebURLResponse {
// for details.
BLINK_PLATFORM_EXPORT void SetURLListViaServiceWorker(
const WebVector<WebURL>&);
-
- // Returns the last URL of the URL list of the Response object the
- // ServiceWorker passed to respondWith() if it did. Otherwise returns an empty
- // URL.
- BLINK_PLATFORM_EXPORT WebURL OriginalURLViaServiceWorker() const;
-
- // The boundary of the response. Set only when this is a multipart response.
- BLINK_PLATFORM_EXPORT void SetMultipartBoundary(const char* bytes,
- size_t /* size */);
+ // Returns true if the URL list is not empty.
+ BLINK_PLATFORM_EXPORT bool HasUrlListViaServiceWorker() const;
// The cache name of the CacheStorage from where the response is served via
// the ServiceWorker. Null if the response isn't from the CacheStorage.
@@ -290,17 +292,6 @@ class WebURLResponse {
BLINK_PLATFORM_EXPORT void SetIsSignedExchangeInnerResponse(bool);
- // Extra data associated with the underlying resource response. Resource
- // responses can be copied. If non-null, each copy of a resource response
- // holds a pointer to the extra data, and the extra data pointer will be
- // deleted when the last resource response is destroyed. Setting the extra
- // data pointer will cause the underlying resource response to be
- // dissociated from any existing non-null extra data pointer.
- BLINK_PLATFORM_EXPORT ExtraData* GetExtraData() const;
- BLINK_PLATFORM_EXPORT void SetExtraData(ExtraData*);
-
- BLINK_PLATFORM_EXPORT void AppendRedirectResponse(const WebURLResponse&);
-
#if INSIDE_BLINK
protected:
// Permit subclasses to set arbitrary ResourceResponse pointer as
diff --git a/chromium/third_party/blink/public/platform/web_video_frame_submitter.h b/chromium/third_party/blink/public/platform/web_video_frame_submitter.h
index 94bc7a5543c..75b50514431 100644
--- a/chromium/third_party/blink/public/platform/web_video_frame_submitter.h
+++ b/chromium/third_party/blink/public/platform/web_video_frame_submitter.h
@@ -26,12 +26,12 @@ namespace blink {
// Sets the proper context_provider and compositing mode onto the Submitter.
using WebSubmitterConfigurationCallback =
base::OnceCallback<void(bool, scoped_refptr<viz::ContextProvider>)>;
+
// Callback to obtain the media ContextProvider and a bool indicating whether
// we are in software compositing mode.
using WebContextProviderCallback =
base::RepeatingCallback<void(scoped_refptr<viz::ContextProvider>,
WebSubmitterConfigurationCallback)>;
-using WebFrameSinkDestroyedCallback = base::RepeatingCallback<void()>;
// Exposes the VideoFrameSubmitter, which submits CompositorFrames containing
// decoded VideoFrames from the VideoFrameProvider to the compositor for
@@ -50,22 +50,22 @@ class BLINK_PLATFORM_EXPORT WebVideoFrameSubmitter
virtual void Initialize(cc::VideoFrameProvider*) = 0;
// Set the rotation state of the video to be used while appending frames.
+ //
+ // TODO(dalecurtis): This could be removed in favor of getting it from each
+ // VideoFrame, but today that information isn't set everywhere.
virtual void SetRotation(media::VideoRotation) = 0;
- // Set if the video is opaque or not.
- virtual void SetIsOpaque(bool) = 0;
-
// Prepares the compositor frame sink to accept frames by providing
- // a SurfaceId, with its associated allocation time. The callback is to be
- // used when on context loss to prevent the submitter from continuing to
- // submit frames with invalid resources.
- virtual void EnableSubmission(viz::SurfaceId,
- base::TimeTicks,
- WebFrameSinkDestroyedCallback) = 0;
-
- // Updates whether we should submit frames or not based on whether the video
- // is visible on screen.
- virtual void UpdateSubmissionState(bool) = 0;
+ // a SurfaceId, with its associated allocation time.
+ virtual void EnableSubmission(viz::SurfaceId, base::TimeTicks) = 0;
+
+ // Set whether the surface is visible within the current view port. Stops
+ // submission if not unless SetForceSubmit(true) has been called.
+ virtual void SetIsSurfaceVisible(bool) = 0;
+
+ // Set whether the page containing the video element is visible. Stops
+ // submission if not unless SetForceSubmit(true) has been called.
+ virtual void SetIsPageVisible(bool) = 0;
// Set whether frames should always be submitted regardless of visibility.
virtual void SetForceSubmit(bool) = 0;
diff --git a/chromium/third_party/blink/public/platform/web_worker_fetch_context.h b/chromium/third_party/blink/public/platform/web_worker_fetch_context.h
index 1c6c2def226..7ba05c74ec4 100644
--- a/chromium/third_party/blink/public/platform/web_worker_fetch_context.h
+++ b/chromium/third_party/blink/public/platform/web_worker_fetch_context.h
@@ -14,6 +14,7 @@
#include "third_party/blink/public/platform/web_application_cache_host.h"
#include "third_party/blink/public/platform/web_document_subresource_filter.h"
#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/public/platform/websocket_handshake_throttle.h"
@@ -27,6 +28,13 @@ namespace blink {
class WebURLRequest;
class WebDocumentSubresourceFilter;
+// Helper class allowing WebWorkerFetchContextImpl to notify blink upon an
+// accept languages update. This class will be extended by WorkerNavigator.
+class AcceptLanguagesWatcher {
+ public:
+ virtual void NotifyUpdate() = 0;
+};
+
// WebWorkerFetchContext is a per-worker object created on the main thread,
// passed to a worker (dedicated, shared and service worker) and initialized on
// the worker thread by InitializeOnWorkerThread(). It contains information
@@ -58,7 +66,7 @@ class WebWorkerFetchContext : public base::RefCounted<WebWorkerFetchContext> {
// pointer is valid throughout the lifetime of this context.
virtual void SetTerminateSyncLoadEvent(base::WaitableEvent*) = 0;
- virtual void InitializeOnWorkerThread() = 0;
+ virtual void InitializeOnWorkerThread(AcceptLanguagesWatcher*) = 0;
// Returns a WebURLLoaderFactory which is associated with the worker context.
// The returned WebURLLoaderFactory is owned by |this|.
@@ -110,9 +118,6 @@ class WebWorkerFetchContext : public base::RefCounted<WebWorkerFetchContext> {
const WebURL& insecure_url) {}
virtual void SetApplicationCacheHostID(int id) {}
- virtual int ApplicationCacheHostID() const {
- return WebApplicationCacheHost::kAppCacheNoHostId;
- }
// Sets the builder object of WebDocumentSubresourceFilter on the main thread
// which will be used in TakeSubresourceFilter() to create a
@@ -133,6 +138,9 @@ class WebWorkerFetchContext : public base::RefCounted<WebWorkerFetchContext> {
CreateWebSocketHandshakeThrottle() {
return nullptr;
}
+
+ // Returns the current list of user prefered languages.
+ virtual blink::WebString GetAcceptLanguages() const = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/public_typemaps.gni b/chromium/third_party/blink/public/public_typemaps.gni
index d59930b8015..b5f261fd7bb 100644
--- a/chromium/third_party/blink/public/public_typemaps.gni
+++ b/chromium/third_party/blink/public/public_typemaps.gni
@@ -4,11 +4,13 @@
# These are typemaps which are exposed by Blink to its embedder.
typemaps = [
- "//third_party/blink/public/platform/content_security_policy.typemap",
+ "//third_party/blink/public/common/fetch/fetch_api_request_headers.typemap",
"//third_party/blink/public/common/indexeddb/indexed_db_default.typemap",
+ "//third_party/blink/public/common/loader/url_loader_factory_bundle.typemap",
"//third_party/blink/public/common/manifest/display_mode.typemap",
"//third_party/blink/public/common/manifest/manifest.typemap",
+ "//third_party/blink/public/common/mediastream/media_devices.typemap",
+ "//third_party/blink/public/common/mediastream/media_stream.typemap",
"//third_party/blink/public/common/notifications/notification_types.typemap",
"//third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap",
- "//third_party/blink/public/web/console_message.typemap",
]
diff --git a/chromium/third_party/blink/public/web/DEPS b/chromium/third_party/blink/public/web/DEPS
index 6d1ee56973c..1169ede7c5b 100644
--- a/chromium/third_party/blink/public/web/DEPS
+++ b/chromium/third_party/blink/public/web/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+base/callback.h",
+ "+base/containers/span.h",
"+base/files/file_path.h",
"+base/optional.h",
"+base/macros.h",
@@ -10,6 +11,7 @@ include_rules = [
"+cc/input/browser_controls_state.h",
"+cc/paint/paint_canvas.h",
"+cc/paint/paint_flags.h",
+ "+cc/trees/element_id.h",
"+mojo/public",
"+services/network/public/mojom/cors.mojom-shared.h",
"+services/network/public/mojom/cors_origin_pattern.mojom-shared.h",
diff --git a/chromium/third_party/blink/public/web/blink.h b/chromium/third_party/blink/public/web/blink.h
index d2551617885..a15ea060fce 100644
--- a/chromium/third_party/blink/public/web/blink.h
+++ b/chromium/third_party/blink/public/web/blink.h
@@ -65,14 +65,14 @@ BLINK_EXPORT void CreateMainThreadAndInitialize(
BLINK_EXPORT v8::Isolate* MainThreadIsolate();
// Alters the rendering of content to conform to a fixed set of rules.
-BLINK_EXPORT void SetLayoutTestMode(bool);
-BLINK_EXPORT bool LayoutTestMode();
+BLINK_EXPORT void SetWebTestMode(bool);
+BLINK_EXPORT bool WebTestMode();
-// Enables or disables the use of the mock theme for layout tests. This function
-// must be called only if setLayoutTestMode(true).
+// Enables or disables the use of the mock theme for web tests. This function
+// must be called only if SetWebTestMode(true).
BLINK_EXPORT void SetMockThemeEnabledForTest(bool);
-// Alters the rendering of fonts for layout tests.
+// Alters the rendering of fonts for web tests.
BLINK_EXPORT void SetFontAntialiasingEnabledForTest(bool);
BLINK_EXPORT bool FontAntialiasingEnabledForTest();
diff --git a/chromium/third_party/blink/public/web/console_message.mojom b/chromium/third_party/blink/public/web/console_message.mojom
deleted file mode 100644
index e7bdebd9443..00000000000
--- a/chromium/third_party/blink/public/web/console_message.mojom
+++ /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.
-
-module blink.mojom;
-
-// Mojom representation of blink::WebConsoleMessage.
-// The values and the order are the same with blink::WebConsoleMessage::Level.
-enum ConsoleMessageLevel {
- Verbose,
- Info,
- Warning,
- Error
-};
diff --git a/chromium/third_party/blink/public/web/console_message.typemap b/chromium/third_party/blink/public/web/console_message.typemap
deleted file mode 100644
index a35e044dada..00000000000
--- a/chromium/third_party/blink/public/web/console_message.typemap
+++ /dev/null
@@ -1,13 +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.
-
-mojom = "//third_party/blink/public/web/console_message.mojom"
-public_headers = [ "//third_party/blink/public/web/web_console_message.h" ]
-traits_headers =
- [ "//third_party/blink/public/web/console_message_struct_traits.h" ]
-deps = [
- "//third_party/blink/public:shared_typemap_traits",
-]
-type_mappings =
- [ "blink.mojom.ConsoleMessageLevel=::blink::WebConsoleMessage::Level" ]
diff --git a/chromium/third_party/blink/public/web/console_message_struct_traits.cc b/chromium/third_party/blink/public/web/console_message_struct_traits.cc
deleted file mode 100644
index a5b5a37a9fb..00000000000
--- a/chromium/third_party/blink/public/web/console_message_struct_traits.cc
+++ /dev/null
@@ -1,43 +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 "third_party/blink/public/web/console_message_struct_traits.h"
-
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace mojo {
-
-// Ensure that the WebConsoleMessage::Level enum values stay in sync with the
-// mojom::ConsoleMessageLevel.
-#define STATIC_ASSERT_ENUM(a, b) \
- static_assert(static_cast<int>(a) == static_cast<int>(b), \
- "mismatching enum : " #a)
-
-STATIC_ASSERT_ENUM(::blink::WebConsoleMessage::Level::kLevelVerbose,
- ::blink::mojom::ConsoleMessageLevel::Verbose);
-STATIC_ASSERT_ENUM(::blink::WebConsoleMessage::Level::kLevelInfo,
- ::blink::mojom::ConsoleMessageLevel::Info);
-STATIC_ASSERT_ENUM(::blink::WebConsoleMessage::Level::kLevelWarning,
- ::blink::mojom::ConsoleMessageLevel::Warning);
-STATIC_ASSERT_ENUM(::blink::WebConsoleMessage::Level::kLevelError,
- ::blink::mojom::ConsoleMessageLevel::Error);
-
-// static
-::blink::mojom::ConsoleMessageLevel
-EnumTraits<::blink::mojom::ConsoleMessageLevel,
- ::blink::WebConsoleMessage::Level>::
- ToMojom(::blink::WebConsoleMessage::Level level) {
- return static_cast<::blink::mojom::ConsoleMessageLevel>(level);
-}
-
-// static
-bool EnumTraits<::blink::mojom::ConsoleMessageLevel,
- ::blink::WebConsoleMessage::Level>::
- FromMojom(::blink::mojom::ConsoleMessageLevel in,
- ::blink::WebConsoleMessage::Level* out) {
- *out = static_cast<::blink::WebConsoleMessage::Level>(in);
- return true;
-}
-
-} // namespace mojo
diff --git a/chromium/third_party/blink/public/web/console_message_struct_traits.h b/chromium/third_party/blink/public/web/console_message_struct_traits.h
deleted file mode 100644
index 1d1f5a4f4bb..00000000000
--- a/chromium/third_party/blink/public/web/console_message_struct_traits.h
+++ /dev/null
@@ -1,25 +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 THIRD_PARTY_BLINK_PUBLIC_WEB_CONSOLE_MESSAGE_STRUCT_TRAITS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_WEB_CONSOLE_MESSAGE_STRUCT_TRAITS_H_
-
-#include "mojo/public/cpp/bindings/enum_traits.h"
-#include "third_party/blink/public/web/console_message.mojom-shared.h"
-#include "third_party/blink/public/web/web_console_message.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<::blink::mojom::ConsoleMessageLevel,
- ::blink::WebConsoleMessage::Level> {
- static ::blink::mojom::ConsoleMessageLevel ToMojom(
- ::blink::WebConsoleMessage::Level);
- static bool FromMojom(::blink::mojom::ConsoleMessageLevel,
- ::blink::WebConsoleMessage::Level* out);
-};
-
-} // namespace mojo
-
-#endif
diff --git a/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index da9863c746a..732f4239164 100644
--- a/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -270,6 +270,16 @@ class WebServiceWorkerContextClient {
CreateServiceWorkerFetchContext(WebServiceWorkerNetworkProvider*) {
return nullptr;
}
+
+ // Called when a task is going to be scheduled on the service worker.
+ // The service worker shouldn't request to be terminated until the task is
+ // finished. Returns an id for the task. The caller must call DidEndTask()
+ // with the returned id to notify that the task is finished.
+ virtual int WillStartTask() { return -1; }
+
+ // Called when a task is finished. |task_id| must be a return value of
+ // WillStartTask().
+ virtual void DidEndTask(int task_id) {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
index 3e1026f9f9c..2bb2c56fb16 100644
--- a/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
+++ b/chromium/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -34,7 +34,7 @@
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "third_party/blink/public/common/messaging/transferable_message.h"
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-shared.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-shared.h"
#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
#include "third_party/blink/public/platform/web_canonical_cookie.h"
diff --git a/chromium/third_party/blink/public/web/web_associated_url_loader_client.h b/chromium/third_party/blink/public/web/web_associated_url_loader_client.h
index f77e851e1e9..669fca664f2 100644
--- a/chromium/third_party/blink/public/web/web_associated_url_loader_client.h
+++ b/chromium/third_party/blink/public/web/web_associated_url_loader_client.h
@@ -20,7 +20,7 @@ class WebAssociatedURLLoaderClient {
virtual void DidSendData(unsigned long long bytes_sent,
unsigned long long total_bytes_to_be_sent) {}
virtual void DidReceiveResponse(const WebURLResponse&) {}
- virtual void DidDownloadData(int data_length) {}
+ virtual void DidDownloadData(unsigned long long data_length) {}
virtual void DidReceiveData(const char* data, int data_length) {}
virtual void DidReceiveCachedMetadata(const char* data, int data_length) {}
virtual void DidFinishLoading() {}
diff --git a/chromium/third_party/blink/public/web/web_ax_object.h b/chromium/third_party/blink/public/web/web_ax_object.h
index 58d439ea7cf..7dee9992eb1 100644
--- a/chromium/third_party/blink/public/web/web_ax_object.h
+++ b/chromium/third_party/blink/public/web/web_ax_object.h
@@ -159,6 +159,7 @@ class WebAXObject {
BLINK_EXPORT WebString FontFamily() const;
BLINK_EXPORT float FontSize() const;
BLINK_EXPORT bool CanvasHasFallbackContent() const;
+ BLINK_EXPORT WebAXObject ErrorMessage() const;
// If this is an image, returns the image (scaled to maxSize) as a data url.
BLINK_EXPORT WebString ImageDataUrl(const WebSize& max_size) const;
BLINK_EXPORT WebAXRestriction Restriction() const;
diff --git a/chromium/third_party/blink/public/web/web_console_message.h b/chromium/third_party/blink/public/web/web_console_message.h
index 89933a057d7..dff8bae6723 100644
--- a/chromium/third_party/blink/public/web/web_console_message.h
+++ b/chromium/third_party/blink/public/web/web_console_message.h
@@ -31,39 +31,28 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_CONSOLE_MESSAGE_H_
#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_CONSOLE_MESSAGE_H_
+#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_node.h"
namespace blink {
struct WebConsoleMessage {
- enum Level {
- kLevelVerbose,
- kLevelInfo,
- kLevelWarning,
- kLevelError,
- kLevelLast = kLevelError
- };
-
- Level level;
+ mojom::ConsoleMessageLevel level = mojom::ConsoleMessageLevel::kInfo;
WebString text;
WebVector<blink::WebNode> nodes;
WebString url;
- unsigned line_number;
- unsigned column_number;
+ unsigned line_number = 0;
+ unsigned column_number = 0;
- WebConsoleMessage() : level(kLevelInfo), line_number(0), column_number(0) {}
- WebConsoleMessage(Level level,
+ WebConsoleMessage() = default;
+ WebConsoleMessage(mojom::ConsoleMessageLevel level,
const WebString& text,
const WebVector<blink::WebNode>& nodes)
- : level(level),
- text(text),
- nodes(nodes),
- line_number(0),
- column_number(0) {}
- WebConsoleMessage(Level level, const WebString& text)
+ : level(level), text(text), nodes(nodes) {}
+ WebConsoleMessage(mojom::ConsoleMessageLevel level, const WebString& text)
: WebConsoleMessage(level, text, WebVector<blink::WebNode>()) {}
- WebConsoleMessage(Level level,
+ WebConsoleMessage(mojom::ConsoleMessageLevel level,
const WebString& text,
const WebString url,
unsigned line_number,
diff --git a/chromium/third_party/blink/public/web/web_document.h b/chromium/third_party/blink/public/web/web_document.h
index b92d57ac2b7..6ab2d5c458b 100644
--- a/chromium/third_party/blink/public/web/web_document.h
+++ b/chromium/third_party/blink/public/web/web_document.h
@@ -95,13 +95,7 @@ class WebDocument : public WebNode {
BLINK_EXPORT WebElement Body() const;
BLINK_EXPORT WebElement Head();
BLINK_EXPORT WebString Title() const;
-
- // |use_inner_text| controls which implementation to use for text dump,
- // spec-conformant Element.innerText or legacy, to help progressive
- // rebaseline of layout test text dumps.
- // TODO(xiaochengh): Remove this flag when rebaseline is complete.
- BLINK_EXPORT WebString ContentAsTextForTesting(bool use_inner_text) const;
-
+ BLINK_EXPORT WebString ContentAsTextForTesting() const;
BLINK_EXPORT WebElementCollection All();
BLINK_EXPORT void Forms(WebVector<WebFormElement>&) const;
BLINK_EXPORT WebURL CompleteURL(const WebString&) const;
diff --git a/chromium/third_party/blink/public/web/web_document_loader.h b/chromium/third_party/blink/public/web/web_document_loader.h
index b11eb4d45b2..2cffdc89c3e 100644
--- a/chromium/third_party/blink/public/web/web_document_loader.h
+++ b/chromium/third_party/blink/public/web/web_document_loader.h
@@ -34,6 +34,7 @@
#include <memory>
#include "base/time/time.h"
+#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "third_party/blink/public/platform/web_archive_info.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_source_location.h"
@@ -50,6 +51,10 @@ class WebURLResponse;
template <typename T>
class WebVector;
+namespace mojom {
+enum class FetchCacheMode : int32_t;
+} // namespace mojom
+
// An interface to expose the blink::DocumentLoader to the content layer,
// including SetExtraData() and GetExtraData() to allow the content layer to
// store data that isn't relevant to Blink.
@@ -60,8 +65,29 @@ class BLINK_EXPORT WebDocumentLoader {
virtual ~ExtraData() = default;
};
- // Returns the original request that resulted in this datasource.
- virtual const WebURLRequest& OriginalRequest() const = 0;
+ static bool WillLoadUrlAsEmpty(const WebURL&);
+
+ // Returns the url of original request which initited this load.
+ virtual WebURL OriginalUrl() const = 0;
+
+ // Returns the http referrer of original request which initited this load.
+ virtual WebString OriginalReferrer() const = 0;
+
+ // Returns the url corresponding to this load. It may also be a url
+ // specified by a redirect that was followed.
+ virtual WebURL GetUrl() const = 0;
+
+ // Returns the http method of the request corresponding to this load.
+ virtual WebString HttpMethod() const = 0;
+
+ // Returns the cache mode of the request corresponding to this load.
+ virtual mojom::FetchCacheMode GetCacheMode() const = 0;
+
+ // Returns the http referrer of the request corresponding to this load.
+ virtual WebString Referrer() const = 0;
+
+ // Returns the referrer policy of the request corresponding to this load.
+ virtual network::mojom::ReferrerPolicy GetReferrerPolicy() const = 0;
// Returns the request corresponding to this datasource. It may
// include additional request headers added by WebKit that were not
@@ -119,8 +145,6 @@ class BLINK_EXPORT WebDocumentLoader {
virtual WebServiceWorkerNetworkProvider*
GetServiceWorkerNetworkProvider() = 0;
- virtual void ResetSourceLocation() = 0;
-
// Can be used to temporarily suspend feeding the parser with new data. The
// parser will be allowed to read new data when ResumeParser() is called the
// same number of time than BlockParser().
@@ -136,6 +160,9 @@ class BLINK_EXPORT WebDocumentLoader {
// Whether this load was started with a user gesture.
virtual bool HadUserGesture() const = 0;
+ // Returns true when the document is a FTP directory.
+ virtual bool IsListingFtpDirectory() const = 0;
+
protected:
~WebDocumentLoader() = default;
};
diff --git a/chromium/third_party/blink/public/web/web_frame.h b/chromium/third_party/blink/public/web/web_frame.h
index 607229a45f8..188e2075bce 100644
--- a/chromium/third_party/blink/public/web/web_frame.h
+++ b/chromium/third_party/blink/public/web/web_frame.h
@@ -144,7 +144,7 @@ class BLINK_EXPORT WebFrame {
void SetOpener(WebFrame*);
// Reset the frame that opened this frame to 0.
- // This is executed between layout tests runs
+ // This is executed between web tests runs
void ClearOpener();
// Returns the parent frame or 0 if this is a top-most frame.
diff --git a/chromium/third_party/blink/public/web/web_frame_content_dumper.h b/chromium/third_party/blink/public/web/web_frame_content_dumper.h
index 5b697ed35e1..ba01602c87a 100644
--- a/chromium/third_party/blink/public/web/web_frame_content_dumper.h
+++ b/chromium/third_party/blink/public/web/web_frame_content_dumper.h
@@ -49,7 +49,7 @@ class WebFrameContentDumper {
BLINK_EXPORT static WebString DumpAsMarkup(WebLocalFrame*);
// Returns a text representation of the render tree. This method is used
- // to support layout tests.
+ // to support web tests.
BLINK_EXPORT static WebString DumpLayoutTreeAsText(
WebLocalFrame*,
LayoutAsTextControls to_show = kLayoutAsTextNormal);
diff --git a/chromium/third_party/blink/public/web/web_frame_widget.h b/chromium/third_party/blink/public/web/web_frame_widget.h
index 41d2efaf9bd..bbc30ef1130 100644
--- a/chromium/third_party/blink/public/web/web_frame_widget.h
+++ b/chromium/third_party/blink/public/web/web_frame_widget.h
@@ -31,7 +31,6 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_FRAME_WIDGET_H_
#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_FRAME_WIDGET_H_
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_drag_operation.h"
#include "third_party/blink/public/platform/web_touch_action.h"
@@ -58,24 +57,6 @@ class WebFrameWidget : public WebWidget {
WebWidgetClient*,
WebLocalFrame* local_root);
- // Overrides the WebFrameWidget's background and base background color. You
- // can use this to enforce a transparent background, which is useful if you
- // want to have some custom background rendered behind the widget.
- virtual void SetBackgroundColorOverride(SkColor) = 0;
- virtual void ClearBackgroundColorOverride() = 0;
- virtual void SetBaseBackgroundColorOverride(SkColor) = 0;
- virtual void ClearBaseBackgroundColorOverride() = 0;
-
- // Sets the base color used for this WebFrameWidget's background. This is in
- // effect the default background color used for pages with no
- // background-color style in effect, or used as the alpha-blended basis for
- // any pages with translucent background-color style. (For pages with opaque
- // background-color style, this property is effectively ignored).
- // Setting this takes effect for the currently loaded page, if any, and
- // persists across subsequent navigations. Defaults to white prior to the
- // first call to this method.
- virtual void SetBaseBackgroundColor(SkColor) = 0;
-
// Returns the local root of this WebFrameWidget.
virtual WebLocalFrame* LocalRoot() const = 0;
@@ -147,6 +128,10 @@ class WebFrameWidget : public WebWidget {
// inside) this widget into view. The scrolling might end with a final zooming
// into the editable region which is performed in the main frame process.
virtual bool ScrollFocusedEditableElementIntoView() = 0;
+
+ // This function provides zooming for find in page results when browsing with
+ // page autosize.
+ virtual void ZoomToFindInPageRect(const WebRect& rect_in_root_frame) = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/web/web_local_frame.h b/chromium/third_party/blink/public/web/web_local_frame.h
index 4b680e1b99e..0c72c57ac76 100644
--- a/chromium/third_party/blink/public/web/web_local_frame.h
+++ b/chromium/third_party/blink/public/web/web_local_frame.h
@@ -12,7 +12,8 @@
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/frame/sandbox_flags.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/ad_tagging/ad_frame.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_focus_type.h"
#include "third_party/blink/public/platform/web_size.h"
@@ -45,7 +46,6 @@ class WebPerformance;
class WebRange;
class WebSecurityOrigin;
class WebScriptExecutionCallback;
-class WebSharedWorkerRepositoryClient;
class WebSpellCheckPanelHostClient;
class WebString;
class WebTextCheckClient;
@@ -55,6 +55,7 @@ enum class WebTreeScopeType;
struct WebAssociatedURLLoaderOptions;
struct WebConsoleMessage;
struct WebContentSecurityPolicyViolation;
+struct WebIsolatedWorldInfo;
struct WebMediaPlayerAction;
struct WebPoint;
struct WebPrintParams;
@@ -77,6 +78,7 @@ class WebLocalFrame : public WebFrame {
WebView*,
WebLocalFrameClient*,
blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebFrame* opener = nullptr,
const WebString& name = WebString(),
WebSandboxFlags = WebSandboxFlags::kNone);
@@ -101,6 +103,7 @@ class WebLocalFrame : public WebFrame {
BLINK_EXPORT static WebLocalFrame* CreateProvisional(
WebLocalFrameClient*,
blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebRemoteFrame*,
WebSandboxFlags,
ParsedFeaturePolicy);
@@ -110,7 +113,8 @@ class WebLocalFrame : public WebFrame {
// it's no longer needed.
virtual WebLocalFrame* CreateLocalChild(WebTreeScopeType,
WebLocalFrameClient*,
- blink::InterfaceRegistry*) = 0;
+ blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle) = 0;
// Returns the WebFrame associated with the current V8 context. This
// function can return 0 if the context is associated with a Document that
@@ -132,8 +136,6 @@ class WebLocalFrame : public WebFrame {
virtual void SetAutofillClient(WebAutofillClient*) = 0;
virtual WebAutofillClient* AutofillClient() = 0;
- virtual void SetSharedWorkerRepositoryClient(
- WebSharedWorkerRepositoryClient*) = 0;
// Closing -------------------------------------------------------------
@@ -301,36 +303,22 @@ class WebLocalFrame : public WebFrame {
// gets its own wrappers for all DOM nodes and DOM constructors.
//
// worldID must be > 0 (as 0 represents the main world).
- // worldID must be < EmbedderWorldIdLimit, high number used internally.
+ // worldID must be < kEmbedderWorldIdLimit, high number used internally.
virtual void ExecuteScriptInIsolatedWorld(int world_id,
const WebScriptSource&) = 0;
// worldID must be > 0 (as 0 represents the main world).
- // worldID must be < EmbedderWorldIdLimit, high number used internally.
+ // worldID must be < kEmbedderWorldIdLimit, high number used internally.
// DEPRECATED: Use WebLocalFrame::requestExecuteScriptInIsolatedWorld.
WARN_UNUSED_RESULT virtual v8::Local<v8::Value>
ExecuteScriptInIsolatedWorldAndReturnValue(int world_id,
const WebScriptSource&) = 0;
- // Associates an isolated world (see above for description) with a security
- // origin. XMLHttpRequest instances used in that world will be considered
- // to come from that origin, not the frame's.
- //
- // Currently the origin shouldn't be aliased, because IsolatedCopy() is
- // taken before associating it to an isolated world and aliased relationship,
- // if any, is broken. crbug.com/779730
- virtual void SetIsolatedWorldSecurityOrigin(int world_id,
- const WebSecurityOrigin&) = 0;
-
- // Associates a content security policy with an isolated world. This policy
- // should be used when evaluating script in the isolated world, and should
- // also replace a protected resource's CSP when evaluating resources
- // injected into the DOM.
- //
- // FIXME: Setting this simply bypasses the protected resource's CSP. It
- // doesn't yet restrict the isolated world to the provided policy.
- virtual void SetIsolatedWorldContentSecurityPolicy(int world_id,
- const WebString&) = 0;
+ // Sets up an isolated world by associating a |world_id| with |info|.
+ // worldID must be > 0 (as 0 represents the main world).
+ // worldID must be < kEmbedderWorldIdLimit, high number used internally.
+ virtual void SetIsolatedWorldInfo(int world_id,
+ const WebIsolatedWorldInfo& info) = 0;
// Executes script in the context of the current page and returns the value
// that the script evaluated to.
@@ -397,7 +385,7 @@ class WebLocalFrame : public WebFrame {
};
// worldID must be > 0 (as 0 represents the main world).
- // worldID must be < EmbedderWorldIdLimit, high number used internally.
+ // worldID must be < kEmbedderWorldIdLimit, high number used internally.
virtual void RequestExecuteScriptInIsolatedWorld(
int world_id,
const WebScriptSource* source_in,
@@ -406,11 +394,6 @@ class WebLocalFrame : public WebFrame {
ScriptExecutionType,
WebScriptExecutionCallback*) = 0;
- // Associates an isolated world with human-readable name which is useful for
- // extension debugging.
- virtual void SetIsolatedWorldHumanReadableName(int world_id,
- const WebString&) = 0;
-
// Logs to the console associated with this frame.
virtual void AddMessageToConsole(const WebConsoleMessage&) = 0;
@@ -620,6 +603,9 @@ class WebLocalFrame : public WebFrame {
// This will be removed following the deprecation.
virtual void UsageCountChromeLoadTimes(const WebString& metric) = 0;
+ // Dispatches an event when a Portal gets activated.
+ virtual void OnPortalActivated() = 0;
+
// Scheduling ---------------------------------------------------------------
virtual FrameScheduler* Scheduler() const = 0;
@@ -721,17 +707,17 @@ class WebLocalFrame : public WebFrame {
// This setter is available in case the embedder has more information about
// whether or not the frame is an ad.
- virtual void SetIsAdSubframe() = 0;
+ virtual void SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type) = 0;
// Testing ------------------------------------------------------------------
// Dumps the layer tree, used by the accelerated compositor, in
- // text form. This is used only by layout tests.
+ // text form. This is used only by web tests.
virtual WebString GetLayerTreeAsTextForTesting(
bool show_debug_info = false) const = 0;
// Prints the frame into the canvas, with page boundaries drawn as one pixel
- // wide blue lines. This method exists to support layout tests.
+ // wide blue lines. This method exists to support web tests.
virtual void PrintPagesForTesting(cc::PaintCanvas*, const WebSize&) = 0;
// Returns the bounds rect for current selection. If selection is performed
diff --git a/chromium/third_party/blink/public/web/web_local_frame_client.h b/chromium/third_party/blink/public/web/web_local_frame_client.h
index 2a46b3fabd8..177112d7b6e 100644
--- a/chromium/third_party/blink/public/web/web_local_frame_client.h
+++ b/chromium/third_party/blink/public/web/web_local_frame_client.h
@@ -39,7 +39,6 @@
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/common/frame/sandbox_flags.h"
#include "third_party/blink/public/common/frame/user_activation_update_type.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
#include "third_party/blink/public/platform/blame_context.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
#include "third_party/blink/public/platform/web_application_cache_host.h"
@@ -66,7 +65,6 @@
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_frame_load_type.h"
#include "third_party/blink/public/web/web_frame_owner_properties.h"
-#include "third_party/blink/public/web/web_global_object_reuse_policy.h"
#include "third_party/blink/public/web/web_history_commit_type.h"
#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/public/web/web_icon_url.h"
@@ -228,6 +226,13 @@ class BLINK_EXPORT WebLocalFrameClient {
return nullptr;
}
+ // Request the creation of a new portal.
+ virtual std::pair<WebRemoteFrame*, base::UnguessableToken> CreatePortal(
+ mojo::ScopedMessagePipeHandle pipe) {
+ return std::pair<WebRemoteFrame*, base::UnguessableToken>(
+ nullptr, base::UnguessableToken());
+ }
+
// Called when Blink cannot find a frame with the given name in the frame's
// browsing instance. This gives the embedder a chance to return a frame
// from outside of the browsing instance.
@@ -380,8 +385,7 @@ class BLINK_EXPORT WebLocalFrameClient {
virtual void DidCreateDocumentLoader(WebDocumentLoader*) {}
// A new provisional load has been started.
- virtual void DidStartProvisionalLoad(WebDocumentLoader* document_loader,
- WebURLRequest& request) {}
+ virtual void DidStartProvisionalLoad(WebDocumentLoader* document_loader) {}
// The provisional load failed. The WebHistoryCommitType is the commit type
// that would have been used had the load succeeded.
@@ -391,9 +395,17 @@ class BLINK_EXPORT WebLocalFrameClient {
// The provisional datasource is now committed. The first part of the
// response body has been received, and the encoding of the response
// body is known.
+ // The mojo::ScopedMessagePipeHandle is a DocumentInterfaceBroker handle. When
+ // a load commits and a new Document is created, Blink creates a new
+ // DocumentInterfaceBroker endpoint to ensure that interface requests in the
+ // newly committed Document are associated with the correct origin (even if
+ // the origin of the old and the new Document are the same). The one
+ // exception is if the Window object is reused; in that case, the old
+ // DocumentInterfaceBroker handle will be reused, and the endpoint won't be
+ // bound to any requests.
virtual void DidCommitProvisionalLoad(const WebHistoryItem&,
WebHistoryCommitType,
- WebGlobalObjectReusePolicy) {}
+ mojo::ScopedMessagePipeHandle) {}
// The frame's document has just been initialized.
virtual void DidCreateNewDocument() {}
@@ -767,11 +779,6 @@ class BLINK_EXPORT WebLocalFrameClient {
// Visibility ----------------------------------------------------------
- // Returns the current visibility of the WebFrame.
- virtual mojom::PageVisibilityState VisibilityState() const {
- return mojom::PageVisibilityState::kVisible;
- }
-
// Overwrites the given URL to use an HTML5 embed if possible.
// An empty URL is returned if the URL is not overriden.
virtual WebURL OverrideFlashEmbedWithHTML(const WebURL& url) {
diff --git a/chromium/third_party/blink/public/web/web_navigation_control.h b/chromium/third_party/blink/public/web/web_navigation_control.h
index 5c51faef825..271c97bb54a 100644
--- a/chromium/third_party/blink/public/web/web_navigation_control.h
+++ b/chromium/third_party/blink/public/web/web_navigation_control.h
@@ -14,12 +14,10 @@
namespace blink {
-class WebData;
-class WebString;
class WebURL;
struct WebURLError;
-class WebURLRequest;
class WebHistoryItem;
+struct WebNavigationInfo;
struct WebNavigationParams;
// This interface gives control to navigation-related functionality of
@@ -36,15 +34,10 @@ class WebNavigationControl : public WebLocalFrame {
// Note: this may lead to the destruction of the frame.
virtual bool DispatchBeforeUnloadEvent(bool is_reload) = 0;
- // Commits a cross-document navigation in the frame. For history navigations,
- // a valid WebHistoryItem should be provided.
+ // Commits a cross-document navigation in the frame. See WebNavigationParams
+ // for details.
// TODO(dgozman): return mojom::CommitResult.
virtual void CommitNavigation(
- const WebURLRequest&,
- WebFrameLoadType,
- const WebHistoryItem&,
- bool is_client_redirect,
- const base::UnguessableToken& devtools_navigation_token,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) = 0;
@@ -63,36 +56,6 @@ class WebNavigationControl : public WebLocalFrame {
// return something meaningful?
virtual void LoadJavaScriptURL(const WebURL&) = 0;
- // This method is short-hand for calling CommitDataNavigation, where mime_type
- // is "text/html" and text_encoding is "UTF-8".
- // TODO(dgozman): rename to CommitHTMLStringNavigation.
- virtual void LoadHTMLString(const WebData& html,
- const WebURL& base_url,
- const WebURL& unreachable_url = WebURL()) = 0;
-
- // Navigates to the given |data| with specified |mime_type| and optional
- // |text_encoding|.
- //
- // If specified, |unreachable_url| is reported via
- // WebDocumentLoader::UnreachableURL.
- //
- // If |replace| is false, then this data will be loaded as a normal
- // navigation. Otherwise, the current history item will be replaced.
- //
- // Request's url indicates the security origin and is used as a base
- // url to resolve links in the committed document.
- virtual void CommitDataNavigation(
- const WebURLRequest&,
- const WebData&,
- const WebString& mime_type,
- const WebString& text_encoding,
- const WebURL& unreachable_url,
- WebFrameLoadType,
- const WebHistoryItem&,
- bool is_client_redirect,
- std::unique_ptr<WebNavigationParams> navigation_params,
- std::unique_ptr<WebDocumentLoader::ExtraData> navigation_data) = 0;
-
enum FallbackContentResult {
// An error page should be shown instead of fallback.
NoFallbackContent,
@@ -114,6 +77,7 @@ class WebNavigationControl : public WebLocalFrame {
// in this frame. Used to propagate state when this frame has navigated
// cross process.
virtual void SetCommittedFirstRealLoad() = 0;
+ virtual bool HasCommittedFirstRealLoad() = 0;
// Informs the frame that the navigation it asked the client to do was
// dropped.
@@ -129,12 +93,7 @@ class WebNavigationControl : public WebLocalFrame {
// is actually being handled by the client.
// TODO(dgozman): remove this together with placeholder document loader.
virtual bool CreatePlaceholderDocumentLoader(
- const WebURLRequest&,
- WebFrameLoadType,
- WebNavigationType,
- bool is_client_redirect,
- const base::UnguessableToken& devtools_navigation_token,
- std::unique_ptr<WebNavigationParams>,
+ const WebNavigationInfo&,
std::unique_ptr<WebDocumentLoader::ExtraData>) = 0;
protected:
diff --git a/chromium/third_party/blink/public/web/web_navigation_params.h b/chromium/third_party/blink/public/web/web_navigation_params.h
index b32880710f1..1f63b1cc7f0 100644
--- a/chromium/third_party/blink/public/web/web_navigation_params.h
+++ b/chromium/third_party/blink/public/web/web_navigation_params.h
@@ -7,24 +7,38 @@
#include <memory>
+#include "base/containers/span.h"
#include "base/optional.h"
#include "base/time/time.h"
+#include "base/unguessable_token.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_content_security_policy.h"
+#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
+#include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_source_location.h"
#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_frame_load_type.h"
+#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/public/web/web_navigation_policy.h"
#include "third_party/blink/public/web/web_navigation_timings.h"
#include "third_party/blink/public/web/web_navigation_type.h"
#include "third_party/blink/public/web/web_triggering_event_info.h"
+#if INSIDE_BLINK
+#include "base/memory/scoped_refptr.h"
+#endif
+
namespace blink {
+class KURL;
+class SharedBuffer;
+
// This structure holds all information collected by Blink when
// navigation is being initiated.
struct BLINK_EXPORT WebNavigationInfo {
@@ -58,6 +72,10 @@ struct BLINK_EXPORT WebNavigationInfo {
// by the window.open'd frame.
bool is_opener_navigation = false;
+ // Whether the runtime feature
+ // |BlockingDownloadsInSandboxWithoutUserActivation| is enabled.
+ bool blocking_downloads_in_sandbox_without_user_activation_enabled = false;
+
// Event information. See WebTriggeringEventInfo.
WebTriggeringEventInfo triggering_event_info =
WebTriggeringEventInfo::kUnknown;
@@ -85,6 +103,10 @@ struct BLINK_EXPORT WebNavigationInfo {
// the input start time.
base::TimeTicks input_start;
+ // This is the navigation relevant CSP to be used during request and response
+ // checks.
+ WebContentSecurityPolicyList initiator_csp;
+
// The navigation initiator, if any.
mojo::ScopedMessagePipeHandle navigation_initiator_handle;
@@ -103,9 +125,70 @@ struct BLINK_EXPORT WebNavigationInfo {
// WebDocumentLoader::ExtraData, which is an opaque structure stored in the
// DocumentLoader and used by the embedder.
struct BLINK_EXPORT WebNavigationParams {
+ WebNavigationParams();
+ ~WebNavigationParams();
+
+ // Allows to specify |devtools_navigation_token|, instead of creating
+ // a new one.
+ explicit WebNavigationParams(const base::UnguessableToken&);
+
+ // Shortcut for navigating based on WebNavigationInfo parameters.
+ static std::unique_ptr<WebNavigationParams> CreateFromInfo(
+ const WebNavigationInfo&);
+
+ // Shortcut for loading html with "text/html" mime type and "UTF8" encoding.
+ static std::unique_ptr<WebNavigationParams> CreateWithHTMLString(
+ base::span<const char> html,
+ const WebURL& base_url);
+
+#if INSIDE_BLINK
+ // Shortcut for loading html with "text/html" mime type and "UTF8" encoding.
+ static std::unique_ptr<WebNavigationParams> CreateWithHTMLBuffer(
+ scoped_refptr<SharedBuffer> buffer,
+ const KURL& base_url);
+#endif
+
+ // The request to navigate to. Its URL indicates the security origin
+ // and will be used as a base URL to resolve links in the committed document.
+ // TODO(dgozman): do we actually need a request here? Maybe just a URL?
+ WebURLRequest request;
+
+ // If the data is non null, it will be used as a main resource content
+ // instead of loading the request above.
+ WebData data;
+ // Specifies the mime type of the raw data. Must be set together with the
+ // data.
+ WebString mime_type;
+ // The encoding of the raw data. Must be set together with the data.
+ WebString text_encoding;
+ // If non-null, used as a URL which we weren't able to load. For example,
+ // history item will contain this URL instead of request's URL.
+ // This URL can be retrieved through WebDocumentLoader::UnreachableURL.
+ WebURL unreachable_url;
+
+ // The load type. See WebFrameLoadType for definition.
+ WebFrameLoadType frame_load_type = WebFrameLoadType::kStandard;
+ // History item should be provided for back-forward load types.
+ WebHistoryItem history_item;
+ // Whether this navigation is a result of client redirect.
+ bool is_client_redirect = false;
+
+ // The origin in which a navigation should commit. When provided, Blink
+ // should use this origin directly and not compute locally the new document
+ // origin.
+ WebSecurityOrigin origin_to_commit;
+
+ // The devtools token for this navigation. See DocumentLoader
+ // for details.
+ base::UnguessableToken devtools_navigation_token;
+ // Known timings related to navigation. If the navigation has
+ // started in another process, timings are propagated from there.
WebNavigationTimings navigation_timings;
- base::Optional<WebSourceLocation> source_location;
+ // Whether this navigation had a transient user activation.
bool is_user_activated = false;
+
+ // The service worker network provider to be used in the new
+ // document.
std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
service_worker_network_provider;
};
diff --git a/chromium/third_party/blink/public/web/web_pepper_socket_client.h b/chromium/third_party/blink/public/web/web_pepper_socket_client.h
index c13cfa12f36..547e89208a4 100644
--- a/chromium/third_party/blink/public/web/web_pepper_socket_client.h
+++ b/chromium/third_party/blink/public/web/web_pepper_socket_client.h
@@ -51,7 +51,7 @@ class WebPepperSocketClient {
virtual void DidReceiveMessage(const WebString& message) {}
virtual void DidReceiveArrayBuffer(const WebArrayBuffer& array_buffer) {}
virtual void DidReceiveMessageError() {}
- virtual void DidConsumeBufferedAmount(unsigned long consumed) {}
+ virtual void DidConsumeBufferedAmount(uint64_t consumed) {}
virtual void DidStartClosingHandshake() {}
virtual void DidClose(ClosingHandshakeCompletionStatus,
unsigned short code,
diff --git a/chromium/third_party/blink/public/web/web_performance.h b/chromium/third_party/blink/public/web/web_performance.h
index 39d8d120b84..3f64ff31ba8 100644
--- a/chromium/third_party/blink/public/web/web_performance.h
+++ b/chromium/third_party/blink/public/web/web_performance.h
@@ -87,15 +87,18 @@ class WebPerformance {
BLINK_EXPORT double LoadEventEnd() const;
BLINK_EXPORT double FirstLayout() const;
BLINK_EXPORT double FirstPaint() const;
- BLINK_EXPORT double FirstTextPaint() const;
BLINK_EXPORT double FirstImagePaint() const;
BLINK_EXPORT double FirstContentfulPaint() const;
BLINK_EXPORT double FirstMeaningfulPaint() const;
BLINK_EXPORT double FirstMeaningfulPaintCandidate() const;
BLINK_EXPORT double LargestImagePaint() const;
+ BLINK_EXPORT uint64_t LargestImagePaintSize() const;
BLINK_EXPORT double LastImagePaint() const;
+ BLINK_EXPORT uint64_t LastImagePaintSize() const;
BLINK_EXPORT double LargestTextPaint() const;
+ BLINK_EXPORT uint64_t LargestTextPaintSize() const;
BLINK_EXPORT double LastTextPaint() const;
+ BLINK_EXPORT uint64_t LastTextPaintSize() const;
BLINK_EXPORT double PageInteractive() const;
BLINK_EXPORT double PageInteractiveDetection() const;
BLINK_EXPORT double FirstInputInvalidatingInteractive() const;
diff --git a/chromium/third_party/blink/public/web/web_remote_frame.h b/chromium/third_party/blink/public/web/web_remote_frame.h
index be3e7c20f0d..07710adc2c7 100644
--- a/chromium/third_party/blink/public/web/web_remote_frame.h
+++ b/chromium/third_party/blink/public/web/web_remote_frame.h
@@ -9,6 +9,7 @@
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/common/frame/sandbox_flags.h"
#include "third_party/blink/public/common/frame/user_activation_update_type.h"
+#include "third_party/blink/public/mojom/csp/content_security_policy.mojom-shared.h"
#include "third_party/blink/public/platform/web_content_security_policy.h"
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
#include "third_party/blink/public/platform/web_scroll_types.h"
@@ -54,6 +55,7 @@ class WebRemoteFrame : public WebFrame {
WebSandboxFlags,
WebLocalFrameClient*,
blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebFrame* previous_sibling,
const ParsedFeaturePolicy&,
const WebFrameOwnerProperties&,
@@ -90,7 +92,7 @@ class WebRemoteFrame : public WebFrame {
// Adds |header| to the set of replicated CSP headers.
virtual void AddReplicatedContentSecurityPolicyHeader(
const WebString& header_value,
- WebContentSecurityPolicyType,
+ mojom::ContentSecurityPolicyType,
WebContentSecurityPolicySource) = 0;
// Resets replicated CSP headers to an empty set.
diff --git a/chromium/third_party/blink/public/web/web_remote_frame_client.h b/chromium/third_party/blink/public/web/web_remote_frame_client.h
index de85c479a3c..f9a76268b8e 100644
--- a/chromium/third_party/blink/public/web/web_remote_frame_client.h
+++ b/chromium/third_party/blink/public/web/web_remote_frame_client.h
@@ -39,6 +39,8 @@ class WebRemoteFrameClient {
// A remote frame was asked to start a navigation.
virtual void Navigate(const WebURLRequest& request,
bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
mojo::ScopedMessagePipeHandle blob_url_token) {}
virtual void FrameRectsChanged(const WebRect& local_frame_rect,
diff --git a/chromium/third_party/blink/public/web/web_settings.h b/chromium/third_party/blink/public/web/web_settings.h
index bc8f39fb9fe..2856333395a 100644
--- a/chromium/third_party/blink/public/web/web_settings.h
+++ b/chromium/third_party/blink/public/web/web_settings.h
@@ -61,12 +61,6 @@ class WebSettings {
kFullCodeWithoutHeatCheck
};
- enum class SavePreviousDocumentResources {
- kNever,
- kUntilOnDOMContentLoaded,
- kUntilOnLoad
- };
-
// Selection strategy defines how the selection granularity changes when the
// selection extent is moved.
enum class SelectionStrategyType {
@@ -158,6 +152,7 @@ class WebSettings {
virtual void SetDownloadableBinaryFontsEnabled(bool) = 0;
virtual void SetEditingBehavior(EditingBehavior) = 0;
virtual void SetEnableScrollAnimator(bool) = 0;
+ virtual void SetPrefersReducedMotion(bool) = 0;
virtual void SetEnableTouchAdjustment(bool) = 0;
virtual void SetSmoothScrollForFindEnabled(bool) = 0;
virtual void SetWebGL1Enabled(bool) = 0;
@@ -172,6 +167,7 @@ class WebSettings {
virtual void SetForceZeroLayoutHeight(bool) = 0;
virtual void SetFullscreenSupported(bool) = 0;
virtual void SetHideDownloadUI(bool) = 0;
+ virtual void SetHighlightAds(bool) = 0;
virtual void SetHistoryEntryRequiresUserGesture(bool) = 0;
virtual void SetHyperlinkAuditingEnabled(bool) = 0;
virtual void SetIgnoreMainFrameOverflowHiddenQuirk(bool) = 0;
@@ -183,16 +179,13 @@ class WebSettings {
virtual void SetLoadsImagesAutomatically(bool) = 0;
virtual void SetLoadWithOverviewMode(bool) = 0;
virtual void SetShouldReuseGlobalForUnownedMainFrame(bool) = 0;
- virtual void SetSavePreviousDocumentResources(
- SavePreviousDocumentResources) = 0;
virtual void SetLocalStorageEnabled(bool) = 0;
virtual void SetMainFrameClipsContent(bool) = 0;
virtual void SetMainFrameResizesAreOrientationChanges(bool) = 0;
virtual void SetMaxTouchPoints(int) = 0;
virtual void SetPictureInPictureEnabled(bool) = 0;
virtual void SetDataSaverHoldbackWebApi(bool) = 0;
- virtual void SetDataSaverHoldbackMediaApi(bool) = 0;
- virtual void SetMediaPlaybackGestureWhitelistScope(const WebString&) = 0;
+ virtual void SetWebAppScope(const WebString&) = 0;
virtual void SetPresentationRequiresUserGesture(bool) = 0;
virtual void SetEmbeddedMediaExperienceEnabled(bool) = 0;
virtual void SetImmersiveModeEnabled(bool) = 0;
@@ -205,7 +198,6 @@ class WebSettings {
virtual void SetPassiveEventListenerDefault(PassiveEventListenerDefault) = 0;
virtual void SetPasswordEchoDurationInSeconds(double) = 0;
virtual void SetPasswordEchoEnabled(bool) = 0;
- virtual void SetPerTilePaintingEnabled(bool) = 0;
virtual void SetPictographFontFamily(const WebString&,
UScriptCode = USCRIPT_COMMON) = 0;
virtual void SetPluginsEnabled(bool) = 0;
@@ -230,8 +222,6 @@ class WebSettings {
virtual void SetShouldClearDocumentBackground(bool) = 0;
virtual void SetShouldRespectImageOrientation(bool) = 0;
virtual void SetShowContextMenuOnMouseUp(bool) = 0;
- virtual void SetShowFPSCounter(bool) = 0;
- virtual void SetShowPaintRects(bool) = 0;
virtual void SetShrinksViewportContentToFit(bool) = 0;
virtual void SetSmartInsertDeleteEnabled(bool) = 0;
// Spatial navigation feature, when enabled, improves the experience
diff --git a/chromium/third_party/blink/public/web/web_shared_worker.h b/chromium/third_party/blink/public/web/web_shared_worker.h
index 1a2777638bb..4d689c0f799 100644
--- a/chromium/third_party/blink/public/web/web_shared_worker.h
+++ b/chromium/third_party/blink/public/web/web_shared_worker.h
@@ -37,10 +37,10 @@
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "third_party/blink/public/common/privacy_preferences.h"
+#include "third_party/blink/public/mojom/csp/content_security_policy.mojom-shared.h"
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-shared.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_content_security_policy.h"
namespace base {
class SingleThreadTaskRunner;
@@ -70,7 +70,7 @@ class BLINK_EXPORT WebSharedWorker {
const WebURL& script_url,
const WebString& name,
const WebString& content_security_policy,
- WebContentSecurityPolicyType,
+ mojom::ContentSecurityPolicyType,
mojom::IPAddressSpace,
const base::UnguessableToken& devtools_worker_token,
PrivacyPreferences privacy_preferences,
diff --git a/chromium/third_party/blink/public/web/web_shared_worker_client.h b/chromium/third_party/blink/public/web/web_shared_worker_client.h
index 4cc9627328f..ab6be749cc5 100644
--- a/chromium/third_party/blink/public/web/web_shared_worker_client.h
+++ b/chromium/third_party/blink/public/web/web_shared_worker_client.h
@@ -39,7 +39,6 @@ namespace blink {
class WebApplicationCacheHost;
class WebApplicationCacheHostClient;
-class WebNotificationPresenter;
class WebServiceWorkerNetworkProvider;
// Provides an interface back to the in-page script object for a worker.
@@ -58,10 +57,6 @@ class WebSharedWorkerClient {
virtual void WorkerScriptLoadFailed() = 0;
virtual void SelectAppCacheID(long long) = 0;
- // Returns the notification presenter for this worker context. Pointer
- // is owned by the object implementing WebSharedWorkerClient.
- virtual WebNotificationPresenter* NotificationPresenter() = 0;
-
// Called on the main webkit thread in the worker process during
// initialization.
virtual std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
diff --git a/chromium/third_party/blink/public/web/web_shared_worker_connect_listener.h b/chromium/third_party/blink/public/web/web_shared_worker_connect_listener.h
deleted file mode 100644
index 039db858870..00000000000
--- a/chromium/third_party/blink/public/web/web_shared_worker_connect_listener.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SHARED_WORKER_CONNECT_LISTENER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SHARED_WORKER_CONNECT_LISTENER_H_
-
-#include "third_party/blink/public/mojom/shared_worker/shared_worker_creation_context_type.mojom-shared.h"
-#include "third_party/blink/public/platform/web_feature.mojom-shared.h"
-
-namespace blink {
-
-// This is the callback interface passed from blink to the embedder.
-class WebSharedWorkerConnectListener {
- public:
- virtual ~WebSharedWorkerConnectListener() = default;
-
- // Called when a worker is created.
- virtual void WorkerCreated(mojom::SharedWorkerCreationContextType) = 0;
-
- // Called when worker script load fails.
- virtual void ScriptLoadFailed() = 0;
-
- // Called when a connection is established.
- virtual void Connected() = 0;
-
- // Called when some API to be recorded in UseCounter is called on the worker
- // global scope.
- virtual void CountFeature(mojom::WebFeature) = 0;
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/public/web/web_shared_worker_repository_client.h b/chromium/third_party/blink/public/web/web_shared_worker_repository_client.h
deleted file mode 100644
index 00002bb9122..00000000000
--- a/chromium/third_party/blink/public/web/web_shared_worker_repository_client.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SHARED_WORKER_REPOSITORY_CLIENT_H_
-#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SHARED_WORKER_REPOSITORY_CLIENT_H_
-
-#include <memory>
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-shared.h"
-#include "third_party/blink/public/mojom/shared_worker/shared_worker_creation_context_type.mojom-shared.h"
-
-namespace blink {
-
-class MessagePortChannel;
-class WebSharedWorkerConnectListener;
-class WebString;
-class WebURL;
-
-class WebSharedWorkerRepositoryClient {
- public:
- // Unique identifier for the parent document of a worker (unique within a
- // given process).
- using DocumentID = unsigned long long;
-
- // Connects to a shared worker.
- virtual void Connect(
- const WebURL&,
- const WebString& name,
- DocumentID,
- const WebString& content_security_policy,
- WebContentSecurityPolicyType,
- mojom::IPAddressSpace,
- mojom::SharedWorkerCreationContextType,
- MessagePortChannel,
- mojo::ScopedMessagePipeHandle blob_url_token,
- std::unique_ptr<blink::WebSharedWorkerConnectListener>) = 0;
-
- // Invoked when a document has been detached. DocumentID can be re-used after
- // documentDetached() is invoked.
- virtual void DocumentDetached(DocumentID) {}
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SHARED_WORKER_REPOSITORY_CLIENT_H_
diff --git a/chromium/third_party/blink/public/web/web_text_check_client.h b/chromium/third_party/blink/public/web/web_text_check_client.h
index 71b4bdfb291..d4a73719128 100644
--- a/chromium/third_party/blink/public/web/web_text_check_client.h
+++ b/chromium/third_party/blink/public/web/web_text_check_client.h
@@ -34,10 +34,6 @@ class WebTextCheckClient {
const WebString& text_to_check,
WebTextCheckingCompletion* completion_callback) {}
- // Clear all stored references to requests, so that it will not become a
- // leak source.
- virtual void CancelAllPendingRequests() {}
-
protected:
virtual ~WebTextCheckClient() = default;
};
diff --git a/chromium/third_party/blink/public/web/web_user_media_request.h b/chromium/third_party/blink/public/web/web_user_media_request.h
index 0196f53f6f5..a5fd1217f9c 100644
--- a/chromium/third_party/blink/public/web/web_user_media_request.h
+++ b/chromium/third_party/blink/public/web/web_user_media_request.h
@@ -57,7 +57,8 @@ class BLINK_EXPORT WebUserMediaRequest {
kCapture,
kTrackStart,
kFailedDueToShutdown,
- kKillSwitchOn
+ kKillSwitchOn,
+ kSystemPermissionDenied
};
enum class MediaType {
diff --git a/chromium/third_party/blink/public/web/web_view.h b/chromium/third_party/blink/public/web/web_view.h
index e14420e7897..f7f0ae5b0c7 100644
--- a/chromium/third_party/blink/public/web/web_view.h
+++ b/chromium/third_party/blink/public/web/web_view.h
@@ -33,7 +33,6 @@
#include "base/time/time.h"
#include "third_party/blink/public/common/manifest/web_display_mode.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
#include "third_party/blink/public/platform/web_drag_operation.h"
#include "third_party/blink/public/platform/web_focus_type.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -49,6 +48,7 @@ class WebFrame;
class WebHitTestResult;
class WebLocalFrame;
class WebPageImportanceSignals;
+class WebPagePopup;
class WebPrerendererClient;
class WebRemoteFrame;
class WebSettings;
@@ -82,13 +82,25 @@ class WebView {
// as appropriate. It is legal to modify settings before completing
// initialization.
//
- // client may be null, while PageVisibilityState defines the initial
- // visibility of the page.
+ // clients may be null, but should both be null or not together.
+ // |is_hidden| defines the initial visibility of the page.
+ // |compositing_enabled| dictates whether accelerated compositing should be
+ // enabled for the page. It must be false if no clients are provided, or if a
+ // LayerTreeView will not be set for the WebWidget.
+ // TODO(danakj): This field should go away as WebWidgets always composite
+ // their output.
BLINK_EXPORT static WebView* Create(WebViewClient*,
- WebWidgetClient*,
- mojom::PageVisibilityState,
+ bool is_hidden,
+ bool compositing_enabled,
WebView* opener);
+ // Called on WebView when a WebFrameWidget is created for a local main frame,
+ // and can be set back to null when the WebWidgetClient is removed due to the
+ // main frame being detached.
+ // TODO(danakj): Move this to WebWidget and merge with SetLayerTreeView, have
+ // it be null/not set when the main frame is remote.
+ virtual void SetWebWidgetClient(WebWidgetClient*) = 0;
+
// Initializes the various client interfaces.
virtual void SetPrerendererClient(WebPrerendererClient*) = 0;
@@ -253,6 +265,9 @@ class WebView {
// Requests a page-scale animation based on the specified point/rect.
virtual void AnimateDoubleTapZoom(const gfx::Point&, const WebRect&) = 0;
+ // Requests a page-scale animation based on the specified rect.
+ virtual void ZoomToFindInPageRect(const WebRect&) = 0;
+
// Sets the display mode of the web app.
virtual void SetDisplayMode(WebDisplayMode) = 0;
@@ -269,8 +284,8 @@ class WebView {
virtual float ZoomFactorForDeviceScaleFactor() = 0;
// Resize the view at the same time as changing the state of the top
- // controls. If |browserControlsShrinkLayout| is true, the embedder shrunk the
- // WebView size by the browser controls height.
+ // controls. If |browser_controls_shrink_layout| is true, the embedder shrunk
+ // the WebView size by the browser controls height.
virtual void ResizeWithBrowserControls(
const WebSize&,
float top_controls_height,
@@ -330,8 +345,11 @@ class WebView {
// Sets whether select popup menus should be rendered by the browser.
BLINK_EXPORT static void SetUseExternalPopupMenus(bool);
- // Hides any popup (suggestions, selects...) that might be showing.
- virtual void HidePopups() = 0;
+ // Cancels and hides the current popup (datetime, select...) if any.
+ virtual void CancelPagePopup() = 0;
+
+ // Returns the current popup if any.
+ virtual WebPagePopup* GetPagePopup() const = 0;
// Visited link state --------------------------------------------------
@@ -353,6 +371,19 @@ class WebView {
unsigned inactive_background_color,
unsigned inactive_foreground_color) = 0;
+ // Sets the default background color when the page has not loaded enough to
+ // know a background colour. This can be overridden by the methods below as
+ // well.
+ virtual void SetBaseBackgroundColor(SkColor) {}
+
+ // Overrides the page's background and base background color. You
+ // can use this to enforce a transparent background, which is useful if you
+ // want to have some custom background rendered behind the widget.
+ virtual void SetBackgroundColorOverride(SkColor) {}
+ virtual void ClearBackgroundColorOverride() {}
+ virtual void SetBaseBackgroundColorOverride(SkColor) {}
+ virtual void ClearBaseBackgroundColorOverride() {}
+
// Modal dialog support ------------------------------------------------
// Call these methods before and after running a nested, modal event loop
@@ -360,10 +391,6 @@ class WebView {
BLINK_EXPORT static void WillEnterModalLoop();
BLINK_EXPORT static void DidExitModalLoop();
- virtual void SetShowPaintRects(bool) = 0;
- virtual void SetShowFPSCounter(bool) = 0;
- virtual void SetShowScrollBottleneckRects(bool) = 0;
-
// Scheduling -----------------------------------------------------------
virtual PageScheduler* Scheduler() const = 0;
@@ -371,14 +398,13 @@ class WebView {
// Visibility -----------------------------------------------------------
// Sets the visibility of the WebView.
- virtual void SetVisibilityState(mojom::PageVisibilityState visibility_state,
- bool is_initial_state) {}
- virtual mojom::PageVisibilityState VisibilityState() = 0;
+ virtual void SetIsHidden(bool hidden, bool is_initial_state) = 0;
+ virtual bool IsHidden() = 0;
- // PageOverlay ----------------------------------------------------------
+ // FrameOverlay ----------------------------------------------------------
// Overlay this WebView with a solid color.
- virtual void SetPageOverlayColor(SkColor) = 0;
+ virtual void SetMainFrameOverlayColor(SkColor) = 0;
// Page Importance Signals ----------------------------------------------
diff --git a/chromium/third_party/blink/public/web/web_view_client.h b/chromium/third_party/blink/public/web/web_view_client.h
index 7617170e0a3..7436b8eafb7 100644
--- a/chromium/third_party/blink/public/web/web_view_client.h
+++ b/chromium/third_party/blink/public/web/web_view_client.h
@@ -33,7 +33,6 @@
#include "base/strings/string_piece.h"
#include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_ax_enums.h"
#include "third_party/blink/public/web/web_frame.h"
@@ -44,10 +43,10 @@ namespace blink {
class WebDateTimeChooserCompletion;
class WebNode;
+class WebPagePopup;
class WebURL;
class WebURLRequest;
class WebView;
-class WebWidget;
enum class WebSandboxFlags;
struct WebDateTimeChooserParams;
struct WebRect;
@@ -79,7 +78,7 @@ class WebViewClient {
}
// Create a new popup WebWidget.
- virtual WebWidget* CreatePopup(WebLocalFrame*) { return nullptr; }
+ virtual WebPagePopup* CreatePopup(WebLocalFrame*) { return nullptr; }
// Returns the session storage namespace id associated with this WebView.
virtual base::StringPiece GetSessionStorageNamespaceId() {
@@ -200,8 +199,6 @@ class WebViewClient {
// Gestures -------------------------------------------------------------
virtual bool CanHandleGestureEvent() { return false; }
-
- virtual WebWidgetClient* WidgetClient() = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/web/web_widget.h b/chromium/third_party/blink/public/web/web_widget.h
index ba20f614dc4..2e90d02f279 100644
--- a/chromium/third_party/blink/public/web/web_widget.h
+++ b/chromium/third_party/blink/public/web/web_widget.h
@@ -35,6 +35,7 @@
#include "base/time/time.h"
#include "cc/input/browser_controls_state.h"
#include "cc/paint/paint_canvas.h"
+#include "cc/trees/element_id.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_float_size.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
@@ -61,7 +62,6 @@ class Point;
namespace blink {
class WebCoalescedInputEvent;
class WebLayerTreeView;
-class WebPagePopup;
class WebWidget {
public:
@@ -128,30 +128,18 @@ class WebWidget {
virtual void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) {}
// Called to paint the rectangular region within the WebWidget
- // onto the specified canvas at (viewPort.x,viewPort.y).
+ // onto the specified canvas at (view_port.x, view_port.y).
//
- // Before calling PaintContent(), you must call
- // UpdateLifecycle(LifecycleUpdate::All): this method assumes the lifecycle
- // is clean. It is okay to call paint multiple times once the lifecycle is
- // updated, assuming no other changes are made to the WebWidget (e.g., once
+ // Before calling PaintContent(), the caller must ensure the lifecycle of the
+ // widget's frame is clean by calling UpdateLifecycle(LifecycleUpdate::All).
+ // It is okay to call paint multiple times once the lifecycle is clean,
+ // assuming no other changes are made to the WebWidget (e.g., once
// events are processed, it should be assumed that another call to
// UpdateLifecycle is warranted before painting again). Paints starting from
// the main LayoutView's property tree state, thus ignoring any transient
// transormations (e.g. pinch-zoom, dev tools emulation, etc.).
virtual void PaintContent(cc::PaintCanvas*, const WebRect& view_port) {}
- // Similar to PaintContent() but ignores compositing decisions, squashing all
- // contents of the WebWidget into the output given to the cc::PaintCanvas.
- //
- // Before calling PaintContentIgnoringCompositing(), you must call
- // UpdateLifecycle(LifecycleUpdate::All): this method assumes the lifecycle is
- // clean.
- virtual void PaintContentIgnoringCompositing(cc::PaintCanvas*,
- const WebRect&) {}
-
- // Run layout and paint of all pending document changes asynchronously.
- virtual void LayoutAndPaintAsync(base::OnceClosure callback) {}
-
// This should only be called when isAcceleratedCompositingActive() is true.
virtual void CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) {}
@@ -192,6 +180,12 @@ class WebWidget {
virtual void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
bool has_scrolled_by_touch) {}
+ virtual void SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) {}
+ virtual void SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) {}
+
// Called to inform the WebWidget that mouse capture was lost.
virtual void MouseCaptureLost() {}
@@ -211,18 +205,12 @@ class WebWidget {
// to render its contents.
virtual bool IsAcceleratedCompositingActive() const { return false; }
- // Returns true if the WebWidget created is of type WebView.
- virtual bool IsWebView() const { return false; }
-
// Returns true if the WebWidget created is of type PepperWidget.
virtual bool IsPepperWidget() const { return false; }
// Returns true if the WebWidget created is of type WebFrameWidget.
virtual bool IsWebFrameWidget() const { return false; }
- // Returns true if the WebWidget created is of type WebPagePopup.
- virtual bool IsPagePopup() const { return false; }
-
// The WebLayerTreeView initialized on this WebWidgetClient will be going away
// and is no longer safe to access.
virtual void WillCloseLayerTreeView() {}
@@ -237,16 +225,6 @@ class WebWidget {
// reasons such as the user exiting lock, window focus changing, etc.
virtual void DidLosePointerLock() {}
- // The page background color. Can be used for filling in areas without
- // content.
- virtual SkColor BackgroundColor() const {
- return 0xFFFFFFFF; /* SK_ColorWHITE */
- }
-
- // The currently open page popup, which are calendar and datalist pickers
- // but not the select popup.
- virtual WebPagePopup* GetPagePopup() const { return 0; }
-
// Called by client to request showing the context menu.
virtual void ShowContextMenu(WebMenuSourceType) {}
diff --git a/chromium/third_party/blink/public/web/web_widget_client.h b/chromium/third_party/blink/public/web/web_widget_client.h
index 2c4127359ad..b19ca4cc153 100644
--- a/chromium/third_party/blink/public/web/web_widget_client.h
+++ b/chromium/third_party/blink/public/web/web_widget_client.h
@@ -67,12 +67,18 @@ class WebWidgetClient {
// Called when a region of the WebWidget needs to be re-painted.
virtual void DidInvalidateRect(const WebRect&) {}
- // FIXME: Remove all overrides of this.
- virtual bool AllowsBrokenNullLayerTreeView() const { return false; }
-
- // Called when a call to WebWidget::animate is required
+ // Called to request a BeginMainFrame from the compositor. For tests with
+ // single thread and no scheduler, the impl should schedule a task to run
+ // a synchronous composite.
virtual void ScheduleAnimation() {}
+ // Show or hide compositor debug visualizations.
+ virtual void SetShowFPSCounter(bool) {}
+ virtual void SetShowPaintRects(bool) {}
+ virtual void SetShowDebugBorders(bool) {}
+ virtual void SetShowScrollBottleneckRects(bool) {}
+ virtual void SetShowHitTestBorders(bool) {}
+
// A notification callback for when the intrinsic sizing of the
// widget changed. This is only called for SVG within a remote frame.
virtual void IntrinsicSizingInfoChanged(const WebIntrinsicSizingInfo&) {}
@@ -91,8 +97,11 @@ class WebWidgetClient {
virtual void AutoscrollFling(const WebFloatSize& velocity) {}
virtual void AutoscrollEnd() {}
- // Called when the widget should be closed. WebWidget::close() should
- // be called asynchronously as a result of this notification.
+ // Called when the window for this top-level widget should be closed.
+ // WebWidget::Close() should be called asynchronously as a result of this
+ // notification.
+ // TODO(danakj): Move this to WebView::CloseWindowSoon(), so we can call
+ // it when the main frame is remote and there is no top-level widget.
virtual void CloseWidgetSoon() {}
// Called to show the widget according to the given policy.
@@ -151,6 +160,10 @@ class WebWidgetClient {
// event occurs.
virtual void RequestUnbufferedInputEvents() {}
+ // Requests unbuffered (ie. low latency) input due to debugger being
+ // attached. Debugger needs to paint when stopped in the event handler.
+ virtual void SetNeedsUnbufferedInputForDebugger(bool) {}
+
// Called during WebWidget::HandleInputEvent for a TouchStart event to inform
// the embedder of the touch actions that are permitted for this touch.
virtual void SetTouchAction(WebTouchAction touch_action) {}
@@ -183,6 +196,9 @@ class WebWidgetClient {
// Double tap zooms a rect in the main-frame renderer.
virtual void AnimateDoubleTapZoomInMainFrame(const blink::WebPoint& point,
const blink::WebRect& bounds) {}
+
+ // Find in page zooms a rect in the main-frame renderer.
+ virtual void ZoomToFindInPageRectInMainFrame(const blink::WebRect& rect) {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/BUILD.gn b/chromium/third_party/blink/renderer/BUILD.gn
index 48d3b41eae3..b8718cabbd1 100644
--- a/chromium/third_party/blink/renderer/BUILD.gn
+++ b/chromium/third_party/blink/renderer/BUILD.gn
@@ -35,10 +35,20 @@ config("features") {
# inside_blink -----------------------------------------------------------------
config("inside_blink") {
+ cflags = []
defines = [
"BLINK_IMPLEMENTATION=1",
"INSIDE_BLINK",
]
+ if (is_clang) {
+ cflags += [
+ "-Wconversion",
+ "-Wno-float-conversion",
+ "-Wno-sign-conversion",
+ "-Wno-implicit-float-conversion",
+ "-Wno-implicit-int-conversion",
+ ]
+ }
}
# blink_pch --------------------------------------------------------------------
@@ -93,22 +103,8 @@ config("config") {
}
if (is_clang && blink_gc_plugin && clang_use_chrome_plugins) {
- # On Windows, the plugin is built directly into clang, so there's
- # no need to load it dynamically.
- if (host_os != "win") {
- _blink_gc_plugin_dll_extension = "so"
- if (host_os == "mac") {
- _blink_gc_plugin_dll_extension = "dylib"
- }
- cflags += [
- "-Xclang",
- "-load",
- "-Xclang",
- rebase_path(
- "${clang_base_path}/lib/libBlinkGCPlugin.${_blink_gc_plugin_dll_extension}",
- root_build_dir),
- ]
- }
+ # The plugin is built directly into clang, so there's no need to load it
+ # dynamically.
cflags += [
"-Xclang",
"-add-plugin",
diff --git a/chromium/third_party/blink/renderer/DEPS b/chromium/third_party/blink/renderer/DEPS
index 2515e2d0205..c305f913fcf 100644
--- a/chromium/third_party/blink/renderer/DEPS
+++ b/chromium/third_party/blink/renderer/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+base/format_macros.h",
"+base/gtest_prod_util.h",
"+base/location.h",
+ "+base/logging.h",
"+base/macros.h",
"+base/memory/ptr_util.h",
"+base/memory/weak_ptr.h",
@@ -24,6 +25,7 @@ include_rules = [
"+base/sequenced_task_runner.h",
"+base/single_thread_task_runner.h",
"+base/stl_util.h",
+ "+base/synchronization",
"+base/sys_byteorder.h",
"+base/system/sys_info.h",
"+base/task/post_task.h",
diff --git a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
index 29c3d757a9f..63ac8fa8df9 100644
--- a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
+++ b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -222,7 +222,7 @@ As shorthand, a constructor with no arguments can be written as `[Constructor]`
Whether you should allow an interface to have constructor depends on the spec of the interface.
*** note
-Currently `[Constructor(...)]` does not yet support optional arguments w/o defaults. It just supports optional `[Default=Undefined]`.
+Currently `[Constructor(...)]` does not yet support optional arguments w/o defaults. It just supports optional `[DefaultValue=Undefined]`.
***
### [EnforceRange] _(t)_
@@ -932,29 +932,22 @@ If the method/accessor creates elements or modifies DOM nodes in any way, it sho
Usage: `[CustomElementCallbacks]` takes no arguments.
-### [Default] _(p)_
+### [HighEntropy] _(m, a, c)_
-Summary: `[Default]` allows one to specify the default values for optional arguments. This removes the need to have C++ overloads in the Blink implementation.
+Summary: Denotes an API that exposes data that folks on the internet find useful for fingerprinting.
-Standard: In Web IDL, [default values for optional arguments](https://heycam.github.io/webidl/#dfn-optional-argument-default-value) are written as `optional type identifier = value`. Blink supports this but not all implementations have been updated to handle overloaded functions - see [bug 258153](https://crbug.com/258153). `[Default=Undefined]` was added to all optional parameters to preserve compatibility until the C++ implementations are updated.
+Attributes and methods marked as `[HighEntropy]` are known to be practically useful for [identifying particular clients](https://dev.chromium.org/Home/chromium-security/client-identification-mechanisms) on the web today.
+Both methods and attribute/constant getters annotated with this attribute are wired up to [`Dactyloscoper::Record`](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/blink/renderer/core/frame/use_counter.cc&q=Dactyloscoper::Record) for additional processing.
-Usage: `[Default=Undefined]` can be specified on any optional parameter:
+This attribute must be accompanied by either `[Measure]` or `[MeasureAs]`.
```webidl
-interface HTMLFoo {
- void func1(long a, long b, optional long c, optional long d);
- void func2(long a, long b, [Default=Undefined] optional long c);
-};
+[HighEntropy, Measure] attribute Node interestingAttribute;
+[HighEntropy, MeasureAs=InterestingNamedAttribute] attribute Node interestingNamedAttribute;
+[HighEntropy, Measure] Node getInterestingNode();
+[HighEntropy, Measure] const INTERESTING_CONSTANT = 1;
```
-The parameters marked with the standard Web IDL `optional` qualifier are optional, and JavaScript can omit the parameters. Obviously, if parameter X is marked with `optional` then all subsequent parameters of X should be marked with `optional`.
-
-The difference between `optional` and `[Default=Undefined]` optional is whether the Blink implementation requires overloaded methods or not: without a default value, the Blink implementation must have overloaded C++ functions, while with a default value, the Blink implementation only needs a single C++ function.
-
-In case of func1(...), if JavaScript calls func1(100, 200), then `HTMLFoo::func1(int a, int b)` is called in Blink. If JavaScript calls `func1(100, 200, 300)`, then `HTMLFoo::func1(int a, int b, int c)` is called in Blink. If JavaScript calls `func1(100, 200, 300, 400)`, then `HTMLFoo::func1(int a, int b, int c, int d)` is called in Blink. In other words, if the Blink implementation has overloaded methods, you can use `optional`.
-
-In case of func2(...) which adds `[Default=Undefined]`, if JavaScript calls `func2(100, 200)`, then it behaves as if JavaScript called `func2(100, 200, undefined)`. Consequently, `HTMLFoo::func2(int a, int b, int c)` is called in Blink. 100 is passed to `a`, 200 is passed to `b`, and 0 is passed to `c`. (A JavaScript `undefined` is converted to 0, following the value conversion rule in the Web IDL spec; if it were a DOMString parameter, it would end up as the string `"undefined"`.) In this way, Blink needs to just implement `func2(int a, int b, int c)` and needs not to implement both `func2(int a, int b)` and `func2(int a, int b, int c)`.
-
### [DeprecateAs] _(m, a, c)_
Summary: Measures usage of a deprecated feature via UseCounter, and notifies developers about deprecation via a console warning.
@@ -1130,17 +1123,17 @@ If the name of the corresponding content attribute is different from the attribu
Whether `[Reflect]` should be specified or not depends on the spec of each attribute.
-### [ReflectEmpty="value"] _(a)_
+### [ReflectEmpty] _(a)_
Specification: [Enumerated attributes](http://www.whatwg.org/specs/web-apps/current-work/#enumerated-attribute) - _defined in spec prose, not as an IDL extended attribute._
-Summary: `[ReflectEmpty="value"]` gives the attribute keyword value to reflect when an attribute is present, but without a value; it supplements `[ReflectOnly]` and `[Reflect]`.
+Summary: `[ReflectEmpty]` gives the attribute keyword value to reflect when an attribute is present, but without a value; it supplements `[ReflectOnly]` and `[Reflect]`.
Usage: The possible usage is `[ReflectEmpty="value"]` in combination with `[ReflectOnly]`:
```webidl
interface HTMLMyElement {
- [Reflect, ReflectOnly="for"|"against", ReflectEmpty="for"] attribute DOMString vote;
+ [Reflect, ReflectOnly=("for", "against"), ReflectEmpty="for"] attribute DOMString vote;
};
```
@@ -1148,17 +1141,17 @@ The `[ReflectEmpty]` extended attribute specifies the value that an IDL getter f
`[ReflectEmpty]` should be used if the specification for the content attribute has an empty attribute value mapped to some attribute state. For HTML, this applies to [enumerated attributes](http://www.whatwg.org/specs/web-apps/current-work/#enumerated-attribute) only.
-### [ReflectInvalid="value"] _(a)_
+### [ReflectInvalid] _(a)_
Specification: [Limited value attributes](http://www.whatwg.org/specs/web-apps/current-work/#limited-to-only-known-values) - _defined in spec prose, not as an IDL extended attribute._
-Summary: `[ReflectInvalid="value"]` gives the attribute keyword value to reflect when an attribute has an invalid/unknown value. It supplements `[ReflectOnly]` and `[Reflect]`.
+Summary: `[ReflectInvalid]` gives the attribute keyword value to reflect when an attribute has an invalid/unknown value. It supplements `[ReflectOnly]` and `[Reflect]`.
Usage: The possible usage is `[ReflectInvalid="value"]` in combination with `[ReflectOnly]`:
```webidl
interface HTMLMyElement {
- [Reflect, ReflectOnly="left"|"right", ReflectInvalid="left"] attribute DOMString direction;
+ [Reflect, ReflectOnly=("left", "right"), ReflectInvalid="left"] attribute DOMString direction;
};
```
@@ -1166,17 +1159,17 @@ The `[ReflectInvalid]` extended attribute specifies the value that an IDL getter
`[ReflectInvalid]` should be used if the specification for the content attribute has an _invalid value state_ defined. For HTML, this applies to [enumerated attributes](http://www.whatwg.org/specs/web-apps/current-work/#enumerated-attribute) only.
-### [ReflectMissing="value"] _(a)_
+### [ReflectMissing] _(a)_
Specification: [Limited value attributes](http://www.whatwg.org/specs/web-apps/current-work/#limited-to-only-known-values) - _defined in spec prose, not as an IDL extended attribute._
-Summary: `[ReflectMissing="value"]` gives the attribute keyword value to reflect when an attribute isn't present. It supplements `[ReflectOnly]` and `[Reflect]`.
+Summary: `[ReflectMissing]` gives the attribute keyword value to reflect when an attribute isn't present. It supplements `[ReflectOnly]` and `[Reflect]`.
Usage: The possible usage is `[ReflectMissing="value"]` in combination with `[ReflectOnly]`:
```webidl
interface HTMLMyElement {
- [Reflect, ReflectOnly="ltr"|"rtl"|"auto", ReflectMissing="auto"] attribute DOMString preload;
+ [Reflect, ReflectOnly=("ltr", "rtl", "auto"), ReflectMissing="auto"] attribute DOMString preload;
};
```
@@ -1184,26 +1177,26 @@ The `[ReflectMissing]` extended attribute specifies the value that an IDL getter
`[ReflectMissing]` should be used if the specification for the content attribute has a _missing value state_ defined. For HTML, this applies to [enumerated attributes](http://www.whatwg.org/specs/web-apps/current-work/#enumerated-attribute) only.
-### [ReflectOnly=&lt;list&gt;] _(a)_
+### [ReflectOnly] _(a)_
Specification: [Limited value attributes](http://www.whatwg.org/specs/web-apps/current-work/#limited-to-only-known-values) - _defined in spec prose, not as an IDL extended attribute._
-Summary: `[ReflectOnly=<list>]` indicates that a reflected string attribute should be limited to a set of allowable values; it supplements `[Reflect]`.
+Summary: `[ReflectOnly]` indicates that a reflected string attribute should be limited to a set of allowable values; it supplements `[Reflect]`.
-Usage: The possible usage is `[ReflectOnly="A1"|...|"An"]` where A1 (up to n) are the attribute values allowed. `[ReflectOnly=<list>]` is used in combination with `[Reflect]`:
+Usage: The possible usages are `[ReflectOnly="value"]` and `[ReflectOnly=("A1",...,"An")]` where A1 (up to n) are the attribute values allowed. `[ReflectOnly]` is used in combination with `[Reflect]`:
```webidl
interface HTMLMyElement {
[Reflect, ReflectOnly="on"] attribute DOMString toggle;
- [Reflect=q, ReflectOnly="first"|"second"|"third"|"fourth"] attribute DOMString quarter;
+ [Reflect=q, ReflectOnly=("first", "second", "third", "fourth")] attribute DOMString quarter;
};
```
-The ReflectOnly attribute limits the range of values that the attribute getter can return from its reflected attribute. If the content attribute has a value that is a case-insensitive match for one of the values given in the `ReflectOnly`'s list (using "`|`" as separator), then it will be returned. To allow attribute values that use characters that go beyond what IDL identifiers may contain, string literals are used. This is a Blink syntactic extension to extended attributes.
+The ReflectOnly attribute limits the range of values that the attribute getter can return from its reflected attribute. If the content attribute has a value that is a case-insensitive match for one of `ReflectOnly`'s values, then it will be returned. To allow attribute values that use characters that go beyond what IDL identifiers may contain, string literals are used. This is a Blink syntactic extension to extended attributes.
If there is no match, the empty string will be returned. As required by the specification, no such checking is performed when the reflected IDL attribute is set.
-`[ReflectOnly=<list>]` should be used if the specification for a reflected IDL attribute says it is _"limited to only known values"_.
+`[ReflectOnly]` should be used if the specification for a reflected IDL attribute says it is _"limited to only known values"_.
### [RuntimeEnabled] _(i, m, a, c)_
@@ -1560,6 +1553,30 @@ interface HTMLFoo {
```
+### [DefaultValue] _(p)_
+
+Summary: `[DefaultValue]` allows one to specify the default values for optional arguments. This removes the need to have C++ overloads in the Blink implementation.
+
+Standard: In Web IDL, [default values for optional arguments](https://heycam.github.io/webidl/#dfn-optional-argument-default-value) are written as `optional type identifier = value`. Blink supports this but not all implementations have been updated to handle overloaded functions - see [bug 258153](https://crbug.com/258153). `[DefaultValue=Undefined]` was added to all optional parameters to preserve compatibility until the C++ implementations are updated.
+
+Usage: `[DefaultValue=Undefined]` can be specified on any optional parameter:
+
+```webidl
+interface HTMLFoo {
+ void func1(long a, long b, optional long c, optional long d);
+ void func2(long a, long b, [DefaultValue=Undefined] optional long c);
+};
+```
+
+The parameters marked with the standard Web IDL `optional` qualifier are optional, and JavaScript can omit the parameters. Obviously, if parameter X is marked with `optional` then all subsequent parameters of X should be marked with `optional`.
+
+The difference between `optional` and `[DefaultValue=Undefined]` optional is whether the Blink implementation requires overloaded methods or not: without a default value, the Blink implementation must have overloaded C++ functions, while with a default value, the Blink implementation only needs a single C++ function.
+
+In case of `func1(...)`, if JavaScript calls `func1(100, 200)`, then `HTMLFoo::func1(int a, int b)` is called in Blink. If JavaScript calls `func1(100, 200, 300)`, then `HTMLFoo::func1(int a, int b, int c)` is called in Blink. If JavaScript calls `func1(100, 200, 300, 400)`, then `HTMLFoo::func1(int a, int b, int c, int d)` is called in Blink. In other words, if the Blink implementation has overloaded methods, you can use `optional` without `[DefaultValue=Undefined]`.
+
+In case of `func2(...)` which adds `[DefaultValue=Undefined]`, if JavaScript calls `func2(100, 200)`, then it behaves as if JavaScript called `func2(100, 200, undefined)`. Consequently, `HTMLFoo::func2(int a, int b, int c)` is called in Blink. 100 is passed to `a`, 200 is passed to `b`, and 0 is passed to `c`. (A JavaScript `undefined` is converted to 0, following the value conversion rule in the Web IDL spec; if it were a DOMString parameter, it would end up as the string `"undefined"`.) In this way, Blink needs to just implement `func2(int a, int b, int c)` and needs not to implement both `func2(int a, int b)` and `func2(int a, int b, int c)`.
+
+
## Discouraged Blink-specific IDL Extended Attributes
These extended attributes are _discouraged_ - they are not deprecated, but they should be avoided and removed if possible.
diff --git a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
index 9a36e75ff2d..4d7403c2099 100644
--- a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
+++ b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -37,7 +37,7 @@ AllowShared
CEReactions
CachedAccessor
CachedAttribute=*
-CallWith=ExecutionContext|ScriptState|ScriptArguments|CurrentWindow|EnteredWindow|ThisValue
+CallWith=CurrentWindow|EnteredWindow|ExecutionContext|Isolate|ScriptState|ThisValue
CheckSecurity=Receiver|ReturnValue
Clamp
Constructor
@@ -49,7 +49,7 @@ CrossOrigin=|Getter|Setter
Custom=|Getter|Setter|LegacyCallAsFunction|PropertyGetter|PropertyEnumerator|PropertyQuery|CallPrologue|CallEpilogue
CustomConstructor
CustomElementCallbacks
-Default=Undefined
+DefaultValue=Undefined
DeprecateAs=*
DoNotCheckConstants
DoNotTestNewObject
@@ -58,6 +58,7 @@ Exposed=*
FeaturePolicy=*
FlexibleArrayBufferView
Global=*
+HighEntropy
HTMLConstructor
ImmutablePrototype
ImplementedAs=*
@@ -88,16 +89,16 @@ ReflectMissing=*
ReflectOnly=*
Replaceable
# Valid values for [RuntimeEnabled] are the Runtime Enabled Features, listed in
-# Source/platform/runtime_enabled_features.json5
+# third_party/blink/renderer/platform/runtime_enabled_features.json5
RuntimeEnabled=*
# Valid values for [RuntimeCallStatsCounter] are counters defined in
-# Source/platform/bindings/RuntimeCallStats.h
+# third_party/blink/renderer/platform/bindings/runtime_call_stats.h
RuntimeCallStatsCounter=*
SameObject
SaveSameObject
SecureContext=|*
Serializable
-SetterCallWith=ExecutionContext|ScriptState|ScriptArguments|CurrentWindow|EnteredWindow
+SetterCallWith=CurrentWindow|EnteredWindow|ExecutionContext|Isolate|ScriptState
Transferable
TreatNonObjectAsNull
TreatNullAs=EmptyString
diff --git a/chromium/third_party/blink/renderer/bindings/bindings.gni b/chromium/third_party/blink/renderer/bindings/bindings.gni
index 104cce2c56d..7dff42655b9 100644
--- a/chromium/third_party/blink/renderer/bindings/bindings.gni
+++ b/chromium/third_party/blink/renderer/bindings/bindings.gni
@@ -9,6 +9,12 @@ import("//third_party/blink/renderer/bindings/modules/v8/v8.gni")
bindings_core_v8_files =
get_path_info([
+ "core/v8/active_script_wrappable.h",
+ "core/v8/array_value.cc",
+ "core/v8/array_value.h",
+ "core/v8/binding_security.cc",
+ "core/v8/binding_security.h",
+ "core/v8/callback_promise_adapter.h",
"core/v8/custom/v8_custom_xpath_ns_resolver.cc",
"core/v8/custom/v8_custom_xpath_ns_resolver.h",
"core/v8/custom/v8_dev_tools_host_custom.cc",
@@ -26,12 +32,6 @@ bindings_core_v8_files =
"core/v8/custom/v8_shadow_root_custom.cc",
"core/v8/custom/v8_window_custom.cc",
"core/v8/custom/v8_xml_http_request_custom.cc",
- "core/v8/active_script_wrappable.h",
- "core/v8/array_value.cc",
- "core/v8/array_value.h",
- "core/v8/binding_security.cc",
- "core/v8/binding_security.h",
- "core/v8/callback_promise_adapter.h",
"core/v8/custom_wrappable_adapter.cc",
"core/v8/custom_wrappable_adapter.h",
"core/v8/dictionary.cc",
@@ -39,19 +39,19 @@ bindings_core_v8_files =
"core/v8/dictionary_helper_for_core.cc",
"core/v8/generated_code_helper.cc",
"core/v8/generated_code_helper.h",
- "core/v8/initialize_v8_extras_binding.cc",
- "core/v8/initialize_v8_extras_binding.h",
"core/v8/idl_dictionary_base.cc",
"core/v8/idl_dictionary_base.h",
"core/v8/idl_types.h",
"core/v8/idl_types_base.h",
+ "core/v8/initialize_v8_extras_binding.cc",
+ "core/v8/initialize_v8_extras_binding.h",
"core/v8/iterable.h",
"core/v8/js_based_event_listener.cc",
"core/v8/js_based_event_listener.h",
"core/v8/js_event_handler.cc",
"core/v8/js_event_handler.h",
- "core/v8/js_event_handler_for_content_attribute.h",
"core/v8/js_event_handler_for_content_attribute.cc",
+ "core/v8/js_event_handler_for_content_attribute.h",
"core/v8/js_event_listener.cc",
"core/v8/js_event_listener.h",
"core/v8/local_window_proxy.cc",
@@ -66,6 +66,7 @@ bindings_core_v8_files =
"core/v8/remote_window_proxy.cc",
"core/v8/remote_window_proxy.h",
"core/v8/retained_object_info.h",
+ "core/v8/sanitize_script_errors.h",
"core/v8/scheduled_action.cc",
"core/v8/scheduled_action.h",
"core/v8/script_controller.cc",
@@ -76,6 +77,7 @@ bindings_core_v8_files =
"core/v8/script_custom_element_definition.h",
"core/v8/script_custom_element_definition_builder.cc",
"core/v8/script_custom_element_definition_builder.h",
+ "core/v8/script_custom_element_definition_data.h",
"core/v8/script_event_listener.cc",
"core/v8/script_event_listener.h",
"core/v8/script_function.cc",
@@ -84,7 +86,6 @@ bindings_core_v8_files =
"core/v8/script_iterator.h",
"core/v8/script_module.cc",
"core/v8/script_module.h",
- "core/v8/sanitize_script_errors.h",
"core/v8/script_promise.cc",
"core/v8/script_promise.h",
"core/v8/script_promise_property.h",
@@ -103,6 +104,22 @@ bindings_core_v8_files =
"core/v8/script_streamer_thread.h",
"core/v8/script_value.cc",
"core/v8/script_value.h",
+ "core/v8/serialization/post_message_helper.cc",
+ "core/v8/serialization/post_message_helper.h",
+ "core/v8/serialization/serialization_tag.h",
+ "core/v8/serialization/serialized_color_params.cc",
+ "core/v8/serialization/serialized_color_params.h",
+ "core/v8/serialization/serialized_script_value.cc",
+ "core/v8/serialization/serialized_script_value.h",
+ "core/v8/serialization/serialized_script_value_factory.cc",
+ "core/v8/serialization/serialized_script_value_factory.h",
+ "core/v8/serialization/transferables.h",
+ "core/v8/serialization/unpacked_serialized_script_value.cc",
+ "core/v8/serialization/unpacked_serialized_script_value.h",
+ "core/v8/serialization/v8_script_value_deserializer.cc",
+ "core/v8/serialization/v8_script_value_deserializer.h",
+ "core/v8/serialization/v8_script_value_serializer.cc",
+ "core/v8/serialization/v8_script_value_serializer.h",
"core/v8/source_location.cc",
"core/v8/source_location.h",
"core/v8/to_v8_for_core.cc",
@@ -116,12 +133,12 @@ bindings_core_v8_files =
"core/v8/v8_cache_options.h",
"core/v8/v8_code_cache.cc",
"core/v8/v8_code_cache.h",
+ "core/v8/v8_context_snapshot.cc",
+ "core/v8/v8_context_snapshot.h",
"core/v8/v8_dom_configuration.cc",
"core/v8/v8_dom_configuration.h",
"core/v8/v8_embedder_graph_builder.cc",
"core/v8/v8_embedder_graph_builder.h",
- "core/v8/v8_event_listener_helper.cc",
- "core/v8/v8_event_listener_helper.h",
"core/v8/v8_event_listener_info.h",
"core/v8/v8_gc_controller.cc",
"core/v8/v8_gc_controller.h",
@@ -134,8 +151,6 @@ bindings_core_v8_files =
"core/v8/v8_initializer.h",
"core/v8/v8_intersection_observer_delegate.cc",
"core/v8/v8_intersection_observer_delegate.h",
- "core/v8/v8_throw_dom_exception.cc",
- "core/v8/v8_throw_dom_exception.h",
"core/v8/v8_iterator_result_value.cc",
"core/v8/v8_iterator_result_value.h",
"core/v8/v8_object_builder.cc",
@@ -147,9 +162,9 @@ bindings_core_v8_files =
"core/v8/v8_persistent_value_vector.h",
"core/v8/v8_script_runner.cc",
"core/v8/v8_script_runner.h",
- "core/v8/v8_context_snapshot.cc",
- "core/v8/v8_context_snapshot.h",
"core/v8/v8_string_resource.h",
+ "core/v8/v8_throw_dom_exception.cc",
+ "core/v8/v8_throw_dom_exception.h",
"core/v8/v8_v0_custom_element_lifecycle_callbacks.cc",
"core/v8/v8_v0_custom_element_lifecycle_callbacks.h",
"core/v8/v8_wasm_response_extensions.cc",
@@ -160,22 +175,8 @@ bindings_core_v8_files =
"core/v8/window_proxy_manager.h",
"core/v8/worker_or_worklet_script_controller.cc",
"core/v8/worker_or_worklet_script_controller.h",
- "core/v8/serialization/post_message_helper.cc",
- "core/v8/serialization/post_message_helper.h",
- "core/v8/serialization/serialized_color_params.cc",
- "core/v8/serialization/serialized_color_params.h",
- "core/v8/serialization/serialization_tag.h",
- "core/v8/serialization/serialized_script_value.cc",
- "core/v8/serialization/serialized_script_value.h",
- "core/v8/serialization/serialized_script_value_factory.cc",
- "core/v8/serialization/serialized_script_value_factory.h",
- "core/v8/serialization/transferables.h",
- "core/v8/serialization/unpacked_serialized_script_value.cc",
- "core/v8/serialization/unpacked_serialized_script_value.h",
- "core/v8/serialization/v8_script_value_deserializer.cc",
- "core/v8/serialization/v8_script_value_deserializer.h",
- "core/v8/serialization/v8_script_value_serializer.cc",
- "core/v8/serialization/v8_script_value_serializer.h",
+ "core/v8/world_safe_v8_reference.cc",
+ "core/v8/world_safe_v8_reference.h",
],
"abspath")
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/BUILD.gn b/chromium/third_party/blink/renderer/bindings/core/v8/BUILD.gn
index b37b8ca15c5..d45e747235c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/BUILD.gn
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/BUILD.gn
@@ -36,8 +36,6 @@ bindings_core_generated_union_type_files = [
"$bindings_core_v8_output_dir/double_or_double_or_null_sequence.h",
"$bindings_core_v8_output_dir/double_or_internal_enum.cc",
"$bindings_core_v8_output_dir/double_or_internal_enum.h",
- "$bindings_core_v8_output_dir/double_or_performance_mark_options.cc",
- "$bindings_core_v8_output_dir/double_or_performance_mark_options.h",
"$bindings_core_v8_output_dir/double_or_scroll_timeline_auto_keyword.cc",
"$bindings_core_v8_output_dir/double_or_scroll_timeline_auto_keyword.h",
"$bindings_core_v8_output_dir/double_or_string.cc",
@@ -82,10 +80,10 @@ bindings_core_generated_union_type_files = [
"$bindings_core_v8_output_dir/string_or_css_variable_reference_value.h",
"$bindings_core_v8_output_dir/string_or_double.cc",
"$bindings_core_v8_output_dir/string_or_double.h",
- "$bindings_core_v8_output_dir/string_or_double_or_performance_measure_options.cc",
- "$bindings_core_v8_output_dir/string_or_double_or_performance_measure_options.h",
"$bindings_core_v8_output_dir/string_or_element_creation_options.cc",
"$bindings_core_v8_output_dir/string_or_element_creation_options.h",
+ "$bindings_core_v8_output_dir/string_or_performance_measure_options.cc",
+ "$bindings_core_v8_output_dir/string_or_performance_measure_options.h",
"$bindings_core_v8_output_dir/string_or_string_sequence.cc",
"$bindings_core_v8_output_dir/string_or_string_sequence.h",
"$bindings_core_v8_output_dir/string_or_trusted_html.cc",
@@ -148,8 +146,8 @@ generated_core_callback_function_files = [
"$bindings_core_v8_output_dir/v8_custom_element_disabled_state_changed_callback.h",
"$bindings_core_v8_output_dir/v8_custom_element_form_associated_callback.cc",
"$bindings_core_v8_output_dir/v8_custom_element_form_associated_callback.h",
- "$bindings_core_v8_output_dir/v8_display_lock_callback.cc",
- "$bindings_core_v8_output_dir/v8_display_lock_callback.h",
+ "$bindings_core_v8_output_dir/v8_custom_element_restore_value_callback.cc",
+ "$bindings_core_v8_output_dir/v8_custom_element_restore_value_callback.h",
"$bindings_core_v8_output_dir/v8_event_handler_non_null.cc",
"$bindings_core_v8_output_dir/v8_event_handler_non_null.h",
"$bindings_core_v8_output_dir/v8_frame_request_callback.cc",
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS b/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS
new file mode 100644
index 00000000000..56c5278e151
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS
@@ -0,0 +1,4 @@
+per-file v8_wasm_response_extensions.*=ahaas@chromium.org
+
+# TEAM: blink-reviews-bindings@chromium.org
+# COMPONENT: Blink>Bindings
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc b/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc
index 1247b37e548..b720ebd7642 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc
@@ -144,10 +144,10 @@ bool CanAccessWindow(const LocalDOMWindow* accessing_window,
DOMWindow* FindWindow(v8::Isolate* isolate,
const WrapperTypeInfo* type,
v8::Local<v8::Object> holder) {
- if (V8Window::wrapper_type_info.Equals(type))
+ if (V8Window::GetWrapperTypeInfo()->Equals(type))
return V8Window::ToImpl(holder);
- if (V8Location::wrapper_type_info.Equals(type))
+ if (V8Location::GetWrapperTypeInfo()->Equals(type))
return V8Location::ToImpl(holder)->DomWindow();
// This function can handle only those types listed above.
@@ -388,7 +388,7 @@ bool BindingSecurity::ShouldAllowWrapperCreationOrThrowException(
// https://html.spec.whatwg.org/multipage/browsers.html#security-location,
// cross-origin script access to a few properties of Location is allowed.
// Location already implements the necessary security checks.
- if (wrapper_type_info->Equals(&V8Location::wrapper_type_info))
+ if (wrapper_type_info->Equals(V8Location::GetWrapperTypeInfo()))
return true;
ExceptionState exception_state(accessing_context->GetIsolate(),
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_message_channel_custom.cc b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_message_channel_custom.cc
index 29e05ce937b..1724ee5d869 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_message_channel_custom.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_message_channel_custom.cc
@@ -57,7 +57,7 @@ void V8MessageChannel::ConstructorCustom(
wrapper, ToV8(channel->port2(), wrapper, isolate));
V8SetReturnValue(info, V8DOMWrapper::AssociateObjectWithWrapper(
- isolate, channel, &wrapper_type_info, wrapper));
+ isolate, channel, GetWrapperTypeInfo(), wrapper));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
index 829ca7a3dce..492091a5094 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
@@ -33,7 +33,7 @@ void V8ReadableStream::ConstructorCustom(
auto* impl = MakeGarbageCollected<ReadableStream>();
v8::Local<v8::Object> wrapper = info.Holder();
wrapper = impl->AssociateWithWrapper(
- info.GetIsolate(), &V8ReadableStream::wrapper_type_info, wrapper);
+ info.GetIsolate(), V8ReadableStream::GetWrapperTypeInfo(), wrapper);
if (num_args >= 1) {
underlying_source =
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc
index bdc358aff38..68afcfad52f 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
@@ -30,10 +30,11 @@ void V8WritableStream::ConstructorCustom(
ScriptValue strategy = ScriptValue(ScriptState::Current(info.GetIsolate()),
v8::Undefined(info.GetIsolate()));
int num_args = info.Length();
- auto* impl = MakeGarbageCollected<WritableStream>();
+ // TODO(ricea): Switch on Blink feature.
+ auto* impl = MakeGarbageCollected<WritableStreamWrapper>();
v8::Local<v8::Object> wrapper = info.Holder();
wrapper = impl->AssociateWithWrapper(
- info.GetIsolate(), &V8WritableStream::wrapper_type_info, wrapper);
+ info.GetIsolate(), V8WritableStream::GetWrapperTypeInfo(), wrapper);
if (num_args >= 1) {
underlying_sink =
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc b/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc
index c914e8ba00c..3a4ba8ed3e9 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc
@@ -63,17 +63,23 @@ CustomWrappableAdapter* CustomWrappableAdapter::LookupInternal(
void CustomWrappableAdapter::Attach(ScriptState* script_state,
v8::Local<v8::Object> object,
- const V8PrivateProperty::Symbol& property,
- CustomWrappableAdapter* adapter) {
+ const V8PrivateProperty::Symbol& property) {
+ v8::Local<v8::Object> wrapper_object =
+ CreateAndInitializeWrapper(script_state);
+ property.Set(object, wrapper_object);
+}
+
+v8::Local<v8::Object> CustomWrappableAdapter::CreateAndInitializeWrapper(
+ ScriptState* script_state) {
DCHECK(wrapper_.IsEmpty());
v8::Isolate* isolate = script_state->GetIsolate();
v8::Local<v8::Object> wrapper_object = V8DOMWrapper::CreateWrapper(
isolate, script_state->GetContext()->Global(), &custom_wrappable_info);
V8DOMWrapper::AssociateObjectWithWrapper(
- isolate, adapter, &custom_wrappable_info, wrapper_object);
- property.Set(object, wrapper_object);
+ isolate, this, &custom_wrappable_info, wrapper_object);
wrapper_.Set(isolate, wrapper_object);
custom_wrappable_info.ConfigureWrapper(&wrapper_.Get());
+ return wrapper_object;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h b/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h
index 2a5e4063ae7..74507081f74 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h
@@ -35,11 +35,17 @@ class CORE_EXPORT CustomWrappableAdapter : public CustomWrappable {
return static_cast<T*>(LookupInternal(object, property));
}
- // Attaches a given |adapter| to |object|'s |property|.
+ // Attaches |this| adapter to |object|'s |property|.
void Attach(ScriptState*,
v8::Local<v8::Object> object,
- const V8PrivateProperty::Symbol& property,
- CustomWrappableAdapter* adapter);
+ const V8PrivateProperty::Symbol& property);
+
+ // Creates and sets up the JS wrapper object. May only be called once. Returns
+ // the wrapper object.
+ //
+ // This method can be used when the wrapper is needed to actually create the
+ // object that it should be attached to. Prefer |Attach| when possible.
+ v8::Local<v8::Object> CreateAndInitializeWrapper(ScriptState*);
~CustomWrappableAdapter() override = default;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc b/chromium/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc
index b8812eeebee..7dad309e5c9 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc
@@ -159,7 +159,7 @@ bool DictionaryHelper::Get(const Dictionary& dictionary,
int64_t int64_value;
if (!v8_value->IntegerValue(dictionary.V8Context()).To(&int64_value))
return false;
- value = int64_value;
+ value = static_cast<unsigned long>(int64_value);
return true;
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc b/chromium/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
index f261dc2d84c..a7907b1db6c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
@@ -44,14 +44,14 @@ constexpr WebFeatureIdNameLookupEntry web_feature_id_name_lookup_table[] = {
class CountUseForBindings : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
- auto* self = new CountUseForBindings(script_state);
+ auto* self = MakeGarbageCollected<CountUseForBindings>(script_state);
return self->BindToV8Function();
}
- private:
explicit CountUseForBindings(ScriptState* script_state)
: ScriptFunction(script_state) {}
+ private:
ScriptValue Call(ScriptValue value) override {
String string_id;
if (!value.ToString(string_id)) {
@@ -131,10 +131,12 @@ void AddOriginals(ScriptState* script_state, v8::Local<v8::Object> binding) {
};
v8::Local<v8::Value> message_port = ObjectGet(global, "MessagePort");
+ v8::Local<v8::Value> dom_exception = ObjectGet(global, "DOMException");
- // Some Worklets don't have MessagePort. In this case, serialization will
- // be disabled.
- if (message_port->IsUndefined())
+ // Most Worklets don't have MessagePort. In this case, serialization will
+ // fail. AudioWorklet has MessagePort but no DOMException, so it can't use
+ // serialization for now.
+ if (message_port->IsUndefined() || dom_exception->IsUndefined())
return;
v8::Local<v8::Value> event_target_prototype =
@@ -153,7 +155,6 @@ void AddOriginals(ScriptState* script_state, v8::Local<v8::Object> binding) {
Bind("MessageEvent_data_get", GetOwnPDGet(message_event_prototype, "data"));
- v8::Local<v8::Value> dom_exception = ObjectGet(global, "DOMException");
Bind("DOMException", dom_exception);
v8::Local<v8::Value> dom_exception_prototype = GetPrototype(dom_exception);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc b/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
index c82ca3efb48..07591f1ecb9 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
@@ -4,13 +4,121 @@
#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
+#include <utility>
+
#include "base/logging.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
namespace blink {
+namespace {
+
+class IsolatedWorldCSPDelegate final
+ : public GarbageCollectedFinalized<IsolatedWorldCSPDelegate>,
+ public ContentSecurityPolicyDelegate {
+ USING_GARBAGE_COLLECTED_MIXIN(IsolatedWorldCSPDelegate);
+
+ public:
+ IsolatedWorldCSPDelegate(Document& document,
+ scoped_refptr<SecurityOrigin> security_origin,
+ bool apply_policy)
+ : document_(&document),
+ security_origin_(std::move(security_origin)),
+ apply_policy_(apply_policy) {
+ DCHECK(security_origin_);
+ }
+
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(document_);
+ ContentSecurityPolicyDelegate::Trace(visitor);
+ }
+
+ const SecurityOrigin* GetSecurityOrigin() override {
+ return security_origin_.get();
+ }
+
+ const KURL& Url() const override {
+ // This is used to populate violation data's violation url. See
+ // https://w3c.github.io/webappsec-csp/#violation-url.
+ // TODO(crbug.com/916885): Figure out if we want to support violation
+ // reporting for isolated world CSPs.
+ DEFINE_STATIC_LOCAL(KURL, g_empty_url, ());
+ return g_empty_url;
+ }
+
+ // Isolated world CSPs don't support these directives: "sandbox",
+ // "treat-as-public-address", "trusted-types" and "upgrade-insecure-requests".
+ // These directives depend on ExecutionContext for their implementation and
+ // since isolated worlds don't have their own ExecutionContext, these are not
+ // supported.
+ void SetSandboxFlags(SandboxFlags) override {}
+ void SetAddressSpace(mojom::IPAddressSpace) override {}
+ void SetRequireTrustedTypes() override {}
+ void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override {}
+
+ // TODO(crbug.com/916885): Figure out if we want to support violation
+ // reporting for isolated world CSPs.
+ std::unique_ptr<SourceLocation> GetSourceLocation() override {
+ return nullptr;
+ }
+ base::Optional<uint16_t> GetStatusCode() override { return base::nullopt; }
+ String GetDocumentReferrer() override { return g_empty_string; }
+ void DispatchViolationEvent(const SecurityPolicyViolationEventInit&,
+ Element*) override {
+ DCHECK(apply_policy_);
+ }
+ void PostViolationReport(const SecurityPolicyViolationEventInit&,
+ const String& stringified_report,
+ bool is_frame_ancestors_violation,
+ const Vector<String>& report_endpoints,
+ bool use_reporting_api) override {
+ DCHECK(apply_policy_);
+ }
+
+ void Count(WebFeature feature) override {
+ // Log the features used by isolated world CSPs on the underlying Document.
+ UseCounter::Count(document_, feature);
+ }
+
+ void AddConsoleMessage(ConsoleMessage* console_message) override {
+ // Add console messages on the underlying Document.
+ document_->AddConsoleMessage(console_message);
+ }
+
+ void DisableEval(const String& error_message) override {
+ // TODO(crbug.com/896041): Implement this.
+ NOTIMPLEMENTED();
+ }
+
+ void ReportBlockedScriptExecutionToInspector(
+ const String& directive_text) override {
+ // TODO(crbug.com/896041): Figure out if this needs to be implemented.
+ NOTIMPLEMENTED();
+ }
+
+ void DidAddContentSecurityPolicies(
+ const blink::WebVector<WebContentSecurityPolicy>&) override {}
+
+ private:
+ const Member<Document> document_;
+ const scoped_refptr<SecurityOrigin> security_origin_;
+
+ // Whether the 'IsolatedWorldCSP' feature is enabled, and we are applying the
+ // CSP provided by the isolated world.
+ const bool apply_policy_;
+};
+
+} // namespace
+
// static
IsolatedWorldCSP& IsolatedWorldCSP::Get() {
DCHECK(IsMainThread());
@@ -18,15 +126,23 @@ IsolatedWorldCSP& IsolatedWorldCSP::Get() {
return g_isolated_world_csp;
}
-void IsolatedWorldCSP::SetContentSecurityPolicy(int world_id,
- const String& policy) {
+void IsolatedWorldCSP::SetContentSecurityPolicy(
+ int world_id,
+ const String& policy,
+ scoped_refptr<SecurityOrigin> self_origin) {
DCHECK(IsMainThread());
DCHECK(DOMWrapperWorld::IsIsolatedWorldId(world_id));
- if (policy.IsEmpty())
+ if (!policy) {
csp_map_.erase(world_id);
- else
- csp_map_.Set(world_id, true);
+ return;
+ }
+
+ DCHECK(self_origin);
+ PolicyInfo policy_info;
+ policy_info.policy = policy;
+ policy_info.self_origin = std::move(self_origin);
+ csp_map_.Set(world_id, policy_info);
}
bool IsolatedWorldCSP::HasContentSecurityPolicy(int world_id) const {
@@ -34,7 +150,38 @@ bool IsolatedWorldCSP::HasContentSecurityPolicy(int world_id) const {
DCHECK(DOMWrapperWorld::IsIsolatedWorldId(world_id));
auto it = csp_map_.find(world_id);
- return it != csp_map_.end() ? it->value : false;
+ return it != csp_map_.end();
+}
+
+ContentSecurityPolicy* IsolatedWorldCSP::CreateIsolatedWorldCSP(
+ Document& document,
+ int world_id) {
+ DCHECK(IsMainThread());
+ DCHECK(DOMWrapperWorld::IsIsolatedWorldId(world_id));
+
+ auto it = csp_map_.find(world_id);
+ if (it == csp_map_.end())
+ return nullptr;
+
+ const String& policy = it->value.policy;
+ scoped_refptr<SecurityOrigin> self_origin = it->value.self_origin;
+
+ const bool apply_policy = RuntimeEnabledFeatures::IsolatedWorldCSPEnabled();
+
+ ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+
+ IsolatedWorldCSPDelegate* delegate =
+ MakeGarbageCollected<IsolatedWorldCSPDelegate>(
+ document, std::move(self_origin), apply_policy);
+ csp->BindToDelegate(*delegate);
+
+ if (apply_policy) {
+ csp->AddPolicyFromHeaderValue(policy,
+ kContentSecurityPolicyHeaderTypeEnforce,
+ kContentSecurityPolicyHeaderSourceHTTP);
+ }
+
+ return csp;
}
IsolatedWorldCSP::IsolatedWorldCSP() = default;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h b/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h
index 99c61b6fdc7..615cf1d1868 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h
@@ -7,11 +7,15 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
+class ContentSecurityPolicy;
+class Document;
+
// A singleton storing content security policy for each isolated world.
class CORE_EXPORT IsolatedWorldCSP {
public:
@@ -19,21 +23,35 @@ class CORE_EXPORT IsolatedWorldCSP {
// Associated an isolated world with a Content Security Policy. Resources
// embedded into the main world's DOM from script executed in an isolated
- // world should be restricted based on the isolated world's DOM, not the
+ // world should be restricted based on the isolated world's CSP, not the
// main world's.
//
- // FIXME: Right now, resource injection simply bypasses the main world's
- // DOM. More work is necessary to allow the isolated world's policy to be
- // applied correctly.
- void SetContentSecurityPolicy(int world_id, const String& policy);
+ // TODO(crbug.com/896041): Right now, resource injection simply bypasses the
+ // main world's CSP. More work is necessary to allow the isolated world's
+ // policy to be applied correctly.
+ // Note: If |policy| is null, the PolicyInfo for |world_id| is cleared. If
+ // |policy| is specified, |self_origin| must not be null.
+ void SetContentSecurityPolicy(int world_id,
+ const String& policy,
+ scoped_refptr<SecurityOrigin> self_origin);
bool HasContentSecurityPolicy(int world_id) const;
+ // Creates a ContentSecurityPolicy instance for the given isolated |world_id|
+ // and |document|. Returns null if no ContentSecurityPolicy is defined for the
+ // given isolated |world_id|.
+ ContentSecurityPolicy* CreateIsolatedWorldCSP(Document& document,
+ int world_id);
+
private:
+ struct PolicyInfo {
+ String policy;
+ scoped_refptr<SecurityOrigin> self_origin;
+ };
+
IsolatedWorldCSP();
- // Map from the isolated world |world_id| to a bool denoting if it has a CSP
- // defined.
- HashMap<int, bool> csp_map_;
+ // Map from the isolated world |world_id| to its PolicyInfo.
+ HashMap<int, PolicyInfo> csp_map_;
DISALLOW_COPY_AND_ASSIGN(IsolatedWorldCSP);
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc b/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
index d31f6da9421..c3bacc5e748 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
@@ -11,13 +11,12 @@
#include "third_party/blink/renderer/core/dom/document_parser.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
#include "third_party/blink/renderer/platform/instance_counters.h"
namespace blink {
-JSBasedEventListener::JSBasedEventListener(ListenerType listener_type)
- : EventListener(listener_type) {
- DCHECK(IsJSBased());
+JSBasedEventListener::JSBasedEventListener() {
if (IsMainThread()) {
InstanceCounters::IncrementCounter(
InstanceCounters::kJSEventListenerCounter);
@@ -84,10 +83,11 @@ void JSBasedEventListener::Invoke(
return;
}
- ScriptState* script_state_of_listener = GetScriptState();
- DCHECK(script_state_of_listener);
+ ScriptState* script_state_of_listener = GetScriptStateOrReportError("invoke");
+ if (!script_state_of_listener)
+ return; // The error is already reported.
if (!script_state_of_listener->ContextIsValid())
- return;
+ return; // Silently fail.
ScriptState::Scope listener_script_state_scope(script_state_of_listener);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h b/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h
index 11b430b15fc..1e47648243c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "v8/include/v8.h"
namespace blink {
@@ -14,6 +15,7 @@ namespace blink {
class DOMWrapperWorld;
class Event;
class EventTarget;
+class ScriptState;
class SourceLocation;
// |JSBasedEventListener| is the base class for JS-based event listeners,
@@ -22,27 +24,6 @@ class SourceLocation;
// implements the common features.
class CORE_EXPORT JSBasedEventListener : public EventListener {
public:
- static const JSBasedEventListener* Cast(const EventListener* listener) {
- return listener && listener->IsJSBased()
- ? static_cast<const JSBasedEventListener*>(listener)
- : nullptr;
- }
-
- static JSBasedEventListener* Cast(EventListener* listener) {
- return const_cast<JSBasedEventListener*>(
- Cast(const_cast<const EventListener*>(listener)));
- }
-
- // TODO(bindings): consider to remove this (and use GetListenerObject()
- // instead) because this method is used in mostly only generated classes.
- static v8::Local<v8::Value> GetListenerOrNull(v8::Isolate* isolate,
- EventTarget* event_target,
- EventListener* listener) {
- if (auto* v8_listener = Cast(listener))
- return v8_listener->GetListenerObject(*event_target);
- return v8::Null(isolate);
- }
-
~JSBasedEventListener() override;
// blink::EventListener overrides:
@@ -70,10 +51,24 @@ class CORE_EXPORT JSBasedEventListener : public EventListener {
virtual std::unique_ptr<SourceLocation> GetSourceLocation(EventTarget&);
+ // Helper functions for DowncastTraits.
+ bool IsJSBasedEventListener() const override { return true; }
+ virtual bool IsJSEventListener() const { return false; }
+ virtual bool IsJSEventHandler() const { return false; }
+
protected:
- explicit JSBasedEventListener(ListenerType);
+ JSBasedEventListener();
+
virtual v8::Isolate* GetIsolate() const = 0;
+ // Returns the ScriptState of the relevant realm of the callback object.
+ // Must be used only when it's sure that the callback object is the same
+ // origin-domain.
virtual ScriptState* GetScriptState() const = 0;
+ // Returns the ScriptState of the relevant realm of the callback object iff
+ // the callback is the same origin-domain. Otherwise, reports the error and
+ // returns nullptr.
+ virtual ScriptState* GetScriptStateOrReportError(
+ const char* operation) const = 0;
virtual DOMWrapperWorld& GetWorld() const = 0;
private:
@@ -88,6 +83,13 @@ class CORE_EXPORT JSBasedEventListener : public EventListener {
v8::Local<v8::Value> js_event) = 0;
};
+template <>
+struct DowncastTraits<JSBasedEventListener> {
+ static bool AllowFrom(const EventListener& event_listener) {
+ return event_listener.IsJSBasedEventListener();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_JS_BASED_EVENT_LISTENER_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
index 39c41dc88a7..ab11c080eaa 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
@@ -13,6 +13,16 @@
namespace blink {
+// static
+JSEventHandler* JSEventHandler::CreateOrNull(v8::Local<v8::Value> value,
+ HandlerType type) {
+ if (!value->IsObject())
+ return nullptr;
+
+ return MakeGarbageCollected<JSEventHandler>(
+ V8EventHandlerNonNull::Create(value.As<v8::Object>()), type);
+}
+
v8::Local<v8::Value> JSEventHandler::GetEffectiveFunction(EventTarget& target) {
v8::Local<v8::Value> v8_listener = GetListenerObject(target);
if (!v8_listener.IsEmpty() && v8_listener->IsFunction())
@@ -20,10 +30,8 @@ v8::Local<v8::Value> JSEventHandler::GetEffectiveFunction(EventTarget& target) {
return v8::Undefined(GetIsolate());
}
-void JSEventHandler::SetCompiledHandler(
- ScriptState* script_state,
- v8::Local<v8::Function> listener,
- const V8PrivateProperty::Symbol& property) {
+void JSEventHandler::SetCompiledHandler(ScriptState* incumbent_script_state,
+ v8::Local<v8::Function> listener) {
DCHECK(!HasCompiledHandler());
// https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler
@@ -36,9 +44,8 @@ void JSEventHandler::SetCompiledHandler(
// content attribute gets lazily compiled. This context is the same one of the
// relevant realm of |listener| and its event target.
v8::Context::BackupIncumbentScope backup_incumbent_scope(
- script_state->GetContext());
+ incumbent_script_state->GetContext());
event_handler_ = V8EventHandlerNonNull::Create(listener);
- Attach(script_state, listener, property, this);
}
// https://html.spec.whatwg.org/C/webappapis.html#the-event-handler-processing-algorithm
@@ -104,15 +111,8 @@ void JSEventHandler::InvokeInternal(EventTarget& event_target,
arguments = {ScriptValue::From(script_state_of_listener, js_event)};
}
- const bool is_beforeunload_event =
- event.IsBeforeUnloadEvent() &&
- event.type() == event_type_names::kBeforeunload;
- const bool is_print_event =
- // TODO(yukishiino): Should check event.Is{Before,After}PrintEvent.
- event.type() == event_type_names::kBeforeprint ||
- event.type() == event_type_names::kAfterprint;
if (!event_handler_->IsRunnableOrThrowException(
- (is_beforeunload_event || is_print_event)
+ event.ShouldDispatchEvenWhenExecutionContextIsPaused()
? V8EventHandlerNonNull::IgnorePause::kIgnore
: V8EventHandlerNonNull::IgnorePause::kDontIgnore)) {
return;
@@ -164,6 +164,9 @@ void JSEventHandler::InvokeInternal(EventTarget& event_target,
// then return value will never be false, since in such cases
// return value will have been coerced into either null or a
// DOMString.
+ const bool is_beforeunload_event =
+ event.IsBeforeUnloadEvent() &&
+ event.type() == event_type_names::kBeforeunload;
if (is_beforeunload_event) {
if (result_for_beforeunload) {
event.preventDefault();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.h b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.h
index 65214a8cff3..891b8664d66 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler.h
@@ -25,35 +25,31 @@ class CORE_EXPORT JSEventHandler : public JSBasedEventListener {
kOnBeforeUnloadEventHandler,
};
- static JSEventHandler* Create(ScriptState* script_state,
- v8::Local<v8::Object> listener,
- const V8PrivateProperty::Symbol& property,
- HandlerType type) {
- return MakeGarbageCollected<JSEventHandler>(script_state, listener,
- property, type);
+ // TODO(bindings): Consider to remove these two helper functions. These are
+ // only used by generated bindings code (OnxxxAttribute{Getter,Setter}), and
+ // it should be implemented based on V8EventHandlerNonNull.
+ static JSEventHandler* CreateOrNull(v8::Local<v8::Value>, HandlerType);
+ static v8::Local<v8::Value> AsV8Value(v8::Isolate* isolate,
+ EventTarget* event_target,
+ EventListener* listener) {
+ if (JSEventHandler* event_handler = DynamicTo<JSEventHandler>(listener)) {
+ return event_handler->GetListenerObject(*event_target);
+ }
+ return v8::Null(isolate);
}
- JSEventHandler(ScriptState* script_state,
- v8::Local<v8::Object> listener,
- const V8PrivateProperty::Symbol& property,
- HandlerType type)
- : JSBasedEventListener(kJSEventHandlerType),
- event_handler_(V8EventHandlerNonNull::Create(listener)),
- type_(type) {
- Attach(script_state, listener, property, this);
- }
-
- explicit JSEventHandler(HandlerType type)
- : JSBasedEventListener(kJSEventHandlerType), type_(type) {}
+ explicit JSEventHandler(V8EventHandlerNonNull* event_handler,
+ HandlerType type)
+ : event_handler_(event_handler), type_(type) {}
// blink::CustomWrappable overrides:
void Trace(blink::Visitor* visitor) override;
// blink::EventListener overrides:
- bool operator==(const EventListener& other) const override {
+ bool IsEventHandler() const final { return true; }
+ bool Matches(const EventListener& other) const override {
return this == &other;
}
- bool IsEventHandler() const final { return true; }
// blink::JSBasedEventListener overrides:
// TODO(crbug.com/881688): remove empty check for this method. This method
@@ -63,7 +59,12 @@ class CORE_EXPORT JSEventHandler : public JSBasedEventListener {
}
v8::Local<v8::Value> GetEffectiveFunction(EventTarget&) override;
+ // Helper functions for DowncastTraits.
+ bool IsJSEventHandler() const override { return true; }
+
protected:
+ explicit JSEventHandler(HandlerType type) : type_(type) {}
+
// blink::JSBasedEventListener override:
v8::Isolate* GetIsolate() const override {
return event_handler_->GetIsolate();
@@ -71,15 +72,19 @@ class CORE_EXPORT JSEventHandler : public JSBasedEventListener {
ScriptState* GetScriptState() const override {
return event_handler_->CallbackRelevantScriptState();
}
+ ScriptState* GetScriptStateOrReportError(
+ const char* operation) const override {
+ return event_handler_->CallbackRelevantScriptStateOrReportError(
+ "EventHandler", operation);
+ }
DOMWrapperWorld& GetWorld() const override {
- return event_handler_->CallbackRelevantScriptState()->World();
+ return event_handler_->GetWorld();
}
// Initializes |event_handler_| with |listener|. This method must be used only
// when content attribute gets lazily compiled.
- void SetCompiledHandler(ScriptState* script_state,
- v8::Local<v8::Function> listener,
- const V8PrivateProperty::Symbol& property);
+ void SetCompiledHandler(ScriptState* incumbent_script_state,
+ v8::Local<v8::Function> listener);
bool HasCompiledHandler() const { return event_handler_; }
@@ -103,6 +108,20 @@ class CORE_EXPORT JSEventHandler : public JSBasedEventListener {
const HandlerType type_;
};
+template <>
+struct DowncastTraits<JSEventHandler> {
+ static bool AllowFrom(const EventListener& event_listener) {
+ if (const JSBasedEventListener* js_based_event_listener =
+ DynamicTo<JSBasedEventListener>(event_listener)) {
+ return js_based_event_listener->IsJSEventHandler();
+ }
+ return false;
+ }
+ static bool AllowFrom(const JSBasedEventListener& event_listener) {
+ return event_listener.IsJSEventHandler();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_JS_EVENT_HANDLER_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
index 005f2dbf0b1..cfc41316c7b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
@@ -54,22 +54,29 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
// object, let element be null, and document be eventTarget's associated
// Document.
Element* element = nullptr;
+ const LocalDOMWindow* window = nullptr;
Document* document = nullptr;
- Node* node = event_target.ToNode();
- const DOMWindow* window = event_target.ToDOMWindow();
- if (node && node->IsElementNode()) {
- element = ToElement(node);
- document = &node->GetDocument();
- } else if (node && node->IsDocumentNode()) {
- // Attributes for |blink::HTMLBodyElement| is treated as ones for
- // |blink::Document| unlike the definition in standards.
- document = &node->GetDocument();
+ if (Node* node = event_target.ToNode()) {
+ if (node->IsDocumentNode()) {
+ // Some of content attributes for |HTMLBodyElement| are treated as ones
+ // for |Document| unlike the definition in HTML standard. Those content
+ // attributes are not listed in the Window-reflecting body element event
+ // handler set.
+ // https://html.spec.whatwg.org/C/#window-reflecting-body-element-event-handler-set
+ document = &node->GetDocument();
+ } else {
+ element = ToElement(node);
+ document = &node->GetDocument();
+ }
+ // EventTarget::GetExecutionContext() sometimes returns the document which
+ // created the EventTarget, and sometimes returns the document to which
+ // the EventTarget is currently attached. The former might be different
+ // from |document|.
} else {
- // TODO(crbug.com/891635): Add these checks here:
- // DCHECK(window);
- // DCHECK(event_target.ToLocalDOMWindow());
- // DCHECK_EQ(event_target.ToLocalDOMWindow()->document(), document);
- document = To<Document>(execution_context_of_event_target);
+ window = event_target.ToLocalDOMWindow();
+ DCHECK(window);
+ document = window->document();
+ DCHECK_EQ(document, To<Document>(execution_context_of_event_target));
}
DCHECK(document);
@@ -83,7 +90,7 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
v8::Context::Scope event_target_context_scope(v8_context_of_event_target);
// Step 2. If scripting is disabled for document, then return null.
- if (!document->AllowInlineEventHandler(node, this, source_url_,
+ if (!document->AllowInlineEventHandler(element, this, source_url_,
position_.line_))
return v8::Null(GetIsolate());
@@ -126,7 +133,7 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
// SVG requires to introduce evt as an alias to event in event handlers.
// See ANNOTATION 3: https://www.w3.org/TR/SVG/interact.html#SVGEvents
parameter_list[parameter_list_size++] =
- V8String(isolate, node && node->IsSVGElement() ? "evt" : "event");
+ V8String(isolate, element && element->IsSVGElement() ? "evt" : "event");
parameter_list[parameter_list_size++] = V8String(isolate, "source");
parameter_list[parameter_list_size++] = V8String(isolate, "lineno");
parameter_list[parameter_list_size++] = V8String(isolate, "colno");
@@ -135,7 +142,7 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
// SVG requires to introduce evt as an alias to event in event handlers.
// See ANNOTATION 3: https://www.w3.org/TR/SVG/interact.html#SVGEvents
parameter_list[parameter_list_size++] =
- V8String(isolate, node && node->IsSVGElement() ? "evt" : "event");
+ V8String(isolate, element && element->IsSVGElement() ? "evt" : "event");
}
DCHECK_LE(parameter_list_size, base::size(parameter_list));
@@ -159,8 +166,7 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
V8String(isolate, source_url_),
v8::Integer::New(isolate, position_.line_.ZeroBasedInt()),
v8::Integer::New(isolate, position_.column_.ZeroBasedInt()),
- // TODO(yukiy): consider which value should be passed here.
- v8::True(isolate));
+ v8::True(isolate)); // True as |SanitizeScriptErrors::kDoNotSanitize|
v8::ScriptCompiler::Source source(V8String(isolate, script_body_), origin);
v8::Local<v8::Function> compiled_function;
@@ -188,9 +194,7 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
// EventHandler callback function object whose object reference is function
// and whose callback context is settings object.
compiled_function->SetName(V8String(isolate, function_name_));
- SetCompiledHandler(
- script_state_of_event_target, compiled_function,
- V8PrivateProperty::GetCustomWrappableEventHandler(GetIsolate()));
+ SetCompiledHandler(script_state_of_event_target, compiled_function);
return JSEventHandler::GetListenerObject(event_target);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc
index ba7f69cd0fa..0bcdc0b7afe 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc
@@ -48,17 +48,8 @@ void JSEventListener::InvokeInternal(EventTarget&,
v8::Local<v8::Value> js_event) {
// Step 10: Call a listener with event's currentTarget as receiver and event
// and handle errors if thrown.
- const bool is_beforeunload_event =
- event.IsBeforeUnloadEvent() &&
- event.type() == event_type_names::kBeforeunload;
- const bool is_print_event =
- // TODO(yukishiino): Should check event.Is{Before,After}PrintEvent.
- event.type() == event_type_names::kBeforeprint ||
- event.type() == event_type_names::kAfterprint;
- const bool is_media_query_list_event =
- event.InterfaceName() == event_interface_names::kMediaQueryListEvent;
if (!event_listener_->IsRunnableOrThrowException(
- (is_beforeunload_event || is_print_event || is_media_query_list_event)
+ event.ShouldDispatchEvenWhenExecutionContextIsPaused()
? V8EventListener::IgnorePause::kIgnore
: V8EventListener::IgnorePause::kDontIgnore)) {
return;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.h b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.h
index a31902f48ce..fb9509017c1 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_listener.h
@@ -15,21 +15,12 @@ namespace blink {
// https://dom.spec.whatwg.org/#callbackdef-eventlistener
class CORE_EXPORT JSEventListener final : public JSBasedEventListener {
public:
- static JSEventListener* Create(ScriptState* script_state,
- v8::Local<v8::Object> listener,
- const V8PrivateProperty::Symbol& property) {
- return MakeGarbageCollected<JSEventListener>(script_state, listener,
- property);
+ static JSEventListener* CreateOrNull(V8EventListener* listener) {
+ return listener ? MakeGarbageCollected<JSEventListener>(listener) : nullptr;
}
- JSEventListener(ScriptState* script_state,
- v8::Local<v8::Object> listener,
- const V8PrivateProperty::Symbol& property)
- : JSBasedEventListener(kJSEventListenerType),
- event_listener_(V8EventListener::CreateOrNull(listener)) {
- DCHECK(event_listener_);
- Attach(script_state, listener, property, this);
- }
+ explicit JSEventListener(V8EventListener* listener)
+ : event_listener_(listener) {}
// blink::CustomWrappable overrides:
void Trace(blink::Visitor*) override;
@@ -40,11 +31,10 @@ class CORE_EXPORT JSEventListener final : public JSBasedEventListener {
// multiple CallbackInterfaceBase objects that have the same
// |CallbackInterfaceBase::callback_object_| but have different
// |CallbackInterfaceBase::incumbent_script_state_|s.
- bool operator==(const EventListener& other) const override {
- if (other.GetType() != kJSEventListenerType)
- return false;
- return event_listener_->HasTheSameCallbackObject(
- *static_cast<const JSEventListener*>(&other)->event_listener_);
+ bool Matches(const EventListener& other) const override {
+ const auto* other_listener = DynamicTo<JSEventListener>(other);
+ return other_listener && event_listener_->HasTheSameCallbackObject(
+ *other_listener->event_listener_);
}
// blink::JSBasedEventListener overrides:
@@ -55,6 +45,9 @@ class CORE_EXPORT JSEventListener final : public JSBasedEventListener {
}
v8::Local<v8::Value> GetEffectiveFunction(EventTarget&) override;
+ // Helper functions for DowncastTraits.
+ bool IsJSEventListener() const override { return true; }
+
protected:
// blink::JSBasedEventListener overrides:
v8::Isolate* GetIsolate() const override {
@@ -63,8 +56,13 @@ class CORE_EXPORT JSEventListener final : public JSBasedEventListener {
ScriptState* GetScriptState() const override {
return event_listener_->CallbackRelevantScriptState();
}
+ ScriptState* GetScriptStateOrReportError(
+ const char* operation) const override {
+ return event_listener_->CallbackRelevantScriptStateOrReportError(
+ "EventListener", operation);
+ }
DOMWrapperWorld& GetWorld() const override {
- return event_listener_->CallbackRelevantScriptState()->World();
+ return event_listener_->GetWorld();
}
private:
@@ -76,6 +74,14 @@ class CORE_EXPORT JSEventListener final : public JSBasedEventListener {
const TraceWrapperMember<V8EventListener> event_listener_;
};
+template <>
+struct DowncastTraits<JSEventListener> {
+ static bool AllowFrom(const EventListener& event_listener) {
+ auto* js_based = DynamicTo<JSBasedEventListener>(event_listener);
+ return js_based && js_based->IsJSEventListener();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_JS_EVENT_LISTENER_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
index b43ca24b259..9c3e848f01a 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -73,9 +73,19 @@ void LocalWindowProxy::Trace(blink::Visitor* visitor) {
void LocalWindowProxy::DisposeContext(Lifecycle next_status,
FrameReuseStatus frame_reuse_status) {
- DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached ||
+ DCHECK(next_status == Lifecycle::kForciblyPurgeV8Memory ||
+ next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetached);
+ // If the current lifecycle is kForciblyPurgeV8Memory, the next state should
+ // be kGlobalObjectIsDetached. The necessary operations are already done in
+ // kForciblyPurgeMemory and thus can return here.
+ if (lifecycle_ == Lifecycle::kForciblyPurgeV8Memory) {
+ DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached);
+ lifecycle_ = next_status;
+ return;
+ }
+
if (lifecycle_ != Lifecycle::kContextIsInitialized)
return;
@@ -86,8 +96,8 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
// it returns.
GetFrame()->Client()->WillReleaseScriptContext(context, world_->GetWorldId());
MainThreadDebugger::Instance()->ContextWillBeDestroyed(script_state_);
-
- if (next_status == Lifecycle::kGlobalObjectIsDetached) {
+ if (next_status == Lifecycle::kForciblyPurgeV8Memory ||
+ next_status == Lifecycle::kGlobalObjectIsDetached) {
// Clean up state on the global proxy, which will be reused.
if (!global_proxy_.IsEmpty()) {
CHECK(global_proxy_ == context->Global());
@@ -132,6 +142,9 @@ void LocalWindowProxy::Initialize() {
("Blink.Binding.InitializeNonMainLocalWindowProxy", 0, 10000000, 50));
ScopedUsHistogramTimer timer(GetFrame()->IsMainFrame() ? main_frame_hist
: non_main_frame_hist);
+ // TODO(alph): Remove this temporary code for debugging
+ // https://crbug.com/728693.
+ CHECK(!GetFrame()->IsProvisional());
ScriptForbiddenScope::AllowUserAgentScript allow_script;
// Inspector may request V8 interruption to process DevTools protocol
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits.h b/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits.h
index a29ab59dbba..66ae3276790 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits.h
@@ -56,11 +56,6 @@ struct NativeValueTraitsBase<
// return toInt32(isolate, value, exceptionState, NormalConversion);
// }
// }
-//
-// Note that there exist some specializations (particularly in V8Binding.h) for
-// which T actually represents the final C++ type that a JavaScript value
-// should be converted to. Introducing new specializations of this kind is
-// discouraged.
template <typename T, typename SFINAEHelper = void>
struct NativeValueTraits;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h b/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
index ca71a4f0458..7b28cf760ba 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
@@ -28,11 +28,6 @@ struct CORE_EXPORT NativeValueTraits<IDLBoolean>
};
// Integers
-//
-// All integer specializations offer a second nativeValue() besides the default
-// one: it takes an IntegerConversionConfiguration argument to let callers
-// specify how the integers should be converted. The default nativeValue()
-// overload will always use NormalConversion.
template <>
struct CORE_EXPORT NativeValueTraits<IDLByte>
: public NativeValueTraitsBase<IDLByte> {
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc b/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
index dcf2acf1ce4..4e20acf894c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
@@ -51,13 +51,24 @@ RemoteWindowProxy::RemoteWindowProxy(v8::Isolate* isolate,
void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
FrameReuseStatus) {
- DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached ||
+ DCHECK(next_status == Lifecycle::kForciblyPurgeV8Memory ||
+ next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetached);
+ // If the current lifecycle is kForciblyPurgeV8Memory, the next state should
+ // be kGlobalObjectIsDetached. The necessary operations are already done in
+ // kForciblyPurgeMemory and thus can return here.
+ if (lifecycle_ == Lifecycle::kForciblyPurgeV8Memory) {
+ DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached);
+ lifecycle_ = next_status;
+ return;
+ }
+
if (lifecycle_ != Lifecycle::kContextIsInitialized)
return;
- if (next_status == Lifecycle::kGlobalObjectIsDetached &&
+ if ((next_status == Lifecycle::kForciblyPurgeV8Memory ||
+ next_status == Lifecycle::kGlobalObjectIsDetached) &&
!global_proxy_.IsEmpty()) {
global_proxy_.Get().SetWrapperClassId(0);
V8DOMWrapper::ClearNativeInfo(GetIsolate(),
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h b/chromium/third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h
index d718c74b0f8..b6aba6544ec 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h
@@ -26,7 +26,7 @@ namespace blink {
enum class SanitizeScriptErrors {
// "muted errors" is false
kDoNotSanitize,
- // *muted errors" is true
+ // "muted errors" is true
kSanitize
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc b/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
index 1fac6f436b7..4a92bd36314 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
@@ -35,12 +35,11 @@
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -53,9 +52,8 @@ namespace blink {
ScheduledAction* ScheduledAction::Create(ScriptState* script_state,
ExecutionContext* target,
- const ScriptValue& handler,
+ V8Function* handler,
const Vector<ScriptValue>& arguments) {
- DCHECK(handler.IsFunction());
if (!script_state->World().IsWorkerWorld()) {
if (!BindingSecurity::ShouldAllowAccessToFrame(
EnteredDOMWindow(script_state->GetIsolate()),
@@ -84,21 +82,45 @@ ScheduledAction* ScheduledAction::Create(ScriptState* script_state,
return MakeGarbageCollected<ScheduledAction>(script_state, handler);
}
+ScheduledAction::ScheduledAction(ScriptState* script_state,
+ V8Function* function,
+ const Vector<ScriptValue>& arguments)
+ : script_state_(ScriptStateProtectingContext::Create(script_state)),
+ function_(function),
+ arguments_(arguments) {}
+
+ScheduledAction::ScheduledAction(ScriptState* script_state, const String& code)
+ : script_state_(ScriptStateProtectingContext::Create(script_state)),
+ code_(code) {}
+
+ScheduledAction::ScheduledAction(ScriptState* script_state)
+ : script_state_(ScriptStateProtectingContext::Create(script_state)) {}
+
ScheduledAction::~ScheduledAction() {
// Verify that owning DOMTimer has eagerly disposed.
- DCHECK(info_.IsEmpty());
+ DCHECK(!script_state_);
+ DCHECK(!function_);
+ DCHECK(arguments_.IsEmpty());
+ DCHECK(code_.IsNull());
}
void ScheduledAction::Dispose() {
- code_ = String();
- info_.Clear();
- function_.Clear();
script_state_->Reset();
script_state_.Clear();
-}
-
-void ScheduledAction::Trace(blink::Visitor* visitor) {
- visitor->Trace(script_state_);
+ if (function_) {
+ // setTimeout is pretty common and heavily used, and we need a special
+ // optimization to let V8 Scavenger GC collect the function object as
+ // soon as possible in order to reduce the memory usage.
+ // See also https://crbug.com/919474 and https://crbug.com/919475 .
+ //
+ // This optimization is safe because this ScheduledAction *owns* |function_|
+ // (i.e. no other objects reference |function_|) and this ScheduledAction
+ // immediately discards |function_| (so never uses it).
+ function_->DisposeV8FunctionImmediatelyToReduceMemoryFootprint();
+ function_.Clear();
+ }
+ arguments_.clear();
+ code_ = String();
}
void ScheduledAction::Execute(ExecutionContext* context) {
@@ -128,47 +150,19 @@ void ScheduledAction::Execute(ExecutionContext* context) {
}
}
-ScheduledAction::ScheduledAction(ScriptState* script_state,
- const ScriptValue& function,
- const Vector<ScriptValue>& arguments)
- : ScheduledAction(script_state) {
- DCHECK(function.IsFunction());
- function_.Set(script_state->GetIsolate(),
- v8::Local<v8::Function>::Cast(function.V8Value()));
- info_.ReserveCapacity(arguments.size());
- for (const ScriptValue& argument : arguments)
- info_.Append(argument.V8Value());
-}
-
-ScheduledAction::ScheduledAction(ScriptState* script_state, const String& code)
- : ScheduledAction(script_state) {
- code_ = code;
+void ScheduledAction::Trace(blink::Visitor* visitor) {
+ visitor->Trace(script_state_);
+ visitor->Trace(function_);
}
-ScheduledAction::ScheduledAction(ScriptState* script_state)
- : script_state_(ScriptStateProtectingContext::Create(script_state)),
- info_(script_state->GetIsolate()) {}
-
void ScheduledAction::Execute(LocalFrame* frame) {
DCHECK(script_state_->ContextIsValid());
+ // https://html.spec.whatwg.org/C/#timer-initialisation-steps
TRACE_EVENT0("v8", "ScheduledAction::execute");
- if (!function_.IsEmpty()) {
+ if (function_) {
DVLOG(1) << "ScheduledAction::execute " << this << ": have function";
- v8::Local<v8::Function> function =
- function_.NewLocal(script_state_->GetIsolate());
- ScriptState* script_state_for_func =
- ScriptState::From(function->CreationContext());
- if (!script_state_for_func->ContextIsValid()) {
- DVLOG(1) << "ScheduledAction::execute " << this
- << ": function's context is empty";
- return;
- }
- Vector<v8::Local<v8::Value>> info;
- CreateLocalHandlesForArgs(&info);
- V8ScriptRunner::CallFunction(
- function, frame->GetDocument(), script_state_->GetContext()->Global(),
- info.size(), info.data(), script_state_->GetIsolate());
+ function_->InvokeAndReportException(frame->DomWindow(), arguments_);
} else {
DVLOG(1) << "ScheduledAction::execute " << this
<< ": executing from source";
@@ -188,29 +182,12 @@ void ScheduledAction::Execute(LocalFrame* frame) {
}
void ScheduledAction::Execute(WorkerGlobalScope* worker) {
+ DCHECK(script_state_->ContextIsValid());
DCHECK(worker->GetThread()->IsCurrentThread());
- if (!script_state_->ContextIsValid()) {
- DVLOG(1) << "ScheduledAction::execute " << this << ": context is empty";
- return;
- }
-
- if (!function_.IsEmpty()) {
- ScriptState::Scope scope(script_state_->Get());
- v8::Local<v8::Function> function =
- function_.NewLocal(script_state_->GetIsolate());
- ScriptState* script_state_for_func =
- ScriptState::From(function->CreationContext());
- if (!script_state_for_func->ContextIsValid()) {
- DVLOG(1) << "ScheduledAction::execute " << this
- << ": function's context is empty";
- return;
- }
- Vector<v8::Local<v8::Value>> info;
- CreateLocalHandlesForArgs(&info);
- V8ScriptRunner::CallFunction(
- function, worker, script_state_->GetContext()->Global(), info.size(),
- info.data(), script_state_->GetIsolate());
+ // https://html.spec.whatwg.org/C/#timer-initialisation-steps
+ if (function_) {
+ function_->InvokeAndReportException(worker, arguments_);
} else {
// We're using |SanitizeScriptErrors::kDoNotSanitize| to keep the existing
// behavior, but this causes failures on
@@ -223,12 +200,4 @@ void ScheduledAction::Execute(WorkerGlobalScope* worker) {
}
}
-void ScheduledAction::CreateLocalHandlesForArgs(
- Vector<v8::Local<v8::Value>>* handles) {
- wtf_size_t handle_count = SafeCast<wtf_size_t>(info_.Size());
- handles->ReserveCapacity(handle_count);
- for (wtf_size_t i = 0; i < handle_count; ++i)
- handles->push_back(info_.Get(i));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.h b/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
index efc73bfad1b..daeb13aadb3 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
@@ -31,9 +31,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCHEDULED_ACTION_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCHEDULED_ACTION_H_
-#include "third_party/blink/renderer/bindings/core/v8/v8_persistent_value_vector.h"
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -41,47 +40,51 @@
namespace blink {
-class LocalFrame;
class ExecutionContext;
+class LocalFrame;
+class ScriptState;
+class ScriptStateProtectingContext;
class ScriptValue;
+class V8Function;
class WorkerGlobalScope;
-class ScheduledAction final
- : public GarbageCollectedFinalized<ScheduledAction> {
+class ScheduledAction final : public GarbageCollectedFinalized<ScheduledAction>,
+ public NameClient {
WTF_MAKE_NONCOPYABLE(ScheduledAction);
public:
static ScheduledAction* Create(ScriptState*,
ExecutionContext* target,
- const ScriptValue& handler,
+ V8Function* handler,
const Vector<ScriptValue>& arguments);
static ScheduledAction* Create(ScriptState*,
ExecutionContext* target,
const String& handler);
- ScheduledAction(ScriptState*,
- const ScriptValue& handler,
- const Vector<ScriptValue>& arguments);
- ScheduledAction(ScriptState*, const String& handler);
-
+ explicit ScheduledAction(ScriptState*,
+ V8Function* handler,
+ const Vector<ScriptValue>& arguments);
+ explicit ScheduledAction(ScriptState*, const String& handler);
// Creates an empty ScheduledAction.
explicit ScheduledAction(ScriptState*);
~ScheduledAction();
+
void Dispose();
+ void Execute(ExecutionContext*);
+
void Trace(blink::Visitor*);
- void Execute(ExecutionContext*);
+ const char* NameInHeapSnapshot() const override { return "ScheduledAction"; }
private:
void Execute(LocalFrame*);
void Execute(WorkerGlobalScope*);
- void CreateLocalHandlesForArgs(Vector<v8::Local<v8::Value>>* handles);
Member<ScriptStateProtectingContext> script_state_;
- ScopedPersistent<v8::Function> function_;
- V8PersistentValueVector<v8::Value> info_;
+ TraceWrapperMember<V8Function> function_;
+ Vector<ScriptValue> arguments_;
String code_;
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc
index e9d6c322097..1ce14d0a395 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc
@@ -211,15 +211,19 @@ void ScriptController::UpdateDocument() {
EnableEval();
}
-bool ScriptController::ExecuteScriptIfJavaScriptURL(const KURL& url,
- Element* element) {
+bool ScriptController::ExecuteScriptIfJavaScriptURL(
+ const KURL& url,
+ Element* element,
+ ContentSecurityPolicyDisposition check_main_world_csp) {
if (!url.ProtocolIsJavaScript())
return false;
const int kJavascriptSchemeLength = sizeof("javascript:") - 1;
- String script_source = DecodeURLEscapeSequences(url.GetString());
+ String script_source = DecodeURLEscapeSequences(
+ url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
bool should_bypass_main_world_content_security_policy =
+ check_main_world_csp == kDoNotCheckContentSecurityPolicy ||
ContentSecurityPolicy::ShouldBypassMainWorld(GetFrame()->GetDocument());
if (!GetFrame()->GetPage() ||
(!should_bypass_main_world_content_security_policy &&
@@ -234,12 +238,6 @@ bool ScriptController::ExecuteScriptIfJavaScriptURL(const KURL& url,
script_source = script_source.Substring(kJavascriptSchemeLength);
- bool progress_notifications_needed =
- GetFrame()->Loader().StateMachine()->IsDisplayingInitialEmptyDocument() &&
- !GetFrame()->IsLoading();
- if (progress_notifications_needed)
- GetFrame()->Loader().Progress().ProgressStarted();
-
Document* owner_document = GetFrame()->GetDocument();
bool location_change_before =
@@ -266,11 +264,8 @@ bool ScriptController::ExecuteScriptIfJavaScriptURL(const KURL& url,
if (!GetFrame()->GetPage())
return true;
- if (result.IsEmpty() || !result->IsString()) {
- if (progress_notifications_needed)
- GetFrame()->Loader().Progress().ProgressCompleted();
+ if (result.IsEmpty() || !result->IsString())
return true;
- }
String script_result = ToCoreString(v8::Local<v8::String>::Cast(result));
// We're still in a frame, so there should be a DocumentLoader.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h
index 89af1d7854b..946948e02ce 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/bindings/shared_persistent.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
@@ -120,7 +121,11 @@ class CORE_EXPORT ScriptController final
SanitizeScriptErrors sanitize_script_errors);
// Returns true if argument is a JavaScript URL.
- bool ExecuteScriptIfJavaScriptURL(const KURL&, Element*);
+ bool ExecuteScriptIfJavaScriptURL(
+ const KURL&,
+ Element*,
+ ContentSecurityPolicyDisposition check_main_world_csp =
+ kCheckContentSecurityPolicy);
// Creates a new isolated world for DevTools with the given human readable
// |world_name| and returns it id or nullptr on failure.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
index db2db818149..d4dafc3156c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_data.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_adopted_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_attribute_changed_callback.h"
@@ -74,35 +75,19 @@ ScriptCustomElementDefinition* ScriptCustomElementDefinition::ForConstructor(
}
ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create(
- ScriptState* script_state,
- CustomElementRegistry* registry,
+ const ScriptCustomElementDefinitionData& data,
const CustomElementDescriptor& descriptor,
- CustomElementDefinition::Id id,
- V8CustomElementConstructor* constructor,
- V8VoidFunction* connected_callback,
- V8VoidFunction* disconnected_callback,
- V8CustomElementAdoptedCallback* adopted_callback,
- V8CustomElementAttributeChangedCallback* attribute_changed_callback,
- V8CustomElementFormAssociatedCallback* form_associated_callback,
- V8CustomElementDisabledStateChangedCallback*
- disabled_state_changed_callback,
- HashSet<AtomicString>&& observed_attributes,
- const Vector<String>& disabled_features,
- FormAssociationFlag form_association_flag) {
- ScriptCustomElementDefinition* definition =
- MakeGarbageCollected<ScriptCustomElementDefinition>(
- script_state, descriptor, constructor, connected_callback,
- disconnected_callback, adopted_callback, attribute_changed_callback,
- form_associated_callback, disabled_state_changed_callback,
- std::move(observed_attributes), disabled_features,
- form_association_flag);
+ CustomElementDefinition::Id id) {
+ auto* definition =
+ MakeGarbageCollected<ScriptCustomElementDefinition>(data, descriptor);
// Tag the JavaScript constructor object with its ID.
+ ScriptState* script_state = data.script_state_;
v8::Local<v8::Value> id_value =
v8::Integer::NewFromUnsigned(script_state->GetIsolate(), id);
auto private_id =
script_state->PerContextData()->GetPrivateCustomElementDefinitionId();
- CHECK(constructor->CallbackObject()
+ CHECK(data.constructor_->CallbackObject()
->SetPrivate(script_state->GetContext(), private_id, id_value)
.ToChecked());
@@ -110,31 +95,23 @@ ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create(
}
ScriptCustomElementDefinition::ScriptCustomElementDefinition(
- ScriptState* script_state,
- const CustomElementDescriptor& descriptor,
- V8CustomElementConstructor* constructor,
- V8VoidFunction* connected_callback,
- V8VoidFunction* disconnected_callback,
- V8CustomElementAdoptedCallback* adopted_callback,
- V8CustomElementAttributeChangedCallback* attribute_changed_callback,
- V8CustomElementFormAssociatedCallback* form_associated_callback,
- V8CustomElementDisabledStateChangedCallback*
- disabled_state_changed_callback,
- HashSet<AtomicString>&& observed_attributes,
- const Vector<String>& disabled_features,
- FormAssociationFlag form_association_flag)
+ const ScriptCustomElementDefinitionData& data,
+ const CustomElementDescriptor& descriptor)
: CustomElementDefinition(descriptor,
- std::move(observed_attributes),
- disabled_features,
- form_association_flag),
- script_state_(script_state),
- constructor_(constructor),
- connected_callback_(connected_callback),
- disconnected_callback_(disconnected_callback),
- adopted_callback_(adopted_callback),
- attribute_changed_callback_(attribute_changed_callback),
- form_associated_callback_(form_associated_callback),
- disabled_state_changed_callback_(disabled_state_changed_callback) {}
+ std::move(data.observed_attributes_),
+ data.disabled_features_,
+ data.is_form_associated_
+ ? FormAssociationFlag::kYes
+ : FormAssociationFlag::kNo),
+ script_state_(data.script_state_),
+ constructor_(data.constructor_),
+ connected_callback_(data.connected_callback_),
+ disconnected_callback_(data.disconnected_callback_),
+ adopted_callback_(data.adopted_callback_),
+ attribute_changed_callback_(data.attribute_changed_callback_),
+ form_associated_callback_(data.form_associated_callback_),
+ form_reset_callback_(data.form_reset_callback_),
+ disabled_state_changed_callback_(data.disabled_state_changed_callback_) {}
void ScriptCustomElementDefinition::Trace(Visitor* visitor) {
visitor->Trace(script_state_);
@@ -144,6 +121,7 @@ void ScriptCustomElementDefinition::Trace(Visitor* visitor) {
visitor->Trace(adopted_callback_);
visitor->Trace(attribute_changed_callback_);
visitor->Trace(form_associated_callback_);
+ visitor->Trace(form_reset_callback_);
visitor->Trace(disabled_state_changed_callback_);
CustomElementDefinition::Trace(visitor);
}
@@ -192,7 +170,7 @@ HTMLElement* ScriptCustomElementDefinition::CreateAutonomousCustomElementSync(
element = CreateElementForConstructor(document);
DCHECK(!try_catch.HasCaught());
- ConstructionStackScope construction_stack_scope(this, element);
+ ConstructionStackScope construction_stack_scope(*this, *element);
element = CallConstructor();
} else {
element = CallConstructor();
@@ -220,7 +198,7 @@ HTMLElement* ScriptCustomElementDefinition::CreateAutonomousCustomElementSync(
}
// https://html.spec.whatwg.org/multipage/scripting.html#upgrades
-bool ScriptCustomElementDefinition::RunConstructor(Element* element) {
+bool ScriptCustomElementDefinition::RunConstructor(Element& element) {
if (!script_state_->ContextIsValid())
return false;
ScriptState::Scope scope(script_state_);
@@ -239,7 +217,7 @@ bool ScriptCustomElementDefinition::RunConstructor(Element* element) {
// To report InvalidStateError Exception, when the constructor returns some
// different object
- if (result != element) {
+ if (result != &element) {
const String& message =
"custom element constructors must call super() first and must "
"not return a different object";
@@ -289,35 +267,39 @@ bool ScriptCustomElementDefinition::HasFormAssociatedCallback() const {
return form_associated_callback_;
}
+bool ScriptCustomElementDefinition::HasFormResetCallback() const {
+ return form_reset_callback_;
+}
+
bool ScriptCustomElementDefinition::HasDisabledStateChangedCallback() const {
return disabled_state_changed_callback_;
}
-void ScriptCustomElementDefinition::RunConnectedCallback(Element* element) {
+void ScriptCustomElementDefinition::RunConnectedCallback(Element& element) {
if (!connected_callback_)
return;
- connected_callback_->InvokeAndReportException(element);
+ connected_callback_->InvokeAndReportException(&element);
}
-void ScriptCustomElementDefinition::RunDisconnectedCallback(Element* element) {
+void ScriptCustomElementDefinition::RunDisconnectedCallback(Element& element) {
if (!disconnected_callback_)
return;
- disconnected_callback_->InvokeAndReportException(element);
+ disconnected_callback_->InvokeAndReportException(&element);
}
-void ScriptCustomElementDefinition::RunAdoptedCallback(Element* element,
- Document* old_owner,
- Document* new_owner) {
+void ScriptCustomElementDefinition::RunAdoptedCallback(Element& element,
+ Document& old_owner,
+ Document& new_owner) {
if (!adopted_callback_)
return;
- adopted_callback_->InvokeAndReportException(element, old_owner, new_owner);
+ adopted_callback_->InvokeAndReportException(&element, &old_owner, &new_owner);
}
void ScriptCustomElementDefinition::RunAttributeChangedCallback(
- Element* element,
+ Element& element,
const QualifiedName& name,
const AtomicString& old_value,
const AtomicString& new_value) {
@@ -325,23 +307,29 @@ void ScriptCustomElementDefinition::RunAttributeChangedCallback(
return;
attribute_changed_callback_->InvokeAndReportException(
- element, name.LocalName(), old_value, new_value, name.NamespaceURI());
+ &element, name.LocalName(), old_value, new_value, name.NamespaceURI());
}
void ScriptCustomElementDefinition::RunFormAssociatedCallback(
- Element* element,
+ Element& element,
HTMLFormElement* nullable_form) {
if (!form_associated_callback_)
return;
- form_associated_callback_->InvokeAndReportException(element, nullable_form);
+ form_associated_callback_->InvokeAndReportException(&element, nullable_form);
+}
+
+void ScriptCustomElementDefinition::RunFormResetCallback(Element& element) {
+ if (!form_reset_callback_)
+ return;
+ form_reset_callback_->InvokeAndReportException(&element);
}
void ScriptCustomElementDefinition::RunDisabledStateChangedCallback(
- Element* element,
+ Element& element,
bool is_disabled) {
if (!disabled_state_changed_callback_)
return;
- disabled_state_changed_callback_->InvokeAndReportException(element,
+ disabled_state_changed_callback_->InvokeAndReportException(&element,
is_disabled);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h
index 4a1eb049dd2..0fa75ab27d1 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h
@@ -17,6 +17,7 @@ namespace blink {
class CustomElementDescriptor;
class CustomElementRegistry;
+class ScriptCustomElementDefinitionData;
class V8CustomElementAdoptedCallback;
class V8CustomElementAttributeChangedCallback;
class V8CustomElementConstructor;
@@ -35,36 +36,12 @@ class CORE_EXPORT ScriptCustomElementDefinition final
v8::Local<v8::Value> constructor);
static ScriptCustomElementDefinition* Create(
- ScriptState*,
- CustomElementRegistry*,
+ const ScriptCustomElementDefinitionData& data,
const CustomElementDescriptor&,
- CustomElementDefinition::Id,
- V8CustomElementConstructor* constructor,
- V8VoidFunction* connected_callback,
- V8VoidFunction* disconnected_callback,
- V8CustomElementAdoptedCallback* adopted_callback,
- V8CustomElementAttributeChangedCallback* attribute_changed_callback,
- V8CustomElementFormAssociatedCallback* form_associated_callback,
- V8CustomElementDisabledStateChangedCallback*
- disabled_state_changed_callback,
- HashSet<AtomicString>&& observed_attributes,
- const Vector<String>& disabled_features,
- FormAssociationFlag form_association_flag);
-
- ScriptCustomElementDefinition(
- ScriptState*,
- const CustomElementDescriptor&,
- V8CustomElementConstructor* constructor,
- V8VoidFunction* connected_callback,
- V8VoidFunction* disconnected_callback,
- V8CustomElementAdoptedCallback* adopted_callback,
- V8CustomElementAttributeChangedCallback* attribute_changed_callback,
- V8CustomElementFormAssociatedCallback* form_associated_callback,
- V8CustomElementDisabledStateChangedCallback*
- disabled_state_changed_callback,
- HashSet<AtomicString>&& observed_attributes,
- const Vector<String>& disabled_features,
- FormAssociationFlag form_association_flag);
+ CustomElementDefinition::Id);
+
+ ScriptCustomElementDefinition(const ScriptCustomElementDefinitionData& data,
+ const CustomElementDescriptor&);
~ScriptCustomElementDefinition() override = default;
void Trace(Visitor*) override;
@@ -78,26 +55,28 @@ class CORE_EXPORT ScriptCustomElementDefinition final
bool HasDisconnectedCallback() const override;
bool HasAdoptedCallback() const override;
bool HasFormAssociatedCallback() const override;
+ bool HasFormResetCallback() const override;
bool HasDisabledStateChangedCallback() const override;
- void RunConnectedCallback(Element*) override;
- void RunDisconnectedCallback(Element*) override;
- void RunAdoptedCallback(Element*,
- Document* old_owner,
- Document* new_owner) override;
- void RunAttributeChangedCallback(Element*,
+ void RunConnectedCallback(Element&) override;
+ void RunDisconnectedCallback(Element&) override;
+ void RunAdoptedCallback(Element&,
+ Document& old_owner,
+ Document& new_owner) override;
+ void RunAttributeChangedCallback(Element&,
const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value) override;
- void RunFormAssociatedCallback(Element* element,
+ void RunFormAssociatedCallback(Element& element,
HTMLFormElement* nullable_form) override;
- void RunDisabledStateChangedCallback(Element* element,
+ void RunFormResetCallback(Element& element) override;
+ void RunDisabledStateChangedCallback(Element& element,
bool is_disabled) override;
private:
// Implementations of |CustomElementDefinition|
ScriptValue GetConstructorForScript() final;
- bool RunConstructor(Element*) override;
+ bool RunConstructor(Element&) override;
// Calls the constructor. The script scope, etc. must already be set up.
Element* CallConstructor();
@@ -116,6 +95,7 @@ class CORE_EXPORT ScriptCustomElementDefinition final
attribute_changed_callback_;
TraceWrapperMember<V8CustomElementFormAssociatedCallback>
form_associated_callback_;
+ TraceWrapperMember<V8VoidFunction> form_reset_callback_;
TraceWrapperMember<V8CustomElementDisabledStateChangedCallback>
disabled_state_changed_callback_;
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.cc
index 79f2c83793f..83e94a35ced 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_disabled_state_changed_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_form_associated_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_restore_value_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
#include "third_party/blink/renderer/platform/bindings/callback_method_retriever.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
@@ -28,15 +29,16 @@ ScriptCustomElementDefinitionBuilder::ScriptCustomElementDefinitionBuilder(
CustomElementRegistry* registry,
V8CustomElementConstructor* constructor,
ExceptionState& exception_state)
- : script_state_(script_state),
- exception_state_(exception_state),
- registry_(registry),
- constructor_(constructor) {}
+ : exception_state_(exception_state) {
+ data_.script_state_ = script_state;
+ data_.registry_ = registry;
+ data_.constructor_ = constructor;
+}
bool ScriptCustomElementDefinitionBuilder::CheckConstructorIntrinsics() {
- DCHECK(script_state_->World().IsMainWorld());
+ DCHECK(GetScriptState()->World().IsMainWorld());
- if (!constructor_->IsConstructor()) {
+ if (!Constructor()->IsConstructor()) {
exception_state_.ThrowTypeError(
"constructor argument is not a constructor");
return false;
@@ -46,7 +48,7 @@ bool ScriptCustomElementDefinitionBuilder::CheckConstructorIntrinsics() {
bool ScriptCustomElementDefinitionBuilder::CheckConstructorNotRegistered() {
if (!ScriptCustomElementDefinition::ForConstructor(
- script_state_, registry_, constructor_->CallbackObject()))
+ GetScriptState(), data_.registry_, Constructor()->CallbackObject()))
return true;
// Constructor is already registered.
@@ -59,7 +61,7 @@ bool ScriptCustomElementDefinitionBuilder::CheckConstructorNotRegistered() {
bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
// https://html.spec.whatwg.org/C/custom-elements.html#element-definition
// step 10. Run the following substeps while catching any exceptions:
- CallbackMethodRetriever retriever(constructor_);
+ CallbackMethodRetriever retriever(Constructor());
retriever.GetPrototypeObject(exception_state_);
if (exception_state_.HadException())
@@ -70,7 +72,7 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
if (exception_state_.HadException())
return false;
if (v8_connected_callback_->IsFunction()) {
- connected_callback_ =
+ data_.connected_callback_ =
V8VoidFunction::Create(v8_connected_callback_.As<v8::Function>());
}
v8_disconnected_callback_ =
@@ -78,7 +80,7 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
if (exception_state_.HadException())
return false;
if (v8_disconnected_callback_->IsFunction()) {
- disconnected_callback_ =
+ data_.disconnected_callback_ =
V8VoidFunction::Create(v8_disconnected_callback_.As<v8::Function>());
}
v8_adopted_callback_ =
@@ -86,7 +88,7 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
if (exception_state_.HadException())
return false;
if (v8_adopted_callback_->IsFunction()) {
- adopted_callback_ = V8CustomElementAdoptedCallback::Create(
+ data_.adopted_callback_ = V8CustomElementAdoptedCallback::Create(
v8_adopted_callback_.As<v8::Function>());
}
v8_attribute_changed_callback_ = retriever.GetMethodOrUndefined(
@@ -94,20 +96,21 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
if (exception_state_.HadException())
return false;
if (v8_attribute_changed_callback_->IsFunction()) {
- attribute_changed_callback_ =
+ data_.attribute_changed_callback_ =
V8CustomElementAttributeChangedCallback::Create(
v8_attribute_changed_callback_.As<v8::Function>());
}
// step 10.6. If the value of the entry in lifecycleCallbacks with key
// "attributeChangedCallback" is not null, then:
- if (attribute_changed_callback_) {
- v8::Isolate* isolate = script_state_->GetIsolate();
+ if (data_.attribute_changed_callback_) {
+ v8::Isolate* isolate = Isolate();
v8::Local<v8::Context> current_context = isolate->GetCurrentContext();
- v8::TryCatch try_catch(script_state_->GetIsolate());
+ v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> v8_observed_attributes;
- if (!constructor_->CallbackObject()
+ if (!Constructor()
+ ->CallbackObject()
->Get(current_context,
V8AtomicString(isolate, "observedAttributes"))
.ToLocal(&v8_observed_attributes)) {
@@ -121,19 +124,20 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
isolate, v8_observed_attributes, exception_state_);
if (exception_state_.HadException())
return false;
- observed_attributes_.ReserveCapacityForSize(observed_attrs.size());
+ data_.observed_attributes_.ReserveCapacityForSize(observed_attrs.size());
for (const auto& attribute : observed_attrs)
- observed_attributes_.insert(AtomicString(attribute));
+ data_.observed_attributes_.insert(AtomicString(attribute));
}
}
if (RuntimeEnabledFeatures::ElementInternalsEnabled()) {
- auto* isolate = script_state_->GetIsolate();
+ auto* isolate = Isolate();
v8::Local<v8::Context> current_context = isolate->GetCurrentContext();
v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> v8_disabled_features;
- if (!constructor_->CallbackObject()
+ if (!Constructor()
+ ->CallbackObject()
->Get(current_context, V8AtomicString(isolate, "disabledFeatures"))
.ToLocal(&v8_disabled_features)) {
exception_state_.RethrowV8Exception(try_catch.Exception());
@@ -141,7 +145,7 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
}
if (!v8_disabled_features->IsUndefined()) {
- disabled_features_ =
+ data_.disabled_features_ =
NativeValueTraits<IDLSequence<IDLString>>::NativeValue(
isolate, v8_disabled_features, exception_state_);
if (exception_state_.HadException())
@@ -150,12 +154,13 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
}
if (RuntimeEnabledFeatures::FormAssociatedCustomElementsEnabled()) {
- auto* isolate = script_state_->GetIsolate();
+ auto* isolate = Isolate();
v8::Local<v8::Context> current_context = isolate->GetCurrentContext();
v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> v8_form_associated;
- if (!constructor_->CallbackObject()
+ if (!Constructor()
+ ->CallbackObject()
->Get(current_context, V8AtomicString(isolate, "formAssociated"))
.ToLocal(&v8_form_associated)) {
exception_state_.RethrowV8Exception(try_catch.Exception());
@@ -163,20 +168,30 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
}
if (!v8_form_associated->IsUndefined()) {
- is_form_associated_ = NativeValueTraits<IDLBoolean>::NativeValue(
+ data_.is_form_associated_ = NativeValueTraits<IDLBoolean>::NativeValue(
isolate, v8_form_associated, exception_state_);
if (exception_state_.HadException())
return false;
}
}
- if (is_form_associated_) {
+ if (data_.is_form_associated_) {
v8_form_associated_callback_ = retriever.GetMethodOrUndefined(
"formAssociatedCallback", exception_state_);
if (exception_state_.HadException())
return false;
if (v8_form_associated_callback_->IsFunction()) {
- form_associated_callback_ = V8CustomElementFormAssociatedCallback::Create(
- v8_form_associated_callback_.As<v8::Function>());
+ data_.form_associated_callback_ =
+ V8CustomElementFormAssociatedCallback::Create(
+ v8_form_associated_callback_.As<v8::Function>());
+ }
+
+ v8_form_reset_callback_ =
+ retriever.GetMethodOrUndefined("formResetCallback", exception_state_);
+ if (exception_state_.HadException())
+ return false;
+ if (v8_form_reset_callback_->IsFunction()) {
+ data_.form_reset_callback_ =
+ V8VoidFunction::Create(v8_form_reset_callback_.As<v8::Function>());
}
v8_disabled_state_changed_callback_ = retriever.GetMethodOrUndefined(
@@ -184,10 +199,24 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
if (exception_state_.HadException())
return false;
if (v8_disabled_state_changed_callback_->IsFunction()) {
- disabled_state_changed_callback_ =
+ data_.disabled_state_changed_callback_ =
V8CustomElementDisabledStateChangedCallback::Create(
v8_disabled_state_changed_callback_.As<v8::Function>());
}
+
+ v8_restore_value_callback_ = retriever.GetMethodOrUndefined(
+ "restoreValueCallback", exception_state_);
+ if (exception_state_.HadException())
+ return false;
+ if (!v8_restore_value_callback_->IsFunction()) {
+ exception_state_.ThrowDOMException(
+ DOMExceptionCode::kTypeMismatchError,
+ "A class for form-associated custom elements must have a "
+ "'restoreValueCallback'.");
+ return false;
+ }
+ data_.restore_value_callback_ = V8CustomElementRestoreValueCallback::Create(
+ v8_restore_value_callback_.As<v8::Function>());
}
return true;
@@ -196,14 +225,11 @@ bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
CustomElementDefinition* ScriptCustomElementDefinitionBuilder::Build(
const CustomElementDescriptor& descriptor,
CustomElementDefinition::Id id) {
- return ScriptCustomElementDefinition::Create(
- script_state_, registry_, descriptor, id, constructor_,
- connected_callback_, disconnected_callback_, adopted_callback_,
- attribute_changed_callback_, form_associated_callback_,
- disabled_state_changed_callback_, std::move(observed_attributes_),
- disabled_features_,
- is_form_associated_ ? FormAssociationFlag::kYes
- : FormAssociationFlag::kNo);
+ return ScriptCustomElementDefinition::Create(data_, descriptor, id);
+}
+
+v8::Isolate* ScriptCustomElementDefinitionBuilder::Isolate() {
+ return data_.script_state_->GetIsolate();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.h
index c34319489d5..d057c0abdc8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_builder.h
@@ -5,29 +5,16 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_CUSTOM_ELEMENT_DEFINITION_BUILDER_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_CUSTOM_ELEMENT_DEFINITION_BUILDER_H_
-#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_data.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_definition_builder.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
#include "v8/include/v8.h"
namespace blink {
-class CustomElementRegistry;
class ExceptionState;
-class ScriptState;
-class V8CustomElementAdoptedCallback;
-class V8CustomElementAttributeChangedCallback;
-class V8CustomElementConstructor;
-class V8CustomElementDisabledStateChangedCallback;
-class V8CustomElementFormAssociatedCallback;
-class V8VoidFunction;
class CORE_EXPORT ScriptCustomElementDefinitionBuilder
: public CustomElementDefinitionBuilder {
@@ -48,10 +35,12 @@ class CORE_EXPORT ScriptCustomElementDefinitionBuilder
CustomElementDefinition::Id) override;
private:
- Member<ScriptState> script_state_;
+ ScriptState* GetScriptState() { return data_.script_state_; }
+ v8::Isolate* Isolate();
+ V8CustomElementConstructor* Constructor() { return data_.constructor_; }
+
ExceptionState& exception_state_;
- Member<CustomElementRegistry> registry_;
- const Member<V8CustomElementConstructor> constructor_;
+ ScriptCustomElementDefinitionData data_;
// These v8::Local handles on stack make the function objects alive until we
// finish building the CustomElementDefinition and wrapper-tracing on it gets
// available.
@@ -60,17 +49,9 @@ class CORE_EXPORT ScriptCustomElementDefinitionBuilder
v8::Local<v8::Value> v8_adopted_callback_;
v8::Local<v8::Value> v8_attribute_changed_callback_;
v8::Local<v8::Value> v8_form_associated_callback_;
+ v8::Local<v8::Value> v8_form_reset_callback_;
v8::Local<v8::Value> v8_disabled_state_changed_callback_;
- Member<V8VoidFunction> connected_callback_;
- Member<V8VoidFunction> disconnected_callback_;
- Member<V8CustomElementAdoptedCallback> adopted_callback_;
- Member<V8CustomElementAttributeChangedCallback> attribute_changed_callback_;
- Member<V8CustomElementFormAssociatedCallback> form_associated_callback_;
- Member<V8CustomElementDisabledStateChangedCallback>
- disabled_state_changed_callback_;
- HashSet<AtomicString> observed_attributes_;
- Vector<String> disabled_features_;
- bool is_form_associated_ = false;
+ v8::Local<v8::Value> v8_restore_value_callback_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_data.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_data.h
new file mode 100644
index 00000000000..7efb089f7e0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition_data.h
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_CUSTOM_ELEMENT_DEFINITION_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_CUSTOM_ELEMENT_DEFINITION_DATA_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
+
+namespace blink {
+
+class CustomElementRegistry;
+class ScriptState;
+class V8CustomElementAdoptedCallback;
+class V8CustomElementAttributeChangedCallback;
+class V8CustomElementConstructor;
+class V8CustomElementDisabledStateChangedCallback;
+class V8CustomElementFormAssociatedCallback;
+class V8CustomElementRestoreValueCallback;
+class V8VoidFunction;
+
+class ScriptCustomElementDefinitionData {
+ STACK_ALLOCATED();
+
+ public:
+ ScriptCustomElementDefinitionData() {}
+
+ Member<ScriptState> script_state_;
+ Member<CustomElementRegistry> registry_;
+ Member<V8CustomElementConstructor> constructor_;
+ Member<V8VoidFunction> connected_callback_;
+ Member<V8VoidFunction> disconnected_callback_;
+ Member<V8CustomElementAdoptedCallback> adopted_callback_;
+ Member<V8CustomElementAttributeChangedCallback> attribute_changed_callback_;
+ Member<V8CustomElementFormAssociatedCallback> form_associated_callback_;
+ Member<V8VoidFunction> form_reset_callback_;
+ Member<V8CustomElementDisabledStateChangedCallback>
+ disabled_state_changed_callback_;
+ Member<V8CustomElementRestoreValueCallback> restore_value_callback_;
+ HashSet<AtomicString> observed_attributes_;
+ Vector<String> disabled_features_;
+ bool is_form_associated_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(ScriptCustomElementDefinitionData);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_CUSTOM_ELEMENT_DEFINITION_DATA_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_event_listener.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_event_listener.cc
index 1ffd0df22d2..d735ce4ebf7 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_event_listener.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_event_listener.cc
@@ -55,7 +55,7 @@ EventListener* CreateAttributeEventListener(Node* node,
OrdinalNumber::First());
String source_url;
- v8::Isolate* isolate = ToIsolate(&node->GetDocument());
+ v8::Isolate* isolate = node->GetDocument().GetIsolate();
if (LocalFrame* frame = node->GetDocument().GetFrame()) {
ScriptController& script_controller = frame->GetScriptController();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc
index f9f16efb1f5..3657116ff81 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc
@@ -11,6 +11,7 @@ namespace blink {
void ScriptFunction::Trace(blink::Visitor* visitor) {
visitor->Trace(script_state_);
+ CustomWrappableAdapter::Trace(visitor);
}
v8::Local<v8::Function> ScriptFunction::BindToV8Function() {
@@ -19,9 +20,9 @@ v8::Local<v8::Function> ScriptFunction::BindToV8Function() {
bind_to_v8_function_already_called_ = true;
#endif
- v8::Isolate* isolate = script_state_->GetIsolate();
- v8::Local<v8::External> wrapper = v8::External::New(isolate, this);
- script_state_->World().RegisterDOMObjectHolder(isolate, this, wrapper);
+ v8::Local<v8::Object> wrapper = CreateAndInitializeWrapper(script_state_);
+ // The wrapper is held alive by the CallHandlerInfo internally in V8 as long
+ // as the function is alive.
return v8::Function::New(script_state_->GetContext(), CallCallback, wrapper,
0, v8::ConstructorBehavior::kThrow)
.ToLocalChecked();
@@ -39,11 +40,10 @@ void ScriptFunction::CallRaw(const v8::FunctionCallbackInfo<v8::Value>& args) {
void ScriptFunction::CallCallback(
const v8::FunctionCallbackInfo<v8::Value>& args) {
- DCHECK(args.Data()->IsExternal());
RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(args.GetIsolate(),
"Blink_CallCallback");
ScriptFunction* script_function = static_cast<ScriptFunction*>(
- v8::Local<v8::External>::Cast(args.Data())->Value());
+ ToCustomWrappable(v8::Local<v8::Object>::Cast(args.Data())));
script_function->CallRaw(args);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h
index ef0ebb9ea3d..c9828700362 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_FUNCTION_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_FUNCTION_H_
+#include "third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -49,11 +50,13 @@ namespace blink {
// return self->BindToV8Function();
// }
// };
-class CORE_EXPORT ScriptFunction
- : public GarbageCollectedFinalized<ScriptFunction> {
+class CORE_EXPORT ScriptFunction : public CustomWrappableAdapter {
public:
- virtual ~ScriptFunction() = default;
- virtual void Trace(blink::Visitor*);
+ ~ScriptFunction() override = default;
+
+ void Trace(blink::Visitor*) override;
+
+ const char* NameInHeapSnapshot() const override { return "ScriptFunction"; }
protected:
explicit ScriptFunction(ScriptState* script_state)
@@ -76,7 +79,7 @@ class CORE_EXPORT ScriptFunction
Member<ScriptState> script_state_;
#if DCHECK_IS_ON()
- // bindToV8Function must not be called twice.
+ // BindToV8Function() must not be called twice.
bool bind_to_v8_function_already_called_ = false;
#endif
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc
index f7ca42d342a..0ecf8eba0c7 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc
@@ -53,7 +53,18 @@ class PromiseAllHandler final
if (promises.IsEmpty())
return ScriptPromise::Cast(script_state,
v8::Array::New(script_state->GetIsolate()));
- return (new PromiseAllHandler(script_state, promises))->resolver_.Promise();
+ return (MakeGarbageCollected<PromiseAllHandler>(script_state, promises))
+ ->resolver_.Promise();
+ }
+
+ PromiseAllHandler(ScriptState* script_state, Vector<ScriptPromise> promises)
+ : number_of_pending_promises_(promises.size()), resolver_(script_state) {
+ DCHECK(!promises.IsEmpty());
+ values_.resize(promises.size());
+ for (wtf_size_t i = 0; i < promises.size(); ++i) {
+ promises[i].Then(CreateFulfillFunction(script_state, i),
+ CreateRejectFunction(script_state));
+ }
}
virtual void Trace(blink::Visitor* visitor) {}
@@ -70,17 +81,11 @@ class PromiseAllHandler final
ResolveType resolve_type,
wtf_size_t index,
PromiseAllHandler* handler) {
- AdapterFunction* self =
- new AdapterFunction(script_state, resolve_type, index, handler);
+ AdapterFunction* self = MakeGarbageCollected<AdapterFunction>(
+ script_state, resolve_type, index, handler);
return self->BindToV8Function();
}
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(handler_);
- ScriptFunction::Trace(visitor);
- }
-
- private:
AdapterFunction(ScriptState* script_state,
ResolveType resolve_type,
wtf_size_t index,
@@ -90,6 +95,12 @@ class PromiseAllHandler final
index_(index),
handler_(handler) {}
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(handler_);
+ ScriptFunction::Trace(visitor);
+ }
+
+ private:
ScriptValue Call(ScriptValue value) override {
if (resolve_type_ == kFulfilled)
handler_->OnFulfilled(index_, value);
@@ -104,15 +115,6 @@ class PromiseAllHandler final
Member<PromiseAllHandler> handler_;
};
- PromiseAllHandler(ScriptState* script_state, Vector<ScriptPromise> promises)
- : number_of_pending_promises_(promises.size()), resolver_(script_state) {
- DCHECK(!promises.IsEmpty());
- values_.resize(promises.size());
- for (wtf_size_t i = 0; i < promises.size(); ++i)
- promises[i].Then(CreateFulfillFunction(script_state, i),
- CreateRejectFunction(script_state));
- }
-
v8::Local<v8::Function> CreateFulfillFunction(ScriptState* script_state,
wtf_size_t index) {
return AdapterFunction::Create(script_state, AdapterFunction::kFulfilled,
@@ -245,24 +247,32 @@ ScriptPromise ScriptPromise::Then(v8::Local<v8::Function> on_fulfilled,
if (promise_.IsEmpty())
return ScriptPromise();
- v8::Local<v8::Object> promise = promise_.V8Value().As<v8::Object>();
+ v8::Local<v8::Promise> promise = promise_.V8Value().As<v8::Promise>();
+
+ if (on_fulfilled.IsEmpty() && on_rejected.IsEmpty())
+ return *this;
- DCHECK(promise->IsPromise());
- // Return this Promise if no handlers are given.
- // In fact it is not the exact bahavior of Promise.prototype.then
- // but that is not a problem in this case.
- v8::Local<v8::Promise> result_promise = promise.As<v8::Promise>();
- if (!on_fulfilled.IsEmpty()) {
- if (!result_promise->Then(script_state_->GetContext(), on_fulfilled)
- .ToLocal(&result_promise))
+ v8::Local<v8::Promise> result_promise;
+ if (on_rejected.IsEmpty()) {
+ if (!promise->Then(script_state_->GetContext(), on_fulfilled)
+ .ToLocal(&result_promise)) {
return ScriptPromise();
+ }
+ return ScriptPromise(script_state_, result_promise);
}
- if (!on_rejected.IsEmpty()) {
- if (!result_promise->Catch(script_state_->GetContext(), on_rejected)
- .ToLocal(&result_promise))
+
+ if (on_fulfilled.IsEmpty()) {
+ if (!promise->Catch(script_state_->GetContext(), on_rejected)
+ .ToLocal(&result_promise)) {
return ScriptPromise();
+ }
+ return ScriptPromise(script_state_, result_promise);
}
+ if (!promise->Then(script_state_->GetContext(), on_fulfilled, on_rejected)
+ .ToLocal(&result_promise)) {
+ return ScriptPromise();
+ }
return ScriptPromise(script_state_, result_promise);
}
@@ -333,6 +343,12 @@ v8::Local<v8::Promise> ScriptPromise::RejectRaw(ScriptState* script_state,
return promise;
}
+void ScriptPromise::MarkAsHandled() {
+ if (promise_.IsEmpty())
+ return;
+ promise_.V8Value().As<v8::Promise>()->MarkAsHandled();
+}
+
ScriptPromise ScriptPromise::All(ScriptState* script_state,
const Vector<ScriptPromise>& promises) {
return PromiseAllHandler::All(script_state, promises);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h
index 1015e4057c2..99c0119c4fa 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h
@@ -67,9 +67,8 @@ class CORE_EXPORT ScriptPromise final {
~ScriptPromise();
- ScriptPromise Then(
- v8::Local<v8::Function> on_fulfilled,
- v8::Local<v8::Function> on_rejected = v8::Local<v8::Function>());
+ ScriptPromise Then(v8::Local<v8::Function> on_fulfilled,
+ v8::Local<v8::Function> on_rejected = {});
bool IsObject() const { return promise_.IsObject(); }
@@ -89,6 +88,9 @@ class CORE_EXPORT ScriptPromise final {
void Clear() { promise_.Clear(); }
+ // Marks this promise as handled to avoid reporting unhandled rejections.
+ void MarkAsHandled();
+
bool operator==(const ScriptPromise& value) const {
return promise_ == value.promise_;
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_base.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_base.cc
index fa1fb64ec8b..7b1ae6c4523 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_base.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_base.cc
@@ -16,7 +16,7 @@ ScriptPromisePropertyBase::ScriptPromisePropertyBase(
ExecutionContext* execution_context,
Name name)
: ContextClient(execution_context),
- isolate_(ToIsolate(execution_context)),
+ isolate_(execution_context->GetIsolate()),
name_(name),
state_(kPending) {}
@@ -166,8 +166,20 @@ void ScriptPromisePropertyBase::ClearWrappers() {
if (!wrapper.IsEmpty()) {
v8::Context::Scope scope(wrapper->CreationContext());
// TODO(peria): Use deleteProperty() if http://crbug.com/v8/6227 is fixed.
- ResolverSymbol().Set(wrapper, v8::Undefined(isolate_));
- PromiseSymbol().Set(wrapper, v8::Undefined(isolate_));
+
+ // Check whether the value has been set or not. Unfortunately, HasValue
+ // cannot be used as it triggers regular ScriptForbiddenScope through V8
+ // callbacks. GetOrUndefined avoids this because it does not enter a
+ // proper scope in V8.
+ v8::Local<v8::Value> cache;
+ if (ResolverSymbol().GetOrUndefined(wrapper).ToLocal(&cache) &&
+ !cache->IsUndefined()) {
+ ResolverSymbol().Set(wrapper, v8::Undefined(isolate_));
+ }
+ if (PromiseSymbol().GetOrUndefined(wrapper).ToLocal(&cache) &&
+ !cache->IsUndefined()) {
+ PromiseSymbol().Set(wrapper, v8::Undefined(isolate_));
+ }
}
}
wrappers_.clear();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
index 608124103c8..78cce79853f 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
@@ -30,14 +30,14 @@ namespace {
class NotReached : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
- NotReached* self = new NotReached(script_state);
+ NotReached* self = MakeGarbageCollected<NotReached>(script_state);
return self->BindToV8Function();
}
- private:
explicit NotReached(ScriptState* script_state)
: ScriptFunction(script_state) {}
+ private:
ScriptValue Call(ScriptValue) override;
};
@@ -51,16 +51,17 @@ class StubFunction : public ScriptFunction {
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
ScriptValue& value,
size_t& call_count) {
- StubFunction* self = new StubFunction(script_state, value, call_count);
+ StubFunction* self =
+ MakeGarbageCollected<StubFunction>(script_state, value, call_count);
return self->BindToV8Function();
}
- private:
StubFunction(ScriptState* script_state,
ScriptValue& value,
size_t& call_count)
: ScriptFunction(script_state), value_(value), call_count_(call_count) {}
+ private:
ScriptValue Call(ScriptValue arg) override {
value_ = arg;
call_count_++;
@@ -79,9 +80,10 @@ class GarbageCollectedHolder final : public GarbageCollectedScriptWrappable {
Property;
GarbageCollectedHolder(ExecutionContext* execution_context)
: GarbageCollectedScriptWrappable("holder"),
- property_(new Property(execution_context,
- ToGarbageCollectedScriptWrappable(),
- Property::kReady)) {}
+ property_(
+ MakeGarbageCollected<Property>(execution_context,
+ ToGarbageCollectedScriptWrappable(),
+ Property::kReady)) {}
Property* GetProperty() { return property_; }
GarbageCollectedScriptWrappable* ToGarbageCollectedScriptWrappable() {
@@ -110,7 +112,7 @@ class ScriptPromisePropertyTestBase {
virtual ~ScriptPromisePropertyTestBase() { DestroyContext(); }
Document& GetDocument() { return page_->GetDocument(); }
- v8::Isolate* GetIsolate() { return ToIsolate(&GetDocument()); }
+ v8::Isolate* GetIsolate() { return GetDocument().GetIsolate(); }
ScriptState* MainScriptState() {
return ToScriptStateForMainWorld(GetDocument().GetFrame());
}
@@ -194,7 +196,7 @@ class ScriptPromisePropertyNonScriptWrappableResolutionTargetTest
typedef ScriptPromiseProperty<Member<GarbageCollectedScriptWrappable>, T,
ToV8UndefinedGenerator>
Property;
- Property* property = new Property(
+ Property* property = MakeGarbageCollected<Property>(
&GetDocument(),
MakeGarbageCollected<GarbageCollectedScriptWrappable>("holder"),
Property::kReady);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
index f00ecd53742..db31c692c7e 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
@@ -15,7 +15,7 @@
namespace blink {
ScriptPromiseResolver::ScriptPromiseResolver(ScriptState* script_state)
- : PausableObject(ExecutionContext::From(script_state)),
+ : ContextLifecycleObserver(ExecutionContext::From(script_state)),
state_(kPending),
script_state_(script_state),
resolver_(script_state) {
@@ -25,8 +25,8 @@ ScriptPromiseResolver::ScriptPromiseResolver(ScriptState* script_state)
}
}
-#if DCHECK_IS_ON()
ScriptPromiseResolver::~ScriptPromiseResolver() {
+#if DCHECK_IS_ON()
// This is here temporarily to make it easier to track down which promise
// resolvers are being abandoned.
// TODO(crbug.com/873980): Remove this.
@@ -41,8 +41,8 @@ ScriptPromiseResolver::~ScriptPromiseResolver() {
DCHECK(state_ == kDetached || !is_promise_called_ ||
!GetScriptState()->ContextIsValid() || !GetExecutionContext() ||
GetExecutionContext()->IsContextDestroyed());
-}
#endif
+}
void ScriptPromiseResolver::Reject(ExceptionState& exception_state) {
DCHECK(exception_state.HadException());
@@ -50,15 +50,6 @@ void ScriptPromiseResolver::Reject(ExceptionState& exception_state) {
exception_state.ClearException();
}
-void ScriptPromiseResolver::Pause() {
- deferred_resolve_task_.Cancel();
-}
-
-void ScriptPromiseResolver::Unpause() {
- if (state_ == kResolving || state_ == kRejecting)
- ScheduleResolveOrReject();
-}
-
void ScriptPromiseResolver::Detach() {
if (state_ == kDetached)
return;
@@ -115,7 +106,7 @@ void ScriptPromiseResolver::ResolveOrRejectDeferred() {
void ScriptPromiseResolver::Trace(blink::Visitor* visitor) {
visitor->Trace(script_state_);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h
index f6df61365bf..1b247be68e0 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h
@@ -8,7 +8,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
@@ -28,37 +28,32 @@ namespace blink {
// functionalities.
// - A ScriptPromiseResolver retains a ScriptState. A caller
// can call resolve or reject from outside of a V8 context.
-// - This class is an PausableObject and keeps track of the associated
-// ExecutionContext state. When the ExecutionContext is suspended,
-// resolve or reject will be delayed. When it is stopped, resolve or reject
+// - This class is an ContextLifecycleObserver and keeps track of the
+// associated ExecutionContext state. When it is stopped, resolve or reject
// will be ignored.
//
// There are cases where promises cannot work (e.g., where the thread is being
// terminated). In such cases operations will silently fail.
class CORE_EXPORT ScriptPromiseResolver
: public GarbageCollectedFinalized<ScriptPromiseResolver>,
- public PausableObject {
+ public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(ScriptPromiseResolver);
WTF_MAKE_NONCOPYABLE(ScriptPromiseResolver);
public:
static ScriptPromiseResolver* Create(ScriptState* script_state) {
- ScriptPromiseResolver* resolver =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- resolver->PauseIfNeeded();
- return resolver;
+ return MakeGarbageCollected<ScriptPromiseResolver>(script_state);
}
// You need to call suspendIfNeeded after the construction because
// this is an PausableObject.
explicit ScriptPromiseResolver(ScriptState*);
+ virtual ~ScriptPromiseResolver();
#if DCHECK_IS_ON()
// Eagerly finalized so as to ensure valid access to getExecutionContext()
// from the destructor's assert.
EAGERLY_FINALIZE();
-
- ~ScriptPromiseResolver() override;
#endif
// Anything that can be passed to toV8 can be passed to this function.
@@ -90,9 +85,7 @@ class CORE_EXPORT ScriptPromiseResolver
return resolver_.Promise();
}
- // PausableObject implementation.
- void Pause() override;
- void Unpause() override;
+ // ContextLifecycleObserver implementation.
void ContextDestroyed(ExecutionContext*) override { Detach(); }
// Calling this function makes the resolver release its internal resources.
@@ -140,8 +133,7 @@ class CORE_EXPORT ScriptPromiseResolver
}
if (GetExecutionContext()->IsContextPaused()) {
- // Retain this object until it is actually resolved or rejected.
- KeepAliveWhilePending();
+ ScheduleResolveOrReject();
return;
}
// TODO(esprehn): This is a hack, instead we should CHECK that
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
index 2e5e2075c60..d226bca4a94 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
@@ -25,14 +25,15 @@ class TestHelperFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
String* value) {
- TestHelperFunction* self = new TestHelperFunction(script_state, value);
+ TestHelperFunction* self =
+ MakeGarbageCollected<TestHelperFunction>(script_state, value);
return self->BindToV8Function();
}
- private:
TestHelperFunction(ScriptState* script_state, String* value)
: ScriptFunction(script_state), value_(value) {}
+ private:
ScriptValue Call(ScriptValue value) override {
DCHECK(!value.IsEmpty());
*value_ = ToCoreString(value.V8Value()
@@ -201,22 +202,17 @@ TEST_F(ScriptPromiseResolverTest, stop) {
class ScriptPromiseResolverKeepAlive : public ScriptPromiseResolver {
public:
static ScriptPromiseResolverKeepAlive* Create(ScriptState* script_state) {
- ScriptPromiseResolverKeepAlive* resolver =
- new ScriptPromiseResolverKeepAlive(script_state);
- resolver->PauseIfNeeded();
- return resolver;
+ return MakeGarbageCollected<ScriptPromiseResolverKeepAlive>(script_state);
}
+ explicit ScriptPromiseResolverKeepAlive(ScriptState* script_state)
+ : ScriptPromiseResolver(script_state) {}
~ScriptPromiseResolverKeepAlive() override { destructor_calls_++; }
static void Reset() { destructor_calls_ = 0; }
static bool IsAlive() { return !destructor_calls_; }
static int destructor_calls_;
-
- private:
- explicit ScriptPromiseResolverKeepAlive(ScriptState* script_state)
- : ScriptPromiseResolver(script_state) {}
};
int ScriptPromiseResolverKeepAlive::destructor_calls_ = 0;
@@ -320,7 +316,7 @@ TEST_F(ScriptPromiseResolverTest, suspend) {
BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
ASSERT_TRUE(ScriptPromiseResolverKeepAlive::IsAlive());
- GetExecutionContext()->PausePausableObjects();
+ GetExecutionContext()->PausePausableObjects(PauseState::kFrozen);
resolver->Resolve("hello");
ThreadState::Current()->CollectGarbage(
BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc
index 5192d0beb78..0662945692e 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc
@@ -52,14 +52,15 @@ class FunctionForScriptPromiseTest : public ScriptFunction {
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
ScriptValue* output) {
FunctionForScriptPromiseTest* self =
- new FunctionForScriptPromiseTest(script_state, output);
+ MakeGarbageCollected<FunctionForScriptPromiseTest>(script_state,
+ output);
return self->BindToV8Function();
}
- private:
FunctionForScriptPromiseTest(ScriptState* script_state, ScriptValue* output)
: ScriptFunction(script_state), output_(output) {}
+ private:
ScriptValue Call(ScriptValue value) override {
DCHECK(!value.IsEmpty());
*output_ = value;
@@ -69,6 +70,23 @@ class FunctionForScriptPromiseTest : public ScriptFunction {
ScriptValue* output_;
};
+class ThrowingFunction : public ScriptFunction {
+ public:
+ static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
+ auto* self = MakeGarbageCollected<ThrowingFunction>(script_state);
+ return self->BindToV8Function();
+ }
+
+ ThrowingFunction(ScriptState* script_state) : ScriptFunction(script_state) {}
+
+ private:
+ ScriptValue Call(ScriptValue value) override {
+ v8::Isolate* isolate = GetScriptState()->GetIsolate();
+ isolate->ThrowException(v8::Undefined(isolate));
+ return ScriptValue();
+ }
+};
+
String ToString(v8::Local<v8::Context> context, const ScriptValue& value) {
return ToCoreString(value.V8Value()->ToString(context).ToLocalChecked());
}
@@ -79,7 +97,7 @@ Vector<String> ToStringArray(v8::Isolate* isolate, const ScriptValue& value) {
isolate, value.V8Value(), exception_state);
}
-TEST(ScriptPromiseTest, constructFromNonPromise) {
+TEST(ScriptPromiseTest, ConstructFromNonPromise) {
V8TestingScope scope;
v8::TryCatch try_catch(scope.GetIsolate());
ScriptPromise promise(scope.GetScriptState(),
@@ -88,7 +106,7 @@ TEST(ScriptPromiseTest, constructFromNonPromise) {
ASSERT_TRUE(promise.IsEmpty());
}
-TEST(ScriptPromiseTest, thenResolve) {
+TEST(ScriptPromiseTest, ThenResolve) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
ScriptPromise promise = resolver.Promise();
@@ -114,7 +132,7 @@ TEST(ScriptPromiseTest, thenResolve) {
EXPECT_TRUE(on_rejected.IsEmpty());
}
-TEST(ScriptPromiseTest, resolveThen) {
+TEST(ScriptPromiseTest, ResolveThen) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
ScriptPromise promise = resolver.Promise();
@@ -135,7 +153,7 @@ TEST(ScriptPromiseTest, resolveThen) {
EXPECT_TRUE(on_rejected.IsEmpty());
}
-TEST(ScriptPromiseTest, thenReject) {
+TEST(ScriptPromiseTest, ThenReject) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
ScriptPromise promise = resolver.Promise();
@@ -161,7 +179,75 @@ TEST(ScriptPromiseTest, thenReject) {
EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected));
}
-TEST(ScriptPromiseTest, rejectThen) {
+TEST(ScriptPromiseTest, ThrowingOnFulfilled) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ ScriptValue on_rejected, on_fulfilled2, on_rejected2;
+
+ promise =
+ promise.Then(ThrowingFunction::CreateFunction(scope.GetScriptState()),
+ FunctionForScriptPromiseTest::CreateFunction(
+ scope.GetScriptState(), &on_rejected));
+ promise.Then(FunctionForScriptPromiseTest::CreateFunction(
+ scope.GetScriptState(), &on_fulfilled2),
+ FunctionForScriptPromiseTest::CreateFunction(
+ scope.GetScriptState(), &on_rejected2));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_rejected.IsEmpty());
+ EXPECT_TRUE(on_fulfilled2.IsEmpty());
+ EXPECT_TRUE(on_rejected2.IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ resolver.Resolve(V8String(scope.GetIsolate(), "hello"));
+
+ EXPECT_TRUE(on_rejected.IsEmpty());
+ EXPECT_TRUE(on_fulfilled2.IsEmpty());
+ EXPECT_TRUE(on_rejected2.IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_TRUE(on_rejected.IsEmpty());
+ EXPECT_TRUE(on_fulfilled2.IsEmpty());
+ EXPECT_FALSE(on_rejected2.IsEmpty());
+}
+
+TEST(ScriptPromiseTest, ThrowingOnRejected) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ ScriptValue on_fulfilled, on_fulfilled2, on_rejected2;
+
+ promise =
+ promise.Then(FunctionForScriptPromiseTest::CreateFunction(
+ scope.GetScriptState(), &on_fulfilled2),
+ ThrowingFunction::CreateFunction(scope.GetScriptState()));
+ promise.Then(FunctionForScriptPromiseTest::CreateFunction(
+ scope.GetScriptState(), &on_fulfilled2),
+ FunctionForScriptPromiseTest::CreateFunction(
+ scope.GetScriptState(), &on_rejected2));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_fulfilled.IsEmpty());
+ EXPECT_TRUE(on_fulfilled2.IsEmpty());
+ EXPECT_TRUE(on_rejected2.IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ resolver.Reject(V8String(scope.GetIsolate(), "hello"));
+
+ EXPECT_TRUE(on_fulfilled.IsEmpty());
+ EXPECT_TRUE(on_fulfilled2.IsEmpty());
+ EXPECT_TRUE(on_rejected2.IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_TRUE(on_fulfilled.IsEmpty());
+ EXPECT_TRUE(on_fulfilled2.IsEmpty());
+ EXPECT_FALSE(on_rejected2.IsEmpty());
+}
+
+TEST(ScriptPromiseTest, RejectThen) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
ScriptPromise promise = resolver.Promise();
@@ -182,7 +268,7 @@ TEST(ScriptPromiseTest, rejectThen) {
EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected));
}
-TEST(ScriptPromiseTest, castPromise) {
+TEST(ScriptPromiseTest, CastPromise) {
V8TestingScope scope;
ScriptPromise promise = Resolver(scope.GetScriptState()).Promise();
ScriptPromise new_promise =
@@ -192,7 +278,7 @@ TEST(ScriptPromiseTest, castPromise) {
EXPECT_EQ(promise.V8Value(), new_promise.V8Value());
}
-TEST(ScriptPromiseTest, castNonPromise) {
+TEST(ScriptPromiseTest, CastNonPromise) {
V8TestingScope scope;
ScriptValue on_fulfilled1, on_fulfilled2, on_rejected1, on_rejected2;
@@ -231,7 +317,7 @@ TEST(ScriptPromiseTest, castNonPromise) {
EXPECT_TRUE(on_rejected2.IsEmpty());
}
-TEST(ScriptPromiseTest, reject) {
+TEST(ScriptPromiseTest, Reject) {
V8TestingScope scope;
ScriptValue on_fulfilled, on_rejected;
@@ -256,7 +342,7 @@ TEST(ScriptPromiseTest, reject) {
EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected));
}
-TEST(ScriptPromiseTest, rejectWithExceptionState) {
+TEST(ScriptPromiseTest, RejectWithExceptionState) {
V8TestingScope scope;
ScriptValue on_fulfilled, on_rejected;
ScriptPromise promise = ScriptPromise::RejectWithDOMException(
@@ -279,7 +365,7 @@ TEST(ScriptPromiseTest, rejectWithExceptionState) {
ToString(scope.GetContext(), on_rejected));
}
-TEST(ScriptPromiseTest, allWithEmptyPromises) {
+TEST(ScriptPromiseTest, AllWithEmptyPromises) {
V8TestingScope scope;
ScriptValue on_fulfilled, on_rejected;
@@ -302,7 +388,7 @@ TEST(ScriptPromiseTest, allWithEmptyPromises) {
EXPECT_TRUE(on_rejected.IsEmpty());
}
-TEST(ScriptPromiseTest, allWithResolvedPromises) {
+TEST(ScriptPromiseTest, AllWithResolvedPromises) {
V8TestingScope scope;
ScriptValue on_fulfilled, on_rejected;
@@ -332,7 +418,7 @@ TEST(ScriptPromiseTest, allWithResolvedPromises) {
EXPECT_TRUE(on_rejected.IsEmpty());
}
-TEST(ScriptPromiseTest, allWithRejectedPromise) {
+TEST(ScriptPromiseTest, AllWithRejectedPromise) {
V8TestingScope scope;
ScriptValue on_fulfilled, on_rejected;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_source_code.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_source_code.cc
index 312f8934487..2993ffb7c08 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_source_code.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_source_code.cc
@@ -83,7 +83,8 @@ ScriptSourceCode::ScriptSourceCode(ScriptStreamer* streamer,
cache_handler_(resource->CacheHandler()),
streamer_(streamer),
not_streaming_reason_(reason),
- url_(StripFragmentIdentifier(resource->GetResponse().Url())),
+ url_(
+ StripFragmentIdentifier(resource->GetResponse().CurrentRequestUrl())),
source_map_url_(SourceMapUrlFromResponse(resource->GetResponse())),
start_position_(TextPosition::MinimumPosition()),
source_location_type_(ScriptSourceLocationType::kExternalFile) {
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
index dc00b6abda9..fafa399669c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
@@ -160,7 +160,8 @@ TEST_F(ScriptStreamingTest, CompilingStreamedScript) {
// Test that we can successfully compile a streamed script.
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
AppendData("function foo() {");
@@ -198,7 +199,8 @@ TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) {
// handle it gracefully.
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
AppendData("function foo() {");
AppendData("this is the part which will be a parse error");
@@ -237,7 +239,8 @@ TEST_F(ScriptStreamingTest, CancellingStreaming) {
// while streaming is ongoing, and ScriptStreamer handles it gracefully.
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
AppendData("function foo() {");
@@ -262,7 +265,8 @@ TEST_F(ScriptStreamingTest, DataAfterDisposingPendingScript) {
// before streaming is started, and ScriptStreamer handles it gracefully.
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
// In general, we cannot control what the background thread is doing
@@ -298,7 +302,8 @@ TEST_F(ScriptStreamingTest, SuppressingStreaming) {
// script is loaded.
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
AppendData("function foo() {");
AppendPadding();
@@ -306,7 +311,7 @@ TEST_F(ScriptStreamingTest, SuppressingStreaming) {
SingleCachedMetadataHandler* cache_handler = GetResource()->CacheHandler();
EXPECT_TRUE(cache_handler);
cache_handler->SetCachedMetadata(V8CodeCache::TagForCodeCache(cache_handler),
- "X", 1,
+ reinterpret_cast<const uint8_t*>("X"), 1,
CachedMetadataHandler::kCacheLocally);
AppendPadding();
@@ -327,7 +332,8 @@ TEST_F(ScriptStreamingTest, EmptyScripts) {
// loaded.
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
// Finish the script without sending any data.
@@ -346,7 +352,8 @@ TEST_F(ScriptStreamingTest, SmallScripts) {
ScriptStreamer::SetSmallScriptThresholdForTesting(100);
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
AppendData("function foo() { }");
@@ -368,7 +375,8 @@ TEST_F(ScriptStreamingTest, ScriptsWithSmallFirstChunk) {
ScriptStreamer::SetSmallScriptThresholdForTesting(100);
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
// This is the first data chunk which is small.
@@ -405,7 +413,8 @@ TEST_F(ScriptStreamingTest, EncodingChanges) {
GetResource()->SetEncodingForTest("windows-1252");
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
GetResource()->SetEncodingForTest("UTF-8");
@@ -444,7 +453,8 @@ TEST_F(ScriptStreamingTest, EncodingFromBOM) {
GetResource()->SetEncodingForTest("windows-1252");
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
// \xef\xbb\xbf is the UTF-8 byte order mark. \xec\x92\x81 are the raw bytes
@@ -478,7 +488,8 @@ TEST_F(ScriptStreamingTest, GarbageCollectDuringStreaming) {
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
EXPECT_FALSE(client->Finished());
@@ -492,7 +503,8 @@ TEST_F(ScriptStreamingTest, ResourceSetRevalidatingRequest) {
V8TestingScope scope;
GetResource()->StartStreaming(loading_task_runner_);
- TestPendingScriptClient* client = new TestPendingScriptClient;
+ TestPendingScriptClient* client =
+ MakeGarbageCollected<TestPendingScriptClient>();
GetPendingScript()->WatchForLoad(client);
// Kick the streaming off.
@@ -503,14 +515,16 @@ TEST_F(ScriptStreamingTest, ResourceSetRevalidatingRequest) {
ProcessTasksUntilStreamingComplete();
// Second start streaming should fail.
- EXPECT_FALSE(GetResource()->StartStreaming(loading_task_runner_));
+ GetResource()->StartStreaming(loading_task_runner_);
+ EXPECT_FALSE(GetResource()->HasRunningStreamer());
ResourceRequest request(GetResource()->Url());
GetResource()->SetRevalidatingRequest(request);
// The next streaming should still fail, but the reason should be
// "kRevalidate".
- EXPECT_FALSE(GetResource()->StartStreaming(loading_task_runner_));
+ GetResource()->StartStreaming(loading_task_runner_);
+ EXPECT_FALSE(GetResource()->HasRunningStreamer());
EXPECT_EQ(GetResource()->NoStreamerReason(), ScriptStreamer::kRevalidate);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_value.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_value.cc
index 291b5b6c290..4df0baeb46e 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_value.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_value.cc
@@ -99,14 +99,4 @@ ScriptValue ScriptValue::CreateNull(ScriptState* script_state) {
return ScriptValue(script_state, v8::Null(script_state->GetIsolate()));
}
-// static
-ScriptValue ScriptValue::ToWorldSafeScriptValue(
- ScriptState* target_script_state,
- const TraceWrapperV8Reference<v8::Value>& value) {
- return ScriptValue(
- target_script_state,
- ToWorldSafeValue(target_script_state,
- value.NewLocal(target_script_state->GetIsolate())));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_value.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_value.h
index fda34f5bf06..457c56aabff 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_value.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_value.h
@@ -169,10 +169,6 @@ class CORE_EXPORT ScriptValue final {
static ScriptValue CreateNull(ScriptState*);
- static ScriptValue ToWorldSafeScriptValue(
- ScriptState* target_script_state,
- const TraceWrapperV8Reference<v8::Value>& value);
-
private:
// TODO(peria): Move ScriptValue to Oilpan heap.
GC_PLUGIN_IGNORE("813731")
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_wrappable_marking_visitor_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_wrappable_marking_visitor_test.cc
index 15b9fe13297..7fa7e445c8a 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_wrappable_marking_visitor_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_wrappable_marking_visitor_test.cc
@@ -226,20 +226,20 @@ namespace {
class HandleContainer
: public blink::GarbageCollectedFinalized<HandleContainer> {
public:
- static HandleContainer* Create() { return new HandleContainer(); }
+ static HandleContainer* Create() {
+ return MakeGarbageCollected<HandleContainer>();
+ }
+
+ HandleContainer() = default;
virtual ~HandleContainer() = default;
- void Trace(blink::Visitor* visitor) {
- visitor->Trace(handle_.Cast<v8::Value>());
- }
+ void Trace(blink::Visitor* visitor) { visitor->Trace(handle_); }
void SetValue(v8::Isolate* isolate, v8::Local<v8::String> string) {
handle_.Set(isolate, string);
}
private:
- HandleContainer() = default;
-
TraceWrapperV8Reference<v8::String> handle_;
};
@@ -413,7 +413,14 @@ class Base : public blink::GarbageCollected<Base>,
public:
static Base* Create(DeathAwareScriptWrappable* wrapper_in_base,
DeathAwareScriptWrappable* wrapper_in_mixin) {
- return new Base(wrapper_in_base, wrapper_in_mixin);
+ return MakeGarbageCollected<Base>(wrapper_in_base, wrapper_in_mixin);
+ }
+
+ Base(DeathAwareScriptWrappable* wrapper_in_base,
+ DeathAwareScriptWrappable* wrapper_in_mixin)
+ : Mixin(wrapper_in_mixin), wrapper_in_base_(wrapper_in_base) {
+ // Use field_;
+ field_ = 0;
}
void Trace(Visitor* visitor) override {
@@ -424,13 +431,6 @@ class Base : public blink::GarbageCollected<Base>,
const char* NameInHeapSnapshot() const override { return "HandleContainer"; }
protected:
- Base(DeathAwareScriptWrappable* wrapper_in_base,
- DeathAwareScriptWrappable* wrapper_in_mixin)
- : Mixin(wrapper_in_mixin), wrapper_in_base_(wrapper_in_base) {
- // Use field_;
- field_ = 0;
- }
-
DeathAwareScriptWrappable::Wrapper wrapper_in_base_;
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
index 3cbeb15d057..f65a8add719 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
@@ -68,6 +68,7 @@ enum SerializationTag {
// OffscreenCanvas. For OffscreenCanvas
// transfer
kReadableStreamTransferTag = 'r', // index:uint32_t
+ kTransformStreamTransferTag = 'm', // index:uint32_t
kWritableStreamTransferTag = 'w', // index:uint32_t
kDOMPointTag = 'Q', // x:Double, y:Double, z:Double, w:Double
kDOMPointReadOnlyTag = 'W', // x:Double, y:Double, z:Double, w:Double
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
index 0fbf601bfe2..78a579ae4b4 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
@@ -49,11 +49,13 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_offscreen_canvas.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_shared_array_buffer.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_transform_stream.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/transform_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h"
@@ -386,32 +388,76 @@ void SerializedScriptValue::TransferReadableStreams(
ExceptionState& exception_state) {
auto* execution_context = ExecutionContext::From(script_state);
for (ReadableStream* readable_stream : readable_streams) {
- mojo::MessagePipe pipe;
- MessagePort* local_port = MessagePort::Create(*execution_context);
- local_port->Entangle(std::move(pipe.handle0));
- readable_stream->Serialize(script_state, local_port, exception_state);
+ TransferReadableStream(script_state, execution_context, readable_stream,
+ exception_state);
if (exception_state.HadException())
return;
- stream_channels_.push_back(MessagePortChannel(std::move(pipe.handle1)));
}
}
+void SerializedScriptValue::TransferReadableStream(
+ ScriptState* script_state,
+ ExecutionContext* execution_context,
+ ReadableStream* readable_stream,
+ ExceptionState& exception_state) {
+ MessagePort* local_port = AddStreamChannel(execution_context);
+ readable_stream->Serialize(script_state, local_port, exception_state);
+ if (exception_state.HadException())
+ return;
+}
+
void SerializedScriptValue::TransferWritableStreams(
ScriptState* script_state,
const WritableStreamArray& writable_streams,
ExceptionState& exception_state) {
auto* execution_context = ExecutionContext::From(script_state);
for (WritableStream* writable_stream : writable_streams) {
- mojo::MessagePipe pipe;
- MessagePort* local_port = MessagePort::Create(*execution_context);
- local_port->Entangle(std::move(pipe.handle0));
- writable_stream->Serialize(script_state, local_port, exception_state);
+ TransferWritableStream(script_state, execution_context, writable_stream,
+ exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+}
+
+void SerializedScriptValue::TransferWritableStream(
+ ScriptState* script_state,
+ ExecutionContext* execution_context,
+ WritableStream* writable_stream,
+ ExceptionState& exception_state) {
+ MessagePort* local_port = AddStreamChannel(execution_context);
+ writable_stream->Serialize(script_state, local_port, exception_state);
+ if (exception_state.HadException())
+ return;
+}
+
+void SerializedScriptValue::TransferTransformStreams(
+ ScriptState* script_state,
+ const TransformStreamArray& transform_streams,
+ ExceptionState& exception_state) {
+ auto* execution_context = ExecutionContext::From(script_state);
+ for (TransformStream* transform_stream : transform_streams) {
+ TransferReadableStream(script_state, execution_context,
+ transform_stream->Readable(), exception_state);
+ if (exception_state.HadException())
+ return;
+ TransferWritableStream(script_state, execution_context,
+ transform_stream->Writable(), exception_state);
if (exception_state.HadException())
return;
- stream_channels_.push_back(MessagePortChannel(std::move(pipe.handle1)));
}
}
+// Creates an entangled pair of channels. Adds one end to |stream_channels_| as
+// a MessagePortChannel, and returns the other end as a MessagePort.
+MessagePort* SerializedScriptValue::AddStreamChannel(
+ ExecutionContext* execution_context) {
+ mojo::MessagePipe pipe;
+ MessagePort* local_port = MessagePort::Create(*execution_context);
+ local_port->Entangle(std::move(pipe.handle0));
+ stream_channels_.push_back(MessagePortChannel(std::move(pipe.handle1)));
+ return local_port;
+}
+
void SerializedScriptValue::TransferArrayBuffers(
v8::Isolate* isolate,
const ArrayBufferArray& array_buffers,
@@ -592,6 +638,18 @@ bool SerializedScriptValue::ExtractTransferables(
return false;
}
transferables.writable_streams.push_back(stream);
+ } else if (RuntimeEnabledFeatures::TransferableStreamsEnabled() &&
+ V8TransformStream::HasInstance(transferable_object, isolate)) {
+ TransformStream* stream = V8TransformStream::ToImpl(
+ v8::Local<v8::Object>::Cast(transferable_object));
+ if (transferables.transform_streams.Contains(stream)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kDataCloneError,
+ "TransformStream at index " + String::Number(i) +
+ " is a duplicate of an earlier TransformStream.");
+ return false;
+ }
+ transferables.transform_streams.push_back(stream);
} else {
exception_state.ThrowTypeError("Value at index " + String::Number(i) +
" does not have a transferable type.");
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
index eea425054ed..0702f58f0bc 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
@@ -53,6 +53,8 @@ namespace blink {
class BlobDataHandle;
class DOMSharedArrayBuffer;
class ExceptionState;
+class ExecutionContext;
+class MessagePort;
class ScriptValue;
class SharedBuffer;
class StaticBitmapImage;
@@ -72,7 +74,7 @@ class CORE_EXPORT SerializedScriptValue
using SharedArrayBufferContentsArray = Vector<WTF::ArrayBufferContents, 1>;
using ImageBitmapContentsArray = Vector<scoped_refptr<StaticBitmapImage>, 1>;
using TransferredWasmModulesArray =
- WTF::Vector<v8::WasmCompiledModule::TransferrableModule>;
+ WTF::Vector<v8::WasmModuleObject::TransferrableModule>;
using MessagePortChannelArray = Vector<MessagePortChannel>;
// Increment this for each incompatible change to the wire format.
@@ -295,9 +297,22 @@ class CORE_EXPORT SerializedScriptValue
void TransferReadableStreams(ScriptState*,
const ReadableStreamArray&,
ExceptionState&);
+ void TransferReadableStream(ScriptState* script_state,
+ ExecutionContext* execution_context,
+ ReadableStream* readable_streams,
+ ExceptionState& exception_state);
void TransferWritableStreams(ScriptState*,
const WritableStreamArray&,
ExceptionState&);
+ void TransferWritableStream(ScriptState* script_state,
+ ExecutionContext* execution_context,
+ WritableStream* writable_streams,
+ ExceptionState& exception_state);
+ void TransferTransformStreams(ScriptState*,
+ const TransformStreamArray&,
+ ExceptionState&);
+ MessagePort* AddStreamChannel(ExecutionContext*);
+
void CloneSharedArrayBuffers(SharedArrayBufferArray&);
DataBufferPtr data_buffer_;
size_t data_buffer_size_ = 0;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h
index 2408ccf5276..d1937e15699 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h
@@ -19,6 +19,7 @@ class MessagePort;
class MojoHandle;
class ReadableStream;
class WritableStream;
+class TransformStream;
using ArrayBufferArray = HeapVector<Member<DOMArrayBufferBase>>;
using ImageBitmapArray = HeapVector<Member<ImageBitmap>>;
@@ -27,6 +28,7 @@ using MessagePortArray = HeapVector<Member<MessagePort>>;
using MojoHandleArray = HeapVector<Member<blink::MojoHandle>>;
using ReadableStreamArray = HeapVector<Member<ReadableStream>>;
using WritableStreamArray = HeapVector<Member<WritableStream>>;
+using TransformStreamArray = HeapVector<Member<TransformStream>>;
class CORE_EXPORT Transferables final {
STACK_ALLOCATED();
@@ -42,6 +44,7 @@ class CORE_EXPORT Transferables final {
MojoHandleArray mojo_handles;
ReadableStreamArray readable_streams;
WritableStreamArray writable_streams;
+ TransformStreamArray transform_streams;
};
// Along with extending |Transferables| to hold a new kind of transferable
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
index bf2da93684b..4c6ec62896f 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/mojo/mojo_handle.h"
#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/transform_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h"
@@ -536,6 +537,28 @@ ScriptWrappable* V8ScriptValueDeserializer::ReadDOMObject(
script_state_, (*transferred_stream_ports_)[index].Get(),
exception_state);
}
+ case kTransformStreamTransferTag: {
+ if (!RuntimeEnabledFeatures::TransferableStreamsEnabled())
+ return nullptr;
+ uint32_t index = 0;
+ if (!ReadUint32(&index) || !transferred_stream_ports_ ||
+ index + 1 >= transferred_stream_ports_->size()) {
+ return nullptr;
+ }
+ ReadableStream* readable = ReadableStream::Deserialize(
+ script_state_, (*transferred_stream_ports_)[index].Get(),
+ exception_state);
+ if (!readable)
+ return nullptr;
+
+ WritableStream* writable = WritableStream::Deserialize(
+ script_state_, (*transferred_stream_ports_)[index + 1].Get(),
+ exception_state);
+ if (!writable)
+ return nullptr;
+
+ return MakeGarbageCollected<TransformStream>(readable, writable);
+ }
default:
break;
}
@@ -655,15 +678,15 @@ v8::MaybeLocal<v8::Object> V8ScriptValueDeserializer::ReadHostObject(
return wrapper.As<v8::Object>();
}
-v8::MaybeLocal<v8::WasmCompiledModule>
+v8::MaybeLocal<v8::WasmModuleObject>
V8ScriptValueDeserializer::GetWasmModuleFromId(v8::Isolate* isolate,
uint32_t id) {
if (id < serialized_script_value_->WasmModules().size()) {
- return v8::WasmCompiledModule::FromTransferrableModule(
+ return v8::WasmModuleObject::FromTransferrableModule(
isolate, serialized_script_value_->WasmModules()[id]);
}
CHECK(serialized_script_value_->WasmModules().IsEmpty());
- return v8::MaybeLocal<v8::WasmCompiledModule>();
+ return v8::MaybeLocal<v8::WasmModuleObject>();
}
v8::MaybeLocal<v8::SharedArrayBuffer>
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h
index 665dcfe18d7..78511fe2f23 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h
@@ -100,8 +100,8 @@ class CORE_EXPORT V8ScriptValueDeserializer
// v8::ValueDeserializer::Delegate
v8::MaybeLocal<v8::Object> ReadHostObject(v8::Isolate*) override;
- v8::MaybeLocal<v8::WasmCompiledModule> GetWasmModuleFromId(v8::Isolate*,
- uint32_t) override;
+ v8::MaybeLocal<v8::WasmModuleObject> GetWasmModuleFromId(v8::Isolate*,
+ uint32_t) override;
v8::MaybeLocal<v8::SharedArrayBuffer> GetSharedArrayBufferFromId(
v8::Isolate*,
uint32_t) override;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
index c37928dcd5c..19b2d96dc16 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_shared_array_buffer.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_transform_stream.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
#include "third_party/blink/renderer/core/geometry/dom_matrix.h"
#include "third_party/blink/renderer/core/geometry/dom_matrix_read_only.h"
@@ -36,6 +37,7 @@
#include "third_party/blink/renderer/core/html/canvas/image_data.h"
#include "third_party/blink/renderer/core/mojo/mojo_handle.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/transform_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h"
#include "third_party/blink/renderer/platform/file_metadata.h"
@@ -170,6 +172,9 @@ void V8ScriptValueSerializer::FinalizeTransfer(
return;
if (RuntimeEnabledFeatures::TransferableStreamsEnabled()) {
+ // Order matters here, because the order in which streams are added to the
+ // |stream_ports_| array must match the indexes which are calculated in
+ // WriteDOMObject().
serialized_script_value_->TransferReadableStreams(
script_state_, transferables_->readable_streams, exception_state);
if (exception_state.HadException())
@@ -178,6 +183,10 @@ void V8ScriptValueSerializer::FinalizeTransfer(
script_state_, transferables_->writable_streams, exception_state);
if (exception_state.HadException())
return;
+ serialized_script_value_->TransferTransformStreams(
+ script_state_, transferables_->transform_streams, exception_state);
+ if (exception_state.HadException())
+ return;
}
}
}
@@ -193,7 +202,7 @@ void V8ScriptValueSerializer::WriteUTF8String(const String& string) {
bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
ExceptionState& exception_state) {
const WrapperTypeInfo* wrapper_type_info = wrappable->GetWrapperTypeInfo();
- if (wrapper_type_info == &V8Blob::wrapper_type_info) {
+ if (wrapper_type_info == V8Blob::GetWrapperTypeInfo()) {
Blob* blob = wrappable->ToImpl<Blob>();
serialized_script_value_->BlobDataHandles().Set(blob->Uuid(),
blob->GetBlobDataHandle());
@@ -212,11 +221,11 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
}
return true;
}
- if (wrapper_type_info == &V8File::wrapper_type_info) {
+ if (wrapper_type_info == V8File::GetWrapperTypeInfo()) {
WriteTag(blob_info_array_ ? kFileIndexTag : kFileTag);
return WriteFile(wrappable->ToImpl<File>(), exception_state);
}
- if (wrapper_type_info == &V8FileList::wrapper_type_info) {
+ if (wrapper_type_info == V8FileList::GetWrapperTypeInfo()) {
// This does not presently deduplicate a File object and its entry in a
// FileList, which is non-standard behavior.
FileList* file_list = wrappable->ToImpl<FileList>();
@@ -229,7 +238,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
}
return true;
}
- if (wrapper_type_info == &V8ImageBitmap::wrapper_type_info) {
+ if (wrapper_type_info == V8ImageBitmap::GetWrapperTypeInfo()) {
ImageBitmap* image_bitmap = wrappable->ToImpl<ImageBitmap>();
if (image_bitmap->IsNeutered()) {
exception_state.ThrowDOMException(
@@ -270,7 +279,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteRawBytes(pixels->Data(), pixels->length());
return true;
}
- if (wrapper_type_info == &V8ImageData::wrapper_type_info) {
+ if (wrapper_type_info == V8ImageData::GetWrapperTypeInfo()) {
ImageData* image_data = wrappable->ToImpl<ImageData>();
WriteTag(kImageDataTag);
SerializedColorParams color_params(image_data->GetCanvasColorParams(),
@@ -289,7 +298,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteRawBytes(pixel_buffer->Data(), pixel_buffer_length);
return true;
}
- if (wrapper_type_info == &V8DOMPoint::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMPoint::GetWrapperTypeInfo()) {
DOMPoint* point = wrappable->ToImpl<DOMPoint>();
WriteTag(kDOMPointTag);
WriteDouble(point->x());
@@ -298,7 +307,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteDouble(point->w());
return true;
}
- if (wrapper_type_info == &V8DOMPointReadOnly::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMPointReadOnly::GetWrapperTypeInfo()) {
DOMPointReadOnly* point = wrappable->ToImpl<DOMPointReadOnly>();
WriteTag(kDOMPointReadOnlyTag);
WriteDouble(point->x());
@@ -307,7 +316,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteDouble(point->w());
return true;
}
- if (wrapper_type_info == &V8DOMRect::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMRect::GetWrapperTypeInfo()) {
DOMRect* rect = wrappable->ToImpl<DOMRect>();
WriteTag(kDOMRectTag);
WriteDouble(rect->x());
@@ -316,7 +325,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteDouble(rect->height());
return true;
}
- if (wrapper_type_info == &V8DOMRectReadOnly::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMRectReadOnly::GetWrapperTypeInfo()) {
DOMRectReadOnly* rect = wrappable->ToImpl<DOMRectReadOnly>();
WriteTag(kDOMRectReadOnlyTag);
WriteDouble(rect->x());
@@ -325,7 +334,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteDouble(rect->height());
return true;
}
- if (wrapper_type_info == &V8DOMQuad::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMQuad::GetWrapperTypeInfo()) {
DOMQuad* quad = wrappable->ToImpl<DOMQuad>();
WriteTag(kDOMQuadTag);
for (const DOMPoint* point :
@@ -337,7 +346,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
}
return true;
}
- if (wrapper_type_info == &V8DOMMatrix::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMMatrix::GetWrapperTypeInfo()) {
DOMMatrix* matrix = wrappable->ToImpl<DOMMatrix>();
if (matrix->is2D()) {
WriteTag(kDOMMatrix2DTag);
@@ -368,7 +377,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
}
return true;
}
- if (wrapper_type_info == &V8DOMMatrixReadOnly::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMMatrixReadOnly::GetWrapperTypeInfo()) {
DOMMatrixReadOnly* matrix = wrappable->ToImpl<DOMMatrixReadOnly>();
if (matrix->is2D()) {
WriteTag(kDOMMatrix2DReadOnlyTag);
@@ -399,7 +408,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
}
return true;
}
- if (wrapper_type_info == &V8MessagePort::wrapper_type_info) {
+ if (wrapper_type_info == V8MessagePort::GetWrapperTypeInfo()) {
MessagePort* message_port = wrappable->ToImpl<MessagePort>();
size_t index = kNotFound;
if (transferables_)
@@ -415,7 +424,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteUint32(static_cast<uint32_t>(index));
return true;
}
- if (wrapper_type_info == &V8MojoHandle::wrapper_type_info &&
+ if (wrapper_type_info == V8MojoHandle::GetWrapperTypeInfo() &&
RuntimeEnabledFeatures::MojoJSEnabled()) {
MojoHandle* mojo_handle = wrappable->ToImpl<MojoHandle>();
size_t index = kNotFound;
@@ -435,7 +444,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteUint32(static_cast<uint32_t>(index));
return true;
}
- if (wrapper_type_info == &V8OffscreenCanvas::wrapper_type_info) {
+ if (wrapper_type_info == V8OffscreenCanvas::GetWrapperTypeInfo()) {
OffscreenCanvas* canvas = wrappable->ToImpl<OffscreenCanvas>();
size_t index = kNotFound;
if (transferables_)
@@ -468,7 +477,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteUint32(canvas->SinkId());
return true;
}
- if (wrapper_type_info == &V8ReadableStream::wrapper_type_info &&
+ if (wrapper_type_info == V8ReadableStream::GetWrapperTypeInfo() &&
RuntimeEnabledFeatures::TransferableStreamsEnabled()) {
ReadableStream* stream = wrappable->ToImpl<ReadableStream>();
size_t index = kNotFound;
@@ -492,7 +501,7 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteUint32(static_cast<uint32_t>(index));
return true;
}
- if (wrapper_type_info == &V8WritableStream::wrapper_type_info &&
+ if (wrapper_type_info == V8WritableStream::GetWrapperTypeInfo() &&
RuntimeEnabledFeatures::TransferableStreamsEnabled()) {
WritableStream* stream = wrappable->ToImpl<WritableStream>();
size_t index = kNotFound;
@@ -521,6 +530,41 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
static_cast<uint32_t>(index + transferables_->readable_streams.size()));
return true;
}
+ if (wrapper_type_info == V8TransformStream::GetWrapperTypeInfo() &&
+ RuntimeEnabledFeatures::TransferableStreamsEnabled()) {
+ TransformStream* stream = wrappable->ToImpl<TransformStream>();
+ size_t index = kNotFound;
+ if (transferables_)
+ index = transferables_->transform_streams.Find(stream);
+ if (index == kNotFound) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kDataCloneError,
+ "A TransformStream could not be cloned "
+ "because it was not transferred.");
+ return false;
+ }
+ if (stream->Readable()
+ ->IsLocked(script_state_, exception_state)
+ .value_or(true) ||
+ stream->Writable()
+ ->IsLocked(script_state_, exception_state)
+ .value_or(true)) {
+ if (exception_state.HadException())
+ return false;
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kDataCloneError,
+ "A TransformStream could not be cloned because it was locked");
+ return false;
+ }
+ WriteTag(kTransformStreamTransferTag);
+ DCHECK(transferables_);
+ // TransformStreams use two ports each. The stored index is the index of the
+ // first one. The first TransformStream is stored in the array after all the
+ // ReadableStreams and WritableStreams.
+ WriteUint32(static_cast<uint32_t>(index * 2 +
+ transferables_->readable_streams.size() +
+ transferables_->writable_streams.size()));
+ return true;
+ }
return false;
}
@@ -635,7 +679,7 @@ v8::Maybe<uint32_t> V8ScriptValueSerializer::GetSharedArrayBufferId(
v8::Maybe<uint32_t> V8ScriptValueSerializer::GetWasmModuleTransferId(
v8::Isolate* isolate,
- v8::Local<v8::WasmCompiledModule> module) {
+ v8::Local<v8::WasmModuleObject> module) {
if (for_storage_) {
DCHECK(exception_state_);
DCHECK_EQ(isolate, script_state_->GetIsolate());
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h
index 7d8031fd428..e159a1e0115 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h
@@ -92,7 +92,7 @@ class CORE_EXPORT V8ScriptValueSerializer
v8::Maybe<uint32_t> GetWasmModuleTransferId(
v8::Isolate*,
- v8::Local<v8::WasmCompiledModule>) override;
+ v8::Local<v8::WasmModuleObject>) override;
// Reallocates memory at |ptr| to the new size and returns the new pointer or
// nullptr on failure. |actual_size| will hold the actual size of allocation
// requested.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
index 861eb3a1dce..276b094b120 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -1031,8 +1031,7 @@ TEST(V8ScriptValueSerializerTest, RoundTripImageBitmapWithColorSpaceInfo) {
// Make a 10x7 red ImageBitmap in P3 color space.
SkImageInfo info = SkImageInfo::Make(
10, 7, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut));
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, SkNamedGamut::kDCIP3));
sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
surface->getCanvas()->clear(SK_ColorRED);
ImageBitmap* image_bitmap = ImageBitmap::Create(
@@ -1138,8 +1137,7 @@ TEST(V8ScriptValueSerializerTest, DecodeImageBitmapV18) {
uint8_t pixel[8] = {};
SkImageInfo info = SkImageInfo::Make(
1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut));
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, SkNamedGamut::kDCIP3));
ASSERT_TRUE(new_image_bitmap->BitmapImage()
->PaintImageForCurrentFrame()
.GetSkImage()
@@ -1843,7 +1841,7 @@ TEST(V8ScriptValueSerializerTest, DecodeWithInefficientVersionEnvelope) {
}
// Sanity check for transferring ReadableStreams. This is mostly tested via
-// layout tests.
+// web tests.
TEST(V8ScriptValueSerializerTest, RoundTripReadableStream) {
ScopedTransferableStreamsForTest enable_transferable_streams(true);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc b/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
index 1a433797400..a4171bada28 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
@@ -217,6 +217,12 @@ void UseCounterCallback(v8::Isolate* isolate,
case v8::Isolate::kOptimizedFunctionWithOneShotBytecode:
blink_feature = WebFeature::kV8OptimizedFunctionWithOneShotBytecode;
break;
+ case v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp:
+ blink_feature = WebFeature::kV8RegExpMatchIsTrueishOnNonJSRegExp;
+ break;
+ case v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp:
+ blink_feature = WebFeature::kV8RegExpMatchIsFalseishOnJSRegExp;
+ break;
default:
// This can happen if V8 has added counters that this version of Blink
// does not know about. It's harmless.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
index 6b9272e13bf..2c848e5f7c4 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
@@ -91,7 +91,7 @@ bool V0CustomElementConstructorBuilder::ValidateOptions(
prototype_ = v8::Object::New(script_state_->GetIsolate());
v8::Local<v8::Object> base_prototype =
script_state_->PerContextData()->PrototypeForType(
- &V8HTMLElement::wrapper_type_info);
+ V8HTMLElement::GetWrapperTypeInfo());
if (!base_prototype.IsEmpty()) {
bool set_prototype;
if (!prototype_->SetPrototype(script_state_->GetContext(), base_prototype)
@@ -103,7 +103,7 @@ bool V0CustomElementConstructorBuilder::ValidateOptions(
}
AtomicString namespace_uri = html_names::xhtmlNamespaceURI;
- if (HasValidPrototypeChainFor(&V8SVGElement::wrapper_type_info))
+ if (HasValidPrototypeChainFor(V8SVGElement::GetWrapperTypeInfo()))
namespace_uri = svg_names::kNamespaceURI;
DCHECK(!try_catch.HasCaught());
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
index e2df2fbb1a2..caff64e7d7d 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -641,6 +641,12 @@ LocalDOMWindow* EnteredDOMWindow(v8::Isolate* isolate) {
return window;
}
+LocalDOMWindow* IncumbentDOMWindow(v8::Isolate* isolate) {
+ LocalDOMWindow* window = ToLocalDOMWindow(isolate->GetIncumbentContext());
+ DCHECK(window);
+ return window;
+}
+
LocalDOMWindow* CurrentDOMWindow(v8::Isolate* isolate) {
return ToLocalDOMWindow(isolate->GetCurrentContext());
}
@@ -660,11 +666,11 @@ ExecutionContext* ToExecutionContext(v8::Local<v8::Context> context) {
return nullptr;
const WrapperTypeInfo* wrapper_type_info = ToWrapperTypeInfo(global_proxy);
- if (wrapper_type_info->Equals(&V8Window::wrapper_type_info))
+ if (wrapper_type_info->Equals(V8Window::GetWrapperTypeInfo()))
return V8Window::ToImpl(global_proxy)->GetExecutionContext();
- if (wrapper_type_info->IsSubclass(&V8WorkerGlobalScope::wrapper_type_info))
+ if (wrapper_type_info->IsSubclass(V8WorkerGlobalScope::GetWrapperTypeInfo()))
return V8WorkerGlobalScope::ToImpl(global_proxy)->GetExecutionContext();
- if (wrapper_type_info->IsSubclass(&V8WorkletGlobalScope::wrapper_type_info))
+ if (wrapper_type_info->IsSubclass(V8WorkletGlobalScope::GetWrapperTypeInfo()))
return V8WorkletGlobalScope::ToImpl(global_proxy)->GetExecutionContext();
NOTREACHED();
@@ -697,7 +703,7 @@ void ToFlexibleArrayBufferView(v8::Isolate* isolate,
}
size_t length = buffer->ByteLength();
buffer->CopyContents(storage, length);
- result.SetSmall(storage, length);
+ result.SetSmall(storage, SafeCast<uint32_t>(length));
}
static ScriptState* ToScriptStateImpl(LocalFrame* frame,
@@ -872,22 +878,6 @@ bool HasCallableIteratorSymbol(v8::Isolate* isolate,
return iterator_getter->IsFunction();
}
-v8::Isolate* ToIsolate(const ExecutionContext* context) {
- if (!context)
- return nullptr;
-
-#if DCHECK_IS_ON()
- v8::Isolate* isolate;
- if (context && context->IsDocument())
- isolate = V8PerIsolateData::MainThreadIsolate();
- else
- isolate = v8::Isolate::GetCurrent();
- DCHECK(context->GetIsolate() == isolate);
-#endif
-
- return context->GetIsolate();
-}
-
v8::Isolate* ToIsolate(const LocalFrame* frame) {
DCHECK(frame);
return frame->GetWindowProxyManager()->GetIsolate();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
index 8fcde3226b4..6b817eeab64 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
@@ -436,12 +436,12 @@ CORE_EXPORT bool HasCallableIteratorSymbol(v8::Isolate*,
v8::Local<v8::Value>,
ExceptionState&);
-CORE_EXPORT v8::Isolate* ToIsolate(const ExecutionContext*);
CORE_EXPORT v8::Isolate* ToIsolate(const LocalFrame*);
CORE_EXPORT DOMWindow* ToDOMWindow(v8::Isolate*, v8::Local<v8::Value>);
CORE_EXPORT LocalDOMWindow* ToLocalDOMWindow(v8::Local<v8::Context>);
LocalDOMWindow* EnteredDOMWindow(v8::Isolate*);
+LocalDOMWindow* IncumbentDOMWindow(v8::Isolate*);
CORE_EXPORT LocalDOMWindow* CurrentDOMWindow(v8::Isolate*);
CORE_EXPORT ExecutionContext* ToExecutionContext(v8::Local<v8::Context>);
CORE_EXPORT void RegisterToExecutionContextForModules(ExecutionContext* (
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
index 9faae3cef3f..84209a86ddf 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
@@ -77,11 +77,10 @@ v8::ScriptCompiler::CachedData* V8CodeCache::CreateCachedData(
scoped_refptr<CachedMetadata> cached_metadata =
cache_handler->GetCachedMetadata(code_cache_tag);
DCHECK(cached_metadata);
- const char* data = cached_metadata->Data();
+ const uint8_t* data = cached_metadata->Data();
int length = cached_metadata->size();
return new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(data), length,
- v8::ScriptCompiler::CachedData::BufferNotOwned);
+ data, length, v8::ScriptCompiler::CachedData::BufferNotOwned);
}
std::tuple<v8::ScriptCompiler::CompileOptions,
@@ -202,7 +201,7 @@ void V8CodeCache::ProduceCache(
std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data(
v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript()));
if (cached_data) {
- const char* data = reinterpret_cast<const char*>(cached_data->data);
+ const uint8_t* data = cached_data->data;
int length = cached_data->length;
if (length > 1024) {
// Omit histogram samples for small cache data to avoid outliers.
@@ -253,9 +252,9 @@ void V8CodeCache::SetCacheTimeStamp(
SingleCachedMetadataHandler* cache_handler) {
double now = WTF::CurrentTime();
cache_handler->ClearCachedMetadata(CachedMetadataHandler::kCacheLocally);
- cache_handler->SetCachedMetadata(TagForTimeStamp(cache_handler),
- reinterpret_cast<char*>(&now), sizeof(now),
- CachedMetadataHandler::kSendToPlatform);
+ cache_handler->SetCachedMetadata(
+ TagForTimeStamp(cache_handler), reinterpret_cast<uint8_t*>(&now),
+ sizeof(now), CachedMetadataHandler::kSendToPlatform);
}
// static
@@ -302,10 +301,9 @@ scoped_refptr<CachedMetadata> V8CodeCache::GenerateFullCodeCache(
.ToLocal(&unbound_script)) {
cached_data.reset(v8::ScriptCompiler::CreateCodeCache(unbound_script));
if (cached_data && cached_data->length) {
- cached_metadata = CachedMetadata::Create(
- CacheTag(kCacheTagCode, encoding.GetName()),
- reinterpret_cast<const char*>(cached_data->data),
- cached_data->length);
+ cached_metadata =
+ CachedMetadata::Create(CacheTag(kCacheTagCode, encoding.GetName()),
+ cached_data->data, cached_data->length);
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc
index 6db6b620402..94ac2acb35e 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc
@@ -47,7 +47,7 @@ v8::Local<v8::Object> CreatePlainWrapper(v8::Isolate* isolate,
const DOMWrapperWorld& world,
v8::Local<v8::Context> context,
const WrapperTypeInfo* type) {
- CHECK(V8HTMLDocument::wrapper_type_info.Equals(type));
+ CHECK(V8HTMLDocument::GetWrapperTypeInfo()->Equals(type));
v8::Context::Scope scope(context);
v8::Local<v8::Function> interface_object =
@@ -71,15 +71,15 @@ struct SnapshotInterface {
InstallRuntimeEnabledFeaturesOnTemplateFunction install_function;
};
SnapshotInterface g_snapshot_interfaces[] = {
- {&V8Window::wrapper_type_info,
+ {V8Window::GetWrapperTypeInfo(),
V8Window::InstallRuntimeEnabledFeaturesOnTemplate},
- {&V8HTMLDocument::wrapper_type_info,
+ {V8HTMLDocument::GetWrapperTypeInfo(),
V8HTMLDocument::InstallRuntimeEnabledFeaturesOnTemplate},
- {&V8EventTarget::wrapper_type_info,
+ {V8EventTarget::GetWrapperTypeInfo(),
V8EventTarget::InstallRuntimeEnabledFeaturesOnTemplate},
- {&V8Node::wrapper_type_info,
+ {V8Node::GetWrapperTypeInfo(),
V8Node::InstallRuntimeEnabledFeaturesOnTemplate},
- {&V8Document::wrapper_type_info,
+ {V8Document::GetWrapperTypeInfo(),
V8Document::InstallRuntimeEnabledFeaturesOnTemplate},
};
constexpr size_t kSnapshotInterfaceSize = base::size(g_snapshot_interfaces);
@@ -98,13 +98,13 @@ const WrapperTypeInfo* FieldTypeToWrapperTypeInfo(InternalFieldType type) {
NOTREACHED();
break;
case InternalFieldType::kNodeType:
- return &V8Node::wrapper_type_info;
+ return V8Node::GetWrapperTypeInfo();
case InternalFieldType::kDocumentType:
- return &V8Document::wrapper_type_info;
+ return V8Document::GetWrapperTypeInfo();
case InternalFieldType::kHTMLDocumentType:
- return &V8HTMLDocument::wrapper_type_info;
+ return V8HTMLDocument::GetWrapperTypeInfo();
case InternalFieldType::kHTMLDocumentObject:
- return &V8HTMLDocument::wrapper_type_info;
+ return V8HTMLDocument::GetWrapperTypeInfo();
}
NOTREACHED();
return nullptr;
@@ -175,7 +175,7 @@ bool V8ContextSnapshot::InstallConditionalFeatures(
{
v8::Local<v8::Object> window_wrapper =
global_proxy->GetPrototype().As<v8::Object>();
- const WrapperTypeInfo* type = &V8Window::wrapper_type_info;
+ const WrapperTypeInfo* type = V8Window::GetWrapperTypeInfo();
v8::Local<v8::Function> interface = data->ConstructorForType(type);
v8::Local<v8::Object> prototype = interface->Get(context, prototype_str)
.ToLocalChecked()
@@ -188,7 +188,7 @@ bool V8ContextSnapshot::InstallConditionalFeatures(
InstallOriginTrialFeatures(type, script_state, prototype, interface);
}
{
- const WrapperTypeInfo* type = &V8EventTarget::wrapper_type_info;
+ const WrapperTypeInfo* type = V8EventTarget::GetWrapperTypeInfo();
v8::Local<v8::Function> interface = data->ConstructorForType(type);
v8::Local<v8::Object> prototype = interface->Get(context, prototype_str)
.ToLocalChecked()
@@ -212,7 +212,7 @@ bool V8ContextSnapshot::InstallConditionalFeatures(
CHECK(document->ContainsWrapper());
v8::Local<v8::Object> document_wrapper =
ToV8(document, global_proxy, isolate).As<v8::Object>();
- const WrapperTypeInfo* type = &V8HTMLDocument::wrapper_type_info;
+ const WrapperTypeInfo* type = V8HTMLDocument::GetWrapperTypeInfo();
v8::Local<v8::Function> interface = data->ConstructorForType(type);
v8::Local<v8::Object> prototype = interface->Get(context, prototype_str)
.ToLocalChecked()
@@ -225,7 +225,7 @@ bool V8ContextSnapshot::InstallConditionalFeatures(
InstallOriginTrialFeatures(type, script_state, prototype, interface);
}
{
- const WrapperTypeInfo* type = &V8Document::wrapper_type_info;
+ const WrapperTypeInfo* type = V8Document::GetWrapperTypeInfo();
v8::Local<v8::Function> interface = data->ConstructorForType(type);
v8::Local<v8::Object> prototype = interface->Get(context, prototype_str)
.ToLocalChecked()
@@ -238,7 +238,7 @@ bool V8ContextSnapshot::InstallConditionalFeatures(
InstallOriginTrialFeatures(type, script_state, prototype, interface);
}
{
- const WrapperTypeInfo* type = &V8Node::wrapper_type_info;
+ const WrapperTypeInfo* type = V8Node::GetWrapperTypeInfo();
v8::Local<v8::Function> interface = data->ConstructorForType(type);
v8::Local<v8::Object> prototype = interface->Get(context, prototype_str)
.ToLocalChecked()
@@ -264,12 +264,13 @@ void V8ContextSnapshot::EnsureInterfaceTemplates(v8::Isolate* isolate) {
// Update the install functions for V8Window and V8Document to work for their
// partial interfaces.
SnapshotInterface& snapshot_window = g_snapshot_interfaces[0];
- DCHECK(V8Window::wrapper_type_info.Equals(snapshot_window.wrapper_type_info));
+ DCHECK(V8Window::GetWrapperTypeInfo()->Equals(
+ snapshot_window.wrapper_type_info));
snapshot_window.install_function =
V8Window::install_runtime_enabled_features_on_template_function_;
SnapshotInterface& snapshot_document = g_snapshot_interfaces[4];
- DCHECK(V8Document::wrapper_type_info.Equals(
+ DCHECK(V8Document::GetWrapperTypeInfo()->Equals(
snapshot_document.wrapper_type_info));
snapshot_document.install_function =
V8Document::install_runtime_enabled_features_on_template_function_;
@@ -324,17 +325,17 @@ v8::StartupData V8ContextSnapshot::SerializeInternalField(
InternalFieldType field_type = InternalFieldType::kNone;
const WrapperTypeInfo* wrapper_type = ToWrapperTypeInfo(object);
if (kV8DOMWrapperObjectIndex == index) {
- if (blink::V8HTMLDocument::wrapper_type_info.Equals(wrapper_type)) {
+ if (blink::V8HTMLDocument::GetWrapperTypeInfo()->Equals(wrapper_type)) {
field_type = InternalFieldType::kHTMLDocumentObject;
}
DCHECK_LE(kV8DefaultWrapperInternalFieldCount,
object->InternalFieldCount());
} else if (kV8DOMWrapperTypeIndex == index) {
- if (blink::V8HTMLDocument::wrapper_type_info.Equals(wrapper_type)) {
+ if (blink::V8HTMLDocument::GetWrapperTypeInfo()->Equals(wrapper_type)) {
field_type = InternalFieldType::kHTMLDocumentType;
- } else if (blink::V8Document::wrapper_type_info.Equals(wrapper_type)) {
+ } else if (blink::V8Document::GetWrapperTypeInfo()->Equals(wrapper_type)) {
field_type = InternalFieldType::kDocumentType;
- } else if (blink::V8Node::wrapper_type_info.Equals(wrapper_type)) {
+ } else if (blink::V8Node::GetWrapperTypeInfo()->Equals(wrapper_type)) {
field_type = InternalFieldType::kNodeType;
}
DCHECK_LE(kV8PrototypeInternalFieldcount, object->InternalFieldCount());
@@ -467,7 +468,7 @@ void V8ContextSnapshot::TakeSnapshotForWorld(v8::SnapshotCreator* creator,
wrapper_type_info->DomTemplate(isolate, world);
CHECK(!interface_template.IsEmpty());
interface_templates[i] = interface_template;
- if (V8Window::wrapper_type_info.Equals(wrapper_type_info)) {
+ if (V8Window::GetWrapperTypeInfo()->Equals(wrapper_type_info)) {
window_template = interface_template;
}
}
@@ -490,10 +491,10 @@ void V8ContextSnapshot::TakeSnapshotForWorld(v8::SnapshotCreator* creator,
if (world.IsMainWorld()) {
v8::Context::Scope scope(context);
v8::Local<v8::Object> document_wrapper = CreatePlainWrapper(
- isolate, world, context, &V8HTMLDocument::wrapper_type_info);
+ isolate, world, context, V8HTMLDocument::GetWrapperTypeInfo());
int indices[] = {kV8DOMWrapperObjectIndex, kV8DOMWrapperTypeIndex};
void* values[] = {nullptr, const_cast<WrapperTypeInfo*>(
- &V8HTMLDocument::wrapper_type_info)};
+ V8HTMLDocument::GetWrapperTypeInfo())};
document_wrapper->SetAlignedPointerInInternalFields(base::size(indices),
indices, values);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc
index 65b479d8c92..739ba61e9f2 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc
@@ -802,7 +802,7 @@ void V8DOMConfiguration::InitializeDOMInterfaceTemplate(
// Note that V8 minor GC does not collect an object which has an own property.
// So, if we set the class string to the platform object as an own property,
// it prevents V8 minor GC to collect the object (V8 minor GC only collects
- // an empty object). If set, a layout test fast/dom/minor-dom-gc.html fails.
+ // an empty object). If set, a web test fast/dom/minor-dom-gc.html fails.
SetClassString(isolate, prototype_template, interface_name);
if (!parent_interface_template.IsEmpty()) {
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
deleted file mode 100644
index a21fa6020eb..00000000000
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h"
-#include "third_party/blink/renderer/bindings/core/v8/js_event_handler.h"
-#include "third_party/blink/renderer/bindings/core/v8/js_event_listener.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_window.h"
-#include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
-
-namespace blink {
-namespace {
-
-template <typename ListenerType, typename ListenerFactory>
-ListenerType* GetEventListenerInternal(
- ScriptState* script_state,
- v8::Local<v8::Object> object,
- const V8PrivateProperty::Symbol& listener_property,
- ListenerLookupType lookup,
- const ListenerFactory& listener_factory) {
- DCHECK(script_state->GetIsolate()->InContext());
- ListenerType* listener =
- CustomWrappableAdapter::Lookup<ListenerType>(object, listener_property);
- if (listener || lookup == kListenerFindOnly)
- return listener;
-
- return listener_factory();
-}
-
-} // namespace
-
-// static
-EventListener* V8EventListenerHelper::GetEventListener(
- ScriptState* script_state,
- v8::Local<v8::Value> value,
- ListenerLookupType lookup) {
- RUNTIME_CALL_TIMER_SCOPE(script_state->GetIsolate(),
- RuntimeCallStats::CounterId::kGetEventListener);
-
- if (!value->IsObject())
- return nullptr;
- v8::Local<v8::Object> object = value.As<v8::Object>();
- v8::Isolate* isolate = script_state->GetIsolate();
- V8PrivateProperty::Symbol listener_property =
- V8PrivateProperty::GetCustomWrappableEventListener(isolate);
-
- return GetEventListenerInternal<EventListener>(
- script_state, object, listener_property, lookup,
- [object, script_state, listener_property]() {
- return static_cast<EventListener*>(
- JSEventListener::Create(script_state, object, listener_property));
- });
-}
-
-// static
-EventListener* V8EventListenerHelper::GetEventHandler(
- ScriptState* script_state,
- v8::Local<v8::Value> value,
- JSEventHandler::HandlerType handler_type,
- ListenerLookupType lookup) {
- RUNTIME_CALL_TIMER_SCOPE(script_state->GetIsolate(),
- RuntimeCallStats::CounterId::kGetEventListener);
-
- if (!value->IsObject())
- return nullptr;
- v8::Local<v8::Object> object = value.As<v8::Object>();
- v8::Isolate* isolate = script_state->GetIsolate();
- V8PrivateProperty::Symbol listener_property =
- V8PrivateProperty::GetCustomWrappableEventHandler(isolate);
-
- return GetEventListenerInternal<EventListener>(
- script_state, object, listener_property, lookup,
- [object, script_state, listener_property, handler_type]() {
- return static_cast<EventListener*>(JSEventHandler::Create(
- script_state, object, listener_property, handler_type));
- });
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h b/chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h
deleted file mode 100644
index 4ac4d83a574..00000000000
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_EVENT_LISTENER_HELPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_EVENT_LISTENER_HELPER_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/js_event_handler.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-enum ListenerLookupType {
- kListenerFindOnly,
- kListenerFindOrCreate,
-};
-
-// This is a container for V8EventListenerOrEventHandler objects that uses
-// hidden properties of v8::Object to speed up lookups.
-class V8EventListenerHelper {
- STATIC_ONLY(V8EventListenerHelper);
-
- public:
- CORE_EXPORT static EventListener* GetEventListener(ScriptState*,
- v8::Local<v8::Value>,
- ListenerLookupType);
- CORE_EXPORT static EventListener* GetEventHandler(ScriptState*,
- v8::Local<v8::Value>,
- JSEventHandler::HandlerType,
- ListenerLookupType);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_EVENT_LISTENER_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc
index 9ee7d0958a4..0f291416e26 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.cc
@@ -40,8 +40,9 @@ ScriptValue EvalWithPrintingError(V8TestingScope* scope, const char* script) {
v8::TryCatch block(scope->GetIsolate());
ScriptValue r = Eval(scope, script);
if (block.HasCaught()) {
- ADD_FAILURE() << ToCoreString(
- block.Exception()->ToString(scope->GetIsolate()))
+ ADD_FAILURE() << ToCoreString(block.Exception()
+ ->ToString(scope->GetContext())
+ .ToLocalChecked())
.Utf8()
.data();
block.ReThrow();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc
index aa166403c83..1a0d6564935 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc
@@ -74,7 +74,7 @@ void V8HTMLConstructor::HtmlConstructor(
// Autonomous custom element
// 4.1. If the active function object is not HTMLElement, then throw a
// TypeError
- if (!V8HTMLElement::wrapper_type_info.Equals(&wrapper_type_info)) {
+ if (!V8HTMLElement::GetWrapperTypeInfo()->Equals(&wrapper_type_info)) {
V8ThrowException::ThrowTypeError(isolate,
"Illegal constructor: autonomous custom "
"elements must extend HTMLElement");
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 0050eb07bf1..bec05f5222c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -131,13 +131,6 @@ size_t NearHeapLimitCallbackOnMainThread(void* data,
size_t current_heap_limit,
size_t initial_heap_limit) {
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(data);
- V8PerIsolateData* per_isolate_data = V8PerIsolateData::From(isolate);
- if (per_isolate_data->IsNearV8HeapLimitHandled()) {
- // Ignore all calls after the first one.
- return current_heap_limit;
- }
- per_isolate_data->HandledNearV8HeapLimit();
-
// Find the main document for UKM recording.
Document* document = nullptr;
int pages = 0;
@@ -174,12 +167,6 @@ size_t NearHeapLimitCallbackOnWorkerThread(void* data,
size_t current_heap_limit,
size_t initial_heap_limit) {
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(data);
- V8PerIsolateData* per_isolate_data = V8PerIsolateData::From(isolate);
- if (per_isolate_data->IsNearV8HeapLimitHandled()) {
- // Ignore all calls after the first one.
- return current_heap_limit;
- }
- per_isolate_data->HandledNearV8HeapLimit();
// Do not record UKM on worker thread.
Record(NearV8HeapLimitHandling::kIgnoredDueToWorker, isolate,
current_heap_limit, nullptr, 0);
@@ -198,7 +185,7 @@ static String ExtractMessageForConsole(v8::Isolate* isolate,
if (V8DOMWrapper::IsWrapper(isolate, data)) {
v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(data);
const WrapperTypeInfo* type = ToWrapperTypeInfo(obj);
- if (V8DOMException::wrapper_type_info.IsSubclass(type)) {
+ if (V8DOMException::GetWrapperTypeInfo()->IsSubclass(type)) {
DOMException* exception = V8DOMException::ToImpl(obj);
if (exception && !exception->MessageForConsole().IsEmpty())
return exception->ToStringForConsole();
@@ -552,9 +539,9 @@ static bool WasmInstanceOverride(
if (!source->IsWebAssemblyCompiledModule())
return false;
- v8::Local<v8::WasmCompiledModule> module =
- v8::Local<v8::WasmCompiledModule>::Cast(source);
- if (module->GetWasmWireBytesRef().size > kWasmWireBytesLimit) {
+ v8::CompiledWasmModule compiled_module =
+ v8::Local<v8::WasmModuleObject>::Cast(source)->GetCompiledModule();
+ if (compiled_module.GetWireBytesRef().size() > kWasmWireBytesLimit) {
ThrowRangeException(
args.GetIsolate(),
"WebAssembly.Instance is disallowed on the main thread, "
@@ -691,12 +678,8 @@ void V8Initializer::InitializeMainThread(const intptr_t* reference_table) {
WTF::ArrayBufferContents::Initialize(AdjustAmountOfExternalAllocatedMemory);
DEFINE_STATIC_LOCAL(ArrayBufferAllocator, array_buffer_allocator, ());
- auto v8_extras_mode = RuntimeEnabledFeatures::ExperimentalV8ExtrasEnabled()
- ? gin::IsolateHolder::kStableAndExperimentalV8Extras
- : gin::IsolateHolder::kStableV8Extras;
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
- v8_extras_mode, &array_buffer_allocator,
- reference_table);
+ &array_buffer_allocator, reference_table);
ThreadScheduler* scheduler = ThreadScheduler::Current();
@@ -705,12 +688,6 @@ void V8Initializer::InitializeMainThread(const intptr_t* reference_table) {
Platform::Current()->IsTakingV8ContextSnapshot()
? V8PerIsolateData::V8ContextSnapshotMode::kTakeSnapshot
: V8PerIsolateData::V8ContextSnapshotMode::kUseSnapshot;
- if (v8_context_snapshot_mode ==
- V8PerIsolateData::V8ContextSnapshotMode::kUseSnapshot &&
- !RuntimeEnabledFeatures::V8ContextSnapshotEnabled()) {
- v8_context_snapshot_mode =
- V8PerIsolateData::V8ContextSnapshotMode::kDontUseSnapshot;
- }
#else
V8PerIsolateData::V8ContextSnapshotMode v8_context_snapshot_mode =
V8PerIsolateData::V8ContextSnapshotMode::kDontUseSnapshot;
@@ -741,6 +718,7 @@ void V8Initializer::InitializeMainThread(const intptr_t* reference_table) {
DCHECK(g_near_heap_limit_on_main_thread_callback_);
isolate->AddNearHeapLimitCallback(NearHeapLimitCallbackOnMainThread,
isolate);
+ isolate->AutomaticallyRestoreInitialHeapLimit();
}
isolate->SetFatalErrorHandler(ReportFatalErrorInMainThread);
isolate->AddMessageListenerWithErrorLevel(
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.h b/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.h
index 8bd08db89d5..57be7473f66 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.h
@@ -44,7 +44,8 @@ enum class NearV8HeapLimitHandling {
kIgnoredDueToSmallUptime = 1,
kIgnoredDueToChangedHeapLimit = 2,
kIgnoredDueToWorker = 3,
- kMaxValue = kIgnoredDueToWorker
+ kIgnoredDueToCooldownTime = 4,
+ kMaxValue = kIgnoredDueToCooldownTime
};
// A callback function called when V8 reaches the heap limit.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
index 45f880934e0..796219bf88b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -155,11 +155,6 @@ v8::MaybeLocal<v8::Script> CompileScriptInternal(
}
return script;
}
- // TODO(v8:8252): Remove the default case once deprecated options are
- // removed from v8::ScriptCompiler::CompileOptions.
- default:
- NOTREACHED();
- break;
}
// All switch branches should return and we should never get here.
@@ -364,9 +359,19 @@ v8::MaybeLocal<v8::Value> V8ScriptRunner::CallAsConstructor(
v8::MicrotasksScope microtasks_scope(isolate,
v8::MicrotasksScope::kRunMicrotasks);
probe::CallFunction probe(context, function, depth);
+
+ if (!depth) {
+ TRACE_EVENT_BEGIN1("devtools.timeline", "FunctionCall", "data",
+ inspector_function_call_event::Data(context, function));
+ }
+
v8::MaybeLocal<v8::Value> result =
constructor->CallAsConstructor(isolate->GetCurrentContext(), argc, argv);
CHECK(!isolate->IsDead());
+
+ if (!depth)
+ TRACE_EVENT_END0("devtools.timeline", "FunctionCall");
+
return result;
}
@@ -402,11 +407,19 @@ v8::MaybeLocal<v8::Value> V8ScriptRunner::CallFunction(
v8::Isolate::SafeForTerminationScope safe_for_termination(isolate);
v8::MicrotasksScope microtasks_scope(isolate,
v8::MicrotasksScope::kRunMicrotasks);
+ if (!depth) {
+ TRACE_EVENT_BEGIN1("devtools.timeline", "FunctionCall", "data",
+ inspector_function_call_event::Data(context, function));
+ }
+
probe::CallFunction probe(context, function, depth);
v8::MaybeLocal<v8::Value> result =
function->Call(isolate->GetCurrentContext(), receiver, argc, args);
CHECK(!isolate->IsDead());
+ if (!depth)
+ TRACE_EVENT_END0("devtools.timeline", "FunctionCall");
+
return result;
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
index 0511190227b..c50c77d2fef 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
@@ -67,7 +67,10 @@ class FetchDataLoaderForWasmStreaming final : public FetchDataLoader,
break;
}
case BytesConsumer::Result::kDone: {
- streaming_->Finish();
+ {
+ ScriptState::Scope scope(script_state_);
+ streaming_->Finish();
+ }
client_->DidFetchDataLoadedCustomFormat();
return;
}
@@ -222,9 +225,10 @@ void StreamFromResponseCallback(
}
FetchDataLoaderForWasmStreaming* loader =
- new FetchDataLoaderForWasmStreaming(script_state, streaming);
- response->BodyBuffer()->StartLoading(loader, new WasmDataLoaderClient(),
- exception_state);
+ MakeGarbageCollected<FetchDataLoaderForWasmStreaming>(script_state,
+ streaming);
+ response->BodyBuffer()->StartLoading(
+ loader, MakeGarbageCollected<WasmDataLoaderClient>(), exception_state);
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
index b4b0f69411b..d0f514251e4 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
@@ -32,7 +32,6 @@
#include <utility>
-#include "base/debug/alias.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.h"
#include "third_party/blink/renderer/core/frame/dom_window.h"
@@ -74,6 +73,10 @@ void WindowProxy::ClearForSwap() {
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillNotBeReused);
}
+void WindowProxy::ClearForV8MemoryPurge() {
+ DisposeContext(Lifecycle::kForciblyPurgeV8Memory, kFrameWillNotBeReused);
+}
+
v8::Local<v8::Object> WindowProxy::GlobalProxyIfNotDetached() {
if (lifecycle_ == Lifecycle::kContextIsInitialized) {
DLOG_IF(FATAL, !is_global_object_attached_)
@@ -100,8 +103,6 @@ v8::Local<v8::Object> WindowProxy::ReleaseGlobalProxy() {
void WindowProxy::SetGlobalProxy(v8::Local<v8::Object> global_proxy) {
DCHECK_EQ(lifecycle_, Lifecycle::kContextIsUninitialized);
- base::debug::StackTrace initialization_stack = initialization_stack_;
- base::debug::Alias(&initialization_stack);
CHECK(global_proxy_.IsEmpty());
global_proxy_.Set(isolate_, global_proxy);
@@ -153,7 +154,6 @@ void WindowProxy::InitializeIfNeeded() {
if (lifecycle_ == Lifecycle::kContextIsUninitialized ||
lifecycle_ == Lifecycle::kGlobalObjectIsDetached) {
Initialize();
- initialization_stack_ = base::debug::StackTrace();
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h
index c2f135f7fad..7d29727eac4 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h
@@ -31,7 +31,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WINDOW_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WINDOW_PROXY_H_
-#include "base/debug/stack_trace.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
@@ -153,6 +152,7 @@ class WindowProxy : public GarbageCollectedFinalized<WindowProxy> {
void ClearForClose();
void ClearForNavigation();
void ClearForSwap();
+ void ClearForV8MemoryPurge();
CORE_EXPORT v8::Local<v8::Object> GlobalProxyIfNotDetached();
v8::Local<v8::Object> ReleaseGlobalProxy();
@@ -176,18 +176,28 @@ class WindowProxy : public GarbageCollectedFinalized<WindowProxy> {
// - Possible next states: kContextIsInitialized
// It's possible to detach the context's frame from the DOM or navigate to a
// new page without initializing the WindowProxy, however, there is no
- // transition to |kFrameIsDetached| or |kGlobalObjectIsDetached|
- // because |DisposeContext| does not change the state if the state is
- // |kContextIsUninitialized|. In either case of a) the browsing context
- // container is detached from the DOM or b) the page is navigated away, there
- // must be no way for author script to access the context of
- // |kContextIsUninitialized| because |kContextIsUninitialized| means that
- // author script has never accessed the context, hence there must exist no
- // reference to the context.
+ // transition to |kFrameIsDetached| or |kGlobalObjectIsDetached| or
+ // |kForciblyPurgeV8Memory| because |DisposeContext| does not change the state
+ // if the state is |kContextIsUninitialized|. In either case of a) the
+ // browsing context container is detached from the DOM or b) the page is
+ // navigated away, there must be no way for author script to access the
+ // context of |kContextIsUninitialized| because |kContextIsUninitialized|
+ // means that author script has never accessed the context, hence there must
+ // exist no reference to the context.
//
// * kContextIsInitialized
// The context is initialized and its frame is still attached to the DOM.
- // - Possible next states: kFrameIsDetached, kGlobalObjectIsDetached
+ // - Possible next states: kFrameIsDetached, kGlobalObjectIsDetached,
+ // kForciblyPurgeV8Memory
+ //
+ // * kForciblyPurgeV8Memory
+ // The context is initialized and its frame is still attached to the DOM, but
+ // the global object is detached from the global proxy in order to drop all
+ // references to v8, hopefully causing all JS objects to be collected for
+ // memory reduction.
+ // - Possible next states: kGlobalObjectIsDetached
+ // Navigation can occur after V8 memory purge, and the state will transition
+ // to kGlobalObjectIsDetached in that case.
//
// * kGlobalObjectIsDetached
// The context is initialized and its frame is still attached to the DOM, but
@@ -221,6 +231,9 @@ class WindowProxy : public GarbageCollectedFinalized<WindowProxy> {
// v8::Context is initialized.
kContextIsInitialized,
// The global object (inner global) is detached from the global proxy (outer
+ // global). Could transition to kGlobalObjectIsDetached.
+ kForciblyPurgeV8Memory,
+ // The global object (inner global) is detached from the global proxy (outer
// global).
kGlobalObjectIsDetached,
// The context's frame is detached from the DOM.
@@ -262,10 +275,6 @@ class WindowProxy : public GarbageCollectedFinalized<WindowProxy> {
// to be destroyed.
ScopedPersistent<v8::Object> global_proxy_;
Lifecycle lifecycle_;
-
- // TODO(dcheng): Remove this temporary code for debugging
- // https://crbug.com/728693.
- base::debug::StackTrace initialization_stack_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
index 35096d43d7c..122f33e3bb5 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
@@ -33,6 +33,12 @@ void WindowProxyManager::ClearForSwap() {
entry.value->ClearForSwap();
}
+void WindowProxyManager::ClearForV8MemoryPurge() {
+ window_proxy_->ClearForV8MemoryPurge();
+ for (auto& entry : isolated_worlds_)
+ entry.value->ClearForV8MemoryPurge();
+}
+
void WindowProxyManager::ReleaseGlobalProxies(
GlobalProxyVector& global_proxies) {
DCHECK(global_proxies.IsEmpty());
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
index 8cbe4da1d0b..c988154a1c5 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
@@ -29,6 +29,7 @@ class WindowProxyManager : public GarbageCollected<WindowProxyManager> {
void ClearForClose();
void CORE_EXPORT ClearForNavigation();
void ClearForSwap();
+ void ClearForV8MemoryPurge();
// Global proxies are passed in a vector to maintain their order: global proxy
// object for the main world is always first. This is needed to prevent bugs
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc b/chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc
new file mode 100644
index 00000000000..7ee67ac88a7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+
+namespace blink {
+
+// static
+v8::Local<v8::Value> WorldSafeV8ReferenceInternal::ToWorldSafeValue(
+ ScriptState* target_script_state,
+ const TraceWrapperV8Reference<v8::Value>& v8_reference,
+ const DOMWrapperWorld& v8_reference_world) {
+ DCHECK(!v8_reference.IsEmpty());
+
+ v8::Isolate* isolate = target_script_state->GetIsolate();
+
+ if (&v8_reference_world == &target_script_state->World())
+ return v8_reference.NewLocal(isolate);
+
+ // If |v8_reference| is a v8::Object, clones |v8_reference| in the context of
+ // |target_script_state| and returns it. Otherwise returns |v8_reference|
+ // itself that is already safe to access in |target_script_state|.
+
+ v8::Local<v8::Value> value = v8_reference.NewLocal(isolate);
+ if (!value->IsObject())
+ return value;
+
+ v8::Context::Scope target_context_scope(target_script_state->GetContext());
+ return SerializedScriptValue::SerializeAndSwallowExceptions(isolate, value)
+ ->Deserialize(isolate);
+}
+
+// static
+void WorldSafeV8ReferenceInternal::MaybeCheckCreationContextWorld(
+ const DOMWrapperWorld& world,
+ v8::Local<v8::Value> value) {
+ if (!value->IsObject())
+ return;
+
+ ScriptState* script_state =
+ ScriptState::From(value.As<v8::Object>()->CreationContext());
+ CHECK_EQ(&world, &script_state->World());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h b/chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h
new file mode 100644
index 00000000000..85b3e322567
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h
@@ -0,0 +1,122 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ScriptState;
+
+// This is a namespace to provide utility functions to WorldSafeV8Reference.
+class CORE_EXPORT WorldSafeV8ReferenceInternal final {
+ STATIC_ONLY(WorldSafeV8ReferenceInternal);
+
+ private:
+ // Returns a V8 reference that is safe to access in |target_script_state|.
+ // The return value may be a cloned object.
+ //
+ // TODO(crbug.com/803478): ScriptValue::V8ValueFor should be replaced with
+ // this function, or these two functions should be merged at least.
+ static v8::Local<v8::Value> ToWorldSafeValue(
+ ScriptState* target_script_state,
+ const TraceWrapperV8Reference<v8::Value>& v8_reference,
+ const DOMWrapperWorld& v8_reference_world);
+
+ // Checks the world of |value|'s creation context if |value| is a v8::Object.
+ // The given |world| and |value|'s world must match. Otherwise, crashes.
+ //
+ // TODO(yukishiino): Find the best place to put this function. We might want
+ // to share this function among other clients, e.g. access to wrapper objects
+ // across worlds.
+ static void MaybeCheckCreationContextWorld(const DOMWrapperWorld& world,
+ v8::Local<v8::Value> value);
+
+ template <typename V8Type>
+ friend class WorldSafeV8Reference;
+};
+
+// This class provides safe access to v8::Value across worlds. This class
+// provides accessors that check whether the value is accessed in the same world
+// or not, also provides an accessor that clones the value when accessed across
+// worlds.
+template <typename V8Type>
+class WorldSafeV8Reference final {
+ DISALLOW_NEW();
+
+ public:
+ WorldSafeV8Reference() = default;
+ explicit WorldSafeV8Reference(v8::Isolate* isolate, v8::Local<V8Type> value)
+ : v8_reference_(isolate, value),
+ world_(&DOMWrapperWorld::Current(isolate)) {
+ WorldSafeV8ReferenceInternal::MaybeCheckCreationContextWorld(*world_.get(),
+ value);
+ }
+ ~WorldSafeV8Reference() = default;
+
+ // Returns the V8 reference. Crashes if |target_script_state|'s world is
+ // different from this V8 reference's world.
+ v8::Local<V8Type> Get(ScriptState* target_script_state) const {
+ DCHECK(!v8_reference_.IsEmpty());
+ CHECK_EQ(world_.get(), &target_script_state->World());
+ return v8_reference_.NewLocal(target_script_state->GetIsolate());
+ }
+
+ // Returns a V8 reference that is safe to access in |target_script_state|.
+ // The return value may be a cloned object.
+ v8::Local<V8Type> GetAcrossWorld(ScriptState* target_script_state) const {
+ return WorldSafeV8ReferenceInternal::ToWorldSafeValue(
+ target_script_state, v8_reference_, *world_.get())
+ .template As<V8Type>();
+ }
+
+ // Sets a new V8 reference. Crashes if |new_value|'s world is different from
+ // this V8 reference's world.
+ void Set(v8::Isolate* isolate, v8::Local<V8Type> new_value) {
+ DCHECK(!new_value.IsEmpty());
+ const DOMWrapperWorld& new_world = DOMWrapperWorld::Current(isolate);
+ WorldSafeV8ReferenceInternal::MaybeCheckCreationContextWorld(new_world,
+ new_value);
+ CHECK(v8_reference_.IsEmpty() || world_.get() == &new_world);
+ v8_reference_.Set(isolate, new_value);
+ world_ = WrapRefCounted(&new_world);
+ }
+
+ // Forcibly sets a new V8 reference even when the worlds are different. The
+ // world of this V8 reference will be |new_value|'s world.
+ void SetAcrossWorld(v8::Isolate* isolate, v8::Local<V8Type> new_value) {
+ DCHECK(!new_value.IsEmpty());
+ const DOMWrapperWorld& new_world = DOMWrapperWorld::Current(isolate);
+ v8_reference_.Set(isolate, new_value);
+ world_ = WrapRefCounted(&new_world);
+ }
+
+ void Reset() {
+ v8_reference_.Clear();
+ world_.reset();
+ }
+
+ bool IsEmpty() const { return v8_reference_.IsEmpty(); }
+
+ void Trace(blink::Visitor* visitor) { visitor->Trace(v8_reference_); }
+
+ private:
+ TraceWrapperV8Reference<V8Type> v8_reference_;
+ // The world of the current context at the time when |v8_reference_| was set.
+ // It's guaranteed that, if |v8_reference_| is a v8::Object, the world of the
+ // creation context of |v8_reference_| is the same as |world_|.
+ scoped_refptr<const DOMWrapperWorld> world_;
+
+ DISALLOW_COPY_AND_ASSIGN(WorldSafeV8Reference);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn b/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn
index 2ca7b7e007c..8a0f8908ef8 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn
@@ -103,7 +103,6 @@ group("generate_mojo_bindings") {
"//services/device/public/mojom:generic_sensor_headers",
"//services/device/public/mojom:mojom_blink_headers",
"//services/shape_detection/public/mojom:mojom_blink_headers",
- "//third_party/blink/public:media_devices_mojo_bindings_blink_headers",
# IndexedDB Mojom Blink headers are provided by the mojom_modules
# target.
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/custom/v8_extendable_message_event_custom.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/custom/v8_extendable_message_event_custom.cc
index 70ffc789015..ca6940f0ea2 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/custom/v8_extendable_message_event_custom.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/custom/v8_extendable_message_event_custom.cc
@@ -43,7 +43,7 @@ void V8ExtendableMessageEvent::ConstructorCustom(
ExtendableMessageEvent::Create(type, event_init_dict);
v8::Local<v8::Object> wrapper = info.Holder();
wrapper = impl->AssociateWithWrapper(
- isolate, &V8ExtendableMessageEvent::wrapper_type_info, wrapper);
+ isolate, V8ExtendableMessageEvent::GetWrapperTypeInfo(), wrapper);
// TODO(bashi): Workaround for http://crbug.com/529941. We need to store
// |data| as a private value to avoid cyclic references.
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni b/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni
index b2cf0233114..4df4bd24a6c 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -48,6 +48,8 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/idb_object_store_or_idb_index.h",
"$bindings_modules_v8_output_dir/idb_object_store_or_idb_index_or_idb_cursor.cc",
"$bindings_modules_v8_output_dir/idb_object_store_or_idb_index_or_idb_cursor.h",
+ "$bindings_modules_v8_output_dir/int32_array_or_long_sequence.cc",
+ "$bindings_modules_v8_output_dir/int32_array_or_long_sequence.h",
"$bindings_modules_v8_output_dir/long_or_constrain_long_range.cc",
"$bindings_modules_v8_output_dir/long_or_constrain_long_range.h",
"$bindings_modules_v8_output_dir/media_stream_track_or_string.cc",
@@ -76,8 +78,6 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/string_or_unsigned_long.h",
"$bindings_modules_v8_output_dir/unsigned_long_or_unsigned_long_sequence.cc",
"$bindings_modules_v8_output_dir/unsigned_long_or_unsigned_long_sequence.h",
- "$bindings_modules_v8_output_dir/usv_string_or_long.cc",
- "$bindings_modules_v8_output_dir/usv_string_or_long.h",
"$bindings_modules_v8_output_dir/webgl_rendering_context_or_webgl2_rendering_context.cc",
"$bindings_modules_v8_output_dir/webgl_rendering_context_or_webgl2_rendering_context.h",
]
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
index 0e3011dfbdc..58f2d6880d2 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
@@ -31,11 +31,11 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
return false;
const WrapperTypeInfo* wrapper_type_info = wrappable->GetWrapperTypeInfo();
- if (wrapper_type_info == &V8CryptoKey::wrapper_type_info) {
+ if (wrapper_type_info == V8CryptoKey::GetWrapperTypeInfo()) {
return WriteCryptoKey(wrappable->ToImpl<CryptoKey>()->Key(),
exception_state);
}
- if (wrapper_type_info == &V8DOMFileSystem::wrapper_type_info) {
+ if (wrapper_type_info == V8DOMFileSystem::GetWrapperTypeInfo()) {
DOMFileSystem* fs = wrappable->ToImpl<DOMFileSystem>();
if (!fs->Clonable()) {
exception_state.ThrowDOMException(
@@ -50,7 +50,7 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
WriteUTF8String(fs->RootURL().GetString());
return true;
}
- if (wrapper_type_info == &V8RTCCertificate::wrapper_type_info) {
+ if (wrapper_type_info == V8RTCCertificate::GetWrapperTypeInfo()) {
RTCCertificate* certificate = wrappable->ToImpl<RTCCertificate>();
rtc::RTCCertificatePEM pem = certificate->Certificate()->ToPEM();
WriteTag(kRTCCertificateTag);
@@ -58,7 +58,7 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
WriteUTF8String(pem.certificate().c_str());
return true;
}
- if (wrapper_type_info == &V8DetectedBarcode::wrapper_type_info) {
+ if (wrapper_type_info == V8DetectedBarcode::GetWrapperTypeInfo()) {
DetectedBarcode* detected_barcode = wrappable->ToImpl<DetectedBarcode>();
WriteTag(kDetectedBarcodeTag);
WriteUTF8String(detected_barcode->rawValue());
@@ -76,7 +76,7 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
}
return true;
}
- if (wrapper_type_info == &V8DetectedFace::wrapper_type_info) {
+ if (wrapper_type_info == V8DetectedFace::GetWrapperTypeInfo()) {
DetectedFace* detected_face = wrappable->ToImpl<DetectedFace>();
WriteTag(kDetectedFaceTag);
DOMRectReadOnly* bounding_box = detected_face->boundingBox();
@@ -97,7 +97,7 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
}
return true;
}
- if (wrapper_type_info == &V8DetectedText::wrapper_type_info) {
+ if (wrapper_type_info == V8DetectedText::GetWrapperTypeInfo()) {
DetectedText* detected_text = wrappable->ToImpl<DetectedText>();
WriteTag(kDetectedTextTag);
WriteUTF8String(detected_text->rawValue());
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
index 57d8c4a59d5..4e984d0216c 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -270,11 +270,12 @@ bool ConvertCryptoResult<bool>(const ScriptValue& value) {
template <typename T>
class WebCryptoResultAdapter : public ScriptFunction {
- private:
+ public:
WebCryptoResultAdapter(ScriptState* script_state,
base::RepeatingCallback<void(T)> function)
: ScriptFunction(script_state), function_(std::move(function)) {}
+ private:
ScriptValue Call(ScriptValue value) final {
function_.Run(ConvertCryptoResult<T>(value));
return ScriptValue::From(GetScriptState(), ToV8UndefinedGenerator());
@@ -291,9 +292,10 @@ WebCryptoResult ToWebCryptoResult(ScriptState* script_state,
base::RepeatingCallback<void(T)> function) {
CryptoResultImpl* result = CryptoResultImpl::Create(script_state);
result->Promise().Then(
- (new WebCryptoResultAdapter<T>(script_state, std::move(function)))
+ (MakeGarbageCollected<WebCryptoResultAdapter<T>>(script_state,
+ std::move(function)))
->BindToV8Function(),
- (new WebCryptoResultAdapter<DOMException*>(
+ (MakeGarbageCollected<WebCryptoResultAdapter<DOMException*>>(
script_state, WTF::BindRepeating([](DOMException* exception) {
CHECK(false) << "crypto operation failed";
})))
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
index 8ae7cf65e24..af3a05cd20c 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
@@ -65,11 +66,11 @@ v8::Local<v8::Value> ToV8(const IDBKeyPath& value,
v8::Local<v8::Object> creation_context,
v8::Isolate* isolate) {
switch (value.GetType()) {
- case IDBKeyPath::kNullType:
+ case mojom::IDBKeyPathType::Null:
return v8::Null(isolate);
- case IDBKeyPath::kStringType:
+ case mojom::IDBKeyPathType::String:
return V8String(isolate, value.GetString());
- case IDBKeyPath::kArrayType:
+ case mojom::IDBKeyPathType::Array:
return ToV8(value.Array(), creation_context, isolate);
}
NOTREACHED();
@@ -90,21 +91,23 @@ v8::Local<v8::Value> ToV8(const IDBKey* key,
v8::Local<v8::Context> context = isolate->GetCurrentContext();
switch (key->GetType()) {
- case IDBKey::kInvalidType:
- case IDBKey::kTypeEnumMax:
+ case mojom::IDBKeyType::Invalid:
+ case mojom::IDBKeyType::Min:
NOTREACHED();
return v8::Local<v8::Value>();
- case IDBKey::kNumberType:
+ case mojom::IDBKeyType::Null:
+ return v8::Null(isolate);
+ case mojom::IDBKeyType::Number:
return v8::Number::New(isolate, key->Number());
- case IDBKey::kStringType:
+ case mojom::IDBKeyType::String:
return V8String(isolate, key->GetString());
- case IDBKey::kBinaryType:
+ case mojom::IDBKeyType::Binary:
// https://w3c.github.io/IndexedDB/#convert-a-value-to-a-key
return ToV8(DOMArrayBuffer::Create(key->Binary()), creation_context,
isolate);
- case IDBKey::kDateType:
+ case mojom::IDBKeyType::Date:
return v8::Date::New(context, key->Date()).ToLocalChecked();
- case IDBKey::kArrayType: {
+ case mojom::IDBKeyType::Array: {
v8::Local<v8::Array> array = v8::Array::New(isolate, key->Array().size());
for (wtf_size_t i = 0; i < key->Array().size(); ++i) {
v8::Local<v8::Value> value =
@@ -375,7 +378,7 @@ static std::unique_ptr<IDBKey> CreateIDBKeyFromValueAndKeyPath(
ExceptionState& exception_state) {
DCHECK(!key_path.IsNull());
v8::HandleScope handle_scope(isolate);
- if (key_path.GetType() == IDBKeyPath::kArrayType) {
+ if (key_path.GetType() == mojom::IDBKeyPathType::Array) {
IDBKey::KeyArray result;
const Vector<String>& array = key_path.Array();
for (wtf_size_t i = 0; i < array.size(); ++i) {
@@ -387,7 +390,7 @@ static std::unique_ptr<IDBKey> CreateIDBKeyFromValueAndKeyPath(
return IDBKey::CreateArray(std::move(result));
}
- DCHECK_EQ(key_path.GetType(), IDBKeyPath::kStringType);
+ DCHECK_EQ(key_path.GetType(), mojom::IDBKeyPathType::String);
return CreateIDBKeyFromValueAndKeyPath(isolate, value, key_path.GetString(),
exception_state);
}
@@ -494,7 +497,7 @@ bool InjectV8KeyIntoV8Value(v8::Isolate* isolate,
IDB_TRACE("injectIDBV8KeyIntoV8Value");
DCHECK(isolate->InContext());
- DCHECK_EQ(key_path.GetType(), IDBKeyPath::kStringType);
+ DCHECK_EQ(key_path.GetType(), mojom::IDBKeyPathType::String);
Vector<String> key_path_elements = ParseKeyPath(key_path.GetString());
// The conbination of a key generator and an empty key path is forbidden by
@@ -584,7 +587,7 @@ bool CanInjectIDBKeyIntoScriptValue(v8::Isolate* isolate,
const ScriptValue& script_value,
const IDBKeyPath& key_path) {
IDB_TRACE("canInjectIDBKeyIntoScriptValue");
- DCHECK_EQ(key_path.GetType(), IDBKeyPath::kStringType);
+ DCHECK_EQ(key_path.GetType(), mojom::IDBKeyPathType::String);
Vector<String> key_path_elements = ParseKeyPath(key_path.GetString());
if (!key_path_elements.size())
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
index c9194ea91c5..8ba3c6ca6c8 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
@@ -26,9 +26,6 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -118,7 +115,7 @@ void CheckKeyPathStringValue(v8::Isolate* isolate,
std::unique_ptr<IDBKey> idb_key =
CheckKeyFromValueAndKeyPathInternal(isolate, value, key_path);
ASSERT_TRUE(idb_key);
- ASSERT_EQ(IDBKey::kStringType, idb_key->GetType());
+ ASSERT_EQ(mojom::IDBKeyType::String, idb_key->GetType());
ASSERT_TRUE(expected == idb_key->GetString());
}
@@ -129,7 +126,7 @@ void CheckKeyPathNumberValue(v8::Isolate* isolate,
std::unique_ptr<IDBKey> idb_key =
CheckKeyFromValueAndKeyPathInternal(isolate, value, key_path);
ASSERT_TRUE(idb_key);
- ASSERT_EQ(IDBKey::kNumberType, idb_key->GetType());
+ ASSERT_EQ(mojom::IDBKeyType::Number, idb_key->GetType());
ASSERT_TRUE(expected == idb_key->Number());
}
@@ -179,15 +176,16 @@ void SerializeV8Value(v8::Local<v8::Value> value,
std::unique_ptr<IDBValue> CreateIDBValue(v8::Isolate* isolate,
Vector<char>& wire_bytes,
double primary_key,
- const WebString& key_path) {
+ const String& key_path) {
WebData web_data(SharedBuffer::AdoptVector(wire_bytes));
- WebIDBValue web_idb_value(web_data, Vector<WebBlobInfo>());
- web_idb_value.SetInjectedPrimaryKey(WebIDBKey::CreateNumber(primary_key),
- WebIDBKeyPath(key_path));
-
- std::unique_ptr<IDBValue> idb_value = web_idb_value.ReleaseIdbValue();
- idb_value->SetIsolate(isolate);
- return idb_value;
+ scoped_refptr<SharedBuffer> data(web_data);
+ std::unique_ptr<IDBValue> value =
+ IDBValue::Create(data, Vector<WebBlobInfo>());
+ value->SetInjectedPrimaryKey(IDBKey::CreateNumber(primary_key),
+ IDBKeyPath(key_path));
+
+ value->SetIsolate(isolate);
+ return value;
}
TEST(IDBKeyFromValueAndKeyPathTest, TopLevelPropertyStringValue) {
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
index af1ae5c051e..58da9c0e82b 100755
--- a/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
@@ -92,14 +92,21 @@ def origin_trial_features_info(info_provider, reader, idl_filenames, target_comp
types_for_feature = defaultdict(set)
includes = set()
+ # Gather interfaces which are implemented by other interfaces.
+ implemented_interfaces = set()
+ for name, interface_info in info_provider.interfaces_info.iteritems():
+ # Skip special entries such as 'dictionaries' or 'ancestors'.
+ if name.lower() == name:
+ continue
+ implemented_interfaces.update(interface_info.get('implements_interfaces'))
+
for idl_filename in idl_filenames:
interface, implements = read_idl_file(reader, idl_filename)
feature_names = get_origin_trial_feature_names_from_interface(interface)
- # If this interface has NoInterfaceObject then we don't want to add
- # includes for it because it is a base interface to be implemented
- # by other interfaces, and does not generate an ECMAScript binding.
- if 'NoInterfaceObject' in interface.extended_attributes:
+ # If this interface is implemented by other interfaces, we don't generate
+ # V8 bindings code for it.
+ if interface.name in implemented_interfaces:
continue
# If this interface implements another one,
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py
index b7980d186d5..27073618789 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py
@@ -49,7 +49,6 @@ IdlDefinitions
IdlLiteral
IdlOperation < TypedObject
IdlArgument < TypedObject
- IdlSerializer
IdlStringifier
IdlIterable < IdlIterableOrMaplikeOrSetlike
IdlMaplike < IdlIterableOrMaplikeOrSetlike
@@ -298,7 +297,6 @@ class IdlInterface(object):
self.extended_attributes = {}
self.operations = []
self.parent = None
- self.serializer = None
self.stringifier = None
self.iterable = None
self.has_indexed_elements = False
@@ -350,9 +348,6 @@ class IdlInterface(object):
self.operations.append(op)
elif child_class == 'Inherit':
self.parent = child.GetName()
- elif child_class == 'Serializer':
- self.serializer = IdlSerializer(child)
- self.process_serializer()
elif child_class == 'Stringifier':
self.stringifier = IdlStringifier(child)
self.process_stringifier()
@@ -406,12 +401,6 @@ class IdlInterface(object):
elif self.setlike:
self.setlike.accept(visitor)
- def process_serializer(self):
- """Add the serializer's named operation child, if it has one, as a regular
- operation of this interface."""
- if self.serializer.operation:
- self.operations.append(self.serializer.operation)
-
def process_stringifier(self):
"""Add the stringifier's attribute or named operation child, if it has
one, as a regular attribute/operation of this interface."""
@@ -425,8 +414,6 @@ class IdlInterface(object):
self.attributes.extend(other.attributes)
self.constants.extend(other.constants)
self.operations.extend(other.operations)
- if self.serializer is None:
- self.serializer = other.serializer
if self.stringifier is None:
self.stringifier = other.stringifier
@@ -649,42 +636,6 @@ def arguments_node_to_arguments(node):
################################################################################
-# Serializers
-################################################################################
-
-class IdlSerializer(object):
- def __init__(self, node):
- self.attribute_name = node.GetProperty('ATTRIBUTE')
- self.attribute_names = None
- self.operation = None
- self.extended_attributes = {}
- self.is_attribute = False
- self.is_getter = False
- self.is_inherit = False
- self.is_list = False
- self.is_map = False
-
- for child in node.GetChildren():
- child_class = child.GetClass()
- if child_class == 'Operation':
- self.operation = IdlOperation(child)
- elif child_class == 'List':
- self.is_list = True
- self.is_getter = bool(child.GetProperty('GETTER'))
- self.attributes = child.GetProperty('ATTRIBUTES')
- elif child_class == 'Map':
- self.is_map = True
- self.is_attribute = bool(child.GetProperty('ATTRIBUTE'))
- self.is_getter = bool(child.GetProperty('GETTER'))
- self.is_inherit = bool(child.GetProperty('INHERIT'))
- self.attributes = child.GetProperty('ATTRIBUTES')
- elif child_class == 'ExtAttributes':
- self.extended_attributes = ext_attributes_node_to_extended_attributes(child)
- else:
- raise ValueError('Unrecognized node class: %s' % child_class)
-
-
-################################################################################
# Stringifiers
################################################################################
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py
index f06d6dfc206..6aca226c0b1 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py
@@ -129,6 +129,9 @@ def attribute_context(interface, attribute, interfaces):
deprecate_as = v8_utilities.deprecate_as(attribute)
measure_as = v8_utilities.measure_as(attribute, interface)
+ # [HighEntropy]
+ high_entropy = v8_utilities.high_entropy(attribute)
+
is_lazy_data_attribute = \
(constructor_type and not (measure_as or deprecate_as)) or \
(str(idl_type) == 'Window' and attribute.name in ('frames', 'self', 'window'))
@@ -144,6 +147,7 @@ def attribute_context(interface, attribute, interfaces):
'cpp_name': cpp_name(attribute),
'cpp_type': idl_type.cpp_type,
'cpp_type_initializer': idl_type.cpp_type_initializer,
+ 'high_entropy': high_entropy,
'deprecate_as': deprecate_as,
'enum_type': idl_type.enum_type,
'enum_values': idl_type.enum_values,
@@ -497,19 +501,16 @@ def setter_expression(interface, attribute, context):
arguments.append('*impl')
idl_type = attribute.idl_type
if idl_type.base_type == 'EventHandler':
- getter_name = scoped_name(interface, attribute, cpp_name(attribute))
- context['event_handler_getter_expression'] = '%s(%s)' % (
- getter_name, ', '.join(arguments))
handler_type = 'kEventHandler'
if attribute.name == 'onerror':
handler_type = 'kOnErrorEventHandler'
elif attribute.name == 'onbeforeunload':
handler_type = 'kOnBeforeUnloadEventHandler'
arguments.append(
- 'V8EventListenerHelper::GetEventHandler(' +
- 'ScriptState::ForRelevantRealm(info), v8_value, ' +
+ 'JSEventHandler::CreateOrNull(' +
+ 'v8_value, ' +
'JSEventHandler::HandlerType::' + handler_type +
- ', kListenerFindOrCreate)')
+ ')')
elif idl_type.base_type == 'SerializedScriptValue':
arguments.append('std::move(cpp_value)')
else:
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py
index 7b5227a2de2..04860137a09 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py
@@ -115,6 +115,11 @@ def member_context(dictionary, member):
raise Exception(
'Required member %s must not have a default value.' % member.name)
+ if idl_type.is_nullable and idl_type.inner_type.is_dictionary:
+ raise Exception(
+ 'The inner type of nullable member %s must not be a dictionary.' %
+ member.name)
+
# In most cases, we don't have to distinguish `null` and `not present`,
# and use null-states (e.g. nullptr, foo.IsUndefinedOrNull()) to show such
# states for some types for memory usage and performance.
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py
index 3468250813a..5dcbc51fac8 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py
@@ -685,13 +685,13 @@ def methods_context(interface):
generated_iterator_method('keys'),
entries_or_values_method,
- # void forEach(Function callback, [Default=Undefined] optional any thisArg)
+ # void forEach(Function callback, [DefaultValue=Undefined] optional any thisArg)
generated_method(IdlType('void'), 'forEach',
# TODO(yukishiino): |callback| should be type of Function.
arguments=[generated_argument(IdlType('CallbackFunctionTreatedAsScriptValue'), 'callback'),
generated_argument(IdlType('any'), 'thisArg',
is_optional=True,
- extended_attributes={'Default': 'Undefined'})],
+ extended_attributes={'DefaultValue': 'Undefined'})],
extended_attributes=forEach_extended_attributes),
])
@@ -762,24 +762,6 @@ def methods_context(interface):
# FIXME: maplike<> and setlike<> should also imply the presence of a
# 'size' attribute.
- # Serializer
- if interface.serializer:
- serializer = interface.serializer
- serializer_ext_attrs = serializer.extended_attributes.copy()
- if serializer.operation:
- return_type = serializer.operation.idl_type
- implemented_as = serializer.operation.name
- else:
- return_type = IdlType('any')
- implemented_as = None
- if 'CallWith' not in serializer_ext_attrs:
- serializer_ext_attrs['CallWith'] = 'ScriptState'
- methods.append(generated_method(
- return_type=return_type,
- name='toJSON',
- extended_attributes=serializer_ext_attrs,
- implemented_as=implemented_as))
-
# Stringifier
if interface.stringifier:
stringifier = interface.stringifier
@@ -841,6 +823,7 @@ def constant_context(constant, interface):
'deprecate_as': v8_utilities.deprecate_as(constant), # [DeprecateAs]
'idl_type': constant.idl_type.name,
'measure_as': v8_utilities.measure_as(constant, interface), # [MeasureAs]
+ 'high_entropy': v8_utilities.high_entropy(constant), # [HighEntropy]
'name': constant.name,
'origin_trial_feature_name': v8_utilities.origin_trial_feature_name(constant), # [OriginTrialEnabled]
# FIXME: use 'reflected_name' as correct 'name'
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py
index 11dbd99db4d..f63b86a3f1e 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py
@@ -139,10 +139,6 @@ def method_context(interface, method, is_visible=True):
this_cpp_value = cpp_value(interface, method, len(arguments))
- is_call_with_script_arguments = has_extended_attribute_value(method, 'CallWith', 'ScriptArguments')
- if is_call_with_script_arguments:
- includes.update(['bindings/core/v8/script_call_stack.h',
- 'core/inspector/script_arguments.h'])
is_call_with_script_state = has_extended_attribute_value(method, 'CallWith', 'ScriptState')
is_call_with_this_value = has_extended_attribute_value(method, 'CallWith', 'ThisValue')
if is_call_with_script_state or is_call_with_this_value:
@@ -195,6 +191,7 @@ def method_context(interface, method, is_visible=True):
if idl_type.is_explicit_nullable else idl_type.cpp_type),
'cpp_value': this_cpp_value,
'cpp_type_initializer': idl_type.cpp_type_initializer,
+ 'high_entropy': v8_utilities.high_entropy(method), # [HighEntropy]
'deprecate_as': v8_utilities.deprecate_as(method), # [DeprecateAs]
'do_not_test_new_object': 'DoNotTestNewObject' in extended_attributes,
'exposed_test': v8_utilities.exposed(method, interface), # [Exposed]
@@ -209,7 +206,6 @@ def method_context(interface, method, is_visible=True):
if argument_context['is_optional_without_default_value']),
'idl_type': idl_type.base_type,
'is_call_with_execution_context': has_extended_attribute_value(method, 'CallWith', 'ExecutionContext'),
- 'is_call_with_script_arguments': is_call_with_script_arguments,
'is_call_with_script_state': is_call_with_script_state,
'is_call_with_this_value': is_call_with_this_value,
'is_ce_reactions': is_ce_reactions,
@@ -287,8 +283,9 @@ def argument_context(interface, method, argument, index, is_visible=True):
'enum_type': idl_type.enum_type,
'enum_values': idl_type.enum_values,
'handle': '%s_handle' % snake_case_name,
- # FIXME: remove once [Default] removed and just use argument.default_value
- 'has_default': 'Default' in extended_attributes or set_default_value,
+ # TODO(peria): remove once [DefaultValue] removed and just use
+ # argument.default_value. https://crbug.com/924419
+ 'has_default': 'DefaultValue' in extended_attributes or set_default_value,
'has_type_checking_interface': has_type_checking_interface,
# Dictionary is special-cased, but arrays and sequences shouldn't be
'idl_type': idl_type.base_type,
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py
index 7bb7a2fc29a..3765385eb00 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py
@@ -60,7 +60,6 @@ from v8_utilities import binding_header_filename, extended_attribute_value_conta
NON_WRAPPER_TYPES = frozenset([
'Dictionary',
'EventHandler',
- 'EventListener',
'NodeFilter',
'SerializedScriptValue',
])
@@ -130,7 +129,6 @@ CPP_SPECIAL_CONVERSION_RULES = {
'Date': 'double',
'Dictionary': 'Dictionary',
'EventHandler': 'EventListener*',
- 'EventListener': 'EventListener*',
'Promise': 'ScriptPromise',
'ScriptValue': 'ScriptValue',
# FIXME: Eliminate custom bindings for XPathNSResolver http://crbug.com/345529
@@ -403,8 +401,7 @@ INCLUDES_FOR_TYPE = {
'core/typed_arrays/array_buffer_view_helpers.h',
'core/typed_arrays/flexible_array_buffer_view.h']),
'Dictionary': set(['bindings/core/v8/dictionary.h']),
- 'EventHandler': set(['bindings/core/v8/v8_event_listener_helper.h']),
- 'EventListener': set(['bindings/core/v8/v8_event_listener_helper.h']),
+ 'EventHandler': set(['bindings/core/v8/js_event_handler.h']),
'HTMLCollection': set(['bindings/core/v8/v8_html_collection.h',
'core/dom/class_collection.h',
'core/dom/tag_collection.h',
@@ -1013,8 +1010,7 @@ CPP_VALUE_TO_V8_VALUE = {
'V8String({isolate}, {cpp_value}).As<v8::Value>())'),
# Special cases
'Dictionary': '{cpp_value}.V8Value()',
- 'EventHandler':
- 'JSBasedEventListener::GetListenerOrNull({isolate}, impl, {cpp_value})',
+ 'EventHandler': 'JSEventHandler::AsV8Value({isolate}, impl, {cpp_value})',
'NodeFilter': 'ToV8({cpp_value}, {creation_context}, {isolate})',
'Record': 'ToV8({cpp_value}, {creation_context}, {isolate})',
'ScriptValue': '{cpp_value}.V8Value()',
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py
index 0d523207b43..348084951b9 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py
@@ -206,9 +206,9 @@ def activity_logging_world_check(member):
# [CallWith]
CALL_WITH_ARGUMENTS = {
+ 'Isolate': 'info.GetIsolate()',
'ScriptState': 'script_state',
'ExecutionContext': 'execution_context',
- 'ScriptArguments': 'script_arguments',
'CurrentWindow': 'CurrentDOMWindow(info.GetIsolate())',
'EnteredWindow': 'EnteredDOMWindow(info.GetIsolate())',
'Document': 'document',
@@ -216,9 +216,9 @@ CALL_WITH_ARGUMENTS = {
}
# List because key order matters, as we want arguments in deterministic order
CALL_WITH_VALUES = [
+ 'Isolate',
'ScriptState',
'ExecutionContext',
- 'ScriptArguments',
'CurrentWindow',
'EnteredWindow',
'Document',
@@ -402,6 +402,19 @@ def measure_as(definition_or_member, interface):
return None
+# [HighEntropy]
+def high_entropy(definition_or_member):
+ extended_attributes = definition_or_member.extended_attributes
+ if 'HighEntropy' in extended_attributes:
+ includes.add('core/frame/dactyloscoper.h')
+ if not ('Measure' in extended_attributes or 'MeasureAs' in extended_attributes):
+ raise Exception('%s specified [HighEntropy], but does not include '
+ 'either [Measure] or [MeasureAs]'
+ % definition_or_member.name)
+ return True
+ return False
+
+
# [OriginTrialEnabled]
def origin_trial_feature_name(definition_or_member):
"""Returns the name of the feature for the OriginTrialEnabled attribute.
diff --git a/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl
index 3f3d94dcd9f..202786f4e80 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl
@@ -252,7 +252,11 @@ const v8::FunctionCallbackInfo<v8::Value>& info
{% endif %}
{% if attribute.measure_as %}
- UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{attribute.measure_as('AttributeGetter')}});
+ ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate());
+ UseCounter::Count(execution_context_for_measurement, WebFeature::k{{attribute.measure_as('AttributeGetter')}});
+ {% if attribute.high_entropy %}
+ Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{attribute.measure_as('AttributeGetter')}});
+ {% endif %}
{% endif %}
{% if world_suffix in attribute.activity_logging_world_list_for_getter %}
@@ -290,13 +294,17 @@ void {{v8_class_or_partial}}::{{attribute.camel_case_name}}ConstructorGetterCall
{% endif %}
{% if attribute.measure_as %}
- UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{attribute.measure_as('ConstructorGetter')}});
+ ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate());
+ UseCounter::Count(execution_context_for_measurement, WebFeature::k{{attribute.measure_as('ConstructorGetter')}});
+ {% if attribute.high_entropy %}
+ Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{attribute.measure_as('ConstructorGetter')}});
+ {% endif %}
{% endif %}
{% if attribute.is_named_constructor %}
V8{{attribute.constructor_type}}::NamedConstructorAttributeGetter(property, info);
{% else %}
- V8ConstructorAttributeGetter(property, info, &V8{{attribute.constructor_type}}::wrapper_type_info);
+ V8ConstructorAttributeGetter(property, info, V8{{attribute.constructor_type}}::GetWrapperTypeInfo());
{% endif %}
}
{% endmacro %}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl
index 9331774ef04..c4e1ea8b9e8 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl
@@ -51,22 +51,22 @@ void {{cpp_class}}::InvokeAndReportException({{argument_declarations | join(', '
{% if callback_function_name == 'EventHandlerNonNull' %}
bool {{cpp_class}}::IsRunnableOrThrowException(IgnorePause ignore_pause) {
+ ScriptState* callback_relevant_script_state =
+ CallbackRelevantScriptState();
+
bool is_runnable =
ignore_pause == IgnorePause::kIgnore ?
IsCallbackFunctionRunnableIgnoringPause(
- CallbackRelevantScriptState(), IncumbentScriptState()) :
+ callback_relevant_script_state, IncumbentScriptState()) :
IsCallbackFunctionRunnable(
- CallbackRelevantScriptState(), IncumbentScriptState());
+ callback_relevant_script_state, IncumbentScriptState());
if (is_runnable)
return true;
// Wrapper-tracing for the callback function makes the function object and
// its creation context alive. Thus it's safe to use the creation context
// of the callback function here.
- v8::HandleScope handle_scope(GetIsolate());
- v8::Local<v8::Object> callback_object = CallbackObject();
- CHECK(!callback_object.IsEmpty());
- v8::Context::Scope context_scope(callback_object->CreationContext());
+ ScriptState::Scope scope(callback_relevant_script_state);
V8ThrowException::ThrowError(
GetIsolate(),
ExceptionMessages::FailedToExecute(
diff --git a/chromium/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl b/chromium/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
index bb739787bd1..0e27d98ff63 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
@@ -72,6 +72,8 @@ class V8PersistentCallbackFunction<{{cpp_class}}> final : public V8PersistentCal
using V8CallbackFunction = {{cpp_class}};
public:
+ explicit V8PersistentCallbackFunction(V8CallbackFunction* callback_function)
+ : V8PersistentCallbackFunctionBase(callback_function) {}
~V8PersistentCallbackFunction() override = default;
// Returns a wrapper-tracing version of this callback function.
@@ -83,9 +85,6 @@ class V8PersistentCallbackFunction<{{cpp_class}}> final : public V8PersistentCal
{% endif %}
private:
- explicit V8PersistentCallbackFunction(V8CallbackFunction* callback_function)
- : V8PersistentCallbackFunctionBase(callback_function) {}
-
V8CallbackFunction* Proxy() {
return As<V8CallbackFunction>();
}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl
index 527221ba342..a0bf43f0c09 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl
@@ -20,7 +20,7 @@ namespace blink {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#endif
-const WrapperTypeInfo {{v8_class}}::wrapper_type_info = {
+const WrapperTypeInfo {{snake_case_v8_class}}_wrapper_type_info = {
gin::kEmbedderBlink,
{{v8_class}}::DomTemplate,
nullptr,
@@ -42,7 +42,7 @@ static void Install{{v8_class}}Template(v8::Isolate* isolate, const DOMWrapperWo
// Initialize the interface object's template.
V8DOMConfiguration::InitializeDOMInterfaceTemplate(
isolate, interface_template,
- {{v8_class}}::wrapper_type_info.interface_name,
+ {{v8_class}}::GetWrapperTypeInfo()->interface_name,
v8::Local<v8::FunctionTemplate>(),
kV8DefaultWrapperInternalFieldCount);
interface_template->SetLength(0);
@@ -59,7 +59,7 @@ v8::Local<v8::FunctionTemplate> {{v8_class}}::DomTemplate(v8::Isolate* isolate,
return V8DOMConfiguration::DomClassTemplate(
isolate,
world,
- const_cast<WrapperTypeInfo*>(&wrapper_type_info),
+ const_cast<WrapperTypeInfo*>(GetWrapperTypeInfo()),
Install{{v8_class}}Template);
}
{% endif %}{# is_legacy_callback_interface #}
@@ -68,19 +68,6 @@ const char* {{v8_class}}::NameInHeapSnapshot() const {
return "{{v8_class}}";
}
-// static
-{{v8_class}}* {{v8_class}}::CreateOrNull(v8::Local<v8::Object> callback_object) {
- v8::Local<v8::Context> creation_context = callback_object->CreationContext();
- // When |callback_object| is an object in RemoteContext (i.e. RemoteInstance),
- // the object has no creation context, and no way to proceed.
- // TODO(crbug.com/886588): Make CreateOrNull into Create removing the early
- // return with nullptr.
- if (creation_context.IsEmpty())
- return nullptr;
-
- return MakeGarbageCollected<{{v8_class}}>(callback_object, creation_context);
-}
-
{% for method in methods %}
v8::Maybe<{{method.cpp_type}}> {{v8_class}}::{{method.name}}({{method.argument_declarations | join(', ')}}) {
@@ -111,22 +98,22 @@ void {{v8_class}}::InvokeAndReportException({{methods[0].argument_declarations |
{% if interface_name == 'EventListener' %}
bool {{v8_class}}::IsRunnableOrThrowException(IgnorePause ignore_pause) {
+ ScriptState* callback_relevant_script_state =
+ CallbackRelevantScriptState();
+
bool is_runnable =
ignore_pause == IgnorePause::kIgnore ?
IsCallbackFunctionRunnableIgnoringPause(
- CallbackRelevantScriptState(), IncumbentScriptState()) :
+ callback_relevant_script_state, IncumbentScriptState()) :
IsCallbackFunctionRunnable(
- CallbackRelevantScriptState(), IncumbentScriptState());
+ callback_relevant_script_state, IncumbentScriptState());
if (is_runnable)
return true;
// Wrapper-tracing for the callback function makes the function object and
// its creation context alive. Thus it's safe to use the creation context
// of the callback function here.
- v8::HandleScope handle_scope(GetIsolate());
- v8::Local<v8::Object> callback_object = CallbackObject();
- CHECK(!callback_object.IsEmpty());
- v8::Context::Scope context_scope(callback_object->CreationContext());
+ ScriptState::Scope scope(callback_relevant_script_state);
V8ThrowException::ThrowError(
GetIsolate(),
ExceptionMessages::FailedToExecute(
diff --git a/chromium/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl b/chromium/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl
index 2fdb7be87fb..fa259312cb5 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl
@@ -14,31 +14,34 @@ namespace blink {
class {{forward_declaration}};
{% endfor %}
+{% if is_legacy_callback_interface %}
+{{exported}}extern const WrapperTypeInfo {{snake_case_v8_class}}_wrapper_type_info;
+{% endif %}
+
class {{exported}}{{v8_class}} final : public CallbackInterfaceBase {
public:
{% if is_legacy_callback_interface %}
// Support of "legacy callback interface"
static v8::Local<v8::FunctionTemplate> DomTemplate(v8::Isolate*, const DOMWrapperWorld&);
- static const WrapperTypeInfo wrapper_type_info;
+ static constexpr const WrapperTypeInfo* GetWrapperTypeInfo() {
+ return &{{snake_case_v8_class}}_wrapper_type_info;
+ }
+
// Constants
{% for constant in constants %}
static constexpr {{constant.cpp_type}} {{constant.name}} = {{constant.value}};
{% endfor %}
{% endif %}
- // Creates and returns a new instance. Returns nullptr when |callback_object|
- // is an object in a remote context (e.g. cross origin window object). The
- // call sites may want to throw a SecurityError in the case.
- // See also crbug.com/886588
- static {{v8_class}}* CreateOrNull(v8::Local<v8::Object> callback_object);
+ static {{v8_class}}* Create(v8::Local<v8::Object> callback_object) {
+ return MakeGarbageCollected<{{v8_class}}>(callback_object);
+ }
{% set single_operation_enum_value =
'kSingleOperation' if is_single_operation_callback_interface else
'kNotSingleOperation' %}
- explicit {{v8_class}}(
- v8::Local<v8::Object> callback_object,
- v8::Local<v8::Context> callback_object_creation_context)
- : CallbackInterfaceBase(callback_object, callback_object_creation_context,
+ explicit {{v8_class}}(v8::Local<v8::Object> callback_object)
+ : CallbackInterfaceBase(callback_object,
{{single_operation_enum_value}}) {}
~{{v8_class}}() override = default;
@@ -79,6 +82,8 @@ class V8PersistentCallbackInterface<{{v8_class}}> final : public V8PersistentCal
using V8CallbackInterface = {{v8_class}};
public:
+ explicit V8PersistentCallbackInterface(V8CallbackInterface* callback_interface)
+ : V8PersistentCallbackInterfaceBase(callback_interface) {}
~V8PersistentCallbackInterface() override = default;
{% for method in methods %}
@@ -89,9 +94,6 @@ class V8PersistentCallbackInterface<{{v8_class}}> final : public V8PersistentCal
{% endif %}
private:
- explicit V8PersistentCallbackInterface(V8CallbackInterface* callback_interface)
- : V8PersistentCallbackInterfaceBase(callback_interface) {}
-
V8CallbackInterface* Proxy() {
return As<V8CallbackInterface>();
}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
index 647fd8ae4d7..6c5ae31b312 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
@@ -21,8 +21,16 @@
return_cpp_type, return_native_value_traits_tag, arguments,
is_treat_non_object_as_null, bypass_runnability_check,
interface_name, operation_name) %}
+ ScriptState* callback_relevant_script_state =
+ CallbackRelevantScriptStateOrThrowException(
+ "{{interface_name}}",
+ "{{operation_name}}");
+ if (!callback_relevant_script_state) {
+ return v8::Nothing<{{return_cpp_type}}>();
+ }
+
{% if not bypass_runnability_check %}
- if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState(),
+ if (!IsCallbackFunctionRunnable(callback_relevant_script_state,
IncumbentScriptState())) {
// Wrapper-tracing for the callback function makes the function object and
// its creation context alive. Thus it's safe to use the creation context
@@ -43,7 +51,7 @@
// step: Prepare to run script with relevant settings.
ScriptState::Scope callback_relevant_context_scope(
- CallbackRelevantScriptState());
+ callback_relevant_script_state);
// step: Prepare to run a callback with stored settings.
v8::Context::BackupIncumbentScope backup_incumbent_scope(
IncumbentScriptState()->GetContext());
@@ -109,7 +117,7 @@
// step 9.2.2. If getResult is an abrupt completion, set completion to
// getResult and jump to the step labeled return.
v8::Local<v8::Value> value;
- if (!CallbackObject()->Get(CallbackRelevantScriptState()->GetContext(),
+ if (!CallbackObject()->Get(callback_relevant_script_state->GetContext(),
V8String(GetIsolate(), "{{operation_name}}"))
.ToLocal(&value)) {
return v8::Nothing<{{return_cpp_type}}>();
@@ -135,7 +143,7 @@
{% endif %}
{# Fill |this_arg|. #}
{% if invoke_or_construct == 'invoke' %}
- this_arg = ToV8(callback_this_value, CallbackRelevantScriptState());
+ this_arg = ToV8(callback_this_value, callback_relevant_script_state);
{% elif interface_or_function == 'callback interface' %}
if (!IsCallbackObjectCallable()) {
// step 11. If value's interface is not a single operation callback
@@ -146,7 +154,7 @@
// step 2. If thisArg was not given, let thisArg be undefined.
this_arg = v8::Undefined(GetIsolate());
} else {
- this_arg = ToV8(callback_this_value, CallbackRelevantScriptState());
+ this_arg = ToV8(callback_this_value, callback_relevant_script_state);
}
{% endif %}
@@ -174,7 +182,7 @@
// labeled return.
{% if arguments %}
v8::Local<v8::Object> argument_creation_context =
- CallbackRelevantScriptState()->GetContext()->Global();
+ callback_relevant_script_state->GetContext()->Global();
ALLOW_UNUSED_LOCAL(argument_creation_context);
{% set has_variadic_argument = arguments[-1].is_variadic %}
{% set non_variadic_arguments = arguments | rejectattr('is_variadic') | list %}
@@ -209,7 +217,7 @@
if (!V8ScriptRunner::CallAsConstructor(
GetIsolate(),
function,
- ExecutionContext::From(CallbackRelevantScriptState()),
+ ExecutionContext::From(callback_relevant_script_state),
argc,
argv).ToLocal(&call_result)) {
// step 11. If callResult is an abrupt completion, set completion to
@@ -220,7 +228,7 @@
// step: Let callResult be Call(X, thisArg, esArgs).
if (!V8ScriptRunner::CallFunction(
function,
- ExecutionContext::From(CallbackRelevantScriptState()),
+ ExecutionContext::From(callback_relevant_script_state),
this_arg,
argc,
argv,
diff --git a/chromium/third_party/blink/renderer/bindings/templates/constants.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/constants.cc.tmpl
index a9fba5a4017..2ba625e541f 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/constants.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/constants.cc.tmpl
@@ -8,7 +8,11 @@ void {{v8_class_or_partial}}::{{constant.camel_case_name}}ConstantGetterCallback
Deprecation::CountDeprecation(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{constant.deprecate_as}});
{% endif %}
{% if constant.measure_as %}
- UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{constant.measure_as('ConstantGetter')}});
+ ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate());
+ UseCounter::Count(execution_context_for_measurement, WebFeature::k{{constant.measure_as('ConstantGetter')}});
+ {% if constant.high_entropy %}
+ Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{constant.measure_as('ConstantGetter')}});
+ {% endif %}
{% endif %}
{% if constant.idl_type in ('Double', 'Float') %}
V8SetReturnValue(info, {{constant.value}});
diff --git a/chromium/third_party/blink/renderer/bindings/templates/external_reference_table.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/external_reference_table.cc.tmpl
index dcd1bee8fa4..4f44253b784 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/external_reference_table.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/external_reference_table.cc.tmpl
@@ -75,7 +75,7 @@ const intptr_t* {{class}}::GetTable() {
{% endif %}
{% if interface.has_security_check %}
reinterpret_cast<intptr_t>({{v8_class}}::SecurityCheck),
- reinterpret_cast<intptr_t>(&{{v8_class}}::wrapper_type_info),
+ reinterpret_cast<intptr_t>({{v8_class}}::GetWrapperTypeInfo()),
{% endif %}
{# Other properties #}
{% if interface.has_constructor_callback %}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/interface.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/interface.cc.tmpl
index 06dc821d117..069ccbe9a4d 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/interface.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/interface.cc.tmpl
@@ -787,7 +787,7 @@ void {{v8_class_or_partial}}::{{cpp_class}}OriginSafeMethodSetterCallback(
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#endif
-const WrapperTypeInfo {{v8_class}}Constructor::wrapper_type_info = {
+const WrapperTypeInfo {{snake_case_v8_class}}_constructor_wrapper_type_info = {
gin::kEmbedderBlink,
{{v8_class}}Constructor::DomTemplate,
{{install_conditional_features_func or 'nullptr'}},
@@ -831,7 +831,7 @@ void {{v8_class}}Constructor::NamedConstructorAttributeGetter(
}
v8::Local<v8::Function> named_constructor =
- per_context_data->ConstructorForType(&{{v8_class}}Constructor::wrapper_type_info);
+ per_context_data->ConstructorForType({{v8_class}}Constructor::GetWrapperTypeInfo());
// Set the prototype of named constructors to the regular constructor.
auto private_property =
@@ -842,15 +842,21 @@ void {{v8_class}}Constructor::NamedConstructorAttributeGetter(
if (!private_property.GetOrUndefined(named_constructor).ToLocal(&private_value) ||
private_value->IsUndefined()) {
v8::Local<v8::Function> interface =
- per_context_data->ConstructorForType(&{{v8_class}}::wrapper_type_info);
- v8::Local<v8::Value> interfacePrototype =
+ per_context_data->ConstructorForType({{v8_class}}::GetWrapperTypeInfo());
+ v8::Local<v8::Value> interface_prototype =
interface->Get(current_context, V8AtomicString(info.GetIsolate(), "prototype"))
.ToLocalChecked();
- bool result = named_constructor->Set(
+ // https://heycam.github.io/webidl/#named-constructors
+ // 8. Perform ! DefinePropertyOrThrow(F, "prototype",
+ // PropertyDescriptor{[[Value]]: proto, [[Writable]]: false,
+ // [[Enumerable]]: false,
+ // [Configurable]]: false}).
+ const v8::PropertyAttribute prototype_attributes =
+ static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+ bool result = named_constructor->DefineOwnProperty(
current_context, V8AtomicString(info.GetIsolate(), "prototype"),
- interfacePrototype).ToChecked();
- if (!result)
- return;
+ interface_prototype, prototype_attributes).ToChecked();
+ CHECK(result);
private_property.Set(named_constructor, v8::True(info.GetIsolate()));
}
@@ -915,7 +921,11 @@ static void Constructor(const v8::FunctionCallbackInfo<v8::Value>& info) {
{{exported}}void ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
{{ runtime_timer_scope_disabled_by_default(runtime_call_stats.constructor_counter) }}
{% if measure_as %}
- UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{measure_as('Constructor')}});
+ ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate());
+ UseCounter::Count(execution_context_for_measurement, WebFeature::k{{measure_as('Constructor')}});
+ {% if high_entropy %}
+ Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{measure_as('Constructor')}});
+ {% endif %}
{% endif %}
if (!info.IsConstructCall()) {
V8ThrowException::ThrowTypeError(
@@ -933,7 +943,7 @@ static void Constructor(const v8::FunctionCallbackInfo<v8::Value>& info) {
{{v8_class}}::ConstructorCustom(info);
{% elif has_html_constructor %}
V8HTMLConstructor::HtmlConstructor(
- info, {{v8_class}}::wrapper_type_info, HTMLElementType::k{{interface_name}});
+ info, *{{v8_class}}::GetWrapperTypeInfo(), HTMLElementType::k{{interface_name}});
{% else %}
{{internal_namespace}}::Constructor(info);
{% endif %}
@@ -1051,7 +1061,7 @@ v8::Local<v8::FunctionTemplate> {{v8_class}}::DomTemplate(
v8::Isolate* isolate, const DOMWrapperWorld& world) {
{% set install_template_function = '%s::install_%s_template_function_' % (v8_class, snake_case_v8_class) if has_partial_interface else 'Install%sTemplate' % v8_class %}
return V8DOMConfiguration::DomClassTemplate(
- isolate, world, const_cast<WrapperTypeInfo*>(&wrapper_type_info),
+ isolate, world, const_cast<WrapperTypeInfo*>({{v8_class}}::GetWrapperTypeInfo()),
{{install_template_function}});
}
@@ -1097,13 +1107,13 @@ v8::Local<v8::FunctionTemplate>
{% if not is_array_buffer_or_view %}
bool {{v8_class}}::HasInstance(v8::Local<v8::Value> v8_value, v8::Isolate* isolate) {
- return V8PerIsolateData::From(isolate)->HasInstance(&wrapper_type_info, v8_value);
+ return V8PerIsolateData::From(isolate)->HasInstance({{v8_class}}::GetWrapperTypeInfo(), v8_value);
}
v8::Local<v8::Object> {{v8_class}}::FindInstanceInPrototypeChain(
v8::Local<v8::Value> v8_value, v8::Isolate* isolate) {
return V8PerIsolateData::From(isolate)->FindInstanceInPrototypeChain(
- &wrapper_type_info, v8_value);
+ {{v8_class}}::GetWrapperTypeInfo(), v8_value);
}
{% endif %}
@@ -1277,7 +1287,7 @@ void {{v8_class}}::UpdateWrapperTypeInfo(
{% endif %}
if (install_conditional_features_function) {
- {{v8_class}}::wrapper_type_info.install_conditional_features_function =
+ {{v8_class}}::GetWrapperTypeInfo()->install_conditional_features_function =
install_conditional_features_function;
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/interface.h.tmpl b/chromium/third_party/blink/renderer/bindings/templates/interface.h.tmpl
index 240114540c7..c124e53e940 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/interface.h.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/interface.h.tmpl
@@ -14,15 +14,27 @@ namespace blink {
class ScriptState;
{% endif %}
{% if named_constructor %}
+
+extern const WrapperTypeInfo {{snake_case_v8_class}}_constructor_wrapper_type_info;
+
class {{v8_class}}Constructor {
STATIC_ONLY({{v8_class}}Constructor);
public:
static v8::Local<v8::FunctionTemplate> DomTemplate(v8::Isolate*, const DOMWrapperWorld&);
static void NamedConstructorAttributeGetter(v8::Local<v8::Name> property_name, const v8::PropertyCallbackInfo<v8::Value>& info);
- static const WrapperTypeInfo wrapper_type_info;
+ static constexpr const WrapperTypeInfo* GetWrapperTypeInfo() {
+ return &{{snake_case_v8_class}}_constructor_wrapper_type_info;
+ }
};
{% endif %}
+
+{% if has_partial_interface %}
+{{exported}}extern WrapperTypeInfo {{snake_case_v8_class}}_wrapper_type_info;
+{% else %}
+{{exported}}extern const WrapperTypeInfo {{snake_case_v8_class}}_wrapper_type_info;
+{% endif %}
+
class {{v8_class}} {
STATIC_ONLY({{v8_class}});
public:
@@ -40,11 +52,15 @@ class {{v8_class}} {
}
{% endif %}
{{exported}}static {{cpp_class}}* ToImplWithTypeCheck(v8::Isolate*, v8::Local<v8::Value>);
+
{% if has_partial_interface %}
- {{exported}}static WrapperTypeInfo wrapper_type_info;
+ {{exported}}static constexpr WrapperTypeInfo* GetWrapperTypeInfo() {
{% else %}
- {{exported}}static const WrapperTypeInfo wrapper_type_info;
+ {{exported}}static constexpr const WrapperTypeInfo* GetWrapperTypeInfo() {
{% endif %}
+ return &{{snake_case_v8_class}}_wrapper_type_info;
+ }
+
{% for method in methods %}
{% if method.is_custom %}
static void {{method.camel_case_name}}MethodCustom(const v8::FunctionCallbackInfo<v8::Value>&);
diff --git a/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
index 1f41c62eb8a..e49940ba0c9 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
@@ -9,7 +9,7 @@
namespace blink {
{% set dom_template = '%s::DomTemplate' % v8_class if not is_array_buffer_or_view else 'nullptr' %}
-{% set parent_wrapper_type_info = '&V8%s::wrapper_type_info' % parent_interface
+{% set parent_wrapper_type_info = 'V8%s::GetWrapperTypeInfo()' % parent_interface
if parent_interface else 'nullptr' %}
{% set active_scriptwrappable_inheritance =
'kInheritFromActiveScriptWrappable'
@@ -24,7 +24,7 @@ namespace blink {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#endif
-{{wrapper_type_info_const}}WrapperTypeInfo {{v8_class}}::wrapper_type_info = {
+{{wrapper_type_info_const}}WrapperTypeInfo {{snake_case_v8_class}}_wrapper_type_info = {
gin::kEmbedderBlink,
{{dom_template}},
{{install_conditional_features_func or 'nullptr'}},
@@ -42,7 +42,7 @@ namespace blink {
// This static member must be declared by DEFINE_WRAPPERTYPEINFO in {{cpp_class}}.h.
// For details, see the comment of DEFINE_WRAPPERTYPEINFO in
// platform/bindings/ScriptWrappable.h.
-const WrapperTypeInfo& {{cpp_class}}::wrapper_type_info_ = {{v8_class}}::wrapper_type_info;
+const WrapperTypeInfo& {{cpp_class}}::wrapper_type_info_ = {{snake_case_v8_class}}_wrapper_type_info;
{% endif %}
{% if active_scriptwrappable %}
@@ -292,7 +292,7 @@ void {{v8_class_or_partial}}::CrossOriginNamedGetter(v8::Local<v8::Name> name, c
BindingSecurity::FailedAccessCheckFor(
info.GetIsolate(),
- &{{v8_class}}::wrapper_type_info,
+ {{v8_class}}::GetWrapperTypeInfo(),
info.Holder());
{% endif %}
}
@@ -318,7 +318,7 @@ void {{v8_class_or_partial}}::CrossOriginNamedSetter(v8::Local<v8::Name> name, v
BindingSecurity::FailedAccessCheckFor(
info.GetIsolate(),
- &{{v8_class}}::wrapper_type_info,
+ {{v8_class}}::GetWrapperTypeInfo(),
info.Holder());
}
{% endif %}
@@ -428,7 +428,7 @@ static void Install{{v8_class}}Template(
'V8%s::DomTemplate(isolate, world)' % parent_interface
if parent_interface else
'v8::Local<v8::FunctionTemplate>()' %}
- V8DOMConfiguration::InitializeDOMInterfaceTemplate(isolate, interface_template, {{v8_class}}::wrapper_type_info.interface_name, {{parent_interface_template}}, {{v8_class}}::kInternalFieldCount);
+ V8DOMConfiguration::InitializeDOMInterfaceTemplate(isolate, interface_template, {{v8_class}}::GetWrapperTypeInfo()->interface_name, {{parent_interface_template}}, {{v8_class}}::kInternalFieldCount);
{% if constructors or has_custom_constructor or has_html_constructor %}
interface_template->SetCallHandler({{internal_namespace}}::ConstructorCallback);
interface_template->SetLength({{interface_length}});
@@ -497,7 +497,7 @@ static void Install{{v8_class}}Template(
nullptr,
{{cross_origin_named_enumerator}}),
v8::IndexedPropertyHandlerConfiguration({{cross_origin_indexed_getter}}),
- v8::External::New(isolate, const_cast<WrapperTypeInfo*>(&{{v8_class}}::wrapper_type_info)));
+ v8::External::New(isolate, const_cast<WrapperTypeInfo*>({{v8_class}}::GetWrapperTypeInfo())));
{% endif %}
{% if (indexed_property_getter or named_property_getter) and not is_partial %}
@@ -793,7 +793,7 @@ void {{v8_class_or_partial}}::InstallRuntimeEnabledFeaturesImpl(
#error "We don't expect a runtime enabled interface {{v8_class_or_partial}} to have InstallRuntimeEnabledFeatures()."
{% endif %}
- v8::Local<v8::FunctionTemplate> interface_template = {{v8_class}}::wrapper_type_info.DomTemplate(isolate, world);
+ v8::Local<v8::FunctionTemplate> interface_template = {{v8_class}}::GetWrapperTypeInfo()->DomTemplate(isolate, world);
v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
ALLOW_UNUSED_LOCAL(signature);
@@ -865,7 +865,7 @@ void {{v8_class_or_partial}}::Install{{feature.name}}(
v8::Local<v8::Function> interface) {
{% if feature.attributes or feature.methods %}
v8::Local<v8::FunctionTemplate> interface_template =
- {{v8_class}}::wrapper_type_info.DomTemplate(isolate, world);
+ {{v8_class}}::GetWrapperTypeInfo()->DomTemplate(isolate, world);
v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
ALLOW_UNUSED_LOCAL(signature);
{% endif %}
@@ -923,9 +923,9 @@ void {{v8_class_or_partial}}::Install{{feature.name}}(
ScriptState* script_state, v8::Local<v8::Object> instance) {
V8PerContextData* per_context_data = script_state->PerContextData();
v8::Local<v8::Object> prototype = per_context_data->PrototypeForType(
- &{{v8_class}}::wrapper_type_info);
+ {{v8_class}}::GetWrapperTypeInfo());
v8::Local<v8::Function> interface = per_context_data->ConstructorForType(
- &{{v8_class}}::wrapper_type_info);
+ {{v8_class}}::GetWrapperTypeInfo());
ALLOW_UNUSED_LOCAL(interface);
Install{{feature.name}}(script_state->GetIsolate(), script_state->World(), instance, prototype, interface);
}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
index f524655e74d..f2250dcd840 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
@@ -152,34 +152,8 @@ if (UNLIKELY(num_args_passed <= {{argument.index}})) {
}
{% endif %}
{% if argument.is_callback_interface %}
-{# FIXME: remove EventListener special case. crbug.com/630986 #}
-{% if argument.idl_type == 'EventListener' %}
-if (info[{{argument.index}}]->IsNullOrUndefined()) {
- // Just go through.
-} else if (info[{{argument.index}}]->IsObject()) {
- // TODO(crbug.com/886588): Remove the following special casing.
- if (info[{{argument.index}}].As<v8::Object>()->CreationContext().IsEmpty()) {
- {{define_exception_state}}
- exception_state.ThrowSecurityError("The callback provided as parameter {{argument.index + 1}} is a cross origin object.");
- return;
- }
-} else {
- {{throw_argument_error(method, argument, "The callback provided as parameter %(index)d is not an object.")}}
- return;
-}
-{% if method.name == 'removeEventListener' or method.name == 'removeListener' %}
-{{argument.local_cpp_variable}} = V8EventListenerHelper::GetEventListener(ScriptState::Current(info.GetIsolate()), info[{{argument.index}}], kListenerFindOnly);
-{% else %}{# method.name == 'AddEventListener' #}
-{{argument.local_cpp_variable}} = V8EventListenerHelper::GetEventListener(ScriptState::Current(info.GetIsolate()), info[{{argument.index}}], kListenerFindOrCreate);
-{% endif %}{# method.name #}
-{% else %}{# argument.idl_type == 'EventListener' #}
if (info[{{argument.index}}]->IsObject()) {
- {{argument.local_cpp_variable}} = V8{{argument.idl_type}}::CreateOrNull(info[{{argument.index}}].As<v8::Object>());
- if (!{{argument.local_cpp_variable}}) {
- {{define_exception_state}}
- exception_state.ThrowSecurityError("The callback provided as parameter {{argument.index + 1}} is a cross origin object.");
- return;
- }
+ {{argument.local_cpp_variable}} = V8{{argument.idl_type}}::Create(info[{{argument.index}}].As<v8::Object>());
{% if argument.is_nullable %}
} else if (info[{{argument.index}}]->IsNullOrUndefined()) {
{{argument.local_cpp_variable}} = nullptr;
@@ -191,7 +165,6 @@ if (info[{{argument.index}}]->IsObject()) {
{{throw_argument_error(method, argument, "The callback provided as parameter %(index)d is not an object.")}}
return;
}
-{% endif %}{# argument.idl_type == 'EventListener' #}
{% elif argument.is_callback_function %}
if (info[{{argument.index}}]->IsFunction()) {
{{v8_value_to_local_cpp_value(argument)}}
@@ -291,10 +264,6 @@ ExecutionContext* execution_context = ExecutionContext::ForCurrentRealm(info);
ExecutionContext* execution_context = ExecutionContext::ForRelevantRealm(info);
{% endif %}
{% endif %}
-{% if method.is_call_with_script_arguments %}
-{# [CallWith=ScriptArguments] #}
-ScriptArguments* scriptArguments(ScriptArguments::Create(script_state, info, {{method.number_of_arguments}}));
-{% endif %}
{% if method.is_call_with_document %}
{# [ConstructorCallWith=Document] #}
Document& document = *To<Document>(ToExecutionContext(
@@ -477,7 +446,11 @@ static void {{overloads.camel_case_name}}Method{{world_suffix}}(const v8::Functi
{% macro test_and_call_overloaded_method(test, method, overloads, world_suffix) %}
if ({{test}}) {
{% if method.measure_as and not overloads.measure_all_as %}
- UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.measure_as('Method')}});
+ ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate());
+ UseCounter::Count(execution_context_for_measurement, WebFeature::k{{method.measure_as('Method')}});
+ {% if method.high_entropy %}
+ Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{method.measure_as('Method')}});
+ {% endif %}
{% endif %}
{% if method.deprecate_as and not overloads.deprecate_all_as %}
Deprecation::CountDeprecation(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.deprecate_as}});
@@ -499,7 +472,11 @@ void {{v8_class_or_partial}}::{{method.camel_case_name}}MethodCallback{{world_su
{% endif %}
{% if not method.overloads %}{# Overloaded methods are measured in overload_resolution_method() #}
{% if method.measure_as %}
- UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.measure_as('Method')}});
+ ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate());
+ UseCounter::Count(execution_context_for_measurement, WebFeature::k{{method.measure_as('Method')}});
+ {% if method.high_entropy %}
+ Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{method.measure_as('Method')}});
+ {% endif %}
{% endif %}
{% if method.deprecate_as %}
Deprecation::CountDeprecation(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.deprecate_as}});
@@ -535,7 +512,7 @@ static void {{method.camel_case_name}}OriginSafeMethodGetter{{world_suffix}}(con
V8PerIsolateData* data = V8PerIsolateData::From(info.GetIsolate());
const DOMWrapperWorld& world = DOMWrapperWorld::World(info.GetIsolate()->GetCurrentContext());
v8::Local<v8::FunctionTemplate> interface_template =
- data->FindInterfaceTemplate(world, &{{v8_class}}::wrapper_type_info);
+ data->FindInterfaceTemplate(world, {{v8_class}}::GetWrapperTypeInfo());
v8::Local<v8::Signature> signature = v8::Signature::New(info.GetIsolate(), interface_template);
v8::Local<v8::FunctionTemplate> method_template =
@@ -618,7 +595,7 @@ static void {{name}}(const v8::FunctionCallbackInfo<v8::Value>& info) {
if constructor.is_named_constructor else
'') %}
v8::Local<v8::Object> wrapper = info.Holder();
-wrapper = impl->AssociateWithWrapper(info.GetIsolate(), &{{constructor_class}}::wrapper_type_info, wrapper);
+wrapper = impl->AssociateWithWrapper(info.GetIsolate(), {{constructor_class}}::GetWrapperTypeInfo(), wrapper);
V8SetReturnValue(info, wrapper);
{% endmacro %}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_core.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_core.cc.tmpl
index 8646c398535..cb37e805a9c 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_core.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_core.cc.tmpl
@@ -31,7 +31,7 @@ void InstallOriginTrialFeaturesForCore(
const DOMWrapperWorld& world = script_state->World();
// TODO(iclelland): Unify ContextFeatureSettings with the rest of the
// conditional features.
- if (wrapper_type_info == &V8Window::wrapper_type_info) {
+ if (wrapper_type_info == V8Window::GetWrapperTypeInfo()) {
auto* settings = ContextFeatureSettings::From(
execution_context,
ContextFeatureSettings::CreationMode::kDontCreateIfNotExists);
@@ -45,7 +45,7 @@ void InstallOriginTrialFeaturesForCore(
// TODO(iclelland): Extract this common code out of OriginTrialFeaturesForCore
// and OriginTrialFeaturesForModules into a block.
{% for interface in installers_by_interface %}
- if (wrapper_type_info == &{{interface.v8_class}}::wrapper_type_info) {
+ if (wrapper_type_info == {{interface.v8_class}}::GetWrapperTypeInfo()) {
{% if interface.is_global %}
v8::Local<v8::Object> instance_object =
script_state->GetContext()->Global();
@@ -81,7 +81,7 @@ void InstallPendingOriginTrialFeatureForCore(const String& feature,
v8::Local<v8::Object>(), v8::Local<v8::Function>());
{% else %}
if (context_data->GetExistingConstructorAndPrototypeForType(
- &{{installer.v8_class}}::wrapper_type_info, &prototype_object, &interface_object)) {
+ {{installer.v8_class}}::GetWrapperTypeInfo(), &prototype_object, &interface_object)) {
{{installer.v8_class_or_partial}}::{{installer.install_method}}(
isolate, world, v8::Local<v8::Object>(), prototype_object, interface_object);
}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_modules.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_modules.cc.tmpl
index 8ad8c353989..dc8b78a0100 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_modules.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/origin_trial_features_for_modules.cc.tmpl
@@ -34,7 +34,7 @@ void InstallOriginTrialFeaturesForModules(
// TODO(iclelland): Extract this common code out of OriginTrialFeaturesForCore
// and OriginTrialFeaturesForModules into a block.
{% for interface in installers_by_interface %}
- if (wrapper_type_info == &{{interface.v8_class}}::wrapper_type_info) {
+ if (wrapper_type_info == {{interface.v8_class}}::GetWrapperTypeInfo()) {
{% if interface.is_global %}
v8::Local<v8::Object> instance_object =
script_state->GetContext()->Global();
@@ -73,7 +73,7 @@ void InstallPendingOriginTrialFeatureForModules(
v8::Local<v8::Object>(), v8::Local<v8::Function>());
{% else %}
if (context_data->GetExistingConstructorAndPrototypeForType(
- &{{installer.v8_class}}::wrapper_type_info, &prototype_object, &interface_object)) {
+ {{installer.v8_class}}::GetWrapperTypeInfo(), &prototype_object, &interface_object)) {
{{installer.v8_class_or_partial}}::{{installer.install_method}}(
isolate, world, v8::Local<v8::Object>(), prototype_object, interface_object);
}
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_primitive_value_unit_trie.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_primitive_value_unit_trie.py
index 316284c0cbf..318d1136300 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_primitive_value_unit_trie.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_primitive_value_unit_trie.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
import json5_generator
import trie_builder
import template_expander
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
index 5cb3e205fff..665487dbd62 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
@@ -1,9 +1,5 @@
#!/usr/bin/env python
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
from core.css import css_properties
import gperf
import json5_generator
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_tokenizer_codepoints.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_tokenizer_codepoints.py
index c48d23ae703..a51c5917d33 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_tokenizer_codepoints.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_tokenizer_codepoints.py
@@ -6,7 +6,6 @@
import os
import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
import in_generator
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_id_mappings.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_id_mappings.py
index b0cdb892012..f929b7869e4 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_id_mappings.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_id_mappings.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
from blinkbuild.name_style_converter import NameStyleConverter
import json5_generator
import template_expander
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_keywords.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_keywords.py
index 7c08560cfcf..3110d0f597b 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_keywords.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_value_keywords.py
@@ -1,10 +1,5 @@
#!/usr/bin/env python
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
-import os.path
import subprocess
from name_utilities import enum_for_css_keyword
import json5_generator
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_cssom_types.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_cssom_types.py
index 6c44db014ce..93e0afe11ac 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_cssom_types.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_cssom_types.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
from core.css import css_properties
import json5_generator
from name_utilities import enum_for_css_keyword
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_feature_names.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_feature_names.py
index 5f1ad9cbf88..e58585b91b5 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_feature_names.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_feature_names.py
@@ -4,10 +4,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
import json5_generator
import make_names
import media_feature_symbol
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_features.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_features.py
index fcf89d7d4f2..8d3d09c0d25 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_features.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_media_features.py
@@ -4,10 +4,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
from blinkbuild.name_style_converter import NameStyleConverter
import media_feature_symbol
import json5_generator
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
index 060d2f32a5a..a166b36ae3e 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
@@ -27,10 +27,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
from core.css import css_properties
from collections import defaultdict
import json5_generator
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/parser/make_atrule_names.py b/chromium/third_party/blink/renderer/build/scripts/core/css/parser/make_atrule_names.py
index 2715f4dcf18..2a7d636556e 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/parser/make_atrule_names.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/parser/make_atrule_names.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../../..'))
-
import gperf
import json5_generator
import template_expander
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_base.py b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_base.py
index 8399000b7f2..637bc3a88fd 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_base.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_base.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../../..'))
-
import json5_generator
import template_expander
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py
index 6f8788f3404..3899bd626a1 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py
@@ -3,9 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../../..'))
import json5_generator
import template_expander
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property.h.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property.h.tmpl
index becfce1a85b..aeb11ecad88 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property.h.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property.h.tmpl
@@ -9,9 +9,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTY_H_
+#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/core/css/properties/css_unresolved_property.h"
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -42,6 +45,9 @@ class CSSProperty : public CSSUnresolvedProperty {
NOTREACHED();
return CSSPropertyInvalid;
}
+ virtual CSSPropertyName GetCSSPropertyName() const {
+ return CSSPropertyName(PropertyID());
+ }
bool IDEquals(CSSPropertyID id) const { return PropertyID() == id; }
bool IsResolvedProperty() const override { return true; }
virtual bool IsInterpolable() const { return false; }
@@ -96,6 +102,19 @@ class CSSProperty : public CSSUnresolvedProperty {
const LayoutObject*,
Node*,
bool allow_visited_style) const;
+ CORE_EXPORT virtual std::unique_ptr<CrossThreadStyleValue>
+ CrossThreadStyleValueFromComputedStyle(const ComputedStyle& computed_style,
+ const LayoutObject* layout_object,
+ Node* node,
+ bool allow_visited_style) const {
+ const CSSValue* css_value = CSSValueFromComputedStyle(
+ computed_style, layout_object, node, allow_visited_style);
+ if (!css_value)
+ return std::make_unique<CrossThreadUnsupportedValue>("");
+ // Make an isolated copy to ensure that it is safe to pass cross thread.
+ return std::make_unique<CrossThreadUnsupportedValue>(
+ css_value->CssText().IsolatedCopy());
+ }
virtual const CSSProperty& ResolveDirectionAwareProperty(
TextDirection,
WritingMode) const {
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/cssom_types.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/cssom_types.cc.tmpl
index 4b7dc54bb91..7bea2c9c13f 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/cssom_types.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/cssom_types.cc.tmpl
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/css/cssom/cssom_types.h"
+#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h"
#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/core/css/cssom/css_style_value.h"
@@ -99,8 +100,8 @@ bool CSSOMTypes::PropertyCanTake(CSSPropertyID id,
if (id == CSSPropertyVariable && registration) {
if (value.GetType() == CSSStyleValue::kUnknownType) {
- return ToCSSUnsupportedStyleValue(value).GetCustomPropertyName() ==
- custom_property_name;
+ return ToCSSUnsupportedStyleValue(value).IsValidFor(
+ CSSPropertyName(custom_property_name));
}
match = registration->Syntax().Match(value);
return match != nullptr;
@@ -111,7 +112,7 @@ bool CSSOMTypes::PropertyCanTake(CSSPropertyID id,
id, ToCSSKeywordValue(value));
}
if (value.GetType() == CSSStyleValue::kUnknownType) {
- return ToCSSUnsupportedStyleValue(value).GetProperty() == id;
+ return ToCSSUnsupportedStyleValue(value).IsValidFor(CSSPropertyName(id));
}
if (value.GetType() == CSSStyleValue::kUnparsedType) {
return true;
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.cc.tmpl
index f17e0f58f03..6456a79e430 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/style_property_shorthand.cc.tmpl
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/core/style_property_shorthand.h"
+#include "base/stl_util.h" // for base::size()
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -41,7 +42,7 @@ const StylePropertyShorthand& {{property.name.to_lower_camel_case()}}Shorthand()
static StylePropertyShorthand {{property.name.to_lower_camel_case()}}Longhands(
{{property.property_id}},
{{property.name.to_lower_camel_case()}}Properties,
- arraysize({{property.name.to_lower_camel_case()}}Properties));
+ base::size({{property.name.to_lower_camel_case()}}Properties));
return {{property.name.to_lower_camel_case()}}Longhands;
}
{% endfor %}
@@ -53,7 +54,7 @@ const StylePropertyShorthand& offsetShorthandWithoutPositionAnchor() {
&GetCSSPropertyOffsetDistance(),
&GetCSSPropertyOffsetRotate(),
};
- DEFINE_STATIC_LOCAL(StylePropertyShorthand, offsetLonghands, (CSSPropertyOffset, offsetProperties, arraysize(offsetProperties)));
+ DEFINE_STATIC_LOCAL(StylePropertyShorthand, offsetLonghands, (CSSPropertyOffset, offsetProperties, base::size(offsetProperties)));
return offsetLonghands;
}
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py b/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
index 21dbfa4cae8..1f248f956a2 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
import math
import json5_generator
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_initial_values.py b/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_initial_values.py
index c2627b20542..c596a09e828 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_initial_values.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_initial_values.py
@@ -3,10 +3,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import os
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
import json5_generator
import template_expander
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
index 5697ad5a947..75971286372 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
@@ -11,20 +11,20 @@
namespace blink {
-struct SameSizeAsComputedStyleBase {
+struct SameSizeVerifierForComputedStyleBase {
{% if computed_style.subgroups is defined %}
- void* dataRefs[{{computed_style.subgroups|length}}];
+ void* data_refs[{{computed_style.subgroups|length}}];
{% endif %}
{% for field in computed_style.fields|rejectattr("is_bit_field") %}
{{field.type_name}} {{field.name}};
{% endfor %}
- unsigned m_bit_fields[{{computed_style.num_32_bit_words_for_bit_fields}}];
+ unsigned bit_fields[{{computed_style.num_32_bit_words_for_bit_fields}}];
};
// If this fails, the packing algorithm in make_computed_style_base.py has
// failed to produce the optimal packed size. To fix, update the algorithm to
// ensure that the buckets are placed so that each takes up at most 1 word.
-ASSERT_SIZE(ComputedStyleBase, SameSizeAsComputedStyleBase);
+ASSERT_SIZE(ComputedStyleBase, SameSizeVerifierForComputedStyleBase);
// Constructor and destructor are protected so that only the parent class ComputedStyle
// can instantiate this class.
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base_constants.h.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base_constants.h.tmpl
index aee3668af2f..9ca650e2ec4 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base_constants.h.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base_constants.h.tmpl
@@ -14,7 +14,7 @@ namespace blink {
{% for enum in enums %}
enum class {{enum.type_name}} : unsigned {
{% for value in enum.values %}
- {{value}}{{print_if(enum.is_set, " = " ~ (0 if loop.first else 2**loop.index0))}},
+ {{value}}{{print_if(enum.is_set, " = " ~ (0 if loop.first else 2**(loop.index0 - 1)))}},
{% endfor %}
};
diff --git a/chromium/third_party/blink/renderer/build/scripts/gperf.py b/chromium/third_party/blink/renderer/build/scripts/gperf.py
index df7b713a8a2..a917ceb0861 100644
--- a/chromium/third_party/blink/renderer/build/scripts/gperf.py
+++ b/chromium/third_party/blink/renderer/build/scripts/gperf.py
@@ -21,9 +21,10 @@ def generate_gperf(gperf_path, gperf_input, gperf_args):
# the normal solution of shell=True (as this has to run on many
# platforms), so instead we catch the error and raise a
# CalledProcessError like subprocess would do when shell=True is set.
+ cmd = [gperf_path] + gperf_args
try:
gperf = subprocess.Popen(
- [gperf_path] + gperf_args,
+ cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
universal_newlines=True)
@@ -42,7 +43,7 @@ def generate_gperf(gperf_path, gperf_input, gperf_args):
return '// Generated by %s\n' % script + gperf_output
except OSError:
raise subprocess.CalledProcessError(
- 127, gperf_args, output='Command not found.')
+ 127, cmd, output='Command not found.')
def use_jinja_gperf_template(template_path, gperf_extra_args=None):
diff --git a/chromium/third_party/blink/renderer/build/scripts/make_element_type_helpers.py b/chromium/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
index 210e5c26fd8..057a1be1fe8 100755
--- a/chromium/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
+++ b/chromium/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
@@ -10,6 +10,7 @@ import hasher
import json5_generator
import template_expander
+from blinkbuild.name_style_converter import NameStyleConverter
def _symbol(tag):
return 'k' + tag['name'].to_upper_camel_case()
@@ -55,8 +56,8 @@ class MakeElementTypeHelpersWriter(json5_generator.Writer):
(basename + '.cc'): self.generate_helper_implementation,
}
- base_element_header = 'third_party/blink/renderer/core/' \
- '{0}/{0}_element.h'.format(self.namespace.lower())
+ base_element_header = 'third_party/blink/renderer/core/{}/{}_element.h'.format(
+ self.namespace.lower(), NameStyleConverter(self.namespace).to_snake_case())
self._template_context = {
'base_element_header': base_element_header,
'cpp_namespace': self.namespace.lower() + '_names',
diff --git a/chromium/third_party/blink/renderer/build/scripts/run_with_pythonpath.py b/chromium/third_party/blink/renderer/build/scripts/run_with_pythonpath.py
new file mode 100755
index 00000000000..9da708d0eeb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/build/scripts/run_with_pythonpath.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# 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.
+
+import os
+import subprocess
+import sys
+
+
+# python run_with_pythonpath.py -I path1 ... -I pathN foo/bar/baz.py args...
+# ==> Run "python foo/bar/baz.py args..." with PYTHONPATH=path1:..:pathN
+def main():
+ python_paths = []
+ args = sys.argv[1:]
+ while len(args) >= 2 and args[0] == '-I':
+ python_paths.append(args[1])
+ args = args[2:]
+
+ env = os.environ.copy()
+ if len(python_paths) > 0:
+ existing_pp = (os.pathsep + env['PYTHONPATH']) if 'PYTHONPATH' in env else ''
+ env['PYTHONPATH'] = os.pathsep.join(python_paths) + existing_pp
+ sys.exit(subprocess.call([sys.executable] + args, env=env))
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/blink/renderer/build/scripts/scripts.gni b/chromium/third_party/blink/renderer/build/scripts/scripts.gni
index eac21781f4e..f5b360f7084 100644
--- a/chromium/third_party/blink/renderer/build/scripts/scripts.gni
+++ b/chromium/third_party/blink/renderer/build/scripts/scripts.gni
@@ -82,6 +82,34 @@ make_core_generated_deps = [
"//third_party/blink/renderer/core:core_event_interfaces",
]
+# A wrapper for python scripts. This adds the following paths to PYTHONPATH,
+# then run invoker.script.
+# - //third_party/blink/renderer/build/scripts
+# - //third_party
+template("blink_python_runner") {
+ action(target_name) {
+ script = "$_scripts_dir/run_with_pythonpath.py"
+ inputs = [
+ invoker.script,
+ ]
+ if (defined(invoker.inputs)) {
+ inputs += invoker.inputs
+ }
+ outputs = invoker.outputs
+ args = [
+ "-I",
+ rebase_path(_scripts_dir, root_build_dir),
+ "-I",
+ rebase_path("//third_party", root_build_dir),
+ rebase_path(invoker.script, root_build_dir),
+ ] + invoker.args
+ if (defined(invoker.deps)) {
+ deps = invoker.deps
+ }
+ forward_variables_from(invoker, [ "visibility" ])
+ }
+}
+
# TODO(crbug.com/732657): Remove this once everything that uses this switches over to
# the 'code_generator' template instead.
# Template to run most of scripts that process "*.json5" files.
@@ -97,7 +125,7 @@ make_core_generated_deps = [
# deps [optional]:
# Depenendencies. If unspecified defaults to make_core_generated_deps.
template("process_json5_files") {
- action(target_name) {
+ blink_python_runner(target_name) {
script = invoker.script
inputs = invoker.in_files
@@ -146,7 +174,7 @@ template("process_json5_files") {
# deps [optional]:
# Depenendencies. If unspecified defaults to make_core_generated_deps.
template("code_generator") {
- action(target_name) {
+ blink_python_runner(target_name) {
script = invoker.script
inputs = invoker.json_inputs + invoker.templates + scripts_for_json5_files
if (defined(invoker.other_inputs)) {
diff --git a/chromium/third_party/blink/renderer/build/scripts/template_expander.py b/chromium/third_party/blink/renderer/build/scripts/template_expander.py
index 339e2ab37cb..2cf3ad6a098 100644
--- a/chromium/third_party/blink/renderer/build/scripts/template_expander.py
+++ b/chromium/third_party/blink/renderer/build/scripts/template_expander.py
@@ -29,10 +29,6 @@
import os
import sys
-_current_dir = os.path.dirname(os.path.realpath(__file__))
-# jinja2 is in chromium's third_party directory
-# Insert at front to override system libraries, and after path[0] == script dir
-sys.path.insert(1, os.path.join(_current_dir, *([os.pardir] * 4)))
import jinja2
@@ -43,8 +39,9 @@ def apply_template(template_path, params, filters=None, tests=None, template_cac
template = template_cache.get(template_path, None)
if template is None:
+ current_dir = os.path.dirname(os.path.realpath(__file__))
jinja_env = jinja2.Environment(
- loader=jinja2.FileSystemLoader(_current_dir),
+ loader=jinja2.FileSystemLoader(current_dir),
keep_trailing_newline=True, # newline-terminate generated files
lstrip_blocks=True, # so can indent control flow tags
trim_blocks=True) # so don't need {%- -%} everywhere
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
index 96ede7f9df0..46dc718a4c6 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/{{namespace|lower}}_element_factory.h"
+#include "base/stl_util.h" // for base::size()
#include "third_party/blink/renderer/core/{{namespace|lower}}_names.h"
{% for header in tags|groupby('interface_header') %}
#include "{{header[0]}}"
@@ -56,7 +57,7 @@ static void create{{namespace}}FunctionMap() {
{ {{cpp_namespace}}::{{tag|symbol}}Tag, {{namespace}}{{tag|symbol}}Constructor },
{% endfor %}
};
- for (size_t i = 0; i < arraysize(data); i++)
+ for (size_t i = 0; i < base::size(data); i++)
g_{{namespace}}_constructors->Set(data[i].tag.LocalName(), data[i].func);
}
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/internal_runtime_flags.h.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/internal_runtime_flags.h.tmpl
index bcc131bfc92..c3d92f8928f 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/internal_runtime_flags.h.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/internal_runtime_flags.h.tmpl
@@ -23,7 +23,7 @@ class InternalRuntimeFlags : public ScriptWrappable {
InternalRuntimeFlags() {}
- // These are reset between layout tests from Internals::resetToConsistentState
+ // These are reset between web tests from Internals::resetToConsistentState
// using RuntimeEnabledFeatures::Backup.
{% for feature in standard_features if feature.settable_from_internals %}
void set{{feature.name}}Enabled(bool isEnabled) {
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/make_names.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/make_names.cc.tmpl
index 9d0a3104de7..acd9e0f500f 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/make_names.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/make_names.cc.tmpl
@@ -5,6 +5,7 @@
#include "{{this_include_path}}"
+#include "base/stl_util.h" // for base::size()
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
@@ -33,7 +34,7 @@ void Init{{suffix}}() {
{% endfor %}
};
- for (size_t i = 0; i < arraysize(kNames); ++i) {
+ for (size_t i = 0; i < base::size(kNames); ++i) {
StringImpl* impl = StringImpl::CreateStatic(kNames[i].name, kNames[i].length, kNames[i].hash);
void* address = reinterpret_cast<AtomicString*>(&{{suffix|lower}}names_storage) + i;
new (address) AtomicString(impl);
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/make_qualified_names.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/make_qualified_names.cc.tmpl
index eacbbd47517..6fbf1ae5d5a 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/make_qualified_names.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/make_qualified_names.cc.tmpl
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/stl_util.h" // for base::size()
#include "third_party/blink/renderer/platform/wtf/static_constructors.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -76,7 +77,7 @@ void Init() {
size_t tag_i = 0;
{% endif %}
size_t attr_i = 0;
- for (size_t i = 0; i < arraysize(kNames); ++i) {
+ for (size_t i = 0; i < base::size(kNames); ++i) {
StringImpl* impl = StringImpl::CreateStatic(kNames[i].name, kNames[i].length, kNames[i].hash);
{% if tags %}
if (kNames[i].is_tag) {
diff --git a/chromium/third_party/blink/renderer/controller/BUILD.gn b/chromium/third_party/blink/renderer/controller/BUILD.gn
index c9f9a18f118..7668f372520 100644
--- a/chromium/third_party/blink/renderer/controller/BUILD.gn
+++ b/chromium/third_party/blink/renderer/controller/BUILD.gn
@@ -43,6 +43,10 @@ component("controller") {
"controller_export.h",
"dev_tools_frontend_impl.cc",
"dev_tools_frontend_impl.h",
+ "memory_usage_monitor.cc",
+ "memory_usage_monitor.h",
+ "memory_usage_monitor_android.cc",
+ "memory_usage_monitor_android.h",
]
if (is_android) {
@@ -134,7 +138,11 @@ jumbo_source_set("webkit_unit_tests_sources") {
]
sources += bindings_unittest_files
if (is_android) {
- sources += [ "oom_intervention_impl_test.cc" ]
+ sources += [
+ "memory_usage_monitor_android_test.cc",
+ "memory_usage_monitor_test.cc",
+ "oom_intervention_impl_test.cc",
+ ]
}
deps = [
diff --git a/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.cc b/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.cc
index c17f99b6e56..33792cd6a13 100644
--- a/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.cc
+++ b/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.cc
@@ -23,13 +23,15 @@ BloatedRendererDetector::OnNearV8HeapLimitOnMainThread() {
NearV8HeapLimitHandling
BloatedRendererDetector::OnNearV8HeapLimitOnMainThreadImpl() {
+ WTF::TimeTicks now = WTF::CurrentTimeTicks();
if (!RuntimeEnabledFeatures::
BloatedRendererDetectionSkipUptimeCheckEnabled()) {
- WTF::TimeDelta uptime = (WTF::CurrentTimeTicks() - startup_time_);
- if (uptime.InMinutes() < kMinimumUptimeInMinutes) {
- return NearV8HeapLimitHandling::kIgnoredDueToSmallUptime;
+ WTF::TimeDelta delta = now - last_detection_time_;
+ if (delta.InMinutes() < kMinimumCooldownInMinutes) {
+ return NearV8HeapLimitHandling::kIgnoredDueToCooldownTime;
}
}
+ last_detection_time_ = now;
RendererResourceCoordinator::Get().OnRendererIsBloated();
return NearV8HeapLimitHandling::kForwardedToBrowser;
}
diff --git a/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.h b/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.h
index aab1f16f590..c2e4faede40 100644
--- a/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.h
+++ b/chromium/third_party/blink/renderer/controller/bloated_renderer_detector.h
@@ -29,18 +29,20 @@ class CONTROLLER_EXPORT BloatedRendererDetector {
private:
friend class BloatedRendererDetectorTest;
+ FRIEND_TEST_ALL_PREFIXES(BloatedRendererDetectorTest, CooldownTime);
FRIEND_TEST_ALL_PREFIXES(BloatedRendererDetectorTest, ForwardToBrowser);
- FRIEND_TEST_ALL_PREFIXES(BloatedRendererDetectorTest, SmallUptime);
+ FRIEND_TEST_ALL_PREFIXES(BloatedRendererDetectorTest, MultipleDetections);
- // The minimum uptime after which bloated renderer detection starts.
- static const int kMinimumUptimeInMinutes = 10;
+ // The time which should pass between 2 successive detections of bloated
+ // renderer.
+ static const int kMinimumCooldownInMinutes = 10;
- explicit BloatedRendererDetector(WTF::TimeTicks startup_time)
- : startup_time_(startup_time) {}
+ explicit BloatedRendererDetector(WTF::TimeTicks time)
+ : last_detection_time_(time) {}
NearV8HeapLimitHandling OnNearV8HeapLimitOnMainThreadImpl();
- const WTF::TimeTicks startup_time_;
+ WTF::TimeTicks last_detection_time_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/bloated_renderer_detector_test.cc b/chromium/third_party/blink/renderer/controller/bloated_renderer_detector_test.cc
index 7172996d91a..72c7734f9d5 100644
--- a/chromium/third_party/blink/renderer/controller/bloated_renderer_detector_test.cc
+++ b/chromium/third_party/blink/renderer/controller/bloated_renderer_detector_test.cc
@@ -11,30 +11,43 @@ namespace blink {
class BloatedRendererDetectorTest : public testing::Test {
public:
- static TimeDelta GetMockLargeUptime() {
+ static TimeDelta GetMockAfterCooldown() {
return TimeDelta::FromMinutes(
- BloatedRendererDetector::kMinimumUptimeInMinutes + 1);
+ BloatedRendererDetector::kMinimumCooldownInMinutes + 1);
}
- static TimeDelta GetMockSmallUptime() {
+ static TimeDelta GetMockBeforeCooldown() {
return TimeDelta::FromMinutes(
- BloatedRendererDetector::kMinimumUptimeInMinutes - 1);
+ BloatedRendererDetector::kMinimumCooldownInMinutes - 1);
}
};
TEST_F(BloatedRendererDetectorTest, ForwardToBrowser) {
WTF::ScopedMockClock clock;
- clock.Advance(GetMockLargeUptime());
+ clock.Advance(GetMockAfterCooldown());
BloatedRendererDetector detector(TimeTicks{});
EXPECT_EQ(NearV8HeapLimitHandling::kForwardedToBrowser,
detector.OnNearV8HeapLimitOnMainThreadImpl());
}
-TEST_F(BloatedRendererDetectorTest, SmallUptime) {
+TEST_F(BloatedRendererDetectorTest, CooldownTime) {
WTF::ScopedMockClock clock;
- clock.Advance(GetMockSmallUptime());
+ clock.Advance(GetMockBeforeCooldown());
BloatedRendererDetector detector(TimeTicks{});
- EXPECT_EQ(NearV8HeapLimitHandling::kIgnoredDueToSmallUptime,
+ EXPECT_EQ(NearV8HeapLimitHandling::kIgnoredDueToCooldownTime,
+ detector.OnNearV8HeapLimitOnMainThreadImpl());
+}
+
+TEST_F(BloatedRendererDetectorTest, MultipleDetections) {
+ WTF::ScopedMockClock clock;
+ clock.Advance(GetMockAfterCooldown());
+ BloatedRendererDetector detector(TimeTicks{});
+ EXPECT_EQ(NearV8HeapLimitHandling::kForwardedToBrowser,
+ detector.OnNearV8HeapLimitOnMainThreadImpl());
+ EXPECT_EQ(NearV8HeapLimitHandling::kIgnoredDueToCooldownTime,
+ detector.OnNearV8HeapLimitOnMainThreadImpl());
+ clock.Advance(GetMockAfterCooldown());
+ EXPECT_EQ(NearV8HeapLimitHandling::kForwardedToBrowser,
detector.OnNearV8HeapLimitOnMainThreadImpl());
}
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc b/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc
new file mode 100644
index 00000000000..16e9978ec6b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc
@@ -0,0 +1,73 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/controller/memory_usage_monitor.h"
+
+#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
+
+namespace blink {
+
+namespace {
+constexpr TimeDelta kPingInterval = TimeDelta::FromSeconds(1);
+}
+
+MemoryUsageMonitor::MemoryUsageMonitor()
+ : timer_(Thread::MainThread()->GetTaskRunner(),
+ this,
+ &MemoryUsageMonitor::TimerFired) {}
+
+void MemoryUsageMonitor::AddObserver(Observer* observer) {
+ StartMonitoringIfNeeded();
+ observers_.AddObserver(observer);
+}
+
+void MemoryUsageMonitor::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void MemoryUsageMonitor::StartMonitoringIfNeeded() {
+ if (timer_.IsActive())
+ return;
+ timer_.StartRepeating(kPingInterval, FROM_HERE);
+}
+
+void MemoryUsageMonitor::StopMonitoring() {
+ timer_.Stop();
+}
+
+MemoryUsage MemoryUsageMonitor::GetCurrentMemoryUsage() {
+ MemoryUsage usage;
+ GetV8MemoryUsage(usage);
+ GetBlinkMemoryUsage(usage);
+ GetProcessMemoryUsage(usage);
+ return usage;
+}
+
+void MemoryUsageMonitor::GetV8MemoryUsage(MemoryUsage& usage) {
+ v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
+ DCHECK(isolate);
+ v8::HeapStatistics heap_statistics;
+ isolate->GetHeapStatistics(&heap_statistics);
+ // TODO: Add memory usage for worker threads.
+ usage.v8_bytes =
+ heap_statistics.total_heap_size() + heap_statistics.malloced_memory();
+}
+
+void MemoryUsageMonitor::GetBlinkMemoryUsage(MemoryUsage& usage) {
+ usage.blink_gc_bytes = ProcessHeap::TotalAllocatedObjectSize() +
+ ProcessHeap::TotalMarkedObjectSize();
+ usage.partition_alloc_bytes = WTF::Partitions::TotalSizeOfCommittedPages();
+}
+
+void MemoryUsageMonitor::TimerFired(TimerBase*) {
+ MemoryUsage usage = GetCurrentMemoryUsage();
+ for (auto& observer : observers_)
+ observer.OnMemoryPing(usage);
+ if (!observers_.might_have_observers())
+ StopMonitoring();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor.h b/chromium/third_party/blink/renderer/controller/memory_usage_monitor.h
new file mode 100644
index 00000000000..86e87069298
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor.h
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CONTROLLER_MEMORY_USAGE_MONITOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CONTROLLER_MEMORY_USAGE_MONITOR_H_
+
+#include "base/observer_list.h"
+#include "third_party/blink/renderer/controller/controller_export.h"
+#include "third_party/blink/renderer/platform/timer.h"
+
+namespace blink {
+
+// nan means data not available.
+struct MemoryUsage {
+ double v8_bytes = std::numeric_limits<double>::quiet_NaN();
+ double partition_alloc_bytes = std::numeric_limits<double>::quiet_NaN();
+ double blink_gc_bytes = std::numeric_limits<double>::quiet_NaN();
+ double private_footprint_bytes = std::numeric_limits<double>::quiet_NaN();
+ double swap_bytes = std::numeric_limits<double>::quiet_NaN();
+ double vm_size_bytes = std::numeric_limits<double>::quiet_NaN();
+};
+
+// Periodically checks the memory usage and notifies its observers. Monitoring
+// automatically starts/stops depending on whether an observer exists.
+class CONTROLLER_EXPORT MemoryUsageMonitor {
+ public:
+ static MemoryUsageMonitor& Instance();
+
+ class Observer : public base::CheckedObserver {
+ public:
+ virtual void OnMemoryPing(MemoryUsage) = 0;
+ };
+
+ MemoryUsageMonitor();
+ virtual ~MemoryUsageMonitor() = default;
+
+ // Returns the current memory usage.
+ MemoryUsage GetCurrentMemoryUsage();
+
+ // Ensures that an observer is only added once.
+ void AddObserver(Observer*);
+ // Observers must be removed before they are destroyed.
+ void RemoveObserver(Observer*);
+
+ bool TimerIsActive() const { return timer_.IsActive(); }
+
+ protected:
+ // Adds V8 related memory usage data to the given struct.
+ void GetV8MemoryUsage(MemoryUsage&);
+ // Adds Blink related memory usage data to the given struct.
+ void GetBlinkMemoryUsage(MemoryUsage&);
+ // Adds process related memory usage data to the given struct.
+ virtual void GetProcessMemoryUsage(MemoryUsage&) {}
+
+ private:
+ virtual void StartMonitoringIfNeeded();
+ virtual void StopMonitoring();
+
+ void TimerFired(TimerBase*);
+
+ TaskRunnerTimer<MemoryUsageMonitor> timer_;
+ base::ObserverList<Observer> observers_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CONTROLLER_MEMORY_USAGE_MONITOR_H_
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.cc b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.cc
new file mode 100644
index 00000000000..40fa749503c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.cc
@@ -0,0 +1,106 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/controller/memory_usage_monitor_android.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "third_party/blink/public/platform/platform.h"
+
+namespace blink {
+
+namespace {
+
+constexpr uint32_t kMaxLineSize = 4096;
+bool ReadFileContents(int fd, base::span<char> contents) {
+ lseek(fd, 0, SEEK_SET);
+ int res = read(fd, contents.data(), contents.size() - 1);
+ if (res <= 0)
+ return false;
+ contents.data()[res] = '\0';
+ return true;
+}
+
+// Since the measurement is done every second in background, optimizations are
+// in place to get just the metrics we need from the proc files. So, this
+// calculation exists here instead of using the cross-process memory-infra code.
+bool CalculateProcessMemoryFootprint(int statm_fd,
+ int status_fd,
+ uint64_t* private_footprint,
+ uint64_t* swap_footprint,
+ uint64_t* vm_size) {
+ // Get total resident and shared sizes from statm file.
+ static size_t page_size = getpagesize();
+ uint64_t resident_pages;
+ uint64_t shared_pages;
+ uint64_t vm_size_pages;
+ char line[kMaxLineSize];
+ if (!ReadFileContents(statm_fd, line))
+ return false;
+ int num_scanned = sscanf(line, "%" SCNu64 " %" SCNu64 " %" SCNu64,
+ &vm_size_pages, &resident_pages, &shared_pages);
+ if (num_scanned != 3)
+ return false;
+
+ // Get swap size from status file. The format is: VmSwap : 10 kB.
+ if (!ReadFileContents(status_fd, line))
+ return false;
+ char* swap_line = strstr(line, "VmSwap");
+ if (!swap_line)
+ return false;
+ num_scanned = sscanf(swap_line, "VmSwap: %" SCNu64 " kB", swap_footprint);
+ if (num_scanned != 1)
+ return false;
+
+ *swap_footprint *= 1024;
+ *private_footprint =
+ (resident_pages - shared_pages) * page_size + *swap_footprint;
+ *vm_size = vm_size_pages * page_size;
+ return true;
+}
+
+} // namespace
+
+// static
+MemoryUsageMonitor& MemoryUsageMonitor::Instance() {
+ DEFINE_STATIC_LOCAL(MemoryUsageMonitorAndroid, monitor, ());
+ return monitor;
+}
+
+void MemoryUsageMonitorAndroid::GetProcessMemoryUsage(MemoryUsage& usage) {
+ ResetFileDescriptors();
+
+ if (!statm_fd_.is_valid() || !status_fd_.is_valid())
+ return;
+ uint64_t private_footprint, swap, vm_size;
+ if (CalculateProcessMemoryFootprint(statm_fd_.get(), status_fd_.get(),
+ &private_footprint, &swap, &vm_size)) {
+ usage.private_footprint_bytes = static_cast<double>(private_footprint);
+ usage.swap_bytes = static_cast<double>(swap);
+ usage.vm_size_bytes = static_cast<double>(vm_size);
+ }
+}
+
+void MemoryUsageMonitorAndroid::ResetFileDescriptors() {
+ if (file_descriptors_reset_)
+ return;
+ file_descriptors_reset_ = true;
+ // See https://goo.gl/KjWnZP For details about why we read these files from
+ // sandboxed renderer. Keep these files open when detection is enabled.
+ if (!statm_fd_.is_valid())
+ statm_fd_.reset(open("/proc/self/statm", O_RDONLY));
+ if (!status_fd_.is_valid())
+ status_fd_.reset(open("/proc/self/status", O_RDONLY));
+}
+
+void MemoryUsageMonitorAndroid::ReplaceFileDescriptorsForTesting(
+ base::File statm_file,
+ base::File status_file) {
+ statm_fd_.reset(statm_file.TakePlatformFile());
+ status_fd_.reset(status_file.TakePlatformFile());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.h b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.h
new file mode 100644
index 00000000000..0693731f555
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android.h
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CONTROLLER_MEMORY_USAGE_MONITOR_ANDROID_H_
+#define THIRD_PARTY_BLINK_RENDERER_CONTROLLER_MEMORY_USAGE_MONITOR_ANDROID_H_
+
+#include "base/files/file.h"
+#include "base/files/scoped_file.h"
+#include "third_party/blink/renderer/controller/controller_export.h"
+#include "third_party/blink/renderer/controller/memory_usage_monitor.h"
+
+namespace blink {
+
+class CONTROLLER_EXPORT MemoryUsageMonitorAndroid : public MemoryUsageMonitor {
+ public:
+ MemoryUsageMonitorAndroid() = default;
+
+ void ReplaceFileDescriptorsForTesting(base::File statm_file,
+ base::File status_file);
+
+ private:
+ void ResetFileDescriptors();
+ void GetProcessMemoryUsage(MemoryUsage&) override;
+
+ bool file_descriptors_reset_ = false;
+ // The file descriptor to current process proc files. The files are kept open
+ // when detection is on to reduce measurement overhead.
+ base::ScopedFD statm_fd_;
+ base::ScopedFD status_fd_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CONTROLLER_MEMORY_USAGE_MONITOR_ANDROID_H_
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android_test.cc b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android_test.cc
new file mode 100644
index 00000000000..403c5bbb1ec
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_android_test.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/controller/memory_usage_monitor_android.h"
+
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(MemoryUsageMonitorAndroidTest, CalculateProcessFootprint) {
+ MemoryUsageMonitorAndroid monitor;
+
+ const char kStatusFile[] =
+ "First: 1\n Second: 2 kB\nVmSwap: 10 kB \n Third: 10 kB\n Last: 8";
+ const char kStatmFile[] = "100 40 25 0 0";
+ uint64_t expected_swap_kb = 10;
+ uint64_t expected_private_footprint_kb =
+ (40 - 25) * getpagesize() / 1024 + expected_swap_kb;
+ uint64_t expected_vm_size_kb = 100 * getpagesize() / 1024;
+
+ base::FilePath statm_path;
+ EXPECT_TRUE(base::CreateTemporaryFile(&statm_path));
+ EXPECT_EQ(static_cast<int>(sizeof(kStatmFile)),
+ base::WriteFile(statm_path, kStatmFile, sizeof(kStatmFile)));
+ base::File statm_file(statm_path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ base::FilePath status_path;
+ EXPECT_TRUE(base::CreateTemporaryFile(&status_path));
+ EXPECT_EQ(static_cast<int>(sizeof(kStatusFile)),
+ base::WriteFile(status_path, kStatusFile, sizeof(kStatusFile)));
+ base::File status_file(status_path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+
+ monitor.ReplaceFileDescriptorsForTesting(std::move(statm_file),
+ std::move(status_file));
+
+ MemoryUsage usage = monitor.GetCurrentMemoryUsage();
+ EXPECT_EQ(expected_private_footprint_kb,
+ static_cast<uint64_t>(usage.private_footprint_bytes / 1024));
+ EXPECT_EQ(expected_swap_kb, static_cast<uint64_t>(usage.swap_bytes / 1024));
+ EXPECT_EQ(expected_vm_size_kb,
+ static_cast<uint64_t>(usage.vm_size_bytes / 1024));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor_test.cc b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_test.cc
new file mode 100644
index 00000000000..c2931f12c88
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor_test.cc
@@ -0,0 +1,67 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/controller/memory_usage_monitor.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+class CountingObserver : public MemoryUsageMonitor::Observer {
+ public:
+ void OnMemoryPing(MemoryUsage) override { ++count_; }
+ int count() const { return count_; }
+
+ private:
+ int count_ = 0;
+};
+
+TEST(MemoryUsageMonitorTest, StartStopMonitor) {
+ std::unique_ptr<CountingObserver> observer =
+ std::make_unique<CountingObserver>();
+ EXPECT_FALSE(MemoryUsageMonitor::Instance().TimerIsActive());
+ MemoryUsageMonitor::Instance().AddObserver(observer.get());
+
+ EXPECT_TRUE(MemoryUsageMonitor::Instance().TimerIsActive());
+ EXPECT_EQ(0, observer->count());
+
+ test::RunDelayedTasks(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(1, observer->count());
+
+ test::RunDelayedTasks(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(2, observer->count());
+ MemoryUsageMonitor::Instance().RemoveObserver(observer.get());
+
+ test::RunDelayedTasks(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(2, observer->count());
+ EXPECT_FALSE(MemoryUsageMonitor::Instance().TimerIsActive());
+}
+
+class OneShotObserver : public CountingObserver {
+ public:
+ void OnMemoryPing(MemoryUsage usage) override {
+ MemoryUsageMonitor::Instance().RemoveObserver(this);
+ CountingObserver::OnMemoryPing(usage);
+ }
+};
+
+TEST(MemoryUsageMonitorTest, RemoveObserverFromNotification) {
+ std::unique_ptr<OneShotObserver> observer1 =
+ std::make_unique<OneShotObserver>();
+ std::unique_ptr<CountingObserver> observer2 =
+ std::make_unique<CountingObserver>();
+ MemoryUsageMonitor::Instance().AddObserver(observer1.get());
+ MemoryUsageMonitor::Instance().AddObserver(observer2.get());
+ EXPECT_EQ(0, observer1->count());
+ EXPECT_EQ(0, observer2->count());
+ test::RunDelayedTasks(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(1, observer1->count());
+ EXPECT_EQ(1, observer2->count());
+ test::RunDelayedTasks(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(1, observer1->count());
+ EXPECT_EQ(2, observer2->count());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/oom_intervention_impl.cc b/chromium/third_party/blink/renderer/controller/oom_intervention_impl.cc
index 24b601ff70b..680dd044269 100644
--- a/chromium/third_party/blink/renderer/controller/oom_intervention_impl.cc
+++ b/chromium/third_party/blink/renderer/controller/oom_intervention_impl.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
namespace blink {
@@ -36,7 +37,8 @@ void OomInterventionImpl::StartDetection(
mojom::blink::OomInterventionHostPtr host,
mojom::blink::DetectionArgsPtr detection_args,
bool renderer_pause_enabled,
- bool navigate_ads_enabled) {
+ bool navigate_ads_enabled,
+ bool purge_v8_memory_enabled) {
host_ = std::move(host);
// Disable intervention if we cannot get memory details of current process.
@@ -46,6 +48,7 @@ void OomInterventionImpl::StartDetection(
detection_args_ = std::move(detection_args);
renderer_pause_enabled_ = renderer_pause_enabled;
navigate_ads_enabled_ = navigate_ads_enabled;
+ purge_v8_memory_enabled_ = purge_v8_memory_enabled;
timer_.Start(TimeDelta(), TimeDelta::FromSeconds(1), FROM_HERE);
}
@@ -77,12 +80,14 @@ void OomInterventionImpl::Check(TimerBase*) {
ReportMemoryStats(current_memory);
if (oom_detected) {
- if (navigate_ads_enabled_) {
+ if (navigate_ads_enabled_ || purge_v8_memory_enabled_) {
for (const auto& page : Page::OrdinaryPages()) {
if (page->MainFrame()->IsLocalFrame()) {
- ToLocalFrame(page->MainFrame())
- ->GetDocument()
- ->NavigateLocalAdsFrames();
+ LocalFrame* frame = ToLocalFrame(page->MainFrame());
+ if (navigate_ads_enabled_)
+ frame->GetDocument()->NavigateLocalAdsFrames();
+ if (purge_v8_memory_enabled_)
+ frame->ForciblyPurgeV8Memory();
}
}
}
@@ -92,8 +97,12 @@ void OomInterventionImpl::Check(TimerBase*) {
// mojo strong binding is disconnected.
pauser_.reset(new ScopedPagePauser);
}
+
host_->OnHighMemoryUsage();
timer_.Stop();
+ // Send memory pressure notification to trigger GC.
+ Thread::MainThread()->GetTaskRunner()->PostTask(FROM_HERE,
+ base::BindOnce(&TriggerGC));
// Notify V8GCForContextDispose that page navigation gc is needed when
// intervention runs, as it indicates that memory usage is high.
V8GCForContextDispose::Instance().SetForcePageNavigationGC();
@@ -109,17 +118,21 @@ void OomInterventionImpl::ReportMemoryStats(
OomInterventionMetrics& current_memory) {
UMA_HISTOGRAM_MEMORY_MB(
"Memory.Experimental.OomIntervention.RendererBlinkUsage",
- current_memory.current_blink_usage_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_blink_usage_kb / 1024));
UMA_HISTOGRAM_MEMORY_LARGE_MB(
"Memory.Experimental.OomIntervention."
"RendererPrivateMemoryFootprint",
- current_memory.current_private_footprint_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_private_footprint_kb / 1024));
UMA_HISTOGRAM_MEMORY_MB(
"Memory.Experimental.OomIntervention.RendererSwapFootprint",
- current_memory.current_swap_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_swap_kb / 1024));
UMA_HISTOGRAM_MEMORY_LARGE_MB(
"Memory.Experimental.OomIntervention.RendererVmSize",
- current_memory.current_vm_size_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_vm_size_kb / 1024));
CrashMemoryMetricsReporterImpl::Instance().WriteIntoSharedMemory(
current_memory);
@@ -131,35 +144,46 @@ void OomInterventionImpl::TimerFiredUMAReport(TimerBase*) {
case 3:
base::UmaHistogramSparse(
"Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter10secs",
- current_memory.current_blink_usage_kb / 1024 -
- metrics_at_intervention_.current_blink_usage_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_blink_usage_kb / 1024 -
+ metrics_at_intervention_.current_blink_usage_kb / 1024));
base::UmaHistogramSparse(
"Memory.Experimental.OomIntervention.ReducedRendererPMFAfter10secs",
- current_memory.current_private_footprint_kb / 1024 -
- metrics_at_intervention_.current_private_footprint_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_private_footprint_kb / 1024 -
+ metrics_at_intervention_.current_private_footprint_kb / 1024));
break;
case 2:
base::UmaHistogramSparse(
"Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter20secs",
- current_memory.current_blink_usage_kb / 1024 -
- metrics_at_intervention_.current_blink_usage_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_blink_usage_kb / 1024 -
+ metrics_at_intervention_.current_blink_usage_kb / 1024));
base::UmaHistogramSparse(
"Memory.Experimental.OomIntervention.ReducedRendererPMFAfter20secs",
- current_memory.current_private_footprint_kb / 1024 -
- metrics_at_intervention_.current_private_footprint_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_private_footprint_kb / 1024 -
+ metrics_at_intervention_.current_private_footprint_kb / 1024));
break;
case 1:
base::UmaHistogramSparse(
"Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter30secs",
- current_memory.current_blink_usage_kb / 1024 -
- metrics_at_intervention_.current_blink_usage_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_blink_usage_kb / 1024 -
+ metrics_at_intervention_.current_blink_usage_kb / 1024));
base::UmaHistogramSparse(
"Memory.Experimental.OomIntervention.ReducedRendererPMFAfter30secs",
- current_memory.current_private_footprint_kb / 1024 -
- metrics_at_intervention_.current_private_footprint_kb / 1024);
+ base::saturated_cast<base::Histogram::Sample>(
+ current_memory.current_private_footprint_kb / 1024 -
+ metrics_at_intervention_.current_private_footprint_kb / 1024));
delayed_report_timer_.Stop();
break;
}
}
+void OomInterventionImpl::TriggerGC() {
+ V8PerIsolateData::MainThreadIsolate()->MemoryPressureNotification(
+ v8::MemoryPressureLevel::kCritical);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/oom_intervention_impl.h b/chromium/third_party/blink/renderer/controller/oom_intervention_impl.h
index 1b23b81270e..21ed667e08a 100644
--- a/chromium/third_party/blink/renderer/controller/oom_intervention_impl.h
+++ b/chromium/third_party/blink/renderer/controller/oom_intervention_impl.h
@@ -31,7 +31,8 @@ class CONTROLLER_EXPORT OomInterventionImpl
void StartDetection(mojom::blink::OomInterventionHostPtr,
mojom::blink::DetectionArgsPtr detection_args,
bool renderer_pause_enabled,
- bool navigate_ads_enabled) override;
+ bool navigate_ads_enabled,
+ bool purge_v8_memory_enabled) override;
private:
FRIEND_TEST_ALL_PREFIXES(OomInterventionImplTest, DetectedAndDeclined);
@@ -49,11 +50,14 @@ class CONTROLLER_EXPORT OomInterventionImpl
void TimerFiredUMAReport(TimerBase*);
+ static void TriggerGC();
+
mojom::blink::DetectionArgsPtr detection_args_;
mojom::blink::OomInterventionHostPtr host_;
bool renderer_pause_enabled_ = false;
bool navigate_ads_enabled_ = false;
+ bool purge_v8_memory_enabled_ = false;
TaskRunnerTimer<OomInterventionImpl> timer_;
std::unique_ptr<ScopedPagePauser> pauser_;
OomInterventionMetrics metrics_at_intervention_;
diff --git a/chromium/third_party/blink/renderer/controller/oom_intervention_impl_test.cc b/chromium/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
index be703563197..28fb8dc995d 100644
--- a/chromium/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
+++ b/chromium/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
@@ -80,11 +80,13 @@ class OomInterventionImplTest : public testing::Test {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad("about:blank");
Page* page = web_view->MainFrameImpl()->GetFrame()->GetPage();
EXPECT_FALSE(page->Paused());
- RunDetection(true, false);
+ RunDetection(true, false, false);
return page;
}
- void RunDetection(bool renderer_pause_enabled, bool navigate_ads_enabled) {
+ void RunDetection(bool renderer_pause_enabled,
+ bool navigate_ads_enabled,
+ bool purge_v8_memory_enabled) {
mojom::blink::OomInterventionHostPtr host_ptr;
MockOomInterventionHost mock_host(mojo::MakeRequest(&host_ptr));
@@ -95,7 +97,8 @@ class OomInterventionImplTest : public testing::Test {
args->virtual_memory_thresold = kTestVmSizeThreshold;
intervention_->StartDetection(std::move(host_ptr), std::move(args),
- renderer_pause_enabled, navigate_ads_enabled);
+ renderer_pause_enabled, navigate_ads_enabled,
+ purge_v8_memory_enabled);
test::RunDelayedTasks(TimeDelta::FromSeconds(1));
}
@@ -241,9 +244,9 @@ TEST_F(OomInterventionImplTest, CalculateProcessFootprint) {
mojom::blink::OomInterventionHostPtr host_ptr;
MockOomInterventionHost mock_host(mojo::MakeRequest(&host_ptr));
mojom::blink::DetectionArgsPtr args(mojom::blink::DetectionArgs::New());
- intervention_->StartDetection(std::move(host_ptr), std::move(args),
- true /*renderer_pause_enabled*/,
- true /*navigate_ads_enabled*/);
+ intervention_->StartDetection(
+ std::move(host_ptr), std::move(args), true /*renderer_pause_enabled*/,
+ true /*navigate_ads_enabled*/, true /*purge_v8_memory_enabled*/);
// Create unsafe shared memory region to write metrics in reporter.
base::UnsafeSharedMemoryRegion shm =
base::UnsafeSharedMemoryRegion::Create(sizeof(OomInterventionMetrics));
@@ -290,18 +293,35 @@ TEST_F(OomInterventionImplTest, V1DetectionAdsNavigation) {
WebString::FromUTF8("non-ad"));
LocalFrame* local_adframe = ToLocalFrame(WebFrame::ToCoreFrame(*ad_iframe));
- local_adframe->SetIsAdSubframe();
+ local_adframe->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
LocalFrame* local_non_adframe =
ToLocalFrame(WebFrame::ToCoreFrame(*non_ad_iframe));
EXPECT_TRUE(local_adframe->IsAdSubframe());
EXPECT_FALSE(local_non_adframe->IsAdSubframe());
- RunDetection(true, true);
+ RunDetection(true, true, false);
EXPECT_EQ(local_adframe->GetDocument()->Url().GetString(), "about:blank");
EXPECT_NE(local_non_adframe->GetDocument()->Url().GetString(), "about:blank");
EXPECT_TRUE(page->Paused());
}
+TEST_F(OomInterventionImplTest, V2DetectionV8PurgeMemory) {
+ OomInterventionMetrics mock_metrics = {};
+ mock_metrics.current_blink_usage_kb = (kTestBlinkThreshold / 1024) - 1;
+ mock_metrics.current_private_footprint_kb = (kTestPMFThreshold / 1024) - 1;
+ mock_metrics.current_swap_kb = (kTestSwapThreshold / 1024) - 1;
+ // Set value more than the threshold to trigger intervention.
+ mock_metrics.current_vm_size_kb = (kTestVmSizeThreshold / 1024) + 1;
+ intervention_->SetMetrics(mock_metrics);
+
+ WebViewImpl* web_view = web_view_helper_.InitializeAndLoad("about:blank");
+ Page* page = web_view->MainFrameImpl()->GetFrame()->GetPage();
+ LocalFrame* frame = ToLocalFrame(page->MainFrame());
+ EXPECT_FALSE(frame->GetDocument()->ExecutionContext::IsContextDestroyed());
+ RunDetection(true, true, true);
+ EXPECT_TRUE(frame->GetDocument()->ExecutionContext::IsContextDestroyed());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/BUILD.gn b/chromium/third_party/blink/renderer/core/BUILD.gn
index 0eacbb576ae..14b4353fa04 100644
--- a/chromium/third_party/blink/renderer/core/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/BUILD.gn
@@ -350,6 +350,7 @@ generate_event_interfaces("core_event_interfaces") {
"events/message_event.idl",
"events/mouse_event.idl",
"events/mutation_event.idl",
+ "events/overscroll_event.idl",
"events/page_transition_event.idl",
"events/picture_in_picture_control_event.idl",
"events/pointer_event.idl",
@@ -382,7 +383,7 @@ group("generated_testing_idls") {
]
}
-action("generated_settings_macros") {
+blink_python_runner("generated_settings_macros") {
script = "../build/scripts/make_settings.py"
inputs = scripts_for_json5_files + [
@@ -401,7 +402,7 @@ action("generated_settings_macros") {
]
}
-action("generated_testing_idls_settings") {
+blink_python_runner("generated_testing_idls_settings") {
script = "../build/scripts/make_internal_settings.py"
inputs = scripts_for_json5_files + [
@@ -425,7 +426,7 @@ action("generated_testing_idls_settings") {
]
}
-action("generated_testing_idls_internal_runtime_flags") {
+blink_python_runner("generated_testing_idls_internal_runtime_flags") {
script = "../build/scripts/make_internal_runtime_flags.py"
inputs = scripts_for_json5_files + [
@@ -1415,7 +1416,7 @@ action("make_core_generated_html_entity_table") {
deps = make_core_generated_deps
}
-action("make_core_generated_css_tokenizer_codepoints") {
+blink_python_runner("make_core_generated_css_tokenizer_codepoints") {
visibility = [] # Allow re-assignment of list.
visibility = [ ":*" ]
script = "../build/scripts/core/css/make_css_tokenizer_codepoints.py"
@@ -1438,7 +1439,7 @@ action("make_core_generated_css_tokenizer_codepoints") {
deps = make_core_generated_deps
}
-action("make_core_generated_css_primitive_value_unit_trie") {
+blink_python_runner("make_core_generated_css_primitive_value_unit_trie") {
visibility = [] # Allow re-assignment of list.
visibility = [ ":*" ]
script = "../build/scripts/core/css/make_css_primitive_value_unit_trie.py"
@@ -1467,7 +1468,7 @@ action("make_core_generated_css_primitive_value_unit_trie") {
deps = make_core_generated_deps
}
-action("make_core_generated_html_element_lookup_trie") {
+blink_python_runner("make_core_generated_html_element_lookup_trie") {
visibility = [] # Allow re-assignment of list.
visibility = [ ":*" ]
script = "../build/scripts/make_element_lookup_trie.py"
@@ -1498,7 +1499,7 @@ action("make_core_generated_html_element_lookup_trie") {
deps = make_core_generated_deps
}
-action("make_core_generated_origin_trials") {
+blink_python_runner("make_core_generated_origin_trials") {
script = "../build/scripts/make_origin_trials.py"
inputs = scripts_for_json5_files + [
@@ -1524,7 +1525,7 @@ action("make_core_generated_origin_trials") {
]
}
}
-action("make_core_generated_web_origin_trials") {
+blink_python_runner("make_core_generated_web_origin_trials") {
script = "../build/scripts/make_web_origin_trials.py"
inputs = scripts_for_json5_files + [
@@ -1719,6 +1720,7 @@ jumbo_source_set("unit_tests") {
"animation/list_interpolation_functions_test.cc",
"animation/property_handle_test.cc",
"animation/scroll_timeline_test.cc",
+ "animation/scroll_timeline_util_test.cc",
"animation/timing_calculations_test.cc",
"animation/timing_input_test.cc",
"clipboard/data_object_test.cc",
@@ -1742,6 +1744,7 @@ jumbo_source_set("unit_tests") {
"css/css_test_helpers.cc",
"css/css_test_helpers.h",
"css/css_value_test_helper.h",
+ "css/cssom/cross_thread_style_value_test.cc",
"css/cssom/css_math_invert_test.cc",
"css/cssom/css_math_negate_test.cc",
"css/cssom/css_numeric_value_type_test.cc",
@@ -1749,6 +1752,7 @@ jumbo_source_set("unit_tests") {
"css/cssom/css_style_image_value_test.cc",
"css/cssom/css_unit_value_test.cc",
"css/cssom/css_unparsed_value_test.cc",
+ "css/cssom/paint_worklet_style_property_map_test.cc",
"css/cssom/prepopulated_computed_style_property_map_test.cc",
"css/drag_update_test.cc",
"css/font_face_cache_test.cc",
@@ -1794,6 +1798,8 @@ jumbo_source_set("unit_tests") {
"css/threaded/filter_operation_resolver_threaded_test.cc",
"css/threaded/font_object_threaded_test.cc",
"css/threaded/text_renderer_threaded_test.cc",
+ "display_lock/display_lock_budget_test.cc",
+ "display_lock/display_lock_context_test.cc",
"dom/attr_test.cc",
"dom/document_statistics_collector_test.cc",
"dom/document_test.cc",
@@ -1812,7 +1818,6 @@ jumbo_source_set("unit_tests") {
"dom/names_map_test.cc",
"dom/node_test.cc",
"dom/nth_index_cache_test.cc",
- "dom/pausable_object_test.cc",
"dom/range_test.cc",
"dom/scripted_animation_controller_test.cc",
"dom/scripted_idle_task_controller_test.cc",
@@ -1832,6 +1837,7 @@ jumbo_source_set("unit_tests") {
"events/pointer_event_factory_test.cc",
"events/touch_event_test.cc",
"events/web_input_event_conversion_test.cc",
+ "execution_context/pausable_object_test.cc",
"exported/local_frame_client_impl_test.cc",
"exported/prerendering_test.cc",
"exported/web_associated_url_loader_impl_test.cc",
@@ -1857,6 +1863,7 @@ jumbo_source_set("unit_tests") {
"feature_policy/policy_test.cc",
"fetch/blob_bytes_consumer_test.cc",
"fetch/body_stream_buffer_test.cc",
+ "fetch/buffering_bytes_consumer_test.cc",
"fetch/bytes_consumer_for_data_consumer_handle_test.cc",
"fetch/bytes_consumer_test.cc",
"fetch/bytes_consumer_test_util.cc",
@@ -1882,6 +1889,7 @@ jumbo_source_set("unit_tests") {
"frame/document_loading_rendering_test.cc",
"frame/dom_timer_test.cc",
"frame/find_in_page_test.cc",
+ "frame/frame_overlay_test.cc",
"frame/frame_serializer_test.cc",
"frame/frame_test.cc",
"frame/frame_test_helpers.cc",
@@ -1918,6 +1926,7 @@ jumbo_source_set("unit_tests") {
"html/forms/email_input_type_test.cc",
"html/forms/external_popup_menu_test.cc",
"html/forms/file_input_type_test.cc",
+ "html/forms/form_controller_test.cc",
"html/forms/form_data_test.cc",
"html/forms/html_form_control_element_test.cc",
"html/forms/html_form_element_test.cc",
@@ -1946,15 +1955,19 @@ jumbo_source_set("unit_tests") {
"html/image_document_test.cc",
"html/imports/html_import_sheets_test.cc",
"html/lazy_load_frame_observer_test.cc",
+ "html/lazy_load_image_observer_test.cc",
"html/link_element_loading_test.cc",
"html/link_rel_attribute_test.cc",
"html/list_item_ordinal_test.cc",
"html/media/autoplay_uma_helper_test.cc",
"html/media/html_media_element_event_listeners_test.cc",
"html/media/html_media_element_test.cc",
+ "html/media/html_media_test_helper.cc",
+ "html/media/html_media_test_helper.h",
"html/media/html_video_element_persistent_test.cc",
"html/media/html_video_element_test.cc",
"html/media/media_custom_controls_fullscreen_detector_test.cc",
+ "html/media/video_wake_lock_test.cc",
"html/media_element_filling_viewport_test.cc",
"html/parser/atomic_html_token_test.cc",
"html/parser/compact_html_token_test.cc",
@@ -1987,6 +2000,7 @@ jumbo_source_set("unit_tests") {
"inspector/protocol_parser_test.cc",
"inspector/protocol_unittest.cc",
"intersection_observer/intersection_observer_test.cc",
+ "invisible_dom/find_invisible_test.cc",
"layout/api/selection_state_test.cc",
"layout/collapsed_border_value_test.cc",
"layout/custom/layout_worklet_test.cc",
@@ -2012,6 +2026,7 @@ jumbo_source_set("unit_tests") {
"layout/layout_table_row_test.cc",
"layout/layout_table_section_test.cc",
"layout/layout_table_test.cc",
+ "layout/layout_text_control_single_line_test.cc",
"layout/layout_text_control_test.cc",
"layout/layout_text_fragment_test.cc",
"layout/layout_text_test.cc",
@@ -2030,6 +2045,7 @@ jumbo_source_set("unit_tests") {
"layout/ng/geometry/ng_physical_offset_test.cc",
"layout/ng/geometry/ng_physical_rect_test.cc",
"layout/ng/inline/ng_baseline_test.cc",
+ "layout/ng/inline/ng_caret_navigator_test.cc",
"layout/ng/inline/ng_caret_position_test.cc",
"layout/ng/inline/ng_inline_fragment_traversal_test.cc",
"layout/ng/inline/ng_inline_items_builder_test.cc",
@@ -2065,7 +2081,6 @@ jumbo_source_set("unit_tests") {
"layout/svg/layout_svg_text_test.cc",
"layout/text_autosizer_test.cc",
"layout/visual_rect_mapping_test.cc",
- "loader/allowed_by_nosniff_test.cc",
"loader/base_fetch_context_test.cc",
"loader/document_load_timing_test.cc",
"loader/document_loader_test.cc",
@@ -2100,9 +2115,10 @@ jumbo_source_set("unit_tests") {
"page/context_menu_controller_test.cc",
"page/drag_controller_test.cc",
"page/focus_controller_test.cc",
- "page/page_overlay_test.cc",
"page/page_popup_client_test.cc",
"page/print_context_test.cc",
+ "page/scrolling/fragment_anchor_test.cc",
+ "page/scrolling/main_thread_scrolling_reasons_test.cc",
"page/scrolling/root_scroller_test.cc",
"page/scrolling/scroll_into_view_test.cc",
"page/scrolling/scroll_metrics_test.cc",
@@ -2129,6 +2145,7 @@ jumbo_source_set("unit_tests") {
"paint/first_meaningful_paint_detector_test.cc",
"paint/fragment_data_test.cc",
"paint/html_canvas_painter_test.cc",
+ "paint/image_element_timing_test.cc",
"paint/image_paint_timing_detector_test.cc",
"paint/link_highlight_impl_test.cc",
"paint/ng/ng_paint_fragment_test.cc",
@@ -2149,7 +2166,7 @@ jumbo_source_set("unit_tests") {
"paint/paint_property_tree_printer_test.cc",
"paint/paint_property_tree_update_tests.cc",
"paint/pre_paint_tree_walk_test.cc",
- "paint/stub_chrome_client_for_spv2.h",
+ "paint/stub_chrome_client_for_cap.h",
"paint/table_painter_test.cc",
"paint/text_paint_timing_detector_test.cc",
"paint/text_painter_test.cc",
@@ -2199,10 +2216,6 @@ jumbo_source_set("unit_tests") {
"testing/sim/sim_request.h",
"testing/sim/sim_test.cc",
"testing/sim/sim_test.h",
- "testing/sim/sim_web_frame_client.cc",
- "testing/sim/sim_web_frame_client.h",
- "testing/sim/sim_web_view_client.cc",
- "testing/sim/sim_web_view_client.h",
"timing/memory_info_test.cc",
"timing/performance_navigation_timing_test.cc",
"timing/performance_observer_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/DEPS b/chromium/third_party/blink/renderer/core/DEPS
index a6c68014db6..b5e5273007a 100644
--- a/chromium/third_party/blink/renderer/core/DEPS
+++ b/chromium/third_party/blink/renderer/core/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+base/atomic_sequence_num.h",
"+base/files/file.h",
"+base/memory/scoped_refptr.h",
+ "+base/strings/stringprintf.h",
"+base/synchronization/waitable_event.h",
"+base/task/sequence_manager/task_time_observer.h",
"+base/unguessable_token.h",
@@ -28,17 +29,20 @@ include_rules = [
"+cc/paint/display_item_list.h",
"+cc/paint/paint_canvas.h",
"+cc/paint/paint_flags.h",
+ "+cc/paint/paint_worklet_input.h",
"+gpu/config/gpu_feature_info.h",
"-inspector/v8",
"+inspector/v8/public",
"+mojo/public/cpp/base",
"+mojo/public/cpp/bindings",
"+mojo/public/cpp/system",
+ "+services/device/public/mojom/wake_lock.mojom-blink.h",
"+services/metrics/public",
"+services/network/public/cpp/cors/cors_error_status.h",
"+services/network/public/cpp/features.h",
"+services/network/public/cpp/shared_url_loader_factory.h",
"+services/resource_coordinator/public/cpp/resource_coordinator_features.h",
+ "+services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h",
"+services/service_manager/public",
"+services/ws/public/mojom/ime/ime.mojom-shared.h",
"+skia/public/interfaces/bitmap_skbitmap_struct_traits.h",
@@ -74,7 +78,7 @@ specific_include_rules = {
# TODO(crbug.com/838693): Test harnesses use LayerTreeView
# from content instead of a fake WebLayerTreeView implementation, so
# that the Web abstraction can go away.
- "+content/renderer/gpu",
+ "+content/renderer/compositor",
"+content/test",
"+third_party/blink/renderer/core/frame/web_local_frame_impl.h",
"+third_party/blink/renderer/core/frame/web_remote_frame_impl.h",
diff --git a/chromium/third_party/blink/renderer/core/OWNERS b/chromium/third_party/blink/renderer/core/OWNERS
index 50bd98e64c5..80e3fa5b205 100644
--- a/chromium/third_party/blink/renderer/core/OWNERS
+++ b/chromium/third_party/blink/renderer/core/OWNERS
@@ -13,7 +13,6 @@ dcheng@chromium.org
# dtapuska reviews input-related changes
dtapuska@chromium.org
dgozman@chromium.org
-dominicc@chromium.org
# drott reviews font specific changes.
drott@chromium.org
dsinclair@chromium.org
@@ -56,7 +55,7 @@ pfeldman@chromium.org
pkasting@chromium.org
rego@igalia.com
rbyers@chromium.org
-rob.buis@samsung.com
+rbuis@igalia.com
robhogan@gmail.com
schenney@chromium.org
senorblanco@chromium.org
@@ -70,7 +69,8 @@ tonyg@chromium.org
# vollick reviews compositor integration, accelerated transitions, animations and scrolling, scrolling coordinator, CSS transforms
vollick@chromium.org
wangxianzhu@chromium.org
-yoav@yoav.ws
+yhirano@chromium.org
+yoavweiss@chromium.org
yutak@chromium.org
# TEAM: blink-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.cc b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.cc
index 8910b9bfed6..8d5ba4bc658 100644
--- a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.cc
+++ b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.cc
@@ -31,6 +31,7 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/web/web_ax_enums.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h"
@@ -77,7 +78,7 @@ const char* g_aria_widgets[] = {
static ARIAWidgetSet* CreateARIARoleWidgetSet() {
ARIAWidgetSet* widget_set = new HashSet<String, CaseFoldingHash>();
- for (size_t i = 0; i < arraysize(g_aria_widgets); ++i)
+ for (size_t i = 0; i < base::size(g_aria_widgets); ++i)
widget_set->insert(String(g_aria_widgets[i]));
return widget_set;
}
@@ -111,7 +112,8 @@ const char* g_aria_interactive_widget_attributes[] = {
};
bool HasInteractiveARIAAttribute(const Element& element) {
- for (size_t i = 0; i < arraysize(g_aria_interactive_widget_attributes); ++i) {
+ for (size_t i = 0; i < base::size(g_aria_interactive_widget_attributes);
+ ++i) {
const char* attribute = g_aria_interactive_widget_attributes[i];
if (element.hasAttribute(attribute)) {
return true;
diff --git a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h
index 5913d693276..e9dfdd775bb 100644
--- a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h
+++ b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h
@@ -103,6 +103,8 @@ class CORE_EXPORT AXObjectCache
virtual void HandleLayoutComplete(Document*) = 0;
virtual void HandleClicked(Node*) = 0;
virtual void HandleAutofillStateChanged(Element*, bool) = 0;
+ virtual void HandleValidationMessageVisibilityChanged(
+ const Element* form_control) = 0;
// Handle any notifications which arrived while layout was dirty.
virtual void ProcessUpdatesAfterLayout(Document&) = 0;
diff --git a/chromium/third_party/blink/renderer/core/animation/BUILD.gn b/chromium/third_party/blink/renderer/core/animation/BUILD.gn
index b96fc0b8da2..8dcf27c7d56 100644
--- a/chromium/third_party/blink/renderer/core/animation/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/animation/BUILD.gn
@@ -182,6 +182,8 @@ blink_core_sources("animation") {
"sampled_effect.h",
"scroll_timeline.cc",
"scroll_timeline.h",
+ "scroll_timeline_util.cc",
+ "scroll_timeline_util.h",
"shadow_interpolation_functions.cc",
"shadow_interpolation_functions.h",
"side_index.h",
diff --git a/chromium/third_party/blink/renderer/core/animation/README.md b/chromium/third_party/blink/renderer/core/animation/README.md
index e6ffefb1335..9481e72d44f 100644
--- a/chromium/third_party/blink/renderer/core/animation/README.md
+++ b/chromium/third_party/blink/renderer/core/animation/README.md
@@ -61,8 +61,8 @@ The Blink animation engine interacts with Blink/Chrome in the following ways:
A subset of style properties (currently transform, opacity, filter, and
backdrop-filter) can be mutated on the compositor thread. Animations that
- mutates only these properties are a candidate for being accelerated and run
- on compositor thread which ensures they are isolated from Blink's main
+ mutate only these properties are candidates for being accelerated and run
+ on the compositor thread which ensures they are isolated from Blink's main
thread work.
Whether or not an animation can be accelerated is determined by
@@ -74,7 +74,7 @@ The Blink animation engine interacts with Blink/Chrome in the following ways:
#### Lifetime of a compositor animation
Animations that can be accelerated get added to the [PendingAnimations][]
- list. The pending list is updates as part of document lifecycle and ensures
+ list. The pending list is updated as part of document lifecycle and ensures
each pending animation gets a corresponding [cc::AnimationPlayer][]
representing the animation on the compositor. The player is initialized with
appropriate timing values and corresponding effects.
@@ -91,20 +91,20 @@ The Blink animation engine interacts with Blink/Chrome in the following ways:
animations do not cause spurious commits from main to compositor (See
[CompositedLayerMapping::UpdateGraphicsLayerGeometry()][])
- A compositor animation provide updates on its playback state changes (e.g.,
+ A compositor animation provides updates on its playback state changes (e.g.,
on start, finish, abort) to its blink counterpart via
[CompositorAnimationDelegate][] interface. Blink animation uses the start
event callback to obtain an accurate start time for the animation which is
important to ensure its output accurately reflects the compositor animation
output.
-[CheckCanStartAnimationOnCompositor()]: https://cs.chromium.org/search/?q=file:Animation.h+function:CheckCanStartAnimationOnCompositor
+[CheckCanStartAnimationOnCompositor()]: https://cs.chromium.org/search/?q=file:animation.h+function:CheckCanStartAnimationOnCompositor
[FailureCodes]: https://cs.chromium.org/search/?q=return%5Cs%2B(CompositorAnimations::)?FailureCode
[cc::AnimationPlayer]: https://cs.chromium.org/search/?q=file:src/cc/animation/animation_player.h+class:AnimationPlayer
-[PendingAnimations]: https://cs.chromium.org/search/?q=file:PendingAnimations.h+class:PendingAnimations
-[Animation::PreCommit()]: https://cs.chromium.org/search/?q=file:Animation.h+function:PreCommit
-[CompositorAnimationDelegate]: https://cs.chromium.org/search/?q=file:CompositorAnimationDelegate.h
-[CompositedLayerMapping::UpdateGraphicsLayerGeometry()]: https://cs.chromium.org/search/?q=file:CompositedLayerMapping.h+function:UpdateGraphicsLayerGeometry
+[PendingAnimations]: https://cs.chromium.org/search/?q=file:pending_animations.h+class:PendingAnimations
+[Animation::PreCommit()]: https://cs.chromium.org/search/?q=file:animation.h+function:PreCommit
+[CompositorAnimationDelegate]: https://cs.chromium.org/search/?q=file:compositor_animation_delegate.h
+[CompositedLayerMapping::UpdateGraphicsLayerGeometry()]: https://cs.chromium.org/search/?q=file:composited_layer_mapping.h+function:UpdateGraphicsLayerGeometry
* ### Javascript
@@ -358,9 +358,9 @@ manually construct an instance of your object to [extending RenderingTest][]
where you can load HTML, [enable compositing][] if necessary, and run assertions
about the state.
-[extending Test]: https://cs.chromium.org/search/?q=public%5C+testing::Test+file:core%5C/Animation&sq=package:chromium&type=cs
+[extending Test]: https://cs.chromium.org/search/?q=public%5C+testing::Test+file:core%5C/animation&sq=package:chromium&type=cs
[extending RenderingTest]: https://cs.chromium.org/search/?q=public%5C+RenderingTest+file:core%5C/animation&type=cs
-[enable compositing]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/animation/compositor_animations_test.cc?type=cs&sq=package:chromium&q=file:core%5C/animation%5C/.*Test%5C.cpp+EnableCompositing
+[enable compositing]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/animation/compositor_animations_test.cc?type=cs&sq=package:chromium&q=file:core%5C/animation%5C/.*test%5C.cpp+EnableCompositing
## Ongoing work
@@ -384,4 +384,4 @@ web animation but it allows the animation itself to be highly customized in
Javascript by providing an `animate` callback. These animations run inside an
isolated worklet global scope.
-[WorkletAnimation]: https://cs.chromium.org/search/?q=file:animationworklet/WorkletAnimation.h+class:WorkletAnimation
+[WorkletAnimation]: https://cs.chromium.org/search/?q=file:animationworklet/worklet_animation.h+class:WorkletAnimation
diff --git a/chromium/third_party/blink/renderer/core/animation/animatable/animatable_double.h b/chromium/third_party/blink/renderer/core/animation/animatable/animatable_double.h
index aba5ff02ad4..d9c379963d6 100644
--- a/chromium/third_party/blink/renderer/core/animation/animatable/animatable_double.h
+++ b/chromium/third_party/blink/renderer/core/animation/animatable/animatable_double.h
@@ -38,10 +38,11 @@ namespace blink {
class CORE_EXPORT AnimatableDouble final : public AnimatableValue {
public:
+ AnimatableDouble(double number) : number_(number) {}
~AnimatableDouble() override = default;
static AnimatableDouble* Create(double number) {
- return new AnimatableDouble(number);
+ return MakeGarbageCollected<AnimatableDouble>(number);
}
double ToDouble() const { return number_; }
@@ -51,7 +52,6 @@ class CORE_EXPORT AnimatableDouble final : public AnimatableValue {
double fraction) const override;
private:
- AnimatableDouble(double number) : number_(number) {}
AnimatableType GetType() const override { return kTypeDouble; }
double number_;
diff --git a/chromium/third_party/blink/renderer/core/animation/animatable/animatable_filter_operations.h b/chromium/third_party/blink/renderer/core/animation/animatable/animatable_filter_operations.h
index 10814622a15..cdb0ab7378f 100644
--- a/chromium/third_party/blink/renderer/core/animation/animatable/animatable_filter_operations.h
+++ b/chromium/third_party/blink/renderer/core/animation/animatable/animatable_filter_operations.h
@@ -41,9 +41,11 @@ class AnimatableFilterOperations final : public AnimatableValue {
public:
static AnimatableFilterOperations* Create(
const FilterOperations& operations) {
- return new AnimatableFilterOperations(operations);
+ return MakeGarbageCollected<AnimatableFilterOperations>(operations);
}
+ AnimatableFilterOperations(const FilterOperations& operations)
+ : operation_wrapper_(FilterOperationsWrapper::Create(operations)) {}
~AnimatableFilterOperations() override = default;
const FilterOperations& Operations() const {
@@ -57,9 +59,6 @@ class AnimatableFilterOperations final : public AnimatableValue {
double fraction) const override;
private:
- AnimatableFilterOperations(const FilterOperations& operations)
- : operation_wrapper_(FilterOperationsWrapper::Create(operations)) {}
-
AnimatableType GetType() const override { return kTypeFilterOperations; }
Member<FilterOperationsWrapper> operation_wrapper_;
diff --git a/chromium/third_party/blink/renderer/core/animation/animatable/animatable_transform.h b/chromium/third_party/blink/renderer/core/animation/animatable/animatable_transform.h
index 10842bf4e4c..817c57a7a71 100644
--- a/chromium/third_party/blink/renderer/core/animation/animatable/animatable_transform.h
+++ b/chromium/third_party/blink/renderer/core/animation/animatable/animatable_transform.h
@@ -39,10 +39,14 @@ namespace blink {
class CORE_EXPORT AnimatableTransform final : public AnimatableValue {
public:
+ explicit AnimatableTransform(const TransformOperations& transform,
+ double zoom)
+ : transform_(transform), zoom_(zoom) {}
~AnimatableTransform() override = default;
+
static AnimatableTransform* Create(const TransformOperations& transform,
double zoom) {
- return new AnimatableTransform(transform, zoom);
+ return MakeGarbageCollected<AnimatableTransform>(transform, zoom);
}
const TransformOperations& GetTransformOperations() const {
return transform_;
@@ -54,9 +58,6 @@ class CORE_EXPORT AnimatableTransform final : public AnimatableValue {
double fraction) const override;
private:
- explicit AnimatableTransform(const TransformOperations& transform,
- double zoom)
- : transform_(transform), zoom_(zoom) {}
AnimatableType GetType() const override { return kTypeTransform; }
const TransformOperations transform_;
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.cc b/chromium/third_party/blink/renderer/core/animation/animation.cc
index bab13cab062..7dad569a20d 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation.cc
@@ -80,7 +80,7 @@ Animation* Animation::Create(AnimationEffect* effect,
DocumentTimeline* subtimeline = ToDocumentTimeline(timeline);
- Animation* animation = new Animation(
+ Animation* animation = MakeGarbageCollected<Animation>(
subtimeline->GetDocument()->ContextDocument(), *subtimeline, effect);
if (subtimeline) {
@@ -685,9 +685,9 @@ void Animation::finish(ExceptionState& exception_state) {
ScriptPromise Animation::finished(ScriptState* script_state) {
if (!finished_promise_) {
- finished_promise_ =
- new AnimationPromise(ExecutionContext::From(script_state), this,
- AnimationPromise::kFinished);
+ finished_promise_ = MakeGarbageCollected<AnimationPromise>(
+ ExecutionContext::From(script_state), this,
+ AnimationPromise::kFinished);
if (PlayStateInternal() == kFinished)
finished_promise_->Resolve(this);
}
@@ -696,8 +696,8 @@ ScriptPromise Animation::finished(ScriptState* script_state) {
ScriptPromise Animation::ready(ScriptState* script_state) {
if (!ready_promise_) {
- ready_promise_ = new AnimationPromise(ExecutionContext::From(script_state),
- this, AnimationPromise::kReady);
+ ready_promise_ = MakeGarbageCollected<AnimationPromise>(
+ ExecutionContext::From(script_state), this, AnimationPromise::kReady);
if (PlayStateInternal() != kPending)
ready_promise_->Resolve(this);
}
@@ -1318,7 +1318,7 @@ void Animation::Trace(blink::Visitor* visitor) {
Animation::CompositorAnimationHolder*
Animation::CompositorAnimationHolder::Create(Animation* animation) {
- return new CompositorAnimationHolder(animation);
+ return MakeGarbageCollected<CompositorAnimationHolder>(animation);
}
Animation::CompositorAnimationHolder::CompositorAnimationHolder(
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.h b/chromium/third_party/blink/renderer/core/animation/animation.h
index de4b82499fc..c4a6db7c401 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation.h
@@ -93,6 +93,7 @@ class CORE_EXPORT Animation final : public EventTargetWithInlineData,
AnimationTimeline*,
ExceptionState&);
+ Animation(ExecutionContext*, DocumentTimeline&, AnimationEffect*);
~Animation() override;
void Dispose();
@@ -233,8 +234,6 @@ class CORE_EXPORT Animation final : public EventTargetWithInlineData,
RegisteredEventListener&) override;
private:
- Animation(ExecutionContext*, DocumentTimeline&, AnimationEffect*);
-
void ClearOutdated();
void ForceServiceOnNextFrame();
@@ -356,6 +355,8 @@ class CORE_EXPORT Animation final : public EventTargetWithInlineData,
public:
static CompositorAnimationHolder* Create(Animation*);
+ explicit CompositorAnimationHolder(Animation*);
+
void Detach();
void Trace(blink::Visitor* visitor) { visitor->Trace(animation_); }
@@ -365,8 +366,6 @@ class CORE_EXPORT Animation final : public EventTargetWithInlineData,
}
private:
- explicit CompositorAnimationHolder(Animation*);
-
void Dispose();
std::unique_ptr<CompositorAnimation> compositor_animation_;
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect.cc b/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
index 5adbdf56aa9..ffd0a17316a 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
@@ -180,9 +180,15 @@ void AnimationEffect::UpdateInheritedTime(double inherited_time,
double time_to_next_iteration = std::numeric_limits<double>::infinity();
if (needs_update) {
const double active_duration = RepeatedDuration();
+ // TODO(yigu): Direction of WorkletAnimation is always forwards based on
+ // the calculation. Need to unify the logic to handle it correctly.
+ // https://crbug.com/896249.
+ const AnimationDirection direction =
+ (GetAnimation() && GetAnimation()->playbackRate() < 0) ? kBackwards
+ : kForwards;
const Phase current_phase =
- CalculatePhase(active_duration, local_time, timing_);
+ CalculatePhase(active_duration, local_time, direction, timing_);
// FIXME: parentPhase depends on groups being implemented.
const AnimationEffect::Phase kParentPhase = AnimationEffect::kPhaseActive;
const double active_time = CalculateActiveTime(
@@ -227,12 +233,21 @@ void AnimationEffect::UpdateInheritedTime(double inherited_time,
const double local_active_duration =
kLocalIterationDuration * timing_.iteration_count;
DCHECK_GE(local_active_duration, 0);
+ const double end_time = std::max(
+ timing_.start_delay + active_duration + timing_.end_delay, 0.0);
+ const double before_active_boundary_time =
+ std::max(std::min(timing_.start_delay, end_time), 0.0);
+ // local_local_time should be greater than or equal to the
+ // before_active_boundary_time once the local_time goes past the start
+ // delay.
const double local_local_time =
local_time < timing_.start_delay
? local_time
- : local_active_duration + timing_.start_delay;
- const AnimationEffect::Phase local_current_phase =
- CalculatePhase(local_active_duration, local_local_time, timing_);
+ : std::max(local_active_duration + timing_.start_delay,
+ before_active_boundary_time);
+
+ const AnimationEffect::Phase local_current_phase = CalculatePhase(
+ local_active_duration, local_local_time, direction, timing_);
const double local_active_time = CalculateActiveTime(
local_active_duration,
ResolvedFillMode(timing_.fill_mode, IsKeyframeEffect()),
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect.h b/chromium/third_party/blink/renderer/core/animation/animation_effect.h
index 502a8d4f7a3..feb3b477363 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect.h
@@ -82,6 +82,12 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
kPhaseAfter,
kPhaseNone,
};
+ // Represents the animation direction from the Web Animations spec, see
+ // https://drafts.csswg.org/web-animations-1/#animation-direction.
+ enum AnimationDirection {
+ kForwards,
+ kBackwards,
+ };
class EventDelegate : public GarbageCollectedFinalized<EventDelegate> {
public:
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc b/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
index 3e215ff26c2..557ed22d95e 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/animation/animation_input_helpers.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/animation/property_handle.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/parser/css_parser.h"
@@ -200,7 +201,7 @@ const AttributeNameMap& GetSupportedAttributes() {
&svg_names::kYChannelSelectorAttr,
&svg_names::kZAttr,
};
- for (size_t i = 0; i < arraysize(attributes); i++) {
+ for (size_t i = 0; i < base::size(attributes); i++) {
DCHECK(!SVGElement::IsAnimatableCSSProperty(*attributes[i]));
supported_attributes.Set(*attributes[i], attributes[i]);
}
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_test.cc b/chromium/third_party/blink/renderer/core/animation/animation_test.cc
index ef9d2620489..c0a9e879bd5 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_test.cc
@@ -869,7 +869,7 @@ TEST_F(AnimationAnimationTest, PauseAfterCancel) {
}
TEST_F(AnimationAnimationTest, NoCompositeWithoutCompositedElementId) {
- ScopedSlimmingPaintV2ForTest enable_s_pv2(true);
+ ScopedCompositeAfterPaintForTest enable_cap(true);
SetBodyInnerHTML(
"<div id='foo' style='position: relative'></div>"
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
index 1cc872bd6af..45d30eb9965 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -146,7 +146,7 @@ bool HasIncompatibleAnimations(const Element& target_element,
CompositorElementIdNamespace CompositorElementNamespaceForProperty(
CSSPropertyID property) {
if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// Pre-BlinkGenPropertyTrees, all animations affect the primary
// ElementId namespace.
return CompositorElementIdNamespace::kPrimary;
@@ -327,7 +327,7 @@ CompositorAnimations::CheckCanStartElementOnCompositor(
return FailureCode::NonActionable("Accelerated animations are disabled");
}
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// We query paint property tree state below to determine whether the
// animation is compositable. There is a known lifecycle violation where an
// animation can be cancelled during style update. See
@@ -504,8 +504,8 @@ void CompositorAnimations::AttachCompositedLayers(
PaintLayer* layer =
ToLayoutBoxModelObject(element.GetLayoutObject())->Layer();
- // Composited animations do not depend on a composited layer mapping for SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // Composited animations do not depend on a composited layer mapping for CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (!layer->IsAllowedToQueryCompositingState() ||
!layer->GetCompositedLayerMapping() ||
!layer->GetCompositedLayerMapping()->MainGraphicsLayer())
@@ -524,7 +524,7 @@ void CompositorAnimations::AttachCompositedLayers(
// Currently we use the kPrimaryEffect node to know if nodes have been
// created for animations.
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
element_id_namespace = CompositorElementIdNamespace::kPrimaryEffect;
}
compositor_animation->AttachElement(CompositorElementIdFromUniqueObjectId(
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations.h b/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
index 30d53abb1b7..84413c1043a 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -149,9 +149,9 @@ class CORE_EXPORT CompositorAnimations {
friend class AnimationCompositorAnimationsTest;
FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
- CanStartElementOnCompositorTransformSPv2);
+ CanStartElementOnCompositorTransformCAP);
FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
- CanStartElementOnCompositorEffectSPv2);
+ CanStartElementOnCompositorEffectCAP);
FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
CanStartElementOnCompositorEffect);
FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index a8154a61f89..d27d062cf5f 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -287,8 +287,17 @@ class AnimationCompositorAnimationsTest : public RenderingTest {
class AnimatableMockStringKeyframe : public StringKeyframe {
public:
static StringKeyframe* Create(double offset) {
- return new AnimatableMockStringKeyframe(offset);
+ return MakeGarbageCollected<AnimatableMockStringKeyframe>(offset);
}
+
+ AnimatableMockStringKeyframe(double offset)
+ : StringKeyframe(),
+ property_specific_(
+ MakeGarbageCollected<
+ AnimatableMockPropertySpecificStringKeyframe>(offset)) {
+ SetOffset(offset);
+ }
+
Keyframe::PropertySpecificKeyframe* CreatePropertySpecificKeyframe(
const PropertyHandle&,
EffectModel::CompositeOperation,
@@ -347,12 +356,6 @@ class AnimationCompositorAnimationsTest : public RenderingTest {
};
Member<PropertySpecificKeyframe> property_specific_;
- AnimatableMockStringKeyframe(double offset)
- : StringKeyframe(),
- property_specific_(
- new AnimatableMockPropertySpecificStringKeyframe(offset)) {
- SetOffset(offset);
- }
};
StringKeyframe* CreateAnimatableReplaceKeyframe(CSSPropertyID id,
@@ -461,7 +464,8 @@ class AnimationCompositorAnimationsTest : public RenderingTest {
LocalFrame* GetFrame() const { return helper_.LocalMainFrame()->GetFrame(); }
void BeginFrame() {
- helper_.GetWebView()->BeginFrame(WTF::CurrentTimeTicks());
+ helper_.GetWebView()->MainFrameWidget()->BeginFrame(
+ WTF::CurrentTimeTicks());
}
void ForceFullCompositingUpdate() {
@@ -1756,13 +1760,13 @@ void UpdateDummyEffectNode(ObjectPaintProperties& properties,
} // namespace
TEST_F(AnimationCompositorAnimationsTest,
- CanStartElementOnCompositorTransformSPv2) {
+ CanStartElementOnCompositorTransformCAP) {
Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
layout_object->EnsureIdForTestingProxy();
element->SetLayoutObject(layout_object);
- ScopedSlimmingPaintV2ForTest enable_s_pv2(true);
+ ScopedCompositeAfterPaintForTest enable_cap(true);
auto& properties = layout_object->GetMutableForPainting()
.FirstFragment()
.EnsurePaintProperties();
@@ -1789,13 +1793,13 @@ TEST_F(AnimationCompositorAnimationsTest,
}
TEST_F(AnimationCompositorAnimationsTest,
- CanStartElementOnCompositorEffectSPv2) {
+ CanStartElementOnCompositorEffectCAP) {
Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
layout_object->EnsureIdForTestingProxy();
element->SetLayoutObject(layout_object);
- ScopedSlimmingPaintV2ForTest enable_s_pv2(true);
+ ScopedCompositeAfterPaintForTest enable_cap(true);
auto& properties = layout_object->GetMutableForPainting()
.FirstFragment()
.EnsurePaintProperties();
@@ -1891,7 +1895,7 @@ TEST_F(AnimationCompositorAnimationsTest, CanStartElementOnCompositorEffect) {
Element* target = document->getElementById("target");
const ObjectPaintProperties* properties =
target->GetLayoutObject()->FirstFragment().PaintProperties();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_TRUE(properties->Transform()->HasDirectCompositingReasons());
CompositorAnimations::FailureCode code =
CompositorAnimations::CheckCanStartElementOnCompositor(*target);
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
index 529e50a61c6..9f111cf0378 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/core/animation/element_animations.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/paint/stub_chrome_client_for_spv2.h"
+#include "third_party/blink/renderer/core/paint/stub_chrome_client_for_cap.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_delegate.h"
@@ -16,7 +16,7 @@ namespace blink {
class CSSAnimationsTest : public RenderingTest {
public:
CSSAnimationsTest()
- : chrome_client_(MakeGarbageCollected<StubChromeClientForSPv2>()) {
+ : chrome_client_(MakeGarbageCollected<StubChromeClientForCAP>()) {
EnablePlatform();
platform()->SetThreadedAnimationEnabled(true);
}
@@ -58,7 +58,7 @@ class CSSAnimationsTest : public RenderingTest {
}
private:
- Persistent<StubChromeClientForSPv2> chrome_client_;
+ Persistent<StubChromeClientForCAP> chrome_client_;
};
// Verify that a composited animation is retargeted according to its composited
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
index 924a3ab7893..fa2106da6b8 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
@@ -159,10 +159,9 @@ Color CSSColorInterpolationType::ResolveInterpolableColor(
if (alpha == 0)
return Color::kTransparent;
- return MakeRGBA(static_cast<int>(round(red / alpha)),
- static_cast<int>(round(green / alpha)),
- static_cast<int>(round(blue / alpha)),
- static_cast<int>(round(alpha)));
+ return MakeRGBA(
+ clampTo<int>(round(red / alpha)), clampTo<int>(round(green / alpha)),
+ clampTo<int>(round(blue / alpha)), clampTo<int>(round(alpha)));
}
class InheritedColorChecker
diff --git a/chromium/third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.cc
index 34b35395972..75df242561c 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/animation/underlying_length_checker.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
index a363e1f7bbc..2eb8bc30487 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/css/css_font_variation_value.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink {
@@ -210,10 +211,11 @@ void CSSFontVariationSettingsInterpolationType::ApplyStandardPropertyValue(
scoped_refptr<FontVariationSettings> settings =
FontVariationSettings::Create();
wtf_size_t length = numbers.length();
+ // Do clampTo here, which follows the same logic as ConsumeFontVariationTag.
for (wtf_size_t i = 0; i < length; ++i) {
settings->Append(FontVariationAxis(
tags[i],
- static_cast<float>(ToInterpolableNumber(numbers.Get(i))->Value())));
+ clampTo<float>(ToInterpolableNumber(numbers.Get(i))->Value())));
}
state.GetFontBuilder().SetVariationSettings(settings);
}
diff --git a/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
index 504e59f143d..893589c499c 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
index 849c0e9d55e..b26f3124b8d 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.cc
index c127a212707..85736429f12 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.cc
@@ -174,7 +174,7 @@ void CSSOffsetRotateInterpolationType::ApplyStandardPropertyValue(
const NonInterpolableValue* non_interpolable_value,
StyleResolverState& state) const {
state.Style()->SetOffsetRotate(StyleOffsetRotation(
- ToInterpolableNumber(interpolable_value).Value(),
+ clampTo<float>(ToInterpolableNumber(interpolable_value).Value()),
ToCSSOffsetRotationNonInterpolableValue(*non_interpolable_value)
.RotationType()));
}
diff --git a/chromium/third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.cc
index 0071b81ef8d..e3018530ffa 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
index 8fb1c798557..ddeaef26ff2 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/element_animation.cc b/chromium/third_party/blink/renderer/core/animation/element_animation.cc
index 0999d0082b5..4b2724b8d4f 100644
--- a/chromium/third_party/blink/renderer/core/animation/element_animation.cc
+++ b/chromium/third_party/blink/renderer/core/animation/element_animation.cc
@@ -28,12 +28,14 @@ namespace {
void ReportFeaturePolicyViolationsIfNecessary(
const Document& document,
const KeyframeEffectModelBase& effect) {
- if (document.IsFeatureEnabled(mojom::FeaturePolicyFeature::kLayoutAnimations))
- return;
- for (const auto* blocked_property :
- LayoutAnimationsPolicy::AffectedCSSProperties()) {
- if (effect.Affects(PropertyHandle(*blocked_property)))
- LayoutAnimationsPolicy::ReportViolation(*blocked_property, document);
+ for (const auto& property_handle : effect.Properties()) {
+ if (!property_handle.IsCSSProperty())
+ continue;
+ const auto& css_property = property_handle.GetCSSProperty();
+ if (LayoutAnimationsPolicy::AffectedCSSProperties().Contains(
+ &css_property)) {
+ LayoutAnimationsPolicy::ReportViolation(css_property, document);
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolation_effect.h b/chromium/third_party/blink/renderer/core/animation/interpolation_effect.h
index 1b261ec0d4b..78cfee54a8a 100644
--- a/chromium/third_party/blink/renderer/core/animation/interpolation_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/interpolation_effect.h
@@ -39,7 +39,7 @@ class CORE_EXPORT InterpolationEffect
double end,
double apply_from,
double apply_to) {
- interpolations_.push_back(new InterpolationRecord(
+ interpolations_.push_back(MakeGarbageCollected<InterpolationRecord>(
interpolation, std::move(easing), start, end, apply_from, apply_to));
}
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolation_effect_test.cc b/chromium/third_party/blink/renderer/core/animation/interpolation_effect_test.cc
index 2c978b28da5..b7808c03833 100644
--- a/chromium/third_party/blink/renderer/core/animation/interpolation_effect_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/interpolation_effect_test.cc
@@ -40,7 +40,7 @@ Interpolation* CreateInterpolation(int from, int to) {
TEST(AnimationInterpolationEffectTest, SingleInterpolation) {
Persistent<InterpolationEffect> interpolation_effect =
- new InterpolationEffect;
+ MakeGarbageCollected<InterpolationEffect>();
interpolation_effect->AddInterpolation(
CreateInterpolation(0, 10), scoped_refptr<TimingFunction>(), 0, 1, -1, 2);
@@ -71,7 +71,7 @@ TEST(AnimationInterpolationEffectTest, SingleInterpolation) {
TEST(AnimationInterpolationEffectTest, MultipleInterpolations) {
Persistent<InterpolationEffect> interpolation_effect =
- new InterpolationEffect;
+ MakeGarbageCollected<InterpolationEffect>();
interpolation_effect->AddInterpolation(
CreateInterpolation(10, 15), scoped_refptr<TimingFunction>(), 1, 2, 1, 3);
interpolation_effect->AddInterpolation(
diff --git a/chromium/third_party/blink/renderer/core/animation/invalidatable_interpolation.h b/chromium/third_party/blink/renderer/core/animation/invalidatable_interpolation.h
index 5f7fdc569cc..5c60251616a 100644
--- a/chromium/third_party/blink/renderer/core/animation/invalidatable_interpolation.h
+++ b/chromium/third_party/blink/renderer/core/animation/invalidatable_interpolation.h
@@ -35,10 +35,22 @@ class CORE_EXPORT InvalidatableInterpolation : public Interpolation {
const PropertyHandle& property,
PropertySpecificKeyframe* start_keyframe,
PropertySpecificKeyframe* end_keyframe) {
- return new InvalidatableInterpolation(property, start_keyframe,
- end_keyframe);
+ return MakeGarbageCollected<InvalidatableInterpolation>(
+ property, start_keyframe, end_keyframe);
}
+ InvalidatableInterpolation(const PropertyHandle& property,
+ PropertySpecificKeyframe* start_keyframe,
+ PropertySpecificKeyframe* end_keyframe)
+ : Interpolation(),
+ property_(property),
+ interpolation_types_(nullptr),
+ interpolation_types_version_(0),
+ start_keyframe_(start_keyframe),
+ end_keyframe_(end_keyframe),
+ current_fraction_(std::numeric_limits<double>::quiet_NaN()),
+ is_conversion_cached_(false) {}
+
const PropertyHandle& GetProperty() const final { return property_; }
void Interpolate(int iteration, double fraction) override;
bool DependsOnUnderlyingValue() const final;
@@ -58,18 +70,6 @@ class CORE_EXPORT InvalidatableInterpolation : public Interpolation {
}
private:
- InvalidatableInterpolation(const PropertyHandle& property,
- PropertySpecificKeyframe* start_keyframe,
- PropertySpecificKeyframe* end_keyframe)
- : Interpolation(),
- property_(property),
- interpolation_types_(nullptr),
- interpolation_types_version_(0),
- start_keyframe_(start_keyframe),
- end_keyframe_(end_keyframe),
- current_fraction_(std::numeric_limits<double>::quiet_NaN()),
- is_conversion_cached_(false) {}
-
using ConversionCheckers = InterpolationType::ConversionCheckers;
std::unique_ptr<TypedInterpolationValue> MaybeConvertUnderlyingValue(
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe.h b/chromium/third_party/blink/renderer/core/animation/keyframe.h
index 909a4b61b6d..ccf93f6fb8d 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe.h
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe.h
@@ -120,6 +120,9 @@ class CORE_EXPORT Keyframe : public GarbageCollectedFinalized<Keyframe> {
class CORE_EXPORT PropertySpecificKeyframe
: public GarbageCollectedFinalized<PropertySpecificKeyframe> {
public:
+ PropertySpecificKeyframe(double offset,
+ scoped_refptr<TimingFunction> easing,
+ EffectModel::CompositeOperation);
virtual ~PropertySpecificKeyframe() = default;
double Offset() const { return offset_; }
TimingFunction& Easing() const { return *easing_; }
@@ -159,10 +162,6 @@ class CORE_EXPORT Keyframe : public GarbageCollectedFinalized<Keyframe> {
virtual void Trace(Visitor*){};
protected:
- PropertySpecificKeyframe(double offset,
- scoped_refptr<TimingFunction> easing,
- EffectModel::CompositeOperation);
-
double offset_;
scoped_refptr<TimingFunction> easing_;
EffectModel::CompositeOperation composite_;
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
index 2c4e8d31b26..b291cf94ac8 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
@@ -325,9 +325,11 @@ void KeyframeEffectModelBase::EnsureKeyframeGroups() const {
KeyframeGroupMap::iterator group_iter = keyframe_groups_->find(property);
PropertySpecificKeyframeGroup* group;
if (group_iter == keyframe_groups_->end()) {
- group = keyframe_groups_
- ->insert(property, new PropertySpecificKeyframeGroup)
- .stored_value->value.Get();
+ group =
+ keyframe_groups_
+ ->insert(property,
+ MakeGarbageCollected<PropertySpecificKeyframeGroup>())
+ .stored_value->value.Get();
} else {
group = group_iter->value.Get();
}
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
index 3fe078e32a4..1d02dbd98db 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
@@ -153,7 +153,7 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel {
protected:
KeyframeEffectModelBase(CompositeOperation composite,
scoped_refptr<TimingFunction> default_keyframe_easing)
- : interpolation_effect_(new InterpolationEffect),
+ : interpolation_effect_(MakeGarbageCollected<InterpolationEffect>()),
last_iteration_(0),
last_fraction_(std::numeric_limits<double>::quiet_NaN()),
last_iteration_duration_(AnimationTimeDelta()),
diff --git a/chromium/third_party/blink/renderer/core/animation/length_interpolation_functions.cc b/chromium/third_party/blink/renderer/core/animation/length_interpolation_functions.cc
index b1cd14d943c..cbf455a28a0 100644
--- a/chromium/third_party/blink/renderer/core/animation/length_interpolation_functions.cc
+++ b/chromium/third_party/blink/renderer/core/animation/length_interpolation_functions.cc
@@ -190,9 +190,11 @@ Length LengthInterpolationFunctions::CreateLength(
if (percentage != 0)
has_percentage = true;
- if (pixels != 0 && has_percentage)
- return Length(
- CalculationValue::Create(PixelsAndPercent(pixels, percentage), range));
+ if (pixels != 0 && has_percentage) {
+ return Length(CalculationValue::Create(
+ PixelsAndPercent(clampTo<float>(pixels), clampTo<float>(percentage)),
+ range));
+ }
if (has_percentage)
return Length(ClampToRange(percentage, range), kPercent);
return Length(
diff --git a/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc b/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc
index 527c9e8f47a..d049473f14b 100644
--- a/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc
@@ -10,6 +10,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/animation/css_number_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/interpolation_value.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
index 394c242f7f2..63868fca81a 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -65,8 +65,10 @@ bool StringToScrollOffset(String scroll_offset, CSSPrimitiveValue** result) {
Node* ResolveScrollSource(Element* scroll_source) {
// When in quirks mode we need the style to be clean, so we don't use
// |ScrollingElementNoLayout|.
- if (scroll_source == scroll_source->GetDocument().scrollingElement())
+ if (scroll_source &&
+ scroll_source == scroll_source->GetDocument().scrollingElement()) {
return &scroll_source->GetDocument();
+ }
return scroll_source;
}
} // namespace
@@ -122,14 +124,16 @@ ScrollTimeline::ScrollTimeline(Element* scroll_source,
start_scroll_offset_(start_scroll_offset),
end_scroll_offset_(end_scroll_offset),
time_range_(time_range) {
- DCHECK(scroll_source_);
}
double ScrollTimeline::currentTime(bool& is_null) {
is_null = true;
- // 1. If scrollSource does not currently have a CSS layout box, or if its
- // layout box is not a scroll container, return an unresolved time value.
- LayoutBox* layout_box = resolved_scroll_source_->GetLayoutBox();
+
+ // 1. If scrollSource is null, does not currently have a CSS layout box, or if
+ // its layout box is not a scroll container, return an unresolved time value.
+ LayoutBox* layout_box = resolved_scroll_source_
+ ? resolved_scroll_source_->GetLayoutBox()
+ : nullptr;
if (!layout_box || !layout_box->HasOverflowClip()) {
return std::numeric_limits<double>::quiet_NaN();
}
@@ -291,6 +295,9 @@ void ScrollTimeline::ResolveScrollStartAndEnd(
}
void ScrollTimeline::AttachAnimation() {
+ if (!resolved_scroll_source_)
+ return;
+
GetActiveScrollTimelineSet().insert(resolved_scroll_source_);
if (resolved_scroll_source_->IsElementNode())
ToElement(resolved_scroll_source_)->SetNeedsCompositingUpdate();
@@ -306,6 +313,9 @@ void ScrollTimeline::AttachAnimation() {
}
void ScrollTimeline::DetachAnimation() {
+ if (!resolved_scroll_source_)
+ return;
+
GetActiveScrollTimelineSet().erase(resolved_scroll_source_);
if (resolved_scroll_source_->IsElementNode())
ToElement(resolved_scroll_source_)->SetNeedsCompositingUpdate();
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
index ee43c4539c9..a78393c25c8 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -58,8 +58,10 @@ class CORE_EXPORT ScrollTimeline final : public AnimationTimeline {
// Returns the Node that should actually have the ScrollableArea (if one
// exists). This can differ from |scrollSource| when |scroll_source_| is the
- // Document's scrollingElement.
+ // Document's scrollingElement, and it may be null if the document was removed
+ // before the ScrollTimeline was created.
Node* ResolvedScrollSource() const { return resolved_scroll_source_; }
+
ScrollDirection GetOrientation() const { return orientation_; }
void GetCurrentAndMaxOffset(const LayoutBox*,
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_options.idl b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_options.idl
index 0f518d2e4d6..74e907227c7 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_options.idl
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_options.idl
@@ -14,7 +14,7 @@ enum ScrollDirection {
enum ScrollTimelineAutoKeyword { "auto" };
dictionary ScrollTimelineOptions {
- Element scrollSource;
+ Element? scrollSource = null;
ScrollDirection orientation = "block";
DOMString startScrollOffset = "auto";
DOMString endScrollOffset = "auto";
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
index 5de8c38bf37..0ea4dcba6c0 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
@@ -220,4 +220,24 @@ TEST_F(ScrollTimelineTest,
EXPECT_EQ(&GetDocument(), scroll_timeline->ResolvedScrollSource());
}
+TEST_F(ScrollTimelineTest, AttachOrDetachAnimationWithNullScrollSource) {
+ // Directly call the constructor to make it easier to pass a null
+ // scrollSource. The alternative approach would require us to remove the
+ // documentElement from the document.
+ Element* scroll_source = nullptr;
+ CSSPrimitiveValue* start_scroll_offset = nullptr;
+ CSSPrimitiveValue* end_scroll_offset = nullptr;
+ ScrollTimeline* scroll_timeline = MakeGarbageCollected<ScrollTimeline>(
+ scroll_source, ScrollTimeline::Block, start_scroll_offset,
+ end_scroll_offset, 100);
+
+ // Sanity checks.
+ ASSERT_EQ(scroll_timeline->scrollSource(), nullptr);
+ ASSERT_EQ(scroll_timeline->ResolvedScrollSource(), nullptr);
+
+ // These calls should be no-ops in this mode, and shouldn't crash.
+ scroll_timeline->AttachAnimation();
+ scroll_timeline->DetachAnimation();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.cc
new file mode 100644
index 00000000000..c9667a02f43
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.cc
@@ -0,0 +1,119 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/scroll_timeline_util.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/double_or_scroll_timeline_auto_keyword.h"
+#include "third_party/blink/renderer/core/animation/animation_timeline.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
+
+namespace blink {
+
+namespace scroll_timeline_util {
+
+std::unique_ptr<CompositorScrollTimeline> ToCompositorScrollTimeline(
+ AnimationTimeline* timeline) {
+ if (!timeline || timeline->IsDocumentTimeline())
+ return nullptr;
+
+ ScrollTimeline* scroll_timeline = ToScrollTimeline(timeline);
+ Node* scroll_source = scroll_timeline->ResolvedScrollSource();
+ base::Optional<CompositorElementId> element_id =
+ GetCompositorScrollElementId(scroll_source);
+
+ DoubleOrScrollTimelineAutoKeyword time_range;
+ scroll_timeline->timeRange(time_range);
+ // TODO(smcgruer): Handle 'auto' time range value.
+ DCHECK(time_range.IsDouble());
+
+ LayoutBox* box = scroll_source ? scroll_source->GetLayoutBox() : nullptr;
+
+ CompositorScrollTimeline::ScrollDirection orientation = ConvertOrientation(
+ scroll_timeline->GetOrientation(), box ? box->Style() : nullptr);
+
+ base::Optional<double> start_scroll_offset;
+ base::Optional<double> end_scroll_offset;
+ if (box) {
+ double current_offset;
+ double max_offset;
+ scroll_timeline->GetCurrentAndMaxOffset(box, current_offset, max_offset);
+
+ double resolved_start_scroll_offset = 0;
+ double resolved_end_scroll_offset = max_offset;
+ scroll_timeline->ResolveScrollStartAndEnd(box, max_offset,
+ resolved_start_scroll_offset,
+ resolved_end_scroll_offset);
+ start_scroll_offset = resolved_start_scroll_offset;
+ end_scroll_offset = resolved_end_scroll_offset;
+ }
+
+ return std::make_unique<CompositorScrollTimeline>(
+ element_id, orientation, start_scroll_offset, end_scroll_offset,
+ time_range.GetAsDouble());
+}
+
+base::Optional<CompositorElementId> GetCompositorScrollElementId(
+ const Node* node) {
+ if (!node || !node->GetLayoutObject() || !node->GetLayoutObject()->UniqueId())
+ return base::nullopt;
+ return CompositorElementIdFromUniqueObjectId(
+ node->GetLayoutObject()->UniqueId(),
+ CompositorElementIdNamespace::kScroll);
+}
+
+// The compositor does not know about writing modes, so we have to convert the
+// web concepts of 'block' and 'inline' direction into absolute vertical or
+// horizontal directions.
+CompositorScrollTimeline::ScrollDirection ConvertOrientation(
+ ScrollTimeline::ScrollDirection orientation,
+ const ComputedStyle* style) {
+ // Easy cases; physical is always physical.
+ if (orientation == ScrollTimeline::Horizontal)
+ return CompositorScrollTimeline::ScrollRight;
+ if (orientation == ScrollTimeline::Vertical)
+ return CompositorScrollTimeline::ScrollDown;
+
+ // Harder cases; first work out which axis is which, and then for each check
+ // which edge we start at.
+
+ // writing-mode: horizontal-tb
+ bool is_horizontal_writing_mode =
+ style ? style->IsHorizontalWritingMode() : true;
+ // writing-mode: vertical-lr
+ bool is_flipped_lines_writing_mode =
+ style ? style->IsFlippedLinesWritingMode() : false;
+ // direction: ltr;
+ bool is_ltr_direction = style ? style->IsLeftToRightDirection() : true;
+
+ if (orientation == ScrollTimeline::Block) {
+ if (is_horizontal_writing_mode) {
+ // For horizontal writing mode, block is vertical. The starting edge is
+ // always the top.
+ return CompositorScrollTimeline::ScrollDown;
+ }
+ // For vertical writing mode, the block axis is horizontal. The starting
+ // edge depends on if we are lr or rl.
+ return is_flipped_lines_writing_mode ? CompositorScrollTimeline::ScrollRight
+ : CompositorScrollTimeline::ScrollLeft;
+ }
+
+ DCHECK_EQ(orientation, ScrollTimeline::Inline);
+ if (is_horizontal_writing_mode) {
+ // For horizontal writing mode, inline is horizontal. The starting edge
+ // depends on the directionality.
+ return is_ltr_direction ? CompositorScrollTimeline::ScrollRight
+ : CompositorScrollTimeline::ScrollLeft;
+ }
+ // For vertical writing mode, inline is vertical. The starting edge still
+ // depends on the directionality; whether it is vertical-lr or vertical-rl
+ // does not matter.
+ return is_ltr_direction ? CompositorScrollTimeline::ScrollDown
+ : CompositorScrollTimeline::ScrollUp;
+}
+
+} // namespace scroll_timeline_util
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.h b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.h
new file mode 100644
index 00000000000..a1111278ccd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_UTIL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_UTIL_H_
+
+#include <memory>
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/animation/compositor_animation.h"
+
+namespace blink {
+
+class AnimationTimeline;
+class ComputedStyle;
+class Node;
+
+namespace scroll_timeline_util {
+
+// Converts the input timeline to the compositor representation of a
+// ScrollTimeline. Returns nullptr if the input is not a ScrollTimeline.
+std::unique_ptr<CompositorScrollTimeline> CORE_EXPORT
+ToCompositorScrollTimeline(AnimationTimeline*);
+
+// Retrieves the 'scroll' compositor element id for the input node, or
+// base::nullopt if it does not exist.
+base::Optional<CompositorElementId> CORE_EXPORT
+GetCompositorScrollElementId(const Node*);
+
+// Convert the blink concept of a ScrollTimeline orientation into the cc one.
+//
+// This implements a subset of the conversions documented in
+// https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical
+CompositorScrollTimeline::ScrollDirection CORE_EXPORT
+ConvertOrientation(ScrollTimeline::ScrollDirection, const ComputedStyle*);
+
+} // namespace scroll_timeline_util
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_UTIL_H_
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
new file mode 100644
index 00000000000..cd0ec23e17c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
@@ -0,0 +1,220 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/scroll_timeline_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/animation/document_timeline.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+
+namespace scroll_timeline_util {
+
+using ScrollTimelineUtilTest = PageTestBase;
+
+// This test covers only the basic conversions for element id, time range,
+// orientation, and start and end scroll offset. Complex orientation conversions
+// are tested in the GetOrientation* tests, and complex start/end scroll offset
+// resolutions are tested in blink::ScrollTimelineTest.
+TEST_F(ScrollTimelineUtilTest, ToCompositorScrollTimeline) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #scroller {
+ overflow: auto;
+ width: 100px;
+ height: 100px;
+ }
+ #contents {
+ height: 1000px;
+ }
+ </style>
+ <div id='scroller'><div id='contents'></div></div>
+ )HTML");
+
+ Element* scroller = GetElementById("scroller");
+ base::Optional<CompositorElementId> element_id =
+ GetCompositorScrollElementId(scroller);
+ ASSERT_TRUE(element_id.has_value());
+
+ ScrollTimelineOptions* options = ScrollTimelineOptions::Create();
+ options->setScrollSource(scroller);
+ const double time_range = 100;
+ options->setTimeRange(
+ DoubleOrScrollTimelineAutoKeyword::FromDouble(time_range));
+ options->setOrientation("block");
+ options->setStartScrollOffset("50px");
+ options->setEndScrollOffset("auto");
+ ScrollTimeline* timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ std::unique_ptr<CompositorScrollTimeline> compositor_timeline =
+ ToCompositorScrollTimeline(timeline);
+ EXPECT_EQ(compositor_timeline->GetActiveIdForTest(), base::nullopt);
+ EXPECT_EQ(compositor_timeline->GetPendingIdForTest(), element_id);
+ EXPECT_EQ(compositor_timeline->GetTimeRangeForTest(), time_range);
+ EXPECT_EQ(compositor_timeline->GetDirectionForTest(),
+ CompositorScrollTimeline::ScrollDown);
+ EXPECT_EQ(compositor_timeline->GetStartScrollOffsetForTest(), 50);
+ // 900 is contents-size - scroller-viewport == 1000 - 100
+ EXPECT_EQ(compositor_timeline->GetEndScrollOffsetForTest(), 900);
+}
+
+TEST_F(ScrollTimelineUtilTest, ToCompositorScrollTimelineNullParameter) {
+ EXPECT_EQ(ToCompositorScrollTimeline(nullptr), nullptr);
+}
+
+TEST_F(ScrollTimelineUtilTest,
+ ToCompositorScrollTimelineDocumentTimelineParameter) {
+ DocumentTimeline* timeline =
+ DocumentTimeline::Create(Document::CreateForTest());
+ EXPECT_EQ(ToCompositorScrollTimeline(timeline), nullptr);
+}
+
+TEST_F(ScrollTimelineUtilTest, ToCompositorScrollTimelineNullScrollSource) {
+ // Directly call the constructor to make it easier to pass a null
+ // scrollSource. The alternative approach would require us to remove the
+ // documentElement from the document.
+ Element* scroll_source = nullptr;
+ CSSPrimitiveValue* start_scroll_offset = nullptr;
+ CSSPrimitiveValue* end_scroll_offset = nullptr;
+ ScrollTimeline* timeline = MakeGarbageCollected<ScrollTimeline>(
+ scroll_source, ScrollTimeline::Block, start_scroll_offset,
+ end_scroll_offset, 100);
+
+ std::unique_ptr<CompositorScrollTimeline> compositor_timeline =
+ ToCompositorScrollTimeline(timeline);
+ ASSERT_TRUE(compositor_timeline.get());
+ EXPECT_EQ(compositor_timeline->GetPendingIdForTest(), base::nullopt);
+}
+
+TEST_F(ScrollTimelineUtilTest, ToCompositorScrollTimelineNullLayoutBox) {
+ Element* div = HTMLDivElement::Create(GetDocument());
+ ASSERT_FALSE(div->GetLayoutBox());
+
+ ScrollTimelineOptions* options = ScrollTimelineOptions::Create();
+ DoubleOrScrollTimelineAutoKeyword time_range =
+ DoubleOrScrollTimelineAutoKeyword::FromDouble(100);
+ options->setTimeRange(time_range);
+ options->setScrollSource(div);
+ ScrollTimeline* timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ std::unique_ptr<CompositorScrollTimeline> compositor_timeline =
+ ToCompositorScrollTimeline(timeline);
+ EXPECT_TRUE(compositor_timeline.get());
+ // Here we just want to test the start/end scroll offset.
+ // ToCompositorScrollTimelineNullScrollSource covers the expected pending id
+ // and ConvertOrientationNullStyle covers the orientation conversion.
+ EXPECT_EQ(compositor_timeline->GetStartScrollOffsetForTest(), base::nullopt);
+ EXPECT_EQ(compositor_timeline->GetEndScrollOffsetForTest(), base::nullopt);
+}
+
+TEST_F(ScrollTimelineUtilTest, ConvertOrientationPhysicalCases) {
+ // For physical the writing-mode and directionality shouldn't matter, so make
+ // sure it doesn't.
+ Vector<WritingMode> writing_modes = {WritingMode::kHorizontalTb,
+ WritingMode::kVerticalLr,
+ WritingMode::kVerticalRl};
+ Vector<TextDirection> directions = {TextDirection::kLtr, TextDirection::kRtl};
+
+ scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+ for (const WritingMode& writing_mode : writing_modes) {
+ for (const TextDirection& direction : directions) {
+ style->SetWritingMode(writing_mode);
+ style->SetDirection(direction);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Vertical, style.get()),
+ CompositorScrollTimeline::ScrollDown);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Horizontal, style.get()),
+ CompositorScrollTimeline::ScrollRight);
+ }
+ }
+}
+
+TEST_F(ScrollTimelineUtilTest, ConvertOrientationLogical) {
+ scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+
+ // horizontal-tb, ltr
+ style->SetWritingMode(WritingMode::kHorizontalTb);
+ style->SetDirection(TextDirection::kLtr);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, style.get()),
+ CompositorScrollTimeline::ScrollDown);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, style.get()),
+ CompositorScrollTimeline::ScrollRight);
+
+ // vertical-lr, ltr
+ style->SetWritingMode(WritingMode::kVerticalLr);
+ style->SetDirection(TextDirection::kLtr);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, style.get()),
+ CompositorScrollTimeline::ScrollRight);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, style.get()),
+ CompositorScrollTimeline::ScrollDown);
+
+ // vertical-rl, ltr
+ style->SetWritingMode(WritingMode::kVerticalRl);
+ style->SetDirection(TextDirection::kLtr);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, style.get()),
+ CompositorScrollTimeline::ScrollLeft);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, style.get()),
+ CompositorScrollTimeline::ScrollDown);
+
+ // horizontal-tb, rtl
+ style->SetWritingMode(WritingMode::kHorizontalTb);
+ style->SetDirection(TextDirection::kRtl);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, style.get()),
+ CompositorScrollTimeline::ScrollDown);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, style.get()),
+ CompositorScrollTimeline::ScrollLeft);
+
+ // vertical-lr, rtl
+ style->SetWritingMode(WritingMode::kVerticalLr);
+ style->SetDirection(TextDirection::kRtl);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, style.get()),
+ CompositorScrollTimeline::ScrollRight);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, style.get()),
+ CompositorScrollTimeline::ScrollUp);
+
+ // vertical-rl, rtl
+ style->SetWritingMode(WritingMode::kVerticalRl);
+ style->SetDirection(TextDirection::kRtl);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, style.get()),
+ CompositorScrollTimeline::ScrollLeft);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, style.get()),
+ CompositorScrollTimeline::ScrollUp);
+}
+
+TEST_F(ScrollTimelineUtilTest, ConvertOrientationNullStyle) {
+ // When the style is nullptr we assume horizontal-tb and ltr direction. This
+ // means that block is ScrollDown and inline is ScrollRight
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Vertical, nullptr),
+ CompositorScrollTimeline::ScrollDown);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Horizontal, nullptr),
+ CompositorScrollTimeline::ScrollRight);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Block, nullptr),
+ CompositorScrollTimeline::ScrollDown);
+ EXPECT_EQ(ConvertOrientation(ScrollTimeline::Inline, nullptr),
+ CompositorScrollTimeline::ScrollRight);
+}
+
+TEST_F(ScrollTimelineUtilTest, GetCompositorScrollElementIdNullNode) {
+ EXPECT_EQ(GetCompositorScrollElementId(nullptr), base::nullopt);
+}
+
+TEST_F(ScrollTimelineUtilTest, GetCompositorScrollElementIdNullLayoutObject) {
+ Element* div = HTMLDivElement::Create(GetDocument());
+ ASSERT_FALSE(div->GetLayoutObject());
+ EXPECT_EQ(GetCompositorScrollElementId(nullptr), base::nullopt);
+}
+
+TEST_F(ScrollTimelineUtilTest, GetCompositorScrollElementIdNoUniqueId) {
+ SetBodyInnerHTML("<div id='test'></div>");
+ Element* test = GetElementById("test");
+ ASSERT_TRUE(test->GetLayoutObject());
+ ASSERT_FALSE(test->GetLayoutObject()->UniqueId());
+ EXPECT_EQ(GetCompositorScrollElementId(test), base::nullopt);
+}
+
+} // namespace scroll_timeline_util
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc b/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
index ff3c9c12c60..d696d002dee 100644
--- a/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
+++ b/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
@@ -141,7 +141,7 @@ void StringKeyframe::Trace(Visitor* visitor) {
}
Keyframe* StringKeyframe::Clone() const {
- return new StringKeyframe(*this);
+ return MakeGarbageCollected<StringKeyframe>(*this);
}
Keyframe::PropertySpecificKeyframe*
diff --git a/chromium/third_party/blink/renderer/core/animation/string_keyframe.h b/chromium/third_party/blink/renderer/core/animation/string_keyframe.h
index d2b824f200c..b8847abae4a 100644
--- a/chromium/third_party/blink/renderer/core/animation/string_keyframe.h
+++ b/chromium/third_party/blink/renderer/core/animation/string_keyframe.h
@@ -27,7 +27,16 @@ class StyleSheetContents;
// expand shorthand properties; that is done for computed keyframes.
class CORE_EXPORT StringKeyframe : public Keyframe {
public:
- static StringKeyframe* Create() { return new StringKeyframe; }
+ static StringKeyframe* Create() {
+ return MakeGarbageCollected<StringKeyframe>();
+ }
+
+ StringKeyframe()
+ : css_property_map_(
+ MutableCSSPropertyValueSet::Create(kHTMLStandardMode)),
+ presentation_attribute_map_(
+ MutableCSSPropertyValueSet::Create(kHTMLStandardMode)) {}
+ StringKeyframe(const StringKeyframe& copy_from);
MutableCSSPropertyValueSet::SetResult SetCSSPropertyValue(
const AtomicString& property_name,
@@ -88,10 +97,19 @@ class CORE_EXPORT StringKeyframe : public Keyframe {
scoped_refptr<TimingFunction> easing,
const CSSValue* value,
EffectModel::CompositeOperation composite) {
- return new CSSPropertySpecificKeyframe(offset, std::move(easing), value,
- composite);
+ return MakeGarbageCollected<CSSPropertySpecificKeyframe>(
+ offset, std::move(easing), value, composite);
}
+ CSSPropertySpecificKeyframe(double offset,
+ scoped_refptr<TimingFunction> easing,
+ const CSSValue* value,
+ EffectModel::CompositeOperation composite)
+ : Keyframe::PropertySpecificKeyframe(offset,
+ std::move(easing),
+ composite),
+ value_(value) {}
+
const CSSValue* Value() const { return value_.Get(); }
bool PopulateAnimatableValue(const PropertyHandle&,
@@ -110,15 +128,6 @@ class CORE_EXPORT StringKeyframe : public Keyframe {
void Trace(Visitor*) override;
private:
- CSSPropertySpecificKeyframe(double offset,
- scoped_refptr<TimingFunction> easing,
- const CSSValue* value,
- EffectModel::CompositeOperation composite)
- : Keyframe::PropertySpecificKeyframe(offset,
- std::move(easing),
- composite),
- value_(value) {}
-
Keyframe::PropertySpecificKeyframe* CloneWithOffset(
double offset) const override;
bool IsCSSPropertySpecificKeyframe() const override { return true; }
@@ -135,10 +144,19 @@ class CORE_EXPORT StringKeyframe : public Keyframe {
scoped_refptr<TimingFunction> easing,
const String& value,
EffectModel::CompositeOperation composite) {
- return new SVGPropertySpecificKeyframe(offset, std::move(easing), value,
- composite);
+ return MakeGarbageCollected<SVGPropertySpecificKeyframe>(
+ offset, std::move(easing), value, composite);
}
+ SVGPropertySpecificKeyframe(double offset,
+ scoped_refptr<TimingFunction> easing,
+ const String& value,
+ EffectModel::CompositeOperation composite)
+ : Keyframe::PropertySpecificKeyframe(offset,
+ std::move(easing),
+ composite),
+ value_(value) {}
+
const String& Value() const { return value_; }
PropertySpecificKeyframe* CloneWithOffset(double offset) const final;
@@ -151,30 +169,12 @@ class CORE_EXPORT StringKeyframe : public Keyframe {
scoped_refptr<TimingFunction> easing) const final;
private:
- SVGPropertySpecificKeyframe(double offset,
- scoped_refptr<TimingFunction> easing,
- const String& value,
- EffectModel::CompositeOperation composite)
- : Keyframe::PropertySpecificKeyframe(offset,
- std::move(easing),
- composite),
- value_(value) {}
-
bool IsSVGPropertySpecificKeyframe() const override { return true; }
String value_;
};
- protected:
- StringKeyframe()
- : css_property_map_(
- MutableCSSPropertyValueSet::Create(kHTMLStandardMode)),
- presentation_attribute_map_(
- MutableCSSPropertyValueSet::Create(kHTMLStandardMode)) {}
-
private:
- StringKeyframe(const StringKeyframe& copy_from);
-
Keyframe* Clone() const override;
Keyframe::PropertySpecificKeyframe* CreatePropertySpecificKeyframe(
const PropertyHandle&,
diff --git a/chromium/third_party/blink/renderer/core/animation/timing_calculations.h b/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
index 396a0cf0ae8..db759dc2e59 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
+++ b/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
@@ -50,18 +50,31 @@ static inline double MultiplyZeroAlwaysGivesZero(AnimationTimeDelta x,
return x.is_zero() || y == 0 ? 0 : (x * y).InSecondsF();
}
-static inline AnimationEffect::Phase CalculatePhase(double active_duration,
- double local_time,
- const Timing& specified) {
+// https://drafts.csswg.org/web-animations-1/#animation-effect-phases-and-states
+static inline AnimationEffect::Phase CalculatePhase(
+ double active_duration,
+ double local_time,
+ AnimationEffect::AnimationDirection direction,
+ const Timing& specified) {
DCHECK_GE(active_duration, 0);
if (IsNull(local_time))
return AnimationEffect::kPhaseNone;
- double end_time =
- specified.start_delay + active_duration + specified.end_delay;
- if (local_time < std::min(specified.start_delay, end_time))
+ double end_time = std::max(
+ specified.start_delay + active_duration + specified.end_delay, 0.0);
+ double before_active_boundary_time =
+ std::max(std::min(specified.start_delay, end_time), 0.0);
+ if (local_time < before_active_boundary_time ||
+ (local_time == before_active_boundary_time &&
+ direction == AnimationEffect::AnimationDirection::kBackwards)) {
return AnimationEffect::kPhaseBefore;
- if (local_time >= std::min(specified.start_delay + active_duration, end_time))
+ }
+ double active_after_boundary_time = std::max(
+ std::min(specified.start_delay + active_duration, end_time), 0.0);
+ if (local_time > active_after_boundary_time ||
+ (local_time == active_after_boundary_time &&
+ direction == AnimationEffect::AnimationDirection::kForwards)) {
return AnimationEffect::kPhaseAfter;
+ }
return AnimationEffect::kPhaseActive;
}
@@ -89,13 +102,12 @@ static inline double CalculateActiveTime(double active_duration,
AnimationEffect::Phase phase,
const Timing& specified) {
DCHECK_GE(active_duration, 0);
- DCHECK_EQ(phase, CalculatePhase(active_duration, local_time, specified));
switch (phase) {
case AnimationEffect::kPhaseBefore:
if (fill_mode == Timing::FillMode::BACKWARDS ||
fill_mode == Timing::FillMode::BOTH)
- return 0;
+ return std::max(local_time - specified.start_delay, 0.0);
return NullValue();
case AnimationEffect::kPhaseActive:
if (IsActiveInParentPhase(parent_phase, fill_mode))
@@ -103,9 +115,10 @@ static inline double CalculateActiveTime(double active_duration,
return NullValue();
case AnimationEffect::kPhaseAfter:
if (fill_mode == Timing::FillMode::FORWARDS ||
- fill_mode == Timing::FillMode::BOTH)
- return std::max(0.0, std::min(active_duration,
- active_duration + specified.end_delay));
+ fill_mode == Timing::FillMode::BOTH) {
+ return std::max(
+ 0.0, std::min(active_duration, local_time - specified.start_delay));
+ }
return NullValue();
case AnimationEffect::kPhaseNone:
DCHECK(IsNull(local_time));
diff --git a/chromium/third_party/blink/renderer/core/animation/timing_calculations_test.cc b/chromium/third_party/blink/renderer/core/animation/timing_calculations_test.cc
index 8e6ea85070f..116b427c632 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing_calculations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/timing_calculations_test.cc
@@ -55,6 +55,10 @@ TEST(AnimationTimingCalculationsTest, ActiveTime) {
EXPECT_EQ(0, CalculateActiveTime(20, Timing::FillMode::BOTH, 0,
AnimationEffect::kPhaseActive,
AnimationEffect::kPhaseBefore, timing));
+ timing.start_delay = -10;
+ EXPECT_EQ(5, CalculateActiveTime(20, Timing::FillMode::BACKWARDS, -5,
+ AnimationEffect::kPhaseActive,
+ AnimationEffect::kPhaseBefore, timing));
// Active Phase
timing.start_delay = 10;
diff --git a/chromium/third_party/blink/renderer/core/animation/transition_interpolation.h b/chromium/third_party/blink/renderer/core/animation/transition_interpolation.h
index 2eba87a952f..2ebada4f8c1 100644
--- a/chromium/third_party/blink/renderer/core/animation/transition_interpolation.h
+++ b/chromium/third_party/blink/renderer/core/animation/transition_interpolation.h
@@ -45,30 +45,11 @@ class CORE_EXPORT TransitionInterpolation : public Interpolation {
InterpolationValue&& end,
AnimatableValue* compositor_start,
AnimatableValue* compositor_end) {
- return new TransitionInterpolation(property, type, std::move(start),
- std::move(end), compositor_start,
- compositor_end);
+ return MakeGarbageCollected<TransitionInterpolation>(
+ property, type, std::move(start), std::move(end), compositor_start,
+ compositor_end);
}
- void Apply(StyleResolverState&) const;
-
- bool IsTransitionInterpolation() const final { return true; }
-
- const PropertyHandle& GetProperty() const final { return property_; }
-
- std::unique_ptr<TypedInterpolationValue> GetInterpolatedValue() const;
-
- AnimatableValue* GetInterpolatedCompositorValue() const;
-
- void Interpolate(int iteration, double fraction) final;
-
- void Trace(Visitor* visitor) override {
- visitor->Trace(compositor_start_);
- visitor->Trace(compositor_end_);
- Interpolation::Trace(visitor);
- }
-
- protected:
TransitionInterpolation(const PropertyHandle& property,
const InterpolationType& type,
InterpolationValue&& start,
@@ -95,6 +76,24 @@ class CORE_EXPORT TransitionInterpolation : public Interpolation {
property_.GetCSSProperty().IsCompositableProperty());
}
+ void Apply(StyleResolverState&) const;
+
+ bool IsTransitionInterpolation() const final { return true; }
+
+ const PropertyHandle& GetProperty() const final { return property_; }
+
+ std::unique_ptr<TypedInterpolationValue> GetInterpolatedValue() const;
+
+ AnimatableValue* GetInterpolatedCompositorValue() const;
+
+ void Interpolate(int iteration, double fraction) final;
+
+ void Trace(Visitor* visitor) override {
+ visitor->Trace(compositor_start_);
+ visitor->Trace(compositor_end_);
+ Interpolation::Trace(visitor);
+ }
+
private:
const InterpolableValue& CurrentInterpolableValue() const;
NonInterpolableValue* CurrentNonInterpolableValue() const;
diff --git a/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h b/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
index 768bdf86899..768f9a73f9f 100644
--- a/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
+++ b/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
@@ -22,8 +22,16 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
public:
static TransitionKeyframe* Create(const PropertyHandle& property) {
DCHECK(!property.IsSVGAttribute());
- return new TransitionKeyframe(property);
+ return MakeGarbageCollected<TransitionKeyframe>(property);
}
+
+ TransitionKeyframe(const PropertyHandle& property) : property_(property) {}
+ TransitionKeyframe(const TransitionKeyframe& copy_from)
+ : Keyframe(copy_from.offset_, copy_from.composite_, copy_from.easing_),
+ property_(copy_from.property_),
+ value_(copy_from.value_->Clone()),
+ compositor_value_(copy_from.compositor_value_) {}
+
void SetValue(std::unique_ptr<TypedInterpolationValue> value) {
// Speculative CHECK to help investigate crbug.com/826627. The theory is
// that |SetValue| is being called with a |value| that has no underlying
@@ -48,10 +56,22 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
EffectModel::CompositeOperation composite,
std::unique_ptr<TypedInterpolationValue> value,
AnimatableValue* compositor_value) {
- return new PropertySpecificKeyframe(offset, std::move(easing), composite,
- std::move(value), compositor_value);
+ return MakeGarbageCollected<PropertySpecificKeyframe>(
+ offset, std::move(easing), composite, std::move(value),
+ compositor_value);
}
+ PropertySpecificKeyframe(double offset,
+ scoped_refptr<TimingFunction> easing,
+ EffectModel::CompositeOperation composite,
+ std::unique_ptr<TypedInterpolationValue> value,
+ AnimatableValue* compositor_value)
+ : Keyframe::PropertySpecificKeyframe(offset,
+ std::move(easing),
+ composite),
+ value_(std::move(value)),
+ compositor_value_(compositor_value) {}
+
const AnimatableValue* GetAnimatableValue() const final {
return compositor_value_;
}
@@ -72,17 +92,6 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
void Trace(Visitor*) override;
private:
- PropertySpecificKeyframe(double offset,
- scoped_refptr<TimingFunction> easing,
- EffectModel::CompositeOperation composite,
- std::unique_ptr<TypedInterpolationValue> value,
- AnimatableValue* compositor_value)
- : Keyframe::PropertySpecificKeyframe(offset,
- std::move(easing),
- composite),
- value_(std::move(value)),
- compositor_value_(compositor_value) {}
-
Keyframe::PropertySpecificKeyframe* CloneWithOffset(
double offset) const final {
return Create(offset, easing_, composite_, value_->Clone(),
@@ -94,17 +103,11 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
};
private:
- TransitionKeyframe(const PropertyHandle& property) : property_(property) {}
-
- TransitionKeyframe(const TransitionKeyframe& copy_from)
- : Keyframe(copy_from.offset_, copy_from.composite_, copy_from.easing_),
- property_(copy_from.property_),
- value_(copy_from.value_->Clone()),
- compositor_value_(copy_from.compositor_value_) {}
-
bool IsTransitionKeyframe() const final { return true; }
- Keyframe* Clone() const final { return new TransitionKeyframe(*this); }
+ Keyframe* Clone() const final {
+ return MakeGarbageCollected<TransitionKeyframe>(*this);
+ }
Keyframe::PropertySpecificKeyframe* CreatePropertySpecificKeyframe(
const PropertyHandle&,
diff --git a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
index fc280aa2e75..4b73d0a4fd9 100644
--- a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
+++ b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
@@ -110,6 +110,19 @@ WorkletAnimationController::EnsureMainThreadMutatorDispatcher(
return mutator_dispatcher;
}
+// TODO(yigu): Currently one animator name is synced back per registration.
+// Eventually all registered names should be synced in batch once a module
+// completes its loading in the worklet scope. https://crbug.com/920722.
+void WorkletAnimationController::SynchronizeAnimatorName(
+ const String& animator_name) {
+ animator_names_.insert(animator_name);
+}
+
+bool WorkletAnimationController::IsAnimatorRegistered(
+ const String& animator_name) const {
+ return animator_names_.Contains(animator_name);
+}
+
void WorkletAnimationController::SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output_state) {
if (!output_state)
@@ -126,7 +139,8 @@ void WorkletAnimationController::MutateAnimations() {
if (!main_thread_mutator_client_)
return;
- main_thread_mutator_client_->Mutator()->Mutate(CollectAnimationStates());
+ main_thread_mutator_client_->Mutator()->MutateSynchronously(
+ CollectAnimationStates());
}
std::unique_ptr<AnimationWorkletDispatcherInput>
diff --git a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
index a20ebe8c28d..3b9bdb7774b 100644
--- a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
+++ b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
@@ -55,8 +55,17 @@ class CORE_EXPORT WorkletAnimationController
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
EnsureMainThreadMutatorDispatcher(
scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner);
+
void SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output) override;
+ void NotifyAnimationsPending() override {}
+ void NotifyAnimationsReady() override {}
+
+ void SynchronizeAnimatorName(const String& animator_name) override;
+ // Returns true if the animator with given name is registered in
+ // AnimationWorkletGlobalScope.
+ bool IsAnimatorRegistered(const String& animator_name) const;
+
void Trace(blink::Visitor*);
private:
@@ -67,6 +76,8 @@ class CORE_EXPORT WorkletAnimationController
HeapHashSet<Member<WorkletAnimationBase>> pending_animations_;
HeapHashMap<int, Member<WorkletAnimationBase>> animations_;
+ WTF::HashSet<String> animator_names_;
+
// TODO(yigu): The following proxy is needed for platform/ to access this
// class. We should bypass it eventually.
std::unique_ptr<MainThreadMutatorClient> main_thread_mutator_client_;
diff --git a/chromium/third_party/blink/renderer/core/aom/accessible_node.cc b/chromium/third_party/blink/renderer/core/aom/accessible_node.cc
index b90ae774577..d4b6f8a0c42 100644
--- a/chromium/third_party/blink/renderer/core/aom/accessible_node.cc
+++ b/chromium/third_party/blink/renderer/core/aom/accessible_node.cc
@@ -218,7 +218,7 @@ AccessibleNode::~AccessibleNode() = default;
// static
AccessibleNode* AccessibleNode::Create(Document& document) {
- return new AccessibleNode(document);
+ return MakeGarbageCollected<AccessibleNode>(document);
}
Document* AccessibleNode::GetDocument() const {
diff --git a/chromium/third_party/blink/renderer/core/aom/accessible_node_list.cc b/chromium/third_party/blink/renderer/core/aom/accessible_node_list.cc
index 87e0c616e91..602afc4e62d 100644
--- a/chromium/third_party/blink/renderer/core/aom/accessible_node_list.cc
+++ b/chromium/third_party/blink/renderer/core/aom/accessible_node_list.cc
@@ -16,7 +16,7 @@ static const unsigned kMaxItems = 65536;
// static
AccessibleNodeList* AccessibleNodeList::Create(
const HeapVector<Member<AccessibleNode>>& nodes) {
- AccessibleNodeList* result = new AccessibleNodeList();
+ AccessibleNodeList* result = MakeGarbageCollected<AccessibleNodeList>();
result->nodes_ = nodes;
return result;
}
diff --git a/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.cc b/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.cc
index fa71c7ed576..a2ece93a892 100644
--- a/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.cc
+++ b/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.cc
@@ -46,7 +46,8 @@ class ComputedAccessibleNodePromiseResolver::RequestAnimationFrameCallback final
ComputedAccessibleNodePromiseResolver*
ComputedAccessibleNodePromiseResolver::Create(ScriptState* script_state,
Element& element) {
- return new ComputedAccessibleNodePromiseResolver(script_state, element);
+ return MakeGarbageCollected<ComputedAccessibleNodePromiseResolver>(
+ script_state, element);
}
ComputedAccessibleNodePromiseResolver::ComputedAccessibleNodePromiseResolver(
@@ -109,7 +110,7 @@ void ComputedAccessibleNodePromiseResolver::UpdateTreeAndResolve() {
ComputedAccessibleNode* ComputedAccessibleNode::Create(AXID ax_id,
WebComputedAXTree* tree,
LocalFrame* frame) {
- return new ComputedAccessibleNode(ax_id, tree, frame);
+ return MakeGarbageCollected<ComputedAccessibleNode>(ax_id, tree, frame);
}
ComputedAccessibleNode::ComputedAccessibleNode(AXID ax_id,
diff --git a/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.h b/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.h
index d56b6725fae..bb415a1fe06 100644
--- a/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.h
+++ b/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.h
@@ -24,6 +24,8 @@ class ComputedAccessibleNodePromiseResolver final
: public GarbageCollectedFinalized<ComputedAccessibleNodePromiseResolver> {
public:
static ComputedAccessibleNodePromiseResolver* Create(ScriptState*, Element&);
+
+ ComputedAccessibleNodePromiseResolver(ScriptState*, Element&);
~ComputedAccessibleNodePromiseResolver() {}
ScriptPromise Promise();
@@ -32,7 +34,6 @@ class ComputedAccessibleNodePromiseResolver final
void Trace(blink::Visitor*);
private:
- ComputedAccessibleNodePromiseResolver(ScriptState*, Element&);
void UpdateTreeAndResolve();
class RequestAnimationFrameCallback;
@@ -48,6 +49,8 @@ class ComputedAccessibleNode : public ScriptWrappable {
public:
static ComputedAccessibleNode* Create(AXID, WebComputedAXTree*, LocalFrame*);
+
+ ComputedAccessibleNode(AXID, WebComputedAXTree*, LocalFrame*);
~ComputedAccessibleNode() override;
void Trace(Visitor*) override;
@@ -96,7 +99,6 @@ class ComputedAccessibleNode : public ScriptWrappable {
ScriptPromise ensureUpToDate(ScriptState*);
private:
- ComputedAccessibleNode(AXID, WebComputedAXTree*, LocalFrame*);
bool GetBoolAttribute(WebAOMBoolAttribute, bool& is_null) const;
int32_t GetIntAttribute(WebAOMIntAttribute, bool& is_null) const;
float GetFloatAttribute(WebAOMFloatAttribute, bool& is_null) const;
diff --git a/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.idl b/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.idl
index e8b62928fed..803e1c54b83 100644
--- a/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.idl
+++ b/chromium/third_party/blink/renderer/core/aom/computed_accessible_node.idl
@@ -49,5 +49,5 @@
readonly attribute ComputedAccessibleNode? previousSibling;
readonly attribute ComputedAccessibleNode? nextSibling;
- [CallWith=ScriptState] Promise ensureUpToDate();
+ [CallWith=ScriptState] Promise<any> ensureUpToDate();
};
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc b/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc
index d020720ebb9..9f2e9745600 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -349,12 +349,7 @@ void DataTransfer::setDragImage(Element* image, int x, int y) {
}
void DataTransfer::ClearDragImage() {
- if (!CanSetDragImage())
- return;
-
- drag_image_ = nullptr;
- drag_loc_ = IntPoint();
- drag_image_element_ = nullptr;
+ setDragImage(nullptr, nullptr, IntPoint());
}
void DataTransfer::SetDragImageResource(ImageResourceContent* img,
diff --git a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc
index a39e7856299..a889c15eef9 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -160,22 +160,15 @@ SkBitmap SystemClipboard::ReadImage(mojom::ClipboardBuffer buffer) {
return image;
}
-void SystemClipboard::WriteImage(Image* image,
- const KURL& url,
- const String& title) {
+void SystemClipboard::WriteImageWithTag(Image* image,
+ const KURL& url,
+ const String& title) {
DCHECK(image);
PaintImage paint_image = image->PaintImageForCurrentFrame();
SkBitmap bitmap;
if (sk_sp<SkImage> sk_image = paint_image.GetSkImage())
sk_image->asLegacyBitmap(&bitmap);
- if (bitmap.isNull())
- return;
-
- // TODO(piman): this should not be NULL, but it is. crbug.com/369621
- if (!bitmap.getPixels())
- return;
-
clipboard_->WriteImage(mojom::ClipboardBuffer::kStandard, bitmap);
if (url.IsValid() && !url.IsEmpty()) {
@@ -198,6 +191,11 @@ void SystemClipboard::WriteImage(Image* image,
clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard);
}
+void SystemClipboard::WriteImage(const SkBitmap& bitmap) {
+ clipboard_->WriteImage(mojom::ClipboardBuffer::kStandard, bitmap);
+ clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard);
+}
+
String SystemClipboard::ReadCustomData(const String& type) {
if (!IsValidBufferType(buffer_))
return String();
@@ -220,9 +218,7 @@ void SystemClipboard::WriteDataObject(DataObject* data_object) {
HashMap<String, String> custom_data;
WebDragData data = data_object->ToWebDragData();
- const WebVector<WebDragData::Item>& item_list = data.Items();
- for (size_t i = 0; i < item_list.size(); ++i) {
- const WebDragData::Item& item = item_list[i];
+ for (const WebDragData::Item& item : data.Items()) {
if (item.storage_type == WebDragData::Item::kStorageTypeString) {
if (item.string_type == blink::kMimeTypeTextPlain) {
clipboard_->WriteText(mojom::ClipboardBuffer::kStandard,
@@ -251,7 +247,7 @@ bool SystemClipboard::IsValidBufferType(mojom::ClipboardBuffer buffer) {
return true;
#else
// Chrome OS and non-X11 unix builds do not support
- // the X selection clipboad.
+ // the X selection clipboard.
// TODO: remove the need for this case, see http://crbug.com/361753
return false;
#endif
diff --git a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h
index e63b7646f01..ca65a4414ff 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h
+++ b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h
@@ -50,7 +50,10 @@ class CORE_EXPORT SystemClipboard {
String ReadRTF();
SkBitmap ReadImage(mojom::ClipboardBuffer);
- void WriteImage(Image*, const KURL&, const String& title);
+ // Write the image and its associated tag (bookmark/HTML types).
+ void WriteImageWithTag(Image*, const KURL&, const String& title);
+ // Write the image only.
+ void WriteImage(const SkBitmap&);
String ReadCustomData(const String& type);
void WriteDataObject(DataObject*);
diff --git a/chromium/third_party/blink/renderer/core/context_features/context_feature_settings.cc b/chromium/third_party/blink/renderer/core/context_features/context_feature_settings.cc
index f4cb020123d..48533e9795d 100644
--- a/chromium/third_party/blink/renderer/core/context_features/context_feature_settings.cc
+++ b/chromium/third_party/blink/renderer/core/context_features/context_feature_settings.cc
@@ -22,7 +22,7 @@ ContextFeatureSettings* ContextFeatureSettings::From(
ContextFeatureSettings* settings =
Supplement<ExecutionContext>::From<ContextFeatureSettings>(context);
if (!settings && creation_mode == CreationMode::kCreateIfNotExists) {
- settings = new ContextFeatureSettings(*context);
+ settings = MakeGarbageCollected<ContextFeatureSettings>(*context);
Supplement<ExecutionContext>::ProvideTo(*context, settings);
}
return settings;
diff --git a/chromium/third_party/blink/renderer/core/core_idl_files.gni b/chromium/third_party/blink/renderer/core/core_idl_files.gni
index 228aa27c1e6..9e3cff070dd 100644
--- a/chromium/third_party/blink/renderer/core/core_idl_files.gni
+++ b/chromium/third_party/blink/renderer/core/core_idl_files.gni
@@ -102,7 +102,6 @@ core_idl_files =
"css/cssom/style_property_map.idl",
"css/cssom/style_property_map_read_only.idl",
"display_lock/display_lock_context.idl",
- "display_lock/display_lock_suspended_handle.idl",
"dom/abort_controller.idl",
"dom/abort_signal.idl",
"dom/attr.idl",
@@ -160,10 +159,12 @@ core_idl_files =
"events/message_event.idl",
"events/mouse_event.idl",
"events/mutation_event.idl",
+ "events/overscroll_event.idl",
"events/page_transition_event.idl",
"events/picture_in_picture_control_event.idl",
"events/pointer_event.idl",
"events/pop_state_event.idl",
+ "events/portal_activate_event.idl",
"events/progress_event.idl",
"events/promise_rejection_event.idl",
"events/resource_progress_event.idl",
@@ -173,7 +174,7 @@ core_idl_files =
"events/transition_event.idl",
"events/ui_event.idl",
"events/wheel_event.idl",
- "feature_policy/policy.idl",
+ "feature_policy/feature_policy.idl",
"fetch/body.idl",
"fetch/headers.idl",
"fetch/request.idl",
@@ -288,6 +289,7 @@ core_idl_files =
"html/media/html_audio_element.idl",
"html/media/media_error.idl",
"html/portal/html_portal_element.idl",
+ "html/portal/portal_host.idl",
"html/track/audio_track_list.idl",
"html/track/html_track_element.idl",
"html/track/text_track.idl",
@@ -545,6 +547,7 @@ core_dependency_idl_files =
"fullscreen/document_fullscreen.idl",
"fullscreen/element_fullscreen.idl",
"html/html_hyperlink_element_utils.idl",
+ "html/portal/window_portal_host.idl",
"layout/custom/css_layout_worklet.idl",
"svg/svg_document.idl",
"svg/svg_filter_primitive_standard_attributes.idl",
@@ -610,6 +613,7 @@ core_dictionary_idl_files =
"dom/events/event_init.idl",
"dom/events/event_listener_options.idl",
"dom/events/event_modifier_init.idl",
+ "display_lock/display_lock_options.idl",
"events/animation_event_init.idl",
"events/animation_playback_event_init.idl",
"events/application_cache_error_event_init.idl",
@@ -623,6 +627,7 @@ core_dictionary_idl_files =
"events/keyboard_event_init.idl",
"events/message_event_init.idl",
"events/mouse_event_init.idl",
+ "events/overscroll_event_init.idl",
"events/page_transition_event_init.idl",
"events/picture_in_picture_control_event_init.idl",
"events/pointer_event_init.idl",
@@ -654,6 +659,8 @@ core_dictionary_idl_files =
"html/canvas/baselines.idl",
"html/canvas/image_data_color_settings.idl",
"html/canvas/image_encode_options.idl",
+ "html/custom/validity_state_flags.idl",
+ "html/forms/form_data_event_init.idl",
"html/track/track_event_init.idl",
"imagebitmap/image_bitmap_options.idl",
"input/input_device_capabilities_init.idl",
diff --git a/chromium/third_party/blink/renderer/core/css/BUILD.gn b/chromium/third_party/blink/renderer/core/css/BUILD.gn
index fe7c36aa421..a36316b2242 100644
--- a/chromium/third_party/blink/renderer/core/css/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/css/BUILD.gn
@@ -195,6 +195,9 @@ blink_core_sources("css") {
"css_viewport_rule.h",
"cssom/computed_style_property_map.cc",
"cssom/computed_style_property_map.h",
+ "cssom/cross_thread_style_value.h",
+ "cssom/cross_thread_unsupported_value.cc",
+ "cssom/cross_thread_unsupported_value.h",
"cssom/css_keyword_value.cc",
"cssom/css_keyword_value.h",
"cssom/css_math_invert.cc",
@@ -260,6 +263,10 @@ blink_core_sources("css") {
"cssom/element_computed_style_map.h",
"cssom/inline_style_property_map.cc",
"cssom/inline_style_property_map.h",
+ "cssom/paint_worklet_input.cc",
+ "cssom/paint_worklet_input.h",
+ "cssom/paint_worklet_style_property_map.cc",
+ "cssom/paint_worklet_style_property_map.h",
"cssom/prepopulated_computed_style_property_map.cc",
"cssom/prepopulated_computed_style_property_map.h",
"cssom/style_property_map.cc",
diff --git a/chromium/third_party/blink/renderer/core/css/css.dict b/chromium/third_party/blink/renderer/core/css/css.dict
index a7772b74d22..65727288bb2 100644
--- a/chromium/third_party/blink/renderer/core/css/css.dict
+++ b/chromium/third_party/blink/renderer/core/css/css.dict
@@ -918,6 +918,9 @@
"reset-size"
"dynamic"
"non-scaling-stroke"
+"no-preference"
+"light"
+"dark"
# at-rules
"@charset"
diff --git a/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc b/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc
index 163d827584a..38db457fa7f 100644
--- a/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/computed_style_css_value_mapping.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
@@ -199,7 +200,7 @@ CSSComputedStyleDeclaration::ComputableProperties() {
DEFINE_STATIC_LOCAL(Vector<const CSSProperty*>, properties, ());
if (properties.IsEmpty()) {
CSSProperty::FilterEnabledCSSPropertiesIntoVector(
- kComputedPropertyArray, arraysize(kComputedPropertyArray), properties);
+ kComputedPropertyArray, base::size(kComputedPropertyArray), properties);
}
return properties;
}
@@ -378,8 +379,9 @@ String CSSComputedStyleDeclaration::GetPropertyValue(
CSSPropertyID property_id) const {
// allow_visited_style_ is true only for access from DevTools.
if (!allow_visited_style_ && property_id == CSSPropertyWebkitAppearance) {
- UseCounter::Count(node_->GetDocument(),
- WebFeature::kGetComputedStyleWebkitAppearance);
+ UseCounter::Count(
+ node_->GetDocument(),
+ WebFeature::kGetComputedStyleForWebkitAppearanceExcludeDevTools);
}
const CSSValue* value = GetPropertyCSSValue(CSSProperty::Get(property_id));
if (value)
diff --git a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc
index 07a7419077b..2e124897d58 100644
--- a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc
@@ -45,7 +45,8 @@ namespace blink {
CSSDefaultStyleSheets& CSSDefaultStyleSheets::Instance() {
DEFINE_STATIC_LOCAL(Persistent<CSSDefaultStyleSheets>,
- css_default_style_sheets, (new CSSDefaultStyleSheets));
+ css_default_style_sheets,
+ (MakeGarbageCollected<CSSDefaultStyleSheets>()));
return *css_default_style_sheets;
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h
index 9bc119b7c20..bc67b935091 100644
--- a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h
+++ b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h
@@ -42,6 +42,8 @@ class CSSDefaultStyleSheets
public:
CORE_EXPORT static CSSDefaultStyleSheets& Instance();
+ CSSDefaultStyleSheets();
+
bool EnsureDefaultStyleSheetsForElement(const Element&);
void EnsureDefaultStyleSheetForFullscreen();
@@ -86,7 +88,6 @@ class CSSDefaultStyleSheets
void Trace(blink::Visitor*);
private:
- CSSDefaultStyleSheets();
void InitializeDefaultStyles();
Member<RuleSet> default_style_;
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_face.cc b/chromium/third_party/blink/renderer/core/css/css_font_face.cc
index 397dfeb7d69..841fc12e6a7 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_face.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_font_face.cc
@@ -43,10 +43,16 @@ void CSSFontFace::AddSource(CSSFontFaceSource* source) {
sources_.push_back(source);
}
-void CSSFontFace::SetSegmentedFontFace(
+void CSSFontFace::AddSegmentedFontFace(
CSSSegmentedFontFace* segmented_font_face) {
- DCHECK(!segmented_font_face_);
- segmented_font_face_ = segmented_font_face;
+ DCHECK(!segmented_font_faces_.Contains(segmented_font_face));
+ segmented_font_faces_.insert(segmented_font_face);
+}
+
+void CSSFontFace::RemoveSegmentedFontFace(
+ CSSSegmentedFontFace* segmented_font_face) {
+ DCHECK(segmented_font_faces_.Contains(segmented_font_face));
+ segmented_font_faces_.erase(segmented_font_face);
}
void CSSFontFace::DidBeginLoad() {
@@ -70,8 +76,8 @@ bool CSSFontFace::FontLoaded(RemoteFontFaceSource* source) {
}
}
- if (segmented_font_face_)
- segmented_font_face_->FontFaceInvalidated();
+ for (CSSSegmentedFontFace* segmented_font_face : segmented_font_faces_)
+ segmented_font_face->FontFaceInvalidated();
return true;
}
@@ -82,17 +88,21 @@ void CSSFontFace::SetDisplay(FontDisplay value) {
}
size_t CSSFontFace::ApproximateBlankCharacterCount() const {
- if (!sources_.IsEmpty() && sources_.front()->IsInBlockPeriod() &&
- segmented_font_face_)
- return segmented_font_face_->ApproximateCharacterCount();
- return 0;
+ if (sources_.IsEmpty() || !sources_.front()->IsInBlockPeriod())
+ return 0;
+ size_t approximate_character_count_ = 0;
+ for (CSSSegmentedFontFace* segmented_font_face : segmented_font_faces_) {
+ approximate_character_count_ +=
+ segmented_font_face->ApproximateCharacterCount();
+ }
+ return approximate_character_count_;
}
bool CSSFontFace::FallbackVisibilityChanged(RemoteFontFaceSource* source) {
if (!IsValid() || source != sources_.front())
return false;
- if (segmented_font_face_)
- segmented_font_face_->FontFaceInvalidated();
+ for (CSSSegmentedFontFace* segmented_font_face : segmented_font_faces_)
+ segmented_font_face->FontFaceInvalidated();
return true;
}
@@ -113,8 +123,7 @@ scoped_refptr<SimpleFontData> CSSFontFace::GetFontData(
return nullptr;
if (scoped_refptr<SimpleFontData> result = source->GetFontData(
- font_description,
- segmented_font_face_->GetFontSelectionCapabilities())) {
+ font_description, font_face_->GetFontSelectionCapabilities())) {
// The active source may already be loading or loaded. Adjust our
// FontFace status accordingly.
if (LoadStatus() == FontFace::kUnloaded &&
@@ -202,7 +211,7 @@ void CSSFontFace::SetLoadStatus(FontFace::LoadStatusType new_status) {
else
font_face_->SetLoadStatus(new_status);
- if (!segmented_font_face_ || !font_face_->GetExecutionContext())
+ if (segmented_font_faces_.IsEmpty() || !font_face_->GetExecutionContext())
return;
if (auto* document = DynamicTo<Document>(font_face_->GetExecutionContext())) {
@@ -216,7 +225,7 @@ void CSSFontFace::SetLoadStatus(FontFace::LoadStatusType new_status) {
}
void CSSFontFace::Trace(blink::Visitor* visitor) {
- visitor->Trace(segmented_font_face_);
+ visitor->Trace(segmented_font_faces_);
visitor->Trace(sources_);
visitor->Trace(font_face_);
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_face.h b/chromium/third_party/blink/renderer/core/css/css_font_face.h
index 3ded0f27c87..94a98ee3b89 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_face.h
+++ b/chromium/third_party/blink/renderer/core/css/css_font_face.h
@@ -51,7 +51,6 @@ class CORE_EXPORT CSSFontFace final
public:
CSSFontFace(FontFace* font_face, Vector<UnicodeRange>& ranges)
: ranges_(base::AdoptRef(new UnicodeRangeSet(ranges))),
- segmented_font_face_(nullptr),
font_face_(font_face) {
DCHECK(font_face_);
}
@@ -60,8 +59,8 @@ class CORE_EXPORT CSSFontFace final
scoped_refptr<UnicodeRangeSet> Ranges() { return ranges_; }
- void SetSegmentedFontFace(CSSSegmentedFontFace*);
- void ClearSegmentedFontFace() { segmented_font_face_ = nullptr; }
+ void AddSegmentedFontFace(CSSSegmentedFontFace*);
+ void RemoveSegmentedFontFace(CSSSegmentedFontFace*);
bool IsValid() const { return !sources_.IsEmpty(); }
size_t ApproximateBlankCharacterCount() const;
@@ -91,7 +90,7 @@ class CORE_EXPORT CSSFontFace final
void SetLoadStatus(FontFace::LoadStatusType);
scoped_refptr<UnicodeRangeSet> ranges_;
- Member<CSSSegmentedFontFace> segmented_font_face_;
+ HeapHashSet<Member<CSSSegmentedFontFace>> segmented_font_faces_;
HeapDeque<Member<CSSFontFaceSource>> sources_;
Member<FontFace> font_face_;
DISALLOW_COPY_AND_ASSIGN(CSSFontFace);
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_face_source.cc b/chromium/third_party/blink/renderer/core/css/css_font_face_source.cc
index a924d627902..331efc1e28e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_face_source.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_font_face_source.cc
@@ -58,7 +58,9 @@ scoped_refptr<SimpleFontData> CSSFontFaceSource::GetFontData(
return CreateFontData(font_description, font_selection_capabilities);
}
- FontCacheKey key = font_description.CacheKey(FontFaceCreationParams());
+ bool is_unique_match = false;
+ FontCacheKey key =
+ font_description.CacheKey(FontFaceCreationParams(), is_unique_match);
// Get or create the font data. Take care to avoid dangling references into
// font_data_table_, because it is modified below during pruning.
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_face_source_test.cc b/chromium/third_party/blink/renderer/core/css/css_font_face_source_test.cc
index 3ff7e0c0e78..62ffbf43a47 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_face_source_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_font_face_source_test.cc
@@ -42,7 +42,9 @@ unsigned SimulateHashCalculation(float size) {
FontDescription font_description;
font_description.SetSizeAdjust(size);
font_description.SetAdjustedSize(size);
- return font_description.CacheKey(FontFaceCreationParams()).GetHash();
+ bool is_unique_match = false;
+ return font_description.CacheKey(FontFaceCreationParams(), is_unique_match)
+ .GetHash();
}
}
@@ -50,9 +52,9 @@ TEST(CSSFontFaceSourceTest, HashCollision) {
DummyFontFaceSource font_face_source;
// Even if the hash value collide, fontface cache should return different
// value for different fonts.
- EXPECT_EQ(SimulateHashCalculation(527), SimulateHashCalculation(3099));
- EXPECT_NE(font_face_source.GetFontDataForSize(527),
- font_face_source.GetFontDataForSize(3099));
+ EXPECT_EQ(SimulateHashCalculation(6009), SimulateHashCalculation(8634));
+ EXPECT_NE(font_face_source.GetFontDataForSize(6009),
+ font_face_source.GetFontDataForSize(8634));
}
// Exercises the size font_data_table_ assertions in CSSFontFaceSource.
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc b/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc
index c1843a36109..3db4ccb0308 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc
@@ -25,6 +25,8 @@
#include "third_party/blink/renderer/core/css/css_font_face_src_value.h"
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/css/css_markup.h"
#include "third_party/blink/renderer/core/css/style_sheet_contents.h"
@@ -88,8 +90,10 @@ FontResource& CSSFontFaceSrcValue::Fetch(ExecutionContext* context,
ResourceLoaderOptions options;
options.initiator_info.name = fetch_initiator_type_names::kCSS;
FetchParameters params(resource_request, options);
- if (RuntimeEnabledFeatures::WebFontsCacheAwareTimeoutAdaptationEnabled())
+ if (base::FeatureList::IsEnabled(
+ features::kWebFontsCacheAwareTimeoutAdaption)) {
params.SetCacheAwareLoadingEnabled(kIsCacheAwareLoadingEnabled);
+ }
params.SetContentSecurityCheck(should_check_content_security_policy_);
const SecurityOrigin* security_origin = context->GetSecurityOrigin();
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_feature_values_rule.h b/chromium/third_party/blink/renderer/core/css/css_font_feature_values_rule.h
index a70caec1ee7..679fa25561d 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_feature_values_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/css_font_feature_values_rule.h
@@ -18,9 +18,10 @@ class CSSFontFeatureValuesRule final : public CSSRule {
public:
static CSSFontFeatureValuesRule* Create(StyleRuleFontFeatureValues* rule,
CSSStyleSheet* sheet) {
- return new CSSFontFeatureValuesRule(rule, sheet);
+ return MakeGarbageCollected<CSSFontFeatureValuesRule>(rule, sheet);
}
+ CSSFontFeatureValuesRule(StyleRuleFontFeatureValues*, CSSStyleSheet* parent);
~CSSFontFeatureValuesRule() override;
void setFontFamily(const String& font_family);
@@ -38,8 +39,6 @@ class CSSFontFeatureValuesRule final : public CSSRule {
void Trace(blink::Visitor*) override;
private:
- CSSFontFeatureValuesRule(StyleRuleFontFeatureValues*, CSSStyleSheet* parent);
-
CSSRule::Type type() const override { return kFontFeatureValuesRule; }
Member<StyleRuleFontFeatureValues> font_feature_values_rule_;
diff --git a/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc b/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc
index 8e7d83f0d31..e21002978bb 100644
--- a/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc
@@ -29,6 +29,8 @@
#include <algorithm>
#include <tuple>
#include <utility>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/css_calculation_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
@@ -1203,7 +1205,7 @@ FloatSize RadiusToCorner(const FloatPoint& point,
unsigned corner_index = 0;
float distance = (point - corners[corner_index]).DiagonalLength();
- for (unsigned i = 1; i < arraysize(corners); ++i) {
+ for (unsigned i = 1; i < base::size(corners); ++i) {
float new_distance = (point - corners[i]).DiagonalLength();
if (compare(new_distance, distance)) {
corner_index = i;
diff --git a/chromium/third_party/blink/renderer/core/css/css_image_value.cc b/chromium/third_party/blink/renderer/core/css/css_image_value.cc
index ac9305000c7..7627124ae7b 100644
--- a/chromium/third_party/blink/renderer/core/css/css_image_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_image_value.cc
@@ -78,11 +78,16 @@ StyleImage* CSSImageValue::CacheImage(
document.GetFrame()->IsClientLoFiAllowed(params.GetResourceRequest())) {
params.SetClientLoFiPlaceholder();
}
- cached_image_ = StyleFetchedImage::Create(
- document, params,
- image_request_optimization == FetchParameters::kDeferImageLoad);
+ bool is_lazily_loaded =
+ image_request_optimization == FetchParameters::kDeferImageLoad &&
+ // Only http/https images are eligible to be lazily loaded.
+ params.Url().ProtocolIsInHTTPFamily();
+ if (is_lazily_loaded)
+ params.SetLazyImageDeferred();
+
+ cached_image_ =
+ StyleFetchedImage::Create(document, params, is_lazily_loaded);
}
-
return cached_image_.Get();
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_keyframe_rule.h b/chromium/third_party/blink/renderer/core/css/css_keyframe_rule.h
index df8f03f392f..0b3332ff5cf 100644
--- a/chromium/third_party/blink/renderer/core/css/css_keyframe_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/css_keyframe_rule.h
@@ -56,8 +56,8 @@ class CSSKeyframeRule final : public CSSRule {
private:
CSSRule::Type type() const override { return kKeyframeRule; }
- Member<StyleRuleKeyframe> keyframe_;
- mutable Member<KeyframeStyleRuleCSSStyleDeclaration>
+ TraceWrapperMember<StyleRuleKeyframe> keyframe_;
+ mutable TraceWrapperMember<KeyframeStyleRuleCSSStyleDeclaration>
properties_cssom_wrapper_;
friend class CSSKeyframesRule;
diff --git a/chromium/third_party/blink/renderer/core/css/css_keyframes_rule.h b/chromium/third_party/blink/renderer/core/css/css_keyframes_rule.h
index e9db4179268..8b2f17e9394 100644
--- a/chromium/third_party/blink/renderer/core/css/css_keyframes_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/css_keyframes_rule.h
@@ -122,9 +122,10 @@ class CSSKeyframesRule final : public CSSRule {
private:
CSSRule::Type type() const override { return kKeyframesRule; }
- Member<StyleRuleKeyframes> keyframes_rule_;
- mutable HeapVector<Member<CSSKeyframeRule>> child_rule_cssom_wrappers_;
- mutable Member<CSSRuleList> rule_list_cssom_wrapper_;
+ TraceWrapperMember<StyleRuleKeyframes> keyframes_rule_;
+ mutable HeapVector<TraceWrapperMember<CSSKeyframeRule>>
+ child_rule_cssom_wrappers_;
+ mutable TraceWrapperMember<CSSRuleList> rule_list_cssom_wrapper_;
bool is_prefixed_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_properties.json5 b/chromium/third_party/blink/renderer/core/css/css_properties.json5
index 9a6fcd2c5f5..316e06a0629 100644
--- a/chromium/third_party/blink/renderer/core/css/css_properties.json5
+++ b/chromium/third_party/blink/renderer/core/css/css_properties.json5
@@ -2884,7 +2884,7 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
svg: true,
- converter: "ConvertColor",
+ converter: "ConvertStyleColor",
keywords: ["currentcolor"],
typedom_types: ["Keyword"],
},
@@ -3961,9 +3961,9 @@
property_methods: ["CSSValueFromComputedStyleInternal"],
independent: true,
inherited: true,
- field_template: "keyword",
+ field_template: "multi_keyword", // We use a bitflag field due peformance issues
keywords: [
- "normal", "pre", "pre-wrap", "pre-line", "nowrap", "-webkit-nowrap"
+ "none", "normal", "pre", "pre-wrap", "pre-line", "nowrap", "-webkit-nowrap", "break-spaces"
],
typedom_types: ["Keyword"],
default_value: "normal",
@@ -4476,9 +4476,9 @@
{
name: "animation",
longhands: [
- "animation-name", "animation-duration", "animation-timing-function",
- "animation-delay", "animation-iteration-count", "animation-direction",
- "animation-fill-mode", "animation-play-state"
+ "animation-duration", "animation-timing-function", "animation-delay",
+ "animation-iteration-count", "animation-direction",
+ "animation-fill-mode", "animation-play-state", "animation-name"
],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
},
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_name.cc b/chromium/third_party/blink/renderer/core/css/css_property_name.cc
index a268c6772e3..6aa0bbc3bb6 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_name.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_property_name.cc
@@ -21,6 +21,14 @@ static_assert(sizeof(CSSPropertyName) == sizeof(SameSizeAsCSSPropertyName),
} // namespace
+bool CSSPropertyName::operator==(const CSSPropertyName& other) const {
+ if (property_id_ != other.property_id_)
+ return false;
+ if (property_id_ != CSSPropertyVariable)
+ return true;
+ return custom_property_name_ == other.custom_property_name_;
+}
+
AtomicString CSSPropertyName::ToAtomicString() const {
if (IsCustomProperty())
return custom_property_name_;
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_name.h b/chromium/third_party/blink/renderer/core/css/css_property_name.h
index 517dd73599d..e7c2433c76a 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_name.h
+++ b/chromium/third_party/blink/renderer/core/css/css_property_name.h
@@ -5,8 +5,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_NAME_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_NAME_H_
+#include "base/optional.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
namespace blink {
@@ -28,6 +30,20 @@ class CORE_EXPORT CSSPropertyName {
DCHECK(!custom_property_name.IsNull());
}
+ static base::Optional<CSSPropertyName> From(const String& value) {
+ const CSSPropertyID property_id = cssPropertyID(value);
+ if (property_id == CSSPropertyInvalid)
+ return base::nullopt;
+ if (property_id == CSSPropertyVariable)
+ return base::make_optional(CSSPropertyName(AtomicString(value)));
+ return base::make_optional(CSSPropertyName(property_id));
+ }
+
+ bool operator==(const CSSPropertyName&) const;
+ bool operator!=(const CSSPropertyName& other) const {
+ return !(*this == other);
+ }
+
CSSPropertyID Id() const { return property_id_; }
bool IsCustomProperty() const { return property_id_ == CSSPropertyVariable; }
@@ -41,4 +57,6 @@ class CORE_EXPORT CSSPropertyName {
} // namespace blink
+WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::CSSPropertyName);
+
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_NAME_H_
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_name_test.cc b/chromium/third_party/blink/renderer/core/css/css_property_name_test.cc
index 7dd12abe1dc..5feb4906ecb 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_name_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_property_name_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/properties/css_property.h"
namespace blink {
@@ -28,4 +29,28 @@ TEST(CSSPropertyNameTest, GetNameCustomProperty) {
EXPECT_EQ(AtomicString("--x"), name.ToAtomicString());
}
+TEST(CSSPropertyNameTest, OperatorEquals) {
+ EXPECT_EQ(CSSPropertyName("--x"), CSSPropertyName("--x"));
+ EXPECT_EQ(CSSPropertyName(CSSPropertyColor),
+ CSSPropertyName(CSSPropertyColor));
+ EXPECT_NE(CSSPropertyName("--x"), CSSPropertyName("--y"));
+ EXPECT_NE(CSSPropertyName(CSSPropertyColor),
+ CSSPropertyName(CSSPropertyBackgroundColor));
+}
+
+TEST(CSSPropertyNameTest, From) {
+ EXPECT_TRUE(CSSPropertyName::From("color"));
+ EXPECT_TRUE(CSSPropertyName::From("--x"));
+ EXPECT_FALSE(CSSPropertyName::From("notaproperty"));
+ EXPECT_FALSE(CSSPropertyName::From("-not-a-property"));
+
+ EXPECT_EQ(*CSSPropertyName::From("color"), CSSPropertyName(CSSPropertyColor));
+ EXPECT_EQ(*CSSPropertyName::From("--x"), CSSPropertyName("--x"));
+}
+
+TEST(CSSPropertyNameTest, FromNativeCSSProperty) {
+ CSSPropertyName name = GetCSSPropertyFontSize().GetCSSPropertyName();
+ EXPECT_EQ(CSSPropertyName(CSSPropertyFontSize), name);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_quad_value.h b/chromium/third_party/blink/renderer/core/css/css_quad_value.h
index dc6718c1f88..eebf3f0bea4 100644
--- a/chromium/third_party/blink/renderer/core/css/css_quad_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_quad_value.h
@@ -39,6 +39,11 @@ class CORE_EXPORT CSSQuadValue : public CSSValue {
return MakeGarbageCollected<CSSQuadValue>(top, right, bottom, left,
serialization_type);
}
+ static CSSQuadValue* Create(CSSValue* value,
+ TypeForSerialization serialization_type) {
+ return MakeGarbageCollected<CSSQuadValue>(value, value, value, value,
+ serialization_type);
+ }
CSSQuadValue(CSSValue* top,
CSSValue* right,
diff --git a/chromium/third_party/blink/renderer/core/css/css_segmented_font_face.cc b/chromium/third_party/blink/renderer/core/css/css_segmented_font_face.cc
index 9bb9c5df126..3a67864fc52 100644
--- a/chromium/third_party/blink/renderer/core/css/css_segmented_font_face.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_segmented_font_face.cc
@@ -67,7 +67,7 @@ void CSSSegmentedFontFace::FontFaceInvalidated() {
void CSSSegmentedFontFace::AddFontFace(FontFace* font_face,
bool css_connected) {
PruneTable();
- font_face->CssFontFace()->SetSegmentedFontFace(this);
+ font_face->CssFontFace()->AddSegmentedFontFace(this);
if (css_connected) {
font_faces_.InsertBefore(first_non_css_connected_face_, font_face);
} else {
@@ -88,7 +88,7 @@ void CSSSegmentedFontFace::RemoveFontFace(FontFace* font_face) {
font_faces_.erase(it);
PruneTable();
- font_face->CssFontFace()->ClearSegmentedFontFace();
+ font_face->CssFontFace()->RemoveSegmentedFontFace(this);
}
scoped_refptr<FontData> CSSSegmentedFontFace::GetFontData(
@@ -98,8 +98,9 @@ scoped_refptr<FontData> CSSSegmentedFontFace::GetFontData(
const FontSelectionRequest& font_selection_request =
font_description.GetFontSelectionRequest();
- FontCacheKey key = font_description.CacheKey(FontFaceCreationParams(),
- font_selection_request);
+ bool is_unique_match = false;
+ FontCacheKey key = font_description.CacheKey(
+ FontFaceCreationParams(), is_unique_match, font_selection_request);
scoped_refptr<SegmentedFontData>& font_data =
font_data_table_.insert(key, nullptr).stored_value->value;
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector.cc b/chromium/third_party/blink/renderer/core/css/css_selector.cc
index 8b651b9b6d0..e07bcc48aff 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_selector.cc
@@ -28,6 +28,8 @@
#include <algorithm>
#include <memory>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/css_markup.h"
#include "third_party/blink/renderer/core/css/css_selector_list.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
@@ -419,11 +421,11 @@ static CSSSelector::PseudoType NameToPseudoType(const AtomicString& name,
if (has_arguments) {
pseudo_type_map = kPseudoTypeWithArgumentsMap;
pseudo_type_map_end =
- kPseudoTypeWithArgumentsMap + arraysize(kPseudoTypeWithArgumentsMap);
+ kPseudoTypeWithArgumentsMap + base::size(kPseudoTypeWithArgumentsMap);
} else {
pseudo_type_map = kPseudoTypeWithoutArgumentsMap;
pseudo_type_map_end = kPseudoTypeWithoutArgumentsMap +
- arraysize(kPseudoTypeWithoutArgumentsMap);
+ base::size(kPseudoTypeWithoutArgumentsMap);
}
const NameToPseudoStruct* match = std::lower_bound(
pseudo_type_map, pseudo_type_map_end, name,
@@ -1042,6 +1044,25 @@ bool CSSSelector::IsTreeAbidingPseudoElement() const {
GetPseudoType() == kPseudoPlaceholder);
}
+bool CSSSelector::IsAllowedAfterPart() const {
+ if (Match() != CSSSelector::kPseudoElement) {
+ return false;
+ }
+ // Everything that makes sense should work following ::part. This whitelist
+ // restricts it to what has been tested.
+ switch (GetPseudoType()) {
+ case kPseudoBefore:
+ case kPseudoAfter:
+ case kPseudoPlaceholder:
+ case kPseudoFirstLine:
+ case kPseudoFirstLetter:
+ case kPseudoSelection:
+ return true;
+ default:
+ return false;
+ }
+}
+
template <typename Functor>
static bool ForAnyInTagHistory(const Functor& functor,
const CSSSelector& selector) {
@@ -1086,6 +1107,13 @@ bool CSSSelector::HasDeepCombinatorOrShadowPseudo() const {
*this);
}
+bool CSSSelector::FollowsPart() const {
+ const CSSSelector* previous = TagHistory();
+ if (!previous)
+ return false;
+ return previous->GetPseudoType() == kPseudoPart;
+}
+
bool CSSSelector::NeedsUpdatedDistribution() const {
return ForAnyInTagHistory(
[](const CSSSelector& selector) -> bool {
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector.h b/chromium/third_party/blink/renderer/core/css/css_selector.h
index 72f1d831db9..619f661cb76 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector.h
+++ b/chromium/third_party/blink/renderer/core/css/css_selector.h
@@ -381,10 +381,13 @@ class CORE_EXPORT CSSSelector {
bool MatchesPseudoElement() const;
bool IsTreeAbidingPseudoElement() const;
+ bool IsAllowedAfterPart() const;
bool HasContentPseudo() const;
bool HasSlottedPseudo() const;
bool HasDeepCombinatorOrShadowPseudo() const;
+ // Returns true if the immediately preceeding simple selector is ::part.
+ bool FollowsPart() const;
bool NeedsUpdatedDistribution() const;
bool HasPseudoIs() const;
bool HasPseudoWhere() const;
diff --git a/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc b/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc
index eba408502a8..d0d5e609d86 100644
--- a/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc
@@ -21,6 +21,8 @@
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/bindings/core/v8/media_list_or_string.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/css/css_import_rule.h"
#include "third_party/blink/renderer/core/css/css_rule_list.h"
@@ -41,6 +43,7 @@
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/svg/svg_style_element.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -93,20 +96,25 @@ const Document* CSSStyleSheet::SingleOwnerDocument(
}
CSSStyleSheet* CSSStyleSheet::Create(Document& document,
+ ExceptionState& exception_state) {
+ return CSSStyleSheet::Create(document, CSSStyleSheetInit::Create(),
+ exception_state);
+}
+
+CSSStyleSheet* CSSStyleSheet::Create(Document& document,
const CSSStyleSheetInit* options,
ExceptionState& exception_state) {
- if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled()) {
- exception_state.ThrowTypeError("Illegal constructor");
- return nullptr;
- }
// Folowing steps at spec draft
// https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-cssstylesheet
CSSParserContext* parser_context = CSSParserContext::Create(document);
StyleSheetContents* contents = StyleSheetContents::Create(parser_context);
CSSStyleSheet* sheet = MakeGarbageCollected<CSSStyleSheet>(contents, nullptr);
+ sheet->SetAssociatedDocument(&document);
+ sheet->SetIsConstructed(true);
sheet->SetTitle(options->title());
sheet->ClearOwnerNode();
sheet->ClearOwnerRule();
+ contents->RegisterClient(sheet);
scoped_refptr<MediaQuerySet> media_query_set;
if (options->media().IsString())
media_query_set = MediaQuerySet::Create(options->media().GetAsString());
@@ -147,8 +155,8 @@ CSSStyleSheet* CSSStyleSheet::CreateInline(Node& owner_node,
const WTF::TextEncoding& encoding) {
CSSParserContext* parser_context = CSSParserContext::Create(
owner_node.GetDocument(), owner_node.GetDocument().BaseURL(),
- false /* is_opaque_response_from_service_worker */,
- owner_node.GetDocument().GetReferrerPolicy(), encoding);
+ true /* origin_clean */, owner_node.GetDocument().GetReferrerPolicy(),
+ encoding);
StyleSheetContents* sheet =
StyleSheetContents::Create(base_url.GetString(), parser_context);
return MakeGarbageCollected<CSSStyleSheet>(sheet, owner_node, true,
@@ -318,30 +326,7 @@ void CSSStyleSheet::ClearOwnerNode() {
}
bool CSSStyleSheet::CanAccessRules() const {
- if (enable_rule_access_for_inspector_)
- return true;
-
- // Opaque responses should never be accessible, mod DevTools. See comments for
- // IsOpaqueResponseFromServiceWorker().
- if (contents_->IsOpaqueResponseFromServiceWorker())
- return false;
-
- if (is_inline_stylesheet_)
- return true;
- KURL base_url = contents_->BaseURL();
- if (base_url.IsEmpty())
- return true;
- Document* document = OwnerDocument();
- if (!document)
- return true;
- if (document->GetSecurityOrigin()->CanReadContent(base_url))
- return true;
- if (allow_rule_access_from_origin_ &&
- document->GetSecurityOrigin()->CanAccess(
- allow_rule_access_from_origin_.get())) {
- return true;
- }
- return false;
+ return enable_rule_access_for_inspector_ || contents_->IsOriginClean();
}
CSSRuleList* CSSStyleSheet::rules(ExceptionState& exception_state) {
@@ -357,6 +342,14 @@ unsigned CSSStyleSheet::insertRule(const String& rule_string,
return 0;
}
+ if (is_constructed_ && resolver_) {
+ // We can't access rules on a constructed stylesheet if it's still waiting
+ // for some imports to load (|resolver_| is still set).
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Can't modify rules while the sheet is waiting for some @imports.");
+ return 0;
+ }
DCHECK(child_rule_cssom_wrappers_.IsEmpty() ||
child_rule_cssom_wrappers_.size() == contents_->RuleCount());
@@ -380,6 +373,12 @@ unsigned CSSStyleSheet::insertRule(const String& rule_string,
return 0;
}
RuleMutationScope mutation_scope(this);
+ if (rule->IsImportRule() && is_constructed_) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Can't insert @import rules to a constructed stylesheet.");
+ return 0;
+ }
bool success = contents_->WrapperInsertRule(rule, index);
if (!success) {
if (rule->IsNamespaceRule())
@@ -405,6 +404,15 @@ void CSSStyleSheet::deleteRule(unsigned index,
return;
}
+ if (is_constructed_ && resolver_) {
+ // We can't access rules on a constructed stylesheet if it's still waiting
+ // for some imports to load (|resolver_| is still set).
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Can't modify rules while the sheet is waiting for some @imports.");
+ return;
+ }
+
DCHECK(child_rule_cssom_wrappers_.IsEmpty() ||
child_rule_cssom_wrappers_.size() == contents_->RuleCount());
@@ -455,6 +463,45 @@ int CSSStyleSheet::addRule(const String& selector,
return addRule(selector, style, length(), exception_state);
}
+ScriptPromise CSSStyleSheet::replace(ScriptState* script_state,
+ const String& text,
+ ExceptionState& exception_state) {
+ if (!is_constructed_) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Can't call replace on non-constructed CSSStyleSheets.");
+ }
+ // Parses the text synchronously, loads import rules asynchronously.
+ SetText(text, true /* allow_import_rules */, exception_state);
+ if (!IsLoading())
+ return ScriptPromise::Cast(script_state, ToV8(this, script_state));
+ resolver_ = ScriptPromiseResolver::Create(script_state);
+ return resolver_->Promise();
+}
+
+void CSSStyleSheet::replaceSync(const String& text,
+ ExceptionState& exception_state) {
+ if (!is_constructed_) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Can't call replaceSync on non-constructed CSSStyleSheets.");
+ }
+ SetText(text, false /* allow_import_rules */, exception_state);
+}
+
+void CSSStyleSheet::ResolveReplacePromiseIfNeeded(bool load_error_occured) {
+ if (!resolver_)
+ return;
+ if (load_error_occured) {
+ resolver_->Reject(DOMException::Create(DOMExceptionCode::kNotAllowedError,
+ "Loading @imports failed."));
+ } else {
+ resolver_->Resolve(this);
+ }
+ resolver_ = nullptr;
+ DidMutateRules();
+}
+
CSSRuleList* CSSStyleSheet::cssRules(ExceptionState& exception_state) {
if (!CanAccessRules()) {
exception_state.ThrowSecurityError("Cannot access rules");
@@ -496,17 +543,14 @@ CSSStyleSheet* CSSStyleSheet::parentStyleSheet() const {
}
Document* CSSStyleSheet::OwnerDocument() const {
+ if (is_constructed_)
+ return associated_document_;
const CSSStyleSheet* root = this;
while (root->parentStyleSheet())
root = root->parentStyleSheet();
return root->ownerNode() ? &root->ownerNode()->GetDocument() : nullptr;
}
-void CSSStyleSheet::SetAllowRuleAccessFromOrigin(
- scoped_refptr<const SecurityOrigin> allowed_origin) {
- allow_rule_access_from_origin_ = std::move(allowed_origin);
-}
-
bool CSSStyleSheet::SheetLoaded() {
DCHECK(owner_node_);
SetLoadCompleted(owner_node_->SheetLoaded());
@@ -594,6 +638,7 @@ void CSSStyleSheet::Trace(blink::Visitor* visitor) {
visitor->Trace(rule_list_cssom_wrapper_);
visitor->Trace(adopted_tree_scopes_);
visitor->Trace(associated_document_);
+ visitor->Trace(resolver_);
StyleSheet::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_style_sheet.h b/chromium/third_party/blink/renderer/core/css/css_style_sheet.h
index 51d77f9a018..01f6a96292a 100644
--- a/chromium/third_party/blink/renderer/core/css/css_style_sheet.h
+++ b/chromium/third_party/blink/renderer/core/css/css_style_sheet.h
@@ -44,7 +44,9 @@ class CSSStyleSheetInit;
class Document;
class ExceptionState;
class MediaQuerySet;
-class SecurityOrigin;
+class ScriptPromise;
+class ScriptPromiseResolver;
+class ScriptState;
class StyleSheetContents;
class CORE_EXPORT CSSStyleSheet final : public StyleSheet {
@@ -53,6 +55,7 @@ class CORE_EXPORT CSSStyleSheet final : public StyleSheet {
public:
static const Document* SingleOwnerDocument(const CSSStyleSheet*);
+ static CSSStyleSheet* Create(Document&, ExceptionState&);
static CSSStyleSheet* Create(Document&,
const CSSStyleSheetInit*,
ExceptionState&);
@@ -100,6 +103,12 @@ class CORE_EXPORT CSSStyleSheet final : public StyleSheet {
deleteRule(index, exception_state);
}
+ ScriptPromise replace(ScriptState* script_state,
+ const String& text,
+ ExceptionState&);
+ void replaceSync(const String& text, ExceptionState&);
+ void ResolveReplacePromiseIfNeeded(bool load_error_occured);
+
// For CSSRuleList.
unsigned length() const;
CSSRule* item(unsigned index);
@@ -126,10 +135,6 @@ class CORE_EXPORT CSSStyleSheet final : public StyleSheet {
return device_dependent_media_query_results_;
}
void SetTitle(const String& title) { title_ = title; }
- // Set by LinkStyle iff CORS-enabled fetch of stylesheet succeeded from this
- // origin.
- void SetAllowRuleAccessFromOrigin(
- scoped_refptr<const SecurityOrigin> allowed_origin);
void AddedAdoptedToTreeScope(TreeScope& tree_scope) {
adopted_tree_scopes_.insert(&tree_scope);
@@ -195,6 +200,12 @@ class CORE_EXPORT CSSStyleSheet final : public StyleSheet {
bool IsAlternate() const;
bool CanBeActivated(const String& current_preferrable_name) const;
+ void SetIsConstructed(bool is_constructed) {
+ is_constructed_ = is_constructed;
+ }
+
+ bool IsConstructed() { return is_constructed_; }
+
void Trace(blink::Visitor*) override;
private:
@@ -235,18 +246,19 @@ class CORE_EXPORT CSSStyleSheet final : public StyleSheet {
bool alternate_from_constructor_ = false;
bool enable_rule_access_for_inspector_ = false;
+ bool is_constructed_ = false;
+
String title_;
scoped_refptr<MediaQuerySet> media_queries_;
MediaQueryResultList viewport_dependent_media_query_results_;
MediaQueryResultList device_dependent_media_query_results_;
- scoped_refptr<const SecurityOrigin> allow_rule_access_from_origin_;
-
Member<Node> owner_node_;
Member<CSSRule> owner_rule_;
HeapHashSet<Member<TreeScope>> adopted_tree_scopes_;
Member<Document> associated_document_;
HashSet<AtomicString> custom_element_tag_names_;
+ Member<ScriptPromiseResolver> resolver_;
TextPosition start_position_;
Member<MediaList> media_cssom_wrapper_;
diff --git a/chromium/third_party/blink/renderer/core/css/css_style_sheet.idl b/chromium/third_party/blink/renderer/core/css/css_style_sheet.idl
index 1251d19c8c3..3ee4e190eaa 100644
--- a/chromium/third_party/blink/renderer/core/css/css_style_sheet.idl
+++ b/chromium/third_party/blink/renderer/core/css/css_style_sheet.idl
@@ -21,6 +21,9 @@
// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
[
+ ConstructorCallWith=Document,
+ RaisesException=Constructor,
+ Constructor(optional CSSStyleSheetInit options),
Exposed=Window
] interface CSSStyleSheet : StyleSheet {
readonly attribute CSSRule? ownerRule;
@@ -28,8 +31,11 @@
[RaisesException] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
[RaisesException] void deleteRule(unsigned long index);
+ [CallWith=ScriptState, RaisesException] Promise<CSSStyleSheet> replace(DOMString text);
+ [RaisesException] void replaceSync(DOMString text);
+
// Non-standard APIs
[MeasureAs=CSSStyleSheetRules, RaisesException] readonly attribute CSSRuleList rules;
- [MeasureAs=CSSStyleSheetAddRule, RaisesException] long addRule([Default=Undefined] optional DOMString selector, [Default=Undefined] optional DOMString style, optional unsigned long index);
- [MeasureAs=CSSStyleSheetRemoveRule, RaisesException] void removeRule([Default=Undefined] optional unsigned long index);
+ [MeasureAs=CSSStyleSheetAddRule, RaisesException] long addRule([DefaultValue=Undefined] optional DOMString selector, [DefaultValue=Undefined] optional DOMString style, optional unsigned long index);
+ [MeasureAs=CSSStyleSheetRemoveRule, RaisesException] void removeRule([DefaultValue=Undefined] optional unsigned long index);
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_style_sheet_test.cc b/chromium/third_party/blink/renderer/core/css/css_style_sheet_test.cc
index 3cdf716f661..8f786dd6cf6 100644
--- a/chromium/third_party/blink/renderer/core/css/css_style_sheet_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_style_sheet_test.cc
@@ -21,7 +21,6 @@ class CSSStyleSheetTest : public PageTestBase {
protected:
void SetUp() override {
PageTestBase::SetUp();
- RuntimeEnabledFeatures::SetConstructableStylesheetsEnabled(true);
}
class FunctionForTest : public ScriptFunction {
@@ -47,15 +46,6 @@ class CSSStyleSheetTest : public PageTestBase {
};
};
-TEST_F(CSSStyleSheetTest, ConstructorWithoutRuntimeFlagThrowsException) {
- DummyExceptionStateForTesting exception_state;
- RuntimeEnabledFeatures::SetConstructableStylesheetsEnabled(false);
- EXPECT_EQ(CSSStyleSheet::Create(GetDocument(), CSSStyleSheetInit::Create(),
- exception_state),
- nullptr);
- ASSERT_TRUE(exception_state.HadException());
-}
-
TEST_F(CSSStyleSheetTest,
CSSStyleSheetConstructionWithNonEmptyCSSStyleSheetInit) {
DummyExceptionStateForTesting exception_state;
@@ -80,114 +70,4 @@ TEST_F(CSSStyleSheetTest,
ASSERT_FALSE(exception_state.HadException());
}
-TEST_F(CSSStyleSheetTest, CreateEmptyCSSStyleSheetWithEmptyCSSStyleSheetInit) {
- V8TestingScope scope;
- DummyExceptionStateForTesting exception_state;
- CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
- scope.GetScriptState(), CSSStyleSheetInit::Create(), exception_state);
- ASSERT_FALSE(exception_state.HadException());
- EXPECT_TRUE(sheet->href().IsNull());
- EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
- EXPECT_EQ(sheet->ownerNode(), nullptr);
- EXPECT_EQ(sheet->ownerRule(), nullptr);
- EXPECT_EQ(sheet->media()->length(), 0U);
- EXPECT_EQ(sheet->title(), StringImpl::empty_);
- EXPECT_FALSE(sheet->AlternateFromConstructor());
- EXPECT_FALSE(sheet->disabled());
- EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
- ASSERT_FALSE(exception_state.HadException());
-}
-
-TEST_F(CSSStyleSheetTest,
- CreateEmptyCSSStyleSheetWithNonEmptyCSSStyleSheetInit) {
- CSSStyleSheetInit* init = CSSStyleSheetInit::Create();
- init->setMedia(MediaListOrString::FromString("screen, print"));
- init->setTitle("test");
- init->setAlternate(true);
- init->setDisabled(true);
- V8TestingScope scope;
- DummyExceptionStateForTesting exception_state;
- CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
- scope.GetScriptState(), init, exception_state);
- ASSERT_FALSE(exception_state.HadException());
- EXPECT_TRUE(sheet->href().IsNull());
- EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
- EXPECT_EQ(sheet->ownerNode(), nullptr);
- EXPECT_EQ(sheet->ownerRule(), nullptr);
- EXPECT_EQ(sheet->media()->length(), 2U);
- EXPECT_EQ(sheet->media()->mediaText(), init->media().GetAsString());
- EXPECT_EQ(sheet->title(), init->title());
- EXPECT_TRUE(sheet->AlternateFromConstructor());
- EXPECT_TRUE(sheet->disabled());
- ASSERT_FALSE(exception_state.HadException());
-}
-
-TEST_F(CSSStyleSheetTest,
- CreateCSSStyleSheetWithEmptyCSSStyleSheetInitAndText) {
- V8TestingScope scope;
- DummyExceptionStateForTesting exception_state;
- ScriptPromise promise = GetDocument().createCSSStyleSheet(
- scope.GetScriptState(), "", CSSStyleSheetInit::Create(), exception_state);
- EXPECT_FALSE(promise.IsEmpty());
- ASSERT_FALSE(exception_state.HadException());
- ScriptValue on_fulfilled, on_rejected;
- promise.Then(
- FunctionForTest::CreateFunction(scope.GetScriptState(), &on_fulfilled),
- FunctionForTest::CreateFunction(scope.GetScriptState(), &on_rejected));
-
- v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
- CSSStyleSheet* sheet = V8CSSStyleSheet::ToImplWithTypeCheck(
- scope.GetIsolate(), on_fulfilled.V8Value());
- EXPECT_TRUE(sheet->href().IsNull());
- EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
- EXPECT_EQ(sheet->ownerNode(), nullptr);
- EXPECT_EQ(sheet->ownerRule(), nullptr);
- EXPECT_EQ(sheet->media()->length(), 0U);
- EXPECT_EQ(sheet->title(), StringImpl::empty_);
- EXPECT_FALSE(sheet->AlternateFromConstructor());
- EXPECT_FALSE(sheet->disabled());
- EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
- ASSERT_FALSE(exception_state.HadException());
-}
-
-TEST_F(CSSStyleSheetTest,
- CreateCSSStyleSheetWithNonEmptyCSSStyleSheetInitAndText) {
- String styleText[2] = {".red { color: red; }",
- ".red + span + span { color: red; }"};
- CSSStyleSheetInit* init = CSSStyleSheetInit::Create();
- init->setMedia(MediaListOrString::FromString("screen, print"));
- init->setTitle("test");
- init->setAlternate(true);
- init->setDisabled(true);
- V8TestingScope scope;
- DummyExceptionStateForTesting exception_state;
- ScriptPromise promise = GetDocument().createCSSStyleSheet(
- scope.GetScriptState(), styleText[0] + styleText[1], init,
- exception_state);
- EXPECT_FALSE(promise.IsEmpty());
- ASSERT_FALSE(exception_state.HadException());
- ScriptValue on_fulfilled, on_rejected;
- promise.Then(
- FunctionForTest::CreateFunction(scope.GetScriptState(), &on_fulfilled),
- FunctionForTest::CreateFunction(scope.GetScriptState(), &on_rejected));
-
- v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
- CSSStyleSheet* sheet = V8CSSStyleSheet::ToImplWithTypeCheck(
- scope.GetIsolate(), on_fulfilled.V8Value());
-
- EXPECT_TRUE(sheet->href().IsNull());
- EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
- EXPECT_EQ(sheet->ownerNode(), nullptr);
- EXPECT_EQ(sheet->ownerRule(), nullptr);
- EXPECT_EQ(sheet->media()->length(), 2U);
- EXPECT_EQ(sheet->media()->mediaText(), init->media().GetAsString());
- EXPECT_EQ(sheet->title(), init->title());
- EXPECT_TRUE(sheet->AlternateFromConstructor());
- EXPECT_TRUE(sheet->disabled());
- EXPECT_EQ(sheet->cssRules(exception_state)->length(), 2U);
- EXPECT_EQ(sheet->cssRules(exception_state)->item(0)->cssText(), styleText[0]);
- EXPECT_EQ(sheet->cssRules(exception_state)->item(1)->cssText(), styleText[1]);
- ASSERT_FALSE(exception_state.HadException());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5 b/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5
index 6967328735d..bfa19f63716 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -455,6 +455,7 @@
"bidi-override",
"blink",
"both",
+ "break-spaces",
"close-quote",
"embed",
"fixed",
@@ -1196,5 +1197,15 @@
// pan-up,
// pan-down
// none
+
+ // (prefers-*:) media features
+ "no-preference",
+
+ // (prefers-color-scheme:) media feature
+ "dark",
+ "light",
+
+ // (prefers-reduced-motion:) media feature
+ "reduce",
],
}
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.cc
index e7c767f2c26..303d6d78208 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.cc
@@ -175,8 +175,11 @@ unsigned int ComputedStylePropertyMap::size() {
.size();
}
-bool ComputedStylePropertyMap::ComparePropertyNames(const String& a,
- const String& b) {
+bool ComputedStylePropertyMap::ComparePropertyNames(
+ const CSSPropertyName& name_a,
+ const CSSPropertyName& name_b) {
+ AtomicString a = name_a.ToAtomicString();
+ AtomicString b = name_b.ToAtomicString();
if (a.StartsWith("--"))
return b.StartsWith("--") && WTF::CodePointCompareLessThan(a, b);
if (a.StartsWith("-")) {
@@ -259,7 +262,7 @@ void ComputedStylePropertyMap::ForEachProperty(
// Have to sort by all properties by code point, so we have to store
// them in a buffer first.
- HeapVector<std::pair<AtomicString, Member<const CSSValue>>> values;
+ HeapVector<std::pair<CSSPropertyName, Member<const CSSValue>>> values;
for (const CSSProperty* property :
CSSComputedStyleDeclaration::ComputableProperties()) {
DCHECK(property);
@@ -267,7 +270,7 @@ void ComputedStylePropertyMap::ForEachProperty(
const CSSValue* value = property->CSSValueFromComputedStyle(
*style, nullptr /* layout_object */, StyledNode(), false);
if (value)
- values.emplace_back(property->GetPropertyNameAtomicString(), value);
+ values.emplace_back(CSSPropertyName(property->PropertyID()), value);
}
PropertyRegistry* registry =
@@ -275,7 +278,7 @@ void ComputedStylePropertyMap::ForEachProperty(
for (const auto& name_value :
ComputedStyleCSSValueMapping::GetVariables(*style, registry)) {
- values.emplace_back(name_value.key, name_value.value);
+ values.emplace_back(CSSPropertyName(name_value.key), name_value.value);
}
std::sort(values.begin(), values.end(), [](const auto& a, const auto& b) {
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.h b/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.h
index 9fa239bacc2..0bcd9f97db4 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/computed_style_property_map.h
@@ -26,9 +26,14 @@ class CORE_EXPORT ComputedStylePropertyMap
: public StylePropertyMapReadOnlyMainThread {
public:
static ComputedStylePropertyMap* Create(Node* node) {
- return new ComputedStylePropertyMap(node);
+ return MakeGarbageCollected<ComputedStylePropertyMap>(node);
}
+ ComputedStylePropertyMap(Node* node, const String& pseudo_element = String())
+ : StylePropertyMapReadOnlyMainThread(),
+ pseudo_id_(CSSSelector::ParsePseudoId(pseudo_element)),
+ node_(node) {}
+
void Trace(blink::Visitor* visitor) override {
visitor->Trace(node_);
StylePropertyMapReadOnlyMainThread::Trace(visitor);
@@ -39,14 +44,10 @@ class CORE_EXPORT ComputedStylePropertyMap
// ComputedStylePropertyMap needs to be sorted. This puts CSS properties
// first, then prefixed properties, then custom properties. Everything is
// sorted by code point within each category.
- static bool ComparePropertyNames(const String&, const String&);
+ static bool ComparePropertyNames(const CSSPropertyName&,
+ const CSSPropertyName&);
protected:
- ComputedStylePropertyMap(Node* node, const String& pseudo_element = String())
- : StylePropertyMapReadOnlyMainThread(),
- pseudo_id_(CSSSelector::ParsePseudoId(pseudo_element)),
- node_(node) {}
-
const CSSValue* GetProperty(CSSPropertyID) override;
const CSSValue* GetCustomProperty(AtomicString) override;
void ForEachProperty(const IterationCallback&) override;
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h
new file mode 100644
index 00000000000..080a5845714
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CROSS_THREAD_STYLE_VALUE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CROSS_THREAD_STYLE_VALUE_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/core_export.h"
+
+namespace blink {
+
+class CSSStyleValue;
+
+// This class is designed for CSS Paint such that its instance can be safely
+// passed cross threads.
+class CORE_EXPORT CrossThreadStyleValue {
+ public:
+ virtual ~CrossThreadStyleValue() = default;
+
+ virtual CSSStyleValue* ToCSSStyleValue() = 0;
+
+ protected:
+ CrossThreadStyleValue() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CrossThreadStyleValue);
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc
new file mode 100644
index 00000000000..3c27af08af3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc
@@ -0,0 +1,83 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
+
+#include <memory>
+#include "base/single_thread_task_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h"
+#include "third_party/blink/renderer/core/css/cssom/css_style_value.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/waitable_event.h"
+#include "third_party/blink/renderer/platform/web_thread_supporting_gc.h"
+
+namespace blink {
+
+class CrossThreadStyleValueTest : public testing::Test {
+ public:
+ void ShutDown(WaitableEvent* waitable_event) {
+ DCHECK(!IsMainThread());
+ thread_->ShutdownOnThread();
+ waitable_event->Signal();
+ }
+
+ void ShutDownThread() {
+ WaitableEvent waitable_event;
+ thread_->PostTask(FROM_HERE,
+ CrossThreadBind(&CrossThreadStyleValueTest::ShutDown,
+ CrossThreadUnretained(this),
+ CrossThreadUnretained(&waitable_event)));
+ waitable_event.Wait();
+ }
+
+ void CheckUnsupportedValue(
+ WaitableEvent* waitable_event,
+ std::unique_ptr<CrossThreadUnsupportedValue> value) {
+ DCHECK(!IsMainThread());
+ thread_->InitializeOnThread();
+
+ EXPECT_EQ(value->value_, "Unsupported");
+ waitable_event->Signal();
+ }
+
+ protected:
+ std::unique_ptr<WebThreadSupportingGC> thread_;
+};
+
+// Ensure that a CrossThreadUnsupportedValue can be safely passed cross
+// threads.
+TEST_F(CrossThreadStyleValueTest, PassUnsupportedValueCrossThread) {
+ std::unique_ptr<CrossThreadUnsupportedValue> value =
+ std::make_unique<CrossThreadUnsupportedValue>("Unsupported");
+ DCHECK(value);
+
+ // Use a WebThreadSupportingGC to emulate worklet thread.
+ thread_ = WebThreadSupportingGC::Create(
+ ThreadCreationParams(WebThreadType::kTestThread));
+ WaitableEvent waitable_event;
+ thread_->PostTask(
+ FROM_HERE,
+ CrossThreadBind(&CrossThreadStyleValueTest::CheckUnsupportedValue,
+ CrossThreadUnretained(this),
+ CrossThreadUnretained(&waitable_event),
+ WTF::Passed(std::move(value))));
+ waitable_event.Wait();
+
+ ShutDownThread();
+}
+
+TEST_F(CrossThreadStyleValueTest, CrossThreadUnsupportedValueToCSSStyleValue) {
+ std::unique_ptr<CrossThreadUnsupportedValue> value =
+ std::make_unique<CrossThreadUnsupportedValue>("Unsupported");
+ DCHECK(value);
+
+ const CSSStyleValue* const style_value = value->ToCSSStyleValue();
+ EXPECT_EQ(style_value->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+ EXPECT_EQ(style_value->CSSText(), "Unsupported");
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.cc b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.cc
new file mode 100644
index 00000000000..020bafb1f82
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.cc
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h"
+
+#include "third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h"
+
+namespace blink {
+
+CSSStyleValue* CrossThreadUnsupportedValue::ToCSSStyleValue() {
+ return CSSUnsupportedStyleValue::Create(value_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h
new file mode 100644
index 00000000000..3a3be4bc817
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CROSS_THREAD_UNSUPPORTED_VALUE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CROSS_THREAD_UNSUPPORTED_VALUE_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class CSSStyleValue;
+
+class CORE_EXPORT CrossThreadUnsupportedValue final
+ : public CrossThreadStyleValue {
+ public:
+ explicit CrossThreadUnsupportedValue(const String& value) : value_(value) {}
+ ~CrossThreadUnsupportedValue() override = default;
+
+ CSSStyleValue* ToCSSStyleValue() override;
+
+ private:
+ friend class CrossThreadStyleValueTest;
+
+ String value_;
+ DISALLOW_COPY_AND_ASSIGN(CrossThreadUnsupportedValue);
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/css_resource_value_test.cc b/chromium/third_party/blink/renderer/core/css/cssom/css_resource_value_test.cc
index 8b0b9358cf8..d5deccaf024 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/css_resource_value_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/css_resource_value_test.cc
@@ -25,16 +25,26 @@ class FakeCSSResourceValue : public CSSResourceValue {
} // namespace
TEST(CSSResourceValueTest, TestStatus) {
- EXPECT_EQ((new FakeCSSResourceValue(ResourceStatus::kNotStarted))->state(),
- "unloaded");
- EXPECT_EQ((new FakeCSSResourceValue(ResourceStatus::kPending))->state(),
- "loading");
- EXPECT_EQ((new FakeCSSResourceValue(ResourceStatus::kCached))->state(),
- "loaded");
- EXPECT_EQ((new FakeCSSResourceValue(ResourceStatus::kLoadError))->state(),
- "error");
- EXPECT_EQ((new FakeCSSResourceValue(ResourceStatus::kDecodeError))->state(),
- "error");
+ EXPECT_EQ(
+ (MakeGarbageCollected<FakeCSSResourceValue>(ResourceStatus::kNotStarted))
+ ->state(),
+ "unloaded");
+ EXPECT_EQ(
+ (MakeGarbageCollected<FakeCSSResourceValue>(ResourceStatus::kPending))
+ ->state(),
+ "loading");
+ EXPECT_EQ(
+ (MakeGarbageCollected<FakeCSSResourceValue>(ResourceStatus::kCached))
+ ->state(),
+ "loaded");
+ EXPECT_EQ(
+ (MakeGarbageCollected<FakeCSSResourceValue>(ResourceStatus::kLoadError))
+ ->state(),
+ "error");
+ EXPECT_EQ(
+ (MakeGarbageCollected<FakeCSSResourceValue>(ResourceStatus::kDecodeError))
+ ->state(),
+ "error");
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/css_style_image_value.h b/chromium/third_party/blink/renderer/core/css/cssom/css_style_image_value.h
index 6ddc0ba67e8..77e9d0e5275 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/css_style_image_value.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/css_style_image_value.h
@@ -29,10 +29,7 @@ class CORE_EXPORT CSSStyleImageValue : public CSSResourceValue,
// CanvasImageSource
bool IsCSSImageValue() const final { return true; }
- bool WouldTaintOrigin(
- const SecurityOrigin* destination_security_origin) const final {
- return true;
- }
+ bool WouldTaintOrigin() const final { return true; }
FloatSize ElementSize(const FloatSize& default_object_size) const final;
protected:
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.h b/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.h
index 2d1f43bf1a3..6bba2d8fff5 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.h
@@ -32,7 +32,6 @@ class CORE_EXPORT CSSStyleValue : public ScriptWrappable {
// This enum ordering is significant for CSSStyleValue::IsNumericValue.
enum StyleValueType {
kUnknownType,
- kShorthandType,
kUnparsedType,
kKeywordType,
// Start of CSSNumericValue subclasses
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h b/chromium/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h
index ce971b49259..3eb73efe084 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h
@@ -6,46 +6,54 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CSS_UNSUPPORTED_STYLE_VALUE_H_
#include "base/macros.h"
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/cssom/css_style_value.h"
namespace blink {
// CSSUnsupportedStyleValue is the internal representation of a base
// CSSStyleValue that is returned when we do not yet support a CSS Typed OM type
-// for a given CSS Value. It is tied to a specific CSS property and is only
-// considered valid for that property.
+// for a given CSS Value.
+//
+// It is either:
+//
+// * Tied to a specific CSS property, and therefore only valid for that
+// property, or
+// * Tied to no CSS property at all, in which case it's not valid for any
+// property.
+
class CORE_EXPORT CSSUnsupportedStyleValue final : public CSSStyleValue {
public:
- static CSSUnsupportedStyleValue* Create(
- CSSPropertyID property,
- const AtomicString& custom_property_name,
- const String& css_text) {
- return MakeGarbageCollected<CSSUnsupportedStyleValue>(
- property, custom_property_name, css_text);
+ static CSSUnsupportedStyleValue* Create(const CSSValue& value) {
+ return MakeGarbageCollected<CSSUnsupportedStyleValue>(value.CssText());
+ }
+ static CSSUnsupportedStyleValue* Create(const String& css_text) {
+ return MakeGarbageCollected<CSSUnsupportedStyleValue>(css_text);
}
- static CSSUnsupportedStyleValue* Create(
- CSSPropertyID property,
- const AtomicString& custom_property_name,
- const CSSValue& value) {
- return MakeGarbageCollected<CSSUnsupportedStyleValue>(
- property, custom_property_name, value.CssText());
+ static CSSUnsupportedStyleValue* Create(const CSSPropertyName& name,
+ const String& css_text) {
+ return MakeGarbageCollected<CSSUnsupportedStyleValue>(name, css_text);
+ }
+ static CSSUnsupportedStyleValue* Create(const CSSPropertyName& name,
+ const CSSValue& value) {
+ return MakeGarbageCollected<CSSUnsupportedStyleValue>(name,
+ value.CssText());
}
- CSSUnsupportedStyleValue(CSSPropertyID property,
- const AtomicString& custom_property_name,
- const String& css_text)
- : property_(property), custom_property_name_(custom_property_name) {
+ CSSUnsupportedStyleValue(const String& css_text) { SetCSSText(css_text); }
+ CSSUnsupportedStyleValue(const CSSPropertyName& name, const String& css_text)
+ : name_(name) {
SetCSSText(css_text);
- DCHECK_EQ(property == CSSPropertyVariable, !custom_property_name.IsNull());
}
StyleValueType GetType() const override {
return StyleValueType::kUnknownType;
}
- CSSPropertyID GetProperty() const { return property_; }
- const AtomicString& GetCustomPropertyName() const {
- return custom_property_name_;
+ bool IsValidFor(const CSSPropertyName& name) const {
+ return name_ && *name_ == name;
}
+
const CSSValue* ToCSSValue() const override {
NOTREACHED();
return nullptr;
@@ -54,10 +62,7 @@ class CORE_EXPORT CSSUnsupportedStyleValue final : public CSSStyleValue {
String toString() const final { return CSSText(); }
private:
- const CSSPropertyID property_;
- // Name is set when property_ is CSSPropertyVariable, otherwise it's
- // g_null_atom.
- AtomicString custom_property_name_;
+ base::Optional<CSSPropertyName> name_;
DISALLOW_COPY_AND_ASSIGN(CSSUnsupportedStyleValue);
};
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/declared_style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/declared_style_property_map.cc
index 1856f7f80ee..7727b705cfc 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/declared_style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/declared_style_property_map.cc
@@ -100,15 +100,7 @@ void DeclaredStylePropertyMap::ForEachProperty(
const CSSPropertyValueSet& declared_style_set = GetStyleRule()->Properties();
for (unsigned i = 0; i < declared_style_set.PropertyCount(); i++) {
const auto& property_reference = declared_style_set.PropertyAt(i);
- if (property_reference.Id() == CSSPropertyVariable) {
- const auto& decl =
- ToCSSCustomPropertyDeclaration(property_reference.Value());
- callback(decl.GetName(), property_reference.Value());
- } else {
- const CSSProperty& property = CSSProperty::Get(property_reference.Id());
- callback(property.GetPropertyNameAtomicString(),
- property_reference.Value());
- }
+ callback(property_reference.Name(), property_reference.Value());
}
}
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/inline_style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/inline_style_property_map.cc
index 65e9ed9260c..048930d7101 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/inline_style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/inline_style_property_map.cc
@@ -74,14 +74,7 @@ void InlineStylePropertyMap::ForEachProperty(
owner_element_->EnsureMutableInlineStyle();
for (unsigned i = 0; i < inline_style_set.PropertyCount(); i++) {
const auto& property_reference = inline_style_set.PropertyAt(i);
- if (property_reference.Id() == CSSPropertyVariable) {
- const auto& decl =
- ToCSSCustomPropertyDeclaration(property_reference.Value());
- callback(decl.GetName(), property_reference.Value());
- } else {
- callback(property_reference.Property().GetPropertyNameAtomicString(),
- property_reference.Value());
- }
+ callback(property_reference.Name(), property_reference.Value());
}
}
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc
new file mode 100644
index 00000000000..8b029b01c24
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+
+namespace blink {
+
+PaintWorkletInput::PaintWorkletInput(
+ const std::string& name,
+ const FloatSize& container_size,
+ float effective_zoom,
+ const Document& document,
+ const ComputedStyle& style,
+ Node* styled_node,
+ const Vector<CSSPropertyID>& native_properties,
+ const Vector<AtomicString>& custom_properties)
+ : name_(name),
+ container_size_(container_size),
+ effective_zoom_(effective_zoom),
+ style_map_(MakeGarbageCollected<PaintWorkletStylePropertyMap>(
+ document,
+ style,
+ styled_node,
+ native_properties,
+ custom_properties)) {}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
new file mode 100644
index 00000000000..1a88409c42a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_PAINT_WORKLET_INPUT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_PAINT_WORKLET_INPUT_H_
+
+#include <memory>
+#include "cc/paint/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h"
+#include "third_party/blink/renderer/platform/geometry/float_size.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+class CORE_EXPORT PaintWorkletInput : public cc::PaintWorkletInput {
+ public:
+ PaintWorkletInput(const std::string& name,
+ const FloatSize& container_size,
+ float effective_zoom,
+ const Document&,
+ const ComputedStyle&,
+ Node* styled_node,
+ const Vector<CSSPropertyID>& native_properties,
+ const Vector<AtomicString>& custom_properties);
+
+ ~PaintWorkletInput() override = default;
+
+ // PaintWorkletInput implementation
+ gfx::SizeF GetSize() const override {
+ return gfx::SizeF(container_size_.Width(), container_size_.Height());
+ }
+
+ const std::string& Name() const { return name_; }
+ const FloatSize& ContainerSize() const { return container_size_; }
+ float EffectiveZoom() const { return effective_zoom_; }
+ PaintWorkletStylePropertyMap* StyleMap() { return style_map_.Get(); }
+
+ private:
+ const std::string name_;
+ const FloatSize container_size_;
+ const float effective_zoom_;
+ const CrossThreadPersistent<PaintWorkletStylePropertyMap> style_map_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_PAINT_WORKLET_INPUT_H_
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc
new file mode 100644
index 00000000000..8f393eea6f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc
@@ -0,0 +1,165 @@
+// Copyright 2018 the Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h"
+
+#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
+#include "third_party/blink/renderer/core/css/css_variable_data.h"
+#include "third_party/blink/renderer/core/css/cssom/computed_style_property_map.h"
+#include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h"
+#include "third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h"
+#include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+
+namespace blink {
+
+namespace {
+
+class PaintWorkletStylePropertyMapIterationSource final
+ : public PairIterable<String, CSSStyleValueVector>::IterationSource {
+ public:
+ explicit PaintWorkletStylePropertyMapIterationSource(
+ HeapVector<PaintWorkletStylePropertyMap::StylePropertyMapEntry> values)
+ : index_(0), values_(values) {}
+
+ bool Next(ScriptState*,
+ String& key,
+ CSSStyleValueVector& value,
+ ExceptionState&) override {
+ if (index_ >= values_.size())
+ return false;
+
+ const PaintWorkletStylePropertyMap::StylePropertyMapEntry& pair =
+ values_.at(index_++);
+ key = pair.first;
+ value = pair.second;
+ return true;
+ }
+
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(values_);
+ PairIterable<String, CSSStyleValueVector>::IterationSource::Trace(visitor);
+ }
+
+ private:
+ wtf_size_t index_;
+ const HeapVector<PaintWorkletStylePropertyMap::StylePropertyMapEntry> values_;
+};
+
+} // namespace
+
+PaintWorkletStylePropertyMap::PaintWorkletStylePropertyMap(
+ const Document& document,
+ const ComputedStyle& style,
+ Node* styled_node,
+ const Vector<CSSPropertyID>& native_properties,
+ const Vector<AtomicString>& custom_properties)
+ : StylePropertyMapReadOnly() {
+ DCHECK(IsMainThread());
+ values_.ReserveCapacityForSize(native_properties.size() +
+ custom_properties.size());
+ BuildNativeValues(style, styled_node, native_properties);
+ BuildCustomValues(document, style, styled_node, custom_properties);
+}
+
+void PaintWorkletStylePropertyMap::BuildNativeValues(
+ const ComputedStyle& style,
+ Node* styled_node,
+ const Vector<CSSPropertyID>& native_properties) {
+ DCHECK(IsMainThread());
+ for (const auto& property_id : native_properties) {
+ // Silently drop shorthand properties.
+ DCHECK_NE(property_id, CSSPropertyInvalid);
+ DCHECK_NE(property_id, CSSPropertyVariable);
+ if (CSSProperty::Get(property_id).IsShorthand())
+ continue;
+ std::unique_ptr<CrossThreadStyleValue> value =
+ CSSProperty::Get(property_id)
+ .CrossThreadStyleValueFromComputedStyle(
+ style, /* layout_object */ nullptr, styled_node,
+ /* allow_visited_style */ false);
+ String key = CSSProperty::Get(property_id).GetPropertyNameString();
+ if (!key.IsSafeToSendToAnotherThread())
+ key = key.IsolatedCopy();
+ values_.Set(key, std::move(value));
+ }
+}
+
+void PaintWorkletStylePropertyMap::BuildCustomValues(
+ const Document& document,
+ const ComputedStyle& style,
+ Node* styled_node,
+ const Vector<AtomicString>& custom_properties) {
+ DCHECK(IsMainThread());
+ for (const auto& property_name : custom_properties) {
+ CSSPropertyRef ref(property_name, document);
+ std::unique_ptr<CrossThreadStyleValue> value =
+ ref.GetProperty().CrossThreadStyleValueFromComputedStyle(
+ style, /* layout_object */ nullptr, styled_node,
+ /* allow_visited_style */ false);
+ // Ensure that the String can be safely passed cross threads.
+ String key = property_name.GetString();
+ if (!key.IsSafeToSendToAnotherThread())
+ key = key.IsolatedCopy();
+ values_.Set(key, std::move(value));
+ }
+}
+
+CSSStyleValue* PaintWorkletStylePropertyMap::get(
+ const ExecutionContext* execution_context,
+ const String& property_name,
+ ExceptionState& exception_state) {
+ CSSStyleValueVector all_values =
+ getAll(execution_context, property_name, exception_state);
+ return all_values.IsEmpty() ? nullptr : all_values[0];
+}
+
+CSSStyleValueVector PaintWorkletStylePropertyMap::getAll(
+ const ExecutionContext* execution_context,
+ const String& property_name,
+ ExceptionState& exception_state) {
+ CSSPropertyID property_id = cssPropertyID(property_name);
+ if (property_id == CSSPropertyInvalid) {
+ exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
+ return CSSStyleValueVector();
+ }
+
+ DCHECK(isValidCSSPropertyID(property_id));
+
+ CSSStyleValueVector values;
+ auto value = values_.find(property_name);
+ if (value == values_.end())
+ return CSSStyleValueVector();
+ values.push_back(value->value->ToCSSStyleValue());
+ return values;
+}
+
+bool PaintWorkletStylePropertyMap::has(
+ const ExecutionContext* execution_context,
+ const String& property_name,
+ ExceptionState& exception_state) {
+ return !getAll(execution_context, property_name, exception_state).IsEmpty();
+}
+
+unsigned PaintWorkletStylePropertyMap::size() {
+ return values_.size();
+}
+
+PaintWorkletStylePropertyMap::IterationSource*
+PaintWorkletStylePropertyMap::StartIteration(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ // TODO(xidachen): implement this function. Note that the output should be
+ // sorted.
+ NOTREACHED();
+ HeapVector<PaintWorkletStylePropertyMap::StylePropertyMapEntry> result;
+ return MakeGarbageCollected<PaintWorkletStylePropertyMapIterationSource>(
+ result);
+}
+
+void PaintWorkletStylePropertyMap::Trace(blink::Visitor* visitor) {
+ StylePropertyMapReadOnly::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h
new file mode 100644
index 00000000000..fe7b063ad82
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h
@@ -0,0 +1,73 @@
+// Copyright 2018 the Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_PAINT_WORKLET_STYLE_PROPERTY_MAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_PAINT_WORKLET_STYLE_PROPERTY_MAP_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
+#include "third_party/blink/renderer/core/css/cssom/style_property_map_read_only.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+// This class is designed for CSS Paint such that it can be safely passed cross
+// threads.
+//
+// Here is a typical usage.
+// At CSSPaintValue::GetImage which is on the main thread, build an instance
+// of Blink::PaintWorkletInput which calls the constructor of this class. The
+// ownership of this style map belongs to the Blink::PaintWorkletInput, which
+// will eventually be passed to the worklet thread and used in the JS callback.
+class CORE_EXPORT PaintWorkletStylePropertyMap
+ : public StylePropertyMapReadOnly {
+ public:
+ using StylePropertyMapEntry = std::pair<String, CSSStyleValueVector>;
+ // This constructor should be called on main-thread only.
+ PaintWorkletStylePropertyMap(const Document&,
+ const ComputedStyle&,
+ Node* styled_node,
+ const Vector<CSSPropertyID>& native_properties,
+ const Vector<AtomicString>& custom_properties);
+
+ CSSStyleValue* get(const ExecutionContext*,
+ const String& property_name,
+ ExceptionState&) override;
+
+ CSSStyleValueVector getAll(const ExecutionContext*,
+ const String& property_name,
+ ExceptionState&) override;
+
+ bool has(const ExecutionContext*,
+ const String& property_name,
+ ExceptionState&) override;
+
+ unsigned int size() override;
+
+ void Trace(blink::Visitor*) override;
+
+ const HashMap<String, std::unique_ptr<CrossThreadStyleValue>>&
+ ValuesForTest() {
+ return values_;
+ }
+
+ private:
+ IterationSource* StartIteration(ScriptState*, ExceptionState&) override;
+
+ void BuildNativeValues(const ComputedStyle&,
+ Node* styled_node,
+ const Vector<CSSPropertyID>& native_properties);
+ void BuildCustomValues(const Document&,
+ const ComputedStyle&,
+ Node* styled_node,
+ const Vector<AtomicString>& custom_properties);
+
+ HashMap<String, std::unique_ptr<CrossThreadStyleValue>> values_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintWorkletStylePropertyMap);
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
new file mode 100644
index 00000000000..11bb7adb479
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
@@ -0,0 +1,222 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h"
+
+#include <memory>
+#include "base/single_thread_task_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/waitable_event.h"
+#include "third_party/blink/renderer/platform/web_thread_supporting_gc.h"
+
+namespace blink {
+
+class PaintWorkletStylePropertyMapTest : public PageTestBase {
+ public:
+ PaintWorkletStylePropertyMapTest() = default;
+
+ void SetUp() override { PageTestBase::SetUp(IntSize()); }
+
+ Node* PageNode() { return GetDocument().documentElement(); }
+
+ void ShutDown(WaitableEvent* waitable_event) {
+ DCHECK(!IsMainThread());
+ thread_->ShutdownOnThread();
+ waitable_event->Signal();
+ }
+
+ void ShutDownThread() {
+ WaitableEvent waitable_event;
+ thread_->PostTask(
+ FROM_HERE, CrossThreadBind(&PaintWorkletStylePropertyMapTest::ShutDown,
+ CrossThreadUnretained(this),
+ CrossThreadUnretained(&waitable_event)));
+ waitable_event.Wait();
+ }
+
+ void CheckCustomProperties(PaintWorkletStylePropertyMap* map,
+ DummyExceptionStateForTesting& exception_state) {
+ const CSSStyleValue* foo = map->get(nullptr, "--foo", exception_state);
+ ASSERT_NE(nullptr, foo);
+ ASSERT_EQ(CSSStyleValue::kUnknownType, foo->GetType());
+ EXPECT_FALSE(exception_state.HadException());
+
+ EXPECT_EQ(true, map->has(nullptr, "--foo", exception_state));
+ EXPECT_FALSE(exception_state.HadException());
+
+ CSSStyleValueVector fooAll = map->getAll(nullptr, "--foo", exception_state);
+ EXPECT_EQ(1U, fooAll.size());
+ ASSERT_NE(nullptr, fooAll[0]);
+ ASSERT_EQ(CSSStyleValue::kUnknownType, fooAll[0]->GetType());
+ EXPECT_FALSE(exception_state.HadException());
+
+ EXPECT_EQ(nullptr, map->get(nullptr, "--quix", exception_state));
+ EXPECT_FALSE(exception_state.HadException());
+
+ EXPECT_EQ(false, map->has(nullptr, "--quix", exception_state));
+ EXPECT_FALSE(exception_state.HadException());
+
+ EXPECT_EQ(CSSStyleValueVector(),
+ map->getAll(nullptr, "--quix", exception_state));
+ EXPECT_FALSE(exception_state.HadException());
+ }
+
+ void CheckNativeProperties(PaintWorkletStylePropertyMap* map,
+ DummyExceptionStateForTesting& exception_state) {
+ map->get(nullptr, "color", exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+
+ map->has(nullptr, "color", exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+
+ map->getAll(nullptr, "color", exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+
+ map->get(nullptr, "align-contents", exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+ exception_state.ClearException();
+
+ map->has(nullptr, "align-contents", exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+ exception_state.ClearException();
+
+ map->getAll(nullptr, "align-contents", exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+ exception_state.ClearException();
+ }
+
+ void CheckStyleMap(WaitableEvent* waitable_event,
+ scoped_refptr<PaintWorkletInput> input) {
+ DCHECK(!IsMainThread());
+ thread_->InitializeOnThread();
+
+ PaintWorkletStylePropertyMap* map = input->StyleMap();
+ DCHECK(map);
+ DummyExceptionStateForTesting exception_state;
+ CheckNativeProperties(map, exception_state);
+ CheckCustomProperties(map, exception_state);
+
+ const HashMap<String, std::unique_ptr<CrossThreadStyleValue>>& values =
+ map->ValuesForTest();
+ EXPECT_EQ(values.size(), 4u);
+ EXPECT_EQ(values.at("color")->ToCSSStyleValue()->CSSText(),
+ "rgb(0, 255, 0)");
+ EXPECT_EQ(values.at("color")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+ EXPECT_EQ(values.at("align-items")->ToCSSStyleValue()->CSSText(), "normal");
+ EXPECT_EQ(values.at("align-items")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+ EXPECT_EQ(values.at("--foo")->ToCSSStyleValue()->CSSText(), "PaintWorklet");
+ EXPECT_EQ(values.at("--foo")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+ EXPECT_EQ(values.at("--bar")->ToCSSStyleValue()->CSSText(), "");
+ EXPECT_EQ(values.at("--bar")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+
+ waitable_event->Signal();
+ }
+
+ protected:
+ std::unique_ptr<WebThreadSupportingGC> thread_;
+};
+
+TEST_F(PaintWorkletStylePropertyMapTest, NativePropertyAccessors) {
+ Vector<CSSPropertyID> native_properties(
+ {CSSPropertyColor, CSSPropertyAlignItems, CSSPropertyBackground});
+ Vector<AtomicString> empty_custom_properties;
+ GetDocument().documentElement()->style()->setProperty(
+ &GetDocument(), "color", "rgb(0, 255, 0)", "", ASSERT_NO_EXCEPTION);
+
+ UpdateAllLifecyclePhasesForTest();
+ Node* node = PageNode();
+
+ PaintWorkletStylePropertyMap* map =
+ MakeGarbageCollected<PaintWorkletStylePropertyMap>(
+ GetDocument(), node->ComputedStyleRef(), node, native_properties,
+ empty_custom_properties);
+
+ const HashMap<String, std::unique_ptr<CrossThreadStyleValue>>& values =
+ map->ValuesForTest();
+ EXPECT_EQ(values.size(), 2u);
+ EXPECT_EQ(values.at("color")->ToCSSStyleValue()->CSSText(), "rgb(0, 255, 0)");
+ EXPECT_EQ(values.at("color")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+ EXPECT_EQ(values.at("align-items")->ToCSSStyleValue()->CSSText(), "normal");
+ EXPECT_EQ(values.at("align-items")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+
+ DummyExceptionStateForTesting exception_state;
+ CheckNativeProperties(map, exception_state);
+}
+
+TEST_F(PaintWorkletStylePropertyMapTest, CustomPropertyAccessors) {
+ Vector<CSSPropertyID> empty_native_properties;
+ Vector<AtomicString> custom_properties({"--foo", "--bar"});
+ GetDocument().documentElement()->style()->setProperty(
+ &GetDocument(), "--foo", "PaintWorklet", "", ASSERT_NO_EXCEPTION);
+
+ UpdateAllLifecyclePhasesForTest();
+ Node* node = PageNode();
+
+ PaintWorkletStylePropertyMap* map =
+ MakeGarbageCollected<PaintWorkletStylePropertyMap>(
+ GetDocument(), node->ComputedStyleRef(), node,
+ empty_native_properties, custom_properties);
+
+ const HashMap<String, std::unique_ptr<CrossThreadStyleValue>>& values =
+ map->ValuesForTest();
+ EXPECT_EQ(values.size(), 2u);
+ EXPECT_EQ(values.at("--foo")->ToCSSStyleValue()->CSSText(), "PaintWorklet");
+ EXPECT_EQ(values.at("--foo")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+ EXPECT_EQ(values.at("--bar")->ToCSSStyleValue()->CSSText(), "");
+ EXPECT_EQ(values.at("--bar")->ToCSSStyleValue()->GetType(),
+ CSSStyleValue::StyleValueType::kUnknownType);
+
+ DummyExceptionStateForTesting exception_state;
+ CheckCustomProperties(map, exception_state);
+}
+
+// This test ensures that Blink::PaintWorkletInput can be safely passed cross
+// threads and no information is lost.
+TEST_F(PaintWorkletStylePropertyMapTest, PassValuesCrossThread) {
+ Vector<CSSPropertyID> native_properties(
+ {CSSPropertyColor, CSSPropertyAlignItems});
+ GetDocument().documentElement()->style()->setProperty(
+ &GetDocument(), "color", "rgb(0, 255, 0)", "", ASSERT_NO_EXCEPTION);
+ Vector<AtomicString> custom_properties({"--foo", "--bar"});
+ GetDocument().documentElement()->style()->setProperty(
+ &GetDocument(), "--foo", "PaintWorklet", "", ASSERT_NO_EXCEPTION);
+
+ UpdateAllLifecyclePhasesForTest();
+ Node* node = PageNode();
+
+ scoped_refptr<PaintWorkletInput> input =
+ base::MakeRefCounted<PaintWorkletInput>(
+ "test", FloatSize(100, 100), 1.0f, GetDocument(),
+ node->ComputedStyleRef(), node, native_properties, custom_properties);
+ DCHECK(input);
+
+ thread_ = WebThreadSupportingGC::Create(
+ ThreadCreationParams(WebThreadType::kTestThread));
+ WaitableEvent waitable_event;
+ thread_->PostTask(
+ FROM_HERE, CrossThreadBind(
+ &PaintWorkletStylePropertyMapTest::CheckStyleMap,
+ CrossThreadUnretained(this),
+ CrossThreadUnretained(&waitable_event), std::move(input)));
+ waitable_event.Wait();
+
+ ShutDownThread();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.cc
index 310444d9973..375abfb6d2c 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.cc
@@ -96,17 +96,16 @@ void PrepopulatedComputedStylePropertyMap::ForEachProperty(
const IterationCallback& callback) {
// Have to sort by all properties by code point, so we have to store
// them in a buffer first.
- HeapVector<std::pair<AtomicString, Member<const CSSValue>>> values;
+ HeapVector<std::pair<CSSPropertyName, Member<const CSSValue>>> values;
for (const auto& entry : native_values_) {
DCHECK(entry.value);
- values.emplace_back(
- CSSProperty::Get(entry.key).GetPropertyNameAtomicString(), entry.value);
+ values.emplace_back(CSSPropertyName(entry.key), entry.value);
}
for (const auto& entry : custom_values_) {
DCHECK(entry.value);
- values.emplace_back(entry.key, entry.value);
+ values.emplace_back(CSSPropertyName(entry.key), entry.value);
}
std::sort(values.begin(), values.end(), [](const auto& a, const auto& b) {
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc b/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
index 30e93f2bee1..cb34c4b2cce 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
@@ -18,6 +18,20 @@ class PrepopulatedComputedStylePropertyMapTest : public PageTestBase {
public:
PrepopulatedComputedStylePropertyMapTest() = default;
+ void SetElementWithStyle(const String& value) {
+ GetDocument().body()->SetInnerHTMLFromString("<div id='target' style='" +
+ value + "'></div>");
+ UpdateAllLifecyclePhasesForTest();
+ }
+
+ const CSSValue* GetNativeValue(const CSSPropertyID& property_id) {
+ Element* node = GetDocument().getElementById("target");
+ return CSSProperty::Get(property_id)
+ .CSSValueFromComputedStyle(node->ComputedStyleRef(),
+ nullptr /* layout_object */, node,
+ false /* allow_visited_style */);
+ }
+
CSSComputedStyleDeclaration* Declaration() const {
return declaration_.Get();
}
@@ -111,4 +125,10 @@ TEST_F(PrepopulatedComputedStylePropertyMapTest, CustomPropertyAccessors) {
EXPECT_FALSE(exception_state.HadException());
}
+TEST_F(PrepopulatedComputedStylePropertyMapTest, WidthBeingAuto) {
+ SetElementWithStyle("width:auto");
+ const CSSValue* value = GetNativeValue(CSSPropertyWidth);
+ EXPECT_EQ("auto", value->CssText());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
index 3994c6abc7e..6f86a084d2e 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/css/cssom/style_property_map.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
+#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/css_value_pair.h"
#include "third_party/blink/renderer/core/css/cssom/css_style_value.h"
@@ -443,7 +444,7 @@ void StylePropertyMap::append(const ExecutionContext* execution_context,
GetCustomProperty(*execution_context, custom_property_name)) {
DCHECK(css_value->IsValueList());
style_values = StyleValueFactory::CssValueToStyleValueVector(
- property_id, custom_property_name, *css_value);
+ CSSPropertyName(custom_property_name), *css_value);
}
// Append incoming CSSStyleValues:
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.cc b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.cc
index 3adb7f95625..7af8d208832 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.h"
#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
+#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
@@ -61,52 +62,47 @@ CSSStyleValue* StylePropertyMapReadOnlyMainThread::get(
const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) {
- const CSSPropertyID property_id = cssPropertyID(property_name);
- if (property_id == CSSPropertyInvalid) {
+ base::Optional<CSSPropertyName> name = CSSPropertyName::From(property_name);
+
+ if (!name) {
exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
return nullptr;
}
- DCHECK(isValidCSSPropertyID(property_id));
- const CSSProperty& property = CSSProperty::Get(property_id);
+ const CSSProperty& property = CSSProperty::Get(name->Id());
if (property.IsShorthand())
return GetShorthandProperty(property);
- AtomicString custom_property_name = property_id == CSSPropertyVariable
- ? AtomicString(property_name)
- : g_null_atom;
-
const CSSValue* value =
- (property_id == CSSPropertyVariable)
- ? GetCustomProperty(*execution_context, custom_property_name)
- : GetProperty(property_id);
+ (name->IsCustomProperty())
+ ? GetCustomProperty(*execution_context, name->ToAtomicString())
+ : GetProperty(name->Id());
if (!value)
return nullptr;
// Custom properties count as repeated whenever we have a CSSValueList.
if (property.IsRepeated() ||
- (property_id == CSSPropertyVariable && value->IsValueList())) {
- CSSStyleValueVector values = StyleValueFactory::CssValueToStyleValueVector(
- property_id, custom_property_name, *value);
+ (name->IsCustomProperty() && value->IsValueList())) {
+ CSSStyleValueVector values =
+ StyleValueFactory::CssValueToStyleValueVector(*name, *value);
return values.IsEmpty() ? nullptr : values[0];
}
- return StyleValueFactory::CssValueToStyleValue(property_id,
- custom_property_name, *value);
+ return StyleValueFactory::CssValueToStyleValue(*name, *value);
}
CSSStyleValueVector StylePropertyMapReadOnlyMainThread::getAll(
const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) {
- CSSPropertyID property_id = cssPropertyID(property_name);
- if (property_id == CSSPropertyInvalid) {
+ base::Optional<CSSPropertyName> name = CSSPropertyName::From(property_name);
+
+ if (!name) {
exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
return CSSStyleValueVector();
}
- DCHECK(isValidCSSPropertyID(property_id));
- const CSSProperty& property = CSSProperty::Get(property_id);
+ const CSSProperty& property = CSSProperty::Get(name->Id());
if (property.IsShorthand()) {
CSSStyleValueVector values;
if (CSSStyleValue* value = GetShorthandProperty(property))
@@ -114,19 +110,14 @@ CSSStyleValueVector StylePropertyMapReadOnlyMainThread::getAll(
return values;
}
- AtomicString custom_property_name = property_id == CSSPropertyVariable
- ? AtomicString(property_name)
- : g_null_atom;
-
const CSSValue* value =
- (property_id == CSSPropertyVariable)
- ? GetCustomProperty(*execution_context, custom_property_name)
- : GetProperty(property_id);
+ (name->IsCustomProperty())
+ ? GetCustomProperty(*execution_context, name->ToAtomicString())
+ : GetProperty(name->Id());
if (!value)
return CSSStyleValueVector();
- return StyleValueFactory::CssValueToStyleValueVector(
- property_id, custom_property_name, *value);
+ return StyleValueFactory::CssValueToStyleValueVector(*name, *value);
}
bool StylePropertyMapReadOnlyMainThread::has(
@@ -156,29 +147,25 @@ StylePropertyMapReadOnlyMainThread::StartIteration(ScriptState* script_state,
const ExecutionContext& execution_context =
*ExecutionContext::From(script_state);
- ForEachProperty([&result, &execution_context](const String& property_name,
+ ForEachProperty([&result, &execution_context](const CSSPropertyName& name,
const CSSValue& css_value) {
- const auto property_id = cssPropertyID(property_name);
-
const CSSValue* value = &css_value;
- AtomicString custom_property_name = g_null_atom;
-
- if (property_id == CSSPropertyVariable) {
- custom_property_name = AtomicString(property_name);
+ // TODO(andruud): Refactor this. ForEachProperty should yield the correct,
+ // already-parsed value in the first place.
+ if (name.IsCustomProperty()) {
const auto* document = DynamicTo<Document>(execution_context);
if (document) {
value = PropertyRegistry::ParseIfRegistered(
- *document, custom_property_name, value);
+ *document, name.ToAtomicString(), value);
}
}
- auto values = StyleValueFactory::CssValueToStyleValueVector(
- property_id, custom_property_name, *value);
- result.emplace_back(property_name, std::move(values));
+ auto values = StyleValueFactory::CssValueToStyleValueVector(name, *value);
+ result.emplace_back(name.ToAtomicString(), std::move(values));
});
- return new StylePropertyMapIterationSource(result);
+ return MakeGarbageCollected<StylePropertyMapIterationSource>(result);
}
CSSStyleValue* StylePropertyMapReadOnlyMainThread::GetShorthandProperty(
@@ -187,8 +174,8 @@ CSSStyleValue* StylePropertyMapReadOnlyMainThread::GetShorthandProperty(
const auto serialization = SerializationForShorthand(property);
if (serialization.IsEmpty())
return nullptr;
- return CSSUnsupportedStyleValue::Create(property.PropertyID(), g_null_atom,
- serialization);
+ return CSSUnsupportedStyleValue::Create(
+ CSSPropertyName(property.PropertyID()), serialization);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.h b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.h
index dab11e66550..0acda918953 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map_read_only_main_thread.h
@@ -10,6 +10,7 @@
namespace blink {
class CSSProperty;
+class CSSPropertyName;
class CORE_EXPORT StylePropertyMapReadOnlyMainThread
: public StylePropertyMapReadOnly {
@@ -37,7 +38,7 @@ class CORE_EXPORT StylePropertyMapReadOnlyMainThread
virtual const CSSValue* GetCustomProperty(AtomicString) = 0;
using IterationCallback =
- std::function<void(const AtomicString&, const CSSValue&)>;
+ std::function<void(const CSSPropertyName&, const CSSValue&)>;
virtual void ForEachProperty(const IterationCallback&) = 0;
virtual String SerializationForShorthand(const CSSProperty&) = 0;
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc b/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
index 29b7fd06596..73d9f24f9c5 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_image_value.h"
+#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/core/css/css_value_pair.h"
#include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
@@ -31,6 +32,20 @@ namespace blink {
namespace {
+// Reify and return a CSSStyleValue, if |value| can be reified without the
+// context of a CSS property.
+CSSStyleValue* CreateStyleValueWithoutProperty(const CSSValue& value) {
+ if (value.IsCSSWideKeyword())
+ return CSSKeywordValue::FromCSSValue(value);
+ if (value.IsVariableReferenceValue())
+ return CSSUnparsedValue::FromCSSValue(ToCSSVariableReferenceValue(value));
+ if (value.IsCustomPropertyDeclaration()) {
+ return CSSUnparsedValue::FromCSSValue(
+ ToCSSCustomPropertyDeclaration(value));
+ }
+ return nullptr;
+}
+
CSSStyleValue* CreateStyleValue(const CSSValue& value) {
if (value.IsIdentifierValue() || value.IsCustomIdentValue())
return CSSKeywordValue::FromCSSValue(value);
@@ -85,7 +100,8 @@ CSSStyleValue* CreateStyleValueWithPropertyInternal(CSSPropertyID property_id,
ToCSSIdentifierValue(value).GetValueID() == CSSValueCurrentcolor) {
return CSSKeywordValue::Create("currentcolor");
}
- return CSSUnsupportedStyleValue::Create(property_id, g_null_atom, value);
+ return CSSUnsupportedStyleValue::Create(CSSPropertyName(property_id),
+ value);
case CSSPropertyContain: {
if (value.IsIdentifierValue())
return CreateStyleValue(value);
@@ -195,19 +211,15 @@ CSSStyleValue* CreateStyleValueWithPropertyInternal(CSSPropertyID property_id,
CSSStyleValue* CreateStyleValueWithProperty(CSSPropertyID property_id,
const CSSValue& value) {
- // These cannot be overridden by individual properties.
- if (value.IsCSSWideKeyword())
- return CSSKeywordValue::FromCSSValue(value);
- if (value.IsVariableReferenceValue())
- return CSSUnparsedValue::FromCSSValue(ToCSSVariableReferenceValue(value));
- if (value.IsCustomPropertyDeclaration()) {
- return CSSUnparsedValue::FromCSSValue(
- ToCSSCustomPropertyDeclaration(value));
- }
+ DCHECK_NE(property_id, CSSPropertyInvalid);
+
+ if (CSSStyleValue* style_value = CreateStyleValueWithoutProperty(value))
+ return style_value;
if (!CSSOMTypes::IsPropertySupported(property_id)) {
DCHECK_NE(property_id, CSSPropertyVariable);
- return CSSUnsupportedStyleValue::Create(property_id, g_null_atom, value);
+ return CSSUnsupportedStyleValue::Create(CSSPropertyName(property_id),
+ value);
}
CSSStyleValue* style_value =
@@ -217,14 +229,10 @@ CSSStyleValue* CreateStyleValueWithProperty(CSSPropertyID property_id,
return CreateStyleValue(value);
}
-CSSStyleValueVector UnsupportedCSSValue(
- CSSPropertyID property_id,
- const AtomicString& custom_property_name,
- const CSSValue& value) {
- DCHECK_EQ(property_id == CSSPropertyVariable, !custom_property_name.IsNull());
+CSSStyleValueVector UnsupportedCSSValue(const CSSPropertyName& name,
+ const CSSValue& value) {
CSSStyleValueVector style_value_vector;
- style_value_vector.push_back(CSSUnsupportedStyleValue::Create(
- property_id, custom_property_name, value));
+ style_value_vector.push_back(CSSUnsupportedStyleValue::Create(name, value));
return style_value_vector;
}
@@ -249,7 +257,7 @@ CSSStyleValueVector StyleValueFactory::FromString(
StyleRule::RuleType::kStyle)) {
if (parsed_properties.size() == 1) {
const auto result = StyleValueFactory::CssValueToStyleValueVector(
- parsed_properties[0].Id(), g_null_atom,
+ CSSPropertyName(parsed_properties[0].Id()),
*parsed_properties[0].Value());
// TODO(801935): Handle list-valued properties.
if (result.size() == 1U)
@@ -260,8 +268,8 @@ CSSStyleValueVector StyleValueFactory::FromString(
// Shorthands are not yet supported.
CSSStyleValueVector result;
- result.push_back(
- CSSUnsupportedStyleValue::Create(property_id, g_null_atom, css_text));
+ result.push_back(CSSUnsupportedStyleValue::Create(
+ CSSPropertyName(property_id), css_text));
return result;
}
@@ -273,7 +281,7 @@ CSSStyleValueVector StyleValueFactory::FromString(
return CSSStyleValueVector();
return StyleValueFactory::CssValueToStyleValueVector(
- property_id, custom_property_name, *value);
+ CSSPropertyName(custom_property_name), *value);
}
if ((property_id == CSSPropertyVariable && !tokens.IsEmpty()) ||
@@ -291,17 +299,13 @@ CSSStyleValueVector StyleValueFactory::FromString(
}
CSSStyleValue* StyleValueFactory::CssValueToStyleValue(
- CSSPropertyID property_id,
- const AtomicString& custom_property_name,
+ const CSSPropertyName& name,
const CSSValue& css_value) {
- DCHECK(!CSSProperty::Get(property_id).IsRepeated());
- DCHECK_EQ(property_id == CSSPropertyVariable, !custom_property_name.IsNull());
+ DCHECK(!CSSProperty::Get(name.Id()).IsRepeated());
CSSStyleValue* style_value =
- CreateStyleValueWithProperty(property_id, css_value);
- if (!style_value) {
- return CSSUnsupportedStyleValue::Create(property_id, custom_property_name,
- css_value);
- }
+ CreateStyleValueWithProperty(name.Id(), css_value);
+ if (!style_value)
+ return CSSUnsupportedStyleValue::Create(name, css_value);
return style_value;
}
@@ -338,12 +342,11 @@ CSSStyleValueVector StyleValueFactory::CoerceStyleValuesOrStrings(
}
CSSStyleValueVector StyleValueFactory::CssValueToStyleValueVector(
- CSSPropertyID property_id,
- const AtomicString& custom_property_name,
+ const CSSPropertyName& name,
const CSSValue& css_value) {
- DCHECK_EQ(property_id == CSSPropertyVariable, !custom_property_name.IsNull());
CSSStyleValueVector style_value_vector;
+ CSSPropertyID property_id = name.Id();
CSSStyleValue* style_value =
CreateStyleValueWithProperty(property_id, css_value);
if (style_value) {
@@ -364,7 +367,7 @@ CSSStyleValueVector StyleValueFactory::CssValueToStyleValueVector(
// https://github.com/w3c/css-houdini-drafts/issues/290
(property_id == CSSPropertyVariable &&
CSSTransformComponent::FromCSSValue(css_value))) {
- return UnsupportedCSSValue(property_id, custom_property_name, css_value);
+ return UnsupportedCSSValue(name, css_value);
}
// We assume list-valued properties are always stored as a list.
@@ -372,7 +375,7 @@ CSSStyleValueVector StyleValueFactory::CssValueToStyleValueVector(
for (const CSSValue* inner_value : css_value_list) {
style_value = CreateStyleValueWithProperty(property_id, *inner_value);
if (!style_value)
- return UnsupportedCSSValue(property_id, custom_property_name, css_value);
+ return UnsupportedCSSValue(name, css_value);
style_value_vector.push_back(style_value);
}
return style_value_vector;
@@ -380,7 +383,14 @@ CSSStyleValueVector StyleValueFactory::CssValueToStyleValueVector(
CSSStyleValueVector StyleValueFactory::CssValueToStyleValueVector(
const CSSValue& css_value) {
- return CssValueToStyleValueVector(CSSPropertyInvalid, g_null_atom, css_value);
+ CSSStyleValueVector style_value_vector;
+
+ if (CSSStyleValue* value = CreateStyleValueWithoutProperty(css_value))
+ style_value_vector.push_back(value);
+ else
+ style_value_vector.push_back(CSSUnsupportedStyleValue::Create(css_value));
+
+ return style_value_vector;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.h b/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.h
index 094c4635dc1..97e73500a10 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.h
@@ -14,6 +14,7 @@ namespace blink {
class CSSParserContext;
class CSSProperty;
+class CSSPropertyName;
class CSSValue;
class ExecutionContext;
class PropertyRegistration;
@@ -28,14 +29,10 @@ class CORE_EXPORT StyleValueFactory {
const PropertyRegistration*,
const String&,
const CSSParserContext*);
- static CSSStyleValue* CssValueToStyleValue(
- CSSPropertyID,
- const AtomicString& custom_property_name,
- const CSSValue&);
- static CSSStyleValueVector CssValueToStyleValueVector(
- CSSPropertyID,
- const AtomicString& custom_property_name,
- const CSSValue&);
+ static CSSStyleValue* CssValueToStyleValue(const CSSPropertyName&,
+ const CSSValue&);
+ static CSSStyleValueVector CssValueToStyleValueVector(const CSSPropertyName&,
+ const CSSValue&);
// Returns an empty vector on error conditions.
static CSSStyleValueVector CoerceStyleValuesOrStrings(
const CSSProperty& property,
@@ -43,7 +40,16 @@ class CORE_EXPORT StyleValueFactory {
const PropertyRegistration*,
const HeapVector<CSSStyleValueOrString>& values,
const ExecutionContext&);
- // If you don't have complex CSS properties, use this one.
+ // Reify a CSSStyleValue without the context of a CSS property. For most
+ // CSSValues, this will result in a CSSUnsupportedStyleValue. Note that the
+ // CSSUnsupportedStyleValue returned from this function (unlike regular
+ // CSSUnsupportedStyleValues) do not have an associated CSS property,
+ // which means that any attempt to StylePropertyMap.set/setAll such values
+ // will always fail. Therefore, this function should only be used in
+ // situations where declared and inline style objects [1] are not accessible,
+ // such as paint worklets.
+ //
+ // [1] https://www.w3.org/TR/css-typed-om-1/#declared-stylepropertymap-objects
static CSSStyleValueVector CssValueToStyleValueVector(const CSSValue&);
};
diff --git a/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc b/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
index f2564bb483e..2bb47e92ca2 100644
--- a/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
+++ b/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
@@ -91,20 +91,15 @@ void DocumentStyleSheetCollection::CollectStyleSheetsFromCandidates(
if (!GetTreeScope().HasAdoptedStyleSheets())
return;
- StyleSheetList& adopted_style_sheets = GetTreeScope().AdoptedStyleSheets();
- unsigned length = adopted_style_sheets.length();
- for (unsigned index = 0; index < length; ++index) {
- StyleSheet* sheet = adopted_style_sheets.item(index);
- if (!sheet)
- continue;
- CSSStyleSheet* css_sheet = ToCSSStyleSheet(sheet);
- if (!css_sheet ||
- !css_sheet->CanBeActivated(
+ for (CSSStyleSheet* sheet : GetTreeScope().AdoptedStyleSheets()) {
+ if (!sheet ||
+ !sheet->CanBeActivated(
GetDocument().GetStyleEngine().PreferredStylesheetSetName()))
continue;
+ DCHECK_EQ(GetDocument(), sheet->AssociatedDocument());
collector.AppendSheetForList(sheet);
collector.AppendActiveStyleSheet(
- std::make_pair(css_sheet, master_engine.RuleSetForSheet(*css_sheet)));
+ std::make_pair(sheet, master_engine.RuleSetForSheet(*sheet)));
}
}
diff --git a/chromium/third_party/blink/renderer/core/css/font_face.cc b/chromium/third_party/blink/renderer/core/css/font_face.cc
index 85cb342aa95..f983d2b6359 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face.cc
@@ -456,8 +456,8 @@ void FontFace::SetError(DOMException* error) {
ScriptPromise FontFace::FontStatusPromise(ScriptState* script_state) {
if (!loaded_property_) {
- loaded_property_ = new LoadedProperty(ExecutionContext::From(script_state),
- this, LoadedProperty::kLoaded);
+ loaded_property_ = MakeGarbageCollected<LoadedProperty>(
+ ExecutionContext::From(script_state), this, LoadedProperty::kLoaded);
if (status_ == kLoaded)
loaded_property_->Resolve(this);
else if (status_ == kError)
@@ -741,7 +741,8 @@ void FontFace::InitCSSFontFace(const unsigned char* data, size_t size) {
scoped_refptr<SharedBuffer> buffer = SharedBuffer::Create(data, size);
BinaryDataFontFaceSource* source =
- new BinaryDataFontFaceSource(buffer.get(), ots_parse_message_);
+ MakeGarbageCollected<BinaryDataFontFaceSource>(buffer.get(),
+ ots_parse_message_);
if (source->IsValid())
SetLoadStatus(kLoaded);
else
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc b/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc
index b80e2624494..0cc922c1e84 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face_cache_test.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 "third_party/blink/renderer/core/css/font_face_cache.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/css_font_face_src_value.h"
#include "third_party/blink/renderer/core/css/css_font_family_value.h"
@@ -11,7 +13,6 @@
#include "third_party/blink/renderer/core/css/css_segmented_font_face.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/font_face.h"
-#include "third_party/blink/renderer/core/css/font_face_cache.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
@@ -70,7 +71,7 @@ void FontFaceCacheTest::AppendTestFaceForCapabilities(const CSSValue& stretch,
CSSPropertyValue(GetCSSPropertyFontFamily(), *family_name),
CSSPropertyValue(GetCSSPropertySrc(), *src_value_list)};
MutableCSSPropertyValueSet* font_face_descriptor =
- MutableCSSPropertyValueSet::Create(properties, arraysize(properties));
+ MutableCSSPropertyValueSet::Create(properties, base::size(properties));
font_face_descriptor->SetProperty(CSSPropertyFontStretch, stretch);
font_face_descriptor->SetProperty(CSSPropertyFontStyle, style);
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set.cc b/chromium/third_party/blink/renderer/core/css/font_face_set.cc
index d67753bbdfa..886ba8d69e1 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set.cc
@@ -7,30 +7,29 @@
#include "third_party/blink/renderer/core/css/font_face_cache.h"
#include "third_party/blink/renderer/core/css/font_face_set_load_event.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
const int FontFaceSet::kDefaultFontSize = 10;
const char FontFaceSet::kDefaultFontFamily[] = "sans-serif";
-void FontFaceSet::Pause() {
- async_runner_->Pause();
-}
-
-void FontFaceSet::Unpause() {
- async_runner_->Unpause();
-}
-
-void FontFaceSet::ContextDestroyed(ExecutionContext*) {
- async_runner_->Stop();
-}
-
void FontFaceSet::HandlePendingEventsAndPromisesSoon() {
- // async_runner_ will be automatically stopped on destruction.
- async_runner_->RunAsync();
+ if (!pending_task_queued_) {
+ if (auto* context = GetExecutionContext()) {
+ pending_task_queued_ = true;
+ context->GetTaskRunner(TaskType::kFontLoading)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&FontFaceSet::HandlePendingEventsAndPromises,
+ WrapPersistent(this)));
+ }
+ }
}
void FontFaceSet::HandlePendingEventsAndPromises() {
+ pending_task_queued_ = false;
+ if (!GetExecutionContext())
+ return;
FireLoadingEvent();
FireDoneEventIfPossible();
}
@@ -112,8 +111,7 @@ void FontFaceSet::Trace(blink::Visitor* visitor) {
visitor->Trace(loaded_fonts_);
visitor->Trace(failed_fonts_);
visitor->Trace(ready_);
- visitor->Trace(async_runner_);
- PausableObject::Trace(visitor);
+ ContextClient::Trace(visitor);
EventTargetWithInlineData::Trace(visitor);
FontFace::LoadFontCallback::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set.h b/chromium/third_party/blink/renderer/core/css/font_face_set.h
index b56e097baf1..935a00684cc 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set.h
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set.h
@@ -12,10 +12,9 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/css/font_face.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/fonts/font_selector.h"
@@ -32,23 +31,17 @@ class FontFaceCache;
using FontFaceSetIterable = SetlikeIterable<Member<FontFace>>;
class CORE_EXPORT FontFaceSet : public EventTargetWithInlineData,
- public PausableObject,
+ public ContextClient,
public FontFaceSetIterable,
public FontFace::LoadFontCallback {
DEFINE_WRAPPERTYPEINFO();
public:
FontFaceSet(ExecutionContext& context)
- : PausableObject(&context),
- is_loading_(false),
- should_fire_loading_event_(false),
- ready_(new ReadyProperty(GetExecutionContext(),
- this,
- ReadyProperty::kReady)),
- async_runner_(AsyncMethodRunner<FontFaceSet>::Create(
- this,
- &FontFaceSet::HandlePendingEventsAndPromises,
- context.GetTaskRunner(TaskType::kInternalDefault))) {}
+ : ContextClient(&context),
+ ready_(MakeGarbageCollected<ReadyProperty>(GetExecutionContext(),
+ this,
+ ReadyProperty::kReady)) {}
~FontFaceSet() override = default;
DEFINE_ATTRIBUTE_EVENT_LISTENER(loading, kLoading);
@@ -60,7 +53,7 @@ class CORE_EXPORT FontFaceSet : public EventTargetWithInlineData,
virtual ScriptPromise ready(ScriptState*) = 0;
ExecutionContext* GetExecutionContext() const override {
- return PausableObject::GetExecutionContext();
+ return ContextClient::GetExecutionContext();
}
const AtomicString& InterfaceName() const override {
@@ -74,11 +67,6 @@ class CORE_EXPORT FontFaceSet : public EventTargetWithInlineData,
void AddFontFacesToFontFaceCache(FontFaceCache*);
- // PausableObject
- void Pause() override;
- void Unpause() override;
- void ContextDestroyed(ExecutionContext*) override;
-
wtf_size_t size() const;
virtual AtomicString status() const = 0;
@@ -109,16 +97,15 @@ class CORE_EXPORT FontFaceSet : public EventTargetWithInlineData,
Member<FontFaceSet>,
Member<DOMException>>;
- bool is_loading_;
- bool should_fire_loading_event_;
+ bool is_loading_ = false;
+ bool should_fire_loading_event_ = false;
+ bool pending_task_queued_ = false;
HeapLinkedHashSet<Member<FontFace>> non_css_connected_faces_;
HeapHashSet<Member<FontFace>> loading_fonts_;
FontFaceArray loaded_fonts_;
FontFaceArray failed_fonts_;
Member<ReadyProperty> ready_;
- Member<AsyncMethodRunner<FontFaceSet>> async_runner_;
-
class IterationSource final : public FontFaceSetIterable::IterationSource {
public:
explicit IterationSource(const HeapVector<Member<FontFace>>& font_faces)
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc b/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc
index 36b128a3c59..8c760925ca9 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc
@@ -48,15 +48,10 @@ const char FontFaceSetDocument::kSupplementName[] = "FontFaceSetDocument";
FontFaceSetDocument::FontFaceSetDocument(Document& document)
: FontFaceSet(document), Supplement<Document>(document) {
- PauseIfNeeded();
}
FontFaceSetDocument::~FontFaceSetDocument() = default;
-Document* FontFaceSetDocument::GetDocument() const {
- return To<Document>(GetExecutionContext());
-}
-
bool FontFaceSetDocument::InActiveContext() const {
ExecutionContext* context = GetExecutionContext();
return context && To<Document>(context)->IsActive();
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set_document.h b/chromium/third_party/blink/renderer/core/css/font_face_set_document.h
index 0ced9aaa9fc..f6b2a638669 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set_document.h
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set_document.h
@@ -36,7 +36,6 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/platform/async_method_runner.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -59,8 +58,6 @@ class CORE_EXPORT FontFaceSetDocument final : public FontFaceSet,
AtomicString status() const override;
- Document* GetDocument() const;
-
void DidLayout();
void BeginFontLoading(FontFace*);
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set_worker.cc b/chromium/third_party/blink/renderer/core/css/font_face_set_worker.cc
index 5e7ee27f0fb..270f40abf59 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set_worker.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set_worker.cc
@@ -26,7 +26,6 @@ const char FontFaceSetWorker::kSupplementName[] = "FontFaceSetWorker";
FontFaceSetWorker::FontFaceSetWorker(WorkerGlobalScope& worker)
: FontFaceSet(worker), Supplement<WorkerGlobalScope>(worker) {
- PauseIfNeeded();
}
FontFaceSetWorker::~FontFaceSetWorker() = default;
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set_worker.h b/chromium/third_party/blink/renderer/core/css/font_face_set_worker.h
index f56d7f2903a..bf397c4b1fb 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set_worker.h
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set_worker.h
@@ -11,7 +11,6 @@
#include "third_party/blink/renderer/core/css/font_face.h"
#include "third_party/blink/renderer/core/css/font_face_set.h"
#include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/async_method_runner.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc b/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc
index c8192681129..1c85e0576cf 100644
--- a/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc
@@ -69,25 +69,23 @@ bool InvalidationSet::InvalidatesElement(Element& element) const {
if (invalidation_flags_.WholeSubtreeInvalid())
return true;
- if (tag_names_ &&
- tag_names_->Contains(element.LocalNameForSelectorMatching())) {
+ if (HasTagName(element.LocalNameForSelectorMatching())) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(
element, kInvalidationSetMatchedTagName, *this,
element.LocalNameForSelectorMatching());
return true;
}
- if (element.HasID() && ids_ &&
- ids_->Contains(element.IdForStyleResolution())) {
+ if (element.HasID() && HasId(element.IdForStyleResolution())) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(
element, kInvalidationSetMatchedId, *this,
element.IdForStyleResolution());
return true;
}
- if (element.HasClass() && classes_) {
+ if (element.HasClass() && HasClasses()) {
const SpaceSplitString& class_names = element.ClassNames();
- for (const auto& class_name : *classes_) {
+ for (const auto& class_name : Classes()) {
if (class_names.Contains(class_name)) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(
element, kInvalidationSetMatchedClass, *this, class_name);
@@ -96,8 +94,8 @@ bool InvalidationSet::InvalidatesElement(Element& element) const {
}
}
- if (element.hasAttributes() && attributes_) {
- for (const auto& attribute : *attributes_) {
+ if (element.hasAttributes() && HasAttributes()) {
+ for (const auto& attribute : Attributes()) {
if (element.hasAttribute(attribute)) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(
element, kInvalidationSetMatchedAttribute, *this, attribute);
@@ -116,8 +114,7 @@ bool InvalidationSet::InvalidatesElement(Element& element) const {
}
bool InvalidationSet::InvalidatesTagName(Element& element) const {
- if (tag_names_ &&
- tag_names_->Contains(element.LocalNameForSelectorMatching())) {
+ if (HasTagName(element.LocalNameForSelectorMatching())) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(
element, kInvalidationSetMatchedTagName, *this,
element.LocalNameForSelectorMatching());
@@ -189,25 +186,17 @@ void InvalidationSet::Combine(const InvalidationSet& other) {
if (other.InvalidatesParts())
SetInvalidatesParts();
- if (other.classes_) {
- for (const auto& class_name : *other.classes_)
- AddClass(class_name);
- }
+ for (const auto& class_name : other.Classes())
+ AddClass(class_name);
- if (other.ids_) {
- for (const auto& id : *other.ids_)
- AddId(id);
- }
+ for (const auto& id : other.Ids())
+ AddId(id);
- if (other.tag_names_) {
- for (const auto& tag_name : *other.tag_names_)
- AddTagName(tag_name);
- }
+ for (const auto& tag_name : other.TagNames())
+ AddTagName(tag_name);
- if (other.attributes_) {
- for (const auto& attribute : *other.attributes_)
- AddAttribute(attribute);
- }
+ for (const auto& attribute : other.Attributes())
+ AddAttribute(attribute);
}
void InvalidationSet::Destroy() const {
@@ -217,56 +206,45 @@ void InvalidationSet::Destroy() const {
delete ToSiblingInvalidationSet(this);
}
-HashSet<AtomicString>& InvalidationSet::EnsureClassSet() {
- if (!classes_)
- classes_ = std::make_unique<HashSet<AtomicString>>();
- return *classes_;
-}
-
-HashSet<AtomicString>& InvalidationSet::EnsureIdSet() {
- if (!ids_)
- ids_ = std::make_unique<HashSet<AtomicString>>();
- return *ids_;
-}
-
-HashSet<AtomicString>& InvalidationSet::EnsureTagNameSet() {
- if (!tag_names_)
- tag_names_ = std::make_unique<HashSet<AtomicString>>();
- return *tag_names_;
+void InvalidationSet::ClearAllBackings() {
+ classes_.Clear(backing_flags_);
+ ids_.Clear(backing_flags_);
+ tag_names_.Clear(backing_flags_);
+ attributes_.Clear(backing_flags_);
}
-HashSet<AtomicString>& InvalidationSet::EnsureAttributeSet() {
- if (!attributes_)
- attributes_ = std::make_unique<HashSet<AtomicString>>();
- return *attributes_;
+bool InvalidationSet::HasEmptyBackings() const {
+ return classes_.IsEmpty(backing_flags_) && ids_.IsEmpty(backing_flags_) &&
+ tag_names_.IsEmpty(backing_flags_) &&
+ attributes_.IsEmpty(backing_flags_);
}
void InvalidationSet::AddClass(const AtomicString& class_name) {
if (WholeSubtreeInvalid())
return;
CHECK(!class_name.IsEmpty());
- EnsureClassSet().insert(class_name);
+ classes_.Add(backing_flags_, class_name);
}
void InvalidationSet::AddId(const AtomicString& id) {
if (WholeSubtreeInvalid())
return;
CHECK(!id.IsEmpty());
- EnsureIdSet().insert(id);
+ ids_.Add(backing_flags_, id);
}
void InvalidationSet::AddTagName(const AtomicString& tag_name) {
if (WholeSubtreeInvalid())
return;
CHECK(!tag_name.IsEmpty());
- EnsureTagNameSet().insert(tag_name);
+ tag_names_.Add(backing_flags_, tag_name);
}
void InvalidationSet::AddAttribute(const AtomicString& attribute) {
if (WholeSubtreeInvalid())
return;
CHECK(!attribute.IsEmpty());
- EnsureAttributeSet().insert(attribute);
+ attributes_.Add(backing_flags_, attribute);
}
void InvalidationSet::SetWholeSubtreeInvalid() {
@@ -279,10 +257,7 @@ void InvalidationSet::SetWholeSubtreeInvalid() {
invalidation_flags_.SetInsertionPointCrossing(false);
invalidation_flags_.SetInvalidatesSlotted(false);
invalidation_flags_.SetInvalidatesParts(false);
- classes_ = nullptr;
- ids_ = nullptr;
- tag_names_ = nullptr;
- attributes_ = nullptr;
+ ClearAllBackings();
}
namespace {
@@ -330,30 +305,30 @@ void InvalidationSet::ToTracedValue(TracedValue* value) const {
if (invalidation_flags_.InvalidatesParts())
value->SetBoolean("invalidatesParts", true);
- if (ids_) {
+ if (HasIds()) {
value->BeginArray("ids");
- for (const auto& id : *ids_)
+ for (const auto& id : Ids())
value->PushString(id);
value->EndArray();
}
- if (classes_) {
+ if (HasClasses()) {
value->BeginArray("classes");
- for (const auto& class_name : *classes_)
+ for (const auto& class_name : Classes())
value->PushString(class_name);
value->EndArray();
}
- if (tag_names_) {
+ if (HasTagNames()) {
value->BeginArray("tagNames");
- for (const auto& tag_name : *tag_names_)
+ for (const auto& tag_name : TagNames())
value->PushString(tag_name);
value->EndArray();
}
- if (attributes_) {
+ if (HasAttributes()) {
value->BeginArray("attributes");
- for (const auto& attribute : *attributes_)
+ for (const auto& attribute : Attributes())
value->PushString(attribute);
value->EndArray();
}
diff --git a/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.h b/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.h
index 46e5e578466..5ab9e943826 100644
--- a/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.h
+++ b/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set.h
@@ -165,7 +165,7 @@ class CORE_EXPORT InvalidationSet
}
bool IsEmpty() const {
- return !classes_ && !ids_ && !tag_names_ && !attributes_ &&
+ return HasEmptyBackings() &&
!invalidation_flags_.InvalidateCustomPseudo() &&
!invalidation_flags_.InsertionPointCrossing() &&
!invalidation_flags_.InvalidatesSlotted() &&
@@ -180,23 +180,6 @@ class CORE_EXPORT InvalidationSet
void Show() const;
#endif
- const HashSet<AtomicString>& ClassSetForTesting() const {
- DCHECK(classes_);
- return *classes_;
- }
- const HashSet<AtomicString>& IdSetForTesting() const {
- DCHECK(ids_);
- return *ids_;
- }
- const HashSet<AtomicString>& TagNameSetForTesting() const {
- DCHECK(tag_names_);
- return *tag_names_;
- }
- const HashSet<AtomicString>& AttributeSetForTesting() const {
- DCHECK(attributes_);
- return *attributes_;
- }
-
void Combine(const InvalidationSet& other);
// Returns a singleton DescendantInvalidationSet which only has
@@ -211,30 +194,176 @@ class CORE_EXPORT InvalidationSet
// shadow-including descendants with part attributes.
static InvalidationSet* PartInvalidationSet();
+ enum class BackingType {
+ kClasses,
+ kIds,
+ kTagNames,
+ kAttributes
+ // These values are used as bit-indices, and must be smaller than 8.
+ // See Backing::GetMask.
+ };
+
+ template <BackingType>
+ union Backing;
+
+ // Each BackingType has a corresponding bit in an instance of this class. A
+ // set bit indicates that the Backing at that position is a HashSet. An unset
+ // bit indicates a StringImpl (which may be nullptr).
+ class BackingFlags {
+ private:
+ uint8_t bits_ = 0;
+ template <BackingType>
+ friend union Backing;
+ };
+
+ // InvalidationSet needs to maintain HashSets of classes, ids, tag names and
+ // attributes to invalidate. However, since it's common for these hash sets
+ // to contain only one element (with a total capacity of 8), we avoid creating
+ // the actual HashSets until we have more than one item. If a set contains
+ // just one item, we store a pointer to a StringImpl instead, along with a
+ // bit indicating either StringImpl or HashSet.
+ //
+ // The bits (see BackingFlags) associated with each Backing are stored on the
+ // outside, to make sizeof(InvalidationSet) as small as possible.
+ //
+ // WARNING: Backings must be cleared manually in ~InvalidationSet, otherwise
+ // a StringImpl or HashSet will leak.
+ template <BackingType type>
+ union Backing {
+ using Flags = BackingFlags;
+ static_assert(static_cast<size_t>(type) < sizeof(BackingFlags::bits_) * 8,
+ "Enough bits in BackingFlags");
+
+ // Adds an AtomicString to the associated Backing. If the Backing is
+ // currently empty, we simply AddRef the StringImpl of the incoming
+ // AtomicString. If the Backing already has one item, we first "upgrade"
+ // to a HashSet, and add the AtomicString.
+ void Add(Flags&, const AtomicString&);
+ // Clears the associated Backing. If the Backing is a StringImpl, it is
+ // released. If the Backing is a HashSet, it is deleted.
+ void Clear(Flags&);
+ bool Contains(const Flags&, const AtomicString&) const;
+ bool IsEmpty(const Flags&) const;
+ bool IsHashSet(const Flags& flags) const { return flags.bits_ & GetMask(); }
+
+ // A simple forward iterator, which can either "iterate" over a single
+ // StringImpl, or act as a wrapper for HashSet<AtomicString>::iterator.
+ class Iterator {
+ public:
+ enum class Type { kString, kHashSet };
+
+ explicit Iterator(StringImpl* string_impl)
+ : type_(Type::kString), string_(string_impl) {}
+ explicit Iterator(HashSet<AtomicString>::iterator iterator)
+ : type_(Type::kHashSet), hash_set_iterator_(iterator) {}
+
+ bool operator==(const Iterator& other) const {
+ if (type_ != other.type_)
+ return false;
+ if (type_ == Type::kString)
+ return string_ == other.string_;
+ return hash_set_iterator_ == other.hash_set_iterator_;
+ }
+ bool operator!=(const Iterator& other) const { return !(*this == other); }
+ void operator++() {
+ if (type_ == Type::kString)
+ string_ = g_null_atom;
+ else
+ ++hash_set_iterator_;
+ }
+
+ const AtomicString& operator*() const {
+ return type_ == Type::kString ? string_ : *hash_set_iterator_;
+ }
+
+ private:
+ Type type_;
+ // Used when type_ is kString.
+ AtomicString string_;
+ // Used when type_ is kHashSet.
+ HashSet<AtomicString>::iterator hash_set_iterator_;
+ };
+
+ class Range {
+ public:
+ Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
+ Iterator begin() const { return begin_; };
+ Iterator end() const { return end_; };
+
+ private:
+ Iterator begin_;
+ Iterator end_;
+ };
+
+ Range Items(const Flags& flags) const {
+ Iterator begin = IsHashSet(flags) ? Iterator(hash_set_->begin())
+ : Iterator(string_impl_);
+ Iterator end = IsHashSet(flags) ? Iterator(hash_set_->end())
+ : Iterator(g_null_atom.Impl());
+ return Range(begin, end);
+ }
+
+ private:
+ uint8_t GetMask() const { return 1u << static_cast<size_t>(type); }
+ void SetIsString(Flags& flags) { flags.bits_ &= ~GetMask(); }
+ void SetIsHashSet(Flags& flags) { flags.bits_ |= GetMask(); }
+
+ StringImpl* string_impl_ = nullptr;
+ HashSet<AtomicString>* hash_set_;
+ };
+
protected:
explicit InvalidationSet(InvalidationType);
~InvalidationSet() {
CHECK(is_alive_);
is_alive_ = false;
+ ClearAllBackings();
}
private:
friend struct InvalidationSetDeleter;
+ friend class RuleFeatureSetTest;
void Destroy() const;
+ void ClearAllBackings();
+ bool HasEmptyBackings() const;
+
+ bool HasClasses() const { return !classes_.IsEmpty(backing_flags_); }
+ bool HasIds() const { return !ids_.IsEmpty(backing_flags_); }
+ bool HasTagNames() const { return !tag_names_.IsEmpty(backing_flags_); }
+ bool HasAttributes() const { return !attributes_.IsEmpty(backing_flags_); }
+
+ bool HasId(const AtomicString& string) const {
+ return ids_.Contains(backing_flags_, string);
+ }
+
+ bool HasTagName(const AtomicString& string) const {
+ return tag_names_.Contains(backing_flags_, string);
+ }
- HashSet<AtomicString>& EnsureClassSet();
- HashSet<AtomicString>& EnsureIdSet();
- HashSet<AtomicString>& EnsureTagNameSet();
- HashSet<AtomicString>& EnsureAttributeSet();
+ Backing<BackingType::kClasses>::Range Classes() const {
+ return classes_.Items(backing_flags_);
+ }
- // FIXME: optimize this if it becomes a memory issue.
- std::unique_ptr<HashSet<AtomicString>> classes_;
- std::unique_ptr<HashSet<AtomicString>> ids_;
- std::unique_ptr<HashSet<AtomicString>> tag_names_;
- std::unique_ptr<HashSet<AtomicString>> attributes_;
+ Backing<BackingType::kIds>::Range Ids() const {
+ return ids_.Items(backing_flags_);
+ }
+
+ Backing<BackingType::kTagNames>::Range TagNames() const {
+ return tag_names_.Items(backing_flags_);
+ }
+
+ Backing<BackingType::kAttributes>::Range Attributes() const {
+ return attributes_.Items(backing_flags_);
+ }
+
+ Backing<BackingType::kClasses> classes_;
+ Backing<BackingType::kIds> ids_;
+ Backing<BackingType::kTagNames> tag_names_;
+ Backing<BackingType::kAttributes> attributes_;
InvalidationFlags invalidation_flags_;
+ BackingFlags backing_flags_;
unsigned type_ : 1;
@@ -303,6 +432,61 @@ struct InvalidationLists {
InvalidationSetVector siblings;
};
+template <typename InvalidationSet::BackingType type>
+void InvalidationSet::Backing<type>::Add(InvalidationSet::BackingFlags& flags,
+ const AtomicString& string) {
+ DCHECK(!string.IsNull());
+ if (IsHashSet(flags)) {
+ hash_set_->insert(string);
+ } else if (string_impl_) {
+ if (Equal(string_impl_, string.Impl()))
+ return;
+ AtomicString atomic_string(string_impl_);
+ string_impl_->Release();
+ hash_set_ = new HashSet<AtomicString>();
+ hash_set_->insert(atomic_string);
+ hash_set_->insert(string);
+ SetIsHashSet(flags);
+ } else {
+ string_impl_ = string.Impl();
+ string_impl_->AddRef();
+ }
+}
+
+template <typename InvalidationSet::BackingType type>
+void InvalidationSet::Backing<type>::Clear(
+ InvalidationSet::BackingFlags& flags) {
+ if (IsHashSet(flags)) {
+ if (hash_set_) {
+ delete hash_set_;
+ string_impl_ = nullptr;
+ }
+ } else {
+ if (string_impl_) {
+ string_impl_->Release();
+ string_impl_ = nullptr;
+ }
+ }
+ SetIsString(flags);
+}
+
+template <typename InvalidationSet::BackingType type>
+bool InvalidationSet::Backing<type>::Contains(
+ const InvalidationSet::BackingFlags& flags,
+ const AtomicString& string) const {
+ if (IsHashSet(flags))
+ return hash_set_->Contains(string);
+ if (string_impl_)
+ return Equal(string.Impl(), string_impl_);
+ return false;
+}
+
+template <typename InvalidationSet::BackingType type>
+bool InvalidationSet::Backing<type>::IsEmpty(
+ const InvalidationSet::BackingFlags& flags) const {
+ return !IsHashSet(flags) && !string_impl_;
+}
+
DEFINE_TYPE_CASTS(DescendantInvalidationSet,
InvalidationSet,
value,
diff --git a/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set_test.cc b/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set_test.cc
index d349080ae60..c78335147db 100644
--- a/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/invalidation/invalidation_set_test.cc
@@ -7,6 +7,230 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
+namespace {
+
+using BackingType = InvalidationSet::BackingType;
+using BackingFlags = InvalidationSet::BackingFlags;
+template <BackingType type>
+using Backing = InvalidationSet::Backing<type>;
+
+template <BackingType type>
+bool HasAny(const Backing<type>& backing,
+ const BackingFlags& flags,
+ std::initializer_list<const char*> args) {
+ for (const char* str : args) {
+ if (backing.Contains(flags, str))
+ return true;
+ }
+ return false;
+}
+
+template <BackingType type>
+bool HasAll(const Backing<type>& backing,
+ const BackingFlags& flags,
+ std::initializer_list<const char*> args) {
+ for (const char* str : args) {
+ if (!backing.Contains(flags, str))
+ return false;
+ }
+ return true;
+}
+
+TEST(InvalidationSetTest, Backing_Create) {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ ASSERT_FALSE(backing.IsHashSet(flags));
+}
+
+TEST(InvalidationSetTest, Backing_Add) {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ backing.Add(flags, AtomicString("test1"));
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ backing.Add(flags, AtomicString("test2"));
+ ASSERT_TRUE(backing.IsHashSet(flags));
+}
+
+TEST(InvalidationSetTest, Backing_AddSame) {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ backing.Add(flags, AtomicString("test1"));
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ backing.Add(flags, AtomicString("test1"));
+ // No need to upgrade to HashSet if we're adding the item we already have.
+ ASSERT_FALSE(backing.IsHashSet(flags));
+}
+
+TEST(InvalidationSetTest, Backing_Independence) {
+ BackingFlags flags;
+
+ Backing<BackingType::kClasses> classes;
+ Backing<BackingType::kIds> ids;
+ Backing<BackingType::kTagNames> tag_names;
+ Backing<BackingType::kAttributes> attributes;
+
+ classes.Add(flags, "test1");
+ ids.Add(flags, "test2");
+ tag_names.Add(flags, "test3");
+ attributes.Add(flags, "test4");
+
+ // Adding to set does not affect other backings:
+ ASSERT_TRUE(classes.Contains(flags, "test1"));
+ ASSERT_FALSE(HasAny(classes, flags, {"test2", "test3", "test4"}));
+
+ ASSERT_TRUE(ids.Contains(flags, "test2"));
+ ASSERT_FALSE(HasAny(ids, flags, {"test1", "test3", "test4"}));
+
+ ASSERT_TRUE(tag_names.Contains(flags, "test3"));
+ ASSERT_FALSE(HasAny(tag_names, flags, {"test1", "test2", "test4"}));
+
+ ASSERT_TRUE(attributes.Contains(flags, "test4"));
+ ASSERT_FALSE(HasAny(attributes, flags, {"test1", "test2", "test3"}));
+
+ // Adding additional items to one set does not affect others:
+ classes.Add(flags, "test5");
+ tag_names.Add(flags, "test6");
+
+ ASSERT_TRUE(HasAll(classes, flags, {"test1", "test5"}));
+ ASSERT_FALSE(HasAny(classes, flags, {"test2", "test3", "test4", "test6"}));
+
+ ASSERT_TRUE(ids.Contains(flags, "test2"));
+ ASSERT_FALSE(
+ HasAny(ids, flags, {"test1", "test3", "test4", "test5", "test6"}));
+
+ ASSERT_TRUE(HasAll(tag_names, flags, {"test3", "test6"}));
+ ASSERT_FALSE(HasAny(tag_names, flags, {"test1", "test2", "test4", "test5"}));
+
+ ASSERT_TRUE(attributes.Contains(flags, "test4"));
+ ASSERT_FALSE(HasAny(attributes, flags, {"test1", "test2", "test3"}));
+
+ // Clearing one set does not clear others:
+
+ classes.Clear(flags);
+ ids.Clear(flags);
+ attributes.Clear(flags);
+
+ auto all_test_strings = {"test1", "test2", "test3",
+ "test4", "test5", "test6"};
+
+ ASSERT_FALSE(HasAny(classes, flags, all_test_strings));
+ ASSERT_FALSE(HasAny(ids, flags, all_test_strings));
+ ASSERT_FALSE(HasAny(attributes, flags, all_test_strings));
+
+ ASSERT_FALSE(classes.IsHashSet(flags));
+ ASSERT_FALSE(ids.IsHashSet(flags));
+ ASSERT_FALSE(attributes.IsHashSet(flags));
+
+ ASSERT_TRUE(tag_names.IsHashSet(flags));
+ ASSERT_TRUE(HasAll(tag_names, flags, {"test3", "test6"}));
+ ASSERT_FALSE(HasAny(tag_names, flags, {"test1", "test2", "test4", "test5"}));
+}
+
+TEST(InvalidationSetTest, Backing_ClearContains) {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ // Clearing an empty set:
+ ASSERT_FALSE(backing.Contains(flags, "test1"));
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ backing.Clear(flags);
+ ASSERT_FALSE(backing.IsHashSet(flags));
+
+ // Add one element to the set, and clear it:
+ backing.Add(flags, "test1");
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ ASSERT_TRUE(backing.Contains(flags, "test1"));
+ backing.Clear(flags);
+ ASSERT_FALSE(backing.Contains(flags, "test1"));
+ ASSERT_FALSE(backing.IsHashSet(flags));
+
+ // Add two elements to the set, and clear them:
+ backing.Add(flags, "test1");
+ ASSERT_FALSE(backing.IsHashSet(flags));
+ ASSERT_TRUE(backing.Contains(flags, "test1"));
+ ASSERT_FALSE(backing.Contains(flags, "test2"));
+ backing.Add(flags, "test2");
+ ASSERT_TRUE(backing.IsHashSet(flags));
+ ASSERT_TRUE(backing.Contains(flags, "test1"));
+ ASSERT_TRUE(backing.Contains(flags, "test2"));
+ backing.Clear(flags);
+ ASSERT_FALSE(backing.Contains(flags, "test1"));
+ ASSERT_FALSE(backing.Contains(flags, "test2"));
+ ASSERT_FALSE(backing.IsHashSet(flags));
+}
+
+TEST(InvalidationSetTest, Backing_BackingIsEmpty) {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ ASSERT_TRUE(backing.IsEmpty(flags));
+ backing.Add(flags, "test1");
+ ASSERT_FALSE(backing.IsEmpty(flags));
+ backing.Add(flags, "test2");
+ backing.Clear(flags);
+ ASSERT_TRUE(backing.IsEmpty(flags));
+}
+
+TEST(InvalidationSetTest, Backing_IsEmpty) {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ ASSERT_TRUE(backing.IsEmpty(flags));
+
+ backing.Add(flags, "test1");
+ ASSERT_FALSE(backing.IsEmpty(flags));
+
+ backing.Clear(flags);
+ ASSERT_TRUE(backing.IsEmpty(flags));
+}
+
+TEST(InvalidationSetTest, Backing_Iterator) {
+ // Iterate over empty set.
+ {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ Vector<AtomicString> strings;
+ for (const AtomicString& str : backing.Items(flags))
+ strings.push_back(str);
+ ASSERT_EQ(0u, strings.size());
+ }
+
+ // Iterate over set with one item.
+ {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ backing.Add(flags, "test1");
+ Vector<AtomicString> strings;
+ for (const AtomicString& str : backing.Items(flags))
+ strings.push_back(str);
+ ASSERT_EQ(1u, strings.size());
+ ASSERT_TRUE(strings.Contains("test1"));
+ }
+
+ // Iterate over set with multiple items.
+ {
+ BackingFlags flags;
+ Backing<BackingType::kClasses> backing;
+
+ backing.Add(flags, "test1");
+ backing.Add(flags, "test2");
+ backing.Add(flags, "test3");
+ Vector<AtomicString> strings;
+ for (const AtomicString& str : backing.Items(flags))
+ strings.push_back(str);
+ ASSERT_EQ(3u, strings.size());
+ ASSERT_TRUE(strings.Contains("test1"));
+ ASSERT_TRUE(strings.Contains("test2"));
+ ASSERT_TRUE(strings.Contains("test3"));
+ }
+}
// Once we setWholeSubtreeInvalid, we should not keep the HashSets.
TEST(InvalidationSetTest, SubtreeInvalid_AddBefore) {
@@ -88,4 +312,5 @@ TEST(InvalidationSetTest, ShowDebug) {
}
#endif // NDEBUG
+} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_feature_names.json5 b/chromium/third_party/blink/renderer/core/css/media_feature_names.json5
index 4640d1a8340..976f70d400c 100644
--- a/chromium/third_party/blink/renderer/core/css/media_feature_names.json5
+++ b/chromium/third_party/blink/renderer/core/css/media_feature_names.json5
@@ -48,6 +48,8 @@
"min-width",
"min-resolution",
"pointer",
+ "prefers-color-scheme",
+ "prefers-reduced-motion",
"resolution",
"-webkit-transform-3d",
"scan",
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc b/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc
index e0e5ca28faa..e78a42f7899 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/public/common/manifest/web_display_mode.h"
#include "third_party/blink/public/platform/pointer_properties.h"
#include "third_party/blink/public/platform/shape_properties.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_resolution_units.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
@@ -701,6 +702,22 @@ static bool PointerMediaFeatureEval(const MediaQueryExpValue& value,
(pointer == kPointerTypeFine && value.id == CSSValueFine);
}
+static bool PrefersReducedMotionMediaFeatureEval(
+ const MediaQueryExpValue& value,
+ MediaFeaturePrefix,
+ const MediaValues& media_values) {
+ // If the value is not valid, this was passed without an argument. In that
+ // case, it implicitly resolves to 'reduce'.
+ if (!value.IsValid())
+ return media_values.PrefersReducedMotion();
+
+ if (!value.is_id)
+ return false;
+
+ return (value.id == CSSValueNoPreference) ^
+ media_values.PrefersReducedMotion();
+}
+
static bool ShapeMediaFeatureEval(const MediaQueryExpValue& value,
MediaFeaturePrefix,
const MediaValues& media_values) {
@@ -809,6 +826,26 @@ static bool ColorGamutMediaFeatureEval(const MediaQueryExpValue& value,
return false;
}
+static bool PrefersColorSchemeMediaFeatureEval(
+ const MediaQueryExpValue& value,
+ MediaFeaturePrefix,
+ const MediaValues& media_values) {
+ WebColorScheme preferred_scheme = media_values.PreferredColorScheme();
+
+ if (!value.IsValid())
+ return preferred_scheme != WebColorScheme::kNoPreference;
+
+ if (!value.is_id)
+ return false;
+
+ return (preferred_scheme == WebColorScheme::kNoPreference &&
+ value.id == CSSValueNoPreference) ||
+ (preferred_scheme == WebColorScheme::kDark &&
+ value.id == CSSValueDark) ||
+ (preferred_scheme == WebColorScheme::kLight &&
+ value.id == CSSValueLight);
+}
+
void MediaQueryEvaluator::Init() {
// Create the table.
g_function_map = new FunctionMap;
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_exp.cc b/chromium/third_party/blink/renderer/core/css/media_query_exp.cc
index 8719608cb98..02a0ce831ed 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -72,6 +72,19 @@ static inline bool FeatureWithValidIdent(const String& media_feature,
ident == CSSValueRec2020;
}
+ if (RuntimeEnabledFeatures::MediaQueryPrefersColorSchemeEnabled()) {
+ if (media_feature == kPrefersColorSchemeMediaFeature) {
+ return ident == CSSValueNoPreference || ident == CSSValueDark ||
+ ident == CSSValueLight;
+ }
+ }
+
+ if (RuntimeEnabledFeatures::MediaQueryPrefersReducedMotionEnabled()) {
+ if (media_feature == kPrefersReducedMotionMediaFeature) {
+ return ident == CSSValueNoPreference || ident == CSSValueReduce;
+ }
+ }
+
return false;
}
@@ -186,7 +199,10 @@ static inline bool FeatureWithoutValue(const String& media_feature) {
media_feature == kScanMediaFeature ||
media_feature == kShapeMediaFeature ||
media_feature == kColorGamutMediaFeature ||
- media_feature == kImmersiveMediaFeature;
+ media_feature == kImmersiveMediaFeature ||
+ media_feature == kPrefersColorSchemeMediaFeature ||
+ (RuntimeEnabledFeatures::MediaQueryPrefersReducedMotionEnabled() &&
+ media_feature == kPrefersReducedMotionMediaFeature);
}
bool MediaQueryExp::IsViewportDependent() const {
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_list.cc b/chromium/third_party/blink/renderer/core/css/media_query_list.cc
index 51ebc837cb4..82f9d0848c4 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_list.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_list.cc
@@ -52,18 +52,12 @@ String MediaQueryList::media() const {
return media_->MediaText();
}
-void MediaQueryList::addDeprecatedListener(EventListener* listener) {
- if (!listener)
- return;
-
- addEventListener(event_type_names::kChange, listener, false);
+void MediaQueryList::addDeprecatedListener(V8EventListener* listener) {
+ addEventListener(event_type_names::kChange, listener);
}
-void MediaQueryList::removeDeprecatedListener(EventListener* listener) {
- if (!listener)
- return;
-
- removeEventListener(event_type_names::kChange, listener, false);
+void MediaQueryList::removeDeprecatedListener(V8EventListener* listener) {
+ removeEventListener(event_type_names::kChange, listener);
}
void MediaQueryList::AddListener(MediaQueryListListener* listener) {
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_list.h b/chromium/third_party/blink/renderer/core/css/media_query_list.h
index 4ca8fd6b741..687ef7945d9 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_list.h
+++ b/chromium/third_party/blink/renderer/core/css/media_query_list.h
@@ -66,8 +66,8 @@ class CORE_EXPORT MediaQueryList final
// These two functions are provided for compatibility with JS code
// written before the change listener became a DOM event.
- void addDeprecatedListener(EventListener*);
- void removeDeprecatedListener(EventListener*);
+ void addDeprecatedListener(V8EventListener*);
+ void removeDeprecatedListener(V8EventListener*);
// C++ code can use these functions to listen to changes instead of having to
// use DOM event listeners.
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_list_event.h b/chromium/third_party/blink/renderer/core/css/media_query_list_event.h
index c150a53a640..834144f4db3 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_list_event.h
+++ b/chromium/third_party/blink/renderer/core/css/media_query_list_event.h
@@ -60,6 +60,19 @@ class MediaQueryListEvent final : public Event {
return event_interface_names::kMediaQueryListEvent;
}
+ // beforeprint/afterprint events need to be dispatched while the execution
+ // context is paused. When printing, window.print() invoked by beforeprint/
+ // afterprint event listeners should have no effect, hence the event dispatch
+ // needs to be done during the pause.
+ // Accordingly, MediaQueryListEvent is also expected to be dispatched while
+ // printing.
+ bool ShouldDispatchEvenWhenExecutionContextIsPaused() const override {
+ // TODO(thestig,yukishiino): Probably it's better to return true only when
+ // we're actually printing. It's possible that execution contexts are
+ // paused for other reasons (e.g. other modal dialogs).
+ return true;
+ }
+
void Trace(blink::Visitor* visitor) override {
Event::Trace(visitor);
visitor->Trace(media_query_list_);
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_list_test.cc b/chromium/third_party/blink/renderer/core/css/media_query_list_test.cc
index 17c1226c0d7..a42e6349310 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_list_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_list_test.cc
@@ -25,7 +25,7 @@ TEST(MediaQueryListTest, CrashInStop) {
Document* document = Document::CreateForTest();
MediaQueryList* list = MediaQueryList::Create(
document, MediaQueryMatcher::Create(*document), MediaQuerySet::Create());
- list->AddListener(new TestListener());
+ list->AddListener(MakeGarbageCollected<TestListener>());
list->ContextDestroyed(document);
// This test passes if it's not crashed.
}
diff --git a/chromium/third_party/blink/renderer/core/css/media_values.cc b/chromium/third_party/blink/renderer/core/css/media_values.cc
index 1a63d544825..3dd82185dd8 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_values.cc
@@ -176,6 +176,18 @@ ColorSpaceGamut MediaValues::CalculateColorGamut(LocalFrame* frame) {
frame->GetPage()->GetChromeClient().GetScreenInfo());
}
+WebColorScheme MediaValues::CalculatePreferredColorScheme(LocalFrame* frame) {
+ DCHECK(frame);
+ DCHECK(frame->GetSettings());
+ return frame->GetSettings()->GetPreferredColorScheme();
+}
+
+bool MediaValues::CalculatePrefersReducedMotion(LocalFrame* frame) {
+ DCHECK(frame);
+ DCHECK(frame->GetSettings());
+ return frame->GetSettings()->GetPrefersReducedMotion();
+}
+
bool MediaValues::ComputeLengthImpl(double value,
CSSPrimitiveValue::UnitType type,
unsigned default_font_size,
diff --git a/chromium/third_party/blink/renderer/core/css/media_values.h b/chromium/third_party/blink/renderer/core/css/media_values.h
index c33d238427b..b95315b2558 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values.h
+++ b/chromium/third_party/blink/renderer/core/css/media_values.h
@@ -18,6 +18,7 @@ class Document;
class CSSPrimitiveValue;
class LocalFrame;
enum class ColorSpaceGamut;
+enum class WebColorScheme;
class CORE_EXPORT MediaValues : public GarbageCollectedFinalized<MediaValues> {
public:
@@ -76,6 +77,8 @@ class CORE_EXPORT MediaValues : public GarbageCollectedFinalized<MediaValues> {
virtual void OverrideViewportDimensions(double width, double height) = 0;
virtual DisplayShape GetDisplayShape() const = 0;
virtual ColorSpaceGamut ColorGamut() const = 0;
+ virtual WebColorScheme PreferredColorScheme() const = 0;
+ virtual bool PrefersReducedMotion() const = 0;
protected:
static double CalculateViewportWidth(LocalFrame*);
@@ -97,6 +100,8 @@ class CORE_EXPORT MediaValues : public GarbageCollectedFinalized<MediaValues> {
static int CalculateAvailableHoverTypes(LocalFrame*);
static DisplayShape CalculateDisplayShape(LocalFrame*);
static ColorSpaceGamut CalculateColorGamut(LocalFrame*);
+ static WebColorScheme CalculatePreferredColorScheme(LocalFrame*);
+ static bool CalculatePrefersReducedMotion(LocalFrame*);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_cached.cc b/chromium/third_party/blink/renderer/core/css/media_values_cached.cc
index 5d8f675d030..65385045089 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_cached.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_values_cached.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/css/media_values_cached.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -30,7 +31,9 @@ MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData()
strict_mode(true),
display_mode(kWebDisplayModeBrowser),
display_shape(kDisplayShapeRect),
- color_gamut(ColorSpaceGamut::kUnknown) {}
+ color_gamut(ColorSpaceGamut::kUnknown),
+ preferred_color_scheme(WebColorScheme::kNoPreference),
+ prefers_reduced_motion(false) {}
MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
Document& document)
@@ -69,6 +72,8 @@ MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
media_type = MediaValues::CalculateMediaType(frame);
display_shape = MediaValues::CalculateDisplayShape(frame);
color_gamut = MediaValues::CalculateColorGamut(frame);
+ preferred_color_scheme = MediaValues::CalculatePreferredColorScheme(frame);
+ prefers_reduced_motion = MediaValues::CalculatePrefersReducedMotion(frame);
}
}
@@ -192,4 +197,12 @@ ColorSpaceGamut MediaValuesCached::ColorGamut() const {
return data_.color_gamut;
}
+WebColorScheme MediaValuesCached::PreferredColorScheme() const {
+ return data_.preferred_color_scheme;
+}
+
+bool MediaValuesCached::PrefersReducedMotion() const {
+ return data_.prefers_reduced_motion;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_cached.h b/chromium/third_party/blink/renderer/core/css/media_values_cached.h
index dfa427f7c38..aad52e0f1df 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_cached.h
+++ b/chromium/third_party/blink/renderer/core/css/media_values_cached.h
@@ -36,6 +36,8 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
WebDisplayMode display_mode;
DisplayShape display_shape;
ColorSpaceGamut color_gamut;
+ WebColorScheme preferred_color_scheme;
+ bool prefers_reduced_motion;
MediaValuesCachedData();
explicit MediaValuesCachedData(Document&);
@@ -61,6 +63,8 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
data.display_mode = display_mode;
data.display_shape = display_shape;
data.color_gamut = color_gamut;
+ data.preferred_color_scheme = preferred_color_scheme;
+ data.prefers_reduced_motion = prefers_reduced_motion;
return data;
}
};
@@ -100,6 +104,8 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
WebDisplayMode DisplayMode() const override;
DisplayShape GetDisplayShape() const override;
ColorSpaceGamut ColorGamut() const override;
+ WebColorScheme PreferredColorScheme() const override;
+ bool PrefersReducedMotion() const override;
void OverrideViewportDimensions(double width, double height) override;
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc
index 6d8ad635a0c..bb31bc4b79b 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/css/media_values_dynamic.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_resolution_units.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
@@ -52,17 +53,17 @@ MediaValues* MediaValuesDynamic::Copy() const {
bool MediaValuesDynamic::ComputeLength(double value,
CSSPrimitiveValue::UnitType type,
int& result) const {
- return MediaValues::ComputeLength(
- value, type, CalculateDefaultFontSize(frame_),
- CalculateViewportWidth(frame_), CalculateViewportHeight(frame_), result);
+ return MediaValues::ComputeLength(value, type,
+ CalculateDefaultFontSize(frame_),
+ ViewportWidth(), ViewportHeight(), result);
}
bool MediaValuesDynamic::ComputeLength(double value,
CSSPrimitiveValue::UnitType type,
double& result) const {
- return MediaValues::ComputeLength(
- value, type, CalculateDefaultFontSize(frame_),
- CalculateViewportWidth(frame_), CalculateViewportHeight(frame_), result);
+ return MediaValues::ComputeLength(value, type,
+ CalculateDefaultFontSize(frame_),
+ ViewportWidth(), ViewportHeight(), result);
}
double MediaValuesDynamic::ViewportWidth() const {
@@ -141,6 +142,14 @@ ColorSpaceGamut MediaValuesDynamic::ColorGamut() const {
return CalculateColorGamut(frame_);
}
+WebColorScheme MediaValuesDynamic::PreferredColorScheme() const {
+ return CalculatePreferredColorScheme(frame_);
+}
+
+bool MediaValuesDynamic::PrefersReducedMotion() const {
+ return CalculatePrefersReducedMotion(frame_);
+}
+
Document* MediaValuesDynamic::GetDocument() const {
return frame_->GetDocument();
}
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h
index 0d522475059..dae64dc63f3 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h
+++ b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h
@@ -48,6 +48,8 @@ class CORE_EXPORT MediaValuesDynamic : public MediaValues {
WebDisplayMode DisplayMode() const override;
DisplayShape GetDisplayShape() const override;
ColorSpaceGamut ColorGamut() const override;
+ WebColorScheme PreferredColorScheme() const override;
+ bool PrefersReducedMotion() const override;
Document* GetDocument() const override;
bool HasValues() const override;
void OverrideViewportDimensions(double width, double height) override;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc
index fa214682792..330f7d27c84 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc
@@ -33,9 +33,9 @@ CSSParserContext* CSSParserContext::Create(const ExecutionContext& context) {
policy_disposition = kCheckContentSecurityPolicy;
return MakeGarbageCollected<CSSParserContext>(
- context.Url(), false /* is_opaque_response_from_service_worker */,
- WTF::TextEncoding(), kHTMLStandardMode, kHTMLStandardMode, kLiveProfile,
- referrer, true, false, context.GetSecureContextMode(), policy_disposition,
+ context.Url(), true /* origin_clean */, WTF::TextEncoding(),
+ kHTMLStandardMode, kHTMLStandardMode, kLiveProfile, referrer, true, false,
+ context.GetSecureContextMode(), policy_disposition,
DynamicTo<Document>(context));
}
@@ -60,9 +60,9 @@ CSSParserContext* CSSParserContext::Create(
const CSSParserContext* other,
const Document* use_counter_document) {
return MakeGarbageCollected<CSSParserContext>(
- other->base_url_, other->is_opaque_response_from_service_worker_,
- other->charset_, other->mode_, other->match_mode_, other->profile_,
- other->referrer_, other->is_html_document_,
+ other->base_url_, other->origin_clean_, other->charset_, other->mode_,
+ other->match_mode_, other->profile_, other->referrer_,
+ other->is_html_document_,
other->use_legacy_background_size_shorthand_behavior_,
other->secure_context_mode_, other->should_check_content_security_policy_,
use_counter_document);
@@ -72,13 +72,13 @@ CSSParserContext* CSSParserContext::Create(
CSSParserContext* CSSParserContext::Create(
const CSSParserContext* other,
const KURL& base_url,
- bool is_opaque_response_from_service_worker,
+ bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy,
const WTF::TextEncoding& charset,
const Document* use_counter_document) {
return MakeGarbageCollected<CSSParserContext>(
- base_url, is_opaque_response_from_service_worker, charset, other->mode_,
- other->match_mode_, other->profile_,
+ base_url, origin_clean, charset, other->mode_, other->match_mode_,
+ other->profile_,
Referrer(base_url.StrippedForUseAsReferrer(), referrer_policy),
other->is_html_document_,
other->use_legacy_background_size_shorthand_behavior_,
@@ -93,17 +93,15 @@ CSSParserContext* CSSParserContext::Create(
SelectorProfile profile,
const Document* use_counter_document) {
return MakeGarbageCollected<CSSParserContext>(
- KURL(), false /* is_opaque_response_from_service_worker */,
- WTF::TextEncoding(), mode, mode, profile, Referrer(), false, false,
- secure_context_mode, kDoNotCheckContentSecurityPolicy,
- use_counter_document);
+ KURL(), true /* origin_clean */, WTF::TextEncoding(), mode, mode, profile,
+ Referrer(), false, false, secure_context_mode,
+ kDoNotCheckContentSecurityPolicy, use_counter_document);
}
// static
CSSParserContext* CSSParserContext::Create(const Document& document) {
return CSSParserContext::Create(
- document, document.BaseURL(),
- false /* is_opaque_response_from_service_worker */,
+ document, document.BaseURL(), true /* origin_clean */,
document.GetReferrerPolicy(), WTF::TextEncoding(), kLiveProfile);
}
@@ -111,7 +109,7 @@ CSSParserContext* CSSParserContext::Create(const Document& document) {
CSSParserContext* CSSParserContext::Create(
const Document& document,
const KURL& base_url_override,
- bool is_opaque_response_from_service_worker,
+ bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy_override,
const WTF::TextEncoding& charset,
SelectorProfile profile) {
@@ -143,15 +141,15 @@ CSSParserContext* CSSParserContext::Create(
policy_disposition = kCheckContentSecurityPolicy;
return MakeGarbageCollected<CSSParserContext>(
- base_url_override, is_opaque_response_from_service_worker, charset, mode,
- match_mode, profile, referrer, document.IsHTMLDocument(),
+ base_url_override, origin_clean, charset, mode, match_mode, profile,
+ referrer, document.IsHTMLDocument(),
use_legacy_background_size_shorthand_behavior,
document.GetSecureContextMode(), policy_disposition, &document);
}
CSSParserContext::CSSParserContext(
const KURL& base_url,
- bool is_opaque_response_from_service_worker,
+ bool origin_clean,
const WTF::TextEncoding& charset,
CSSParserMode mode,
CSSParserMode match_mode,
@@ -163,8 +161,7 @@ CSSParserContext::CSSParserContext(
ContentSecurityPolicyDisposition policy_disposition,
const Document* use_counter_document)
: base_url_(base_url),
- is_opaque_response_from_service_worker_(
- is_opaque_response_from_service_worker),
+ origin_clean_(origin_clean),
charset_(charset),
mode_(mode),
match_mode_(match_mode),
@@ -178,9 +175,9 @@ CSSParserContext::CSSParserContext(
document_(use_counter_document) {}
bool CSSParserContext::operator==(const CSSParserContext& other) const {
- return base_url_ == other.base_url_ && charset_ == other.charset_ &&
- mode_ == other.mode_ && match_mode_ == other.match_mode_ &&
- profile_ == other.profile_ &&
+ return base_url_ == other.base_url_ && origin_clean_ == other.origin_clean_ &&
+ charset_ == other.charset_ && mode_ == other.mode_ &&
+ match_mode_ == other.match_mode_ && profile_ == other.profile_ &&
is_html_document_ == other.is_html_document_ &&
use_legacy_background_size_shorthand_behavior_ ==
other.use_legacy_background_size_shorthand_behavior_ &&
@@ -206,8 +203,8 @@ const CSSParserContext* StrictCSSParserContext(
return context;
}
-bool CSSParserContext::IsOpaqueResponseFromServiceWorker() const {
- return is_opaque_response_from_service_worker_;
+bool CSSParserContext::IsOriginClean() const {
+ return origin_clean_;
}
bool CSSParserContext::IsSecureContext() const {
@@ -244,14 +241,10 @@ bool CSSParserContext::IsDocumentHandleEqual(const Document* other) const {
return document_.Get() == other;
}
-bool CSSParserContext::IsLayoutAnimationsPolicyEnforced() const {
- return document_ && !document_->IsFeatureEnabled(
- mojom::FeaturePolicyFeature::kLayoutAnimations);
-}
-
void CSSParserContext::ReportLayoutAnimationsViolationIfNeeded(
const StyleRuleKeyframe& rule) const {
- DCHECK(IsLayoutAnimationsPolicyEnforced());
+ if (!document_)
+ return;
for (size_t i = 0; i < rule.Properties().PropertyCount(); ++i) {
const CSSProperty& property = rule.Properties().PropertyAt(i).Property();
if (!LayoutAnimationsPolicy::AffectedCSSProperties().Contains(&property))
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h
index c14c66fda31..574a2296ee0 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h
@@ -45,7 +45,7 @@ class CORE_EXPORT CSSParserContext
static CSSParserContext* Create(
const CSSParserContext* other,
const KURL& base_url_override,
- bool is_opaque_response_from_service_worker,
+ bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy_override,
const WTF::TextEncoding& charset_override,
const Document* use_counter_document);
@@ -59,7 +59,7 @@ class CORE_EXPORT CSSParserContext
static CSSParserContext* Create(
const Document&,
const KURL& base_url_override,
- bool is_opaque_response_from_service_worker,
+ bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy_override,
const WTF::TextEncoding& charset = WTF::TextEncoding(),
SelectorProfile = kLiveProfile);
@@ -67,7 +67,7 @@ class CORE_EXPORT CSSParserContext
static CSSParserContext* Create(const ExecutionContext&);
CSSParserContext(const KURL& base_url,
- bool is_opaque_response_from_service_worker,
+ bool origin_clean,
const WTF::TextEncoding& charset,
CSSParserMode,
CSSParserMode match_mode,
@@ -92,9 +92,7 @@ class CORE_EXPORT CSSParserContext
bool IsHTMLDocument() const { return is_html_document_; }
bool IsLiveProfile() const { return profile_ == kLiveProfile; }
- // See documentation in StyleSheetContents for this function.
- bool IsOpaqueResponseFromServiceWorker() const;
-
+ bool IsOriginClean() const;
bool IsSecureContext() const;
// This quirk is to maintain compatibility with Android apps built on
@@ -129,14 +127,17 @@ class CORE_EXPORT CSSParserContext
// report CSS transitions as well (https://crbug.com/906147).
// TODO(ekaramad): We should provide a source location in the violation
// report (https://crbug.com/906150, ).
- bool IsLayoutAnimationsPolicyEnforced() const;
void ReportLayoutAnimationsViolationIfNeeded(const StyleRuleKeyframe&) const;
void Trace(blink::Visitor*);
private:
KURL base_url_;
- const bool is_opaque_response_from_service_worker_;
+
+ // If true, allows reading and modifying of the CSS rules.
+ // https://drafts.csswg.org/cssom/#concept-css-style-sheet-origin-clean-flag
+ const bool origin_clean_;
+
WTF::TextEncoding charset_;
CSSParserMode mode_;
CSSParserMode match_mode_;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
index 07d25b3c6f3..45e7ba7f9bc 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
@@ -877,7 +877,9 @@ bool CSSParserFastPaths::IsValidKeywordPropertyAndValue(
case CSSPropertyWhiteSpace:
return value_id == CSSValueNormal || value_id == CSSValuePre ||
value_id == CSSValuePreWrap || value_id == CSSValuePreLine ||
- value_id == CSSValueNowrap;
+ value_id == CSSValueNowrap ||
+ (RuntimeEnabledFeatures::CSS3TextBreakSpacesEnabled() &&
+ value_id == CSSValueBreakSpaces);
case CSSPropertyWordBreak:
return value_id == CSSValueNormal || value_id == CSSValueBreakAll ||
value_id == CSSValueKeepAll || value_id == CSSValueBreakWord;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
index 1f1d7f8c47e..0add560d8d4 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -319,8 +319,8 @@ CSSSelectorList CSSParserImpl::ParsePageSelector(
std::unique_ptr<CSSParserSelector> selector;
if (!type_selector.IsNull() && pseudo.IsNull()) {
- selector = CSSParserSelector::Create(QualifiedName(
- g_null_atom, type_selector, style_sheet->DefaultNamespace()));
+ selector = CSSParserSelector::Create(
+ QualifiedName(g_null_atom, type_selector, g_star_atom));
} else {
selector = CSSParserSelector::Create();
if (!pseudo.IsNull()) {
@@ -330,8 +330,8 @@ CSSSelectorList CSSParserImpl::ParsePageSelector(
return CSSSelectorList();
}
if (!type_selector.IsNull()) {
- selector->PrependTagSelector(QualifiedName(
- g_null_atom, type_selector, style_sheet->DefaultNamespace()));
+ selector->PrependTagSelector(
+ QualifiedName(g_null_atom, type_selector, g_star_atom));
}
}
@@ -572,9 +572,8 @@ StyleRuleBase* CSSParserImpl::ConsumeQualifiedRule(
CSSParserTokenStream::BlockGuard guard(stream);
StyleRuleKeyframe* keyframe_style_rule =
ConsumeKeyframeStyleRule(prelude, prelude_offset, stream);
- if (context_->IsLayoutAnimationsPolicyEnforced()) {
+ if (keyframe_style_rule)
context_->ReportLayoutAnimationsViolationIfNeeded(*keyframe_style_rule);
- }
return keyframe_style_rule;
}
if (allowed_rules == kFontFeatureRules) {
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h b/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h
index b55eda0e968..6cc896948e8 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h
@@ -99,6 +99,7 @@ class CORE_EXPORT CSSParserSelector {
bool IsTreeAbidingPseudoElement() const {
return selector_->IsTreeAbidingPseudoElement();
}
+ bool IsAllowedAfterPart() const { return selector_->IsAllowedAfterPart(); }
const CSSSelectorList* SelectorList() const {
return selector_->SelectorList();
}
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
index 7e7a1d43cac..1bc35b3f689 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -453,7 +453,9 @@ CSSPrimitiveValue* ConsumeGradientLengthOrPercent(
CSSPrimitiveValue* ConsumeAngle(
CSSParserTokenRange& range,
const CSSParserContext* context,
- base::Optional<WebFeature> unitless_zero_feature) {
+ base::Optional<WebFeature> unitless_zero_feature,
+ double minimum_value,
+ double maximum_value) {
// Ensure that we have a context for counting the
// unitless_zero_feature if it is requested.
DCHECK(context || !unitless_zero_feature);
@@ -479,12 +481,32 @@ CSSPrimitiveValue* ConsumeAngle(
}
CalcParser calc_parser(range, kValueRangeAll);
if (const CSSCalcValue* calculation = calc_parser.Value()) {
- if (calculation->Category() == kCalcAngle)
- return calc_parser.ConsumeValue();
+ if (calculation->Category() != kCalcAngle)
+ return nullptr;
+ if (CSSPrimitiveValue* result = calc_parser.ConsumeValue()) {
+ if (result->GetDoubleValue() < minimum_value) {
+ return CSSPrimitiveValue::Create(minimum_value,
+ result->TypeWithCalcResolved());
+ }
+ if (result->GetDoubleValue() > maximum_value) {
+ return CSSPrimitiveValue::Create(maximum_value,
+ result->TypeWithCalcResolved());
+ }
+ return result;
+ }
}
return nullptr;
}
+CSSPrimitiveValue* ConsumeAngle(
+ CSSParserTokenRange& range,
+ const CSSParserContext* context,
+ base::Optional<WebFeature> unitless_zero_feature) {
+ return ConsumeAngle(range, context, std::move(unitless_zero_feature),
+ std::numeric_limits<double>::lowest(),
+ std::numeric_limits<double>::max());
+}
+
CSSPrimitiveValue* ConsumeTime(CSSParserTokenRange& range,
ValueRange value_range) {
const CSSParserToken& token = range.Peek();
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
index dc58c66aafc..9dbf89cbc75 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
@@ -67,6 +67,12 @@ CSSPrimitiveValue* ConsumeAngle(
CSSParserTokenRange&,
const CSSParserContext*,
base::Optional<WebFeature> unitless_zero_feature);
+CSSPrimitiveValue* ConsumeAngle(
+ CSSParserTokenRange&,
+ const CSSParserContext*,
+ base::Optional<WebFeature> unitless_zero_feature,
+ double minimum_value,
+ double maximum_value);
CSSPrimitiveValue* ConsumeTime(CSSParserTokenRange&, ValueRange);
CSSPrimitiveValue* ConsumeResolution(CSSParserTokenRange&);
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
index 2918f7a99ee..ddfeaa52c39 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
@@ -263,12 +263,20 @@ bool IsPseudoClassValidAfterPseudoElement(
bool IsSimpleSelectorValidAfterPseudoElement(
const CSSParserSelector& simple_selector,
CSSSelector::PseudoType compound_pseudo_element) {
- if (compound_pseudo_element == CSSSelector::kPseudoUnknown)
- return true;
- if (compound_pseudo_element == CSSSelector::kPseudoContent)
- return simple_selector.Match() != CSSSelector::kPseudoElement;
- if (compound_pseudo_element == CSSSelector::kPseudoSlotted)
- return simple_selector.IsTreeAbidingPseudoElement();
+ switch (compound_pseudo_element) {
+ case CSSSelector::kPseudoUnknown:
+ return true;
+ case CSSSelector::kPseudoContent:
+ return simple_selector.Match() != CSSSelector::kPseudoElement;
+ case CSSSelector::kPseudoSlotted:
+ return simple_selector.IsTreeAbidingPseudoElement();
+ case CSSSelector::kPseudoPart:
+ if (simple_selector.IsAllowedAfterPart())
+ return true;
+ break;
+ default:
+ break;
+ }
if (simple_selector.Match() != CSSSelector::kPseudoClass)
return false;
CSSSelector::PseudoType pseudo = simple_selector.GetPseudoType();
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
index a795cba47fa..c588c5005c6 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
@@ -563,6 +563,26 @@ TEST(CSSSelectorParserTest, ShadowPartPseudoElementValid) {
}
}
+TEST(CSSSelectorParserTest, ShadowPartAndBeforeAfterPseudoElementValid) {
+ const char* test_cases[] = {
+ "::part(ident)::before", "::part(ident)::after",
+ "::part(ident)::placeholder", "::part(ident)::first-line",
+ "::part(ident)::first-letter", "::part(ident)::selection"};
+
+ for (auto* test_case : test_cases) {
+ SCOPED_TRACE(test_case);
+ CSSTokenizer tokenizer(test_case);
+ const auto tokens = tokenizer.TokenizeToEOF();
+ CSSParserTokenRange range(tokens);
+ CSSSelectorList list = CSSSelectorParser::ParseSelector(
+ range,
+ CSSParserContext::Create(kHTMLStandardMode,
+ SecureContextMode::kInsecureContext),
+ nullptr);
+ EXPECT_STREQ(test_case, list.SelectorsText().Ascii().data());
+ }
+}
+
TEST(CSSSelectorParserTest, UseCountShadowPseudo) {
std::unique_ptr<DummyPageHolder> dummy_holder =
DummyPageHolder::Create(IntSize(500, 500));
diff --git a/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 73b8a08f7a3..e71a1b6bef6 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
+#include "third_party/blink/renderer/core/svg/svg_element.h"
namespace blink {
@@ -502,7 +503,7 @@ CSSValue* ComputedStyleUtils::MinWidthOrMinHeightAuto(
LayoutObject* layout_object =
styled_node ? styled_node->GetLayoutObject() : nullptr;
if (layout_object && layout_object->IsBox() &&
- (ToLayoutBox(layout_object)->IsFlexItem() ||
+ (ToLayoutBox(layout_object)->IsFlexItemIncludingNG() ||
ToLayoutBox(layout_object)->IsGridItem())) {
return CSSIdentifierValue::Create(CSSValueAuto);
}
@@ -1272,14 +1273,28 @@ CSSValue* ComputedStyleUtils::ValueForGridPosition(
return list;
}
-LayoutRect ComputedStyleUtils::SizingBox(const LayoutObject& layout_object) {
- if (!layout_object.IsBox())
- return LayoutRect();
+static bool IsSVGObjectWithWidthAndHeight(const LayoutObject& layout_object) {
+ DCHECK(layout_object.IsSVGChild());
+ return layout_object.IsSVGImage() || layout_object.IsSVGForeignObject() ||
+ (layout_object.IsSVGShape() &&
+ IsSVGRectElement(layout_object.GetNode()));
+}
+FloatSize ComputedStyleUtils::UsedBoxSize(const LayoutObject& layout_object) {
+ if (layout_object.IsSVGChild() &&
+ IsSVGObjectWithWidthAndHeight(layout_object)) {
+ FloatSize size(layout_object.ObjectBoundingBox().Size());
+ // The object bounding box does not have zoom applied. Multiply with zoom
+ // here since we'll divide by it when we produce the CSS value.
+ size.Scale(layout_object.StyleRef().EffectiveZoom());
+ return size;
+ }
+ if (!layout_object.IsBox())
+ return FloatSize();
const LayoutBox& box = ToLayoutBox(layout_object);
- return box.StyleRef().BoxSizing() == EBoxSizing::kBorderBox
- ? box.BorderBoxRect()
- : box.ComputedCSSContentBoxRect();
+ return FloatSize(box.StyleRef().BoxSizing() == EBoxSizing::kBorderBox
+ ? box.BorderBoxRect().Size()
+ : box.ComputedCSSContentBoxRect().Size());
}
CSSValue* ComputedStyleUtils::RenderTextDecorationFlagsToCSSValue(
@@ -1627,18 +1642,30 @@ CSSFunctionValue* ValueForMatrixTransform(
return transform_value;
}
+FloatRect ComputedStyleUtils::ReferenceBoxForTransform(
+ const LayoutObject& layout_object,
+ UsePixelSnappedBox pixel_snap_box) {
+ if (layout_object.IsSVGChild())
+ return ComputeSVGTransformReferenceBox(layout_object);
+ if (layout_object.IsBox()) {
+ const auto& layout_box = ToLayoutBox(layout_object);
+ if (pixel_snap_box == kUsePixelSnappedBox)
+ return FloatRect(layout_box.PixelSnappedBorderBoxRect());
+ return FloatRect(layout_box.BorderBoxRect());
+ }
+ return FloatRect();
+}
+
CSSValue* ComputedStyleUtils::ComputedTransform(
const LayoutObject* layout_object,
const ComputedStyle& style) {
if (!layout_object || !style.HasTransform())
return CSSIdentifierValue::Create(CSSValueNone);
- IntRect box;
- if (layout_object->IsBox())
- box = PixelSnappedIntRect(ToLayoutBox(layout_object)->BorderBoxRect());
+ FloatRect reference_box = ReferenceBoxForTransform(*layout_object);
TransformationMatrix transform;
- style.ApplyTransform(transform, LayoutSize(box.Size()),
+ style.ApplyTransform(transform, reference_box,
ComputedStyle::kExcludeTransformOrigin,
ComputedStyle::kExcludeMotionPath,
ComputedStyle::kExcludeIndependentTransformProperties);
@@ -2111,17 +2138,15 @@ bool ComputedStyleUtils::WidthOrHeightShouldReturnUsedValue(
// The display property is 'none'.
if (!object)
return false;
+ // Non-root SVG objects return the resolved value except <image>,
+ // <rect> and <foreignObject> which return the used value.
+ if (object->IsSVGChild())
+ return IsSVGObjectWithWidthAndHeight(*object);
// According to
// http://www.w3.org/TR/CSS2/visudet.html#the-width-property and
// http://www.w3.org/TR/CSS2/visudet.html#the-height-property, the "width" or
// "height" property does not apply to non-atomic inline elements.
- if (!object->IsAtomicInlineLevel() && object->IsInline())
- return false;
- // Non-root SVG objects return the resolved value.
- // TODO(fs): Return the used value for <image>, <rect> and <foreignObject> (to
- // which 'width' or 'height' can be said to apply) too? We don't return the
- // used value for other geometric properties ('x', 'y' et.c.)
- return !object->IsSVGChild();
+ return object->IsAtomicInlineLevel() || !object->IsInline();
}
CSSValueList* ComputedStyleUtils::ValuesForShorthandProperty(
diff --git a/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.h
index b4133eeac32..c4dead787ab 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -112,7 +112,7 @@ class ComputedStyleUtils {
const LayoutObject*,
const ComputedStyle&);
static CSSValue* ValueForGridPosition(const GridPosition&);
- static LayoutRect SizingBox(const LayoutObject&);
+ static FloatSize UsedBoxSize(const LayoutObject&);
static CSSValue* RenderTextDecorationFlagsToCSSValue(TextDecoration);
static CSSValue* ValueForTextDecorationStyle(ETextDecorationStyle);
static CSSValue* ValueForTextDecorationSkipInk(ETextDecorationSkipInk);
@@ -132,6 +132,17 @@ class ComputedStyleUtils {
const ComputedStyle&);
static const CSSValue& ValueForBorderRadiusCorner(const LengthSize&,
const ComputedStyle&);
+ // TODO(fs): For some properties ('transform') we use the pixel snapped
+ // border-box as the reference box. In other cases ('transform-origin') we use
+ // the "unsnapped" border-box. Maybe use the same (the "unsnapped") in both
+ // cases?
+ enum UsePixelSnappedBox {
+ kDontUsePixelSnappedBox,
+ kUsePixelSnappedBox,
+ };
+ static FloatRect ReferenceBoxForTransform(
+ const LayoutObject&,
+ UsePixelSnappedBox = kUsePixelSnappedBox);
static CSSValue* ComputedTransform(const LayoutObject*, const ComputedStyle&);
static CSSValue* CreateTransitionPropertyValue(
const CSSTransitionData::TransitionProperty&);
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index b7c96bbf4ae..69c35eae760 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -42,6 +42,7 @@
#include "third_party/blink/renderer/core/svg/svg_parsing_error.h"
#include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
#include "third_party/blink/renderer/platform/animation/timing_function.h"
+#include "third_party/blink/renderer/platform/fonts/font_selection_types.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -1390,8 +1391,8 @@ CSSValue* ConsumeFontStyle(CSSParserTokenRange& range,
CSSIdentifierValue* oblique_identifier =
css_property_parser_helpers::ConsumeIdent<CSSValueOblique>(range);
- CSSPrimitiveValue* start_angle =
- css_property_parser_helpers::ConsumeAngle(range, nullptr, base::nullopt);
+ CSSPrimitiveValue* start_angle = css_property_parser_helpers::ConsumeAngle(
+ range, nullptr, base::nullopt, MinObliqueValue(), MaxObliqueValue());
if (!start_angle)
return oblique_identifier;
if (!IsAngleWithinLimits(start_angle))
@@ -1403,8 +1404,8 @@ CSSValue* ConsumeFontStyle(CSSParserTokenRange& range,
return CSSFontStyleRangeValue::Create(*oblique_identifier, *value_list);
}
- CSSPrimitiveValue* end_angle =
- css_property_parser_helpers::ConsumeAngle(range, nullptr, base::nullopt);
+ CSSPrimitiveValue* end_angle = css_property_parser_helpers::ConsumeAngle(
+ range, nullptr, base::nullopt, MinObliqueValue(), MaxObliqueValue());
if (!end_angle || !IsAngleWithinLimits(end_angle))
return nullptr;
@@ -2597,5 +2598,12 @@ CSSValue* ParsePaintStroke(CSSParserTokenRange& range,
return css_property_parser_helpers::ConsumeColor(range, context.Mode());
}
+css_property_parser_helpers::UnitlessQuirk UnitlessUnlessShorthand(
+ const CSSParserLocalContext& local_context) {
+ return local_context.CurrentShorthand() == CSSPropertyInvalid
+ ? css_property_parser_helpers::UnitlessQuirk::kAllow
+ : css_property_parser_helpers::UnitlessQuirk::kForbid;
+}
+
} // namespace css_parsing_utils
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index c7cbb4c5316..342e6547a33 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -237,6 +237,9 @@ CSSValue* ConsumeBorderWidth(CSSParserTokenRange&,
CSSValue* ParsePaintStroke(CSSParserTokenRange&, const CSSParserContext&);
CSSValue* ParseSpacing(CSSParserTokenRange&, const CSSParserContext&);
+css_property_parser_helpers::UnitlessQuirk UnitlessUnlessShorthand(
+ const CSSParserLocalContext&);
+
template <CSSValueID start, CSSValueID end>
CSSValue* ConsumePositionLonghand(CSSParserTokenRange& range,
CSSParserMode css_parser_mode) {
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc
index 11ba397918c..3748065020d 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/css/properties/css_property.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
@@ -16,8 +17,9 @@ const StylePropertyShorthand& CSSProperty::BorderDirections() {
static const CSSProperty* kProperties[4] = {
&GetCSSPropertyBorderTop(), &GetCSSPropertyBorderRight(),
&GetCSSPropertyBorderBottom(), &GetCSSPropertyBorderLeft()};
- DEFINE_STATIC_LOCAL(StylePropertyShorthand, border_directions,
- (CSSPropertyBorder, kProperties, arraysize(kProperties)));
+ DEFINE_STATIC_LOCAL(
+ StylePropertyShorthand, border_directions,
+ (CSSPropertyBorder, kProperties, base::size(kProperties)));
return border_directions;
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_outset_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_outset_custom.cc
index 7f0185f3c27..e0f12599988 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_outset_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_outset_custom.cc
@@ -30,12 +30,10 @@ const CSSValue* BorderImageOutset::CSSValueFromComputedStyleInternal(
const CSSValue* BorderImageOutset::InitialValue() const {
DEFINE_STATIC_LOCAL(
- Persistent<CSSValue>, zeroInteger,
- (CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kInteger)));
- DEFINE_STATIC_LOCAL(
Persistent<CSSQuadValue>, value,
- (CSSQuadValue::Create(zeroInteger, zeroInteger, zeroInteger, zeroInteger,
- CSSQuadValue::kSerializeAsQuad)));
+ (CSSQuadValue::Create(
+ CSSPrimitiveValue::Create(0, CSSPrimitiveValue::UnitType::kInteger),
+ CSSQuadValue::kSerializeAsQuad)));
return value;
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_slice_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_slice_custom.cc
index 62888d64f9e..83a8d7ab3f4 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_slice_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_slice_custom.cc
@@ -29,9 +29,14 @@ const CSSValue* BorderImageSlice::CSSValueFromComputedStyleInternal(
}
const CSSValue* BorderImageSlice::InitialValue() const {
- DEFINE_STATIC_LOCAL(Persistent<CSSValue>, value,
- (CSSPrimitiveValue::Create(
- 100, CSSPrimitiveValue::UnitType::kPercentage)));
+ DEFINE_STATIC_LOCAL(
+ Persistent<CSSBorderImageSliceValue>, value,
+ (CSSBorderImageSliceValue::Create(
+ CSSQuadValue::Create(
+ CSSPrimitiveValue::Create(
+ 100, CSSPrimitiveValue::UnitType::kPercentage),
+ CSSQuadValue::kSerializeAsQuad),
+ /* fill */ false)));
return value;
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_width_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_width_custom.cc
index 6b3bd3bd6a1..cbf66971fbe 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_width_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/border_image_width_custom.cc
@@ -30,12 +30,10 @@ const CSSValue* BorderImageWidth::CSSValueFromComputedStyleInternal(
const CSSValue* BorderImageWidth::InitialValue() const {
DEFINE_STATIC_LOCAL(
- Persistent<CSSValue>, oneInteger,
- (CSSPrimitiveValue::Create(1, CSSPrimitiveValue::UnitType::kInteger)));
- DEFINE_STATIC_LOCAL(
Persistent<CSSQuadValue>, value,
- (CSSQuadValue::Create(oneInteger, oneInteger, oneInteger, oneInteger,
- CSSQuadValue::kSerializeAsQuad)));
+ (CSSQuadValue::Create(
+ CSSPrimitiveValue::Create(1, CSSPrimitiveValue::UnitType::kInteger),
+ CSSQuadValue::kSerializeAsQuad)));
return value;
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc
index 7f22bfd645a..bed946ff1fe 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc
@@ -17,12 +17,13 @@ class CSSParserLocalContext;
namespace css_longhand {
-const CSSValue* Bottom::ParseSingleValue(CSSParserTokenRange& range,
- const CSSParserContext& context,
- const CSSParserLocalContext&) const {
+const CSSValue* Bottom::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
return css_parsing_utils::ConsumeMarginOrOffset(
range, context.Mode(),
- css_property_parser_helpers::UnitlessQuirk::kAllow);
+ css_parsing_utils::UnitlessUnlessShorthand(local_context));
}
bool Bottom::IsLayoutDependent(const ComputedStyle* style,
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
index f139d170b76..d68af9edff8 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
@@ -30,6 +30,10 @@ const AtomicString& CustomProperty::GetPropertyNameAtomicString() const {
return name_;
}
+CSSPropertyName CustomProperty::GetCSSPropertyName() const {
+ return CSSPropertyName(name_);
+}
+
void CustomProperty::ApplyInitial(StyleResolverState& state) const {
state.Style()->RemoveVariable(name_, IsInherited());
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h
index 57a2f0fb393..0cbabc05847 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h
@@ -30,6 +30,7 @@ class CORE_EXPORT CustomProperty : public Variable {
bool IsInherited() const override;
const AtomicString& GetPropertyNameAtomicString() const override;
+ CSSPropertyName GetCSSPropertyName() const override;
void ApplyInitial(StyleResolverState&) const override;
void ApplyInherit(StyleResolverState&) const override;
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
index 9224db4b406..af4ec4caa8e 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
@@ -31,8 +31,8 @@ class CustomPropertyTest : public PageTestBase {
const CSSValue* GetComputedValue(const CustomProperty& property) {
Element* node = GetDocument().getElementById("target");
return property.CSSValueFromComputedStyle(node->ComputedStyleRef(),
- nullptr /* layout_object*/, node,
- false /* allow_visisted_style */);
+ nullptr /* layout_object */, node,
+ false /* allow_visited_style */);
}
const CSSValue* ParseValue(const Longhand& property,
@@ -194,4 +194,9 @@ TEST_F(CustomPropertyTest, ParseSingleValueValidatedUntyped) {
EXPECT_FALSE(value2);
}
+TEST_F(CustomPropertyTest, GetCSSPropertyName) {
+ CustomProperty property("--x", GetDocument());
+ EXPECT_EQ(CSSPropertyName("--x"), property.GetCSSPropertyName());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/height_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/height_custom.cc
index 4c843c38f23..09104b72ed9 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/height_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/height_custom.cc
@@ -22,7 +22,7 @@ const CSSValue* Height::ParseSingleValue(CSSParserTokenRange& range,
bool Height::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsBox();
+ return layout_object && (layout_object->IsBox() || layout_object->IsSVG());
}
const CSSValue* Height::CSSValueFromComputedStyleInternal(
@@ -33,7 +33,7 @@ const CSSValue* Height::CSSValueFromComputedStyleInternal(
bool allow_visited_style) const {
if (ComputedStyleUtils::WidthOrHeightShouldReturnUsedValue(layout_object)) {
return ZoomAdjustedPixelValue(
- ComputedStyleUtils::SizingBox(*layout_object).Height(), style);
+ ComputedStyleUtils::UsedBoxSize(*layout_object).Height(), style);
}
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Height(),
style);
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc
index e9f4074e5e4..d986478cf27 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc
@@ -17,12 +17,13 @@ class CSSParserLocalContext;
namespace css_longhand {
-const CSSValue* Left::ParseSingleValue(CSSParserTokenRange& range,
- const CSSParserContext& context,
- const CSSParserLocalContext&) const {
+const CSSValue* Left::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
return css_parsing_utils::ConsumeMarginOrOffset(
range, context.Mode(),
- css_property_parser_helpers::UnitlessQuirk::kAllow);
+ css_parsing_utils::UnitlessUnlessShorthand(local_context));
}
bool Left::IsLayoutDependent(const ComputedStyle* style,
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc
index 3ea427901af..55e234c0428 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc
@@ -17,12 +17,13 @@ class CSSParserLocalContext;
namespace css_longhand {
-const CSSValue* Right::ParseSingleValue(CSSParserTokenRange& range,
- const CSSParserContext& context,
- const CSSParserLocalContext&) const {
+const CSSValue* Right::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
return css_parsing_utils::ConsumeMarginOrOffset(
range, context.Mode(),
- css_property_parser_helpers::UnitlessQuirk::kAllow);
+ css_parsing_utils::UnitlessUnlessShorthand(local_context));
}
bool Right::IsLayoutDependent(const ComputedStyle* style,
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc
index 34328499657..2d56fccd642 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc
@@ -17,12 +17,13 @@ class CSSParserLocalContext;
namespace css_longhand {
-const CSSValue* Top::ParseSingleValue(CSSParserTokenRange& range,
- const CSSParserContext& context,
- const CSSParserLocalContext&) const {
+const CSSValue* Top::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
return css_parsing_utils::ConsumeMarginOrOffset(
range, context.Mode(),
- css_property_parser_helpers::UnitlessQuirk::kAllow);
+ css_parsing_utils::UnitlessUnlessShorthand(local_context));
}
bool Top::IsLayoutDependent(const ComputedStyle* style,
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_custom.cc
index e419eb86f4c..a84008a1470 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_custom.cc
@@ -25,7 +25,8 @@ const CSSValue* Transform::ParseSingleValue(
bool Transform::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsBox();
+ return layout_object &&
+ (layout_object->IsBox() || layout_object->IsSVGChild());
}
const CSSValue* Transform::CSSValueFromComputedStyleInternal(
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_origin_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_origin_custom.cc
index e5fd8d94be9..1cdce977413 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_origin_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/transform_origin_custom.cc
@@ -39,7 +39,8 @@ const CSSValue* TransformOrigin::ParseSingleValue(
bool TransformOrigin::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsBox();
+ return layout_object &&
+ (layout_object->IsBox() || layout_object->IsSVGChild());
}
const CSSValue* TransformOrigin::CSSValueFromComputedStyleInternal(
@@ -50,24 +51,21 @@ const CSSValue* TransformOrigin::CSSValueFromComputedStyleInternal(
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
if (layout_object) {
- LayoutRect box;
- if (layout_object->IsBox())
- box = ToLayoutBox(layout_object)->BorderBoxRect();
-
- list->Append(*ZoomAdjustedPixelValue(
- MinimumValueForLength(style.TransformOriginX(), box.Width()), style));
- list->Append(*ZoomAdjustedPixelValue(
- MinimumValueForLength(style.TransformOriginY(), box.Height()), style));
- if (style.TransformOriginZ() != 0)
- list->Append(*ZoomAdjustedPixelValue(style.TransformOriginZ(), style));
+ FloatRect reference_box = ComputedStyleUtils::ReferenceBoxForTransform(
+ *layout_object, ComputedStyleUtils::kDontUsePixelSnappedBox);
+ FloatSize resolved_origin(
+ FloatValueForLength(style.TransformOriginX(), reference_box.Width()),
+ FloatValueForLength(style.TransformOriginY(), reference_box.Height()));
+ list->Append(*ZoomAdjustedPixelValue(resolved_origin.Width(), style));
+ list->Append(*ZoomAdjustedPixelValue(resolved_origin.Height(), style));
} else {
list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
style.TransformOriginX(), style));
list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
style.TransformOriginY(), style));
- if (style.TransformOriginZ() != 0)
- list->Append(*ZoomAdjustedPixelValue(style.TransformOriginZ(), style));
}
+ if (style.TransformOriginZ() != 0)
+ list->Append(*ZoomAdjustedPixelValue(style.TransformOriginZ(), style));
return list;
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/variable.h b/chromium/third_party/blink/renderer/core/css/properties/longhands/variable.h
index cb0137e5c2b..f1eb99390db 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/variable.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/variable.h
@@ -22,6 +22,10 @@ class CORE_EXPORT Variable : public Longhand {
bool IsInherited() const override { return true; }
bool IsAffectedByAll() const override { return false; }
CSSPropertyID PropertyID() const override { return CSSPropertyVariable; }
+ CSSPropertyName GetCSSPropertyName() const override {
+ NOTREACHED();
+ return CSSPropertyName("");
+ }
const char* GetPropertyName() const override { return "variable"; }
const WTF::AtomicString& GetPropertyNameAtomicString() const override {
DEFINE_STATIC_LOCAL(const AtomicString, name, ("variable"));
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/width_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/width_custom.cc
index e48fb203761..8414fa9c0c8 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/width_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/width_custom.cc
@@ -22,7 +22,7 @@ const CSSValue* Width::ParseSingleValue(CSSParserTokenRange& range,
bool Width::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsBox();
+ return layout_object && (layout_object->IsBox() || layout_object->IsSVG());
}
const CSSValue* Width::CSSValueFromComputedStyleInternal(
@@ -33,7 +33,7 @@ const CSSValue* Width::CSSValueFromComputedStyleInternal(
bool allow_visited_style) const {
if (ComputedStyleUtils::WidthOrHeightShouldReturnUsedValue(layout_object)) {
return ZoomAdjustedPixelValue(
- ComputedStyleUtils::SizingBox(*layout_object).Width(), style);
+ ComputedStyleUtils::UsedBoxSize(*layout_object).Width(), style);
}
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Width(),
style);
diff --git a/chromium/third_party/blink/renderer/core/css/properties/shorthands/animation_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/shorthands/animation_custom.cc
index eb60bd55abb..4f27aa440cf 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/shorthands/animation_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/shorthands/animation_custom.cc
@@ -92,7 +92,6 @@ const CSSValue* Animation::CSSValueFromComputedStyleInternal(
CSSValueList* animations_list = CSSValueList::CreateCommaSeparated();
for (wtf_size_t i = 0; i < animation_data->NameList().size(); ++i) {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
- list->Append(*CSSCustomIdentValue::Create(animation_data->NameList()[i]));
list->Append(*CSSPrimitiveValue::Create(
CSSTimingData::GetRepeated(animation_data->DurationList(), i),
CSSPrimitiveValue::UnitType::kSeconds));
@@ -110,6 +109,7 @@ const CSSValue* Animation::CSSValueFromComputedStyleInternal(
CSSTimingData::GetRepeated(animation_data->FillModeList(), i)));
list->Append(*ComputedStyleUtils::ValueForAnimationPlayState(
CSSTimingData::GetRepeated(animation_data->PlayStateList(), i)));
+ list->Append(*CSSCustomIdentValue::Create(animation_data->NameList()[i]));
animations_list->Append(*list);
}
return animations_list;
diff --git a/chromium/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc
index 9ac731d078b..60909281584 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/css/properties/shorthands/border.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/css_initial_value.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
@@ -52,7 +53,7 @@ const CSSValue* Border::CSSValueFromComputedStyleInternal(
static const CSSProperty* kProperties[3] = {&GetCSSPropertyBorderRight(),
&GetCSSPropertyBorderBottom(),
&GetCSSPropertyBorderLeft()};
- for (size_t i = 0; i < arraysize(kProperties); ++i) {
+ for (size_t i = 0; i < base::size(kProperties); ++i) {
const CSSValue* value_for_side = kProperties[i]->CSSValueFromComputedStyle(
style, layout_object, styled_node, allow_visited_style);
if (!DataEquivalent(value, value_for_side)) {
diff --git a/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc b/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc
index 2f758c5d349..79c84eb2348 100644
--- a/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc
+++ b/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc
@@ -83,7 +83,7 @@ RemoteFontFaceSource::RemoteFontFaceSource(CSSFontFace* css_font_face,
FontDisplay display)
: face_(css_font_face),
font_selector_(font_selector),
- display_(display),
+ display_(GetFontDisplayWithFeaturePolicyCheck(display, font_selector)),
phase_(kNoLimitExceeded),
is_intervention_triggered_(ShouldTriggerWebFontsIntervention()) {
DCHECK(face_);
@@ -168,7 +168,7 @@ void RemoteFontFaceSource::SetDisplay(FontDisplay display) {
// using the loaded font.
if (IsLoaded())
return;
- display_ = display;
+ display_ = GetFontDisplayWithFeaturePolicyCheck(display, font_selector_);
UpdatePeriod();
}
@@ -188,6 +188,18 @@ void RemoteFontFaceSource::UpdatePeriod() {
period_ = new_period;
}
+FontDisplay RemoteFontFaceSource::GetFontDisplayWithFeaturePolicyCheck(
+ FontDisplay display,
+ const FontSelector* font_selector) const {
+ ExecutionContext* context = font_selector->GetExecutionContext();
+ if (display != kFontDisplayFallback && context && context->IsDocument() &&
+ !To<Document>(context)->IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kFontDisplay)) {
+ return kFontDisplayOptional;
+ }
+ return display;
+}
+
bool RemoteFontFaceSource::ShouldTriggerWebFontsIntervention() {
const auto* document =
DynamicTo<Document>(font_selector_->GetExecutionContext());
diff --git a/chromium/third_party/blink/renderer/core/css/remote_font_face_source.h b/chromium/third_party/blink/renderer/core/css/remote_font_face_source.h
index f3c93bcdf14..25118f8fb2f 100644
--- a/chromium/third_party/blink/renderer/core/css/remote_font_face_source.h
+++ b/chromium/third_party/blink/renderer/core/css/remote_font_face_source.h
@@ -112,6 +112,8 @@ class RemoteFontFaceSource final : public CSSFontFaceSource,
void UpdatePeriod();
bool ShouldTriggerWebFontsIntervention();
bool IsLowPriorityLoadingAllowedForRemoteFont() const override;
+ FontDisplay GetFontDisplayWithFeaturePolicyCheck(FontDisplay,
+ const FontSelector*) const;
// Our owning font face.
Member<CSSFontFace> face_;
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h b/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
index 9bcf1581af9..49bb15d112a 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
@@ -24,7 +24,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_ELEMENT_RESOLVE_CONTEXT_H_
#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc b/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
index 8cf83d116c4..1ad8fc15443 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
@@ -108,8 +108,8 @@ SVGResource* ElementStyleResources::GetSVGResourceFromValue(
if (value.IsLocal(element_->GetDocument())) {
SVGTreeScopeResources& tree_scope_resources =
tree_scope.EnsureSVGTreeScopedResources();
- AtomicString decoded_fragment(
- DecodeURLEscapeSequences(value.FragmentIdentifier()));
+ AtomicString decoded_fragment(DecodeURLEscapeSequences(
+ value.FragmentIdentifier(), DecodeURLMode::kUTF8OrIsomorphic));
return tree_scope_resources.ResourceForId(decoded_fragment);
}
if (allow_external == kAllowExternalResource)
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
index d314ef36016..09cba01c56e 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
@@ -88,8 +88,10 @@ void MatchedPropertiesCache::Add(const ComputedStyle& style,
const MatchedPropertiesVector& properties) {
DCHECK(hash);
Cache::AddResult add_result = cache_.insert(hash, nullptr);
- if (add_result.is_new_entry || !add_result.stored_value->value)
- add_result.stored_value->value = new CachedMatchedProperties;
+ if (add_result.is_new_entry || !add_result.stored_value->value) {
+ add_result.stored_value->value =
+ MakeGarbageCollected<CachedMatchedProperties>();
+ }
CachedMatchedProperties* cache_item = add_result.stored_value->value.Get();
if (!add_result.is_new_entry)
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc b/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
index 9f4f7482a19..1ecd8713066 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
@@ -117,8 +117,7 @@ void ScopedStyleResolver::CollectFeaturesTo(
device_dependent_media_query_results_);
for (auto sheet : author_style_sheets_) {
- if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled())
- DCHECK(sheet->ownerNode());
+ DCHECK(sheet->ownerNode() || sheet->IsConstructed());
StyleSheetContents* contents = sheet->Contents();
if (contents->HasOneClient() ||
visited_shared_style_sheet_contents.insert(contents).is_new_entry)
@@ -222,8 +221,7 @@ void ScopedStyleResolver::CollectMatchingAuthorRules(
ShadowV0CascadeOrder cascade_order) {
wtf_size_t sheet_index = 0;
for (auto sheet : author_style_sheets_) {
- if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled())
- DCHECK(sheet->ownerNode());
+ DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++);
collector.CollectMatchingRules(match_request, cascade_order);
@@ -235,8 +233,7 @@ void ScopedStyleResolver::CollectMatchingShadowHostRules(
ShadowV0CascadeOrder cascade_order) {
wtf_size_t sheet_index = 0;
for (auto sheet : author_style_sheets_) {
- if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled())
- DCHECK(sheet->ownerNode());
+ DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++);
collector.CollectMatchingShadowHostRules(match_request, cascade_order);
@@ -277,8 +274,7 @@ void ScopedStyleResolver::CollectMatchingPartPseudoRules(
return;
wtf_size_t sheet_index = 0;
for (auto sheet : author_style_sheets_) {
- if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled())
- DCHECK(sheet->ownerNode());
+ DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++);
collector.CollectMatchingPartPseudoRules(match_request, part_names,
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index b492c41928e..036ce676f14 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -321,11 +321,24 @@ static void MatchElementScopeRules(const Element& element,
collector.FinishAddingAuthorRulesForTreeScope();
}
+void StyleResolver::MatchPseudoPartRulesForUAHost(
+ const Element& element,
+ ElementRuleCollector& collector) {
+ if (element.ShadowPseudoId() != "-webkit-input-placeholder")
+ return;
+
+ // We allow ::placeholder pseudo element after ::part(). See
+ // MatchSlottedRulesForUAHost for a more detailed explanation.
+ DCHECK(element.OwnerShadowHost());
+ MatchPseudoPartRules(*element.OwnerShadowHost(), collector);
+}
+
void StyleResolver::MatchPseudoPartRules(const Element& element,
ElementRuleCollector& collector) {
if (!RuntimeEnabledFeatures::CSSPartPseudoElementEnabled())
return;
+ MatchPseudoPartRulesForUAHost(element, collector);
DOMTokenList* part = element.GetPart();
if (!part)
return;
@@ -1036,10 +1049,8 @@ scoped_refptr<ComputedStyle> StyleResolver::InitialStyleForElement(
scoped_refptr<ComputedStyle> StyleResolver::StyleForText(Text* text_node) {
DCHECK(text_node);
-
Node* parent_node = LayoutTreeBuilderTraversal::Parent(*text_node);
- if (!parent_node || !parent_node->GetComputedStyle())
- return InitialStyleForElement(GetDocument());
+ DCHECK(parent_node);
return parent_node->MutableComputedStyle();
}
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h
index fe4ae0d29fc..4c64d6e9a1a 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -157,6 +157,7 @@ class CORE_EXPORT StyleResolver final
// This matches `::part` selectors. It looks in ancestor scopes as far as
// part mapping requires.
void MatchPseudoPartRules(const Element&, ElementRuleCollector&);
+ void MatchPseudoPartRulesForUAHost(const Element&, ElementRuleCollector&);
void MatchScopedRulesV0(const Element&,
ElementRuleCollector&,
ScopedStyleResolver*);
diff --git a/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc b/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc
index 91ad65c8d0c..4db33d502db 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc
@@ -216,9 +216,31 @@ bool RequiresSubtreeInvalidation(const CSSSelector& selector) {
}
}
+// Creates a copy of an InvalidationSet by combining an empty InvalidationSet
+// (of the same type) with the specified InvalidationSet.
+//
+// See also InvalidationSet::Combine.
+scoped_refptr<InvalidationSet> CopyInvalidationSet(
+ const InvalidationSet& invalidation_set) {
+ if (invalidation_set.GetType() == kInvalidateSiblings) {
+ scoped_refptr<InvalidationSet> copy =
+ SiblingInvalidationSet::Create(nullptr);
+ copy->Combine(invalidation_set);
+ return copy;
+ }
+ if (invalidation_set.IsSelfInvalidationSet()) {
+ scoped_refptr<InvalidationSet> copy = DescendantInvalidationSet::Create();
+ copy->SetInvalidatesSelf();
+ return copy;
+ }
+ scoped_refptr<InvalidationSet> copy = DescendantInvalidationSet::Create();
+ copy->Combine(invalidation_set);
+ return copy;
+}
+
} // anonymous namespace
-InvalidationSet& RuleFeatureSet::StoredInvalidationSet(
+InvalidationSet& RuleFeatureSet::EnsureMutableInvalidationSet(
scoped_refptr<InvalidationSet>& invalidation_set,
InvalidationType type,
PositionType position) {
@@ -233,8 +255,8 @@ InvalidationSet& RuleFeatureSet::StoredInvalidationSet(
// the SelfInvalidationSet() when we create a SiblingInvalidationSet. We may
// be able to let SiblingInvalidationSets reference the singleton set for
// descendants as well. TODO(futhark@chromium.org)
- invalidation_set = DescendantInvalidationSet::Create();
- invalidation_set->SetInvalidatesSelf();
+ invalidation_set = CopyInvalidationSet(*invalidation_set);
+ DCHECK(invalidation_set->HasOneRef());
}
if (!invalidation_set) {
if (type == kInvalidateDescendants) {
@@ -247,6 +269,12 @@ InvalidationSet& RuleFeatureSet::StoredInvalidationSet(
}
return *invalidation_set;
}
+ // If the currently stored invalidation_set is shared with other
+ // RuleFeatureSets (for example), we must copy it before modifying it.
+ if (!invalidation_set->HasOneRef()) {
+ invalidation_set = CopyInvalidationSet(*invalidation_set);
+ DCHECK(invalidation_set->HasOneRef());
+ }
if (invalidation_set->GetType() == type)
return *invalidation_set;
@@ -259,27 +287,57 @@ InvalidationSet& RuleFeatureSet::StoredInvalidationSet(
return *invalidation_set;
}
-InvalidationSet& RuleFeatureSet::EnsureInvalidationSet(
- HashMap<AtomicString, scoped_refptr<InvalidationSet>>& map,
- const AtomicString& key,
- InvalidationType type,
- PositionType position) {
+InvalidationSet& RuleFeatureSet::EnsureInvalidationSet(InvalidationSetMap& map,
+ const AtomicString& key,
+ InvalidationType type,
+ PositionType position) {
scoped_refptr<InvalidationSet>& invalidation_set =
map.insert(key, nullptr).stored_value->value;
- return StoredInvalidationSet(invalidation_set, type, position);
+ return EnsureMutableInvalidationSet(invalidation_set, type, position);
}
InvalidationSet& RuleFeatureSet::EnsureInvalidationSet(
- HashMap<CSSSelector::PseudoType,
- scoped_refptr<InvalidationSet>,
- WTF::IntHash<unsigned>,
- WTF::UnsignedWithZeroKeyHashTraits<unsigned>>& map,
+ PseudoTypeInvalidationSetMap& map,
CSSSelector::PseudoType key,
InvalidationType type,
PositionType position) {
scoped_refptr<InvalidationSet>& invalidation_set =
map.insert(key, nullptr).stored_value->value;
- return StoredInvalidationSet(invalidation_set, type, position);
+ return EnsureMutableInvalidationSet(invalidation_set, type, position);
+}
+
+void RuleFeatureSet::AddInvalidationSet(
+ InvalidationSetMap& map,
+ const AtomicString& key,
+ scoped_refptr<InvalidationSet> invalidation_set) {
+ DCHECK(invalidation_set);
+ scoped_refptr<InvalidationSet>& slot =
+ map.insert(key, nullptr).stored_value->value;
+ if (!slot) {
+ slot = invalidation_set;
+ } else {
+ EnsureInvalidationSet(
+ map, key, invalidation_set->GetType(),
+ invalidation_set->IsSelfInvalidationSet() ? kSubject : kAncestor)
+ .Combine(*invalidation_set);
+ }
+}
+
+void RuleFeatureSet::AddInvalidationSet(
+ PseudoTypeInvalidationSetMap& map,
+ CSSSelector::PseudoType key,
+ scoped_refptr<InvalidationSet> invalidation_set) {
+ DCHECK(invalidation_set);
+ scoped_refptr<InvalidationSet>& slot =
+ map.insert(key, nullptr).stored_value->value;
+ if (!slot) {
+ slot = invalidation_set;
+ } else {
+ EnsureInvalidationSet(
+ map, key, invalidation_set->GetType(),
+ invalidation_set->IsSelfInvalidationSet() ? kSubject : kAncestor)
+ .Combine(*invalidation_set);
+ }
}
void ExtractInvalidationSets(InvalidationSet* invalidation_set,
@@ -395,19 +453,19 @@ void RuleFeatureSet::ExtractInvalidationSetFeaturesFromSimpleSelector(
InvalidationSetFeatures& features) {
if (selector.Match() == CSSSelector::kTag &&
selector.TagQName().LocalName() != CSSSelector::UniversalSelectorAtom()) {
- features.tag_names.push_back(selector.TagQName().LocalName());
+ features.NarrowToTag(selector.TagQName().LocalName());
return;
}
if (selector.Match() == CSSSelector::kId) {
- features.ids.push_back(selector.Value());
+ features.NarrowToId(selector.Value());
return;
}
if (selector.Match() == CSSSelector::kClass) {
- features.classes.push_back(selector.Value());
+ features.NarrowToClass(selector.Value());
return;
}
if (selector.IsAttributeSelector()) {
- features.attributes.push_back(selector.Attribute().LocalName());
+ features.NarrowToAttribute(selector.Attribute().LocalName());
return;
}
switch (selector.GetPseudoType()) {
@@ -600,7 +658,7 @@ RuleFeatureSet::ExtractInvalidationSetFeaturesFromSelectorList(
// Don't add any features if one of the sub-selectors of does not contain
// any invalidation set features. E.g. :-webkit-any(*, span).
if (all_sub_selectors_have_features)
- features.Add(any_features);
+ features.NarrowToFeatures(any_features);
return kNormalInvalidation;
}
@@ -917,30 +975,15 @@ void RuleFeatureSet::Add(const RuleFeatureSet& other) {
CHECK(is_alive_);
CHECK(other.is_alive_);
CHECK_NE(&other, this);
- for (const auto& entry : other.class_invalidation_sets_) {
- EnsureInvalidationSet(
- class_invalidation_sets_, entry.key, entry.value->GetType(),
- entry.value->IsSelfInvalidationSet() ? kSubject : kAncestor)
- .Combine(*entry.value);
- }
- for (const auto& entry : other.attribute_invalidation_sets_) {
- EnsureInvalidationSet(
- attribute_invalidation_sets_, entry.key, entry.value->GetType(),
- entry.value->IsSelfInvalidationSet() ? kSubject : kAncestor)
- .Combine(*entry.value);
- }
- for (const auto& entry : other.id_invalidation_sets_) {
- EnsureInvalidationSet(
- id_invalidation_sets_, entry.key, entry.value->GetType(),
- entry.value->IsSelfInvalidationSet() ? kSubject : kAncestor)
- .Combine(*entry.value);
- }
+ for (const auto& entry : other.class_invalidation_sets_)
+ AddInvalidationSet(class_invalidation_sets_, entry.key, entry.value);
+ for (const auto& entry : other.attribute_invalidation_sets_)
+ AddInvalidationSet(attribute_invalidation_sets_, entry.key, entry.value);
+ for (const auto& entry : other.id_invalidation_sets_)
+ AddInvalidationSet(id_invalidation_sets_, entry.key, entry.value);
for (const auto& entry : other.pseudo_invalidation_sets_) {
- EnsureInvalidationSet(
- pseudo_invalidation_sets_,
- static_cast<CSSSelector::PseudoType>(entry.key), entry.value->GetType(),
- entry.value->IsSelfInvalidationSet() ? kSubject : kAncestor)
- .Combine(*entry.value);
+ auto key = static_cast<CSSSelector::PseudoType>(entry.key);
+ AddInvalidationSet(pseudo_invalidation_sets_, key, entry.value);
}
if (other.universal_sibling_invalidation_set_) {
EnsureUniversalSiblingInvalidationSet().Combine(
@@ -1226,6 +1269,16 @@ void RuleFeatureSet::InvalidationSetFeatures::Add(
has_nth_pseudo |= other.has_nth_pseudo;
}
+void RuleFeatureSet::InvalidationSetFeatures::NarrowToFeatures(
+ const InvalidationSetFeatures& other) {
+ unsigned size = Size();
+ unsigned other_size = other.Size();
+ if (size == 0 || (1 <= other_size && other_size < size)) {
+ ClearFeatures();
+ Add(other);
+ }
+}
+
bool RuleFeatureSet::InvalidationSetFeatures::HasFeatures() const {
return !classes.IsEmpty() || !attributes.IsEmpty() || !ids.IsEmpty() ||
!tag_names.IsEmpty() || invalidation_flags.InvalidateCustomPseudo() ||
diff --git a/chromium/third_party/blink/renderer/core/css/rule_feature_set.h b/chromium/third_party/blink/renderer/core/css/rule_feature_set.h
index b81bfba81b2..aca0cb67426 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_feature_set.h
+++ b/chromium/third_party/blink/renderer/core/css/rule_feature_set.h
@@ -202,6 +202,42 @@ class CORE_EXPORT RuleFeatureSet {
bool HasFeatures() const;
bool HasIdClassOrAttribute() const;
+ void NarrowToClass(const AtomicString& class_name) {
+ if (Size() == 1 && (!ids.IsEmpty() || !classes.IsEmpty()))
+ return;
+ ClearFeatures();
+ classes.push_back(class_name);
+ }
+ void NarrowToAttribute(const AtomicString& attribute) {
+ if (Size() == 1 &&
+ (!ids.IsEmpty() || !classes.IsEmpty() || !attributes.IsEmpty()))
+ return;
+ ClearFeatures();
+ attributes.push_back(attribute);
+ }
+ void NarrowToId(const AtomicString& id) {
+ if (Size() == 1 && !ids.IsEmpty())
+ return;
+ ClearFeatures();
+ ids.push_back(id);
+ }
+ void NarrowToTag(const AtomicString& tag_name) {
+ if (Size() == 1)
+ return;
+ ClearFeatures();
+ tag_names.push_back(tag_name);
+ }
+ void NarrowToFeatures(const InvalidationSetFeatures&);
+ void ClearFeatures() {
+ classes.clear();
+ attributes.clear();
+ ids.clear();
+ tag_names.clear();
+ }
+ unsigned Size() const {
+ return classes.size() + attributes.size() + ids.size() + tag_names.size();
+ }
+
Vector<AtomicString> classes;
Vector<AtomicString> attributes;
Vector<AtomicString> ids;
@@ -264,23 +300,34 @@ class CORE_EXPORT RuleFeatureSet {
void UpdateRuleSetInvalidation(const InvalidationSetFeatures&);
- static InvalidationSet& StoredInvalidationSet(scoped_refptr<InvalidationSet>&,
- InvalidationType,
- PositionType);
- static InvalidationSet& EnsureInvalidationSet(
- HashMap<AtomicString, scoped_refptr<InvalidationSet>>&,
- const AtomicString& key,
- InvalidationType,
- PositionType);
- static InvalidationSet& EnsureInvalidationSet(
- HashMap<CSSSelector::PseudoType,
- scoped_refptr<InvalidationSet>,
- WTF::IntHash<unsigned>,
- WTF::UnsignedWithZeroKeyHashTraits<unsigned>>&,
- CSSSelector::PseudoType key,
+ static InvalidationSet& EnsureMutableInvalidationSet(
+ scoped_refptr<InvalidationSet>&,
InvalidationType,
PositionType);
+ InvalidationSet& EnsureInvalidationSet(InvalidationSetMap&,
+ const AtomicString& key,
+ InvalidationType,
+ PositionType);
+ InvalidationSet& EnsureInvalidationSet(PseudoTypeInvalidationSetMap&,
+ CSSSelector::PseudoType key,
+ InvalidationType,
+ PositionType);
+
+ // Adds an InvalidationSet to this RuleFeatureSet.
+ //
+ // A copy-on-write mechanism is used: if we don't already have an invalidation
+ // set for |key|, we simply retain the incoming invalidation set without
+ // copying any data. If another AddInvalidationSet call takes place with the
+ // same key, we copy the existing InvalidationSet (if necessary) before
+ // combining it with the incoming InvalidationSet.
+ void AddInvalidationSet(InvalidationSetMap&,
+ const AtomicString& key,
+ scoped_refptr<InvalidationSet>);
+ void AddInvalidationSet(PseudoTypeInvalidationSetMap&,
+ CSSSelector::PseudoType key,
+ scoped_refptr<InvalidationSet>);
+
FeatureMetadata metadata_;
InvalidationSetMap class_invalidation_sets_;
InvalidationSetMap attribute_invalidation_sets_;
diff --git a/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc b/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc
index b70ba8a458f..6890475013a 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc
@@ -110,23 +110,35 @@ class RuleFeatureSetTest : public testing::Test {
rule_feature_set_.CollectNthInvalidationSet(invalidation_lists);
}
- const HashSet<AtomicString>& ClassSet(
- const InvalidationSet& invalidation_set) {
- return invalidation_set.ClassSetForTesting();
+ void AddTo(RuleFeatureSet& rule_feature_set) {
+ rule_feature_set.Add(rule_feature_set_);
}
- const HashSet<AtomicString>& IdSet(const InvalidationSet& invalidation_set) {
- return invalidation_set.IdSetForTesting();
+ using BackingType = InvalidationSet::BackingType;
+
+ template <BackingType type>
+ HashSet<AtomicString> ToHashSet(
+ typename InvalidationSet::Backing<type>::Range range) {
+ HashSet<AtomicString> hash_set;
+ for (auto str : range)
+ hash_set.insert(str);
+ return hash_set;
+ }
+
+ HashSet<AtomicString> ClassSet(const InvalidationSet& invalidation_set) {
+ return ToHashSet<BackingType::kClasses>(invalidation_set.Classes());
}
- const HashSet<AtomicString>& TagNameSet(
- const InvalidationSet& invalidation_set) {
- return invalidation_set.TagNameSetForTesting();
+ HashSet<AtomicString> IdSet(const InvalidationSet& invalidation_set) {
+ return ToHashSet<BackingType::kIds>(invalidation_set.Ids());
}
- const HashSet<AtomicString>& AttributeSet(
- const InvalidationSet& invalidation_set) {
- return invalidation_set.AttributeSetForTesting();
+ HashSet<AtomicString> TagNameSet(const InvalidationSet& invalidation_set) {
+ return ToHashSet<BackingType::kTagNames>(invalidation_set.TagNames());
+ }
+
+ HashSet<AtomicString> AttributeSet(const InvalidationSet& invalidation_set) {
+ return ToHashSet<BackingType::kAttributes>(invalidation_set.Attributes());
}
void ExpectNoInvalidation(InvalidationSetVector& invalidation_sets) {
@@ -290,6 +302,69 @@ class RuleFeatureSetTest : public testing::Test {
EXPECT_TRUE(invalidation_sets[0]->InvalidatesParts());
}
+ enum class RefCount { kOne, kMany };
+
+ template <typename MapType, typename KeyType>
+ void ExpectRefCountForInvalidationSet(const MapType& map,
+ const KeyType& key,
+ RefCount ref_count) {
+ auto it = map.find(key);
+ ASSERT_NE(map.end(), it);
+
+ if (ref_count == RefCount::kOne) {
+ EXPECT_TRUE(it->value->HasOneRef());
+
+ // For SiblingInvalidationSets, we also require that the inner
+ // InvalidationSets either don't exist, or have a refcount of 1.
+ if (it->value->GetType() == kInvalidateSiblings) {
+ const SiblingInvalidationSet& sibling_invalidation_set =
+ ToSiblingInvalidationSet(*it->value);
+ bool sibling_descendants_has_one_ref =
+ !sibling_invalidation_set.SiblingDescendants() ||
+ sibling_invalidation_set.SiblingDescendants()->HasOneRef();
+ bool descendants_has_one_ref =
+ !sibling_invalidation_set.Descendants() ||
+ sibling_invalidation_set.Descendants()->HasOneRef();
+ EXPECT_TRUE(sibling_descendants_has_one_ref);
+ EXPECT_TRUE(descendants_has_one_ref);
+ }
+ } else {
+ EXPECT_FALSE(it->value->HasOneRef());
+ }
+ }
+
+ void ExpectRefCountForClassInvalidationSet(
+ const RuleFeatureSet& rule_feature_set,
+ const AtomicString& class_name,
+ RefCount ref_count) {
+ ExpectRefCountForInvalidationSet(rule_feature_set.class_invalidation_sets_,
+ class_name, ref_count);
+ }
+
+ void ExpectRefCountForAttributeInvalidationSet(
+ const RuleFeatureSet& rule_feature_set,
+ const AtomicString& attribute,
+ RefCount ref_count) {
+ ExpectRefCountForInvalidationSet(
+ rule_feature_set.attribute_invalidation_sets_, attribute, ref_count);
+ }
+
+ void ExpectRefCountForIdInvalidationSet(
+ const RuleFeatureSet& rule_feature_set,
+ const AtomicString& id,
+ RefCount ref_count) {
+ ExpectRefCountForInvalidationSet(rule_feature_set.id_invalidation_sets_, id,
+ ref_count);
+ }
+
+ void ExpectRefCountForPseudoInvalidationSet(
+ const RuleFeatureSet& rule_feature_set,
+ CSSSelector::PseudoType key,
+ RefCount ref_count) {
+ ExpectRefCountForInvalidationSet(rule_feature_set.pseudo_invalidation_sets_,
+ key, ref_count);
+ }
+
private:
RuleFeatureSet rule_feature_set_;
Persistent<Document> document_;
@@ -376,6 +451,25 @@ TEST_F(RuleFeatureSetTest, any) {
ExpectNoInvalidation(invalidation_lists.siblings);
}
+TEST_F(RuleFeatureSetTest, repeatedAny) {
+ EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
+ CollectFeatures(":-webkit-any(.v, .w):-webkit-any(.x, .y, .z)"));
+
+ {
+ InvalidationLists invalidation_lists;
+ CollectInvalidationSetsForClass(invalidation_lists, "v");
+ ExpectSelfInvalidation(invalidation_lists.descendants);
+ ExpectNoInvalidation(invalidation_lists.siblings);
+ }
+
+ {
+ InvalidationLists invalidation_lists;
+ CollectInvalidationSetsForClass(invalidation_lists, "x");
+ ExpectSelfInvalidation(invalidation_lists.descendants);
+ ExpectNoInvalidation(invalidation_lists.siblings);
+ }
+}
+
TEST_F(RuleFeatureSetTest, anyIdDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :-webkit-any(#b, #c)"));
@@ -385,6 +479,15 @@ TEST_F(RuleFeatureSetTest, anyIdDescendant) {
ExpectIdInvalidation("b", "c", invalidation_lists.descendants);
}
+TEST_F(RuleFeatureSetTest, repeatedAnyDescendant) {
+ EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
+ CollectFeatures(".a :-webkit-any(.v, .w):-webkit-any(.x, .y, .z)"));
+
+ InvalidationLists invalidation_lists;
+ CollectInvalidationSetsForClass(invalidation_lists, "a");
+ ExpectClassInvalidation("v", "w", invalidation_lists.descendants);
+}
+
TEST_F(RuleFeatureSetTest, anyTagDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :-webkit-any(span, div)"));
@@ -1246,4 +1349,133 @@ TEST_F(RuleFeatureSetTest, invalidatesParts) {
EXPECT_TRUE(invalidation_lists.descendants[0]->InvalidatesParts());
}
}
+
+TEST_F(RuleFeatureSetTest, CopyOnWrite) {
+ // RuleFeatureSet local1 has an entry in each of the class/id/attribute/
+ // pseudo sets.
+ RuleFeatureSet local1;
+ CollectFeatures(".a .b");
+ CollectFeatures("#d .e");
+ CollectFeatures("[thing] .f");
+ CollectFeatures(":hover .h");
+ AddTo(local1);
+ ClearFeatures();
+ ExpectRefCountForClassInvalidationSet(local1, "a", RefCount::kOne);
+ ExpectRefCountForIdInvalidationSet(local1, "d", RefCount::kOne);
+ ExpectRefCountForAttributeInvalidationSet(local1, "thing", RefCount::kOne);
+ ExpectRefCountForPseudoInvalidationSet(local1, CSSSelector::kPseudoHover,
+ RefCount::kOne);
+
+ // RuleFeatureSet local2 overlaps partially with local1.
+ RuleFeatureSet local2;
+ CollectFeatures(".a .c");
+ CollectFeatures("#d img");
+ AddTo(local2);
+ ClearFeatures();
+ ExpectRefCountForClassInvalidationSet(local2, "a", RefCount::kOne);
+ ExpectRefCountForIdInvalidationSet(local2, "d", RefCount::kOne);
+
+ // RuleFeatureSet local3 overlaps partially with local1, but not with local2.
+ RuleFeatureSet local3;
+ CollectFeatures("[thing] .g");
+ CollectFeatures(":hover .i");
+ AddTo(local3);
+ ClearFeatures();
+ ExpectRefCountForAttributeInvalidationSet(local3, "thing", RefCount::kOne);
+ ExpectRefCountForPseudoInvalidationSet(local3, CSSSelector::kPseudoHover,
+ RefCount::kOne);
+
+ // Using an empty RuleFeatureSet to simulate the global RuleFeatureSet:
+ RuleFeatureSet global;
+
+ // After adding local1, we expect to share the InvalidationSets with local1.
+ global.Add(local1);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
+ ExpectRefCountForIdInvalidationSet(global, "d", RefCount::kMany);
+ ExpectRefCountForAttributeInvalidationSet(global, "thing", RefCount::kMany);
+ ExpectRefCountForPseudoInvalidationSet(global, CSSSelector::kPseudoHover,
+ RefCount::kMany);
+
+ // For the InvalidationSet keys that overlap with local1, |global| now had to
+ // copy the existing InvalidationSets at those keys before modifying them,
+ // so we expect |global| to be the only reference holder to those
+ // InvalidationSets.
+ global.Add(local2);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kOne);
+ ExpectRefCountForIdInvalidationSet(global, "d", RefCount::kOne);
+ ExpectRefCountForAttributeInvalidationSet(global, "thing", RefCount::kMany);
+ ExpectRefCountForPseudoInvalidationSet(global, CSSSelector::kPseudoHover,
+ RefCount::kMany);
+
+ global.Add(local3);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kOne);
+ ExpectRefCountForIdInvalidationSet(global, "d", RefCount::kOne);
+ ExpectRefCountForAttributeInvalidationSet(global, "thing", RefCount::kOne);
+ ExpectRefCountForPseudoInvalidationSet(global, CSSSelector::kPseudoHover,
+ RefCount::kOne);
+}
+
+TEST_F(RuleFeatureSetTest, CopyOnWrite_SiblingDescendantPairs) {
+ // Test data:
+ std::vector<const char*> data;
+ // Descendant.
+ data.push_back(".a .b0");
+ data.push_back(".a .b1");
+ // Sibling.
+ data.push_back(".a + .b2");
+ data.push_back(".a + .b3");
+ // Sibling with sibling descendants.
+ data.push_back(".a + .b4 .b5");
+ data.push_back(".a + .b6 .b7");
+ // Sibling with descendants.
+ data.push_back(".a + .b8, .a .b9");
+ data.push_back(".a + .b10, .a .b11");
+ // Sibling with sibling descendants and descendants.
+ data.push_back(".a + .b12 .b13, .a .b14");
+ data.push_back(".a + .b15 .b16, .a .b17");
+
+ // For each possible pair in |data|, make sure that we are properly sharing
+ // the InvalidationSet from |local1| until we add the InvalidationSet from
+ // |local2|.
+ for (const char* selector1 : data) {
+ for (const char* selector2 : data) {
+ RuleFeatureSet local1;
+ CollectFeatures(selector1);
+ AddTo(local1);
+ ClearFeatures();
+
+ RuleFeatureSet local2;
+ CollectFeatures(selector2);
+ AddTo(local2);
+ ClearFeatures();
+
+ RuleFeatureSet global;
+ global.Add(local1);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
+ global.Add(local2);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kOne);
+ }
+ }
+}
+
+TEST_F(RuleFeatureSetTest, CopyOnWrite_SelfInvalidation) {
+ RuleFeatureSet local1;
+ CollectFeatures(".a");
+ AddTo(local1);
+ ClearFeatures();
+
+ RuleFeatureSet local2;
+ CollectFeatures(".a");
+ AddTo(local2);
+ ClearFeatures();
+
+ // Adding the SelfInvalidationSet to the SelfInvalidationSet does not cause
+ // a copy.
+ RuleFeatureSet global;
+ global.Add(local1);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
+ global.Add(local2);
+ ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/rule_set.cc b/chromium/third_party/blink/renderer/core/css/rule_set.cc
index 5dd78121577..dcdca93d11b 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_set.cc
@@ -41,8 +41,6 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-#include "third_party/blink/renderer/platform/wtf/terminated_array_builder.h"
-
namespace blink {
static inline PropertyWhitelistType DeterminePropertyWhitelistType(
@@ -71,7 +69,8 @@ RuleData* RuleData::MaybeCreate(StyleRule* rule,
return nullptr;
if (position >= (1 << RuleData::kPositionBits))
return nullptr;
- return new RuleData(rule, selector_index, position, add_rule_flags);
+ return MakeGarbageCollected<RuleData>(rule, selector_index, position,
+ add_rule_flags);
}
RuleData::RuleData(StyleRule* rule,
@@ -99,7 +98,7 @@ void RuleSet::AddToRuleSet(const AtomicString& key,
Member<HeapLinkedStack<Member<const RuleData>>>& rules =
map.insert(key, nullptr).stored_value->value;
if (!rules)
- rules = new HeapLinkedStack<Member<const RuleData>>;
+ rules = MakeGarbageCollected<HeapLinkedStack<Member<const RuleData>>>();
rules->Push(rule_data);
}
@@ -215,9 +214,13 @@ bool RuleSet::FindBestRuleSetAndAdd(const CSSSelector& component,
focus_pseudo_class_rules_.push_back(rule_data);
return true;
case CSSSelector::kPseudoPlaceholder:
- AddToRuleSet(AtomicString("-webkit-input-placeholder"),
- EnsurePendingRules()->shadow_pseudo_element_rules,
- rule_data);
+ if (it->FollowsPart()) {
+ part_pseudo_rules_.push_back(rule_data);
+ } else {
+ AddToRuleSet(AtomicString("-webkit-input-placeholder"),
+ EnsurePendingRules()->shadow_pseudo_element_rules,
+ rule_data);
+ }
return true;
case CSSSelector::kPseudoHost:
case CSSSelector::kPseudoHostContext:
diff --git a/chromium/third_party/blink/renderer/core/css/rule_set.h b/chromium/third_party/blink/renderer/core/css/rule_set.h
index 6f57a02f8b5..41c028185b9 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_set.h
+++ b/chromium/third_party/blink/renderer/core/css/rule_set.h
@@ -84,6 +84,11 @@ class CORE_EXPORT RuleData : public GarbageCollected<RuleData> {
unsigned position,
AddRuleFlags);
+ RuleData(StyleRule*,
+ unsigned selector_index,
+ unsigned position,
+ AddRuleFlags);
+
unsigned GetPosition() const { return position_; }
StyleRule* Rule() const { return rule_; }
const CSSSelector& Selector() const {
@@ -125,11 +130,6 @@ class CORE_EXPORT RuleData : public GarbageCollected<RuleData> {
static constexpr size_t kPositionBits = 18;
private:
- RuleData(StyleRule*,
- unsigned selector_index,
- unsigned position,
- AddRuleFlags);
-
Member<StyleRule> rule_;
unsigned selector_index_ : kSelectorIndexBits;
unsigned position_ : kPositionBits;
diff --git a/chromium/third_party/blink/renderer/core/css/selector_checker.cc b/chromium/third_party/blink/renderer/core/css/selector_checker.cc
index 971c5659c92..8eec220e64f 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_checker.cc
@@ -59,6 +59,7 @@
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/spatial_navigation.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
@@ -1398,6 +1399,14 @@ bool SelectorChecker::MatchesSpatialNavigationFocusPseudoClass(
const Element& element) {
if (!IsSpatialNavigationEnabled(element.GetDocument().GetFrame()))
return false;
+ if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+ DCHECK(element.GetDocument().GetPage());
+ Element* interested_element = element.GetDocument()
+ .GetPage()
+ ->GetSpatialNavigationController()
+ .GetInterestedElement();
+ return interested_element && *interested_element == element;
+ }
if (RuntimeEnabledFeatures::SpatialNavigationForcesOutlineEnabled()) {
// TODO(mthiesse): Decouple spatial navigation target from focus, so that
// if spat nav is enabled, but not used, we don't override focus ring
diff --git a/chromium/third_party/blink/renderer/core/css/selector_query.cc b/chromium/third_party/blink/renderer/core/css/selector_query.cc
index 642f0b61a1b..b941e0714e9 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_query.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_query.cc
@@ -534,8 +534,7 @@ SelectorQuery* SelectorQueryCache::Add(const AtomicString& selectors,
CSSSelectorList selector_list = CSSParser::ParseSelector(
CSSParserContext::Create(
- document, document.BaseURL(),
- false /* is_opaque_response_from_service_worker */,
+ document, document.BaseURL(), true /* origin_clean */,
document.GetReferrerPolicy(), WTF::TextEncoding(),
CSSParserContext::kSnapshotProfile),
nullptr, selectors);
diff --git a/chromium/third_party/blink/renderer/core/css/selector_query_test.cc b/chromium/third_party/blink/renderer/core/css/selector_query_test.cc
index b677facb58f..8168aeb1dc0 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_query_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_query_test.cc
@@ -68,11 +68,10 @@ TEST(SelectorQueryTest, NotMatchingPseudoElement) {
"<body><style>span::before { content: 'X' }</style><span></span></body>");
CSSSelectorList selector_list = CSSParser::ParseSelector(
- CSSParserContext::Create(
- *document, NullURL(),
- false /* is_opaque_response_from_service_worker */,
- network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ CSSParserContext::Create(*document, NullURL(), true /* origin_clean */,
+ network::mojom::ReferrerPolicy::kDefault,
+ WTF::TextEncoding(),
+ CSSParserContext::kSnapshotProfile),
nullptr, "span::before");
std::unique_ptr<SelectorQuery> query =
SelectorQuery::Adopt(std::move(selector_list));
@@ -80,11 +79,10 @@ TEST(SelectorQueryTest, NotMatchingPseudoElement) {
EXPECT_EQ(nullptr, elm);
selector_list = CSSParser::ParseSelector(
- CSSParserContext::Create(
- *document, NullURL(),
- false /* is_opaque_response_from_service_worker */,
- network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ CSSParserContext::Create(*document, NullURL(), true /* origin_clean */,
+ network::mojom::ReferrerPolicy::kDefault,
+ WTF::TextEncoding(),
+ CSSParserContext::kSnapshotProfile),
nullptr, "span");
query = SelectorQuery::Adopt(std::move(selector_list));
elm = query->QueryFirst(*document);
@@ -101,11 +99,10 @@ TEST(SelectorQueryTest, LastOfTypeNotFinishedParsing) {
document->body()->BeginParsingChildren();
CSSSelectorList selector_list = CSSParser::ParseSelector(
- CSSParserContext::Create(
- *document, NullURL(),
- false /* is_opaque_response_from_service_worker */,
- network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ CSSParserContext::Create(*document, NullURL(), true /* origin_clean */,
+ network::mojom::ReferrerPolicy::kDefault,
+ WTF::TextEncoding(),
+ CSSParserContext::kSnapshotProfile),
nullptr, "p:last-of-type");
std::unique_ptr<SelectorQuery> query =
SelectorQuery::Adopt(std::move(selector_list));
diff --git a/chromium/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc b/chromium/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc
index 8a8867ac811..f8b4cb0acfc 100644
--- a/chromium/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc
+++ b/chromium/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc
@@ -65,17 +65,12 @@ void ShadowTreeStyleSheetCollection::CollectStyleSheets(
if (!GetTreeScope().HasAdoptedStyleSheets())
return;
- StyleSheetList& adopted_style_sheets = GetTreeScope().AdoptedStyleSheets();
- unsigned length = adopted_style_sheets.length();
- for (unsigned index = 0; index < length; ++index) {
- StyleSheet* sheet = adopted_style_sheets.item(index);
- if (!sheet)
- continue;
- CSSStyleSheet* css_sheet = ToCSSStyleSheet(sheet);
- if (!css_sheet || !css_sheet->CanBeActivated(g_null_atom))
+ for (CSSStyleSheet* sheet : GetTreeScope().AdoptedStyleSheets()) {
+ if (!sheet || !sheet->CanBeActivated(g_null_atom))
continue;
+ DCHECK_EQ(GetTreeScope().GetDocument(), sheet->AssociatedDocument());
collection.AppendActiveStyleSheet(
- std::make_pair(css_sheet, master_engine.RuleSetForSheet(*css_sheet)));
+ std::make_pair(sheet, master_engine.RuleSetForSheet(*sheet)));
}
}
diff --git a/chromium/third_party/blink/renderer/core/css/style-invalidation.md b/chromium/third_party/blink/renderer/core/css/style-invalidation.md
index aaa1498a80c..5e647a38625 100644
--- a/chromium/third_party/blink/renderer/core/css/style-invalidation.md
+++ b/chromium/third_party/blink/renderer/core/css/style-invalidation.md
@@ -26,12 +26,12 @@ An invalidation set represents
* criteria for matching against a node
* instructions for whether/how to descend the tree into the node's children
-If we have a style rule `".c1 .c2 { ... }"`
+If we have a style rule `".c1 div.c2 { ... }"`
then style recalculation is needed
when a `c1`-class is added or removed
as an ancestor of a `c2`-class
or when a `c2`-class is added or removed
-as a descendant of a `c1`-class element
+from a div that is a descendant of a `c1`-class element
(here adding/removing can be adding/removing an element
or just adding/removing these classes on existing elements).
We don't want to do full style recalc
@@ -43,13 +43,14 @@ otherwise we collect everything as pending invalidation sets.
In the example,
if a `c1`-class is added to an element in the tree,
-we need to invalidate all of its descendants which have class c2.
+we need to invalidate all of its descendants which have class `c2`.
Rather than perform a search right now,
we just mark the element with a pending invalidation set
that matches against `c2`
and descends into all light-descendants.
+(We won't invalidate all div descendants, as class `c2` is more specific.)
-If a `c2`-class element is added to the tree,
+If class `c2` is added to an element in the tree,
then it needs recalculation
if it has a `c1`-class ancestor.
We never search _up_ the tree at this point
@@ -57,6 +58,7 @@ or during style invalidation,
we only do that during recalculation,
so this becomes an immediate invalidation,
even though it may be unnecessary.
+Similarly, we don't check if the `c2`-class element is a div.
Eventually all DOM changes have been turned into immediate invalidations
or pending invalidation sets.
diff --git a/chromium/third_party/blink/renderer/core/css/style_attribute_mutation_scope.cc b/chromium/third_party/blink/renderer/core/css/style_attribute_mutation_scope.cc
index 58ff83ce080..8633cdf82da 100644
--- a/chromium/third_party/blink/renderer/core/css/style_attribute_mutation_scope.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_attribute_mutation_scope.cc
@@ -101,7 +101,7 @@ StyleAttributeMutationScope::~StyleAttributeMutationScope() {
if (CustomElementDefinition* definition =
DefinitionIfStyleChangedCallback(element)) {
definition->EnqueueAttributeChangedCallback(
- element, html_names::kStyleAttr, old_value_,
+ *element, html_names::kStyleAttr, old_value_,
element->getAttribute(html_names::kStyleAttr));
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_change_reason.cc b/chromium/third_party/blink/renderer/core/css/style_change_reason.cc
index 7fed20e4839..26c4072f4a9 100644
--- a/chromium/third_party/blink/renderer/core/css/style_change_reason.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_change_reason.cc
@@ -19,6 +19,7 @@ const char kControlValue[] = "ControlValue";
const char kControl[] = "Control";
const char kDeclarativeContent[] = "Extension declarativeContent.css";
const char kDesignMode[] = "DesignMode";
+const char kFindInvisible[] = "FindInvisible";
const char kFontSizeChange[] = "FontSizeChange";
const char kFonts[] = "Fonts";
const char kFrame[] = "Frame";
diff --git a/chromium/third_party/blink/renderer/core/css/style_change_reason.h b/chromium/third_party/blink/renderer/core/css/style_change_reason.h
index 7d21ac935b0..cfb2070a0b2 100644
--- a/chromium/third_party/blink/renderer/core/css/style_change_reason.h
+++ b/chromium/third_party/blink/renderer/core/css/style_change_reason.h
@@ -26,6 +26,7 @@ extern const char kFrame[];
extern const char kFontSizeChange[];
extern const char kFonts[];
extern const char kFullscreen[];
+extern const char kFindInvisible[];
extern const char kInheritedStyleChangeFromParentFrame[];
extern const char kInline[];
extern const char kInlineCSSStyleMutated[];
diff --git a/chromium/third_party/blink/renderer/core/css/style_engine.cc b/chromium/third_party/blink/renderer/core/css/style_engine.cc
index 2fd4861f44b..db393e393ab 100644
--- a/chromium/third_party/blink/renderer/core/css/style_engine.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_engine.cc
@@ -288,19 +288,19 @@ void StyleEngine::ModifiedStyleSheetCandidateNode(Node& node) {
SetNeedsActiveStyleUpdate(node.GetTreeScope());
}
-void StyleEngine::AdoptedStyleSheetsWillChange(TreeScope& tree_scope,
- StyleSheetList* old_sheets,
- StyleSheetList* new_sheets) {
+void StyleEngine::AdoptedStyleSheetsWillChange(
+ TreeScope& tree_scope,
+ const HeapVector<Member<CSSStyleSheet>>& old_sheets,
+ const HeapVector<Member<CSSStyleSheet>>& new_sheets) {
if (GetDocument().IsDetached())
return;
- unsigned old_sheets_count = old_sheets ? old_sheets->length() : 0;
- unsigned new_sheets_count = new_sheets ? new_sheets->length() : 0;
+ unsigned old_sheets_count = old_sheets.size();
+ unsigned new_sheets_count = new_sheets.size();
unsigned min_count = std::min(old_sheets_count, new_sheets_count);
unsigned index = 0;
- while (index < min_count &&
- old_sheets->item(index) == new_sheets->item(index)) {
+ while (index < min_count && old_sheets[index] == new_sheets[index]) {
index++;
}
@@ -308,17 +308,18 @@ void StyleEngine::AdoptedStyleSheetsWillChange(TreeScope& tree_scope,
return;
for (unsigned i = index; i < old_sheets_count; ++i) {
- ToCSSStyleSheet(old_sheets->item(i))
- ->RemovedAdoptedFromTreeScope(tree_scope);
+ old_sheets[i]->RemovedAdoptedFromTreeScope(tree_scope);
}
for (unsigned i = index; i < new_sheets_count; ++i) {
- ToCSSStyleSheet(new_sheets->item(i))->AddedAdoptedToTreeScope(tree_scope);
+ new_sheets[i]->AddedAdoptedToTreeScope(tree_scope);
}
if (new_sheets_count) {
EnsureStyleSheetCollectionFor(tree_scope);
if (tree_scope != document_)
active_tree_scopes_.insert(&tree_scope);
+ } else if (!StyleSheetCollectionFor(tree_scope)) {
+ return;
}
SetNeedsActiveStyleUpdate(tree_scope);
}
@@ -529,7 +530,8 @@ void StyleEngine::ResetAuthorStyle(TreeScope& tree_scope) {
if (!scoped_resolver)
return;
- global_rule_set_->MarkDirty();
+ if (global_rule_set_)
+ global_rule_set_->MarkDirty();
if (tree_scope.RootNode().IsDocumentNode()) {
scoped_resolver->ResetAuthorStyle();
return;
diff --git a/chromium/third_party/blink/renderer/core/css/style_engine.h b/chromium/third_party/blink/renderer/core/css/style_engine.h
index 354d1c7cb62..d05f7cbc72d 100644
--- a/chromium/third_party/blink/renderer/core/css/style_engine.h
+++ b/chromium/third_party/blink/renderer/core/css/style_engine.h
@@ -136,9 +136,10 @@ class CORE_EXPORT StyleEngine final
void AddStyleSheetCandidateNode(Node&);
void RemoveStyleSheetCandidateNode(Node&, ContainerNode& insertion_point);
void ModifiedStyleSheetCandidateNode(Node&);
- void AdoptedStyleSheetsWillChange(TreeScope&,
- StyleSheetList* old_sheets,
- StyleSheetList* new_sheets);
+ void AdoptedStyleSheetsWillChange(
+ TreeScope&,
+ const HeapVector<Member<CSSStyleSheet>>& old_sheets,
+ const HeapVector<Member<CSSStyleSheet>>& new_sheets);
void AddedCustomElementDefaultStyles(
const HeapVector<Member<CSSStyleSheet>>& default_styles);
void MediaQueriesChangedInScope(TreeScope&);
diff --git a/chromium/third_party/blink/renderer/core/css/style_engine_test.cc b/chromium/third_party/blink/renderer/core/css/style_engine_test.cc
index 26cd17b201c..2e52cb263ec 100644
--- a/chromium/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -6,6 +6,7 @@
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/css/css_font_selector.h"
@@ -41,6 +42,7 @@ using namespace css_test_helpers;
class StyleEngineTest : public testing::Test {
protected:
void SetUp() override;
+ void TearDown() override;
Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
StyleEngine& GetStyleEngine() { return GetDocument().GetStyleEngine(); }
@@ -64,12 +66,17 @@ class StyleEngineTest : public testing::Test {
private:
std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+ RuntimeEnabledFeatures::Backup features_backup_;
};
void StyleEngineTest::SetUp() {
dummy_page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
}
+void StyleEngineTest::TearDown() {
+ features_backup_.Restore();
+}
+
StyleEngineTest::RuleSetInvalidation
StyleEngineTest::ScheduleInvalidationsForRules(TreeScope& tree_scope,
const String& css_text) {
@@ -1189,21 +1196,22 @@ TEST_F(StyleEngineTest, StyleSheetsForStyleSheetList_ShadowRoot) {
EXPECT_FALSE(GetStyleEngine().NeedsActiveStyleUpdate());
}
-class StyleEngineClient : public frame_test_helpers::TestWebViewClient {
+class StyleEngineClient : public frame_test_helpers::TestWebWidgetClient {
public:
- StyleEngineClient() : device_scale_factor_(1.f) {}
+ // WebWidgetClient overrides.
void ConvertWindowToViewport(WebFloatRect* rect) override {
rect->x *= device_scale_factor_;
rect->y *= device_scale_factor_;
rect->width *= device_scale_factor_;
rect->height *= device_scale_factor_;
}
+
void set_device_scale_factor(float device_scale_factor) {
device_scale_factor_ = device_scale_factor;
}
private:
- float device_scale_factor_;
+ float device_scale_factor_ = 1.f;
};
TEST_F(StyleEngineTest, ViewportDescriptionForZoomDSF) {
@@ -1212,7 +1220,7 @@ TEST_F(StyleEngineTest, ViewportDescriptionForZoomDSF) {
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl =
- web_view_helper.Initialize(nullptr, &client, nullptr, nullptr);
+ web_view_helper.Initialize(nullptr, nullptr, &client);
web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -1476,6 +1484,55 @@ TEST_F(StyleEngineTest, MediaQueriesChangeDefaultFontSize) {
GetCSSPropertyColor()));
}
+TEST_F(StyleEngineTest, MediaQueriesChangeColorScheme) {
+ RuntimeEnabledFeatures::SetMediaQueryPrefersColorSchemeEnabled(true);
+
+ GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+ <style>
+ body { color: red }
+ @media (prefers-color-scheme: dark) {
+ body { color: green }
+ }
+ </style>
+ <body></body>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+ EXPECT_EQ(MakeRGB(255, 0, 0),
+ GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+ GetCSSPropertyColor()));
+
+ GetDocument().GetSettings()->SetPreferredColorScheme(WebColorScheme::kDark);
+ UpdateAllLifecyclePhases();
+ EXPECT_EQ(MakeRGB(0, 128, 0),
+ GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+ GetCSSPropertyColor()));
+}
+
+TEST_F(StyleEngineTest, MediaQueriesChangePrefersReducedMotion) {
+ RuntimeEnabledFeatures::SetMediaQueryPrefersReducedMotionEnabled(true);
+ GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+ <style>
+ body { color: red }
+ @media (prefers-reduced-motion: reduce) {
+ body { color: green }
+ }
+ </style>
+ <body></body>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+ EXPECT_EQ(MakeRGB(255, 0, 0),
+ GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+ GetCSSPropertyColor()));
+
+ GetDocument().GetSettings()->SetPrefersReducedMotion(true);
+ UpdateAllLifecyclePhases();
+ EXPECT_EQ(MakeRGB(0, 128, 0),
+ GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
+ GetCSSPropertyColor()));
+}
+
TEST_F(StyleEngineTest, ShadowRootStyleRecalcCrash) {
GetDocument().body()->SetInnerHTMLFromString("<div id=host></div>");
HTMLElement* host = ToHTMLElement(GetDocument().getElementById("host"));
@@ -1716,4 +1773,55 @@ TEST_F(StyleEngineTest, CSSSelectorEmptyWhitespaceOnlyFail) {
EXPECT_TRUE(is_counted(div_elements->item(4)));
}
+TEST_F(StyleEngineTest, EnsuredComputedStyleRecalc) {
+ GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+ <div style="display:none">
+ <div>
+ <div id="computed">
+ <span id="span"><span>XXX</span></span>
+ </div>
+ </div>
+ </div>
+ )HTML");
+ UpdateAllLifecyclePhases();
+
+ Element* computed = GetDocument().getElementById("computed");
+ Element* span_outer = GetDocument().getElementById("span");
+ Node* span_inner = span_outer->firstChild();
+
+ // Initially all null in display:none subtree.
+ EXPECT_FALSE(computed->GetComputedStyle());
+ EXPECT_FALSE(span_outer->GetComputedStyle());
+ EXPECT_FALSE(span_inner->GetComputedStyle());
+
+ // Force computed style down to #computed.
+ computed->EnsureComputedStyle();
+ UpdateAllLifecyclePhases();
+ EXPECT_TRUE(computed->GetComputedStyle());
+ EXPECT_FALSE(span_outer->GetComputedStyle());
+ EXPECT_FALSE(span_inner->GetComputedStyle());
+
+ // Setting span color should not create ComputedStyles during style recalc.
+ span_outer->SetInlineStyleProperty(CSSPropertyColor, "blue");
+ EXPECT_TRUE(span_outer->NeedsStyleRecalc());
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
+ GetStyleEngine().RecalcStyle(kNoChange);
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
+
+ EXPECT_FALSE(span_outer->NeedsStyleRecalc());
+ EXPECT_FALSE(span_outer->GetComputedStyle());
+ EXPECT_FALSE(span_inner->GetComputedStyle());
+ // #computed still non-null because #span_outer is the recalc root.
+ EXPECT_TRUE(computed->GetComputedStyle());
+
+ // Triggering style recalc which propagates the color down the tree should
+ // clear ComputedStyle objects in the display:none subtree.
+ GetDocument().body()->SetInlineStyleProperty(CSSPropertyColor, "pink");
+ UpdateAllLifecyclePhases();
+
+ EXPECT_FALSE(computed->GetComputedStyle());
+ EXPECT_FALSE(span_outer->GetComputedStyle());
+ EXPECT_FALSE(span_inner->GetComputedStyle());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc b/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc
index 1979b42a684..187ef07820f 100644
--- a/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc
@@ -12,7 +12,7 @@
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/loader/fetch/substitute_data.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
@@ -82,9 +82,8 @@ class StyleEnvironmentVariablesTest : public PageTestBase {
void SimulateNavigation() {
const KURL& url = KURL(NullURL(), "https://www.example.com");
GetDocument().GetFrame()->Loader().CommitNavigation(
- ResourceRequest(url), SubstituteData(SharedBuffer::Create()),
- ClientRedirectPolicy::kNotClientRedirect,
- base::UnguessableToken::Create());
+ WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ nullptr /* extra_data */);
blink::test::RunPendingTasks();
ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_media.idl b/chromium/third_party/blink/renderer/core/css/style_media.idl
index 5e11e729feb..f87108f5ab1 100644
--- a/chromium/third_party/blink/renderer/core/css/style_media.idl
+++ b/chromium/third_party/blink/renderer/core/css/style_media.idl
@@ -35,5 +35,5 @@
NoInterfaceObject
] interface StyleMedia {
[MeasureAs=StyleMediaType] readonly attribute DOMString type;
- [MeasureAs=StyleMediaMatchMedium] boolean matchMedium([Default=Undefined] optional DOMString mediaquery);
+ [MeasureAs=StyleMediaMatchMedium] boolean matchMedium([DefaultValue=Undefined] optional DOMString mediaquery);
};
diff --git a/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc b/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc
index 1d94c517dc8..ea3d503a5fa 100644
--- a/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -24,6 +24,8 @@
#include "third_party/blink/renderer/core/css/style_property_serializer.h"
#include <bitset>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_markup.h"
@@ -1037,7 +1039,7 @@ String StylePropertySerializer::BorderPropertyValue(
const StylePropertyShorthand& color) const {
const StylePropertyShorthand properties[3] = {width, style, color};
StringBuilder result;
- for (size_t i = 0; i < arraysize(properties); ++i) {
+ for (size_t i = 0; i < base::size(properties); ++i) {
String value = GetCommonValue(properties[i]);
if (value.IsNull())
return String();
@@ -1056,7 +1058,7 @@ String StylePropertySerializer::BorderImagePropertyValue() const {
&GetCSSPropertyBorderImageSource(), &GetCSSPropertyBorderImageSlice(),
&GetCSSPropertyBorderImageWidth(), &GetCSSPropertyBorderImageOutset(),
&GetCSSPropertyBorderImageRepeat()};
- size_t length = arraysize(properties);
+ size_t length = base::size(properties);
for (size_t i = 0; i < length; ++i) {
const CSSValue& value = *property_set_.GetPropertyCSSValue(*properties[i]);
if (!result.IsEmpty())
diff --git a/chromium/third_party/blink/renderer/core/css/style_property_shorthand_custom.cc b/chromium/third_party/blink/renderer/core/css/style_property_shorthand_custom.cc
index 685c6bd2e40..7548c8249b4 100644
--- a/chromium/third_party/blink/renderer/core/css/style_property_shorthand_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_property_shorthand_custom.cc
@@ -21,6 +21,8 @@
#include "third_party/blink/renderer/core/style_property_shorthand.h"
+#include "base/stl_util.h"
+
namespace blink {
const StylePropertyShorthand& animationShorthandForParsing() {
@@ -44,7 +46,7 @@ const StylePropertyShorthand& animationShorthandForParsing() {
&GetCSSPropertyAnimationName()};
static StylePropertyShorthand webkit_animation_longhands_for_parsing(
CSSPropertyAnimation, kAnimationPropertiesForParsing,
- arraysize(kAnimationPropertiesForParsing));
+ base::size(kAnimationPropertiesForParsing));
return webkit_animation_longhands_for_parsing;
}
@@ -57,7 +59,7 @@ const StylePropertyShorthand& transitionShorthandForParsing() {
&GetCSSPropertyTransitionDelay(), &GetCSSPropertyTransitionProperty()};
static StylePropertyShorthand transition_longhands(
CSSPropertyTransition, kTransitionProperties,
- arraysize(kTransitionProperties));
+ base::size(kTransitionProperties));
return transition_longhands;
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule.h b/chromium/third_party/blink/renderer/core/css/style_rule.h
index a6488356465..8a9596d8dcd 100644
--- a/chromium/third_party/blink/renderer/core/css/style_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/style_rule.h
@@ -345,11 +345,16 @@ class CORE_EXPORT StyleRuleFontFeatureValues : public StyleRuleBase {
static StyleRuleFontFeatureValues* Create(
const CSSValueList* font_family,
const CSSIdentifierValue* font_display) {
- return new StyleRuleFontFeatureValues(font_family, font_display);
+ return MakeGarbageCollected<StyleRuleFontFeatureValues>(font_family,
+ font_display);
}
+ StyleRuleFontFeatureValues(const CSSValueList* font_family,
+ const CSSIdentifierValue* font_display);
+ StyleRuleFontFeatureValues(const StyleRuleFontFeatureValues&) = default;
+
StyleRuleFontFeatureValues* Copy() const {
- return new StyleRuleFontFeatureValues(*this);
+ return MakeGarbageCollected<StyleRuleFontFeatureValues>(*this);
}
const CSSValueList& FontFamily() const {
@@ -361,10 +366,6 @@ class CORE_EXPORT StyleRuleFontFeatureValues : public StyleRuleBase {
void TraceAfterDispatch(blink::Visitor*);
private:
- StyleRuleFontFeatureValues(const CSSValueList* font_family,
- const CSSIdentifierValue* font_display);
- StyleRuleFontFeatureValues(const StyleRuleFontFeatureValues&) = default;
-
Member<const CSSValueList> font_family_;
Member<const CSSIdentifierValue> font_display_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule_import.cc b/chromium/third_party/blink/renderer/core/css/style_rule_import.cc
index c53f60348eb..257ffde40b9 100644
--- a/chromium/third_party/blink/renderer/core/css/style_rule_import.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_rule_import.cc
@@ -79,8 +79,8 @@ void StyleRuleImport::NotifyFinished(Resource* resource) {
context = parent_style_sheet_->ParserContext();
}
context = CSSParserContext::Create(
- context, cached_style_sheet->GetResponse().Url(),
- cached_style_sheet->GetResponse().IsOpaqueResponseFromServiceWorker(),
+ context, cached_style_sheet->GetResponse().ResponseUrl(),
+ cached_style_sheet->GetResponse().IsCorsSameOrigin(),
cached_style_sheet->GetReferrerPolicy(), cached_style_sheet->Encoding(),
document);
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc b/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc
index e171adc065c..73fc14c7b33 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc
@@ -41,8 +41,8 @@ void StyleSheetCollection::Dispose() {
}
void StyleSheetCollection::Swap(StyleSheetCollection& other) {
- ::blink::swap(style_sheets_for_style_sheet_list_,
- other.style_sheets_for_style_sheet_list_);
+ swap(style_sheets_for_style_sheet_list_,
+ other.style_sheets_for_style_sheet_list_);
active_author_style_sheets_.swap(other.active_author_style_sheets_);
sheet_list_dirty_ = false;
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc
index 2338cc7a86b..03fb43b5faa 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc
@@ -124,9 +124,6 @@ bool StyleSheetContents::IsCacheableForResource() const {
// This would require dealing with multiple clients for load callbacks.
if (!LoadCompleted())
return false;
- if (has_media_queries_ &&
- !RuntimeEnabledFeatures::CacheStyleSheetWithMediaQueriesEnabled())
- return false;
// FIXME: Support copying import rules.
if (!import_rules_.IsEmpty())
return false;
@@ -337,30 +334,15 @@ void StyleSheetContents::ParseAuthorStyleSheet(
inspector_parse_author_style_sheet_event::Data(cached_style_sheet));
TimeTicks start_time = CurrentTimeTicks();
- bool is_same_origin_request =
- security_origin && security_origin->CanRequest(BaseURL());
-
- // When the response was fetched via the Service Worker, the original URL may
- // not be same as the base URL.
- // TODO(horo): When we will use the original URL as the base URL, we can
- // remove this check. crbug.com/553535
- if (is_same_origin_request &&
- cached_style_sheet->GetResponse().WasFetchedViaServiceWorker()) {
- const KURL original_url(
- cached_style_sheet->GetResponse().OriginalURLViaServiceWorker());
- // |originalURL| is empty when the response is created in the SW.
- if (!original_url.IsEmpty() && !security_origin->CanRequest(original_url))
- is_same_origin_request = false;
- }
-
+ const ResourceResponse& response = cached_style_sheet->GetResponse();
CSSStyleSheetResource::MIMETypeCheck mime_type_check =
- IsQuirksModeBehavior(parser_context_->Mode()) && is_same_origin_request
+ (IsQuirksModeBehavior(parser_context_->Mode()) &&
+ response.IsCorsSameOrigin())
? CSSStyleSheetResource::MIMETypeCheck::kLax
: CSSStyleSheetResource::MIMETypeCheck::kStrict;
String sheet_text =
cached_style_sheet->SheetText(parser_context_, mime_type_check);
- const ResourceResponse& response = cached_style_sheet->GetResponse();
source_map_url_ = response.HttpHeaderField(http_names::kSourceMap);
if (source_map_url_.IsEmpty()) {
// Try to get deprecated header.
@@ -441,6 +423,12 @@ void StyleSheetContents::CheckLoaded() {
if (loading_clients[i]->LoadCompleted())
continue;
+ if (loading_clients[i]->IsConstructed()) {
+ // Resolve the promise for CSSStyleSheet.replace calls.
+ loading_clients[i]->ResolveReplacePromiseIfNeeded(did_load_error_occur_);
+ continue;
+ }
+
// sheetLoaded might be invoked after its owner node is removed from
// document.
if (Node* owner_node = loading_clients[i]->ownerNode()) {
@@ -567,7 +555,6 @@ StyleSheetContents* StyleSheetContents::ParentStyleSheet() const {
void StyleSheetContents::RegisterClient(CSSStyleSheet* sheet) {
DCHECK(!loading_clients_.Contains(sheet));
DCHECK(!completed_clients_.Contains(sheet));
-
// InspectorCSSAgent::BuildObjectForRule creates CSSStyleSheet without any
// owner node.
if (!sheet->OwnerDocument())
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h
index 81e515579dd..8a7a562bcd6 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h
@@ -149,29 +149,12 @@ class CORE_EXPORT StyleSheetContents
// style sheet. This property probably isn't useful for much except the
// JavaScript binding (which needs to use this value for security).
String OriginalURL() const { return original_url_; }
- // The final request URL after redirects. WARNING: Be careful when
- // using this for security checks. It can be different from the actual
- // response URL if a service worker is involved. See
- // IsOpaqueResponseFromServiceWorker().
+ // The response URL after redirects and service worker interception.
const KURL& BaseURL() const { return parser_context_->BaseURL(); }
- // True if a service worker intercepted the request for this style sheet and
- // returned an opaque response. This context should NOT have access to the
- // contents, regardless of BaseURL().
- //
- // For example:
- // 1. Page at a.com requests a.com/style.css.
- // 2. Service worker responds with b.com/style.css (without CORS).
- // 3. The BaseURL() is "a.com/style.css" but this context is should not have
- // access to contents.
- //
- // You might ask why we don't change BaseURL() to be the actual response URL.
- // In fact, the spec says we should! See crbug.com/553535. But we would still
- // need this "is opaque" bit, since in step 2 above the service worker might
- // have used CORS to get a non-opaque response from b.com.
- bool IsOpaqueResponseFromServiceWorker() const {
- return parser_context_->IsOpaqueResponseFromServiceWorker();
- }
+ // If true, allows reading and modifying of the CSS rules.
+ // https://drafts.csswg.org/cssom/#concept-css-style-sheet-origin-clean-flag
+ bool IsOriginClean() const { return parser_context_->IsOriginClean(); }
unsigned RuleCount() const;
StyleRuleBase* RuleAt(unsigned index) const;
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_list.cc b/chromium/third_party/blink/renderer/core/css/style_sheet_list.cc
index 2990d6a88b3..68f4e467ac4 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_list.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_list.cc
@@ -30,24 +30,9 @@
namespace blink {
StyleSheetList* StyleSheetList::Create() {
- DCHECK(RuntimeEnabledFeatures::ConstructableStylesheetsEnabled());
return MakeGarbageCollected<StyleSheetList>();
}
-StyleSheetList* StyleSheetList::Create(
- const HeapVector<Member<CSSStyleSheet>>& style_sheet_vector,
- ExceptionState& exception_state) {
- if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled()) {
- exception_state.ThrowTypeError("Illegal constructor");
- return nullptr;
- }
- return MakeGarbageCollected<StyleSheetList>(style_sheet_vector);
-}
-
-StyleSheetList::StyleSheetList(
- const HeapVector<Member<CSSStyleSheet>>& style_sheet_vector)
- : style_sheet_vector_(style_sheet_vector) {}
-
StyleSheetList::StyleSheetList(TreeScope* tree_scope)
: tree_scope_(tree_scope) {
CHECK(tree_scope);
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_list.h b/chromium/third_party/blink/renderer/core/css/style_sheet_list.h
index 4533e7cda07..65ba830093e 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_list.h
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_list.h
@@ -38,14 +38,11 @@ class CORE_EXPORT StyleSheetList final : public ScriptWrappable {
public:
static StyleSheetList* Create();
- static StyleSheetList* Create(const HeapVector<Member<CSSStyleSheet>>&,
- ExceptionState&);
static StyleSheetList* Create(TreeScope* tree_scope) {
return MakeGarbageCollected<StyleSheetList>(tree_scope);
}
- explicit StyleSheetList(const HeapVector<Member<CSSStyleSheet>>&);
explicit StyleSheetList(TreeScope*);
StyleSheetList() {}
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_list.idl b/chromium/third_party/blink/renderer/core/css/style_sheet_list.idl
index 163c8f1d373..2a7d00e5d94 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_list.idl
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_list.idl
@@ -21,8 +21,6 @@
// https://drafts.csswg.org/cssom/#the-stylesheetlist-interface
[
- RaisesException=Constructor,
- Constructor(sequence<CSSStyleSheet> sheets),
Exposed=Window
] interface StyleSheetList {
[Measure] getter StyleSheet? item(unsigned long index);
diff --git a/chromium/third_party/blink/renderer/core/display_lock/BUILD.gn b/chromium/third_party/blink/renderer/core/display_lock/BUILD.gn
index d6cce9bb2ba..c0a8bc270d2 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/display_lock/BUILD.gn
@@ -6,10 +6,16 @@ import("//third_party/blink/renderer/core/core.gni")
blink_core_sources("display_lock") {
sources = [
+ "display_lock_budget.cc",
+ "display_lock_budget.h",
"display_lock_context.cc",
"display_lock_context.h",
- "display_lock_suspended_handle.cc",
- "display_lock_suspended_handle.h",
+ "strict_yielding_display_lock_budget.cc",
+ "strict_yielding_display_lock_budget.h",
+ "unyielding_display_lock_budget.cc",
+ "unyielding_display_lock_budget.h",
+ "yielding_display_lock_budget.cc",
+ "yielding_display_lock_budget.h",
]
public_deps = [
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.cc
new file mode 100644
index 00000000000..8aaf596f3f3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.cc
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
+
+namespace blink {
+
+DisplayLockBudget::DisplayLockBudget(DisplayLockContext* context)
+ : context_(context) {}
+
+bool DisplayLockBudget::MarkAncestorsDirtyForPhaseIfNeeded(Phase phase) {
+ switch (phase) {
+ case Phase::kStyle:
+ return context_->MarkAncestorsForStyleRecalcIfNeeded();
+ case Phase::kLayout:
+ return context_->MarkAncestorsForLayoutIfNeeded();
+ case Phase::kPrePaint:
+ return context_->MarkAncestorsForPrePaintIfNeeded();
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool DisplayLockBudget::IsElementDirtyForPhase(Phase phase) const {
+ switch (phase) {
+ case Phase::kStyle:
+ return context_->IsElementDirtyForStyleRecalc();
+ case Phase::kLayout:
+ return context_->IsElementDirtyForLayout();
+ case Phase::kPrePaint:
+ return context_->IsElementDirtyForPrePaint();
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.h b/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.h
new file mode 100644
index 00000000000..4199cb904f9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_BUDGET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_BUDGET_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+
+namespace blink {
+
+class DisplayLockContext;
+class CORE_EXPORT DisplayLockBudget {
+ public:
+ enum class Phase : unsigned {
+ kStyle,
+ kLayout,
+ kPrePaint,
+ kFirst = kStyle,
+ kLast = kPrePaint
+ };
+
+ DisplayLockBudget(DisplayLockContext*);
+ virtual ~DisplayLockBudget() = default;
+
+ // Returns true if the given phase is allowed to proceed under the current
+ // budget.
+ virtual bool ShouldPerformPhase(Phase) const = 0;
+
+ // Notifies the budget that the given phase was completed.
+ virtual void DidPerformPhase(Phase) = 0;
+
+ // Notifies the budget that a new lifecycle update phase is going to start.
+ virtual void WillStartLifecycleUpdate() = 0;
+
+ // Returns true if according to this budget, we still need a lifecycle update.
+ // For example, if a budget blocked a needed phase, then it this will return
+ // true indicating that another frame is needed.
+ virtual bool NeedsLifecycleUpdates() const = 0;
+
+ protected:
+ // Marks the ancestor chain dirty for the given phase if it's needed. Returns
+ // true if the ancestors were marked dirty and false otherwise.
+ bool MarkAncestorsDirtyForPhaseIfNeeded(Phase);
+
+ // Returns true if there is likely to be work for the given phase.
+ bool IsElementDirtyForPhase(Phase) const;
+
+ private:
+ // This is a backpointer to the context, which should always outlive this
+ // budget, so it's untraced.
+ UntracedMember<DisplayLockContext> context_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_BUDGET_H_
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc
new file mode 100644
index 00000000000..d32b99bb69b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc
@@ -0,0 +1,364 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
+#include "third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h"
+#include "third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h"
+#include "third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h"
+#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
+
+namespace blink {
+
+class DisplayLockBudgetTest : public RenderingTest {
+ public:
+ void SetUp() override {
+ RenderingTest::SetUp();
+ features_backup_.emplace();
+ RuntimeEnabledFeatures::SetDisplayLockingEnabled(true);
+ }
+
+ void TearDown() override {
+ if (features_backup_) {
+ features_backup_->Restore();
+ features_backup_.reset();
+ }
+ }
+
+ double GetBudgetMs(const YieldingDisplayLockBudget& budget) const {
+ return budget.GetCurrentBudgetMs();
+ }
+
+ private:
+ base::Optional<RuntimeEnabledFeatures::Backup> features_backup_;
+};
+
+TEST_F(DisplayLockBudgetTest, UnyieldingBudget) {
+ // Note that we're not testing the display lock here, just the budget so we
+ // can do minimal work to ensure we have a context, ignoring containment and
+ // other requirements.
+ SetBodyInnerHTML(R"HTML(
+ <div id="container"></div>
+ )HTML");
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ ASSERT_TRUE(element->GetDisplayLockContext());
+ UnyieldingDisplayLockBudget budget(element->GetDisplayLockContext());
+
+ // Since the lifecycle is clean, we don't actually need any updates.
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+
+ // Dirtying the element will cause us to do updates.
+ element->GetLayoutObject()->SetNeedsLayout("");
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ // Check everything twice since it shouldn't matter how many times we ask the
+ // unyielding budget, the results should always be the same.
+ for (int i = 0; i < 2; ++i) {
+ budget.WillStartLifecycleUpdate();
+ // Note that although we only dirtied layout, all phases "should" complete,
+ // since the budget should never be responsible for blocking phases for any
+ // reason other than we're out of budget.
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kStyle);
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kLayout);
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kPrePaint);
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+ }
+}
+
+TEST_F(DisplayLockBudgetTest, StrictYieldingBudget) {
+ // Note that we're not testing the display lock here, just the budget so we
+ // can do minimal work to ensure we have a context, ignoring containment and
+ // other requirements.
+ SetBodyInnerHTML(R"HTML(
+ <div id="container"></div>
+ )HTML");
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ ASSERT_TRUE(element->GetDisplayLockContext());
+ StrictYieldingDisplayLockBudget budget(element->GetDisplayLockContext());
+
+ // Since the lifecycle is clean, we don't actually need any updates.
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+
+ // Dirtying the element will cause us to do updates.
+ element->GetLayoutObject()->SetNeedsLayout("");
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ {
+ budget.WillStartLifecycleUpdate();
+ // Initially all of the phase checks should return true, since we don't know
+ // which phase the system wants to process next.
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Not doing anything should ensure that we schedule another animation by
+ // returning true here.
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+ }
+ {
+ budget.WillStartLifecycleUpdate();
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Once we perform a phase, its check should remain true, but the rest
+ // will be false for this cycle.
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kStyle);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_FALSE(
+ budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // We would need at least one more run to finish everything.
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+ }
+ {
+ budget.WillStartLifecycleUpdate();
+ // Run the previous block again, now everything will always return true
+ // since the phase we complete here (style) has already been completed
+ // before, and we are open to complete a new phase.
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Since we already befored style before, no new phase has been processed
+ // and all phases are allowed to finish.
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kStyle);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // We would need at least one more run to finish everything.
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+ }
+ {
+ budget.WillStartLifecycleUpdate();
+ // On the next run, the checks for phases completed before should always
+ // return true, and as before since we haven't completed a new phase, the
+ // remainder of the phases should return true for now.
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // This check is the same as in the previous block, but is here to verify
+ // that going through NeedsLifecycleUpdates() and then
+ // WillStartLifecycleUpdate() again doesn't change the fact that we should
+ // still perform all of the phases at this point.
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kStyle);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Let's say layout was clean and we jumped and did prepaint instead, now
+ // every phase before and including prepaint should be true, the rest are
+ // locked from completing.
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kPrePaint);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Note that since we processed everything, we no longer need lifecycle
+ // updates.
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+ }
+ {
+ // Do one more run to ensure everything is still returning true.
+ budget.WillStartLifecycleUpdate();
+ // On the last run, we'll complete all phases. Since there is only one
+ // remaining phase we haven't done, all of the checks should always return
+ // true (it's either an old phase or a first uncompleted phase).
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kStyle);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kLayout);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kPrePaint);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Since we completed everything, we should now be returning false here (no
+ // more updates needed).
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+ }
+}
+
+TEST_F(DisplayLockBudgetTest,
+ StrictYieldingBudgetOnlyNeedsUpdatesForDirtyPhases) {
+ // Note that we're not testing the display lock here, just the budget so we
+ // can do minimal work to ensure we have a context, ignoring containment and
+ // other requirements.
+ SetBodyInnerHTML(R"HTML(
+ <div id="container"></div>
+ )HTML");
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ ASSERT_TRUE(element->GetDisplayLockContext());
+ StrictYieldingDisplayLockBudget budget(element->GetDisplayLockContext());
+
+ // Since the lifecycle is clean, we don't actually need any updates.
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+
+ // Dirtying the element will cause us to do updates.
+ element->GetLayoutObject()->SetNeedsLayout("");
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ // Cleaning the lifecycle phases makes the budget not want any more updates.
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+
+ element->GetLayoutObject()->SetNeedsLayout("");
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+ budget.WillStartLifecycleUpdate();
+
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kLayout);
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ budget.WillStartLifecycleUpdate();
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kPrePaint);
+
+ // Note that since the layout was indicated as done (from the budget
+ // perspective), it will no longer need updates even though the true layout is
+ // dirty. This is because it will no longer block layout from synchronously
+ // completing whenever necessary.
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+}
+
+TEST_F(DisplayLockBudgetTest, YieldingBudget) {
+ // Note that we're not testing the display lock here, just the budget so we
+ // can do minimal work to ensure we have a context, ignoring containment and
+ // other requirements.
+ SetBodyInnerHTML(R"HTML(
+ <div id="container"></div>
+ )HTML");
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ ASSERT_TRUE(element->GetDisplayLockContext());
+ YieldingDisplayLockBudget budget(element->GetDisplayLockContext());
+
+ WTF::ScopedMockClock clock;
+
+ // Since the lifecycle is clean, we don't actually need any updates.
+ EXPECT_FALSE(budget.NeedsLifecycleUpdates());
+
+ // Dirtying the element will cause us to do updates.
+ element->GetLayoutObject()->SetNeedsLayout("");
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ budget.WillStartLifecycleUpdate();
+ // Initially all of the phase checks should return true, since we don't know
+ // which phase the system wants to process next.
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Not doing anything should ensure that we schedule another animation by
+ // returning true here.
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ // Advancing the clock a bit will make us still want to the phases.
+ clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget) / 2));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // However, once we're out of budget, we will not do anything.
+ clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget)));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Starting a new lifecycle will reset the budget.
+ budget.WillStartLifecycleUpdate();
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Performing a phase still keeps the rest of the phases available for work
+ // since we haven't advanced the clock.
+ budget.DidPerformPhase(DisplayLockBudget::Phase::kStyle);
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Now that we're out of budget, phases performed previously should remain
+ // true.
+ clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget) * 2));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Sanity check here: the element still needs layout.
+ EXPECT_TRUE(budget.NeedsLifecycleUpdates());
+
+ // Resetting the budget, and advnacing again should yield the same results as
+ // before.
+ budget.WillStartLifecycleUpdate();
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+ clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget) * 2));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+
+ // Eventually the budget becomes essentially infinite.
+ for (int i = 0; i < 60; ++i)
+ budget.WillStartLifecycleUpdate();
+
+ EXPECT_GT(GetBudgetMs(budget), 1e6);
+ for (int i = 0; i < 60; ++i) {
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
+ EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
+ clock.Advance(TimeDelta::FromMillisecondsD(10000));
+ }
+}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 386b85b0106..0fe7c2515e6 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -4,113 +4,64 @@
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_callback.h"
-#include "third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.h"
+#include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_options.h"
+#include "third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h"
+#include "third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h"
+#include "third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
namespace blink {
-// Change this to 1 to enable each function stderr logging.
-// TODO(vmpstr): Remove this after debugging is all done.
-#if 0
-class CORE_EXPORT DisplayLockScopedLogger {
- public:
- DisplayLockScopedLogger(const char* function,
- const DisplayLockContext::State* state,
- const DisplayLockContext::LifecycleUpdateState* lifecycle_update_state)
- : function_(function), state_(state), lifecycle_update_state_(lifecycle_update_state) {
- for (int i = 0; i < s_indent_; ++i)
- fprintf(stderr, " ");
- fprintf(stderr, "entering %s: state %s lifecycle_update_state %s\n",
- function, StateToString(*state),
- LifecycleUpdateStateToString(*lifecycle_update_state));
- ++s_indent_;
- }
-
- ~DisplayLockScopedLogger() {
- --s_indent_;
- for (int i = 0; i < s_indent_; ++i)
- fprintf(stderr, " ");
- fprintf(stderr, "exiting %s: state %s lifecycle_update_state %s\n",
- function_, StateToString(*state_),
- LifecycleUpdateStateToString(*lifecycle_update_state_));
- }
-
- private:
- const char* StateToString(DisplayLockContext::State state) {
- switch (state) {
- case DisplayLockContext::kUninitialized:
- return "kUninitialized";
- case DisplayLockContext::kSuspended:
- return "kSuspended";
- case DisplayLockContext::kCallbacksPending:
- return "kCallbacksPending";
- case DisplayLockContext::kDisconnected:
- return "kDisconnected";
- case DisplayLockContext::kCommitting:
- return "kCommitting";
- case DisplayLockContext::kResolving:
- return "kResolving";
- case DisplayLockContext::kResolved:
- return "kResolved";
- }
- return "<unknown>";
- };
-
- const char* LifecycleUpdateStateToString(
- DisplayLockContext::LifecycleUpdateState state) {
- switch (state) {
- case DisplayLockContext::kNeedsStyle:
- return "kNeedsStyle";
- case DisplayLockContext::kNeedsLayout:
- return "kNeedsLayout";
- case DisplayLockContext::kNeedsPrePaint:
- return "kNeedsPrePaint";
- case DisplayLockContext::kNeedsPaint:
- return "kNeedsPaint";
- case DisplayLockContext::kDone:
- return "kDone";
- }
- return "<unknown>";
- }
-
- const char* function_;
- const DisplayLockContext::State* state_;
- const DisplayLockContext::LifecycleUpdateState* lifecycle_update_state_;
- static int s_indent_;
-};
+namespace {
+// The default timeout for the lock if a timeout is not specified. Defaults to 1
+// sec.
+double kDefaultLockTimeoutMs = 1000.;
+
+// Helper function that returns an immediately rejected promise.
+ScriptPromise GetRejectedPromise(ScriptState* script_state) {
+ auto* resolver = ScriptPromiseResolver::Create(script_state);
+ auto promise = resolver->Promise();
+ resolver->Reject();
+ return promise;
+}
-int DisplayLockScopedLogger::s_indent_ = 0;
+// Helper function that returns an immediately resolved promise.
+ScriptPromise GetResolvedPromise(ScriptState* script_state) {
+ auto* resolver = ScriptPromiseResolver::Create(script_state);
+ auto promise = resolver->Promise();
+ resolver->Resolve();
+ return promise;
+}
-#define SCOPED_LOGGER(func) \
- DisplayLockScopedLogger logger(func, &state_, &lifecycle_update_state_)
-#else
-#define SCOPED_LOGGER(func)
-#endif // #if 0
+} // namespace
DisplayLockContext::DisplayLockContext(Element* element,
ExecutionContext* context)
- : ContextLifecycleObserver(context), element_(element) {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
+ : ContextLifecycleObserver(context),
+ element_(element),
+ weak_factory_(this) {
+ DCHECK(element_->GetDocument().View());
+ element_->GetDocument().View()->RegisterForLifecycleNotifications(this);
}
DisplayLockContext::~DisplayLockContext() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- DCHECK(state_ == kResolved || state_ == kSuspended) << state_;
- DCHECK(callbacks_.IsEmpty());
+ DCHECK_EQ(state_, kUnlocked);
}
void DisplayLockContext::Trace(blink::Visitor* visitor) {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- visitor->Trace(callbacks_);
- visitor->Trace(resolver_);
+ visitor->Trace(update_resolver_);
+ visitor->Trace(commit_resolver_);
+ visitor->Trace(acquire_resolver_);
visitor->Trace(element_);
ScriptWrappable::Trace(visitor);
ActiveScriptWrappable::Trace(visitor);
@@ -118,310 +69,382 @@ void DisplayLockContext::Trace(blink::Visitor* visitor) {
}
void DisplayLockContext::Dispose() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- RejectAndCleanUp();
+ // Note that if we have any resolvers at dispose time, then it's too late to
+ // reject the promise, since we are not allowed to create new strong
+ // references to objects already set for destruction (and rejecting would do
+ // this since the rejection has to be deferred). We need to detach instead.
+ // TODO(vmpstr): See if there is another earlier time we can detect that we're
+ // going to be disposed.
+ FinishUpdateResolver(kDetach);
+ FinishCommitResolver(kDetach);
+ FinishAcquireResolver(kDetach);
+ CancelTimeoutTask();
+ state_ = kUnlocked;
+
+ if (element_ && element_->GetDocument().View())
+ element_->GetDocument().View()->UnregisterFromLifecycleNotifications(this);
+ weak_factory_.InvalidateWeakPtrs();
}
void DisplayLockContext::ContextDestroyed(ExecutionContext*) {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- RejectAndCleanUp();
+ FinishUpdateResolver(kReject);
+ FinishCommitResolver(kReject);
+ FinishAcquireResolver(kReject);
+ state_ = kUnlocked;
}
bool DisplayLockContext::HasPendingActivity() const {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- // If we haven't resolved it, we should stick around.
- return !IsResolved();
-}
-
-void DisplayLockContext::ScheduleCallback(V8DisplayLockCallback* callback) {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- callbacks_.push_back(callback);
-
- // Suspended state supercedes any new lock requests.
- if (state_ == kSuspended)
- return;
- state_ = kCallbacksPending;
-
- ScheduleTaskIfNeeded();
+ // If we're locked or doing any work and have an element, then we should stay
+ // alive. If the element is gone, then there is no reason for the context to
+ // remain. Also, if we're unlocked we're essentially "idle" so GC can clean us
+ // up. If the script needs the context, the element would create a new one.
+ return element_ && state_ != kUnlocked;
}
-void DisplayLockContext::RequestLock(V8DisplayLockCallback* callback,
- ScriptState* script_state) {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (!resolver_) {
- DCHECK(script_state);
- resolver_ = ScriptPromiseResolver::Create(script_state);
+ScriptPromise DisplayLockContext::acquire(ScriptState* script_state,
+ DisplayLockOptions* options) {
+ double timeout_ms = (options && options->hasTimeout())
+ ? options->timeout()
+ : kDefaultLockTimeoutMs;
+ // We always reschedule a timeout task even if we're not starting a new
+ // acquire. The reason for this is that the last acquire dictates the timeout
+ // interval. Note that the following call cancels any existing timeout tasks.
+ RescheduleTimeoutTask(timeout_ms);
+
+ if (state_ == kPendingAcquire) {
+ DCHECK(acquire_resolver_);
+ return acquire_resolver_->Promise();
}
- ScheduleCallback(callback);
-}
+ DCHECK(!acquire_resolver_);
-void DisplayLockContext::schedule(V8DisplayLockCallback* callback) {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- DCHECK(state_ == kSuspended || state_ == kCallbacksPending);
+ // At this point, if we're not unlocked, then we must already be locked.
+ if (state_ != kUnlocked)
+ return GetResolvedPromise(script_state);
- ScheduleCallback(callback);
-}
+ update_budget_.reset();
-DisplayLockSuspendedHandle* DisplayLockContext::suspend() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- ++suspended_count_;
- state_ = kSuspended;
- return new DisplayLockSuspendedHandle(this);
-}
+ // If we're already connected then we need to ensure that 1. layout is clean
+ // and 2. we have removed the current painted output.
+ if (element_->isConnected()) {
+ acquire_resolver_ = ScriptPromiseResolver::Create(script_state);
+ state_ = kPendingAcquire;
+ MarkPaintLayerNeedsRepaint();
+ ScheduleAnimation();
+ return acquire_resolver_->Promise();
+ }
-Element* DisplayLockContext::lockedElement() const {
- return element_;
+ // Otherwise (if we're not connected), we can acquire the lock immediately.
+ locked_frame_rect_ = LayoutRect();
+ state_ = kLocked;
+ return GetResolvedPromise(script_state);
}
-void DisplayLockContext::ProcessQueue() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- // It's important to clear this before running the tasks, since the tasks can
- // call ScheduleCallback() which will re-schedule a PostTask() for us to
- // continue the work.
- process_queue_task_scheduled_ = false;
-
- // If we're not in callbacks pending, then we shouldn't run anything at the
- // moment.
- if (state_ != kCallbacksPending)
- return;
-
- // Get a local copy of all the tasks we will run.
- // TODO(vmpstr): This should possibly be subject to a budget instead.
- HeapVector<Member<V8DisplayLockCallback>> callbacks;
- callbacks.swap(callbacks_);
-
- for (auto& callback : callbacks) {
- DCHECK(callback);
- {
- // A re-implementation of InvokeAndReportException, in order for us to
- // be able to query |try_catch| to determine whether or not we need to
- // reject our promise.
- v8::TryCatch try_catch(callback->GetIsolate());
- try_catch.SetVerbose(true);
-
- auto result = callback->Invoke(nullptr, this);
- ALLOW_UNUSED_LOCAL(result);
- if (try_catch.HasCaught()) {
- RejectAndCleanUp();
- // We should run the checkpoint here, since the rejection callback (for
- // the promise rejected in RejectAndCleanUp()) may modify DOM which
- // should happen here, as opposed to after a potential lifecycle update
- // (or whenever the next microtask checkpoint is going to happen).
- Microtask::PerformCheckpoint(callback->GetIsolate());
- return;
- }
- }
+ScriptPromise DisplayLockContext::update(ScriptState* script_state) {
+ // Reject if we're unlocked or disconnected.
+ if (state_ == kUnlocked || state_ == kPendingAcquire ||
+ !element_->isConnected()) {
+ return GetRejectedPromise(script_state);
}
- if (callbacks_.IsEmpty() && state_ != kSuspended) {
- if (element_->isConnected()) {
- StartCommit();
- } else {
- state_ = kDisconnected;
- }
+ // If we have a resolver, then we're at least updating already, just return
+ // the same promise.
+ if (update_resolver_) {
+ DCHECK(state_ == kUpdating || state_ == kCommitting) << state_;
+ return update_resolver_->Promise();
}
+
+ update_resolver_ = ScriptPromiseResolver::Create(script_state);
+ StartUpdateIfNeeded();
+ return update_resolver_->Promise();
}
-void DisplayLockContext::RejectAndCleanUp() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (resolver_) {
- state_ = kResolved;
- resolver_->Reject();
- resolver_ = nullptr;
+ScriptPromise DisplayLockContext::commit(ScriptState* script_state) {
+ // Reject if we're unlocked.
+ if (state_ == kUnlocked)
+ return GetRejectedPromise(script_state);
+
+ // If we have a resolver, we must be committing already, just return the same
+ // promise.
+ if (commit_resolver_) {
+ DCHECK(state_ == kCommitting) << state_;
+ return commit_resolver_->Promise();
}
- callbacks_.clear();
- // We may have a dirty subtree and have not propagated the dirty bit up the
- // ancestor tree. Since we're now rejecting the promise and unlocking the
- // element, ensure that we can reach both style and layout subtrees if they
- // are dirty by propagating the bit.
- MarkAncestorsForStyleRecalcIfNeeded();
- MarkAncestorsForLayoutIfNeeded();
+ // Now that we've explicitly been requested to commit, we have cancel the
+ // timeout task.
+ CancelTimeoutTask();
+
+ // Note that we don't resolve the update promise here, since it should still
+ // finish updating before resolution. That is, calling update() and commit()
+ // together will still wait until the lifecycle is clean before resolving any
+ // of the promises.
+ DCHECK_NE(state_, kCommitting);
+ commit_resolver_ = ScriptPromiseResolver::Create(script_state);
+ auto promise = commit_resolver_->Promise();
+ StartCommit();
+ return promise;
}
-void DisplayLockContext::Resume() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- DCHECK_GT(suspended_count_, 0u);
- DCHECK_EQ(state_, kSuspended);
- if (--suspended_count_ == 0) {
- // When becoming unsuspended here are the possible transitions:
- // - If there are callbacks to run, then pending callbacks
- // - If we're not connected, then we're soft suspended, ie disconnected.
- // - Otherwise, we can start committing.
- if (!callbacks_.IsEmpty()) {
- state_ = kCallbacksPending;
- } else if (element_->isConnected()) {
- StartCommit();
- } else {
- state_ = kDisconnected;
- }
- }
- ScheduleTaskIfNeeded();
+void DisplayLockContext::FinishUpdateResolver(ResolverState state) {
+ FinishResolver(&update_resolver_, state);
}
-void DisplayLockContext::NotifyWillNotResume() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- DCHECK_GT(suspended_count_, 0u);
- // The promise will never reject or resolve since we're now indefinitely
- // suspended.
- // TODO(vmpstr): We should probably issue a console warning.
- // We keep the state as suspended.
- DCHECK_EQ(state_, kSuspended);
- resolver_->Detach();
- resolver_ = nullptr;
+void DisplayLockContext::FinishCommitResolver(ResolverState state) {
+ FinishResolver(&commit_resolver_, state);
}
-void DisplayLockContext::ScheduleTaskIfNeeded() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (state_ != kCallbacksPending || process_queue_task_scheduled_)
- return;
-
- DCHECK(GetExecutionContext());
- DCHECK(GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
- GetExecutionContext()
- ->GetTaskRunner(TaskType::kMiscPlatformAPI)
- ->PostTask(FROM_HERE, WTF::Bind(&DisplayLockContext::ProcessQueue,
- WrapWeakPersistent(this)));
- process_queue_task_scheduled_ = true;
+void DisplayLockContext::FinishAcquireResolver(ResolverState state) {
+ FinishResolver(&acquire_resolver_, state);
}
-void DisplayLockContext::NotifyConnectedMayHaveChanged() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (element_->isConnected()) {
- if (state_ == kDisconnected)
- StartCommit();
+void DisplayLockContext::FinishResolver(Member<ScriptPromiseResolver>* resolver,
+ ResolverState state) {
+ if (!*resolver)
return;
+ switch (state) {
+ case kResolve:
+ // In order to avoid script doing work as a part of the lifecycle update,
+ // we delay the resolution to be in a task.
+ GetExecutionContext()
+ ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->PostTask(FROM_HERE, WTF::Bind(
+ +[](ScriptPromiseResolver* resolver) {
+ resolver->Resolve();
+ },
+ WrapPersistent(resolver->Get())));
+ break;
+ case kReject:
+ (*resolver)->Reject();
+ break;
+ case kDetach:
+ (*resolver)->Detach();
}
- // All other states should remain as they are. Specifically, if we're
- // acquiring the lock then we should finish doing so; if we're resolving, then
- // we should finish that as well.
- if (state_ == kCommitting)
- state_ = kDisconnected;
+ *resolver = nullptr;
}
bool DisplayLockContext::ShouldStyle() const {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- return state_ >= kCommitting;
+ return update_forced_ || state_ > kUpdating ||
+ (state_ == kUpdating &&
+ update_budget_->ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
}
void DisplayLockContext::DidStyle() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (state_ != kCommitting)
+ if (state_ != kCommitting && state_ != kUpdating &&
+ state_ != kPendingAcquire && !update_forced_) {
return;
+ }
- // We must have contain: content for display locking.
- auto* style = element_->GetComputedStyle();
- if (!style || !style->ContainsContent()) {
- RejectAndCleanUp();
+ // We must have "contain: style layout" for display locking.
+ // Note that we should also have this containment even if we're forcing
+ // this update to happen. Otherwise, proceeding with layout may cause
+ // unexpected behavior. By rejecting the promise, the behavior can be detected
+ // by script.
+ if (!ElementSupportsDisplayLocking()) {
+ FinishUpdateResolver(kReject);
+ FinishCommitResolver(kReject);
+ FinishAcquireResolver(kReject);
+ state_ = state_ == kUpdating ? kLocked : kUnlocked;
return;
}
- if (lifecycle_update_state_ <= kNeedsStyle) {
- // Normally we need to do layout next, but if it's not dirty then we can
- // skip ahead to pre-paint.
- if (MarkAncestorsForLayoutIfNeeded())
- lifecycle_update_state_ = kNeedsLayout;
- else
- lifecycle_update_state_ = kNeedsPrePaint;
- }
+ if (state_ == kUpdating)
+ update_budget_->DidPerformPhase(DisplayLockBudget::Phase::kStyle);
}
bool DisplayLockContext::ShouldLayout() const {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- return std::tie(state_, lifecycle_update_state_) >=
- std::tuple<State, LifecycleUpdateState>{kCommitting, kNeedsLayout};
+ return update_forced_ || state_ > kUpdating ||
+ (state_ == kUpdating && update_budget_->ShouldPerformPhase(
+ DisplayLockBudget::Phase::kLayout));
}
void DisplayLockContext::DidLayout() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (state_ != kCommitting)
- return;
-
- if (lifecycle_update_state_ <= kNeedsLayout)
- lifecycle_update_state_ = kNeedsPrePaint;
+ if (state_ == kUpdating)
+ update_budget_->DidPerformPhase(DisplayLockBudget::Phase::kLayout);
}
bool DisplayLockContext::ShouldPrePaint() const {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- return std::tie(state_, lifecycle_update_state_) >=
- std::tuple<State, LifecycleUpdateState>{kCommitting, kNeedsPrePaint};
+ return update_forced_ || state_ > kUpdating ||
+ (state_ == kUpdating && update_budget_->ShouldPerformPhase(
+ DisplayLockBudget::Phase::kPrePaint));
}
void DisplayLockContext::DidPrePaint() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (state_ != kCommitting)
- return;
-
- // Since we should be under containment, we should have a layer. If we don't,
- // then paint might not happen and we'll never resolve.
- DCHECK(element_->GetLayoutObject()->HasLayer());
- if (lifecycle_update_state_ <= kNeedsPrePaint)
- lifecycle_update_state_ = kNeedsPaint;
+ if (state_ == kUpdating)
+ update_budget_->DidPerformPhase(DisplayLockBudget::Phase::kPrePaint);
+
+#if DCHECK_IS_ON()
+ if (state_ == kUpdating || state_ == kCommitting) {
+ // Since we should be under containment, we should have a layer. If we
+ // don't, then paint might not happen and we'll never resolve.
+ DCHECK(element_->GetLayoutObject()->HasLayer());
+ }
+#endif
}
bool DisplayLockContext::ShouldPaint() const {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- return std::tie(state_, lifecycle_update_state_) >=
- std::tuple<State, LifecycleUpdateState>{kCommitting, kNeedsPaint};
+ // Note that forced updates should never require us to paint, so we don't
+ // check |update_forced_| here. In other words, although |update_forced_|
+ // could be true here, we still should not paint. This also holds for
+ // kUpdating state, since updates should not paint.
+ return state_ == kCommitting || state_ == kUnlocked;
}
void DisplayLockContext::DidPaint() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (state_ != kCommitting)
+ // This is here for symmetry, but could be removed if necessary.
+}
+
+bool DisplayLockContext::IsSearchable() const {
+ // TODO(vmpstr): Support "searchable: true" option, which allows locked
+ // elements to be searched.
+ return state_ == kUnlocked;
+}
+
+void DisplayLockContext::DidAttachLayoutTree() {
+ if (state_ == kUnlocked)
return;
- if (lifecycle_update_state_ <= kNeedsPaint)
- lifecycle_update_state_ = kDone;
+ // Note that although we checked at style recalc time that the element has
+ // "contain: style layout", it might not actually apply the containment at the
+ // layout object level. This confirms that containment should apply.
+ if (!ElementSupportsDisplayLocking()) {
+ FinishUpdateResolver(kReject);
+ FinishCommitResolver(kReject);
+ state_ = state_ == kUpdating ? kLocked : kUnlocked;
+ }
+}
- DCHECK(resolver_);
- state_ = kResolving;
- resolver_->Resolve();
- resolver_ = nullptr;
+DisplayLockContext::ScopedPendingFrameRect
+DisplayLockContext::GetScopedPendingFrameRect() {
+ if (state_ >= kCommitting)
+ return ScopedPendingFrameRect(nullptr);
- // After the above resolution callback runs (in a microtask), we should
- // finish resolving if the lock was not re-acquired.
- Microtask::EnqueueMicrotask(WTF::Bind(&DisplayLockContext::FinishResolution,
- WrapWeakPersistent(this)));
+ DCHECK(element_->GetLayoutObject() && element_->GetLayoutBox());
+ element_->GetLayoutBox()->SetFrameRectForDisplayLock(pending_frame_rect_);
+ return ScopedPendingFrameRect(this);
}
-void DisplayLockContext::DidAttachLayoutTree() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
+void DisplayLockContext::NotifyPendingFrameRectScopeEnded() {
+ DCHECK(element_->GetLayoutObject() && element_->GetLayoutBox());
+ DCHECK(locked_frame_rect_);
+ pending_frame_rect_ = element_->GetLayoutBox()->FrameRect();
+ element_->GetLayoutBox()->SetFrameRectForDisplayLock(*locked_frame_rect_);
+}
- // Note that although we checked at style recalc time that the element has
- // "contain: content", it might not actually apply the containment (e.g. see
- // ShouldApplyContentContainment()). This confirms that containment should
- // apply.
- auto* layout_object = element_->GetLayoutObject();
- if (!layout_object || !layout_object->ShouldApplyContentContainment())
- RejectAndCleanUp();
+DisplayLockContext::ScopedForcedUpdate
+DisplayLockContext::GetScopedForcedUpdate() {
+ if (state_ >= kCommitting)
+ return ScopedForcedUpdate(nullptr);
+
+ DCHECK(!update_forced_);
+ update_forced_ = true;
+
+ // Now that the update is forced, we should ensure that style layout, and
+ // prepaint code can reach it via dirty bits. Note that paint isn't a part of
+ // this, since |update_forced_| doesn't force paint to happen. See
+ // ShouldPaint().
+ MarkAncestorsForStyleRecalcIfNeeded();
+ MarkAncestorsForLayoutIfNeeded();
+ MarkAncestorsForPrePaintIfNeeded();
+ return ScopedForcedUpdate(this);
}
-void DisplayLockContext::FinishResolution() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
- if (state_ == kResolving)
- state_ = kResolved;
+void DisplayLockContext::NotifyForcedUpdateScopeEnded() {
+ DCHECK(update_forced_);
+ update_forced_ = false;
}
void DisplayLockContext::StartCommit() {
- SCOPED_LOGGER(__PRETTY_FUNCTION__);
+ // If we don't have an element or we're not connected, then the process of
+ // committing is the same as just unlocking the element.
+ if (!element_ || !element_->isConnected()) {
+ state_ = kUnlocked;
+ update_budget_.reset();
+ FinishUpdateResolver(kReject);
+ // TODO(vmpstr): Should we resolve here? What's the path to unlocking an
+ // element without connecting it (i.e. acquire the lock, then change your
+ // mind).
+ FinishCommitResolver(kReject);
+ return;
+ }
+
+ // If we have just started to acquire, we can unlock immediately since we
+ // didn't have a chance to lock yet.
+ if (state_ == kPendingAcquire) {
+ FinishAcquireResolver(kReject);
+ FinishCommitResolver(kResolve);
+ state_ = kUnlocked;
+ return;
+ }
+
+ if (state_ != kUpdating)
+ ScheduleAnimation();
+
+ DCHECK_LT(state_, kCommitting);
state_ = kCommitting;
- lifecycle_update_state_ = kNeedsStyle;
+ update_budget_.reset();
- if (!MarkAncestorsForStyleRecalcIfNeeded())
- DidStyle();
+ // We're committing without a budget, so ensure we can reach style.
+ MarkAncestorsForStyleRecalcIfNeeded();
- // The above DidStyle() may reject the promise since it checks that we have
- // containment before proceeding.
- if (state_ != kCommitting)
+ auto* layout_object = element_->GetLayoutObject();
+ // We might commit without connecting, so there is no layout object yet.
+ if (!layout_object)
return;
- // Schedule an animation to perform the lifecycle phases.
- element_->GetDocument().GetPage()->Animator().ScheduleVisualUpdate(
- element_->GetDocument().GetFrame());
+ // Now that we know we have a layout object, we should ensure that we can
+ // reach the rest of the phases as well.
+ MarkAncestorsForLayoutIfNeeded();
+ MarkAncestorsForPrePaintIfNeeded();
+ MarkPaintLayerNeedsRepaint();
+
+ // We also need to commit the pending frame rect at this point.
+ bool frame_rect_changed =
+ ToLayoutBox(layout_object)->FrameRect() != pending_frame_rect_;
+
+ // If the frame rect hasn't actually changed then we don't need to do
+ // anything. Other than wait for commit to happen
+ if (!frame_rect_changed)
+ return;
+
+ // Set the pending frame rect as the new one, and ensure to schedule a layout
+ // for just the box itself. Note that we use the non-display locked version to
+ // ensure all the hooks are property invoked.
+ ToLayoutBox(layout_object)->SetFrameRect(pending_frame_rect_);
+ layout_object->SetNeedsLayout(
+ layout_invalidation_reason::kDisplayLockCommitting);
+}
+
+void DisplayLockContext::StartUpdateIfNeeded() {
+ // We should not be calling this if we're unlocked.
+ DCHECK_NE(state_, kUnlocked);
+ // Any state other than kLocked means that we are already in the process of
+ // updating/committing, so we can piggy back on that process without kicking
+ // off any new updates.
+ if (state_ != kLocked)
+ return;
+
+ // We don't need to mark anything dirty since the budget will take care of
+ // that for us.
+ update_budget_ = CreateNewBudget();
+ state_ = kUpdating;
+ ScheduleAnimation();
+}
+
+std::unique_ptr<DisplayLockBudget> DisplayLockContext::CreateNewBudget() {
+ switch (BudgetType::kDefault) {
+ case BudgetType::kDoNotYield:
+ return base::WrapUnique(new UnyieldingDisplayLockBudget(this));
+ case BudgetType::kStrictYieldBetweenLifecyclePhases:
+ return base::WrapUnique(new StrictYieldingDisplayLockBudget(this));
+ case BudgetType::kYieldBetweenLifecyclePhases:
+ return base::WrapUnique(new YieldingDisplayLockBudget(this));
+ }
+ NOTREACHED();
+ return nullptr;
}
bool DisplayLockContext::MarkAncestorsForStyleRecalcIfNeeded() {
- if (element_->NeedsStyleRecalc() || element_->ChildNeedsStyleRecalc()) {
+ if (IsElementDirtyForStyleRecalc()) {
element_->MarkAncestorsWithChildNeedsStyleRecalc();
return true;
}
@@ -429,13 +452,201 @@ bool DisplayLockContext::MarkAncestorsForStyleRecalcIfNeeded() {
}
bool DisplayLockContext::MarkAncestorsForLayoutIfNeeded() {
+ if (IsElementDirtyForLayout()) {
+ element_->GetLayoutObject()->MarkContainerChainForLayout();
+ return true;
+ }
+ return false;
+}
+
+bool DisplayLockContext::MarkAncestorsForPrePaintIfNeeded() {
+ if (IsElementDirtyForPrePaint()) {
+ auto* layout_object = element_->GetLayoutObject();
+ if (auto* parent = layout_object->Parent())
+ parent->SetSubtreeShouldCheckForPaintInvalidation();
+ return true;
+ }
+ return false;
+}
+
+bool DisplayLockContext::MarkPaintLayerNeedsRepaint() {
if (auto* layout_object = element_->GetLayoutObject()) {
- if (layout_object->NeedsLayout()) {
- layout_object->MarkContainerChainForLayout();
- return true;
- }
+ layout_object->PaintingLayer()->SetNeedsRepaint();
+ return true;
+ }
+ return false;
+}
+
+bool DisplayLockContext::IsElementDirtyForStyleRecalc() const {
+ return element_->NeedsStyleRecalc() || element_->ChildNeedsStyleRecalc();
+}
+
+bool DisplayLockContext::IsElementDirtyForLayout() const {
+ if (auto* layout_object = element_->GetLayoutObject())
+ return layout_object->NeedsLayout();
+ return false;
+}
+
+bool DisplayLockContext::IsElementDirtyForPrePaint() const {
+ if (auto* layout_object = element_->GetLayoutObject()) {
+ return layout_object->ShouldCheckForPaintInvalidation() ||
+ layout_object->SubtreeShouldCheckForPaintInvalidation() ||
+ layout_object->NeedsPaintPropertyUpdate() ||
+ layout_object->DescendantNeedsPaintPropertyUpdate();
}
return false;
}
+void DisplayLockContext::DidMoveToNewDocument(Document& old_document) {
+ // Since we're observing the lifecycle updates, ensure that we listen to the
+ // right document's view.
+ if (old_document.View())
+ old_document.View()->UnregisterFromLifecycleNotifications(this);
+ if (element_ && element_->GetDocument().View())
+ element_->GetDocument().View()->RegisterForLifecycleNotifications(this);
+}
+
+void DisplayLockContext::WillStartLifecycleUpdate() {
+ if (state_ == kUpdating)
+ update_budget_->WillStartLifecycleUpdate();
+}
+
+void DisplayLockContext::DidFinishLifecycleUpdate() {
+ if (state_ == kPendingAcquire) {
+ if (!ElementSupportsDisplayLocking()) {
+ FinishAcquireResolver(kReject);
+ state_ = kUnlocked;
+ return;
+ }
+
+ FinishAcquireResolver(kResolve);
+ state_ = kLocked;
+ auto* layout_object = element_->GetLayoutObject();
+ if (layout_object && layout_object->IsBox()) {
+ locked_frame_rect_ = ToLayoutBox(layout_object)->FrameRect();
+ } else {
+ locked_frame_rect_ = LayoutRect();
+ }
+ return;
+ }
+
+ if (state_ == kCommitting) {
+ FinishUpdateResolver(kResolve);
+ FinishCommitResolver(kResolve);
+ CancelTimeoutTask();
+ state_ = kUnlocked;
+ return;
+ }
+
+ if (state_ != kUpdating)
+ return;
+
+ // If we became disconnected for any reason, then we should reject the
+ // update promise and go back to the locked state.
+ if (!element_ || !element_->isConnected()) {
+ FinishUpdateResolver(kReject);
+ update_budget_.reset();
+ state_ = kLocked;
+ return;
+ }
+
+ if (update_budget_->NeedsLifecycleUpdates()) {
+ // Note that we post a task to schedule an animation, since rAF requests can
+ // be ignored if they happen from within a lifecycle update.
+ GetExecutionContext()
+ ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->PostTask(FROM_HERE, WTF::Bind(&DisplayLockContext::ScheduleAnimation,
+ WrapWeakPersistent(this)));
+ return;
+ }
+
+ FinishUpdateResolver(kResolve);
+ update_budget_.reset();
+ state_ = kLocked;
+}
+
+void DisplayLockContext::ScheduleAnimation() {
+ DCHECK(element_->isConnected());
+
+ // Schedule an animation to perform the lifecycle phases.
+ element_->GetDocument().GetPage()->Animator().ScheduleVisualUpdate(
+ element_->GetDocument().GetFrame());
+}
+
+void DisplayLockContext::RescheduleTimeoutTask(double delay) {
+ CancelTimeoutTask();
+
+ if (!std::isfinite(delay))
+ return;
+
+ // Make sure the delay is at least 1ms.
+ delay = std::max(delay, 1.);
+ GetExecutionContext()
+ ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->PostDelayedTask(FROM_HERE,
+ WTF::Bind(&DisplayLockContext::TriggerTimeout,
+ weak_factory_.GetWeakPtr()),
+ TimeDelta::FromMillisecondsD(delay));
+ timeout_task_is_scheduled_ = true;
+}
+
+void DisplayLockContext::CancelTimeoutTask() {
+ if (!timeout_task_is_scheduled_)
+ return;
+ weak_factory_.InvalidateWeakPtrs();
+ timeout_task_is_scheduled_ = false;
+}
+
+void DisplayLockContext::TriggerTimeout() {
+ StartCommit();
+ timeout_task_is_scheduled_ = false;
+}
+
+bool DisplayLockContext::ElementSupportsDisplayLocking() const {
+ DCHECK(element_ && !IsElementDirtyForStyleRecalc());
+ // If we have a layout object, check that since it's a more authoritative
+ // source of containment information.
+ if (auto* layout_object = element_->GetLayoutObject()) {
+ return layout_object->ShouldApplyStyleContainment() &&
+ layout_object->ShouldApplyLayoutContainment();
+ }
+
+ // Otherwise, fallback on just checking style.
+ auto* style = element_->GetComputedStyle();
+ return style && style->ContainsStyle() && style->ContainsLayout();
+}
+
+// Scoped objects implementation
+// -----------------------------------------------
+
+DisplayLockContext::ScopedPendingFrameRect::ScopedPendingFrameRect(
+ DisplayLockContext* context)
+ : context_(context) {}
+
+DisplayLockContext::ScopedPendingFrameRect::ScopedPendingFrameRect(
+ ScopedPendingFrameRect&& other)
+ : context_(other.context_) {
+ other.context_ = nullptr;
+}
+
+DisplayLockContext::ScopedPendingFrameRect::~ScopedPendingFrameRect() {
+ if (context_)
+ context_->NotifyPendingFrameRectScopeEnded();
+}
+
+DisplayLockContext::ScopedForcedUpdate::ScopedForcedUpdate(
+ DisplayLockContext* context)
+ : context_(context) {}
+
+DisplayLockContext::ScopedForcedUpdate::ScopedForcedUpdate(
+ ScopedForcedUpdate&& other)
+ : context_(other.context_) {
+ other.context_ = nullptr;
+}
+
+DisplayLockContext::ScopedForcedUpdate::~ScopedForcedUpdate() {
+ if (context_)
+ context_->NotifyForcedUpdateScopeEnded();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 64019e8e0cd..3144eda6c75 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -8,40 +8,73 @@
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/compiler.h"
namespace blink {
class DisplayLockSuspendedHandle;
class Element;
-class V8DisplayLockCallback;
+class DisplayLockOptions;
class DisplayLockScopedLogger;
class CORE_EXPORT DisplayLockContext final
: public ScriptWrappable,
public ActiveScriptWrappable<DisplayLockContext>,
- public ContextLifecycleObserver {
+ public ContextLifecycleObserver,
+ public LocalFrameView::LifecycleNotificationObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(DisplayLockContext);
+ USING_PRE_FINALIZER(DisplayLockContext, Dispose);
public:
- // Conceptually the states are private, but made public for debugging /
- // logging.
- enum State {
- kUninitialized,
- kSuspended,
- kCallbacksPending,
- kDisconnected,
- kCommitting,
- kResolving,
- kResolved
+ // Determines what type of budget to use. This can be overridden via
+ // DisplayLockContext::SetBudgetType().
+ // - kDoNotYield:
+ // This will effectively do all of the lifecycle phases when we're
+ // committing. That is, this is the "no budget" option.
+ // - kStrictYieldBetweenLifecyclePhases:
+ // This type always yields between each lifecycle phase, even if that
+ // phase was quick (note that it still skips phases that don't need any
+ // updates).
+ // - kYieldBetweenLifecyclePhases:
+ // This type will only yield between lifecycle phases (not in the middle
+ // of one). However, if there is sufficient time left (TODO(vmpstr):
+ // define this), then it will continue on to the next lifecycle phase.
+ enum class BudgetType {
+ kDoNotYield,
+ kStrictYieldBetweenLifecyclePhases,
+ kYieldBetweenLifecyclePhases,
+ kDefault = kYieldBetweenLifecyclePhases
+ };
+
+ // See GetScopedPendingFrameRect() for description.
+ class ScopedPendingFrameRect {
+ public:
+ ScopedPendingFrameRect(ScopedPendingFrameRect&&);
+ ~ScopedPendingFrameRect();
+
+ private:
+ friend class DisplayLockContext;
+
+ ScopedPendingFrameRect(DisplayLockContext*);
+
+ UntracedMember<DisplayLockContext> context_ = nullptr;
};
- enum LifecycleUpdateState {
- kNeedsStyle,
- kNeedsLayout,
- kNeedsPrePaint,
- kNeedsPaint,
- kDone
+ // See GetScopedForcedUpdate() for description.
+ class ScopedForcedUpdate {
+ public:
+ ScopedForcedUpdate(ScopedForcedUpdate&&);
+ ~ScopedForcedUpdate();
+
+ private:
+ friend class DisplayLockContext;
+
+ ScopedForcedUpdate(DisplayLockContext*);
+
+ UntracedMember<DisplayLockContext> context_ = nullptr;
};
DisplayLockContext(Element*, ExecutionContext*);
@@ -53,39 +86,15 @@ class CORE_EXPORT DisplayLockContext final
// ContextLifecycleObserver overrides.
void ContextDestroyed(ExecutionContext*) override;
- // ActiveScriptWrappable overrides. If there is an outstanding task scheduled
- // to process the callback queue, then this return true.
- // TODO(vmpstr): In the future this would also be true while we're doing
- // co-operative work.
+ // ActiveScriptWrappable overrides. This keeps the context alive as long as we
+ // have an element and we're not unlocked.
bool HasPendingActivity() const final;
- // Notify that the lock was requested. Note that for a new context, this has
- // to be called first. For an existing lock, this will either extend the
- // lifetime of the current lock, or start acquiring a new lock (depending on
- // whether this lock is active or passive).
- void RequestLock(V8DisplayLockCallback*, ScriptState*);
-
- // Returns true if the promise associated with this context was already
- // resolved (or rejected).
- bool IsResolved() const { return state_ == kResolved; }
-
- // Returns a ScriptPromise associated with this context.
- ScriptPromise Promise() const {
- DCHECK(resolver_);
- return resolver_->Promise();
- }
-
- // Called when the connected state may have changed.
- void NotifyConnectedMayHaveChanged();
-
- // Rejects the associated promise if one exists, and clears the current queue.
- // This effectively makes the context finalized.
- void RejectAndCleanUp();
-
- // JavaScript interface implementation.
- void schedule(V8DisplayLockCallback*);
- DisplayLockSuspendedHandle* suspend();
- Element* lockedElement() const;
+ // JavaScript interface implementation. See display_lock_context.idl for
+ // description.
+ ScriptPromise acquire(ScriptState*, DisplayLockOptions*);
+ ScriptPromise update(ScriptState*);
+ ScriptPromise commit(ScriptState*);
// Lifecycle observation / state functions.
bool ShouldStyle() const;
@@ -97,55 +106,122 @@ class CORE_EXPORT DisplayLockContext final
bool ShouldPaint() const;
void DidPaint();
+ // Returns true if the contents of the associated element should be visible
+ // for find-in-page and tab order.
+ bool IsSearchable() const;
+
+ // Called when the layout tree is attached. This is used to verify
+ // containment.
void DidAttachLayoutTree();
+ // Returns a ScopedPendingFrameRect object which exposes the pending layout
+ // frame rect to LayoutBox. This is used to ensure that children of the locked
+ // element use the pending layout frame to update the size of the element.
+ // After the scoped object is destroyed, the previous frame rect is restored
+ // and the pending one is stored in the context until it is needed.
+ ScopedPendingFrameRect GetScopedPendingFrameRect();
+
+ // Returns a ScopedForcedUpdate object which for the duration of its lifetime
+ // will allow updates to happen on this element's subtree. For the element
+ // itself, the frame rect will still be the same as at the time the lock was
+ // acquired. Only one ScopedForcedUpdate can be retrieved from the same
+ // context at a time.
+ ScopedForcedUpdate GetScopedForcedUpdate();
+
+ // This is called when the element with which this context is associated is
+ // moved to a new document. Used to listen to the lifecycle update from the
+ // right document's view.
+ void DidMoveToNewDocument(Document& old_document);
+
+ // LifecycleNotificationObserver overrides.
+ void WillStartLifecycleUpdate() override;
+ void DidFinishLifecycleUpdate() override;
+
private:
+ friend class DisplayLockContextTest;
friend class DisplayLockSuspendedHandle;
+ friend class DisplayLockBudget;
- // Schedules a new callback. If this is the first callback to be scheduled,
- // then a valid ScriptState must be provided, which will be used to create a
- // new ScriptPromiseResolver. In other cases, the ScriptState is ignored.
- void ScheduleCallback(V8DisplayLockCallback*);
-
- // Processes the current queue of callbacks.
- void ProcessQueue();
-
- // Called by the suspended handle in order to resume context operations.
- void Resume();
-
- // Called by the suspended handle informing us that it was disposed without
- // resuming, meaning it will never resume.
- void NotifyWillNotResume();
-
- // Schedule a task if one is required. Specifically, this would schedule a
- // task if one was not already scheduled and if we need to either process
- // callbacks or to resolve the associated promise.
- void ScheduleTaskIfNeeded();
-
- // A function that finishes resolving the promise by establishing a microtask
- // checkpoint. Note that this should be scheduled after entering the
- // kResolving state. If the state is still kResolving after the microtask
- // checkpoint finishes (ie, the lock was not re-acquired), we enter the final
- // kResolved state.
- void FinishResolution();
+ // The current state of the lock. Note that the order of these matters.
+ enum State {
+ kLocked,
+ kUpdating,
+ kCommitting,
+ kUnlocked,
+ kPendingAcquire,
+ };
// Initiate a commit.
void StartCommit();
+ // Initiate an update.
+ void StartUpdateIfNeeded();
// The following functions propagate dirty bits from the locked element up to
// the ancestors in order to be reached. They return true if the element or
// its subtree were dirty, and false otherwise.
bool MarkAncestorsForStyleRecalcIfNeeded();
bool MarkAncestorsForLayoutIfNeeded();
-
- HeapVector<Member<V8DisplayLockCallback>> callbacks_;
- Member<ScriptPromiseResolver> resolver_;
- Member<Element> element_;
-
- bool process_queue_task_scheduled_ = false;
- unsigned suspended_count_ = 0;
- State state_ = kUninitialized;
- LifecycleUpdateState lifecycle_update_state_ = kNeedsStyle;
+ bool MarkAncestorsForPrePaintIfNeeded();
+ bool MarkPaintLayerNeedsRepaint();
+
+ bool IsElementDirtyForStyleRecalc() const;
+ bool IsElementDirtyForLayout() const;
+ bool IsElementDirtyForPrePaint() const;
+
+ // When ScopedPendingFrameRect is destroyed, it calls this function. See
+ // GetScopedPendingFrameRect() for more information.
+ void NotifyPendingFrameRectScopeEnded();
+
+ // When ScopedForcedUpdate is destroyed, it calls this function. See
+ // GetScopedForcedUpdate() for more information.
+ void NotifyForcedUpdateScopeEnded();
+
+ // Creates a new update budget based on the BudgetType::kDefault enum. In
+ // other words, it will create a budget of that type.
+ // TODO(vmpstr): In tests, we will probably switch the value to test other
+ // budgets. As well, this makes it easier to change the budget right in the
+ // enum definitions.
+ std::unique_ptr<DisplayLockBudget> CreateNewBudget();
+
+ // Helper to schedule an animation to delay lifecycle updates for the next
+ // frame.
+ void ScheduleAnimation();
+
+ // Timeout implementation. When the lock is acquired, we kick off a timeout
+ // task that will trigger a commit (which can be canceled by other calls to
+ // schedule or by a call to commit). Note that calling RescheduleTimeoutTask()
+ // will cancel any previously scheduled task.
+ void RescheduleTimeoutTask(double delay);
+ void CancelTimeoutTask();
+ void TriggerTimeout();
+
+ // Helper functions to resolve the update/commit promises.
+ enum ResolverState { kResolve, kReject, kDetach };
+ void FinishUpdateResolver(ResolverState);
+ void FinishCommitResolver(ResolverState);
+ void FinishAcquireResolver(ResolverState);
+ void FinishResolver(Member<ScriptPromiseResolver>*, ResolverState);
+
+ // Returns true if the element supports display locking. Note that this can
+ // only be called if the style is clean. It checks the layout object if it
+ // exists. Otherwise, falls back to checking computed style.
+ bool ElementSupportsDisplayLocking() const;
+
+ std::unique_ptr<DisplayLockBudget> update_budget_;
+
+ Member<ScriptPromiseResolver> commit_resolver_;
+ Member<ScriptPromiseResolver> update_resolver_;
+ Member<ScriptPromiseResolver> acquire_resolver_;
+ WeakMember<Element> element_;
+
+ State state_ = kUnlocked;
+ LayoutRect pending_frame_rect_;
+ base::Optional<LayoutRect> locked_frame_rect_;
+
+ bool update_forced_ = false;
+ bool timeout_task_is_scheduled_ = false;
+
+ base::WeakPtrFactory<DisplayLockContext> weak_factory_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.idl b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.idl
index 40cd8b5ea01..2e34af83b91 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.idl
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.idl
@@ -2,20 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-[RuntimeEnabled=DisplayLocking]
-callback DisplayLockCallback = void(DisplayLockContext context);
-
[RuntimeEnabled=DisplayLocking, ActiveScriptWrappable]
interface DisplayLockContext {
- // Schedule continuation work for this context. Multiple calls are allowed and
- // will run in the order scheduled.
- void schedule(DisplayLockCallback callback);
+ // Acquires a display lock (possibly asynchronously) with the given options.
+ // Returns a promise that resolves when the lock is acquired.
+ [CallWith=ScriptState] Promise<any> acquire(optional DisplayLockOptions options);
- // Suspend the context, preventing the lock from being released. Multiple
- // calls to suspend are allowed: in order to resume the context, resume() must
- // be called on each of the returned DisplayLockSuspendedHandles.
- DisplayLockSuspendedHandle suspend();
+ // Causes co-operative updates to happen on the locked subtree.
+ // Returns a promise that resolves when the update is finished.
+ [CallWith=ScriptState] Promise<any> update();
- // Represents the element on which this locked has been acquired.
- [SameObject, Affects=Nothing] readonly attribute Element lockedElement;
+ // Commits the locked subtree, which releases the lock and updates any
+ // necessary lifecycle phases.
+ // Returns a promise that resolves when the commit is finished.
+ [CallWith=ScriptState] Promise<any> commit();
};
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
new file mode 100644
index 00000000000..d553821ebfe
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -0,0 +1,335 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/editing/finder/text_finder.h"
+#include "third_party/blink/renderer/core/frame/find_in_page.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+namespace {
+class DisplayLockTestFindInPageClient : public mojom::blink::FindInPageClient {
+ public:
+ DisplayLockTestFindInPageClient()
+ : find_results_are_ready_(false), count_(-1), binding_(this) {}
+
+ ~DisplayLockTestFindInPageClient() override = default;
+
+ void SetFrame(WebLocalFrameImpl* frame) {
+ mojom::blink::FindInPageClientPtr client;
+ binding_.Bind(MakeRequest(&client));
+ frame->GetFindInPage()->SetClient(std::move(client));
+ }
+
+ void SetNumberOfMatches(
+ int request_id,
+ unsigned int current_number_of_matches,
+ mojom::blink::FindMatchUpdateType final_update) final {
+ count_ = current_number_of_matches;
+ find_results_are_ready_ =
+ (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
+ }
+
+ void SetActiveMatch(int request_id,
+ const WebRect& active_match_rect,
+ int active_match_ordinal,
+ mojom::blink::FindMatchUpdateType final_update) final {
+ find_results_are_ready_ =
+ (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
+ }
+
+ bool FindResultsAreReady() const { return find_results_are_ready_; }
+ int Count() const { return count_; }
+ void Reset() {
+ find_results_are_ready_ = false;
+ count_ = -1;
+ }
+
+ private:
+ bool find_results_are_ready_;
+ int count_;
+ mojo::Binding<mojom::blink::FindInPageClient> binding_;
+};
+
+} // namespace
+
+class DisplayLockContextTest : public testing::Test {
+ public:
+ void SetUp() override {
+ features_backup_.emplace();
+ RuntimeEnabledFeatures::SetDisplayLockingEnabled(true);
+ web_view_helper_.Initialize();
+ }
+
+ void TearDown() override {
+ if (features_backup_) {
+ features_backup_->Restore();
+ features_backup_.reset();
+ }
+ web_view_helper_.Reset();
+ }
+
+ Document& GetDocument() {
+ return *static_cast<Document*>(
+ web_view_helper_.LocalMainFrame()->GetDocument());
+ }
+ TextFinder& GetTextFinder() {
+ return web_view_helper_.LocalMainFrame()->EnsureTextFinder();
+ }
+ FindInPage* GetFindInPage() {
+ return web_view_helper_.LocalMainFrame()->GetFindInPage();
+ }
+ WebLocalFrameImpl* LocalMainFrame() {
+ return web_view_helper_.LocalMainFrame();
+ }
+
+ void UpdateAllLifecyclePhasesForTest() {
+ GetDocument().View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kTest);
+ }
+
+ void SetHtmlInnerHTML(const char* content) {
+ GetDocument().documentElement()->SetInnerHTMLFromString(
+ String::FromUTF8(content));
+ UpdateAllLifecyclePhasesForTest();
+ }
+
+ void ResizeAndFocus() {
+ web_view_helper_.Resize(WebSize(640, 480));
+ web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
+ test::RunPendingTasks();
+ }
+
+ private:
+ base::Optional<RuntimeEnabledFeatures::Backup> features_backup_;
+ frame_test_helpers::WebViewHelper web_view_helper_;
+};
+
+TEST_F(DisplayLockContextTest, LockedElementIsNotSearchableViaTextFinder) {
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ #container {
+ width: 100px;
+ height: 100px;
+ contain: content;
+ }
+ </style>
+ <body><div id="container">testing</div></body>
+ )HTML");
+
+ int identifier = 0;
+ WebString search_text(String("testing"));
+ auto& text_finder = GetTextFinder();
+ auto find_options = mojom::blink::FindOptions::New();
+ bool wrap_within_frame = true;
+
+ ASSERT_TRUE(text_finder.Find(identifier, search_text, *find_options,
+ wrap_within_frame));
+ text_finder.ClearActiveFindMatch();
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ // We should be in pending acquire state, which means we would allow things
+ // like style and layout but disallow paint.
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+
+ UpdateAllLifecyclePhasesForTest();
+
+ // Sanity checks to ensure the element is locked.
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+
+ EXPECT_FALSE(element->GetDisplayLockContext()->IsSearchable());
+
+ EXPECT_FALSE(text_finder.Find(identifier, search_text, *find_options,
+ wrap_within_frame));
+
+ // Now commit the lock and ensure we can find the text.
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->commit(script_state);
+ }
+
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint());
+
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_TRUE(text_finder.Find(identifier, search_text, *find_options,
+ wrap_within_frame));
+}
+
+TEST_F(DisplayLockContextTest, LockedElementIsNotSearchableViaFindInPage) {
+ ResizeAndFocus();
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ #container {
+ width: 100px;
+ height: 100px;
+ contain: content;
+ }
+ </style>
+ <body><div id="container">testing</div></body>
+ )HTML");
+
+ WebString search_text(String("testing"));
+ auto* find_in_page = GetFindInPage();
+ ASSERT_TRUE(find_in_page);
+
+ DisplayLockTestFindInPageClient client;
+ client.SetFrame(LocalMainFrame());
+
+ auto find_options = mojom::blink::FindOptions::New();
+ find_options->run_synchronously_for_testing = true;
+ find_options->find_next = false;
+ find_options->forward = true;
+
+ int current_id = 123;
+ find_in_page->Find(current_id++, "testing", find_options->Clone());
+ EXPECT_FALSE(client.FindResultsAreReady());
+ test::RunPendingTasks();
+ EXPECT_TRUE(client.FindResultsAreReady());
+ EXPECT_EQ(1, client.Count());
+ client.Reset();
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ // We should be in pending acquire state, which means we would allow things
+ // like style and layout but disallow paint.
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+
+ UpdateAllLifecyclePhasesForTest();
+
+ // Sanity checks to ensure the element is locked.
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+
+ EXPECT_FALSE(element->GetDisplayLockContext()->IsSearchable());
+
+ find_in_page->Find(current_id++, "testing", find_options->Clone());
+ EXPECT_FALSE(client.FindResultsAreReady());
+ test::RunPendingTasks();
+ EXPECT_TRUE(client.FindResultsAreReady());
+ EXPECT_EQ(0, client.Count());
+ client.Reset();
+
+ // Now commit the lock and ensure we can find the text.
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->commit(script_state);
+ }
+
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint());
+
+ UpdateAllLifecyclePhasesForTest();
+
+ find_in_page->Find(current_id++, "testing", find_options->Clone());
+ EXPECT_FALSE(client.FindResultsAreReady());
+ test::RunPendingTasks();
+ EXPECT_TRUE(client.FindResultsAreReady());
+ EXPECT_EQ(1, client.Count());
+ client.Reset();
+}
+
+TEST_F(DisplayLockContextTest, LockedElementAndDescendantsAreNotFocusable) {
+ ResizeAndFocus();
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ #container {
+ width: 100px;
+ height: 100px;
+ contain: content;
+ }
+ </style>
+ <body>
+ <div id="container">
+ <input id="textfield", type="text">
+ </div>
+ </body>
+ )HTML");
+
+ // We start off as being focusable.
+ ASSERT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable());
+ ASSERT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable());
+ ASSERT_TRUE(GetDocument().getElementById("textfield")->IsFocusable());
+
+ auto* element = GetDocument().getElementById("container");
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->acquire(script_state, nullptr);
+ }
+
+ // We should be in pending acquire state, which means we would allow things
+ // like style and layout but disallow paint.
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+
+ UpdateAllLifecyclePhasesForTest();
+
+ // Sanity checks to ensure the element is locked.
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+
+ // The input should not be focusable now.
+ EXPECT_FALSE(
+ GetDocument().getElementById("textfield")->IsKeyboardFocusable());
+ EXPECT_FALSE(GetDocument().getElementById("textfield")->IsMouseFocusable());
+ EXPECT_FALSE(GetDocument().getElementById("textfield")->IsFocusable());
+
+ // Calling explicit focus() should also not focus the element.
+ GetDocument().getElementById("textfield")->focus();
+ EXPECT_FALSE(GetDocument().FocusedElement());
+
+ // Now commit the lock and ensure we can focus the input
+ {
+ auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+ ScriptState::Scope scope(script_state);
+ element->getDisplayLockForBindings()->commit(script_state);
+ }
+
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
+ EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint());
+
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable());
+ EXPECT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable());
+ EXPECT_TRUE(GetDocument().getElementById("textfield")->IsFocusable());
+
+ // Calling explicit focus() should focus the element
+ GetDocument().getElementById("textfield")->focus();
+ EXPECT_EQ(GetDocument().FocusedElement(),
+ GetDocument().getElementById("textfield"));
+}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.idl b/chromium/third_party/blink/renderer/core/display_lock/display_lock_options.idl
index 0b4dc90e6d2..0e5a81891eb 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.idl
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_options.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-[RuntimeEnabled=DisplayLocking] interface DisplayLockSuspendedHandle {
- void resume();
+dictionary DisplayLockOptions {
+ unrestricted double timeout;
};
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.cc
deleted file mode 100644
index 85a36b8ac86..00000000000
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.h"
-#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
-
-namespace blink {
-
-DisplayLockSuspendedHandle::DisplayLockSuspendedHandle(
- DisplayLockContext* context)
- : context_(context) {}
-
-DisplayLockSuspendedHandle::~DisplayLockSuspendedHandle() {}
-
-void DisplayLockSuspendedHandle::Trace(blink::Visitor* visitor) {
- ScriptWrappable::Trace(visitor);
- visitor->Trace(context_);
-}
-
-void DisplayLockSuspendedHandle::Dispose() {
- // If we're disposing the handle and we still have a valid reference to the
- // context, it means that this handle was never resumed. In turn, this means
- // that we will never resume the context. We should inform the context of
- // this.
- // TODO(vmpstr): It is possible that we want to resume the context on dispose,
- // making gc observable from script. If that's the case, this should be
- // changed to instead resume the context.
- if (context_)
- context_->NotifyWillNotResume();
- context_ = nullptr;
-}
-
-void DisplayLockSuspendedHandle::resume() {
- if (context_)
- context_->Resume();
- context_ = nullptr;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.h b/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.h
deleted file mode 100644
index 9e96daba140..00000000000
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_suspended_handle.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_SUSPENDED_HANDLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_SUSPENDED_HANDLE_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class DisplayLockContext;
-class CORE_EXPORT DisplayLockSuspendedHandle final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- DisplayLockSuspendedHandle(DisplayLockContext* context);
- ~DisplayLockSuspendedHandle() override;
-
- // GC functions.
- void Trace(blink::Visitor*) override;
- void Dispose();
-
- // JavaScript interface implementation.
- void resume();
-
- private:
- WeakMember<DisplayLockContext> context_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_SUSPENDED_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.cc b/chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.cc
new file mode 100644
index 00000000000..aca76e246aa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.cc
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h"
+
+#include <algorithm>
+
+namespace blink {
+
+StrictYieldingDisplayLockBudget::StrictYieldingDisplayLockBudget(
+ DisplayLockContext* context)
+ : DisplayLockBudget(context) {}
+
+bool StrictYieldingDisplayLockBudget::ShouldPerformPhase(Phase phase) const {
+ // We should perform any phase earlier than the one we already completed.
+ // Also, we should complete a new phase once per cycle.
+ return (last_completed_phase_ && phase <= *last_completed_phase_) ||
+ !completed_new_phase_this_cycle_;
+}
+
+void StrictYieldingDisplayLockBudget::DidPerformPhase(Phase phase) {
+ if (!completed_new_phase_this_cycle_ &&
+ (!last_completed_phase_ || phase > *last_completed_phase_)) {
+ last_completed_phase_ = phase;
+ completed_new_phase_this_cycle_ = true;
+ }
+
+#if DCHECK_IS_ON()
+ // If we completed a new phase this cycle, then we should not complete any
+ // later phases in the same cycle.
+ if (completed_new_phase_this_cycle_) {
+ DCHECK(last_completed_phase_);
+ DCHECK(phase <= *last_completed_phase_);
+ }
+#endif
+}
+
+void StrictYieldingDisplayLockBudget::WillStartLifecycleUpdate() {
+ // Figure out the next phase we would run. If we had completed a phase before,
+ // then we should try to complete the next one, otherwise we'll start with the
+ // first phase.
+ Phase next_phase =
+ last_completed_phase_
+ ? static_cast<Phase>(
+ std::min(static_cast<unsigned>(*last_completed_phase_) + 1,
+ static_cast<unsigned>(Phase::kLast)))
+ : Phase::kFirst;
+
+ // Mark the next phase we're scheduled to run.
+ for (auto phase = static_cast<unsigned>(next_phase);
+ phase <= static_cast<unsigned>(Phase::kLast); ++phase) {
+ if (MarkAncestorsDirtyForPhaseIfNeeded(static_cast<Phase>(phase)))
+ break;
+ }
+
+ completed_new_phase_this_cycle_ = false;
+}
+
+bool StrictYieldingDisplayLockBudget::NeedsLifecycleUpdates() const {
+ if (last_completed_phase_ && *last_completed_phase_ == Phase::kLast)
+ return false;
+
+ auto next_phase = last_completed_phase_
+ ? static_cast<Phase>(
+ static_cast<unsigned>(*last_completed_phase_) + 1)
+ : Phase::kFirst;
+ // Check if any future phase needs updates.
+ for (auto phase = static_cast<unsigned>(next_phase);
+ phase <= static_cast<unsigned>(Phase::kLast); ++phase) {
+ if (IsElementDirtyForPhase(static_cast<Phase>(phase)))
+ return true;
+ }
+ return false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h b/chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h
new file mode 100644
index 00000000000..da7512a4520
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/strict_yielding_display_lock_budget.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_STRICT_YIELDING_DISPLAY_LOCK_BUDGET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_STRICT_YIELDING_DISPLAY_LOCK_BUDGET_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
+
+namespace blink {
+
+// This budget yields between lifecycle phases even if that phase is quick. In
+// other words, it will only do one new lifecycle phase at a time, and block the
+// future ones. Any lifecycle phases that have already been allowed by this
+// budget in the past are not blocked.
+class CORE_EXPORT StrictYieldingDisplayLockBudget final
+ : public DisplayLockBudget {
+ public:
+ StrictYieldingDisplayLockBudget(DisplayLockContext*);
+ ~StrictYieldingDisplayLockBudget() override = default;
+
+ bool ShouldPerformPhase(Phase) const override;
+ void DidPerformPhase(Phase) override;
+ void WillStartLifecycleUpdate() override;
+ // Returns true if any of the lifecycles that have been previously blocked by
+ // this budget need updates. Note that this does not check lifecycle phases
+ // that have already completed by this budget even if they are now dirty
+ // again. This is done to prevent starvation (ie, it is possible for the
+ // budget to always schedule more work if something in rAF keeps dirtying
+ // layout, for example).
+ bool NeedsLifecycleUpdates() const override;
+
+ protected:
+ base::Optional<Phase> last_completed_phase_;
+ bool completed_new_phase_this_cycle_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_STRICT_YIELDING_DISPLAY_LOCK_BUDGET_H_
diff --git a/chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.cc b/chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.cc
new file mode 100644
index 00000000000..bf0d00f3a16
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h"
+
+namespace blink {
+
+UnyieldingDisplayLockBudget::UnyieldingDisplayLockBudget(
+ DisplayLockContext* context)
+ : DisplayLockBudget(context) {}
+
+bool UnyieldingDisplayLockBudget::ShouldPerformPhase(Phase) const {
+ return true;
+}
+
+void UnyieldingDisplayLockBudget::DidPerformPhase(Phase) {}
+
+void UnyieldingDisplayLockBudget::WillStartLifecycleUpdate() {
+ // Mark all the phases dirty since we have no intention of yielding.
+ for (auto phase = static_cast<unsigned>(Phase::kFirst);
+ phase <= static_cast<unsigned>(Phase::kLast); ++phase) {
+ MarkAncestorsDirtyForPhaseIfNeeded(static_cast<Phase>(phase));
+ }
+}
+
+bool UnyieldingDisplayLockBudget::NeedsLifecycleUpdates() const {
+ for (auto phase = static_cast<unsigned>(Phase::kFirst);
+ phase <= static_cast<unsigned>(Phase::kLast); ++phase) {
+ if (IsElementDirtyForPhase(static_cast<Phase>(phase)))
+ return true;
+ }
+ return false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h b/chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h
new file mode 100644
index 00000000000..aed8c3a964b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/unyielding_display_lock_budget.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_UNYIELDING_DISPLAY_LOCK_BUDGET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_UNYIELDING_DISPLAY_LOCK_BUDGET_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
+
+namespace blink {
+
+// This budget never yields. That is, this is essentially infinite budget that
+// will finish all of the lifecycle phases for the locked subtree if given the
+// chance.
+class CORE_EXPORT UnyieldingDisplayLockBudget final : public DisplayLockBudget {
+ public:
+ UnyieldingDisplayLockBudget(DisplayLockContext*);
+ ~UnyieldingDisplayLockBudget() override = default;
+
+ bool ShouldPerformPhase(Phase) const override;
+ void DidPerformPhase(Phase) override;
+ void WillStartLifecycleUpdate() override;
+ bool NeedsLifecycleUpdates() const override;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_UNYIELDING_DISPLAY_LOCK_BUDGET_H_
diff --git a/chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.cc b/chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.cc
new file mode 100644
index 00000000000..c41dcc551c3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h"
+
+#include "third_party/blink/renderer/platform/wtf/time.h"
+
+#include <algorithm>
+
+namespace blink {
+
+YieldingDisplayLockBudget::YieldingDisplayLockBudget(
+ DisplayLockContext* context)
+ : DisplayLockBudget(context) {}
+
+bool YieldingDisplayLockBudget::ShouldPerformPhase(Phase phase) const {
+ // We should perform any phase earlier than the one we already completed.
+ if (last_completed_phase_ && phase <= *last_completed_phase_)
+ return true;
+
+ // Otherwise, we can still do work while we're not past the deadline.
+ return CurrentTimeTicks() < deadline_;
+}
+
+void YieldingDisplayLockBudget::DidPerformPhase(Phase phase) {
+ if (!last_completed_phase_ || phase > *last_completed_phase_)
+ last_completed_phase_ = phase;
+}
+
+void YieldingDisplayLockBudget::WillStartLifecycleUpdate() {
+ ++lifecycle_count_;
+ deadline_ =
+ CurrentTimeTicks() + TimeDelta::FromMillisecondsD(GetCurrentBudgetMs());
+
+ // Figure out the next phase we would run. If we had completed a phase before,
+ // then we should try to complete the next one, otherwise we'll start with the
+ // first phase.
+ Phase next_phase =
+ last_completed_phase_
+ ? static_cast<Phase>(
+ std::min(static_cast<unsigned>(*last_completed_phase_) + 1,
+ static_cast<unsigned>(Phase::kLast)))
+ : Phase::kFirst;
+
+ // Mark the next phase we're scheduled to run.
+ for (auto phase = static_cast<unsigned>(next_phase);
+ phase <= static_cast<unsigned>(Phase::kLast); ++phase) {
+ if (MarkAncestorsDirtyForPhaseIfNeeded(static_cast<Phase>(phase)))
+ break;
+ }
+}
+
+bool YieldingDisplayLockBudget::NeedsLifecycleUpdates() const {
+ if (last_completed_phase_ && *last_completed_phase_ == Phase::kLast)
+ return false;
+
+ auto next_phase = last_completed_phase_
+ ? static_cast<Phase>(
+ static_cast<unsigned>(*last_completed_phase_) + 1)
+ : Phase::kFirst;
+ // Check if any future phase needs updates.
+ for (auto phase = static_cast<unsigned>(next_phase);
+ phase <= static_cast<unsigned>(Phase::kLast); ++phase) {
+ if (IsElementDirtyForPhase(static_cast<Phase>(phase)))
+ return true;
+ }
+ return false;
+}
+
+double YieldingDisplayLockBudget::GetCurrentBudgetMs() const {
+ if (TimeTicks::IsHighResolution()) {
+ if (lifecycle_count_ < 3)
+ return 4.;
+ if (lifecycle_count_ < 10)
+ return 8.;
+ if (lifecycle_count_ < 60)
+ return 16.;
+ } else {
+ // Without a high resolution clock, the resolution can be as bad as 15ms, so
+ // increase the budgets accordingly to ensure we don't abort before doing
+ // any phases.
+ if (lifecycle_count_ < 60)
+ return 16.;
+ }
+ return 1e9;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h b/chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h
new file mode 100644
index 00000000000..41a7d18f67d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_YIELDING_DISPLAY_LOCK_BUDGET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_YIELDING_DISPLAY_LOCK_BUDGET_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
+
+namespace blink {
+
+// This budget yields between lifecycle phases even if that phase is quick. In
+// other words, it will only do one new lifecycle phase at a time, and block the
+// future ones. Any lifecycle phases that have already been allowed by this
+// budget in the past are not blocked.
+class CORE_EXPORT YieldingDisplayLockBudget final : public DisplayLockBudget {
+ public:
+ YieldingDisplayLockBudget(DisplayLockContext*);
+ ~YieldingDisplayLockBudget() override = default;
+
+ bool ShouldPerformPhase(Phase) const override;
+ void DidPerformPhase(Phase) override;
+ void WillStartLifecycleUpdate() override;
+ // Returns true if any of the lifecycles that have been previously blocked by
+ // this budget need updates. Note that this does not check lifecycle phases
+ // that have already completed by this budget even if they are now dirty
+ // again. This is done to prevent starvation (ie, it is possible for the
+ // budget to always schedule more work if something in rAF keeps dirtying
+ // layout, for example).
+ bool NeedsLifecycleUpdates() const override;
+
+ protected:
+ friend class DisplayLockBudgetTest;
+
+ double GetCurrentBudgetMs() const;
+
+ int lifecycle_count_ = 0;
+ TimeTicks deadline_;
+ base::Optional<Phase> last_completed_phase_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_YIELDING_DISPLAY_LOCK_BUDGET_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/BUILD.gn b/chromium/third_party/blink/renderer/core/dom/BUILD.gn
index b9b40b4a345..07e459ecbe1 100644
--- a/chromium/third_party/blink/renderer/core/dom/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/dom/BUILD.gn
@@ -126,6 +126,7 @@ blink_core_sources("dom") {
"events/event_target.h",
"events/event_target_impl.cc",
"events/event_target_impl.h",
+ "events/native_event_listener.h",
"events/node_event_context.cc",
"events/node_event_context.h",
"events/registered_event_listener.cc",
@@ -143,6 +144,7 @@ blink_core_sources("dom") {
"flat_tree_node_data.h",
"flat_tree_traversal.cc",
"flat_tree_traversal.h",
+ "flat_tree_traversal_forbidden_scope.h",
"frame_request_callback_collection.cc",
"frame_request_callback_collection.h",
"global_event_handlers.h",
@@ -206,8 +208,6 @@ blink_core_sources("dom") {
"nth_index_cache.h",
"parent_node.h",
"parser_content_policy.h",
- "pausable_object.cc",
- "pausable_object.h",
"presentation_attribute_style.cc",
"presentation_attribute_style.h",
"processing_instruction.cc",
diff --git a/chromium/third_party/blink/renderer/core/dom/abort_controller.cc b/chromium/third_party/blink/renderer/core/dom/abort_controller.cc
index f912925ab81..3ffb73aa65b 100644
--- a/chromium/third_party/blink/renderer/core/dom/abort_controller.cc
+++ b/chromium/third_party/blink/renderer/core/dom/abort_controller.cc
@@ -10,11 +10,11 @@
namespace blink {
AbortController* AbortController::Create(ExecutionContext* context) {
- return new AbortController(context);
+ return MakeGarbageCollected<AbortController>(context);
}
AbortController::AbortController(ExecutionContext* execution_context)
- : signal_(new AbortSignal(execution_context)) {}
+ : signal_(MakeGarbageCollected<AbortSignal>(execution_context)) {}
AbortController::~AbortController() = default;
diff --git a/chromium/third_party/blink/renderer/core/dom/abort_controller.h b/chromium/third_party/blink/renderer/core/dom/abort_controller.h
index 1cbd6845aba..7381decb45e 100644
--- a/chromium/third_party/blink/renderer/core/dom/abort_controller.h
+++ b/chromium/third_party/blink/renderer/core/dom/abort_controller.h
@@ -21,6 +21,8 @@ class AbortController final : public ScriptWrappable {
public:
static AbortController* Create(ExecutionContext*);
+
+ explicit AbortController(ExecutionContext*);
~AbortController() override;
// abort_controller.idl
@@ -34,8 +36,6 @@ class AbortController final : public ScriptWrappable {
void Trace(Visitor*) override;
private:
- explicit AbortController(ExecutionContext*);
-
Member<AbortSignal> signal_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl b/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl
index 199a90acffa..3d6d7c81573 100644
--- a/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl
+++ b/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl
@@ -20,10 +20,13 @@
[CEReactions, Reflect=aria_current] attribute DOMString? ariaCurrent;
[CEReactions, Reflect=aria_describedby] attribute DOMString? ariaDescribedBy;
[CEReactions, Reflect=aria_details] attribute DOMString? ariaDetails;
- [CEReactions, Reflect=aria_errormessage] attribute DOMString? ariaDisabled;
- [CEReactions, Reflect=aria_flowto] attribute DOMString? ariaExpanded;
+ [CEReactions, Reflect=aria_disabled] attribute DOMString? ariaDisabled;
+ [CEReactions, Reflect=aria_errormessage] attribute DOMString? ariaErrorMessage;
+ [CEReactions, Reflect=aria_expanded] attribute DOMString? ariaExpanded;
+ [CEReactions, Reflect=aria_flowto] attribute DOMString? ariaFlowTo;
[CEReactions, Reflect=aria_haspopup] attribute DOMString? ariaHasPopup;
- [CEReactions, Reflect=aria_keyshortcuts] attribute DOMString? ariaHidden;
+ [CEReactions, Reflect=aria_hidden] attribute DOMString? ariaHidden;
+ [CEReactions, Reflect=aria_keyshortcuts] attribute DOMString? ariaKeyShortcuts;
[CEReactions, Reflect=aria_label] attribute DOMString? ariaLabel;
[CEReactions, Reflect=aria_labelledby] attribute DOMString? ariaLabelledBy;
[CEReactions, Reflect=aria_level] attribute DOMString? ariaLevel;
diff --git a/chromium/third_party/blink/renderer/core/dom/attr.cc b/chromium/third_party/blink/renderer/core/dom/attr.cc
index 392a07f3fbc..2fd0e8e8ece 100644
--- a/chromium/third_party/blink/renderer/core/dom/attr.cc
+++ b/chromium/third_party/blink/renderer/core/dom/attr.cc
@@ -47,13 +47,13 @@ Attr::Attr(Document& document,
standalone_value_or_attached_local_name_(standalone_value) {}
Attr* Attr::Create(Element& element, const QualifiedName& name) {
- return new Attr(element, name);
+ return MakeGarbageCollected<Attr>(element, name);
}
Attr* Attr::Create(Document& document,
const QualifiedName& name,
const AtomicString& value) {
- return new Attr(document, name, value);
+ return MakeGarbageCollected<Attr>(document, name, value);
}
Attr::~Attr() = default;
@@ -94,7 +94,7 @@ void Attr::setNodeValue(const String& v) {
}
Node* Attr::Clone(Document& factory, CloneChildrenFlag) const {
- return new Attr(factory, name_, value());
+ return MakeGarbageCollected<Attr>(factory, name_, value());
}
void Attr::DetachFromElementWithValue(const AtomicString& value) {
@@ -110,7 +110,7 @@ void Attr::AttachToElement(Element* element,
standalone_value_or_attached_local_name_ = attached_local_name;
}
-void Attr::Trace(blink::Visitor* visitor) {
+void Attr::Trace(Visitor* visitor) {
visitor->Trace(element_);
Node::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/attr.h b/chromium/third_party/blink/renderer/core/dom/attr.h
index cf12ab1b088..d56a049aa08 100644
--- a/chromium/third_party/blink/renderer/core/dom/attr.h
+++ b/chromium/third_party/blink/renderer/core/dom/attr.h
@@ -41,6 +41,9 @@ class CORE_EXPORT Attr final : public Node {
static Attr* Create(Document&,
const QualifiedName&,
const AtomicString& value);
+
+ Attr(Element&, const QualifiedName&);
+ Attr(Document&, const QualifiedName&, const AtomicString& value);
~Attr() override;
String name() const { return name_.ToString(); }
@@ -59,12 +62,9 @@ class CORE_EXPORT Attr final : public Node {
const AtomicString& namespaceURI() const { return name_.NamespaceURI(); }
const AtomicString& prefix() const { return name_.Prefix(); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- Attr(Element&, const QualifiedName&);
- Attr(Document&, const QualifiedName&, const AtomicString& value);
-
bool IsElementNode() const =
delete; // This will catch anyone doing an unnecessary check.
diff --git a/chromium/third_party/blink/renderer/core/dom/attr_test.cc b/chromium/third_party/blink/renderer/core/dom/attr_test.cc
index 95e33710977..657c44602bb 100644
--- a/chromium/third_party/blink/renderer/core/dom/attr_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/attr_test.cc
@@ -33,32 +33,36 @@ Attr* AttrTest::CreateAttribute() {
TEST_F(AttrTest, InitialValueState) {
Attr* attr = CreateAttribute();
+ Node* node = attr;
EXPECT_EQ(g_empty_atom, attr->value());
- EXPECT_EQ(g_empty_string, attr->ToNode()->nodeValue());
+ EXPECT_EQ(g_empty_string, node->nodeValue());
EXPECT_EQ(g_empty_string, attr->textContent());
}
TEST_F(AttrTest, SetValue) {
Attr* attr = CreateAttribute();
+ Node* node = attr;
attr->setValue(Value());
EXPECT_EQ(Value(), attr->value());
- EXPECT_EQ(Value(), attr->ToNode()->nodeValue());
+ EXPECT_EQ(Value(), node->nodeValue());
EXPECT_EQ(Value(), attr->textContent());
}
TEST_F(AttrTest, SetNodeValue) {
Attr* attr = CreateAttribute();
- attr->ToNode()->setNodeValue(Value());
+ Node* node = attr;
+ node->setNodeValue(Value());
EXPECT_EQ(Value(), attr->value());
- EXPECT_EQ(Value(), attr->ToNode()->nodeValue());
+ EXPECT_EQ(Value(), node->nodeValue());
EXPECT_EQ(Value(), attr->textContent());
}
TEST_F(AttrTest, SetTextContent) {
Attr* attr = CreateAttribute();
+ Node* node = attr;
attr->setTextContent(Value());
EXPECT_EQ(Value(), attr->value());
- EXPECT_EQ(Value(), attr->ToNode()->nodeValue());
+ EXPECT_EQ(Value(), node->nodeValue());
EXPECT_EQ(Value(), attr->textContent());
}
diff --git a/chromium/third_party/blink/renderer/core/dom/cdata_section.cc b/chromium/third_party/blink/renderer/core/dom/cdata_section.cc
index fd0982d976a..200272af471 100644
--- a/chromium/third_party/blink/renderer/core/dom/cdata_section.cc
+++ b/chromium/third_party/blink/renderer/core/dom/cdata_section.cc
@@ -29,7 +29,7 @@ inline CDATASection::CDATASection(Document& document, const String& data)
: Text(document, data, kCreateText) {}
CDATASection* CDATASection::Create(Document& document, const String& data) {
- return new CDATASection(document, data);
+ return MakeGarbageCollected<CDATASection>(document, data);
}
String CDATASection::nodeName() const {
diff --git a/chromium/third_party/blink/renderer/core/dom/cdata_section.h b/chromium/third_party/blink/renderer/core/dom/cdata_section.h
index c665e30f1cc..2ed11b2ae64 100644
--- a/chromium/third_party/blink/renderer/core/dom/cdata_section.h
+++ b/chromium/third_party/blink/renderer/core/dom/cdata_section.h
@@ -33,9 +33,9 @@ class CDATASection final : public Text {
public:
static CDATASection* Create(Document&, const String&);
- private:
CDATASection(Document&, const String&);
+ private:
String nodeName() const override;
NodeType getNodeType() const override;
Text* CloneWithData(Document&, const String&) const override;
diff --git a/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc b/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
index f377fc47895..7d9f0ae3893 100644
--- a/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
+++ b/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
@@ -76,7 +76,7 @@ ChildListMutationAccumulator* ChildListMutationAccumulator::GetOrCreate(
if (!result.is_new_entry) {
accumulator = result.stored_value->value;
} else {
- accumulator = new ChildListMutationAccumulator(
+ accumulator = MakeGarbageCollected<ChildListMutationAccumulator>(
&target,
MutationObserverInterestGroup::CreateForChildListMutation(target));
result.stored_value->value = accumulator;
@@ -151,7 +151,7 @@ bool ChildListMutationAccumulator::IsEmpty() {
return result;
}
-void ChildListMutationAccumulator::Trace(blink::Visitor* visitor) {
+void ChildListMutationAccumulator::Trace(Visitor* visitor) {
visitor->Trace(target_);
visitor->Trace(removed_nodes_);
visitor->Trace(added_nodes_);
diff --git a/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.h b/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.h
index 2cc10f33603..62cd18ac1e4 100644
--- a/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.h
+++ b/chromium/third_party/blink/renderer/core/dom/child_list_mutation_scope.h
@@ -54,6 +54,8 @@ class ChildListMutationAccumulator final
public:
static ChildListMutationAccumulator* GetOrCreate(Node&);
+ ChildListMutationAccumulator(Node*, MutationObserverInterestGroup*);
+
void ChildAdded(Node*);
void WillRemoveChild(Node*);
@@ -64,11 +66,9 @@ class ChildListMutationAccumulator final
void EnterMutationScope() { mutation_scopes_++; }
void LeaveMutationScope();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
- ChildListMutationAccumulator(Node*, MutationObserverInterestGroup*);
-
void EnqueueMutationRecord();
bool IsEmpty();
bool IsAddedNodeInOrder(Node*);
diff --git a/chromium/third_party/blink/renderer/core/dom/child_node_list.cc b/chromium/third_party/blink/renderer/core/dom/child_node_list.cc
index e93469872fa..457df191759 100644
--- a/chromium/third_party/blink/renderer/core/dom/child_node_list.cc
+++ b/chromium/third_party/blink/renderer/core/dom/child_node_list.cc
@@ -83,7 +83,7 @@ Node* ChildNodeList::TraverseBackwardToOffset(unsigned offset,
return nullptr;
}
-void ChildNodeList::Trace(blink::Visitor* visitor) {
+void ChildNodeList::Trace(Visitor* visitor) {
visitor->Trace(parent_);
visitor->Trace(collection_index_cache_);
NodeList::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/dom/child_node_list.h b/chromium/third_party/blink/renderer/core/dom/child_node_list.h
index 6c9ebb912cd..9a5256903b7 100644
--- a/chromium/third_party/blink/renderer/core/dom/child_node_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/child_node_list.h
@@ -34,9 +34,10 @@ namespace blink {
class ChildNodeList final : public NodeList {
public:
static ChildNodeList* Create(ContainerNode& root_node) {
- return new ChildNodeList(root_node);
+ return MakeGarbageCollected<ChildNodeList>(root_node);
}
+ explicit ChildNodeList(ContainerNode& root_node);
~ChildNodeList() override;
// DOM API.
@@ -63,11 +64,9 @@ class ChildNodeList final : public NodeList {
Node& current_node,
unsigned& current_offset) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- explicit ChildNodeList(ContainerNode& root_node);
-
bool IsChildNodeList() const override { return true; }
Node* VirtualOwnerNode() const override;
diff --git a/chromium/third_party/blink/renderer/core/dom/class_collection.h b/chromium/third_party/blink/renderer/core/dom/class_collection.h
index b4c7d6bc143..b0b27e233db 100644
--- a/chromium/third_party/blink/renderer/core/dom/class_collection.h
+++ b/chromium/third_party/blink/renderer/core/dom/class_collection.h
@@ -46,16 +46,15 @@ class ClassCollection final : public HTMLCollection {
CollectionType type,
const AtomicString& class_names) {
DCHECK_EQ(type, kClassCollectionType);
- return new ClassCollection(root_node, class_names);
+ return MakeGarbageCollected<ClassCollection>(root_node, class_names);
}
+ ClassCollection(ContainerNode& root_node, const AtomicString& class_names);
~ClassCollection() override;
bool ElementMatches(const Element&) const;
private:
- ClassCollection(ContainerNode& root_node, const AtomicString& class_names);
-
SpaceSplitString class_names_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/collection_index_cache.h b/chromium/third_party/blink/renderer/core/dom/collection_index_cache.h
index 7572bea8c29..caf4bf7b3c1 100644
--- a/chromium/third_party/blink/renderer/core/dom/collection_index_cache.h
+++ b/chromium/third_party/blink/renderer/core/dom/collection_index_cache.h
@@ -66,7 +66,7 @@ class CollectionIndexCache {
void NodeInserted();
void NodeRemoved();
- virtual void Trace(blink::Visitor* visitor) { visitor->Trace(current_node_); }
+ virtual void Trace(Visitor* visitor) { visitor->Trace(current_node_); }
protected:
ALWAYS_INLINE NodeType* CachedNode() const { return current_node_; }
diff --git a/chromium/third_party/blink/renderer/core/dom/comment.cc b/chromium/third_party/blink/renderer/core/dom/comment.cc
index 79b47423352..d7476d197b8 100644
--- a/chromium/third_party/blink/renderer/core/dom/comment.cc
+++ b/chromium/third_party/blink/renderer/core/dom/comment.cc
@@ -29,7 +29,7 @@ inline Comment::Comment(Document& document, const String& text)
: CharacterData(document, text, kCreateOther) {}
Comment* Comment::Create(Document& document, const String& text) {
- return new Comment(document, text);
+ return MakeGarbageCollected<Comment>(document, text);
}
String Comment::nodeName() const {
diff --git a/chromium/third_party/blink/renderer/core/dom/comment.h b/chromium/third_party/blink/renderer/core/dom/comment.h
index 5b1579ba869..b8d1d7b44d4 100644
--- a/chromium/third_party/blink/renderer/core/dom/comment.h
+++ b/chromium/third_party/blink/renderer/core/dom/comment.h
@@ -33,9 +33,9 @@ class CORE_EXPORT Comment final : public CharacterData {
public:
static Comment* Create(Document&, const String&);
- private:
Comment(Document&, const String&);
+ private:
String nodeName() const override;
NodeType getNodeType() const override;
Node* Clone(Document&, CloneChildrenFlag) const override;
diff --git a/chromium/third_party/blink/renderer/core/dom/container_node.cc b/chromium/third_party/blink/renderer/core/dom/container_node.cc
index cce4bc210c6..59467cf7652 100644
--- a/chromium/third_party/blink/renderer/core/dom/container_node.cc
+++ b/chromium/third_party/blink/renderer/core/dom/container_node.cc
@@ -651,7 +651,7 @@ void ContainerNode::WillRemoveChildren() {
ChildFrameDisconnector::kDescendantsOnly);
}
-void ContainerNode::Trace(blink::Visitor* visitor) {
+void ContainerNode::Trace(Visitor* visitor) {
visitor->Trace(first_child_);
visitor->Trace(last_child_);
Node::Trace(visitor);
@@ -673,7 +673,7 @@ Node* ContainerNode::RemoveChild(Node* old_child,
Node* child = old_child;
- GetDocument().RemoveFocusedElementOfSubtree(child);
+ GetDocument().RemoveFocusedElementOfSubtree(*child);
// Events fired when blurring currently focused node might have moved this
// child into a different parent.
@@ -793,7 +793,7 @@ void ContainerNode::RemoveChildren(SubtreeModificationAction action) {
// children will be removed.
// This must be later than willRemoveChildren, which might change focus
// state of a child.
- GetDocument().RemoveFocusedElementOfSubtree(this, true);
+ GetDocument().RemoveFocusedElementOfSubtree(*this, true);
// Removing a node from a selection can cause widget updates.
GetDocument().NodeChildrenWillBeRemoved(*this);
@@ -1402,7 +1402,8 @@ void ContainerNode::SetRestyleFlag(DynamicRestyleFlags mask) {
EnsureRareData().SetRestyleFlag(mask);
}
-void ContainerNode::RecalcDescendantStyles(StyleRecalcChange change) {
+void ContainerNode::RecalcDescendantStyles(StyleRecalcChange change,
+ bool calc_invisible) {
DCHECK(GetDocument().InStyleRecalc());
DCHECK(change >= kUpdatePseudoElements || ChildNeedsStyleRecalc());
DCHECK(!NeedsStyleRecalc());
@@ -1413,7 +1414,7 @@ void ContainerNode::RecalcDescendantStyles(StyleRecalcChange change) {
} else if (child->IsElementNode()) {
Element* element = ToElement(child);
if (element->ShouldCallRecalcStyle(change))
- element->RecalcStyle(change);
+ element->RecalcStyle(change, calc_invisible);
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/dom/container_node.h b/chromium/third_party/blink/renderer/core/dom/container_node.h
index afb12644d32..6e219660654 100644
--- a/chromium/third_party/blink/renderer/core/dom/container_node.h
+++ b/chromium/third_party/blink/renderer/core/dom/container_node.h
@@ -289,7 +289,7 @@ class CORE_EXPORT ContainerNode : public Node {
Element* changed_element,
Node* node_before_change,
Node* node_after_change);
- void RecalcDescendantStyles(StyleRecalcChange);
+ void RecalcDescendantStyles(StyleRecalcChange, bool calc_invisible = false);
void RebuildChildrenLayoutTrees(WhitespaceAttacher&);
void RebuildLayoutTreeForChild(Node* child, WhitespaceAttacher&);
void RebuildNonDistributedChildren();
@@ -365,7 +365,9 @@ class CORE_EXPORT ContainerNode : public Node {
// CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
virtual void ChildrenChanged(const ChildrenChange&);
- void Trace(blink::Visitor*) override;
+ virtual bool ChildrenCanHaveStyle() const { return true; }
+
+ void Trace(Visitor*) override;
protected:
ContainerNode(TreeScope*, ConstructionType = kCreateContainer);
diff --git a/chromium/third_party/blink/renderer/core/dom/context_features.h b/chromium/third_party/blink/renderer/core/dom/context_features.h
index bf995fb1104..b9a534bba0f 100644
--- a/chromium/third_party/blink/renderer/core/dom/context_features.h
+++ b/chromium/third_party/blink/renderer/core/dom/context_features.h
@@ -57,13 +57,13 @@ class ContextFeatures final : public GarbageCollectedFinalized<ContextFeatures>,
static bool PagePopupEnabled(Document*);
static bool MutationEventsEnabled(Document*);
+ explicit ContextFeatures(std::unique_ptr<ContextFeaturesClient> client)
+ : client_(std::move(client)) {}
+
bool IsEnabled(Document*, FeatureType, bool) const;
void UrlDidChange(Document*);
private:
- explicit ContextFeatures(std::unique_ptr<ContextFeaturesClient> client)
- : client_(std::move(client)) {}
-
std::unique_ptr<ContextFeaturesClient> client_;
};
@@ -89,7 +89,7 @@ void ProvideContextFeaturesToDocumentFrom(Document&, Page&);
inline ContextFeatures* ContextFeatures::Create(
std::unique_ptr<ContextFeaturesClient> client) {
- return new ContextFeatures(std::move(client));
+ return MakeGarbageCollected<ContextFeatures>(std::move(client));
}
inline bool ContextFeatures::IsEnabled(Document* document,
diff --git a/chromium/third_party/blink/renderer/core/dom/context_features_client_impl.cc b/chromium/third_party/blink/renderer/core/dom/context_features_client_impl.cc
index 69f26b6058b..ce95f2303b8 100644
--- a/chromium/third_party/blink/renderer/core/dom/context_features_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/dom/context_features_client_impl.cc
@@ -73,6 +73,9 @@ class ContextFeaturesCache final
static ContextFeaturesCache& From(Document&);
+ explicit ContextFeaturesCache(Document& document)
+ : Supplement<Document>(document) {}
+
Entry& EntryFor(ContextFeatures::FeatureType type) {
size_t index = static_cast<size_t>(type);
SECURITY_DCHECK(index < ContextFeatures::kFeatureTypeSize);
@@ -81,14 +84,11 @@ class ContextFeaturesCache final
void ValidateAgainst(Document*);
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
Supplement<Document>::Trace(visitor);
}
private:
- explicit ContextFeaturesCache(Document& document)
- : Supplement<Document>(document) {}
-
String domain_;
Entry entries_[ContextFeatures::kFeatureTypeSize];
};
@@ -99,7 +99,7 @@ ContextFeaturesCache& ContextFeaturesCache::From(Document& document) {
ContextFeaturesCache* cache =
Supplement<Document>::From<ContextFeaturesCache>(document);
if (!cache) {
- cache = new ContextFeaturesCache(document);
+ cache = MakeGarbageCollected<ContextFeaturesCache>(document);
ProvideTo(document, cache);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.cc b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.cc
index 1e755ea7e6f..6881ef503a4 100644
--- a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.cc
+++ b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.cc
@@ -28,7 +28,7 @@
#include "third_party/blink/renderer/core/dom/context_lifecycle_notifier.h"
#include "base/auto_reset.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
namespace blink {
@@ -42,11 +42,12 @@ void ContextLifecycleNotifier::NotifyResumingPausableObjects() {
DCHECK_EQ(pausable_object->GetExecutionContext(), Context());
DCHECK(pausable_object->PauseIfNeededCalled());
#endif
- pausable_object->Unpause();
+ pausable_object->ContextUnpaused();
});
}
-void ContextLifecycleNotifier::NotifySuspendingPausableObjects() {
+void ContextLifecycleNotifier::NotifySuspendingPausableObjects(
+ PauseState state) {
ForEachObserver([&](ContextLifecycleObserver* observer) {
if (observer->ObserverType() !=
ContextLifecycleObserver::kPausableObjectType)
@@ -56,7 +57,7 @@ void ContextLifecycleNotifier::NotifySuspendingPausableObjects() {
DCHECK_EQ(pausable_object->GetExecutionContext(), Context());
DCHECK(pausable_object->PauseIfNeededCalled());
#endif
- pausable_object->Pause();
+ pausable_object->ContextPaused(state);
});
}
diff --git a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.h b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.h
index a7895c68719..c8aa17b7724 100644
--- a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.h
+++ b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_notifier.h
@@ -30,6 +30,7 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/pause_state.h"
#include "third_party/blink/renderer/platform/lifecycle_notifier.h"
namespace blink {
@@ -42,7 +43,7 @@ class CORE_EXPORT ContextLifecycleNotifier
: public LifecycleNotifier<ExecutionContext, ContextLifecycleObserver> {
public:
void NotifyResumingPausableObjects();
- void NotifySuspendingPausableObjects();
+ void NotifySuspendingPausableObjects(PauseState state);
unsigned PausableObjectCount() const;
diff --git a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc
index 74d061613a3..4df3f8a4ba9 100644
--- a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc
+++ b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc
@@ -22,12 +22,19 @@ ExecutionContext* ContextClient::GetExecutionContext() const {
: nullptr;
}
+Document* ContextClient::GetDocument() const {
+ return execution_context_
+ ? DynamicTo<Document>(
+ static_cast<ExecutionContext*>(execution_context_))
+ : nullptr;
+}
+
LocalFrame* ContextClient::GetFrame() const {
- auto* document = DynamicTo<Document>(GetExecutionContext());
+ auto* document = GetDocument();
return document ? document->GetFrame() : nullptr;
}
-void ContextClient::Trace(blink::Visitor* visitor) {
+void ContextClient::Trace(Visitor* visitor) {
visitor->Trace(execution_context_);
}
@@ -50,7 +57,7 @@ LocalFrame* DOMWindowClient::GetFrame() const {
return dom_window_ ? dom_window_->GetFrame() : nullptr;
}
-void DOMWindowClient::Trace(blink::Visitor* visitor) {
+void DOMWindowClient::Trace(Visitor* visitor) {
visitor->Trace(dom_window_);
}
}
diff --git a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.h b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.h
index bbba1d3aa9b..c8648ad6df1 100644
--- a/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.h
+++ b/chromium/third_party/blink/renderer/core/dom/context_lifecycle_observer.h
@@ -33,6 +33,7 @@
namespace blink {
+class Document;
class LocalDOMWindow;
class LocalFrame;
@@ -67,11 +68,14 @@ class CORE_EXPORT ContextClient : public GarbageCollectedMixin {
// From then on, returns null instead.
ExecutionContext* GetExecutionContext() const;
+ // Return a live document if associated with it. Returns null otherwise.
+ Document* GetDocument() const;
+
// If associated with a live document, returns the associated frame.
// Returns null otherwise.
LocalFrame* GetFrame() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
explicit ContextClient(ExecutionContext*);
@@ -151,7 +155,7 @@ class CORE_EXPORT DOMWindowClient : public GarbageCollectedMixin {
LocalDOMWindow* DomWindow() const;
LocalFrame* GetFrame() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
explicit DOMWindowClient(LocalDOMWindow*);
diff --git a/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc b/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc
index 0a18a0a6e08..5a368399d2d 100644
--- a/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc
+++ b/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc
@@ -200,7 +200,7 @@ bool DatasetDOMStringMap::DeleteItem(const String& name) {
return false;
}
-void DatasetDOMStringMap::Trace(blink::Visitor* visitor) {
+void DatasetDOMStringMap::Trace(Visitor* visitor) {
visitor->Trace(element_);
DOMStringMap::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.h b/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.h
index 998d8f7a1bb..e3d457b11ee 100644
--- a/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/dataset_dom_string_map.h
@@ -49,7 +49,7 @@ class DatasetDOMStringMap final : public DOMStringMap {
ExceptionState&) override;
bool DeleteItem(const String& name) override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<Element> element_;
diff --git a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc b/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc
index 9ef449dc262..8b7f4478414 100644
--- a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc
+++ b/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc
@@ -66,7 +66,7 @@ Node* DistributedNodes::PreviousTo(const Node* node) const {
return at(index - 1);
}
-void DistributedNodes::Trace(blink::Visitor* visitor) {
+void DistributedNodes::Trace(Visitor* visitor) {
visitor->Trace(nodes_);
visitor->Trace(indices_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h b/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h
index 003bcbc5e88..265dd6e67b3 100644
--- a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h
+++ b/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h
@@ -64,7 +64,7 @@ class DistributedNodes final {
void Swap(DistributedNodes& other);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
HeapVector<Member<Node>> nodes_;
diff --git a/chromium/third_party/blink/renderer/core/dom/document.cc b/chromium/third_party/blink/renderer/core/dom/document.cc
index ca5e41dc1be..e5d02bd5288 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document.cc
@@ -32,15 +32,16 @@
#include <memory>
#include "base/auto_reset.h"
+#include "base/macros.h"
#include "base/optional.h"
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/metrics/public/mojom/ukm_interface.mojom-shared.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/interface_provider.h"
#include "third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
@@ -49,8 +50,8 @@
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_prerendering_support.h"
#include "third_party/blink/renderer/bindings/core/v8/html_script_element_or_svg_script_element.h"
+#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_element_creation_options.h"
@@ -68,7 +69,6 @@
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_style_declaration.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
-#include "third_party/blink/renderer/core/css/css_style_sheet_init.h"
#include "third_party/blink/renderer/core/css/cssom/computed_style_property_map.h"
#include "third_party/blink/renderer/core/css/font_face_set_document.h"
#include "third_party/blink/renderer/core/css/invalidation/style_invalidator.h"
@@ -134,6 +134,7 @@
#include "third_party/blink/renderer/core/events/before_unload_event.h"
#include "third_party/blink/renderer/core/events/event_factory.h"
#include "third_party/blink/renderer/core/events/hash_change_event.h"
+#include "third_party/blink/renderer/core/events/overscroll_event.h"
#include "third_party/blink/renderer/core/events/page_transition_event.h"
#include "third_party/blink/renderer/core/events/visual_viewport_resize_event.h"
#include "third_party/blink/renderer/core/events/visual_viewport_scroll_event.h"
@@ -220,6 +221,7 @@
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
#include "third_party/blink/renderer/core/loader/navigation_scheduler.h"
#include "third_party/blink/renderer/core/loader/prerenderer_client.h"
+#include "third_party/blink/renderer/core/loader/progress_tracker.h"
#include "third_party/blink/renderer/core/loader/text_resource_decoder_builder.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -253,7 +255,6 @@
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
-#include "third_party/blink/renderer/core/workers/shared_worker_repository_client.h"
#include "third_party/blink/renderer/core/xml/parser/xml_document_parser.h"
#include "third_party/blink/renderer/core/xml_names.h"
#include "third_party/blink/renderer/core/xmlns_names.h"
@@ -269,8 +270,10 @@
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/instance_counters.h"
+#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/language.h"
+#include "third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -573,7 +576,7 @@ class Document::NetworkStateObserver final
online_observer_handle_ = nullptr;
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
ContextLifecycleObserver::Trace(visitor);
}
@@ -655,7 +658,7 @@ Document::Document(const DocumentInit& initializer,
document_classes_(document_classes),
is_view_source_(false),
saw_elements_in_known_namespaces_(false),
- is_srcdoc_document_(initializer.ShouldTreatURLAsSrcdocDocument()),
+ is_srcdoc_document_(initializer.IsSrcdocDocument()),
is_mobile_document_(false),
layout_view_(nullptr),
has_fullscreen_supplement_(false),
@@ -687,7 +690,6 @@ Document::Document(const DocumentInit& initializer,
has_viewport_units_(false),
parser_sync_policy_(kAllowAsynchronousParsing),
node_count_(0),
- password_count_(0),
logged_field_edit_(false),
secure_context_state_(SecureContextState::kUnknown),
ukm_source_id_(ukm::UkmRecorder::GetNewSourceID()),
@@ -698,13 +700,21 @@ Document::Document(const DocumentInit& initializer,
viewport_data_(MakeGarbageCollected<ViewportData>(*this)),
agent_cluster_id_(base::UnguessableToken::Create()),
parsed_feature_policies_(
- static_cast<int>(mojom::FeaturePolicyFeature::kMaxValue) + 1) {
+ static_cast<int>(mojom::FeaturePolicyFeature::kMaxValue) + 1),
+ potentially_violated_features_(
+ static_cast<size_t>(mojom::FeaturePolicyFeature::kMaxValue) + 1U),
+ isolated_world_csp_map_(
+ MakeGarbageCollected<
+ HeapHashMap<int, Member<ContentSecurityPolicy>>>()) {
if (frame_) {
DCHECK(frame_->GetPage());
ProvideContextFeaturesToDocumentFrom(*this, *frame_->GetPage());
fetcher_ = frame_->Loader().GetDocumentLoader()->Fetcher();
- FrameFetchContext::ProvideDocumentToContext(fetcher_->Context(), this);
+ frame_->Loader()
+ .GetDocumentLoader()
+ ->ProvideDocumentToResourceFetcherProperties(*this);
+ fetcher_->SetConsoleLogger(this);
// TODO(dcheng): Why does this need to check that DOMWindow is non-null?
CustomElementRegistry* registry =
@@ -713,9 +723,11 @@ Document::Document(const DocumentInit& initializer,
if (registry && registration_context_)
registry->Entangle(registration_context_);
} else if (imports_controller_) {
- fetcher_ = FrameFetchContext::CreateFetcherFromDocument(this);
+ fetcher_ = FrameFetchContext::CreateFetcherForImportedDocument(this);
} else {
- fetcher_ = ResourceFetcher::Create(nullptr);
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *MakeGarbageCollected<NullResourceFetcherProperties>(),
+ &FetchContext::NullInstance(), GetTaskRunner(TaskType::kNetworking)));
}
DCHECK(fetcher_);
@@ -745,8 +757,8 @@ Document::Document(const DocumentInit& initializer,
lifecycle_.AdvanceTo(DocumentLifecycle::kInactive);
// Since CSSFontSelector requires Document::fetcher_ and StyleEngine owns
- // CSSFontSelector, need to initialize style_engine_ after initializing
- // fetcher_.
+ // CSSFontSelector, need to initialize |style_engine_| after initializing
+ // |fetcher_|.
style_engine_ = StyleEngine::Create(*this);
// The parent's parser should be suspended together with all the other
@@ -853,6 +865,34 @@ bool Document::ShouldInstallV8Extensions() const {
return frame_->Client()->AllowScriptExtensions();
}
+ContentSecurityPolicy* Document::GetContentSecurityPolicyForWorld() {
+ v8::Isolate* isolate = GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Context> v8_context = isolate->GetCurrentContext();
+
+ // This can be called before we enter v8, hence the context might be empty,
+ // which implies we are not in an isolated world.
+ if (v8_context.IsEmpty())
+ return GetContentSecurityPolicy();
+
+ DOMWrapperWorld& world = DOMWrapperWorld::Current(isolate);
+ if (!world.IsIsolatedWorld())
+ return GetContentSecurityPolicy();
+
+ int world_id = world.GetWorldId();
+ auto it = isolated_world_csp_map_->find(world_id);
+ if (it != isolated_world_csp_map_->end())
+ return it->value;
+
+ ContentSecurityPolicy* policy =
+ IsolatedWorldCSP::Get().CreateIsolatedWorldCSP(*this, world_id);
+ if (!policy)
+ return GetContentSecurityPolicy();
+
+ isolated_world_csp_map_->insert(world_id, policy);
+ return policy;
+}
+
void Document::ChildrenChanged(const ChildrenChange& change) {
ContainerNode::ChildrenChanged(change);
document_element_ = ElementTraversal::FirstWithin(*this);
@@ -1126,63 +1166,6 @@ Element* Document::CreateElement(const QualifiedName& q_name,
flags, is);
}
-ScriptPromise Document::createCSSStyleSheet(ScriptState* script_state,
- const String& text,
- ExceptionState& exception_state) {
- return Document::createCSSStyleSheet(
- script_state, text, CSSStyleSheetInit::Create(), exception_state);
-}
-
-ScriptPromise Document::createCSSStyleSheet(ScriptState* script_state,
- const String& text,
- const CSSStyleSheetInit* options,
- ExceptionState& exception_state) {
- // Even though this function returns a Promise, it actually does all the work
- // at once here because CSS parsing is done synchronously on the main thread.
- // TODO(rakina): Find a way to improve this.
- CSSStyleSheet* sheet = CSSStyleSheet::Create(*this, options, exception_state);
- sheet->SetText(text, true /* allow_import_rules */, exception_state);
- sheet->SetAssociatedDocument(this);
- return ScriptPromise::Cast(script_state, ToV8(sheet, script_state));
-}
-
-CSSStyleSheet* Document::createCSSStyleSheetSync(
- ScriptState* script_state,
- const String& text,
- ExceptionState& exception_state) {
- return Document::createCSSStyleSheetSync(
- script_state, text, CSSStyleSheetInit::Create(), exception_state);
-}
-
-CSSStyleSheet* Document::createCSSStyleSheetSync(
- ScriptState* script_state,
- const String& text,
- const CSSStyleSheetInit* options,
- ExceptionState& exception_state) {
- CSSStyleSheet* sheet = CSSStyleSheet::Create(*this, options, exception_state);
- sheet->SetText(text, false /* allow_import_rules */, exception_state);
- if (exception_state.HadException())
- return nullptr;
- sheet->SetAssociatedDocument(this);
- return sheet;
-}
-
-CSSStyleSheet* Document::createEmptyCSSStyleSheet(
- ScriptState* script_state,
- const CSSStyleSheetInit* options,
- ExceptionState& exception_state) {
- CSSStyleSheet* sheet = CSSStyleSheet::Create(*this, options, exception_state);
- sheet->SetAssociatedDocument(this);
- return sheet;
-}
-
-CSSStyleSheet* Document::createEmptyCSSStyleSheet(
- ScriptState* script_state,
- ExceptionState& exception_state) {
- return Document::createEmptyCSSStyleSheet(
- script_state, CSSStyleSheetInit::Create(), exception_state);
-}
-
ScriptValue Document::registerElement(ScriptState* script_state,
const AtomicString& name,
const ElementRegistrationOptions* options,
@@ -1765,19 +1748,19 @@ void Document::setDir(const AtomicString& value) {
html->setDir(value);
}
-mojom::PageVisibilityState Document::GetPageVisibilityState() const {
+bool Document::IsPageVisible() const {
// The visibility of the document is inherited from the visibility of the
// page. If there is no page associated with the document, we will assume
// that the page is hidden, as specified by the spec:
// https://w3c.github.io/page-visibility/#hidden-attribute
if (!frame_ || !frame_->GetPage())
- return mojom::PageVisibilityState::kHidden;
+ return false;
// While visibilitychange is being dispatched during unloading it is
// expected that the visibility is hidden regardless of the page's
// visibility.
if (load_event_progress_ >= kUnloadVisibilityChangeInProgress)
- return mojom::PageVisibilityState::kHidden;
- return frame_->GetPage()->VisibilityState();
+ return false;
+ return frame_->GetPage()->IsPageVisible();
}
bool Document::IsPrefetchOnly() const {
@@ -1790,11 +1773,11 @@ bool Document::IsPrefetchOnly() const {
}
String Document::visibilityState() const {
- return PageVisibilityStateString(GetPageVisibilityState());
+ return PageHiddenStateString(hidden());
}
bool Document::hidden() const {
- return GetPageVisibilityState() != mojom::PageVisibilityState::kVisible;
+ return !IsPageVisible();
}
bool Document::wasDiscarded() const {
@@ -1811,7 +1794,7 @@ void Document::DidChangeVisibilityState() {
DispatchEvent(
*Event::CreateBubble(event_type_names::kWebkitvisibilitychange));
- if (GetPageVisibilityState() == mojom::PageVisibilityState::kVisible)
+ if (IsPageVisible())
Timeline().SetAllCompositorPending();
if (hidden() && canvas_font_cache_)
@@ -1819,7 +1802,7 @@ void Document::DidChangeVisibilityState() {
InteractiveDetector* interactive_detector = InteractiveDetector::From(*this);
if (interactive_detector) {
- interactive_detector->OnPageVisibilityChanged(GetPageVisibilityState());
+ interactive_detector->OnPageHiddenChanged(hidden());
}
}
@@ -1833,7 +1816,7 @@ Node::NodeType Document::getNodeType() const {
FormController& Document::GetFormController() {
if (!form_controller_) {
- form_controller_ = FormController::Create();
+ form_controller_ = MakeGarbageCollected<FormController>(*this);
HistoryItem* history_item = Loader() ? Loader()->GetHistoryItem() : nullptr;
if (history_item)
history_item->SetDocumentState(form_controller_->FormElementsState());
@@ -2355,7 +2338,7 @@ void Document::UpdateStyle() {
PropagateStyleToViewport();
View()->UpdateCountersAfterStyleChange();
- GetLayoutView()->RecalcOverflow();
+ GetLayoutView()->RecalcLayoutOverflow();
DCHECK(!NeedsStyleRecalc());
DCHECK(!ChildNeedsStyleRecalc());
@@ -2380,6 +2363,8 @@ void Document::ViewportDefiningElementDidChange() {
HTMLBodyElement* body = FirstBodyElement();
if (!body)
return;
+ if (body->NeedsReattachLayoutTree())
+ return;
LayoutObject* layout_object = body->GetLayoutObject();
if (layout_object && layout_object->IsLayoutBlock()) {
// When the overflow style for documentElement changes to or from visible,
@@ -2460,6 +2445,7 @@ void Document::UpdateStyleAndLayout() {
DCHECK(IsMainThread());
HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
+ ScriptForbiddenScope forbid_script;
LocalFrameView* frame_view = View();
DCHECK(!frame_view || !frame_view->IsInPerformLayout())
@@ -2492,17 +2478,8 @@ void Document::LayoutUpdated() {
// If we're restoring a scroll position from history, that takes precedence
// over scrolling to the anchor in the URL.
- View()->ScrollAndFocusFragmentAnchor();
-
- // Script run in the call above may detach the document.
- if (GetFrame() && View()) {
- GetFrame()->Loader().RestoreScrollPositionAndViewState();
-
- // The focus call above can execute JS which can dirty layout. Ensure
- // layout is clean since this is called from UpdateLayout.
- if (View()->NeedsLayout())
- View()->UpdateLayout();
- }
+ View()->InvokeFragmentAnchor();
+ GetFrame()->Loader().RestoreScrollPositionAndViewState();
// Plugins can run script inside layout which can detach the page.
// TODO(dcheng): Does it make sense to do any of this work if detached?
@@ -2586,6 +2563,14 @@ void Document::UpdateStyleAndLayoutTreeIgnorePendingStylesheets() {
void Document::UpdateStyleAndLayoutIgnorePendingStylesheets(
Document::RunPostLayoutTasks run_post_layout_tasks) {
+ DCHECK(!find_in_page_root_);
+ UpdateStyleAndLayoutIgnorePendingStylesheetsConsideringInvisibleNodes(
+ run_post_layout_tasks);
+}
+
+void Document::
+ UpdateStyleAndLayoutIgnorePendingStylesheetsConsideringInvisibleNodes(
+ Document::RunPostLayoutTasks run_post_layout_tasks) {
LocalFrameView* local_view = View();
if (local_view)
local_view->WillStartForcedLayout();
@@ -2631,6 +2616,26 @@ void Document::EnsurePaintLocationDataValidForNode(const Node* node) {
if (!node->InActiveDocument())
return;
+ // If we're forcing location information to be updated, we need to ensure that
+ // all locked elements in the ancestor chain allow us to do the updates. When
+ // the scoped objects are destroyed, the locks are restored. Note that the
+ // frame rect of the locked elements themselves will still be the same as at
+ // the time the lock was acquired.
+ // TODO(vmpstr): This is somewhat inefficient, since we would pay the cost of
+ // traversing the ancestor chain even for nodes that are not in the locked
+ // subtree. We need to figure out if there is a supplementary structure that
+ // we can use to quickly identify nodes that are in the locked subtree.
+ Vector<DisplayLockContext::ScopedForcedUpdate> scoped_update_forced_list;
+ if (RuntimeEnabledFeatures::DisplayLockingEnabled()) {
+ for (auto* ancestor = node; ancestor;
+ ancestor = ancestor->ParentOrShadowHostNode()) {
+ if (!ancestor->IsElementNode())
+ continue;
+ if (auto* context = ToElement(ancestor)->GetDisplayLockContext())
+ scoped_update_forced_list.push_back(context->GetScopedForcedUpdate());
+ }
+ }
+
// For all nodes we must have up-to-date style and have performed layout to do
// any location-based calculation.
UpdateStyleAndLayoutIgnorePendingStylesheets();
@@ -2642,8 +2647,8 @@ void Document::EnsurePaintLocationDataValidForNode(const Node* node) {
if (View() && node->GetLayoutObject() &&
node->GetLayoutObject()->StyleRef().SubtreeIsSticky()) {
bool success = false;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // In SPv2, compositing inputs are cleaned as part of PrePaint.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // In CAP, compositing inputs are cleaned as part of PrePaint.
success = View()->UpdateAllLifecyclePhasesExceptPaint();
} else {
success = View()->UpdateLifecycleToCompositingInputsClean();
@@ -2777,6 +2782,9 @@ void Document::Initialize() {
// attached to a frame. Otherwise ContextLifecycleObserver::contextDestroyed
// wouldn't be fired.
network_state_observer_ = MakeGarbageCollected<NetworkStateObserver>(*this);
+
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ AttachCompositorAnimationTimeline();
}
void Document::Shutdown() {
@@ -2824,12 +2832,17 @@ void Document::Shutdown() {
markers_->PrepareForDestruction();
- if (GetPage())
+ if (GetPage()) {
GetPage()->DocumentDetached(this);
- probe::documentDetached(this);
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ if (auto* compositor_timeline = Timeline().CompositorTimeline()) {
+ GetPage()->GetChromeClient().DetachCompositorAnimationTimeline(
+ compositor_timeline, frame_.Get());
+ }
+ }
+ }
- if (frame_->Client()->GetSharedWorkerRepositoryClient())
- frame_->Client()->GetSharedWorkerRepositoryClient()->DocumentDetached(this);
+ probe::documentDetached(this);
// FIXME: consider using PausableObject.
if (scripted_animation_controller_)
@@ -3210,6 +3223,7 @@ void Document::CancelParsing() {
SetParsingState(kFinishedParsing);
SetReadyState(kComplete);
SuppressLoadEvent();
+ javascript_url_task_handle_.Cancel();
}
DocumentParser* Document::OpenForNavigation(
@@ -3354,20 +3368,19 @@ Element* Document::ViewportDefiningElement() const {
return root_element;
}
-Document* Document::open(LocalDOMWindow* entered_window,
+Document* Document::open(v8::Isolate* isolate,
const AtomicString& type,
const AtomicString& replace,
ExceptionState& exception_state) {
if (replace == "replace") {
UseCounter::Count(Loader(), WebFeature::kDocumentOpenTwoArgsWithReplace);
}
- open(entered_window->document(), exception_state);
+ open(EnteredDOMWindow(isolate)->document(), exception_state);
return this;
}
-DOMWindow* Document::open(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+DOMWindow* Document::open(v8::Isolate* isolate,
+ const USVStringOrTrustedURL& string_or_url,
const AtomicString& name,
const AtomicString& features,
ExceptionState& exception_state) {
@@ -3376,10 +3389,9 @@ DOMWindow* Document::open(LocalDOMWindow* current_window,
"The document has no window associated.");
return nullptr;
}
- AtomicString frame_name = name.IsEmpty() ? "_blank" : name;
- return domWindow()->open(stringOrUrl, frame_name, features, current_window,
- entered_window, exception_state);
+ return domWindow()->open(isolate, string_or_url, name, features,
+ exception_state);
}
// https://html.spec.whatwg.org/C/dynamic-markup-insertion.html#dom-document-close
@@ -3435,7 +3447,6 @@ void Document::close() {
void Document::ImplicitClose() {
DCHECK(!InStyleRecalc());
- DCHECK(parser_);
load_event_progress_ = kLoadEventInProgress;
@@ -3493,7 +3504,7 @@ void Document::ImplicitClose() {
}
if (View())
- View()->ScrollAndFocusFragmentAnchor();
+ View()->InvokeFragmentAnchor();
load_event_progress_ = kLoadEventCompleted;
@@ -3524,6 +3535,7 @@ static bool AllDescendantsAreComplete(Frame* frame) {
bool Document::ShouldComplete() {
return parsing_state_ == kFinishedParsing && HaveImportsLoaded() &&
!fetcher_->BlockingRequestCount() && !IsDelayingLoadEvent() &&
+ !javascript_url_task_handle_.IsActive() &&
load_event_progress_ != kLoadEventInProgress &&
AllDescendantsAreComplete(frame_);
}
@@ -3563,10 +3575,6 @@ bool Document::CheckCompletedInternal() {
// The readystatechanged or load event may have disconnected this frame.
if (!frame_ || !frame_->IsAttached())
return false;
- if (frame_->GetSettings()->GetSavePreviousDocumentResources() ==
- SavePreviousDocumentResources::kUntilOnLoad) {
- fetcher_->ClearResourcesFromPreviousFetcher();
- }
frame_->GetNavigationScheduler().StartTimer();
View()->HandleLoadCompleted();
// The document itself is complete, but if a child frame was restarted due to
@@ -3607,9 +3615,8 @@ bool Document::CheckCompletedInternal() {
return true;
}
-bool Document::DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
+bool Document::DispatchBeforeUnloadEvent(ChromeClient* chrome_client,
bool is_reload,
- bool auto_cancel,
bool& did_allow_navigation) {
if (!dom_window_)
return true;
@@ -3671,9 +3678,9 @@ bool Document::DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
return true;
}
- // If |auto_cancel| is set then do not ask the |chrome_client| to display a
- // modal dialog. Simply indicate that the navigation should not proceed.
- if (auto_cancel) {
+ // If |chrome_client| is null simply indicate that the navigation should
+ // not proceed.
+ if (!chrome_client) {
beforeunload_dialog_histogram.Count(kNoDialogAutoCancelTrue);
did_allow_navigation = false;
return false;
@@ -3684,7 +3691,7 @@ bool Document::DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
BeforeUnloadDialogHistogramEnum::kShowDialog);
const TimeTicks beforeunload_confirmpanel_start = CurrentTimeTicks();
did_allow_navigation =
- chrome_client.OpenBeforeUnloadConfirmPanel(text, frame_, is_reload);
+ chrome_client->OpenBeforeUnloadConfirmPanel(text, frame_, is_reload);
const TimeTicks beforeunload_confirmpanel_end = CurrentTimeTicks();
if (did_allow_navigation) {
// Only record when a navigation occurs, since we want to understand
@@ -3727,9 +3734,11 @@ void Document::DispatchUnloadEvents() {
if (!frame_)
return;
- mojom::PageVisibilityState visibility_state = GetPageVisibilityState();
+ // This must be queried before |load_event_progress_| is changed to
+ // kUnloadVisibilityChangeInProgress because that would change the result.
+ bool page_visible = IsPageVisible();
load_event_progress_ = kUnloadVisibilityChangeInProgress;
- if (visibility_state != mojom::PageVisibilityState::kHidden) {
+ if (page_visible) {
// Dispatch visibilitychange event, but don't bother doing
// other notifications as we're about to be unloaded.
const TimeTicks pagevisibility_hidden_event_start = CurrentTimeTicks();
@@ -3938,7 +3947,9 @@ void Document::write(const String& text,
DCHECK(parser_);
PerformanceMonitor::ReportGenericViolation(
this, PerformanceMonitor::kDiscouragedAPIUse,
- "Avoid using document.write(). https://developers.google.com/web/updates/2016/08/removing-document-write",
+ "Avoid using document.write(). "
+ "https://developers.google.com/web/updates/2016/08/"
+ "removing-document-write",
base::TimeDelta(), nullptr);
probe::breakableLocation(this, "Document.write");
parser_->insert(text);
@@ -3953,13 +3964,11 @@ void Document::writeln(const String& text,
write("\n", entered_document);
}
-void Document::write(LocalDOMWindow* calling_window,
+void Document::write(v8::Isolate* isolate,
const Vector<String>& text,
ExceptionState& exception_state) {
- DCHECK(calling_window);
-
- if (GetSecurityContext().RequireTrustedTypes()) {
- DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ if (IsTrustedTypesEnabledForDoc()) {
+ DCHECK(origin_trials::TrustedDOMTypesEnabled(this));
exception_state.ThrowTypeError(
"This document can only write `TrustedHTML` objects.");
return;
@@ -3971,16 +3980,15 @@ void Document::write(LocalDOMWindow* calling_window,
StringBuilder builder;
for (const String& string : text)
builder.Append(string);
- write(builder.ToString(), calling_window->document(), exception_state);
+ write(builder.ToString(), EnteredDOMWindow(isolate)->document(),
+ exception_state);
}
-void Document::writeln(LocalDOMWindow* calling_window,
+void Document::writeln(v8::Isolate* isolate,
const Vector<String>& text,
ExceptionState& exception_state) {
- DCHECK(calling_window);
-
- if (GetSecurityContext().RequireTrustedTypes()) {
- DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ if (IsTrustedTypesEnabledForDoc()) {
+ DCHECK(origin_trials::TrustedDOMTypesEnabled(this));
exception_state.ThrowTypeError(
"This document can only write `TrustedHTML` objects.");
return;
@@ -3992,23 +4000,29 @@ void Document::writeln(LocalDOMWindow* calling_window,
StringBuilder builder;
for (const String& string : text)
builder.Append(string);
- writeln(builder.ToString(), calling_window->document(), exception_state);
+ writeln(builder.ToString(), EnteredDOMWindow(isolate)->document(),
+ exception_state);
}
-void Document::write(LocalDOMWindow* calling_window,
+bool Document::IsTrustedTypesEnabledForDoc() const {
+ return SecurityContext::RequireTrustedTypes() &&
+ origin_trials::TrustedDOMTypesEnabled(this);
+}
+
+void Document::write(v8::Isolate* isolate,
TrustedHTML* text,
ExceptionState& exception_state) {
- DCHECK(calling_window);
- DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
- write(text->toString(), calling_window->document(), exception_state);
+ DCHECK(origin_trials::TrustedDOMTypesEnabled(this));
+ write(text->toString(), EnteredDOMWindow(isolate)->document(),
+ exception_state);
}
-void Document::writeln(LocalDOMWindow* calling_window,
+void Document::writeln(v8::Isolate* isolate,
TrustedHTML* text,
ExceptionState& exception_state) {
- DCHECK(calling_window);
- DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
- writeln(text->toString(), calling_window->document(), exception_state);
+ DCHECK(origin_trials::TrustedDOMTypesEnabled(this));
+ writeln(text->toString(), EnteredDOMWindow(isolate)->document(),
+ exception_state);
}
DOMTimerCoordinator* Document::Timers() {
@@ -4058,7 +4072,8 @@ void Document::UpdateBaseURL() {
// DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2
// HTML], the base URI is computed using first the value of the href attribute
// of the HTML BASE element if any, and the value of the documentURI attribute
- // from the Document interface otherwise (which we store, preparsed, in url_).
+ // from the Document interface otherwise (which we store, preparsed, in
+ // |url_|).
if (!base_element_url_.IsEmpty())
base_url_ = base_element_url_;
else if (!base_url_override_.IsEmpty())
@@ -4639,17 +4654,17 @@ void Document::SetActiveElement(Element* new_active_element) {
active_element_ = new_active_element;
}
-void Document::RemoveFocusedElementOfSubtree(Node* node,
+void Document::RemoveFocusedElementOfSubtree(Node& node,
bool among_children_only) {
if (!focused_element_)
return;
// We can't be focused if we're not in the document.
- if (!node->isConnected())
+ if (!node.isConnected())
return;
bool contains =
- node->IsShadowIncludingInclusiveAncestorOf(focused_element_.Get());
- if (contains && (focused_element_ != node || !among_children_only))
+ node.IsShadowIncludingInclusiveAncestorOf(focused_element_.Get());
+ if (contains && (focused_element_ != &node || !among_children_only))
ClearFocusedElement();
}
@@ -4797,7 +4812,7 @@ bool Document::SetFocusedElement(Element* new_focused_element,
CancelFocusAppearanceUpdate();
EnsurePaintLocationDataValidForNode(focused_element_);
// UpdateStyleAndLayout can call SetFocusedElement (through
- // ScrollAndFocusFragmentAnchor called in Document::LayoutUpdated) and clear
+ // InvokeFragmentAnchor called in Document::LayoutUpdated) and clear
// focused_element_.
if (focused_element_ != new_focused_element) {
focus_change_blocked = true;
@@ -5132,6 +5147,21 @@ void Document::EnqueueScrollEventForNode(Node* target) {
EnsureScriptedAnimationController().EnqueuePerFrameEvent(scroll_event);
}
+void Document::EnqueueScrollEndEventForNode(Node* target) {
+ Event* scroll_end_event = Event::Create(event_type_names::kScrollend);
+ scroll_end_event->SetTarget(target);
+ EnsureScriptedAnimationController().EnqueuePerFrameEvent(scroll_end_event);
+}
+
+void Document::EnqueueOverscrollEventForNode(Node* target,
+ double delta_x,
+ double delta_y) {
+ Event* overscroll_event =
+ OverscrollEvent::Create(event_type_names::kOverscroll, delta_x, delta_y);
+ overscroll_event->SetTarget(target);
+ EnsureScriptedAnimationController().EnqueuePerFrameEvent(overscroll_event);
+}
+
void Document::EnqueueResizeEvent() {
Event* event = Event::Create(event_type_names::kResize);
event->SetTarget(domWindow());
@@ -5176,30 +5206,6 @@ const OriginAccessEntry& Document::AccessEntryFromURL() {
return *access_entry_from_url_;
}
-void Document::SendSensitiveInputVisibility() {
- if (sensitive_input_visibility_task_.IsActive())
- return;
-
- sensitive_input_visibility_task_ = PostCancellableTask(
- *GetTaskRunner(TaskType::kInternalLoading), FROM_HERE,
- WTF::Bind(&Document::SendSensitiveInputVisibilityInternal,
- WrapWeakPersistent(this)));
-}
-
-void Document::SendSensitiveInputVisibilityInternal() {
- if (!GetFrame())
- return;
-
- mojom::blink::InsecureInputServicePtr insecure_input_service_ptr;
- GetFrame()->GetInterfaceProvider().GetInterface(
- mojo::MakeRequest(&insecure_input_service_ptr));
- if (password_count_ > 0) {
- insecure_input_service_ptr->PasswordFieldVisibleInInsecureContext();
- return;
- }
- insecure_input_service_ptr->AllPasswordFieldsInInsecureContextInvisible();
-}
-
void Document::SendDidEditFieldInInsecureContext() {
if (!GetFrame())
return;
@@ -5405,7 +5411,7 @@ void Document::setCookie(const String& value, ExceptionState& exception_state) {
const AtomicString& Document::referrer() const {
if (Loader())
- return Loader()->GetRequest().HttpReferrer();
+ return Loader()->Referrer();
return g_null_atom;
}
@@ -5528,6 +5534,19 @@ String Document::lastModified() const {
date.Minute(), date.Second());
}
+void Document::SetFindInPageRoot(Element* find_in_page_root) {
+ DCHECK(RuntimeEnabledFeatures::InvisibleDOMEnabled());
+ DCHECK(!find_in_page_root || !find_in_page_root_);
+ find_in_page_root_ = find_in_page_root;
+}
+
+scoped_refptr<const SecurityOrigin> Document::TopFrameOrigin() const {
+ if (!GetFrame())
+ return scoped_refptr<const SecurityOrigin>();
+
+ return GetFrame()->Tree().Top().GetSecurityContext()->GetSecurityOrigin();
+}
+
const KURL Document::SiteForCookies() const {
// TODO(mkwst): This doesn't properly handle HTML Import documents.
@@ -6056,6 +6075,51 @@ LocalDOMWindow* Document::defaultView() const {
return frame_ ? dom_window_ : nullptr;
}
+namespace {
+
+using resource_coordinator::mojom::InterventionPolicy;
+using resource_coordinator::mojom::PolicyControlledIntervention;
+
+typedef bool (*InterventionPolicyGetter)(const ExecutionContext*);
+struct InterventionPolicyGetters {
+ InterventionPolicyGetter opt_in_getter;
+ InterventionPolicyGetter opt_out_getter;
+};
+
+constexpr InterventionPolicyGetters kInterventionPolicyGetters[] = {
+ {&origin_trials::PageLifecycleTransitionsOptInEnabled,
+ &origin_trials::PageLifecycleTransitionsOptOutEnabled}};
+
+static_assert(base::size(kInterventionPolicyGetters) ==
+ static_cast<size_t>(PolicyControlledIntervention::kMaxValue) +
+ 1,
+ "kInterventionPolicyGetters array must be kept in sync with "
+ "mojom::PolicyControlledIntervention enum.");
+
+// A helper function for setting intervention policy values on a frame en masse.
+void SetInitialInterventionPolicies(FrameResourceCoordinator* frame_coordinator,
+ const ExecutionContext* context) {
+ // Note that these must be emitted in order, as the *last* policy being set
+ // is used as a sentinel in the browser-side logic to infer that the frame has
+ // transmitted all of its policy data.
+ for (size_t i = 0; i < base::size(kInterventionPolicyGetters); ++i) {
+ bool opt_in = (*kInterventionPolicyGetters[i].opt_in_getter)(context);
+ bool opt_out = (*kInterventionPolicyGetters[i].opt_out_getter)(context);
+
+ // An explicit opt-out overrides an explicit opt-in if both are present.
+ InterventionPolicy policy = InterventionPolicy::kDefault;
+ if (opt_out)
+ policy = InterventionPolicy::kOptOut;
+ else if (opt_in)
+ policy = InterventionPolicy::kOptIn;
+
+ frame_coordinator->SetInterventionPolicy(
+ static_cast<PolicyControlledIntervention>(i), policy);
+ }
+}
+
+} // namespace
+
void Document::FinishedParsing() {
DCHECK(!GetScriptableDocumentParser() || !parser_->IsParsing());
DCHECK(!GetScriptableDocumentParser() || ready_state_ != kLoading);
@@ -6113,6 +6177,13 @@ void Document::FinishedParsing() {
inspector_mark_load_event::Data(frame));
probe::domContentLoadedEventFired(frame);
frame->GetIdlenessDetector()->DomContentLoadedEventFired();
+
+ // Forward intervention policy state to the corresponding frame object
+ // in the resource coordinator.
+ // TODO(chrisha): Plumb in dynamic policy changes driven from Javascript.
+ if (auto* frame_coordinator = frame->GetFrameResourceCoordinator()) {
+ SetInitialInterventionPolicies(frame_coordinator, this);
+ }
}
// Schedule dropping of the ElementDataCache. We keep it alive for a while
@@ -6126,10 +6197,6 @@ void Document::FinishedParsing() {
// Parser should have picked up all preloads by now
fetcher_->ClearPreloads(ResourceFetcher::kClearSpeculativeMarkupPreloads);
- if (!frame_ || frame_->GetSettings()->GetSavePreviousDocumentResources() ==
- SavePreviousDocumentResources::kUntilOnDOMContentLoaded) {
- fetcher_->ClearResourcesFromPreviousFetcher();
- }
if (IsPrefetchOnly())
WebPrerenderingSupport::Current()->PrefetchFinished();
@@ -6269,34 +6336,68 @@ void Document::ApplyFeaturePolicyFromHeader(
}
}
-void Document::ApplyFeaturePolicy(const ParsedFeaturePolicy& declared_policy) {
- FeaturePolicy* parent_feature_policy = nullptr;
- ParsedFeaturePolicy container_policy;
+const ParsedFeaturePolicy Document::GetOwnerContainerPolicy() const {
+ // If this frame is not the main frame, then get the container policy from its
+ // owner.
+ if (frame_ && frame_->Owner())
+ return frame_->Owner()->ContainerPolicy();
+ return ParsedFeaturePolicy();
+}
- // If this frame is not the main frame, then get the appropriate parent policy
- // and container policy to construct the policy for this frame.
- if (frame_) {
- if (!frame_->IsMainFrame()) {
- parent_feature_policy =
- frame_->Tree().Parent()->GetSecurityContext()->GetFeaturePolicy();
- }
- if (frame_->Owner())
- container_policy = frame_->Owner()->ContainerPolicy();
- }
+const FeaturePolicy* Document::GetParentFeaturePolicy() const {
+ // If this frame is not the main frame, then get the feature policy from its
+ // parent.
+ if (frame_ && !frame_->IsMainFrame())
+ return frame_->Tree().Parent()->GetSecurityContext()->GetFeaturePolicy();
+ return nullptr;
+}
- InitializeFeaturePolicy(declared_policy, container_policy,
- parent_feature_policy);
+void Document::ApplyFeaturePolicy(const ParsedFeaturePolicy& declared_policy) {
+ InitializeFeaturePolicy(declared_policy, GetOwnerContainerPolicy(),
+ GetParentFeaturePolicy());
// At this point, the document will not have been installed in the frame's
// LocalDOMWindow, so we cannot call frame_->IsFeatureEnabled. This calls
// SecurityContext::IsFeatureEnabled instead, which cannot report, but we
// don't need reporting here in any case.
is_vertical_scroll_enforced_ =
+ frame_ && !frame_->IsMainFrame() &&
RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
!GetFeaturePolicy()->IsFeatureEnabled(
mojom::FeaturePolicyFeature::kVerticalScroll);
}
+void Document::ApplyReportOnlyFeaturePolicyFromHeader(
+ const String& feature_policy_report_only_header) {
+ if (feature_policy_report_only_header.IsEmpty())
+ return;
+ // TODO(iclelland): Remove this message when reporting is no longer part of an
+ // origin trial.
+ // Note that we do not return here. Instead, the header is parsed and the
+ // report-only policy is stored, in case a valid Origin Trial token is added
+ // later. In that case, any subsequent violations will be correctly reported.
+ if (!origin_trials::FeaturePolicyReportingEnabled(this)) {
+ AddConsoleMessage(ConsoleMessage::Create(
+ kSecurityMessageSource, kWarningMessageLevel,
+ "Feature-Policy-Report-Only header will have no effect unless Feature "
+ "Policy reporting is enabled with an Origin Trial. Sign up at "
+ "https://developers.chrome.com/origintrials/"));
+ }
+
+ UseCounter::Count(*this, WebFeature::kFeaturePolicyReportOnlyHeader);
+ Vector<String> messages;
+ const ParsedFeaturePolicy& report_only_policy = ParseFeaturePolicyHeader(
+ feature_policy_report_only_header, GetSecurityOrigin(), &messages);
+ for (auto& message : messages) {
+ AddConsoleMessage(ConsoleMessage::Create(
+ kSecurityMessageSource, kErrorMessageLevel,
+ "Error with Feature-Policy-Report-Only header: " + message));
+ }
+
+ AddReportOnlyFeaturePolicy(report_only_policy, GetOwnerContainerPolicy(),
+ GetParentFeaturePolicy());
+}
+
bool Document::AllowedToUseDynamicMarkUpInsertion(
const char* api_name,
ExceptionState& exception_state) {
@@ -6373,36 +6474,65 @@ void Document::InitSecurityContext(const DocumentInit& initializer) {
AddInsecureNavigationUpgrade(to_upgrade);
}
- const ContentSecurityPolicy* policy_to_inherit = nullptr;
+ ContentSecurityPolicy* last_origin_document_csp_ =
+ frame_ ? frame_->Loader().GetLastOriginDocumentCSP() : nullptr;
+
+ scoped_refptr<SecurityOrigin> document_origin;
+ cookie_url_ = url_;
+ if (initializer.OriginToCommit()) {
+ // Origin to commit is specified by the browser process, it must be taken
+ // and used directly. It is currently supplied only for session history
+ // navigations, where the origin was already calcuated previously and
+ // stored on the session history entry.
+ document_origin = initializer.OriginToCommit();
+ } else {
+ if (Document* owner_document = initializer.OwnerDocument()) {
+ // Alias certain security properties from |owner_document|. Used for
+ // the case of about:blank pages inheriting the security properties of
+ // their requestor context.
+ // Note that this is currently somewhat broken; Blink always inherits
+ // from the parent or opener, even though it should actually be
+ // inherited from the request initiator.
+ document_origin = owner_document->GetMutableSecurityOrigin();
+ cookie_url_ = owner_document->CookieURL();
+ if (url_.IsEmpty())
+ last_origin_document_csp_ = owner_document->GetContentSecurityPolicy();
+ } else {
+ // Otherwise, create an origin that propagates precursor information
+ // as needed. For non-opaque origins, this creates a standard tuple
+ // origin, but for opaque origins, it creates an origin with the
+ // initiator origin as the precursor.
+ document_origin = SecurityOrigin::CreateWithReferenceOrigin(
+ url_, initializer.InitiatorOrigin().get());
+ }
+ }
if (IsSandboxed(kSandboxOrigin)) {
- cookie_url_ = url_;
- scoped_refptr<SecurityOrigin> security_origin =
- SecurityOrigin::CreateUniqueOpaque();
+ DCHECK(!initializer.ContextDocument());
+ scoped_refptr<SecurityOrigin> sandboxed_origin =
+ initializer.OriginToCommit() ? initializer.OriginToCommit()
+ : document_origin->DeriveNewOpaqueOrigin();
+
// If we're supposed to inherit our security origin from our
// owner, but we're also sandboxed, the only things we inherit are
// the origin's potential trustworthiness and the ability to
// load local resources. The latter lets about:blank iframes in
// file:// URL documents load images and other resources from
// the file system.
- Document* owner = initializer.OwnerDocument();
- if (owner) {
- if (owner->GetSecurityOrigin()->IsPotentiallyTrustworthy())
- security_origin->SetOpaqueOriginIsPotentiallyTrustworthy(true);
- if (owner->GetSecurityOrigin()->CanLoadLocalResources())
- security_origin->GrantLoadLocalResources();
- policy_to_inherit = owner->GetContentSecurityPolicy();
+ if (initializer.OwnerDocument()) {
+ if (document_origin->IsPotentiallyTrustworthy())
+ sandboxed_origin->SetOpaqueOriginIsPotentiallyTrustworthy(true);
+ if (document_origin->CanLoadLocalResources())
+ sandboxed_origin->GrantLoadLocalResources();
+ if (url_.IsEmpty()) {
+ last_origin_document_csp_ =
+ initializer.OwnerDocument()->GetContentSecurityPolicy();
+ }
}
- SetSecurityOrigin(std::move(security_origin));
- } else if (Document* owner = initializer.OwnerDocument()) {
- cookie_url_ = owner->CookieURL();
- // We alias the SecurityOrigins to match Firefox, see Bug 15313
- // https://bugs.webkit.org/show_bug.cgi?id=15313
- SetSecurityOrigin(owner->GetMutableSecurityOrigin());
- policy_to_inherit = owner->GetContentSecurityPolicy();
- } else {
cookie_url_ = url_;
- SetSecurityOrigin(SecurityOrigin::Create(url_));
+ SetSecurityOrigin(std::move(sandboxed_origin));
+ } else {
+ SetSecurityOrigin(std::move(document_origin));
}
// Set the address space before setting up CSP, as the latter may override
@@ -6431,8 +6561,7 @@ void Document::InitSecurityContext(const DocumentInit& initializer) {
SetContentSecurityPolicy(
ImportsController()->Master()->GetContentSecurityPolicy());
} else {
- InitContentSecurityPolicy(nullptr, policy_to_inherit,
- initializer.PreviousDocumentCSP());
+ InitContentSecurityPolicy(nullptr, last_origin_document_csp_);
}
if (Settings* settings = initializer.GetSettings()) {
@@ -6495,52 +6624,38 @@ void Document::InitSecureContextState() {
// will attempt to copy over the policy
void Document::InitContentSecurityPolicy(
ContentSecurityPolicy* csp,
- const ContentSecurityPolicy* policy_to_inherit,
- const ContentSecurityPolicy* previous_document_csp) {
+ const ContentSecurityPolicy* last_origin_document_csp) {
SetContentSecurityPolicy(csp ? csp : ContentSecurityPolicy::Create());
- GetContentSecurityPolicy()->BindToExecutionContext(this);
+ GetContentSecurityPolicy()->BindToDelegate(
+ GetContentSecurityPolicyDelegate());
- // We inherit the parent/opener's CSP for documents with "local" schemes:
- // 'about', 'blob', 'data', and 'filesystem'. We also inherit CSP for
- // documents with empty/invalid URLs because we treat those URLs as
- // 'about:blank' in Blink.
- //
- // https://w3c.github.io/webappsec-csp/#initialize-document-csp
- //
- // TODO(dcheng): This is similar enough to work we're doing in
- // 'DocumentLoader::ensureWriter' that it might make sense to combine them.
- if (policy_to_inherit) {
- GetContentSecurityPolicy()->CopyStateFrom(policy_to_inherit);
- } else {
- if (frame_) {
+ // We should inherit the navigation initiator CSP if the document is loaded
+ // using a local-scheme url.
+ if (last_origin_document_csp &&
+ (url_.IsEmpty() || url_.ProtocolIsAbout() || url_.ProtocolIsData() ||
+ url_.ProtocolIs("blob") || url_.ProtocolIs("filesystem"))) {
+ GetContentSecurityPolicy()->CopyStateFrom(last_origin_document_csp);
+ }
+
+ if (IsPluginDocument()) {
+ // TODO(andypaicu): This should inherit the origin document's plugin types
+ // but because this could be a OOPIF document it might not have access.
+ // In this situation we fallback on using the parent/opener.
+ if (last_origin_document_csp) {
+ GetContentSecurityPolicy()->CopyPluginTypesFrom(last_origin_document_csp);
+ } else if (frame_) {
Frame* inherit_from = frame_->Tree().Parent()
? frame_->Tree().Parent()
: frame_->Client()->Opener();
if (inherit_from && frame_ != inherit_from) {
DCHECK(inherit_from->GetSecurityContext() &&
inherit_from->GetSecurityContext()->GetContentSecurityPolicy());
- policy_to_inherit =
- inherit_from->GetSecurityContext()->GetContentSecurityPolicy();
+ GetContentSecurityPolicy()->CopyPluginTypesFrom(
+ inherit_from->GetSecurityContext()->GetContentSecurityPolicy());
}
}
-
- // If we don't have an opener or parent, inherit from the previous
- // document CSP.
- if (!policy_to_inherit)
- policy_to_inherit = previous_document_csp;
-
- // We should inherit the relevant CSP if the document is loaded using
- // a local-scheme url.
- if (policy_to_inherit &&
- (url_.IsEmpty() || url_.ProtocolIsAbout() || url_.ProtocolIsData() ||
- url_.ProtocolIs("blob") || url_.ProtocolIs("filesystem")))
- GetContentSecurityPolicy()->CopyStateFrom(policy_to_inherit);
}
- // Plugin documents inherit their parent/opener's 'plugin-types' directive
- // regardless of URL.
- if (policy_to_inherit && IsPluginDocument())
- GetContentSecurityPolicy()->CopyPluginTypesFrom(policy_to_inherit);
}
bool Document::IsSecureTransitionTo(const KURL& url) const {
@@ -6924,8 +7039,15 @@ void Document::ServiceScriptedAnimations(
}
ScriptedIdleTaskController& Document::EnsureScriptedIdleTaskController() {
- if (!scripted_idle_task_controller_)
+ if (!scripted_idle_task_controller_) {
scripted_idle_task_controller_ = ScriptedIdleTaskController::Create(this);
+ // We need to make sure that we don't start up the idle controller if we
+ // don't have an attached frame and if execution context is destroyed.
+ if (!frame_ || !frame_->IsAttached() ||
+ ExecutionContext::IsContextDestroyed()) {
+ scripted_idle_task_controller_->ContextPaused(PauseState::kFrozen);
+ }
+ }
return *scripted_idle_task_controller_;
}
@@ -7164,6 +7286,14 @@ Locale& Document::GetCachedLocale(const AtomicString& locale) {
return *(result.stored_value->value);
}
+void Document::AttachCompositorAnimationTimeline() {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (auto* compositor_timeline = Timeline().CompositorTimeline()) {
+ GetPage()->GetChromeClient().AttachCompositorAnimationTimeline(
+ compositor_timeline, frame_.Get());
+ }
+}
+
AnimationClock& Document::GetAnimationClock() {
DCHECK(GetPage());
return GetPage()->Animator().Clock();
@@ -7439,30 +7569,6 @@ const PropertyRegistry* Document::GetPropertyRegistry() const {
return const_cast<Document*>(this)->GetPropertyRegistry();
}
-void Document::IncrementPasswordCount() {
- ++password_count_;
- if (IsSecureContext() || password_count_ != 1) {
- // The browser process only cares about passwords on pages where the
- // top-level URL is not secure. Secure contexts must have a top-level
- // URL that is secure, so there is no need to send notifications for
- // password fields in secure contexts.
- //
- // Also, only send a message on the first visible password field; the
- // browser process doesn't care about the presence of additional
- // password fields beyond that.
- return;
- }
- SendSensitiveInputVisibility();
-}
-
-void Document::DecrementPasswordCount() {
- DCHECK_GT(password_count_, 0u);
- --password_count_;
- if (IsSecureContext() || password_count_ > 0)
- return;
- SendSensitiveInputVisibility();
-}
-
void Document::MaybeQueueSendDidEditFieldInInsecureContext() {
if (logged_field_edit_ || sensitive_input_edited_task_.IsActive() ||
IsSecureContext()) {
@@ -7521,7 +7627,7 @@ scoped_refptr<base::SingleThreadTaskRunner> Document::GetTaskRunner(
return Thread::Current()->GetTaskRunner();
}
-Policy* Document::policy() {
+DOMFeaturePolicy* Document::featurePolicy() {
if (!policy_)
policy_ = MakeGarbageCollected<DocumentPolicy>(this);
return policy_.Get();
@@ -7553,7 +7659,7 @@ StylePropertyMapReadOnly* Document::RemoveComputedStyleMapItem(
return computed_style;
}
-void Document::Trace(blink::Visitor* visitor) {
+void Document::Trace(Visitor* visitor) {
visitor->Trace(imports_controller_);
visitor->Trace(doc_type_);
visitor->Trace(implementation_);
@@ -7614,6 +7720,8 @@ void Document::Trace(blink::Visitor* visitor) {
visitor->Trace(slot_assignment_engine_);
visitor->Trace(viewport_data_);
visitor->Trace(lazy_load_image_observer_);
+ visitor->Trace(isolated_world_csp_map_);
+ visitor->Trace(find_in_page_root_);
Supplementable<Document>::Trace(visitor);
TreeScope::Trace(visitor);
ContainerNode::Trace(visitor);
@@ -7690,11 +7798,20 @@ LazyLoadImageObserver& Document::EnsureLazyLoadImageObserver() {
return *lazy_load_image_observer_;
}
+void Document::CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature feature) const {
+ size_t index = static_cast<size_t>(feature);
+ if (potentially_violated_features_.QuickGet(index))
+ return;
+ potentially_violated_features_.QuickSet(index);
+ UMA_HISTOGRAM_ENUMERATION("Blink.UseCounter.FeaturePolicy.PotentialViolation",
+ feature);
+}
void Document::ReportFeaturePolicyViolation(
mojom::FeaturePolicyFeature feature,
mojom::FeaturePolicyDisposition disposition,
const String& message) const {
- if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled())
+ if (!origin_trials::FeaturePolicyReportingEnabled(this))
return;
LocalFrame* frame = GetFrame();
if (!frame)
@@ -7737,6 +7854,58 @@ void Document::IncrementNumberOfCanvases() {
num_canvases_++;
}
+void Document::ExecuteJavaScriptUrl(
+ const KURL& url,
+ ContentSecurityPolicyDisposition disposition) {
+ if (!frame_)
+ return;
+ frame_->GetScriptController().ExecuteScriptIfJavaScriptURL(url, nullptr,
+ disposition);
+ CheckCompleted();
+}
+
+void Document::ProcessJavaScriptUrl(
+ const KURL& url,
+ ContentSecurityPolicyDisposition disposition) {
+ DCHECK(url.ProtocolIsJavaScript());
+ if (frame_->Loader().StateMachine()->IsDisplayingInitialEmptyDocument())
+ load_event_progress_ = kLoadEventNotRun;
+ frame_->Loader().Progress().ProgressStarted();
+ // Some sites appear to depend on javascript:'' synchronously populating an
+ // iframe, similar to about:blank. See https://crbug.com/923585
+ // TODO(japhet): The spec doesn't say anything about ever loading JS urls
+ // synchronously. It's unclear whether the problem is that JS url navigation
+ // has to be sync in certain situations, or if these are just legacy websites
+ // assuming non-spec-compliant behavior. Either way, this special case seems
+ // hacky.
+ if (frame_->Loader().StateMachine()->IsDisplayingInitialEmptyDocument() &&
+ (url == "javascript:''" || url == "javascript:\"\"")) {
+ ExecuteJavaScriptUrl(url, disposition);
+ return;
+ }
+ javascript_url_task_handle_ = PostCancellableTask(
+ *GetTaskRunner(TaskType::kNetworking), FROM_HERE,
+ WTF::Bind(&Document::ExecuteJavaScriptUrl, WrapWeakPersistent(this), url,
+ disposition));
+}
+
+void Document::CancelPendingJavaScriptUrl() {
+ if (javascript_url_task_handle_.IsActive())
+ javascript_url_task_handle_.Cancel();
+}
+
+bool Document::IsInWebAppScope() const {
+ if (!GetSettings())
+ return false;
+
+ const String& web_app_scope = GetSettings()->GetWebAppScope();
+ if (web_app_scope.IsNull() || web_app_scope.IsEmpty())
+ return false;
+
+ DCHECK_EQ(KURL(web_app_scope).GetString(), web_app_scope);
+ return Url().GetString().StartsWith(web_app_scope);
+}
+
void Document::SendViolationReport(
mojom::blink::CSPViolationParamsPtr violation_params) {
std::unique_ptr<SourceLocation> source_location = SourceLocation::Create(
@@ -7767,6 +7936,12 @@ void Document::SendViolationReport(
nullptr /* Element */);
}
+bool Document::ChildrenCanHaveStyle() const {
+ if (LayoutObject* view = GetLayoutView())
+ return view->CanHaveChildren();
+ return false;
+}
+
template class CORE_TEMPLATE_EXPORT Supplement<Document>;
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/document.h b/chromium/third_party/blink/renderer/core/dom/document.h
index 18de74e9ce7..f0f751197c3 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.h
+++ b/chromium/third_party/blink/renderer/core/dom/document.h
@@ -62,9 +62,9 @@
#include "third_party/blink/renderer/core/frame/hosts_using_features.h"
#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
#include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/timer.h"
@@ -83,17 +83,12 @@ class UkmRecorder;
namespace blink {
-namespace mojom {
-enum class PageVisibilityState : int32_t;
-} // namespace mojom
-
class AnimationClock;
class AXContext;
class AXObjectCache;
class Attr;
class CDATASection;
class CSSStyleSheet;
-class CSSStyleSheetInit;
class CanvasFontCache;
class ChromeClient;
class Comment;
@@ -114,6 +109,7 @@ class DocumentParser;
class DocumentState;
class DocumentTimeline;
class DocumentType;
+class DOMFeaturePolicy;
class Element;
class ElementDataCache;
class ElementRegistrationOptions;
@@ -156,7 +152,6 @@ class NthIndexCache;
class OriginAccessEntry;
class Page;
class PendingAnimations;
-class Policy;
class ProcessingInstruction;
class PropertyRegistry;
class QualifiedName;
@@ -164,7 +159,6 @@ class Range;
class ResizeObserverController;
class ResourceFetcher;
class RootScrollerController;
-class ScriptPromise;
class ScriptValue;
class SVGDocumentExtensions;
class SVGUseElement;
@@ -266,20 +260,21 @@ class CORE_EXPORT Document : public ContainerNode,
const Position&);
// Support JS introspection of frame policy (e.g. feature policy).
- Policy* policy();
+ DOMFeaturePolicy* featurePolicy();
MediaQueryMatcher& GetMediaQueryMatcher();
void MediaQueryAffectingValueChanged();
- using SecurityContext::GetSecurityOrigin;
- using SecurityContext::GetMutableSecurityOrigin;
using SecurityContext::GetContentSecurityPolicy;
+ using SecurityContext::GetMutableSecurityOrigin;
+ using SecurityContext::GetSecurityOrigin;
using TreeScope::getElementById;
// ExecutionContext overrides:
bool IsDocument() const final { return true; }
bool ShouldInstallV8Extensions() const final;
+ ContentSecurityPolicy* GetContentSecurityPolicyForWorld() override;
bool CanContainRangeEndPoint() const override { return true; }
@@ -353,30 +348,6 @@ class CORE_EXPORT Document : public ContainerNode,
Element* CreateRawElement(const QualifiedName&,
const CreateElementFlags = CreateElementFlags());
- CSSStyleSheet* createEmptyCSSStyleSheet(ScriptState*,
- const CSSStyleSheetInit*,
- ExceptionState&);
-
- CSSStyleSheet* createEmptyCSSStyleSheet(ScriptState*, ExceptionState&);
-
- ScriptPromise createCSSStyleSheet(ScriptState*,
- const String&,
- ExceptionState&);
-
- ScriptPromise createCSSStyleSheet(ScriptState*,
- const String&,
- const CSSStyleSheetInit*,
- ExceptionState&);
-
- CSSStyleSheet* createCSSStyleSheetSync(ScriptState*,
- const String&,
- const CSSStyleSheetInit*,
- ExceptionState&);
-
- CSSStyleSheet* createCSSStyleSheetSync(ScriptState*,
- const String&,
- ExceptionState&);
-
Element* ElementFromPoint(double x, double y) const;
HeapVector<Member<Element>> ElementsFromPoint(double x, double y) const;
Range* caretRangeFromPoint(int x, int y);
@@ -419,7 +390,7 @@ class CORE_EXPORT Document : public ContainerNode,
}
String visibilityState() const;
- mojom::PageVisibilityState GetPageVisibilityState() const;
+ bool IsPageVisible() const;
bool hidden() const;
void DidChangeVisibilityState();
@@ -511,8 +482,8 @@ class CORE_EXPORT Document : public ContainerNode,
// document's frame_, if any. Can be null.
// TODO(kochi): Audit usage of this interface (crbug.com/746150).
LocalFrame* GetFrameOfMasterDocument() const;
- Page* GetPage() const; // can be null
- Settings* GetSettings() const; // can be null
+ Page* GetPage() const; // can be null
+ Settings* GetSettings() const; // can be null
float DevicePixelRatio() const;
@@ -548,6 +519,10 @@ class CORE_EXPORT Document : public ContainerNode,
};
void UpdateStyleAndLayoutIgnorePendingStylesheets(
RunPostLayoutTasks = kRunPostLayoutTasksAsyhnchronously);
+ // Same as UpdateStyleAndLayoutIgnorePendingStyleSheets()
+ // but allows style & layout tree calculation for invisible nodes.
+ void UpdateStyleAndLayoutIgnorePendingStylesheetsConsideringInvisibleNodes(
+ RunPostLayoutTasks = kRunPostLayoutTasksAsyhnchronously);
void UpdateStyleAndLayoutIgnorePendingStylesheetsForNode(Node*);
scoped_refptr<ComputedStyle> StyleForElementIgnoringPendingStylesheets(
Element*);
@@ -579,6 +554,8 @@ class CORE_EXPORT Document : public ContainerNode,
ResourceFetcher* Fetcher() const override { return fetcher_.Get(); }
+ using ExecutionContext::NotifyContextDestroyed;
+
void Initialize();
virtual void Shutdown();
@@ -617,13 +594,12 @@ class CORE_EXPORT Document : public ContainerNode,
// This is the DOM API document.open() implementation.
// document.open() opens a new window when called with three arguments.
- Document* open(LocalDOMWindow* entered_window,
+ Document* open(v8::Isolate*,
const AtomicString& type,
const AtomicString& replace,
ExceptionState&);
- DOMWindow* open(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+ DOMWindow* open(v8::Isolate*,
+ const USVStringOrTrustedURL& string_or_url,
const AtomicString& name,
const AtomicString& features,
ExceptionState&);
@@ -644,24 +620,21 @@ class CORE_EXPORT Document : public ContainerNode,
//
// |chrome_client| is used to synchronously get user consent (via a modal
// javascript dialog) to allow the unload to proceed if the beforeunload
- // handler returns a non-null value, indicating unsaved state.
+ // handler returns a non-null value, indicating unsaved state. If a
+ // null |chrome_client| is provided and the beforeunload returns a non-null
+ // value this function will automatically return false, indicating that the
+ // unload should not proceed. A null chrome client is set to by the freezing
+ // logic, which uses this to determine if a non-empty beforeunload handler
+ // is present before allowing discarding to proceed.
//
// |is_reload| indicates if the beforeunload is being triggered because of a
// reload operation, otherwise it is assumed to be a page close or navigation.
//
- // If |auto_cancel| is true and the beforeunload returns a non-null value then
- // the |chrome_client| will not be invoked, and this function will
- // automatically return false, indicating that the unload should not proceed.
- // This is set to true by the freezing logic, which uses this to determine if
- // a non-empty beforeunload handler is present before allowing discarding to
- // proceed.
- //
// |did_allow_navigation| is set to reflect the choice made by the user via
// the modal dialog. The value is meaningless if |auto_cancel|
// is true, in which case it will always be set to false.
- bool DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
+ bool DispatchBeforeUnloadEvent(ChromeClient* chrome_client,
bool is_reload,
- bool auto_cancel,
bool& did_allow_navigation);
void DispatchUnloadEvents();
@@ -684,13 +657,14 @@ class CORE_EXPORT Document : public ContainerNode,
void writeln(const String& text,
Document* entered_document = nullptr,
ExceptionState& = ASSERT_NO_EXCEPTION);
- void write(LocalDOMWindow*, const Vector<String>& text, ExceptionState&);
- void writeln(LocalDOMWindow*, const Vector<String>& text, ExceptionState&);
+ void write(v8::Isolate*, const Vector<String>& text, ExceptionState&);
+ void writeln(v8::Isolate*, const Vector<String>& text, ExceptionState&);
// TrustedHTML variants of the above.
// TODO(mkwst): Write a spec for this.
- void write(LocalDOMWindow*, TrustedHTML*, ExceptionState&);
- void writeln(LocalDOMWindow*, TrustedHTML*, ExceptionState&);
+ void write(v8::Isolate*, TrustedHTML*, ExceptionState&);
+ void writeln(v8::Isolate*, TrustedHTML*, ExceptionState&);
+ bool IsTrustedTypesEnabledForDoc() const;
bool WellFormed() const { return well_formed_; }
@@ -817,7 +791,7 @@ class CORE_EXPORT Document : public ContainerNode,
Element* HoverElement() const { return hover_element_.Get(); }
- void RemoveFocusedElementOfSubtree(Node*, bool among_children_only = false);
+ void RemoveFocusedElementOfSubtree(Node&, bool among_children_only = false);
void HoveredElementDetached(Element&);
void ActiveChainNodeDetached(Element&);
@@ -952,6 +926,10 @@ class CORE_EXPORT Document : public ContainerNode,
}
String lastModified() const;
+ Element* FindInPageRoot() const { return find_in_page_root_.Get(); }
+
+ void SetFindInPageRoot(Element* find_in_page_root);
+
// The cookieURL is used to query the cookie database for this document's
// cookies. For example, if the cookie URL is http://example.com, we'll
// use the non-Secure cookies for example.com when computing
@@ -965,6 +943,8 @@ class CORE_EXPORT Document : public ContainerNode,
const KURL& CookieURL() const { return cookie_url_; }
void SetCookieURL(const KURL& url) { cookie_url_ = url; }
+ scoped_refptr<const SecurityOrigin> TopFrameOrigin() const;
+
const KURL SiteForCookies() const;
// The following implements the rule from HTML 4 for what valid names are.
@@ -1118,10 +1098,8 @@ class CORE_EXPORT Document : public ContainerNode,
// the document will take ownership of the policy
// the second parameter specifies a policy to inherit meaning the document
// will attempt to copy over the policy
- void InitContentSecurityPolicy(
- ContentSecurityPolicy* = nullptr,
- const ContentSecurityPolicy* policy_to_inherit = nullptr,
- const ContentSecurityPolicy* previous_document_csp = nullptr);
+ void InitContentSecurityPolicy(ContentSecurityPolicy* = nullptr,
+ const ContentSecurityPolicy* = nullptr);
bool IsSecureTransitionTo(const KURL&) const;
@@ -1174,6 +1152,10 @@ class CORE_EXPORT Document : public ContainerNode,
void EnqueueResizeEvent();
void EnqueueScrollEventForNode(Node*);
+ void EnqueueScrollEndEventForNode(Node*);
+ void EnqueueOverscrollEventForNode(Node* target,
+ double delta_x,
+ double delta_y);
void EnqueueAnimationFrameTask(base::OnceClosure);
void EnqueueAnimationFrameEvent(Event*);
// Only one event for a target/event type combination will be dispatched per
@@ -1266,6 +1248,11 @@ class CORE_EXPORT Document : public ContainerNode,
// Return a Locale for the default locale if the argument is null or empty.
Locale& GetCachedLocale(const AtomicString& locale = g_null_atom);
+ // For CompositeAfterPaint. This is called internally from Initialize(), but
+ // for the local frame root, the frame widget may be not set at the time,
+ // so this is also called from WebLocalFrameImpl::SetFrameWidget().
+ void AttachCompositorAnimationTimeline();
+
AnimationClock& GetAnimationClock();
DocumentTimeline& Timeline() const { return *timeline_; }
PendingAnimations& GetPendingAnimations() { return *pending_animations_; }
@@ -1316,7 +1303,7 @@ class CORE_EXPORT Document : public ContainerNode,
void UpdateActiveStyle();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
AtomicString ConvertLocalName(const AtomicString&);
@@ -1396,11 +1383,6 @@ class CORE_EXPORT Document : public ContainerNode,
const PropertyRegistry* GetPropertyRegistry() const;
PropertyRegistry* GetPropertyRegistry();
- // Document maintains a counter of visible non-secure password
- // fields in the page. Used to notify the embedder when all visible
- // non-secure password fields are no longer visible.
- void IncrementPasswordCount();
- void DecrementPasswordCount();
// Used to notify the embedder when the user edits the value of a
// text field in a non-secure context.
void MaybeQueueSendDidEditFieldInInsecureContext();
@@ -1409,10 +1391,15 @@ class CORE_EXPORT Document : public ContainerNode,
service_manager::InterfaceProvider* GetInterfaceProvider() final;
// Set an explicit feature policy on this document in response to an HTTP
- // Feature Policy header. This will be relayed to the embedder through the
+ // Feature-Policy header. This will be relayed to the embedder through the
// LocalFrameClient.
void ApplyFeaturePolicyFromHeader(const String& feature_policy_header);
+ // Set the report-only feature policy on this document in response to an HTTP
+ // Feature-Policy-Report-Only header.
+ void ApplyReportOnlyFeaturePolicyFromHeader(
+ const String& feature_policy_report_only_header);
+
const AtomicString& bgColor() const;
void setBgColor(const AtomicString&);
const AtomicString& fgColor() const;
@@ -1467,6 +1454,23 @@ class CORE_EXPORT Document : public ContainerNode,
bool IsSlotAssignmentRecalcForbidden() { return false; }
#endif
+ unsigned& FlatTreeTraversalForbiddenRecursionDepth() {
+ return flat_tree_traversal_forbidden_recursion_depth_;
+ }
+ bool IsFlatTreeTraversalForbidden() {
+ return flat_tree_traversal_forbidden_recursion_depth_ > 0;
+ }
+
+ unsigned& SlotAssignmentRecalcDepth() {
+ return slot_assignment_recalc_depth_;
+ }
+ bool IsInSlotAssignmentRecalc() const {
+ // Since we forbid recursive slot assignement recalc, the depth should be
+ // <= 1.
+ DCHECK_LE(slot_assignment_recalc_depth_, 1u);
+ return slot_assignment_recalc_depth_ == 1;
+ }
+
bool IsVerticalScrollEnforced() const { return is_vertical_scroll_enforced_; }
bool IsLazyLoadPolicyEnforced() const;
@@ -1491,6 +1495,8 @@ class CORE_EXPORT Document : public ContainerNode,
return agent_cluster_id_;
}
+ void CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature) const override;
void ReportFeaturePolicyViolation(
mojom::FeaturePolicyFeature,
mojom::FeaturePolicyDisposition,
@@ -1506,6 +1512,14 @@ class CORE_EXPORT Document : public ContainerNode,
void IncrementNumberOfCanvases();
+ void ProcessJavaScriptUrl(const KURL&, ContentSecurityPolicyDisposition);
+ void CancelPendingJavaScriptUrl();
+
+ // Returns whether the document is inside the scope specified in the Web App
+ // Manifest. If the document doesn't run in a context of a Web App or has no
+ // associated Web App Manifest, it will return false.
+ bool IsInWebAppScope() const;
+
protected:
void DidUpdateSecurityOrigin() final;
@@ -1561,6 +1575,7 @@ class CORE_EXPORT Document : public ContainerNode,
void UpdateStyleInvalidationIfNeeded();
void UpdateStyle();
void NotifyLayoutTreeOfSubtreeChanges();
+ bool ChildrenCanHaveStyle() const final;
// ImplicitClose() actually does the work of closing the input stream.
void ImplicitClose();
@@ -1591,6 +1606,7 @@ class CORE_EXPORT Document : public ContainerNode,
void UpdateBaseURL();
void ExecuteScriptsWaitingForResources();
+ void ExecuteJavaScriptUrl(const KURL&, ContentSecurityPolicyDisposition);
void LoadEventDelayTimerFired(TimerBase*);
void PluginLoadingTimerFired(TimerBase*);
@@ -1621,8 +1637,6 @@ class CORE_EXPORT Document : public ContainerNode,
const OriginAccessEntry& AccessEntryFromURL();
- void SendSensitiveInputVisibility();
- void SendSensitiveInputVisibilityInternal();
void SendDidEditFieldInInsecureContext();
bool HaveImportsLoaded() const;
@@ -1634,6 +1648,9 @@ class CORE_EXPORT Document : public ContainerNode,
const AtomicString& BodyAttributeValue(const QualifiedName&) const;
void SetBodyAttribute(const QualifiedName&, const AtomicString&);
+ const ParsedFeaturePolicy GetOwnerContainerPolicy() const;
+ const FeaturePolicy* GetParentFeaturePolicy() const;
+
// Set the feature policy on this document, inheriting as necessary from the
// parent document and frame owner (if they exist). The caller must ensure
// that any changes to the declared policy are relayed to the embedder through
@@ -1673,12 +1690,16 @@ class CORE_EXPORT Document : public ContainerNode,
bool well_formed_;
+ // When doing find-in-page and we need to calculate style & layout tree for
+ // invisible nodes, this variable will be set with the invisible root for
+ // the currently processed block in find-in-page.
+ WeakMember<Element> find_in_page_root_;
+
// Document URLs.
KURL url_; // Document.URL: The URL from which this document was retrieved.
KURL base_url_; // Node.baseURI: The URL to use when resolving relative URLs.
- // An alternative base URL that takes precedence over base_url_ (but
- // not base_element_url_).
- KURL base_url_override_;
+ KURL base_url_override_; // An alternative base URL that takes precedence
+ // over base_url_ (but not base_element_url_).
KURL base_element_url_; // The URL set by the <base> element.
KURL cookie_url_; // The URL to use for cookie access.
std::unique_ptr<OriginAccessEntry> access_entry_from_url_;
@@ -1700,6 +1721,7 @@ class CORE_EXPORT Document : public ContainerNode,
bool compatibility_mode_locked_;
TaskHandle execute_scripts_waiting_for_resources_task_handle_;
+ TaskHandle javascript_url_task_handle_;
bool has_autofocused_;
WebFocusType last_focus_type_;
@@ -1892,12 +1914,8 @@ class CORE_EXPORT Document : public ContainerNode,
Member<PropertyRegistry> property_registry_;
- unsigned password_count_;
-
bool logged_field_edit_;
- TaskHandle sensitive_input_visibility_task_;
-
TaskHandle sensitive_input_edited_task_;
SecureContextState secure_context_state_;
@@ -1915,10 +1933,12 @@ class CORE_EXPORT Document : public ContainerNode,
#if DCHECK_IS_ON()
unsigned slot_assignment_recalc_forbidden_recursion_depth_;
#endif
+ unsigned slot_assignment_recalc_depth_ = 0;
+ unsigned flat_tree_traversal_forbidden_recursion_depth_;
bool needs_to_record_ukm_outlive_time_;
- Member<Policy> policy_;
+ Member<DOMFeaturePolicy> policy_;
Member<SlotAssignmentEngine> slot_assignment_engine_;
@@ -1950,8 +1970,15 @@ class CORE_EXPORT Document : public ContainerNode,
// Tracks which feature policies have already been parsed, so as not to count
// them multiple times.
BitVector parsed_feature_policies_;
+ // Tracks which features have already been potentially violated in this
+ // document. This helps to count them only once per page load.
+ mutable BitVector potentially_violated_features_;
AtomicString override_last_modified_;
+
+ // Map from isolated world IDs to their ContentSecurityPolicy instances.
+ Member<HeapHashMap<int, Member<ContentSecurityPolicy>>>
+ isolated_world_csp_map_;
};
extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Document>;
diff --git a/chromium/third_party/blink/renderer/core/dom/document.idl b/chromium/third_party/blink/renderer/core/dom/document.idl
index 0477c21d353..bcd542a6ed1 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.idl
+++ b/chromium/third_party/blink/renderer/core/dom/document.idl
@@ -20,7 +20,7 @@
[Custom] callback CustomElementConstructor = Element ();
-// https://html.spec.whatwg.org/#the-document-object
+// https://html.spec.whatwg.org/C/#the-document-object
enum DocumentReadyState { "loading", "interactive", "complete" };
@@ -33,7 +33,7 @@ enum AddressSpace { "local", "private", "public" };
typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// https://dom.spec.whatwg.org/#interface-document
-// https://html.spec.whatwg.org/multipage/dom.html#documents
+// https://html.spec.whatwg.org/C/#documents
[
Constructor(),
@@ -74,11 +74,6 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[NewObject] Range createRange();
- [CallWith=ScriptState, NewObject, RaisesException, RuntimeEnabled=ConstructableStylesheets] Promise<CSSStyleSheet> createCSSStyleSheet(DOMString text, optional CSSStyleSheetInit options);
- [CallWith=ScriptState, NewObject, RaisesException, RuntimeEnabled=ConstructableStylesheets] CSSStyleSheet createCSSStyleSheetSync(DOMString text, optional CSSStyleSheetInit options);
- [CallWith=ScriptState, NewObject, RaisesException, RuntimeEnabled=ConstructableStylesheets] CSSStyleSheet createEmptyCSSStyleSheet(optional CSSStyleSheetInit options);
-
-
// NodeFilter.SHOW_ALL = 0xFFFFFFFF
[NewObject] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
[NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
@@ -121,16 +116,18 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[ImplementedAs=currentScriptForBinding] readonly attribute HTMLOrSVGScriptElement? currentScript;
// dynamic markup insertion
- [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = "");
- [CallWith=(CurrentWindow,EnteredWindow), RaisesException, MeasureAs=DocumentOpenThreeArgs] Window open(URLString url, DOMString name, DOMString features);
+ [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = "");
+ [CallWith=Isolate, RaisesException, MeasureAs=DocumentOpenThreeArgs] Window open(URLString url, DOMString name, DOMString features);
[CEReactions, RaisesException] void close();
- [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void write(DOMString... text);
- [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void writeln(DOMString... text);
+ [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void write(DOMString... text);
+ [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void writeln(DOMString... text);
// TrustedTypes variants of the above.
- // TODO(mkwst): Write a spec for this.
- [RuntimeEnabled=TrustedDOMTypes, CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void write(TrustedHTML text);
- [RuntimeEnabled=TrustedDOMTypes, CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void writeln(TrustedHTML text);
+ // Note: This should be gated on [OriginTrialEnabled=TrustedDOMTypes], but
+ // since OriginTrialEnabled isn't compatible with overloaded methods, we're
+ // handling these unconditionally.
+ [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void write(TrustedHTML text);
+ [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void writeln(TrustedHTML text);
// user interaction
[Affects=Nothing] readonly attribute Window? defaultView;
@@ -174,7 +171,7 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// Custom Elements
// https://w3c.github.io/webcomponents/spec/custom/#extensions-to-document-interface-to-register
// FIXME: The registerElement return type should be Function.
- [RuntimeEnabled=CustomElementsV0, CallWith=ScriptState, CustomElementCallbacks, RaisesException, DeprecateAs=DocumentRegisterElement] any registerElement(DOMString type, optional ElementRegistrationOptions options);
+ [OriginTrialEnabled=CustomElementsV0, CallWith=ScriptState, CustomElementCallbacks, RaisesException, DeprecateAs=DocumentRegisterElement] any registerElement(DOMString type, optional ElementRegistrationOptions options);
// https://w3c.github.io/webcomponents/spec/custom/#extensions-to-document-interface-to-instantiate
[CustomElementCallbacks, PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName, (DOMString or ElementCreationOptions) options);
[CustomElementCallbacks, RaisesException] Element createElementNS(DOMString? namespaceURI, DOMString qualifiedName, (DOMString or ElementCreationOptions) options);
@@ -190,14 +187,11 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[RuntimeEnabled=CorsRFC1918, ImplementedAs=addressSpaceForBindings] readonly attribute AddressSpace addressSpace;
// Non-standard APIs
- [MeasureAs=DocumentCaretRangeFromPoint] Range caretRangeFromPoint([Default=Undefined] optional long x, [Default=Undefined] optional long y);
+ [MeasureAs=DocumentCaretRangeFromPoint] Range caretRangeFromPoint([DefaultValue=Undefined] optional long x, [DefaultValue=Undefined] optional long y);
- // https://wicg.github.io/feature-policy
- // TODO(iclelland): add spec for JS exposure in the spec for Feature Policy.
- // Please refer to this doc for more details for now:
- // https://docs.google.com/a/chromium.org/document/d/1wvk3cXkblNnbkMcsKayseK-k0SMGiP9b9fQFgfpqQpc/edit?usp=sharing
- [OriginTrialEnabled=FeaturePolicyJavaScriptInterface] readonly attribute Policy policy;
+ // https://wicg.github.io/feature-policy/#the-policy-object
+ [OriginTrialEnabled=FeaturePolicyJavaScriptInterface] readonly attribute FeaturePolicy featurePolicy;
// Deprecated prefixed page visibility API.
// TODO(davidben): This is a property so attaching a deprecation warning results in false positives when outputting
diff --git a/chromium/third_party/blink/renderer/core/dom/document_init.cc b/chromium/third_party/blink/renderer/core/dom/document_init.cc
index a1db021d271..0c1eb95414c 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_init.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_init.cc
@@ -76,10 +76,9 @@ bool DocumentInit::ShouldSetURL() const {
return (loader && loader->GetFrame()->Tree().Parent()) || !url_.IsEmpty();
}
-bool DocumentInit::ShouldTreatURLAsSrcdocDocument() const {
- return parent_document_ &&
- document_loader_->GetFrame()->Loader().ShouldTreatURLAsSrcdocDocument(
- url_);
+bool DocumentInit::IsSrcdocDocument() const {
+ // TODO(dgozman): why do we check |parent_document_| here?
+ return parent_document_ && is_srcdoc_document_;
}
DocumentLoader* DocumentInit::MasterDocumentLoader() const {
@@ -168,10 +167,32 @@ DocumentInit& DocumentInit::WithURL(const KURL& url) {
DocumentInit& DocumentInit::WithOwnerDocument(Document* owner_document) {
DCHECK(!owner_document_);
+ DCHECK(!initiator_origin_ || !owner_document ||
+ owner_document->GetSecurityOrigin() == initiator_origin_);
owner_document_ = owner_document;
return *this;
}
+DocumentInit& DocumentInit::WithInitiatorOrigin(
+ scoped_refptr<const SecurityOrigin> initiator_origin) {
+ DCHECK(!initiator_origin_);
+ DCHECK(!initiator_origin || !owner_document_ ||
+ owner_document_->GetSecurityOrigin() == initiator_origin);
+ initiator_origin_ = std::move(initiator_origin);
+ return *this;
+}
+
+DocumentInit& DocumentInit::WithOriginToCommit(
+ scoped_refptr<SecurityOrigin> origin_to_commit) {
+ origin_to_commit_ = std::move(origin_to_commit);
+ return *this;
+}
+
+DocumentInit& DocumentInit::WithSrcdocDocument(bool is_srcdoc_document) {
+ is_srcdoc_document_ = is_srcdoc_document;
+ return *this;
+}
+
DocumentInit& DocumentInit::WithRegistrationContext(
V0CustomElementRegistrationContext* registration_context) {
DCHECK(!create_new_registration_context_);
@@ -202,11 +223,4 @@ Document* DocumentInit::ContextDocument() const {
return context_document_;
}
-DocumentInit& DocumentInit::WithPreviousDocumentCSP(
- const ContentSecurityPolicy* previous_csp) {
- DCHECK(!previous_csp_);
- previous_csp_ = previous_csp;
- return *this;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/document_init.h b/chromium/third_party/blink/renderer/core/dom/document_init.h
index ef4787d86ab..1848849969c 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_init.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_init.h
@@ -72,7 +72,7 @@ class CORE_EXPORT DocumentInit final {
}
bool HasSecurityContext() const { return MasterDocumentLoader(); }
- bool ShouldTreatURLAsSrcdocDocument() const;
+ bool IsSrcdocDocument() const;
bool ShouldSetURL() const;
SandboxFlags GetSandboxFlags() const;
bool IsHostedInReservedIPRange() const;
@@ -97,15 +97,27 @@ class CORE_EXPORT DocumentInit final {
DocumentInit& WithOwnerDocument(Document*);
Document* OwnerDocument() const { return owner_document_.Get(); }
+ // Specifies the SecurityOrigin in which the URL was requested. This is
+ // relevant for determining properties of the resulting document's origin
+ // when loading data: and about: schemes.
+ DocumentInit& WithInitiatorOrigin(
+ scoped_refptr<const SecurityOrigin> initiator_origin);
+ const scoped_refptr<const SecurityOrigin>& InitiatorOrigin() const {
+ return initiator_origin_;
+ }
+
+ DocumentInit& WithOriginToCommit(
+ scoped_refptr<SecurityOrigin> origin_to_commit);
+ const scoped_refptr<SecurityOrigin>& OriginToCommit() const {
+ return origin_to_commit_;
+ }
+
+ DocumentInit& WithSrcdocDocument(bool is_srcdoc_document);
+
DocumentInit& WithRegistrationContext(V0CustomElementRegistrationContext*);
V0CustomElementRegistrationContext* RegistrationContext(Document*) const;
DocumentInit& WithNewRegistrationContext();
- DocumentInit& WithPreviousDocumentCSP(const ContentSecurityPolicy*);
- const ContentSecurityPolicy* PreviousDocumentCSP() const {
- return previous_csp_.Get();
- }
-
private:
DocumentInit(HTMLImportsController*);
@@ -124,10 +136,32 @@ class CORE_EXPORT DocumentInit final {
KURL url_;
Member<Document> owner_document_;
+ // Initiator origin is used for calculating the document origin when the
+ // navigation is started in a different process. In such cases, the document
+ // which initiates the navigation sends its origin to the browser process and
+ // it is provided by the browser process here. It is used for cases such as
+ // data: URLs, which inherit their origin from the initiator of the
+ // navigation.
+ // Note: about:blank should also behave this way, however currently it
+ // inherits its origin from the parent frame or opener, regardless of whether
+ // it is the initiator or not.
+ scoped_refptr<const SecurityOrigin> initiator_origin_;
+
+ // The |origin_to_commit_| is to be used directly without calculating the
+ // document origin at initialization time. It is specified by the browser
+ // process for session history navigations. This allows us to preserve
+ // the origin across session history and ensure the exact same origin
+ // is present on such navigations to URLs that inherit their origins (e.g.
+ // about:blank and data: URLs).
+ scoped_refptr<SecurityOrigin> origin_to_commit_;
+
+ // Whether we should treat the new document as "srcdoc" document. This
+ // affects security checks, since srcdoc's content comes directly from
+ // the parent document, not from loading a URL.
+ bool is_srcdoc_document_ = false;
+
Member<V0CustomElementRegistrationContext> registration_context_;
bool create_new_registration_context_;
-
- Member<const ContentSecurityPolicy> previous_csp_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/document_lifecycle.cc b/chromium/third_party/blink/renderer/core/dom/document_lifecycle.cc
index 179903bc14d..2a1c3b4d032 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_lifecycle.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_lifecycle.cc
@@ -137,10 +137,10 @@ bool DocumentLifecycle::CanAdvanceTo(LifecycleState next_state) const {
return true;
if (next_state == kLayoutClean)
return true;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInCompositingUpdate)
return true;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInPrePaint)
return true;
break;
@@ -160,10 +160,10 @@ bool DocumentLifecycle::CanAdvanceTo(LifecycleState next_state) const {
return true;
if (next_state == kLayoutClean)
return true;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInCompositingUpdate)
return true;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInPrePaint)
return true;
break;
@@ -200,21 +200,21 @@ bool DocumentLifecycle::CanAdvanceTo(LifecycleState next_state) const {
return true;
if (next_state == kStyleClean)
return true;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInCompositingUpdate)
return true;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInPrePaint)
return true;
break;
case kInCompositingUpdate:
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
// Once we are in the compositing update, we can either just clean the
// inputs or do the whole of compositing.
return next_state == kCompositingInputsClean ||
next_state == kCompositingClean;
case kCompositingInputsClean:
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
// We can return to style re-calc, layout, or the start of compositing.
if (next_state == kInStyleRecalc)
return true;
@@ -227,7 +227,7 @@ bool DocumentLifecycle::CanAdvanceTo(LifecycleState next_state) const {
return true;
break;
case kCompositingClean:
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
if (next_state == kInStyleRecalc)
return true;
if (next_state == kInPreLayout)
@@ -248,7 +248,7 @@ bool DocumentLifecycle::CanAdvanceTo(LifecycleState next_state) const {
return true;
if (next_state == kInPreLayout)
return true;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInCompositingUpdate)
return true;
if (next_state == kInPrePaint)
@@ -263,7 +263,7 @@ bool DocumentLifecycle::CanAdvanceTo(LifecycleState next_state) const {
return true;
if (next_state == kInPreLayout)
return true;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
next_state == kInCompositingUpdate)
return true;
if (next_state == kInPrePaint)
diff --git a/chromium/third_party/blink/renderer/core/dom/document_lifecycle.h b/chromium/third_party/blink/renderer/core/dom/document_lifecycle.h
index 5d02b2874ec..5e339f6e98a 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_lifecycle.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_lifecycle.h
@@ -77,7 +77,7 @@ class CORE_EXPORT DocumentLifecycle {
// In InPaint step, paint artifacts are generated and raster invalidations
// are issued.
- // In SPv2, composited layers are generated/updated.
+ // In CAP, composited layers are generated/updated.
kInPaint,
kPaintClean,
diff --git a/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h b/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h
index a319c1210ca..0b5d46d66cd 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h
@@ -30,13 +30,15 @@ class DocumentOrShadowRoot {
return &shadow_root.StyleSheets();
}
- static StyleSheetList* adoptedStyleSheets(TreeScope& tree_scope) {
- return &tree_scope.AdoptedStyleSheets();
+ static const HeapVector<Member<CSSStyleSheet>>& adoptedStyleSheets(
+ TreeScope& tree_scope) {
+ return tree_scope.AdoptedStyleSheets();
}
- static void setAdoptedStyleSheets(TreeScope& tree_scope,
- StyleSheetList* adopted_style_sheets,
- ExceptionState& exception_state) {
+ static void setAdoptedStyleSheets(
+ TreeScope& tree_scope,
+ HeapVector<Member<CSSStyleSheet>>& adopted_style_sheets,
+ ExceptionState& exception_state) {
tree_scope.SetAdoptedStyleSheets(adopted_style_sheets, exception_state);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.idl b/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.idl
index ac5e1fcd3f1..b7242fc1fcc 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.idl
+++ b/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.idl
@@ -23,5 +23,5 @@
// Fullscreen API
// https://fullscreen.spec.whatwg.org/
[LenientSetter, RuntimeEnabled=FullscreenUnprefixed] readonly attribute Element? fullscreenElement;
- [RuntimeEnabled=ConstructableStylesheets, RaisesException=Setter] attribute StyleSheetList adoptedStyleSheets;
+ [RaisesException=Setter] attribute FrozenArray<CSSStyleSheet> adoptedStyleSheets;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/document_parser.cc b/chromium/third_party/blink/renderer/core/dom/document_parser.cc
index 996d00c591c..4b5ad3abc09 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_parser.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_parser.cc
@@ -42,7 +42,7 @@ DocumentParser::DocumentParser(Document* document)
DocumentParser::~DocumentParser() = default;
-void DocumentParser::Trace(blink::Visitor* visitor) {
+void DocumentParser::Trace(Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(clients_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/document_parser.h b/chromium/third_party/blink/renderer/core/dom/document_parser.h
index 9ffd54d4286..16860fde376 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_parser.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_parser.h
@@ -42,7 +42,7 @@ class CORE_EXPORT DocumentParser
public NameClient {
public:
virtual ~DocumentParser();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
const char* NameInHeapSnapshot() const override { return "DocumentParser"; }
virtual ScriptableDocumentParser* AsScriptableDocumentParser() {
diff --git a/chromium/third_party/blink/renderer/core/dom/document_parser_client.h b/chromium/third_party/blink/renderer/core/dom/document_parser_client.h
index 0f199fda727..bdc55f19124 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_parser_client.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_parser_client.h
@@ -14,7 +14,7 @@ class DocumentParserClient : public GarbageCollectedMixin {
// This callback is called when all data pushed to parser has been consumed.
virtual void NotifyParserStopped() = 0;
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
protected:
DocumentParserClient() = default;
diff --git a/chromium/third_party/blink/renderer/core/dom/document_parser_timing.cc b/chromium/third_party/blink/renderer/core/dom/document_parser_timing.cc
index d184e49935d..044ea560e91 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_parser_timing.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_parser_timing.cc
@@ -66,7 +66,7 @@ void DocumentParserTiming::RecordParserBlockedOnScriptExecutionDuration(
NotifyDocumentParserTimingChanged();
}
-void DocumentParserTiming::Trace(blink::Visitor* visitor) {
+void DocumentParserTiming::Trace(Visitor* visitor) {
Supplement<Document>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/document_parser_timing.h b/chromium/third_party/blink/renderer/core/dom/document_parser_timing.h
index 8cd533d7092..98dbc0b17dc 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_parser_timing.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_parser_timing.h
@@ -97,7 +97,7 @@ class DocumentParserTiming final
return parser_blocked_on_script_execution_from_document_write_duration_;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void NotifyDocumentParserTimingChanged();
diff --git a/chromium/third_party/blink/renderer/core/dom/document_test.cc b/chromium/third_party/blink/renderer/core/dom/document_test.cc
index f20a13bac88..3ce1a808061 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_test.cc
@@ -32,6 +32,7 @@
#include <memory>
+#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -97,7 +98,7 @@ class TestSynchronousMutationObserver
node_to_be_removed_(node_with_index.GetNode()),
offset_(offset) {}
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(node_);
visitor->Trace(node_to_be_removed_);
}
@@ -119,7 +120,7 @@ class TestSynchronousMutationObserver
old_length_(old_length),
new_length_(new_length) {}
- void Trace(blink::Visitor* visitor) { visitor->Trace(node_); }
+ void Trace(Visitor* visitor) { visitor->Trace(node_); }
};
TestSynchronousMutationObserver(Document&);
@@ -159,7 +160,7 @@ class TestSynchronousMutationObserver
return updated_character_data_records_;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// Implement |SynchronousMutationObserver| member functions.
@@ -206,7 +207,8 @@ void TestSynchronousMutationObserver::DidMergeTextNodes(
const NodeWithIndex& node_with_index,
unsigned offset) {
merge_text_nodes_records_.push_back(
- new MergeTextNodesRecord(&node, node_with_index, offset));
+ MakeGarbageCollected<MergeTextNodesRecord>(&node, node_with_index,
+ offset));
}
void TestSynchronousMutationObserver::DidMoveTreeToNewDocument(
@@ -223,8 +225,9 @@ void TestSynchronousMutationObserver::DidUpdateCharacterData(
unsigned offset,
unsigned old_length,
unsigned new_length) {
- updated_character_data_records_.push_back(new UpdateCharacterDataRecord(
- character_data, offset, old_length, new_length));
+ updated_character_data_records_.push_back(
+ MakeGarbageCollected<UpdateCharacterDataRecord>(character_data, offset,
+ old_length, new_length));
}
void TestSynchronousMutationObserver::NodeChildrenWillBeRemoved(
@@ -236,7 +239,7 @@ void TestSynchronousMutationObserver::NodeWillBeRemoved(Node& node) {
removed_nodes_.push_back(&node);
}
-void TestSynchronousMutationObserver::Trace(blink::Visitor* visitor) {
+void TestSynchronousMutationObserver::Trace(Visitor* visitor) {
visitor->Trace(children_changed_nodes_);
visitor->Trace(merge_text_nodes_records_);
visitor->Trace(move_tree_to_new_document_nodes_);
@@ -260,7 +263,7 @@ class TestDocumentShutdownObserver
return context_destroyed_called_counter_;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// Implement |DocumentShutdownObserver| member functions.
@@ -279,7 +282,7 @@ void TestDocumentShutdownObserver::ContextDestroyed(Document*) {
++context_destroyed_called_counter_;
}
-void TestDocumentShutdownObserver::Trace(blink::Visitor* visitor) {
+void TestDocumentShutdownObserver::Trace(Visitor* visitor) {
DocumentShutdownObserver::Trace(visitor);
}
@@ -314,7 +317,7 @@ class MockDocumentValidationMessageClient
}
void WillBeDestroyed() override {}
- // virtual void Trace(blink::Visitor* visitor) {
+ // virtual void Trace(Visitor* visitor) {
// ValidationMessageClient::trace(visitor); }
};
@@ -626,7 +629,8 @@ TEST_F(DocumentTest, EnforceSandboxFlags) {
}
TEST_F(DocumentTest, SynchronousMutationNotifier) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
EXPECT_EQ(GetDocument(), observer.LifecycleContext());
EXPECT_EQ(0, observer.CountContextDestroyedCalled());
@@ -660,14 +664,16 @@ TEST_F(DocumentTest, SynchronousMutationNotifier) {
}
TEST_F(DocumentTest, SynchronousMutationNotifieAppendChild) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
GetDocument().body()->AppendChild(GetDocument().createTextNode("a123456789"));
ASSERT_EQ(1u, observer.ChildrenChangedNodes().size());
EXPECT_EQ(GetDocument().body(), observer.ChildrenChangedNodes()[0]);
}
TEST_F(DocumentTest, SynchronousMutationNotifieInsertBefore) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
GetDocument().documentElement()->InsertBefore(
GetDocument().createTextNode("a123456789"), GetDocument().body());
ASSERT_EQ(1u, observer.ChildrenChangedNodes().size());
@@ -676,7 +682,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifieInsertBefore) {
}
TEST_F(DocumentTest, SynchronousMutationNotifierMergeTextNodes) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
Text* merge_sample_a = GetDocument().createTextNode("a123456789");
GetDocument().body()->AppendChild(merge_sample_a);
@@ -695,7 +702,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifierMergeTextNodes) {
}
TEST_F(DocumentTest, SynchronousMutationNotifierMoveTreeToNewDocument) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
Node* move_sample = GetDocument().CreateRawElement(html_names::kDivTag);
move_sample->appendChild(GetDocument().createTextNode("a123"));
@@ -710,7 +718,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifierMoveTreeToNewDocument) {
}
TEST_F(DocumentTest, SynchronousMutationNotifieRemoveChild) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
GetDocument().documentElement()->RemoveChild(GetDocument().body());
ASSERT_EQ(1u, observer.ChildrenChangedNodes().size());
EXPECT_EQ(GetDocument().documentElement(),
@@ -718,7 +727,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifieRemoveChild) {
}
TEST_F(DocumentTest, SynchronousMutationNotifieReplaceChild) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
Element* const replaced_node = GetDocument().body();
GetDocument().documentElement()->ReplaceChild(
GetDocument().CreateRawElement(html_names::kDivTag),
@@ -735,7 +745,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifieReplaceChild) {
TEST_F(DocumentTest, SynchronousMutationNotifierSplitTextNode) {
V8TestingScope scope;
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
Text* split_sample = GetDocument().createTextNode("0123456789");
GetDocument().body()->AppendChild(split_sample);
@@ -746,7 +757,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifierSplitTextNode) {
}
TEST_F(DocumentTest, SynchronousMutationNotifierUpdateCharacterData) {
- auto& observer = *new TestSynchronousMutationObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestSynchronousMutationObserver>(GetDocument());
Text* append_sample = GetDocument().createTextNode("a123456789");
GetDocument().body()->AppendChild(append_sample);
@@ -792,7 +804,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifierUpdateCharacterData) {
}
TEST_F(DocumentTest, DocumentShutdownNotifier) {
- auto& observer = *new TestDocumentShutdownObserver(GetDocument());
+ auto& observer =
+ *MakeGarbageCollected<TestDocumentShutdownObserver>(GetDocument());
EXPECT_EQ(GetDocument(), observer.LifecycleContext());
EXPECT_EQ(0, observer.CountContextDestroyedCalled());
@@ -825,7 +838,7 @@ TEST_F(DocumentTest, ValidationMessageCleanup) {
ValidationMessageClient* original_client =
&GetPage().GetValidationMessageClient();
MockDocumentValidationMessageClient* mock_client =
- new MockDocumentValidationMessageClient();
+ MakeGarbageCollected<MockDocumentValidationMessageClient>();
GetDocument().GetSettings()->SetScriptEnabled(true);
GetPage().SetValidationMessageClientForTesting(mock_client);
// ImplicitOpen()-CancelParsing() makes Document.loadEventFinished()
@@ -966,6 +979,99 @@ TEST_F(DocumentTest, InterfaceInvalidatorDestruction) {
EXPECT_EQ(1, obs.CountInvalidateCalled());
}
+// Test fixture parameterized on whether the "IsolatedWorldCSP" feature is
+// enabled.
+class IsolatedWorldCSPTest : public DocumentTest,
+ public testing::WithParamInterface<bool> {
+ public:
+ IsolatedWorldCSPTest() {
+ RuntimeEnabledFeatures::SetIsolatedWorldCSPEnabled(GetParam());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IsolatedWorldCSPTest);
+};
+
+// Tests ExecutionContext::GetContentSecurityPolicyForWorld().
+TEST_P(IsolatedWorldCSPTest, CSPForWorld) {
+ using ::testing::ElementsAre;
+
+ // Set a CSP for the main world.
+ const char* kMainWorldCSP = "connect-src https://google.com;";
+ GetDocument().GetContentSecurityPolicy()->DidReceiveHeader(
+ kMainWorldCSP, kContentSecurityPolicyHeaderTypeEnforce,
+ kContentSecurityPolicyHeaderSourceHTTP);
+
+ LocalFrame* frame = GetDocument().GetFrame();
+ ScriptState* main_world_script_state = ToScriptStateForMainWorld(frame);
+ v8::Isolate* isolate = main_world_script_state->GetIsolate();
+
+ constexpr int kIsolatedWorldWithoutCSPId = 1;
+ scoped_refptr<DOMWrapperWorld> world_without_csp =
+ DOMWrapperWorld::EnsureIsolatedWorld(isolate, kIsolatedWorldWithoutCSPId);
+ ASSERT_TRUE(world_without_csp->IsIsolatedWorld());
+ ScriptState* isolated_world_without_csp_script_state =
+ ToScriptState(frame, *world_without_csp);
+
+ const char* kIsolatedWorldCSP = "script-src 'none';";
+ constexpr int kIsolatedWorldWithCSPId = 2;
+ scoped_refptr<DOMWrapperWorld> world_with_csp =
+ DOMWrapperWorld::EnsureIsolatedWorld(isolate, kIsolatedWorldWithCSPId);
+ ASSERT_TRUE(world_with_csp->IsIsolatedWorld());
+ ScriptState* isolated_world_with_csp_script_state =
+ ToScriptState(frame, *world_with_csp);
+ IsolatedWorldCSP::Get().SetContentSecurityPolicy(
+ kIsolatedWorldWithCSPId, kIsolatedWorldCSP,
+ SecurityOrigin::Create(KURL("chrome-extension://123")));
+
+ // Returns the csp headers being used for the current world.
+ auto get_csp_headers = [this]() {
+ return GetDocument().GetContentSecurityPolicyForWorld()->Headers();
+ };
+
+ {
+ SCOPED_TRACE("In main world.");
+ ScriptState::Scope scope(main_world_script_state);
+ EXPECT_THAT(get_csp_headers(),
+ ElementsAre(CSPHeaderAndType(
+ {kMainWorldCSP, kContentSecurityPolicyHeaderTypeEnforce})));
+ }
+
+ {
+ SCOPED_TRACE("In isolated world without csp.");
+ ScriptState::Scope scope(isolated_world_without_csp_script_state);
+
+ // If we are in an isolated world with no CSP defined, we use the main world
+ // CSP.
+ EXPECT_THAT(get_csp_headers(),
+ ElementsAre(CSPHeaderAndType(
+ {kMainWorldCSP, kContentSecurityPolicyHeaderTypeEnforce})));
+ }
+
+ {
+ bool is_isolated_world_csp_enabled = GetParam();
+ SCOPED_TRACE(base::StringPrintf(
+ "In isolated world with csp and 'IsolatedWorldCSP' %s",
+ is_isolated_world_csp_enabled ? "enabled" : "disabled"));
+ ScriptState::Scope scope(isolated_world_with_csp_script_state);
+
+ if (!is_isolated_world_csp_enabled) {
+ // With 'IsolatedWorldCSP' feature disabled, we should just bypass the
+ // main world CSP by using an empty CSP.
+ EXPECT_TRUE(get_csp_headers().IsEmpty());
+ } else {
+ // With 'IsolatedWorldCSP' feature enabled, we use the isolated world's
+ // CSP if it specified one.
+ EXPECT_THAT(
+ get_csp_headers(),
+ ElementsAre(CSPHeaderAndType(
+ {kIsolatedWorldCSP, kContentSecurityPolicyHeaderTypeEnforce})));
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(, IsolatedWorldCSPTest, testing::Values(true, false));
+
TEST_F(DocumentTest, CanExecuteScriptsWithSandboxAndIsolatedWorld) {
constexpr SandboxFlags kSandboxMask = kSandboxScripts;
GetDocument().EnforceSandboxFlags(kSandboxMask);
@@ -988,7 +1094,8 @@ TEST_F(DocumentTest, CanExecuteScriptsWithSandboxAndIsolatedWorld) {
scoped_refptr<DOMWrapperWorld> world_with_csp =
DOMWrapperWorld::EnsureIsolatedWorld(isolate, kIsolatedWorldWithCSPId);
IsolatedWorldCSP::Get().SetContentSecurityPolicy(
- kIsolatedWorldWithCSPId, String::FromUTF8("script-src *"));
+ kIsolatedWorldWithCSPId, String::FromUTF8("script-src *"),
+ SecurityOrigin::Create(KURL("chrome-extension://123")));
ScriptState* isolated_world_with_csp_script_state =
ToScriptState(frame, *world_with_csp);
ASSERT_TRUE(world_with_csp->IsIsolatedWorld());
diff --git a/chromium/third_party/blink/renderer/core/dom/document_timing.cc b/chromium/third_party/blink/renderer/core/dom/document_timing.cc
index 2644b1ec1a4..bf58fc556fa 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_timing.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_timing.cc
@@ -14,7 +14,7 @@ namespace blink {
DocumentTiming::DocumentTiming(Document& document) : document_(document) {}
-void DocumentTiming::Trace(blink::Visitor* visitor) {
+void DocumentTiming::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/document_timing.h b/chromium/third_party/blink/renderer/core/dom/document_timing.h
index 6fb3303bda5..5aed8975f2c 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_timing.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_timing.h
@@ -59,7 +59,7 @@ class DocumentTiming final {
TimeTicks DomComplete() const { return dom_complete_; }
TimeTicks FirstLayout() const { return first_layout_; }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
LocalFrame* GetFrame() const;
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc b/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc
index 3dac1a5a6f6..31d7915a56b 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc
+++ b/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc
@@ -292,7 +292,7 @@ Document* DOMImplementation::createDocument(const String& type,
return HTMLDocument::Create(init);
}
-void DOMImplementation::Trace(blink::Visitor* visitor) {
+void DOMImplementation::Trace(Visitor* visitor) {
visitor->Trace(document_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_implementation.h b/chromium/third_party/blink/renderer/core/dom/dom_implementation.h
index b30c6f1b66d..42b802d97ed 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_implementation.h
+++ b/chromium/third_party/blink/renderer/core/dom/dom_implementation.h
@@ -68,7 +68,7 @@ class CORE_EXPORT DOMImplementation final : public ScriptWrappable {
static bool IsTextMIMEType(const String&);
static bool IsJSONMIMEType(const String&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<Document> document_;
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc b/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc
index b4b6a439367..b20d2b259d8 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc
+++ b/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc
@@ -78,7 +78,7 @@ bool CheckTokensSyntax(const Vector<String>& tokens,
} // anonymous namespace
-void DOMTokenList::Trace(blink::Visitor* visitor) {
+void DOMTokenList::Trace(Visitor* visitor) {
visitor->Trace(element_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_token_list.h b/chromium/third_party/blink/renderer/core/dom/dom_token_list.h
index 00c1f1f2319..b375512d5ec 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_token_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/dom_token_list.h
@@ -49,7 +49,7 @@ class CORE_EXPORT DOMTokenList : public ScriptWrappable {
DOMTokenList(Element& element, const QualifiedName& attr)
: element_(element), attribute_name_(attr) {}
~DOMTokenList() override = default;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
unsigned length() const { return token_set_.size(); }
const AtomicString item(unsigned index) const;
diff --git a/chromium/third_party/blink/renderer/core/dom/element.cc b/chromium/third_party/blink/renderer/core/dom/element.cc
index c0561e2fc14..c971b86f411 100644
--- a/chromium/third_party/blink/renderer/core/dom/element.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element.cc
@@ -36,7 +36,7 @@
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script_url.h"
#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_options.h"
#include "third_party/blink/renderer/core/accessibility/ax_context.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/animation/css/css_animations.h"
@@ -468,7 +468,7 @@ void Element::SynchronizeAttribute(const AtomicString& local_name) const {
// animated SVG Attribute. It would seem we should only call this method
// if SVGElement::isAnimatableAttribute is true, but the list of
// animatable attributes in isAnimatableAttribute does not suffice to
- // pass all layout tests. Also, animated_svg_attributes_are_dirty_ stays
+ // pass all web tests. Also, animated_svg_attributes_are_dirty_ stays
// dirty unless SynchronizeAnimatedSVGAttribute is called with
// AnyQName(). This means that even if Element::SynchronizeAttribute()
// is called on all attributes, animated_svg_attributes_are_dirty_ remains
@@ -1267,6 +1267,10 @@ InvisibleState Element::Invisible() const {
return InvisibleState::kInvisible;
}
+bool Element::HasInvisibleAttribute() const {
+ return Invisible() != InvisibleState::kMissing;
+}
+
void Element::DispatchActivateInvisibleEventIfNeeded() {
if (!RuntimeEnabledFeatures::InvisibleDOMEnabled())
return;
@@ -1480,9 +1484,23 @@ void Element::setAttribute(
ExceptionState& exception_state) {
// TODO(vogelheim): Check whether this applies to non-HTML documents, too.
AtomicString name_lowercase = LowercaseIfNecessary(name);
- if (GetCheckedAttributeNames().Contains(name_lowercase)) {
- String attr_value =
- GetStringFromTrustedType(string_or_TT, &GetDocument(), exception_state);
+ const AttrNameToTrustedType* attribute_types = &GetCheckedAttributeTypes();
+ AttrNameToTrustedType::const_iterator it =
+ attribute_types->find(name_lowercase);
+ if (it != attribute_types->end()) {
+ String attr_value = GetStringFromSpecificTrustedType(
+ string_or_TT, it->value, &GetDocument(), exception_state);
+ if (!exception_state.HadException())
+ setAttribute(name_lowercase, AtomicString(attr_value), exception_state);
+ return;
+ } else if (name_lowercase.StartsWith("on")) {
+ // TODO(jakubvrana): This requires TrustedScript in all attributes starting
+ // with "on", including e.g. "one". We use this pattern elsewhere (e.g. in
+ // IsEventHandlerAttribute) but it's not ideal. Consider using the event
+ // attribute of the resulting AttributeTriggers.
+ String attr_value = GetStringFromSpecificTrustedType(
+ string_or_TT, SpecificTrustedType::kTrustedScript, &GetDocument(),
+ exception_state);
if (!exception_state.HadException())
setAttribute(name_lowercase, AtomicString(attr_value), exception_state);
return;
@@ -1492,9 +1510,9 @@ void Element::setAttribute(
setAttribute(name_lowercase, value_string, exception_state);
}
-const HashSet<AtomicString>& Element::GetCheckedAttributeNames() const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({}));
- return attribute_set;
+const AttrNameToTrustedType& Element::GetCheckedAttributeTypes() const {
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map, ({}));
+ return attribute_map;
}
void Element::setAttribute(const QualifiedName& name,
@@ -1897,17 +1915,15 @@ Node::InsertionNotificationRequest Element::InsertedInto(
if (LocalFrameView* frame_view = GetDocument().View())
frame_view->SetIntersectionObservationState(LocalFrameView::kRequired);
}
- if (rare_data->GetDisplayLockContext())
- rare_data->GetDisplayLockContext()->NotifyConnectedMayHaveChanged();
}
if (isConnected()) {
if (GetCustomElementState() == CustomElementState::kCustom)
- CustomElement::EnqueueConnectedCallback(this);
+ CustomElement::EnqueueConnectedCallback(*this);
else if (IsUpgradedV0CustomElement())
V0CustomElement::DidAttach(this, GetDocument());
else if (GetCustomElementState() == CustomElementState::kUndefined)
- CustomElement::TryToUpgrade(this);
+ CustomElement::TryToUpgrade(*this);
}
TreeScope& scope = insertion_point.GetTreeScope();
@@ -1938,8 +1954,6 @@ void Element::RemovedFrom(ContainerNode& insertion_point) {
// pseudo elements.
ElementRareData* rare_data = GetElementRareData();
rare_data->ClearPseudoElements();
- if (rare_data->GetDisplayLockContext())
- rare_data->GetDisplayLockContext()->NotifyConnectedMayHaveChanged();
}
if (Fullscreen::IsFullscreenElement(*this)) {
@@ -1973,7 +1987,7 @@ void Element::RemovedFrom(ContainerNode& insertion_point) {
GetDocument().SetCSSTarget(nullptr);
if (GetCustomElementState() == CustomElementState::kCustom)
- CustomElement::EnqueueDisconnectedCallback(this);
+ CustomElement::EnqueueDisconnectedCallback(*this);
else if (IsUpgradedV0CustomElement())
V0CustomElement::DidDetach(this, insertion_point.GetDocument());
}
@@ -2137,7 +2151,8 @@ void Element::DetachLayoutTree(const AttachContext& context) {
DCHECK(NeedsAttach());
}
-scoped_refptr<ComputedStyle> Element::StyleForLayoutObject() {
+scoped_refptr<ComputedStyle> Element::StyleForLayoutObject(
+ bool calc_invisible) {
DCHECK(GetDocument().InStyleRecalc());
// FIXME: Instead of clearing updates that may have been added from calls to
@@ -2147,7 +2162,7 @@ scoped_refptr<ComputedStyle> Element::StyleForLayoutObject() {
element_animations->CssAnimations().ClearPendingUpdate();
if (RuntimeEnabledFeatures::InvisibleDOMEnabled() &&
- hasAttribute(html_names::kInvisibleAttr)) {
+ hasAttribute(html_names::kInvisibleAttr) && !calc_invisible) {
auto style =
GetDocument().GetStyleResolver()->InitialStyleForElement(GetDocument());
style->SetDisplay(EDisplay::kNone);
@@ -2209,7 +2224,7 @@ void Element::RecalcStyleForTraversalRootAncestor() {
DidRecalcStyle(kNoChange);
}
-void Element::RecalcStyle(StyleRecalcChange change) {
+void Element::RecalcStyle(StyleRecalcChange change, bool calc_invisible) {
DCHECK(GetDocument().InStyleRecalc());
DCHECK(!GetDocument().Lifecycle().InDetach());
@@ -2264,8 +2279,13 @@ void Element::RecalcStyle(StyleRecalcChange change) {
}
}
+ // If we are on the find-in-page root, we need to calculate style for
+ // invisible nodes in this subtree.
+ if (!calc_invisible && this == GetDocument().FindInPageRoot())
+ calc_invisible = true;
+
if (ParentComputedStyle()) {
- change = RecalcOwnStyle(change);
+ change = RecalcOwnStyle(change, calc_invisible);
} else if (!CanParticipateInFlatTree()) {
// Recalculate style for Shadow DOM v0 <content> insertion point.
// It does not take style since it's not part of the flat tree, but we
@@ -2301,7 +2321,7 @@ void Element::RecalcStyle(StyleRecalcChange change) {
if (root->ShouldCallRecalcStyle(change))
root->RecalcStyle(change);
}
- RecalcDescendantStyles(change);
+ RecalcDescendantStyles(change, calc_invisible);
}
UpdatePseudoElement(kPseudoIdAfter, change);
@@ -2342,7 +2362,8 @@ scoped_refptr<ComputedStyle> Element::PropagateInheritedProperties(
return new_style;
}
-StyleRecalcChange Element::RecalcOwnStyle(StyleRecalcChange change) {
+StyleRecalcChange Element::RecalcOwnStyle(StyleRecalcChange change,
+ bool calc_invisible) {
DCHECK(GetDocument().InStyleRecalc());
DCHECK(change >= kIndependentInherit || NeedsStyleRecalc());
DCHECK(ParentComputedStyle());
@@ -2355,7 +2376,7 @@ StyleRecalcChange Element::RecalcOwnStyle(StyleRecalcChange change) {
// set these directly on the ComputedStyle object.
scoped_refptr<ComputedStyle> new_style = PropagateInheritedProperties(change);
if (!new_style)
- new_style = StyleForLayoutObject();
+ new_style = StyleForLayoutObject(calc_invisible);
if (!new_style) {
DCHECK(IsPseudoElement());
SetNeedsReattachLayoutTree();
@@ -2454,7 +2475,8 @@ void Element::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
// layout tree siblings.
WhitespaceAttacher local_attacher;
WhitespaceAttacher* child_attacher;
- if (GetLayoutObject() || !HasDisplayContentsStyle()) {
+ if (GetLayoutObject() ||
+ (!HasDisplayContentsStyle() && CanParticipateInFlatTree())) {
whitespace_attacher.DidVisitElement(this);
if (GetDocument().GetStyleEngine().NeedsWhitespaceReattachment(this))
local_attacher.SetReattachAllWhitespaceNodes();
@@ -3085,7 +3107,7 @@ void Element::RemoveAttributeInternal(
} else if (GetCustomElementState() == CustomElementState::kCustom) {
// This would otherwise be enqueued by willModifyAttribute.
CustomElement::EnqueueAttributeChangedCallback(
- this, name, value_being_removed, g_null_atom);
+ *this, name, value_being_removed, g_null_atom);
}
}
@@ -3335,7 +3357,8 @@ bool Element::IsKeyboardFocusable() const {
return isConnected() && !IsInert() && IsFocusableStyle() &&
((SupportsFocus() && tabIndex() >= 0) ||
(RuntimeEnabledFeatures::KeyboardFocusableScrollersEnabled() &&
- IsScrollableNode(this)));
+ IsScrollableNode(this))) &&
+ !IsDisplayLockedForFocus();
}
bool Element::IsMouseFocusable() const {
@@ -3343,7 +3366,29 @@ bool Element::IsMouseFocusable() const {
// isn't active (style can't be invalidated in a non-active document).
DCHECK(!GetDocument().IsActive() ||
!GetDocument().NeedsLayoutTreeUpdateForNode(*this));
- return isConnected() && !IsInert() && IsFocusableStyle() && SupportsFocus();
+ return isConnected() && !IsInert() && IsFocusableStyle() && SupportsFocus() &&
+ !IsDisplayLockedForFocus();
+}
+
+bool Element::IsDisplayLockedForFocus() const {
+ if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
+ return false;
+ // TODO(vmpstr): Similar to Document::EnsurePaintLocationDataValidForNode(),
+ // this iterates up to the ancestor hierarchy looking for locked display
+ // locks. This is inefficient, particularly since it's unlikely that this will
+ // yield any "true" results in practice. We need to come up with a way to
+ // check whether a node is in a locked subtree quickly.
+ // See crbug.com/924550 for more details.
+ for (const Node* current = this; current;
+ current = current->ParentOrShadowHostNode()) {
+ if (!current->IsElementNode())
+ continue;
+ if (auto* context = ToElement(current)->GetDisplayLockContext()) {
+ if (!context->IsSearchable())
+ return true;
+ }
+ }
+ return false;
}
bool Element::IsFocusedElementInDocument() const {
@@ -3566,21 +3611,9 @@ void Element::SetNeedsResizeObserverUpdate() {
}
}
-ScriptPromise Element::acquireDisplayLock(ScriptState* script_state,
- V8DisplayLockCallback* callback) {
- auto* context = EnsureElementRareData().EnsureDisplayLockContext(
+DisplayLockContext* Element::getDisplayLockForBindings() {
+ return EnsureElementRareData().EnsureDisplayLockContext(
this, GetExecutionContext());
- context->RequestLock(callback, script_state);
- auto lock_promise = context->Promise();
-
- // Only support "mode 2" display locking, which requires that the lock is
- // acquired before the element is connected. Note that we need to call this
- // after actually getting the promise to avoid ScriptPromiseResolver asserts.
- // TODO(vmpstr): Implement mode 1.
- if (isConnected())
- context->RejectAndCleanUp();
-
- return lock_promise;
}
DisplayLockContext* Element::GetDisplayLockContext() const {
@@ -3655,7 +3688,7 @@ void Element::insertAdjacentHTML(const String& where,
}
}
-void Element::setPointerCapture(int pointer_id,
+void Element::setPointerCapture(PointerId pointer_id,
ExceptionState& exception_state) {
if (GetDocument().GetFrame()) {
if (!GetDocument().GetFrame()->GetEventHandler().IsPointerEventActive(
@@ -3677,7 +3710,7 @@ void Element::setPointerCapture(int pointer_id,
}
}
-void Element::releasePointerCapture(int pointer_id,
+void Element::releasePointerCapture(PointerId pointer_id,
ExceptionState& exception_state) {
if (GetDocument().GetFrame()) {
if (!GetDocument().GetFrame()->GetEventHandler().IsPointerEventActive(
@@ -3692,18 +3725,12 @@ void Element::releasePointerCapture(int pointer_id,
}
}
-bool Element::hasPointerCapture(int pointer_id) const {
+bool Element::hasPointerCapture(PointerId pointer_id) const {
return GetDocument().GetFrame() &&
GetDocument().GetFrame()->GetEventHandler().HasPointerCapture(
pointer_id, this);
}
-bool Element::HasProcessedPointerCapture(int pointer_id) const {
- return GetDocument().GetFrame() &&
- GetDocument().GetFrame()->GetEventHandler().HasProcessedPointerCapture(
- pointer_id, this);
-}
-
String Element::outerText() {
// Getting outerText is the same as getting innerText, only
// setting is different. You would think this should get the plain
@@ -3817,9 +3844,12 @@ const ComputedStyle* Element::EnsureComputedStyle(
ComputedStyle* element_style = MutableComputedStyle();
if (!element_style) {
ElementRareData& rare_data = EnsureElementRareData();
- if (!rare_data.GetComputedStyle())
- rare_data.SetComputedStyle(
- GetDocument().StyleForElementIgnoringPendingStylesheets(this));
+ if (!rare_data.GetComputedStyle()) {
+ scoped_refptr<ComputedStyle> new_style =
+ GetDocument().StyleForElementIgnoringPendingStylesheets(this);
+ new_style->SetIsEnsuredInDisplayNone();
+ rare_data.SetComputedStyle(std::move(new_style));
+ }
element_style = rare_data.GetComputedStyle();
}
@@ -3963,13 +3993,6 @@ void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
return;
}
- if (phase == StyleUpdatePhase::kRebuildLayoutTree &&
- element->NeedsReattachLayoutTree()) {
- // We were already updated in RecalcStyle and ready for reattach.
- DCHECK(element->GetNonAttachedStyle());
- return;
- }
-
if (!CanGeneratePseudoElement(kPseudoIdFirstLetter)) {
GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
return;
@@ -3983,6 +4006,13 @@ void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
return;
}
+ if (phase == StyleUpdatePhase::kRebuildLayoutTree &&
+ element->NeedsReattachLayoutTree()) {
+ // We were already updated in RecalcStyle and ready for reattach.
+ DCHECK(element->GetNonAttachedStyle());
+ return;
+ }
+
bool text_node_changed =
remaining_text_layout_object !=
ToFirstLetterPseudoElement(element)->RemainingTextLayoutObject();
@@ -4470,7 +4500,7 @@ void Element::WillModifyAttribute(const QualifiedName& name,
}
if (GetCustomElementState() == CustomElementState::kCustom) {
- CustomElement::EnqueueAttributeChangedCallback(this, name, old_value,
+ CustomElement::EnqueueAttributeChangedCallback(*this, name, old_value,
new_value);
}
@@ -4571,6 +4601,9 @@ void Element::DidMoveToNewDocument(Document& old_document) {
if (NeedsURLResolutionForInlineStyle(*this, old_document, GetDocument()))
ReResolveURLsInInlineStyle(GetDocument(), EnsureMutableInlineStyle());
+
+ if (auto* context = GetDisplayLockContext())
+ context->DidMoveToNewDocument(old_document);
}
void Element::UpdateNamedItemRegistration(NamedItemType type,
@@ -5095,7 +5128,7 @@ void Element::LogUpdateAttributeIfIsolatedWorldAndInDocument(
activity_logger->LogEvent("blinkSetAttribute", argv.size(), argv.data());
}
-void Element::Trace(blink::Visitor* visitor) {
+void Element::Trace(Visitor* visitor) {
if (HasRareData())
visitor->TraceWithWrappers(GetElementRareData());
visitor->Trace(element_data_);
diff --git a/chromium/third_party/blink/renderer/core/dom/element.h b/chromium/third_party/blink/renderer/core/dom/element.h
index 430fd713515..f4528dbf8c3 100644
--- a/chromium/third_party/blink/renderer/core/dom/element.h
+++ b/chromium/third_party/blink/renderer/core/dom/element.h
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/html/focus_options.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
@@ -87,7 +88,6 @@ class StylePropertyMap;
class StylePropertyMapReadOnly;
class USVStringOrTrustedURL;
class V0CustomElementDefinition;
-class V8DisplayLockCallback;
enum SpellcheckAttributeState {
kSpellcheckAttributeTrue,
@@ -151,6 +151,8 @@ struct FocusParams {
typedef HeapVector<TraceWrapperMember<Attr>> AttrNodeList;
+typedef HashMap<AtomicString, SpecificTrustedType> AttrNameToTrustedType;
+
class CORE_EXPORT Element : public ContainerNode {
DEFINE_WRAPPERTYPEINFO();
@@ -221,7 +223,7 @@ class CORE_EXPORT Element : public ContainerNode {
ExceptionState&);
// Returns attributes that should be checked against Trusted Types
- virtual const HashSet<AtomicString>& GetCheckedAttributeNames() const;
+ virtual const AttrNameToTrustedType& GetCheckedAttributeTypes() const;
// Trusted Type HTML variant
void setAttribute(const QualifiedName&,
@@ -336,6 +338,8 @@ class CORE_EXPORT Element : public ContainerNode {
AccessibleNode* accessibleNode();
InvisibleState Invisible() const;
+ bool HasInvisibleAttribute() const;
+
void DispatchActivateInvisibleEventIfNeeded();
bool IsInsideInvisibleStaticSubtree();
@@ -507,7 +511,7 @@ class CORE_EXPORT Element : public ContainerNode {
virtual LayoutObject* CreateLayoutObject(const ComputedStyle&);
virtual bool LayoutObjectIsNeeded(const ComputedStyle&) const;
- void RecalcStyle(StyleRecalcChange);
+ void RecalcStyle(StyleRecalcChange, bool calc_invisible = false);
void RecalcStyleForTraversalRootAncestor();
void RebuildLayoutTreeForTraversalRootAncestor() {
RebuildFirstLetterLayoutTree();
@@ -700,21 +704,14 @@ class CORE_EXPORT Element : public ContainerNode {
const StringOrTrustedHTML&,
ExceptionState&);
- void setPointerCapture(int pointer_id, ExceptionState&);
- void releasePointerCapture(int pointer_id, ExceptionState&);
+ void setPointerCapture(PointerId poinetr_id, ExceptionState&);
+ void releasePointerCapture(PointerId pointer_id, ExceptionState&);
// Returns true iff the element would capture the next pointer event. This
// is true between a setPointerCapture call and a releasePointerCapture (or
// implicit release) call:
// https://w3c.github.io/pointerevents/#dom-element-haspointercapture
- bool hasPointerCapture(int pointer_id) const;
-
- // Returns true iff the element has received a gotpointercapture event for
- // the |pointerId| but hasn't yet received a lostpointercapture event for
- // the same id. The time window during which this is true is "delayed" from
- // (but overlapping with) the time window for hasPointerCapture():
- // https://w3c.github.io/pointerevents/#process-pending-pointer-capture
- bool HasProcessedPointerCapture(int pointer_id) const;
+ bool hasPointerCapture(PointerId pointer_id) const;
String TextFromChildren();
@@ -836,7 +833,8 @@ class CORE_EXPORT Element : public ContainerNode {
bool IsSpellCheckingEnabled() const;
// FIXME: public for LayoutTreeBuilder, we shouldn't expose this though.
- scoped_refptr<ComputedStyle> StyleForLayoutObject();
+ scoped_refptr<ComputedStyle> StyleForLayoutObject(
+ bool calc_invisible = false);
bool HasID() const;
bool HasClass() const;
@@ -884,7 +882,7 @@ class CORE_EXPORT Element : public ContainerNode {
const char element[],
const AttributeModificationParams&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
SpellcheckAttributeState GetSpellcheckAttributeState() const;
@@ -898,7 +896,7 @@ class CORE_EXPORT Element : public ContainerNode {
EnsureResizeObserverData();
void SetNeedsResizeObserverUpdate();
- ScriptPromise acquireDisplayLock(ScriptState*, V8DisplayLockCallback*);
+ DisplayLockContext* getDisplayLockForBindings();
DisplayLockContext* GetDisplayLockContext() const;
bool StyleRecalcBlockedByDisplayLock() const;
@@ -945,8 +943,6 @@ class CORE_EXPORT Element : public ContainerNode {
// don't have layoutObjects. e.g., HTMLOptionElement.
virtual bool IsFocusableStyle() const;
- virtual bool ChildrenCanHaveStyle() const { return true; }
-
// classAttributeChanged() exists to share code between
// parseAttribute (called via setAttribute()) and
// svgAttributeChanged (called when element.className.baseValue is set)
@@ -1000,7 +996,8 @@ class CORE_EXPORT Element : public ContainerNode {
// and returns the new style. Otherwise, returns null.
scoped_refptr<ComputedStyle> PropagateInheritedProperties(StyleRecalcChange);
- StyleRecalcChange RecalcOwnStyle(StyleRecalcChange);
+ StyleRecalcChange RecalcOwnStyle(StyleRecalcChange,
+ bool calc_invisible = false);
// Returns true if we should traverse shadow including children and pseudo
// elements for RecalcStyle.
@@ -1113,6 +1110,8 @@ class CORE_EXPORT Element : public ContainerNode {
void NotifyDisplayLockDidRecalcStyle();
+ bool IsDisplayLockedForFocus() const;
+
Member<ElementData> element_data_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/element.idl b/chromium/third_party/blink/renderer/core/dom/element.idl
index 6c6e91778ca..df946e6a90e 100644
--- a/chromium/third_party/blink/renderer/core/dom/element.idl
+++ b/chromium/third_party/blink/renderer/core/dom/element.idl
@@ -122,8 +122,8 @@ interface Element : Node {
// Non-standard API
[MeasureAs=ElementScrollIntoViewIfNeeded] void scrollIntoViewIfNeeded(optional boolean centerIfNeeded);
- [RuntimeEnabled=ShadowDOMV0, RaisesException, DeprecateAs=ElementCreateShadowRoot] ShadowRoot createShadowRoot();
- [RuntimeEnabled=ShadowDOMV0] NodeList getDestinationInsertionPoints();
+ [OriginTrialEnabled=ShadowDOMV0, RaisesException, DeprecateAs=ElementCreateShadowRoot] ShadowRoot createShadowRoot();
+ [OriginTrialEnabled=ShadowDOMV0] NodeList getDestinationInsertionPoints();
// Experimental accessibility API
[RuntimeEnabled=ComputedAccessibilityInfo] readonly attribute DOMString? computedRole;
@@ -140,8 +140,8 @@ interface Element : Node {
attribute EventHandler onbeforepaste;
attribute EventHandler onsearch;
- // Display locking.
- [RuntimeEnabled=DisplayLocking, CallWith=ScriptState] Promise acquireDisplayLock(DisplayLockCallback callback);
+ // Display locking. Returns a display lock context.
+ [RuntimeEnabled=DisplayLocking, ImplementedAs=getDisplayLockForBindings] readonly attribute DisplayLockContext displayLock;
};
Element implements ParentNode;
diff --git a/chromium/third_party/blink/renderer/core/dom/element_data.cc b/chromium/third_party/blink/renderer/core/dom/element_data.cc
index a772eead2ba..d556fd26d21 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_data.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element_data.cc
@@ -108,7 +108,7 @@ bool ElementData::IsEquivalent(const ElementData* other) const {
return true;
}
-void ElementData::Trace(blink::Visitor* visitor) {
+void ElementData::Trace(Visitor* visitor) {
if (is_unique_)
ToUniqueElementData(this)->TraceAfterDispatch(visitor);
else
diff --git a/chromium/third_party/blink/renderer/core/dom/element_data.h b/chromium/third_party/blink/renderer/core/dom/element_data.h
index 7ee0db9ab0f..052ba7b55e6 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/element_data.h
@@ -80,7 +80,7 @@ class ElementData : public GarbageCollectedFinalized<ElementData> {
bool IsUnique() const { return is_unique_; }
void TraceAfterDispatch(blink::Visitor*);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
protected:
ElementData();
diff --git a/chromium/third_party/blink/renderer/core/dom/element_data_cache.cc b/chromium/third_party/blink/renderer/core/dom/element_data_cache.cc
index b090762305c..a729e0fef94 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_data_cache.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element_data_cache.cc
@@ -64,7 +64,7 @@ ElementDataCache::CachedShareableElementDataWithAttributes(
ElementDataCache::ElementDataCache() = default;
-void ElementDataCache::Trace(blink::Visitor* visitor) {
+void ElementDataCache::Trace(Visitor* visitor) {
visitor->Trace(shareable_element_data_cache_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/element_data_cache.h b/chromium/third_party/blink/renderer/core/dom/element_data_cache.h
index 9e115429704..bf26dba58fa 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_data_cache.h
+++ b/chromium/third_party/blink/renderer/core/dom/element_data_cache.h
@@ -48,7 +48,7 @@ class ElementDataCache final : public GarbageCollected<ElementDataCache> {
ShareableElementData* CachedShareableElementDataWithAttributes(
const Vector<Attribute>&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
typedef HeapHashMap<unsigned, Member<ShareableElementData>, AlreadyHashed>
diff --git a/chromium/third_party/blink/renderer/core/dom/element_rare_data.h b/chromium/third_party/blink/renderer/core/dom/element_rare_data.h
index 6f8d1dbc904..9a7c006383f 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_rare_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/element_rare_data.h
@@ -161,7 +161,7 @@ class ElementRareData : public NodeRareData {
AccessibleNode* GetAccessibleNode() const { return accessible_node_.Get(); }
AccessibleNode* EnsureAccessibleNode(Element* owner_element) {
if (!accessible_node_) {
- accessible_node_ = new AccessibleNode(owner_element);
+ accessible_node_ = MakeGarbageCollected<AccessibleNode>(owner_element);
}
return accessible_node_;
}
@@ -194,8 +194,9 @@ class ElementRareData : public NodeRareData {
DisplayLockContext* EnsureDisplayLockContext(Element* element,
ExecutionContext* context) {
- if (!display_lock_context_ || display_lock_context_->IsResolved()) {
- display_lock_context_ = new DisplayLockContext(element, context);
+ if (!display_lock_context_) {
+ display_lock_context_ =
+ MakeGarbageCollected<DisplayLockContext>(element, context);
}
return display_lock_context_.Get();
}
@@ -219,8 +220,8 @@ class ElementRareData : public NodeRareData {
std::unique_ptr<NamesMap> part_names_map_;
TraceWrapperMember<NamedNodeMap> attribute_map_;
TraceWrapperMember<AttrNodeList> attr_node_list_;
- Member<InlineCSSStyleDeclaration> cssom_wrapper_;
- Member<InlineStylePropertyMap> cssom_map_wrapper_;
+ TraceWrapperMember<InlineCSSStyleDeclaration> cssom_wrapper_;
+ TraceWrapperMember<InlineStylePropertyMap> cssom_map_wrapper_;
Member<ElementAnimations> element_animations_;
TraceWrapperMember<ElementIntersectionObserverData>
diff --git a/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.cc b/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.cc
index 912ea5fd730..2ce69d3bb32 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.cc
@@ -45,7 +45,7 @@ void ElementVisibilityObserver::DeliverObservationsForTesting() {
intersection_observer_->Deliver();
}
-void ElementVisibilityObserver::Trace(blink::Visitor* visitor) {
+void ElementVisibilityObserver::Trace(Visitor* visitor) {
visitor->Trace(element_);
visitor->Trace(intersection_observer_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.h b/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.h
index 34e1e08a5f4..c0957137e0e 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.h
+++ b/chromium/third_party/blink/renderer/core/dom/element_visibility_observer.h
@@ -43,7 +43,7 @@ class CORE_EXPORT ElementVisibilityObserver final
void DeliverObservationsForTesting();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
private:
class ElementVisibilityCallback;
diff --git a/chromium/third_party/blink/renderer/core/dom/empty_node_list.cc b/chromium/third_party/blink/renderer/core/dom/empty_node_list.cc
index 01cc7ca6dd2..7edbab93e93 100644
--- a/chromium/third_party/blink/renderer/core/dom/empty_node_list.cc
+++ b/chromium/third_party/blink/renderer/core/dom/empty_node_list.cc
@@ -42,7 +42,7 @@ Node* EmptyNodeList::VirtualOwnerNode() const {
return &OwnerNode();
}
-void EmptyNodeList::Trace(blink::Visitor* visitor) {
+void EmptyNodeList::Trace(Visitor* visitor) {
visitor->Trace(owner_);
NodeList::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/empty_node_list.h b/chromium/third_party/blink/renderer/core/dom/empty_node_list.h
index 85b73df2943..8e835b886dd 100644
--- a/chromium/third_party/blink/renderer/core/dom/empty_node_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/empty_node_list.h
@@ -47,7 +47,7 @@ class EmptyNodeList final : public NodeList {
Node& OwnerNode() const { return *owner_; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
unsigned length() const override { return 0; }
diff --git a/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc b/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc
index 746d8e4d995..711feae9b09 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc
@@ -25,7 +25,7 @@ AddEventListenerOptionsResolved::AddEventListenerOptionsResolved(
AddEventListenerOptionsResolved::~AddEventListenerOptionsResolved() = default;
-void AddEventListenerOptionsResolved::Trace(blink::Visitor* visitor) {
+void AddEventListenerOptionsResolved::Trace(Visitor* visitor) {
AddEventListenerOptions::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h b/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h
index fcb23b68aa8..e6872ac9f32 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h
@@ -17,12 +17,15 @@ class CORE_EXPORT AddEventListenerOptionsResolved
: public AddEventListenerOptions {
public:
static AddEventListenerOptionsResolved* Create() {
- return new AddEventListenerOptionsResolved();
+ return MakeGarbageCollected<AddEventListenerOptionsResolved>();
}
static AddEventListenerOptionsResolved* Create(
const AddEventListenerOptions* options) {
- return new AddEventListenerOptionsResolved(options);
+ return MakeGarbageCollected<AddEventListenerOptionsResolved>(options);
}
+
+ AddEventListenerOptionsResolved();
+ AddEventListenerOptionsResolved(const AddEventListenerOptions*);
~AddEventListenerOptionsResolved() override;
void SetPassiveForcedForDocumentTarget(bool forced) {
@@ -37,12 +40,9 @@ class CORE_EXPORT AddEventListenerOptionsResolved
void SetPassiveSpecified(bool specified) { passive_specified_ = specified; }
bool PassiveSpecified() const { return passive_specified_; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- AddEventListenerOptionsResolved();
- AddEventListenerOptionsResolved(const AddEventListenerOptions*);
-
bool passive_forced_for_document_target_;
bool passive_specified_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/events/custom_event.cc b/chromium/third_party/blink/renderer/core/dom/events/custom_event.cc
index a5ae410abad..2c4de684181 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/custom_event.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/custom_event.cc
@@ -25,8 +25,6 @@
#include "third_party/blink/renderer/core/dom/events/custom_event.h"
-#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h"
#include "third_party/blink/renderer/core/event_interface_names.h"
namespace blink {
@@ -37,10 +35,9 @@ CustomEvent::CustomEvent(ScriptState* script_state,
const AtomicString& type,
const CustomEventInit* initializer)
: Event(type, initializer) {
- world_ = WrapRefCounted(&script_state->World());
if (initializer->hasDetail()) {
- detail_.Set(initializer->detail().GetIsolate(),
- initializer->detail().V8Value());
+ detail_.SetAcrossWorld(initializer->detail().GetIsolate(),
+ initializer->detail().V8Value());
}
}
@@ -52,30 +49,22 @@ void CustomEvent::initCustomEvent(ScriptState* script_state,
bool cancelable,
const ScriptValue& script_value) {
initEvent(type, bubbles, cancelable);
- world_ = WrapRefCounted(&script_state->World());
if (!IsBeingDispatched() && !script_value.IsEmpty())
- detail_.Set(script_value.GetIsolate(), script_value.V8Value());
+ detail_.SetAcrossWorld(script_value.GetIsolate(), script_value.V8Value());
}
ScriptValue CustomEvent::detail(ScriptState* script_state) const {
v8::Isolate* isolate = script_state->GetIsolate();
if (detail_.IsEmpty())
return ScriptValue(script_state, v8::Null(isolate));
- // Returns a clone of |detail_| if the world is different.
- if (!world_ || world_->GetWorldId() != script_state->World().GetWorldId()) {
- v8::Local<v8::Value> value = detail_.NewLocal(isolate);
- scoped_refptr<SerializedScriptValue> serialized =
- SerializedScriptValue::SerializeAndSwallowExceptions(isolate, value);
- return ScriptValue(script_state, serialized->Deserialize(isolate));
- }
- return ScriptValue(script_state, detail_.NewLocal(isolate));
+ return ScriptValue(script_state, detail_.GetAcrossWorld(script_state));
}
const AtomicString& CustomEvent::InterfaceName() const {
return event_interface_names::kCustomEvent;
}
-void CustomEvent::Trace(blink::Visitor* visitor) {
+void CustomEvent::Trace(Visitor* visitor) {
visitor->Trace(detail_);
Event::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/custom_event.h b/chromium/third_party/blink/renderer/core/dom/events/custom_event.h
index 9d2f33faac0..3cce5f21cd8 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/custom_event.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/custom_event.h
@@ -26,11 +26,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_CUSTOM_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_CUSTOM_EVENT_H_
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/custom_event_init.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
namespace blink {
@@ -40,14 +39,19 @@ class CORE_EXPORT CustomEvent final : public Event {
public:
~CustomEvent() override;
- static CustomEvent* Create() { return new CustomEvent; }
+ static CustomEvent* Create() { return MakeGarbageCollected<CustomEvent>(); }
static CustomEvent* Create(ScriptState* script_state,
const AtomicString& type,
const CustomEventInit* initializer) {
- return new CustomEvent(script_state, type, initializer);
+ return MakeGarbageCollected<CustomEvent>(script_state, type, initializer);
}
+ CustomEvent();
+ CustomEvent(ScriptState*,
+ const AtomicString& type,
+ const CustomEventInit* initializer);
+
void initCustomEvent(ScriptState*,
const AtomicString& type,
bool bubbles,
@@ -58,16 +62,10 @@ class CORE_EXPORT CustomEvent final : public Event {
ScriptValue detail(ScriptState*) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- CustomEvent();
- CustomEvent(ScriptState*,
- const AtomicString& type,
- const CustomEventInit* initializer);
-
- scoped_refptr<DOMWrapperWorld> world_;
- TraceWrapperV8Reference<v8::Value> detail_;
+ WorldSafeV8Reference<v8::Value> detail_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event.cc b/chromium/third_party/blink/renderer/core/dom/events/event.cc
index 7b3b0bf7f99..a1e0e64c8b6 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event.cc
@@ -394,7 +394,7 @@ DispatchEventResult Event::DispatchEvent(EventDispatcher& dispatcher) {
return dispatcher.Dispatch();
}
-void Event::Trace(blink::Visitor* visitor) {
+void Event::Trace(Visitor* visitor) {
visitor->Trace(current_target_);
visitor->Trace(target_);
visitor->Trace(underlying_event_);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event.h b/chromium/third_party/blink/renderer/core/dom/events/event.h
index 654b6faaaa0..8c35bc5ae51 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event.h
@@ -308,9 +308,16 @@ class CORE_EXPORT Event : public ScriptWrappable {
legacy_did_listeners_throw_flag_ = true;
}
+ // In general, event listeners do not run when related execution contexts are
+ // paused. However, when this function returns true, event listeners ignore
+ // the pause and run.
+ virtual bool ShouldDispatchEvenWhenExecutionContextIsPaused() const {
+ return false;
+ }
+
virtual DispatchEventResult DispatchEvent(EventDispatcher&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
virtual void ReceivedTarget();
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h
index e09e49f4584..59eba27ca46 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h
@@ -43,7 +43,7 @@ class Node;
class EventDispatchHandlingState
: public GarbageCollected<EventDispatchHandlingState> {
public:
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
};
enum EventDispatchContinuation { kContinueDispatching, kDoneDispatching };
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_listener.h b/chromium/third_party/blink/renderer/core/dom/events/event_listener.h
index b5b2e7449db..3d7eb513a4e 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_listener.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_listener.h
@@ -21,7 +21,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_EVENT_LISTENER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_EVENT_LISTENER_H_
-#include "third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h"
+#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -32,23 +32,22 @@ namespace blink {
class Event;
class ExecutionContext;
-class CORE_EXPORT EventListener : public CustomWrappableAdapter {
+// EventListener represents 'callback' in 'event listener' in DOM standard.
+// https://dom.spec.whatwg.org/#concept-event-listener
+//
+// While RegisteredEventListener represents 'event listener', which consists of
+// - type
+// - callback
+// - capture
+// - passive
+// - once
+// - removed
+// EventListener represents 'callback' part.
+class CORE_EXPORT EventListener
+ : public GarbageCollectedFinalized<EventListener>,
+ public NameClient {
public:
- enum ListenerType {
- // |kJSEventListenerType| corresponds to EventListener defined in standard:
- // https://dom.spec.whatwg.org/#callbackdef-eventlistener
- kJSEventListenerType,
- // |kJSEventHandlerType| corresponds to EventHandler defined in standard:
- // https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-attributes
- kJSEventHandlerType,
- // These are for C++ native callbacks.
- kImageEventListenerType,
- kCPPEventListenerType,
- kConditionEventListenerType,
- };
-
- explicit EventListener(ListenerType type) : type_(type) {}
- ~EventListener() override = default;
+ virtual ~EventListener() = default;
// Invokes this event listener.
virtual void Invoke(ExecutionContext*, Event*) = 0;
@@ -69,22 +68,31 @@ class CORE_EXPORT EventListener : public CustomWrappableAdapter {
return false;
}
- virtual bool operator==(const EventListener&) const = 0;
+ // Returns true if this event listener is considered as the same with the
+ // other event listener (in context of EventTarget.removeEventListener).
+ // See also |RegisteredEventListener::Matches|.
+ //
+ // This function must satisfy the symmetric property; a.Matches(b) must
+ // produce the same result as b.Matches(a).
+ virtual bool Matches(const EventListener&) const = 0;
- ListenerType GetType() const { return type_; }
-
- // Returns true if this EventListener is implemented based on JS object.
- bool IsJSBased() const {
- return type_ == kJSEventListenerType || type_ == kJSEventHandlerType;
- }
-
- // Returns true if this EventListener is C++ native callback.
- bool IsNativeBased() const { return !IsJSBased(); }
+ virtual void Trace(Visitor*) {}
const char* NameInHeapSnapshot() const override { return "EventListener"; }
+ // Helper functions for DowncastTraits.
+ virtual bool IsJSBasedEventListener() const { return false; }
+ virtual bool IsNativeEventListener() const { return false; }
+
private:
- ListenerType type_;
+ EventListener() = default;
+
+ // Only these two classes are direct subclasses of EventListener. Other
+ // subclasses must inherit from either of them.
+ friend class JSBasedEventListener;
+ friend class NativeEventListener;
+
+ DISALLOW_COPY_AND_ASSIGN(EventListener);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.cc b/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.cc
index f508802ea06..b6f19c4a7c0 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.cc
@@ -207,7 +207,7 @@ void EventListenerMap::CopyEventListenersNotCreatedFromMarkupToTarget(
}
}
-void EventListenerMap::Trace(blink::Visitor* visitor) {
+void EventListenerMap::Trace(Visitor* visitor) {
visitor->Trace(entries_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.h b/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.h
index 57da2d12a25..0c16cfe2b73 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_listener_map.h
@@ -72,7 +72,7 @@ class CORE_EXPORT EventListenerMap final {
void CopyEventListenersNotCreatedFromMarkupToTarget(EventTarget*);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
friend class EventListenerIterator;
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_path.cc b/chromium/third_party/blink/renderer/core/dom/events/event_path.cc
index a353eb91562..d5bc6014197 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_path.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_path.cc
@@ -417,7 +417,7 @@ void EventPath::CheckReachability(TreeScope& tree_scope,
}
#endif
-void EventPath::Trace(blink::Visitor* visitor) {
+void EventPath::Trace(Visitor* visitor) {
visitor->Trace(node_event_contexts_);
visitor->Trace(node_);
visitor->Trace(event_);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_path.h b/chromium/third_party/blink/renderer/core/dom/events/event_path.h
index be0d71d2c43..07102f25af7 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_path.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_path.h
@@ -83,7 +83,7 @@ class CORE_EXPORT EventPath final
static EventTarget& EventTargetRespectingTargetRules(Node&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void Clear() {
node_event_contexts_.clear();
tree_scope_event_contexts_.clear();
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_queue.cc b/chromium/third_party/blink/renderer/core/dom/events/event_queue.cc
index 55abadf355f..b3cb21da2a6 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_queue.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_queue.cc
@@ -48,7 +48,7 @@ EventQueue::EventQueue(ExecutionContext* context, TaskType task_type)
EventQueue::~EventQueue() = default;
-void EventQueue::Trace(blink::Visitor* visitor) {
+void EventQueue::Trace(Visitor* visitor) {
visitor->Trace(queued_events_);
ContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_queue.h b/chromium/third_party/blink/renderer/core/dom/events/event_queue.h
index a1ecfb3d427..35e60f3bcab 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_queue.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_queue.h
@@ -47,7 +47,7 @@ class CORE_EXPORT EventQueue final
EventQueue(ExecutionContext*, TaskType);
~EventQueue();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
bool EnqueueEvent(const base::Location&, Event&);
void CancelAllEvents();
bool HasPendingEvents() const;
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_target.cc b/chromium/third_party/blink/renderer/core/dom/events/event_target.cc
index 42faeb2a461..a14c537ca18 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_target.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/bindings/core/v8/add_event_listener_options_or_boolean.h"
#include "third_party/blink/renderer/bindings/core/v8/event_listener_options_or_boolean.h"
#include "third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h"
+#include "third_party/blink/renderer/bindings/core/v8/js_event_listener.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
@@ -127,7 +128,7 @@ void ReportBlockedEvent(EventTarget& target,
RegisteredEventListener* registered_listener,
base::TimeDelta delayed) {
JSBasedEventListener* listener =
- JSBasedEventListener::Cast(registered_listener->Callback());
+ DynamicTo<JSBasedEventListener>(registered_listener->Callback());
if (!listener)
return;
@@ -161,7 +162,7 @@ EventTargetData::EventTargetData() = default;
EventTargetData::~EventTargetData() = default;
-void EventTargetData::Trace(blink::Visitor* visitor) {
+void EventTargetData::Trace(Visitor* visitor) {
visitor->Trace(event_listener_map);
}
@@ -289,7 +290,7 @@ void EventTarget::SetDefaultAddEventListenerOptions(
event_type == event_type_names::kMousewheel && ToLocalDOMWindow() &&
event_listener && !options->hasPassive()) {
JSBasedEventListener* v8_listener =
- JSBasedEventListener::Cast(event_listener);
+ DynamicTo<JSBasedEventListener>(event_listener);
if (!v8_listener)
return;
v8::Local<v8::Value> callback_object =
@@ -352,21 +353,22 @@ void EventTarget::SetDefaultAddEventListenerOptions(
}
bool EventTarget::addEventListener(const AtomicString& event_type,
- EventListener* listener,
- bool use_capture) {
- AddEventListenerOptionsResolved* options =
- AddEventListenerOptionsResolved::Create();
- options->setCapture(use_capture);
- SetDefaultAddEventListenerOptions(event_type, listener, options);
- return AddEventListenerInternal(event_type, listener, options);
+ V8EventListener* listener) {
+ EventListener* event_listener = JSEventListener::CreateOrNull(listener);
+ return addEventListener(event_type, event_listener);
}
bool EventTarget::addEventListener(
const AtomicString& event_type,
- EventListener* listener,
+ V8EventListener* listener,
const AddEventListenerOptionsOrBoolean& options_union) {
- if (options_union.IsBoolean())
- return addEventListener(event_type, listener, options_union.GetAsBoolean());
+ EventListener* event_listener = JSEventListener::CreateOrNull(listener);
+
+ if (options_union.IsBoolean()) {
+ return addEventListener(event_type, event_listener,
+ options_union.GetAsBoolean());
+ }
+
if (options_union.IsAddEventListenerOptions()) {
AddEventListenerOptionsResolved* resolved_options =
AddEventListenerOptionsResolved::Create();
@@ -378,9 +380,20 @@ bool EventTarget::addEventListener(
resolved_options->setOnce(options->once());
if (options->hasCapture())
resolved_options->setCapture(options->capture());
- return addEventListener(event_type, listener, resolved_options);
+ return addEventListener(event_type, event_listener, resolved_options);
}
- return addEventListener(event_type, listener);
+
+ return addEventListener(event_type, event_listener);
+}
+
+bool EventTarget::addEventListener(const AtomicString& event_type,
+ EventListener* listener,
+ bool use_capture) {
+ AddEventListenerOptionsResolved* options =
+ AddEventListenerOptionsResolved::Create();
+ options->setCapture(use_capture);
+ SetDefaultAddEventListenerOptions(event_type, listener, options);
+ return AddEventListenerInternal(event_type, listener, options);
}
bool EventTarget::addEventListener(const AtomicString& event_type,
@@ -412,7 +425,8 @@ bool EventTarget::AddEventListenerInternal(
event_type, listener, options, &registered_listener);
if (added) {
AddedEventListener(event_type, registered_listener);
- if (listener->IsJSBased() && IsInstrumentedForAsyncStack(event_type)) {
+ if (IsA<JSBasedEventListener>(listener) &&
+ IsInstrumentedForAsyncStack(event_type)) {
probe::AsyncTaskScheduled(GetExecutionContext(), event_type, listener);
}
}
@@ -448,26 +462,36 @@ void EventTarget::AddedEventListener(
}
bool EventTarget::removeEventListener(const AtomicString& event_type,
- const EventListener* listener,
- bool use_capture) {
- EventListenerOptions* options = EventListenerOptions::Create();
- options->setCapture(use_capture);
- return RemoveEventListenerInternal(event_type, listener, options);
+ V8EventListener* listener) {
+ EventListener* event_listener = JSEventListener::CreateOrNull(listener);
+ return removeEventListener(event_type, event_listener);
}
bool EventTarget::removeEventListener(
const AtomicString& event_type,
- const EventListener* listener,
+ V8EventListener* listener,
const EventListenerOptionsOrBoolean& options_union) {
+ EventListener* event_listener = JSEventListener::CreateOrNull(listener);
+
if (options_union.IsBoolean()) {
- return removeEventListener(event_type, listener,
+ return removeEventListener(event_type, event_listener,
options_union.GetAsBoolean());
}
+
if (options_union.IsEventListenerOptions()) {
EventListenerOptions* options = options_union.GetAsEventListenerOptions();
- return removeEventListener(event_type, listener, options);
+ return removeEventListener(event_type, event_listener, options);
}
- return removeEventListener(event_type, listener);
+
+ return removeEventListener(event_type, event_listener);
+}
+
+bool EventTarget::removeEventListener(const AtomicString& event_type,
+ const EventListener* listener,
+ bool use_capture) {
+ EventListenerOptions* options = EventListenerOptions::Create();
+ options->setCapture(use_capture);
+ return RemoveEventListenerInternal(event_type, listener, options);
}
bool EventTarget::removeEventListener(const AtomicString& event_type,
@@ -547,7 +571,8 @@ bool EventTarget::SetAttributeEventListener(const AtomicString& event_type,
return false;
}
if (registered_listener) {
- if (listener->IsJSBased() && IsInstrumentedForAsyncStack(event_type)) {
+ if (IsA<JSBasedEventListener>(listener) &&
+ IsInstrumentedForAsyncStack(event_type)) {
probe::AsyncTaskScheduled(GetExecutionContext(), event_type, listener);
}
registered_listener->SetCallback(listener);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_target.h b/chromium/third_party/blink/renderer/core/dom/events/event_target.h
index 69d0db56ec5..60fa150d39e 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_target.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_target.h
@@ -60,6 +60,7 @@ class MessagePort;
class Node;
class ScriptState;
class ServiceWorker;
+class V8EventListener;
struct FiringEventIterator {
DISALLOW_NEW();
@@ -80,7 +81,7 @@ class CORE_EXPORT EventTargetData final
EventTargetData();
~EventTargetData();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
EventListenerMap event_listener_map;
std::unique_ptr<FiringEventIteratorVector> firing_event_iterators;
@@ -132,22 +133,24 @@ class CORE_EXPORT EventTarget : public ScriptWrappable {
static EventTarget* Create(ScriptState*);
+ bool addEventListener(const AtomicString& event_type, V8EventListener*);
bool addEventListener(const AtomicString& event_type,
- EventListener*,
- bool use_capture = false);
+ V8EventListener*,
+ const AddEventListenerOptionsOrBoolean&);
bool addEventListener(const AtomicString& event_type,
EventListener*,
- const AddEventListenerOptionsOrBoolean&);
+ bool use_capture = false);
bool addEventListener(const AtomicString& event_type,
EventListener*,
AddEventListenerOptionsResolved*);
+ bool removeEventListener(const AtomicString& event_type, V8EventListener*);
bool removeEventListener(const AtomicString& event_type,
- const EventListener*,
- bool use_capture = false);
+ V8EventListener*,
+ const EventListenerOptionsOrBoolean&);
bool removeEventListener(const AtomicString& event_type,
const EventListener*,
- const EventListenerOptionsOrBoolean&);
+ bool use_capture = false);
bool removeEventListener(const AtomicString& event_type,
const EventListener*,
EventListenerOptions*);
@@ -234,7 +237,7 @@ class CORE_EXPORT EventTargetWithInlineData : public EventTarget {
public:
~EventTargetWithInlineData() override = default;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(event_target_data_);
EventTarget::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.cc b/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.cc
index 91a841a8799..7ffa91a586d 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.cc
@@ -18,7 +18,7 @@ ExecutionContext* EventTargetImpl::GetExecutionContext() const {
return ContextLifecycleObserver::GetExecutionContext();
}
-void EventTargetImpl::Trace(blink::Visitor* visitor) {
+void EventTargetImpl::Trace(Visitor* visitor) {
EventTargetWithInlineData::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.h b/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.h
index 77fe99923fe..42f33aced17 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_target_impl.h
@@ -32,7 +32,7 @@ class CORE_EXPORT EventTargetImpl final : public EventTargetWithInlineData,
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/events/native_event_listener.h b/chromium/third_party/blink/renderer/core/dom/events/native_event_listener.h
new file mode 100644
index 00000000000..7e5b67417c6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/events/native_event_listener.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_NATIVE_EVENT_LISTENER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_NATIVE_EVENT_LISTENER_H_
+
+#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+
+namespace blink {
+
+// |NativeEventListener| is the base class for event listeners implemented in
+// C++ and the counterpart of |JSBasedEventListener|.
+class CORE_EXPORT NativeEventListener : public EventListener {
+ public:
+ ~NativeEventListener() override = default;
+
+ // blink::EventListener overrides:
+ bool Matches(const EventListener& other) const override {
+ return this == &other;
+ }
+
+ // Helper functions for DowncastTraits.
+ bool IsNativeEventListener() const override { return true; }
+ virtual bool IsConditionEventListener() const { return false; }
+ virtual bool IsImageEventListener() const { return false; }
+
+ protected:
+ NativeEventListener() = default;
+};
+
+template <>
+struct DowncastTraits<NativeEventListener> {
+ static bool AllowFrom(const EventListener& event_listener) {
+ return event_listener.IsNativeEventListener();
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_NATIVE_EVENT_LISTENER_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/events/node_event_context.cc b/chromium/third_party/blink/renderer/core/dom/events/node_event_context.cc
index 16d26106b99..ff6a94ff4e0 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/node_event_context.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/node_event_context.cc
@@ -38,7 +38,7 @@ namespace blink {
NodeEventContext::NodeEventContext(Node& node, EventTarget& current_target)
: node_(node), current_target_(current_target) {}
-void NodeEventContext::Trace(blink::Visitor* visitor) {
+void NodeEventContext::Trace(Visitor* visitor) {
visitor->Trace(node_);
visitor->Trace(current_target_);
visitor->Trace(tree_scope_event_context_);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/node_event_context.h b/chromium/third_party/blink/renderer/core/dom/events/node_event_context.h
index 21c2ca244f5..feb59f0d3c8 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/node_event_context.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/node_event_context.h
@@ -43,7 +43,7 @@ class CORE_EXPORT NodeEventContext {
public:
// FIXME: Use ContainerNode instead of Node.
NodeEventContext(Node&, EventTarget& current_target);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
Node& GetNode() const { return *node_; }
diff --git a/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.cc b/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.cc
index 93685d95475..352f24e5c12 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.cc
@@ -80,7 +80,7 @@ bool RegisteredEventListener::Matches(
// Equality is soley based on the listener and useCapture flags.
DCHECK(callback_);
DCHECK(listener);
- return *callback_ == *listener &&
+ return callback_->Matches(*listener) &&
static_cast<bool>(use_capture_) == options->capture();
}
@@ -110,12 +110,12 @@ bool RegisteredEventListener::ShouldFire(const Event& event) const {
return true;
}
-bool RegisteredEventListener::operator==(
- const RegisteredEventListener& other) const {
- // Equality is soley based on the listener and useCapture flags.
- DCHECK(callback_);
- DCHECK(other.callback_);
- return *callback_ == *other.callback_ && use_capture_ == other.use_capture_;
+bool operator==(const RegisteredEventListener& lhs,
+ const RegisteredEventListener& rhs) {
+ DCHECK(lhs.Callback());
+ DCHECK(rhs.Callback());
+ return lhs.Callback()->Matches(*rhs.Callback()) &&
+ lhs.Capture() == rhs.Capture();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.h b/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.h
index 248e143f347..7cee60d200b 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/registered_event_listener.h
@@ -82,8 +82,6 @@ class RegisteredEventListener final {
bool ShouldFire(const Event&) const;
- bool operator==(const RegisteredEventListener& other) const;
-
private:
TraceWrapperMember<EventListener> callback_;
unsigned use_capture_ : 1;
@@ -94,6 +92,8 @@ class RegisteredEventListener final {
unsigned passive_specified_ : 1;
};
+bool operator==(const RegisteredEventListener&, const RegisteredEventListener&);
+
} // namespace blink
WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::RegisteredEventListener);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc b/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
index 2133bac406e..5d9e7685838 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
@@ -96,7 +96,7 @@ TreeScopeEventContext::TreeScopeEventContext(TreeScope& tree_scope)
pre_order_(-1),
post_order_(-1) {}
-void TreeScopeEventContext::Trace(blink::Visitor* visitor) {
+void TreeScopeEventContext::Trace(Visitor* visitor) {
visitor->Trace(tree_scope_);
visitor->Trace(target_);
visitor->Trace(related_target_);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h b/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h
index eac6b4a0d04..b3aaa544af3 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h
@@ -50,7 +50,7 @@ class CORE_EXPORT TreeScopeEventContext final
static TreeScopeEventContext* Create(TreeScope&);
TreeScopeEventContext(TreeScope&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
TreeScope& GetTreeScope() const { return *tree_scope_; }
ContainerNode& RootNode() const { return tree_scope_->RootNode(); }
diff --git a/chromium/third_party/blink/renderer/core/dom/events/window_event_context.cc b/chromium/third_party/blink/renderer/core/dom/events/window_event_context.cc
index 3e3de47918c..abf6206b1b8 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/window_event_context.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/window_event_context.cc
@@ -61,7 +61,7 @@ bool WindowEventContext::HandleLocalEvents(Event& event) {
return true;
}
-void WindowEventContext::Trace(blink::Visitor* visitor) {
+void WindowEventContext::Trace(Visitor* visitor) {
visitor->Trace(window_);
visitor->Trace(target_);
visitor->Trace(related_target_);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/window_event_context.h b/chromium/third_party/blink/renderer/core/dom/events/window_event_context.h
index 07d72e5b1a6..3f95a3ee64a 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/window_event_context.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/window_event_context.h
@@ -46,7 +46,7 @@ class WindowEventContext : public GarbageCollected<WindowEventContext> {
EventTarget* RelatedTarget() const;
bool HandleLocalEvents(Event&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Member<LocalDOMWindow> window_;
diff --git a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
index a689ec3a7aa..4176191ff5f 100644
--- a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
+++ b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -164,7 +164,7 @@ LayoutText* FirstLetterPseudoElement::FirstLetterTextLayoutObject(
first_letter_text_layout_object->IsMenuList()) {
return nullptr;
} else if (first_letter_text_layout_object
- ->IsFlexibleBoxIncludingDeprecated() ||
+ ->IsFlexibleBoxIncludingDeprecatedAndNG() ||
first_letter_text_layout_object->IsLayoutGrid()) {
first_letter_text_layout_object =
first_letter_text_layout_object->NextSibling();
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h b/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h
index 96d98836eb3..a3d77f558ae 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h
@@ -6,11 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_FLAT_TREE_NODE_DATA_H_
#include "base/macros.h"
+#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
-class Node;
class HTMLSlotElement;
class FlatTreeNodeData final : public GarbageCollected<FlatTreeNodeData> {
@@ -39,6 +39,7 @@ class FlatTreeNodeData final : public GarbageCollected<FlatTreeNodeData> {
friend class FlatTreeTraversal;
friend class HTMLSlotElement;
+ friend HTMLSlotElement* Node::AssignedSlot() const;
WeakMember<HTMLSlotElement> assigned_slot_;
WeakMember<Node> previous_in_assigned_nodes_;
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
index 92e6ec38f32..27505913fab 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
@@ -116,6 +116,15 @@ Node* FlatTreeTraversal::TraverseSiblings(const Node& node,
Node* FlatTreeTraversal::TraverseSiblingsForV1HostChild(
const Node& node,
TraversalDirection direction) {
+ if (!RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled()) {
+ HTMLSlotElement* slot = node.AssignedSlot();
+ if (!slot)
+ return nullptr;
+ return direction == kTraversalDirectionForward
+ ? slot->AssignedNodeNextTo(node)
+ : slot->AssignedNodePreviousTo(node);
+ }
+
ShadowRoot* shadow_root = node.ParentElementShadowRoot();
DCHECK(shadow_root);
if (!shadow_root->HasSlotAssignment()) {
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h
index da283a34310..e57fa3651fe 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h
@@ -144,6 +144,7 @@ class CORE_EXPORT FlatTreeTraversal {
};
static void AssertPrecondition(const Node& node) {
+ DCHECK(!node.GetDocument().IsFlatTreeTraversalForbidden());
DCHECK(!node.NeedsDistributionRecalc());
DCHECK(node.CanParticipateInFlatTree());
}
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_forbidden_scope.h b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_forbidden_scope.h
new file mode 100644
index 00000000000..668f2b186d6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_forbidden_scope.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_FLAT_TREE_TRAVERSAL_FORBIDDEN_SCOPE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_FLAT_TREE_TRAVERSAL_FORBIDDEN_SCOPE_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+
+namespace blink {
+
+class FlatTreeTraversalForbiddenScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit FlatTreeTraversalForbiddenScope(Document& document)
+ : count_(document.FlatTreeTraversalForbiddenRecursionDepth()) {
+ ++count_;
+ }
+
+ ~FlatTreeTraversalForbiddenScope() {
+ DCHECK_GT(count_, 0u);
+ --count_;
+ }
+
+ private:
+ unsigned& count_;
+ DISALLOW_COPY_AND_ASSIGN(FlatTreeTraversalForbiddenScope);
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc b/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
index 02b71b6619e..b101838c1da 100644
--- a/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
+++ b/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
@@ -88,7 +88,7 @@ void FrameRequestCallbackCollection::ExecuteCallbacks(
callbacks_to_invoke_.clear();
}
-void FrameRequestCallbackCollection::Trace(blink::Visitor* visitor) {
+void FrameRequestCallbackCollection::Trace(Visitor* visitor) {
visitor->Trace(callbacks_);
visitor->Trace(callbacks_to_invoke_);
visitor->Trace(context_);
diff --git a/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.h b/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.h
index 3d69e24d821..de0dec351ec 100644
--- a/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.h
+++ b/chromium/third_party/blink/renderer/core/dom/frame_request_callback_collection.h
@@ -31,7 +31,7 @@ class GC_PLUGIN_IGNORE("crbug.com/841830")
: public GarbageCollectedFinalized<FrameCallback>,
public NameClient {
public:
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
const char* NameInHeapSnapshot() const override { return "FrameCallback"; }
virtual ~FrameCallback() = default;
virtual void Invoke(double) = 0;
@@ -61,7 +61,7 @@ class GC_PLUGIN_IGNORE("crbug.com/841830")
static V8FrameCallback* Create(V8FrameRequestCallback* callback) {
return MakeGarbageCollected<V8FrameCallback>(callback);
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
const char* NameInHeapSnapshot() const override {
return "V8FrameCallback";
}
@@ -81,7 +81,7 @@ class GC_PLUGIN_IGNORE("crbug.com/841830")
bool IsEmpty() const { return !callbacks_.size(); }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
const char* NameInHeapSnapshot() const override {
return "FrameRequestCallbackCollection";
}
diff --git a/chromium/third_party/blink/renderer/core/dom/global_event_handlers.h b/chromium/third_party/blink/renderer/core/dom/global_event_handlers.h
index 36f277a1940..056f5f80477 100644
--- a/chromium/third_party/blink/renderer/core/dom/global_event_handlers.h
+++ b/chromium/third_party/blink/renderer/core/dom/global_event_handlers.h
@@ -85,6 +85,7 @@ class GlobalEventHandlers {
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(mouseover, kMouseover);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(mouseup, kMouseup);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(mousewheel, kMousewheel);
+ DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(overscroll, kOverscroll);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pause, kPause);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(play, kPlay);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(playing, kPlaying);
@@ -102,6 +103,7 @@ class GlobalEventHandlers {
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(reset, kReset);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(resize, kResize);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(scroll, kScroll);
+ DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(scrollend, kScrollend);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(seeked, kSeeked);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(seeking, kSeeking);
DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(select, kSelect);
diff --git a/chromium/third_party/blink/renderer/core/dom/global_event_handlers.idl b/chromium/third_party/blink/renderer/core/dom/global_event_handlers.idl
index adff5bb486f..a6da520b836 100644
--- a/chromium/third_party/blink/renderer/core/dom/global_event_handlers.idl
+++ b/chromium/third_party/blink/renderer/core/dom/global_event_handlers.idl
@@ -77,6 +77,7 @@
attribute EventHandler onmouseover;
attribute EventHandler onmouseup;
attribute EventHandler onmousewheel;
+ [RuntimeEnabled=OverscrollCustomization] attribute EventHandler onoverscroll;
attribute EventHandler onpause;
attribute EventHandler onplay;
attribute EventHandler onplaying;
@@ -85,6 +86,7 @@
attribute EventHandler onreset;
attribute EventHandler onresize;
attribute EventHandler onscroll;
+ [RuntimeEnabled=OverscrollCustomization] attribute EventHandler onscrollend;
attribute EventHandler onseeked;
attribute EventHandler onseeking;
attribute EventHandler onselect;
diff --git a/chromium/third_party/blink/renderer/core/dom/id_target_observer.cc b/chromium/third_party/blink/renderer/core/dom/id_target_observer.cc
index a4efa5adc29..2df3ab5fa08 100644
--- a/chromium/third_party/blink/renderer/core/dom/id_target_observer.cc
+++ b/chromium/third_party/blink/renderer/core/dom/id_target_observer.cc
@@ -37,7 +37,7 @@ IdTargetObserver::IdTargetObserver(IdTargetObserverRegistry& observer_registry,
IdTargetObserver::~IdTargetObserver() = default;
-void IdTargetObserver::Trace(blink::Visitor* visitor) {
+void IdTargetObserver::Trace(Visitor* visitor) {
visitor->Trace(registry_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/id_target_observer.h b/chromium/third_party/blink/renderer/core/dom/id_target_observer.h
index 69ae02539e6..13bce1cf590 100644
--- a/chromium/third_party/blink/renderer/core/dom/id_target_observer.h
+++ b/chromium/third_party/blink/renderer/core/dom/id_target_observer.h
@@ -36,7 +36,7 @@ class IdTargetObserverRegistry;
class IdTargetObserver : public GarbageCollectedFinalized<IdTargetObserver> {
public:
virtual ~IdTargetObserver();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
virtual void IdTargetChanged() = 0;
virtual void Unregister();
diff --git a/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.cc b/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
index 7c73ad21e8a..3c8baed19d1 100644
--- a/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
+++ b/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
@@ -33,7 +33,7 @@ IdTargetObserverRegistry* IdTargetObserverRegistry::Create() {
return MakeGarbageCollected<IdTargetObserverRegistry>();
}
-void IdTargetObserverRegistry::Trace(blink::Visitor* visitor) {
+void IdTargetObserverRegistry::Trace(Visitor* visitor) {
visitor->Trace(registry_);
visitor->Trace(notifying_observers_in_set_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.h b/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.h
index fd7d78960a3..bb55fe61bcc 100644
--- a/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.h
+++ b/chromium/third_party/blink/renderer/core/dom/id_target_observer_registry.h
@@ -46,7 +46,7 @@ class IdTargetObserverRegistry final
IdTargetObserverRegistry() : notifying_observers_in_set_(nullptr) {}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void NotifyObservers(const AtomicString& id);
bool HasObservers(const AtomicString& id) const;
diff --git a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index 24f2266c427..0ab2778a21f 100644
--- a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -292,7 +292,7 @@ void ReattachLegacyLayoutObjectList::ForceLegacyLayoutIfNeeded() {
state_ = State::kClosed;
}
-void ReattachLegacyLayoutObjectList::Trace(blink::Visitor* visitor) {
+void ReattachLegacyLayoutObjectList::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.h b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.h
index f71adc0d85b..ab2f711c7ab 100644
--- a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.h
+++ b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.h
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -86,7 +87,8 @@ class LayoutTreeBuilder {
// AddChild() implementations to walk up the tree to find the correct
// layout tree parent/siblings.
if (next && next->IsText() && next->Parent()->IsAnonymous() &&
- next->Parent()->IsInline()) {
+ next->Parent()->IsInline() &&
+ !ToLayoutInline(next->Parent())->IsFirstLineAnonymous()) {
return next->Parent();
}
return next;
@@ -155,7 +157,7 @@ class CORE_EXPORT ReattachLegacyLayoutObjectList final {
}
void ForceLegacyLayoutIfNeeded();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Member<Document> document_;
diff --git a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
index 9c02d00533a..878f2efead0 100644
--- a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
@@ -304,17 +304,11 @@ LayoutObject* LayoutTreeBuilderTraversal::NextInTopLayer(
wtf_size_t position = top_layer_elements.Find(&element);
DCHECK_NE(position, kNotFound);
for (wtf_size_t i = position + 1; i < top_layer_elements.size(); ++i) {
- if (top_layer_elements[i]->NeedsReattachLayoutTree()) {
- // top_layer_elements[i] is either about to have its LayoutObject removed
- // from the LayoutView or it has just been moved to the top layer and the
- // current LayoutObject is not in LayoutView and should not be considered
- // as a LayoutObject sibling. For the former case we could use it as a
- // sibling, but for the latter using it as a sibling will confuse the
- // AddChild code as it will not have a common non-anonymous layout tree
- // ancestor.
- continue;
- }
- if (LayoutObject* layout_object = top_layer_elements[i]->GetLayoutObject())
+ LayoutObject* layout_object = top_layer_elements[i]->GetLayoutObject();
+ // If top_layer_elements[i] is not a LayoutView child, its LayoutObject is
+ // not re-attached and not in the top layer yet, thus we can not use it as a
+ // sibling LayoutObject.
+ if (layout_object && layout_object->Parent()->IsLayoutView())
return layout_object;
}
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/dom/live_node_list.cc b/chromium/third_party/blink/renderer/core/dom/live_node_list.cc
index 4be5c8db964..cb200589697 100644
--- a/chromium/third_party/blink/renderer/core/dom/live_node_list.cc
+++ b/chromium/third_party/blink/renderer/core/dom/live_node_list.cc
@@ -88,7 +88,7 @@ Element* LiveNodeList::TraverseBackwardToOffset(
current_element, &RootNode(), offset, current_offset, IsMatch(*this));
}
-void LiveNodeList::Trace(blink::Visitor* visitor) {
+void LiveNodeList::Trace(Visitor* visitor) {
visitor->Trace(collection_items_cache_);
LiveNodeListBase::Trace(visitor);
NodeList::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/dom/live_node_list.h b/chromium/third_party/blink/renderer/core/dom/live_node_list.h
index b4dcb24c380..37f27fe048d 100644
--- a/chromium/third_party/blink/renderer/core/dom/live_node_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/live_node_list.h
@@ -71,7 +71,7 @@ class CORE_EXPORT LiveNodeList : public NodeList, public LiveNodeListBase {
Element& current_node,
unsigned& current_offset) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Node* VirtualOwnerNode() const final;
diff --git a/chromium/third_party/blink/renderer/core/dom/live_node_list_base.h b/chromium/third_party/blink/renderer/core/dom/live_node_list_base.h
index 2a1d02984e0..0884032b5af 100644
--- a/chromium/third_party/blink/renderer/core/dom/live_node_list_base.h
+++ b/chromium/third_party/blink/renderer/core/dom/live_node_list_base.h
@@ -77,7 +77,7 @@ class CORE_EXPORT LiveNodeListBase : public GarbageCollectedMixin {
static bool ShouldInvalidateTypeOnAttributeChange(NodeListInvalidationType,
const QualifiedName&);
- void Trace(blink::Visitor* visitor) override { visitor->Trace(owner_node_); }
+ void Trace(Visitor* visitor) override { visitor->Trace(owner_node_); }
protected:
Document& GetDocument() const { return owner_node_->GetDocument(); }
diff --git a/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.cc b/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.cc
index 7250fafc569..bb032edd84f 100644
--- a/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.cc
+++ b/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.cc
@@ -30,7 +30,7 @@ void LiveNodeListRegistry::Remove(const LiveNodeListBase* list,
RecomputeMask();
}
-void LiveNodeListRegistry::Trace(blink::Visitor* visitor) {
+void LiveNodeListRegistry::Trace(Visitor* visitor) {
visitor->RegisterWeakMembers<LiveNodeListRegistry,
&LiveNodeListRegistry::ClearWeakMembers>(this);
}
@@ -44,7 +44,7 @@ void LiveNodeListRegistry::RecomputeMask() {
void LiveNodeListRegistry::ClearWeakMembers(Visitor*) {
auto* it = std::remove_if(data_.begin(), data_.end(), [](Entry entry) {
- return !ObjectAliveTrait<LiveNodeListBase>::IsHeapObjectAlive(entry.first);
+ return !ThreadHeap::IsHeapObjectAlive(entry.first);
});
if (it == data_.end())
return;
diff --git a/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.h b/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.h
index ae72920d3c8..fb4b87df88b 100644
--- a/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.h
+++ b/chromium/third_party/blink/renderer/core/dom/live_node_list_registry.h
@@ -45,7 +45,7 @@ class CORE_EXPORT LiveNodeListRegistry {
return mask_ & MaskForInvalidationType(type);
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
static inline unsigned MaskForInvalidationType(
diff --git a/chromium/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc b/chromium/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc
index 48b0416b369..10783807850 100644
--- a/chromium/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc
@@ -101,14 +101,15 @@ TEST_F(LiveNodeListRegistryTest, ExplicitRemove) {
struct LiveNodeListRegistryWrapper
: public GarbageCollectedFinalized<LiveNodeListRegistryWrapper> {
LiveNodeListRegistry registry;
- void Trace(blink::Visitor* visitor) { visitor->Trace(registry); }
+ void Trace(Visitor* visitor) { visitor->Trace(registry); }
};
// The set of types which match should be updated as elements are removed due to
// the garbage collected. Similar to the previous case, except all references to
// |a| are removed together by the GC.
TEST_F(LiveNodeListRegistryTest, ImplicitRemove) {
- auto wrapper = WrapPersistent(new LiveNodeListRegistryWrapper);
+ auto wrapper =
+ WrapPersistent(MakeGarbageCollected<LiveNodeListRegistryWrapper>());
auto& registry = wrapper->registry;
auto a = WrapPersistent(CreateNodeList());
auto b = WrapPersistent(CreateNodeList());
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer.cc b/chromium/third_party/blink/renderer/core/dom/mutation_observer.cc
index 34227f76acd..a14b7aa53e7 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer.cc
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer.cc
@@ -73,7 +73,7 @@ class MutationObserver::V8DelegateImpl final
callback_->InvokeAndReportException(&observer, records, &observer);
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(callback_);
MutationObserver::Delegate::Trace(visitor);
ContextClient::Trace(visitor);
@@ -372,7 +372,7 @@ void MutationObserver::DeliverMutations() {
slot->DispatchSlotChangeEvent();
}
-void MutationObserver::Trace(blink::Visitor* visitor) {
+void MutationObserver::Trace(Visitor* visitor) {
visitor->Trace(delegate_);
visitor->Trace(records_);
visitor->Trace(registrations_);
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer.h b/chromium/third_party/blink/renderer/core/dom/mutation_observer.h
index 5013393edca..b4dfc5992bf 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer.h
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer.h
@@ -85,7 +85,7 @@ class CORE_EXPORT MutationObserver final
virtual ExecutionContext* GetExecutionContext() const = 0;
virtual void Deliver(const MutationRecordVector& records,
MutationObserver&) = 0;
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
const char* NameInHeapSnapshot() const override {
return "MutationObserver::Delegate";
}
@@ -117,7 +117,7 @@ class CORE_EXPORT MutationObserver final
// Eagerly finalized as destructor accesses heap object members.
EAGERLY_FINALIZE();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
struct ObserverLessThan;
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc b/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc
index e6c553ecf22..899ff635d7c 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc
@@ -88,7 +88,7 @@ void MutationObserverInterestGroup::EnqueueMutationRecord(
}
}
-void MutationObserverInterestGroup::Trace(blink::Visitor* visitor) {
+void MutationObserverInterestGroup::Trace(Visitor* visitor) {
visitor->Trace(observers_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h b/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h
index 341a5cbda19..966474e7110 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h
@@ -83,7 +83,7 @@ class MutationObserverInterestGroup final
bool IsOldValueRequested();
void EnqueueMutationRecord(MutationRecord*);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
static MutationObserverInterestGroup* CreateIfNeeded(
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.cc b/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.cc
index 156a106ee30..cb96ce57d75 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.cc
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.cc
@@ -148,7 +148,7 @@ void MutationObserverRegistration::AddRegistrationNodesToSet(
nodes.insert(iter->Get());
}
-void MutationObserverRegistration::Trace(blink::Visitor* visitor) {
+void MutationObserverRegistration::Trace(Visitor* visitor) {
visitor->Trace(observer_);
visitor->Trace(registration_node_);
visitor->Trace(registration_node_keep_alive_);
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.h b/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.h
index bfcff43fb48..57ee4735261 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.h
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer_registration.h
@@ -88,7 +88,7 @@ class CORE_EXPORT MutationObserverRegistration final
void Dispose();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
const char* NameInHeapSnapshot() const override {
return "MutationObserverRegistration";
}
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_observer_test.cc b/chromium/third_party/blink/renderer/core/dom/mutation_observer_test.cc
index 4f8b0290f53..63598f4016c 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_observer_test.cc
@@ -22,7 +22,7 @@ class EmptyMutationCallback : public MutationObserver::Delegate {
void Deliver(const MutationRecordVector&, MutationObserver&) override {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(document_);
MutationObserver::Delegate::Trace(visitor);
}
@@ -40,8 +40,8 @@ TEST(MutationObserverTest, DisconnectCrash) {
root->SetInnerHTMLFromString("<head><title>\n</title></head><body></body>");
Node* head = root->firstChild()->firstChild();
DCHECK(head);
- Persistent<MutationObserver> observer =
- MutationObserver::Create(new EmptyMutationCallback(*document));
+ Persistent<MutationObserver> observer = MutationObserver::Create(
+ MakeGarbageCollected<EmptyMutationCallback>(*document));
MutationObserverInit* init = MutationObserverInit::Create();
init->setCharacterDataOldValue(false);
observer->observe(head, init, ASSERT_NO_EXCEPTION);
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_record.cc b/chromium/third_party/blink/renderer/core/dom/mutation_record.cc
index a8fe80cba29..c4909cd8c34 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_record.cc
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_record.cc
@@ -53,7 +53,7 @@ class ChildListRecord : public MutationRecord {
previous_sibling_(previous_sibling),
next_sibling_(next_sibling) {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(target_);
visitor->Trace(added_nodes_);
visitor->Trace(removed_nodes_);
@@ -82,7 +82,7 @@ class RecordWithEmptyNodeLists : public MutationRecord {
RecordWithEmptyNodeLists(Node* target, const String& old_value)
: target_(target), old_value_(old_value) {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(target_);
visitor->Trace(added_nodes_);
visitor->Trace(removed_nodes_);
@@ -145,7 +145,7 @@ class MutationRecordWithNullOldValue : public MutationRecord {
public:
MutationRecordWithNullOldValue(MutationRecord* record) : record_(record) {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(record_);
MutationRecord::Trace(visitor);
}
@@ -191,24 +191,24 @@ MutationRecord* MutationRecord::CreateChildList(Node* target,
StaticNodeList* removed,
Node* previous_sibling,
Node* next_sibling) {
- return new ChildListRecord(target, added, removed, previous_sibling,
- next_sibling);
+ return MakeGarbageCollected<ChildListRecord>(target, added, removed,
+ previous_sibling, next_sibling);
}
MutationRecord* MutationRecord::CreateAttributes(
Node* target,
const QualifiedName& name,
const AtomicString& old_value) {
- return new AttributesRecord(target, name, old_value);
+ return MakeGarbageCollected<AttributesRecord>(target, name, old_value);
}
MutationRecord* MutationRecord::CreateCharacterData(Node* target,
const String& old_value) {
- return new CharacterDataRecord(target, old_value);
+ return MakeGarbageCollected<CharacterDataRecord>(target, old_value);
}
MutationRecord* MutationRecord::CreateWithNullOldValue(MutationRecord* record) {
- return new MutationRecordWithNullOldValue(record);
+ return MakeGarbageCollected<MutationRecordWithNullOldValue>(record);
}
MutationRecord::~MutationRecord() = default;
diff --git a/chromium/third_party/blink/renderer/core/dom/mutation_record.h b/chromium/third_party/blink/renderer/core/dom/mutation_record.h
index 16a695db2a7..bc692474a00 100644
--- a/chromium/third_party/blink/renderer/core/dom/mutation_record.h
+++ b/chromium/third_party/blink/renderer/core/dom/mutation_record.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_MUTATION_RECORD_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_MUTATION_RECORD_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -43,7 +44,7 @@ template <typename NodeType>
class StaticNodeTypeList;
using StaticNodeList = StaticNodeTypeList<Node>;
-class MutationRecord : public ScriptWrappable {
+class CORE_EXPORT MutationRecord : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/core/dom/named_node_map.cc b/chromium/third_party/blink/renderer/core/dom/named_node_map.cc
index f0b19a3c7f9..af97e374a74 100644
--- a/chromium/third_party/blink/renderer/core/dom/named_node_map.cc
+++ b/chromium/third_party/blink/renderer/core/dom/named_node_map.cc
@@ -126,7 +126,7 @@ bool NamedNodeMap::NamedPropertyQuery(const AtomicString& name,
return properties.Contains(name);
}
-void NamedNodeMap::Trace(blink::Visitor* visitor) {
+void NamedNodeMap::Trace(Visitor* visitor) {
visitor->Trace(element_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/named_node_map.h b/chromium/third_party/blink/renderer/core/dom/named_node_map.h
index a8209b6c484..4e7b144fb32 100644
--- a/chromium/third_party/blink/renderer/core/dom/named_node_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/named_node_map.h
@@ -69,7 +69,7 @@ class NamedNodeMap final : public ScriptWrappable {
void NamedPropertyEnumerator(Vector<String>& names, ExceptionState&) const;
bool NamedPropertyQuery(const AtomicString&, ExceptionState&) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<Element> element_;
diff --git a/chromium/third_party/blink/renderer/core/dom/names_map.cc b/chromium/third_party/blink/renderer/core/dom/names_map.cc
index ad7dbc30b11..d289df5f1ac 100644
--- a/chromium/third_party/blink/renderer/core/dom/names_map.cc
+++ b/chromium/third_party/blink/renderer/core/dom/names_map.cc
@@ -38,20 +38,23 @@ void NamesMap::Add(const AtomicString& key, const AtomicString& value) {
add_result.stored_value->value.value().Add(value);
}
-// Parser for HTML partmap attribute. See
-// http://drafts.csswg.org/css-shadow-parts/ but with modifications.
+// Parser for HTML exportparts attribute. See
+// http://drafts.csswg.org/css-shadow-parts/.
//
-// This implements a modified version where the key is first and the value is
-// second and => is not used to separate key and value. It also allows an ident
-// token on its own as a short-hand for forwarding with the same name.
+// Summary is that we are parsing a comma-separated list of part-mappings. A
+// part mapping is a part name or 2 colon-separated part names. If any
+// part-mapping is invalid, we ignore it and continue parsing after the next
+// comma. Part names are delimited by space, comma or colon. Apart from that,
+// whitespace is not significant.
// The states that can occur while parsing the part map and their transitions.
-// A "+" indicates that this transition should consume the current character.
-// A "*" indicates that this is invalid input, usually the decision here is
-// to just do our best and recover gracefully.
+// A "+" indicates that this transition should consume the current character. A
+// "*" indicates that this is invalid input. In general invalid input causes us
+// to reject the current mapping and returns us to searching for a comma.
enum State {
kPreKey, // Searching for the start of a key:
- // space, comma, colon* -> kPreKey+
+ // space, comma -> kPreKey+
+ // colon* -> kError+
// else -> kKey
kKey, // Searching for the end of a key:
// comma -> kPreKey+
@@ -61,18 +64,24 @@ enum State {
kPostKey, // Searching for a delimiter:
// comma -> kPreKey+
// colon -> kPreValue+
- // space, else* -> kPostKey+
+ // space -> kPostKey+
+ // else* -> kError+
kPreValue, // Searching for the start of a value:
- // comma -> kPreKey+
- // colon*, space -> kPreValue+
+ // colon* -> kPostValue+
+ // comma* -> kPreKey+
+ // space -> kPreValue+
// else -> kValue+
kValue, // Searching for the end of a value:
// comma -> kPreKey+
- // colon*, space -> kPostValue+
+ // space -> kPostValue+
+ // colon* -> kError+
// else -> kValue+
kPostValue, // Searching for the comma after the value:
// comma -> kPreKey+
- // colon*, else -> kPostValue+
+ // colon*, else* -> kError+
+ kError, // Searching for the comma after an error:
+ // comma -> kPreKey+
+ // else* -> kError+
};
template <typename CharacterType>
@@ -86,27 +95,30 @@ void NamesMap::Set(const AtomicString& source,
// The start of the current token.
unsigned start = 0;
State state = kPreKey;
+ // The key and value are held here until we succeed in parsing a valid
+ // part-mapping.
AtomicString key;
+ AtomicString value;
while (cur < length) {
- // Almost all cases break, ensuring that some input is consumed and we avoid
- // an infinite loop. For the few transitions which should happen without
- // consuming input we fall through into the new state's case. This makes it
- // easy to see the cases which don't consume input and check that they lead
- // to a case which does.
+ // All cases break, ensuring that some input is consumed and we avoid
+ // an infinite loop.
//
// The only state which should set a value for key is kKey, as we leave the
// state.
switch (state) {
case kPreKey:
- // Skip any number of spaces, commas and colons. When we find something
- // else, it is the start of a key.
- if ((IsHTMLSpaceOrComma<CharacterType>(characters[cur]) ||
- IsColon<CharacterType>(characters[cur]))) {
+ // Skip any number of spaces, commas. When we find something else, it is
+ // the start of a key.
+ if (IsHTMLSpaceOrComma<CharacterType>(characters[cur]))
+ break;
+ // Colon is invalid here.
+ if (IsColon<CharacterType>(characters[cur])) {
+ state = kError;
break;
}
start = cur;
state = kKey;
- FALLTHROUGH;
+ break;
case kKey:
// At a comma this was a key without a value, the implicit value is the
// same as the key.
@@ -133,21 +145,24 @@ void NamesMap::Set(const AtomicString& source,
// At a colon this was a key with a value, we expect a value.
} else if (IsColon<CharacterType>(characters[cur])) {
state = kPreValue;
+ // Anything else except space is invalid.
+ } else if (!IsHTMLSpace<CharacterType>(characters[cur])) {
+ key = g_null_atom;
+ state = kError;
}
- // Spaces should be consumed. We consume other characters too
- // although the input is invalid
break;
case kPreValue:
- // At a comma this was a key without a value, the implicit value is the
- // same as the key.
- if (IsComma<CharacterType>(characters[cur])) {
- Add(key, key);
+ // Colon is invalid.
+ if (IsColon<CharacterType>(characters[cur])) {
+ state = kError;
+ // Comma is invalid.
+ } else if (IsComma<CharacterType>(characters[cur])) {
state = kPreKey;
+ // Space is ignored.
+ } else if (IsHTMLSpace<CharacterType>(characters[cur])) {
+ break;
// If we reach a non-space character, we have found the start of the
// value.
- } else if (IsColon<CharacterType>(characters[cur]) ||
- IsHTMLSpace<CharacterType>(characters[cur])) {
- break;
} else {
start = cur;
state = kValue;
@@ -157,21 +172,35 @@ void NamesMap::Set(const AtomicString& source,
// At a comma, we have found the end of the value and expect
// the next key.
if (IsComma<CharacterType>(characters[cur])) {
- Add(key, AtomicString(characters + start, cur - start));
+ value = AtomicString(characters + start, cur - start);
+ Add(key, value);
state = kPreKey;
- // At a space or colon, we have found the end of the value,
- // although a colon is invalid here.
+ // At a space, we have found the end of the value, store it.
} else if (IsHTMLSpace<CharacterType>(characters[cur]) ||
IsColon<CharacterType>(characters[cur])) {
- Add(key, AtomicString(characters + start, cur - start));
+ value = AtomicString(characters + start, cur - start);
state = kPostValue;
+ // A colon is invalid.
+ } else if (IsColon<CharacterType>(characters[cur])) {
+ state = kError;
}
break;
case kPostValue:
- // At a comma, we start looking for the next key.
+ // At a comma, accept what we have and start looking for the next key.
+ if (IsComma<CharacterType>(characters[cur])) {
+ Add(key, value);
+ state = kPreKey;
+ // Anything else except a space is invalid.
+ } else if (!IsHTMLSpace<CharacterType>(characters[cur])) {
+ state = kError;
+ }
+ break;
+ case kError:
+ // At a comma, start looking for the next key.
if (IsComma<CharacterType>(characters[cur])) {
state = kPreKey;
}
+ // Anything else is consumed.
break;
}
@@ -187,15 +216,19 @@ void NamesMap::Set(const AtomicString& source,
key = AtomicString(characters + start, cur - start);
FALLTHROUGH;
case kPostKey:
- case kPreValue:
- // The string ends after a key but with nothing else useful.
+ // The string ends with a key.
Add(key, key);
break;
+ case kPreValue:
+ break;
case kValue:
// The string ends with a value.
- Add(key, AtomicString(characters + start, cur - start));
- break;
+ value = AtomicString(characters + start, cur - start);
+ FALLTHROUGH;
case kPostValue:
+ Add(key, value);
+ break;
+ case kError:
break;
}
}
diff --git a/chromium/third_party/blink/renderer/core/dom/names_map.h b/chromium/third_party/blink/renderer/core/dom/names_map.h
index cf098ce31a2..00ec9fe2868 100644
--- a/chromium/third_party/blink/renderer/core/dom/names_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/names_map.h
@@ -18,23 +18,16 @@
namespace blink {
// Parses and stores mappings from part name to ordered set of part names as in
-// http://drafts.csswg.org/css-shadow-parts/ (with modifications).
+// http://drafts.csswg.org/css-shadow-parts/.
// TODO(crbug/805271): Deduplicate identical maps as SpaceSplitString does so
-// that elements with identical partmap attributes share instances.
+// that elements with identical exportparts attributes share instances.
class CORE_EXPORT NamesMap {
public:
NamesMap() = default;
explicit NamesMap(const AtomicString& string);
// Clears any existing mapping, parses the string and sets the mapping from
- // that. This implements a modified version from the spec, where the key is
- // first and the value is second and "=>" is not used to separate key and
- // value. It also allows an ident token on its own as a short-hand for
- // forwarding with the same name. So "a b, a c, d e, f" becomes
- //
- // a: {b, c}
- // d: {e}
- // f: {f}
+ // that.
void Set(const AtomicString&);
void Clear() { data_.clear(); };
// Inserts value into the ordered set under key.
diff --git a/chromium/third_party/blink/renderer/core/dom/names_map_test.cc b/chromium/third_party/blink/renderer/core/dom/names_map_test.cc
index 995fade172d..fb3b7f0af66 100644
--- a/chromium/third_party/blink/renderer/core/dom/names_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/names_map_test.cc
@@ -26,48 +26,103 @@ void ExpectEqMap(const ExpectedMap& exp, NamesMap& map) {
}
TEST(NamesMapTest, Set) {
- Vector<std::pair<String, ExpectedMap>> test_cases({
- // Various valid values.
- {"foo", {{"foo", "foo"}}},
- {"foo: bar", {{"foo", "bar"}}},
- {"foo : bar", {{"foo", "bar"}}},
- {"foo: bar, foo: buz", {{"foo", "bar buz"}}},
- {"foo: bar, buz", {{"foo", "bar"}, {"buz", "buz"}}},
- {"foo: bar, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo, buz: bar", {{"foo", "foo"}, {"buz", "bar"}}},
-
- // This is an error but qux should be ignored.
- {"foo: bar qux, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar qux", {{"foo", "bar"}, {"buz", "bar"}}},
-
- // This is an error but the extra commas and colons should be ignored.
- {"foo:", {{"foo", "foo"}}},
- {"foo:,", {{"foo", "foo"}}},
- {"foo :", {{"foo", "foo"}}},
- {"foo :,", {{"foo", "foo"}}},
- {"foo: bar, buz:", {{"foo", "bar"}, {"buz", "buz"}}},
- {"foo: bar, buz :", {{"foo", "bar"}, {"buz", "buz"}}},
- {",foo: bar, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar,, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar,", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar,,", {{"foo", "bar"}, {"buz", "bar"}}},
- {":foo: bar, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar:, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: :bar, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar:", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar::", {{"foo", "bar"}, {"buz", "bar"}}},
-
- // Spaces in odd places.
- {" foo: bar, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar", {{"foo", "bar"}, {"buz", "bar"}}},
- {"foo: bar, buz: bar ", {{"foo", "bar"}, {"buz", "bar"}}},
+ // This is vector of pairs where first is an expected output and second is a
+ // vector of inputs, all of which should produce that output.
+ Vector<std::pair<ExpectedMap, Vector<String>>> test_cases({
+ // First a set of tests where we have an expected value and several valid
+ // strings that encode that value, followed by strings encode the same
+ // value but include invalid input.
+ {{},
+ {
+ // Valid
+ "",
+ " ",
+ " ",
+ ",",
+ ",,",
+ " ,",
+ ", ",
+ " , , ",
+ // Invalid
+ ":",
+ "foo:",
+ "foo: bar buz",
+ ":bar",
+ ": bar buz",
+ }},
+ {{{"foo", "foo"}},
+ {
+ // Valid
+ "foo",
+ " foo",
+ ", foo",
+ ", foo",
+ "foo",
+ "foo ",
+ "foo,",
+ "foo ,"
+ // Plus invalid
+ ":,foo",
+ ":bar,foo",
+ "bar:,foo",
+ "bar: bar buz,foo",
+ "foo,:",
+ "foo, :bar",
+ "foo, bar:",
+ "foo, bar: bar buz",
+ }},
+ {{{"foo", "bar"}},
+ {
+ // Valid
+ "foo:bar",
+ " foo:bar",
+ "foo :bar",
+ "foo: bar",
+ "foo:bar ",
+ "foo:bar",
+ ",foo:bar",
+ ", foo:bar",
+ " ,foo:bar",
+ "foo:bar,",
+ "foo:bar, ",
+ "foo:bar ,",
+ // Plus invalid
+ ":,foo:bar",
+ ":bar,foo:bar",
+ "bar:,foo:bar",
+ "bar: bar buz,foo:bar",
+ "foo:bar,:",
+ "foo:bar, :bar",
+ "foo:bar, bar:",
+ "foo:bar, bar: bar buz",
+ }},
+ {{{"foo", "bar buz"}},
+ {
+ // Valid
+ "foo:bar,foo:buz",
+ "foo:bar, foo:buz",
+ "foo:bar ,foo:buz",
+ // Plus invalid. In this case invalid occurs between the valid items.
+ "foo:bar,bar:,foo:buz",
+ "foo:bar,bar: ,foo:buz",
+ "foo:bar,:bar,foo:buz",
+ "foo:bar, :bar,foo:buz",
+ "foo:bar,bar: bill bob,foo:buz",
+ }},
+ // Miscellaneous tests.
+ // Same value for 2 keys.
+ {{{"foo", "bar"}, {"buz", "bar"}}, {"foo:bar,buz:bar"}},
+ // Mix key-only with key-value.
+ {{{"foo", "foo"}, {"buz", "bar"}}, {"foo,buz:bar", "buz:bar,foo"}},
});
NamesMap map;
for (auto test_case : test_cases) {
- SCOPED_TRACE(test_case.first);
- map.Set(AtomicString(test_case.first));
- ExpectEqMap(test_case.second, map);
+ for (String input : test_case.second) {
+ SCOPED_TRACE(input);
+ map.Set(AtomicString(input));
+ ExpectEqMap(test_case.first, map);
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/dom/node.cc b/chromium/third_party/blink/renderer/core/dom/node.cc
index 89e4681f15a..651594a737e 100644
--- a/chromium/third_party/blink/renderer/core/dom/node.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node.cc
@@ -140,7 +140,7 @@ namespace {
ScrollCustomizationCallbacks& GetScrollCustomizationCallbacks() {
DEFINE_STATIC_LOCAL(Persistent<ScrollCustomizationCallbacks>,
scroll_customization_callbacks,
- (new ScrollCustomizationCallbacks));
+ (MakeGarbageCollected<ScrollCustomizationCallbacks>()));
return *scroll_customization_callbacks;
}
@@ -2793,10 +2793,40 @@ StaticNodeList* Node::getDestinationInsertionPoints() {
}
HTMLSlotElement* Node::AssignedSlot() const {
- // assignedSlot doesn't need to call updateDistribution().
+ // assignedSlot doesn't need to recalc assignment.
DCHECK(!IsPseudoElement());
- if (ShadowRoot* root = V1ShadowRootOfParent())
+ ShadowRoot* root = V1ShadowRootOfParent();
+ if (!root)
+ return nullptr;
+ if (!RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled()) {
+ return root->AssignedSlotFor(*this);
+ }
+
+ if (!root->HasSlotAssignment())
+ return nullptr;
+
+ // TODO(hayato): Node::AssignedSlot() shouldn't be called while
+ // in executing RecalcAssignment(), however, unfortunately,
+ // that could happen as follows:
+ //
+ // 1. RecalsAssignment() can detach a node
+ // 2. Then, DetachLayoutTree() may use FlatTreeTraversal via the hook of
+ // AXObjectCacheImpl::ChildrenChanged().
+ //
+ // Note that using FlatTreeTraversal in detaching layout tree should be banned
+ // in the long term.
+ //
+ // If we can remove such code path, we don't need to check
+ // IsInSlotAssignmentRecalc() here.
+ if (root->NeedsSlotAssignmentRecalc() ||
+ GetDocument().IsInSlotAssignmentRecalc()) {
+ // FlatTreeNodeData is not realiable here. Entering slow path.
return root->AssignedSlotFor(*this);
+ }
+ if (FlatTreeNodeData* data = GetFlatTreeNodeData()) {
+ DCHECK_EQ(root->AssignedSlotFor(*this), data->AssignedSlot());
+ return data->AssignedSlot();
+ }
return nullptr;
}
@@ -2812,10 +2842,10 @@ HTMLSlotElement* Node::FinalDestinationSlot() const {
}
HTMLSlotElement* Node::assignedSlotForBinding() {
- // assignedSlot doesn't need to call updateDistribution().
+ // assignedSlot doesn't need to recalc slot assignment
if (ShadowRoot* root = V1ShadowRootOfParent()) {
if (root->GetType() == ShadowRootType::kOpen)
- return root->AssignedSlotFor(*this);
+ return AssignedSlot();
}
return nullptr;
}
@@ -3008,7 +3038,7 @@ bool Node::HasMediaControlAncestor() const {
return false;
}
-void Node::Trace(blink::Visitor* visitor) {
+void Node::Trace(Visitor* visitor) {
visitor->Trace(parent_or_shadow_host_node_);
visitor->Trace(previous_);
visitor->Trace(next_);
diff --git a/chromium/third_party/blink/renderer/core/dom/node.h b/chromium/third_party/blink/renderer/core/dom/node.h
index 32e30eb5b52..9d10e865422 100644
--- a/chromium/third_party/blink/renderer/core/dom/node.h
+++ b/chromium/third_party/blink/renderer/core/dom/node.h
@@ -706,10 +706,10 @@ class CORE_EXPORT Node : public EventTarget {
// Wrapper for nodes that don't have a layoutObject, but still cache the style
// (like HTMLOptionElement).
- inline ComputedStyle* MutableComputedStyle() const;
- inline const ComputedStyle* GetComputedStyle() const;
- inline const ComputedStyle* ParentComputedStyle() const;
- inline const ComputedStyle& ComputedStyleRef() const;
+ ComputedStyle* MutableComputedStyle() const;
+ const ComputedStyle* GetComputedStyle() const;
+ const ComputedStyle* ParentComputedStyle() const;
+ const ComputedStyle& ComputedStyleRef() const;
const ComputedStyle* EnsureComputedStyle(
PseudoId pseudo_element_specifier = kPseudoIdNone) {
@@ -797,8 +797,6 @@ class CORE_EXPORT Node : public EventTarget {
const Node*,
ShadowTreesTreatment = kTreatShadowTreesAsDisconnected) const;
- Node* ToNode() final;
-
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const final;
@@ -888,7 +886,7 @@ class CORE_EXPORT Node : public EventTarget {
// If the node is a plugin, then this returns its WebPluginContainer.
WebPluginContainerImpl* GetWebPluginContainer() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
enum NodeFlags {
@@ -1022,6 +1020,8 @@ class CORE_EXPORT Node : public EventTarget {
// per-thread.
virtual String DebugNodeName() const;
+ Node* ToNode() final;
+
bool IsUserActionElementActive() const;
bool IsUserActionElementInActiveChain() const;
bool IsUserActionElementDragged() const;
@@ -1106,7 +1106,7 @@ DEFINE_COMPARISON_OPERATORS_WITH_REFERENCES(Node)
#define DECLARE_NODE_FACTORY(T) static T* Create(Document&)
#define DEFINE_NODE_FACTORY(T) \
- T* T::Create(Document& document) { return new T(document); }
+ T* T::Create(Document& document) { return MakeGarbageCollected<T>(document); }
CORE_EXPORT std::ostream& operator<<(std::ostream&, const Node&);
CORE_EXPORT std::ostream& operator<<(std::ostream&, const Node*);
diff --git a/chromium/third_party/blink/renderer/core/dom/node_computed_style.h b/chromium/third_party/blink/renderer/core/dom/node_computed_style.h
index 7e6bf7f6e06..12322e297e2 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_computed_style.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_computed_style.h
@@ -54,7 +54,12 @@ inline const ComputedStyle* Node::ParentComputedStyle() const {
if (!CanParticipateInFlatTree())
return nullptr;
ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(*this);
- return parent ? parent->GetComputedStyle() : nullptr;
+ if (parent && parent->ChildrenCanHaveStyle()) {
+ const ComputedStyle* parent_style = parent->GetComputedStyle();
+ if (parent_style && !parent_style->IsEnsuredInDisplayNone())
+ return parent_style;
+ }
+ return nullptr;
}
inline const ComputedStyle& Node::ComputedStyleRef() const {
diff --git a/chromium/third_party/blink/renderer/core/dom/node_iterator.cc b/chromium/third_party/blink/renderer/core/dom/node_iterator.cc
index 7c514b0bee0..a54a1aafc19 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_iterator.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node_iterator.cc
@@ -199,7 +199,7 @@ void NodeIterator::UpdateForNodeRemoval(Node& removed_node,
}
}
-void NodeIterator::Trace(blink::Visitor* visitor) {
+void NodeIterator::Trace(Visitor* visitor) {
visitor->Trace(reference_node_);
visitor->Trace(candidate_node_);
ScriptWrappable::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/dom/node_iterator.h b/chromium/third_party/blink/renderer/core/dom/node_iterator.h
index b3707560da9..4ad2a3bd245 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_iterator.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_iterator.h
@@ -58,7 +58,7 @@ class NodeIterator final : public ScriptWrappable, public NodeIteratorBase {
// This function is called before any node is removed from the document tree.
void NodeWillBeRemoved(Node&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
class NodePointer {
@@ -75,7 +75,7 @@ class NodeIterator final : public ScriptWrappable, public NodeIteratorBase {
Member<Node> node;
bool is_pointer_before_node;
- void Trace(blink::Visitor* visitor) { visitor->Trace(node); }
+ void Trace(Visitor* visitor) { visitor->Trace(node); }
};
void UpdateForNodeRemoval(Node& node_to_be_removed, NodePointer&) const;
diff --git a/chromium/third_party/blink/renderer/core/dom/node_iterator_base.cc b/chromium/third_party/blink/renderer/core/dom/node_iterator_base.cc
index 6835dd716e4..5c09ca00ba3 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_iterator_base.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node_iterator_base.cc
@@ -88,7 +88,7 @@ unsigned NodeIteratorBase::AcceptNode(Node* node,
return result;
}
-void NodeIteratorBase::Trace(blink::Visitor* visitor) {
+void NodeIteratorBase::Trace(Visitor* visitor) {
visitor->Trace(root_);
visitor->Trace(filter_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/node_iterator_base.h b/chromium/third_party/blink/renderer/core/dom/node_iterator_base.h
index d58dcf604cc..f90d919fdf4 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_iterator_base.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_iterator_base.h
@@ -42,7 +42,7 @@ class NodeIteratorBase : public GarbageCollectedMixin {
unsigned whatToShow() const { return what_to_show_; }
V8NodeFilter* filter() const { return filter_.Get(); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
NodeIteratorBase(Node*, unsigned what_to_show, V8NodeFilter*);
diff --git a/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.cc b/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.cc
index dfa31e4f94d..055dc5af715 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.cc
@@ -45,7 +45,7 @@ void NodeListsNodeData::InvalidateCaches(const QualifiedName* attr_name) {
cache.value->InvalidateCache();
}
-void NodeListsNodeData::Trace(blink::Visitor* visitor) {
+void NodeListsNodeData::Trace(Visitor* visitor) {
visitor->Trace(child_node_list_);
visitor->Trace(atomic_name_caches_);
visitor->Trace(tag_collection_ns_caches_);
diff --git a/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.h b/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.h
index e562e8badda..246d997b279 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_lists_node_data.h
@@ -174,7 +174,7 @@ class NodeListsNodeData final : public GarbageCollected<NodeListsNodeData> {
}
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
// Can be a ChildNodeList or an EmptyNodeList.
diff --git a/chromium/third_party/blink/renderer/core/dom/node_rare_data.cc b/chromium/third_party/blink/renderer/core/dom/node_rare_data.cc
index 89c6f58e7d3..8ec8440a213 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_rare_data.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node_rare_data.cc
@@ -55,7 +55,7 @@ NodeMutationObserverData* NodeMutationObserverData::Create() {
static_assert(sizeof(NodeRareData) == sizeof(SameSizeAsNodeRareData),
"NodeRareData should stay small");
-void NodeMutationObserverData::Trace(blink::Visitor* visitor) {
+void NodeMutationObserverData::Trace(Visitor* visitor) {
visitor->Trace(registry_);
visitor->Trace(transient_registry_);
}
@@ -92,7 +92,7 @@ void NodeRareData::TraceAfterDispatch(blink::Visitor* visitor) {
visitor->Trace(node_lists_);
}
-void NodeRareData::Trace(blink::Visitor* visitor) {
+void NodeRareData::Trace(Visitor* visitor) {
if (is_element_rare_data_)
static_cast<ElementRareData*>(this)->TraceAfterDispatch(visitor);
else
diff --git a/chromium/third_party/blink/renderer/core/dom/node_rare_data.h b/chromium/third_party/blink/renderer/core/dom/node_rare_data.h
index 2e4ec9c7c6a..fe3e6ca5cc8 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_rare_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -59,7 +59,7 @@ class NodeMutationObserverData final
void AddRegistration(MutationObserverRegistration* registration);
void RemoveRegistration(MutationObserverRegistration* registration);
- void Trace(blink::Visitor* visitor);
+ void Trace(Visitor* visitor);
private:
HeapVector<TraceWrapperMember<MutationObserverRegistration>> registry_;
@@ -191,7 +191,7 @@ class NodeRareData : public GarbageCollectedFinalized<NodeRareData>,
kNumberOfDynamicRestyleFlags = 14
};
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void TraceAfterDispatch(blink::Visitor*);
void FinalizeGarbageCollectedObject();
diff --git a/chromium/third_party/blink/renderer/core/dom/nth_index_cache.cc b/chromium/third_party/blink/renderer/core/dom/nth_index_cache.cc
index 8c31f852a2c..ead53713a34 100644
--- a/chromium/third_party/blink/renderer/core/dom/nth_index_cache.cc
+++ b/chromium/third_party/blink/renderer/core/dom/nth_index_cache.cc
@@ -257,7 +257,7 @@ NthIndexData::NthIndexData(ContainerNode& parent, const QualifiedName& type) {
count_ = count;
}
-void NthIndexData::Trace(blink::Visitor* visitor) {
+void NthIndexData::Trace(Visitor* visitor) {
visitor->Trace(element_index_map_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/nth_index_cache.h b/chromium/third_party/blink/renderer/core/dom/nth_index_cache.h
index 1b9a9ccc646..b2aa37a7b9b 100644
--- a/chromium/third_party/blink/renderer/core/dom/nth_index_cache.h
+++ b/chromium/third_party/blink/renderer/core/dom/nth_index_cache.h
@@ -25,7 +25,7 @@ class CORE_EXPORT NthIndexData final : public GarbageCollected<NthIndexData> {
unsigned NthOfTypeIndex(Element&) const;
unsigned NthLastOfTypeIndex(Element&) const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
HeapHashMap<Member<Element>, unsigned> element_index_map_;
diff --git a/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc b/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
index 78e52699a7d..c4591614bce 100644
--- a/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
+++ b/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
@@ -64,7 +64,7 @@ static bool operator!=(const PresentationAttributeCacheKey& a,
struct PresentationAttributeCacheEntry final
: public GarbageCollectedFinalized<PresentationAttributeCacheEntry> {
public:
- void Trace(blink::Visitor* visitor) { visitor->Trace(value); }
+ void Trace(Visitor* visitor) { visitor->Trace(value); }
PresentationAttributeCacheKey key;
Member<CSSPropertyValueSet> value;
diff --git a/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc b/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc
index 8178485b71f..876b8a52c34 100644
--- a/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc
+++ b/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc
@@ -199,15 +199,15 @@ void ProcessingInstruction::NotifyFinished(Resource* resource) {
is_xsl_ ? IncrementLoadEventDelayCount::Create(GetDocument()) : nullptr;
if (is_xsl_) {
sheet_ = XSLStyleSheet::Create(this, resource->Url(),
- resource->GetResponse().Url());
+ resource->GetResponse().ResponseUrl());
ToXSLStyleSheet(sheet_.Get())
->ParseString(ToXSLStyleSheetResource(resource)->Sheet());
} else {
DCHECK(is_css_);
CSSStyleSheetResource* style_resource = ToCSSStyleSheetResource(resource);
CSSParserContext* parser_context = CSSParserContext::Create(
- GetDocument(), style_resource->GetResponse().Url(),
- style_resource->GetResponse().IsOpaqueResponseFromServiceWorker(),
+ GetDocument(), style_resource->GetResponse().ResponseUrl(),
+ style_resource->GetResponse().IsCorsSameOrigin(),
style_resource->GetReferrerPolicy(), style_resource->Encoding());
StyleSheetContents* new_sheet =
@@ -289,7 +289,7 @@ void ProcessingInstruction::RemovePendingSheet() {
style_engine_context_);
}
-void ProcessingInstruction::Trace(blink::Visitor* visitor) {
+void ProcessingInstruction::Trace(Visitor* visitor) {
visitor->Trace(sheet_);
visitor->Trace(listener_for_xslt_);
CharacterData::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/dom/processing_instruction.h b/chromium/third_party/blink/renderer/core/dom/processing_instruction.h
index 8341102cbd7..8975bc5a723 100644
--- a/chromium/third_party/blink/renderer/core/dom/processing_instruction.h
+++ b/chromium/third_party/blink/renderer/core/dom/processing_instruction.h
@@ -44,7 +44,7 @@ class CORE_EXPORT ProcessingInstruction final : public CharacterData,
ProcessingInstruction(Document&, const String& target, const String& data);
~ProcessingInstruction() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
const String& target() const { return target_; }
const String& LocalHref() const { return local_href_; }
@@ -64,7 +64,7 @@ class CORE_EXPORT ProcessingInstruction final : public CharacterData,
// Detach event listener from its processing instruction.
virtual void Detach() = 0;
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
};
void SetEventListenerForXSLT(DetachableEventListener* listener) {
diff --git a/chromium/third_party/blink/renderer/core/dom/pseudo_element_data.h b/chromium/third_party/blink/renderer/core/dom/pseudo_element_data.h
index 76db5ac2b0d..2e3d64f2f8c 100644
--- a/chromium/third_party/blink/renderer/core/dom/pseudo_element_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/pseudo_element_data.h
@@ -21,7 +21,7 @@ class PseudoElementData final : public GarbageCollected<PseudoElementData> {
PseudoElement* GetPseudoElement(PseudoId) const;
bool HasPseudoElements() const;
void ClearPseudoElements();
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(generated_before_);
visitor->Trace(generated_after_);
visitor->Trace(generated_first_letter_);
diff --git a/chromium/third_party/blink/renderer/core/dom/range.cc b/chromium/third_party/blink/renderer/core/dom/range.cc
index 2a626e82804..e2f86e3cc6a 100644
--- a/chromium/third_party/blink/renderer/core/dom/range.cc
+++ b/chromium/third_party/blink/renderer/core/dom/range.cc
@@ -1823,7 +1823,7 @@ void Range::RemoveFromSelectionIfInDifferentRoot(Document& old_document) {
selection.ClearDocumentCachedRange();
}
-void Range::Trace(blink::Visitor* visitor) {
+void Range::Trace(Visitor* visitor) {
visitor->Trace(owner_document_);
visitor->Trace(start_);
visitor->Trace(end_);
diff --git a/chromium/third_party/blink/renderer/core/dom/range.h b/chromium/third_party/blink/renderer/core/dom/range.h
index ec46883ee63..e25d568643d 100644
--- a/chromium/third_party/blink/renderer/core/dom/range.h
+++ b/chromium/third_party/blink/renderer/core/dom/range.h
@@ -176,7 +176,7 @@ class CORE_EXPORT Range final : public ScriptWrappable {
static Node* CheckNodeWOffset(Node*, unsigned offset, ExceptionState&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void SetDocument(Document&);
diff --git a/chromium/third_party/blink/renderer/core/dom/range.idl b/chromium/third_party/blink/renderer/core/dom/range.idl
index 09fcdd407c1..20959766617 100644
--- a/chromium/third_party/blink/renderer/core/dom/range.idl
+++ b/chromium/third_party/blink/renderer/core/dom/range.idl
@@ -19,9 +19,6 @@
*/
// https://dom.spec.whatwg.org/#interface-range
-// The `HTMLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
[
Constructor,
ConstructorCallWith=Document
@@ -75,5 +72,5 @@
[NewObject, RaisesException, CEReactions, CustomElementCallbacks] DocumentFragment createContextualFragment(HTMLString fragment);
// Non-standard API
- [RaisesException, DeprecateAs=RangeExpand] void expand([Default=Undefined] optional DOMString unit);
+ [RaisesException, DeprecateAs=RangeExpand] void expand([DefaultValue=Undefined] optional DOMString unit);
};
diff --git a/chromium/third_party/blink/renderer/core/dom/range_boundary_point.h b/chromium/third_party/blink/renderer/core/dom/range_boundary_point.h
index 1329ced6fbe..a4f4656f43b 100644
--- a/chromium/third_party/blink/renderer/core/dom/range_boundary_point.h
+++ b/chromium/third_party/blink/renderer/core/dom/range_boundary_point.h
@@ -59,7 +59,7 @@ class RangeBoundaryPoint {
void InvalidateOffset();
void MarkValid() const;
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(container_node_);
visitor->Trace(child_before_boundary_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.cc b/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.cc
index 8a99807a342..be1db3140f0 100644
--- a/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.cc
@@ -42,7 +42,7 @@ bool ScriptableDocumentParser::IsParsingAtLineNumber() const {
return IsParsing() && !IsWaitingForScripts() && !IsExecutingScript();
}
-void ScriptableDocumentParser::Trace(blink::Visitor* visitor) {
+void ScriptableDocumentParser::Trace(Visitor* visitor) {
visitor->Trace(inline_script_cache_handler_);
DecodedDataDocumentParser::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.h b/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.h
index f2d0177ec0d..8f13d6a6ea1 100644
--- a/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.h
+++ b/chromium/third_party/blink/renderer/core/dom/scriptable_document_parser.h
@@ -37,7 +37,7 @@ class SourceKeyedCachedMetadataHandler;
class CORE_EXPORT ScriptableDocumentParser : public DecodedDataDocumentParser {
public:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// Only used by Document::open for deciding if its safe to act on a
// JavaScript document.open() call right now, or it should be ignored.
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
index 0bcedc826eb..2ee4b8eee5e 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
@@ -45,7 +45,7 @@ std::pair<EventTarget*, StringImpl*> EventTargetKey(const Event* event) {
ScriptedAnimationController::ScriptedAnimationController(Document* document)
: document_(document), callback_collection_(document), suspend_count_(0) {}
-void ScriptedAnimationController::Trace(blink::Visitor* visitor) {
+void ScriptedAnimationController::Trace(Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(callback_collection_);
visitor->Trace(event_queue_);
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h
index a1ca3e62ab0..6b088872d33 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h
@@ -53,7 +53,7 @@ class CORE_EXPORT ScriptedAnimationController
explicit ScriptedAnimationController(Document*);
virtual ~ScriptedAnimationController() = default;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
const char* NameInHeapSnapshot() const override {
return "ScriptedAnimationController";
}
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller_test.cc b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller_test.cc
index 8be822368a7..efc56674de5 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller_test.cc
@@ -5,12 +5,13 @@
#include "third_party/blink/renderer/core/dom/scripted_animation_controller.h"
#include <memory>
+
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -117,14 +118,10 @@ TEST_F(ScriptedAnimationControllerTest, EnqueueWithinTask) {
namespace {
-class RunTaskEventListener final : public EventListener {
+class RunTaskEventListener final : public NativeEventListener {
public:
- RunTaskEventListener(base::RepeatingClosure task)
- : EventListener(kCPPEventListenerType), task_(std::move(task)) {}
+ RunTaskEventListener(base::RepeatingClosure task) : task_(std::move(task)) {}
void Invoke(ExecutionContext*, Event*) override { task_.Run(); }
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
private:
base::RepeatingClosure task_;
@@ -139,7 +136,8 @@ TEST_F(ScriptedAnimationControllerTest, EnqueueTaskAndEvent) {
Controller().EnqueueTask(observer.CreateTask(1));
GetDocument().addEventListener(
- "test", new RunTaskEventListener(observer.CreateTask(2)));
+ "test",
+ MakeGarbageCollected<RunTaskEventListener>(observer.CreateTask(2)));
Event* event = Event::Create("test");
event->SetTarget(&GetDocument());
Controller().EnqueueEvent(event);
@@ -173,7 +171,8 @@ TEST_F(ScriptedAnimationControllerTest, RegisterCallbackAndEnqueueTask) {
Event* event = Event::Create("test");
event->SetTarget(&GetDocument());
- Controller().RegisterCallback(new RunTaskCallback(observer.CreateTask(1)));
+ Controller().RegisterCallback(
+ MakeGarbageCollected<RunTaskCallback>(observer.CreateTask(1)));
Controller().EnqueueTask(observer.CreateTask(2));
EXPECT_EQ(0u, observer.Order().size());
@@ -186,14 +185,17 @@ TEST_F(ScriptedAnimationControllerTest, RegisterCallbackAndEnqueueTask) {
TEST_F(ScriptedAnimationControllerTest, TestHasCallback) {
TaskOrderObserver observer;
- Controller().RegisterCallback(new RunTaskCallback(observer.CreateTask(1)));
+ Controller().RegisterCallback(
+ MakeGarbageCollected<RunTaskCallback>(observer.CreateTask(1)));
EXPECT_TRUE(Controller().HasCallback());
Controller().CancelCallback(1);
EXPECT_FALSE(Controller().HasCallback());
- Controller().RegisterCallback(new RunTaskCallback(observer.CreateTask(1)));
- Controller().RegisterCallback(new RunTaskCallback(observer.CreateTask(2)));
+ Controller().RegisterCallback(
+ MakeGarbageCollected<RunTaskCallback>(observer.CreateTask(1)));
+ Controller().RegisterCallback(
+ MakeGarbageCollected<RunTaskCallback>(observer.CreateTask(2)));
EXPECT_TRUE(Controller().HasCallback());
Controller().CancelCallback(1);
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
index d9bb0cbdd94..5a9aac8382a 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
@@ -79,7 +79,7 @@ ScriptedIdleTaskController::V8IdleTask::V8IdleTask(
V8IdleRequestCallback* callback)
: callback_(callback) {}
-void ScriptedIdleTaskController::V8IdleTask::Trace(blink::Visitor* visitor) {
+void ScriptedIdleTaskController::V8IdleTask::Trace(Visitor* visitor) {
visitor->Trace(callback_);
ScriptedIdleTaskController::IdleTask::Trace(visitor);
}
@@ -99,7 +99,7 @@ ScriptedIdleTaskController::ScriptedIdleTaskController(
ScriptedIdleTaskController::~ScriptedIdleTaskController() = default;
-void ScriptedIdleTaskController::Trace(blink::Visitor* visitor) {
+void ScriptedIdleTaskController::Trace(Visitor* visitor) {
visitor->Trace(idle_tasks_);
PausableObject::Trace(visitor);
}
@@ -226,11 +226,11 @@ void ScriptedIdleTaskController::ContextDestroyed(ExecutionContext*) {
idle_tasks_.clear();
}
-void ScriptedIdleTaskController::Pause() {
+void ScriptedIdleTaskController::ContextPaused(PauseState) {
paused_ = true;
}
-void ScriptedIdleTaskController::Unpause() {
+void ScriptedIdleTaskController::ContextUnpaused() {
DCHECK(paused_);
paused_ = false;
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
index c734b7cef99..8d347bdd347 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_idle_request_callback.h"
#include "third_party/blink/renderer/core/dom/idle_deadline.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -37,7 +37,7 @@ class CORE_EXPORT ScriptedIdleTaskController
explicit ScriptedIdleTaskController(ExecutionContext*);
~ScriptedIdleTaskController() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
const char* NameInHeapSnapshot() const override {
return "ScriptedIdleTaskController";
}
@@ -49,7 +49,7 @@ class CORE_EXPORT ScriptedIdleTaskController
class IdleTask : public GarbageCollectedFinalized<IdleTask>,
public NameClient {
public:
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
const char* NameInHeapSnapshot() const override { return "IdleTask"; }
virtual ~IdleTask() = default;
virtual void invoke(IdleDeadline*) = 0;
@@ -67,7 +67,7 @@ class CORE_EXPORT ScriptedIdleTaskController
~V8IdleTask() override = default;
void invoke(IdleDeadline*) override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
TraceWrapperMember<V8IdleRequestCallback> callback_;
@@ -78,8 +78,8 @@ class CORE_EXPORT ScriptedIdleTaskController
// PausableObject interface.
void ContextDestroyed(ExecutionContext*) override;
- void Pause() override;
- void Unpause() override;
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
void CallbackFired(CallbackId,
TimeTicks deadline,
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
index b17a00e9b99..f910b5f1f8e 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
@@ -95,11 +95,10 @@ TEST_F(ScriptedIdleTaskControllerTest, RunCallback) {
MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield::DONT_YIELD);
ScopedSchedulerOverrider scheduler_overrider(&scheduler);
- NullExecutionContext execution_context;
ScriptedIdleTaskController* controller =
ScriptedIdleTaskController::Create(execution_context_);
- Persistent<MockIdleTask> idle_task(new MockIdleTask());
+ Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
IdleRequestOptions* options = IdleRequestOptions::Create();
EXPECT_FALSE(scheduler.HasIdleTask());
int id = controller->RegisterCallback(idle_task, options);
@@ -116,11 +115,10 @@ TEST_F(ScriptedIdleTaskControllerTest, DontRunCallbackWhenAskedToYield) {
MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield::YIELD);
ScopedSchedulerOverrider scheduler_overrider(&scheduler);
- NullExecutionContext execution_context;
ScriptedIdleTaskController* controller =
ScriptedIdleTaskController::Create(execution_context_);
- Persistent<MockIdleTask> idle_task(new MockIdleTask());
+ Persistent<MockIdleTask> idle_task(MakeGarbageCollected<MockIdleTask>());
IdleRequestOptions* options = IdleRequestOptions::Create();
int id = controller->RegisterCallback(idle_task, options);
EXPECT_NE(0, id);
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.cc b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.cc
index 0b3319f95b5..0cc70fbaecf 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.cc
@@ -11,44 +11,22 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_task_queue_post_callback.h"
#include "third_party/blink/renderer/core/dom/abort_signal.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
-namespace {
-
-class TaskQueuePostCallbackWrapper {
- public:
- static std::unique_ptr<TaskQueuePostCallbackWrapper> Create(
- int id,
- ScriptedTaskQueue* task_queue) {
- return std::unique_ptr<TaskQueuePostCallbackWrapper>(
- new TaskQueuePostCallbackWrapper(id, task_queue));
- }
-
- void TaskFired() {
- if (task_queue_)
- task_queue_->CallbackFired(id_);
- }
-
- private:
- TaskQueuePostCallbackWrapper(int id, ScriptedTaskQueue* task_queue)
- : id_(id), task_queue_(task_queue) {}
-
- int id_;
- WeakPersistent<ScriptedTaskQueue> task_queue_;
-};
-
-} // namespace
-
class ScriptedTaskQueue::WrappedCallback
- : public GarbageCollected<WrappedCallback> {
+ : public GarbageCollectedFinalized<WrappedCallback> {
WTF_MAKE_NONCOPYABLE(WrappedCallback);
public:
WrappedCallback(V8TaskQueuePostCallback* callback,
- ScriptPromiseResolver* resolver)
- : callback_(callback), resolver_(resolver) {}
+ ScriptPromiseResolver* resolver,
+ TaskHandle task_handle)
+ : callback_(callback),
+ resolver_(resolver),
+ task_handle_(std::move(task_handle)) {}
void Trace(Visitor* visitor) {
visitor->Trace(callback_);
@@ -65,19 +43,19 @@ class ScriptedTaskQueue::WrappedCallback
private:
TraceWrapperMember<V8TaskQueuePostCallback> callback_;
Member<ScriptPromiseResolver> resolver_;
+ TaskHandle task_handle_;
};
ScriptedTaskQueue::ScriptedTaskQueue(ExecutionContext* context,
TaskType task_type)
- : PausableObject(context) {
+ : ContextLifecycleObserver(context) {
task_runner_ = GetExecutionContext()->GetTaskRunner(task_type);
- PauseIfNeeded();
}
-void ScriptedTaskQueue::Trace(blink::Visitor* visitor) {
+void ScriptedTaskQueue::Trace(Visitor* visitor) {
visitor->Trace(pending_tasks_);
ScriptWrappable::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
ScriptPromise ScriptedTaskQueue::postTask(ScriptState* script_state,
@@ -97,22 +75,17 @@ ScriptPromise ScriptedTaskQueue::postTask(ScriptState* script_state,
WTF::Bind(&ScriptedTaskQueue::AbortTask, WrapPersistent(this), id));
}
- pending_tasks_.Set(id, new WrappedCallback(callback, resolver));
+ TaskHandle task_handle = PostCancellableTask(
+ *task_runner_, FROM_HERE,
+ WTF::Bind(&ScriptedTaskQueue::CallbackFired, WrapPersistent(this), id));
- auto callback_wrapper = TaskQueuePostCallbackWrapper::Create(id, this);
- task_runner_->PostTask(FROM_HERE,
- WTF::Bind(&TaskQueuePostCallbackWrapper::TaskFired,
- std::move(callback_wrapper)));
+ pending_tasks_.Set(id, MakeGarbageCollected<WrappedCallback>(
+ callback, resolver, std::move(task_handle)));
return resolver->Promise();
}
void ScriptedTaskQueue::CallbackFired(CallbackId id) {
- if (paused_) {
- paused_tasks_.push_back(id);
- return;
- }
-
auto task_iter = pending_tasks_.find(id);
if (task_iter == pending_tasks_.end())
return;
@@ -134,24 +107,6 @@ void ScriptedTaskQueue::AbortTask(CallbackId id) {
void ScriptedTaskQueue::ContextDestroyed(ExecutionContext*) {
pending_tasks_.clear();
- paused_tasks_.clear();
-}
-
-void ScriptedTaskQueue::Pause() {
- paused_ = true;
-}
-
-void ScriptedTaskQueue::Unpause() {
- paused_ = false;
-
- for (auto& task_id : paused_tasks_) {
- auto callback_wrapper = TaskQueuePostCallbackWrapper::Create(task_id, this);
- task_runner_->PostTask(FROM_HERE,
- WTF::Bind(&TaskQueuePostCallbackWrapper::TaskFired,
- std::move(callback_wrapper)));
- }
-
- paused_tasks_.clear();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.h b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.h
index d5b3bdba441..03d7f1a4d68 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.h
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_SCRIPTED_TASK_QUEUE_H_
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -18,16 +18,18 @@ class V8TaskQueuePostCallback;
// This class corresponds to the ScriptedTaskQueue interface.
class CORE_EXPORT ScriptedTaskQueue final : public ScriptWrappable,
- public PausableObject {
+ public ContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(ScriptedTaskQueue);
public:
static ScriptedTaskQueue* Create(ExecutionContext* context,
TaskType task_type) {
- return new ScriptedTaskQueue(context, task_type);
+ return MakeGarbageCollected<ScriptedTaskQueue>(context, task_type);
}
+ explicit ScriptedTaskQueue(ExecutionContext*, TaskType);
+
using CallbackId = int;
ScriptPromise postTask(ScriptState*,
@@ -36,23 +38,17 @@ class CORE_EXPORT ScriptedTaskQueue final : public ScriptWrappable,
void CallbackFired(CallbackId id);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- explicit ScriptedTaskQueue(ExecutionContext*, TaskType);
-
- // PausableObject interface.
+ // ContextLifecycleObserver interface.
void ContextDestroyed(ExecutionContext*) override;
- void Pause() override;
- void Unpause() override;
void AbortTask(CallbackId id);
class WrappedCallback;
HeapHashMap<CallbackId, TraceWrapperMember<WrappedCallback>> pending_tasks_;
- Vector<CallbackId> paused_tasks_;
CallbackId next_callback_id_ = 1;
- bool paused_ = false;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc
index b25ead2315f..fa6c7adc8e3 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc
@@ -19,7 +19,8 @@ ScriptedTaskQueueController* ScriptedTaskQueueController::From(
ScriptedTaskQueueController* task_queue_controller =
Supplement<Document>::From<ScriptedTaskQueueController>(document);
if (!task_queue_controller) {
- task_queue_controller = new ScriptedTaskQueueController(&document);
+ task_queue_controller =
+ MakeGarbageCollected<ScriptedTaskQueueController>(&document);
Supplement<Document>::ProvideTo(document, task_queue_controller);
}
return task_queue_controller;
@@ -29,7 +30,7 @@ ScriptedTaskQueueController::ScriptedTaskQueueController(
ExecutionContext* context)
: ContextLifecycleObserver(context) {}
-void ScriptedTaskQueueController::Trace(blink::Visitor* visitor) {
+void ScriptedTaskQueueController::Trace(Visitor* visitor) {
visitor->Trace(task_queues_);
Supplement<Document>::Trace(visitor);
ScriptWrappable::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h
index 8e690c0660f..9f5084c97bf 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h
@@ -34,11 +34,11 @@ class CORE_EXPORT ScriptedTaskQueueController final
ScriptedTaskQueue* defaultQueue(const String&);
- void Trace(blink::Visitor*) override;
-
- private:
explicit ScriptedTaskQueueController(ExecutionContext*);
+ void Trace(Visitor*) override;
+
+ private:
HeapHashMap<String, TraceWrapperMember<ScriptedTaskQueue>> task_queues_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root.cc b/chromium/third_party/blink/renderer/core/dom/shadow_root.cc
index 04bd6ddae57..39d2eed15fc 100644
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root.cc
+++ b/chromium/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -56,7 +56,6 @@ void ShadowRoot::Distribute() {
}
struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope {
- char empty_class_fields_due_to_gc_mixin_marker[1];
Member<void*> member[3];
unsigned counters_and_flags[1];
};
@@ -253,7 +252,7 @@ void ShadowRoot::SetNeedsDistributionRecalc() {
V0().ClearDistribution();
}
-void ShadowRoot::Trace(blink::Visitor* visitor) {
+void ShadowRoot::Trace(Visitor* visitor) {
visitor->Trace(style_sheet_list_);
visitor->Trace(slot_assignment_);
visitor->Trace(shadow_root_v0_);
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root.h b/chromium/third_party/blink/renderer/core/dom/shadow_root.h
index 2f981ad6eaa..632cc0effd0 100644
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root.h
+++ b/chromium/third_party/blink/renderer/core/dom/shadow_root.h
@@ -171,7 +171,7 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
style_sheet_list_ = style_sheet_list;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
~ShadowRoot() override;
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h b/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h
index d836af74400..c95f0d89117 100644
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h
+++ b/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h
@@ -80,7 +80,7 @@ class CORE_EXPORT ShadowRootV0 final
void SetNeedsSelectFeatureSet() { needs_select_feature_set_ = true; }
SelectRuleFeatureSet& SelectFeatures() { return select_features_; }
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(shadow_root_);
visitor->Trace(descendant_insertion_points_);
visitor->Trace(node_to_insertion_points_);
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc b/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc
index bd70c6e1626..50900696933 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/dom/slot_assignment.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -14,6 +15,7 @@
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/html_details_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
+#include "third_party/blink/renderer/core/html/parser/nesting_level_incrementer.h"
namespace blink {
@@ -151,6 +153,12 @@ void SlotAssignment::DidRemoveSlotInternal(
if (FindHostChildBySlotName(slot_name)) {
// |slot| lost assigned nodes
if (slot_mutation_type == SlotMutationType::kRemoved) {
+ if (RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled()) {
+ // |slot|'s previously assigned nodes' flat tree node data became
+ // dirty. Call SetNeedsAssignmentRecalc() to clear their flat tree
+ // node data surely in recalc timing.
+ SetNeedsAssignmentRecalc();
+ }
slot.DidSlotChangeAfterRemovedFromShadowTree();
} else {
slot.DidSlotChangeAfterRenaming();
@@ -224,12 +232,18 @@ void SlotAssignment::SetNeedsAssignmentRecalc() {
void SlotAssignment::RecalcAssignment() {
if (!needs_assignment_recalc_)
return;
+ NestingLevelIncrementer slot_assignment_recalc_depth(
+ owner_->GetDocument().SlotAssignmentRecalcDepth());
+
#if DCHECK_IS_ON()
DCHECK(!owner_->GetDocument().IsSlotAssignmentRecalcForbidden());
#endif
// To detect recursive RecalcAssignment, which shouldn't happen.
SlotAssignmentRecalcForbiddenScope forbid_slot_recalc(owner_->GetDocument());
+ FlatTreeTraversalForbiddenScope forbid_flat_tree_traversal(
+ owner_->GetDocument());
+
needs_assignment_recalc_ = false;
for (Member<HTMLSlotElement> slot : Slots())
@@ -273,7 +287,8 @@ void SlotAssignment::RecalcAssignment() {
if (slot) {
slot->AppendAssignedNode(child);
} else {
- child.ClearFlatTreeNodeData();
+ if (RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled())
+ child.ClearFlatTreeNodeData();
child.LazyReattachIfAttached();
}
}
@@ -350,7 +365,7 @@ HTMLSlotElement* SlotAssignment::GetCachedFirstSlotWithoutAccessingNodeTree(
return nullptr;
}
-void SlotAssignment::Trace(blink::Visitor* visitor) {
+void SlotAssignment::Trace(Visitor* visitor) {
visitor->Trace(slots_);
visitor->Trace(slot_map_);
visitor->Trace(owner_);
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment.h b/chromium/third_party/blink/renderer/core/dom/slot_assignment.h
index 36230f6404e..c2647ea5267 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment.h
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment.h
@@ -55,7 +55,7 @@ class SlotAssignment final : public GarbageCollected<SlotAssignment> {
HTMLSlotElement* FindSlotChange(HTMLSlotElement& slot, Node& child);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
bool NeedsAssignmentRecalc() const { return needs_assignment_recalc_; }
void SetNeedsAssignmentRecalc();
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.cc b/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.cc
index c4bb49abb68..d3eb72116d4 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.cc
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.cc
@@ -51,7 +51,7 @@ void SlotAssignmentEngine::RecalcSlotAssignments() {
DCHECK(shadow_roots_needing_recalc_.IsEmpty());
}
-void SlotAssignmentEngine::Trace(blink::Visitor* visitor) {
+void SlotAssignmentEngine::Trace(Visitor* visitor) {
visitor->Trace(shadow_roots_needing_recalc_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.h b/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.h
index ae8a0f6a20d..c1fb4498de2 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.h
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment_engine.h
@@ -32,7 +32,7 @@ class SlotAssignmentEngine final
void RecalcSlotAssignments();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
HeapHashSet<WeakMember<ShadowRoot>> shadow_roots_needing_recalc_;
diff --git a/chromium/third_party/blink/renderer/core/dom/space_split_string.cc b/chromium/third_party/blink/renderer/core/dom/space_split_string.cc
index cfe0bdbcc32..3d5c2fb6239 100644
--- a/chromium/third_party/blink/renderer/core/dom/space_split_string.cc
+++ b/chromium/third_party/blink/renderer/core/dom/space_split_string.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
+#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
namespace blink {
@@ -168,8 +169,8 @@ AtomicString SpaceSplitString::SerializeToString() const {
}
SpaceSplitString::DataMap& SpaceSplitString::SharedDataMap() {
- DEFINE_STATIC_LOCAL(DataMap, map, ());
- return map;
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<DataMap>, map, ());
+ return *map;
}
void SpaceSplitString::Set(const AtomicString& input_string) {
diff --git a/chromium/third_party/blink/renderer/core/dom/static_node_list.h b/chromium/third_party/blink/renderer/core/dom/static_node_list.h
index 9e911b1e163..115f52ab0ec 100644
--- a/chromium/third_party/blink/renderer/core/dom/static_node_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/static_node_list.h
@@ -53,7 +53,7 @@ class StaticNodeTypeList final : public NodeList {
unsigned length() const override;
NodeType* item(unsigned index) const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
HeapVector<TraceWrapperMember<NodeType>> nodes_;
@@ -64,7 +64,8 @@ using StaticNodeList = StaticNodeTypeList<Node>;
template <typename NodeType>
StaticNodeTypeList<NodeType>* StaticNodeTypeList<NodeType>::Adopt(
HeapVector<Member<NodeType>>& nodes) {
- StaticNodeTypeList<NodeType>* node_list = new StaticNodeTypeList<NodeType>;
+ StaticNodeTypeList<NodeType>* node_list =
+ MakeGarbageCollected<StaticNodeTypeList<NodeType>>();
swap(node_list->nodes_, nodes);
return node_list;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/static_range.cc b/chromium/third_party/blink/renderer/core/dom/static_range.cc
index c5d3f6cb54e..0015892f1bf 100644
--- a/chromium/third_party/blink/renderer/core/dom/static_range.cc
+++ b/chromium/third_party/blink/renderer/core/dom/static_range.cc
@@ -58,7 +58,7 @@ Range* StaticRange::toRange(ExceptionState& exception_state) const {
return range;
}
-void StaticRange::Trace(blink::Visitor* visitor) {
+void StaticRange::Trace(Visitor* visitor) {
visitor->Trace(owner_document_);
visitor->Trace(start_container_);
visitor->Trace(end_container_);
diff --git a/chromium/third_party/blink/renderer/core/dom/static_range.h b/chromium/third_party/blink/renderer/core/dom/static_range.h
index 8989453af29..09b83bdb361 100644
--- a/chromium/third_party/blink/renderer/core/dom/static_range.h
+++ b/chromium/third_party/blink/renderer/core/dom/static_range.h
@@ -68,7 +68,7 @@ class CORE_EXPORT StaticRange final : public ScriptWrappable {
Range* toRange(ExceptionState& = ASSERT_NO_EXCEPTION) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<Document> owner_document_; // Required by |toRange()|.
diff --git a/chromium/third_party/blink/renderer/core/dom/template_content_document_fragment.h b/chromium/third_party/blink/renderer/core/dom/template_content_document_fragment.h
index a68faf52563..5a1c6462676 100644
--- a/chromium/third_party/blink/renderer/core/dom/template_content_document_fragment.h
+++ b/chromium/third_party/blink/renderer/core/dom/template_content_document_fragment.h
@@ -44,7 +44,7 @@ class TemplateContentDocumentFragment final : public DocumentFragment {
Element* Host() const { return host_; }
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(host_);
DocumentFragment::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/text.cc b/chromium/third_party/blink/renderer/core/dom/text.cc
index 6a91669ed26..7ee5d04f48a 100644
--- a/chromium/third_party/blink/renderer/core/dom/text.cc
+++ b/chromium/third_party/blink/renderer/core/dom/text.cc
@@ -258,8 +258,9 @@ static inline bool CanHaveWhitespaceChildren(
if (parent.IsTable() || parent.IsTableRow() || parent.IsTableSection() ||
parent.IsLayoutTableCol() || parent.IsFrameSet() ||
- parent.IsFlexibleBox() || parent.IsLayoutGrid() || parent.IsSVGRoot() ||
- parent.IsSVGContainer() || parent.IsSVGImage() || parent.IsSVGShape()) {
+ parent.IsFlexibleBoxIncludingNG() || parent.IsLayoutGrid() ||
+ parent.IsSVGRoot() || parent.IsSVGContainer() || parent.IsSVGImage() ||
+ parent.IsSVGShape()) {
if (!context.use_previous_in_flow || !context.previous_in_flow ||
!context.previous_in_flow->IsText())
return false;
@@ -392,8 +393,8 @@ void Text::RecalcTextStyle(StyleRecalcChange change) {
GetDocument().EnsureStyleResolver().StyleForText(this);
const ComputedStyle* layout_parent_style =
GetLayoutObject()->Parent()->Style();
- if (new_style != layout_parent_style &&
- !new_style->InheritedEqual(*layout_parent_style)) {
+ if (!new_style || (new_style != layout_parent_style &&
+ !new_style->InheritedEqual(*layout_parent_style))) {
// The computed style or the need for an anonymous inline wrapper for a
// display:contents text child changed.
SetNeedsReattachLayoutTree();
@@ -471,7 +472,7 @@ Text* Text::CloneWithData(Document& factory, const String& data) const {
return Create(factory, data);
}
-void Text::Trace(blink::Visitor* visitor) {
+void Text::Trace(Visitor* visitor) {
CharacterData::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/text.h b/chromium/third_party/blink/renderer/core/dom/text.h
index e44317ab67a..5a5b7ba666b 100644
--- a/chromium/third_party/blink/renderer/core/dom/text.h
+++ b/chromium/third_party/blink/renderer/core/dom/text.h
@@ -72,7 +72,7 @@ class CORE_EXPORT Text : public CharacterData {
bool CanContainRangeEndPoint() const final { return true; }
NodeType getNodeType() const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
String nodeName() const override;
diff --git a/chromium/third_party/blink/renderer/core/dom/text.idl b/chromium/third_party/blink/renderer/core/dom/text.idl
index 36f98f54d0a..7c814dac21b 100644
--- a/chromium/third_party/blink/renderer/core/dom/text.idl
+++ b/chromium/third_party/blink/renderer/core/dom/text.idl
@@ -31,5 +31,5 @@
[ImplementedAs=assignedSlotForBinding] readonly attribute HTMLSlotElement? assignedSlot;
// Non-standard API:
- [RuntimeEnabled=ShadowDOMV0] NodeList getDestinationInsertionPoints();
+ [OriginTrialEnabled=ShadowDOMV0] NodeList getDestinationInsertionPoints();
};
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.cc b/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.cc
index 9d7157e024d..652c9c7183d 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.cc
@@ -63,7 +63,7 @@ void TreeOrderedList::Remove(const Node* node) {
nodes_.erase(const_cast<Node*>(node));
}
-void TreeOrderedList::Trace(blink::Visitor* visitor) {
+void TreeOrderedList::Trace(Visitor* visitor) {
visitor->Trace(nodes_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.h b/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.h
index 19fb759b5de..0cf13075075 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_list.h
@@ -63,7 +63,7 @@ class TreeOrderedList final {
const_reverse_iterator rbegin() const { return nodes_.rbegin(); }
const_reverse_iterator rend() const { return nodes_.rend(); }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
HeapListHashSet<Member<Node>, 32> nodes_;
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc
index 4d70591c129..c81c81c1a19 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc
@@ -205,11 +205,11 @@ Element* TreeOrderedMap::GetCachedFirstElementWithoutAccessingNodeTree(
return entry->element;
}
-void TreeOrderedMap::Trace(blink::Visitor* visitor) {
+void TreeOrderedMap::Trace(Visitor* visitor) {
visitor->Trace(map_);
}
-void TreeOrderedMap::MapEntry::Trace(blink::Visitor* visitor) {
+void TreeOrderedMap::MapEntry::Trace(Visitor* visitor) {
visitor->Trace(element);
visitor->Trace(ordered_list);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h
index 5ca8d4fbbe9..5eecc62287b 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h
@@ -67,7 +67,7 @@ class TreeOrderedMap : public GarbageCollected<TreeOrderedMap> {
// TreeOrderedMap exactly.
Element* GetCachedFirstElementWithoutAccessingNodeTree(const AtomicString&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
#if DCHECK_IS_ON()
// While removing a ContainerNode, ID lookups won't be precise should the tree
@@ -101,7 +101,7 @@ class TreeOrderedMap : public GarbageCollected<TreeOrderedMap> {
explicit MapEntry(Element& first_element)
: element(first_element), count(1) {}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
Member<Element> element;
unsigned count;
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope.cc b/chromium/third_party/blink/renderer/core/dom/tree_scope.cc
index 1c645585bff..1f5d8b6a449 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope.cc
@@ -339,44 +339,36 @@ SVGTreeScopeResources& TreeScope::EnsureSVGTreeScopedResources() {
}
bool TreeScope::HasAdoptedStyleSheets() const {
- return adopted_style_sheets_ && adopted_style_sheets_->length() > 0;
+ return adopted_style_sheets_.size() > 0;
}
-StyleSheetList& TreeScope::AdoptedStyleSheets() {
- if (!adopted_style_sheets_)
- SetAdoptedStyleSheets(StyleSheetList::Create());
- return *adopted_style_sheets_;
+const HeapVector<Member<CSSStyleSheet>>& TreeScope::AdoptedStyleSheets() {
+ return adopted_style_sheets_;
}
-void TreeScope::SetAdoptedStyleSheets(StyleSheetList* adopted_style_sheets,
- ExceptionState& exception_state) {
- unsigned style_sheets_count =
- adopted_style_sheets ? adopted_style_sheets->length() : 0;
- for (unsigned i = 0; i < style_sheets_count; ++i) {
- CSSStyleSheet* style_sheet = ToCSSStyleSheet(adopted_style_sheets->item(i));
- Document* associated_document = style_sheet->AssociatedDocument();
- Node* owner_node = style_sheet->ownerNode();
+void TreeScope::SetAdoptedStyleSheets(
+ HeapVector<Member<CSSStyleSheet>>& adopted_style_sheets,
+ ExceptionState& exception_state) {
+ for (CSSStyleSheet* sheet : adopted_style_sheets) {
+ if (!sheet->IsConstructed()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Can't adopt non-constructed stylesheets.");
+ return;
+ }
+ Document* associated_document = sheet->AssociatedDocument();
if (associated_document && *associated_document != GetDocument()) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
- "Sharing constructable stylesheets in "
+ "Sharing constructed stylesheets in "
"multiple documents is not allowed");
return;
}
- if (owner_node && owner_node->GetDocument() != GetDocument()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotAllowedError,
- "When the style sheet's owner node and the AdoptedStyleSheets' tree "
- "scope is not in the same Document tree, adding non-constructed "
- "stylesheets to AdoptedStyleSheets is not allowed");
- return;
- }
- // TODO(momon): Don't allow using non-constructed stylesheets, pending
- // resolution of https://github.com/WICG/construct-stylesheets/issues/34
}
SetAdoptedStyleSheets(adopted_style_sheets);
}
-void TreeScope::SetAdoptedStyleSheets(StyleSheetList* adopted_style_sheets) {
+void TreeScope::SetAdoptedStyleSheets(
+ HeapVector<Member<CSSStyleSheet>>& adopted_style_sheets) {
GetDocument().GetStyleEngine().AdoptedStyleSheetsWillChange(
*this, adopted_style_sheets_, adopted_style_sheets);
adopted_style_sheets_ = adopted_style_sheets;
@@ -627,7 +619,7 @@ void TreeScope::SetNeedsStyleRecalcForViewportUnits() {
}
}
-void TreeScope::Trace(blink::Visitor* visitor) {
+void TreeScope::Trace(Visitor* visitor) {
visitor->Trace(root_node_);
visitor->Trace(document_);
visitor->Trace(parent_tree_scope_);
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope.h b/chromium/third_party/blink/renderer/core/dom/tree_scope.h
index 36687327f26..d2adf8fd9d8 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope.h
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope.h
@@ -38,6 +38,7 @@
namespace blink {
class ContainerNode;
+class CSSStyleSheet;
class DOMSelection;
class Document;
class Element;
@@ -46,7 +47,6 @@ class HitTestResult;
class IdTargetObserverRegistry;
class SVGTreeScopeResources;
class ScopedStyleResolver;
-class StyleSheetList;
// The root node of a document tree (in which case this is a Document) or of a
// shadow tree (in which case this is a ShadowRoot). Various things, like
@@ -131,7 +131,7 @@ class CORE_EXPORT TreeScope : public GarbageCollectedMixin {
Element* GetElementByAccessKey(const String& key) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
ScopedStyleResolver* GetScopedStyleResolver() const {
return scoped_style_resolver_.Get();
@@ -142,9 +142,10 @@ class CORE_EXPORT TreeScope : public GarbageCollectedMixin {
SVGTreeScopeResources& EnsureSVGTreeScopedResources();
bool HasAdoptedStyleSheets() const;
- StyleSheetList& AdoptedStyleSheets();
- void SetAdoptedStyleSheets(StyleSheetList*);
- void SetAdoptedStyleSheets(StyleSheetList*, ExceptionState&);
+ const HeapVector<Member<CSSStyleSheet>>& AdoptedStyleSheets();
+ void SetAdoptedStyleSheets(HeapVector<Member<CSSStyleSheet>>&);
+ void SetAdoptedStyleSheets(HeapVector<Member<CSSStyleSheet>>&,
+ ExceptionState&);
protected:
TreeScope(ContainerNode&, Document&);
@@ -176,7 +177,7 @@ class CORE_EXPORT TreeScope : public GarbageCollectedMixin {
Member<SVGTreeScopeResources> svg_tree_scoped_resources_;
- Member<StyleSheetList> adopted_style_sheets_;
+ HeapVector<Member<CSSStyleSheet>> adopted_style_sheets_;
};
inline bool TreeScope::HasElementWithId(const AtomicString& id) const {
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc b/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
index 5fd92dc65ff..7b27e500da0 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
@@ -93,6 +93,9 @@ void TreeScopeAdopter::MoveShadowTreeToNewDocument(
Document& old_document,
Document& new_document) const {
DCHECK_NE(old_document, new_document);
+ HeapVector<Member<CSSStyleSheet>> empty_vector;
+ shadow_root.SetAdoptedStyleSheets(empty_vector);
+
if (shadow_root.GetType() == ShadowRootType::V0) {
new_document.SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV0);
} else if (shadow_root.IsV1() && !shadow_root.IsUserAgent()) {
@@ -161,9 +164,8 @@ inline void TreeScopeAdopter::MoveNodeToNewDocument(
old_document.MoveNodeIteratorsToNewDocument(node, new_document);
if (node.GetCustomElementState() == CustomElementState::kCustom) {
- Element& element = ToElement(node);
- CustomElement::EnqueueAdoptedCallback(&element, &old_document,
- &new_document);
+ CustomElement::EnqueueAdoptedCallback(ToElement(node), old_document,
+ new_document);
}
if (node.IsShadowRoot())
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_walker.cc b/chromium/third_party/blink/renderer/core/dom/tree_walker.cc
index 19491db3a8a..605d031aca9 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_walker.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_walker.cc
@@ -248,7 +248,7 @@ Children:
return nullptr;
}
-void TreeWalker::Trace(blink::Visitor* visitor) {
+void TreeWalker::Trace(Visitor* visitor) {
visitor->Trace(current_);
ScriptWrappable::Trace(visitor);
NodeIteratorBase::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_walker.h b/chromium/third_party/blink/renderer/core/dom/tree_walker.h
index 43f338bde1d..875c7eccc9b 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_walker.h
+++ b/chromium/third_party/blink/renderer/core/dom/tree_walker.h
@@ -57,7 +57,7 @@ class TreeWalker final : public ScriptWrappable, public NodeIteratorBase {
Node* previousNode(ExceptionState&);
Node* nextNode(ExceptionState&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Node* SetCurrent(Node*);
diff --git a/chromium/third_party/blink/renderer/core/dom/user_action_element_set.cc b/chromium/third_party/blink/renderer/core/dom/user_action_element_set.cc
index 409ab5ae154..eabc3e8a053 100644
--- a/chromium/third_party/blink/renderer/core/dom/user_action_element_set.cc
+++ b/chromium/third_party/blink/renderer/core/dom/user_action_element_set.cc
@@ -102,7 +102,7 @@ inline void UserActionElementSet::SetFlags(Element* element, unsigned flags) {
elements_.insert(element, flags);
}
-void UserActionElementSet::Trace(blink::Visitor* visitor) {
+void UserActionElementSet::Trace(Visitor* visitor) {
visitor->Trace(elements_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/user_action_element_set.h b/chromium/third_party/blink/renderer/core/dom/user_action_element_set.h
index 9287449d807..408825e8507 100644
--- a/chromium/third_party/blink/renderer/core/dom/user_action_element_set.h
+++ b/chromium/third_party/blink/renderer/core/dom/user_action_element_set.h
@@ -73,7 +73,7 @@ class UserActionElementSet final {
void DidDetach(Element&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
enum ElementFlags {
diff --git a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc b/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc
index 930d432559c..d0779c26b5e 100644
--- a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc
+++ b/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc
@@ -262,7 +262,7 @@ void V0InsertionPoint::RemovedFrom(ContainerNode& insertion_point) {
HTMLElement::RemovedFrom(insertion_point);
}
-void V0InsertionPoint::Trace(blink::Visitor* visitor) {
+void V0InsertionPoint::Trace(Visitor* visitor) {
visitor->Trace(distributed_nodes_);
HTMLElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h b/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h
index e50c8f4faff..ad84b8ecc3e 100644
--- a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h
+++ b/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h
@@ -75,7 +75,7 @@ class CORE_EXPORT V0InsertionPoint : public HTMLElement {
return distributed_nodes_.PreviousTo(node);
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
V0InsertionPoint(const QualifiedName&, Document&);
diff --git a/chromium/third_party/blink/renderer/core/dom/visited_link_state.cc b/chromium/third_party/blink/renderer/core/dom/visited_link_state.cc
index 9541ae52fa7..211ab8a7e7b 100644
--- a/chromium/third_party/blink/renderer/core/dom/visited_link_state.cc
+++ b/chromium/third_party/blink/renderer/core/dom/visited_link_state.cc
@@ -135,7 +135,7 @@ EInsideLink VisitedLinkState::DetermineLinkStateSlowCase(
return EInsideLink::kInsideUnvisitedLink;
}
-void VisitedLinkState::Trace(blink::Visitor* visitor) {
+void VisitedLinkState::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/visited_link_state.h b/chromium/third_party/blink/renderer/core/dom/visited_link_state.h
index 7b663e99667..9df9e21c81d 100644
--- a/chromium/third_party/blink/renderer/core/dom/visited_link_state.h
+++ b/chromium/third_party/blink/renderer/core/dom/visited_link_state.h
@@ -57,7 +57,7 @@ class VisitedLinkState : public GarbageCollectedFinalized<VisitedLinkState> {
return EInsideLink::kNotInsideLink;
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
const Document& GetDocument() const { return *document_; }
diff --git a/chromium/third_party/blink/renderer/core/dom/weak_identifier_map.h b/chromium/third_party/blink/renderer/core/dom/weak_identifier_map.h
index 07b2d9a8ec1..eed341b57d8 100644
--- a/chromium/third_party/blink/renderer/core/dom/weak_identifier_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/weak_identifier_map.h
@@ -30,7 +30,7 @@ template <typename T, typename IdentifierType>
class WeakIdentifierMapBase<T, IdentifierType, true>
: public GarbageCollected<WeakIdentifierMapBase<T, IdentifierType, true>> {
public:
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(object_to_identifier_);
visitor->Trace(identifier_to_object_);
}
@@ -59,6 +59,8 @@ class WeakIdentifierMap final
return result;
}
+ WeakIdentifierMap() = default;
+
static T* Lookup(IdentifierType identifier) {
return Instance().identifier_to_object_.at(identifier);
}
@@ -70,8 +72,6 @@ class WeakIdentifierMap final
private:
static WeakIdentifierMap<T, IdentifierType>& Instance();
- WeakIdentifierMap() = default;
-
static IdentifierType Next() {
static IdentifierType last_id = 0;
return ++last_id;
@@ -96,15 +96,16 @@ class WeakIdentifierMap final
WeakIdentifierMap<T, ##__VA_ARGS__>::Instance(); \
extern template class WeakIdentifierMap<T, ##__VA_ARGS__>;
-#define DEFINE_WEAK_IDENTIFIER_MAP(T, ...) \
- template class WeakIdentifierMap<T, ##__VA_ARGS__>; \
- template <> \
- WeakIdentifierMap<T, ##__VA_ARGS__>& \
- WeakIdentifierMap<T, ##__VA_ARGS__>::Instance() { \
- using RefType = WeakIdentifierMap<T, ##__VA_ARGS__>; \
- DEFINE_STATIC_LOCAL(Persistent<RefType>, map_instance, \
- (new WeakIdentifierMap<T, ##__VA_ARGS__>())); \
- return *map_instance; \
+#define DEFINE_WEAK_IDENTIFIER_MAP(T, ...) \
+ template class WeakIdentifierMap<T, ##__VA_ARGS__>; \
+ template <> \
+ WeakIdentifierMap<T, ##__VA_ARGS__>& \
+ WeakIdentifierMap<T, ##__VA_ARGS__>::Instance() { \
+ using RefType = WeakIdentifierMap<T, ##__VA_ARGS__>; \
+ DEFINE_STATIC_LOCAL( \
+ Persistent<RefType>, map_instance, \
+ (MakeGarbageCollected<WeakIdentifierMap<T, ##__VA_ARGS__>>())); \
+ return *map_instance; \
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/BUILD.gn b/chromium/third_party/blink/renderer/core/editing/BUILD.gn
index 878a31410c7..faa763c30ae 100644
--- a/chromium/third_party/blink/renderer/core/editing/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/editing/BUILD.gn
@@ -130,6 +130,8 @@ blink_core_sources("editing") {
"element_inner_text.cc",
"ephemeral_range.cc",
"ephemeral_range.h",
+ "finder/find_buffer.cc",
+ "finder/find_buffer.h",
"finder/find_in_page_coordinates.cc",
"finder/find_in_page_coordinates.h",
"finder/find_task_controller.cc",
@@ -361,6 +363,7 @@ jumbo_source_set("unit_tests") {
"editor_test.cc",
"element_inner_text_test.cc",
"ephemeral_range_test.cc",
+ "finder/find_buffer_test.cc",
"frame_caret_test.cc",
"frame_selection_test.cc",
"granularity_strategy_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc
index dfa851f01ad..eb0d5c208f5 100644
--- a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc
+++ b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc
@@ -100,7 +100,8 @@ LayoutRect CaretDisplayItemClient::ComputeCaretRect(
if (caret_position.IsNull())
return LayoutRect();
- DCHECK(caret_position.AnchorNode()->GetLayoutObject());
+ if (!caret_position.AnchorNode()->GetLayoutObject())
+ return LayoutRect();
// First compute a rect local to the layoutObject at the selection start.
const LocalCaretRect& caret_rect = LocalCaretRectOfPosition(caret_position);
diff --git a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client_test.cc b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client_test.cc
index 016d26c9732..9db9334e0eb 100644
--- a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client_test.cc
@@ -359,8 +359,8 @@ TEST_P(CaretDisplayItemClientTest, CompositingChange) {
container->setAttribute(html_names::kStyleAttr, "will-change: transform");
UpdateAllLifecyclePhasesForCaretTest();
// TODO(wangxianzhu): Why will-change:transform doens't trigger compositing
- // in SPv2?
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // in CAP?
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(LayoutRect(50, 50, 1, 1),
GetCaretDisplayItemClient().VisualRect());
}
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/append_node_command.h b/chromium/third_party/blink/renderer/core/editing/commands/append_node_command.h
index fc15800215a..3887fac3c45 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/append_node_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/append_node_command.h
@@ -33,14 +33,14 @@ namespace blink {
class AppendNodeCommand final : public SimpleEditCommand {
public:
static AppendNodeCommand* Create(ContainerNode* parent, Node* node) {
- return new AppendNodeCommand(parent, node);
+ return MakeGarbageCollected<AppendNodeCommand>(parent, node);
}
+ AppendNodeCommand(ContainerNode* parent, Node*);
+
void Trace(blink::Visitor*) override;
private:
- AppendNodeCommand(ContainerNode* parent, Node*);
-
void DoApply(EditingState*) override;
void DoUnapply() override;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
index e31fc21483e..7e43b6f61b0 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
@@ -902,7 +902,7 @@ void ApplyStyleCommand::FixRangeAndApplyInlineStyle(
Element* editable_root = RootEditableElement(*start_node);
if (start_node != editable_root) {
// TODO(editing-dev): Investigate why |start| can be after |end| here in
- // some cases. For example, in LayoutTest
+ // some cases. For example, in web test
// editing/style/make-text-writing-direction-inline-{mac,win}.html
// blink::Range object will collapse to end in this case but EphemeralRange
// will trigger DCHECK, so we have to explicitly handle this.
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.h b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.h
index 0e2c87f6e35..da3965528ff 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.h
@@ -50,29 +50,27 @@ class CORE_EXPORT ApplyStyleCommand final : public CompositeEditCommand {
const EditingStyle* style,
InputEvent::InputType input_type,
EPropertyLevel level = kPropertyDefault) {
- return new ApplyStyleCommand(document, style, input_type, level);
+ return MakeGarbageCollected<ApplyStyleCommand>(document, style, input_type,
+ level);
}
static ApplyStyleCommand* Create(Document& document,
const EditingStyle* style,
const Position& start,
const Position& end) {
- return new ApplyStyleCommand(document, style, start, end);
+ return MakeGarbageCollected<ApplyStyleCommand>(document, style, start, end);
}
static ApplyStyleCommand* Create(Element* element, bool remove_only) {
- return new ApplyStyleCommand(element, remove_only);
+ return MakeGarbageCollected<ApplyStyleCommand>(element, remove_only);
}
static ApplyStyleCommand* Create(
Document& document,
const EditingStyle* style,
IsInlineElementToRemoveFunction is_inline_element_to_remove_function,
InputEvent::InputType input_type) {
- return new ApplyStyleCommand(
+ return MakeGarbageCollected<ApplyStyleCommand>(
document, style, is_inline_element_to_remove_function, input_type);
}
- void Trace(blink::Visitor*) override;
-
- private:
ApplyStyleCommand(Document&,
const EditingStyle*,
InputEvent::InputType,
@@ -87,6 +85,9 @@ class CORE_EXPORT ApplyStyleCommand final : public CompositeEditCommand {
bool (*is_inline_element_to_remove)(const Element*),
InputEvent::InputType);
+ void Trace(blink::Visitor*) override;
+
+ private:
void DoApply(EditingState*) override;
InputEvent::InputType GetInputType() const override;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/break_blockquote_command.h b/chromium/third_party/blink/renderer/core/editing/commands/break_blockquote_command.h
index 583676737b7..eff91d54cbd 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/break_blockquote_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/break_blockquote_command.h
@@ -33,11 +33,12 @@ namespace blink {
class BreakBlockquoteCommand final : public CompositeEditCommand {
public:
static BreakBlockquoteCommand* Create(Document& document) {
- return new BreakBlockquoteCommand(document);
+ return MakeGarbageCollected<BreakBlockquoteCommand>(document);
}
- private:
explicit BreakBlockquoteCommand(Document&);
+
+ private:
void DoApply(EditingState*) override;
};
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc
index 1e898abeb71..3cf0ee68df3 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc
@@ -69,7 +69,7 @@ class CompositeEditCommandTest : public EditingTestBase {};
TEST_F(CompositeEditCommandTest, insertNodeBefore) {
SetBodyContent("<div contenteditable><b></b></div>");
- SampleCommand& sample = *new SampleCommand(GetDocument());
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
Node* insert_child = GetDocument().createTextNode("foo");
Element* ref_child = GetDocument().QuerySelector("b");
Element* div = GetDocument().QuerySelector("div");
@@ -82,7 +82,7 @@ TEST_F(CompositeEditCommandTest, insertNodeBefore) {
TEST_F(CompositeEditCommandTest, insertNodeBeforeInUneditable) {
SetBodyContent("<div><b></b></div>");
- SampleCommand& sample = *new SampleCommand(GetDocument());
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
Node* insert_child = GetDocument().createTextNode("foo");
Element* ref_child = GetDocument().QuerySelector("b");
@@ -93,7 +93,7 @@ TEST_F(CompositeEditCommandTest, insertNodeBeforeInUneditable) {
TEST_F(CompositeEditCommandTest, insertNodeBeforeDisconnectedNode) {
SetBodyContent("<div><b></b></div>");
- SampleCommand& sample = *new SampleCommand(GetDocument());
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
Node* insert_child = GetDocument().createTextNode("foo");
Element* ref_child = GetDocument().QuerySelector("b");
Element* div = GetDocument().QuerySelector("div");
@@ -108,7 +108,7 @@ TEST_F(CompositeEditCommandTest, insertNodeBeforeDisconnectedNode) {
TEST_F(CompositeEditCommandTest, insertNodeBeforeWithDirtyLayoutTree) {
SetBodyContent("<div><b></b></div>");
- SampleCommand& sample = *new SampleCommand(GetDocument());
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
Node* insert_child = GetDocument().createTextNode("foo");
Element* ref_child = GetDocument().QuerySelector("b");
Element* div = GetDocument().QuerySelector("div");
@@ -125,7 +125,7 @@ TEST_F(CompositeEditCommandTest,
SetBodyContent(
"<style>div{-webkit-user-modify:read-only;user-select:none;}</style>"
"foo");
- SampleCommand& sample = *new SampleCommand(GetDocument());
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
Element* body = GetDocument().body();
Node* text = body->lastChild();
body->setAttribute(html_names::kContenteditableAttr, "true");
@@ -144,7 +144,7 @@ TEST_F(CompositeEditCommandTest,
TEST_F(CompositeEditCommandTest, InsertNodeOnDisconnectedParent) {
SetBodyContent("<p><b></b></p>");
- SampleCommand& sample = *new SampleCommand(GetDocument());
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
Node* insert_child = GetDocument().QuerySelector("b");
Element* ref_child = GetDocument().QuerySelector("p");
ref_child->remove();
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/create_link_command.h b/chromium/third_party/blink/renderer/core/editing/commands/create_link_command.h
index 27c695f045b..04ec2426138 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/create_link_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/create_link_command.h
@@ -33,12 +33,12 @@ namespace blink {
class CreateLinkCommand final : public CompositeEditCommand {
public:
static CreateLinkCommand* Create(Document& document, const String& link_url) {
- return new CreateLinkCommand(document, link_url);
+ return MakeGarbageCollected<CreateLinkCommand>(document, link_url);
}
- private:
CreateLinkCommand(Document&, const String& link_url);
+ private:
void DoApply(EditingState*) override;
String url_;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/editing_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/editing_command_test.cc
index ece012f6632..fdd281e8775 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/editing_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/editing_command_test.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/web_editing_command_type.h"
#include "third_party/blink/renderer/core/editing/commands/editor_command.h"
#include "third_party/blink/renderer/core/editing/commands/editor_command_names.h"
@@ -26,7 +27,7 @@ const CommandNameEntry kCommandNameEntries[] = {
};
// Test all commands except WebEditingCommandType::Invalid.
static_assert(
- arraysize(kCommandNameEntries) + 1 ==
+ base::size(kCommandNameEntries) + 1 ==
static_cast<size_t>(WebEditingCommandType::kNumberOfCommandTypes),
"must test all valid WebEditingCommandType");
@@ -35,7 +36,7 @@ static_assert(
class EditingCommandTest : public EditingTestBase {};
TEST_F(EditingCommandTest, EditorCommandOrder) {
- for (size_t i = 1; i < arraysize(kCommandNameEntries); ++i) {
+ for (size_t i = 1; i < base::size(kCommandNameEntries); ++i) {
EXPECT_GT(0, strcasecmp(kCommandNameEntries[i - 1].name,
kCommandNameEntries[i].name))
<< "EDITOR_COMMAND_MAP must be case-folding ordered. Incorrect index:"
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc
index 2e631eeb321..12a1440082d 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc
@@ -60,6 +60,7 @@
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/html_br_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -89,7 +90,7 @@ const CommandNameEntry kCommandNameEntries[] = {
};
// Handles all commands except WebEditingCommandType::Invalid.
static_assert(
- arraysize(kCommandNameEntries) + 1 ==
+ base::size(kCommandNameEntries) + 1 ==
static_cast<size_t>(WebEditingCommandType::kNumberOfCommandTypes),
"must handle all valid WebEditingCommandType");
@@ -1185,6 +1186,13 @@ static bool EnabledSelectAll(LocalFrame& frame,
if (Node* root = HighestEditableRoot(selection.Start())) {
if (!root->hasChildren())
return false;
+
+ // When the editable contains a BR only, it appears as an empty line, in
+ // which case allowing select-all confuses users.
+ if (root->firstChild() == root->lastChild() &&
+ IsHTMLBRElement(root->firstChild()))
+ return false;
+
// TODO(amaralp): Return false if already fully selected.
}
// TODO(amaralp): Address user-select handling.
@@ -1779,7 +1787,7 @@ static const EditorInternalCommand* InternalCommand(
};
// Handles all commands except WebEditingCommandType::Invalid.
static_assert(
- arraysize(kEditorCommands) + 1 ==
+ base::size(kEditorCommands) + 1 ==
static_cast<size_t>(WebEditingCommandType::kNumberOfCommandTypes),
"must handle all valid WebEditingCommandType");
@@ -1790,7 +1798,7 @@ static const EditorInternalCommand* InternalCommand(
int command_index = static_cast<int>(command_type) - 1;
DCHECK(command_index >= 0 &&
- command_index < static_cast<int>(arraysize(kEditorCommands)));
+ command_index < static_cast<int>(base::size(kEditorCommands)));
return &kEditorCommands[command_index];
}
diff --git a/chromium/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc b/chromium/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc
index f299a7e443d..c47e61e631a 100644
--- a/chromium/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/use_mock_scrollbar_settings.h"
@@ -50,11 +51,13 @@ class ComputeLayerSelectionTest : public EditingTestBase {
TEST_F(ComputeLayerSelectionTest, ComputeLayerSelection) {
SetBodyContent(R"HTML(
<!DOCTYPE html>
- input {
- font: 10px/1 Ahem;
- padding: 0;
- border: 0;
- }
+ <style>
+ input {
+ font: 10px/1 Ahem;
+ padding: 0;
+ border: 0;
+ }
+ </style>
<input id=target width=20 value='test test test test test tes tes test'
style='width: 100px; height: 20px;'>
)HTML");
@@ -67,6 +70,35 @@ TEST_F(ComputeLayerSelectionTest, ComputeLayerSelection) {
EXPECT_TRUE(composited_selection.end.hidden);
}
+TEST_F(ComputeLayerSelectionTest, DontCrashOnLayerCreation) {
+ SetBodyContent(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ input {
+ font: 10px/1 Ahem;
+ padding: 0;
+ border: 0;
+ width: 100px; height: 20px;
+ position: relative;
+ }
+ </style>
+ <input id=target width=20 value='test test test test test tes tes test'>
+ )HTML");
+ Element* target = GetDocument().getElementById("target");
+
+ FocusAndSelectAll(ToHTMLInputElement(target));
+
+ const cc::LayerSelection& composited_selection =
+ ComputeLayerSelection(Selection());
+ EXPECT_FALSE(composited_selection.start.hidden);
+ EXPECT_TRUE(composited_selection.end.hidden);
+
+ target->setAttribute(html_names::kStyleAttr, "will-change: transform");
+
+ UpdateAllLifecyclePhasesForTest();
+ // Passes if no crash.
+}
+
TEST_F(ComputeLayerSelectionTest, PositionInScrollableRoot) {
SetBodyContent(R"HTML(
<!DOCTYPE html>
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_style.cc b/chromium/third_party/blink/renderer/core/editing/editing_style.cc
index 14f3e079cda..3a318172e52 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_style.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_style.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/editing/editing_style.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/css_color_value.h"
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
@@ -98,7 +99,7 @@ static const Vector<const CSSProperty*>& AllEditingProperties() {
DEFINE_STATIC_LOCAL(Vector<const CSSProperty*>, properties, ());
if (properties.IsEmpty()) {
CSSProperty::FilterEnabledCSSPropertiesIntoVector(
- kStaticEditingProperties, arraysize(kStaticEditingProperties),
+ kStaticEditingProperties, base::size(kStaticEditingProperties),
properties);
for (wtf_size_t index = 0; index < properties.size(); index++) {
if (properties[index]->IDEquals(CSSPropertyTextDecoration)) {
@@ -114,7 +115,7 @@ static const Vector<const CSSProperty*>& InheritableEditingProperties() {
DEFINE_STATIC_LOCAL(Vector<const CSSProperty*>, properties, ());
if (properties.IsEmpty()) {
CSSProperty::FilterEnabledCSSPropertiesIntoVector(
- kStaticEditingProperties, arraysize(kStaticEditingProperties),
+ kStaticEditingProperties, base::size(kStaticEditingProperties),
properties);
for (wtf_size_t index = 0; index < properties.size();) {
if (!properties[index]->IsInherited()) {
@@ -712,7 +713,7 @@ static Vector<const CSSProperty*>& BlockPropertiesVector() {
DEFINE_STATIC_LOCAL(Vector<const CSSProperty*>, properties, ());
if (properties.IsEmpty()) {
CSSProperty::FilterEnabledCSSPropertiesIntoVector(
- kStaticBlockProperties, arraysize(kStaticBlockProperties), properties);
+ kStaticBlockProperties, base::size(kStaticBlockProperties), properties);
}
return properties;
}
@@ -837,7 +838,7 @@ EditingTriState EditingStyle::TriStateOfStyle(
};
if (should_ignore_text_only_properties == kIgnoreTextOnlyProperties) {
difference->RemovePropertiesInSet(kTextOnlyProperties,
- arraysize(kTextOnlyProperties));
+ base::size(kTextOnlyProperties));
}
if (difference->IsEmpty())
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc b/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc
index 312d2bb7448..e070814b20b 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -1610,7 +1610,7 @@ DispatchEventResult DispatchBeforeInputDataTransfer(
InputEvent* before_input_event;
- if (HasRichlyEditableStyle(*(target->ToNode())) || !data_transfer) {
+ if (HasRichlyEditableStyle(*target) || !data_transfer) {
before_input_event = InputEvent::CreateBeforeInput(
input_type, data_transfer, InputTypeIsCancelable(input_type),
InputEvent::EventIsComposing::kNotComposing,
@@ -1705,7 +1705,8 @@ void WriteImageNodeToClipboard(const Node& node, const String& title) {
return;
const KURL url_string = node.GetDocument().CompleteURL(
StripLeadingAndTrailingHTMLSpaces(GetUrlStringFromNode(node)));
- SystemClipboard::GetInstance().WriteImage(image.get(), url_string, title);
+ SystemClipboard::GetInstance().WriteImageWithTag(image.get(), url_string,
+ title);
}
Element* FindEventTargetFrom(LocalFrame& frame,
diff --git a/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc b/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc
index e96d4a71387..a4073909eb6 100644
--- a/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc
+++ b/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc
@@ -212,27 +212,13 @@ bool ElementInnerTextCollector::ShouldEmitNewlineForTableRow(
return false;
}
-// Note: LayoutFlowThread, used for multicol, can't provide offset mapping.
-bool CanUseOffsetMapping(const LayoutObject& object) {
- return object.IsLayoutBlockFlow() && !object.IsLayoutFlowThread();
-}
-
-LayoutBlockFlow* ContainingBlockFlowFor(const LayoutText& object) {
- for (LayoutObject* runner = object.Parent(); runner;
- runner = runner->Parent()) {
- if (!CanUseOffsetMapping(*runner))
- continue;
- return ToLayoutBlockFlow(runner);
- }
- return nullptr;
-}
-
const NGOffsetMapping* ElementInnerTextCollector::GetOffsetMapping(
const LayoutText& layout_text) {
// TODO(editing-dev): We should handle "text-transform" in "::first-line".
// In legacy layout, |InlineTextBox| holds original text and text box
// paint does text transform.
- LayoutBlockFlow* const block_flow = ContainingBlockFlowFor(layout_text);
+ LayoutBlockFlow* const block_flow =
+ NGOffsetMapping::GetInlineFormattingContextOf(layout_text);
DCHECK(block_flow) << layout_text;
if (block_flow == last_offset_mapping_block_flow_)
return last_offset_mapping_;
@@ -402,8 +388,8 @@ void ElementInnerTextCollector::ProcessTextNode(const Text& node) {
const LayoutText& layout_text = *node.GetLayoutObject();
if (LayoutText* first_letter_part = layout_text.GetFirstLetterPart()) {
if (layout_text.TextLength() == 0 ||
- ContainingBlockFlowFor(layout_text) !=
- ContainingBlockFlowFor(*first_letter_part)) {
+ NGOffsetMapping::GetInlineFormattingContextOf(layout_text) !=
+ NGOffsetMapping::GetInlineFormattingContextOf(*first_letter_part)) {
// "::first-letter" with "float" reach here.
ProcessLayoutText(*first_letter_part, node);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc b/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc
index b1b58a03e37..1d98598aeea 100644
--- a/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc
@@ -24,11 +24,6 @@ INSTANTIATE_TEST_CASE_P(All, ElementInnerTest, testing::Bool());
TEST_P(ElementInnerTest, ListItemWithLeadingWhiteSpace) {
SetBodyContent("<li id=target> abc</li>");
Element& target = *GetDocument().getElementById("target");
- if (!LayoutNGEnabled()) {
- // TODO(crbug.com/908339) Actual result should be "abc", no leading space.
- EXPECT_EQ(" abc", target.innerText());
- return;
- }
EXPECT_EQ("abc", target.innerText());
}
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc
new file mode 100644
index 00000000000..6cd63bbe743
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -0,0 +1,354 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
+
+#include "third_party/blink/renderer/core/css/style_change_reason.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/range.h"
+#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/editing/editing_utilities.h"
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h"
+#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
+#include "third_party/blink/renderer/core/invisible_dom/invisible_dom.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/text/unicode_utilities.h"
+#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
+#include "third_party/blink/renderer/platform/wtf/text/unicode.h"
+
+namespace blink {
+
+FindBuffer::FindBuffer(const PositionInFlatTree& start_position) {
+ DCHECK(start_position.ComputeContainerNode());
+ CollectTextUntilBlockBoundary(*start_position.ComputeContainerNode());
+}
+
+FindBuffer::Results::Results() {
+ empty_result_ = true;
+}
+
+FindBuffer::Results::Results(const Vector<UChar>& buffer,
+ String search_text,
+ const mojom::blink::FindOptions& options) {
+ // We need to own the |search_text| because |text_searcher_| only has a
+ // StringView (doesn't own the search text).
+ search_text_ = search_text;
+ text_searcher_.SetPattern(search_text_, options.match_case);
+ text_searcher_.SetText(buffer.data(), buffer.size());
+ text_searcher_.SetOffset(0);
+}
+
+FindBuffer::Results::Iterator::Iterator(TextSearcherICU* text_searcher)
+ : text_searcher_(text_searcher), has_match_(true) {
+ operator++();
+}
+
+const FindBuffer::BufferMatchResult FindBuffer::Results::Iterator::operator*()
+ const {
+ DCHECK(has_match_);
+ return FindBuffer::BufferMatchResult({match_.start, match_.length});
+}
+
+void FindBuffer::Results::Iterator::operator++() {
+ DCHECK(has_match_);
+ has_match_ = text_searcher_->NextMatchResult(match_);
+}
+
+FindBuffer::Results::Iterator FindBuffer::Results::begin() {
+ if (empty_result_)
+ return end();
+ text_searcher_.SetOffset(0);
+ return Iterator(&text_searcher_);
+}
+
+FindBuffer::Results::Iterator FindBuffer::Results::end() const {
+ return Iterator();
+}
+
+unsigned FindBuffer::Results::CountForTesting() {
+ unsigned result = 0;
+ for (Iterator it = begin(); it != end(); ++it) {
+ ++result;
+ }
+ return result;
+}
+
+void FindBuffer::InvisibleLayoutScope::EnsureRecalc(Node& block_root) {
+ if (did_recalc_)
+ return;
+ did_recalc_ = true;
+ DCHECK(block_root.GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kStyleClean);
+ if (InvisibleDOM::IsInsideInvisibleSubtree(block_root))
+ invisible_root_ = InvisibleDOM::InvisibleRoot(block_root);
+ else
+ invisible_root_ = &ToElement(block_root);
+ invisible_root_->GetDocument().SetFindInPageRoot(invisible_root_);
+ invisible_root_->SetNeedsStyleRecalc(
+ kSubtreeStyleChange,
+ StyleChangeReasonForTracing::Create(style_change_reason::kFindInvisible));
+ // TODO(rakina): This currently does layout too and might be expensive. In the
+ // future, we might to figure out a way to make NGOffsetMapping work with only
+ // style & layout tree so that we don't have to do layout here.
+ invisible_root_->GetDocument()
+ .UpdateStyleAndLayoutIgnorePendingStylesheetsConsideringInvisibleNodes();
+}
+
+FindBuffer::InvisibleLayoutScope::~InvisibleLayoutScope() {
+ if (!did_recalc_)
+ return;
+ invisible_root_->GetDocument().SetFindInPageRoot(nullptr);
+ invisible_root_->SetNeedsStyleRecalc(
+ kSubtreeStyleChange,
+ StyleChangeReasonForTracing::Create(style_change_reason::kFindInvisible));
+ invisible_root_->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
+}
+
+bool ShouldIgnoreContents(const Node& node) {
+ if (!node.IsHTMLElement())
+ return false;
+ const HTMLElement& element = ToHTMLElement(node);
+ return (!element.ShouldSerializeEndTag() && !IsHTMLInputElement(element)) ||
+ IsHTMLIFrameElement(element) || IsHTMLImageElement(element) ||
+ IsHTMLLegendElement(element) || IsHTMLMeterElement(element) ||
+ IsHTMLObjectElement(element) || IsHTMLProgressElement(element) ||
+ IsHTMLSelectElement(element) || IsHTMLStyleElement(element) ||
+ IsHTMLScriptElement(element) || IsHTMLVideoElement(element) ||
+ IsHTMLAudioElement(element) ||
+ (element.GetDisplayLockContext() &&
+ !element.GetDisplayLockContext()->IsSearchable());
+}
+
+Node* GetDisplayNoneAncestor(const Node& node) {
+ for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
+ const ComputedStyle* style = ancestor.EnsureComputedStyle();
+ if (style && style->Display() == EDisplay::kNone)
+ return &ancestor;
+ if (ancestor.IsDocumentNode())
+ return nullptr;
+ }
+ return nullptr;
+}
+
+bool IsBlock(EDisplay display) {
+ return display == EDisplay::kBlock || display == EDisplay::kTable ||
+ display == EDisplay::kFlowRoot || display == EDisplay::kGrid ||
+ display == EDisplay::kFlex || display == EDisplay::kListItem;
+}
+
+Node* GetVisibleTextNode(Node& start_node) {
+ Node* node = &start_node;
+ // Move to outside display none subtree if we're inside one.
+ while (Node* ancestor = GetDisplayNoneAncestor(*node)) {
+ if (ancestor->IsDocumentNode())
+ return nullptr;
+ node = FlatTreeTraversal::NextSkippingChildren(*ancestor);
+ if (!node)
+ return nullptr;
+ }
+ // Move to first text node that's visible.
+ while (node) {
+ const ComputedStyle* style = node->EnsureComputedStyle();
+ if (ShouldIgnoreContents(*node) ||
+ (style && style->Display() == EDisplay::kNone)) {
+ // This element and its descendants are not visible, skip it.
+ node = FlatTreeTraversal::NextSkippingChildren(*node);
+ continue;
+ }
+ if (style && style->Visibility() == EVisibility::kVisible &&
+ node->IsTextNode()) {
+ return node;
+ }
+ // This element is hidden, but node might be visible,
+ // or this is not a text node, so we move on.
+ node = FlatTreeTraversal::Next(*node);
+ }
+ return nullptr;
+}
+
+Node& GetLowestDisplayBlockInclusiveAncestor(const Node& start_node) {
+ // Gets lowest inclusive ancestor that has block display value.
+ // <div id=outer>a<div id=inner>b</div>c</div>
+ // If we run this on "a" or "c" text node in we will get the outer div.
+ // If we run it on the "b" text node we will get the inner div.
+ for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(start_node)) {
+ const ComputedStyle* style = ancestor.EnsureComputedStyle();
+ if (style && !ancestor.IsTextNode() && IsBlock(style->Display()))
+ return ancestor;
+ }
+ return *start_node.GetDocument().documentElement();
+}
+
+std::unique_ptr<FindBuffer::Results> FindBuffer::FindMatches(
+ const WebString& search_text,
+ const mojom::blink::FindOptions& options) const {
+ if (buffer_.IsEmpty() || search_text.length() > buffer_.size())
+ return std::make_unique<Results>();
+ String search_text_16_bit = search_text;
+ search_text_16_bit.Ensure16Bit();
+ FoldQuoteMarksAndSoftHyphens(search_text_16_bit);
+ return std::make_unique<Results>(buffer_, search_text_16_bit, options);
+}
+
+// Collects text until block boundary located at or after |start_node|
+// to |buffer_|. Saves the next starting node after the block to
+// |node_after_block_|.
+void FindBuffer::CollectTextUntilBlockBoundary(Node& start_node) {
+ // Get first visible text node from |start_node|.
+ Node* node = GetVisibleTextNode(start_node);
+ if (!node || !node->isConnected()) {
+ node_after_block_ = nullptr;
+ return;
+ }
+ Node& block_ancestor = GetLowestDisplayBlockInclusiveAncestor(*node);
+ const Node* just_after_block = FlatTreeTraversal::Next(
+ FlatTreeTraversal::LastWithinOrSelf(block_ancestor));
+ const LayoutBlockFlow* last_block_flow = nullptr;
+
+ // Calculate layout tree and style for invisible nodes inside the whole
+ // subtree of |block_ancestor|.
+ if (node && InvisibleDOM::IsInsideInvisibleSubtree(*node))
+ invisible_layout_scope_.EnsureRecalc(block_ancestor);
+
+ // Collect all text under |block_ancestor| to |buffer_|,
+ // unless we meet another block on the way. If so, we should split.
+ // Example: <div id="outer">a<span>b</span>c<div>d</div></div>
+ // Will try to collect all text in outer div but will actually
+ // stop when it encounters the inner div. So buffer will be "abc".
+ Node* const first_traversed_node = node;
+ while (node && node != just_after_block) {
+ if (ShouldIgnoreContents(*node)) {
+ // Move the node so we wouldn't encounter this node or its descendants
+ // later.
+ buffer_.push_back(kObjectReplacementCharacter);
+ node = FlatTreeTraversal::NextSkippingChildren(*node);
+ continue;
+ }
+ if (node->IsElementNode() && ToElement(node)->HasInvisibleAttribute() &&
+ !invisible_layout_scope_.DidRecalc()) {
+ // We found and invisible node. Calculate the layout & style for the whole
+ // block at once, and we need to recalculate the NGOffsetMapping and start
+ // from the beginning again because the layout tree had changed.
+ mapping_needs_recalc_ = true;
+ node = first_traversed_node;
+ last_block_flow = nullptr;
+ offset_mapping_storage_ = nullptr;
+ buffer_.clear();
+ invisible_layout_scope_.EnsureRecalc(block_ancestor);
+ continue;
+ }
+ const ComputedStyle* style = node->EnsureComputedStyle();
+ if (style->Display() == EDisplay::kNone) {
+ // This element and its descendants are not visible, skip it.
+ // We can safely just check the computed style of this node since
+ // we guarantee |block_ancestor| is visible.
+ node = FlatTreeTraversal::NextSkippingChildren(*node);
+ if (node && !FlatTreeTraversal::IsDescendantOf(*node, block_ancestor))
+ break;
+ continue;
+ }
+ // This node is in its own sub-block separate from our starting position.
+ if (first_traversed_node != node && !node->IsTextNode() &&
+ IsBlock(style->Display())) {
+ break;
+ }
+
+ if (style->Visibility() == EVisibility::kVisible && node->IsTextNode() &&
+ node->GetLayoutObject()) {
+ const Text& text_node = ToText(*node);
+ LayoutBlockFlow& block_flow =
+ *NGOffsetMapping::GetInlineFormattingContextOf(
+ *text_node.GetLayoutObject());
+ if (last_block_flow && last_block_flow != block_flow) {
+ // We enter another block flow.
+ break;
+ }
+ if (!last_block_flow) {
+ DCHECK(!offset_mapping_storage_);
+ last_block_flow = &block_flow;
+ }
+ AddTextToBuffer(text_node, block_flow);
+ }
+ node = FlatTreeTraversal::Next(*node);
+ }
+ node_after_block_ = node;
+ FoldQuoteMarksAndSoftHyphens(buffer_.data(), buffer_.size());
+}
+
+EphemeralRangeInFlatTree FindBuffer::RangeFromBufferIndex(
+ unsigned start_index,
+ unsigned end_index) const {
+ DCHECK_LE(start_index, end_index);
+ PositionInFlatTree start_position =
+ PositionAtStartOfCharacterAtIndex(start_index);
+ PositionInFlatTree end_position =
+ PositionAtEndOfCharacterAtIndex(end_index - 1);
+ return EphemeralRangeInFlatTree(start_position, end_position);
+}
+
+FindBuffer::BufferNodeMapping FindBuffer::MappingForIndex(
+ unsigned index) const {
+ // Get the first entry that starts at a position higher than offset, and
+ // move back one entry.
+ auto* it = std::upper_bound(
+ buffer_node_mappings_.begin(), buffer_node_mappings_.end(), index,
+ [](const unsigned offset, const BufferNodeMapping& entry) {
+ return offset < entry.offset_in_buffer;
+ });
+ DCHECK_NE(it, buffer_node_mappings_.begin());
+ auto* const entry = std::prev(it);
+ return *entry;
+}
+
+PositionInFlatTree FindBuffer::PositionAtStartOfCharacterAtIndex(
+ unsigned index) const {
+ DCHECK_LT(index, buffer_.size());
+ BufferNodeMapping entry = MappingForIndex(index);
+ return ToPositionInFlatTree(offset_mapping_->GetLastPosition(
+ index - entry.offset_in_buffer + entry.offset_in_mapping));
+}
+
+PositionInFlatTree FindBuffer::PositionAtEndOfCharacterAtIndex(
+ unsigned index) const {
+ DCHECK_LT(index, buffer_.size());
+ BufferNodeMapping entry = MappingForIndex(index);
+ return ToPositionInFlatTree(offset_mapping_->GetFirstPosition(
+ index - entry.offset_in_buffer + entry.offset_in_mapping + 1));
+}
+
+void FindBuffer::AddTextToBuffer(const Text& text_node,
+ LayoutBlockFlow& block_flow) {
+ if (!offset_mapping_ || mapping_needs_recalc_) {
+ offset_mapping_ =
+ NGInlineNode::GetOffsetMapping(&block_flow, &offset_mapping_storage_);
+ mapping_needs_recalc_ = false;
+ }
+ const String mapped_text = offset_mapping_->GetText();
+ const NGMappingUnitRange range =
+ offset_mapping_->GetMappingUnitsForNode(text_node);
+ unsigned last_unit_end = 0;
+ bool first_unit = true;
+ for (const NGOffsetMappingUnit& unit : range) {
+ String text_for_unit =
+ mapped_text.Substring(unit.TextContentStart(),
+ unit.TextContentEnd() - unit.TextContentStart());
+ text_for_unit.Ensure16Bit();
+ text_for_unit.Replace('\n', kObjectReplacementCharacter);
+ if (first_unit || last_unit_end != unit.TextContentStart()) {
+ // This is the first unit, or the units are not consecutive, so we need to
+ // insert a new BufferNodeMapping.
+ buffer_node_mappings_.push_back(
+ BufferNodeMapping({buffer_.size(), unit.TextContentStart()}));
+ first_unit = false;
+ }
+ buffer_.Append(text_for_unit.Characters16(), text_for_unit.length());
+ last_unit_end = unit.TextContentEnd();
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h
new file mode 100644
index 00000000000..80ea303f223
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h
@@ -0,0 +1,174 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_FIND_BUFFER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_FIND_BUFFER_H_
+
+#include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink.h"
+#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
+#include "third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+
+namespace blink {
+
+class LayoutBlockFlow;
+class Node;
+class WebString;
+
+// Buffer for find-in-page, collects text until it meets a block/other
+// delimiters. Uses TextSearcherICU to find match in buffer.
+// See doc at https://goo.gl/rnXjBu
+class CORE_EXPORT FindBuffer {
+ STACK_ALLOCATED();
+
+ public:
+ FindBuffer(const PositionInFlatTree& start_position);
+
+ // A match result, containing the starting position of the match and
+ // the length of the match.
+ struct BufferMatchResult {
+ const unsigned start;
+ const unsigned length;
+ };
+
+ // All match results for this buffer. We can iterate through the
+ // BufferMatchResults one by one using the Iterator.
+ class CORE_EXPORT Results {
+ public:
+ Results();
+
+ Results(const Vector<UChar>& buffer,
+ String search_text,
+ const mojom::blink::FindOptions& options);
+
+ class CORE_EXPORT Iterator
+ : public std::iterator<std::forward_iterator_tag, BufferMatchResult> {
+ public:
+ Iterator() = default;
+ Iterator(TextSearcherICU* text_searcher);
+
+ bool operator==(const Iterator& other) {
+ return has_match_ == other.has_match_;
+ }
+
+ bool operator!=(const Iterator& other) {
+ return has_match_ != other.has_match_;
+ }
+
+ const BufferMatchResult operator*() const;
+
+ void operator++();
+
+ private:
+ TextSearcherICU* text_searcher_;
+ MatchResultICU match_;
+ bool has_match_ = false;
+ };
+
+ Iterator begin();
+
+ Iterator end() const;
+
+ unsigned CountForTesting();
+
+ private:
+ bool empty_result_ = false;
+ String search_text_;
+ TextSearcherICU text_searcher_;
+ };
+
+ // Finds all the match for |search_text| in |buffer_|.
+ std::unique_ptr<Results> FindMatches(
+ const WebString& search_text,
+ const mojom::blink::FindOptions& options) const;
+
+ // Gets a flat tree range corresponding to text in the [start_index,
+ // end_index) of |buffer|.
+ EphemeralRangeInFlatTree RangeFromBufferIndex(unsigned start_index,
+ unsigned end_index) const;
+
+ PositionInFlatTree PositionAfterBlock() const {
+ if (!node_after_block_)
+ return PositionInFlatTree();
+ return PositionInFlatTree::FirstPositionInNode(*node_after_block_);
+ }
+
+ private:
+ // Collects text for one LayoutBlockFlow located at or after |start_node|
+ // to |buffer_|, might be stopped without finishing one full LayoutBlockFlow
+ // if we encountered another LayoutBLockFlow. Saves the next starting node
+ // after the block (first node in another LayoutBlockFlow) to
+ // |node_after_block_|.
+ void CollectTextUntilBlockBoundary(Node& start_node);
+
+ class CORE_EXPORT InvisibleLayoutScope {
+ STACK_ALLOCATED();
+
+ public:
+ InvisibleLayoutScope() {}
+ ~InvisibleLayoutScope();
+
+ void EnsureRecalc(Node& block_root);
+ bool DidRecalc() { return did_recalc_; }
+
+ private:
+ bool did_recalc_ = false;
+ Member<Element> invisible_root_;
+ };
+
+ // Mapping for position in buffer -> actual node where the text came from,
+ // along with the offset in the NGOffsetMapping of this find_buffer.
+ // This is needed because when we find a match in the buffer, we want to know
+ // where it's located in the NGOffsetMapping for this FindBuffer.
+ // Example: (assume there are no whitespace)
+ // <div>
+ // aaa
+ // <span style="float:right;">bbb<span>ccc</span></span>
+ // ddd
+ // </div>
+ // We can finish FIP with three FindBuffer runs:
+ // Run #1, 1 BufferNodeMapping with mapping text = "aaa\uFFFCddd",
+ // The "\uFFFC" is the object replacement character created by the float.
+ // For text node "aaa", oib = 0, oim = 0.
+ // Content of |buffer_| = "aaa".
+ // Run #2, 2 BufferNodeMappings, with mapping text = "bbbccc",
+ // 1. For text node "bbb", oib = 0, oim = 0.
+ // 2. For text node "ccc", oib = 3, oim = 3.
+ // Content of |buffer_| = "bbbccc".
+ // Run #3, 1 BufferNodeMapping with mapping text = "aaa\uFFFCddd",
+ // For text node "ddd", oib = 0, oim = 4.
+ // Content of |buffer_| = "ddd".
+ // Since the LayoutBlockFlow for "aaa" and "ddd" is the same, they have the
+ // same NGOffsetMapping, the |offset_in_mapping_| for the BufferNodeMapping in
+ // run #3 is 4 (the index of first "d" character in the mapping text).
+ struct BufferNodeMapping {
+ const unsigned offset_in_buffer;
+ const unsigned offset_in_mapping;
+ };
+
+ BufferNodeMapping MappingForIndex(unsigned index) const;
+
+ PositionInFlatTree PositionAtStartOfCharacterAtIndex(unsigned index) const;
+
+ PositionInFlatTree PositionAtEndOfCharacterAtIndex(unsigned index) const;
+
+ void AddTextToBuffer(const Text& text_node, LayoutBlockFlow& block_flow);
+
+ InvisibleLayoutScope invisible_layout_scope_;
+ Member<Node> node_after_block_;
+ Vector<UChar> buffer_;
+ Vector<BufferNodeMapping> buffer_node_mappings_;
+
+ // For legacy layout, we need to save a unique_ptr of the NGOffsetMapping
+ // because nobody owns it. In LayoutNG, the NGOffsetMapping is owned by
+ // the corresponding LayoutBlockFlow, so we don't need to save it.
+ std::unique_ptr<NGOffsetMapping> offset_mapping_storage_;
+ const NGOffsetMapping* offset_mapping_ = nullptr;
+
+ bool mapping_needs_recalc_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_FIND_BUFFER_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
new file mode 100644
index 00000000000..71cb1338c28
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
@@ -0,0 +1,280 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
+
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
+#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+
+namespace blink {
+
+class FindBufferTest : public EditingTestBase {
+ protected:
+ PositionInFlatTree FirstPosition() {
+ return PositionInFlatTree::FirstPositionInNode(
+ *GetDocument().documentElement());
+ }
+
+ PositionInFlatTree PositionFromParentId(const char* id, unsigned offset) {
+ return PositionInFlatTree(GetElementById(id)->firstChild(), offset);
+ }
+
+ std::string SerializeRange(const EphemeralRangeInFlatTree& range) {
+ return GetSelectionTextInFlatTreeFromBody(
+ SelectionInFlatTree::Builder().SetAsForwardSelection(range).Build());
+ }
+};
+
+TEST_F(FindBufferTest, FindInline) {
+ SetBodyContent(
+ "<div id='container'>a<span id='span'>b</span><b id='b'>c</b><div "
+ "id='none' style='display:none'>d</div><div id='inline-div' "
+ "style='display: inline;'>e</div></div>");
+ FindBuffer buffer(FirstPosition());
+ EXPECT_TRUE(buffer.PositionAfterBlock().IsNull());
+ std::unique_ptr<FindBuffer::Results> results =
+ buffer.FindMatches("abce", *mojom::blink::FindOptions::New());
+ EXPECT_EQ(1u, results->CountForTesting());
+ FindBuffer::BufferMatchResult match = *results->begin();
+ EXPECT_EQ(0u, match.start);
+ EXPECT_EQ(4u, match.length);
+ EXPECT_EQ(
+ EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("inline-div", 1)),
+ buffer.RangeFromBufferIndex(match.start, match.start + match.length));
+}
+
+TEST_F(FindBufferTest, RangeFromBufferIndex) {
+ SetBodyContent(
+ "<div id='container'>a <span id='span'> b</span><b id='b'>cc</b><div "
+ "id='none' style='display:none'>d</div><div id='inline-div' "
+ "style='display: inline;'>e</div></div>");
+ FindBuffer buffer(FirstPosition());
+ // Range for "a"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("container", 1)),
+ buffer.RangeFromBufferIndex(0, 1));
+ EXPECT_EQ(
+ "<div id=\"container\">^a| <span id=\"span\"> b</span><b "
+ "id=\"b\">cc</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(0, 1)));
+ // Range for "a "
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("container", 2)),
+ buffer.RangeFromBufferIndex(0, 2));
+ EXPECT_EQ(
+ "<div id=\"container\">^a |<span id=\"span\"> b</span><b "
+ "id=\"b\">cc</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(0, 2)));
+ // Range for "a b"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("span", 2)),
+ buffer.RangeFromBufferIndex(0, 3));
+ EXPECT_EQ(
+ "<div id=\"container\">^a <span id=\"span\"> b|</span><b "
+ "id=\"b\">cc</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(0, 3)));
+ // Range for "a bc"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("b", 1)),
+ buffer.RangeFromBufferIndex(0, 4));
+ EXPECT_EQ(
+ "<div id=\"container\">^a <span id=\"span\"> b</span><b "
+ "id=\"b\">c|c</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(0, 4)));
+ // Range for "a bcc"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("b", 2)),
+ buffer.RangeFromBufferIndex(0, 5));
+ EXPECT_EQ(
+ "<div id=\"container\">^a <span id=\"span\"> b</span><b "
+ "id=\"b\">cc|</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(0, 5)));
+ // Range for "a bcce"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0),
+ PositionFromParentId("inline-div", 1)),
+ buffer.RangeFromBufferIndex(0, 6));
+ EXPECT_EQ(
+ "<div id=\"container\">^a <span id=\"span\"> b</span><b "
+ "id=\"b\">cc</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e|</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(0, 6)));
+ // Range for " b"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 1),
+ PositionFromParentId("span", 2)),
+ buffer.RangeFromBufferIndex(1, 3));
+ EXPECT_EQ(
+ "<div id=\"container\">a^ <span id=\"span\"> b|</span><b "
+ "id=\"b\">cc</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(1, 3)));
+ // Range for " bc"
+ EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 1),
+ PositionFromParentId("b", 1)),
+ buffer.RangeFromBufferIndex(1, 4));
+ EXPECT_EQ(
+ "<div id=\"container\">a^ <span id=\"span\"> b</span><b "
+ "id=\"b\">c|c</b><div id=\"none\" style=\"display:none\">d</div><div "
+ "id=\"inline-div\" style=\"display: inline;\">e</div></div>",
+ SerializeRange(buffer.RangeFromBufferIndex(1, 4)));
+}
+
+class FindBufferBlockTest : public FindBufferTest,
+ public testing::WithParamInterface<std::string> {};
+
+INSTANTIATE_TEST_CASE_P(Blocks,
+ FindBufferBlockTest,
+ testing::Values("block",
+ "table",
+ "flow-root",
+ "grid",
+ "flex",
+ "list-item"));
+
+TEST_P(FindBufferBlockTest, FindBlock) {
+ SetBodyContent("text<div id='block' style='display: " + GetParam() +
+ ";'>block</div><span id='span'>span</span>");
+ FindBuffer text_buffer(FirstPosition());
+ EXPECT_EQ(GetElementById("block"),
+ *text_buffer.PositionAfterBlock().ComputeContainerNode());
+ EXPECT_EQ(1u,
+ text_buffer.FindMatches("text", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, text_buffer
+ .FindMatches("textblock", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(
+ 0u,
+ text_buffer.FindMatches("text block", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+
+ FindBuffer block_buffer(text_buffer.PositionAfterBlock());
+ EXPECT_EQ(GetElementById("span"),
+ *block_buffer.PositionAfterBlock().ComputeContainerNode());
+ EXPECT_EQ(
+ 1u, block_buffer.FindMatches("block", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, block_buffer
+ .FindMatches("textblock", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(
+ 0u,
+ block_buffer.FindMatches("text block", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, block_buffer
+ .FindMatches("blockspan", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(
+ 0u,
+ block_buffer.FindMatches("block span", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+
+ FindBuffer span_buffer(block_buffer.PositionAfterBlock());
+ EXPECT_TRUE(span_buffer.PositionAfterBlock().IsNull());
+ EXPECT_EQ(1u,
+ span_buffer.FindMatches("span", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, span_buffer
+ .FindMatches("blockspan", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(
+ 0u,
+ span_buffer.FindMatches("block span", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+}
+
+class FindBufferSeparatorTest
+ : public FindBufferTest,
+ public testing::WithParamInterface<std::string> {};
+
+INSTANTIATE_TEST_CASE_P(Separators,
+ FindBufferSeparatorTest,
+ testing::Values("br",
+ "hr",
+ "legend",
+ "meter",
+ "object",
+ "progress",
+ "select",
+ "video"));
+
+TEST_P(FindBufferSeparatorTest, FindSeparatedElements) {
+ SetBodyContent("a<" + GetParam() + ">a</" + GetParam() + ">a");
+ FindBuffer buffer(FirstPosition());
+ EXPECT_EQ(0u, buffer.FindMatches("aa", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+}
+
+TEST_F(FindBufferTest, WhiteSpaceCollapsingPreWrap) {
+ SetBodyContent(
+ " a \n b <b> c </b> d <span style='white-space: pre-wrap'> e "
+ "</span>");
+ FindBuffer buffer(FirstPosition());
+ EXPECT_EQ(
+ 1u, buffer.FindMatches("a b c d e ", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+};
+
+TEST_F(FindBufferTest, WhiteSpaceCollapsingPre) {
+ SetBodyContent("<div style='white-space: pre;'>a \n b</div>");
+ FindBuffer buffer(FirstPosition());
+ EXPECT_EQ(1u, buffer.FindMatches("a", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(1u, buffer.FindMatches("b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("ab", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a\n b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a \nb", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a \n b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+}
+
+TEST_F(FindBufferTest, WhiteSpaceCollapsingPreLine) {
+ SetBodyContent("<div style='white-space: pre-line;'>a \n b</div>");
+ FindBuffer buffer(FirstPosition());
+ EXPECT_EQ(1u, buffer.FindMatches("a", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(1u, buffer.FindMatches("b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("ab", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a \n b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a\n b", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a \nb", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+ EXPECT_EQ(0u, buffer.FindMatches("a\nb", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+}
+
+TEST_F(FindBufferTest, BidiTest) {
+ SetBodyContent("<bdo dir=rtl id=bdo>foo<span>bar</span></bdo>");
+ FindBuffer buffer(FirstPosition());
+ EXPECT_EQ(1u, buffer.FindMatches("foobar", *mojom::blink::FindOptions::New())
+ ->CountForTesting());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.cc b/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.cc
index b78d4974944..67736f9c97c 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.cc
@@ -9,9 +9,9 @@
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/dom/scripted_idle_task_controller.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
#include "third_party/blink/renderer/core/editing/finder/find_options.h"
#include "third_party/blink/renderer/core/editing/finder/text_finder.h"
-#include "third_party/blink/renderer/core/editing/iterators/search_buffer.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/platform/histogram.h"
@@ -32,27 +32,10 @@ class FindTaskController::IdleFindTask
int identifier,
const WebString& search_text,
const mojom::blink::FindOptions& options) {
- return new IdleFindTask(controller, document, identifier, search_text,
- options);
+ return MakeGarbageCollected<IdleFindTask>(controller, document, identifier,
+ search_text, options);
}
- void Dispose() {
- DCHECK_GT(callback_handle_, 0);
- document_->CancelIdleCallback(callback_handle_);
- }
-
- void ForceInvocationForTesting() {
- invoke(IdleDeadline::Create(CurrentTimeTicks() + kFindTaskTestTimeout,
- IdleDeadline::CallbackType::kCalledWhenIdle));
- }
-
- void Trace(Visitor* visitor) override {
- visitor->Trace(controller_);
- visitor->Trace(document_);
- ScriptedIdleTaskController::IdleTask::Trace(visitor);
- }
-
- private:
IdleFindTask(FindTaskController* controller,
Document* document,
int identifier,
@@ -73,6 +56,23 @@ class FindTaskController::IdleFindTask
callback_handle_ = document_->RequestIdleCallback(this, request_options);
}
+ void Dispose() {
+ DCHECK_GT(callback_handle_, 0);
+ document_->CancelIdleCallback(callback_handle_);
+ }
+
+ void ForceInvocationForTesting() {
+ invoke(IdleDeadline::Create(CurrentTimeTicks() + kFindTaskTestTimeout,
+ IdleDeadline::CallbackType::kCalledWhenIdle));
+ }
+
+ void Trace(Visitor* visitor) override {
+ visitor->Trace(controller_);
+ visitor->Trace(document_);
+ ScriptedIdleTaskController::IdleTask::Trace(visitor);
+ }
+
+ private:
void invoke(IdleDeadline* deadline) override {
if (!controller_->ShouldFindMatches(search_text_, *options_)) {
controller_->DidFinishTask(identifier_, search_text_, *options_,
@@ -106,41 +106,38 @@ class FindTaskController::IdleFindTask
int match_count = 0;
bool full_range_searched = false;
- PositionInFlatTree next_scoping_start;
+ PositionInFlatTree next_task_start_position;
do {
- // Find next occurrence of the search string.
- // FIXME: (http://crbug.com/6818) This WebKit operation may run for longer
- // than the timeout value, and is not interruptible as it is currently
- // written. We may need to rewrite it with interruptibility in mind, or
- // find an alternative.
- const EphemeralRangeInFlatTree result = FindPlainText(
- EphemeralRangeInFlatTree(search_start, search_end), search_text_,
- options_->match_case ? 0 : kCaseInsensitive);
- if (result.IsCollapsed()) {
- // Not found.
- full_range_searched = true;
- break;
- }
- Range* result_range = Range::Create(
- result.GetDocument(), ToPositionInDOMTree(result.StartPosition()),
- ToPositionInDOMTree(result.EndPosition()));
- if (result_range->collapsed()) {
- // resultRange will be collapsed if the matched text spans over multiple
- // TreeScopes. FIXME: Show such matches to users.
- search_start = result.EndPosition();
- if (deadline->timeRemaining() > 0)
+ // Find in the whole block.
+ FindBuffer buffer(search_start);
+ std::unique_ptr<FindBuffer::Results> match_results =
+ buffer.FindMatches(search_text_, *options_);
+ for (FindBuffer::BufferMatchResult match : *match_results) {
+ const EphemeralRangeInFlatTree ephemeral_match_range =
+ buffer.RangeFromBufferIndex(match.start,
+ match.start + match.length);
+ Range* const match_range = Range::Create(
+ ephemeral_match_range.GetDocument(),
+ ToPositionInDOMTree(ephemeral_match_range.StartPosition()),
+ ToPositionInDOMTree(ephemeral_match_range.EndPosition()));
+ if (match_range->collapsed()) {
+ // resultRange will be collapsed if the matched text spans over
+ // multiple TreeScopes. TODO(rakina): Show such matches to users.
+ next_task_start_position = ephemeral_match_range.EndPosition();
continue;
+ }
+ ++match_count;
+ controller_->DidFindMatch(identifier_, match_range);
+ }
+ // At this point, all text in the block collected above has been
+ // processed. Now we move to the next block if there's any,
+ // otherwise we should stop.
+ search_start = buffer.PositionAfterBlock();
+ if (search_start.IsNull()) {
+ full_range_searched = true;
break;
}
- ++match_count;
- controller_->DidFindMatch(identifier_, result_range);
-
- // Set the new start for the search range to be the end of the previous
- // result range. There is no need to use a VisiblePosition here,
- // since findPlainText will use a TextIterator to go over the visible
- // text nodes.
- search_start = result.EndPosition();
- next_scoping_start = search_start;
+ next_task_start_position = search_start;
} while (deadline->timeRemaining() > 0);
const TimeDelta time_spent = CurrentTimeTicks() - start_time;
@@ -148,7 +145,7 @@ class FindTaskController::IdleFindTask
time_spent - time_available);
controller_->DidFinishTask(identifier_, search_text_, *options_,
- full_range_searched, next_scoping_start,
+ full_range_searched, next_task_start_position,
match_count);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.h b/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.h
index 99f0b3c4e53..1b99f852f8b 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.h
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_task_controller.h
@@ -24,9 +24,11 @@ class CORE_EXPORT FindTaskController final
public:
static FindTaskController* Create(WebLocalFrameImpl& owner_frame,
TextFinder& text_finder) {
- return new FindTaskController(owner_frame, text_finder);
+ return MakeGarbageCollected<FindTaskController>(owner_frame, text_finder);
}
+ FindTaskController(WebLocalFrameImpl& owner_frame, TextFinder& text_finder);
+
// Starts an effort of finding |search_text| in |owner_frame|,
// which will be done asynchronously with idle tasks.
void StartRequest(int identifier,
@@ -75,8 +77,6 @@ class CORE_EXPORT FindTaskController final
void Trace(Visitor* visitor);
private:
- FindTaskController(WebLocalFrameImpl& owner_frame, TextFinder& text_finder);
-
void RequestIdleFindTask(int identifier,
const WebString& search_text,
const mojom::blink::FindOptions& options);
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc b/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc
index 7398b74c230..1f9438e77b9 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -33,6 +33,7 @@
#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache_base.h"
@@ -44,7 +45,6 @@
#include "third_party/blink/renderer/core/editing/finder/find_options.h"
#include "third_party/blink/renderer/core/editing/finder/find_task_controller.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/editing/iterators/search_buffer.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
@@ -154,7 +154,7 @@ bool TextFinder::Find(int identifier,
->GetDocument()
->GetTextAutosizer()
->PageNeedsAutosizing()) {
- OwnerFrame().ViewImpl()->ZoomToFindInPageRect(
+ OwnerFrame().LocalRoot()->FrameWidget()->ZoomToFindInPageRect(
OwnerFrame().GetFrameView()->ConvertToRootFrame(
EnclosingIntRect(LayoutObject::AbsoluteBoundingBoxRectForRange(
EphemeralRange(active_match_.Get())))));
@@ -635,7 +635,8 @@ int TextFinder::SelectFindMatch(unsigned index, WebRect* selection_rect) {
// Zoom to the active match.
active_match_rect = OwnerFrame().GetFrameView()->ConvertToRootFrame(
active_match_bounding_box);
- OwnerFrame().ViewImpl()->ZoomToFindInPageRect(active_match_rect);
+ OwnerFrame().LocalRoot()->FrameWidget()->ZoomToFindInPageRect(
+ active_match_rect);
}
if (selection_rect)
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc b/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
index 824e3109cbc..8a2b8f70f62 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
@@ -34,7 +34,7 @@ class TextFinderTest : public testing::Test {
TextFinderTest() {
web_view_helper_.Initialize();
WebLocalFrameImpl& frame_impl = *web_view_helper_.LocalMainFrame();
- frame_impl.ViewImpl()->Resize(WebSize(640, 480));
+ frame_impl.ViewImpl()->MainFrameWidget()->Resize(WebSize(640, 480));
frame_impl.ViewImpl()->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
document_ = static_cast<Document*>(frame_impl.GetDocument());
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc b/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc
index 44f12350d35..d48cf0dbb1a 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc
@@ -18,14 +18,13 @@ namespace blink {
class FrameCaretTest : public EditingTestBase {
public:
- FrameCaretTest()
- : was_running_layout_test_(WebTestSupport::IsRunningWebTest()) {
+ FrameCaretTest() : was_running_web_test_(WebTestSupport::IsRunningWebTest()) {
// The caret blink timer doesn't work if IsRunningWebTest() because
// LayoutTheme::CaretBlinkInterval() returns 0.
WebTestSupport::SetIsRunningWebTest(false);
}
~FrameCaretTest() override {
- WebTestSupport::SetIsRunningWebTest(was_running_layout_test_);
+ WebTestSupport::SetIsRunningWebTest(was_running_web_test_);
}
static bool ShouldBlinkCaret(const FrameCaret& caret) {
@@ -33,7 +32,7 @@ class FrameCaretTest : public EditingTestBase {
}
private:
- const bool was_running_layout_test_;
+ const bool was_running_web_test_;
};
TEST_F(FrameCaretTest, BlinkAfterTyping) {
diff --git a/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc b/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc
index 76e7cf31051..c569a9ed663 100644
--- a/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc
+++ b/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc
@@ -61,8 +61,10 @@ InlineTextBox* SearchAheadForBetterMatch(const LayoutText* layout_object) {
next = next->NextInPreOrder(container)) {
if (next->IsLayoutBlock())
return nullptr;
- if (next->IsBR())
- return nullptr;
+ if (next->IsBR()) {
+ if (!RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return nullptr;
+ }
if (IsNonTextLeafChild(next))
return nullptr;
if (next->IsText()) {
@@ -108,6 +110,8 @@ InlineBoxPosition AdjustInlineBoxPositionForTextDirection(InlineBox* inline_box,
int caret_offset) {
DCHECK(caret_offset == inline_box->CaretLeftmostOffset() ||
caret_offset == inline_box->CaretRightmostOffset());
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return InlineBoxPosition(inline_box, caret_offset);
return BidiAdjustment::AdjustForCaretPositionResolution(
InlineBoxPosition(inline_box, caret_offset));
}
@@ -123,6 +127,8 @@ bool IsCaretAtEdgeOfInlineTextBox(int caret_offset,
DCHECK_EQ(caret_offset, box.CaretMaxOffset());
if (affinity == TextAffinity::kUpstream)
return true;
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return false;
return box.NextLeafChild() && box.NextLeafChild()->IsLineBreak();
}
@@ -136,13 +142,38 @@ InlineBoxPosition ComputeInlineBoxPositionForTextNode(
InlineBox* inline_box = nullptr;
InlineTextBox* candidate = nullptr;
+ // Used only with bidi caret affinity enabled, in which case, we may receive
+ // positions like "foo | CBA"/downstream, which should be resolved at "|CBA"
+ // instead of "foo |".
+ InlineTextBox* closest_out_of_range_box = nullptr;
+
for (InlineTextBox* box : text_layout_object->TextBoxes()) {
int caret_min_offset = box->CaretMinOffset();
int caret_max_offset = box->CaretMaxOffset();
if (caret_offset < caret_min_offset || caret_offset > caret_max_offset ||
- (caret_offset == caret_max_offset && box->IsLineBreak()))
+ (caret_offset == caret_max_offset && box->IsLineBreak())) {
+ if (!RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ continue;
+ // For downstream, find the closest box starting after |caret_offset|.
+ if (affinity == TextAffinity::kDownstream) {
+ if (caret_offset >= caret_min_offset)
+ continue;
+ if (!closest_out_of_range_box ||
+ caret_min_offset < closest_out_of_range_box->CaretMinOffset()) {
+ closest_out_of_range_box = box;
+ }
+ continue;
+ }
+ // For upstream, find the closest box ending before |caret_offset|.
+ if (caret_offset <= caret_max_offset)
+ continue;
+ if (!closest_out_of_range_box ||
+ caret_max_offset > closest_out_of_range_box->CaretMaxOffset()) {
+ closest_out_of_range_box = box;
+ }
continue;
+ }
if (caret_offset > caret_min_offset && caret_offset < caret_max_offset)
return InlineBoxPosition(box, caret_offset);
@@ -155,6 +186,23 @@ InlineBoxPosition ComputeInlineBoxPositionForTextNode(
candidate = box;
}
+ if (!inline_box && closest_out_of_range_box) {
+ if (caret_offset < closest_out_of_range_box->CaretMinOffset()) {
+ DCHECK_EQ(affinity, TextAffinity::kDownstream);
+ return InlineBoxPosition(closest_out_of_range_box,
+ closest_out_of_range_box->CaretMinOffset());
+ }
+ DCHECK_GT(caret_offset, closest_out_of_range_box->CaretMaxOffset());
+ // When the input is upstream after a line break, we should try to find a
+ // caret position in the next line instead of resolving here.
+ if (!closest_out_of_range_box->IsLineBreak()) {
+ DCHECK_EQ(affinity, TextAffinity::kUpstream);
+ return InlineBoxPosition(closest_out_of_range_box,
+ closest_out_of_range_box->CaretMaxOffset());
+ }
+ // No proper out-of-range box to use. Fall through.
+ }
+
// TODO(editing-dev): The fixup below seems hacky. It may also be incorrect in
// non-ltr text. Make it saner.
if (candidate && candidate == text_layout_object->LastTextBox() &&
diff --git a/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc b/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc
index 222f2d07ca1..f4ad06eea58 100644
--- a/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc
@@ -6,8 +6,10 @@
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -23,6 +25,9 @@ std::ostream& operator<<(std::ostream& ostream,
class InlineBoxPositionTest : public EditingTestBase {};
TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionBidiIsolate) {
+ // InlineBoxPosition is a legacy-only data structure.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
// "|" is bidi-level 0, and "foo" and "bar" are bidi-level 2
SetBodyContent(
"|<span id=sample style='unicode-bidi: isolate;'>foo<br>bar</span>|");
@@ -38,6 +43,9 @@ TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionBidiIsolate) {
// http://crbug.com/716093
TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionMixedEditable) {
+ // InlineBoxPosition is a legacy-only data structure.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
SetBodyContent(
"<div contenteditable id=sample>abc<input contenteditable=false></div>");
Element* const sample = GetDocument().getElementById("sample");
@@ -51,6 +59,9 @@ TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionMixedEditable) {
// http://crbug.com/841363
TEST_F(InlineBoxPositionTest, InFlatTreeAfterInputWithPlaceholderDoesntCrash) {
+ // InlineBoxPosition is a legacy-only data structure.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
SetBodyContent("foo <input placeholder=bla> bar");
const Element* const input = GetDocument().QuerySelector("input");
const LayoutBox* const input_layout = ToLayoutBox(input->GetLayoutObject());
@@ -64,4 +75,48 @@ TEST_F(InlineBoxPositionTest, InFlatTreeAfterInputWithPlaceholderDoesntCrash) {
EXPECT_EQ(1, box_position.offset_in_box);
}
+TEST_F(InlineBoxPositionTest, DownstreamBeforeLineBreakLTR) {
+ // InlineBoxPosition is a legacy-only data structure.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
+ // This test is for a bidi caret afinity specific behavior.
+ ScopedBidiCaretAffinityForTest scoped_bidi_affinity(true);
+
+ SetBodyContent("<div id=div>&#x05D0;&#x05D1;&#x05D2<br>ABC</div>");
+ const Element* const div = GetElementById("div");
+ const Node* const rtl_text = div->firstChild();
+ const PositionWithAffinity before_br(Position(rtl_text, 3),
+ TextAffinity::kDownstream);
+
+ const Element* const br = GetDocument().QuerySelector("br");
+ const InlineBox* const box =
+ ToLayoutText(br->GetLayoutObject())->FirstTextBox();
+
+ const InlineBoxPosition box_position = ComputeInlineBoxPosition(before_br);
+ EXPECT_EQ(box, box_position.inline_box);
+ EXPECT_EQ(0, box_position.offset_in_box);
+}
+
+TEST_F(InlineBoxPositionTest, DownstreamBeforeLineBreakRTL) {
+ // InlineBoxPosition is a legacy-only data structure.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
+ // This test is for a bidi caret afinity specific behavior.
+ ScopedBidiCaretAffinityForTest scoped_bidi_affinity(true);
+
+ SetBodyContent("<div id=div dir=rtl>ABC<br>&#x05D0;&#x05D1;&#x05D2;</div>");
+ const Element* const div = GetElementById("div");
+ const Node* const rtl_text = div->firstChild();
+ const PositionWithAffinity before_br(Position(rtl_text, 3),
+ TextAffinity::kDownstream);
+
+ const Element* const br = GetDocument().QuerySelector("br");
+ const InlineBox* const box =
+ ToLayoutText(br->GetLayoutObject())->FirstTextBox();
+
+ const InlineBoxPosition box_position = ComputeInlineBoxPosition(before_br);
+ EXPECT_EQ(box, box_position.inline_box);
+ EXPECT_EQ(0, box_position.offset_in_box);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/inline_box_traversal.cc b/chromium/third_party/blink/renderer/core/editing/inline_box_traversal.cc
index 1534c8cf7b9..5a69889e960 100644
--- a/chromium/third_party/blink/renderer/core/editing/inline_box_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/editing/inline_box_traversal.cc
@@ -289,9 +289,14 @@ class AbstractInlineBoxAndSideAffinity {
return ToPositionInFlatTree(ToNGCaretPosition().ToPositionInDOMTree());
const InlineBoxPosition inline_box_position = ToInlineBoxPosition();
- return PositionInFlatTree::EditingPositionOf(
- inline_box_position.inline_box->GetLineLayoutItem().GetNode(),
- inline_box_position.offset_in_box);
+ const LineLayoutItem item =
+ inline_box_position.inline_box->GetLineLayoutItem();
+ const int text_start_offset =
+ item.IsText() ? LineLayoutText(item).TextStartOffset() : 0;
+ const int offset_in_node =
+ text_start_offset + inline_box_position.offset_in_box;
+ return PositionInFlatTree::EditingPositionOf(item.GetNode(),
+ offset_in_node);
}
AbstractInlineBox GetBox() const { return box_; }
@@ -846,6 +851,7 @@ const InlineBox& InlineBoxTraversal::FindRightBoundaryOfEntireBidiRun(
InlineBoxPosition BidiAdjustment::AdjustForCaretPositionResolution(
const InlineBoxPosition& caret_position) {
+ DCHECK(!RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
const AbstractInlineBoxAndSideAffinity unadjusted(caret_position);
const AbstractInlineBoxAndSideAffinity adjusted =
unadjusted.AtLeftSide()
@@ -858,6 +864,7 @@ InlineBoxPosition BidiAdjustment::AdjustForCaretPositionResolution(
NGCaretPosition BidiAdjustment::AdjustForCaretPositionResolution(
const NGCaretPosition& caret_position) {
+ DCHECK(!RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
const AbstractInlineBoxAndSideAffinity unadjusted(caret_position);
const AbstractInlineBoxAndSideAffinity adjusted =
unadjusted.AtLeftSide()
@@ -870,6 +877,7 @@ NGCaretPosition BidiAdjustment::AdjustForCaretPositionResolution(
InlineBoxPosition BidiAdjustment::AdjustForHitTest(
const InlineBoxPosition& caret_position) {
+ DCHECK(!RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
const AbstractInlineBoxAndSideAffinity unadjusted(caret_position);
const AbstractInlineBoxAndSideAffinity adjusted =
unadjusted.AtLeftSide()
@@ -880,6 +888,7 @@ InlineBoxPosition BidiAdjustment::AdjustForHitTest(
NGCaretPosition BidiAdjustment::AdjustForHitTest(
const NGCaretPosition& caret_position) {
+ DCHECK(!RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
const AbstractInlineBoxAndSideAffinity unadjusted(caret_position);
const AbstractInlineBoxAndSideAffinity adjusted =
unadjusted.AtLeftSide()
@@ -891,6 +900,7 @@ NGCaretPosition BidiAdjustment::AdjustForHitTest(
SelectionInFlatTree BidiAdjustment::AdjustForRangeSelection(
const VisiblePositionInFlatTree& base,
const VisiblePositionInFlatTree& extent) {
+ DCHECK(!RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
return RangeSelectionAdjuster::AdjustFor(base, extent);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/search_buffer_test.cc b/chromium/third_party/blink/renderer/core/editing/iterators/search_buffer_test.cc
index 2a5d4864fd7..2411961ee8a 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/search_buffer_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/search_buffer_test.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/editing/iterators/search_buffer.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
@@ -71,7 +72,7 @@ TEST_F(SearchBufferTest, FindPlainTextInvalidTarget) {
static const UChar* invalid_u_strings[] = {kInvalid1, kInvalid2, kInvalid3};
- for (size_t i = 0; i < arraysize(invalid_u_strings); ++i) {
+ for (size_t i = 0; i < base::size(invalid_u_strings); ++i) {
String invalid_target(invalid_u_strings[i]);
EphemeralRange found_range =
FindPlainText(EphemeralRange(range), invalid_target, 0);
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index 9fe4180b251..7e64926b9be 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -174,6 +174,11 @@ bool ShouldHandleChildren(const Node& node,
// |EntersTextControls| flag is set.
if (!behavior.EntersTextControls() && IsTextControl(node))
return false;
+
+ if (node.IsElementNode()) {
+ if (auto* context = ToElement(node).GetDisplayLockContext())
+ return context->IsSearchable();
+ }
return true;
}
@@ -550,7 +555,7 @@ void TextIteratorAlgorithm<Strategy>::HandleReplacedElement() {
return;
}
// TODO(editing-dev): We can remove |UpdateForReplacedElement()| call when
- // we address layout test failures (text diff by newlines only) and unit
+ // we address web test failures (text diff by newlines only) and unit
// tests, e.g. TextIteratorTest.IgnoreAltTextInTextControls.
text_state_.UpdateForReplacedElement(*node_);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/layout_selection.cc b/chromium/third_party/blink/renderer/core/editing/layout_selection.cc
index a93e9e1f1e6..4c381d95d92 100644
--- a/chromium/third_party/blink/renderer/core/editing/layout_selection.cc
+++ b/chromium/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -110,7 +110,7 @@ class SelectionPaintRange : public GarbageCollected<SelectionPaintRange> {
LayoutSelection::LayoutSelection(FrameSelection& frame_selection)
: frame_selection_(&frame_selection),
has_pending_selection_(false),
- paint_range_(new SelectionPaintRange) {}
+ paint_range_(MakeGarbageCollected<SelectionPaintRange>()) {}
enum class SelectionMode {
kNone,
@@ -176,7 +176,8 @@ struct OldSelectedNodes {
STACK_ALLOCATED();
public:
- OldSelectedNodes() : paint_range(new SelectionPaintRange) {}
+ OldSelectedNodes()
+ : paint_range(MakeGarbageCollected<SelectionPaintRange>()) {}
OldSelectedNodes(OldSelectedNodes&& other) {
paint_range = other.paint_range;
selected_map = std::move(other.selected_map);
@@ -197,7 +198,8 @@ struct NewPaintRangeAndSelectedNodes {
STACK_ALLOCATED();
public:
- NewPaintRangeAndSelectedNodes() : paint_range(new SelectionPaintRange) {}
+ NewPaintRangeAndSelectedNodes()
+ : paint_range(MakeGarbageCollected<SelectionPaintRange>()) {}
NewPaintRangeAndSelectedNodes(
SelectionPaintRange* passed_paint_range,
HeapHashSet<Member<const Node>>&& passed_selected_objects)
@@ -297,9 +299,10 @@ static void SetSelectionStateIfNeeded(const Node& node, SelectionState state) {
static void SetShouldInvalidateSelection(
const NewPaintRangeAndSelectedNodes& new_range,
const OldSelectedNodes& old_selected_objects) {
- // We invalidate each LayoutObject in new SelectionPaintRange which
- // has SelectionState of kStart, kEnd, kStartAndEnd, or kInside
- // and is not in old SelectionPaintRange.
+ // We invalidate each LayoutObject in
+ // MakeGarbageCollected<SelectionPaintRange> which has SelectionState of
+ // kStart, kEnd, kStartAndEnd, or kInside and is not in old
+ // SelectionPaintRange.
for (const Node* node : new_range.selected_objects) {
if (old_selected_objects.selected_map.Contains(node))
continue;
@@ -541,8 +544,8 @@ static SelectionPaintRange* ComputeNewPaintRange(
? GetTextContentOffsetEnd(end_node, paint_range.end_offset)
: paint_range.end_offset;
- return new SelectionPaintRange(*paint_range.start_node, start_offset,
- *paint_range.end_node, end_offset);
+ return MakeGarbageCollected<SelectionPaintRange>(
+ *paint_range.start_node, start_offset, *paint_range.end_node, end_offset);
}
// ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end
@@ -789,8 +792,8 @@ static NewPaintRangeAndSelectedNodes CalcSelectionRangeAndSetSelectionState(
selected_objects.insert(end_node);
}
- SelectionPaintRange* new_range =
- new SelectionPaintRange(*start_node, start_offset, *end_node, end_offset);
+ SelectionPaintRange* new_range = MakeGarbageCollected<SelectionPaintRange>(
+ *start_node, start_offset, *end_node, end_offset);
if (!RuntimeEnabledFeatures::LayoutNGEnabled())
return {new_range, std::move(selected_objects)};
return {ComputeNewPaintRange(*new_range), std::move(selected_objects)};
diff --git a/chromium/third_party/blink/renderer/core/editing/link_selection_test.cc b/chromium/third_party/blink/renderer/core/editing/link_selection_test.cc
index 9c0d13e7d49..8d247864bd5 100644
--- a/chromium/third_party/blink/renderer/core/editing/link_selection_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/link_selection_test.cc
@@ -6,6 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_coalesced_input_event.h"
#include "third_party/blink/public/web/web_settings.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -62,7 +63,8 @@ void LinkSelectionTestBase::EmulateMouseDrag(const IntPoint& down_point,
const auto& down_event = frame_test_helpers::CreateMouseEvent(
WebMouseEvent::kMouseDown, WebMouseEvent::Button::kLeft, down_point,
modifiers);
- web_view_->HandleInputEvent(WebCoalescedInputEvent(down_event));
+ web_view_->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(down_event));
}
const int kMoveEventsNumber = 10;
@@ -74,14 +76,16 @@ void LinkSelectionTestBase::EmulateMouseDrag(const IntPoint& down_point,
const auto& move_event = frame_test_helpers::CreateMouseEvent(
WebMouseEvent::kMouseMove, WebMouseEvent::Button::kLeft, move_point,
modifiers);
- web_view_->HandleInputEvent(WebCoalescedInputEvent(move_event));
+ web_view_->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(move_event));
}
if (drag_flags & kSendUpEvent) {
const auto& up_event = frame_test_helpers::CreateMouseEvent(
WebMouseEvent::kMouseUp, WebMouseEvent::Button::kLeft, up_point,
modifiers);
- web_view_->HandleInputEvent(WebCoalescedInputEvent(up_event));
+ web_view_->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(up_event));
}
}
@@ -92,9 +96,9 @@ void LinkSelectionTestBase::EmulateMouseClick(const IntPoint& click_point,
auto event = frame_test_helpers::CreateMouseEvent(
WebMouseEvent::kMouseDown, button, click_point, modifiers);
event.click_count = count;
- web_view_->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view_->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
event.SetType(WebMouseEvent::kMouseUp);
- web_view_->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view_->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
}
void LinkSelectionTestBase::EmulateMouseDown(const IntPoint& click_point,
@@ -104,7 +108,7 @@ void LinkSelectionTestBase::EmulateMouseDown(const IntPoint& click_point,
auto event = frame_test_helpers::CreateMouseEvent(
WebMouseEvent::kMouseDown, button, click_point, modifiers);
event.click_count = count;
- web_view_->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view_->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
}
String LinkSelectionTestBase::GetSelectionText() {
@@ -137,7 +141,7 @@ class LinkSelectionTest : public LinkSelectionTestBase {
frame_test_helpers::LoadHTMLString(
main_frame_, kHTMLString,
url_test_helpers::ToKURL("http://foobar.com"));
- web_view_->Resize(WebSize(800, 600));
+ web_view_->MainFrameWidget()->Resize(WebSize(800, 600));
web_view_->GetPage()->GetFocusController().SetActive(true);
auto* document = main_frame_->GetFrame()->GetDocument();
@@ -265,18 +269,12 @@ TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownloadWhenTextSelected) {
class LinkSelectionClickEventsTest : public LinkSelectionTestBase {
protected:
- class MockEventListener final : public EventListener {
+ class MockEventListener final : public NativeEventListener {
public:
static MockEventListener* Create() {
return MakeGarbageCollected<MockEventListener>();
}
- MockEventListener() : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
MOCK_METHOD2(Invoke, void(ExecutionContext* executionContext, Event*));
};
@@ -290,7 +288,7 @@ class LinkSelectionClickEventsTest : public LinkSelectionTestBase {
frame_test_helpers::LoadHTMLString(
main_frame_, kHTMLString,
url_test_helpers::ToKURL("http://foobar.com"));
- web_view_->Resize(WebSize(800, 600));
+ web_view_->MainFrameWidget()->Resize(WebSize(800, 600));
web_view_->GetPage()->GetFocusController().SetActive(true);
auto* document = main_frame_->GetFrame()->GetDocument();
diff --git a/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc b/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc
index 04834d9fd3e..d5d92a31d94 100644
--- a/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc
+++ b/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc
@@ -111,10 +111,7 @@ LocalCaretRect LocalSelectionRectOfPositionTemplate(
return LocalCaretRect();
if (NGInlineFormattingContextOf(adjusted.GetPosition())) {
- // TODO(editing-dev): Use selection height instead of caret height, or
- // decide if we need to keep the distinction between caret height and
- // selection height in NG.
- return ComputeNGLocalCaretRect(adjusted);
+ return ComputeNGLocalSelectionRect(adjusted);
}
// TODO(editing-dev): This DCHECK is for ensuring the correctness of
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc b/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc
index 5ea2177bf85..fa085a4fc5d 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc
@@ -12,10 +12,10 @@ namespace blink {
class ActiveSuggestionMarkerListImplTest : public EditingTestBase {
protected:
ActiveSuggestionMarkerListImplTest()
- : marker_list_(new ActiveSuggestionMarkerListImpl()) {}
+ : marker_list_(MakeGarbageCollected<ActiveSuggestionMarkerListImpl>()) {}
DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
- return new ActiveSuggestionMarker(
+ return MakeGarbageCollected<ActiveSuggestionMarker>(
start_offset, end_offset, Color::kTransparent,
ws::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc b/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc
index c73d81df78c..d4921c6118f 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc
@@ -13,28 +13,29 @@ namespace blink {
class ActiveSuggestionMarkerTest : public testing::Test {};
TEST_F(ActiveSuggestionMarkerTest, MarkerType) {
- DocumentMarker* marker = new ActiveSuggestionMarker(
+ DocumentMarker* marker = MakeGarbageCollected<ActiveSuggestionMarker>(
0, 1, Color::kTransparent, ImeTextSpanThickness::kNone,
Color::kTransparent);
EXPECT_EQ(DocumentMarker::kActiveSuggestion, marker->GetType());
}
TEST_F(ActiveSuggestionMarkerTest, IsStyleableMarker) {
- DocumentMarker* marker = new ActiveSuggestionMarker(
+ DocumentMarker* marker = MakeGarbageCollected<ActiveSuggestionMarker>(
0, 1, Color::kTransparent, ImeTextSpanThickness::kNone,
Color::kTransparent);
EXPECT_TRUE(IsStyleableMarker(*marker));
}
TEST_F(ActiveSuggestionMarkerTest, ConstructorAndGetters) {
- ActiveSuggestionMarker* marker = new ActiveSuggestionMarker(
+ ActiveSuggestionMarker* marker = MakeGarbageCollected<ActiveSuggestionMarker>(
0, 1, Color::kDarkGray, ImeTextSpanThickness::kThin, Color::kGray);
EXPECT_EQ(Color::kDarkGray, marker->UnderlineColor());
EXPECT_FALSE(marker->HasThicknessThick());
EXPECT_EQ(Color::kGray, marker->BackgroundColor());
- ActiveSuggestionMarker* thick_marker = new ActiveSuggestionMarker(
- 0, 1, Color::kDarkGray, ImeTextSpanThickness::kThick, Color::kGray);
+ ActiveSuggestionMarker* thick_marker =
+ MakeGarbageCollected<ActiveSuggestionMarker>(
+ 0, 1, Color::kDarkGray, ImeTextSpanThickness::kThick, Color::kGray);
EXPECT_EQ(true, thick_marker->HasThicknessThick());
}
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc b/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc
index c979e285703..fc7fd27a63a 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc
@@ -13,12 +13,12 @@ namespace blink {
class CompositionMarkerListImplTest : public EditingTestBase {
protected:
CompositionMarkerListImplTest()
- : marker_list_(new CompositionMarkerListImpl()) {}
+ : marker_list_(MakeGarbageCollected<CompositionMarkerListImpl>()) {}
DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
- return new CompositionMarker(start_offset, end_offset, Color::kTransparent,
- ws::mojom::ImeTextSpanThickness::kThin,
- Color::kBlack);
+ return MakeGarbageCollected<CompositionMarker>(
+ start_offset, end_offset, Color::kTransparent,
+ ws::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
}
Persistent<CompositionMarkerListImpl> marker_list_;
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc b/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc
index c088ffc2dbd..7414cfa6c33 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc
@@ -13,27 +13,27 @@ namespace blink {
class CompositionMarkerTest : public testing::Test {};
TEST_F(CompositionMarkerTest, MarkerType) {
- DocumentMarker* marker =
- new CompositionMarker(0, 1, Color::kTransparent,
- ImeTextSpanThickness::kNone, Color::kTransparent);
+ DocumentMarker* marker = MakeGarbageCollected<CompositionMarker>(
+ 0, 1, Color::kTransparent, ImeTextSpanThickness::kNone,
+ Color::kTransparent);
EXPECT_EQ(DocumentMarker::kComposition, marker->GetType());
}
TEST_F(CompositionMarkerTest, IsStyleableMarker) {
- DocumentMarker* marker =
- new CompositionMarker(0, 1, Color::kTransparent,
- ImeTextSpanThickness::kNone, Color::kTransparent);
+ DocumentMarker* marker = MakeGarbageCollected<CompositionMarker>(
+ 0, 1, Color::kTransparent, ImeTextSpanThickness::kNone,
+ Color::kTransparent);
EXPECT_TRUE(IsStyleableMarker(*marker));
}
TEST_F(CompositionMarkerTest, ConstructorAndGetters) {
- CompositionMarker* marker = new CompositionMarker(
+ CompositionMarker* marker = MakeGarbageCollected<CompositionMarker>(
0, 1, Color::kDarkGray, ImeTextSpanThickness::kThin, Color::kGray);
EXPECT_EQ(Color::kDarkGray, marker->UnderlineColor());
EXPECT_TRUE(marker->HasThicknessThin());
EXPECT_EQ(Color::kGray, marker->BackgroundColor());
- CompositionMarker* thick_marker = new CompositionMarker(
+ CompositionMarker* thick_marker = MakeGarbageCollected<CompositionMarker>(
0, 1, Color::kDarkGray, ImeTextSpanThickness::kThick, Color::kGray);
EXPECT_TRUE(thick_marker->HasThicknessThick());
}
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc b/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
index 0af406cc024..9036d8cce8a 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
+++ b/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
@@ -87,9 +87,9 @@ DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex(
DocumentMarkerList* CreateListForType(DocumentMarker::MarkerType type) {
switch (type) {
case DocumentMarker::kActiveSuggestion:
- return new ActiveSuggestionMarkerListImpl();
+ return MakeGarbageCollected<ActiveSuggestionMarkerListImpl>();
case DocumentMarker::kComposition:
- return new CompositionMarkerListImpl();
+ return MakeGarbageCollected<CompositionMarkerListImpl>();
case DocumentMarker::kSpelling:
return MakeGarbageCollected<SpellingMarkerListImpl>();
case DocumentMarker::kGrammar:
@@ -187,8 +187,8 @@ void DocumentMarkerController::AddCompositionMarker(
DCHECK(!document_->NeedsLayoutTreeUpdate());
AddMarkerInternal(range, [underline_color, thickness, background_color](
int start_offset, int end_offset) {
- return new CompositionMarker(start_offset, end_offset, underline_color,
- thickness, background_color);
+ return MakeGarbageCollected<CompositionMarker>(
+ start_offset, end_offset, underline_color, thickness, background_color);
});
}
@@ -200,8 +200,8 @@ void DocumentMarkerController::AddActiveSuggestionMarker(
DCHECK(!document_->NeedsLayoutTreeUpdate());
AddMarkerInternal(range, [underline_color, thickness, background_color](
int start_offset, int end_offset) {
- return new ActiveSuggestionMarker(start_offset, end_offset, underline_color,
- thickness, background_color);
+ return MakeGarbageCollected<ActiveSuggestionMarker>(
+ start_offset, end_offset, underline_color, thickness, background_color);
});
}
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc b/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
index f389a04493a..3a9e3f5598a 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
@@ -102,6 +102,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedMarkedByNormalize) {
MarkNodeContents(parent);
EXPECT_EQ(2u, MarkerController().Markers().size());
parent->normalize();
+ UpdateAllLifecyclePhasesForTest();
}
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
@@ -114,6 +115,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedMarkedByRemoveChildren) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
parent->RemoveChildren();
+ UpdateAllLifecyclePhasesForTest();
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
EXPECT_EQ(0u, MarkerController().Markers().size());
@@ -127,6 +129,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedByRemoveMarked) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
parent->RemoveChild(parent->firstChild());
+ UpdateAllLifecyclePhasesForTest();
}
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
@@ -141,6 +144,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedMarkedByRemoveAncestor) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
parent->parentNode()->parentNode()->RemoveChild(parent->parentNode());
+ UpdateAllLifecyclePhasesForTest();
}
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
@@ -155,6 +159,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedMarkedByRemoveParent) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
parent->parentNode()->RemoveChild(parent);
+ UpdateAllLifecyclePhasesForTest();
}
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
@@ -169,6 +174,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedMarkedByReplaceChild) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
parent->ReplaceChild(CreateTextNode("bar"), parent->firstChild());
+ UpdateAllLifecyclePhasesForTest();
}
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
@@ -183,6 +189,7 @@ TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedBySetInnerHTML) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
SetBodyContent("");
+ UpdateAllLifecyclePhasesForTest();
}
// No more reference to marked node.
ThreadState::Current()->CollectAllGarbage();
@@ -200,6 +207,7 @@ TEST_F(DocumentMarkerControllerTest, SynchronousMutationNotificationAfterGC) {
MarkNodeContents(parent);
EXPECT_EQ(1u, MarkerController().Markers().size());
parent->parentNode()->RemoveChild(parent);
+ UpdateAllLifecyclePhasesForTest();
}
// GC the marked node, so it disappears from WeakMember collections.
diff --git a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc
index 8f696f4c36b..77e7ff4f619 100644
--- a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc
@@ -29,6 +29,11 @@ LocalCaretRect ComputeNGLocalCaretRect(
return ComputeNGLocalCaretRect(ToPositionInDOMTreeWithAffinity(position));
}
+LocalCaretRect ComputeNGLocalSelectionRect(
+ const PositionInFlatTreeWithAffinity& position) {
+ return ComputeNGLocalSelectionRect(ToPositionInDOMTreeWithAffinity(position));
+}
+
bool InSameNGLineBox(const PositionInFlatTreeWithAffinity& position1,
const PositionInFlatTreeWithAffinity& position2) {
return InSameNGLineBox(ToPositionInDOMTreeWithAffinity(position1),
diff --git a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h
index 0497f1b9078..fb866a55212 100644
--- a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h
+++ b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h
@@ -22,6 +22,8 @@ const LayoutBlockFlow* NGInlineFormattingContextOf(const PositionInFlatTree&);
NGCaretPosition ComputeNGCaretPosition(const PositionInFlatTreeWithAffinity&);
LocalCaretRect ComputeNGLocalCaretRect(const PositionInFlatTreeWithAffinity&);
+LocalCaretRect ComputeNGLocalSelectionRect(
+ const PositionInFlatTreeWithAffinity&);
bool InSameNGLineBox(const PositionInFlatTreeWithAffinity&,
const PositionInFlatTreeWithAffinity&);
diff --git a/chromium/third_party/blink/renderer/core/editing/plain_text_range_test.cc b/chromium/third_party/blink/renderer/core/editing/plain_text_range_test.cc
index d57f351bf0c..086ab5c51ed 100644
--- a/chromium/third_party/blink/renderer/core/editing/plain_text_range_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/plain_text_range_test.cc
@@ -9,10 +9,7 @@
namespace blink {
-class PlainTextRangeTest : public EditingTestBase {
- protected:
- Element* InsertHTMLElement(const char* element_code, const char* element_id);
-};
+class PlainTextRangeTest : public EditingTestBase {};
TEST_F(PlainTextRangeTest, RangeContainingTableCellBoundary) {
SetBodyInnerHTML(
diff --git a/chromium/third_party/blink/renderer/core/editing/selection.idl b/chromium/third_party/blink/renderer/core/editing/selection.idl
index fc128c0574f..d6d5cf0464b 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection.idl
+++ b/chromium/third_party/blink/renderer/core/editing/selection.idl
@@ -66,7 +66,7 @@
[MeasureAs=SelectionExtentOffset] readonly attribute unsigned long extentOffset;
// https://github.com/w3c/selection-api/issues/37
- [MeasureAs=SelectionModify] void modify([Default=Undefined] optional DOMString alter,
- [Default=Undefined] optional DOMString direction,
- [Default=Undefined] optional DOMString granularity);
+ [MeasureAs=SelectionModify] void modify([DefaultValue=Undefined] optional DOMString alter,
+ [DefaultValue=Undefined] optional DOMString direction,
+ [DefaultValue=Undefined] optional DOMString granularity);
};
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_controller.cc b/chromium/third_party/blink/renderer/core/editing/selection_controller.cc
index 2a7adcfd18e..a380f8b3f7c 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_controller.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_controller.cc
@@ -174,11 +174,11 @@ void SelectionController::ContextDestroyed(Document*) {
original_base_in_flat_tree_ = PositionInFlatTreeWithAffinity();
}
-static PositionInFlatTree AdjustPositionRespectUserSelectAll(
+static PositionInFlatTreeWithAffinity AdjustPositionRespectUserSelectAll(
Node* inner_node,
const PositionInFlatTree& selection_start,
const PositionInFlatTree& selection_end,
- const PositionInFlatTree& position) {
+ const PositionInFlatTreeWithAffinity& position) {
const VisibleSelectionInFlatTree& selection_in_user_select_all =
CreateVisibleSelection(ExpandSelectionToRespectUserSelectAll(
inner_node,
@@ -188,9 +188,10 @@ static PositionInFlatTree AdjustPositionRespectUserSelectAll(
if (!selection_in_user_select_all.IsRange())
return position;
if (selection_in_user_select_all.Start().CompareTo(selection_start) < 0)
- return selection_in_user_select_all.Start();
+ return PositionInFlatTreeWithAffinity(selection_in_user_select_all.Start());
+ // TODO(xiaochengh): Do we need to use upstream affinity for end?
if (selection_end.CompareTo(selection_in_user_select_all.End()) < 0)
- return selection_in_user_select_all.End();
+ return PositionInFlatTreeWithAffinity(selection_in_user_select_all.End());
return position;
}
@@ -211,7 +212,7 @@ static PositionInFlatTree ComputeStartFromEndForExtendForward(
}
static SelectionInFlatTree ExtendSelectionAsDirectional(
- const PositionInFlatTree& position,
+ const PositionInFlatTreeWithAffinity& position,
const SelectionInFlatTree& selection,
TextGranularity granularity) {
DCHECK(!selection.IsNone());
@@ -219,7 +220,7 @@ static SelectionInFlatTree ExtendSelectionAsDirectional(
const PositionInFlatTree& start = selection.ComputeStartPosition();
const PositionInFlatTree& end = selection.ComputeEndPosition();
const PositionInFlatTree& base = selection.IsBaseFirst() ? start : end;
- if (position < base) {
+ if (position.GetPosition() < base) {
// Extend backward yields backward selection
// - forward selection: *abc ^def ghi| => |abc def^ ghi
// - backward selection: *abc |def ghi^ => |abc def ghi^
@@ -230,9 +231,11 @@ static SelectionInFlatTree ExtendSelectionAsDirectional(
? ComputeEndRespectingGranularity(
new_start, PositionInFlatTreeWithAffinity(start), granularity)
: end;
- return SelectionInFlatTree::Builder()
- .SetBaseAndExtent(new_end, new_start)
- .Build();
+ SelectionInFlatTree::Builder builder;
+ builder.SetBaseAndExtent(new_end, new_start);
+ if (new_start == new_end)
+ builder.SetAffinity(position.Affinity());
+ return builder.Build();
}
// Extend forward yields forward selection
@@ -244,9 +247,11 @@ static SelectionInFlatTree ExtendSelectionAsDirectional(
: ComputeStartFromEndForExtendForward(end, granularity);
const PositionInFlatTree& new_end = ComputeEndRespectingGranularity(
new_start, PositionInFlatTreeWithAffinity(position), granularity);
- return SelectionInFlatTree::Builder()
- .SetBaseAndExtent(new_start, new_end)
- .Build();
+ SelectionInFlatTree::Builder builder;
+ builder.SetBaseAndExtent(new_start, new_end);
+ if (new_start == new_end)
+ builder.SetAffinity(position.Affinity());
+ return builder.Build();
}
static SelectionInFlatTree ExtendSelectionAsNonDirectional(
@@ -258,6 +263,8 @@ static SelectionInFlatTree ExtendSelectionAsNonDirectional(
// Shift+Click deselects when selection was created right-to-left
const PositionInFlatTree& start = selection.ComputeStartPosition();
const PositionInFlatTree& end = selection.ComputeEndPosition();
+ if (start == end && position == start)
+ return selection;
if (position < start) {
return SelectionInFlatTree::Builder()
.SetBaseAndExtent(
@@ -336,10 +343,9 @@ bool SelectionController::HandleSingleClick(
if (extend_selection && !selection.IsNone()) {
// Note: "fast/events/shift-click-user-select-none.html" makes
// |pos.isNull()| true.
- const PositionInFlatTree& adjusted_position =
+ const PositionInFlatTreeWithAffinity adjusted_position =
AdjustPositionRespectUserSelectAll(inner_node, selection.Start(),
- selection.End(),
- position_to_use.GetPosition());
+ selection.End(), position_to_use);
const TextGranularity granularity = Selection().Granularity();
if (adjusted_position.IsNull()) {
UpdateSelectionForMouseDownDispatchingSelectStart(
@@ -352,8 +358,9 @@ bool SelectionController::HandleSingleClick(
frame_->GetEditor().Behavior().ShouldConsiderSelectionAsDirectional()
? ExtendSelectionAsDirectional(adjusted_position,
selection.AsSelection(), granularity)
- : ExtendSelectionAsNonDirectional(
- adjusted_position, selection.AsSelection(), granularity),
+ : ExtendSelectionAsNonDirectional(adjusted_position.GetPosition(),
+ selection.AsSelection(),
+ granularity),
SetSelectionOptions::Builder().SetGranularity(granularity).Build());
return false;
}
@@ -516,10 +523,10 @@ void SelectionController::UpdateSelectionForMouseDrag(
return;
}
- const PositionInFlatTree& adjusted_position =
- AdjustPositionRespectUserSelectAll(target, visible_selection.Start(),
- visible_selection.End(),
- target_position.DeepEquivalent());
+ const PositionInFlatTreeWithAffinity adjusted_position =
+ AdjustPositionRespectUserSelectAll(
+ target, visible_selection.Start(), visible_selection.End(),
+ target_position.ToPositionWithAffinity());
const SelectionInFlatTree& adjusted_selection =
should_extend_selection
? ExtendSelectionAsDirectional(adjusted_position,
@@ -789,7 +796,8 @@ void SelectionController::SetNonDirectionalSelectionIfNeeded(
const VisiblePositionInFlatTree& extent =
CreateVisiblePosition(new_selection.Extent());
const SelectionInFlatTree& adjusted_selection =
- endpoints_adjustment_mode == kAdjustEndpointsAtBidiBoundary
+ (!RuntimeEnabledFeatures::BidiCaretAffinityEnabled() &&
+ endpoints_adjustment_mode == kAdjustEndpointsAtBidiBoundary)
? BidiAdjustment::AdjustForRangeSelection(base, extent)
: SelectionInFlatTree::Builder()
.SetBaseAndExtent(base.DeepEquivalent(),
@@ -957,9 +965,9 @@ bool SelectionController::HandleMousePressEvent(
// If we got the event back, that must mean it wasn't prevented,
// so it's allowed to start a drag or selection if it wasn't in a scrollbar.
- mouse_down_may_start_select_ =
- (CanMouseDownStartSelect(event.InnerNode()) || IsLinkSelection(event)) &&
- !event.GetScrollbar();
+ mouse_down_may_start_select_ = (CanMouseDownStartSelect(event.InnerNode()) ||
+ IsSelectionOverLink(event)) &&
+ !event.GetScrollbar();
mouse_down_was_single_click_in_selection_ = false;
if (!Selection().IsAvailable()) {
// "gesture-tap-frame-removed.html" reaches here.
@@ -1269,7 +1277,7 @@ FrameSelection& SelectionController::Selection() const {
return frame_->Selection();
}
-bool IsLinkSelection(const MouseEventWithHitTestResults& event) {
+bool IsSelectionOverLink(const MouseEventWithHitTestResults& event) {
return (event.Event().GetModifiers() & WebInputEvent::Modifiers::kAltKey) !=
0 &&
event.IsOverLink();
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_controller.h b/chromium/third_party/blink/renderer/core/editing/selection_controller.h
index d9933c7b37f..1371e1785f5 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_controller.h
+++ b/chromium/third_party/blink/renderer/core/editing/selection_controller.h
@@ -146,7 +146,7 @@ class CORE_EXPORT SelectionController final
DISALLOW_COPY_AND_ASSIGN(SelectionController);
};
-bool IsLinkSelection(const MouseEventWithHitTestResults&);
+bool IsSelectionOverLink(const MouseEventWithHitTestResults&);
bool IsExtendingSelection(const MouseEventWithHitTestResults&);
CORE_EXPORT SelectionInFlatTree
AdjustSelectionWithTrailingWhitespace(const SelectionInFlatTree&);
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc b/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc
index 8dbd8c40b5b..1b2bf5a5da9 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc
@@ -131,7 +131,7 @@ TextDirection SelectionModifier::DirectionOfEnclosingBlock() const {
const Position& selection_extent = selection_.Extent();
// TODO(editing-dev): Check for Position::IsNotNull is an easy fix for few
- // editing/ layout tests, that didn't expect that (e.g.
+ // editing/ web tests, that didn't expect that (e.g.
// editing/selection/extend-byline-withfloat.html).
// That should be fixed in a more appropriate manner.
// We should either have SelectionModifier aborted earlier for null selection,
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier_character.cc b/chromium/third_party/blink/renderer/core/editing/selection_modifier_character.cc
index 194724bcbe6..8bf4ba347a8 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier_character.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier_character.cc
@@ -39,6 +39,9 @@
#include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
namespace blink {
@@ -148,6 +151,13 @@ struct TraversalLeft {
return box.Root().GetLogicalStartNonPseudoBox();
return box.Root().GetLogicalEndNonPseudoBox();
}
+
+ static NGCaretNavigator::VisualCaretMovementResult ForwardPositionOf(
+ const NGCaretNavigator& caret_navigator,
+ const NGCaretNavigator::Position& caret_position) {
+ DCHECK(RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
+ return caret_navigator.LeftPositionOf(caret_position);
+ }
};
// The traversal strategy for |RightPositionOf()|.
@@ -254,6 +264,13 @@ struct TraversalRight {
return box.Root().GetLogicalEndNonPseudoBox();
return box.Root().GetLogicalStartNonPseudoBox();
}
+
+ static NGCaretNavigator::VisualCaretMovementResult ForwardPositionOf(
+ const NGCaretNavigator& caret_navigator,
+ const NGCaretNavigator::Position& caret_position) {
+ DCHECK(RuntimeEnabledFeatures::BidiCaretAffinityEnabled());
+ return caret_navigator.RightPositionOf(caret_position);
+ }
};
template <typename Traversal>
@@ -478,17 +495,97 @@ static PositionTemplate<Strategy> TraverseInternalAlgorithm(
}
template <typename Strategy, typename Traversal>
+PositionWithAffinityTemplate<Strategy> TraverseWithBidiCaretAffinity(
+ const PositionWithAffinityTemplate<Strategy> start_position_with_affinity) {
+ const PositionTemplate<Strategy> start_position =
+ start_position_with_affinity.GetPosition();
+ const Position start_position_in_dom = ToPositionInDOMTree(start_position);
+ if (start_position_in_dom.IsNull())
+ return PositionWithAffinityTemplate<Strategy>();
+
+ LayoutBlockFlow* const context =
+ NGOffsetMapping::GetInlineFormattingContextOf(start_position_in_dom);
+ if (!context) {
+ // We reach here if, e.g., the position is in an empty block.
+ // TODO(xiaochengh): Investigate if we reach here for other reaseons.
+#if DCHECK_IS_ON()
+ const Node* node = start_position.ComputeContainerNode();
+ DCHECK(node) << start_position;
+ const LayoutObject* object = node->GetLayoutObject();
+ DCHECK(object) << start_position;
+ DCHECK(object->IsLayoutBlockFlow()) << start_position;
+ DCHECK(!HasRenderedNonAnonymousDescendantsWithHeight(object))
+ << start_position;
+#endif
+ const TextDirection block_direction =
+ DirectionOfEnclosingBlockOf(start_position);
+ // TODO(xiaochengh): Should return the visual line start/end of the position
+ // below.
+ return PositionWithAffinityTemplate<Strategy>(
+ Traversal::ForwardVisuallyDistinctCandidateOf(block_direction,
+ start_position));
+ }
+
+ // TODO(xiaochengh): The double pointer pattern below is confusing and
+ // cumbersome, but necessary for now. Make it easier.
+ std::unique_ptr<NGOffsetMapping> mapping_storage;
+ const NGOffsetMapping* mapping =
+ NGInlineNode::GetOffsetMapping(context, &mapping_storage);
+ DCHECK(mapping);
+
+ const base::Optional<unsigned> start_offset =
+ mapping->GetTextContentOffset(start_position_in_dom);
+ DCHECK(start_offset.has_value());
+
+ DCHECK(mapping->GetCaretNavigator());
+ const NGCaretNavigator& caret_navigator = *mapping->GetCaretNavigator();
+ const NGCaretNavigator::Position start_caret_position =
+ caret_navigator.CaretPositionFromTextContentOffsetAndAffinity(
+ start_offset.value(), start_position_with_affinity.Affinity());
+ NGCaretNavigator::VisualCaretMovementResult result_caret_position =
+ Traversal::ForwardPositionOf(caret_navigator, start_caret_position);
+ if (result_caret_position.IsWithinContext()) {
+ DCHECK(result_caret_position.position.has_value());
+ return FromPositionInDOMTree<Strategy>(mapping->GetPositionWithAffinity(
+ result_caret_position.position.value()));
+ }
+
+ // We reach here if we need to move out of the current block.
+ if (result_caret_position.IsBeforeContext()) {
+ // TODO(xiaochengh): Move to the visual end of the previous block.
+ return PositionWithAffinityTemplate<Strategy>();
+ }
+
+ DCHECK(result_caret_position.IsAfterContext());
+ // TODO(xiaochengh): Move to the visual beginning of the next block.
+ return PositionWithAffinityTemplate<Strategy>();
+}
+
+template <typename Strategy, typename Traversal>
VisiblePositionTemplate<Strategy> TraverseAlgorithm(
const VisiblePositionTemplate<Strategy>& visible_position) {
DCHECK(visible_position.IsValid()) << visible_position;
- const PositionTemplate<Strategy> pos =
- TraverseInternalAlgorithm<Strategy, Traversal>(visible_position);
- // TODO(yosin) Why can't we move left from the last position in a tree?
- if (pos.AtStartOfTree() || pos.AtEndOfTree())
- return VisiblePositionTemplate<Strategy>();
-
- const VisiblePositionTemplate<Strategy> result = CreateVisiblePosition(pos);
- DCHECK_NE(result.DeepEquivalent(), visible_position.DeepEquivalent());
+
+ VisiblePositionTemplate<Strategy> result;
+ if (!RuntimeEnabledFeatures::BidiCaretAffinityEnabled()) {
+ const PositionTemplate<Strategy> pos =
+ TraverseInternalAlgorithm<Strategy, Traversal>(visible_position);
+ // TODO(yosin) Why can't we move left from the last position in a tree?
+ if (pos.AtStartOfTree() || pos.AtEndOfTree())
+ return VisiblePositionTemplate<Strategy>();
+ result = CreateVisiblePosition(pos);
+ DCHECK_NE(result.DeepEquivalent(), visible_position.DeepEquivalent());
+ } else {
+ const PositionWithAffinityTemplate<Strategy> pos =
+ TraverseWithBidiCaretAffinity<Strategy, Traversal>(
+ visible_position.ToPositionWithAffinity());
+ if (pos.IsNull())
+ return VisiblePositionTemplate<Strategy>();
+ result = CreateVisiblePosition(pos);
+ DCHECK_NE(result.ToPositionWithAffinity(),
+ visible_position.ToPositionWithAffinity())
+ << visible_position;
+ }
return Traversal::HonorEditingBoundary(
DirectionOfEnclosingBlockOf(result.DeepEquivalent()), result,
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc b/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc
index 5ef3bd00e72..25d769018e9 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -21,6 +22,10 @@ TEST_F(SelectionModifierTest, ExtendForwardByWordNone) {
}
TEST_F(SelectionModifierTest, leftPositionOf) {
+ // TODO(editing-dev): The behavior is for editable text only.
+ // Enable it in LayoutNG phase 2+.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
const char* body_content =
"<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b "
"id=three>333</b>";
@@ -68,6 +73,10 @@ TEST_F(SelectionModifierTest, MoveForwardByWordNone) {
}
TEST_F(SelectionModifierTest, rightPositionOf) {
+ // TODO(editing-dev): The behavior is for editable text only.
+ // Enable it in LayoutNG phase 2+.
+ ScopedLayoutNGForTest scoped_layout_ng(false);
+
const char* body_content =
"<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b "
"id=three>333</b>";
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc b/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
index 298c5571e7a..789bf35a9b4 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/editing/serializers/markup_formatter.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/dom/cdata_section.h"
#include "third_party/blink/renderer/core/dom/comment.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -114,11 +115,11 @@ void MarkupFormatter::AppendCharactersReplacingEntities(
if (source.Is8Bit()) {
AppendCharactersReplacingEntitiesInternal(
result, source.Characters8() + offset, length, kEntityMaps,
- arraysize(kEntityMaps), entity_mask);
+ base::size(kEntityMaps), entity_mask);
} else {
AppendCharactersReplacingEntitiesInternal(
result, source.Characters16() + offset, length, kEntityMaps,
- arraysize(kEntityMaps), entity_mask);
+ base::size(kEntityMaps), entity_mask);
}
}
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc b/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
index 25c3c356383..2ad96832dc0 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
@@ -21,7 +21,7 @@ static size_t Mismatch(const std::string& input1, const std::string& input2) {
}
// This is smoke test of |StyledMarkupSerializer|. Full testing will be done
-// in layout tests.
+// in web tests.
class StyledMarkupSerializerTest : public EditingTestBase {
protected:
template <typename Strategy>
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.cc b/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.cc
index d1f45225520..e4d6b57c21b 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.cc
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.cc
@@ -30,7 +30,7 @@ const int kInvalidChunkIndex = -1;
// static
ColdModeSpellCheckRequester* ColdModeSpellCheckRequester::Create(
LocalFrame& frame) {
- return new ColdModeSpellCheckRequester(frame);
+ return MakeGarbageCollected<ColdModeSpellCheckRequester>(frame);
}
void ColdModeSpellCheckRequester::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.h b/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.h
index 12fe2e355e3..cf73d780d24 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.h
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/cold_mode_spell_check_requester.h
@@ -25,6 +25,8 @@ class ColdModeSpellCheckRequester
public:
static ColdModeSpellCheckRequester* Create(LocalFrame&);
+ explicit ColdModeSpellCheckRequester(LocalFrame&);
+
void SetNeedsMoreInvocationForTesting() {
needs_more_invocation_for_testing_ = true;
}
@@ -37,8 +39,6 @@ class ColdModeSpellCheckRequester
void Trace(blink::Visitor*);
private:
- explicit ColdModeSpellCheckRequester(LocalFrame&);
-
LocalFrame& GetFrame() const { return *frame_; }
SpellCheckRequester& GetSpellCheckRequester() const;
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.cc b/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.cc
index 6dfe7b5ec4e..8f7de165492 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.cc
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.cc
@@ -70,7 +70,7 @@ void IdleSpellCheckController::Trace(blink::Visitor* visitor) {
}
IdleSpellCheckController* IdleSpellCheckController::Create(LocalFrame& frame) {
- return new IdleSpellCheckController(frame);
+ return MakeGarbageCollected<IdleSpellCheckController>(frame);
}
IdleSpellCheckController::IdleSpellCheckController(LocalFrame& frame)
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h b/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h
index 5e03f504dce..646d7444001 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h
@@ -34,6 +34,8 @@ class CORE_EXPORT IdleSpellCheckController final
public:
static IdleSpellCheckController* Create(LocalFrame&);
+
+ explicit IdleSpellCheckController(LocalFrame&);
~IdleSpellCheckController();
enum class State {
@@ -66,8 +68,6 @@ class CORE_EXPORT IdleSpellCheckController final
private:
class IdleCallback;
- explicit IdleSpellCheckController(LocalFrame&);
-
LocalFrame& GetFrame() const { return *frame_; }
// Returns whether there is an active document to work on.
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
index 4f1134de40f..3098bd0798f 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
@@ -59,12 +59,14 @@ class WebTextCheckingCompletionImpl : public WebTextCheckingCompletion {
void DidFinishCheckingText(
const WebVector<WebTextCheckingResult>& results) override {
- request_->DidSucceed(ToCoreResults(results));
+ if (request_)
+ request_->DidSucceed(ToCoreResults(results));
delete this;
}
void DidCancelCheckingText() override {
- request_->DidCancel();
+ if (request_)
+ request_->DidCancel();
// TODO(dgozman): use std::unique_ptr.
delete this;
}
@@ -72,7 +74,9 @@ class WebTextCheckingCompletionImpl : public WebTextCheckingCompletion {
private:
virtual ~WebTextCheckingCompletionImpl() = default;
- Persistent<SpellCheckRequest> request_;
+ // As |WebTextCheckingCompletionImpl| is mananaged outside Blink, it should
+ // only keep weak references to Blink objects to prevent memory leaks.
+ WeakPersistent<SpellCheckRequest> request_;
};
} // namespace
@@ -233,11 +237,6 @@ void SpellCheckRequester::PrepareForLeakDetection() {
// the leak detector, they're all cancelled to prevent flaky leaks being
// reported.
request_queue_.clear();
- // WebTextCheckClient stores a set of WebTextCheckingCompletion objects,
- // which may store references to already invoked requests. We should clear
- // these references to prevent them from being a leak source.
- if (WebTextCheckClient* text_checker_client = GetTextCheckerClient())
- text_checker_client->CancelAllPendingRequests();
}
void SpellCheckRequester::InvokeRequest(SpellCheckRequest* request) {
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
index c25947e0511..419b1d02523 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
@@ -97,6 +97,9 @@ class CORE_EXPORT SpellChecker final : public GarbageCollected<SpellChecker> {
//
// Hence allow the leak detector to effectively stop the spell checker to
// ensure leak reporting stability.
+ //
+ // TODO(xiaochengh): Now that there's no strong reference to SpellCheckRequest
+ // from outside Blink, this function may have become redundant. Investigate.
void PrepareForLeakDetection();
void DidAttachDocument(Document*);
diff --git a/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc b/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc
index 64fe6ae2a45..9f3c4eb386f 100644
--- a/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc
+++ b/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/editing/state_machines/state_machine_util.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/text/character.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
@@ -27,7 +28,7 @@ const uint32_t kIndicSyllabicCategoryViramaList[] = {
// Returns true if the code point has Indic_Syllabic_Category=Virama property.
// See http://www.unicode.org/Public/9.0.0/ucd/IndicSyllabicCategory-9.0.0d2.txt
bool IsIndicSyllabicCategoryVirama(uint32_t code_point) {
- const int length = arraysize(kIndicSyllabicCategoryViramaList);
+ const int length = base::size(kIndicSyllabicCategoryViramaList);
return std::binary_search(kIndicSyllabicCategoryViramaList,
kIndicSyllabicCategoryViramaList + length,
code_point);
diff --git a/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.h b/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.h
index c569e181737..4425482df1e 100644
--- a/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.h
+++ b/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.h
@@ -19,7 +19,7 @@ class HTMLElement;
// |SelectionSample| provides parsing HTML text with selection markers and
// serializes DOM tree with selection markers.
// Selection markers are represents by "^" for selection base and "|" for
-// selection extent like "assert_selection.js" in layout test.
+// selection extent like "assert_selection.js" in web test.
//
// To set selection at before children or after children instead of start or
// end of |Text| node, we should use selection marker only |Comment| node like:
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_position.cc b/chromium/third_party/blink/renderer/core/editing/visible_position.cc
index 71dab2ad3d9..eceeae9bccc 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_position.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_position.cc
@@ -31,10 +31,15 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
+#include "third_party/blink/renderer/core/editing/local_caret_rect.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
@@ -88,6 +93,50 @@ VisiblePositionTemplate<Strategy> VisiblePositionTemplate<Strategy>::Create(
if (position_with_affinity.Affinity() == TextAffinity::kDownstream)
return VisiblePositionTemplate<Strategy>(downstream_position);
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled()) {
+ // When not at a line wrap or bidi boundary, make sure to end up with
+ // |TextAffinity::Downstream| affinity.
+ const PositionWithAffinityTemplate<Strategy> upstream_position(
+ deep_position, TextAffinity::kUpstream);
+
+ if (!InSameLine(downstream_position, upstream_position))
+ return VisiblePositionTemplate<Strategy>(upstream_position);
+
+ if (!NGOffsetMapping::AcceptsPosition(ToPositionInDOMTree(deep_position))) {
+ // editing/selection/mixed-editability-10.html reaches here.
+ // We can't check bidi in such case. Use downstream as the default.
+ // TODO(xiaochengh): Investigate why we reach here and how to work around.
+ return VisiblePositionTemplate<Strategy>(downstream_position);
+ }
+
+ // Check if the position is at bidi boundary.
+ const LayoutObject* layout_object =
+ deep_position.AnchorNode()->GetLayoutObject();
+ DCHECK(layout_object) << position_with_affinity;
+ if (!layout_object->IsInline())
+ return VisiblePositionTemplate<Strategy>(downstream_position);
+ LayoutBlockFlow* const context =
+ NGOffsetMapping::GetInlineFormattingContextOf(*layout_object);
+ DCHECK(context);
+
+ // TODO(xiaochengh): The double pointer pattern below is confusing and
+ // cumbersome, but necessary for now. Make it easier.
+ std::unique_ptr<NGOffsetMapping> mapping_storage;
+ const NGOffsetMapping* mapping =
+ NGInlineNode::GetOffsetMapping(context, &mapping_storage);
+ DCHECK(mapping);
+
+ const base::Optional<unsigned> offset =
+ mapping->GetTextContentOffset(ToPositionInDOMTree(deep_position));
+ DCHECK(offset.has_value());
+
+ DCHECK(mapping->GetCaretNavigator());
+ const NGCaretNavigator& caret_navigator = *mapping->GetCaretNavigator();
+ if (caret_navigator.OffsetIsBidiBoundary(offset.value()))
+ return VisiblePositionTemplate<Strategy>(upstream_position);
+ return VisiblePositionTemplate<Strategy>(downstream_position);
+ }
+
// When not at a line wrap, make sure to end up with
// |TextAffinity::Downstream| affinity.
const PositionWithAffinityTemplate<Strategy> upstream_position(
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units.cc b/chromium/third_party/blink/renderer/core/editing/visible_units.cc
index debe9cadf33..525cb366c98 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units.cc
@@ -689,11 +689,11 @@ static PositionTemplate<Strategy> MostBackwardCaretPosition(
continue;
const unsigned text_start_offset = text_layout_object->TextStartOffset();
if (current_node != start_node) {
- // This assertion fires in layout tests in the case-transform.html test
+ // This assertion fires in web tests in the case-transform.html test
// because of a mix-up between offsets in the text in the DOM tree with
// text in the layout tree which can have a different length due to case
// transformation.
- // Until we resolve that, disable this so we can run the layout tests!
+ // Until we resolve that, disable this so we can run the web tests!
// DCHECK_GE(currentOffset, layoutObject->caretMaxOffset());
return PositionTemplate<Strategy>(
current_node, layout_object->CaretMaxOffset() + text_start_offset);
@@ -936,7 +936,8 @@ static bool IsVisuallyEquivalentCandidateAlgorithm(
if (!layout_object->IsSelectable())
return false;
- if (layout_object->IsLayoutBlockFlow() || layout_object->IsFlexibleBox() ||
+ if (layout_object->IsLayoutBlockFlow() ||
+ layout_object->IsFlexibleBoxIncludingNG() ||
layout_object->IsLayoutGrid()) {
if (ToLayoutBlock(layout_object)->LogicalHeight() ||
anchor_node->GetDocument().body() == anchor_node) {
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc
index 90c566c30a0..84bb55bec37 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc
@@ -153,11 +153,12 @@ Node* PreviousLeafWithSameEditability(const Node& node,
return nullptr;
}
-Node* NextLeafWithSameEditability(Node* node, EditableType editable_type) {
+Node* NextLeafWithGivenEditability(Node* node,
+ EditableType editable_type,
+ bool editable) {
if (!node)
return nullptr;
- const bool editable = HasEditableStyle(*node, editable_type);
for (Node* runner = NextAtomicLeafNode(*node); runner;
runner = NextAtomicLeafNode(*runner)) {
if (editable == HasEditableStyle(*runner, editable_type))
@@ -338,12 +339,20 @@ Position NextRootInlineBoxCandidatePosition(
DCHECK(visible_position.IsValid()) << visible_position;
ContainerNode* highest_root =
HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
- Node* next_node = NextLeafWithSameEditability(node, editable_type);
- while (next_node && InSameLine(*next_node, visible_position))
- next_node = NextLeafWithSameEditability(next_node, kContentIsEditable);
+ // TODO(xiaochengh): We probably also need to pass in the starting editability
+ // to |PreviousLeafWithSameEditability|.
+ const bool is_editable = HasEditableStyle(
+ *visible_position.DeepEquivalent().ComputeContainerNode(), editable_type);
+ Node* next_node =
+ NextLeafWithGivenEditability(node, editable_type, is_editable);
+ while (next_node && InSameLine(*next_node, visible_position)) {
+ next_node = NextLeafWithGivenEditability(next_node, kContentIsEditable,
+ is_editable);
+ }
for (Node* runner = next_node; runner && !runner->IsShadowRoot();
- runner = NextLeafWithSameEditability(runner, editable_type)) {
+ runner =
+ NextLeafWithGivenEditability(runner, editable_type, is_editable)) {
if (HighestEditableRootOfNode(*runner, editable_type) != highest_root)
break;
diff --git a/chromium/third_party/blink/renderer/core/events/BUILD.gn b/chromium/third_party/blink/renderer/core/events/BUILD.gn
index f7facc6bd6a..b6f51c73afe 100644
--- a/chromium/third_party/blink/renderer/core/events/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/events/BUILD.gn
@@ -6,12 +6,14 @@ import("//third_party/blink/renderer/core/core.gni")
blink_core_sources("events") {
sources = [
+ "after_print_event.h",
"animation_event.cc",
"animation_event.h",
"animation_playback_event.cc",
"animation_playback_event.h",
"application_cache_error_event.cc",
"application_cache_error_event.h",
+ "before_print_event.h",
"before_text_inserted_event.cc",
"before_text_inserted_event.h",
"before_unload_event.cc",
@@ -46,6 +48,8 @@ blink_core_sources("events") {
"mutation_event.h",
"navigator_events.cc",
"navigator_events.h",
+ "overscroll_event.cc",
+ "overscroll_event.h",
"page_transition_event.cc",
"page_transition_event.h",
"picture_in_picture_control_event.cc",
@@ -56,6 +60,8 @@ blink_core_sources("events") {
"pointer_event_factory.h",
"pop_state_event.cc",
"pop_state_event.h",
+ "portal_activate_event.cc",
+ "portal_activate_event.h",
"progress_event.cc",
"progress_event.h",
"promise_rejection_event.cc",
diff --git a/chromium/third_party/blink/renderer/core/events/after_print_event.h b/chromium/third_party/blink/renderer/core/events/after_print_event.h
new file mode 100644
index 00000000000..5fad32c6555
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/after_print_event.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_AFTER_PRINT_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_AFTER_PRINT_EVENT_H_
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
+
+namespace blink {
+
+class AfterPrintEvent final : public Event {
+ public:
+ static AfterPrintEvent* Create() {
+ return MakeGarbageCollected<AfterPrintEvent>();
+ }
+
+ AfterPrintEvent()
+ : Event(event_type_names::kAfterprint, Bubbles::kNo, Cancelable::kNo) {}
+ ~AfterPrintEvent() override = default;
+
+ // beforeprint/afterprint events need to be dispatched while the execution
+ // context is paused. When printing, window.print() invoked by beforeprint/
+ // afterprint event listeners should have no effect, hence the event dispatch
+ // needs to be done during the pause.
+ bool ShouldDispatchEvenWhenExecutionContextIsPaused() const override {
+ return true;
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_AFTER_PRINT_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/core/events/animation_event.h b/chromium/third_party/blink/renderer/core/events/animation_event.h
index 199d47f182a..9f468caeccf 100644
--- a/chromium/third_party/blink/renderer/core/events/animation_event.h
+++ b/chromium/third_party/blink/renderer/core/events/animation_event.h
@@ -35,19 +35,27 @@ class AnimationEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
- static AnimationEvent* Create() { return new AnimationEvent; }
+ static AnimationEvent* Create() {
+ return (MakeGarbageCollected<AnimationEvent>());
+ }
static AnimationEvent* Create(const AtomicString& type,
const String& animation_name,
double elapsed_time,
const String& pseudo_element) {
- return new AnimationEvent(type, animation_name, elapsed_time,
- pseudo_element);
+ return MakeGarbageCollected<AnimationEvent>(type, animation_name,
+ elapsed_time, pseudo_element);
}
static AnimationEvent* Create(const AtomicString& type,
const AnimationEventInit* initializer) {
- return new AnimationEvent(type, initializer);
+ return MakeGarbageCollected<AnimationEvent>(type, initializer);
}
+ AnimationEvent();
+ AnimationEvent(const AtomicString& type,
+ const String& animation_name,
+ double elapsed_time,
+ const String& pseudo_element);
+ AnimationEvent(const AtomicString&, const AnimationEventInit*);
~AnimationEvent() override;
const String& animationName() const;
@@ -59,13 +67,6 @@ class AnimationEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- AnimationEvent();
- AnimationEvent(const AtomicString& type,
- const String& animation_name,
- double elapsed_time,
- const String& pseudo_element);
- AnimationEvent(const AtomicString&, const AnimationEventInit*);
-
String animation_name_;
double elapsed_time_;
String pseudo_element_;
diff --git a/chromium/third_party/blink/renderer/core/events/animation_playback_event.h b/chromium/third_party/blink/renderer/core/events/animation_playback_event.h
index ed953d6998b..c69886eedb8 100644
--- a/chromium/third_party/blink/renderer/core/events/animation_playback_event.h
+++ b/chromium/third_party/blink/renderer/core/events/animation_playback_event.h
@@ -18,14 +18,20 @@ class AnimationPlaybackEvent final : public Event {
static AnimationPlaybackEvent* Create(const AtomicString& type,
double current_time,
double timeline_time) {
- return new AnimationPlaybackEvent(type, current_time, timeline_time);
+ return MakeGarbageCollected<AnimationPlaybackEvent>(type, current_time,
+ timeline_time);
}
static AnimationPlaybackEvent* Create(
const AtomicString& type,
const AnimationPlaybackEventInit* initializer) {
- return new AnimationPlaybackEvent(type, initializer);
+ return MakeGarbageCollected<AnimationPlaybackEvent>(type, initializer);
}
+ AnimationPlaybackEvent(const AtomicString& type,
+ double current_time,
+ double timeline_time);
+ AnimationPlaybackEvent(const AtomicString&,
+ const AnimationPlaybackEventInit*);
~AnimationPlaybackEvent() override;
double currentTime(bool& is_null) const;
@@ -36,12 +42,6 @@ class AnimationPlaybackEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- AnimationPlaybackEvent(const AtomicString& type,
- double current_time,
- double timeline_time);
- AnimationPlaybackEvent(const AtomicString&,
- const AnimationPlaybackEventInit*);
-
base::Optional<double> current_time_;
base::Optional<double> timeline_time_;
};
diff --git a/chromium/third_party/blink/renderer/core/events/application_cache_error_event.cc b/chromium/third_party/blink/renderer/core/events/application_cache_error_event.cc
index 561ed3ace45..545095351ca 100644
--- a/chromium/third_party/blink/renderer/core/events/application_cache_error_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/application_cache_error_event.cc
@@ -4,12 +4,12 @@
#include "third_party/blink/renderer/core/events/application_cache_error_event.h"
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
#include "third_party/blink/renderer/core/event_type_names.h"
namespace blink {
-static const String& ErrorReasonToString(
- WebApplicationCacheHost::ErrorReason reason) {
+static const String& ErrorReasonToString(mojom::AppCacheErrorReason reason) {
DEFINE_STATIC_LOCAL(String, error_manifest, ("manifest"));
DEFINE_STATIC_LOCAL(String, error_signature, ("signature"));
DEFINE_STATIC_LOCAL(String, error_resource, ("resource"));
@@ -20,21 +20,21 @@ static const String& ErrorReasonToString(
DEFINE_STATIC_LOCAL(String, error_unknown, ("unknown"));
switch (reason) {
- case WebApplicationCacheHost::kManifestError:
+ case mojom::AppCacheErrorReason::APPCACHE_MANIFEST_ERROR:
return error_manifest;
- case WebApplicationCacheHost::kSignatureError:
+ case mojom::AppCacheErrorReason::APPCACHE_SIGNATURE_ERROR:
return error_signature;
- case WebApplicationCacheHost::kResourceError:
+ case mojom::AppCacheErrorReason::APPCACHE_RESOURCE_ERROR:
return error_resource;
- case WebApplicationCacheHost::kChangedError:
+ case mojom::AppCacheErrorReason::APPCACHE_CHANGED_ERROR:
return error_changed;
- case WebApplicationCacheHost::kAbortError:
+ case mojom::AppCacheErrorReason::APPCACHE_ABORT_ERROR:
return error_abort;
- case WebApplicationCacheHost::kQuotaError:
+ case mojom::AppCacheErrorReason::APPCACHE_QUOTA_ERROR:
return error_quota;
- case WebApplicationCacheHost::kPolicyError:
+ case mojom::AppCacheErrorReason::APPCACHE_POLICY_ERROR:
return error_policy;
- case WebApplicationCacheHost::kUnknownError:
+ case mojom::AppCacheErrorReason::APPCACHE_UNKNOWN_ERROR:
return error_unknown;
}
NOTREACHED();
@@ -42,7 +42,7 @@ static const String& ErrorReasonToString(
}
ApplicationCacheErrorEvent::ApplicationCacheErrorEvent(
- WebApplicationCacheHost::ErrorReason reason,
+ mojom::AppCacheErrorReason reason,
const String& url,
int status,
const String& message)
diff --git a/chromium/third_party/blink/renderer/core/events/application_cache_error_event.h b/chromium/third_party/blink/renderer/core/events/application_cache_error_event.h
index c4822d2dfc1..a36022cabfc 100644
--- a/chromium/third_party/blink/renderer/core/events/application_cache_error_event.h
+++ b/chromium/third_party/blink/renderer/core/events/application_cache_error_event.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_APPLICATION_CACHE_ERROR_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_APPLICATION_CACHE_ERROR_EVENT_H_
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
#include "third_party/blink/public/platform/web_application_cache_host_client.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/event_interface_names.h"
@@ -17,20 +18,27 @@ class ApplicationCacheErrorEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
+ ApplicationCacheErrorEvent(mojom::AppCacheErrorReason,
+ const String& url,
+ int status,
+ const String& message);
+ ApplicationCacheErrorEvent(const AtomicString& event_type,
+ const ApplicationCacheErrorEventInit* initializer);
~ApplicationCacheErrorEvent() override;
- static ApplicationCacheErrorEvent* Create(
- WebApplicationCacheHost::ErrorReason reason,
- const String& url,
- int status,
- const String& message) {
- return new ApplicationCacheErrorEvent(reason, url, status, message);
+ static ApplicationCacheErrorEvent* Create(mojom::AppCacheErrorReason reason,
+ const String& url,
+ int status,
+ const String& message) {
+ return MakeGarbageCollected<ApplicationCacheErrorEvent>(reason, url, status,
+ message);
}
static ApplicationCacheErrorEvent* Create(
const AtomicString& event_type,
const ApplicationCacheErrorEventInit* initializer) {
- return new ApplicationCacheErrorEvent(event_type, initializer);
+ return MakeGarbageCollected<ApplicationCacheErrorEvent>(event_type,
+ initializer);
}
const String& reason() const { return reason_; }
@@ -45,13 +53,6 @@ class ApplicationCacheErrorEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- ApplicationCacheErrorEvent(WebApplicationCacheHost::ErrorReason,
- const String& url,
- int status,
- const String& message);
- ApplicationCacheErrorEvent(const AtomicString& event_type,
- const ApplicationCacheErrorEventInit* initializer);
-
String reason_;
String url_;
int status_;
diff --git a/chromium/third_party/blink/renderer/core/events/before_print_event.h b/chromium/third_party/blink/renderer/core/events/before_print_event.h
new file mode 100644
index 00000000000..20b02b73593
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/before_print_event.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_BEFORE_PRINT_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_BEFORE_PRINT_EVENT_H_
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
+
+namespace blink {
+
+class BeforePrintEvent final : public Event {
+ public:
+ static BeforePrintEvent* Create() {
+ return MakeGarbageCollected<BeforePrintEvent>();
+ }
+
+ BeforePrintEvent()
+ : Event(event_type_names::kBeforeprint, Bubbles::kNo, Cancelable::kNo) {}
+ ~BeforePrintEvent() override = default;
+
+ // beforeprint/afterprint events need to be dispatched while the execution
+ // context is paused. When printing, window.print() invoked by beforeprint/
+ // afterprint event listeners should have no effect, hence the event dispatch
+ // needs to be done during the pause.
+ bool ShouldDispatchEvenWhenExecutionContextIsPaused() const override {
+ return true;
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_BEFORE_PRINT_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/core/events/before_text_inserted_event.h b/chromium/third_party/blink/renderer/core/events/before_text_inserted_event.h
index 13a5d2628c6..d593f9e9946 100644
--- a/chromium/third_party/blink/renderer/core/events/before_text_inserted_event.h
+++ b/chromium/third_party/blink/renderer/core/events/before_text_inserted_event.h
@@ -32,10 +32,11 @@ namespace blink {
class BeforeTextInsertedEvent final : public Event {
public:
+ explicit BeforeTextInsertedEvent(const String&);
~BeforeTextInsertedEvent() override;
static BeforeTextInsertedEvent* Create(const String& text) {
- return new BeforeTextInsertedEvent(text);
+ return MakeGarbageCollected<BeforeTextInsertedEvent>(text);
}
const AtomicString& InterfaceName() const override;
@@ -47,8 +48,6 @@ class BeforeTextInsertedEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- explicit BeforeTextInsertedEvent(const String&);
-
String text_;
};
diff --git a/chromium/third_party/blink/renderer/core/events/before_unload_event.h b/chromium/third_party/blink/renderer/core/events/before_unload_event.h
index 6d735418639..2782808c164 100644
--- a/chromium/third_party/blink/renderer/core/events/before_unload_event.h
+++ b/chromium/third_party/blink/renderer/core/events/before_unload_event.h
@@ -34,9 +34,12 @@ class BeforeUnloadEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
+ BeforeUnloadEvent();
~BeforeUnloadEvent() override;
- static BeforeUnloadEvent* Create() { return new BeforeUnloadEvent; }
+ static BeforeUnloadEvent* Create() {
+ return MakeGarbageCollected<BeforeUnloadEvent>();
+ }
bool IsBeforeUnloadEvent() const override;
@@ -49,11 +52,16 @@ class BeforeUnloadEvent final : public Event {
return event_interface_names::kBeforeUnloadEvent;
}
+ // A confirmation dialog for leaving a page is expected to be shown
+ // regardless of the state of the page. So, beforeunload's event
+ // listeners should always run regardless of pause.
+ bool ShouldDispatchEvenWhenExecutionContextIsPaused() const override {
+ return true;
+ }
+
void Trace(blink::Visitor*) override;
private:
- BeforeUnloadEvent();
-
String return_value_;
};
diff --git a/chromium/third_party/blink/renderer/core/events/clipboard_event.h b/chromium/third_party/blink/renderer/core/events/clipboard_event.h
index a0a8afbf758..a0f55a6099c 100644
--- a/chromium/third_party/blink/renderer/core/events/clipboard_event.h
+++ b/chromium/third_party/blink/renderer/core/events/clipboard_event.h
@@ -35,16 +35,18 @@ class ClipboardEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
+ ClipboardEvent(const AtomicString& type, DataTransfer* clipboard_data);
+ ClipboardEvent(const AtomicString& type, const ClipboardEventInit*);
~ClipboardEvent() override;
static ClipboardEvent* Create(const AtomicString& type,
DataTransfer* data_transfer) {
- return new ClipboardEvent(type, data_transfer);
+ return MakeGarbageCollected<ClipboardEvent>(type, data_transfer);
}
static ClipboardEvent* Create(const AtomicString& type,
const ClipboardEventInit* initializer) {
- return new ClipboardEvent(type, initializer);
+ return MakeGarbageCollected<ClipboardEvent>(type, initializer);
}
DataTransfer* clipboardData() const { return clipboard_data_.Get(); }
@@ -52,10 +54,6 @@ class ClipboardEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- ClipboardEvent(const AtomicString& type,
- DataTransfer* clipboard_data);
- ClipboardEvent(const AtomicString& type, const ClipboardEventInit*);
-
const AtomicString& InterfaceName() const override;
bool IsClipboardEvent() const override;
diff --git a/chromium/third_party/blink/renderer/core/events/composition_event.h b/chromium/third_party/blink/renderer/core/events/composition_event.h
index 6588fe28977..ec3bc420141 100644
--- a/chromium/third_party/blink/renderer/core/events/composition_event.h
+++ b/chromium/third_party/blink/renderer/core/events/composition_event.h
@@ -36,19 +36,24 @@ class CompositionEvent final : public UIEvent {
DEFINE_WRAPPERTYPEINFO();
public:
- static CompositionEvent* Create() { return new CompositionEvent; }
+ static CompositionEvent* Create() {
+ return MakeGarbageCollected<CompositionEvent>();
+ }
static CompositionEvent* Create(const AtomicString& type,
AbstractView* view,
const String& data) {
- return new CompositionEvent(type, view, data);
+ return MakeGarbageCollected<CompositionEvent>(type, view, data);
}
static CompositionEvent* Create(const AtomicString& type,
const CompositionEventInit* initializer) {
- return new CompositionEvent(type, initializer);
+ return MakeGarbageCollected<CompositionEvent>(type, initializer);
}
+ CompositionEvent();
+ CompositionEvent(const AtomicString& type, AbstractView*, const String&);
+ CompositionEvent(const AtomicString& type, const CompositionEventInit*);
~CompositionEvent() override;
void initCompositionEvent(const AtomicString& type,
@@ -66,10 +71,6 @@ class CompositionEvent final : public UIEvent {
void Trace(blink::Visitor*) override;
private:
- CompositionEvent();
- CompositionEvent(const AtomicString& type, AbstractView*, const String&);
- CompositionEvent(const AtomicString& type, const CompositionEventInit*);
-
String data_;
};
diff --git a/chromium/third_party/blink/renderer/core/events/composition_event.idl b/chromium/third_party/blink/renderer/core/events/composition_event.idl
index 891ba598387..fd8a17947b0 100644
--- a/chromium/third_party/blink/renderer/core/events/composition_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/composition_event.idl
@@ -34,9 +34,9 @@
// https://w3c.github.io/uievents/#idl-interface-CompositionEvent-initializers
// TODO(foolip): None of the initCompositionEvent() arguments should be
// optional, and the spec has a locale argument after data.
- [Measure] void initCompositionEvent([Default=Undefined] optional DOMString type,
- [Default=Undefined] optional boolean bubbles,
- [Default=Undefined] optional boolean cancelable,
- [Default=Undefined] optional Window? view,
- [Default=Undefined] optional DOMString data);
+ [Measure] void initCompositionEvent([DefaultValue=Undefined] optional DOMString type,
+ [DefaultValue=Undefined] optional boolean bubbles,
+ [DefaultValue=Undefined] optional boolean cancelable,
+ [DefaultValue=Undefined] optional Window? view,
+ [DefaultValue=Undefined] optional DOMString data);
};
diff --git a/chromium/third_party/blink/renderer/core/events/error_event.idl b/chromium/third_party/blink/renderer/core/events/error_event.idl
index d6298b109c8..89d3b0cde09 100644
--- a/chromium/third_party/blink/renderer/core/events/error_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/error_event.idl
@@ -32,8 +32,8 @@
[
Constructor(DOMString type, optional ErrorEventInit eventInitDict),
- ConstructorCallWith=ScriptState
- // TODO(foolip): Exposed=(Window,Worker)
+ ConstructorCallWith=ScriptState,
+ Exposed=(Window,Worker)
] interface ErrorEvent : Event {
readonly attribute DOMString message;
readonly attribute DOMString filename;
diff --git a/chromium/third_party/blink/renderer/core/events/event_type_names.json5 b/chromium/third_party/blink/renderer/core/events/event_type_names.json5
index 7ccc7fe8402..dcf0c8b722c 100644
--- a/chromium/third_party/blink/renderer/core/events/event_type_names.json5
+++ b/chromium/third_party/blink/renderer/core/events/event_type_names.json5
@@ -30,6 +30,7 @@
"addsourcebuffer",
"addstream",
"addtrack",
+ "advertisementreceived",
"afterprint",
"animationend",
"animationiteration",
@@ -105,6 +106,7 @@
"dragstart",
"drop",
"durationchange",
+ "elementtimingbufferfull",
"emptied",
"encrypted",
"end",
@@ -191,6 +193,7 @@
"online",
"open",
"orientationchange",
+ "overscroll",
"pagehide",
"pageshow",
"paste",
@@ -214,6 +217,7 @@
"pointerrawmove",
"pointerup",
"popstate",
+ "portalactivate",
"progress",
"processorerror",
"push",
@@ -233,6 +237,7 @@
"result",
"resume",
"scroll",
+ "scrollend",
"search",
"securitypolicyviolation",
"seeked",
diff --git a/chromium/third_party/blink/renderer/core/events/input_event.cc b/chromium/third_party/blink/renderer/core/events/input_event.cc
index 26f60649ea8..9b4eb5304bd 100644
--- a/chromium/third_party/blink/renderer/core/events/input_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/input_event.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/events/input_event.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/web_editing_command_type.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
#include "third_party/blink/renderer/core/dom/range.h"
@@ -59,7 +60,7 @@ const struct {
};
static_assert(
- arraysize(kInputTypeStringNameMap) ==
+ base::size(kInputTypeStringNameMap) ==
static_cast<size_t>(InputEvent::InputType::kNumberOfInputTypes),
"must handle all InputEvent::InputType");
diff --git a/chromium/third_party/blink/renderer/core/events/message_event.idl b/chromium/third_party/blink/renderer/core/events/message_event.idl
index 317eda18574..250ed2ce591 100644
--- a/chromium/third_party/blink/renderer/core/events/message_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/message_event.idl
@@ -40,14 +40,14 @@
[CachedAttribute=isPortsDirty] readonly attribute FrozenArray<MessagePort> ports;
[RuntimeEnabled=UserActivationAPI] readonly attribute UserActivation? userActivation;
- // TODO(foolip): none of the arguments should have [Default=Undefined] (they
+ // TODO(foolip): none of the arguments should have [DefaultValue=Undefined] (they
// have other default values in the spec) and |sourceArg|'s type is wrong.
[Custom, MeasureAs=InitMessageEvent] void initMessageEvent(DOMString typeArg,
- [Default=Undefined] optional boolean canBubbleArg,
- [Default=Undefined] optional boolean cancelableArg,
- [Default=Undefined] optional any dataArg,
- [Default=Undefined] optional DOMString originArg,
- [Default=Undefined] optional DOMString lastEventIdArg,
- [Default=Undefined] optional EventTarget sourceArg,
- [Default=Undefined] optional sequence<MessagePort> portsArg);
+ [DefaultValue=Undefined] optional boolean canBubbleArg,
+ [DefaultValue=Undefined] optional boolean cancelableArg,
+ [DefaultValue=Undefined] optional any dataArg,
+ [DefaultValue=Undefined] optional DOMString originArg,
+ [DefaultValue=Undefined] optional DOMString lastEventIdArg,
+ [DefaultValue=Undefined] optional EventTarget sourceArg,
+ [DefaultValue=Undefined] optional sequence<MessagePort> portsArg);
};
diff --git a/chromium/third_party/blink/renderer/core/events/mouse_event.idl b/chromium/third_party/blink/renderer/core/events/mouse_event.idl
index 8dc2e487a73..3135644e421 100644
--- a/chromium/third_party/blink/renderer/core/events/mouse_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/mouse_event.idl
@@ -39,21 +39,21 @@
// https://w3c.github.io/uievents/#idl-interface-MouseEvent-initializers
// TODO(foolip): None of the initMouseEvent() arguments should be optional.
- [CallWith=ScriptState, Measure] void initMouseEvent([Default=Undefined] optional DOMString type,
- [Default=Undefined] optional boolean bubbles,
- [Default=Undefined] optional boolean cancelable,
- [Default=Undefined] optional Window? view,
- [Default=Undefined] optional long detail,
- [Default=Undefined] optional long screenX,
- [Default=Undefined] optional long screenY,
- [Default=Undefined] optional long clientX,
- [Default=Undefined] optional long clientY,
- [Default=Undefined] optional boolean ctrlKey,
- [Default=Undefined] optional boolean altKey,
- [Default=Undefined] optional boolean shiftKey,
- [Default=Undefined] optional boolean metaKey,
- [Default=Undefined] optional unsigned short button,
- [Default=Undefined] optional EventTarget? relatedTarget);
+ [CallWith=ScriptState, Measure] void initMouseEvent([DefaultValue=Undefined] optional DOMString type,
+ [DefaultValue=Undefined] optional boolean bubbles,
+ [DefaultValue=Undefined] optional boolean cancelable,
+ [DefaultValue=Undefined] optional Window? view,
+ [DefaultValue=Undefined] optional long detail,
+ [DefaultValue=Undefined] optional long screenX,
+ [DefaultValue=Undefined] optional long screenY,
+ [DefaultValue=Undefined] optional long clientX,
+ [DefaultValue=Undefined] optional long clientY,
+ [DefaultValue=Undefined] optional boolean ctrlKey,
+ [DefaultValue=Undefined] optional boolean altKey,
+ [DefaultValue=Undefined] optional boolean shiftKey,
+ [DefaultValue=Undefined] optional boolean metaKey,
+ [DefaultValue=Undefined] optional unsigned short button,
+ [DefaultValue=Undefined] optional EventTarget? relatedTarget);
readonly attribute double pageX;
readonly attribute double pageY;
diff --git a/chromium/third_party/blink/renderer/core/events/mutation_event.idl b/chromium/third_party/blink/renderer/core/events/mutation_event.idl
index c377ae55fd9..562049599e0 100644
--- a/chromium/third_party/blink/renderer/core/events/mutation_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/mutation_event.idl
@@ -31,12 +31,12 @@ interface MutationEvent : Event {
readonly attribute DOMString attrName;
readonly attribute unsigned short attrChange;
// TODO(foolip): None of the initMutationEvent() arguments should be optional.
- [Measure] void initMutationEvent([Default=Undefined] optional DOMString type,
- [Default=Undefined] optional boolean bubbles,
- [Default=Undefined] optional boolean cancelable,
- [Default=Undefined] optional Node? relatedNode,
- [Default=Undefined] optional DOMString prevValue,
- [Default=Undefined] optional DOMString newValue,
- [Default=Undefined] optional DOMString attrName,
- [Default=Undefined] optional unsigned short attrChange);
+ [Measure] void initMutationEvent([DefaultValue=Undefined] optional DOMString type,
+ [DefaultValue=Undefined] optional boolean bubbles,
+ [DefaultValue=Undefined] optional boolean cancelable,
+ [DefaultValue=Undefined] optional Node? relatedNode,
+ [DefaultValue=Undefined] optional DOMString prevValue,
+ [DefaultValue=Undefined] optional DOMString newValue,
+ [DefaultValue=Undefined] optional DOMString attrName,
+ [DefaultValue=Undefined] optional unsigned short attrChange);
};
diff --git a/chromium/third_party/blink/renderer/core/events/navigator_events.idl b/chromium/third_party/blink/renderer/core/events/navigator_events.idl
index 0bc89e285f8..da8d0e7af72 100644
--- a/chromium/third_party/blink/renderer/core/events/navigator_events.idl
+++ b/chromium/third_party/blink/renderer/core/events/navigator_events.idl
@@ -33,5 +33,5 @@
[
ImplementedAs=NavigatorEvents
] partial interface Navigator {
- readonly attribute long maxTouchPoints;
+ [HighEntropy, MeasureAs=NavigatorMaxTouchPoints] readonly attribute long maxTouchPoints;
};
diff --git a/chromium/third_party/blink/renderer/core/events/overscroll_event.cc b/chromium/third_party/blink/renderer/core/events/overscroll_event.cc
new file mode 100644
index 00000000000..d171cb08091
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/overscroll_event.cc
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/events/overscroll_event.h"
+
+namespace blink {
+OverscrollEvent::OverscrollEvent(const AtomicString& type,
+ double delta_x,
+ double delta_y)
+ : Event(type, Bubbles::kNo, Cancelable::kNo),
+ delta_x_(delta_x),
+ delta_y_(delta_y) {}
+
+OverscrollEvent::OverscrollEvent(const AtomicString& type,
+ const OverscrollEventInit* initializer)
+ : Event(type, Bubbles::kNo, Cancelable::kNo),
+ delta_x_(initializer->deltaX()),
+ delta_y_(initializer->deltaY()) {}
+
+void OverscrollEvent::Trace(blink::Visitor* visitor) {
+ Event::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/events/overscroll_event.h b/chromium/third_party/blink/renderer/core/events/overscroll_event.h
new file mode 100644
index 00000000000..ab7cffe0ab6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/overscroll_event.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_OVERSCROLL_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_OVERSCROLL_EVENT_H_
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/events/overscroll_event_init.h"
+
+namespace blink {
+
+class OverscrollEvent final : public Event {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static OverscrollEvent* Create(const AtomicString& type,
+ double delta_x,
+ double delta_y) {
+ return MakeGarbageCollected<OverscrollEvent>(type, delta_x, delta_y);
+ }
+ static OverscrollEvent* Create(const AtomicString& type,
+ const OverscrollEventInit* initializer) {
+ return MakeGarbageCollected<OverscrollEvent>(type, initializer);
+ }
+
+ OverscrollEvent(const AtomicString&, double delta_x, double delta_y);
+ OverscrollEvent(const AtomicString&, const OverscrollEventInit*);
+
+ double deltaX() const { return delta_x_; }
+ double deltaY() const { return delta_y_; }
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ double delta_x_ = 0;
+ double delta_y_ = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_OVERSCROLL_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/core/events/overscroll_event.idl b/chromium/third_party/blink/renderer/core/events/overscroll_event.idl
new file mode 100644
index 00000000000..a29ed0f7b85
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/overscroll_event.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// TODO(sahel): Add link to w3c. https://crbugs.com/907601
+
+[
+ Constructor(DOMString type, optional OverscrollEventInit eventInitDict),
+ RuntimeEnabled=OverscrollCustomization
+] interface OverscrollEvent : Event {
+ readonly attribute double deltaX;
+ readonly attribute double deltaY;
+};
diff --git a/chromium/third_party/blink/renderer/core/events/overscroll_event_init.idl b/chromium/third_party/blink/renderer/core/events/overscroll_event_init.idl
new file mode 100644
index 00000000000..6d9e286b916
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/overscroll_event_init.idl
@@ -0,0 +1,10 @@
+// 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.
+
+// TODO(sahel): Add link to w3c. https://crbugs.com/907601
+
+dictionary OverscrollEventInit : EventInit {
+ double deltaX = 0.0;
+ double deltaY = 0.0;
+};
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event.h b/chromium/third_party/blink/renderer/core/events/pointer_event.h
index 22626408581..8b90668588b 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event.h
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event.h
@@ -29,7 +29,7 @@ class CORE_EXPORT PointerEvent final : public MouseEvent {
const PointerEventInit*,
TimeTicks platform_time_stamp);
- int32_t pointerId() const { return pointer_id_; }
+ PointerId pointerId() const { return pointer_id_; }
double width() const { return width_; }
double height() const { return height_; }
float pressure() const { return pressure_; }
@@ -70,7 +70,7 @@ class CORE_EXPORT PointerEvent final : public MouseEvent {
void Trace(blink::Visitor*) override;
private:
- int32_t pointer_id_;
+ PointerId pointer_id_;
double width_;
double height_;
float pressure_;
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event_factory.cc b/chromium/third_party/blink/renderer/core/events/pointer_event_factory.cc
index 7b57f3554c0..12d5f4503fc 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event_factory.cc
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event_factory.cc
@@ -181,10 +181,10 @@ HeapVector<Member<PointerEvent>> PointerEventFactory::CreateEventSequence(
return result;
}
-const int PointerEventFactory::kInvalidId = 0;
+const PointerId PointerEventFactory::kInvalidId = 0;
// Mouse id is 1 to behave the same as MS Edge for compatibility reasons.
-const int PointerEventFactory::kMouseId = 1;
+const PointerId PointerEventFactory::kMouseId = 1;
PointerEventInit* PointerEventFactory::ConvertIdTypeButtonsEvent(
const WebPointerEvent& web_pointer_event) {
@@ -220,8 +220,8 @@ PointerEventInit* PointerEventFactory::ConvertIdTypeButtonsEvent(
pointer_event_init->setButtons(buttons);
const IncomingId incoming_id(pointer_type, web_pointer_event.id);
- int pointer_id = AddIdAndActiveButtons(incoming_id, buttons != 0,
- web_pointer_event.hovering);
+ PointerId pointer_id = AddIdAndActiveButtons(incoming_id, buttons != 0,
+ web_pointer_event.hovering);
pointer_event_init->setPointerId(pointer_id);
pointer_event_init->setPointerType(
PointerTypeNameForWebPointPointerType(pointer_type));
@@ -460,9 +460,9 @@ void PointerEventFactory::Clear() {
current_id_ = PointerEventFactory::kMouseId + 1;
}
-int PointerEventFactory::AddIdAndActiveButtons(const IncomingId p,
- bool is_active_buttons,
- bool hovering) {
+PointerId PointerEventFactory::AddIdAndActiveButtons(const IncomingId p,
+ bool is_active_buttons,
+ bool hovering) {
// Do not add extra mouse pointer as it was added in initialization
if (p.GetPointerType() == WebPointerProperties::PointerType::kMouse) {
pointer_id_mapping_.Set(kMouseId,
@@ -471,14 +471,14 @@ int PointerEventFactory::AddIdAndActiveButtons(const IncomingId p,
}
if (pointer_incoming_id_mapping_.Contains(p)) {
- int mapped_id = pointer_incoming_id_mapping_.at(p);
+ PointerId mapped_id = pointer_incoming_id_mapping_.at(p);
pointer_id_mapping_.Set(mapped_id,
PointerAttributes(p, is_active_buttons, hovering));
return mapped_id;
}
int type_int = p.PointerTypeInt();
// We do not handle the overflow of m_currentId as it should be very rare
- int mapped_id = current_id_++;
+ PointerId mapped_id = current_id_++;
if (!id_count_[type_int])
primary_id_[type_int] = mapped_id;
id_count_[type_int]++;
@@ -488,7 +488,7 @@ int PointerEventFactory::AddIdAndActiveButtons(const IncomingId p,
return mapped_id;
}
-bool PointerEventFactory::Remove(const int mapped_id) {
+bool PointerEventFactory::Remove(const PointerId mapped_id) {
// Do not remove mouse pointer id as it should always be there
if (mapped_id == kMouseId || !pointer_id_mapping_.Contains(mapped_id))
return false;
@@ -504,12 +504,13 @@ bool PointerEventFactory::Remove(const int mapped_id) {
return true;
}
-Vector<int> PointerEventFactory::GetPointerIdsOfNonHoveringPointers() const {
- Vector<int> mapped_ids;
+Vector<PointerId> PointerEventFactory::GetPointerIdsOfNonHoveringPointers()
+ const {
+ Vector<PointerId> mapped_ids;
for (auto iter = pointer_id_mapping_.begin();
iter != pointer_id_mapping_.end(); ++iter) {
- int mapped_id = iter->key;
+ PointerId mapped_id = iter->key;
if (!iter->value.hovering)
mapped_ids.push_back(mapped_id);
}
@@ -519,7 +520,7 @@ Vector<int> PointerEventFactory::GetPointerIdsOfNonHoveringPointers() const {
return mapped_ids;
}
-bool PointerEventFactory::IsPrimary(int mapped_id) const {
+bool PointerEventFactory::IsPrimary(PointerId mapped_id) const {
if (!pointer_id_mapping_.Contains(mapped_id))
return false;
@@ -527,7 +528,7 @@ bool PointerEventFactory::IsPrimary(int mapped_id) const {
return primary_id_[p.PointerTypeInt()] == mapped_id;
}
-bool PointerEventFactory::IsActive(const int pointer_id) const {
+bool PointerEventFactory::IsActive(const PointerId pointer_id) const {
return pointer_id_mapping_.Contains(pointer_id);
}
@@ -542,24 +543,25 @@ bool PointerEventFactory::IsPrimary(
if (!id_count_[static_cast<int>(properties.pointer_type)])
return true;
- int pointer_id = GetPointerEventId(properties);
+ PointerId pointer_id = GetPointerEventId(properties);
return (pointer_id != PointerEventFactory::kInvalidId &&
IsPrimary(pointer_id));
}
-bool PointerEventFactory::IsActiveButtonsState(const int pointer_id) const {
+bool PointerEventFactory::IsActiveButtonsState(
+ const PointerId pointer_id) const {
return pointer_id_mapping_.Contains(pointer_id) &&
pointer_id_mapping_.at(pointer_id).is_active_buttons;
}
WebPointerProperties::PointerType PointerEventFactory::GetPointerType(
- int pointer_id) const {
+ PointerId pointer_id) const {
if (!IsActive(pointer_id))
return WebPointerProperties::PointerType::kUnknown;
return pointer_id_mapping_.at(pointer_id).incoming_id.GetPointerType();
}
-int PointerEventFactory::GetPointerEventId(
+PointerId PointerEventFactory::GetPointerEventId(
const WebPointerProperties& properties) const {
if (properties.pointer_type == WebPointerProperties::PointerType::kMouse)
return PointerEventFactory::kMouseId;
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event_factory.h b/chromium/third_party/blink/renderer/core/events/pointer_event_factory.h
index 67413673980..6592a2b4ffb 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event_factory.h
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event_factory.h
@@ -35,9 +35,8 @@ class CORE_EXPORT PointerEventFactory {
const Vector<WebPointerEvent>& predicted_events,
LocalDOMWindow* view);
- PointerEvent* CreatePointerCancelEvent(
- const int pointer_id,
- TimeTicks platfrom_time_stamp);
+ PointerEvent* CreatePointerCancelEvent(const PointerId pointer_id,
+ TimeTicks platfrom_time_stamp);
// For creating raw move events in chorded button case.
PointerEvent* CreatePointerRawMoveEvent(PointerEvent*);
@@ -56,16 +55,16 @@ class CORE_EXPORT PointerEventFactory {
// When a particular pointerId is removed, the id is considered free even
// though there might have been other PointerEvents that were generated with
// the same id before.
- bool Remove(const int);
+ bool Remove(const PointerId);
// Returns all ids of pointers that are not hovering.
- Vector<int> GetPointerIdsOfNonHoveringPointers() const;
+ Vector<PointerId> GetPointerIdsOfNonHoveringPointers() const;
// Returns whether a pointer id exists and active.
- bool IsActive(const int) const;
+ bool IsActive(const PointerId) const;
// Returns whether a pointer id exists and has at least one pressed button.
- bool IsActiveButtonsState(const int) const;
+ bool IsActiveButtonsState(const PointerId) const;
// Returns the id of the pointer event corresponding to the given pointer
// properties if exists otherwise s_invalidId.
@@ -73,24 +72,23 @@ class CORE_EXPORT PointerEventFactory {
// Returns pointerType of for the given pointerId if such id is active.
// Otherwise it returns WebPointerProperties::PointerType::Unknown.
- WebPointerProperties::PointerType GetPointerType(int pointer_id) const;
+ WebPointerProperties::PointerType GetPointerType(PointerId pointer_id) const;
// Returns whether a WebPoinerProperties is primary pointer.
bool IsPrimary(const WebPointerProperties&) const;
- static const int kMouseId;
+ static const PointerId kMouseId;
// Removes pointer_id from the map.
- void RemoveLastPosition(const int pointer_id);
+ void RemoveLastPosition(const PointerId pointer_id);
// Returns last_position of for the given pointerId if such id is active.
// Otherwise it returns the PositionInScreen of the given events, so we will
// get movement = 0 when there is no last position.
- FloatPoint GetLastPointerPosition(int pointer_id,
+ FloatPoint GetLastPointerPosition(PointerId pointer_id,
const WebPointerProperties& event) const;
private:
- typedef WTF::UnsignedWithZeroKeyHashTraits<int> UnsignedHash;
typedef struct IncomingId : public std::pair<int, int> {
IncomingId() = default;
IncomingId(WebPointerProperties::PointerType pointer_type, int raw_id)
@@ -115,10 +113,10 @@ class CORE_EXPORT PointerEventFactory {
hovering(hovering) {}
} PointerAttributes;
- int AddIdAndActiveButtons(const IncomingId,
- bool is_active_buttons,
- bool hovering);
- bool IsPrimary(const int) const;
+ PointerId AddIdAndActiveButtons(const IncomingId,
+ bool is_active_buttons,
+ bool hovering);
+ bool IsPrimary(const PointerId) const;
PointerEventInit* ConvertIdTypeButtonsEvent(const WebPointerEvent&);
void SetEventSpecificFields(PointerEventInit*, const AtomicString& type);
@@ -134,17 +132,21 @@ class CORE_EXPORT PointerEventFactory {
const Vector<WebPointerEvent>& event_list,
LocalDOMWindow* view);
- void SetLastPosition(int pointer_id, const WebPointerProperties& event);
+ void SetLastPosition(PointerId pointer_id, const WebPointerProperties& event);
- static const int kInvalidId;
+ static const PointerId kInvalidId;
- int current_id_;
+ PointerId current_id_;
HashMap<IncomingId,
- int,
+ PointerId,
WTF::PairHash<int, int>,
- WTF::PairHashTraits<UnsignedHash, UnsignedHash>>
+ WTF::PairHashTraits<WTF::UnsignedWithZeroKeyHashTraits<int>,
+ WTF::UnsignedWithZeroKeyHashTraits<int>>>
pointer_incoming_id_mapping_;
- HashMap<int, PointerAttributes, WTF::IntHash<int>, UnsignedHash>
+ HashMap<PointerId,
+ PointerAttributes,
+ WTF::IntHash<PointerId>,
+ WTF::UnsignedWithZeroKeyHashTraits<PointerId>>
pointer_id_mapping_;
int primary_id_[static_cast<int>(
WebPointerProperties::PointerType::kLastEntry) +
@@ -153,7 +155,10 @@ class CORE_EXPORT PointerEventFactory {
WebPointerProperties::PointerType::kLastEntry) +
1];
- HashMap<int, FloatPoint, WTF::IntHash<int>, UnsignedHash>
+ HashMap<PointerId,
+ FloatPoint,
+ WTF::IntHash<PointerId>,
+ WTF::UnsignedWithZeroKeyHashTraits<PointerId>>
pointer_id_last_position_mapping_;
};
diff --git a/chromium/third_party/blink/renderer/core/events/portal_activate_event.cc b/chromium/third_party/blink/renderer/core/events/portal_activate_event.cc
new file mode 100644
index 00000000000..5d7ddae0ea5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/portal_activate_event.cc
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/events/portal_activate_event.h"
+
+#include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
+
+namespace blink {
+
+PortalActivateEvent* PortalActivateEvent::Create() {
+ return MakeGarbageCollected<PortalActivateEvent>();
+}
+
+PortalActivateEvent::PortalActivateEvent()
+ : Event(event_type_names::kPortalactivate,
+ Bubbles::kNo,
+ Cancelable::kNo,
+ CurrentTimeTicks()) {}
+
+PortalActivateEvent::~PortalActivateEvent() = default;
+
+void PortalActivateEvent::Trace(blink::Visitor* visitor) {
+ Event::Trace(visitor);
+}
+
+const AtomicString& PortalActivateEvent::InterfaceName() const {
+ return event_type_names::kPortalactivate;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/events/portal_activate_event.h b/chromium/third_party/blink/renderer/core/events/portal_activate_event.h
new file mode 100644
index 00000000000..8936f89d54f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/portal_activate_event.h
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PORTAL_ACTIVATE_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PORTAL_ACTIVATE_EVENT_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+
+namespace blink {
+
+class CORE_EXPORT PortalActivateEvent : public Event {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static PortalActivateEvent* Create();
+
+ PortalActivateEvent();
+ ~PortalActivateEvent() override;
+
+ void Trace(blink::Visitor*) override;
+
+ // Event overrides
+ const AtomicString& InterfaceName() const override;
+
+ private:
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PORTAL_ACTIVATE_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/core/events/portal_activate_event.idl b/chromium/third_party/blink/renderer/core/events/portal_activate_event.idl
new file mode 100644
index 00000000000..74e22f914fb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/portal_activate_event.idl
@@ -0,0 +1,9 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/portals/#the-portalactivateevent-interface
+
+[Exposed=Window, RuntimeEnabled=Portals]
+interface PortalActivateEvent : Event {
+};
diff --git a/chromium/third_party/blink/renderer/core/events/text_event.idl b/chromium/third_party/blink/renderer/core/events/text_event.idl
index 2ae52eb0a1a..37ea2536407 100644
--- a/chromium/third_party/blink/renderer/core/events/text_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/text_event.idl
@@ -35,10 +35,10 @@ interface TextEvent : UIEvent {
[Measure] readonly attribute DOMString data;
- [Measure] void initTextEvent([Default=Undefined] optional DOMString type,
- [Default=Undefined] optional boolean bubbles,
- [Default=Undefined] optional boolean cancelable,
- [Default=Undefined] optional Window? view,
- [Default=Undefined] optional DOMString data);
+ [Measure] void initTextEvent([DefaultValue=Undefined] optional DOMString type,
+ [DefaultValue=Undefined] optional boolean bubbles,
+ [DefaultValue=Undefined] optional boolean cancelable,
+ [DefaultValue=Undefined] optional Window? view,
+ [DefaultValue=Undefined] optional DOMString data);
};
diff --git a/chromium/third_party/blink/renderer/core/events/touch_event_test.cc b/chromium/third_party/blink/renderer/core/events/touch_event_test.cc
index 652db736442..b987a51cf00 100644
--- a/chromium/third_party/blink/renderer/core/events/touch_event_test.cc
+++ b/chromium/third_party/blink/renderer/core/events/touch_event_test.cc
@@ -47,7 +47,7 @@ class ConsoleCapturingChromeClient : public EmptyChromeClient {
class TouchEventTest : public PageTestBase {
public:
void SetUp() override {
- chrome_client_ = new ConsoleCapturingChromeClient();
+ chrome_client_ = MakeGarbageCollected<ConsoleCapturingChromeClient>();
Page::PageClients clients;
FillWithEmptyClients(clients);
clients.chrome_client = chrome_client_.Get();
diff --git a/chromium/third_party/blink/renderer/core/events/ui_event.idl b/chromium/third_party/blink/renderer/core/events/ui_event.idl
index 20e8fc95224..ed34dba7c05 100644
--- a/chromium/third_party/blink/renderer/core/events/ui_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/ui_event.idl
@@ -29,11 +29,11 @@
// https://w3c.github.io/uievents/#idl-interface-UIEvent-initializers
// TODO(foolip): None of the initUIEvent() arguments should be optional.
- [Measure] void initUIEvent([Default=Undefined] optional DOMString type,
- [Default=Undefined] optional boolean bubbles,
- [Default=Undefined] optional boolean cancelable,
- [Default=Undefined] optional Window? view,
- [Default=Undefined] optional long detail);
+ [Measure] void initUIEvent([DefaultValue=Undefined] optional DOMString type,
+ [DefaultValue=Undefined] optional boolean bubbles,
+ [DefaultValue=Undefined] optional boolean cancelable,
+ [DefaultValue=Undefined] optional Window? view,
+ [DefaultValue=Undefined] optional long detail);
readonly attribute unsigned long which;
};
diff --git a/chromium/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc b/chromium/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
index ae1d84dfb87..93f5fe7822d 100644
--- a/chromium/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
+++ b/chromium/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
@@ -123,7 +123,7 @@ TEST(WebInputEventConversionTest, InputEventsScaling) {
web_view->GetSettings()->SetViewportEnabled(true);
int page_width = 640;
int page_height = 480;
- web_view->Resize(WebSize(page_width, page_height));
+ web_view->MainFrameWidget()->Resize(WebSize(page_width, page_height));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -337,12 +337,11 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
web_view->GetSettings()->SetViewportEnabled(true);
int page_width = 640;
int page_height = 480;
- web_view->Resize(WebSize(page_width, page_height));
+ web_view->MainFrameWidget()->Resize(WebSize(page_width, page_height));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
web_view->SetPageScaleFactor(2);
- web_view->MainFrameImpl()->SetInputEventsScaleForEmulation(1.5);
LocalFrameView* view = ToLocalFrame(web_view->GetPage()->MainFrame())->View();
@@ -359,8 +358,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
TransformWebMouseEvent(view, web_mouse_event);
FloatPoint position = transformed_event.PositionInRootFrame();
- EXPECT_FLOAT_EQ(30, position.X());
- EXPECT_FLOAT_EQ(30, position.Y());
+ EXPECT_FLOAT_EQ(45, position.X());
+ EXPECT_FLOAT_EQ(45, position.Y());
EXPECT_EQ(90, transformed_event.PositionInScreen().x);
EXPECT_EQ(90, transformed_event.PositionInScreen().y);
EXPECT_EQ(60, transformed_event.movement_x);
@@ -392,8 +391,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
EXPECT_EQ(events.size(), coalescedevents.size());
FloatPoint position = coalescedevents[0].PositionInRootFrame();
- EXPECT_FLOAT_EQ(30, position.X());
- EXPECT_FLOAT_EQ(30, position.Y());
+ EXPECT_FLOAT_EQ(45, position.X());
+ EXPECT_FLOAT_EQ(45, position.Y());
EXPECT_EQ(90, coalescedevents[0].PositionInScreen().x);
EXPECT_EQ(90, coalescedevents[0].PositionInScreen().y);
@@ -401,8 +400,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
EXPECT_EQ(60, coalescedevents[0].movement_y);
position = coalescedevents[1].PositionInRootFrame();
- EXPECT_FLOAT_EQ(30, position.X());
- EXPECT_FLOAT_EQ(40, position.Y());
+ EXPECT_FLOAT_EQ(45, position.X());
+ EXPECT_FLOAT_EQ(60, position.Y());
EXPECT_EQ(90, coalescedevents[1].PositionInScreen().x);
EXPECT_EQ(120, coalescedevents[1].PositionInScreen().y);
@@ -424,12 +423,12 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
TransformWebGestureEvent(view, web_gesture_event);
FloatPoint position = scaled_gesture_event.PositionInRootFrame();
- EXPECT_FLOAT_EQ(30, position.X());
- EXPECT_FLOAT_EQ(30, position.Y());
+ EXPECT_FLOAT_EQ(45, position.X());
+ EXPECT_FLOAT_EQ(45, position.Y());
EXPECT_EQ(90, scaled_gesture_event.PositionInScreen().x);
EXPECT_EQ(90, scaled_gesture_event.PositionInScreen().y);
- EXPECT_EQ(20, scaled_gesture_event.DeltaXInRootFrame());
- EXPECT_EQ(20, scaled_gesture_event.DeltaYInRootFrame());
+ EXPECT_EQ(30, scaled_gesture_event.DeltaXInRootFrame());
+ EXPECT_EQ(30, scaled_gesture_event.DeltaYInRootFrame());
}
{
@@ -443,8 +442,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
WebGestureEvent scaled_gesture_event =
TransformWebGestureEvent(view, web_gesture_event);
IntSize area = FlooredIntSize(scaled_gesture_event.TapAreaInRootFrame());
- EXPECT_EQ(10, area.Width());
- EXPECT_EQ(10, area.Height());
+ EXPECT_EQ(15, area.Width());
+ EXPECT_EQ(15, area.Height());
}
{
@@ -458,8 +457,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
WebGestureEvent scaled_gesture_event =
TransformWebGestureEvent(view, web_gesture_event);
IntSize area = FlooredIntSize(scaled_gesture_event.TapAreaInRootFrame());
- EXPECT_EQ(10, area.Width());
- EXPECT_EQ(10, area.Height());
+ EXPECT_EQ(15, area.Width());
+ EXPECT_EQ(15, area.Height());
}
{
@@ -473,8 +472,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
WebGestureEvent scaled_gesture_event =
TransformWebGestureEvent(view, web_gesture_event);
IntSize area = FlooredIntSize(scaled_gesture_event.TapAreaInRootFrame());
- EXPECT_EQ(10, area.Width());
- EXPECT_EQ(10, area.Height());
+ EXPECT_EQ(15, area.Width());
+ EXPECT_EQ(15, area.Height());
}
{
@@ -488,8 +487,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
WebGestureEvent scaled_gesture_event =
TransformWebGestureEvent(view, web_gesture_event);
IntSize area = FlooredIntSize(scaled_gesture_event.TapAreaInRootFrame());
- EXPECT_EQ(10, area.Width());
- EXPECT_EQ(10, area.Height());
+ EXPECT_EQ(15, area.Width());
+ EXPECT_EQ(15, area.Height());
}
{
@@ -503,8 +502,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
WebGestureEvent scaled_gesture_event =
TransformWebGestureEvent(view, web_gesture_event);
IntSize area = FlooredIntSize(scaled_gesture_event.TapAreaInRootFrame());
- EXPECT_EQ(10, area.Width());
- EXPECT_EQ(10, area.Height());
+ EXPECT_EQ(15, area.Width());
+ EXPECT_EQ(15, area.Height());
}
{
@@ -518,8 +517,8 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
WebGestureEvent scaled_gesture_event =
TransformWebGestureEvent(view, web_gesture_event);
IntSize area = FlooredIntSize(scaled_gesture_event.TapAreaInRootFrame());
- EXPECT_EQ(10, area.Width());
- EXPECT_EQ(10, area.Height());
+ EXPECT_EQ(15, area.Width());
+ EXPECT_EQ(15, area.Height());
}
{
@@ -536,10 +535,10 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
EXPECT_FLOAT_EQ(90, transformed_event.PositionInScreen().x);
EXPECT_FLOAT_EQ(90, transformed_event.PositionInScreen().y);
- EXPECT_FLOAT_EQ(30, transformed_event.PositionInWidget().x);
- EXPECT_FLOAT_EQ(30, transformed_event.PositionInWidget().y);
- EXPECT_FLOAT_EQ(10, transformed_event.width);
- EXPECT_FLOAT_EQ(10, transformed_event.height);
+ EXPECT_FLOAT_EQ(45, transformed_event.PositionInWidget().x);
+ EXPECT_FLOAT_EQ(45, transformed_event.PositionInWidget().y);
+ EXPECT_FLOAT_EQ(15, transformed_event.width);
+ EXPECT_FLOAT_EQ(15, transformed_event.height);
}
{
@@ -569,18 +568,18 @@ TEST(WebInputEventConversionTest, InputEventsTransform) {
coalescedevents[0].WebPointerEventInRootFrame();
EXPECT_FLOAT_EQ(90, transformed_event.PositionInScreen().x);
EXPECT_FLOAT_EQ(90, transformed_event.PositionInScreen().y);
- EXPECT_FLOAT_EQ(30, transformed_event.PositionInWidget().x);
- EXPECT_FLOAT_EQ(30, transformed_event.PositionInWidget().y);
- EXPECT_FLOAT_EQ(10, transformed_event.width);
- EXPECT_FLOAT_EQ(10, transformed_event.height);
+ EXPECT_FLOAT_EQ(45, transformed_event.PositionInWidget().x);
+ EXPECT_FLOAT_EQ(45, transformed_event.PositionInWidget().y);
+ EXPECT_FLOAT_EQ(15, transformed_event.width);
+ EXPECT_FLOAT_EQ(15, transformed_event.height);
transformed_event = coalescedevents[1].WebPointerEventInRootFrame();
EXPECT_FLOAT_EQ(120, transformed_event.PositionInScreen().x);
EXPECT_FLOAT_EQ(90, transformed_event.PositionInScreen().y);
- EXPECT_FLOAT_EQ(40, transformed_event.PositionInWidget().x);
- EXPECT_FLOAT_EQ(30, transformed_event.PositionInWidget().y);
- EXPECT_FLOAT_EQ(20, transformed_event.width);
- EXPECT_FLOAT_EQ(10, transformed_event.height);
+ EXPECT_FLOAT_EQ(60, transformed_event.PositionInWidget().x);
+ EXPECT_FLOAT_EQ(45, transformed_event.PositionInWidget().y);
+ EXPECT_FLOAT_EQ(30, transformed_event.width);
+ EXPECT_FLOAT_EQ(15, transformed_event.height);
}
}
@@ -594,7 +593,7 @@ TEST(WebInputEventConversionTest, InputEventsConversions) {
web_view_helper.InitializeAndLoad(base_url + file_name);
int page_width = 640;
int page_height = 480;
- web_view->Resize(WebSize(page_width, page_height));
+ web_view->MainFrameWidget()->Resize(WebSize(page_width, page_height));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -632,7 +631,7 @@ TEST(WebInputEventConversionTest, VisualViewportOffset) {
web_view_helper.InitializeAndLoad(base_url + file_name);
int page_width = 640;
int page_height = 480;
- web_view->Resize(WebSize(page_width, page_height));
+ web_view->MainFrameWidget()->Resize(WebSize(page_width, page_height));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -731,14 +730,14 @@ TEST(WebInputEventConversionTest, ElasticOverscroll) {
web_view_helper.InitializeAndLoad(base_url + file_name);
int page_width = 640;
int page_height = 480;
- web_view->Resize(WebSize(page_width, page_height));
+ web_view->MainFrameWidget()->Resize(WebSize(page_width, page_height));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
LocalFrameView* view = ToLocalFrame(web_view->GetPage()->MainFrame())->View();
gfx::Vector2dF elastic_overscroll(10, -20);
- web_view->ApplyViewportChanges(
+ web_view->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), elastic_overscroll, 1.0f, 0.0f});
// Just elastic overscroll.
@@ -807,12 +806,12 @@ TEST(WebInputEventConversionTest, ElasticOverscrollWithPageReload) {
web_view_helper.InitializeAndLoad(base_url + file_name);
int page_width = 640;
int page_height = 480;
- web_view->Resize(WebSize(page_width, page_height));
+ web_view->MainFrameWidget()->Resize(WebSize(page_width, page_height));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
gfx::Vector2dF elastic_overscroll(10, -20);
- web_view->ApplyViewportChanges(
+ web_view->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), elastic_overscroll, 1.0f, 0.0f});
frame_test_helpers::ReloadFrame(
web_view_helper.GetWebView()->MainFrameImpl());
diff --git a/chromium/third_party/blink/renderer/core/events/wheel_event.cc b/chromium/third_party/blink/renderer/core/events/wheel_event.cc
index c7cb037aef2..2fa4989abf4 100644
--- a/chromium/third_party/blink/renderer/core/events/wheel_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/wheel_event.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/clipboard/data_transfer.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
#include "third_party/blink/renderer/core/event_interface_names.h"
+#include "third_party/blink/renderer/core/frame/intervention.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
@@ -122,10 +123,22 @@ bool WheelEvent::IsWheelEvent() const {
void WheelEvent::preventDefault() {
MouseEvent::preventDefault();
+ PassiveMode passive_mode = HandlingPassive();
+ if (passive_mode == PassiveMode::kPassiveForcedDocumentLevel) {
+ String id = "PreventDefaultPassive";
+ String message =
+ "Unable to preventDefault inside passive event listener due to "
+ "target being treated as passive. See "
+ "https://www.chromestatus.com/features/6662647093133312";
+ if (view() && view()->IsLocalDOMWindow() && view()->GetFrame()) {
+ Intervention::GenerateReport(ToLocalDOMWindow(view())->GetFrame(), id,
+ message);
+ }
+ }
+
if (!currentTarget() || !currentTarget()->IsTopLevelNode())
return;
- PassiveMode passive_mode = HandlingPassive();
if (passive_mode == PassiveMode::kPassiveForcedDocumentLevel ||
passive_mode == PassiveMode::kNotPassiveDefault) {
if (ExecutionContext* context = currentTarget()->GetExecutionContext()) {
diff --git a/chromium/third_party/blink/renderer/core/execution_context/BUILD.gn b/chromium/third_party/blink/renderer/core/execution_context/BUILD.gn
index eed99d11dda..ea7da46d478 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/execution_context/BUILD.gn
@@ -8,6 +8,9 @@ blink_core_sources("execution_context") {
sources = [
"execution_context.cc",
"execution_context.h",
+ "pausable_object.cc",
+ "pausable_object.h",
+ "pause_state.h",
"remote_security_context.cc",
"remote_security_context.h",
"security_context.cc",
diff --git a/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc b/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc
index 4a50fa9f0a6..601da877049 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -31,12 +31,14 @@
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/core/events/error_event.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
+#include "third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
@@ -49,8 +51,8 @@ ExecutionContext::ExecutionContext(v8::Isolate* isolate)
: isolate_(isolate),
circular_sequential_id_(0),
in_dispatch_error_event_(false),
- is_context_paused_(false),
is_context_destroyed_(false),
+ csp_delegate_(MakeGarbageCollected<ExecutionContextCSPDelegate>(*this)),
window_interaction_tokens_(0),
referrer_policy_(network::mojom::ReferrerPolicy::kDefault),
invalidator_(std::make_unique<InterfaceInvalidator>()) {}
@@ -75,15 +77,15 @@ ExecutionContext* ExecutionContext::ForRelevantRealm(
return ToExecutionContext(info.Holder()->CreationContext());
}
-void ExecutionContext::PausePausableObjects() {
- DCHECK(!is_context_paused_);
- NotifySuspendingPausableObjects();
- is_context_paused_ = true;
+void ExecutionContext::PausePausableObjects(PauseState state) {
+ DCHECK(!pause_state_);
+ pause_state_ = state;
+ NotifySuspendingPausableObjects(state);
}
void ExecutionContext::UnpausePausableObjects() {
- DCHECK(is_context_paused_);
- is_context_paused_ = false;
+ DCHECK(pause_state_.has_value());
+ pause_state_.reset();
NotifyResumingPausableObjects();
}
@@ -93,8 +95,8 @@ void ExecutionContext::NotifyContextDestroyed() {
ContextLifecycleNotifier::NotifyContextDestroyed();
}
-void ExecutionContext::PauseScheduledTasks() {
- PausePausableObjects();
+void ExecutionContext::PauseScheduledTasks(PauseState state) {
+ PausePausableObjects(state);
TasksWerePaused();
}
@@ -108,8 +110,8 @@ void ExecutionContext::PausePausableObjectIfNeeded(PausableObject* object) {
DCHECK(Contains(object));
#endif
// Ensure all PausableObjects are paused also newly created ones.
- if (is_context_paused_)
- object->Pause();
+ if (pause_state_)
+ object->ContextPaused(pause_state_.value());
}
void ExecutionContext::DispatchErrorEvent(
@@ -164,6 +166,17 @@ PublicURLManager& ExecutionContext::GetPublicURLManager() {
return *public_url_manager_;
}
+ContentSecurityPolicyDelegate&
+ExecutionContext::GetContentSecurityPolicyDelegate() {
+ return *csp_delegate_;
+}
+
+ContentSecurityPolicy* ExecutionContext::GetContentSecurityPolicyForWorld() {
+ // Isolated worlds are only relevant for Documents. Hence just return the main
+ // world's content security policy by default.
+ return GetContentSecurityPolicy();
+}
+
const SecurityOrigin* ExecutionContext::GetSecurityOrigin() {
return GetSecurityContext().GetSecurityOrigin();
}
@@ -204,13 +217,6 @@ String ExecutionContext::OutgoingReferrer() const {
return Url().StrippedForUseAsReferrer();
}
-FetchClientSettingsObjectSnapshot*
-ExecutionContext::CreateFetchClientSettingsObjectSnapshot() {
- return MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
- BaseURL(), GetSecurityOrigin(), GetReferrerPolicy(), OutgoingReferrer(),
- GetHttpsState());
-}
-
void ExecutionContext::ParseAndSetReferrerPolicy(const String& policies,
bool support_legacy_keywords) {
network::mojom::ReferrerPolicy referrer_policy;
@@ -256,7 +262,9 @@ void ExecutionContext::RemoveURLFromMemoryCache(const KURL& url) {
void ExecutionContext::Trace(blink::Visitor* visitor) {
visitor->Trace(public_url_manager_);
visitor->Trace(pending_exceptions_);
+ visitor->Trace(csp_delegate_);
ContextLifecycleNotifier::Trace(visitor);
+ ConsoleLoggerImplBase::Trace(visitor);
Supplementable<ExecutionContext>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/execution_context/execution_context.h b/chromium/third_party/blink/renderer/core/execution_context/execution_context.h
index 0d868015baf..037c5f3a796 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -32,12 +32,14 @@
#include "base/location.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/unguessable_token.h"
-#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/execution_context/pause_state.h"
+#include "third_party/blink/renderer/core/loader/console_logger_impl_base.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -51,15 +53,20 @@ namespace service_manager {
class InterfaceProvider;
}
+namespace network {
+namespace mojom {
+enum class ReferrerPolicy : int32_t;
+} // namespace mojom
+} // namespace network
+
namespace blink {
-class ConsoleMessage;
class ContentSecurityPolicy;
+class ContentSecurityPolicyDelegate;
class CoreProbeSink;
class DOMTimerCoordinator;
class ErrorEvent;
class EventTarget;
-class FetchClientSettingsObjectSnapshot;
class FrameOrWorkerScheduler;
class InterfaceInvalidator;
class KURL;
@@ -103,7 +110,8 @@ enum class SecureContextMode { kInsecureContext, kSecureContext };
// by an extension developer, but these share an ExecutionContext (the document)
// in common.
class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
- public Supplementable<ExecutionContext> {
+ public Supplementable<ExecutionContext>,
+ public ConsoleLoggerImplBase {
MERGE_GARBAGE_COLLECTED_MIXINS();
public:
@@ -141,6 +149,16 @@ class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
SecurityOrigin* GetMutableSecurityOrigin();
ContentSecurityPolicy* GetContentSecurityPolicy();
+
+ // Returns the content security policy to be used based on the current
+ // JavaScript world we are in.
+ // Note: As part of crbug.com/896041, existing usages of
+ // ContentSecurityPolicy::ShouldBypassMainWorld should eventually be replaced
+ // by GetContentSecurityPolicyForWorld. However this is under active
+ // development, hence new callers should still use
+ // ContentSecurityPolicy::ShouldBypassMainWorld for now.
+ virtual ContentSecurityPolicy* GetContentSecurityPolicyForWorld();
+
virtual const KURL& Url() const = 0;
virtual const KURL& BaseURL() const = 0;
virtual KURL CompleteURL(const String& url) const = 0;
@@ -171,19 +189,20 @@ class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
void DispatchErrorEvent(ErrorEvent*, SanitizeScriptErrors);
- virtual void AddConsoleMessage(ConsoleMessage*) = 0;
virtual void ExceptionThrown(ErrorEvent*) = 0;
PublicURLManager& GetPublicURLManager();
+ ContentSecurityPolicyDelegate& GetContentSecurityPolicyDelegate();
+
virtual void RemoveURLFromMemoryCache(const KURL&);
- void PausePausableObjects();
+ void PausePausableObjects(PauseState);
void UnpausePausableObjects();
void StopPausableObjects();
void NotifyContextDestroyed() override;
- void PauseScheduledTasks();
+ void PauseScheduledTasks(PauseState);
void UnpauseScheduledTasks();
// TODO(haraken): Remove these methods by making the customers inherit from
@@ -193,8 +212,9 @@ class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
virtual void TasksWerePaused() {}
virtual void TasksWereUnpaused() {}
- bool IsContextPaused() const { return is_context_paused_; }
+ bool IsContextPaused() const { return pause_state_.has_value(); }
bool IsContextDestroyed() const { return is_context_destroyed_; }
+ base::Optional<PauseState> ContextPauseState() const { return pause_state_; }
// Called after the construction of an PausableObject to synchronize
// pause state.
@@ -226,8 +246,6 @@ class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
virtual String OutgoingReferrer() const;
- FetchClientSettingsObjectSnapshot* CreateFetchClientSettingsObjectSnapshot();
-
// Parses a comma-separated list of referrer policy tokens, and sets
// the context's referrer policy to the last one that is a valid
// policy. Logs a message to the console if none of the policy
@@ -271,11 +289,13 @@ class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
bool in_dispatch_error_event_;
HeapVector<Member<ErrorEvent>> pending_exceptions_;
- bool is_context_paused_;
+ base::Optional<PauseState> pause_state_;
bool is_context_destroyed_;
Member<PublicURLManager> public_url_manager_;
+ const Member<ContentSecurityPolicyDelegate> csp_delegate_;
+
// Counter that keeps track of how many window interaction calls are allowed
// for this ExecutionContext. Callers are expected to call
// |allowWindowInteraction()| and |consumeWindowInteraction()| in order to
diff --git a/chromium/third_party/blink/renderer/core/dom/pausable_object.cc b/chromium/third_party/blink/renderer/core/execution_context/pausable_object.cc
index bb23fbd1cf6..66616d522bc 100644
--- a/chromium/third_party/blink/renderer/core/dom/pausable_object.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/pausable_object.cc
@@ -24,7 +24,7 @@
*
*/
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/instance_counters.h"
@@ -59,9 +59,9 @@ void PausableObject::PauseIfNeeded() {
context->PausePausableObjectIfNeeded(this);
}
-void PausableObject::Pause() {}
+void PausableObject::ContextPaused(PauseState) {}
-void PausableObject::Unpause() {}
+void PausableObject::ContextUnpaused() {}
void PausableObject::DidMoveToNewExecutionContext(ExecutionContext* context) {
SetContext(context);
@@ -71,12 +71,13 @@ void PausableObject::DidMoveToNewExecutionContext(ExecutionContext* context) {
return;
}
- if (context->IsContextPaused()) {
- Pause();
+ base::Optional<PauseState> pause_state = context->ContextPauseState();
+ if (pause_state) {
+ ContextPaused(pause_state.value());
return;
}
- Unpause();
+ ContextUnpaused();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/pausable_object.h b/chromium/third_party/blink/renderer/core/execution_context/pausable_object.h
index 304f429f468..b9dd7b6c201 100644
--- a/chromium/third_party/blink/renderer/core/dom/pausable_object.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/pausable_object.h
@@ -24,8 +24,8 @@
*
*/
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_PAUSABLE_OBJECT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_PAUSABLE_OBJECT_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSABLE_OBJECT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSABLE_OBJECT_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
@@ -48,7 +48,7 @@ namespace blink {
//
// Objects with asynchronous activity, especially activity that may have an
// observable effect on web-visible state, on should suspend that activity while
-// the page is paused by overriding Pause() and Unpause().
+// the page is paused by overriding ContextPaused() and ContextUnpaused().
//
// https://html.spec.whatwg.org/multipage/webappapis.html#pause
class CORE_EXPORT PausableObject : public ContextLifecycleObserver {
@@ -64,8 +64,8 @@ class CORE_EXPORT PausableObject : public ContextLifecycleObserver {
// These methods have an empty default implementation so that subclasses
// which don't need special treatment can skip implementation.
- virtual void Pause();
- virtual void Unpause();
+ virtual void ContextPaused(PauseState);
+ virtual void ContextUnpaused();
void DidMoveToNewExecutionContext(ExecutionContext*);
@@ -80,4 +80,4 @@ class CORE_EXPORT PausableObject : public ContextLifecycleObserver {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_PAUSABLE_OBJECT_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSABLE_OBJECT_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/pausable_object_test.cc b/chromium/third_party/blink/renderer/core/execution_context/pausable_object_test.cc
index c43ea1e1457..8da0960bed0 100644
--- a/chromium/third_party/blink/renderer/core/dom/pausable_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/pausable_object_test.cc
@@ -28,7 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include <memory>
#include "testing/gmock/include/gmock/gmock.h"
@@ -95,7 +95,7 @@ TEST_F(PausableObjectTest, MoveToActiveDocument) {
}
TEST_F(PausableObjectTest, MoveToSuspendedDocument) {
- DestDocument().PauseScheduledTasks();
+ DestDocument().PauseScheduledTasks(PauseState::kFrozen);
EXPECT_CALL(PausableObject(), Pause());
PausableObject().DidMoveToNewExecutionContext(&DestDocument());
diff --git a/chromium/third_party/blink/renderer/core/execution_context/pause_state.h b/chromium/third_party/blink/renderer/core/execution_context/pause_state.h
new file mode 100644
index 00000000000..4ec7b3f5c38
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/execution_context/pause_state.h
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSE_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSE_STATE_H_
+
+namespace blink {
+
+// This enum represents the pausing state of the ExecutionContext.
+
+enum class PauseState {
+ // Pause tasks only. Used for nested event loops (alert, print).
+ kPaused,
+ // Freeze everything including media. Used for policies that
+ // have auto stopping of media that is hidden.
+ kFrozen
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSE_STATE_H_
diff --git a/chromium/third_party/blink/renderer/core/execution_context/security_context.cc b/chromium/third_party/blink/renderer/core/execution_context/security_context.cc
index 28651e7cca5..1314284c5c4 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -104,6 +104,20 @@ String SecurityContext::addressSpaceForBindings() const {
return "public";
}
+void SecurityContext::SetRequireTrustedTypes() {
+ DCHECK(require_safe_types_ ||
+ content_security_policy_->IsRequireTrustedTypes());
+ require_safe_types_ = true;
+}
+
+void SecurityContext::SetRequireTrustedTypesForTesting() {
+ require_safe_types_ = true;
+}
+
+bool SecurityContext::RequireTrustedTypes() const {
+ return require_safe_types_;
+}
+
void SecurityContext::SetFeaturePolicy(
std::unique_ptr<FeaturePolicy> feature_policy) {
// This method should be called before a FeaturePolicy has been created.
@@ -111,9 +125,6 @@ void SecurityContext::SetFeaturePolicy(
feature_policy_ = std::move(feature_policy);
}
-// Uses the parent enforcing policy; parsed_header and container_policy can
-// both contain report-only directives, which will be used to construct the
-// report-only policy for this context.
void SecurityContext::InitializeFeaturePolicy(
const ParsedFeaturePolicy& parsed_header,
const ParsedFeaturePolicy& container_policy,
@@ -126,31 +137,34 @@ void SecurityContext::InitializeFeaturePolicy(
}
feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
- parent_feature_policy,
- *DirectivesWithDisposition(mojom::FeaturePolicyDisposition::kEnforce,
- container_policy),
- security_origin_->ToUrlOrigin());
- feature_policy_->SetHeaderPolicy(*DirectivesWithDisposition(
- mojom::FeaturePolicyDisposition::kEnforce, parsed_header));
- if (RuntimeEnabledFeatures::FeaturePolicyReportingEnabled()) {
- report_only_feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
- parent_feature_policy,
- *DirectivesWithDisposition(mojom::FeaturePolicyDisposition::kReport,
- container_policy),
- security_origin_->ToUrlOrigin());
- report_only_feature_policy_->SetHeaderPolicy(*DirectivesWithDisposition(
- mojom::FeaturePolicyDisposition::kReport, parsed_header));
- }
+ parent_feature_policy, container_policy, security_origin_->ToUrlOrigin());
+ feature_policy_->SetHeaderPolicy(parsed_header);
+}
+
+// Uses the parent enforcing policy as the basis for the report-only policy.
+void SecurityContext::AddReportOnlyFeaturePolicy(
+ const ParsedFeaturePolicy& parsed_report_only_header,
+ const ParsedFeaturePolicy& container_policy,
+ const FeaturePolicy* parent_feature_policy) {
+ report_only_feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
+ parent_feature_policy, container_policy, security_origin_->ToUrlOrigin());
+ report_only_feature_policy_->SetHeaderPolicy(parsed_report_only_header);
}
bool SecurityContext::IsFeatureEnabled(mojom::FeaturePolicyFeature feature,
ReportOptions report_on_failure,
const String& message) const {
+ if (report_on_failure == ReportOptions::kReportOnFailure) {
+ // We are expecting a violation report in case the feature is disabled in
+ // the context. Therefore, this qualifies as a potential violation (i.e.,
+ // if the feature was disabled it would generate a report).
+ CountPotentialFeaturePolicyViolation(feature);
+ }
+
FeatureEnabledState state = GetFeatureEnabledState(feature);
if (state == FeatureEnabledState::kEnabled)
return true;
- if (report_on_failure == ReportOptions::kReportOnFailure &&
- RuntimeEnabledFeatures::FeaturePolicyReportingEnabled()) {
+ if (report_on_failure == ReportOptions::kReportOnFailure) {
ReportFeaturePolicyViolation(
feature,
(state == FeatureEnabledState::kReportOnly
diff --git a/chromium/third_party/blink/renderer/core/execution_context/security_context.h b/chromium/third_party/blink/renderer/core/execution_context/security_context.h
index fc777a3388d..c8b85ca5928 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/security_context.h
@@ -32,7 +32,6 @@
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
@@ -103,9 +102,11 @@ class CORE_EXPORT SecurityContext : public GarbageCollectedMixin {
mojom::IPAddressSpace AddressSpace() const { return address_space_; }
String addressSpaceForBindings() const;
- void SetRequireTrustedTypes() { require_safe_types_ = true; }
- bool RequireTrustedTypes() const { return require_safe_types_; }
+ void SetRequireTrustedTypes();
+ bool RequireTrustedTypes() const;
+ void SetRequireTrustedTypesForTesting(); // Skips sanity checks.
+ // https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-insecure-navigations-set
void SetInsecureNavigationsSet(const std::vector<unsigned>& set) {
insecure_navigations_to_upgrade_.clear();
for (unsigned hash : set)
@@ -118,6 +119,7 @@ class CORE_EXPORT SecurityContext : public GarbageCollectedMixin {
return &insecure_navigations_to_upgrade_;
}
+ // https://w3c.github.io/webappsec-upgrade-insecure-requests/#insecure-requests-policy
virtual void SetInsecureRequestPolicy(WebInsecureRequestPolicy policy) {
insecure_request_policy_ = policy;
}
@@ -138,6 +140,10 @@ class CORE_EXPORT SecurityContext : public GarbageCollectedMixin {
void InitializeFeaturePolicy(const ParsedFeaturePolicy& parsed_header,
const ParsedFeaturePolicy& container_policy,
const FeaturePolicy* parent_feature_policy);
+ void AddReportOnlyFeaturePolicy(
+ const ParsedFeaturePolicy& parsed_report_only_header,
+ const ParsedFeaturePolicy& container_policy,
+ const FeaturePolicy* parent_feature_policy);
// Tests whether the policy-controlled feature is enabled in this frame.
// Optionally sends a report to any registered reporting observers or
@@ -149,6 +155,8 @@ class CORE_EXPORT SecurityContext : public GarbageCollectedMixin {
ReportOptions report_on_failure = ReportOptions::kDoNotReport,
const String& message = g_empty_string) const;
FeatureEnabledState GetFeatureEnabledState(mojom::FeaturePolicyFeature) const;
+ virtual void CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature) const {}
virtual void ReportFeaturePolicyViolation(
mojom::FeaturePolicyFeature,
mojom::FeaturePolicyDisposition,
diff --git a/chromium/third_party/blink/renderer/core/exported/BUILD.gn b/chromium/third_party/blink/renderer/core/exported/BUILD.gn
index 6b0519caa53..1aef6372470 100644
--- a/chromium/third_party/blink/renderer/core/exported/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/exported/BUILD.gn
@@ -7,8 +7,6 @@ blink_core_sources("exported") {
sources = [
"local_frame_client_impl.cc",
"local_frame_client_impl.h",
- "shared_worker_repository_client_impl.cc",
- "shared_worker_repository_client_impl.h",
"web_array_buffer.cc",
"web_array_buffer_converter.cc",
"web_associated_url_loader_impl.cc",
@@ -48,6 +46,7 @@ blink_core_sources("exported") {
"web_local_frame_client.cc",
"web_memory_statistics.cc",
"web_meta_element.cc",
+ "web_navigation_params.cc",
"web_node.cc",
"web_option_element.cc",
"web_page_importance_signals.cc",
diff --git a/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 6a56e3f8bea..4db791f0d6b 100644
--- a/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -66,7 +66,6 @@
#include "third_party/blink/renderer/core/events/current_input_event.h"
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
-#include "third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h"
#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
#include "third_party/blink/renderer/core/exported/web_document_loader_impl.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
@@ -161,11 +160,21 @@ void ResetWheelAndTouchEventHandlerProperties(LocalFrame& frame) {
} // namespace
-LocalFrameClientImpl::LocalFrameClientImpl(WebLocalFrameImpl* frame)
- : web_frame_(frame) {}
+LocalFrameClientImpl::LocalFrameClientImpl(
+ WebLocalFrameImpl* frame,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle)
+ : web_frame_(frame) {
+ DCHECK(document_interface_broker_handle.is_valid());
+ document_interface_broker_.Bind(mojom::blink::DocumentInterfaceBrokerPtrInfo(
+ std::move(document_interface_broker_handle),
+ mojom::blink::DocumentInterfaceBroker::Version_));
+}
-LocalFrameClientImpl* LocalFrameClientImpl::Create(WebLocalFrameImpl* frame) {
- return MakeGarbageCollected<LocalFrameClientImpl>(frame);
+LocalFrameClientImpl* LocalFrameClientImpl::Create(
+ WebLocalFrameImpl* frame,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle) {
+ return MakeGarbageCollected<LocalFrameClientImpl>(
+ frame, std::move(document_interface_broker_handle));
}
LocalFrameClientImpl::~LocalFrameClientImpl() = default;
@@ -418,12 +427,10 @@ void LocalFrameClientImpl::DispatchWillCommitProvisionalLoad() {
}
void LocalFrameClientImpl::DispatchDidStartProvisionalLoad(
- DocumentLoader* loader,
- const ResourceRequest& request) {
+ DocumentLoader* loader) {
if (web_frame_->Client()) {
- WrappedResourceRequest wrapped_request(request);
web_frame_->Client()->DidStartProvisionalLoad(
- WebDocumentLoaderImpl::FromDocumentLoader(loader), wrapped_request);
+ WebDocumentLoaderImpl::FromDocumentLoader(loader));
}
}
@@ -449,8 +456,17 @@ void LocalFrameClientImpl::DispatchDidCommitLoad(
}
if (web_frame_->Client()) {
+ mojom::blink::DocumentInterfaceBrokerRequest
+ document_interface_broker_request;
+ if (global_object_reuse_policy !=
+ WebGlobalObjectReusePolicy::kUseExisting) {
+ document_interface_broker_request =
+ mojo::MakeRequest(&document_interface_broker_);
+ }
+
web_frame_->Client()->DidCommitProvisionalLoad(
- WebHistoryItem(item), commit_type, global_object_reuse_policy);
+ WebHistoryItem(item), commit_type,
+ document_interface_broker_request.PassMessagePipe());
if (web_frame_->GetFrame()->IsLocalRoot()) {
// This update should be sent as soon as loading the new document begins
// so that the browser and compositor could reset their states. However,
@@ -500,6 +516,7 @@ void LocalFrameClientImpl::BeginNavigation(
mojom::blink::BlobURLTokenPtr blob_url_token,
base::TimeTicks input_start_time,
const String& href_translate,
+ WebContentSecurityPolicyList initiator_csp,
mojom::blink::NavigationInitiatorPtr navigation_initiator) {
if (!web_frame_->Client())
return;
@@ -519,6 +536,7 @@ void LocalFrameClientImpl::BeginNavigation(
: kWebContentSecurityPolicyDispositionDoNotCheck;
navigation_info->blob_url_token = blob_url_token.PassInterface().PassHandle();
navigation_info->input_start = input_start_time;
+ navigation_info->initiator_csp = std::move(initiator_csp);
navigation_info->navigation_initiator_handle =
navigation_initiator.PassInterface().PassHandle();
@@ -550,6 +568,11 @@ void LocalFrameClientImpl::BeginNavigation(
origin_document->GetFrame()->Client()->Opener() ==
ToCoreFrame(web_frame_);
+ navigation_info
+ ->blocking_downloads_in_sandbox_without_user_activation_enabled =
+ RuntimeEnabledFeatures::
+ BlockingDownloadsInSandboxWithoutUserActivationEnabled();
+
// The frame has navigated either by itself or by the action of the
// |origin_document| when it is defined. |source_location| represents the
// line of code that has initiated the navigation. It is used to let web
@@ -741,20 +764,13 @@ void LocalFrameClientImpl::SelectorMatchChanged(
DocumentLoader* LocalFrameClientImpl::CreateDocumentLoader(
LocalFrame* frame,
- const ResourceRequest& request,
- const SubstituteData& data,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DCHECK(frame);
WebDocumentLoaderImpl* document_loader =
- MakeGarbageCollected<WebDocumentLoaderImpl>(
- frame, request, data, client_redirect_policy,
- devtools_navigation_token, load_type, navigation_type,
- std::move(navigation_params));
+ MakeGarbageCollected<WebDocumentLoaderImpl>(frame, navigation_type,
+ std::move(navigation_params));
document_loader->SetExtraData(std::move(extra_data));
if (web_frame_->Client())
web_frame_->Client()->DidCreateDocumentLoader(document_loader);
@@ -798,6 +814,12 @@ LocalFrame* LocalFrameClientImpl::CreateFrame(
return web_frame_->CreateChildFrame(name, owner_element);
}
+std::pair<RemoteFrame*, base::UnguessableToken>
+LocalFrameClientImpl::CreatePortal(HTMLPortalElement* portal,
+ mojom::blink::PortalRequest request) {
+ return web_frame_->CreatePortal(portal, std::move(request));
+}
+
WebPluginContainerImpl* LocalFrameClientImpl::CreatePlugin(
HTMLPlugInElement& element,
const KURL& url,
@@ -946,11 +968,6 @@ WebContentSettingsClient* LocalFrameClientImpl::GetContentSettingsClient() {
return web_frame_->GetContentSettingsClient();
}
-SharedWorkerRepositoryClient*
-LocalFrameClientImpl::GetSharedWorkerRepositoryClient() {
- return web_frame_->SharedWorkerRepositoryClient();
-}
-
std::unique_ptr<WebApplicationCacheHost>
LocalFrameClientImpl::CreateApplicationCacheHost(
WebApplicationCacheHostClient* client) {
@@ -1057,6 +1074,12 @@ LocalFrameClientImpl::GetInterfaceProvider() {
return web_frame_->Client()->GetInterfaceProvider();
}
+mojom::blink::DocumentInterfaceBroker*
+LocalFrameClientImpl::GetDocumentInterfaceBroker() {
+ DCHECK(document_interface_broker_.is_bound());
+ return document_interface_broker_.get();
+}
+
AssociatedInterfaceProvider*
LocalFrameClientImpl::GetRemoteNavigationAssociatedInterfaces() {
return web_frame_->Client()->GetRemoteNavigationAssociatedInterfaces();
diff --git a/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index 518e9b24efa..e075470ebc5 100644
--- a/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -36,6 +36,7 @@
#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
@@ -51,9 +52,10 @@ struct WebScrollIntoViewParams;
class LocalFrameClientImpl final : public LocalFrameClient {
public:
- static LocalFrameClientImpl* Create(WebLocalFrameImpl*);
+ static LocalFrameClientImpl* Create(WebLocalFrameImpl*,
+ mojo::ScopedMessagePipeHandle);
- explicit LocalFrameClientImpl(WebLocalFrameImpl*);
+ LocalFrameClientImpl(WebLocalFrameImpl*, mojo::ScopedMessagePipeHandle);
~LocalFrameClientImpl() override;
void Trace(blink::Visitor*) override;
@@ -97,8 +99,7 @@ class LocalFrameClientImpl final : public LocalFrameClient {
WebHistoryCommitType,
bool content_initiated) override;
void DispatchWillCommitProvisionalLoad() override;
- void DispatchDidStartProvisionalLoad(DocumentLoader*,
- const ResourceRequest&) override;
+ void DispatchDidStartProvisionalLoad(DocumentLoader*) override;
void DispatchDidReceiveTitle(const String&) override;
void DispatchDidChangeIcons(IconType) override;
void DispatchDidCommitLoad(HistoryItem*,
@@ -126,6 +127,7 @@ class LocalFrameClientImpl final : public LocalFrameClient {
mojom::blink::BlobURLTokenPtr,
base::TimeTicks input_start_time,
const String& href_translate,
+ WebContentSecurityPolicyList,
mojom::blink::NavigationInitiatorPtr) override;
void DispatchWillSendSubmitEvent(HTMLFormElement*) override;
void DidStartLoading() override;
@@ -161,11 +163,6 @@ class LocalFrameClientImpl final : public LocalFrameClient {
// layer
DocumentLoader* CreateDocumentLoader(
LocalFrame*,
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType,
WebNavigationType,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) override;
@@ -180,6 +177,9 @@ class LocalFrameClientImpl final : public LocalFrameClient {
void TransitionToCommittedForNewPage() override;
LocalFrame* CreateFrame(const WTF::AtomicString& name,
HTMLFrameOwnerElement*) override;
+ std::pair<RemoteFrame*, base::UnguessableToken> CreatePortal(
+ HTMLPortalElement*,
+ mojom::blink::PortalRequest) override;
WebPluginContainerImpl* CreatePlugin(HTMLPlugInElement&,
const KURL&,
const Vector<WTF::String>&,
@@ -222,8 +222,6 @@ class LocalFrameClientImpl final : public LocalFrameClient {
override;
WebContentSettingsClient* GetContentSettingsClient() override;
- SharedWorkerRepositoryClient* GetSharedWorkerRepositoryClient() override;
-
std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
WebApplicationCacheHostClient*) override;
@@ -259,6 +257,9 @@ class LocalFrameClientImpl final : public LocalFrameClient {
std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override;
service_manager::InterfaceProvider* GetInterfaceProvider() override;
+
+ mojom::blink::DocumentInterfaceBroker* GetDocumentInterfaceBroker() override;
+
AssociatedInterfaceProvider* GetRemoteNavigationAssociatedInterfaces()
override;
@@ -308,6 +309,8 @@ class LocalFrameClientImpl final : public LocalFrameClient {
Member<WebLocalFrameImpl> web_frame_;
String user_agent_;
+
+ mojom::blink::DocumentInterfaceBrokerPtr document_interface_broker_;
};
DEFINE_TYPE_CASTS(LocalFrameClientImpl,
diff --git a/chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.cc b/chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.cc
deleted file mode 100644
index 79069a7d307..00000000000
--- a/chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h"
-
-#include <memory>
-#include <utility>
-#include "third_party/blink/public/platform/web_content_security_policy.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/web/blink.h"
-#include "third_party/blink/public/web/web_shared_worker.h"
-#include "third_party/blink/public/web/web_shared_worker_connect_listener.h"
-#include "third_party/blink/public/web/web_shared_worker_repository_client.h"
-#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/workers/shared_worker.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
-
-namespace blink {
-namespace {
-
-mojom::SharedWorkerCreationContextType ToCreationContextType(
- bool is_secure_context) {
- return is_secure_context ? mojom::SharedWorkerCreationContextType::kSecure
- : mojom::SharedWorkerCreationContextType::kNonsecure;
-}
-
-} // namespace
-
-// Implementation of the callback interface passed to the embedder. This will be
-// destructed when a connection to a shared worker is established.
-class SharedWorkerConnectListener final
- : public WebSharedWorkerConnectListener {
- public:
- explicit SharedWorkerConnectListener(SharedWorker* worker)
- : worker_(worker) {}
-
- ~SharedWorkerConnectListener() override {
- // We have lost our connection to the worker. If this happens before
- // Connected() is called, then it suggests that the document is gone or
- // going away.
- }
-
- // WebSharedWorkerConnectListener overrides.
-
- void WorkerCreated(
- mojom::SharedWorkerCreationContextType creation_context_type) override {
- worker_->SetIsBeingConnected(true);
-
- // No nested workers (for now) - connect() should only be called from
- // document context.
- DCHECK(worker_->GetExecutionContext()->IsDocument());
- DCHECK_EQ(creation_context_type,
- ToCreationContextType(
- worker_->GetExecutionContext()->IsSecureContext()));
- }
-
- void ScriptLoadFailed() override {
- worker_->DispatchEvent(*Event::CreateCancelable(event_type_names::kError));
- worker_->SetIsBeingConnected(false);
- }
-
- void Connected() override { worker_->SetIsBeingConnected(false); }
-
- void CountFeature(WebFeature feature) override {
- UseCounter::Count(worker_->GetExecutionContext(), feature);
- }
-
- Persistent<SharedWorker> worker_;
-};
-
-static WebSharedWorkerRepositoryClient::DocumentID GetId(void* document) {
- DCHECK(document);
- return reinterpret_cast<WebSharedWorkerRepositoryClient::DocumentID>(
- document);
-}
-
-void SharedWorkerRepositoryClientImpl::Connect(
- SharedWorker* worker,
- MessagePortChannel port,
- const KURL& url,
- mojom::blink::BlobURLTokenPtr blob_url_token,
- const String& name) {
- DCHECK(client_);
-
- // No nested workers (for now) - connect() should only be called from document
- // context.
- Document* document = To<Document>(worker->GetExecutionContext());
-
- // TODO(estark): this is broken, as it only uses the first header
- // when multiple might have been sent. Fix by making the
- // SharedWorkerConnectListener interface take a map that can contain
- // multiple headers.
- Vector<CSPHeaderAndType> headers =
- worker->GetExecutionContext()->GetContentSecurityPolicy()->Headers();
- WebString header;
- WebContentSecurityPolicyType header_type =
- kWebContentSecurityPolicyTypeReport;
-
- if (headers.size() > 0) {
- header = headers[0].first;
- header_type = static_cast<WebContentSecurityPolicyType>(headers[0].second);
- }
-
- bool is_secure_context = worker->GetExecutionContext()->IsSecureContext();
- std::unique_ptr<WebSharedWorkerConnectListener> listener =
- std::make_unique<SharedWorkerConnectListener>(worker);
- client_->Connect(
- url, name, GetId(document), header, header_type,
- worker->GetExecutionContext()->GetSecurityContext().AddressSpace(),
- ToCreationContextType(is_secure_context), std::move(port),
- blob_url_token.PassInterface().PassHandle(), std::move(listener));
-}
-
-void SharedWorkerRepositoryClientImpl::DocumentDetached(Document* document) {
- DCHECK(client_);
- client_->DocumentDetached(GetId(document));
-}
-
-SharedWorkerRepositoryClientImpl::SharedWorkerRepositoryClientImpl(
- WebSharedWorkerRepositoryClient* client)
- : client_(client) {}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h b/chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h
deleted file mode 100644
index 3b0b0461192..00000000000
--- a/chromium/third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXPORTED_SHARED_WORKER_REPOSITORY_CLIENT_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EXPORTED_SHARED_WORKER_REPOSITORY_CLIENT_IMPL_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/workers/shared_worker_repository_client.h"
-
-namespace blink {
-
-class WebSharedWorkerRepositoryClient;
-
-class CORE_EXPORT SharedWorkerRepositoryClientImpl final
- : public SharedWorkerRepositoryClient {
- USING_FAST_MALLOC(SharedWorkerRepositoryClientImpl);
-
- public:
- static std::unique_ptr<SharedWorkerRepositoryClientImpl> Create(
- WebSharedWorkerRepositoryClient* client) {
- return base::WrapUnique(new SharedWorkerRepositoryClientImpl(client));
- }
-
- ~SharedWorkerRepositoryClientImpl() override = default;
-
- void Connect(SharedWorker*,
- MessagePortChannel,
- const KURL&,
- mojom::blink::BlobURLTokenPtr,
- const String& name) override;
- void DocumentDetached(Document*) override;
-
- private:
- explicit SharedWorkerRepositoryClientImpl(WebSharedWorkerRepositoryClient*);
-
- WebSharedWorkerRepositoryClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(SharedWorkerRepositoryClientImpl);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EXPORTED_SHARED_WORKER_REPOSITORY_CLIENT_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
index 01f76873441..fdef3ea01a2 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
@@ -112,7 +112,7 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final
void DidReceiveResponse(unsigned long,
const ResourceResponse&,
std::unique_ptr<WebDataConsumerHandle>) override;
- void DidDownloadData(int /*dataLength*/) override;
+ void DidDownloadData(unsigned long long /*dataLength*/) override;
void DidReceiveData(const char*, unsigned /*dataLength*/) override;
void DidReceiveCachedMetadata(const char*, int /*dataLength*/) override;
void DidFinishLoading(unsigned long /*identifier*/) override;
@@ -241,7 +241,7 @@ void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveResponse(
}
void WebAssociatedURLLoaderImpl::ClientAdapter::DidDownloadData(
- int data_length) {
+ unsigned long long data_length) {
if (!client_)
return;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc b/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
index 1af35bb2efd..78b1bfd6b86 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
@@ -33,6 +33,7 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
@@ -92,7 +93,7 @@ class WebAssociatedURLLoaderTest : public testing::Test,
"invisible_iframe.html", "visible_iframe.html",
"zero_sized_iframe.html",
};
- for (size_t i = 0; i < arraysize(iframe_support_files); ++i) {
+ for (size_t i = 0; i < base::size(iframe_support_files); ++i) {
RegisterMockedUrl(url_root, iframe_support_files[i]);
}
@@ -122,7 +123,8 @@ class WebAssociatedURLLoaderTest : public testing::Test,
const WebURLResponse& redirect_response) override {
will_follow_redirect_ = true;
EXPECT_EQ(expected_new_url_, new_url);
- EXPECT_EQ(expected_redirect_response_.Url(), redirect_response.Url());
+ EXPECT_EQ(expected_redirect_response_.CurrentRequestUrl(),
+ redirect_response.CurrentRequestUrl());
EXPECT_EQ(expected_redirect_response_.HttpStatusCode(),
redirect_response.HttpStatusCode());
EXPECT_EQ(expected_redirect_response_.MimeType(),
@@ -138,11 +140,14 @@ class WebAssociatedURLLoaderTest : public testing::Test,
void DidReceiveResponse(const WebURLResponse& response) override {
did_receive_response_ = true;
actual_response_ = WebURLResponse(response);
- EXPECT_EQ(expected_response_.Url(), response.Url());
+ EXPECT_EQ(expected_response_.CurrentRequestUrl(),
+ response.CurrentRequestUrl());
EXPECT_EQ(expected_response_.HttpStatusCode(), response.HttpStatusCode());
}
- void DidDownloadData(int data_length) override { did_download_data_ = true; }
+ void DidDownloadData(unsigned long long data_length) override {
+ did_download_data_ = true;
+ }
void DidReceiveData(const char* data, int data_length) override {
did_receive_data_ = true;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
index 7520cb45f8d..73736ecc81d 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
@@ -122,10 +122,16 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
instance_->QuitNow();
}
+ static void PauseForPageWait(WebLocalFrameImpl* frame) {
+ if (instance_)
+ instance_->RunForPageWait(frame);
+ }
+
private:
ClientMessageLoopAdapter(
std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop)
: running_for_debug_break_(false),
+ running_for_page_wait_(false),
message_loop_(std::move(message_loop)) {
DCHECK(message_loop_.get());
}
@@ -135,7 +141,17 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
return;
running_for_debug_break_ = true;
- RunLoop(WebLocalFrameImpl::FromFrame(frame));
+ if (!running_for_page_wait_)
+ RunLoop(WebLocalFrameImpl::FromFrame(frame));
+ }
+
+ void RunForPageWait(WebLocalFrameImpl* frame) {
+ if (running_for_page_wait_)
+ return;
+
+ running_for_page_wait_ = true;
+ if (!running_for_debug_break_)
+ RunLoop(frame);
}
void RunLoop(WebLocalFrameImpl* frame) {
@@ -158,16 +174,36 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
void QuitNow() override {
if (running_for_debug_break_) {
running_for_debug_break_ = false;
- // Undo steps (3), (2) and (1) from above.
- // NOTE: This code used to be above right after the |mesasge_loop_->Run()|
- // code, but it is moved here to support browser-side navigation.
- message_loop_->QuitNow();
- WebView::DidExitModalLoop();
- WebFrameWidgetBase::SetIgnoreInputEvents(false);
+ if (!running_for_page_wait_)
+ DoQuit();
+ }
+ }
+
+ bool QuitForPageWait() {
+ if (running_for_page_wait_) {
+ running_for_page_wait_ = false;
+ if (!running_for_debug_break_)
+ DoQuit();
+ return true;
}
+ return false;
+ }
+
+ void DoQuit() {
+ // Undo steps (3), (2) and (1) from above.
+ // NOTE: This code used to be above right after the |mesasge_loop_->Run()|
+ // code, but it is moved here to support browser-side navigation.
+ message_loop_->QuitNow();
+ WebView::DidExitModalLoop();
+ WebFrameWidgetBase::SetIgnoreInputEvents(false);
}
void RunIfWaitingForDebugger(LocalFrame* frame) override {
+ // If we've paused for Page.waitForDebugger, handle it ourselves.
+ if (QuitForPageWait())
+ return;
+
+ // Otherwise, pass to the client (embedded workers do it differently).
WebDevToolsAgentImpl* agent =
WebLocalFrameImpl::FromFrame(frame)->DevToolsAgentImpl();
if (agent && agent->worker_client_)
@@ -175,6 +211,7 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
}
bool running_for_debug_break_;
+ bool running_for_page_wait_;
std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop_;
static ClientMessageLoopAdapter* instance_;
@@ -258,7 +295,8 @@ void WebDevToolsAgentImpl::AttachSession(DevToolsSession* session,
session->Append(MakeGarbageCollected<InspectorEmulationAgent>(
web_local_frame_impl_.Get()));
- session->Append(new InspectorTestingAgent(inspected_frames));
+ session->Append(
+ MakeGarbageCollected<InspectorTestingAgent>(inspected_frames));
// Call session init callbacks registered from higher layers.
CoreInitializer::GetInstance().InitInspectorAgentSession(
@@ -307,7 +345,7 @@ WebDevToolsAgentImpl::WebDevToolsAgentImpl(
MakeGarbageCollected<InspectorResourceContainer>(inspected_frames_)),
include_view_agents_(include_view_agents) {
DCHECK(IsMainThread());
- agent_ = new DevToolsAgent(
+ agent_ = MakeGarbageCollected<DevToolsAgent>(
this, inspected_frames_.Get(), probe_sink_.Get(),
web_local_frame_impl_->GetFrame()->GetInspectorTaskRunner(),
Platform::Current()->GetIOTaskRunner());
@@ -419,7 +457,11 @@ void WebDevToolsAgentImpl::PageLayoutInvalidated(bool resized) {
it.value->PageLayoutInvalidated(resized);
}
-bool WebDevToolsAgentImpl::IsInspectorLayer(GraphicsLayer* layer) {
+void WebDevToolsAgentImpl::WaitForDebugger() {
+ ClientMessageLoopAdapter::PauseForPageWait(web_local_frame_impl_);
+}
+
+bool WebDevToolsAgentImpl::IsInspectorLayer(const cc::Layer* layer) {
for (auto& it : overlay_agents_) {
if (it.value->IsInspectorLayer(layer))
return true;
@@ -439,6 +481,12 @@ void WebDevToolsAgentImpl::UpdateOverlays() {
it.value->UpdateAllOverlayLifecyclePhases();
}
+void WebDevToolsAgentImpl::PaintOverlays(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ for (auto& it : overlay_agents_)
+ it.value->PaintOverlay(context);
+}
+
void WebDevToolsAgentImpl::DispatchBufferedTouchEvents() {
for (auto& it : overlay_agents_)
it.value->DispatchBufferedTouchEvents();
diff --git a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
index 2d963761a90..8039d45c91e 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
@@ -45,7 +45,7 @@
namespace blink {
class ClientMessageLoopAdapter;
-class GraphicsLayer;
+class GraphicsContext;
class InspectedFrames;
class InspectorNetworkAgent;
class InspectorOverlayAgent;
@@ -80,7 +80,11 @@ class CORE_EXPORT WebDevToolsAgentImpl final
void WillBeDestroyed();
void FlushProtocolNotifications();
+
+ bool HasOverlays() const { return !overlay_agents_.IsEmpty(); }
void UpdateOverlays();
+ void PaintOverlays(GraphicsContext&); // For CompositeAfterPaint.
+
bool HandleInputEvent(const WebInputEvent&);
void DispatchBufferedTouchEvents();
void BindRequest(mojom::blink::DevToolsAgentHostAssociatedPtrInfo,
@@ -104,9 +108,10 @@ class CORE_EXPORT WebDevToolsAgentImpl final
// InspectorPageAgent::Client implementation.
void PageLayoutInvalidated(bool resized) override;
+ void WaitForDebugger() override;
// InspectorLayerTreeAgent::Client implementation.
- bool IsInspectorLayer(GraphicsLayer*) override;
+ bool IsInspectorLayer(const cc::Layer*) override;
// Thread::TaskObserver implementation.
void WillProcessTask(const base::PendingTask&) override;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document.cc b/chromium/third_party/blink/renderer/core/exported/web_document.cc
index 1c09baa37b6..49a6ac70def 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_document.cc
@@ -154,21 +154,11 @@ WebString WebDocument::Title() const {
return WebString(ConstUnwrap<Document>()->title());
}
-WebString WebDocument::ContentAsTextForTesting(bool use_inner_text) const {
+WebString WebDocument::ContentAsTextForTesting() const {
Element* document_element = ConstUnwrap<Document>()->documentElement();
if (!document_element)
return WebString();
- if (use_inner_text)
- return document_element->innerText();
-
- // TODO(editing-dev): We should use |Element::innerText()|.
- const_cast<Document*>(ConstUnwrap<Document>())
- ->UpdateStyleAndLayoutIgnorePendingStylesheetsForNode(document_element);
- if (!document_element->GetLayoutObject())
- return document_element->textContent(true);
- return WebString(
- PlainText(EphemeralRange::RangeOfContents(*document_element),
- TextIteratorBehavior::Builder().SetForInnerText(true).Build()));
+ return document_element->innerText();
}
WebElementCollection WebDocument::All() {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
index f7dc115595f..a406461190e 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
@@ -48,8 +48,38 @@
namespace blink {
-const WebURLRequest& WebDocumentLoaderImpl::OriginalRequest() const {
- return original_request_wrapper_;
+// static
+bool WebDocumentLoader::WillLoadUrlAsEmpty(const WebURL& url) {
+ return DocumentLoader::WillLoadUrlAsEmpty(url);
+}
+
+WebURL WebDocumentLoaderImpl::OriginalUrl() const {
+ return DocumentLoader::OriginalUrl();
+}
+
+WebString WebDocumentLoaderImpl::OriginalReferrer() const {
+ return DocumentLoader::OriginalReferrer();
+}
+
+WebURL WebDocumentLoaderImpl::GetUrl() const {
+ return request_wrapper_.Url();
+}
+
+WebString WebDocumentLoaderImpl::HttpMethod() const {
+ return request_wrapper_.HttpMethod();
+}
+
+mojom::FetchCacheMode WebDocumentLoaderImpl::GetCacheMode() const {
+ return request_wrapper_.GetCacheMode();
+}
+
+WebString WebDocumentLoaderImpl::Referrer() const {
+ return DocumentLoader::Referrer();
+}
+
+network::mojom::ReferrerPolicy WebDocumentLoaderImpl::GetReferrerPolicy()
+ const {
+ return request_wrapper_.GetReferrerPolicy();
}
const WebURLRequest& WebDocumentLoaderImpl::GetRequest() const {
@@ -99,23 +129,10 @@ void WebDocumentLoaderImpl::SetExtraData(
WebDocumentLoaderImpl::WebDocumentLoaderImpl(
LocalFrame* frame,
- const ResourceRequest& request,
- const SubstituteData& data,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params)
- : DocumentLoader(frame,
- request,
- data,
- client_redirect_policy,
- devtools_navigation_token,
- load_type,
- navigation_type,
- std::move(navigation_params)),
- original_request_wrapper_(DocumentLoader::OriginalRequest()),
- request_wrapper_(DocumentLoader::GetRequest()),
+ : DocumentLoader(frame, navigation_type, std::move(navigation_params)),
+ request_wrapper_(request_),
response_wrapper_(DocumentLoader::GetResponse()) {}
WebDocumentLoaderImpl::~WebDocumentLoaderImpl() {
@@ -144,10 +161,6 @@ WebDocumentLoaderImpl::GetServiceWorkerNetworkProvider() {
return DocumentLoader::GetServiceWorkerNetworkProvider();
}
-void WebDocumentLoaderImpl::ResetSourceLocation() {
- DocumentLoader::ResetSourceLocation();
-}
-
void WebDocumentLoaderImpl::BlockParser() {
DocumentLoader::BlockParser();
}
@@ -169,6 +182,10 @@ bool WebDocumentLoaderImpl::HadUserGesture() const {
return DocumentLoader::had_transient_activation();
}
+bool WebDocumentLoaderImpl::IsListingFtpDirectory() const {
+ return DocumentLoader::IsListingFtpDirectory();
+}
+
void WebDocumentLoaderImpl::Trace(blink::Visitor* visitor) {
DocumentLoader::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h
index d83f96afc82..dc6a4afee30 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h
@@ -50,11 +50,6 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
public WebDocumentLoader {
public:
WebDocumentLoaderImpl(LocalFrame*,
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params);
@@ -63,7 +58,13 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
}
// WebDocumentLoader methods:
- const WebURLRequest& OriginalRequest() const override;
+ WebURL OriginalUrl() const override;
+ WebString OriginalReferrer() const override;
+ WebURL GetUrl() const override;
+ WebString HttpMethod() const override;
+ mojom::FetchCacheMode GetCacheMode() const override;
+ WebString Referrer() const override;
+ network::mojom::ReferrerPolicy GetReferrerPolicy() const override;
const WebURLRequest& GetRequest() const override;
const WebURLResponse& GetResponse() const override;
bool HasUnreachableURL() const override;
@@ -79,12 +80,12 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
void SetServiceWorkerNetworkProvider(
std::unique_ptr<WebServiceWorkerNetworkProvider>) override;
WebServiceWorkerNetworkProvider* GetServiceWorkerNetworkProvider() override;
- void ResetSourceLocation() override;
void BlockParser() override;
void ResumeParser() override;
bool IsArchive() const override;
WebArchiveInfo GetArchiveInfo() const override;
bool HadUserGesture() const override;
+ bool IsListingFtpDirectory() const override;
void Trace(blink::Visitor*) override;
@@ -95,7 +96,6 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
// Mutable because the const getters will magically sync these to the
// latest version from WebKit.
- mutable WrappedResourceRequest original_request_wrapper_;
mutable WrappedResourceRequest request_wrapper_;
mutable WrappedResourceResponse response_wrapper_;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc b/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
index 5ff778ae876..eea0d561424 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
@@ -73,8 +73,7 @@ class TestDocumentSubresourceFilter : public WebDocumentSubresourceFilter {
class SubresourceFilteringWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
- void DidStartProvisionalLoad(WebDocumentLoader* data_source,
- WebURLRequest& request) override {
+ void DidStartProvisionalLoad(WebDocumentLoader* data_source) override {
// Normally, the filter should be set when the load is committed. For
// the sake of this test, however, inject it earlier to verify that it
// is not consulted for the main resource load.
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_test.cc b/chromium/third_party/blink/renderer/core/exported/web_document_test.cc
index 0f691ce334c..9d982f033fe 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_test.cc
@@ -338,10 +338,17 @@ Document* WebDocumentFirstPartyTest::NestedNestedDocument() const {
->GetDocument();
}
+bool OriginsEqual(const char* path,
+ scoped_refptr<const SecurityOrigin> origin) {
+ return SecurityOrigin::Create(ToOriginA(path))
+ ->IsSameSchemeHostPort(origin.get());
+}
+
TEST_F(WebDocumentFirstPartyTest, Empty) {
Load(g_empty_file);
ASSERT_EQ(ToOriginA(g_empty_file), TopDocument()->SiteForCookies());
+ ASSERT_TRUE(OriginsEqual(g_empty_file, TopDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginA) {
@@ -349,6 +356,10 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginA) {
ASSERT_EQ(ToOriginA(g_nested_origin_a), TopDocument()->SiteForCookies());
ASSERT_EQ(ToOriginA(g_nested_origin_a), NestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a, TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(
+ OriginsEqual(g_nested_origin_a, NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginSubA) {
@@ -357,6 +368,11 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginSubA) {
ASSERT_EQ(ToOriginA(g_nested_origin_sub_a), TopDocument()->SiteForCookies());
ASSERT_EQ(ToOriginA(g_nested_origin_sub_a),
NestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(
+ OriginsEqual(g_nested_origin_sub_a, TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(
+ OriginsEqual(g_nested_origin_sub_a, NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginSecureA) {
@@ -366,6 +382,11 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginSecureA) {
TopDocument()->SiteForCookies());
ASSERT_EQ(ToOriginA(g_nested_origin_secure_a),
NestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(
+ OriginsEqual(g_nested_origin_secure_a, TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_secure_a,
+ NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginAInOriginA) {
@@ -377,6 +398,11 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginAInOriginA) {
NestedDocument()->SiteForCookies());
ASSERT_EQ(ToOriginA(g_nested_origin_a_in_origin_a),
NestedNestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_a,
+ TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_a,
+ NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginAInOriginB) {
@@ -386,6 +412,13 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginAInOriginB) {
TopDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedNestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_b,
+ TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_b,
+ NestedDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_b,
+ NestedNestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginB) {
@@ -393,6 +426,10 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginB) {
ASSERT_EQ(ToOriginA(g_nested_origin_b), TopDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b, TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(
+ OriginsEqual(g_nested_origin_b, NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginBInOriginA) {
@@ -403,6 +440,13 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginBInOriginA) {
ASSERT_EQ(ToOriginA(g_nested_origin_b_in_origin_a),
NestedDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedNestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b_in_origin_a,
+ TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b_in_origin_a,
+ NestedDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b_in_origin_a,
+ NestedNestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedOriginBInOriginB) {
@@ -412,6 +456,13 @@ TEST_F(WebDocumentFirstPartyTest, NestedOriginBInOriginB) {
TopDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedNestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b_in_origin_b,
+ TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b_in_origin_b,
+ NestedDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_b_in_origin_b,
+ NestedNestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedSrcdoc) {
@@ -419,6 +470,10 @@ TEST_F(WebDocumentFirstPartyTest, NestedSrcdoc) {
ASSERT_EQ(ToOriginA(g_nested_src_doc), TopDocument()->SiteForCookies());
ASSERT_EQ(ToOriginA(g_nested_src_doc), NestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_src_doc, TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(
+ OriginsEqual(g_nested_src_doc, NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest, NestedData) {
@@ -426,6 +481,9 @@ TEST_F(WebDocumentFirstPartyTest, NestedData) {
ASSERT_EQ(ToOriginA(g_nested_data), TopDocument()->SiteForCookies());
ASSERT_EQ(NullURL(), NestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_data, TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_data, NestedDocument()->TopFrameOrigin()));
}
TEST_F(WebDocumentFirstPartyTest,
@@ -440,6 +498,13 @@ TEST_F(WebDocumentFirstPartyTest,
NestedDocument()->SiteForCookies());
ASSERT_EQ(ToOriginA(g_nested_origin_a_in_origin_b),
NestedNestedDocument()->SiteForCookies());
+
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_b,
+ TopDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_b,
+ NestedDocument()->TopFrameOrigin()));
+ ASSERT_TRUE(OriginsEqual(g_nested_origin_a_in_origin_b,
+ NestedNestedDocument()->TopFrameOrigin()));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
index 867f8106544..5d68324b9c7 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/public/web/web_frame_content_dumper.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_view.h"
@@ -26,138 +27,6 @@ namespace blink {
namespace {
-const int text_dumper_max_depth = 512;
-
-bool IsRenderedAndVisible(const Node& node) {
- if (node.GetLayoutObject() &&
- node.GetLayoutObject()->Style()->Visibility() == EVisibility::kVisible)
- return true;
- if (node.IsElementNode() && ToElement(node).HasDisplayContentsStyle())
- return true;
- return false;
-}
-
-size_t RequiredLineBreaksAround(const Node& node) {
- if (!IsRenderedAndVisible(node))
- return 0;
- if (node.IsTextNode())
- return 0;
- if (IsHTMLParagraphElement(node))
- return 2;
- if (LayoutObject* layout_object = node.GetLayoutObject()) {
- if (!layout_object->Style()->IsDisplayInlineType())
- return 1;
- if (layout_object->Style()->Display() == EDisplay::kTableCaption)
- return 1;
- }
- return 0;
-}
-
-// This class dumps innerText of a node into a StringBuilder, following the spec
-// [*] but with a simplified whitespace handling algorithm when processing text
-// nodes: only leading and trailing collapsed whitespaces are removed; all other
-// whitespace characters are left as-is, without any collapsing or conversion.
-// For example, from HTML <p>\na\n\nb\n</p>, we get text dump "a\n\nb".
-// [*] https://developer.mozilla.org/en-US/docs/Web/API/Node/innerText
-class TextDumper final {
- STACK_ALLOCATED();
-
- public:
- TextDumper(StringBuilder& builder, size_t max_length)
- : builder_(builder), max_length_(max_length) {}
-
- void DumpTextFrom(const Node& node) {
- DCHECK(!has_emitted_);
- DCHECK(!required_line_breaks_);
- HandleNode(node, 0);
- }
-
- private:
- void HandleNode(const Node& node, int depth) {
- const size_t required_line_breaks_around = RequiredLineBreaksAround(node);
- AddRequiredLineBreaks(required_line_breaks_around);
-
- if (depth < text_dumper_max_depth) {
- for (const Node& child : NodeTraversal::ChildrenOf(node)) {
- HandleNode(child, depth + 1);
- if (builder_.length() >= max_length_)
- return;
- }
- }
-
- if (!IsRenderedAndVisible(node))
- return;
-
- if (node.IsTextNode())
- return HandleTextNode(ToText(node));
-
- if (IsHTMLBRElement(node))
- return DumpText("\n");
-
- if (LayoutObject* layout_object = node.GetLayoutObject()) {
- if (layout_object->IsTableCell() &&
- ToLayoutTableCell(layout_object)->NextCell())
- return DumpText("\t");
- if (layout_object->IsTableRow() &&
- ToLayoutTableRow(layout_object)->NextRow())
- return DumpText("\n");
- }
-
- AddRequiredLineBreaks(required_line_breaks_around);
- }
-
- void HandleTextNode(const Text& node) {
- const LayoutText* layout_text = node.GetLayoutObject();
- if (!layout_text)
- return;
- if (layout_text->IsTextFragment() &&
- ToLayoutTextFragment(layout_text)->IsRemainingTextLayoutObject()) {
- const LayoutText* first_letter =
- ToLayoutText(AssociatedLayoutObjectOf(node, 0));
- if (first_letter && first_letter != layout_text)
- HandleLayoutText(*first_letter);
- }
- HandleLayoutText(*layout_text);
- }
-
- void HandleLayoutText(const LayoutText& text) {
- if (!text.HasNonCollapsedText())
- return;
- size_t text_start = text.CaretMinOffset();
- size_t text_end = text.CaretMaxOffset();
- String dump = text.GetText().Substring(text_start, text_end - text_start);
- DumpText(dump);
- }
-
- void AddRequiredLineBreaks(size_t required) {
- required_line_breaks_ = std::max(required, required_line_breaks_);
- }
-
- void DumpText(String text) {
- if (!text.length())
- return;
-
- if (has_emitted_ && required_line_breaks_) {
- for (size_t i = 0; i < required_line_breaks_; ++i)
- builder_.Append('\n');
- }
- required_line_breaks_ = 0;
- builder_.Append(text);
- has_emitted_ = true;
-
- if (builder_.length() > max_length_)
- builder_.Resize(max_length_);
- }
-
- bool has_emitted_ = false;
- size_t required_line_breaks_ = 0;
-
- StringBuilder& builder_;
- const size_t max_length_;
-
- DISALLOW_COPY_AND_ASSIGN(TextDumper);
-};
-
void FrameContentAsPlainText(size_t max_chars,
LocalFrame* frame,
StringBuilder& output) {
@@ -171,12 +40,15 @@ void FrameContentAsPlainText(size_t max_chars,
DCHECK(!frame->View()->NeedsLayout());
DCHECK(!document->NeedsLayoutTreeUpdate());
- if (document->documentElement())
- TextDumper(output, max_chars).DumpTextFrom(*document->documentElement());
+ if (document->documentElement()) {
+ output.Append(document->documentElement()->innerText());
+ if (output.length() >= max_chars)
+ output.Resize(max_chars);
+ }
// The separator between frames when the frames are converted to plain text.
const LChar kFrameSeparator[] = {'\n', '\n'};
- const size_t frame_separator_length = arraysize(kFrameSeparator);
+ const size_t frame_separator_length = base::size(kFrameSeparator);
// Recursively walk the children.
const FrameTree& frame_tree = frame->Tree();
diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_serializer.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_serializer.cc
index 277218ce3cb..9e4bae89336 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_frame_serializer.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_frame_serializer.cc
@@ -62,6 +62,7 @@
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/platform/histogram.h"
@@ -402,14 +403,10 @@ std::pair<Node*, Element*> MHTMLFrameSerializerDelegate::GetAuxiliaryDOMTree(
bool CacheControlNoStoreHeaderPresent(
const WebLocalFrameImpl& web_local_frame) {
- const ResourceResponse& response =
- web_local_frame.GetDocumentLoader()->GetResponse().ToResourceResponse();
- if (response.CacheControlContainsNoStore())
- return true;
-
- const ResourceRequest& request =
- web_local_frame.GetDocumentLoader()->GetRequest().ToResourceRequest();
- return request.CacheControlContainsNoStore();
+ return web_local_frame.GetDocumentLoader()
+ ->GetResponse()
+ .ToResourceResponse()
+ .CacheControlContainsNoStore();
}
bool FrameShouldBeSerializedAsMHTML(
diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
index 22f4dfe135d..47b6e810939 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
@@ -321,7 +321,7 @@ TEST_F(WebFrameSerializerSanitizationTest, ImageLoadedFromSrcForNormalDPI) {
}
TEST_F(WebFrameSerializerSanitizationTest, RemovePopupOverlayIfRequested) {
- WebView()->Resize(WebSize(500, 500));
+ WebView()->MainFrameWidget()->Resize(WebSize(500, 500));
SetRemovePopupOverlay(true);
String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
@@ -331,7 +331,7 @@ TEST_F(WebFrameSerializerSanitizationTest, RemovePopupOverlayIfRequested) {
}
TEST_F(WebFrameSerializerSanitizationTest, PopupOverlayNotFound) {
- WebView()->Resize(WebSize(500, 500));
+ WebView()->MainFrameWidget()->Resize(WebSize(500, 500));
SetRemovePopupOverlay(true);
String mhtml =
GenerateMHTMLFromHtml("http://www.test.com", "text_only_page.html");
@@ -340,7 +340,7 @@ TEST_F(WebFrameSerializerSanitizationTest, PopupOverlayNotFound) {
}
TEST_F(WebFrameSerializerSanitizationTest, KeepPopupOverlayIfNotRequested) {
- WebView()->Resize(WebSize(500, 500));
+ WebView()->MainFrameWidget()->Resize(WebSize(500, 500));
SetRemovePopupOverlay(false);
String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc
index 6a958b1f7f0..4bac8b63743 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -37,6 +37,7 @@
#include <memory>
#include <set>
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
#include "mojo/public/cpp/bindings/binding.h"
@@ -44,8 +45,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/common/page/launching_process_state.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_cache.h"
#include "third_party/blink/public/platform/web_coalesced_input_event.h"
@@ -149,6 +150,8 @@
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
#include "third_party/blink/renderer/platform/testing/scoped_fake_plugin_registry.h"
@@ -347,7 +350,8 @@ class WebFrameTest : public testing::Test {
IntRect& caret_bounds) {
Element* element = helper.GetWebView()->FocusedElement();
WebRect caret_in_viewport, unused;
- helper.GetWebView()->SelectionBounds(caret_in_viewport, unused);
+ helper.GetWebView()->MainFrameWidget()->SelectionBounds(caret_in_viewport,
+ unused);
caret_bounds =
helper.GetWebView()->GetPage()->GetVisualViewport().ViewportToRootFrame(
caret_in_viewport);
@@ -452,7 +456,6 @@ TEST_F(WebFrameTest, RequestExecuteScript) {
TEST_F(WebFrameTest, SuspendedRequestExecuteScript) {
RegisterMockedHttpURLLoad("foo.html");
- RegisterMockedHttpURLLoad("bar.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
@@ -462,11 +465,7 @@ TEST_F(WebFrameTest, SuspendedRequestExecuteScript) {
web_view_helper.LocalMainFrame()->MainWorldScriptContext());
// Suspend scheduled tasks so the script doesn't run.
- web_view_helper.GetWebView()
- ->MainFrameImpl()
- ->GetFrame()
- ->GetDocument()
- ->PauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(true);
web_view_helper.GetWebView()
->MainFrameImpl()
->RequestExecuteScriptAndReturnValue(
@@ -474,10 +473,7 @@ TEST_F(WebFrameTest, SuspendedRequestExecuteScript) {
RunPendingTasks();
EXPECT_FALSE(callback_helper.DidComplete());
- // If the frame navigates, pending scripts should be removed, but the callback
- // should always be ran.
- frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
- base_url_ + "bar.html");
+ web_view_helper.Reset();
EXPECT_TRUE(callback_helper.DidComplete());
EXPECT_EQ(String(), callback_helper.StringValue());
}
@@ -526,7 +522,7 @@ TEST_F(WebFrameTest, RequestExecuteV8FunctionWhileSuspended) {
// Suspend scheduled tasks so the script doesn't run.
WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
- main_frame->GetFrame()->GetDocument()->PauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(true);
ScriptExecutionCallbackHelper callback_helper(context);
v8::Local<v8::Function> function =
@@ -537,7 +533,7 @@ TEST_F(WebFrameTest, RequestExecuteV8FunctionWhileSuspended) {
RunPendingTasks();
EXPECT_FALSE(callback_helper.DidComplete());
- main_frame->GetFrame()->GetDocument()->UnpauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(false);
RunPendingTasks();
EXPECT_TRUE(callback_helper.DidComplete());
EXPECT_EQ("hello", callback_helper.StringValue());
@@ -557,7 +553,7 @@ TEST_F(WebFrameTest, RequestExecuteV8FunctionWhileSuspendedWithUserGesture) {
// Suspend scheduled tasks so the script doesn't run.
WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
- main_frame->GetFrame()->GetDocument()->PauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(true);
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Local<v8::Context> context =
@@ -576,7 +572,7 @@ TEST_F(WebFrameTest, RequestExecuteV8FunctionWhileSuspendedWithUserGesture) {
RunPendingTasks();
EXPECT_FALSE(callback_helper.DidComplete());
- main_frame->GetFrame()->GetDocument()->UnpauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(false);
RunPendingTasks();
EXPECT_TRUE(callback_helper.DidComplete());
EXPECT_EQ(true, callback_helper.BoolValue());
@@ -643,23 +639,22 @@ TEST_F(WebFrameTest, CallingPostPausableTaskWhilePaused)
ScriptState::Scope scope(ToScriptStateForMainWorld(main_frame->GetFrame()));
// Suspend scheduled tasks so the script doesn't run.
- main_frame->GetFrame()->GetDocument()->PauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(true);
ScriptNotPausedCallbackHelper callback_helper;
main_frame->PostPausableTask(callback_helper.GetCallback());
RunPendingTasks();
EXPECT_FALSE(callback_helper.result());
- main_frame->GetFrame()->GetDocument()->UnpauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(false);
RunPendingTasks();
ASSERT_TRUE(callback_helper.result());
EXPECT_EQ(WebLocalFrame::PausableTaskResult::kReady,
*callback_helper.result());
}
-TEST_F(WebFrameTest, CallingPostPausableTaskAndNavigating) {
+TEST_F(WebFrameTest, CallingPostPausableTaskAndDestroying) {
RegisterMockedHttpURLLoad("foo.html");
- RegisterMockedHttpURLLoad("bar.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
@@ -668,17 +663,14 @@ TEST_F(WebFrameTest, CallingPostPausableTaskAndNavigating) {
ScriptState::Scope scope(ToScriptStateForMainWorld(main_frame->GetFrame()));
// Suspend scheduled tasks so the script doesn't run.
- main_frame->GetFrame()->GetDocument()->PauseScheduledTasks();
+ web_view_helper.GetWebView()->GetPage()->SetPaused(true);
ScriptNotPausedCallbackHelper callback_helper;
main_frame->PostPausableTask(callback_helper.GetCallback());
RunPendingTasks();
EXPECT_FALSE(callback_helper.result());
- // If the frame navigates, pending scripts should be removed, but the callback
- // should always be ran.
- frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
- base_url_ + "bar.html");
+ web_view_helper.Reset();
ASSERT_TRUE(callback_helper.result());
EXPECT_EQ(WebLocalFrame::PausableTaskResult::kContextInvalidOrDestroyed,
*callback_helper.result());
@@ -1881,7 +1873,7 @@ TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
"viewport-auto-initial-scale.html",
"viewport-target-densitydpi-device-and-fixed-width.html"};
float page_scale_factors[] = {0.5f, 1.0f};
- for (size_t i = 0; i < arraysize(pages); ++i)
+ for (size_t i = 0; i < base::size(pages); ++i)
RegisterMockedHttpURLLoad(pages[i]);
FixedLayoutTestWebViewClient client;
@@ -1890,7 +1882,7 @@ TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
int viewport_height = 300;
float enforced_page_scale_factor = 0.75f;
- for (size_t i = 0; i < arraysize(pages); ++i) {
+ for (size_t i = 0; i < base::size(pages); ++i) {
for (int quirk_enabled = 0; quirk_enabled <= 1; ++quirk_enabled) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + pages[i], nullptr, &client,
@@ -1903,7 +1895,7 @@ TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
web_view_helper.Resize(WebSize(viewport_width, viewport_height));
float expected_page_scale_factor =
- quirk_enabled && i < arraysize(page_scale_factors)
+ quirk_enabled && i < base::size(page_scale_factors)
? page_scale_factors[i]
: enforced_page_scale_factor;
EXPECT_EQ(expected_page_scale_factor,
@@ -2755,7 +2747,7 @@ TEST_F(WebFrameTest, targetDensityDpiHigh) {
int viewport_width = 640;
int viewport_height = 480;
- for (size_t i = 0; i < arraysize(device_scale_factors); ++i) {
+ for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
float device_scale_factor = device_scale_factors[i];
float device_dpi = device_scale_factor * 160.0f;
client.screen_info_.device_scale_factor = device_scale_factor;
@@ -2803,7 +2795,7 @@ TEST_F(WebFrameTest, targetDensityDpiDevice) {
int viewport_width = 640;
int viewport_height = 480;
- for (size_t i = 0; i < arraysize(device_scale_factors); ++i) {
+ for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
client.screen_info_.device_scale_factor = device_scale_factors[i];
frame_test_helpers::WebViewHelper web_view_helper;
@@ -2846,7 +2838,7 @@ TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth) {
int viewport_width = 640;
int viewport_height = 480;
- for (size_t i = 0; i < arraysize(device_scale_factors); ++i) {
+ for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
client.screen_info_.device_scale_factor = device_scale_factors[i];
frame_test_helpers::WebViewHelper web_view_helper;
@@ -3233,7 +3225,8 @@ class WebFrameResizeTest : public WebFrameTest {
WebSize(viewport_size.width, viewport_size.height));
web_view_helper.GetWebView()->SetPageScaleFactor(
initial_page_scale_factor);
- ASSERT_EQ(viewport_size, web_view_helper.GetWebView()->Size());
+ ASSERT_EQ(viewport_size,
+ web_view_helper.GetWebView()->MainFrameWidget()->Size());
ASSERT_EQ(initial_page_scale_factor,
web_view_helper.GetWebView()->PageScaleFactor());
web_view_helper.Resize(
@@ -3403,11 +3396,9 @@ TEST_F(WebFrameTest, updateOverlayScrollbarLayers)
int view_width = 500;
int view_height = 500;
- std::unique_ptr<FakeCompositingWebViewClient>
- fake_compositing_web_view_client =
- std::make_unique<FakeCompositingWebViewClient>();
+ FakeCompositingWebViewClient fake_compositing_web_view_client;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, fake_compositing_web_view_client.get(),
+ web_view_helper.Initialize(nullptr, &fake_compositing_web_view_client,
nullptr, &ConfigureCompositingWebView);
web_view_helper.Resize(WebSize(view_width, view_height));
@@ -3437,9 +3428,9 @@ void SimulatePageScale(WebViewImpl* web_view_impl, float& scale) {
float scale_delta =
web_view_impl->FakePageScaleAnimationPageScaleForTesting() /
web_view_impl->PageScaleFactor();
- web_view_impl->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(),
- scale_delta, 0,
- cc::BrowserControlsState::kBoth});
+ web_view_impl->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), scale_delta, 0,
+ cc::BrowserControlsState::kBoth});
scale = web_view_impl->PageScaleFactor();
}
@@ -3636,7 +3627,7 @@ TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) {
// back to the div.
SimulateDoubleTap(web_view_helper.GetWebView(), top_point, scale);
EXPECT_FLOAT_EQ(1, scale);
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 0.6f, 0,
cc::BrowserControlsState::kBoth});
SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale);
@@ -3647,7 +3638,7 @@ TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) {
// If we didn't yet get an auto-zoom update and a second double-tap arrives,
// should go back to minimum scale.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
@@ -3703,7 +3694,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest) {
EXPECT_FLOAT_EQ(1, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale
@@ -3725,7 +3716,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest) {
EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale
@@ -3795,7 +3786,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest) {
EXPECT_FLOAT_EQ(legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// 1 < maximumLegibleScaleFactor < minimumPageScale <
@@ -3818,7 +3809,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest) {
EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// minimumPageScale < 1 < maximumLegibleScaleFactor <
@@ -3841,7 +3832,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest) {
EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale <
@@ -3915,7 +3906,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) {
EXPECT_FLOAT_EQ(legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// 1 < accessibilityFontScaleFactor < minimumPageScale <
@@ -3938,7 +3929,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) {
EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// minimumPageScale < 1 < accessibilityFontScaleFactor <
@@ -3961,7 +3952,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) {
EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale);
// Zoom in to reset double_tap_zoom_in_effect flag.
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.1f, 0,
cc::BrowserControlsState::kBoth});
// minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale <
@@ -4505,7 +4496,7 @@ class ClearScrollStateOnCommitWebFrameClient
// frame_test_helpers::TestWebFrameClient:
void DidCommitProvisionalLoad(const WebHistoryItem&,
WebHistoryCommitType,
- WebGlobalObjectReusePolicy) override {
+ mojo::ScopedMessagePipeHandle) override {
Frame()->View()->ResetScrollAndScaleState();
}
};
@@ -4553,7 +4544,7 @@ TEST_F(WebFrameTest, ReloadWhileProvisional) {
web_view_helper.LocalMainFrame()->GetDocumentLoader();
ASSERT_TRUE(document_loader);
EXPECT_EQ(ToKURL(base_url_ + "fixed_layout.html"),
- KURL(document_loader->GetRequest().Url()));
+ KURL(document_loader->GetUrl()));
}
TEST_F(WebFrameTest, AppendRedirects) {
@@ -4645,28 +4636,33 @@ TEST_F(WebFrameTest, TabKeyCursorMoveTriggersOneSelectionChange) {
// Move to the next text-field: 1 cursor change.
counter.Reset();
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_down));
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_up));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(tab_down));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(tab_up));
EXPECT_EQ(1, counter.Count());
// Move to another text-field: 1 cursor change.
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_down));
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_up));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(tab_down));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(tab_up));
EXPECT_EQ(2, counter.Count());
// Move to a number-field: 1 cursor change.
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_down));
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_up));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(tab_down));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(tab_up));
EXPECT_EQ(3, counter.Count());
// Move to an editable element: 1 cursor change.
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_down));
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_up));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(tab_down));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(tab_up));
EXPECT_EQ(4, counter.Count());
// Move to a non-editable element: 0 cursor changes.
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_down));
- web_view->HandleInputEvent(WebCoalescedInputEvent(tab_up));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(tab_down));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(tab_up));
EXPECT_EQ(4, counter.Count());
}
@@ -5196,7 +5192,7 @@ TEST_F(WebFrameTest, FindInPageActiveIndex) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "find_match_count.html",
&frame_client);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
RunPendingTasks();
const char* kFindString = "a";
@@ -5578,7 +5574,7 @@ TEST_F(WebFrameTest, FindInPageJavaScriptUpdatesDOMProperOrdinal) {
frame_test_helpers::LoadHTMLString(frame, html,
url_test_helpers::ToKURL(base_url_));
web_view_helper.Resize(WebSize(640, 480));
- web_view_helper.GetWebView()->SetFocus(true);
+ web_view_helper.GetWebView()->MainFrameWidget()->SetFocus(true);
RunPendingTasks();
TestFindInPageClient find_in_page_client;
@@ -5657,7 +5653,7 @@ TEST_F(WebFrameTest, FindInPageForcedRedoOfFindInPage) {
frame_test_helpers::LoadHTMLString(frame, html,
url_test_helpers::ToKURL(base_url_));
web_view_helper.Resize(WebSize(640, 480));
- web_view_helper.GetWebView()->SetFocus(true);
+ web_view_helper.GetWebView()->MainFrameWidget()->SetFocus(true);
RunPendingTasks();
TestFindInPageClient find_in_page_client;
@@ -5734,7 +5730,8 @@ TEST_F(WebFrameTest, SelectRange) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("Some test text for testing.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->ExecuteCommand(WebString::FromUTF8("Unselect"));
EXPECT_EQ("", SelectionAsString(frame));
frame->SelectRange(TopLeft(start_web_rect),
@@ -5749,7 +5746,8 @@ TEST_F(WebFrameTest, SelectRange) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("Some offscreen test text for testing.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->ExecuteCommand(WebString::FromUTF8("Unselect"));
EXPECT_EQ("", SelectionAsString(frame));
frame->SelectRange(TopLeft(start_web_rect),
@@ -5846,7 +5844,8 @@ TEST_F(WebFrameTest, SelectRangeInIframe) {
frame = web_view_helper.GetWebView()->MainFrame();
WebLocalFrame* subframe = frame->FirstChild()->ToWebLocalFrame();
EXPECT_EQ("Some test text for testing.", SelectionAsString(subframe));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
subframe->ExecuteCommand(WebString::FromUTF8("Unselect"));
EXPECT_EQ("", SelectionAsString(subframe));
subframe->SelectRange(TopLeft(start_web_rect),
@@ -5873,7 +5872,8 @@ TEST_F(WebFrameTest, SelectRangeDivContentEditable) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->SelectRange(BottomRightMinusOne(end_web_rect), WebPoint(0, 0));
EXPECT_EQ("16-char header. This text is initially selected.",
@@ -5884,13 +5884,16 @@ TEST_F(WebFrameTest, SelectRangeDivContentEditable) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->SelectRange(TopLeft(start_web_rect),
BottomRightMinusOne(end_web_rect));
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->SelectRange(TopLeft(start_web_rect), WebPoint(640, 480));
EXPECT_EQ("This text is initially selected. 16-char footer.",
SelectionAsString(frame));
@@ -5914,7 +5917,8 @@ TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->SelectRange(BottomRightMinusOne(end_web_rect), WebPoint(0, 0));
EXPECT_EQ("16-char header. This text is initially selected.",
@@ -5925,14 +5929,17 @@ TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->SelectRange(TopLeft(start_web_rect),
BottomRightMinusOne(end_web_rect));
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->SelectRange(TopLeft(start_web_rect), WebPoint(640, 480));
EXPECT_EQ("This text is initially selected. 16-char footer.",
SelectionAsString(frame));
@@ -6058,7 +6065,8 @@ TEST_F(WebFrameTest, MoveRangeSelectionExtent) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->MoveRangeSelectionExtent(WebPoint(640, 480));
EXPECT_EQ("This text is initially selected. 16-char footer.",
@@ -6095,7 +6103,8 @@ TEST_F(WebFrameTest, MoveRangeSelectionExtentCannotCollapse) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
frame->MoveRangeSelectionExtent(BottomRightMinusOne(start_web_rect));
EXPECT_EQ("This text is initially selected.", SelectionAsString(frame));
@@ -6122,7 +6131,8 @@ TEST_F(WebFrameTest, MoveRangeSelectionExtentScollsInputField) {
&web_view_helper);
frame = web_view_helper.LocalMainFrame();
EXPECT_EQ("Length", SelectionAsString(frame));
- web_view_helper.GetWebView()->SelectionBounds(start_web_rect, end_web_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ start_web_rect, end_web_rect);
EXPECT_EQ(0, frame->GetFrame()
->Selection()
@@ -6303,19 +6313,21 @@ TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved) {
WebRect end_rect;
frame->ExecuteScript(WebScriptSource("selectRange();"));
- web_view_helper.GetWebView()->SelectionBounds(initial_start_rect,
- initial_end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ initial_start_rect, initial_end_rect);
WebPoint moved_start(TopLeft(initial_start_rect));
moved_start.y += 40;
frame->SelectRange(moved_start, BottomRightMinusOne(initial_end_rect));
- web_view_helper.GetWebView()->SelectionBounds(start_rect, end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(start_rect,
+ end_rect);
EXPECT_EQ(start_rect, initial_start_rect);
EXPECT_EQ(end_rect, initial_end_rect);
moved_start.y -= 80;
frame->SelectRange(moved_start, BottomRightMinusOne(initial_end_rect));
- web_view_helper.GetWebView()->SelectionBounds(start_rect, end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(start_rect,
+ end_rect);
EXPECT_EQ(start_rect, initial_start_rect);
EXPECT_EQ(end_rect, initial_end_rect);
@@ -6323,13 +6335,15 @@ TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved) {
moved_end.y += 40;
frame->SelectRange(TopLeft(initial_start_rect), moved_end);
- web_view_helper.GetWebView()->SelectionBounds(start_rect, end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(start_rect,
+ end_rect);
EXPECT_EQ(start_rect, initial_start_rect);
EXPECT_EQ(end_rect, initial_end_rect);
moved_end.y -= 80;
frame->SelectRange(TopLeft(initial_start_rect), moved_end);
- web_view_helper.GetWebView()->SelectionBounds(start_rect, end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(start_rect,
+ end_rect);
EXPECT_EQ(start_rect, initial_start_rect);
EXPECT_EQ(end_rect, initial_end_rect);
}
@@ -6349,19 +6363,21 @@ TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved) {
WebRect end_rect;
frame->ExecuteScript(WebScriptSource("selectCaret();"));
- web_view_helper.GetWebView()->SelectionBounds(initial_start_rect,
- initial_end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(
+ initial_start_rect, initial_end_rect);
WebPoint move_to(TopLeft(initial_start_rect));
move_to.y += 40;
frame->MoveCaretSelection(move_to);
- web_view_helper.GetWebView()->SelectionBounds(start_rect, end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(start_rect,
+ end_rect);
EXPECT_EQ(start_rect, initial_start_rect);
EXPECT_EQ(end_rect, initial_end_rect);
move_to.y -= 80;
frame->MoveCaretSelection(move_to);
- web_view_helper.GetWebView()->SelectionBounds(start_rect, end_rect);
+ web_view_helper.GetWebView()->MainFrameWidget()->SelectionBounds(start_rect,
+ end_rect);
EXPECT_EQ(start_rect, initial_start_rect);
EXPECT_EQ(end_rect, initial_end_rect);
}
@@ -6375,7 +6391,7 @@ class CompositedSelectionBoundsTest
: ScopedCompositedSelectionUpdateForTest(true) {
RegisterMockedHttpURLLoad("Ahem.ttf");
- web_view_helper_.Initialize(nullptr, &web_view_client_);
+ web_view_helper_.Initialize(nullptr, nullptr, &web_widget_client_);
web_view_helper_.GetWebView()->GetSettings()->SetDefaultFontSize(12);
web_view_helper_.GetWebView()->SetDefaultPageScaleLimits(1, 1);
web_view_helper_.Resize(WebSize(640, 480));
@@ -6383,13 +6399,13 @@ class CompositedSelectionBoundsTest
void RunTestWithNoSelection(const char* test_file) {
RegisterMockedHttpURLLoad(test_file);
- web_view_helper_.GetWebView()->SetFocus(true);
+ web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
frame_test_helpers::LoadFrame(
web_view_helper_.GetWebView()->MainFrameImpl(), base_url_ + test_file);
UpdateAllLifecyclePhases(web_view_helper_.GetWebView());
cc::LayerTreeHost* layer_tree_host =
- web_view_client_.layer_tree_view()->layer_tree_host();
+ web_widget_client_.layer_tree_view()->layer_tree_host();
const cc::LayerSelection& selection = layer_tree_host->selection();
ASSERT_EQ(selection, cc::LayerSelection());
@@ -6399,7 +6415,7 @@ class CompositedSelectionBoundsTest
void RunTest(const char* test_file) {
RegisterMockedHttpURLLoad(test_file);
- web_view_helper_.GetWebView()->SetFocus(true);
+ web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
frame_test_helpers::LoadFrame(
web_view_helper_.GetWebView()->MainFrameImpl(), base_url_ + test_file);
UpdateAllLifecyclePhases(web_view_helper_.GetWebView());
@@ -6489,7 +6505,7 @@ class CompositedSelectionBoundsTest
.HandleGestureEvent(gesture_event);
cc::LayerTreeHost* layer_tree_host =
- web_view_client_.layer_tree_view()->layer_tree_host();
+ web_widget_client_.layer_tree_view()->layer_tree_host();
const cc::LayerSelection& selection = layer_tree_host->selection();
ASSERT_NE(selection, cc::LayerSelection());
@@ -6576,7 +6592,7 @@ class CompositedSelectionBoundsTest
: clm->MainGraphicsLayer();
}
- frame_test_helpers::TestWebViewClient web_view_client_;
+ frame_test_helpers::TestWebWidgetClient web_widget_client_;
frame_test_helpers::WebViewHelper web_view_helper_;
};
@@ -6627,69 +6643,6 @@ TEST_F(CompositedSelectionBoundsTest, InputScrolled) {
#endif
#endif
-class TestSubstituteDataWebFrameClient
- : public frame_test_helpers::TestWebFrameClient {
- public:
- TestSubstituteDataWebFrameClient() : commit_called_(false) {}
- ~TestSubstituteDataWebFrameClient() override = default;
-
- // frame_test_helpers::TestWebFrameClient:
- void DidFailProvisionalLoad(const WebURLError& error,
- WebHistoryCommitType) override {
- Frame()->CommitDataNavigation(
- WebURLRequest(ToKURL("chrome-error://chromewebdata/")),
- WebData("This should appear"), WebString::FromUTF8("text/html"),
- WebString::FromUTF8("UTF-8"), error.url(),
- WebFrameLoadType::kReplaceCurrentItem, WebHistoryItem(),
- false /* is_client_redirect */, nullptr, nullptr);
- }
- void DidCommitProvisionalLoad(const WebHistoryItem&,
- WebHistoryCommitType,
- WebGlobalObjectReusePolicy) override {
- if (Frame()->GetDocumentLoader()->GetResponse().Url() !=
- WebURL(url_test_helpers::ToKURL("about:blank")))
- commit_called_ = true;
- }
-
- bool CommitCalled() const { return commit_called_; }
-
- private:
- bool commit_called_;
-};
-
-TEST_F(WebFrameTest, ReplaceNavigationAfterHistoryNavigation) {
- TestSubstituteDataWebFrameClient web_frame_client;
-
- frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.InitializeAndLoad("about:blank", &web_frame_client);
- WebLocalFrame* frame = web_view_helper.GetWebView()->MainFrameImpl();
-
- // Load a url as a history navigation that will return an error.
- // TestSubstituteDataWebFrameClient will start a SubstituteData load in
- // response to the load failure, which should get fully committed. Due to
- // https://bugs.webkit.org/show_bug.cgi?id=91685,
- // FrameLoader::didReceiveData() wasn't getting called in this case, which
- // resulted in the SubstituteData document not getting displayed.
- std::string error_url = "http://0.0.0.0";
- ResourceError error = ResourceError::Failure(ToKURL(error_url));
- WebURLResponse response;
- response.SetURL(url_test_helpers::ToKURL(error_url));
- response.SetMIMEType("text/html");
- response.SetHTTPStatusCode(500);
- WebHistoryItem error_history_item;
- error_history_item.Initialize();
- error_history_item.SetURLString(
- WebString::FromUTF8(error_url.c_str(), error_url.length()));
- Platform::Current()->GetURLLoaderMockFactory()->RegisterErrorURL(
- url_test_helpers::ToKURL(error_url), response, error);
- frame_test_helpers::LoadHistoryItem(frame, error_history_item,
- mojom::FetchCacheMode::kDefault);
- WebString text = WebFrameContentDumper::DumpWebViewAsText(
- web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
- EXPECT_EQ("This should appear", text.Utf8());
- EXPECT_TRUE(web_frame_client.CommitCalled());
-}
-
class TestWillInsertBodyWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
@@ -6699,7 +6652,7 @@ class TestWillInsertBodyWebFrameClient
// frame_test_helpers::TestWebFrameClient:
void DidCommitProvisionalLoad(const WebHistoryItem&,
WebHistoryCommitType,
- WebGlobalObjectReusePolicy) override {
+ mojo::ScopedMessagePipeHandle) override {
did_load_ = true;
}
@@ -6906,12 +6859,6 @@ class StubbornTextCheckClient : public WebTextCheckClient {
WebTextCheckingCompletion* completion) override {
completion_ = completion;
}
- void CancelAllPendingRequests() override {
- if (!completion_)
- return;
- completion_->DidCancelCheckingText();
- completion_ = nullptr;
- }
void KickNoResults() { Kick(-1, -1, kWebTextDecorationTypeSpelling); }
@@ -7275,7 +7222,7 @@ TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage) {
// Do a compositor scroll, verify that this is counted as a user scroll.
scrollable_area->DidScroll(FloatPoint(0, 1));
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.7f, 0,
cc::BrowserControlsState::kBoth});
EXPECT_TRUE(client.WasFrameScrolled());
@@ -7286,7 +7233,7 @@ TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage) {
// The page scale 1.0f and scroll.
scrollable_area->DidScroll(FloatPoint(0, 2));
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, 0,
cc::BrowserControlsState::kBoth});
EXPECT_TRUE(client.WasFrameScrolled());
@@ -7296,7 +7243,7 @@ TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage) {
// No scroll event if there is no scroll delta.
scrollable_area->DidScroll(FloatPoint(0, 2));
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, 0,
cc::BrowserControlsState::kBoth});
EXPECT_FALSE(client.WasFrameScrolled());
@@ -7305,7 +7252,7 @@ TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage) {
// Non zero page scale and scroll.
scrollable_area->DidScroll(FloatPoint(9, 15));
- web_view_helper.GetWebView()->ApplyViewportChanges(
+ web_view_helper.GetWebView()->MainFrameWidget()->ApplyViewportChanges(
{gfx::ScrollOffset(), gfx::Vector2dF(), 0.6f, 0,
cc::BrowserControlsState::kBoth});
EXPECT_TRUE(client.WasFrameScrolled());
@@ -7459,41 +7406,7 @@ TEST_F(WebFrameTest, BackToReload) {
frame_test_helpers::ReloadFrame(frame);
EXPECT_EQ(mojom::FetchCacheMode::kValidateCache,
- frame->GetDocumentLoader()->GetRequest().GetCacheMode());
-}
-
-TEST_F(WebFrameTest, BackDuringChildFrameReload) {
- RegisterMockedHttpURLLoad("page_with_blank_iframe.html");
- frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.InitializeAndLoad(base_url_ + "page_with_blank_iframe.html");
- WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
- const FrameLoader& main_frame_loader = main_frame->GetFrame()->Loader();
- WebLocalFrame* child_frame = main_frame->FirstChild()->ToWebLocalFrame();
- ASSERT_TRUE(child_frame);
-
- // Start a history navigation, then have a different frame commit a
- // navigation. In this case, reload an about:blank frame, which will commit
- // synchronously. After the history navigation completes, both the
- // appropriate document url and the current history item should reflect the
- // history navigation.
- RegisterMockedHttpURLLoad("white-1x1.png");
- WebHistoryItem item;
- item.Initialize();
- WebURL history_url(ToKURL(base_url_ + "white-1x1.png"));
- item.SetURLString(history_url.GetString());
- HistoryItem* history_item = item;
- ResourceRequest request =
- history_item->GenerateResourceRequest(mojom::FetchCacheMode::kDefault);
- main_frame->CommitNavigation(
- WrappedResourceRequest(request), WebFrameLoadType::kBackForward, item,
- false, base::UnguessableToken::Create(), nullptr /* navigation_params */,
- nullptr /* extra_data */);
-
- frame_test_helpers::ReloadFrame(child_frame);
- EXPECT_EQ(item.UrlString(), main_frame->GetDocument().Url().GetString());
- EXPECT_EQ(item.UrlString(), WebString(main_frame_loader.GetDocumentLoader()
- ->GetHistoryItem()
- ->UrlString()));
+ frame->GetDocumentLoader()->GetCacheMode());
}
TEST_F(WebFrameTest, ReloadPost) {
@@ -7509,50 +7422,25 @@ TEST_F(WebFrameTest, ReloadPost) {
frame_test_helpers::PumpPendingRequestsForFrameToLoad(
web_view_helper.LocalMainFrame());
EXPECT_EQ(WebString::FromUTF8("POST"),
- frame->GetDocumentLoader()->GetRequest().HttpMethod());
+ frame->GetDocumentLoader()->HttpMethod());
frame_test_helpers::ReloadFrame(frame);
EXPECT_EQ(mojom::FetchCacheMode::kValidateCache,
- frame->GetDocumentLoader()->GetRequest().GetCacheMode());
+ frame->GetDocumentLoader()->GetCacheMode());
EXPECT_EQ(kWebNavigationTypeFormResubmitted,
frame->GetDocumentLoader()->GetNavigationType());
}
-TEST_F(WebFrameTest, LoadHistoryItemReload) {
- RegisterMockedHttpURLLoad("fragment_middle_click.html");
- frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.InitializeAndLoad(base_url_ + "fragment_middle_click.html");
- WebLocalFrame* frame = web_view_helper.LocalMainFrame();
- const FrameLoader& main_frame_loader =
- web_view_helper.LocalMainFrame()->GetFrame()->Loader();
- Persistent<HistoryItem> first_item =
- main_frame_loader.GetDocumentLoader()->GetHistoryItem();
- EXPECT_TRUE(first_item);
-
- RegisterMockedHttpURLLoad("white-1x1.png");
- frame_test_helpers::LoadFrame(frame, base_url_ + "white-1x1.png");
- EXPECT_NE(first_item.Get(),
- main_frame_loader.GetDocumentLoader()->GetHistoryItem());
-
- // Cache policy overrides should take.
- frame_test_helpers::LoadHistoryItem(frame, WebHistoryItem(first_item),
- mojom::FetchCacheMode::kValidateCache);
- EXPECT_EQ(first_item.Get(),
- main_frame_loader.GetDocumentLoader()->GetHistoryItem());
- EXPECT_EQ(mojom::FetchCacheMode::kValidateCache,
- frame->GetDocumentLoader()->GetRequest().GetCacheMode());
-}
-
class TestCachePolicyWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
TestCachePolicyWebFrameClient()
: cache_mode_(mojom::FetchCacheMode::kDefault),
- will_send_request_call_count_(0) {}
+ begin_navigation_call_count_(0) {}
~TestCachePolicyWebFrameClient() override = default;
mojom::FetchCacheMode GetCacheMode() const { return cache_mode_; }
- int WillSendRequestCallCount() const { return will_send_request_call_count_; }
+ int BeginNavigationCallCount() const { return begin_navigation_call_count_; }
TestCachePolicyWebFrameClient& ChildClient(size_t i) {
return *child_clients_[i].get();
}
@@ -7573,15 +7461,16 @@ class TestCachePolicyWebFrameClient
child_clients_.push_back(std::move(child));
return CreateLocalChild(*parent, scope, child_ptr);
}
- void WillSendRequest(WebURLRequest& request) override {
- cache_mode_ = request.GetCacheMode();
- will_send_request_call_count_++;
+ void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
+ cache_mode_ = info->url_request.GetCacheMode();
+ begin_navigation_call_count_++;
+ TestWebFrameClient::BeginNavigation(std::move(info));
}
private:
mojom::FetchCacheMode cache_mode_;
Vector<std::unique_ptr<TestCachePolicyWebFrameClient>> child_clients_;
- int will_send_request_call_count_;
+ int begin_navigation_call_count_;
};
TEST_F(WebFrameTest, ReloadIframe) {
@@ -7601,7 +7490,7 @@ TEST_F(WebFrameTest, ReloadIframe) {
ToWebLocalFrameImpl(main_frame->FirstChild());
EXPECT_EQ(child_client, child_frame->Client());
EXPECT_EQ(1u, main_frame->GetFrame()->Tree().ScopedChildCount());
- EXPECT_EQ(1, child_client->WillSendRequestCallCount());
+ EXPECT_EQ(1, child_client->BeginNavigationCallCount());
EXPECT_EQ(mojom::FetchCacheMode::kDefault, child_client->GetCacheMode());
frame_test_helpers::ReloadFrame(main_frame);
@@ -7618,7 +7507,7 @@ TEST_F(WebFrameTest, ReloadIframe) {
// But there should still only be one subframe.
EXPECT_EQ(1u, main_frame->GetFrame()->Tree().ScopedChildCount());
- EXPECT_EQ(1, new_child_client->WillSendRequestCallCount());
+ EXPECT_EQ(1, new_child_client->BeginNavigationCallCount());
// Sub-frames should not be forcibly revalidated.
// TODO(toyoshim): Will consider to revalidate main resources in sub-frames
// on reloads. Or will do only for bypassingCache.
@@ -7632,12 +7521,10 @@ class TestSameDocumentWebFrameClient
~TestSameDocumentWebFrameClient() override = default;
// frame_test_helpers::TestWebFrameClient:
- void WillSendRequest(WebURLRequest&) override {
- FrameLoader& frame_loader =
- ToWebLocalFrameImpl(Frame())->GetFrame()->Loader();
- if (frame_loader.GetProvisionalDocumentLoader()->LoadType() ==
- WebFrameLoadType::kReload)
+ void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
+ if (info->frame_load_type == WebFrameLoadType::kReload)
frame_load_type_reload_seen_ = true;
+ TestWebFrameClient::BeginNavigation(std::move(info));
}
bool FrameLoadTypeReloadSeen() const { return frame_load_type_reload_seen_; }
@@ -7818,6 +7705,9 @@ TEST_F(WebFrameTest, PushStateStartsAndStops) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "push_state.html", &client);
+ // Wait for push state navigation to complete.
+ frame_test_helpers::PumpPendingRequestsForFrameToLoad(
+ web_view_helper.LocalMainFrame());
EXPECT_EQ(client.StartLoadingCount(), 2);
EXPECT_EQ(client.StopLoadingCount(), 2);
}
@@ -7873,8 +7763,7 @@ class TestHistoryChildWebFrameClient
~TestHistoryChildWebFrameClient() override = default;
// frame_test_helpers::TestWebFrameClient:
- void DidStartProvisionalLoad(WebDocumentLoader* document_loader,
- WebURLRequest& request) override {
+ void DidStartProvisionalLoad(WebDocumentLoader* document_loader) override {
replaces_current_history_item_ =
document_loader->ReplacesCurrentHistoryItem();
}
@@ -7987,8 +7876,8 @@ TEST_F(WebFrameTest, overflowHiddenRewrite) {
cc::Layer* cc_scroll_layer = scroll_layer->CcLayer();
// Verify that the cc::Layer is not scrollable initially.
- ASSERT_FALSE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_FALSE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_FALSE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_FALSE(cc_scroll_layer->GetUserScrollableVertical());
// Call javascript to make the layer scrollable, and verify it.
WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
@@ -7997,8 +7886,8 @@ TEST_F(WebFrameTest, overflowHiddenRewrite) {
scroll_layer = compositor->ScrollLayer();
cc_scroll_layer = scroll_layer->CcLayer();
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableVertical());
}
// Test that currentHistoryItem reflects the current page, not the provisional
@@ -8013,15 +7902,15 @@ TEST_F(WebFrameTest, CurrentHistoryItem) {
const FrameLoader& main_frame_loader =
web_view_helper.LocalMainFrame()->GetFrame()->Loader();
WebURLRequest request(ToKURL(url));
- frame->StartNavigation(request);
- // Before commit, there is no history item.
+ // Before navigation, there is no history item.
EXPECT_FALSE(main_frame_loader.GetDocumentLoader()->GetHistoryItem());
+ frame->StartNavigation(request);
frame_test_helpers::PumpPendingRequestsForFrameToLoad(
web_view_helper.LocalMainFrame());
- // After commit, there is.
+ // After navigation, there is.
HistoryItem* item = main_frame_loader.GetDocumentLoader()->GetHistoryItem();
ASSERT_TRUE(item);
EXPECT_EQ(WTF::String(url.data()), item->UrlString());
@@ -8126,50 +8015,50 @@ TEST_F(WebFrameTest, FrameViewScrollAccountsForBrowserControls) {
// Simulate the browser controls showing by 20px, thus shrinking the viewport
// and allowing it to scroll an additional 20px.
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- 20.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ 20.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
EXPECT_EQ(ScrollOffset(0, 1920),
frame_view->LayoutViewport()->MaximumScrollOffset());
// Show more, make sure the scroll actually gets clamped.
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- 20.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ 20.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
EXPECT_EQ(ScrollOffset(0, 1940),
frame_view->LayoutViewport()->GetScrollOffset());
// Hide until there's 10px showing.
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- -30.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ -30.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
EXPECT_EQ(ScrollOffset(0, 1910),
frame_view->LayoutViewport()->MaximumScrollOffset());
// Simulate a LayoutEmbeddedContent::resize. The frame is resized to
// accomodate the browser controls and Blink's view of the browser controls
// matches that of the CC
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- 30.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ 30.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
web_view->ResizeWithBrowserControls(WebSize(100, 60), 40.0f, 0, true);
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
EXPECT_EQ(ScrollOffset(0, 1940),
frame_view->LayoutViewport()->MaximumScrollOffset());
// Now simulate hiding.
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- -10.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ -10.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
EXPECT_EQ(ScrollOffset(0, 1930),
frame_view->LayoutViewport()->MaximumScrollOffset());
// Reset to original state: 100px widget height, browser controls fully
// hidden.
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- -30.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ -30.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
web_view->ResizeWithBrowserControls(WebSize(100, 100),
browser_controls_height, 0, false);
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
@@ -8180,15 +8069,15 @@ TEST_F(WebFrameTest, FrameViewScrollAccountsForBrowserControls) {
// should allow an extra 0.5px of scrolling in the visual viewport. Make
// sure we're not losing any pixels when applying the adjustment on the
// main frame.
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- 1.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ 1.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
EXPECT_EQ(ScrollOffset(0, 1901),
frame_view->LayoutViewport()->MaximumScrollOffset());
- web_view->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
- 2.0f / browser_controls_height,
- cc::BrowserControlsState::kBoth});
+ web_view->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f,
+ 2.0f / browser_controls_height, cc::BrowserControlsState::kBoth});
EXPECT_EQ(ScrollOffset(0, 1903),
frame_view->LayoutViewport()->MaximumScrollOffset());
}
@@ -8239,7 +8128,7 @@ TEST_F(WebFrameTest, FullscreenLayerSize) {
Element* div_fullscreen = document->getElementById("div1");
Fullscreen::RequestFullscreen(*div_fullscreen);
EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
@@ -8278,7 +8167,7 @@ TEST_F(WebFrameTest, FullscreenLayerNonScrollable) {
Element* div_fullscreen = document->getElementById("div1");
Fullscreen::RequestFullscreen(*div_fullscreen);
EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
@@ -8291,17 +8180,17 @@ TEST_F(WebFrameTest, FullscreenLayerNonScrollable) {
frame_view->GetPage()->GetVisualViewport().ScrollLayer();
ASSERT_FALSE(
- layout_viewport_scroll_layer->CcLayer()->user_scrollable_horizontal());
+ layout_viewport_scroll_layer->CcLayer()->GetUserScrollableHorizontal());
ASSERT_FALSE(
- layout_viewport_scroll_layer->CcLayer()->user_scrollable_vertical());
+ layout_viewport_scroll_layer->CcLayer()->GetUserScrollableVertical());
ASSERT_FALSE(
- visual_viewport_scroll_layer->CcLayer()->user_scrollable_horizontal());
+ visual_viewport_scroll_layer->CcLayer()->GetUserScrollableHorizontal());
ASSERT_FALSE(
- visual_viewport_scroll_layer->CcLayer()->user_scrollable_vertical());
+ visual_viewport_scroll_layer->CcLayer()->GetUserScrollableVertical());
// Verify that the viewports are scrollable upon exiting fullscreen.
EXPECT_EQ(div_fullscreen, Fullscreen::FullscreenElementFrom(*document));
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
@@ -8309,13 +8198,13 @@ TEST_F(WebFrameTest, FullscreenLayerNonScrollable) {
visual_viewport_scroll_layer =
frame_view->GetPage()->GetVisualViewport().ScrollLayer();
ASSERT_TRUE(
- layout_viewport_scroll_layer->CcLayer()->user_scrollable_horizontal());
+ layout_viewport_scroll_layer->CcLayer()->GetUserScrollableHorizontal());
ASSERT_TRUE(
- layout_viewport_scroll_layer->CcLayer()->user_scrollable_vertical());
+ layout_viewport_scroll_layer->CcLayer()->GetUserScrollableVertical());
ASSERT_TRUE(
- visual_viewport_scroll_layer->CcLayer()->user_scrollable_horizontal());
+ visual_viewport_scroll_layer->CcLayer()->GetUserScrollableHorizontal());
ASSERT_TRUE(
- visual_viewport_scroll_layer->CcLayer()->user_scrollable_vertical());
+ visual_viewport_scroll_layer->CcLayer()->GetUserScrollableVertical());
}
TEST_F(WebFrameTest, FullscreenMainFrame) {
@@ -8337,8 +8226,8 @@ TEST_F(WebFrameTest, FullscreenMainFrame) {
->LayerForScrolling()
->CcLayer();
ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableVertical());
LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
Document* document = frame->GetDocument();
@@ -8346,7 +8235,7 @@ TEST_F(WebFrameTest, FullscreenMainFrame) {
LocalFrame::NotifyUserActivation(frame);
Fullscreen::RequestFullscreen(*document->documentElement());
EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
EXPECT_EQ(document->documentElement(),
Fullscreen::FullscreenElementFrom(*document));
@@ -8362,14 +8251,14 @@ TEST_F(WebFrameTest, FullscreenMainFrame) {
->LayerForScrolling()
->CcLayer();
ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableVertical());
// Verify the main frame still behaves correctly after a resize.
web_view_helper.Resize(WebSize(viewport_height, viewport_width));
ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableVertical());
}
TEST_F(WebFrameTest, FullscreenSubframe) {
@@ -8396,7 +8285,7 @@ TEST_F(WebFrameTest, FullscreenSubframe) {
LocalFrame::NotifyUserActivation(frame);
Element* div_fullscreen = document->getElementById("div1");
Fullscreen::RequestFullscreen(*div_fullscreen);
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
// Verify that the element is sized to the viewport.
@@ -8438,7 +8327,7 @@ TEST_F(WebFrameTest, FullscreenNestedExit) {
LocalFrame::NotifyUserActivation(top_doc->GetFrame());
Fullscreen::RequestFullscreen(*top_body);
}
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
{
@@ -8446,7 +8335,7 @@ TEST_F(WebFrameTest, FullscreenNestedExit) {
LocalFrame::NotifyUserActivation(iframe_doc->GetFrame());
Fullscreen::RequestFullscreen(*iframe_body);
}
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
Microtask::PerformCheckpoint(V8PerIsolateData::MainThreadIsolate());
UpdateAllLifecyclePhases(web_view_impl);
@@ -8455,7 +8344,7 @@ TEST_F(WebFrameTest, FullscreenNestedExit) {
EXPECT_EQ(iframe, Fullscreen::FullscreenElementFrom(*top_doc));
EXPECT_EQ(iframe_body, Fullscreen::FullscreenElementFrom(*iframe_doc));
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
// We should now have fully exited fullscreen.
@@ -8491,7 +8380,7 @@ TEST_F(WebFrameTest, FullscreenWithTinyViewport) {
std::unique_ptr<UserGestureIndicator> gesture =
LocalFrame::NotifyUserActivation(frame);
Fullscreen::RequestFullscreen(*frame->GetDocument()->documentElement());
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(384, layout_view->LogicalWidth().Floor());
EXPECT_EQ(640, layout_view->LogicalHeight().Floor());
@@ -8499,7 +8388,7 @@ TEST_F(WebFrameTest, FullscreenWithTinyViewport) {
EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(320, layout_view->LogicalWidth().Floor());
EXPECT_EQ(533, layout_view->LogicalHeight().Floor());
@@ -8530,7 +8419,7 @@ TEST_F(WebFrameTest, FullscreenResizeWithTinyViewport) {
std::unique_ptr<UserGestureIndicator> gesture =
LocalFrame::NotifyUserActivation(frame);
Fullscreen::RequestFullscreen(*frame->GetDocument()->documentElement());
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(384, layout_view->LogicalWidth().Floor());
EXPECT_EQ(640, layout_view->LogicalHeight().Floor());
@@ -8550,7 +8439,7 @@ TEST_F(WebFrameTest, FullscreenResizeWithTinyViewport) {
EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(320, layout_view->LogicalWidth().Floor());
EXPECT_EQ(192, layout_view->LogicalHeight().Floor());
@@ -8598,7 +8487,7 @@ TEST_F(WebFrameTest, FullscreenRestoreScaleFactorUponExiting) {
Fullscreen::RequestFullscreen(*frame->GetDocument()->body());
}
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
client.screen_info_.rect.width = screen_size_minus_status_bars.width;
client.screen_info_.rect.height = screen_size_minus_status_bars.height;
@@ -8612,7 +8501,7 @@ TEST_F(WebFrameTest, FullscreenRestoreScaleFactorUponExiting) {
EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
client.screen_info_.rect.width = screen_size_minus_status_bars.width;
client.screen_info_.rect.height = screen_size_minus_status_bars.height;
@@ -8659,7 +8548,7 @@ TEST_F(WebFrameTest, ClearFullscreenConstraintsOnNavigation) {
std::unique_ptr<UserGestureIndicator> gesture =
LocalFrame::NotifyUserActivation(frame, UserGestureToken::kNewGesture);
Fullscreen::RequestFullscreen(*frame->GetDocument()->documentElement());
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
// Entering fullscreen causes layout size and page scale limits to be
@@ -8676,7 +8565,7 @@ TEST_F(WebFrameTest, ClearFullscreenConstraintsOnNavigation) {
KURL test_url = ToKURL("about:blank");
WebLocalFrame* web_frame = web_view_helper.LocalMainFrame();
frame_test_helpers::LoadHTMLString(web_frame, kSource, test_url);
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
// Make sure the new page's layout size and scale factor limits aren't
@@ -8691,13 +8580,14 @@ TEST_F(WebFrameTest, ClearFullscreenConstraintsOnNavigation) {
TEST_F(WebFrameTest, OverlayFullscreenVideo) {
ScopedForceOverlayFullscreenVideoForTest force_overlay_fullscreen_video(true);
RegisterMockedHttpURLLoad("fullscreen_video.html");
- frame_test_helpers::TestWebViewClient web_view_client;
+ frame_test_helpers::TestWebWidgetClient web_widget_client;
frame_test_helpers::WebViewHelper web_view_helper;
- WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "fullscreen_video.html", nullptr, &web_view_client);
+ WebViewImpl* web_view_impl =
+ web_view_helper.InitializeAndLoad(base_url_ + "fullscreen_video.html",
+ nullptr, nullptr, &web_widget_client);
const cc::LayerTreeHost* layer_tree_host =
- web_view_client.layer_tree_view()->layer_tree_host();
+ web_widget_client.layer_tree_view()->layer_tree_host();
LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
std::unique_ptr<UserGestureIndicator> gesture =
@@ -8709,12 +8599,12 @@ TEST_F(WebFrameTest, OverlayFullscreenVideo) {
EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
video->webkitEnterFullscreen();
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_TRUE(video->IsFullscreen());
EXPECT_LT(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_FALSE(video->IsFullscreen());
EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
@@ -8886,7 +8776,7 @@ TEST_F(WebFrameTest, ReloadBypassingCache) {
WebLocalFrame* frame = web_view_helper.LocalMainFrame();
frame_test_helpers::ReloadFrameBypassingCache(frame);
EXPECT_EQ(mojom::FetchCacheMode::kBypassCache,
- frame->GetDocumentLoader()->GetRequest().GetCacheMode());
+ frame->GetDocumentLoader()->GetCacheMode());
}
static void NodeImageTestValidation(const IntSize& reference_bitmap_size,
@@ -9192,7 +9082,7 @@ TEST_F(WebFrameSwapTest, SwapFirstChild) {
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
- EXPECT_EQ("\n\nhello\n\nb\n\n\na\n\nc", content);
+ EXPECT_EQ(" \n\nhello\n\nb \n\na\n\nc", content);
}
void WebFrameTest::SwapAndVerifyMiddleChildConsistency(
@@ -9228,7 +9118,7 @@ TEST_F(WebFrameSwapTest, SwapMiddleChild) {
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
- EXPECT_EQ("\n\na\n\nhello\n\nc", content);
+ EXPECT_EQ(" \n\na\n\nhello\n\nc", content);
}
void WebFrameTest::SwapAndVerifyLastChildConsistency(const char* const message,
@@ -9258,7 +9148,7 @@ TEST_F(WebFrameSwapTest, SwapLastChild) {
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
- EXPECT_EQ("\n\na\n\nb\n\n\na\n\nhello", content);
+ EXPECT_EQ(" \n\na\n\nb \n\na\n\nhello", content);
}
TEST_F(WebFrameSwapTest, DetachProvisionalFrame) {
@@ -9371,7 +9261,7 @@ TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren) {
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
- EXPECT_EQ("\n\na\n\nhello\n\nc", content);
+ EXPECT_EQ(" \n\na\n\nhello\n\nc", content);
}
TEST_F(WebFrameSwapTest, SwapPreservesGlobalContext) {
@@ -9586,7 +9476,7 @@ class RemoteToLocalSwapWebFrameClient
// frame_test_helpers::TestWebFrameClient:
void DidCommitProvisionalLoad(const WebHistoryItem&,
WebHistoryCommitType history_commit_type,
- WebGlobalObjectReusePolicy) override {
+ mojo::ScopedMessagePipeHandle) override {
history_commit_type_ = history_commit_type;
remote_frame_->Swap(Frame());
}
@@ -9654,6 +9544,8 @@ class RemoteNavigationClient
// frame_test_helpers::TestWebRemoteFrameClient:
void Navigate(const WebURLRequest& request,
bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
mojo::ScopedMessagePipeHandle) override {
last_request_ = request;
}
@@ -9698,37 +9590,41 @@ TEST_F(WebFrameSwapTest, WindowOpenOnRemoteFrame) {
LocalDOMWindow* main_window =
ToWebLocalFrameImpl(MainFrame())->GetFrame()->DomWindow();
- KURL destination = ToKURL("data:text/html:destination");
+ String destination = "data:text/html:destination";
NonThrowableExceptionState exception_state;
+ ScriptState* script_state =
+ ToScriptStateForMainWorld(main_window->GetFrame());
+ ScriptState::Scope entered_context_scope(script_state);
+ v8::Context::BackupIncumbentScope incumbent_context_scope(
+ script_state->GetContext());
main_window->open(
+ script_state->GetIsolate(),
USVStringOrTrustedURL::FromTrustedURL(TrustedURL::Create(destination)),
- "frame1", "", main_window, main_window, exception_state);
+ "frame1", "", exception_state);
ASSERT_FALSE(remote_client.LastRequest().IsNull());
- EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(destination));
+ EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(KURL(destination)));
// Pointing a named frame to an empty URL should just return a reference to
// the frame's window without navigating it.
DOMWindow* result = main_window->open(
- USVStringOrTrustedURL::FromTrustedURL(TrustedURL::Create(ToKURL(""))),
- "frame1", "", main_window, main_window, exception_state);
- EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(destination));
+ script_state->GetIsolate(),
+ USVStringOrTrustedURL::FromTrustedURL(TrustedURL::Create("")), "frame1",
+ "", exception_state);
+ EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(KURL(destination)));
EXPECT_EQ(result, WebFrame::ToCoreFrame(*remote_frame)->DomWindow());
Reset();
}
-class RemoteWindowCloseClient : public frame_test_helpers::TestWebViewClient {
+class RemoteWindowCloseClient : public frame_test_helpers::TestWebWidgetClient {
public:
- RemoteWindowCloseClient() : closed_(false) {}
- ~RemoteWindowCloseClient() override = default;
-
- // frame_test_helpers::TestWebViewClient:
+ // WebWidgetClient implementation.
void CloseWidgetSoon() override { closed_ = true; }
bool Closed() const { return closed_; }
private:
- bool closed_;
+ bool closed_ = false;
};
TEST_F(WebFrameTest, WindowOpenRemoteClose) {
@@ -9736,9 +9632,9 @@ TEST_F(WebFrameTest, WindowOpenRemoteClose) {
main_web_view.Initialize();
// Create a remote window that will be closed later in the test.
- RemoteWindowCloseClient view_client;
+ RemoteWindowCloseClient client;
frame_test_helpers::WebViewHelper popup;
- popup.InitializeRemote(nullptr, nullptr, &view_client);
+ popup.InitializeRemote(nullptr, nullptr, nullptr, &client);
popup.RemoteMainFrame()->SetOpener(main_web_view.LocalMainFrame());
LocalFrame* local_frame = main_web_view.LocalMainFrame()->GetFrame();
@@ -9746,13 +9642,17 @@ TEST_F(WebFrameTest, WindowOpenRemoteClose) {
// Attempt to close the window, which should fail as it isn't opened
// by a script.
- remote_frame->DomWindow()->close(local_frame->DomWindow());
- EXPECT_FALSE(view_client.Closed());
+ ScriptState* local_script_state = ToScriptStateForMainWorld(local_frame);
+ ScriptState::Scope entered_context_scope(local_script_state);
+ v8::Context::BackupIncumbentScope incumbent_context_scope(
+ local_script_state->GetContext());
+ remote_frame->DomWindow()->close(local_script_state->GetIsolate());
+ EXPECT_FALSE(client.Closed());
// Marking it as opened by a script should now allow it to be closed.
remote_frame->GetPage()->SetOpenedByDOM();
- remote_frame->DomWindow()->close(local_frame->DomWindow());
- EXPECT_TRUE(view_client.Closed());
+ remote_frame->DomWindow()->close(local_script_state->GetIsolate());
+ EXPECT_TRUE(client.Closed());
}
TEST_F(WebFrameTest, NavigateRemoteToLocalWithOpener) {
@@ -9804,7 +9704,7 @@ class CommitTypeWebFrameClient : public frame_test_helpers::TestWebFrameClient {
// frame_test_helpers::TestWebFrameClient:
void DidCommitProvisionalLoad(const WebHistoryItem&,
WebHistoryCommitType history_commit_type,
- WebGlobalObjectReusePolicy) override {
+ mojo::ScopedMessagePipeHandle) override {
history_commit_type_ = history_commit_type;
}
@@ -9860,7 +9760,7 @@ TEST_F(WebFrameTest, FrameWidgetTest) {
*helper.RemoteMainFrame(), WebString(), WebFrameOwnerProperties(),
nullptr, nullptr, &child_widget_client);
- helper.GetWebView()->Resize(WebSize(1000, 1000));
+ helper.GetWebView()->MainFrameWidget()->Resize(WebSize(1000, 1000));
WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests(),
@@ -10099,6 +9999,8 @@ TEST_F(WebFrameTest, SendBeaconFromChildWithRemoteMainFrame) {
RegisterMockedHttpURLLoad("send_beacon.html");
RegisterMockedHttpURLLoad("reload_post.html"); // url param to sendBeacon()
frame_test_helpers::LoadFrame(local_frame, base_url_ + "send_beacon.html");
+ // Wait for the post.
+ frame_test_helpers::PumpPendingRequestsForFrameToLoad(local_frame);
}
TEST_F(WebFrameTest, SiteForCookiesFromChildWithRemoteMainFrame) {
@@ -10163,19 +10065,20 @@ TEST_F(WebFrameTest, PausedPageLoadWithRemoteMainFrame) {
LocalFrame* local_child = web_local_child->GetFrame();
EXPECT_FALSE(page->Paused());
EXPECT_FALSE(
- local_child->GetDocument()->Fetcher()->Context().DefersLoading());
+ local_child->GetDocument()->Fetcher()->GetProperties().IsPaused());
{
ScopedPagePauser pauser;
EXPECT_TRUE(page->Paused());
EXPECT_TRUE(
- local_child->GetDocument()->Fetcher()->Context().DefersLoading());
+ local_child->GetDocument()->Fetcher()->GetProperties().IsPaused());
}
EXPECT_FALSE(page->Paused());
EXPECT_FALSE(
- local_child->GetDocument()->Fetcher()->Context().DefersLoading());
+ local_child->GetDocument()->Fetcher()->GetProperties().IsPaused());
}
-class OverscrollWebViewClient : public frame_test_helpers::TestWebViewClient {
+class OverscrollWebWidgetClient
+ : public frame_test_helpers::TestWebWidgetClient {
public:
MOCK_METHOD5(DidOverscroll,
void(const WebFloatSize&,
@@ -10214,19 +10117,20 @@ class WebFrameOverscrollTest
void ScrollBegin(frame_test_helpers::WebViewHelper* web_view_helper,
float delta_x_hint,
float delta_y_hint) {
- web_view_helper->GetWebView()->HandleInputEvent(GenerateEvent(
- WebInputEvent::kGestureScrollBegin, delta_x_hint, delta_y_hint));
+ web_view_helper->GetWebView()->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin, delta_x_hint,
+ delta_y_hint));
}
void ScrollUpdate(frame_test_helpers::WebViewHelper* web_view_helper,
float delta_x,
float delta_y) {
- web_view_helper->GetWebView()->HandleInputEvent(
+ web_view_helper->GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, delta_x, delta_y));
}
void ScrollEnd(frame_test_helpers::WebViewHelper* web_view_helper) {
- web_view_helper->GetWebView()->HandleInputEvent(
+ web_view_helper->GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollEnd));
}
};
@@ -10238,11 +10142,11 @@ INSTANTIATE_TEST_CASE_P(All,
TEST_P(WebFrameOverscrollTest,
AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
- nullptr, &client, nullptr,
+ nullptr, nullptr, &client,
ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
@@ -10292,11 +10196,11 @@ TEST_P(WebFrameOverscrollTest,
TEST_P(WebFrameOverscrollTest,
AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/div-overscroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/div-overscroll.html", nullptr, &client, nullptr,
+ base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr, &client,
ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
@@ -10341,11 +10245,11 @@ TEST_P(WebFrameOverscrollTest,
}
TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/div-overscroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/div-overscroll.html", nullptr, &client, nullptr,
+ base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr, &client,
ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
@@ -10368,13 +10272,13 @@ TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll) {
}
TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/iframe-overscroll.html");
RegisterMockedHttpURLLoad("overscroll/scrollable-iframe.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/iframe-overscroll.html", nullptr, &client,
- nullptr, ConfigureAndroid);
+ base_url_ + "overscroll/iframe-overscroll.html", nullptr, nullptr,
+ &client, ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
ScrollBegin(&web_view_helper, 0, -320);
@@ -10404,11 +10308,11 @@ TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll) {
}
TEST_P(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/overscroll.html", nullptr, &client, nullptr,
+ base_url_ + "overscroll/overscroll.html", nullptr, nullptr, &client,
ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
web_view_impl->SetPageScaleFactor(3.0);
@@ -10450,11 +10354,11 @@ TEST_P(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled) {
}
TEST_P(WebFrameOverscrollTest, NoOverscrollForSmallvalues) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
- nullptr, &client, nullptr,
+ nullptr, nullptr, &client,
ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
@@ -10512,11 +10416,11 @@ TEST_P(WebFrameOverscrollTest, NoOverscrollForSmallvalues) {
}
TEST_P(WebFrameOverscrollTest, OverscrollBehaviorAffectsDidOverscroll) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
- nullptr, &client, nullptr,
+ nullptr, nullptr, &client,
ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
@@ -10566,13 +10470,13 @@ TEST_P(WebFrameOverscrollTest, OverscrollBehaviorAffectsDidOverscroll) {
}
TEST_P(WebFrameOverscrollTest, OnlyMainFrameOverscrollBehaviorHasEffect) {
- OverscrollWebViewClient client;
+ OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/iframe-overscroll.html");
RegisterMockedHttpURLLoad("overscroll/scrollable-iframe.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/iframe-overscroll.html", nullptr, &client,
- nullptr, ConfigureAndroid);
+ base_url_ + "overscroll/iframe-overscroll.html", nullptr, nullptr,
+ &client, ConfigureAndroid);
web_view_helper.Resize(WebSize(200, 200));
WebLocalFrame* mainFrame =
@@ -10699,12 +10603,12 @@ class CallbackOrderingWebFrameClient
EXPECT_EQ(0, callback_count_++);
frame_test_helpers::TestWebFrameClient::DidStartLoading();
}
- void DidStartProvisionalLoad(WebDocumentLoader*, WebURLRequest&) override {
+ void DidStartProvisionalLoad(WebDocumentLoader*) override {
EXPECT_EQ(1, callback_count_++);
}
void DidCommitProvisionalLoad(const WebHistoryItem&,
WebHistoryCommitType,
- WebGlobalObjectReusePolicy) override {
+ mojo::ScopedMessagePipeHandle) override {
EXPECT_EQ(2, callback_count_++);
}
void DidFinishDocumentLoad() override { EXPECT_EQ(3, callback_count_++); }
@@ -10906,7 +10810,7 @@ TEST_F(WebFrameTest, SaveImageAt) {
frame_test_helpers::WebViewHelper helper;
SaveImageFromDataURLWebFrameClient client;
WebViewImpl* web_view = helper.InitializeAndLoad(url, &client);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
UpdateAllLifecyclePhases(web_view);
WebLocalFrame* local_frame = web_view->MainFrameImpl();
@@ -10943,7 +10847,7 @@ TEST_F(WebFrameTest, SaveImageWithImageMap) {
frame_test_helpers::WebViewHelper helper;
SaveImageFromDataURLWebFrameClient client;
WebViewImpl* web_view = helper.InitializeAndLoad(url, &client);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
WebLocalFrame* local_frame = web_view->MainFrameImpl();
@@ -10977,7 +10881,7 @@ TEST_F(WebFrameTest, CopyImageWithImageMap) {
frame_test_helpers::WebViewHelper helper;
WebViewImpl* web_view = helper.InitializeAndLoad(url, &client);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
client.Reset();
WebLocalFrame* local_frame = web_view->MainFrameImpl();
@@ -11251,24 +11155,23 @@ TEST_F(WebFrameTest, ScrollBeforeLayoutDoesntCrash) {
// Try GestureScrollEnd and GestureScrollUpdate first to make sure that not
// seeing a Begin first doesn't break anything. (This currently happens).
- web_view_helper.GetWebView()->HandleInputEvent(
+ web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(end_event));
- web_view_helper.GetWebView()->HandleInputEvent(
+ web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(update_event));
// Try a full Begin/Update/End cycle.
- web_view_helper.GetWebView()->HandleInputEvent(
+ web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(begin_event));
- web_view_helper.GetWebView()->HandleInputEvent(
+ web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(update_event));
- web_view_helper.GetWebView()->HandleInputEvent(
+ web_view_helper.GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(end_event));
}
TEST_F(WebFrameTest, MouseOverDifferntNodeClearsTooltip) {
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, nullptr,
- [](WebSettings* settings) {});
+ web_view_helper.Initialize();
web_view_helper.Resize(WebSize(200, 200));
WebViewImpl* web_view = web_view_helper.GetWebView();
@@ -11358,7 +11261,7 @@ class WebFrameSimTest : public SimTest {
};
TEST_F(WebFrameSimTest, HitTestWithIgnoreClippingAtNegativeOffset) {
- WebView().Resize(WebSize(500, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 300));
WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
SimRequest r("https://example.com/test.html", "text/html");
@@ -11410,7 +11313,7 @@ TEST_F(WebFrameSimTest, HitTestWithIgnoreClippingAtNegativeOffset) {
}
TEST_F(WebFrameSimTest, TickmarksDocumentRelative) {
- WebView().Resize(WebSize(500, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 300));
WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
SimRequest request("https://example.com/test.html", "text/html");
@@ -11460,7 +11363,7 @@ TEST_F(WebFrameSimTest, TickmarksDocumentRelative) {
}
TEST_F(WebFrameSimTest, FindInPageSelectNextMatch) {
- WebView().Resize(WebSize(500, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 300));
WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
SimRequest request("https://example.com/test.html", "text/html");
@@ -11538,7 +11441,7 @@ TEST_F(WebFrameSimTest, FindInPageSelectNextMatch) {
// Test bubbling a document (End key) scroll from an inner iframe. This test
// passes if it does not crash. https://crbug.com/904247.
TEST_F(WebFrameSimTest, ScrollToEndBubblingCrash) {
- WebView().Resize(WebSize(500, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 300));
WebView().GetPage()->GetSettings().SetScrollAnimatorEnabled(false);
SimRequest request("https://example.com/test.html", "text/html");
@@ -11576,84 +11479,25 @@ TEST_F(WebFrameSimTest, ScrollToEndBubblingCrash) {
// Scroll the iframe to the end.
key_event.SetType(WebInputEvent::kRawKeyDown);
- WebView().HandleInputEvent(WebCoalescedInputEvent(key_event));
+ WebView().MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
key_event.SetType(WebInputEvent::kKeyUp);
- WebView().HandleInputEvent(WebCoalescedInputEvent(key_event));
+ WebView().MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
Compositor().BeginFrame();
// End key should now bubble from the iframe up to the main viewport.
key_event.SetType(WebInputEvent::kRawKeyDown);
- WebView().HandleInputEvent(WebCoalescedInputEvent(key_event));
+ WebView().MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
key_event.SetType(WebInputEvent::kKeyUp);
- WebView().HandleInputEvent(WebCoalescedInputEvent(key_event));
-}
-
-// Basic smoke test of the paint path used by the Android disambiguation popup.
-TEST_F(WebFrameSimTest, DisambiguationPopupPixelTest) {
- WebView().Resize(WebSize(400, 600));
- WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
- UseAndroidSettings();
-
- SimRequest request("https://example.com/test.html", "text/html");
- LoadURL("https://example.com/test.html");
- request.Complete(R"HTML(
- <!DOCTYPE html>
- <style>
- body, html {
- width: 4000px;
- height: 4000px;
- margin: 0;
- }
- #box {
- position: absolute;
- left: 200px;
- top: 300px;
- width: 100px;
- height: 100px;
- background-color: red;
- }
- </style>
- <div id="box"></div>
- )HTML");
-
- Compositor().BeginFrame();
-
- ASSERT_EQ(0.25f, WebView().PageScaleFactor());
-
- // Pick exactly the rect covered by the red <div> on the page. Paint it at 4x
- // magnification.
- float scale = 4.f;
- WebRect zoom_rect(200, 300, 100, 100);
- gfx::Size canvas_size(zoom_rect.width * scale, zoom_rect.height * scale);
-
- SkImageInfo info =
- SkImageInfo::MakeN32Premul(canvas_size.width(), canvas_size.height());
-
- size_t size = info.computeMinByteSize();
- auto buffer = std::make_unique<uint8_t[]>(size);
-
- SkBitmap bitmap;
- bitmap.installPixels(info, buffer.get(), info.minRowBytes());
- cc::SkiaPaintCanvas canvas(bitmap);
- canvas.scale(scale, scale);
- canvas.translate(-zoom_rect.x, -zoom_rect.y);
-
- WebView().MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
- WebView().PaintContentIgnoringCompositing(&canvas, zoom_rect);
-
- // All the pixels in the canvas should be the <div> color.
- for (int x = 0; x < canvas_size.width(); ++x) {
- for (int y = 0; y < canvas_size.height(); ++y) {
- ASSERT_EQ(bitmap.getColor(x, y), SK_ColorRED)
- << "Mismatching pixel at (" << x << ", " << y << ")";
- }
- }
+ WebView().MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
}
TEST_F(WebFrameSimTest, TestScrollFocusedEditableElementIntoView) {
- WebView().Resize(WebSize(500, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 300));
WebView().SetDefaultPageScaleLimits(1.f, 4);
WebView().EnableFakePageScaleAnimationForTesting(true);
WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
@@ -11734,7 +11578,7 @@ TEST_F(WebFrameSimTest, TestScrollFocusedEditableElementIntoView) {
// Now resize the visual viewport so that the input box is no longer in view
// (e.g. a keyboard is overlayed).
- WebView().ResizeVisualViewport(IntSize(200, 100));
+ WebView().MainFrameWidget()->ResizeVisualViewport(IntSize(200, 100));
ASSERT_FALSE(visual_viewport.VisibleRectInDocument().Contains(inputRect));
WebView()
@@ -11761,7 +11605,7 @@ TEST_F(WebFrameSimTest, ScrollFocusedIntoViewClipped) {
// input visible, we need to also scroll those clip/scroller elements This
// test ensures we do so. https://crbug.com/270018.
UseAndroidSettings();
- WebView().Resize(WebSize(400, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 600));
WebView().EnableFakePageScaleAnimationForTesting(true);
WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
@@ -11814,7 +11658,7 @@ TEST_F(WebFrameSimTest, ScrollFocusedIntoViewClipped) {
// Simulate the keyboard being shown and resizing the widget. Cause a scroll
// into view after.
- WebView().Resize(WebSize(400, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 300));
float scale_before = visual_viewport.Scale();
WebView()
@@ -11851,7 +11695,7 @@ TEST_F(WebFrameSimTest, ScrollFocusedIntoViewClipped) {
TEST_F(WebFrameSimTest, DoubleTapZoomWhileScrolled) {
UseAndroidSettings();
- WebView().Resize(WebSize(490, 500));
+ WebView().MainFrameWidget()->Resize(WebSize(490, 500));
WebView().EnableFakePageScaleAnimationForTesting(true);
WebView().GetSettings()->SetTextAutosizingEnabled(false);
WebView().SetDefaultPageScaleLimits(0.5f, 4);
@@ -11960,7 +11804,7 @@ TEST_F(WebFrameSimTest, ChangeBackgroundColor) {
// Ensure we don't crash if we try to scroll into view the focused editable
// element which doesn't have a LayoutObject.
TEST_F(WebFrameSimTest, ScrollFocusedEditableIntoViewNoLayoutObject) {
- WebView().Resize(WebSize(500, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 600));
WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false);
SimRequest r("https://example.com/test.html", "text/html");
@@ -11998,7 +11842,7 @@ TEST_F(WebFrameSimTest, ScrollFocusedEditableIntoViewNoLayoutObject) {
// The resize should cause the focused element to lose its LayoutObject. If
// this resize came from the Android on-screen keyboard, this would be
// followed by a ScrollFocusedEditableElementIntoView. Ensure we don't crash.
- WebView().Resize(WebSize(500, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 300));
ASSERT_FALSE(input->GetLayoutObject());
ASSERT_EQ(input, WebView().FocusedElement());
@@ -12098,7 +11942,7 @@ TEST_F(WebFrameSimTest, NormalIFrameHasLayoutObjects) {
TEST_F(WebFrameSimTest, RtlInitialScrollOffsetWithViewport) {
UseAndroidSettings();
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
WebView().SetDefaultPageScaleLimits(0.25f, 2);
SimRequest main_resource("https://example.com/test.html", "text/html");
@@ -12144,7 +11988,7 @@ TEST_F(WebFrameSimTest, LayoutViewportExceedsLayoutOverflow) {
TEST_F(WebFrameSimTest, LayoutViewLocalVisualRect) {
UseAndroidSettings();
- WebView().Resize(WebSize(600, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(600, 400));
WebView().SetDefaultPageScaleLimits(0.5f, 2);
SimRequest main_resource("https://example.com/test.html", "text/html");
@@ -12352,7 +12196,7 @@ bool TestSelectAll(const std::string& html) {
WebViewImpl* web_view = web_view_helper.Initialize(&frame);
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
ToKURL("about:blank"));
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
RunPendingTasks();
@@ -12366,7 +12210,8 @@ bool TestSelectAll(const std::string& html) {
mouse_event.button = WebMouseEvent::Button::kRight;
mouse_event.SetPositionInWidget(8, 8);
mouse_event.click_count = 1;
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
RunPendingTasks();
web_view_helper.Reset();
return frame.GetMenuData().edit_flags & WebContextMenuData::kCanSelectAll;
@@ -12389,7 +12234,7 @@ TEST_F(WebFrameTest, ContextMenuDataSelectedText) {
const std::string& html = "<input value=' '>";
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
ToKURL("about:blank"));
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases(web_view);
RunPendingTasks();
web_view->SetInitialFocus(false);
@@ -12404,7 +12249,8 @@ TEST_F(WebFrameTest, ContextMenuDataSelectedText) {
mouse_event.button = WebMouseEvent::Button::kRight;
mouse_event.SetPositionInWidget(8, 8);
mouse_event.click_count = 1;
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
RunPendingTasks();
web_view_helper.Reset();
EXPECT_EQ(frame.GetMenuData().selected_text, " ");
@@ -12417,7 +12263,7 @@ TEST_F(WebFrameTest, ContextMenuDataPasswordSelectedText) {
const std::string& html = "<input type='password' value='password'>";
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
ToKURL("about:blank"));
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases(web_view);
RunPendingTasks();
web_view->SetInitialFocus(false);
@@ -12432,7 +12278,8 @@ TEST_F(WebFrameTest, ContextMenuDataPasswordSelectedText) {
mouse_event.button = WebMouseEvent::Button::kRight;
mouse_event.SetPositionInWidget(8, 8);
mouse_event.click_count = 1;
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
RunPendingTasks();
web_view_helper.Reset();
@@ -12450,7 +12297,7 @@ TEST_F(WebFrameTest, ContextMenuDataNonLocatedMenu) {
"Next line</div>";
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), html,
ToKURL("about:blank"));
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases(web_view);
RunPendingTasks();
web_view->SetInitialFocus(false);
@@ -12463,9 +12310,10 @@ TEST_F(WebFrameTest, ContextMenuDataNonLocatedMenu) {
mouse_event.button = WebMouseEvent::Button::kLeft;
mouse_event.SetPositionInWidget(0, 0);
mouse_event.click_count = 2;
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
- web_view->ShowContextMenu(kMenuSourceTouch);
+ web_view->MainFrameWidget()->ShowContextMenu(kMenuSourceTouch);
RunPendingTasks();
web_view_helper.Reset();
@@ -12514,10 +12362,7 @@ class TestFallbackWebFrameClient
TestWebFrameClient::BeginNavigation(std::move(info));
return;
}
- Frame()->CreatePlaceholderDocumentLoader(
- info->url_request, info->frame_load_type, info->navigation_type,
- info->is_client_redirect, base::UnguessableToken::Create(), nullptr,
- nullptr);
+ Frame()->CreatePlaceholderDocumentLoader(*info, nullptr /* extra_data */);
}
private:
@@ -12785,9 +12630,21 @@ TEST_F(WebFrameTest, GetCanonicalUrlForSharingMultiple) {
frame->GetDocument().CanonicalUrlForSharing());
}
+TEST_F(WebFrameTest, NavigationTimingInfo) {
+ RegisterMockedHttpURLLoad("foo.html");
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
+ ResourceTimingInfo* navigation_timing_info = web_view_helper.LocalMainFrame()
+ ->GetFrame()
+ ->Loader()
+ .GetDocumentLoader()
+ ->GetNavigationTimingInfo();
+ EXPECT_EQ(navigation_timing_info->TransferSize(), 34);
+}
+
TEST_F(WebFrameSimTest, EnterFullscreenResetScrollAndScaleState) {
UseAndroidSettings();
- WebView().Resize(WebSize(490, 500));
+ WebView().MainFrameWidget()->Resize(WebSize(490, 500));
WebView().EnableFakePageScaleAnimationForTesting(true);
WebView().GetSettings()->SetTextAutosizingEnabled(false);
WebView().SetDefaultPageScaleLimits(0.5f, 4);
@@ -12823,14 +12680,14 @@ TEST_F(WebFrameSimTest, EnterFullscreenResetScrollAndScaleState) {
std::unique_ptr<UserGestureIndicator> gesture =
LocalFrame::NotifyUserActivation(frame);
Fullscreen::RequestFullscreen(*element);
- WebView().DidEnterFullscreen();
+ WebView().MainFrameWidget()->DidEnterFullscreen();
// Page scale factor must be 1.0 during fullscreen for elements to be sized
// properly.
EXPECT_EQ(1.0f, WebView().PageScaleFactor());
// Confirm that exiting fullscreen restores back to default values.
- WebView().DidExitFullscreen();
+ WebView().MainFrameWidget()->DidExitFullscreen();
WebView().MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
diff --git a/chromium/third_party/blink/renderer/core/exported/web_label_element.cc b/chromium/third_party/blink/renderer/core/exported/web_label_element.cc
index b889bebc70a..2c4f8c3ca84 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_label_element.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_label_element.cc
@@ -32,7 +32,6 @@
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
#include "third_party/blink/renderer/core/html_names.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_layer_test.cc b/chromium/third_party/blink/renderer/core/exported/web_layer_test.cc
index 359904e49a3..68930d46654 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_layer_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_layer_test.cc
@@ -34,7 +34,7 @@ class WebLayerListTest : public PaintTestConfigurations, public testing::Test {
void SetUp() override {
web_view_helper_ = std::make_unique<frame_test_helpers::WebViewHelper>();
- web_view_helper_->Initialize(nullptr, &web_view_client_, nullptr,
+ web_view_helper_->Initialize(nullptr, nullptr, &web_widget_client_,
&ConfigureCompositingWebView);
web_view_helper_->Resize(WebSize(200, 200));
@@ -44,6 +44,8 @@ class WebLayerListTest : public PaintTestConfigurations, public testing::Test {
paint_artifact_compositor()->EnableExtraDataForTesting();
}
+ void TearDown() override { web_view_helper_.reset(); }
+
// Both sets the inner html and runs the document lifecycle.
void InitializeWithHTML(LocalFrame& frame, const String& html_content) {
frame.GetDocument()->body()->SetInnerHTMLFromString(html_content);
@@ -85,7 +87,7 @@ class WebLayerListTest : public PaintTestConfigurations, public testing::Test {
}
cc::LayerTreeHost* LayerTreeHost() {
- return web_view_client_.layer_tree_view()->layer_tree_host();
+ return web_widget_client_.layer_tree_view()->layer_tree_host();
}
Element* GetElementById(const AtomicString& id) {
@@ -103,7 +105,7 @@ class WebLayerListTest : public PaintTestConfigurations, public testing::Test {
return GetLocalFrameView()->GetPaintArtifactCompositorForTesting();
}
- frame_test_helpers::TestWebViewClient web_view_client_;
+ frame_test_helpers::TestWebWidgetClient web_widget_client_;
std::unique_ptr<frame_test_helpers::WebViewHelper> web_view_helper_;
};
@@ -137,7 +139,7 @@ TEST_P(WebLayerListTest, DidScrollCallbackAfterScrollableAreaChanges) {
auto initial_scroll_hit_test_layer_count = ScrollHitTestLayerCount();
cc::Layer* overflow_scroll_layer = nullptr;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
overflow_scroll_layer = ScrollHitTestLayerAt(ScrollHitTestLayerCount() - 1);
} else {
overflow_scroll_layer = ContentLayerAt(ContentLayerCount() - 2);
@@ -167,13 +169,13 @@ TEST_P(WebLayerListTest, DidScrollCallbackAfterScrollableAreaChanges) {
// The web scroll layer has not been deleted yet and we should be able to
// apply impl-side offsets without crashing.
EXPECT_EQ(ContentLayerCount(), initial_content_layer_count);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_EQ(ScrollHitTestLayerCount(), initial_scroll_hit_test_layer_count);
overflow_scroll_layer->SetScrollOffsetFromImplSide(gfx::ScrollOffset(0, 3));
UpdateAllLifecyclePhases();
EXPECT_LT(ContentLayerCount(), initial_content_layer_count);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_LT(ScrollHitTestLayerCount(), initial_scroll_hit_test_layer_count);
}
@@ -193,7 +195,7 @@ TEST_P(WebLayerListTest, FrameViewScroll) {
EXPECT_NE(nullptr, scrollable_area);
cc::Layer* scroll_layer = nullptr;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(ScrollHitTestLayerCount(), 1u);
scroll_layer = ScrollHitTestLayerAt(0);
} else {
@@ -218,7 +220,7 @@ TEST_P(WebLayerListTest, FrameViewScroll) {
class WebLayerListSimTest : public PaintTestConfigurations, public SimTest {
public:
void InitializeWithHTML(const String& html) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -255,6 +257,10 @@ class WebLayerListSimTest : public PaintTestConfigurations, public SimTest {
WebWidget::LifecycleUpdateReason::kTest);
}
+ cc::PropertyTrees* GetPropertyTrees() {
+ return Compositor().layer_tree_view().layer_tree_host()->property_trees();
+ }
+
private:
PaintArtifactCompositor* paint_artifact_compositor() {
return MainFrame().GetFrameView()->GetPaintArtifactCompositorForTesting();
@@ -264,10 +270,10 @@ class WebLayerListSimTest : public PaintTestConfigurations, public SimTest {
INSTANTIATE_LAYER_LIST_TEST_CASE_P(WebLayerListSimTest);
TEST_P(WebLayerListSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
- // TODO(crbug.com/765003): SPV2 may make different layerization decisions and
+ // TODO(crbug.com/765003): CAP may make different layerization decisions and
// we cannot guarantee that both divs will be composited in this test. When
- // SPV2 gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // CAP gets closer to launch, this test should be updated to pass.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithHTML(R"HTML(
@@ -315,10 +321,10 @@ TEST_P(WebLayerListSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
}
TEST_P(WebLayerListSimTest, LayerUpdatesDoNotInvalidateLaterLayers) {
- // TODO(crbug.com/765003): SPV2 may make different layerization decisions and
+ // TODO(crbug.com/765003): CAP may make different layerization decisions and
// we cannot guarantee that both divs will be composited in this test. When
- // SPV2 gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // CAP gets closer to launch, this test should be updated to pass.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithHTML(R"HTML(
@@ -376,7 +382,8 @@ TEST_P(WebLayerListSimTest, LayerUpdatesDoNotInvalidateLaterLayers) {
EXPECT_FALSE(host->LayersThatShouldPushProperties().count(c_layer));
}
-TEST_P(WebLayerListSimTest, NoopChangeDoesNotCauseFullTreeSync) {
+TEST_P(WebLayerListSimTest,
+ NoopChangeDoesNotCauseFullTreeSyncOrPropertyTreeUpdate) {
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -394,10 +401,15 @@ TEST_P(WebLayerListSimTest, NoopChangeDoesNotCauseFullTreeSync) {
// Initially the host should not need to sync.
auto* layer_tree_host = Compositor().layer_tree_view().layer_tree_host();
EXPECT_FALSE(layer_tree_host->needs_full_tree_sync());
+ int sequence_number = GetPropertyTrees()->sequence_number;
+ EXPECT_GT(sequence_number, 0);
// A no-op update should not cause the host to need a full tree sync.
UpdateAllLifecyclePhases();
EXPECT_FALSE(layer_tree_host->needs_full_tree_sync());
+ // It should also not cause a property tree update - the sequence number
+ // should not change.
+ EXPECT_EQ(sequence_number, GetPropertyTrees()->sequence_number);
}
// When a property tree change occurs that affects layer position, all layers
@@ -407,10 +419,10 @@ TEST_P(WebLayerListSimTest, NoopChangeDoesNotCauseFullTreeSync) {
// this occurs in BuildPropertyTreesInternal (see:
// SetLayerPropertyChangedForChild).
TEST_P(WebLayerListSimTest, LayerSubtreeTransformPropertyChanged) {
- // TODO(crbug.com/765003): SPV2 may make different layerization decisions and
+ // TODO(crbug.com/765003): CAP may make different layerization decisions and
// we cannot guarantee that both divs will be composited in this test. When
- // SPV2 gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // CAP gets closer to launch, this test should be updated to pass.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithHTML(R"HTML(
@@ -471,10 +483,10 @@ TEST_P(WebLayerListSimTest, LayerSubtreeTransformPropertyChanged) {
// This test is similar to |LayerSubtreeTransformPropertyChanged| but for
// effect property node changes.
TEST_P(WebLayerListSimTest, LayerSubtreeEffectPropertyChanged) {
- // TODO(crbug.com/765003): SPV2 may make different layerization decisions and
+ // TODO(crbug.com/765003): CAP may make different layerization decisions and
// we cannot guarantee that both divs will be composited in this test. When
- // SPV2 gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // CAP gets closer to launch, this test should be updated to pass.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithHTML(R"HTML(
@@ -534,10 +546,10 @@ TEST_P(WebLayerListSimTest, LayerSubtreeEffectPropertyChanged) {
// This test is similar to |LayerSubtreeTransformPropertyChanged| but for
// clip property node changes.
TEST_P(WebLayerListSimTest, LayerSubtreeClipPropertyChanged) {
- // TODO(crbug.com/765003): SPV2 may make different layerization decisions and
+ // TODO(crbug.com/765003): CAP may make different layerization decisions and
// we cannot guarantee that both divs will be composited in this test. When
- // SPV2 gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // CAP gets closer to launch, this test should be updated to pass.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithHTML(R"HTML(
@@ -593,10 +605,10 @@ TEST_P(WebLayerListSimTest, LayerSubtreeClipPropertyChanged) {
}
TEST_P(WebLayerListSimTest, LayerSubtreeOverflowClipPropertyChanged) {
- // TODO(crbug.com/765003): SPV2 may make different layerization decisions and
+ // TODO(crbug.com/765003): CAP may make different layerization decisions and
// we cannot guarantee that both divs will be composited in this test. When
- // SPV2 gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // CAP gets closer to launch, this test should be updated to pass.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc b/chromium/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc
index cca943ffa8f..8a9e2edea3d 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_meaningful_layouts_test.cc
@@ -18,8 +18,6 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharacters) {
LoadURL("https://example.com/index.html");
- main_resource.Start();
-
// Write 201 characters.
const char* ten_characters = "0123456789";
for (int i = 0; i < 20; ++i)
@@ -30,7 +28,7 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharacters) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().VisuallyNonEmptyLayoutCount());
}
TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharactersEventually) {
@@ -38,8 +36,6 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharactersEventually) {
LoadURL("https://example.com/index.html");
- main_resource.Start();
-
// Write 200 characters.
const char* ten_characters = "0123456789";
for (int i = 0; i < 20; ++i)
@@ -48,7 +44,7 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharactersEventually) {
// Pump a frame mid-load.
Compositor().BeginFrame();
- EXPECT_EQ(0, WebViewClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(0, WebWidgetClient().VisuallyNonEmptyLayoutCount());
// Write more than 200 characters.
main_resource.Write("!");
@@ -59,7 +55,7 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyTextCharactersEventually) {
// not as the character count goes over 200.
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().VisuallyNonEmptyLayoutCount());
}
// TODO(dglazkov): Write pixel-count and canvas-based VisuallyNonEmpty tests
@@ -69,8 +65,6 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyMissingPump) {
LoadURL("https://example.com/index.html");
- main_resource.Start();
-
// Write <200 characters.
main_resource.Write("less than 200 characters.");
@@ -89,7 +83,7 @@ TEST_F(WebMeaningfulLayoutsTest, VisuallyNonEmptyMissingPump) {
Compositor().BeginFrame();
// ... which correctly signals the VisuallyNonEmpty.
- EXPECT_EQ(1, WebViewClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().VisuallyNonEmptyLayoutCount());
}
TEST_F(WebMeaningfulLayoutsTest, FinishedParsing) {
@@ -101,7 +95,7 @@ TEST_F(WebMeaningfulLayoutsTest, FinishedParsing) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().FinishedParsingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedParsingLayoutCount());
}
TEST_F(WebMeaningfulLayoutsTest, FinishedLoading) {
@@ -113,12 +107,13 @@ TEST_F(WebMeaningfulLayoutsTest, FinishedLoading) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().FinishedLoadingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedLoadingLayoutCount());
}
TEST_F(WebMeaningfulLayoutsTest, FinishedParsingThenLoading) {
SimRequest main_resource("https://example.com/index.html", "text/html");
- SimRequest image_resource("https://example.com/cat.png", "image/png");
+ SimSubresourceRequest image_resource("https://example.com/cat.png",
+ "image/png");
LoadURL("https://example.com/index.html");
@@ -126,8 +121,8 @@ TEST_F(WebMeaningfulLayoutsTest, FinishedParsingThenLoading) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().FinishedParsingLayoutCount());
- EXPECT_EQ(0, WebViewClient().FinishedLoadingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedParsingLayoutCount());
+ EXPECT_EQ(0, WebWidgetClient().FinishedLoadingLayoutCount());
image_resource.Complete("image data");
@@ -136,8 +131,8 @@ TEST_F(WebMeaningfulLayoutsTest, FinishedParsingThenLoading) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().FinishedParsingLayoutCount());
- EXPECT_EQ(1, WebViewClient().FinishedLoadingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedParsingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedLoadingLayoutCount());
}
TEST_F(WebMeaningfulLayoutsTest, WithIFrames) {
@@ -150,9 +145,9 @@ TEST_F(WebMeaningfulLayoutsTest, WithIFrames) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().VisuallyNonEmptyLayoutCount());
- EXPECT_EQ(1, WebViewClient().FinishedParsingLayoutCount());
- EXPECT_EQ(0, WebViewClient().FinishedLoadingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedParsingLayoutCount());
+ EXPECT_EQ(0, WebWidgetClient().FinishedLoadingLayoutCount());
iframe_resource.Complete("iframe data");
@@ -161,9 +156,9 @@ TEST_F(WebMeaningfulLayoutsTest, WithIFrames) {
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().VisuallyNonEmptyLayoutCount());
- EXPECT_EQ(1, WebViewClient().FinishedParsingLayoutCount());
- EXPECT_EQ(1, WebViewClient().FinishedLoadingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedParsingLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().FinishedLoadingLayoutCount());
}
// NoOverflowInIncrementVisuallyNonEmptyPixelCount tests fail if the number of
@@ -172,15 +167,15 @@ TEST_F(WebMeaningfulLayoutsTest, WithIFrames) {
TEST_F(WebMeaningfulLayoutsTest,
NoOverflowInIncrementVisuallyNonEmptyPixelCount) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest svg_resource("https://example.com/test.svg", "image/svg+xml");
+ SimSubresourceRequest svg_resource("https://example.com/test.svg",
+ "image/svg+xml");
LoadURL("https://example.com/test.html");
- main_resource.Start();
main_resource.Write("<DOCTYPE html><body><img src=\"test.svg\">");
// Run pending tasks to initiate the request to test.svg.
test::RunPendingTasks();
- EXPECT_EQ(0, WebViewClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(0, WebWidgetClient().VisuallyNonEmptyLayoutCount());
// We serve the SVG file and check visuallyNonEmptyLayoutCount() before
// mainResource.finish() because finishing the main resource causes
@@ -192,7 +187,7 @@ TEST_F(WebMeaningfulLayoutsTest,
"width=\"65536\"></svg>");
svg_resource.Finish();
Compositor().BeginFrame();
- EXPECT_EQ(1, WebViewClient().VisuallyNonEmptyLayoutCount());
+ EXPECT_EQ(1, WebWidgetClient().VisuallyNonEmptyLayoutCount());
main_resource.Finish();
}
@@ -201,7 +196,8 @@ TEST_F(WebMeaningfulLayoutsTest,
// a pending stylesheet if a layout is triggered before it loads.
TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingRenderBlockingStylesheet) {
SimRequest main_resource("https://example.com/index.html", "text/html");
- SimRequest style_resource("https://example.com/style.css", "text/css");
+ SimSubresourceRequest style_resource("https://example.com/style.css",
+ "text/css");
LoadURL("https://example.com/index.html");
@@ -221,7 +217,8 @@ TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingRenderBlockingStylesheet) {
// be considered a pending stylesheet if a layout is triggered before it loads.
TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingScriptBlockingStylesheet) {
SimRequest main_resource("https://example.com/index.html", "text/html");
- SimRequest style_resource("https://example.com/style.css", "text/css");
+ SimSubresourceRequest style_resource("https://example.com/style.css",
+ "text/css");
LoadURL("https://example.com/index.html");
@@ -240,7 +237,8 @@ TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingScriptBlockingStylesheet) {
// a pending stylesheet if a layout is triggered before it loads.
TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingImportInHead) {
SimRequest main_resource("https://example.com/index.html", "text/html");
- SimRequest import_resource("https://example.com/import.html", "text/html");
+ SimSubresourceRequest import_resource("https://example.com/import.html",
+ "text/html");
LoadURL("https://example.com/index.html");
@@ -262,7 +260,8 @@ TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingImportInHead) {
// a pending stylesheet if a layout is triggered before it loads.
TEST_F(WebMeaningfulLayoutsTest, LayoutWithPendingImportInBody) {
SimRequest main_resource("https://example.com/index.html", "text/html");
- SimRequest import_resource("https://example.com/import.html", "text/html");
+ SimSubresourceRequest import_resource("https://example.com/import.html",
+ "text/html");
LoadURL("https://example.com/index.html");
diff --git a/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc b/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc
new file mode 100644
index 00000000000..db8fa31dcb0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/web/web_navigation_params.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
+
+namespace blink {
+
+WebNavigationParams::WebNavigationParams()
+ : devtools_navigation_token(base::UnguessableToken::Create()) {}
+
+WebNavigationParams::~WebNavigationParams() = default;
+
+WebNavigationParams::WebNavigationParams(
+ const base::UnguessableToken& devtools_navigation_token)
+ : devtools_navigation_token(devtools_navigation_token) {}
+
+// static
+std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateFromInfo(
+ const WebNavigationInfo& info) {
+ auto result = std::make_unique<WebNavigationParams>();
+ result->request = info.url_request;
+ result->frame_load_type = info.frame_load_type;
+ result->is_client_redirect = info.is_client_redirect;
+ result->navigation_timings.input_start = info.input_start;
+ return result;
+};
+
+// static
+std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateWithHTMLString(
+ base::span<const char> html,
+ const WebURL& base_url) {
+ auto result = std::make_unique<WebNavigationParams>();
+ result->request = WebURLRequest(base_url);
+ result->data = WebData(html.data(), html.size());
+ result->mime_type = "text/html";
+ result->text_encoding = "UTF-8";
+ return result;
+}
+
+#if INSIDE_BLINK
+// static
+std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateWithHTMLBuffer(
+ scoped_refptr<SharedBuffer> buffer,
+ const KURL& base_url) {
+ auto result = std::make_unique<WebNavigationParams>();
+ result->request = WebURLRequest(base_url);
+ result->data = WebData(std::move(buffer));
+ result->mime_type = "text/html";
+ result->text_encoding = "UTF-8";
+ return result;
+}
+#endif
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_node_test.cc b/chromium/third_party/blink/renderer/core/exported/web_node_test.cc
index d16be0dbb31..0e03462165a 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_node_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_node_test.cc
@@ -62,12 +62,12 @@ class WebNodeSimTest : public SimTest {};
TEST_F(WebNodeSimTest, IsFocused) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_resource("https://example.com/style.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/style.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
- main_resource.Start();
main_resource.Write(R"HTML(
<!DOCTYPE html>
<link rel=stylesheet href=style.css>
diff --git a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index 37e97dc863a..8b71a1fc444 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -125,19 +125,18 @@ class PagePopupChromeClient final : public EmptyChromeClient {
}
void ScheduleAnimation(const LocalFrameView*) override {
- // Calling scheduleAnimation on m_webView so WebViewTestProxy will call
- // beginFrame.
if (WebTestSupport::IsRunningWebTest()) {
- popup_->web_view_->MainFrameImpl()
- ->FrameWidgetImpl()
- ->ScheduleAnimation();
- }
-
- if (popup_->layer_tree_view_) {
- popup_->layer_tree_view_->SetNeedsBeginFrame();
+ // In single threaded web tests, the main frame's WebWidgetClient
+ // (provided by WebViewTestProxy or WebWidgetTestProxy) runs the composite
+ // step for the current popup. We don't run popup tests with a compositor
+ // thread.
+ popup_->web_view_->WidgetClient()->ScheduleAnimation();
return;
}
- popup_->widget_client_->ScheduleAnimation();
+
+ // TODO(danakj): Why null check? Can ScheduleAnimation() happen after the
+ // call to WillCloseLayerTreeView()?
+ popup_->WidgetClient()->ScheduleAnimation();
}
void AttachCompositorAnimationTimeline(CompositorAnimationTimeline* timeline,
@@ -421,7 +420,7 @@ void WebPagePopupImpl::UpdateAllLifecyclePhasesAndCompositeForTesting(
void WebPagePopupImpl::PaintContent(cc::PaintCanvas* canvas,
const WebRect& rect) {
if (!closing_) {
- PageWidgetDelegate::PaintContent(*page_, canvas, rect, MainFrame());
+ PageWidgetDelegate::PaintContent(canvas, rect, MainFrame());
}
}
@@ -576,10 +575,6 @@ LocalDOMWindow* WebPagePopupImpl::Window() {
return MainFrame().DomWindow();
}
-void WebPagePopupImpl::LayoutAndPaintAsync(base::OnceClosure callback) {
- layer_tree_view_->LayoutAndPaintAsync(std::move(callback));
-}
-
void WebPagePopupImpl::CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) {
DCHECK(IsAcceleratedCompositingActive());
@@ -595,7 +590,7 @@ WebPoint WebPagePopupImpl::PositionRelativeToOwner() {
void WebPagePopupImpl::Cancel() {
if (popup_client_)
- popup_client_->ClosePopup();
+ popup_client_->CancelPopup();
}
WebRect WebPagePopupImpl::WindowRectInScreen() const {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h
index 6193629a2d8..f8b1ec817c6 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h
@@ -68,7 +68,6 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
return other && popup_client_ == other->popup_client_;
}
LocalDOMWindow* Window();
- void LayoutAndPaintAsync(base::OnceClosure callback) override;
void CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) override;
WebPoint PositionRelativeToOwner() override;
@@ -94,7 +93,6 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
void Close() override;
WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override;
void SetFocus(bool) override;
- bool IsPagePopup() const override { return true; }
bool IsAcceleratedCompositingActive() const override {
return is_accelerated_compositing_active_;
}
@@ -146,13 +144,9 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
DISALLOW_COPY_AND_ASSIGN(WebPagePopupImpl);
};
-DEFINE_TYPE_CASTS(WebPagePopupImpl,
- WebWidget,
- widget,
- widget->IsPagePopup(),
- widget.IsPagePopup());
-// WebPagePopupImpl is the only implementation of PagePopup, so no
-// further checking required.
+// WebPagePopupImpl is the only implementation of WebPagePopup and PagePopup, so
+// no further checking required.
+DEFINE_TYPE_CASTS(WebPagePopupImpl, WebPagePopup, widget, true, true);
DEFINE_TYPE_CASTS(WebPagePopupImpl, PagePopup, popup, true, true);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_performance.cc b/chromium/third_party/blink/renderer/core/exported/web_performance.cc
index e35518a8ad2..408008befed 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_performance.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_performance.cc
@@ -154,10 +154,6 @@ double WebPerformance::FirstPaint() const {
return MillisecondsToSeconds(private_->timing()->FirstPaint());
}
-double WebPerformance::FirstTextPaint() const {
- return MillisecondsToSeconds(private_->timing()->FirstTextPaint());
-}
-
double WebPerformance::FirstImagePaint() const {
return MillisecondsToSeconds(private_->timing()->FirstImagePaint());
}
@@ -179,18 +175,34 @@ double WebPerformance::LargestImagePaint() const {
return MillisecondsToSeconds(private_->timing()->LargestImagePaint());
}
+uint64_t WebPerformance::LargestImagePaintSize() const {
+ return private_->timing()->LargestImagePaintSize();
+}
+
double WebPerformance::LastImagePaint() const {
return MillisecondsToSeconds(private_->timing()->LastImagePaint());
}
+uint64_t WebPerformance::LastImagePaintSize() const {
+ return private_->timing()->LastImagePaintSize();
+}
+
double WebPerformance::LargestTextPaint() const {
return MillisecondsToSeconds(private_->timing()->LargestTextPaint());
}
+uint64_t WebPerformance::LargestTextPaintSize() const {
+ return private_->timing()->LargestTextPaintSize();
+}
+
double WebPerformance::LastTextPaint() const {
return MillisecondsToSeconds(private_->timing()->LastTextPaint());
}
+uint64_t WebPerformance::LastTextPaintSize() const {
+ return private_->timing()->LastTextPaintSize();
+}
+
double WebPerformance::PageInteractive() const {
return MillisecondsToSeconds(private_->timing()->PageInteractive());
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index f0a6c825840..68128c69b99 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -172,14 +172,15 @@ void WebPluginContainerImpl::Paint(GraphicsContext& context,
if (!cull_rect.Intersects(FrameRect()))
return;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && layer_) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && layer_) {
layer_->SetOffsetToTransformParent(
gfx::Vector2dF(frame_rect_.X(), frame_rect_.Y()));
layer_->SetBounds(gfx::Size(frame_rect_.Size()));
layer_->SetIsDrawable(true);
- // With Slimming Paint v2, composited plugins should have their layers
- // inserted rather than invoking WebPlugin::paint.
+ // When compositing is after paint, composited plugins should have their
+ // layers inserted rather than invoking WebPlugin::paint.
RecordForeignLayer(context, DisplayItem::kForeignLayerPlugin, layer_);
+ ParentFrameView().SetPaintArtifactCompositorNeedsUpdate();
return;
}
@@ -547,7 +548,8 @@ WebString WebPluginContainerImpl::ExecuteScriptURL(const WebURL& url,
const KURL& kurl = url;
DCHECK(kurl.ProtocolIs("javascript"));
- String script = DecodeURLEscapeSequences(kurl.GetString());
+ String script = DecodeURLEscapeSequences(kurl.GetString(),
+ DecodeURLMode::kUTF8OrIsomorphic);
if (!element_->GetDocument().GetContentSecurityPolicy()->AllowJavaScriptURLs(
element_, script, element_->GetDocument().Url(), OrdinalNumber())) {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
index 8e07ace292c..2278524297e 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -286,7 +286,7 @@ void ExecuteContextMenuCommand(WebViewImpl* web_view,
WebPoint(30, 30), 0);
event.click_count = 1;
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
EXPECT_TRUE(
web_view->MainFrame()->ToWebLocalFrame()->ExecuteCommand(command_name));
}
@@ -491,7 +491,7 @@ TEST_F(WebPluginContainerTest, CopyFromContextMenu) {
// Now, let's try a more complex scenario:
// 1) open the context menu. This will focus the plugin.
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
// 2) document blurs the plugin, because it can.
web_view->ClearFocusedElement();
// 3) Copy should still operate on the context node, even though the focus had
@@ -794,7 +794,7 @@ TEST_F(WebPluginContainerTest, GestureLongPressReachesPlugin) {
// plugin doesn't receive it.
event.SetPositionInWidget(WebFloatPoint(0, 0));
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kUndefined, test_plugin->GetLastInputEventType());
@@ -805,7 +805,7 @@ TEST_F(WebPluginContainerTest, GestureLongPressReachesPlugin) {
event.SetPositionInWidget(
WebFloatPoint(rect.x + rect.width / 2, rect.y + rect.height / 2));
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kGestureLongPress,
@@ -837,7 +837,7 @@ TEST_F(WebPluginContainerTest, MouseEventButtons) {
WebRect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kMouseMove, test_plugin->GetLastInputEventType());
@@ -869,7 +869,7 @@ TEST_F(WebPluginContainerTest, MouseWheelEventTranslated) {
WebRect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kMouseWheel, test_plugin->GetLastInputEventType());
@@ -909,8 +909,8 @@ TEST_F(WebPluginContainerTest, TouchEventScrolled) {
WebFloatPoint(rect.x + rect.width / 2, rect.y + rect.height / 2)),
1.0f, 1.0f);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
- web_view->DispatchBufferedTouchEvents();
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kTouchStart, test_plugin->GetLastInputEventType());
@@ -953,8 +953,8 @@ TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
WebCoalescedInputEvent coalesced_event(event);
- web_view->HandleInputEvent(coalesced_event);
- web_view->DispatchBufferedTouchEvents();
+ web_view->MainFrameWidget()->HandleInputEvent(coalesced_event);
+ web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
RunPendingTasks();
EXPECT_EQ(static_cast<const size_t>(1),
@@ -1000,8 +1000,8 @@ TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
coalesced_event.AddCoalescedEvent(event2);
coalesced_event.AddCoalescedEvent(event3);
- web_view->HandleInputEvent(coalesced_event);
- web_view->DispatchBufferedTouchEvents();
+ web_view->MainFrameWidget()->HandleInputEvent(coalesced_event);
+ web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
RunPendingTasks();
EXPECT_EQ(static_cast<const size_t>(3),
@@ -1041,7 +1041,7 @@ TEST_F(WebPluginContainerTest, MouseWheelEventScrolled) {
WebRect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kMouseWheel, test_plugin->GetLastInputEventType());
@@ -1077,7 +1077,7 @@ TEST_F(WebPluginContainerTest, MouseEventScrolled) {
WebRect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
EXPECT_EQ(WebInputEvent::kMouseMove, test_plugin->GetLastInputEventType());
@@ -1116,7 +1116,7 @@ TEST_F(WebPluginContainerTest, MouseEventZoomed) {
WebRect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
// rect.width/height divided by 4 because the rect is in viewport bounds and
@@ -1158,7 +1158,7 @@ TEST_F(WebPluginContainerTest, MouseWheelEventZoomed) {
WebRect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
RunPendingTasks();
// rect.width/height divided by 4 because the rect is in viewport bounds and
@@ -1177,7 +1177,7 @@ TEST_F(WebPluginContainerTest, TouchEventZoomed) {
base_url_ + "plugin_scroll.html", &plugin_web_frame_client);
DCHECK(web_view);
web_view->GetSettings()->SetPluginsEnabled(true);
- web_view->Resize(WebSize(300, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(300, 300));
web_view->SetPageScaleFactor(2);
web_view->SmoothScroll(0, 300, 0);
UpdateAllLifecyclePhases(web_view);
@@ -1203,8 +1203,8 @@ TEST_F(WebPluginContainerTest, TouchEventZoomed) {
WebFloatPoint(rect.x + rect.width / 2, rect.y + rect.height / 2)),
1.0f, 1.0f);
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
- web_view->DispatchBufferedTouchEvents();
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
RunPendingTasks();
// rect.width/height divided by 4 because the rect is in viewport bounds and
@@ -1497,8 +1497,8 @@ class CompositedPlugin : public FakeWebPlugin {
} // namespace
-TEST_F(WebPluginContainerTest, CompositedPluginSPv2) {
- ScopedSlimmingPaintV2ForTest enable_s_pv2(true);
+TEST_F(WebPluginContainerTest, CompositedPluginCAP) {
+ ScopedCompositeAfterPaintForTest enable_cap(true);
RegisterMockedURL("plugin.html");
// Must outlive |web_view_helper|
CustomPluginWebFrameClient<CompositedPlugin> web_frame_client;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
index fab7bc61192..6386fc5ec91 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
@@ -144,13 +144,15 @@ WebLocalFrame* WebRemoteFrameImpl::CreateLocalChild(
WebSandboxFlags sandbox_flags,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle,
WebFrame* previous_sibling,
const ParsedFeaturePolicy& container_policy,
const WebFrameOwnerProperties& frame_owner_properties,
FrameOwnerElementType frame_owner_element_type,
WebFrame* opener) {
- WebLocalFrameImpl* child =
- WebLocalFrameImpl::Create(scope, client, interface_registry, opener);
+ WebLocalFrameImpl* child = WebLocalFrameImpl::Create(
+ scope, client, interface_registry,
+ std::move(document_interface_broker_handle), opener);
InsertAfter(child, previous_sibling);
RemoteFrameOwner* owner = RemoteFrameOwner::Create(
static_cast<SandboxFlags>(sandbox_flags), container_policy,
@@ -264,7 +266,7 @@ void WebRemoteFrameImpl::ApplyReplicatedFeaturePolicyHeader() {
void WebRemoteFrameImpl::AddReplicatedContentSecurityPolicyHeader(
const WebString& header_value,
- WebContentSecurityPolicyType type,
+ mojom::ContentSecurityPolicyType type,
WebContentSecurityPolicySource source) {
GetFrame()
->GetSecurityContext()
@@ -297,6 +299,7 @@ void WebRemoteFrameImpl::ForwardResourceTimingToParent(
ToWebLocalFrameImpl(Parent()->ToWebLocalFrame());
HTMLFrameOwnerElement* owner_element =
ToHTMLFrameOwnerElement(frame_->Owner());
+ DCHECK(owner_element);
DOMWindowPerformance::performance(*parent_frame->GetFrame()->DomWindow())
->AddResourceTiming(info, owner_element->localName());
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.h b/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
index 964952f5079..93929468862 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
@@ -51,6 +51,7 @@ class CORE_EXPORT WebRemoteFrameImpl final
WebSandboxFlags,
WebLocalFrameClient*,
blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebFrame* previous_sibling,
const ParsedFeaturePolicy&,
const WebFrameOwnerProperties&,
@@ -75,7 +76,7 @@ class CORE_EXPORT WebRemoteFrameImpl final
const ParsedFeaturePolicy& parsed_header) override;
void AddReplicatedContentSecurityPolicyHeader(
const WebString& header_value,
- WebContentSecurityPolicyType,
+ mojom::ContentSecurityPolicyType,
WebContentSecurityPolicySource) override;
void ResetReplicatedContentSecurityPolicy() override;
void SetReplicatedInsecureRequestPolicy(WebInsecureRequestPolicy) override;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc
index 67f8c013de1..9eee26ccff3 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -42,8 +42,6 @@ WebSettingsImpl::WebSettingsImpl(Settings* settings,
DevToolsEmulator* dev_tools_emulator)
: settings_(settings),
dev_tools_emulator_(dev_tools_emulator),
- show_fps_counter_(false),
- show_paint_rects_(false),
render_v_sync_notification_enabled_(false),
auto_zoom_focused_node_to_legible_scale_(false),
support_deprecated_target_density_dpi_(false),
@@ -259,12 +257,6 @@ void WebSettingsImpl::SetShouldReuseGlobalForUnownedMainFrame(bool enabled) {
settings_->SetShouldReuseGlobalForUnownedMainFrame(enabled);
}
-void WebSettingsImpl::SetSavePreviousDocumentResources(
- SavePreviousDocumentResources save_resources) {
- settings_->SetSavePreviousDocumentResources(
- static_cast<blink::SavePreviousDocumentResources>(save_resources));
-}
-
void WebSettingsImpl::SetPluginsEnabled(bool enabled) {
dev_tools_emulator_->SetPluginsEnabled(enabled);
}
@@ -461,14 +453,6 @@ void WebSettingsImpl::SetShowContextMenuOnMouseUp(bool enabled) {
settings_->SetShowContextMenuOnMouseUp(enabled);
}
-void WebSettingsImpl::SetShowFPSCounter(bool show) {
- show_fps_counter_ = show;
-}
-
-void WebSettingsImpl::SetShowPaintRects(bool show) {
- show_paint_rects_ = show;
-}
-
void WebSettingsImpl::SetEditingBehavior(EditingBehavior behavior) {
settings_->SetEditingBehaviorType(static_cast<EditingBehaviorType>(behavior));
}
@@ -513,6 +497,10 @@ void WebSettingsImpl::SetPresentationReceiver(bool enabled) {
settings_->SetPresentationReceiver(enabled);
}
+void WebSettingsImpl::SetHighlightAds(bool enabled) {
+ settings_->SetHighlightAds(enabled);
+}
+
void WebSettingsImpl::SetHistoryEntryRequiresUserGesture(bool enabled) {
settings_->SetHistoryEntryRequiresUserGesture(enabled);
}
@@ -564,10 +552,6 @@ void WebSettingsImpl::SetPasswordEchoDurationInSeconds(
settings_->SetPasswordEchoDurationInSeconds(duration_in_seconds);
}
-void WebSettingsImpl::SetPerTilePaintingEnabled(bool enabled) {
- per_tile_painting_enabled_ = enabled;
-}
-
void WebSettingsImpl::SetShouldPrintBackgrounds(bool enabled) {
settings_->SetShouldPrintBackgrounds(enabled);
}
@@ -580,6 +564,10 @@ void WebSettingsImpl::SetEnableScrollAnimator(bool enabled) {
settings_->SetScrollAnimatorEnabled(enabled);
}
+void WebSettingsImpl::SetPrefersReducedMotion(bool enabled) {
+ settings_->SetPrefersReducedMotion(enabled);
+}
+
void WebSettingsImpl::SetEnableTouchAdjustment(bool enabled) {
settings_->SetTouchAdjustmentEnabled(enabled);
}
@@ -616,13 +604,8 @@ void WebSettingsImpl::SetDataSaverHoldbackWebApi(bool enabled) {
settings_->SetDataSaverHoldbackWebApi(enabled);
}
-void WebSettingsImpl::SetDataSaverHoldbackMediaApi(bool enabled) {
- settings_->SetDataSaverHoldbackMediaApi(enabled);
-}
-
-void WebSettingsImpl::SetMediaPlaybackGestureWhitelistScope(
- const WebString& scope) {
- settings_->SetMediaPlaybackGestureWhitelistScope(scope);
+void WebSettingsImpl::SetWebAppScope(const WebString& scope) {
+ settings_->SetWebAppScope(scope);
}
void WebSettingsImpl::SetPresentationRequiresUserGesture(bool required) {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h
index 0d4722a8a90..ebe2619f53d 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -82,6 +82,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetDownloadableBinaryFontsEnabled(bool) override;
void SetEditingBehavior(EditingBehavior) override;
void SetEnableScrollAnimator(bool) override;
+ void SetPrefersReducedMotion(bool) override;
void SetEnableTouchAdjustment(bool) override;
void SetWebGL1Enabled(bool) override;
void SetWebGL2Enabled(bool) override;
@@ -96,6 +97,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetFullscreenSupported(bool) override;
void SetHideDownloadUI(bool) override;
void SetPresentationReceiver(bool) override;
+ void SetHighlightAds(bool) override;
void SetHistoryEntryRequiresUserGesture(bool) override;
void SetHyperlinkAuditingEnabled(bool) override;
void SetIgnoreMainFrameOverflowHiddenQuirk(bool) override;
@@ -107,15 +109,13 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetLoadsImagesAutomatically(bool) override;
void SetLoadWithOverviewMode(bool) override;
void SetShouldReuseGlobalForUnownedMainFrame(bool) override;
- void SetSavePreviousDocumentResources(SavePreviousDocumentResources) override;
void SetLocalStorageEnabled(bool) override;
void SetMainFrameClipsContent(bool) override;
void SetMainFrameResizesAreOrientationChanges(bool) override;
void SetMaxTouchPoints(int) override;
void SetPictureInPictureEnabled(bool) override;
void SetDataSaverHoldbackWebApi(bool) override;
- void SetDataSaverHoldbackMediaApi(bool) override;
- void SetMediaPlaybackGestureWhitelistScope(const WebString&) override;
+ void SetWebAppScope(const WebString&) override;
void SetPresentationRequiresUserGesture(bool) override;
void SetEmbeddedMediaExperienceEnabled(bool) override;
void SetImmersiveModeEnabled(bool) override;
@@ -128,7 +128,6 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetPassiveEventListenerDefault(PassiveEventListenerDefault) override;
void SetPasswordEchoDurationInSeconds(double) override;
void SetPasswordEchoEnabled(bool) override;
- void SetPerTilePaintingEnabled(bool) override;
void SetPictographFontFamily(const WebString&,
UScriptCode = USCRIPT_COMMON) override;
void SetPluginsEnabled(bool) override;
@@ -152,8 +151,6 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetShouldClearDocumentBackground(bool) override;
void SetShouldRespectImageOrientation(bool) override;
void SetShowContextMenuOnMouseUp(bool) override;
- void SetShowFPSCounter(bool) override;
- void SetShowPaintRects(bool) override;
void SetShrinksViewportContentToFit(bool) override;
void SetSmartInsertDeleteEnabled(bool) override;
void SetSmoothScrollForFindEnabled(bool) override;
@@ -221,8 +218,6 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetLazyImageLoadingDistanceThresholdPx3G(int) override;
void SetLazyImageLoadingDistanceThresholdPx4G(int) override;
- bool ShowFPSCounter() const { return show_fps_counter_; }
- bool ShowPaintRects() const { return show_paint_rects_; }
bool RenderVSyncNotificationEnabled() const {
return render_v_sync_notification_enabled_;
}
@@ -230,7 +225,6 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
return auto_zoom_focused_node_to_legible_scale_;
}
bool DoubleTapToZoomEnabled() const;
- bool PerTilePaintingEnabled() const { return per_tile_painting_enabled_; }
bool SupportDeprecatedTargetDensityDPI() const {
return support_deprecated_target_density_dpi_;
}
@@ -251,11 +245,8 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
private:
Settings* settings_;
UntracedMember<DevToolsEmulator> dev_tools_emulator_;
- bool show_fps_counter_;
- bool show_paint_rects_;
bool render_v_sync_notification_enabled_;
bool auto_zoom_focused_node_to_legible_scale_;
- bool per_tile_painting_enabled_;
bool support_deprecated_target_density_dpi_;
// This quirk is to maintain compatibility with Android apps built on
// the Android SDK prior to and including version 18. Presumably, this
diff --git a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
index 9de43de6741..6c13eed2270 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
@@ -33,6 +33,7 @@
#include <memory>
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
#include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -41,7 +42,6 @@
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_worker_fetch_context.h"
-#include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h"
#include "third_party/blink/renderer/core/core_initializer.h"
@@ -49,9 +49,10 @@
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/worker_devtools_params.h"
+#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
-#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/script/script.h"
#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
@@ -65,7 +66,9 @@
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -125,17 +128,12 @@ void WebSharedWorkerImpl::OnShadowPageInitialized() {
shadow_page_->DocumentLoader()->SetServiceWorkerNetworkProvider(
client_->CreateServiceWorkerNetworkProvider());
main_script_loader_ = MakeGarbageCollected<WorkerClassicScriptLoader>();
-
- network::mojom::FetchRequestMode fetch_request_mode =
- network::mojom::FetchRequestMode::kSameOrigin;
- network::mojom::FetchCredentialsMode fetch_credentials_mode =
- network::mojom::FetchCredentialsMode::kSameOrigin;
-
main_script_loader_->LoadTopLevelScriptAsynchronously(
- *shadow_page_->GetDocument(), script_request_url_,
- mojom::RequestContextType::SHARED_WORKER, fetch_request_mode,
- fetch_credentials_mode, creation_address_space_,
- false /* is_nested_worker */,
+ *shadow_page_->GetDocument(), shadow_page_->GetDocument()->Fetcher(),
+ script_request_url_, mojom::RequestContextType::SHARED_WORKER,
+ network::mojom::FetchRequestMode::kSameOrigin,
+ network::mojom::FetchCredentialsMode::kSameOrigin,
+ creation_address_space_,
Bind(&WebSharedWorkerImpl::DidReceiveScriptLoaderResponse,
WTF::Unretained(this)),
Bind(&WebSharedWorkerImpl::OnScriptLoaderFinished,
@@ -193,14 +191,14 @@ void WebSharedWorkerImpl::ConnectTaskOnWorkerThread(
// event.
DCHECK(worker_thread_->IsCurrentThread());
auto* scope = To<SharedWorkerGlobalScope>(worker_thread_->GlobalScope());
- scope->ConnectPausable(std::move(channel));
+ scope->Connect(std::move(channel));
}
void WebSharedWorkerImpl::StartWorkerContext(
const WebURL& script_request_url,
const WebString& name,
const WebString& content_security_policy,
- WebContentSecurityPolicyType policy_type,
+ mojom::ContentSecurityPolicyType policy_type,
mojom::IPAddressSpace creation_address_space,
const base::UnguessableToken& devtools_worker_token,
PrivacyPreferences privacy_preferences,
@@ -282,40 +280,34 @@ void WebSharedWorkerImpl::ContinueOnScriptLoaderFinished() {
// (e.g. GrantUniversalAccess) that can be overriden in regular documents
// via WebPreference by embedders. (crbug.com/254993)
Document* document = shadow_page_->GetDocument();
- const SecurityOrigin* starter_origin = document->GetSecurityOrigin();
- bool starter_secure_context = document->IsSecureContext();
-
- WorkerClients* worker_clients = WorkerClients::Create();
- CoreInitializer::GetInstance().ProvideLocalFileSystemToWorker(
- *worker_clients);
- CoreInitializer::GetInstance().ProvideIndexedDBClientToWorker(
- *worker_clients);
- ProvideContentSettingsClientToWorker(
- worker_clients, std::make_unique<SharedWorkerContentSettingsProxy>(
- std::move(content_settings_info_)));
+ // Creates 'outside settings' used in the "Processing model" algorithm in the
+ // HTML spec:
+ // https://html.spec.whatwg.org/multipage/workers.html#worker-processing-model
+ //
+ // TODO(nhiroki): According to the spec, the 'outside settings' should
+ // correspond to the Document that called 'new SharedWorker()'. However,
+ // for now there is no way to pass the settings object over mojo IPCs, so as
+ // a stopgap the shadow page's Document is used here.
+ auto* outside_settings_object =
+ MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ document->Fetcher()->GetProperties().GetFetchClientSettingsObject());
scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context =
client_->CreateWorkerFetchContext(
shadow_page_->DocumentLoader()->GetServiceWorkerNetworkProvider());
DCHECK(web_worker_fetch_context);
web_worker_fetch_context->SetApplicationCacheHostID(
- shadow_page_->GetDocument()
- ->Fetcher()
- ->Context()
- .ApplicationCacheHostID());
+ document->Loader()->GetApplicationCacheHost()->GetHostID());
ContentSecurityPolicy* content_security_policy =
main_script_loader_->GetContentSecurityPolicy();
- network::mojom::ReferrerPolicy referrer_policy =
- network::mojom::ReferrerPolicy::kDefault;
+ auto referrer_policy = network::mojom::ReferrerPolicy::kDefault;
if (!main_script_loader_->GetReferrerPolicy().IsNull()) {
SecurityPolicy::ReferrerPolicyFromHeaderValue(
main_script_loader_->GetReferrerPolicy(),
kDoNotSupportReferrerPolicyLegacyKeywords, &referrer_policy);
}
- auto worker_settings = std::make_unique<WorkerSettings>(
- shadow_page_->GetDocument()->GetFrame()->GetSettings());
// TODO(nhiroki); Set |script_type| to mojom::ScriptType::kModule for module
// fetch (https://crbug.com/824646).
@@ -328,33 +320,43 @@ void WebSharedWorkerImpl::ContinueOnScriptLoaderFinished() {
auto global_scope_creation_params =
std::make_unique<GlobalScopeCreationParams>(
- script_response_url, script_type, document->UserAgent(),
- std::move(web_worker_fetch_context),
+ script_response_url, script_type,
+ // TODO(nhiroki): Implement off-the-main-thread worker script fetch
+ // for shared workers (https://crbug.com/835717).
+ OffMainThreadWorkerScriptFetchOption::kDisabled,
+ document->UserAgent(), std::move(web_worker_fetch_context),
content_security_policy ? content_security_policy->Headers()
: Vector<CSPHeaderAndType>(),
- referrer_policy, starter_origin, starter_secure_context,
- document->GetHttpsState(), worker_clients,
- main_script_loader_->ResponseAddressSpace(),
+ referrer_policy, outside_settings_object->GetSecurityOrigin(),
+ document->IsSecureContext(), outside_settings_object->GetHttpsState(),
+ CreateWorkerClients(), main_script_loader_->ResponseAddressSpace(),
main_script_loader_->OriginTrialTokens(), devtools_worker_token_,
- std::move(worker_settings), kV8CacheOptionsDefault,
- nullptr /* worklet_module_response_map */,
+ std::make_unique<WorkerSettings>(document->GetFrame()->GetSettings()),
+ kV8CacheOptionsDefault, nullptr /* worklet_module_response_map */,
std::move(pending_interface_provider_));
- String source_code = main_script_loader_->SourceText();
+ StartWorkerThread(std::move(global_scope_creation_params),
+ script_response_url, main_script_loader_->SourceText());
+
+ probe::scriptImported(document, main_script_loader_->Identifier(),
+ main_script_loader_->SourceText());
+ main_script_loader_ = nullptr;
+}
+void WebSharedWorkerImpl::StartWorkerThread(
+ std::unique_ptr<GlobalScopeCreationParams> global_scope_creation_params,
+ const KURL& script_response_url,
+ const String& source_code) {
+ DCHECK(IsMainThread());
reporting_proxy_ = MakeGarbageCollected<SharedWorkerReportingProxy>(
this, parent_execution_context_task_runners_);
worker_thread_ =
std::make_unique<SharedWorkerThread>(name_, *reporting_proxy_);
- probe::scriptImported(document, main_script_loader_->Identifier(),
- main_script_loader_->SourceText());
- main_script_loader_ = nullptr;
auto thread_startup_data = WorkerBackingThreadStartupData::CreateDefault();
thread_startup_data.atomics_wait_mode =
WorkerBackingThreadStartupData::AtomicsWaitMode::kAllow;
-
auto devtools_params = DevToolsAgent::WorkerThreadCreated(
- document, GetWorkerThread(), script_response_url);
+ shadow_page_->GetDocument(), GetWorkerThread(), script_response_url);
GetWorkerThread()->Start(std::move(global_scope_creation_params),
thread_startup_data, std::move(devtools_params),
@@ -366,6 +368,18 @@ void WebSharedWorkerImpl::ContinueOnScriptLoaderFinished() {
client_->WorkerScriptLoaded();
}
+WorkerClients* WebSharedWorkerImpl::CreateWorkerClients() {
+ WorkerClients* worker_clients = WorkerClients::Create();
+ CoreInitializer::GetInstance().ProvideLocalFileSystemToWorker(
+ *worker_clients);
+ CoreInitializer::GetInstance().ProvideIndexedDBClientToWorker(
+ *worker_clients);
+ ProvideContentSettingsClientToWorker(
+ worker_clients, std::make_unique<SharedWorkerContentSettingsProxy>(
+ std::move(content_settings_info_)));
+ return worker_clients;
+}
+
void WebSharedWorkerImpl::TerminateWorkerContext() {
DCHECK(IsMainThread());
TerminateWorkerThread();
diff --git a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
index 98073b09b4a..eb757ea59d0 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
@@ -39,10 +39,10 @@
#include "base/memory/weak_ptr.h"
#include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
#include "third_party/blink/public/common/privacy_preferences.h"
+#include "third_party/blink/public/mojom/csp/content_security_policy.mojom-blink.h"
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-shared.h"
-#include "third_party/blink/public/platform/web_content_security_policy.h"
+#include "third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom-blink.h"
#include "third_party/blink/public/web/web_shared_worker_client.h"
-#include "third_party/blink/public/web/worker_content_settings_proxy.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/exported/worker_shadow_page.h"
#include "third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.h"
@@ -92,7 +92,7 @@ class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker,
const WebURL&,
const WebString& name,
const WebString& content_security_policy,
- WebContentSecurityPolicyType,
+ mojom::ContentSecurityPolicyType,
mojom::IPAddressSpace,
const base::UnguessableToken& devtools_worker_token,
PrivacyPreferences privacy_preferences,
@@ -121,6 +121,10 @@ class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker,
void DidReceiveScriptLoaderResponse();
void OnScriptLoaderFinished();
void ContinueOnScriptLoaderFinished();
+ void StartWorkerThread(std::unique_ptr<GlobalScopeCreationParams>,
+ const KURL& script_response_url,
+ const String& source_code);
+ WorkerClients* CreateWorkerClients();
void ConnectTaskOnWorkerThread(MessagePortChannel);
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc
index 9246cf14bca..2455c372862 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -38,7 +38,6 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/web_float_point.h"
#include "third_party/blink/public/platform/web_image.h"
#include "third_party/blink/public/platform/web_input_event.h"
@@ -70,6 +69,7 @@
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/dom/context_features_client_impl.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
@@ -135,10 +135,12 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/page_popup_client.h"
#include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/window_performance.h"
@@ -240,17 +242,12 @@ bool WebViewImpl::UseExternalPopupMenus() {
namespace {
-class EmptyEventListener final : public EventListener {
+class EmptyEventListener final : public NativeEventListener {
public:
- static EmptyEventListener* Create() { return new EmptyEventListener(); }
-
- bool operator==(const EventListener& other) const override {
- return this == &other;
+ static EmptyEventListener* Create() {
+ return MakeGarbageCollected<EmptyEventListener>();
}
- private:
- EmptyEventListener() : EventListener(kCPPEventListenerType) {}
-
void Invoke(ExecutionContext* execution_context, Event*) override {}
};
@@ -259,20 +256,21 @@ class EmptyEventListener final : public EventListener {
// WebView ----------------------------------------------------------------
WebView* WebView::Create(WebViewClient* client,
- WebWidgetClient* widget_client,
- mojom::PageVisibilityState visibility_state,
+ bool is_hidden,
+ bool compositing_enabled,
WebView* opener) {
- return WebViewImpl::Create(client, widget_client, visibility_state,
+ return WebViewImpl::Create(client, is_hidden, compositing_enabled,
static_cast<WebViewImpl*>(opener));
}
WebViewImpl* WebViewImpl::Create(WebViewClient* client,
- WebWidgetClient* widget_client,
- mojom::PageVisibilityState visibility_state,
+ bool is_hidden,
+ bool compositing_enabled,
WebViewImpl* opener) {
- // Pass the WebViewImpl's self-reference to the caller.
+ // Take a self-reference for WebViewImpl that is released by calling Close(),
+ // then return a raw pointer to the caller.
auto web_view = base::AdoptRef(
- new WebViewImpl(client, widget_client, visibility_state, opener));
+ new WebViewImpl(client, is_hidden, compositing_enabled, opener));
web_view->AddRef();
return web_view.get();
}
@@ -287,17 +285,17 @@ void WebView::ResetVisitedLinkState(bool invalidate_visited_link_hashes) {
void WebViewImpl::SetPrerendererClient(
WebPrerendererClient* prerenderer_client) {
- DCHECK(page_);
- ProvidePrerendererClientTo(*page_, MakeGarbageCollected<PrerendererClient>(
- *page_, prerenderer_client));
+ DCHECK(AsView().page);
+ ProvidePrerendererClientTo(*AsView().page,
+ MakeGarbageCollected<PrerendererClient>(
+ *AsView().page, prerenderer_client));
}
WebViewImpl::WebViewImpl(WebViewClient* client,
- WebWidgetClient* widget_client,
- mojom::PageVisibilityState visibility_state,
+ bool is_hidden,
+ bool does_composite,
WebViewImpl* opener)
- : client_(client),
- widget_client_(widget_client),
+ : as_view_(client),
chrome_client_(ChromeClientImpl::Create(this)),
should_auto_resize_(false),
zoom_level_(0),
@@ -315,8 +313,7 @@ WebViewImpl::WebViewImpl(WebViewClient* client,
ime_accept_events_(true),
dev_tools_emulator_(nullptr),
tabs_to_links_(false),
- does_composite_(widget_client_ &&
- !widget_client_->AllowsBrokenNullLayerTreeView()),
+ does_composite_(does_composite),
layer_tree_view_(nullptr),
root_layer_(nullptr),
root_graphics_layer_(nullptr),
@@ -335,31 +332,39 @@ WebViewImpl::WebViewImpl(WebViewClient* client,
display_mode_(kWebDisplayModeBrowser),
elastic_overscroll_(FloatSize()),
mutator_dispatcher_(nullptr) {
- DCHECK_EQ(!!client_, !!widget_client_);
+ if (!AsView().client) {
+ DCHECK(!does_composite_);
+ }
Page::PageClients page_clients;
page_clients.chrome_client = chrome_client_.Get();
- page_ =
+ AsView().page =
Page::CreateOrdinary(page_clients, opener ? opener->GetPage() : nullptr);
- CoreInitializer::GetInstance().ProvideModulesToPage(*page_, client_);
- SetVisibilityState(visibility_state, true);
+ CoreInitializer::GetInstance().ProvideModulesToPage(*AsView().page,
+ AsView().client);
+ SetIsHidden(is_hidden, /*is_initial_state=*/true);
// When not compositing, keep the Page in the loop so that it will paint all
// content into the root layer, as multiple layers can only be used when
// compositing them together later.
if (does_composite_)
- page_->GetSettings().SetAcceleratedCompositingEnabled(true);
+ AsView().page->GetSettings().SetAcceleratedCompositingEnabled(true);
dev_tools_emulator_ = DevToolsEmulator::Create(this);
AllInstances().insert(this);
page_importance_signals_.SetObserver(client);
- resize_viewport_anchor_ = MakeGarbageCollected<ResizeViewportAnchor>(*page_);
+ resize_viewport_anchor_ =
+ MakeGarbageCollected<ResizeViewportAnchor>(*AsView().page);
}
WebViewImpl::~WebViewImpl() {
- DCHECK(!page_);
+ DCHECK(!AsView().page);
+}
+
+void WebViewImpl::SetWebWidgetClient(WebWidgetClient* client) {
+ AsWidget().client = client;
}
WebDevToolsAgentImpl* WebViewImpl::MainFrameDevToolsAgentImpl() {
@@ -368,24 +373,25 @@ WebDevToolsAgentImpl* WebViewImpl::MainFrameDevToolsAgentImpl() {
}
WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
- return page_ && page_->MainFrame() && page_->MainFrame()->IsLocalFrame()
- ? WebLocalFrameImpl::FromFrame(page_->DeprecatedLocalMainFrame())
+ Page* page = AsView().page.Get();
+ return page && page->MainFrame() && page->MainFrame()->IsLocalFrame()
+ ? WebLocalFrameImpl::FromFrame(page->DeprecatedLocalMainFrame())
: nullptr;
}
bool WebViewImpl::TabKeyCyclesThroughElements() const {
- DCHECK(page_);
- return page_->TabKeyCyclesThroughElements();
+ DCHECK(AsView().page);
+ return AsView().page->TabKeyCyclesThroughElements();
}
void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) {
- if (page_)
- page_->SetTabKeyCyclesThroughElements(value);
+ if (AsView().page)
+ AsView().page->SetTabKeyCyclesThroughElements(value);
}
void WebViewImpl::HandleMouseLeave(LocalFrame& main_frame,
const WebMouseEvent& event) {
- client_->SetMouseOverURL(WebURL());
+ AsView().client->SetMouseOverURL(WebURL());
PageWidgetEventHandler::HandleMouseLeave(main_frame, event);
}
@@ -397,28 +403,25 @@ void WebViewImpl::HandleMouseDown(LocalFrame& main_frame,
scoped_refptr<WebPagePopupImpl> page_popup;
if (event.button == WebMouseEvent::Button::kLeft) {
page_popup = page_popup_;
- HidePopups();
+ CancelPagePopup();
DCHECK(!page_popup_);
}
// Take capture on a mouse down on a plugin so we can send it mouse events.
// If the hit node is a plugin but a scrollbar is over it don't start mouse
// capture because it will interfere with the scrollbar receiving events.
- if (event.button == WebMouseEvent::Button::kLeft &&
- page_->MainFrame()->IsLocalFrame()) {
+ if (event.button == WebMouseEvent::Button::kLeft) {
HitTestLocation location(
- page_->DeprecatedLocalMainFrame()->View()->ConvertFromRootFrame(
- event.PositionInWidget()));
- HitTestResult result(page_->DeprecatedLocalMainFrame()
- ->GetEventHandler()
- .HitTestResultAtLocation(location));
+ main_frame.View()->ConvertFromRootFrame(event.PositionInWidget()));
+ HitTestResult result(
+ main_frame.GetEventHandler().HitTestResultAtLocation(location));
result.SetToShadowHostIfInRestrictedShadowRoot();
Node* hit_node = result.InnerNodeOrImageMapImage();
if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() &&
hit_node->GetLayoutObject()->IsEmbeddedObject()) {
mouse_capture_node_ = hit_node;
- page_->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(true);
+ main_frame.Client()->SetMouseCapture(true);
TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this);
}
}
@@ -463,7 +466,7 @@ void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) {
if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
return;
- page_->GetContextMenuController().ClearContextMenu();
+ AsView().page->GetContextMenuController().ClearContextMenu();
WebMouseEvent transformed_event =
TransformWebMouseEvent(MainFrameImpl()->GetFrameView(), event);
@@ -476,7 +479,7 @@ void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) {
if (result.InnerNodeOrImageMapImage())
target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame();
else
- target_frame = page_->GetFocusController().FocusedOrMainFrame();
+ target_frame = AsView().page->GetFocusController().FocusedOrMainFrame();
if (!target_frame->IsLocalFrame())
return;
@@ -485,7 +488,7 @@ void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) {
{
ContextMenuAllowedScope scope;
target_local_frame->GetEventHandler().SendContextMenuEvent(
- transformed_event, nullptr);
+ transformed_event);
}
// Actually showing the context menu is handled by the ContextMenuController
// implementation...
@@ -506,13 +509,13 @@ void WebViewImpl::HandleMouseUp(LocalFrame& main_frame,
WebInputEventResult WebViewImpl::HandleMouseWheel(
LocalFrame& main_frame,
const WebMouseWheelEvent& event) {
- HidePopups();
+ CancelPagePopup();
return PageWidgetEventHandler::HandleMouseWheel(main_frame, event);
}
WebInputEventResult WebViewImpl::HandleGestureEvent(
const WebGestureEvent& event) {
- if (!client_ || !WidgetClient() || !client_->CanHandleGestureEvent()) {
+ if (!AsView().client || !AsView().client->CanHandleGestureEvent()) {
return WebInputEventResult::kNotHandled;
}
@@ -542,7 +545,7 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
}
}
event_result = WebInputEventResult::kHandledSystem;
- WidgetClient()->DidHandleGestureEvent(event, event_cancelled);
+ AsWidget().client->DidHandleGestureEvent(event, event_cancelled);
return event_result;
case WebInputEvent::kGestureScrollBegin:
case WebInputEvent::kGestureScrollEnd:
@@ -556,7 +559,7 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
->GetFrame()
->GetEventHandler()
.HandleGestureScrollEvent(scaled_event);
- WidgetClient()->DidHandleGestureEvent(event, event_cancelled);
+ AsWidget().client->DidHandleGestureEvent(event, event_cancelled);
return event_result;
default:
break;
@@ -565,8 +568,10 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
// Hit test across all frames and do touch adjustment as necessary for the
// event type.
GestureEventWithHitTestResults targeted_event =
- page_->DeprecatedLocalMainFrame()->GetEventHandler().TargetGestureEvent(
- scaled_event);
+ AsView()
+ .page->DeprecatedLocalMainFrame()
+ ->GetEventHandler()
+ .TargetGestureEvent(scaled_event);
// Handle link highlighting outside the main switch to avoid getting lost in
// the complicated set of cases handled below.
@@ -599,6 +604,8 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
// closed. It needs to be closed.
CancelPagePopup();
}
+ // Don't have this value persist outside of a single tap gesture, plus
+ // we're done with it now.
last_hidden_page_popup_ = nullptr;
break;
}
@@ -608,7 +615,7 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
break;
- page_->GetContextMenuController().ClearContextMenu();
+ AsView().page->GetContextMenuController().ClearContextMenu();
{
ContextMenuAllowedScope scope;
event_result =
@@ -625,8 +632,10 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
// When we close a popup because of a GestureTapDown, we also save it so
// we can prevent the following GestureTap from immediately reopening the
// same popup.
+ // This value should not persist outside of a gesture, so is cleared by
+ // GestureTap (where it is used) and by GestureCancel.
last_hidden_page_popup_ = page_popup_;
- HidePopups();
+ CancelPagePopup();
DCHECK(!page_popup_);
event_result =
MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
@@ -634,6 +643,7 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
break;
}
case WebInputEvent::kGestureTapCancel: {
+ // Don't have this value persist outside of a single tap gesture.
last_hidden_page_popup_ = nullptr;
event_result =
MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
@@ -654,7 +664,7 @@ WebInputEventResult WebViewImpl::HandleGestureEvent(
}
default: { NOTREACHED(); }
}
- WidgetClient()->DidHandleGestureEvent(event, event_cancelled);
+ AsWidget().client->DidHandleGestureEvent(event, event_cancelled);
return event_result;
}
@@ -704,38 +714,9 @@ void WebViewImpl::EnableFakePageScaleAnimationForTesting(bool enable) {
fake_page_scale_animation_page_scale_factor_ = 0;
}
-void WebViewImpl::SetShowFPSCounter(bool show) {
- if (layer_tree_view_) {
- TRACE_EVENT0("blink", "WebViewImpl::setShowFPSCounter");
- layer_tree_view_->SetShowFPSCounter(show);
- }
-}
-
-void WebViewImpl::SetShowPaintRects(bool show) {
- if (layer_tree_view_) {
- TRACE_EVENT0("blink", "WebViewImpl::setShowPaintRects");
- layer_tree_view_->SetShowPaintRects(show);
- }
-}
-
-void WebViewImpl::SetShowDebugBorders(bool show) {
- if (layer_tree_view_)
- layer_tree_view_->SetShowDebugBorders(show);
-}
-
-void WebViewImpl::SetShowScrollBottleneckRects(bool show) {
- if (layer_tree_view_)
- layer_tree_view_->SetShowScrollBottleneckRects(show);
-}
-
-void WebViewImpl::SetShowHitTestBorders(bool show) {
- if (layer_tree_view_)
- layer_tree_view_->SetShowHitTestBorders(show);
-}
-
void WebViewImpl::AcceptLanguagesChanged() {
- if (client_)
- FontCache::AcceptLanguagesChanged(client_->AcceptLanguages());
+ if (AsView().client)
+ FontCache::AcceptLanguagesChanged(AsView().client->AcceptLanguages());
if (!GetPage())
return;
@@ -1030,7 +1011,8 @@ Node* WebViewImpl::BestTapNode(
const GestureEventWithHitTestResults& targeted_tap_event) {
TRACE_EVENT0("input", "WebViewImpl::bestTapNode");
- if (!page_ || !page_->MainFrame())
+ Page* page = AsView().page.Get();
+ if (!page || !page->MainFrame())
return nullptr;
Node* best_touch_node = targeted_tap_event.GetHitTestResult().InnerNode();
@@ -1050,11 +1032,11 @@ Node* WebViewImpl::BestTapNode(
return nullptr;
Node* cursor_defining_ancestor = FindCursorDefiningAncestor(
- best_touch_node, page_->DeprecatedLocalMainFrame());
+ best_touch_node, page->DeprecatedLocalMainFrame());
// We show a highlight on tap only when the current node shows a hand cursor
if (!cursor_defining_ancestor ||
!ShowsHandCursor(cursor_defining_ancestor,
- page_->DeprecatedLocalMainFrame())) {
+ page->DeprecatedLocalMainFrame())) {
return nullptr;
}
@@ -1067,10 +1049,10 @@ Node* WebViewImpl::BestTapNode(
best_touch_node = cursor_defining_ancestor;
cursor_defining_ancestor = FindCursorDefiningAncestor(
LayoutTreeBuilderTraversal::Parent(*best_touch_node),
- page_->DeprecatedLocalMainFrame());
+ page->DeprecatedLocalMainFrame());
} while (cursor_defining_ancestor &&
ShowsHandCursor(cursor_defining_ancestor,
- page_->DeprecatedLocalMainFrame()));
+ page->DeprecatedLocalMainFrame()));
return best_touch_node;
}
@@ -1137,9 +1119,7 @@ void WebViewImpl::AnimateDoubleTapZoom(const gfx::Point& point_in_root_frame,
}
void WebViewImpl::ZoomToFindInPageRect(const WebRect& rect_in_root_frame) {
- // TODO(lukasza): https://crbug.com/734209: Add OOPIF support.
- if (!MainFrameImpl())
- return;
+ DCHECK(MainFrameImpl());
WebRect block_bounds = MainFrameImpl()->FrameWidgetImpl()->ComputeBlockBound(
gfx::Point(rect_in_root_frame.x + rect_in_root_frame.width / 2,
@@ -1210,15 +1190,16 @@ void WebViewImpl::ShowContextMenuForElement(WebElement element) {
}
}
-PagePopup* WebViewImpl::OpenPagePopup(PagePopupClient* client) {
+WebPagePopupImpl* WebViewImpl::OpenPagePopup(PagePopupClient* client) {
DCHECK(client);
- if (HasOpenedPopup())
- HidePopups();
+
+ // This guarantees there is never more than 1 PagePopup active at a time.
+ CancelPagePopup();
DCHECK(!page_popup_);
WebLocalFrameImpl* frame = WebLocalFrameImpl::FromFrame(
client->OwnerElement().GetDocument().GetFrame()->LocalFrameRoot());
- WebWidget* popup_widget = client_->CreatePopup(frame);
+ WebPagePopup* popup_widget = AsView().client->CreatePopup(frame);
// CreatePopup returns nullptr if this renderer process is about to die.
if (!popup_widget)
return nullptr;
@@ -1228,6 +1209,11 @@ PagePopup* WebViewImpl::OpenPagePopup(PagePopupClient* client) {
return page_popup_.get();
}
+void WebViewImpl::CancelPagePopup() {
+ if (page_popup_)
+ page_popup_->Cancel();
+}
+
void WebViewImpl::ClosePagePopup(PagePopup* popup) {
DCHECK(popup);
WebPagePopupImpl* popup_impl = ToWebPagePopupImpl(popup);
@@ -1242,11 +1228,6 @@ void WebViewImpl::CleanupPagePopup() {
DisablePopupMouseWheelEventListener();
}
-void WebViewImpl::CancelPagePopup() {
- if (page_popup_)
- page_popup_->Cancel();
-}
-
void WebViewImpl::EnablePopupMouseWheelEventListener(
WebLocalFrameImpl* local_root) {
DCHECK(!popup_mouse_wheel_event_listener_);
@@ -1280,7 +1261,8 @@ LocalDOMWindow* WebViewImpl::PagePopupWindow() const {
}
Frame* WebViewImpl::FocusedCoreFrame() const {
- return page_ ? page_->GetFocusController().FocusedOrMainFrame() : nullptr;
+ Page* page = AsView().page.Get();
+ return page ? page->GetFocusController().FocusedOrMainFrame() : nullptr;
}
// WebWidget ------------------------------------------------------------------
@@ -1289,16 +1271,17 @@ void WebViewImpl::Close() {
DCHECK(AllInstances().Contains(this));
AllInstances().erase(this);
- if (page_) {
- // Initiate shutdown for the entire frameset. This will cause a lot of
- // notifications to be sent.
- page_->WillBeDestroyed();
- page_.Clear();
- }
+ // We don't want Close() to happen twice do we??
+ CHECK(AsView().page);
+
+ // Initiate shutdown for the entire frameset. This will cause a lot of
+ // notifications to be sent.
+ AsView().page->WillBeDestroyed();
+ AsView().page.Clear();
// Reset the delegate to prevent notifications being sent as we're being
// deleted.
- client_ = nullptr;
+ AsView().client = nullptr;
Release(); // Balances a reference acquired in WebView::Create
}
@@ -1514,7 +1497,7 @@ void WebViewImpl::DidUpdateFullscreenSize() {
void WebViewImpl::SetSuppressFrameRequestsWorkaroundFor704763Only(
bool suppress_frame_requests) {
- page_->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
+ AsView().page->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
suppress_frame_requests);
}
void WebViewImpl::BeginFrame(base::TimeTicks last_frame_time) {
@@ -1525,9 +1508,14 @@ void WebViewImpl::BeginFrame(base::TimeTicks last_frame_time) {
if (!MainFrameImpl())
return;
+ if (LocalFrameView* view = MainFrameImpl()->GetFrameView()) {
+ if (FragmentAnchor* anchor = view->GetFragmentAnchor())
+ anchor->PerformPreRafActions();
+ }
+
DocumentLifecycle::AllowThrottlingScope throttling_scope(
MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
- PageWidgetDelegate::Animate(*page_, last_frame_time);
+ PageWidgetDelegate::Animate(*AsView().page, last_frame_time);
}
void WebViewImpl::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
@@ -1547,8 +1535,8 @@ void WebViewImpl::UpdateLifecycle(LifecycleUpdate requested_update,
DocumentLifecycle::AllowThrottlingScope throttling_scope(
MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
- PageWidgetDelegate::UpdateLifecycle(*page_, *MainFrameImpl()->GetFrame(),
- requested_update, reason);
+ PageWidgetDelegate::UpdateLifecycle(
+ *AsView().page, *MainFrameImpl()->GetFrame(), requested_update, reason);
if (requested_update == LifecycleUpdate::kLayout)
return;
@@ -1600,22 +1588,8 @@ void WebViewImpl::PaintContent(cc::PaintCanvas* canvas, const WebRect& rect) {
// This should only be used when compositing is not being used for this
// WebView, and it is painting into the recording of its parent.
DCHECK(!IsAcceleratedCompositingActive());
- PageWidgetDelegate::PaintContent(*page_, canvas, rect,
- *page_->DeprecatedLocalMainFrame());
-}
-
-void WebViewImpl::PaintContentIgnoringCompositing(cc::PaintCanvas* canvas,
- const WebRect& rect) {
- // This is called on a composited WebViewImpl, but we will ignore it,
- // producing all possible content of the WebViewImpl into the PaintCanvas.
- DCHECK(IsAcceleratedCompositingActive());
- PageWidgetDelegate::PaintContentIgnoringCompositing(
- *page_, canvas, rect, *page_->DeprecatedLocalMainFrame());
-}
-
-void WebViewImpl::LayoutAndPaintAsync(base::OnceClosure callback) {
- if (layer_tree_view_)
- layer_tree_view_->LayoutAndPaintAsync(std::move(callback));
+ PageWidgetDelegate::PaintContent(canvas, rect,
+ *AsView().page->DeprecatedLocalMainFrame());
}
void WebViewImpl::CompositeAndReadbackAsync(
@@ -1734,6 +1708,22 @@ WebInputEventResult WebViewImpl::HandleInputEvent(
}
}
+ if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) {
+ // Notify the focus frame of the input. Note that the other frames are not
+ // notified as input is only handled by the focused frame.
+ Frame* frame = FocusedCoreFrame();
+ if (frame && frame->IsLocalFrame()) {
+ LocalFrame* local_frame = ToLocalFrame(frame);
+ if (local_frame && local_frame->View() &&
+ local_frame->View()
+ ->GetPaintTimingDetector()
+ .NeedToNotifyInputOrScroll()) {
+ local_frame->View()->GetPaintTimingDetector().NotifyInputEvent(
+ input_event.GetType());
+ }
+ }
+ }
+
// Skip the pointerrawmove for mouse capture case.
if (mouse_capture_node_ &&
input_event.GetType() == WebInputEvent::kPointerRawMove)
@@ -1809,23 +1799,24 @@ WebInputEventResult WebViewImpl::HandleCapturedMouseEvent(
}
void WebViewImpl::SetCursorVisibilityState(bool is_visible) {
- if (page_)
- page_->SetIsCursorVisible(is_visible);
+ if (AsView().page)
+ AsView().page->SetIsCursorVisible(is_visible);
}
void WebViewImpl::MouseCaptureLost() {
TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this);
mouse_capture_node_ = nullptr;
- if (page_->DeprecatedLocalMainFrame())
- page_->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(false);
+ if (AsView().page->DeprecatedLocalMainFrame())
+ AsView().page->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(false);
}
void WebViewImpl::SetFocus(bool enable) {
if (enable)
- page_->GetFocusController().SetActive(true);
- page_->GetFocusController().SetFocused(enable);
+ AsView().page->GetFocusController().SetActive(true);
+ AsView().page->GetFocusController().SetFocused(enable);
if (enable) {
- LocalFrame* focused_frame = page_->GetFocusController().FocusedFrame();
+ LocalFrame* focused_frame =
+ AsView().page->GetFocusController().FocusedFrame();
if (focused_frame) {
Element* element = focused_frame->GetDocument()->FocusedElement();
if (element && focused_frame->Selection()
@@ -1850,15 +1841,16 @@ void WebViewImpl::SetFocus(bool enable) {
}
ime_accept_events_ = true;
} else {
- HidePopups();
+ CancelPagePopup();
// Clear focus on the currently focused frame if any.
- if (!page_)
+ if (!AsView().page)
return;
- LocalFrame* frame = page_->MainFrame() && page_->MainFrame()->IsLocalFrame()
- ? page_->DeprecatedLocalMainFrame()
- : nullptr;
+ LocalFrame* frame =
+ AsView().page->MainFrame() && AsView().page->MainFrame()->IsLocalFrame()
+ ? ToLocalFrame(AsView().page->MainFrame())
+ : nullptr;
if (!frame)
return;
@@ -1906,25 +1898,6 @@ bool WebViewImpl::SelectionBounds(WebRect& anchor_web,
return true;
}
-SkColor WebViewImpl::BackgroundColor() const {
- if (background_color_override_enabled_)
- return background_color_override_;
- if (!page_)
- return BaseBackgroundColor().Rgb();
- if (!page_->MainFrame())
- return BaseBackgroundColor().Rgb();
- if (!page_->MainFrame()->IsLocalFrame())
- return BaseBackgroundColor().Rgb();
- LocalFrameView* view = page_->DeprecatedLocalMainFrame()->View();
- if (!view)
- return BaseBackgroundColor().Rgb();
- return view->DocumentBackgroundColor().Rgb();
-}
-
-WebPagePopupImpl* WebViewImpl::GetPagePopup() const {
- return page_popup_.get();
-}
-
bool WebViewImpl::IsAcceleratedCompositingActive() const {
return !!root_layer_;
}
@@ -1965,7 +1938,7 @@ void WebViewImpl::DidLosePointerLock() {
WebSettingsImpl* WebViewImpl::SettingsImpl() {
if (!web_settings_) {
web_settings_ = std::make_unique<WebSettingsImpl>(
- &page_->GetSettings(), dev_tools_emulator_.Get());
+ &AsView().page->GetSettings(), dev_tools_emulator_.Get());
}
DCHECK(web_settings_);
return web_settings_.get();
@@ -1976,21 +1949,24 @@ WebSettings* WebViewImpl::GetSettings() {
}
WebString WebViewImpl::PageEncoding() const {
- if (!page_)
+ if (!AsView().page)
return WebString();
- if (!page_->MainFrame()->IsLocalFrame())
+ if (!AsView().page->MainFrame()->IsLocalFrame())
return WebString();
+ LocalFrame* main_frame = ToLocalFrame(AsView().page->MainFrame());
+
// FIXME: Is this check needed?
- if (!page_->DeprecatedLocalMainFrame()->GetDocument()->Loader())
+ if (!main_frame->GetDocument()->Loader())
return WebString();
- return page_->DeprecatedLocalMainFrame()->GetDocument()->EncodingName();
+ return main_frame->GetDocument()->EncodingName();
}
WebFrame* WebViewImpl::MainFrame() {
- return WebFrame::FromFrame(page_ ? page_->MainFrame() : nullptr);
+ Page* page = AsView().page.Get();
+ return WebFrame::FromFrame(page ? page->MainFrame() : nullptr);
}
WebLocalFrame* WebViewImpl::FocusedFrame() {
@@ -2025,7 +2001,7 @@ void WebViewImpl::FocusDocumentView(WebFrame* frame) {
}
void WebViewImpl::SetInitialFocus(bool reverse) {
- if (!page_)
+ if (!AsView().page)
return;
Frame* frame = GetPage()->GetFocusController().FocusedOrMainFrame();
if (frame->IsLocalFrame()) {
@@ -2305,16 +2281,16 @@ double WebViewImpl::SetZoomLevel(double zoom_level) {
if (compositor_device_scale_factor_override_) {
// Adjust the page's DSF so that DevicePixelRatio becomes
// m_zoomFactorForDeviceScaleFactor.
- GetPage()->SetDeviceScaleFactorDeprecated(
+ AsView().page->SetDeviceScaleFactorDeprecated(
zoom_factor_for_device_scale_factor_ /
compositor_device_scale_factor_override_);
zoom_factor *= compositor_device_scale_factor_override_;
} else {
- GetPage()->SetDeviceScaleFactorDeprecated(1.f);
+ AsView().page->SetDeviceScaleFactorDeprecated(1.f);
zoom_factor *= zoom_factor_for_device_scale_factor_;
}
}
- PropagateZoomFactorToLocalFrameRoots(page_->MainFrame(), zoom_factor);
+ PropagateZoomFactorToLocalFrameRoots(AsView().page->MainFrame(), zoom_factor);
return zoom_level_;
}
@@ -2323,7 +2299,7 @@ void WebViewImpl::ZoomLimitsChanged(double minimum_zoom_level,
double maximum_zoom_level) {
minimum_zoom_level_ = minimum_zoom_level;
maximum_zoom_level_ = maximum_zoom_level;
- client_->ZoomLimitsChanged(minimum_zoom_level_, maximum_zoom_level_);
+ AsView().client->ZoomLimitsChanged(minimum_zoom_level_, maximum_zoom_level_);
}
float WebViewImpl::TextZoomFactor() {
@@ -2501,8 +2477,13 @@ void WebViewImpl::RefreshPageScaleFactor() {
void WebViewImpl::UpdatePageDefinedViewportConstraints(
const ViewportDescription& description) {
- if (!GetPage() || (!size_.width && !size_.height) ||
- !GetPage()->MainFrame()->IsLocalFrame())
+ if (!GetPage() || (!size_.width && !size_.height))
+ return;
+ // The viewport is a property of the main frame and its widget, so ignore it
+ // when the main frame is remote.
+ // TODO(danakj): Remove calls to this method from ChromeClient and DCHECK this
+ // instead.
+ if (!GetPage()->MainFrame()->IsLocalFrame())
return;
// When viewport is disabled (non-mobile), we always use gpu rasterization.
@@ -2518,12 +2499,16 @@ void WebViewImpl::UpdatePageDefinedViewportConstraints(
// for non-viewport-specified pages in order to avoid crashes or other
// problems on mobile devices with gpu rasterization.
bool viewport_enabled = GetSettings()->ViewportEnabled();
- matches_heuristics_for_gpu_rasterization_ =
+ bool gpu_rasterization_allowed =
viewport_enabled ? description.MatchesHeuristicsForGpuRasterization()
: true;
+
+ // 1. Non-composited WebViews do not worry about gpu rasterization.
+ // 2. After removing the LayerTreeView during shutdown, but before the frame
+ // is detached, we may do layout still.
if (layer_tree_view_) {
layer_tree_view_->HeuristicsForGpuRasterizationUpdated(
- matches_heuristics_for_gpu_rasterization_);
+ gpu_rasterization_allowed);
}
if (!viewport_enabled) {
@@ -2623,9 +2608,9 @@ IntSize WebViewImpl::ContentsSize() const {
}
WebSize WebViewImpl::ContentsPreferredMinimumSize() {
- Document* document = page_->MainFrame()->IsLocalFrame()
- ? page_->DeprecatedLocalMainFrame()->GetDocument()
- : nullptr;
+ if (!AsView().page->MainFrame()->IsLocalFrame())
+ return WebSize();
+ Document* document = ToLocalFrame(AsView().page->MainFrame())->GetDocument();
if (!document || !document->GetLayoutView() || !document->documentElement() ||
!document->documentElement()->GetLayoutBox())
return WebSize();
@@ -2753,12 +2738,12 @@ void WebViewImpl::SendResizeEventAndRepaint() {
MainFrameImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
}
- if (client_) {
+ if (AsWidget().client) {
if (layer_tree_view_) {
UpdateLayerTreeViewport();
} else {
WebRect damaged_rect(0, 0, size_.width, size_.height);
- client_->WidgetClient()->DidInvalidateRect(damaged_rect);
+ AsWidget().client->DidInvalidateRect(damaged_rect);
}
}
}
@@ -2796,11 +2781,11 @@ void WebViewImpl::SetDeviceEmulationTransform(
if (transform == device_emulation_transform_)
return;
device_emulation_transform_ = transform;
+ GetPage()->GetVisualViewport().SetNeedsPaintPropertyUpdate();
UpdateDeviceEmulationTransform();
}
-TransformationMatrix WebViewImpl::GetDeviceEmulationTransformForTesting()
- const {
+TransformationMatrix WebViewImpl::GetDeviceEmulationTransform() const {
return device_emulation_transform_;
}
@@ -2814,8 +2799,10 @@ void WebViewImpl::DisableDeviceEmulation() {
}
void WebViewImpl::PerformCustomContextMenuAction(unsigned action) {
- if (page_)
- page_->GetContextMenuController().CustomContextMenuItemSelected(action);
+ if (AsView().page) {
+ AsView().page->GetContextMenuController().CustomContextMenuItemSelected(
+ action);
+ }
}
void WebViewImpl::ShowContextMenu(WebMenuSourceType source_type) {
@@ -2835,15 +2822,11 @@ WebURL WebViewImpl::GetURLForDebugTrace() {
}
void WebViewImpl::DidCloseContextMenu() {
- LocalFrame* frame = page_->GetFocusController().FocusedFrame();
+ LocalFrame* frame = AsView().page->GetFocusController().FocusedFrame();
if (frame)
frame->Selection().SetCaretBlinkingSuspended(false);
}
-void WebViewImpl::HidePopups() {
- CancelPagePopup();
-}
-
WebInputMethodController* WebViewImpl::GetActiveWebInputMethodController()
const {
WebLocalFrameImpl* local_frame =
@@ -2851,6 +2834,18 @@ WebInputMethodController* WebViewImpl::GetActiveWebInputMethodController()
return local_frame ? local_frame->GetInputMethodController() : nullptr;
}
+SkColor WebViewImpl::BackgroundColor() const {
+ if (background_color_override_enabled_)
+ return background_color_override_;
+ Page* page = AsView().page.Get();
+ if (page && page->MainFrame() && page->MainFrame()->IsLocalFrame()) {
+ LocalFrameView* view = ToLocalFrame(page->MainFrame())->View();
+ if (view)
+ return view->DocumentBackgroundColor().Rgb();
+ }
+ return BaseBackgroundColor().Rgb();
+}
+
Color WebViewImpl::BaseBackgroundColor() const {
return base_background_color_override_enabled_
? base_background_color_override_
@@ -2902,8 +2897,9 @@ void WebViewImpl::ClearBaseBackgroundColorOverride() {
void WebViewImpl::UpdateBaseBackgroundColor() {
Color color = BaseBackgroundColor();
- if (page_->MainFrame() && page_->MainFrame()->IsLocalFrame()) {
- LocalFrameView* view = page_->DeprecatedLocalMainFrame()->View();
+ if (AsView().page->MainFrame() &&
+ AsView().page->MainFrame()->IsLocalFrame()) {
+ LocalFrameView* view = ToLocalFrame(AsView().page->MainFrame())->View();
view->SetBaseBackgroundColor(color);
view->UpdateBaseBackgroundColorRecursively(color);
}
@@ -2925,11 +2921,11 @@ void WebViewImpl::SetDomainRelaxationForbidden(bool forbidden,
}
void WebViewImpl::SetWindowFeatures(const WebWindowFeatures& features) {
- page_->SetWindowFeatures(features);
+ AsView().page->SetWindowFeatures(features);
}
void WebViewImpl::SetOpenedByDOM() {
- page_->SetOpenedByDOM();
+ AsView().page->SetOpenedByDOM();
}
void WebViewImpl::SetSelectionColors(unsigned active_background_color,
@@ -2963,7 +2959,7 @@ void WebViewImpl::DidCommitLoad(bool is_new_navigation,
void WebViewImpl::ResizeAfterLayout() {
DCHECK(MainFrameImpl());
- if (!client_ || !client_->CanUpdateLayout())
+ if (!AsView().client || !AsView().client->CanUpdateLayout())
return;
if (should_auto_resize_) {
@@ -2976,7 +2972,7 @@ void WebViewImpl::ResizeAfterLayout() {
GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_);
view->SetInitialViewportSize(size_);
- client_->DidAutoResize(size_);
+ AsView().client->DidAutoResize(size_);
SendResizeEventAndRepaint();
}
}
@@ -2989,10 +2985,10 @@ void WebViewImpl::ResizeAfterLayout() {
void WebViewImpl::MainFrameLayoutUpdated() {
DCHECK(MainFrameImpl());
- if (!client_)
+ if (!AsView().client)
return;
- client_->DidUpdateMainFrameLayout();
+ AsView().client->DidUpdateMainFrameLayout();
}
void WebViewImpl::DidChangeContentsSize() {
@@ -3015,7 +3011,7 @@ void WebViewImpl::DidChangeContentsSize() {
void WebViewImpl::PageScaleFactorChanged() {
GetPageScaleConstraintsSet().SetNeedsReset(false);
UpdateLayerTreeViewport();
- client_->PageScaleFactorChanged();
+ AsView().client->PageScaleFactorChanged();
dev_tools_emulator_->MainFrameScrollOrScaleChanged();
}
@@ -3039,8 +3035,10 @@ void WebViewImpl::SetZoomFactorOverride(float zoom_factor) {
SetZoomLevel(ZoomLevel());
}
-void WebViewImpl::SetPageOverlayColor(SkColor color) {
- page_->SetPageOverlayColor(color);
+void WebViewImpl::SetMainFrameOverlayColor(SkColor color) {
+ DCHECK(AsView().page->MainFrame());
+ if (AsView().page->MainFrame()->IsLocalFrame())
+ ToLocalFrame(AsView().page->MainFrame())->SetMainFrameColorOverlay(color);
}
WebPageImportanceSignals* WebViewImpl::PageImportanceSignals() {
@@ -3048,7 +3046,7 @@ WebPageImportanceSignals* WebViewImpl::PageImportanceSignals() {
}
Element* WebViewImpl::FocusedElement() const {
- LocalFrame* frame = page_->GetFocusController().FocusedFrame();
+ LocalFrame* frame = AsView().page->GetFocusController().FocusedFrame();
if (!frame)
return nullptr;
@@ -3061,16 +3059,13 @@ Element* WebViewImpl::FocusedElement() const {
HitTestResult WebViewImpl::HitTestResultForRootFramePos(
const LayoutPoint& pos_in_root_frame) {
- if (!page_->MainFrame()->IsLocalFrame())
+ if (!AsView().page->MainFrame()->IsLocalFrame())
return HitTestResult();
+ LocalFrame* main_frame = ToLocalFrame(AsView().page->MainFrame());
HitTestLocation location(
- page_->DeprecatedLocalMainFrame()->View()->ConvertFromRootFrame(
- pos_in_root_frame));
- HitTestResult result =
- page_->DeprecatedLocalMainFrame()
- ->GetEventHandler()
- .HitTestResultAtLocation(
- location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
+ main_frame->View()->ConvertFromRootFrame(pos_in_root_frame));
+ HitTestResult result = main_frame->GetEventHandler().HitTestResultAtLocation(
+ location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
result.SetToShadowHostIfInRestrictedShadowRoot();
return result;
}
@@ -3078,7 +3073,7 @@ HitTestResult WebViewImpl::HitTestResultForRootFramePos(
WebHitTestResult WebViewImpl::HitTestResultForTap(
const gfx::Point& tap_point_window_pos,
const WebSize& tap_area) {
- if (!page_->MainFrame()->IsLocalFrame())
+ if (!AsView().page->MainFrame()->IsLocalFrame())
return HitTestResult();
WebGestureEvent tap_event(
@@ -3093,9 +3088,9 @@ WebHitTestResult WebViewImpl::HitTestResultForTap(
WebGestureEvent scaled_event =
TransformWebGestureEvent(MainFrameImpl()->GetFrameView(), tap_event);
+ LocalFrame* main_frame = ToLocalFrame(AsView().page->MainFrame());
HitTestResult result =
- page_->DeprecatedLocalMainFrame()
- ->GetEventHandler()
+ main_frame->GetEventHandler()
.HitTestResultForGestureEvent(
scaled_event, HitTestRequest::kReadOnly | HitTestRequest::kActive)
.GetHitTestResult();
@@ -3156,8 +3151,8 @@ void WebViewImpl::SetRootGraphicsLayer(GraphicsLayer* graphics_layer) {
if (!layer_tree_view_)
return;
- // In SPv2, setRootLayer is used instead.
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ // In CAP, setRootLayer is used instead.
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
visual_viewport.AttachLayerTree(graphics_layer);
@@ -3204,9 +3199,9 @@ void WebViewImpl::SetRootLayer(scoped_refptr<cc::Layer> layer) {
void WebViewImpl::InvalidateRect(const IntRect& rect) {
if (layer_tree_view_) {
UpdateLayerTreeViewport();
- } else if (client_) {
+ } else if (AsWidget().client) {
// This is only for WebViewPlugin.
- client_->WidgetClient()->DidInvalidateRect(rect);
+ AsWidget().client->DidInvalidateRect(rect);
}
}
@@ -3226,23 +3221,15 @@ GraphicsLayer* WebViewImpl::RootGraphicsLayer() {
return root_graphics_layer_;
}
-void WebViewImpl::ScheduleAnimationForWidget() {
- if (layer_tree_view_) {
- layer_tree_view_->SetNeedsBeginFrame();
- return;
- }
- if (client_)
- client_->WidgetClient()->ScheduleAnimation();
-}
-
void WebViewImpl::SetLayerTreeView(WebLayerTreeView* layer_tree_view) {
+ DCHECK(does_composite_);
layer_tree_view_ = layer_tree_view;
if (Platform::Current()->IsThreadedAnimationEnabled()) {
animation_host_ = std::make_unique<CompositorAnimationHost>(
layer_tree_view_->CompositorAnimationHost());
}
- page_->LayerTreeViewInitialized(*layer_tree_view_, nullptr);
+ AsView().page->LayerTreeViewInitialized(*layer_tree_view_, nullptr);
// We don't yet have a page loaded at this point of the initialization of
// WebViewImpl, so don't allow cc to commit any frames Blink might
// try to create in the meantime.
@@ -3291,6 +3278,56 @@ void WebViewImpl::RecordWheelAndTouchScrollingCount(
UseCounter::Count(MainFrameImpl()->GetFrame(), WebFeature::kScrollByTouch);
}
+Node* WebViewImpl::FindNodeFromScrollableCompositorElementId(
+ cc::ElementId element_id) const {
+ if (!GetPage())
+ return nullptr;
+
+ if (element_id == GetPage()->GetVisualViewport().GetCompositorElementId()) {
+ // Return the Document in this case since the window.visualViewport DOM
+ // object is not a node.
+ if (MainFrameImpl())
+ return MainFrameImpl()->GetDocument();
+ }
+
+ if (!GetPage()->GetScrollingCoordinator())
+ return nullptr;
+ ScrollableArea* scrollable_area =
+ GetPage()
+ ->GetScrollingCoordinator()
+ ->ScrollableAreaWithElementIdInAllLocalFrames(element_id);
+ if (!scrollable_area || !scrollable_area->GetLayoutBox())
+ return nullptr;
+
+ return scrollable_area->GetLayoutBox()->GetNode();
+}
+
+void WebViewImpl::SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) {
+ if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
+ return;
+
+ DCHECK(!overscroll_delta.IsZero());
+ Node* target_node =
+ FindNodeFromScrollableCompositorElementId(scroll_latched_element_id);
+ if (target_node) {
+ target_node->GetDocument().EnqueueOverscrollEventForNode(
+ target_node, overscroll_delta.x(), overscroll_delta.y());
+ }
+}
+
+void WebViewImpl::SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) {
+ if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
+ return;
+
+ Node* target_node =
+ FindNodeFromScrollableCompositorElementId(scroll_latched_element_id);
+ if (target_node)
+ target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
+}
+
void WebViewImpl::UpdateLayerTreeViewport() {
if (!GetPage() || !layer_tree_view_)
return;
@@ -3322,18 +3359,15 @@ PageScheduler* WebViewImpl::Scheduler() const {
return GetPage()->GetPageScheduler();
}
-void WebViewImpl::SetVisibilityState(
- mojom::PageVisibilityState visibility_state,
- bool is_initial_state) {
+void WebViewImpl::SetIsHidden(bool hidden, bool is_initial_state) {
DCHECK(GetPage());
- GetPage()->SetVisibilityState(visibility_state, is_initial_state);
- GetPage()->GetPageScheduler()->SetPageVisible(
- visibility_state == mojom::PageVisibilityState::kVisible);
+ GetPage()->SetIsHidden(hidden, is_initial_state);
+ GetPage()->GetPageScheduler()->SetPageVisible(!hidden);
}
-mojom::PageVisibilityState WebViewImpl::VisibilityState() {
+bool WebViewImpl::IsHidden() {
DCHECK(GetPage());
- return GetPage()->VisibilityState();
+ return !GetPage()->IsPageVisible();
}
void WebViewImpl::ForceNextWebGLContextCreationToFail() {
@@ -3391,15 +3425,15 @@ WebWidget* WebViewImpl::MainFrameWidget() {
}
void WebViewImpl::AddAutoplayFlags(int32_t value) {
- page_->AddAutoplayFlags(value);
+ AsView().page->AddAutoplayFlags(value);
}
void WebViewImpl::ClearAutoplayFlags() {
- page_->ClearAutoplayFlags();
+ AsView().page->ClearAutoplayFlags();
}
int32_t WebViewImpl::AutoplayFlagsForTest() {
- return page_->AutoplayFlags();
+ return AsView().page->AutoplayFlags();
}
void WebViewImpl::DeferMainFrameUpdateForTesting() {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_impl.h b/chromium/third_party/blink/renderer/core/exported/web_view_impl.h
index a3c6109531c..c83d975c7b0 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -101,59 +101,16 @@ class CORE_EXPORT WebViewImpl final : public WebView,
public PageWidgetEventHandler {
public:
static WebViewImpl* Create(WebViewClient*,
- WebWidgetClient*,
- mojom::PageVisibilityState,
+ bool is_hidden,
+ bool compositing_enabled,
WebViewImpl* opener);
static HashSet<WebViewImpl*>& AllInstances();
// Returns true if popup menus should be rendered by the browser, false if
// they should be rendered by WebKit (which is the default).
static bool UseExternalPopupMenus();
- // WebWidget methods:
- void SetLayerTreeView(WebLayerTreeView*) override;
- void Close() override;
- WebSize Size() override;
- void Resize(const WebSize&) override;
- void ResizeVisualViewport(const WebSize&) override;
- void DidEnterFullscreen() override;
- void DidExitFullscreen() override;
-
- void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) override;
- void BeginFrame(base::TimeTicks last_frame_time) override;
- void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
- void UpdateLifecycle(LifecycleUpdate requested_update,
- LifecycleUpdateReason reason) override;
- void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) override;
- void RequestPresentationCallbackForTesting(
- base::OnceClosure callback) override;
- void PaintContent(cc::PaintCanvas*, const WebRect&) override;
- void PaintContentIgnoringCompositing(cc::PaintCanvas*,
- const WebRect&) override;
- void LayoutAndPaintAsync(base::OnceClosure callback) override;
- void CompositeAndReadbackAsync(
- base::OnceCallback<void(const SkBitmap&)> callback) override;
- void ThemeChanged() override;
- WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override;
- WebInputEventResult DispatchBufferedTouchEvents() override;
- void SetCursorVisibilityState(bool is_visible) override;
- void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override;
- void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
- bool has_scrolled_by_touch) override;
- void MouseCaptureLost() override;
- void SetFocus(bool enable) override;
- SkColor BackgroundColor() const override;
- WebPagePopupImpl* GetPagePopup() const override;
- bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
- bool IsAcceleratedCompositingActive() const override;
- void WillCloseLayerTreeView() override;
- void DidAcquirePointerLock() override;
- void DidNotAcquirePointerLock() override;
- void DidLosePointerLock() override;
- void ShowContextMenu(WebMenuSourceType) override;
- WebURL GetURLForDebugTrace() override;
-
// WebView methods:
- bool IsWebView() const override { return true; }
+ void SetWebWidgetClient(WebWidgetClient*) override;
void SetPrerendererClient(WebPrerendererClient*) override;
WebSettings* GetSettings() override;
WebString PageEncoding() const override;
@@ -177,7 +134,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void SetInitialFocus(bool reverse) override;
void ClearFocusedElement() override;
void SmoothScroll(int target_x, int target_y, long duration_ms) override;
- void ZoomToFindInPageRect(const WebRect&);
void AdvanceFocus(bool reverse) override;
void AdvanceFocusAcrossFrames(WebFocusType,
WebRemoteFrame* from,
@@ -204,7 +160,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void SetDisplayMode(WebDisplayMode) override;
void AnimateDoubleTapZoom(const gfx::Point&,
const WebRect& block_bounds) override;
-
+ void ZoomToFindInPageRect(const WebRect&) override;
void SetDeviceScaleFactor(float) override;
void SetZoomFactorForDeviceScaleFactor(float) override;
float ZoomFactorForDeviceScaleFactor() override {
@@ -228,17 +184,18 @@ class CORE_EXPORT WebViewImpl final : public WebView,
unsigned inactive_foreground_color) override;
void PerformCustomContextMenuAction(unsigned action) override;
void DidCloseContextMenu() override;
- void HidePopups() override;
- void SetPageOverlayColor(SkColor) override;
+ void CancelPagePopup() override;
+ WebPagePopupImpl* GetPagePopup() const override { return page_popup_.get(); }
+ void SetMainFrameOverlayColor(SkColor) override;
WebPageImportanceSignals* PageImportanceSignals() override;
- void SetShowPaintRects(bool) override;
- void SetShowDebugBorders(bool);
- void SetShowFPSCounter(bool) override;
- void SetShowScrollBottleneckRects(bool) override;
- void SetShowHitTestBorders(bool);
void AcceptLanguagesChanged() override;
void SetPageFrozen(bool frozen) override;
WebWidget* MainFrameWidget() override;
+ void SetBaseBackgroundColor(SkColor) override;
+ void SetBackgroundColorOverride(SkColor) override;
+ void ClearBackgroundColorOverride() override;
+ void SetBaseBackgroundColorOverride(SkColor) override;
+ void ClearBaseBackgroundColorOverride() override;
void DidUpdateFullscreenSize();
@@ -250,16 +207,12 @@ class CORE_EXPORT WebViewImpl final : public WebView,
HitTestResult CoreHitTestResultAt(const gfx::Point&);
void InvalidateRect(const IntRect&);
- void SetBaseBackgroundColor(SkColor);
- void SetBaseBackgroundColorOverride(SkColor);
- void ClearBaseBackgroundColorOverride();
- void SetBackgroundColorOverride(SkColor);
- void ClearBackgroundColorOverride();
void SetZoomFactorOverride(float);
void SetCompositorDeviceScaleFactorOverride(float);
void SetDeviceEmulationTransform(const TransformationMatrix&);
- TransformationMatrix GetDeviceEmulationTransformForTesting() const;
+ TransformationMatrix GetDeviceEmulationTransform() const;
+ SkColor BackgroundColor() const;
Color BaseBackgroundColor() const;
bool BackgroundColorOverrideEnabled() const {
return background_color_override_enabled_;
@@ -271,14 +224,14 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// Returns the currently focused Element or null if no element has focus.
Element* FocusedElement() const;
- WebViewClient* Client() { return client_; }
+ WebViewClient* Client() { return AsView().client; }
// TODO(dcheng): This client should be acquirable from the MainFrameImpl
// in some cases? We need to know how to get it in all cases.
- WebWidgetClient* WidgetClient() { return widget_client_; }
+ WebWidgetClient* WidgetClient() { return AsWidget().client; }
// Returns the page object associated with this view. This may be null when
// the page is shutting down, but will be valid at all other times.
- Page* GetPage() const { return page_.Get(); }
+ Page* GetPage() const { return AsView().page.Get(); }
WebDevToolsAgentImpl* MainFrameDevToolsAgentImpl();
@@ -336,8 +289,11 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void UpdateMainFrameLayoutSize();
void UpdatePageDefinedViewportConstraints(const ViewportDescription&);
- PagePopup* OpenPagePopup(PagePopupClient*);
+ WebPagePopupImpl* OpenPagePopup(PagePopupClient*);
+ bool HasOpenedPopup() const { return page_popup_.get(); }
void ClosePagePopup(PagePopup*);
+ // Callback from PagePopup when it is closed, which it can be done directly
+ // without coming through WebViewImpl.
void CleanupPagePopup();
LocalDOMWindow* PagePopupWindow() const;
@@ -346,10 +302,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
PaintLayerCompositor* Compositor() const;
PageScheduler* Scheduler() const override;
- void SetVisibilityState(mojom::PageVisibilityState, bool) override;
- mojom::PageVisibilityState VisibilityState() override;
-
- bool HasOpenedPopup() const { return page_popup_.get(); }
+ void SetIsHidden(bool hidden, bool is_initial_state) override;
+ bool IsHidden() override;
// Called by a full frame plugin inside this view to inform it that its
// zoom level has been updated. The plugin should only call this function
@@ -401,10 +355,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
return animation_host_.get();
}
- bool MatchesHeuristicsForGpuRasterizationForTesting() const {
- return matches_heuristics_for_gpu_rasterization_;
- }
-
BrowserControls& GetBrowserControls();
// Called anytime browser controls layout height or content offset have
// changed.
@@ -436,10 +386,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// root.
WebInputMethodController* GetActiveWebInputMethodController() const;
- void SetLastHiddenPagePopup(WebPagePopupImpl* page_popup) {
- last_hidden_page_popup_ = page_popup;
- }
-
bool ShouldZoomToLegibleScale(const Element&);
void ZoomAndScrollToFocusedEditableElementRect(
const IntRect& element_bounds_in_document,
@@ -448,6 +394,11 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void StopDeferringCommits() { scoped_defer_main_frame_update_.reset(); }
+ // This function checks the element ids of ScrollableAreas only and returns
+ // the equivalent DOM Node if such exists.
+ Node* FindNodeFromScrollableCompositorElementId(
+ cc::ElementId element_id) const;
+
void DeferMainFrameUpdateForTesting();
private:
@@ -459,6 +410,56 @@ class CORE_EXPORT WebViewImpl final : public WebView,
FRIEND_TEST_ALL_PREFIXES(WebFrameTest,
DivScrollIntoEditableTestWithDeviceScaleFactor);
+ // TODO(danakj): DCHECK in these that we're not inside a wrong API stackframe.
+ struct ViewData;
+ ViewData& AsView() { return as_view_; }
+ const ViewData& AsView() const { return as_view_; }
+ struct WidgetData;
+ WidgetData& AsWidget() { return as_widget_; }
+ const WidgetData& AsWidget() const { return as_widget_; }
+
+ // WebWidget methods:
+ void SetLayerTreeView(WebLayerTreeView*) override;
+ void Close() override;
+ WebSize Size() override;
+ void Resize(const WebSize&) override;
+ void ResizeVisualViewport(const WebSize&) override;
+ void DidEnterFullscreen() override;
+ void DidExitFullscreen() override;
+ void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) override;
+ void BeginFrame(base::TimeTicks last_frame_time) override;
+ void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
+ void UpdateLifecycle(LifecycleUpdate requested_update,
+ LifecycleUpdateReason reason) override;
+ void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) override;
+ void RequestPresentationCallbackForTesting(
+ base::OnceClosure callback) override;
+ void PaintContent(cc::PaintCanvas*, const WebRect&) override;
+ void CompositeAndReadbackAsync(
+ base::OnceCallback<void(const SkBitmap&)> callback) override;
+ void ThemeChanged() override;
+ WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override;
+ WebInputEventResult DispatchBufferedTouchEvents() override;
+ void SetCursorVisibilityState(bool is_visible) override;
+ void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override;
+ void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
+ bool has_scrolled_by_touch) override;
+ void SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) override;
+ void SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) override;
+ void MouseCaptureLost() override;
+ void SetFocus(bool enable) override;
+ bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
+ bool IsAcceleratedCompositingActive() const override;
+ void WillCloseLayerTreeView() override;
+ void DidAcquirePointerLock() override;
+ void DidNotAcquirePointerLock() override;
+ void DidLosePointerLock() override;
+ void ShowContextMenu(WebMenuSourceType) override;
+ WebURL GetURLForDebugTrace() override;
+
void SetPageScaleFactorAndLocation(float, const FloatPoint&);
void PropagateZoomFactorToLocalFrameRoots(Frame*, float);
@@ -472,9 +473,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
float bottom_controls_height,
bool browser_controls_shrink_layout);
- // TODO(lfg): Remove once WebViewFrameWidget is deleted.
- void ScheduleAnimationForWidget();
-
void UpdateBaseBackgroundColor();
friend class WebView; // So WebView::Create can call our constructor
@@ -482,13 +480,11 @@ class CORE_EXPORT WebViewImpl final : public WebView,
friend class WTF::RefCounted<WebViewImpl>;
WebViewImpl(WebViewClient*,
- WebWidgetClient*,
- mojom::PageVisibilityState,
+ bool is_hidden,
+ bool does_composite,
WebViewImpl* opener);
~WebViewImpl() override;
- void HideSelectPopup();
-
HitTestResult HitTestResultForRootFramePos(const LayoutPoint&);
void ConfigureAutoResizeMode();
@@ -521,8 +517,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void EnablePopupMouseWheelEventListener(WebLocalFrameImpl* local_root);
void DisablePopupMouseWheelEventListener();
- void CancelPagePopup();
-
float DeviceScaleFactor() const;
void SetRootGraphicsLayer(GraphicsLayer*);
@@ -553,8 +547,24 @@ class CORE_EXPORT WebViewImpl final : public WebView,
IntPoint& scroll,
bool& need_animation);
- WebViewClient* client_; // Can be null (e.g. unittests, shared workers, etc.)
- WebWidgetClient* widget_client_; // Can also be null.
+ // These member variables should not be accessed within calls to WebWidget
+ // APIs. They can be called from within WebView APIs, and internal methods,
+ // though these need to be sorted as being for the view or the widget also.
+ struct ViewData {
+ ViewData(WebViewClient* client) : client(client) {}
+
+ // Can be null (e.g. unittests, shared workers, etc).
+ WebViewClient* client;
+ Persistent<Page> page;
+ } as_view_;
+
+ // These member variables should not be accessed within calls to WebView
+ // APIs. They can be called from within WebWidget APIs, and internal methods,
+ // though these need to be sorted as being for the view or the widget also.
+ struct WidgetData {
+ // Can be null (e.g. unittests, shared workers, etc).
+ WebWidgetClient* client = nullptr;
+ } as_widget_;
Persistent<ChromeClient> chrome_client_;
@@ -566,8 +576,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// The upper bound on the size when auto-resizing.
IntSize max_auto_size_;
- Persistent<Page> page_;
-
// An object that can be used to manipulate m_page->settings() without linking
// against WebCore. This is lazily allocated the first time GetWebSettings()
// is called.
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_test.cc b/chromium/third_party/blink/renderer/core/exported/web_view_test.cc
index 0776bb4f4c1..7c4e37f2be7 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -34,6 +34,7 @@
#include <memory>
#include <string>
+#include "base/stl_util.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/trees/layer_tree_host.h"
@@ -43,7 +44,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/common/manifest/web_display_mode.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
+#include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_coalesced_input_event.h"
#include "third_party/blink/public/platform/web_cursor_info.h"
@@ -106,7 +107,7 @@
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/page_visibility_state.h"
+#include "third_party/blink/renderer/core/page/page_hidden_state.h"
#include "third_party/blink/renderer/core/page/print_context.h"
#include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -195,9 +196,10 @@ class AutoResizeWebViewClient : public frame_test_helpers::TestWebViewClient {
TestData test_data_;
};
-class TapHandlingWebViewClient : public frame_test_helpers::TestWebViewClient {
+class TapHandlingWebWidgetClient
+ : public frame_test_helpers::TestWebWidgetClient {
public:
- // WebViewClient methods
+ // WebWidgetClient overrides.
void DidHandleGestureEvent(const WebGestureEvent& event,
bool event_cancelled) override {
if (event.GetType() == WebInputEvent::kGestureTap) {
@@ -401,7 +403,7 @@ TEST_F(WebViewTest, BrokenImage) {
WebViewImpl* web_view = web_view_helper_.Initialize();
web_view->GetSettings()->SetLoadsImagesAutomatically(true);
LoadFrame(web_view->MainFrameImpl(), url);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
std::string image_url = "http://www.test.com/non_existent.png";
@@ -418,7 +420,7 @@ TEST_F(WebViewTest, BrokenInputImage) {
WebViewImpl* web_view = web_view_helper_.Initialize();
web_view->GetSettings()->SetLoadsImagesAutomatically(true);
LoadFrame(web_view->MainFrameImpl(), url);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
std::string image_url = "http://www.test.com/non_existent.png";
@@ -487,19 +489,28 @@ TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame) {
// Note: this test doesn't use WebViewHelper since it intentionally runs
// initialization code between WebView and WebLocalFrame creation.
frame_test_helpers::TestWebViewClient web_view_client;
+ frame_test_helpers::TestWebWidgetClient web_widget_client;
WebViewImpl* web_view = static_cast<WebViewImpl*>(
- WebView::Create(&web_view_client, &web_view_client,
- mojom::PageVisibilityState::kVisible, nullptr));
+ WebView::Create(&web_view_client,
+ /*is_hidden=*/false,
+ /*compositing_enabled=*/true, nullptr));
EXPECT_NE(SK_ColorBLUE, web_view->BackgroundColor());
// webView does not have a frame yet, but we should still be able to set the
// background color.
web_view->SetBaseBackgroundColor(SK_ColorBLUE);
EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
+
+ // TODO(danakj): Make this part of attaching the main frame's WebFrameWidget.
+ web_view->SetWebWidgetClient(&web_widget_client);
+
frame_test_helpers::TestWebFrameClient web_frame_client;
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
- web_view, &web_frame_client, nullptr, nullptr);
+ web_view, &web_frame_client, nullptr,
+ mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
web_frame_client.Bind(frame);
- web_view->Close();
+ // This closes the WebView also.
+ web_view->MainFrameWidget()->Close();
}
TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent) {
@@ -513,7 +524,7 @@ TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent) {
// Set WebView background to green with alpha.
web_view->SetBaseBackgroundColor(kAlphaGreen);
web_view->GetSettings()->SetShouldClearDocumentBackground(false);
- web_view->Resize(WebSize(kWidth, kHeight));
+ web_view->MainFrameWidget()->Resize(WebSize(kWidth, kHeight));
UpdateAllLifecyclePhases();
// Set canvas background to red with alpha.
@@ -552,36 +563,36 @@ TEST_F(WebViewTest, FocusIsInactive) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "visible_iframe.html");
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
web_view->SetIsActive(true);
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
EXPECT_TRUE(frame->GetFrame()->GetDocument()->IsHTMLDocument());
Document* document = frame->GetFrame()->GetDocument();
EXPECT_TRUE(document->hasFocus());
- web_view->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(false);
web_view->SetIsActive(false);
EXPECT_FALSE(document->hasFocus());
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
web_view->SetIsActive(true);
EXPECT_TRUE(document->hasFocus());
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
web_view->SetIsActive(false);
EXPECT_FALSE(document->hasFocus());
- web_view->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(false);
web_view->SetIsActive(true);
EXPECT_FALSE(document->hasFocus());
web_view->SetIsActive(false);
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
EXPECT_TRUE(document->hasFocus());
web_view->SetIsActive(true);
- web_view->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(false);
EXPECT_FALSE(document->hasFocus());
}
TEST_F(WebViewTest, DocumentHasFocus) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(
@@ -608,11 +619,11 @@ TEST_F(WebViewTest, DocumentHasFocus) {
log_element.TextContent().Utf8().data());
web_view->SetIsActive(false);
- web_view->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(false);
EXPECT_FALSE(document->hasFocus());
EXPECT_TRUE(log_element.TextContent().IsEmpty());
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
EXPECT_TRUE(document->hasFocus());
EXPECT_STREQ("document.hasFocus(): true",
log_element.TextContent().Utf8().data());
@@ -664,7 +675,7 @@ TEST_F(WebViewTest, HitTestResultAtWithPageScaleAndPan) {
ToKURL(url), test::CoreTestDataPath("specify_size.html"));
WebViewImpl* web_view = web_view_helper_.Initialize();
LoadFrame(web_view->MainFrameImpl(), url);
- web_view->Resize(WebSize(100, 100));
+ web_view->MainFrameWidget()->Resize(WebSize(100, 100));
gfx::Point hit_point(75, 75);
// Image is at top left quandrant, so should not hit it.
@@ -720,7 +731,7 @@ TEST_F(WebViewTest, HitTestResultForTapWithTapAreaPageScaleAndPan) {
std::string url = RegisterMockedHttpURLLoad("hit_test.html");
WebViewImpl* web_view = web_view_helper_.Initialize();
LoadFrame(web_view->MainFrameImpl(), url);
- web_view->Resize(WebSize(100, 100));
+ web_view->MainFrameWidget()->Resize(WebSize(100, 100));
gfx::Point hit_point(55, 55);
// Image is at top left quandrant, so should not hit it.
@@ -1047,7 +1058,7 @@ TEST_F(WebViewTest, LongPressOutsideInputShouldNotSelectPlaceholderText) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "input_placeholder.html");
web_view->SetInitialFocus(false);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -1063,7 +1074,8 @@ TEST_F(WebViewTest, LongPressOutsideInputShouldNotSelectPlaceholderText) {
kWebGestureDeviceTouchscreen);
event.SetPositionInWidget(WebFloatPoint(100, 150));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
EXPECT_TRUE(web_view->MainFrameImpl()->SelectionAsText().IsEmpty());
}
@@ -1424,7 +1436,7 @@ TEST_F(WebViewTest, FinishCompositionDoesNotRevealSelection) {
RegisterMockedHttpURLLoad("form_with_input.html");
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "form_with_input.html");
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
web_view->SetInitialFocus(false);
EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().height);
@@ -1727,7 +1739,7 @@ TEST_F(WebViewTest, IsSelectionAnchorFirst) {
EXPECT_TRUE(frame->IsSelectionAnchorFirst());
WebRect anchor;
WebRect focus;
- web_view->SelectionBounds(anchor, focus);
+ web_view->MainFrameWidget()->SelectionBounds(anchor, focus);
frame->SelectRange(WebPoint(focus.x, focus.y), WebPoint(anchor.x, anchor.y));
EXPECT_FALSE(frame->IsSelectionAnchorFirst());
}
@@ -1775,7 +1787,7 @@ TEST_F(
Element* current_focus = nullptr;
Element* next_focus = nullptr;
int next_previous_flags;
- for (size_t i = 0; i < arraysize(focused_elements); ++i) {
+ for (size_t i = 0; i < base::size(focused_elements); ++i) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -1795,7 +1807,7 @@ TEST_F(
EXPECT_EQ(current_focus, document->FocusedElement());
// Backward Navigation in form1 with PREVIOUS
- for (size_t i = arraysize(focused_elements); i-- > 0;) {
+ for (size_t i = base::size(focused_elements); i-- > 0;) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -1994,7 +2006,7 @@ TEST_F(
Element* current_focus = nullptr;
Element* next_focus = nullptr;
int next_previous_flags;
- for (size_t i = 0; i < arraysize(focused_elements); ++i) {
+ for (size_t i = 0; i < base::size(focused_elements); ++i) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -2014,7 +2026,7 @@ TEST_F(
EXPECT_EQ(current_focus, document->FocusedElement());
// Backward Navigation in form1 with PREVIOUS
- for (size_t i = arraysize(focused_elements); i-- > 0;) {
+ for (size_t i = base::size(focused_elements); i-- > 0;) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -2095,7 +2107,7 @@ TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithTabIndexElements) {
Element* current_focus = nullptr;
Element* next_focus = nullptr;
int next_previous_flags;
- for (size_t i = 0; i < arraysize(focused_elements); ++i) {
+ for (size_t i = 0; i < base::size(focused_elements); ++i) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -2116,7 +2128,7 @@ TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithTabIndexElements) {
// Backward Navigation in form with PREVIOUS which has tabindex attribute
// which differs visual order.
- for (size_t i = arraysize(focused_elements); i-- > 0;) {
+ for (size_t i = base::size(focused_elements); i-- > 0;) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -2185,7 +2197,7 @@ TEST_F(WebViewTest,
Element* current_focus = nullptr;
Element* next_focus = nullptr;
int next_previous_flags;
- for (size_t i = 0; i < arraysize(focused_elements); ++i) {
+ for (size_t i = 0; i < base::size(focused_elements); ++i) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -2206,7 +2218,7 @@ TEST_F(WebViewTest,
// Backward Navigation in form with PREVIOUS which has has
// disabled/enabled elements which will gets skipped during navigation.
- for (size_t i = arraysize(focused_elements); i-- > 0;) {
+ for (size_t i = base::size(focused_elements); i-- > 0;) {
current_focus = document->getElementById(focused_elements[i].element_id);
EXPECT_EQ(current_focus, document->FocusedElement());
next_previous_flags =
@@ -2232,7 +2244,7 @@ TEST_F(WebViewTest, ExitingDeviceEmulationResetsPageScale) {
RegisterMockedHttpURLLoad("200-by-300.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
- web_view_impl->Resize(WebSize(200, 300));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(200, 300));
float page_scale_expected = web_view_impl->PageScaleFactor();
@@ -2254,7 +2266,7 @@ TEST_F(WebViewTest, HistoryResetScrollAndScaleState) {
RegisterMockedHttpURLLoad("200-by-300.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
- web_view_impl->Resize(WebSize(100, 150));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
UpdateAllLifecyclePhases();
EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
@@ -2299,7 +2311,7 @@ TEST_F(WebViewTest, BackForwardRestoreScroll) {
RegisterMockedHttpURLLoad("back_forward_restore_scroll.html");
WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(
base_url_ + "back_forward_restore_scroll.html");
- web_view_impl->Resize(WebSize(640, 480));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(640, 480));
web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -2353,7 +2365,7 @@ TEST_F(WebViewTest, FullscreenNoResetScroll) {
RegisterMockedHttpURLLoad("fullscreen_style.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "fullscreen_style.html");
- web_view_impl->Resize(WebSize(800, 600));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(800, 600));
UpdateAllLifecyclePhases();
// Scroll the page down.
@@ -2366,7 +2378,7 @@ TEST_F(WebViewTest, FullscreenNoResetScroll) {
std::unique_ptr<UserGestureIndicator> gesture =
LocalFrame::NotifyUserActivation(frame);
Fullscreen::RequestFullscreen(*element);
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases();
// Assert the scroll position on the document element doesn't change.
@@ -2374,7 +2386,7 @@ TEST_F(WebViewTest, FullscreenNoResetScroll) {
web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2100));
- web_view_impl->DidExitFullscreen();
+ web_view_impl->MainFrameWidget()->DidExitFullscreen();
UpdateAllLifecyclePhases();
EXPECT_EQ(2100, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
@@ -2385,7 +2397,7 @@ TEST_F(WebViewTest, FullscreenBackgroundColor) {
RegisterMockedHttpURLLoad("fullscreen_style.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "fullscreen_style.html");
- web_view_impl->Resize(WebSize(800, 600));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(800, 600));
UpdateAllLifecyclePhases();
EXPECT_EQ(SK_ColorWHITE, web_view_impl->BackgroundColor());
@@ -2396,7 +2408,7 @@ TEST_F(WebViewTest, FullscreenBackgroundColor) {
std::unique_ptr<UserGestureIndicator> gesture =
LocalFrame::NotifyUserActivation(frame);
Fullscreen::RequestFullscreen(*element);
- web_view_impl->DidEnterFullscreen();
+ web_view_impl->MainFrameWidget()->DidEnterFullscreen();
UpdateAllLifecyclePhases();
EXPECT_EQ(SK_ColorYELLOW, web_view_impl->BackgroundColor());
@@ -2500,7 +2512,7 @@ bool WebViewTest::TapElement(WebInputEvent::Type type, Element* element) {
kWebGestureDeviceTouchscreen);
event.SetPositionInWidget(center);
- web_view_helper_.GetWebView()->HandleInputEvent(
+ web_view_helper_.GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event));
RunPendingTasks();
return true;
@@ -2526,9 +2538,9 @@ IntSize WebViewTest::PrintICBSizeFromPageSize(const FloatSize& page_size) {
}
TEST_F(WebViewTest, ClientTapHandling) {
- TapHandlingWebViewClient client;
- WebView* web_view =
- web_view_helper_.InitializeAndLoad("about:blank", nullptr, &client);
+ TapHandlingWebWidgetClient client;
+ WebView* web_view = web_view_helper_.InitializeAndLoad("about:blank", nullptr,
+ nullptr, &client);
WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests(),
kWebGestureDeviceTouchscreen);
@@ -2552,12 +2564,15 @@ TEST_F(WebViewTest, ClientTapHandling) {
TEST_F(WebViewTest, ClientTapHandlingNullWebViewClient) {
// Note: this test doesn't use WebViewHelper since WebViewHelper creates an
// internal WebViewClient on demand if the supplied WebViewClient is null.
- WebViewImpl* web_view = static_cast<WebViewImpl*>(WebView::Create(
- nullptr, nullptr, mojom::PageVisibilityState::kVisible, nullptr));
+ WebViewImpl* web_view = static_cast<WebViewImpl*>(
+ WebView::Create(nullptr, /*is_hidden=*/false,
+ /*compositing_enabled=*/false, nullptr));
frame_test_helpers::TestWebFrameClient web_frame_client;
frame_test_helpers::TestWebWidgetClient web_widget_client;
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame(
- web_view, &web_frame_client, nullptr, nullptr);
+ web_view, &web_frame_client, nullptr,
+ mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), nullptr);
web_frame_client.Bind(local_frame);
blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, local_frame);
@@ -2566,8 +2581,10 @@ TEST_F(WebViewTest, ClientTapHandlingNullWebViewClient) {
kWebGestureDeviceTouchscreen);
event.SetPositionInWidget(WebFloatPoint(3, 8));
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
- web_view->Close();
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
+ // This also closes the WebView.
+ web_view->MainFrameWidget()->Close();
}
TEST_F(WebViewTest, LongPressEmptyDiv) {
@@ -2576,7 +2593,7 @@ TEST_F(WebViewTest, LongPressEmptyDiv) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "long_press_empty_div.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2587,7 +2604,8 @@ TEST_F(WebViewTest, LongPressEmptyDiv) {
event.SetPositionInWidget(WebFloatPoint(250, 150));
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
}
TEST_F(WebViewTest, LongPressEmptyDivAlwaysShow) {
@@ -2596,7 +2614,7 @@ TEST_F(WebViewTest, LongPressEmptyDivAlwaysShow) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "long_press_empty_div.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(true);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2607,7 +2625,8 @@ TEST_F(WebViewTest, LongPressEmptyDivAlwaysShow) {
event.SetPositionInWidget(WebFloatPoint(250, 150));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
}
TEST_F(WebViewTest, LongPressObject) {
@@ -2616,7 +2635,7 @@ TEST_F(WebViewTest, LongPressObject) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "long_press_object.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(true);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2627,7 +2646,8 @@ TEST_F(WebViewTest, LongPressObject) {
event.SetPositionInWidget(WebFloatPoint(10, 10));
EXPECT_NE(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
HTMLElement* element = ToHTMLElement(
web_view->MainFrameImpl()->GetDocument().GetElementById("obj"));
@@ -2640,7 +2660,7 @@ TEST_F(WebViewTest, LongPressObjectFallback) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "long_press_object_fallback.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(true);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2651,7 +2671,8 @@ TEST_F(WebViewTest, LongPressObjectFallback) {
event.SetPositionInWidget(WebFloatPoint(10, 10));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
HTMLElement* element = ToHTMLElement(
web_view->MainFrameImpl()->GetDocument().GetElementById("obj"));
@@ -2664,7 +2685,7 @@ TEST_F(WebViewTest, LongPressImage) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "long_press_image.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2675,7 +2696,8 @@ TEST_F(WebViewTest, LongPressImage) {
event.SetPositionInWidget(WebFloatPoint(10, 10));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
}
TEST_F(WebViewTest, LongPressVideo) {
@@ -2684,7 +2706,7 @@ TEST_F(WebViewTest, LongPressVideo) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "long_press_video.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2695,7 +2717,8 @@ TEST_F(WebViewTest, LongPressVideo) {
event.SetPositionInWidget(WebFloatPoint(10, 10));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
}
TEST_F(WebViewTest, LongPressLink) {
@@ -2704,7 +2727,7 @@ TEST_F(WebViewTest, LongPressLink) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "long_press_link.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2715,7 +2738,8 @@ TEST_F(WebViewTest, LongPressLink) {
event.SetPositionInWidget(WebFloatPoint(500, 300));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
}
// Tests that we send touchcancel when drag start by long press.
@@ -2729,7 +2753,7 @@ TEST_F(WebViewTest, TouchCancelOnStartDragging) {
base_url_ + "long_press_draggable_div.html");
web_view->SettingsImpl()->SetTouchDragDropEnabled(true);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2737,8 +2761,9 @@ TEST_F(WebViewTest, TouchCancelOnStartDragging) {
WebInputEvent::kPointerDown,
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
pointer_down.SetPositionInWidget(250, 8);
- web_view->HandleInputEvent(WebCoalescedInputEvent(pointer_down));
- web_view->DispatchBufferedTouchEvents();
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_down));
+ web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
WebString target_id = WebString::FromUTF8("target");
@@ -2753,8 +2778,9 @@ TEST_F(WebViewTest, TouchCancelOnStartDragging) {
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
pointer_cancel.SetPositionInWidget(250, 8);
EXPECT_NE(WebInputEventResult::kHandledSuppressed,
- web_view->HandleInputEvent(WebCoalescedInputEvent(pointer_cancel)));
- web_view->DispatchBufferedTouchEvents();
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_cancel)));
+ web_view->MainFrameWidget()->DispatchBufferedTouchEvents();
EXPECT_STREQ("touchcancel",
web_view->MainFrameImpl()->GetDocument().Title().Utf8().data());
}
@@ -2769,7 +2795,7 @@ TEST_F(WebViewTest, showContextMenuOnLongPressingLinks) {
base_url_ + "long_press_links_and_images.html");
web_view->SettingsImpl()->SetTouchDragDropEnabled(true);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2791,7 +2817,7 @@ TEST_F(WebViewTest, LongPressEmptyEditableSelection) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "long_press_empty_editable_selection.html");
web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false);
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2802,7 +2828,8 @@ TEST_F(WebViewTest, LongPressEmptyEditableSelection) {
event.SetPositionInWidget(WebFloatPoint(10, 10));
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
}
TEST_F(WebViewTest, LongPressEmptyNonEditableSelection) {
@@ -2810,7 +2837,7 @@ TEST_F(WebViewTest, LongPressEmptyNonEditableSelection) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "long_press_image.html");
- web_view->Resize(WebSize(500, 500));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 500));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2822,7 +2849,8 @@ TEST_F(WebViewTest, LongPressEmptyNonEditableSelection) {
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event)));
EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
}
@@ -2831,7 +2859,7 @@ TEST_F(WebViewTest, LongPressSelection) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "longpress_selection.html");
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2851,7 +2879,7 @@ TEST_F(WebViewTest, FinishComposingTextDoesNotDismissHandles) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "longpress_selection.html");
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2887,7 +2915,7 @@ TEST_F(WebViewTest, TouchDoesntSelectEmptyTextarea) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "longpress_textarea.html");
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2906,7 +2934,7 @@ TEST_F(WebViewTest, TouchDoesntSelectEmptyTextarea) {
event.SetPositionInWidget(WebFloatPoint(100, 25));
event.data.tap.tap_count = 2;
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
HTMLTextAreaElement* text_area_element = ToHTMLTextAreaElement(
@@ -2920,7 +2948,7 @@ TEST_F(WebViewTest, TouchDoesntSelectEmptyTextarea) {
EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
// Double-tap past last word of textbox.
- web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
}
#endif
@@ -2930,7 +2958,7 @@ TEST_F(WebViewTest, LongPressImageTextarea) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "longpress_image_contenteditable.html");
- web_view->Resize(WebSize(500, 300));
+ web_view->MainFrameWidget()->Resize(WebSize(500, 300));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2950,7 +2978,7 @@ TEST_F(WebViewTest, BlinkCaretAfterLongPress) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "blink_caret_on_typing_after_long_press.html");
- web_view->Resize(WebSize(640, 480));
+ web_view->MainFrameWidget()->Resize(WebSize(640, 480));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -2979,7 +3007,8 @@ TEST_F(WebViewTest, BlinkCaretOnClosingContextMenu) {
mouse_event.button = WebMouseEvent::Button::kRight;
mouse_event.SetPositionInWidget(1, 1);
mouse_event.click_count = 1;
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
RunPendingTasks();
WebLocalFrameImpl* main_frame = web_view->MainFrameImpl();
@@ -2999,7 +3028,7 @@ TEST_F(WebViewTest, SelectionOnReadOnlyInput) {
RegisterMockedHttpURLLoad("selection_readonly.html");
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "selection_readonly.html");
- web_view->Resize(WebSize(640, 480));
+ web_view->MainFrameWidget()->Resize(WebSize(640, 480));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -3021,7 +3050,7 @@ TEST_F(WebViewTest, KeyDownScrollsHandled) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "content-width-1000.html");
- web_view->Resize(WebSize(100, 100));
+ web_view->MainFrameWidget()->Resize(WebSize(100, 100));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -3032,60 +3061,74 @@ TEST_F(WebViewTest, KeyDownScrollsHandled) {
// RawKeyDown pagedown should be handled.
key_event.windows_key_code = VKEY_NEXT;
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
// Coalesced KeyDown arrow-down should be handled.
key_event.windows_key_code = VKEY_DOWN;
key_event.SetType(WebInputEvent::kKeyDown);
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
// Ctrl-Home should be handled...
key_event.windows_key_code = VKEY_HOME;
key_event.SetModifiers(WebInputEvent::kControlKey);
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
// But Ctrl-Down should not.
key_event.windows_key_code = VKEY_DOWN;
key_event.SetModifiers(WebInputEvent::kControlKey);
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
// Shift, meta, and alt should not be handled.
key_event.windows_key_code = VKEY_NEXT;
key_event.SetModifiers(WebInputEvent::kShiftKey);
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
key_event.windows_key_code = VKEY_NEXT;
key_event.SetModifiers(WebInputEvent::kMetaKey);
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
key_event.windows_key_code = VKEY_NEXT;
key_event.SetModifiers(WebInputEvent::kAltKey);
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
// System-key labeled Alt-Down (as in Windows) should do nothing,
// but non-system-key labeled Alt-Down (as in Mac) should be handled
@@ -3095,18 +3138,22 @@ TEST_F(WebViewTest, KeyDownScrollsHandled) {
key_event.is_system_key = true;
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kNotHandled,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
key_event.windows_key_code = VKEY_DOWN;
key_event.SetModifiers(WebInputEvent::kAltKey);
key_event.is_system_key = false;
key_event.SetType(WebInputEvent::kRawKeyDown);
EXPECT_EQ(WebInputEventResult::kHandledSystem,
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event)));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event)));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
}
class MiddleClickAutoscrollWebWidgetClient
@@ -3131,7 +3178,7 @@ TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "content-width-1000.html", nullptr, nullptr, &client);
- web_view->Resize(WebSize(100, 100));
+ web_view->MainFrameWidget()->Resize(WebSize(100, 100));
UpdateAllLifecyclePhases();
RunPendingTasks();
@@ -3143,9 +3190,11 @@ TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
mouse_event.click_count = 1;
// Start middle-click autoscroll.
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
mouse_event.SetType(WebInputEvent::kMouseUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
EXPECT_EQ(MiddlePanningCursor().GetType(), client.GetLastCursorType());
@@ -3160,13 +3209,18 @@ TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
// End middle-click autoscroll.
mouse_event.SetType(WebInputEvent::kMouseDown);
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
mouse_event.SetType(WebInputEvent::kMouseUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
web_view->GetChromeClient().SetCursorForPlugin(WebCursorInfo(IBeamCursor()),
local_frame);
EXPECT_EQ(IBeamCursor().GetType(), client.GetLastCursorType());
+
+ // Explicitly reset to break dependency on locally scoped client.
+ web_view_helper_.Reset();
}
static void ConfigueCompositingWebView(WebSettings* settings) {
@@ -3175,12 +3229,12 @@ static void ConfigueCompositingWebView(WebSettings* settings) {
TEST_F(WebViewTest, ShowPressOnTransformedLink) {
frame_test_helpers::WebViewHelper web_view_helper;
- WebViewImpl* web_view_impl = web_view_helper.Initialize(
- nullptr, nullptr, nullptr, &ConfigueCompositingWebView);
+ WebViewImpl* web_view_impl =
+ web_view_helper.InitializeWithSettings(&ConfigueCompositingWebView);
int page_width = 640;
int page_height = 480;
- web_view_impl->Resize(WebSize(page_width, page_height));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(
@@ -3197,7 +3251,8 @@ TEST_F(WebViewTest, ShowPressOnTransformedLink) {
event.SetPositionInWidget(WebFloatPoint(20, 20));
// Just make sure we don't hit any asserts.
- web_view_impl->HandleInputEvent(WebCoalescedInputEvent(event));
+ web_view_impl->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(event));
}
class MockAutofillClient : public WebAutofillClient {
@@ -3253,7 +3308,7 @@ TEST_F(WebViewTest, LosingFocusDoesNotTriggerAutofillTextChange) {
// Clear the focus and track that the subsequent composition commit does not
// trigger a text changed notification for autofill.
client.ClearChangeCounts();
- web_view->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(false);
EXPECT_EQ(0, client.TextChanges());
frame->SetAutofillClient(nullptr);
@@ -3301,7 +3356,8 @@ TEST_F(WebViewTest, CompositionNotCancelledByBackspace) {
WebInputEvent::GetStaticTimeStampForTests());
key_event.dom_key = Platform::Current()->DomKeyEnumFromString("\b");
key_event.windows_key_code = VKEY_BACK;
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
frame->SetEditableSelectionOffsets(6, 6);
EXPECT_TRUE(active_input_method_controller->SetComposition(
@@ -3311,7 +3367,8 @@ TEST_F(WebViewTest, CompositionNotCancelledByBackspace) {
"after pressing Backspace");
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
web_view->AdvanceFocus(false);
}
@@ -3478,9 +3535,9 @@ TEST_F(WebViewTest, DispatchesFocusOutFocusInOnViewToggleFocus) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "focusout_focusin_events.html");
- web_view->SetFocus(true);
- web_view->SetFocus(false);
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(true);
WebElement element =
web_view->MainFrameImpl()->GetDocument().GetElementById("message");
@@ -3492,9 +3549,9 @@ TEST_F(WebViewTest, DispatchesDomFocusOutDomFocusInOnViewToggleFocus) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "domfocusout_domfocusin_events.html");
- web_view->SetFocus(true);
- web_view->SetFocus(false);
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(true);
WebElement element =
web_view->MainFrameImpl()->GetDocument().GetElementById("message");
@@ -3605,9 +3662,9 @@ TEST_F(WebViewTest, DispatchesFocusBlurOnViewToggle) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "focus_blur_events.html");
- web_view->SetFocus(true);
- web_view->SetFocus(false);
- web_view->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(true);
+ web_view->MainFrameWidget()->SetFocus(false);
+ web_view->MainFrameWidget()->SetFocus(true);
WebElement element =
web_view->MainFrameImpl()->GetDocument().GetElementById("message");
@@ -3863,7 +3920,7 @@ TEST_F(WebViewTest, HasTouchEventHandlers) {
// This test checks that deleting nodes which have only non-JS-registered touch
// handlers also removes them from the event handler registry. Note that this
// is different from detaching and re-attaching the same node, which is covered
-// by layout tests under fast/events/.
+// by web tests under fast/events/.
TEST_F(WebViewTest, DeleteElementWithRegisteredHandler) {
std::string url = RegisterMockedHttpURLLoad("simple_div.html");
WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(url);
@@ -3908,7 +3965,7 @@ TEST_F(WebViewTest, TextInputFlags) {
document->SetFocusedElement(
input_element,
FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone, nullptr));
- web_view_impl->SetFocus(true);
+ web_view_impl->MainFrameWidget()->SetFocus(true);
WebTextInputInfo info1 = active_input_method_controller->TextInputInfo();
EXPECT_EQ(kWebTextInputFlagAutocompleteOff | kWebTextInputFlagAutocorrectOff |
kWebTextInputFlagSpellcheckOff |
@@ -3921,7 +3978,7 @@ TEST_F(WebViewTest, TextInputFlags) {
document->SetFocusedElement(
input_element,
FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone, nullptr));
- web_view_impl->SetFocus(true);
+ web_view_impl->MainFrameWidget()->SetFocus(true);
WebTextInputInfo info2 = active_input_method_controller->TextInputInfo();
EXPECT_EQ(kWebTextInputFlagAutocompleteOn | kWebTextInputFlagAutocorrectOn |
kWebTextInputFlagSpellcheckOn |
@@ -3935,7 +3992,7 @@ TEST_F(WebViewTest, TextInputFlags) {
document->SetFocusedElement(
text_area_element,
FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone, nullptr));
- web_view_impl->SetFocus(true);
+ web_view_impl->MainFrameWidget()->SetFocus(true);
WebTextInputInfo info3 = active_input_method_controller->TextInputInfo();
EXPECT_EQ(kWebTextInputFlagAutocapitalizeSentences, info3.flags);
@@ -3965,9 +4022,11 @@ TEST_F(WebViewTest, FirstUserGestureObservedKeyEvent) {
WebInputEvent::GetStaticTimeStampForTests());
key_event.dom_key = Platform::Current()->DomKeyEnumFromString(" ");
key_event.windows_key_code = VKEY_SPACE;
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
key_event.SetType(WebInputEvent::kKeyUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
EXPECT_EQ(2, client.GetUserGestureNotificationsCount());
frame->SetAutofillClient(nullptr);
@@ -3990,9 +4049,11 @@ TEST_F(WebViewTest, FirstUserGestureObservedMouseEvent) {
mouse_event.button = WebMouseEvent::Button::kLeft;
mouse_event.SetPositionInWidget(1, 1);
mouse_event.click_count = 1;
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
mouse_event.SetType(WebInputEvent::kMouseUp);
- web_view->HandleInputEvent(WebCoalescedInputEvent(mouse_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_event));
EXPECT_EQ(1, client.GetUserGestureNotificationsCount());
frame->SetAutofillClient(nullptr);
@@ -4095,7 +4156,7 @@ TEST_F(WebViewTest, PreferredSize) {
TEST_F(WebViewTest, PreferredMinimumSizeQuirksMode) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
frame_test_helpers::LoadHTMLString(
web_view->MainFrameImpl(),
R"HTML(<html>
@@ -4175,12 +4236,14 @@ class MojoTestHelper {
MojoTestHelper(const String& test_file,
frame_test_helpers::WebViewHelper& web_view_helper)
: web_view_helper_(web_view_helper) {
- web_view_ = web_view_helper.InitializeAndLoad(
- WebString(test_file).Utf8(), &web_frame_client_, &web_view_client_);
+ web_view_ = web_view_helper.InitializeAndLoad(WebString(test_file).Utf8(),
+ &web_frame_client_);
}
+
~MojoTestHelper() {
web_view_helper_.Reset(); // Remove dependency on locally scoped client.
}
+
// Bind the test API to a service with the given |name| and repeating Bind
// method given by |callback|.
void BindTestApi(
@@ -4197,7 +4260,6 @@ class MojoTestHelper {
WebViewImpl* web_view_;
frame_test_helpers::WebViewHelper& web_view_helper_;
frame_test_helpers::TestWebFrameClient web_frame_client_;
- frame_test_helpers::TestWebViewClient web_view_client_;
std::unique_ptr<service_manager::InterfaceProvider::TestApi> test_api_;
};
@@ -4254,7 +4316,7 @@ class ShowUnhandledTapTest : public WebViewTest {
WebString::FromUTF8(base_url_ + test_file), web_view_helper_));
web_view_ = mojo_test_helper_->WebView();
- web_view_->Resize(WebSize(500, 300));
+ web_view_->MainFrameWidget()->Resize(WebSize(500, 300));
web_view_->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
RunPendingTasks();
@@ -4381,30 +4443,13 @@ TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithTextSizes) {
#endif // BUILDFLAG(ENABLE_UNHANDLED_TAP)
-TEST_F(WebViewTest, StopLoadingIfJavaScriptURLReturnsNoStringResult) {
- ViewCreatingWebViewClient client;
- frame_test_helpers::WebViewHelper main_web_view;
- main_web_view.InitializeAndLoad("about:blank", nullptr, &client);
-
- WebLocalFrame* frame = main_web_view.GetWebView()->MainFrameImpl();
- v8::HandleScope scope(v8::Isolate::GetCurrent());
- v8::Local<v8::Value> v8_value =
- frame->ExecuteScriptAndReturnValue(WebScriptSource(
- "var win = window.open('javascript:false'); win.document"));
- ASSERT_TRUE(v8_value->IsObject());
- Document* document =
- V8Document::ToImplWithTypeCheck(v8::Isolate::GetCurrent(), v8_value);
- ASSERT_TRUE(document);
- EXPECT_FALSE(document->GetFrame()->IsLoading());
-}
-
#if defined(OS_MACOSX)
TEST_F(WebViewTest, WebSubstringUtil) {
RegisterMockedHttpURLLoad("content_editable_populated.html");
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "content_editable_populated.html");
web_view->GetSettings()->SetDefaultFontSize(12);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
WebPoint baseline_point;
@@ -4434,7 +4479,7 @@ TEST_F(WebViewTest, WebSubstringUtilBaselinePoint) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "content_editable_multiline.html");
web_view->GetSettings()->SetDefaultFontSize(12);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
WebPoint old_point;
@@ -4452,7 +4497,7 @@ TEST_F(WebViewTest, WebSubstringUtilPinchZoom) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "content_editable_populated.html");
web_view->GetSettings()->SetDefaultFontSize(12);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
NSAttributedString* result = nil;
@@ -4481,7 +4526,7 @@ TEST_F(WebViewTest, WebSubstringUtilIframe) {
web_view_helper_.InitializeAndLoad(base_url_ + "single_iframe.html");
web_view->GetSettings()->SetDefaultFontSize(12);
web_view->GetSettings()->SetJavaScriptEnabled(true);
- web_view->Resize(WebSize(400, 400));
+ web_view->MainFrameWidget()->Resize(WebSize(400, 400));
WebLocalFrameImpl* main_frame = web_view->MainFrameImpl();
WebLocalFrameImpl* child_frame = WebLocalFrameImpl::FromFrame(
ToLocalFrame(main_frame->GetFrame()->Tree().FirstChild()));
@@ -4621,7 +4666,12 @@ TEST_F(WebViewTest, ClosingPageIsPaused) {
LocalFrame* main_frame = ToLocalFrame(page->MainFrame());
EXPECT_FALSE(main_frame->DomWindow()->closed());
- main_frame->DomWindow()->close(nullptr);
+ ScriptState* script_state = ToScriptStateForMainWorld(main_frame);
+ ScriptState::Scope entered_context_scope(script_state);
+ v8::Context::BackupIncumbentScope incumbent_context_scope(
+ script_state->GetContext());
+
+ main_frame->DomWindow()->close(script_state->GetIsolate());
// The window should be marked closed...
EXPECT_TRUE(main_frame->DomWindow()->closed());
// EXPECT_TRUE(page->isClosing());
@@ -4638,7 +4688,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
RegisterMockedHttpURLLoad("200-by-300.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
- web_view_impl->Resize(WebSize(100, 150));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
SetViewportSize(WebSize(100, 150));
VisualViewport* visual_viewport =
&web_view_impl->GetPage()->GetVisualViewport();
@@ -4646,8 +4696,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
TransformationMatrix expected_matrix;
expected_matrix.MakeIdentity();
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
EXPECT_FALSE(dev_tools_emulator->VisibleContentRectForPainting());
EXPECT_TRUE(visual_viewport->ContainerLayer()->MasksToBounds());
@@ -4655,8 +4704,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
// visual viewport clipping.
dev_tools_emulator->ForceViewport(WebFloatPoint(50, 55), 2.f);
expected_matrix.MakeIdentity().Scale(2.f).Translate(-50, -55);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
EXPECT_EQ(IntRect(50, 55, 50, 75),
*dev_tools_emulator->VisibleContentRectForPainting());
EXPECT_FALSE(visual_viewport->ContainerLayer()->MasksToBounds());
@@ -4664,8 +4712,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
// Setting new override discards previous one.
dev_tools_emulator->ForceViewport(WebFloatPoint(5.4f, 10.5f), 1.5f);
expected_matrix.MakeIdentity().Scale(1.5f).Translate(-5.4f, -10.5f);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
EXPECT_EQ(IntRect(5, 10, 68, 101),
*dev_tools_emulator->VisibleContentRectForPainting());
EXPECT_FALSE(visual_viewport->ContainerLayer()->MasksToBounds());
@@ -4674,8 +4721,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
// visual viewport clipping.
dev_tools_emulator->ResetViewport();
expected_matrix.MakeIdentity();
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
EXPECT_FALSE(dev_tools_emulator->VisibleContentRectForPainting());
EXPECT_TRUE(visual_viewport->ContainerLayer()->MasksToBounds());
}
@@ -4684,19 +4730,17 @@ TEST_F(WebViewTest, ViewportOverrideIntegratesDeviceMetricsOffsetAndScale) {
RegisterMockedHttpURLLoad("200-by-300.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
- web_view_impl->Resize(WebSize(100, 150));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
TransformationMatrix expected_matrix;
expected_matrix.MakeIdentity();
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
WebDeviceEmulationParams emulation_params;
emulation_params.scale = 2.f;
web_view_impl->EnableDeviceEmulation(emulation_params);
expected_matrix.MakeIdentity().Scale(2.f);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
// Device metrics offset and scale are applied before viewport override.
web_view_impl->GetDevToolsEmulator()->ForceViewport(WebFloatPoint(5, 10),
@@ -4705,15 +4749,14 @@ TEST_F(WebViewTest, ViewportOverrideIntegratesDeviceMetricsOffsetAndScale) {
.Scale(1.5f)
.Translate(-5, -10)
.Scale(2.f);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
}
TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
RegisterMockedHttpURLLoad("200-by-300.html");
WebViewImpl* web_view_impl =
web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
- web_view_impl->Resize(WebSize(100, 150));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(100, 150));
SetViewportSize(WebSize(100, 150));
LocalFrameView* frame_view =
web_view_impl->MainFrameImpl()->GetFrame()->View();
@@ -4721,8 +4764,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
TransformationMatrix expected_matrix;
expected_matrix.MakeIdentity();
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
// Initial transform takes current page scale and scroll position into
// account.
@@ -4735,8 +4777,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
.Translate(-50, -55)
.Translate(100, 150)
.Scale(1. / 1.5f);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
// Page scroll and scale are irrelevant for visibleContentRect.
EXPECT_EQ(IntRect(50, 55, 50, 75),
*dev_tools_emulator->VisibleContentRectForPainting());
@@ -4749,8 +4790,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
.Translate(-50, -55)
.Translate(50, 55)
.Scale(1. / 1.5f);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
// visibleContentRect doesn't change.
EXPECT_EQ(IntRect(50, 55, 50, 75),
*dev_tools_emulator->VisibleContentRectForPainting());
@@ -4762,8 +4802,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
.Translate(-50, -55)
.Translate(50, 55)
.Scale(1. / 2.f);
- EXPECT_EQ(expected_matrix,
- web_view_impl->GetDeviceEmulationTransformForTesting());
+ EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
// visibleContentRect doesn't change.
EXPECT_EQ(IntRect(50, 55, 50, 75),
*dev_tools_emulator->VisibleContentRectForPainting());
@@ -4771,7 +4810,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
TEST_F(WebViewTest, ResizeForPrintingViewportUnits) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
@@ -4801,12 +4840,12 @@ TEST_F(WebViewTest, ResizeForPrintingViewportUnits) {
EXPECT_EQ(expected_size.Width(), vw_element->OffsetWidth());
EXPECT_EQ(expected_size.Height(), vw_element->OffsetHeight());
- web_view->Resize(FlooredIntSize(page_size));
+ web_view->MainFrameWidget()->Resize(FlooredIntSize(page_size));
EXPECT_EQ(expected_size.Width(), vw_element->OffsetWidth());
EXPECT_EQ(expected_size.Height(), vw_element->OffsetHeight());
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
frame->PrintEnd();
EXPECT_EQ(800, vw_element->OffsetWidth());
@@ -4814,7 +4853,7 @@ TEST_F(WebViewTest, ResizeForPrintingViewportUnits) {
TEST_F(WebViewTest, WidthMediaQueryWithPageZoomAfterPrinting) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
web_view->SetZoomLevel(WebView::ZoomFactorToZoomLevel(2.0));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
@@ -4849,7 +4888,7 @@ TEST_F(WebViewTest, WidthMediaQueryWithPageZoomAfterPrinting) {
TEST_F(WebViewTest, ViewportUnitsPrintingWithPageZoom) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
web_view->SetZoomLevel(WebView::ZoomFactorToZoomLevel(2.0));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
@@ -4888,7 +4927,7 @@ TEST_F(WebViewTest, ViewportUnitsPrintingWithPageZoom) {
TEST_F(WebViewTest, DeviceEmulationResetScrollbars) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->Resize(WebSize(800, 600));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 600));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
@@ -5050,7 +5089,8 @@ TEST_F(WebViewTest, FirstInputDelayReported) {
key_event1.windows_key_code = VKEY_SPACE;
key_event1.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event1));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event1));
EXPECT_NEAR(50, interactive_detector->GetFirstInputDelay().InMillisecondsF(),
0.01);
@@ -5066,7 +5106,8 @@ TEST_F(WebViewTest, FirstInputDelayReported) {
key_event2.windows_key_code = VKEY_SPACE;
clock.Advance(TimeDelta::FromMilliseconds(60));
key_event2.SetTimeStamp(CurrentTimeTicks());
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event2));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event2));
EXPECT_NEAR(50, interactive_detector->GetFirstInputDelay().InMillisecondsF(),
0.01);
@@ -5104,7 +5145,8 @@ TEST_F(WebViewTest, LongestInputDelayReported) {
key_event1.windows_key_code = VKEY_SPACE;
key_event1.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event1));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event1));
TimeTicks longest_input_timestamp = CurrentTimeTicks();
@@ -5115,7 +5157,8 @@ TEST_F(WebViewTest, LongestInputDelayReported) {
key_event2.windows_key_code = VKEY_SPACE;
key_event2.SetTimeStamp(longest_input_timestamp);
clock.Advance(TimeDelta::FromMilliseconds(100));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event2));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event2));
WebKeyboardEvent key_event3(WebInputEvent::kRawKeyDown,
WebInputEvent::kNoModifiers,
@@ -5124,7 +5167,8 @@ TEST_F(WebViewTest, LongestInputDelayReported) {
key_event3.windows_key_code = VKEY_SPACE;
key_event3.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(70));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event3));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event3));
EXPECT_NEAR(100,
interactive_detector->GetLongestInputDelay().InMillisecondsF(),
@@ -5153,7 +5197,8 @@ TEST_F(WebViewTest, InputDelayReported) {
key_event1.windows_key_code = VKEY_SPACE;
key_event1.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event1));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event1));
WebKeyboardEvent key_event2(WebInputEvent::kRawKeyDown,
WebInputEvent::kNoModifiers,
@@ -5162,7 +5207,8 @@ TEST_F(WebViewTest, InputDelayReported) {
key_event2.windows_key_code = VKEY_SPACE;
key_event2.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event2));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event2));
WebKeyboardEvent key_event3(WebInputEvent::kRawKeyDown,
WebInputEvent::kNoModifiers,
@@ -5171,16 +5217,24 @@ TEST_F(WebViewTest, InputDelayReported) {
key_event3.windows_key_code = VKEY_SPACE;
key_event3.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(70));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event3));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event3));
- histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputDelay", 3);
- histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay", 50, 2);
- histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay", 70, 1);
+ histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputDelay2",
+ 3);
+ histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay2",
+ 50, 2);
+ histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay2",
+ 70, 1);
- histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputTimestamp", 3);
- histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputTimestamp", 70, 1);
- histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputTimestamp", 120, 1);
- histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputTimestamp", 170, 1);
+ histogram_tester.ExpectTotalCount(
+ "PageLoad.InteractiveTiming.InputTimestamp2", 3);
+ histogram_tester.ExpectBucketCount(
+ "PageLoad.InteractiveTiming.InputTimestamp2", 70, 1);
+ histogram_tester.ExpectBucketCount(
+ "PageLoad.InteractiveTiming.InputTimestamp2", 120, 1);
+ histogram_tester.ExpectBucketCount(
+ "PageLoad.InteractiveTiming.InputTimestamp2", 170, 1);
}
// Tests that if the page was backgrounded while an input event was queued,
@@ -5214,7 +5268,8 @@ TEST_F(WebViewTest, LongestInputDelayPageBackgroundedDuringQueuing) {
TimeTicks key_event1_time = CurrentTimeTicks();
key_event1.SetTimeStamp(key_event1_time);
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event1));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event1));
WebKeyboardEvent key_event2(WebInputEvent::kRawKeyDown,
WebInputEvent::kNoModifiers,
@@ -5223,12 +5278,13 @@ TEST_F(WebViewTest, LongestInputDelayPageBackgroundedDuringQueuing) {
key_event2.windows_key_code = VKEY_SPACE;
key_event2.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(100));
- web_view->SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
+ web_view->SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
clock.Advance(TimeDelta::FromMilliseconds(100));
- web_view->SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
+ web_view->SetIsHidden(/*is_hidden=*/false, /*initial_state=*/false);
clock.Advance(TimeDelta::FromMilliseconds(100));
// Total input delay is >300ms.
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event2));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event2));
EXPECT_NEAR(
50, interactive_detector->GetLongestInputDelay().InMillisecondsF(), 0.01);
@@ -5240,7 +5296,7 @@ TEST_F(WebViewTest, LongestInputDelayPageBackgroundedDuringQueuing) {
// calculate longest input delay.
TEST_F(WebViewTest, LongestInputDelayPageBackgroundedAtNavStart) {
WebViewImpl* web_view = web_view_helper_.Initialize();
- web_view->SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
+ web_view->SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
"<html><body></body></html>", base_url);
@@ -5265,8 +5321,9 @@ TEST_F(WebViewTest, LongestInputDelayPageBackgroundedAtNavStart) {
key_event.windows_key_code = VKEY_SPACE;
key_event.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(100));
- web_view->SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->SetIsHidden(/*is_hidden=*/false, /*initial_state=*/false);
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
EXPECT_TRUE(interactive_detector->GetLongestInputDelay().is_zero());
}
@@ -5294,9 +5351,9 @@ TEST_F(WebViewTest, LongestInputDelayPageBackgroundedNotDuringQueuing) {
EXPECT_TRUE(interactive_detector->GetLongestInputDelay().is_zero());
- web_view->SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
+ web_view->SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
clock.Advance(TimeDelta::FromMilliseconds(100));
- web_view->SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
+ web_view->SetIsHidden(/*is_hidden=*/false, /*initial_state=*/false);
clock.Advance(TimeDelta::FromMilliseconds(1));
WebKeyboardEvent key_event(WebInputEvent::kRawKeyDown,
@@ -5307,7 +5364,8 @@ TEST_F(WebViewTest, LongestInputDelayPageBackgroundedNotDuringQueuing) {
TimeTicks key_event_time = CurrentTimeTicks();
key_event.SetTimeStamp(key_event_time);
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
EXPECT_NEAR(
50, interactive_detector->GetLongestInputDelay().InMillisecondsF(), 0.01);
@@ -5340,7 +5398,8 @@ TEST_F(WebViewTest, PointerDownUpFirstInputDelay) {
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
pointer_down.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(pointer_down));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_down));
// We don't know if this pointer event will result in a scroll or not, so we
// can't report its delay. We don't consider a scroll to be meaningful input.
@@ -5352,7 +5411,8 @@ TEST_F(WebViewTest, PointerDownUpFirstInputDelay) {
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
clock.Advance(TimeDelta::FromMilliseconds(60));
pointer_up.SetTimeStamp(CurrentTimeTicks());
- web_view->HandleInputEvent(WebCoalescedInputEvent(pointer_up));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_up));
EXPECT_NEAR(50, interactive_detector->GetFirstInputDelay().InMillisecondsF(),
0.01);
@@ -5376,6 +5436,7 @@ TEST_F(WebViewTest, PointerDownCancelFirstInputDelay) {
ASSERT_NE(nullptr, document);
WTF::ScopedMockClock clock;
+ clock.Advance(TimeDelta::FromMilliseconds(70));
InteractiveDetector* interactive_detector(
InteractiveDetector::From(*document));
@@ -5386,19 +5447,21 @@ TEST_F(WebViewTest, PointerDownCancelFirstInputDelay) {
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
pointer_down.SetTimeStamp(CurrentTimeTicks());
clock.Advance(TimeDelta::FromMilliseconds(50));
- web_view->HandleInputEvent(WebCoalescedInputEvent(pointer_down));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_down));
// We don't know if this pointer event will result in a scroll or not, so we
// can't report its delay. We don't consider a scroll to be meaningful input.
EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
- // When we receive a pointer up, we report the delay of the pointer down.
+ // When we receive a pointer cancel, we should not report the pointer down.
WebPointerEvent pointer_cancel(
WebInputEvent::kPointerCancel,
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
clock.Advance(TimeDelta::FromMilliseconds(60));
pointer_cancel.SetTimeStamp(CurrentTimeTicks());
- web_view->HandleInputEvent(WebCoalescedInputEvent(pointer_cancel));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_cancel));
// We received a pointer cancel, so this is a scroll gesture. No meaningful
// input has occurred yet.
@@ -5406,6 +5469,130 @@ TEST_F(WebViewTest, PointerDownCancelFirstInputDelay) {
EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null());
}
+// Check that input delay isn't reported when there is pointer down, pointer
+// cancel, and pointer up.
+TEST_F(WebViewTest, PointerDownCancelUpInputDelay) {
+ WebViewImpl* web_view = web_view_helper_.Initialize();
+ WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
+ frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
+ "<html><body></body onpointerdown="
+ "></html>",
+ base_url);
+
+ LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
+ ASSERT_NE(nullptr, main_frame);
+ Document* document = main_frame->GetDocument();
+ ASSERT_NE(nullptr, document);
+
+ WTF::ScopedMockClock clock;
+ clock.Advance(TimeDelta::FromMilliseconds(70));
+
+ InteractiveDetector* interactive_detector(
+ InteractiveDetector::From(*document));
+ ASSERT_NE(nullptr, interactive_detector);
+
+ WebPointerEvent pointer_down(
+ WebInputEvent::kPointerDown,
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
+ pointer_down.SetTimeStamp(CurrentTimeTicks());
+ clock.Advance(TimeDelta::FromMilliseconds(50));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_down));
+
+ // We don't know if this pointer event will result in a scroll or not, so we
+ // can't report its delay. We don't consider a scroll to be meaningful input.
+ EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
+
+ // When we receive a pointer cancel, we should not report the pointer down.
+ WebPointerEvent pointer_cancel(
+ WebInputEvent::kPointerCancel,
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
+ clock.Advance(TimeDelta::FromMilliseconds(60));
+ pointer_cancel.SetTimeStamp(CurrentTimeTicks());
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_cancel));
+
+ EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
+
+ // When we receive a pointer up, because we received a pointer cancel, no
+ // input delay should be recorded.
+ WebPointerEvent pointer_up(
+ WebInputEvent::kPointerUp,
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
+ clock.Advance(TimeDelta::FromMilliseconds(60));
+ pointer_up.SetTimeStamp(CurrentTimeTicks());
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_up));
+
+ EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
+ EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null());
+ EXPECT_TRUE(interactive_detector->GetLongestInputDelay().is_zero());
+ EXPECT_TRUE(interactive_detector->GetLongestInputTimestamp().is_null());
+}
+
+// Check that first input delay isn't reported when there is pointer down,
+// pointer caused UA action, and pointer up.
+TEST_F(WebViewTest, PointerDownCausedUaActionUpInputDelay) {
+ WebViewImpl* web_view = web_view_helper_.Initialize();
+ WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
+ frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(),
+ "<html><body></body onpointerdown="
+ "></html>",
+ base_url);
+
+ LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
+ ASSERT_NE(nullptr, main_frame);
+ Document* document = main_frame->GetDocument();
+ ASSERT_NE(nullptr, document);
+
+ WTF::ScopedMockClock clock;
+ clock.Advance(TimeDelta::FromMilliseconds(70));
+
+ InteractiveDetector* interactive_detector(
+ InteractiveDetector::From(*document));
+ ASSERT_NE(nullptr, interactive_detector);
+
+ WebPointerEvent pointer_down(
+ WebInputEvent::kPointerDown,
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
+ pointer_down.SetTimeStamp(CurrentTimeTicks());
+ clock.Advance(TimeDelta::FromMilliseconds(50));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_down));
+
+ // We don't know if this pointer event will result in a scroll or not, so we
+ // can't report its delay. We don't consider a scroll to be meaningful input.
+ EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
+
+ // When we receive a pointer caused UA action, we should not report the
+ // pointer down.
+ WebPointerEvent pointer_cancel(
+ WebInputEvent::kPointerCausedUaAction,
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
+ clock.Advance(TimeDelta::FromMilliseconds(60));
+ pointer_cancel.SetTimeStamp(CurrentTimeTicks());
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_cancel));
+
+ EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
+ EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null());
+
+ // When we receive a pointer up, because we received a pointer caused UA
+ // action, no input delay should be recorded.
+ WebPointerEvent pointer_up(
+ WebInputEvent::kPointerUp,
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5);
+ clock.Advance(TimeDelta::FromMilliseconds(60));
+ pointer_up.SetTimeStamp(CurrentTimeTicks());
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(pointer_up));
+
+ EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero());
+ EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null());
+ EXPECT_TRUE(interactive_detector->GetLongestInputDelay().is_zero());
+ EXPECT_TRUE(interactive_detector->GetLongestInputTimestamp().is_null());
+}
+
// We need a way for JS to advance the mock clock. Hook into console.log, so
// that logging advances the clock by |event_handling_delay| seconds.
class MockClockAdvancingWebFrameClient
@@ -5464,7 +5651,8 @@ TEST_F(WebViewTest, FirstInputDelayExcludesProcessingTime) {
clock.Advance(TimeDelta::FromMilliseconds(5000));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
TimeDelta first_input_delay = interactive_detector->GetFirstInputDelay();
EXPECT_EQ(5000, first_input_delay.InMillisecondsF());
@@ -5509,11 +5697,73 @@ TEST_F(WebViewTest, LongestInputDelayExcludesProcessingTime) {
clock.Advance(TimeDelta::FromMilliseconds(5000));
- web_view->HandleInputEvent(WebCoalescedInputEvent(key_event));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(key_event));
TimeDelta longest_input_delay = interactive_detector->GetLongestInputDelay();
EXPECT_EQ(5000, longest_input_delay.InMillisecondsF());
web_view_helper_.Reset(); // Remove dependency on locally scoped client.
}
+
+TEST_F(WebViewTest, RootLayerAttachment) {
+ WebView* web_view = web_view_helper_.InitializeAndLoad("about:blank");
+
+ // Do a lifecycle update that includes compositing but not paint. Hit test
+ // events are an example of a real case where this occurs
+ // (see: WebViewTest::ClientTapHandling).
+ web_view->MainFrameWidget()->UpdateLifecycle(
+ WebFrameWidget::LifecycleUpdate::kPrePaint,
+ WebWidget::LifecycleUpdateReason::kTest);
+
+ // With BlinkGenPropertyTrees, layers (including the root layer) should not be
+ // attached until the paint lifecycle phase.
+ auto* layer_tree_view = web_view_helper_.GetLayerTreeView();
+ EXPECT_FALSE(layer_tree_view->GetRootLayer());
+
+ // Do a full lifecycle update and ensure that the root layer has been added.
+ web_view->MainFrameWidget()->UpdateLifecycle(
+ WebFrameWidget::LifecycleUpdate::kAll,
+ WebWidget::LifecycleUpdateReason::kTest);
+ EXPECT_TRUE(layer_tree_view->GetRootLayer());
+}
+
+// Verifies that we emit Blink.UseCounter.FeaturePolicy.PotentialAnimation for
+// CSS and JS animations in a document.
+TEST_F(WebViewTest, PotentialViolationReportsForLayoutAnimations) {
+ const char* kHistogramName =
+ "Blink.UseCounter.FeaturePolicy.PotentialViolation";
+ WebViewImpl* web_view = web_view_helper_.Initialize();
+ // A page with non-violating animation does not generate report.
+ WebURL base_url_no_violation =
+ url_test_helpers::ToKURL("http://good-css.example.com/");
+ frame_test_helpers::LoadHTMLString(
+ web_view->MainFrameImpl(),
+ "<html><head><style>@keyframes foo {from "
+ "{color: blue;} to {color: red}}</style></head></html>",
+ base_url_no_violation);
+ HistogramTester histogram_tester;
+ histogram_tester.ExpectTotalCount(kHistogramName, 0);
+ // Page with 2 potential (CSS) layout-animation violations.
+ WebURL base_url_css_violations =
+ url_test_helpers::ToKURL("http://bad-css.example.com/");
+ frame_test_helpers::LoadHTMLString(
+ web_view->MainFrameImpl(),
+ "<html><head><style>@keyframes bar {"
+ "from{height: 100px;} to {height: 200px;}}"
+ "@keyframes baz {from{top: 100px;} to {top: 200px;}}"
+ "</style></head></html>",
+ base_url_css_violations);
+ histogram_tester.ExpectTotalCount(kHistogramName, 1);
+ // Page with a JS layout-animations violation.
+ WebURL base_url_js_violations =
+ url_test_helpers::ToKURL("http://js.example.com/");
+ frame_test_helpers::LoadHTMLString(
+ web_view->MainFrameImpl(),
+ "<html><body><div></div><script>document.body.firstChild.animate("
+ "{top: '100px'});</script></body></html>",
+ base_url_js_violations);
+ histogram_tester.ExpectTotalCount(kHistogramName, 2);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/worker_shadow_page.cc b/chromium/third_party/blink/renderer/core/exported/worker_shadow_page.cc
index 1ca8862eda6..1fe55298c73 100644
--- a/chromium/third_party/blink/renderer/core/exported/worker_shadow_page.cc
+++ b/chromium/third_party/blink/renderer/core/exported/worker_shadow_page.cc
@@ -5,11 +5,11 @@
#include "third_party/blink/renderer/core/exported/worker_shadow_page.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
+#include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
-#include "third_party/blink/renderer/platform/loader/fetch/substitute_data.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
namespace blink {
@@ -19,22 +19,28 @@ constexpr char kDoNotTrackHeader[] = "DNT";
} // namespace
+mojo::ScopedMessagePipeHandle CreateStubDocumentInterfaceBrokerHandle() {
+ mojom::blink::DocumentInterfaceBrokerPtrInfo info;
+ return mojo::MakeRequest(&info).PassMessagePipe();
+}
+
WorkerShadowPage::WorkerShadowPage(
Client* client,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
PrivacyPreferences preferences)
: client_(client),
web_view_(WebViewImpl::Create(nullptr,
- nullptr,
- mojom::PageVisibilityState::kVisible,
+ /*is_hidden=*/false,
+ /*compositing_enabled=*/false,
nullptr)),
- main_frame_(
- WebLocalFrameImpl::CreateMainFrame(web_view_,
- this,
- nullptr /* interface_registry */,
- nullptr /* opener */,
- g_empty_atom,
- WebSandboxFlags::kNone)),
+ main_frame_(WebLocalFrameImpl::CreateMainFrame(
+ web_view_,
+ this,
+ nullptr /* interface_registry */,
+ CreateStubDocumentInterfaceBrokerHandle(),
+ nullptr /* opener */,
+ g_empty_atom,
+ WebSandboxFlags::kNone)),
loader_factory_(std::move(loader_factory)),
preferences_(std::move(preferences)) {
DCHECK(IsMainThread());
@@ -58,12 +64,10 @@ void WorkerShadowPage::Initialize(const KURL& script_url) {
// Construct substitute data source. We only need it to have same origin as
// the worker so the loading checks work correctly.
CString content("");
- scoped_refptr<SharedBuffer> buffer(
- SharedBuffer::Create(content.data(), content.length()));
main_frame_->GetFrame()->Loader().CommitNavigation(
- ResourceRequest(script_url), SubstituteData(buffer),
- ClientRedirectPolicy::kNotClientRedirect,
- base::UnguessableToken::Create());
+ WebNavigationParams::CreateWithHTMLBuffer(
+ SharedBuffer::Create(content.data(), content.length()), script_url),
+ nullptr /* extra_data */);
}
void WorkerShadowPage::DidFinishDocumentLoad() {
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/BUILD.gn b/chromium/third_party/blink/renderer/core/feature_policy/BUILD.gn
index c9aa37d4179..70fab1ab0e3 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/feature_policy/BUILD.gn
@@ -7,12 +7,12 @@ import("//third_party/blink/renderer/core/core.gni")
blink_core_sources("feature_policy") {
sources = [
"document_policy.h",
+ "dom_feature_policy.cc",
+ "dom_feature_policy.h",
"feature_policy.cc",
"feature_policy.h",
"iframe_policy.h",
"layout_animations_policy.cc",
"layout_animations_policy.h",
- "policy.cc",
- "policy.h",
]
}
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/document_policy.h b/chromium/third_party/blink/renderer/core/feature_policy/document_policy.h
index 3743ef9b32f..164b1e643f6 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/document_policy.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/document_policy.h
@@ -7,14 +7,14 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/feature_policy/policy.h"
+#include "third_party/blink/renderer/core/feature_policy/dom_feature_policy.h"
#include "third_party/blink/renderer/platform/heap/member.h"
namespace blink {
// DocumentPolicy inherits Policy. It represents the feature policy
// introspection of a document.
-class CORE_EXPORT DocumentPolicy final : public Policy {
+class CORE_EXPORT DocumentPolicy final : public DOMFeaturePolicy {
public:
// Create a new DocumentPolicy, which is associated with |document|.
explicit DocumentPolicy(Document* document) : document_(document) {}
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/policy.cc b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
index 474a4771017..d3db96bbd62 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/policy.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.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 "third_party/blink/renderer/core/feature_policy/policy.h"
+#include "third_party/blink/renderer/core/feature_policy/dom_feature_policy.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/feature_policy/feature_policy.h"
@@ -12,7 +12,7 @@
namespace blink {
-bool Policy::allowsFeature(const String& feature) const {
+bool DOMFeaturePolicy::allowsFeature(const String& feature) const {
if (GetDefaultFeatureNameMap().Contains(feature)) {
return GetPolicy()->IsFeatureEnabled(
GetDefaultFeatureNameMap().at(feature));
@@ -22,7 +22,8 @@ bool Policy::allowsFeature(const String& feature) const {
return false;
}
-bool Policy::allowsFeature(const String& feature, const String& url) const {
+bool DOMFeaturePolicy::allowsFeature(const String& feature,
+ const String& url) const {
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString(url);
if (!origin || origin->IsOpaque()) {
@@ -41,7 +42,14 @@ bool Policy::allowsFeature(const String& feature, const String& url) const {
GetDefaultFeatureNameMap().at(feature), origin->ToUrlOrigin());
}
-Vector<String> Policy::allowedFeatures() const {
+Vector<String> DOMFeaturePolicy::features() const {
+ Vector<String> features;
+ for (const auto& entry : GetDefaultFeatureNameMap())
+ features.push_back(entry.key);
+ return features;
+}
+
+Vector<String> DOMFeaturePolicy::allowedFeatures() const {
Vector<String> allowed_features;
for (const auto& entry : GetDefaultFeatureNameMap()) {
if (GetPolicy()->IsFeatureEnabled(entry.value))
@@ -50,7 +58,8 @@ Vector<String> Policy::allowedFeatures() const {
return allowed_features;
}
-Vector<String> Policy::getAllowlistForFeature(const String& feature) const {
+Vector<String> DOMFeaturePolicy::getAllowlistForFeature(
+ const String& feature) const {
if (GetDefaultFeatureNameMap().Contains(feature)) {
const FeaturePolicy::Allowlist allowlist =
GetPolicy()->GetAllowlistForFeature(
@@ -68,17 +77,18 @@ Vector<String> Policy::getAllowlistForFeature(const String& feature) const {
return Vector<String>();
}
-void Policy::AddWarningForUnrecognizedFeature(const String& feature) const {
+void DOMFeaturePolicy::AddWarningForUnrecognizedFeature(
+ const String& feature) const {
GetDocument()->AddConsoleMessage(
ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel,
"Unrecognized feature: '" + feature + "'."));
}
-void Policy::Trace(blink::Visitor* visitor) {
+void DOMFeaturePolicy::Trace(blink::Visitor* visitor) {
ScriptWrappable::Trace(visitor);
}
-void Policy::UpdateContainerPolicy(
+void DOMFeaturePolicy::UpdateContainerPolicy(
const ParsedFeaturePolicy& container_policy,
scoped_refptr<const SecurityOrigin> src_origin) {}
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/policy.h b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
index 1f066f24c00..e9766df12bc 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/policy.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.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 THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_POLICY_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_POLICY_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_DOM_FEATURE_POLICY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_DOM_FEATURE_POLICY_H_
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -15,13 +15,13 @@ namespace blink {
class Document;
class SecurityOrigin;
-// Policy provides an interface for feature policy introspection of a document
-// (DocumentPolicy) or an iframe (IFramePolicy).
-class CORE_EXPORT Policy : public ScriptWrappable {
+// DOMFeaturePolicy provides an interface for feature policy introspection of a
+// document (DocumentPolicy) or an iframe (IFramePolicy).
+class CORE_EXPORT DOMFeaturePolicy : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- ~Policy() override = default;
+ ~DOMFeaturePolicy() override = default;
// Implementation of methods of the policy interface:
// Returns whether or not the given feature is allowed on the origin of the
@@ -30,14 +30,16 @@ class CORE_EXPORT Policy : public ScriptWrappable {
// Returns whether or not the given feature is allowed on the origin of the
// given URL.
bool allowsFeature(const String& feature, const String& url) const;
+ // Returns a list of feature names that are supported by the user agent.
+ Vector<String> features() const;
// Returns a list of feature names that are allowed on the self origin.
Vector<String> allowedFeatures() const;
// Returns a list of feature name that are allowed on the origin of the given
// URL.
Vector<String> getAllowlistForFeature(const String& url) const;
- // Inform the Policy object when the container policy on its frame element has
- // changed.
+ // Inform the DOMFeaturePolicy object when the container policy on its frame
+ // element has changed.
virtual void UpdateContainerPolicy(
const ParsedFeaturePolicy& container_policy = {},
scoped_refptr<const SecurityOrigin> src_origin = nullptr);
@@ -56,4 +58,4 @@ class CORE_EXPORT Policy : public ScriptWrappable {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_POLICY_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_DOM_FEATURE_POLICY_H_
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.cc b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.cc
index c3ec251454e..6a705510db7 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.cc
@@ -18,9 +18,6 @@
namespace blink {
-constexpr char kReportOnlySuffix[] = "-report-only";
-constexpr size_t kReportOnlySuffixLength = 12;
-
ParsedFeaturePolicy ParseFeaturePolicyHeader(
const String& policy,
scoped_refptr<const SecurityOrigin> origin,
@@ -48,7 +45,7 @@ ParsedFeaturePolicy ParseFeaturePolicy(
Document* document) {
ParsedFeaturePolicy allowlists;
BitVector features_specified(
- static_cast<int>(mojom::FeaturePolicyFeature::kMaxValue));
+ static_cast<int>(mojom::FeaturePolicyFeature::kMaxValue) + 1);
// RFC2616, section 4.2 specifies that headers appearing multiple times can be
// combined with a comma. Walk the header string, and parse each comma
@@ -68,21 +65,9 @@ ParsedFeaturePolicy ParseFeaturePolicy(
// Empty policy. Skip.
if (tokens.IsEmpty())
continue;
- mojom::FeaturePolicyDisposition disposition =
- mojom::FeaturePolicyDisposition::kEnforce;
- String feature_name;
- if (RuntimeEnabledFeatures::FeaturePolicyReportingEnabled() &&
- tokens[0].EndsWith(kReportOnlySuffix)) {
- feature_name = tokens[0].Substring(
- 0, tokens[0].length() - kReportOnlySuffixLength);
- disposition = mojom::FeaturePolicyDisposition::kReport;
- } else {
- feature_name = tokens[0];
- }
+ String feature_name = tokens[0];
if (!feature_names.Contains(feature_name)) {
if (messages) {
- // Console message should display the entire string, with
- // "-report-only" suffix if it was originally included.
messages->push_back("Unrecognized feature: '" + tokens[0] + "'.");
}
continue;
@@ -91,8 +76,6 @@ ParsedFeaturePolicy ParseFeaturePolicy(
mojom::FeaturePolicyFeature feature = feature_names.at(feature_name);
// If a policy has already been specified for the current feature, drop
// the new policy.
- // TODO(crbug.com/904880): Allow a report-only and an enforcing version in
- // the same parsed policy.
if (features_specified.QuickGet(static_cast<int>(feature)))
continue;
@@ -112,7 +95,6 @@ ParsedFeaturePolicy ParseFeaturePolicy(
ParsedFeaturePolicyDeclaration allowlist;
allowlist.feature = feature;
- allowlist.disposition = disposition;
features_specified.QuickSet(static_cast<int>(feature));
std::vector<url::Origin> origins;
// If a policy entry has no (optional) values (e,g,
@@ -206,7 +188,6 @@ bool DisallowFeatureIfNotPresent(mojom::FeaturePolicyFeature feature,
allowlist.feature = feature;
allowlist.matches_all_origins = false;
allowlist.matches_opaque_src = false;
- allowlist.disposition = mojom::FeaturePolicyDisposition::kEnforce;
policy.push_back(allowlist);
return true;
}
@@ -219,7 +200,6 @@ bool AllowFeatureEverywhereIfNotPresent(mojom::FeaturePolicyFeature feature,
allowlist.feature = feature;
allowlist.matches_all_origins = true;
allowlist.matches_opaque_src = true;
- allowlist.disposition = mojom::FeaturePolicyDisposition::kEnforce;
policy.push_back(allowlist);
return true;
}
@@ -276,6 +256,8 @@ const FeatureNameMap& GetDefaultFeatureNameMap() {
ASSERT_ORIGIN_TRIAL(WebVR);
ASSERT_ORIGIN_TRIAL(WebXR);
default_feature_name_map.Set("vr", mojom::FeaturePolicyFeature::kWebVr);
+ default_feature_name_map.Set("wake-lock",
+ mojom::FeaturePolicyFeature::kWakeLock);
if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
default_feature_name_map.Set(
"layout-animations", mojom::FeaturePolicyFeature::kLayoutAnimations);
@@ -283,6 +265,8 @@ const FeatureNameMap& GetDefaultFeatureNameMap() {
mojom::FeaturePolicyFeature::kDocumentWrite);
default_feature_name_map.Set(
"document-domain", mojom::FeaturePolicyFeature::kDocumentDomain);
+ default_feature_name_map.Set("font-display-late-swap",
+ mojom::FeaturePolicyFeature::kFontDisplay);
default_feature_name_map.Set(
"unoptimized-images",
mojom::FeaturePolicyFeature::kUnoptimizedImages);
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/policy.idl b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.idl
index d2d5ad3169d..beadb010328 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/policy.idl
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.idl
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://wicg.github.io/feature-policy
-// TODO(iclelland): add spec for JS exposure in the spec for Feature Policy.
-// Please refer to this doc for more details for now:
-// https://docs.google.com/a/chromium.org/document/d/1wvk3cXkblNnbkMcsKayseK-k0SMGiP9b9fQFgfpqQpc/edit?usp=sharing
+// https://wicg.github.io/feature-policy/#the-policy-object
[
NoInterfaceObject,
- OriginTrialEnabled=FeaturePolicyJavaScriptInterface
-] interface Policy {
+ OriginTrialEnabled=FeaturePolicyJavaScriptInterface,
+ ImplementedAs=DOMFeaturePolicy
+] interface FeaturePolicy {
[MeasureAs=FeaturePolicyJSAPI] boolean allowsFeature(DOMString feature, optional DOMString url);
+ [MeasureAs=FeaturePolicyJSAPI] sequence<DOMString> features();
[MeasureAs=FeaturePolicyJSAPI] sequence<DOMString> allowedFeatures();
[MeasureAs=FeaturePolicyJSAPI] sequence<DOMString> getAllowlistForFeature(DOMString feature);
};
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
index 54d36ab9d49..083afa21240 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
@@ -67,15 +67,6 @@ class FeaturePolicyParserTest : public testing::Test {
~FeaturePolicyParserTest() override = default;
- /*void SetUp() override {
- chrome_client_ = new ConsoleCapturingChromeClient();
- Page::PageClients clients;
- FillWithEmptyClients(clients);
- clients.chrome_client = chrome_client_.Get();
- SetupPageWithClients(&clients);
- Page::InsertOrdinaryPageForTesting(&GetPage());
- }*/
-
scoped_refptr<const SecurityOrigin> origin_a_ =
SecurityOrigin::CreateFromString(ORIGIN_A);
scoped_refptr<const SecurityOrigin> origin_b_ =
@@ -439,12 +430,10 @@ class FeaturePolicyMutationTest : public testing::Test {
ParsedFeaturePolicy test_policy = {{mojom::FeaturePolicyFeature::kFullscreen,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{url_origin_a_, url_origin_b_}},
{mojom::FeaturePolicyFeature::kGeolocation,
false,
false,
- mojom::FeaturePolicyDisposition::kEnforce,
{url_origin_a_}}};
ParsedFeaturePolicy empty_policy = {};
};
@@ -605,4 +594,41 @@ TEST_F(FeaturePolicyMutationTest, TestAllowNewFeatureUnconditionally) {
test_policy));
}
+class FeaturePolicyViolationHistogramTest : public testing::Test {
+ protected:
+ FeaturePolicyViolationHistogramTest() = default;
+
+ ~FeaturePolicyViolationHistogramTest() override = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FeaturePolicyViolationHistogramTest);
+};
+
+TEST_F(FeaturePolicyViolationHistogramTest, PotentialViolation) {
+ HistogramTester tester;
+ const char* histogram_name =
+ "Blink.UseCounter.FeaturePolicy.PotentialViolation";
+ std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
+ DummyPageHolder::Create();
+ // Probing feature state should not count.
+ dummy_page_holder_->GetDocument().IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kPayment);
+ tester.ExpectTotalCount(histogram_name, 0);
+ // Checking the feature state with reporting intent should record a potential
+ // violation.
+ dummy_page_holder_->GetDocument().IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kPayment, ReportOptions::kReportOnFailure);
+ tester.ExpectTotalCount(histogram_name, 1);
+ // The potential violation for an already recorded violation does not count
+ // again.
+ dummy_page_holder_->GetDocument().IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kPayment, ReportOptions::kReportOnFailure);
+ tester.ExpectTotalCount(histogram_name, 1);
+ // Sanity check: check some other feature to increase the count.
+ dummy_page_holder_->GetDocument().IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kFullscreen,
+ ReportOptions::kReportOnFailure);
+ tester.ExpectTotalCount(histogram_name, 2);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h b/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h
index d4645da598f..c6adca5e826 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h
@@ -6,16 +6,17 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_IFRAME_POLICY_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/feature_policy/policy.h"
+#include "third_party/blink/renderer/core/feature_policy/dom_feature_policy.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
-// IFramePolicy inherits Policy. It represents the feature policy introspection
-// of an iframe contained in a document. It is tynthetic from the parent policy
-// and the iframe container policy (parsed from the allow attribute).
-class IFramePolicy final : public Policy {
+// IFramePolicy inherits Policy. It represents the feature policy of an iframe
+// contained in a document, as seen from that document (not including any
+// information private to that frame). It is synthesized from the parent
+// document's policy and the iframe's container policy.
+class IFramePolicy final : public DOMFeaturePolicy {
public:
~IFramePolicy() override = default;
@@ -33,15 +34,13 @@ class IFramePolicy final : public Policy {
const ParsedFeaturePolicy& container_policy,
scoped_refptr<const SecurityOrigin> src_origin) override {
policy_ = FeaturePolicy::CreateFromParentPolicy(
- parent_document_->GetFeaturePolicy(),
- *DirectivesWithDisposition(mojom::FeaturePolicyDisposition::kEnforce,
- container_policy),
+ parent_document_->GetFeaturePolicy(), container_policy,
src_origin->ToUrlOrigin());
}
void Trace(blink::Visitor* visitor) override {
visitor->Trace(parent_document_);
- Policy::Trace(visitor);
+ DOMFeaturePolicy::Trace(visitor);
}
protected:
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.cc b/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.cc
index e85b8f52673..3722ff92d21 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.cc
@@ -35,15 +35,16 @@ LayoutAnimationsPolicy::AffectedCSSProperties() {
}
// static
-
-// static
void LayoutAnimationsPolicy::ReportViolation(
const CSSProperty& animated_property,
const SecurityContext& security_context) {
DCHECK(AffectedCSSProperties().Contains(&animated_property));
auto state = security_context.GetFeatureEnabledState(
mojom::FeaturePolicyFeature::kLayoutAnimations);
- DCHECK_NE(FeatureEnabledState::kEnabled, state);
+ security_context.CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature::kLayoutAnimations);
+ if (state == FeatureEnabledState::kEnabled)
+ return;
security_context.ReportFeaturePolicyViolation(
mojom::FeaturePolicyFeature::kLayoutAnimations,
state == FeatureEnabledState::kReportOnly
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.h b/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.h
index 3b62d4dc9e3..3efcff1dcce 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/layout_animations_policy.h
@@ -24,7 +24,10 @@ class LayoutAnimationsPolicy {
// policy 'layout-animations'.
static const HashSet<const CSSProperty*>& AffectedCSSProperties();
- // Generates a violation report for the blocked |animation_property|.
+ // Generates a violation report for the blocked |animation_property| only if
+ // the feature 'layout-animations' is disabled in |security_context|. Invoking
+ // this method emits a potential violation of the 'layout-animations' policy
+ // which is tracked by Blink.UserCounters.FeaturePolicy.PotentialViolation.
static void ReportViolation(const CSSProperty& animated_property,
const SecurityContext& security_context);
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/policy_test.cc b/chromium/third_party/blink/renderer/core/feature_policy/policy_test.cc
index 2d45104c4b4..3101b3d4e24 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/policy_test.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/policy_test.cc
@@ -31,11 +31,11 @@ class PolicyTest : public testing::Test {
"https://example.com https://example.net");
}
- Policy* GetPolicy() const { return policy_; }
+ DOMFeaturePolicy* GetPolicy() const { return policy_; }
protected:
Persistent<Document> document_;
- Persistent<Policy> policy_;
+ Persistent<DOMFeaturePolicy> policy_;
};
class DocumentPolicyTest : public PolicyTest {
diff --git a/chromium/third_party/blink/renderer/core/fetch/BUILD.gn b/chromium/third_party/blink/renderer/core/fetch/BUILD.gn
index e109ffe2de2..0a898323bc1 100644
--- a/chromium/third_party/blink/renderer/core/fetch/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/fetch/BUILD.gn
@@ -12,6 +12,8 @@ blink_core_sources("fetch") {
"body.h",
"body_stream_buffer.cc",
"body_stream_buffer.h",
+ "buffering_bytes_consumer.cc",
+ "buffering_bytes_consumer.h",
"bytes_consumer.cc",
"bytes_consumer.h",
"bytes_consumer_for_data_consumer_handle.cc",
diff --git a/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc
index 8a2581ef3d1..fccd9f836e4 100644
--- a/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc
@@ -68,7 +68,7 @@ TEST_F(BlobBytesConsumerTest, TwoPhaseRead) {
scoped_refptr<BlobDataHandle> blob_data_handle = CreateBlob(body);
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
EXPECT_FALSE(DidStartLoading());
@@ -82,7 +82,9 @@ TEST_F(BlobBytesConsumerTest, TwoPhaseRead) {
EXPECT_FALSE(consumer->DrainAsFormData());
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
- auto result = (new BytesConsumerTestUtil::TwoPhaseReader(consumer))->Run();
+ auto result =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(consumer))
+ ->Run();
EXPECT_EQ(Result::kDone, result.first);
EXPECT_EQ("hello, world",
BytesConsumerTestUtil::CharVectorToString(result.second));
@@ -91,8 +93,9 @@ TEST_F(BlobBytesConsumerTest, TwoPhaseRead) {
TEST_F(BlobBytesConsumerTest, CancelBeforeStarting) {
scoped_refptr<BlobDataHandle> blob_data_handle = CreateBlob("foo bar");
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
- BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient();
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
+ BlobBytesConsumerTestClient* client =
+ MakeGarbageCollected<BlobBytesConsumerTestClient>();
consumer->SetClient(client);
consumer->Cancel();
@@ -108,8 +111,9 @@ TEST_F(BlobBytesConsumerTest, CancelBeforeStarting) {
TEST_F(BlobBytesConsumerTest, CancelAfterStarting) {
scoped_refptr<BlobDataHandle> blob_data_handle = CreateBlob("foo bar");
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
- BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient();
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
+ BlobBytesConsumerTestClient* client =
+ MakeGarbageCollected<BlobBytesConsumerTestClient>();
consumer->SetClient(client);
const char* buffer = nullptr;
@@ -129,7 +133,7 @@ TEST_F(BlobBytesConsumerTest, DrainAsBlobDataHandle) {
String body = "hello, world";
scoped_refptr<BlobDataHandle> blob_data_handle = CreateBlob(body);
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
EXPECT_FALSE(DidStartLoading());
@@ -149,7 +153,7 @@ TEST_F(BlobBytesConsumerTest, DrainAsBlobDataHandle_2) {
"uuid", "", -1, CreateBlob("foo bar")->CloneBlobPtr().PassInterface());
;
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
EXPECT_FALSE(DidStartLoading());
@@ -169,7 +173,7 @@ TEST_F(BlobBytesConsumerTest, DrainAsBlobDataHandle_3) {
"uuid", "", -1, CreateBlob("foo bar")->CloneBlobPtr().PassInterface());
;
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
EXPECT_FALSE(DidStartLoading());
@@ -184,7 +188,7 @@ TEST_F(BlobBytesConsumerTest, DrainAsFormData) {
String body = "hello, world";
scoped_refptr<BlobDataHandle> blob_data_handle = CreateBlob(body);
BlobBytesConsumer* consumer =
- new BlobBytesConsumer(&GetDocument(), blob_data_handle);
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), blob_data_handle);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
EXPECT_FALSE(DidStartLoading());
@@ -202,7 +206,8 @@ TEST_F(BlobBytesConsumerTest, DrainAsFormData) {
}
TEST_F(BlobBytesConsumerTest, ConstructedFromNullHandle) {
- BlobBytesConsumer* consumer = new BlobBytesConsumer(&GetDocument(), nullptr);
+ BlobBytesConsumer* consumer =
+ MakeGarbageCollected<BlobBytesConsumer>(&GetDocument(), nullptr);
const char* buffer = nullptr;
size_t available;
EXPECT_EQ(BytesConsumer::PublicState::kClosed, consumer->GetPublicState());
diff --git a/chromium/third_party/blink/renderer/core/fetch/body.cc b/chromium/third_party/blink/renderer/core/fetch/body.cc
index ded01690aab..d4e91deda0f 100644
--- a/chromium/third_party/blink/renderer/core/fetch/body.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/body.cc
@@ -151,9 +151,10 @@ ScriptPromise Body::arrayBuffer(ScriptState* script_state,
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
if (BodyBuffer()) {
- BodyBuffer()->StartLoading(FetchDataLoader::CreateLoaderAsArrayBuffer(),
- new BodyArrayBufferConsumer(resolver),
- exception_state);
+ BodyBuffer()->StartLoading(
+ FetchDataLoader::CreateLoaderAsArrayBuffer(),
+ MakeGarbageCollected<BodyArrayBufferConsumer>(resolver),
+ exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
@@ -180,7 +181,7 @@ ScriptPromise Body::blob(ScriptState* script_state,
if (BodyBuffer()) {
BodyBuffer()->StartLoading(
FetchDataLoader::CreateLoaderAsBlobHandle(MimeType()),
- new BodyBlobConsumer(resolver), exception_state);
+ MakeGarbageCollected<BodyBlobConsumer>(resolver), exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
@@ -216,7 +217,8 @@ ScriptPromise Body::formData(ScriptState* script_state,
if (body_buffer && !boundary.IsEmpty()) {
body_buffer->StartLoading(
FetchDataLoader::CreateLoaderAsFormData(boundary),
- new BodyFormDataConsumer(resolver), exception_state);
+ MakeGarbageCollected<BodyFormDataConsumer>(resolver),
+ exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
@@ -226,9 +228,10 @@ ScriptPromise Body::formData(ScriptState* script_state,
}
} else if (parsedType == "application/x-www-form-urlencoded") {
if (BodyBuffer()) {
- BodyBuffer()->StartLoading(FetchDataLoader::CreateLoaderAsString(),
- new BodyFormDataConsumer(resolver),
- exception_state);
+ BodyBuffer()->StartLoading(
+ FetchDataLoader::CreateLoaderAsString(),
+ MakeGarbageCollected<BodyFormDataConsumer>(resolver),
+ exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
@@ -240,9 +243,10 @@ ScriptPromise Body::formData(ScriptState* script_state,
return promise;
} else {
if (BodyBuffer()) {
- BodyBuffer()->StartLoading(FetchDataLoader::CreateLoaderAsFailure(),
- new BodyFormDataConsumer(resolver),
- exception_state);
+ BodyBuffer()->StartLoading(
+ FetchDataLoader::CreateLoaderAsFailure(),
+ MakeGarbageCollected<BodyFormDataConsumer>(resolver),
+ exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
@@ -271,7 +275,8 @@ ScriptPromise Body::json(ScriptState* script_state,
ScriptPromise promise = resolver->Promise();
if (BodyBuffer()) {
BodyBuffer()->StartLoading(FetchDataLoader::CreateLoaderAsString(),
- new BodyJsonConsumer(resolver), exception_state);
+ MakeGarbageCollected<BodyJsonConsumer>(resolver),
+ exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
@@ -298,7 +303,8 @@ ScriptPromise Body::text(ScriptState* script_state,
ScriptPromise promise = resolver->Promise();
if (BodyBuffer()) {
BodyBuffer()->StartLoading(FetchDataLoader::CreateLoaderAsString(),
- new BodyTextConsumer(resolver), exception_state);
+ MakeGarbageCollected<BodyTextConsumer>(resolver),
+ exception_state);
if (exception_state.HadException()) {
// Need to resolve the ScriptPromiseResolver to avoid a DCHECK().
resolver->Resolve();
diff --git a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
index d35b65a2f5e..69622f37cf6 100644
--- a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
@@ -198,8 +198,9 @@ void BodyStreamBuffer::StartLoading(FetchDataLoader* loader,
auto* handle = ReleaseHandle(exception_state);
if (exception_state.HadException())
return;
- loader->Start(handle, new LoaderClient(ExecutionContext::From(script_state_),
- this, client));
+ loader->Start(handle,
+ MakeGarbageCollected<LoaderClient>(
+ ExecutionContext::From(script_state_), this, client));
}
void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
@@ -228,8 +229,8 @@ void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
return;
}
- *branch1 = new BodyStreamBuffer(script_state_, stream1);
- *branch2 = new BodyStreamBuffer(script_state_, stream2);
+ *branch1 = MakeGarbageCollected<BodyStreamBuffer>(script_state_, stream1);
+ *branch2 = MakeGarbageCollected<BodyStreamBuffer>(script_state_, stream2);
return;
}
BytesConsumer* dest1 = nullptr;
@@ -241,8 +242,10 @@ void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
}
BytesConsumer::Tee(ExecutionContext::From(script_state_), handle, &dest1,
&dest2);
- *branch1 = new BodyStreamBuffer(script_state_, dest1, signal_);
- *branch2 = new BodyStreamBuffer(script_state_, dest2, signal_);
+ *branch1 =
+ MakeGarbageCollected<BodyStreamBuffer>(script_state_, dest1, signal_);
+ *branch2 =
+ MakeGarbageCollected<BodyStreamBuffer>(script_state_, dest2, signal_);
}
ScriptPromise BodyStreamBuffer::pull(ScriptState* script_state) {
diff --git a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
index 02464aca51c..331007f8cab 100644
--- a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
@@ -64,8 +64,9 @@ class BodyStreamBufferTest : public testing::Test {
v8::TryCatch block(script_state->GetIsolate());
ScriptValue r = Eval(script_state, s);
if (block.HasCaught()) {
- ADD_FAILURE() << ToCoreString(block.Exception()->ToString(
- script_state->GetIsolate()))
+ ADD_FAILURE() << ToCoreString(block.Exception()
+ ->ToString(script_state->GetContext())
+ .ToLocalChecked())
.Utf8()
.data();
block.ReThrow();
@@ -80,7 +81,7 @@ class MockFetchDataLoader : public FetchDataLoader {
// finished. Since most tests don't care about this, use NiceMock so that the
// calls to Cancel() are ignored.
static testing::NiceMock<MockFetchDataLoader>* Create() {
- return new testing::NiceMock<MockFetchDataLoader>();
+ return MakeGarbageCollected<testing::NiceMock<MockFetchDataLoader>>();
}
MOCK_METHOD2(Start, void(BytesConsumer*, FetchDataLoader::Client*));
@@ -107,12 +108,12 @@ TEST_F(BodyStreamBufferTest, Tee) {
EXPECT_CALL(checkpoint, Call(4));
ReplayingBytesConsumer* src =
- new ReplayingBytesConsumer(&scope.GetDocument());
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "world"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
BodyStreamBuffer* new1;
BodyStreamBuffer* new2;
@@ -172,7 +173,7 @@ TEST_F(BodyStreamBufferTest, TeeFromHandleMadeFromStream) {
EXPECT_CALL(checkpoint, Call(4));
BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), stream);
+ MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(), stream);
BodyStreamBuffer* new1;
BodyStreamBuffer* new2;
@@ -212,9 +213,10 @@ TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandle) {
auto size = data->length();
scoped_refptr<BlobDataHandle> blob_data_handle =
BlobDataHandle::Create(std::move(data), size);
- BodyStreamBuffer* buffer = new BodyStreamBuffer(
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
scope.GetScriptState(),
- new BlobBytesConsumer(scope.GetExecutionContext(), blob_data_handle),
+ MakeGarbageCollected<BlobBytesConsumer>(scope.GetExecutionContext(),
+ blob_data_handle),
nullptr);
EXPECT_FALSE(buffer->IsStreamLocked(ASSERT_NO_EXCEPTION).value_or(true));
@@ -234,9 +236,10 @@ TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandle) {
TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandleReturnsNull) {
V8TestingScope scope;
// This BytesConsumer is not drainable.
- BytesConsumer* src = new ReplayingBytesConsumer(&scope.GetDocument());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
EXPECT_FALSE(buffer->IsStreamLocked(ASSERT_NO_EXCEPTION).value_or(true));
EXPECT_FALSE(buffer->IsStreamDisturbed(ASSERT_NO_EXCEPTION).value_or(true));
@@ -259,7 +262,7 @@ TEST_F(BodyStreamBufferTest,
ReadableStream::Create(scope.GetScriptState(), exception_state);
ASSERT_TRUE(stream);
BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), stream);
+ MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(), stream);
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_FALSE(buffer->IsStreamLocked(exception_state).value_or(true));
@@ -284,11 +287,11 @@ TEST_F(BodyStreamBufferTest, DrainAsFormData) {
scoped_refptr<EncodedFormData> input_form_data =
data->EncodeMultiPartFormData();
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(),
- MakeGarbageCollected<FormDataBytesConsumer>(
- scope.GetExecutionContext(), input_form_data),
- nullptr);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(),
+ MakeGarbageCollected<FormDataBytesConsumer>(scope.GetExecutionContext(),
+ input_form_data),
+ nullptr);
EXPECT_FALSE(buffer->IsStreamLocked(ASSERT_NO_EXCEPTION).value_or(true));
EXPECT_FALSE(buffer->IsStreamDisturbed(ASSERT_NO_EXCEPTION).value_or(true));
@@ -306,9 +309,10 @@ TEST_F(BodyStreamBufferTest, DrainAsFormData) {
TEST_F(BodyStreamBufferTest, DrainAsFormDataReturnsNull) {
V8TestingScope scope;
// This BytesConsumer is not drainable.
- BytesConsumer* src = new ReplayingBytesConsumer(&scope.GetDocument());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
EXPECT_FALSE(buffer->IsStreamLocked(ASSERT_NO_EXCEPTION).value_or(true));
EXPECT_FALSE(buffer->IsStreamDisturbed(ASSERT_NO_EXCEPTION).value_or(true));
@@ -328,7 +332,7 @@ TEST_F(BodyStreamBufferTest,
auto* stream =
ReadableStream::Create(scope.GetScriptState(), exception_state);
BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), stream);
+ MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(), stream);
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_FALSE(buffer->IsStreamLocked(exception_state).value_or(true));
@@ -356,12 +360,12 @@ TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsArrayBuffer) {
EXPECT_CALL(checkpoint, Call(2));
ReplayingBytesConsumer* src =
- new ReplayingBytesConsumer(&scope.GetDocument());
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
buffer->StartLoading(FetchDataLoader::CreateLoaderAsArrayBuffer(), client,
ASSERT_NO_EXCEPTION);
@@ -394,12 +398,12 @@ TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsBlob) {
EXPECT_CALL(checkpoint, Call(2));
ReplayingBytesConsumer* src =
- new ReplayingBytesConsumer(&scope.GetDocument());
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
buffer->StartLoading(FetchDataLoader::CreateLoaderAsBlobHandle("text/plain"),
client, ASSERT_NO_EXCEPTION);
@@ -428,12 +432,12 @@ TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsString) {
EXPECT_CALL(checkpoint, Call(2));
ReplayingBytesConsumer* src =
- new ReplayingBytesConsumer(&scope.GetDocument());
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
buffer->StartLoading(FetchDataLoader::CreateLoaderAsString(), client,
ASSERT_NO_EXCEPTION);
@@ -460,7 +464,7 @@ TEST_F(BodyStreamBufferTest, LoadClosedHandle) {
EXPECT_CALL(*client, DidFetchDataLoadedString(String("")));
EXPECT_CALL(checkpoint, Call(2));
- BodyStreamBuffer* buffer = new BodyStreamBuffer(
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
scope.GetScriptState(), BytesConsumer::CreateClosed(), nullptr);
EXPECT_TRUE(buffer->IsStreamClosed(ASSERT_NO_EXCEPTION).value_or(false));
@@ -489,7 +493,7 @@ TEST_F(BodyStreamBufferTest, LoadErroredHandle) {
EXPECT_CALL(*client, DidFetchDataLoadFailed());
EXPECT_CALL(checkpoint, Call(2));
- BodyStreamBuffer* buffer = new BodyStreamBuffer(
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
scope.GetScriptState(),
BytesConsumer::CreateErrored(BytesConsumer::Error()), nullptr);
@@ -520,12 +524,12 @@ TEST_F(BodyStreamBufferTest, LoaderShouldBeKeptAliveByBodyStreamBuffer) {
EXPECT_CALL(checkpoint, Call(2));
ReplayingBytesConsumer* src =
- new ReplayingBytesConsumer(&scope.GetDocument());
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- Persistent<BodyStreamBuffer> buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ Persistent<BodyStreamBuffer> buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
buffer->StartLoading(FetchDataLoader::CreateLoaderAsString(), client,
ASSERT_NO_EXCEPTION);
@@ -538,11 +542,11 @@ TEST_F(BodyStreamBufferTest, LoaderShouldBeKeptAliveByBodyStreamBuffer) {
TEST_F(BodyStreamBufferTest, SourceShouldBeCanceledWhenCanceled) {
V8TestingScope scope;
ReplayingBytesConsumer* consumer =
- new BytesConsumerTestUtil::ReplayingBytesConsumer(
+ MakeGarbageCollected<BytesConsumerTestUtil::ReplayingBytesConsumer>(
scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), consumer, nullptr);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), consumer, nullptr);
ScriptValue reason(scope.GetScriptState(),
V8String(scope.GetScriptState()->GetIsolate(), "reason"));
EXPECT_FALSE(consumer->IsCancelled());
@@ -553,12 +557,12 @@ TEST_F(BodyStreamBufferTest, SourceShouldBeCanceledWhenCanceled) {
TEST_F(BodyStreamBufferTest, NestedPull) {
V8TestingScope scope;
ReplayingBytesConsumer* src =
- new ReplayingBytesConsumer(&scope.GetDocument());
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kError));
- Persistent<BodyStreamBuffer> buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ Persistent<BodyStreamBuffer> buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
auto result =
scope.GetScriptState()->GetContext()->Global()->CreateDataProperty(
@@ -583,9 +587,10 @@ TEST_F(BodyStreamBufferTest, NestedPull) {
TEST_F(BodyStreamBufferTest, NullAbortSignalIsNotAborted) {
V8TestingScope scope;
// This BytesConsumer is not drainable.
- BytesConsumer* src = new ReplayingBytesConsumer(&scope.GetDocument());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, nullptr);
+ BytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, nullptr);
EXPECT_FALSE(buffer->IsAborted());
}
@@ -593,10 +598,11 @@ TEST_F(BodyStreamBufferTest, NullAbortSignalIsNotAborted) {
TEST_F(BodyStreamBufferTest, AbortSignalMakesAborted) {
V8TestingScope scope;
// This BytesConsumer is not drainable.
- BytesConsumer* src = new ReplayingBytesConsumer(&scope.GetDocument());
- auto* signal = new AbortSignal(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, signal);
+ BytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
+ auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, signal);
EXPECT_FALSE(buffer->IsAborted());
signal->SignalAbort();
@@ -626,9 +632,9 @@ TEST_F(BodyStreamBufferTest,
EXPECT_CALL(checkpoint, Call(3));
- auto* signal = new AbortSignal(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, signal);
+ auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, signal);
checkpoint.Call(1);
signal->SignalAbort();
@@ -660,9 +666,9 @@ TEST_F(BodyStreamBufferTest, AbortAfterStartLoadingCallsDataLoaderClientAbort) {
EXPECT_CALL(checkpoint, Call(3));
- auto* signal = new AbortSignal(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, signal);
+ auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, signal);
checkpoint.Call(1);
buffer->StartLoading(loader, client, ASSERT_NO_EXCEPTION);
@@ -695,9 +701,9 @@ TEST_F(BodyStreamBufferTest,
EXPECT_CALL(checkpoint, Call(3));
- auto* signal = new AbortSignal(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- new BodyStreamBuffer(scope.GetScriptState(), src, signal);
+ auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), src, signal);
checkpoint.Call(1);
buffer->StartLoading(loader, client, ASSERT_NO_EXCEPTION);
diff --git a/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.cc
new file mode 100644
index 00000000000..d87337c3622
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.cc
@@ -0,0 +1,144 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h"
+
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+BufferingBytesConsumer::BufferingBytesConsumer(BytesConsumer* bytes_consumer)
+ : bytes_consumer_(bytes_consumer) {
+ bytes_consumer_->SetClient(this);
+}
+
+BufferingBytesConsumer::~BufferingBytesConsumer() = default;
+
+BytesConsumer::Result BufferingBytesConsumer::BeginRead(const char** buffer,
+ size_t* available) {
+ if (buffer_.IsEmpty()) {
+ if (has_seen_error_)
+ return Result::kError;
+
+ if (has_seen_end_of_data_) {
+ ClearClient();
+ return Result::kDone;
+ }
+
+ BufferData();
+
+ if (has_seen_error_)
+ return Result::kError;
+
+ if (buffer_.IsEmpty())
+ return has_seen_end_of_data_ ? Result::kDone : Result::kShouldWait;
+ }
+
+ DCHECK_LT(offset_for_first_chunk_, buffer_[0].size());
+ *buffer = buffer_[0].data() + offset_for_first_chunk_;
+ *available = buffer_[0].size() - offset_for_first_chunk_;
+ return Result::kOk;
+}
+
+BytesConsumer::Result BufferingBytesConsumer::EndRead(size_t read_size) {
+ if (buffer_.IsEmpty()) {
+ DCHECK(has_seen_error_);
+ return Result::kError;
+ }
+
+ DCHECK_LE(offset_for_first_chunk_ + read_size, buffer_[0].size());
+ offset_for_first_chunk_ += read_size;
+
+ if (offset_for_first_chunk_ == buffer_[0].size()) {
+ offset_for_first_chunk_ = 0;
+ buffer_.pop_front();
+ }
+
+ if (buffer_.IsEmpty() && has_seen_end_of_data_) {
+ ClearClient();
+ return Result::kDone;
+ }
+ return Result::kOk;
+}
+
+scoped_refptr<BlobDataHandle> BufferingBytesConsumer::DrainAsBlobDataHandle(
+ BlobSizePolicy policy) {
+ return bytes_consumer_->DrainAsBlobDataHandle(policy);
+}
+
+scoped_refptr<EncodedFormData> BufferingBytesConsumer::DrainAsFormData() {
+ return bytes_consumer_->DrainAsFormData();
+}
+
+mojo::ScopedDataPipeConsumerHandle BufferingBytesConsumer::DrainAsDataPipe() {
+ // We intentionally return an empty handle here, because returning a DataPipe
+ // may activate back pressure.
+ return {};
+}
+
+void BufferingBytesConsumer::SetClient(BytesConsumer::Client* client) {
+ client_ = client;
+}
+
+void BufferingBytesConsumer::ClearClient() {
+ client_ = nullptr;
+}
+
+void BufferingBytesConsumer::Cancel() {
+ ClearClient();
+ bytes_consumer_->Cancel();
+}
+
+BytesConsumer::PublicState BufferingBytesConsumer::GetPublicState() const {
+ if (buffer_.IsEmpty())
+ return bytes_consumer_->GetPublicState();
+ return PublicState::kReadableOrWaiting;
+}
+
+BytesConsumer::Error BufferingBytesConsumer::GetError() const {
+ return bytes_consumer_->GetError();
+}
+
+void BufferingBytesConsumer::Trace(Visitor* visitor) {
+ visitor->Trace(bytes_consumer_);
+ visitor->Trace(client_);
+ BytesConsumer::Trace(visitor);
+ BytesConsumer::Client::Trace(visitor);
+}
+
+void BufferingBytesConsumer::OnStateChange() {
+ BytesConsumer::Client* client = client_;
+ BufferData();
+ if (client)
+ client->OnStateChange();
+}
+
+void BufferingBytesConsumer::BufferData() {
+ while (true) {
+ const char* p = nullptr;
+ size_t available = 0;
+ auto result = bytes_consumer_->BeginRead(&p, &available);
+ if (result == Result::kShouldWait)
+ return;
+ if (result == Result::kOk) {
+ Vector<char> chunk;
+ chunk.Append(p, SafeCast<wtf_size_t>(available));
+ buffer_.push_back(std::move(chunk));
+ result = bytes_consumer_->EndRead(available);
+ }
+ if (result == Result::kDone) {
+ has_seen_end_of_data_ = true;
+ ClearClient();
+ return;
+ }
+ if (result != Result::kOk) {
+ buffer_.clear();
+ has_seen_error_ = true;
+ ClearClient();
+ return;
+ }
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h b/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h
new file mode 100644
index 00000000000..db3a5af11e7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_BUFFERING_BYTES_CONSUMER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_BUFFERING_BYTES_CONSUMER_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/fetch/bytes_consumer.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+// BufferingBytesConsumer is a BytesConsumer. It takes a BytesConsumer
+// ("the original BytesConsumer") as a constructor parameter, and results read
+// from the BufferingBytesConsumer are as same as results which would be read
+// from the original BytesConsumer.
+// BufferingBytesConsumer buffers reads chunks from the original BytesConsumer
+// and store it until they are read, before read requests are issued from the
+// client.
+class CORE_EXPORT BufferingBytesConsumer final : public BytesConsumer,
+ private BytesConsumer::Client {
+ USING_GARBAGE_COLLECTED_MIXIN(BufferingBytesConsumer);
+
+ public:
+ // Creates a BufferingBytesConsumer. |bytes_consumer| is the original
+ // BytesConsumer.
+ // |bytes_consumer| must not have a client.
+ explicit BufferingBytesConsumer(BytesConsumer* bytes_consumer);
+ ~BufferingBytesConsumer() override;
+
+ // BufferingBytesConsumer
+ Result BeginRead(const char** buffer, size_t* available) override;
+ Result EndRead(size_t read_size) override;
+ scoped_refptr<BlobDataHandle> DrainAsBlobDataHandle(BlobSizePolicy) override;
+ scoped_refptr<EncodedFormData> DrainAsFormData() override;
+ mojo::ScopedDataPipeConsumerHandle DrainAsDataPipe() override;
+ void SetClient(BytesConsumer::Client*) override;
+ void ClearClient() override;
+ void Cancel() override;
+ PublicState GetPublicState() const override;
+ Error GetError() const override;
+ String DebugName() const override { return "BufferingBytesConsumer"; }
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ // BufferingBytesConsumer::Client
+ void OnStateChange() override;
+ void BufferData();
+
+ const TraceWrapperMember<BytesConsumer> bytes_consumer_;
+ Deque<Vector<char>> buffer_;
+ size_t offset_for_first_chunk_ = 0;
+ bool has_seen_end_of_data_ = false;
+ bool has_seen_error_ = false;
+ Member<BytesConsumer::Client> client_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_BUFFERING_BYTES_CONSUMER_H_
diff --git a/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer_test.cc
new file mode 100644
index 00000000000..2ac51b6dfc8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/fetch/buffering_bytes_consumer_test.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h"
+
+namespace blink {
+namespace {
+
+class BufferingBytesConsumerTest : public testing::Test {
+ public:
+ using ReplayingBytesConsumer = BytesConsumerTestUtil::ReplayingBytesConsumer;
+ using Command = BytesConsumerTestUtil::Command;
+ using TwoPhaseReader = BytesConsumerTestUtil::TwoPhaseReader;
+ using Result = BytesConsumer::Result;
+ using PublicState = BytesConsumer::PublicState;
+
+ static String CharVectorToString(const Vector<char>& x) {
+ return BytesConsumerTestUtil::CharVectorToString(x);
+ }
+};
+
+TEST_F(BufferingBytesConsumerTest, Read) {
+ V8TestingScope scope;
+ auto* replaying_bytes_consumer =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&scope.GetDocument());
+
+ replaying_bytes_consumer->Add(Command(Command::kWait));
+ replaying_bytes_consumer->Add(Command(Command::kData, "1"));
+ replaying_bytes_consumer->Add(Command(Command::kWait));
+ replaying_bytes_consumer->Add(Command(Command::kWait));
+ replaying_bytes_consumer->Add(Command(Command::kData, "23"));
+ replaying_bytes_consumer->Add(Command(Command::kData, "4"));
+ replaying_bytes_consumer->Add(Command(Command::kData, "567"));
+ replaying_bytes_consumer->Add(Command(Command::kData, "8"));
+ replaying_bytes_consumer->Add(Command(Command::kDone));
+
+ auto* bytes_consumer =
+ MakeGarbageCollected<BufferingBytesConsumer>(replaying_bytes_consumer);
+
+ EXPECT_EQ(PublicState::kReadableOrWaiting, bytes_consumer->GetPublicState());
+ auto* reader = MakeGarbageCollected<TwoPhaseReader>(bytes_consumer);
+ auto result = reader->Run();
+
+ EXPECT_EQ(PublicState::kClosed, bytes_consumer->GetPublicState());
+ ASSERT_EQ(result.first, Result::kDone);
+ EXPECT_EQ("12345678", CharVectorToString(result.second));
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer.cc
index c8c77e1a933..20951911b9f 100644
--- a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer.cc
@@ -38,8 +38,10 @@ class TeeHelper final : public GarbageCollectedFinalized<TeeHelper>,
public:
TeeHelper(ExecutionContext* execution_context, BytesConsumer* consumer)
: src_(consumer),
- destination1_(new Destination(execution_context, this)),
- destination2_(new Destination(execution_context, this)) {
+ destination1_(
+ MakeGarbageCollected<Destination>(execution_context, this)),
+ destination2_(
+ MakeGarbageCollected<Destination>(execution_context, this)) {
consumer->SetClient(this);
// As no client is set to either destinations, Destination::notify() is
// no-op in this function.
@@ -64,7 +66,8 @@ class TeeHelper final : public GarbageCollectedFinalized<TeeHelper>,
}
Chunk* chunk = nullptr;
if (result == Result::kOk) {
- chunk = new Chunk(buffer, SafeCast<wtf_size_t>(available));
+ chunk = MakeGarbageCollected<Chunk>(buffer,
+ SafeCast<wtf_size_t>(available));
result = src_->EndRead(available);
}
switch (result) {
@@ -78,6 +81,10 @@ class TeeHelper final : public GarbageCollectedFinalized<TeeHelper>,
NOTREACHED();
return;
case Result::kDone:
+ if (chunk) {
+ destination1_->Enqueue(chunk);
+ destination2_->Enqueue(chunk);
+ }
if (destination1_was_empty)
destination1_->Notify();
if (destination2_was_empty)
@@ -367,9 +374,11 @@ void BytesConsumer::Tee(ExecutionContext* execution_context,
src->DrainAsBlobDataHandle(BlobSizePolicy::kAllowBlobWithInvalidSize);
if (blob_data_handle) {
// Register a client in order to be consistent.
- src->SetClient(new NoopClient);
- *dest1 = new BlobBytesConsumer(execution_context, blob_data_handle);
- *dest2 = new BlobBytesConsumer(execution_context, blob_data_handle);
+ src->SetClient(MakeGarbageCollected<NoopClient>());
+ *dest1 = MakeGarbageCollected<BlobBytesConsumer>(execution_context,
+ blob_data_handle);
+ *dest2 = MakeGarbageCollected<BlobBytesConsumer>(execution_context,
+ blob_data_handle);
return;
}
@@ -384,17 +393,17 @@ void BytesConsumer::Tee(ExecutionContext* execution_context,
return;
}
- TeeHelper* tee = new TeeHelper(execution_context, src);
+ TeeHelper* tee = MakeGarbageCollected<TeeHelper>(execution_context, src);
*dest1 = tee->Destination1();
*dest2 = tee->Destination2();
}
BytesConsumer* BytesConsumer::CreateErrored(const BytesConsumer::Error& error) {
- return new ErroredBytesConsumer(error);
+ return MakeGarbageCollected<ErroredBytesConsumer>(error);
}
BytesConsumer* BytesConsumer::CreateClosed() {
- return new ClosedBytesConsumer();
+ return MakeGarbageCollected<ClosedBytesConsumer>();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle_test.cc b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle_test.cc
index ef9b5ef183b..51bff88e8bf 100644
--- a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle_test.cc
@@ -40,7 +40,7 @@ class MockBytesConsumerClient
public:
static MockBytesConsumerClient* Create() {
- return new testing::StrictMock<MockBytesConsumerClient>();
+ return MakeGarbageCollected<testing::StrictMock<MockBytesConsumerClient>>();
}
MOCK_METHOD0(OnStateChange, void());
String DebugName() const override { return "MockBytesConsumerClient"; }
@@ -62,7 +62,7 @@ class MockDataConsumerHandle final : public WebDataConsumerHandle {
void Trace(blink::Visitor* visitor) {}
};
- MockDataConsumerHandle() : proxy_(new MockReaderProxy) {}
+ MockDataConsumerHandle() : proxy_(MakeGarbageCollected<MockReaderProxy>()) {}
MockReaderProxy* Proxy() { return proxy_; }
const char* DebugName() const override { return "MockDataConsumerHandle"; }
@@ -96,7 +96,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, Create) {
handle->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello"));
handle->Add(DataConsumerCommand(DataConsumerCommand::kDone));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
}
TEST_F(BytesConsumerForDataConsumerHandleTest, BecomeReadable) {
@@ -112,7 +113,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, BecomeReadable) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello"));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(client);
EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting,
consumer->GetPublicState());
@@ -137,7 +139,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, BecomeClosed) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kDone));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(client);
EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting,
consumer->GetPublicState());
@@ -161,7 +164,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, BecomeErrored) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kError));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(client);
EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting,
consumer->GetPublicState());
@@ -184,7 +188,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, ClearClient) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kError));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(client);
consumer->ClearClient();
@@ -197,7 +202,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, TwoPhaseReadWhenReadable) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello"));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
const char* buffer = nullptr;
@@ -216,7 +222,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, TwoPhaseReadWhenReadable) {
TEST_F(BytesConsumerForDataConsumerHandleTest, TwoPhaseReadWhenWaiting) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
const char* buffer = nullptr;
size_t available = 0;
@@ -227,7 +234,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, TwoPhaseReadWhenClosed) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kDone));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
const char* buffer = nullptr;
size_t available = 0;
@@ -238,7 +246,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, TwoPhaseReadWhenErrored) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
handle->Add(DataConsumerCommand(DataConsumerCommand::kError));
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
const char* buffer = nullptr;
size_t available = 0;
@@ -249,7 +258,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, TwoPhaseReadWhenErrored) {
TEST_F(BytesConsumerForDataConsumerHandleTest, Cancel) {
std::unique_ptr<ReplayingHandle> handle = ReplayingHandle::Create();
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
consumer->Cancel();
const char* buffer = nullptr;
@@ -264,7 +274,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, drainAsBlobDataHandle) {
std::make_unique<MockDataConsumerHandle>();
Persistent<MockDataConsumerHandle::MockReaderProxy> proxy = handle->Proxy();
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
Checkpoint checkpoint;
@@ -283,7 +294,8 @@ TEST_F(BytesConsumerForDataConsumerHandleTest, drainAsFormData) {
std::make_unique<MockDataConsumerHandle>();
Persistent<MockDataConsumerHandle::MockReaderProxy> proxy = handle->Proxy();
Persistent<BytesConsumer> consumer =
- new BytesConsumerForDataConsumerHandle(&GetDocument(), std::move(handle));
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ &GetDocument(), std::move(handle));
consumer->SetClient(MockBytesConsumerClient::Create());
Checkpoint checkpoint;
diff --git a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test.cc
index e709975543e..61511494b62 100644
--- a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test.cc
@@ -83,7 +83,8 @@ class FakeBlobBytesConsumer : public BytesConsumer {
};
TEST_F(BytesConsumerTeeTest, CreateDone) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
EXPECT_FALSE(src->IsCancelled());
@@ -91,8 +92,12 @@ TEST_F(BytesConsumerTeeTest, CreateDone) {
BytesConsumer* dest2 = nullptr;
BytesConsumer::Tee(&GetDocument(), src, &dest1, &dest2);
- auto result1 = (new BytesConsumerTestUtil::TwoPhaseReader(dest1))->Run();
- auto result2 = (new BytesConsumerTestUtil::TwoPhaseReader(dest2))->Run();
+ auto result1 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest1))
+ ->Run();
+ auto result2 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run();
EXPECT_EQ(Result::kDone, result1.first);
EXPECT_TRUE(result1.second.IsEmpty());
@@ -111,7 +116,8 @@ TEST_F(BytesConsumerTeeTest, CreateDone) {
}
TEST_F(BytesConsumerTeeTest, TwoPhaseRead) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
@@ -130,8 +136,48 @@ TEST_F(BytesConsumerTeeTest, TwoPhaseRead) {
EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting,
dest2->GetPublicState());
- auto result1 = (new BytesConsumerTestUtil::TwoPhaseReader(dest1))->Run();
- auto result2 = (new BytesConsumerTestUtil::TwoPhaseReader(dest2))->Run();
+ auto result1 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest1))
+ ->Run();
+ auto result2 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run();
+
+ EXPECT_EQ(Result::kDone, result1.first);
+ EXPECT_EQ("hello, world",
+ BytesConsumerTestUtil::CharVectorToString(result1.second));
+ EXPECT_EQ(BytesConsumer::PublicState::kClosed, dest1->GetPublicState());
+ EXPECT_EQ(Result::kDone, result2.first);
+ EXPECT_EQ("hello, world",
+ BytesConsumerTestUtil::CharVectorToString(result2.second));
+ EXPECT_EQ(BytesConsumer::PublicState::kClosed, dest2->GetPublicState());
+ EXPECT_FALSE(src->IsCancelled());
+}
+
+TEST_F(BytesConsumerTeeTest, TwoPhaseReadWithDataAndDone) {
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
+
+ src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
+ src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
+ src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
+ src->Add(BytesConsumerCommand(BytesConsumerCommand::kDataAndDone, "world"));
+
+ BytesConsumer* dest1 = nullptr;
+ BytesConsumer* dest2 = nullptr;
+ BytesConsumer::Tee(&GetDocument(), src, &dest1, &dest2);
+
+ EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting,
+ dest1->GetPublicState());
+ EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting,
+ dest2->GetPublicState());
+
+ auto result1 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest1))
+ ->Run();
+ auto result2 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run();
EXPECT_EQ(Result::kDone, result1.first);
EXPECT_EQ("hello, world",
@@ -145,7 +191,8 @@ TEST_F(BytesConsumerTeeTest, TwoPhaseRead) {
}
TEST_F(BytesConsumerTeeTest, Error) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "world"));
@@ -158,8 +205,12 @@ TEST_F(BytesConsumerTeeTest, Error) {
EXPECT_EQ(BytesConsumer::PublicState::kErrored, dest1->GetPublicState());
EXPECT_EQ(BytesConsumer::PublicState::kErrored, dest2->GetPublicState());
- auto result1 = (new BytesConsumerTestUtil::TwoPhaseReader(dest1))->Run();
- auto result2 = (new BytesConsumerTestUtil::TwoPhaseReader(dest2))->Run();
+ auto result1 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest1))
+ ->Run();
+ auto result2 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run();
EXPECT_EQ(Result::kError, result1.first);
EXPECT_TRUE(result1.second.IsEmpty());
@@ -178,7 +229,8 @@ TEST_F(BytesConsumerTeeTest, Error) {
}
TEST_F(BytesConsumerTeeTest, Cancel) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
@@ -205,7 +257,8 @@ TEST_F(BytesConsumerTeeTest, Cancel) {
}
TEST_F(BytesConsumerTeeTest, CancelShouldNotAffectTheOtherDestination) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
@@ -228,7 +281,9 @@ TEST_F(BytesConsumerTeeTest, CancelShouldNotAffectTheOtherDestination) {
dest2->GetPublicState());
EXPECT_FALSE(src->IsCancelled());
- auto result2 = (new BytesConsumerTestUtil::TwoPhaseReader(dest2))->Run();
+ auto result2 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run();
EXPECT_EQ(BytesConsumer::PublicState::kClosed, dest1->GetPublicState());
EXPECT_EQ(BytesConsumer::PublicState::kClosed, dest2->GetPublicState());
@@ -239,7 +294,8 @@ TEST_F(BytesConsumerTeeTest, CancelShouldNotAffectTheOtherDestination) {
}
TEST_F(BytesConsumerTeeTest, CancelShouldNotAffectTheOtherDestination2) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
@@ -262,7 +318,9 @@ TEST_F(BytesConsumerTeeTest, CancelShouldNotAffectTheOtherDestination2) {
dest2->GetPublicState());
EXPECT_FALSE(src->IsCancelled());
- auto result2 = (new BytesConsumerTestUtil::TwoPhaseReader(dest2))->Run();
+ auto result2 =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run();
EXPECT_EQ(BytesConsumer::PublicState::kClosed, dest1->GetPublicState());
EXPECT_EQ(BytesConsumer::PublicState::kErrored, dest2->GetPublicState());
@@ -273,7 +331,8 @@ TEST_F(BytesConsumerTeeTest, CancelShouldNotAffectTheOtherDestination2) {
TEST_F(BytesConsumerTeeTest, BlobHandle) {
scoped_refptr<BlobDataHandle> blob_data_handle =
BlobDataHandle::Create(BlobData::Create(), 12345);
- BytesConsumer* src = new FakeBlobBytesConsumer(blob_data_handle);
+ BytesConsumer* src =
+ MakeGarbageCollected<FakeBlobBytesConsumer>(blob_data_handle);
BytesConsumer* dest1 = nullptr;
BytesConsumer* dest2 = nullptr;
@@ -294,7 +353,8 @@ TEST_F(BytesConsumerTeeTest, BlobHandle) {
TEST_F(BytesConsumerTeeTest, BlobHandleWithInvalidSize) {
scoped_refptr<BlobDataHandle> blob_data_handle =
BlobDataHandle::Create(BlobData::Create(), -1);
- BytesConsumer* src = new FakeBlobBytesConsumer(blob_data_handle);
+ BytesConsumer* src =
+ MakeGarbageCollected<FakeBlobBytesConsumer>(blob_data_handle);
BytesConsumer* dest1 = nullptr;
BytesConsumer* dest2 = nullptr;
@@ -312,7 +372,8 @@ TEST_F(BytesConsumerTeeTest, BlobHandleWithInvalidSize) {
}
TEST_F(BytesConsumerTeeTest, ConsumerCanBeErroredInTwoPhaseRead) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "a"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kError));
@@ -320,7 +381,8 @@ TEST_F(BytesConsumerTeeTest, ConsumerCanBeErroredInTwoPhaseRead) {
BytesConsumer* dest1 = nullptr;
BytesConsumer* dest2 = nullptr;
BytesConsumer::Tee(&GetDocument(), src, &dest1, &dest2);
- BytesConsumerTestClient* client = new BytesConsumerTestClient();
+ BytesConsumerTestClient* client =
+ MakeGarbageCollected<BytesConsumerTestClient>();
dest1->SetClient(client);
const char* buffer = nullptr;
@@ -332,7 +394,9 @@ TEST_F(BytesConsumerTeeTest, ConsumerCanBeErroredInTwoPhaseRead) {
dest1->GetPublicState());
int num_on_state_change_called = client->NumOnStateChangeCalled();
EXPECT_EQ(Result::kError,
- (new BytesConsumerTestUtil::TwoPhaseReader(dest2))->Run().first);
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(dest2))
+ ->Run()
+ .first);
EXPECT_EQ(BytesConsumer::PublicState::kErrored, dest1->GetPublicState());
EXPECT_EQ(num_on_state_change_called + 1, client->NumOnStateChangeCalled());
EXPECT_EQ('a', buffer[0]);
@@ -341,11 +405,13 @@ TEST_F(BytesConsumerTeeTest, ConsumerCanBeErroredInTwoPhaseRead) {
TEST_F(BytesConsumerTeeTest,
AsyncNotificationShouldBeDispatchedWhenAllDataIsConsumed) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "a"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kWait));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- BytesConsumerTestClient* client = new BytesConsumerTestClient();
+ BytesConsumerTestClient* client =
+ MakeGarbageCollected<BytesConsumerTestClient>();
BytesConsumer* dest1 = nullptr;
BytesConsumer* dest2 = nullptr;
@@ -377,10 +443,12 @@ TEST_F(BytesConsumerTeeTest,
TEST_F(BytesConsumerTeeTest,
AsyncCloseNotificationShouldBeCancelledBySubsequentReadCall) {
- ReplayingBytesConsumer* src = new ReplayingBytesConsumer(&GetDocument());
+ ReplayingBytesConsumer* src =
+ MakeGarbageCollected<ReplayingBytesConsumer>(&GetDocument());
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "a"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- BytesConsumerTestClient* client = new BytesConsumerTestClient();
+ BytesConsumerTestClient* client =
+ MakeGarbageCollected<BytesConsumerTestClient>();
BytesConsumer* dest1 = nullptr;
BytesConsumer* dest2 = nullptr;
diff --git a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.cc b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.cc
index 93bdfddbd84..9ff3bb84b76 100644
--- a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.cc
@@ -56,6 +56,7 @@ Result BytesConsumerTestUtil::ReplayingBytesConsumer::BeginRead(
}
const Command& command = commands_[0];
switch (command.GetName()) {
+ case Command::kDataAndDone:
case Command::kData:
DCHECK_LE(offset_, command.Body().size());
*buffer = command.Body().data() + offset_;
@@ -87,7 +88,8 @@ Result BytesConsumerTestUtil::ReplayingBytesConsumer::BeginRead(
Result BytesConsumerTestUtil::ReplayingBytesConsumer::EndRead(size_t read) {
DCHECK(!commands_.IsEmpty());
const Command& command = commands_[0];
- DCHECK_EQ(Command::kData, command.GetName());
+ const auto name = command.GetName();
+ DCHECK(name == Command::kData || name == Command::kDataAndDone);
offset_ += read;
DCHECK_LE(offset_, command.Body().size());
if (offset_ < command.Body().size())
@@ -95,7 +97,12 @@ Result BytesConsumerTestUtil::ReplayingBytesConsumer::EndRead(size_t read) {
offset_ = 0;
commands_.pop_front();
- return Result::kOk;
+
+ if (name == Command::kData)
+ return Result::kOk;
+
+ Close();
+ return Result::kDone;
}
void BytesConsumerTestUtil::ReplayingBytesConsumer::SetClient(Client* client) {
diff --git a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h
index 17acda4e944..082093cf582 100644
--- a/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h
+++ b/chromium/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h
@@ -24,7 +24,7 @@ class BytesConsumerTestUtil {
class MockBytesConsumer : public BytesConsumer {
public:
static MockBytesConsumer* Create() {
- return new testing::StrictMock<MockBytesConsumer>();
+ return MakeGarbageCollected<testing::StrictMock<MockBytesConsumer>>();
}
MOCK_METHOD2(BeginRead, Result(const char**, size_t*));
@@ -51,7 +51,8 @@ class BytesConsumerTestUtil {
public:
static testing::StrictMock<MockFetchDataLoaderClient>* Create() {
- return new testing::StrictMock<MockFetchDataLoaderClient>;
+ return MakeGarbageCollected<
+ testing::StrictMock<MockFetchDataLoaderClient>>();
}
void Trace(blink::Visitor* visitor) override {
@@ -89,6 +90,7 @@ class BytesConsumerTestUtil {
kDone,
kError,
kWait,
+ kDataAndDone,
};
explicit Command(Name name) : name_(name) {}
diff --git a/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc
index 6f7b6080b58..832bc0d125f 100644
--- a/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
@@ -39,7 +40,7 @@ DataPipeBytesConsumer::DataPipeBytesConsumer(
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
execution_context->GetTaskRunner(TaskType::kNetworking)) {
DCHECK(data_pipe_.is_valid());
- *notifier = new CompletionNotifier(this);
+ *notifier = MakeGarbageCollected<CompletionNotifier>(this);
watcher_.Watch(
data_pipe_.get(),
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
@@ -96,7 +97,7 @@ BytesConsumer::Result DataPipeBytesConsumer::EndRead(size_t read) {
DCHECK(is_in_two_phase_read_);
is_in_two_phase_read_ = false;
DCHECK(IsReadableOrWaiting());
- MojoResult rv = data_pipe_->EndReadData(read);
+ MojoResult rv = data_pipe_->EndReadData(SafeCast<uint32_t>(read));
if (rv != MOJO_RESULT_OK) {
SetError(Error("error"));
return Result::kError;
diff --git a/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer_test.cc
index 843a98e6500..ac21f5dcebe 100644
--- a/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer_test.cc
@@ -33,10 +33,12 @@ TEST_F(DataPipeBytesConsumerTest, TwoPhaseRead) {
pipe.producer_handle.reset();
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
notifier->SignalComplete();
- auto result = (new BytesConsumerTestUtil::TwoPhaseReader(consumer))->Run();
+ auto result =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(consumer))
+ ->Run();
EXPECT_EQ(Result::kDone, result.first);
EXPECT_EQ(
kData,
@@ -58,14 +60,16 @@ TEST_F(DataPipeBytesConsumerTest, TwoPhaseRead_SignalError) {
pipe.producer_handle.reset();
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
// Then explicitly signal an error. This should override the pipe completion
// and result in kError.
notifier->SignalError(BytesConsumer::Error());
- auto result = (new BytesConsumerTestUtil::TwoPhaseReader(consumer))->Run();
+ auto result =
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(consumer))
+ ->Run();
EXPECT_EQ(Result::kError, result.first);
EXPECT_TRUE(result.second.IsEmpty());
}
@@ -78,7 +82,7 @@ TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeComplete) {
ASSERT_TRUE(pipe.producer_handle.is_valid());
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -106,7 +110,7 @@ TEST_F(DataPipeBytesConsumerTest, CompleteBeforeEndOfPipe) {
ASSERT_TRUE(pipe.producer_handle.is_valid());
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -137,7 +141,7 @@ TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeError) {
ASSERT_TRUE(pipe.producer_handle.is_valid());
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -165,7 +169,7 @@ TEST_F(DataPipeBytesConsumerTest, ErrorBeforeEndOfPipe) {
ASSERT_TRUE(pipe.producer_handle.is_valid());
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -195,7 +199,7 @@ TEST_F(DataPipeBytesConsumerTest, DrainPipeBeforeComplete) {
ASSERT_TRUE(pipe.producer_handle.is_valid());
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -225,7 +229,7 @@ TEST_F(DataPipeBytesConsumerTest, CompleteBeforeDrainPipe) {
ASSERT_TRUE(pipe.producer_handle.is_valid());
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
- DataPipeBytesConsumer* consumer = new DataPipeBytesConsumer(
+ DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
&GetDocument(), std::move(pipe.consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
index 01df3bd6def..877c0ad1058 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
@@ -630,29 +630,30 @@ class FetchDataLoaderAsDataPipe final : public FetchDataLoader,
FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle(
const String& mime_type) {
- return new FetchDataLoaderAsBlobHandle(mime_type);
+ return MakeGarbageCollected<FetchDataLoaderAsBlobHandle>(mime_type);
}
FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() {
- return new FetchDataLoaderAsArrayBuffer();
+ return MakeGarbageCollected<FetchDataLoaderAsArrayBuffer>();
}
FetchDataLoader* FetchDataLoader::CreateLoaderAsFailure() {
- return new FetchDataLoaderAsFailure();
+ return MakeGarbageCollected<FetchDataLoaderAsFailure>();
}
FetchDataLoader* FetchDataLoader::CreateLoaderAsFormData(
const String& multipartBoundary) {
- return new FetchDataLoaderAsFormData(multipartBoundary);
+ return MakeGarbageCollected<FetchDataLoaderAsFormData>(multipartBoundary);
}
FetchDataLoader* FetchDataLoader::CreateLoaderAsString() {
- return new FetchDataLoaderAsString();
+ return MakeGarbageCollected<FetchDataLoaderAsString>();
}
FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- return new FetchDataLoaderAsDataPipe(std::move(task_runner));
+ return MakeGarbageCollected<FetchDataLoaderAsDataPipe>(
+ std::move(task_runner));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.h b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.h
index f8cafb75b57..220ab82e1d6 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.h
@@ -21,12 +21,12 @@ class FormData;
// FetchDataLoader subclasses
// 1. take a BytesConsumer,
// 2. read all data, and
-// 3. call either didFetchDataLoaded...() on success or
-// difFetchDataLoadFailed() otherwise
+// 3. call either DidFetchDataLoaded...() on success or
+// DidFetchDataLoadFailed() otherwise
// on the thread where FetchDataLoader is created.
//
-// - Client's methods can be called synchronously in start().
-// - If FetchDataLoader::cancel() is called, Client's methods will not be
+// - Client's methods can be called synchronously in Start().
+// - If FetchDataLoader::Cancel() is called, Client's methods will not be
// called anymore.
class CORE_EXPORT FetchDataLoader
: public GarbageCollectedFinalized<FetchDataLoader> {
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
index 783bfce4c9b..65e9f6f1e01 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/core/fetch/fetch_data_loader.h"
#include <memory>
+
+#include "base/stl_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle.h"
@@ -55,7 +57,7 @@ constexpr char kQuickBrownFoxFormData[] =
"Quick brown fox\r\n"
"--boundary--\r\n";
constexpr size_t kQuickBrownFoxFormDataLength =
- arraysize(kQuickBrownFoxFormData) - 1u;
+ base::size(kQuickBrownFoxFormData) - 1u;
TEST(FetchDataLoaderTest, LoadAsBlob) {
Checkpoint checkpoint;
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
index 8ebaecb375f..4adad478587 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
#include <utility>
+
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -23,7 +25,7 @@ TEST(FetchHeaderListTest, Append) {
std::make_pair("ConTenT-TyPe", "application/xml"),
std::make_pair("ConTenT-TyPe", "foo"), std::make_pair("X-Foo", "bar"),
};
- EXPECT_EQ(arraysize(expectedHeaders), headerList->size());
+ EXPECT_EQ(base::size(expectedHeaders), headerList->size());
size_t i = 0;
for (const auto& header : headerList->List()) {
EXPECT_EQ(expectedHeaders[i].first, header.first);
@@ -46,7 +48,7 @@ TEST(FetchHeaderListTest, Set) {
std::make_pair("some-header", "some value"),
std::make_pair("X-Foo", "bar"),
};
- EXPECT_EQ(arraysize(expectedHeaders), headerList->size());
+ EXPECT_EQ(base::size(expectedHeaders), headerList->size());
size_t i = 0;
for (const auto& header : headerList->List()) {
EXPECT_EQ(expectedHeaders[i].first, header.first);
@@ -68,7 +70,7 @@ TEST(FetchHeaderListTest, Erase) {
const std::pair<String, String> expectedHeaders[] = {
std::make_pair("X-Foo", "bar"),
};
- EXPECT_EQ(arraysize(expectedHeaders), headerList->size());
+ EXPECT_EQ(base::size(expectedHeaders), headerList->size());
size_t i = 0;
for (const auto& header : headerList->List()) {
EXPECT_EQ(expectedHeaders[i].first, header.first);
@@ -113,7 +115,7 @@ TEST(FetchHeaderListTest, SortAndCombine) {
std::make_pair("x-foo", "bar")};
const Vector<FetchHeaderList::Header> sortedAndCombined =
headerList->SortAndCombine();
- EXPECT_EQ(arraysize(expectedHeaders), sortedAndCombined.size());
+ EXPECT_EQ(base::size(expectedHeaders), sortedAndCombined.size());
size_t i = 0;
for (const auto& headerPair : headerList->SortAndCombine()) {
EXPECT_EQ(expectedHeaders[i].first, headerPair.first);
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
index c14847a8eb6..f97dcf9383f 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fetch/body.h"
#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
+#include "third_party/blink/renderer/core/fetch/buffering_bytes_consumer.h"
#include "third_party/blink/renderer/core/fetch/bytes_consumer.h"
#include "third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle.h"
#include "third_party/blink/renderer/core/fetch/fetch_request_data.h"
@@ -455,15 +456,15 @@ void FetchManager::Loader::DidReceiveResponse(
DCHECK(handle);
// TODO(horo): This check could be false when we will use the response url
// in service worker responses. (crbug.com/553535)
- DCHECK(response.Url() == url_list_.back());
+ DCHECK(response.CurrentRequestUrl() == url_list_.back());
ScriptState* script_state = resolver_->GetScriptState();
ScriptState::Scope scope(script_state);
response_http_status_code_ = response.HttpStatusCode();
FetchRequestData::Tainting tainting = fetch_request_data_->ResponseTainting();
- if (response.Url().ProtocolIsData()) {
- if (fetch_request_data_->Url() == response.Url()) {
+ if (response.CurrentRequestUrl().ProtocolIsData()) {
+ if (fetch_request_data_->Url() == response.CurrentRequestUrl()) {
// A direct request to data.
tainting = FetchRequestData::kBasicTainting;
} else {
@@ -487,7 +488,7 @@ void FetchManager::Loader::DidReceiveResponse(
return;
}
}
- } else if (!SecurityOrigin::Create(response.Url())
+ } else if (!SecurityOrigin::Create(response.CurrentRequestUrl())
->IsSameSchemeHostPort(fetch_request_data_->Origin().get())) {
// Recompute the tainting if the request was redirected to a different
// origin.
@@ -534,19 +535,32 @@ void FetchManager::Loader::DidReceiveResponse(
FetchResponseData* response_data = nullptr;
SRIBytesConsumer* sri_consumer = nullptr;
if (fetch_request_data_->Integrity().IsEmpty()) {
- response_data = FetchResponseData::CreateWithBuffer(new BodyStreamBuffer(
- script_state,
- new BytesConsumerForDataConsumerHandle(
- ExecutionContext::From(script_state), std::move(handle)),
- signal_));
+ BytesConsumer* bytes_consumer =
+ MakeGarbageCollected<BytesConsumerForDataConsumerHandle>(
+ GetExecutionContext(), std::move(handle));
+ if (!response.CacheControlContainsNoStore()) {
+ // BufferingBytesConsumer reads chunks from |bytes_consumer| as soon as
+ // they get available to relieve backpressure.
+ //
+ // https://fetch.spec.whatwg.org/#fetching
+ // The user agent should ignore the suspension request if the ongoing
+ // fetch is updating the response in the HTTP cache for the request.
+ bytes_consumer =
+ MakeGarbageCollected<BufferingBytesConsumer>(bytes_consumer);
+ }
+ response_data = FetchResponseData::CreateWithBuffer(
+ MakeGarbageCollected<BodyStreamBuffer>(script_state, bytes_consumer,
+ signal_));
} else {
- sri_consumer = new SRIBytesConsumer();
+ sri_consumer = MakeGarbageCollected<SRIBytesConsumer>();
response_data = FetchResponseData::CreateWithBuffer(
- new BodyStreamBuffer(script_state, sri_consumer, signal_));
+ MakeGarbageCollected<BodyStreamBuffer>(script_state, sri_consumer,
+ signal_));
}
response_data->SetStatus(response.HttpStatusCode());
- if (response.Url().ProtocolIsAbout() || response.Url().ProtocolIsData() ||
- response.Url().ProtocolIs("blob")) {
+ if (response.CurrentRequestUrl().ProtocolIsAbout() ||
+ response.CurrentRequestUrl().ProtocolIsData() ||
+ response.CurrentRequestUrl().ProtocolIs("blob")) {
response_data->SetStatusMessage("OK");
} else {
response_data->SetStatusMessage(response.HttpStatusText());
@@ -554,18 +568,31 @@ void FetchManager::Loader::DidReceiveResponse(
for (auto& it : response.HttpHeaderFields())
response_data->HeaderList()->Append(it.key, it.value);
+
+ // Corresponds to https://fetch.spec.whatwg.org/#main-fetch step:
+ // "If |internalResponse|’s URL list is empty, then set it to a clone of
+ // |request|’s URL list."
if (response.UrlListViaServiceWorker().IsEmpty()) {
- // Note: |urlListViaServiceWorker| is empty, unless the response came from a
- // service worker, in which case it will only be empty if it was created
- // through MakeGarbageCollected<Response>().
+ // Note: |UrlListViaServiceWorker()| is empty, unless the response came from
+ // a service worker, in which case it will only be empty if it was created
+ // through new Response().
response_data->SetURLList(url_list_);
} else {
DCHECK(response.WasFetchedViaServiceWorker());
response_data->SetURLList(response.UrlListViaServiceWorker());
}
+
response_data->SetMIMEType(response.MimeType());
response_data->SetResponseTime(response.ResponseTime());
+ if (response.WasCached()) {
+ response_data->SetResponseSource(
+ network::mojom::FetchResponseSource::kHttpCache);
+ } else if (!response.WasFetchedViaServiceWorker()) {
+ response_data->SetResponseSource(
+ network::mojom::FetchResponseSource::kNetwork);
+ }
+
FetchResponseData* tainted_response = nullptr;
DCHECK(!(network_utils::IsRedirectResponseCode(response_http_status_code_) &&
@@ -604,7 +631,7 @@ void FetchManager::Loader::DidReceiveResponse(
DCHECK(!integrity_verifier_);
integrity_verifier_ = MakeGarbageCollected<SRIVerifier>(
std::move(handle), sri_consumer, r, this,
- fetch_request_data_->Integrity(), response.Url(),
+ fetch_request_data_->Integrity(), response.CurrentRequestUrl(),
r->GetResponse()->GetType(),
resolver_->GetExecutionContext()->GetTaskRunner(TaskType::kNetworking));
}
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc
index 28ef8e1a34c..8eca9b7e213 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc
@@ -35,17 +35,11 @@ FetchRequestData* FetchRequestData::Create(
it != web_request.Headers().end(); ++it)
request->header_list_->Append(it->key, it->value);
if (scoped_refptr<EncodedFormData> body = web_request.Body()) {
- request->SetBuffer(new BodyStreamBuffer(
+ request->SetBuffer(MakeGarbageCollected<BodyStreamBuffer>(
script_state,
MakeGarbageCollected<FormDataBytesConsumer>(
ExecutionContext::From(script_state), std::move(body)),
nullptr /* AbortSignal */));
- } else if (web_request.GetBlobDataHandle()) {
- request->SetBuffer(new BodyStreamBuffer(
- script_state,
- new BlobBytesConsumer(ExecutionContext::From(script_state),
- web_request.GetBlobDataHandle()),
- nullptr /* AbortSignal */));
}
request->SetContext(web_request.GetRequestContext());
request->SetReferrerString(web_request.ReferrerUrl().GetString());
@@ -78,10 +72,10 @@ FetchRequestData* FetchRequestData::Create(
request->header_list_->Append(pair.key, pair.value);
}
if (fetch_api_request.blob) {
- request->SetBuffer(new BodyStreamBuffer(
+ request->SetBuffer(MakeGarbageCollected<BodyStreamBuffer>(
script_state,
- new BlobBytesConsumer(ExecutionContext::From(script_state),
- fetch_api_request.blob),
+ MakeGarbageCollected<BlobBytesConsumer>(
+ ExecutionContext::From(script_state), fetch_api_request.blob),
nullptr /* AbortSignal */));
}
request->SetContext(fetch_api_request.request_context_type);
@@ -150,8 +144,8 @@ FetchRequestData* FetchRequestData::Pass(ScriptState* script_state,
FetchRequestData* request = FetchRequestData::CloneExceptBody();
if (buffer_) {
request->buffer_ = buffer_;
- buffer_ = new BodyStreamBuffer(script_state, BytesConsumer::CreateClosed(),
- nullptr /* AbortSignal */);
+ buffer_ = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state, BytesConsumer::CreateClosed(), nullptr /* AbortSignal */);
buffer_->CloseAndLockAndDisturb(exception_state);
if (exception_state.HadException())
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h
index 1db691f0d02..52cb6ff4d70 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h
@@ -11,7 +11,7 @@
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index cdd01b31e69..28cc7d23562 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
using Type = network::mojom::FetchResponseType;
+using ResponseSource = network::mojom::FetchResponseSource;
namespace blink {
@@ -45,15 +46,16 @@ FetchResponseData* FetchResponseData::Create() {
// "Unless stated otherwise, a response's url is null, status is 200, status
// message is the empty byte sequence, header list is an empty header list,
// and body is null."
- return MakeGarbageCollected<FetchResponseData>(Type::kDefault, 200,
- g_empty_atom);
+ return MakeGarbageCollected<FetchResponseData>(
+ Type::kDefault, ResponseSource::kUnspecified, 200, g_empty_atom);
}
FetchResponseData* FetchResponseData::CreateNetworkErrorResponse() {
// "A network error is a response whose status is always 0, status message
// is always the empty byte sequence, header list is aways an empty list,
// and body is always null."
- return MakeGarbageCollected<FetchResponseData>(Type::kError, 0, g_empty_atom);
+ return MakeGarbageCollected<FetchResponseData>(
+ Type::kError, ResponseSource::kUnspecified, 0, g_empty_atom);
}
FetchResponseData* FetchResponseData::CreateWithBuffer(
@@ -69,7 +71,7 @@ FetchResponseData* FetchResponseData::CreateBasicFilteredResponse() const {
// header list excludes any headers in internal response's header list whose
// name is `Set-Cookie` or `Set-Cookie2`."
FetchResponseData* response = MakeGarbageCollected<FetchResponseData>(
- Type::kBasic, status_, status_message_);
+ Type::kBasic, response_source_, status_, status_message_);
response->SetURLList(url_list_);
for (const auto& header : header_list_->List()) {
if (FetchUtils::IsForbiddenResponseHeaderName(header.first))
@@ -93,7 +95,7 @@ FetchResponseData* FetchResponseData::CreateCorsFilteredResponse(
// parsing `Access-Control-Expose-Headers` in internal response's header
// list."
FetchResponseData* response = MakeGarbageCollected<FetchResponseData>(
- Type::kCors, status_, status_message_);
+ Type::kCors, response_source_, status_, status_message_);
response->SetURLList(url_list_);
for (const auto& header : header_list_->List()) {
const String& name = header.first;
@@ -118,8 +120,8 @@ FetchResponseData* FetchResponseData::CreateOpaqueFilteredResponse() const {
// cache state is 'none'."
//
// https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
- FetchResponseData* response =
- MakeGarbageCollected<FetchResponseData>(Type::kOpaque, 0, g_empty_atom);
+ FetchResponseData* response = MakeGarbageCollected<FetchResponseData>(
+ Type::kOpaque, response_source_, 0, g_empty_atom);
response->internal_response_ = const_cast<FetchResponseData*>(this);
return response;
}
@@ -133,7 +135,7 @@ FetchResponseData* FetchResponseData::CreateOpaqueRedirectFilteredResponse()
//
// https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect
FetchResponseData* response = MakeGarbageCollected<FetchResponseData>(
- Type::kOpaqueRedirect, 0, g_empty_atom);
+ Type::kOpaqueRedirect, response_source_, 0, g_empty_atom);
response->SetURLList(url_list_);
response->internal_response_ = const_cast<FetchResponseData*>(this);
return response;
@@ -180,6 +182,7 @@ FetchResponseData* FetchResponseData::Clone(ScriptState* script_state,
ExceptionState& exception_state) {
FetchResponseData* new_response = Create();
new_response->type_ = type_;
+ new_response->response_source_ = response_source_;
if (termination_reason_) {
new_response->termination_reason_ = std::make_unique<TerminationReason>();
*new_response->termination_reason_ = *termination_reason_;
@@ -242,6 +245,7 @@ void FetchResponseData::PopulateWebServiceWorkerResponse(
if (internal_response_) {
internal_response_->PopulateWebServiceWorkerResponse(response);
response.SetResponseType(type_);
+ response.SetResponseSource(response_source_);
response.SetCorsExposedHeaderNames(
HeaderSetToWebVector(cors_exposed_header_names_));
return;
@@ -250,6 +254,7 @@ void FetchResponseData::PopulateWebServiceWorkerResponse(
response.SetStatus(Status());
response.SetStatusText(StatusMessage());
response.SetResponseType(type_);
+ response.SetResponseSource(response_source_);
response.SetResponseTime(ResponseTime());
response.SetCacheStorageCacheName(CacheStorageCacheName());
response.SetCorsExposedHeaderNames(
@@ -265,6 +270,7 @@ FetchResponseData::PopulateFetchAPIResponse() {
mojom::blink::FetchAPIResponsePtr response =
internal_response_->PopulateFetchAPIResponse();
response->response_type = type_;
+ response->response_source = response_source_;
response->cors_exposed_header_names =
HeaderSetToVector(cors_exposed_header_names_);
return response;
@@ -275,6 +281,7 @@ FetchResponseData::PopulateFetchAPIResponse() {
response->status_code = status_;
response->status_text = status_message_;
response->response_type = type_;
+ response->response_source = response_source_;
response->response_time = response_time_;
response->cache_storage_cache_name = cache_storage_cache_name_;
response->cors_exposed_header_names =
@@ -285,9 +292,11 @@ FetchResponseData::PopulateFetchAPIResponse() {
}
FetchResponseData::FetchResponseData(Type type,
+ network::mojom::FetchResponseSource source,
unsigned short status,
AtomicString status_message)
: type_(type),
+ response_source_(source),
status_(status),
status_message_(status_message),
header_list_(FetchHeaderList::Create()),
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
index d1116775c9a..319d7b9efdf 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -10,8 +10,8 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
#include "third_party/blink/public/platform/web_http_header_set.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -45,6 +45,7 @@ class CORE_EXPORT FetchResponseData final
static FetchResponseData* CreateWithBuffer(BodyStreamBuffer*);
FetchResponseData(network::mojom::FetchResponseType,
+ network::mojom::FetchResponseSource,
unsigned short,
AtomicString);
@@ -62,6 +63,9 @@ class CORE_EXPORT FetchResponseData final
FetchResponseData* Clone(ScriptState*, ExceptionState& exception_state);
network::mojom::FetchResponseType GetType() const { return type_; }
+ network::mojom::FetchResponseSource ResponseSource() const {
+ return response_source_;
+ }
const KURL* Url() const;
unsigned short Status() const { return status_; }
AtomicString StatusMessage() const { return status_message_; }
@@ -78,6 +82,9 @@ class CORE_EXPORT FetchResponseData final
return cors_exposed_header_names_;
}
+ void SetResponseSource(network::mojom::FetchResponseSource response_source) {
+ response_source_ = response_source;
+ }
void SetURLList(const Vector<KURL>&);
const Vector<KURL>& UrlList() const { return url_list_; }
const Vector<KURL>& InternalURLList() const;
@@ -111,6 +118,7 @@ class CORE_EXPORT FetchResponseData final
private:
network::mojom::FetchResponseType type_;
+ network::mojom::FetchResponseSource response_source_;
std::unique_ptr<TerminationReason> termination_reason_;
Vector<KURL> url_list_;
unsigned short status_;
diff --git a/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
index 6561f1c4e80..418f9160823 100644
--- a/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -159,8 +159,8 @@ class DataPipeAndDataBytesConsumer final : public BytesConsumer {
if (!simple_consumer_) {
scoped_refptr<EncodedFormData> simple_data =
EncodedFormData::Create(iter_->data_);
- simple_consumer_ =
- new SimpleFormDataBytesConsumer(std::move(simple_data));
+ simple_consumer_ = MakeGarbageCollected<SimpleFormDataBytesConsumer>(
+ std::move(simple_data));
if (client_)
simple_consumer_->SetClient(client_);
}
@@ -201,7 +201,7 @@ class DataPipeAndDataBytesConsumer final : public BytesConsumer {
WrapWeakPersistent(this)));
DataPipeBytesConsumer::CompletionNotifier* completion_notifier =
nullptr;
- data_pipe_consumer_ = new DataPipeBytesConsumer(
+ data_pipe_consumer_ = MakeGarbageCollected<DataPipeBytesConsumer>(
execution_context_, std::move(pipe_consumer_handle),
&completion_notifier);
completion_notifier_ = completion_notifier;
@@ -435,7 +435,7 @@ class ComplexFormDataBytesConsumer final : public BytesConsumer {
blob_data->SetContentType(AtomicString("multipart/form-data; boundary=") +
form_data_->Boundary().data());
auto size = blob_data->length();
- blob_bytes_consumer_ = new BlobBytesConsumer(
+ blob_bytes_consumer_ = MakeGarbageCollected<BlobBytesConsumer>(
execution_context, BlobDataHandle::Create(std::move(blob_data), size));
}
@@ -491,8 +491,9 @@ class ComplexFormDataBytesConsumer final : public BytesConsumer {
} // namespace
FormDataBytesConsumer::FormDataBytesConsumer(const String& string)
- : impl_(new SimpleFormDataBytesConsumer(EncodedFormData::Create(
- UTF8Encoding().Encode(string, WTF::kNoUnencodables)))) {}
+ : impl_(MakeGarbageCollected<SimpleFormDataBytesConsumer>(
+ EncodedFormData::Create(
+ UTF8Encoding().Encode(string, WTF::kNoUnencodables)))) {}
FormDataBytesConsumer::FormDataBytesConsumer(DOMArrayBuffer* buffer)
: FormDataBytesConsumer(buffer->Data(), buffer->ByteLength()) {}
@@ -501,7 +502,7 @@ FormDataBytesConsumer::FormDataBytesConsumer(DOMArrayBufferView* view)
: FormDataBytesConsumer(view->BaseAddress(), view->byteLength()) {}
FormDataBytesConsumer::FormDataBytesConsumer(const void* data, wtf_size_t size)
- : impl_(new SimpleFormDataBytesConsumer(
+ : impl_(MakeGarbageCollected<SimpleFormDataBytesConsumer>(
EncodedFormData::Create(data, size))) {}
FormDataBytesConsumer::FormDataBytesConsumer(
@@ -525,13 +526,14 @@ BytesConsumer* FormDataBytesConsumer::GetImpl(
DCHECK(form_data);
switch (GetType(form_data.get())) {
case FormDataType::kSimple:
- return new SimpleFormDataBytesConsumer(std::move(form_data));
+ return MakeGarbageCollected<SimpleFormDataBytesConsumer>(
+ std::move(form_data));
case FormDataType::kComplex:
- return new ComplexFormDataBytesConsumer(
+ return MakeGarbageCollected<ComplexFormDataBytesConsumer>(
execution_context, std::move(form_data), consumer_for_testing);
case FormDataType::kDataPipeAndDataOnly:
- return new DataPipeAndDataBytesConsumer(execution_context,
- form_data.get());
+ return MakeGarbageCollected<DataPipeAndDataBytesConsumer>(
+ execution_context, form_data.get());
}
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
index 0fa2fc170aa..dadbfd407c4 100644
--- a/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h"
#include "base/memory/scoped_refptr.h"
+#include "base/stl_util.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/system/data_pipe_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -127,7 +128,7 @@ class FormDataBytesConsumerTest : public PageTestBase {
TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromString) {
auto result =
- (new BytesConsumerTestUtil::TwoPhaseReader(
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(
MakeGarbageCollected<FormDataBytesConsumer>("hello, world")))
->Run();
EXPECT_EQ(Result::kDone, result.first);
@@ -137,7 +138,7 @@ TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromString) {
TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromStringNonLatin) {
constexpr UChar kCs[] = {0x3042, 0};
- auto result = (new BytesConsumerTestUtil::TwoPhaseReader(
+ auto result = (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(
MakeGarbageCollected<FormDataBytesConsumer>(String(kCs))))
->Run();
EXPECT_EQ(Result::kDone, result.first);
@@ -148,12 +149,12 @@ TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromStringNonLatin) {
TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromArrayBuffer) {
constexpr unsigned char kData[] = {0x21, 0xfe, 0x00, 0x00, 0xff, 0xa3,
0x42, 0x30, 0x42, 0x99, 0x88};
- DOMArrayBuffer* buffer = DOMArrayBuffer::Create(kData, arraysize(kData));
- auto result = (new BytesConsumerTestUtil::TwoPhaseReader(
+ DOMArrayBuffer* buffer = DOMArrayBuffer::Create(kData, base::size(kData));
+ auto result = (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(
MakeGarbageCollected<FormDataBytesConsumer>(buffer)))
->Run();
Vector<char> expected;
- expected.Append(kData, arraysize(kData));
+ expected.Append(kData, base::size(kData));
EXPECT_EQ(Result::kDone, result.first);
EXPECT_EQ(expected, result.second);
@@ -163,8 +164,8 @@ TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromArrayBufferView) {
constexpr unsigned char kData[] = {0x21, 0xfe, 0x00, 0x00, 0xff, 0xa3,
0x42, 0x30, 0x42, 0x99, 0x88};
constexpr size_t kOffset = 1, kSize = 4;
- DOMArrayBuffer* buffer = DOMArrayBuffer::Create(kData, arraysize(kData));
- auto result = (new BytesConsumerTestUtil::TwoPhaseReader(
+ DOMArrayBuffer* buffer = DOMArrayBuffer::Create(kData, base::size(kData));
+ auto result = (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(
MakeGarbageCollected<FormDataBytesConsumer>(
DOMUint8Array::Create(buffer, kOffset, kSize))))
->Run();
@@ -181,7 +182,7 @@ TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromSimpleFormData) {
data->AppendData("hoge", 4);
auto result =
- (new BytesConsumerTestUtil::TwoPhaseReader(
+ (MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(
MakeGarbageCollected<FormDataBytesConsumer>(&GetDocument(), data)))
->Run();
EXPECT_EQ(Result::kDone, result.first);
@@ -426,7 +427,7 @@ TEST_F(FormDataBytesConsumerTest, SetClientWithComplexFormData) {
EXPECT_CALL(checkpoint, Call(3));
checkpoint.Call(1);
- consumer->SetClient(new NoopClient());
+ consumer->SetClient(MakeGarbageCollected<NoopClient>());
checkpoint.Call(2);
consumer->ClearClient();
checkpoint.Call(3);
@@ -455,7 +456,8 @@ TEST_F(FormDataBytesConsumerTest, DataPipeFormData) {
scoped_refptr<EncodedFormData> input_form_data = DataPipeFormData();
auto* consumer = MakeGarbageCollected<FormDataBytesConsumer>(&GetDocument(),
input_form_data);
- auto* reader = new BytesConsumerTestUtil::TwoPhaseReader(consumer);
+ auto* reader =
+ MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(consumer);
std::pair<BytesConsumer::Result, Vector<char>> result = reader->Run();
EXPECT_EQ(Result::kDone, result.first);
EXPECT_EQ("foo hello world here's another data pipe bar baz",
@@ -496,7 +498,8 @@ TEST_F(FormDataBytesConsumerTest,
EXPECT_EQ(BytesConsumer::Result::kOk, consumer->EndRead(available));
// The consumer should still be readable. Finish reading.
- auto* reader = new BytesConsumerTestUtil::TwoPhaseReader(consumer);
+ auto* reader =
+ MakeGarbageCollected<BytesConsumerTestUtil::TwoPhaseReader>(consumer);
std::pair<BytesConsumer::Result, Vector<char>> result = reader->Run();
EXPECT_EQ(Result::kDone, result.first);
EXPECT_EQ(" hello world here's another data pipe bar baz",
diff --git a/chromium/third_party/blink/renderer/core/fetch/global_fetch.cc b/chromium/third_party/blink/renderer/core/fetch/global_fetch.cc
index c152c1d5d23..0d474ed8097 100644
--- a/chromium/third_party/blink/renderer/core/fetch/global_fetch.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/global_fetch.cc
@@ -34,12 +34,15 @@ class GlobalFetchImpl final
GlobalFetchImpl* supplement =
Supplement<T>::template From<GlobalFetchImpl>(supplementable);
if (!supplement) {
- supplement = new GlobalFetchImpl(execution_context);
+ supplement = MakeGarbageCollected<GlobalFetchImpl>(execution_context);
Supplement<T>::ProvideTo(supplementable, supplement);
}
return supplement;
}
+ explicit GlobalFetchImpl(ExecutionContext* execution_context)
+ : fetch_manager_(FetchManager::Create(execution_context)) {}
+
ScriptPromise Fetch(ScriptState* script_state,
const RequestInfo& input,
const RequestInit* init,
@@ -78,9 +81,6 @@ class GlobalFetchImpl final
}
private:
- explicit GlobalFetchImpl(ExecutionContext* execution_context)
- : fetch_manager_(FetchManager::Create(execution_context)) {}
-
Member<FetchManager> fetch_manager_;
};
diff --git a/chromium/third_party/blink/renderer/core/fetch/headers.cc b/chromium/third_party/blink/renderer/core/fetch/headers.cc
index 1dd5e6a61e6..63a499a9056 100644
--- a/chromium/third_party/blink/renderer/core/fetch/headers.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/headers.cc
@@ -97,11 +97,26 @@ void Headers::append(const String& name,
// name, return."
if (guard_ == kRequestGuard && cors::IsForbiddenHeaderName(name))
return;
- // "5. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
- // no-CORS-safelisted header, return."
- if (guard_ == kRequestNoCorsGuard &&
- !cors::IsNoCorsSafelistedHeader(name, normalized_value)) {
- return;
+ // 5. Otherwise, if guard is |request-no-cors|:
+ if (guard_ == kRequestNoCorsGuard) {
+ // Let |temporaryValue| be the result of getting name from |headers|’s
+ // header list.
+ String temp;
+ header_list_->Get(name, temp);
+
+ // If |temporaryValue| is null, then set |temporaryValue| to |value|.
+ // Otherwise, set |temporaryValue| to |temporaryValue|, followed by
+ // 0x2C 0x20, followed by |value|.
+ if (temp.IsNull()) {
+ temp = normalized_value;
+ } else {
+ temp = temp + ", " + normalized_value;
+ }
+
+ // If |name|/|temporaryValue| is not a no-CORS-safelisted request-header,
+ // then return.
+ if (!cors::IsNoCorsSafelistedHeader(name, temp))
+ return;
}
// "6. Otherwise, if guard is |response| and |name| is a forbidden response
// header name, return."
@@ -129,10 +144,12 @@ void Headers::remove(const String& name, ExceptionState& exception_state) {
// name, return."
if (guard_ == kRequestGuard && cors::IsForbiddenHeaderName(name))
return;
- // "4. Otherwise, if guard is |request-no-CORS| and |name|/`invalid` is not
- // a no-CORS-safelisted header, return."
+ // "4. Otherwise, if the context object’s guard is |request-no-cors|, |name|
+ // is not a no-CORS-safelisted request-header name, and |name| is not a
+ // privileged no-CORS request-header name, return."
if (guard_ == kRequestNoCorsGuard &&
- !cors::IsNoCorsSafelistedHeader(name, "invalid")) {
+ !cors::IsNoCorsSafelistedHeaderName(name) &&
+ !cors::IsPrivilegedNoCorsHeaderName(name)) {
return;
}
// "5. Otherwise, if guard is |response| and |name| is a forbidden response
@@ -282,7 +299,7 @@ void Headers::Trace(blink::Visitor* visitor) {
PairIterable<String, String>::IterationSource* Headers::StartIteration(
ScriptState*,
ExceptionState&) {
- return new HeadersIterationSource(header_list_);
+ return MakeGarbageCollected<HeadersIterationSource>(header_list_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/multipart_parser.cc b/chromium/third_party/blink/renderer/core/fetch/multipart_parser.cc
index 4a3112319d9..4be2be009e1 100644
--- a/chromium/third_party/blink/renderer/core/fetch/multipart_parser.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/multipart_parser.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/fetch/multipart_parser.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -18,10 +19,10 @@ namespace {
constexpr char kCloseDelimiterSuffix[] = "--\r\n";
constexpr size_t kCloseDelimiterSuffixSize =
- arraysize(kCloseDelimiterSuffix) - 1u;
+ base::size(kCloseDelimiterSuffix) - 1u;
constexpr size_t kDashBoundaryOffset = 2u; // The length of "\r\n".
constexpr char kDelimiterSuffix[] = "\r\n";
-constexpr size_t kDelimiterSuffixSize = arraysize(kDelimiterSuffix) - 1u;
+constexpr size_t kDelimiterSuffixSize = base::size(kDelimiterSuffix) - 1u;
} // namespace
diff --git a/chromium/third_party/blink/renderer/core/fetch/multipart_parser_test.cc b/chromium/third_party/blink/renderer/core/fetch/multipart_parser_test.cc
index e1ad8a927ca..ec7d5e73eaf 100644
--- a/chromium/third_party/blink/renderer/core/fetch/multipart_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/multipart_parser_test.cc
@@ -72,7 +72,8 @@ TEST(MultipartParserTest, AppendDataInChunks) {
Vector<char> boundary;
boundary.Append("boundary", 8u);
for (const size_t size : sizes) {
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
@@ -117,7 +118,8 @@ TEST(MultipartParserTest, Epilogue) {
Vector<char> boundary;
boundary.Append("boundary", 8u);
for (size_t end : ends) {
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
@@ -160,7 +162,8 @@ TEST(MultipartParserTest, NoEndBoundary) {
Vector<char> boundary;
boundary.Append("boundary", 8u);
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
@@ -180,7 +183,8 @@ TEST(MultipartParserTest, NoStartBoundary) {
Vector<char> boundary;
boundary.Append("boundary", 8u);
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
@@ -194,7 +198,8 @@ TEST(MultipartParserTest, NoStartNorEndBoundary) {
Vector<char> boundary;
boundary.Append("boundary", 8u);
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
@@ -215,7 +220,8 @@ TEST(MultipartParserTest, Preamble) {
Vector<char> boundary;
boundary.Append("boundary", 8u);
for (const size_t start : kStarts) {
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
@@ -274,7 +280,8 @@ TEST(MultipartParserTest, PreambleWithMalformedBoundary) {
Vector<char> boundary;
boundary.Append("--boundary", 10u);
for (const size_t start : kStarts) {
- MockMultipartParserClient* client = new MockMultipartParserClient;
+ MockMultipartParserClient* client =
+ MakeGarbageCollected<MockMultipartParserClient>();
MultipartParser* parser =
MakeGarbageCollected<MultipartParser>(boundary, client);
diff --git a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
index bb43d5f1a1e..3f89e4bfbfb 100644
--- a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
@@ -130,7 +130,8 @@ BytesConsumer::Result ReadableStreamBytesConsumer::BeginRead(
DCHECK(!reader.IsEmpty());
ReadableStreamOperations::DefaultReaderRead(script_state_, reader)
.Then(OnFulfilled::CreateFunction(script_state_, this),
- OnRejected::CreateFunction(script_state_, this));
+ OnRejected::CreateFunction(script_state_, this))
+ .MarkAsHandled();
}
return Result::kShouldWait;
}
diff --git a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
index 8e7a529f8d0..7bdef5d9d27 100644
--- a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
@@ -34,12 +34,15 @@ class MockClient : public GarbageCollectedFinalized<MockClient>,
USING_GARBAGE_COLLECTED_MIXIN(MockClient);
public:
- static MockClient* Create() { return new StrictMock<MockClient>(); }
- MOCK_METHOD0(OnStateChange, void());
- String DebugName() const override { return "MockClient"; }
+ static MockClient* Create() {
+ return MakeGarbageCollected<StrictMock<MockClient>>();
+ }
MockClient() = default;
+ MOCK_METHOD0(OnStateChange, void());
+ String DebugName() const override { return "MockClient"; }
+
void Trace(blink::Visitor* visitor) override {}
};
diff --git a/chromium/third_party/blink/renderer/core/fetch/request.cc b/chromium/third_party/blink/renderer/core/fetch/request.cc
index e420f2d219e..b86e08c70e8 100644
--- a/chromium/third_party/blink/renderer/core/fetch/request.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/request.cc
@@ -25,8 +25,10 @@
#include "third_party/blink/renderer/core/fetch/request_init.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/url/url_search_params.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
@@ -101,16 +103,17 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
if (V8Blob::HasInstance(body, isolate)) {
Blob* blob = V8Blob::ToImpl(body.As<v8::Object>());
- return_buffer = new BodyStreamBuffer(
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state,
- new BlobBytesConsumer(execution_context, blob->GetBlobDataHandle()),
+ MakeGarbageCollected<BlobBytesConsumer>(execution_context,
+ blob->GetBlobDataHandle()),
nullptr /* AbortSignal */);
content_type = blob->type();
} else if (body->IsArrayBuffer()) {
// Avoid calling into V8 from the following constructor parameters, which
// is potentially unsafe.
DOMArrayBuffer* array_buffer = V8ArrayBuffer::ToImpl(body.As<v8::Object>());
- return_buffer = new BodyStreamBuffer(
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(array_buffer),
nullptr /* AbortSignal */);
} else if (body->IsArrayBufferView()) {
@@ -118,7 +121,7 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
// is potentially unsafe.
DOMArrayBufferView* array_buffer_view =
V8ArrayBufferView::ToImpl(body.As<v8::Object>());
- return_buffer = new BodyStreamBuffer(
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state,
MakeGarbageCollected<FormDataBytesConsumer>(array_buffer_view),
nullptr /* AbortSignal */);
@@ -129,19 +132,19 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
// FormDataEncoder::generateUniqueBoundaryString.
content_type = AtomicString("multipart/form-data; boundary=") +
form_data->Boundary().data();
- return_buffer =
- new BodyStreamBuffer(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */);
} else if (V8URLSearchParams::HasInstance(body, isolate)) {
scoped_refptr<EncodedFormData> form_data =
V8URLSearchParams::ToImpl(body.As<v8::Object>())->ToEncodedFormData();
- return_buffer =
- new BodyStreamBuffer(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */);
content_type = "application/x-www-form-urlencoded;charset=UTF-8";
} else {
String string = NativeValueTraits<IDLUSVString>::NativeValue(
@@ -149,7 +152,7 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
if (exception_state.HadException())
return nullptr;
- return_buffer = new BodyStreamBuffer(
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(string),
nullptr /* AbortSignal */);
content_type = "text/plain;charset=UTF-8";
@@ -381,9 +384,12 @@ Request* Request::CreateRequestWithRequestOrString(
// This is not yet standardized, but we can assume the following:
// "If |init|'s importance member is present, set |request|'s importance
// mode to it." For more information see Priority Hints at
- // https://crbug.com/821464
+ // https://crbug.com/821464.
DCHECK(init->importance().IsNull() ||
- RuntimeEnabledFeatures::PriorityHintsEnabled());
+ origin_trials::PriorityHintsEnabled(execution_context));
+ if (!init->importance().IsNull())
+ UseCounter::Count(execution_context, WebFeature::kPriorityHints);
+
if (init->importance() == "low") {
request->SetImportance(mojom::FetchImportanceMode::kImportanceLow);
} else if (init->importance() == "high") {
@@ -562,7 +568,7 @@ Request* Request::CreateRequestWithRequestOrString(
// non-null, run these substeps:"
if (input_request && input_request->BodyBuffer()) {
// "Let |dummyStream| be an empty ReadableStream object."
- auto* dummy_stream = new BodyStreamBuffer(
+ auto* dummy_stream = MakeGarbageCollected<BodyStreamBuffer>(
script_state, BytesConsumer::CreateClosed(), nullptr);
// "Set |input|'s request's body to a new body whose stream is
// |dummyStream|."
@@ -666,7 +672,8 @@ Request::Request(ScriptState* script_state, FetchRequestData* request)
: Request(script_state,
request,
Headers::Create(request->HeaderList()),
- new AbortSignal(ExecutionContext::From(script_state))) {
+ MakeGarbageCollected<AbortSignal>(
+ ExecutionContext::From(script_state))) {
headers_->SetGuard(Headers::kRequestGuard);
}
@@ -675,7 +682,7 @@ String Request::method() const {
return request_->Method();
}
-KURL Request::url() const {
+const KURL& Request::url() const {
return request_->Url();
}
@@ -873,7 +880,8 @@ Request* Request::clone(ScriptState* script_state,
return nullptr;
Headers* headers = Headers::Create(request->HeaderList());
headers->SetGuard(headers_->GetGuard());
- auto* signal = new AbortSignal(ExecutionContext::From(script_state));
+ auto* signal =
+ MakeGarbageCollected<AbortSignal>(ExecutionContext::From(script_state));
signal->Follow(signal_);
return MakeGarbageCollected<Request>(script_state, request, headers, signal);
}
diff --git a/chromium/third_party/blink/renderer/core/fetch/request.h b/chromium/third_party/blink/renderer/core/fetch/request.h
index e51937d1264..acb74c1afdb 100644
--- a/chromium/third_party/blink/renderer/core/fetch/request.h
+++ b/chromium/third_party/blink/renderer/core/fetch/request.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_REQUEST_H_
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
#include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
@@ -65,7 +65,7 @@ class CORE_EXPORT Request final : public Body {
// From Request.idl:
String method() const;
- KURL url() const;
+ const KURL& url() const;
Headers* getHeaders() const { return headers_; }
String destination() const;
String referrer() const;
diff --git a/chromium/third_party/blink/renderer/core/fetch/request_init.idl b/chromium/third_party/blink/renderer/core/fetch/request_init.idl
index 82e7336ae8e..267391de81a 100644
--- a/chromium/third_party/blink/renderer/core/fetch/request_init.idl
+++ b/chromium/third_party/blink/renderer/core/fetch/request_init.idl
@@ -21,7 +21,7 @@ dictionary RequestInit {
RequestRedirect redirect;
DOMString integrity;
boolean keepalive;
- [RuntimeEnabled=PriorityHints] RequestImportance importance;
+ [OriginTrialEnabled=PriorityHints] RequestImportance importance;
AbortSignal? signal;
// TODO(domfarolino): add support for RequestInit window member.
//any window; // can only be set to null
diff --git a/chromium/third_party/blink/renderer/core/fetch/request_test.cc b/chromium/third_party/blink/renderer/core/fetch/request_test.cc
index d5720fcfd56..59f18f1c145 100644
--- a/chromium/third_party/blink/renderer/core/fetch/request_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/request_test.cc
@@ -75,8 +75,10 @@ TEST(ServiceWorkerRequestTest, FromAndToFetchAPIRequest) {
fetch_api_request->cache_mode = kCacheMode;
fetch_api_request->redirect_mode = kRedirectMode;
fetch_api_request->request_context_type = kContext;
- for (int i = 0; headers[i].key; ++i)
- fetch_api_request->headers.insert(headers[i].key, headers[i].value);
+ for (int i = 0; headers[i].key; ++i) {
+ fetch_api_request->headers.insert(String(headers[i].key),
+ String(headers[i].value));
+ }
fetch_api_request->referrer =
mojom::blink::Referrer::New(KURL(NullURL(), referrer), kReferrerPolicy);
diff --git a/chromium/third_party/blink/renderer/core/fetch/response.cc b/chromium/third_party/blink/renderer/core/fetch/response.cc
index 8816b18ff17..3319dedc582 100644
--- a/chromium/third_party/blink/renderer/core/fetch/response.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/response.cc
@@ -86,6 +86,7 @@ FetchResponseData* CreateFetchResponseDataFromFetchAPIResponse(
else
response = FetchResponseData::CreateNetworkErrorResponse();
+ response->SetResponseSource(fetch_api_response.response_source);
response->SetURLList(fetch_api_response.url_list);
response->SetStatus(fetch_api_response.status_code);
response->SetStatusMessage(WTF::AtomicString(fetch_api_response.status_text));
@@ -97,10 +98,10 @@ FetchResponseData* CreateFetchResponseDataFromFetchAPIResponse(
response->HeaderList()->Append(header.key, header.value);
if (fetch_api_response.blob) {
- response->ReplaceBodyStreamBuffer(new BodyStreamBuffer(
+ response->ReplaceBodyStreamBuffer(MakeGarbageCollected<BodyStreamBuffer>(
script_state,
- new BlobBytesConsumer(ExecutionContext::From(script_state),
- fetch_api_response.blob),
+ MakeGarbageCollected<BlobBytesConsumer>(
+ ExecutionContext::From(script_state), fetch_api_response.blob),
nullptr /* AbortSignal */));
}
@@ -159,16 +160,17 @@ Response* Response::Create(ScriptState* script_state,
// https://crbug.com/335871.
} else if (V8Blob::HasInstance(body, isolate)) {
Blob* blob = V8Blob::ToImpl(body.As<v8::Object>());
- body_buffer = new BodyStreamBuffer(
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state,
- new BlobBytesConsumer(execution_context, blob->GetBlobDataHandle()),
+ MakeGarbageCollected<BlobBytesConsumer>(execution_context,
+ blob->GetBlobDataHandle()),
nullptr /* AbortSignal */);
content_type = blob->type();
} else if (body->IsArrayBuffer()) {
// Avoid calling into V8 from the following constructor parameters, which
// is potentially unsafe.
DOMArrayBuffer* array_buffer = V8ArrayBuffer::ToImpl(body.As<v8::Object>());
- body_buffer = new BodyStreamBuffer(
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(array_buffer),
nullptr /* AbortSignal */);
} else if (body->IsArrayBufferView()) {
@@ -176,7 +178,7 @@ Response* Response::Create(ScriptState* script_state,
// is potentially unsafe.
DOMArrayBufferView* array_buffer_view =
V8ArrayBufferView::ToImpl(body.As<v8::Object>());
- body_buffer = new BodyStreamBuffer(
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state,
MakeGarbageCollected<FormDataBytesConsumer>(array_buffer_view),
nullptr /* AbortSignal */);
@@ -187,31 +189,31 @@ Response* Response::Create(ScriptState* script_state,
// FormDataEncoder::generateUniqueBoundaryString.
content_type = AtomicString("multipart/form-data; boundary=") +
form_data->Boundary().data();
- body_buffer =
- new BodyStreamBuffer(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */);
} else if (V8URLSearchParams::HasInstance(body, isolate)) {
scoped_refptr<EncodedFormData> form_data =
V8URLSearchParams::ToImpl(body.As<v8::Object>())->ToEncodedFormData();
- body_buffer =
- new BodyStreamBuffer(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */);
content_type = "application/x-www-form-urlencoded;charset=UTF-8";
} else if (V8ReadableStream::HasInstance(body, isolate)) {
UseCounter::Count(execution_context,
WebFeature::kFetchResponseConstructionWithStream);
- body_buffer = new BodyStreamBuffer(
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state, V8ReadableStream::ToImpl(body.As<v8::Object>()));
} else {
String string = NativeValueTraits<IDLUSVString>::NativeValue(
isolate, body, exception_state);
if (exception_state.HadException())
return nullptr;
- body_buffer = new BodyStreamBuffer(
+ body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(string),
nullptr /* AbortSignal */);
content_type = "text/plain;charset=UTF-8";
diff --git a/chromium/third_party/blink/renderer/core/fetch/response_init.idl b/chromium/third_party/blink/renderer/core/fetch/response_init.idl
index 8dc8e0d5a79..ca291cb5990 100644
--- a/chromium/third_party/blink/renderer/core/fetch/response_init.idl
+++ b/chromium/third_party/blink/renderer/core/fetch/response_init.idl
@@ -6,6 +6,6 @@
dictionary ResponseInit {
unsigned short status = 200;
- ByteString statusText = "OK";
+ ByteString statusText = "";
HeadersInit headers;
};
diff --git a/chromium/third_party/blink/renderer/core/fetch/response_test.cc b/chromium/third_party/blink/renderer/core/fetch/response_test.cc
index 4bca9a8ba62..64b961850ff 100644
--- a/chromium/third_party/blink/renderer/core/fetch/response_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/response_test.cc
@@ -6,7 +6,7 @@
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -76,9 +76,9 @@ void CheckResponseStream(ScriptState* script_state,
EXPECT_FALSE(cloned_response->BodyBuffer());
}
BytesConsumerTestUtil::MockFetchDataLoaderClient* client1 =
- new BytesConsumerTestUtil::MockFetchDataLoaderClient();
+ MakeGarbageCollected<BytesConsumerTestUtil::MockFetchDataLoaderClient>();
BytesConsumerTestUtil::MockFetchDataLoaderClient* client2 =
- new BytesConsumerTestUtil::MockFetchDataLoaderClient();
+ MakeGarbageCollected<BytesConsumerTestUtil::MockFetchDataLoaderClient>();
EXPECT_CALL(*client1, DidFetchDataLoadedString(String("Hello, world")));
EXPECT_CALL(*client2, DidFetchDataLoadedString(String("Hello, world")));
@@ -92,12 +92,12 @@ void CheckResponseStream(ScriptState* script_state,
BodyStreamBuffer* CreateHelloWorldBuffer(ScriptState* script_state) {
using BytesConsumerCommand = BytesConsumerTestUtil::Command;
BytesConsumerTestUtil::ReplayingBytesConsumer* src =
- new BytesConsumerTestUtil::ReplayingBytesConsumer(
+ MakeGarbageCollected<BytesConsumerTestUtil::ReplayingBytesConsumer>(
ExecutionContext::From(script_state));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "Hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "world"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
- return new BodyStreamBuffer(script_state, src, nullptr);
+ return MakeGarbageCollected<BodyStreamBuffer>(script_state, src, nullptr);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneDefault) {
@@ -161,7 +161,7 @@ TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneOpaque) {
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneError) {
V8TestingScope scope;
- BodyStreamBuffer* buffer = new BodyStreamBuffer(
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
scope.GetScriptState(),
BytesConsumer::CreateErrored(BytesConsumer::Error()), nullptr);
FetchResponseData* fetch_response_data =
@@ -177,9 +177,9 @@ TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneError) {
EXPECT_FALSE(exception_state.HadException());
BytesConsumerTestUtil::MockFetchDataLoaderClient* client1 =
- new BytesConsumerTestUtil::MockFetchDataLoaderClient();
+ MakeGarbageCollected<BytesConsumerTestUtil::MockFetchDataLoaderClient>();
BytesConsumerTestUtil::MockFetchDataLoaderClient* client2 =
- new BytesConsumerTestUtil::MockFetchDataLoaderClient();
+ MakeGarbageCollected<BytesConsumerTestUtil::MockFetchDataLoaderClient>();
EXPECT_CALL(*client1, DidFetchDataLoadFailed());
EXPECT_CALL(*client2, DidFetchDataLoadFailed());
diff --git a/chromium/third_party/blink/renderer/core/fileapi/blob.cc b/chromium/third_party/blink/renderer/core/fileapi/blob.cc
index 494a2b31ed1..7658bb68538 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/blob.cc
+++ b/chromium/third_party/blink/renderer/core/fileapi/blob.cc
@@ -100,7 +100,8 @@ Blob* Blob::Create(
normalize_line_endings_to_native);
long long blob_size = blob_data->length();
- return new Blob(BlobDataHandle::Create(std::move(blob_data), blob_size));
+ return MakeGarbageCollected<Blob>(
+ BlobDataHandle::Create(std::move(blob_data), blob_size));
}
Blob* Blob::Create(const unsigned char* data,
@@ -113,7 +114,8 @@ Blob* Blob::Create(const unsigned char* data,
blob_data->AppendBytes(data, bytes);
long long blob_size = blob_data->length();
- return new Blob(BlobDataHandle::Create(std::move(blob_data), blob_size));
+ return MakeGarbageCollected<Blob>(
+ BlobDataHandle::Create(std::move(blob_data), blob_size));
}
// static
diff --git a/chromium/third_party/blink/renderer/core/fileapi/blob.h b/chromium/third_party/blink/renderer/core/fileapi/blob.h
index e02dabae0ef..dbe1e22715e 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/blob.h
+++ b/chromium/third_party/blink/renderer/core/fileapi/blob.h
@@ -56,7 +56,7 @@ class CORE_EXPORT Blob : public ScriptWrappable,
public:
static Blob* Create(ExecutionContext*, ExceptionState&) {
- return new Blob(BlobDataHandle::Create());
+ return MakeGarbageCollected<Blob>(BlobDataHandle::Create());
}
static Blob* Create(
@@ -66,13 +66,14 @@ class CORE_EXPORT Blob : public ScriptWrappable,
ExceptionState&);
static Blob* Create(scoped_refptr<BlobDataHandle> blob_data_handle) {
- return new Blob(std::move(blob_data_handle));
+ return MakeGarbageCollected<Blob>(std::move(blob_data_handle));
}
static Blob* Create(const unsigned char* data,
size_t bytes,
const String& content_type);
+ explicit Blob(scoped_refptr<BlobDataHandle>);
~Blob() override;
virtual unsigned long long size() const { return blob_data_handle_->size(); }
@@ -118,8 +119,6 @@ class CORE_EXPORT Blob : public ScriptWrappable,
bool IsBlob() const override { return true; }
protected:
- explicit Blob(scoped_refptr<BlobDataHandle>);
-
static void PopulateBlobData(
BlobData*,
const HeapVector<ArrayBufferOrArrayBufferViewOrBlobOrUSVString>& parts,
diff --git a/chromium/third_party/blink/renderer/core/fileapi/file.cc b/chromium/third_party/blink/renderer/core/fileapi/file.cc
index 22cfc7837f4..45d9c510997 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/file.cc
+++ b/chromium/third_party/blink/renderer/core/fileapi/file.cc
@@ -232,7 +232,8 @@ File::File(const KURL& file_system_url,
metadata.length)),
has_backing_file_(false),
user_visibility_(user_visibility),
- name_(DecodeURLEscapeSequences(file_system_url.LastPathComponent())),
+ name_(DecodeURLEscapeSequences(file_system_url.LastPathComponent(),
+ DecodeURLMode::kUTF8OrIsomorphic)),
file_system_url_(file_system_url),
snapshot_size_(metadata.length),
snapshot_modification_time_ms_(metadata.modification_time) {}
diff --git a/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h b/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h
index 747a254d098..6b5da439b52 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h
+++ b/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h
@@ -38,6 +38,8 @@ namespace blink {
enum class FileErrorCode;
+// For more information on how to read Blobs in your specific situation, see:
+// https://chromium.googlesource.com/chromium/src/+/HEAD/storage/browser/blob/README.md#accessing-reading
class CORE_EXPORT FileReaderLoaderClient {
public:
virtual ~FileReaderLoaderClient() = default;
diff --git a/chromium/third_party/blink/renderer/core/frame/BUILD.gn b/chromium/third_party/blink/renderer/core/frame/BUILD.gn
index a89c8f6b5f2..3c8b749feb3 100644
--- a/chromium/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/frame/BUILD.gn
@@ -19,12 +19,16 @@ blink_core_sources("frame") {
"csp/csp_directive_list.h",
"csp/csp_source.cc",
"csp/csp_source.h",
+ "csp/execution_context_csp_delegate.cc",
+ "csp/execution_context_csp_delegate.h",
"csp/media_list_directive.cc",
"csp/media_list_directive.h",
"csp/source_list_directive.cc",
"csp/source_list_directive.h",
"csp/string_list_directive.cc",
"csp/string_list_directive.h",
+ "dactyloscoper.cc",
+ "dactyloscoper.h",
"deprecated_schedule_style_recalc_during_layout.cc",
"deprecated_schedule_style_recalc_during_layout.h",
"deprecation.cc",
@@ -56,6 +60,8 @@ blink_core_sources("frame") {
"frame_console.h",
"frame_lifecycle.cc",
"frame_lifecycle.h",
+ "frame_overlay.cc",
+ "frame_overlay.h",
"frame_owner.h",
"frame_serializer.cc",
"frame_serializer.h",
@@ -113,8 +119,6 @@ blink_core_sources("frame") {
"pausable_script_executor.h",
"pausable_task.cc",
"pausable_task.h",
- "pausable_timer.cc",
- "pausable_timer.h",
"performance_monitor.cc",
"performance_monitor.h",
"picture_in_picture_controller.cc",
diff --git a/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc
index 128a79f7c50..617ca7c1b28 100644
--- a/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -111,7 +111,7 @@ class AdTrackerTest : public testing::Test {
void AdTrackerTest::SetUp() {
page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
page_holder_->GetDocument().SetURL(KURL("https://example.com/foo"));
- ad_tracker_ = new TestAdTracker(GetFrame());
+ ad_tracker_ = MakeGarbageCollected<TestAdTracker>(GetFrame());
ad_tracker_->SetExecutionContext(&page_holder_->GetDocument());
}
@@ -204,8 +204,7 @@ class AdTrackerSimTest : public SimTest {
"https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
- main_resource_->Start();
- ad_tracker_ = new TestAdTracker(GetDocument().GetFrame());
+ ad_tracker_ = MakeGarbageCollected<TestAdTracker>(GetDocument().GetFrame());
GetDocument().GetFrame()->SetAdTrackerForTesting(ad_tracker_);
}
@@ -226,8 +225,8 @@ class AdTrackerSimTest : public SimTest {
TEST_F(AdTrackerSimTest, ScriptLoadedWhileExecutingAdScript) {
const char kAdUrl[] = "https://example.com/ad_script.js";
const char kVanillaUrl[] = "https://example.com/vanilla_script.js";
- SimRequest ad_resource(kAdUrl, "text/javascript");
- SimRequest vanilla_script(kVanillaUrl, "text/javascript");
+ SimSubresourceRequest ad_resource(kAdUrl, "text/javascript");
+ SimSubresourceRequest vanilla_script(kVanillaUrl, "text/javascript");
ad_tracker_->SetAdSuffix("ad_script.js");
@@ -249,7 +248,7 @@ TEST_F(AdTrackerSimTest, ScriptLoadedWhileExecutingAdScript) {
// Unknown script running in an ad context should be labeled as ad script.
TEST_F(AdTrackerSimTest, ScriptDetectedByContext) {
const char kAdScriptUrl[] = "https://example.com/ad_script.js";
- SimRequest ad_script(kAdScriptUrl, "text/javascript");
+ SimSubresourceRequest ad_script(kAdScriptUrl, "text/javascript");
ad_tracker_->SetAdSuffix("ad_script.js");
@@ -273,9 +272,10 @@ TEST_F(AdTrackerSimTest, ScriptDetectedByContext) {
}
TEST_F(AdTrackerSimTest, AdResourceDetectedByContext) {
- SimRequest ad_script("https://example.com/ad_script.js", "text/javascript");
+ SimSubresourceRequest ad_script("https://example.com/ad_script.js",
+ "text/javascript");
SimRequest ad_frame("https://example.com/ad_frame.html", "text/html");
- SimRequest foo_css("https://example.com/foo.css", "text/style");
+ SimSubresourceRequest foo_css("https://example.com/foo.css", "text/style");
ad_tracker_->SetAdSuffix("ad_script.js");
// Create an iframe that's considered an ad.
@@ -306,7 +306,8 @@ TEST_F(AdTrackerSimTest, AdResourceDetectedByContext) {
// When inline script in an ad frame inserts an iframe into a non-ad frame, the
// new frame should be considered an ad.
TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) {
- SimRequest ad_script("https://example.com/ad_script.js", "text/javascript");
+ SimSubresourceRequest ad_script("https://example.com/ad_script.js",
+ "text/javascript");
SimRequest ad_iframe("https://example.com/ad_frame.html", "text/html");
ad_tracker_->SetAdSuffix("ad_script.js");
@@ -340,8 +341,8 @@ TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) {
TEST_F(AdTrackerSimTest, ImageLoadedWhileExecutingAdScript) {
const char kAdUrl[] = "https://example.com/ad_script.js";
const char kVanillaUrl[] = "https://example.com/vanilla_image.jpg";
- SimRequest ad_resource(kAdUrl, "text/javascript");
- SimRequest vanilla_image(kVanillaUrl, "image/jpeg");
+ SimSubresourceRequest ad_resource(kAdUrl, "text/javascript");
+ SimSubresourceRequest vanilla_image(kVanillaUrl, "image/jpeg");
ad_tracker_->SetAdSuffix("ad_script.js");
@@ -364,7 +365,7 @@ TEST_F(AdTrackerSimTest, ImageLoadedWhileExecutingAdScript) {
TEST_F(AdTrackerSimTest, FrameLoadedWhileExecutingAdScript) {
const char kAdUrl[] = "https://example.com/ad_script.js";
const char kVanillaUrl[] = "https://example.com/vanilla_page.html";
- SimRequest ad_resource(kAdUrl, "text/javascript");
+ SimSubresourceRequest ad_resource(kAdUrl, "text/javascript");
SimRequest vanilla_page(kVanillaUrl, "text/html");
ad_tracker_->SetAdSuffix("ad_script.js");
@@ -391,8 +392,8 @@ TEST_F(AdTrackerSimTest, Contexts) {
// gets tagged as an ad script in the subframe, that shouldn't cause it to
// be treated as an ad in the main frame.
SimRequest iframe_resource("https://example.com/iframe.html", "text/html");
- SimRequest library_resource("https://example.com/library.js",
- "text/javascript");
+ SimSubresourceRequest library_resource("https://example.com/library.js",
+ "text/javascript");
main_resource_->Complete(R"HTML(
<script src=library.js></script>
@@ -404,8 +405,8 @@ TEST_F(AdTrackerSimTest, Contexts) {
// The library script is loaded for a second time, this time in the
// subframe. Mark it as an ad.
- SimRequest library_resource_for_subframe("https://example.com/library.js",
- "text/javascript");
+ SimSubresourceRequest library_resource_for_subframe(
+ "https://example.com/library.js", "text/javascript");
ad_tracker_->SetAdSuffix("library.js");
iframe_resource.Complete(R"HTML(
@@ -426,7 +427,8 @@ TEST_F(AdTrackerSimTest, Contexts) {
}
TEST_F(AdTrackerSimTest, SameOriginSubframeFromAdScript) {
- SimRequest ad_resource("https://example.com/ad_script.js", "text/javascript");
+ SimSubresourceRequest ad_resource("https://example.com/ad_script.js",
+ "text/javascript");
SimRequest iframe_resource("https://example.com/iframe.html", "text/html");
ad_tracker_->SetAdSuffix("ad_script.js");
@@ -448,7 +450,8 @@ TEST_F(AdTrackerSimTest, SameOriginSubframeFromAdScript) {
}
TEST_F(AdTrackerSimTest, SameOriginDocWrittenSubframeFromAdScript) {
- SimRequest ad_resource("https://example.com/ad_script.js", "text/javascript");
+ SimSubresourceRequest ad_resource("https://example.com/ad_script.js",
+ "text/javascript");
ad_tracker_->SetAdSuffix("ad_script.js");
main_resource_->Complete(R"HTML(
@@ -479,7 +482,6 @@ class AdTrackerDisabledSimTest : public SimTest {
"https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
- main_resource_->Start();
}
std::unique_ptr<SimRequest> main_resource_;
diff --git a/chromium/third_party/blink/renderer/core/frame/bar_prop.h b/chromium/third_party/blink/renderer/core/frame/bar_prop.h
index 2155edeb604..5d73c76cb3b 100644
--- a/chromium/third_party/blink/renderer/core/frame/bar_prop.h
+++ b/chromium/third_party/blink/renderer/core/frame/bar_prop.h
@@ -52,15 +52,16 @@ class BarProp final : public ScriptWrappable, public DOMWindowClient {
};
static BarProp* Create(LocalFrame* frame, Type type) {
- return new BarProp(frame, type);
+ return MakeGarbageCollected<BarProp>(frame, type);
}
+ BarProp(LocalFrame*, Type);
+
bool visible() const;
void Trace(blink::Visitor*) override;
private:
- BarProp(LocalFrame*, Type);
Type type_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/browser_controls.h b/chromium/third_party/blink/renderer/core/frame/browser_controls.h
index 9391a89907d..5545e44bc99 100644
--- a/chromium/third_party/blink/renderer/core/frame/browser_controls.h
+++ b/chromium/third_party/blink/renderer/core/frame/browser_controls.h
@@ -25,9 +25,11 @@ class CORE_EXPORT BrowserControls final
: public GarbageCollected<BrowserControls> {
public:
static BrowserControls* Create(const Page& page) {
- return new BrowserControls(page);
+ return MakeGarbageCollected<BrowserControls>(page);
}
+ explicit BrowserControls(const Page&);
+
void Trace(blink::Visitor*);
// The height the top controls are hidden; used for viewport adjustments
@@ -58,7 +60,6 @@ class CORE_EXPORT BrowserControls final
cc::BrowserControlsState PermittedState() const { return permitted_state_; }
private:
- explicit BrowserControls(const Page&);
void ResetBaseline();
float BottomContentOffset();
diff --git a/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc b/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc
index 87ff69a57ba..5cc681e8b7b 100644
--- a/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc
@@ -84,7 +84,7 @@ class BrowserControlsTest : public testing::Test {
helper_.InitializeAndLoad(base_url_ + page_name, nullptr, nullptr, nullptr,
&ConfigureSettings);
- GetWebView()->Resize(IntSize(400, 400));
+ GetWebView()->MainFrameWidget()->Resize(IntSize(400, 400));
return GetWebView();
}
@@ -122,11 +122,11 @@ class BrowserControlsTest : public testing::Test {
}
void VerticalScroll(float delta_y) {
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollBegin, 0, delta_y));
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, delta_y));
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollEnd));
}
@@ -191,11 +191,12 @@ class BrowserControlsSimTest : public SimTest {
}
void VerticalScroll(float delta_y) {
- WebView().HandleInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollBegin, 0, delta_y));
- WebView().HandleInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, delta_y));
- WebView().HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ WebView().MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
}
};
@@ -212,14 +213,16 @@ class BrowserControlsSimTest : public SimTest {
TEST_F(BrowserControlsTest, MAYBE(HideOnScrollDown)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be shown.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
// Browser controls should be scrolled partially and page should not scroll.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -25.f));
EXPECT_FLOAT_EQ(25.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 0),
@@ -228,14 +231,14 @@ TEST_F(BrowserControlsTest, MAYBE(HideOnScrollDown)) {
// Browser controls should consume 25px and become hidden. Excess scroll
// should be
// consumed by the page.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -40.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 15),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
// Only page should consume scroll
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -20.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 35),
@@ -246,15 +249,17 @@ TEST_F(BrowserControlsTest, MAYBE(HideOnScrollDown)) {
TEST_F(BrowserControlsTest, MAYBE(HideBottomControlsOnScrollDown)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be shown.
- web_view->ResizeWithBrowserControls(web_view->Size(), 0, 50.f, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 0,
+ 50.f, true);
web_view->GetBrowserControls().SetShownRatio(1);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
// Bottom controls and page content should both scroll and there should be
// no content offset.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -25.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_FLOAT_EQ(0.5f, web_view->GetBrowserControls().ShownRatio());
@@ -262,10 +267,12 @@ TEST_F(BrowserControlsTest, MAYBE(HideBottomControlsOnScrollDown)) {
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
// Browser controls should become completely hidden.
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -40.f));
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ShownRatio());
EXPECT_EQ(ScrollOffset(0, 65.f),
@@ -276,19 +283,21 @@ TEST_F(BrowserControlsTest, MAYBE(HideBottomControlsOnScrollDown)) {
TEST_F(BrowserControlsTest, MAYBE(ShowOnScrollUp)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be hidden.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, false);
web_view->GetBrowserControls().SetShownRatio(0);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 10.f));
EXPECT_FLOAT_EQ(10.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 0),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 50.f));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 0),
@@ -299,22 +308,28 @@ TEST_F(BrowserControlsTest, MAYBE(ShowOnScrollUp)) {
TEST_F(BrowserControlsTest, MAYBE(ShowBottomControlsOnScrollUp)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be hidden.
- web_view->ResizeWithBrowserControls(web_view->Size(), 0, 50.f, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 0,
+ 50.f, false);
web_view->GetBrowserControls().SetShownRatio(0);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
// Allow some space to scroll up.
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -50.f));
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 25.f));
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_FLOAT_EQ(0.5f, web_view->GetBrowserControls().ShownRatio());
EXPECT_EQ(ScrollOffset(0, 25),
@@ -326,17 +341,19 @@ TEST_F(BrowserControlsTest, MAYBE(ShowBottomControlsOnScrollUp)) {
TEST_F(BrowserControlsTest, MAYBE(ScrollDownThenUp)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be shown and position page at 100px.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
GetFrame()->View()->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 100),
kProgrammaticScroll);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
// Scroll down to completely hide browser controls. Excess deltaY (100px)
// should be consumed by the page.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -150.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 200),
@@ -344,13 +361,13 @@ TEST_F(BrowserControlsTest, MAYBE(ScrollDownThenUp)) {
// Scroll up and ensure the browser controls does not move until we recover
// 100px previously scrolled.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 40.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 160),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 60.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 100),
@@ -358,14 +375,14 @@ TEST_F(BrowserControlsTest, MAYBE(ScrollDownThenUp)) {
// Now we have hit the threshold so further scroll up should be consumed by
// browser controls.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 30.f));
EXPECT_FLOAT_EQ(30.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 100),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
// Once top control is fully shown then page should consume any excess scroll.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 70.f));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 50),
@@ -377,30 +394,32 @@ TEST_F(BrowserControlsTest, MAYBE(ScrollDownThenUp)) {
TEST_F(BrowserControlsTest, MAYBE(ScrollUpThenDown)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be hidden and position page at 100px.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, false);
web_view->GetBrowserControls().SetShownRatio(0);
GetFrame()->View()->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 100),
kProgrammaticScroll);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
// Scroll up to completely show browser controls. Excess deltaY (50px) should
// be consumed by the page.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 100.f));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 50),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
// Scroll down and ensure only browser controls is scrolled
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -40.f));
EXPECT_FLOAT_EQ(10.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 50),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -60.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 100),
@@ -411,20 +430,22 @@ TEST_F(BrowserControlsTest, MAYBE(ScrollUpThenDown)) {
TEST_F(BrowserControlsTest, MAYBE(HorizontalScroll)) {
WebViewImpl* web_view = Initialize();
// initialize browser controls to be shown.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
// Browser controls should not consume horizontal scroll.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, -110.f, -100.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(110, 50),
GetFrame()->View()->LayoutViewport()->GetScrollOffset());
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, -40.f, 0));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(150, 50),
@@ -438,14 +459,16 @@ TEST_F(BrowserControlsTest, MAYBE(PageScaleHasNoImpact)) {
web_view->SetPageScaleFactor(2.0);
// Initialize browser controls to be shown.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
// Browser controls should be scrolled partially and page should not scroll.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -20.f));
EXPECT_FLOAT_EQ(30.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 0),
@@ -453,30 +476,32 @@ TEST_F(BrowserControlsTest, MAYBE(PageScaleHasNoImpact)) {
// Browser controls should consume 30px and become hidden. Excess scroll
// should be consumed by the page at 2x scale.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -70.f));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 20),
GetFrame()->View()->GetScrollableArea()->GetScrollOffset());
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
// Change page scale and test.
web_view->SetPageScaleFactor(0.5);
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollBegin));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 20),
GetFrame()->View()->GetScrollableArea()->GetScrollOffset());
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 50.f));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 20),
GetFrame()->View()->GetScrollableArea()->GetScrollOffset());
// At 0.5x scale scrolling 10px should take us to the top of the page.
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 10.f));
EXPECT_FLOAT_EQ(50.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(ScrollOffset(0, 0),
@@ -493,7 +518,8 @@ TEST_F(BrowserControlsTest, MAYBE(FloatingPointSlippage)) {
web_view->SetPageScaleFactor(2.0);
// Initialize browser controls to be shown.
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
web_view->GetBrowserControls().ScrollBegin();
@@ -510,7 +536,8 @@ TEST_F(BrowserControlsTest, MAYBE(FloatingPointSlippage)) {
// Scrollable subregions should scroll before browser controls
TEST_F(BrowserControlsTest, MAYBE(ScrollableSubregionScrollFirst)) {
WebViewImpl* web_view = Initialize("overflow-scrolling.html");
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
GetFrame()->View()->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 50),
kProgrammaticScroll);
@@ -560,7 +587,8 @@ TEST_F(BrowserControlsTest, MAYBE(ScrollableSubregionScrollFirst)) {
// Scrollable iframes should scroll before browser controls
TEST_F(BrowserControlsTest, MAYBE(ScrollableIframeScrollFirst)) {
WebViewImpl* web_view = Initialize("iframe-scrolling.html");
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
GetFrame()->View()->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 50),
kProgrammaticScroll);
@@ -610,13 +638,16 @@ TEST_F(BrowserControlsTest, MAYBE(ScrollableIframeScrollFirst)) {
// Browser controls visibility should remain consistent when height is changed.
TEST_F(BrowserControlsTest, MAYBE(HeightChangeMaintainsVisibility)) {
WebViewImpl* web_view = Initialize();
- web_view->ResizeWithBrowserControls(web_view->Size(), 20.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 20.f,
+ 0, false);
web_view->GetBrowserControls().SetShownRatio(0);
- web_view->ResizeWithBrowserControls(web_view->Size(), 20.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 20.f,
+ 0, false);
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
- web_view->ResizeWithBrowserControls(web_view->Size(), 40.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 40.f,
+ 0, false);
EXPECT_FLOAT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
// Scroll up to show browser controls.
@@ -625,14 +656,16 @@ TEST_F(BrowserControlsTest, MAYBE(HeightChangeMaintainsVisibility)) {
// Changing height of a fully shown browser controls should correctly adjust
// content offset
- web_view->ResizeWithBrowserControls(web_view->Size(), 30.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 30.f,
+ 0, false);
EXPECT_FLOAT_EQ(30.f, web_view->GetBrowserControls().ContentOffset());
}
// Zero delta should not have any effect on browser controls.
TEST_F(BrowserControlsTest, MAYBE(ZeroHeightMeansNoEffect)) {
WebViewImpl* web_view = Initialize();
- web_view->ResizeWithBrowserControls(web_view->Size(), 0, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 0, 0,
+ false);
web_view->GetBrowserControls().SetShownRatio(0);
GetFrame()->View()->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 100),
kProgrammaticScroll);
@@ -657,7 +690,8 @@ TEST_F(BrowserControlsTest, MAYBE(ZeroHeightMeansNoEffect)) {
TEST_F(BrowserControlsTest, MAYBE(ScrollUpPastLimitDoesNotHide)) {
WebViewImpl* web_view = Initialize();
// Initialize browser controls to be shown
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, true);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, true);
web_view->GetBrowserControls().SetShownRatio(1);
// Use 2x scale so that both visual viewport and frameview are scrollable
web_view->SetPageScaleFactor(2.0);
@@ -1087,9 +1121,9 @@ TEST_F(BrowserControlsTest,
// Zoom in to 2X and fully scroll both viewports.
web_view->SetPageScaleFactor(page_scale);
{
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollBegin));
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, -10000));
ASSERT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
@@ -1100,7 +1134,8 @@ TEST_F(BrowserControlsTest,
view->LayoutViewport()->GetScrollOffset().Height());
EXPECT_EQ(expected_root_offset, root_viewport->GetScrollOffset().Height());
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
}
// Commit the browser controls resize so that the browser controls do not
@@ -1122,9 +1157,9 @@ TEST_F(BrowserControlsTest,
// account for this and keep the visual viewport at the same location relative
// to the document (i.e. the user shouldn't see a movement).
{
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollBegin));
- web_view->HandleInputEvent(
+ web_view->MainFrameWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::kGestureScrollUpdate, 0, 80));
GetVisualViewport().ClampToBoundaries();
@@ -1134,7 +1169,8 @@ TEST_F(BrowserControlsTest,
ASSERT_EQ(80.f, web_view->GetBrowserControls().ContentOffset());
EXPECT_EQ(expected_root_offset, root_viewport->GetScrollOffset().Height());
- web_view->HandleInputEvent(GenerateEvent(WebInputEvent::kGestureScrollEnd));
+ web_view->MainFrameWidget()->HandleInputEvent(
+ GenerateEvent(WebInputEvent::kGestureScrollEnd));
}
}
@@ -1231,7 +1267,8 @@ TEST_F(BrowserControlsSimTest, MAYBE(ViewportUnitsWhenControlsLocked)) {
// Test the size adjustment sent to the viewport when top controls exist.
TEST_F(BrowserControlsTest, MAYBE(TopControlsSizeAdjustment)) {
WebViewImpl* web_view = Initialize();
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, 0, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ 0, false);
web_view->GetBrowserControls().SetShownRatio(1);
EXPECT_FLOAT_EQ(-50.f,
web_view->GetBrowserControls().UnreportedSizeAdjustment());
@@ -1250,7 +1287,8 @@ TEST_F(BrowserControlsTest, MAYBE(TopControlsSizeAdjustment)) {
// the content offset.
TEST_F(BrowserControlsTest, MAYBE(BottomControlsSizeAdjustment)) {
WebViewImpl* web_view = Initialize();
- web_view->ResizeWithBrowserControls(web_view->Size(), 0, 50.f, false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 0,
+ 50.f, false);
web_view->GetBrowserControls().SetShownRatio(1);
EXPECT_FLOAT_EQ(0.f,
web_view->GetBrowserControls().UnreportedSizeAdjustment());
@@ -1267,8 +1305,8 @@ TEST_F(BrowserControlsTest, MAYBE(BottomControlsSizeAdjustment)) {
TEST_F(BrowserControlsTest, MAYBE(GrowingHeightKeepsTopControlsHidden)) {
WebViewImpl* web_view = Initialize();
float bottom_height = web_view->GetBrowserControls().BottomHeight();
- web_view->ResizeWithBrowserControls(web_view->Size(), 1.f, bottom_height,
- false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 1.f,
+ bottom_height, false);
web_view->GetBrowserControls().UpdateConstraintsAndState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kHidden,
@@ -1278,12 +1316,12 @@ TEST_F(BrowserControlsTest, MAYBE(GrowingHeightKeepsTopControlsHidden)) {
// shouln't change.
EXPECT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
- web_view->ResizeWithBrowserControls(web_view->Size(), 50.f, bottom_height,
- false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(), 50.f,
+ bottom_height, false);
EXPECT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
- web_view->ResizeWithBrowserControls(web_view->Size(), 100.f, bottom_height,
- false);
+ web_view->ResizeWithBrowserControls(web_view->MainFrameWidget()->Size(),
+ 100.f, bottom_height, false);
EXPECT_EQ(0.f, web_view->GetBrowserControls().ContentOffset());
}
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 181137417d9..f30eb4eb1e4 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include <memory>
+#include <utility>
#include <vector>
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
@@ -39,7 +40,7 @@
#include "third_party/blink/renderer/core/dom/dom_string_list.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
-#include "third_party/blink/renderer/core/events/security_policy_violation_event.h"
+#include "third_party/blink/renderer/core/events/security_policy_violation_event_init.h"
#include "third_party/blink/renderer/core/frame/csp/csp_directive_list.h"
#include "third_party/blink/renderer/core/frame/csp/csp_source.h"
#include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
@@ -53,11 +54,6 @@
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/html/html_script_element.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/ping_loader.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/core/workers/worklet_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/json/json_values.h"
#include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
@@ -65,11 +61,9 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h"
-#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/known_ports.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/reporting_service_proxy_ptr_holder.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/not_found.h"
#include "third_party/blink/renderer/platform/wtf/string_hasher.h"
@@ -112,11 +106,12 @@ bool ContentSecurityPolicy::IsNonceableElement(const Element* element) {
// element: if their names or values contain "<script" or "<style", we won't
// apply the nonce when loading script.
//
- // TODO(mkwst): We'll should also skip elements for which the HTML parser
- // dropped attributes: https://crbug.com/740615 and https://crbug.com/790955.
- //
// See http://blog.innerht.ml/csp-2015/#danglingmarkupinjection for an example
// of the kind of attack this is aimed at mitigating.
+
+ if (element->HasDuplicateAttribute())
+ nonceable = false;
+
if (nonceable) {
static const char kScriptString[] = "<SCRIPT";
static const char kStyleString[] = "<STYLE";
@@ -153,7 +148,7 @@ static WebFeature GetUseCounterType(ContentSecurityPolicyHeaderType type) {
}
ContentSecurityPolicy::ContentSecurityPolicy()
- : execution_context_(nullptr),
+ : delegate_(nullptr),
override_inline_style_allowed_(false),
script_hash_algorithms_used_(kContentSecurityPolicyHashAlgorithmNone),
style_hash_algorithms_used_(kContentSecurityPolicyHashAlgorithmNone),
@@ -162,80 +157,69 @@ ContentSecurityPolicy::ContentSecurityPolicy()
require_safe_types_(false),
insecure_request_policy_(kLeaveInsecureRequestsAlone) {}
-void ContentSecurityPolicy::BindToExecutionContext(
- ExecutionContext* execution_context) {
- execution_context_ = execution_context;
- ApplyPolicySideEffectsToExecutionContext();
+void ContentSecurityPolicy::BindToDelegate(
+ ContentSecurityPolicyDelegate& delegate) {
+ // TODO(crbug.com/915954): Add DCHECK(!delegate_). It seems some call sites
+ // call this function multiple times.
+ delegate_ = &delegate;
+ ApplyPolicySideEffectsToDelegate();
}
void ContentSecurityPolicy::SetupSelf(const SecurityOrigin& security_origin) {
// Ensure that 'self' processes correctly.
self_protocol_ = security_origin.Protocol();
- self_source_ = new CSPSource(this, self_protocol_, security_origin.Host(),
- security_origin.Port(), String(),
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+ self_source_ = MakeGarbageCollected<CSPSource>(
+ this, self_protocol_, security_origin.Host(), security_origin.Port(),
+ String(), CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+}
+
+void ContentSecurityPolicy::SetupSelf(const ContentSecurityPolicy& other) {
+ self_protocol_ = other.self_protocol_;
+ if (other.self_source_) {
+ self_source_ =
+ MakeGarbageCollected<CSPSource>(this, *(other.self_source_.Get()));
+ }
}
-void ContentSecurityPolicy::ApplyPolicySideEffectsToExecutionContext() {
- DCHECK(execution_context_ &&
- execution_context_->GetSecurityContext().GetSecurityOrigin());
- SecurityContext& security_context = execution_context_->GetSecurityContext();
+void ContentSecurityPolicy::ApplyPolicySideEffectsToDelegate() {
+ DCHECK(delegate_);
- SetupSelf(*security_context.GetSecurityOrigin());
+ const SecurityOrigin* security_origin = delegate_->GetSecurityOrigin();
+ DCHECK(security_origin);
+
+ SetupSelf(*security_origin);
// Set mixed content checking and sandbox flags, then dump all the parsing
// error messages, then poke at histograms.
- Document* document = this->GetDocument();
if (sandbox_mask_ != kSandboxNone) {
- UseCounter::Count(execution_context_, WebFeature::kSandboxViaCSP);
- if (document)
- document->EnforceSandboxFlags(sandbox_mask_);
- else
- security_context.ApplySandboxFlags(sandbox_mask_);
- }
- if (treat_as_public_address_) {
- security_context.SetAddressSpace(mojom::IPAddressSpace::kPublic);
- }
- if (require_safe_types_) {
- security_context.SetRequireTrustedTypes();
+ Count(WebFeature::kSandboxViaCSP);
+ delegate_->SetSandboxFlags(sandbox_mask_);
}
+ if (treat_as_public_address_)
+ delegate_->SetAddressSpace(mojom::IPAddressSpace::kPublic);
- // Upgrade Insecure Requests: Update the policy.
- security_context.SetInsecureRequestPolicy(
- security_context.GetInsecureRequestPolicy() | insecure_request_policy_);
- if (document)
- document->DidEnforceInsecureRequestPolicy();
-
- // Upgrade Insecure Requests: Update the set of insecure URLs to upgrade.
- if (insecure_request_policy_ & kUpgradeInsecureRequests) {
- UseCounter::Count(execution_context_,
- WebFeature::kUpgradeInsecureRequestsEnabled);
- if (!execution_context_->Url().Host().IsEmpty()) {
- uint32_t hash = execution_context_->Url().Host().Impl()->GetHash();
- security_context.AddInsecureNavigationUpgrade(hash);
- if (document)
- document->DidEnforceInsecureNavigationsSet();
- }
- }
+ if (require_safe_types_)
+ delegate_->SetRequireTrustedTypes();
+
+ delegate_->AddInsecureRequestPolicy(insecure_request_policy_);
for (const auto& console_message : console_messages_)
- execution_context_->AddConsoleMessage(console_message);
+ delegate_->AddConsoleMessage(console_message);
console_messages_.clear();
for (const auto& policy : policies_) {
- UseCounter::Count(execution_context_,
- GetUseCounterType(policy->HeaderType()));
+ Count(GetUseCounterType(policy->HeaderType()));
if (policy->AllowDynamic(
ContentSecurityPolicy::DirectiveType::kScriptSrcAttr) ||
policy->AllowDynamic(
ContentSecurityPolicy::DirectiveType::kScriptSrcElem)) {
- UseCounter::Count(execution_context_, WebFeature::kCSPWithStrictDynamic);
+ Count(WebFeature::kCSPWithStrictDynamic);
}
if (policy->AllowEval(nullptr,
SecurityViolationReportingPolicy::kSuppressReporting,
kWillNotThrowException, g_empty_string)) {
- UseCounter::Count(execution_context_, WebFeature::kCSPWithUnsafeEval);
+ Count(WebFeature::kCSPWithUnsafeEval);
}
}
@@ -243,27 +227,24 @@ void ContentSecurityPolicy::ApplyPolicySideEffectsToExecutionContext() {
// the check in the V8Initializer::codeGenerationCheckCallbackInMainThread
// callback to determine whether the call should execute or not.
if (!disable_eval_error_message_.IsNull())
- execution_context_->DisableEval(disable_eval_error_message_);
+ delegate_->DisableEval(disable_eval_error_message_);
}
ContentSecurityPolicy::~ContentSecurityPolicy() = default;
void ContentSecurityPolicy::Trace(blink::Visitor* visitor) {
- visitor->Trace(execution_context_);
+ visitor->Trace(delegate_);
visitor->Trace(policies_);
visitor->Trace(console_messages_);
visitor->Trace(self_source_);
}
-Document* ContentSecurityPolicy::GetDocument() const {
- return DynamicTo<Document>(execution_context_.Get());
-}
-
void ContentSecurityPolicy::CopyStateFrom(const ContentSecurityPolicy* other) {
DCHECK(policies_.IsEmpty());
for (const auto& policy : other->policies_)
AddAndReportPolicyFromHeaderValue(policy->Header(), policy->HeaderType(),
policy->HeaderSource());
+ SetupSelf(*other);
}
void ContentSecurityPolicy::CopyPluginTypesFrom(
@@ -298,22 +279,25 @@ void ContentSecurityPolicy::DidReceiveHeader(
ContentSecurityPolicyHeaderSource source) {
AddAndReportPolicyFromHeaderValue(header, type, source);
- // This might be called after we've been bound to an execution context. For
- // example, a <meta> element might be injected after page load.
- if (execution_context_)
- ApplyPolicySideEffectsToExecutionContext();
+ // This might be called after we've been bound to a delegate. For example, a
+ // <meta> element might be injected after page load.
+ if (delegate_)
+ ApplyPolicySideEffectsToDelegate();
}
bool ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
const ResourceResponse& response,
const SecurityOrigin* parent_origin) {
- if (response.Url().IsEmpty() || response.Url().ProtocolIsAbout() ||
- response.Url().ProtocolIsData() || response.Url().ProtocolIs("blob") ||
- response.Url().ProtocolIs("filesystem")) {
+ if (response.CurrentRequestUrl().IsEmpty() ||
+ response.CurrentRequestUrl().ProtocolIsAbout() ||
+ response.CurrentRequestUrl().ProtocolIsData() ||
+ response.CurrentRequestUrl().ProtocolIs("blob") ||
+ response.CurrentRequestUrl().ProtocolIs("filesystem")) {
return true;
}
- if (parent_origin->CanAccess(SecurityOrigin::Create(response.Url()).get()))
+ if (parent_origin->CanAccess(
+ SecurityOrigin::Create(response.CurrentRequestUrl()).get()))
return true;
String header = response.HttpHeaderField(http_names::kAllowCSPFrom);
@@ -409,10 +393,9 @@ void ContentSecurityPolicy::AddAndReportPolicyFromHeaderValue(
policies[i - previous_policy_count] =
policies_[i]->ExposeForNavigationalChecks();
}
- if (GetDocument() && GetDocument()->GetFrame()) {
- GetDocument()->GetFrame()->Client()->DidAddContentSecurityPolicies(
- policies);
- }
+
+ if (delegate_)
+ delegate_->DidAddContentSecurityPolicies(policies);
}
void ContentSecurityPolicy::SetOverrideAllowInlineStyle(bool value) {
@@ -426,9 +409,9 @@ void ContentSecurityPolicy::SetOverrideURLForSelf(const KURL& url) {
// to an execution context.
scoped_refptr<const SecurityOrigin> origin = SecurityOrigin::Create(url);
self_protocol_ = origin->Protocol();
- self_source_ =
- new CSPSource(this, self_protocol_, origin->Host(), origin->Port(),
- String(), CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+ self_source_ = MakeGarbageCollected<CSPSource>(
+ this, self_protocol_, origin->Host(), origin->Port(), String(),
+ CSPSource::kNoWildcard, CSPSource::kNoWildcard);
}
Vector<CSPHeaderAndType> ContentSecurityPolicy::Headers() const {
@@ -664,22 +647,6 @@ bool ContentSecurityPolicy::AllowPluginTypeForDocument(
type, type_attribute, url, reporting_policy))
return false;
- // CSP says that a plugin document in a nested browsing context should
- // inherit the plugin-types of its parent.
- //
- // FIXME: The plugin-types directive should be pushed down into the
- // current document instead of reaching up to the parent for it here.
- LocalFrame* frame = document.GetFrame();
- if (frame && frame->Tree().Parent() && document.IsPluginDocument()) {
- ContentSecurityPolicy* parent_csp = frame->Tree()
- .Parent()
- ->GetSecurityContext()
- ->GetContentSecurityPolicy();
- if (parent_csp && !parent_csp->AllowPluginType(type, type_attribute, url,
- reporting_policy))
- return false;
- }
-
return true;
}
@@ -691,12 +658,10 @@ bool ContentSecurityPolicy::AllowScriptFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_)) {
- UseCounter::Count(
- GetDocument(),
- parser_disposition == kParserInserted
- ? WebFeature::kScriptWithCSPBypassingSchemeParserInserted
- : WebFeature::kScriptWithCSPBypassingSchemeNotParserInserted);
+ if (ShouldBypassContentSecurityPolicy(url)) {
+ Count(parser_disposition == kParserInserted
+ ? WebFeature::kScriptWithCSPBypassingSchemeParserInserted
+ : WebFeature::kScriptWithCSPBypassingSchemeNotParserInserted);
// If we're running experimental features, bypass CSP only for
// non-parser-inserted resources whose scheme otherwise bypasses CSP. If
@@ -709,7 +674,7 @@ bool ContentSecurityPolicy::AllowScriptFromSource(
// The schemes where javascript:-URLs are blocked are usually privileged
// pages, so do not allow the CSP to be bypassed either.
!SchemeRegistry::ShouldTreatURLSchemeAsNotAllowingJavascriptURLs(
- execution_context_->GetSecurityOrigin()->Protocol())) {
+ delegate_->GetSecurityOrigin()->Protocol())) {
return true;
}
}
@@ -834,7 +799,7 @@ bool ContentSecurityPolicy::AllowObjectFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -853,7 +818,7 @@ bool ContentSecurityPolicy::AllowPrefetchFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -872,7 +837,7 @@ bool ContentSecurityPolicy::AllowFrameFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -891,8 +856,7 @@ bool ContentSecurityPolicy::AllowImageFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_,
- SchemeRegistry::kPolicyAreaImage))
+ if (ShouldBypassContentSecurityPolicy(url, SchemeRegistry::kPolicyAreaImage))
return true;
bool is_allowed = true;
@@ -912,8 +876,7 @@ bool ContentSecurityPolicy::AllowStyleFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_,
- SchemeRegistry::kPolicyAreaStyle))
+ if (ShouldBypassContentSecurityPolicy(url, SchemeRegistry::kPolicyAreaStyle))
return true;
bool is_allowed = true;
@@ -931,7 +894,7 @@ bool ContentSecurityPolicy::AllowFontFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -950,7 +913,7 @@ bool ContentSecurityPolicy::AllowMediaFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -969,7 +932,7 @@ bool ContentSecurityPolicy::AllowConnectToSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -988,7 +951,7 @@ bool ContentSecurityPolicy::AllowFormAction(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -1008,7 +971,7 @@ bool ContentSecurityPolicy::AllowBaseURI(
SecurityViolationReportingPolicy reporting_policy) const {
// `base-uri` isn't affected by 'upgrade-insecure-requests', so we'll check
// both report-only and enforce headers here.
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -1041,42 +1004,7 @@ bool ContentSecurityPolicy::AllowWorkerContextFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- // CSP 1.1 moves workers from 'script-src' to the new 'child-src'. Measure the
- // impact of this backwards-incompatible change.
- // TODO(mkwst): We reverted this.
- if (Document* document = this->GetDocument()) {
- UseCounter::Count(*document, WebFeature::kWorkerSubjectToCSP);
- bool is_allowed_worker = true;
- if (!ShouldBypassContentSecurityPolicy(url, execution_context_)) {
- for (const auto& policy : policies_) {
- if (!CheckHeaderTypeMatches(check_header_type, policy->HeaderType()))
- continue;
- is_allowed_worker &= policy->AllowWorkerFromSource(
- url, redirect_status,
- SecurityViolationReportingPolicy::kSuppressReporting);
- }
- }
-
- bool is_allowed_script = true;
-
- if (!ShouldBypassContentSecurityPolicy(url, execution_context_)) {
- for (const auto& policy : policies_) {
- if (!CheckHeaderTypeMatches(check_header_type, policy->HeaderType()))
- continue;
- is_allowed_script &= policy->AllowScriptFromSource(
- url, AtomicString(), IntegrityMetadataSet(), kNotParserInserted,
- redirect_status,
- SecurityViolationReportingPolicy::kSuppressReporting);
- }
- }
-
- if (is_allowed_worker && !is_allowed_script) {
- UseCounter::Count(*document,
- WebFeature::kWorkerAllowedByChildBlockedByScript);
- }
- }
-
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -1095,7 +1023,7 @@ bool ContentSecurityPolicy::AllowManifestFromSource(
RedirectStatus redirect_status,
SecurityViolationReportingPolicy reporting_policy,
CheckHeaderType check_header_type) const {
- if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+ if (ShouldBypassContentSecurityPolicy(url))
return true;
bool is_allowed = true;
@@ -1139,8 +1067,8 @@ bool ContentSecurityPolicy::IsActiveForConnections() const {
return false;
}
-const KURL ContentSecurityPolicy::Url() const {
- return execution_context_->Url();
+const KURL ContentSecurityPolicy::FallbackUrlForPlugin() const {
+ return delegate_ ? delegate_->Url() : KURL();
}
void ContentSecurityPolicy::EnforceSandboxFlags(SandboxFlags mask) {
@@ -1154,8 +1082,8 @@ void ContentSecurityPolicy::TreatAsPublicAddress() {
}
void ContentSecurityPolicy::RequireTrustedTypes() {
- if (!RuntimeEnabledFeatures::TrustedDOMTypesEnabled())
- return;
+ // We store whether CSP demands a policy. The caller still needs to check
+ // whether the feature is enabled in the first place.
require_safe_types_ = true;
}
@@ -1168,7 +1096,7 @@ void ContentSecurityPolicy::UpgradeInsecureRequests() {
}
static String StripURLForUseInReport(
- ExecutionContext* context,
+ const SecurityOrigin* security_origin,
const KURL& url,
RedirectStatus redirect_status,
const ContentSecurityPolicy::DirectiveType& effective_type) {
@@ -1181,7 +1109,7 @@ static String StripURLForUseInReport(
// (and, by extension, in plugin documents), strip cross-origin 'frame-src'
// and 'object-src' violations down to an origin. https://crbug.com/633306
bool can_safely_expose_url =
- context->GetSecurityOrigin()->CanRequest(url) ||
+ security_origin->CanRequest(url) ||
(redirect_status == RedirectStatus::kNoRedirect &&
effective_type != ContentSecurityPolicy::DirectiveType::kFrameSrc &&
effective_type != ContentSecurityPolicy::DirectiveType::kObjectSrc);
@@ -1198,7 +1126,7 @@ static String StripURLForUseInReport(
static void GatherSecurityPolicyViolationEventData(
SecurityPolicyViolationEventInit* init,
- ExecutionContext* context,
+ ContentSecurityPolicyDelegate* delegate,
const String& directive_text,
const ContentSecurityPolicy::DirectiveType& effective_type,
const KURL& blocked_url,
@@ -1213,13 +1141,14 @@ static void GatherSecurityPolicyViolationEventData(
// |document| has not yet been initialized. In this case, we'll set both
// 'documentURI' and 'blockedURI' to the blocked document's URL.
String stripped_url = StripURLForUseInReport(
- context, blocked_url, RedirectStatus::kNoRedirect,
+ delegate->GetSecurityOrigin(), blocked_url, RedirectStatus::kNoRedirect,
ContentSecurityPolicy::DirectiveType::kDefaultSrc);
init->setDocumentURI(stripped_url);
init->setBlockedURI(stripped_url);
} else {
String stripped_url = StripURLForUseInReport(
- context, context->Url(), RedirectStatus::kNoRedirect,
+ delegate->GetSecurityOrigin(), delegate->Url(),
+ RedirectStatus::kNoRedirect,
ContentSecurityPolicy::DirectiveType::kDefaultSrc);
init->setDocumentURI(stripped_url);
switch (violation_type) {
@@ -1230,8 +1159,9 @@ static void GatherSecurityPolicyViolationEventData(
init->setBlockedURI("eval");
break;
case ContentSecurityPolicy::kURLViolation:
- init->setBlockedURI(StripURLForUseInReport(
- context, blocked_url, redirect_status, effective_type));
+ init->setBlockedURI(
+ StripURLForUseInReport(delegate->GetSecurityOrigin(), blocked_url,
+ redirect_status, effective_type));
break;
}
}
@@ -1246,20 +1176,31 @@ static void GatherSecurityPolicyViolationEventData(
: "report");
init->setStatusCode(0);
- // TODO(mkwst): We only have referrer and status code information for
- // Documents. It would be nice to get them for Workers as well.
- if (auto* document = DynamicTo<Document>(*context)) {
- init->setReferrer(document->referrer());
- if (!SecurityOrigin::IsSecure(context->Url()) && document->Loader())
- init->setStatusCode(document->Loader()->GetResponse().HttpStatusCode());
- }
-
- // If no source location is provided, use the source location of the context.
+ // See https://w3c.github.io/webappsec-csp/#create-violation-for-global.
+ // Step 3. If global is a Window object, set violation’s referrer to global’s
+ // document's referrer. [spec text]
+ String referrer = delegate->GetDocumentReferrer();
+ if (referrer)
+ init->setReferrer(referrer);
+
+ // Step 4. Set violation’s status to the HTTP status code for the resource
+ // associated with violation’s global object. [spec text]
+ base::Optional<uint16_t> status_code = delegate->GetStatusCode();
+ if (status_code)
+ init->setStatusCode(*status_code);
+
+ // If no source location is provided, use the source location from the
+ // |delegate|.
+ // Step 2. If the user agent is currently executing script, and can extract a
+ // source file’s URL, line number, and column number from the global, set
+ // violation’s source file, line number, and column number accordingly.
+ // [spec text]
if (!source_location)
- source_location = SourceLocation::Capture(context);
- if (source_location->LineNumber()) {
+ source_location = delegate->GetSourceLocation();
+ if (source_location && source_location->LineNumber()) {
KURL source = KURL(source_location->Url());
- init->setSourceFile(StripURLForUseInReport(context, source, redirect_status,
+ init->setSourceFile(StripURLForUseInReport(delegate->GetSecurityOrigin(),
+ source, redirect_status,
effective_type));
init->setLineNumber(source_location->LineNumber());
init->setColumnNumber(source_location->ColumnNumber());
@@ -1295,26 +1236,29 @@ void ContentSecurityPolicy::ReportViolation(
// TODO(lukasza): Support sending reports from OOPIFs -
// https://crbug.com/611232 (or move CSP child-src and frame-src checks to the
// browser process - see https://crbug.com/376522).
- if (!execution_context_ && !context_frame) {
+ if (!delegate_ && !context_frame) {
DCHECK(effective_type == DirectiveType::kChildSrc ||
effective_type == DirectiveType::kFrameSrc ||
effective_type == DirectiveType::kPluginTypes);
return;
}
- DCHECK((execution_context_ && !context_frame) ||
+ DCHECK((delegate_ && !context_frame) ||
((effective_type == DirectiveType::kFrameAncestors) && context_frame));
SecurityPolicyViolationEventInit* violation_data =
SecurityPolicyViolationEventInit::Create();
- // If we're processing 'frame-ancestors', use |contextFrame|'s execution
- // context to gather data. Otherwise, use the policy's execution context.
- ExecutionContext* relevant_context =
- context_frame ? context_frame->GetDocument() : execution_context_;
- DCHECK(relevant_context);
+ // If we're processing 'frame-ancestors', use the delegate for the
+ // |context_frame|'s document to gather data. Otherwise, use the policy's
+ // |delegate_|.
+ ContentSecurityPolicyDelegate* relevant_delegate =
+ context_frame
+ ? &context_frame->GetDocument()->GetContentSecurityPolicyDelegate()
+ : delegate_.Get();
+ DCHECK(relevant_delegate);
GatherSecurityPolicyViolationEventData(
- violation_data, relevant_context, directive_text, effective_type,
+ violation_data, relevant_delegate, directive_text, effective_type,
blocked_url, header, redirect_status, header_type, violation_type,
std::move(source_location), source);
@@ -1323,24 +1267,17 @@ void ContentSecurityPolicy::ReportViolation(
// we should at least stop spamming reporting endpoints. See
// https://crbug.com/524356 for detail.
if (!violation_data->sourceFile().IsEmpty() &&
- ShouldBypassContentSecurityPolicy(KURL(violation_data->sourceFile()),
- execution_context_)) {
+ ShouldBypassContentSecurityPolicy(KURL(violation_data->sourceFile()))) {
return;
}
PostViolationReport(violation_data, context_frame, report_endpoints,
use_reporting_api);
- // Fire a violation event if we're working within an execution context (e.g.
- // we're not processing 'frame-ancestors').
- if (execution_context_) {
- execution_context_->GetTaskRunner(TaskType::kNetworking)
- ->PostTask(
- FROM_HERE,
- WTF::Bind(&ContentSecurityPolicy::DispatchViolationEvents,
- WrapPersistent(this), WrapPersistent(violation_data),
- WrapPersistent(element)));
- }
+ // Fire a violation event if we're working with a delegate (e.g. we're not
+ // processing 'frame-ancestors').
+ if (delegate_)
+ delegate_->DispatchViolationEvent(*violation_data, element);
}
void ContentSecurityPolicy::PostViolationReport(
@@ -1392,70 +1329,19 @@ void ContentSecurityPolicy::PostViolationReport(
if (ShouldSendViolationReport(stringified_report)) {
DidSendViolationReport(stringified_report);
- // TODO(mkwst): Support POSTing violation reports from a Worker.
- Document* document =
- context_frame ? context_frame->GetDocument() : this->GetDocument();
- if (!document)
- return;
-
- LocalFrame* frame = document->GetFrame();
- if (!frame)
- return;
-
- scoped_refptr<EncodedFormData> report =
- EncodedFormData::Create(stringified_report.Utf8());
-
- DEFINE_STATIC_LOCAL(ReportingServiceProxyPtrHolder,
- reporting_service_proxy_holder, ());
-
- for (const auto& report_endpoint : report_endpoints) {
- if (use_reporting_api) {
- reporting_service_proxy_holder.QueueCspViolationReport(
- document->Url(), report_endpoint, violation_data);
- } else {
- // If we have a context frame we're dealing with 'frame-ancestors' and
- // we don't have our own execution context. Use the frame's document to
- // complete the endpoint URL, overriding its URL with the blocked
- // document's URL.
- DCHECK(!context_frame || !execution_context_);
- DCHECK(!context_frame ||
- GetDirectiveType(violation_data->effectiveDirective()) ==
- DirectiveType::kFrameAncestors);
- KURL url =
- context_frame
- ? frame->GetDocument()->CompleteURLWithOverride(
- report_endpoint, KURL(violation_data->blockedURI()))
- // We use the FallbackBaseURL to ensure that we don't
- // respect base elements when determining the report
- // endpoint URL.
- : frame->GetDocument()->CompleteURLWithOverride(
- report_endpoint, frame->GetDocument()->FallbackBaseURL());
- PingLoader::SendViolationReport(
- frame, url, report,
- PingLoader::kContentSecurityPolicyViolationReport);
- }
- }
- }
-}
+ // If we're processing 'frame-ancestors', use the delegate for the
+ // |context_frame|'s document to post violation report. Otherwise, use the
+ // policy's |delegate_|.
+ bool is_frame_ancestors_violation = !!context_frame;
+ ContentSecurityPolicyDelegate* relevant_delegate =
+ is_frame_ancestors_violation
+ ? &context_frame->GetDocument()->GetContentSecurityPolicyDelegate()
+ : delegate_.Get();
+ DCHECK(relevant_delegate);
-void ContentSecurityPolicy::DispatchViolationEvents(
- const SecurityPolicyViolationEventInit* violation_data,
- Element* element) {
- // Worklets don't support Events in general.
- if (execution_context_->IsWorkletGlobalScope())
- return;
-
- SecurityPolicyViolationEvent& event = *SecurityPolicyViolationEvent::Create(
- event_type_names::kSecuritypolicyviolation, violation_data);
- DCHECK(event.bubbles());
-
- if (auto* document = DynamicTo<Document>(*execution_context_)) {
- if (element && element->isConnected() && element->GetDocument() == document)
- element->EnqueueEvent(event, TaskType::kInternalDefault);
- else
- document->EnqueueEvent(event, TaskType::kInternalDefault);
- } else if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_)) {
- scope->EnqueueEvent(event, TaskType::kInternalDefault);
+ relevant_delegate->PostViolationReport(*violation_data, stringified_report,
+ is_frame_ancestors_violation,
+ report_endpoints, use_reporting_api);
}
}
@@ -1645,15 +1531,16 @@ void ContentSecurityPolicy::LogToConsole(ConsoleMessage* console_message,
LocalFrame* frame) {
if (frame)
frame->GetDocument()->AddConsoleMessage(console_message);
- else if (execution_context_)
- execution_context_->AddConsoleMessage(console_message);
+ else if (delegate_)
+ delegate_->AddConsoleMessage(console_message);
else
console_messages_.push_back(console_message);
}
void ContentSecurityPolicy::ReportBlockedScriptExecutionToInspector(
const String& directive_text) const {
- probe::scriptExecutionBlockedByCSP(execution_context_, directive_text);
+ if (delegate_)
+ delegate_->ReportBlockedScriptExecutionToInspector(directive_text);
}
bool ContentSecurityPolicy::ExperimentalFeaturesEnabled() const {
@@ -1687,9 +1574,12 @@ bool ContentSecurityPolicy::ShouldBypassMainWorld(
if (!context)
return false;
- v8::Isolate* isolate = ToIsolate(context);
+ v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> v8_context = isolate->GetCurrentContext();
+
+ // This can be called before we enter v8, hence the context might be empty,
+ // which implies we are not in an isolated world.
if (v8_context.IsEmpty())
return false;
@@ -1864,24 +1754,22 @@ bool ContentSecurityPolicy::Subsumes(const ContentSecurityPolicy& other) const {
return policies_[0]->Subsumes(other_vector);
}
-// static
bool ContentSecurityPolicy::ShouldBypassContentSecurityPolicy(
const KURL& url,
- ExecutionContext* execution_context,
- SchemeRegistry::PolicyAreas area) {
+ SchemeRegistry::PolicyAreas area) const {
bool should_bypass_csp;
if (SecurityOrigin::ShouldUseInnerURL(url)) {
should_bypass_csp = SchemeRegistry::SchemeShouldBypassContentSecurityPolicy(
SecurityOrigin::ExtractInnerURL(url).Protocol(), area);
if (should_bypass_csp) {
- UseCounter::Count(execution_context, WebFeature::kInnerSchemeBypassesCSP);
+ Count(WebFeature::kInnerSchemeBypassesCSP);
}
} else {
should_bypass_csp = SchemeRegistry::SchemeShouldBypassContentSecurityPolicy(
url.Protocol(), area);
}
if (should_bypass_csp) {
- UseCounter::Count(execution_context, WebFeature::kSchemeBypassesCSP);
+ Count(WebFeature::kSchemeBypassesCSP);
}
return should_bypass_csp;
@@ -1949,4 +1837,9 @@ bool ContentSecurityPolicy::HasPolicyFromSource(
return false;
}
+void ContentSecurityPolicy::Count(WebFeature feature) const {
+ if (delegate_)
+ delegate_->Count(feature);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index 6d795e65bf7..2f70e785623 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -29,11 +29,12 @@
#include <memory>
#include <utility>
+#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/inspector/console_types.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -62,7 +63,9 @@ class CSPDirectiveList;
class CSPSource;
class Document;
class Element;
+class ExecutionContext;
class LocalFrameClient;
+class LocalFrame;
class KURL;
class ResourceRequest;
class SecurityOrigin;
@@ -76,6 +79,56 @@ typedef HeapVector<Member<ConsoleMessage>> ConsoleMessageVector;
typedef std::pair<String, ContentSecurityPolicyHeaderType> CSPHeaderAndType;
using RedirectStatus = ResourceRequest::RedirectStatus;
+// A delegate interface to implement violation reporting, support for some
+// directives and other miscellaneous functionality.
+class CORE_EXPORT ContentSecurityPolicyDelegate : public GarbageCollectedMixin {
+ public:
+ // Returns the SecurityOrigin this content security policy is bound to. Used
+ // for matching the 'self' keyword. Must return a non-null value.
+ // See https://w3c.github.io/webappsec-csp/#policy-self-origin.
+ virtual const SecurityOrigin* GetSecurityOrigin() = 0;
+
+ // Returns the URL this content security policy is bound to.
+ // Used for https://w3c.github.io/webappsec-csp/#violation-url and so.
+ // Note: Url() is used for several purposes that are specced slightly
+ // differently.
+ // See comments at the callers.
+ virtual const KURL& Url() const = 0;
+
+ // Directives support.
+ virtual void SetSandboxFlags(SandboxFlags) = 0;
+ virtual void SetAddressSpace(mojom::IPAddressSpace) = 0;
+ virtual void SetRequireTrustedTypes() = 0;
+ virtual void AddInsecureRequestPolicy(WebInsecureRequestPolicy) = 0;
+
+ // Violation reporting.
+
+ // See https://w3c.github.io/webappsec-csp/#create-violation-for-global.
+ // These functions are used to create the violation object.
+ virtual std::unique_ptr<SourceLocation> GetSourceLocation() = 0;
+ virtual base::Optional<uint16_t> GetStatusCode() = 0;
+ // If the Delegate is not bound to a document, a null string should be
+ // returned as the referrer.
+ virtual String GetDocumentReferrer() = 0;
+
+ virtual void DispatchViolationEvent(const SecurityPolicyViolationEventInit&,
+ Element*) = 0;
+ virtual void PostViolationReport(const SecurityPolicyViolationEventInit&,
+ const String& stringified_report,
+ bool is_frame_ancestors_violaton,
+ const Vector<String>& report_endpoints,
+ bool use_reporting_api) = 0;
+
+ virtual void Count(WebFeature) = 0;
+
+ virtual void AddConsoleMessage(ConsoleMessage*) = 0;
+ virtual void DisableEval(const String& error_message) = 0;
+ virtual void ReportBlockedScriptExecutionToInspector(
+ const String& directive_text) = 0;
+ virtual void DidAddContentSecurityPolicies(
+ const blink::WebVector<WebContentSecurityPolicy>&) = 0;
+};
+
class CORE_EXPORT ContentSecurityPolicy
: public GarbageCollectedFinalized<ContentSecurityPolicy> {
public:
@@ -139,12 +192,17 @@ class CORE_EXPORT ContentSecurityPolicy
static const size_t kMaxSampleLength = 40;
- static ContentSecurityPolicy* Create() { return new ContentSecurityPolicy(); }
+ static ContentSecurityPolicy* Create() {
+ return MakeGarbageCollected<ContentSecurityPolicy>();
+ }
+
+ ContentSecurityPolicy();
~ContentSecurityPolicy();
void Trace(blink::Visitor*);
- void BindToExecutionContext(ExecutionContext*);
+ void BindToDelegate(ContentSecurityPolicyDelegate&);
void SetupSelf(const SecurityOrigin&);
+ void SetupSelf(const ContentSecurityPolicy&);
void CopyStateFrom(const ContentSecurityPolicy*);
void CopyPluginTypesFrom(const ContentSecurityPolicy*);
@@ -399,10 +457,13 @@ class CORE_EXPORT ContentSecurityPolicy
void ReportBlockedScriptExecutionToInspector(
const String& directive_text) const;
- const KURL Url() const;
+ // Used as <object>'s URL when there is no `src` attribute.
+ const KURL FallbackUrlForPlugin() const;
+
void EnforceSandboxFlags(SandboxFlags);
void TreatAsPublicAddress();
void RequireTrustedTypes();
+ bool IsRequireTrustedTypes() const { return require_safe_types_; }
String EvalDisabledErrorMessage() const;
// Upgrade-Insecure-Requests and Block-All-Mixed-Content are represented in
@@ -424,10 +485,6 @@ class CORE_EXPORT ContentSecurityPolicy
CSPSource* GetSelfSource() const { return self_source_; }
static bool ShouldBypassMainWorld(const ExecutionContext*);
- static bool ShouldBypassContentSecurityPolicy(
- const KURL&,
- ExecutionContext*,
- SchemeRegistry::PolicyAreas = SchemeRegistry::kPolicyAreaAll);
static bool IsNonceableElement(const Element*);
@@ -446,8 +503,6 @@ class CORE_EXPORT ContentSecurityPolicy
// https://w3c.github.io/webappsec-csp/embedded/#subsume-policy
bool Subsumes(const ContentSecurityPolicy&) const;
- Document* GetDocument() const;
-
bool HasHeaderDeliveredPolicy() const { return header_delivered_; }
static bool IsValidCSPAttr(const String& attr,
@@ -487,6 +542,8 @@ class CORE_EXPORT ContentSecurityPolicy
directive_type == ContentSecurityPolicy::DirectiveType::kStyleSrcElem);
}
+ void Count(WebFeature feature) const;
+
private:
FRIEND_TEST_ALL_PREFIXES(ContentSecurityPolicyTest, NonceInline);
FRIEND_TEST_ALL_PREFIXES(ContentSecurityPolicyTest, NonceSinglePolicy);
@@ -498,9 +555,7 @@ class CORE_EXPORT ContentSecurityPolicy
FRIEND_TEST_ALL_PREFIXES(FrameFetchContextTest,
PopulateResourceRequestChecksReportOnlyCSP);
- ContentSecurityPolicy();
-
- void ApplyPolicySideEffectsToExecutionContext();
+ void ApplyPolicySideEffectsToDelegate();
void LogToConsole(const String& message, MessageLevel = kErrorMessageLevel);
@@ -510,8 +565,6 @@ class CORE_EXPORT ContentSecurityPolicy
bool ShouldSendViolationReport(const String&) const;
void DidSendViolationReport(const String&);
- void DispatchViolationEvents(const SecurityPolicyViolationEventInit*,
- Element*);
void PostViolationReport(const SecurityPolicyViolationEventInit*,
LocalFrame*,
const Vector<String>& report_endpoints,
@@ -530,7 +583,11 @@ class CORE_EXPORT ContentSecurityPolicy
const Member<CSPDirectiveList>&,
InlineType);
- Member<ExecutionContext> execution_context_;
+ bool ShouldBypassContentSecurityPolicy(
+ const KURL&,
+ SchemeRegistry::PolicyAreas = SchemeRegistry::kPolicyAreaAll) const;
+
+ Member<ContentSecurityPolicyDelegate> delegate_;
bool override_inline_style_allowed_;
CSPDirectiveListVector policies_;
ConsoleMessageVector console_messages_;
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index 0ff44e2659e..f6065a4d9e4 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -71,7 +71,7 @@ TEST_F(ContentSecurityPolicyTest, ParseInsecureRequestPolicy) {
execution_context = CreateExecutionContext();
execution_context->SetSecurityOrigin(secure_origin);
execution_context->SetURL(secure_url);
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_EQ(test.expected_policy,
execution_context->GetInsecureRequestPolicy());
bool expect_upgrade = test.expected_policy & kUpgradeInsecureRequests;
@@ -91,7 +91,7 @@ TEST_F(ContentSecurityPolicyTest, ParseInsecureRequestPolicy) {
execution_context = CreateExecutionContext();
execution_context->SetSecurityOrigin(secure_origin);
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_EQ(kLeaveInsecureRequestsAlone,
execution_context->GetInsecureRequestPolicy());
EXPECT_FALSE(execution_context->InsecureNavigationsToUpgrade()->Contains(
@@ -107,7 +107,7 @@ TEST_F(ContentSecurityPolicyTest, ParseEnforceTreatAsPublicAddressDisabled) {
csp->DidReceiveHeader("treat-as-public-address",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_EQ(mojom::IPAddressSpace::kPrivate, execution_context->AddressSpace());
}
@@ -119,7 +119,7 @@ TEST_F(ContentSecurityPolicyTest, ParseEnforceTreatAsPublicAddressEnabled) {
csp->DidReceiveHeader("treat-as-public-address",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_EQ(mojom::IPAddressSpace::kPublic, execution_context->AddressSpace());
}
@@ -224,7 +224,7 @@ TEST_F(ContentSecurityPolicyTest, IsActiveForConnectionsWithDefaultSrc) {
// Tests that frame-ancestors directives are discarded from policies
// delivered in <meta> elements.
TEST_F(ContentSecurityPolicyTest, FrameAncestorsInMeta) {
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("frame-ancestors 'none';",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceMeta);
@@ -238,7 +238,7 @@ TEST_F(ContentSecurityPolicyTest, FrameAncestorsInMeta) {
// Tests that sandbox directives are discarded from policies
// delivered in <meta> elements.
TEST_F(ContentSecurityPolicyTest, SandboxInMeta) {
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("sandbox;", kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceMeta);
EXPECT_FALSE(execution_context->GetSecurityOrigin()->IsOpaque());
@@ -270,7 +270,7 @@ TEST_F(ContentSecurityPolicyTest, ReportURIInMeta) {
// makes. https://crbug.com/603952
TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
const KURL url("https://example.test");
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("object-src 'none';",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceMeta);
@@ -290,7 +290,7 @@ TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
TEST_F(ContentSecurityPolicyTest, ConnectSrc) {
const KURL url("https://example.test");
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("connect-src 'none';",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceMeta);
@@ -323,7 +323,7 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderMissingIntegrity) {
const KURL url("https://example.test");
// Enforce
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -359,7 +359,7 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderMissingIntegrity) {
SecurityViolationReportingPolicy::kSuppressReporting));
// Report
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -402,10 +402,10 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderPresentIntegrity) {
IntegrityMetadataSet integrity_metadata;
integrity_metadata.insert(
IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
// Enforce
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -442,7 +442,7 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderPresentIntegrity) {
// Content-Security-Policy-Report-Only is not supported in meta element,
// so nothing should be blocked
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -484,7 +484,7 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaMissingIntegrity) {
const KURL url("https://example.test");
// Enforce
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceMeta);
@@ -521,7 +521,7 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaMissingIntegrity) {
// Content-Security-Policy-Report-Only is not supported in meta element,
// so nothing should be blocked
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceMeta);
@@ -564,10 +564,10 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaPresentIntegrity) {
IntegrityMetadataSet integrity_metadata;
integrity_metadata.insert(
IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
// Enforce
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceMeta);
@@ -604,7 +604,7 @@ TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaPresentIntegrity) {
// Content-Security-Policy-Report-Only is not supported in meta element,
// so nothing should be blocked
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader("require-sri-for script style",
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceMeta);
@@ -667,7 +667,8 @@ TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy) {
// Single enforce-mode policy should match `test.expected`:
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(
+ execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(test.policy,
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -680,7 +681,8 @@ TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy) {
// Single report-mode policy should always be `true`:
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(
+ execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(test.policy,
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -727,7 +729,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
// Enforce 'script-src'
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(document);
+ policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(String("script-src ") + test.policy,
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -739,7 +741,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
// Enforce 'style-src'
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(document);
+ policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(String("style-src ") + test.policy,
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -751,7 +753,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
// Report 'script-src'
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(document);
+ policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(String("script-src ") + test.policy,
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -762,7 +764,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
// Report 'style-src'
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(document);
+ policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(String("style-src ") + test.policy,
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -832,7 +834,8 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
// Enforce / Report
Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(
+ execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(test.policy1,
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -854,7 +857,8 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
// Report / Enforce
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(
+ execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(test.policy1,
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -876,7 +880,8 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
// Enforce / Enforce
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(
+ execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(test.policy1,
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -893,7 +898,8 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
// Report / Report
policy = ContentSecurityPolicy::Create();
- policy->BindToExecutionContext(execution_context.Get());
+ policy->BindToDelegate(
+ execution_context->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(test.policy1,
kContentSecurityPolicyHeaderTypeReport,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1051,7 +1057,7 @@ TEST_F(ContentSecurityPolicyTest, RequestsAllowedWhenBypassingCSP) {
execution_context = CreateExecutionContext();
execution_context->SetSecurityOrigin(secure_origin); // https://example.com
execution_context->SetURL(secure_url); // https://example.com
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("default-src https://example.com",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1091,7 +1097,7 @@ TEST_F(ContentSecurityPolicyTest, FilesystemAllowedWhenBypassingCSP) {
execution_context = CreateExecutionContext();
execution_context->SetSecurityOrigin(secure_origin); // https://example.com
execution_context->SetURL(secure_url); // https://example.com
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("default-src https://example.com",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1136,7 +1142,7 @@ TEST_F(ContentSecurityPolicyTest, BlobAllowedWhenBypassingCSP) {
execution_context = CreateExecutionContext();
execution_context->SetSecurityOrigin(secure_origin); // https://example.com
execution_context->SetURL(secure_url); // https://example.com
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("default-src https://example.com",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1179,7 +1185,7 @@ TEST_F(ContentSecurityPolicyTest, CSPBypassDisabledWhenSchemeIsPrivileged) {
execution_context = CreateExecutionContext();
execution_context->SetSecurityOrigin(secure_origin);
execution_context->SetURL(BlankURL());
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("script-src http://example.com",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1359,14 +1365,16 @@ TEST_F(ContentSecurityPolicyTest, IsValidCSPAttrTest) {
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesNoDirective) {
- csp->BindToExecutionContext(execution_context.Get());
+ execution_context->SetRequireTrustedTypesForTesting();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("", kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy"));
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesSimpleDirective) {
- csp->BindToExecutionContext(execution_context.Get());
+ execution_context->SetRequireTrustedTypesForTesting();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("trusted-types one two three",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1377,7 +1385,8 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypesSimpleDirective) {
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesWhitespace) {
- csp->BindToExecutionContext(execution_context.Get());
+ execution_context->SetRequireTrustedTypesForTesting();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1387,7 +1396,8 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypesWhitespace) {
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesEmpty) {
- csp->BindToExecutionContext(execution_context.Get());
+ execution_context->SetRequireTrustedTypesForTesting();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("trusted-types",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1395,7 +1405,8 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypesEmpty) {
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesStar) {
- csp->BindToExecutionContext(execution_context.Get());
+ execution_context->SetRequireTrustedTypesForTesting();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("trusted-types *",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1403,7 +1414,8 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypesStar) {
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesReserved) {
- csp->BindToExecutionContext(execution_context.Get());
+ execution_context->SetRequireTrustedTypesForTesting();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("trusted-types one \"two\" 'three'",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
@@ -1425,7 +1437,7 @@ TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
csp->DidReceiveHeader("sCrIpt-sRc http://example.com",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_TRUE(csp->AllowScriptFromSource(
example_url, String(), IntegrityMetadataSet(), kParserInserted));
@@ -1439,7 +1451,7 @@ TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
"SCRipt-SRC http://example.com; script-src http://not-example.com;",
kContentSecurityPolicyHeaderTypeEnforce,
kContentSecurityPolicyHeaderSourceHTTP);
- csp->BindToExecutionContext(execution_context.Get());
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_TRUE(csp->AllowScriptFromSource(
example_url, String(), IntegrityMetadataSet(), kParserInserted));
@@ -1447,4 +1459,74 @@ TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
not_example_url, String(), IntegrityMetadataSet(), kParserInserted));
}
+// Tests that using an empty CSP works and doesn't impose any policy
+// restrictions.
+TEST_F(ContentSecurityPolicyTest, EmptyCSPIsNoOp) {
+ csp = ContentSecurityPolicy::Create();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
+
+ const KURL example_url("http://example.com");
+ Document* document = Document::CreateForTest();
+ String source;
+ String context_url;
+ String nonce;
+ OrdinalNumber ordinal_number;
+ Element* element =
+ HTMLScriptElement::Create(*document, CreateElementFlags::ByParser());
+
+ EXPECT_TRUE(csp->Headers().IsEmpty());
+ EXPECT_TRUE(
+ csp->AllowJavaScriptURLs(element, source, context_url, ordinal_number));
+ EXPECT_TRUE(csp->AllowInlineEventHandler(element, source, context_url,
+ ordinal_number));
+ EXPECT_TRUE(csp->AllowEval(nullptr, SecurityViolationReportingPolicy::kReport,
+ ContentSecurityPolicy::kWillNotThrowException,
+ g_empty_string));
+ EXPECT_TRUE(csp->AllowWasmEval(
+ nullptr, SecurityViolationReportingPolicy::kReport,
+ ContentSecurityPolicy::kWillNotThrowException, g_empty_string));
+ EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
+ "application/x-type-1", example_url));
+ EXPECT_TRUE(csp->AllowPluginTypeForDocument(
+ *document, "application/x-type-1", "application/x-type-1", example_url,
+ SecurityViolationReportingPolicy::kSuppressReporting));
+ EXPECT_TRUE(csp->AllowObjectFromSource(example_url));
+ EXPECT_TRUE(csp->AllowPrefetchFromSource(example_url));
+ EXPECT_TRUE(csp->AllowFrameFromSource(example_url));
+ EXPECT_TRUE(csp->AllowImageFromSource(example_url));
+ EXPECT_TRUE(csp->AllowFontFromSource(example_url));
+ EXPECT_TRUE(csp->AllowMediaFromSource(example_url));
+ EXPECT_TRUE(csp->AllowConnectToSource(example_url));
+ EXPECT_TRUE(csp->AllowFormAction(example_url));
+ EXPECT_TRUE(csp->AllowBaseURI(example_url));
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy"));
+ EXPECT_TRUE(csp->AllowWorkerContextFromSource(example_url));
+ EXPECT_TRUE(csp->AllowManifestFromSource(example_url));
+ EXPECT_TRUE(csp->AllowScriptFromSource(
+ example_url, nonce, IntegrityMetadataSet(), kParserInserted));
+ EXPECT_TRUE(csp->AllowStyleFromSource(example_url, nonce));
+ EXPECT_TRUE(csp->AllowInlineScript(
+ element, context_url, nonce, ordinal_number, source,
+ ContentSecurityPolicy::InlineType::kBlock));
+ EXPECT_TRUE(csp->AllowInlineStyle(element, context_url, nonce, ordinal_number,
+ source,
+ ContentSecurityPolicy::InlineType::kBlock));
+ EXPECT_TRUE(csp->AllowAncestors(document->GetFrame(), example_url));
+ EXPECT_FALSE(csp->IsFrameAncestorsEnforced());
+ EXPECT_TRUE(csp->AllowRequestWithoutIntegrity(
+ mojom::RequestContextType::SCRIPT, example_url));
+ EXPECT_TRUE(csp->AllowRequest(mojom::RequestContextType::SCRIPT, example_url,
+ nonce, IntegrityMetadataSet(),
+ kParserInserted));
+ EXPECT_FALSE(csp->IsActive());
+ EXPECT_FALSE(csp->IsActiveForConnections());
+ EXPECT_TRUE(csp->FallbackUrlForPlugin().IsEmpty());
+ EXPECT_EQ(kLeaveInsecureRequestsAlone, csp->GetInsecureRequestPolicy());
+ EXPECT_FALSE(csp->HasHeaderDeliveredPolicy());
+ EXPECT_FALSE(csp->SupportsWasmEval());
+ EXPECT_EQ(kSandboxNone, csp->GetSandboxMask());
+ EXPECT_FALSE(
+ csp->HasPolicyFromSource(kContentSecurityPolicyHeaderSourceHTTP));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index 51884a11a96..0e3acb41065 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -96,7 +96,8 @@ CSPDirectiveList* CSPDirectiveList::Create(
ContentSecurityPolicyHeaderType type,
ContentSecurityPolicyHeaderSource source,
bool should_parse_wasm_eval) {
- CSPDirectiveList* directives = new CSPDirectiveList(policy, type, source);
+ CSPDirectiveList* directives =
+ MakeGarbageCollected<CSPDirectiveList>(policy, type, source);
directives->Parse(begin, end, should_parse_wasm_eval);
if (!directives->CheckEval(directives->OperativeDirective(
@@ -275,8 +276,10 @@ bool CSPDirectiveList::CheckSource(
// If |url| is empty, fall back to the policy URL to ensure that <object>'s
// without a `src` can be blocked/allowed, as they can still load plugins
// even though they don't actually have a URL.
- return !directive || directive->Allows(url.IsEmpty() ? policy_->Url() : url,
- redirect_status);
+ return !directive ||
+ directive->Allows(
+ url.IsEmpty() ? policy_->FallbackUrlForPlugin() : url,
+ redirect_status);
}
bool CSPDirectiveList::CheckAncestors(SourceListDirective* directive,
@@ -957,8 +960,7 @@ bool CSPDirectiveList::AllowBaseURI(
!CheckSource(
OperativeDirective(ContentSecurityPolicy::DirectiveType::kBaseURI),
url, redirect_status)) {
- UseCounter::Count(policy_->GetDocument(),
- WebFeature::kBaseWouldBeBlockedByDefaultSrc);
+ policy_->Count(WebFeature::kBaseWouldBeBlockedByDefaultSrc);
}
return result;
@@ -1121,7 +1123,7 @@ bool CSPDirectiveList::ParseDirective(const UChar* begin,
// The directive-name must be non-empty.
if (name_begin == position) {
// Malformed CSP: directive starts with invalid characters
- UseCounter::Count(policy_->GetDocument(), WebFeature::kMalformedCSP);
+ policy_->Count(WebFeature::kMalformedCSP);
SkipWhile<UChar, IsNotASCIISpace>(position, end);
policy_->ReportUnsupportedDirective(
@@ -1137,7 +1139,7 @@ bool CSPDirectiveList::ParseDirective(const UChar* begin,
if (!SkipExactly<UChar, IsASCIISpace>(position, end)) {
// Malformed CSP: after the directive name we don't have a space
- UseCounter::Count(policy_->GetDocument(), WebFeature::kMalformedCSP);
+ policy_->Count(WebFeature::kMalformedCSP);
SkipWhile<UChar, IsNotASCIISpace>(position, end);
policy_->ReportUnsupportedDirective(
@@ -1152,7 +1154,7 @@ bool CSPDirectiveList::ParseDirective(const UChar* begin,
if (position != end) {
// Malformed CSP: directive value has invalid characters
- UseCounter::Count(policy_->GetDocument(), WebFeature::kMalformedCSP);
+ policy_->Count(WebFeature::kMalformedCSP);
policy_->ReportInvalidDirectiveValueCharacter(
*name, String(value_begin, static_cast<wtf_size_t>(end - value_begin)));
@@ -1256,33 +1258,56 @@ void CSPDirectiveList::ParseReportURI(const String& name, const String& value) {
ParseAndAppendReportEndpoints(value);
}
+// For "report-uri" directive, this method corresponds to:
+// https://w3c.github.io/webappsec-csp/#report-violation
+// Step 3.4.2. For each token returned by splitting a string on ASCII whitespace
+// with directive's value as the input. [spec text]
+
+// For "report-to" directive, the spec says |value| is a single token
+// but we use the same logic as "report-uri" and thus we split |value| by
+// ASCII whitespaces.
+// https://w3c.github.io/webappsec-csp/#directive-report-to
+//
+// TODO(https://crbug.com/916265): Fix this inconsistency.
void CSPDirectiveList::ParseAndAppendReportEndpoints(const String& value) {
Vector<UChar> characters;
value.AppendTo(characters);
+ // https://infra.spec.whatwg.org/#split-on-ascii-whitespace
+
+ // Step 2. Let tokens be a list of strings, initially empty. [spec text]
+ DCHECK(report_endpoints_.IsEmpty());
+
const UChar* position = characters.data();
const UChar* end = position + characters.size();
+ // Step 4. While position is not past the end of input: [spec text]
while (position < end) {
+ // Step 3. Skip ASCII whitespace within input given position. [spec text]
+ // Step 4.3. Skip ASCII whitespace within input given position. [spec text]
+ //
+ // Note: IsASCIISpace returns true for U+000B which is not included in
+ // https://infra.spec.whatwg.org/#ascii-whitespace.
+ // TODO(mkwst): Investigate why the restrictions in the infra spec are
+ // different than those in Blink here.
SkipWhile<UChar, IsASCIISpace>(position, end);
+ // Step 4.1. Let token be the result of collecting a sequence of code points
+ // that are not ASCII whitespace from input, given position. [spec text]
const UChar* endpoint_begin = position;
SkipWhile<UChar, IsNotASCIISpace>(position, end);
if (endpoint_begin < position) {
+ // Step 4.2. Append token to tokens. [spec text]
String endpoint = String(
endpoint_begin, static_cast<wtf_size_t>(position - endpoint_begin));
report_endpoints_.push_back(endpoint);
}
}
- if (report_endpoints_.size() > 1) {
- UseCounter::Count(policy_->GetDocument(),
- WebFeature::kReportUriMultipleEndpoints);
- } else {
- UseCounter::Count(policy_->GetDocument(),
- WebFeature::kReportUriSingleEndpoint);
- }
+ policy_->Count(report_endpoints_.size() > 1
+ ? WebFeature::kReportUriMultipleEndpoints
+ : WebFeature::kReportUriSingleEndpoint);
}
template <class CSPDirectiveType>
@@ -1304,7 +1329,7 @@ void CSPDirectiveList::SetCSPDirective(const String& name,
return;
}
- directive = new CSPDirectiveType(name, value, policy_);
+ directive = MakeGarbageCollected<CSPDirectiveType>(name, value, policy_);
}
void CSPDirectiveList::ApplySandboxPolicy(const String& name,
@@ -1360,7 +1385,8 @@ void CSPDirectiveList::RequireTrustedTypes(const String& name,
return;
}
policy_->RequireTrustedTypes();
- trusted_types_ = new StringListDirective(name, value, policy_);
+ trusted_types_ =
+ MakeGarbageCollected<StringListDirective>(name, value, policy_);
}
void CSPDirectiveList::EnforceStrictMixedContentChecking(const String& name,
@@ -1473,12 +1499,11 @@ void CSPDirectiveList::AddDirective(const String& name, const String& value) {
} else if (type == ContentSecurityPolicy::DirectiveType::kReportTo &&
base::FeatureList::IsEnabled(network::features::kReporting)) {
ParseReportTo(name, value);
+ } else if (type == ContentSecurityPolicy::DirectiveType::kTrustedTypes) {
+ RequireTrustedTypes(name, value);
} else if (policy_->ExperimentalFeaturesEnabled()) {
if (type == ContentSecurityPolicy::DirectiveType::kRequireSRIFor) {
ParseRequireSRIFor(name, value);
- } else if (type == ContentSecurityPolicy::DirectiveType::kTrustedTypes &&
- RuntimeEnabledFeatures::TrustedDOMTypesEnabled()) {
- RequireTrustedTypes(name, value);
} else if (type == ContentSecurityPolicy::DirectiveType::kPrefetchSrc) {
SetCSPDirective<SourceListDirective>(name, value, prefetch_src_);
} else {
@@ -1702,7 +1727,8 @@ bool CSPDirectiveList::Subsumes(const CSPDirectiveListVector& other) {
WebContentSecurityPolicy CSPDirectiveList::ExposeForNavigationalChecks() const {
WebContentSecurityPolicy policy;
- policy.disposition = static_cast<WebContentSecurityPolicyType>(header_type_);
+ policy.disposition =
+ static_cast<mojom::ContentSecurityPolicyType>(header_type_);
policy.source = static_cast<WebContentSecurityPolicySource>(header_source_);
std::vector<WebContentSecurityPolicyDirective> directives;
for (const auto& directive :
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
index 99967718d25..c56732b6d0b 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
@@ -38,6 +38,10 @@ class CORE_EXPORT CSPDirectiveList
ContentSecurityPolicyHeaderSource,
bool should_parse_wasm_eval = false);
+ CSPDirectiveList(ContentSecurityPolicy*,
+ ContentSecurityPolicyHeaderType,
+ ContentSecurityPolicyHeaderSource);
+
void Parse(const UChar* begin,
const UChar* end,
bool should_parse_wasm_eval = false);
@@ -207,10 +211,6 @@ class CORE_EXPORT CSPDirectiveList
enum RequireSRIForToken { kNone = 0, kScript = 1 << 0, kStyle = 1 << 1 };
- CSPDirectiveList(ContentSecurityPolicy*,
- ContentSecurityPolicyHeaderType,
- ContentSecurityPolicyHeaderSource);
-
bool ParseDirective(const UChar* begin,
const UChar* end,
String* name,
@@ -380,6 +380,14 @@ class CORE_EXPORT CSPDirectiveList
uint8_t require_sri_for_;
+ // If a "report-to" directive is used:
+ // - |report_endpoints_| is a list of token parsed from the "report-to"
+ // directive's value, and
+ // - |use_reporting_api_| is true.
+ // Otherwise,
+ // - |report_endpoints_| is a list of uri-reference parsed from a
+ // "report-uri" directive's value if any, and
+ // - |use_reporting_api_| is false.
Vector<String> report_endpoints_;
bool use_reporting_api_;
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc
index e458082a84f..85264b2a20f 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc
@@ -30,6 +30,15 @@ CSPSource::CSPSource(ContentSecurityPolicy* policy,
host_wildcard_(host_wildcard),
port_wildcard_(port_wildcard) {}
+CSPSource::CSPSource(ContentSecurityPolicy* policy, const CSPSource& other)
+ : CSPSource(policy,
+ other.scheme_,
+ other.host_,
+ other.port_,
+ other.path_,
+ other.host_wildcard_,
+ other.port_wildcard_) {}
+
bool CSPSource::Matches(const KURL& url,
ResourceRequest::RedirectStatus redirect_status) const {
SchemeMatchingResult schemes_match = SchemeMatches(url.Protocol());
@@ -104,7 +113,6 @@ CSPSource::SchemeMatchingResult CSPSource::SchemeMatches(
}
bool CSPSource::HostMatches(const String& host) const {
- Document* document = policy_->GetDocument();
bool match;
bool equal_hosts = host_ == host;
@@ -121,10 +129,8 @@ bool CSPSource::HostMatches(const String& host) const {
// the following count measures when a match fails that would have
// passed the old, incorrect style, in case a lot of sites were
// relying on that behavior.
- if (document && equal_hosts) {
- UseCounter::Count(*document,
- WebFeature::kCSPSourceWildcardWouldMatchExactHost);
- }
+ if (equal_hosts)
+ policy_->Count(WebFeature::kCSPSourceWildcardWouldMatchExactHost);
} else {
// host-part = 1*host-char *( "." 1*host-char )
match = equal_hosts;
@@ -137,7 +143,8 @@ bool CSPSource::PathMatches(const String& url_path) const {
if (path_.IsEmpty() || (path_ == "/" && url_path.IsEmpty()))
return true;
- String path = DecodeURLEscapeSequences(url_path);
+ String path =
+ DecodeURLEscapeSequences(url_path, DecodeURLMode::kUTF8OrIsomorphic);
if (path_.EndsWith("/"))
return path.StartsWith(path_);
@@ -234,9 +241,9 @@ CSPSource* CSPSource::Intersect(CSPSource* other) const {
: other->scheme_;
if (IsSchemeOnly() || other->IsSchemeOnly()) {
const CSPSource* stricter = IsSchemeOnly() ? other : this;
- return new CSPSource(policy_, scheme, stricter->host_, stricter->port_,
- stricter->path_, stricter->host_wildcard_,
- stricter->port_wildcard_);
+ return MakeGarbageCollected<CSPSource>(
+ policy_, scheme, stricter->host_, stricter->port_, stricter->path_,
+ stricter->host_wildcard_, stricter->port_wildcard_);
}
String host = host_wildcard_ == kNoWildcard ? host_ : other->host_;
@@ -253,8 +260,8 @@ CSPSource* CSPSource::Intersect(CSPSource* other) const {
(host_wildcard_ == kHasWildcard) ? other->host_wildcard_ : host_wildcard_;
WildcardDisposition port_wildcard =
(port_wildcard_ == kHasWildcard) ? other->port_wildcard_ : port_wildcard_;
- return new CSPSource(policy_, scheme, host, port, path, host_wildcard,
- port_wildcard);
+ return MakeGarbageCollected<CSPSource>(policy_, scheme, host, port, path,
+ host_wildcard, port_wildcard);
}
bool CSPSource::IsSchemeOnly() const {
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h
index 937d6a507cd..b749204b167 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h
@@ -44,8 +44,9 @@ class CORE_EXPORT CSPSource : public GarbageCollectedFinalized<CSPSource> {
const String& path,
WildcardDisposition host_wildcard,
WildcardDisposition port_wildcard);
+ CSPSource(ContentSecurityPolicy* policy, const CSPSource& other);
bool IsSchemeOnly() const;
- const String& GetScheme() { return scheme_; };
+ const String& GetScheme() { return scheme_; }
bool Matches(const KURL&,
ResourceRequest::RedirectStatus =
ResourceRequest::RedirectStatus::kNoRedirect) const;
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
index 76f21801b0f..529f86d11c2 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
@@ -306,11 +306,11 @@ TEST_F(CSPSourceTest, DoesNotSubsume) {
{{"http", "example.com", "/", 443}, {"about", "example.com", "/", 800}},
};
for (const auto& test : cases) {
- CSPSource* returned = new CSPSource(
+ CSPSource* returned = MakeGarbageCollected<CSPSource>(
csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* required = new CSPSource(
+ CSPSource* required = MakeGarbageCollected<CSPSource>(
csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
@@ -362,11 +362,11 @@ TEST_F(CSPSourceTest, Subsumes) {
};
for (const auto& test : cases) {
- CSPSource* returned = new CSPSource(
+ CSPSource* returned = MakeGarbageCollected<CSPSource>(
csp.Get(), test.a.scheme, "example.com", test.a.port, test.a.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* required = new CSPSource(
+ CSPSource* required = MakeGarbageCollected<CSPSource>(
csp.Get(), test.b.scheme, "example.com", test.b.port, test.b.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
@@ -378,10 +378,10 @@ TEST_F(CSPSourceTest, Subsumes) {
// When returned CSP has a wildcard but the required csp doesn't, then it is
// not subsumed.
for (const auto& test : cases) {
- CSPSource* returned = new CSPSource(
+ CSPSource* returned = MakeGarbageCollected<CSPSource>(
csp.Get(), test.a.scheme, "example.com", test.a.port, test.a.path,
CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- CSPSource* required = new CSPSource(
+ CSPSource* required = MakeGarbageCollected<CSPSource>(
csp.Get(), test.b.scheme, "example.com", test.b.port, test.b.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
@@ -389,7 +389,7 @@ TEST_F(CSPSourceTest, Subsumes) {
// If required csp also allows a wildcard in host, then the answer should be
// as expected.
- CSPSource* required2 = new CSPSource(
+ CSPSource* required2 = MakeGarbageCollected<CSPSource>(
csp.Get(), test.b.scheme, "example.com", test.b.port, test.b.path,
CSPSource::kHasWildcard, CSPSource::kNoWildcard);
EXPECT_EQ(required2->Subsumes(returned), test.expected);
@@ -460,19 +460,19 @@ TEST_F(CSPSourceTest, WildcardsSubsumes) {
// There are different cases for wildcards but now also the second CSPSource
// has a more specific path.
for (const auto& test : cases) {
- CSPSource* returned =
- new CSPSource(csp.Get(), "http", "example.com", 0, "/",
- test.a.host_dispotion, test.a.port_dispotion);
- CSPSource* required =
- new CSPSource(csp.Get(), "http", "example.com", 0, "/",
- test.b.host_dispotion, test.b.port_dispotion);
+ CSPSource* returned = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "example.com", 0, "/", test.a.host_dispotion,
+ test.a.port_dispotion);
+ CSPSource* required = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "example.com", 0, "/", test.b.host_dispotion,
+ test.b.port_dispotion);
EXPECT_EQ(required->Subsumes(returned), test.expected);
// Wildcards should not matter when required csp is stricter than returned
// csp.
- CSPSource* required2 =
- new CSPSource(csp.Get(), "https", "example.com", 0, "/",
- test.b.host_dispotion, test.b.port_dispotion);
+ CSPSource* required2 = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "https", "example.com", 0, "/", test.b.host_dispotion,
+ test.b.port_dispotion);
EXPECT_FALSE(required2->Subsumes(returned));
}
}
@@ -500,12 +500,12 @@ TEST_F(CSPSourceTest, SchemesOnlySubsumes) {
};
for (const auto& test : cases) {
- CSPSource* returned =
- new CSPSource(csp.Get(), test.a_scheme, "example.com", 0, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* required =
- new CSPSource(csp.Get(), test.b_scheme, "example.com", 0, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+ CSPSource* returned = MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.a_scheme, "example.com", 0, "/", CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard);
+ CSPSource* required = MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.b_scheme, "example.com", 0, "/", CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard);
EXPECT_EQ(required->Subsumes(returned), test.expected);
}
}
@@ -603,11 +603,11 @@ TEST_F(CSPSourceTest, IsSimilar) {
};
for (const auto& test : cases) {
- CSPSource* returned = new CSPSource(
+ CSPSource* returned = MakeGarbageCollected<CSPSource>(
csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* required = new CSPSource(
+ CSPSource* required = MakeGarbageCollected<CSPSource>(
csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
CSPSource::kNoWildcard, CSPSource::kNoWildcard);
@@ -645,24 +645,24 @@ TEST_F(CSPSourceTest, FirstSubsumesSecond) {
{{"http", "second-example.com", 0, "/"}, "https", false},
};
- CSPSource* no_wildcards =
- new CSPSource(csp.Get(), "http", "example.com", 0, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* host_wildcard =
- new CSPSource(csp.Get(), "http", "third-example.com", 0, "/",
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- CSPSource* port_wildcard =
- new CSPSource(csp.Get(), "http", "third-example.com", 0, "/",
- CSPSource::kNoWildcard, CSPSource::kHasWildcard);
- CSPSource* both_wildcards =
- new CSPSource(csp.Get(), "http", "third-example.com", 0, "/",
- CSPSource::kHasWildcard, CSPSource::kHasWildcard);
- CSPSource* http_only =
- new CSPSource(csp.Get(), "http", "", 0, "", CSPSource::kNoWildcard,
- CSPSource::kNoWildcard);
- CSPSource* https_only =
- new CSPSource(csp.Get(), "https", "", 0, "", CSPSource::kNoWildcard,
- CSPSource::kNoWildcard);
+ CSPSource* no_wildcards = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "example.com", 0, "/", CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard);
+ CSPSource* host_wildcard = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "third-example.com", 0, "/", CSPSource::kHasWildcard,
+ CSPSource::kNoWildcard);
+ CSPSource* port_wildcard = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "third-example.com", 0, "/", CSPSource::kNoWildcard,
+ CSPSource::kHasWildcard);
+ CSPSource* both_wildcards = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "third-example.com", 0, "/", CSPSource::kHasWildcard,
+ CSPSource::kHasWildcard);
+ CSPSource* http_only = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "http", "", 0, "", CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard);
+ CSPSource* https_only = MakeGarbageCollected<CSPSource>(
+ csp.Get(), "https", "", 0, "", CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard);
for (const auto& test : cases) {
// Setup default vectors.
@@ -674,12 +674,12 @@ TEST_F(CSPSourceTest, FirstSubsumesSecond) {
list_a.push_back(no_wildcards);
// Add CSPSources based on the current test.
- list_b.push_back(new CSPSource(
+ list_b.push_back(MakeGarbageCollected<CSPSource>(
csp.Get(), test.source_b.scheme, test.source_b.host, 0,
test.source_b.path, CSPSource::kNoWildcard, CSPSource::kNoWildcard));
- list_a.push_back(
- new CSPSource(csp.Get(), test.scheme_a, "second-example.com", 0, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard));
+ list_a.push_back(MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.scheme_a, "second-example.com", 0, "/",
+ CSPSource::kNoWildcard, CSPSource::kNoWildcard));
// listB contains: ["http://example.com/", test.listB]
// listA contains: ["http://example.com/",
// test.schemeA + "://second-example.com/"]
@@ -809,12 +809,12 @@ TEST_F(CSPSourceTest, Intersect) {
};
for (const auto& test : cases) {
- CSPSource* a =
- new CSPSource(csp.Get(), test.a.scheme, test.a.host, test.a.port,
- test.a.path, test.a.host_wildcard, test.a.port_wildcard);
- CSPSource* b =
- new CSPSource(csp.Get(), test.b.scheme, test.b.host, test.b.port,
- test.b.path, test.b.host_wildcard, test.b.port_wildcard);
+ CSPSource* a = MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
+ test.a.host_wildcard, test.a.port_wildcard);
+ CSPSource* b = MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
+ test.b.host_wildcard, test.b.port_wildcard);
CSPSource* normalized = a->Intersect(b);
Source intersect_ab = {
@@ -885,13 +885,13 @@ TEST_F(CSPSourceTest, IntersectSchemesOnly) {
};
for (const auto& test : cases) {
- CSPSource* a =
- new CSPSource(csp.Get(), test.a.scheme, test.a.host, test.a.port,
- test.a.path, test.a.host_wildcard, test.a.port_wildcard);
+ CSPSource* a = MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
+ test.a.host_wildcard, test.a.port_wildcard);
- CSPSource* b =
- new CSPSource(csp.Get(), test.b.scheme, test.b.host, test.b.port,
- test.b.path, test.b.host_wildcard, test.b.port_wildcard);
+ CSPSource* b = MakeGarbageCollected<CSPSource>(
+ csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
+ test.b.host_wildcard, test.b.port_wildcard);
CSPSource* normalized = a->Intersect(b);
Source intersect_ab = {
@@ -1020,7 +1020,7 @@ TEST_F(CSPSourceTest, MatchingAsSelf) {
KURL base;
for (const auto& test : cases) {
- CSPSource* self_source = new CSPSource(
+ CSPSource* self_source = MakeGarbageCollected<CSPSource>(
csp.Get(), test.self_source.scheme, test.self_source.host,
test.self_source.port, test.self_source.path,
test.self_source.host_wildcard, test.self_source.port_wildcard);
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc b/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
new file mode 100644
index 00000000000..9fa20c76811
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
@@ -0,0 +1,254 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/events/security_policy_violation_event.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/ping_loader.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
+#include "third_party/blink/renderer/platform/weborigin/reporting_service_proxy_ptr_holder.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+
+namespace blink {
+
+ExecutionContextCSPDelegate::ExecutionContextCSPDelegate(
+ ExecutionContext& execution_context)
+ : execution_context_(&execution_context) {}
+
+void ExecutionContextCSPDelegate::Trace(blink::Visitor* visitor) {
+ visitor->Trace(execution_context_);
+ ContentSecurityPolicyDelegate::Trace(visitor);
+}
+
+const SecurityOrigin* ExecutionContextCSPDelegate::GetSecurityOrigin() {
+ return execution_context_->GetSecurityOrigin();
+}
+
+const KURL& ExecutionContextCSPDelegate::Url() const {
+ return execution_context_->Url();
+}
+
+void ExecutionContextCSPDelegate::SetSandboxFlags(SandboxFlags mask) {
+ GetSecurityContext().EnforceSandboxFlags(mask);
+}
+
+void ExecutionContextCSPDelegate::SetAddressSpace(mojom::IPAddressSpace space) {
+ GetSecurityContext().SetAddressSpace(space);
+}
+
+void ExecutionContextCSPDelegate::SetRequireTrustedTypes() {
+ if (origin_trials::TrustedDOMTypesEnabled(execution_context_))
+ GetSecurityContext().SetRequireTrustedTypes();
+}
+
+void ExecutionContextCSPDelegate::AddInsecureRequestPolicy(
+ WebInsecureRequestPolicy policy) {
+ SecurityContext& security_context = GetSecurityContext();
+
+ Document* document = GetDocument();
+
+ // Step 2. Set settings’s insecure requests policy to Upgrade. [spec text]
+ // Upgrade Insecure Requests: Update the policy.
+ security_context.SetInsecureRequestPolicy(
+ security_context.GetInsecureRequestPolicy() | policy);
+ if (document)
+ document->DidEnforceInsecureRequestPolicy();
+
+ // Upgrade Insecure Requests: Update the set of insecure URLs to upgrade.
+ if (policy & kUpgradeInsecureRequests) {
+ // Spec: Enforcing part of:
+ // https://w3c.github.io/webappsec-upgrade-insecure-requests/#delivery
+ // Step 3. Let tuple be a tuple of the protected resource’s URL's host and
+ // port. [spec text]
+ // Step 4. Insert tuple into settings’s upgrade insecure navigations set.
+ // [spec text]
+ Count(WebFeature::kUpgradeInsecureRequestsEnabled);
+ if (!Url().Host().IsEmpty()) {
+ uint32_t hash = Url().Host().Impl()->GetHash();
+ security_context.AddInsecureNavigationUpgrade(hash);
+ if (document)
+ document->DidEnforceInsecureNavigationsSet();
+ }
+ }
+}
+
+std::unique_ptr<SourceLocation>
+ExecutionContextCSPDelegate::GetSourceLocation() {
+ return SourceLocation::Capture(execution_context_);
+}
+
+base::Optional<uint16_t> ExecutionContextCSPDelegate::GetStatusCode() {
+ base::Optional<uint16_t> status_code;
+
+ // TODO(mkwst): We only have status code information for Documents. It would
+ // be nice to get them for Workers as well.
+ Document* document = GetDocument();
+ if (document && !SecurityOrigin::IsSecure(document->Url()) &&
+ document->Loader()) {
+ status_code = document->Loader()->GetResponse().HttpStatusCode();
+ }
+
+ return status_code;
+}
+
+String ExecutionContextCSPDelegate::GetDocumentReferrer() {
+ String referrer;
+
+ // TODO(mkwst): We only have referrer information for Documents. It would be
+ // nice to get them for Workers as well.
+ if (Document* document = GetDocument())
+ referrer = document->referrer();
+ return referrer;
+}
+
+void ExecutionContextCSPDelegate::DispatchViolationEvent(
+ const SecurityPolicyViolationEventInit& violation_data,
+ Element* element) {
+ execution_context_->GetTaskRunner(TaskType::kNetworking)
+ ->PostTask(
+ FROM_HERE,
+ WTF::Bind(
+ &ExecutionContextCSPDelegate::DispatchViolationEventInternal,
+ WrapPersistent(this), WrapPersistent(&violation_data),
+ WrapPersistent(element)));
+}
+
+void ExecutionContextCSPDelegate::PostViolationReport(
+ const SecurityPolicyViolationEventInit& violation_data,
+ const String& stringified_report,
+ bool is_frame_ancestors_violation,
+ const Vector<String>& report_endpoints,
+ bool use_reporting_api) {
+ DCHECK_EQ(is_frame_ancestors_violation,
+ ContentSecurityPolicy::DirectiveType::kFrameAncestors ==
+ ContentSecurityPolicy::GetDirectiveType(
+ violation_data.effectiveDirective()));
+
+ // TODO(mkwst): Support POSTing violation reports from a Worker.
+ Document* document = GetDocument();
+ if (!document)
+ return;
+
+ LocalFrame* frame = document->GetFrame();
+ if (!frame)
+ return;
+
+ scoped_refptr<EncodedFormData> report =
+ EncodedFormData::Create(stringified_report.Utf8());
+
+ DEFINE_STATIC_LOCAL(ReportingServiceProxyPtrHolder,
+ reporting_service_proxy_holder, ());
+
+ for (const auto& report_endpoint : report_endpoints) {
+ if (use_reporting_api) {
+ // https://w3c.github.io/webappsec-csp/#report-violation
+ // Step 3.5. If violation’s policy’s directive set contains a directive
+ // named "report-to" (directive): [spec text]
+ //
+ // https://w3c.github.io/reporting/#queue-report
+ // Step 2. If url was not provided by the caller, let url be settings’s
+ // creation URL. [spec text]
+ reporting_service_proxy_holder.QueueCspViolationReport(
+ Url(), report_endpoint, &violation_data);
+ continue;
+ }
+
+ // Use the frame's document to complete the endpoint URL, overriding its URL
+ // with the blocked document's URL.
+ // https://w3c.github.io/webappsec-csp/#report-violation
+ // Step 3.4.2.1. Let endpoint be the result of executing the URL parser with
+ // token as the input, and violation’s url as the base URL. [spec text]
+ KURL url = is_frame_ancestors_violation
+ ? document->CompleteURLWithOverride(
+ report_endpoint, KURL(violation_data.blockedURI()))
+ // We use the FallbackBaseURL to ensure that we don't
+ // respect base elements when determining the report
+ // endpoint URL.
+ // Note: According to Step 3.4.2.1 mentioned above, the base
+ // URL is "violation’s url" which should be violation's
+ // global object's URL. So using FallbackBaseURL() might be
+ // inconsistent.
+ : document->CompleteURLWithOverride(
+ report_endpoint, document->FallbackBaseURL());
+ PingLoader::SendViolationReport(
+ frame, url, report, PingLoader::kContentSecurityPolicyViolationReport);
+ }
+}
+
+void ExecutionContextCSPDelegate::Count(WebFeature feature) {
+ UseCounter::Count(execution_context_, feature);
+}
+
+void ExecutionContextCSPDelegate::AddConsoleMessage(
+ ConsoleMessage* console_message) {
+ execution_context_->AddConsoleMessage(console_message);
+}
+
+void ExecutionContextCSPDelegate::DisableEval(const String& error_message) {
+ execution_context_->DisableEval(error_message);
+}
+
+void ExecutionContextCSPDelegate::ReportBlockedScriptExecutionToInspector(
+ const String& directive_text) {
+ probe::scriptExecutionBlockedByCSP(execution_context_, directive_text);
+}
+
+void ExecutionContextCSPDelegate::DidAddContentSecurityPolicies(
+ const blink::WebVector<WebContentSecurityPolicy>& policies) {
+ Document* document = GetDocument();
+ if (document && document->GetFrame())
+ document->GetFrame()->Client()->DidAddContentSecurityPolicies(policies);
+}
+
+SecurityContext& ExecutionContextCSPDelegate::GetSecurityContext() {
+ return execution_context_->GetSecurityContext();
+}
+
+Document* ExecutionContextCSPDelegate::GetDocument() {
+ return DynamicTo<Document>(execution_context_.Get());
+}
+
+void ExecutionContextCSPDelegate::DispatchViolationEventInternal(
+ const SecurityPolicyViolationEventInit* violation_data,
+ Element* element) {
+ // Worklets don't support Events in general.
+ if (execution_context_->IsWorkletGlobalScope())
+ return;
+
+ // https://w3c.github.io/webappsec-csp/#report-violation.
+ // Step 3.1. If target is not null, and global is a Window, and target’s
+ // shadow-including root is not global’s associated Document, set target to
+ // null. [spec text]
+ // Step 3.2. If target is null:
+ // Step 3.2.1. Set target be violation’s global object.
+ // Step 3.2.2. If target is a Window, set target to target’s associated
+ // Document. [spec text]
+ // Step 3.3. Fire an event named securitypolicyviolation that uses the
+ // SecurityPolicyViolationEvent interface at target.. [spec text]
+ SecurityPolicyViolationEvent& event = *SecurityPolicyViolationEvent::Create(
+ event_type_names::kSecuritypolicyviolation, violation_data);
+ DCHECK(event.bubbles());
+
+ if (auto* document = GetDocument()) {
+ if (element && element->isConnected() && element->GetDocument() == document)
+ element->EnqueueEvent(event, TaskType::kInternalDefault);
+ else
+ document->EnqueueEvent(event, TaskType::kInternalDefault);
+ } else if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_)) {
+ scope->EnqueueEvent(event, TaskType::kInternalDefault);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h b/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
new file mode 100644
index 00000000000..7ab27c24700
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_EXECUTION_CONTEXT_CSP_DELEGATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_EXECUTION_CONTEXT_CSP_DELEGATE_H_
+
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+
+namespace blink {
+
+class Document;
+class ExecutionContext;
+class SecurityContext;
+
+class ExecutionContextCSPDelegate final
+ : public GarbageCollected<ExecutionContextCSPDelegate>,
+ public ContentSecurityPolicyDelegate {
+ USING_GARBAGE_COLLECTED_MIXIN(ExecutionContextCSPDelegate);
+
+ public:
+ explicit ExecutionContextCSPDelegate(ExecutionContext&);
+
+ void Trace(blink::Visitor*) override;
+
+ // ContentSecurityPolicyDelegate overrides:
+ const SecurityOrigin* GetSecurityOrigin() override;
+ const KURL& Url() const override;
+ void SetSandboxFlags(SandboxFlags) override;
+ void SetAddressSpace(mojom::IPAddressSpace) override;
+ void SetRequireTrustedTypes() override;
+ void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override;
+ std::unique_ptr<SourceLocation> GetSourceLocation() override;
+ base::Optional<uint16_t> GetStatusCode() override;
+ String GetDocumentReferrer() override;
+ void DispatchViolationEvent(const SecurityPolicyViolationEventInit&,
+ Element*) override;
+ void PostViolationReport(const SecurityPolicyViolationEventInit&,
+ const String& stringified_report,
+ bool is_frame_ancestors_violation,
+ const Vector<String>& report_endpoints,
+ bool use_reporting_api) override;
+ void Count(WebFeature) override;
+ void AddConsoleMessage(ConsoleMessage*) override;
+ void DisableEval(const String& error_message) override;
+ void ReportBlockedScriptExecutionToInspector(
+ const String& directive_text) override;
+ void DidAddContentSecurityPolicies(
+ const blink::WebVector<WebContentSecurityPolicy>&) override;
+
+ private:
+ SecurityContext& GetSecurityContext();
+ Document* GetDocument();
+ void DispatchViolationEventInternal(const SecurityPolicyViolationEventInit*,
+ Element*);
+
+ const Member<ExecutionContext> execution_context_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_EXECUTION_CONTEXT_CSP_DELEGATE_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc
index cc8dd0e2062..273ee8147df 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc
@@ -165,8 +165,8 @@ void SourceListDirective::Parse(const UChar* begin, const UChar* end) {
if (ContentSecurityPolicy::GetDirectiveType(host) !=
ContentSecurityPolicy::DirectiveType::kUndefined)
policy_->ReportDirectiveAsSourceExpression(directive_name_, host);
- list_.push_back(new CSPSource(policy_, scheme, host, port, path,
- host_wildcard, port_wildcard));
+ list_.push_back(MakeGarbageCollected<CSPSource>(
+ policy_, scheme, host, port, path, host_wildcard, port_wildcard));
} else {
policy_->ReportInvalidSourceExpression(
directive_name_, String(begin_source, static_cast<wtf_size_t>(
@@ -568,7 +568,8 @@ bool SourceListDirective::ParsePath(const UChar* begin,
}
*path = DecodeURLEscapeSequences(
- String(begin, static_cast<wtf_size_t>(position - begin)));
+ String(begin, static_cast<wtf_size_t>(position - begin)),
+ DecodeURLMode::kUTF8OrIsomorphic);
DCHECK(position <= end);
DCHECK(position == end || (*position == '#' || *position == '?'));
@@ -695,19 +696,19 @@ HeapVector<Member<CSPSource>> SourceListDirective::GetSources(
Member<CSPSource> self) const {
HeapVector<Member<CSPSource>> sources = list_;
if (allow_star_) {
- sources.push_back(new CSPSource(policy_, "ftp", String(), 0, String(),
- CSPSource::kNoWildcard,
- CSPSource::kNoWildcard));
- sources.push_back(new CSPSource(policy_, "ws", String(), 0, String(),
- CSPSource::kNoWildcard,
- CSPSource::kNoWildcard));
- sources.push_back(new CSPSource(policy_, "http", String(), 0, String(),
- CSPSource::kNoWildcard,
- CSPSource::kNoWildcard));
+ sources.push_back(MakeGarbageCollected<CSPSource>(
+ policy_, "ftp", String(), 0, String(), CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard));
+ sources.push_back(MakeGarbageCollected<CSPSource>(
+ policy_, "ws", String(), 0, String(), CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard));
+ sources.push_back(MakeGarbageCollected<CSPSource>(
+ policy_, "http", String(), 0, String(), CSPSource::kNoWildcard,
+ CSPSource::kNoWildcard));
if (self) {
- sources.push_back(new CSPSource(policy_, self->GetScheme(), String(), 0,
- String(), CSPSource::kNoWildcard,
- CSPSource::kNoWildcard));
+ sources.push_back(MakeGarbageCollected<CSPSource>(
+ policy_, self->GetScheme(), String(), 0, String(),
+ CSPSource::kNoWildcard, CSPSource::kNoWildcard));
}
} else if (allow_self_ && self) {
sources.push_back(self);
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
index ff0b7139002..236e891d740 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
@@ -36,7 +36,7 @@ class SourceListDirectiveTest : public testing::Test {
SecurityOrigin::Create(secure_url));
document = Document::CreateForTest();
document->SetSecurityOrigin(secure_origin);
- csp->BindToExecutionContext(document.Get());
+ csp->BindToDelegate(document->GetContentSecurityPolicyDelegate());
}
ContentSecurityPolicy* SetUpWithOrigin(const String& origin) {
@@ -46,7 +46,7 @@ class SourceListDirectiveTest : public testing::Test {
Document* document = Document::CreateForTest();
document->SetSecurityOrigin(secure_origin);
ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
- csp->BindToExecutionContext(document);
+ csp->BindToDelegate(document->GetContentSecurityPolicyDelegate());
return csp;
}
diff --git a/chromium/third_party/blink/renderer/core/frame/dactyloscoper.cc b/chromium/third_party/blink/renderer/core/frame/dactyloscoper.cc
new file mode 100644
index 00000000000..c384ff49f7c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/dactyloscoper.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/dactyloscoper.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+
+namespace blink {
+
+Dactyloscoper::Dactyloscoper() = default;
+
+void Dactyloscoper::Record(WebFeature feature) {
+ // TODO(mkwst): This is a stub. We'll pull in more interesting functionality
+ // here over time.
+}
+
+// static
+void Dactyloscoper::Record(ExecutionContext* context, WebFeature feature) {
+ // TODO: Workers.
+ if (!context)
+ return;
+ if (auto* document = DynamicTo<Document>(context)) {
+ if (DocumentLoader* loader = document->Loader())
+ loader->GetDactyloscoper().Record(feature);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/dactyloscoper.h b/chromium/third_party/blink/renderer/core/frame/dactyloscoper.h
new file mode 100644
index 00000000000..d0796ca2753
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/dactyloscoper.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DACTYLOSCOPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DACTYLOSCOPER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class ExecutionContext;
+
+class CORE_EXPORT Dactyloscoper {
+ DISALLOW_NEW();
+
+ public:
+ Dactyloscoper();
+
+ void Record(WebFeature);
+
+ static void Record(ExecutionContext*, WebFeature);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Dactyloscoper);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DACTYLOSCOPER_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/deprecation.cc b/chromium/third_party/blink/renderer/core/frame/deprecation.cc
index e8a2f73bda7..b3e2678e41e 100644
--- a/chromium/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/chromium/third_party/blink/renderer/core/frame/deprecation.cc
@@ -173,18 +173,6 @@ String ReplacedWillBeRemoved(const char* feature,
feature, MilestoneString(milestone), replacement, details);
}
-String DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
- const char* function,
- const char* allow_string,
- Milestone milestone) {
- return String::Format(
- "%s usage in cross-origin iframes is deprecated and will be disabled in "
- "%s. To continue to use this feature, it must be enabled by the "
- "embedding document using Feature Policy, e.g. "
- "<iframe allow=\"%s\" ...>. See https://goo.gl/EuHzyv for more details.",
- function, MilestoneString(milestone), allow_string);
-}
-
DeprecationInfo GetDeprecationInfo(WebFeature feature) {
switch (feature) {
// Quota
@@ -479,39 +467,6 @@ DeprecationInfo GetDeprecationInfo(WebFeature feature) {
ReplacedWillBeRemoved(":unresolved pseudo selector", ":not(:defined)",
kM73, "4642138092470272")};
- case WebFeature::
- kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe:
- return {"EncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe",
- kM64,
- DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
- "requestMediaKeySystemAccess", "encrypted-media", kM64)};
-
- case WebFeature::kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe:
- return {"GeolocationDisallowedByFeaturePolicyInCrossOriginIframe", kM64,
- DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
- "getCurrentPosition and watchPosition", "geolocation", kM64)};
-
- case WebFeature::
- kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe:
- return {"GetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe",
- kM64,
- DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
- "getUserMedia (microphone)", "microphone", kM64)};
-
- case WebFeature::
- kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe:
- return {"GetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe",
- kM64,
- DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
- "getUserMedia (camera)", "camera", kM64)};
-
- case WebFeature::
- kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe:
- return {"RequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe",
- kM64,
- DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
- "requestMIDIAccess", "midi", kM64)};
-
case WebFeature::kPresentationRequestStartInsecureOrigin:
case WebFeature::kPresentationReceiverInsecureOrigin:
return {
@@ -592,12 +547,6 @@ DeprecationInfo GetDeprecationInfo(WebFeature feature) {
"5687444770914304 for more details",
MilestoneString(kM71))};
- case WebFeature::kPPAPIWebSocket:
- // TODO(ricea): Update once we have an expected release date for M74.
- return {"PPAPIWebSocket", kUnknown,
- "The Native Client Pepper WebSocket API is deprecated and will "
- "be disabled in M74, mid-2019"};
-
case WebFeature::kCacheStorageAddAllSuccessWithDuplicate:
return {"CacheStorageAddAllSuccessWithDuplicate", kM72,
WillBeRemoved("Cache.addAll() with duplicate requests", kM72,
@@ -754,58 +703,6 @@ void Deprecation::CountDeprecationCrossOriginIframe(const Document& document,
CountDeprecationCrossOriginIframe(frame, feature);
}
-void Deprecation::CountDeprecationFeaturePolicy(
- const Document& document,
- mojom::FeaturePolicyFeature feature) {
- LocalFrame* frame = document.GetFrame();
- if (!frame)
- return;
-
- // If the feature is allowed, don't log a warning.
- if (document.IsFeatureEnabled(feature))
- return;
-
- // If the feature is disabled, log a warning but only if the request is from a
- // cross-origin iframe. Ideally we would check here if the feature is actually
- // disabled due to the parent frame's policy (as opposed to the current frame
- // disabling the feature on itself) but that can't happen right now anyway
- // (until the general syntax is shipped) and this is also a good enough
- // approximation for deprecation messages.
- switch (feature) {
- case mojom::FeaturePolicyFeature::kEncryptedMedia:
- CountDeprecationCrossOriginIframe(
- frame,
- WebFeature::
- kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe);
- break;
- case mojom::FeaturePolicyFeature::kGeolocation:
- CountDeprecationCrossOriginIframe(
- frame,
- WebFeature::kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe);
- break;
- case mojom::FeaturePolicyFeature::kMicrophone:
- CountDeprecationCrossOriginIframe(
- frame,
- WebFeature::
- kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe);
- break;
- case mojom::FeaturePolicyFeature::kCamera:
- CountDeprecationCrossOriginIframe(
- frame,
- WebFeature::
- kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe);
- break;
- case mojom::FeaturePolicyFeature::kMidiFeature:
- CountDeprecationCrossOriginIframe(
- frame,
- WebFeature::
- kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe);
- break;
- default:
- NOTREACHED();
- }
-}
-
void Deprecation::GenerateReport(const LocalFrame* frame, WebFeature feature) {
DeprecationInfo info = GetDeprecationInfo(feature);
diff --git a/chromium/third_party/blink/renderer/core/frame/deprecation.h b/chromium/third_party/blink/renderer/core/frame/deprecation.h
index 6cc1eff3385..dbdc93beedf 100644
--- a/chromium/third_party/blink/renderer/core/frame/deprecation.h
+++ b/chromium/third_party/blink/renderer/core/frame/deprecation.h
@@ -49,9 +49,6 @@ class CORE_EXPORT Deprecation {
static void CountDeprecationCrossOriginIframe(const LocalFrame*, WebFeature);
static void CountDeprecationCrossOriginIframe(const Document&, WebFeature);
- static void CountDeprecationFeaturePolicy(const Document&,
- mojom::FeaturePolicyFeature);
-
static String DeprecationMessage(WebFeature);
// Note: this is only public for tests.
diff --git a/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc b/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc
index 632f5506bb2..2b4e3f2591c 100644
--- a/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc
@@ -25,8 +25,6 @@ TEST_F(DocumentLoadingRenderingTest,
LoadURL("https://example.com/test.html");
- main_resource.Start();
-
// Still in the head, should not resume commits.
main_resource.Write("<!DOCTYPE html>");
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
@@ -46,12 +44,11 @@ TEST_F(DocumentLoadingRenderingTest,
TEST_F(DocumentLoadingRenderingTest,
ShouldResumeCommitsAfterBodyIfSheetsLoaded) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
-
// Still in the head, should not resume commits.
main_resource.Write("<!DOCTYPE html><link rel=stylesheet href=test.css>");
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
@@ -76,12 +73,11 @@ TEST_F(DocumentLoadingRenderingTest,
TEST_F(DocumentLoadingRenderingTest, ShouldResumeCommitsAfterSheetsLoaded) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
-
// Still in the head, should not resume commits.
main_resource.Write("<!DOCTYPE html><link rel=stylesheet href=test.css>");
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
@@ -107,12 +103,11 @@ TEST_F(DocumentLoadingRenderingTest, ShouldResumeCommitsAfterSheetsLoaded) {
TEST_F(DocumentLoadingRenderingTest,
ShouldResumeCommitsAfterDocumentElementWithNoSheets) {
SimRequest main_resource("https://example.com/test.svg", "image/svg+xml");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.svg");
- main_resource.Start();
-
// Sheet loading and no documentElement, so don't resume.
main_resource.Write("<?xml-stylesheet type='text/css' href='test.css'?>");
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
@@ -132,12 +127,11 @@ TEST_F(DocumentLoadingRenderingTest,
TEST_F(DocumentLoadingRenderingTest, ShouldResumeCommitsAfterSheetsLoadForXml) {
SimRequest main_resource("https://example.com/test.svg", "image/svg+xml");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.svg");
- main_resource.Start();
-
// Not done parsing.
main_resource.Write("<?xml-stylesheet type='text/css' href='test.css'?>");
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
@@ -165,8 +159,6 @@ TEST_F(DocumentLoadingRenderingTest, ShouldResumeCommitsAfterFinishParsingXml) {
LoadURL("https://example.com/test.svg");
- main_resource.Start();
-
// Finish parsing, no sheets loading so resume.
main_resource.Finish();
EXPECT_FALSE(Compositor().DeferMainFrameUpdate());
@@ -177,7 +169,6 @@ TEST_F(DocumentLoadingRenderingTest, ShouldResumeImmediatelyForImageDocuments) {
LoadURL("https://example.com/test.png");
- main_resource.Start();
EXPECT_TRUE(Compositor().DeferMainFrameUpdate());
// Not really a valid image but enough for the test. ImageDocuments should
@@ -191,13 +182,13 @@ TEST_F(DocumentLoadingRenderingTest, ShouldResumeImmediatelyForImageDocuments) {
TEST_F(DocumentLoadingRenderingTest, ShouldScheduleFrameAfterSheetsLoaded) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest first_css_resource("https://example.com/first.css", "text/css");
- SimRequest second_css_resource("https://example.com/second.css", "text/css");
+ SimSubresourceRequest first_css_resource("https://example.com/first.css",
+ "text/css");
+ SimSubresourceRequest second_css_resource("https://example.com/second.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
-
// Load a stylesheet.
main_resource.Write(
"<!DOCTYPE html><link id=link rel=stylesheet href=first.css>");
@@ -228,11 +219,12 @@ TEST_F(DocumentLoadingRenderingTest,
ShouldNotPaintIframeContentWithPendingSheets) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/frame.html", "text/html");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
main_resource.Complete(R"HTML(
<!DOCTYPE html>
@@ -313,11 +305,12 @@ TEST_F(DocumentLoadingRenderingTest,
ShouldThrottleIframeLifecycleUntilPendingSheetsLoaded) {
SimRequest main_resource("https://example.com/main.html", "text/html");
SimRequest frame_resource("https://example.com/frame.html", "text/html");
- SimRequest css_resource("https://example.com/frame.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/frame.css",
+ "text/css");
LoadURL("https://example.com/main.html");
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
main_resource.Complete(R"HTML(
<!DOCTYPE html>
@@ -335,7 +328,7 @@ TEST_F(DocumentLoadingRenderingTest,
ToHTMLIFrameElement(GetDocument().getElementById("frame"));
// Frame while the child frame still has pending sheets.
- auto* frame1_callback = new CheckRafCallback();
+ auto* frame1_callback = MakeGarbageCollected<CheckRafCallback>();
child_frame->contentDocument()->RequestAnimationFrame(frame1_callback);
auto frame1 = Compositor().BeginFrame();
EXPECT_FALSE(frame1_callback->WasCalled());
@@ -347,7 +340,7 @@ TEST_F(DocumentLoadingRenderingTest,
css_resource.Complete();
// Frame with all lifecycle updates enabled.
- auto* frame2_callback = new CheckRafCallback();
+ auto* frame2_callback = MakeGarbageCollected<CheckRafCallback>();
child_frame->contentDocument()->RequestAnimationFrame(frame2_callback);
auto frame2 = Compositor().BeginFrame();
EXPECT_TRUE(frame1_callback->WasCalled());
@@ -359,13 +352,13 @@ TEST_F(DocumentLoadingRenderingTest,
TEST_F(DocumentLoadingRenderingTest,
ShouldContinuePaintingWhenSheetsStartedAfterBody) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
- SimRequest css_body_resource("https://example.com/testBody.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource("https://example.com/testBody.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
-
// Still in the head, should not paint.
main_resource.Write("<!DOCTYPE html><link rel=stylesheet href=testHead.css>");
EXPECT_FALSE(GetDocument().IsRenderingReady());
@@ -399,13 +392,12 @@ TEST_F(DocumentLoadingRenderingTest,
TEST_F(DocumentLoadingRenderingTest,
returnBoundingClientRectCorrectlyWhileLoadingImport) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest import_resource("https://example.com/import.css", "text/css");
+ SimSubresourceRequest import_resource("https://example.com/import.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- WebView().Resize(WebSize(800, 600));
-
- main_resource.Start();
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
main_resource.Write(R"HTML(
<html><body>
@@ -436,12 +428,11 @@ TEST_F(DocumentLoadingRenderingTest,
TEST_F(DocumentLoadingRenderingTest, StableSVGStopStylingWhileLoadingImport) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest import_resource("https://example.com/import.css", "text/css");
+ SimSubresourceRequest import_resource("https://example.com/import.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
-
main_resource.Write(R"HTML(
<html><body>
<svg>
@@ -461,8 +452,9 @@ TEST_F(DocumentLoadingRenderingTest, StableSVGStopStylingWhileLoadingImport) {
Element* element = GetDocument().getElementById("test");
ASSERT_NE(nullptr, element);
- EXPECT_EQ(0xff008000, element->ComputedStyleRef().SvgStyle().StopColor());
- EXPECT_EQ(.5f, element->ComputedStyleRef().SvgStyle().StopOpacity());
+ const SVGComputedStyle& svg_style = element->ComputedStyleRef().SvgStyle();
+ EXPECT_EQ(0xff008000, svg_style.StopColor().GetColor());
+ EXPECT_EQ(.5f, svg_style.StopOpacity());
};
EXPECT_TRUE(GetDocument().IsRenderingReady());
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_timer.cc b/chromium/third_party/blink/renderer/core/frame/dom_timer.cc
index 92c91b49c45..419c2da4ca7 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_timer.cc
+++ b/chromium/third_party/blink/renderer/core/frame/dom_timer.cc
@@ -28,6 +28,7 @@
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/core/v8/scheduled_action.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
@@ -80,7 +81,8 @@ DOMTimer::DOMTimer(ExecutionContext* context,
TimeDelta interval,
bool single_shot,
int timeout_id)
- : PausableTimer(context, TaskType::kJavascriptTimer),
+ : ContextLifecycleObserver(context),
+ TimerBase(context->GetTaskRunner(TaskType::kJavascriptTimer)),
timeout_id_(timeout_id),
nesting_level_(context->Timers()->TimerNestingLevel() + 1),
action_(action) {
@@ -101,7 +103,6 @@ DOMTimer::DOMTimer(ExecutionContext* context,
else
StartRepeating(interval_milliseconds, FROM_HERE);
- PauseIfNeeded();
TRACE_EVENT_INSTANT1("devtools.timeline", "TimerInstall",
TRACE_EVENT_SCOPE_THREAD, "data",
inspector_timer_install_event::Data(
@@ -128,7 +129,7 @@ void DOMTimer::Stop() {
if (action_)
action_->Dispose();
action_ = nullptr;
- PausableTimer::Stop();
+ TimerBase::Stop();
}
void DOMTimer::ContextDestroyed(ExecutionContext*) {
@@ -174,6 +175,9 @@ void DOMTimer::Fired() {
action->Execute(context);
+ // Eagerly clear out |action|'s resources.
+ action->Dispose();
+
// ExecutionContext might be already gone when we executed action->execute().
ExecutionContext* execution_context = GetExecutionContext();
if (!execution_context)
@@ -182,8 +186,6 @@ void DOMTimer::Fired() {
execution_context->Timers()->SetTimerNestingLevel(0);
// Eagerly unregister as ExecutionContext observer.
ClearContext();
- // Eagerly clear out |action|'s resources.
- action->Dispose();
}
scoped_refptr<base::SingleThreadTaskRunner> DOMTimer::TimerTaskRunner() const {
@@ -192,7 +194,7 @@ scoped_refptr<base::SingleThreadTaskRunner> DOMTimer::TimerTaskRunner() const {
void DOMTimer::Trace(blink::Visitor* visitor) {
visitor->Trace(action_);
- PausableTimer::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_timer.h b/chromium/third_party/blink/renderer/core/frame/dom_timer.h
index fee0571722f..bdc854356b2 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_timer.h
+++ b/chromium/third_party/blink/renderer/core/frame/dom_timer.h
@@ -28,18 +28,23 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DOM_TIMER_H_
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/bindings/core/v8/scheduled_action.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
-#include "third_party/blink/renderer/core/frame/pausable_timer.h"
+#include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/timer.h"
namespace blink {
class ExecutionContext;
+class ScheduledAction;
class CORE_EXPORT DOMTimer final : public GarbageCollectedFinalized<DOMTimer>,
- public PausableTimer {
+ public ContextLifecycleObserver,
+ public TimerBase,
+ public NameClient {
USING_GARBAGE_COLLECTED_MIXIN(DOMTimer);
public:
@@ -58,7 +63,7 @@ class CORE_EXPORT DOMTimer final : public GarbageCollectedFinalized<DOMTimer>,
int timeout_id);
~DOMTimer() override;
- // PausableObject
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// Eager finalization is needed to promptly stop this Timer object.
@@ -67,11 +72,12 @@ class CORE_EXPORT DOMTimer final : public GarbageCollectedFinalized<DOMTimer>,
// already have been finalized & must not be accessed.
EAGERLY_FINALIZE();
void Trace(blink::Visitor*) override;
+ const char* NameInHeapSnapshot() const override { return "DOMTimer"; }
void Stop() override;
private:
- friend class DOMTimerCoordinator; // For create().
+ friend class DOMTimerCoordinator; // For Create().
static DOMTimer* Create(ExecutionContext* context,
ScheduledAction* action,
@@ -88,7 +94,7 @@ class CORE_EXPORT DOMTimer final : public GarbageCollectedFinalized<DOMTimer>,
int timeout_id_;
int nesting_level_;
- Member<ScheduledAction> action_;
+ TraceWrapperMember<ScheduledAction> action_;
scoped_refptr<UserGestureToken> user_gesture_token_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_timer_coordinator.h b/chromium/third_party/blink/renderer/core/frame/dom_timer_coordinator.h
index 03c35bcef1c..e15c6c5f2c8 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_timer_coordinator.h
+++ b/chromium/third_party/blink/renderer/core/frame/dom_timer_coordinator.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
@@ -59,7 +60,7 @@ class DOMTimerCoordinator {
private:
int NextID();
- using TimeoutMap = HeapHashMap<int, Member<DOMTimer>>;
+ using TimeoutMap = HeapHashMap<int, TraceWrapperMember<DOMTimer>>;
TimeoutMap timers_;
int circular_sequential_id_;
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_window.cc b/chromium/third_party/blink/renderer/core/frame/dom_window.cc
index d19eb5424fa..6d293ff99ce 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/chromium/third_party/blink/renderer/core/frame/dom_window.cc
@@ -115,7 +115,7 @@ DOMWindow* DOMWindow::top() const {
return GetFrame()->Tree().Top().DomWindow();
}
-void DOMWindow::postMessage(LocalDOMWindow* incumbent_window,
+void DOMWindow::postMessage(v8::Isolate* isolate,
const ScriptValue& message,
const String& target_origin,
Vector<ScriptValue>& transfer,
@@ -124,21 +124,17 @@ void DOMWindow::postMessage(LocalDOMWindow* incumbent_window,
options->setTargetOrigin(target_origin);
if (!transfer.IsEmpty())
options->setTransfer(transfer);
- postMessage(incumbent_window, message, options, exception_state);
+ postMessage(isolate, message, options, exception_state);
}
-void DOMWindow::postMessage(LocalDOMWindow* incumbent_window,
+void DOMWindow::postMessage(v8::Isolate* isolate,
const ScriptValue& message,
const WindowPostMessageOptions* options,
ExceptionState& exception_state) {
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
UseCounter::Count(incumbent_window->GetFrame(),
WebFeature::kWindowPostMessage);
- // Since remote windows do not have a v8::Context, we cannot use
- // [CallWith=ScriptState], and there is no good way to get the v8::Isolate.
- // As a compromise, ask the isolate to the WindowProxyManager.
- v8::Isolate* isolate = window_proxy_manager_->GetIsolate();
-
Transferables transferables;
scoped_refptr<SerializedScriptValue> serialized_message =
PostMessageHelper::SerializeMessageByMove(isolate, message, options,
@@ -164,7 +160,7 @@ bool DOMWindow::IsCurrentlyDisplayedInFrame() const {
return GetFrame() && GetFrame()->GetPage();
}
-bool DOMWindow::IsInsecureScriptAccess(LocalDOMWindow& calling_window,
+bool DOMWindow::IsInsecureScriptAccess(LocalDOMWindow& accessing_window,
const KURL& url) {
if (!url.ProtocolIsJavaScript())
return false;
@@ -173,21 +169,21 @@ bool DOMWindow::IsInsecureScriptAccess(LocalDOMWindow& calling_window,
// way we should allow the access.
if (IsCurrentlyDisplayedInFrame()) {
// FIXME: Is there some way to eliminate the need for a separate
- // "callingWindow == this" check?
- if (&calling_window == this)
+ // "accessing_window == this" check?
+ if (&accessing_window == this)
return false;
// FIXME: The name canAccess seems to be a roundabout way to ask "can
// execute script". Can we name the SecurityOrigin function better to make
// this more clear?
- if (calling_window.document()->GetSecurityOrigin()->CanAccess(
+ if (accessing_window.document()->GetSecurityOrigin()->CanAccess(
GetFrame()->GetSecurityContext()->GetSecurityOrigin())) {
return false;
}
}
- calling_window.PrintErrorMessage(
- CrossDomainAccessErrorMessage(&calling_window));
+ accessing_window.PrintErrorMessage(
+ CrossDomainAccessErrorMessage(&accessing_window));
return true;
}
@@ -198,16 +194,16 @@ bool DOMWindow::IsInsecureScriptAccess(LocalDOMWindow& calling_window,
//
// http://crbug.com/17325
String DOMWindow::SanitizedCrossDomainAccessErrorMessage(
- const LocalDOMWindow* calling_window) const {
- if (!calling_window || !calling_window->document() || !GetFrame())
+ const LocalDOMWindow* accessing_window) const {
+ if (!accessing_window || !accessing_window->document() || !GetFrame())
return String();
- const KURL& calling_window_url = calling_window->document()->Url();
- if (calling_window_url.IsNull())
+ const KURL& accessing_window_url = accessing_window->document()->Url();
+ if (accessing_window_url.IsNull())
return String();
const SecurityOrigin* active_origin =
- calling_window->document()->GetSecurityOrigin();
+ accessing_window->document()->GetSecurityOrigin();
String message = "Blocked a frame with origin \"" +
active_origin->ToString() +
"\" from accessing a cross-origin frame.";
@@ -219,18 +215,18 @@ String DOMWindow::SanitizedCrossDomainAccessErrorMessage(
}
String DOMWindow::CrossDomainAccessErrorMessage(
- const LocalDOMWindow* calling_window) const {
- if (!calling_window || !calling_window->document() || !GetFrame())
+ const LocalDOMWindow* accessing_window) const {
+ if (!accessing_window || !accessing_window->document() || !GetFrame())
return String();
- const KURL& calling_window_url = calling_window->document()->Url();
- if (calling_window_url.IsNull())
+ const KURL& accessing_window_url = accessing_window->document()->Url();
+ if (accessing_window_url.IsNull())
return String();
// FIXME: This message, and other console messages, have extra newlines.
// Should remove them.
const SecurityOrigin* active_origin =
- calling_window->document()->GetSecurityOrigin();
+ accessing_window->document()->GetSecurityOrigin();
const SecurityOrigin* target_origin =
GetFrame()->GetSecurityContext()->GetSecurityOrigin();
// It's possible for a remote frame to be same origin with respect to a
@@ -246,7 +242,7 @@ String DOMWindow::CrossDomainAccessErrorMessage(
// Sandbox errors: Use the origin of the frames' location, rather than their
// actual origin (since we know that at least one will be "null").
- KURL active_url = calling_window->document()->Url();
+ KURL active_url = accessing_window->document()->Url();
// TODO(alexmos): RemoteFrames do not have a document, and their URLs
// aren't replicated. For now, construct the URL using the replicated
// origin for RemoteFrames. If the target frame is remote and sandboxed,
@@ -255,13 +251,13 @@ String DOMWindow::CrossDomainAccessErrorMessage(
? blink::ToLocalDOMWindow(this)->document()->Url()
: KURL(NullURL(), target_origin->ToString());
if (GetFrame()->GetSecurityContext()->IsSandboxed(kSandboxOrigin) ||
- calling_window->document()->IsSandboxed(kSandboxOrigin)) {
+ accessing_window->document()->IsSandboxed(kSandboxOrigin)) {
message = "Blocked a frame at \"" +
SecurityOrigin::Create(active_url)->ToString() +
"\" from accessing a frame at \"" +
SecurityOrigin::Create(target_url)->ToString() + "\". ";
if (GetFrame()->GetSecurityContext()->IsSandboxed(kSandboxOrigin) &&
- calling_window->document()->IsSandboxed(kSandboxOrigin))
+ accessing_window->document()->IsSandboxed(kSandboxOrigin))
return "Sandbox access violation: " + message +
" Both frames are sandboxed and lack the \"allow-same-origin\" "
"flag.";
@@ -307,7 +303,14 @@ String DOMWindow::CrossDomainAccessErrorMessage(
return message + "Protocols, domains, and ports must match.";
}
-void DOMWindow::close(LocalDOMWindow* incumbent_window) {
+void DOMWindow::close(v8::Isolate* isolate) {
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
+ Close(incumbent_window);
+}
+
+void DOMWindow::Close(LocalDOMWindow* incumbent_window) {
+ DCHECK(incumbent_window);
+
if (!GetFrame() || !GetFrame()->IsMainFrame())
return;
@@ -315,16 +318,10 @@ void DOMWindow::close(LocalDOMWindow* incumbent_window) {
if (!page)
return;
- Document* active_document = nullptr;
- if (incumbent_window) {
- DCHECK(IsMainThread());
- active_document = incumbent_window->document();
- if (!active_document)
- return;
-
- if (!active_document->GetFrame() ||
- !active_document->GetFrame()->CanNavigate(*GetFrame()))
- return;
+ Document* active_document = incumbent_window->document();
+ if (!(active_document && active_document->GetFrame() &&
+ active_document->GetFrame()->CanNavigate(*GetFrame()))) {
+ return;
}
Settings* settings = GetFrame()->GetSettings();
@@ -333,12 +330,10 @@ void DOMWindow::close(LocalDOMWindow* incumbent_window) {
if (!page->OpenedByDOM() && GetFrame()->Client()->BackForwardLength() > 1 &&
!allow_scripts_to_close_windows) {
- if (active_document) {
- active_document->domWindow()->GetFrameConsole()->AddMessage(
- ConsoleMessage::Create(
- kJSMessageSource, kWarningMessageLevel,
- "Scripts may close only the windows that were opened by it."));
- }
+ active_document->domWindow()->GetFrameConsole()->AddMessage(
+ ConsoleMessage::Create(
+ kJSMessageSource, kWarningMessageLevel,
+ "Scripts may close only the windows that were opened by it."));
return;
}
@@ -360,7 +355,7 @@ void DOMWindow::close(LocalDOMWindow* incumbent_window) {
window_is_closing_ = true;
}
-void DOMWindow::focus(LocalDOMWindow* incumbent_window) {
+void DOMWindow::focus(v8::Isolate* isolate) {
if (!GetFrame())
return;
@@ -368,7 +363,14 @@ void DOMWindow::focus(LocalDOMWindow* incumbent_window) {
if (!page)
return;
- DCHECK(incumbent_window);
+ // HTML standard doesn't require to check the incumbent realm, but Blink
+ // historically checks it for some reasons, maybe the same reason as |close|.
+ // (|close| checks whether the incumbent realm is eligible to close the window
+ // in order to prevent a (cross origin) window from abusing |close| to close
+ // pages randomly or with a malicious intent.)
+ // https://html.spec.whatwg.org/C/#dom-window-focus
+ // https://html.spec.whatwg.org/C/#focusing-steps
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
ExecutionContext* incumbent_execution_context =
incumbent_window->GetExecutionContext();
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_window.h b/chromium/third_party/blink/renderer/core/frame/dom_window.h
index 63e0a019542..bbac21f3e62 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_window.h
+++ b/chromium/third_party/blink/renderer/core/frame/dom_window.h
@@ -89,17 +89,18 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
DOMWindow* parent() const;
DOMWindow* top() const;
- void focus(LocalDOMWindow* incumbent_window);
+ void focus(v8::Isolate*);
virtual void blur() = 0;
- void close(LocalDOMWindow* incumbent_window);
+ void close(v8::Isolate*);
+ void Close(LocalDOMWindow* incumbent_window);
- void postMessage(LocalDOMWindow* incumbent_window,
+ void postMessage(v8::Isolate*,
const ScriptValue& message,
const String& target_origin,
Vector<ScriptValue>& transfer,
ExceptionState&);
- void postMessage(LocalDOMWindow* incumbent_window,
+ void postMessage(v8::Isolate*,
const ScriptValue& message,
const WindowPostMessageOptions* options,
ExceptionState&);
@@ -108,10 +109,10 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
DOMWindow* AnonymousIndexedGetter(uint32_t index) const;
String SanitizedCrossDomainAccessErrorMessage(
- const LocalDOMWindow* calling_window) const;
+ const LocalDOMWindow* accessing_window) const;
String CrossDomainAccessErrorMessage(
- const LocalDOMWindow* calling_window) const;
- bool IsInsecureScriptAccess(LocalDOMWindow& calling_window, const KURL&);
+ const LocalDOMWindow* accessing_window) const;
+ bool IsInsecureScriptAccess(LocalDOMWindow& accessing_window, const KURL&);
// FIXME: When this DOMWindow is no longer the active DOMWindow (i.e.,
// when its document is no longer the document that is displayed in its
diff --git a/chromium/third_party/blink/renderer/core/frame/event_handler_registry.cc b/chromium/third_party/blink/renderer/core/frame/event_handler_registry.cc
index e9035652d37..2b3fbebdf31 100644
--- a/chromium/third_party/blink/renderer/core/frame/event_handler_registry.cc
+++ b/chromium/third_party/blink/renderer/core/frame/event_handler_registry.cc
@@ -143,7 +143,7 @@ bool EventHandlerRegistry::UpdateEventHandlerInternal(
if (op != kRemoveAll) {
if (handlers_changed)
- NotifyHasHandlersChanged(target, handler_class, new_num_handlers > 0);
+ NotifyHandlersChanged(target, handler_class, new_num_handlers > 0);
if (target_set_changed) {
NotifyDidAddOrRemoveEventHandlerTarget(GetLocalFrameForTarget(target),
@@ -232,7 +232,7 @@ void EventHandlerRegistry::DidRemoveAllEventHandlers(EventTarget& target) {
EventHandlerClass handler_class = static_cast<EventHandlerClass>(i);
if (handlers_changed[i]) {
bool has_handlers = targets_[handler_class].Contains(&target);
- NotifyHasHandlersChanged(&target, handler_class, has_handlers);
+ NotifyHandlersChanged(&target, handler_class, has_handlers);
}
if (target_set_changed[i]) {
NotifyDidAddOrRemoveEventHandlerTarget(GetLocalFrameForTarget(&target),
@@ -241,7 +241,7 @@ void EventHandlerRegistry::DidRemoveAllEventHandlers(EventTarget& target) {
}
}
-void EventHandlerRegistry::NotifyHasHandlersChanged(
+void EventHandlerRegistry::NotifyHandlersChanged(
EventTarget* target,
EventHandlerClass handler_class,
bool has_active_handlers) {
diff --git a/chromium/third_party/blink/renderer/core/frame/event_handler_registry.h b/chromium/third_party/blink/renderer/core/frame/event_handler_registry.h
index 92df7a3036e..1ea4847844c 100644
--- a/chromium/third_party/blink/renderer/core/frame/event_handler_registry.h
+++ b/chromium/third_party/blink/renderer/core/frame/event_handler_registry.h
@@ -100,12 +100,12 @@ class CORE_EXPORT EventHandlerRegistry final
EventTarget*);
// Called on the EventHandlerRegistry of the root Document to notify
- // clients when we have added the first handler or removed the last one for
- // a given event class. |hasActiveHandlers| can be used to distinguish
- // between the two cases.
- void NotifyHasHandlersChanged(EventTarget*,
- EventHandlerClass,
- bool has_active_handlers);
+ // clients when we have added or remove a handler for a given event class.
+ // |hasActiveHandlers| can be used to distinguish between having and not
+ // having an active handler.
+ void NotifyHandlersChanged(EventTarget*,
+ EventHandlerClass,
+ bool has_active_handlers);
// Called to notify clients whenever a single event handler target is
// registered or unregistered. If several handlers are registered for the
diff --git a/chromium/third_party/blink/renderer/core/frame/external.idl b/chromium/third_party/blink/renderer/core/frame/external.idl
index 977e4e005d6..3a7787d3909 100644
--- a/chromium/third_party/blink/renderer/core/frame/external.idl
+++ b/chromium/third_party/blink/renderer/core/frame/external.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-[NoInterfaceObject]
+[Exposed=Window]
interface External {
void AddSearchProvider();
void IsSearchProviderInstalled();
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_console.cc b/chromium/third_party/blink/renderer/core/frame/frame_console.cc
index fa8dfed9e34..607e38de922 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_console.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_console.cc
@@ -46,24 +46,6 @@ namespace blink {
FrameConsole::FrameConsole(LocalFrame& frame) : frame_(&frame) {}
void FrameConsole::AddMessage(ConsoleMessage* console_message) {
- // PlzNavigate: when trying to commit a navigation, the SourceLocation
- // information for how the request was triggered has been stored in the
- // provisional DocumentLoader. Use it instead.
- DocumentLoader* provisional_loader =
- frame_->Loader().GetProvisionalDocumentLoader();
- if (provisional_loader) {
- std::unique_ptr<SourceLocation> source_location =
- provisional_loader->CopySourceLocation();
- if (source_location) {
- Vector<DOMNodeId> nodes(console_message->Nodes());
- LocalFrame* frame = console_message->Frame();
- console_message = ConsoleMessage::Create(
- console_message->Source(), console_message->Level(),
- console_message->Message(), std::move(source_location));
- console_message->SetNodes(frame, std::move(nodes));
- }
- }
-
if (AddMessageToStorage(console_message))
ReportMessageToClient(console_message->Source(), console_message->Level(),
console_message->Message(),
@@ -124,7 +106,7 @@ void FrameConsole::ReportResourceResponseReceived(
response.HttpStatusText() + ')';
ConsoleMessage* console_message = ConsoleMessage::CreateForRequest(
kNetworkMessageSource, kErrorMessageLevel, message,
- response.Url().GetString(), loader, request_identifier);
+ response.CurrentRequestUrl().GetString(), loader, request_identifier);
AddMessage(console_message);
}
@@ -146,6 +128,7 @@ void FrameConsole::DidFailLoading(DocumentLoader* loader,
void FrameConsole::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
+ ConsoleLoggerImplBase::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_console.h b/chromium/third_party/blink/renderer/core/frame/frame_console.h
index d8061d221da..71722a5c754 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_console.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_console.h
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/inspector/console_types.h"
+#include "third_party/blink/renderer/core/loader/console_logger_impl_base.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -49,7 +50,10 @@ class SourceLocation;
// around ChromeClient calls and the way that Blink core/ can add messages to
// the console.
class CORE_EXPORT FrameConsole final
- : public GarbageCollectedFinalized<FrameConsole> {
+ : public GarbageCollectedFinalized<FrameConsole>,
+ public ConsoleLoggerImplBase {
+ USING_GARBAGE_COLLECTED_MIXIN(FrameConsole);
+
public:
static FrameConsole* Create(LocalFrame& frame) {
return MakeGarbageCollected<FrameConsole>(frame);
@@ -57,6 +61,10 @@ class CORE_EXPORT FrameConsole final
explicit FrameConsole(LocalFrame&);
+ // ConsoleLoggerImplBase implementation.
+ void AddConsoleMessage(ConsoleMessage* message) override {
+ AddMessage(message);
+ }
void AddMessage(ConsoleMessage*);
bool AddMessageToStorage(ConsoleMessage*);
@@ -73,7 +81,7 @@ class CORE_EXPORT FrameConsole final
unsigned long request_identifier,
const ResourceError&);
- void Trace(blink::Visitor*);
+ void Trace(blink::Visitor*) override;
private:
Member<LocalFrame> frame_;
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc b/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
new file mode 100644
index 00000000000..c69be2adb6b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
+ * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "third_party/blink/renderer/core/frame/frame_overlay.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "cc/layers/picture_layer.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_layer_client.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
+#include "third_party/blink/renderer/platform/scroll/main_thread_scrolling_reason.h"
+
+namespace blink {
+
+std::unique_ptr<FrameOverlay> FrameOverlay::Create(
+ LocalFrame* local_frame,
+ std::unique_ptr<FrameOverlay::Delegate> delegate) {
+ return base::WrapUnique(new FrameOverlay(local_frame, std::move(delegate)));
+}
+
+FrameOverlay::FrameOverlay(LocalFrame* local_frame,
+ std::unique_ptr<FrameOverlay::Delegate> delegate)
+ : frame_(local_frame), delegate_(std::move(delegate)) {
+ DCHECK(frame_);
+}
+
+FrameOverlay::~FrameOverlay() {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+ if (!layer_)
+ return;
+ layer_->RemoveFromParent();
+ layer_ = nullptr;
+}
+
+void FrameOverlay::Update() {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ delegate_->Invalidate();
+ return;
+ }
+
+ auto* local_root_frame_widget =
+ WebLocalFrameImpl::FromFrame(frame_)->LocalRootFrameWidget();
+ if (!local_root_frame_widget->IsAcceleratedCompositingActive())
+ return;
+
+ GraphicsLayer* parent_layer =
+ frame_->IsMainFrame()
+ ? frame_->GetPage()->GetVisualViewport().ContainerLayer()
+ : local_root_frame_widget->RootGraphicsLayer();
+ if (!layer_) {
+ if (!parent_layer)
+ return;
+ layer_ = GraphicsLayer::Create(*this);
+ layer_->SetDrawsContent(true);
+
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ // This is required for contents of overlay to stay in sync with the page
+ // while scrolling. When BlinkGenPropertyTrees is enabled, scrolling is
+ // prevented by using the root scroll node in the root property tree
+ // state.
+ cc::Layer* cc_layer = layer_->CcLayer();
+ cc_layer->AddMainThreadScrollingReasons(
+ MainThreadScrollingReason::kFrameOverlay);
+ }
+
+ layer_->SetLayerState(PropertyTreeState::Root(), IntPoint());
+ }
+
+ layer_->SetSize(gfx::Size(Size()));
+ layer_->SetNeedsDisplay();
+ if (parent_layer)
+ parent_layer->SetPaintArtifactCompositorNeedsUpdate();
+}
+
+IntSize FrameOverlay::Size() const {
+ if (frame_->IsMainFrame())
+ return frame_->GetPage()->GetVisualViewport().Size();
+ return frame_->GetPage()->GetVisualViewport().Size().ExpandedTo(
+ frame_->View()->Size());
+}
+
+LayoutRect FrameOverlay::VisualRect() const {
+ return LayoutRect(IntPoint(), Size());
+}
+
+IntRect FrameOverlay::ComputeInterestRect(const GraphicsLayer* graphics_layer,
+ const IntRect&) const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ return IntRect(IntPoint(), Size());
+}
+
+void FrameOverlay::EnsureOverlayAttached() const {
+ DCHECK(layer_);
+ auto* local_root_frame_widget =
+ WebLocalFrameImpl::FromFrame(frame_)->LocalRootFrameWidget();
+ GraphicsLayer* parent_layer =
+ frame_->GetPage()->MainFrame()->IsLocalFrame()
+ ? frame_->GetPage()->GetVisualViewport().ContainerLayer()
+ : local_root_frame_widget->RootGraphicsLayer();
+ DCHECK(parent_layer);
+ if (layer_->Parent() != parent_layer)
+ parent_layer->AddChild(layer_.get());
+}
+
+void FrameOverlay::PaintContents(const GraphicsLayer* graphics_layer,
+ GraphicsContext& gc,
+ GraphicsLayerPaintingPhase phase,
+ const IntRect& interest_rect) const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ DCHECK(layer_);
+ EnsureOverlayAttached();
+ delegate_->PaintFrameOverlay(*this, gc, Size());
+}
+
+String FrameOverlay::DebugName(const GraphicsLayer*) const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ return "Frame Overlay Content Layer";
+}
+
+void FrameOverlay::Paint(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ delegate_->PaintFrameOverlay(*this, context, Size());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/page_overlay.h b/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
index 814caa99969..df4968466bc 100644
--- a/chromium/third_party/blink/renderer/core/page/page_overlay.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
@@ -26,8 +26,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_OVERLAY_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_OVERLAY_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_OVERLAY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_OVERLAY_H_
#include <memory>
#include "third_party/blink/renderer/core/core_export.h"
@@ -42,34 +42,54 @@ class GraphicsContext;
class LocalFrame;
// Manages a layer that is overlaid on a WebLocalFrame's content.
-class CORE_EXPORT PageOverlay : public GraphicsLayerClient,
- public DisplayItemClient {
+class CORE_EXPORT FrameOverlay : public GraphicsLayerClient,
+ public DisplayItemClient {
public:
class Delegate {
public:
virtual ~Delegate() = default;
// Paints page overlay contents.
- virtual void PaintPageOverlay(const PageOverlay&,
- GraphicsContext&,
- const IntSize& web_view_size) const = 0;
+ virtual void PaintFrameOverlay(const FrameOverlay&,
+ GraphicsContext&,
+ const IntSize& view_size) const = 0;
+ // For CompositeAfterPaint. Invalidates composited layers managed by the
+ // delegate if any.
+ virtual void Invalidate() {}
};
- static std::unique_ptr<PageOverlay> Create(
+ static std::unique_ptr<FrameOverlay> Create(
LocalFrame*,
- std::unique_ptr<PageOverlay::Delegate>);
+ std::unique_ptr<FrameOverlay::Delegate>);
- ~PageOverlay() override;
+ ~FrameOverlay() override;
void Update();
- GraphicsLayer* GetGraphicsLayer() const { return layer_.get(); }
+ // For CompositeAfterPaint.
+ void Paint(GraphicsContext&);
+
+ GraphicsLayer* GetGraphicsLayer() const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ return layer_.get();
+ }
+
+ // FrameOverlay is always the same size as the viewport.
+ IntSize Size() const;
+
+ // Ensure that |layer_| is attached to the root graphics layer. Updates
+ // to the frames compositing may remove the graphics layer at any
+ // point. This should be called before calling PaintContents.
+ void EnsureOverlayAttached() const;
+
+ const Delegate* GetDelegate() const { return delegate_.get(); }
+ const LocalFrame& Frame() const { return *frame_; }
// DisplayItemClient methods.
- String DebugName() const final { return "PageOverlay"; }
+ String DebugName() const final { return "FrameOverlay"; }
LayoutRect VisualRect() const override;
- // GraphicsLayerClient implementation
+ // GraphicsLayerClient implementation. Not needed for CompositeAfterPaint.
bool NeedsRepaint(const GraphicsLayer&) const override { return true; }
IntRect ComputeInterestRect(const GraphicsLayer*,
const IntRect&) const override;
@@ -80,10 +100,10 @@ class CORE_EXPORT PageOverlay : public GraphicsLayerClient,
String DebugName(const GraphicsLayer*) const override;
private:
- PageOverlay(LocalFrame*, std::unique_ptr<PageOverlay::Delegate>);
+ FrameOverlay(LocalFrame*, std::unique_ptr<FrameOverlay::Delegate>);
Persistent<LocalFrame> frame_;
- std::unique_ptr<PageOverlay::Delegate> delegate_;
+ std::unique_ptr<FrameOverlay::Delegate> delegate_;
std::unique_ptr<GraphicsLayer> layer_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_overlay_test.cc b/chromium/third_party/blink/renderer/core/frame/frame_overlay_test.cc
new file mode 100644
index 00000000000..eac7cc1a41b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay_test.cc
@@ -0,0 +1,121 @@
+// 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 "third_party/blink/renderer/core/frame/frame_overlay.h"
+
+#include <memory>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
+#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Property;
+
+namespace blink {
+namespace {
+
+// FrameOverlay that paints a solid color.
+class SolidColorOverlay : public FrameOverlay::Delegate {
+ public:
+ SolidColorOverlay(Color color) : color_(color) {}
+
+ void PaintFrameOverlay(const FrameOverlay& frame_overlay,
+ GraphicsContext& graphics_context,
+ const IntSize& size) const override {
+ if (DrawingRecorder::UseCachedDrawingIfPossible(
+ graphics_context, frame_overlay, DisplayItem::kFrameOverlay))
+ return;
+ FloatRect rect(0, 0, size.Width(), size.Height());
+ DrawingRecorder recorder(graphics_context, frame_overlay,
+ DisplayItem::kFrameOverlay);
+ graphics_context.FillRect(rect, color_);
+ }
+
+ private:
+ Color color_;
+};
+
+class FrameOverlayTest : public testing::Test, public PaintTestConfigurations {
+ protected:
+ static constexpr int kViewportWidth = 800;
+ static constexpr int kViewportHeight = 600;
+
+ FrameOverlayTest() {
+ helper_.Initialize(nullptr, nullptr, nullptr);
+ GetWebView()->MainFrameWidget()->Resize(
+ WebSize(kViewportWidth, kViewportHeight));
+ GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
+ WebWidget::LifecycleUpdateReason::kTest);
+ }
+
+ WebViewImpl* GetWebView() const { return helper_.GetWebView(); }
+
+ std::unique_ptr<FrameOverlay> CreateSolidYellowOverlay() {
+ return FrameOverlay::Create(
+ GetWebView()->MainFrameImpl()->GetFrame(),
+ std::make_unique<SolidColorOverlay>(SK_ColorYELLOW));
+ }
+
+ template <typename OverlayType>
+ void RunFrameOverlayTestWithAcceleratedCompositing();
+
+ private:
+ frame_test_helpers::WebViewHelper helper_;
+};
+
+class MockFrameOverlayCanvas : public SkCanvas {
+ public:
+ MOCK_METHOD2(onDrawRect, void(const SkRect&, const SkPaint&));
+};
+
+INSTANTIATE_PAINT_TEST_CASE_P(FrameOverlayTest);
+
+TEST_P(FrameOverlayTest, AcceleratedCompositing) {
+ std::unique_ptr<FrameOverlay> frame_overlay = CreateSolidYellowOverlay();
+ frame_overlay->Update();
+ GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
+ WebWidget::LifecycleUpdateReason::kTest);
+
+ // Ideally, we would get results from the compositor that showed that this
+ // page overlay actually winds up getting drawn on top of the rest.
+ // For now, we just check that the GraphicsLayer will draw the right thing.
+ MockFrameOverlayCanvas canvas;
+ EXPECT_CALL(canvas,
+ onDrawRect(SkRect::MakeWH(kViewportWidth, kViewportHeight),
+ Property(&SkPaint::getColor, SK_ColorYELLOW)));
+
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ PaintRecordBuilder builder;
+ frame_overlay->Paint(builder.Context());
+ builder.EndRecording()->Playback(&canvas);
+ } else {
+ auto* graphics_layer = frame_overlay->GetGraphicsLayer();
+ graphics_layer->Paint();
+ graphics_layer->CapturePaintRecord()->Playback(&canvas);
+ }
+}
+
+TEST_P(FrameOverlayTest, VisualRect) {
+ std::unique_ptr<FrameOverlay> frame_overlay = CreateSolidYellowOverlay();
+ frame_overlay->Update();
+ GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
+ WebWidget::LifecycleUpdateReason::kTest);
+ EXPECT_EQ(LayoutRect(0, 0, kViewportWidth, kViewportHeight),
+ frame_overlay->VisualRect());
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_serializer_test.cc b/chromium/third_party/blink/renderer/core/frame/frame_serializer_test.cc
index c17c0a7ca05..83ecd24c346 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_serializer_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_serializer_test.cc
@@ -66,7 +66,7 @@ class FrameSerializerTest : public testing::Test,
protected:
void SetUp() override {
// We want the images to load.
- helper_.Initialize(nullptr, nullptr, nullptr, &ConfigureSettings);
+ helper_.InitializeWithSettings(&ConfigureSettings);
}
void TearDown() override {
@@ -115,6 +115,10 @@ class FrameSerializerTest : public testing::Test,
frame_test_helpers::LoadFrame(
helper_.GetWebView()->MainFrameImpl(),
KURL(base_url_, url).GetString().Utf8().data());
+ // Sometimes we have iframes created in "onload" handler - wait for them to
+ // load.
+ frame_test_helpers::PumpPendingRequestsForFrameToLoad(
+ helper_.GetWebView()->MainFrameImpl());
FrameSerializer serializer(resources_, *this);
Frame* frame = helper_.LocalMainFrame()->GetFrame();
for (; frame; frame = frame->Tree().TraverseNext()) {
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_test.cc b/chromium/third_party/blink/renderer/core/frame/frame_test.cc
index da0c1e369f5..aabd268726f 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_test.cc
@@ -26,17 +26,12 @@ class FrameTest : public PageTestBase {
void Navigate(const String& destinationUrl, bool user_activated) {
const KURL& url = KURL(NullURL(), destinationUrl);
+ auto navigation_params =
+ WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url);
+ if (user_activated)
+ navigation_params->is_user_activated = true;
GetDocument().GetFrame()->Loader().CommitNavigation(
- ResourceRequest(url), SubstituteData(SharedBuffer::Create()),
- ClientRedirectPolicy::kNotClientRedirect,
- base::UnguessableToken::Create());
- if (user_activated) {
- GetDocument()
- .GetFrame()
- ->Loader()
- .GetProvisionalDocumentLoader()
- ->SetUserActivated();
- }
+ std::move(navigation_params), nullptr /* extra_data */);
blink::test::RunPendingTasks();
ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
}
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index 27c7728d6af..d15a9b145e6 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -35,13 +35,13 @@
#include "cc/test/test_ukm_recorder_factory.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_settings.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/public/web/web_console_message.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_navigation_params.h"
#include "third_party/blink/public/web/web_settings.h"
@@ -49,7 +49,9 @@
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/core/exported/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/fake_web_plugin.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -101,28 +103,23 @@ T* CreateDefaultClientIfNeeded(T* client, std::unique_ptr<T>& owned_client) {
return owned_client.get();
}
-std::unique_ptr<WebNavigationParams> BuildDummyNavigationParams() {
- std::unique_ptr<WebNavigationParams> navigation_params =
- std::make_unique<WebNavigationParams>();
- navigation_params->navigation_timings.navigation_start =
- base::TimeTicks::Now();
- navigation_params->navigation_timings.fetch_start = base::TimeTicks::Now();
- return navigation_params;
-}
-
} // namespace
-void LoadFrame(WebLocalFrame* frame, const std::string& url) {
+void LoadFrameDontWait(WebLocalFrame* frame, const WebURL& url) {
WebLocalFrameImpl* impl = ToWebLocalFrameImpl(frame);
- WebURL web_url(url_test_helpers::ToKURL(url));
- if (web_url.ProtocolIs("javascript")) {
- impl->LoadJavaScriptURL(web_url);
+ if (url.ProtocolIs("javascript")) {
+ impl->LoadJavaScriptURL(url);
} else {
- impl->CommitNavigation(
- WebURLRequest(web_url), blink::WebFrameLoadType::kStandard,
- blink::WebHistoryItem(), false, base::UnguessableToken::Create(),
- BuildDummyNavigationParams(), nullptr /* extra_data */);
+ auto params = std::make_unique<WebNavigationParams>();
+ params->request = WebURLRequest(url);
+ params->navigation_timings.navigation_start = base::TimeTicks::Now();
+ params->navigation_timings.fetch_start = base::TimeTicks::Now();
+ impl->CommitNavigation(std::move(params), nullptr /* extra_data */);
}
+}
+
+void LoadFrame(WebLocalFrame* frame, const std::string& url) {
+ LoadFrameDontWait(frame, url_test_helpers::ToKURL(url));
PumpPendingRequestsForFrameToLoad(frame);
}
@@ -130,7 +127,9 @@ void LoadHTMLString(WebLocalFrame* frame,
const std::string& html,
const WebURL& base_url) {
WebLocalFrameImpl* impl = ToWebLocalFrameImpl(frame);
- impl->LoadHTMLString(WebData(html.data(), html.size()), base_url, WebURL());
+ impl->CommitNavigation(
+ WebNavigationParams::CreateWithHTMLString(html, base_url),
+ nullptr /* extra_data */);
PumpPendingRequestsForFrameToLoad(frame);
}
@@ -139,11 +138,14 @@ void LoadHistoryItem(WebLocalFrame* frame,
mojom::FetchCacheMode cache_mode) {
WebLocalFrameImpl* impl = ToWebLocalFrameImpl(frame);
HistoryItem* history_item = item;
- impl->CommitNavigation(
- WrappedResourceRequest(history_item->GenerateResourceRequest(cache_mode)),
- WebFrameLoadType::kBackForward, item, false /* is_client_redirect */,
- base::UnguessableToken::Create(), BuildDummyNavigationParams(),
- nullptr /* extra_data */);
+ auto params = std::make_unique<WebNavigationParams>();
+ params->request =
+ WrappedResourceRequest(history_item->GenerateResourceRequest(cache_mode));
+ params->frame_load_type = WebFrameLoadType::kBackForward;
+ params->history_item = item;
+ params->navigation_timings.navigation_start = base::TimeTicks::Now();
+ params->navigation_timings.fetch_start = base::TimeTicks::Now();
+ impl->CommitNavigation(std::move(params), nullptr /* extra_data */);
PumpPendingRequestsForFrameToLoad(frame);
}
@@ -184,8 +186,10 @@ WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent,
TestWebFrameClient* client) {
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
- WebLocalFrameImpl* frame =
- ToWebLocalFrameImpl(parent.CreateLocalChild(scope, client, nullptr));
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
+ WebLocalFrameImpl* frame = ToWebLocalFrameImpl(parent.CreateLocalChild(
+ scope, client, nullptr,
+ mojo::MakeRequest(&document_interface_broker).PassMessagePipe()));
client->Bind(frame, std::move(owned_client));
return frame;
}
@@ -196,8 +200,10 @@ WebLocalFrameImpl* CreateLocalChild(
std::unique_ptr<TestWebFrameClient> self_owned) {
DCHECK(self_owned);
TestWebFrameClient* client = self_owned.get();
- WebLocalFrameImpl* frame =
- ToWebLocalFrameImpl(parent.CreateLocalChild(scope, client, nullptr));
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
+ WebLocalFrameImpl* frame = ToWebLocalFrameImpl(parent.CreateLocalChild(
+ scope, client, nullptr,
+ mojo::MakeRequest(&document_interface_broker).PassMessagePipe()));
client->Bind(frame, std::move(self_owned));
return frame;
}
@@ -206,28 +212,31 @@ WebLocalFrameImpl* CreateProvisional(WebRemoteFrame& old_frame,
TestWebFrameClient* client) {
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
WebLocalFrameImpl* frame =
ToWebLocalFrameImpl(WebLocalFrame::CreateProvisional(
- client, nullptr, &old_frame, WebSandboxFlags::kNone,
- ParsedFeaturePolicy()));
+ client, nullptr,
+ mojo::MakeRequest(&document_interface_broker).PassMessagePipe(),
+ &old_frame, WebSandboxFlags::kNone, ParsedFeaturePolicy()));
client->Bind(frame, std::move(owned_client));
+ std::unique_ptr<TestWebWidgetClient> widget_client;
// Create a local root, if necessary.
if (!frame->Parent()) {
+ widget_client = std::make_unique<TestWebWidgetClient>();
// TODO(dcheng): The main frame widget currently has a special case.
// Eliminate this once WebView is no longer a WebWidget.
- WebWidgetClient* widget_client =
- frame->ViewImpl()->Client()->WidgetClient();
- WebFrameWidget::CreateForMainFrame(widget_client, frame);
+ WebFrameWidget::CreateForMainFrame(widget_client.get(), frame);
} else if (frame->Parent()->IsWebRemoteFrame()) {
- auto widget_client = std::make_unique<TestWebWidgetClient>();
+ widget_client = std::make_unique<TestWebWidgetClient>();
WebFrameWidget* frame_widget =
WebFrameWidget::CreateForChildLocalRoot(widget_client.get(), frame);
frame_widget->Resize(WebSize());
// The WebWidget requires a LayerTreeView to be set, either by the
// WebWidgetClient itself or by someone else. We do that here.
frame_widget->SetLayerTreeView(widget_client->layer_tree_view());
- client->BindWidgetClient(std::move(widget_client));
}
+ if (widget_client)
+ client->BindWidgetClient(std::move(widget_client));
return frame;
}
@@ -247,9 +256,11 @@ WebLocalFrameImpl* CreateLocalChild(WebRemoteFrame& parent,
TestWebWidgetClient* widget_client) {
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
WebLocalFrameImpl* frame = ToWebLocalFrameImpl(parent.CreateLocalChild(
WebTreeScopeType::kDocument, name, WebSandboxFlags::kNone, client,
- nullptr, previous_sibling, ParsedFeaturePolicy(), properties,
+ nullptr, mojo::MakeRequest(&document_interface_broker).PassMessagePipe(),
+ previous_sibling, ParsedFeaturePolicy(), properties,
FrameOwnerElementType::kIframe, nullptr));
client->Bind(frame, std::move(owned_client));
@@ -289,6 +300,8 @@ WebRemoteFrameImpl* CreateRemoteChild(
WebViewHelper::WebViewHelper() : web_view_(nullptr) {}
WebViewHelper::~WebViewHelper() {
+ // Close the WebViewImpl before the WebViewClient/WebWidgetClient are
+ // destroyed.
Reset();
}
@@ -296,7 +309,7 @@ WebViewImpl* WebViewHelper::InitializeWithOpener(
WebFrame* opener,
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
- TestWebWidgetClient* test_web_widget_client,
+ TestWebWidgetClient* web_widget_client,
void (*update_settings_func)(WebSettings*)) {
Reset();
@@ -307,16 +320,21 @@ WebViewImpl* WebViewHelper::InitializeWithOpener(
std::unique_ptr<TestWebFrameClient> owned_web_frame_client;
web_frame_client =
CreateDefaultClientIfNeeded(web_frame_client, owned_web_frame_client);
+ mojom::blink::DocumentInterfaceBrokerPtrInfo document_interface_broker;
WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
- web_view_, web_frame_client, nullptr, opener);
+ web_view_, web_frame_client, nullptr,
+ mojo::MakeRequest(&document_interface_broker).PassMessagePipe(), opener);
web_frame_client->Bind(frame, std::move(owned_web_frame_client));
+ test_web_widget_client_ = CreateDefaultClientIfNeeded(
+ web_widget_client, owned_test_web_widget_client_);
// TODO(dcheng): The main frame widget currently has a special case.
// Eliminate this once WebView is no longer a WebWidget.
- WebWidgetClient* web_widget_client = test_web_widget_client;
- if (!web_widget_client)
- web_widget_client = test_web_view_client_->WidgetClient();
- blink::WebFrameWidget::CreateForMainFrame(web_widget_client, frame);
+ blink::WebFrameWidget::CreateForMainFrame(test_web_widget_client_, frame);
+ // TODO(danakj): Make this part of attaching the main frame's WebFrameWidget.
+ web_view_->MainFrameWidget()->SetLayerTreeView(
+ test_web_widget_client_->layer_tree_view());
+
// Set an initial size for subframes.
if (frame->Parent())
frame->FrameWidget()->Resize(WebSize());
@@ -333,6 +351,12 @@ WebViewImpl* WebViewHelper::Initialize(
web_widget_client, update_settings_func);
}
+WebViewImpl* WebViewHelper::InitializeWithSettings(
+ void (*update_settings_func)(WebSettings*)) {
+ return InitializeWithOpener(nullptr, nullptr, nullptr, nullptr,
+ update_settings_func);
+}
+
WebViewImpl* WebViewHelper::InitializeAndLoad(
const std::string& url,
TestWebFrameClient* web_frame_client,
@@ -350,7 +374,8 @@ WebViewImpl* WebViewHelper::InitializeAndLoad(
WebViewImpl* WebViewHelper::InitializeRemote(
TestWebRemoteFrameClient* web_remote_frame_client,
scoped_refptr<SecurityOrigin> security_origin,
- TestWebViewClient* web_view_client) {
+ TestWebViewClient* web_view_client,
+ TestWebWidgetClient* web_widget_client) {
Reset();
InitializeWebView(web_view_client, nullptr);
@@ -366,6 +391,13 @@ WebViewImpl* WebViewHelper::InitializeRemote(
security_origin = SecurityOrigin::CreateUniqueOpaque();
frame->GetFrame()->GetSecurityContext()->SetReplicatedOrigin(
std::move(security_origin));
+
+ test_web_widget_client_ = CreateDefaultClientIfNeeded(
+ web_widget_client, owned_test_web_widget_client_);
+ // TODO(danakj): Remove this! Make WebViewImpl not need a WebWidgetClient when
+ // the main frame is remote.
+ web_view_->SetWebWidgetClient(test_web_widget_client_);
+
return web_view_;
}
@@ -377,11 +409,15 @@ void WebViewHelper::LoadAhem() {
}
void WebViewHelper::Reset() {
+ if (test_web_view_client_)
+ test_web_view_client_->DestroyChildViews();
if (web_view_) {
DCHECK(!TestWebFrameClient::IsLoading());
- web_view_->Close();
+ // This closes the WebView also.
+ web_view_->MainFrameWidget()->Close();
web_view_ = nullptr;
}
+ test_web_view_client_ = nullptr;
}
WebLocalFrameImpl* WebViewHelper::LocalMainFrame() const {
@@ -393,19 +429,17 @@ WebRemoteFrameImpl* WebViewHelper::RemoteMainFrame() const {
}
void WebViewHelper::Resize(WebSize size) {
- test_web_view_client_->ClearAnimationScheduled();
- GetWebView()->Resize(size);
- EXPECT_FALSE(test_web_view_client_->AnimationScheduled());
- test_web_view_client_->ClearAnimationScheduled();
+ GetWebView()->MainFrameWidget()->Resize(size);
}
void WebViewHelper::InitializeWebView(TestWebViewClient* web_view_client,
class WebView* opener) {
- web_view_client =
+ test_web_view_client_ =
CreateDefaultClientIfNeeded(web_view_client, owned_test_web_view_client_);
web_view_ = static_cast<WebViewImpl*>(
- WebView::Create(web_view_client, web_view_client,
- mojom::PageVisibilityState::kVisible, opener));
+ WebView::Create(test_web_view_client_,
+ /*is_hidden=*/false,
+ /*compositing_enabled=*/true, opener));
web_view_->GetSettings()->SetJavaScriptEnabled(true);
web_view_->GetSettings()->SetPluginsEnabled(true);
// Enable (mocked) network loads of image URLs, as this simplifies
@@ -415,18 +449,17 @@ void WebViewHelper::InitializeWebView(TestWebViewClient* web_view_client,
// Consequently, all external image resources must be mocked.
web_view_->GetSettings()->SetLoadsImagesAutomatically(true);
- web_view_->SetLayerTreeView(web_view_client->layer_tree_view());
web_view_->SetDeviceScaleFactor(
- web_view_client->GetScreenInfo().device_scale_factor);
+ test_web_view_client_->GetScreenInfo().device_scale_factor);
web_view_->SetDefaultPageScaleLimits(1, 4);
-
- test_web_view_client_ = web_view_client;
}
int TestWebFrameClient::loads_in_progress_ = 0;
TestWebFrameClient::TestWebFrameClient()
- : interface_provider_(new service_manager::InterfaceProvider()) {}
+ : interface_provider_(new service_manager::InterfaceProvider()),
+ effective_connection_type_(WebEffectiveConnectionType::kTypeUnknown),
+ weak_factory_(this) {}
void TestWebFrameClient::Bind(WebLocalFrame* frame,
std::unique_ptr<TestWebFrameClient> self_owned) {
@@ -476,14 +509,50 @@ void TestWebFrameClient::DidStopLoading() {
void TestWebFrameClient::BeginNavigation(
std::unique_ptr<WebNavigationInfo> info) {
- frame_->CommitNavigation(
- info->url_request, info->frame_load_type, blink::WebHistoryItem(),
- info->is_client_redirect, base::UnguessableToken::Create(),
- nullptr /* navigation_params */, nullptr /* extra_data */);
+ navigation_callback_.Cancel();
+ if (DocumentLoader::WillLoadUrlAsEmpty(info->url_request.Url()) ||
+ !frame_->HasCommittedFirstRealLoad()) {
+ CommitNavigation(std::move(info));
+ return;
+ }
+
+ if (!frame_->CreatePlaceholderDocumentLoader(*info, nullptr /* extra_data */))
+ return;
+
+ navigation_callback_.Reset(
+ base::BindOnce(&TestWebFrameClient::CommitNavigation,
+ weak_factory_.GetWeakPtr(), std::move(info)));
+ frame_->GetTaskRunner(blink::TaskType::kInternalLoading)
+ ->PostTask(FROM_HERE, navigation_callback_.callback());
+}
+
+void TestWebFrameClient::CommitNavigation(
+ std::unique_ptr<WebNavigationInfo> info) {
+ if (!frame_)
+ return;
+ auto params = WebNavigationParams::CreateFromInfo(*info);
+ frame_->CommitNavigation(std::move(params), nullptr /* extra_data */);
+}
+
+WebEffectiveConnectionType TestWebFrameClient::GetEffectiveConnectionType() {
+ return effective_connection_type_;
+}
+
+void TestWebFrameClient::SetEffectiveConnectionTypeForTesting(
+ WebEffectiveConnectionType effective_connection_type) {
+ effective_connection_type_ = effective_connection_type;
+}
+
+void TestWebFrameClient::DidAddMessageToConsole(
+ const WebConsoleMessage& message,
+ const WebString& source_name,
+ unsigned source_line,
+ const WebString& stack_trace) {
+ console_messages_.push_back(message.text);
}
-void TestWebFrameClient::DidCreateDocumentLoader(
- WebDocumentLoader* document_loader) {
+WebPlugin* TestWebFrameClient::CreatePlugin(const WebPluginParams& params) {
+ return new FakeWebPlugin(params);
}
TestWebRemoteFrameClient::TestWebRemoteFrameClient() = default;
@@ -515,11 +584,11 @@ content::LayerTreeView* LayerTreeViewFactory::Initialize(
// For web contents, layer transforms should scale up the contents of layers
// to keep content always crisp when possible.
settings.layer_transforms_should_scale_layer_contents = true;
- // Both BlinkGenPropertyTrees and SlimmingPaintV2 should imply layer lists in
- // the compositor. Some code across the boundaries makes assumptions based on
- // this so ensure tests run using this configuration as well.
+ // Both BlinkGenPropertyTrees and CompositeAfterPaint should imply layer lists
+ // in the compositor. Some code across the boundaries makes assumptions based
+ // on this so ensure tests run using this configuration as well.
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
settings.use_layer_lists = true;
}
@@ -533,12 +602,42 @@ content::LayerTreeView* LayerTreeViewFactory::Initialize(
return layer_tree_view_.get();
}
-TestWebWidgetClient::TestWebWidgetClient() {
- layer_tree_view_ = layer_tree_view_factory_.Initialize();
+TestWebWidgetClient::TestWebWidgetClient(
+ content::LayerTreeViewDelegate* delegate) {
+ layer_tree_view_ = layer_tree_view_factory_.Initialize(delegate);
}
-TestWebViewClient::TestWebViewClient(content::LayerTreeViewDelegate* delegate) {
- layer_tree_view_ = layer_tree_view_factory_.Initialize(delegate);
+void TestWebWidgetClient::DidMeaningfulLayout(
+ WebMeaningfulLayout meaningful_layout) {
+ switch (meaningful_layout) {
+ case WebMeaningfulLayout::kVisuallyNonEmpty:
+ visually_non_empty_layout_count_++;
+ break;
+ case WebMeaningfulLayout::kFinishedParsing:
+ finished_parsing_layout_count_++;
+ break;
+ case WebMeaningfulLayout::kFinishedLoading:
+ finished_loading_layout_count_++;
+ break;
+ }
+}
+
+void TestWebViewClient::DestroyChildViews() {
+ child_web_views_.clear();
+}
+
+WebView* TestWebViewClient::CreateView(WebLocalFrame* opener,
+ const WebURLRequest&,
+ const WebWindowFeatures&,
+ const WebString& name,
+ WebNavigationPolicy,
+ bool,
+ WebSandboxFlags,
+ const SessionStorageNamespaceId&) {
+ auto webview_helper = std::make_unique<WebViewHelper>();
+ WebView* result = webview_helper->InitializeWithOpener(opener);
+ child_web_views_.push_back(std::move(webview_helper));
+ return result;
}
} // namespace frame_test_helpers
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h
index ccfbc3273ca..bd4aa756469 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -37,12 +37,13 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "cc/test/test_task_graph_runner.h"
-#include "content/renderer/gpu/layer_tree_view.h"
+#include "content/renderer/compositor/layer_tree_view.h"
#include "content/test/stub_layer_tree_view_delegate.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/test/web_fake_thread_scheduler.h"
#include "third_party/blink/public/platform/web_mouse_event.h"
@@ -59,6 +60,7 @@
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/core/testing/use_mock_scrollbar_settings.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
#define EXPECT_FLOAT_POINT_EQ(expected, actual) \
do { \
@@ -93,10 +95,12 @@ class TestWebFrameClient;
class TestWebRemoteFrameClient;
class TestWebWidgetClient;
class TestWebViewClient;
+class WebViewHelper;
-// Loads a url into the specified WebLocalFrame for testing purposes. Pumps any
-// pending resource requests, as well as waiting for the threaded parser to
-// finish, before returning.
+// Loads a url into the specified WebLocalFrame for testing purposes.
+void LoadFrameDontWait(WebLocalFrame*, const WebURL& url);
+// Same as above, but also pumps any pending resource requests,
+// as well as waiting for the threaded parser to finish, before returning.
void LoadFrame(WebLocalFrame*, const std::string& url);
// Same as above, but for WebLocalFrame::LoadHTMLString().
void LoadHTMLString(WebLocalFrame*,
@@ -181,40 +185,62 @@ class LayerTreeViewFactory {
class TestWebWidgetClient : public WebWidgetClient {
public:
- TestWebWidgetClient();
+ // If no delegate is given, a stub is used.
+ explicit TestWebWidgetClient(content::LayerTreeViewDelegate* = nullptr);
~TestWebWidgetClient() override = default;
+ // WebWidgetClient:
+ void ScheduleAnimation() override { animation_scheduled_ = true; }
+
content::LayerTreeView* layer_tree_view() { return layer_tree_view_; }
+ bool AnimationScheduled() { return animation_scheduled_; }
+ void ClearAnimationScheduled() { animation_scheduled_ = false; }
+
+ void DidMeaningfulLayout(WebMeaningfulLayout) override;
+
+ int VisuallyNonEmptyLayoutCount() const {
+ return visually_non_empty_layout_count_;
+ }
+ int FinishedParsingLayoutCount() const {
+ return finished_parsing_layout_count_;
+ }
+ int FinishedLoadingLayoutCount() const {
+ return finished_loading_layout_count_;
+ }
+
private:
content::LayerTreeView* layer_tree_view_ = nullptr;
LayerTreeViewFactory layer_tree_view_factory_;
+ bool animation_scheduled_ = false;
+ int visually_non_empty_layout_count_ = 0;
+ int finished_parsing_layout_count_ = 0;
+ int finished_loading_layout_count_ = 0;
};
-class TestWebViewClient : public WebViewClient, public WebWidgetClient {
+class TestWebViewClient : public WebViewClient {
public:
- // If no delegate is given, a stub is used.
- explicit TestWebViewClient(content::LayerTreeViewDelegate* = nullptr);
+ TestWebViewClient() = default;
~TestWebViewClient() override = default;
- content::LayerTreeView* layer_tree_view() { return layer_tree_view_; }
-
- // WebWidgetClient:
- void ScheduleAnimation() override { animation_scheduled_ = true; }
+ void DestroyChildViews();
- // WebViewClient:
+ // WebViewClient overrides.
bool CanHandleGestureEvent() override { return true; }
bool CanUpdateLayout() override { return true; }
- WebWidgetClient* WidgetClient() override { return this; }
blink::WebScreenInfo GetScreenInfo() override { return {}; }
-
- bool AnimationScheduled() { return animation_scheduled_; }
- void ClearAnimationScheduled() { animation_scheduled_ = false; }
+ WebView* CreateView(WebLocalFrame* opener,
+ const WebURLRequest&,
+ const WebWindowFeatures&,
+ const WebString& name,
+ WebNavigationPolicy,
+ bool,
+ WebSandboxFlags,
+ const SessionStorageNamespaceId&) override;
private:
- content::LayerTreeView* layer_tree_view_ = nullptr;
LayerTreeViewFactory layer_tree_view_factory_;
- bool animation_scheduled_ = false;
+ WTF::Vector<std::unique_ptr<WebViewHelper>> child_web_views_;
};
// Convenience class for handling the lifetime of a WebView and its associated
@@ -244,6 +270,11 @@ class WebViewHelper {
TestWebWidgetClient* = nullptr,
void (*update_settings_func)(WebSettings*) = nullptr);
+ // Same as InitializeWithOpener(), but passes null for everything but the
+ // settings function.
+ WebViewImpl* InitializeWithSettings(
+ void (*update_settings_func)(WebSettings*));
+
// Same as Initialize() but also performs the initial load of the url. Only
// returns once the load is complete.
WebViewImpl* InitializeAndLoad(
@@ -258,7 +289,8 @@ class WebViewHelper {
// origin.
WebViewImpl* InitializeRemote(TestWebRemoteFrameClient* = nullptr,
scoped_refptr<SecurityOrigin> = nullptr,
- TestWebViewClient* = nullptr);
+ TestWebViewClient* = nullptr,
+ TestWebWidgetClient* = nullptr);
// Load the 'Ahem' font to this WebView.
// The 'Ahem' font is the only font whose font metrics is consistent across
@@ -272,20 +304,23 @@ class WebViewHelper {
WebViewImpl* GetWebView() const { return web_view_; }
content::LayerTreeView* GetLayerTreeView() const {
- return test_web_view_client_->layer_tree_view();
+ return test_web_widget_client_->layer_tree_view();
}
WebLocalFrameImpl* LocalMainFrame() const;
WebRemoteFrameImpl* RemoteMainFrame() const;
private:
- void InitializeWebView(TestWebViewClient*, class WebView* opener);
+ void InitializeWebView(TestWebViewClient*,
+ class WebView* opener);
WebViewImpl* web_view_;
UseMockScrollbarSettings mock_scrollbar_settings_;
- // Non-null if the WebViewHelper owns the TestWebViewClient.
+
std::unique_ptr<TestWebViewClient> owned_test_web_view_client_;
- TestWebViewClient* test_web_view_client_;
+ TestWebViewClient* test_web_view_client_ = nullptr;
+ std::unique_ptr<TestWebWidgetClient> owned_test_web_widget_client_;
+ TestWebWidgetClient* test_web_widget_client_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(WebViewHelper);
};
@@ -299,6 +334,7 @@ class TestWebFrameClient : public WebLocalFrameClient {
~TestWebFrameClient() override = default;
static bool IsLoading() { return loads_in_progress_ > 0; }
+ Vector<String>& ConsoleMessages() { return console_messages_; }
WebNavigationControl* Frame() const { return frame_; }
// Pass ownership of the TestWebFrameClient to |self_owned| here if the
@@ -320,7 +356,6 @@ class TestWebFrameClient : public WebLocalFrameClient {
FrameOwnerElementType) override;
void DidStartLoading() override;
void DidStopLoading() override;
- void DidCreateDocumentLoader(WebDocumentLoader*) override;
service_manager::InterfaceProvider* GetInterfaceProvider() override {
return interface_provider_.get();
}
@@ -331,8 +366,18 @@ class TestWebFrameClient : public WebLocalFrameClient {
return Platform::Current()->CreateDefaultURLLoaderFactory();
}
void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override;
+ WebEffectiveConnectionType GetEffectiveConnectionType() override;
+ void SetEffectiveConnectionTypeForTesting(
+ WebEffectiveConnectionType) override;
+ void DidAddMessageToConsole(const WebConsoleMessage&,
+ const WebString& source_name,
+ unsigned source_line,
+ const WebString& stack_trace) override;
+ WebPlugin* CreatePlugin(const WebPluginParams& params) override;
private:
+ void CommitNavigation(std::unique_ptr<WebNavigationInfo>);
+
static int loads_in_progress_;
// If set to a non-null value, self-deletes on frame detach.
@@ -346,7 +391,12 @@ class TestWebFrameClient : public WebLocalFrameClient {
// Bind().
WebNavigationControl* frame_ = nullptr;
+ base::CancelableOnceCallback<void()> navigation_callback_;
std::unique_ptr<WebWidgetClient> owned_widget_client_;
+ WebEffectiveConnectionType effective_connection_type_;
+ Vector<String> console_messages_;
+
+ base::WeakPtrFactory<TestWebFrameClient> weak_factory_;
};
// Minimal implementation of WebRemoteFrameClient needed for unit tests that
diff --git a/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc b/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc
index 2e6d3604102..3c0cb048b5e 100644
--- a/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc
+++ b/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc
@@ -256,7 +256,8 @@ void FullscreenController::UpdatePageScaleConstraints(bool reset_constraints) {
web_view_base_->GetPageScaleConstraintsSet().SetNeedsReset(true);
} else {
fullscreen_constraints = PageScaleConstraints(1.0, 1.0, 1.0);
- fullscreen_constraints.layout_size = FloatSize(web_view_base_->Size());
+ fullscreen_constraints.layout_size =
+ FloatSize(web_view_base_->MainFrameWidget()->Size());
}
web_view_base_->GetPageScaleConstraintsSet().SetFullscreenConstraints(
fullscreen_constraints);
diff --git a/chromium/third_party/blink/renderer/core/frame/history.cc b/chromium/third_party/blink/renderer/core/frame/history.cc
index 5446de4128f..32923260452 100644
--- a/chromium/third_party/blink/renderer/core/frame/history.cc
+++ b/chromium/third_party/blink/renderer/core/frame/history.cc
@@ -213,7 +213,6 @@ void History::pushState(scoped_refptr<SerializedScriptValue> data,
ExceptionState& exception_state) {
StateObjectAdded(std::move(data), title, url, ScrollRestorationInternal(),
WebFrameLoadType::kStandard, exception_state);
- UseCounter::Count(GetFrame(), WebFeature::kHistoryPushState);
}
void History::replaceState(scoped_refptr<SerializedScriptValue> data,
@@ -222,7 +221,6 @@ void History::replaceState(scoped_refptr<SerializedScriptValue> data,
ExceptionState& exception_state) {
StateObjectAdded(std::move(data), title, url, ScrollRestorationInternal(),
WebFrameLoadType::kReplaceCurrentItem, exception_state);
- UseCounter::Count(GetFrame(), WebFeature::kHistoryReplaceState);
}
KURL History::UrlForState(const String& url_string) {
diff --git a/chromium/third_party/blink/renderer/core/frame/history.idl b/chromium/third_party/blink/renderer/core/frame/history.idl
index 376d6c5f56d..1d3633dd101 100644
--- a/chromium/third_party/blink/renderer/core/frame/history.idl
+++ b/chromium/third_party/blink/renderer/core/frame/history.idl
@@ -28,13 +28,13 @@
enum ScrollRestoration {"auto", "manual"};
interface History {
- [RaisesException] readonly attribute unsigned long length;
+ [MeasureAs=HistoryLength, RaisesException] readonly attribute unsigned long length;
[Measure, RaisesException] attribute ScrollRestoration scrollRestoration;
// TODO(foolip): The SerializedScriptValue type should be any.
[CachedAttribute=stateChanged, RaisesException] readonly attribute SerializedScriptValue state;
[CallWith=ScriptState, RaisesException] void go(optional long delta = 0);
[CallWith=ScriptState, RaisesException] void back();
[CallWith=ScriptState, RaisesException] void forward();
- [RaisesException] void pushState(SerializedScriptValue data, DOMString title, optional DOMString? url = null);
- [RaisesException] void replaceState(SerializedScriptValue data, DOMString title, optional DOMString? url = null);
+ [MeasureAs=HistoryPushState, RaisesException] void pushState(SerializedScriptValue data, DOMString title, optional DOMString? url = null);
+ [MeasureAs=HistoryReplaceState, RaisesException] void replaceState(SerializedScriptValue data, DOMString title, optional DOMString? url = null);
};
diff --git a/chromium/third_party/blink/renderer/core/frame/link_highlights.cc b/chromium/third_party/blink/renderer/core/frame/link_highlights.cc
index 8a4ec54e697..9f570e96278 100644
--- a/chromium/third_party/blink/renderer/core/frame/link_highlights.cc
+++ b/chromium/third_party/blink/renderer/core/frame/link_highlights.cc
@@ -132,4 +132,10 @@ CompositorElementId LinkHighlights::element_id(const LayoutObject& object) {
return CompositorElementId();
}
+void LinkHighlights::Paint(GraphicsContext& context) const {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ for (const auto& highlight : link_highlights_)
+ highlight->Paint(context);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/link_highlights.h b/chromium/third_party/blink/renderer/core/frame/link_highlights.h
index 55bf38e6ddc..fc58e13eb67 100644
--- a/chromium/third_party/blink/renderer/core/frame/link_highlights.h
+++ b/chromium/third_party/blink/renderer/core/frame/link_highlights.h
@@ -13,6 +13,7 @@
namespace blink {
+class GraphicsContext;
class Page;
class LinkHighlightImpl;
class CompositorAnimationHost;
@@ -21,6 +22,12 @@ class WebLayerTreeView;
class LocalFrame;
class LayoutObject;
+// TODO(wangxianzhu): Since the tap disambiguation feature was removed,
+// (http://crrev.com/c/579263), LinkHighlights no longer needs to manage
+// multiple link highlights. Rename this class to LinkHighlight and move
+// it under core/page, and rename LinkHighlightImpl (core/paint) to
+// LinkHighlightPainter. This will be convenient to do when we remove
+// GraphicsLayer for CompositeAfterPaint.
class CORE_EXPORT LinkHighlights final
: public GarbageCollectedFinalized<LinkHighlights> {
public:
@@ -55,12 +62,17 @@ class CORE_EXPORT LinkHighlights final
CompositorElementId element_id(const LayoutObject& object);
+ // For CompositeAfterPaint.
+ void Paint(GraphicsContext&) const;
+
private:
FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, verifyWebViewImplIntegration);
FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, resetDuringNodeRemoval);
FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, resetLayerTreeView);
+ FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, HighlightInvalidation);
FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, multipleHighlights);
FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, HighlightLayerEffectNode);
+ FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, MultiColumn);
void RemoveAllHighlights();
diff --git a/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc b/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc
index 49aa591e6c8..2adb444114a 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -48,6 +48,7 @@
#include "third_party/blink/renderer/core/css/media_query_matcher.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_media.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
#include "third_party/blink/renderer/core/dom/dom_implementation.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
@@ -74,7 +75,6 @@
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/core/frame/pausable_timer.h"
#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
#include "third_party/blink/renderer/core/frame/screen.h"
#include "third_party/blink/renderer/core/frame/scroll_to_options.h"
@@ -107,6 +107,7 @@
#include "third_party/blink/renderer/platform/bindings/microtask.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
+#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
@@ -114,72 +115,6 @@ namespace blink {
// Timeout for link preloads to be used after window.onload
static constexpr TimeDelta kUnusedPreloadTimeout = TimeDelta::FromSeconds(3);
-class PostMessageTimer final
- : public GarbageCollectedFinalized<PostMessageTimer>,
- public PausableTimer {
- USING_GARBAGE_COLLECTED_MIXIN(PostMessageTimer);
-
- public:
- PostMessageTimer(LocalDOMWindow& window,
- MessageEvent* event,
- scoped_refptr<const SecurityOrigin> target_origin,
- std::unique_ptr<SourceLocation> location,
- UserGestureToken* user_gesture_token)
- : PausableTimer(window.document(), TaskType::kPostedMessage),
- event_(event),
- window_(&window),
- target_origin_(std::move(target_origin)),
- location_(std::move(location)),
- user_gesture_token_(user_gesture_token),
- disposal_allowed_(true) {}
-
- MessageEvent* Event() const { return event_; }
- const SecurityOrigin* TargetOrigin() const { return target_origin_.get(); }
- std::unique_ptr<SourceLocation> TakeLocation() {
- return std::move(location_);
- }
- UserGestureToken* GetUserGestureToken() const {
- return user_gesture_token_.get();
- }
- void ContextDestroyed(ExecutionContext* destroyed_context) override {
- PausableTimer::ContextDestroyed(destroyed_context);
-
- if (disposal_allowed_)
- Dispose();
- }
-
- // Eager finalization is needed to promptly stop this timer object.
- // (see DOMTimer comment for more.)
- EAGERLY_FINALIZE();
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(event_);
- visitor->Trace(window_);
- PausableTimer::Trace(visitor);
- }
-
- // TODO(alexclarke): Override timerTaskRunner() to pass in a document specific
- // default task runner.
-
- private:
- void Fired() override {
- probe::AsyncTask async_task(window_->document(), this);
- disposal_allowed_ = false;
- window_->PostMessageTimerFired(this);
- Dispose();
- // Oilpan optimization: unregister as an observer right away.
- ClearContext();
- }
-
- void Dispose() { window_->RemovePostMessageTimer(this); }
-
- Member<MessageEvent> event_;
- Member<LocalDOMWindow> window_;
- scoped_refptr<const SecurityOrigin> target_origin_;
- std::unique_ptr<SourceLocation> location_;
- scoped_refptr<UserGestureToken> user_gesture_token_;
- bool disposal_allowed_;
-};
-
static void UpdateSuddenTerminationStatus(
LocalDOMWindow* dom_window,
bool added_listener,
@@ -282,14 +217,14 @@ void LocalDOMWindow::ClearDocument() {
void LocalDOMWindow::AcceptLanguagesChanged() {
if (navigator_)
- navigator_->SetLanguagesChanged();
+ navigator_->SetLanguagesDirty();
DispatchEvent(*Event::Create(event_type_names::kLanguagechange));
}
TrustedTypePolicyFactory* LocalDOMWindow::trustedTypes() const {
if (!trusted_types_)
- trusted_types_ = TrustedTypePolicyFactory::Create(GetFrame());
+ trusted_types_ = TrustedTypePolicyFactory::Create(GetExecutionContext());
return trusted_types_.Get();
}
@@ -603,37 +538,35 @@ void LocalDOMWindow::SchedulePostMessage(
// is problematic; consider imposing a limit or other restriction if this
// surfaces often as a problem (see crbug.com/587012).
std::unique_ptr<SourceLocation> location = SourceLocation::Capture(source);
- PostMessageTimer* timer = MakeGarbageCollected<PostMessageTimer>(
- *this, event, std::move(target), std::move(location),
- UserGestureIndicator::CurrentToken());
- timer->StartOneShot(TimeDelta(), FROM_HERE);
- timer->PauseIfNeeded();
- probe::AsyncTaskScheduled(document(), "postMessage", timer);
- post_message_timers_.insert(timer);
+ document_->GetTaskRunner(TaskType::kPostedMessage)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&LocalDOMWindow::DispatchPostMessage,
+ WrapPersistent(this), WrapPersistent(event),
+ WrapRefCounted(UserGestureIndicator::CurrentToken()),
+ std::move(target), std::move(location)));
+ probe::AsyncTaskScheduled(document(), "postMessage", event);
}
-void LocalDOMWindow::PostMessageTimerFired(PostMessageTimer* timer) {
+void LocalDOMWindow::DispatchPostMessage(
+ MessageEvent* event,
+ scoped_refptr<UserGestureToken> token,
+ scoped_refptr<const SecurityOrigin> intended_target_origin,
+ std::unique_ptr<SourceLocation> location) {
+ probe::AsyncTask async_task(document(), event);
if (!IsCurrentlyDisplayedInFrame())
return;
- MessageEvent* event = timer->Event();
-
- UserGestureToken* token = timer->GetUserGestureToken();
std::unique_ptr<UserGestureIndicator> gesture_indicator;
if (!RuntimeEnabledFeatures::UserActivationV2Enabled() && token &&
token->HasGestures() && document()) {
gesture_indicator =
- LocalFrame::NotifyUserActivation(document()->GetFrame(), token);
+ LocalFrame::NotifyUserActivation(document()->GetFrame(), token.get());
}
event->EntangleMessagePorts(document());
- DispatchMessageEventWithOriginCheck(timer->TargetOrigin(), event,
- timer->TakeLocation());
-}
-
-void LocalDOMWindow::RemovePostMessageTimer(PostMessageTimer* timer) {
- post_message_timers_.erase(timer);
+ DispatchMessageEventWithOriginCheck(intended_target_origin.get(), event,
+ std::move(location));
}
void LocalDOMWindow::DispatchMessageEventWithOriginCheck(
@@ -1468,83 +1401,51 @@ void LocalDOMWindow::PrintErrorMessage(const String& message) const {
ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));
}
-DOMWindow* LocalDOMWindow::open(ExecutionContext* executionContext,
- LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
+ const USVStringOrTrustedURL& string_or_url,
const AtomicString& target,
const String& features,
ExceptionState& exception_state) {
- String url = GetStringFromTrustedURL(stringOrUrl, document_, exception_state);
- if (!exception_state.HadException()) {
- return openFromString(executionContext, current_window, entered_window, url,
- target, features, exception_state);
- }
- return nullptr;
-}
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
+ LocalDOMWindow* entered_window = EnteredDOMWindow(isolate);
-DOMWindow* LocalDOMWindow::openFromString(ExecutionContext* executionContext,
- LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String& url,
- const AtomicString& target,
- const String& features,
- ExceptionState& exception_state) {
// If the bindings implementation is 100% correct, the current realm and the
// entered realm should be same origin-domain. However, to be on the safe
- // side and add some defense in depth, we'll check against the entered realm
+ // side and add some defense in depth, we'll check against the entry realm
// as well here.
if (!BindingSecurity::ShouldAllowAccessTo(entered_window, this,
exception_state)) {
- UseCounter::Count(executionContext, WebFeature::kWindowOpenRealmMismatch);
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kWindowOpenRealmMismatch);
return nullptr;
}
- DCHECK(!target.IsNull());
- return openFromString(url, target, features, current_window, entered_window,
- exception_state);
-}
-DOMWindow* LocalDOMWindow::open(const USVStringOrTrustedURL& stringOrUrl,
- const AtomicString& frame_name,
- const String& window_features_string,
- LocalDOMWindow* calling_window,
- LocalDOMWindow* entered_window,
- ExceptionState& exception_state) {
- String url = GetStringFromTrustedURL(stringOrUrl, document_, exception_state);
- if (!exception_state.HadException()) {
- return openFromString(url, frame_name, window_features_string,
- calling_window, entered_window, exception_state);
- }
- return nullptr;
-}
+ const String& url_string =
+ GetStringFromTrustedURL(string_or_url, document_, exception_state);
+ if (exception_state.HadException())
+ return nullptr;
-DOMWindow* LocalDOMWindow::openFromString(const String& url_string,
- const AtomicString& frame_name,
- const String& window_features_string,
- LocalDOMWindow* calling_window,
- LocalDOMWindow* entered_window,
- ExceptionState& exception_state) {
if (!IsCurrentlyDisplayedInFrame())
return nullptr;
- if (!calling_window->GetFrame())
+ if (!incumbent_window->GetFrame())
return nullptr;
- Document* active_document = calling_window->document();
+ Document* active_document = incumbent_window->document();
if (!active_document)
return nullptr;
- LocalFrame* first_frame = entered_window->GetFrame();
- if (!first_frame)
+ LocalFrame* entered_window_frame = entered_window->GetFrame();
+ if (!entered_window_frame)
return nullptr;
UseCounter::Count(*active_document, WebFeature::kDOMWindowOpen);
- if (!window_features_string.IsEmpty())
+ if (!features.IsEmpty())
UseCounter::Count(*active_document, WebFeature::kDOMWindowOpenFeatures);
// Get the target frame for the special cases of _top and _parent.
// In those cases, we schedule a location change right now and return early.
Frame* target_frame = nullptr;
- if (EqualIgnoringASCIICase(frame_name, "_top")) {
+ if (EqualIgnoringASCIICase(target, "_top")) {
target_frame = &GetFrame()->Tree().Top();
- } else if (EqualIgnoringASCIICase(frame_name, "_parent")) {
+ } else if (EqualIgnoringASCIICase(target, "_parent")) {
if (Frame* parent = GetFrame()->Tree().Parent())
target_frame = parent;
else
@@ -1557,9 +1458,10 @@ DOMWindow* LocalDOMWindow::openFromString(const String& url_string,
return nullptr;
}
- KURL completed_url = first_frame->GetDocument()->CompleteURL(url_string);
+ KURL completed_url =
+ entered_window_frame->GetDocument()->CompleteURL(url_string);
- if (target_frame->DomWindow()->IsInsecureScriptAccess(*calling_window,
+ if (target_frame->DomWindow()->IsInsecureScriptAccess(*incumbent_window,
completed_url))
return target_frame->DomWindow();
@@ -1572,10 +1474,8 @@ DOMWindow* LocalDOMWindow::openFromString(const String& url_string,
return target_frame->DomWindow();
}
- DOMWindow* new_window =
- CreateWindow(url_string, frame_name, window_features_string,
- *calling_window, *first_frame, *GetFrame(), exception_state);
- return new_window;
+ return CreateWindow(url_string, target, features, *incumbent_window,
+ *entered_window_frame, *GetFrame(), exception_state);
}
void LocalDOMWindow::Trace(blink::Visitor* visitor) {
@@ -1594,7 +1494,6 @@ void LocalDOMWindow::Trace(blink::Visitor* visitor) {
visitor->Trace(modulator_);
visitor->Trace(external_);
visitor->Trace(application_cache_);
- visitor->Trace(post_message_timers_);
visitor->Trace(visualViewport_);
visitor->Trace(event_listener_observers_);
visitor->Trace(trusted_types_);
diff --git a/chromium/third_party/blink/renderer/core/frame/local_dom_window.h b/chromium/third_party/blink/renderer/core/frame/local_dom_window.h
index a15415a0bcc..7b4a71dac5e 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -60,7 +60,6 @@ class MediaQueryList;
class MessageEvent;
class Modulator;
class Navigator;
-class PostMessageTimer;
class Screen;
class ScriptedTaskQueueController;
class ScriptPromise;
@@ -271,27 +270,22 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
Element* frameElement() const;
- DOMWindow* open(ExecutionContext*,
- LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+ DOMWindow* open(v8::Isolate*,
+ const USVStringOrTrustedURL& string_or_url,
const AtomicString& target,
const String& features,
ExceptionState&);
- DOMWindow* open(const USVStringOrTrustedURL& stringOrUrl,
- const AtomicString& frame_name,
- const String& window_features_string,
- LocalDOMWindow* calling_window,
- LocalDOMWindow* entered_window,
- ExceptionState&);
-
FrameConsole* GetFrameConsole() const;
void PrintErrorMessage(const String&) const;
- void PostMessageTimerFired(PostMessageTimer*);
- void RemovePostMessageTimer(PostMessageTimer*);
+ void DispatchPostMessage(
+ MessageEvent* event,
+ scoped_refptr<UserGestureToken> token,
+ scoped_refptr<const SecurityOrigin> intended_target_origin,
+ std::unique_ptr<SourceLocation>);
+
void DispatchMessageEventWithOriginCheck(
const SecurityOrigin* intended_target_origin,
Event*,
@@ -347,21 +341,6 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
void DispatchLoadEvent();
void ClearDocument();
- DOMWindow* openFromString(ExecutionContext*,
- LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String& url,
- const AtomicString& target,
- const String& features,
- ExceptionState&);
-
- DOMWindow* openFromString(const String& url_string,
- const AtomicString& frame_name,
- const String& window_features_string,
- LocalDOMWindow* calling_window,
- LocalDOMWindow* entered_window,
- ExceptionState&);
-
// Return the viewport size including scrollbars.
IntSize GetViewportSize() const;
@@ -397,7 +376,6 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
scoped_refptr<SerializedScriptValue> pending_state_object_;
- HeapHashSet<Member<PostMessageTimer>> post_message_timers_;
HeapHashSet<WeakMember<EventListenerObserver>> event_listener_observers_;
mutable Member<TrustedTypePolicyFactory> trusted_types_;
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.cc b/chromium/third_party/blink/renderer/core/frame/local_frame.cc
index 72df3508f9e..9c8ffb99f78 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame.cc
@@ -66,6 +66,7 @@
#include "third_party/blink/renderer/core/frame/ad_tracker.h"
#include "third_party/blink/renderer/core/frame/event_handler_registry.h"
#include "third_party/blink/renderer/core/frame/frame_console.h"
+#include "third_party/blink/renderer/core/frame/frame_overlay.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -100,8 +101,10 @@
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h"
@@ -290,7 +293,7 @@ LocalFrame::~LocalFrame() {
// Verify that the LocalFrameView has been cleared as part of detaching
// the frame owner.
DCHECK(!view_);
- if (is_ad_subframe_)
+ if (IsAdSubframe())
InstanceCounters::DecrementCounter(InstanceCounters::kAdSubframeCounter);
}
@@ -349,10 +352,11 @@ void LocalFrame::DetachImpl(FrameDetachType type) {
// Starting here, the code must be safe against re-entrancy. Dispatching
// events, et cetera can run Javascript, which can reenter Detach().
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
if (this == UserActivationNotifierFrame())
UserActivationNotifierFrame().Clear();
+ frame_color_overlay_.reset();
+
if (IsLocalRoot()) {
performance_monitor_->Shutdown();
if (ad_tracker_)
@@ -517,21 +521,21 @@ Frame* LocalFrame::FindFrameForNavigation(const AtomicString& name,
void LocalFrame::Reload(WebFrameLoadType load_type,
ClientRedirectPolicy client_redirect_policy) {
DCHECK(IsReloadLoadType(load_type));
- if (client_redirect_policy == ClientRedirectPolicy::kNotClientRedirect) {
- if (!loader_.GetDocumentLoader()->GetHistoryItem())
- return;
- FrameLoadRequest request = FrameLoadRequest(
- nullptr,
- loader_.ResourceRequestForReload(load_type, client_redirect_policy));
- request.SetClientRedirect(client_redirect_policy);
- if (const WebInputEvent* input_event = CurrentInputEvent::Get()) {
- request.SetInputStartTime(input_event->TimeStamp());
- }
- loader_.StartNavigation(request, load_type);
- } else {
- DCHECK_EQ(WebFrameLoadType::kReload, load_type);
- navigation_scheduler_->ScheduleReload();
+ if (!loader_.GetDocumentLoader()->GetHistoryItem())
+ return;
+ FrameLoadRequest request = FrameLoadRequest(
+ nullptr,
+ loader_.ResourceRequestForReload(load_type, client_redirect_policy));
+ request.SetClientRedirect(client_redirect_policy);
+ if (const WebInputEvent* input_event = CurrentInputEvent::Get())
+ request.SetInputStartTime(input_event->TimeStamp());
+ if (client_redirect_policy == ClientRedirectPolicy::kClientRedirect) {
+ probe::frameScheduledNavigation(this, request.GetResourceRequest().Url(),
+ 0.0, ClientNavigationReason::kReload);
+ probe::frameClearedScheduledNavigation(this);
}
+
+ loader_.StartNavigation(request, load_type);
}
LocalWindowProxy* LocalFrame::WindowProxy(DOMWrapperWorld& world) {
@@ -581,8 +585,7 @@ void LocalFrame::DidFreeze() {
// handler indicating potentially unsaved user state.
bool unused_did_allow_navigation = false;
bool proceed = GetDocument()->DispatchBeforeUnloadEvent(
- *View()->GetChromeClient(), false /* is_reload */,
- true /* auto_cancel */, unused_did_allow_navigation);
+ nullptr, false /* is_reload */, unused_did_allow_navigation);
frame_resource_coordinator->SetHasNonEmptyBeforeUnload(!proceed);
}
@@ -821,7 +824,8 @@ void LocalFrame::SetPageAndTextZoomFactors(float page_zoom_factor,
document->SetNeedsStyleRecalc(
kSubtreeStyleChange,
StyleChangeReasonForTracing::Create(style_change_reason::kZoom));
- document->UpdateStyleAndLayoutIgnorePendingStylesheets();
+ if (View() && View()->DidFirstLayout())
+ document->UpdateStyleAndLayoutIgnorePendingStylesheets();
}
void LocalFrame::DeviceScaleFactorChanged() {
@@ -916,7 +920,7 @@ String LocalFrame::GetLayerTreeAsTextForTesting(unsigned flags) const {
return String();
std::unique_ptr<JSONObject> layers;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
layers = View()->CompositedLayersAsJSON(static_cast<LayerTreeFlags>(flags));
} else {
if (const auto* root_layer =
@@ -970,12 +974,12 @@ inline LocalFrame::LocalFrame(LocalFrameClient* client,
!(GetSettings() && GetSettings()->GetDataSaverHoldbackWebApi()) &&
GetNetworkStateNotifier().SaveDataEnabled()) {
if (IsLocalRoot()) {
- probe_sink_ = new CoreProbeSink();
+ probe_sink_ = MakeGarbageCollected<CoreProbeSink>();
performance_monitor_ = MakeGarbageCollected<PerformanceMonitor>(this);
inspector_trace_events_ = MakeGarbageCollected<InspectorTraceEvents>();
probe_sink_->addInspectorTraceEvents(inspector_trace_events_);
if (RuntimeEnabledFeatures::AdTaggingEnabled()) {
- ad_tracker_ = new AdTracker(this);
+ ad_tracker_ = MakeGarbageCollected<AdTracker>(this);
}
} else {
// Inertness only needs to be updated if this frame might inherit the
@@ -1048,7 +1052,7 @@ bool LocalFrame::CanNavigate(const Frame& target_frame,
if (has_user_gesture)
framebust_params |= kUserGestureBit;
- if (is_ad_subframe_)
+ if (IsAdSubframe())
framebust_params |= kAdBit;
UseCounter::Count(this, WebFeature::kTopNavigationFromSubFrame);
@@ -1274,8 +1278,10 @@ void LocalFrame::SetIsAdSubframeIfNecessary() {
bool parent_is_ad =
parent->IsLocalFrame() && ToLocalFrame(parent)->IsAdSubframe();
- if (parent_is_ad || ad_tracker_->IsAdScriptInStack())
- SetIsAdSubframe();
+ if (parent_is_ad || ad_tracker_->IsAdScriptInStack()) {
+ SetIsAdSubframe(parent_is_ad ? blink::mojom::AdFrameType::kChildAd
+ : blink::mojom::AdFrameType::kRootAd);
+ }
}
service_manager::InterfaceProvider& LocalFrame::GetInterfaceProvider() {
@@ -1283,6 +1289,12 @@ service_manager::InterfaceProvider& LocalFrame::GetInterfaceProvider() {
return *Client()->GetInterfaceProvider();
}
+mojom::blink::DocumentInterfaceBroker&
+LocalFrame::GetDocumentInterfaceBroker() {
+ DCHECK(Client());
+ return *Client()->GetDocumentInterfaceBroker();
+}
+
AssociatedInterfaceProvider*
LocalFrame::GetRemoteNavigationAssociatedInterfaces() {
DCHECK(Client());
@@ -1480,6 +1492,41 @@ ComputedAccessibleNode* LocalFrame::GetOrCreateComputedAccessibleNode(
return computed_node_mapping_.at(ax_id);
}
+bool LocalFrame::IsAdSubframe() const {
+ return ad_frame_type_ != blink::mojom::AdFrameType::kNonAd;
+}
+
+bool LocalFrame::IsAdRoot() const {
+ return ad_frame_type_ == blink::mojom::AdFrameType::kRootAd;
+}
+
+void LocalFrame::SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type) {
+ DCHECK(!IsMainFrame());
+
+ // Once |ad_frame_type_| has been set to an ad type on this frame, it cannot
+ // be changed.
+ if (ad_frame_type == blink::mojom::AdFrameType::kNonAd)
+ return;
+ if (ad_frame_type_ != blink::mojom::AdFrameType::kNonAd)
+ return;
+ ad_frame_type_ = ad_frame_type;
+ UpdateAdHighlight();
+ frame_scheduler_->SetIsAdFrame();
+ InstanceCounters::IncrementCounter(InstanceCounters::kAdSubframeCounter);
+}
+
+void LocalFrame::UpdateAdHighlight() {
+ if (!IsAdRoot()) {
+ // Verify that non root ad subframes do not have an overlay.
+ DCHECK(IsMainFrame() || !frame_color_overlay_);
+ return;
+ }
+ if (GetPage()->GetSettings().GetHighlightAds())
+ SetSubframeColorOverlay(SkColorSetARGB(128, 255, 0, 0));
+ else
+ SetSubframeColorOverlay(Color::kTransparent);
+}
+
void LocalFrame::PauseSubresourceLoading(
blink::mojom::blink::PauseSubresourceLoadingHandleRequest request) {
auto handle = GetFrameScheduler()->GetPauseSubresourceLoadingHandle();
@@ -1621,4 +1668,90 @@ bool LocalFrame::ConsumeTransientUserActivation(
return ConsumeTransientUserActivationInLocalTree();
}
+namespace {
+
+class FrameColorOverlay final : public FrameOverlay::Delegate {
+ public:
+ explicit FrameColorOverlay(LocalFrame* frame, SkColor color)
+ : color_(color), frame_(frame) {}
+
+ private:
+ void PaintFrameOverlay(const FrameOverlay& frame_overlay,
+ GraphicsContext& graphics_context,
+ const IntSize&) const override {
+ const auto* view = frame_->View();
+ DCHECK(view);
+ if (view->Width() == 0 || view->Height() == 0)
+ return;
+ ScopedPaintChunkProperties properties(
+ graphics_context.GetPaintController(),
+ view->GetLayoutView()->FirstFragment().LocalBorderBoxProperties(),
+ frame_overlay, DisplayItem::kFrameOverlay);
+ if (DrawingRecorder::UseCachedDrawingIfPossible(
+ graphics_context, frame_overlay, DisplayItem::kFrameOverlay))
+ return;
+ DrawingRecorder recorder(graphics_context, frame_overlay,
+ DisplayItem::kFrameOverlay);
+ FloatRect rect(0, 0, view->Width(), view->Height());
+ graphics_context.FillRect(rect, color_);
+ }
+
+ SkColor color_;
+ Persistent<LocalFrame> frame_;
+};
+
+} // namespace
+
+void LocalFrame::SetMainFrameColorOverlay(SkColor color) {
+ DCHECK(IsMainFrame());
+ SetFrameColorOverlay(color);
+}
+
+void LocalFrame::SetSubframeColorOverlay(SkColor color) {
+ DCHECK(!IsMainFrame());
+ SetFrameColorOverlay(color);
+}
+
+void LocalFrame::SetFrameColorOverlay(SkColor color) {
+ frame_color_overlay_.reset();
+
+ if (color == Color::kTransparent)
+ return;
+
+ frame_color_overlay_ = FrameOverlay::Create(
+ this, std::make_unique<FrameColorOverlay>(this, color));
+
+ // Update compositing which will create graphics layers so the page color
+ // update below will be able to attach to the root graphics layer.
+ if (View()) {
+ View()->UpdateLifecycleToCompositingCleanPlusScrolling();
+ frame_color_overlay_->Update();
+ }
+}
+
+void LocalFrame::PaintFrameColorOverlay() {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (!frame_color_overlay_)
+ return;
+ frame_color_overlay_->Update();
+ if (frame_color_overlay_->GetGraphicsLayer())
+ frame_color_overlay_->GetGraphicsLayer()->Paint();
+}
+
+void LocalFrame::PaintFrameColorOverlay(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (!frame_color_overlay_)
+ return;
+ frame_color_overlay_->Update();
+ frame_color_overlay_->Paint(context);
+}
+
+void LocalFrame::ForciblyPurgeV8Memory() {
+ GetDocument()->NotifyContextDestroyed();
+
+ WindowProxyManager* window_proxy_manager = GetWindowProxyManager();
+ window_proxy_manager->ClearForV8MemoryPurge();
+ Loader().StopAllLoaders();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.h b/chromium/third_party/blink/renderer/core/frame/local_frame.h
index 2c4d2eaf11b..92ea3730539 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame.h
@@ -33,6 +33,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "third_party/blink/public/mojom/ad_tagging/ad_frame.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h"
#include "third_party/blink/public/platform/reporting.mojom-blink.h"
@@ -75,6 +76,7 @@ class EventHandler;
class EventHandlerRegistry;
class FloatSize;
class FrameConsole;
+class FrameOverlay;
class FrameResourceCoordinator;
// class FrameScheduler;
class FrameSelection;
@@ -105,6 +107,12 @@ class WebContentSettingsClient;
class WebPluginContainerImpl;
class WebURLLoaderFactory;
+namespace mojom {
+namespace blink {
+class DocumentInterfaceBroker;
+} // namespace blink
+} // namespace mojom
+
extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<LocalFrame>;
class CORE_EXPORT LocalFrame final : public Frame,
@@ -294,6 +302,7 @@ class CORE_EXPORT LocalFrame final : public Frame,
bool CanNavigate(const Frame&, const KURL& destination_url = KURL());
service_manager::InterfaceProvider& GetInterfaceProvider();
+ mojom::blink::DocumentInterfaceBroker& GetDocumentInterfaceBroker();
InterfaceRegistry* GetInterfaceRegistry() { return interface_registry_; }
// Returns an AssociatedInterfaceProvider the frame can use to request
@@ -347,7 +356,9 @@ class CORE_EXPORT LocalFrame final : public Frame,
// viewport intersection and occlusion/obscuration available that accounts for
// remote ancestor frames and their respective scroll positions, clips, etc.
void SetViewportIntersectionFromParent(const IntRect&, bool);
- IntRect RemoteViewportIntersection() { return remote_viewport_intersection_; }
+ IntRect RemoteViewportIntersection() const {
+ return remote_viewport_intersection_;
+ }
bool MayBeOccludedOrObscuredByRemoteAncestor() const {
return occluded_or_obscured_by_ancestor_;
}
@@ -380,15 +391,12 @@ class CORE_EXPORT LocalFrame final : public Frame,
// Calculated in the constructor but LocalFrames created on behalf of OOPIF
// aren't set until just before commit (ReadyToCommitNavigation time) by the
// embedder.
- bool IsAdSubframe() const { return is_ad_subframe_; }
- void SetIsAdSubframe() {
- DCHECK(!IsMainFrame());
- if (is_ad_subframe_)
- return;
- is_ad_subframe_ = true;
- frame_scheduler_->SetIsAdFrame();
- InstanceCounters::IncrementCounter(InstanceCounters::kAdSubframeCounter);
- }
+ bool IsAdSubframe() const;
+ bool IsAdRoot() const;
+ void SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type);
+
+ // Updates the frame color overlay to match the highlight ad setting.
+ void UpdateAdHighlight();
// Binds |request| and prevents resource loading until either the frame is
// navigated or the request pipe is closed.
@@ -410,6 +418,21 @@ class CORE_EXPORT LocalFrame final : public Frame,
const mojom::blink::ReportingServiceProxyPtr& GetReportingService() const;
+ // Overlays a color on top of this LocalFrameView if it is associated with
+ // the main frame. Should not have multiple consumers.
+ void SetMainFrameColorOverlay(SkColor color);
+
+ // Overlays a color on top of this LocalFrameView if it is associated with
+ // a subframe. Should not have multiple consumers.
+ void SetSubframeColorOverlay(SkColor color);
+ void PaintFrameColorOverlay();
+
+ // For CompositeAfterPaint.
+ void PaintFrameColorOverlay(GraphicsContext&);
+
+ // To be called from OomInterventionImpl.
+ void ForciblyPurgeV8Memory();
+
private:
friend class FrameNavigationDisabler;
@@ -453,6 +476,8 @@ class CORE_EXPORT LocalFrame final : public Frame,
// after updating all ancestor/descendant frames.
bool ConsumeTransientUserActivation(UserActivationUpdateSource update_source);
+ void SetFrameColorOverlay(SkColor color);
+
std::unique_ptr<FrameScheduler> frame_scheduler_;
// Holds all PauseSubresourceLoadingHandles allowing either |this| to delete
@@ -490,11 +515,11 @@ class CORE_EXPORT LocalFrame final : public Frame,
bool in_view_source_mode_;
- // True if this frame is heuristically determined to have been created for
- // advertising purposes. It's per-frame (as opposed to per-document) because
- // when an iframe is created on behalf of ad script that same frame is not
- // typically reused for non-ad purposes.
- bool is_ad_subframe_ = false;
+ // Type of frame detected by heuristics checking if the frame was created
+ // for advertising purposes. It's per-frame (as opposed to per-document)
+ // because when an iframe is created on behalf of ad script that same frame is
+ // not typically reused for non-ad purposes.
+ blink::mojom::AdFrameType ad_frame_type_ = blink::mojom::AdFrameType::kNonAd;
Member<CoreProbeSink> probe_sink_;
scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
@@ -536,6 +561,8 @@ class CORE_EXPORT LocalFrame final : public Frame,
// state that get updated whenever the network state changes. That way, this
// field would be no longer necessary.
const bool is_save_data_enabled_;
+
+ std::unique_ptr<FrameOverlay> frame_color_overlay_;
};
inline FrameLoader& LocalFrame::Loader() const {
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_client.h b/chromium/third_party/blink/renderer/core/frame/local_frame_client.h
index 9f97e491238..da19c0a3644 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -35,6 +35,7 @@
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/mojom/frame/navigation_initiator.mojom-blink.h"
+#include "third_party/blink/public/mojom/portal/portal.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_effective_connection_type.h"
@@ -55,6 +56,7 @@
#include "third_party/blink/renderer/core/frame/frame_client.h"
#include "third_party/blink/renderer/core/frame/frame_types.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/remote_frame.h"
#include "third_party/blink/renderer/core/html/link_resource.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
@@ -75,6 +77,10 @@ class InterfaceProvider;
namespace blink {
namespace mojom {
enum class WebFeature : int32_t;
+
+namespace blink {
+class DocumentInterfaceBroker;
+} // namespace blink
} // namespace mojom
class AssociatedInterfaceProvider;
@@ -83,6 +89,7 @@ class DocumentLoader;
class HTMLFormElement;
class HTMLFrameOwnerElement;
class HTMLMediaElement;
+class HTMLPortalElement;
class HTMLPlugInElement;
class HistoryItem;
class KURL;
@@ -91,8 +98,6 @@ class ResourceError;
class ResourceRequest;
class ResourceResponse;
class SecurityOrigin;
-class SharedWorkerRepositoryClient;
-class SubstituteData;
class WebApplicationCacheHost;
class WebApplicationCacheHostClient;
class WebCookieJar;
@@ -133,8 +138,7 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
WebHistoryCommitType,
bool content_initiated) {}
virtual void DispatchWillCommitProvisionalLoad() = 0;
- virtual void DispatchDidStartProvisionalLoad(DocumentLoader*,
- const ResourceRequest&) = 0;
+ virtual void DispatchDidStartProvisionalLoad(DocumentLoader*) = 0;
virtual void DispatchDidReceiveTitle(const String&) = 0;
virtual void DispatchDidChangeIcons(IconType) = 0;
virtual void DispatchDidCommitLoad(HistoryItem*,
@@ -164,6 +168,7 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
mojom::blink::BlobURLTokenPtr,
base::TimeTicks input_start_time,
const String& href_translate,
+ WebContentSecurityPolicyList,
mojom::blink::NavigationInitiatorPtr) = 0;
virtual void DispatchWillSendSubmitEvent(HTMLFormElement*) = 0;
@@ -245,11 +250,6 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual DocumentLoader* CreateDocumentLoader(
LocalFrame*,
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType,
WebNavigationType,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) = 0;
@@ -267,6 +267,13 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual LocalFrame* CreateFrame(const AtomicString& name,
HTMLFrameOwnerElement*) = 0;
+ // Creates a portal for the |HTMLPortalElement| and binds the other end of the
+ // |PortalRequest|. Returns a pair of a RemoteFrame and a token that
+ // identifies the portal.
+ virtual std::pair<RemoteFrame*, base::UnguessableToken> CreatePortal(
+ HTMLPortalElement*,
+ mojom::blink::PortalRequest) = 0;
+
// Whether or not plugin creation should fail if the HTMLPlugInElement isn't
// in the DOM after plugin initialization.
enum DetachedPluginPolicy {
@@ -343,10 +350,6 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual WebContentSettingsClient* GetContentSettingsClient() = 0;
- virtual SharedWorkerRepositoryClient* GetSharedWorkerRepositoryClient() {
- return nullptr;
- }
-
virtual std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
WebApplicationCacheHostClient*) = 0;
@@ -383,6 +386,10 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
return nullptr;
}
+ virtual mojom::blink::DocumentInterfaceBroker* GetDocumentInterfaceBroker() {
+ return nullptr;
+ }
+
virtual AssociatedInterfaceProvider*
GetRemoteNavigationAssociatedInterfaces() {
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
index 87d8798a1df..cb48172ae6c 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -33,7 +33,6 @@
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "cc/layers/picture_layer.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
@@ -51,6 +50,7 @@
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/frame/browser_controls.h"
#include "third_party/blink/renderer/core/frame/event_handler_registry.h"
+#include "third_party/blink/renderer/core/frame/frame_overlay.h"
#include "third_party/blink/renderer/core/frame/frame_view_auto_size_info.h"
#include "third_party/blink/renderer/core/frame/link_highlights.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -70,6 +70,8 @@
#include "third_party/blink/renderer/core/html/html_frame_element.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
+#include "third_party/blink/renderer/core/html/portal/document_portals.h"
+#include "third_party/blink/renderer/core/html/portal/html_portal_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
@@ -96,11 +98,13 @@
#include "third_party/blink/renderer/core/page/frame_tree.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/print_context.h"
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_context.h"
#include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
#include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
#include "third_party/blink/renderer/core/page/validation_message_client.h"
#include "third_party/blink/renderer/core/paint/block_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
@@ -132,7 +136,6 @@
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
@@ -166,10 +169,6 @@ constexpr int kA4PortraitPageHeight = 842;
constexpr int kLetterPortraitPageWidth = 612;
constexpr int kLetterPortraitPageHeight = 792;
-constexpr char kCssFragmentIdentifierPrefix[] = "targetElement=";
-constexpr size_t kCssFragmentIdentifierPrefixLength =
- base::size(kCssFragmentIdentifierPrefix);
-
// Logs a UseCounter for the size of the cursor that will be set. This will be
// used for compatibility analysis to determine whether the maximum size can be
// reduced.
@@ -221,9 +220,7 @@ LocalFrameView::LocalFrameView(LocalFrame& frame, IntRect frame_rect)
visually_non_empty_character_count_(0),
visually_non_empty_pixel_count_(0),
is_visually_non_empty_(false),
- fragment_anchor_(nullptr),
sticky_position_object_count_(0),
- input_events_scale_factor_for_emulation_(1),
layout_size_fixed_to_frame_size_(true),
needs_update_geometries_(false),
root_layer_did_scroll_(false),
@@ -245,13 +242,19 @@ LocalFrameView::LocalFrameView(LocalFrame& frame, IntRect frame_rect)
base::WrapUnique(g_initial_track_all_paint_invalidations
? new Vector<ObjectPaintInvalidation>
: nullptr)),
+ composited_element_ids_(CompositorElementIdSet()),
main_thread_scrolling_reasons_(0),
forced_layout_stack_depth_(0),
forced_layout_start_time_(TimeTicks()),
paint_frame_count_(0),
unique_id_(NewUniqueObjectId()),
jank_tracker_(std::make_unique<JankTracker>(this)),
- paint_timing_detector_(new PaintTimingDetector(this)) {
+ paint_timing_detector_(MakeGarbageCollected<PaintTimingDetector>(this))
+#if DCHECK_IS_ON()
+ ,
+ is_updating_descendant_dependent_flags_(false)
+#endif
+{
// Propagate the marginwidth/height and scrolling modes to the view.
if (frame_->Owner() &&
frame_->Owner()->ScrollingMode() == kScrollbarAlwaysOff)
@@ -294,6 +297,7 @@ void LocalFrameView::Trace(blink::Visitor* visitor) {
visitor->Trace(anchoring_adjustment_queue_);
visitor->Trace(print_context_);
visitor->Trace(paint_timing_detector_);
+ visitor->Trace(lifecycle_observers_);
}
template <typename Function>
@@ -307,6 +311,14 @@ void LocalFrameView::ForAllChildViewsAndPlugins(const Function& function) {
for (const auto& plugin : plugins_) {
function(*plugin);
}
+
+ if (Document* document = frame_->GetDocument()) {
+ for (HTMLPortalElement* portal :
+ DocumentPortals::From(*document).GetPortals()) {
+ if (Frame* frame = portal->ContentFrame())
+ function(*frame->View());
+ }
+ }
}
template <typename Function>
@@ -624,21 +636,7 @@ void LocalFrameView::PerformPreLayoutTasks() {
void LocalFrameView::LayoutFromRootObject(LayoutObject& root) {
LayoutState layout_state(root);
- if (!root.IsBoxModelObject()) {
- root.UpdateLayout();
- } else {
- // Laying out the root may change its visual overflow. If so, that
- // visual overflow needs to propagate to its containing block.
- LayoutBoxModelObject& box_object = ToLayoutBoxModelObject(root);
- LayoutRect previous_visual_overflow_rect = box_object.VisualOverflowRect();
- box_object.UpdateLayout();
- if (box_object.VisualOverflowRect() != previous_visual_overflow_rect) {
- // TODO(chrishtr): this can probably just set the dirty bit for
- // visual overflow, not layout overflow.
- box_object.SetNeedsOverflowRecalc();
- GetLayoutView()->RecalcOverflow();
- }
- }
+ root.UpdateLayout();
}
void LocalFrameView::PrepareLayoutAnalyzer() {
@@ -750,195 +748,193 @@ void LocalFrameView::UpdateLayout() {
DCHECK_EQ(frame_->View(), this);
DCHECK(frame_->GetPage());
- {
- ScriptForbiddenScope forbid_script;
+ ScriptForbiddenScope forbid_script;
- if (IsInPerformLayout() || ShouldThrottleRendering() ||
- !frame_->GetDocument()->IsActive())
- return;
+ if (IsInPerformLayout() || ShouldThrottleRendering() ||
+ !frame_->GetDocument()->IsActive())
+ return;
- TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout");
+ TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout");
- RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(),
- RuntimeCallStats::CounterId::kUpdateLayout);
+ RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(),
+ RuntimeCallStats::CounterId::kUpdateLayout);
- // The actual call to UpdateGeometries is in PerformPostLayoutTasks.
- SetNeedsUpdateGeometries();
+ // The actual call to UpdateGeometries is in PerformPostLayoutTasks.
+ SetNeedsUpdateGeometries();
- if (auto_size_info_)
- auto_size_info_->AutoSizeIfNeeded();
+ if (auto_size_info_)
+ auto_size_info_->AutoSizeIfNeeded();
+
+ has_pending_layout_ = false;
+
+ Document* document = frame_->GetDocument();
+ TRACE_EVENT_BEGIN1("devtools.timeline", "Layout", "beginData",
+ inspector_layout_event::BeginData(this));
+ probe::UpdateLayout probe(document);
+
+ PerformPreLayoutTasks();
- has_pending_layout_ = false;
+ VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
+ DoubleSize viewport_size(visual_viewport.VisibleWidthCSSPx(),
+ visual_viewport.VisibleHeightCSSPx());
- Document* document = frame_->GetDocument();
- TRACE_EVENT_BEGIN1("devtools.timeline", "Layout", "beginData",
- inspector_layout_event::BeginData(this));
- probe::UpdateLayout probe(document);
+ // TODO(crbug.com/460956): The notion of a single root for layout is no
+ // longer applicable. Remove or update this code.
+ LayoutObject* root_for_this_layout = GetLayoutView();
- PerformPreLayoutTasks();
+ FontCachePurgePreventer font_cache_purge_preventer;
+ {
+ base::AutoReset<bool> change_scheduling_enabled(&layout_scheduling_enabled_,
+ false);
+ nested_layout_count_++;
+
+ // If the layout view was marked as needing layout after we added items in
+ // the subtree roots we need to clear the roots and do the layout from the
+ // layoutView.
+ if (GetLayoutView()->NeedsLayout())
+ ClearLayoutSubtreeRootsAndMarkContainingBlocks();
+ GetLayoutView()->ClearHitTestCache();
- VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
- DoubleSize viewport_size(visual_viewport.VisibleWidthCSSPx(),
- visual_viewport.VisibleHeightCSSPx());
+ bool in_subtree_layout = IsSubtreeLayout();
// TODO(crbug.com/460956): The notion of a single root for layout is no
// longer applicable. Remove or update this code.
- LayoutObject* root_for_this_layout = GetLayoutView();
-
- FontCachePurgePreventer font_cache_purge_preventer;
- {
- base::AutoReset<bool> change_scheduling_enabled(
- &layout_scheduling_enabled_, false);
- nested_layout_count_++;
-
- // If the layout view was marked as needing layout after we added items in
- // the subtree roots we need to clear the roots and do the layout from the
- // layoutView.
- if (GetLayoutView()->NeedsLayout())
- ClearLayoutSubtreeRootsAndMarkContainingBlocks();
- GetLayoutView()->ClearHitTestCache();
-
- bool in_subtree_layout = IsSubtreeLayout();
-
- // TODO(crbug.com/460956): The notion of a single root for layout is no
- // longer applicable. Remove or update this code.
- if (in_subtree_layout)
- root_for_this_layout = layout_subtree_root_list_.RandomRoot();
-
- if (!root_for_this_layout) {
- // FIXME: Do we need to set m_size here?
- NOTREACHED();
- return;
- }
+ if (in_subtree_layout)
+ root_for_this_layout = layout_subtree_root_list_.RandomRoot();
+
+ if (!root_for_this_layout) {
+ // FIXME: Do we need to set m_size here?
+ NOTREACHED();
+ return;
+ }
- if (!in_subtree_layout) {
- ClearLayoutSubtreeRootsAndMarkContainingBlocks();
- Node* body = document->body();
- if (body && body->GetLayoutObject()) {
- if (IsHTMLFrameSetElement(*body)) {
+ if (!in_subtree_layout) {
+ ClearLayoutSubtreeRootsAndMarkContainingBlocks();
+ Node* body = document->body();
+ if (body && body->GetLayoutObject()) {
+ if (IsHTMLFrameSetElement(*body)) {
+ body->GetLayoutObject()->SetChildNeedsLayout();
+ } else if (IsHTMLBodyElement(*body)) {
+ if (!first_layout_ && size_.Height() != GetLayoutSize().Height() &&
+ body->GetLayoutObject()->EnclosingBox()->StretchesToViewport())
body->GetLayoutObject()->SetChildNeedsLayout();
- } else if (IsHTMLBodyElement(*body)) {
- if (!first_layout_ && size_.Height() != GetLayoutSize().Height() &&
- body->GetLayoutObject()->EnclosingBox()->StretchesToViewport())
- body->GetLayoutObject()->SetChildNeedsLayout();
- }
}
+ }
- if (first_layout_) {
- first_layout_ = false;
- last_viewport_size_ = GetLayoutSize();
- last_zoom_factor_ = GetLayoutView()->StyleRef().Zoom();
-
- ScrollbarMode h_mode;
- ScrollbarMode v_mode;
- GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
- if (v_mode == kScrollbarAuto) {
- GetLayoutView()
- ->GetScrollableArea()
- ->ForceVerticalScrollbarForFirstLayout();
- }
+ if (first_layout_) {
+ first_layout_ = false;
+ last_viewport_size_ = GetLayoutSize();
+ last_zoom_factor_ = GetLayoutView()->StyleRef().Zoom();
+
+ ScrollbarMode h_mode;
+ ScrollbarMode v_mode;
+ GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
+ if (v_mode == kScrollbarAuto) {
+ GetLayoutView()
+ ->GetScrollableArea()
+ ->ForceVerticalScrollbarForFirstLayout();
}
+ }
- LayoutSize old_size = size_;
-
- size_ = LayoutSize(GetLayoutSize());
-
- if (old_size != size_ && !first_layout_) {
- LayoutBox* root_layout_object =
- document->documentElement()
- ? document->documentElement()->GetLayoutBox()
- : nullptr;
- LayoutBox* body_layout_object = root_layout_object && document->body()
- ? document->body()->GetLayoutBox()
- : nullptr;
- if (body_layout_object && body_layout_object->StretchesToViewport())
- body_layout_object->SetChildNeedsLayout();
- else if (root_layout_object &&
- root_layout_object->StretchesToViewport())
- root_layout_object->SetChildNeedsLayout();
- }
+ LayoutSize old_size = size_;
+
+ size_ = LayoutSize(GetLayoutSize());
+
+ if (old_size != size_ && !first_layout_) {
+ LayoutBox* root_layout_object =
+ document->documentElement()
+ ? document->documentElement()->GetLayoutBox()
+ : nullptr;
+ LayoutBox* body_layout_object = root_layout_object && document->body()
+ ? document->body()->GetLayoutBox()
+ : nullptr;
+ if (body_layout_object && body_layout_object->StretchesToViewport())
+ body_layout_object->SetChildNeedsLayout();
+ else if (root_layout_object &&
+ root_layout_object->StretchesToViewport())
+ root_layout_object->SetChildNeedsLayout();
}
+ }
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree",
- this, TracedLayoutObject::Create(*GetLayoutView(), false));
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree",
+ this, TracedLayoutObject::Create(*GetLayoutView(), false));
- IntSize old_size(Size());
+ IntSize old_size(Size());
- PerformLayout(in_subtree_layout);
+ PerformLayout(in_subtree_layout);
- IntSize new_size(Size());
- if (old_size != new_size) {
- SetNeedsLayout();
- MarkViewportConstrainedObjectsForLayout(
- old_size.Width() != new_size.Width(),
- old_size.Height() != new_size.Height());
- }
+ IntSize new_size(Size());
+ if (old_size != new_size) {
+ SetNeedsLayout();
+ MarkViewportConstrainedObjectsForLayout(
+ old_size.Width() != new_size.Width(),
+ old_size.Height() != new_size.Height());
+ }
- if (NeedsLayout()) {
- base::AutoReset<bool> suppress(&suppress_adjust_view_size_, true);
- UpdateLayout();
- }
+ if (NeedsLayout()) {
+ base::AutoReset<bool> suppress(&suppress_adjust_view_size_, true);
+ UpdateLayout();
+ }
- DCHECK(layout_subtree_root_list_.IsEmpty());
- } // Reset m_layoutSchedulingEnabled to its previous value.
- CheckDoesNotNeedLayout();
+ DCHECK(layout_subtree_root_list_.IsEmpty());
+ } // Reset m_layoutSchedulingEnabled to its previous value.
+ CheckDoesNotNeedLayout();
- DocumentLifecycle::Scope lifecycle_scope(Lifecycle(),
- DocumentLifecycle::kLayoutClean);
+ DocumentLifecycle::Scope lifecycle_scope(Lifecycle(),
+ DocumentLifecycle::kLayoutClean);
- frame_timing_requests_dirty_ = true;
+ frame_timing_requests_dirty_ = true;
- // FIXME: Could find the common ancestor layer of all dirty subtrees and
- // mark from there. crbug.com/462719
- GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
+ // FIXME: Could find the common ancestor layer of all dirty subtrees and
+ // mark from there. crbug.com/462719
+ GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree",
- this, TracedLayoutObject::Create(*GetLayoutView(), true));
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", this,
+ TracedLayoutObject::Create(*GetLayoutView(), true));
- GetLayoutView()->Compositor()->DidLayout();
- layout_count_for_testing_++;
+ GetLayoutView()->Compositor()->DidLayout();
+ layout_count_for_testing_++;
- if (AXObjectCache* cache = document->ExistingAXObjectCache()) {
- const KURL& url = document->Url();
- if (url.IsValid() && !url.IsAboutBlankURL()) {
- cache->HandleLayoutComplete(document);
- cache->ProcessUpdatesAfterLayout(*document);
- }
+ if (AXObjectCache* cache = document->ExistingAXObjectCache()) {
+ const KURL& url = document->Url();
+ if (url.IsValid() && !url.IsAboutBlankURL()) {
+ cache->HandleLayoutComplete(document);
+ cache->ProcessUpdatesAfterLayout(*document);
}
- UpdateDocumentAnnotatedRegions();
- CheckDoesNotNeedLayout();
+ }
+ UpdateDocumentAnnotatedRegions();
+ CheckDoesNotNeedLayout();
- if (nested_layout_count_ == 1) {
- PerformPostLayoutTasks();
- CheckDoesNotNeedLayout();
- }
+ if (nested_layout_count_ == 1) {
+ PerformPostLayoutTasks();
+ CheckDoesNotNeedLayout();
+ }
- // FIXME: The notion of a single root for layout is no longer applicable.
- // Remove or update this code. crbug.com/460596
- TRACE_EVENT_END1("devtools.timeline", "Layout", "endData",
- inspector_layout_event::EndData(root_for_this_layout));
- probe::didChangeViewport(frame_.Get());
+ // FIXME: The notion of a single root for layout is no longer applicable.
+ // Remove or update this code. crbug.com/460596
+ TRACE_EVENT_END1("devtools.timeline", "Layout", "endData",
+ inspector_layout_event::EndData(root_for_this_layout));
+ probe::didChangeViewport(frame_.Get());
- nested_layout_count_--;
- if (nested_layout_count_)
- return;
+ nested_layout_count_--;
+ if (nested_layout_count_)
+ return;
#if DCHECK_IS_ON()
- // Post-layout assert that nobody was re-marked as needing layout during
- // layout.
- GetLayoutView()->AssertSubtreeIsLaidOut();
+ // Post-layout assert that nobody was re-marked as needing layout during
+ // layout.
+ GetLayoutView()->AssertSubtreeIsLaidOut();
#endif
- if (frame_->IsMainFrame()) {
- // Scrollbars changing state can cause a visual viewport size change.
- DoubleSize new_viewport_size(visual_viewport.VisibleWidthCSSPx(),
- visual_viewport.VisibleHeightCSSPx());
- if (new_viewport_size != viewport_size)
- frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
- }
- } // ScriptForbiddenScope
+ if (frame_->IsMainFrame()) {
+ // Scrollbars changing state can cause a visual viewport size change.
+ DoubleSize new_viewport_size(visual_viewport.VisibleWidthCSSPx(),
+ visual_viewport.VisibleHeightCSSPx());
+ if (new_viewport_size != viewport_size)
+ frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
+ }
GetFrame().GetDocument()->LayoutUpdated();
CheckDoesNotNeedLayout();
@@ -1262,8 +1258,7 @@ void LocalFrameView::MarkViewportConstrainedObjectsForLayout(
bool LocalFrameView::ShouldSetCursor() const {
Page* page = GetFrame().GetPage();
- return page &&
- page->VisibilityState() != mojom::PageVisibilityState::kHidden &&
+ return page && page->IsPageVisible() &&
!frame_->GetEventHandler().IsMousePositionUnknown() &&
page->GetFocusController().IsActive();
}
@@ -1280,14 +1275,12 @@ void LocalFrameView::InvalidateBackgroundAttachmentFixedDescendantsOnScroll(
if (scrolled_object != GetLayoutView() &&
!layout_object->IsDescendantOf(&scrolled_object))
continue;
- // An object needs to be repainted on scroll when it has background-
- // attachment:fixed, unless the background will be separately composited
- // i.e. when a LayoutView paints backgrounds only into scrolling contents.
+ // An object needs to repaint the background on scroll when it has
+ // background-attachment:fixed unless the object is the LayoutView and the
+ // background is not painted on the scrolling contents.
if (layout_object == GetLayoutView() &&
- GetLayoutView()->GetBackgroundPaintLocation() ==
- kBackgroundPaintInScrollingContents &&
- (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
- GetLayoutView()->Compositor()->PreferCompositingToLCDTextEnabled()))
+ !(GetLayoutView()->GetBackgroundPaintLocation() &
+ kBackgroundPaintInScrollingContents))
continue;
layout_object->SetBackgroundNeedsFullPaintInvalidation();
}
@@ -1325,7 +1318,7 @@ bool LocalFrameView::InvalidateViewportConstrainedObjects() {
// if we're not compositing-inputs-clean, then we can't query
// layer->SubtreeIsInvisible() here.
layout_object->SetSubtreeShouldCheckForPaintInvalidation();
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
!layer->NeedsRepaint()) {
// Paint properties of the layer relative to its containing graphics
// layer may change if the paint properties escape the graphics layer's
@@ -1355,154 +1348,8 @@ bool LocalFrameView::InvalidateViewportConstrainedObjects() {
return fast_path_allowed;
}
-void LocalFrameView::ProcessUrlFragment(const KURL& url,
- UrlFragmentBehavior behavior) {
- // If our URL has no ref, then we have no place we need to jump to.
- // OTOH If CSS target was set previously, we want to set it to 0, recalc
- // and possibly paint invalidation because :target pseudo class may have been
- // set (see bug 11321).
- // Similarly for svg, if we had a previous svgView() then we need to reset
- // the initial view if we don't have a fragment.
- if (!url.HasFragmentIdentifier() && !frame_->GetDocument()->CssTarget() &&
- !frame_->GetDocument()->IsSVGDocument())
- return;
-
- UseCounter::Count(&GetFrame(), WebFeature::kScrollToFragmentRequested);
- // Try the raw fragment for HTML documents, but skip it for `svgView()`:
- String fragment_identifier = url.FragmentIdentifier();
- if (!frame_->GetDocument()->IsSVGDocument() &&
- ProcessUrlFragmentHelper(fragment_identifier, behavior)) {
- UseCounter::Count(&GetFrame(), WebFeature::kScrollToFragmentSucceedWithRaw);
- return;
- }
-
- // Try again after decoding the fragment.
- if (frame_->GetDocument()->Encoding().IsValid()) {
- DecodeURLResult decode_result;
- if (ProcessUrlFragmentHelper(
- DecodeURLEscapeSequences(fragment_identifier, &decode_result),
- behavior)) {
- switch (decode_result) {
- case DecodeURLResult::kAsciiOnly:
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentSucceedWithASCII);
- break;
- case DecodeURLResult::kUTF8:
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentSucceedWithUTF8);
- break;
- case DecodeURLResult::kIsomorphic:
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentSucceedWithIsomorphic);
- break;
- }
- } else {
- switch (decode_result) {
- case DecodeURLResult::kAsciiOnly:
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentFailWithASCII);
- break;
- case DecodeURLResult::kUTF8:
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentFailWithUTF8);
- break;
- case DecodeURLResult::kIsomorphic:
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentFailWithIsomorphic);
- break;
- }
- }
- } else {
- UseCounter::Count(&GetFrame(),
- WebFeature::kScrollToFragmentFailWithInvalidEncoding);
- }
-}
-
-bool LocalFrameView::ProcessUrlFragmentHelper(const String& name,
- UrlFragmentBehavior behavior) {
- DCHECK(frame_->GetDocument());
-
- Element* anchor_node;
- String selector;
- if (RuntimeEnabledFeatures::CSSFragmentIdentifiersEnabled() &&
- ParseCSSFragmentIdentifier(name, &selector)) {
- anchor_node =
- FindCSSFragmentAnchor(AtomicString(selector), frame_->GetDocument());
- } else {
- anchor_node = frame_->GetDocument()->FindAnchor(name);
- }
-
- // Setting to null will clear the current target.
- frame_->GetDocument()->SetCSSTarget(anchor_node);
-
- if (frame_->GetDocument()->IsSVGDocument()) {
- if (SVGSVGElement* svg =
- ToSVGSVGElementOrNull(frame_->GetDocument()->documentElement())) {
- svg->SetupInitialView(name, anchor_node);
- if (!anchor_node)
- return false;
- }
- // If this is not the top-level frame, then don't scroll to the
- // anchor position.
- if (!frame_->IsMainFrame())
- return false;
- }
-
- // Implement the rule that "" and "top" both mean top of page as in other
- // browsers.
- if (!anchor_node &&
- !(name.IsEmpty() || DeprecatedEqualIgnoringCase(name, "top")))
- return false;
-
- if (anchor_node)
- anchor_node->DispatchActivateInvisibleEventIfNeeded();
-
- if (behavior == kUrlFragmentDontScroll)
- return true;
-
- if (!anchor_node) {
- fragment_anchor_ = frame_->GetDocument();
- needs_focus_on_fragment_ = false;
- } else {
- fragment_anchor_ = anchor_node;
- needs_focus_on_fragment_ = true;
- }
-
- // If rendering is blocked, we'll necessarily have a layout to kick off the
- // scroll and focus.
- if (frame_->GetDocument()->IsRenderingReady()) {
- frame_->GetDocument()->UpdateStyleAndLayoutTree();
-
- // If layout is needed, we will scroll in performPostLayoutTasks. Otherwise,
- // scroll and focus immediately.
- if (NeedsLayout())
- UpdateLayout();
- else
- ScrollAndFocusFragmentAnchor();
- }
-
- return true;
-}
-
-Element* LocalFrameView::FindCSSFragmentAnchor(const AtomicString& selector,
- Document* document) {
- DummyExceptionStateForTesting exception_state;
- return document->QuerySelector(selector, exception_state);
-}
-
-bool LocalFrameView::ParseCSSFragmentIdentifier(const String& fragment,
- String* selector) {
- size_t pos = fragment.Find(kCssFragmentIdentifierPrefix);
- if (pos == 0) {
- *selector = fragment.Substring(kCssFragmentIdentifierPrefixLength - 1);
- return true;
- }
-
- return false;
-}
-
-void LocalFrameView::ClearFragmentAnchor() {
- fragment_anchor_ = nullptr;
+void LocalFrameView::ProcessUrlFragment(const KURL& url, bool should_scroll) {
+ fragment_anchor_ = FragmentAnchor::TryCreate(url, should_scroll, *frame_);
}
void LocalFrameView::SetLayoutSize(const IntSize& size) {
@@ -1588,10 +1435,8 @@ void LocalFrameView::HandleLoadCompleted() {
if (auto_size_info_)
auto_size_info_->AutoSizeIfNeeded();
- // If there is a pending layout, the fragment anchor will be cleared when it
- // finishes.
- if (!NeedsLayout())
- ClearFragmentAnchor();
+ if (fragment_anchor_)
+ fragment_anchor_->DidCompleteLoad();
}
void LocalFrameView::ClearLayoutSubtreeRoot(const LayoutObject& root) {
@@ -1820,73 +1665,13 @@ void LocalFrameView::UpdateBaseBackgroundColorRecursively(
});
}
-void LocalFrameView::ScrollAndFocusFragmentAnchor() {
- Node* anchor_node = fragment_anchor_;
- if (!anchor_node)
- return;
-
- if (!frame_->GetDocument()->IsRenderingReady())
+void LocalFrameView::InvokeFragmentAnchor() {
+ FragmentAnchor* fragment_anchor = fragment_anchor_;
+ if (!fragment_anchor)
return;
- if (anchor_node->GetLayoutObject()) {
- LayoutRect rect;
- if (anchor_node != frame_->GetDocument()) {
- rect = anchor_node->BoundingBoxForScrollIntoView();
- } else {
- if (Element* document_element = frame_->GetDocument()->documentElement())
- rect = document_element->BoundingBoxForScrollIntoView();
- }
-
- Frame* boundary_frame = frame_->FindUnsafeParentScrollPropagationBoundary();
-
- // FIXME: Handle RemoteFrames
- if (boundary_frame && boundary_frame->IsLocalFrame()) {
- ToLocalFrame(boundary_frame)
- ->View()
- ->SetSafeToPropagateScrollToParent(false);
- }
-
- Element* anchor_element = anchor_node->IsElementNode()
- ? ToElement(anchor_node)
- : frame_->GetDocument()->documentElement();
- if (anchor_element) {
- ScrollIntoViewOptions* options = ScrollIntoViewOptions::Create();
- options->setBlock("start");
- options->setInlinePosition("nearest");
- anchor_element->ScrollIntoViewNoVisualUpdate(options);
- }
-
- if (boundary_frame && boundary_frame->IsLocalFrame()) {
- ToLocalFrame(boundary_frame)
- ->View()
- ->SetSafeToPropagateScrollToParent(true);
- }
-
- if (AXObjectCache* cache = frame_->GetDocument()->ExistingAXObjectCache())
- cache->HandleScrolledToAnchor(anchor_node);
-
- // If the anchor accepts keyboard focus and fragment scrolling is allowed,
- // move focus there to aid users relying on keyboard navigation.
- // If anchorNode is not focusable or fragment scrolling is not allowed,
- // clear focus, which matches the behavior of other browsers.
- if (needs_focus_on_fragment_) {
- if (anchor_node->IsElementNode() &&
- ToElement(anchor_node)->IsFocusable()) {
- ToElement(anchor_node)->focus();
- } else {
- frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint(
- anchor_node);
- frame_->GetDocument()->ClearFocusedElement();
- }
- needs_focus_on_fragment_ = false;
- }
- }
-
- // The fragment anchor should only be maintained while the frame is still
- // loading. If the frame is done loading, clear the anchor now. Otherwise,
- // restore it since it may have been cleared during scrollRectToVisible.
- fragment_anchor_ =
- frame_->GetDocument()->IsLoadCompleted() ? nullptr : anchor_node;
+ if (!fragment_anchor_->Invoke())
+ fragment_anchor_ = nullptr;
}
bool LocalFrameView::UpdatePlugins() {
@@ -2024,14 +1809,10 @@ void LocalFrameView::SendResizeEventIfNeeded() {
probe::didResizeMainFrame(frame_.Get());
}
-void LocalFrameView::SetInputEventsScaleForEmulation(
- float content_scale_factor) {
- input_events_scale_factor_for_emulation_ = content_scale_factor;
-}
-
float LocalFrameView::InputEventsScaleFactor() const {
float page_scale = frame_->GetPage()->GetVisualViewport().Scale();
- return page_scale * input_events_scale_factor_for_emulation_;
+ return page_scale *
+ frame_->GetPage()->GetChromeClient().InputEventsScaleForEmulation();
}
void LocalFrameView::NotifyPageThatContentAreaWillPaint() const {
@@ -2113,6 +1894,12 @@ Color LocalFrameView::DocumentBackgroundColor() const {
void LocalFrameView::WillBeRemovedFromFrame() {
if (paint_artifact_compositor_)
paint_artifact_compositor_->WillBeRemovedFromFrame();
+
+ if (Settings* settings = frame_->GetSettings()) {
+ DCHECK(frame_->GetPage());
+ if (settings->GetSpatialNavigationEnabled())
+ frame_->GetPage()->GetSpatialNavigationController().DidDetachFrameView();
+ }
}
LocalFrameView* LocalFrameView::ParentFrameView() const {
@@ -2158,20 +1945,15 @@ void LocalFrameView::UpdateAllLifecyclePhases(
// TODO(schenney): add a scrolling update lifecycle phase.
// TODO(schenney): Pass a LifecycleUpdateReason in here
bool LocalFrameView::UpdateLifecycleToCompositingCleanPlusScrolling() {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return UpdateAllLifecyclePhasesExceptPaint();
- } else {
- return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
- DocumentLifecycle::kCompositingClean,
- DocumentLifecycle::LifecycleUpdateReason::kOther);
- }
+ return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
+ DocumentLifecycle::kCompositingClean,
+ DocumentLifecycle::LifecycleUpdateReason::kOther);
}
// TODO(schenney): Pass a LifecycleUpdateReason in here
bool LocalFrameView::UpdateLifecycleToCompositingInputsClean() {
- // When SPv2 is enabled, the standard compositing lifecycle steps do not
- // exist; compositing is done after paint instead.
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
DocumentLifecycle::kCompositingInputsClean,
DocumentLifecycle::LifecycleUpdateReason::kOther);
@@ -2366,6 +2148,9 @@ bool LocalFrameView::UpdateLifecyclePhases(
if (reason == DocumentLifecycle::LifecycleUpdateReason::kBeginMainFrame)
EnsureUkmAggregator().BeginMainFrame();
+ for (auto& observer : lifecycle_observers_)
+ observer->WillStartLifecycleUpdate();
+
// If we're in PrintBrowser mode, setup a print context.
// TODO(vmpstr): It doesn't seem like we need to do this every lifecycle
// update, but rather once somewhere at creation time.
@@ -2388,6 +2173,9 @@ bool LocalFrameView::UpdateLifecyclePhases(
UpdateThrottlingStatusForSubtree();
+ for (auto& observer : lifecycle_observers_)
+ observer->DidFinishLifecycleUpdate();
+
return Lifecycle().GetState() == target_state;
}
@@ -2417,8 +2205,8 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
if (!run_more_lifecycle_phases)
return;
- // TODO(pdr): PrePaint should be under the "Paint" devtools timeline
- // step for slimming paint v2.
+ // TODO(pdr): PrePaint should be under the "Paint" devtools timeline step
+ // when CompositeAfterPaint is enabled.
run_more_lifecycle_phases = RunPrePaintLifecyclePhase(target_state);
DCHECK(ShouldThrottleRendering() ||
Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
@@ -2483,7 +2271,6 @@ bool LocalFrameView::RunStyleAndLayoutLifecyclePhases(
});
frame_->GetPage()->GetValidationMessageClient().LayoutOverlay();
- frame_->GetPage()->UpdatePageColorOverlay();
if (target_state == DocumentLifecycle::kPaintClean) {
ForAllNonThrottledLocalFrameViews(
@@ -2506,15 +2293,21 @@ bool LocalFrameView::RunCompositingLifecyclePhase(
auto* layout_view = GetLayoutView();
DCHECK(layout_view);
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
LocalFrameUkmAggregator::kCompositing);
layout_view->Compositor()->UpdateIfNeededRecursive(target_state);
} else {
+#if DCHECK_IS_ON()
+ SetIsUpdatingDescendantDependentFlags(true);
+#endif
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.GetLayoutView()->Layer()->UpdateDescendantDependentFlags();
frame_view.GetLayoutView()->CommitPendingSelection();
});
+#if DCHECK_IS_ON()
+ SetIsUpdatingDescendantDependentFlags(false);
+#endif
}
// We may be in kCompositingInputsClean clean, which does not need to notify
@@ -2524,14 +2317,7 @@ bool LocalFrameView::RunCompositingLifecyclePhase(
*this);
}
- // We need to run more phases only if the target is beyond kCompositingClean.
- if (target_state > DocumentLifecycle::kCompositingClean) {
- // TODO(vmpstr): Why is composited selection only updated if we're moving
- // past kCompositingClean?
- UpdateCompositedSelectionIfNeeded();
- return true;
- }
- return false;
+ return target_state > DocumentLifecycle::kCompositingClean;
}
bool LocalFrameView::RunPrePaintLifecyclePhase(
@@ -2546,9 +2332,23 @@ bool LocalFrameView::RunPrePaintLifecyclePhase(
// we need to propagate the flags into the ancestor chain so that
// PrePaintTreeWalk can reach this frame.
frame_view.SetNeedsPaintPropertyUpdate();
+ // We may record more foreign layers under the frame.
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ frame_view.SetPaintArtifactCompositorNeedsUpdate();
if (auto* owner = frame_view.GetFrame().OwnerLayoutObject())
owner->SetShouldCheckForPaintInvalidation();
}
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // For pre-CompositeAfterPaint this is done during compositing update.
+ // This is before PrePaintTreeWalk because it will update main thread
+ // scrolling reasons.
+ frame_view.GetScrollableArea()->UpdateCompositorScrollAnimations();
+ if (const auto* animating_scrollable_areas =
+ frame_view.AnimatingScrollableAreas()) {
+ for (auto scrollable_area : *animating_scrollable_areas)
+ scrollable_area->UpdateCompositorScrollAnimations();
+ }
+ }
});
{
@@ -2558,6 +2358,8 @@ bool LocalFrameView::RunPrePaintLifecyclePhase(
PrePaintTreeWalk().WalkTree(*this);
}
+ UpdateCompositedSelectionIfNeeded();
+
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPrePaintClean);
});
@@ -2577,7 +2379,7 @@ void LocalFrameView::RunPaintLifecyclePhase() {
TRACE_EVENT0("blink,benchmark", "LocalFrameView::RunPaintLifecyclePhase");
// While printing a document, the paint walk is done by the printing
// component into a special canvas. There is no point doing a normal paint
- // step (or animations update for BlinkGenPropertyTrees/SPv2) when in this
+ // step (or animations update for BlinkGenPropertyTrees/CAP) when in this
// mode.
//
// RuntimeEnabledFeatures::PrintBrowserEnabled is a mode which runs the
@@ -2588,19 +2390,17 @@ void LocalFrameView::RunPaintLifecyclePhase() {
if (!print_mode_enabled)
PaintTree();
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (GetLayoutView()->Compositor()->InCompositingMode()) {
GetScrollingCoordinator()->UpdateAfterPaint(this);
}
}
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
if (!print_mode_enabled) {
- base::Optional<CompositorElementIdSet> composited_element_ids =
- CompositorElementIdSet();
+ auto& composited_element_ids = composited_element_ids_;
PushPaintArtifactToCompositor(composited_element_ids.value());
- // TODO(pdr): Add call to UpdateCompositorScrollAnimations here.
ForAllNonThrottledLocalFrameViews(
[&composited_element_ids](LocalFrameView& frame_view) {
DocumentAnimations::UpdateAnimations(
@@ -2614,7 +2414,7 @@ void LocalFrameView::RunPaintLifecyclePhase() {
// PaintController for BlinkGenPropertyTrees is transient.
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// Property tree changed state is typically cleared through
// |PaintController::FinishCycle| but that will be a no-op because
// the paint controller is transient, so force the changed state to be
@@ -2624,7 +2424,7 @@ void LocalFrameView::RunPaintLifecyclePhase() {
auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
if (root) {
ForAllGraphicsLayers(*root, [](GraphicsLayer& layer) {
- if (layer.DrawsContent() && layer.HasLayerState()) {
+ if (layer.PaintsContentOrHitTest() && layer.HasLayerState()) {
layer.GetPaintController().ClearPropertyTreeChangedStateTo(
layer.GetPropertyTreeState());
}
@@ -2661,49 +2461,25 @@ void LocalFrameView::PerformScrollAnchoringAdjustments() {
}
}
+static void RecordGraphicsLayerAsForeignLayer(
+ GraphicsContext& context,
+ const GraphicsLayer* graphics_layer) {
+ // TODO(trchen): Currently the GraphicsLayer hierarchy is still built during
+ // CompositingUpdate, and we have to clear them here to ensure no extraneous
+ // layers are still attached. In future we will disable all those layer
+ // hierarchy code so we won't need this line.
+ graphics_layer->CcLayer()->RemoveAllChildren();
+ RecordForeignLayer(context, DisplayItem::kForeignLayerWrapper,
+ graphics_layer->CcLayer(),
+ graphics_layer->GetPropertyTreeState());
+}
+
static void CollectViewportLayersForLayerList(GraphicsContext& context,
VisualViewport& visual_viewport) {
DCHECK(RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
-
- // Collect the visual viewport container layer.
- {
- GraphicsLayer* container_layer = visual_viewport.ContainerLayer();
- ScopedPaintChunkProperties container_scope(
- context.GetPaintController(), container_layer->GetPropertyTreeState(),
- *container_layer, DisplayItem::kForeignLayerWrapper);
-
- // TODO(trchen): Currently the GraphicsLayer hierarchy is still built during
- // CompositingUpdate, and we have to clear them here to ensure no extraneous
- // layers are still attached. In future we will disable all those layer
- // hierarchy code so we won't need this line.
- container_layer->CcLayer()->RemoveAllChildren();
- RecordForeignLayer(context, DisplayItem::kForeignLayerWrapper,
- container_layer->CcLayer());
- }
-
- // Collect the page scale layer.
- {
- GraphicsLayer* scale_layer = visual_viewport.PageScaleLayer();
- ScopedPaintChunkProperties scale_scope(
- context.GetPaintController(), scale_layer->GetPropertyTreeState(),
- *scale_layer, DisplayItem::kForeignLayerWrapper);
-
- scale_layer->CcLayer()->RemoveAllChildren();
- RecordForeignLayer(context, DisplayItem::kForeignLayerWrapper,
- scale_layer->CcLayer());
- }
-
- // Collect the visual viewport scroll layer.
- {
- GraphicsLayer* scroll_layer = visual_viewport.ScrollLayer();
- ScopedPaintChunkProperties scroll_scope(
- context.GetPaintController(), scroll_layer->GetPropertyTreeState(),
- *scroll_layer, DisplayItem::kForeignLayerWrapper);
-
- scroll_layer->CcLayer()->RemoveAllChildren();
- RecordForeignLayer(context, DisplayItem::kForeignLayerWrapper,
- scroll_layer->CcLayer());
- }
+ RecordGraphicsLayerAsForeignLayer(context, visual_viewport.ContainerLayer());
+ RecordGraphicsLayerAsForeignLayer(context, visual_viewport.PageScaleLayer());
+ RecordGraphicsLayerAsForeignLayer(context, visual_viewport.ScrollLayer());
}
static void CollectDrawableLayersForLayerListRecursively(
@@ -2718,25 +2494,14 @@ static void CollectDrawableLayersForLayerListRecursively(
// that don't for the purposes of hit testing. For example, an empty div
// will not draw content but needs to create a layer to ensure scroll events
// do not pass through it.
- if (layer->DrawsContent() || layer->GetHitTestableWithoutDrawsContent()) {
- ScopedPaintChunkProperties scope(context.GetPaintController(),
- layer->GetPropertyTreeState(), *layer,
- DisplayItem::kForeignLayerWrapper);
- // TODO(trchen): Currently the GraphicsLayer hierarchy is still built
- // during CompositingUpdate, and we have to clear them here to ensure no
- // extraneous layers are still attached. In future we will disable all
- // those layer hierarchy code so we won't need this line.
- layer->CcLayer()->RemoveAllChildren();
- RecordForeignLayer(context, DisplayItem::kForeignLayerWrapper,
- layer->CcLayer());
+ if (layer->PaintsContentOrHitTest() ||
+ layer->GetHitTestableWithoutDrawsContent()) {
+ RecordGraphicsLayerAsForeignLayer(context, layer);
}
if (auto* contents_layer = layer->ContentsLayer()) {
- ScopedPaintChunkProperties scope(
- context.GetPaintController(), layer->GetContentsPropertyTreeState(),
- *layer, DisplayItem::kForeignLayerContentsWrapper);
RecordForeignLayer(context, DisplayItem::kForeignLayerContentsWrapper,
- contents_layer);
+ contents_layer, layer->GetContentsPropertyTreeState());
}
DCHECK(!layer->ContentsClippingMaskLayer());
@@ -2759,11 +2524,8 @@ static void CollectLinkHighlightLayersForLayerListRecursively(
auto* highlight_layer = highlight->Layer();
auto property_tree_state = layer->GetPropertyTreeState();
property_tree_state.SetEffect(highlight->effect());
- ScopedPaintChunkProperties scope(context.GetPaintController(),
- property_tree_state, *highlight,
- DisplayItem::kForeignLayerLinkHighlight);
RecordForeignLayer(context, DisplayItem::kForeignLayerLinkHighlight,
- highlight_layer);
+ highlight_layer, property_tree_state);
}
for (const auto* child : layer->Children())
@@ -2791,11 +2553,16 @@ void LocalFrameView::PaintTree() {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (!paint_controller_)
paint_controller_ = PaintController::Create();
- if (GetLayoutView()->Layer()->NeedsRepaint()) {
+ // TODO(crbug.com/917911): Painting of overlays should not force repainting
+ // of the frame contents.
+ auto* web_local_frame_impl = WebLocalFrameImpl::FromFrame(frame_);
+ bool has_dev_tools_overlays =
+ web_local_frame_impl && web_local_frame_impl->HasDevToolsOverlays();
+ if (GetLayoutView()->Layer()->NeedsRepaint() || has_dev_tools_overlays) {
GraphicsContext graphics_context(*paint_controller_);
if (RuntimeEnabledFeatures::PrintBrowserEnabled())
graphics_context.SetPrinting(true);
@@ -2812,6 +2579,24 @@ void LocalFrameView::PaintTree() {
PaintInternal(graphics_context, kGlobalPaintNormalPhase,
CullRect::Infinite());
+
+ frame_->GetPage()->GetLinkHighlights().Paint(graphics_context);
+
+ frame_->GetPage()->GetValidationMessageClient().PaintOverlay(
+ graphics_context);
+ frame_->PaintFrameColorOverlay(graphics_context);
+ ForAllNonThrottledLocalFrameViews(
+ [&graphics_context](LocalFrameView& view) {
+ view.frame_->PaintFrameColorOverlay(graphics_context);
+ });
+
+ // Devtools overlays query the inspected page's paint data so this update
+ // needs to be after other paintings.
+ if (has_dev_tools_overlays) {
+ web_local_frame_impl->UpdateDevToolsOverlays();
+ web_local_frame_impl->PaintDevToolsOverlays(graphics_context);
+ }
+
paint_controller_->CommitNewDisplayItems();
}
} else {
@@ -2840,17 +2625,24 @@ void LocalFrameView::PaintTree() {
PaintGraphicsLayerRecursively(layer_for_scroll_corner);
}
}
- }
- // TODO(chrishtr): Link highlights don't currently paint themselves,
- // it's still driven by cc. Fix this.
- // This uses an invalidation approach based on graphics layer raster
- // invalidation so it must be after paint. This adds/removes link highlight
- // layers so it must be before |CollectDrawableLayersForLayerListRecursively|.
- frame_->GetPage()->GetLinkHighlights().UpdateGeometry();
+ // This uses an invalidation approach based on graphics layer raster
+ // invalidation so it must be after paint. This adds/removes link highlight
+ // layers so it must be before
+ // |CollectDrawableLayersForLayerListRecursively|.
+ frame_->GetPage()->GetLinkHighlights().UpdateGeometry();
- frame_->GetPage()->GetValidationMessageClient().PaintOverlay();
- frame_->GetPage()->PaintPageColorOverlay();
+ frame_->GetPage()->GetValidationMessageClient().PaintOverlay();
+ frame_->PaintFrameColorOverlay();
+ ForAllNonThrottledLocalFrameViews(
+ [](LocalFrameView& view) { view.frame_->PaintFrameColorOverlay(); });
+
+ // Devtools overlays query the inspected page's paint data so this update
+ // needs to be after other paintings. Because devtools overlays can add
+ // layers, this needs to be before layers are collected.
+ if (auto* web_local_frame_impl = WebLocalFrameImpl::FromFrame(frame_))
+ web_local_frame_impl->UpdateDevToolsOverlays();
+ }
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
@@ -2858,14 +2650,8 @@ void LocalFrameView::PaintTree() {
layout_view->Layer()->ClearNeedsRepaintRecursively();
});
- // Devtools overlays query the inspected page's paint data so this update
- // needs to be after the lifecycle advance to kPaintClean. Because devtools
- // overlays can add layers, this needs to be before layers are collected.
- if (auto* web_local_frame_impl = WebLocalFrameImpl::FromFrame(frame_))
- web_local_frame_impl->UpdateDevToolsOverlays();
-
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// BlinkGenPropertyTrees just needs a transient PaintController to
// collect the foreign layers which doesn't need caching. It also
// shouldn't affect caching status of DisplayItemClients because it's
@@ -2896,11 +2682,25 @@ void LocalFrameView::PaintTree() {
}
}
+const cc::Layer* LocalFrameView::RootCcLayer() const {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ return paint_artifact_compositor_ ? paint_artifact_compositor_->RootLayer()
+ : nullptr;
+ }
+
+ if (const auto* root_graphics_layer =
+ frame_->GetPage()->GetVisualViewport().RootGraphicsLayer()) {
+ return root_graphics_layer->CcLayer();
+ }
+ return nullptr;
+}
+
void LocalFrameView::PushPaintArtifactToCompositor(
CompositorElementIdSet& composited_element_ids) {
TRACE_EVENT0("blink", "LocalFrameView::pushPaintArtifactToCompositor");
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
if (!frame_->GetSettings()->GetAcceleratedCompositingEnabled())
@@ -2917,6 +2717,8 @@ void LocalFrameView::PushPaintArtifactToCompositor(
// The layer being scrolled is destroyed before the
// ScrollingCoordinator.
WrapWeakPersistent(page->GetScrollingCoordinator())));
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ GetLayoutView()->Compositor()->AttachRootLayerViaChromeClient();
page->GetChromeClient().AttachRootLayer(
paint_artifact_compositor_->RootLayer(), &GetFrame());
}
@@ -2924,9 +2726,19 @@ void LocalFrameView::PushPaintArtifactToCompositor(
SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
LocalFrameUkmAggregator::kCompositingCommit);
+ PaintArtifactCompositor::ViewportProperties viewport_properties;
+ const auto& viewport = page->GetVisualViewport();
+ viewport_properties.page_scale = viewport.GetPageScaleNode();
+ viewport_properties.inner_scroll_translation =
+ viewport.GetScrollTranslationNode();
+
+ PaintArtifactCompositor::Settings settings;
+ settings.prefer_compositing_to_lcd_text =
+ page->GetSettings().GetPreferCompositingToLCDTextEnabled();
+
paint_artifact_compositor_->Update(
paint_controller_->GetPaintArtifactShared(), composited_element_ids,
- page->GetVisualViewport().GetPageScaleNode());
+ viewport_properties, settings);
}
std::unique_ptr<JSONObject> LocalFrameView::CompositedLayersAsJSON(
@@ -3393,7 +3205,7 @@ void LocalFrameView::SetTracksPaintInvalidations(
base::WrapUnique(track_paint_invalidations
? new Vector<ObjectPaintInvalidation>
: nullptr);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (paint_artifact_compositor_) {
paint_artifact_compositor_->SetTracksRasterInvalidations(
track_paint_invalidations);
@@ -3459,7 +3271,7 @@ void LocalFrameView::ScrollableAreasDidChange() {
// to be notified post-layout to recompute gesture regions.
// TODO(wjmaclean): It would be nice to move the !NeedsLayout() check from
// here to SetScrollGestureRegionIsDirty(), but at present doing so breaks
- // layout tests. This suggests that there is something that wants to set the
+ // web tests. This suggests that there is something that wants to set the
// dirty bit when layout is needed, and won't re-try setting the bit after
// layout has completed - it would be nice to find that and fix it.
if (!NeedsLayout())
@@ -3625,8 +3437,8 @@ void LocalFrameView::SetLayoutSizeInternal(const IntSize& size) {
void LocalFrameView::ClipPaintRect(FloatRect* paint_rect) const {
// TODO(wangxianzhu): Support ChromeClient::VisibleContentRectForPainting()
- // for SPv2.
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ // with CompositeAfterPaint.
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
// Paint the whole rect if "mainFrameClipsContent" is false, meaning that
// WebPreferences::record_whole_document is true.
@@ -3747,10 +3559,40 @@ void LocalFrameView::Paint(GraphicsContext& context,
PaintInternal(context, global_paint_flags, cull_rect);
}
-void LocalFrameView::PaintWithLifecycleUpdate(
+void LocalFrameView::PaintInternal(GraphicsContext& context,
+ const GlobalPaintFlags global_paint_flags,
+ const CullRect& cull_rect) const {
+ FramePainter(*this).Paint(context, global_paint_flags, cull_rect);
+}
+
+static bool PaintOutsideOfLifecycleIsAllowed(GraphicsContext& context,
+ const LocalFrameView& frame_view) {
+ // A paint outside of lifecycle should not conflict about paint controller
+ // caching with the default painting executed during lifecycle update,
+ // otherwise the caller should either use a transient paint controller or
+ // explicitly skip cache.
+ if (context.GetPaintController().IsSkippingCache())
+ return true;
+ // For CompositeAfterPaint, they always conflict because we always paint into
+ // paint_controller_ during lifecycle update.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return false;
+ // For pre-CompositeAfterPaint, they conflict if the local frame root has a
+ // a root graphics layer.
+ return !frame_view.GetFrame()
+ .LocalFrameRoot()
+ .View()
+ ->GetLayoutView()
+ ->Compositor()
+ ->PaintRootGraphicsLayer();
+}
+
+void LocalFrameView::PaintOutsideOfLifecycle(
GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
const CullRect& cull_rect) {
+ DCHECK(PaintOutsideOfLifecycleIsAllowed(context, *this));
+
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
@@ -3762,26 +3604,32 @@ void LocalFrameView::PaintWithLifecycleUpdate(
});
}
-void LocalFrameView::PaintInternal(GraphicsContext& context,
- const GlobalPaintFlags global_paint_flags,
- const CullRect& cull_rect) const {
- FramePainter(*this).Paint(context, global_paint_flags, cull_rect);
-}
+void LocalFrameView::PaintContentsOutsideOfLifecycle(
+ GraphicsContext& context,
+ const GlobalPaintFlags global_paint_flags,
+ const CullRect& cull_rect) {
+ DCHECK(PaintOutsideOfLifecycleIsAllowed(context, *this));
-void LocalFrameView::PaintContents(GraphicsContext& context,
- const GlobalPaintFlags global_paint_flags,
- const IntRect& damage_rect) {
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
- FramePainter(*this).PaintContents(context, global_paint_flags, damage_rect);
+ FramePainter(*this).PaintContents(context, global_paint_flags, cull_rect);
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
});
}
+sk_sp<PaintRecord> LocalFrameView::GetPaintRecord() const {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ DCHECK_EQ(DocumentLifecycle::kPaintClean, Lifecycle().GetState());
+ DCHECK(frame_->IsLocalRoot());
+ DCHECK(paint_controller_);
+ return paint_controller_->GetPaintArtifact().GetPaintRecord(
+ PropertyTreeState::Root());
+}
+
IntRect LocalFrameView::ConvertToRootFrame(const IntRect& local_rect) const {
if (LocalFrameView* parent = ParentFrameView()) {
IntRect parent_rect = ConvertToContainingEmbeddedContentView(local_rect);
@@ -3977,6 +3825,12 @@ void LocalFrameView::UpdateViewportIntersectionsForSubtree() {
child->View()->UpdateViewportIntersectionsForSubtree();
}
+ for (HTMLPortalElement* portal :
+ DocumentPortals::From(*frame_->GetDocument()).GetPortals()) {
+ if (portal->ContentFrame())
+ portal->ContentFrame()->View()->UpdateViewportIntersectionsForSubtree();
+ }
+
intersection_observation_state_ = kNotNeeded;
}
@@ -4069,6 +3923,9 @@ void LocalFrameView::UpdateRenderThrottlingStatus(
layout_view->AddSubtreePaintPropertyUpdateReason(
SubtreePaintPropertyUpdateReason::kPreviouslySkipped);
}
+ // We may record more foreign layers under the frame.
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ SetPaintArtifactCompositorNeedsUpdate();
}
EventHandlerRegistry& registry = frame_->GetEventHandlerRegistry();
@@ -4113,6 +3970,12 @@ void LocalFrameView::SetIntersectionObservationState(
intersection_observation_state_ = state;
}
+void LocalFrameView::SetPaintArtifactCompositorNeedsUpdate() const {
+ LocalFrameView* root = GetFrame().LocalFrameRoot().View();
+ if (root && root->paint_artifact_compositor_)
+ root->paint_artifact_compositor_->SetNeedsUpdate(true);
+}
+
unsigned LocalFrameView::GetIntersectionObservationFlags() const {
unsigned flags = 0;
@@ -4334,24 +4197,21 @@ MainThreadScrollingReasons LocalFrameView::GetMainThreadScrollingReasons()
}
String LocalFrameView::MainThreadScrollingReasonsAsText() {
- MainThreadScrollingReasons reasons = main_thread_scrolling_reasons_;
- // TODO(pdr): We should also use the property tree main thread scrolling
- // reasons when RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled is true.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ MainThreadScrollingReasons reasons = 0;
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
-
- // Slimming paint v2 stores main thread scrolling reasons on property
- // trees instead of in |main_thread_scrolling_reasons_|.
if (const auto* scroll =
GetLayoutView()->FirstFragment().PaintProperties()->Scroll()) {
reasons = scroll->GetMainThreadScrollingReasons();
}
} else {
DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kCompositingClean);
+ reasons = main_thread_scrolling_reasons_;
if (GraphicsLayer* layer_for_scrolling =
LayoutViewport()->LayerForScrolling()) {
if (cc::Layer* cc_layer = layer_for_scrolling->CcLayer())
- reasons = cc_layer->main_thread_scrolling_reasons();
+ reasons = cc_layer->GetMainThreadScrollingReasons();
}
}
@@ -4397,4 +4257,14 @@ LocalFrameUkmAggregator& LocalFrameView::EnsureUkmAggregator() {
return *ukm_aggregator_;
}
+void LocalFrameView::RegisterForLifecycleNotifications(
+ LifecycleNotificationObserver* observer) {
+ lifecycle_observers_.insert(observer);
+}
+
+void LocalFrameView::UnregisterFromLifecycleNotifications(
+ LifecycleNotificationObserver* observer) {
+ lifecycle_observers_.erase(observer);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view.h b/chromium/third_party/blink/renderer/core/frame/local_frame_view.h
index 7c8923a7894..fb5bd13d66a 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -41,9 +41,16 @@
#include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
+#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
#include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h"
#include "third_party/blink/renderer/platform/graphics/subtree_paint_property_update_reason.h"
#include "third_party/blink/renderer/platform/timer.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace cc {
+class Layer;
+}
namespace blink {
@@ -53,12 +60,11 @@ class CompositorAnimationHost;
class CompositorAnimationTimeline;
class Cursor;
class DisplayItemClient;
-class Document;
class DocumentLifecycle;
-class Element;
class ElementVisibilityObserver;
class FloatRect;
class FloatSize;
+class FragmentAnchor;
class Frame;
class FrameViewAutoSizeInfo;
class JSONObject;
@@ -66,14 +72,12 @@ class JankTracker;
class KURL;
class LayoutAnalyzer;
class LayoutBox;
-class LayoutEmbeddedContent;
class LayoutEmbeddedObject;
class LayoutObject;
class LayoutRect;
class LayoutSVGRoot;
class LayoutView;
class LocalFrame;
-class Node;
class Page;
class PaintArtifactCompositor;
class PaintController;
@@ -104,9 +108,16 @@ class CORE_EXPORT LocalFrameView final
friend class PaintControllerPaintTestBase;
friend class Internals;
- friend class LayoutEmbeddedContent; // for invalidateTreeIfNeeded
public:
+ class CORE_EXPORT LifecycleNotificationObserver
+ : public GarbageCollectedMixin {
+ public:
+ // These are called when the lifecycle updates start/finish.
+ virtual void WillStartLifecycleUpdate() = 0;
+ virtual void DidFinishLifecycleUpdate() = 0;
+ };
+
static LocalFrameView* Create(LocalFrame&);
static LocalFrameView* Create(LocalFrame&, const IntSize& initial_size);
@@ -207,6 +218,8 @@ class CORE_EXPORT LocalFrameView final
// view.
unsigned GetIntersectionObservationFlags() const;
+ void SetPaintArtifactCompositorNeedsUpdate() const;
+
// Marks this frame, and ancestor frames, as needing a mandatory compositing
// update. This overrides throttling for one frame, up to kCompositingClean.
void SetNeedsForcedCompositingUpdate();
@@ -251,9 +264,6 @@ class CORE_EXPORT LocalFrameView final
// Scale used to convert incoming input events.
float InputEventsScaleFactor() const;
- // Scale used to convert incoming input events while emulating device metics.
- void SetInputEventsScaleForEmulation(float);
-
void DidChangeScrollOffset();
void ViewportSizeChanged(bool width_changed, bool height_changed);
@@ -378,15 +388,15 @@ class CORE_EXPORT LocalFrameView final
const FloatSize& original_page_size,
float maximum_shrink_factor);
- enum UrlFragmentBehavior { kUrlFragmentScroll, kUrlFragmentDontScroll };
// Updates the fragment anchor element based on URL's fragment identifier.
// Updates corresponding ':target' CSS pseudo class on the anchor element.
- // If |UrlFragmentScroll| is passed it sets the anchor element so that it
- // will be focused and scrolled into view during layout. The scroll offset is
- // maintained during the frame loading process.
- void ProcessUrlFragment(const KURL&,
- UrlFragmentBehavior = kUrlFragmentScroll);
- void ClearFragmentAnchor();
+ // If |Behavior| is passed it can be used to prevent scrolling/focusing while
+ // still performing all related side-effects like setting :target (used for
+ // e.g. in history restoration to override the scroll offset). The scroll
+ // offset is maintained during the frame loading process.
+ void ProcessUrlFragment(const KURL&, bool should_scroll = true);
+ FragmentAnchor* GetFragmentAnchor() { return fragment_anchor_; }
+ void InvokeFragmentAnchor();
// Methods to convert points and rects between the coordinate space of the
// layoutObject, and this view.
@@ -532,19 +542,24 @@ class CORE_EXPORT LocalFrameView final
LayoutPoint FrameToDocument(const LayoutPoint&) const;
LayoutRect FrameToDocument(const LayoutRect&) const;
- // Handles painting of the contents of the view as well as the scrollbars.
- void Paint(GraphicsContext&,
- const GlobalPaintFlags,
- const CullRect&,
- const IntSize& paint_offset = IntSize()) const override;
- // Paints, and also updates the lifecycle to in-paint and paint clean
- // beforehand. Call this for painting use-cases outside of the lifecycle.
- void PaintWithLifecycleUpdate(GraphicsContext&,
- const GlobalPaintFlags,
- const CullRect&);
- void PaintContents(GraphicsContext&,
- const GlobalPaintFlags,
- const IntRect& damage_rect);
+ // Normally a LocalFrameView synchronously paints during full lifecycle
+ // updates, into the local frame root's PaintController (CompositeAfterPaint)
+ // or the PaintControllers of GraphicsLayers (pre-CompositeAfterPaint)
+ // However, in some cases (e.g. when printing) we need to paint the frame view
+ // into a PaintController other than the default one(s). The following
+ // functions are provided for these cases. This frame view must be in
+ // PrePaintClean or PaintClean state when these functions are called.
+ void PaintOutsideOfLifecycle(
+ GraphicsContext&,
+ const GlobalPaintFlags,
+ const CullRect& cull_rect = CullRect::Infinite());
+ void PaintContentsOutsideOfLifecycle(GraphicsContext&,
+ const GlobalPaintFlags,
+ const CullRect&);
+
+ // Get the PaintRecord based on the cached paint artifact generated during
+ // the last paint in lifecycle update. For CompositeAfterPaint only.
+ sk_sp<PaintRecord> GetPaintRecord() const;
void Show() override;
void Hide() override;
@@ -606,7 +621,7 @@ class CORE_EXPORT LocalFrameView final
void DequeueScrollAnchoringAdjustment(ScrollableArea*);
void PerformScrollAnchoringAdjustments();
- // Only for SPv2.
+ // Only for CompositeAfterPaint.
std::unique_ptr<JSONObject> CompositedLayersAsJSON(LayerTreeFlags);
// Recursively update frame tree. Each frame has its only
@@ -654,11 +669,13 @@ class CORE_EXPORT LocalFrameView final
const WebScrollIntoViewParams&);
PaintArtifactCompositor* GetPaintArtifactCompositorForTesting() {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
return paint_artifact_compositor_.get();
}
+ const cc::Layer* RootCcLayer() const;
+
enum ForceThrottlingInvalidationBehavior {
kDontForceThrottlingInvalidation,
kForceThrottlingInvalidation
@@ -684,7 +701,6 @@ class CORE_EXPORT LocalFrameView final
CompositorAnimationHost* GetCompositorAnimationHost() const;
CompositorAnimationTimeline* GetCompositorAnimationTimeline() const;
- void ScrollAndFocusFragmentAnchor();
JankTracker& GetJankTracker() { return *jank_tracker_; }
PaintTimingDetector& GetPaintTimingDetector() const {
return *paint_timing_detector_;
@@ -693,6 +709,18 @@ class CORE_EXPORT LocalFrameView final
// Return the UKM aggregator for this frame, creating it if necessary.
LocalFrameUkmAggregator& EnsureUkmAggregator();
+#if DCHECK_IS_ON()
+ void SetIsUpdatingDescendantDependentFlags(bool val) {
+ is_updating_descendant_dependent_flags_ = val;
+ }
+ bool IsUpdatingDescendantDependentFlags() const {
+ return is_updating_descendant_dependent_flags_;
+ }
+#endif
+
+ void RegisterForLifecycleNotifications(LifecycleNotificationObserver*);
+ void UnregisterFromLifecycleNotifications(LifecycleNotificationObserver*);
+
protected:
void NotifyFrameRectsChangedIfNeeded();
@@ -725,6 +753,12 @@ class CORE_EXPORT LocalFrameView final
};
#endif
+ // EmbeddedContentView implementation
+ void Paint(GraphicsContext&,
+ const GlobalPaintFlags,
+ const CullRect&,
+ const IntSize& = IntSize()) const final;
+
void PaintInternal(GraphicsContext&,
const GlobalPaintFlags,
const CullRect&) const;
@@ -796,10 +830,6 @@ class CORE_EXPORT LocalFrameView final
void UpdatePluginsTimerFired(TimerBase*);
bool UpdatePlugins();
- bool ProcessUrlFragmentHelper(const String&, UrlFragmentBehavior);
- bool ParseCSSFragmentIdentifier(const String&, String*);
- Element* FindCSSFragmentAnchor(const AtomicString&, Document*);
-
void UpdateCompositedSelectionIfNeeded();
void SetNeedsCompositingUpdate(CompositingUpdateType);
@@ -879,7 +909,7 @@ class CORE_EXPORT LocalFrameView final
bool is_visually_non_empty_;
LayoutObjectCounter layout_object_counter_;
- Member<Node> fragment_anchor_;
+ Member<FragmentAnchor> fragment_anchor_;
Member<ScrollableAreaSet> scrollable_areas_;
Member<ScrollableAreaSet> animating_scrollable_areas_;
@@ -889,8 +919,6 @@ class CORE_EXPORT LocalFrameView final
ObjectSet background_attachment_fixed_objects_;
Member<FrameViewAutoSizeInfo> auto_size_info_;
- float input_events_scale_factor_for_emulation_;
-
IntSize layout_size_;
IntSize initial_viewport_size_;
bool layout_size_fixed_to_frame_size_;
@@ -960,10 +988,17 @@ class CORE_EXPORT LocalFrameView final
std::unique_ptr<Vector<ObjectPaintInvalidation>>
tracked_object_paint_invalidations_;
- // For Slimming Paint v2 only.
+ // For CompositeAfterPaint only.
std::unique_ptr<PaintController> paint_controller_;
std::unique_ptr<PaintArtifactCompositor> paint_artifact_compositor_;
+ // The set of ElementIds that were composited by PaintArtifactCompositor
+ // during the Paint lifecycle phase. Only used by BlinkGenPropertyTrees and
+ // CompositeAfterPaint. These are stored here because sometimes
+ // PaintArtifactCompositor::Update() does not run (if the dirty bit is not
+ // set) and in that case, the element ids from the prior run are retained.
+ base::Optional<CompositorElementIdSet> composited_element_ids_;
+
MainThreadScrollingReasons main_thread_scrolling_reasons_;
std::unique_ptr<LocalFrameUkmAggregator> ukm_aggregator_;
@@ -979,6 +1014,12 @@ class CORE_EXPORT LocalFrameView final
std::unique_ptr<JankTracker> jank_tracker_;
Member<PaintTimingDetector> paint_timing_detector_;
+ HeapHashSet<WeakMember<LifecycleNotificationObserver>> lifecycle_observers_;
+
+#if DCHECK_IS_ON()
+ bool is_updating_descendant_dependent_flags_;
+#endif
+
FRIEND_TEST_ALL_PREFIXES(WebViewTest, DeviceEmulationResetScrollbars);
};
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc
index 058ac945f74..028a3b7a84a 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc
@@ -52,7 +52,7 @@ class LocalFrameViewTest : public RenderingTest {
protected:
LocalFrameViewTest()
: RenderingTest(SingleChildLocalFrameClient::Create()),
- chrome_client_(new AnimationMockChromeClient) {
+ chrome_client_(MakeGarbageCollected<AnimationMockChromeClient>()) {
EXPECT_CALL(GetAnimationMockChromeClient(), AttachRootGraphicsLayer(_, _))
.Times(AnyNumber());
}
@@ -273,7 +273,8 @@ TEST_F(LocalFrameViewSimTest, CSSFragmentIdentifierEmptySelector) {
// See https://crbug.com/851338.
TEST_F(LocalFrameViewSimTest, FragmentNavChangesFocusWhileRenderingBlocked) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_resource("https://example.com/sheet.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/sheet.css",
+ "text/css");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
@@ -281,7 +282,7 @@ TEST_F(LocalFrameViewSimTest, FragmentNavChangesFocusWhileRenderingBlocked) {
<link rel="stylesheet" type="text/css" href="sheet.css">
<a id="anchorlink" href="#bottom">Link to bottom of the page</a>
<div style="height: 1000px;"></div>
- <input id="bottom">Bottom of the page</a>
+ <input id="bottom">Bottom of the page</input>
)HTML");
ScrollableArea* viewport = GetDocument().View()->LayoutViewport();
@@ -319,6 +320,7 @@ TEST_F(LocalFrameViewSimTest, FragmentNavChangesFocusWhileRenderingBlocked) {
// fragment should be activated at that point.
css_resource.Complete("");
RunPendingTasks();
+ Compositor().BeginFrame();
ASSERT_TRUE(GetDocument().IsLoadCompleted());
EXPECT_EQ(GetDocument().getElementById("bottom"),
GetDocument().ActiveElement())
diff --git a/chromium/third_party/blink/renderer/core/frame/location.cc b/chromium/third_party/blink/renderer/core/frame/location.cc
index 3306af7bdb4..24cb53f3652 100644
--- a/chromium/third_party/blink/renderer/core/frame/location.cc
+++ b/chromium/third_party/blink/renderer/core/frame/location.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/bindings/core/v8/binding_security.h"
#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/dom_window.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -117,19 +118,21 @@ String Location::hash() const {
return DOMURLUtilsReadOnly::hash(Url());
}
-void Location::setHref(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+void Location::setHref(v8::Isolate* isolate,
+ const USVStringOrTrustedURL& string_or_url,
ExceptionState& exception_state) {
- String url = GetStringFromTrustedURL(stringOrUrl, current_window->document(),
- exception_state);
- if (!exception_state.HadException()) {
- SetLocation(url, current_window, entered_window, &exception_state);
- }
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
+ LocalDOMWindow* entered_window = EnteredDOMWindow(isolate);
+
+ const String& url = GetStringFromTrustedURL(
+ string_or_url, incumbent_window->document(), exception_state);
+ if (exception_state.HadException())
+ return;
+
+ SetLocation(url, incumbent_window, entered_window, &exception_state);
}
-void Location::setProtocol(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
+void Location::setProtocol(v8::Isolate* isolate,
const String& protocol,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
@@ -139,62 +142,57 @@ void Location::setProtocol(LocalDOMWindow* current_window,
"'" + protocol + "' is an invalid protocol.");
return;
}
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::setHost(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
+void Location::setHost(v8::Isolate* isolate,
const String& host,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetHostAndPort(host);
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::setHostname(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
+void Location::setHostname(v8::Isolate* isolate,
const String& hostname,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetHost(hostname);
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::setPort(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String& port_string,
+void Location::setPort(v8::Isolate* isolate,
+ const String& port,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
- url.SetPort(port_string);
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+ url.SetPort(port);
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::setPathname(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
+void Location::setPathname(v8::Isolate* isolate,
const String& pathname,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetPath(pathname);
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::setSearch(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
+void Location::setSearch(v8::Isolate* isolate,
const String& search,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetQuery(search);
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::setHash(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
+void Location::setHash(v8::Isolate* isolate,
const String& hash,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
@@ -208,42 +206,40 @@ void Location::setHash(LocalDOMWindow* current_window,
// cases where fragment identifiers are ignored or invalid.
if (EqualIgnoringNullity(old_fragment_identifier, url.FragmentIdentifier()))
return;
- SetLocation(url.GetString(), current_window, entered_window,
- &exception_state);
+ SetLocation(url.GetString(), IncumbentDOMWindow(isolate),
+ EnteredDOMWindow(isolate), &exception_state);
}
-void Location::assign(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+void Location::assign(v8::Isolate* isolate,
+ const USVStringOrTrustedURL& string_or_url,
ExceptionState& exception_state) {
- // TODO(yukishiino): Remove this check once we remove [CrossOrigin] from
- // the |assign| DOM operation's definition in Location.idl. See the comment
- // in Location.idl for details.
- if (!BindingSecurity::ShouldAllowAccessTo(current_window, this,
- exception_state)) {
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
+ LocalDOMWindow* entered_window = EnteredDOMWindow(isolate);
+
+ const String& url = GetStringFromTrustedURL(
+ string_or_url, incumbent_window->document(), exception_state);
+ if (exception_state.HadException())
return;
- }
- String url = GetStringFromTrustedURL(stringOrUrl, current_window->document(),
- exception_state);
- if (!exception_state.HadException()) {
- SetLocation(url, current_window, entered_window, &exception_state);
- }
+ SetLocation(url, incumbent_window, entered_window, &exception_state);
}
-void Location::replace(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL& stringOrUrl,
+void Location::replace(v8::Isolate* isolate,
+ const USVStringOrTrustedURL& string_or_url,
ExceptionState& exception_state) {
- String url = GetStringFromTrustedURL(stringOrUrl, current_window->document(),
- exception_state);
- if (!exception_state.HadException()) {
- SetLocation(url, current_window, entered_window, &exception_state,
- SetLocationPolicy::kReplaceThisFrame);
- }
+ LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
+ LocalDOMWindow* entered_window = EnteredDOMWindow(isolate);
+
+ const String& url = GetStringFromTrustedURL(
+ string_or_url, incumbent_window->document(), exception_state);
+ if (exception_state.HadException())
+ return;
+
+ SetLocation(url, incumbent_window, entered_window, &exception_state,
+ SetLocationPolicy::kReplaceThisFrame);
}
-void Location::reload(LocalDOMWindow* current_window) {
+void Location::reload() {
if (!IsAttached())
return;
if (GetDocument()->Url().ProtocolIsJavaScript())
@@ -294,6 +290,22 @@ void Location::SetLocation(const String& url,
if (dom_window_->IsInsecureScriptAccess(*current_window, completed_url))
return;
+ // Check the source browsing context's CSP to fulfill the CSP check
+ // requirement of https://html.spec.whatwg.org/#navigate for javascript URLs.
+ // Although the spec states we should perform this check on task execution,
+ // we do this prior to dispatch since the parent frame's CSP may be
+ // inaccessible if the target frame is out of process.
+ Document* current_document = current_window->document();
+ if (current_document && completed_url.ProtocolIsJavaScript() &&
+ !ContentSecurityPolicy::ShouldBypassMainWorld(current_document)) {
+ String script_source = DecodeURLEscapeSequences(
+ completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
+ if (!current_document->GetContentSecurityPolicy()->AllowJavaScriptURLs(
+ nullptr, script_source, current_document->Url(), OrdinalNumber())) {
+ return;
+ }
+ }
+
V8DOMActivityLogger* activity_logger =
V8DOMActivityLogger::CurrentActivityLoggerIfIsolatedWorld();
if (activity_logger) {
diff --git a/chromium/third_party/blink/renderer/core/frame/location.h b/chromium/third_party/blink/renderer/core/frame/location.h
index 18853bec66f..67c557878d2 100644
--- a/chromium/third_party/blink/renderer/core/frame/location.h
+++ b/chromium/third_party/blink/renderer/core/frame/location.h
@@ -61,56 +61,26 @@ class CORE_EXPORT Location final : public ScriptWrappable {
DOMWindow* DomWindow() const { return dom_window_.Get(); }
- void setHref(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL&,
- ExceptionState&);
+ void setHref(v8::Isolate*, const USVStringOrTrustedURL&, ExceptionState&);
void href(USVStringOrTrustedURL&) const;
- void assign(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL&,
- ExceptionState&);
- void replace(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const USVStringOrTrustedURL&,
- ExceptionState&);
- void reload(LocalDOMWindow* current_window);
-
- void setProtocol(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void assign(v8::Isolate*, const USVStringOrTrustedURL&, ExceptionState&);
+ void replace(v8::Isolate*, const USVStringOrTrustedURL&, ExceptionState&);
+ void reload();
+
+ void setProtocol(v8::Isolate*, const String&, ExceptionState&);
String protocol() const;
- void setHost(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void setHost(v8::Isolate*, const String&, ExceptionState&);
String host() const;
- void setHostname(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void setHostname(v8::Isolate*, const String&, ExceptionState&);
String hostname() const;
- void setPort(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void setPort(v8::Isolate*, const String&, ExceptionState&);
String port() const;
- void setPathname(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void setPathname(v8::Isolate*, const String&, ExceptionState&);
String pathname() const;
- void setSearch(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void setSearch(v8::Isolate*, const String&, ExceptionState&);
String search() const;
- void setHash(LocalDOMWindow* current_window,
- LocalDOMWindow* entered_window,
- const String&,
- ExceptionState&);
+ void setHash(v8::Isolate*, const String&, ExceptionState&);
String hash() const;
String origin() const;
diff --git a/chromium/third_party/blink/renderer/core/frame/location.idl b/chromium/third_party/blink/renderer/core/frame/location.idl
index 59d42cedfe6..ba5f5683496 100644
--- a/chromium/third_party/blink/renderer/core/frame/location.idl
+++ b/chromium/third_party/blink/renderer/core/frame/location.idl
@@ -26,22 +26,13 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-// https://html.spec.whatwg.org/multipage/browsers.html#location
+// https://html.spec.whatwg.org/C/#the-location-interface
[
CheckSecurity=Receiver,
Exposed=Window
] interface Location {
- // |assign| is *NOT* cross-origin accessible in the spec, but it needs
- // the Incumbent realm when navigating the page. See the below link.
- // https://html.spec.whatwg.org/multipage/browsers.html#location-object-navigate
- // Unfortunately, Blink does not support the Incumbent realm so far, and
- // we need a hack of assignOriginSafeMethodGetter to simulate the Incumbent
- // realm. Thus, we have [CrossOrigin] here just for the hack although
- // |assign| itself is not cross-origin accessible.
- // TODO(yukishiino): Remove [CrossOrigin] once we support the Incumbent
- // realm correctly.
- [CallWith=(CurrentWindow,EnteredWindow), CrossOrigin, RaisesException, Unforgeable] void assign(URLString url);
+ [CallWith=Isolate, RaisesException, Unforgeable] void assign(URLString url);
// |replace|, and *writing* |href| do not require a security check, as they
// *change* the page, and thus these do not change any property of an
@@ -49,24 +40,24 @@
// However, *reading* |href|, or accessing any component, is a security
// problem, since that allows tracking navigation.
// https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
- [CallWith=(CurrentWindow,EnteredWindow), CrossOrigin, RaisesException, Unforgeable] void replace(URLString url);
- [CallWith=CurrentWindow, Unforgeable] void reload();
+ [CallWith=Isolate, CrossOrigin, RaisesException, Unforgeable] void replace(URLString url);
+ [Unforgeable] void reload();
// TODO(foolip): |ancestorOrigins| should have [Unforgeable, SameObject].
[Unforgeable] readonly attribute DOMStringList ancestorOrigins;
- [Affects=Nothing, SetterCallWith=(CurrentWindow,EnteredWindow), CrossOrigin=Setter, RaisesException=Setter, Unforgeable] attribute URLString href;
+ [Affects=Nothing, SetterCallWith=Isolate, CrossOrigin=Setter, RaisesException=Setter, Unforgeable] attribute URLString href;
// TODO(yukishiino): Use [Unforgeable] stringifier instead of toString.
[Unforgeable] DOMString toString();
[MeasureAs=LocationOrigin, Unforgeable] readonly attribute USVString origin;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString protocol;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString host;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString hostname;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString port;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString pathname;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString search;
- [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString hash;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString protocol;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString host;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString hostname;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString port;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString pathname;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString search;
+ [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString hash;
// TODO(foolip): Location does not have a valueOf() override in the spec.
// See the comment in Location.h for the purpose of this.
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator.cc b/chromium/third_party/blink/renderer/core/frame/navigator.cc
index c7dd8edefb6..2d22c0bea63 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator.cc
+++ b/chromium/third_party/blink/renderer/core/frame/navigator.cc
@@ -32,13 +32,13 @@
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/language.h"
#include "third_party/blink/renderer/platform/memory_coordinator.h"
namespace blink {
-Navigator::Navigator(LocalFrame* frame) : DOMWindowClient(frame) {}
+Navigator::Navigator(LocalFrame* frame)
+ : NavigatorLanguage(frame->GetDocument()), DOMWindowClient(frame) {}
String Navigator::productSub() const {
return "20030107";
@@ -83,38 +83,21 @@ bool Navigator::cookieEnabled() const {
return CookiesEnabled(GetFrame()->GetDocument());
}
-Vector<String> Navigator::languages() {
- languages_changed_ = false;
-
+String Navigator::GetAcceptLanguages() {
String accept_languages;
if (GetFrame() && GetFrame()->GetPage()) {
accept_languages =
GetFrame()->GetPage()->GetChromeClient().AcceptLanguages();
+ } else {
+ accept_languages = DefaultLanguage();
}
- probe::applyAcceptLanguageOverride(GetFrame(), &accept_languages);
-
- Vector<String> languages;
- accept_languages.Split(',', languages);
-
- // Sanitizing tokens. We could do that more extensively but we should assume
- // that the accept languages are already sane and support BCP47. It is
- // likely a waste of time to make sure the tokens matches that spec here.
- for (wtf_size_t i = 0; i < languages.size(); ++i) {
- String& token = languages[i];
- token = token.StripWhiteSpace();
- if (token.length() >= 3 && token[2] == '_')
- token.replace(2, 1, "-");
- }
-
- if (languages.IsEmpty())
- languages.push_back(DefaultLanguage());
-
- return languages;
+ return accept_languages;
}
void Navigator::Trace(blink::Visitor* visitor) {
ScriptWrappable::Trace(visitor);
+ NavigatorLanguage::Trace(visitor);
DOMWindowClient::Trace(visitor);
Supplementable<Navigator>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator.h b/chromium/third_party/blink/renderer/core/frame/navigator.h
index 68d88ddaf08..302f29d2511 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator.h
+++ b/chromium/third_party/blink/renderer/core/frame/navigator.h
@@ -66,8 +66,7 @@ class CORE_EXPORT Navigator final : public ScriptWrappable,
String platform() const override;
String userAgent() const override;
- // NavigatorLanguage
- Vector<String> languages() override;
+ String GetAcceptLanguages() override;
void Trace(blink::Visitor*) override;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator.idl b/chromium/third_party/blink/renderer/core/frame/navigator.idl
index 7126b21d94b..473881930b2 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator.idl
+++ b/chromium/third_party/blink/renderer/core/frame/navigator.idl
@@ -23,13 +23,13 @@ interface Navigator {
// objects implementing this interface also implement the interfaces given below
// TODO(foolip): vendorSub should be on NavigatorID.
- [MeasureAs=NavigatorVendorSub] readonly attribute DOMString vendorSub;
+ [HighEntropy, MeasureAs=NavigatorVendorSub] readonly attribute DOMString vendorSub;
// TODO(foolip): productSub and vendor are not yet in the spec:
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27954
- [MeasureAs=NavigatorProductSub] readonly attribute DOMString productSub;
+ [HighEntropy, MeasureAs=NavigatorProductSub] readonly attribute DOMString productSub;
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27786
- [MeasureAs=NavigatorVendor] readonly attribute DOMString vendor;
+ [HighEntropy, MeasureAs=NavigatorVendor] readonly attribute DOMString vendor;
};
Navigator implements NavigatorConcurrentHardware;
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl b/chromium/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl
index b6f63bb7460..af79103d69b 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_concurrent_hardware.idl
@@ -8,5 +8,5 @@
NoInterfaceObject,
Exposed=(Window,Worker)
] interface NavigatorConcurrentHardware {
- readonly attribute unsigned long long hardwareConcurrency;
+ [HighEntropy, MeasureAs=NavigatorHardwareConcurrency] readonly attribute unsigned long long hardwareConcurrency;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_device_memory.idl b/chromium/third_party/blink/renderer/core/frame/navigator_device_memory.idl
index a0c717c1161..03e558c8c5a 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_device_memory.idl
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_device_memory.idl
@@ -8,6 +8,6 @@
NoInterfaceObject,
Exposed=(Window,Worker)
] interface NavigatorDeviceMemory {
- [MeasureAs=NavigatorDeviceMemory,RuntimeEnabled=NavigatorDeviceMemory,SecureContext]
+ [HighEntropy,MeasureAs=NavigatorDeviceMemory,RuntimeEnabled=NavigatorDeviceMemory,SecureContext]
readonly attribute float deviceMemory;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_id.idl b/chromium/third_party/blink/renderer/core/frame/navigator_id.idl
index 3f8bf7b5d71..9e60756d688 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_id.idl
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_id.idl
@@ -36,10 +36,10 @@
] interface NavigatorID {
readonly attribute DOMString appCodeName; // constant "Mozilla"
readonly attribute DOMString appName; // constant "Netscape"
- readonly attribute DOMString appVersion;
- readonly attribute DOMString platform;
+ [HighEntropy, MeasureAs=NavigatorAppVersion] readonly attribute DOMString appVersion;
+ [HighEntropy, MeasureAs=NavigatorPlatform] readonly attribute DOMString platform;
readonly attribute DOMString product; // constant "Gecko"
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=22555
// boolean taintEnabled(); // constant false
- [Affects=Nothing] readonly attribute DOMString userAgent;
+ [Affects=Nothing, HighEntropy, MeasureAs=NavigatorUserAgent] readonly attribute DOMString userAgent;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_language.cc b/chromium/third_party/blink/renderer/core/frame/navigator_language.cc
index 89f5cf01515..d2f3e4cc36c 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_language.cc
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_language.cc
@@ -4,22 +4,65 @@
#include "third_party/blink/renderer/core/frame/navigator_language.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/language.h"
namespace blink {
-NavigatorLanguage::NavigatorLanguage() = default;
+Vector<String> ParseAndSanitize(const String& accept_languages) {
+ Vector<String> languages;
+ accept_languages.Split(',', languages);
+
+ // Sanitizing tokens. We could do that more extensively but we should assume
+ // that the accept languages are already sane and support BCP47. It is
+ // likely a waste of time to make sure the tokens matches that spec here.
+ for (size_t i = 0; i < languages.size(); ++i) {
+ String& token = languages[i];
+ token = token.StripWhiteSpace();
+ if (token.length() >= 3 && token[2] == '_')
+ token.replace(2, 1, "-");
+ }
+
+ if (languages.IsEmpty())
+ languages.push_back(DefaultLanguage());
+
+ return languages;
+}
+
+NavigatorLanguage::NavigatorLanguage(ExecutionContext* context)
+ : context_(context) {}
AtomicString NavigatorLanguage::language() {
return AtomicString(languages().front());
}
-bool NavigatorLanguage::hasLanguagesChanged() const {
- return languages_changed_;
+const Vector<String>& NavigatorLanguage::languages() {
+ if (languages_dirty_) {
+ String accept_languages_override;
+ probe::applyAcceptLanguageOverride(context_, &accept_languages_override);
+
+ if (!accept_languages_override.IsNull()) {
+ languages_ = ParseAndSanitize(accept_languages_override);
+ } else {
+ languages_ = ParseAndSanitize(GetAcceptLanguages());
+ }
+
+ languages_dirty_ = false;
+ }
+ return languages_;
+}
+
+bool NavigatorLanguage::IsLanguagesDirty() const {
+ return languages_dirty_;
+}
+
+void NavigatorLanguage::SetLanguagesDirty() {
+ languages_dirty_ = true;
+ languages_.clear();
}
-void NavigatorLanguage::SetLanguagesChanged() {
- languages_changed_ = true;
+void NavigatorLanguage::Trace(blink::Visitor* visitor) {
+ visitor->Trace(context_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_language.h b/chromium/third_party/blink/renderer/core/frame/navigator_language.h
index 4651aa8d27d..b6507f9f4e6 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_language.h
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_language.h
@@ -6,21 +6,29 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATOR_LANGUAGE_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
-class CORE_EXPORT NavigatorLanguage {
+class CORE_EXPORT NavigatorLanguage : public GarbageCollectedMixin {
public:
- NavigatorLanguage();
+ explicit NavigatorLanguage(ExecutionContext*);
AtomicString language();
- virtual Vector<String> languages() = 0;
- bool hasLanguagesChanged() const;
- void SetLanguagesChanged();
+ const Vector<String>& languages();
+ bool IsLanguagesDirty() const;
+ void SetLanguagesDirty();
+
+ void Trace(blink::Visitor*) override;
protected:
- bool languages_changed_ = true;
+ bool languages_dirty_ = true;
+ WeakMember<ExecutionContext> context_;
+ virtual String GetAcceptLanguages() = 0;
+
+ private:
+ Vector<String> languages_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_language.idl b/chromium/third_party/blink/renderer/core/frame/navigator_language.idl
index d77bba562a1..f587304069d 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_language.idl
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_language.idl
@@ -8,6 +8,6 @@
NoInterfaceObject,
Exposed=(Window,Worker)
] interface NavigatorLanguage {
- readonly attribute DOMString language;
- [CachedAttribute=hasLanguagesChanged] readonly attribute FrozenArray<DOMString> languages;
+ [HighEntropy, MeasureAs=NavigatorLanguage] readonly attribute DOMString language;
+ [CachedAttribute=IsLanguagesDirty, HighEntropy, MeasureAs=NavigatorLanguages] readonly attribute FrozenArray<DOMString> languages;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.cc b/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.cc
index 9911e246571..148e0a75309 100644
--- a/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.cc
+++ b/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.cc
@@ -64,7 +64,7 @@ const PageScaleConstraints& PageScaleConstraintsSet::DefaultConstraints()
void PageScaleConstraintsSet::UpdatePageDefinedConstraints(
const ViewportDescription& description,
- Length legacy_fallback_width) {
+ const Length& legacy_fallback_width) {
page_defined_constraints_ =
description.Resolve(FloatSize(icb_size_), legacy_fallback_width);
diff --git a/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.h b/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.h
index 3571f7b5266..6144ae48b25 100644
--- a/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.h
+++ b/chromium/third_party/blink/renderer/core/frame/page_scale_constraints_set.h
@@ -52,9 +52,11 @@ class CORE_EXPORT PageScaleConstraintsSet
: public GarbageCollected<PageScaleConstraintsSet> {
public:
static PageScaleConstraintsSet* Create(Page* page) {
- return new PageScaleConstraintsSet(page);
+ return MakeGarbageCollected<PageScaleConstraintsSet>(page);
}
+ PageScaleConstraintsSet(Page* page);
+
void Trace(blink::Visitor*);
void SetDefaultConstraints(const PageScaleConstraints&);
@@ -66,7 +68,7 @@ class CORE_EXPORT PageScaleConstraintsSet
return page_defined_constraints_;
}
void UpdatePageDefinedConstraints(const ViewportDescription&,
- Length legacy_fallback_width);
+ const Length& legacy_fallback_width);
void AdjustForAndroidWebViewQuirks(const ViewportDescription&,
int layout_fallback_width,
float device_scale_factor,
@@ -113,8 +115,6 @@ class CORE_EXPORT PageScaleConstraintsSet
IntSize InitialViewportSize() const { return icb_size_; }
private:
- PageScaleConstraintsSet(Page* page);
-
PageScaleConstraints ComputeConstraintsStack() const;
void AdjustFinalConstraintsToContentsSize();
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.cc
index 322cb06f821..8e4321fcba6 100644
--- a/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.cc
+++ b/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.cc
@@ -19,6 +19,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
@@ -142,7 +143,8 @@ PausableScriptExecutor* PausableScriptExecutor::Create(
ScriptState* script_state = ToScriptState(frame, *world);
return MakeGarbageCollected<PausableScriptExecutor>(
frame, script_state, callback,
- new WebScriptExecutor(sources, world->GetWorldId(), user_gesture));
+ MakeGarbageCollected<WebScriptExecutor>(sources, world->GetWorldId(),
+ user_gesture));
}
void PausableScriptExecutor::CreateAndRun(
@@ -163,13 +165,14 @@ void PausableScriptExecutor::CreateAndRun(
PausableScriptExecutor* executor =
MakeGarbageCollected<PausableScriptExecutor>(
frame, script_state, callback,
- new V8FunctionExecutor(isolate, function, receiver, argc, argv));
+ MakeGarbageCollected<V8FunctionExecutor>(isolate, function, receiver,
+ argc, argv));
executor->Run();
}
void PausableScriptExecutor::ContextDestroyed(
ExecutionContext* destroyed_context) {
- PausableTimer::ContextDestroyed(destroyed_context);
+ ContextLifecycleObserver::ContextDestroyed(destroyed_context);
if (callback_) {
// Though the context is (about to be) destroyed, the callback is invoked
@@ -187,11 +190,10 @@ PausableScriptExecutor::PausableScriptExecutor(
ScriptState* script_state,
WebScriptExecutionCallback* callback,
Executor* executor)
- : PausableTimer(frame->GetDocument(), TaskType::kJavascriptTimer),
+ : ContextLifecycleObserver(frame->GetDocument()),
script_state_(script_state),
callback_(callback),
blocking_option_(kNonBlocking),
- keep_alive_(this),
executor_(executor) {
CHECK(script_state_);
CHECK(script_state_->ContextIsValid());
@@ -199,20 +201,17 @@ PausableScriptExecutor::PausableScriptExecutor(
PausableScriptExecutor::~PausableScriptExecutor() = default;
-void PausableScriptExecutor::Fired() {
- ExecuteAndDestroySelf();
-}
-
void PausableScriptExecutor::Run() {
ExecutionContext* context = GetExecutionContext();
DCHECK(context);
if (!context->IsContextPaused()) {
- PauseIfNeeded();
ExecuteAndDestroySelf();
return;
}
- StartOneShot(TimeDelta(), FROM_HERE);
- PauseIfNeeded();
+ task_handle_ = PostCancellableTask(
+ *context->GetTaskRunner(TaskType::kJavascriptTimer), FROM_HERE,
+ WTF::Bind(&PausableScriptExecutor::ExecuteAndDestroySelf,
+ WrapPersistent(this)));
}
void PausableScriptExecutor::RunAsync(BlockingOption blocking) {
@@ -222,8 +221,10 @@ void PausableScriptExecutor::RunAsync(BlockingOption blocking) {
if (blocking_option_ == kOnloadBlocking)
To<Document>(GetExecutionContext())->IncrementLoadEventDelayCount();
- StartOneShot(TimeDelta(), FROM_HERE);
- PauseIfNeeded();
+ task_handle_ = PostCancellableTask(
+ *context->GetTaskRunner(TaskType::kJavascriptTimer), FROM_HERE,
+ WTF::Bind(&PausableScriptExecutor::ExecuteAndDestroySelf,
+ WrapPersistent(this)));
}
void PausableScriptExecutor::ExecuteAndDestroySelf() {
@@ -252,15 +253,14 @@ void PausableScriptExecutor::ExecuteAndDestroySelf() {
void PausableScriptExecutor::Dispose() {
// Remove object as a ContextLifecycleObserver.
- PausableObject::ClearContext();
- keep_alive_.Clear();
- Stop();
+ ContextLifecycleObserver::ClearContext();
+ task_handle_.Cancel();
}
void PausableScriptExecutor::Trace(blink::Visitor* visitor) {
visitor->Trace(script_state_);
visitor->Trace(executor_);
- PausableTimer::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h b/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h
index c268810f799..327d5289bc1 100644
--- a/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h
+++ b/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h
@@ -7,10 +7,10 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/frame/pausable_timer.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "v8/include/v8.h"
@@ -23,7 +23,7 @@ class WebScriptExecutionCallback;
class CORE_EXPORT PausableScriptExecutor final
: public GarbageCollectedFinalized<PausableScriptExecutor>,
- public PausableTimer {
+ public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(PausableScriptExecutor);
public:
@@ -57,7 +57,7 @@ class CORE_EXPORT PausableScriptExecutor final
ScriptState*,
WebScriptExecutionCallback*,
Executor*);
- ~PausableScriptExecutor() override;
+ virtual ~PausableScriptExecutor();
void Run();
void RunAsync(BlockingOption);
@@ -66,7 +66,6 @@ class CORE_EXPORT PausableScriptExecutor final
void Trace(blink::Visitor*) override;
private:
- void Fired() override;
void ExecuteAndDestroySelf();
void Dispose();
@@ -74,8 +73,7 @@ class CORE_EXPORT PausableScriptExecutor final
Member<ScriptState> script_state_;
WebScriptExecutionCallback* callback_;
BlockingOption blocking_option_;
-
- SelfKeepAlive<PausableScriptExecutor> keep_alive_;
+ TaskHandle task_handle_;
Member<Executor> executor_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_task.cc b/chromium/third_party/blink/renderer/core/frame/pausable_task.cc
index 99b9d6a34c9..ea88b33c8e4 100644
--- a/chromium/third_party/blink/renderer/core/frame/pausable_task.cc
+++ b/chromium/third_party/blink/renderer/core/frame/pausable_task.cc
@@ -6,6 +6,7 @@
#include "base/location.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -25,7 +26,6 @@ void PausableTask::Post(ExecutionContext* context,
}
void PausableTask::ContextDestroyed(ExecutionContext* destroyed_context) {
- PausableTimer::ContextDestroyed(destroyed_context);
DCHECK(callback_);
Dispose();
@@ -34,7 +34,7 @@ void PausableTask::ContextDestroyed(ExecutionContext* destroyed_context) {
WebLocalFrame::PausableTaskResult::kContextInvalidOrDestroyed);
}
-void PausableTask::Fired() {
+void PausableTask::Run() {
CHECK(!GetExecutionContext()->IsContextDestroyed());
DCHECK(!GetExecutionContext()->IsContextPaused());
DCHECK(callback_);
@@ -50,23 +50,23 @@ void PausableTask::Fired() {
PausableTask::PausableTask(ExecutionContext* context,
WebLocalFrame::PausableTaskCallback callback)
- : PausableTimer(context, TaskType::kJavascriptTimer),
+ : ContextLifecycleObserver(context),
callback_(std::move(callback)),
keep_alive_(this) {
DCHECK(callback_);
DCHECK(context);
DCHECK(!context->IsContextDestroyed());
DCHECK(context->IsContextPaused());
-
- StartOneShot(TimeDelta(), FROM_HERE);
- PauseIfNeeded();
+ task_handle_ = PostCancellableTask(
+ *context->GetTaskRunner(TaskType::kInternalDefault), FROM_HERE,
+ WTF::Bind(&PausableTask::Run, WrapPersistent(this)));
}
void PausableTask::Dispose() {
// Remove object as a ContextLifecycleObserver.
- PausableObject::ClearContext();
+ ContextLifecycleObserver::ClearContext();
keep_alive_.Clear();
- Stop();
+ task_handle_.Cancel();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_task.h b/chromium/third_party/blink/renderer/core/frame/pausable_task.h
index d5ff5e02e42..e62b19ed02e 100644
--- a/chromium/third_party/blink/renderer/core/frame/pausable_task.h
+++ b/chromium/third_party/blink/renderer/core/frame/pausable_task.h
@@ -9,8 +9,9 @@
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/frame/pausable_timer.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
namespace blink {
@@ -19,27 +20,28 @@ namespace blink {
// invalidated.
class CORE_EXPORT PausableTask final
: public GarbageCollectedFinalized<PausableTask>,
- public PausableTimer {
+ public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(PausableTask);
public:
// Note: This asserts that the context is currently suspended.
PausableTask(ExecutionContext*, WebLocalFrame::PausableTaskCallback);
- ~PausableTask() override;
+ virtual ~PausableTask();
// Checks if the context is paused, and, if not, executes the callback
// immediately. Otherwise constructs a PausableTask that will run the
// callback when execution is unpaused.
static void Post(ExecutionContext*, WebLocalFrame::PausableTaskCallback);
- // PausableTimer:
+ // ContextLifecycleObserver:
void ContextDestroyed(ExecutionContext*) override;
- void Fired() override;
private:
+ void Run();
void Dispose();
WebLocalFrame::PausableTaskCallback callback_;
+ TaskHandle task_handle_;
SelfKeepAlive<PausableTask> keep_alive_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_timer.cc b/chromium/third_party/blink/renderer/core/frame/pausable_timer.cc
deleted file mode 100644
index ec5bd0fdb07..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/pausable_timer.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "third_party/blink/renderer/core/frame/pausable_timer.h"
-
-#include "third_party/blink/public/platform/task_type.h"
-
-namespace blink {
-
-namespace {
-// TimerBase::NextFireIntervalDelta returns a delta >= 0.
-constexpr TimeDelta kNextFireIntervalInvalid = TimeDelta::Min();
-} // namespace
-
-PausableTimer::PausableTimer(ExecutionContext* context, TaskType task_type)
- : TimerBase(context->GetTaskRunner(task_type)),
- PausableObject(context),
- next_fire_interval_(kNextFireIntervalInvalid) {
- DCHECK(context);
-}
-
-PausableTimer::~PausableTimer() = default;
-
-void PausableTimer::Stop() {
- next_fire_interval_ = kNextFireIntervalInvalid;
- TimerBase::Stop();
-}
-
-void PausableTimer::ContextDestroyed(ExecutionContext*) {
- Stop();
-}
-
-void PausableTimer::Pause() {
-#if DCHECK_IS_ON()
- DCHECK(!paused_);
- paused_ = true;
-#endif
- if (IsActive()) {
- next_fire_interval_ = NextFireInterval();
- DCHECK_GE(next_fire_interval_, TimeDelta());
- repeat_interval_ = RepeatInterval();
- TimerBase::Stop();
- }
-}
-
-void PausableTimer::Unpause() {
-#if DCHECK_IS_ON()
- DCHECK(paused_);
- paused_ = false;
-#endif
- if (next_fire_interval_ >= TimeDelta()) {
- // start() was called before, therefore location() is already set.
- // m_nextFireInterval is only set in suspend() if the Timer was active.
- Start(next_fire_interval_, repeat_interval_, GetLocation());
- next_fire_interval_ = kNextFireIntervalInvalid;
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_timer.h b/chromium/third_party/blink/renderer/core/frame/pausable_timer.h
deleted file mode 100644
index 40cf8b05c56..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/pausable_timer.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_PAUSABLE_TIMER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_PAUSABLE_TIMER_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
-#include "third_party/blink/renderer/platform/timer.h"
-
-namespace blink {
-
-class CORE_EXPORT PausableTimer : public TimerBase, public PausableObject {
- public:
- explicit PausableTimer(ExecutionContext*, TaskType);
- ~PausableTimer() override;
-
- // PausableObject
- void ContextDestroyed(ExecutionContext*) override;
- void Pause() final;
- void Unpause() final;
-
- void Stop() override;
-
- private:
- void Fired() override = 0;
-
- TimeDelta next_fire_interval_;
- TimeDelta repeat_interval_;
-#if DCHECK_IS_ON()
- bool paused_ = false;
-#endif
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_PAUSABLE_TIMER_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc b/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc
index 6a4bf4f5ea8..a509a164f63 100644
--- a/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc
+++ b/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/core_initializer.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
namespace blink {
@@ -30,6 +31,16 @@ PictureInPictureController& PictureInPictureController::From(
return *controller;
}
+// static
+bool PictureInPictureController::IsElementInPictureInPicture(
+ const Element* element) {
+ DCHECK(element);
+ Document& document = element->GetDocument();
+ PictureInPictureController* controller =
+ Supplement<Document>::From<PictureInPictureController>(document);
+ return controller && controller->IsPictureInPictureElement(element);
+}
+
void PictureInPictureController::Trace(blink::Visitor* visitor) {
Supplement<Document>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.h b/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
index a0e61ab1438..98b35b80f3e 100644
--- a/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
+++ b/chromium/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
@@ -31,6 +31,10 @@ class CORE_EXPORT PictureInPictureController
// Should be called before any other call to make sure a document is attached.
static PictureInPictureController& From(Document&);
+ // Returns whether the given element is currently in Picture-in-Picture. It
+ // returns false if PictureInPictureController is not attached to a document.
+ static bool IsElementInPictureInPicture(const Element*);
+
// List of Picture-in-Picture support statuses. If status is kEnabled,
// Picture-in-Picture is enabled for a document or element, otherwise it is
// not supported.
@@ -59,6 +63,15 @@ class CORE_EXPORT PictureInPictureController
// Should be called when an element has exited Picture-in-Picture.
virtual void OnExitedPictureInPicture(ScriptPromiseResolver*) = 0;
+ // Add video element to the list of video elements for the associated document
+ // that are eligible to Auto Picture-in-Picture.
+ virtual void AddToAutoPictureInPictureElementsList(HTMLVideoElement*) = 0;
+
+ // Remove video element from the list of video elements for the associated
+ // document that are eligible to Auto Picture-in-Picture.
+ virtual void RemoveFromAutoPictureInPictureElementsList(
+ HTMLVideoElement*) = 0;
+
// Should be called when a custom control on a video element in
// Picture-in-Picture is clicked. |control_id| is the identifier for its
// custom control. This is defined by the site that calls the web API.
@@ -70,14 +83,17 @@ class CORE_EXPORT PictureInPictureController
HTMLVideoElement*,
const std::vector<PictureInPictureControlInfo>&) = 0;
- // Returns whether the given element is currently in Picture-in-Picture.
- virtual bool IsPictureInPictureElement(const Element*) const = 0;
void Trace(blink::Visitor*) override;
protected:
explicit PictureInPictureController(Document&);
+ // Returns whether the given element is currently in Picture-in-Picture.
+ // It is protected so that clients use the static method
+ // IsElementInPictureInPicture() that avoids creating the controller.
+ virtual bool IsPictureInPictureElement(const Element*) const = 0;
+
DISALLOW_COPY_AND_ASSIGN(PictureInPictureController);
};
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame.cc
index 1db7ea1e0f6..18e376f2170 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -91,8 +91,20 @@ void RemoteFrame::Navigate(const FrameLoadRequest& passed_request,
FrameLoader::UpgradeInsecureRequest(frame_request.GetResourceRequest(),
frame_request.OriginDocument());
+ Document* document = frame_request.OriginDocument();
+ bool is_opener_navigation = document && document->GetFrame() &&
+ document->GetFrame()->Client()->Opener() == this;
+
+ bool prevent_sandboxed_download =
+ GetSecurityContext() &&
+ GetSecurityContext()->IsSandboxed(kSandboxDownloads) &&
+ !frame_request.GetResourceRequest().HasUserGesture() &&
+ RuntimeEnabledFeatures::
+ BlockingDownloadsInSandboxWithoutUserActivationEnabled();
+
Client()->Navigate(frame_request.GetResourceRequest(),
frame_load_type == WebFrameLoadType::kReplaceCurrentItem,
+ is_opener_navigation, prevent_sandboxed_download,
frame_request.GetBlobURLToken());
}
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h
index faf6c60739f..b9c8598e311 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h
@@ -30,6 +30,8 @@ class RemoteFrameClient : public FrameClient {
virtual void Navigate(const ResourceRequest&,
bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
mojom::blink::BlobURLTokenPtr) = 0;
unsigned BackForwardLength() override = 0;
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
index 3a840c698e4..ffb4e27bada 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
@@ -111,11 +111,14 @@ base::UnguessableToken RemoteFrameClientImpl::GetDevToolsFrameToken() const {
void RemoteFrameClientImpl::Navigate(
const ResourceRequest& request,
bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
mojom::blink::BlobURLTokenPtr blob_url_token) {
if (web_frame_->Client()) {
- web_frame_->Client()->Navigate(WrappedResourceRequest(request),
- should_replace_current_entry,
- blob_url_token.PassInterface().PassHandle());
+ web_frame_->Client()->Navigate(
+ WrappedResourceRequest(request), should_replace_current_entry,
+ is_opener_navigation, prevent_sandboxed_download,
+ blob_url_token.PassInterface().PassHandle());
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
index bfdd480b970..06878012e4c 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
@@ -37,6 +37,8 @@ class RemoteFrameClientImpl final : public RemoteFrameClient {
// RemoteFrameClient overrides:
void Navigate(const ResourceRequest&,
bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
mojom::blink::BlobURLTokenPtr) override;
unsigned BackForwardLength() override;
void CheckCompleted() override;
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc
index f74fd56d6cc..5697f4bfd5e 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/core/frame/remote_frame_view.h"
+#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
+#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element_visibility_observer.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -32,11 +34,26 @@ LocalFrameView* RemoteFrameView::ParentFrameView() const {
if (!is_attached_)
return nullptr;
- Frame* parent_frame = remote_frame_->Tree().Parent();
- if (parent_frame && parent_frame->IsLocalFrame())
- return ToLocalFrame(parent_frame)->View();
+ HTMLFrameOwnerElement* owner = remote_frame_->DeprecatedLocalOwner();
+ if (owner && owner->OwnerType() == FrameOwnerElementType::kPortal)
+ return owner->GetDocument().GetFrame()->View();
- return nullptr;
+ // |is_attached_| is only set from AttachToLayout(), which ensures that the
+ // parent is a local frame.
+ return ToLocalFrame(remote_frame_->Tree().Parent())->View();
+}
+
+LocalFrameView* RemoteFrameView::ParentLocalRootFrameView() const {
+ if (!is_attached_)
+ return nullptr;
+
+ HTMLFrameOwnerElement* owner = remote_frame_->DeprecatedLocalOwner();
+ if (owner && owner->OwnerType() == FrameOwnerElementType::kPortal)
+ return owner->GetDocument().GetFrame()->LocalFrameRoot().View();
+
+ // |is_attached_| is only set from AttachToLayout(), which ensures that the
+ // parent is a local frame.
+ return ToLocalFrame(remote_frame_->Tree().Parent())->LocalFrameRoot().View();
}
void RemoteFrameView::AttachToLayout() {
@@ -68,8 +85,7 @@ void RemoteFrameView::UpdateViewportIntersectionsForSubtree() {
if (!owner)
return;
- LocalFrameView* local_root_view =
- ToLocalFrame(remote_frame_->Tree().Parent())->LocalFrameRoot().View();
+ LocalFrameView* local_root_view = ParentLocalRootFrameView();
if (!local_root_view)
return;
@@ -139,8 +155,7 @@ void RemoteFrameView::UpdateViewportIntersectionsForSubtree() {
}
IntRect RemoteFrameView::GetCompositingRect() {
- LocalFrameView* local_root_view =
- ToLocalFrame(remote_frame_->Tree().Parent())->LocalFrameRoot().View();
+ LocalFrameView* local_root_view = ParentLocalRootFrameView();
if (!local_root_view || !remote_frame_->OwnerLayoutObject())
return IntRect();
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h
index 37e7179f1d4..9389744405e 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h
@@ -76,6 +76,12 @@ class RemoteFrameView final : public GarbageCollectedFinalized<RemoteFrameView>,
private:
LocalFrameView* ParentFrameView() const;
+ // This function returns the LocalFrameView associated with the parent frame's
+ // local root, or nullptr if the parent frame is not a local frame. For
+ // portals, this will return the local root associated with the portal's
+ // owner.
+ LocalFrameView* ParentLocalRootFrameView() const;
+
void UpdateRenderThrottlingStatus(bool hidden, bool subtree_throttled);
bool CanThrottleRendering() const;
void SetupRenderThrottling();
diff --git a/chromium/third_party/blink/renderer/core/frame/reporting_context.cc b/chromium/third_party/blink/renderer/core/frame/reporting_context.cc
index 7692ab2209a..e749011f8b8 100644
--- a/chromium/third_party/blink/renderer/core/frame/reporting_context.cc
+++ b/chromium/third_party/blink/renderer/core/frame/reporting_context.cc
@@ -33,12 +33,16 @@ ReportingContext* ReportingContext::From(ExecutionContext* context) {
void ReportingContext::QueueReport(Report* report) {
CountReport(report);
- report_buffer_.insert(report);
- // Only the most recent 100 reports will remain buffered.
+ // Buffer the report.
+ if (!report_buffer_.Contains(report->type()))
+ report_buffer_.insert(report->type(), HeapListHashSet<Member<Report>>());
+ report_buffer_.find(report->type())->value.insert(report);
+
+ // Only the most recent 100 reports will remain buffered, per report type.
// https://w3c.github.io/reporting/#notify-observers
- if (report_buffer_.size() > 100)
- report_buffer_.RemoveFirst();
+ if (report_buffer_.at(report->type()).size() > 100)
+ report_buffer_.find(report->type())->value.RemoveFirst();
for (auto observer : observers_)
observer->QueueReport(report);
@@ -69,8 +73,11 @@ void ReportingContext::RegisterObserver(ReportingObserver* observer) {
return;
observer->ClearBuffered();
- for (auto report : report_buffer_)
- observer->QueueReport(report);
+ for (auto type : report_buffer_) {
+ for (Report* report : type.value) {
+ observer->QueueReport(report);
+ }
+ }
}
void ReportingContext::UnregisterObserver(ReportingObserver* observer) {
diff --git a/chromium/third_party/blink/renderer/core/frame/reporting_context.h b/chromium/third_party/blink/renderer/core/frame/reporting_context.h
index 9332439b6be..4b86d997728 100644
--- a/chromium/third_party/blink/renderer/core/frame/reporting_context.h
+++ b/chromium/third_party/blink/renderer/core/frame/reporting_context.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/supplementable.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -46,7 +47,7 @@ class CORE_EXPORT ReportingContext final
private:
HeapListHashSet<Member<ReportingObserver>> observers_;
- HeapListHashSet<Member<Report>> report_buffer_;
+ HeapHashMap<String, HeapListHashSet<Member<Report>>> report_buffer_;
Member<ExecutionContext> execution_context_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc b/chromium/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc
index 0bc0072506a..b9fd355b6dc 100644
--- a/chromium/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc
@@ -26,7 +26,7 @@ class RotationViewportAnchorTest : public SimTest {
};
TEST_F(RotationViewportAnchorTest, SimpleAbsolutePosition) {
- WebView().Resize(WebSize(400, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -58,7 +58,7 @@ TEST_F(RotationViewportAnchorTest, SimpleAbsolutePosition) {
layout_viewport->SetScrollOffset(ScrollOffset(3050 - 200, 4050),
kProgrammaticScroll);
- WebView().Resize(WebSize(600, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(600, 400));
Compositor().BeginFrame();
EXPECT_EQ(3050 - 200, layout_viewport->GetScrollOffset().Width());
@@ -66,7 +66,7 @@ TEST_F(RotationViewportAnchorTest, SimpleAbsolutePosition) {
}
TEST_F(RotationViewportAnchorTest, PositionRelativeToViewportSize) {
- WebView().Resize(WebSize(100, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(100, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -93,24 +93,25 @@ TEST_F(RotationViewportAnchorTest, PositionRelativeToViewportSize) {
Document& document = GetDocument();
ScrollableArea* layout_viewport = document.View()->LayoutViewport();
- IntPoint target_position(5 * WebView().Size().width,
- 5 * WebView().Size().height);
+ IntPoint target_position(5 * WebView().MainFrameWidget()->Size().width,
+ 5 * WebView().MainFrameWidget()->Size().height);
// Place the target at the top-center of the viewport. This is where the
// rotation anchor finds the node to anchor to.
layout_viewport->SetScrollOffset(
- ScrollOffset(target_position.X() - WebView().Size().width / 2 + 25,
+ ScrollOffset(target_position.X() -
+ WebView().MainFrameWidget()->Size().width / 2 + 25,
target_position.Y()),
kProgrammaticScroll);
- WebView().Resize(WebSize(600, 100));
+ WebView().MainFrameWidget()->Resize(WebSize(600, 100));
Compositor().BeginFrame();
- target_position =
- IntPoint(5 * WebView().Size().width, 5 * WebView().Size().height);
+ target_position = IntPoint(5 * WebView().MainFrameWidget()->Size().width,
+ 5 * WebView().MainFrameWidget()->Size().height);
IntPoint expected_offset(
- target_position.X() - WebView().Size().width / 2 + 25,
+ target_position.X() - WebView().MainFrameWidget()->Size().width / 2 + 25,
target_position.Y());
EXPECT_EQ(expected_offset.X(), layout_viewport->GetScrollOffset().Width());
diff --git a/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc b/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc
index e704a36bcc4..24cada8b0bb 100644
--- a/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc
+++ b/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc
@@ -73,8 +73,10 @@ SandboxFlags ParseSandboxPolicy(const SpaceSplitString& policy,
} else if (EqualIgnoringASCIICase(
sandbox_token, "allow-top-navigation-by-user-activation")) {
flags &= ~kSandboxTopNavigationByUserActivation;
- } else if (EqualIgnoringASCIICase(sandbox_token, "allow-downloads") &&
- RuntimeEnabledFeatures::BlockingDownloadsInSandboxEnabled()) {
+ } else if (EqualIgnoringASCIICase(
+ sandbox_token, "allow-downloads-without-user-activation") &&
+ RuntimeEnabledFeatures::
+ BlockingDownloadsInSandboxWithoutUserActivationEnabled()) {
flags &= ~kSandboxDownloads;
} else {
token_errors.Append(token_errors.IsEmpty() ? "'" : ", '");
diff --git a/chromium/third_party/blink/renderer/core/frame/screen.idl b/chromium/third_party/blink/renderer/core/frame/screen.idl
index 44dee75e00f..2e7e9c36d21 100644
--- a/chromium/third_party/blink/renderer/core/frame/screen.idl
+++ b/chromium/third_party/blink/renderer/core/frame/screen.idl
@@ -31,14 +31,14 @@
[
Exposed=Window
] interface Screen {
- readonly attribute long availWidth;
- readonly attribute long availHeight;
- readonly attribute long width;
- readonly attribute long height;
- readonly attribute unsigned long colorDepth;
- readonly attribute unsigned long pixelDepth;
+ [HighEntropy, Measure] readonly attribute long availWidth;
+ [HighEntropy, Measure] readonly attribute long availHeight;
+ [HighEntropy, Measure] readonly attribute long width;
+ [HighEntropy, Measure] readonly attribute long height;
+ [HighEntropy, Measure] readonly attribute unsigned long colorDepth;
+ [HighEntropy, Measure] readonly attribute unsigned long pixelDepth;
// Non-standard
- [Measure] readonly attribute long availLeft;
- [Measure] readonly attribute long availTop;
+ [HighEntropy, Measure] readonly attribute long availLeft;
+ [HighEntropy, Measure] readonly attribute long availTop;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/scroll_into_view_options.idl b/chromium/third_party/blink/renderer/core/frame/scroll_into_view_options.idl
index 8e22c35ae34..117a7aebc36 100644
--- a/chromium/third_party/blink/renderer/core/frame/scroll_into_view_options.idl
+++ b/chromium/third_party/blink/renderer/core/frame/scroll_into_view_options.idl
@@ -1,6 +1,6 @@
enum ScrollLogicalPosition { "start", "center", "end", "nearest" };
dictionary ScrollIntoViewOptions : ScrollOptions {
- ScrollLogicalPosition block = "center";
- [ImplementedAs=inlinePosition] ScrollLogicalPosition inline = "center";
+ ScrollLogicalPosition block = "start";
+ [ImplementedAs=inlinePosition] ScrollLogicalPosition inline = "nearest";
}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/frame/settings.h b/chromium/third_party/blink/renderer/core/frame/settings.h
index 5e6cede4f4c..3df729d1550 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings.h
+++ b/chromium/third_party/blink/renderer/core/frame/settings.h
@@ -33,6 +33,7 @@
#include "base/macros.h"
#include "third_party/blink/public/common/manifest/web_display_mode.h"
#include "third_party/blink/public/platform/pointer_properties.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
#include "third_party/blink/public/platform/web_effective_connection_type.h"
#include "third_party/blink/public/platform/web_viewport_style.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h"
@@ -73,7 +74,7 @@ class CORE_EXPORT Settings {
void SetBypassCSP(bool enabled) { bypass_csp_ = enabled; }
bool BypassCSP() const { return bypass_csp_; }
- // Only set by Layout Tests, and only used if textAutosizingEnabled() returns
+ // Only set by web tests, and only used if TextAutosizingEnabled() returns
// true.
void SetTextAutosizingWindowSizeOverride(const IntSize&);
const IntSize& TextAutosizingWindowSizeOverride() const {
diff --git a/chromium/third_party/blink/renderer/core/frame/settings.json5 b/chromium/third_party/blink/renderer/core/frame/settings.json5
index 61e5873fd60..e6c29b1b15b 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings.json5
+++ b/chromium/third_party/blink/renderer/core/frame/settings.json5
@@ -138,7 +138,11 @@
name: "shouldClearDocumentBackground",
initial: true,
},
-
+ {
+ name: "HighlightAds",
+ initial: false,
+ invalidate: "HighlightAds"
+ },
{
name: "textAreasAreResizable",
initial: false,
@@ -221,7 +225,7 @@
},
{
- name: "mediaPlaybackGestureWhitelistScope",
+ name: "webAppScope",
type: "String",
},
@@ -257,7 +261,7 @@
invalidate: "Style",
},
- // Used in layout tests for gesture tap highlights. Makes the highlights square
+ // Used in web tests for gesture tap highlights. Makes the highlights square
// (rather than rounded) to make it possible to reftest the results.
{
name: "mockGestureTapHighlightsEnabled",
@@ -498,7 +502,7 @@
type: "double",
},
- // Only used by Layout Tests and inspector emulation.
+ // Only used by web tests and inspector emulation.
{
name: "mediaTypeOverride",
initial: "\"\"",
@@ -786,12 +790,6 @@
},
{
- name: "savePreviousDocumentResources",
- initial: "SavePreviousDocumentResources::kNever",
- type: "SavePreviousDocumentResources",
- },
-
- {
name: "historyEntryRequiresUserGesture",
initial: false,
},
@@ -832,14 +830,6 @@
initial: false,
},
- // Whether data saver holdback is enabled when queried by the media APIs within Blink. If
- // enabled, data saver appears as disabled to the media APIs even if it has been actually
- // enabled by the user.
- {
- name: "dataSaverHoldbackMediaApi",
- initial: false,
- },
-
// Whether to invalidate device-dependent media queries and restore scroll positions
// on frame resize assuming device rotation.
{
@@ -1022,5 +1012,22 @@
initial: 800,
type: "int",
},
+
+ // Preferred color scheme from the OS/application passed to the renderer for
+ // evaluating the prefers-color-scheme media query.
+ {
+ name: "preferredColorScheme",
+ initial: "WebColorScheme::kNoPreference",
+ invalidate: "MediaQuery",
+ type: "WebColorScheme",
+ },
+
+ // Preferred motion-reduction setting from the OS/application passed to the
+ // renderer for evaluating the prefers-reduced-motion media query.
+ {
+ name: "prefersReducedMotion",
+ initial: false,
+ invalidate: "MediaQuery",
+ },
],
}
diff --git a/chromium/third_party/blink/renderer/core/frame/settings_delegate.h b/chromium/third_party/blink/renderer/core/frame/settings_delegate.h
index 2d959cc6884..548edcff823 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings_delegate.h
+++ b/chromium/third_party/blink/renderer/core/frame/settings_delegate.h
@@ -66,6 +66,7 @@ class CORE_EXPORT SettingsDelegate {
kDOMWorldsChange,
kMediaControlsChange,
kPluginsChange,
+ kHighlightAdsChange,
};
virtual void SettingsChanged(ChangeType) = 0;
diff --git a/chromium/third_party/blink/renderer/core/frame/use_counter.cc b/chromium/third_party/blink/renderer/core/frame/use_counter.cc
index 3bf1d23d42b..ec72ff34402 100644
--- a/chromium/third_party/blink/renderer/core/frame/use_counter.cc
+++ b/chromium/third_party/blink/renderer/core/frame/use_counter.cc
@@ -1345,6 +1345,8 @@ void UseCounter::DidCommitLoad(const LocalFrame* frame) {
const KURL url = frame->GetDocument()->Url();
if (url.ProtocolIs("chrome-extension"))
context_ = kExtensionContext;
+ if (url.ProtocolIs("file"))
+ context_ = kFileContext;
DCHECK_EQ(kPreCommit, commit_state_);
commit_state_ = kCommited;
@@ -1366,8 +1368,10 @@ void UseCounter::DidCommitLoad(const LocalFrame* frame) {
// TODO(loonybear): remove or move SVG histogram and extension histogram
// to the browser side.
- if ((context_ == kSVGImageContext || context_ == kExtensionContext))
+ if ((context_ == kSVGImageContext || context_ == kExtensionContext ||
+ context_ == kFileContext)) {
FeaturesHistogram().Count(static_cast<int>(WebFeature::kPageVisits));
+ }
}
}
@@ -1528,9 +1532,6 @@ void UseCounter::NotifyFeatureCounted(WebFeature feature) {
}
EnumerationHistogram& UseCounter::FeaturesHistogram() const {
- DCHECK_NE(kDisabledContext, context_);
- // The default features histogram is being recorded on the browser side.
- DCHECK_NE(kDefaultContext, context_);
// Every SVGImage has it's own Page instance, and multiple web pages can
// share the usage of a single SVGImage. Ideally perhaps we'd delegate
// metrics from an SVGImage to one of the Page's it's displayed in, but
@@ -1543,9 +1544,29 @@ EnumerationHistogram& UseCounter::FeaturesHistogram() const {
DEFINE_STATIC_LOCAL(blink::EnumerationHistogram, extension_histogram,
("Blink.UseCounter.Extensions.Features",
static_cast<int32_t>(WebFeature::kNumberOfFeatures)));
+ DEFINE_STATIC_LOCAL(blink::EnumerationHistogram, file_histogram,
+ ("Blink.UseCounter.File.Features",
+ static_cast<int32_t>(WebFeature::kNumberOfFeatures)));
// Track what features/properties have been reported to the browser side
// histogram.
- return context_ == kSVGImageContext ? svg_histogram : extension_histogram;
+ switch (context_) {
+ case kDefaultContext:
+ // The default features histogram is being recorded on the browser side.
+ NOTREACHED();
+ break;
+ case kSVGImageContext:
+ return svg_histogram;
+ case kExtensionContext:
+ return extension_histogram;
+ case kFileContext:
+ return file_histogram;
+ case kDisabledContext:
+ NOTREACHED();
+ break;
+ }
+ NOTREACHED();
+ blink::EnumerationHistogram* null = nullptr;
+ return *null;
}
EnumerationHistogram& UseCounter::CssHistogram() const {
diff --git a/chromium/third_party/blink/renderer/core/frame/use_counter.h b/chromium/third_party/blink/renderer/core/frame/use_counter.h
index 22481b447de..c3708c5c7bc 100644
--- a/chromium/third_party/blink/renderer/core/frame/use_counter.h
+++ b/chromium/third_party/blink/renderer/core/frame/use_counter.h
@@ -75,6 +75,8 @@ class CORE_EXPORT UseCounter {
kSVGImageContext,
// Counters for extensions.
kExtensionContext,
+ // Context for file:// URLs.
+ kFileContext,
// Context when counters should be disabled (eg, internal pages such as
// about, chrome-devtools, etc).
kDisabledContext
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
index 071f9bd7a53..b22e342c3df 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -82,6 +82,11 @@ VisualViewport::VisualViewport(Page& owner)
Reset();
}
+TransformPaintPropertyNode* VisualViewport::GetDeviceEmulationTransformNode()
+ const {
+ return device_emulation_transform_node_.get();
+}
+
TransformPaintPropertyNode*
VisualViewport::GetOverscrollElasticityTransformNode() const {
return overscroll_elasticity_transform_node_.get();
@@ -105,6 +110,7 @@ void VisualViewport::UpdatePaintPropertyNodesIfNeeded(
return;
needs_paint_property_update_ = false;
+ SetPaintArtifactCompositorNeedsUpdate();
auto* transform_parent = context.current.transform;
auto* scroll_parent = context.current.scroll;
@@ -116,6 +122,25 @@ void VisualViewport::UpdatePaintPropertyNodesIfNeeded(
DCHECK(clip_parent);
DCHECK(effect_parent);
+ {
+ const auto& device_emulation_transform =
+ GetChromeClient()->GetDeviceEmulationTransform();
+ if (!device_emulation_transform.IsIdentity()) {
+ TransformPaintPropertyNode::State state;
+ state.matrix = device_emulation_transform;
+ if (!device_emulation_transform_node_) {
+ device_emulation_transform_node_ = TransformPaintPropertyNode::Create(
+ *transform_parent, std::move(state));
+ } else {
+ device_emulation_transform_node_->Update(*transform_parent,
+ std::move(state));
+ }
+ transform_parent = device_emulation_transform_node_.get();
+ } else {
+ device_emulation_transform_node_ = nullptr;
+ }
+ }
+
if (inner_viewport_container_layer_) {
inner_viewport_container_layer_->SetLayerState(
PropertyTreeState(transform_parent, clip_parent, effect_parent),
@@ -170,6 +195,12 @@ void VisualViewport::UpdatePaintPropertyNodesIfNeeded(
state.max_scroll_offset_affected_by_page_scale = true;
state.compositor_element_id = GetCompositorScrollElementId();
+ if (MainFrame() &&
+ !MainFrame()->GetSettings()->GetThreadedScrollingEnabled()) {
+ state.main_thread_scrolling_reasons =
+ MainThreadScrollingReason::kThreadedScrollingDisabled;
+ }
+
if (!scroll_node_) {
scroll_node_ =
ScrollPaintPropertyNode::Create(*scroll_parent, std::move(state));
@@ -218,8 +249,7 @@ void VisualViewport::UpdatePaintPropertyNodesIfNeeded(
overlay_scrollbar_horizontal_->SetLayerState(
PropertyTreeState(transform_parent, context.current.clip,
horizontal_scrollbar_effect_node_.get()),
- IntPoint(overlay_scrollbar_horizontal_->GetPosition().x(),
- overlay_scrollbar_horizontal_->GetPosition().y()));
+ ScrollbarOffset(ScrollbarOrientation::kHorizontalScrollbar));
}
if (overlay_scrollbar_vertical_) {
@@ -239,8 +269,7 @@ void VisualViewport::UpdatePaintPropertyNodesIfNeeded(
overlay_scrollbar_vertical_->SetLayerState(
PropertyTreeState(transform_parent, context.current.clip,
vertical_scrollbar_effect_node_.get()),
- IntPoint(overlay_scrollbar_vertical_->GetPosition().x(),
- overlay_scrollbar_vertical_->GetPosition().y()));
+ ScrollbarOffset(ScrollbarOrientation::kVerticalScrollbar));
}
}
@@ -524,6 +553,9 @@ bool VisualViewport::MagnifyScaleAroundAnchor(float magnify_delta,
}
void VisualViewport::CreateLayerTree() {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
if (inner_viewport_scroll_layer_)
return;
@@ -549,7 +581,8 @@ void VisualViewport::CreateLayerTree() {
ScrollingCoordinator* coordinator = GetPage().GetScrollingCoordinator();
DCHECK(coordinator);
inner_viewport_scroll_layer_->SetIsContainerForFixedPositionLayers(true);
- coordinator->UpdateUserInputScrollable(this);
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ coordinator->UpdateUserInputScrollable(this);
// Set masks to bounds so the compositor doesn't clobber a manually
// set inner viewport container layer size.
@@ -629,6 +662,32 @@ void VisualViewport::InitializeScrollbars() {
frame->View()->VisualViewportScrollbarsChanged();
}
+int VisualViewport::ScrollbarThickness() const {
+ ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::MobileTheme();
+ int thickness = theme.ScrollbarThickness(kRegularScrollbar);
+ return clampTo<int>(std::floor(
+ GetPage().GetChromeClient().WindowToViewportScalar(thickness)));
+}
+
+IntSize VisualViewport::ScrollbarSize(ScrollbarOrientation orientation) const {
+ if (orientation == kHorizontalScrollbar) {
+ int viewport_width = inner_viewport_container_layer_->Size().width();
+ return IntSize(viewport_width - ScrollbarThickness(), ScrollbarThickness());
+ }
+ int viewport_height = inner_viewport_container_layer_->Size().height();
+ return IntSize(ScrollbarThickness(), viewport_height - ScrollbarThickness());
+}
+
+IntPoint VisualViewport::ScrollbarOffset(
+ ScrollbarOrientation orientation) const {
+ if (orientation == kHorizontalScrollbar) {
+ int viewport_height = inner_viewport_container_layer_->Size().height();
+ return IntPoint(0, viewport_height - ScrollbarThickness());
+ }
+ int viewport_width = inner_viewport_container_layer_->Size().width();
+ return IntPoint(viewport_width - ScrollbarThickness(), 0);
+}
+
void VisualViewport::SetupScrollbar(ScrollbarOrientation orientation) {
bool is_horizontal = orientation == kHorizontalScrollbar;
GraphicsLayer* scrollbar_graphics_layer =
@@ -637,32 +696,26 @@ void VisualViewport::SetupScrollbar(ScrollbarOrientation orientation) {
std::unique_ptr<ScrollingCoordinator::ScrollbarLayerGroup>&
scrollbar_layer_group = is_horizontal ? scrollbar_layer_group_horizontal_
: scrollbar_layer_group_vertical_;
- if (!scrollbar_graphics_layer->Parent()) {
+ if (!scrollbar_graphics_layer->Parent())
inner_viewport_container_layer_->AddChild(scrollbar_graphics_layer);
- scrollbar_graphics_layer->SetLayerState(
- PropertyTreeState(PropertyTreeState::Root()), IntPoint());
- }
- ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::MobileTheme();
- int thumb_thickness = clampTo<int>(
- std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
- theme.ThumbThickness())));
- int scrollbar_thickness = clampTo<int>(
- std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
- theme.ScrollbarThickness(kRegularScrollbar))));
- int scrollbar_margin = clampTo<int>(
- std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
- theme.ScrollbarMargin())));
if (!scrollbar_layer_group) {
ScrollingCoordinator* coordinator = GetPage().GetScrollingCoordinator();
DCHECK(coordinator);
+ ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::MobileTheme();
+ int thumb_thickness = clampTo<int>(
+ std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
+ theme.ThumbThickness())));
+ int scrollbar_margin = clampTo<int>(
+ std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
+ theme.ScrollbarMargin())));
scrollbar_layer_group = coordinator->CreateSolidColorScrollbarLayer(
orientation, thumb_thickness, scrollbar_margin, false,
GetScrollbarElementId(orientation));
// The compositor will control the scrollbar's visibility. Set to invisible
- // by default so scrollbars don't show up in layout tests.
+ // by default so scrollbars don't show up in web tests.
scrollbar_layer_group->layer->SetOpacity(0.f);
scrollbar_graphics_layer->SetContentsToCcLayer(
scrollbar_layer_group->layer.get(),
@@ -672,26 +725,13 @@ void VisualViewport::SetupScrollbar(ScrollbarOrientation orientation) {
inner_viewport_scroll_layer_->CcLayer()->element_id());
}
- int x_position = is_horizontal
- ? 0
- : inner_viewport_container_layer_->Size().width() -
- scrollbar_thickness;
- int y_position = is_horizontal
- ? inner_viewport_container_layer_->Size().height() -
- scrollbar_thickness
- : 0;
- int width = is_horizontal ? inner_viewport_container_layer_->Size().width() -
- scrollbar_thickness
- : scrollbar_thickness;
- int height = is_horizontal
- ? scrollbar_thickness
- : inner_viewport_container_layer_->Size().height() -
- scrollbar_thickness;
-
// Use the GraphicsLayer to position the scrollbars.
- scrollbar_graphics_layer->SetPosition(FloatPoint(x_position, y_position));
- scrollbar_graphics_layer->SetSize(gfx::Size(width, height));
- scrollbar_graphics_layer->SetContentsRect(IntRect(0, 0, width, height));
+ const auto& position = ScrollbarOffset(orientation);
+ scrollbar_graphics_layer->SetPosition(FloatPoint(position));
+
+ const auto& size = ScrollbarSize(orientation);
+ scrollbar_graphics_layer->SetSize(gfx::Size(size));
+ scrollbar_graphics_layer->SetContentsRect(IntRect(IntPoint(), size));
needs_paint_property_update_ = true;
}
@@ -1076,6 +1116,11 @@ void VisualViewport::SetOverlayScrollbarsHidden(bool hidden) {
ScrollableArea::SetScrollbarsHiddenIfOverlay(hidden);
}
+void VisualViewport::SetPaintArtifactCompositorNeedsUpdate() const {
+ if (MainFrame() && MainFrame()->View())
+ MainFrame()->View()->SetPaintArtifactCompositorNeedsUpdate();
+}
+
String VisualViewport::DebugName(const GraphicsLayer* graphics_layer) const {
String name;
if (graphics_layer == inner_viewport_container_layer_.get()) {
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
index a3f08928337..2ca09611cb7 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -258,6 +258,7 @@ class CORE_EXPORT VisualViewport final
ScrollbarTheme& GetPageScrollbarTheme() const override;
bool VisualViewportSuppliesScrollbars() const override;
+ TransformPaintPropertyNode* GetDeviceEmulationTransformNode() const;
TransformPaintPropertyNode* GetOverscrollElasticityTransformNode() const;
TransformPaintPropertyNode* GetPageScaleNode() const;
TransformPaintPropertyNode* GetScrollTranslationNode() const;
@@ -296,11 +297,16 @@ class CORE_EXPORT VisualViewport final
GraphicsLayerPaintingPhase,
const IntRect&) const override;
void SetOverlayScrollbarsHidden(bool) override;
+ void SetPaintArtifactCompositorNeedsUpdate() const override;
String DebugName(const GraphicsLayer*) const override;
const ScrollableArea* GetScrollableAreaForTesting(
const GraphicsLayer*) const override;
+ int ScrollbarThickness() const;
+ IntSize ScrollbarSize(ScrollbarOrientation) const;
+ IntPoint ScrollbarOffset(ScrollbarOrientation) const;
+
void SetupScrollbar(ScrollbarOrientation);
void NotifyRootFrameViewport() const;
@@ -337,6 +343,7 @@ class CORE_EXPORT VisualViewport final
std::unique_ptr<GraphicsLayer> overlay_scrollbar_horizontal_;
std::unique_ptr<GraphicsLayer> overlay_scrollbar_vertical_;
+ scoped_refptr<TransformPaintPropertyNode> device_emulation_transform_node_;
scoped_refptr<TransformPaintPropertyNode>
overscroll_elasticity_transform_node_;
scoped_refptr<TransformPaintPropertyNode> scale_transform_node_;
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.idl b/chromium/third_party/blink/renderer/core/frame/visual_viewport.idl
index 00317b9f566..4d64ea5347d 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.idl
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.idl
@@ -29,16 +29,16 @@
[
ImplementedAs=DOMVisualViewport
] interface VisualViewport : EventTarget {
- [Measure] readonly attribute double offsetLeft;
- [Measure] readonly attribute double offsetTop;
+ [HighEntropy, Measure] readonly attribute double offsetLeft;
+ [HighEntropy, Measure] readonly attribute double offsetTop;
- [Measure] readonly attribute double pageLeft;
- [Measure] readonly attribute double pageTop;
+ [HighEntropy, Measure] readonly attribute double pageLeft;
+ [HighEntropy, Measure] readonly attribute double pageTop;
- [Measure] readonly attribute double width;
- [Measure] readonly attribute double height;
+ [HighEntropy, Measure] readonly attribute double width;
+ [HighEntropy, Measure] readonly attribute double height;
- [Measure] readonly attribute double scale;
+ [HighEntropy, Measure] readonly attribute double scale;
attribute EventHandler onresize;
attribute EventHandler onscroll;
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index 9af2fe59732..078b245ce53 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -9,7 +9,7 @@
#include "cc/layers/picture_layer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_coalesced_input_event.h"
#include "third_party/blink/public/platform/web_input_event.h"
@@ -88,8 +88,7 @@ class VisualViewportTest : public testing::Test,
void (*override_settings_func)(WebSettings*) = nullptr) {
if (!override_settings_func)
override_settings_func = &ConfigureSettings;
- helper_.Initialize(nullptr, &mock_web_view_client_, nullptr,
- override_settings_func);
+ helper_.Initialize(nullptr, nullptr, nullptr, override_settings_func);
WebView()->SetDefaultPageScaleLimits(1, 4);
}
@@ -97,8 +96,7 @@ class VisualViewportTest : public testing::Test,
void (*override_settings_func)(WebSettings*) = nullptr) {
if (!override_settings_func)
override_settings_func = &ConfigureAndroidSettings;
- helper_.Initialize(nullptr, &mock_web_view_client_, nullptr,
- override_settings_func);
+ helper_.Initialize(nullptr, nullptr, nullptr, override_settings_func);
WebView()->SetDefaultPageScaleLimits(0.25f, 5);
}
@@ -208,7 +206,6 @@ class VisualViewportTest : public testing::Test,
protected:
std::string base_url_;
- frame_test_helpers::TestWebViewClient mock_web_view_client_;
frame_test_helpers::WebViewHelper helper_;
};
@@ -218,28 +215,28 @@ INSTANTIATE_PAINT_TEST_CASE_P(VisualViewportTest);
// WebView resizes the VisualViewport.
TEST_P(VisualViewportTest, TestResize) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
NavigateTo("about:blank");
ForceFullCompositingUpdate();
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
- IntSize web_view_size = WebView()->Size();
+ IntSize web_view_size = WebView()->MainFrameWidget()->Size();
// Make sure the visual viewport was initialized.
EXPECT_EQ(web_view_size, visual_viewport.Size());
// Resizing the WebView should change the VisualViewport.
web_view_size = IntSize(640, 480);
- WebView()->Resize(web_view_size);
- EXPECT_EQ(web_view_size, IntSize(WebView()->Size()));
+ WebView()->MainFrameWidget()->Resize(web_view_size);
+ EXPECT_EQ(web_view_size, IntSize(WebView()->MainFrameWidget()->Size()));
EXPECT_EQ(web_view_size, visual_viewport.Size());
// Resizing the visual viewport shouldn't affect the WebView.
IntSize new_viewport_size = IntSize(320, 200);
visual_viewport.SetSize(new_viewport_size);
- EXPECT_EQ(web_view_size, IntSize(WebView()->Size()));
+ EXPECT_EQ(web_view_size, IntSize(WebView()->MainFrameWidget()->Size()));
EXPECT_EQ(new_viewport_size, visual_viewport.Size());
}
@@ -256,7 +253,7 @@ TEST_P(VisualViewportTest, TestVisibleContentRect) {
// Vertical scrollbar width and horizontal scrollbar height.
IntSize scrollbar_size = IntSize(15, 15);
- WebView()->Resize(size);
+ WebView()->MainFrameWidget()->Resize(size);
// Scroll layout viewport and verify visibleContentRect.
WebView()->MainFrameImpl()->SetScrollOffset(WebSize(0, 50));
@@ -286,7 +283,7 @@ TEST_P(VisualViewportTest, TestVisibleContentRect) {
// make it appear to stay still). This caused bugs like crbug.com/453859.
TEST_P(VisualViewportTest, TestResizeAtFullyScrolledPreservesViewportLocation) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
RegisterMockedHttpURLLoad("content-width-1000.html");
NavigateTo(base_url_ + "content-width-1000.html");
@@ -312,12 +309,12 @@ TEST_P(VisualViewportTest, TestResizeAtFullyScrolledPreservesViewportLocation) {
// Shrink the WebView, this should cause both viewports to shrink and
// WebView should do whatever it needs to do to preserve the visible
// location.
- WebView()->Resize(IntSize(700, 550));
+ WebView()->MainFrameWidget()->Resize(IntSize(700, 550));
EXPECT_EQ(expected_location,
frame_view.GetScrollableArea()->VisibleContentRect().Location());
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
EXPECT_EQ(expected_location,
frame_view.GetScrollableArea()->VisibleContentRect().Location());
@@ -355,7 +352,7 @@ TEST_P(VisualViewportTest, TestResizeAfterVerticalScroll) {
RegisterMockedHttpURLLoad("200-by-800-viewport.html");
NavigateTo(base_url_ + "200-by-800-viewport.html");
- WebView()->Resize(IntSize(100, 200));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 200));
// Scroll main frame to the bottom of the document
WebView()->MainFrameImpl()->SetScrollOffset(WebSize(0, 400));
@@ -374,7 +371,7 @@ TEST_P(VisualViewportTest, TestResizeAfterVerticalScroll) {
visual_viewport.VisibleRect().Size());
// Verify the paint property nodes and GeometryMapper cache.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
UpdateAllLifecyclePhases();
EXPECT_EQ(TransformationMatrix().Scale(2),
@@ -388,7 +385,7 @@ TEST_P(VisualViewportTest, TestResizeAfterVerticalScroll) {
}
// Perform the resizing
- WebView()->Resize(IntSize(200, 100));
+ WebView()->MainFrameWidget()->Resize(IntSize(200, 100));
// After resizing the scale changes 2.0 -> 4.0
EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 25), visual_viewport.VisibleRect().Size());
@@ -398,7 +395,7 @@ TEST_P(VisualViewportTest, TestResizeAfterVerticalScroll) {
EXPECT_FLOAT_SIZE_EQ(FloatSize(0, 75), visual_viewport.GetScrollOffset());
// Verify the paint property nodes and GeometryMapper cache.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
UpdateAllLifecyclePhases();
EXPECT_EQ(TransformationMatrix().Scale(4),
@@ -446,7 +443,7 @@ TEST_P(VisualViewportTest, TestResizeAfterHorizontalScroll) {
RegisterMockedHttpURLLoad("200-by-800-viewport.html");
NavigateTo(base_url_ + "200-by-800-viewport.html");
- WebView()->Resize(IntSize(100, 200));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 200));
// Outer viewport takes the whole width of the document.
@@ -462,7 +459,7 @@ TEST_P(VisualViewportTest, TestResizeAfterHorizontalScroll) {
visual_viewport.VisibleRect().Size());
// Verify the paint property nodes and GeometryMapper cache.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
UpdateAllLifecyclePhases();
EXPECT_EQ(TransformationMatrix().Scale(2),
@@ -475,7 +472,7 @@ TEST_P(VisualViewportTest, TestResizeAfterHorizontalScroll) {
&TransformPaintPropertyNode::Root()));
}
- WebView()->Resize(IntSize(200, 100));
+ WebView()->MainFrameWidget()->Resize(IntSize(200, 100));
// After resizing the scale changes 2.0 -> 4.0
EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 25), visual_viewport.VisibleRect().Size());
@@ -485,7 +482,7 @@ TEST_P(VisualViewportTest, TestResizeAfterHorizontalScroll) {
EXPECT_FLOAT_SIZE_EQ(FloatSize(150, 0), visual_viewport.GetScrollOffset());
// Verify the paint property nodes and GeometryMapper cache.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
UpdateAllLifecyclePhases();
EXPECT_EQ(TransformationMatrix().Scale(4),
@@ -502,7 +499,7 @@ TEST_P(VisualViewportTest, TestResizeAfterHorizontalScroll) {
// Test that the container layer gets sized properly if the WebView is resized
// prior to the VisualViewport being attached to the layer tree.
TEST_P(VisualViewportTest, TestWebViewResizedBeforeAttachment) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithDesktopSettings();
@@ -513,7 +510,7 @@ TEST_P(VisualViewportTest, TestWebViewResizedBeforeAttachment) {
WebFrameWidgetBase* main_frame_widget =
WebView()->MainFrameImpl()->FrameWidgetImpl();
main_frame_widget->SetRootGraphicsLayer(nullptr);
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
NavigateTo("about:blank");
UpdateAllLifecyclePhases();
@@ -534,7 +531,7 @@ TEST_P(VisualViewportTest, TestWebViewResizedBeforeAttachment) {
// location of the viewport.
TEST_P(VisualViewportTest, TestVisibleRect) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
NavigateTo("about:blank");
ForceFullCompositingUpdate();
@@ -542,11 +539,12 @@ TEST_P(VisualViewportTest, TestVisibleRect) {
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
// Initial visible rect should be the whole frame.
- EXPECT_EQ(IntSize(WebView()->Size()), visual_viewport.Size());
+ EXPECT_EQ(IntSize(WebView()->MainFrameWidget()->Size()),
+ visual_viewport.Size());
// Viewport is whole frame.
IntSize size = IntSize(400, 200);
- WebView()->Resize(size);
+ WebView()->MainFrameWidget()->Resize(size);
UpdateAllLifecyclePhases();
visual_viewport.SetSize(size);
@@ -584,7 +582,7 @@ TEST_P(VisualViewportTest, TestVisibleRect) {
// and scroll location of the viewport relative to the document.
TEST_P(VisualViewportTest, TestVisibleRectInDocument) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(100, 400));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 400));
RegisterMockedHttpURLLoad("200-by-800-viewport.html");
NavigateTo(base_url_ + "200-by-800-viewport.html");
@@ -609,7 +607,7 @@ TEST_P(VisualViewportTest, TestVisibleRectInDocument) {
TEST_P(VisualViewportTest, TestFractionalScrollOffsetIsNotOverwritten) {
ScopedFractionalScrollOffsetsForTest fractional_scroll_offsets(true);
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(200, 250));
+ WebView()->MainFrameWidget()->Resize(IntSize(200, 250));
RegisterMockedHttpURLLoad("200-by-800-viewport.html");
NavigateTo(base_url_ + "200-by-800-viewport.html");
@@ -627,7 +625,7 @@ TEST_P(VisualViewportTest, TestFractionalScrollOffsetIsNotOverwritten) {
// that the visual viewport always stays within the bounds of the main frame.
TEST_P(VisualViewportTest, TestOffsetClamping) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(
@@ -688,7 +686,7 @@ TEST_P(VisualViewportTest, TestOffsetClamping) {
// keyboard came up.
TEST_P(VisualViewportTest, TestOffsetClampingWithResize) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
NavigateTo("about:blank");
ForceFullCompositingUpdate();
@@ -756,7 +754,7 @@ TEST_P(VisualViewportTest, TestOffsetClampingWithResize) {
// main frame when we apply both scaling and resizes.
TEST_P(VisualViewportTest, TestOffsetClampingWithResizeAndScale) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
NavigateTo("about:blank");
ForceFullCompositingUpdate();
@@ -787,10 +785,12 @@ TEST_P(VisualViewportTest, TestOffsetClampingWithResizeAndScale) {
EXPECT_EQ(IntSize(330, 250), visual_viewport.Size());
// Resize both the viewport and the frame to be larger.
- WebView()->Resize(IntSize(640, 480));
+ WebView()->MainFrameWidget()->Resize(IntSize(640, 480));
UpdateAllLifecyclePhases();
- EXPECT_EQ(IntSize(WebView()->Size()), visual_viewport.Size());
- EXPECT_EQ(IntSize(WebView()->Size()), GetFrame()->View()->FrameRect().Size());
+ EXPECT_EQ(IntSize(WebView()->MainFrameWidget()->Size()),
+ visual_viewport.Size());
+ EXPECT_EQ(IntSize(WebView()->MainFrameWidget()->Size()),
+ GetFrame()->View()->FrameRect().Size());
visual_viewport.SetLocation(FloatPoint(1000, 1000));
EXPECT_FLOAT_POINT_EQ(FloatPoint(320, 240),
visual_viewport.VisibleRect().Location());
@@ -809,12 +809,12 @@ TEST_P(VisualViewportTest, TestOffsetClampingWithResizeAndScale) {
// the aspect ratio.
TEST_P(VisualViewportTest, TestFrameViewSizedToContent) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
RegisterMockedHttpURLLoad("200-by-300-viewport.html");
NavigateTo(base_url_ + "200-by-300-viewport.html");
- WebView()->Resize(IntSize(600, 800));
+ WebView()->MainFrameWidget()->Resize(IntSize(600, 800));
UpdateAllLifecyclePhases();
// Note: the size is ceiled and should match the behavior in CC's
@@ -828,12 +828,12 @@ TEST_P(VisualViewportTest, TestFrameViewSizedToContent) {
// so make sure the LocalFrameView is sized to the viewport.
TEST_P(VisualViewportTest, TestFrameViewSizedToMinimumScale) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
RegisterMockedHttpURLLoad("200-by-300.html");
NavigateTo(base_url_ + "200-by-300.html");
- WebView()->Resize(IntSize(100, 160));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 160));
UpdateAllLifecyclePhases();
EXPECT_EQ(IntSize(100, 160),
@@ -844,7 +844,7 @@ TEST_P(VisualViewportTest, TestFrameViewSizedToMinimumScale) {
// scroll layer. crbug.com/423189.
TEST_P(VisualViewportTest, TestAttachingNewFrameSetsInnerScrollLayerSize) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
// Load a wider page first, the navigation should resize the scroll layer to
// the smaller size on the second navigation.
@@ -866,8 +866,12 @@ TEST_P(VisualViewportTest, TestAttachingNewFrameSetsInnerScrollLayerSize) {
UpdateAllLifecyclePhases();
// Ensure the scroll contents size matches the frame view's size.
- EXPECT_EQ(IntSize(320, 240), IntSize(visual_viewport.ScrollLayer()->Size()));
- if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(IntSize(320, 240),
+ IntSize(visual_viewport.ScrollLayer()->Size()));
+ }
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(IntSize(320, 240),
visual_viewport.GetScrollNode()->ContentsSize());
}
@@ -882,7 +886,7 @@ TEST_P(VisualViewportTest, TestAttachingNewFrameSetsInnerScrollLayerSize) {
// appropriately sized in the presence of a viewport <meta> tag.
TEST_P(VisualViewportTest, TestFrameViewSizedToViewportMetaMinimumScale) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(320, 240));
+ WebView()->MainFrameWidget()->Resize(IntSize(320, 240));
RegisterMockedHttpURLLoad("200-by-300-min-scale-2.html");
NavigateTo(base_url_ + "200-by-300-min-scale-2.html");
@@ -898,7 +902,7 @@ TEST_P(VisualViewportTest, TestFrameViewSizedToViewportMetaMinimumScale) {
TEST_P(VisualViewportTest, TestVisualViewportGetsSizeInAutoSizeMode) {
InitializeWithDesktopSettings();
- EXPECT_EQ(IntSize(0, 0), IntSize(WebView()->Size()));
+ EXPECT_EQ(IntSize(0, 0), IntSize(WebView()->MainFrameWidget()->Size()));
EXPECT_EQ(IntSize(0, 0), GetFrame()->GetPage()->GetVisualViewport().Size());
WebView()->EnableAutoResizeMode(WebSize(10, 10), WebSize(1000, 1000));
@@ -914,7 +918,7 @@ TEST_P(VisualViewportTest, TestVisualViewportGetsSizeInAutoSizeMode) {
// viewport.
TEST_P(VisualViewportTest, TestTextSelectionHandles) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(500, 800));
+ WebView()->MainFrameWidget()->Resize(IntSize(500, 800));
RegisterMockedHttpURLLoad("pinch-viewport-input-field.html");
NavigateTo(base_url_ + "pinch-viewport-input-field.html");
@@ -924,14 +928,15 @@ TEST_P(VisualViewportTest, TestTextSelectionHandles) {
WebRect original_anchor;
WebRect original_focus;
- WebView()->SelectionBounds(original_anchor, original_focus);
+ WebView()->MainFrameWidget()->SelectionBounds(original_anchor,
+ original_focus);
WebView()->SetPageScaleFactor(2);
visual_viewport.SetLocation(FloatPoint(100, 400));
WebRect anchor;
WebRect focus;
- WebView()->SelectionBounds(anchor, focus);
+ WebView()->MainFrameWidget()->SelectionBounds(anchor, focus);
IntPoint expected(IntRect(original_anchor).Location());
expected.MoveBy(-FlooredIntPoint(visual_viewport.VisibleRect().Location()));
@@ -984,7 +989,7 @@ TEST_P(VisualViewportTest, TestSavedToHistoryItem) {
// Test restoring a HistoryItem properly restores the visual viewport's state.
TEST_P(VisualViewportTest, TestRestoredFromHistoryItem) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(200, 300));
+ WebView()->MainFrameWidget()->Resize(IntSize(200, 300));
RegisterMockedHttpURLLoad("200-by-300.html");
@@ -1011,7 +1016,7 @@ TEST_P(VisualViewportTest, TestRestoredFromHistoryItem) {
// viewport.
TEST_P(VisualViewportTest, TestRestoredFromLegacyHistoryItem) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(100, 150));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 150));
RegisterMockedHttpURLLoad("200-by-300-viewport.html");
@@ -1088,7 +1093,7 @@ TEST_P(VisualViewportTest,
DISABLED_TestWebFrameRangeAccountsForVisualViewportScroll) {
InitializeWithDesktopSettings();
WebView()->GetSettings()->SetDefaultFontSize(12);
- WebView()->Resize(WebSize(640, 480));
+ WebView()->MainFrameWidget()->Resize(WebSize(640, 480));
RegisterMockedHttpURLLoad("move_range.html");
NavigateTo(base_url_ + "move_range.html");
@@ -1104,7 +1109,7 @@ TEST_P(VisualViewportTest,
mainFrame->ExecuteScript(WebScriptSource("selectRange();"));
EXPECT_EQ("ir", mainFrame->SelectionAsText().Utf8());
- WebView()->SelectionBounds(base_rect, extent_rect);
+ WebView()->MainFrameWidget()->SelectionBounds(base_rect, extent_rect);
WebPoint initialPoint(base_rect.x, base_rect.y);
WebPoint endPoint(extent_rect.x, extent_rect.y);
@@ -1121,7 +1126,7 @@ TEST_P(VisualViewportTest,
// relayout.
TEST_P(VisualViewportTest, TestWebViewResizeCausesViewportConstrainedLayout) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(500, 300));
+ WebView()->MainFrameWidget()->Resize(IntSize(500, 300));
RegisterMockedHttpURLLoad("pinch-viewport-fixed-pos.html");
NavigateTo(base_url_ + "pinch-viewport-fixed-pos.html");
@@ -1155,7 +1160,7 @@ MATCHER_P2(ContextMenuAtLocation,
// viewport offset.
TEST_P(VisualViewportTest, TestContextMenuShownInCorrectLocation) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(200, 300));
+ WebView()->MainFrameWidget()->Resize(IntSize(200, 300));
RegisterMockedHttpURLLoad("200-by-300.html");
NavigateTo(base_url_ + "200-by-300.html");
@@ -1181,12 +1186,15 @@ TEST_P(VisualViewportTest, TestContextMenuShownInCorrectLocation) {
// Do a sanity check with no scale applied.
WebView()->MainFrameImpl()->SetClient(&mock_web_frame_client);
- WebView()->HandleInputEvent(WebCoalescedInputEvent(mouse_down_event));
- WebView()->HandleInputEvent(WebCoalescedInputEvent(mouse_up_event));
+ WebView()->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_down_event));
+ WebView()->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_up_event));
Mock::VerifyAndClearExpectations(&mock_web_frame_client);
mouse_down_event.button = WebMouseEvent::Button::kLeft;
- WebView()->HandleInputEvent(WebCoalescedInputEvent(mouse_down_event));
+ WebView()->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_down_event));
// Now pinch zoom into the page and move the visual viewport. The context menu
// should still appear at the location of the event, relative to the WebView.
@@ -1200,8 +1208,10 @@ TEST_P(VisualViewportTest, TestContextMenuShownInCorrectLocation) {
mouse_down_event.PositionInWidget().y)));
mouse_down_event.button = WebMouseEvent::Button::kRight;
- WebView()->HandleInputEvent(WebCoalescedInputEvent(mouse_down_event));
- WebView()->HandleInputEvent(WebCoalescedInputEvent(mouse_up_event));
+ WebView()->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_down_event));
+ WebView()->MainFrameWidget()->HandleInputEvent(
+ WebCoalescedInputEvent(mouse_up_event));
// Reset the old client so destruction can occur naturally.
WebView()->MainFrameImpl()->SetClient(old_client);
@@ -1210,7 +1220,7 @@ TEST_P(VisualViewportTest, TestContextMenuShownInCorrectLocation) {
// Test that the client is notified if page scroll events.
TEST_P(VisualViewportTest, TestClientNotifiedOfScrollEvents) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(200, 300));
+ WebView()->MainFrameWidget()->Resize(IntSize(200, 300));
RegisterMockedHttpURLLoad("200-by-300.html");
NavigateTo(base_url_ + "200-by-300.html");
@@ -1244,7 +1254,7 @@ TEST_P(VisualViewportTest, TestClientNotifiedOfScrollEvents) {
TEST_P(VisualViewportTest, ScrollIntoViewFractionalOffset) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(1000, 1000));
+ WebView()->MainFrameWidget()->Resize(IntSize(1000, 1000));
RegisterMockedHttpURLLoad("scroll-into-view.html");
NavigateTo(base_url_ + "scroll-into-view.html");
@@ -1333,8 +1343,9 @@ TEST_P(VisualViewportTest, TestBrowserControlsAdjustment) {
EXPECT_EQ(IntSize(1000, 900), frame_view.FrameRect().Size());
// Simulate bringing down the browser controls by 20px.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1, 1,
- cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, 1,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(FloatSize(500, 430), visual_viewport.VisibleRect().Size());
// Test that the scroll bounds are adjusted appropriately: the visual viewport
@@ -1351,9 +1362,9 @@ TEST_P(VisualViewportTest, TestBrowserControlsAdjustment) {
frame_view.LayoutViewport()->GetScrollOffset());
// Simulate bringing up the browser controls by 10.5px.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1,
- -10.5f / 20,
- cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, -10.5f / 20,
+ cc::BrowserControlsState::kBoth});
EXPECT_FLOAT_SIZE_EQ(FloatSize(500, 440.5f),
visual_viewport.VisibleRect().Size());
@@ -1387,8 +1398,9 @@ TEST_P(VisualViewportTest, TestBrowserControlsAdjustmentWithScale) {
// Simulate bringing down the browser controls by 20px. Since we're zoomed in,
// the browser controls take up half as much space (in document-space) than
// they do at an unzoomed level.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1, 1,
- cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, 1,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(FloatSize(250, 215), visual_viewport.VisibleRect().Size());
// Test that the scroll bounds are adjusted appropriately.
@@ -1404,8 +1416,9 @@ TEST_P(VisualViewportTest, TestBrowserControlsAdjustmentWithScale) {
// Scale back out, LocalFrameView max scroll shouldn't have changed. Visual
// viewport should be moved up to accomodate larger view.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 0.5f,
- 0, cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 0.5f, 0,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(1, visual_viewport.Scale());
EXPECT_EQ(expected, frame_view.LayoutViewport()->GetScrollOffset());
frame_view.LayoutViewport()->ScrollBy(ScrollOffset(10000, 10000),
@@ -1417,13 +1430,15 @@ TEST_P(VisualViewportTest, TestBrowserControlsAdjustmentWithScale) {
EXPECT_EQ(FloatSize(500, 860 - 430), visual_viewport.GetScrollOffset());
// Scale out, use a scale that causes fractional rects.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 0.8f,
- -1, cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 0.8f, -1,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(FloatSize(625, 562.5), visual_viewport.VisibleRect().Size());
// Bring out the browser controls by 11
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1,
- 11 / 20.f, cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, 11 / 20.f,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(FloatSize(625, 548.75), visual_viewport.VisibleRect().Size());
// Ensure max scroll offsets are updated properly.
@@ -1588,9 +1603,11 @@ TEST_P(VisualViewportTest, TestBrowserControlsShrinkAdjustmentAndResize) {
// the main frame's scroll offset. crbug.com/428193.
TEST_P(VisualViewportTest, TestTopControlHidingResizeDoesntClampMainFrame) {
InitializeWithAndroidSettings();
- WebView()->ResizeWithBrowserControls(WebView()->Size(), 500, 0, false);
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1, 1,
- cc::BrowserControlsState::kBoth});
+ WebView()->ResizeWithBrowserControls(WebView()->MainFrameWidget()->Size(),
+ 500, 0, false);
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, 1,
+ cc::BrowserControlsState::kBoth});
WebView()->ResizeWithBrowserControls(WebSize(1000, 1000), 500, 0, true);
RegisterMockedHttpURLLoad("content-width-1000.html");
@@ -1600,8 +1617,9 @@ TEST_P(VisualViewportTest, TestTopControlHidingResizeDoesntClampMainFrame) {
// Scroll the LocalFrameView to the bottom of the page but "hide" the browser
// controls on the compositor side so the max scroll position should account
// for the full viewport height.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1, -1,
- cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, -1,
+ cc::BrowserControlsState::kBoth});
LocalFrameView& frame_view = *WebView()->MainFrameImpl()->GetFrameView();
frame_view.LayoutViewport()->SetScrollOffset(ScrollOffset(0, 10000),
kProgrammaticScroll);
@@ -1621,8 +1639,11 @@ static void configureHiddenScrollbarsSettings(WebSettings* settings) {
// layer when hideScrollbars WebSetting is true.
TEST_P(VisualViewportTest,
TestScrollbarsNotAttachedWhenHideScrollbarsSettingIsTrue) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
InitializeWithAndroidSettings(configureHiddenScrollbarsSettings);
- WebView()->Resize(IntSize(100, 150));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 150));
NavigateTo("about:blank");
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
@@ -1634,8 +1655,11 @@ TEST_P(VisualViewportTest,
// layer when hideScrollbars WebSetting is false.
TEST_P(VisualViewportTest,
TestScrollbarsAttachedWhenHideScrollbarsSettingIsFalse) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(100, 150));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 150));
NavigateTo("about:blank");
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
@@ -1648,11 +1672,11 @@ TEST_P(VisualViewportTest,
// Tests that the layout viewport's scroll layer bounds are updated in a
// compositing change update. crbug.com/423188.
TEST_P(VisualViewportTest, TestChangingContentSizeAffectsScrollBounds) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(100, 150));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 150));
RegisterMockedHttpURLLoad("content-width-1000.html");
NavigateTo(base_url_ + "content-width-1000.html");
@@ -1688,14 +1712,14 @@ TEST_P(VisualViewportTest, ResizeVisualViewportStaysWithinOuterViewport) {
NavigateTo("about:blank");
UpdateAllLifecyclePhases();
- WebView()->ResizeVisualViewport(IntSize(100, 100));
+ WebView()->MainFrameWidget()->ResizeVisualViewport(IntSize(100, 100));
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
visual_viewport.Move(ScrollOffset(0, 100));
EXPECT_EQ(100, visual_viewport.GetScrollOffset().Height());
- WebView()->ResizeVisualViewport(IntSize(100, 200));
+ WebView()->MainFrameWidget()->ResizeVisualViewport(IntSize(100, 200));
EXPECT_EQ(0, visual_viewport.GetScrollOffset().Height());
}
@@ -1703,7 +1727,7 @@ TEST_P(VisualViewportTest, ResizeVisualViewportStaysWithinOuterViewport) {
TEST_P(VisualViewportTest, ElementBoundsInViewportSpaceAccountsForViewport) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(500, 800));
+ WebView()->MainFrameWidget()->Resize(IntSize(500, 800));
RegisterMockedHttpURLLoad("pinch-viewport-input-field.html");
NavigateTo(base_url_ + "pinch-viewport-input-field.html");
@@ -1732,7 +1756,7 @@ TEST_P(VisualViewportTest, ElementBoundsInViewportSpaceAccountsForViewport) {
TEST_P(VisualViewportTest, ElementVisibleBoundsInVisualViewport) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(640, 1080));
+ WebView()->MainFrameWidget()->Resize(IntSize(640, 1080));
RegisterMockedHttpURLLoad("viewport-select.html");
NavigateTo(base_url_ + "viewport-select.html");
@@ -1748,8 +1772,8 @@ TEST_P(VisualViewportTest, ElementVisibleBoundsInVisualViewport) {
// Test that the various window.scroll and document.body.scroll properties and
// methods don't change with the visual viewport.
TEST_P(VisualViewportTest, visualViewportIsInert) {
- WebViewImpl* web_view_impl = helper_.Initialize(nullptr, nullptr, nullptr,
- &ConfigureAndroidCompositing);
+ WebViewImpl* web_view_impl =
+ helper_.InitializeWithSettings(&ConfigureAndroidCompositing);
web_view_impl->MainFrameWidget()->Resize(IntSize(200, 300));
@@ -1830,7 +1854,7 @@ TEST_P(VisualViewportTest, visualViewportIsInert) {
TEST_P(VisualViewportTest, TestMainFrameInitializationSizing) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(100, 200));
+ WebView()->MainFrameWidget()->Resize(IntSize(100, 200));
RegisterMockedHttpURLLoad("content-width-1000-min-scale.html");
NavigateTo(base_url_ + "content-width-1000-min-scale.html");
@@ -1849,7 +1873,7 @@ TEST_P(VisualViewportTest, TestMainFrameInitializationSizing) {
// Tests that the maximum scroll offset of the viewport can be fractional.
TEST_P(VisualViewportTest, FractionalMaxScrollOffset) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(101, 201));
+ WebView()->MainFrameWidget()->Resize(IntSize(101, 201));
NavigateTo("about:blank");
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
@@ -1868,15 +1892,15 @@ TEST_P(VisualViewportTest, FractionalMaxScrollOffset) {
// ScrollAnimatorBase class.
TEST_P(VisualViewportTest, SlowScrollAfterImplScroll) {
InitializeWithDesktopSettings();
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
NavigateTo("about:blank");
VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
// Apply some scroll and scale from the impl-side.
- WebView()->ApplyViewportChanges({gfx::ScrollOffset(300, 200),
- gfx::Vector2dF(0, 0), 2, 0,
- cc::BrowserControlsState::kBoth});
+ WebView()->MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(300, 200), gfx::Vector2dF(0, 0), 2, 0,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(FloatSize(300, 200), visual_viewport.GetScrollOffset());
@@ -1941,7 +1965,7 @@ TEST_P(VisualViewportTest, AccessibilityHitTestWhileZoomedIn) {
// Tests that the maximum scroll offset of the viewport can be fractional.
TEST_P(VisualViewportTest, TestCoordinateTransforms) {
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
RegisterMockedHttpURLLoad("content-width-1000.html");
NavigateTo(base_url_ + "content-width-1000.html");
@@ -1998,7 +2022,7 @@ TEST_P(VisualViewportTest, TestCoordinateTransforms) {
TEST_P(VisualViewportTest, WindowDimensionsOnLoad) {
InitializeWithAndroidSettings();
RegisterMockedHttpURLLoad("window_dimensions.html");
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
NavigateTo(base_url_ + "window_dimensions.html");
Element* output = GetFrame()->GetDocument()->getElementById("output");
@@ -2014,7 +2038,7 @@ TEST_P(VisualViewportTest, WindowDimensionsOnLoad) {
TEST_P(VisualViewportTest, WindowDimensionsOnLoadWideContent) {
InitializeWithAndroidSettings();
RegisterMockedHttpURLLoad("window_dimensions_wide_div.html");
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
NavigateTo(base_url_ + "window_dimensions_wide_div.html");
Element* output = GetFrame()->GetDocument()->getElementById("output");
@@ -2035,7 +2059,7 @@ TEST_P(VisualViewportTest, ResizeWithScrollAnchoring) {
kProgrammaticScroll);
UpdateAllLifecyclePhases();
- WebView()->Resize(IntSize(800, 300));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 300));
EXPECT_EQ(ScrollOffset(700, 200),
frame_view.LayoutViewport()->GetScrollOffset());
}
@@ -2046,7 +2070,7 @@ TEST_P(VisualViewportTest, ResizeAnchoringWithRootScroller) {
ScopedSetRootScrollerForTest root_scroller(true);
InitializeWithAndroidSettings();
- WebView()->Resize(IntSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 600));
RegisterMockedHttpURLLoad("root-scroller-div.html");
NavigateTo(base_url_ + "root-scroller-div.html");
@@ -2064,7 +2088,7 @@ TEST_P(VisualViewportTest, ResizeAnchoringWithRootScroller) {
VisualViewport& visual_viewport = WebView()->GetPage()->GetVisualViewport();
visual_viewport.SetScrollOffset(ScrollOffset(0, 400), kProgrammaticScroll);
- WebView()->Resize(IntSize(800, 500));
+ WebView()->MainFrameWidget()->Resize(IntSize(800, 500));
EXPECT_EQ(ScrollOffset(), frame_view.LayoutViewport()->GetScrollOffset());
}
@@ -2089,7 +2113,7 @@ TEST_P(VisualViewportTest, RotationAnchoringWithRootScroller) {
scroller->setScrollTop(800);
- WebView()->Resize(IntSize(600, 800));
+ WebView()->MainFrameWidget()->Resize(IntSize(600, 800));
EXPECT_EQ(ScrollOffset(), frame_view.LayoutViewport()->GetScrollOffset());
EXPECT_EQ(600, scroller->scrollTop());
@@ -2098,11 +2122,11 @@ TEST_P(VisualViewportTest, RotationAnchoringWithRootScroller) {
// Make sure a composited background-attachment:fixed background gets resized
// by browser controls.
TEST_P(VisualViewportTest, ResizeCompositedAndFixedBackground) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
- WebViewImpl* web_view_impl = helper_.Initialize(nullptr, nullptr, nullptr,
- &ConfigureAndroidCompositing);
+ WebViewImpl* web_view_impl =
+ helper_.InitializeWithSettings(&ConfigureAndroidCompositing);
int page_width = 640;
int page_height = 480;
@@ -2172,11 +2196,11 @@ static void ConfigureAndroidNonCompositing(WebSettings* settings) {
// Make sure a non-composited background-attachment:fixed background gets
// resized by browser controls.
TEST_P(VisualViewportTest, ResizeNonCompositedAndFixedBackground) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
- WebViewImpl* web_view_impl = helper_.Initialize(
- nullptr, nullptr, nullptr, &ConfigureAndroidNonCompositing);
+ WebViewImpl* web_view_impl =
+ helper_.InitializeWithSettings(&ConfigureAndroidNonCompositing);
int page_width = 640;
int page_height = 480;
@@ -2245,8 +2269,8 @@ TEST_P(VisualViewportTest, ResizeNonCompositedAndFixedBackground) {
// Make sure a browser control resize with background-attachment:not-fixed
// background doesn't cause invalidation or layout.
TEST_P(VisualViewportTest, ResizeNonFixedBackgroundNoLayoutOrInvalidation) {
- WebViewImpl* web_view_impl = helper_.Initialize(nullptr, nullptr, nullptr,
- &ConfigureAndroidCompositing);
+ WebViewImpl* web_view_impl =
+ helper_.InitializeWithSettings(&ConfigureAndroidCompositing);
int page_width = 640;
int page_height = 480;
@@ -2297,7 +2321,7 @@ TEST_P(VisualViewportTest, ResizeNonFixedBackgroundNoLayoutOrInvalidation) {
ASSERT_EQ(page_width, document->View()->GetLayoutSize().Width());
ASSERT_EQ(smallest_height, document->View()->GetLayoutSize().Height());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// No invalidations should have occurred on either main layer or scrolling
// contents layer.
EXPECT_FALSE(MainGraphicsLayerHasRasterInvalidations(document));
@@ -2308,8 +2332,8 @@ TEST_P(VisualViewportTest, ResizeNonFixedBackgroundNoLayoutOrInvalidation) {
}
TEST_P(VisualViewportTest, InvalidateLayoutViewWhenDocumentSmallerThanView) {
- WebViewImpl* web_view_impl = helper_.Initialize(nullptr, nullptr, nullptr,
- &ConfigureAndroidCompositing);
+ WebViewImpl* web_view_impl =
+ helper_.InitializeWithSettings(&ConfigureAndroidCompositing);
int page_width = 320;
int page_height = 590;
@@ -2333,7 +2357,7 @@ TEST_P(VisualViewportTest, InvalidateLayoutViewWhenDocumentSmallerThanView) {
ASSERT_EQ(page_width, document->View()->GetLayoutSize().Width());
ASSERT_EQ(page_height, document->View()->GetLayoutSize().Height());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// Incremental raster invalidation is needed because the resize exposes
// unpainted area of background.
EXPECT_FALSE(MainGraphicsLayerHasRasterInvalidations(document));
@@ -2353,7 +2377,7 @@ TEST_P(VisualViewportTest, InvalidateLayoutViewWhenDocumentSmallerThanView) {
web_view_impl->ResizeWithBrowserControls(WebSize(page_width, page_height),
browser_controls_height, 0, false);
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// No raster invalidation is needed because of no change within the root
// scrolling layer.
EXPECT_FALSE(MainGraphicsLayerHasRasterInvalidations(document));
@@ -2465,7 +2489,7 @@ class VisualViewportSimTest : public SimTest {
// Test that we correcty size the visual viewport's scrolling contents layer
// when the layout viewport is smaller.
TEST_F(VisualViewportSimTest, ScrollingContentsSmallerThanContainer) {
- WebView().Resize(WebSize(400, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2496,8 +2520,9 @@ TEST_F(VisualViewportSimTest, ScrollingContentsSmallerThanContainer) {
visual_viewport.GetScrollNode()->ContentsSize());
}
- WebView().ApplyViewportChanges({gfx::ScrollOffset(1, 1), gfx::Vector2dF(), 2,
- 1, cc::BrowserControlsState::kBoth});
+ WebView().MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(1, 1), gfx::Vector2dF(), 2, 1,
+ cc::BrowserControlsState::kBoth});
EXPECT_EQ(gfx::Size(400, 600), visual_viewport.ContainerLayer()->Size());
EXPECT_EQ(gfx::Size(400, 600),
visual_viewport.ContainerLayer()->CcLayer()->bounds());
@@ -2513,5 +2538,27 @@ TEST_F(VisualViewportSimTest, ScrollingContentsSmallerThanContainer) {
}
}
+TEST_P(VisualViewportTest, DeviceEmulationTransformNode) {
+ InitializeWithAndroidSettings();
+
+ TransformationMatrix emulation_transform = TransformationMatrix();
+ emulation_transform.Translate(314, 159);
+ WebView()->SetDeviceEmulationTransform(emulation_transform);
+
+ WebView()->MainFrameWidget()->Resize(IntSize(400, 400));
+ NavigateTo("about:blank");
+ UpdateAllLifecyclePhases();
+
+ VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
+ EXPECT_EQ(visual_viewport.GetDeviceEmulationTransformNode()->Matrix(),
+ emulation_transform);
+
+ // Set an identity device emulation transform and ensure the transform
+ // paint property node is cleared.
+ WebView()->SetDeviceEmulationTransform(TransformationMatrix());
+ UpdateAllLifecyclePhases();
+ EXPECT_EQ(visual_viewport.GetDeviceEmulationTransformNode(), nullptr);
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 6dc35ef78f1..2267de355f5 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -286,6 +286,31 @@ WebDragOperation WebFrameWidgetBase::DragTargetDragEnterOrOver(
return drag_operation_;
}
+void WebFrameWidgetBase::SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) {
+ if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
+ return;
+
+ Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
+ scroll_latched_element_id);
+ if (target_node) {
+ target_node->GetDocument().EnqueueOverscrollEventForNode(
+ target_node, overscroll_delta.x(), overscroll_delta.y());
+ }
+}
+
+void WebFrameWidgetBase::SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) {
+ if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
+ return;
+
+ Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
+ scroll_latched_element_id);
+ if (target_node)
+ target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
+}
+
WebFloatPoint WebFrameWidgetBase::ViewportToRootFrame(
const WebFloatPoint& point_in_viewport) const {
return GetPage()->GetVisualViewport().ViewportToRootFrame(point_in_viewport);
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h
index 85f7be0fe79..f2b86f7ae9a 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h
@@ -56,7 +56,6 @@ class CORE_EXPORT WebFrameWidgetBase
// Called once the local root is bound via |BindLocalRoot()|.
virtual void Initialize() = 0;
virtual bool ForSubframe() const = 0;
- virtual void ScheduleAnimation() = 0;
virtual void IntrinsicSizingInfoChanged(const IntrinsicSizingInfo&) {}
virtual base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
EnsureCompositorMutatorDispatcher(
@@ -98,6 +97,11 @@ class CORE_EXPORT WebFrameWidgetBase
const WebFloatPoint& screen_point,
WebDragOperation) override;
void DragSourceSystemDragEnded() override;
+ void SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) override;
+ void SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) override;
WebLocalFrame* FocusedWebLocalFrameInWidget() const override;
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index fa541de5f81..f927f69844e 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -37,7 +37,6 @@
#include "base/optional.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
#include "third_party/blink/public/web/web_autofill_client.h"
@@ -160,10 +159,6 @@ WebFrameWidgetImpl::WebFrameWidgetImpl(WebWidgetClient& client)
is_accelerated_compositing_active_(false),
layer_tree_view_closed_(false),
suppress_next_keypress_event_(false),
- background_color_override_enabled_(false),
- background_color_override_(Color::kTransparent),
- base_background_color_override_enabled_(false),
- base_background_color_override_(Color::kTransparent),
ime_accept_events_(true),
self_keep_alive_(this) {}
@@ -258,7 +253,7 @@ void WebFrameWidgetImpl::ResizeVisualViewport(const WebSize& new_size) {
// both the WebViewImpl size and the Page's VisualViewport. If there are
// multiple OOPIFs on a page, this will currently be set redundantly by
// each of them. See https://crbug.com/599688.
- View()->Resize(new_size);
+ View()->MainFrameWidget()->Resize(new_size);
View()->DidUpdateFullscreenSize();
}
@@ -277,11 +272,11 @@ void WebFrameWidgetImpl::UpdateMainFrameLayoutSize() {
}
void WebFrameWidgetImpl::DidEnterFullscreen() {
- View()->DidEnterFullscreen();
+ View()->MainFrameWidget()->DidEnterFullscreen();
}
void WebFrameWidgetImpl::DidExitFullscreen() {
- View()->DidExitFullscreen();
+ View()->MainFrameWidget()->DidExitFullscreen();
}
void WebFrameWidgetImpl::SetSuppressFrameRequestsWorkaroundFor704763Only(
@@ -324,7 +319,6 @@ void WebFrameWidgetImpl::UpdateLifecycle(LifecycleUpdate requested_update,
LocalRootImpl()->GetFrame()->GetDocument()->Lifecycle());
PageWidgetDelegate::UpdateLifecycle(*GetPage(), *LocalRootImpl()->GetFrame(),
requested_update, reason);
- UpdateLayerTreeBackgroundColor();
}
void WebFrameWidgetImpl::PaintContent(cc::PaintCanvas* canvas,
@@ -343,58 +337,6 @@ void WebFrameWidgetImpl::UpdateLayerTreeViewport() {
1, View()->MinimumPageScaleFactor(), View()->MaximumPageScaleFactor());
}
-void WebFrameWidgetImpl::UpdateLayerTreeBackgroundColor() {
- if (!layer_tree_view_)
- return;
-
- SkColor color = BackgroundColor();
- layer_tree_view_->SetBackgroundColor(color);
-}
-
-void WebFrameWidgetImpl::SetBackgroundColorOverride(SkColor color) {
- background_color_override_enabled_ = true;
- background_color_override_ = color;
- UpdateLayerTreeBackgroundColor();
-}
-
-void WebFrameWidgetImpl::ClearBackgroundColorOverride() {
- background_color_override_enabled_ = false;
- UpdateLayerTreeBackgroundColor();
-}
-
-void WebFrameWidgetImpl::SetBaseBackgroundColorOverride(SkColor color) {
- if (base_background_color_override_enabled_ &&
- base_background_color_override_ == color) {
- return;
- }
-
- base_background_color_override_enabled_ = true;
- base_background_color_override_ = color;
- // Force lifecycle update to ensure we're good to call
- // LocalFrameView::setBaseBackgroundColor().
- LocalRootImpl()
- ->GetFrameView()
- ->UpdateLifecycleToCompositingCleanPlusScrolling();
- UpdateBaseBackgroundColor();
-}
-
-void WebFrameWidgetImpl::ClearBaseBackgroundColorOverride() {
- if (!base_background_color_override_enabled_)
- return;
-
- base_background_color_override_enabled_ = false;
- // Force lifecycle update to ensure we're good to call
- // LocalFrameView::setBaseBackgroundColor().
- LocalRootImpl()
- ->GetFrameView()
- ->UpdateLifecycleToCompositingCleanPlusScrolling();
- UpdateBaseBackgroundColor();
-}
-
-void WebFrameWidgetImpl::LayoutAndPaintAsync(base::OnceClosure callback) {
- layer_tree_view_->LayoutAndPaintAsync(std::move(callback));
-}
-
void WebFrameWidgetImpl::CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) {
layer_tree_view_->CompositeAndReadbackAsync(std::move(callback));
@@ -533,25 +475,6 @@ void WebFrameWidgetImpl::SetCursorVisibilityState(bool is_visible) {
GetPage()->SetIsCursorVisible(is_visible);
}
-Color WebFrameWidgetImpl::BaseBackgroundColor() const {
- return base_background_color_override_enabled_
- ? base_background_color_override_
- : base_background_color_;
-}
-
-void WebFrameWidgetImpl::SetBaseBackgroundColor(SkColor color) {
- if (base_background_color_ == color)
- return;
-
- base_background_color_ = color;
- UpdateBaseBackgroundColor();
-}
-
-void WebFrameWidgetImpl::UpdateBaseBackgroundColor() {
- LocalRootImpl()->GetFrameView()->SetBaseBackgroundColor(
- BaseBackgroundColor());
-}
-
WebInputMethodController*
WebFrameWidgetImpl::GetActiveWebInputMethodController() const {
WebLocalFrameImpl* local_frame =
@@ -575,17 +498,6 @@ bool WebFrameWidgetImpl::ScrollFocusedEditableElementIntoView() {
}
void WebFrameWidgetImpl::Initialize() {
- if (LocalRoot()->Parent())
- SetBackgroundColorOverride(Color::kTransparent);
-}
-
-void WebFrameWidgetImpl::ScheduleAnimation() {
- if (layer_tree_view_) {
- layer_tree_view_->SetNeedsBeginFrame();
- return;
- }
- DCHECK(Client());
- Client()->ScheduleAnimation();
}
void WebFrameWidgetImpl::IntrinsicSizingInfoChanged(
@@ -668,15 +580,6 @@ void WebFrameWidgetImpl::SetFocus(bool enable) {
}
}
-SkColor WebFrameWidgetImpl::BackgroundColor() const {
- if (background_color_override_enabled_)
- return background_color_override_;
- if (!LocalRootImpl()->GetFrameView())
- return base_background_color_;
- LocalFrameView* view = LocalRootImpl()->GetFrameView();
- return view->DocumentBackgroundColor().Rgb();
-}
-
bool WebFrameWidgetImpl::SelectionBounds(WebRect& anchor_web,
WebRect& focus_web) const {
const LocalFrame* local_frame = FocusedLocalFrameInWidget();
@@ -768,7 +671,7 @@ void WebFrameWidgetImpl::HandleMouseDown(LocalFrame& main_frame,
scoped_refptr<WebPagePopupImpl> page_popup;
if (event.button == WebMouseEvent::Button::kLeft) {
page_popup = view_impl->GetPagePopup();
- view_impl->HidePopups();
+ view_impl->CancelPagePopup();
}
// Take capture on a mouse down on a plugin so we can send it mouse events.
@@ -802,7 +705,7 @@ void WebFrameWidgetImpl::HandleMouseDown(LocalFrame& main_frame,
view_impl->GetPagePopup()->HasSamePopupClient(page_popup.get())) {
// That click triggered a page popup that is the same as the one we just
// closed. It needs to be closed.
- view_impl->HidePopups();
+ view_impl->CancelPagePopup();
}
// Dispatch the contextmenu event regardless of if the click was swallowed.
@@ -848,7 +751,7 @@ void WebFrameWidgetImpl::MouseContextMenu(const WebMouseEvent& event) {
{
ContextMenuAllowedScope scope;
target_local_frame->GetEventHandler().SendContextMenuEvent(
- transformed_event, nullptr);
+ transformed_event);
}
// Actually showing the context menu is handled by the ContextMenuClient
// implementation...
@@ -869,8 +772,7 @@ void WebFrameWidgetImpl::HandleMouseUp(LocalFrame& main_frame,
WebInputEventResult WebFrameWidgetImpl::HandleMouseWheel(
LocalFrame& frame,
const WebMouseWheelEvent& event) {
-
- View()->HidePopups();
+ View()->CancelPagePopup();
return PageWidgetEventHandler::HandleMouseWheel(frame, event);
}
@@ -892,15 +794,15 @@ WebInputEventResult WebFrameWidgetImpl::HandleGestureEvent(
// Touch pinch zoom and scroll on the page (outside of a popup) must hide
// the popup. In case of a touch scroll or pinch zoom, this function is
// called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE.
- // When we close a popup because of a GestureTapDown, we also save it so
- // we can prevent the following GestureTap from immediately reopening the
- // same popup.
- view_impl->SetLastHiddenPagePopup(view_impl->GetPagePopup());
- View()->HidePopups();
- FALLTHROUGH;
- case WebInputEvent::kGestureTapCancel:
- View()->SetLastHiddenPagePopup(nullptr);
+ // WebViewImpl takes additional steps to avoid the following GestureTap
+ // from re-opening the popup being closed here, but since GestureTap will
+ // unconditionally close the current popup here, it is not used/needed.
+ // TODO(wjmaclean): We should maybe mirror what WebViewImpl does, the
+ // HandleGestureEvent() needs to happen inside or before the GestureTap
+ // case to do so.
+ View()->CancelPagePopup();
break;
+ case WebInputEvent::kGestureTapCancel:
case WebInputEvent::kGestureShowPress:
break;
case WebInputEvent::kGestureDoubleTap:
@@ -1087,6 +989,10 @@ void WebFrameWidgetImpl::SetLayerTreeView(WebLayerTreeView* layer_tree_view) {
// be moved from WebViewImpl into WebFrameWidget and used for all local
// frame roots. https://crbug.com/712794
layer_tree_view_->HeuristicsForGpuRasterizationUpdated(true);
+
+ // WebFrameWidgetImpl is used for child frames, which always have a
+ // transparent background color.
+ layer_tree_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
}
void WebFrameWidgetImpl::SetIsAcceleratedCompositingActive(bool active) {
@@ -1105,7 +1011,6 @@ void WebFrameWidgetImpl::SetIsAcceleratedCompositingActive(bool active) {
TRACE_EVENT0("blink",
"WebViewImpl::setIsAcceleratedCompositingActive(true)");
layer_tree_view_->SetRootLayer(root_layer_);
- UpdateLayerTreeBackgroundColor();
UpdateLayerTreeViewport();
is_accelerated_compositing_active_ = true;
}
@@ -1166,6 +1071,11 @@ HitTestResult WebFrameWidgetImpl::CoreHitTestResultAt(
return HitTestResultForRootFramePos(point_in_root_frame);
}
+void WebFrameWidgetImpl::ZoomToFindInPageRect(
+ const WebRect& rect_in_root_frame) {
+ Client()->ZoomToFindInPageRectInMainFrame(rect_in_root_frame);
+}
+
HitTestResult WebFrameWidgetImpl::HitTestResultForRootFramePos(
const LayoutPoint& pos_in_root_frame) {
LayoutPoint doc_point(
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
index 53ea0234dc7..622592b3f59 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -89,7 +89,6 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
void UpdateLifecycle(LifecycleUpdate requested_update,
LifecycleUpdateReason reason) override;
void PaintContent(cc::PaintCanvas*, const WebRect&) override;
- void LayoutAndPaintAsync(base::OnceClosure callback) override;
void CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) override;
void ThemeChanged() override;
@@ -101,7 +100,6 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
void ApplyViewportChanges(const ApplyViewportChangesArgs&) override;
void MouseCaptureLost() override;
void SetFocus(bool enable) override;
- SkColor BackgroundColor() const override;
bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
bool IsAcceleratedCompositingActive() const override;
void WillCloseLayerTreeView() override;
@@ -113,11 +111,6 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
WebURL GetURLForDebugTrace() override;
// WebFrameWidget implementation.
- void SetBackgroundColorOverride(SkColor) override;
- void ClearBackgroundColorOverride() override;
- void SetBaseBackgroundColorOverride(SkColor) override;
- void ClearBaseBackgroundColorOverride() override;
- void SetBaseBackgroundColor(SkColor) override;
WebInputMethodController* GetActiveWebInputMethodController() const override;
bool ScrollFocusedEditableElementIntoView() override;
@@ -138,7 +131,6 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
void Initialize() override;
void SetLayerTreeView(WebLayerTreeView*) override;
bool ForSubframe() const override { return true; }
- void ScheduleAnimation() override;
void IntrinsicSizingInfoChanged(const IntrinsicSizingInfo&) override;
void DidCreateLocalRootView() override;
@@ -147,6 +139,7 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
WebLayerTreeView* GetLayerTreeView() const override;
CompositorAnimationHost* AnimationHost() const override;
HitTestResult CoreHitTestResultAt(const gfx::Point&) override;
+ void ZoomToFindInPageRect(const WebRect& rect_in_root_frame) override;
// Exposed for the purpose of overriding device metrics.
void SendResizeEventAndRepaint();
@@ -160,8 +153,6 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
return root_graphics_layer_;
};
- Color BaseBackgroundColor() const;
-
void Trace(blink::Visitor*) override;
private:
@@ -173,8 +164,6 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
void SetIsAcceleratedCompositingActive(bool);
void UpdateLayerTreeViewport();
- void UpdateLayerTreeBackgroundColor();
- void UpdateBaseBackgroundColor();
// PageWidgetEventHandler functions
void HandleMouseLeave(LocalFrame&, const WebMouseEvent&) override;
@@ -222,18 +211,11 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase,
bool did_suspend_parsing_ = false;
- bool background_color_override_enabled_;
- SkColor background_color_override_;
- bool base_background_color_override_enabled_;
- SkColor base_background_color_override_;
-
// TODO(ekaramad): Can we remove this and make sure IME events are not called
// when there is no page focus?
// Represents whether or not this object should process incoming IME events.
bool ime_accept_events_;
- SkColor base_background_color_;
-
SelfKeepAlive<WebFrameWidgetImpl> self_keep_alive_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 6f286a3e400..5a9963e8ed5 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -94,13 +94,13 @@
#include "base/macros.h"
#include "build/build_config.h"
-
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/platform/interface_registry.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_double_size.h"
#include "third_party/blink/public/platform/web_float_point.h"
#include "third_party/blink/public/platform/web_float_rect.h"
+#include "third_party/blink/public/platform/web_isolated_world_info.h"
#include "third_party/blink/public/platform/web_point.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_security_origin.h"
@@ -167,8 +167,10 @@
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/writing_direction.h"
+#include "third_party/blink/renderer/core/events/after_print_event.h"
+#include "third_party/blink/renderer/core/events/before_print_event.h"
+#include "third_party/blink/renderer/core/events/portal_activate_event.h"
#include "third_party/blink/renderer/core/exported/local_frame_client_impl.h"
-#include "third_party/blink/renderer/core/exported/shared_worker_repository_client_impl.h"
#include "third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h"
#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
#include "third_party/blink/renderer/core/exported/web_document_loader_impl.h"
@@ -204,6 +206,8 @@
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html/plugin_document.h"
+#include "third_party/blink/renderer/core/html/portal/document_portals.h"
+#include "third_party/blink/renderer/core/html/portal/html_portal_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
@@ -246,7 +250,6 @@
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
-#include "third_party/blink/renderer/platform/loader/fetch/substitute_data.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -402,8 +405,8 @@ class ChromePrintContext : public PrintContext {
PaintRecordBuilder builder(&context.Canvas()->getMetaData(), &context);
- frame_view->PaintContents(builder.Context(), kGlobalPaintNormalPhase,
- page_rect);
+ frame_view->PaintContentsOutsideOfLifecycle(
+ builder.Context(), kGlobalPaintNormalPhase, CullRect(page_rect));
{
ScopedPaintChunkProperties scoped_paint_chunk_properties(
builder.Context().GetPaintController(), property_tree_state, builder,
@@ -578,12 +581,6 @@ void WebLocalFrameImpl::SetContentSettingsClient(
content_settings_client_ = client;
}
-void WebLocalFrameImpl::SetSharedWorkerRepositoryClient(
- WebSharedWorkerRepositoryClient* client) {
- shared_worker_repository_client_ =
- SharedWorkerRepositoryClientImpl::Create(client);
-}
-
ScrollableArea* WebLocalFrameImpl::LayoutViewport() const {
if (LocalFrameView* view = GetFrameView())
return view->LayoutViewport();
@@ -663,9 +660,10 @@ bool WebLocalFrameImpl::IsAdSubframe() const {
return GetFrame()->IsAdSubframe();
}
-void WebLocalFrameImpl::SetIsAdSubframe() {
+void WebLocalFrameImpl::SetIsAdSubframe(
+ blink::mojom::AdFrameType ad_frame_type) {
DCHECK(GetFrame());
- GetFrame()->SetIsAdSubframe();
+ GetFrame()->SetIsAdSubframe(ad_frame_type);
}
void WebLocalFrameImpl::DispatchUnloadEvent() {
@@ -691,7 +689,7 @@ void WebLocalFrameImpl::ExecuteScriptInIsolatedWorld(
int world_id,
const WebScriptSource& source_in) {
DCHECK(GetFrame());
- CHECK_GT(world_id, 0);
+ CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit);
// Note: An error event in an isolated world will never be dispatched to
@@ -706,7 +704,7 @@ WebLocalFrameImpl::ExecuteScriptInIsolatedWorldAndReturnValue(
int world_id,
const WebScriptSource& source_in) {
DCHECK(GetFrame());
- CHECK_GT(world_id, 0);
+ CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit);
// Note: An error event in an isolated world will never be dispatched to
@@ -715,28 +713,23 @@ WebLocalFrameImpl::ExecuteScriptInIsolatedWorldAndReturnValue(
world_id, source_in, KURL(), SanitizeScriptErrors::kDoNotSanitize);
}
-void WebLocalFrameImpl::SetIsolatedWorldSecurityOrigin(
- int world_id,
- const WebSecurityOrigin& security_origin) {
+void WebLocalFrameImpl::SetIsolatedWorldInfo(int world_id,
+ const WebIsolatedWorldInfo& info) {
DCHECK(GetFrame());
- DOMWrapperWorld::SetIsolatedWorldSecurityOrigin(
- world_id,
- security_origin.Get() ? security_origin.Get()->IsolatedCopy() : nullptr);
-}
+ CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
+ CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit);
-void WebLocalFrameImpl::SetIsolatedWorldContentSecurityPolicy(
- int world_id,
- const WebString& policy) {
- DCHECK(GetFrame());
- IsolatedWorldCSP::Get().SetContentSecurityPolicy(world_id, policy);
-}
+ scoped_refptr<SecurityOrigin> security_origin =
+ info.security_origin.Get() ? info.security_origin.Get()->IsolatedCopy()
+ : nullptr;
-void WebLocalFrameImpl::SetIsolatedWorldHumanReadableName(
- int world_id,
- const WebString& human_readable_name) {
- DCHECK(GetFrame());
+ CHECK(info.content_security_policy.IsNull() || security_origin);
+
+ DOMWrapperWorld::SetIsolatedWorldSecurityOrigin(world_id, security_origin);
DOMWrapperWorld::SetNonMainWorldHumanReadableName(world_id,
- human_readable_name);
+ info.human_readable_name);
+ IsolatedWorldCSP::Get().SetContentSecurityPolicy(
+ world_id, info.content_security_policy, security_origin);
}
void WebLocalFrameImpl::AddMessageToConsole(const WebConsoleMessage& message) {
@@ -744,16 +737,16 @@ void WebLocalFrameImpl::AddMessageToConsole(const WebConsoleMessage& message) {
MessageLevel web_core_message_level = kInfoMessageLevel;
switch (message.level) {
- case WebConsoleMessage::kLevelVerbose:
+ case mojom::ConsoleMessageLevel::kVerbose:
web_core_message_level = kVerboseMessageLevel;
break;
- case WebConsoleMessage::kLevelInfo:
+ case mojom::ConsoleMessageLevel::kInfo:
web_core_message_level = kInfoMessageLevel;
break;
- case WebConsoleMessage::kLevelWarning:
+ case mojom::ConsoleMessageLevel::kWarning:
web_core_message_level = kWarningMessageLevel;
break;
- case WebConsoleMessage::kLevelError:
+ case mojom::ConsoleMessageLevel::kError:
web_core_message_level = kErrorMessageLevel;
break;
}
@@ -853,7 +846,7 @@ void WebLocalFrameImpl::RequestExecuteScriptInIsolatedWorld(
ScriptExecutionType option,
WebScriptExecutionCallback* callback) {
DCHECK(GetFrame());
- CHECK_GT(world_id, 0);
+ CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit);
scoped_refptr<DOMWrapperWorld> isolated_world =
@@ -950,16 +943,6 @@ void WebLocalFrameImpl::CheckCompleted() {
GetFrame()->GetDocument()->CheckCompleted();
}
-void WebLocalFrameImpl::LoadHTMLString(const WebData& data,
- const WebURL& base_url,
- const WebURL& unreachable_url) {
- DCHECK(GetFrame());
- CommitDataNavigation(
- WebURLRequest(base_url), data, WebString::FromUTF8("text/html"),
- WebString::FromUTF8("UTF-8"), unreachable_url,
- WebFrameLoadType::kStandard, WebHistoryItem(), false, nullptr, nullptr);
-}
-
void WebLocalFrameImpl::StopLoading() {
if (!GetFrame())
return;
@@ -1490,6 +1473,9 @@ void WebLocalFrameImpl::DispatchAfterPrintEvent() {
void WebLocalFrameImpl::DispatchPrintEventRecursively(
const AtomicString& event_type) {
+ DCHECK(event_type == event_type_names::kBeforeprint ||
+ event_type == event_type_names::kAfterprint);
+
HeapVector<Member<Frame>> frames;
for (Frame* frame = frame_; frame; frame = frame->Tree().TraverseNext(frame_))
frames.push_back(frame);
@@ -1501,7 +1487,10 @@ void WebLocalFrameImpl::DispatchPrintEventRecursively(
}
if (!frame->Tree().IsDescendantOf(frame_))
continue;
- ToLocalFrame(frame)->DomWindow()->DispatchEvent(*Event::Create(event_type));
+ Event* event = event_type == event_type_names::kBeforeprint
+ ? static_cast<Event*>(BeforePrintEvent::Create())
+ : static_cast<Event*>(AfterPrintEvent::Create());
+ ToLocalFrame(frame)->DomWindow()->DispatchEvent(*event);
}
}
@@ -1520,11 +1509,11 @@ int WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
}
if (plugin_container && plugin_container->SupportsPaginatedPrint()) {
- print_context_ = new ChromePluginPrintContext(GetFrame(), plugin_container,
- print_params);
+ print_context_ = MakeGarbageCollected<ChromePluginPrintContext>(
+ GetFrame(), plugin_container, print_params);
} else {
- print_context_ =
- new ChromePrintContext(GetFrame(), print_params.use_printing_layout);
+ print_context_ = MakeGarbageCollected<ChromePrintContext>(
+ GetFrame(), print_params.use_printing_layout);
}
FloatSize size(static_cast<float>(print_params.print_content_area.width),
@@ -1640,30 +1629,36 @@ WebLocalFrame* WebLocalFrame::CreateMainFrame(
WebView* web_view,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle,
WebFrame* opener,
const WebString& name,
WebSandboxFlags sandbox_flags) {
return WebLocalFrameImpl::CreateMainFrame(
- web_view, client, interface_registry, opener, name, sandbox_flags);
+ web_view, client, interface_registry,
+ std::move(document_interface_broker_handle), opener, name, sandbox_flags);
}
WebLocalFrame* WebLocalFrame::CreateProvisional(
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle,
WebRemoteFrame* old_web_frame,
WebSandboxFlags flags,
ParsedFeaturePolicy container_policy) {
return WebLocalFrameImpl::CreateProvisional(
- client, interface_registry, old_web_frame, flags, container_policy);
+ client, interface_registry, std::move(document_interface_broker_handle),
+ old_web_frame, flags, container_policy);
}
WebLocalFrameImpl* WebLocalFrameImpl::Create(
WebTreeScopeType scope,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle,
WebFrame* opener) {
WebLocalFrameImpl* frame = MakeGarbageCollected<WebLocalFrameImpl>(
- scope, client, interface_registry);
+ scope, client, interface_registry,
+ std::move(document_interface_broker_handle));
frame->SetOpener(opener);
return frame;
}
@@ -1672,11 +1667,13 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
WebView* web_view,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle,
WebFrame* opener,
const WebString& name,
WebSandboxFlags sandbox_flags) {
WebLocalFrameImpl* frame = MakeGarbageCollected<WebLocalFrameImpl>(
- WebTreeScopeType::kDocument, client, interface_registry);
+ WebTreeScopeType::kDocument, client, interface_registry,
+ std::move(document_interface_broker_handle));
frame->SetOpener(opener);
Page& page = *static_cast<WebViewImpl*>(web_view)->GetPage();
DCHECK(!page.MainFrame());
@@ -1690,12 +1687,14 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle,
WebRemoteFrame* old_web_frame,
WebSandboxFlags flags,
ParsedFeaturePolicy container_policy) {
DCHECK(client);
WebLocalFrameImpl* web_frame = MakeGarbageCollected<WebLocalFrameImpl>(
- old_web_frame, client, interface_registry);
+ old_web_frame, client, interface_registry,
+ std::move(document_interface_broker_handle));
Frame* old_frame = ToWebRemoteFrameImpl(old_web_frame)->GetFrame();
web_frame->SetParent(old_web_frame->Parent());
web_frame->SetOpener(old_web_frame->Opener());
@@ -1734,9 +1733,11 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
WebLocalFrameImpl* WebLocalFrameImpl::CreateLocalChild(
WebTreeScopeType scope,
WebLocalFrameClient* client,
- blink::InterfaceRegistry* interface_registry) {
+ blink::InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle) {
WebLocalFrameImpl* frame = MakeGarbageCollected<WebLocalFrameImpl>(
- scope, client, interface_registry);
+ scope, client, interface_registry,
+ std::move(document_interface_broker_handle));
AppendChild(frame);
return frame;
}
@@ -1744,13 +1745,15 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateLocalChild(
WebLocalFrameImpl::WebLocalFrameImpl(
WebTreeScopeType scope,
WebLocalFrameClient* client,
- blink::InterfaceRegistry* interface_registry)
+ blink::InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle)
: WebNavigationControl(scope),
client_(client),
- local_frame_client_(LocalFrameClientImpl::Create(this)),
+ local_frame_client_(LocalFrameClientImpl::Create(
+ this,
+ std::move(document_interface_broker_handle))),
autofill_client_(nullptr),
find_in_page_(FindInPage::Create(*this, interface_registry)),
- input_events_scale_factor_for_emulation_(1),
interface_registry_(interface_registry),
input_method_controller_(*this),
spell_check_panel_host_client_(nullptr),
@@ -1763,12 +1766,14 @@ WebLocalFrameImpl::WebLocalFrameImpl(
WebLocalFrameImpl::WebLocalFrameImpl(
WebRemoteFrame* old_web_frame,
WebLocalFrameClient* client,
- blink::InterfaceRegistry* interface_registry)
+ blink::InterfaceRegistry* interface_registry,
+ mojo::ScopedMessagePipeHandle document_interface_broker_handle)
: WebLocalFrameImpl(old_web_frame->InShadowTree()
? WebTreeScopeType::kShadow
: WebTreeScopeType::kDocument,
client,
- interface_registry) {}
+ interface_registry,
+ std::move(document_interface_broker_handle)) {}
WebLocalFrameImpl::~WebLocalFrameImpl() {
// The widget for the frame, if any, must have already been closed.
@@ -1852,16 +1857,37 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
return webframe_child->GetFrame();
}
+std::pair<RemoteFrame*, base::UnguessableToken> WebLocalFrameImpl::CreatePortal(
+ HTMLPortalElement* portal,
+ mojom::blink::PortalRequest request) {
+ auto pair = client_->CreatePortal(request.PassMessagePipe());
+ WebRemoteFrameImpl* portal_frame = ToWebRemoteFrameImpl(pair.first);
+ portal_frame->InitializeCoreFrame(*GetFrame()->GetPage(), portal,
+ g_null_atom);
+ return std::pair<RemoteFrame*, base::UnguessableToken>(
+ portal_frame->GetFrame(), pair.second);
+}
+
void WebLocalFrameImpl::DidChangeContentsSize(const IntSize& size) {
if (GetTextFinder() && GetTextFinder()->TotalMatchCount() > 0)
GetTextFinder()->IncreaseMarkerVersion();
}
+bool WebLocalFrameImpl::HasDevToolsOverlays() const {
+ return dev_tools_agent_ && dev_tools_agent_->HasOverlays();
+}
+
void WebLocalFrameImpl::UpdateDevToolsOverlays() {
if (dev_tools_agent_)
dev_tools_agent_->UpdateOverlays();
}
+void WebLocalFrameImpl::PaintDevToolsOverlays(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (dev_tools_agent_)
+ dev_tools_agent_->PaintOverlays(context);
+}
+
void WebLocalFrameImpl::CreateFrameView() {
TRACE_EVENT0("blink", "WebLocalFrameImpl::createFrameView");
@@ -1894,8 +1920,6 @@ void WebLocalFrameImpl::CreateFrameView() {
web_view->MaxAutoSize());
}
- GetFrame()->View()->SetInputEventsScaleForEmulation(
- input_events_scale_factor_for_emulation_);
GetFrame()->View()->SetDisplayMode(web_view->DisplayMode());
if (frame_widget_)
@@ -1954,15 +1978,6 @@ void WebLocalFrameImpl::DidFinish() {
Client()->DidFinishLoad();
}
-void WebLocalFrameImpl::SetInputEventsScaleForEmulation(
- float content_scale_factor) {
- input_events_scale_factor_for_emulation_ = content_scale_factor;
- if (GetFrame()->View()) {
- GetFrame()->View()->SetInputEventsScaleForEmulation(
- input_events_scale_factor_for_emulation_);
- }
-}
-
HitTestResult WebLocalFrameImpl::HitTestResultForVisualViewportPos(
const IntPoint& pos_in_viewport) {
IntPoint root_frame_point(
@@ -2024,25 +2039,14 @@ bool WebLocalFrameImpl::DispatchBeforeUnloadEvent(bool is_reload) {
}
void WebLocalFrameImpl::CommitNavigation(
- const WebURLRequest& request,
- WebFrameLoadType web_frame_load_type,
- const WebHistoryItem& item,
- bool is_client_redirect,
- const base::UnguessableToken& devtools_navigation_token,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DCHECK(GetFrame());
- DCHECK(!request.IsNull());
- DCHECK(!request.Url().ProtocolIs("javascript"));
+ DCHECK(!navigation_params->request.IsNull());
+ DCHECK(!navigation_params->request.Url().ProtocolIs("javascript"));
if (GetTextFinder())
GetTextFinder()->ClearActiveFindMatch();
-
- HistoryItem* history_item = item;
GetFrame()->Loader().CommitNavigation(
- request.ToResourceRequest(), SubstituteData(),
- is_client_redirect ? ClientRedirectPolicy::kClientRedirect
- : ClientRedirectPolicy::kNotClientRedirect,
- devtools_navigation_token, web_frame_load_type, history_item,
std::move(navigation_params), std::move(extra_data));
}
@@ -2088,7 +2092,8 @@ void WebLocalFrameImpl::LoadJavaScriptURL(const WebURL& url) {
String script = DecodeURLEscapeSequences(
static_cast<const KURL&>(url).GetString().Substring(
- strlen("javascript:")));
+ strlen("javascript:")),
+ DecodeURLMode::kUTF8OrIsomorphic);
std::unique_ptr<UserGestureIndicator> gesture_indicator =
LocalFrame::NotifyUserActivation(GetFrame(),
UserGestureToken::kNewGesture);
@@ -2106,26 +2111,6 @@ void WebLocalFrameImpl::LoadJavaScriptURL(const WebURL& url) {
}
}
-void WebLocalFrameImpl::CommitDataNavigation(
- const WebURLRequest& request,
- const WebData& data,
- const WebString& mime_type,
- const WebString& text_encoding,
- const WebURL& unreachable_url,
- WebFrameLoadType web_frame_load_type,
- const WebHistoryItem& history_item,
- bool is_client_redirect,
- std::unique_ptr<WebNavigationParams> navigation_params,
- std::unique_ptr<WebDocumentLoader::ExtraData> navigation_data) {
- GetFrame()->Loader().CommitNavigation(
- request.ToResourceRequest(),
- SubstituteData(data, mime_type, text_encoding, unreachable_url),
- is_client_redirect ? ClientRedirectPolicy::kClientRedirect
- : ClientRedirectPolicy::kNotClientRedirect,
- base::UnguessableToken::Create(), web_frame_load_type, history_item,
- std::move(navigation_params), std::move(navigation_data));
-}
-
WebNavigationControl::FallbackContentResult
WebLocalFrameImpl::MaybeRenderFallbackContent(const WebURLError& error) const {
DCHECK(GetFrame());
@@ -2156,7 +2141,7 @@ void WebLocalFrameImpl::RenderFallbackContent() const {
void WebLocalFrameImpl::ReportContentSecurityPolicyViolation(
const blink::WebContentSecurityPolicyViolation& violation) {
AddMessageToConsole(blink::WebConsoleMessage(
- WebConsoleMessage::kLevelError, violation.console_message,
+ mojom::ConsoleMessageLevel::kError, violation.console_message,
violation.source_location.url, violation.source_location.line_number,
violation.source_location.column_number));
@@ -2207,6 +2192,11 @@ void WebLocalFrameImpl::SetCommittedFirstRealLoad() {
GetFrame()->SetShouldSendResourceTimingInfoToParent(false);
}
+bool WebLocalFrameImpl::HasCommittedFirstRealLoad() {
+ DCHECK(GetFrame());
+ return GetFrame()->Loader().StateMachine()->CommittedFirstRealDocumentLoad();
+}
+
void WebLocalFrameImpl::NotifyUserActivation() {
LocalFrame::NotifyUserActivation(GetFrame(), UserGestureToken::kNewGesture);
}
@@ -2248,21 +2238,12 @@ void WebLocalFrameImpl::MarkAsLoading() {
}
bool WebLocalFrameImpl::CreatePlaceholderDocumentLoader(
- const WebURLRequest& request,
- WebFrameLoadType frame_load_type,
- WebNavigationType navigation_type,
- bool is_client_redirect,
- const base::UnguessableToken& devtools_navigation_token,
- std::unique_ptr<WebNavigationParams> navigation_params,
+ const WebNavigationInfo& info,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
- DCHECK(!request.IsNull());
- DCHECK(!request.Url().ProtocolIs("javascript"));
+ DCHECK(!info.url_request.IsNull());
+ DCHECK(!info.url_request.Url().ProtocolIs("javascript"));
return GetFrame()->Loader().CreatePlaceholderDocumentLoader(
- request.ToResourceRequest(),
- is_client_redirect ? ClientRedirectPolicy::kClientRedirect
- : ClientRedirectPolicy::kNotClientRedirect,
- devtools_navigation_token, frame_load_type, navigation_type,
- std::move(navigation_params), std::move(extra_data));
+ info, std::move(extra_data));
}
void WebLocalFrameImpl::SendOrientationChangeEvent() {
@@ -2333,6 +2314,14 @@ void WebLocalFrameImpl::WillDetachParent() {
void WebLocalFrameImpl::SetFrameWidget(WebFrameWidgetBase* frame_widget) {
frame_widget_ = frame_widget;
+
+ // This is needed because the local frame root's widget may not be set when
+ // Document::Initialize() called AttachmentCompositorAnimationTimeline()
+ // (which requires frame widget to be effective).
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && frame_widget) {
+ if (auto* document = GetFrame()->GetDocument())
+ document->AttachCompositorAnimationTimeline();
+ }
}
WebFrameWidget* WebLocalFrameImpl::FrameWidget() const {
@@ -2528,6 +2517,11 @@ void WebLocalFrameImpl::PerformMediaPlayerAction(
}
}
+void WebLocalFrameImpl::OnPortalActivated() {
+ PortalActivateEvent* event = PortalActivateEvent::Create();
+ GetFrame()->DomWindow()->DispatchEvent(*event);
+}
+
void WebLocalFrameImpl::SetTextCheckClient(
WebTextCheckClient* text_check_client) {
text_check_client_ = text_check_client;
diff --git a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 3f046d8c623..d5e92aad674 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -36,15 +36,18 @@
#include "base/single_thread_task_runner.h"
+#include "third_party/blink/public/mojom/ad_tagging/ad_frame.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink.h"
+#include "third_party/blink/public/mojom/portal/portal.mojom-blink.h"
#include "third_party/blink/public/platform/web_file_system_type.h"
-#include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
#include "third_party/blink/public/web/web_history_commit_type.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_navigation_control.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/exported/web_input_method_controller_impl.h"
+#include "third_party/blink/renderer/core/exported/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
@@ -55,10 +58,10 @@ namespace blink {
class ChromePrintContext;
class FindInPage;
+class HTMLPortalElement;
class IntSize;
class LocalFrameClientImpl;
class ScrollableArea;
-class SharedWorkerRepositoryClientImpl;
class TextFinder;
class WebAssociatedURLLoader;
struct WebAssociatedURLLoaderOptions;
@@ -92,8 +95,6 @@ class CORE_EXPORT WebLocalFrameImpl final
WebString AssignedName() const override;
void SetName(const WebString&) override;
WebVector<WebIconURL> IconURLs(int icon_types_mask) const override;
- void SetSharedWorkerRepositoryClient(
- WebSharedWorkerRepositoryClient*) override;
WebSize GetScrollOffset() const override;
void SetScrollOffset(const WebSize&) override;
WebSize DocumentSize() const override;
@@ -103,7 +104,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WebDocument GetDocument() const override;
WebPerformance Performance() const override;
bool IsAdSubframe() const override;
- void SetIsAdSubframe() override;
+ void SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type) override;
void DispatchUnloadEvent() override;
void ExecuteScript(const WebScriptSource&) override;
void ExecuteScriptInIsolatedWorld(int world_id,
@@ -111,12 +112,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WARN_UNUSED_RESULT v8::Local<v8::Value>
ExecuteScriptInIsolatedWorldAndReturnValue(int world_id,
const WebScriptSource&) override;
- void SetIsolatedWorldSecurityOrigin(int world_id,
- const WebSecurityOrigin&) override;
- void SetIsolatedWorldContentSecurityPolicy(int world_id,
- const WebString&) override;
- void SetIsolatedWorldHumanReadableName(int world_id,
- const WebString&) override;
+ void SetIsolatedWorldInfo(int world_id, const WebIsolatedWorldInfo&) override;
void AddMessageToConsole(const WebConsoleMessage&) override;
void Alert(const WebString& message) override;
bool Confirm(const WebString& message) override;
@@ -155,9 +151,6 @@ class CORE_EXPORT WebLocalFrameImpl final
void ReloadLoFiImages() override;
void StartNavigation(const WebURLRequest&) override;
void CheckCompleted() override;
- void LoadHTMLString(const WebData& html,
- const WebURL& base_url,
- const WebURL& unreachable_url) override;
void StopLoading() override;
WebDocumentLoader* GetProvisionalDocumentLoader() const override;
WebDocumentLoader* GetDocumentLoader() const override;
@@ -255,7 +248,8 @@ class CORE_EXPORT WebLocalFrameImpl final
// WebLocalFrame methods:
WebLocalFrameImpl* CreateLocalChild(WebTreeScopeType,
WebLocalFrameClient*,
- blink::InterfaceRegistry*) override;
+ blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle) override;
void SetAutofillClient(WebAutofillClient*) override;
WebAutofillClient* AutofillClient() override;
bool IsLocalRoot() const override;
@@ -303,15 +297,11 @@ class CORE_EXPORT WebLocalFrameImpl final
void AdvanceFocusInForm(WebFocusType) override;
void PerformMediaPlayerAction(const WebPoint&,
const WebMediaPlayerAction&) override;
+ void OnPortalActivated() override;
// WebNavigationControl methods:
bool DispatchBeforeUnloadEvent(bool) override;
void CommitNavigation(
- const WebURLRequest&,
- WebFrameLoadType,
- const WebHistoryItem&,
- bool is_client_redirect,
- const base::UnguessableToken& devtools_navigation_token,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) override;
blink::mojom::CommitResult CommitSameDocumentNavigation(
@@ -321,30 +311,15 @@ class CORE_EXPORT WebLocalFrameImpl final
bool is_client_redirect,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) override;
void LoadJavaScriptURL(const WebURL&) override;
- void CommitDataNavigation(
- const WebURLRequest&,
- const WebData&,
- const WebString& mime_type,
- const WebString& text_encoding,
- const WebURL& unreachable_url,
- WebFrameLoadType,
- const WebHistoryItem&,
- bool is_client_redirect,
- std::unique_ptr<WebNavigationParams> navigation_params,
- std::unique_ptr<WebDocumentLoader::ExtraData> navigation_data) override;
FallbackContentResult MaybeRenderFallbackContent(
const WebURLError&) const override;
void RenderFallbackContent() const override;
void SetCommittedFirstRealLoad() override;
+ bool HasCommittedFirstRealLoad() override;
void ClientDroppedNavigation() override;
void MarkAsLoading() override;
bool CreatePlaceholderDocumentLoader(
- const WebURLRequest&,
- WebFrameLoadType,
- WebNavigationType,
- bool is_client_redirect,
- const base::UnguessableToken& devtools_navigation_token,
- std::unique_ptr<WebNavigationParams>,
+ const WebNavigationInfo&,
std::unique_ptr<WebDocumentLoader::ExtraData>) override;
void InitializeCoreFrame(Page&, FrameOwner*, const AtomicString& name);
@@ -356,33 +331,43 @@ class CORE_EXPORT WebLocalFrameImpl final
static WebLocalFrameImpl* Create(WebTreeScopeType,
WebLocalFrameClient*,
InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebFrame* opener);
static WebLocalFrameImpl* CreateMainFrame(WebView*,
WebLocalFrameClient*,
InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebFrame* opener,
const WebString& name,
WebSandboxFlags);
static WebLocalFrameImpl* CreateProvisional(WebLocalFrameClient*,
InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle,
WebRemoteFrame*,
WebSandboxFlags,
ParsedFeaturePolicy);
WebLocalFrameImpl(WebTreeScopeType,
WebLocalFrameClient*,
- blink::InterfaceRegistry*);
+ blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle);
WebLocalFrameImpl(WebRemoteFrame*,
WebLocalFrameClient*,
- blink::InterfaceRegistry*);
+ blink::InterfaceRegistry*,
+ mojo::ScopedMessagePipeHandle);
~WebLocalFrameImpl() override;
LocalFrame* CreateChildFrame(const AtomicString& name,
HTMLFrameOwnerElement*);
+ std::pair<RemoteFrame*, base::UnguessableToken> CreatePortal(
+ HTMLPortalElement*,
+ mojom::blink::PortalRequest);
void DidChangeContentsSize(const IntSize&);
+ bool HasDevToolsOverlays() const;
void UpdateDevToolsOverlays();
+ void PaintDevToolsOverlays(GraphicsContext&); // For CompositeAfterPaint.
void CreateFrameView();
@@ -420,12 +405,6 @@ class CORE_EXPORT WebLocalFrameImpl final
return content_settings_client_;
}
- SharedWorkerRepositoryClientImpl* SharedWorkerRepositoryClient() const {
- return shared_worker_repository_client_.get();
- }
-
- void SetInputEventsScaleForEmulation(float);
-
WebTextCheckClient* GetTextCheckerClient() const {
return text_check_client_;
}
@@ -496,8 +475,6 @@ class CORE_EXPORT WebLocalFrameImpl final
WebAutofillClient* autofill_client_;
WebContentSettingsClient* content_settings_client_ = nullptr;
- std::unique_ptr<SharedWorkerRepositoryClientImpl>
- shared_worker_repository_client_;
Member<FindInPage> find_in_page_;
@@ -505,10 +482,6 @@ class CORE_EXPORT WebLocalFrameImpl final
// information. Is used by PrintPage().
Member<ChromePrintContext> print_context_;
- // Stores the additional input events scale when device metrics
- // emulation is enabled.
- float input_events_scale_factor_for_emulation_;
-
// Borrowed pointers to Mojo objects.
blink::InterfaceRegistry* interface_registry_;
diff --git a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
index 9533a997685..8831aafb924 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
@@ -12,13 +11,18 @@ namespace blink {
WebViewFrameWidget::WebViewFrameWidget(WebWidgetClient& client,
WebViewImpl& web_view)
- : WebFrameWidgetBase(client),
- web_view_(&web_view),
- self_keep_alive_(this) {}
+ : WebFrameWidgetBase(client), web_view_(&web_view), self_keep_alive_(this) {
+ // TODO(danakj): SetLayerTreeView() here as well, then we can Close() the
+ // WebViewImpl's widget bits in Close().
+ web_view_->SetWebWidgetClient(&client);
+}
WebViewFrameWidget::~WebViewFrameWidget() = default;
void WebViewFrameWidget::Close() {
+ // TODO(danakj): Close() the WebViewImpl here, when we reset the LayerTreeView
+ // in the constructor.
+ web_view_->SetWebWidgetClient(nullptr);
web_view_ = nullptr;
WebFrameWidgetBase::Close();
@@ -71,10 +75,6 @@ void WebViewFrameWidget::PaintContent(cc::PaintCanvas* canvas,
web_view_->PaintContent(canvas, view_port);
}
-void WebViewFrameWidget::LayoutAndPaintAsync(base::OnceClosure callback) {
- web_view_->LayoutAndPaintAsync(std::move(callback));
-}
-
void WebViewFrameWidget::CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)> callback) {
web_view_->CompositeAndReadbackAsync(std::move(callback));
@@ -108,6 +108,16 @@ void WebViewFrameWidget::RecordWheelAndTouchScrollingCount(
web_view_->RecordWheelAndTouchScrollingCount(has_scrolled_by_wheel,
has_scrolled_by_touch);
}
+void WebViewFrameWidget::SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) {
+ web_view_->SendOverscrollEventFromImplSide(overscroll_delta,
+ scroll_latched_element_id);
+}
+void WebViewFrameWidget::SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) {
+ web_view_->SendScrollEndEventFromImplSide(scroll_latched_element_id);
+}
void WebViewFrameWidget::MouseCaptureLost() {
web_view_->MouseCaptureLost();
@@ -130,38 +140,10 @@ void WebViewFrameWidget::WillCloseLayerTreeView() {
web_view_->WillCloseLayerTreeView();
}
-SkColor WebViewFrameWidget::BackgroundColor() const {
- return web_view_->BackgroundColor();
-}
-
-WebPagePopup* WebViewFrameWidget::GetPagePopup() const {
- return web_view_->GetPagePopup();
-}
-
WebURL WebViewFrameWidget::GetURLForDebugTrace() {
return web_view_->GetURLForDebugTrace();
}
-void WebViewFrameWidget::SetBackgroundColorOverride(SkColor color) {
- web_view_->SetBackgroundColorOverride(color);
-}
-
-void WebViewFrameWidget::ClearBackgroundColorOverride() {
- web_view_->ClearBackgroundColorOverride();
-}
-
-void WebViewFrameWidget::SetBaseBackgroundColorOverride(SkColor color) {
- web_view_->SetBaseBackgroundColorOverride(color);
-}
-
-void WebViewFrameWidget::ClearBaseBackgroundColorOverride() {
- web_view_->ClearBaseBackgroundColorOverride();
-}
-
-void WebViewFrameWidget::SetBaseBackgroundColor(SkColor color) {
- web_view_->SetBaseBackgroundColor(color);
-}
-
WebInputMethodController*
WebViewFrameWidget::GetActiveWebInputMethodController() const {
return web_view_->GetActiveWebInputMethodController();
@@ -179,10 +161,6 @@ void WebViewFrameWidget::SetLayerTreeView(WebLayerTreeView*) {
NOTREACHED();
}
-void WebViewFrameWidget::ScheduleAnimation() {
- web_view_->ScheduleAnimationForWidget();
-}
-
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
WebViewFrameWidget::EnsureCompositorMutatorDispatcher(
scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner) {
@@ -217,6 +195,11 @@ HitTestResult WebViewFrameWidget::CoreHitTestResultAt(const gfx::Point& point) {
return web_view_->CoreHitTestResultAt(point);
}
+void WebViewFrameWidget::ZoomToFindInPageRect(
+ const WebRect& rect_in_root_frame) {
+ web_view_->ZoomToFindInPageRect(rect_in_root_frame);
+}
+
void WebViewFrameWidget::Trace(blink::Visitor* visitor) {
WebFrameWidgetBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h
index e9217a0dacb..fdffbc96842 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -53,7 +53,6 @@ class CORE_EXPORT WebViewFrameWidget : public WebFrameWidgetBase {
void UpdateLifecycle(LifecycleUpdate requested_update,
LifecycleUpdateReason reason) override;
void PaintContent(cc::PaintCanvas*, const WebRect& view_port) override;
- void LayoutAndPaintAsync(base::OnceClosure callback) override;
void CompositeAndReadbackAsync(
base::OnceCallback<void(const SkBitmap&)>) override;
void ThemeChanged() override;
@@ -63,23 +62,19 @@ class CORE_EXPORT WebViewFrameWidget : public WebFrameWidgetBase {
void ApplyViewportChanges(const ApplyViewportChangesArgs&) override;
void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
bool has_scrolled_by_touch) override;
+ void SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) override;
+ void SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) override;
void MouseCaptureLost() override;
void SetFocus(bool) override;
bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
bool IsAcceleratedCompositingActive() const override;
- bool IsWebView() const override { return false; }
- bool IsPagePopup() const override { return false; }
void WillCloseLayerTreeView() override;
- SkColor BackgroundColor() const override;
- WebPagePopup* GetPagePopup() const override;
WebURL GetURLForDebugTrace() override;
// WebFrameWidget overrides:
- void SetBackgroundColorOverride(SkColor) override;
- void ClearBackgroundColorOverride() override;
- void SetBaseBackgroundColorOverride(SkColor) override;
- void ClearBaseBackgroundColorOverride() override;
- void SetBaseBackgroundColor(SkColor) override;
WebInputMethodController* GetActiveWebInputMethodController() const override;
bool ScrollFocusedEditableElementIntoView() override;
WebHitTestResult HitTestResultAt(const gfx::Point&) override;
@@ -88,7 +83,6 @@ class CORE_EXPORT WebViewFrameWidget : public WebFrameWidgetBase {
void Initialize() override;
void SetLayerTreeView(WebLayerTreeView*) override;
bool ForSubframe() const override { return false; }
- void ScheduleAnimation() override;
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
EnsureCompositorMutatorDispatcher(
scoped_refptr<base::SingleThreadTaskRunner>*) override;
@@ -98,6 +92,7 @@ class CORE_EXPORT WebViewFrameWidget : public WebFrameWidgetBase {
WebLayerTreeView* GetLayerTreeView() const override;
CompositorAnimationHost* AnimationHost() const override;
HitTestResult CoreHitTestResultAt(const gfx::Point&) override;
+ void ZoomToFindInPageRect(const WebRect& rect_in_root_frame) override;
void Trace(blink::Visitor*) override;
diff --git a/chromium/third_party/blink/renderer/core/frame/window.idl b/chromium/third_party/blink/renderer/core/frame/window.idl
index a189cb39294..a0396aacddb 100644
--- a/chromium/third_party/blink/renderer/core/frame/window.idl
+++ b/chromium/third_party/blink/renderer/core/frame/window.idl
@@ -49,22 +49,10 @@
[Replaceable, MeasureAs=BarPropStatusbar] readonly attribute BarProp statusbar;
[Replaceable, MeasureAs=BarPropToolbar] readonly attribute BarProp toolbar;
attribute DOMString status;
- // https://html.spec.whatwg.org/multipage/window-object.html#dom-window-close
- // TODO(yukishiino): Replace |CurrentWindow| with the incumbent window or
- // something once the incumbent realm is implemented. Currently,
- // OriginSafeMethodGetter + CurrentWindow are used instead of the incumbent
- // one.
- [CrossOrigin, CallWith=CurrentWindow] void close();
+ [CrossOrigin, CallWith=Isolate] void close();
[CrossOrigin] readonly attribute boolean closed;
void stop();
- // https://html.spec.whatwg.org/multipage/interaction.html#dom-window-focus
- // https://html.spec.whatwg.org/multipage/interaction.html#focusing-steps
- // TODO(yukishiino): Remove [CallWith=CurrentWindow] or clarify why
- // we need it. focus() is not supposed to use the incumbent realm.
- // So, we shouldn't need to use CurrentWindow here, however, somehow
- // DOMWindow::focus() is checking if the incumbent window is eligible to
- // focus another window.
- [CrossOrigin, CallWith=CurrentWindow] void focus();
+ [CrossOrigin, CallWith=Isolate] void focus();
[CrossOrigin] void blur();
// other browsing contexts
@@ -75,7 +63,7 @@
[CrossOrigin, Custom=Setter] attribute Window opener;
[Replaceable, CrossOrigin] readonly attribute Window? parent;
[CheckSecurity=ReturnValue, Custom=Getter] readonly attribute Element? frameElement;
- [CallWith=(ExecutionContext,CurrentWindow,EnteredWindow), RaisesException] Window? open(optional URLString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "");
+ [CallWith=Isolate, RaisesException] Window? open(optional URLString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "");
// indexed properties
// https://html.spec.whatwg.org/C/browsers.html#windowproxy-getownproperty
@@ -95,9 +83,9 @@
[Measure, CallWith=ScriptState] DOMString? prompt(optional DOMString message = "", optional DOMString defaultValue = "");
[Measure, CallWith=ScriptState] void print();
- [CrossOrigin, CallWith=CurrentWindow, RaisesException] void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
+ [CrossOrigin, CallWith=Isolate, RaisesException] void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
- [CrossOrigin, CallWith=CurrentWindow, RaisesException] void postMessage(any message, optional WindowPostMessageOptions options);
+ [CrossOrigin, CallWith=Isolate, RaisesException] void postMessage(any message, optional WindowPostMessageOptions options);
// WindowOrWorkerGlobalScope mixin
// https://html.spec.whatwg.org/#windoworworkerglobalscope-mixin
@@ -127,7 +115,7 @@
// CSSOM View Module
// https://drafts.csswg.org/cssom-view/#extensions-to-the-window-interface
- [NewObject] MediaQueryList matchMedia(DOMString query);
+ [HighEntropy, Measure, NewObject] MediaQueryList matchMedia(DOMString query);
[SameObject, Replaceable] readonly attribute Screen screen;
[RuntimeEnabled=WorkerTaskQueue, SameObject, Replaceable] readonly attribute ScriptedTaskQueueController TaskQueue;
@@ -139,14 +127,14 @@
void resizeBy(long x, long y);
// viewport
- [Affects=Nothing, Replaceable] readonly attribute long innerWidth;
- [Affects=Nothing, Replaceable] readonly attribute long innerHeight;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowInnerWidth, Replaceable] readonly attribute long innerWidth;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowInnerHeight, Replaceable] readonly attribute long innerHeight;
// viewport scrolling
- [Replaceable] readonly attribute double scrollX;
- [Replaceable] readonly attribute double pageXOffset;
- [Replaceable] readonly attribute double scrollY;
- [Replaceable] readonly attribute double pageYOffset;
+ [HighEntropy, MeasureAs=WindowScrollX, Replaceable] readonly attribute double scrollX;
+ [HighEntropy, MeasureAs=WindowPageXOffset, Replaceable] readonly attribute double pageXOffset;
+ [HighEntropy, MeasureAs=WindowScrollY, Replaceable] readonly attribute double scrollY;
+ [HighEntropy, MeasureAs=WindowPageYOffset, Replaceable] readonly attribute double pageYOffset;
void scroll(optional ScrollToOptions options);
void scroll(unrestricted double x, unrestricted double y);
void scrollTo(optional ScrollToOptions options);
@@ -159,11 +147,11 @@
[Replaceable, SameObject] readonly attribute VisualViewport visualViewport;
// client
- [Affects=Nothing, Replaceable] readonly attribute long screenX;
- [Affects=Nothing, Replaceable] readonly attribute long screenY;
- [Affects=Nothing, Replaceable] readonly attribute long outerWidth;
- [Affects=Nothing, Replaceable] readonly attribute long outerHeight;
- [Affects=Nothing, Replaceable] readonly attribute double devicePixelRatio;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowScreenX, Replaceable] readonly attribute long screenX;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowScreenY, Replaceable] readonly attribute long screenY;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowOuterWidth, Replaceable] readonly attribute long outerWidth;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowOuterHeight, Replaceable] readonly attribute long outerHeight;
+ [Affects=Nothing, HighEntropy, MeasureAs=WindowDevicePixelRatio, Replaceable] readonly attribute double devicePixelRatio;
// Selection API
// https://w3c.github.io/selection-api/#extensions-to-window-interface
@@ -181,7 +169,7 @@
// This is the interface orientation in degrees. Some examples are:
// 0 is straight up; -90 is when the device is rotated 90 clockwise;
// 90 is when rotated counter clockwise.
- [MeasureAs=WindowOrientation, RuntimeEnabled=OrientationEvent] readonly attribute long orientation;
+ [HighEntropy, MeasureAs=WindowOrientation, RuntimeEnabled=OrientationEvent] readonly attribute long orientation;
// Accessibility Object Model
// https://github.com/WICG/aom/blob/HEAD/explainer.md
@@ -193,16 +181,16 @@
// Non-standard APIs
[MeasureAs=WindowClientInformation, Replaceable] readonly attribute Navigator clientInformation;
[Replaceable, MeasureAs=WindowEvent, Custom=Getter, NotEnumerable] readonly attribute Event event;
- [MeasureAs=WindowFind] boolean find([Default=Undefined] optional DOMString string,
- [Default=Undefined] optional boolean caseSensitive,
- [Default=Undefined] optional boolean backwards,
- [Default=Undefined] optional boolean wrap,
- [Default=Undefined] optional boolean wholeWord,
- [Default=Undefined] optional boolean searchInFrames,
- [Default=Undefined] optional boolean showDialog);
+ [MeasureAs=WindowFind] boolean find([DefaultValue=Undefined] optional DOMString string,
+ [DefaultValue=Undefined] optional boolean caseSensitive,
+ [DefaultValue=Undefined] optional boolean backwards,
+ [DefaultValue=Undefined] optional boolean wrap,
+ [DefaultValue=Undefined] optional boolean wholeWord,
+ [DefaultValue=Undefined] optional boolean searchInFrames,
+ [DefaultValue=Undefined] optional boolean showDialog);
[MeasureAs=WindowOffscreenBuffering, Replaceable, NotEnumerable] readonly attribute boolean offscreenBuffering;
- [MeasureAs=WindowScreenLeft, Replaceable] readonly attribute long screenLeft;
- [MeasureAs=WindowScreenTop, Replaceable] readonly attribute long screenTop;
+ [HighEntropy, MeasureAs=WindowScreenLeft, Replaceable] readonly attribute long screenLeft;
+ [HighEntropy, MeasureAs=WindowScreenTop, Replaceable] readonly attribute long screenTop;
[MeasureAs=WindowDefaultStatus] attribute DOMString defaultStatus;
[MeasureAs=WindowDefaultstatus, ImplementedAs=defaultStatus] attribute DOMString defaultstatus;
[MeasureAs=StyleMedia] readonly attribute StyleMedia styleMedia;
@@ -226,9 +214,8 @@
attribute DOMMatrixConstructor WebKitCSSMatrix;
- //TrustedTypes API
- //http://github.com/wicg/trusted-types
- [RuntimeEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory TrustedTypes;
+ // TrustedTypes API: http://github.com/wicg/trusted-types
+ [OriginTrialEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory TrustedTypes;
};
Window implements GlobalEventHandlers;
diff --git a/chromium/third_party/blink/renderer/core/frame/window_event_handlers.h b/chromium/third_party/blink/renderer/core/frame/window_event_handlers.h
index c5b06f34756..d1c9a72d911 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_event_handlers.h
+++ b/chromium/third_party/blink/renderer/core/frame/window_event_handlers.h
@@ -52,6 +52,8 @@ class WindowEventHandlers {
DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(pagehide, kPagehide);
DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(pageshow, kPageshow);
DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(popstate, kPopstate);
+ DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(portalactivate,
+ kPortalactivate);
DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(rejectionhandled,
kRejectionhandled);
DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(storage, kStorage);
diff --git a/chromium/third_party/blink/renderer/core/frame/window_event_handlers.idl b/chromium/third_party/blink/renderer/core/frame/window_event_handlers.idl
index f8c25fb7ab3..2ee41eae597 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_event_handlers.idl
+++ b/chromium/third_party/blink/renderer/core/frame/window_event_handlers.idl
@@ -46,6 +46,7 @@
attribute EventHandler onpagehide;
attribute EventHandler onpageshow;
attribute EventHandler onpopstate;
+ [RuntimeEnabled=Portals] attribute EventHandler onportalactivate;
attribute EventHandler onrejectionhandled;
attribute EventHandler onstorage;
attribute EventHandler onunhandledrejection;
diff --git a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
index ace639fce91..17970335799 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/frame/window_or_worker_global_scope.h"
+#include "third_party/blink/renderer/bindings/core/v8/scheduled_action.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -128,7 +129,7 @@ String WindowOrWorkerGlobalScope::atob(EventTarget&,
int WindowOrWorkerGlobalScope::setTimeout(
ScriptState* script_state,
EventTarget& event_target,
- const ScriptValue& handler,
+ V8Function* handler,
int timeout,
const Vector<ScriptValue>& arguments) {
ExecutionContext* execution_context = event_target.GetExecutionContext();
@@ -174,7 +175,7 @@ int WindowOrWorkerGlobalScope::setTimeoutFromString(
if (!IsAllowed(script_state, execution_context, true, handler))
return 0;
// Don't allow setting timeouts to run empty functions. Was historically a
- // perfomance issue.
+ // performance issue.
if (handler.IsEmpty())
return 0;
if (timeout >= 0 && execution_context->IsDocument()) {
@@ -191,7 +192,7 @@ int WindowOrWorkerGlobalScope::setTimeoutFromString(
int WindowOrWorkerGlobalScope::setInterval(
ScriptState* script_state,
EventTarget& event_target,
- const ScriptValue& handler,
+ V8Function* handler,
int timeout,
const Vector<ScriptValue>& arguments) {
ExecutionContext* execution_context = event_target.GetExecutionContext();
@@ -232,7 +233,7 @@ int WindowOrWorkerGlobalScope::setIntervalFromString(
if (!IsAllowed(script_state, execution_context, true, handler))
return 0;
// Don't allow setting timeouts to run empty functions. Was historically a
- // perfomance issue.
+ // performance issue.
if (handler.IsEmpty())
return 0;
ScheduledAction* action =
diff --git a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
index 2126c4a515b..0cb1db28ad2 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
@@ -47,6 +47,7 @@ class ScriptPromise;
class ScriptState;
class ScriptValue;
class StringOrTrustedScript;
+class V8Function;
typedef HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas
ImageBitmapSourceUnion;
@@ -64,7 +65,7 @@ class WindowOrWorkerGlobalScope {
static int setTimeout(ScriptState*,
EventTarget&,
- const ScriptValue& handler,
+ V8Function* handler,
int timeout,
const Vector<ScriptValue>& arguments);
static int setTimeout(ScriptState*,
@@ -80,7 +81,7 @@ class WindowOrWorkerGlobalScope {
const Vector<ScriptValue>&);
static int setInterval(ScriptState*,
EventTarget&,
- const ScriptValue& handler,
+ V8Function* handler,
int timeout,
const Vector<ScriptValue>&);
static int setInterval(ScriptState*,
diff --git a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
index 1b78426e59e..e19ec9076bd 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
+++ b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
@@ -47,19 +47,17 @@ typedef (HTMLImageElement or
[RaisesException] DOMString btoa(DOMString btoa);
[RaisesException] DOMString atob(DOMString atob);
- // TODO(yukishiino): Use TimerHandler (or Function at least) to implement
- // setTimeout and setInterval.
// https://html.spec.whatwg.org/C/webappapis.html#windoworworkerglobalscope-mixin
- [CallWith=ScriptState, RuntimeCallStatsCounter=WindowSetTimeout] long setTimeout(CallbackFunctionTreatedAsScriptValue handler, optional long timeout = 0, any... arguments);
+ [CallWith=ScriptState, RuntimeCallStatsCounter=WindowSetTimeout] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
[CallWith=ScriptState, RaisesException] long setTimeout(ScriptString handler, optional long timeout = 0, any... arguments);
void clearTimeout(optional long handle = 0);
- [CallWith=ScriptState] long setInterval(CallbackFunctionTreatedAsScriptValue handler, optional long timeout = 0, any... arguments);
+ [CallWith=ScriptState] long setInterval(Function handler, optional long timeout = 0, any... arguments);
[CallWith=ScriptState, RaisesException] long setInterval(ScriptString handler, optional long timeout = 0, any... arguments);
void clearInterval(optional long handle = 0);
// ImageBitmap
- [CallWith=ScriptState] Promise createImageBitmap(
+ [CallWith=ScriptState] Promise<ImageBitmap> createImageBitmap(
ImageBitmapSource imageBitmap, optional ImageBitmapOptions options);
- [CallWith=ScriptState] Promise createImageBitmap(
+ [CallWith=ScriptState] Promise<ImageBitmap> createImageBitmap(
ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options);
};
diff --git a/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc
index d7b294a975c..456df6999a7 100644
--- a/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc
+++ b/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -678,7 +678,7 @@ void Fullscreen::ContinueRequestFullscreen(Document& document,
// 10.2. Reject |promise| with a TypeError exception and terminate these
// steps.
- if (resolver) {
+ if (resolver && resolver->GetScriptState()->ContextIsValid()) {
ScriptState::Scope scope(resolver->GetScriptState());
// TODO(dtapuska): Change error to be something useful instead of just a
// boolean and return this to the user.
diff --git a/chromium/third_party/blink/renderer/core/geometry/OWNERS b/chromium/third_party/blink/renderer/core/geometry/OWNERS
index 0262a7d1b3b..204a655208e 100644
--- a/chromium/third_party/blink/renderer/core/geometry/OWNERS
+++ b/chromium/third_party/blink/renderer/core/geometry/OWNERS
@@ -1,3 +1,2 @@
-dominicc@chromium.org
fserb@chromium.org
jinho.bang@samsung.com
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
index 3a5ac0c294f..df1e000d432 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
@@ -243,6 +243,10 @@ DOMMatrix* DOMMatrixReadOnly::scale3d(double scale,
return DOMMatrix::Create(this)->scale3dSelf(scale, ox, oy, oz);
}
+DOMMatrix* DOMMatrixReadOnly::scaleNonUniform(double sx, double sy) {
+ return DOMMatrix::Create(this)->scaleSelf(sx, sy, 1, 0, 0, 0);
+}
+
DOMMatrix* DOMMatrixReadOnly::rotate(double rot_x) {
return DOMMatrix::Create(this)->rotateSelf(rot_x);
}
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.h b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.h
index 7970ea5bf47..5b640565726 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.h
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.h
@@ -100,6 +100,7 @@ class CORE_EXPORT DOMMatrixReadOnly : public ScriptWrappable {
double ox = 0,
double oy = 0,
double oz = 0);
+ DOMMatrix* scaleNonUniform(double sx = 1, double sy = 1);
DOMMatrix* scale3d(double scale = 1,
double ox = 0,
double oy = 0,
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl
index 803bbd11d8e..dfc75bb8cf3 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl
@@ -53,6 +53,8 @@
optional unrestricted double originX = 0,
optional unrestricted double originY = 0,
optional unrestricted double originZ = 0);
+ DOMMatrix scaleNonUniform(optional unrestricted double scaleX = 1,
+ optional unrestricted double scaleY = 1);
DOMMatrix scale3d(optional unrestricted double scale = 1,
optional unrestricted double originX = 0,
optional unrestricted double originY = 0,
@@ -77,5 +79,5 @@
Float32Array toFloat32Array();
Float64Array toFloat64Array();
[Exposed=Window, RaisesException] stringifier;
- serializer = { attribute };
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_point_read_only.idl b/chromium/third_party/blink/renderer/core/geometry/dom_point_read_only.idl
index 1075a7e875d..51791cfcdf0 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_point_read_only.idl
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_point_read_only.idl
@@ -19,5 +19,5 @@
[RaisesException] DOMPoint matrixTransform(optional DOMMatrixInit matrix);
- serializer = { attribute };
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_quad.idl b/chromium/third_party/blink/renderer/core/geometry/dom_quad.idl
index 0af1f801778..5f18cdf89df 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_quad.idl
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_quad.idl
@@ -5,10 +5,9 @@
// https://drafts.fxtf.org/geometry/#domquad
[
- Constructor(optional DOMPointInit p1, optional DOMPointInit p2,
- optional DOMPointInit p3, optional DOMPointInit p4),
- Exposed=(Window,Worker),
- Serializable
+ Constructor(optional DOMPointInit p1, optional DOMPointInit p2, optional DOMPointInit p3, optional DOMPointInit p4),
+ Exposed=(Window,Worker),
+ Serializable
]
interface DOMQuad {
[NewObject] static DOMQuad fromRect(optional DOMRectInit other);
@@ -20,5 +19,5 @@ interface DOMQuad {
[SameObject] readonly attribute DOMPoint p4;
[NewObject] DOMRect getBounds();
- serializer = { attribute };
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl b/chromium/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl
index 9cd59610639..39f4a35096c 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl
@@ -21,5 +21,5 @@
readonly attribute unrestricted double bottom;
readonly attribute unrestricted double left;
- serializer = { attribute };
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/html/BUILD.gn b/chromium/third_party/blink/renderer/core/html/BUILD.gn
index 483f737abc3..dc155966d1a 100644
--- a/chromium/third_party/blink/renderer/core/html/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/html/BUILD.gn
@@ -43,31 +43,21 @@ blink_core_sources("html") {
"custom/ce_reactions_scope.h",
"custom/custom_element.cc",
"custom/custom_element.h",
- "custom/custom_element_adopted_callback_reaction.cc",
- "custom/custom_element_adopted_callback_reaction.h",
- "custom/custom_element_attribute_changed_callback_reaction.cc",
- "custom/custom_element_attribute_changed_callback_reaction.h",
- "custom/custom_element_connected_callback_reaction.cc",
- "custom/custom_element_connected_callback_reaction.h",
"custom/custom_element_definition.cc",
"custom/custom_element_definition.h",
"custom/custom_element_definition_builder.h",
"custom/custom_element_descriptor.h",
"custom/custom_element_descriptor_hash.h",
- "custom/custom_element_disconnected_callback_reaction.cc",
- "custom/custom_element_disconnected_callback_reaction.h",
- "custom/custom_element_form_associated_callback_reaction.cc",
- "custom/custom_element_form_associated_callback_reaction.h",
"custom/custom_element_reaction.cc",
"custom/custom_element_reaction.h",
+ "custom/custom_element_reaction_factory.cc",
+ "custom/custom_element_reaction_factory.h",
"custom/custom_element_reaction_queue.cc",
"custom/custom_element_reaction_queue.h",
"custom/custom_element_reaction_stack.cc",
"custom/custom_element_reaction_stack.h",
"custom/custom_element_registry.cc",
"custom/custom_element_registry.h",
- "custom/custom_element_upgrade_reaction.cc",
- "custom/custom_element_upgrade_reaction.h",
"custom/custom_element_upgrade_sorter.cc",
"custom/custom_element_upgrade_sorter.h",
"custom/element_internals.cc",
@@ -227,8 +217,6 @@ blink_core_sources("html") {
"forms/internal_popup_menu.h",
"forms/keyboard_clickable_input_type_view.cc",
"forms/keyboard_clickable_input_type_view.h",
- "forms/labelable_element.cc",
- "forms/labelable_element.h",
"forms/labels_node_list.cc",
"forms/labels_node_list.h",
"forms/listed_element.cc",
@@ -502,12 +490,20 @@ blink_core_sources("html") {
"media/media_remoting_interstitial.h",
"media/picture_in_picture_interstitial.cc",
"media/picture_in_picture_interstitial.h",
+ "media/remote_playback_controller.cc",
+ "media/remote_playback_controller.h",
+ "media/remote_playback_observer.h",
+ "media/video_wake_lock.cc",
+ "media/video_wake_lock.h",
"plugin_document.cc",
"plugin_document.h",
"portal/document_portals.cc",
"portal/document_portals.h",
+ "portal/dom_window_portal_host.cc",
+ "portal/dom_window_portal_host.h",
"portal/html_portal_element.cc",
"portal/html_portal_element.h",
+ "portal/portal_host.h",
"rel_list.cc",
"rel_list.h",
"shadow/details_marker_control.cc",
diff --git a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics.cc b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics.cc
index f9c46deb318..4a1cc024bf6 100644
--- a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics.cc
+++ b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics.cc
@@ -126,8 +126,8 @@ bool IsUrlIncrementedByOne(const HTMLAnchorElement& anchor_element) {
// overflows.
IntRect AbsoluteElementBoundingBoxRect(const LayoutObject* layout_object) {
Vector<LayoutRect> rects;
- layout_object->AddElementVisualOverflowRects(rects, LayoutPoint());
-
+ layout_object->AddOutlineRects(rects, LayoutPoint(),
+ NGOutlineType::kIncludeBlockVisualOverflow);
return layout_object
->LocalToAbsoluteQuad(FloatQuad(FloatRect(UnionRect(rects))))
.EnclosingBoundingBox();
@@ -212,7 +212,7 @@ base::Optional<AnchorElementMetrics> AnchorElementMetrics::Create(
base::Optional<AnchorElementMetrics>
AnchorElementMetrics::MaybeReportClickedMetricsOnClick(
const HTMLAnchorElement* anchor_element) {
- if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsClicked) ||
+ if (!base::FeatureList::IsEnabled(features::kNavigationPredictor) ||
!anchor_element->Href().ProtocolIsInHTTPFamily() ||
!GetRootDocument(*anchor_element)->Url().ProtocolIsInHTTPFamily() ||
!anchor_element->GetDocument().BaseURL().ProtocolIsInHTTPFamily()) {
@@ -236,7 +236,7 @@ AnchorElementMetrics::MaybeReportClickedMetricsOnClick(
void AnchorElementMetrics::MaybeReportViewportMetricsOnLoad(
Document& document) {
DCHECK(document.GetFrame());
- if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsVisible) ||
+ if (!base::FeatureList::IsEnabled(features::kNavigationPredictor) ||
document.ParentDocument() || !document.View() ||
!document.Url().ProtocolIsInHTTPFamily() ||
!document.BaseURL().ProtocolIsInHTTPFamily()) {
diff --git a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
index 78cd5f0a282..2bf83494153 100644
--- a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
+++ b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
@@ -41,7 +41,7 @@ AnchorElementMetricsSender* AnchorElementMetricsSender::From(
AnchorElementMetricsSender* sender =
Supplement<Document>::From<AnchorElementMetricsSender>(document);
if (!sender) {
- sender = new AnchorElementMetricsSender(document);
+ sender = MakeGarbageCollected<AnchorElementMetricsSender>(document);
ProvideTo(document, sender);
}
return sender;
@@ -51,8 +51,7 @@ AnchorElementMetricsSender* AnchorElementMetricsSender::From(
bool AnchorElementMetricsSender::HasAnchorElementMetricsSender(
Document& document) {
bool is_feature_enabled =
- base::FeatureList::IsEnabled(features::kRecordAnchorMetricsClicked) ||
- base::FeatureList::IsEnabled(features::kRecordAnchorMetricsVisible);
+ base::FeatureList::IsEnabled(features::kNavigationPredictor);
const KURL& url = document.BaseURL();
return is_feature_enabled && !document.ParentDocument() && url.IsValid() &&
url.ProtocolIsInHTTPFamily();
@@ -96,7 +95,7 @@ AnchorElementMetricsSender::GetAnchorElements() const {
return anchor_elements_;
}
-void AnchorElementMetricsSender::Trace(blink::Visitor* visitor) {
+void AnchorElementMetricsSender::Trace(Visitor* visitor) {
visitor->Trace(anchor_elements_);
Supplement<Document>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h
index 17a34d159a9..bfd7d5847bc 100644
--- a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h
+++ b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h
@@ -28,6 +28,7 @@ class CORE_EXPORT AnchorElementMetricsSender final
public:
static const char kSupplementName[];
+ explicit AnchorElementMetricsSender(Document&);
virtual ~AnchorElementMetricsSender();
// Returns the anchor element metrics sender of the root document of
@@ -52,11 +53,9 @@ class CORE_EXPORT AnchorElementMetricsSender final
// Returns the stored |anchor_elements_|.
const HeapHashSet<Member<HTMLAnchorElement>>& GetAnchorElements() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- explicit AnchorElementMetricsSender(Document&);
-
// Associates |metrics_host_| with the IPC interface if not already, so it can
// be used to send messages. Returns true if associated, false otherwise.
bool AssociateInterface();
diff --git a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc
index 8c38c5c923b..ccd840873df 100644
--- a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc
@@ -21,7 +21,7 @@ class AnchorElementMetricsSenderTest : public SimTest {
void SetUp() override {
SimTest::SetUp();
- feature_list_.InitAndEnableFeature(features::kRecordAnchorMetricsClicked);
+ feature_list_.InitAndEnableFeature(features::kNavigationPredictor);
}
base::test::ScopedFeatureList feature_list_;
diff --git a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
index f318644f099..f7cab0f4fc1 100644
--- a/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
@@ -45,8 +45,9 @@ class AnchorElementMetricsTest : public SimTest {
void SetUp() override {
SimTest::SetUp();
- WebView().Resize(WebSize(kViewportWidth, kViewportHeight));
- feature_list_.InitAndEnableFeature(features::kRecordAnchorMetricsClicked);
+ WebView().MainFrameWidget()->Resize(
+ WebSize(kViewportWidth, kViewportHeight));
+ feature_list_.InitAndEnableFeature(features::kNavigationPredictor);
}
base::test::ScopedFeatureList feature_list_;
@@ -84,20 +85,18 @@ TEST_F(AnchorElementMetricsTest, FinchControl) {
HTMLAnchorElement* anchor_element =
ToHTMLAnchorElement(GetDocument().getElementById("anchor"));
- // With feature kRecordAnchorMetricsClicked disabled, we should not see any
+ // With feature kNavigationPredictor disabled, we should not see any
// count in histograms.
base::test::ScopedFeatureList disabled_feature_list;
- disabled_feature_list.InitAndDisableFeature(
- features::kRecordAnchorMetricsClicked);
+ disabled_feature_list.InitAndDisableFeature(features::kNavigationPredictor);
AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element);
histogram_tester.ExpectTotalCount("AnchorElementMetrics.Clicked.RatioArea",
0);
- // If we enable feature kRecordAnchorMetricsClicked, we should see count is 1
+ // If we enable feature kNavigationPredictor, we should see count is 1
// in histograms.
base::test::ScopedFeatureList enabled_feature_list;
- enabled_feature_list.InitAndEnableFeature(
- features::kRecordAnchorMetricsClicked);
+ enabled_feature_list.InitAndEnableFeature(features::kNavigationPredictor);
AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element);
histogram_tester.ExpectTotalCount("AnchorElementMetrics.Clicked.RatioArea",
1);
@@ -121,10 +120,8 @@ TEST_F(AnchorElementMetricsTest, NonHTTPOnClick) {
// Tests that a data page with an HTTPS anchor is not reported when the anchor
// is clicked.
- SimRequest data_resource("data://example.com/", "text/html");
- LoadURL("data://example.com/");
- data_resource.Complete(
- "<a id='anchor' href='https://google.com/'>google</a>");
+ LoadURL(
+ "data:text/html,<a id='anchor' href='https://google.com/'>google</a>");
anchor_element = ToHTMLAnchorElement(GetDocument().getElementById("anchor"));
AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element);
@@ -240,7 +237,8 @@ TEST_F(AnchorElementMetricsTest, AnchorFeatureExtract) {
TEST_F(AnchorElementMetricsTest, AnchorFeatureInIframe) {
SimRequest main_resource("https://example.com/page1", "text/html");
SimRequest iframe_resource("https://example.com/iframe.html", "text/html");
- SimRequest image_resource("https://example.com/cat.png", "image/png");
+ SimSubresourceRequest image_resource("https://example.com/cat.png",
+ "image/png");
LoadURL("https://example.com/page1");
@@ -313,7 +311,8 @@ TEST_F(AnchorElementMetricsTest, AnchorFeatureInIframe) {
TEST_F(AnchorElementMetricsTest, AnchorFeatureInIframeNonHttp) {
SimRequest main_resource("content://example.com/page1", "text/html");
SimRequest iframe_resource("https://example.com/iframe.html", "text/html");
- SimRequest image_resource("https://example.com/cat.png", "image/png");
+ SimSubresourceRequest image_resource("https://example.com/cat.png",
+ "image/png");
LoadURL("content://example.com/page1");
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index ddb353c2327..345ec0109c6 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -298,14 +298,14 @@ void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) {
return;
}
// Webp encoder does not support progressive encoding. We also don't use idle
- // encoding for layout tests, since the idle task start and completition
- // deadlines (6.7s or 13s) bypass the layout test running deadline (6s)
+ // encoding for web tests, since the idle task start and completition
+ // deadlines (6.7s or 13s) bypass the web test running deadline (6s)
// and result in timeouts on different tests. We use
// enforce_idle_encoding_for_test_ to test idle encoding in unit tests.
bool use_idle_encoding =
(mime_type_ != kMimeTypeWebp) &&
(enforce_idle_encoding_for_test_ ||
- !RuntimeEnabledFeatures::NoIdleEncodingForLayoutTestsEnabled());
+ !RuntimeEnabledFeatures::NoIdleEncodingForWebTestsEnabled());
if (!use_idle_encoding) {
if (!IsMainThread()) {
@@ -588,7 +588,7 @@ void CanvasAsyncBlobCreator::PostDelayedTaskToCurrentThread(
TimeDelta::FromMillisecondsD(delay_ms));
}
-void CanvasAsyncBlobCreator::Trace(blink::Visitor* visitor) {
+void CanvasAsyncBlobCreator::Trace(Visitor* visitor) {
visitor->Trace(context_);
visitor->Trace(encode_options_);
visitor->Trace(callback_);
@@ -597,12 +597,12 @@ void CanvasAsyncBlobCreator::Trace(blink::Visitor* visitor) {
sk_sp<SkColorSpace> CanvasAsyncBlobCreator::BlobColorSpaceToSkColorSpace(
String blob_color_space) {
- SkColorSpace::Gamut gamut = SkColorSpace::kSRGB_Gamut;
+ skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB;
if (blob_color_space == kDisplayP3ImageColorSpaceName)
- gamut = SkColorSpace::kDCIP3_D65_Gamut;
+ gamut = SkNamedGamut::kDCIP3;
else if (blob_color_space == kRec2020ImageColorSpaceName)
- gamut = SkColorSpace::kRec2020_Gamut;
- return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+ gamut = SkNamedGamut::kRec2020;
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
}
bool CanvasAsyncBlobCreator::EncodeImageForConvertToBlobTest() {
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
index 4e8d51ccb46..c2224e507a5 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
@@ -82,7 +82,7 @@ class CORE_EXPORT CanvasAsyncBlobCreator
virtual void SignalTaskSwitchInStartTimeoutEventForTesting() {}
virtual void SignalTaskSwitchInCompleteTimeoutEventForTesting() {}
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
static sk_sp<SkColorSpace> BlobColorSpaceToSkColorSpace(
String blob_color_space);
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
index dddd9665758..7b54c19ce2e 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -245,13 +245,15 @@ TEST_F(CanvasAsyncBlobCreatorTest, ColorManagedConvertToBlob) {
color_space_params.push_back(std::pair<sk_sp<SkColorSpace>, SkColorType>(
SkColorSpace::MakeSRGBLinear(), kRGBA_F16_SkColorType));
color_space_params.push_back(std::pair<sk_sp<SkColorSpace>, SkColorType>(
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut),
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, SkNamedGamut::kDCIP3),
kRGBA_F16_SkColorType));
color_space_params.push_back(std::pair<sk_sp<SkColorSpace>, SkColorType>(
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kRec2020_Gamut),
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, SkNamedGamut::kRec2020),
kRGBA_F16_SkColorType));
+ color_space_params.push_back(std::pair<sk_sp<SkColorSpace>, SkColorType>(
+ nullptr, kRGBA_F16_SkColorType));
+ color_space_params.push_back(
+ std::pair<sk_sp<SkColorSpace>, SkColorType>(nullptr, kN32_SkColorType));
std::list<String> blob_mime_types = {"image/png", "image/webp", "image/jpeg"};
std::list<String> blob_color_spaces = {kSRGBImageColorSpaceName,
@@ -261,9 +263,11 @@ TEST_F(CanvasAsyncBlobCreatorTest, ColorManagedConvertToBlob) {
kRGBA8ImagePixelFormatName, kRGBA16ImagePixelFormatName,
};
- // The maximum difference locally observed is 2.
- const unsigned uint8_color_tolerance = 2;
- const float f16_color_tolerance = 0.01;
+ // Maximum differences are both observed locally with
+ // kRGBA16ImagePixelFormatName, kSRGBImageColorSpaceName and nil input color
+ // space
+ const unsigned uint8_color_tolerance = 3;
+ const float f16_color_tolerance = 0.015;
for (auto color_space_param : color_space_params) {
for (auto blob_mime_type : blob_mime_types) {
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.cc
index 0e22e2b9277..1f87cdea86e 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.cc
@@ -13,8 +13,4 @@ CanvasContextCreationAttributesCore::CanvasContextCreationAttributesCore(
CanvasContextCreationAttributesCore::~CanvasContextCreationAttributesCore() {}
-void CanvasContextCreationAttributesCore::Trace(blink::Visitor* visitor) {
- visitor->Trace(compatible_xr_device);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h
index a6f46ede75f..614e4e3a873 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h
@@ -31,11 +31,7 @@ class CORE_EXPORT CanvasContextCreationAttributesCore {
bool premultiplied_alpha = true;
bool preserve_drawing_buffer = false;
bool stencil = false;
-
- // This attribute is of type XRDevice, defined in modules/xr/xr_device.h
- Member<ScriptWrappable> compatible_xr_device;
-
- void Trace(blink::Visitor*);
+ bool xr_compatible = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
index 7c0c4641fca..f9de29a6c49 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
@@ -59,9 +59,8 @@ bool CanvasFontCache::GetFontUsingDefaultStyle(const String& font_string,
HashMap<String, Font>::iterator i =
fonts_resolved_using_default_style_.find(font_string);
if (i != fonts_resolved_using_default_style_.end()) {
- DCHECK(font_lru_list_.Contains(font_string));
- font_lru_list_.erase(font_string);
- font_lru_list_.insert(font_string);
+ auto add_result = font_lru_list_.PrependOrMoveToFirst(font_string);
+ DCHECK(!add_result.is_new_entry);
resolved_font = i->value;
return true;
}
@@ -85,10 +84,9 @@ MutableCSSPropertyValueSet* CanvasFontCache::ParseFont(
MutableCSSPropertyValueSet* parsed_style;
MutableStylePropertyMap::iterator i = fetched_fonts_.find(font_string);
if (i != fetched_fonts_.end()) {
- DCHECK(font_lru_list_.Contains(font_string));
+ auto add_result = font_lru_list_.PrependOrMoveToFirst(font_string);
+ DCHECK(!add_result.is_new_entry);
parsed_style = i->value;
- font_lru_list_.erase(font_string);
- font_lru_list_.insert(font_string);
} else {
parsed_style = MutableCSSPropertyValueSet::Create(kHTMLStandardMode);
CSSParser::ParseValue(parsed_style, CSSPropertyFont, font_string, true,
@@ -103,15 +101,15 @@ MutableCSSPropertyValueSet* CanvasFontCache::ParseFont(
if (font_value && font_value->IsCSSWideKeyword())
return nullptr;
fetched_fonts_.insert(font_string, parsed_style);
- font_lru_list_.insert(font_string);
+ font_lru_list_.PrependOrMoveToFirst(font_string);
// Hard limit is applied here, on the fly, while the soft limit is
// applied at the end of the task.
if (fetched_fonts_.size() > HardMaxFonts()) {
DCHECK_EQ(fetched_fonts_.size(), HardMaxFonts() + 1);
DCHECK_EQ(font_lru_list_.size(), HardMaxFonts() + 1);
- fetched_fonts_.erase(font_lru_list_.front());
- fonts_resolved_using_default_style_.erase(font_lru_list_.front());
- font_lru_list_.RemoveFirst();
+ fetched_fonts_.erase(font_lru_list_.back());
+ fonts_resolved_using_default_style_.erase(font_lru_list_.back());
+ font_lru_list_.pop_back();
}
}
SchedulePruningIfNeeded();
@@ -123,9 +121,9 @@ void CanvasFontCache::DidProcessTask(const base::PendingTask& pending_task) {
DCHECK(pruning_scheduled_);
DCHECK(main_cache_purge_preventer_);
while (fetched_fonts_.size() > MaxFonts()) {
- fetched_fonts_.erase(font_lru_list_.front());
- fonts_resolved_using_default_style_.erase(font_lru_list_.front());
- font_lru_list_.RemoveFirst();
+ fetched_fonts_.erase(font_lru_list_.back());
+ fonts_resolved_using_default_style_.erase(font_lru_list_.back());
+ font_lru_list_.pop_back();
}
main_cache_purge_preventer_.reset();
Thread::Current()->RemoveTaskObserver(this);
@@ -151,7 +149,7 @@ void CanvasFontCache::PruneAll() {
fonts_resolved_using_default_style_.clear();
}
-void CanvasFontCache::Trace(blink::Visitor* visitor) {
+void CanvasFontCache::Trace(Visitor* visitor) {
visitor->Trace(fetched_fonts_);
visitor->Trace(document_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
index 76cd7105c29..5f22e6811be 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
@@ -37,7 +37,7 @@ class CORE_EXPORT CanvasFontCache final
void PruneAll();
unsigned size();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
static unsigned MaxFonts();
unsigned HardMaxFonts();
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc
index be64ecda505..1cd5df937a6 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc
@@ -7,7 +7,6 @@
#include <memory>
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
@@ -72,7 +71,7 @@ TEST_F(CanvasFontCacheTest, CacheHardLimit) {
TEST_F(CanvasFontCacheTest, PageVisibilityChange) {
Context2d()->setFont("10px sans-serif");
EXPECT_TRUE(Cache()->IsInCache("10px sans-serif"));
- GetPage().SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
+ GetPage().SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
EXPECT_FALSE(Cache()->IsInCache("10px sans-serif"));
Context2d()->setFont("15px sans-serif");
@@ -83,7 +82,7 @@ TEST_F(CanvasFontCacheTest, PageVisibilityChange) {
EXPECT_TRUE(Cache()->IsInCache("10px sans-serif"));
EXPECT_FALSE(Cache()->IsInCache("15px sans-serif"));
- GetPage().SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
+ GetPage().SetIsHidden(/*is_hidden=*/false, /*initial_state=*/false);
Context2d()->setFont("15px sans-serif");
Context2d()->setFont("10px sans-serif");
EXPECT_TRUE(Cache()->IsInCache("10px sans-serif"));
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
index c1c40cc5e39..86478c5c04d 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
@@ -37,7 +37,6 @@ namespace blink {
class FloatRect;
class Image;
-class SecurityOrigin;
enum SourceImageStatus {
kNormalSourceImageStatus,
@@ -58,8 +57,7 @@ class CORE_EXPORT CanvasImageSource {
// already tainted because this function may be used to determine whether
// a CanvasPattern is "origin clean", and that pattern may be used on
// another canvas, which may not be already tainted.
- virtual bool WouldTaintOrigin(
- const SecurityOrigin* destination_security_origin) const = 0;
+ virtual bool WouldTaintOrigin() const = 0;
virtual bool IsCSSImageValue() const { return false; }
virtual bool IsImageElement() const { return false; }
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
index d89924b4cd0..16deefe9a3f 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
@@ -163,9 +163,7 @@ CanvasRenderingContext::ResolveContextTypeAliases(
return type;
}
-bool CanvasRenderingContext::WouldTaintOrigin(
- CanvasImageSource* image_source,
- const SecurityOrigin* destination_security_origin) {
+bool CanvasRenderingContext::WouldTaintOrigin(CanvasImageSource* image_source) {
// Don't taint the canvas on data URLs. This special case is needed here
// because CanvasImageSource::WouldTaintOrigin() can return false for data
// URLs due to restrictions on SVG foreignObject nodes as described in
@@ -178,12 +176,11 @@ bool CanvasRenderingContext::WouldTaintOrigin(
if (has_url && source_url.ProtocolIsData())
return false;
- return image_source->WouldTaintOrigin(destination_security_origin);
+ return image_source->WouldTaintOrigin();
}
-void CanvasRenderingContext::Trace(blink::Visitor* visitor) {
+void CanvasRenderingContext::Trace(Visitor* visitor) {
visitor->Trace(host_);
- visitor->Trace(creation_attributes_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index 6da915a4488..565a8b01675 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -181,7 +181,7 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable,
virtual void PushFrame() {}
virtual ImageBitmap* TransferToImageBitmap(ScriptState*) { return nullptr; }
- bool WouldTaintOrigin(CanvasImageSource*, const SecurityOrigin*);
+ bool WouldTaintOrigin(CanvasImageSource*);
void DidMoveToNewDocument(Document*);
void DetachHost() { host_ = nullptr; }
@@ -190,7 +190,7 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable,
return creation_attributes_;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
virtual void Stop() = 0;
protected:
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index c711d30571a..b0a51a2e7d0 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -18,15 +18,18 @@ namespace blink {
CanvasRenderingContextHost::CanvasRenderingContextHost() = default;
-void CanvasRenderingContextHost::RecordCanvasSizeToUMA(unsigned width,
- unsigned height,
+void CanvasRenderingContextHost::RecordCanvasSizeToUMA(const IntSize& size,
HostType hostType) {
+ if (did_record_canvas_size_to_uma_)
+ return;
+ did_record_canvas_size_to_uma_ = true;
+
if (hostType == kCanvasHost) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Blink.Canvas.SqrtNumberOfPixels",
- std::sqrt(width * height), 1, 5000, 100);
+ std::sqrt(size.Area()), 1, 5000, 100);
} else if (hostType == kOffscreenCanvasHost) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Blink.OffscreenCanvas.SqrtNumberOfPixels",
- std::sqrt(width * height), 1, 5000, 100);
+ std::sqrt(size.Area()), 1, 5000, 100);
} else {
NOTREACHED();
}
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
index d0b86e7ab6a..daea7c9aed5 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
@@ -39,7 +39,7 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost,
kOffscreenCanvasHost,
};
- void static RecordCanvasSizeToUMA(unsigned width, unsigned height, HostType);
+ void RecordCanvasSizeToUMA(const IntSize&, HostType);
virtual void DetachContext() = 0;
virtual void DidDraw(const FloatRect& rect) = 0;
@@ -104,6 +104,7 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost,
scoped_refptr<StaticBitmapImage> CreateTransparentImage(const IntSize&) const;
bool did_fail_to_create_resource_provider_ = false;
+ bool did_record_canvas_size_to_uma_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index e2c1a35081b..c9a271fdd85 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -37,6 +37,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/numerics/checked_math.h"
#include "build/build_config.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/core/css/css_font_selector.h"
@@ -145,9 +146,6 @@ intptr_t HTMLCanvasElement::global_gpu_memory_usage_ = 0;
unsigned HTMLCanvasElement::global_accelerated_context_count_ = 0;
HTMLCanvasElement::~HTMLCanvasElement() {
- CanvasRenderingContextHost::RecordCanvasSizeToUMA(
- size_.Width(), size_.Height(),
- CanvasRenderingContextHost::HostType::kCanvasHost);
if (surface_layer_bridge_ && surface_layer_bridge_->GetCcLayer())
GraphicsLayer::UnregisterContentsLayer(surface_layer_bridge_->GetCcLayer());
v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
@@ -254,6 +252,16 @@ void HTMLCanvasElement::RegisterRenderingContextFactory(
CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
const String& type,
const CanvasContextCreationAttributesCore& attributes) {
+ auto* old_contents_cc_layer = ContentsCcLayer();
+ auto* result = GetCanvasRenderingContextInternal(type, attributes);
+ if (ContentsCcLayer() != old_contents_cc_layer)
+ OnContentsCcLayerChanged();
+ return result;
+}
+
+CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContextInternal(
+ const String& type,
+ const CanvasContextCreationAttributesCore& attributes) {
CanvasRenderingContext::ContextType context_type =
CanvasRenderingContext::ContextTypeFromId(type);
@@ -265,9 +273,8 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
}
// Log the aliased context type used.
- if (!context_) {
+ if (!context_)
UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.ContextType", context_type);
- }
context_type =
CanvasRenderingContext::ResolveContextTypeAliases(context_type);
@@ -309,7 +316,7 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
DidDraw();
}
- if (attributes.low_latency &&
+ if (context_->CreationAttributes().low_latency &&
origin_trials::LowLatencyCanvasEnabled(&GetDocument())) {
CreateLayer();
SetNeedsUnbufferedInputEvents(true);
@@ -386,6 +393,8 @@ void HTMLCanvasElement::DidDraw() {
void HTMLCanvasElement::FinalizeFrame() {
TRACE_EVENT0("blink", "HTMLCanvasElement::FinalizeFrame");
+ RecordCanvasSizeToUMA(size_,
+ CanvasRenderingContextHost::HostType::kCanvasHost);
// FinalizeFrame indicates the end of a script task that may have rendered
// into the canvas, now is a good time to unlock cache entries.
@@ -397,7 +406,8 @@ void HTMLCanvasElement::FinalizeFrame() {
// Compute to determine whether disable accleration is needed
if (IsAccelerated() &&
canvas_heuristic_parameters::kGPUReadbackForcesNoAcceleration &&
- !RuntimeEnabledFeatures::Canvas2dFixedRenderingModeEnabled()) {
+ !RuntimeEnabledFeatures::Canvas2dFixedRenderingModeEnabled() &&
+ !base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) {
if (gpu_readback_invoked_in_current_frame_) {
gpu_readback_successive_frames_++;
gpu_readback_invoked_in_current_frame_ = false;
@@ -454,6 +464,9 @@ void HTMLCanvasElement::FinalizeFrame() {
void HTMLCanvasElement::DisableAcceleration(
std::unique_ptr<Canvas2DLayerBridge>
unaccelerated_bridge_used_for_testing) {
+ if (base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) {
+ NOTREACHED();
+ }
// Create and configure an unaccelerated Canvas2DLayerBridge.
std::unique_ptr<Canvas2DLayerBridge> bridge;
if (unaccelerated_bridge_used_for_testing)
@@ -971,6 +984,9 @@ void HTMLCanvasElement::PushFrame(scoped_refptr<CanvasResource> image,
}
bool HTMLCanvasElement::ShouldAccelerate(AccelerationCriteria criteria) const {
+ if (base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas))
+ return true;
+
if (context_ && !Is2d())
return false;
@@ -1091,7 +1107,7 @@ void HTMLCanvasElement::NotifyGpuContextLost() {
context_->LoseContext(CanvasRenderingContext::kRealLostContext);
}
-void HTMLCanvasElement::Trace(blink::Visitor* visitor) {
+void HTMLCanvasElement::Trace(Visitor* visitor) {
visitor->Trace(listeners_);
visitor->Trace(context_);
ContextLifecycleObserver::Trace(visitor);
@@ -1224,7 +1240,8 @@ scoped_refptr<Image> HTMLCanvasElement::GetSourceImageForCanvas(
if (canvas_heuristic_parameters::kDisableAccelerationToAvoidReadbacks &&
!RuntimeEnabledFeatures::Canvas2dFixedRenderingModeEnabled() &&
hint == kPreferNoAcceleration && canvas2d_bridge_ &&
- canvas2d_bridge_->IsAccelerated()) {
+ canvas2d_bridge_->IsAccelerated() &&
+ !base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) {
DisableAcceleration();
}
image = RenderingContext()->GetImage(hint);
@@ -1239,7 +1256,7 @@ scoped_refptr<Image> HTMLCanvasElement::GetSourceImageForCanvas(
return image;
}
-bool HTMLCanvasElement::WouldTaintOrigin(const SecurityOrigin*) const {
+bool HTMLCanvasElement::WouldTaintOrigin() const {
return !OriginClean();
}
@@ -1386,10 +1403,12 @@ void HTMLCanvasElement::OnWebLayerUpdated() {
void HTMLCanvasElement::RegisterContentsLayer(cc::Layer* layer) {
GraphicsLayer::RegisterContentsLayer(layer);
+ OnContentsCcLayerChanged();
}
void HTMLCanvasElement::UnregisterContentsLayer(cc::Layer* layer) {
GraphicsLayer::UnregisterContentsLayer(layer);
+ OnContentsCcLayerChanged();
}
FontSelector* HTMLCanvasElement::GetFontSelector() {
@@ -1494,4 +1513,20 @@ bool HTMLCanvasElement::HasImageBitmapContext() const {
type == CanvasRenderingContext::kContextXRPresent);
}
+cc::Layer* HTMLCanvasElement::ContentsCcLayer() const {
+ if (surface_layer_bridge_)
+ return surface_layer_bridge_->GetCcLayer();
+ if (context_ && context_->IsComposited())
+ return context_->CcLayer();
+ return nullptr;
+}
+
+void HTMLCanvasElement::OnContentsCcLayerChanged() {
+ // We need to repaint the layer because the foreign layer display item may
+ // appear, disappear or change.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ GetLayoutObject() && GetLayoutObject()->HasLayer())
+ GetLayoutBoxModelObject()->Layer()->SetNeedsRepaint();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index 59a1f9549cc..59b612e3511 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -102,6 +102,8 @@ class CORE_EXPORT HTMLCanvasElement final
using Node::GetExecutionContext;
DECLARE_NODE_FACTORY(HTMLCanvasElement);
+
+ explicit HTMLCanvasElement(Document&);
~HTMLCanvasElement() override;
// Attributes and functions exposed to script
@@ -195,7 +197,7 @@ class CORE_EXPORT HTMLCanvasElement final
scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
AccelerationHint,
const FloatSize&) override;
- bool WouldTaintOrigin(const SecurityOrigin*) const override;
+ bool WouldTaintOrigin() const override;
FloatSize ElementSize(const FloatSize&) const override;
bool IsCanvasElement() const override { return true; }
bool IsOpaque() const override;
@@ -232,7 +234,7 @@ class CORE_EXPORT HTMLCanvasElement final
base::WeakPtr<CanvasResourceDispatcher>,
scoped_refptr<base::SingleThreadTaskRunner>,
unsigned resource_id) override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void SetResourceProviderForTesting(std::unique_ptr<CanvasResourceProvider>,
std::unique_ptr<Canvas2DLayerBridge>,
@@ -299,11 +301,15 @@ class CORE_EXPORT HTMLCanvasElement final
scoped_refptr<StaticBitmapImage> Snapshot(SourceDrawingBuffer,
AccelerationHint) const;
+ // Returns the cc layer containing the contents. It's the cc layer of
+ // SurfaceLayerBridge() or RenderingContext(), or nullptr if the canvas is not
+ // composited.
+ cc::Layer* ContentsCcLayer() const;
+
protected:
void DidMoveToNewDocument(Document& old_document) override;
private:
- explicit HTMLCanvasElement(Document&);
void Dispose();
using ContextFactoryVector =
@@ -339,6 +345,12 @@ class CORE_EXPORT HTMLCanvasElement final
// ImageBitmapRenderingContextBase.
bool HasImageBitmapContext() const;
+ CanvasRenderingContext* GetCanvasRenderingContextInternal(
+ const String&,
+ const CanvasContextCreationAttributesCore&);
+
+ void OnContentsCcLayerChanged();
+
HeapHashSet<WeakMember<CanvasDrawListener>> listeners_;
IntSize size_;
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl
index 609b8bd249b..f62bc324fe9 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl
@@ -37,11 +37,11 @@ interface HTMLCanvasElement : HTMLElement
// Note: The arguments argument is variadic in the spec, but not here as
// only one extra argument is actually used.
// FIXME: type should not have a default value.
- [MeasureAs=CanvasToDataURL, RaisesException] DOMString toDataURL(optional DOMString type = null, optional any arguments);
+ [HighEntropy, MeasureAs=CanvasToDataURL, RaisesException] DOMString toDataURL(optional DOMString type = null, optional any arguments);
- [MeasureAs=CanvasToBlob, RaisesException] void toBlob(BlobCallback _callback, optional DOMString type = null, optional any arguments);
+ [HighEntropy, MeasureAs=CanvasToBlob, RaisesException] void toBlob(BlobCallback _callback, optional DOMString type = null, optional any arguments);
- [RuntimeEnabled=CanvasColorManagement, MeasureAs=CanvasConvertToBlob, RaisesException, CallWith=ScriptState] Promise<Blob> convertToBlob(optional ImageEncodeOptions options);
+ [HighEntropy, RuntimeEnabled=CanvasColorManagement, MeasureAs=CanvasConvertToBlob, RaisesException, CallWith=ScriptState] Promise<Blob> convertToBlob(optional ImageEncodeOptions options);
};
// https://html.spec.whatwg.org/multipage/canvas.html#blobcallback
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
index d39416e4e22..d6258f2da86 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
@@ -355,9 +355,14 @@ ImageData* ImageData::Create(scoped_refptr<StaticBitmapImage> image,
return image_data;
}
+ base::CheckedNumeric<uint32_t> area = image->Size().Area();
+ area *= 4;
+
+ if (!area.IsValid())
+ return nullptr;
// Create image data with f32 storage
- DOMFloat32Array* f32_array = ImageData::AllocateAndValidateFloat32Array(
- image->Size().Area() * 4, nullptr);
+ DOMFloat32Array* f32_array =
+ ImageData::AllocateAndValidateFloat32Array(area.ValueOrDie(), nullptr);
if (!f32_array)
return nullptr;
image_info = image_info.makeColorType(kRGBA_F32_SkColorType);
@@ -823,14 +828,17 @@ bool ImageData::ImageDataInCanvasColorSettings(
return data_transform_successful;
}
+ base::CheckedNumeric<uint32_t> area = size_.Area();
+ if (!area.IsValid())
+ return false;
bool data_transform_successful =
skcms_Transform(src_data, src_pixel_format, src_alpha_format,
src_profile_ptr, converted_pixels, dst_pixel_format,
- dst_alpha_format, dst_profile_ptr, size_.Area());
+ dst_alpha_format, dst_profile_ptr, area.ValueOrDie());
return data_transform_successful;
}
-void ImageData::Trace(blink::Visitor* visitor) {
+void ImageData::Trace(Visitor* visitor) {
visitor->Trace(color_settings_);
visitor->Trace(data_);
visitor->Trace(data_u16_);
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.h b/chromium/third_party/blink/renderer/core/html/canvas/image_data.h
index e5adfd82b59..d33e9aaee20 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.h
@@ -159,7 +159,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable,
base::Optional<IntRect> crop_rect,
const ImageBitmapOptions*) override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
WARN_UNUSED_RESULT v8::Local<v8::Object> AssociateWithWrapper(
v8::Isolate*,
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc
index 25f4742ce1f..00a07749812 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc
@@ -73,10 +73,8 @@ scoped_refptr<Image> ImageElementBase::GetSourceImageForCanvas(
return source_image->ImageForDefaultFrame();
}
-bool ImageElementBase::WouldTaintOrigin(
- const SecurityOrigin* destination_security_origin) const {
- return CachedImage() &&
- !CachedImage()->IsAccessAllowed(destination_security_origin);
+bool ImageElementBase::WouldTaintOrigin() const {
+ return CachedImage() && !CachedImage()->IsAccessAllowed();
}
FloatSize ImageElementBase::ElementSize(
@@ -114,7 +112,7 @@ bool ImageElementBase::IsAccelerated() const {
}
const KURL& ImageElementBase::SourceURL() const {
- return CachedImage()->GetResponse().Url();
+ return CachedImage()->GetResponse().CurrentRequestUrl();
}
bool ImageElementBase::IsOpaque() const {
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h
index 8a36a2c7779..0b8979db73d 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h
@@ -36,8 +36,7 @@ class CORE_EXPORT ImageElementBase : public CanvasImageSource,
AccelerationHint,
const FloatSize&) override;
- bool WouldTaintOrigin(
- const SecurityOrigin* destination_security_origin) const override;
+ bool WouldTaintOrigin() const override;
FloatSize ElementSize(const FloatSize& default_object_size) const override;
FloatSize DefaultDestinationSize(
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.cc b/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.cc
index 7936129e4a1..20ec8f7a1d2 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.cc
@@ -38,7 +38,7 @@ float TextMetrics::GetFontBaseline(const TextBaseline& text_baseline,
return 0;
}
-void TextMetrics::Trace(blink::Visitor* visitor) {
+void TextMetrics::Trace(Visitor* visitor) {
visitor->Trace(baselines_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.h b/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.h
index b6473de7351..4776eedf160 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/text_metrics.h
@@ -69,7 +69,7 @@ class CORE_EXPORT TextMetrics final : public ScriptWrappable {
static float GetFontBaseline(const TextBaseline&, const SimpleFontData&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void Update(const Font&,
diff --git a/chromium/third_party/blink/renderer/core/html/collection_items_cache.h b/chromium/third_party/blink/renderer/core/html/collection_items_cache.h
index 5567f5424bf..c311e300c62 100644
--- a/chromium/third_party/blink/renderer/core/html/collection_items_cache.h
+++ b/chromium/third_party/blink/renderer/core/html/collection_items_cache.h
@@ -47,7 +47,7 @@ class CollectionItemsCache : public CollectionIndexCache<Collection, NodeType> {
CollectionItemsCache();
~CollectionItemsCache();
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(cached_list_);
Base::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/README.md b/chromium/third_party/blink/renderer/core/html/custom/README.md
index d8cab10145c..74d4f3bf254 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/README.md
+++ b/chromium/third_party/blink/renderer/core/html/custom/README.md
@@ -80,12 +80,12 @@ with CustomElement so you can run them with:
$ out/Debug/webkit_unit_tests --gtest_filter=CustomElement*
-###### Layout Tests
+###### Web Tests
-The custom element layout tests are generally in
+The custom element web tests are generally in
third_party/blink/web_tests/custom-elements.
-All custom elements layout tests use the [web-platform-tests
+All custom elements web tests use the [web-platform-tests
harness](https://web-platform-tests.org/) and follow its style. The
WPT style is not very prescriptive, so be consistent with other custom
elements tests.
diff --git a/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.cc b/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.cc
index 574580d4ad1..0b1091407c7 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.cc
@@ -12,8 +12,8 @@ namespace blink {
CEReactionsScope* CEReactionsScope::top_of_stack_ = nullptr;
-void CEReactionsScope::EnqueueToCurrentQueue(Element* element,
- CustomElementReaction* reaction) {
+void CEReactionsScope::EnqueueToCurrentQueue(Element& element,
+ CustomElementReaction& reaction) {
if (!work_to_do_) {
work_to_do_ = true;
CustomElementReactionStack::Current().Push();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.h b/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.h
index beecfd45690..8578963d80b 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/ce_reactions_scope.h
@@ -33,7 +33,7 @@ class CORE_EXPORT CEReactionsScope final {
top_of_stack_ = top_of_stack_->prev_;
}
- void EnqueueToCurrentQueue(Element*, CustomElementReaction*);
+ void EnqueueToCurrentQueue(Element&, CustomElementReaction&);
private:
static CEReactionsScope* top_of_stack_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc
index 372e3ec5cb5..a7a6164af96 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
@@ -210,7 +210,7 @@ HTMLElement* CustomElement::CreateFailedElement(Document& document,
return element;
}
-void CustomElement::Enqueue(Element* element, CustomElementReaction* reaction) {
+void CustomElement::Enqueue(Element& element, CustomElementReaction& reaction) {
// To enqueue an element on the appropriate element queue
// https://html.spec.whatwg.org/multipage/scripting.html#enqueue-an-element-on-the-appropriate-element-queue
@@ -226,37 +226,32 @@ void CustomElement::Enqueue(Element* element, CustomElementReaction* reaction) {
CustomElementReactionStack::Current().EnqueueToBackupQueue(element, reaction);
}
-void CustomElement::EnqueueConnectedCallback(Element* element) {
- CustomElementDefinition* definition =
- DefinitionForElementWithoutCheck(*element);
+void CustomElement::EnqueueConnectedCallback(Element& element) {
+ auto* definition = DefinitionForElementWithoutCheck(element);
if (definition->HasConnectedCallback())
definition->EnqueueConnectedCallback(element);
}
-void CustomElement::EnqueueDisconnectedCallback(Element* element) {
- CustomElementDefinition* definition =
- DefinitionForElementWithoutCheck(*element);
+void CustomElement::EnqueueDisconnectedCallback(Element& element) {
+ auto* definition = DefinitionForElementWithoutCheck(element);
if (definition->HasDisconnectedCallback())
definition->EnqueueDisconnectedCallback(element);
}
-void CustomElement::EnqueueAdoptedCallback(Element* element,
- Document* old_owner,
- Document* new_owner) {
- DCHECK_EQ(element->GetCustomElementState(), CustomElementState::kCustom);
- CustomElementDefinition* definition =
- DefinitionForElementWithoutCheck(*element);
+void CustomElement::EnqueueAdoptedCallback(Element& element,
+ Document& old_owner,
+ Document& new_owner) {
+ auto* definition = DefinitionForElementWithoutCheck(element);
if (definition->HasAdoptedCallback())
definition->EnqueueAdoptedCallback(element, old_owner, new_owner);
}
void CustomElement::EnqueueAttributeChangedCallback(
- Element* element,
+ Element& element,
const QualifiedName& name,
const AtomicString& old_value,
const AtomicString& new_value) {
- CustomElementDefinition* definition =
- DefinitionForElementWithoutCheck(*element);
+ auto* definition = DefinitionForElementWithoutCheck(element);
if (definition->HasAttributeChangedCallback(name))
definition->EnqueueAttributeChangedCallback(element, name, old_value,
new_value);
@@ -265,29 +260,44 @@ void CustomElement::EnqueueAttributeChangedCallback(
void CustomElement::EnqueueFormAssociatedCallback(
Element& element,
HTMLFormElement* nullable_form) {
- auto* definition = DefinitionForElementWithoutCheck(element);
- if (definition->HasFormAssociatedCallback()) {
- Enqueue(&element,
- MakeGarbageCollected<CustomElementFormAssociatedCallbackReaction>(
- definition, nullable_form));
+ auto& definition = *DefinitionForElementWithoutCheck(element);
+ if (definition.HasFormAssociatedCallback()) {
+ Enqueue(element, CustomElementReactionFactory::CreateFormAssociated(
+ definition, nullable_form));
+ }
+}
+
+void CustomElement::EnqueueFormResetCallback(Element& element) {
+ auto& definition = *DefinitionForElementWithoutCheck(element);
+ if (definition.HasFormResetCallback()) {
+ Enqueue(element, CustomElementReactionFactory::CreateFormReset(definition));
+ }
+}
+
+void CustomElement::EnqueueDisabledStateChangedCallback(Element& element,
+ bool is_disabled) {
+ auto& definition = *DefinitionForElementWithoutCheck(element);
+ if (definition.HasDisabledStateChangedCallback()) {
+ Enqueue(element, CustomElementReactionFactory::CreateDisabledStateChanged(
+ definition, is_disabled));
}
}
-void CustomElement::TryToUpgrade(Element* element,
+void CustomElement::TryToUpgrade(Element& element,
bool upgrade_invisible_elements) {
// Try to upgrade an element
// https://html.spec.whatwg.org/multipage/scripting.html#concept-try-upgrade
- DCHECK_EQ(element->GetCustomElementState(), CustomElementState::kUndefined);
+ DCHECK_EQ(element.GetCustomElementState(), CustomElementState::kUndefined);
- CustomElementRegistry* registry = CustomElement::Registry(*element);
+ CustomElementRegistry* registry = CustomElement::Registry(element);
if (!registry)
return;
- const AtomicString& is_value = element->IsValue();
+ const AtomicString& is_value = element.IsValue();
if (CustomElementDefinition* definition =
registry->DefinitionFor(CustomElementDescriptor(
- is_value.IsNull() ? element->localName() : is_value,
- element->localName())))
+ is_value.IsNull() ? element.localName() : is_value,
+ element.localName())))
definition->EnqueueUpgradeReaction(element, upgrade_invisible_elements);
else
registry->AddCandidate(element);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element.h
index a7ce7c32af7..80c78fc3508 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element.h
@@ -94,20 +94,23 @@ class CORE_EXPORT CustomElement {
const AtomicString& is_value);
static HTMLElement* CreateFailedElement(Document&, const QualifiedName&);
- static void Enqueue(Element*, CustomElementReaction*);
- static void EnqueueConnectedCallback(Element*);
- static void EnqueueDisconnectedCallback(Element*);
- static void EnqueueAdoptedCallback(Element*,
- Document* old_owner,
- Document* new_owner);
- static void EnqueueAttributeChangedCallback(Element*,
+ static void Enqueue(Element&, CustomElementReaction&);
+ static void EnqueueConnectedCallback(Element&);
+ static void EnqueueDisconnectedCallback(Element&);
+ static void EnqueueAdoptedCallback(Element&,
+ Document& old_owner,
+ Document& new_owner);
+ static void EnqueueAttributeChangedCallback(Element&,
const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value);
static void EnqueueFormAssociatedCallback(Element& element,
HTMLFormElement* nullable_form);
+ static void EnqueueFormResetCallback(Element& element);
+ static void EnqueueDisabledStateChangedCallback(Element& element,
+ bool is_disabled);
- static void TryToUpgrade(Element*, bool upgrade_invisible_elements = false);
+ static void TryToUpgrade(Element&, bool upgrade_invisible_elements = false);
static void AddEmbedderCustomElementNameForTesting(const AtomicString& name,
ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.cc
deleted file mode 100644
index cf53c2e63a6..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.cc
+++ /dev/null
@@ -1,32 +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 "third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-
-namespace blink {
-
-CustomElementAdoptedCallbackReaction::CustomElementAdoptedCallbackReaction(
- CustomElementDefinition* definition,
- Document* old_owner,
- Document* new_owner)
- : CustomElementReaction(definition),
- old_owner_(old_owner),
- new_owner_(new_owner) {
- DCHECK(definition->HasAdoptedCallback());
-}
-
-void CustomElementAdoptedCallbackReaction::Trace(blink::Visitor* visitor) {
- CustomElementReaction::Trace(visitor);
- visitor->Trace(old_owner_);
- visitor->Trace(new_owner_);
-}
-
-void CustomElementAdoptedCallbackReaction::Invoke(Element* element) {
- definition_->RunAdoptedCallback(element, old_owner_.Get(), new_owner_.Get());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.h
deleted file mode 100644
index 399c033033e..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.h
+++ /dev/null
@@ -1,37 +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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_ADOPTED_CALLBACK_REACTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_ADOPTED_CALLBACK_REACTION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class Document;
-
-class CORE_EXPORT CustomElementAdoptedCallbackReaction final
- : public CustomElementReaction {
- public:
- CustomElementAdoptedCallbackReaction(CustomElementDefinition*,
- Document* old_owner,
- Document* new_owner);
-
- void Trace(blink::Visitor*) override;
-
- private:
- void Invoke(Element*) override;
-
- Member<Document> old_owner_;
- Member<Document> new_owner_;
-
- DISALLOW_COPY_AND_ASSIGN(CustomElementAdoptedCallbackReaction);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_ADOPTED_CALLBACK_REACTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.cc
deleted file mode 100644
index 8f892bd2bbb..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.cc
+++ /dev/null
@@ -1,29 +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 "third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.h"
-
-#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-
-namespace blink {
-
-CustomElementAttributeChangedCallbackReaction::
- CustomElementAttributeChangedCallbackReaction(
- CustomElementDefinition* definition,
- const QualifiedName& name,
- const AtomicString& old_value,
- const AtomicString& new_value)
- : CustomElementReaction(definition),
- name_(name),
- old_value_(old_value),
- new_value_(new_value) {
- DCHECK(definition->HasAttributeChangedCallback(name));
-}
-
-void CustomElementAttributeChangedCallbackReaction::Invoke(Element* element) {
- definition_->RunAttributeChangedCallback(element, name_, old_value_,
- new_value_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.h
deleted file mode 100644
index afd965dd3a4..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.h
+++ /dev/null
@@ -1,36 +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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_ATTRIBUTE_CHANGED_CALLBACK_REACTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_ATTRIBUTE_CHANGED_CALLBACK_REACTION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/dom/qualified_name.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class CORE_EXPORT CustomElementAttributeChangedCallbackReaction final
- : public CustomElementReaction {
- public:
- CustomElementAttributeChangedCallbackReaction(CustomElementDefinition*,
- const QualifiedName&,
- const AtomicString& old_value,
- const AtomicString& new_value);
-
- private:
- void Invoke(Element*) override;
-
- QualifiedName name_;
- AtomicString old_value_;
- AtomicString new_value_;
-
- DISALLOW_COPY_AND_ASSIGN(CustomElementAttributeChangedCallbackReaction);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_ATTRIBUTE_CHANGED_CALLBACK_REACTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.cc
deleted file mode 100644
index f5b7275670a..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.cc
+++ /dev/null
@@ -1,21 +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 "third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.h"
-
-#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-
-namespace blink {
-
-CustomElementConnectedCallbackReaction::CustomElementConnectedCallbackReaction(
- CustomElementDefinition* definition)
- : CustomElementReaction(definition) {
- DCHECK(definition->HasConnectedCallback());
-}
-
-void CustomElementConnectedCallbackReaction::Invoke(Element* element) {
- definition_->RunConnectedCallback(element);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.h
deleted file mode 100644
index 26b05014ee4..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.h
+++ /dev/null
@@ -1,28 +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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_CONNECTED_CALLBACK_REACTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_CONNECTED_CALLBACK_REACTION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class CORE_EXPORT CustomElementConnectedCallbackReaction final
- : public CustomElementReaction {
- public:
- CustomElementConnectedCallbackReaction(CustomElementDefinition*);
-
- private:
- void Invoke(Element*) override;
-
- DISALLOW_COPY_AND_ASSIGN(CustomElementConnectedCallbackReaction);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_CONNECTED_CALLBACK_REACTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
index 30979be3de3..62d852ab750 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
@@ -10,13 +10,9 @@
#include "third_party/blink/renderer/core/dom/attr.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/html/custom/custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_adopted_callback_reaction.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_attribute_changed_callback_reaction.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_connected_callback_reaction.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html_element_factory.h"
@@ -42,36 +38,36 @@ CustomElementDefinition::CustomElementDefinition(
CustomElementDefinition::~CustomElementDefinition() = default;
-void CustomElementDefinition::Trace(blink::Visitor* visitor) {
+void CustomElementDefinition::Trace(Visitor* visitor) {
visitor->Trace(construction_stack_);
visitor->Trace(default_style_sheets_);
}
-static String ErrorMessageForConstructorResult(Element* element,
+static String ErrorMessageForConstructorResult(Element& element,
Document& document,
const QualifiedName& tag_name) {
// https://dom.spec.whatwg.org/#concept-create-element
// 6.1.4. If result's attribute list is not empty, then throw a
// NotSupportedError.
- if (element->hasAttributes())
+ if (element.hasAttributes())
return "The result must not have attributes";
// 6.1.5. If result has children, then throw a NotSupportedError.
- if (element->HasChildren())
+ if (element.HasChildren())
return "The result must not have children";
// 6.1.6. If result's parent is not null, then throw a NotSupportedError.
- if (element->parentNode())
+ if (element.parentNode())
return "The result must not have a parent";
// 6.1.7. If result's node document is not document, then throw a
// NotSupportedError.
- if (&element->GetDocument() != &document)
+ if (&element.GetDocument() != &document)
return "The result must be in the same document";
// 6.1.8. If result's namespace is not the HTML namespace, then throw a
// NotSupportedError.
- if (element->namespaceURI() != html_names::xhtmlNamespaceURI)
+ if (element.namespaceURI() != html_names::xhtmlNamespaceURI)
return "The result must have HTML namespace";
// 6.1.9. If result's local name is not equal to localName, then throw a
// NotSupportedError.
- if (element->localName() != tag_name.LocalName())
+ if (element.localName() != tag_name.LocalName())
return "The result must have the same localName";
return String();
}
@@ -93,7 +89,7 @@ void CustomElementDefinition::CheckConstructorResult(
// 6.1.4. through 6.1.9.
const String message =
- ErrorMessageForConstructorResult(element, document, tag_name);
+ ErrorMessageForConstructorResult(*element, document, tag_name);
if (!message.IsEmpty()) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
message);
@@ -149,9 +145,9 @@ HTMLElement* CustomElementDefinition::CreateElement(
// 5.4. Otherwise, enqueue a custom element upgrade reaction given
// result and definition.
if (!flags.IsAsyncCustomElements())
- Upgrade(result);
+ Upgrade(*result);
else
- EnqueueUpgradeReaction(result);
+ EnqueueUpgradeReaction(*result);
return ToHTMLElement(result);
}
@@ -170,16 +166,16 @@ HTMLElement* CustomElementDefinition::CreateElement(
element->SetCustomElementState(CustomElementState::kUndefined);
// 6.2.2. Enqueue a custom element upgrade reaction given result and
// definition.
- EnqueueUpgradeReaction(element);
+ EnqueueUpgradeReaction(*element);
return element;
}
CustomElementDefinition::ConstructionStackScope::ConstructionStackScope(
- CustomElementDefinition* definition,
- Element* element)
- : construction_stack_(definition->construction_stack_), element_(element) {
+ CustomElementDefinition& definition,
+ Element& element)
+ : construction_stack_(definition.construction_stack_), element_(element) {
// Push the construction stack.
- construction_stack_.push_back(element);
+ construction_stack_.push_back(&element);
depth_ = construction_stack_.size();
}
@@ -191,31 +187,31 @@ CustomElementDefinition::ConstructionStackScope::~ConstructionStackScope() {
}
// https://html.spec.whatwg.org/multipage/scripting.html#concept-upgrade-an-element
-void CustomElementDefinition::Upgrade(Element* element) {
- DCHECK_EQ(element->GetCustomElementState(), CustomElementState::kUndefined);
+void CustomElementDefinition::Upgrade(Element& element) {
+ DCHECK_EQ(element.GetCustomElementState(), CustomElementState::kUndefined);
if (!observed_attributes_.IsEmpty())
EnqueueAttributeChangedCallbackForAllAttributes(element);
- if (element->isConnected() && HasConnectedCallback())
+ if (element.isConnected() && HasConnectedCallback())
EnqueueConnectedCallback(element);
bool succeeded = false;
{
- ConstructionStackScope construction_stack_scope(this, element);
+ ConstructionStackScope construction_stack_scope(*this, element);
succeeded = RunConstructor(element);
}
if (!succeeded) {
- element->SetCustomElementState(CustomElementState::kFailed);
+ element.SetCustomElementState(CustomElementState::kFailed);
CustomElementReactionStack::Current().ClearQueue(element);
return;
}
- element->SetCustomElementDefinition(this);
+ element.SetCustomElementDefinition(this);
if (IsFormAssociated())
- ToHTMLElement(element)->EnsureElementInternals().DidUpgrade();
- AddDefaultStylesTo(*element);
+ ToHTMLElement(element).EnsureElementInternals().DidUpgrade();
+ AddDefaultStylesTo(element);
}
void CustomElementDefinition::AddDefaultStylesTo(Element& element) {
@@ -254,48 +250,47 @@ bool CustomElementDefinition::HasStyleAttributeChangedCallback() const {
}
void CustomElementDefinition::EnqueueUpgradeReaction(
- Element* element,
+ Element& element,
bool upgrade_invisible_elements) {
- CustomElement::Enqueue(element, new CustomElementUpgradeReaction(
- this, upgrade_invisible_elements));
+ CustomElement::Enqueue(element, CustomElementReactionFactory::CreateUpgrade(
+ *this, upgrade_invisible_elements));
}
-void CustomElementDefinition::EnqueueConnectedCallback(Element* element) {
+void CustomElementDefinition::EnqueueConnectedCallback(Element& element) {
CustomElement::Enqueue(element,
- new CustomElementConnectedCallbackReaction(this));
+ CustomElementReactionFactory::CreateConnected(*this));
}
-void CustomElementDefinition::EnqueueDisconnectedCallback(Element* element) {
- CustomElement::Enqueue(element,
- new CustomElementDisconnectedCallbackReaction(this));
+void CustomElementDefinition::EnqueueDisconnectedCallback(Element& element) {
+ CustomElement::Enqueue(
+ element, CustomElementReactionFactory::CreateDisconnected(*this));
}
-void CustomElementDefinition::EnqueueAdoptedCallback(Element* element,
- Document* old_document,
- Document* new_document) {
- CustomElementReaction* reaction = new CustomElementAdoptedCallbackReaction(
- this, old_document, new_document);
- CustomElement::Enqueue(element, reaction);
+void CustomElementDefinition::EnqueueAdoptedCallback(Element& element,
+ Document& old_document,
+ Document& new_document) {
+ CustomElement::Enqueue(element, CustomElementReactionFactory::CreateAdopted(
+ *this, old_document, new_document));
}
void CustomElementDefinition::EnqueueAttributeChangedCallback(
- Element* element,
+ Element& element,
const QualifiedName& name,
const AtomicString& old_value,
const AtomicString& new_value) {
CustomElement::Enqueue(element,
- new CustomElementAttributeChangedCallbackReaction(
- this, name, old_value, new_value));
+ CustomElementReactionFactory::CreateAttributeChanged(
+ *this, name, old_value, new_value));
}
void CustomElementDefinition::EnqueueAttributeChangedCallbackForAllAttributes(
- Element* element) {
+ Element& element) {
// Avoid synchronizing all attributes unless it is needed, while enqueing
// callbacks "in order" as defined in the spec.
// https://html.spec.whatwg.org/multipage/scripting.html#concept-upgrade-an-element
for (const AtomicString& name : observed_attributes_)
- element->SynchronizeAttribute(name);
- for (const auto& attribute : element->AttributesWithoutUpdate()) {
+ element.SynchronizeAttribute(name);
+ for (const auto& attribute : element.AttributesWithoutUpdate()) {
if (HasAttributeChangedCallback(attribute.GetName())) {
EnqueueAttributeChangedCallback(element, attribute.GetName(), g_null_atom,
attribute.Value());
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.h
index f94bf3ae33b..a47ce0f3efb 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition.h
@@ -41,7 +41,7 @@ class CORE_EXPORT CustomElementDefinition
virtual ~CustomElementDefinition();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
const char* NameInHeapSnapshot() const override {
return "CustomElementDefinition";
}
@@ -67,7 +67,7 @@ class CORE_EXPORT CustomElementDefinition
const QualifiedName&,
const CreateElementFlags);
- void Upgrade(Element*);
+ void Upgrade(Element&);
virtual bool HasConnectedCallback() const = 0;
virtual bool HasDisconnectedCallback() const = 0;
@@ -75,30 +75,32 @@ class CORE_EXPORT CustomElementDefinition
bool HasAttributeChangedCallback(const QualifiedName&) const;
bool HasStyleAttributeChangedCallback() const;
virtual bool HasFormAssociatedCallback() const = 0;
+ virtual bool HasFormResetCallback() const = 0;
virtual bool HasDisabledStateChangedCallback() const = 0;
- virtual void RunConnectedCallback(Element*) = 0;
- virtual void RunDisconnectedCallback(Element*) = 0;
- virtual void RunAdoptedCallback(Element*,
- Document* old_owner,
- Document* new_owner) = 0;
- virtual void RunAttributeChangedCallback(Element*,
+ virtual void RunConnectedCallback(Element&) = 0;
+ virtual void RunDisconnectedCallback(Element&) = 0;
+ virtual void RunAdoptedCallback(Element&,
+ Document& old_owner,
+ Document& new_owner) = 0;
+ virtual void RunAttributeChangedCallback(Element&,
const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value) = 0;
- virtual void RunFormAssociatedCallback(Element* element,
+ virtual void RunFormAssociatedCallback(Element& element,
HTMLFormElement* nullable_form) = 0;
- virtual void RunDisabledStateChangedCallback(Element* element,
+ virtual void RunFormResetCallback(Element& element) = 0;
+ virtual void RunDisabledStateChangedCallback(Element& element,
bool is_disabled) = 0;
- void EnqueueUpgradeReaction(Element*,
+ void EnqueueUpgradeReaction(Element&,
bool upgrade_invisible_elements = false);
- void EnqueueConnectedCallback(Element*);
- void EnqueueDisconnectedCallback(Element*);
- void EnqueueAdoptedCallback(Element*,
- Document* old_owner,
- Document* new_owner);
- void EnqueueAttributeChangedCallback(Element*,
+ void EnqueueConnectedCallback(Element&);
+ void EnqueueDisconnectedCallback(Element&);
+ void EnqueueAdoptedCallback(Element&,
+ Document& old_owner,
+ Document& new_owner);
+ void EnqueueAttributeChangedCallback(Element&,
const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value);
@@ -123,7 +125,7 @@ class CORE_EXPORT CustomElementDefinition
DISALLOW_COPY_AND_ASSIGN(ConstructionStackScope);
public:
- ConstructionStackScope(CustomElementDefinition*, Element*);
+ ConstructionStackScope(CustomElementDefinition&, Element&);
~ConstructionStackScope();
private:
@@ -142,7 +144,7 @@ class CORE_EXPORT CustomElementDefinition
void AddDefaultStylesTo(Element&);
- virtual bool RunConstructor(Element*) = 0;
+ virtual bool RunConstructor(Element&) = 0;
static void CheckConstructorResult(Element*,
Document&,
@@ -160,7 +162,7 @@ class CORE_EXPORT CustomElementDefinition
HeapVector<Member<CSSStyleSheet>> default_style_sheets_;
- void EnqueueAttributeChangedCallbackForAllAttributes(Element*);
+ void EnqueueAttributeChangedCallbackForAllAttributes(Element&);
DISALLOW_COPY_AND_ASSIGN(CustomElementDefinition);
};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
index 07d98d1445b..404a9472907 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
@@ -21,7 +21,7 @@ class ConstructorFails : public TestCustomElementDefinition {
ConstructorFails(const CustomElementDescriptor& descriptor)
: TestCustomElementDefinition(descriptor) {}
~ConstructorFails() override = default;
- bool RunConstructor(Element*) override { return false; }
+ bool RunConstructor(Element&) override { return false; }
DISALLOW_COPY_AND_ASSIGN(ConstructorFails);
};
@@ -29,8 +29,8 @@ class ConstructorFails : public TestCustomElementDefinition {
} // namespace
TEST(CustomElementDefinitionTest, upgrade_clearsReactionQueueOnFailure) {
- Element* element = CreateElement("a-a");
- EXPECT_EQ(CustomElementState::kUndefined, element->GetCustomElementState())
+ Element& element = *CreateElement("a-a");
+ EXPECT_EQ(CustomElementState::kUndefined, element.GetCustomElementState())
<< "sanity check: this element should be ready to upgrade";
{
CEReactionsScope reactions;
@@ -39,18 +39,18 @@ TEST(CustomElementDefinitionTest, upgrade_clearsReactionQueueOnFailure) {
commands->push_back(MakeGarbageCollected<Unreached>(
"upgrade failure should clear the reaction queue"));
reactions.EnqueueToCurrentQueue(
- element, MakeGarbageCollected<TestReaction>(commands));
+ element, *MakeGarbageCollected<TestReaction>(commands));
ConstructorFails definition(CustomElementDescriptor("a-a", "a-a"));
definition.Upgrade(element);
}
- EXPECT_EQ(CustomElementState::kFailed, element->GetCustomElementState())
+ EXPECT_EQ(CustomElementState::kFailed, element.GetCustomElementState())
<< "failing to construct should have set the 'failed' element state";
}
TEST(CustomElementDefinitionTest,
upgrade_clearsReactionQueueOnFailure_backupStack) {
- Element* element = CreateElement("a-a");
- EXPECT_EQ(CustomElementState::kUndefined, element->GetCustomElementState())
+ Element& element = *CreateElement("a-a");
+ EXPECT_EQ(CustomElementState::kUndefined, element.GetCustomElementState())
<< "sanity check: this element should be ready to upgrade";
ResetCustomElementReactionStackForTest reset_reaction_stack;
HeapVector<Member<Command>>* commands =
@@ -58,10 +58,10 @@ TEST(CustomElementDefinitionTest,
commands->push_back(MakeGarbageCollected<Unreached>(
"upgrade failure should clear the reaction queue"));
reset_reaction_stack.Stack().EnqueueToBackupQueue(
- element, MakeGarbageCollected<TestReaction>(commands));
+ element, *MakeGarbageCollected<TestReaction>(commands));
ConstructorFails definition(CustomElementDescriptor("a-a", "a-a"));
definition.Upgrade(element);
- EXPECT_EQ(CustomElementState::kFailed, element->GetCustomElementState())
+ EXPECT_EQ(CustomElementState::kFailed, element.GetCustomElementState())
<< "failing to construct should have set the 'failed' element state";
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.cc
deleted file mode 100644
index 7a64879a040..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.cc
+++ /dev/null
@@ -1,22 +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 "third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.h"
-
-#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-
-namespace blink {
-
-CustomElementDisconnectedCallbackReaction::
- CustomElementDisconnectedCallbackReaction(
- CustomElementDefinition* definition)
- : CustomElementReaction(definition) {
- DCHECK(definition->HasDisconnectedCallback());
-}
-
-void CustomElementDisconnectedCallbackReaction::Invoke(Element* element) {
- definition_->RunDisconnectedCallback(element);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.h
deleted file mode 100644
index 1260f9ddf86..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_disconnected_callback_reaction.h
+++ /dev/null
@@ -1,28 +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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_DISCONNECTED_CALLBACK_REACTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_DISCONNECTED_CALLBACK_REACTION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class CORE_EXPORT CustomElementDisconnectedCallbackReaction final
- : public CustomElementReaction {
- public:
- CustomElementDisconnectedCallbackReaction(CustomElementDefinition*);
-
- private:
- void Invoke(Element*) override;
-
- DISALLOW_COPY_AND_ASSIGN(CustomElementDisconnectedCallbackReaction);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_DISCONNECTED_CALLBACK_REACTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.cc
deleted file mode 100644
index dc77d5c9cdf..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
-
-namespace blink {
-
-CustomElementFormAssociatedCallbackReaction::
- CustomElementFormAssociatedCallbackReaction(
- CustomElementDefinition* definition,
- HTMLFormElement* nullable_form)
- : CustomElementReaction(definition), form_(nullable_form) {
- DCHECK(definition->HasFormAssociatedCallback());
-}
-
-void CustomElementFormAssociatedCallbackReaction::Trace(Visitor* visitor) {
- visitor->Trace(form_);
- CustomElementReaction::Trace(visitor);
-}
-
-void CustomElementFormAssociatedCallbackReaction::Invoke(Element* element) {
- definition_->RunFormAssociatedCallback(element, form_.Get());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.h
deleted file mode 100644
index 01d1d1b2de3..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_form_associated_callback_reaction.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_FORM_ASSOCIATED_CALLBACK_REACTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_FORM_ASSOCIATED_CALLBACK_REACTION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
-
-namespace blink {
-
-class HTMLFormElement;
-
-class CustomElementFormAssociatedCallbackReaction final
- : public CustomElementReaction {
- public:
- CustomElementFormAssociatedCallbackReaction(CustomElementDefinition*,
- HTMLFormElement* nullable_form);
- void Trace(Visitor*) override;
-
- private:
- void Invoke(Element*) override;
-
- Member<HTMLFormElement> form_;
-
- DISALLOW_COPY_AND_ASSIGN(CustomElementFormAssociatedCallbackReaction);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_FORM_ASSOCIATED_CALLBACK_REACTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.cc
index f512d384d48..dd88199be20 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.cc
@@ -9,10 +9,10 @@
namespace blink {
CustomElementReaction::CustomElementReaction(
- CustomElementDefinition* definition)
+ CustomElementDefinition& definition)
: definition_(definition) {}
-void CustomElementReaction::Trace(blink::Visitor* visitor) {
+void CustomElementReaction::Trace(Visitor* visitor) {
visitor->Trace(definition_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.h
index 2ae6f586878..d83fecfd726 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction.h
@@ -17,12 +17,12 @@ class Element;
class CORE_EXPORT CustomElementReaction
: public GarbageCollectedFinalized<CustomElementReaction> {
public:
- CustomElementReaction(CustomElementDefinition*);
+ CustomElementReaction(CustomElementDefinition&);
virtual ~CustomElementReaction() = default;
- virtual void Invoke(Element*) = 0;
+ virtual void Invoke(Element&) = 0;
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
protected:
Member<CustomElementDefinition> definition_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.cc
new file mode 100644
index 00000000000..a24a72a9fd8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.cc
@@ -0,0 +1,264 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
+#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
+
+namespace blink {
+
+class CustomElementUpgradeReaction final : public CustomElementReaction {
+ public:
+ CustomElementUpgradeReaction(CustomElementDefinition& definition,
+ bool upgrade_invisible_elements)
+ : CustomElementReaction(definition),
+ upgrade_invisible_elements_(upgrade_invisible_elements) {}
+
+ private:
+ void Invoke(Element& element) override {
+ // Don't call Upgrade() if it's already upgraded. Multiple upgrade reactions
+ // could be enqueued because the state changes in step 10 of upgrades.
+ // https://html.spec.whatwg.org/multipage/scripting.html#upgrades
+ if (element.GetCustomElementState() == CustomElementState::kUndefined) {
+ // Don't upgrade elements inside an invisible-static tree, unless it was
+ // triggered by CustomElementRegistry::upgrade.
+ if (!RuntimeEnabledFeatures::InvisibleDOMEnabled() ||
+ !element.IsInsideInvisibleStaticSubtree() ||
+ upgrade_invisible_elements_)
+ definition_->Upgrade(element);
+ }
+ }
+
+ bool upgrade_invisible_elements_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementUpgradeReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementConnectedCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementConnectedCallbackReaction(CustomElementDefinition& definition)
+ : CustomElementReaction(definition) {
+ DCHECK(definition.HasConnectedCallback());
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunConnectedCallback(element);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementConnectedCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementDisconnectedCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementDisconnectedCallbackReaction(CustomElementDefinition& definition)
+ : CustomElementReaction(definition) {
+ DCHECK(definition.HasDisconnectedCallback());
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunDisconnectedCallback(element);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementDisconnectedCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementAdoptedCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementAdoptedCallbackReaction(CustomElementDefinition& definition,
+ Document& old_owner,
+ Document& new_owner)
+ : CustomElementReaction(definition),
+ old_owner_(old_owner),
+ new_owner_(new_owner) {
+ DCHECK(definition.HasAdoptedCallback());
+ }
+
+ void Trace(Visitor* visitor) override {
+ visitor->Trace(old_owner_);
+ visitor->Trace(new_owner_);
+ CustomElementReaction::Trace(visitor);
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunAdoptedCallback(element, *old_owner_, *new_owner_);
+ }
+
+ Member<Document> old_owner_;
+ Member<Document> new_owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementAdoptedCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementAttributeChangedCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementAttributeChangedCallbackReaction(
+ CustomElementDefinition& definition,
+ const QualifiedName& name,
+ const AtomicString& old_value,
+ const AtomicString& new_value)
+ : CustomElementReaction(definition),
+ name_(name),
+ old_value_(old_value),
+ new_value_(new_value) {
+ DCHECK(definition.HasAttributeChangedCallback(name));
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunAttributeChangedCallback(element, name_, old_value_,
+ new_value_);
+ }
+
+ QualifiedName name_;
+ AtomicString old_value_;
+ AtomicString new_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementAttributeChangedCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementFormAssociatedCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementFormAssociatedCallbackReaction(
+ CustomElementDefinition& definition,
+ HTMLFormElement* nullable_form)
+ : CustomElementReaction(definition), form_(nullable_form) {
+ DCHECK(definition.HasFormAssociatedCallback());
+ }
+
+ void Trace(Visitor* visitor) override {
+ visitor->Trace(form_);
+ CustomElementReaction::Trace(visitor);
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunFormAssociatedCallback(element, form_.Get());
+ }
+
+ Member<HTMLFormElement> form_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementFormAssociatedCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementFormResetCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementFormResetCallbackReaction(CustomElementDefinition& definition)
+ : CustomElementReaction(definition) {
+ DCHECK(definition.HasFormResetCallback());
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunFormResetCallback(element);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementFormResetCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+class CustomElementDisabledStateChangedCallbackReaction final
+ : public CustomElementReaction {
+ public:
+ CustomElementDisabledStateChangedCallbackReaction(
+ CustomElementDefinition& definition,
+ bool is_disabled)
+ : CustomElementReaction(definition), is_disabled_(is_disabled) {
+ DCHECK(definition.HasDisabledStateChangedCallback());
+ }
+
+ private:
+ void Invoke(Element& element) override {
+ definition_->RunDisabledStateChangedCallback(element, is_disabled_);
+ }
+
+ bool is_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomElementDisabledStateChangedCallbackReaction);
+};
+
+// ----------------------------------------------------------------
+
+CustomElementReaction& CustomElementReactionFactory::CreateUpgrade(
+ CustomElementDefinition& definition,
+ bool upgrade_invisible_elements) {
+ return *MakeGarbageCollected<CustomElementUpgradeReaction>(
+ definition, upgrade_invisible_elements);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateConnected(
+ CustomElementDefinition& definition) {
+ return *MakeGarbageCollected<CustomElementConnectedCallbackReaction>(
+ definition);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateDisconnected(
+ CustomElementDefinition& definition) {
+ return *MakeGarbageCollected<CustomElementDisconnectedCallbackReaction>(
+ definition);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateAdopted(
+ CustomElementDefinition& definition,
+ Document& old_owner,
+ Document& new_owner) {
+ return *MakeGarbageCollected<CustomElementAdoptedCallbackReaction>(
+ definition, old_owner, new_owner);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateAttributeChanged(
+ CustomElementDefinition& definition,
+ const QualifiedName& name,
+ const AtomicString& old_value,
+ const AtomicString& new_value) {
+ return *MakeGarbageCollected<CustomElementAttributeChangedCallbackReaction>(
+ definition, name, old_value, new_value);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateFormAssociated(
+ CustomElementDefinition& definition,
+ HTMLFormElement* nullable_form) {
+ return *MakeGarbageCollected<CustomElementFormAssociatedCallbackReaction>(
+ definition, nullable_form);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateFormReset(
+ CustomElementDefinition& definition) {
+ return *MakeGarbageCollected<CustomElementFormResetCallbackReaction>(
+ definition);
+}
+
+CustomElementReaction& CustomElementReactionFactory::CreateDisabledStateChanged(
+ CustomElementDefinition& definition,
+ bool is_disabled) {
+ return *MakeGarbageCollected<
+ CustomElementDisabledStateChangedCallbackReaction>(definition,
+ is_disabled);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h
new file mode 100644
index 00000000000..d1312a453c2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_REACTION_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_REACTION_FACTORY_H_
+
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class CustomElementDefinition;
+class CustomElementReaction;
+class Document;
+class HTMLFormElement;
+class QualifiedName;
+
+class CustomElementReactionFactory {
+ STATIC_ONLY(CustomElementReactionFactory);
+
+ public:
+ static CustomElementReaction& CreateUpgrade(
+ CustomElementDefinition& definition,
+ bool upgrade_invisible_elements);
+ static CustomElementReaction& CreateConnected(
+ CustomElementDefinition& definition);
+ static CustomElementReaction& CreateDisconnected(
+ CustomElementDefinition& definition);
+ static CustomElementReaction& CreateAdopted(
+ CustomElementDefinition& definition,
+ Document& old_owner,
+ Document& new_owner);
+ static CustomElementReaction& CreateAttributeChanged(
+ CustomElementDefinition& definition,
+ const QualifiedName& name,
+ const AtomicString& old_value,
+ const AtomicString& new_value);
+ static CustomElementReaction& CreateFormAssociated(
+ CustomElementDefinition& definition,
+ HTMLFormElement* nullable_form);
+ static CustomElementReaction& CreateFormReset(
+ CustomElementDefinition& definition);
+ static CustomElementReaction& CreateDisabledStateChanged(
+ CustomElementDefinition& definition,
+ bool is_disabled);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_REACTION_FACTORY_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc
index 0691daeff4d..386f02a9746 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc
@@ -14,19 +14,19 @@ CustomElementReactionQueue::CustomElementReactionQueue() : index_(0u) {}
CustomElementReactionQueue::~CustomElementReactionQueue() = default;
-void CustomElementReactionQueue::Trace(blink::Visitor* visitor) {
+void CustomElementReactionQueue::Trace(Visitor* visitor) {
visitor->Trace(reactions_);
}
-void CustomElementReactionQueue::Add(CustomElementReaction* reaction) {
- reactions_.push_back(reaction);
+void CustomElementReactionQueue::Add(CustomElementReaction& reaction) {
+ reactions_.push_back(&reaction);
}
// There is one queue per element, so this could be invoked
// recursively.
-void CustomElementReactionQueue::InvokeReactions(Element* element) {
+void CustomElementReactionQueue::InvokeReactions(Element& element) {
TRACE_EVENT1("blink", "CustomElementReactionQueue::invokeReactions", "name",
- element->localName().Utf8());
+ element.localName().Utf8());
while (index_ < reactions_.size()) {
CustomElementReaction* reaction = reactions_[index_];
reactions_[index_++] = nullptr;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h
index 50a3b13f31b..04910fae5cb 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h
@@ -20,10 +20,10 @@ class CORE_EXPORT CustomElementReactionQueue final
CustomElementReactionQueue();
~CustomElementReactionQueue();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
- void Add(CustomElementReaction*);
- void InvokeReactions(Element*);
+ void Add(CustomElementReaction&);
+ void InvokeReactions(Element&);
bool IsEmpty() { return reactions_.IsEmpty(); }
void Clear();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
index 651efd1e45e..b0d1320dc90 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
@@ -9,6 +9,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -16,45 +17,50 @@ namespace blink {
TEST(CustomElementReactionQueueTest, invokeReactions_one) {
std::vector<char> log;
- CustomElementReactionQueue* queue = new CustomElementReactionQueue();
+ CustomElementReactionQueue* queue =
+ MakeGarbageCollected<CustomElementReactionQueue>();
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
- queue->InvokeReactions(nullptr);
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ Element* test_element = CreateElement(AtomicString("my-element"));
+ queue->InvokeReactions(*test_element);
EXPECT_EQ(log, std::vector<char>({'a'}))
<< "the reaction should have been invoked";
}
TEST(CustomElementReactionQueueTest, invokeReactions_many) {
std::vector<char> log;
- CustomElementReactionQueue* queue = new CustomElementReactionQueue();
+ CustomElementReactionQueue* queue =
+ MakeGarbageCollected<CustomElementReactionQueue>();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('b', log));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('c', log));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
}
- queue->InvokeReactions(nullptr);
+ Element* test_element = CreateElement(AtomicString("my-element"));
+ queue->InvokeReactions(*test_element);
EXPECT_EQ(log, std::vector<char>({'a', 'b', 'c'}))
<< "the reaction should have been invoked";
}
TEST(CustomElementReactionQueueTest, invokeReactions_recursive) {
std::vector<char> log;
- CustomElementReactionQueue* queue = new CustomElementReactionQueue();
+ CustomElementReactionQueue* queue =
+ MakeGarbageCollected<CustomElementReactionQueue>();
HeapVector<Member<Command>>* third_commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
@@ -78,38 +84,41 @@ TEST(CustomElementReactionQueueTest, invokeReactions_recursive) {
CustomElementReaction* first = MakeGarbageCollected<TestReaction>(
first_commands); // Non-empty recursion
- queue->Add(first);
- queue->InvokeReactions(nullptr);
+ queue->Add(*first);
+ Element* test_element = CreateElement(AtomicString("my-element"));
+ queue->InvokeReactions(*test_element);
EXPECT_EQ(log, std::vector<char>({'a', 'b', 'c'}))
<< "the reactions should have been invoked";
}
TEST(CustomElementReactionQueueTest, clear_duringInvoke) {
std::vector<char> log;
- CustomElementReactionQueue* queue = new CustomElementReactionQueue();
+ CustomElementReactionQueue* queue =
+ MakeGarbageCollected<CustomElementReactionQueue>();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(new Call(WTF::Bind(
- [](CustomElementReactionQueue* queue, Element*) { queue->Clear(); },
+ commands->push_back(MakeGarbageCollected<Call>(WTF::Bind(
+ [](CustomElementReactionQueue* queue, Element&) { queue->Clear(); },
WrapPersistent(queue))));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('b', log));
- queue->Add(MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(commands));
}
- queue->InvokeReactions(nullptr);
+ Element* test_element = CreateElement(AtomicString("my-element"));
+ queue->InvokeReactions(*test_element);
EXPECT_EQ(log, std::vector<char>({'a'}))
<< "only 'a' should be logged; the second log should have been cleared";
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.cc
index 48b65d63226..da990e89831 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.cc
@@ -17,7 +17,7 @@ namespace {
Persistent<CustomElementReactionStack>& GetCustomElementReactionStack() {
DEFINE_STATIC_LOCAL(Persistent<CustomElementReactionStack>,
custom_element_reaction_stack,
- (new CustomElementReactionStack));
+ (MakeGarbageCollected<CustomElementReactionStack>()));
return custom_element_reaction_stack;
}
@@ -28,7 +28,7 @@ Persistent<CustomElementReactionStack>& GetCustomElementReactionStack() {
CustomElementReactionStack::CustomElementReactionStack() = default;
-void CustomElementReactionStack::Trace(blink::Visitor* visitor) {
+void CustomElementReactionStack::Trace(Visitor* visitor) {
visitor->Trace(map_);
visitor->Trace(stack_);
visitor->Trace(backup_queue_);
@@ -49,7 +49,7 @@ void CustomElementReactionStack::InvokeReactions(ElementQueue& queue) {
for (wtf_size_t i = 0; i < queue.size(); ++i) {
Element* element = queue[i];
if (CustomElementReactionQueue* reactions = map_.at(element)) {
- reactions->InvokeReactions(element);
+ reactions->InvokeReactions(*element);
CHECK(reactions->IsEmpty());
map_.erase(element);
}
@@ -57,30 +57,30 @@ void CustomElementReactionStack::InvokeReactions(ElementQueue& queue) {
}
void CustomElementReactionStack::EnqueueToCurrentQueue(
- Element* element,
- CustomElementReaction* reaction) {
+ Element& element,
+ CustomElementReaction& reaction) {
Enqueue(stack_.back(), element, reaction);
}
void CustomElementReactionStack::Enqueue(Member<ElementQueue>& queue,
- Element* element,
- CustomElementReaction* reaction) {
+ Element& element,
+ CustomElementReaction& reaction) {
if (!queue)
queue = MakeGarbageCollected<ElementQueue>();
- queue->push_back(element);
+ queue->push_back(&element);
- CustomElementReactionQueue* reactions = map_.at(element);
+ CustomElementReactionQueue* reactions = map_.at(&element);
if (!reactions) {
- reactions = new CustomElementReactionQueue();
- map_.insert(element, reactions);
+ reactions = MakeGarbageCollected<CustomElementReactionQueue>();
+ map_.insert(&element, reactions);
}
reactions->Add(reaction);
}
void CustomElementReactionStack::EnqueueToBackupQueue(
- Element* element,
- CustomElementReaction* reaction) {
+ Element& element,
+ CustomElementReaction& reaction) {
// https://html.spec.whatwg.org/multipage/scripting.html#backup-element-queue
DCHECK(!CEReactionsScope::Current());
@@ -97,8 +97,8 @@ void CustomElementReactionStack::EnqueueToBackupQueue(
Enqueue(backup_queue_, element, reaction);
}
-void CustomElementReactionStack::ClearQueue(Element* element) {
- if (CustomElementReactionQueue* reactions = map_.at(element))
+void CustomElementReactionStack::ClearQueue(Element& element) {
+ if (CustomElementReactionQueue* reactions = map_.at(&element))
reactions->Clear();
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h
index d90aa9cc631..b445589da29 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h
@@ -23,16 +23,16 @@ class CORE_EXPORT CustomElementReactionStack final
public:
CustomElementReactionStack();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
const char* NameInHeapSnapshot() const override {
return "CustomElementReactionStack";
}
void Push();
void PopInvokingReactions();
- void EnqueueToCurrentQueue(Element*, CustomElementReaction*);
- void EnqueueToBackupQueue(Element*, CustomElementReaction*);
- void ClearQueue(Element*);
+ void EnqueueToCurrentQueue(Element&, CustomElementReaction&);
+ void EnqueueToBackupQueue(Element&, CustomElementReaction&);
+ void ClearQueue(Element&);
static CustomElementReactionStack& Current();
@@ -50,7 +50,7 @@ class CORE_EXPORT CustomElementReactionStack final
void InvokeBackupQueue();
void InvokeReactions(ElementQueue&);
- void Enqueue(Member<ElementQueue>&, Element*, CustomElementReaction*);
+ void Enqueue(Member<ElementQueue>&, Element&, CustomElementReaction&);
DISALLOW_COPY_AND_ASSIGN(CustomElementReactionStack);
};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
index 49ec44d502d..b46132e7054 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
@@ -19,13 +19,14 @@ namespace blink {
TEST(CustomElementReactionStackTest, one) {
std::vector<char> log;
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
stack->PopInvokingReactions();
EXPECT_EQ(log, std::vector<char>({'a'}))
@@ -35,21 +36,22 @@ TEST(CustomElementReactionStackTest, one) {
TEST(CustomElementReactionStackTest, multipleElements) {
std::vector<char> log;
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('b', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->PopInvokingReactions();
@@ -60,13 +62,14 @@ TEST(CustomElementReactionStackTest, multipleElements) {
TEST(CustomElementReactionStackTest, popTopEmpty) {
std::vector<char> log;
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
stack->Push();
stack->PopInvokingReactions();
@@ -77,22 +80,23 @@ TEST(CustomElementReactionStackTest, popTopEmpty) {
TEST(CustomElementReactionStackTest, popTop) {
std::vector<char> log;
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->Push();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('b', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->PopInvokingReactions();
@@ -103,30 +107,31 @@ TEST(CustomElementReactionStackTest, popTop) {
TEST(CustomElementReactionStackTest, requeueingDoesNotReorderElements) {
std::vector<char> log;
- Element* element = CreateElement("a");
+ Element& element = *CreateElement("a");
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
stack->EnqueueToCurrentQueue(element,
- MakeGarbageCollected<TestReaction>(commands));
+ *MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('z', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('b', log));
stack->EnqueueToCurrentQueue(element,
- MakeGarbageCollected<TestReaction>(commands));
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->PopInvokingReactions();
@@ -137,38 +142,39 @@ TEST(CustomElementReactionStackTest, requeueingDoesNotReorderElements) {
TEST(CustomElementReactionStackTest, oneReactionQueuePerElement) {
std::vector<char> log;
- Element* element = CreateElement("a");
+ Element& element = *CreateElement("a");
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('a', log));
stack->EnqueueToCurrentQueue(element,
- MakeGarbageCollected<TestReaction>(commands));
+ *MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('z', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->Push();
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('y', log));
- stack->EnqueueToCurrentQueue(CreateElement("a"),
- MakeGarbageCollected<TestReaction>(commands));
+ stack->EnqueueToCurrentQueue(*CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(commands));
}
{
HeapVector<Member<Command>>* commands =
MakeGarbageCollected<HeapVector<Member<Command>>>();
commands->push_back(MakeGarbageCollected<Log>('b', log));
stack->EnqueueToCurrentQueue(element,
- MakeGarbageCollected<TestReaction>(commands));
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->PopInvokingReactions();
@@ -183,18 +189,18 @@ TEST(CustomElementReactionStackTest, oneReactionQueuePerElement) {
class EnqueueToStack : public Command {
public:
EnqueueToStack(CustomElementReactionStack* stack,
- Element* element,
+ Element& element,
CustomElementReaction* reaction)
: stack_(stack), element_(element), reaction_(reaction) {}
~EnqueueToStack() override = default;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
Command::Trace(visitor);
visitor->Trace(stack_);
visitor->Trace(element_);
visitor->Trace(reaction_);
}
- void Run(Element*) override {
- stack_->EnqueueToCurrentQueue(element_, reaction_);
+ void Run(Element&) override {
+ stack_->EnqueueToCurrentQueue(*element_, *reaction_);
}
private:
@@ -208,9 +214,10 @@ class EnqueueToStack : public Command {
TEST(CustomElementReactionStackTest, enqueueFromReaction) {
std::vector<char> log;
- Element* element = CreateElement("a");
+ Element& element = *CreateElement("a");
- CustomElementReactionStack* stack = new CustomElementReactionStack();
+ CustomElementReactionStack* stack =
+ MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
HeapVector<Member<Command>>* subcommands =
@@ -221,7 +228,7 @@ TEST(CustomElementReactionStackTest, enqueueFromReaction) {
commands->push_back(MakeGarbageCollected<EnqueueToStack>(
stack, element, MakeGarbageCollected<TestReaction>(subcommands)));
stack->EnqueueToCurrentQueue(element,
- MakeGarbageCollected<TestReaction>(commands));
+ *MakeGarbageCollected<TestReaction>(commands));
}
stack->PopInvokingReactions();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
index 396d89d636c..a746fe3dbb8 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
@@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -26,18 +27,18 @@ class Command : public GarbageCollectedFinalized<Command> {
public:
Command() = default;
virtual ~Command() = default;
- virtual void Trace(blink::Visitor* visitor) {}
- virtual void Run(Element*) = 0;
+ virtual void Trace(Visitor* visitor) {}
+ virtual void Run(Element&) = 0;
DISALLOW_COPY_AND_ASSIGN(Command);
};
class Call : public Command {
public:
- using Callback = base::OnceCallback<void(Element*)>;
+ using Callback = base::OnceCallback<void(Element&)>;
Call(Callback callback) : callback_(std::move(callback)) {}
~Call() override = default;
- void Run(Element* element) override { std::move(callback_).Run(element); }
+ void Run(Element& element) override { std::move(callback_).Run(element); }
private:
Callback callback_;
@@ -49,7 +50,7 @@ class Unreached : public Command {
public:
Unreached(const char* message) : message_(message) {}
~Unreached() override = default;
- void Run(Element*) override { EXPECT_TRUE(false) << message_; }
+ void Run(Element&) override { EXPECT_TRUE(false) << message_; }
private:
const char* message_;
@@ -61,7 +62,7 @@ class Log : public Command {
public:
Log(char what, std::vector<char>& where) : what_(what), where_(where) {}
~Log() override = default;
- void Run(Element*) override { where_.push_back(what_); }
+ void Run(Element&) override { where_.push_back(what_); }
private:
char what_;
@@ -74,11 +75,11 @@ class Recurse : public Command {
public:
Recurse(CustomElementReactionQueue* queue) : queue_(queue) {}
~Recurse() override = default;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
Command::Trace(visitor);
visitor->Trace(queue_);
}
- void Run(Element* element) override { queue_->InvokeReactions(element); }
+ void Run(Element& element) override { queue_->InvokeReactions(element); }
private:
Member<CustomElementReactionQueue> queue_;
@@ -91,12 +92,12 @@ class Enqueue : public Command {
Enqueue(CustomElementReactionQueue* queue, CustomElementReaction* reaction)
: queue_(queue), reaction_(reaction) {}
~Enqueue() override = default;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
Command::Trace(visitor);
visitor->Trace(queue_);
visitor->Trace(reaction_);
}
- void Run(Element*) override { queue_->Add(reaction_); }
+ void Run(Element&) override { queue_->Add(*reaction_); }
private:
Member<CustomElementReactionQueue> queue_;
@@ -108,13 +109,16 @@ class Enqueue : public Command {
class TestReaction : public CustomElementReaction {
public:
TestReaction(HeapVector<Member<Command>>* commands)
- : CustomElementReaction(nullptr), commands_(commands) {}
+ : CustomElementReaction(
+ *MakeGarbageCollected<TestCustomElementDefinition>(
+ CustomElementDescriptor("mock-element", "mock-element"))),
+ commands_(commands) {}
~TestReaction() override = default;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
CustomElementReaction::Trace(visitor);
visitor->Trace(commands_);
}
- void Invoke(Element* element) override {
+ void Invoke(Element& element) override {
for (auto& command : *commands_)
command->Run(element);
}
@@ -129,7 +133,7 @@ class ResetCustomElementReactionStackForTest final {
STACK_ALLOCATED();
public:
ResetCustomElementReactionStackForTest()
- : stack_(new CustomElementReactionStack),
+ : stack_(MakeGarbageCollected<CustomElementReactionStack>()),
old_stack_(
CustomElementReactionStackTestSupport::SetCurrentForTest(stack_)) {}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
index 866bdc2f28f..06817ada693 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -24,7 +24,6 @@
#include "third_party/blink/renderer/core/html/custom/custom_element_definition_builder.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_descriptor.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h"
#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html_element_type_helpers.h"
@@ -78,7 +77,8 @@ bool ThrowIfValidName(const AtomicString& name,
CustomElementRegistry* CustomElementRegistry::Create(
const LocalDOMWindow* owner) {
- CustomElementRegistry* registry = new CustomElementRegistry(owner);
+ CustomElementRegistry* registry =
+ MakeGarbageCollected<CustomElementRegistry>(owner);
Document* document = owner->document();
if (V0CustomElementRegistrationContext* v0 =
document ? document->RegistrationContext() : nullptr)
@@ -93,7 +93,7 @@ CustomElementRegistry::CustomElementRegistry(const LocalDOMWindow* owner)
upgrade_candidates_(MakeGarbageCollected<UpgradeCandidateMap>()),
reaction_stack_(&CustomElementReactionStack::Current()) {}
-void CustomElementRegistry::Trace(blink::Visitor* visitor) {
+void CustomElementRegistry::Trace(Visitor* visitor) {
visitor->Trace(definitions_);
visitor->Trace(owner_);
visitor->Trace(v0_);
@@ -221,7 +221,7 @@ CustomElementDefinition* CustomElementRegistry::DefineInternal(
HeapVector<Member<Element>> candidates;
CollectCandidates(descriptor, &candidates);
for (Element* candidate : candidates)
- definition->EnqueueUpgradeReaction(candidate);
+ definition->EnqueueUpgradeReaction(*candidate);
// 16: when-defined promise processing
const auto& entry = when_defined_promise_map_.find(name);
@@ -289,10 +289,10 @@ CustomElementDefinition* CustomElementRegistry::DefinitionForId(
return id ? definitions_[id - 1].Get() : nullptr;
}
-void CustomElementRegistry::AddCandidate(Element* candidate) {
- AtomicString name = candidate->localName();
+void CustomElementRegistry::AddCandidate(Element& candidate) {
+ AtomicString name = candidate.localName();
if (!CustomElement::IsValidName(name)) {
- const AtomicString& is = candidate->IsValue();
+ const AtomicString& is = candidate.IsValue();
if (!is.IsNull())
name = is;
}
@@ -307,7 +307,7 @@ void CustomElementRegistry::AddCandidate(Element* candidate) {
->insert(name, MakeGarbageCollected<UpgradeCandidateSet>())
.stored_value->value;
}
- set->insert(candidate);
+ set->insert(&candidate);
}
// https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregistry-whendefined
@@ -362,7 +362,7 @@ void CustomElementRegistry::upgrade(Node* root) {
// 2. For each candidate of candidates, try to upgrade candidate.
for (auto& candidate : candidates) {
- CustomElement::TryToUpgrade(candidate,
+ CustomElement::TryToUpgrade(*candidate,
true /* upgrade_invisible_elements */);
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h
index 5b3f44845d1..e29f6503065 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h
@@ -37,6 +37,7 @@ class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
public:
static CustomElementRegistry* Create(const LocalDOMWindow*);
+ CustomElementRegistry(const LocalDOMWindow*);
~CustomElementRegistry() override = default;
CustomElementDefinition* define(ScriptState*,
@@ -56,7 +57,7 @@ class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
// TODO(dominicc): Consider broadening this API when type extensions are
// implemented.
- void AddCandidate(Element*);
+ void AddCandidate(Element&);
ScriptPromise whenDefined(ScriptState*,
const AtomicString& name,
ExceptionState&);
@@ -64,11 +65,9 @@ class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
void Entangle(V0CustomElementRegistrationContext*);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- CustomElementRegistry(const LocalDOMWindow*);
-
CustomElementDefinition* DefineInternal(ScriptState*,
const AtomicString& name,
CustomElementDefinitionBuilder&,
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
index 8061cb734e4..14387061828 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
@@ -18,4 +18,4 @@ callback CustomElementAdoptedCallback = void (Document oldOwner, Document newOwn
callback CustomElementAttributeChangedCallback = void (DOMString localName, DOMString? oldValue, DOMString? newValue, USVString? attrNamespace);
callback CustomElementFormAssociatedCallback = void (HTMLFormElement? form);
callback CustomElementDisabledStateChangedCallback = void (boolean disabled);
-
+callback CustomElementRestoreValueCallback = void (FormDataEntryValue value);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
index 522e8116366..0283563140f 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
@@ -61,7 +61,7 @@ class CustomElementRegistryTest : public PageTestBase {
TEST_F(CustomElementRegistryTest,
collectCandidates_shouldNotIncludeElementsRemovedFromDocument) {
- Element* element = CreateElement("a-a").InDocument(&GetDocument());
+ Element& element = *CreateElement("a-a").InDocument(&GetDocument());
Registry().AddCandidate(element);
HeapVector<Member<Element>> elements;
@@ -77,7 +77,7 @@ TEST_F(CustomElementRegistryTest,
TEST_F(CustomElementRegistryTest,
collectCandidates_shouldNotIncludeElementsInDifferentDocument) {
Element* element = CreateElement("a-a").InDocument(&GetDocument());
- Registry().AddCandidate(element);
+ Registry().AddCandidate(*element);
Document* other_document = HTMLDocument::CreateForTest();
other_document->AppendChild(element);
@@ -99,18 +99,18 @@ TEST_F(CustomElementRegistryTest,
CustomElementDescriptor descriptor("hello-world", "hello-world");
// Does not match: namespace is not HTML
- Element* element_a = CreateElement("hello-world")
- .InDocument(&GetDocument())
- .InNamespace("data:text/date,1981-03-10");
+ Element& element_a = *CreateElement("hello-world")
+ .InDocument(&GetDocument())
+ .InNamespace("data:text/date,1981-03-10");
// Matches
- Element* element_b = CreateElement("hello-world").InDocument(&GetDocument());
+ Element& element_b = *CreateElement("hello-world").InDocument(&GetDocument());
// Does not match: local name is not hello-world
- Element* element_c = CreateElement("button")
- .InDocument(&GetDocument())
- .WithIsValue("hello-world");
- GetDocument().documentElement()->AppendChild(element_a);
- element_a->AppendChild(element_b);
- element_a->AppendChild(element_c);
+ Element& element_c = *CreateElement("button")
+ .InDocument(&GetDocument())
+ .WithIsValue("hello-world");
+ GetDocument().documentElement()->AppendChild(&element_a);
+ element_a.AppendChild(&element_b);
+ element_a.AppendChild(&element_c);
Registry().AddCandidate(element_a);
Registry().AddCandidate(element_b);
@@ -126,9 +126,9 @@ TEST_F(CustomElementRegistryTest,
}
TEST_F(CustomElementRegistryTest, collectCandidates_oneCandidate) {
- Element* element = CreateElement("a-a").InDocument(&GetDocument());
+ Element& element = *CreateElement("a-a").InDocument(&GetDocument());
Registry().AddCandidate(element);
- GetDocument().documentElement()->AppendChild(element);
+ GetDocument().documentElement()->AppendChild(&element);
HeapVector<Member<Element>> elements;
CollectCandidates(CustomElementDescriptor("a-a", "a-a"), &elements);
@@ -146,9 +146,9 @@ TEST_F(CustomElementRegistryTest, collectCandidates_shouldBeInDocumentOrder) {
Element* element_b = factory.WithId("b");
Element* element_c = factory.WithId("c");
- Registry().AddCandidate(element_b);
- Registry().AddCandidate(element_a);
- Registry().AddCandidate(element_c);
+ Registry().AddCandidate(*element_b);
+ Registry().AddCandidate(*element_a);
+ Registry().AddCandidate(*element_c);
GetDocument().documentElement()->AppendChild(element_a);
element_a->AppendChild(element_b);
@@ -174,7 +174,7 @@ class LogUpgradeDefinition : public TestCustomElementDefinition {
},
{}) {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
TestCustomElementDefinition::Trace(visitor);
visitor->Trace(element_);
visitor->Trace(adopted_);
@@ -200,13 +200,13 @@ class LogUpgradeDefinition : public TestCustomElementDefinition {
Vector<AttributeChanged> attribute_changed_;
struct Adopted : public GarbageCollected<Adopted> {
- Adopted(Document* old_owner, Document* new_owner)
+ Adopted(Document& old_owner, Document& new_owner)
: old_owner_(old_owner), new_owner_(new_owner) {}
Member<Document> old_owner_;
Member<Document> new_owner_;
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(old_owner_);
visitor->Trace(new_owner_);
}
@@ -218,7 +218,7 @@ class LogUpgradeDefinition : public TestCustomElementDefinition {
attribute_changed_.clear();
}
- bool RunConstructor(Element* element) override {
+ bool RunConstructor(Element& element) override {
logs_.push_back(kConstructor);
element_ = element;
return TestCustomElementDefinition::RunConstructor(element);
@@ -228,30 +228,30 @@ class LogUpgradeDefinition : public TestCustomElementDefinition {
bool HasDisconnectedCallback() const override { return true; }
bool HasAdoptedCallback() const override { return true; }
- void RunConnectedCallback(Element* element) override {
+ void RunConnectedCallback(Element& element) override {
logs_.push_back(kConnectedCallback);
- EXPECT_EQ(element, element_);
+ EXPECT_EQ(&element, element_);
}
- void RunDisconnectedCallback(Element* element) override {
+ void RunDisconnectedCallback(Element& element) override {
logs_.push_back(kDisconnectedCallback);
- EXPECT_EQ(element, element_);
+ EXPECT_EQ(&element, element_);
}
- void RunAdoptedCallback(Element* element,
- Document* old_owner,
- Document* new_owner) override {
+ void RunAdoptedCallback(Element& element,
+ Document& old_owner,
+ Document& new_owner) override {
logs_.push_back(kAdoptedCallback);
- EXPECT_EQ(element, element_);
+ EXPECT_EQ(&element, element_);
adopted_.push_back(MakeGarbageCollected<Adopted>(old_owner, new_owner));
}
- void RunAttributeChangedCallback(Element* element,
+ void RunAttributeChangedCallback(Element& element,
const QualifiedName& name,
const AtomicString& old_value,
const AtomicString& new_value) override {
logs_.push_back(kAttributeChangedCallback);
- EXPECT_EQ(element, element_);
+ EXPECT_EQ(&element, element_);
attribute_changed_.push_back(AttributeChanged{name, old_value, new_value});
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
index 9f6b8183ad8..5fab6f70106 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
@@ -60,9 +60,9 @@ class TestCustomElementDefinition : public CustomElementDefinition {
ScriptValue GetConstructorForScript() override { return ScriptValue(); }
- bool RunConstructor(Element* element) override {
+ bool RunConstructor(Element& element) override {
if (GetConstructionStack().IsEmpty() ||
- GetConstructionStack().back() != element)
+ GetConstructionStack().back() != &element)
return false;
GetConstructionStack().back().Clear();
return true;
@@ -78,33 +78,39 @@ class TestCustomElementDefinition : public CustomElementDefinition {
bool HasDisconnectedCallback() const override { return false; }
bool HasAdoptedCallback() const override { return false; }
bool HasFormAssociatedCallback() const override { return false; }
+ bool HasFormResetCallback() const override { return false; }
bool HasDisabledStateChangedCallback() const override { return false; }
- void RunConnectedCallback(Element*) override {
+ void RunConnectedCallback(Element&) override {
NOTREACHED() << "definition does not have connected callback";
}
- void RunDisconnectedCallback(Element*) override {
+ void RunDisconnectedCallback(Element&) override {
NOTREACHED() << "definition does not have disconnected callback";
}
- void RunAdoptedCallback(Element*,
- Document* old_owner,
- Document* new_owner) override {
+ void RunAdoptedCallback(Element&,
+ Document& old_owner,
+ Document& new_owner) override {
NOTREACHED() << "definition does not have adopted callback";
}
- void RunAttributeChangedCallback(Element*,
+ void RunAttributeChangedCallback(Element&,
const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value) override {
NOTREACHED() << "definition does not have attribute changed callback";
}
- void RunFormAssociatedCallback(Element* element,
+ void RunFormAssociatedCallback(Element& element,
HTMLFormElement* nullable_form) override {
NOTREACHED() << "definition does not have formAssociatedCallback";
}
- void RunDisabledStateChangedCallback(Element* element,
+
+ void RunFormResetCallback(Element& element) override {
+ NOTREACHED() << "definition does not have formResetCallback";
+ }
+
+ void RunDisabledStateChangedCallback(Element& element,
bool is_disabled) override {
NOTREACHED() << "definition does not have disabledStateChangedCallback";
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.cc
deleted file mode 100644
index 8c49a3e682e..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.cc
+++ /dev/null
@@ -1,32 +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 "third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h"
-
-#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-
-namespace blink {
-
-CustomElementUpgradeReaction::CustomElementUpgradeReaction(
- CustomElementDefinition* definition,
- bool upgrade_invisible_elements)
- : CustomElementReaction(definition),
- upgrade_invisible_elements_(upgrade_invisible_elements) {}
-
-void CustomElementUpgradeReaction::Invoke(Element* element) {
- // Don't call upgrade() if it's already upgraded. Multiple upgrade reactions
- // could be enqueued because the state changes in step 10 of upgrades.
- // https://html.spec.whatwg.org/multipage/scripting.html#upgrades
- if (element->GetCustomElementState() == CustomElementState::kUndefined) {
- // Don't upgrade elements inside an invisible-static tree, unless it was
- // triggered by CustomElementRegistry::upgrade.
- if (!RuntimeEnabledFeatures::InvisibleDOMEnabled() ||
- !element->IsInsideInvisibleStaticSubtree() ||
- upgrade_invisible_elements_)
- definition_->Upgrade(element);
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h
deleted file mode 100644
index 7cb4ad05233..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_upgrade_reaction.h
+++ /dev/null
@@ -1,33 +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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_UPGRADE_REACTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_UPGRADE_REACTION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class Element;
-
-class CORE_EXPORT CustomElementUpgradeReaction final
- : public CustomElementReaction {
- public:
- CustomElementUpgradeReaction(CustomElementDefinition*,
- bool upgrade_invisible_elements);
-
- private:
- void Invoke(Element*) override;
-
- bool upgrade_invisible_elements_;
-
- DISALLOW_COPY_AND_ASSIGN(CustomElementUpgradeReaction);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_UPGRADE_REACTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc b/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc
index 3d14c75c849..83f706a4cd6 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc
@@ -7,12 +7,28 @@
#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
#include "third_party/blink/renderer/core/fileapi/file.h"
#include "third_party/blink/renderer/core/html/custom/custom_element.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
+#include "third_party/blink/renderer/core/html/custom/validity_state_flags.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
+#include "third_party/blink/renderer/core/html/forms/validity_state.h"
#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
+namespace {
+bool IsValidityStateFlagsValid(const ValidityStateFlags* flags) {
+ if (!flags)
+ return true;
+ if (flags->badInput() || flags->customError() || flags->patternMismatch() ||
+ flags->rangeOverflow() || flags->rangeUnderflow() ||
+ flags->stepMismatch() || flags->tooLong() || flags->tooShort() ||
+ flags->typeMismatch() || flags->valueMissing())
+ return false;
+ return true;
+}
+} // anonymous namespace
+
ElementInternals::ElementInternals(HTMLElement& target) : target_(target) {
value_.SetUSVString(String());
}
@@ -21,6 +37,7 @@ void ElementInternals::Trace(Visitor* visitor) {
visitor->Trace(target_);
visitor->Trace(value_);
visitor->Trace(entry_source_);
+ visitor->Trace(validity_flags_);
ListedElement::Trace(visitor);
ScriptWrappable::Trace(visitor);
}
@@ -33,13 +50,13 @@ void ElementInternals::setFormValue(const FileOrUSVString& value,
void ElementInternals::setFormValue(const FileOrUSVString& value,
FormData* entry_source,
ExceptionState& exception_state) {
- if (!Target().IsFormAssociatedCustomElement()) {
+ if (!IsTargetFormAssociated()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"The target element is not a form-associated custom element.");
return;
}
- if (!entry_source || entry_source->size() == 0u) {
+ if (!entry_source) {
value_ = value;
entry_source_ = nullptr;
return;
@@ -49,7 +66,7 @@ void ElementInternals::setFormValue(const FileOrUSVString& value,
}
HTMLFormElement* ElementInternals::form(ExceptionState& exception_state) const {
- if (!Target().IsFormAssociatedCustomElement()) {
+ if (!IsTargetFormAssociated()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"The target element is not a form-associated custom element.");
@@ -58,6 +75,101 @@ HTMLFormElement* ElementInternals::form(ExceptionState& exception_state) const {
return ListedElement::Form();
}
+void ElementInternals::setValidity(ValidityStateFlags* flags,
+ ExceptionState& exception_state) {
+ setValidity(flags, String(), exception_state);
+}
+
+void ElementInternals::setValidity(ValidityStateFlags* flags,
+ const String& message,
+ ExceptionState& exception_state) {
+ if (!IsTargetFormAssociated()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The target element is not a form-associated custom element.");
+ return;
+ }
+ // Custom element authors should provide a message. They can omit the message
+ // argument only if nothing if | flags| is true.
+ if (!IsValidityStateFlagsValid(flags) && message.IsEmpty()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kTypeMismatchError,
+ "The second argument should not be empty if one or more flags in the "
+ "first argument are true.");
+ return;
+ }
+ validity_flags_ = flags;
+ SetCustomValidationMessage(message);
+ SetNeedsValidityCheck();
+}
+
+bool ElementInternals::willValidate(ExceptionState& exception_state) const {
+ if (!IsTargetFormAssociated()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The target element is not a form-associated custom element.");
+ return false;
+ }
+ return WillValidate();
+}
+
+ValidityState* ElementInternals::validity(ExceptionState& exception_state) {
+ if (!IsTargetFormAssociated()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The target element is not a form-associated custom element.");
+ return nullptr;
+ }
+ return ListedElement::validity();
+}
+
+String ElementInternals::ValidationMessageForBinding(
+ ExceptionState& exception_state) {
+ if (!IsTargetFormAssociated()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The target element is not a form-associated custom element.");
+ return String();
+ }
+ return validationMessage();
+}
+
+String ElementInternals::validationMessage() const {
+ if (IsValidityStateFlagsValid(validity_flags_))
+ return String();
+ return CustomValidationMessage();
+}
+
+String ElementInternals::ValidationSubMessage() const {
+ if (PatternMismatch())
+ return Target().FastGetAttribute(html_names::kTitleAttr).GetString();
+ return String();
+}
+
+bool ElementInternals::checkValidity(ExceptionState& exception_state) {
+ if (!IsTargetFormAssociated()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The target element is not a form-associated custom element.");
+ return false;
+ }
+ return ListedElement::checkValidity();
+}
+
+bool ElementInternals::reportValidity(ExceptionState& exception_state) {
+ if (!IsTargetFormAssociated()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The target element is not a form-associated custom element.");
+ return false;
+ }
+ return ListedElement::reportValidity();
+}
+
+LabelsNodeList* ElementInternals::labels() {
+ return Target().labels();
+}
+
void ElementInternals::DidUpgrade() {
ContainerNode* parent = Target().parentNode();
if (!parent)
@@ -76,6 +188,22 @@ void ElementInternals::DidUpgrade() {
}
}
+bool ElementInternals::IsTargetFormAssociated() const {
+ if (Target().IsFormAssociatedCustomElement())
+ return true;
+ if (Target().GetCustomElementState() != CustomElementState::kUndefined)
+ return false;
+ // An element is in "undefined" state in its constructor JavaScript code.
+ // ElementInternals needs to handle elements to be form-associated same as
+ // form-associated custom elements because web authors want to call
+ // form-related operations of ElementInternals in constructors.
+ CustomElementRegistry* registry = CustomElement::Registry(Target());
+ if (!registry)
+ return false;
+ auto* definition = registry->DefinitionForName(Target().localName());
+ return definition && definition->IsFormAssociated();
+}
+
bool ElementInternals::IsFormControlElement() const {
return false;
}
@@ -89,8 +217,10 @@ bool ElementInternals::IsEnumeratable() const {
}
void ElementInternals::AppendToFormData(FormData& form_data) {
+ if (Target().IsDisabledFormControl())
+ return;
const AtomicString& name = Target().FastGetAttribute(html_names::kNameAttr);
- if (!entry_source_ || entry_source_->size() == 0u) {
+ if (!entry_source_) {
if (name.IsNull())
return;
if (value_.IsFile())
@@ -114,4 +244,52 @@ void ElementInternals::DidChangeForm() {
CustomElement::EnqueueFormAssociatedCallback(Target(), Form());
}
+bool ElementInternals::HasBadInput() const {
+ return validity_flags_ && validity_flags_->badInput();
+}
+
+bool ElementInternals::PatternMismatch() const {
+ return validity_flags_ && validity_flags_->patternMismatch();
+}
+
+bool ElementInternals::RangeOverflow() const {
+ return validity_flags_ && validity_flags_->rangeOverflow();
+}
+
+bool ElementInternals::RangeUnderflow() const {
+ return validity_flags_ && validity_flags_->rangeUnderflow();
+}
+
+bool ElementInternals::StepMismatch() const {
+ return validity_flags_ && validity_flags_->stepMismatch();
+}
+
+bool ElementInternals::TooLong() const {
+ return validity_flags_ && validity_flags_->tooLong();
+}
+
+bool ElementInternals::TooShort() const {
+ return validity_flags_ && validity_flags_->tooShort();
+}
+
+bool ElementInternals::TypeMismatch() const {
+ return validity_flags_ && validity_flags_->typeMismatch();
+}
+
+bool ElementInternals::ValueMissing() const {
+ return validity_flags_ && validity_flags_->valueMissing();
+}
+
+bool ElementInternals::CustomError() const {
+ return validity_flags_ && validity_flags_->customError();
+}
+
+void ElementInternals::DisabledStateMightBeChanged() {
+ bool new_disabled = IsActuallyDisabled();
+ if (is_disabled_ == new_disabled)
+ return;
+ is_disabled_ = new_disabled;
+ CustomElement::EnqueueDisabledStateChangedCallback(Target(), new_disabled);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/element_internals.h b/chromium/third_party/blink/renderer/core/html/custom/element_internals.h
index d32036402cd..77d233bae2d 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/element_internals.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/element_internals.h
@@ -13,6 +13,8 @@
namespace blink {
class HTMLElement;
+class LabelsNodeList;
+class ValidityStateFlags;
class ElementInternals : public ScriptWrappable, public ListedElement {
DEFINE_WRAPPERTYPEINFO();
@@ -32,19 +34,46 @@ class ElementInternals : public ScriptWrappable, public ListedElement {
FormData* entry_source,
ExceptionState& exception_state);
HTMLFormElement* form(ExceptionState& exception_state) const;
+ void setValidity(ValidityStateFlags* flags, ExceptionState& exception_state);
+ void setValidity(ValidityStateFlags* flags,
+ const String& message,
+ ExceptionState& exception_state);
+ bool willValidate(ExceptionState& exception_state) const;
+ ValidityState* validity(ExceptionState& exception_state);
+ String ValidationMessageForBinding(ExceptionState& exception_state);
+ bool checkValidity(ExceptionState& exception_state);
+ bool reportValidity(ExceptionState& exception_state);
+ LabelsNodeList* labels();
private:
+ bool IsTargetFormAssociated() const;
+
// ListedElement overrides:
bool IsFormControlElement() const override;
bool IsElementInternals() const override;
bool IsEnumeratable() const override;
void AppendToFormData(FormData& form_data) override;
void DidChangeForm() override;
+ bool HasBadInput() const override;
+ bool PatternMismatch() const override;
+ bool RangeOverflow() const override;
+ bool RangeUnderflow() const override;
+ bool StepMismatch() const override;
+ bool TooLong() const override;
+ bool TooShort() const override;
+ bool TypeMismatch() const override;
+ bool ValueMissing() const override;
+ bool CustomError() const override;
+ String validationMessage() const override;
+ String ValidationSubMessage() const override;
+ void DisabledStateMightBeChanged() override;
Member<HTMLElement> target_;
FileOrUSVString value_;
Member<FormData> entry_source_;
+ bool is_disabled_ = false;
+ Member<ValidityStateFlags> validity_flags_;
DISALLOW_COPY_AND_ASSIGN(ElementInternals);
};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl b/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl
index c918fba298d..958db151e50 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl
+++ b/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl
@@ -11,6 +11,16 @@
interface ElementInternals {
// Attributes and operations for form-associated custom elements.
[RaisesException] void setFormValue(FormDataEntryValue value, optional FormData entrySource);
+
[RaisesException] readonly attribute HTMLFormElement? form;
+
+ [RaisesException] void setValidity(ValidityStateFlags flags, optional DOMString message);
+ [RaisesException] readonly attribute boolean willValidate;
+ [RaisesException] readonly attribute ValidityState validity;
+ [RaisesException, ImplementedAs=ValidationMessageForBinding] readonly attribute DOMString validationMessage;
+ [RaisesException] boolean checkValidity();
+ [RaisesException] boolean reportValidity();
+
+ readonly attribute NodeList labels;
};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc
index d34f4a8b9ca..8550ba58cb0 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc
@@ -124,11 +124,11 @@ V0CustomElementCallbackInvocation::CreateInvocation(
V0CustomElementLifecycleCallbacks::CallbackType which) {
switch (which) {
case V0CustomElementLifecycleCallbacks::kCreatedCallback:
- return new CreatedInvocation(callbacks);
+ return MakeGarbageCollected<CreatedInvocation>(callbacks);
case V0CustomElementLifecycleCallbacks::kAttachedCallback:
case V0CustomElementLifecycleCallbacks::kDetachedCallback:
- return new AttachedDetachedInvocation(callbacks, which);
+ return MakeGarbageCollected<AttachedDetachedInvocation>(callbacks, which);
default:
NOTREACHED();
return nullptr;
@@ -141,10 +141,11 @@ V0CustomElementCallbackInvocation::CreateAttributeChangedInvocation(
const AtomicString& name,
const AtomicString& old_value,
const AtomicString& new_value) {
- return new AttributeChangedInvocation(callbacks, name, old_value, new_value);
+ return MakeGarbageCollected<AttributeChangedInvocation>(callbacks, name,
+ old_value, new_value);
}
-void V0CustomElementCallbackInvocation::Trace(blink::Visitor* visitor) {
+void V0CustomElementCallbackInvocation::Trace(Visitor* visitor) {
visitor->Trace(callbacks_);
V0CustomElementProcessingStep::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h
index c66adb63ec8..23e40003a9d 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h
@@ -56,7 +56,7 @@ class V0CustomElementCallbackInvocation : public V0CustomElementProcessingStep {
V0CustomElementLifecycleCallbacks* Callbacks() { return callbacks_.Get(); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<V0CustomElementLifecycleCallbacks> callbacks_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc
index c4de24bce0c..a48515e4193 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc
@@ -73,7 +73,7 @@ bool V0CustomElementCallbackQueue::ProcessInElementQueue(
return did_work;
}
-void V0CustomElementCallbackQueue::Trace(blink::Visitor* visitor) {
+void V0CustomElementCallbackQueue::Trace(Visitor* visitor) {
visitor->Trace(element_);
visitor->Trace(queue_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h
index 529e1c09d91..853be379b0f 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h
@@ -65,7 +65,7 @@ class V0CustomElementCallbackQueue
}
bool InCreatedCallback() const { return in_created_callback_; }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Member<Element> element_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc
index d7f446b42f0..0856bbdec8f 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc
@@ -43,7 +43,7 @@ V0CustomElementDefinition::V0CustomElementDefinition(
V0CustomElementLifecycleCallbacks* callbacks)
: descriptor_(descriptor), callbacks_(callbacks) {}
-void V0CustomElementDefinition::Trace(blink::Visitor* visitor) {
+void V0CustomElementDefinition::Trace(Visitor* visitor) {
visitor->Trace(callbacks_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h
index 6b5806d85a3..87b5f822e29 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h
@@ -50,7 +50,7 @@ class V0CustomElementDefinition final
return callbacks_.Get();
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
V0CustomElementDescriptor descriptor_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h
index 0cc47120ad2..6e3ed3839a5 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h
@@ -61,7 +61,7 @@ class V0CustomElementLifecycleCallbacks
const AtomicString& old_value,
const AtomicString& new_value) = 0;
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
protected:
explicit V0CustomElementLifecycleCallbacks(CallbackType type)
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc
index cd2b1f7fe1b..fe023ce0db4 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc
@@ -20,8 +20,9 @@ V0CustomElementMicrotaskDispatcher::V0CustomElementMicrotaskDispatcher()
V0CustomElementMicrotaskDispatcher&
V0CustomElementMicrotaskDispatcher::Instance() {
- DEFINE_STATIC_LOCAL(Persistent<V0CustomElementMicrotaskDispatcher>, instance,
- (new V0CustomElementMicrotaskDispatcher));
+ DEFINE_STATIC_LOCAL(
+ Persistent<V0CustomElementMicrotaskDispatcher>, instance,
+ (MakeGarbageCollected<V0CustomElementMicrotaskDispatcher>()));
return *instance;
}
@@ -75,7 +76,7 @@ void V0CustomElementMicrotaskDispatcher::DoDispatch() {
phase_ = kQuiescent;
}
-void V0CustomElementMicrotaskDispatcher::Trace(blink::Visitor* visitor) {
+void V0CustomElementMicrotaskDispatcher::Trace(Visitor* visitor) {
visitor->Trace(elements_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h
index f621b95c063..9aa1567285a 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h
@@ -18,15 +18,15 @@ class V0CustomElementMicrotaskDispatcher final
public:
static V0CustomElementMicrotaskDispatcher& Instance();
+ V0CustomElementMicrotaskDispatcher();
+
void Enqueue(V0CustomElementCallbackQueue*);
bool ElementQueueIsEmpty() { return elements_.IsEmpty(); }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
- V0CustomElementMicrotaskDispatcher();
-
void EnsureMicrotaskScheduledForElementQueue();
void EnsureMicrotaskScheduled();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc
index 79977ccfd39..765c797a02a 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc
@@ -70,7 +70,7 @@ V0CustomElementMicrotaskImportStep::Process() {
return kFinishedProcessing;
}
-void V0CustomElementMicrotaskImportStep::Trace(blink::Visitor* visitor) {
+void V0CustomElementMicrotaskImportStep::Trace(Visitor* visitor) {
visitor->Trace(import_);
visitor->Trace(queue_);
V0CustomElementMicrotaskStep::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h
index eb152f5d3a6..71a23da1367 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h
@@ -59,7 +59,7 @@ class V0CustomElementMicrotaskImportStep final
void Invalidate();
void ImportDidFinishLoading();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void DidUpgradeAllCustomElements();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc
index f600ae46d7f..f043853f4df 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc
@@ -15,7 +15,7 @@ void V0CustomElementMicrotaskQueueBase::Dispatch() {
in_dispatch_ = false;
}
-void V0CustomElementMicrotaskQueueBase::Trace(blink::Visitor* visitor) {
+void V0CustomElementMicrotaskQueueBase::Trace(Visitor* visitor) {
visitor->Trace(queue_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h
index 36e6bd70b7f..81efcc35576 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h
@@ -20,7 +20,7 @@ class V0CustomElementMicrotaskQueueBase
bool IsEmpty() const { return queue_.IsEmpty(); }
void Dispatch();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
#if !defined(NDEBUG)
void Show(unsigned indent);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc
index eed62964c73..ca126aa0fc0 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc
@@ -59,7 +59,7 @@ V0CustomElementMicrotaskResolutionStep::Process() {
return V0CustomElementMicrotaskStep::kFinishedProcessing;
}
-void V0CustomElementMicrotaskResolutionStep::Trace(blink::Visitor* visitor) {
+void V0CustomElementMicrotaskResolutionStep::Trace(Visitor* visitor) {
visitor->Trace(context_);
visitor->Trace(element_);
V0CustomElementMicrotaskStep::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h
index 83bb565de1d..320286e804b 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h
@@ -53,7 +53,7 @@ class V0CustomElementMicrotaskResolutionStep final
const V0CustomElementDescriptor&);
~V0CustomElementMicrotaskResolutionStep() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Result Process() override;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc
index bdf10628a2f..b1c90e24c49 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc
@@ -41,7 +41,7 @@ void V0CustomElementMicrotaskRunQueue::RequestDispatchIfNeeded() {
dispatch_is_pending_ = true;
}
-void V0CustomElementMicrotaskRunQueue::Trace(blink::Visitor* visitor) {
+void V0CustomElementMicrotaskRunQueue::Trace(Visitor* visitor) {
visitor->Trace(sync_queue_);
visitor->Trace(async_queue_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h
index 9ac97493dd2..654dd27fb63 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h
@@ -29,7 +29,7 @@ class V0CustomElementMicrotaskRunQueue
void RequestDispatchIfNeeded();
bool IsEmpty() const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
void Dispatch();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h
index 03a9a240af3..c9f1cfc2a7b 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h
@@ -46,7 +46,7 @@ class V0CustomElementMicrotaskStep
virtual Result Process() = 0;
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
#if !defined(NDEBUG)
virtual void Show(unsigned indent) = 0;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h
index 21b2f0bfadb..31888035245 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h
@@ -46,7 +46,7 @@ class V0CustomElementObserver
// API for CustomElement to kick off notifications
static void NotifyElementWasDestroyed(Element*);
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
protected:
V0CustomElementObserver() = default;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc
index ea9b9880e60..63e9648790b 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc
@@ -43,7 +43,7 @@ wtf_size_t V0CustomElementProcessingStack::element_queue_end_ = kNumSentinels;
V0CustomElementProcessingStack& V0CustomElementProcessingStack::Instance() {
DEFINE_STATIC_LOCAL(Persistent<V0CustomElementProcessingStack>, instance,
- (new V0CustomElementProcessingStack));
+ (MakeGarbageCollected<V0CustomElementProcessingStack>()));
return *instance;
}
@@ -92,7 +92,7 @@ void V0CustomElementProcessingStack::Enqueue(
++element_queue_end_;
}
-void V0CustomElementProcessingStack::Trace(blink::Visitor* visitor) {
+void V0CustomElementProcessingStack::Trace(Visitor* visitor) {
visitor->Trace(flattened_processing_stack_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h
index a2a799e8fdd..62717b7e79e 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h
@@ -62,12 +62,6 @@ class CORE_EXPORT V0CustomElementProcessingStack
static bool InCallbackDeliveryScope() { return element_queue_start_; }
- static V0CustomElementProcessingStack& Instance();
- void Enqueue(V0CustomElementCallbackQueue*);
-
- void Trace(blink::Visitor*);
-
- private:
V0CustomElementProcessingStack() {
// Add a null element as a sentinel. This makes it possible to
// identify elements queued when there is no
@@ -80,6 +74,12 @@ class CORE_EXPORT V0CustomElementProcessingStack
DCHECK_EQ(element_queue_end_, flattened_processing_stack_.size());
}
+ static V0CustomElementProcessingStack& Instance();
+ void Enqueue(V0CustomElementCallbackQueue*);
+
+ void Trace(Visitor*);
+
+ private:
// The start of the element queue on the top of the processing
// stack. An offset into Instance().flattened_processing_stack_.
static wtf_size_t element_queue_start_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h
index 69c5ff14b80..145b69bb3b9 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h
@@ -46,7 +46,7 @@ class V0CustomElementProcessingStep
virtual void Dispatch(Element*) = 0;
virtual bool IsCreatedCallback() const { return false; }
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
DISALLOW_COPY_AND_ASSIGN(V0CustomElementProcessingStep);
};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
index 73ad40a0bec..dfef6252e5b 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
@@ -177,7 +177,7 @@ void V0CustomElementRegistrationContext::SetV1(
registry_.SetV1(v1);
}
-void V0CustomElementRegistrationContext::Trace(blink::Visitor* visitor) {
+void V0CustomElementRegistrationContext::Trace(Visitor* visitor) {
visitor->Trace(candidates_);
visitor->Trace(registry_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h
index fbdc75506d9..92e29a3033c 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h
@@ -69,7 +69,7 @@ class V0CustomElementRegistrationContext final
bool NameIsDefined(const AtomicString& name) const;
void SetV1(const CustomElementRegistry*);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
// Instance creation
void DidGiveTypeExtension(Element*, const AtomicString& type);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
index eccbfad76d2..3fe35754f59 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
@@ -140,7 +140,7 @@ bool V0CustomElementRegistry::V1NameIsDefined(const AtomicString& name) const {
return v1_.Get() && v1_->NameIsDefined(name);
}
-void V0CustomElementRegistry::Trace(blink::Visitor* visitor) {
+void V0CustomElementRegistry::Trace(Visitor* visitor) {
visitor->Trace(definitions_);
visitor->Trace(v1_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h
index f549882baed..477589e2fdf 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h
@@ -51,7 +51,7 @@ class V0CustomElementRegistry final {
DISALLOW_NEW();
public:
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void DocumentWasDetached() { document_was_detached_ = true; }
protected:
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc
index a74a1b2ae3d..666a75d9f17 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc
@@ -90,7 +90,7 @@ V0CustomElementUpgradeCandidateMap::TakeUpgradeCandidatesFor(
return candidates;
}
-void V0CustomElementUpgradeCandidateMap::Trace(blink::Visitor* visitor) {
+void V0CustomElementUpgradeCandidateMap::Trace(Visitor* visitor) {
visitor->Trace(upgrade_candidates_);
visitor->Trace(unresolved_definitions_);
V0CustomElementObserver::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h
index de500414000..f89f4adef58 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h
@@ -55,7 +55,7 @@ class V0CustomElementUpgradeCandidateMap final
void Add(const V0CustomElementDescriptor&, Element*);
ElementSet* TakeUpgradeCandidatesFor(const V0CustomElementDescriptor&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void ElementWasDestroyed(Element*) override;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/validity_state_flags.idl b/chromium/third_party/blink/renderer/core/html/custom/validity_state_flags.idl
new file mode 100644
index 00000000000..2f388b75779
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/custom/validity_state_flags.idl
@@ -0,0 +1,18 @@
+// 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.
+
+// https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.pjt9nhs3gu3k
+
+dictionary ValidityStateFlags {
+ boolean valueMissing = false;
+ boolean typeMismatch = false;
+ boolean patternMismatch = false;
+ boolean tooLong = false;
+ boolean tooShort = false;
+ boolean rangeUnderflow = false;
+ boolean rangeOverflow = false;
+ boolean stepMismatch = false;
+ boolean badInput = false;
+ boolean customError = false;
+};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.cc
index 19f35f6d947..63476d16c3d 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.cc
@@ -46,7 +46,7 @@ using namespace html_names;
BaseButtonInputType::BaseButtonInputType(HTMLInputElement& element)
: InputType(element), KeyboardClickableInputTypeView(element) {}
-void BaseButtonInputType::Trace(blink::Visitor* visitor) {
+void BaseButtonInputType::Trace(Visitor* visitor) {
KeyboardClickableInputTypeView::Trace(visitor);
InputType::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.h
index 829e130cbce..5762feb7a54 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_button_input_type.h
@@ -42,7 +42,7 @@ class BaseButtonInputType : public InputType,
USING_GARBAGE_COLLECTED_MIXIN(BaseButtonInputType);
public:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
protected:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
index 2df7aaf0e64..c1d194df773 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
@@ -42,7 +42,7 @@ namespace blink {
using namespace html_names;
-void BaseCheckableInputType::Trace(blink::Visitor* visitor) {
+void BaseCheckableInputType::Trace(Visitor* visitor) {
InputTypeView::Trace(visitor);
InputType::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h
index e7129cca958..d9696d33e8b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h
@@ -41,7 +41,7 @@ class BaseCheckableInputType : public InputType, public InputTypeView {
USING_GARBAGE_COLLECTED_MIXIN(BaseCheckableInputType);
public:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
protected:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/button_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/button_input_type.cc
index f9a3738deca..b4e301b387b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/button_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/button_input_type.cc
@@ -35,7 +35,7 @@
namespace blink {
InputType* ButtonInputType::Create(HTMLInputElement& element) {
- return new ButtonInputType(element);
+ return MakeGarbageCollected<ButtonInputType>(element);
}
const AtomicString& ButtonInputType::FormControlType() const {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/button_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/button_input_type.h
index 479bd80655c..85dae083ab7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/button_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/button_input_type.h
@@ -39,8 +39,9 @@ class ButtonInputType final : public BaseButtonInputType {
public:
static InputType* Create(HTMLInputElement&);
- private:
ButtonInputType(HTMLInputElement& element) : BaseButtonInputType(element) {}
+
+ private:
const AtomicString& FormControlType() const override;
bool SupportsValidation() const override;
bool IsTextButton() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
index 26a4522ffb1..3951c51e537 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
@@ -39,7 +39,7 @@
namespace blink {
InputType* CheckboxInputType::Create(HTMLInputElement& element) {
- return new CheckboxInputType(element);
+ return MakeGarbageCollected<CheckboxInputType>(element);
}
const AtomicString& CheckboxInputType::FormControlType() const {
@@ -66,7 +66,7 @@ ClickHandlingState* CheckboxInputType::WillDispatchClick() {
// checking we do here. The ClickHandlingState object contains what we need
// to undo what we did here in didDispatchClick.
- ClickHandlingState* state = new ClickHandlingState;
+ ClickHandlingState* state = MakeGarbageCollected<ClickHandlingState>();
state->checked = GetElement().checked();
state->indeterminate = GetElement().indeterminate();
diff --git a/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.h
index 425616ce905..57a55e77701 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/checkbox_input_type.h
@@ -39,9 +39,10 @@ class CheckboxInputType final : public BaseCheckableInputType {
public:
static InputType* Create(HTMLInputElement&);
- private:
CheckboxInputType(HTMLInputElement& element)
: BaseCheckableInputType(element) {}
+
+ private:
const AtomicString& FormControlType() const override;
bool ValueMissing(const String&) const override;
String ValueMissingText() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc b/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
index a20f30155f9..f89a5d4d013 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
@@ -45,14 +45,15 @@ ChooserOnlyTemporalInputTypeView::ChooserOnlyTemporalInputTypeView(
ChooserOnlyTemporalInputTypeView* ChooserOnlyTemporalInputTypeView::Create(
HTMLInputElement& element,
BaseTemporalInputType& input_type) {
- return new ChooserOnlyTemporalInputTypeView(element, input_type);
+ return MakeGarbageCollected<ChooserOnlyTemporalInputTypeView>(element,
+ input_type);
}
ChooserOnlyTemporalInputTypeView::~ChooserOnlyTemporalInputTypeView() {
DCHECK(!date_time_chooser_);
}
-void ChooserOnlyTemporalInputTypeView::Trace(blink::Visitor* visitor) {
+void ChooserOnlyTemporalInputTypeView::Trace(Visitor* visitor) {
visitor->Trace(input_type_);
visitor->Trace(date_time_chooser_);
InputTypeView::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h b/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h
index 9388831482d..3ab8312b2d5 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h
@@ -44,11 +44,11 @@ class ChooserOnlyTemporalInputTypeView final
public:
static ChooserOnlyTemporalInputTypeView* Create(HTMLInputElement&,
BaseTemporalInputType&);
+ ChooserOnlyTemporalInputTypeView(HTMLInputElement&, BaseTemporalInputType&);
~ChooserOnlyTemporalInputTypeView() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- ChooserOnlyTemporalInputTypeView(HTMLInputElement&, BaseTemporalInputType&);
void CloseDateTimeChooser();
// InputTypeView functions:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.cc b/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.cc
index 2efb31cf015..2439e2a0514 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.cc
@@ -44,7 +44,7 @@ ClearButtonElement* ClearButtonElement::Create(
Document& document,
ClearButtonOwner& clear_button_owner) {
ClearButtonElement* element =
- new ClearButtonElement(document, clear_button_owner);
+ MakeGarbageCollected<ClearButtonElement>(document, clear_button_owner);
element->SetShadowPseudoId(AtomicString("-webkit-clear-button"));
element->setAttribute(kIdAttr, shadow_element_names::ClearButton());
return element;
@@ -83,7 +83,7 @@ bool ClearButtonElement::IsClearButtonElement() const {
return true;
}
-void ClearButtonElement::Trace(blink::Visitor* visitor) {
+void ClearButtonElement::Trace(Visitor* visitor) {
visitor->Trace(clear_button_owner_);
HTMLDivElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.h b/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.h
index 6666122bd6b..a3844e1e7aa 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/clear_button_element.h
@@ -42,12 +42,14 @@ class ClearButtonElement final : public HTMLDivElement {
};
static ClearButtonElement* Create(Document&, ClearButtonOwner&);
+
+ ClearButtonElement(Document&, ClearButtonOwner&);
+
void RemoveClearButtonOwner() { clear_button_owner_ = nullptr; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- ClearButtonElement(Document&, ClearButtonOwner&);
void DetachLayoutTree(const AttachContext& = AttachContext()) override;
bool IsMouseFocusable() const override { return false; }
void DefaultEventHandler(Event&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_chooser.h b/chromium/third_party/blink/renderer/core/html/forms/color_chooser.h
index 72012762a3d..87bdbc0d9a5 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_chooser.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_chooser.h
@@ -42,7 +42,7 @@ class CORE_EXPORT ColorChooser : public GarbageCollectedMixin {
public:
ColorChooser();
virtual ~ColorChooser();
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
virtual void SetSelectedColor(const Color&) {}
virtual void EndChooser() {}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_client.h b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_client.h
index 845c5cca368..f87e47ee893 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_client.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_client.h
@@ -45,7 +45,7 @@ class Element;
class CORE_EXPORT ColorChooserClient : public GarbageCollectedMixin {
public:
virtual ~ColorChooserClient();
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
virtual void DidChooseColor(const Color&) = 0;
virtual void DidEndChooser() = 0;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc
index 340e62e1ecf..3187c0b507a 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc
@@ -55,11 +55,11 @@ ColorChooserPopupUIController::~ColorChooserPopupUIController() = default;
void ColorChooserPopupUIController::Dispose() {
// Finalized earlier so as to access chrome_client_ while alive.
- ClosePopup();
+ CancelPopup();
// ~ColorChooserUIController calls EndChooser().
}
-void ColorChooserPopupUIController::Trace(blink::Visitor* visitor) {
+void ColorChooserPopupUIController::Trace(Visitor* visitor) {
visitor->Trace(chrome_client_);
ColorChooserUIController::Trace(visitor);
}
@@ -73,7 +73,7 @@ void ColorChooserPopupUIController::OpenUI() {
void ColorChooserPopupUIController::EndChooser() {
ColorChooserUIController::EndChooser();
- ClosePopup();
+ CancelPopup();
}
AXObject* ColorChooserPopupUIController::RootAXObject() {
@@ -122,7 +122,7 @@ void ColorChooserPopupUIController::SetValueAndClosePopup(
SetValue(string_value);
if (num_value == kColorPickerPopupActionChooseOtherColor)
OpenColorChooser();
- ClosePopup();
+ CancelPopup();
}
void ColorChooserPopupUIController::SetValue(const String& value) {
@@ -149,7 +149,7 @@ void ColorChooserPopupUIController::OpenPopup() {
popup_ = chrome_client_->OpenPagePopup(this);
}
-void ColorChooserPopupUIController::ClosePopup() {
+void ColorChooserPopupUIController::CancelPopup() {
if (!popup_)
return;
chrome_client_->ClosePagePopup(popup_);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.h b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.h
index 53d750e78d5..3d5dc3a7955 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.h
@@ -46,11 +46,15 @@ class CORE_EXPORT ColorChooserPopupUIController final
LocalFrame* frame,
ChromeClient* chrome_client,
blink::ColorChooserClient* client) {
- return new ColorChooserPopupUIController(frame, chrome_client, client);
+ return MakeGarbageCollected<ColorChooserPopupUIController>(
+ frame, chrome_client, client);
}
+ ColorChooserPopupUIController(LocalFrame*,
+ ChromeClient*,
+ blink::ColorChooserClient*);
~ColorChooserPopupUIController() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// ColorChooserUIController functions:
void OpenUI() override;
@@ -65,15 +69,11 @@ class CORE_EXPORT ColorChooserPopupUIController final
Locale& GetLocale() override;
void SetValueAndClosePopup(int, const String&) override;
void SetValue(const String&) override;
- void ClosePopup() override;
+ void CancelPopup() override;
Element& OwnerElement() override;
void DidClosePopup() override;
private:
- ColorChooserPopupUIController(LocalFrame*,
- ChromeClient*,
- blink::ColorChooserClient*);
-
void OpenPopup();
void Dispose();
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.cc b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.cc
index 744cb149c9d..bf0f558e188 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.cc
@@ -41,7 +41,7 @@ ColorChooserUIController::ColorChooserUIController(
ColorChooserUIController::~ColorChooserUIController() {}
-void ColorChooserUIController::Trace(blink::Visitor* visitor) {
+void ColorChooserUIController::Trace(Visitor* visitor) {
visitor->Trace(frame_);
visitor->Trace(client_);
ColorChooser::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h
index 311c2a26b2b..4da2d67a2b6 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h
@@ -49,11 +49,12 @@ class CORE_EXPORT ColorChooserUIController
public:
static ColorChooserUIController* Create(LocalFrame* frame,
blink::ColorChooserClient* client) {
- return new ColorChooserUIController(frame, client);
+ return MakeGarbageCollected<ColorChooserUIController>(frame, client);
}
+ ColorChooserUIController(LocalFrame*, blink::ColorChooserClient*);
~ColorChooserUIController() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void Dispose();
@@ -68,8 +69,6 @@ class CORE_EXPORT ColorChooserUIController
void DidChooseColor(uint32_t color) final;
protected:
- ColorChooserUIController(LocalFrame*, blink::ColorChooserClient*);
-
void OpenColorChooser();
mojom::blink::ColorChooserPtr chooser_;
Member<blink::ColorChooserClient> client_;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/color_input_type.cc
index 88a556cfd6a..5958e5b1bcb 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_input_type.cc
@@ -77,12 +77,12 @@ ColorInputType::ColorInputType(HTMLInputElement& element)
: InputType(element), KeyboardClickableInputTypeView(element) {}
InputType* ColorInputType::Create(HTMLInputElement& element) {
- return new ColorInputType(element);
+ return MakeGarbageCollected<ColorInputType>(element);
}
ColorInputType::~ColorInputType() = default;
-void ColorInputType::Trace(blink::Visitor* visitor) {
+void ColorInputType::Trace(Visitor* visitor) {
visitor->Trace(chooser_);
KeyboardClickableInputTypeView::Trace(visitor);
ColorChooserClient::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/color_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/color_input_type.h
index 904ada1b097..f755a60e4af 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/color_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/color_input_type.h
@@ -46,8 +46,9 @@ class ColorInputType final : public InputType,
public:
static InputType* Create(HTMLInputElement&);
+ explicit ColorInputType(HTMLInputElement&);
~ColorInputType() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
// ColorChooserClient implementation.
@@ -61,7 +62,6 @@ class ColorInputType final : public InputType,
ColorChooserClient* GetColorChooserClient() override;
private:
- explicit ColorInputType(HTMLInputElement&);
InputTypeView* CreateView() override;
ValueMode GetValueMode() const override;
void ValueAttributeChanged() override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser.h b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser.h
index dcbd07d16e7..6738274450d 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser.h
@@ -76,7 +76,7 @@ class CORE_EXPORT DateTimeChooser
// Returns a root AXObject in the DateTimeChooser if it's available.
virtual AXObject* RootAXObject() = 0;
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_client.h b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_client.h
index 5c4478cd04a..7c65f22c8f8 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_client.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_client.h
@@ -42,7 +42,7 @@ class Element;
class CORE_EXPORT DateTimeChooserClient : public GarbageCollectedMixin {
public:
virtual ~DateTimeChooserClient();
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
virtual Element& OwnerElement() const = 0;
// Called when user picked a value.
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
index b378ec7e84a..74ebd861f50 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
@@ -68,7 +68,7 @@ DateTimeChooserImpl* DateTimeChooserImpl::Create(
DateTimeChooserImpl::~DateTimeChooserImpl() = default;
-void DateTimeChooserImpl::Trace(blink::Visitor* visitor) {
+void DateTimeChooserImpl::Trace(Visitor* visitor) {
visitor->Trace(chrome_client_);
visitor->Trace(client_);
DateTimeChooser::Trace(visitor);
@@ -234,7 +234,7 @@ void DateTimeChooserImpl::SetValue(const String& value) {
client_->DidChooseValue(value);
}
-void DateTimeChooserImpl::ClosePopup() {
+void DateTimeChooserImpl::CancelPopup() {
EndChooser();
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h
index e896239a7a4..89b70648184 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h
@@ -58,7 +58,7 @@ class CORE_EXPORT DateTimeChooserImpl final : public DateTimeChooser,
void EndChooser() override;
AXObject* RootAXObject() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// PagePopupClient functions:
@@ -67,7 +67,7 @@ class CORE_EXPORT DateTimeChooserImpl final : public DateTimeChooser,
Locale& GetLocale() override;
void SetValueAndClosePopup(int, const String&) override;
void SetValue(const String&) override;
- void ClosePopup() override;
+ void CancelPopup() override;
Element& OwnerElement() override;
void DidClosePopup() override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
index 3fc5fed2a27..886ff81f370 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
@@ -522,7 +522,7 @@ DateTimeEditElement::DateTimeEditElement(Document& document,
DateTimeEditElement::~DateTimeEditElement() = default;
-void DateTimeEditElement::Trace(blink::Visitor* visitor) {
+void DateTimeEditElement::Trace(Visitor* visitor) {
visitor->Trace(fields_);
visitor->Trace(edit_control_owner_);
HTMLDivElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
index dbd24699789..7dd32765433 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
@@ -86,7 +86,7 @@ class DateTimeEditElement final : public HTMLDivElement,
DateTimeEditElement(Document&, EditControlOwner&);
~DateTimeEditElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void AddField(DateTimeFieldElement*);
bool AnyEditableFieldsHaveValues() const;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.cc b/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.cc
index abf1c264e2d..c1b93a2c39e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.cc
@@ -45,7 +45,7 @@ DateTimeFieldElement::DateTimeFieldElement(Document& document,
FieldOwner& field_owner)
: HTMLSpanElement(document), field_owner_(&field_owner) {}
-void DateTimeFieldElement::Trace(blink::Visitor* visitor) {
+void DateTimeFieldElement::Trace(Visitor* visitor) {
visitor->Trace(field_owner_);
HTMLSpanElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.h b/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.h
index 6a6cb1e77b1..da9a87ca553 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_field_element.h
@@ -76,7 +76,7 @@ class DateTimeFieldElement : public HTMLSpanElement {
virtual void StepUp() = 0;
virtual String Value() const = 0;
virtual String VisibleValue() const = 0;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
static float ComputeTextWidth(const ComputedStyle&, const String&);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.cc b/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.cc
index c5dd3246d79..0756ee835ca 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.cc
@@ -57,7 +57,7 @@ class WebDateTimeChooserCompletionImpl : public WebDateTimeChooserCompletion {
ExternalDateTimeChooser::~ExternalDateTimeChooser() = default;
-void ExternalDateTimeChooser::Trace(blink::Visitor* visitor) {
+void ExternalDateTimeChooser::Trace(Visitor* visitor) {
visitor->Trace(client_);
DateTimeChooser::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.h b/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.h
index 4994a5f361c..aa863d54adf 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_date_time_chooser.h
@@ -45,7 +45,7 @@ class CORE_EXPORT ExternalDateTimeChooser final : public DateTimeChooser {
ExternalDateTimeChooser(DateTimeChooserClient*);
~ExternalDateTimeChooser() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// The following functions are for DateTimeChooserCompletion.
void DidChooseValue(const WebString&);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
index d85936423de..5296c0a6caa 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
@@ -73,7 +73,7 @@ ExternalPopupMenu::ExternalPopupMenu(LocalFrame& frame,
ExternalPopupMenu::~ExternalPopupMenu() = default;
-void ExternalPopupMenu::Trace(blink::Visitor* visitor) {
+void ExternalPopupMenu::Trace(Visitor* visitor) {
visitor->Trace(owner_element_);
visitor->Trace(local_frame_);
PopupMenu::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h
index 12bcb903ae4..c6536a46c9f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h
@@ -64,7 +64,7 @@ class CORE_EXPORT ExternalPopupMenu final : public PopupMenu,
static int ToPopupMenuItemIndex(int index, HTMLSelectElement&);
static int ToExternalPopupMenuItemIndex(int index, HTMLSelectElement&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// PopupMenu methods:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu_test.cc b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu_test.cc
index a688821896f..4b3b9b8cbe2 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu_test.cc
@@ -114,7 +114,7 @@ class ExternalPopupMenuTest : public testing::Test {
void LoadFrame(const std::string& file_name) {
frame_test_helpers::LoadFrame(MainFrame(), base_url_ + file_name);
- WebView()->Resize(WebSize(800, 600));
+ WebView()->MainFrameWidget()->Resize(WebSize(800, 600));
WebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
}
@@ -135,7 +135,7 @@ TEST_F(ExternalPopupMenuTest, PopupAccountsForVisualViewportTransform) {
RegisterMockedURLLoad("select_mid_screen.html");
LoadFrame("select_mid_screen.html");
- WebView()->Resize(WebSize(100, 100));
+ WebView()->MainFrameWidget()->Resize(WebSize(100, 100));
WebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/file_chooser.cc b/chromium/third_party/blink/renderer/core/html/forms/file_chooser.cc
index 2cd55b413d3..834ba4ec068 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/file_chooser.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/file_chooser.cc
@@ -73,7 +73,8 @@ bool FileChooser::OpenFileChooser(ChromeClientImpl& chrome_client_impl) {
if (!frame)
return false;
chrome_client_impl_ = chrome_client_impl;
- frame->GetInterfaceProvider().GetInterface(&file_chooser_);
+ frame->GetInterfaceProvider().GetInterface(
+ &file_chooser_, frame->GetTaskRunner(TaskType::kInternalDefault));
file_chooser_.set_connection_error_handler(
WTF::Bind(&FileChooser::DidCloseChooser, WTF::Unretained(this)));
file_chooser_->OpenFileChooser(
@@ -92,7 +93,8 @@ void FileChooser::EnumerateChosenDirectory() {
if (!frame)
return;
DCHECK(!chrome_client_impl_);
- frame->GetInterfaceProvider().GetInterface(&file_chooser_);
+ frame->GetInterfaceProvider().GetInterface(
+ &file_chooser_, frame->GetTaskRunner(TaskType::kInternalDefault));
file_chooser_.set_connection_error_handler(
WTF::Bind(&FileChooser::DidCloseChooser, WTF::Unretained(this)));
file_chooser_->EnumerateChosenDirectory(
diff --git a/chromium/third_party/blink/renderer/core/html/forms/file_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/file_input_type.cc
index c1d08ba805b..46a0f5f9e72 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/file_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -75,7 +75,7 @@ InputType* FileInputType::Create(HTMLInputElement& element) {
return MakeGarbageCollected<FileInputType>(element);
}
-void FileInputType::Trace(blink::Visitor* visitor) {
+void FileInputType::Trace(Visitor* visitor) {
visitor->Trace(file_list_);
KeyboardClickableInputTypeView::Trace(visitor);
InputType::Trace(visitor);
@@ -142,7 +142,7 @@ void FileInputType::RestoreFormControlState(const FormControlState& state) {
FileList* file_list = FileList::Create();
for (const auto& file : file_vector)
file_list->Append(file);
- SetFiles(file_list);
+ SetFilesAndDispatchEvents(file_list);
}
void FileInputType::AppendToFormData(FormData& form_data) const {
@@ -352,9 +352,9 @@ void FileInputType::MultipleAttributeChanged() {
: WebLocalizedString::kFileButtonChooseFileLabel)));
}
-void FileInputType::SetFiles(FileList* files) {
+bool FileInputType::SetFiles(FileList* files) {
if (!files)
- return;
+ return false;
bool files_changed = false;
if (files->length() != file_list_->length()) {
@@ -376,7 +376,11 @@ void FileInputType::SetFiles(FileList* files) {
if (GetElement().GetLayoutObject())
GetElement().GetLayoutObject()->SetShouldDoFullPaintInvalidation();
- if (files_changed) {
+ return files_changed;
+}
+
+void FileInputType::SetFilesAndDispatchEvents(FileList* files) {
+ if (SetFiles(files)) {
// This call may cause destruction of this instance.
// input instance is safe since it is ref-counted.
GetElement().DispatchInputEvent();
@@ -397,7 +401,7 @@ void FileInputType::FilesChosen(FileChooserFileInfoList files,
}
++i;
}
- SetFiles(CreateFileList(files, base_dir));
+ SetFilesAndDispatchEvents(CreateFileList(files, base_dir));
if (HasConnectedFileChooser())
DisconnectFileChooser();
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/file_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/file_input_type.h
index 0175590f861..51568f3f420 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/file_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/file_input_type.h
@@ -55,7 +55,7 @@ class CORE_EXPORT FileInputType final : public InputType,
FileInputType(HTMLInputElement&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
static Vector<String> FilesFromFormControlState(const FormControlState&);
static FileList* CreateFileList(const FileChooserFileInfoList& files,
@@ -77,7 +77,8 @@ class CORE_EXPORT FileInputType final : public InputType,
LayoutObject* CreateLayoutObject(const ComputedStyle&) const override;
bool CanSetStringValue() const override;
FileList* Files() override;
- void SetFiles(FileList*) override;
+ bool SetFiles(FileList*) override;
+ void SetFilesAndDispatchEvents(FileList*) override;
ValueMode GetValueMode() const override;
bool CanSetValue(const String&) override;
String ValueInFilenameValueMode() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/file_input_type_test.cc b/chromium/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
index 47afb404da6..04c54f3ab1a 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
@@ -127,7 +127,7 @@ TEST(FileInputTypeTest, setFilesFromPaths) {
TEST(FileInputTypeTest, DropTouchesNoPopupOpeningObserver) {
Page::PageClients page_clients;
FillWithEmptyClients(page_clients);
- auto* chrome_client = new WebKitDirectoryChromeClient;
+ auto* chrome_client = MakeGarbageCollected<WebKitDirectoryChromeClient>();
page_clients.chrome_client = chrome_client;
auto page_holder = DummyPageHolder::Create(IntSize(), &page_clients);
Document& doc = page_holder->GetDocument();
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_controller.cc b/chromium/third_party/blink/renderer/core/html/forms/form_controller.cc
index 96c940d9029..be7519f8e2f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_controller.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_controller.cc
@@ -25,6 +25,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
#include "third_party/blink/renderer/core/html/forms/file_chooser.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
@@ -316,7 +318,7 @@ class FormKeyGenerator final
FormKeyGenerator() = default;
- void Trace(blink::Visitor* visitor) { visitor->Trace(form_to_key_map_); }
+ void Trace(Visitor* visitor) { visitor->Trace(form_to_key_map_); }
const AtomicString& FormKey(const HTMLFormControlElementWithState&);
void WillDeleteForm(HTMLFormElement*);
@@ -403,23 +405,18 @@ void FormKeyGenerator::WillDeleteForm(HTMLFormElement* form) {
// ----------------------------------------------------------------------------
-DocumentState* DocumentState::Create() {
- return MakeGarbageCollected<DocumentState>();
-}
+DocumentState::DocumentState(Document& document) : document_(document) {}
-void DocumentState::Trace(blink::Visitor* visitor) {
+void DocumentState::Trace(Visitor* visitor) {
+ visitor->Trace(document_);
visitor->Trace(form_controls_);
}
-void DocumentState::AddControl(HTMLFormControlElementWithState* control) {
- DCHECK(!control->Next() && !control->Prev());
- form_controls_.Append(control);
-}
-
-void DocumentState::RemoveControl(HTMLFormControlElementWithState* control) {
- form_controls_.Remove(control);
- control->SetPrev(nullptr);
- control->SetNext(nullptr);
+void DocumentState::InvalidateControlList() {
+ if (form_controls_dirty_)
+ return;
+ form_controls_.resize(0);
+ form_controls_dirty_ = true;
}
static String FormStateSignature() {
@@ -432,11 +429,20 @@ static String FormStateSignature() {
}
Vector<String> DocumentState::ToStateVector() {
+ if (form_controls_dirty_) {
+ for (auto& element : Traversal<Element>::DescendantsOf(*document_)) {
+ if (auto* control_element = ToHTMLFormControlElementOrNull(element)) {
+ if (auto* stateful_control_element =
+ ToHTMLFormControlElementWithStateOrNull(control_element))
+ form_controls_.push_back(stateful_control_element);
+ }
+ }
+ form_controls_dirty_ = false;
+ }
FormKeyGenerator* key_generator = FormKeyGenerator::Create();
std::unique_ptr<SavedFormStateMap> state_map =
base::WrapUnique(new SavedFormStateMap);
- for (HTMLFormControlElementWithState* control = form_controls_.Head();
- control; control = control->Next()) {
+ for (auto& control : form_controls_) {
DCHECK(control->isConnected());
if (!control->ShouldSaveAndRestoreFormControlState())
continue;
@@ -463,11 +469,12 @@ Vector<String> DocumentState::ToStateVector() {
// ----------------------------------------------------------------------------
-FormController::FormController() : document_state_(DocumentState::Create()) {}
+FormController::FormController(Document& document)
+ : document_state_(MakeGarbageCollected<DocumentState>(document)) {}
FormController::~FormController() = default;
-void FormController::Trace(blink::Visitor* visitor) {
+void FormController::Trace(Visitor* visitor) {
visitor->Trace(document_state_);
visitor->Trace(form_key_generator_);
}
@@ -575,14 +582,8 @@ Vector<String> FormController::GetReferencedFilePaths(
return to_return;
}
-void FormController::RegisterStatefulFormControl(
- HTMLFormControlElementWithState& control) {
- document_state_->AddControl(&control);
-}
-
-void FormController::UnregisterStatefulFormControl(
- HTMLFormControlElementWithState& control) {
- document_state_->RemoveControl(&control);
+void FormController::InvalidateStatefulFormControlList() {
+ document_state_->InvalidateControlList();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_controller.h b/chromium/third_party/blink/renderer/core/html/forms/form_controller.h
index 9ac07b4719f..b3a29fe556e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_controller.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_controller.h
@@ -24,8 +24,8 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_FORM_CONTROLLER_H_
#include <memory>
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
@@ -33,6 +33,7 @@
namespace blink {
+class Document;
class FormKeyGenerator;
class HTMLFormControlElementWithState;
class HTMLFormElement;
@@ -76,32 +77,31 @@ inline void FormControlState::Append(const String& value) {
using SavedFormStateMap =
HashMap<AtomicString, std::unique_ptr<SavedFormState>>;
-class DocumentState final : public GarbageCollected<DocumentState> {
+class CORE_EXPORT DocumentState final
+ : public GarbageCollectedFinalized<DocumentState> {
public:
- static DocumentState* Create();
- void Trace(blink::Visitor*);
+ DocumentState(Document& document);
+ void Trace(Visitor*);
- void AddControl(HTMLFormControlElementWithState*);
- void RemoveControl(HTMLFormControlElementWithState*);
+ void InvalidateControlList();
Vector<String> ToStateVector();
private:
- using FormElementList = HeapDoublyLinkedList<HTMLFormControlElementWithState>;
+ Member<Document> document_;
+ using FormElementList =
+ HeapVector<Member<HTMLFormControlElementWithState>, 64>;
FormElementList form_controls_;
+ bool form_controls_dirty_ = true;
};
-class FormController final : public GarbageCollectedFinalized<FormController> {
+class CORE_EXPORT FormController final
+ : public GarbageCollectedFinalized<FormController> {
public:
- static FormController* Create() {
- return MakeGarbageCollected<FormController>();
- }
-
- FormController();
+ FormController(Document& document);
~FormController();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
- void RegisterStatefulFormControl(HTMLFormControlElementWithState&);
- void UnregisterStatefulFormControl(HTMLFormControlElementWithState&);
+ void InvalidateStatefulFormControlList();
// This should be callled only by Document::formElementsState().
DocumentState* FormElementsState() const;
// This should be callled only by Document::setStateForNewFormElements().
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_controller_test.cc b/chromium/third_party/blink/renderer/core/html/forms/form_controller_test.cc
new file mode 100644
index 00000000000..bfd571e55f6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_controller_test.cc
@@ -0,0 +1,31 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/forms/form_controller.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/html_names.h"
+
+namespace blink {
+
+TEST(DocumentStateTest, ToStateVectorConnected) {
+ Document& doc = *Document::CreateForTest();
+ Element* html = doc.CreateRawElement(html_names::kHTMLTag);
+ doc.appendChild(html);
+ Node* body = html->appendChild(doc.CreateRawElement(html_names::kBodyTag));
+ ToElement(body)->SetInnerHTMLFromString("<select form='ff'></select>");
+ DocumentState* document_state = doc.GetFormController().FormElementsState();
+ Vector<String> state1 = document_state->ToStateVector();
+ // <signature>, <control-size>, <form-key>, <name>, <type>, <data-size(0)>
+ EXPECT_EQ(6u, state1.size());
+ Node* select = body->firstChild();
+ select->remove();
+ // Success if the following ToStateVector() doesn't fail with a DCHECK.
+ Vector<String> state2 = document_state->ToStateVector();
+ EXPECT_EQ(0u, state2.size());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_data.cc b/chromium/third_party/blink/renderer/core/html/forms/form_data.cc
index f3dd566a761..8a4627a0d49 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_data.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_data.cc
@@ -68,7 +68,7 @@ class FormDataIterationSource final
return true;
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(form_data_);
PairIterable<String, FormDataEntryValue>::IterationSource::Trace(visitor);
}
@@ -96,21 +96,24 @@ FormData::FormData() : encoding_(UTF8Encoding()) {}
FormData* FormData::Create(HTMLFormElement* form,
ExceptionState& exception_state) {
- auto* form_data = MakeGarbageCollected<FormData>();
// TODO(tkent): Null check should be unnecessary. We should remove
// LegacyInterfaceTypeChecking from form_data.idl. crbug.com/561338
if (!form)
- return form_data;
- if (!form->ConstructEntryList(nullptr, *form_data)) {
+ return MakeGarbageCollected<FormData>();
+ FormData* form_data = form->ConstructEntryList(nullptr, UTF8Encoding());
+ if (!form_data) {
DCHECK(RuntimeEnabledFeatures::FormDataEventEnabled());
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"The form is constructing entry list.");
return nullptr;
}
- return form_data;
+ // Return a shallow copy of |form_data| because |form_data| is visible in
+ // "formdata" event, and the specification says it should be different from
+ // the FormData object to be returned.
+ return MakeGarbageCollected<FormData>(*form_data);
}
-void FormData::Trace(blink::Visitor* visitor) {
+void FormData::Trace(Visitor* visitor) {
visitor->Trace(entries_);
ScriptWrappable::Trace(visitor);
}
@@ -322,7 +325,7 @@ scoped_refptr<EncodedFormData> FormData::EncodeMultiPartFormData() {
PairIterable<String, FormDataEntryValue>::IterationSource*
FormData::StartIteration(ScriptState*, ExceptionState&) {
- return new FormDataIterationSource(this);
+ return MakeGarbageCollected<FormDataIterationSource>(this);
}
// ----------------------------------------------------------------
@@ -341,7 +344,7 @@ FormData::Entry::Entry(const String& name, Blob* blob, const String& filename)
<< "'name' should be a USVString.";
}
-void FormData::Entry::Trace(blink::Visitor* visitor) {
+void FormData::Entry::Trace(Visitor* visitor) {
visitor->Trace(blob_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_data.h b/chromium/third_party/blink/renderer/core/html/forms/form_data.h
index d3b6aebf6df..8335bbe1115 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_data.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_data.h
@@ -70,7 +70,7 @@ class CORE_EXPORT FormData final
// doesn't clone entries in it because they are immutable.
FormData(const FormData& form_data);
FormData();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// FormData IDL interface.
void append(const String& name, const String& value);
@@ -123,7 +123,7 @@ class FormData::Entry : public GarbageCollectedFinalized<FormData::Entry> {
public:
Entry(const String& name, const String& value);
Entry(const String& name, Blob* blob, const String& filename);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
bool IsString() const { return !blob_; }
bool isFile() const { return blob_; }
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_data_event.cc b/chromium/third_party/blink/renderer/core/html/forms/form_data_event.cc
index 86cb6840115..9b077df8cc7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_data_event.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_data_event.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/event_interface_names.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
+#include "third_party/blink/renderer/core/html/forms/form_data_event_init.h"
namespace blink {
@@ -13,10 +14,24 @@ FormDataEvent::FormDataEvent(FormData& form_data)
: Event(event_type_names::kFormdata, Bubbles::kYes, Cancelable::kNo),
form_data_(form_data) {}
+FormDataEvent::FormDataEvent(const AtomicString& type,
+ const FormDataEventInit* event_init)
+ : Event(type, event_init), form_data_(event_init->formData()) {}
+
FormDataEvent* FormDataEvent::Create(FormData& form_data) {
return MakeGarbageCollected<FormDataEvent>(form_data);
}
+FormDataEvent* FormDataEvent::Create(const AtomicString& type,
+ const FormDataEventInit* event_init) {
+ // FormDataEventInit contains the required 'formData' member.
+ // Binding-generated code guarantees that event_init contains non-null
+ // |formData|.
+ DCHECK(event_init);
+ DCHECK(event_init->formData());
+ return MakeGarbageCollected<FormDataEvent>(type, event_init);
+}
+
void FormDataEvent::Trace(Visitor* visitor) {
visitor->Trace(form_data_);
Event::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_data_event.h b/chromium/third_party/blink/renderer/core/html/forms/form_data_event.h
index 8b94cb06187..820b8b2da2b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_data_event.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_data_event.h
@@ -10,14 +10,17 @@
namespace blink {
class FormData;
+class FormDataEventInit;
class FormDataEvent : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
static FormDataEvent* Create(FormData& form_data);
-
+ static FormDataEvent* Create(const AtomicString& type,
+ const FormDataEventInit* event_init);
FormDataEvent(FormData& form_data);
+ FormDataEvent(const AtomicString& type, const FormDataEventInit* event_init);
void Trace(Visitor* visitor) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_data_event.idl b/chromium/third_party/blink/renderer/core/html/forms/form_data_event.idl
index 1b7c1bca272..e507662757b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/form_data_event.idl
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_data_event.idl
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.je8c7y5qpgki
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#formdataevent
[
+ Constructor(DOMString type, optional FormDataEventInit eventInitDict),
Exposed=Window,
RuntimeEnabled=FormDataEvent
]
diff --git a/chromium/third_party/blink/renderer/core/html/forms/form_data_event_init.idl b/chromium/third_party/blink/renderer/core/html/forms/form_data_event_init.idl
new file mode 100644
index 00000000000..3872929e83d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/forms/form_data_event_init.idl
@@ -0,0 +1,9 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#formdataeventinit
+
+dictionary FormDataEventInit : EventInit {
+ required FormData formData;
+};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
index c4c2c1ae087..16df6671d68 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
@@ -45,7 +45,7 @@ InputType* HiddenInputType::Create(HTMLInputElement& element) {
return MakeGarbageCollected<HiddenInputType>(element);
}
-void HiddenInputType::Trace(blink::Visitor* visitor) {
+void HiddenInputType::Trace(Visitor* visitor) {
InputTypeView::Trace(visitor);
InputType::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h
index dfcc310a336..dfaa025062b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h
@@ -45,7 +45,7 @@ class HiddenInputType final : public InputType, private InputTypeView {
HiddenInputType(HTMLInputElement& element)
: InputType(element), InputTypeView(element) {}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
private:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc
index 91141142733..97a25201cdd 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc
@@ -46,6 +46,13 @@ HTMLButtonElement* HTMLButtonElement::Create(Document& document) {
return MakeGarbageCollected<HTMLButtonElement>(document);
}
+const AttrNameToTrustedType& HTMLButtonElement::GetCheckedAttributeTypes()
+ const {
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"formaction", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
+}
+
void HTMLButtonElement::setType(const AtomicString& type) {
setAttribute(kTypeAttr, type);
}
@@ -94,7 +101,7 @@ void HTMLButtonElement::ParseAttribute(
type_ = BUTTON;
else
type_ = SUBMIT;
- SetNeedsWillValidateCheck();
+ UpdateWillValidateCache();
if (formOwner() && isConnected())
formOwner()->InvalidateDefaultButtonStyle();
} else {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h
index 9347255a87d..ba1b2492fa9 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h
@@ -36,6 +36,8 @@ class HTMLButtonElement final : public HTMLFormControlElement {
explicit HTMLButtonElement(Document&);
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
+
void setType(const AtomicString&);
const AtomicString& Value() const;
@@ -61,7 +63,7 @@ class HTMLButtonElement final : public HTMLFormControlElement {
void AppendToFormData(FormData&) override;
bool IsEnumeratable() const override { return true; }
- bool SupportLabels() const override { return true; }
+ bool IsLabelable() const override { return true; }
bool ShouldForceLegacyLayout() const final { return true; }
bool IsInteractiveContent() const override;
bool SupportsAutofocus() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.idl b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.idl
index a56286740c9..4b9d00eadae 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.idl
@@ -24,7 +24,7 @@ interface HTMLButtonElement : HTMLElement {
[CEReactions, Reflect] attribute boolean autofocus;
[CEReactions, Reflect] attribute boolean disabled;
[ImplementedAs=formOwner] readonly attribute HTMLFormElement? form;
- [CEReactions] attribute DOMString formAction;
+ [CEReactions, RaisesException=Setter] attribute URLString formAction;
[CEReactions] attribute DOMString formEnctype;
[CEReactions] attribute DOMString formMethod;
[CEReactions, Reflect] attribute boolean formNoValidate;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
index 08e25f7fce1..e8225573ccf 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
+#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
#include "third_party/blink/renderer/core/html/html_collection.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -53,8 +54,11 @@ bool HTMLFieldSetElement::MatchesValidityPseudoClasses() const {
bool HTMLFieldSetElement::IsValidElement() {
for (Element* element : *elements()) {
if (element->IsFormControlElement()) {
- if (!ToHTMLFormControlElement(element)->checkValidity(
- nullptr, kCheckValidityDispatchNoEvent))
+ if (!ToHTMLFormControlElement(element)->IsNotCandidateOrValid())
+ return false;
+ } else if (element->IsHTMLElement() &&
+ ToHTMLElement(element)->IsFormAssociatedCustomElement()) {
+ if (!element->EnsureElementInternals().IsNotCandidateOrValid())
return false;
}
}
@@ -73,9 +77,13 @@ HTMLFieldSetElement::InvalidateDescendantDisabledStateAndFindFocusedOne(
bool should_blur = false;
{
EventDispatchForbiddenScope event_forbidden;
- for (HTMLFormControlElement& element :
- Traversal<HTMLFormControlElement>::DescendantsOf(base)) {
- element.AncestorDisabledStateWasChanged();
+ for (HTMLElement& element : Traversal<HTMLElement>::DescendantsOf(base)) {
+ if (auto* control = ToHTMLFormControlElementOrNull(element))
+ control->AncestorDisabledStateWasChanged();
+ else if (element.IsFormAssociatedCustomElement())
+ element.EnsureElementInternals().AncestorDisabledStateWasChanged();
+ else
+ continue;
if (focused_element == &element && element.IsDisabledFormControl())
should_blur = true;
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
index eab7f277272..25e03d1b887 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -24,24 +24,19 @@
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
-#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/validity_state.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/validation_message_client.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
-#include "third_party/blink/renderer/platform/text/bidi_text_run.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
@@ -50,14 +45,8 @@ using namespace html_names;
HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tag_name,
Document& document)
- : LabelableElement(tag_name, document),
+ : HTMLElement(tag_name, document),
autofill_state_(WebAutofillState::kNotFilled),
- data_list_ancestor_state_(kUnknown),
- has_validation_message_(false),
- will_validate_initialized_(false),
- will_validate_(true),
- is_valid_(true),
- validity_is_dirty_(false),
blocks_form_submission_(false) {
SetHasCustomStyleCallbacks();
static unsigned next_free_unique_id = 0;
@@ -66,20 +55,24 @@ HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tag_name,
HTMLFormControlElement::~HTMLFormControlElement() = default;
-void HTMLFormControlElement::Trace(blink::Visitor* visitor) {
+void HTMLFormControlElement::Trace(Visitor* visitor) {
ListedElement::Trace(visitor);
- LabelableElement::Trace(visitor);
+ HTMLElement::Trace(visitor);
}
-String HTMLFormControlElement::formAction() const {
+void HTMLFormControlElement::formAction(USVStringOrTrustedURL& result) const {
const AtomicString& action = FastGetAttribute(kFormactionAttr);
- if (action.IsEmpty())
- return GetDocument().Url();
- return GetDocument().CompleteURL(StripLeadingAndTrailingHTMLSpaces(action));
+ if (action.IsEmpty()) {
+ result.SetUSVString(GetDocument().Url());
+ return;
+ }
+ result.SetUSVString(
+ GetDocument().CompleteURL(StripLeadingAndTrailingHTMLSpaces(action)));
}
-void HTMLFormControlElement::setFormAction(const AtomicString& value) {
- setAttribute(kFormactionAttr, value);
+void HTMLFormControlElement::setFormAction(const USVStringOrTrustedURL& value,
+ ExceptionState& exception_state) {
+ setAttribute(kFormactionAttr, value, exception_state);
}
String HTMLFormControlElement::formEnctype() const {
@@ -134,7 +127,7 @@ void HTMLFormControlElement::ParseAttribute(
UseCounter::Count(GetDocument(), WebFeature::kFormAttribute);
} else if (name == kReadonlyAttr) {
if (params.old_value.IsNull() != params.new_value.IsNull()) {
- SetNeedsWillValidateCheck();
+ UpdateWillValidateCache();
PseudoStateChanged(CSSSelector::kPseudoReadOnly);
PseudoStateChanged(CSSSelector::kPseudoReadWrite);
if (LayoutObject* o = GetLayoutObject())
@@ -157,7 +150,6 @@ void HTMLFormControlElement::DisabledAttributeChanged() {
// <fieldset> while tree traversal.
EventDispatchForbiddenScope event_forbidden;
- SetNeedsWillValidateCheck();
ListedElement::DisabledAttributeChanged();
if (LayoutObject* o = GetLayoutObject())
o->InvalidateIfControlStateChanged(kEnabledControlState);
@@ -261,65 +253,28 @@ void HTMLFormControlElement::DidMoveToNewDocument(Document& old_document) {
Node::InsertionNotificationRequest HTMLFormControlElement::InsertedInto(
ContainerNode& insertion_point) {
- data_list_ancestor_state_ = kUnknown;
HTMLElement::InsertedInto(insertion_point);
ListedElement::InsertedInto(insertion_point);
- SetNeedsWillValidateCheck();
- FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
-
- // Trigger for elements outside of forms.
- if (!formOwner() && insertion_point.isConnected())
- GetDocument().DidAssociateFormControl(this);
-
return kInsertionDone;
}
void HTMLFormControlElement::RemovedFrom(ContainerNode& insertion_point) {
- FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
- HideVisibleValidationMessage();
- has_validation_message_ = false;
- data_list_ancestor_state_ = kUnknown;
HTMLElement::RemovedFrom(insertion_point);
ListedElement::RemovedFrom(insertion_point);
- SetNeedsWillValidateCheck();
}
void HTMLFormControlElement::WillChangeForm() {
ListedElement::WillChangeForm();
- FormOwnerSetNeedsValidityCheck();
if (formOwner() && CanBeSuccessfulSubmitButton())
formOwner()->InvalidateDefaultButtonStyle();
}
void HTMLFormControlElement::DidChangeForm() {
ListedElement::DidChangeForm();
- FormOwnerSetNeedsValidityCheck();
if (formOwner() && isConnected() && CanBeSuccessfulSubmitButton())
formOwner()->InvalidateDefaultButtonStyle();
}
-void HTMLFormControlElement::FormOwnerSetNeedsValidityCheck() {
- if (HTMLFormElement* form = formOwner()) {
- form->PseudoStateChanged(CSSSelector::kPseudoValid);
- form->PseudoStateChanged(CSSSelector::kPseudoInvalid);
- }
-}
-
-void HTMLFormControlElement::FieldSetAncestorsSetNeedsValidityCheck(
- Node* node) {
- if (!node)
- return;
- if (!may_have_field_set_ancestor_)
- return;
- for (HTMLFieldSetElement* field_set =
- Traversal<HTMLFieldSetElement>::FirstAncestorOrSelf(*node);
- field_set;
- field_set = Traversal<HTMLFieldSetElement>::FirstAncestor(*field_set)) {
- field_set->PseudoStateChanged(CSSSelector::kPseudoValid);
- field_set->PseudoStateChanged(CSSSelector::kPseudoInvalid);
- }
-}
-
void HTMLFormControlElement::DispatchChangeEvent() {
DispatchScopedEvent(*Event::CreateBubble(event_type_names::kChange));
}
@@ -378,164 +333,8 @@ int HTMLFormControlElement::tabIndex() const {
return Element::tabIndex();
}
-bool HTMLFormControlElement::RecalcWillValidate() const {
- if (data_list_ancestor_state_ == kUnknown) {
- if (Traversal<HTMLDataListElement>::FirstAncestor(*this))
- data_list_ancestor_state_ = kInsideDataList;
- else
- data_list_ancestor_state_ = kNotInsideDataList;
- }
- return data_list_ancestor_state_ == kNotInsideDataList &&
- !IsDisabledOrReadOnly();
-}
-
bool HTMLFormControlElement::willValidate() const {
- if (!will_validate_initialized_ || data_list_ancestor_state_ == kUnknown) {
- const_cast<HTMLFormControlElement*>(this)->SetNeedsWillValidateCheck();
- } else {
- // If the following assertion fails, setNeedsWillValidateCheck() is not
- // called correctly when something which changes recalcWillValidate() result
- // is updated.
- DCHECK_EQ(will_validate_, RecalcWillValidate());
- }
- return will_validate_;
-}
-
-void HTMLFormControlElement::SetNeedsWillValidateCheck() {
- // We need to recalculate willValidate immediately because willValidate change
- // can causes style change.
- bool new_will_validate = RecalcWillValidate();
- if (will_validate_initialized_ && will_validate_ == new_will_validate)
- return;
- will_validate_initialized_ = true;
- will_validate_ = new_will_validate;
- // Needs to force SetNeedsValidityCheck() to invalidate validity state of
- // FORM/FIELDSET. If this element updates willValidate twice and
- // IsValidElement() is not called between them, the second call of this
- // function still has validity_is_dirty_==true, which means
- // SetNeedsValidityCheck() doesn't invalidate validity state of
- // FORM/FIELDSET.
- validity_is_dirty_ = false;
- SetNeedsValidityCheck();
- // No need to trigger style recalculation here because
- // SetNeedsValidityCheck() does it in the right away. This relies on
- // the assumption that Valid() is always true if willValidate() is false.
-
- if (!will_validate_)
- HideVisibleValidationMessage();
-}
-
-void HTMLFormControlElement::FindCustomValidationMessageTextDirection(
- const String& message,
- TextDirection& message_dir,
- String& sub_message,
- TextDirection& sub_message_dir) {
- message_dir = DetermineDirectionality(message);
- if (!sub_message.IsEmpty())
- sub_message_dir = GetLayoutObject()->Style()->Direction();
-}
-
-void HTMLFormControlElement::UpdateVisibleValidationMessage() {
- Page* page = GetDocument().GetPage();
- if (!page || !page->IsPageVisible() || GetDocument().UnloadStarted())
- return;
- if (page->Paused())
- return;
- String message;
- if (GetLayoutObject() && willValidate())
- message = validationMessage().StripWhiteSpace();
-
- has_validation_message_ = true;
- ValidationMessageClient* client = &page->GetValidationMessageClient();
- TextDirection message_dir = TextDirection::kLtr;
- TextDirection sub_message_dir = TextDirection::kLtr;
- String sub_message = ValidationSubMessage().StripWhiteSpace();
- if (message.IsEmpty()) {
- client->HideValidationMessage(*this);
- } else {
- FindCustomValidationMessageTextDirection(message, message_dir, sub_message,
- sub_message_dir);
- }
- client->ShowValidationMessage(*this, message, message_dir, sub_message,
- sub_message_dir);
-}
-
-void HTMLFormControlElement::HideVisibleValidationMessage() {
- if (!has_validation_message_)
- return;
-
- if (ValidationMessageClient* client = GetValidationMessageClient())
- client->HideValidationMessage(*this);
-}
-
-bool HTMLFormControlElement::IsValidationMessageVisible() const {
- if (!has_validation_message_)
- return false;
-
- ValidationMessageClient* client = GetValidationMessageClient();
- if (!client)
- return false;
-
- return client->IsValidationMessageVisible(*this);
-}
-
-ValidationMessageClient* HTMLFormControlElement::GetValidationMessageClient()
- const {
- Page* page = GetDocument().GetPage();
- if (!page)
- return nullptr;
-
- return &page->GetValidationMessageClient();
-}
-
-bool HTMLFormControlElement::checkValidity(
- HeapVector<Member<HTMLFormControlElement>>* unhandled_invalid_controls,
- CheckValidityEventBehavior event_behavior) {
- if (!willValidate())
- return true;
- if (IsValidElement())
- return true;
- if (event_behavior != kCheckValidityDispatchInvalidEvent)
- return false;
- Document* original_document = &GetDocument();
- DispatchEventResult dispatch_result =
- DispatchEvent(*Event::CreateCancelable(event_type_names::kInvalid));
- if (dispatch_result == DispatchEventResult::kNotCanceled &&
- unhandled_invalid_controls && isConnected() &&
- original_document == GetDocument())
- unhandled_invalid_controls->push_back(this);
- return false;
-}
-
-void HTMLFormControlElement::ShowValidationMessage() {
- scrollIntoViewIfNeeded(false);
- focus();
- UpdateVisibleValidationMessage();
-}
-
-bool HTMLFormControlElement::reportValidity() {
- HeapVector<Member<HTMLFormControlElement>> unhandled_invalid_controls;
- bool is_valid = checkValidity(&unhandled_invalid_controls,
- kCheckValidityDispatchInvalidEvent);
- if (is_valid || unhandled_invalid_controls.IsEmpty())
- return is_valid;
- DCHECK_EQ(unhandled_invalid_controls.size(), 1u);
- DCHECK_EQ(unhandled_invalid_controls[0].Get(), this);
- // Update layout now before calling isFocusable(), which has
- // !layoutObject()->needsLayout() assertion.
- GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
- if (IsFocusable()) {
- ShowValidationMessage();
- return false;
- }
- if (GetDocument().GetFrame()) {
- String message(
- "An invalid form control with name='%name' is not focusable.");
- message.Replace("%name", GetName());
- GetDocument().AddConsoleMessage(ConsoleMessage::Create(
- kRenderingMessageSource, kErrorMessageLevel, message));
- }
- return false;
+ return ListedElement::WillValidate();
}
bool HTMLFormControlElement::MatchesValidityPseudoClasses() const {
@@ -543,42 +342,7 @@ bool HTMLFormControlElement::MatchesValidityPseudoClasses() const {
}
bool HTMLFormControlElement::IsValidElement() {
- if (validity_is_dirty_) {
- is_valid_ = !willValidate() || Valid();
- validity_is_dirty_ = false;
- } else {
- // If the following assertion fails, setNeedsValidityCheck() is not
- // called correctly when something which changes validity is updated.
- DCHECK_EQ(is_valid_, (!willValidate() || Valid()));
- }
- return is_valid_;
-}
-
-void HTMLFormControlElement::SetNeedsValidityCheck() {
- if (!validity_is_dirty_) {
- validity_is_dirty_ = true;
- FormOwnerSetNeedsValidityCheck();
- FieldSetAncestorsSetNeedsValidityCheck(parentNode());
- PseudoStateChanged(CSSSelector::kPseudoValid);
- PseudoStateChanged(CSSSelector::kPseudoInvalid);
- }
-
- // Updates only if this control already has a validation message.
- if (IsValidationMessageVisible()) {
- // Calls UpdateVisibleValidationMessage() even if is_valid_ is not
- // changed because a validation message can be changed.
- GetDocument()
- .GetTaskRunner(TaskType::kDOMManipulation)
- ->PostTask(
- FROM_HERE,
- WTF::Bind(&HTMLFormControlElement::UpdateVisibleValidationMessage,
- WrapPersistent(this)));
- }
-}
-
-void HTMLFormControlElement::setCustomValidity(const String& error) {
- ListedElement::setCustomValidity(error);
- SetNeedsValidityCheck();
+ return ListedElement::IsValidElement();
}
void HTMLFormControlElement::DispatchBlurEvent(
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.h
index 42397ca9ed1..1bccce5aff7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.h
@@ -29,33 +29,27 @@
#include "third_party/blink/public/web/web_autofill_state.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/html/forms/form_associated.h"
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
#include "third_party/blink/renderer/core/html/forms/listed_element.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
class HTMLFormElement;
-class ValidationMessageClient;
-
-enum CheckValidityEventBehavior {
- kCheckValidityDispatchNoEvent,
- kCheckValidityDispatchInvalidEvent
-};
// HTMLFormControlElement is the default implementation of
// ListedElement, and listed element implementations should use
// HTMLFormControlElement unless there is a special reason.
-class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
+class CORE_EXPORT HTMLFormControlElement : public HTMLElement,
public ListedElement,
public FormAssociated {
USING_GARBAGE_COLLECTED_MIXIN(HTMLFormControlElement);
public:
~HTMLFormControlElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
- String formAction() const;
- void setFormAction(const AtomicString&);
+ void formAction(USVStringOrTrustedURL&) const;
+ void setFormAction(const USVStringOrTrustedURL&, ExceptionState&);
String formEnctype() const;
void setFormEnctype(const AtomicString&);
String formMethod() const;
@@ -98,25 +92,6 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
bool willValidate() const override;
- void UpdateVisibleValidationMessage();
- void HideVisibleValidationMessage();
- bool checkValidity(
- HeapVector<Member<HTMLFormControlElement>>* unhandled_invalid_controls =
- nullptr,
- CheckValidityEventBehavior = kCheckValidityDispatchInvalidEvent);
- bool reportValidity();
- // This must be called only after the caller check the element is focusable.
- void ShowValidationMessage();
- bool IsValidationMessageVisible() const;
- // This must be called when a validation constraint or control value is
- // changed.
- void SetNeedsValidityCheck();
- void setCustomValidity(const String&) final;
- void FindCustomValidationMessageTextDirection(const String& message,
- TextDirection& message_dir,
- String& sub_message,
- TextDirection& sub_message_dir);
-
bool IsReadOnly() const;
bool IsDisabledOrReadOnly() const;
@@ -177,10 +152,6 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
void DidRecalcStyle(StyleRecalcChange) override;
- // This must be called any time the result of willValidate() has changed.
- void SetNeedsWillValidateCheck();
- virtual bool RecalcWillValidate() const;
-
virtual void ResetImpl() {}
virtual bool SupportsAutofocus() const;
@@ -193,32 +164,11 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
bool IsValidElement() override;
bool MatchesValidityPseudoClasses() const override;
- ValidationMessageClient* GetValidationMessageClient() const;
-
- // Requests validity recalc for the form owner, if one exists.
- void FormOwnerSetNeedsValidityCheck();
- // Requests validity recalc for all ancestor fieldsets, if exist.
- void FieldSetAncestorsSetNeedsValidityCheck(Node*);
-
unsigned unique_renderer_form_control_id_;
WebString autofill_section_;
enum WebAutofillState autofill_state_;
- enum DataListAncestorState { kUnknown, kInsideDataList, kNotInsideDataList };
- mutable enum DataListAncestorState data_list_ancestor_state_;
-
- bool has_validation_message_ : 1;
- // The initial value of will_validate_ depends on the derived class. We can't
- // initialize it with a virtual function in the constructor. will_validate_
- // is not deterministic as long as will_validate_initialized_ is false.
- mutable bool will_validate_initialized_ : 1;
- mutable bool will_validate_ : 1;
-
- // Cache of valid().
- bool is_valid_ : 1;
- bool validity_is_dirty_ : 1;
-
bool blocks_form_submission_ : 1;
};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_test.cc b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_test.cc
index a152ce28a85..6726d520251 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_test.cc
@@ -44,7 +44,7 @@ class MockFormValidationMessageClient
void DocumentDetached(const Document&) override {}
void WillBeDestroyed() override {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(anchor_);
ValidationMessageClient::Trace(visitor);
}
@@ -117,7 +117,7 @@ TEST_F(HTMLFormControlElementTest, customValidationMessageTextDirection) {
TEST_F(HTMLFormControlElementTest, UpdateValidationMessageSkippedIfPrinting) {
SetHtmlInnerHTML("<body><input required id=input></body>");
ValidationMessageClient* validation_message_client =
- new MockFormValidationMessageClient();
+ MakeGarbageCollected<MockFormValidationMessageClient>();
GetPage().SetValidationMessageClientForTesting(validation_message_client);
Page::OrdinaryPages().insert(&GetPage());
@@ -137,7 +137,8 @@ TEST_F(HTMLFormControlElementTest, DoNotUpdateLayoutDuringDOMMutation) {
ToHTMLFormControlElement(GetDocument().QuerySelector("select"));
auto* const optgroup =
GetDocument().CreateRawElement(html_names::kOptgroupTag);
- auto* validation_client = new MockFormValidationMessageClient();
+ auto* validation_client =
+ MakeGarbageCollected<MockFormValidationMessageClient>();
GetDocument().GetPage()->SetValidationMessageClientForTesting(
validation_client);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.cc b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.cc
index 48c95e73363..9dee6ad021c 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.cc
@@ -24,12 +24,8 @@
#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
-#include "third_party/blink/renderer/core/html/forms/form_controller.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/input_type_names.h"
-#include "third_party/blink/renderer/core/page/chrome_client.h"
namespace blink {
@@ -120,21 +116,6 @@ HTMLFormControlElementWithState::HTMLFormControlElementWithState(
HTMLFormControlElementWithState::~HTMLFormControlElementWithState() = default;
-Node::InsertionNotificationRequest
-HTMLFormControlElementWithState::InsertedInto(ContainerNode& insertion_point) {
- if (insertion_point.isConnected() && !ContainingShadowRoot())
- GetDocument().GetFormController().RegisterStatefulFormControl(*this);
- return HTMLFormControlElement::InsertedInto(insertion_point);
-}
-
-void HTMLFormControlElementWithState::RemovedFrom(
- ContainerNode& insertion_point) {
- if (insertion_point.isConnected() && !ContainingShadowRoot() &&
- !insertion_point.ContainingShadowRoot())
- GetDocument().GetFormController().UnregisterStatefulFormControl(*this);
- HTMLFormControlElement::RemovedFrom(insertion_point);
-}
-
bool HTMLFormControlElementWithState::ShouldAutocomplete() const {
if (!Form())
return true;
@@ -284,37 +265,19 @@ void HTMLFormControlElementWithState::setIDLExposedAutofillValue(
setAttribute(html_names::kAutocompleteAttr, AtomicString(autocomplete_value));
}
-void HTMLFormControlElementWithState::NotifyFormStateChanged() {
- // This can be called during fragment parsing as a result of option
- // selection before the document is active (or even in a frame).
- if (!GetDocument().IsActive())
- return;
- GetDocument().GetFrame()->Client()->DidUpdateCurrentHistoryItem();
-}
-
bool HTMLFormControlElementWithState::ShouldSaveAndRestoreFormControlState()
const {
// We don't save/restore control state in a form with autocomplete=off.
return isConnected() && ShouldAutocomplete();
}
-FormControlState HTMLFormControlElementWithState::SaveFormControlState() const {
- return FormControlState();
-}
-
void HTMLFormControlElementWithState::FinishParsingChildren() {
HTMLFormControlElement::FinishParsingChildren();
- GetDocument().GetFormController().RestoreControlStateFor(*this);
+ ListedElement::TakeStateAndRestore();
}
bool HTMLFormControlElementWithState::IsFormControlElementWithState() const {
return true;
}
-void HTMLFormControlElementWithState::Trace(Visitor* visitor) {
- visitor->Trace(prev_);
- visitor->Trace(next_);
- HTMLFormControlElement::Trace(visitor);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h
index 67485f09696..3ce72691f53 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h
@@ -27,21 +27,11 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
-#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
namespace blink {
-class FormControlState;
-
-class HTMLFormControlElementWithState;
-// Cannot use eager tracing as HTMLFormControlElementWithState objects are part
-// of a HeapDoublyLinkedList and have pointers to the previous and next elements
-// in the list, which can cause very deep stacks in eager tracing.
-WILL_NOT_BE_EAGERLY_TRACED_CLASS(HTMLFormControlElementWithState);
-
class CORE_EXPORT HTMLFormControlElementWithState
- : public HTMLFormControlElement,
- public DoublyLinkedListNode<HTMLFormControlElementWithState> {
+ : public HTMLFormControlElement {
public:
~HTMLFormControlElementWithState() override;
@@ -52,13 +42,9 @@ class CORE_EXPORT HTMLFormControlElementWithState
String IDLExposedAutofillValue() const;
void setIDLExposedAutofillValue(const String& autocomplete_value);
- virtual bool ShouldSaveAndRestoreFormControlState() const;
- virtual FormControlState SaveFormControlState() const;
- // The specified FormControlState must have at least one string value.
- virtual void RestoreFormControlState(const FormControlState&) {}
- void NotifyFormStateChanged();
+ // ListedElement override:
+ bool ShouldSaveAndRestoreFormControlState() const override;
- void Trace(Visitor*) override;
bool UserHasEditedTheField() const { return user_has_edited_the_field_; }
// This is only used in tests, to fake the user's action
void SetUserHasEditedTheFieldForTest() { user_has_edited_the_field_ = true; }
@@ -68,8 +54,6 @@ class CORE_EXPORT HTMLFormControlElementWithState
HTMLFormControlElementWithState(const QualifiedName& tag_name, Document&);
void FinishParsingChildren() override;
- InsertionNotificationRequest InsertedInto(ContainerNode&) override;
- void RemovedFrom(ContainerNode&) override;
bool IsFormControlElementWithState() const final;
private:
@@ -77,14 +61,6 @@ class CORE_EXPORT HTMLFormControlElementWithState
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-anchor-mantle
bool IsWearingAutofillAnchorMantle() const;
-
- // Pointers for DoublyLinkedListNode<HTMLFormControlElementWithState>. This
- // is used for adding an instance to a list of form controls stored in
- // DocumentState. Each instance is only added to its containing document's
- // DocumentState list.
- friend class WTF::DoublyLinkedListNode<HTMLFormControlElementWithState>;
- Member<HTMLFormControlElementWithState> prev_;
- Member<HTMLFormControlElementWithState> next_;
};
DEFINE_TYPE_CASTS(HTMLFormControlElementWithState,
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.cc b/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.cc
index d7319390bda..3846dc3eb6e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.cc
@@ -221,7 +221,7 @@ void HTMLFormControlsCollection::SupportedPropertyNames(Vector<String>& names) {
}
}
-void HTMLFormControlsCollection::Trace(blink::Visitor* visitor) {
+void HTMLFormControlsCollection::Trace(Visitor* visitor) {
visitor->Trace(cached_element_);
HTMLCollection::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.h b/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.h
index 590ea51df68..ed14f970415 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_controls_collection.h
@@ -54,7 +54,7 @@ class HTMLFormControlsCollection final : public HTMLCollection {
HTMLElement* namedItem(const AtomicString& name) const override;
void namedGetter(const AtomicString& name, RadioNodeListOrElement&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void UpdateIdNameCache() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.cc
index 471e80e6cf1..6a73a89661a 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/bindings/core/v8/radio_node_list_or_element.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_event_listener.h"
+#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
#include "third_party/blink/renderer/core/dom/attribute.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
@@ -44,6 +45,7 @@
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/remote_frame.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
@@ -62,6 +64,7 @@
#include "third_party/blink/renderer/core/loader/form_submission.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/loader/navigation_scheduler.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
@@ -87,7 +90,7 @@ HTMLFormElement* HTMLFormElement::Create(Document& document) {
HTMLFormElement::~HTMLFormElement() = default;
-void HTMLFormElement::Trace(blink::Visitor* visitor) {
+void HTMLFormElement::Trace(Visitor* visitor) {
visitor->Trace(past_names_map_);
visitor->Trace(radio_button_group_scope_);
visitor->Trace(listed_elements_);
@@ -96,13 +99,22 @@ void HTMLFormElement::Trace(blink::Visitor* visitor) {
HTMLElement::Trace(visitor);
}
+const AttrNameToTrustedType& HTMLFormElement::GetCheckedAttributeTypes() const {
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"action", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
+}
+
bool HTMLFormElement::MatchesValidityPseudoClasses() const {
return true;
}
bool HTMLFormElement::IsValidElement() {
- return !CheckInvalidControlsAndCollectUnhandled(
- nullptr, kCheckValidityDispatchNoEvent);
+ for (const auto& element : ListedElements()) {
+ if (!element->IsNotCandidateOrValid())
+ return false;
+ }
+ return true;
}
Node::InsertionNotificationRequest HTMLFormElement::InsertedInto(
@@ -207,14 +219,11 @@ void HTMLFormElement::SubmitImplicitly(Event& event,
bool HTMLFormElement::ValidateInteractively() {
UseCounter::Count(GetDocument(), WebFeature::kFormValidationStarted);
- for (const auto& element : ListedElements()) {
- if (element->IsFormControlElement())
- ToHTMLFormControlElement(element)->HideVisibleValidationMessage();
- }
+ for (const auto& element : ListedElements())
+ element->HideVisibleValidationMessage();
- HeapVector<Member<HTMLFormControlElement>> unhandled_invalid_controls;
- if (!CheckInvalidControlsAndCollectUnhandled(
- &unhandled_invalid_controls, kCheckValidityDispatchInvalidEvent))
+ ListedElement::List unhandled_invalid_controls;
+ if (!CheckInvalidControlsAndCollectUnhandled(&unhandled_invalid_controls))
return true;
UseCounter::Count(GetDocument(),
WebFeature::kFormValidationAbortedSubmission);
@@ -227,7 +236,7 @@ bool HTMLFormElement::ValidateInteractively() {
// Focus on the first focusable control and show a validation message.
for (const auto& unhandled : unhandled_invalid_controls) {
- if (unhandled->IsFocusable()) {
+ if (ToHTMLElement(unhandled)->IsFocusable()) {
unhandled->ShowValidationMessage();
UseCounter::Count(GetDocument(),
WebFeature::kFormValidationShowedMessage);
@@ -237,7 +246,7 @@ bool HTMLFormElement::ValidateInteractively() {
// Warn about all of unfocusable controls.
if (GetDocument().GetFrame()) {
for (const auto& unhandled : unhandled_invalid_controls) {
- if (unhandled->IsFocusable())
+ if (ToHTMLElement(unhandled)->IsFocusable())
continue;
String message(
"An invalid form control with name='%name' is not focusable.");
@@ -412,11 +421,13 @@ void HTMLFormElement::Submit(Event* event,
}
}
-bool HTMLFormElement::ConstructEntryList(HTMLFormControlElement* submit_button,
- FormData& form_data) {
+FormData* HTMLFormElement::ConstructEntryList(
+ HTMLFormControlElement* submit_button,
+ const WTF::TextEncoding& encoding) {
if (is_constructing_entry_list_) {
- return false;
+ return nullptr;
}
+ auto& form_data = *MakeGarbageCollected<FormData>(encoding);
base::AutoReset<bool> entry_list_scope(&is_constructing_entry_list_, true);
if (submit_button)
submit_button->SetActivatedSubmit(true);
@@ -436,7 +447,7 @@ bool HTMLFormElement::ConstructEntryList(HTMLFormControlElement* submit_button,
if (submit_button)
submit_button->SetActivatedSubmit(false);
- return true;
+ return &form_data;
}
void HTMLFormElement::ScheduleFormSubmission(FormSubmission* submission) {
@@ -467,10 +478,8 @@ void HTMLFormElement::ScheduleFormSubmission(FormSubmission* submission) {
UseCounter::Count(GetDocument(),
WebFeature::kFormDisabledAttributePresentAndSubmit);
}
- GetDocument()
- .GetFrame()
- ->GetScriptController()
- .ExecuteScriptIfJavaScriptURL(submission->Action(), this);
+ GetDocument().ProcessJavaScriptUrl(submission->Action(),
+ kCheckContentSecurityPolicy);
return;
}
@@ -534,6 +543,8 @@ void HTMLFormElement::reset() {
for (const auto& element : elements) {
if (element->IsFormControlElement())
ToHTMLFormControlElement(element)->Reset();
+ else if (element->IsElementInternals())
+ CustomElement::EnqueueFormResetCallback(*ToHTMLElement(element));
}
is_in_reset_function_ = false;
@@ -623,16 +634,8 @@ void HTMLFormElement::CollectListedElements(
ListedElement::List& elements) const {
elements.clear();
for (HTMLElement& element : Traversal<HTMLElement>::StartsAfter(root)) {
- ListedElement* listed_element = nullptr;
- if (element.IsFormControlElement())
- listed_element = ToHTMLFormControlElement(&element);
- else if (element.IsFormAssociatedCustomElement())
- listed_element = &element.EnsureElementInternals();
- else if (auto* object = ToHTMLObjectElementOrNull(element))
- listed_element = object;
- else
- continue;
- if (listed_element->Form() == this)
+ ListedElement* listed_element = ListedElement::From(element);
+ if (listed_element && listed_element->Form() == this)
elements.push_back(listed_element);
}
}
@@ -692,8 +695,13 @@ String HTMLFormElement::action() const {
return action_url.GetString();
}
-void HTMLFormElement::setAction(const AtomicString& value) {
- setAttribute(kActionAttr, value);
+void HTMLFormElement::action(USVStringOrTrustedURL& result) const {
+ result.SetUSVString(action());
+}
+
+void HTMLFormElement::setAction(const USVStringOrTrustedURL& value,
+ ExceptionState& exception_state) {
+ setAttribute(kActionAttr, value, exception_state);
}
void HTMLFormElement::setEnctype(const AtomicString& value) {
@@ -720,15 +728,13 @@ HTMLFormControlElement* HTMLFormElement::FindDefaultButton() const {
}
bool HTMLFormElement::checkValidity() {
- return !CheckInvalidControlsAndCollectUnhandled(
- nullptr, kCheckValidityDispatchInvalidEvent);
+ return !CheckInvalidControlsAndCollectUnhandled(nullptr);
}
bool HTMLFormElement::CheckInvalidControlsAndCollectUnhandled(
- HeapVector<Member<HTMLFormControlElement>>* unhandled_invalid_controls,
- CheckValidityEventBehavior event_behavior) {
+ ListedElement::List* unhandled_invalid_controls) {
// Copy listedElements because event handlers called from
- // HTMLFormControlElement::checkValidity() might change listedElements.
+ // ListedElement::checkValidity() might change listed_elements.
const ListedElement::List& listed_elements = ListedElements();
HeapVector<Member<ListedElement>> elements;
elements.ReserveCapacity(listed_elements.size());
@@ -736,16 +742,20 @@ bool HTMLFormElement::CheckInvalidControlsAndCollectUnhandled(
elements.push_back(element);
int invalid_controls_count = 0;
for (const auto& element : elements) {
- if (element->Form() == this && element->IsFormControlElement()) {
- HTMLFormControlElement* control = ToHTMLFormControlElement(element);
- if (control->IsSubmittableElement() &&
- !control->checkValidity(unhandled_invalid_controls, event_behavior) &&
- control->formOwner() == this) {
- ++invalid_controls_count;
- if (!unhandled_invalid_controls &&
- event_behavior == kCheckValidityDispatchNoEvent)
- return true;
- }
+ if (element->Form() != this)
+ continue;
+ // TOOD(tkent): Virtualize checkValidity().
+ bool should_check_validity = false;
+ if (element->IsFormControlElement()) {
+ should_check_validity =
+ ToHTMLFormControlElement(element)->IsSubmittableElement();
+ } else if (element->IsElementInternals()) {
+ should_check_validity = true;
+ }
+ if (should_check_validity &&
+ !element->checkValidity(unhandled_invalid_controls) &&
+ element->Form() == this) {
+ ++invalid_controls_count;
}
}
return invalid_controls_count;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.h
index 422613b158a..48e8bd0b551 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.h
@@ -48,7 +48,9 @@ class CORE_EXPORT HTMLFormElement final : public HTMLElement {
explicit HTMLFormElement(Document&);
~HTMLFormElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
+
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
HTMLFormControlsCollection* elements();
void GetNamedElements(const AtomicString&, HeapVector<Member<Element>>&);
@@ -57,7 +59,8 @@ class CORE_EXPORT HTMLFormElement final : public HTMLElement {
HTMLElement* item(unsigned index);
String action() const;
- void setAction(const AtomicString&);
+ void action(USVStringOrTrustedURL&) const;
+ void setAction(const USVStringOrTrustedURL&, ExceptionState&);
String enctype() const { return attributes_.EncodingType(); }
void setEnctype(const AtomicString&);
@@ -109,9 +112,9 @@ class CORE_EXPORT HTMLFormElement final : public HTMLElement {
// 'construct the entry list'
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set
- // Returns false if this form is already running this function.
- bool ConstructEntryList(HTMLFormControlElement* submit_button,
- FormData& form_data);
+ // Returns nullptr if this form is already running this function.
+ FormData* ConstructEntryList(HTMLFormControlElement* submit_button,
+ const WTF::TextEncoding& encoding);
unsigned UniqueRendererFormId() const { return unique_renderer_form_id_; }
@@ -144,9 +147,7 @@ class CORE_EXPORT HTMLFormElement final : public HTMLElement {
// Validates each of the controls, and stores controls of which 'invalid'
// event was not canceled to the specified vector. Returns true if there
// are any invalid controls in this form.
- bool CheckInvalidControlsAndCollectUnhandled(
- HeapVector<Member<HTMLFormControlElement>>*,
- CheckValidityEventBehavior);
+ bool CheckInvalidControlsAndCollectUnhandled(ListedElement::List*);
Element* ElementFromPastNamesMap(const AtomicString&);
void AddToPastNamesMap(Element*, const AtomicString& past_name);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl
index 8a830e253b2..05717232652 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl
@@ -25,7 +25,7 @@
OverrideBuiltins
] interface HTMLFormElement : HTMLElement {
[CEReactions, Reflect=accept_charset] attribute DOMString acceptCharset;
- [CEReactions, URL] attribute DOMString action;
+ [CEReactions, URL, RaisesException=Setter] attribute URLString action;
[CEReactions, Reflect, ReflectOnly=("on","off"), ReflectMissing="on", ReflectInvalid="on"] attribute DOMString autocomplete;
[CEReactions, CustomElementCallbacks] attribute DOMString enctype;
[CEReactions, CustomElementCallbacks] attribute DOMString encoding;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc
index 9922ca55e07..b3b539f6da7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -87,7 +87,7 @@ class ListAttributeTargetObserver : public IdTargetObserver {
ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void IdTargetChanged() override;
private:
@@ -135,7 +135,7 @@ HTMLInputElement* HTMLInputElement::Create(Document& document,
return input_element;
}
-void HTMLInputElement::Trace(blink::Visitor* visitor) {
+void HTMLInputElement::Trace(Visitor* visitor) {
visitor->Trace(input_type_);
visitor->Trace(input_type_view_);
visitor->Trace(list_attribute_target_observer_);
@@ -143,10 +143,12 @@ void HTMLInputElement::Trace(blink::Visitor* visitor) {
TextControlElement::Trace(visitor);
}
-const HashSet<AtomicString>& HTMLInputElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLInputElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"formaction", SpecificTrustedType::kTrustedURL},
+ {"src", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
bool HTMLInputElement::HasPendingActivity() const {
@@ -385,7 +387,7 @@ void HTMLInputElement::InitializeTypeInParsing() {
CreateShadowSubtree();
}
- SetNeedsWillValidateCheck();
+ UpdateWillValidateCache();
if (!default_value.IsNull())
input_type_->WarnIfValueIsInvalid(default_value);
@@ -444,7 +446,7 @@ void HTMLInputElement::UpdateType() {
CreateShadowSubtree();
}
- SetNeedsWillValidateCheck();
+ UpdateWillValidateCache();
if (placeholder_changed) {
// We need to update the UA shadow and then the placeholder visibility flag
@@ -889,9 +891,6 @@ void HTMLInputElement::AttachLayoutTree(AttachContext& context) {
}
void HTMLInputElement::DetachLayoutTree(const AttachContext& context) {
- if (GetLayoutObject()) {
- input_type_->OnDetachWithLayoutObject();
- }
TextControlElement::DetachLayoutTree(context);
needs_to_update_view_value_ = true;
input_type_view_->ClosePopupView();
@@ -1701,7 +1700,7 @@ bool HTMLInputElement::IsEnumeratable() const {
return input_type_->IsEnumeratable();
}
-bool HTMLInputElement::SupportLabels() const {
+bool HTMLInputElement::IsLabelable() const {
return input_type_->IsInteractiveContent();
}
@@ -1810,7 +1809,7 @@ ListAttributeTargetObserver::ListAttributeTargetObserver(
id),
element_(element) {}
-void ListAttributeTargetObserver::Trace(blink::Visitor* visitor) {
+void ListAttributeTargetObserver::Trace(Visitor* visitor) {
visitor->Trace(element_);
IdTargetObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h
index 75f9122ae9e..429f69b02b9 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h
@@ -59,10 +59,10 @@ class CORE_EXPORT HTMLInputElement
HTMLInputElement(Document&, const CreateElementFlags);
~HTMLInputElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
bool HasPendingActivity() const final;
@@ -327,7 +327,7 @@ class CORE_EXPORT HTMLInputElement
bool MayTriggerVirtualKeyboard() const final;
bool IsEnumeratable() const final;
bool IsInteractiveContent() const final;
- bool SupportLabels() const final;
+ bool IsLabelable() const final;
bool MatchesDefaultPseudoClass() const override;
bool IsTextControl() const final { return IsTextField(); }
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl
index 05004841a2d..340d2afbb28 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl
@@ -21,9 +21,6 @@
// https://html.spec.whatwg.org/#the-input-element
-// The `URLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
enum SelectionMode { "select", "start", "end", "preserve" };
[
@@ -42,7 +39,7 @@ enum SelectionMode { "select", "start", "end", "preserve" };
// The 'files' attribute is intentionally not readonly.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=22682
attribute FileList? files;
- [CEReactions] attribute DOMString formAction;
+ [CEReactions, RaisesException=Setter] attribute URLString formAction;
[CEReactions, CustomElementCallbacks] attribute DOMString formEnctype;
[CEReactions, CustomElementCallbacks] attribute DOMString formMethod;
[CEReactions, Reflect] attribute boolean formNoValidate;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc
index 3fea461e8dd..906743e4673 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/core/events/mouse_event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
#include "third_party/blink/renderer/core/html/forms/listed_element.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -50,16 +51,15 @@ HTMLLabelElement* HTMLLabelElement::Create(Document& document) {
return MakeGarbageCollected<HTMLLabelElement>(document);
}
-LabelableElement* HTMLLabelElement::control() const {
+HTMLElement* HTMLLabelElement::control() const {
+ // https://html.spec.whatwg.org/multipage/forms.html#labeled-control
const AtomicString& control_id = getAttribute(kForAttr);
if (control_id.IsNull()) {
- // Search the children and descendants of the label element for a form
- // element.
- // per http://dev.w3.org/html5/spec/Overview.html#the-label-element
- // the form element must be "labelable form-associated element".
- for (LabelableElement& element :
- Traversal<LabelableElement>::DescendantsOf(*this)) {
- if (element.SupportLabels()) {
+ // "If the for attribute is not specified, but the label element has a
+ // labelable element descendant, then the first such descendant in tree
+ // order is the label element's labeled control."
+ for (HTMLElement& element : Traversal<HTMLElement>::DescendantsOf(*this)) {
+ if (element.IsLabelable()) {
if (!element.IsFormControlElement()) {
UseCounter::Count(
GetDocument(),
@@ -75,14 +75,15 @@ LabelableElement* HTMLLabelElement::control() const {
return nullptr;
if (Element* element = GetTreeScope().getElementById(control_id)) {
- if (IsLabelableElement(*element) &&
- ToLabelableElement(*element).SupportLabels()) {
- if (!element->IsFormControlElement()) {
- UseCounter::Count(
- GetDocument(),
- WebFeature::kHTMLLabelElementControlForNonFormAssociatedElement);
+ if (auto* html_element = ToHTMLElementOrNull(*element)) {
+ if (html_element->IsLabelable()) {
+ if (!html_element->IsFormControlElement()) {
+ UseCounter::Count(
+ GetDocument(),
+ WebFeature::kHTMLLabelElementControlForNonFormAssociatedElement);
+ }
+ return html_element;
}
- return ToLabelableElement(element);
}
}
@@ -90,10 +91,11 @@ LabelableElement* HTMLLabelElement::control() const {
}
HTMLFormElement* HTMLLabelElement::form() const {
- if (LabelableElement* control = this->control()) {
- return control->IsFormControlElement()
- ? ToHTMLFormControlElement(control)->Form()
- : nullptr;
+ if (HTMLElement* control = this->control()) {
+ if (auto* form_control_element = ToHTMLFormControlElementOrNull(control))
+ return form_control_element->Form();
+ if (control->IsFormAssociatedCustomElement())
+ return control->EnsureElementInternals().Form();
}
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h
index 0f396c31d3c..ce3c0c44c07 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h
@@ -29,8 +29,6 @@
namespace blink {
-class LabelableElement;
-
class CORE_EXPORT HTMLLabelElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
@@ -39,7 +37,7 @@ class CORE_EXPORT HTMLLabelElement final : public HTMLElement {
explicit HTMLLabelElement(Document&);
- LabelableElement* control() const;
+ HTMLElement* control() const;
HTMLFormElement* form() const;
bool WillRespondToMouseClickEvents() override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_legend_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_legend_element.h
index 802daeb1483..495da50920e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_legend_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_legend_element.h
@@ -34,10 +34,9 @@ class HTMLLegendElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLLegendElement);
- HTMLFormElement* form() const;
-
- private:
explicit HTMLLegendElement(Document&);
+
+ HTMLFormElement* form() const;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_output_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_output_element.cc
index bb88f6ca769..9944b41d6cf 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_output_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_output_element.cc
@@ -123,7 +123,7 @@ int HTMLOutputElement::tabIndex() const {
return HTMLElement::tabIndex();
}
-void HTMLOutputElement::Trace(blink::Visitor* visitor) {
+void HTMLOutputElement::Trace(Visitor* visitor) {
visitor->Trace(tokens_);
HTMLFormControlElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_output_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_output_element.h
index 521e6762d93..036950c0b87 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_output_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_output_element.h
@@ -57,7 +57,7 @@ class CORE_EXPORT HTMLOutputElement final : public HTMLFormControlElement {
return is_default_value_mode_;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void ParseAttribute(const AttributeModificationParams&) override;
@@ -65,7 +65,7 @@ class CORE_EXPORT HTMLOutputElement final : public HTMLFormControlElement {
bool IsDisabledFormControl() const override;
bool MatchesEnabledPseudoClass() const override;
bool IsEnumeratable() const override { return true; }
- bool SupportLabels() const override { return true; }
+ bool IsLabelable() const override { return true; }
bool SupportsFocus() const override;
void ChildrenChanged(const ChildrenChange&) override;
void ResetImpl() override;
@@ -73,7 +73,7 @@ class CORE_EXPORT HTMLOutputElement final : public HTMLFormControlElement {
bool is_default_value_mode_;
String default_value_;
- Member<DOMTokenList> tokens_;
+ TraceWrapperMember<DOMTokenList> tokens_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 040fee3ae90..3ead4ab0b52 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -1843,7 +1843,7 @@ bool HTMLSelectElement::SupportsAutofocus() const {
return true;
}
-void HTMLSelectElement::Trace(blink::Visitor* visitor) {
+void HTMLSelectElement::Trace(Visitor* visitor) {
visitor->Trace(list_items_);
visitor->Trace(last_on_change_option_);
visitor->Trace(active_selection_anchor_);
@@ -2059,7 +2059,7 @@ class HTMLSelectElement::PopupUpdater : public MutationObserver::Delegate {
void Dispose() { observer_->disconnect(); }
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(select_);
visitor->Trace(observer_);
MutationObserver::Delegate::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h
index b3d7f77fe01..c500b26970a 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h
@@ -174,7 +174,7 @@ class CORE_EXPORT HTMLSelectElement final
bool HasNonInBodyInsertionMode() const override { return true; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void CloneNonAttributePropertiesFrom(const Element&,
CloneChildrenFlag) override;
@@ -196,7 +196,7 @@ class CORE_EXPORT HTMLSelectElement final
bool IsEnumeratable() const override { return true; }
bool IsInteractiveContent() const override;
bool SupportsAutofocus() const override;
- bool SupportLabels() const override { return true; }
+ bool IsLabelable() const override { return true; }
FormControlState SaveFormControlState() const override;
void RestoreFormControlState(const FormControlState&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h
index 8af71e66d33..9ae4e6f8d6f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h
@@ -103,7 +103,7 @@ class CORE_EXPORT HTMLTextAreaElement final : public TextControlElement {
bool IsEnumeratable() const override { return true; }
bool IsInteractiveContent() const override;
bool SupportsAutofocus() const override;
- bool SupportLabels() const override { return true; }
+ bool IsLabelable() const override { return true; }
const AtomicString& FormControlType() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/input_type.cc
index c2949159589..340fe9a184a 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/input_type.cc
@@ -139,7 +139,7 @@ const AtomicString& InputType::NormalizeTypeName(
InputType::~InputType() = default;
-void InputType::Trace(blink::Visitor* visitor) {
+void InputType::Trace(Visitor* visitor) {
visitor->Trace(element_);
}
@@ -485,7 +485,11 @@ FileList* InputType::Files() {
return nullptr;
}
-void InputType::SetFiles(FileList*) {}
+bool InputType::SetFiles(FileList*) {
+ return false;
+}
+
+void InputType::SetFilesAndDispatchEvents(FileList*) {}
void InputType::SetFilesFromPaths(const Vector<String>& paths) {}
@@ -642,8 +646,6 @@ void InputType::CopyNonAttributeProperties(const HTMLInputElement&) {}
void InputType::OnAttachWithLayoutObject() {}
-void InputType::OnDetachWithLayoutObject() {}
-
bool InputType::ShouldAppearIndeterminate() const {
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/input_type.h b/chromium/third_party/blink/renderer/core/html/forms/input_type.h
index 16ca8d1a0e7..22475ab2657 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/input_type.h
@@ -58,7 +58,7 @@ class CORE_EXPORT InputType : public GarbageCollectedFinalized<InputType> {
static InputType* CreateText(HTMLInputElement&);
static const AtomicString& NormalizeTypeName(const AtomicString&);
virtual ~InputType();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
virtual InputTypeView* CreateView() = 0;
virtual const AtomicString& FormControlType() const = 0;
@@ -164,7 +164,9 @@ class CORE_EXPORT InputType : public GarbageCollectedFinalized<InputType> {
virtual void SanitizeValueInResponseToMinOrMaxAttributeChange();
virtual bool ShouldRespectAlignAttribute();
virtual FileList* Files();
- virtual void SetFiles(FileList*);
+ // Should return true if the file list was were changed.
+ virtual bool SetFiles(FileList*);
+ virtual void SetFilesAndDispatchEvents(FileList*);
virtual void SetFilesFromPaths(const Vector<String>&);
// Should return true if the given DragData has more than one dropped files.
virtual bool ReceiveDroppedFiles(const DragData*);
@@ -193,7 +195,6 @@ class CORE_EXPORT InputType : public GarbageCollectedFinalized<InputType> {
virtual const QualifiedName& SubResourceAttributeName() const;
virtual void CopyNonAttributeProperties(const HTMLInputElement&);
virtual void OnAttachWithLayoutObject();
- virtual void OnDetachWithLayoutObject();
// Parses the specified string for the type, and return
// the Decimal value for the parsing result if the parsing
diff --git a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc
index 5fdb93d7a2e..44911d944c9 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc
@@ -40,7 +40,7 @@ namespace blink {
InputTypeView::~InputTypeView() = default;
-void InputTypeView::Trace(blink::Visitor* visitor) {
+void InputTypeView::Trace(Visitor* visitor) {
visitor->Trace(element_);
}
@@ -187,7 +187,7 @@ bool InputTypeView::HasBadInput() const {
return false;
}
-void ClickHandlingState::Trace(blink::Visitor* visitor) {
+void ClickHandlingState::Trace(Visitor* visitor) {
visitor->Trace(checked_radio_button);
EventDispatchHandlingState::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h
index 4fa98908002..9e2d8787c16 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h
@@ -58,7 +58,7 @@ class ComputedStyle;
class ClickHandlingState final : public EventDispatchHandlingState {
public:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
bool checked;
bool indeterminate;
@@ -71,7 +71,7 @@ class ClickHandlingState final : public EventDispatchHandlingState {
class CORE_EXPORT InputTypeView : public GarbageCollectedMixin {
public:
virtual ~InputTypeView();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
virtual bool SizeShouldIncludeDecoration(int default_size,
int& preferred_size) const;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
index 12884a037ad..2e9105d5d71 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -80,7 +80,7 @@ class PopupMenuCSSFontSelector : public CSSFontSelector,
scoped_refptr<FontData> GetFontData(const FontDescription&,
const AtomicString&) override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void FontsNeedUpdate(FontSelector*) override;
@@ -107,7 +107,7 @@ void PopupMenuCSSFontSelector::FontsNeedUpdate(FontSelector* font_selector) {
DispatchInvalidationCallbacks();
}
-void PopupMenuCSSFontSelector::Trace(blink::Visitor* visitor) {
+void PopupMenuCSSFontSelector::Trace(Visitor* visitor) {
visitor->Trace(owner_font_selector_);
CSSFontSelector::Trace(visitor);
FontSelectorClient::Trace(visitor);
@@ -223,7 +223,7 @@ InternalPopupMenu::~InternalPopupMenu() {
DCHECK(!popup_);
}
-void InternalPopupMenu::Trace(blink::Visitor* visitor) {
+void InternalPopupMenu::Trace(Visitor* visitor) {
visitor->Trace(chrome_client_);
visitor->Trace(owner_element_);
PopupMenu::Trace(visitor);
@@ -480,7 +480,7 @@ Locale& InternalPopupMenu::GetLocale() {
return Locale::DefaultLocale();
}
-void InternalPopupMenu::ClosePopup() {
+void InternalPopupMenu::CancelPopup() {
if (popup_)
chrome_client_->ClosePagePopup(popup_);
if (owner_element_)
@@ -498,7 +498,7 @@ void InternalPopupMenu::Show() {
}
void InternalPopupMenu::Hide() {
- ClosePopup();
+ CancelPopup();
}
void InternalPopupMenu::UpdateFromElement(UpdateReason) {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.h b/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.h
index d44f353b8da..548ee31737f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.h
@@ -28,7 +28,7 @@ class CORE_EXPORT InternalPopupMenu final : public PopupMenu,
InternalPopupMenu(ChromeClient*, HTMLSelectElement&);
~InternalPopupMenu() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void Update();
@@ -52,7 +52,7 @@ class CORE_EXPORT InternalPopupMenu final : public PopupMenu,
void SelectFontsFromOwnerDocument(Document&) override;
void SetValueAndClosePopup(int, const String&) override;
void SetValue(const String&) override;
- void ClosePopup() override;
+ void CancelPopup() override;
Element& OwnerElement() override;
float ZoomFactor() override { return 1.0; }
Locale& GetLocale() override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/labelable_element.cc b/chromium/third_party/blink/renderer/core/html/forms/labelable_element.cc
deleted file mode 100644
index a8641324673..00000000000
--- a/chromium/third_party/blink/renderer/core/html/forms/labelable_element.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 1999 Antti Koivisto (koivisto@kde.org)
- * (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
- * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
-
-#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
-#include "third_party/blink/renderer/core/dom/node_rare_data.h"
-#include "third_party/blink/renderer/core/html/forms/labels_node_list.h"
-
-namespace blink {
-
-LabelableElement::LabelableElement(const QualifiedName& tag_name,
- Document& document)
- : HTMLElement(tag_name, document) {}
-
-LabelableElement::~LabelableElement() = default;
-
-LabelsNodeList* LabelableElement::labels() {
- if (!SupportLabels())
- return nullptr;
-
- return EnsureCachedCollection<LabelsNodeList>(kLabelsNodeListType);
-}
-
-void LabelableElement::Trace(blink::Visitor* visitor) {
- HTMLElement::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/labelable_element.h b/chromium/third_party/blink/renderer/core/html/forms/labelable_element.h
deleted file mode 100644
index 71fb17d6fa3..00000000000
--- a/chromium/third_party/blink/renderer/core/html/forms/labelable_element.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_LABELABLE_ELEMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_LABELABLE_ELEMENT_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/html_element.h"
-
-namespace blink {
-
-class LabelsNodeList;
-
-// LabelableElement represents "labelable element" defined in the HTML
-// specification, and provides the implementation of the "labels" attribute.
-class CORE_EXPORT LabelableElement : public HTMLElement {
- public:
- ~LabelableElement() override;
- LabelsNodeList* labels();
- virtual bool SupportLabels() const { return false; }
-
- void Trace(blink::Visitor*) override;
-
- protected:
- LabelableElement(const QualifiedName& tag_name, Document&);
-
- private:
- bool IsLabelable() const final { return true; }
-};
-
-inline bool IsLabelableElement(const HTMLElement& element) {
- return element.IsLabelable();
-}
-
-DEFINE_HTMLELEMENT_TYPE_CASTS_WITH_FUNCTION(LabelableElement);
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/html/forms/labels_node_list.cc b/chromium/third_party/blink/renderer/core/html/forms/labels_node_list.cc
index e7d1538a49c..6af3a070c0e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/labels_node_list.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/labels_node_list.cc
@@ -26,7 +26,6 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_rare_data.h"
#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
#include "third_party/blink/renderer/core/html_names.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/listed_element.cc b/chromium/third_party/blink/renderer/core/html/forms/listed_element.cc
index d2cf8cd9da1..96f1bf4f200 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/listed_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/listed_element.cc
@@ -25,16 +25,28 @@
#include "third_party/blink/renderer/core/html/forms/listed_element.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
+#include "third_party/blink/renderer/core/html/forms/form_controller.h"
+#include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
#include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
#include "third_party/blink/renderer/core/html/forms/validity_state.h"
#include "third_party/blink/renderer/core/html/html_object_element.h"
#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/validation_message_client.h"
+#include "third_party/blink/renderer/platform/text/bidi_text_run.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -47,20 +59,26 @@ class FormAttributeTargetObserver : public IdTargetObserver {
FormAttributeTargetObserver(const AtomicString& id, ListedElement*);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void IdTargetChanged() override;
private:
Member<ListedElement> element_;
};
-ListedElement::ListedElement() : form_was_set_by_parser_(false) {}
+ListedElement::ListedElement()
+ : has_validation_message_(false),
+ form_was_set_by_parser_(false),
+ will_validate_initialized_(false),
+ will_validate_(true),
+ is_valid_(true),
+ validity_is_dirty_(false) {}
ListedElement::~ListedElement() {
// We can't call setForm here because it contains virtual calls.
}
-void ListedElement::Trace(blink::Visitor* visitor) {
+void ListedElement::Trace(Visitor* visitor) {
visitor->Trace(form_attribute_target_observer_);
visitor->Trace(form_);
visitor->Trace(validity_state_);
@@ -83,35 +101,65 @@ void ListedElement::InsertedInto(ContainerNode& insertion_point) {
ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
// Force traversal to find ancestor
may_have_field_set_ancestor_ = true;
+ data_list_ancestor_state_ = DataListAncestorState::kUnknown;
+ UpdateWillValidateCache();
if (!form_was_set_by_parser_ || !form_ ||
NodeTraversal::HighestAncestorOrSelf(insertion_point) !=
NodeTraversal::HighestAncestorOrSelf(*form_.Get()))
ResetFormOwner();
- if (!insertion_point.isConnected())
- return;
-
HTMLElement* element = ToHTMLElement(this);
- if (element->FastHasAttribute(kFormAttr))
- ResetFormAttributeTargetObserver();
+ if (insertion_point.isConnected()) {
+ if (element->FastHasAttribute(kFormAttr))
+ ResetFormAttributeTargetObserver();
+ }
+
+ FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
+ DisabledStateMightBeChanged();
+
+ if (IsFormControlElementWithState() && insertion_point.isConnected() &&
+ !element->ContainingShadowRoot()) {
+ element->GetDocument()
+ .GetFormController()
+ .InvalidateStatefulFormControlList();
+ }
+
+ // Trigger for elements outside of forms.
+ if (!form_ && insertion_point.isConnected())
+ element->GetDocument().DidAssociateFormControl(element);
}
void ListedElement::RemovedFrom(ContainerNode& insertion_point) {
+ FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
+ HideVisibleValidationMessage();
+ has_validation_message_ = false;
ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
+ data_list_ancestor_state_ = DataListAncestorState::kUnknown;
+ UpdateWillValidateCache();
HTMLElement* element = ToHTMLElement(this);
if (insertion_point.isConnected() && element->FastHasAttribute(kFormAttr)) {
SetFormAttributeTargetObserver(nullptr);
ResetFormOwner();
- return;
+ } else {
+ // If the form and element are both in the same tree, preserve the
+ // connection to the form. Otherwise, null out our form and remove
+ // ourselves from the form's list of elements.
+ if (form_ && NodeTraversal::HighestAncestorOrSelf(*element) !=
+ NodeTraversal::HighestAncestorOrSelf(*form_.Get()))
+ ResetFormOwner();
+ }
+
+ DisabledStateMightBeChanged();
+
+ if (IsFormControlElementWithState() && insertion_point.isConnected() &&
+ !element->ContainingShadowRoot() &&
+ !insertion_point.ContainingShadowRoot()) {
+ element->GetDocument()
+ .GetFormController()
+ .InvalidateStatefulFormControlList();
}
- // If the form and element are both in the same tree, preserve the connection
- // to the form. Otherwise, null out our form and remove ourselves from the
- // form's list of elements.
- if (form_ && NodeTraversal::HighestAncestorOrSelf(*element) !=
- NodeTraversal::HighestAncestorOrSelf(*form_.Get()))
- ResetFormOwner();
}
HTMLFormElement* ListedElement::FindAssociatedForm(
@@ -166,13 +214,37 @@ void ListedElement::SetForm(HTMLFormElement* new_form) {
DidChangeForm();
}
-void ListedElement::WillChangeForm() {}
+void ListedElement::WillChangeForm() {
+ FormOwnerSetNeedsValidityCheck();
+}
void ListedElement::DidChangeForm() {
if (!form_was_set_by_parser_ && form_ && form_->isConnected()) {
HTMLElement* element = ToHTMLElement(this);
element->GetDocument().DidAssociateFormControl(element);
}
+ FormOwnerSetNeedsValidityCheck();
+}
+
+void ListedElement::FormOwnerSetNeedsValidityCheck() {
+ if (HTMLFormElement* form = Form()) {
+ form->PseudoStateChanged(CSSSelector::kPseudoValid);
+ form->PseudoStateChanged(CSSSelector::kPseudoInvalid);
+ }
+}
+
+void ListedElement::FieldSetAncestorsSetNeedsValidityCheck(Node* node) {
+ if (!node)
+ return;
+ if (!may_have_field_set_ancestor_)
+ return;
+ for (auto* field_set =
+ Traversal<HTMLFieldSetElement>::FirstAncestorOrSelf(*node);
+ field_set;
+ field_set = Traversal<HTMLFieldSetElement>::FirstAncestor(*field_set)) {
+ field_set->PseudoStateChanged(CSSSelector::kPseudoValid);
+ field_set->PseudoStateChanged(CSSSelector::kPseudoInvalid);
+ }
}
void ListedElement::ResetFormOwner() {
@@ -195,6 +267,57 @@ void ListedElement::FormAttributeChanged() {
ResetFormAttributeTargetObserver();
}
+bool ListedElement::RecalcWillValidate() const {
+ const HTMLElement& element = ToHTMLElement(*this);
+ if (data_list_ancestor_state_ == DataListAncestorState::kUnknown) {
+ if (Traversal<HTMLDataListElement>::FirstAncestor(element))
+ data_list_ancestor_state_ = DataListAncestorState::kInsideDataList;
+ else
+ data_list_ancestor_state_ = DataListAncestorState::kNotInsideDataList;
+ }
+ return data_list_ancestor_state_ ==
+ DataListAncestorState::kNotInsideDataList &&
+ !element.IsDisabledFormControl() &&
+ !element.FastHasAttribute(html_names::kReadonlyAttr);
+}
+
+bool ListedElement::WillValidate() const {
+ if (!will_validate_initialized_ ||
+ data_list_ancestor_state_ == DataListAncestorState::kUnknown) {
+ const_cast<ListedElement*>(this)->UpdateWillValidateCache();
+ } else {
+ // If the following assertion fails, UpdateWillValidateCache() is not
+ // called correctly when something which changes RecalcWillValidate() result
+ // is updated.
+ DCHECK_EQ(will_validate_, RecalcWillValidate());
+ }
+ return will_validate_;
+}
+
+void ListedElement::UpdateWillValidateCache() {
+ // We need to recalculate willValidate immediately because willValidate change
+ // can causes style change.
+ bool new_will_validate = RecalcWillValidate();
+ if (will_validate_initialized_ && will_validate_ == new_will_validate)
+ return;
+ will_validate_initialized_ = true;
+ will_validate_ = new_will_validate;
+ // Needs to force SetNeedsValidityCheck() to invalidate validity state of
+ // FORM/FIELDSET. If this element updates willValidate twice and
+ // IsValidElement() is not called between them, the second call of this
+ // function still has validity_is_dirty_==true, which means
+ // SetNeedsValidityCheck() doesn't invalidate validity state of
+ // FORM/FIELDSET.
+ validity_is_dirty_ = false;
+ SetNeedsValidityCheck();
+ // No need to trigger style recalculation here because
+ // SetNeedsValidityCheck() does it in the right away. This relies on
+ // the assumption that Valid() is always true if willValidate() is false.
+
+ if (!will_validate_)
+ HideVisibleValidationMessage();
+}
+
bool ListedElement::CustomError() const {
const HTMLElement* element = ToHTMLElement(this);
return element->willValidate() && !custom_validation_message_.IsEmpty();
@@ -248,6 +371,10 @@ String ListedElement::CustomValidationMessage() const {
return custom_validation_message_;
}
+void ListedElement::SetCustomValidationMessage(const String& message) {
+ custom_validation_message_ = message;
+}
+
String ListedElement::validationMessage() const {
return CustomError() ? custom_validation_message_ : String();
}
@@ -257,13 +384,163 @@ String ListedElement::ValidationSubMessage() const {
}
void ListedElement::setCustomValidity(const String& error) {
- custom_validation_message_ = error;
+ SetCustomValidationMessage(error);
+ SetNeedsValidityCheck();
+}
+
+void ListedElement::FindCustomValidationMessageTextDirection(
+ const String& message,
+ TextDirection& message_dir,
+ String& sub_message,
+ TextDirection& sub_message_dir) {
+ message_dir = DetermineDirectionality(message);
+ if (!sub_message.IsEmpty()) {
+ sub_message_dir =
+ ToHTMLElement(*this).GetLayoutObject()->Style()->Direction();
+ }
+}
+
+void ListedElement::UpdateVisibleValidationMessage() {
+ HTMLElement& element = ToHTMLElement(*this);
+ Page* page = element.GetDocument().GetPage();
+ if (!page || !page->IsPageVisible() || element.GetDocument().UnloadStarted())
+ return;
+ if (page->Paused())
+ return;
+ String message;
+ if (element.GetLayoutObject() && WillValidate())
+ message = validationMessage().StripWhiteSpace();
+
+ has_validation_message_ = true;
+ ValidationMessageClient* client = &page->GetValidationMessageClient();
+ TextDirection message_dir = TextDirection::kLtr;
+ TextDirection sub_message_dir = TextDirection::kLtr;
+ String sub_message = ValidationSubMessage().StripWhiteSpace();
+ if (message.IsEmpty()) {
+ client->HideValidationMessage(element);
+ } else {
+ FindCustomValidationMessageTextDirection(message, message_dir, sub_message,
+ sub_message_dir);
+ }
+ client->ShowValidationMessage(element, message, message_dir, sub_message,
+ sub_message_dir);
+}
+
+void ListedElement::HideVisibleValidationMessage() {
+ if (!has_validation_message_)
+ return;
+
+ if (auto* client = GetValidationMessageClient())
+ client->HideValidationMessage(ToHTMLElement(*this));
+}
+
+bool ListedElement::IsValidationMessageVisible() const {
+ if (!has_validation_message_)
+ return false;
+
+ if (auto* client = GetValidationMessageClient())
+ return client->IsValidationMessageVisible(ToHTMLElement(*this));
+ return false;
+}
+
+ValidationMessageClient* ListedElement::GetValidationMessageClient() const {
+ if (Page* page = ToHTMLElement(*this).GetDocument().GetPage())
+ return &page->GetValidationMessageClient();
+ return nullptr;
+}
+
+bool ListedElement::checkValidity(List* unhandled_invalid_controls) {
+ if (IsNotCandidateOrValid())
+ return true;
+ HTMLElement& element = ToHTMLElement(*this);
+ Document* original_document = &element.GetDocument();
+ DispatchEventResult dispatch_result = element.DispatchEvent(
+ *Event::CreateCancelable(event_type_names::kInvalid));
+ if (dispatch_result == DispatchEventResult::kNotCanceled &&
+ unhandled_invalid_controls && element.isConnected() &&
+ original_document == element.GetDocument())
+ unhandled_invalid_controls->push_back(this);
+ return false;
+}
+
+void ListedElement::ShowValidationMessage() {
+ HTMLElement& element = ToHTMLElement(*this);
+ element.scrollIntoViewIfNeeded(false);
+ element.focus();
+ UpdateVisibleValidationMessage();
+}
+
+bool ListedElement::reportValidity() {
+ List unhandled_invalid_controls;
+ bool is_valid = checkValidity(&unhandled_invalid_controls);
+ if (is_valid || unhandled_invalid_controls.IsEmpty())
+ return is_valid;
+ DCHECK_EQ(unhandled_invalid_controls.size(), 1u);
+ DCHECK_EQ(unhandled_invalid_controls[0].Get(), this);
+ // Update layout now before calling IsFocusable(), which has
+ // !LayoutObject()->NeedsLayout() assertion.
+ HTMLElement& element = ToHTMLElement(*this);
+ element.GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
+ if (element.IsFocusable()) {
+ ShowValidationMessage();
+ return false;
+ }
+ if (element.GetDocument().GetFrame()) {
+ String message(
+ "An invalid form control with name='%name' is not focusable.");
+ message.Replace("%name", GetName());
+ element.GetDocument().AddConsoleMessage(ConsoleMessage::Create(
+ kRenderingMessageSource, kErrorMessageLevel, message));
+ }
+ return false;
+}
+
+bool ListedElement::IsValidElement() {
+ if (validity_is_dirty_) {
+ is_valid_ = !WillValidate() || Valid();
+ validity_is_dirty_ = false;
+ } else {
+ // If the following assertion fails, SetNeedsValidityCheck() is not
+ // called correctly when something which changes validity is updated.
+ DCHECK_EQ(is_valid_, (!WillValidate() || Valid()));
+ }
+ return is_valid_;
+}
+
+bool ListedElement::IsNotCandidateOrValid() {
+ // Apply Element::willValidate(), not ListedElement::WillValidate(), because
+ // some elements override willValidate().
+ return !ToHTMLElement(this)->willValidate() || IsValidElement();
+}
+
+void ListedElement::SetNeedsValidityCheck() {
+ HTMLElement& element = ToHTMLElement(*this);
+ if (!validity_is_dirty_) {
+ validity_is_dirty_ = true;
+ FormOwnerSetNeedsValidityCheck();
+ FieldSetAncestorsSetNeedsValidityCheck(element.parentNode());
+ element.PseudoStateChanged(CSSSelector::kPseudoValid);
+ element.PseudoStateChanged(CSSSelector::kPseudoInvalid);
+ }
+
+ // Updates only if this control already has a validation message.
+ if (IsValidationMessageVisible()) {
+ // Calls UpdateVisibleValidationMessage() even if is_valid_ is not
+ // changed because a validation message can be changed.
+ element.GetDocument()
+ .GetTaskRunner(TaskType::kDOMManipulation)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&ListedElement::UpdateVisibleValidationMessage,
+ WrapPersistent(this)));
+ }
}
void ListedElement::DisabledAttributeChanged() {
+ UpdateWillValidateCache();
HTMLElement& element = ToHTMLElement(*this);
element.PseudoStateChanged(CSSSelector::kPseudoDisabled);
element.PseudoStateChanged(CSSSelector::kPseudoEnabled);
+ DisabledStateMightBeChanged();
}
void ListedElement::UpdateAncestorDisabledState() const {
@@ -312,6 +589,34 @@ bool ListedElement::IsActuallyDisabled() const {
return ancestor_disabled_state_ == AncestorDisabledState::kDisabled;
}
+bool ListedElement::ShouldSaveAndRestoreFormControlState() const {
+ return false;
+}
+
+FormControlState ListedElement::SaveFormControlState() const {
+ return FormControlState();
+}
+
+void ListedElement::RestoreFormControlState(const FormControlState& state) {}
+
+void ListedElement::NotifyFormStateChanged() {
+ Document& doc = ToHTMLElement(*this).GetDocument();
+ // This can be called during fragment parsing as a result of option
+ // selection before the document is active (or even in a frame).
+ if (!doc.IsActive())
+ return;
+ doc.GetFrame()->Client()->DidUpdateCurrentHistoryItem();
+}
+
+void ListedElement::TakeStateAndRestore() {
+ if (IsFormControlElementWithState()) {
+ ToHTMLElement(*this)
+ .GetDocument()
+ .GetFormController()
+ .RestoreControlStateFor(ToHTMLFormControlElementWithState(*this));
+ }
+}
+
void ListedElement::SetFormAttributeTargetObserver(
FormAttributeTargetObserver* new_observer) {
if (form_attribute_target_observer_)
@@ -347,6 +652,19 @@ bool ListedElement::IsElementInternals() const {
return false;
}
+ListedElement* ListedElement::From(Element& element) {
+ auto* html_element = ToHTMLElementOrNull(element);
+ if (!html_element)
+ return nullptr;
+ if (html_element->IsFormControlElement())
+ return ToHTMLFormControlElement(&element);
+ if (html_element->IsFormAssociatedCustomElement())
+ return &element.EnsureElementInternals();
+ if (auto* object = ToHTMLObjectElementOrNull(html_element))
+ return object;
+ return nullptr;
+}
+
const HTMLElement& ToHTMLElement(const ListedElement& listed_element) {
if (listed_element.IsFormControlElement())
return ToHTMLFormControlElement(listed_element);
@@ -383,7 +701,7 @@ FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id,
id),
element_(element) {}
-void FormAttributeTargetObserver::Trace(blink::Visitor* visitor) {
+void FormAttributeTargetObserver::Trace(Visitor* visitor) {
visitor->Trace(element_);
IdTargetObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/listed_element.h b/chromium/third_party/blink/renderer/core/html/forms/listed_element.h
index 577fe86665e..b72ced5ba68 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/listed_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/listed_element.h
@@ -27,23 +27,31 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
class ContainerNode;
class Document;
+class Element;
class FormAttributeTargetObserver;
+class FormControlState;
class FormData;
class HTMLElement;
class HTMLFormElement;
class Node;
+class ValidationMessageClient;
class ValidityState;
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
public:
virtual ~ListedElement();
+ // Returns a valid ListedElement pointer if the specified element is an
+ // instance of a ListedElement subclass, or a form-associated custom element.
+ // Returns nullptr otherwise.
+ static ListedElement* From(Element& element);
static HTMLFormElement* FindAssociatedForm(const HTMLElement*,
const AtomicString& form_id,
@@ -69,11 +77,14 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
void FormRemovedFromTree(const Node& form_root);
+ bool WillValidate() const;
+
// ValidityState attribute implementations
- bool CustomError() const;
+ virtual bool CustomError() const;
- // Override functions for patterMismatch, rangeOverflow, rangerUnderflow,
- // stepMismatch, tooLong, tooShort and valueMissing must call willValidate
+ // Functions for ValidityState interface methods.
+ // Override functions for PatterMismatch, RangeOverflow, RangerUnderflow,
+ // StepMismatch, TooLong, TooShort and ValueMissing must call WillValidate
// method.
virtual bool HasBadInput() const;
virtual bool PatternMismatch() const;
@@ -84,23 +95,69 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
virtual bool TooShort() const;
virtual bool TypeMismatch() const;
virtual bool ValueMissing() const;
+ bool Valid() const;
+
+ using List = HeapVector<Member<ListedElement>>;
+
virtual String validationMessage() const;
virtual String ValidationSubMessage() const;
- bool Valid() const;
virtual void setCustomValidity(const String&);
-
+ void UpdateVisibleValidationMessage();
+ void HideVisibleValidationMessage();
+ bool checkValidity(List* unhandled_invalid_controls = nullptr);
+ bool reportValidity();
+ // This must be called only after the caller check the element is focusable.
+ void ShowValidationMessage();
+ bool IsValidationMessageVisible() const;
+ void FindCustomValidationMessageTextDirection(const String& message,
+ TextDirection& message_dir,
+ String& sub_message,
+ TextDirection& sub_message_dir);
+
+ // For Element::IsValidElement(), which is for :valid :invalid selectors.
+ bool IsValidElement();
+ // Returns true if
+ // - this is not a candidate for constraint validation, or
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#candidate-for-constraint-validation
+ // - this satisfies its constraints
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fv-valid
+ bool IsNotCandidateOrValid();
+
+ // This must be called when a validation constraint or control value is
+ // changed.
+ void SetNeedsValidityCheck();
+
+ // This should be called when |disabled| content attribute is changed.
+ virtual void DisabledAttributeChanged();
+ // Override this if you want to know 'disabled' state changes immediately.
+ virtual void DisabledStateMightBeChanged() {}
+ // This should be called when |form| content attribute is changed.
+ void FormAttributeChanged();
+ // This is for FormAttributeTargteObserver class.
void FormAttributeTargetChanged();
+ // This should be called in Node::InsertedInto().
void InsertedInto(ContainerNode&);
+ // This should be called in Node::RemovedFrom().
void RemovedFrom(ContainerNode&);
+ // This should be called in Node::DidMoveToDocument().
void DidMoveToNewDocument(Document& old_document);
+ // This is for HTMLFieldSetElement class.
void AncestorDisabledStateWasChanged();
// https://html.spec.whatwg.org/multipage/semantics-other.html#concept-element-disabled
bool IsActuallyDisabled() const;
- typedef HeapVector<Member<ListedElement>> List;
+ virtual bool ShouldSaveAndRestoreFormControlState() const;
+ virtual FormControlState SaveFormControlState() const;
+ // The specified FormControlState must have at least one string value.
+ virtual void RestoreFormControlState(const FormControlState& state);
+ // This should be called whenever an element supports state restore changes
+ // its state.
+ void NotifyFormStateChanged();
+ // This should be called in Element::FinishParsingChildren() override.
+ void TakeStateAndRestore();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
ListedElement();
@@ -109,7 +166,6 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
// setForm is confusing.
void SetForm(HTMLFormElement*);
void AssociateByParser(HTMLFormElement*);
- void FormAttributeChanged();
// If you add an override of willChangeForm() or didChangeForm() to a class
// derived from this one, you will need to add a call to setForm(0) to the
@@ -117,9 +173,13 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
virtual void WillChangeForm();
virtual void DidChangeForm();
- String CustomValidationMessage() const;
+ // This must be called any time the result of WillValidate() has changed.
+ void UpdateWillValidateCache();
+ virtual bool RecalcWillValidate() const;
- virtual void DisabledAttributeChanged();
+ String CustomValidationMessage() const;
+ // This is just a setter. This doesn't set |customError| flag.
+ void SetCustomValidationMessage(const String& message);
// False; There are no FIELDSET ancestors.
// True; There might be a FIELDSET ancestor, and thre might be no
@@ -130,17 +190,42 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
void UpdateAncestorDisabledState() const;
void SetFormAttributeTargetObserver(FormAttributeTargetObserver*);
void ResetFormAttributeTargetObserver();
+ // Requests validity recalc for the form owner, if one exists.
+ void FormOwnerSetNeedsValidityCheck();
+ // Requests validity recalc for all ancestor fieldsets, if exist.
+ void FieldSetAncestorsSetNeedsValidityCheck(Node*);
+
+ ValidationMessageClient* GetValidationMessageClient() const;
Member<FormAttributeTargetObserver> form_attribute_target_observer_;
Member<HTMLFormElement> form_;
Member<ValidityState> validity_state_;
String custom_validation_message_;
+ bool has_validation_message_ : 1;
// If form_was_set_by_parser_ is true, form_ is always non-null.
- bool form_was_set_by_parser_;
+ bool form_was_set_by_parser_ : 1;
+
+ // The initial value of will_validate_ depends on the derived class. We can't
+ // initialize it with a virtual function in the constructor. will_validate_
+ // is not deterministic as long as will_validate_initialized_ is false.
+ mutable bool will_validate_initialized_ : 1;
+ mutable bool will_validate_ : 1;
+
+ // Cache of IsValidElement().
+ bool is_valid_ : 1;
+ bool validity_is_dirty_ : 1;
enum class AncestorDisabledState { kUnknown, kEnabled, kDisabled };
mutable AncestorDisabledState ancestor_disabled_state_ =
AncestorDisabledState::kUnknown;
+
+ enum class DataListAncestorState {
+ kUnknown,
+ kInsideDataList,
+ kNotInsideDataList
+ };
+ mutable enum DataListAncestorState data_list_ancestor_state_ =
+ DataListAncestorState::kUnknown;
};
CORE_EXPORT HTMLElement* ToHTMLElement(ListedElement*);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc b/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
index 17eb4fe5825..1588d0f5cd2 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
@@ -324,7 +324,7 @@ MultipleFieldsTemporalInputTypeView::Create(HTMLInputElement& element,
MultipleFieldsTemporalInputTypeView::~MultipleFieldsTemporalInputTypeView() =
default;
-void MultipleFieldsTemporalInputTypeView::Trace(blink::Visitor* visitor) {
+void MultipleFieldsTemporalInputTypeView::Trace(Visitor* visitor) {
visitor->Trace(input_type_);
InputTypeView::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.h b/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.h
index f25ebbea912..933d8dd8912 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.h
@@ -59,7 +59,7 @@ class MultipleFieldsTemporalInputTypeView final
MultipleFieldsTemporalInputTypeView(HTMLInputElement&,
BaseTemporalInputType&);
~MultipleFieldsTemporalInputTypeView() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// DateTimeEditElement::EditControlOwner functions
diff --git a/chromium/third_party/blink/renderer/core/html/forms/password_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/password_input_type.cc
index 5260d8fbad4..0fb452d0094 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/password_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/password_input_type.cc
@@ -77,12 +77,4 @@ bool PasswordInputType::ShouldRespectListAttribute() {
return false;
}
-void PasswordInputType::OnAttachWithLayoutObject() {
- GetElement().GetDocument().IncrementPasswordCount();
-}
-
-void PasswordInputType::OnDetachWithLayoutObject() {
- GetElement().GetDocument().DecrementPasswordCount();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/password_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/password_input_type.h
index 3722b54932d..c113962d42c 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/password_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/password_input_type.h
@@ -49,8 +49,6 @@ class PasswordInputType final : public BaseTextInputType {
FormControlState SaveFormControlState() const override;
void RestoreFormControlState(const FormControlState&) override;
bool ShouldRespectListAttribute() override;
- void OnAttachWithLayoutObject() override;
- void OnDetachWithLayoutObject() override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc b/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
index 75bf907e2e4..0c77d2ff404 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
@@ -11,7 +11,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -37,301 +36,14 @@ class MockInsecureInputService : public mojom::blink::InsecureInputService {
unsigned DidEditFieldCalls() const { return num_did_edit_field_calls_; }
- bool PasswordFieldVisibleCalled() const {
- return password_field_visible_called_;
- }
-
- unsigned NumPasswordFieldsInvisibleCalls() const {
- return num_password_fields_invisible_calls_;
- }
-
private:
- // mojom::InsecureInputService
- void PasswordFieldVisibleInInsecureContext() override {
- password_field_visible_called_ = true;
- }
-
- void AllPasswordFieldsInInsecureContextInvisible() override {
- ++num_password_fields_invisible_calls_;
- }
-
void DidEditFieldInInsecureContext() override { ++num_did_edit_field_calls_; }
mojo::BindingSet<InsecureInputService> binding_set_;
- bool password_field_visible_called_ = false;
unsigned num_did_edit_field_calls_ = 0;
- unsigned num_password_fields_invisible_calls_ = 0;
};
-// Tests that a Mojo message is sent when a visible password field
-// appears on the page.
-TEST(PasswordInputTypeTest, PasswordVisibilityEvent) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_TRUE(mock_service.PasswordFieldVisibleCalled());
-}
-
-// Tests that a Mojo message is not sent when a visible password field
-// appears in a secure context.
-TEST(PasswordInputTypeTest, PasswordVisibilityEventInSecureContext) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().SetURL(KURL("https://example.test"));
- page_holder->GetDocument().SetSecurityOrigin(
- SecurityOrigin::Create(KURL("https://example.test")));
- page_holder->GetDocument().SetSecureContextStateForTesting(
- SecureContextState::kSecure);
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- // No message should have been sent from a secure context.
- blink::test::RunPendingTasks();
- EXPECT_FALSE(mock_service.PasswordFieldVisibleCalled());
-}
-
-// Tests that a Mojo message is sent when a previously invisible password field
-// becomes visible.
-TEST(PasswordInputTypeTest, InvisiblePasswordFieldBecomesVisible) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password' style='display:none;'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- // The message should not be sent for a hidden password field.
- EXPECT_FALSE(mock_service.PasswordFieldVisibleCalled());
-
- // Now make the input visible.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setAttribute("style", "", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_TRUE(mock_service.PasswordFieldVisibleCalled());
-}
-
-// Tests that a Mojo message is sent when a previously non-password field
-// becomes a password.
-TEST(PasswordInputTypeTest, NonPasswordFieldBecomesPassword) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='text'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- // The message should not be sent for a non-password field.
- blink::test::RunPendingTasks();
- EXPECT_FALSE(mock_service.PasswordFieldVisibleCalled());
-
- // Now make the input a password field.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setType("password");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_TRUE(mock_service.PasswordFieldVisibleCalled());
-}
-
-// Tests that a Mojo message is *not* sent when a previously invisible password
-// field becomes a visible non-password field.
-TEST(PasswordInputTypeTest,
- InvisiblePasswordFieldBecomesVisibleNonPasswordField) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password' style='display:none;'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- // The message should not be sent for a hidden password field.
- EXPECT_FALSE(mock_service.PasswordFieldVisibleCalled());
-
- // Now make the input a visible non-password field.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setType("text");
- input->setAttribute("style", "", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_FALSE(mock_service.PasswordFieldVisibleCalled());
-}
-
-// Tests that a Mojo message is sent when the only visible password
-// field becomes invisible.
-TEST(PasswordInputTypeTest, VisiblePasswordFieldBecomesInvisible) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_TRUE(mock_service.PasswordFieldVisibleCalled());
- EXPECT_EQ(0u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // Now make the input invisible.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setAttribute("style", "display:none;", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
-}
-
-// Tests that a Mojo message is sent when all visible password fields
-// become invisible.
-TEST(PasswordInputTypeTest, AllVisiblePasswordFieldBecomeInvisible) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password'><input type='password'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(0u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // Make the first input invisible. There should be no message because
- // there is still a visible input.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setAttribute("style", "display:none;", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(0u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // When all inputs are invisible, then a message should be sent.
- input = ToHTMLInputElement(page_holder->GetDocument().body()->lastChild());
- input->setAttribute("style", "display:none;", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // If the count of visible inputs goes positive again and then back to
- // zero, a message should be sent again.
- input->setAttribute("style", "", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
- input->setAttribute("style", "display:none;", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(2u, mock_service.NumPasswordFieldsInvisibleCalls());
-}
-
-// Tests that a Mojo message is sent when the containing element of a
-// visible password field becomes invisible.
-TEST(PasswordInputTypeTest, PasswordFieldContainerBecomesInvisible) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<div><input type='password'></div>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(0u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // If the containing div becomes invisible, a message should be sent.
- HTMLElement* div =
- ToHTMLDivElement(page_holder->GetDocument().body()->firstChild());
- div->setAttribute("style", "display:none;", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // If the containing div becomes visible and then invisible again, a message
- // should be sent.
- div->setAttribute("style", "", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
- div->setAttribute("style", "display:none;", ASSERT_NO_EXCEPTION);
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(2u, mock_service.NumPasswordFieldsInvisibleCalls());
-}
-
-// Tests that a Mojo message is sent when all visible password fields
-// become non-password fields.
-TEST(PasswordInputTypeTest, PasswordFieldsBecomeNonPasswordFields) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password'><input type='password'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(0u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // Make the first input a non-password input. There should be no
- // message because there is still a visible password input.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setType("text");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(0u, mock_service.NumPasswordFieldsInvisibleCalls());
-
- // When all inputs are no longer passwords, then a message should be sent.
- input = ToHTMLInputElement(page_holder->GetDocument().body()->lastChild());
- input->setType("text");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
-}
-
-// Tests that only one Mojo message is sent for multiple password
-// visibility events within the same task.
-TEST(PasswordInputTypeTest, MultipleEventsInSameTask) {
- std::unique_ptr<DummyPageHolder> page_holder =
- DummyPageHolder::Create(IntSize(2000, 2000));
- MockInsecureInputService mock_service(page_holder->GetFrame());
- page_holder->GetDocument().body()->SetInnerHTMLFromString(
- "<input type='password'>");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- // Make the password field invisible in the same task.
- HTMLInputElement* input =
- ToHTMLInputElement(page_holder->GetDocument().body()->firstChild());
- input->setType("text");
- page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- blink::test::RunPendingTasks();
- // Only a single Mojo message should have been sent, with the latest state of
- // the page (which is that no password fields are visible).
- EXPECT_EQ(1u, mock_service.NumPasswordFieldsInvisibleCalls());
- EXPECT_FALSE(mock_service.PasswordFieldVisibleCalled());
-}
-
// Tests that a Mojo message is sent when a password field is edited
// on the page.
TEST(PasswordInputTypeTest, DidEditFieldEvent) {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.cc b/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.cc
index 252e601eadb..f308755432e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.cc
@@ -175,7 +175,7 @@ void PickerIndicatorElement::DidNotifySubtreeInsertionsToDocument() {
WebLocalizedString::kAXCalendarShowDatePicker)));
}
-void PickerIndicatorElement::Trace(blink::Visitor* visitor) {
+void PickerIndicatorElement::Trace(Visitor* visitor) {
visitor->Trace(picker_indicator_owner_);
visitor->Trace(chooser_);
HTMLDivElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.h b/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.h
index b2d2834dfe2..64b6256f5ad 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/picker_indicator_element.h
@@ -61,7 +61,7 @@ class PickerIndicatorElement final : public HTMLDivElement,
PickerIndicatorElement(Document&, PickerIndicatorOwner&);
~PickerIndicatorElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void OpenPopup();
void ClosePopup();
diff --git a/chromium/third_party/blink/renderer/core/html/forms/popup_menu.h b/chromium/third_party/blink/renderer/core/html/forms/popup_menu.h
index c2175a18ada..8a14dcb89f2 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/popup_menu.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/popup_menu.h
@@ -29,7 +29,7 @@ namespace blink {
class PopupMenu : public GarbageCollectedFinalized<PopupMenu> {
public:
virtual ~PopupMenu() = default;
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
virtual void Show() = 0;
virtual void Hide() = 0;
enum UpdateReason {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc b/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
index f4968e4f40d..50b28e83739 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
@@ -43,7 +43,7 @@ class RadioButtonGroup : public GarbageCollected<RadioButtonGroup> {
bool Contains(HTMLInputElement*) const;
unsigned size() const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
void SetNeedsValidityCheckForAllButtons();
@@ -195,7 +195,7 @@ unsigned RadioButtonGroup::size() const {
return members_.size();
}
-void RadioButtonGroup::Trace(blink::Visitor* visitor) {
+void RadioButtonGroup::Trace(Visitor* visitor) {
visitor->Trace(members_);
visitor->Trace(checked_button_);
}
@@ -297,7 +297,7 @@ void RadioButtonGroupScope::RemoveButton(HTMLInputElement* element) {
}
}
-void RadioButtonGroupScope::Trace(blink::Visitor* visitor) {
+void RadioButtonGroupScope::Trace(Visitor* visitor) {
visitor->Trace(name_to_group_map_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h b/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h
index 8c8c9a20a87..11399c9d004 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h
@@ -37,7 +37,7 @@ class RadioButtonGroupScope {
public:
RadioButtonGroupScope();
~RadioButtonGroupScope();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void AddButton(HTMLInputElement*);
void UpdateCheckedState(HTMLInputElement*);
void RequiredAttributeChanged(HTMLInputElement*);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc
index f12a9a15980..b9577f91d55 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc
@@ -187,7 +187,7 @@ ClickHandlingState* RadioInputType::WillDispatchClick() {
// upcoming action to be "undone", since we want some object in the radio
// group to actually get selected.
- ClickHandlingState* state = new ClickHandlingState;
+ ClickHandlingState* state = MakeGarbageCollected<ClickHandlingState>();
state->checked = GetElement().checked();
state->checked_radio_button = GetElement().CheckedRadioButtonForGroup();
diff --git a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc
index d32bc57d454..34d73082e5c 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc
@@ -79,7 +79,7 @@ RangeInputType::RangeInputType(HTMLInputElement& element)
InputTypeView(element),
tick_mark_values_dirty_(true) {}
-void RangeInputType::Trace(blink::Visitor* visitor) {
+void RangeInputType::Trace(Visitor* visitor) {
InputTypeView::Trace(visitor);
InputType::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h
index a0bd003cb04..ca8e69e8a49 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h
@@ -47,7 +47,7 @@ class RangeInputType final : public InputType, public InputTypeView {
RangeInputType(HTMLInputElement&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
private:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js b/chromium/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js
index faf40b26b4a..9c2249588d6 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js
+++ b/chromium/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js
@@ -93,7 +93,7 @@ function localizeNumber(number) {
* @const
* @type {number}
*/
-var ImperialEraLimit = 2087;
+var ImperialEraLimit = 2117;
/**
* @param {!number} year
@@ -105,6 +105,10 @@ function formatJapaneseImperialEra(year, month) {
// limitation.
if (year > ImperialEraLimit)
return '';
+ if (year >= 2020 || year == 2019 && month >= 4) {
+ // TODO(tkent): Next of Heisei is not published yet.
+ return '';
+ }
if (year > 1989)
return '(\u5e73\u6210' + localizeNumber(year - 1988) + '\u5e74)';
if (year == 1989)
diff --git a/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js b/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js
index 2ed7603e366..59af8767d28 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js
+++ b/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js
@@ -50,6 +50,7 @@ function ListPicker(element, config) {
this._selectElement.addEventListener('change', this._handleChange.bind(this), false);
window.addEventListener('message', this._handleWindowMessage.bind(this), false);
window.addEventListener('mousemove', this._handleWindowMouseMove.bind(this), false);
+ window.addEventListener('mouseover', this._handleWindowMouseOver.bind(this), false);
this._handleWindowTouchMoveBound = this._handleWindowTouchMove.bind(this);
this._handleWindowTouchEndBound = this._handleWindowTouchEnd.bind(this);
this._handleTouchSelectModeScrollBound = this._handleTouchSelectModeScroll.bind(this);
@@ -115,12 +116,15 @@ ListPicker.prototype._handleWindowMouseMove = function(event) {
}
this.lastMousePositionX = event.clientX;
this.lastMousePositionY = event.clientY;
- this._highlightOption(event.target);
this._selectionSetByMouseHover = true;
// Prevent the select element from firing change events for mouse input.
event.preventDefault();
};
+ListPicker.prototype._handleWindowMouseOver = function(event) {
+ this._highlightOption(event.target);
+};
+
ListPicker.prototype._handleMouseUp = function(event) {
if (event.target.tagName !== 'OPTION')
return;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
index 5ae900a02d0..eb64c4cdfb7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -281,7 +281,7 @@ bool SliderThumbElement::WillRespondToMouseClickEvents() {
void SliderThumbElement::DetachLayoutTree(const AttachContext& context) {
if (in_drag_mode_) {
if (LocalFrame* frame = GetDocument().GetFrame())
- frame->GetEventHandler().SetCapturingMouseEventsNode(nullptr);
+ frame->GetEventHandler().SetCapturingMouseEventsElement(nullptr);
}
HTMLDivElement::DetachLayoutTree(context);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
index 3eb98535f7f..0794170231c 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
@@ -89,6 +89,8 @@ class SliderContainerElement final : public HTMLDivElement {
kNoMove,
};
+ explicit SliderContainerElement(Document&);
+
DECLARE_NODE_FACTORY(SliderContainerElement);
HTMLInputElement* HostInput() const;
void DefaultEventHandler(Event&) override;
@@ -98,7 +100,6 @@ class SliderContainerElement final : public HTMLDivElement {
void RemoveAllEventListeners() override;
private:
- explicit SliderContainerElement(Document&);
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() final;
const AtomicString& ShadowPseudoId() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc
index f2f78867196..38ae21536b2 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc
@@ -120,7 +120,7 @@ void SpinButtonElement::DefaultEventHandler(Event& event) {
if (box->PixelSnappedBorderBoxRect().Contains(local)) {
if (!capturing_) {
if (LocalFrame* frame = GetDocument().GetFrame()) {
- frame->GetEventHandler().SetCapturingMouseEventsNode(this);
+ frame->GetEventHandler().SetCapturingMouseEventsElement(this);
capturing_ = true;
if (Page* page = GetDocument().GetPage())
page->GetChromeClient().RegisterPopupOpeningObserver(this);
@@ -191,7 +191,7 @@ void SpinButtonElement::ReleaseCapture(EventDispatch event_dispatch) {
if (!capturing_)
return;
if (LocalFrame* frame = GetDocument().GetFrame()) {
- frame->GetEventHandler().SetCapturingMouseEventsNode(nullptr);
+ frame->GetEventHandler().SetCapturingMouseEventsElement(nullptr);
capturing_ = false;
if (Page* page = GetDocument().GetPage())
page->GetChromeClient().UnregisterPopupOpeningObserver(this);
@@ -250,7 +250,7 @@ bool SpinButtonElement::ShouldRespondToMouseEvents() {
spin_button_owner_->ShouldSpinButtonRespondToMouseEvents();
}
-void SpinButtonElement::Trace(blink::Visitor* visitor) {
+void SpinButtonElement::Trace(Visitor* visitor) {
visitor->Trace(spin_button_owner_);
HTMLDivElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h
index 13b586d7a42..47773256a7b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h
@@ -77,7 +77,7 @@ class CORE_EXPORT SpinButtonElement final : public HTMLDivElement,
void ForwardEvent(Event&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void DetachLayoutTree(const AttachContext&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
index 7c8e72c9115..62b9ee09585 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -180,7 +180,7 @@ TextControlInnerEditorElement::CreateInnerEditorStyle() const {
// We'd like to remove line-height if it's unnecessary because
// overflow:scroll clips editing text by line-height.
- Length logical_height = start_style.LogicalHeight();
+ const Length& logical_height = start_style.LogicalHeight();
// Here, we remove line-height if the INPUT fixed height is taller than the
// line-height. It's not the precise condition because logicalHeight
// includes border and padding if box-sizing:border-box, and there are cases
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
index 0968da45e29..412d25b3ec7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
@@ -113,7 +113,7 @@ TextFieldInputType::TextFieldInputType(HTMLInputElement& element)
TextFieldInputType::~TextFieldInputType() = default;
-void TextFieldInputType::Trace(blink::Visitor* visitor) {
+void TextFieldInputType::Trace(Visitor* visitor) {
InputTypeView::Trace(visitor);
InputType::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h
index 77ced4ace78..c2aeaaae77c 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h
@@ -45,7 +45,7 @@ class TextFieldInputType : public InputType,
USING_GARBAGE_COLLECTED_MIXIN(TextFieldInputType);
public:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
using InputType::GetElement;
protected:
diff --git a/chromium/third_party/blink/renderer/core/html/forms/validity_state.h b/chromium/third_party/blink/renderer/core/html/forms/validity_state.h
index 7daa760dcfa..7e8ad131d4f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/validity_state.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/validity_state.h
@@ -40,7 +40,7 @@ class ValidityState final : public ScriptWrappable {
explicit ValidityState(ListedElement* control) : control_(control) {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(control_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc b/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc
index c55a66f3f58..4903dd6f24d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -51,6 +51,7 @@
#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/network/network_hints.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
namespace blink {
@@ -59,21 +60,23 @@ namespace {
void RecordDownloadMetrics(LocalFrame* frame) {
if (frame->IsMainFrame()) {
- DownloadStats::RecordMainFrameHasGesture(
- LocalFrame::HasTransientUserActivation(frame));
+ DownloadStats::MainFrameDownloadFlags flags;
+ flags.has_sandbox = frame->GetDocument()->IsSandboxed(kSandboxDownloads);
+ flags.has_gesture = LocalFrame::HasTransientUserActivation(frame);
+ DownloadStats::RecordMainFrameDownloadFlags(
+ flags, frame->GetDocument()->UkmSourceID(),
+ frame->GetDocument()->UkmRecorder());
return;
}
- unsigned value = 0;
- if (frame->GetDocument()->IsSandboxed(kSandboxDownloads))
- value |= DownloadStats::kSandboxBit;
- if (frame->IsCrossOriginSubframe())
- value |= DownloadStats::kCrossOriginBit;
- if (frame->IsAdSubframe())
- value |= DownloadStats::kAdBit;
- if (LocalFrame::HasTransientUserActivation(frame))
- value |= DownloadStats::kGestureBit;
- DownloadStats::RecordSubframeSandboxOriginAdGesture(value);
+ DownloadStats::SubframeDownloadFlags flags;
+ flags.has_sandbox = frame->GetDocument()->IsSandboxed(kSandboxDownloads);
+ flags.is_cross_origin = frame->IsCrossOriginSubframe();
+ flags.is_ad_frame = frame->IsAdSubframe();
+ flags.has_gesture = LocalFrame::HasTransientUserActivation(frame);
+ DownloadStats::RecordSubframeDownloadFlags(
+ flags, frame->GetDocument()->UkmSourceID(),
+ frame->GetDocument()->UkmRecorder());
}
} // namespace
@@ -198,10 +201,11 @@ void HTMLAnchorElement::SetActive(bool down) {
ContainerNode::SetActive(down);
}
-const HashSet<AtomicString>& HTMLAnchorElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLAnchorElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"href"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"href", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
void HTMLAnchorElement::AttributeChanged(
@@ -403,10 +407,24 @@ void HTMLAnchorElement::HandleClick(Event& event) {
if (hasAttribute(kDownloadAttr) &&
NavigationPolicyFromEvent(&event) != kNavigationPolicyDownload &&
GetDocument().GetSecurityOrigin()->CanReadContent(completed_url)) {
+ if (frame->IsAdSubframe()) {
+ // Note: Here it covers download originated from clicking on <a download>
+ // link that results in direct download. These two features can also be
+ // logged from browser for download due to navigations to
+ // non-web-renderable content.
+ UseCounter::Count(GetDocument(),
+ LocalFrame::HasTransientUserActivation(frame)
+ ? WebFeature::kDownloadInAdFrameWithUserGesture
+ : WebFeature::kDownloadInAdFrameWithoutUserGesture);
+ }
if (GetDocument().IsSandboxed(kSandboxDownloads)) {
+ if (!LocalFrame::HasTransientUserActivation(frame) &&
+ RuntimeEnabledFeatures::
+ BlockingDownloadsInSandboxWithoutUserActivationEnabled())
+ return;
UseCounter::Count(
GetDocument(),
- UserGestureIndicator::ProcessingUserGesture()
+ LocalFrame::HasTransientUserActivation(frame)
? WebFeature::kHTMLAnchorElementDownloadInSandboxWithUserGesture
: WebFeature::
kHTMLAnchorElementDownloadInSandboxWithoutUserGesture);
@@ -485,7 +503,7 @@ Node::InsertionNotificationRequest HTMLAnchorElement::InsertedInto(
return request;
}
-void HTMLAnchorElement::Trace(blink::Visitor* visitor) {
+void HTMLAnchorElement::Trace(Visitor* visitor) {
visitor->Trace(rel_list_);
HTMLElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_anchor_element.h b/chromium/third_party/blink/renderer/core/html/html_anchor_element.h
index 464ae2a2272..7fdb3347d70 100644
--- a/chromium/third_party/blink/renderer/core/html/html_anchor_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_anchor_element.h
@@ -71,7 +71,7 @@ class CORE_EXPORT HTMLAnchorElement : public HTMLElement, public DOMURLUtils {
~HTMLAnchorElement() override;
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
KURL Href() const;
void SetHref(const AtomicString&);
@@ -100,7 +100,7 @@ class CORE_EXPORT HTMLAnchorElement : public HTMLElement, public DOMURLUtils {
void SendPings(const KURL& destination_url) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_area_element.h b/chromium/third_party/blink/renderer/core/html/html_area_element.h
index 7d710716267..d9d29f0bc2f 100644
--- a/chromium/third_party/blink/renderer/core/html/html_area_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_area_element.h
@@ -40,6 +40,8 @@ class CORE_EXPORT HTMLAreaElement final : public HTMLAnchorElement {
public:
DECLARE_NODE_FACTORY(HTMLAreaElement);
+ explicit HTMLAreaElement(Document&);
+
bool IsDefault() const { return shape_ == kDefault; }
// |containerObject| in the following functions is an object (normally a
@@ -58,7 +60,6 @@ class CORE_EXPORT HTMLAreaElement final : public HTMLAnchorElement {
HTMLImageElement* ImageElement() const;
private:
- explicit HTMLAreaElement(Document&);
~HTMLAreaElement() override;
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5 b/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5
index 688b1ba533b..6a4021d22fe 100644
--- a/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -27,6 +27,7 @@
"autocorrect",
"autofocus",
"autoplay",
+ "autopictureinpicture",
"axis",
"background",
"behavior",
@@ -208,6 +209,7 @@
"ononline",
"onoffline",
"onorientationchange",
+ "onoverscroll",
"onpagehide",
"onpageshow",
"onpaste",
@@ -224,11 +226,13 @@
"onpointerrawmove",
"onpointerup",
"onpopstate",
+ "onportalactivate",
"onprogress",
"onratechange",
"onreset",
"onresize",
"onscroll",
+ "onscrollend",
"onsearch",
"onseeked",
"onseeking",
diff --git a/chromium/third_party/blink/renderer/core/html/html_base_element.cc b/chromium/third_party/blink/renderer/core/html/html_base_element.cc
index c72c4f9dd31..24a433a8c30 100644
--- a/chromium/third_party/blink/renderer/core/html/html_base_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_base_element.cc
@@ -39,9 +39,10 @@ inline HTMLBaseElement::HTMLBaseElement(Document& document)
DEFINE_NODE_FACTORY(HTMLBaseElement)
-const HashSet<AtomicString>& HTMLBaseElement::GetCheckedAttributeNames() const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"href"}));
- return attribute_set;
+const AttrNameToTrustedType& HTMLBaseElement::GetCheckedAttributeTypes() const {
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"href", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
void HTMLBaseElement::ParseAttribute(
diff --git a/chromium/third_party/blink/renderer/core/html/html_base_element.h b/chromium/third_party/blink/renderer/core/html/html_base_element.h
index b6e7ec009e1..32037b3856d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_base_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_base_element.h
@@ -36,16 +36,16 @@ class HTMLBaseElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLBaseElement);
+ explicit HTMLBaseElement(Document&);
+
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
KURL href() const;
void href(USVStringOrTrustedURL&) const;
void setHref(const USVStringOrTrustedURL&, ExceptionState&);
private:
- explicit HTMLBaseElement(Document&);
-
bool IsURLAttribute(const Attribute&) const override;
void ParseAttribute(const AttributeModificationParams&) override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_bdi_element.h b/chromium/third_party/blink/renderer/core/html/html_bdi_element.h
index 2e5a947270b..067e91260ad 100644
--- a/chromium/third_party/blink/renderer/core/html/html_bdi_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_bdi_element.h
@@ -29,7 +29,6 @@ class HTMLBDIElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLBDIElement);
- private:
inline explicit HTMLBDIElement(Document& document)
: HTMLElement(html_names::kBdiTag, document) {}
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_body_element.cc b/chromium/third_party/blink/renderer/core/html/html_body_element.cc
index 86a99736d2a..d668722179e 100644
--- a/chromium/third_party/blink/renderer/core/html/html_body_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_body_element.cc
@@ -211,6 +211,11 @@ void HTMLBodyElement::ParseAttribute(
GetDocument().SetWindowAttributeEventListener(
event_type_names::kLanguagechange,
CreateAttributeEventListener(GetDocument().GetFrame(), name, value));
+ } else if (RuntimeEnabledFeatures::PortalsEnabled() &&
+ name == kOnportalactivateAttr) {
+ GetDocument().SetWindowAttributeEventListener(
+ event_type_names::kPortalactivate,
+ CreateAttributeEventListener(GetDocument().GetFrame(), name, value));
} else {
HTMLElement::ParseAttribute(params);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_body_element.h b/chromium/third_party/blink/renderer/core/html/html_body_element.h
index b03d6cffee2..ef648e878b4 100644
--- a/chromium/third_party/blink/renderer/core/html/html_body_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_body_element.h
@@ -37,6 +37,8 @@ class CORE_EXPORT HTMLBodyElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLBodyElement);
+
+ explicit HTMLBodyElement(Document&);
~HTMLBodyElement() override;
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(blur, kBlur);
@@ -48,8 +50,6 @@ class CORE_EXPORT HTMLBodyElement final : public HTMLElement {
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(orientationchange, kOrientationchange);
private:
- explicit HTMLBodyElement(Document&);
-
void ParseAttribute(const AttributeModificationParams&) override;
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/html/html_br_element.h b/chromium/third_party/blink/renderer/core/html/html_br_element.h
index 630c805b27b..3cff06a77cf 100644
--- a/chromium/third_party/blink/renderer/core/html/html_br_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_br_element.h
@@ -35,11 +35,11 @@ class CORE_EXPORT HTMLBRElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLBRElement);
+ explicit HTMLBRElement(Document&);
+
bool CanContainRangeEndPoint() const override { return false; }
private:
- explicit HTMLBRElement(Document&);
-
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
const QualifiedName&,
diff --git a/chromium/third_party/blink/renderer/core/html/html_collection.cc b/chromium/third_party/blink/renderer/core/html/html_collection.cc
index ca67e176c61..b8692228cf5 100644
--- a/chromium/third_party/blink/renderer/core/html/html_collection.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_collection.cc
@@ -543,7 +543,7 @@ void HTMLCollection::NamedItems(const AtomicString& name,
HTMLCollection::NamedItemCache::NamedItemCache() = default;
-void HTMLCollection::Trace(blink::Visitor* visitor) {
+void HTMLCollection::Trace(Visitor* visitor) {
visitor->Trace(named_item_cache_);
visitor->Trace(collection_items_cache_);
ScriptWrappable::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/html_collection.h b/chromium/third_party/blink/renderer/core/html/html_collection.h
index 0ba2dfaa56f..da96826980f 100644
--- a/chromium/third_party/blink/renderer/core/html/html_collection.h
+++ b/chromium/third_party/blink/renderer/core/html/html_collection.h
@@ -112,7 +112,7 @@ class CORE_EXPORT HTMLCollection : public ScriptWrappable,
Iterator begin() const { return Iterator(this); }
Iterator end() const { return Iterator::CreateEnd(this); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
class NamedItemCache final : public GarbageCollected<NamedItemCache> {
@@ -144,7 +144,7 @@ class CORE_EXPORT HTMLCollection : public ScriptWrappable,
AddElementToMap(name_cache_, name, element);
}
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(id_cache_);
visitor->Trace(name_cache_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_content_element.cc b/chromium/third_party/blink/renderer/core/html/html_content_element.cc
index 00800995151..497d6904aed 100644
--- a/chromium/third_party/blink/renderer/core/html/html_content_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_content_element.cc
@@ -49,7 +49,7 @@ inline HTMLContentElement::HTMLContentElement(Document& document)
HTMLContentElement::~HTMLContentElement() = default;
-void HTMLContentElement::Trace(blink::Visitor* visitor) {
+void HTMLContentElement::Trace(Visitor* visitor) {
V0InsertionPoint::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_content_element.h b/chromium/third_party/blink/renderer/core/html/html_content_element.h
index e8a624180cc..e471352219d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_content_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_content_element.h
@@ -43,6 +43,8 @@ class CORE_EXPORT HTMLContentElement final : public V0InsertionPoint {
public:
DECLARE_NODE_FACTORY(HTMLContentElement);
+
+ HTMLContentElement(Document&);
~HTMLContentElement() override;
bool CanAffectSelector() const override { return true; }
@@ -53,11 +55,9 @@ class CORE_EXPORT HTMLContentElement final : public V0InsertionPoint {
const CSSSelectorList& SelectorList() const;
bool IsSelectValid() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- HTMLContentElement(Document&);
-
void ParseAttribute(const AttributeModificationParams&) override;
bool ValidateSelect() const;
diff --git a/chromium/third_party/blink/renderer/core/html/html_dialog_element.h b/chromium/third_party/blink/renderer/core/html/html_dialog_element.h
index 1562436ff75..2d5ddf52718 100644
--- a/chromium/third_party/blink/renderer/core/html/html_dialog_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_dialog_element.h
@@ -40,6 +40,8 @@ class HTMLDialogElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLDialogElement);
+ explicit HTMLDialogElement(Document&);
+
void close(const String& return_value = String());
void show();
void showModal(ExceptionState&);
@@ -63,8 +65,6 @@ class HTMLDialogElement final : public HTMLElement {
}
private:
- explicit HTMLDialogElement(Document&);
-
bool IsPresentationAttribute(const QualifiedName&) const override;
void DefaultEventHandler(Event&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_directory_element.h b/chromium/third_party/blink/renderer/core/html/html_directory_element.h
index e60d23b6a2b..c34aba84db0 100644
--- a/chromium/third_party/blink/renderer/core/html/html_directory_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_directory_element.h
@@ -33,7 +33,6 @@ class HTMLDirectoryElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLDirectoryElement);
- private:
explicit HTMLDirectoryElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_div_element.h b/chromium/third_party/blink/renderer/core/html/html_div_element.h
index 15ea0c11d4e..fe95f93beac 100644
--- a/chromium/third_party/blink/renderer/core/html/html_div_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_div_element.h
@@ -34,7 +34,6 @@ class CORE_EXPORT HTMLDivElement : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLDivElement);
- protected:
explicit HTMLDivElement(Document&);
private:
diff --git a/chromium/third_party/blink/renderer/core/html/html_dlist_element.h b/chromium/third_party/blink/renderer/core/html/html_dlist_element.h
index dd74175e927..a81b7e3d7a1 100644
--- a/chromium/third_party/blink/renderer/core/html/html_dlist_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_dlist_element.h
@@ -33,7 +33,6 @@ class HTMLDListElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLDListElement);
- private:
explicit HTMLDListElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_document.cc b/chromium/third_party/blink/renderer/core/html/html_document.cc
index 17c13f90795..46585f1dd2e 100644
--- a/chromium/third_party/blink/renderer/core/html/html_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_document.cc
@@ -53,6 +53,7 @@
#include "third_party/blink/renderer/core/html/html_document.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
@@ -136,7 +137,7 @@ static HashSet<StringImpl*>* CreateHtmlCaseInsensitiveAttributesSet() {
&kTargetAttr, &kTextAttr, &kTypeAttr, &kValignAttr,
&kValuetypeAttr, &kVlinkAttr};
- attr_set->ReserveCapacityForSize(arraysize(case_insensitive_attributes));
+ attr_set->ReserveCapacityForSize(base::size(case_insensitive_attributes));
for (const QualifiedName* attr : case_insensitive_attributes)
attr_set->insert(attr->LocalName().Impl());
diff --git a/chromium/third_party/blink/renderer/core/html/html_element.cc b/chromium/third_party/blink/renderer/core/html/html_element.cc
index 0fc74ac10bb..a4574f3b8f9 100644
--- a/chromium/third_party/blink/renderer/core/html/html_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_element.cc
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/text.h"
@@ -57,6 +58,7 @@
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/forms/labels_node_list.h"
#include "third_party/blink/renderer/core/html/html_br_element.h"
#include "third_party/blink/renderer/core/html/html_dimension.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
@@ -337,6 +339,7 @@ AttributeTriggers* HTMLElement::TriggersForAttributeName(
const AtomicString& kNoEvent = g_null_atom;
static AttributeTriggers attribute_triggers[] = {
{kDirAttr, kNoWebFeature, kNoEvent, &HTMLElement::OnDirAttrChanged},
+ {kFormAttr, kNoWebFeature, kNoEvent, &HTMLElement::OnFormAttrChanged},
{kInertAttr, WebFeature::kInertAttribute, kNoEvent,
&HTMLElement::OnInertAttrChanged},
{kLangAttr, kNoWebFeature, kNoEvent, &HTMLElement::OnLangAttrChanged},
@@ -417,6 +420,8 @@ AttributeTriggers* HTMLElement::TriggersForAttributeName(
{kOnmouseupAttr, kNoWebFeature, event_type_names::kMouseup, nullptr},
{kOnmousewheelAttr, kNoWebFeature, event_type_names::kMousewheel,
nullptr},
+ {kOnoverscrollAttr, kNoWebFeature, event_type_names::kOverscroll,
+ nullptr},
{kOnpasteAttr, kNoWebFeature, event_type_names::kPaste, nullptr},
{kOnpauseAttr, kNoWebFeature, event_type_names::kPause, nullptr},
{kOnplayAttr, kNoWebFeature, event_type_names::kPlay, nullptr},
@@ -444,6 +449,7 @@ AttributeTriggers* HTMLElement::TriggersForAttributeName(
{kOnresetAttr, kNoWebFeature, event_type_names::kReset, nullptr},
{kOnresizeAttr, kNoWebFeature, event_type_names::kResize, nullptr},
{kOnscrollAttr, kNoWebFeature, event_type_names::kScroll, nullptr},
+ {kOnscrollendAttr, kNoWebFeature, event_type_names::kScrollend, nullptr},
{kOnseekedAttr, kNoWebFeature, event_type_names::kSeeked, nullptr},
{kOnseekingAttr, kNoWebFeature, event_type_names::kSeeking, nullptr},
{kOnselectAttr, kNoWebFeature, event_type_names::kSelect, nullptr},
@@ -589,6 +595,17 @@ const AtomicString& HTMLElement::EventNameForAttributeName(
void HTMLElement::AttributeChanged(const AttributeModificationParams& params) {
Element::AttributeChanged(params);
+ if (params.name == html_names::kDisabledAttr &&
+ params.old_value.IsNull() != params.new_value.IsNull()) {
+ if (IsFormAssociatedCustomElement()) {
+ EnsureElementInternals().DisabledAttributeChanged();
+ if (params.reason == AttributeModificationReason::kDirectly &&
+ IsDisabledFormControl() &&
+ AdjustedFocusedElementInTreeScope() == this)
+ blur();
+ }
+ return;
+ }
if (params.reason != AttributeModificationReason::kDirectly)
return;
// adjustedFocusedElementInTreeScope() is not trivial. We should check
@@ -1275,6 +1292,12 @@ void HTMLElement::AddHTMLColorToStyle(MutableCSSPropertyValueSet* style,
style->SetProperty(property_id, *CSSColorValue::Create(parsed_color.Rgb()));
}
+LabelsNodeList* HTMLElement::labels() {
+ if (!IsLabelable())
+ return nullptr;
+ return EnsureCachedCollection<LabelsNodeList>(kLabelsNodeListType);
+}
+
bool HTMLElement::IsInteractiveContent() const {
return false;
}
@@ -1399,6 +1422,11 @@ void HTMLElement::OnDirAttrChanged(const AttributeModificationParams& params) {
CalculateAndAdjustDirectionality();
}
+void HTMLElement::OnFormAttrChanged(const AttributeModificationParams& params) {
+ if (IsFormAssociatedCustomElement())
+ EnsureElementInternals().FormAttributeChanged();
+}
+
void HTMLElement::OnInertAttrChanged(
const AttributeModificationParams& params) {
UpdateDistributionForUnknownReasons();
@@ -1466,6 +1494,43 @@ bool HTMLElement::IsFormAssociatedCustomElement() const {
GetCustomElementDefinition()->IsFormAssociated();
}
+bool HTMLElement::SupportsFocus() const {
+ return Element::SupportsFocus() && !IsDisabledFormControl();
+};
+
+bool HTMLElement::IsDisabledFormControl() const {
+ if (!IsFormAssociatedCustomElement())
+ return false;
+ return const_cast<HTMLElement*>(this)
+ ->EnsureElementInternals()
+ .IsActuallyDisabled();
+}
+
+bool HTMLElement::MatchesEnabledPseudoClass() const {
+ return IsFormAssociatedCustomElement() && !const_cast<HTMLElement*>(this)
+ ->EnsureElementInternals()
+ .IsActuallyDisabled();
+}
+
+bool HTMLElement::MatchesValidityPseudoClasses() const {
+ return IsFormAssociatedCustomElement();
+}
+
+bool HTMLElement::willValidate() const {
+ return IsFormAssociatedCustomElement() && const_cast<HTMLElement*>(this)
+ ->EnsureElementInternals()
+ .WillValidate();
+}
+
+bool HTMLElement::IsValidElement() {
+ return IsFormAssociatedCustomElement() &&
+ EnsureElementInternals().IsValidElement();
+}
+
+bool HTMLElement::IsLabelable() const {
+ return IsFormAssociatedCustomElement();
+}
+
} // namespace blink
#ifndef NDEBUG
diff --git a/chromium/third_party/blink/renderer/core/html/html_element.h b/chromium/third_party/blink/renderer/core/html/html_element.h
index dae88c91463..2d9f2e3d5ea 100644
--- a/chromium/third_party/blink/renderer/core/html/html_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_element.h
@@ -37,6 +37,7 @@ class ExceptionState;
class FormAssociated;
class HTMLFormElement;
class KeyboardEvent;
+class LabelsNodeList;
class StringOrTrustedScript;
class StringTreatNullAsEmptyStringOrTrustedScript;
@@ -108,7 +109,11 @@ class CORE_EXPORT HTMLElement : public Element {
virtual bool IsHTMLUnknownElement() const { return false; }
virtual bool IsPluginElement() const { return false; }
- virtual bool IsLabelable() const { return false; }
+ // https://html.spec.whatwg.org/multipage/forms.html#category-label
+ virtual bool IsLabelable() const;
+ // |labels| IDL attribute implementation for IsLabelable()==true elements.
+ LabelsNodeList* labels();
+
// http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#interactive-content
virtual bool IsInteractiveContent() const;
void DefaultEventHandler(Event&) override;
@@ -116,8 +121,14 @@ class CORE_EXPORT HTMLElement : public Element {
static const AtomicString& EventNameForAttributeName(
const QualifiedName& attr_name);
+ bool SupportsFocus() const override;
+ bool IsDisabledFormControl() const override;
+ bool MatchesEnabledPseudoClass() const override;
bool MatchesReadOnlyPseudoClass() const override;
bool MatchesReadWritePseudoClass() const override;
+ bool MatchesValidityPseudoClasses() const override;
+ bool willValidate() const override;
+ bool IsValidElement() override;
static const AtomicString& EventParameterName();
@@ -197,6 +208,7 @@ class CORE_EXPORT HTMLElement : public Element {
const QualifiedName& attr_name);
void OnDirAttrChanged(const AttributeModificationParams&);
+ void OnFormAttrChanged(const AttributeModificationParams&);
void OnInertAttrChanged(const AttributeModificationParams&);
void OnLangAttrChanged(const AttributeModificationParams&);
void OnNonceAttrChanged(const AttributeModificationParams&);
diff --git a/chromium/third_party/blink/renderer/core/html/html_embed_element.cc b/chromium/third_party/blink/renderer/core/html/html_embed_element.cc
index 1f152c3b471..bc92ccacd96 100644
--- a/chromium/third_party/blink/renderer/core/html/html_embed_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_embed_element.cc
@@ -55,10 +55,11 @@ HTMLEmbedElement* HTMLEmbedElement::Create(Document& document,
return element;
}
-const HashSet<AtomicString>& HTMLEmbedElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLEmbedElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedScriptURL}}));
+ return attribute_map;
}
static inline LayoutEmbeddedContent* FindPartLayoutObject(const Node* n) {
diff --git a/chromium/third_party/blink/renderer/core/html/html_embed_element.h b/chromium/third_party/blink/renderer/core/html/html_embed_element.h
index 98a1e7cad6b..88985b45d23 100644
--- a/chromium/third_party/blink/renderer/core/html/html_embed_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_embed_element.h
@@ -40,7 +40,7 @@ class CORE_EXPORT HTMLEmbedElement final : public HTMLPlugInElement {
HTMLEmbedElement(Document&, const CreateElementFlags);
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
bool IsExposed() const;
diff --git a/chromium/third_party/blink/renderer/core/html/html_embed_element.idl b/chromium/third_party/blink/renderer/core/html/html_embed_element.idl
index fc16063a060..73cd221d414 100644
--- a/chromium/third_party/blink/renderer/core/html/html_embed_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_embed_element.idl
@@ -20,10 +20,6 @@
// https://html.spec.whatwg.org/#the-embed-element
-// The `ScriptURLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
-
// TODO(yukishiino): HTMLEmbedElement should not have [OverrideBuiltins].
[
OverrideBuiltins,
diff --git a/chromium/third_party/blink/renderer/core/html/html_font_element.h b/chromium/third_party/blink/renderer/core/html/html_font_element.h
index 2599fc35e0b..65af4d4fbed 100644
--- a/chromium/third_party/blink/renderer/core/html/html_font_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_font_element.h
@@ -36,9 +36,9 @@ class HTMLFontElement final : public HTMLElement {
static bool CssValueFromFontSizeNumber(const String&, CSSValueID&);
- private:
explicit HTMLFontElement(Document&);
+ private:
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
const QualifiedName&,
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_element.cc b/chromium/third_party/blink/renderer/core/html/html_frame_element.cc
index dc1bdd98d4a..98d28bb8296 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_element.cc
@@ -39,10 +39,11 @@ inline HTMLFrameElement::HTMLFrameElement(Document& document)
DEFINE_NODE_FACTORY(HTMLFrameElement)
-const HashSet<AtomicString>& HTMLFrameElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLFrameElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
bool HTMLFrameElement::LayoutObjectIsNeeded(const ComputedStyle&) const {
@@ -92,7 +93,6 @@ ParsedFeaturePolicy HTMLFrameElement::ConstructContainerPolicy(
ParsedFeaturePolicyDeclaration allowlist;
allowlist.feature = mojom::FeaturePolicyFeature::kFullscreen;
allowlist.matches_all_origins = false;
- allowlist.disposition = mojom::FeaturePolicyDisposition::kEnforce;
container_policy.push_back(allowlist);
return container_policy;
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_element.h b/chromium/third_party/blink/renderer/core/html/html_frame_element.h
index 0b416f98a78..e57302d8a40 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_element.h
@@ -37,8 +37,10 @@ class CORE_EXPORT HTMLFrameElement final : public HTMLFrameElementBase {
public:
DECLARE_NODE_FACTORY(HTMLFrameElement);
+ explicit HTMLFrameElement(Document&);
+
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
bool HasFrameBorder() const { return frame_border_; }
@@ -52,8 +54,6 @@ class CORE_EXPORT HTMLFrameElement final : public HTMLFrameElementBase {
}
private:
- explicit HTMLFrameElement(Document&);
-
void AttachLayoutTree(AttachContext&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_element.idl b/chromium/third_party/blink/renderer/core/html/html_frame_element.idl
index 0950629ffa0..ede4af78c2a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_element.idl
@@ -20,9 +20,6 @@
// https://html.spec.whatwg.org/#htmlframeelement
-// The `URLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
[HTMLConstructor]
interface HTMLFrameElement : HTMLElement {
[CEReactions, Reflect] attribute DOMString name;
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_element_base.cc b/chromium/third_party/blink/renderer/core/html/html_frame_element_base.cc
index 466ad257e02..9124cd0a49d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_element_base.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_element_base.cc
@@ -63,7 +63,7 @@ bool HTMLFrameElementBase::IsURLAllowed() const {
// frame. NB: This check can be invoked without any JS on the stack for some
// parser operations. In such case, we use the origin of the frame element's
// containing document as the caller context.
- v8::Isolate* isolate = ToIsolate(&GetDocument());
+ v8::Isolate* isolate = GetDocument().GetIsolate();
LocalDOMWindow* accessing_window = isolate->InContext()
? CurrentDOMWindow(isolate)
: GetDocument().domWindow();
@@ -86,39 +86,8 @@ void HTMLFrameElementBase::OpenURL(bool replace_current_item) {
if (!parent_frame)
return;
- // Support for <frame src="javascript:string">
- KURL script_url;
KURL url = GetDocument().CompleteURL(url_);
- if (url.ProtocolIsJavaScript()) {
- // We'll set/execute |scriptURL| iff CSP allows us to execute inline
- // JavaScript. If CSP blocks inline JavaScript, then exit early if
- // we're trying to execute script in an existing document. If we're
- // executing JavaScript to create a new document (e.g.
- // '<iframe src="javascript:...">' then continue loading 'about:blank'
- // so that the frame is populated with something reasonable.
- if (ContentSecurityPolicy::ShouldBypassMainWorld(&GetDocument()) ||
- GetDocument().GetContentSecurityPolicy()->AllowJavaScriptURLs(
- this, url.GetString(), GetDocument().Url(),
- OrdinalNumber::First())) {
- script_url = url;
- } else {
- if (ContentFrame())
- return;
- }
-
- url = BlankURL();
- }
-
- if (!LoadOrRedirectSubframe(url, frame_name_, replace_current_item))
- return;
- if (!ContentFrame() || script_url.IsEmpty() ||
- !ContentFrame()->IsLocalFrame())
- return;
- if (ContentFrame()->Owner()->GetSandboxFlags() & kSandboxOrigin)
- return;
- ToLocalFrame(ContentFrame())
- ->GetScriptController()
- .ExecuteScriptIfJavaScriptURL(script_url, this);
+ LoadOrRedirectSubframe(url, frame_name_, replace_current_item);
}
void HTMLFrameElementBase::ParseAttribute(
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index ddfe3ce43c3..9eb9c7c7c9d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -20,7 +20,7 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
@@ -409,8 +409,6 @@ bool HTMLFrameOwnerElement::LoadOrRedirectSubframe(
if ((RuntimeEnabledFeatures::LazyFrameLoadingEnabled() ||
RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled()) &&
- GetDocument().GetSettings() &&
- GetDocument().GetSettings()->GetLazyLoadEnabled() &&
!lazy_load_frame_observer_ &&
// Only http:// or https:// URLs are eligible for lazy loading, excluding
// URLs like invalid or empty URLs, "about:blank", local file URLs, etc.
@@ -419,20 +417,19 @@ bool HTMLFrameOwnerElement::LoadOrRedirectSubframe(
(EqualIgnoringASCIICase(FastGetAttribute(html_names::kLazyloadAttr),
"on") ||
(should_lazy_load_children_ &&
- // If lazy loading is restricted to only Data Saver users, then avoid
- // lazy loading unless Data Saver is enabled, taking the Data Saver
- // holdback into consideration.
- (!RuntimeEnabledFeatures::
- RestrictLazyFrameLoadingToDataSaverEnabled() ||
- (!(GetDocument().GetSettings() &&
- GetDocument().GetSettings()->GetDataSaverHoldbackWebApi()) &&
- GetNetworkStateNotifier().SaveDataEnabled())) &&
// Disallow lazy loading by default if javascript in the embedding
// document would be able to access the contents of the frame, since in
// those cases deferring the frame could break the page. Note that this
// check does not take any possible redirects of |url| into account.
!GetDocument().GetSecurityOrigin()->CanAccess(
- SecurityOrigin::Create(url).get())))) {
+ SecurityOrigin::Create(url).get()))) &&
+ // If lazy loading is restricted to only Data Saver users, then avoid
+ // lazy loading unless Data Saver is enabled, taking the Data Saver
+ // holdback into consideration.
+ (!RuntimeEnabledFeatures::RestrictLazyFrameLoadingToDataSaverEnabled() ||
+ (!(GetDocument().GetSettings() &&
+ GetDocument().GetSettings()->GetDataSaverHoldbackWebApi()) &&
+ GetNetworkStateNotifier().SaveDataEnabled()))) {
// By default, avoid deferring subresources inside a lazily loaded frame.
// This will make it possible for subresources in hidden frames to load that
// will never be visible, as well as make it so that deferred frames that
@@ -446,7 +443,9 @@ bool HTMLFrameOwnerElement::LoadOrRedirectSubframe(
if (RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled())
lazy_load_frame_observer_->StartTrackingVisibilityMetrics();
- if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled()) {
+ if (RuntimeEnabledFeatures::LazyFrameLoadingEnabled() &&
+ GetDocument().GetSettings() &&
+ GetDocument().GetSettings()->GetLazyLoadEnabled()) {
lazy_load_frame_observer_->DeferLoadUntilNearViewport(request,
child_load_type);
return true;
@@ -488,7 +487,7 @@ void HTMLFrameOwnerElement::ParseAttribute(
}
}
-void HTMLFrameOwnerElement::Trace(blink::Visitor* visitor) {
+void HTMLFrameOwnerElement::Trace(Visitor* visitor) {
visitor->Trace(content_frame_);
visitor->Trace(embedded_content_view_);
visitor->Trace(lazy_load_frame_observer_);
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h
index e4f22d0cb0f..a7ae9db2d84 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h
@@ -127,7 +127,7 @@ class CORE_EXPORT HTMLFrameOwnerElement : public HTMLElement,
void ParseAttribute(const AttributeModificationParams&) override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
HTMLFrameOwnerElement(const QualifiedName& tag_name, Document&);
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc b/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc
index 3a3503d4fbb..31597f36100 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -205,6 +205,11 @@ void HTMLFrameSetElement::ParseAttribute(
GetDocument().SetWindowAttributeEventListener(
event_type_names::kLanguagechange,
CreateAttributeEventListener(GetDocument().GetFrame(), name, value));
+ } else if (RuntimeEnabledFeatures::PortalsEnabled() &&
+ name == kOnportalactivateAttr) {
+ GetDocument().SetWindowAttributeEventListener(
+ event_type_names::kPortalactivate,
+ CreateAttributeEventListener(GetDocument().GetFrame(), name, value));
} else {
HTMLElement::ParseAttribute(params);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_set_element.h b/chromium/third_party/blink/renderer/core/html/html_frame_set_element.h
index 4f955c7649d..15abb68bf2a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_set_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_set_element.h
@@ -37,6 +37,8 @@ class HTMLFrameSetElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLFrameSetElement);
+ explicit HTMLFrameSetElement(Document&);
+
bool HasFrameBorder() const { return frameborder_; }
bool NoResize() const { return noresize_; }
@@ -64,8 +66,6 @@ class HTMLFrameSetElement final : public HTMLElement {
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(orientationchange, kOrientationchange);
private:
- explicit HTMLFrameSetElement(Document&);
-
void ParseAttribute(const AttributeModificationParams&) override;
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/html/html_head_element.h b/chromium/third_party/blink/renderer/core/html/html_head_element.h
index c49048e0401..d363908be5a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_head_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_head_element.h
@@ -35,10 +35,9 @@ class CORE_EXPORT HTMLHeadElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLHeadElement);
- bool HasNonInBodyInsertionMode() const override { return true; }
-
- private:
explicit HTMLHeadElement(Document&);
+
+ bool HasNonInBodyInsertionMode() const override { return true; }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_hr_element.h b/chromium/third_party/blink/renderer/core/html/html_hr_element.h
index 09087f53858..6fae39b6f8b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_hr_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_hr_element.h
@@ -35,10 +35,11 @@ class HTMLHRElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLHRElement);
+ explicit HTMLHRElement(Document&);
+
bool CanContainRangeEndPoint() const override { return HasChildren(); }
private:
- explicit HTMLHRElement(Document&);
HTMLSelectElement* OwnerSelectElement() const;
bool IsPresentationAttribute(const QualifiedName&) const override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_html_element.h b/chromium/third_party/blink/renderer/core/html/html_html_element.h
index df92bb8c214..1ba669ce9ea 100644
--- a/chromium/third_party/blink/renderer/core/html/html_html_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_html_element.h
@@ -35,13 +35,13 @@ class CORE_EXPORT HTMLHtmlElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLHtmlElement);
+ explicit HTMLHtmlElement(Document&);
+
void InsertedByParser();
bool HasNonInBodyInsertionMode() const override { return true; }
private:
- explicit HTMLHtmlElement(Document&);
-
void MaybeSetupApplicationCache();
bool IsURLAttribute(const Attribute&) const override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc b/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc
index 2301338b30d..6ecacaf01f0 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -50,7 +50,7 @@ inline HTMLIFrameElement::HTMLIFrameElement(Document& document)
DEFINE_NODE_FACTORY(HTMLIFrameElement)
-void HTMLIFrameElement::Trace(blink::Visitor* visitor) {
+void HTMLIFrameElement::Trace(Visitor* visitor) {
visitor->Trace(sandbox_);
visitor->Trace(policy_);
HTMLFrameElementBase::Trace(visitor);
@@ -59,11 +59,12 @@ void HTMLIFrameElement::Trace(blink::Visitor* visitor) {
HTMLIFrameElement::~HTMLIFrameElement() = default;
-const HashSet<AtomicString>& HTMLIFrameElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLIFrameElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set,
- ({"src", "srcdoc"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedURL},
+ {"srcdoc", SpecificTrustedType::kTrustedHTML}}));
+ return attribute_map;
}
void HTMLIFrameElement::SetCollapsed(bool collapse) {
@@ -82,7 +83,7 @@ DOMTokenList* HTMLIFrameElement::sandbox() const {
return sandbox_.Get();
}
-Policy* HTMLIFrameElement::policy() {
+DOMFeaturePolicy* HTMLIFrameElement::featurePolicy() {
if (!policy_) {
policy_ = MakeGarbageCollected<IFramePolicy>(
&GetDocument(), ContainerPolicy(), GetOriginForFeaturePolicy());
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element.h b/chromium/third_party/blink/renderer/core/html/html_iframe_element.h
index ece6e8a827c..12460973576 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element.h
@@ -32,7 +32,7 @@
#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
-class Policy;
+class DOMFeaturePolicy;
class CORE_EXPORT HTMLIFrameElement final
: public HTMLFrameElementBase,
@@ -42,14 +42,17 @@ class CORE_EXPORT HTMLIFrameElement final
public:
DECLARE_NODE_FACTORY(HTMLIFrameElement);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
+
+ explicit HTMLIFrameElement(Document&);
~HTMLIFrameElement() override;
+
DOMTokenList* sandbox() const;
// Support JS introspection of frame policy (e.g. feature policy)
- Policy* policy();
+ DOMFeaturePolicy* featurePolicy();
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
ParsedFeaturePolicy ConstructContainerPolicy(
Vector<String>* /* messages */) const override;
@@ -59,8 +62,6 @@ class CORE_EXPORT HTMLIFrameElement final
}
private:
- explicit HTMLIFrameElement(Document&);
-
void SetCollapsed(bool) override;
void ParseAttribute(const AttributeModificationParams&) override;
@@ -91,8 +92,8 @@ class CORE_EXPORT HTMLIFrameElement final
bool allow_fullscreen_;
bool allow_payment_request_;
bool collapsed_by_client_;
- Member<HTMLIFrameElementSandbox> sandbox_;
- Member<Policy> policy_;
+ TraceWrapperMember<HTMLIFrameElementSandbox> sandbox_;
+ Member<DOMFeaturePolicy> policy_;
network::mojom::ReferrerPolicy referrer_policy_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element.idl b/chromium/third_party/blink/renderer/core/html/html_iframe_element.idl
index c45e0f752d8..7f5f9eae614 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element.idl
@@ -42,12 +42,11 @@ interface HTMLIFrameElement : HTMLElement {
[CEReactions, Reflect] attribute DOMString csp;
// Feature Policy
- // https://wicg.github.io/feature-policy/
[CEReactions, Reflect] attribute DOMString allow;
- // TODO(iclelland): add spec for JS exposure in the spec for Feature Policy.
- // Please refer to this doc for more details for now:
- // https://docs.google.com/a/chromium.org/document/d/1wvk3cXkblNnbkMcsKayseK-k0SMGiP9b9fQFgfpqQpc/edit?usp=sharing
- [OriginTrialEnabled=FeaturePolicyJavaScriptInterface] readonly attribute Policy policy;
+ // https://wicg.github.io/feature-policy/#the-policy-object
+ [OriginTrialEnabled=FeaturePolicyJavaScriptInterface] readonly attribute FeaturePolicy featurePolicy;
+
+ [RuntimeEnabled=LazyFrameLoading, CEReactions, Reflect, ReflectOnly=("on", "off", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString lazyLoad;
// obsolete members
// https://html.spec.whatwg.org/#HTMLIFrameElement-partial
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc b/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc
index 8603fa8bb1b..3108db1b543 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc
@@ -31,8 +31,9 @@ bool IsTokenSupported(const AtomicString& token) {
if (token == supported_token)
return true;
}
- if (token == "allow-downloads" &&
- RuntimeEnabledFeatures::BlockingDownloadsInSandboxEnabled()) {
+ if (token == "allow-downloads-without-user-activation" &&
+ RuntimeEnabledFeatures::
+ BlockingDownloadsInSandboxWithoutUserActivationEnabled()) {
return true;
}
return false;
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_element.cc b/chromium/third_party/blink/renderer/core/html/html_image_element.cc
index eb8a7357e23..c7e07815d09 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_image_element.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/forms/form_associated.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
+#include "third_party/blink/renderer/core/html/html_dimension.h"
#include "third_party/blink/renderer/core/html/html_image_fallback_helper.h"
#include "third_party/blink/renderer/core/html/html_picture_element.h"
#include "third_party/blink/renderer/core/html/html_source_element.h"
@@ -55,6 +56,7 @@
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/core/media_type_names.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/style/content_data.h"
@@ -84,7 +86,7 @@ class HTMLImageElement::ViewportChangeListener final
element_->NotifyViewportChanged();
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(element_);
MediaQueryListListener::Trace(visitor);
}
@@ -126,7 +128,7 @@ HTMLImageElement* HTMLImageElement::Create(Document& document,
HTMLImageElement::~HTMLImageElement() = default;
-void HTMLImageElement::Trace(blink::Visitor* visitor) {
+void HTMLImageElement::Trace(Visitor* visitor) {
visitor->Trace(image_loader_);
visitor->Trace(listener_);
visitor->Trace(form_);
@@ -134,10 +136,11 @@ void HTMLImageElement::Trace(blink::Visitor* visitor) {
HTMLElement::Trace(visitor);
}
-const HashSet<AtomicString>& HTMLImageElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLImageElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
void HTMLImageElement::NotifyViewportChanged() {
@@ -318,6 +321,12 @@ void HTMLImageElement::ParseAttribute(
EqualIgnoringASCIICase(params.new_value, "off") &&
!GetDocument().IsLazyLoadPolicyEnforced()) {
GetImageLoader().LoadDeferredImage(referrer_policy_);
+ } else if (name == kImportanceAttr &&
+ origin_trials::PriorityHintsEnabled(&GetDocument())) {
+ // We only need to keep track of usage here, as the communication of the
+ // |importance| attribute to the loading pipeline takes place in
+ // ImageLoader.
+ UseCounter::Count(GetDocument(), WebFeature::kPriorityHints);
} else {
HTMLElement::ParseAttribute(params);
}
@@ -682,7 +691,7 @@ bool HTMLImageElement::IsServerMap() const {
}
Image* HTMLImageElement::ImageContents() {
- if (!GetImageLoader().ImageComplete())
+ if (!GetImageLoader().ImageComplete() || !GetImageLoader().GetContent())
return nullptr;
return GetImageLoader().GetContent()->GetImage();
@@ -864,4 +873,31 @@ void HTMLImageElement::AssociateWith(HTMLFormElement* form) {
}
}
+// Minimum height or width of the image to start lazyloading.
+constexpr int kMinDimensionToLazyLoad = 10;
+
+bool HTMLImageElement::IsDimensionSmallAndAbsoluteForLazyLoad(
+ const String& attribute_value) {
+ HTMLDimension dimension;
+ return ParseDimensionValue(attribute_value, dimension) &&
+ dimension.IsAbsolute() && dimension.Value() <= kMinDimensionToLazyLoad;
+}
+
+bool HTMLImageElement::IsInlineStyleDimensionsSmall(
+ const CSSPropertyValueSet* property_set) {
+ if (!property_set)
+ return false;
+ const CSSValue* height = property_set->GetPropertyCSSValue(CSSPropertyHeight);
+ const CSSValue* width = property_set->GetPropertyCSSValue(CSSPropertyWidth);
+ if (!height || !height->IsPrimitiveValue() || !width ||
+ !width->IsPrimitiveValue())
+ return false;
+ const CSSPrimitiveValue* width_prim = ToCSSPrimitiveValue(width);
+ const CSSPrimitiveValue* height_prim = ToCSSPrimitiveValue(height);
+ return height_prim->IsPx() &&
+ (height_prim->GetDoubleValue() <= kMinDimensionToLazyLoad) &&
+ width_prim->IsPx() &&
+ (width_prim->GetDoubleValue() <= kMinDimensionToLazyLoad);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_element.h b/chromium/third_party/blink/renderer/core/html/html_image_element.h
index 63817bf8b70..d6f338bad91 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_image_element.h
@@ -60,7 +60,7 @@ class CORE_EXPORT HTMLImageElement final
class ViewportChangeListener;
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
static HTMLImageElement* Create(Document&);
static HTMLImageElement* Create(Document&, const CreateElementFlags);
@@ -72,7 +72,7 @@ class CORE_EXPORT HTMLImageElement final
explicit HTMLImageElement(Document&, bool created_by_parser = false);
~HTMLImageElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
unsigned width();
unsigned height();
@@ -166,6 +166,10 @@ class CORE_EXPORT HTMLImageElement final
return *visible_load_time_metrics_;
}
+ static bool IsDimensionSmallAndAbsoluteForLazyLoad(
+ const String& attribute_value);
+ static bool IsInlineStyleDimensionsSmall(const CSSPropertyValueSet*);
+
protected:
// Controls how an image element appears in the layout. See:
// https://html.spec.whatwg.org/multipage/embedded-content.html#image-request
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_element.idl b/chromium/third_party/blink/renderer/core/html/html_image_element.idl
index b752807f648..03d39e9e16d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_image_element.idl
@@ -41,9 +41,10 @@
readonly attribute DOMString currentSrc;
[CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
[CEReactions, Reflect, ReflectOnly=("async", "sync", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString decoding;
- [CEReactions, RuntimeEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
+ [CEReactions, MeasureAs=PriorityHints, OriginTrialEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
// https://github.com/ojanvafai/intrinsicsize-attribute/blob/master/README.md
[RuntimeEnabled=ExperimentalProductivityFeatures, CEReactions, Reflect] attribute DOMString intrinsicSize;
+ [RuntimeEnabled=LazyImageLoading, CEReactions, Reflect, ReflectOnly=("on", "off", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString lazyLoad;
// obsolete members
// https://html.spec.whatwg.org/#HTMLImageElement-partial
@@ -61,5 +62,5 @@
[MeasureAs=HTMLImageElementX] readonly attribute long x;
[MeasureAs=HTMLImageElementY] readonly attribute long y;
- [CallWith=ScriptState, RaisesException] Promise decode();
+ [CallWith=ScriptState, RaisesException] Promise<void> decode();
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_element_test.cc b/chromium/third_party/blink/renderer/core/html/html_image_element_test.cc
index 1e3ae6781d1..a84a3d1d6a3 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_image_element_test.cc
@@ -12,15 +12,20 @@
namespace blink {
-const int kViewportWidth = 500;
-const int kViewportHeight = 600;
class HTMLImageElementTest : public PageTestBase {
protected:
+ static constexpr int kViewportWidth = 500;
+ static constexpr int kViewportHeight = 600;
+
void SetUp() override {
PageTestBase::SetUp(IntSize(kViewportWidth, kViewportHeight));
}
};
+// Instantiate class constants. Not needed after C++17.
+constexpr int HTMLImageElementTest::kViewportWidth;
+constexpr int HTMLImageElementTest::kViewportHeight;
+
TEST_F(HTMLImageElementTest, width) {
auto* image = HTMLImageElement::Create(GetDocument());
image->setAttribute(html_names::kWidthAttr, "400");
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_fallback_helper.cc b/chromium/third_party/blink/renderer/core/html/html_image_fallback_helper.cc
index 8f1f32cc16d..ac14855c989 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_fallback_helper.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_image_fallback_helper.cc
@@ -36,8 +36,8 @@ static bool ElementRepresentsNothing(const Element& element) {
}
static bool ImageSmallerThanAltImage(int pixels_for_alt_image,
- const Length width,
- const Length height) {
+ const Length& width,
+ const Length& height) {
// We don't have a layout tree so can't compute the size of an image
// relative dimensions - so we just assume we should display the alt image.
if (!width.IsFixed() && !height.IsFixed())
diff --git a/chromium/third_party/blink/renderer/core/html/html_li_element.h b/chromium/third_party/blink/renderer/core/html/html_li_element.h
index 1d66681b599..c2c06325f87 100644
--- a/chromium/third_party/blink/renderer/core/html/html_li_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_li_element.h
@@ -35,9 +35,9 @@ class HTMLLIElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLLIElement);
- private:
explicit HTMLLIElement(Document&);
+ private:
void ParseAttribute(const AttributeModificationParams&) override;
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/html/html_link_element.cc b/chromium/third_party/blink/renderer/core/html/html_link_element.cc
index 8b8de076175..1693c67ee02 100644
--- a/chromium/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_link_element.cc
@@ -41,9 +41,11 @@
#include "third_party/blink/renderer/core/html/link_manifest.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/renderer/core/loader/network_hints_interface.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -65,9 +67,10 @@ HTMLLinkElement* HTMLLinkElement::Create(Document& document,
HTMLLinkElement::~HTMLLinkElement() = default;
-const HashSet<AtomicString>& HTMLLinkElement::GetCheckedAttributeNames() const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"href"}));
- return attribute_set;
+const AttrNameToTrustedType& HTMLLinkElement::GetCheckedAttributeTypes() const {
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"href", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
void HTMLLinkElement::ParseAttribute(
@@ -115,7 +118,8 @@ void HTMLLinkElement::ParseAttribute(
} else if (name == kIntegrityAttr) {
integrity_ = value;
} else if (name == kImportanceAttr &&
- RuntimeEnabledFeatures::PriorityHintsEnabled()) {
+ origin_trials::PriorityHintsEnabled(&GetDocument())) {
+ UseCounter::Count(GetDocument(), WebFeature::kPriorityHints);
importance_ = value;
} else if (name == kDisabledAttr) {
UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled);
@@ -171,7 +175,7 @@ LinkResource* HTMLLinkElement::LinkResourceToProcess() {
if (!link_) {
if (rel_attribute_.IsImport() &&
- RuntimeEnabledFeatures::HTMLImportsEnabled()) {
+ origin_trials::HTMLImportsEnabled(&GetDocument())) {
link_ = LinkImport::Create(this);
} else if (rel_attribute_.IsManifest()) {
link_ = LinkManifest::Create(this);
@@ -389,7 +393,7 @@ DOMTokenList* HTMLLinkElement::sizes() const {
return sizes_.Get();
}
-void HTMLLinkElement::Trace(blink::Visitor* visitor) {
+void HTMLLinkElement::Trace(Visitor* visitor) {
visitor->Trace(link_);
visitor->Trace(sizes_);
visitor->Trace(link_loader_);
diff --git a/chromium/third_party/blink/renderer/core/html/html_link_element.h b/chromium/third_party/blink/renderer/core/html/html_link_element.h
index 89f692587bc..af3537f1e50 100644
--- a/chromium/third_party/blink/renderer/core/html/html_link_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_link_element.h
@@ -35,7 +35,6 @@
#include "third_party/blink/renderer/core/html/link_resource.h"
#include "third_party/blink/renderer/core/html/link_style.h"
#include "third_party/blink/renderer/core/html/rel_list.h"
-#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/renderer/core/loader/link_loader_client.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
@@ -44,6 +43,7 @@ namespace blink {
class KURL;
class LinkImport;
+class LinkLoader;
struct LinkLoadParameters;
class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
@@ -58,7 +58,7 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
~HTMLLinkElement() override;
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
KURL Href() const;
const AtomicString& Rel() const;
@@ -122,7 +122,7 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
}
bool IsCreatedByParser() const { return created_by_parser_; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
LinkStyle* GetLinkStyle() const;
@@ -168,7 +168,7 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
String integrity_;
String importance_;
network::mojom::ReferrerPolicy referrer_policy_;
- Member<DOMTokenList> sizes_;
+ TraceWrapperMember<DOMTokenList> sizes_;
Vector<IntSize> icon_sizes_;
TraceWrapperMember<RelList> rel_list_;
LinkRelAttribute rel_attribute_;
diff --git a/chromium/third_party/blink/renderer/core/html/html_link_element.idl b/chromium/third_party/blink/renderer/core/html/html_link_element.idl
index 933f8083b59..1524f8b74d0 100644
--- a/chromium/third_party/blink/renderer/core/html/html_link_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_link_element.idl
@@ -35,7 +35,7 @@ interface HTMLLinkElement : HTMLElement {
[Reflect, ReflectOnly=("script","style","image","video", "audio", "track", "font", "fetch")] attribute DOMString as;
[CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
[PutForwards=value] readonly attribute DOMTokenList sizes;
- [CEReactions, RuntimeEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
+ [CEReactions, MeasureAs=PriorityHints, OriginTrialEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
[RuntimeEnabled=PreloadImageSrcSet, CEReactions, Reflect] attribute DOMString imageSrcset;
[RuntimeEnabled=PreloadImageSrcSet, CEReactions, Reflect] attribute DOMString imageSizes;
@@ -51,7 +51,7 @@ interface HTMLLinkElement : HTMLElement {
// HTML Imports
// https://w3c.github.io/webcomponents/spec/imports/#interface-import
- [RuntimeEnabled=HTMLImports] readonly attribute Document? import;
+ [OriginTrialEnabled=HTMLImports] readonly attribute Document? import;
// Subresource Integrity
// https://w3c.github.io/webappsec-subresource-integrity/#HTMLLinkElement
diff --git a/chromium/third_party/blink/renderer/core/html/html_map_element.h b/chromium/third_party/blink/renderer/core/html/html_map_element.h
index c5bce072aa8..f92088f8ef5 100644
--- a/chromium/third_party/blink/renderer/core/html/html_map_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_map_element.h
@@ -35,6 +35,8 @@ class CORE_EXPORT HTMLMapElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLMapElement);
+
+ explicit HTMLMapElement(Document&);
~HTMLMapElement() override;
const AtomicString& GetName() const { return name_; }
@@ -46,8 +48,6 @@ class CORE_EXPORT HTMLMapElement final : public HTMLElement {
HTMLCollection* areas();
private:
- explicit HTMLMapElement(Document&);
-
void ParseAttribute(const AttributeModificationParams&) override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_marquee_element.cc b/chromium/third_party/blink/renderer/core/html/html_marquee_element.cc
index a1edeaf400f..4564dc1d02b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_marquee_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_marquee_element.cc
@@ -24,7 +24,6 @@
#include <cstdlib>
-#include "base/macros.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_html_marquee_element.h"
#include "third_party/blink/renderer/core/animation/document_timeline.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect.h"
@@ -37,7 +36,7 @@
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_style_declaration.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -92,7 +91,7 @@ class HTMLMarqueeElement::RequestAnimationFrameCallback final
marquee_->ContinueAnimation();
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(marquee_);
FrameRequestCallbackCollection::FrameCallback::Trace(visitor);
}
@@ -103,29 +102,22 @@ class HTMLMarqueeElement::RequestAnimationFrameCallback final
DISALLOW_COPY_AND_ASSIGN(RequestAnimationFrameCallback);
};
-class HTMLMarqueeElement::AnimationFinished final : public EventListener {
+class HTMLMarqueeElement::AnimationFinished final : public NativeEventListener {
public:
- explicit AnimationFinished(HTMLMarqueeElement* marquee)
- : EventListener(kCPPEventListenerType), marquee_(marquee) {}
-
- bool operator==(const EventListener& that) const override {
- return this == &that;
- }
+ explicit AnimationFinished(HTMLMarqueeElement* marquee) : marquee_(marquee) {}
void Invoke(ExecutionContext*, Event*) override {
++marquee_->loop_count_;
marquee_->start();
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(marquee_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
}
private:
Member<HTMLMarqueeElement> marquee_;
-
- DISALLOW_COPY_AND_ASSIGN(AnimationFinished);
};
Node::InsertionNotificationRequest HTMLMarqueeElement::InsertedInto(
@@ -496,7 +488,7 @@ AtomicString HTMLMarqueeElement::CreateTransform(double value) const {
String::NumberToStringECMAScript(value) + "px)";
}
-void HTMLMarqueeElement::Trace(blink::Visitor* visitor) {
+void HTMLMarqueeElement::Trace(Visitor* visitor) {
visitor->Trace(mover_);
visitor->Trace(player_);
HTMLElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/html_marquee_element.h b/chromium/third_party/blink/renderer/core/html/html_marquee_element.h
index 903870d6804..d9cb385576a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_marquee_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_marquee_element.h
@@ -33,7 +33,7 @@ class HTMLMarqueeElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
public:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
static HTMLMarqueeElement* Create(Document&);
diff --git a/chromium/third_party/blink/renderer/core/html/html_menu_element.h b/chromium/third_party/blink/renderer/core/html/html_menu_element.h
index 773a63af198..259856a92fc 100644
--- a/chromium/third_party/blink/renderer/core/html/html_menu_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_menu_element.h
@@ -33,7 +33,6 @@ class HTMLMenuElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLMenuElement);
- private:
explicit HTMLMenuElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_meta_element.h b/chromium/third_party/blink/renderer/core/html/html_meta_element.h
index 24210e5e1a3..c81b945b627 100644
--- a/chromium/third_party/blink/renderer/core/html/html_meta_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_meta_element.h
@@ -51,6 +51,8 @@ class CORE_EXPORT HTMLMetaElement final : public HTMLElement {
Document*,
bool viewport_meta_zero_values_quirk);
+ explicit HTMLMetaElement(Document&);
+
// Encoding computed from processing the http-equiv, charset and content
// attributes.
WTF::TextEncoding ComputeEncoding() const;
@@ -60,8 +62,6 @@ class CORE_EXPORT HTMLMetaElement final : public HTMLElement {
const AtomicString& GetName() const;
private:
- explicit HTMLMetaElement(Document&);
-
static void ProcessViewportKeyValuePair(Document*,
bool report_warnings,
const String& key,
diff --git a/chromium/third_party/blink/renderer/core/html/html_meter_element.cc b/chromium/third_party/blink/renderer/core/html/html_meter_element.cc
index f643e77030b..a178db4b669 100644
--- a/chromium/third_party/blink/renderer/core/html/html_meter_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_meter_element.cc
@@ -35,7 +35,7 @@ namespace blink {
using namespace html_names;
HTMLMeterElement::HTMLMeterElement(Document& document)
- : LabelableElement(kMeterTag, document) {
+ : HTMLElement(kMeterTag, document) {
UseCounter::Count(document, WebFeature::kMeterElement);
}
@@ -60,7 +60,7 @@ LayoutObject* HTMLMeterElement::CreateLayoutObject(const ComputedStyle& style) {
default:
break;
}
- return LabelableElement::CreateLayoutObject(style);
+ return HTMLElement::CreateLayoutObject(style);
}
void HTMLMeterElement::ParseAttribute(
@@ -70,7 +70,7 @@ void HTMLMeterElement::ParseAttribute(
name == kLowAttr || name == kHighAttr || name == kOptimumAttr)
DidElementStateChange();
else
- LabelableElement::ParseAttribute(params);
+ HTMLElement::ParseAttribute(params);
}
double HTMLMeterElement::value() const {
@@ -223,9 +223,9 @@ bool HTMLMeterElement::CanContainRangeEndPoint() const {
return GetComputedStyle() && !GetComputedStyle()->HasAppearance();
}
-void HTMLMeterElement::Trace(blink::Visitor* visitor) {
+void HTMLMeterElement::Trace(Visitor* visitor) {
visitor->Trace(value_);
- LabelableElement::Trace(visitor);
+ HTMLElement::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_meter_element.h b/chromium/third_party/blink/renderer/core/html/html_meter_element.h
index e1917faedbb..fa329c1f82c 100644
--- a/chromium/third_party/blink/renderer/core/html/html_meter_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_meter_element.h
@@ -22,13 +22,13 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_METER_ELEMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
class HTMLDivElement;
-class CORE_EXPORT HTMLMeterElement final : public LabelableElement {
+class CORE_EXPORT HTMLMeterElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -65,14 +65,14 @@ class CORE_EXPORT HTMLMeterElement final : public LabelableElement {
bool CanContainRangeEndPoint() const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
~HTMLMeterElement() override;
bool AreAuthorShadowsAllowed() const override { return false; }
- bool SupportLabels() const override { return true; }
+ bool IsLabelable() const override { return true; }
bool ShouldForceLegacyLayout() const final { return true; }
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_no_embed_element.h b/chromium/third_party/blink/renderer/core/html/html_no_embed_element.h
index ded37b137a3..63dc0daf5a7 100644
--- a/chromium/third_party/blink/renderer/core/html/html_no_embed_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_no_embed_element.h
@@ -41,9 +41,9 @@ class HTMLNoEmbedElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLNoEmbedElement);
- private:
explicit HTMLNoEmbedElement(Document&);
+ private:
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_no_script_element.h b/chromium/third_party/blink/renderer/core/html/html_no_script_element.h
index 74fdec2e46a..594b5cec410 100644
--- a/chromium/third_party/blink/renderer/core/html/html_no_script_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_no_script_element.h
@@ -41,9 +41,9 @@ class HTMLNoScriptElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLNoScriptElement);
- private:
explicit HTMLNoScriptElement(Document&);
+ private:
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_object_element.cc b/chromium/third_party/blink/renderer/core/html/html_object_element.cc
index 1e7cb2ec9db..09ba3a516a7 100644
--- a/chromium/third_party/blink/renderer/core/html/html_object_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_object_element.cc
@@ -64,16 +64,17 @@ HTMLObjectElement* HTMLObjectElement::Create(Document& document,
return element;
}
-void HTMLObjectElement::Trace(blink::Visitor* visitor) {
+void HTMLObjectElement::Trace(Visitor* visitor) {
ListedElement::Trace(visitor);
HTMLPlugInElement::Trace(visitor);
}
-const HashSet<AtomicString>& HTMLObjectElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLObjectElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set,
- ({"data", "codebase"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"data", SpecificTrustedType::kTrustedScriptURL},
+ {"codebase", SpecificTrustedType::kTrustedScriptURL}}));
+ return attribute_map;
}
LayoutEmbeddedContent* HTMLObjectElement::ExistingLayoutEmbeddedContent()
diff --git a/chromium/third_party/blink/renderer/core/html/html_object_element.h b/chromium/third_party/blink/renderer/core/html/html_object_element.h
index ae5b59d3d50..a6da0c84c6d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_object_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_object_element.h
@@ -48,10 +48,10 @@ class CORE_EXPORT HTMLObjectElement final : public HTMLPlugInElement,
HTMLObjectElement(Document&, const CreateElementFlags);
~HTMLObjectElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
const String& ClassId() const { return class_id_; }
diff --git a/chromium/third_party/blink/renderer/core/html/html_object_element.idl b/chromium/third_party/blink/renderer/core/html/html_object_element.idl
index bd6d6db78a0..305df10f3e7 100644
--- a/chromium/third_party/blink/renderer/core/html/html_object_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_object_element.idl
@@ -26,7 +26,7 @@
ActiveScriptWrappable,
HTMLConstructor
] interface HTMLObjectElement : HTMLElement {
- [CEReactions, Reflect, URL, RaisesException=Setter] attribute URLString data;
+ [CEReactions, Reflect, URL, RaisesException=Setter] attribute ScriptURLString data;
[CEReactions, Reflect] attribute DOMString type;
// TODO(foolip): attribute boolean typeMustMatch;
[CEReactions, Reflect] attribute DOMString name;
@@ -55,7 +55,7 @@
[CEReactions, Reflect] attribute unsigned long hspace;
[CEReactions, Reflect] attribute DOMString standby;
[CEReactions, Reflect] attribute unsigned long vspace;
- [CEReactions, Reflect, URL, RaisesException=Setter] attribute URLString codeBase;
+ [CEReactions, Reflect, URL, RaisesException=Setter] attribute ScriptURLString codeBase;
[CEReactions, Reflect] attribute DOMString codeType;
[CEReactions, Reflect] attribute [TreatNullAs=EmptyString] DOMString border;
diff --git a/chromium/third_party/blink/renderer/core/html/html_olist_element.h b/chromium/third_party/blink/renderer/core/html/html_olist_element.h
index 3495d986356..96ef8d15b6c 100644
--- a/chromium/third_party/blink/renderer/core/html/html_olist_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_olist_element.h
@@ -33,6 +33,8 @@ class HTMLOListElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLOListElement);
+ explicit HTMLOListElement(Document&);
+
int StartConsideringItemCount() const {
return has_explicit_start_ ? start_ : (is_reversed_ ? ItemCount() : 1);
}
@@ -44,8 +46,6 @@ class HTMLOListElement final : public HTMLElement {
void ItemCountChanged() { should_recalculate_item_count_ = true; }
private:
- explicit HTMLOListElement(Document&);
-
void UpdateItemValues();
unsigned ItemCount() const {
diff --git a/chromium/third_party/blink/renderer/core/html/html_paragraph_element.h b/chromium/third_party/blink/renderer/core/html/html_paragraph_element.h
index a896cfb3794..f43f822f2d4 100644
--- a/chromium/third_party/blink/renderer/core/html/html_paragraph_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_paragraph_element.h
@@ -33,9 +33,9 @@ class CORE_EXPORT HTMLParagraphElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLParagraphElement);
- private:
explicit HTMLParagraphElement(Document&);
+ private:
void CollectStyleForPresentationAttribute(
const QualifiedName&,
const AtomicString&,
diff --git a/chromium/third_party/blink/renderer/core/html/html_param_element.h b/chromium/third_party/blink/renderer/core/html/html_param_element.h
index bcf86d39a99..98c853f530e 100644
--- a/chromium/third_party/blink/renderer/core/html/html_param_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_param_element.h
@@ -33,14 +33,14 @@ class HTMLParamElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLParamElement);
+ explicit HTMLParamElement(Document&);
+
const AtomicString& GetName() const;
const AtomicString& Value() const;
static bool IsURLParameter(const String&);
private:
- explicit HTMLParamElement(Document&);
-
bool IsURLAttribute(const Attribute&) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_picture_element.h b/chromium/third_party/blink/renderer/core/html/html_picture_element.h
index 0127628cb29..9b58e2944d0 100644
--- a/chromium/third_party/blink/renderer/core/html/html_picture_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_picture_element.h
@@ -15,13 +15,12 @@ class HTMLPictureElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLPictureElement);
+ explicit HTMLPictureElement(Document&);
+
void SourceOrMediaChanged();
void RemoveListenerFromSourceChildren();
void AddListenerToSourceChildren();
- protected:
- explicit HTMLPictureElement(Document&);
-
private:
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc b/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc
index 301d01dfad2..788ae560c85 100644
--- a/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -129,7 +129,7 @@ HTMLPlugInElement::~HTMLPlugInElement() {
DCHECK(!is_delaying_load_event_);
}
-void HTMLPlugInElement::Trace(blink::Visitor* visitor) {
+void HTMLPlugInElement::Trace(Visitor* visitor) {
visitor->Trace(image_loader_);
visitor->Trace(persisted_plugin_);
HTMLFrameOwnerElement::Trace(visitor);
@@ -189,6 +189,18 @@ bool HTMLPlugInElement::RequestObjectInternal(
ObjectContentType object_type = GetObjectContentType();
if (object_type == ObjectContentType::kFrame ||
object_type == ObjectContentType::kImage || handled_externally_) {
+ if (ContentFrame() && ContentFrame()->IsRemoteFrame()) {
+ // During lazy reattaching, the plugin element loses EmbeddedContentView.
+ // Since the ContentFrame() is not torn down the options here are to
+ // either re-create a new RemoteFrameView or reuse the old one. The former
+ // approach requires CommitNavigation for OOPF to be sent back here in
+ // the parent process. It is easier to just reuse the current FrameView
+ // instead until plugin element issue are properly resolved (for context
+ // see https://crbug.com/781880).
+ DCHECK(!OwnedEmbeddedContentView());
+ SetEmbeddedContentView(ContentFrame()->View());
+ DCHECK(OwnedEmbeddedContentView());
+ }
// If the plugin element already contains a subframe,
// loadOrRedirectSubframe will re-use it. Otherwise, it will create a
// new frame and set it as the LayoutEmbeddedContent's EmbeddedContentView,
@@ -307,7 +319,6 @@ ParsedFeaturePolicy HTMLPlugInElement::ConstructContainerPolicy(
ParsedFeaturePolicyDeclaration allowlist;
allowlist.feature = mojom::FeaturePolicyFeature::kFullscreen;
allowlist.matches_all_origins = false;
- allowlist.disposition = mojom::FeaturePolicyDisposition::kEnforce;
container_policy.push_back(allowlist);
return container_policy;
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_plugin_element.h b/chromium/third_party/blink/renderer/core/html/html_plugin_element.h
index c18b316b963..dbd52be35b6 100644
--- a/chromium/third_party/blink/renderer/core/html/html_plugin_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_plugin_element.h
@@ -67,7 +67,7 @@ class CORE_EXPORT HTMLPlugInElement
public:
~HTMLPlugInElement() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
bool IsPlugin() const final { return true; }
diff --git a/chromium/third_party/blink/renderer/core/html/html_progress_element.cc b/chromium/third_party/blink/renderer/core/html/html_progress_element.cc
index ce39f8a147b..d774d163f02 100644
--- a/chromium/third_party/blink/renderer/core/html/html_progress_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_progress_element.cc
@@ -36,7 +36,7 @@ const double HTMLProgressElement::kIndeterminatePosition = -1;
const double HTMLProgressElement::kInvalidPosition = -2;
HTMLProgressElement::HTMLProgressElement(Document& document)
- : LabelableElement(kProgressTag, document), value_(nullptr) {
+ : HTMLElement(kProgressTag, document), value_(nullptr) {
UseCounter::Count(document, WebFeature::kProgressElement);
}
@@ -76,12 +76,12 @@ void HTMLProgressElement::ParseAttribute(
} else if (params.name == kMaxAttr) {
DidElementStateChange();
} else {
- LabelableElement::ParseAttribute(params);
+ HTMLElement::ParseAttribute(params);
}
}
void HTMLProgressElement::AttachLayoutTree(AttachContext& context) {
- LabelableElement::AttachLayoutTree(context);
+ HTMLElement::AttachLayoutTree(context);
if (LayoutProgress* layout_progress = GetLayoutProgress())
layout_progress->UpdateFromElement();
}
@@ -151,9 +151,9 @@ bool HTMLProgressElement::ShouldAppearIndeterminate() const {
return !IsDeterminate();
}
-void HTMLProgressElement::Trace(blink::Visitor* visitor) {
+void HTMLProgressElement::Trace(Visitor* visitor) {
visitor->Trace(value_);
- LabelableElement::Trace(visitor);
+ HTMLElement::Trace(visitor);
}
void HTMLProgressElement::SetValueWidthPercentage(double width) const {
diff --git a/chromium/third_party/blink/renderer/core/html/html_progress_element.h b/chromium/third_party/blink/renderer/core/html/html_progress_element.h
index cf75eea1e17..5deaca0a3e3 100644
--- a/chromium/third_party/blink/renderer/core/html/html_progress_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_progress_element.h
@@ -22,13 +22,13 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_PROGRESS_ELEMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
class LayoutProgress;
-class CORE_EXPORT HTMLProgressElement final : public LabelableElement {
+class CORE_EXPORT HTMLProgressElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -49,14 +49,14 @@ class CORE_EXPORT HTMLProgressElement final : public LabelableElement {
bool CanContainRangeEndPoint() const override { return false; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
~HTMLProgressElement() override;
bool AreAuthorShadowsAllowed() const override { return false; }
bool ShouldAppearIndeterminate() const override;
- bool SupportLabels() const override { return true; }
+ bool IsLabelable() const override { return true; }
bool ShouldForceLegacyLayout() const final { return true; }
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_rt_element.h b/chromium/third_party/blink/renderer/core/html/html_rt_element.h
index 37364e63295..900b53148e9 100644
--- a/chromium/third_party/blink/renderer/core/html/html_rt_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_rt_element.h
@@ -15,9 +15,9 @@ class HTMLRTElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLRTElement);
- private:
explicit HTMLRTElement(Document&);
+ private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_ruby_element.h b/chromium/third_party/blink/renderer/core/html/html_ruby_element.h
index f0cad9ffdcf..896257274f0 100644
--- a/chromium/third_party/blink/renderer/core/html/html_ruby_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_ruby_element.h
@@ -15,9 +15,9 @@ class HTMLRubyElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLRubyElement);
- private:
explicit HTMLRubyElement(Document&);
+ private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
bool ShouldForceLegacyLayout() const final { return true; }
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_script_element.cc b/chromium/third_party/blink/renderer/core/html/html_script_element.cc
index 35f2ca54bf3..d763efa4673 100644
--- a/chromium/third_party/blink/renderer/core/html/html_script_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_script_element.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/script/script_loader.h"
#include "third_party/blink/renderer/core/script/script_runner.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
@@ -55,10 +56,11 @@ HTMLScriptElement* HTMLScriptElement::Create(Document& document,
return MakeGarbageCollected<HTMLScriptElement>(document, flags);
}
-const HashSet<AtomicString>& HTMLScriptElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLScriptElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src", "text"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedScriptURL}}));
+ return attribute_map;
}
bool HTMLScriptElement::IsURLAttribute(const Attribute& attribute) const {
@@ -92,6 +94,12 @@ void HTMLScriptElement::ParseAttribute(
LogUpdateAttributeIfIsolatedWorldAndInDocument("script", params);
} else if (params.name == kAsyncAttr) {
loader_->HandleAsyncAttribute();
+ } else if (params.name == kImportanceAttr &&
+ origin_trials::PriorityHintsEnabled(&GetDocument())) {
+ // The only thing we need to do for the the importance attribute/Priority
+ // Hints is count usage upon parsing. Processing the value happens when the
+ // element loads.
+ UseCounter::Count(GetDocument(), WebFeature::kPriorityHints);
} else {
HTMLElement::ParseAttribute(params);
}
@@ -200,6 +208,10 @@ String HTMLScriptElement::ReferrerPolicyAttributeValue() const {
return getAttribute(kReferrerpolicyAttr);
}
+String HTMLScriptElement::ImportanceAttributeValue() const {
+ return getAttribute(kImportanceAttr);
+}
+
String HTMLScriptElement::TextFromChildren() {
return Element::TextFromChildren();
}
@@ -265,7 +277,7 @@ Element* HTMLScriptElement::CloneWithoutAttributesAndChildren(
return factory.CreateElement(TagQName(), flags, IsValue());
}
-void HTMLScriptElement::Trace(blink::Visitor* visitor) {
+void HTMLScriptElement::Trace(Visitor* visitor) {
visitor->Trace(loader_);
HTMLElement::Trace(visitor);
ScriptElementBase::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/html_script_element.h b/chromium/third_party/blink/renderer/core/html/html_script_element.h
index 98418db8aea..7ccb77f4664 100644
--- a/chromium/third_party/blink/renderer/core/html/html_script_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_script_element.h
@@ -47,7 +47,7 @@ class CORE_EXPORT HTMLScriptElement final : public HTMLElement,
HTMLScriptElement(Document&, const CreateElementFlags);
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
void text(StringOrTrustedScript& result);
void setText(const StringOrTrustedScript&, ExceptionState&);
@@ -64,7 +64,7 @@ class CORE_EXPORT HTMLScriptElement final : public HTMLElement,
bool IsScriptElement() const override { return true; }
Document& GetDocument() const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void ParseAttribute(const AttributeModificationParams&) override;
@@ -88,6 +88,7 @@ class CORE_EXPORT HTMLScriptElement final : public HTMLElement,
String CrossOriginAttributeValue() const override;
String IntegrityAttributeValue() const override;
String ReferrerPolicyAttributeValue() const override;
+ String ImportanceAttributeValue() const override;
String TextFromChildren() override;
bool AsyncAttributeValue() const override;
bool DeferAttributeValue() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_script_element.idl b/chromium/third_party/blink/renderer/core/html/html_script_element.idl
index 6c9a17751e3..c1bace7b0fc 100644
--- a/chromium/third_party/blink/renderer/core/html/html_script_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_script_element.idl
@@ -29,6 +29,7 @@ interface HTMLScriptElement : HTMLElement {
[CEReactions, Reflect, ReflectOnly=("anonymous","use-credentials"), ReflectEmpty="anonymous", ReflectInvalid="anonymous"] attribute DOMString? crossOrigin;
[CEReactions, RaisesException=Setter] attribute ScriptString text;
[CEReactions, Reflect, ReflectOnly=("", "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "strict-origin", "origin-when-cross-origin", "strict-origin-when-cross-origin", "unsafe-url"), ReflectEmpty="", ReflectInvalid=""] attribute DOMString? referrerPolicy;
+ [CEReactions, MeasureAs=PriorityHints, OriginTrialEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
// obsolete members
// https://html.spec.whatwg.org/#HTMLScriptElement-partial
diff --git a/chromium/third_party/blink/renderer/core/html/html_shadow_element.h b/chromium/third_party/blink/renderer/core/html/html_shadow_element.h
index 9d989489326..2950d15e066 100644
--- a/chromium/third_party/blink/renderer/core/html/html_shadow_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_shadow_element.h
@@ -41,10 +41,9 @@ class HTMLShadowElement final : public V0InsertionPoint {
public:
DECLARE_NODE_FACTORY(HTMLShadowElement);
- ~HTMLShadowElement() override;
- private:
explicit HTMLShadowElement(Document&);
+ ~HTMLShadowElement() override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_slot_element.cc b/chromium/third_party/blink/renderer/core/html/html_slot_element.cc
index 7a9df981b0d..17abe79b148 100644
--- a/chromium/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -185,11 +185,15 @@ void HTMLSlotElement::assign(HeapVector<Member<Node>> nodes) {
void HTMLSlotElement::AppendAssignedNode(Node& host_child) {
DCHECK(host_child.IsSlotable());
+ if (!RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled())
+ assigned_nodes_index_.insert(&host_child, assigned_nodes_.size());
assigned_nodes_.push_back(&host_child);
}
void HTMLSlotElement::ClearAssignedNodes() {
assigned_nodes_.clear();
+ if (!RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled())
+ assigned_nodes_index_.clear();
}
void HTMLSlotElement::ClearAssignedNodesAndFlatTreeChildren() {
@@ -239,6 +243,32 @@ void HTMLSlotElement::DispatchSlotChangeEvent() {
DispatchScopedEvent(*event);
}
+Node* HTMLSlotElement::AssignedNodeNextTo(const Node& node) const {
+ DCHECK(!RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled());
+ DCHECK(SupportsAssignment());
+ ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
+
+ auto it = assigned_nodes_index_.find(&node);
+ DCHECK(it != assigned_nodes_index_.end());
+ unsigned index = it->value;
+ if (index + 1 == assigned_nodes_.size())
+ return nullptr;
+ return assigned_nodes_[index + 1].Get();
+}
+
+Node* HTMLSlotElement::AssignedNodePreviousTo(const Node& node) const {
+ DCHECK(!RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled());
+ DCHECK(SupportsAssignment());
+ ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
+
+ auto it = assigned_nodes_index_.find(&node);
+ DCHECK(it != assigned_nodes_index_.end());
+ unsigned index = it->value;
+ if (index == 0)
+ return nullptr;
+ return assigned_nodes_[index - 1].Get();
+}
+
AtomicString HTMLSlotElement::GetName() const {
return NormalizeSlotName(FastGetAttribute(kNameAttr));
}
@@ -549,8 +579,9 @@ int HTMLSlotElement::tabIndex() const {
return Element::tabIndex();
}
-void HTMLSlotElement::Trace(blink::Visitor* visitor) {
+void HTMLSlotElement::Trace(Visitor* visitor) {
visitor->Trace(assigned_nodes_);
+ visitor->Trace(assigned_nodes_index_);
visitor->Trace(flat_tree_children_);
visitor->Trace(assigned_nodes_candidates_);
HTMLElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/html_slot_element.h b/chromium/third_party/blink/renderer/core/html/html_slot_element.h
index 4e127e195c6..bec406ad9ed 100644
--- a/chromium/third_party/blink/renderer/core/html/html_slot_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_slot_element.h
@@ -64,13 +64,18 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
return nodes.IsEmpty() ? nullptr : nodes.back().Get();
}
+ Node* AssignedNodeNextTo(const Node&) const;
+ Node* AssignedNodePreviousTo(const Node&) const;
+
void AppendAssignedNode(Node&);
+ void ClearAssignedNodes();
const HeapVector<Member<Node>> FlattenedAssignedNodes();
void WillRecalcAssignedNodes() { ClearAssignedNodes(); }
void DidRecalcAssignedNodes() {
- UpdateFlatTreeNodeDataForAssignedNodes();
+ if (RuntimeEnabledFeatures::FastFlatTreeTraversalEnabled())
+ UpdateFlatTreeNodeDataForAssignedNodes();
RecalcFlatTreeChildren();
}
@@ -112,7 +117,7 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
return assigned_nodes_candidates_;
}
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
InsertionNotificationRequest InsertedInto(ContainerNode&) final;
@@ -137,10 +142,10 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
void RecalcFlatTreeChildren();
void UpdateFlatTreeNodeDataForAssignedNodes();
- void ClearAssignedNodes();
void ClearAssignedNodesAndFlatTreeChildren();
HeapVector<Member<Node>> assigned_nodes_;
+ HeapHashMap<Member<const Node>, unsigned> assigned_nodes_index_;
HeapVector<Member<Node>> flat_tree_children_;
bool slotchange_event_enqueued_ = false;
diff --git a/chromium/third_party/blink/renderer/core/html/html_source_element.cc b/chromium/third_party/blink/renderer/core/html/html_source_element.cc
index 38ed258c92b..80c993fd943 100644
--- a/chromium/third_party/blink/renderer/core/html/html_source_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_source_element.cc
@@ -53,7 +53,7 @@ class HTMLSourceElement::Listener final : public MediaQueryListListener {
}
void ClearElement() { element_ = nullptr; }
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(element_);
MediaQueryListListener::Trace(visitor);
}
@@ -72,10 +72,11 @@ DEFINE_NODE_FACTORY(HTMLSourceElement)
HTMLSourceElement::~HTMLSourceElement() = default;
-const HashSet<AtomicString>& HTMLSourceElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLSourceElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
void HTMLSourceElement::CreateMediaQueryList(const AtomicString& media) {
@@ -196,7 +197,7 @@ void HTMLSourceElement::NotifyMediaQueryChanged() {
picture->SourceOrMediaChanged();
}
-void HTMLSourceElement::Trace(blink::Visitor* visitor) {
+void HTMLSourceElement::Trace(Visitor* visitor) {
visitor->Trace(media_query_list_);
visitor->Trace(listener_);
HTMLElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/html_source_element.h b/chromium/third_party/blink/renderer/core/html/html_source_element.h
index 6f3fc9d5c80..369454d7640 100644
--- a/chromium/third_party/blink/renderer/core/html/html_source_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_source_element.h
@@ -42,10 +42,12 @@ class HTMLSourceElement final : public HTMLElement {
class Listener;
DECLARE_NODE_FACTORY(HTMLSourceElement);
+
+ explicit HTMLSourceElement(Document&);
~HTMLSourceElement() override;
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
const AtomicString& type() const;
void SetSrc(const String&);
@@ -60,11 +62,9 @@ class HTMLSourceElement final : public HTMLElement {
void RemoveMediaQueryListListener();
void AddMediaQueryListListener();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- explicit HTMLSourceElement(Document&);
-
void DispatchPendingEvent();
void DidMoveToNewDocument(Document& old_document) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_span_element.h b/chromium/third_party/blink/renderer/core/html/html_span_element.h
index 3c87353da8b..887b4dd6a7d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_span_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_span_element.h
@@ -37,7 +37,6 @@ class CORE_EXPORT HTMLSpanElement : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLSpanElement);
- protected:
explicit HTMLSpanElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_style_element.cc b/chromium/third_party/blink/renderer/core/html/html_style_element.cc
index e4e210e3234..1a3c59a630a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_style_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_style_element.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -150,7 +151,7 @@ void HTMLStyleElement::setDisabled(bool set_disabled) {
style_sheet->setDisabled(set_disabled);
}
-void HTMLStyleElement::Trace(blink::Visitor* visitor) {
+void HTMLStyleElement::Trace(Visitor* visitor) {
StyleElement::Trace(visitor);
HTMLElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_style_element.h b/chromium/third_party/blink/renderer/core/html/html_style_element.h
index 0bb532741f1..c1274beeb3a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_style_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_style_element.h
@@ -46,7 +46,7 @@ class CORE_EXPORT HTMLStyleElement final : public HTMLElement,
bool disabled() const;
void setDisabled(bool);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// Always call this asynchronously because this can cause synchronous
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_caption_element.h b/chromium/third_party/blink/renderer/core/html/html_table_caption_element.h
index b71dd756969..b25261bf50d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_caption_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_table_caption_element.h
@@ -36,11 +36,11 @@ class HTMLTableCaptionElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLTableCaptionElement);
+ HTMLTableCaptionElement(Document&);
+
bool HasNonInBodyInsertionMode() const override { return true; }
private:
- HTMLTableCaptionElement(Document&);
-
void CollectStyleForPresentationAttribute(
const QualifiedName&,
const AtomicString&,
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_col_element.h b/chromium/third_party/blink/renderer/core/html/html_table_col_element.h
index 1e7ff08c793..0d0e3a36cbb 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_col_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_table_col_element.h
@@ -30,7 +30,7 @@
namespace blink {
-class HTMLTableColElement final : public HTMLTablePartElement {
+class CORE_EXPORT HTMLTableColElement final : public HTMLTablePartElement {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_element.cc b/chromium/third_party/blink/renderer/core/html/html_table_element.cc
index 09fcb4d09d0..9bad9c4ab45 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_table_element.cc
@@ -620,7 +620,7 @@ const AtomicString& HTMLTableElement::Summary() const {
return getAttribute(kSummaryAttr);
}
-void HTMLTableElement::Trace(blink::Visitor* visitor) {
+void HTMLTableElement::Trace(Visitor* visitor) {
visitor->Trace(shared_cell_style_);
HTMLElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_element.h b/chromium/third_party/blink/renderer/core/html/html_table_element.h
index 2c01182fc6d..a8a71833a5f 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_table_element.h
@@ -43,6 +43,8 @@ class CORE_EXPORT HTMLTableElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLTableElement);
+ explicit HTMLTableElement(Document&);
+
HTMLTableCaptionElement* caption() const;
void setCaption(HTMLTableCaptionElement*, ExceptionState&);
@@ -73,10 +75,9 @@ class CORE_EXPORT HTMLTableElement final : public HTMLElement {
bool HasNonInBodyInsertionMode() const override { return true; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- explicit HTMLTableElement(Document&);
~HTMLTableElement() override;
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_row_element.h b/chromium/third_party/blink/renderer/core/html/html_table_row_element.h
index 25c2e740bb9..30333a053f8 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_row_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_table_row_element.h
@@ -40,6 +40,8 @@ class CORE_EXPORT HTMLTableRowElement final : public HTMLTablePartElement {
public:
DECLARE_NODE_FACTORY(HTMLTableRowElement);
+ explicit HTMLTableRowElement(Document&);
+
int rowIndex() const;
int sectionRowIndex() const;
@@ -52,8 +54,6 @@ class CORE_EXPORT HTMLTableRowElement final : public HTMLTablePartElement {
bool HasNonInBodyInsertionMode() const override { return true; }
private:
- explicit HTMLTableRowElement(Document&);
-
bool HasLegalLinkAttribute(const QualifiedName&) const override;
const QualifiedName& SubResourceAttributeName() const override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_template_element.cc b/chromium/third_party/blink/renderer/core/html/html_template_element.cc
index 1db069621d0..f8fd14260df 100644
--- a/chromium/third_party/blink/renderer/core/html/html_template_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_template_element.cc
@@ -71,7 +71,7 @@ void HTMLTemplateElement::DidMoveToNewDocument(Document& old_document) {
GetDocument().EnsureTemplateDocument().AdoptIfNeeded(*content_);
}
-void HTMLTemplateElement::Trace(blink::Visitor* visitor) {
+void HTMLTemplateElement::Trace(Visitor* visitor) {
visitor->Trace(content_);
HTMLElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_template_element.h b/chromium/third_party/blink/renderer/core/html/html_template_element.h
index 3bee834fcea..fe9c1d8e9ba 100644
--- a/chromium/third_party/blink/renderer/core/html/html_template_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_template_element.h
@@ -44,11 +44,13 @@ class CORE_EXPORT HTMLTemplateElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLTemplateElement);
+
+ explicit HTMLTemplateElement(Document&);
~HTMLTemplateElement() override;
bool HasNonInBodyInsertionMode() const override { return true; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
DocumentFragment* content() const;
@@ -57,8 +59,6 @@ class CORE_EXPORT HTMLTemplateElement final : public HTMLElement {
CloneChildrenFlag) override;
void DidMoveToNewDocument(Document& old_document) override;
- explicit HTMLTemplateElement(Document&);
-
mutable TraceWrapperMember<TemplateContentDocumentFragment> content_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_title_element.h b/chromium/third_party/blink/renderer/core/html/html_title_element.h
index 9089c14b325..dbc11a99f4b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_title_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_title_element.h
@@ -32,12 +32,12 @@ class HTMLTitleElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLTitleElement);
+ explicit HTMLTitleElement(Document&);
+
String text() const;
void setText(const String&);
private:
- explicit HTMLTitleElement(Document&);
-
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
void ChildrenChanged(const ChildrenChange&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_ulist_element.h b/chromium/third_party/blink/renderer/core/html/html_ulist_element.h
index dfad9625f7c..bca61425321 100644
--- a/chromium/third_party/blink/renderer/core/html/html_ulist_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_ulist_element.h
@@ -33,9 +33,9 @@ class HTMLUListElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLUListElement);
- private:
explicit HTMLUListElement(Document&);
+ private:
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
const QualifiedName&,
diff --git a/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc b/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc
index fa0c0f937e8..4dd94e55adf 100644
--- a/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc
@@ -354,7 +354,7 @@ void HTMLViewSourceDocument::MaybeAddSpanForAnnotation(
}
}
-void HTMLViewSourceDocument::Trace(blink::Visitor* visitor) {
+void HTMLViewSourceDocument::Trace(Visitor* visitor) {
visitor->Trace(current_);
visitor->Trace(tbody_);
visitor->Trace(td_);
diff --git a/chromium/third_party/blink/renderer/core/html/html_view_source_document.h b/chromium/third_party/blink/renderer/core/html/html_view_source_document.h
index 10644df2bde..52a4287ef31 100644
--- a/chromium/third_party/blink/renderer/core/html/html_view_source_document.h
+++ b/chromium/third_party/blink/renderer/core/html/html_view_source_document.h
@@ -47,7 +47,7 @@ class CORE_EXPORT HTMLViewSourceDocument final : public HTMLDocument {
void AddSource(const String&, HTMLToken&, SourceAnnotation);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
DocumentParser* CreateParser() override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_wbr_element.h b/chromium/third_party/blink/renderer/core/html/html_wbr_element.h
index f16a21c48c9..a9a7726478b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_wbr_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_wbr_element.h
@@ -41,9 +41,9 @@ class HTMLWBRElement final : public HTMLElement {
public:
DECLARE_NODE_FACTORY(HTMLWBRElement);
- private:
explicit HTMLWBRElement(Document&);
+ private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
};
diff --git a/chromium/third_party/blink/renderer/core/html/image_document.cc b/chromium/third_party/blink/renderer/core/html/image_document.cc
index 7deabda1b28..c452726f876 100644
--- a/chromium/third_party/blink/renderer/core/html/image_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/image_document.cc
@@ -25,8 +25,9 @@
#include "third_party/blink/renderer/core/html/image_document.h"
#include <limits>
+
#include "third_party/blink/public/platform/web_content_settings_client.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/raw_data_document_parser.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
@@ -53,39 +54,46 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
using namespace html_names;
-class ImageEventListener : public EventListener {
+class ImageEventListener : public NativeEventListener {
public:
static ImageEventListener* Create(ImageDocument* document) {
return MakeGarbageCollected<ImageEventListener>(document);
}
- static const ImageEventListener* Cast(const EventListener* listener) {
- return listener->GetType() == kImageEventListenerType
- ? static_cast<const ImageEventListener*>(listener)
- : nullptr;
- }
- ImageEventListener(ImageDocument* document)
- : EventListener(kImageEventListenerType), doc_(document) {}
+ ImageEventListener(ImageDocument* document) : doc_(document) {}
+
+ bool Matches(const EventListener& other) const override;
- bool operator==(const EventListener& other) const override;
+ void Invoke(ExecutionContext*, Event*) override;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(doc_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
}
- private:
- void Invoke(ExecutionContext*, Event*) override;
+ bool IsImageEventListener() const override { return true; }
+ private:
Member<ImageDocument> doc_;
};
+template <>
+struct DowncastTraits<ImageEventListener> {
+ static bool AllowFrom(const EventListener& event_listener) {
+ const NativeEventListener* native_event_listener =
+ DynamicTo<NativeEventListener>(event_listener);
+ return native_event_listener &&
+ native_event_listener->IsImageEventListener();
+ }
+};
+
class ImageDocumentParser : public RawDataDocumentParser {
public:
static ImageDocumentParser* Create(ImageDocument* document) {
@@ -167,7 +175,8 @@ void ImageDocumentParser::Finish() {
// Compute the title, we use the decoded filename of the resource, falling
// back on the (decoded) hostname if there is no path.
String file_name =
- DecodeURLEscapeSequences(GetDocument()->Url().LastPathComponent());
+ DecodeURLEscapeSequences(GetDocument()->Url().LastPathComponent(),
+ DecodeURLMode::kUTF8OrIsomorphic);
if (file_name.IsEmpty())
file_name = GetDocument()->Url().Host();
GetDocument()->setTitle(ImageTitle(file_name, size));
@@ -554,7 +563,7 @@ bool ImageDocument::ShouldShrinkToFit() const {
return GetFrame()->IsMainFrame() && !is_wrap_content_web_view;
}
-void ImageDocument::Trace(blink::Visitor* visitor) {
+void ImageDocument::Trace(Visitor* visitor) {
visitor->Trace(div_element_);
visitor->Trace(image_element_);
HTMLDocument::Trace(visitor);
@@ -576,10 +585,11 @@ void ImageEventListener::Invoke(ExecutionContext*, Event* event) {
}
}
-bool ImageEventListener::operator==(const EventListener& listener) const {
+bool ImageEventListener::Matches(const EventListener& listener) const {
if (const ImageEventListener* image_event_listener =
- ImageEventListener::Cast(&listener))
+ DynamicTo<ImageEventListener>(listener)) {
return doc_ == image_event_listener->doc_;
+ }
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/html/image_document.h b/chromium/third_party/blink/renderer/core/html/image_document.h
index e8cf65d046b..381272aa787 100644
--- a/chromium/third_party/blink/renderer/core/html/image_document.h
+++ b/chromium/third_party/blink/renderer/core/html/image_document.h
@@ -57,7 +57,7 @@ class CORE_EXPORT ImageDocument final : public HTMLDocument {
void UpdateImageStyle();
bool ShouldShrinkToFit() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
DocumentParser* CreateParser() override;
diff --git a/chromium/third_party/blink/renderer/core/html/image_document_test.cc b/chromium/third_party/blink/renderer/core/html/image_document_test.cc
index 4caa631220b..e88d48fa147 100644
--- a/chromium/third_party/blink/renderer/core/html/image_document_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/image_document_test.cc
@@ -326,7 +326,7 @@ TEST_F(ImageDocumentViewportTest, ZoomForDSFScaleImage) {
HTMLImageElement* img = GetDocument().ImageElement();
// no zoom
- WebView().Resize(IntSize(100, 100));
+ WebView().MainFrameWidget()->Resize(IntSize(100, 100));
WebView().SetZoomFactorForDeviceScaleFactor(1.f);
Compositor().BeginFrame();
EXPECT_EQ(50u, img->width());
@@ -340,7 +340,7 @@ TEST_F(ImageDocumentViewportTest, ZoomForDSFScaleImage) {
// visual viewport should be same in CSS pixel, as no dsf applied.
// This simulates running on two phones with different screen densities but
// same (physical) screen size, image document should displayed the same.
- WebView().Resize(IntSize(400, 400));
+ WebView().MainFrameWidget()->Resize(IntSize(400, 400));
WebView().SetZoomFactorForDeviceScaleFactor(4.f);
Compositor().BeginFrame();
EXPECT_EQ(50u, img->width());
@@ -369,7 +369,7 @@ TEST_F(ImageDocumentViewportTest, DivWidthWithZoomForDSF) {
// Image smaller then webview size, visual viewport is not zoomed, and image
// will be centered in the viewport.
- WebView().Resize(IntSize(200, 200));
+ WebView().MainFrameWidget()->Resize(IntSize(200, 200));
Compositor().BeginFrame();
EXPECT_EQ(50u, img->width());
EXPECT_EQ(50u, img->height());
@@ -383,7 +383,7 @@ TEST_F(ImageDocumentViewportTest, DivWidthWithZoomForDSF) {
// Image wider than webview size, image should fill the visual viewport, and
// visual viewport zoom out to 0.5.
- WebView().Resize(IntSize(50, 50));
+ WebView().MainFrameWidget()->Resize(IntSize(50, 50));
Compositor().BeginFrame();
EXPECT_EQ(50u, img->width());
EXPECT_EQ(50u, img->height());
@@ -394,7 +394,7 @@ TEST_F(ImageDocumentViewportTest, DivWidthWithZoomForDSF) {
// When image is more than 10X wider than webview, shrink the image to fit the
// width of the screen.
- WebView().Resize(IntSize(4, 20));
+ WebView().MainFrameWidget()->Resize(IntSize(4, 20));
Compositor().BeginFrame();
EXPECT_EQ(20u, img->width());
EXPECT_EQ(20u, img->height());
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import.h b/chromium/third_party/blink/renderer/core/html/imports/html_import.h
index 3e1b249eeac..e112e64aa18 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import.h
@@ -66,7 +66,7 @@ class HTMLImport : public GarbageCollectedFinalized<HTMLImport>,
virtual void StateWillChange() {}
virtual void StateDidChange();
- virtual void Trace(blink::Visitor* visitor) {}
+ virtual void Trace(Visitor* visitor) {}
protected:
// Stating from most conservative state.
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc
index 6cb6d5635ab..7ebf6531892 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc
@@ -174,7 +174,7 @@ void HTMLImportChild::Normalize() {
}
}
-void HTMLImportChild::Trace(blink::Visitor* visitor) {
+void HTMLImportChild::Trace(Visitor* visitor) {
visitor->Trace(custom_element_microtask_step_);
visitor->Trace(loader_);
visitor->Trace(client_);
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h
index d0db86e912d..e8265e3ea31 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h
@@ -70,7 +70,7 @@ class HTMLImportChild final : public HTMLImport {
HTMLImportLoader* Loader() const final;
void StateWillChange() final;
void StateDidChange() final;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void DidFinishLoading();
void DidFinishUpgradingCustomElements();
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_child_client.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_child_client.h
index 2f09958ba80..04525f82465 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_child_client.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_child_client.h
@@ -45,7 +45,7 @@ class HTMLImportChildClient : public GarbageCollectedMixin {
virtual void ImportChildWasDisposed(HTMLImportChild*) = 0;
virtual bool IsSync() const = 0;
virtual HTMLLinkElement* Link() = 0;
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc
index 7f72b8d9c46..a482044fc64 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc
@@ -100,7 +100,7 @@ HTMLImportLoader::State HTMLImportLoader::StartWritingAndParsing(
DCHECK(!imports_.IsEmpty());
document_ = HTMLDocument::Create(
DocumentInit::CreateWithImportsController(controller_)
- .WithURL(response.Url()));
+ .WithURL(response.CurrentRequestUrl()));
document_->OpenForNavigation(kAllowAsynchronousParsing, response.MimeType(),
"UTF-8");
@@ -201,7 +201,7 @@ V0CustomElementSyncMicrotaskQueue* HTMLImportLoader::MicrotaskQueue() const {
return microtask_queue_;
}
-void HTMLImportLoader::Trace(blink::Visitor* visitor) {
+void HTMLImportLoader::Trace(Visitor* visitor) {
visitor->Trace(controller_);
visitor->Trace(imports_);
visitor->Trace(document_);
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h
index f87ea503410..a3494cfdb5f 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h
@@ -93,7 +93,7 @@ class HTMLImportLoader final
V0CustomElementSyncMicrotaskQueue* MicrotaskQueue() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// RawResourceClient overrides:
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_sheets_test.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_sheets_test.cc
index 5bddf386595..a7fc5058dd3 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_sheets_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_sheets_test.cc
@@ -16,13 +16,14 @@ class HTMLImportSheetsTest : public SimTest {
void SetUp() override {
SimTest::SetUp();
- WebView().Resize(WebSize(640, 480));
+ WebView().MainFrameWidget()->Resize(WebSize(640, 480));
}
};
TEST_F(HTMLImportSheetsTest, NeedsActiveStyleUpdate) {
SimRequest main_resource("https://example.com/", "text/html");
- SimRequest import_resource("https://example.com/import.html", "text/html");
+ SimSubresourceRequest import_resource("https://example.com/import.html",
+ "text/html");
LoadURL("https://example.com/");
main_resource.Complete("<link id=link rel=import href=import.html>");
@@ -42,7 +43,8 @@ TEST_F(HTMLImportSheetsTest, NeedsActiveStyleUpdate) {
TEST_F(HTMLImportSheetsTest, UpdateStyleSheetList) {
SimRequest main_resource("https://example.com/", "text/html");
- SimRequest import_resource("https://example.com/import.html", "text/html");
+ SimSubresourceRequest import_resource("https://example.com/import.html",
+ "text/html");
LoadURL("https://example.com/");
main_resource.Complete("<link id=link rel=import href=import.html>");
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc
index 9c10e031e86..9e37a0cc7f8 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc
@@ -81,7 +81,7 @@ void HTMLImportTreeRoot::RecalcTimerFired(TimerBase*) {
HTMLImport::RecalcTreeState(this);
}
-void HTMLImportTreeRoot::Trace(blink::Visitor* visitor) {
+void HTMLImportTreeRoot::Trace(Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(imports_);
HTMLImport::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h
index 0baace67990..cfe93b71411 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h
@@ -35,7 +35,7 @@ class HTMLImportTreeRoot final : public HTMLImport, public NameClient {
HTMLImportChild* Add(HTMLImportChild*);
HTMLImportChild* Find(const KURL&) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
const char* NameInHeapSnapshot() const override {
return "HTMLImportTreeRoot";
}
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.cc b/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.cc
index 96f17c3bf4b..99de8f15fc4 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.cc
@@ -148,7 +148,7 @@ HTMLImportLoader* HTMLImportsController::LoaderFor(
return nullptr;
}
-void HTMLImportsController::Trace(blink::Visitor* visitor) {
+void HTMLImportsController::Trace(Visitor* visitor) {
visitor->Trace(root_);
visitor->Trace(loaders_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.h b/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.h
index 74df532bbf9..9c5b97c07a7 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_imports_controller.h
@@ -70,7 +70,7 @@ class HTMLImportsController final
HTMLImportLoader* LoaderAt(wtf_size_t i) const { return loaders_[i]; }
HTMLImportLoader* LoaderFor(const Document&) const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void Dispose();
diff --git a/chromium/third_party/blink/renderer/core/html/imports/link_import.cc b/chromium/third_party/blink/renderer/core/html/imports/link_import.cc
index 47e5978acf2..e0b4360cedb 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/link_import.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/link_import.cc
@@ -132,7 +132,7 @@ void LinkImport::OwnerRemoved() {
GetDocument().GetStyleEngine().HtmlImportAddedOrRemoved();
}
-void LinkImport::Trace(blink::Visitor* visitor) {
+void LinkImport::Trace(Visitor* visitor) {
visitor->Trace(child_);
HTMLImportChildClient::Trace(visitor);
LinkResource::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/imports/link_import.h b/chromium/third_party/blink/renderer/core/html/imports/link_import.h
index 28bc5677b03..4740f6c27f0 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/link_import.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/link_import.h
@@ -57,7 +57,7 @@ class LinkImport final : public LinkResource, public HTMLImportChildClient {
void Process() final;
LinkResourceType GetType() const final { return kImport; }
bool HasLoaded() const final;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void OwnerInserted() final;
void OwnerRemoved() final;
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc
index 225b335ec65..40d89cf594a 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc
@@ -392,7 +392,7 @@ void LazyLoadFrameObserver::RecordInitialDeferralAction(
was_recorded_as_deferred_ = true;
}
-void LazyLoadFrameObserver::Trace(blink::Visitor* visitor) {
+void LazyLoadFrameObserver::Trace(Visitor* visitor) {
visitor->Trace(element_);
visitor->Trace(lazy_load_intersection_observer_);
visitor->Trace(visibility_metrics_observer_);
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
index 5864e31a98c..5aef9962946 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
@@ -54,7 +54,7 @@ class LazyLoadFrameObserver
void LoadImmediately();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
struct LazyLoadRequestInfo;
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
index 2a1da7a02eb..9bfeb4ef4ac 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
@@ -98,11 +98,12 @@ class LazyLoadFramesParamsTest
scoped_restrict_lazy_frame_loading_to_data_saver_for_test_(false) {}
void SetUp() override {
- SetEffectiveConnectionTypeForTesting(
+ WebFrameClient().SetEffectiveConnectionTypeForTesting(
std::get<WebEffectiveConnectionType>(GetParam()));
SimTest::SetUp();
- WebView().Resize(WebSize(kViewportWidth, kViewportHeight));
+ WebView().MainFrameWidget()->Resize(
+ WebSize(kViewportWidth, kViewportHeight));
Settings& settings = WebView().GetPage()->GetSettings();
@@ -114,7 +115,8 @@ class LazyLoadFramesParamsTest
settings.SetLazyFrameLoadingDistanceThresholdPx2G(500);
settings.SetLazyFrameLoadingDistanceThresholdPx3G(600);
settings.SetLazyFrameLoadingDistanceThresholdPx4G(700);
- settings.SetLazyLoadEnabled(true);
+ settings.SetLazyLoadEnabled(
+ RuntimeEnabledFeatures::LazyFrameLoadingEnabled());
}
int GetLoadingDistanceThreshold() const {
@@ -717,12 +719,12 @@ TEST_P(LazyLoadFramesParamsTest, JavascriptStringFrameUrl) {
</body>)HTML",
kViewportHeight + GetLoadingDistanceThreshold() + 100));
- EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
- EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload"));
-
Compositor().BeginFrame();
test::RunPendingTasks();
+ EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
+ EXPECT_TRUE(ConsoleMessages().Contains("child frame element onload"));
+
ExpectVisibleLoadTimeHistogramSamplesIfApplicable(0, 0);
histogram_tester()->ExpectTotalCount(
"Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold", 0);
@@ -1105,11 +1107,12 @@ class LazyLoadFramesTest : public SimTest {
static constexpr int kLoadingDistanceThresholdPx = 1000;
void SetUp() override {
- SetEffectiveConnectionTypeForTesting(
+ WebFrameClient().SetEffectiveConnectionTypeForTesting(
WebEffectiveConnectionType::kTypeUnknown);
SimTest::SetUp();
- WebView().Resize(WebSize(kViewportWidth, kViewportHeight));
+ WebView().MainFrameWidget()->Resize(
+ WebSize(kViewportWidth, kViewportHeight));
Settings& settings = WebView().GetPage()->GetSettings();
settings.SetLazyFrameLoadingDistanceThresholdPxUnknown(
@@ -1248,7 +1251,7 @@ TEST_F(LazyLoadFramesTest, LazyLoadWhenDataSaverDisabledAndRestrictedAttrOn) {
GetNetworkStateNotifier().SetSaveDataEnabled(false);
WebView().GetPage()->GetSettings().SetDataSaverHoldbackWebApi(false);
- TestCrossOriginFrameIsLazilyLoaded("lazyload='on'");
+ TestCrossOriginFrameIsImmediatelyLoaded("lazyload='on'");
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
index 9ebbcba427a..2f10b829b71 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
@@ -245,6 +245,35 @@ void LazyLoadImageObserver::OnVisibilityChanged(
if (entry->isIntersecting()) {
DCHECK(visible_load_time_metrics.time_when_first_visible.is_null());
visible_load_time_metrics.time_when_first_visible = CurrentTimeTicks();
+
+ if (visible_load_time_metrics.record_visibility_metrics &&
+ image_element->GetDocument().GetFrame()) {
+ // Since the visibility metrics are recorded when the image finishes
+ // loading, this means that the image became visible before it
+ // finished loading.
+
+ // Note: If the WebEffectiveConnectionType enum ever gets out of sync
+ // with net::EffectiveConnectionType, then both the AboveTheFold and
+ // BelowTheFold histograms here will have to be updated to record the
+ // sample in terms of net::EffectiveConnectionType instead of
+ // WebEffectiveConnectionType.
+ if (visible_load_time_metrics.is_initially_intersecting) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Blink.VisibleBeforeLoaded.LazyLoadImages.AboveTheFold",
+ image_element->GetDocument()
+ .GetFrame()
+ ->Client()
+ ->GetEffectiveConnectionType());
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Blink.VisibleBeforeLoaded.LazyLoadImages.BelowTheFold",
+ image_element->GetDocument()
+ .GetFrame()
+ ->Client()
+ ->GetEffectiveConnectionType());
+ }
+ }
+
visibility_metrics_observer_->unobserve(image_element);
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
new file mode 100644
index 00000000000..887dae0da68
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
@@ -0,0 +1,99 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/lazy_load_image_observer.h"
+
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/style_image.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+namespace {
+
+class LazyLoadImagesSimTest : public SimTest {
+ protected:
+ LazyLoadImagesSimTest() : scoped_lazy_image_loading_for_test_(true) {}
+ void SetLazyLoadEnabled(bool enabled) {
+ WebView().GetPage()->GetSettings().SetLazyLoadEnabled(enabled);
+ }
+
+ void LoadMainResource() {
+ SimRequest main_resource("https://example.com/", "text/html");
+ LoadURL("https://example.com/");
+
+ main_resource.Complete(String::Format(R"HTML(
+ <style>
+ #deferred_image {
+ height:200px;
+ background-image: url('img.jpg');
+ }
+ </style>
+ <div style='height:10000px;'></div>
+ <div id="deferred_image"></div>
+ )HTML"));
+ }
+
+ void ExpectCSSBackgroundImageDeferredState(bool deferred) {
+ const ComputedStyle* deferred_image_style =
+ GetDocument().getElementById("deferred_image")->GetComputedStyle();
+ EXPECT_TRUE(deferred_image_style->HasBackgroundImage());
+ bool is_background_image_found = false;
+ for (const FillLayer* background_layer =
+ &deferred_image_style->BackgroundLayers();
+ background_layer; background_layer = background_layer->Next()) {
+ if (StyleImage* deferred_image = background_layer->GetImage()) {
+ EXPECT_TRUE(deferred_image->IsImageResource());
+ EXPECT_EQ(deferred, deferred_image->IsLazyloadPossiblyDeferred());
+ EXPECT_NE(deferred, deferred_image->IsLoaded());
+ is_background_image_found = true;
+ }
+ }
+ EXPECT_TRUE(is_background_image_found);
+ }
+
+ private:
+ ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test_;
+};
+
+TEST_F(LazyLoadImagesSimTest, CSSBackgroundImageLoadedWithoutLazyLoad) {
+ SetLazyLoadEnabled(false);
+ SimRequest image_resource("https://example.com/img.jpg", "image/jpeg");
+ LoadMainResource();
+ image_resource.Complete("");
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+ ExpectCSSBackgroundImageDeferredState(false);
+}
+
+TEST_F(LazyLoadImagesSimTest, CSSBackgroundImageDeferredWithLazyLoad) {
+ SetLazyLoadEnabled(true);
+ LoadMainResource();
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+
+ ExpectCSSBackgroundImageDeferredState(true);
+
+ // Scroll down until the background image is visible.
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 10000), kProgrammaticScroll);
+ SimRequest image_resource("https://example.com/img.jpg", "image/jpeg");
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+ image_resource.Complete("");
+ ExpectCSSBackgroundImageDeferredState(false);
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/link_element_loading_test.cc b/chromium/third_party/blink/renderer/core/html/link_element_loading_test.cc
index c82c7593f5f..027810fa1d2 100644
--- a/chromium/third_party/blink/renderer/core/html/link_element_loading_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/link_element_loading_test.cc
@@ -15,11 +15,11 @@ class LinkElementLoadingTest : public SimTest {};
TEST_F(LinkElementLoadingTest,
ShouldCancelLoadingStyleSheetIfLinkElementIsDisconnected) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
main_resource.Write(
"<!DOCTYPE html><link id=link rel=stylesheet href=test.css>");
diff --git a/chromium/third_party/blink/renderer/core/html/link_resource.cc b/chromium/third_party/blink/renderer/core/html/link_resource.cc
index 35e7b21e9da..468226fbc2b 100644
--- a/chromium/third_party/blink/renderer/core/html/link_resource.cc
+++ b/chromium/third_party/blink/renderer/core/html/link_resource.cc
@@ -65,7 +65,7 @@ WTF::TextEncoding LinkResource::GetCharset() const {
return WTF::TextEncoding(charset);
}
-void LinkResource::Trace(blink::Visitor* visitor) {
+void LinkResource::Trace(Visitor* visitor) {
visitor->Trace(owner_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/link_resource.h b/chromium/third_party/blink/renderer/core/html/link_resource.h
index e2defa72a12..d98f8b688d0 100644
--- a/chromium/third_party/blink/renderer/core/html/link_resource.h
+++ b/chromium/third_party/blink/renderer/core/html/link_resource.h
@@ -60,7 +60,7 @@ class CORE_EXPORT LinkResource
virtual void OwnerInserted() {}
virtual bool HasLoaded() const = 0;
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
protected:
void Load();
diff --git a/chromium/third_party/blink/renderer/core/html/link_style.cc b/chromium/third_party/blink/renderer/core/html/link_style.cc
index bccc8cbd29d..4998764e4cd 100644
--- a/chromium/third_party/blink/renderer/core/html/link_style.cc
+++ b/chromium/third_party/blink/renderer/core/html/link_style.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
+#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
#include "third_party/blink/renderer/platform/histogram.h"
@@ -45,8 +46,7 @@ LinkStyle::LinkStyle(HTMLLinkElement* owner)
pending_sheet_type_(kNone),
loading_(false),
fired_load_(false),
- loaded_sheet_(false),
- fetch_following_cors_(false) {}
+ loaded_sheet_(false) {}
LinkStyle::~LinkStyle() = default;
@@ -91,8 +91,8 @@ void LinkStyle::NotifyFinished(Resource* resource) {
}
CSSParserContext* parser_context = CSSParserContext::Create(
- GetDocument(), cached_style_sheet->GetResponse().Url(),
- cached_style_sheet->GetResponse().IsOpaqueResponseFromServiceWorker(),
+ GetDocument(), cached_style_sheet->GetResponse().ResponseUrl(),
+ cached_style_sheet->GetResponse().IsCorsSameOrigin(),
cached_style_sheet->GetReferrerPolicy(), cached_style_sheet->Encoding());
if (StyleSheetContents* parsed_sheet =
@@ -103,7 +103,6 @@ void LinkStyle::NotifyFinished(Resource* resource) {
sheet_->SetMediaQueries(MediaQuerySet::Create(owner_->Media()));
if (owner_->IsInDocumentTree())
SetSheetTitle(owner_->title());
- SetCrossOriginStylesheetStatus(sheet_.Get());
loading_ = false;
parsed_sheet->CheckLoaded();
@@ -121,7 +120,6 @@ void LinkStyle::NotifyFinished(Resource* resource) {
sheet_->SetMediaQueries(MediaQuerySet::Create(owner_->Media()));
if (owner_->IsInDocumentTree())
SetSheetTitle(owner_->title());
- SetCrossOriginStylesheetStatus(sheet_.Get());
style_sheet->ParseAuthorStyleSheet(cached_style_sheet,
GetDocument().GetSecurityOrigin());
@@ -241,17 +239,6 @@ void LinkStyle::SetDisabledState(bool disabled) {
Process();
}
-void LinkStyle::SetCrossOriginStylesheetStatus(CSSStyleSheet* sheet) {
- if (fetch_following_cors_ && GetResource() &&
- !GetResource()->ErrorOccurred()) {
- // Record the security origin the CORS access check succeeded at, if cross
- // origin. Only origins that are script accessible to it may access the
- // stylesheet's rules.
- sheet->SetAllowRuleAccessFromOrigin(GetDocument().GetSecurityOrigin());
- }
- fetch_following_cors_ = false;
-}
-
LinkStyle::LoadReturnValue LinkStyle::LoadStylesheetIfNeeded(
const LinkLoadParameters& params,
const WTF::TextEncoding& charset) {
@@ -263,7 +250,6 @@ LinkStyle::LoadReturnValue LinkStyle::LoadStylesheetIfNeeded(
if (GetResource()) {
RemovePendingSheet();
ClearResource();
- ClearFetchFollowingCors();
}
if (!owner_->ShouldLoadLink())
@@ -291,10 +277,6 @@ LinkStyle::LoadReturnValue LinkStyle::LoadStylesheetIfNeeded(
owner_->IsCreatedByParser();
AddPendingSheet(blocking ? kBlocking : kNonBlocking);
- if (params.cross_origin != kCrossOriginAttributeNotSet) {
- SetFetchFollowingCors();
- }
-
// Load stylesheets that are not needed for the layout immediately with low
// priority. When the link element is created by scripts, load the
// stylesheets asynchronously but in high priority.
@@ -381,7 +363,7 @@ void LinkStyle::OwnerRemoved() {
ClearSheet();
}
-void LinkStyle::Trace(blink::Visitor* visitor) {
+void LinkStyle::Trace(Visitor* visitor) {
visitor->Trace(sheet_);
LinkResource::Trace(visitor);
ResourceClient::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/link_style.h b/chromium/third_party/blink/renderer/core/html/link_style.h
index a9b281b3f4e..22e838ca757 100644
--- a/chromium/third_party/blink/renderer/core/html/link_style.h
+++ b/chromium/third_party/blink/renderer/core/html/link_style.h
@@ -38,7 +38,7 @@ class LinkStyle final : public LinkResource, ResourceClient {
void Process() override;
void OwnerRemoved() override;
bool HasLoaded() const override { return loaded_sheet_; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void StartLoadingDynamicSheet();
void NotifyLoadedSheetAndAllCriticalSubresources(
@@ -74,13 +74,6 @@ class LinkStyle final : public LinkResource, ResourceClient {
void AddPendingSheet(PendingSheetType);
void RemovePendingSheet();
- void SetCrossOriginStylesheetStatus(CSSStyleSheet*);
- void SetFetchFollowingCors() {
- DCHECK(!fetch_following_cors_);
- fetch_following_cors_ = true;
- }
- void ClearFetchFollowingCors() { fetch_following_cors_ = false; }
-
Member<CSSStyleSheet> sheet_;
DisabledState disabled_state_;
PendingSheetType pending_sheet_type_;
@@ -88,7 +81,6 @@ class LinkStyle final : public LinkResource, ResourceClient {
bool loading_;
bool fired_load_;
bool loaded_sheet_;
- bool fetch_following_cors_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc b/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc
index 1949d8b3f8f..f5ee6c8d00d 100644
--- a/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc
+++ b/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc
@@ -288,6 +288,8 @@ void ListItemOrdinal::ItemInsertedOrRemoved(
const Node* item_node = layout_list_item->GetNode();
if (item_node->GetDocument().IsSlotAssignmentOrLegacyDistributionDirty())
return;
+ if (item_node->GetDocument().IsFlatTreeTraversalForbidden())
+ return;
Node* list_node = EnclosingList(item_node);
CHECK(list_node);
diff --git a/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index c48fa73a3b8..b4b4209003b 100644
--- a/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -43,21 +43,6 @@ bool IsDocumentCrossOrigin(const Document& document) {
return frame && frame->IsCrossOriginSubframe();
}
-// Returns whether |document| is whitelisted for autoplay. If true, the user
-// gesture lock will be initilized as false, indicating that the element is
-// allowed to autoplay unmuted without user gesture.
-bool IsDocumentWhitelisted(const Document& document) {
- DCHECK(document.GetSettings());
-
- const String& whitelist_scope =
- document.GetSettings()->GetMediaPlaybackGestureWhitelistScope();
- if (whitelist_scope.IsNull() || whitelist_scope.IsEmpty())
- return false;
-
- DCHECK_EQ(KURL(whitelist_scope).GetString(), whitelist_scope);
- return document.Url().GetString().StartsWith(whitelist_scope);
-}
-
// Return true if and only if the document settings specifies media playback
// requires user gesture on the element.
bool ComputeLockPendingUserGestureRequired(const Document& document) {
@@ -87,7 +72,7 @@ AutoplayPolicy::Type AutoplayPolicy::GetAutoplayPolicyForDocument(
if (!document.GetSettings())
return Type::kNoUserGestureRequired;
- if (IsDocumentWhitelisted(document))
+ if (document.IsInWebAppScope())
return Type::kNoUserGestureRequired;
if (DocumentHasUserExceptionFlag(document))
@@ -393,17 +378,11 @@ bool AutoplayPolicy::IsGestureNeededForPlaybackIfPendingUserGestureIsLocked()
const {
// We want to allow muted video to autoplay if:
// - the flag is enabled;
- // - Data Saver is not enabled;
// - Preload was not disabled (low end devices);
// - Autoplay is enabled in settings;
if (element_->IsHTMLVideoElement() && element_->muted() &&
DocumentShouldAutoplayMutedVideos(element_->GetDocument()) &&
!(element_->GetDocument().GetSettings() &&
- GetNetworkStateNotifier().SaveDataEnabled() &&
- !element_->GetDocument()
- .GetSettings()
- ->GetDataSaverHoldbackMediaApi()) &&
- !(element_->GetDocument().GetSettings() &&
element_->GetDocument()
.GetSettings()
->GetForcePreloadNoneForMediaElements()) &&
@@ -482,7 +461,7 @@ bool AutoplayPolicy::ShouldAutoplay() {
return element_->can_autoplay_ && element_->paused_ && element_->Autoplay();
}
-void AutoplayPolicy::Trace(blink::Visitor* visitor) {
+void AutoplayPolicy::Trace(Visitor* visitor) {
visitor->Trace(element_);
visitor->Trace(autoplay_visibility_observer_);
visitor->Trace(autoplay_uma_helper_);
diff --git a/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.h b/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.h
index 3937336649a..31f7a42ee00 100644
--- a/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.h
+++ b/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.h
@@ -18,7 +18,8 @@ class ElementVisibilityObserver;
class HTMLMediaElement;
// AutoplayPolicy is the class for handles autoplay logics.
-class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
+class CORE_EXPORT AutoplayPolicy final
+ : public GarbageCollected<AutoplayPolicy> {
public:
// Different autoplay policy types.
enum class Type {
@@ -33,7 +34,7 @@ class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
kDocumentUserActivationRequired,
};
- CORE_EXPORT static Type GetAutoplayPolicyForDocument(const Document&);
+ static Type GetAutoplayPolicyForDocument(const Document&);
// Return true if the given |document| is allowed to play.
// This method may check parent frames if allow=autoplay (Feature Policy) was
@@ -41,7 +42,7 @@ class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
// and so on.
// Otherwise, frames are allowed to play if they have been activated or, for
// the main frame, if it has a high MEI.
- CORE_EXPORT static bool IsDocumentAllowedToPlay(const Document&);
+ static bool IsDocumentAllowedToPlay(const Document&);
// Returns true if the given |document| has high media engagement.
static bool DocumentHasHighMediaEngagement(const Document&);
@@ -86,7 +87,7 @@ class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
// Indicates the media element is or will autoplay because of being
// muted.
- CORE_EXPORT bool IsOrWillBeAutoplayingMuted() const;
+ bool IsOrWillBeAutoplayingMuted() const;
// Unlock user gesture if a user gesture can be utilized.
void TryUnlockingUserGesture();
@@ -112,7 +113,7 @@ class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
// avoid false positives.
void EnsureAutoplayInitiatedSet();
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
private:
friend class AutoplayUmaHelper;
diff --git a/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc b/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
index 4fa1e11e7c0..fe50d228e3e 100644
--- a/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
@@ -52,12 +52,11 @@ int64_t GetUserGestureStatusForUkmMetric(LocalFrame* frame) {
} // namespace
AutoplayUmaHelper* AutoplayUmaHelper::Create(HTMLMediaElement* element) {
- return new AutoplayUmaHelper(element);
+ return MakeGarbageCollected<AutoplayUmaHelper>(element);
}
AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element)
- : EventListener(kCPPEventListenerType),
- ContextLifecycleObserver(nullptr),
+ : ContextLifecycleObserver(nullptr),
element_(element),
muted_video_play_method_visibility_observer_(nullptr),
is_visible_(false),
@@ -67,10 +66,6 @@ AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element)
AutoplayUmaHelper::~AutoplayUmaHelper() = default;
-bool AutoplayUmaHelper::operator==(const EventListener& other) const {
- return this == &other;
-}
-
void AutoplayUmaHelper::OnLoadStarted() {
if (element_->GetLoadType() == WebMediaPlayer::kLoadTypeURL)
load_start_time_ = CurrentTimeTicks();
@@ -167,25 +162,12 @@ void AutoplayUmaHelper::OnAutoplayInitiated(AutoplaySource source) {
}
}
- // Record if it will be blocked by Data Saver or Autoplay setting.
+ // Record if it will be blocked by the Autoplay setting.
if (element_->IsHTMLVideoElement() && element_->muted() &&
AutoplayPolicy::DocumentShouldAutoplayMutedVideos(
- element_->GetDocument())) {
- bool data_saver_enabled_for_autoplay =
- GetNetworkStateNotifier().SaveDataEnabled() &&
- element_->GetDocument().GetSettings() &&
- !element_->GetDocument().GetSettings()->GetDataSaverHoldbackMediaApi();
- bool blocked_by_setting =
- !element_->GetAutoplayPolicy().IsAutoplayAllowedPerSettings();
-
- if (data_saver_enabled_for_autoplay && blocked_by_setting) {
- blocked_muted_video_histogram.Count(
- kAutoplayBlockedReasonDataSaverAndSetting);
- } else if (data_saver_enabled_for_autoplay) {
- blocked_muted_video_histogram.Count(kAutoplayBlockedReasonDataSaver);
- } else if (blocked_by_setting) {
- blocked_muted_video_histogram.Count(kAutoplayBlockedReasonSetting);
- }
+ element_->GetDocument()) &&
+ !element_->GetAutoplayPolicy().IsAutoplayAllowedPerSettings()) {
+ blocked_muted_video_histogram.Count(kAutoplayBlockedReasonSetting);
}
element_->addEventListener(event_type_names::kPlaying, this, false);
@@ -493,8 +475,8 @@ bool AutoplayUmaHelper::ShouldRecordUserPausedAutoplayingCrossOriginVideo()
CrossOriginAutoplayResult::kUserPaused);
}
-void AutoplayUmaHelper::Trace(blink::Visitor* visitor) {
- EventListener::Trace(visitor);
+void AutoplayUmaHelper::Trace(Visitor* visitor) {
+ NativeEventListener::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
visitor->Trace(element_);
visitor->Trace(muted_video_play_method_visibility_observer_);
diff --git a/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.h b/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.h
index 0b2991d6dd0..5135f0f1fe6 100644
--- a/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.h
+++ b/chromium/third_party/blink/renderer/core/html/media/autoplay_uma_helper.h
@@ -8,7 +8,7 @@
#include "third_party/blink/public/platform/web_media_player_client.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
@@ -39,9 +39,9 @@ enum class AutoplayUnmuteActionStatus {
// These values are used for histograms. Do not reorder.
enum AutoplayBlockedReason {
- kAutoplayBlockedReasonDataSaver = 0,
+ kAutoplayBlockedReasonDataSaver_DEPRECATED = 0,
kAutoplayBlockedReasonSetting = 1,
- kAutoplayBlockedReasonDataSaverAndSetting = 2,
+ kAutoplayBlockedReasonDataSaverAndSetting_DEPRECATED = 2,
// Keey at the end.
kAutoplayBlockedReasonMax = 3
};
@@ -59,17 +59,16 @@ class Document;
class ElementVisibilityObserver;
class HTMLMediaElement;
-class CORE_EXPORT AutoplayUmaHelper : public EventListener,
+class CORE_EXPORT AutoplayUmaHelper : public NativeEventListener,
public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(AutoplayUmaHelper);
public:
static AutoplayUmaHelper* Create(HTMLMediaElement*);
+ explicit AutoplayUmaHelper(HTMLMediaElement*);
~AutoplayUmaHelper() override;
- bool operator==(const EventListener&) const override;
-
void ContextDestroyed(ExecutionContext*) override;
void OnAutoplayInitiated(AutoplaySource);
@@ -84,7 +83,9 @@ class CORE_EXPORT AutoplayUmaHelper : public EventListener,
bool HasSource() const { return !sources_.empty(); }
- void Trace(blink::Visitor*) override;
+ void Invoke(ExecutionContext*, Event*) override;
+
+ void Trace(Visitor*) override;
private:
friend class MockAutoplayUmaHelper;
@@ -92,8 +93,6 @@ class CORE_EXPORT AutoplayUmaHelper : public EventListener,
// Called when source is initialized and loading starts.
void OnLoadStarted();
- explicit AutoplayUmaHelper(HTMLMediaElement*);
- void Invoke(ExecutionContext*, Event*) override;
void HandlePlayingEvent();
void HandlePauseEvent();
virtual void HandleContextDestroyed(); // Make virtual for testing.
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc b/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc
index 62e70ce5e52..083c35e8c32 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -410,10 +410,11 @@ MIMETypeRegistry::SupportsType HTMLMediaElement::GetSupportsType(
return result;
}
-const HashSet<AtomicString>& HTMLMediaElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLMediaElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
bool HTMLMediaElement::IsHLSURL(const KURL& url) {
@@ -500,6 +501,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
muted_(false),
paused_(true),
seeking_(false),
+ paused_by_context_paused_(false),
sent_stalled_event_(false),
ignore_preload_none_(false),
text_tracks_visible_(false),
@@ -512,7 +514,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
audio_tracks_(AudioTrackList::Create(*this)),
video_tracks_(VideoTrackList::Create(*this)),
audio_source_node_(nullptr),
- autoplay_policy_(new AutoplayPolicy(this)),
+ autoplay_policy_(MakeGarbageCollected<AutoplayPolicy>(this)),
remote_playback_client_(nullptr),
media_controls_(nullptr),
controls_list_(HTMLMediaElementControlsList::Create(this)),
@@ -607,6 +609,7 @@ void HTMLMediaElement::DidMoveToNewDocument(Document& old_document) {
}
bool HTMLMediaElement::SupportsFocus() const {
+ // TODO(https://crbug.com/911882): Depending on result of discussion, remove.
if (ownerDocument()->IsMediaDocument())
return false;
@@ -616,7 +619,7 @@ bool HTMLMediaElement::SupportsFocus() const {
}
bool HTMLMediaElement::IsMouseFocusable() const {
- return false;
+ return !IsFullscreen();
}
void HTMLMediaElement::ParseAttribute(
@@ -1403,6 +1406,11 @@ WebMediaPlayer::LoadType HTMLMediaElement::GetLoadType() const {
return WebMediaPlayer::kLoadTypeURL;
}
+bool HTMLMediaElement::PausedWhenVisible() const {
+ return paused_ && GetWebMediaPlayer() &&
+ !GetWebMediaPlayer()->PausedWhenHidden();
+}
+
bool HTMLMediaElement::TextTracksAreReady() const {
// 4.8.12.11.1 Text track model
// ...
@@ -2345,12 +2353,10 @@ WebMediaPlayer::Preload HTMLMediaElement::PreloadType() const {
return WebMediaPlayer::kPreloadNone;
}
- // If the source scheme is requires network, force preload to 'none' on Data
- // Saver and for low end devices.
+ // If the source scheme is requires network, force preload to 'none' for low
+ // end devices.
if (GetDocument().GetSettings() &&
- ((GetNetworkStateNotifier().SaveDataEnabled() &&
- !GetDocument().GetSettings()->GetDataSaverHoldbackMediaApi()) ||
- GetDocument().GetSettings()->GetForcePreloadNoneForMediaElements()) &&
+ GetDocument().GetSettings()->GetForcePreloadNoneForMediaElements() &&
(current_src_.Protocol() != "blob" && current_src_.Protocol() != "data" &&
current_src_.Protocol() != "file")) {
UseCounter::Count(GetDocument(),
@@ -3455,7 +3461,9 @@ bool HTMLMediaElement::CouldPlayIfEnoughData() const {
bool HTMLMediaElement::EndedPlayback(LoopCondition loop_condition) const {
double dur = duration();
- if (std::isnan(dur))
+ // If we have infinite duration, we'll never have played for long enough to
+ // have ended playback.
+ if (std::isnan(dur) || dur == std::numeric_limits<double>::infinity())
return false;
// 4.8.12.8 Playing the media resource
@@ -3470,16 +3478,6 @@ bool HTMLMediaElement::EndedPlayback(LoopCondition loop_condition) const {
// loop attribute specified,
double now = CurrentPlaybackPosition();
- // Log whether we get a playback position of infinity().
- // TODO(ossu): Once this stat expires, the duration check, below, can be moved
- // up to the top of the function.
- UMA_HISTOGRAM_BOOLEAN("Media.MediaElement.PlaybackPositionIsInfinity",
- now == std::numeric_limits<double>::infinity());
- // If we have infinite duration, we'll never have played for long enough to
- // have ended playback.
- if (dur == std::numeric_limits<double>::infinity())
- return false;
-
if (GetDirectionOfPlayback() == kForward) {
return dur > 0 && now >= dur &&
(loop_condition == LoopCondition::kIgnored || !Loop());
@@ -3586,6 +3584,20 @@ void HTMLMediaElement::ClearMediaPlayer() {
GetLayoutObject()->SetShouldDoFullPaintInvalidation();
}
+void HTMLMediaElement::ContextPaused(PauseState pause_state) {
+ if (pause_state == PauseState::kFrozen && playing_) {
+ paused_by_context_paused_ = true;
+ pause();
+ }
+}
+
+void HTMLMediaElement::ContextUnpaused() {
+ if (paused_by_context_paused_) {
+ paused_by_context_paused_ = false;
+ Play();
+ }
+}
+
void HTMLMediaElement::ContextDestroyed(ExecutionContext*) {
BLINK_MEDIA_LOG << "contextDestroyed(" << (void*)this << ")";
@@ -3622,7 +3634,15 @@ bool HTMLMediaElement::HasPendingActivity() const {
// When networkState is kNetworkLoading, progress and stalled events may be
// fired.
- if (network_state_ == kNetworkLoading)
+ //
+ // When connected to a MediaSource, ignore |network_state_|. The rest
+ // of this method's logic and the HasPendingActivity() of the various
+ // MediaSource API objects more precisely indicate whether or not any pending
+ // activity is expected on the group of connected HTMLMediaElement +
+ // MediaSource API objects. This lets the group of objects be garbage
+ // collected if there is no pending activity nor reachability from a GC root,
+ // even while in kNetworkLoading.
+ if (!media_source_ && network_state_ == kNetworkLoading)
return true;
{
@@ -3641,11 +3661,6 @@ bool HTMLMediaElement::HasPendingActivity() const {
if (seeking_)
return true;
- // When connected to a MediaSource, e.g. setting MediaSource.duration will
- // cause a durationchange event to be fired.
- if (media_source_)
- return true;
-
// Wait for any pending events to be fired.
if (async_event_queue_->HasPendingEvents())
return true;
@@ -3882,7 +3897,7 @@ void HTMLMediaElement::UpdateControlsVisibility() {
CueTimeline& HTMLMediaElement::GetCueTimeline() {
if (!cue_timeline_)
- cue_timeline_ = new CueTimeline(*this);
+ cue_timeline_ = MakeGarbageCollected<CueTimeline>(*this);
return *cue_timeline_;
}
@@ -3971,7 +3986,7 @@ bool HTMLMediaElement::IsInteractiveContent() const {
return FastHasAttribute(kControlsAttr);
}
-void HTMLMediaElement::Trace(blink::Visitor* visitor) {
+void HTMLMediaElement::Trace(Visitor* visitor) {
visitor->Trace(viewport_intersection_observer_);
visitor->Trace(played_time_ranges_);
visitor->Trace(async_event_queue_);
@@ -4212,11 +4227,11 @@ void HTMLMediaElement::AudioClientImpl::SetFormat(uint32_t number_of_channels,
client_->SetFormat(number_of_channels, sample_rate);
}
-void HTMLMediaElement::AudioClientImpl::Trace(blink::Visitor* visitor) {
+void HTMLMediaElement::AudioClientImpl::Trace(Visitor* visitor) {
visitor->Trace(client_);
}
-void HTMLMediaElement::AudioSourceProviderImpl::Trace(blink::Visitor* visitor) {
+void HTMLMediaElement::AudioSourceProviderImpl::Trace(Visitor* visitor) {
visitor->Trace(client_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element.h b/chromium/third_party/blink/renderer/core/html/media/html_media_element.h
index 865fc83725b..e53f1ab5bf0 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element.h
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -35,7 +35,7 @@
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/media/media_controls.h"
#include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h"
@@ -95,7 +95,7 @@ class CORE_EXPORT HTMLMediaElement
public:
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
static MIMETypeRegistry::SupportsType GetSupportsType(const ContentType&);
@@ -111,7 +111,7 @@ class CORE_EXPORT HTMLMediaElement
// for the given document.
static void OnMediaControlsEnabledChange(Document*);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
void ClearWeakMembers(Visitor*);
WebMediaPlayer* GetWebMediaPlayer() const { return web_media_player_.get(); }
@@ -329,6 +329,10 @@ class CORE_EXPORT HTMLMediaElement
bool HasMediaSource() const { return media_source_; }
+ // Return true if element is paused and won't resume automatically if it
+ // becomes visible again.
+ bool PausedWhenVisible() const;
+
protected:
HTMLMediaElement(const QualifiedName&, Document&);
~HTMLMediaElement() override;
@@ -364,6 +368,7 @@ class CORE_EXPORT HTMLMediaElement
// Friend class for testing.
friend class ContextMenuControllerTest;
friend class MediaElementFillingViewportTest;
+ friend class VideoWakeLockTest;
void ResetMediaPlayerAndMediaSource();
@@ -382,6 +387,8 @@ class CORE_EXPORT HTMLMediaElement
bool IsInteractiveContent() const final;
// PausableObject functions.
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
void ContextDestroyed(ExecutionContext*) override;
virtual void UpdateDisplayState() {}
@@ -497,8 +504,6 @@ class CORE_EXPORT HTMLMediaElement
// This does not stop autoplay visibility observation.
void PauseInternal();
- void AllowVideoRendering();
-
void UpdateVolume();
void UpdatePlayState();
bool PotentiallyPlaying() const;
@@ -625,7 +630,14 @@ class CORE_EXPORT HTMLMediaElement
DisplayMode display_mode_;
- Member<HTMLMediaSource> media_source_;
+ // If any portion of an attached HTMLMediaElement (HTMLME) and the MediaSource
+ // Extensions (MSE) API is alive (having pending activity or traceable from a
+ // GC root), the whole group is not GC'ed. Here, using TraceWrapperMember,
+ // instead of Member, because |media_source_|'s wrapper needs to remain alive
+ // at least to successfully dispatch any events enqueued by behavior of the
+ // HTMLME+MSE API. It makes |media_source_|'s wrapper remain alive as long as
+ // this HTMLMediaElement's wrapper is alive.
+ TraceWrapperMember<HTMLMediaSource> media_source_;
// Stores "official playback position", updated periodically from "current
// playback position". Official playback position should not change while
@@ -646,6 +658,7 @@ class CORE_EXPORT HTMLMediaElement
bool muted_ : 1;
bool paused_ : 1;
bool seeking_ : 1;
+ bool paused_by_context_paused_ : 1;
// data has not been loaded since sending a "stalled" event
bool sent_stalled_event_ : 1;
@@ -699,7 +712,7 @@ class CORE_EXPORT HTMLMediaElement
// WebAudioSourceProviderClient
void SetFormat(uint32_t number_of_channels, float sample_rate) override;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Member<AudioSourceProviderClient> client_;
@@ -722,7 +735,7 @@ class CORE_EXPORT HTMLMediaElement
void SetClient(AudioSourceProviderClient*) override;
void ProvideInput(AudioBus*, uint32_t frames_to_process) override;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
WebAudioSourceProvider* web_audio_source_provider_;
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element.idl b/chromium/third_party/blink/renderer/core/html/media/html_media_element.idl
index 3fa256d76c7..ecba4545271 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element.idl
@@ -25,9 +25,6 @@
// https://html.spec.whatwg.org/#media-elements
-// The `URLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" };
[
ActiveScriptWrappable
@@ -49,7 +46,7 @@ enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" };
[CEReactions] attribute DOMString preload;
readonly attribute TimeRanges buffered;
void load();
- CanPlayTypeResult canPlayType(DOMString type);
+ [HighEntropy, Measure] CanPlayTypeResult canPlayType(DOMString type);
// ready state
const unsigned short HAVE_NOTHING = 0;
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h b/chromium/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h
index e2f0d14c465..d7787fa945f 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h
@@ -13,7 +13,7 @@ namespace blink {
class HTMLMediaElement;
-class HTMLMediaElementControlsList final : public DOMTokenList {
+class CORE_EXPORT HTMLMediaElementControlsList final : public DOMTokenList {
public:
static HTMLMediaElementControlsList* Create(HTMLMediaElement* element) {
return MakeGarbageCollected<HTMLMediaElementControlsList>(element);
@@ -22,9 +22,9 @@ class HTMLMediaElementControlsList final : public DOMTokenList {
explicit HTMLMediaElementControlsList(HTMLMediaElement*);
// Whether the list dictates to hide a certain control.
- CORE_EXPORT bool ShouldHideDownload() const;
- CORE_EXPORT bool ShouldHideFullscreen() const;
- CORE_EXPORT bool ShouldHideRemotePlayback() const;
+ bool ShouldHideDownload() const;
+ bool ShouldHideFullscreen() const;
+ bool ShouldHideRemotePlayback() const;
private:
bool ValidateTokenValue(const AtomicString&, ExceptionState&) const override;
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc b/chromium/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc
index e09c9282b71..157d6443366 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc
@@ -10,6 +10,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
#include "third_party/blink/renderer/core/event_type_names.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
@@ -80,7 +81,7 @@ class FakeWebMediaPlayer final : public EmptyWebMediaPlayer {
class MediaStubLocalFrameClient : public EmptyLocalFrameClient {
public:
static MediaStubLocalFrameClient* Create() {
- return new MediaStubLocalFrameClient;
+ return MakeGarbageCollected<MediaStubLocalFrameClient>();
}
std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
@@ -237,18 +238,12 @@ TEST_F(HTMLMediaElementEventListenersTest,
observed_results[0]);
}
-class MockEventListener final : public EventListener {
+class MockEventListener final : public NativeEventListener {
public:
static MockEventListener* Create() {
return MakeGarbageCollected<MockEventListener>();
}
- MockEventListener() : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
MOCK_METHOD2(Invoke, void(ExecutionContext* executionContext, Event*));
};
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc
index 317d3741b5f..9f4182538d6 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -131,6 +131,10 @@ class HTMLMediaElementTest : public testing::TestWithParam<MediaTestParam> {
return !!Media()->lazy_load_visibility_observer_;
}
+ ExecutionContext* GetExecutionContext() const {
+ return &dummy_page_holder_->GetDocument();
+ }
+
private:
std::unique_ptr<DummyPageHolder> dummy_page_holder_;
Persistent<HTMLMediaElement> media_;
@@ -467,4 +471,18 @@ TEST_P(HTMLMediaElementTest, DomInteractive) {
EXPECT_FALSE(Media()->GetDocument().GetTiming().DomInteractive().is_null());
}
+TEST_P(HTMLMediaElementTest, ContextPaused) {
+ Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
+ Media()->Play();
+
+ test::RunPendingTasks();
+ SetReadyState(HTMLMediaElement::kHaveFutureData);
+
+ EXPECT_FALSE(Media()->paused());
+ GetExecutionContext()->PausePausableObjects(PauseState::kFrozen);
+ EXPECT_TRUE(Media()->paused());
+ GetExecutionContext()->UnpausePausableObjects();
+ EXPECT_FALSE(Media()->paused());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.cc b/chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.cc
new file mode 100644
index 00000000000..88e2948835d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.cc
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/media/html_media_test_helper.h"
+
+#include "third_party/blink/public/platform/web_media_player.h"
+
+namespace blink {
+namespace test {
+
+// static
+MediaStubLocalFrameClient* MediaStubLocalFrameClient::Create(
+ std::unique_ptr<WebMediaPlayer> player) {
+ return MakeGarbageCollected<MediaStubLocalFrameClient>(std::move(player));
+}
+
+MediaStubLocalFrameClient::MediaStubLocalFrameClient(
+ std::unique_ptr<WebMediaPlayer> player)
+ : player_(std::move(player)) {}
+
+std::unique_ptr<WebMediaPlayer> MediaStubLocalFrameClient::CreateWebMediaPlayer(
+ HTMLMediaElement&,
+ const WebMediaPlayerSource&,
+ WebMediaPlayerClient*,
+ WebLayerTreeView*) {
+ DCHECK(player_) << " Empty injected player - already used?";
+ return std::move(player_);
+}
+
+} // namespace test
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.h b/chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.h
new file mode 100644
index 00000000000..93d163ac24d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_test_helper.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_HTML_MEDIA_TEST_HELPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_HTML_MEDIA_TEST_HELPER_H_
+
+#include "third_party/blink/renderer/core/loader/empty_clients.h"
+
+namespace blink {
+namespace test {
+
+// This file contains various class to help with HTML Media tests.
+
+// Generic LocalFrameClient stub to be used by media tests that need a
+// WebMediaPlayerimplementation.
+class MediaStubLocalFrameClient : public EmptyLocalFrameClient {
+ public:
+ // Creates a LocalFrameClient that will use the given media player.
+ static MediaStubLocalFrameClient* Create(std::unique_ptr<WebMediaPlayer>);
+
+ explicit MediaStubLocalFrameClient(std::unique_ptr<WebMediaPlayer>);
+
+ std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
+ HTMLMediaElement&,
+ const WebMediaPlayerSource&,
+ WebMediaPlayerClient*,
+ WebLayerTreeView*) override;
+
+ private:
+ std::unique_ptr<WebMediaPlayer> player_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaStubLocalFrameClient);
+};
+
+} // namespace test
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_HTML_MEDIA_TEST_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc b/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc
index d391f486de7..985322e9019 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/core/html/media/media_element_parser_helpers.h"
#include "third_party/blink/renderer/core/html/media/media_remoting_interstitial.h"
#include "third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h"
+#include "third_party/blink/renderer/core/html/media/video_wake_lock.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
@@ -52,6 +53,7 @@
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
@@ -95,6 +97,8 @@ inline HTMLVideoElement::HTMLVideoElement(Document& document)
overridden_intrinsic_size_ =
IntSize(LayoutReplaced::kDefaultWidth, LayoutReplaced::kDefaultHeight);
}
+
+ wake_lock_ = MakeGarbageCollected<VideoWakeLock>(*this);
}
HTMLVideoElement* HTMLVideoElement::Create(Document& document) {
@@ -104,9 +108,10 @@ HTMLVideoElement* HTMLVideoElement::Create(Document& document) {
return video;
}
-void HTMLVideoElement::Trace(blink::Visitor* visitor) {
+void HTMLVideoElement::Trace(Visitor* visitor) {
visitor->Trace(image_loader_);
visitor->Trace(custom_controls_fullscreen_detector_);
+ visitor->Trace(wake_lock_);
visitor->Trace(remoting_interstitial_);
visitor->Trace(picture_in_picture_interstitial_);
HTMLMediaElement::Trace(visitor);
@@ -232,6 +237,16 @@ void HTMLVideoElement::ParseAttribute(
if (intrinsic_size_changed && GetLayoutObject() &&
GetLayoutObject()->IsVideo())
ToLayoutVideo(GetLayoutObject())->IntrinsicSizeChanged();
+ } else if (params.name == kAutopictureinpictureAttr &&
+ origin_trials::AutoPictureInPictureEnabled(
+ GetExecutionContext())) {
+ if (!params.new_value.IsNull()) {
+ PictureInPictureController::From(GetDocument())
+ .AddToAutoPictureInPictureElementsList(this);
+ } else {
+ PictureInPictureController::From(GetDocument())
+ .RemoveFromAutoPictureInPictureElementsList(this);
+ }
} else {
HTMLMediaElement::ParseAttribute(params);
}
@@ -583,7 +598,7 @@ scoped_refptr<Image> HTMLVideoElement::GetSourceImageForCanvas(
return snapshot;
}
-bool HTMLVideoElement::WouldTaintOrigin(const SecurityOrigin*) const {
+bool HTMLVideoElement::WouldTaintOrigin() const {
return !IsMediaDataCorsSameOrigin();
}
@@ -682,8 +697,7 @@ void HTMLVideoElement::PictureInPictureControlClicked(
WebMediaPlayer::DisplayType HTMLVideoElement::DisplayType() const {
if (is_auto_picture_in_picture_ ||
- PictureInPictureController::From(GetDocument())
- .IsPictureInPictureElement(this)) {
+ PictureInPictureController::IsElementInPictureInPicture(this)) {
return WebMediaPlayer::DisplayType::kPictureInPicture;
}
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element.h b/chromium/third_party/blink/renderer/core/html/media/html_video_element.h
index 3d0ec24fb60..9e6a0a1d515 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -45,6 +45,7 @@ class ImageBitmapOptions;
class MediaCustomControlsFullscreenDetector;
class MediaRemotingInterstitial;
class PictureInPictureInterstitial;
+class VideoWakeLock;
class CORE_EXPORT HTMLVideoElement final : public HTMLMediaElement,
public CanvasImageSource,
@@ -55,7 +56,7 @@ class CORE_EXPORT HTMLVideoElement final : public HTMLMediaElement,
static HTMLVideoElement* Create(Document&);
HTMLVideoElement(Document&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
bool HasPendingActivity() const final;
@@ -150,7 +151,7 @@ class CORE_EXPORT HTMLVideoElement final : public HTMLMediaElement,
AccelerationHint,
const FloatSize&) override;
bool IsVideoElement() const override { return true; }
- bool WouldTaintOrigin(const SecurityOrigin*) const override;
+ bool WouldTaintOrigin() const override;
FloatSize ElementSize(const FloatSize&) const override;
const KURL& SourceURL() const override { return currentSrc(); }
bool IsHTMLVideoElement() const override { return true; }
@@ -201,6 +202,8 @@ class CORE_EXPORT HTMLVideoElement final : public HTMLMediaElement,
image_loader_->SetImageForTest(content);
}
+ VideoWakeLock* wake_lock_for_tests() const { return wake_lock_; }
+
protected:
// EventTarget overrides.
void AddedEventListener(const AtomicString& event_type,
@@ -233,6 +236,7 @@ class CORE_EXPORT HTMLVideoElement final : public HTMLMediaElement,
Member<HTMLImageLoader> image_loader_;
Member<MediaCustomControlsFullscreenDetector>
custom_controls_fullscreen_detector_;
+ Member<VideoWakeLock> wake_lock_;
Member<MediaRemotingInterstitial> remoting_interstitial_;
Member<PictureInPictureInterstitial> picture_in_picture_interstitial_;
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element_persistent_test.cc b/chromium/third_party/blink/renderer/core/html/media/html_video_element_persistent_test.cc
index 5cc4de3bb19..a62627c5729 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element_persistent_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element_persistent_test.cc
@@ -34,7 +34,7 @@ using testing::Sequence;
class HTMLVideoElementPersistentTest : public PageTestBase {
protected:
void SetUp() override {
- chrome_client_ = new FullscreenMockChromeClient();
+ chrome_client_ = MakeGarbageCollected<FullscreenMockChromeClient>();
Page::PageClients clients;
FillWithEmptyClients(clients);
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc
index d34ae82dc73..1dbf6e801db 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
#include "third_party/blink/public/platform/web_media_player.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/html/media/html_media_test_helper.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
@@ -25,24 +26,6 @@ class HTMLVideoElementMockMediaPlayer : public EmptyWebMediaPlayer {
MOCK_METHOD1(OnDisplayTypeChanged, void(WebMediaPlayer::DisplayType));
};
-class HTMLVideoElementFrameClient : public EmptyLocalFrameClient {
- public:
- HTMLVideoElementFrameClient(std::unique_ptr<WebMediaPlayer> player)
- : player_(std::move(player)) {}
-
- std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
- HTMLMediaElement&,
- const WebMediaPlayerSource&,
- WebMediaPlayerClient* client,
- WebLayerTreeView*) override {
- DCHECK(player_) << " Empty injected player - already used?";
- return std::move(player_);
- }
-
- private:
- std::unique_ptr<WebMediaPlayer> player_;
-};
-
class HTMLVideoElementTest : public PageTestBase {
public:
void SetUp() override {
@@ -50,10 +33,10 @@ class HTMLVideoElementTest : public PageTestBase {
std::make_unique<HTMLVideoElementMockMediaPlayer>();
media_player_ = mock_media_player.get();
- SetupPageWithClients(nullptr,
- MakeGarbageCollected<HTMLVideoElementFrameClient>(
- std::move(mock_media_player)),
- nullptr);
+ SetupPageWithClients(
+ nullptr,
+ test::MediaStubLocalFrameClient::Create(std::move(mock_media_player)),
+ nullptr);
video_ = HTMLVideoElement::Create(GetDocument());
GetDocument().body()->appendChild(video_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_controls.cc b/chromium/third_party/blink/renderer/core/html/media/media_controls.cc
index d24af6e56f5..4f735e0d753 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_controls.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_controls.cc
@@ -48,7 +48,7 @@ HTMLMediaElement& MediaControls::MediaElement() const {
return *media_element_;
}
-void MediaControls::Trace(blink::Visitor* visitor) {
+void MediaControls::Trace(Visitor* visitor) {
visitor->Trace(media_element_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_controls.h b/chromium/third_party/blink/renderer/core/html/media/media_controls.h
index c9e9179d152..57c9b42217f 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_controls.h
+++ b/chromium/third_party/blink/renderer/core/html/media/media_controls.h
@@ -68,7 +68,7 @@ class CORE_EXPORT MediaControls : public GarbageCollectedMixin {
// TODO(mlamouri): required by LayoutVTTCue.
virtual LayoutObject* ContainerLayoutObject() = 0;
- // Used for layout tests to disable some animations.
+ // Used for web tests to disable some animations.
virtual void SetTestMode(bool) = 0;
// TODO: the following are required by other parts of the media controls
@@ -77,7 +77,7 @@ class CORE_EXPORT MediaControls : public GarbageCollectedMixin {
virtual HTMLDivElement* PanelElement() = 0;
virtual void OnMediaControlsEnabledChange() = 0;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<HTMLMediaElement> media_element_;
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.cc b/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.cc
index c8f46608d54..03efdfa48a9 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.cc
@@ -10,7 +10,9 @@
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/layout/intersection_geometry.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -26,8 +28,8 @@ constexpr float kMostlyFillViewportThresholdOfVisibleProportion = 0.75f;
MediaCustomControlsFullscreenDetector::MediaCustomControlsFullscreenDetector(
HTMLVideoElement& video)
- : EventListener(kCPPEventListenerType),
- video_element_(video),
+ : video_element_(video),
+ viewport_intersection_observer_(nullptr),
check_viewport_intersection_timer_(
video.GetDocument().GetTaskRunner(TaskType::kInternalMedia),
this,
@@ -37,11 +39,6 @@ MediaCustomControlsFullscreenDetector::MediaCustomControlsFullscreenDetector(
Attach();
}
-bool MediaCustomControlsFullscreenDetector::operator==(
- const EventListener& other) const {
- return this == &other;
-}
-
void MediaCustomControlsFullscreenDetector::Attach() {
VideoElement().addEventListener(event_type_names::kLoadedmetadata, this,
true);
@@ -49,9 +46,19 @@ void MediaCustomControlsFullscreenDetector::Attach() {
event_type_names::kWebkitfullscreenchange, this, true);
VideoElement().GetDocument().addEventListener(
event_type_names::kFullscreenchange, this, true);
+ viewport_intersection_observer_ = IntersectionObserver::Create(
+ {}, {}, &(video_element_->GetDocument()),
+ WTF::BindRepeating(
+ &MediaCustomControlsFullscreenDetector::OnIntersectionChanged,
+ WrapWeakPersistent(this)),
+ IntersectionObserver::kFractionOfTarget, 0, false, true);
}
void MediaCustomControlsFullscreenDetector::Detach() {
+ if (viewport_intersection_observer_) {
+ viewport_intersection_observer_->disconnect();
+ viewport_intersection_observer_ = nullptr;
+ }
VideoElement().removeEventListener(event_type_names::kLoadedmetadata, this,
true);
VideoElement().GetDocument().removeEventListener(
@@ -65,16 +72,16 @@ void MediaCustomControlsFullscreenDetector::Detach() {
}
bool MediaCustomControlsFullscreenDetector::ComputeIsDominantVideoForTests(
- const IntRect& target_rect,
- const IntRect& root_rect,
- const IntRect& intersection_rect) {
- if (target_rect.IsEmpty() || root_rect.IsEmpty())
+ const IntSize& target_size,
+ const IntSize& root_size,
+ const IntSize& intersection_size) {
+ if (target_size.IsEmpty() || root_size.IsEmpty())
return false;
const float x_occupation_proportion =
- 1.0f * intersection_rect.Width() / root_rect.Width();
+ 1.0f * intersection_size.Width() / root_size.Width();
const float y_occupation_proportion =
- 1.0f * intersection_rect.Height() / root_rect.Height();
+ 1.0f * intersection_size.Height() / root_size.Height();
// If the viewport is mostly occupied by the video, return true.
if (std::min(x_occupation_proportion, y_occupation_proportion) >=
@@ -92,12 +99,12 @@ bool MediaCustomControlsFullscreenDetector::ComputeIsDominantVideoForTests(
// If the video is mostly visible in the indominant dimension, return true.
// Otherwise return false.
if (x_occupation_proportion > y_occupation_proportion) {
- return target_rect.Height() *
+ return target_size.Height() *
kMostlyFillViewportThresholdOfVisibleProportion <
- intersection_rect.Height();
+ intersection_size.Height();
}
- return target_rect.Width() * kMostlyFillViewportThresholdOfVisibleProportion <
- intersection_rect.Width();
+ return target_size.Width() * kMostlyFillViewportThresholdOfVisibleProportion <
+ intersection_size.Width();
}
void MediaCustomControlsFullscreenDetector::Invoke(ExecutionContext* context,
@@ -129,15 +136,35 @@ void MediaCustomControlsFullscreenDetector::ContextDestroyed() {
void MediaCustomControlsFullscreenDetector::
OnCheckViewportIntersectionTimerFired(TimerBase*) {
DCHECK(IsVideoOrParentFullscreen());
+ if (viewport_intersection_observer_)
+ viewport_intersection_observer_->observe(&VideoElement());
+}
+
+void MediaCustomControlsFullscreenDetector::OnIntersectionChanged(
+ const HeapVector<Member<IntersectionObserverEntry>>& entries) {
+ if (!viewport_intersection_observer_ || !VideoElement().GetLayoutObject())
+ return;
+
+ // We only want a single notification, then stop observing.
+ viewport_intersection_observer_->disconnect();
+
+ const Member<IntersectionObserverEntry>& last_entry = entries.back();
- // TODO(crbug.com/906258): This can cause a crash when DCHECKs are enabled!
- IntersectionGeometry geometry(nullptr, VideoElement(), Vector<Length>(),
- true);
- geometry.ComputeGeometry();
+ // Target and intersection rects must be converted from CSS to device pixels.
+ float zoom = VideoElement().GetLayoutObject()->StyleRef().EffectiveZoom();
+ DOMRectReadOnly* target_rect = last_entry->boundingClientRect();
+ FloatSize target_size(target_rect->width(), target_rect->height());
+ target_size.Scale(zoom);
+ DOMRectReadOnly* intersection_rect = last_entry->intersectionRect();
+ FloatSize intersection_size(intersection_rect->width(),
+ intersection_rect->height());
+ intersection_size.Scale(zoom);
+ DOMRectReadOnly* root_rect = last_entry->rootBounds();
+ FloatSize root_size(root_rect->width(), root_rect->height());
bool is_dominant = ComputeIsDominantVideoForTests(
- geometry.TargetIntRect(), geometry.RootIntRect(),
- geometry.IntersectionIntRect());
+ RoundedIntSize(target_size), RoundedIntSize(root_size),
+ RoundedIntSize(intersection_size));
if (!is_dominant) {
VideoElement().SetIsEffectivelyFullscreen(
@@ -168,9 +195,10 @@ bool MediaCustomControlsFullscreenDetector::IsVideoOrParentFullscreen() {
return fullscreen_element->contains(&VideoElement());
}
-void MediaCustomControlsFullscreenDetector::Trace(blink::Visitor* visitor) {
- EventListener::Trace(visitor);
+void MediaCustomControlsFullscreenDetector::Trace(Visitor* visitor) {
+ NativeEventListener::Trace(visitor);
visitor->Trace(video_element_);
+ visitor->Trace(viewport_intersection_observer_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.h b/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.h
index 072c68fa7f6..a03841b66e9 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.h
+++ b/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector.h
@@ -5,54 +5,52 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_MEDIA_CUSTOM_CONTROLS_FULLSCREEN_DETECTOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_MEDIA_CUSTOM_CONTROLS_FULLSCREEN_DETECTOR_H_
-#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+#include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h"
#include "third_party/blink/renderer/platform/timer.h"
namespace blink {
class HTMLVideoElement;
-class IntRect;
+class IntSize;
class TimerBase;
class CORE_EXPORT MediaCustomControlsFullscreenDetector final
- : public EventListener {
+ : public NativeEventListener {
public:
explicit MediaCustomControlsFullscreenDetector(HTMLVideoElement&);
- // EventListener implementation.
- bool operator==(const EventListener&) const override;
-
void Attach();
void Detach();
void ContextDestroyed();
- void Trace(blink::Visitor*) override;
+ // EventListener implementation.
+ void Invoke(ExecutionContext*, Event*) override;
+
+ void Trace(Visitor*) override;
private:
friend class MediaCustomControlsFullscreenDetectorTest;
friend class HTMLMediaElementEventListenersTest;
- // EventListener implementation.
- void Invoke(ExecutionContext*, Event*) override;
-
HTMLVideoElement& VideoElement() { return *video_element_; }
void OnCheckViewportIntersectionTimerFired(TimerBase*);
+ void OnIntersectionChanged(
+ const HeapVector<Member<IntersectionObserverEntry>>&);
bool IsVideoOrParentFullscreen();
- static bool ComputeIsDominantVideoForTests(const IntRect& target_rect,
- const IntRect& root_rect,
- const IntRect& intersection_rect);
+ static bool ComputeIsDominantVideoForTests(const IntSize& target_size,
+ const IntSize& root_size,
+ const IntSize& intersection_size);
// `video_element_` owns |this|.
Member<HTMLVideoElement> video_element_;
+ Member<IntersectionObserver> viewport_intersection_observer_;
TaskRunnerTimer<MediaCustomControlsFullscreenDetector>
check_viewport_intersection_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaCustomControlsFullscreenDetector);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector_test.cc b/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector_test.cc
index c3f10037478..c8616b2dc45 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_custom_controls_fullscreen_detector_test.cc
@@ -71,8 +71,8 @@ class MediaCustomControlsFullscreenDetectorTest
const IntRect& root_rect,
const IntRect& intersection_rect) {
return MediaCustomControlsFullscreenDetector::
- ComputeIsDominantVideoForTests(target_rect, root_rect,
- intersection_rect);
+ ComputeIsDominantVideoForTests(target_rect.Size(), root_rect.Size(),
+ intersection_rect.Size());
}
private:
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_document.cc b/chromium/third_party/blink/renderer/core/html/media/media_document.cc
index 0cd4b9482ee..0c2805fd106 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_document.cc
@@ -54,25 +54,25 @@ namespace blink {
using namespace html_names;
-// FIXME: Share more code with PluginDocumentParser.
class MediaDocumentParser : public RawDataDocumentParser {
public:
- static MediaDocumentParser* Create(MediaDocument* document) {
- return MakeGarbageCollected<MediaDocumentParser>(document);
- }
-
explicit MediaDocumentParser(Document* document)
- : RawDataDocumentParser(document), did_build_document_structure_(false) {}
+ : RawDataDocumentParser(document) {}
private:
- void AppendBytes(const char*, size_t) override;
+ void AppendBytes(const char*, size_t) override {}
+ void Finish() override;
void CreateDocumentStructure();
- bool did_build_document_structure_;
+ bool did_build_document_structure_ = false;
};
void MediaDocumentParser::CreateDocumentStructure() {
+ if (did_build_document_structure_)
+ return;
+ did_build_document_structure_ = true;
+
DCHECK(GetDocument());
HTMLHtmlElement* root_element = HTMLHtmlElement::Create(*GetDocument());
GetDocument()->AppendChild(root_element);
@@ -109,16 +109,11 @@ void MediaDocumentParser::CreateDocumentStructure() {
if (IsDetached())
return; // DOM insertion events can detach the frame.
root_element->AppendChild(body);
-
- did_build_document_structure_ = true;
}
-void MediaDocumentParser::AppendBytes(const char*, size_t) {
- if (did_build_document_structure_)
- return;
-
+void MediaDocumentParser::Finish() {
CreateDocumentStructure();
- Finish();
+ RawDataDocumentParser::Finish();
}
MediaDocument::MediaDocument(const DocumentInit& initializer)
@@ -134,7 +129,7 @@ MediaDocument::MediaDocument(const DocumentInit& initializer)
}
DocumentParser* MediaDocument::CreateParser() {
- return MediaDocumentParser::Create(this);
+ return MakeGarbageCollected<MediaDocumentParser>(this);
}
void MediaDocument::DefaultEventHandler(Event& event) {
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc b/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
index 8ab20daca59..72d750d209a 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
@@ -64,13 +64,18 @@ bool ParseIntrinsicSizeAttribute(const String& value,
return false;
}
-void ReportUnsizedMediaViolation(const LayoutObject* layout_object) {
+void ReportUnsizedMediaViolation(const LayoutObject* layout_object,
+ bool send_report) {
const ComputedStyle& style = layout_object->StyleRef();
if (!style.LogicalWidth().IsSpecified() &&
!style.LogicalHeight().IsSpecified()) {
- layout_object->GetDocument().ReportFeaturePolicyViolation(
- mojom::FeaturePolicyFeature::kUnsizedMedia,
- mojom::FeaturePolicyDisposition::kEnforce);
+ layout_object->GetDocument().CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature::kUnsizedMedia);
+ if (send_report) {
+ layout_object->GetDocument().ReportFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature::kUnsizedMedia,
+ mojom::FeaturePolicyDisposition::kEnforce);
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.h b/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.h
index 847f8bd2805..be88a6eb092 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.h
+++ b/chromium/third_party/blink/renderer/core/html/media/media_element_parser_helpers.h
@@ -27,7 +27,12 @@ bool ParseIntrinsicSizeAttribute(const String& value,
// are not in an image or media document; returns false otherwise.
bool IsMediaElement(const Element* element);
-void ReportUnsizedMediaViolation(const LayoutObject* layout_object);
+// When |layout_object| is not properly styled (according to
+// FeaturePolocyFeature::kUnsizedMedia) this invocation counts a potential
+// violation. If |send_report| is set, then an actual violation report is
+// generated.
+void ReportUnsizedMediaViolation(const LayoutObject* layout_object,
+ bool send_report);
} // namespace media_element_parser_helpers
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.cc b/chromium/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.cc
index a9b6e631039..1bdbeef0a03 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.cc
@@ -112,12 +112,16 @@ void MediaFragmentURIParser::ParseFragments() {
// a. Decode percent-encoded octets in name and value as defined by RFC
// 3986. If either name or value are not valid percent-encoded strings,
// then remove the name-value pair from the list.
- String name = DecodeURLEscapeSequences(fragment_string.Substring(
- parameter_start, equal_offset - parameter_start));
+ String name = DecodeURLEscapeSequences(
+ fragment_string.Substring(parameter_start,
+ equal_offset - parameter_start),
+ DecodeURLMode::kUTF8OrIsomorphic);
String value;
if (equal_offset != parameter_end) {
- value = DecodeURLEscapeSequences(fragment_string.Substring(
- equal_offset + 1, parameter_end - equal_offset - 1));
+ value = DecodeURLEscapeSequences(
+ fragment_string.Substring(equal_offset + 1,
+ parameter_end - equal_offset - 1),
+ DecodeURLMode::kUTF8OrIsomorphic);
}
// b. Convert name and value to Unicode strings by interpreting them as
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
index 9b4c467f239..c704d862dac 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
@@ -144,7 +144,7 @@ void MediaRemotingInterstitial::OnPosterImageChanged() {
GetVideoElement().getAttribute(html_names::kPosterAttr));
}
-void MediaRemotingInterstitial::Trace(blink::Visitor* visitor) {
+void MediaRemotingInterstitial::Trace(Visitor* visitor) {
visitor->Trace(video_element_);
visitor->Trace(background_image_);
visitor->Trace(cast_icon_);
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h
index 3a2e574498e..6f0e77fa94e 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h
+++ b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h
@@ -48,7 +48,7 @@ class MediaRemotingInterstitial final : public HTMLDivElement {
HTMLVideoElement& GetVideoElement() const { return *video_element_; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// Node override.
diff --git a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
index a6d4939854f..1440cd737ad 100644
--- a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
@@ -45,7 +45,7 @@ class PictureInPictureInterstitial::VideoElementResizeObserverDelegate final
interstitial_->NotifyElementSizeChanged(*entries[0]->contentRect());
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(interstitial_);
ResizeObserver::Delegate::Trace(visitor);
}
@@ -160,7 +160,7 @@ void PictureInPictureInterstitial::OnPosterImageChanged() {
GetVideoElement().getAttribute(html_names::kPosterAttr));
}
-void PictureInPictureInterstitial::Trace(blink::Visitor* visitor) {
+void PictureInPictureInterstitial::Trace(Visitor* visitor) {
visitor->Trace(resize_observer_);
visitor->Trace(video_element_);
visitor->Trace(background_image_);
diff --git a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h
index 5cddd5d722d..deaaff75a85 100644
--- a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h
+++ b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h
@@ -40,7 +40,7 @@ class PictureInPictureInterstitial final : public HTMLDivElement {
void RemovedFrom(ContainerNode&) override;
// Element:
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
class VideoElementResizeObserverDelegate;
diff --git a/chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.cc b/chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.cc
new file mode 100644
index 00000000000..71f3d3c57b8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.cc
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/media/remote_playback_controller.h"
+
+namespace blink {
+
+// static
+const char RemotePlaybackController::kSupplementName[] =
+ "RemotePlaybackController";
+
+// static
+RemotePlaybackController* RemotePlaybackController::From(
+ HTMLMediaElement& element) {
+ return Supplement<HTMLMediaElement>::From<RemotePlaybackController>(element);
+}
+
+void RemotePlaybackController::Trace(Visitor* visitor) {
+ Supplement<HTMLMediaElement>::Trace(visitor);
+}
+
+RemotePlaybackController::RemotePlaybackController(HTMLMediaElement& element)
+ : Supplement<HTMLMediaElement>(element) {}
+
+// static
+void RemotePlaybackController::ProvideTo(HTMLMediaElement& element,
+ RemotePlaybackController* controller) {
+ Supplement<HTMLMediaElement>::ProvideTo(element, controller);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.h b/chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.h
new file mode 100644
index 00000000000..88a9dc312c0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/remote_playback_controller.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_REMOTE_PLAYBACK_CONTROLLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_REMOTE_PLAYBACK_CONTROLLER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class RemotePlaybackObserver;
+
+// Interface exposing RemotePlayback to core/. It is meant to replace
+// WebRemotePlaybackClient in the long run when there will be no need to expose
+// this outside of Blink.
+class CORE_EXPORT RemotePlaybackController
+ : public Supplement<HTMLMediaElement> {
+ public:
+ static const char kSupplementName[];
+
+ static RemotePlaybackController* From(HTMLMediaElement&);
+
+ virtual void AddObserver(RemotePlaybackObserver*) = 0;
+ virtual void RemoveObserver(RemotePlaybackObserver*) = 0;
+
+ void Trace(Visitor*) override;
+
+ protected:
+ explicit RemotePlaybackController(HTMLMediaElement&);
+
+ // To be called by RemotePlayback implementation to register its
+ // implementation.
+ static void ProvideTo(HTMLMediaElement&, RemotePlaybackController*);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_REMOTE_PLAYBACK_CONTROLLER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/media/remote_playback_observer.h b/chromium/third_party/blink/renderer/core/html/media/remote_playback_observer.h
new file mode 100644
index 00000000000..e9e7cc85371
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/remote_playback_observer.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_REMOTE_PLAYBACK_OBSERVER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_REMOTE_PLAYBACK_OBSERVER_H_
+
+namespace blink {
+
+enum class WebRemotePlaybackAvailability;
+enum class WebRemotePlaybackState;
+
+// Interface to be implemented by objects that intend to be notified by remote
+// playback status changes on an HTMLMediaElement. The object should self-add
+// itself to the RemotePlaybackController using the add/remove observer methods.
+class RemotePlaybackObserver : public GarbageCollectedMixin {
+ public:
+ // Called when the remote playback state is changed. The state is related to
+ // the connection to a remote device.
+ virtual void OnRemotePlaybackStateChanged(WebRemotePlaybackState) = 0;
+
+ // Called when the remote playback availability is changed. The availabality
+ // is realted to the presence of a compatible remote device on the network.
+ virtual void OnRemotePlaybackAvailabilityChanged(
+ WebRemotePlaybackAvailability) = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_REMOTE_PLAYBACK_OBSERVER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/media/video_wake_lock.cc b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock.cc
new file mode 100644
index 00000000000..d5dfeb9cd01
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock.cc
@@ -0,0 +1,117 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/media/video_wake_lock.h"
+
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/core/html/media/remote_playback_controller.h"
+
+#include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom-blink.h"
+
+namespace blink {
+
+VideoWakeLock::VideoWakeLock(HTMLVideoElement& video)
+ : PageVisibilityObserver(video.GetDocument().GetPage()),
+ video_element_(video) {
+ VideoElement().addEventListener(event_type_names::kPlaying, this, true);
+ VideoElement().addEventListener(event_type_names::kPause, this, true);
+ VideoElement().addEventListener(event_type_names::kEnterpictureinpicture,
+ this, true);
+ VideoElement().addEventListener(event_type_names::kLeavepictureinpicture,
+ this, true);
+
+ RemotePlaybackController* remote_playback_controller =
+ RemotePlaybackController::From(VideoElement());
+ if (remote_playback_controller)
+ remote_playback_controller->AddObserver(this);
+}
+
+void VideoWakeLock::PageVisibilityChanged() {
+ Update();
+}
+
+void VideoWakeLock::Trace(Visitor* visitor) {
+ NativeEventListener::Trace(visitor);
+ PageVisibilityObserver::Trace(visitor);
+ visitor->Trace(video_element_);
+}
+
+void VideoWakeLock::Invoke(ExecutionContext*, Event* event) {
+ if (event->type() == event_type_names::kPlaying) {
+ playing_ = true;
+ } else if (event->type() == event_type_names::kPause) {
+ playing_ = false;
+ } else {
+ DCHECK(event->type() == event_type_names::kEnterpictureinpicture ||
+ event->type() == event_type_names::kLeavepictureinpicture);
+ }
+
+ Update();
+}
+
+void VideoWakeLock::OnRemotePlaybackStateChanged(WebRemotePlaybackState state) {
+ remote_playback_state_ = state;
+ Update();
+}
+
+void VideoWakeLock::OnRemotePlaybackAvailabilityChanged(
+ WebRemotePlaybackAvailability) {}
+
+void VideoWakeLock::Update() {
+ bool should_be_active = ShouldBeActive();
+ if (should_be_active == active_)
+ return;
+
+ active_ = should_be_active;
+ UpdateWakeLockService();
+}
+
+bool VideoWakeLock::ShouldBeActive() const {
+ bool page_visible = GetPage() && GetPage()->IsPageVisible();
+ bool in_picture_in_picture =
+ PictureInPictureController::IsElementInPictureInPicture(&VideoElement());
+ return playing_ && (page_visible || in_picture_in_picture) &&
+ remote_playback_state_ != WebRemotePlaybackState::kConnected;
+}
+
+void VideoWakeLock::EnsureWakeLockService() {
+ if (wake_lock_service_ && wake_lock_service_.is_bound())
+ return;
+
+ LocalFrame* frame = VideoElement().GetDocument().GetFrame();
+ if (!frame)
+ return;
+
+ blink::mojom::blink::WakeLockServicePtr service;
+ frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service));
+ service->GetWakeLock(device::mojom::WakeLockType::kPreventDisplaySleep,
+ device::mojom::blink::WakeLockReason::kVideoPlayback,
+ "Video Wake Lock",
+ mojo::MakeRequest(&wake_lock_service_));
+ wake_lock_service_.set_connection_error_handler(
+ WTF::Bind(&VideoWakeLock::OnConnectionError, WrapWeakPersistent(this)));
+}
+
+void VideoWakeLock::OnConnectionError() {
+ wake_lock_service_.reset();
+}
+
+void VideoWakeLock::UpdateWakeLockService() {
+ EnsureWakeLockService();
+
+ if (!wake_lock_service_)
+ return;
+
+ if (active_)
+ wake_lock_service_->RequestWakeLock();
+ else
+ wake_lock_service_->CancelWakeLock();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/video_wake_lock.h b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock.h
new file mode 100644
index 00000000000..f3ede1b11bb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock.h
@@ -0,0 +1,83 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_VIDEO_WAKE_LOCK_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_VIDEO_WAKE_LOCK_H_
+
+#include "services/device/public/mojom/wake_lock.mojom-blink.h"
+#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_state.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+#include "third_party/blink/renderer/core/html/media/remote_playback_observer.h"
+#include "third_party/blink/renderer/core/page/page_visibility_observer.h"
+
+namespace blink {
+
+class HTMLVideoElement;
+
+// This is implementing the wake lock logic related to a video element. It will
+// take wake lock iif:
+// - the video is playing;
+// - the page is visible OR the video is in picture-in-picture;
+// - the video isn't being remoted.
+// Each video element implements its own wake lock logic. The service will then
+// merge all the requests and take the appropriate system wake lock.
+// VideoWakeLock only uses "screen" related wake lock: it prevents the screen
+// from locking on mobile or the lockscreen to show up on desktop.
+class CORE_EXPORT VideoWakeLock final : public NativeEventListener,
+ public PageVisibilityObserver,
+ public RemotePlaybackObserver {
+ USING_GARBAGE_COLLECTED_MIXIN(VideoWakeLock)
+
+ public:
+ explicit VideoWakeLock(HTMLVideoElement&);
+
+ void Trace(Visitor*) final;
+
+ // EventListener implementation.
+ void Invoke(ExecutionContext*, Event*) final;
+
+ // RemotePlaybackObserver implementation.
+ void OnRemotePlaybackStateChanged(WebRemotePlaybackState) final;
+ void OnRemotePlaybackAvailabilityChanged(WebRemotePlaybackAvailability) final;
+
+ bool active_for_tests() const { return active_; }
+
+ private:
+ // PageVisibilityObserver implementation.
+ void PageVisibilityChanged() final;
+
+ // Called when any state is changed. Will update active state and notify the
+ // service if needed.
+ void Update();
+
+ // Return whether the wake lock should be active given the current state.
+ bool ShouldBeActive() const;
+
+ // Create a mojo pointer to the wake lock service if possible.
+ void EnsureWakeLockService();
+
+ // Called when the service is no longer connected.
+ void OnConnectionError();
+
+ // Notify the wake lock service of the current wake lock state.
+ void UpdateWakeLockService();
+
+ HTMLVideoElement& VideoElement() { return *video_element_; }
+ const HTMLVideoElement& VideoElement() const { return *video_element_; }
+
+ // `video_element_` owns |this|.
+ Member<HTMLVideoElement> video_element_;
+
+ device::mojom::blink::WakeLockPtr wake_lock_service_;
+
+ bool playing_ = false;
+ bool active_ = false;
+ WebRemotePlaybackState remote_playback_state_ =
+ WebRemotePlaybackState::kDisconnected;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_VIDEO_WAKE_LOCK_H_
diff --git a/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
new file mode 100644
index 00000000000..8fd93c8e56a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
@@ -0,0 +1,223 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/media/video_wake_lock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
+#include "third_party/blink/renderer/core/html/media/html_media_test_helper.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+class VideoWakeLockMediaPlayer : public EmptyWebMediaPlayer {
+ public:
+ void EnterPictureInPicture(PipWindowOpenedCallback callback) final {
+ std::move(callback).Run(WebSize());
+ }
+
+ void ExitPictureInPicture(PipWindowClosedCallback callback) final {
+ std::move(callback).Run();
+ }
+};
+
+class VideoWakeLockTest : public PageTestBase {
+ public:
+ void SetUp() override {
+ PageTestBase::SetupPageWithClients(
+ nullptr, test::MediaStubLocalFrameClient::Create(
+ std::make_unique<VideoWakeLockMediaPlayer>()));
+
+ video_ = HTMLVideoElement::Create(GetDocument());
+ video_wake_lock_ = MakeGarbageCollected<VideoWakeLock>(*video_.Get());
+
+ GetPage().SetIsHidden(false, true);
+ }
+
+ HTMLVideoElement* Video() const { return video_.Get(); }
+ VideoWakeLock* GetVideoWakeLock() const { return video_wake_lock_.Get(); }
+
+ void SetFakeCcLayer(cc::Layer* layer) { video_->SetCcLayer(layer); }
+
+ void SimulatePlaying() {
+ video_wake_lock_->Invoke(&GetDocument(),
+ Event::Create(event_type_names::kPlaying));
+ }
+
+ void SimulatePause() {
+ video_wake_lock_->Invoke(&GetDocument(),
+ Event::Create(event_type_names::kPause));
+ }
+
+ void SimulateEnterPictureInPicture() {
+ PictureInPictureController::From(GetDocument())
+ .EnterPictureInPicture(Video(), nullptr);
+ }
+
+ void SimulateLeavePictureInPicture() {
+ PictureInPictureController::From(GetDocument())
+ .ExitPictureInPicture(Video(), nullptr);
+ }
+
+ private:
+ Persistent<HTMLVideoElement> video_;
+ Persistent<VideoWakeLock> video_wake_lock_;
+};
+
+TEST_F(VideoWakeLockTest, NoLockByDefault) {
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, PlayingVideoRequestsLock) {
+ SimulatePlaying();
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, PausingVideoCancelsLock) {
+ SimulatePlaying();
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+
+ SimulatePause();
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, HiddingPageCancelsLock) {
+ SimulatePlaying();
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+
+ GetPage().SetIsHidden(true, false);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, PlayingWhileHiddenDoesNotRequestLock) {
+ GetPage().SetIsHidden(true, false);
+ SimulatePlaying();
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, ShowingPageRequestsLock) {
+ SimulatePlaying();
+ GetPage().SetIsHidden(true, false);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+
+ GetPage().SetIsHidden(false, false);
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, ShowingPageDoNotRequestsLockIfPaused) {
+ SimulatePlaying();
+ GetPage().SetIsHidden(true, false);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+
+ SimulatePause();
+ GetPage().SetIsHidden(false, false);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, RemotePlaybackDisconnectedDoesNotCancelLock) {
+ SimulatePlaying();
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kDisconnected);
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, RemotePlaybackConnectingDoesNotCancelLock) {
+ SimulatePlaying();
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kConnecting);
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, ActiveRemotePlaybackCancelsLock) {
+ SimulatePlaying();
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kDisconnected);
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kConnected);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, LeavingRemotePlaybackResumesLock) {
+ SimulatePlaying();
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kConnected);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kDisconnected);
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, PictureInPictureLocksWhenPageNotVisible) {
+ // This initialeses the video element in order to not crash when the
+ // interstitial tries to show itself and so that the WebMediaPlayer is set up.
+ scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+ SetFakeCcLayer(layer.get());
+ Video()->SetSrc("http://example.com/foo.mp4");
+ test::RunPendingTasks();
+
+ SimulatePlaying();
+ GetPage().SetIsHidden(true, false);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+
+ SimulateEnterPictureInPicture();
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, PictureInPictureDoesNoLockWhenPaused) {
+ // This initialeses the video element in order to not crash when the
+ // interstitial tries to show itself and so that the WebMediaPlayer is set up.
+ scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+ SetFakeCcLayer(layer.get());
+ Video()->SetSrc("http://example.com/foo.mp4");
+ test::RunPendingTasks();
+
+ SimulatePlaying();
+ GetPage().SetIsHidden(true, false);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+
+ SimulatePause();
+ SimulateEnterPictureInPicture();
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, LeavingPictureInPictureCancelsLock) {
+ // This initialeses the video element in order to not crash when the
+ // interstitial tries to show itself and so that the WebMediaPlayer is set up.
+ scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+ SetFakeCcLayer(layer.get());
+ Video()->SetSrc("http://example.com/foo.mp4");
+ test::RunPendingTasks();
+
+ SimulatePlaying();
+ GetPage().SetIsHidden(true, false);
+ SimulateEnterPictureInPicture();
+ EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
+
+ SimulateLeavePictureInPicture();
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+TEST_F(VideoWakeLockTest, RemotingVideoInPictureInPictureDoesNotRequestLock) {
+ // This initialeses the video element in order to not crash when the
+ // interstitial tries to show itself and so that the WebMediaPlayer is set up.
+ scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+ SetFakeCcLayer(layer.get());
+ Video()->SetSrc("http://example.com/foo.mp4");
+ test::RunPendingTasks();
+
+ SimulatePlaying();
+ SimulateEnterPictureInPicture();
+ GetVideoWakeLock()->OnRemotePlaybackStateChanged(
+ WebRemotePlaybackState::kConnected);
+ EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media_element_filling_viewport_test.cc b/chromium/third_party/blink/renderer/core/html/media_element_filling_viewport_test.cc
index 6b7b2a69780..0be52adfdef 100644
--- a/chromium/third_party/blink/renderer/core/html/media_element_filling_viewport_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media_element_filling_viewport_test.cc
@@ -20,7 +20,7 @@ class MediaElementFillingViewportTest : public SimTest {
void SetUp() override {
SimTest::SetUp();
- WebView().Resize(WebSize(640, 480));
+ WebView().MainFrameWidget()->Resize(WebSize(640, 480));
}
bool IsMostlyFillingViewport(HTMLMediaElement* element) {
diff --git a/chromium/third_party/blink/renderer/core/html/parser/OWNERS b/chromium/third_party/blink/renderer/core/html/parser/OWNERS
index d9dc40ecfa7..23b641cfa1f 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/parser/OWNERS
@@ -1,5 +1,5 @@
kouhei@chromium.org
-yoav@yoav.ws
+yoavweiss@chromium.org
csharrison@chromium.org
# TEAM: loading-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc
index 8818320915a..43a805e7a18 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc
@@ -76,11 +76,12 @@ base::WeakPtr<BackgroundHTMLParser> BackgroundHTMLParser::Create(
void BackgroundHTMLParser::Init(
const KURL& document_url,
std::unique_ptr<CachedDocumentParameters> cached_document_parameters,
- const MediaValuesCached::MediaValuesCachedData& media_values_cached_data) {
+ const MediaValuesCached::MediaValuesCachedData& media_values_cached_data,
+ bool priority_hints_origin_trial_enabled) {
preload_scanner_.reset(new TokenPreloadScanner(
document_url, std::move(cached_document_parameters),
- media_values_cached_data,
- TokenPreloadScanner::ScannerType::kMainDocument));
+ media_values_cached_data, TokenPreloadScanner::ScannerType::kMainDocument,
+ priority_hints_origin_trial_enabled));
}
BackgroundHTMLParser::Configuration::Configuration() {}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h
index 5579a54bcbf..474f5717c33 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.h
@@ -68,7 +68,8 @@ class BackgroundHTMLParser {
scoped_refptr<base::SingleThreadTaskRunner>);
void Init(const KURL& document_url,
std::unique_ptr<CachedDocumentParameters>,
- const MediaValuesCached::MediaValuesCachedData&);
+ const MediaValuesCached::MediaValuesCachedData&,
+ bool priority_hints_origin_trial_enabled);
struct Checkpoint {
USING_FAST_MALLOC(Checkpoint);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc
index 65faae0350f..d7f729c777b 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc
@@ -385,7 +385,7 @@ HTMLConstructionSite::~HTMLConstructionSite() {
DCHECK(pending_text_.IsEmpty());
}
-void HTMLConstructionSite::Trace(blink::Visitor* visitor) {
+void HTMLConstructionSite::Trace(Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(attachment_root_);
visitor->Trace(head_);
@@ -1106,7 +1106,7 @@ void HTMLConstructionSite::FosterParent(Node* node) {
QueueTask(task);
}
-void HTMLConstructionSite::PendingText::Trace(blink::Visitor* visitor) {
+void HTMLConstructionSite::PendingText::Trace(Visitor* visitor) {
visitor->Trace(parent);
visitor->Trace(next_child);
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.h b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.h
index b0d8394321f..05dfa7bced1 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.h
@@ -53,7 +53,7 @@ struct HTMLConstructionSiteTask {
explicit HTMLConstructionSiteTask(Operation op)
: operation(op), self_closing(false) {}
- void Trace(blink::Visitor* visitor) {
+ void Trace(Visitor* visitor) {
visitor->Trace(parent);
visitor->Trace(next_child);
visitor->Trace(child);
@@ -111,7 +111,7 @@ class HTMLConstructionSite final {
Document&,
ParserContentPolicy);
~HTMLConstructionSite();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void InitFragmentParsing(DocumentFragment*, Element* context_element);
@@ -324,7 +324,7 @@ class HTMLConstructionSite final {
return string_builder.IsEmpty();
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
Member<ContainerNode> parent;
Member<Node> next_child;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index 6624165f061..10d1a09ba55 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -47,8 +47,9 @@
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/renderer/core/loader/navigation_scheduler.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/script/html_parser_script_runner.h"
#include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
@@ -166,7 +167,7 @@ void HTMLDocumentParser::Dispose() {
StopBackgroundParser();
}
-void HTMLDocumentParser::Trace(blink::Visitor* visitor) {
+void HTMLDocumentParser::Trace(Visitor* visitor) {
visitor->Trace(tree_builder_);
visitor->Trace(parser_scheduler_);
visitor->Trace(xss_auditor_delegate_);
@@ -322,7 +323,7 @@ void HTMLDocumentParser::EnqueueTokenizedChunk(
// Note that on commit, the loader dispatched preloads for all the non-media
// links.
GetDocument()->Loader()->DispatchLinkHeaderPreloads(
- &chunk->viewport, LinkLoader::kOnlyLoadMedia);
+ &chunk->viewport, PreloadHelper::kOnlyLoadMedia);
tried_loading_link_headers_ = true;
}
@@ -807,9 +808,18 @@ void HTMLDocumentParser::StartBackgroundParser() {
BackgroundHTMLParser::Create(std::move(config), loading_task_runner_);
// TODO(csharrison): This is a hack to initialize MediaValuesCached on the
// correct thread. We should get rid of it.
+
+ // TODO(domfarolino): Remove this once Priority Hints is no longer in Origin
+ // Trial. This currently exists because the TokenPreloadScanner needs to know
+ // the status of the Priority Hints Origin Trial, and has no way of figuring
+ // this out on its own. See https://crbug.com/821464.
+ bool priority_hints_origin_trial_enabled =
+ origin_trials::PriorityHintsEnabled(GetDocument());
+
background_parser_->Init(
GetDocument()->Url(), CachedDocumentParameters::Create(GetDocument()),
- MediaValuesCached::MediaValuesCachedData(*GetDocument()));
+ MediaValuesCached::MediaValuesCachedData(*GetDocument()),
+ priority_hints_origin_trial_enabled);
}
void HTMLDocumentParser::StopBackgroundParser() {
@@ -1028,10 +1038,16 @@ void HTMLDocumentParser::ResumeParsingAfterPause() {
return;
if (have_background_parser_) {
+ // If we paused in the middle of processing a token chunk,
+ // deal with that before starting to pump.
if (last_chunk_before_pause_) {
ValidateSpeculations(std::move(last_chunk_before_pause_));
DCHECK(!last_chunk_before_pause_);
PumpPendingSpeculations();
+ } else if (!IsScheduledForUnpause()) {
+ // Otherwise, start pumping if we're not already scheduled to unpause
+ // already.
+ PumpPendingSpeculations();
}
return;
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h
index 4ed141fb82b..6ee149a789c 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h
@@ -84,7 +84,7 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser,
Element* context_element,
ParserContentPolicy);
~HTMLDocumentParser() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
// TODO(alexclarke): Remove when background parser goes away.
void Dispose();
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc
index 2c95e30b151..586cfc41cc7 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_loading_test.cc
@@ -39,7 +39,8 @@ INSTANTIATE_TEST_CASE_P(NotThreaded,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldNotPauseParsingForExternalStylesheetsInHead) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -62,7 +63,8 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldNotPauseParsingForExternalStylesheetsImportedInHead) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -87,8 +89,10 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldPauseParsingForExternalStylesheetsInBody) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
- SimRequest css_body_resource("https://example.com/testBody.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource("https://example.com/testBody.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -124,17 +128,17 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldPauseParsingForExternalStylesheetsInBodyIncremental) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
- SimRequest css_body_resource1("https://example.com/testBody1.css",
- "text/css");
- SimRequest css_body_resource2("https://example.com/testBody2.css",
- "text/css");
- SimRequest css_body_resource3("https://example.com/testBody3.css",
- "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource1("https://example.com/testBody1.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource2("https://example.com/testBody2.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource3("https://example.com/testBody3.css",
+ "text/css");
LoadURL("https://example.com/test.html");
- main_resource.Start();
main_resource.Write(R"HTML(
<!DOCTYPE html>
<html><head>
@@ -211,7 +215,8 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldNotPauseParsingForExternalNonMatchingStylesheetsInBody) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -237,8 +242,10 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldPauseParsingForExternalStylesheetsImportedInBody) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
- SimRequest css_body_resource("https://example.com/testBody.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource("https://example.com/testBody.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -276,8 +283,10 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldPauseParsingForExternalStylesheetsWrittenInBody) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
- SimRequest css_body_resource("https://example.com/testBody.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
+ SimSubresourceRequest css_body_resource("https://example.com/testBody.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -315,7 +324,8 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
PendingHeadStylesheetShouldNotBlockParserForBodyInlineStyle) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -340,7 +350,8 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
PendingHeadStylesheetShouldNotBlockParserForBodyShadowDom) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_head_resource("https://example.com/testHead.css", "text/css");
+ SimSubresourceRequest css_head_resource("https://example.com/testHead.css",
+ "text/css");
LoadURL("https://example.com/test.html");
@@ -365,8 +376,8 @@ TEST_P(HTMLDocumentParserLoadingTest,
TEST_P(HTMLDocumentParserLoadingTest,
ShouldNotPauseParsingForExternalStylesheetsAttachedInBody) {
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_async_resource("https://example.com/testAsync.css",
- "text/css");
+ SimSubresourceRequest css_async_resource("https://example.com/testAsync.css",
+ "text/css");
LoadURL("https://example.com/test.html");
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc
index 12294237383..325fbbdf552 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc
@@ -74,7 +74,7 @@ TEST_F(HTMLDocumentParserTest, AppendPrefetch) {
HTMLDocument& document = ToHTMLDocument(GetDocument());
ProvidePrerendererClientTo(
*document.GetPage(),
- new MockPrerendererClient(*document.GetPage(), true));
+ MakeGarbageCollected<MockPrerendererClient>(*document.GetPage(), true));
EXPECT_TRUE(document.IsPrefetchOnly());
HTMLDocumentParser* parser = CreateParser(document);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc
index 4e98af78265..87d6b262b20 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.cc
@@ -118,7 +118,7 @@ bool HTMLElementStack::ElementRecord::IsAbove(ElementRecord* other) const {
return false;
}
-void HTMLElementStack::ElementRecord::Trace(blink::Visitor* visitor) {
+void HTMLElementStack::ElementRecord::Trace(Visitor* visitor) {
visitor->Trace(item_);
visitor->Trace(next_);
}
@@ -536,7 +536,7 @@ HTMLElementStack::FurthestBlockForFormattingElement(
return nullptr;
}
-void HTMLElementStack::Trace(blink::Visitor* visitor) {
+void HTMLElementStack::Trace(Visitor* visitor) {
visitor->Trace(top_);
visitor->Trace(root_node_);
visitor->Trace(head_element_);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h
index cdcfeea06c6..b34290c531b 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_element_stack.h
@@ -61,7 +61,7 @@ class HTMLElementStack {
ElementRecord* Next() const { return next_.Get(); }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
friend class HTMLElementStack;
@@ -165,7 +165,7 @@ class HTMLElementStack {
ContainerNode* RootNode() const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
#ifndef NDEBUG
void Show();
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h b/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h
index fe0a6e3582a..168b2cfff78 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_formatting_element_list.h
@@ -76,7 +76,7 @@ class HTMLFormattingElementList {
return !item_ ? !!element : item_->GetElement() != element;
}
- void Trace(blink::Visitor* visitor) { visitor->Trace(item_); }
+ void Trace(Visitor* visitor) { visitor->Trace(item_); }
private:
Member<HTMLStackItem> item_;
@@ -121,7 +121,7 @@ class HTMLFormattingElementList {
const Entry& at(wtf_size_t i) const { return entries_[i]; }
Entry& at(wtf_size_t i) { return entries_[i]; }
- void Trace(blink::Visitor* visitor) { visitor->Trace(entries_); }
+ void Trace(Visitor* visitor) { visitor->Trace(entries_); }
#ifndef NDEBUG
void Show();
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc
index fe9ef5812e5..1946079fa22 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
namespace blink {
@@ -41,6 +42,8 @@ HTMLParserOptions::HTMLParserOptions(Document* document) {
script_enabled = document->CanExecuteScripts(kNotAboutToExecuteScript);
plugins_enabled =
frame->Loader().AllowPlugins(kNotAboutToInstantiatePlugin);
+ priority_hints_origin_trial_enabled =
+ origin_trials::PriorityHintsEnabled(document);
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h
index 33630e22051..912415efca7 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_options.h
@@ -40,6 +40,13 @@ class CORE_EXPORT HTMLParserOptions {
bool script_enabled = false;
bool plugins_enabled = false;
+ // TODO(domfarolino): Remove this when Priority Hints is no longer in an
+ // Origin Trial. See https://crbug.com/821464.
+ // This flag is here because HTMLPreloadScanner needs to know whether or not
+ // the Priority Hints origin trial is enabled or not, and it does not have
+ // access to an ExecutionContext*, but HTMLParserOptions does.
+ bool priority_hints_origin_trial_enabled = false;
+
explicit HTMLParserOptions(Document* = nullptr);
};
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc
index 19c929216af..646d97aaea9 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.cc
@@ -25,8 +25,6 @@
#include "third_party/blink/renderer/core/html/parser/html_parser_scheduler.h"
-#include "base/feature_list.h"
-#include "base/metrics/field_trial_params.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -37,10 +35,6 @@
namespace blink {
-const base::Feature kHTMLParsingYieldTime {
- "HTMLParsingYieldTime", base::FEATURE_DISABLED_BY_DEFAULT
-};
-
PumpSession::PumpSession(unsigned& nesting_level)
: NestingLevelIncrementer(nesting_level) {}
@@ -61,22 +55,16 @@ void SpeculationsPumpSession::AddedElementTokens(size_t count) {
processed_element_tokens_ += count;
}
-const double kDefaultParserTimeLimit = 0.5;
-
HTMLParserScheduler::HTMLParserScheduler(
HTMLDocumentParser* parser,
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner)
: parser_(parser),
loading_task_runner_(std::move(loading_task_runner)),
- is_paused_with_active_timer_(false),
- parser_time_limit_(
- base::GetFieldTrialParamByFeatureAsDouble(kHTMLParsingYieldTime,
- "limit",
- kDefaultParserTimeLimit)) {}
+ is_paused_with_active_timer_(false) {}
HTMLParserScheduler::~HTMLParserScheduler() = default;
-void HTMLParserScheduler::Trace(blink::Visitor* visitor) {
+void HTMLParserScheduler::Trace(Visitor* visitor) {
visitor->Trace(parser_);
}
@@ -120,7 +108,8 @@ inline bool HTMLParserScheduler::ShouldYield(
if (ThreadScheduler::Current()->ShouldYieldForHighPriorityWork())
return true;
- if (session.ElapsedTime() > parser_time_limit_)
+ const double kParserTimeLimit = 0.5;
+ if (session.ElapsedTime() > kParserTimeLimit)
return true;
// Yield if a lot of DOM work has been done in this session and a script tag
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h
index f555db1e1c1..dd8ca0a39c2 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_scheduler.h
@@ -95,7 +95,7 @@ class HTMLParserScheduler final
void Detach(); // Clear active tasks if any.
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
bool ShouldYield(const SpeculationsPumpSession&, bool starting_script) const;
@@ -106,7 +106,6 @@ class HTMLParserScheduler final
TaskHandle cancellable_continue_parse_task_handle_;
bool is_paused_with_active_timer_;
- const double parser_time_limit_;
DISALLOW_COPY_AND_ASSIGN(HTMLParserScheduler);
};
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index 0c9a40302f3..365db5fa361 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -29,8 +29,8 @@
#include <memory>
#include "base/optional.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/media_list.h"
@@ -53,8 +53,9 @@
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
-#include "third_party/blink/renderer/core/loader/link_loader.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/script/script_loader.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
@@ -120,37 +121,6 @@ static bool MediaAttributeMatches(const MediaValuesCached& media_values,
return media_query_evaluator.Eval(*media_queries);
}
-static bool IsDimensionSmallAndAbsoluteForLazyLoad(
- const String& attribute_value) {
- // Minimum height or width of the image to start lazyloading.
- const unsigned kMinDimensionToLazyLoad = 10;
- HTMLDimension dimension;
- return ParseDimensionValue(attribute_value, dimension) &&
- dimension.IsAbsolute() && dimension.Value() <= kMinDimensionToLazyLoad;
-}
-
-static bool IsInlineStyleDimensionsSmall(const String& style_value,
- bool strict_mode) {
- // Minimum height or width of the image to start lazyloading.
- const unsigned kMinDimensionToLazyLoad = 10;
- CSSParserMode mode = strict_mode ? kHTMLStandardMode : kHTMLQuirksMode;
- const ImmutableCSSPropertyValueSet* property_set =
- CSSParser::ParseInlineStyleDeclaration(
- style_value, mode, SecureContextMode::kInsecureContext);
- const CSSValue* height = property_set->GetPropertyCSSValue(CSSPropertyHeight);
- const CSSValue* width = property_set->GetPropertyCSSValue(CSSPropertyWidth);
-
- if (!height || !height->IsPrimitiveValue() || !width ||
- !width->IsPrimitiveValue())
- return false;
- const CSSPrimitiveValue* width_prim = ToCSSPrimitiveValue(width);
- const CSSPrimitiveValue* height_prim = ToCSSPrimitiveValue(height);
- return height_prim->IsPx() &&
- (height_prim->GetDoubleValue() <= kMinDimensionToLazyLoad) &&
- width_prim->IsPx() &&
- (width_prim->GetDoubleValue() <= kMinDimensionToLazyLoad);
-}
-
class TokenPreloadScanner::StartTagScanner {
STACK_ALLOCATED();
@@ -158,7 +128,8 @@ class TokenPreloadScanner::StartTagScanner {
StartTagScanner(const StringImpl* tag_impl,
MediaValuesCached* media_values,
SubresourceIntegrity::IntegrityFeatures features,
- TokenPreloadScanner::ScannerType scanner_type)
+ TokenPreloadScanner::ScannerType scanner_type,
+ bool priority_hints_origin_trial_enabled)
: tag_impl_(tag_impl),
link_is_style_sheet_(false),
link_is_preconnect_(false),
@@ -183,13 +154,16 @@ class TokenPreloadScanner::StartTagScanner {
width_attr_small_absolute_(false),
height_attr_small_absolute_(false),
inline_style_dimensions_small_(false),
- scanner_type_(scanner_type) {
- if (Match(tag_impl_, kImgTag) || Match(tag_impl_, kSourceTag)) {
+ scanner_type_(scanner_type),
+ priority_hints_origin_trial_enabled_(
+ priority_hints_origin_trial_enabled) {
+ if (Match(tag_impl_, kImgTag) || Match(tag_impl_, kSourceTag) ||
+ Match(tag_impl_, kLinkTag)) {
source_size_ = SizesAttributeParser(media_values_, String()).length();
return;
}
- if (!Match(tag_impl_, kInputTag) && !Match(tag_impl_, kLinkTag) &&
- !Match(tag_impl_, kScriptTag) && !Match(tag_impl_, kVideoTag))
+ if (!Match(tag_impl_, kInputTag) && !Match(tag_impl_, kScriptTag) &&
+ !Match(tag_impl_, kVideoTag))
tag_impl_ = nullptr;
}
@@ -365,6 +339,10 @@ class TokenPreloadScanner::StartTagScanner {
!attribute_value.IsNull()) {
SetReferrerPolicy(attribute_value,
kDoNotSupportReferrerPolicyLegacyKeywords);
+ } else if (!importance_mode_set_ &&
+ Match(attribute_name, kImportanceAttr) &&
+ priority_hints_origin_trial_enabled_) {
+ SetImportance(attribute_value);
}
}
@@ -386,7 +364,7 @@ class TokenPreloadScanner::StartTagScanner {
SetReferrerPolicy(attribute_value, kSupportReferrerPolicyLegacyKeywords);
} else if (!importance_mode_set_ &&
Match(attribute_name, kImportanceAttr) &&
- RuntimeEnabledFeatures::PriorityHintsEnabled()) {
+ priority_hints_origin_trial_enabled_) {
SetImportance(attribute_value);
} else if (!lazyload_attr_set_to_off_ &&
Match(attribute_name, kLazyloadAttr) &&
@@ -397,17 +375,24 @@ class TokenPreloadScanner::StartTagScanner {
Match(attribute_name, kWidthAttr) &&
RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
width_attr_small_absolute_ =
- IsDimensionSmallAndAbsoluteForLazyLoad(attribute_value);
+ HTMLImageElement::IsDimensionSmallAndAbsoluteForLazyLoad(
+ attribute_value);
} else if (!height_attr_small_absolute_ &&
Match(attribute_name, kHeightAttr) &&
RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
height_attr_small_absolute_ =
- IsDimensionSmallAndAbsoluteForLazyLoad(attribute_value);
+ HTMLImageElement::IsDimensionSmallAndAbsoluteForLazyLoad(
+ attribute_value);
} else if (!inline_style_dimensions_small_ &&
Match(attribute_name, kStyleAttr) &&
RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
- inline_style_dimensions_small_ = IsInlineStyleDimensionsSmall(
- attribute_value, media_values_->StrictMode());
+ CSSParserMode mode =
+ media_values_->StrictMode() ? kHTMLStandardMode : kHTMLQuirksMode;
+ const ImmutableCSSPropertyValueSet* property_set =
+ CSSParser::ParseInlineStyleDeclaration(
+ attribute_value, mode, SecureContextMode::kInsecureContext);
+ inline_style_dimensions_small_ =
+ HTMLImageElement::IsInlineStyleDimensionsSmall(property_set);
}
}
@@ -464,7 +449,7 @@ class TokenPreloadScanner::StartTagScanner {
ParseSourceSize(attribute_value);
} else if (!importance_mode_set_ &&
Match(attribute_name, kImportanceAttr) &&
- RuntimeEnabledFeatures::PriorityHintsEnabled()) {
+ priority_hints_origin_trial_enabled_) {
SetImportance(attribute_value);
}
}
@@ -555,7 +540,7 @@ class TokenPreloadScanner::StartTagScanner {
base::Optional<ResourceType> ResourceTypeForLinkPreload() const {
DCHECK(link_is_preload_);
- return LinkLoader::GetResourceTypeFromAsAttribute(as_attribute_value_);
+ return PreloadHelper::GetResourceTypeFromAsAttribute(as_attribute_value_);
}
ResourceType GetResourceType() const {
@@ -660,7 +645,7 @@ class TokenPreloadScanner::StartTagScanner {
}
void SetImportance(const String& importance) {
- DCHECK(RuntimeEnabledFeatures::PriorityHintsEnabled());
+ DCHECK(priority_hints_origin_trial_enabled_);
importance_mode_set_ = true;
importance_ = GetFetchImportanceAttributeValue(importance);
}
@@ -706,13 +691,16 @@ class TokenPreloadScanner::StartTagScanner {
bool height_attr_small_absolute_;
bool inline_style_dimensions_small_;
TokenPreloadScanner::ScannerType scanner_type_;
+ // For explanation, see TokenPreloadScanner's declaration.
+ bool priority_hints_origin_trial_enabled_;
};
TokenPreloadScanner::TokenPreloadScanner(
const KURL& document_url,
std::unique_ptr<CachedDocumentParameters> document_parameters,
const MediaValuesCached::MediaValuesCachedData& media_values_cached_data,
- const ScannerType scanner_type)
+ const ScannerType scanner_type,
+ bool priority_hints_origin_trial_enabled)
: document_url_(document_url),
in_style_(false),
in_picture_(false),
@@ -721,6 +709,7 @@ TokenPreloadScanner::TokenPreloadScanner(
document_parameters_(std::move(document_parameters)),
media_values_(MediaValuesCached::Create(media_values_cached_data)),
scanner_type_(scanner_type),
+ priority_hints_origin_trial_enabled_(priority_hints_origin_trial_enabled),
did_rewind_(false) {
DCHECK(document_parameters_.get());
DCHECK(media_values_.Get());
@@ -931,9 +920,9 @@ void TokenPreloadScanner::ScanCommon(const Token& token,
return;
}
- StartTagScanner scanner(tag_impl, media_values_,
- document_parameters_->integrity_features,
- scanner_type_);
+ StartTagScanner scanner(
+ tag_impl, media_values_, document_parameters_->integrity_features,
+ scanner_type_, priority_hints_origin_trial_enabled_);
scanner.ProcessAttributes(token.Attributes());
// TODO(yoav): ViewportWidth is currently racy and might be zero in some
// cases, at least in tests. That problem will go away once
@@ -972,7 +961,8 @@ HTMLPreloadScanner::HTMLPreloadScanner(
: scanner_(document_url,
std::move(document_parameters),
media_values_cached_data,
- scanner_type),
+ scanner_type,
+ options.priority_hints_origin_trial_enabled),
tokenizer_(HTMLTokenizer::Create(options)) {}
HTMLPreloadScanner::~HTMLPreloadScanner() = default;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h
index 881c54bded9..9dc91e1357b 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h
@@ -90,7 +90,8 @@ class TokenPreloadScanner {
TokenPreloadScanner(const KURL& document_url,
std::unique_ptr<CachedDocumentParameters>,
const MediaValuesCached::MediaValuesCachedData&,
- const ScannerType);
+ const ScannerType,
+ bool priority_hints_origin_trial_enabled);
~TokenPreloadScanner();
void Scan(const HTMLToken&,
@@ -162,6 +163,12 @@ class TokenPreloadScanner {
Persistent<MediaValuesCached> media_values_;
ClientHintsPreferences client_hints_preferences_;
ScannerType scanner_type_;
+ // TODO(domfarolino): Remove this once Priority Hints is no longer in Origin
+ // Trial (see https://crbug.com/821464). This member exists because
+ // HTMLPreloadScanner has no access to an ExecutionContext*, and therefore
+ // cannot determine an Origin Trial's status, so we accept this information in
+ // the constructor and set this flag accordingly.
+ bool priority_hints_origin_trial_enabled_;
bool did_rewind_ = false;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc b/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
index d0485f78c89..074049f3e8c 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
@@ -42,16 +42,10 @@ HTMLResourcePreloader* HTMLResourcePreloader::Create(Document& document) {
return MakeGarbageCollected<HTMLResourcePreloader>(document);
}
-void HTMLResourcePreloader::Trace(blink::Visitor* visitor) {
+void HTMLResourcePreloader::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
-int HTMLResourcePreloader::CountPreloads() {
- if (document_->Loader())
- return document_->Loader()->Fetcher()->CountPreloads();
- return 0;
-}
-
static void PreconnectHost(
PreloadRequest* request,
const NetworkHintsInterface& network_hints_interface) {
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.h b/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.h
index 3c431cabb2f..3dad651d22c 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader.h
@@ -50,9 +50,7 @@ class CORE_EXPORT HTMLResourcePreloader
explicit HTMLResourcePreloader(Document&);
- int CountPreloads();
- Document* GetDocument() { return document_.Get(); }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
protected:
void Preload(std::unique_ptr<PreloadRequest>,
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_stack_item.h b/chromium/third_party/blink/renderer/core/html/parser/html_stack_item.h
index d25fe96a9dd..d2778afd1d0 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_stack_item.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_stack_item.h
@@ -218,7 +218,7 @@ class HTMLStackItem : public GarbageCollectedFinalized<HTMLStackItem> {
tag_name == html_names::kWbrTag || tag_name == html_names::kXmpTag;
}
- void Trace(blink::Visitor* visitor) { visitor->Trace(node_); }
+ void Trace(Visitor* visitor) { visitor->Trace(node_); }
private:
Member<ContainerNode> node_;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc
index e927e6bb24c..64364a8af7d 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_tokenizer_fuzzer.cc
@@ -30,9 +30,8 @@ int FuzzTokenizer(const uint8_t* data, size_t size) {
// The tokenizer deals with incremental strings as they are received.
// Split the input into a bunch of small chunks to throw partial tokens
// at the tokenizer and exercise the state machine and resumption.
- CString chunk = fuzzed_data_provider.ConsumeBytesInRange(1, 32);
- SegmentedString segment(String(chunk.data(), chunk.length()));
- input.Append(segment);
+ String chunk = fuzzed_data_provider.ConsumeRandomLengthString(32);
+ input.Append(SegmentedString(chunk));
// If a token was generated from the input then the next call
// needs to use a fresh token for output. If a token is not generated
// then the same token instance needs to be reused in the next calls
@@ -48,7 +47,8 @@ int FuzzTokenizer(const uint8_t* data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Need at least 2 bytes for the options flags and one byte of test data.
- if (size >= 3)
+ // Avoid huge inputs which can cause non-actionable timeout crashes.
+ if (size >= 3 && size <= 16384)
blink::FuzzTokenizer(data, size);
return 0;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index 4d0b1346265..7075f10d6c8 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -269,12 +269,12 @@ void HTMLTreeBuilder::FragmentParsingContext::Init(DocumentFragment* fragment,
context_element, HTMLStackItem::kItemForContextElement);
}
-void HTMLTreeBuilder::FragmentParsingContext::Trace(blink::Visitor* visitor) {
+void HTMLTreeBuilder::FragmentParsingContext::Trace(Visitor* visitor) {
visitor->Trace(fragment_);
visitor->Trace(context_element_stack_item_);
}
-void HTMLTreeBuilder::Trace(blink::Visitor* visitor) {
+void HTMLTreeBuilder::Trace(Visitor* visitor) {
visitor->Trace(fragment_context_);
visitor->Trace(tree_);
visitor->Trace(parser_);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h
index 8615b67c5fa..20a49fc3fda 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h
@@ -78,7 +78,7 @@ class HTMLTreeBuilder final
ParserContentPolicy,
const HTMLParserOptions&);
~HTMLTreeBuilder();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
const HTMLElementStack* OpenElements() const { return tree_.OpenElements(); }
@@ -233,7 +233,7 @@ class HTMLTreeBuilder final
return context_element_stack_item_.Get();
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Member<DocumentFragment> fragment_;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc b/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc
index 892cf94dece..889dbb732dd 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
#include "third_party/blink/renderer/core/script/document_write_intervention.h"
#include "third_party/blink/renderer/core/script/script_loader.h"
#include "third_party/blink/renderer/platform/cross_origin_attribute_value.h"
@@ -113,7 +114,8 @@ Resource* PreloadRequest::Start(Document* document) {
}
}
- return document->Loader()->StartPreload(resource_type_, params);
+ return PreloadHelper::StartPreload(resource_type_, params,
+ document->Fetcher());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/parser/preload_request.h b/chromium/third_party/blink/renderer/core/html/parser/preload_request.h
index dbe82c976f8..82bf24aae89 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/preload_request.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/preload_request.h
@@ -8,8 +8,8 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/script/script.h"
#include "third_party/blink/renderer/platform/cross_origin_attribute_value.h"
diff --git a/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc b/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc
index 8ff95d82df8..d5c6c8ef231 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc
@@ -203,6 +203,12 @@ static int FindXMLEncoding(const char* str, int len, int& encoding_length) {
wtf_size_t TextResourceDecoder::CheckForBOM(const char* data, wtf_size_t len) {
// Check for UTF-16 or UTF-8 BOM mark at the beginning, which is a sure
// sign of a Unicode encoding. We let it override even a user-chosen encoding.
+
+ // if |options_|'s value corresponds to #decode or #utf-8-decode,
+ // CheckForBOM() corresponds to
+ // - Steps 1-6 of https://encoding.spec.whatwg.org/#decode or
+ // - Steps 1-3 of https://encoding.spec.whatwg.org/#utf-8-decode,
+ // respectively.
DCHECK(!checked_for_bom_);
wtf_size_t length_of_bom = 0;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.h b/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.h
index dd03aaa2a8f..f05f096ea40 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder.h
@@ -36,6 +36,10 @@ namespace blink {
class HTMLMetaCharsetParser;
+// Implements https://encoding.spec.whatwg.org/#decode or
+// https://encoding.spec.whatwg.org/#utf-8-decode when an appropriate
+// TextResourceDecoderOptions is given.
+// See comments in text_resource_decoder_options.h.
class CORE_EXPORT TextResourceDecoder {
USING_FAST_MALLOC(TextResourceDecoder);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder_for_fuzzing.h b/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder_for_fuzzing.h
index d71506c9ede..02487b84e56 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder_for_fuzzing.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/text_resource_decoder_for_fuzzing.h
@@ -51,8 +51,7 @@ class TextResourceDecoderForFuzzing : public TextResourceDecoder {
// Note: Charsets can be long (see the various encodings in
// wtf/text). For instance: "unicode-1-1-utf-8". To ensure good coverage,
// set a generous max limit for these sizes (32 bytes should be good).
- return WTF::TextEncoding(
- String::FromUTF8(fuzzed_data.ConsumeBytesInRange(0, 32)));
+ return WTF::TextEncoding(fuzzed_data.ConsumeRandomLengthString(32));
}
};
diff --git a/chromium/third_party/blink/renderer/core/html/parser/xss_auditor.cc b/chromium/third_party/blink/renderer/core/html/parser/xss_auditor.cc
index 0ed6267168d..05e8e9fbd6d 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/xss_auditor.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/xss_auditor.cc
@@ -454,7 +454,7 @@ void XSSAuditor::Init(Document* document,
if (auditor_delegate)
auditor_delegate->SetReportURL(xss_protection_report_url.Copy());
- EncodedFormData* http_body = document_loader->GetRequest().HttpBody();
+ EncodedFormData* http_body = document_loader->HttpBody();
if (http_body && !http_body->IsEmpty())
http_body_as_string_ = http_body->FlattenToString();
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc b/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc
index 609c93215fb..240cc29c9bb 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc
@@ -72,7 +72,7 @@ XSSAuditorDelegate::XSSAuditorDelegate(Document* document)
DCHECK(document_);
}
-void XSSAuditorDelegate::Trace(blink::Visitor* visitor) {
+void XSSAuditorDelegate::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
@@ -84,7 +84,7 @@ scoped_refptr<EncodedFormData> XSSAuditorDelegate::GenerateViolationReport(
String http_body;
if (frame_loader.GetDocumentLoader()) {
if (EncodedFormData* form_data =
- frame_loader.GetDocumentLoader()->OriginalRequest().HttpBody())
+ frame_loader.GetDocumentLoader()->HttpBody())
http_body = form_data->FlattenToString();
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.h b/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.h
index 261edde516d..4379dbb48c8 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.h
@@ -75,7 +75,7 @@ class XSSAuditorDelegate final {
public:
explicit XSSAuditorDelegate(Document*);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
void DidBlockScript(const XSSInfo&);
void SetReportURL(const KURL& url) { report_url_ = url; }
diff --git a/chromium/third_party/blink/renderer/core/html/plugin_document.cc b/chromium/third_party/blink/renderer/core/html/plugin_document.cc
index 70c83c295de..5a716766043 100644
--- a/chromium/third_party/blink/renderer/core/html/plugin_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/plugin_document.cc
@@ -26,7 +26,7 @@
#include "third_party/blink/renderer/core/css/css_color_value.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/raw_data_document_parser.h"
#include "third_party/blink/renderer/core/events/before_unload_event.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
@@ -49,26 +49,22 @@ namespace blink {
using namespace html_names;
-class PluginDocument::BeforeUnloadEventListener : public EventListener {
+class PluginDocument::BeforeUnloadEventListener : public NativeEventListener {
public:
static BeforeUnloadEventListener* Create(PluginDocument* document) {
return MakeGarbageCollected<BeforeUnloadEventListener>(document);
}
explicit BeforeUnloadEventListener(PluginDocument* document)
- : EventListener(kCPPEventListenerType), doc_(document) {}
-
- bool operator==(const EventListener& listener) const override {
- return this == &listener;
- }
+ : doc_(document) {}
void SetShowBeforeUnloadDialog(bool show_dialog) {
show_dialog_ = show_dialog;
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(doc_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
}
private:
@@ -96,15 +92,15 @@ class PluginDocumentParser : public RawDataDocumentParser {
embed_element_(nullptr),
background_color_(background_color) {}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(embed_element_);
RawDataDocumentParser::Trace(visitor);
}
private:
void AppendBytes(const char*, size_t) override;
-
void Finish() override;
+ void StopParsing() override;
void CreateDocumentStructure();
@@ -115,6 +111,9 @@ class PluginDocumentParser : public RawDataDocumentParser {
};
void PluginDocumentParser::CreateDocumentStructure() {
+ if (embed_element_)
+ return;
+
// FIXME: Assert we have a loader to figure out why the original null checks
// and assert were added for the security bug in
// http://trac.webkit.org/changeset/87566
@@ -187,12 +186,9 @@ void PluginDocumentParser::CreateDocumentStructure() {
}
void PluginDocumentParser::AppendBytes(const char* data, size_t length) {
- if (!embed_element_) {
- CreateDocumentStructure();
- if (IsStopped())
- return;
- }
-
+ CreateDocumentStructure();
+ if (IsStopped())
+ return;
if (!length)
return;
if (WebPluginContainerImpl* view = GetPluginView())
@@ -200,10 +196,16 @@ void PluginDocumentParser::AppendBytes(const char* data, size_t length) {
}
void PluginDocumentParser::Finish() {
+ CreateDocumentStructure();
embed_element_ = nullptr;
RawDataDocumentParser::Finish();
}
+void PluginDocumentParser::StopParsing() {
+ CreateDocumentStructure();
+ RawDataDocumentParser::StopParsing();
+}
+
WebPluginContainerImpl* PluginDocumentParser::GetPluginView() const {
return ToPluginDocument(GetDocument())->GetPluginView();
}
@@ -243,7 +245,7 @@ void PluginDocument::Shutdown() {
HTMLDocument::Shutdown();
}
-void PluginDocument::Trace(blink::Visitor* visitor) {
+void PluginDocument::Trace(Visitor* visitor) {
visitor->Trace(plugin_node_);
visitor->Trace(before_unload_event_listener_);
HTMLDocument::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/plugin_document.h b/chromium/third_party/blink/renderer/core/html/plugin_document.h
index 8339e572464..7426183a501 100644
--- a/chromium/third_party/blink/renderer/core/html/plugin_document.h
+++ b/chromium/third_party/blink/renderer/core/html/plugin_document.h
@@ -54,7 +54,7 @@ class CORE_EXPORT PluginDocument final : public HTMLDocument {
void Shutdown() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
class BeforeUnloadEventListener;
diff --git a/chromium/third_party/blink/renderer/core/html/portal/document_portals.cc b/chromium/third_party/blink/renderer/core/html/portal/document_portals.cc
index 4afc5ddc4fe..0f99eb2fa44 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/document_portals.cc
+++ b/chromium/third_party/blink/renderer/core/html/portal/document_portals.cc
@@ -16,7 +16,7 @@ DocumentPortals& DocumentPortals::From(Document& document) {
DocumentPortals* supplement =
Supplement<Document>::From<DocumentPortals>(document);
if (!supplement) {
- supplement = new DocumentPortals(document);
+ supplement = MakeGarbageCollected<DocumentPortals>(document);
Supplement<Document>::ProvideTo(document, supplement);
}
return *supplement;
diff --git a/chromium/third_party/blink/renderer/core/html/portal/document_portals.h b/chromium/third_party/blink/renderer/core/html/portal/document_portals.h
index 6c9ec61adcd..4414d2a1c91 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/document_portals.h
+++ b/chromium/third_party/blink/renderer/core/html/portal/document_portals.h
@@ -30,11 +30,16 @@ class DocumentPortals : public GarbageCollected<DocumentPortals>,
// Retrieves the portal identified by the token.
HTMLPortalElement* GetPortal(const base::UnguessableToken&) const;
- void Trace(Visitor*) override;
+ // Retrieves all portals in the document.
+ const HeapVector<Member<HTMLPortalElement>>& GetPortals() const {
+ return portals_;
+ }
- private:
explicit DocumentPortals(Document&);
+ void Trace(Visitor*) override;
+
+ private:
HeapVector<Member<HTMLPortalElement>> portals_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.cc b/chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.cc
new file mode 100644
index 00000000000..85e3cc58540
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.cc
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/portal/dom_window_portal_host.h"
+
+namespace blink {
+
+// static
+PortalHost* DOMWindowPortalHost::portalHost(LocalDOMWindow& window) {
+ return nullptr;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.h b/chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.h
new file mode 100644
index 00000000000..96e0154f385
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/portal/dom_window_portal_host.h
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PORTAL_DOM_WINDOW_PORTAL_HOST_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PORTAL_DOM_WINDOW_PORTAL_HOST_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+
+namespace blink {
+
+class LocalDOMWindow;
+class PortalHost;
+
+class CORE_EXPORT DOMWindowPortalHost {
+ public:
+ static PortalHost* portalHost(LocalDOMWindow& window);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PORTAL_DOM_WINDOW_PORTAL_HOST_H_
diff --git a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc
index 617ddfff7e8..87081ef45ba 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc
@@ -11,10 +11,13 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/frame/remote_frame.h"
#include "third_party/blink/renderer/core/html/html_unknown_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html/portal/document_portals.h"
#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/layout/layout_iframe.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -27,6 +30,11 @@ HTMLPortalElement::HTMLPortalElement(Document& document)
HTMLPortalElement::~HTMLPortalElement() {}
+void HTMLPortalElement::Trace(Visitor* visitor) {
+ HTMLFrameOwnerElement::Trace(visitor);
+ visitor->Trace(portal_frame_);
+}
+
HTMLElement* HTMLPortalElement::Create(Document& document) {
if (RuntimeEnabledFeatures::PortalsEnabled())
return MakeGarbageCollected<HTMLPortalElement>(document);
@@ -80,15 +88,10 @@ HTMLPortalElement::InsertionNotificationRequest HTMLPortalElement::InsertedInto(
Document& document = GetDocument();
if (node.IsInDocumentTree() && document.IsHTMLDocument()) {
- document.GetFrame()->GetInterfaceProvider().GetInterface(
- mojo::MakeRequest(&portal_ptr_));
- portal_ptr_->Init(WTF::Bind(
- [](HTMLPortalElement* portal,
- const base::UnguessableToken& portal_token) {
- portal->portal_token_ = portal_token;
- DocumentPortals::From(portal->GetDocument()).OnPortalInserted(portal);
- },
- WrapPersistent(this)));
+ std::tie(portal_frame_, portal_token_) =
+ GetDocument().GetFrame()->Client()->CreatePortal(
+ this, mojo::MakeRequest(&portal_ptr_));
+ DocumentPortals::From(GetDocument()).OnPortalInserted(this);
Navigate();
}
@@ -126,4 +129,9 @@ void HTMLPortalElement::ParseAttribute(
Navigate();
}
+LayoutObject* HTMLPortalElement::CreateLayoutObject(
+ const ComputedStyle& style) {
+ return new LayoutIFrame(this);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h
index 6c801cc24a8..d1ac773b7b4 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h
+++ b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h
@@ -15,15 +15,14 @@
namespace blink {
class Document;
+class RemoteFrame;
class ScriptState;
// The HTMLPortalElement implements the <portal> HTML element. The portal
// element can be used to embed another top-level browsing context, which can be
// activated using script. The portal element is still under development and not
// part of the HTML standard. It can be enabled by passing
-// --enable-features=Portals. See
-// https://github.com/KenjiBaheux/portals/blob/master/explainer.md for more
-// details.
+// --enable-features=Portals. See also https://github.com/WICG/portals.
class CORE_EXPORT HTMLPortalElement : public HTMLFrameOwnerElement {
DEFINE_WRAPPERTYPEINFO();
@@ -33,6 +32,9 @@ class CORE_EXPORT HTMLPortalElement : public HTMLFrameOwnerElement {
explicit HTMLPortalElement(Document&);
~HTMLPortalElement() override;
+ // ScriptWrappable overrides.
+ void Trace(Visitor* visitor) override;
+
// idl implementation.
ScriptPromise activate(ScriptState*);
@@ -53,6 +55,7 @@ class CORE_EXPORT HTMLPortalElement : public HTMLFrameOwnerElement {
// Element overrides
bool IsURLAttribute(const Attribute&) const override;
void ParseAttribute(const AttributeModificationParams&) override;
+ LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
// HTMLFrameOwnerElement overrides
ParsedFeaturePolicy ConstructContainerPolicy(Vector<String>*) const override {
@@ -63,6 +66,8 @@ class CORE_EXPORT HTMLPortalElement : public HTMLFrameOwnerElement {
// to reference this portal when communicating with the renderer.
base::UnguessableToken portal_token_;
+ Member<RemoteFrame> portal_frame_;
+
mojom::blink::PortalPtr portal_ptr_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl
index c6890ddfcba..ba90bbdf4b3 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://github.com/KenjiBaheux/portals/blob/master/explainer.md
+// https://wicg.github.io/portals/#the-portal-element
[HTMLConstructor, RuntimeEnabled=Portals]
interface HTMLPortalElement : HTMLElement {
diff --git a/chromium/third_party/blink/renderer/core/html/portal/portal_host.h b/chromium/third_party/blink/renderer/core/html/portal/portal_host.h
new file mode 100644
index 00000000000..f40660728f4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/portal/portal_host.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PORTAL_PORTAL_HOST_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PORTAL_PORTAL_HOST_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+
+namespace blink {
+
+class CORE_EXPORT PortalHost : public EventTargetWithInlineData {
+ DEFINE_WRAPPERTYPEINFO();
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PORTAL_PORTAL_HOST_H_
diff --git a/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl b/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl
new file mode 100644
index 00000000000..7d972d0f34b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/portals/#the-portalhost-interface
+
+[RuntimeEnabled=Portals]
+interface PortalHost : EventTarget {};
diff --git a/chromium/third_party/blink/renderer/core/html/portal/window_portal_host.idl b/chromium/third_party/blink/renderer/core/html/portal/window_portal_host.idl
new file mode 100644
index 00000000000..becf8ac741a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/portal/window_portal_host.idl
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/portals/#miscellaneous-extensions
+
+[
+ ImplementedAs=DOMWindowPortalHost
+] partial interface Window {
+ [RuntimeEnabled=Portals] readonly attribute PortalHost? portalHost;
+};
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc
index 0532db10600..09230015934 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc
@@ -36,7 +36,9 @@
namespace blink {
ProgressShadowElement::ProgressShadowElement(Document& document)
- : HTMLDivElement(document) {}
+ : HTMLDivElement(document) {
+ SetHasCustomStyleCallbacks();
+}
DEFINE_NODE_FACTORY(ProgressShadowElement)
@@ -44,11 +46,14 @@ HTMLProgressElement* ProgressShadowElement::ProgressElement() const {
return ToHTMLProgressElement(OwnerShadowHost());
}
-bool ProgressShadowElement::LayoutObjectIsNeeded(
- const ComputedStyle& style) const {
+scoped_refptr<ComputedStyle>
+ProgressShadowElement::CustomStyleForLayoutObject() {
+ scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
const ComputedStyle* progress_style = ProgressElement()->GetComputedStyle();
- return progress_style && !progress_style->HasAppearance() &&
- HTMLDivElement::LayoutObjectIsNeeded(style);
+ DCHECK(progress_style);
+ if (progress_style->HasAppearance())
+ style->SetDisplay(EDisplay::kNone);
+ return style;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h
index 9e2d21ede52..f8d63f94451 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h
+++ b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h
@@ -43,10 +43,11 @@ class ProgressShadowElement : public HTMLDivElement {
public:
DECLARE_NODE_FACTORY(ProgressShadowElement);
- private:
explicit ProgressShadowElement(Document&);
+
+ private:
HTMLProgressElement* ProgressElement() const;
- bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/track/audio_track.cc b/chromium/third_party/blink/renderer/core/html/track/audio_track.cc
index 00f59bd06f8..c89577c2aeb 100644
--- a/chromium/third_party/blink/renderer/core/html/track/audio_track.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/audio_track.cc
@@ -18,7 +18,7 @@ AudioTrack::AudioTrack(const String& id,
AudioTrack::~AudioTrack() = default;
-void AudioTrack::Trace(blink::Visitor* visitor) {
+void AudioTrack::Trace(Visitor* visitor) {
ScriptWrappable::Trace(visitor);
TrackBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/audio_track.h b/chromium/third_party/blink/renderer/core/html/track/audio_track.h
index 27de0f4887e..db86e9f3df1 100644
--- a/chromium/third_party/blink/renderer/core/html/track/audio_track.h
+++ b/chromium/third_party/blink/renderer/core/html/track/audio_track.h
@@ -21,12 +21,18 @@ class CORE_EXPORT AudioTrack final : public ScriptWrappable, public TrackBase {
const AtomicString& label,
const AtomicString& language,
bool enabled) {
- return new AudioTrack(id, IsValidKindKeyword(kind) ? kind : g_empty_atom,
- label, language, enabled);
+ return MakeGarbageCollected<AudioTrack>(
+ id, IsValidKindKeyword(kind) ? kind : g_empty_atom, label, language,
+ enabled);
}
+ AudioTrack(const String& id,
+ const AtomicString& kind,
+ const AtomicString& label,
+ const AtomicString& language,
+ bool enabled);
~AudioTrack() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
bool enabled() const { return enabled_; }
void setEnabled(bool);
@@ -42,12 +48,6 @@ class CORE_EXPORT AudioTrack final : public ScriptWrappable, public TrackBase {
static bool IsValidKindKeyword(const String&);
private:
- AudioTrack(const String& id,
- const AtomicString& kind,
- const AtomicString& label,
- const AtomicString& language,
- bool enabled);
-
bool enabled_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/track/audio_track_list.cc b/chromium/third_party/blink/renderer/core/html/track/audio_track_list.cc
index 0b9cb73be56..e9374a9a1ab 100644
--- a/chromium/third_party/blink/renderer/core/html/track/audio_track_list.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/audio_track_list.cc
@@ -7,7 +7,7 @@
namespace blink {
AudioTrackList* AudioTrackList::Create(HTMLMediaElement& media_element) {
- return new AudioTrackList(media_element);
+ return MakeGarbageCollected<AudioTrackList>(media_element);
}
AudioTrackList::~AudioTrackList() = default;
diff --git a/chromium/third_party/blink/renderer/core/html/track/audio_track_list.h b/chromium/third_party/blink/renderer/core/html/track/audio_track_list.h
index 7d0f9ee91a5..44d62feecfa 100644
--- a/chromium/third_party/blink/renderer/core/html/track/audio_track_list.h
+++ b/chromium/third_party/blink/renderer/core/html/track/audio_track_list.h
@@ -16,6 +16,7 @@ class CORE_EXPORT AudioTrackList final : public TrackListBase<AudioTrack> {
public:
static AudioTrackList* Create(HTMLMediaElement&);
+ explicit AudioTrackList(HTMLMediaElement&);
~AudioTrackList() override;
bool HasEnabledTrack() const;
@@ -23,12 +24,9 @@ class CORE_EXPORT AudioTrackList final : public TrackListBase<AudioTrack> {
// EventTarget
const AtomicString& InterfaceName() const override;
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
TrackListBase<AudioTrack>::Trace(visitor);
}
-
- private:
- explicit AudioTrackList(HTMLMediaElement&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc
index 37f7e02c0fb..006048780ea 100644
--- a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc
@@ -363,7 +363,7 @@ void CueTimeline::EndIgnoringUpdateRequests() {
UpdateActiveCues(MediaElement().currentTime());
}
-void CueTimeline::Trace(blink::Visitor* visitor) {
+void CueTimeline::Trace(Visitor* visitor) {
visitor->Trace(media_element_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h
index 18869dd4b9f..ad33240e593 100644
--- a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h
+++ b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h
@@ -47,7 +47,7 @@ class CueTimeline final : public GarbageCollectedFinalized<CueTimeline> {
const CueList& CurrentlyActiveCues() const { return currently_active_cues_; }
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
HTMLMediaElement& MediaElement() const { return *media_element_; }
diff --git a/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc b/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc
index 21b74d44baa..09fc6187a92 100644
--- a/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc
@@ -60,10 +60,11 @@ DEFINE_NODE_FACTORY(HTMLTrackElement)
HTMLTrackElement::~HTMLTrackElement() = default;
-const HashSet<AtomicString>& HTMLTrackElement::GetCheckedAttributeNames()
+const AttrNameToTrustedType& HTMLTrackElement::GetCheckedAttributeTypes()
const {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"src"}));
- return attribute_set;
+ DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
+ ({{"src", SpecificTrustedType::kTrustedURL}}));
+ return attribute_map;
}
Node::InsertionNotificationRequest HTMLTrackElement::InsertedInto(
@@ -339,7 +340,7 @@ HTMLMediaElement* HTMLTrackElement::MediaElement() const {
return nullptr;
}
-void HTMLTrackElement::Trace(blink::Visitor* visitor) {
+void HTMLTrackElement::Trace(Visitor* visitor) {
visitor->Trace(track_);
visitor->Trace(loader_);
HTMLElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/track/html_track_element.h b/chromium/third_party/blink/renderer/core/html/track/html_track_element.h
index a4f31081dd1..b51d357be19 100644
--- a/chromium/third_party/blink/renderer/core/html/track/html_track_element.h
+++ b/chromium/third_party/blink/renderer/core/html/track/html_track_element.h
@@ -44,8 +44,10 @@ class HTMLTrackElement final : public HTMLElement,
public:
DECLARE_NODE_FACTORY(HTMLTrackElement);
+ explicit HTMLTrackElement(Document&);
+
// Returns attributes that should be checked against Trusted Types
- const HashSet<AtomicString>& GetCheckedAttributeNames() const override;
+ const AttrNameToTrustedType& GetCheckedAttributeTypes() const override;
const AtomicString& kind();
void setKind(const AtomicString&);
@@ -56,10 +58,9 @@ class HTMLTrackElement final : public HTMLElement,
TextTrack* track();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
- explicit HTMLTrackElement(Document&);
~HTMLTrackElement() override;
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/track/html_track_element.idl b/chromium/third_party/blink/renderer/core/html/track/html_track_element.idl
index bcafa6726f3..001cabc9d9c 100644
--- a/chromium/third_party/blink/renderer/core/html/track/html_track_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/track/html_track_element.idl
@@ -25,9 +25,6 @@
// https://html.spec.whatwg.org/#the-track-element
-// The `URLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
[HTMLConstructor]
interface HTMLTrackElement : HTMLElement {
[CEReactions] attribute DOMString kind;
diff --git a/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.cc b/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.cc
index adc5bf3e86d..560607a0243 100644
--- a/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.cc
@@ -63,7 +63,7 @@ wtf_size_t LoadableTextTrack::TrackElementIndex() const {
return index;
}
-void LoadableTextTrack::Trace(blink::Visitor* visitor) {
+void LoadableTextTrack::Trace(Visitor* visitor) {
visitor->Trace(track_element_);
TextTrack::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.h b/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.h
index 2a5f44c740b..f27a7e18739 100644
--- a/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.h
+++ b/chromium/third_party/blink/renderer/core/html/track/loadable_text_track.h
@@ -53,7 +53,7 @@ class LoadableTextTrack final : public TextTrack {
bool IsDefault() const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<HTMLTrackElement> track_element_;
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track.cc b/chromium/third_party/blink/renderer/core/html/track/text_track.cc
index 59c52cdb198..7a05be9cb9c 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track.cc
@@ -368,7 +368,7 @@ Node* TextTrack::Owner() const {
return MediaElement();
}
-void TextTrack::Trace(blink::Visitor* visitor) {
+void TextTrack::Trace(Visitor* visitor) {
visitor->Trace(cues_);
visitor->Trace(active_cues_);
visitor->Trace(track_list_);
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track.h b/chromium/third_party/blink/renderer/core/html/track/text_track.h
index 6f291977244..6117240e3ad 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track.h
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track.h
@@ -133,7 +133,7 @@ class CORE_EXPORT TextTrack : public EventTargetWithInlineData,
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
void AddListOfCues(HeapVector<Member<TextTrackCue>>&);
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_container.cc b/chromium/third_party/blink/renderer/core/html/track/text_track_container.cc
index 8a571082375..feded826398 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_container.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_container.cc
@@ -55,7 +55,7 @@ class VideoElementResizeDelegate final : public ResizeObserver::Delegate {
entries[0]->target()->GetLayoutObject());
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(text_track_container_);
ResizeObserver::Delegate::Trace(visitor);
}
@@ -69,7 +69,7 @@ class VideoElementResizeDelegate final : public ResizeObserver::Delegate {
TextTrackContainer::TextTrackContainer(Document& document)
: HTMLDivElement(document), default_font_size_(0) {}
-void TextTrackContainer::Trace(blink::Visitor* visitor) {
+void TextTrackContainer::Trace(Visitor* visitor) {
visitor->Trace(video_size_observer_);
HTMLDivElement::Trace(visitor);
}
@@ -96,7 +96,7 @@ LayoutObject* TextTrackContainer::CreateLayoutObject(const ComputedStyle&) {
void TextTrackContainer::ObserveSizeChanges(Element& element) {
video_size_observer_ = ResizeObserver::Create(
- GetDocument(), new VideoElementResizeDelegate(*this));
+ GetDocument(), MakeGarbageCollected<VideoElementResizeDelegate>(*this));
video_size_observer_->observe(&element);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_container.h b/chromium/third_party/blink/renderer/core/html/track/text_track_container.h
index 01a234e7400..0f369a32b2e 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_container.h
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_container.h
@@ -52,7 +52,7 @@ class TextTrackContainer final : public HTMLDivElement {
void UpdateDisplay(HTMLMediaElement&, ExposingControls);
void UpdateDefaultFontSize(LayoutObject*);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
bool IsTextTrackContainer() const override { return true; }
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_cue.cc b/chromium/third_party/blink/renderer/core/html/track/text_track_cue.cc
index ee1c59a070e..08b901b75bd 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_cue.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_cue.cc
@@ -132,7 +132,7 @@ const AtomicString& TextTrackCue::InterfaceName() const {
return event_target_names::kTextTrackCue;
}
-void TextTrackCue::Trace(blink::Visitor* visitor) {
+void TextTrackCue::Trace(Visitor* visitor) {
visitor->Trace(track_);
EventTargetWithInlineData::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_cue.h b/chromium/third_party/blink/renderer/core/html/track/text_track_cue.h
index e992c3ff305..83efced97c6 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_cue.h
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_cue.h
@@ -97,7 +97,7 @@ class TextTrackCue : public EventTargetWithInlineData {
DEFINE_ATTRIBUTE_EVENT_LISTENER(enter, kEnter);
DEFINE_ATTRIBUTE_EVENT_LISTENER(exit, kExit);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
TextTrackCue(double start, double end);
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.cc b/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.cc
index 64d5936b9bd..b7b18a99170 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.cc
@@ -139,7 +139,7 @@ void TextTrackCueList::ValidateCueIndexes() {
first_invalid_index_ = list_.size();
}
-void TextTrackCueList::Trace(blink::Visitor* visitor) {
+void TextTrackCueList::Trace(Visitor* visitor) {
visitor->Trace(list_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.h b/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.h
index a08d4e41d9a..125d21a00cb 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.h
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_cue_list.h
@@ -60,7 +60,7 @@ class TextTrackCueList final : public ScriptWrappable {
}
void ValidateCueIndexes();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
wtf_size_t FindInsertionIndex(const TextTrackCue*) const;
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_list.cc b/chromium/third_party/blink/renderer/core/html/track/text_track_list.cc
index 126f1e0eb46..c1ca2a7652c 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_list.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_list.cc
@@ -296,7 +296,7 @@ HTMLMediaElement* TextTrackList::Owner() const {
return owner_;
}
-void TextTrackList::Trace(blink::Visitor* visitor) {
+void TextTrackList::Trace(Visitor* visitor) {
visitor->Trace(owner_);
visitor->Trace(add_track_tracks_);
visitor->Trace(element_tracks_);
diff --git a/chromium/third_party/blink/renderer/core/html/track/text_track_list.h b/chromium/third_party/blink/renderer/core/html/track/text_track_list.h
index f8f8ad3f4e7..551b04a5751 100644
--- a/chromium/third_party/blink/renderer/core/html/track/text_track_list.h
+++ b/chromium/third_party/blink/renderer/core/html/track/text_track_list.h
@@ -74,7 +74,7 @@ class CORE_EXPORT TextTrackList final : public EventTargetWithInlineData {
bool HasShowingTracks();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void ScheduleTrackEvent(const AtomicString& event_name, TextTrack*);
diff --git a/chromium/third_party/blink/renderer/core/html/track/track_base.cc b/chromium/third_party/blink/renderer/core/html/track/track_base.cc
index 290fd5fcb64..06186ff6f78 100644
--- a/chromium/third_party/blink/renderer/core/html/track/track_base.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/track_base.cc
@@ -48,7 +48,7 @@ TrackBase::TrackBase(WebMediaPlayer::TrackType type,
TrackBase::~TrackBase() = default;
-void TrackBase::Trace(blink::Visitor* visitor) {
+void TrackBase::Trace(Visitor* visitor) {
Supplementable<TrackBase>::Trace(visitor);
visitor->Trace(media_element_);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/track_base.h b/chromium/third_party/blink/renderer/core/html/track/track_base.h
index 7a58eec8f74..d752883ecb6 100644
--- a/chromium/third_party/blink/renderer/core/html/track/track_base.h
+++ b/chromium/third_party/blink/renderer/core/html/track/track_base.h
@@ -53,7 +53,7 @@ class CORE_EXPORT TrackBase : public Supplementable<TrackBase> {
}
HTMLMediaElement* MediaElement() const { return media_element_; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
TrackBase(WebMediaPlayer::TrackType,
diff --git a/chromium/third_party/blink/renderer/core/html/track/track_event.cc b/chromium/third_party/blink/renderer/core/html/track/track_event.cc
index 218fb465a53..535422abe2d 100644
--- a/chromium/third_party/blink/renderer/core/html/track/track_event.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/track_event.cc
@@ -78,7 +78,7 @@ void TrackEvent::track(VideoTrackOrAudioTrackOrTextTrack& return_value) {
}
}
-void TrackEvent::Trace(blink::Visitor* visitor) {
+void TrackEvent::Trace(Visitor* visitor) {
visitor->Trace(track_);
Event::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/track_event.h b/chromium/third_party/blink/renderer/core/html/track/track_event.h
index ce10e6c3f87..9c59e327d0d 100644
--- a/chromium/third_party/blink/renderer/core/html/track/track_event.h
+++ b/chromium/third_party/blink/renderer/core/html/track/track_event.h
@@ -59,7 +59,7 @@ class CORE_EXPORT TrackEvent final : public Event {
void track(VideoTrackOrAudioTrackOrTextTrack&);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<TrackBase> track_;
diff --git a/chromium/third_party/blink/renderer/core/html/track/track_list_base.h b/chromium/third_party/blink/renderer/core/html/track/track_list_base.h
index ebfc9ac6d80..93b747f57b1 100644
--- a/chromium/third_party/blink/renderer/core/html/track/track_list_base.h
+++ b/chromium/third_party/blink/renderer/core/html/track/track_list_base.h
@@ -79,7 +79,7 @@ class TrackListBase : public EventTargetWithInlineData {
ScheduleEvent(Event::Create(event_type_names::kChange));
}
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
visitor->Trace(tracks_);
visitor->Trace(media_element_);
EventTargetWithInlineData::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/track/video_track.cc b/chromium/third_party/blink/renderer/core/html/track/video_track.cc
index 740c1f1304a..ee63e7767c8 100644
--- a/chromium/third_party/blink/renderer/core/html/track/video_track.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/video_track.cc
@@ -18,7 +18,7 @@ VideoTrack::VideoTrack(const String& id,
VideoTrack::~VideoTrack() = default;
-void VideoTrack::Trace(blink::Visitor* visitor) {
+void VideoTrack::Trace(Visitor* visitor) {
ScriptWrappable::Trace(visitor);
TrackBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/video_track.h b/chromium/third_party/blink/renderer/core/html/track/video_track.h
index 3f836c9a67b..5af8076a5ad 100644
--- a/chromium/third_party/blink/renderer/core/html/track/video_track.h
+++ b/chromium/third_party/blink/renderer/core/html/track/video_track.h
@@ -32,7 +32,7 @@ class CORE_EXPORT VideoTrack final : public ScriptWrappable, public TrackBase {
const AtomicString& language,
bool selected);
~VideoTrack() override;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
bool selected() const { return selected_; }
void setSelected(bool);
diff --git a/chromium/third_party/blink/renderer/core/html/track/video_track_list.h b/chromium/third_party/blink/renderer/core/html/track/video_track_list.h
index fbe37cf3618..96c14cfc150 100644
--- a/chromium/third_party/blink/renderer/core/html/track/video_track_list.h
+++ b/chromium/third_party/blink/renderer/core/html/track/video_track_list.h
@@ -26,7 +26,7 @@ class CORE_EXPORT VideoTrackList final : public TrackListBase<VideoTrack> {
void TrackSelected(WebMediaPlayer::TrackId selected_track_id);
- void Trace(blink::Visitor* visitor) override {
+ void Trace(Visitor* visitor) override {
TrackListBase<VideoTrack>::Trace(visitor);
}
};
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc b/chromium/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc
index 235c8222aa2..1ca85898fa7 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/html/track/vtt/buffered_line_reader.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
@@ -173,12 +174,12 @@ TEST(BufferedLineReaderTest, BufferSizes) {
const char* lines[] = {"aaaaaaaaaaaaaaaa", "bbbbbbbbbb", "ccccccccccccc", "",
"dddddd", "", "eeeeeeeeee"};
const NewlineType kBreaks[] = {kLf, kLf, kLf, kLf, kLf, kLf, kLf};
- const size_t num_test_lines = arraysize(lines);
- static_assert(num_test_lines == arraysize(kBreaks),
+ const size_t num_test_lines = base::size(lines);
+ static_assert(num_test_lines == base::size(kBreaks),
"number of test lines and breaks should be the same");
String data = MakeTestData(lines, kBreaks, num_test_lines);
- for (size_t k = 0; k < arraysize(kBlockSizes); ++k) {
+ for (size_t k = 0; k < base::size(kBlockSizes); ++k) {
size_t line_count = 0;
BufferedLineReader reader;
wtf_size_t block_size = kBlockSizes[k];
@@ -200,12 +201,12 @@ TEST(BufferedLineReaderTest, BufferSizesMixedEndings) {
"aaaaaaaaaaaaaaaa", "bbbbbbbbbb", "ccccccccccccc", "",
"dddddd", "eeeeeeeeee", "fffffffffffffffffff"};
const NewlineType kBreaks[] = {kCr, kLf, kCrLf, kCr, kLf, kCrLf, kLf};
- const size_t num_test_lines = arraysize(lines);
- static_assert(num_test_lines == arraysize(kBreaks),
+ const size_t num_test_lines = base::size(lines);
+ static_assert(num_test_lines == base::size(kBreaks),
"number of test lines and breaks should be the same");
String data = MakeTestData(lines, kBreaks, num_test_lines);
- for (size_t k = 0; k < arraysize(kBlockSizes); ++k) {
+ for (size_t k = 0; k < base::size(kBlockSizes); ++k) {
size_t line_count = 0;
BufferedLineReader reader;
wtf_size_t block_size = kBlockSizes[k];
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc
index df6990bb286..88f5e5e8136 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/html/track/vtt/vtt_cue.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/double_or_auto_keyword.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
@@ -57,14 +58,14 @@ namespace blink {
static const CSSValueID kDisplayWritingModeMap[] = {
CSSValueHorizontalTb, CSSValueVerticalRl, CSSValueVerticalLr};
-static_assert(arraysize(kDisplayWritingModeMap) ==
+static_assert(base::size(kDisplayWritingModeMap) ==
VTTCue::kNumberOfWritingDirections,
"displayWritingModeMap should have the same number of elements "
"as VTTCue::NumberOfWritingDirections");
static const CSSValueID kDisplayAlignmentMap[] = {
CSSValueStart, CSSValueCenter, CSSValueEnd, CSSValueLeft, CSSValueRight};
-static_assert(arraysize(kDisplayAlignmentMap) == VTTCue::kNumberOfAlignments,
+static_assert(base::size(kDisplayAlignmentMap) == VTTCue::kNumberOfAlignments,
"displayAlignmentMap should have the same number of elements as "
"VTTCue::NumberOfAlignments");
@@ -1129,7 +1130,7 @@ Document& VTTCue::GetDocument() const {
return cue_background_box_->GetDocument();
}
-void VTTCue::Trace(blink::Visitor* visitor) {
+void VTTCue::Trace(Visitor* visitor) {
visitor->Trace(region_);
visitor->Trace(vtt_node_tree_);
visitor->Trace(cue_background_box_);
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h
index 2d2df08047c..d5265a6c3c9 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h
@@ -155,7 +155,7 @@ class VTTCue final : public TextTrackCue {
String ToString() const override;
#endif
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Document& GetDocument() const;
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
index 42c93811aa4..af2c7e5ab49 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
@@ -600,7 +600,7 @@ void VTTTreeBuilder::ConstructTreeFromToken(Document& document) {
}
}
-void VTTParser::Trace(blink::Visitor* visitor) {
+void VTTParser::Trace(Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(current_region_);
visitor->Trace(client_);
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h
index 209228dc495..cad46f9c884 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h
@@ -53,7 +53,7 @@ class VTTParserClient : public GarbageCollectedMixin {
virtual void NewCuesParsed() = 0;
virtual void FileFailedToParse() = 0;
- void Trace(blink::Visitor* visitor) override {}
+ void Trace(Visitor* visitor) override {}
};
// Implementation of the WebVTT parser algorithm.
@@ -112,7 +112,7 @@ class VTTParser final : public GarbageCollectedFinalized<VTTParser> {
// Transfers ownership of last parsed cues to caller.
void GetNewCues(HeapVector<Member<TextTrackCue>>&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Member<Document> document_;
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc
index 44d1347d995..d2612667418 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc
@@ -413,7 +413,7 @@ void VTTRegion::ScrollTimerFired(TimerBase*) {
DisplayLastVTTCueBox();
}
-void VTTRegion::Trace(blink::Visitor* visitor) {
+void VTTRegion::Trace(Visitor* visitor) {
visitor->Trace(cue_container_);
visitor->Trace(region_display_tree_);
ScriptWrappable::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h
index 44958e7088c..0adac94f793 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h
@@ -88,7 +88,7 @@ class VTTRegion final : public ScriptWrappable {
void DisplayLastVTTCueBox();
void WillRemoveVTTCueBox(VTTCueBox*);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
void PrepareRegionDisplayTree();
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index 6a20a923983..95997336af0 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -570,8 +570,7 @@ ImageBitmap::ImageBitmap(ImageElementBase* image,
if (!image_)
return;
- image_->SetOriginClean(
- !image->WouldTaintOrigin(document->GetSecurityOrigin()));
+ image_->SetOriginClean(!image->WouldTaintOrigin());
UpdateImageBitmapMemoryUsage();
}
@@ -606,8 +605,7 @@ ImageBitmap::ImageBitmap(HTMLVideoElement* video,
if (!image_)
return;
- image_->SetOriginClean(
- !video->WouldTaintOrigin(document->GetSecurityOrigin()));
+ image_->SetOriginClean(!video->WouldTaintOrigin());
UpdateImageBitmapMemoryUsage();
}
@@ -709,8 +707,9 @@ ImageBitmap::ImageBitmap(ImageData* data,
}
// Copy / color convert the pixels
- scoped_refptr<ArrayBuffer> pixels_buffer = ArrayBuffer::CreateOrNull(
- src_rect.Size().Area(), parsed_options.color_params.BytesPerPixel());
+ scoped_refptr<ArrayBuffer> pixels_buffer =
+ ArrayBuffer::CreateOrNull(SafeCast<uint32_t>(src_rect.Size().Area()),
+ parsed_options.color_params.BytesPerPixel());
if (!pixels_buffer)
return;
unsigned byte_length = pixels_buffer->ByteLength();
@@ -987,8 +986,7 @@ ScriptPromise ImageBitmap::CreateAsync(ImageElementBase* image,
ImageBitmap* bitmap =
MakeGarbageCollected<ImageBitmap>(MakeBlankImage(parsed_options));
if (bitmap->BitmapImage()) {
- bitmap->BitmapImage()->SetOriginClean(
- !image->WouldTaintOrigin(document->GetSecurityOrigin()));
+ bitmap->BitmapImage()->SetOriginClean(!image->WouldTaintOrigin());
resolver->Resolve(bitmap);
} else {
resolver->Reject(
@@ -1011,7 +1009,7 @@ ScriptPromise ImageBitmap::CreateAsync(ImageElementBase* image,
CrossThreadBind(&RasterizeImageOnBackgroundThread,
WrapCrossThreadPersistent(resolver),
std::move(paint_record), draw_dst_rect,
- !image->WouldTaintOrigin(document->GetSecurityOrigin()),
+ !image->WouldTaintOrigin(),
WTF::Passed(std::move(passed_parsed_options))));
return promise;
}
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
index 08e225280c0..bea78c0d82d 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
@@ -141,9 +141,7 @@ class CORE_EXPORT ImageBitmap final : public ScriptWrappable,
scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
AccelerationHint,
const FloatSize&) override;
- bool WouldTaintOrigin(const SecurityOrigin*) const override {
- return !image_->OriginClean();
- }
+ bool WouldTaintOrigin() const override { return !image_->OriginClean(); }
void AdjustDrawRects(FloatRect* src_rect, FloatRect* dst_rect) const override;
FloatSize ElementSize(const FloatSize&) const override;
bool IsImageBitmap() const override { return true; }
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index 0b2b63e3962..80d1e199ccf 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -614,8 +614,8 @@ TEST_F(ImageBitmapTest, ImageBitmapPixelFormat) {
// internal SkImage back storage.
ASSERT_EQ(sk_image_internal, sk_image_internal_8888);
- sk_sp<SkColorSpace> p3_color_space = SkColorSpace::MakeRGB(
- SkColorSpace::kLinear_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
+ sk_sp<SkColorSpace> p3_color_space =
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, SkNamedGamut::kDCIP3);
SkImageInfo info_f16 = SkImageInfo::Make(10, 10, kRGBA_F16_SkColorType,
kPremul_SkAlphaType, p3_color_space);
sk_sp<SkSurface> surface_f16(SkSurface::MakeRaster(info_f16));
diff --git a/chromium/third_party/blink/renderer/core/input/event_handler.cc b/chromium/third_party/blink/renderer/core/input/event_handler.cc
index e27e2f2f2c3..4702bdb7b05 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handler.cc
+++ b/chromium/third_party/blink/renderer/core/input/event_handler.cc
@@ -178,7 +178,7 @@ EventHandler::EventHandler(LocalFrame& frame)
void EventHandler::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
visitor->Trace(selection_controller_);
- visitor->Trace(capturing_mouse_events_node_);
+ visitor->Trace(capturing_mouse_events_element_);
visitor->Trace(last_mouse_move_event_subframe_);
visitor->Trace(last_scrollbar_under_mouse_);
visitor->Trace(drag_target_);
@@ -203,7 +203,7 @@ void EventHandler::Clear() {
drag_target_ = nullptr;
should_only_fire_drag_over_event_ = false;
last_mouse_down_user_gesture_token_ = nullptr;
- capturing_mouse_events_node_ = nullptr;
+ capturing_mouse_events_element_ = nullptr;
pointer_event_manager_->Clear();
scroll_manager_->Clear();
gesture_manager_->Clear();
@@ -405,7 +405,7 @@ bool EventHandler::IsSelectingLink(const HitTestResult& result) {
// node, don't treat this as a selection. Note calling
// ComputeVisibleSelectionInDOMTreeDeprecated may update layout.
const bool mouse_selection =
- !capturing_mouse_events_node_ &&
+ !capturing_mouse_events_element_ &&
mouse_event_manager_->MousePressed() &&
GetSelectionController().MouseDownMayStartSelect() &&
!mouse_event_manager_->MouseDownMayStartDrag() &&
@@ -610,7 +610,7 @@ WebInputEventResult EventHandler::HandleMousePressEvent(
return WebInputEventResult::kHandledSuppressed;
if (event_handler_will_reset_capturing_mouse_events_node_)
- capturing_mouse_events_node_ = nullptr;
+ capturing_mouse_events_element_ = nullptr;
mouse_event_manager_->HandleMousePressEventUpdateStates(mouse_event);
if (!frame_->View())
return WebInputEventResult::kNotHandled;
@@ -644,7 +644,7 @@ WebInputEventResult EventHandler::HandleMousePressEvent(
subframe->GetEventHandler().mouse_event_manager_->CapturesDragging());
if (mouse_event_manager_->MousePressed() &&
mouse_event_manager_->CapturesDragging()) {
- capturing_mouse_events_node_ = mev.InnerNode();
+ capturing_mouse_events_element_ = mev.InnerElement();
event_handler_will_reset_capturing_mouse_events_node_ = true;
}
mouse_event_manager_->InvalidateClick();
@@ -680,7 +680,7 @@ WebInputEventResult EventHandler::HandleMousePressEvent(
frame_->Selection().SetCaretBlinkingSuspended(true);
WebInputEventResult event_result = DispatchMousePointerEvent(
- WebInputEvent::kPointerDown, mev.InnerNode(), mev.CanvasRegionId(),
+ WebInputEvent::kPointerDown, mev.InnerElement(), mev.CanvasRegionId(),
mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
// Disabled form controls still need to resize the scrollable area.
@@ -745,22 +745,19 @@ WebInputEventResult EventHandler::HandleMousePressEvent(
last_scrollbar_under_mouse_ = nullptr;
}
- if (event_result != WebInputEventResult::kNotHandled) {
- // Scrollbars should get events anyway, even disabled controls might be
- // scrollable.
- PassMousePressEventToScrollbar(mev);
- } else {
+ // Scrollbars should get events anyway, even disabled controls might be
+ // scrollable.
+ if (PassMousePressEventToScrollbar(mev))
+ event_result = WebInputEventResult::kHandledSystem;
+
+ if (event_result == WebInputEventResult::kNotHandled) {
if (ShouldRefetchEventTarget(mev)) {
HitTestRequest request(HitTestRequest::kReadOnly |
HitTestRequest::kActive);
mev = frame_->GetDocument()->PerformMouseEventHitTest(
request, document_point, mouse_event);
}
-
- if (PassMousePressEventToScrollbar(mev))
- event_result = WebInputEventResult::kHandledSystem;
- else
- event_result = mouse_event_manager_->HandleMousePressEvent(mev);
+ event_result = mouse_event_manager_->HandleMousePressEvent(mev);
}
if (mev.GetHitTestResult().InnerNode() &&
@@ -841,7 +838,7 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
WebInputEvent::Modifiers::kRelativeMotionEvent)) {
mouse_event_manager_->ClearDragHeuristicState();
if (event_handler_will_reset_capturing_mouse_events_node_)
- capturing_mouse_events_node_ = nullptr;
+ capturing_mouse_events_element_ = nullptr;
CaptureMouseEventsToWidget(false);
}
@@ -925,7 +922,7 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
WebInputEventResult event_result = WebInputEventResult::kNotHandled;
bool is_remote_frame = false;
LocalFrame* new_subframe = event_handling_util::GetTargetSubframe(
- mev, capturing_mouse_events_node_.Get(), &is_remote_frame);
+ mev, capturing_mouse_events_element_.Get(), &is_remote_frame);
// We want mouseouts to happen first, from the inside out. First send a
// move event to the last subframe so that it will fire mouseouts.
@@ -941,8 +938,8 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
if (new_subframe) {
// Update over/out state before passing the event to the subframe.
pointer_event_manager_->SendMouseAndPointerBoundaryEvents(
- EffectiveMouseEventTargetNode(mev.InnerNode()), mev.CanvasRegionId(),
- mev.Event());
+ EffectiveMouseEventTargetElement(mev.InnerElement()),
+ mev.CanvasRegionId(), mev.Event());
// Event dispatch in sendMouseAndPointerBoundaryEvents may have caused the
// subframe of the target node to be detached from its LocalFrameView, in
@@ -974,7 +971,7 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
return event_result;
event_result = DispatchMousePointerEvent(
- WebInputEvent::kPointerMove, mev.InnerNode(), mev.CanvasRegionId(),
+ WebInputEvent::kPointerMove, mev.InnerElement(), mev.CanvasRegionId(),
mev.Event(), coalesced_events, predicted_events);
// TODO(crbug.com/346473): Since there is no default action for the mousemove
// event we should consider doing drag&drop even when js cancels the
@@ -1015,8 +1012,8 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent(
if (frame_set_being_resized_) {
CaptureMouseEventsToWidget(false);
return mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
- EffectiveMouseEventTargetNode(frame_set_being_resized_.Get()), String(),
- event_type_names::kMouseup, mouse_event);
+ EffectiveMouseEventTargetElement(frame_set_being_resized_.Get()),
+ String(), event_type_names::kMouseup, mouse_event);
}
if (last_scrollbar_under_mouse_) {
@@ -1024,7 +1021,7 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent(
last_scrollbar_under_mouse_->MouseUp(mouse_event);
CaptureMouseEventsToWidget(false);
return DispatchMousePointerEvent(
- WebInputEvent::kPointerUp, mouse_event_manager_->GetNodeUnderMouse(),
+ WebInputEvent::kPointerUp, mouse_event_manager_->GetElementUnderMouse(),
String(), mouse_event, Vector<WebMouseEvent>(),
Vector<WebMouseEvent>());
}
@@ -1037,11 +1034,10 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent(
MouseEventWithHitTestResults mev =
event_handling_util::PerformMouseEventHitTest(frame_, request,
mouse_event);
- Element* mouse_release_target = mev.InnerElement();
LocalFrame* subframe = event_handling_util::GetTargetSubframe(
- mev, capturing_mouse_events_node_.Get());
+ mev, capturing_mouse_events_element_.Get());
if (event_handler_will_reset_capturing_mouse_events_node_)
- capturing_mouse_events_node_ = nullptr;
+ capturing_mouse_events_element_ = nullptr;
if (subframe)
return PassMouseReleaseEventToSubframe(mev, subframe);
@@ -1063,13 +1059,10 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent(
}
WebInputEventResult event_result = DispatchMousePointerEvent(
- WebInputEvent::kPointerUp, mev.InnerNode(), mev.CanvasRegionId(),
- mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
-
- WebInputEventResult click_event_result =
- mouse_release_target ? mouse_event_manager_->DispatchMouseClickIfNeeded(
- mev, *mouse_release_target)
- : WebInputEventResult::kNotHandled;
+ WebInputEvent::kPointerUp, mev.InnerElement(), mev.CanvasRegionId(),
+ mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>(),
+ (GetSelectionController().HasExtendedSelection() &&
+ IsSelectionOverLink(mev)));
scroll_manager_->ClearResizeScrollableArea(false);
@@ -1079,8 +1072,7 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent(
mouse_event_manager_->HandleMouseReleaseEventUpdateStates();
CaptureMouseEventsToWidget(false);
- return event_handling_util::MergeEventResult(click_event_result,
- event_result);
+ return event_result;
}
static bool TargetIsFrame(Node* target, LocalFrame*& frame) {
@@ -1230,7 +1222,7 @@ WebInputEventResult EventHandler::PerformDragAndDrop(
void EventHandler::ClearDragState() {
scroll_manager_->StopAutoscroll();
drag_target_ = nullptr;
- capturing_mouse_events_node_ = nullptr;
+ capturing_mouse_events_element_ = nullptr;
should_only_fire_drag_over_event_ = false;
}
@@ -1242,26 +1234,21 @@ void EventHandler::RecomputeMouseHoverState() {
mouse_event_manager_->RecomputeMouseHoverState();
}
-void EventHandler::SetCapturingMouseEventsNode(Node* n) {
+void EventHandler::SetCapturingMouseEventsElement(Element* n) {
CaptureMouseEventsToWidget(n);
- capturing_mouse_events_node_ = n;
+ capturing_mouse_events_element_ = n;
}
-Node* EventHandler::EffectiveMouseEventTargetNode(Node* target_node) {
- Node* new_node_under_mouse = target_node;
-
- if (capturing_mouse_events_node_) {
- new_node_under_mouse = capturing_mouse_events_node_.Get();
- } else {
- // If the target node is a text node, dispatch on the parent node -
- // rdar://4196646
- if (new_node_under_mouse && new_node_under_mouse->IsTextNode())
- new_node_under_mouse = FlatTreeTraversal::Parent(*new_node_under_mouse);
+Element* EventHandler::EffectiveMouseEventTargetElement(
+ Element* target_element) {
+ Element* new_element_under_mouse = target_element;
+ if (capturing_mouse_events_element_) {
+ new_element_under_mouse = capturing_mouse_events_element_.Get();
}
- return new_node_under_mouse;
+ return new_element_under_mouse;
}
-bool EventHandler::IsTouchPointerIdActiveOnFrame(int pointer_id,
+bool EventHandler::IsTouchPointerIdActiveOnFrame(PointerId pointer_id,
LocalFrame* frame) const {
DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
return pointer_event_manager_->IsTouchPointerIdActiveOnFrame(pointer_id,
@@ -1269,19 +1256,19 @@ bool EventHandler::IsTouchPointerIdActiveOnFrame(int pointer_id,
}
bool EventHandler::RootFrameTouchPointerActiveInCurrentFrame(
- int pointer_id) const {
+ PointerId pointer_id) const {
return frame_ != &frame_->LocalFrameRoot() &&
frame_->LocalFrameRoot()
.GetEventHandler()
.IsTouchPointerIdActiveOnFrame(pointer_id, frame_);
}
-bool EventHandler::IsPointerEventActive(int pointer_id) {
+bool EventHandler::IsPointerEventActive(PointerId pointer_id) {
return pointer_event_manager_->IsActive(pointer_id) ||
RootFrameTouchPointerActiveInCurrentFrame(pointer_id);
}
-void EventHandler::SetPointerCapture(int pointer_id, EventTarget* target) {
+void EventHandler::SetPointerCapture(PointerId pointer_id, Element* target) {
// TODO(crbug.com/591387): This functionality should be per page not per
// frame.
if (RootFrameTouchPointerActiveInCurrentFrame(pointer_id)) {
@@ -1292,7 +1279,8 @@ void EventHandler::SetPointerCapture(int pointer_id, EventTarget* target) {
}
}
-void EventHandler::ReleasePointerCapture(int pointer_id, EventTarget* target) {
+void EventHandler::ReleasePointerCapture(PointerId pointer_id,
+ Element* target) {
if (RootFrameTouchPointerActiveInCurrentFrame(pointer_id)) {
frame_->LocalFrameRoot().GetEventHandler().ReleasePointerCapture(pointer_id,
target);
@@ -1305,8 +1293,8 @@ void EventHandler::ReleaseMousePointerCapture() {
pointer_event_manager_->ReleaseMousePointerCapture();
}
-bool EventHandler::HasPointerCapture(int pointer_id,
- const EventTarget* target) const {
+bool EventHandler::HasPointerCapture(PointerId pointer_id,
+ const Element* target) const {
if (RootFrameTouchPointerActiveInCurrentFrame(pointer_id)) {
return frame_->LocalFrameRoot().GetEventHandler().HasPointerCapture(
pointer_id, target);
@@ -1315,33 +1303,30 @@ bool EventHandler::HasPointerCapture(int pointer_id,
}
}
-bool EventHandler::HasProcessedPointerCapture(int pointer_id,
- const EventTarget* target) const {
- return pointer_event_manager_->HasProcessedPointerCapture(pointer_id, target);
-}
-
void EventHandler::ProcessPendingPointerCaptureForPointerLock(
const WebMouseEvent& mouse_event) {
pointer_event_manager_->ProcessPendingPointerCaptureForPointerLock(
mouse_event);
}
-void EventHandler::ElementRemoved(EventTarget* target) {
+void EventHandler::ElementRemoved(Element* target) {
pointer_event_manager_->ElementRemoved(target);
if (target)
- mouse_wheel_event_manager_->ElementRemoved(target->ToNode());
+ mouse_wheel_event_manager_->ElementRemoved(target);
}
WebInputEventResult EventHandler::DispatchMousePointerEvent(
const WebInputEvent::Type event_type,
- Node* target_node,
+ Element* target_element,
const String& canvas_region_id,
const WebMouseEvent& mouse_event,
const Vector<WebMouseEvent>& coalesced_events,
- const Vector<WebMouseEvent>& predicted_events) {
+ const Vector<WebMouseEvent>& predicted_events,
+ bool skip_click_dispatch) {
const auto& event_result = pointer_event_manager_->SendMousePointerEvent(
- EffectiveMouseEventTargetNode(target_node), canvas_region_id, event_type,
- mouse_event, coalesced_events, predicted_events);
+ EffectiveMouseEventTargetElement(target_element), canvas_region_id,
+ event_type, mouse_event, coalesced_events, predicted_events,
+ skip_click_dispatch);
return event_result;
}
@@ -1647,8 +1632,9 @@ void EventHandler::UpdateGestureTargetNodeForMouseEvent(
// Insert the frame from the disagreement between last frames and entered
// frames.
while (exited_frame_in_document) {
- Node* last_node_under_tap = exited_frame_in_document->GetEventHandler()
- .mouse_event_manager_->GetNodeUnderMouse();
+ Node* last_node_under_tap =
+ exited_frame_in_document->GetEventHandler()
+ .mouse_event_manager_->GetElementUnderMouse();
if (!last_node_under_tap)
break;
@@ -1688,8 +1674,8 @@ void EventHandler::UpdateGestureTargetNodeForMouseEvent(
wtf_size_t index_exited_frame_chain = exited_frame_chain.size();
while (index_exited_frame_chain) {
LocalFrame* leave_frame = exited_frame_chain[--index_exited_frame_chain];
- leave_frame->GetEventHandler().mouse_event_manager_->SetNodeUnderMouse(
- EffectiveMouseEventTargetNode(nullptr), String(), fake_mouse_move);
+ leave_frame->GetEventHandler().mouse_event_manager_->SetElementUnderMouse(
+ EffectiveMouseEventTargetElement(nullptr), String(), fake_mouse_move);
}
// update the mouseover/mouseenter event
@@ -1699,8 +1685,8 @@ void EventHandler::UpdateGestureTargetNodeForMouseEvent(
if (parent_frame && parent_frame->IsLocalFrame()) {
ToLocalFrame(parent_frame)
->GetEventHandler()
- .mouse_event_manager_->SetNodeUnderMouse(
- EffectiveMouseEventTargetNode(ToHTMLFrameOwnerElement(
+ .mouse_event_manager_->SetElementUnderMouse(
+ EffectiveMouseEventTargetElement(ToHTMLFrameOwnerElement(
entered_frame_chain[index_entered_frame_chain]->Owner())),
String(), fake_mouse_move);
}
@@ -1870,7 +1856,7 @@ void EventHandler::ApplyTouchAdjustment(WebGestureEvent* gesture_event,
WebInputEventResult EventHandler::SendContextMenuEvent(
const WebMouseEvent& event,
- Node* override_target_node) {
+ Element* override_target_element) {
LocalFrameView* v = frame_->View();
if (!v)
return WebInputEventResult::kNotHandled;
@@ -1894,10 +1880,10 @@ WebInputEventResult EventHandler::SendContextMenuEvent(
GetSelectionController().SendContextMenuEvent(mev, position_in_contents);
- Node* target_node =
- override_target_node ? override_target_node : mev.InnerNode();
+ Element* target_element =
+ override_target_element ? override_target_element : mev.InnerElement();
return mouse_event_manager_->DispatchMouseEvent(
- EffectiveMouseEventTargetNode(target_node),
+ EffectiveMouseEventTargetElement(target_element),
event_type_names::kContextmenu, event,
mev.GetHitTestResult().CanvasRegionId(), nullptr, nullptr);
}
diff --git a/chromium/third_party/blink/renderer/core/input/event_handler.h b/chromium/third_party/blink/renderer/core/input/event_handler.h
index d268bfd532d..a102d0ab95e 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handler.h
+++ b/chromium/third_party/blink/renderer/core/input/event_handler.h
@@ -60,7 +60,6 @@ class DataTransfer;
class PaintLayer;
class Element;
class Event;
-class EventTarget;
template <typename EventType>
class EventWithHitTestResults;
class FloatQuad;
@@ -113,8 +112,8 @@ class CORE_EXPORT EventHandler final
return mouse_event_manager_->IsMousePositionUnknown();
}
void ClearMouseEventManager() const { mouse_event_manager_->Clear(); }
- void SetCapturingMouseEventsNode(
- Node*); // A caller is responsible for resetting capturing node to 0.
+ void SetCapturingMouseEventsElement(
+ Element*); // A caller is responsible for resetting capturing node to 0.
WebInputEventResult UpdateDragAndDrop(const WebMouseEvent&, DataTransfer*);
void CancelDragAndDrop(const WebMouseEvent&, DataTransfer*);
@@ -213,22 +212,21 @@ class CORE_EXPORT EventHandler final
WebInputEventResult SendContextMenuEvent(
const WebMouseEvent&,
- Node* override_target_node = nullptr);
+ Element* override_target_element = nullptr);
WebInputEventResult ShowNonLocatedContextMenu(
Element* override_target_element = nullptr,
WebMenuSourceType = kMenuSourceNone);
// Returns whether pointerId is active or not
- bool IsPointerEventActive(int);
+ bool IsPointerEventActive(PointerId);
- void SetPointerCapture(int, EventTarget*);
- void ReleasePointerCapture(int, EventTarget*);
+ void SetPointerCapture(PointerId, Element*);
+ void ReleasePointerCapture(PointerId, Element*);
void ReleaseMousePointerCapture();
- bool HasPointerCapture(int, const EventTarget*) const;
- bool HasProcessedPointerCapture(int, const EventTarget*) const;
+ bool HasPointerCapture(PointerId, const Element*) const;
void ProcessPendingPointerCaptureForPointerLock(const WebMouseEvent&);
- void ElementRemoved(EventTarget*);
+ void ElementRemoved(Element*);
void SetMouseDownMayStartAutoscroll();
@@ -274,7 +272,7 @@ class CORE_EXPORT EventHandler final
ScrollGranularity,
Node* start_node = nullptr);
- bool IsTouchPointerIdActiveOnFrame(int, LocalFrame*) const;
+ bool IsTouchPointerIdActiveOnFrame(PointerId, LocalFrame*) const;
// Clears drag target and related states. It is called when drag is done or
// canceled.
@@ -353,17 +351,18 @@ class CORE_EXPORT EventHandler final
ScrollableArea* AssociatedScrollableArea(const PaintLayer*) const;
- Node* EffectiveMouseEventTargetNode(Node*);
+ Element* EffectiveMouseEventTargetElement(Element*);
// Dispatches ME after corresponding PE provided the PE has not been canceled.
// The |mouse_event_type| arg must be one of {mousedown, mousemove, mouseup}.
WebInputEventResult DispatchMousePointerEvent(
const WebInputEvent::Type,
- Node* target,
+ Element* target,
const String& canvas_region_id,
const WebMouseEvent&,
const Vector<WebMouseEvent>& coalesced_events,
- const Vector<WebMouseEvent>& predicted_events);
+ const Vector<WebMouseEvent>& predicted_events,
+ bool skip_click_dispatch = false);
WebInputEventResult PassMousePressEventToSubframe(
MouseEventWithHitTestResults&,
@@ -396,7 +395,7 @@ class CORE_EXPORT EventHandler final
bool ShouldBrowserControlsConsumeScroll(FloatSize) const;
- bool RootFrameTouchPointerActiveInCurrentFrame(int pointer_id) const;
+ bool RootFrameTouchPointerActiveInCurrentFrame(PointerId pointer_id) const;
void CaptureMouseEventsToWidget(bool);
@@ -414,7 +413,7 @@ class CORE_EXPORT EventHandler final
// crbug.com/449649
TaskRunnerTimer<EventHandler> cursor_update_timer_;
- Member<Node> capturing_mouse_events_node_;
+ Member<Element> capturing_mouse_events_element_;
bool event_handler_will_reset_capturing_mouse_events_node_;
// Indicates whether the current widget is capturing mouse input.
diff --git a/chromium/third_party/blink/renderer/core/input/event_handler_test.cc b/chromium/third_party/blink/renderer/core/input/event_handler_test.cc
index 6a9e9886b0f..7556894ce42 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handler_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -1085,7 +1085,7 @@ TEST_F(EventHandlerTest, MouseLeaveResetsUnknownState) {
// Test that leaving an iframe sets the mouse position to unknown on that
// iframe.
TEST_F(EventHandlerSimTest, MouseLeaveIFrameResets) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/frame.html", "text/html");
@@ -1152,7 +1152,7 @@ TEST_F(EventHandlerSimTest, MouseLeaveIFrameResets) {
// Test that mouse down and move a small distance on a draggable element will
// not change cursor style.
TEST_F(EventHandlerSimTest, CursorStyleBeforeStartDragging) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1194,7 +1194,7 @@ TEST_F(EventHandlerSimTest, CursorStyleBeforeStartDragging) {
// Ensure that tap on element in iframe should apply active state.
TEST_F(EventHandlerSimTest, TapActiveInFrame) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
diff --git a/chromium/third_party/blink/renderer/core/input/event_handling_util.cc b/chromium/third_party/blink/renderer/core/input/event_handling_util.cc
index 9f552bbb040..7f8c440d93c 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handling_util.cc
+++ b/chromium/third_party/blink/renderer/core/input/event_handling_util.cc
@@ -100,11 +100,6 @@ ScrollableArea* AssociatedScrollableArea(const PaintLayer* layer) {
}
ContainerNode* ParentForClickEvent(const Node& node) {
- // IE doesn't dispatch click events for mousedown/mouseup events across form
- // controls.
- if (node.IsHTMLElement() && ToHTMLElement(node).IsInteractiveContent())
- return nullptr;
-
return FlatTreeTraversal::Parent(node);
}
diff --git a/chromium/third_party/blink/renderer/core/input/event_handling_util.h b/chromium/third_party/blink/renderer/core/input/event_handling_util.h
index fc457c2c8c2..b5e8eadc49c 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handling_util.h
+++ b/chromium/third_party/blink/renderer/core/input/event_handling_util.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_EVENT_HANDLING_UTIL_H_
#include "third_party/blink/public/platform/web_input_event_result.h"
+#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
@@ -57,11 +58,11 @@ class PointerEventTarget {
public:
void Trace(blink::Visitor* visitor) {
- visitor->Trace(target_node);
+ visitor->Trace(target_element);
visitor->Trace(target_frame);
}
- Member<Node> target_node;
+ Member<Element> target_element;
Member<LocalFrame> target_frame;
String region;
};
diff --git a/chromium/third_party/blink/renderer/core/input/gesture_manager.cc b/chromium/third_party/blink/renderer/core/input/gesture_manager.cc
index b148e1b134d..20c23488cc8 100644
--- a/chromium/third_party/blink/renderer/core/input/gesture_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/gesture_manager.cc
@@ -176,7 +176,7 @@ WebInputEventResult GestureManager::HandleGestureTap(
WebInputEvent::Modifiers::kIsCompatibilityEventForTouch),
gesture_event.TimeStamp());
mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
- current_hit_test.InnerNode(), current_hit_test.CanvasRegionId(),
+ current_hit_test.InnerElement(), current_hit_test.CanvasRegionId(),
event_type_names::kMousemove, fake_mouse_move);
}
@@ -228,7 +228,7 @@ WebInputEventResult GestureManager::HandleGestureTap(
mouse_down_event_result =
mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
- current_hit_test.InnerNode(), current_hit_test.CanvasRegionId(),
+ current_hit_test.InnerElement(), current_hit_test.CanvasRegionId(),
event_type_names::kMousedown, fake_mouse_down);
selection_controller_->InitializeSelectionState();
if (mouse_down_event_result == WebInputEventResult::kNotHandled) {
@@ -275,8 +275,9 @@ WebInputEventResult GestureManager::HandleGestureTap(
suppress_mouse_events_from_gestures_
? WebInputEventResult::kHandledSuppressed
: mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
- current_hit_test.InnerNode(), current_hit_test.CanvasRegionId(),
- event_type_names::kMouseup, fake_mouse_up);
+ current_hit_test.InnerElement(),
+ current_hit_test.CanvasRegionId(), event_type_names::kMouseup,
+ fake_mouse_up);
WebInputEventResult click_event_result = WebInputEventResult::kNotHandled;
if (tapped_element) {
@@ -290,9 +291,13 @@ WebInputEventResult GestureManager::HandleGestureTap(
tapped_element->UpdateDistributionForFlatTreeTraversal();
Node* click_target_node = current_hit_test.InnerNode()->CommonAncestor(
*tapped_element, event_handling_util::ParentForClickEvent);
+ Element* click_target_element = nullptr;
+ if (click_target_node && click_target_node->IsElementNode())
+ click_target_element = ToElement(click_target_node);
+
click_event_result =
mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
- click_target_node, String(), event_type_names::kClick,
+ click_target_element, String(), event_type_names::kClick,
fake_mouse_up);
}
mouse_event_manager_->SetClickElement(nullptr);
@@ -402,7 +407,7 @@ WebInputEventResult GestureManager::SendContextMenuEventForGesture(
modifiers | WebInputEvent::kIsCompatibilityEventForTouch),
gesture_event.TimeStamp());
mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
- targeted_event.GetHitTestResult().InnerNode(),
+ targeted_event.GetHitTestResult().InnerElement(),
targeted_event.CanvasRegionId(), event_type_names::kMousemove,
fake_mouse_move);
}
diff --git a/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc b/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc
index a334dbd7e65..945cdea4fc4 100644
--- a/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc
@@ -22,10 +22,10 @@ using blink::url_test_helpers::RegisterMockedURLLoadFromBase;
namespace blink {
-class ImeRequestTrackingWebViewClient
+class ImeRequestTrackingWebWidgetClient
: public frame_test_helpers::TestWebWidgetClient {
public:
- ImeRequestTrackingWebViewClient() : virtual_keyboard_request_count_(0) {}
+ ImeRequestTrackingWebWidgetClient() : virtual_keyboard_request_count_(0) {}
// WebWidgetClient methods
void ShowVirtualKeyboardOnElementFocus() override {
@@ -92,13 +92,13 @@ void ImeOnFocusTest::RunImeOnFocusTest(
IntPoint tap_point,
const AtomicString& focus_element,
std::string frame) {
- ImeRequestTrackingWebViewClient client;
+ ImeRequestTrackingWebWidgetClient client;
RegisterMockedURLLoadFromBase(WebString::FromUTF8(base_url_),
test::CoreTestDataPath(),
WebString::FromUTF8(file_name));
WebViewImpl* web_view =
web_view_helper_.Initialize(nullptr, nullptr, &client);
- web_view->Resize(WebSize(800, 1200));
+ web_view->MainFrameWidget()->Resize(WebSize(800, 1200));
LoadFrame(web_view->MainFrameImpl(), base_url_ + file_name);
document_ = web_view_helper_.GetWebView()
->MainFrameImpl()
diff --git a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc
index 04ee9f4ba4f..16dc5458a31 100644
--- a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/spatial_navigation.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
#include "third_party/blink/renderer/platform/windows_keyboard_codes.h"
@@ -45,22 +46,6 @@ static const unsigned short kHIGHBITMASKSHORT = 0x8000;
const int kVKeyProcessKey = 229;
-WebFocusType FocusDirectionForKey(KeyboardEvent* event) {
- if (event->ctrlKey() || event->metaKey() || event->shiftKey())
- return kWebFocusTypeNone;
-
- WebFocusType ret_val = kWebFocusTypeNone;
- if (event->key() == "ArrowDown")
- ret_val = kWebFocusTypeDown;
- else if (event->key() == "ArrowUp")
- ret_val = kWebFocusTypeUp;
- else if (event->key() == "ArrowLeft")
- ret_val = kWebFocusTypeLeft;
- else if (event->key() == "ArrowRight")
- ret_val = kWebFocusTypeRight;
- return ret_val;
-}
-
bool MapKeyCodeForScroll(int key_code,
WebInputEvent::Modifiers modifiers,
ScrollDirection* scroll_direction,
@@ -302,7 +287,11 @@ void KeyboardEventManager::DefaultKeyboardEventHandler(
DefaultTabEventHandler(event);
} else if (event->key() == "Escape") {
DefaultEscapeEventHandler(event);
+ } else if (event->key() == "Enter") {
+ DefaultEnterEventHandler(event);
} else {
+ // TODO(bokan): Seems odd to call the default _arrow_ event handler on
+ // events that aren't necessarily arrow keys.
DefaultArrowEventHandler(event, possible_focused_node);
}
}
@@ -345,10 +334,10 @@ void KeyboardEventManager::DefaultArrowEventHandler(
if (!page)
return;
- WebFocusType type = FocusDirectionForKey(event);
- if (type != kWebFocusTypeNone && IsSpatialNavigationEnabled(frame_) &&
+ if (IsSpatialNavigationEnabled(frame_) &&
!frame_->GetDocument()->InDesignMode()) {
- if (page->GetFocusController().AdvanceFocus(type)) {
+ if (page->GetSpatialNavigationController().HandleArrowKeyboardEvent(
+ event)) {
event->SetDefaultHandled();
return;
}
@@ -410,10 +399,30 @@ void KeyboardEventManager::DefaultTabEventHandler(KeyboardEvent* event) {
}
void KeyboardEventManager::DefaultEscapeEventHandler(KeyboardEvent* event) {
+ Page* page = frame_->GetPage();
+ if (!page)
+ return;
+
+ if (IsSpatialNavigationEnabled(frame_) &&
+ !frame_->GetDocument()->InDesignMode()) {
+ page->GetSpatialNavigationController().HandleEscapeKeyboardEvent(event);
+ }
+
if (HTMLDialogElement* dialog = frame_->GetDocument()->ActiveModalDialog())
dialog->DispatchEvent(*Event::CreateCancelable(event_type_names::kCancel));
}
+void KeyboardEventManager::DefaultEnterEventHandler(KeyboardEvent* event) {
+ Page* page = frame_->GetPage();
+ if (!page)
+ return;
+
+ if (IsSpatialNavigationEnabled(frame_) &&
+ !frame_->GetDocument()->InDesignMode()) {
+ page->GetSpatialNavigationController().HandleEnterKeyboardEvent(event);
+ }
+}
+
static OverrideCapsLockState g_override_caps_lock_state;
void KeyboardEventManager::SetCurrentCapsLockState(
diff --git a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h
index 362a6cbc987..d691a62fd7b 100644
--- a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h
+++ b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h
@@ -55,6 +55,7 @@ class CORE_EXPORT KeyboardEventManager
void DefaultBackspaceEventHandler(KeyboardEvent*);
void DefaultTabEventHandler(KeyboardEvent*);
void DefaultEscapeEventHandler(KeyboardEvent*);
+ void DefaultEnterEventHandler(KeyboardEvent*);
void DefaultArrowEventHandler(KeyboardEvent*, Node*);
const Member<LocalFrame> frame_;
diff --git a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc
index 7b5b4009d8e..17c58aca747 100644
--- a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -119,7 +119,7 @@ MouseEventManager::MouseEventManager(LocalFrame& frame,
}
void MouseEventManager::Clear() {
- node_under_mouse_ = nullptr;
+ element_under_mouse_ = nullptr;
mouse_press_node_ = nullptr;
mouse_down_may_start_autoscroll_ = false;
mouse_down_may_start_drag_ = false;
@@ -146,7 +146,7 @@ MouseEventManager::~MouseEventManager() = default;
void MouseEventManager::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
visitor->Trace(scroll_manager_);
- visitor->Trace(node_under_mouse_);
+ visitor->Trace(element_under_mouse_);
visitor->Trace(mouse_press_node_);
visitor->Trace(click_element_);
visitor->Trace(mouse_down_element_);
@@ -287,23 +287,19 @@ WebInputEventResult MouseEventManager::DispatchMouseEvent(
}
WebInputEventResult MouseEventManager::SetMousePositionAndDispatchMouseEvent(
- Node* target_node,
+ Element* target_element,
const String& canvas_region_id,
const AtomicString& event_type,
const WebMouseEvent& web_mouse_event) {
- // If the target node is a text node, dispatch on the parent node.
- if (target_node && target_node->IsTextNode())
- target_node = FlatTreeTraversal::Parent(*target_node);
-
- SetNodeUnderMouse(target_node, canvas_region_id, web_mouse_event);
-
- return DispatchMouseEvent(node_under_mouse_, event_type, web_mouse_event,
+ SetElementUnderMouse(target_element, canvas_region_id, web_mouse_event);
+ return DispatchMouseEvent(element_under_mouse_, event_type, web_mouse_event,
canvas_region_id, nullptr, nullptr);
}
WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
- const MouseEventWithHitTestResults& mev,
- Element& mouse_release_target) {
+ Element* mouse_release_target,
+ const WebMouseEvent& mouse_event,
+ const String& canvas_region_id) {
// We only prevent click event when the click may cause contextmenu to popup.
// However, we always send auxclick.
bool context_menu_event = false;
@@ -311,20 +307,17 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
// FIXME: The Mac port achieves the same behavior by checking whether the
// context menu is currently open in WebPage::mouseEvent(). Consider merging
// the implementations.
- if (mev.Event().button == WebPointerProperties::Button::kLeft &&
- mev.Event().GetModifiers() & WebInputEvent::Modifiers::kControlKey)
+ if (mouse_event.button == WebPointerProperties::Button::kLeft &&
+ mouse_event.GetModifiers() & WebInputEvent::Modifiers::kControlKey)
context_menu_event = true;
#endif
const bool should_dispatch_click_event =
click_count_ > 0 && !context_menu_event && mouse_down_element_ &&
- mouse_release_target.CanParticipateInFlatTree() &&
+ mouse_release_target &&
+ mouse_release_target->CanParticipateInFlatTree() &&
mouse_down_element_->CanParticipateInFlatTree() &&
- mouse_down_element_->isConnected() &&
- !(frame_->GetEventHandler()
- .GetSelectionController()
- .HasExtendedSelection() &&
- IsLinkSelection(mev));
+ mouse_down_element_->isConnected();
if (!should_dispatch_click_event)
return WebInputEventResult::kNotHandled;
@@ -332,13 +325,13 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
if (mouse_down_element_ == mouse_release_target) {
click_target_node = mouse_down_element_;
} else if (mouse_down_element_->GetDocument() ==
- mouse_release_target.GetDocument()) {
+ mouse_release_target->GetDocument()) {
// Updates distribution because a 'mouseup' event listener can make the
// tree dirty at dispatchMouseEvent() invocation above.
// Unless distribution is updated, commonAncestor would hit ASSERT.
mouse_down_element_->UpdateDistributionForFlatTreeTraversal();
- mouse_release_target.UpdateDistributionForFlatTreeTraversal();
- click_target_node = mouse_release_target.CommonAncestor(
+ mouse_release_target->UpdateDistributionForFlatTreeTraversal();
+ click_target_node = mouse_release_target->CommonAncestor(
*mouse_down_element_, event_handling_util::ParentForClickEvent);
}
if (!click_target_node)
@@ -360,10 +353,10 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
RuntimeEnabledFeatures::ClickRetargettingEnabled()) {
return DispatchMouseEvent(
click_target_node,
- (mev.Event().button == WebPointerProperties::Button::kLeft)
+ (mouse_event.button == WebPointerProperties::Button::kLeft)
? event_type_names::kClick
: event_type_names::kAuxclick,
- mev.Event(), mev.CanvasRegionId(), nullptr, nullptr);
+ mouse_event, canvas_region_id, nullptr, nullptr);
}
return WebInputEventResult::kNotHandled;
@@ -413,17 +406,17 @@ void MouseEventManager::CancelFakeMouseMoveEvent() {
fake_mouse_move_event_timer_.Stop();
}
-void MouseEventManager::SetNodeUnderMouse(
- Node* target,
+void MouseEventManager::SetElementUnderMouse(
+ Element* target,
const String& canvas_region_id,
const WebMouseEvent& web_mouse_event) {
- Node* last_node_under_mouse = node_under_mouse_;
- node_under_mouse_ = target;
+ Element* last_element_under_mouse = element_under_mouse_;
+ element_under_mouse_ = target;
PaintLayer* layer_for_last_node =
- event_handling_util::LayerForNode(last_node_under_mouse);
+ event_handling_util::LayerForNode(last_element_under_mouse);
PaintLayer* layer_for_node_under_mouse =
- event_handling_util::LayerForNode(node_under_mouse_.Get());
+ event_handling_util::LayerForNode(element_under_mouse_.Get());
Page* page = frame_->GetPage();
if (page && (layer_for_last_node &&
@@ -445,13 +438,13 @@ void MouseEventManager::SetNodeUnderMouse(
scrollable_area_for_node_under_mouse->MouseEnteredContentArea();
}
- if (last_node_under_mouse &&
- last_node_under_mouse->GetDocument() != frame_->GetDocument()) {
- last_node_under_mouse = nullptr;
+ if (last_element_under_mouse &&
+ last_element_under_mouse->GetDocument() != frame_->GetDocument()) {
+ last_element_under_mouse = nullptr;
}
- SendBoundaryEvents(last_node_under_mouse, node_under_mouse_, canvas_region_id,
- web_mouse_event);
+ SendBoundaryEvents(last_element_under_mouse, element_under_mouse_,
+ canvas_region_id, web_mouse_event);
}
void MouseEventManager::NodeChildrenWillBeRemoved(ContainerNode& container) {
@@ -477,8 +470,8 @@ void MouseEventManager::NodeWillBeRemoved(Node& node_to_be_removed) {
}
}
-Node* MouseEventManager::GetNodeUnderMouse() {
- return node_under_mouse_;
+Element* MouseEventManager::GetElementUnderMouse() {
+ return element_under_mouse_;
}
WebInputEventResult MouseEventManager::HandleMouseFocus(
@@ -496,12 +489,7 @@ WebInputEventResult MouseEventManager::HandleMouseFocus(
// The layout needs to be up to date to determine if an element is focusable.
frame_->GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
- Element* element = nullptr;
- if (node_under_mouse_) {
- element = node_under_mouse_->IsElementNode()
- ? ToElement(node_under_mouse_)
- : node_under_mouse_->ParentOrShadowHostElement();
- }
+ Element* element = element_under_mouse_;
for (; element; element = element->ParentOrShadowHostElement()) {
if (element->IsFocusable() && element->IsFocusedElementInDocument())
return WebInputEventResult::kNotHandled;
@@ -532,31 +520,25 @@ WebInputEventResult MouseEventManager::HandleMouseFocus(
if (!element && hit_test_result.GetScrollbar())
return WebInputEventResult::kHandledSystem;
- if (Page* page = frame_->GetPage()) {
- // If focus shift is blocked, we eat the event. Note we should never
- // clear swallowEvent if the page already set it (e.g., by canceling
- // default behavior).
- if (element) {
- if (SlideFocusOnShadowHostIfNecessary(*element))
- return WebInputEventResult::kHandledSystem;
- if (!page->GetFocusController().SetFocusedElement(
- element, frame_,
- FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeMouse,
- source_capabilities)))
- return WebInputEventResult::kHandledSystem;
- } else {
- // We call setFocusedElement even with !element in order to blur
- // current focus element when a link is clicked; this is expected by
- // some sites that rely on onChange handlers running from form
- // fields before the button click is processed.
- if (!page->GetFocusController().SetFocusedElement(
- nullptr, frame_,
- FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone,
- source_capabilities)))
- return WebInputEventResult::kHandledSystem;
- }
- }
+ Page* const page = frame_->GetPage();
+ if (!page)
+ return WebInputEventResult::kNotHandled;
+
+ // If focus shift is blocked, we eat the event. Note we should never
+ // clear swallowEvent if the page already set it (e.g., by canceling
+ // default behavior).
+ if (element && SlideFocusOnShadowHostIfNecessary(*element))
+ return WebInputEventResult::kHandledSystem;
+ // We call setFocusedElement even with !element in order to blur
+ // current focus element when a link is clicked; this is expected by
+ // some sites that rely on onChange handlers running from form
+ // fields before the button click is processed.
+ if (!page->GetFocusController().SetFocusedElement(
+ element, frame_,
+ FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeMouse,
+ source_capabilities)))
+ return WebInputEventResult::kHandledSystem;
return WebInputEventResult::kNotHandled;
}
@@ -696,8 +678,8 @@ WebInputEventResult MouseEventManager::HandleMousePressEvent(
bool single_click = event.Event().click_count <= 1;
- mouse_down_may_start_drag_ =
- single_click && !IsLinkSelection(event) && !IsExtendingSelection(event);
+ mouse_down_may_start_drag_ = single_click && !IsSelectionOverLink(event) &&
+ !IsExtendingSelection(event);
mouse_down_ = event.Event();
@@ -944,15 +926,15 @@ bool MouseEventManager::HandleDrag(const MouseEventWithHitTestResults& event,
return true;
}
- // Once we're past the drag threshold, we don't want to treat this gesture as
- // a click.
- InvalidateClick();
-
if (!TryStartDrag(event)) {
// Something failed to start the drag, clean up.
ClearDragDataTransfer();
ResetDragSource();
} else {
+ // Once we're past the drag threshold, we don't want to treat this gesture
+ // as a click.
+ InvalidateClick();
+
// Since drag operation started we need to send a pointercancel for the
// corresponding pointer.
if (initiator == DragInitiator::kMouse) {
diff --git a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h
index c234d92e0df..278f8c30308 100644
--- a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h
+++ b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h
@@ -54,14 +54,15 @@ class CORE_EXPORT MouseEventManager final
bool check_for_listener = false);
WebInputEventResult SetMousePositionAndDispatchMouseEvent(
- Node* target_node,
+ Element* target_element,
const String& canvas_region_id,
const AtomicString& event_type,
const WebMouseEvent&);
WebInputEventResult DispatchMouseClickIfNeeded(
- const MouseEventWithHitTestResults&,
- Element& mouse_release_target);
+ Element* mouse_release_target,
+ const WebMouseEvent& mouse_event,
+ const String& canvas_region_id);
WebInputEventResult DispatchDragSrcEvent(const AtomicString& event_type,
const WebMouseEvent&);
@@ -79,9 +80,9 @@ class CORE_EXPORT MouseEventManager final
const String& canvas_region_id,
const WebMouseEvent&);
- void SetNodeUnderMouse(Node*,
- const String& canvas_region_id,
- const WebMouseEvent&);
+ void SetElementUnderMouse(Element*,
+ const String& canvas_region_id,
+ const WebMouseEvent&);
WebInputEventResult HandleMouseFocus(
const HitTestResult&,
@@ -129,7 +130,7 @@ class CORE_EXPORT MouseEventManager final
// TODO: These functions ideally should be private but the code needs more
// refactoring to be able to remove the dependency from EventHandler.
- Node* GetNodeUnderMouse();
+ Element* GetElementUnderMouse();
bool IsMousePositionUnknown();
// TODO(aelias): Make LastKnownMousePosition return FloatPoint.
IntPoint LastKnownMousePosition();
@@ -217,7 +218,7 @@ class CORE_EXPORT MouseEventManager final
// The effective position of the mouse pointer.
// See
// https://w3c.github.io/pointerevents/#dfn-tracking-the-effective-position-of-the-legacy-mouse-pointer.
- Member<Node> node_under_mouse_;
+ Member<Element> element_under_mouse_;
// The last mouse movement position this frame has seen in viewport
// coordinates.
diff --git a/chromium/third_party/blink/renderer/core/input/overscroll_behavior_test.cc b/chromium/third_party/blink/renderer/core/input/overscroll_behavior_test.cc
index 4e35a028d7e..c642b37b9c6 100644
--- a/chromium/third_party/blink/renderer/core/input/overscroll_behavior_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/overscroll_behavior_test.cc
@@ -29,7 +29,7 @@ class OverscrollBehaviorTest : public SimTest {
void OverscrollBehaviorTest::SetUp() {
SimTest::SetUp();
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc b/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc
index fffde3296b6..990c1a953dc 100644
--- a/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -77,7 +77,7 @@ void PointerEventManager::Clear() {
non_hovering_pointers_canceled_ = false;
pointer_event_factory_.Clear();
touch_ids_for_canceled_pointerdowns_.clear();
- node_under_pointer_.clear();
+ element_under_pointer_.clear();
pointer_capture_target_.clear();
pending_pointer_capture_target_.clear();
user_gesture_holder_.reset();
@@ -86,7 +86,7 @@ void PointerEventManager::Clear() {
void PointerEventManager::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
- visitor->Trace(node_under_pointer_);
+ visitor->Trace(element_under_pointer_);
visitor->Trace(pointer_capture_target_);
visitor->Trace(pending_pointer_capture_target_);
visitor->Trace(touch_event_manager_);
@@ -157,7 +157,7 @@ WebInputEventResult PointerEventManager::DispatchPointerEvent(
if (!target)
return WebInputEventResult::kNotHandled;
- const int pointer_id = pointer_event->pointerId();
+ const PointerId pointer_id = pointer_event->pointerId();
const AtomicString& event_type = pointer_event->type();
if (!frame_ || !HasPointerEventListener(frame_->GetEventHandlerRegistry()))
@@ -177,23 +177,24 @@ WebInputEventResult PointerEventManager::DispatchPointerEvent(
UseCounter::Count(frame_, WebFeature::kPointerEventDispatchPointerDown);
DCHECK(!dispatching_pointer_id_);
- base::AutoReset<int> dispatch_holder(&dispatching_pointer_id_, pointer_id);
+ base::AutoReset<PointerId> dispatch_holder(&dispatching_pointer_id_,
+ pointer_id);
DispatchEventResult dispatch_result = target->DispatchEvent(*pointer_event);
return event_handling_util::ToWebInputEventResult(dispatch_result);
}
return WebInputEventResult::kNotHandled;
}
-EventTarget* PointerEventManager::GetEffectiveTargetForPointerEvent(
- EventTarget* target,
- int pointer_id) {
- if (EventTarget* capturing_target = GetCapturingNode(pointer_id))
+Element* PointerEventManager::GetEffectiveTargetForPointerEvent(
+ Element* target,
+ PointerId pointer_id) {
+ if (Element* capturing_target = GetCapturingElement(pointer_id))
return capturing_target;
return target;
}
void PointerEventManager::SendMouseAndPointerBoundaryEvents(
- Node* entered_node,
+ Element* entered_element,
const String& canvas_region_id,
const WebMouseEvent& mouse_event) {
// Mouse event type does not matter as this pointerevent will only be used
@@ -215,7 +216,7 @@ void PointerEventManager::SendMouseAndPointerBoundaryEvents(
mouse_event.pointer_type)] = false;
}
- ProcessCaptureAndPositionOfPointerEvent(dummy_pointer_event, entered_node,
+ ProcessCaptureAndPositionOfPointerEvent(dummy_pointer_event, entered_element,
canvas_region_id, &mouse_event);
}
@@ -227,22 +228,22 @@ void PointerEventManager::SendBoundaryEvents(EventTarget* exited_target,
boundary_event_dispatcher.SendBoundaryEvents(exited_target, entered_target);
}
-void PointerEventManager::SetNodeUnderPointer(PointerEvent* pointer_event,
- EventTarget* target) {
- if (node_under_pointer_.Contains(pointer_event->pointerId())) {
+void PointerEventManager::SetElementUnderPointer(PointerEvent* pointer_event,
+ Element* target) {
+ if (element_under_pointer_.Contains(pointer_event->pointerId())) {
EventTargetAttributes node =
- node_under_pointer_.at(pointer_event->pointerId());
+ element_under_pointer_.at(pointer_event->pointerId());
if (!target) {
- node_under_pointer_.erase(pointer_event->pointerId());
+ element_under_pointer_.erase(pointer_event->pointerId());
} else if (target !=
- node_under_pointer_.at(pointer_event->pointerId()).target) {
- node_under_pointer_.Set(pointer_event->pointerId(),
- EventTargetAttributes(target));
+ element_under_pointer_.at(pointer_event->pointerId()).target) {
+ element_under_pointer_.Set(pointer_event->pointerId(),
+ EventTargetAttributes(target));
}
SendBoundaryEvents(node.target, target, pointer_event);
} else if (target) {
- node_under_pointer_.insert(pointer_event->pointerId(),
- EventTargetAttributes(target));
+ element_under_pointer_.insert(pointer_event->pointerId(),
+ EventTargetAttributes(target));
SendBoundaryEvents(nullptr, target, pointer_event);
}
}
@@ -265,10 +266,10 @@ void PointerEventManager::HandlePointerInterruption(
// Cancel all non-hovering pointers if the pointer is not mouse.
if (!non_hovering_pointers_canceled_) {
- Vector<int> non_hovering_pointer_ids =
+ Vector<PointerId> non_hovering_pointer_ids =
pointer_event_factory_.GetPointerIdsOfNonHoveringPointers();
- for (int pointer_id : non_hovering_pointer_ids) {
+ for (PointerId pointer_id : non_hovering_pointer_ids) {
canceled_pointer_events.push_back(
pointer_event_factory_.CreatePointerCancelEvent(
pointer_id, web_pointer_event.TimeStamp()));
@@ -281,9 +282,9 @@ void PointerEventManager::HandlePointerInterruption(
for (auto pointer_event : canceled_pointer_events) {
// If we are sending a pointercancel we have sent the pointerevent to some
// target before.
- DCHECK(node_under_pointer_.Contains(pointer_event->pointerId()));
- EventTarget* target =
- node_under_pointer_.at(pointer_event->pointerId()).target;
+ DCHECK(element_under_pointer_.Contains(pointer_event->pointerId()));
+ Element* target =
+ element_under_pointer_.at(pointer_event->pointerId()).target;
DispatchPointerEvent(
GetEffectiveTargetForPointerEvent(target, pointer_event->pointerId()),
@@ -358,7 +359,8 @@ PointerEventManager::ComputePointerEventTarget(
const WebPointerEvent& web_pointer_event) {
event_handling_util::PointerEventTarget pointer_event_target;
- int pointer_id = pointer_event_factory_.GetPointerEventId(web_pointer_event);
+ PointerId pointer_id =
+ pointer_event_factory_.GetPointerEventId(web_pointer_event);
// Do the hit test either when the touch first starts or when the touch
// is not captured. |m_pendingPointerCaptureTarget| indicates the target
// that will be capturing this event. |m_pointerCaptureTarget| may not
@@ -373,34 +375,27 @@ PointerEventManager::ComputePointerEventTarget(
LayoutPoint(web_pointer_event.PositionInWidget())));
HitTestResult hit_test_tesult =
frame_->GetEventHandler().HitTestResultAtLocation(location, hit_type);
- Node* node = hit_test_tesult.InnerNode();
- if (node) {
- pointer_event_target.target_frame = node->GetDocument().GetFrame();
- if (auto* canvas = ToHTMLCanvasElementOrNull(node)) {
+ Element* target = hit_test_tesult.InnerElement();
+ if (target) {
+ pointer_event_target.target_frame = target->GetDocument().GetFrame();
+ if (auto* canvas = ToHTMLCanvasElementOrNull(target)) {
HitTestCanvasResult* hit_test_canvas_result =
canvas->GetControlAndIdIfHitRegionExists(
hit_test_tesult.PointInInnerNodeFrame());
if (hit_test_canvas_result->GetControl())
- node = hit_test_canvas_result->GetControl();
+ target = hit_test_canvas_result->GetControl();
pointer_event_target.region = hit_test_canvas_result->GetId();
}
- // TODO(crbug.com/612456): We need to investigate whether pointer
- // events should go to text nodes or not. If so we need to
- // update the mouse code as well. Also this logic looks similar
- // to the one in TouchEventManager. We should be able to
- // refactor it better after this investigation.
- if (node->IsTextNode())
- node = FlatTreeTraversal::Parent(*node);
- pointer_event_target.target_node = node;
+ pointer_event_target.target_element = target;
}
} else {
- // Set the target of pointer event to the captured node as this
+ // Set the target of pointer event to the captured element as this
// pointer is captured otherwise it would have gone to the if block
// and perform a hit-test.
- pointer_event_target.target_node =
- pending_pointer_capture_target_.at(pointer_id)->ToNode();
+ pointer_event_target.target_element =
+ pending_pointer_capture_target_.at(pointer_id);
pointer_event_target.target_frame =
- pointer_event_target.target_node->GetDocument().GetFrame();
+ pointer_event_target.target_element->GetDocument().GetFrame();
}
return pointer_event_target;
}
@@ -414,15 +409,15 @@ WebInputEventResult PointerEventManager::DispatchTouchPointerEvent(
WebInputEvent::Type::kPointerCausedUaAction);
WebInputEventResult result = WebInputEventResult::kHandledSystem;
- if (pointer_event_target.target_node && pointer_event_target.target_frame &&
- !non_hovering_pointers_canceled_) {
+ if (pointer_event_target.target_element &&
+ pointer_event_target.target_frame && !non_hovering_pointers_canceled_) {
PointerEvent* pointer_event = pointer_event_factory_.Create(
web_pointer_event, coalesced_events, predicted_events,
- pointer_event_target.target_node
- ? pointer_event_target.target_node->GetDocument().domWindow()
+ pointer_event_target.target_element
+ ? pointer_event_target.target_element->GetDocument().domWindow()
: nullptr);
- result = SendTouchPointerEvent(pointer_event_target.target_node,
+ result = SendTouchPointerEvent(pointer_event_target.target_element,
pointer_event, web_pointer_event.hovering);
// If a pointerdown has been canceled, queue the unique id to allow
@@ -442,7 +437,7 @@ WebInputEventResult PointerEventManager::DispatchTouchPointerEvent(
}
WebInputEventResult PointerEventManager::SendTouchPointerEvent(
- EventTarget* target,
+ Element* target,
PointerEvent* pointer_event,
bool hovering) {
if (non_hovering_pointers_canceled_)
@@ -516,7 +511,7 @@ WebInputEventResult PointerEventManager::HandlePointerEvent(
}
target = pointer_locked_element;
} else {
- target = ComputePointerEventTarget(event).target_node;
+ target = ComputePointerEventTarget(event).target_element;
}
PointerEvent* pointer_event =
@@ -627,12 +622,13 @@ WebInputEventResult PointerEventManager::DirectDispatchMousePointerEvent(
}
WebInputEventResult PointerEventManager::SendMousePointerEvent(
- Node* target,
+ Element* target,
const String& canvas_region_id,
const WebInputEvent::Type event_type,
const WebMouseEvent& mouse_event,
const Vector<WebMouseEvent>& coalesced_events,
- const Vector<WebMouseEvent>& predicted_events) {
+ const Vector<WebMouseEvent>& predicted_events,
+ bool skip_click_dispatch) {
DCHECK(event_type == WebInputEvent::kPointerDown ||
event_type == WebInputEvent::kPointerMove ||
event_type == WebInputEvent::kPointerUp);
@@ -674,14 +670,14 @@ WebInputEventResult PointerEventManager::SendMousePointerEvent(
}
}
- EventTarget* pointer_event_target = ProcessCaptureAndPositionOfPointerEvent(
+ Element* pointer_event_target = ProcessCaptureAndPositionOfPointerEvent(
pointer_event, target, canvas_region_id, &mouse_event);
// Don't send fake mouse event to the DOM.
if (fake_event)
return WebInputEventResult::kHandledSuppressed;
- EventTarget* effective_target = GetEffectiveTargetForPointerEvent(
+ Element* effective_target = GetEffectiveTargetForPointerEvent(
pointer_event_target, pointer_event->pointerId());
if ((event_type == WebInputEvent::kPointerDown ||
@@ -706,27 +702,38 @@ WebInputEventResult PointerEventManager::SendMousePointerEvent(
mouse_event.pointer_type)] = true;
}
+ // Only calculate mouse target if either mouse compatibility event or click
+ // should be sent.
if (pointer_event->isPrimary() &&
- !prevent_mouse_event_for_pointer_type_[ToPointerTypeIndex(
- mouse_event.pointer_type)]) {
- EventTarget* mouse_target = effective_target;
- // Event path could be null if pointer event is not dispatched and
- // that happens for example when pointer event feature is not enabled.
+ (!prevent_mouse_event_for_pointer_type_[ToPointerTypeIndex(
+ mouse_event.pointer_type)] ||
+ (!skip_click_dispatch && event_type == WebInputEvent::kPointerUp))) {
+ Element* mouse_target = effective_target;
+ // Event path could be null if the pointer event is not dispatched.
if (!event_handling_util::IsInDocument(mouse_target) &&
pointer_event->HasEventPath()) {
for (const auto& context :
pointer_event->GetEventPath().NodeEventContexts()) {
- if (event_handling_util::IsInDocument(&context.GetNode())) {
- mouse_target = &context.GetNode();
+ if (context.GetNode().IsElementNode() &&
+ event_handling_util::IsInDocument(&context.GetNode())) {
+ mouse_target = ToElement(&context.GetNode());
break;
}
}
}
- result = event_handling_util::MergeEventResult(
- result,
- mouse_event_manager_->DispatchMouseEvent(
- mouse_target, MouseEventNameForPointerEventInputType(event_type),
- mouse_event, canvas_region_id, &last_mouse_position, nullptr));
+ if (!prevent_mouse_event_for_pointer_type_[ToPointerTypeIndex(
+ mouse_event.pointer_type)]) {
+ result = event_handling_util::MergeEventResult(
+ result,
+ mouse_event_manager_->DispatchMouseEvent(
+ mouse_target, MouseEventNameForPointerEventInputType(event_type),
+ mouse_event, canvas_region_id, &last_mouse_position, nullptr));
+ }
+ if (!skip_click_dispatch && mouse_target &&
+ event_type == WebInputEvent::kPointerUp) {
+ mouse_event_manager_->DispatchMouseClickIfNeeded(
+ mouse_target, mouse_event, canvas_region_id);
+ }
}
if (pointer_event->type() == event_type_names::kPointerup ||
@@ -762,16 +769,16 @@ WebInputEventResult PointerEventManager::SendMousePointerEvent(
}
bool PointerEventManager::GetPointerCaptureState(
- int pointer_id,
- EventTarget** pointer_capture_target,
- EventTarget** pending_pointer_capture_target) {
+ PointerId pointer_id,
+ Element** pointer_capture_target,
+ Element** pending_pointer_capture_target) {
PointerCapturingMap::const_iterator it;
it = pointer_capture_target_.find(pointer_id);
- EventTarget* pointer_capture_target_temp =
+ Element* pointer_capture_target_temp =
(it != pointer_capture_target_.end()) ? it->value : nullptr;
it = pending_pointer_capture_target_.find(pointer_id);
- EventTarget* pending_pointercapture_target_temp =
+ Element* pending_pointercapture_target_temp =
(it != pending_pointer_capture_target_.end()) ? it->value : nullptr;
if (pointer_capture_target)
@@ -782,33 +789,32 @@ bool PointerEventManager::GetPointerCaptureState(
return pointer_capture_target_temp != pending_pointercapture_target_temp;
}
-EventTarget* PointerEventManager::ProcessCaptureAndPositionOfPointerEvent(
+Element* PointerEventManager::ProcessCaptureAndPositionOfPointerEvent(
PointerEvent* pointer_event,
- EventTarget* hit_test_target,
+ Element* hit_test_target,
const String& canvas_region_id,
const WebMouseEvent* mouse_event) {
ProcessPendingPointerCapture(pointer_event);
PointerCapturingMap::const_iterator it =
pointer_capture_target_.find(pointer_event->pointerId());
- if (EventTarget* pointercapture_target =
+ if (Element* pointercapture_target =
(it != pointer_capture_target_.end()) ? it->value : nullptr)
hit_test_target = pointercapture_target;
- SetNodeUnderPointer(pointer_event, hit_test_target);
+ SetElementUnderPointer(pointer_event, hit_test_target);
if (mouse_event) {
- mouse_event_manager_->SetNodeUnderMouse(
- hit_test_target ? hit_test_target->ToNode() : nullptr, canvas_region_id,
- *mouse_event);
+ mouse_event_manager_->SetElementUnderMouse(hit_test_target,
+ canvas_region_id, *mouse_event);
}
return hit_test_target;
}
void PointerEventManager::ProcessPendingPointerCapture(
PointerEvent* pointer_event) {
- EventTarget* pointer_capture_target;
- EventTarget* pending_pointer_capture_target;
- const int pointer_id = pointer_event->pointerId();
+ Element* pointer_capture_target;
+ Element* pending_pointer_capture_target;
+ const PointerId pointer_id = pointer_event->pointerId();
const bool is_capture_changed = GetPointerCaptureState(
pointer_id, &pointer_capture_target, &pending_pointer_capture_target);
@@ -821,8 +827,8 @@ void PointerEventManager::ProcessPendingPointerCapture(
// Re-target lostpointercapture to the document when the element is
// no longer participating in the tree.
EventTarget* target = pointer_capture_target;
- if (target->ToNode() && !target->ToNode()->isConnected()) {
- target = target->ToNode()->ownerDocument();
+ if (!pointer_capture_target->isConnected()) {
+ target = pointer_capture_target->ownerDocument();
}
DispatchPointerEvent(
target, pointer_event_factory_.CreatePointerCaptureEvent(
@@ -830,7 +836,7 @@ void PointerEventManager::ProcessPendingPointerCapture(
}
if (pending_pointer_capture_target) {
- SetNodeUnderPointer(pointer_event, pending_pointer_capture_target);
+ SetElementUnderPointer(pointer_event, pending_pointer_capture_target);
DispatchPointerEvent(
pending_pointer_capture_target,
pointer_event_factory_.CreatePointerCaptureEvent(
@@ -852,7 +858,7 @@ void PointerEventManager::ProcessPendingPointerCaptureForPointerLock(
void PointerEventManager::RemoveTargetFromPointerCapturingMapping(
PointerCapturingMap& map,
- const EventTarget* target) {
+ const Element* target) {
// We could have kept a reverse mapping to make this deletion possibly
// faster but it adds some code complication which might not be worth of
// the performance improvement considering there might not be a lot of
@@ -864,28 +870,28 @@ void PointerEventManager::RemoveTargetFromPointerCapturingMapping(
}
}
-EventTarget* PointerEventManager::GetCapturingNode(int pointer_id) {
+Element* PointerEventManager::GetCapturingElement(PointerId pointer_id) {
if (pointer_capture_target_.Contains(pointer_id))
return pointer_capture_target_.at(pointer_id);
return nullptr;
}
void PointerEventManager::RemovePointer(PointerEvent* pointer_event) {
- int pointer_id = pointer_event->pointerId();
+ PointerId pointer_id = pointer_event->pointerId();
if (pointer_event_factory_.Remove(pointer_id)) {
pending_pointer_capture_target_.erase(pointer_id);
pointer_capture_target_.erase(pointer_id);
- node_under_pointer_.erase(pointer_id);
+ element_under_pointer_.erase(pointer_id);
}
}
-void PointerEventManager::ElementRemoved(EventTarget* target) {
+void PointerEventManager::ElementRemoved(Element* target) {
RemoveTargetFromPointerCapturingMapping(pending_pointer_capture_target_,
target);
}
-void PointerEventManager::SetPointerCapture(int pointer_id,
- EventTarget* target) {
+void PointerEventManager::SetPointerCapture(PointerId pointer_id,
+ Element* target) {
UseCounter::Count(frame_, WebFeature::kPointerEventSetCapture);
if (pointer_event_factory_.IsActiveButtonsState(pointer_id)) {
if (pointer_id != dispatching_pointer_id_) {
@@ -896,8 +902,8 @@ void PointerEventManager::SetPointerCapture(int pointer_id,
}
}
-void PointerEventManager::ReleasePointerCapture(int pointer_id,
- EventTarget* target) {
+void PointerEventManager::ReleasePointerCapture(PointerId pointer_id,
+ Element* target) {
// Only the element that is going to get the next pointer event can release
// the capture. Note that this might be different from
// |m_pointercaptureTarget|. |m_pointercaptureTarget| holds the element
@@ -913,22 +919,16 @@ void PointerEventManager::ReleaseMousePointerCapture() {
ReleasePointerCapture(PointerEventFactory::kMouseId);
}
-bool PointerEventManager::HasPointerCapture(int pointer_id,
- const EventTarget* target) const {
+bool PointerEventManager::HasPointerCapture(PointerId pointer_id,
+ const Element* target) const {
return pending_pointer_capture_target_.at(pointer_id) == target;
}
-bool PointerEventManager::HasProcessedPointerCapture(
- int pointer_id,
- const EventTarget* target) const {
- return pointer_capture_target_.at(pointer_id) == target;
-}
-
-void PointerEventManager::ReleasePointerCapture(int pointer_id) {
+void PointerEventManager::ReleasePointerCapture(PointerId pointer_id) {
pending_pointer_capture_target_.erase(pointer_id);
}
-bool PointerEventManager::IsActive(const int pointer_id) const {
+bool PointerEventManager::IsActive(const PointerId pointer_id) const {
return pointer_event_factory_.IsActive(pointer_id);
}
@@ -937,17 +937,17 @@ bool PointerEventManager::IsActive(const int pointer_id) const {
// page managers to their target (event if target is in an iframe) and only
// those managers will keep track of these pointer events.
bool PointerEventManager::IsTouchPointerIdActiveOnFrame(
- int pointer_id,
+ PointerId pointer_id,
LocalFrame* frame) const {
if (pointer_event_factory_.GetPointerType(pointer_id) !=
WebPointerProperties::PointerType::kTouch)
return false;
- Node* last_node_receiving_event =
- node_under_pointer_.Contains(pointer_id)
- ? node_under_pointer_.at(pointer_id).target->ToNode()
+ Element* last_element_receiving_event =
+ element_under_pointer_.Contains(pointer_id)
+ ? element_under_pointer_.at(pointer_id).target
: nullptr;
- return last_node_receiving_event &&
- last_node_receiving_event->GetDocument().GetFrame() == frame;
+ return last_element_receiving_event &&
+ last_element_receiving_event->GetDocument().GetFrame() == frame;
}
bool PointerEventManager::IsAnyTouchActive() const {
diff --git a/chromium/third_party/blink/renderer/core/input/pointer_event_manager.h b/chromium/third_party/blink/renderer/core/input/pointer_event_manager.h
index 479d0189515..aa493c0be9c 100644
--- a/chromium/third_party/blink/renderer/core/input/pointer_event_manager.h
+++ b/chromium/third_party/blink/renderer/core/input/pointer_event_manager.h
@@ -44,12 +44,13 @@ class CORE_EXPORT PointerEventManager
// and sets the newNodeUnderMouse if the capturing is set
// in this function.
WebInputEventResult SendMousePointerEvent(
- Node* target,
+ Element* target,
const String& canvas_region_id,
const WebInputEvent::Type,
const WebMouseEvent&,
const Vector<WebMouseEvent>& coalesced_events,
- const Vector<WebMouseEvent>& predicted_events);
+ const Vector<WebMouseEvent>& predicted_events,
+ bool skip_click_dispatch);
// Sends boundary events pointerout/leave/over/enter and
// mouseout/leave/over/enter to the corresponding targets.
@@ -57,7 +58,7 @@ class CORE_EXPORT PointerEventManager
// leaving a frame. Note that normal mouse events (e.g. mousemove/down/up)
// and their corresponding boundary events will be handled altogether by
// sendMousePointerEvent function.
- void SendMouseAndPointerBoundaryEvents(Node* entered_node,
+ void SendMouseAndPointerBoundaryEvents(Element* entered_element,
const String& canvas_region_id,
const WebMouseEvent&);
@@ -79,26 +80,23 @@ class CORE_EXPORT PointerEventManager
// Resets the internal state of this object.
void Clear();
- void ElementRemoved(EventTarget*);
+ void ElementRemoved(Element*);
- void SetPointerCapture(int, EventTarget*);
- void ReleasePointerCapture(int, EventTarget*);
+ void SetPointerCapture(PointerId, Element*);
+ void ReleasePointerCapture(PointerId, Element*);
void ReleaseMousePointerCapture();
- // See Element::hasPointerCapture(int).
- bool HasPointerCapture(int, const EventTarget*) const;
-
- // See Element::hasProcessedPointerCapture(int).
- bool HasProcessedPointerCapture(int, const EventTarget*) const;
+ // See Element::hasPointerCapture(PointerId).
+ bool HasPointerCapture(PointerId, const Element*) const;
- bool IsActive(const int) const;
+ bool IsActive(const PointerId) const;
// Returns whether there is any touch on the screen.
bool IsAnyTouchActive() const;
// Returns whether pointerId is for an active touch pointerevent and whether
// the last event was sent to the given frame.
- bool IsTouchPointerIdActiveOnFrame(int, LocalFrame*) const;
+ bool IsTouchPointerIdActiveOnFrame(PointerId, LocalFrame*) const;
// Returns true if the primary pointerdown corresponding to the given
// |uniqueTouchEventId| was canceled. Also drops stale ids from
@@ -117,20 +115,19 @@ class CORE_EXPORT PointerEventManager
WebInputEventResult FlushEvents();
private:
- typedef HeapHashMap<int,
- Member<EventTarget>,
- WTF::IntHash<int>,
- WTF::UnsignedWithZeroKeyHashTraits<int>>
+ typedef HeapHashMap<PointerId,
+ Member<Element>,
+ WTF::IntHash<PointerId>,
+ WTF::UnsignedWithZeroKeyHashTraits<PointerId>>
PointerCapturingMap;
class EventTargetAttributes {
DISALLOW_NEW();
public:
void Trace(blink::Visitor* visitor) { visitor->Trace(target); }
- Member<EventTarget> target;
+ Member<Element> target;
EventTargetAttributes() : target(nullptr) {}
- EventTargetAttributes(EventTarget* target)
- : target(target) {}
+ EventTargetAttributes(Element* target) : target(target) {}
};
class PointerEventBoundaryEventDispatcher : public BoundaryEventDispatcher {
@@ -179,14 +176,14 @@ class CORE_EXPORT PointerEventManager
const event_handling_util::PointerEventTarget&);
// Returns whether the event is consumed or not.
- WebInputEventResult SendTouchPointerEvent(EventTarget*,
+ WebInputEventResult SendTouchPointerEvent(Element*,
PointerEvent*,
bool hovering);
void SendBoundaryEvents(EventTarget* exited_target,
EventTarget* entered_target,
PointerEvent*);
- void SetNodeUnderPointer(PointerEvent*, EventTarget*);
+ void SetElementUnderPointer(PointerEvent*, Element*);
// Processes the assignment of |m_pointerCaptureTarget| from
// |m_pendingPointerCaptureTarget| and sends the got/lostpointercapture
@@ -194,30 +191,30 @@ class CORE_EXPORT PointerEventManager
// https://w3c.github.io/pointerevents/#process-pending-pointer-capture
void ProcessPendingPointerCapture(PointerEvent*);
- // Processes the capture state of a pointer, updates node under
+ // Processes the capture state of a pointer, updates element under
// pointer, and sends corresponding boundary events for pointer if
// setPointerPosition is true. It also sends corresponding boundary events
// for mouse if sendMouseEvent is true.
// Returns the target that the pointer event is supposed to be fired at.
- EventTarget* ProcessCaptureAndPositionOfPointerEvent(
+ Element* ProcessCaptureAndPositionOfPointerEvent(
PointerEvent*,
- EventTarget* hit_test_target,
+ Element* hit_test_target,
const String& canvas_region_id = String(),
const WebMouseEvent* = nullptr);
void RemoveTargetFromPointerCapturingMapping(PointerCapturingMap&,
- const EventTarget*);
- EventTarget* GetEffectiveTargetForPointerEvent(EventTarget*, int);
- EventTarget* GetCapturingNode(int);
+ const Element*);
+ Element* GetEffectiveTargetForPointerEvent(Element*, PointerId);
+ Element* GetCapturingElement(PointerId);
void RemovePointer(PointerEvent*);
WebInputEventResult DispatchPointerEvent(EventTarget*,
PointerEvent*,
bool check_for_listener = false);
- void ReleasePointerCapture(int);
+ void ReleasePointerCapture(PointerId);
// Returns true if capture target and pending capture target were different.
- bool GetPointerCaptureState(int pointer_id,
- EventTarget** pointer_capture_target,
- EventTarget** pending_pointer_capture_target);
+ bool GetPointerCaptureState(PointerId pointer_id,
+ Element** pointer_capture_target,
+ Element** pending_pointer_capture_target);
// Only adjust touch type primary pointer down.
bool ShouldAdjustPointerEvent(const WebPointerEvent&) const;
@@ -242,16 +239,16 @@ class CORE_EXPORT PointerEventManager
Deque<uint32_t> touch_ids_for_canceled_pointerdowns_;
- // Note that this map keeps track of node under pointer with id=1 as well
+ // Note that this map keeps track of element under pointer with id=1 as well
// which might be different than m_nodeUnderMouse in EventHandler. That one
// keeps track of any compatibility mouse event positions but this map for
// the pointer with id=1 is only taking care of true mouse related events.
- using NodeUnderPointerMap =
- HeapHashMap<int,
+ using ElementUnderPointerMap =
+ HeapHashMap<PointerId,
EventTargetAttributes,
- WTF::IntHash<int>,
- WTF::UnsignedWithZeroKeyHashTraits<int>>;
- NodeUnderPointerMap node_under_pointer_;
+ WTF::IntHash<PointerId>,
+ WTF::UnsignedWithZeroKeyHashTraits<PointerId>>;
+ ElementUnderPointerMap element_under_pointer_;
PointerCapturingMap pointer_capture_target_;
PointerCapturingMap pending_pointer_capture_target_;
@@ -270,7 +267,7 @@ class CORE_EXPORT PointerEventManager
// The pointerId of the PointerEvent currently being dispatched within this
// frame or 0 if none.
- int dispatching_pointer_id_;
+ PointerId dispatching_pointer_id_;
DISALLOW_COPY_AND_ASSIGN(PointerEventManager);
};
diff --git a/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc b/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
index 99456b36254..925a18f607b 100644
--- a/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/core/input/pointer_event_manager.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
@@ -14,14 +14,10 @@
namespace blink {
namespace {
-class CheckPointerEventListenerCallback final : public EventListener {
+class CheckPointerEventListenerCallback final : public NativeEventListener {
public:
static CheckPointerEventListenerCallback* Create() {
- return new CheckPointerEventListenerCallback();
- }
-
- bool operator==(const EventListener& other) const override {
- return this == &other;
+ return MakeGarbageCollected<CheckPointerEventListenerCallback>();
}
void Invoke(ExecutionContext*, Event* event) override {
@@ -39,21 +35,16 @@ class CheckPointerEventListenerCallback final : public EventListener {
int penEventCount() const { return pen_event_received_count_; }
private:
- CheckPointerEventListenerCallback()
- : EventListener(EventListener::kCPPEventListenerType) {}
int mouse_event_received_count_ = 0;
int touch_event_received_count_ = 0;
int pen_event_received_count_ = 0;
};
-class PointerEventCoordinateListenerCallback final : public EventListener {
+class PointerEventCoordinateListenerCallback final
+ : public NativeEventListener {
public:
static PointerEventCoordinateListenerCallback* Create() {
- return new PointerEventCoordinateListenerCallback();
- }
-
- bool operator==(const EventListener& other) const override {
- return this == &other;
+ return MakeGarbageCollected<PointerEventCoordinateListenerCallback>();
}
void Invoke(ExecutionContext*, Event* event) override {
@@ -80,10 +71,6 @@ class PointerEventCoordinateListenerCallback final : public EventListener {
double last_height_ = 0;
double last_movement_x_ = 0;
double last_movement_y_ = 0;
-
- private:
- PointerEventCoordinateListenerCallback()
- : EventListener(EventListener::kCPPEventListenerType) {}
};
} // namespace
@@ -121,7 +108,7 @@ class PointerEventManagerTest : public SimTest {
};
TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
@@ -133,12 +120,12 @@ TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
GetDocument().body()->addEventListener(event_type_names::kPointercancel,
callback);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerDown,
WebPointerProperties::PointerType::kTouch),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerDown,
WebPointerProperties::PointerType::kPen),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
@@ -150,7 +137,7 @@ TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
ASSERT_EQ(callback->touchEventCount(), 0);
ASSERT_EQ(callback->penEventCount(), 0);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerCausedUaAction,
WebPointerProperties::PointerType::kPen),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
@@ -158,7 +145,7 @@ TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
ASSERT_EQ(callback->touchEventCount(), 1);
ASSERT_EQ(callback->penEventCount(), 1);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerCausedUaAction,
WebPointerProperties::PointerType::kTouch),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
@@ -176,7 +163,7 @@ TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
}
TEST_F(PointerEventManagerTest, PointerEventCoordinates) {
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
@@ -188,7 +175,7 @@ TEST_F(PointerEventManagerTest, PointerEventCoordinates) {
GetDocument().body()->addEventListener(event_type_names::kPointerdown,
callback);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerDown,
WebPointerProperties::PointerType::kTouch,
WebFloatPoint(150, 200), WebFloatPoint(100, 50),
@@ -208,7 +195,7 @@ TEST_F(PointerEventManagerTest, PointerEventCoordinates) {
}
TEST_F(PointerEventManagerTest, PointerEventMovements) {
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
@@ -222,7 +209,7 @@ TEST_F(PointerEventManagerTest, PointerEventMovements) {
// Turn on the flag for test.
RuntimeEnabledFeatures::SetMovementXYInBlinkEnabled(true);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 210), WebFloatPoint(100, 50),
@@ -234,7 +221,7 @@ TEST_F(PointerEventManagerTest, PointerEventMovements) {
ASSERT_EQ(callback->last_movement_x_, 0);
ASSERT_EQ(callback->last_movement_y_, 0);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 200), WebFloatPoint(132, 29),
@@ -246,7 +233,7 @@ TEST_F(PointerEventManagerTest, PointerEventMovements) {
ASSERT_EQ(callback->last_movement_x_, 32);
ASSERT_EQ(callback->last_movement_y_, -21);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 210),
@@ -262,7 +249,7 @@ TEST_F(PointerEventManagerTest, PointerEventMovements) {
// When flag is off, movementX/Y follows the value in WebPointerProperties.
RuntimeEnabledFeatures::SetMovementXYInBlinkEnabled(false);
- WebView().HandleInputEvent(WebCoalescedInputEvent(
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 210), WebFloatPoint(100, 16.25),
diff --git a/chromium/third_party/blink/renderer/core/input/scroll_manager.cc b/chromium/third_party/blink/renderer/core/input/scroll_manager.cc
index 68e636a737a..9be44ffdbb0 100644
--- a/chromium/third_party/blink/renderer/core/input/scroll_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -280,8 +280,35 @@ bool ScrollManager::LogicalScroll(ScrollDirection direction,
ScrollOffset delta = ToScrollDelta(physical_direction, 1);
delta.Scale(scrollable_area->ScrollStep(granularity, kHorizontalScrollbar),
scrollable_area->ScrollStep(granularity, kVerticalScrollbar));
- if (snap_coordinator->SnapForDirection(*box, delta))
- return true;
+ // Pressing the arrow key is considered as a scroll with intended direction
+ // only. Pressing the PgUp/PgDn key is considered as a scroll with intended
+ // direction and end position. Pressing the Home/End key is considered as a
+ // scroll with intended end position only.
+ switch (granularity) {
+ case kScrollByLine: {
+ if (snap_coordinator->SnapForDirection(*box, delta))
+ return true;
+ break;
+ }
+ case kScrollByPage: {
+ if (snap_coordinator->SnapForEndAndDirection(*box, delta))
+ return true;
+ break;
+ }
+ case kScrollByDocument: {
+ FloatPoint end_position = scrollable_area->ScrollPosition() + delta;
+ bool scrolled_x = physical_direction == kScrollLeft ||
+ physical_direction == kScrollRight;
+ bool scrolled_y = physical_direction == kScrollUp ||
+ physical_direction == kScrollDown;
+ if (snap_coordinator->SnapForEndPosition(*box, end_position, scrolled_x,
+ scrolled_y))
+ return true;
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
ScrollResult result = scrollable_area->UserScroll(
granularity, ToScrollDelta(physical_direction, 1));
@@ -575,6 +602,19 @@ WebInputEventResult ScrollManager::HandleGestureScrollUpdate(
if (did_scroll_x || did_scroll_y)
return WebInputEventResult::kHandledSystem;
+ if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
+ // Send the overscroll event to the node that scrolling is latched to which
+ // is either previously scrolled node or the last node in the scroll chain.
+ Node* overscroll_target = previous_gesture_scrolled_node_;
+ if (!overscroll_target && !current_scroll_chain_.empty())
+ overscroll_target = DOMNodeIds::NodeForId(current_scroll_chain_.front());
+
+ if (overscroll_target) {
+ overscroll_target->GetDocument().EnqueueOverscrollEventForNode(
+ overscroll_target, delta.Width(), delta.Height());
+ }
+ }
+
return WebInputEventResult::kNotHandled;
}
@@ -604,6 +644,21 @@ WebInputEventResult ScrollManager::HandleGestureScrollEnd(
CustomizedScroll(*scroll_state);
SnapAtGestureScrollEnd();
NotifyScrollPhaseEndForCustomizedScroll();
+
+ if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
+ // Send the scrollend event to the node that scrolling is latched to
+ // which is either previously scrolled node or the last node in the
+ // scroll chain.
+ DCHECK(!current_scroll_chain_.empty());
+ if (previous_gesture_scrolled_node_) {
+ previous_gesture_scrolled_node_->GetDocument()
+ .EnqueueScrollEndEventForNode(previous_gesture_scrolled_node_);
+ } else if (Node* scroll_end_target =
+ DOMNodeIds::NodeForId(current_scroll_chain_.front())) {
+ scroll_end_target->GetDocument().EnqueueScrollEndEventForNode(
+ scroll_end_target);
+ }
+ }
}
ClearGestureScrollState();
@@ -628,9 +683,9 @@ void ScrollManager::SnapAtGestureScrollEnd() {
if (!snap_coordinator || !layout_box)
return;
- snap_coordinator->SnapForEndPosition(*layout_box,
- did_scroll_x_for_scroll_gesture_,
- did_scroll_y_for_scroll_gesture_);
+ snap_coordinator->SnapAtCurrentPosition(*layout_box,
+ did_scroll_x_for_scroll_gesture_,
+ did_scroll_y_for_scroll_gesture_);
}
bool ScrollManager::GetSnapFlingInfo(
diff --git a/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc b/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc
index 4ad3129285f..d8d162a1a38 100644
--- a/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc
@@ -33,7 +33,7 @@ class ScrollSnapTest : public SimTest {
void ScrollSnapTest::SetUpForDiv() {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -204,7 +204,7 @@ TEST_F(ScrollSnapTest, AnimateFlingToArriveAtSnapPoint) {
TEST_F(ScrollSnapTest, SnapWhenBodyViewportDefining) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -251,7 +251,7 @@ TEST_F(ScrollSnapTest, SnapWhenBodyViewportDefining) {
TEST_F(ScrollSnapTest, SnapWhenHtmlViewportDefining) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -301,7 +301,7 @@ TEST_F(ScrollSnapTest, SnapWhenHtmlViewportDefining) {
TEST_F(ScrollSnapTest, SnapWhenBodyOverflowHtmlViewportDefining) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/input/touch_action_test.cc b/chromium/third_party/blink/renderer/core/input/touch_action_test.cc
index 4e3e1f4d0cd..8fddb09c5c8 100644
--- a/chromium/third_party/blink/renderer/core/input/touch_action_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/touch_action_test.cc
@@ -115,7 +115,7 @@ class TouchActionTest : public testing::Test {
void RunShadowDOMTest(std::string file);
void RunIFrameTest(std::string file);
void SendTouchEvent(WebView*, WebInputEvent::Type, IntPoint client_point);
- WebViewImpl* SetupTest(std::string file, TouchActionTrackingWebWidgetClient&);
+ WebViewImpl* SetupTest(std::string file, TouchActionTrackingWebWidgetClient*);
void RunTestOnTree(ContainerNode* root,
WebView*,
TouchActionTrackingWebWidgetClient&);
@@ -137,7 +137,7 @@ void TouchActionTest::RunTouchActionTest(std::string file) {
// turn them into persistent, stack allocated references. This
// workaround is sufficient to handle this artificial test
// scenario.
- WebViewImpl* web_view = SetupTest(file, client);
+ WebViewImpl* web_view = SetupTest(file, &client);
Persistent<Document> document =
static_cast<Document*>(web_view->MainFrameImpl()->GetDocument());
@@ -150,7 +150,7 @@ void TouchActionTest::RunTouchActionTest(std::string file) {
void TouchActionTest::RunShadowDOMTest(std::string file) {
TouchActionTrackingWebWidgetClient client;
- WebViewImpl* web_view = SetupTest(file, client);
+ WebViewImpl* web_view = SetupTest(file, &client);
DummyExceptionStateForTesting es;
@@ -178,7 +178,7 @@ void TouchActionTest::RunShadowDOMTest(std::string file) {
void TouchActionTest::RunIFrameTest(std::string file) {
TouchActionTrackingWebWidgetClient client;
- WebViewImpl* web_view = SetupTest(file, client);
+ WebViewImpl* web_view = SetupTest(file, &client);
WebFrame* cur_frame = web_view->MainFrame()->FirstChild();
ASSERT_TRUE(cur_frame);
@@ -196,17 +196,17 @@ void TouchActionTest::RunIFrameTest(std::string file) {
WebViewImpl* TouchActionTest::SetupTest(
std::string file,
- TouchActionTrackingWebWidgetClient& client) {
+ TouchActionTrackingWebWidgetClient* client) {
url_test_helpers::RegisterMockedURLLoadFromBase(
WebString::FromUTF8(base_url_), test::CoreTestDataPath(),
WebString::FromUTF8(file));
// Note that JavaScript must be enabled for shadow DOM tests.
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
- base_url_ + file, nullptr, nullptr, &client);
+ base_url_ + file, nullptr, nullptr, client);
// Set size to enable hit testing, and avoid line wrapping for consistency
// with browser.
- web_view->Resize(WebSize(900, 1600));
+ web_view->MainFrameWidget()->Resize(WebSize(900, 1600));
// Scroll to verify the code properly transforms windows to client co-ords.
const int kScrollOffset = 100;
diff --git a/chromium/third_party/blink/renderer/core/input/touch_event_manager.cc b/chromium/third_party/blink/renderer/core/input/touch_event_manager.cc
index b066894903a..e3f6c92a216 100644
--- a/chromium/third_party/blink/renderer/core/input/touch_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/touch_event_manager.cc
@@ -518,7 +518,7 @@ void TouchEventManager::UpdateTouchAttributeMapsForPointerDown(
touch_attribute_map_.Set(event.id,
MakeGarbageCollected<TouchPointAttributes>(event));
- Node* touch_node = pointer_event_target.target_node;
+ Node* touch_node = pointer_event_target.target_element;
String region = pointer_event_target.region;
HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kTouchEvent |
diff --git a/chromium/third_party/blink/renderer/core/input/touch_event_manager_test.cc b/chromium/third_party/blink/renderer/core/input/touch_event_manager_test.cc
index 82f8ae64a44..6ab31db0d5f 100644
--- a/chromium/third_party/blink/renderer/core/input/touch_event_manager_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/touch_event_manager_test.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 "third_party/blink/renderer/core/input/touch_event_manager.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
-#include "third_party/blink/renderer/core/input/touch_event_manager.h"
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -32,13 +32,10 @@ class TouchEventManagerTest : public SimTest {
}
};
-class CheckEventListenerCallback final : public EventListener {
+class CheckEventListenerCallback final : public NativeEventListener {
public:
static CheckEventListenerCallback* Create() {
- return new CheckEventListenerCallback();
- }
- bool operator==(const EventListener& other) const override {
- return this == &other;
+ return MakeGarbageCollected<CheckEventListenerCallback>();
}
void Invoke(ExecutionContext*, Event* event) override {
@@ -48,15 +45,11 @@ class CheckEventListenerCallback final : public EventListener {
bool HasReceivedEvent() const { return event_received_; }
private:
- CheckEventListenerCallback()
- : EventListener(EventListener::kCPPEventListenerType) {
- event_received_ = false;
- }
- bool event_received_;
+ bool event_received_ = false;
};
TEST_F(TouchEventManagerTest, LostTouchDueToInnerIframeRemove) {
- WebView().Resize(WebSize(400, 400));
+ WebView().MainFrameWidget()->Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/inspector/InspectorOverlayPage.html b/chromium/third_party/blink/renderer/core/inspector/InspectorOverlayPage.html
index 0122dc51ec1..4e8b5a56632 100644
--- a/chromium/third_party/blink/renderer/core/inspector/InspectorOverlayPage.html
+++ b/chromium/third_party/blink/renderer/core/inspector/InspectorOverlayPage.html
@@ -32,21 +32,29 @@
body {
margin: 0;
padding: 0;
+ font-size: 13px;
+ color: #222;
+ --arrow-width: 15px;
+ --arrow-height: 8px;
+ --shadow-up: 5px;
+ --shadow-down: -5px;
+ --shadow-direction: var(--shadow-up);
+ --arrow-up: polygon(0 0, 100% 0, 50% 100%);
+ --arrow-down: polygon(50% 0, 0 100%, 100% 100%);
+ --arrow: var(--arrow-up);
}
-body.platform-mac {
- font-size: 11px;
- font-family: Menlo, Monaco;
+body.platform-linux {
+ font-family: Roboto, Ubuntu, Arial, sans-serif;
}
-body.platform-windows {
- font-size: 12px;
- font-family: Consolas, Lucida Console;
+body.platform-mac {
+ color: rgb(48, 57, 66);
+ font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;
}
-body.platform-linux {
- font-size: 11px;
- font-family: dejavu sans mono;
+body.platform-windows {
+ font-family: 'Segoe UI', Tahoma, sans-serif;
}
.fill {
@@ -99,9 +107,6 @@ body.platform-linux {
padding: 0;
flex-shrink: 0;
flex-grow: 0;
-}
-
-.controls-line .button:hover {
cursor: pointer;
}
@@ -140,84 +145,113 @@ body.platform-linux {
z-index: 10;
}
-#tag-name {
- /* Keep this in sync with view-source.css (.html-tag) */
- color: rgb(136, 18, 128);
-}
-
-#node-id {
- /* Keep this in sync with view-source.css (.html-attribute-value) */
- color: rgb(26, 26, 166);
-}
-
-#class-name {
- /* Keep this in sync with view-source.css (.html-attribute-name) */
- color: rgb(153, 69, 0);
-}
-
/* Material */
.hidden {
display: none !important;
}
-.tooltip-content,
-.material-tooltip-arrow {
+.tooltip-content {
position: absolute;
z-index: 10;
-webkit-user-select: none;
}
.tooltip-content {
- background-color: #333740;
- font-size: 11px;
- line-height: 14px;
+ background-color: white;
padding: 5px 8px;
border-radius: 3px;
- color: white;
box-sizing: border-box;
max-width: calc(100% - 4px);
- border: 1px solid hsla(0, 0%, 100%, 0.3);
z-index: 1;
background-clip: padding-box;
will-change: transform;
text-rendering: optimizeLegibility;
pointer-events: none;
+ filter: drop-shadow(0 2px 4px rgba(0,0,0,0.35));
+}
+
+.tooltip-content::after {
+ content: "";
+ background: white;
+ width: var(--arrow-width);
+ height: var(--arrow-height);
+ clip-path: var(--arrow);
+ position: absolute;
+ top: var(--arrow-top);
+ left: var(--arrow-left);
+ visibility: var(--arrow-visibility);
}
.element-info {
display: flex;
+ flex-direction: column;
+ line-height: 16px;
+}
+
+.element-info-header {
+ display: flex;
align-content: stretch;
+ line-height: 16px;
+}
+
+.element-info-body {
+ display: flex;
+ flex-direction: column;
+ border-top: 1px solid #999;
+ padding-top: 2px;
+ margin-top: 2px;
}
-.material-tooltip-arrow {
- border: solid;
- border-color: #333740 transparent;
- border-width: 0 8px 8px 8px;
- z-index: 2;
- margin-top: 1px;
+.element-info-row {
+ display: flex;
+ line-height: 19px;
}
-.material-tooltip-arrow.tooltip-arrow-top {
- border-width: 8px 8px 0 8px;
- margin-top: -1px;
+.element-info-row > * {
+ flex: none;
+}
+
+.element-info-name {
+ color: #666;
+}
+
+.element-info-gap {
+ flex: auto;
+}
+
+.element-info-value {
+ display: flex;
+ text-align: right;
+ color: rgb(48, 57, 66);
+ margin-left: 10px;
+ align-items: baseline;
+}
+
+.color-swatch {
+ display: flex;
+ margin-right: 2px;
+ width: 10px;
+ height: 10px;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
+ line-height: 10px;
+}
+
+.color-swatch-inner {
+ flex: auto;
+ border: 1px solid rgba(128, 128, 128, 0.6);
}
.element-description {
flex: 1 1;
+ font-weight: bold;
word-wrap: break-word;
word-break: break-all;
}
.dimensions {
- border-left: 1px solid hsl(0, 0%, 50%);
- padding-left: 7px;
- margin-left: 7px;
- float: right;
- flex: 0 0 auto;
- white-space: nowrap;
- display: flex;
- align-items: center;
- color: hsl(0, 0%, 85%);
+ color: hsl(0, 0%, 45%);
+ text-align: right;
+ margin-left: 10px;
}
.material-node-width {
@@ -229,15 +263,23 @@ body.platform-linux {
}
.material-tag-name {
- color: hsl(304, 77%, 70%);
+ /* Keep this in sync with inspectorSyntaxHighlight.css (--dom-tag-name-color) */
+ color: rgb(136, 18, 128);
}
-.material-node-id {
- color: hsl(27, 100%, 70%);
+.material-class-name, .material-node-id {
+ /* Keep this in sync with inspectorSyntaxHighlight.css (.webkit-html-attribute-value) */
+ color: rgb(26, 26, 166);
}
-.material-class-name {
- color: hsl(202,92%,77%);
+.contrast-text {
+ border-radius: 3px;
+ width: 20px;
+ height: 16px;
+ text-align: center;
+ line-height: 16px;
+ margin-right: 9px;
+ border: 1px solid #ccc;
}
</style>
@@ -439,7 +481,6 @@ function reset(resetData)
window._controlsVisible = false;
document.querySelector(".controls-line").style.visibility = "hidden";
- document.getElementById("element-title").style.visibility = "hidden";
document.getElementById("tooltip-container").removeChildren();
document.body.classList.remove("dimmed");
@@ -447,144 +488,243 @@ function reset(resetData)
window._gridPainted = false;
}
-function _drawElementTitle(context, elementInfo, bounds)
-{
- document.getElementById("tag-name").textContent = elementInfo.tagName;
- document.getElementById("node-id").textContent = elementInfo.idValue ? "#" + elementInfo.idValue : "";
- document.getElementById("class-name").textContent = (elementInfo.className || "").trimEnd(50);
- document.getElementById("node-width").textContent = elementInfo.nodeWidth;
- document.getElementById("node-height").textContent = elementInfo.nodeHeight;
- var elementTitle = document.getElementById("element-title");
-
- var titleWidth = elementTitle.offsetWidth + 6;
- var titleHeight = elementTitle.offsetHeight + 4;
-
- var anchorTop = bounds.minY;
- var anchorBottom = bounds.maxY;
- var anchorLeft = bounds.minX;
-
- const arrowHeight = 7;
- var renderArrowUp = false;
- var renderArrowDown = false;
-
- var boxX = Math.max(2, anchorLeft);
- if (boxX + titleWidth > canvasWidth)
- boxX = canvasWidth - titleWidth - 2;
-
- var boxY;
- if (anchorTop > canvasHeight) {
- boxY = canvasHeight - titleHeight - arrowHeight;
- renderArrowDown = true;
- } else if (anchorBottom < 0) {
- boxY = arrowHeight;
- renderArrowUp = true;
- } else if (anchorBottom + titleHeight + arrowHeight < canvasHeight) {
- boxY = anchorBottom + arrowHeight - 4;
- renderArrowUp = true;
- } else if (anchorTop - titleHeight - arrowHeight > 0) {
- boxY = anchorTop - titleHeight - arrowHeight + 3;
- renderArrowDown = true;
- } else
- boxY = arrowHeight;
+/**
+ * @param {!String} hexa
+ * @return {!Array<number>}
+ */
+function parseHexa(hexa) {
+ return hexa.match(/#(\w\w)(\w\w)(\w\w)(\w\w)/).slice(1).map(c => parseInt(c, 16) / 255);
+}
- context.save();
- context.translate(0.5, 0.5);
- context.beginPath();
- context.moveTo(boxX, boxY);
- if (renderArrowUp) {
- context.lineTo(boxX + 2 * arrowHeight, boxY);
- context.lineTo(boxX + 3 * arrowHeight, boxY - arrowHeight);
- context.lineTo(boxX + 4 * arrowHeight, boxY);
+/**
+ * @param {!String} hexa
+ * @return {!Array<number>}
+ */
+function normalizeColorString(hexa) {
+ if (hexa.endsWith("FF"))
+ return hexa.substr(0, 7);
+ const [r, g, b, a] = parseHexa(hexa);
+ return `rgba(${(r * 255).toFixed()}, ${(g * 255).toFixed()}, ${(b * 255).toFixed()}, ${Math.round(a * 100) / 100})`;
+}
+
+/**
+* Calculate the contrast ratio between a foreground and a background color.
+* Returns the ratio to 1, for example for two colors with a contrast ratio of 21:1,
+* this function will return 21.
+* See http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
+* @param {!Array<number>} fgRGBA
+* @param {!Array<number>} bgRGBA
+* @return {number}
+*/
+function contrastRatio(fgRGBA, bgRGBA) {
+ // If we have a semi-transparent background color over an unknown
+ // background, draw the line for the "worst case" scenario: where
+ // the unknown background is the same color as the text.
+ bgRGBA = blendColors(bgRGBA, fgRGBA);
+ const fgLuminance = luminance(blendColors(fgRGBA, bgRGBA));
+ const bgLuminance = luminance(bgRGBA);
+ const result = (Math.max(fgLuminance, bgLuminance) + 0.05) / (Math.min(fgLuminance, bgLuminance) + 0.05);
+ return result.toFixed(2);
+
+ /**
+ * Calculate the luminance of this color using the WCAG algorithm.
+ * See http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ * @param {!Array<number>} rgba
+ * @return {number}
+ */
+ function luminance(rgba) {
+ const rSRGB = rgba[0];
+ const gSRGB = rgba[1];
+ const bSRGB = rgba[2];
+
+ const r = rSRGB <= 0.03928 ? rSRGB / 12.92 : Math.pow(((rSRGB + 0.055) / 1.055), 2.4);
+ const g = gSRGB <= 0.03928 ? gSRGB / 12.92 : Math.pow(((gSRGB + 0.055) / 1.055), 2.4);
+ const b = bSRGB <= 0.03928 ? bSRGB / 12.92 : Math.pow(((bSRGB + 0.055) / 1.055), 2.4);
+
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
- context.lineTo(boxX + titleWidth, boxY);
- context.lineTo(boxX + titleWidth, boxY + titleHeight);
- if (renderArrowDown) {
- context.lineTo(boxX + 4 * arrowHeight, boxY + titleHeight);
- context.lineTo(boxX + 3 * arrowHeight, boxY + titleHeight + arrowHeight);
- context.lineTo(boxX + 2 * arrowHeight, boxY + titleHeight);
+
+ /**
+ * Combine the two given color according to alpha blending.
+ * @param {!Array<number>} fgRGBA
+ * @param {!Array<number>} bgRGBA
+ * @return {!Array<number>}
+ */
+ function blendColors(fgRGBA, bgRGBA) {
+ const alpha = fgRGBA[3];
+ return [
+ ((1 - alpha) * bgRGBA[0]) + (alpha * fgRGBA[0]),
+ ((1 - alpha) * bgRGBA[1]) + (alpha * fgRGBA[1]),
+ ((1 - alpha) * bgRGBA[2]) + (alpha * fgRGBA[2]),
+ alpha + (bgRGBA[3] * (1 - alpha))
+ ];
}
- context.lineTo(boxX, boxY + titleHeight);
- context.closePath();
- context.fillStyle = "rgb(255, 255, 194)";
- context.fill();
- context.strokeStyle = "rgb(128, 128, 128)";
- context.stroke();
+}
- context.restore();
+function computeIsLargeFont(contrast) {
+ const boldWeights = new Set(['bold', 'bolder', '600', '700', '800', '900']);
+
+ const fontSizePx = parseFloat(contrast.fontSize.replace('px', ''));
+ const isBold = boldWeights.has(contrast.fontWeight);
- elementTitle.style.visibility = "visible";
- elementTitle.style.top = (boxY + 3) + "px";
- elementTitle.style.left = (boxX + 3) + "px";
+ const fontSizePt = fontSizePx * 72 / 96;
+ if (isBold)
+ return fontSizePt >= 14;
+ else
+ return fontSizePt >= 18;
}
function _createElementDescription(elementInfo)
{
- var elementInfoElement = createElement("div", "element-info");
- var descriptionElement = elementInfoElement.createChild("div", "element-description monospace");
- var tagNameElement = descriptionElement.createChild("b").createChild("span", "material-tag-name");
+ const elementInfoElement = createElement("div", "element-info");
+ const elementInfoHeaderElement = elementInfoElement.createChild("div", "element-info-header");
+ const descriptionElement = elementInfoHeaderElement.createChild("div", "element-description monospace");
+ const tagNameElement = descriptionElement.createChild("span", "material-tag-name");
tagNameElement.textContent = elementInfo.tagName;
- var nodeIdElement = descriptionElement.createChild("span", "material-node-id");
+ const nodeIdElement = descriptionElement.createChild("span", "material-node-id");
nodeIdElement.textContent = elementInfo.idValue ? "#" + elementInfo.idValue : "";
nodeIdElement.classList.toggle("hidden", !elementInfo.idValue);
- var classNameElement = descriptionElement.createChild("span", "material-class-name");
- classNameElement.textContent = (elementInfo.className || "").trim(50);
+ const classNameElement = descriptionElement.createChild("span", "material-class-name");
+ classNameElement.textContent = (elementInfo.className || "").trimEnd(50);
classNameElement.classList.toggle("hidden", !elementInfo.className);
- var dimensionsElement = elementInfoElement.createChild("div", "dimensions");
+ const dimensionsElement = elementInfoHeaderElement.createChild("div", "dimensions");
dimensionsElement.createChild("span", "material-node-width").textContent = Math.round(elementInfo.nodeWidth * 100) / 100;
dimensionsElement.createTextChild("\u00d7");
dimensionsElement.createChild("span", "material-node-height").textContent = Math.round(elementInfo.nodeHeight * 100) / 100;
+
+ const style = elementInfo.style || {};
+ let elementInfoBodyElement;
+
+ const color = style["color"];
+ if (color && color !== "#00000000")
+ addColorRow("Color", color);
+
+ const fontFamily = style["font-family"];
+ const fontSize = style["font-size"];
+ if (fontFamily && fontSize !== "0px")
+ addTextRow("Font", `${fontSize} ${fontFamily}`.trimEnd(20));
+
+ const bgcolor = style["background-color"];
+ if (bgcolor && bgcolor !== "#00000000")
+ addColorRow("Background", bgcolor);
+
+ const margin = style["margin"];
+ if (margin && margin !== "0px")
+ addTextRow("Margin", margin);
+
+ const padding = style["padding"];
+ if (padding && padding !== "0px")
+ addTextRow("Padding", padding);
+
+ const cbgColor = elementInfo.contrast ? elementInfo.contrast.backgroundColor : null;
+ if (color && color !== "#00000000" && cbgColor && cbgColor !== "#00000000")
+ addContrastRow(style["color"], elementInfo.contrast);
+
+ function addRow(name) {
+ if (!elementInfoBodyElement)
+ elementInfoBodyElement = elementInfoElement.createChild("div", "element-info-body")
+ const rowElement = elementInfoBodyElement.createChild("div", "element-info-row");
+ const nameElement = rowElement.createChild("div", "element-info-name");
+ nameElement.textContent = name;
+ rowElement.createChild("div", "element-info-gap");
+ return rowElement.createChild("div", "element-info-value");
+ }
+
+ function addTextRow(name, value) {
+ addRow(name).createTextChild(value);
+ }
+
+ function addColorRow(name, color) {
+ const valueElement = addRow(name);
+ const swatch = valueElement.createChild("div", "color-swatch");
+ const inner = swatch.createChild("div", "color-swatch-inner");
+ inner.style.backgroundColor = color;
+ valueElement.createTextChild(normalizeColorString(color));
+ }
+
+ function addContrastRow(fgColor, contrast) {
+ const ratio = contrastRatio(parseHexa(fgColor), parseHexa(contrast.backgroundColor));
+ const threshold = computeIsLargeFont(contrast) ? 3.0 : 4.5;
+ const valueElement = addRow("Contrast");
+ const sampleText = valueElement.createChild("div", "contrast-text");
+ sampleText.style.color = fgColor;
+ sampleText.style.backgroundColor = contrast.backgroundColor;
+ sampleText.textContent = "Aa";
+ const valueSpan = valueElement.createChild("span");
+ valueSpan.textContent = Math.round(ratio * 100) / 100;
+ if (ratio < threshold) {
+ valueSpan.style.color = "red";
+ valueSpan.style.paddingRight = "5px";
+ valueElement.createTextChild(` < ${threshold.toFixed(1)}`);
+ }
+ }
+
return elementInfoElement;
}
-function _drawMaterialElementTitle(elementInfo, bounds)
+function _drawElementTitle(elementInfo, bounds)
{
- var tooltipContainer = document.getElementById("tooltip-container");
+ const tooltipContainer = document.getElementById("tooltip-container");
tooltipContainer.removeChildren();
_createMaterialTooltip(tooltipContainer, bounds, _createElementDescription(elementInfo), true);
}
function _createMaterialTooltip(parentElement, bounds, contentElement, withArrow)
{
- var tooltipContainer = parentElement.createChild("div");
- var tooltipContent = tooltipContainer.createChild("div", "tooltip-content");
+ const tooltipContainer = parentElement.createChild("div");
+ const tooltipContent = tooltipContainer.createChild("div", "tooltip-content");
tooltipContent.appendChild(contentElement);
- var titleWidth = tooltipContent.offsetWidth;
- var titleHeight = tooltipContent.offsetHeight;
- var arrowRadius = 8;
- var pageMargin = 2;
+ const titleWidth = tooltipContent.offsetWidth;
+ const titleHeight = tooltipContent.offsetHeight;
+ const arrowHalfWidth = 8;
+ const pageMargin = 2;
+ const arrowWidth = arrowHalfWidth * 2;
+ const arrowInset = arrowHalfWidth + 2;
+
+ const containerMinX = pageMargin + arrowInset;
+ const containerMaxX = canvasWidth - pageMargin - arrowInset - arrowWidth;
+
+ // Left align arrow to the tooltip but ensure it is pointing to the element.
+ // Center align arrow if the inspected element bounds are too narrow.
+ const boundsAreTooNarrow = bounds.maxX - bounds.minX < arrowWidth + 2 * arrowInset;
+ let arrowX;
+ if (boundsAreTooNarrow) {
+ arrowX = (bounds.minX + bounds.maxX) * 0.5 - arrowHalfWidth;
+ } else {
+ const xFromLeftBound = bounds.minX + arrowInset;
+ const xFromRightBound = bounds.maxX - arrowInset - arrowWidth;
+ if (xFromLeftBound > containerMinX && xFromLeftBound < containerMaxX)
+ arrowX = xFromLeftBound;
+ else
+ arrowX = Number.constrain(containerMinX, xFromLeftBound, xFromRightBound);
+ }
+ // Hide arrow if element is completely off the sides of the page.
+ const arrowHidden = !withArrow || arrowX < containerMinX || arrowX > containerMaxX;
- var boxX = Math.min(bounds.minX, canvasWidth - titleWidth - pageMargin);
+ let boxX = arrowX - arrowInset;
+ boxX = Number.constrain(boxX, pageMargin, canvasWidth - titleWidth - pageMargin);
- var boxY = bounds.minY - arrowRadius - titleHeight;
- var onTop = true;
+ let boxY = bounds.minY - arrowHalfWidth - titleHeight;
+ let onTop = true;
if (boxY < 0) {
- boxY = Math.min(canvasHeight - titleHeight, bounds.maxY + arrowRadius);
+ boxY = Math.min(canvasHeight - titleHeight, bounds.maxY + arrowHalfWidth);
onTop = false;
} else if (bounds.minY > canvasHeight) {
- boxY = canvasHeight - arrowRadius - titleHeight;
+ boxY = canvasHeight - arrowHalfWidth - titleHeight;
}
tooltipContent.style.top = boxY + "px";
tooltipContent.style.left = boxX + "px";
- if (!withArrow)
+ tooltipContent.style.setProperty('--arrow-visibility', arrowHidden ? 'hidden' : 'visible');
+ if (arrowHidden)
return;
- var tooltipArrow = tooltipContainer.createChild("div", "material-tooltip-arrow");
- // Left align arrow to the tooltip but ensure it is pointing to the element.
- var tooltipBorderRadius = 2;
- var arrowX = boxX + arrowRadius + tooltipBorderRadius;
- if (arrowX < bounds.minX)
- arrowX = bounds.minX + arrowRadius;
- // Hide arrow if element is completely off the sides of the page.
- var arrowHidden = arrowX < pageMargin + tooltipBorderRadius || arrowX + arrowRadius * 2 > canvasWidth - pageMargin - tooltipBorderRadius;
- tooltipArrow.classList.toggle("hidden", arrowHidden);
- if (!arrowHidden) {
- tooltipArrow.classList.toggle("tooltip-arrow-top", onTop);
- tooltipArrow.style.top = (onTop ? boxY + titleHeight : boxY - arrowRadius) + "px";
- tooltipArrow.style.left = arrowX + "px";
- }
+ tooltipContent.style.setProperty('--arrow', onTop ? 'var(--arrow-up)' : 'var(--arrow-down)');
+ tooltipContent.style.setProperty('--shadow-direction', onTop ? 'var(--shadow-up)' : 'var(--shadow-down)');
+ tooltipContent.style.setProperty('--arrow-top', (onTop ? titleHeight : -arrowHalfWidth) + 'px');
+ tooltipContent.style.setProperty('--arrow-left', (arrowX - boxX) + 'px');
}
function _drawRulers(context, bounds, rulerAtRight, rulerAtBottom)
@@ -788,10 +928,8 @@ function drawHighlight(highlight, context)
if (highlight.showExtensionLines)
_drawRulers(context, bounds, rulerAtRight, rulerAtBottom);
- if (highlight.elementInfo && highlight.displayAsMaterial)
- _drawMaterialElementTitle(highlight.elementInfo, bounds);
- else if (highlight.elementInfo)
- _drawElementTitle(context, highlight.elementInfo, bounds);
+ if (highlight.elementInfo)
+ _drawElementTitle(highlight.elementInfo, bounds);
}
if (highlight.gridInfo) {
for (var grid of highlight.gridInfo)
@@ -806,22 +944,11 @@ function drawScreenshotBorder(rect)
{
var context = window.context;
context.save();
- context.fillStyle = "rgba(0, 0, 0, 0.2)";
- context.beginPath();
- context.moveTo(rect.x1 - 0.5, rect.y1 - 0.5);
- context.lineTo(rect.x1 - 0.5, rect.y2 + 0.5);
- context.lineTo(rect.x2 + 0.5, rect.y2 + 0.5);
- context.lineTo(rect.x2 + 0.5, rect.y1 - 0.5);
- context.lineTo(rect.x1 - 0.5, rect.y1 - 0.5);
- context.fill();
- context.strokeStyle = "rgba(255, 255, 255, 0.9)";
+ context.fillStyle = '#0003';
+ context.strokeStyle = '#fffd';
context.lineWidth = 1;
- context.beginPath();
- context.moveTo(rect.x1 - 0.5, rect.y1 - 0.5);
- context.lineTo(rect.x1 - 0.5, rect.y2 + 0.5);
- context.lineTo(rect.x2 + 0.5, rect.y2 + 0.5);
- context.lineTo(rect.x2 + 0.5, rect.y1 - 0.5);
- context.lineTo(rect.x1 - 0.5, rect.y1 - 0.5);
+ context.rect(rect.x1 - 0.5, rect.y1 - 0.5, rect.x2 - rect.x1 + 1, rect.y2 - rect.y1 + 1);
+ context.fill();
context.stroke();
context.restore();
}
@@ -910,6 +1037,36 @@ String.prototype.trimEnd = function(maxLength)
return this.substr(0, maxLength - 1) + "\u2026";
}
+/**
+ * @param {number} num
+ * @param {number} min
+ * @param {number} max
+ * @return {number}
+ */
+Number.constrain = function(num, min, max) {
+ if (num < min)
+ num = min;
+ else if (num > max)
+ num = max;
+ return num;
+};
+
+function test() {
+ document.body.classList.add("platform-mac");
+ reset({
+ viewportSize: {width: 800, height: 600},
+ deviceScaleFactor: 1,
+ pageScaleFactor: 1,
+ pageZoomFactor: 1,
+ scrollX: 0,
+ scrollY: 0
+ });
+ drawHighlight(
+ {"paths":[{"path":["M",122,133.796875,"L",822,133.796875,"L",822,208.796875,"L",122,208.796875,"Z"], "fillColor":"rgba(111, 168, 220, 0.658823529411765)","name":"content"},
+ {"path":["M",122,113.796875,"L",822,113.796875,"L",822,228.796875,"L",122,228.796875,"Z"],"fillColor":"rgba(246, 178, 107, 0.66)","name":"margin"}],"showRulers":false,"showExtensionLines":false,
+ "elementInfo":{"tagName":"p","idValue":"","nodeWidth":"700","nodeHeight":"75","style":{"color":"#FFFFFFFF","font-family":"\"Product Sans\", \"Open Sans\", Roboto, Arial","font-size":"20px","line-height":"25px","padding":"0px","margin":"20px 0px","background-color":"#00000000"},"contrast":{"fontSize":"20px","fontWeight":"400","backgroundColor":"#F9B826BF"}}});
+}
+
window.addEventListener("DOMContentLoaded", onLoaded);
document.addEventListener("keydown", onDocumentKeyDown);
</script>
@@ -917,10 +1074,6 @@ document.addEventListener("keydown", onDocumentKeyDown);
<body class="fill">
</body>
<canvas id="canvas" class="fill"></canvas>
-<div id="element-title">
- <span id="tag-name"></span><span id="node-id"></span><span id="class-name"></span>
- <span id="node-width"></span><span class="px">px</span><span class="px"> &#xD7; </span><span id="node-height"></span><span class="px">px</span>
-</div>
<div id="tooltip-container"></div>
<div class="controls-line">
<div class="message-box"><div id="paused-in-debugger"></div></div>
diff --git a/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.2.json b/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.2.json
index f5a12c612a8..6e3e7e12ded 100644
--- a/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.2.json
+++ b/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.2.json
@@ -478,11 +478,6 @@
"handlers": ["none"]
},
{
- "name": "requestAppBanner",
- "experimental": true,
- "handlers": ["browser"]
- },
- {
"name": "setBlockedEventsWarningThreshold",
"experimental": true,
"parameters": [
diff --git a/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.3.json b/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.3.json
index dbf3b7c0ecc..95985359e7f 100644
--- a/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.3.json
+++ b/chromium/third_party/blink/renderer/core/inspector/browser_protocol-1.3.json
@@ -602,10 +602,6 @@
]
},
{
- "name": "requestAppBanner",
- "experimental": true
- },
- {
"name": "getLayoutMetrics",
"description": "Returns metrics relating to the layouting of the page, such as viewport bounds/scale.",
"returns": [
diff --git a/chromium/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/chromium/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 704c6b7e2c5..9e2e769baa7 100644
--- a/chromium/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/chromium/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
-# Contribuging to Chrome DevTools Protocol: https://docs.google.com/document/d/1c-COD2kaK__5iMM5SEx-PzNA7HFmgttcYfOHHX0HaOM/edit?usp=sharing
+# Contributing to Chrome DevTools Protocol: https://docs.google.com/document/d/1c-COD2kaK__5iMM5SEx-PzNA7HFmgttcYfOHHX0HaOM/edit?usp=sharing
version
major 1
@@ -107,11 +107,12 @@ experimental domain Accessibility
# The sources which contributed to the computation of this property.
optional array of AXValueSource sources
- # Values of AXProperty name: from 'busy' to 'roledescription' - states which apply to every AX
- # node, from 'live' to 'root' - attributes which apply to nodes in live regions, from
- # 'autocomplete' to 'valuetext' - attributes which apply to widgets, from 'checked' to 'selected'
- # - states which apply to widgets, from 'activedescendant' to 'owns' - relationships between
- # elements other than parent/child/sibling.
+ # Values of AXProperty name:
+ # - from 'busy' to 'roledescription': states which apply to every AX node
+ # - from 'live' to 'root': attributes which apply to nodes in live regions
+ # - from 'autocomplete' to 'valuetext': attributes which apply to widgets
+ # - from 'checked' to 'selected': states which apply to widgets
+ # - from 'activedescendant' to 'owns' - relationships between elements other than parent/child/sibling.
type AXPropertyName extends string
enum
busy
@@ -514,6 +515,7 @@ domain Browser
protectedMediaIdentifier
sensors
videoCapture
+ idleDetection
# Grant specific permissions to the given origin and reject all others.
experimental command grantPermissions
@@ -996,8 +998,6 @@ experimental domain CSS
# The computed font weight for this node, as a CSS computed value string (e.g. 'normal' or
# '100').
optional string computedFontWeight
- # The computed font size for the document body, as a computed CSS value string (e.g. '16px').
- optional string computedBodyFontSize
# Returns the computed style for a DOM node identified by `nodeId`.
command getComputedStyleForNode
@@ -1239,7 +1239,7 @@ experimental domain CacheStorage
# Fetches cache entry.
command requestCachedResponse
parameters
- # Id of cache that contains the enty.
+ # Id of cache that contains the entry.
CacheId cacheId
# URL spec of the request.
string requestURL
@@ -1256,12 +1256,59 @@ experimental domain CacheStorage
integer skipCount
# Number of records to fetch.
integer pageSize
+ # If present, only return the entries containing this substring in the path
+ optional string pathFilter
returns
# Array of object store data entries.
array of DataEntry cacheDataEntries
# If true, there are more entries to fetch in the given range.
boolean hasMore
+# A domain for interacting with Cast, Presentation API, and Remote Playback API
+# functionalities.
+experimental domain Cast
+
+ # Starts observing for sinks that can be used for tab mirroring, and if set,
+ # sinks compatible with |presentationUrl| as well. When sinks are found, a
+ # |sinksUpdated| event is fired.
+ # Also starts observing for issue messages. When an issue is added or removed,
+ # an |issueUpdated| event is fired.
+ command enable
+ parameters
+ optional string presentationUrl
+
+ # Stops observing for sinks and issues.
+ command disable
+
+ # Sets a sink to be used when the web page requests the browser to choose a
+ # sink via Presentation API, Remote Playback API, or Cast SDK.
+ command setSinkToUse
+ parameters
+ string sinkName
+
+ # Starts mirroring the tab to the sink.
+ command startTabMirroring
+ parameters
+ string sinkName
+
+ # Stops the active Cast session on the sink.
+ command stopCasting
+ parameters
+ string sinkName
+
+ # This is fired whenever the list of available sinks changes. A sink is a
+ # device or a software surface that you can cast to.
+ event sinksUpdated
+ parameters
+ array of string sinkNames
+
+ # This is fired whenever the outstanding issue/error message changes.
+ # |issueMessage| is empty if there is no issue.
+ event issueUpdated
+ parameters
+ string issueMessage
+
+
# This domain exposes DOM read/write operations. Each DOM Node is represented with its mirror object
# that has an `id`. This `id` can be used to get additional information on the Node, resolve it into
# the JavaScript object wrapper, etc. It is important that client receives DOM events only for the
@@ -1751,6 +1798,8 @@ domain DOM
optional DOM.BackendNodeId backendNodeId
# Symbolic group name that can be used to release multiple objects.
optional string objectGroup
+ # Execution context in which to resolve the node.
+ optional Runtime.ExecutionContextId executionContextId
returns
# JavaScript object wrapper for given node.
Runtime.RemoteObject object
@@ -1789,6 +1838,15 @@ domain DOM
# JavaScript object id of the node wrapper.
optional Runtime.RemoteObjectId objectId
+ # Returns file information for the given
+ # File wrapper.
+ experimental command getFileInfo
+ parameters
+ # JavaScript object id of the node wrapper.
+ Runtime.RemoteObjectId objectId
+ returns
+ string path
+
# Enables console to refer to the node with given id via $x (see Command Line API for more details
# $x functions).
experimental command setInspectedNode
@@ -2776,8 +2834,9 @@ experimental domain IndexedDB
properties
# Database name.
string name
- # Database version.
- integer version
+ # Database version (type is not 'integer', as the standard
+ # requires the version number to be 'unsigned long long')
+ number version
# Object stores in this database.
array of ObjectStore objectStores
@@ -3036,12 +3095,21 @@ domain Input
left
middle
right
+ back
+ forward
+ # A number indicating which buttons are pressed on the mouse when a mouse event is triggered.
+ # Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
+ optional integer buttons
# Number of times the mouse button was clicked (default: 0).
optional integer clickCount
# X delta in CSS pixels for mouse wheel event (default: 0).
optional number deltaX
# Y delta in CSS pixels for mouse wheel event (default: 0).
optional number deltaY
+ # Pointer type (default: "mouse").
+ optional enum pointerType
+ mouse
+ pen
# Dispatches a touch event to the page.
command dispatchTouchEvent
@@ -3818,14 +3886,16 @@ domain Network
# HTTP request headers text.
optional string requestHeadersText
- # WebSocket frame data.
+ # WebSocket message data. This represents an entire WebSocket message, not just a fragmented frame as the name suggests.
type WebSocketFrame extends object
properties
- # WebSocket frame opcode.
+ # WebSocket message opcode.
number opcode
- # WebSocke frame mask.
+ # WebSocket message mask.
boolean mask
- # WebSocke frame payload data.
+ # WebSocket message payload data.
+ # If the opcode is 1, this is a text message and payloadData is a UTF-8 string.
+ # If the opcode isn't 1, then payloadData is a base64 encoded string representing binary data.
string payloadData
# Information about the cached resource.
@@ -3983,8 +4053,6 @@ domain Network
properties
# Signed exchange request URL.
string requestUrl
- # Signed exchange request method.
- string requestMethod
# Signed exchange response code.
integer responseCode
# Signed exchange response headers.
@@ -4459,17 +4527,17 @@ domain Network
# Request initiator.
optional Initiator initiator
- # Fired when WebSocket frame error occurs.
+ # Fired when WebSocket message error occurs.
event webSocketFrameError
parameters
# Request identifier.
RequestId requestId
# Timestamp.
MonotonicTime timestamp
- # WebSocket frame error message.
+ # WebSocket error message.
string errorMessage
- # Fired when WebSocket frame is received.
+ # Fired when WebSocket message is received.
event webSocketFrameReceived
parameters
# Request identifier.
@@ -4479,7 +4547,7 @@ domain Network
# WebSocket response data.
WebSocketFrame response
- # Fired when WebSocket frame is sent.
+ # Fired when WebSocket message is sent.
event webSocketFrameSent
parameters
# Request identifier.
@@ -4522,11 +4590,12 @@ experimental domain Overlay
properties
# Whether the node info tooltip should be shown (default: false).
optional boolean showInfo
+ # Whether the node styles in the tooltip (default: false).
+ optional boolean showStyles
# Whether the rulers should be shown (default: false).
optional boolean showRulers
# Whether the extension lines from node to the rulers should be shown (default: false).
optional boolean showExtensionLines
- optional boolean displayAsMaterial
# The content box highlight fill color (default: transparent).
optional DOM.RGBA contentColor
# The padding highlight fill color (default: transparent).
@@ -4541,8 +4610,6 @@ experimental domain Overlay
optional DOM.RGBA shapeColor
# The shape margin fill color (default: transparent).
optional DOM.RGBA shapeMarginColor
- # Selectors to highlight relevant nodes.
- optional string selectorList
# The grid layout color (default: transparent).
optional DOM.RGBA cssGridColor
@@ -4550,6 +4617,7 @@ experimental domain Overlay
enum
searchForNode
searchForUAShadowDOM
+ captureAreaScreenshot
none
# Disables domain notifications.
@@ -4592,6 +4660,8 @@ experimental domain Overlay
optional DOM.BackendNodeId backendNodeId
# JavaScript object id of the node to be highlighted.
optional Runtime.RemoteObjectId objectId
+ # Selectors to highlight relevant nodes.
+ optional string selector
# Highlights given quad. Coordinates are absolute with respect to the main frame viewport.
command highlightQuad
@@ -4629,6 +4699,12 @@ experimental domain Overlay
# == false`.
optional HighlightConfig highlightConfig
+ # Highlights owner element of all frames detected to be ads.
+ command setShowAdHighlights
+ parameters
+ # True for showing ad highlights
+ boolean show
+
command setPausedInDebuggerMessage
parameters
# The message to display, also triggers resume and step over controls.
@@ -4690,9 +4766,12 @@ experimental domain Overlay
# Fired when user asks to capture screenshot of some area on the page.
event screenshotRequested
parameters
- # Viewport to capture, in CSS.
+ # Viewport to capture, in device independent pixels (dip).
Page.Viewport viewport
+ # Fired when user cancels the inspect mode.
+ event inspectModeCanceled
+
# Actions and events related to the inspected page belong to the page domain.
domain Page
depends on Debugger
@@ -4860,17 +4939,19 @@ domain Page
number clientHeight
# Scale relative to the ideal viewport (size at width=device-width).
number scale
+ # Page zoom factor (CSS to device independent pixels ratio).
+ optional number zoom
# Viewport for capturing screenshot.
type Viewport extends object
properties
- # X offset in CSS pixels.
+ # X offset in device independent pixels (dip).
number x
- # Y offset in CSS pixels
+ # Y offset in device independent pixels (dip).
number y
- # Rectangle width in CSS pixels
+ # Rectangle width in device independent pixels (dip).
number width
- # Rectangle height in CSS pixels
+ # Rectangle height in device independent pixels (dip).
number height
# Page scale factor.
number scale
@@ -5038,6 +5119,9 @@ domain Page
# Array of navigation history entries.
array of NavigationEntry entries
+ # Resets navigation history for the current page.
+ command resetNavigationHistory
+
# Returns content of the given resource.
experimental command getResourceContent
parameters
@@ -5158,8 +5242,6 @@ domain Page
parameters
ScriptIdentifier identifier
- experimental command requestAppBanner
-
# Acknowledges that a screencast frame has been received by the frontend.
experimental command screencastFrameAck
parameters
@@ -5365,6 +5447,9 @@ domain Page
# Specifies the endpoint group to deliver the report to.
optional string group
+ # Pauses page execution. Can be resumed using generic Runtime.runIfWaitingForDebugger.
+ experimental command waitForDebugger
+
event domContentEventFired
parameters
Network.MonotonicTime timestamp
@@ -5828,7 +5913,7 @@ experimental domain Storage
parameters
# Security origin.
string origin
- # Comma separated origin names.
+ # Comma separated list of StorageType to clear.
string storageTypes
# Returns usage and quota in bytes.
diff --git a/chromium/third_party/blink/renderer/core/inspector/console_message.cc b/chromium/third_party/blink/renderer/core/inspector/console_message.cc
index c5aba6d34df..cec47dae6bc 100644
--- a/chromium/third_party/blink/renderer/core/inspector/console_message.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/console_message.cc
@@ -36,7 +36,8 @@ ConsoleMessage* ConsoleMessage::Create(
MessageLevel level,
const String& message,
std::unique_ptr<SourceLocation> location) {
- return new ConsoleMessage(source, level, message, std::move(location));
+ return MakeGarbageCollected<ConsoleMessage>(source, level, message,
+ std::move(location));
}
// static
@@ -121,9 +122,9 @@ void ConsoleMessage::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
}
-STATIC_ASSERT_ENUM(WebConsoleMessage::kLevelVerbose, kVerboseMessageLevel);
-STATIC_ASSERT_ENUM(WebConsoleMessage::kLevelInfo, kInfoMessageLevel);
-STATIC_ASSERT_ENUM(WebConsoleMessage::kLevelWarning, kWarningMessageLevel);
-STATIC_ASSERT_ENUM(WebConsoleMessage::kLevelError, kErrorMessageLevel);
+STATIC_ASSERT_ENUM(mojom::ConsoleMessageLevel::kVerbose, kVerboseMessageLevel);
+STATIC_ASSERT_ENUM(mojom::ConsoleMessageLevel::kInfo, kInfoMessageLevel);
+STATIC_ASSERT_ENUM(mojom::ConsoleMessageLevel::kWarning, kWarningMessageLevel);
+STATIC_ASSERT_ENUM(mojom::ConsoleMessageLevel::kError, kErrorMessageLevel);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/console_message.h b/chromium/third_party/blink/renderer/core/inspector/console_message.h
index 536b9fbcdd8..5105e9ca1dc 100644
--- a/chromium/third_party/blink/renderer/core/inspector/console_message.h
+++ b/chromium/third_party/blink/renderer/core/inspector/console_message.h
@@ -47,6 +47,10 @@ class CORE_EXPORT ConsoleMessage final
std::unique_ptr<SourceLocation>,
WorkerThread*);
+ ConsoleMessage(MessageSource,
+ MessageLevel,
+ const String& message,
+ std::unique_ptr<SourceLocation>);
~ConsoleMessage();
SourceLocation* Location() const;
@@ -63,11 +67,6 @@ class CORE_EXPORT ConsoleMessage final
void Trace(blink::Visitor*);
private:
- ConsoleMessage(MessageSource,
- MessageLevel,
- const String& message,
- std::unique_ptr<SourceLocation>);
-
MessageSource source_;
MessageLevel level_;
String message_;
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
index c0f40a77e0e..d42f29e5396 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
@@ -421,21 +421,6 @@ void DevToolsEmulator::MainFrameScrollOrScaleChanged() {
UpdateRootLayerTransform();
}
-void DevToolsEmulator::ApplyDeviceEmulationTransform(
- TransformationMatrix* transform) {
- if (device_metrics_enabled_) {
- transform->Scale(emulation_params_.scale);
- if (web_view_->MainFrameImpl()) {
- web_view_->MainFrameImpl()->SetInputEventsScaleForEmulation(
- emulation_params_.scale);
- }
- } else {
- if (web_view_->MainFrameImpl()) {
- web_view_->MainFrameImpl()->SetInputEventsScaleForEmulation(1.0);
- }
- }
-}
-
void DevToolsEmulator::ApplyViewportOverride(TransformationMatrix* transform) {
if (!viewport_override_)
return;
@@ -467,7 +452,8 @@ void DevToolsEmulator::UpdateRootLayerTransform() {
// Apply device emulation transform first, so that it is affected by the
// viewport override.
ApplyViewportOverride(&transform);
- ApplyDeviceEmulationTransform(&transform);
+ if (device_metrics_enabled_)
+ transform.Scale(emulation_params_.scale);
web_view_->SetDeviceEmulationTransform(transform);
}
@@ -484,6 +470,10 @@ base::Optional<IntRect> DevToolsEmulator::VisibleContentRectForPainting()
viewport_size.Width(), viewport_size.Height()));
}
+float DevToolsEmulator::InputEventsScaleForEmulation() {
+ return device_metrics_enabled_ ? emulation_params_.scale : 1.0;
+}
+
void DevToolsEmulator::SetTouchEventEmulationEnabled(bool enabled,
int max_touch_points) {
if (!touch_event_emulation_enabled_) {
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
index 0d3d98fddf6..b9680b169f2 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
@@ -66,6 +66,10 @@ class CORE_EXPORT DevToolsEmulator final
// This ensures that all content inside the forced viewport is painted.
base::Optional<IntRect> VisibleContentRectForPainting() const;
+ // Returns the scale used to convert incoming input events while emulating
+ // device metics.
+ float InputEventsScaleForEmulation();
+
private:
void EnableMobileEmulation();
void DisableMobileEmulation();
@@ -74,7 +78,6 @@ class CORE_EXPORT DevToolsEmulator final
// deviceScaleFactor() otherwise.
float CompositorDeviceScaleFactor() const;
- void ApplyDeviceEmulationTransform(TransformationMatrix*);
void ApplyViewportOverride(TransformationMatrix*);
void UpdateRootLayerTransform();
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc
index 64c10cbf7ed..4b454e0be04 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc
@@ -44,7 +44,6 @@
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/inspector/inspector_frontend_client.h"
-#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
@@ -214,27 +213,6 @@ void DevToolsHost::ShowContextMenu(LocalFrame* target_frame,
}
}
-String DevToolsHost::getSelectionBackgroundColor() {
- return LayoutTheme::GetTheme().ActiveSelectionBackgroundColor().Serialized();
-}
-
-String DevToolsHost::getSelectionForegroundColor() {
- return LayoutTheme::GetTheme().ActiveSelectionForegroundColor().Serialized();
-}
-
-String DevToolsHost::getInactiveSelectionBackgroundColor() {
- return LayoutTheme::GetTheme()
- .InactiveSelectionBackgroundColor()
- .Serialized();
-}
-
-String DevToolsHost::getInactiveSelectionForegroundColor() {
- return LayoutTheme::GetTheme()
- .InactiveSelectionForegroundColor()
- .Serialized();
-}
-
-
bool DevToolsHost::isHostedMode() {
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h
index 7e47396306f..8f35f29cd1d 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h
@@ -69,11 +69,6 @@ class CORE_EXPORT DevToolsHost final : public ScriptWrappable {
WebVector<WebMenuItemInfo> items);
void sendMessageToEmbedder(const String& message);
- String getSelectionBackgroundColor();
- String getSelectionForegroundColor();
- String getInactiveSelectionBackgroundColor();
- String getInactiveSelectionForegroundColor();
-
bool isHostedMode();
LocalFrame* FrontendFrame() { return frontend_frame_; }
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.idl b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.idl
index cd4481da7b9..15860965b35 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.idl
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.idl
@@ -41,10 +41,5 @@
[Custom] void showContextMenuAtPoint(float x, float y, any items, optional Document document);
void sendMessageToEmbedder(DOMString message);
- DOMString getSelectionBackgroundColor();
- DOMString getSelectionForegroundColor();
- DOMString getInactiveSelectionBackgroundColor();
- DOMString getInactiveSelectionForegroundColor();
-
boolean isHostedMode();
};
diff --git a/chromium/third_party/blink/renderer/core/inspector/devtools_agent.cc b/chromium/third_party/blink/renderer/core/inspector/devtools_agent.cc
index ce60e4be4cc..0ce78ddf7b5 100644
--- a/chromium/third_party/blink/renderer/core/inspector/devtools_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/devtools_agent.cc
@@ -108,7 +108,7 @@ void DevToolsAgent::AttachDevToolsSession(
mojom::blink::DevToolsSessionRequest io_session_request,
mojom::blink::DevToolsSessionStatePtr reattach_session_state) {
client_->DebuggerTaskStarted();
- DevToolsSession* session = new DevToolsSession(
+ DevToolsSession* session = MakeGarbageCollected<DevToolsSession>(
this, std::move(host), std::move(session_request),
std::move(io_session_request), std::move(reattach_session_state));
sessions_.insert(session);
@@ -124,14 +124,17 @@ void DevToolsAgent::FlushProtocolNotifications() {
session->FlushProtocolNotifications();
}
-void DevToolsAgent::ReportChildWorkers(bool report, bool wait_for_debugger) {
+void DevToolsAgent::ReportChildWorkers(bool report,
+ bool wait_for_debugger,
+ base::OnceClosure callback) {
report_child_workers_ = report;
pause_child_workers_on_start_ = wait_for_debugger;
- if (!report_child_workers_)
- return;
- auto workers = std::move(unreported_child_worker_threads_);
- for (auto& it : workers)
- ReportChildWorker(std::move(it.value));
+ if (report_child_workers_) {
+ auto workers = std::move(unreported_child_worker_threads_);
+ for (auto& it : workers)
+ ReportChildWorker(std::move(it.value));
+ }
+ std::move(callback).Run();
}
// static
diff --git a/chromium/third_party/blink/renderer/core/inspector/devtools_agent.h b/chromium/third_party/blink/renderer/core/inspector/devtools_agent.h
index 51c69ac9eaa..1c4b9dfc0e5 100644
--- a/chromium/third_party/blink/renderer/core/inspector/devtools_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/devtools_agent.h
@@ -11,7 +11,7 @@
#include "base/unguessable_token.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -75,7 +75,9 @@ class CORE_EXPORT DevToolsAgent
mojom::blink::DevToolsSessionRequest io_session,
mojom::blink::DevToolsSessionStatePtr reattach_session_state) override;
void InspectElement(const WebPoint& point) override;
- void ReportChildWorkers(bool report, bool wait_for_debugger) override;
+ void ReportChildWorkers(bool report,
+ bool wait_for_debugger,
+ base::OnceClosure callback) override;
struct WorkerData {
KURL url;
diff --git a/chromium/third_party/blink/renderer/core/inspector/devtools_session.h b/chromium/third_party/blink/renderer/core/inspector/devtools_session.h
index b187664e09f..78f42b6b6b2 100644
--- a/chromium/third_party/blink/renderer/core/inspector/devtools_session.h
+++ b/chromium/third_party/blink/renderer/core/inspector/devtools_session.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
#include "third_party/blink/renderer/core/inspector/protocol/Forward.h"
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc
index d0c272a758d..91d89a1003d 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/inspector/inspector_application_cache_agent.h"
+#include "third_party/blink/public/mojom/appcache/appcache_info.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
@@ -72,7 +73,7 @@ void InspectorApplicationCacheAgent::UpdateApplicationCacheStatus(
return;
ApplicationCacheHost* host = document_loader->GetApplicationCacheHost();
- ApplicationCacheHost::Status status = host->GetStatus();
+ mojom::AppCacheStatus status = host->GetStatus();
ApplicationCacheHost::CacheInfo info = host->ApplicationCacheInfo();
String manifest_url = info.manifest_.GetString();
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index 0e2d2e8bc0d..7774b91c4e8 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -2302,17 +2302,40 @@ Response InspectorCSSAgent::getBackgroundColors(
int node_id,
Maybe<protocol::Array<String>>* background_colors,
Maybe<String>* computed_font_size,
- Maybe<String>* computed_font_weight,
- Maybe<String>* computed_body_font_size) {
+ Maybe<String>* computed_font_weight) {
Element* element = nullptr;
Response response = dom_agent_->AssertElement(node_id, element);
if (!response.isSuccess())
return response;
+ Vector<Color> bgcolors;
+ String fs;
+ String fw;
+ InspectorCSSAgent::GetBackgroundColors(element, &bgcolors, &fs, &fw);
+
+ if (bgcolors.size()) {
+ *background_colors = protocol::Array<String>::create();
+ for (const auto& color : bgcolors) {
+ background_colors->fromJust()->addItem(
+ cssvalue::CSSColorValue::SerializeAsCSSComponentValue(color));
+ }
+ }
+ if (!fs.IsEmpty())
+ *computed_font_size = fs;
+ if (!fw.IsEmpty())
+ *computed_font_weight = fw;
+ return Response::OK();
+}
+
+// static
+void InspectorCSSAgent::GetBackgroundColors(Element* element,
+ Vector<Color>* colors,
+ String* computed_font_size,
+ String* computed_font_weight) {
LayoutRect content_bounds;
LayoutObject* element_layout = element->GetLayoutObject();
if (!element_layout)
- return Response::OK();
+ return;
for (const Node* child = element->firstChild(); child;
child = child->nextSibling()) {
@@ -2330,40 +2353,34 @@ Response InspectorCSSAgent::getBackgroundColors(
}
if (content_bounds.Size().IsEmpty())
- return Response::OK();
+ return;
- Vector<Color> colors;
LocalFrameView* view = element->GetDocument().View();
if (!view)
- return Response::Error("No view.");
+ return;
+
Document& document = element->GetDocument();
bool is_main_frame = document.IsInMainFrame();
bool found_opaque_color = false;
if (is_main_frame) {
// Start with the "default" page color (typically white).
Color base_background_color = view->BaseBackgroundColor();
- colors.push_back(view->BaseBackgroundColor());
+ colors->push_back(view->BaseBackgroundColor());
found_opaque_color = !base_background_color.HasAlpha();
}
found_opaque_color = GetColorsFromRect(content_bounds, element->GetDocument(),
- element, colors);
+ element, *colors);
if (!found_opaque_color && !is_main_frame) {
for (HTMLFrameOwnerElement* owner_element = document.LocalOwner();
!found_opaque_color && owner_element;
owner_element = owner_element->GetDocument().LocalOwner()) {
found_opaque_color = GetColorsFromRect(
- content_bounds, owner_element->GetDocument(), nullptr, colors);
+ content_bounds, owner_element->GetDocument(), nullptr, *colors);
}
}
- *background_colors = protocol::Array<String>::create();
- for (auto color : colors) {
- background_colors->fromJust()->addItem(
- cssvalue::CSSColorValue::SerializeAsCSSComponentValue(color));
- }
-
CSSComputedStyleDeclaration* computed_style_info =
CSSComputedStyleDeclaration::Create(element, true);
const CSSValue* font_size =
@@ -2372,29 +2389,6 @@ Response InspectorCSSAgent::getBackgroundColors(
const CSSValue* font_weight =
computed_style_info->GetPropertyCSSValue(GetCSSPropertyFontWeight());
*computed_font_weight = font_weight->CssText();
-
- HTMLElement* body = element->GetDocument().body();
- CSSComputedStyleDeclaration* computed_style_body =
- CSSComputedStyleDeclaration::Create(body, true);
- const CSSValue* body_font_size =
- computed_style_body->GetPropertyCSSValue(GetCSSPropertyFontSize());
- if (body_font_size) {
- *computed_body_font_size = body_font_size->CssText();
- } else {
- // This is an extremely rare and pathological case -
- // just return the baseline default to avoid a crash.
- // crbug.com/738777
- unsigned default_font_size_keyword =
- FontSizeFunctions::InitialKeywordSize();
- float default_font_size_pixels = FontSizeFunctions::FontSizeForKeyword(
- &document, default_font_size_keyword, false);
- *computed_body_font_size =
- CSSPrimitiveValue::Create(default_font_size_pixels,
- CSSPrimitiveValue::UnitType::kPixels)
- ->CssText();
- }
-
- return Response::OK();
}
void InspectorCSSAgent::SetCoverageEnabled(bool enabled) {
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h
index 863e80996a7..0eab0289797 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h
@@ -109,6 +109,11 @@ class CORE_EXPORT InspectorCSSAgent final
static void CollectAllDocumentStyleSheets(Document*,
HeapVector<Member<CSSStyleSheet>>&);
+ static void GetBackgroundColors(Element* element,
+ Vector<Color>* background_colors,
+ String* computed_font_size,
+ String* computed_font_weight);
+
InspectorCSSAgent(InspectorDOMAgent*,
InspectedFrames*,
InspectorNetworkAgent*,
@@ -204,8 +209,7 @@ class CORE_EXPORT InspectorCSSAgent final
int node_id,
protocol::Maybe<protocol::Array<String>>* background_colors,
protocol::Maybe<String>* computed_font_size,
- protocol::Maybe<String>* computed_font_weight,
- protocol::Maybe<String>* computed_body_font_size) override;
+ protocol::Maybe<String>* computed_font_weight) override;
protocol::Response startRuleUsageTracking() override;
protocol::Response takeCoverageDelta(
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
index 333a9ddbe14..76aa2f24945 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/binding_security.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_file.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
#include "third_party/blink/renderer/core/dom/attr.h"
#include "third_party/blink/renderer/core/dom/character_data.h"
@@ -1333,7 +1334,7 @@ Response InspectorDOMAgent::getNodeForLocation(
node = node->parentNode();
if (!node)
return Response::Error("No node found at given location");
- *backend_node_id = DOMNodeIds::IdForNode(node);
+ *backend_node_id = IdentifiersFactory::IntIdForNode(node);
if (enabled_.Get()) {
Response response = PushDocumentUponHandlelessOperation();
if (!response.isSuccess())
@@ -1346,7 +1347,8 @@ Response InspectorDOMAgent::getNodeForLocation(
Response InspectorDOMAgent::resolveNode(
protocol::Maybe<int> node_id,
protocol::Maybe<int> backend_node_id,
- Maybe<String> object_group,
+ protocol::Maybe<String> object_group,
+ protocol::Maybe<int> execution_context_id,
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject>*
result) {
String object_group_name = object_group.fromMaybe("");
@@ -1362,7 +1364,8 @@ Response InspectorDOMAgent::resolveNode(
if (!node)
return Response::Error("No node with given id found");
- *result = ResolveNode(v8_session_, node, object_group_name);
+ *result = ResolveNode(v8_session_, node, object_group_name,
+ std::move(execution_context_id));
if (!*result) {
return Response::Error(
"Node with given id does not belong to the document");
@@ -2245,7 +2248,7 @@ protocol::Response InspectorDOMAgent::getFrameOwner(
if (!frame_owner)
return Response::Error("No iframe owner for given node");
- *backend_node_id = DOMNodeIds::IdForNode(frame_owner);
+ *backend_node_id = IdentifiersFactory::IntIdForNode(frame_owner);
if (enabled_.Get()) {
Response response = PushDocumentUponHandlelessOperation();
if (!response.isSuccess())
@@ -2255,6 +2258,27 @@ protocol::Response InspectorDOMAgent::getFrameOwner(
return Response::OK();
}
+Response InspectorDOMAgent::getFileInfo(const String& object_id, String* path) {
+ v8::HandleScope handles(isolate_);
+ v8::Local<v8::Value> value;
+ v8::Local<v8::Context> context;
+ std::unique_ptr<v8_inspector::StringBuffer> error;
+ if (!v8_session_->unwrapObject(&error, ToV8InspectorStringView(object_id),
+ &value, &context, nullptr))
+ return Response::Error(ToCoreString(std::move(error)));
+
+ if (!V8File::HasInstance(value, isolate_))
+ return Response::Error("Object id doesn't reference a File");
+ File* file = V8File::ToImpl(v8::Local<v8::Object>::Cast(value));
+ if (!file) {
+ return Response::Error(
+ "Couldn't convert object with given objectId to File");
+ }
+
+ *path = file->GetPath();
+ return Response::OK();
+}
+
Response InspectorDOMAgent::PushDocumentUponHandlelessOperation() {
if (!document_node_to_id_map_->Contains(document_)) {
std::unique_ptr<protocol::DOM::Node> root;
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
index 7042f4ec32b..253b3c11ccc 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
@@ -161,6 +161,7 @@ class CORE_EXPORT InspectorDOMAgent final
protocol::Maybe<int> node_id,
protocol::Maybe<int> backend_node_id,
protocol::Maybe<String> object_group,
+ protocol::Maybe<int> execution_context_id,
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject>*)
override;
protocol::Response getAttributes(
@@ -216,6 +217,9 @@ class CORE_EXPORT InspectorDOMAgent final
int* backend_node_id,
protocol::Maybe<int>* node_id) override;
+ protocol::Response getFileInfo(const String& object_id,
+ String* path) override;
+
bool Enabled() const;
void ReleaseDanglingNodes();
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc
index 2f939601b7d..ef9895c4997 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc
@@ -110,7 +110,7 @@ void InspectorDOMDebuggerAgent::CollectEventListeners(
for (wtf_size_t k = 0; k < listeners->size(); ++k) {
EventListener* event_listener = listeners->at(k).Callback();
JSBasedEventListener* v8_event_listener =
- JSBasedEventListener::Cast(event_listener);
+ DynamicTo<JSBasedEventListener>(event_listener);
if (!v8_event_listener)
continue;
v8::Local<v8::Context> context = ToV8Context(
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
index 8b8013da6cc..8dae62c8d7f 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
@@ -389,8 +389,12 @@ Response InspectorEmulationAgent::setNavigatorOverrides(
void InspectorEmulationAgent::VirtualTimeBudgetExpired() {
TRACE_EVENT_ASYNC_END0("renderer.scheduler", "VirtualTimeBudget", this);
- DCHECK(web_local_frame_);
- web_local_frame_->View()->Scheduler()->SetVirtualTimePolicy(
+ WebView* view = web_local_frame_->View();
+ if (!view) {
+ DCHECK_EQ(false, virtual_time_setup_);
+ return;
+ }
+ view->Scheduler()->SetVirtualTimePolicy(
PageScheduler::VirtualTimePolicy::kPause);
virtual_time_policy_.Set(protocol::Emulation::VirtualTimePolicyEnum::Pause);
GetFrontend()->virtualTimeBudgetExpired();
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc
index a303dac5196..5cc5a92fb42 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -5,6 +5,9 @@
#include "third_party/blink/renderer/core/inspector/inspector_highlight.h"
#include "base/macros.h"
+#include "third_party/blink/renderer/core/css/css_color_value.h"
+#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
+#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
@@ -190,6 +193,60 @@ const ShapeOutsideInfo* ShapeOutsideInfoForNode(Node* node,
return shape_outside_info;
}
+String ToHEXA(const Color& color) {
+ return String::Format("#%02X%02X%02X%02X", color.Red(), color.Green(),
+ color.Blue(), color.Alpha());
+}
+
+void AppendStyleInfo(Node* node,
+ protocol::DictionaryValue* element_info,
+ const InspectorHighlightContrastInfo& node_contrast) {
+ std::unique_ptr<protocol::DictionaryValue> computed_style =
+ protocol::DictionaryValue::create();
+ CSSStyleDeclaration* style = CSSComputedStyleDeclaration::Create(node, true);
+ Vector<AtomicString> properties;
+
+ // For text nodes, we can show color & font properties.
+ bool has_text_children = false;
+ for (Node* child = node->firstChild(); !has_text_children && child;
+ child = child->nextSibling()) {
+ has_text_children = child->IsTextNode();
+ }
+ if (has_text_children) {
+ properties.push_back("color");
+ properties.push_back("font-family");
+ properties.push_back("font-size");
+ properties.push_back("line-height");
+ }
+
+ properties.push_back("padding");
+ properties.push_back("margin");
+ properties.push_back("background-color");
+
+ for (size_t i = 0; i < properties.size(); ++i) {
+ const CSSValue* value = style->GetPropertyCSSValueInternal(properties[i]);
+ if (!value)
+ continue;
+ if (value->IsColorValue()) {
+ Color color = static_cast<const cssvalue::CSSColorValue*>(value)->Value();
+ computed_style->setString(properties[i], ToHEXA(color));
+ } else {
+ computed_style->setString(properties[i], value->CssText());
+ }
+ }
+ element_info->setValue("style", std::move(computed_style));
+
+ if (!node_contrast.font_size.IsEmpty()) {
+ std::unique_ptr<protocol::DictionaryValue> contrast =
+ protocol::DictionaryValue::create();
+ contrast->setString("fontSize", node_contrast.font_size);
+ contrast->setString("fontWeight", node_contrast.font_weight);
+ contrast->setString("backgroundColor",
+ ToHEXA(node_contrast.background_color));
+ element_info->setValue("contrast", std::move(contrast));
+ }
+}
+
std::unique_ptr<protocol::DictionaryValue> BuildElementInfo(Element* element) {
std::unique_ptr<protocol::DictionaryValue> element_info =
protocol::DictionaryValue::create();
@@ -236,7 +293,6 @@ std::unique_ptr<protocol::DictionaryValue> BuildElementInfo(Element* element) {
DOMRect* bounding_box = element->getBoundingClientRect();
element_info->setString("nodeWidth", String::Number(bounding_box->width()));
element_info->setString("nodeHeight", String::Number(bounding_box->height()));
-
return element_info;
}
@@ -250,7 +306,6 @@ std::unique_ptr<protocol::DictionaryValue> BuildTextNodeInfo(Text* text_node) {
text_info->setString("nodeWidth", bounding_box.Width().ToString());
text_info->setString("nodeHeight", bounding_box.Height().ToString());
text_info->setString("tagName", "#text");
-
return text_info;
}
@@ -335,23 +390,22 @@ InspectorHighlight::InspectorHighlight(float scale)
: highlight_paths_(protocol::ListValue::create()),
show_rulers_(false),
show_extension_lines_(false),
- display_as_material_(false),
scale_(scale) {}
InspectorHighlightConfig::InspectorHighlightConfig()
: show_info(false),
+ show_styles(false),
show_rulers(false),
- show_extension_lines(false),
- display_as_material(false) {}
+ show_extension_lines(false) {}
InspectorHighlight::InspectorHighlight(
Node* node,
const InspectorHighlightConfig& highlight_config,
+ const InspectorHighlightContrastInfo& node_contrast,
bool append_element_info)
: highlight_paths_(protocol::ListValue::create()),
show_rulers_(highlight_config.show_rulers),
show_extension_lines_(highlight_config.show_extension_lines),
- display_as_material_(highlight_config.display_as_material),
scale_(1.f) {
LocalFrameView* frame_view = node->GetDocument().View();
if (frame_view)
@@ -362,6 +416,8 @@ InspectorHighlight::InspectorHighlight(
element_info_ = BuildElementInfo(ToElement(node));
else if (append_element_info && node->IsTextNode())
element_info_ = BuildTextNodeInfo(ToText(node));
+ if (element_info_ && highlight_config.show_styles)
+ AppendStyleInfo(node, element_info_.get(), node_contrast);
}
InspectorHighlight::~InspectorHighlight() = default;
@@ -486,7 +542,6 @@ std::unique_ptr<protocol::DictionaryValue> InspectorHighlight::AsProtocolValue()
object->setBoolean("showExtensionLines", show_extension_lines_);
if (element_info_)
object->setValue("elementInfo", element_info_->clone());
- object->setBoolean("displayAsMaterial", display_as_material_);
if (grid_info_ && grid_info_->size() > 0)
object->setValue("gridInfo", grid_info_->clone());
return object;
@@ -711,9 +766,9 @@ InspectorHighlightConfig InspectorHighlight::DefaultConfig() {
config.shape = Color(0, 0, 0, 0);
config.shape_margin = Color(128, 128, 128, 0);
config.show_info = true;
+ config.show_styles = false;
config.show_rulers = true;
config.show_extension_lines = true;
- config.display_as_material = false;
config.css_grid = Color(128, 128, 128, 0);
return config;
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h
index 94cb9ad708f..2f91d696d78 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h
@@ -33,19 +33,26 @@ struct CORE_EXPORT InspectorHighlightConfig {
Color css_grid;
bool show_info;
+ bool show_styles;
bool show_rulers;
bool show_extension_lines;
- bool display_as_material;
String selector_list;
};
+struct InspectorHighlightContrastInfo {
+ Color background_color;
+ String font_size;
+ String font_weight;
+};
+
class CORE_EXPORT InspectorHighlight {
STACK_ALLOCATED();
public:
InspectorHighlight(Node*,
const InspectorHighlightConfig&,
+ const InspectorHighlightContrastInfo&,
bool append_element_info);
explicit InspectorHighlight(float scale);
~InspectorHighlight();
@@ -83,7 +90,6 @@ class CORE_EXPORT InspectorHighlight {
std::unique_ptr<protocol::ListValue> grid_info_;
bool show_rulers_;
bool show_extension_lines_;
- bool display_as_material_;
float scale_;
};
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_history.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_history.cc
index 92094437a39..e83d3053335 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_history.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_history.cc
@@ -97,7 +97,8 @@ void InspectorHistory::AppendPerformedAction(Action* action) {
}
void InspectorHistory::MarkUndoableState() {
- Perform(new UndoableStateMark(), IGNORE_EXCEPTION_FOR_TESTING);
+ Perform(MakeGarbageCollected<UndoableStateMark>(),
+ IGNORE_EXCEPTION_FOR_TESTING);
}
bool InspectorHistory::Undo(ExceptionState& exception_state) {
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc
index 0188270a673..d7f42bca055 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.cc
@@ -33,6 +33,7 @@
#include <memory>
+#include "base/stl_util.h"
#include "cc/base/region.h"
#include "cc/layers/picture_layer.h"
#include "third_party/blink/public/platform/web_float_point.h"
@@ -48,8 +49,6 @@
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
-#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
@@ -69,8 +68,8 @@ using protocol::Maybe;
using protocol::Response;
unsigned InspectorLayerTreeAgent::last_snapshot_id_;
-inline String IdForLayer(const GraphicsLayer* graphics_layer) {
- return String::Number(graphics_layer->CcLayer()->id());
+inline String IdForLayer(const cc::Layer* layer) {
+ return String::Number(layer->id());
}
static std::unique_ptr<protocol::DOM::Rect> BuildObjectForRect(
@@ -96,20 +95,18 @@ static std::unique_ptr<protocol::LayerTree::ScrollRect> BuildScrollRect(
}
static std::unique_ptr<Array<protocol::LayerTree::ScrollRect>>
-BuildScrollRectsForLayer(GraphicsLayer* graphics_layer,
- bool report_wheel_scrollers) {
+BuildScrollRectsForLayer(const cc::Layer* layer, bool report_wheel_scrollers) {
std::unique_ptr<Array<protocol::LayerTree::ScrollRect>> scroll_rects =
Array<protocol::LayerTree::ScrollRect>::create();
- cc::Layer* cc_layer = graphics_layer->CcLayer();
const cc::Region& non_fast_scrollable_rects =
- cc_layer->non_fast_scrollable_region();
+ layer->non_fast_scrollable_region();
for (const gfx::Rect& rect : non_fast_scrollable_rects) {
scroll_rects->addItem(BuildScrollRect(
IntRect(rect),
protocol::LayerTree::ScrollRect::TypeEnum::RepaintsOnScroll));
}
const cc::Region& touch_event_handler_region =
- cc_layer->touch_action_region().region();
+ layer->touch_action_region().region();
for (const gfx::Rect& rect : touch_event_handler_region) {
scroll_rects->addItem(BuildScrollRect(
@@ -119,8 +116,8 @@ BuildScrollRectsForLayer(GraphicsLayer* graphics_layer,
if (report_wheel_scrollers) {
scroll_rects->addItem(BuildScrollRect(
// TODO(yutak): This truncates the floating point position to integers.
- gfx::Rect(cc_layer->position().x(), cc_layer->position().y(),
- cc_layer->bounds().width(), cc_layer->bounds().height()),
+ gfx::Rect(layer->position().x(), layer->position().y(),
+ layer->bounds().width(), layer->bounds().height()),
protocol::LayerTree::ScrollRect::TypeEnum::WheelEventHandler));
}
return scroll_rects->length() ? std::move(scroll_rects) : nullptr;
@@ -128,20 +125,19 @@ BuildScrollRectsForLayer(GraphicsLayer* graphics_layer,
// TODO(flackr): We should be getting the sticky position constraints from the
// property tree once blink is able to access them. https://crbug.com/754339
-static GraphicsLayer* FindLayerByElementId(GraphicsLayer* root,
- CompositorElementId element_id) {
- if (root->CcLayer()->element_id() == element_id)
+static const cc::Layer* FindLayerByElementId(const cc::Layer* root,
+ CompositorElementId element_id) {
+ if (root->element_id() == element_id)
return root;
- for (wtf_size_t i = 0, size = root->Children().size(); i < size; ++i) {
- if (GraphicsLayer* layer =
- FindLayerByElementId(root->Children()[i], element_id))
+ for (auto child : root->children()) {
+ if (const auto* layer = FindLayerByElementId(child.get(), element_id))
return layer;
}
return nullptr;
}
static std::unique_ptr<protocol::LayerTree::StickyPositionConstraint>
-BuildStickyInfoForLayer(GraphicsLayer* root, cc::Layer* layer) {
+BuildStickyInfoForLayer(const cc::Layer* root, const cc::Layer* layer) {
cc::LayerStickyPositionConstraint constraints =
layer->sticky_position_constraint();
if (!constraints.is_sticky)
@@ -164,14 +160,12 @@ BuildStickyInfoForLayer(GraphicsLayer* root, cc::Layer* layer) {
constraints_obj->setNearestLayerShiftingStickyBox(String::Number(
FindLayerByElementId(root,
constraints.nearest_element_shifting_sticky_box)
- ->CcLayer()
->id()));
}
if (constraints.nearest_element_shifting_containing_block) {
constraints_obj->setNearestLayerShiftingContainingBlock(String::Number(
FindLayerByElementId(
root, constraints.nearest_element_shifting_containing_block)
- ->CcLayer()
->id()));
}
@@ -179,60 +173,73 @@ BuildStickyInfoForLayer(GraphicsLayer* root, cc::Layer* layer) {
}
static std::unique_ptr<protocol::LayerTree::Layer> BuildObjectForLayer(
- GraphicsLayer* root,
- GraphicsLayer* graphics_layer,
- int node_id,
+ const cc::Layer* root,
+ const cc::Layer* layer,
bool report_wheel_event_listeners) {
- cc::Layer* cc_layer = graphics_layer->CcLayer();
+ bool using_layer_list =
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled();
+
+ // When the front-end doesn't show internal layers, it will use the the first
+ // DrawsContent layer as the root of the shown layer tree. This doesn't work
+ // for layer list because the non-DrawsContent root layer is the parent of
+ // all DrawsContent layers. We have to cheat the front-end by setting
+ // drawsContent to true for the root layer.
+ bool draws_content =
+ (using_layer_list && root == layer) || layer->DrawsContent();
+
std::unique_ptr<protocol::LayerTree::Layer> layer_object =
protocol::LayerTree::Layer::create()
- .setLayerId(IdForLayer(graphics_layer))
- .setOffsetX(cc_layer->position().x())
- .setOffsetY(cc_layer->position().y())
- .setWidth(cc_layer->bounds().width())
- .setHeight(cc_layer->bounds().height())
- .setPaintCount(graphics_layer->PaintCount())
- .setDrawsContent(cc_layer->DrawsContent())
+ .setLayerId(IdForLayer(layer))
+ .setOffsetX(using_layer_list ? 0 : layer->position().x())
+ .setOffsetY(using_layer_list ? 0 : layer->position().y())
+ .setWidth(layer->bounds().width())
+ .setHeight(layer->bounds().height())
+ .setPaintCount(layer->paint_count())
+ .setDrawsContent(draws_content)
.build();
- if (node_id)
+ if (auto node_id = layer->owner_node_id())
layer_object->setBackendNodeId(node_id);
- GraphicsLayer* parent = graphics_layer->Parent();
- if (parent)
+ if (const auto* parent = layer->parent())
layer_object->setParentLayerId(IdForLayer(parent));
- if (!graphics_layer->ContentsAreVisible())
- layer_object->setInvisible(true);
- const TransformationMatrix& transform = graphics_layer->Transform();
+
+ gfx::Transform transform;
+ gfx::Point3F transform_origin;
+ if (using_layer_list) {
+ transform = layer->ScreenSpaceTransform();
+ } else {
+ transform = layer->transform();
+ transform_origin = layer->transform_origin();
+ }
+
if (!transform.IsIdentity()) {
- TransformationMatrix::FloatMatrix4 flattened_matrix;
- transform.ToColumnMajorFloatArray(flattened_matrix);
- std::unique_ptr<Array<double>> transform_array = Array<double>::create();
- for (size_t i = 0; i < arraysize(flattened_matrix); ++i)
- transform_array->addItem(flattened_matrix[i]);
+ auto transform_array = Array<double>::create();
+ for (int col = 0; col < 4; ++col) {
+ for (int row = 0; row < 4; ++row)
+ transform_array->addItem(transform.matrix().get(row, col));
+ }
layer_object->setTransform(std::move(transform_array));
- const FloatPoint3D& transform_origin = graphics_layer->TransformOrigin();
// FIXME: rename these to setTransformOrigin*
- if (cc_layer->bounds().width() > 0) {
- layer_object->setAnchorX(transform_origin.X() /
- cc_layer->bounds().width());
+ if (layer->bounds().width() > 0) {
+ layer_object->setAnchorX(transform_origin.x() / layer->bounds().width());
} else {
layer_object->setAnchorX(0.f);
}
- if (cc_layer->bounds().height() > 0) {
- layer_object->setAnchorY(transform_origin.Y() /
- cc_layer->bounds().height());
+ if (layer->bounds().height() > 0) {
+ layer_object->setAnchorY(transform_origin.y() / layer->bounds().height());
} else {
layer_object->setAnchorY(0.f);
}
- layer_object->setAnchorZ(transform_origin.Z());
+ layer_object->setAnchorZ(transform_origin.z());
}
std::unique_ptr<Array<protocol::LayerTree::ScrollRect>> scroll_rects =
- BuildScrollRectsForLayer(graphics_layer, report_wheel_event_listeners);
+ BuildScrollRectsForLayer(layer, report_wheel_event_listeners);
if (scroll_rects)
layer_object->setScrollRects(std::move(scroll_rects));
std::unique_ptr<protocol::LayerTree::StickyPositionConstraint> sticky_info =
- BuildStickyInfoForLayer(root, cc_layer);
+ BuildStickyInfoForLayer(root, layer);
if (sticky_info)
layer_object->setStickyPositionConstraint(std::move(sticky_info));
return layer_object;
@@ -277,14 +284,15 @@ void InspectorLayerTreeAgent::LayerTreeDidChange() {
GetFrontend()->layerTreeDidChange(BuildLayerTree());
}
-void InspectorLayerTreeAgent::DidPaint(const GraphicsLayer* graphics_layer,
+void InspectorLayerTreeAgent::DidPaint(const cc::Layer* layer,
GraphicsContext&,
const LayoutRect& rect) {
if (suppress_layer_paint_events_)
return;
+
// Should only happen for LocalFrameView paints when compositing is off.
// Consider different instrumentation method for that.
- if (!graphics_layer)
+ if (!layer)
return;
std::unique_ptr<protocol::DOM::Rect> dom_rect = protocol::DOM::Rect::create()
@@ -293,116 +301,71 @@ void InspectorLayerTreeAgent::DidPaint(const GraphicsLayer* graphics_layer,
.setWidth(rect.Width())
.setHeight(rect.Height())
.build();
- GetFrontend()->layerPainted(IdForLayer(graphics_layer), std::move(dom_rect));
+ GetFrontend()->layerPainted(IdForLayer(layer), std::move(dom_rect));
}
std::unique_ptr<Array<protocol::LayerTree::Layer>>
InspectorLayerTreeAgent::BuildLayerTree() {
- PaintLayerCompositor* compositor = GetPaintLayerCompositor();
- if (!compositor || !compositor->InCompositingMode())
+ const auto* root_layer = RootLayer();
+ if (!root_layer)
return nullptr;
- LayerIdToNodeIdMap layer_id_to_node_id_map;
std::unique_ptr<Array<protocol::LayerTree::Layer>> layers =
Array<protocol::LayerTree::Layer>::create();
- BuildLayerIdToNodeIdMap(compositor->RootLayer(), layer_id_to_node_id_map);
+ auto* root_frame = inspected_frames_->Root();
auto* layer_for_scrolling =
- inspected_frames_->Root()->View()->LayoutViewport()->LayerForScrolling();
+ root_frame->View()->LayoutViewport()->LayerForScrolling();
int scrolling_layer_id =
layer_for_scrolling ? layer_for_scrolling->CcLayer()->id() : 0;
bool have_blocking_wheel_event_handlers =
- inspected_frames_->Root()->GetChromeClient().EventListenerProperties(
- inspected_frames_->Root(), cc::EventListenerClass::kMouseWheel) ==
+ root_frame->GetChromeClient().EventListenerProperties(
+ root_frame, cc::EventListenerClass::kMouseWheel) ==
cc::EventListenerProperties::kBlocking;
- GatherGraphicsLayers(RootGraphicsLayer(), layer_id_to_node_id_map, layers,
- have_blocking_wheel_event_handlers, scrolling_layer_id);
+ GatherLayers(root_layer, layers, have_blocking_wheel_event_handlers,
+ scrolling_layer_id);
return layers;
}
-void InspectorLayerTreeAgent::BuildLayerIdToNodeIdMap(
- PaintLayer* root,
- LayerIdToNodeIdMap& layer_id_to_node_id_map) {
- if (root->HasCompositedLayerMapping()) {
- if (Node* node = root->GetLayoutObject().GeneratingNode()) {
- GraphicsLayer* graphics_layer =
- root->GetCompositedLayerMapping()->ChildForSuperlayers();
- layer_id_to_node_id_map.Set(graphics_layer->CcLayer()->id(),
- IdentifiersFactory::IntIdForNode(node));
- }
- }
- for (PaintLayer* child = root->FirstChild(); child;
- child = child->NextSibling())
- BuildLayerIdToNodeIdMap(child, layer_id_to_node_id_map);
- if (!root->GetLayoutObject().IsLayoutIFrame())
- return;
- FrameView* child_frame_view =
- ToLayoutEmbeddedContent(root->GetLayoutObject()).ChildFrameView();
- if (!child_frame_view || !child_frame_view->IsLocalFrameView())
- return;
- LayoutView* child_layout_view =
- ToLocalFrameView(child_frame_view)->GetLayoutView();
- if (!child_layout_view)
- return;
- PaintLayerCompositor* child_compositor = child_layout_view->Compositor();
- if (!child_compositor)
- return;
- BuildLayerIdToNodeIdMap(child_compositor->RootLayer(),
- layer_id_to_node_id_map);
-}
-
-void InspectorLayerTreeAgent::GatherGraphicsLayers(
- GraphicsLayer* layer,
- HashMap<int, int>& layer_id_to_node_id_map,
+void InspectorLayerTreeAgent::GatherLayers(
+ const cc::Layer* layer,
std::unique_ptr<Array<protocol::LayerTree::Layer>>& layers,
bool has_wheel_event_handlers,
int scrolling_layer_id) {
if (client_->IsInspectorLayer(layer))
return;
- int layer_id = layer->CcLayer()->id();
+ int layer_id = layer->id();
layers->addItem(BuildObjectForLayer(
- RootGraphicsLayer(), layer, layer_id_to_node_id_map.at(layer_id),
+ RootLayer(), layer,
has_wheel_event_handlers && layer_id == scrolling_layer_id));
- for (wtf_size_t i = 0, size = layer->Children().size(); i < size; ++i)
- GatherGraphicsLayers(layer->Children()[i], layer_id_to_node_id_map, layers,
- has_wheel_event_handlers, scrolling_layer_id);
-}
-
-PaintLayerCompositor* InspectorLayerTreeAgent::GetPaintLayerCompositor() {
- auto* layout_view = inspected_frames_->Root()->ContentLayoutObject();
- PaintLayerCompositor* compositor =
- layout_view ? layout_view->Compositor() : nullptr;
- return compositor;
+ for (auto child : layer->children()) {
+ GatherLayers(child.get(), layers, has_wheel_event_handlers,
+ scrolling_layer_id);
+ }
}
-GraphicsLayer* InspectorLayerTreeAgent::RootGraphicsLayer() {
- return inspected_frames_->Root()
- ->GetPage()
- ->GetVisualViewport()
- .RootGraphicsLayer();
+const cc::Layer* InspectorLayerTreeAgent::RootLayer() {
+ return inspected_frames_->Root()->View()->RootCcLayer();
}
-static GraphicsLayer* FindLayerById(GraphicsLayer* root, int layer_id) {
- if (root->CcLayer()->id() == layer_id)
+static const cc::Layer* FindLayerById(const cc::Layer* root, int layer_id) {
+ if (root->id() == layer_id)
return root;
- for (wtf_size_t i = 0, size = root->Children().size(); i < size; ++i) {
- if (GraphicsLayer* layer = FindLayerById(root->Children()[i], layer_id))
+ for (auto child : root->children()) {
+ if (const auto* layer = FindLayerById(child.get(), layer_id))
return layer;
}
return nullptr;
}
Response InspectorLayerTreeAgent::LayerById(const String& layer_id,
- GraphicsLayer*& result) {
+ const cc::Layer*& result) {
bool ok;
int id = layer_id.ToInt(&ok);
if (!ok)
return Response::Error("Invalid layer id");
- PaintLayerCompositor* compositor = GetPaintLayerCompositor();
- if (!compositor)
- return Response::Error("Not in compositing mode");
- result = FindLayerById(RootGraphicsLayer(), id);
+ result = FindLayerById(RootLayer(), id);
if (!result)
return Response::Error("No layer matching given id found");
return Response::OK();
@@ -411,27 +374,26 @@ Response InspectorLayerTreeAgent::LayerById(const String& layer_id,
Response InspectorLayerTreeAgent::compositingReasons(
const String& layer_id,
std::unique_ptr<Array<String>>* reason_strings) {
- GraphicsLayer* graphics_layer = nullptr;
- Response response = LayerById(layer_id, graphics_layer);
+ const cc::Layer* layer = nullptr;
+ Response response = LayerById(layer_id, layer);
if (!response.isSuccess())
return response;
- CompositingReasons reasons_bitmask = graphics_layer->GetCompositingReasons();
+ CompositingReasons reasons = layer->compositing_reasons();
*reason_strings = Array<String>::create();
- for (const char* name : CompositingReason::ShortNames(reasons_bitmask))
+ for (const char* name : CompositingReason::ShortNames(reasons))
(*reason_strings)->addItem(name);
return Response::OK();
}
Response InspectorLayerTreeAgent::makeSnapshot(const String& layer_id,
String* snapshot_id) {
- GraphicsLayer* layer = nullptr;
+ const cc::Layer* layer = nullptr;
Response response = LayerById(layer_id, layer);
if (!response.isSuccess())
return response;
if (!layer->DrawsContent())
return Response::Error("Layer does not draw content");
- IntRect interest_rect(IntPoint(), IntSize(layer->Size()));
suppress_layer_paint_events_ = true;
// If we hit a devtool break point in the middle of document lifecycle, for
@@ -443,22 +405,16 @@ Response InspectorLayerTreeAgent::makeSnapshot(const String& layer_id,
.LifecyclePostponed())
return Response::Error("Layer does not draw content");
- inspected_frames_->Root()->View()->UpdateAllLifecyclePhasesExceptPaint();
- for (auto frame = inspected_frames_->begin();
- frame != inspected_frames_->end(); ++frame) {
- frame->GetDocument()->Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
- }
- layer->Paint(&interest_rect);
- for (auto frame = inspected_frames_->begin();
- frame != inspected_frames_->end(); ++frame) {
- frame->GetDocument()->Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
- }
+ inspected_frames_->Root()->View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kOther);
suppress_layer_paint_events_ = false;
- auto snapshot = base::AdoptRef(new PictureSnapshot(
- ToSkPicture(layer->CapturePaintRecord(), interest_rect)));
+ auto picture = layer->GetPicture();
+ if (!picture)
+ return Response::Error("Layer does not produce picture");
+ auto snapshot = base::MakeRefCounted<PictureSnapshot>(std::move(picture));
*snapshot_id = String::Number(++last_snapshot_id_);
bool new_entry = snapshot_by_id_.insert(*snapshot_id, snapshot).is_new_entry;
DCHECK(new_entry);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h
index cb022887be5..63465954bc2 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h
@@ -35,19 +35,19 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
#include "third_party/blink/renderer/core/inspector/protocol/LayerTree.h"
-#include "third_party/blink/renderer/core/page/page_overlay.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+namespace cc {
+class Layer;
+}
+
namespace blink {
class GraphicsContext;
-class GraphicsLayer;
class InspectedFrames;
class LayoutRect;
class PictureSnapshot;
-class PaintLayer;
-class PaintLayerCompositor;
class CORE_EXPORT InspectorLayerTreeAgent final
: public InspectorBaseAgent<protocol::LayerTree::Metainfo> {
@@ -55,7 +55,7 @@ class CORE_EXPORT InspectorLayerTreeAgent final
class Client {
public:
virtual ~Client() = default;
- virtual bool IsInspectorLayer(GraphicsLayer*) = 0;
+ virtual bool IsInspectorLayer(const cc::Layer*) = 0;
};
static InspectorLayerTreeAgent* Create(InspectedFrames* inspected_frames,
@@ -72,7 +72,7 @@ class CORE_EXPORT InspectorLayerTreeAgent final
// Called from InspectorInstrumentation
void LayerTreeDidChange();
- void DidPaint(const GraphicsLayer*, GraphicsContext&, const LayoutRect&);
+ void DidPaint(const cc::Layer*, GraphicsContext&, const LayoutRect&);
// Called from the front-end.
protocol::Response enable() override;
@@ -109,18 +109,13 @@ class CORE_EXPORT InspectorLayerTreeAgent final
private:
static unsigned last_snapshot_id_;
- GraphicsLayer* RootGraphicsLayer();
+ const cc::Layer* RootLayer();
- PaintLayerCompositor* GetPaintLayerCompositor();
- protocol::Response LayerById(const String& layer_id, GraphicsLayer*&);
+ protocol::Response LayerById(const String& layer_id, const cc::Layer*&);
protocol::Response GetSnapshotById(const String& snapshot_id,
const PictureSnapshot*&);
-
- typedef HashMap<int, int> LayerIdToNodeIdMap;
- void BuildLayerIdToNodeIdMap(PaintLayer*, LayerIdToNodeIdMap&);
- void GatherGraphicsLayers(
- GraphicsLayer*,
- HashMap<int, int>& layer_id_to_node_id_map,
+ void GatherLayers(
+ const cc::Layer*,
std::unique_ptr<protocol::Array<protocol::LayerTree::Layer>>&,
bool has_wheel_event_handlers,
int scrolling_root_layer_id);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_log_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_log_agent.cc
index 651c0a91b02..c362c8410f8 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_log_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_log_agent.cc
@@ -141,8 +141,10 @@ void InspectorLogAgent::ConsoleMessageAdded(ConsoleMessage* message) {
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject>
remote_object = nullptr;
Node* node = DOMNodeIds::NodeForId(node_id);
- if (node)
- remote_object = ResolveNode(v8_session_, node, "console");
+ if (node) {
+ remote_object =
+ ResolveNode(v8_session_, node, "console", protocol::Maybe<int>());
+ }
if (!remote_object) {
remote_object =
NullRemoteObject(v8_session_, message->Frame(), "console");
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 4ab6d6c4648..47db6d2ec10 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -410,6 +410,22 @@ String GetReferrerPolicy(network::mojom::ReferrerPolicy policy) {
return protocol::Network::Request::ReferrerPolicyEnum::
NoReferrerWhenDowngrade;
}
+
+std::unique_ptr<protocol::Network::WebSocketFrame> WebSocketMessageToProtocol(
+ int op_code,
+ bool masked,
+ const char* payload,
+ size_t payload_length) {
+ return protocol::Network::WebSocketFrame::create()
+ .setOpcode(op_code)
+ .setMask(masked)
+ // Only interpret the payload as UTF-8 when it's a text message
+ .setPayloadData(op_code == 1 ? String::FromUTF8WithLatin1Fallback(
+ payload, payload_length)
+ : Base64Encode(payload, payload_length))
+ .build();
+}
+
} // namespace
void InspectorNetworkAgent::Restore() {
@@ -539,7 +555,7 @@ BuildObjectForResourceResponse(const ResourceResponse& response,
std::unique_ptr<protocol::Network::Response> response_object =
protocol::Network::Response::create()
- .setUrl(UrlWithoutFragment(response.Url()).GetString())
+ .setUrl(UrlWithoutFragment(response.CurrentRequestUrl()).GetString())
.setStatus(status)
.setStatusText(status_text)
.setHeaders(BuildObjectForHeaders(headers_map))
@@ -593,7 +609,7 @@ BuildObjectForResourceResponse(const ResourceResponse& response,
ResourceResponse::HTTPVersion::kHTTPVersion_1_1)
protocol = "http/1.1";
} else {
- protocol = response.Url().Protocol();
+ protocol = response.CurrentRequestUrl().Protocol();
}
}
response_object->setProtocol(protocol);
@@ -955,7 +971,7 @@ static bool IsErrorStatusCode(int status_code) {
void InspectorNetworkAgent::DidReceiveData(unsigned long identifier,
DocumentLoader* loader,
const char* data,
- size_t data_length) {
+ uint64_t data_length) {
String request_id = IdentifiersFactory::RequestId(loader, identifier);
if (data) {
@@ -970,8 +986,9 @@ void InspectorNetworkAgent::DidReceiveData(unsigned long identifier,
}
GetFrontend()->dataReceived(
- request_id, CurrentTimeTicksInSeconds(), data_length,
- resources_data_->GetAndClearPendingEncodedDataLength(request_id));
+ request_id, CurrentTimeTicksInSeconds(), static_cast<int>(data_length),
+ static_cast<int>(
+ resources_data_->GetAndClearPendingEncodedDataLength(request_id)));
}
void InspectorNetworkAgent::DidReceiveBlob(unsigned long identifier,
@@ -999,8 +1016,8 @@ void InspectorNetworkAgent::DidFinishLoading(unsigned long identifier,
NetworkResourcesData::ResourceData const* resource_data =
resources_data_->Data(request_id);
- int pending_encoded_data_length =
- resources_data_->GetAndClearPendingEncodedDataLength(request_id);
+ int pending_encoded_data_length = static_cast<int>(
+ resources_data_->GetAndClearPendingEncodedDataLength(request_id));
if (pending_encoded_data_length > 0) {
GetFrontend()->dataReceived(request_id, CurrentTimeTicksInSeconds(), 0,
pending_encoded_data_length);
@@ -1077,12 +1094,14 @@ void InspectorNetworkAgent::WillLoadXHR(XMLHttpRequest* xhr,
const AtomicString& method,
const KURL& url,
bool async,
+ EncodedFormData* form_data,
const HTTPHeaderMap& headers,
bool include_credentials) {
DCHECK(xhr);
DCHECK(!pending_request_);
pending_xhr_replay_data_ = XHRReplayData::Create(
- method, UrlWithoutFragment(url), async, include_credentials);
+ method, UrlWithoutFragment(url), async,
+ form_data ? form_data->DeepCopy() : nullptr, include_credentials);
for (const auto& header : headers)
pending_xhr_replay_data_->AddHeader(header.key, header.value);
}
@@ -1257,41 +1276,29 @@ void InspectorNetworkAgent::DidCloseWebSocket(ExecutionContext*,
CurrentTimeTicksInSeconds());
}
-void InspectorNetworkAgent::DidReceiveWebSocketFrame(unsigned long identifier,
- int op_code,
- bool masked,
- const char* payload,
- size_t payload_length) {
- std::unique_ptr<protocol::Network::WebSocketFrame> frame_object =
- protocol::Network::WebSocketFrame::create()
- .setOpcode(op_code)
- .setMask(masked)
- .setPayloadData(
- String::FromUTF8WithLatin1Fallback(payload, payload_length))
- .build();
+void InspectorNetworkAgent::DidReceiveWebSocketMessage(unsigned long identifier,
+ int op_code,
+ bool masked,
+ const char* payload,
+ size_t payload_length) {
GetFrontend()->webSocketFrameReceived(
IdentifiersFactory::SubresourceRequestId(identifier),
- CurrentTimeTicksInSeconds(), std::move(frame_object));
-}
-
-void InspectorNetworkAgent::DidSendWebSocketFrame(unsigned long identifier,
- int op_code,
- bool masked,
- const char* payload,
- size_t payload_length) {
- std::unique_ptr<protocol::Network::WebSocketFrame> frame_object =
- protocol::Network::WebSocketFrame::create()
- .setOpcode(op_code)
- .setMask(masked)
- .setPayloadData(
- String::FromUTF8WithLatin1Fallback(payload, payload_length))
- .build();
+ CurrentTimeTicksInSeconds(),
+ WebSocketMessageToProtocol(op_code, masked, payload, payload_length));
+}
+
+void InspectorNetworkAgent::DidSendWebSocketMessage(unsigned long identifier,
+ int op_code,
+ bool masked,
+ const char* payload,
+ size_t payload_length) {
GetFrontend()->webSocketFrameSent(
IdentifiersFactory::RequestId(nullptr, identifier),
- CurrentTimeTicksInSeconds(), std::move(frame_object));
+ CurrentTimeTicksInSeconds(),
+ WebSocketMessageToProtocol(op_code, masked, payload, payload_length));
}
-void InspectorNetworkAgent::DidReceiveWebSocketFrameError(
+void InspectorNetworkAgent::DidReceiveWebSocketMessageError(
unsigned long identifier,
const String& error_message) {
GetFrontend()->webSocketFrameError(
@@ -1420,8 +1427,12 @@ Response InspectorNetworkAgent::replayXHR(const String& request_id) {
xhr->setRequestHeader(header.key, header.value,
IGNORE_EXCEPTION_FOR_TESTING);
}
- xhr->SendForInspectorXHRReplay(data ? data->PostData() : nullptr,
- IGNORE_EXCEPTION_FOR_TESTING);
+ scoped_refptr<EncodedFormData> post_data;
+ if (data)
+ post_data = data->PostData();
+ if (!post_data)
+ post_data = xhr_replay_data->FormData();
+ xhr->SendForInspectorXHRReplay(post_data, IGNORE_EXCEPTION_FOR_TESTING);
replay_xhrs_.insert(xhr);
return Response::OK();
@@ -1517,7 +1528,9 @@ void InspectorNetworkAgent::DidCommitLoad(LocalFrame* frame,
}
void InspectorNetworkAgent::FrameScheduledNavigation(LocalFrame* frame,
- ScheduledNavigation*) {
+ const KURL&,
+ double,
+ ClientNavigationReason) {
frame_navigation_initiator_map_.Set(
IdentifiersFactory::FrameId(frame),
BuildInitiatorObject(frame->GetDocument(), FetchInitiatorInfo()));
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h
index 48c5fae036e..e37e634aa19 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h
@@ -109,7 +109,7 @@ class CORE_EXPORT InspectorNetworkAgent final
void DidReceiveData(unsigned long identifier,
DocumentLoader*,
const char* data,
- size_t data_length);
+ uint64_t data_length);
void DidReceiveBlob(unsigned long identifier,
DocumentLoader*,
scoped_refptr<BlobDataHandle>);
@@ -141,6 +141,7 @@ class CORE_EXPORT InspectorNetworkAgent final
const AtomicString& method,
const KURL&,
bool async,
+ EncodedFormData* form_data,
const HTTPHeaderMap& headers,
bool include_crendentials);
void DidFinishXHR(XMLHttpRequest*);
@@ -153,7 +154,10 @@ class CORE_EXPORT InspectorNetworkAgent final
void WillDestroyResource(Resource*);
- void FrameScheduledNavigation(LocalFrame*, ScheduledNavigation*);
+ void FrameScheduledNavigation(LocalFrame*,
+ const KURL&,
+ double delay,
+ ClientNavigationReason);
void FrameClearedScheduledNavigation(LocalFrame*);
void DidCreateWebSocket(ExecutionContext*,
@@ -170,17 +174,17 @@ class CORE_EXPORT InspectorNetworkAgent final
network::mojom::blink::WebSocketHandshakeRequest*,
network::mojom::blink::WebSocketHandshakeResponse*);
void DidCloseWebSocket(ExecutionContext*, unsigned long identifier);
- void DidReceiveWebSocketFrame(unsigned long identifier,
- int op_code,
- bool masked,
- const char* payload,
- size_t payload_length);
- void DidSendWebSocketFrame(unsigned long identifier,
- int op_code,
- bool masked,
- const char* payload,
- size_t payload_length);
- void DidReceiveWebSocketFrameError(unsigned long identifier, const String&);
+ void DidReceiveWebSocketMessage(unsigned long identifier,
+ int op_code,
+ bool masked,
+ const char* payload,
+ size_t payload_length);
+ void DidSendWebSocketMessage(unsigned long identifier,
+ int op_code,
+ bool masked,
+ const char* payload,
+ size_t payload_length);
+ void DidReceiveWebSocketMessageError(unsigned long identifier, const String&);
// Called from frontend
protocol::Response enable(Maybe<int> total_buffer_size,
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index 42874d1a5fe..06442690a19 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -34,9 +34,11 @@
#include "base/auto_reset.h"
#include "build/build_config.h"
+#include "cc/layers/picture_layer.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
@@ -47,16 +49,20 @@
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/frame/frame_overlay.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
+#include "third_party/blink/renderer/core/inspector/inspector_css_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_overlay_host.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -64,11 +70,13 @@
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/page_overlay.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
+#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
+#include "third_party/blink/renderer/platform/keyboard_codes.h"
#include "v8/include/v8.h"
namespace blink {
@@ -133,35 +141,69 @@ bool ParseQuad(std::unique_ptr<protocol::Array<double>> quad_array,
return true;
}
-#if defined(OS_MACOSX)
-const int kCtrlOrMeta = WebInputEvent::kMetaKey;
-#else
-const int kCtrlOrMeta = WebInputEvent::kControlKey;
-#endif
-
} // namespace
class InspectorOverlayAgent::InspectorPageOverlayDelegate final
- : public PageOverlay::Delegate {
+ : public FrameOverlay::Delegate,
+ public cc::ContentLayerClient {
public:
explicit InspectorPageOverlayDelegate(InspectorOverlayAgent& overlay)
- : overlay_(&overlay) {}
+ : overlay_(&overlay) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ layer_ = cc::PictureLayer::Create(this);
+ layer_->SetIsDrawable(true);
+ }
+ }
+ ~InspectorPageOverlayDelegate() override {
+ if (layer_)
+ layer_->ClearClient();
+ }
- void PaintPageOverlay(const PageOverlay&,
- GraphicsContext& graphics_context,
- const IntSize& web_view_size) const override {
+ void PaintFrameOverlay(const FrameOverlay& frame_overlay,
+ GraphicsContext& graphics_context,
+ const IntSize&) const override {
if (overlay_->IsEmpty())
return;
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ layer_->SetBounds(gfx::Size(frame_overlay.Size()));
+ RecordForeignLayer(graphics_context,
+ DisplayItem::kForeignLayerDevToolsOverlay, layer_,
+ PropertyTreeState::Root());
+ return;
+ }
+
LocalFrameView* view = overlay_->OverlayMainFrame()->View();
- DCHECK(!view->NeedsLayout());
- view->PaintWithLifecycleUpdate(
- graphics_context, kGlobalPaintNormalPhase,
- CullRect(IntRect(0, 0, view->Width(), view->Height())));
+ view->PaintOutsideOfLifecycle(graphics_context, kGlobalPaintNormalPhase);
+ }
+
+ void Invalidate() override {
+ if (layer_)
+ layer_->SetNeedsDisplay();
}
+ const cc::Layer* GetLayer() const { return layer_.get(); }
+
private:
+ // cc::ContentLayerClient implementation
+ gfx::Rect PaintableRegion() override { return gfx::Rect(layer_->bounds()); }
+ bool FillsBoundsCompletely() const override { return false; }
+ size_t GetApproximateUnsharedMemoryUsage() const override { return 0; }
+
+ scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
+ PaintingControlSetting) override {
+ auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
+ display_list->StartPaint();
+ display_list->push<cc::DrawRecordOp>(
+ overlay_->OverlayMainFrame()->View()->GetPaintRecord());
+ display_list->EndPaintOfUnpaired(PaintableRegion());
+ display_list->Finalize();
+ return display_list;
+ }
+
Persistent<InspectorOverlayAgent> overlay_;
+ // For CompositeAfterPaint.
+ scoped_refptr<cc::PictureLayer> layer_;
};
class InspectorOverlayAgent::InspectorOverlayChromeClient final
@@ -183,9 +225,13 @@ class InspectorOverlayAgent::InspectorOverlayChromeClient final
}
void SetCursor(const Cursor& cursor, LocalFrame* local_root) override {
+ if (overlay_->inspect_mode_.Get() ==
+ protocol::Overlay::InspectModeEnum::CaptureAreaScreenshot) {
+ return;
+ }
client_->SetCursorOverridden(false);
client_->SetCursor(cursor, overlay_->frame_impl_->GetFrame());
- client_->SetCursorOverridden(false);
+ client_->SetCursorOverridden(true);
}
void SetToolTip(LocalFrame& frame,
@@ -221,17 +267,20 @@ InspectorOverlayAgent::InspectorOverlayAgent(
v8_session_(v8_session),
dom_agent_(dom_agent),
swallow_next_mouse_up_(false),
- inspect_mode_(kNotSearching),
+ swallow_next_escape_up_(false),
backend_node_id_to_inspect_(0),
- enabled_(&agent_state_, /*default_value=*/false),
- suspended_(&agent_state_, /*default_value=*/false),
- show_debug_borders_(&agent_state_, /*default_value=*/false),
- show_fps_counter_(&agent_state_, /*default_value=*/false),
- show_paint_rects_(&agent_state_, /*default_value=*/false),
- show_scroll_bottleneck_rects_(&agent_state_, /*default_value=*/false),
- show_hit_test_borders_(&agent_state_, /*default_value=*/false),
- show_size_on_resize_(&agent_state_, /*default_value=*/false),
- paused_in_debugger_message_(&agent_state_, /*default_value=*/String()) {}
+ enabled_(&agent_state_, false),
+ suspended_(&agent_state_, false),
+ show_ad_highlights_(&agent_state_, false),
+ show_debug_borders_(&agent_state_, false),
+ show_fps_counter_(&agent_state_, false),
+ show_paint_rects_(&agent_state_, false),
+ show_scroll_bottleneck_rects_(&agent_state_, false),
+ show_hit_test_borders_(&agent_state_, false),
+ show_size_on_resize_(&agent_state_, false),
+ paused_in_debugger_message_(&agent_state_, String()),
+ inspect_mode_(&agent_state_, protocol::Overlay::InspectModeEnum::None),
+ inspect_mode_protocol_config_(&agent_state_, String()) {}
InspectorOverlayAgent::~InspectorOverlayAgent() {
DCHECK(!overlay_page_);
@@ -251,6 +300,7 @@ void InspectorOverlayAgent::Trace(blink::Visitor* visitor) {
}
void InspectorOverlayAgent::Restore() {
+ setShowAdHighlights(show_ad_highlights_.Get());
setShowDebugBorders(show_debug_borders_.Get());
setShowFPSCounter(show_fps_counter_.Get());
setShowPaintRects(show_paint_rects_.Get());
@@ -260,6 +310,17 @@ void InspectorOverlayAgent::Restore() {
if (paused_in_debugger_message_.Get().IsNull())
setPausedInDebuggerMessage(paused_in_debugger_message_.Get());
setSuspended(suspended_.Get());
+ if (inspect_mode_.Get() != protocol::Overlay::InspectModeEnum::None) {
+ std::unique_ptr<protocol::Value> value =
+ protocol::StringUtil::parseJSON(inspect_mode_protocol_config_.Get());
+ std::unique_ptr<protocol::Overlay::HighlightConfig> highlight_config;
+ protocol::ErrorSupport errors;
+ if (value) {
+ highlight_config =
+ protocol::Overlay::HighlightConfig::fromValue(value.get(), &errors);
+ }
+ SetSearchingForNode(inspect_mode_.Get(), std::move(highlight_config));
+ }
}
void InspectorOverlayAgent::Dispose() {
@@ -277,11 +338,13 @@ Response InspectorOverlayAgent::enable() {
static_cast<int>(backend_node_id_to_inspect_));
}
backend_node_id_to_inspect_ = 0;
+ SetNeedsUnbufferedInput(true);
return Response::OK();
}
Response InspectorOverlayAgent::disable() {
enabled_.Clear();
+ setShowAdHighlights(false);
setShowDebugBorders(false);
setShowFPSCounter(false);
setShowPaintRects(false);
@@ -290,8 +353,15 @@ Response InspectorOverlayAgent::disable() {
setShowViewportSizeOnResize(false);
setPausedInDebuggerMessage(String());
setSuspended(false);
- SetSearchingForNode(kNotSearching,
+ SetSearchingForNode(protocol::Overlay::InspectModeEnum::None,
Maybe<protocol::Overlay::HighlightConfig>());
+ SetNeedsUnbufferedInput(false);
+ return Response::OK();
+}
+
+Response InspectorOverlayAgent::setShowAdHighlights(bool show) {
+ show_ad_highlights_.Set(show);
+ frame_impl_->ViewImpl()->GetPage()->GetSettings().SetHighlightAds(show);
return Response::OK();
}
@@ -302,7 +372,12 @@ Response InspectorOverlayAgent::setShowDebugBorders(bool show) {
if (!response.isSuccess())
return response;
}
- frame_impl_->ViewImpl()->SetShowDebugBorders(show);
+ WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
+ WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
+ // While a frame is being detached the inspector will shutdown and
+ // turn off debug overlays, but the WebFrameWidget is already gone.
+ if (widget_impl)
+ widget_impl->Client()->SetShowDebugBorders(show);
return Response::OK();
}
@@ -313,7 +388,12 @@ Response InspectorOverlayAgent::setShowFPSCounter(bool show) {
if (!response.isSuccess())
return response;
}
- frame_impl_->ViewImpl()->SetShowFPSCounter(show);
+ WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
+ WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
+ // While a frame is being detached the inspector will shutdown and
+ // turn off debug overlays, but the WebFrameWidget is already gone.
+ if (widget_impl)
+ widget_impl->Client()->SetShowFPSCounter(show);
return Response::OK();
}
@@ -324,7 +404,12 @@ Response InspectorOverlayAgent::setShowPaintRects(bool show) {
if (!response.isSuccess())
return response;
}
- frame_impl_->ViewImpl()->SetShowPaintRects(show);
+ WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
+ WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
+ // While a frame is being detached the inspector will shutdown and
+ // turn off debug overlays, but the WebFrameWidget is already gone.
+ if (widget_impl)
+ widget_impl->Client()->SetShowPaintRects(show);
if (!show && frame_impl_->GetFrameView())
frame_impl_->GetFrameView()->Invalidate();
return Response::OK();
@@ -337,7 +422,12 @@ Response InspectorOverlayAgent::setShowScrollBottleneckRects(bool show) {
if (!response.isSuccess())
return response;
}
- frame_impl_->ViewImpl()->SetShowScrollBottleneckRects(show);
+ WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
+ WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
+ // While a frame is being detached the inspector will shutdown and
+ // turn off debug overlays, but the WebFrameWidget is already gone.
+ if (widget_impl)
+ widget_impl->Client()->SetShowScrollBottleneckRects(show);
return Response::OK();
}
@@ -348,7 +438,12 @@ Response InspectorOverlayAgent::setShowHitTestBorders(bool show) {
if (!response.isSuccess())
return response;
}
- frame_impl_->ViewImpl()->SetShowHitTestBorders(show);
+ WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
+ WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
+ // While a frame is being detached the inspector will shutdown and
+ // turn off debug overlays, but the WebFrameWidget is already gone.
+ if (widget_impl)
+ widget_impl->Client()->SetShowHitTestBorders(show);
return Response::OK();
}
@@ -368,31 +463,28 @@ Response InspectorOverlayAgent::setSuspended(bool suspended) {
if (suspended && !suspended_.Get())
ClearInternal();
suspended_.Set(suspended);
+ SetNeedsUnbufferedInput(!suspended);
return Response::OK();
}
Response InspectorOverlayAgent::setInspectMode(
const String& mode,
Maybe<protocol::Overlay::HighlightConfig> highlight_config) {
- SearchMode search_mode;
- if (mode == protocol::Overlay::InspectModeEnum::SearchForNode) {
- search_mode = kSearchingForNormal;
- } else if (mode == protocol::Overlay::InspectModeEnum::SearchForUAShadowDOM) {
- search_mode = kSearchingForUAShadow;
- } else if (mode == protocol::Overlay::InspectModeEnum::None) {
- search_mode = kNotSearching;
- } else {
+ if (mode != protocol::Overlay::InspectModeEnum::SearchForNode &&
+ mode != protocol::Overlay::InspectModeEnum::SearchForUAShadowDOM &&
+ mode != protocol::Overlay::InspectModeEnum::CaptureAreaScreenshot &&
+ mode != protocol::Overlay::InspectModeEnum::None) {
return Response::Error(
String("Unknown mode \"" + mode + "\" was provided."));
}
- if (search_mode != kNotSearching) {
+ if (mode != protocol::Overlay::InspectModeEnum::None) {
Response response = dom_agent_->PushDocumentUponHandlelessOperation();
if (!response.isSuccess())
return response;
}
- return SetSearchingForNode(search_mode, std::move(highlight_config));
+ return SetSearchingForNode(mode, std::move(highlight_config));
}
Response InspectorOverlayAgent::highlightRect(
@@ -426,7 +518,8 @@ Response InspectorOverlayAgent::highlightNode(
highlight_inspector_object,
Maybe<int> node_id,
Maybe<int> backend_node_id,
- Maybe<String> object_id) {
+ Maybe<String> object_id,
+ Maybe<String> selector_list) {
Node* node = nullptr;
Response response =
dom_agent_->AssertNode(node_id, backend_node_id, object_id, node);
@@ -439,7 +532,8 @@ Response InspectorOverlayAgent::highlightNode(
if (!response.isSuccess())
return response;
- InnerHighlightNode(node, nullptr, *highlight_config, false);
+ InnerHighlightNode(node, nullptr, selector_list.fromMaybe(String()),
+ *highlight_config, false);
return Response::OK();
}
@@ -458,7 +552,7 @@ Response InspectorOverlayAgent::highlightFrame(
InspectorDOMAgent::ParseColor(color.fromMaybe(nullptr));
highlight_config->content_outline =
InspectorDOMAgent::ParseColor(outline_color.fromMaybe(nullptr));
- InnerHighlightNode(frame->DeprecatedLocalOwner(), nullptr,
+ InnerHighlightNode(frame->DeprecatedLocalOwner(), nullptr, String(),
*highlight_config, false);
}
return Response::OK();
@@ -476,7 +570,8 @@ Response InspectorOverlayAgent::getHighlightObjectForTest(
Response response = dom_agent_->AssertNode(node_id, node);
if (!response.isSuccess())
return response;
- InspectorHighlight highlight(node, InspectorHighlight::DefaultConfig(), true);
+ InspectorHighlight highlight(node, InspectorHighlight::DefaultConfig(),
+ InspectorHighlightContrastInfo(), true);
*result = highlight.AsProtocolValue();
return Response::OK();
}
@@ -485,18 +580,20 @@ void InspectorOverlayAgent::Invalidate() {
if (IsEmpty())
return;
- if (!page_overlay_) {
- page_overlay_ = PageOverlay::Create(
+ if (!frame_overlay_) {
+ frame_overlay_ = FrameOverlay::Create(
frame_impl_->GetFrame(),
std::make_unique<InspectorPageOverlayDelegate>(*this));
}
- page_overlay_->Update();
+ frame_overlay_->Update();
+ if (auto* frame_view = frame_impl_->GetFrameView())
+ frame_view->SetPaintArtifactCompositorNeedsUpdate();
}
void InspectorOverlayAgent::UpdateAllOverlayLifecyclePhases() {
- if (page_overlay_)
- page_overlay_->Update();
+ if (frame_overlay_)
+ frame_overlay_->Update();
if (!IsEmpty()) {
base::AutoReset<bool> scoped(&in_layout_, true);
@@ -508,12 +605,26 @@ void InspectorOverlayAgent::UpdateAllOverlayLifecyclePhases() {
DocumentLifecycle::LifecycleUpdateReason::kOther);
}
- if (page_overlay_ && page_overlay_->GetGraphicsLayer())
- page_overlay_->GetGraphicsLayer()->Paint(nullptr);
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && frame_overlay_ &&
+ frame_overlay_->GetGraphicsLayer())
+ frame_overlay_->GetGraphicsLayer()->Paint();
+}
+
+void InspectorOverlayAgent::PaintOverlay(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (frame_overlay_)
+ frame_overlay_->Paint(context);
}
-bool InspectorOverlayAgent::IsInspectorLayer(GraphicsLayer* layer) {
- return page_overlay_ && page_overlay_->GetGraphicsLayer() == layer;
+bool InspectorOverlayAgent::IsInspectorLayer(const cc::Layer* layer) const {
+ if (!frame_overlay_)
+ return false;
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ return layer == static_cast<const InspectorPageOverlayDelegate*>(
+ frame_overlay_->GetDelegate())
+ ->GetLayer();
+ }
+ return layer == frame_overlay_->GetGraphicsLayer()->CcLayer();
}
void InspectorOverlayAgent::DispatchBufferedTouchEvents() {
@@ -523,11 +634,46 @@ void InspectorOverlayAgent::DispatchBufferedTouchEvents() {
}
bool InspectorOverlayAgent::HandleInputEvent(const WebInputEvent& input_event) {
- bool handled = false;
+ if (input_event.GetType() == WebInputEvent::kMouseUp &&
+ swallow_next_mouse_up_) {
+ swallow_next_mouse_up_ = false;
+ return true;
+ }
+
+ if (input_event.GetType() == WebInputEvent::kKeyUp &&
+ swallow_next_escape_up_) {
+ auto keyboard_event = static_cast<const WebKeyboardEvent&>(input_event);
+ if (keyboard_event.windows_key_code == VKEY_ESCAPE) {
+ swallow_next_escape_up_ = false;
+ return true;
+ }
+ }
if (IsEmpty())
return false;
+ // In the inspect mode, after clicking, keyboard events are dispatched here.
+ // Handle Escape below.
+
+ if (inspect_mode_.Get() != protocol::Overlay::InspectModeEnum::None &&
+ input_event.GetType() == WebInputEvent::kRawKeyDown) {
+ auto keyboard_event = static_cast<const WebKeyboardEvent&>(input_event);
+ if (keyboard_event.windows_key_code == VKEY_ESCAPE) {
+ // If we are in the process of dragging, reset the dragging.
+ // Otherwise, cancel searching.
+ if (screenshot_anchor_ != IntPoint::Zero()) {
+ screenshot_anchor_ = IntPoint::Zero();
+ ScheduleUpdate();
+ } else {
+ GetFrontend()->inspectModeCanceled();
+ }
+ swallow_next_escape_up_ = true;
+ return true;
+ }
+ }
+
+ bool handled = false;
+
if (input_event.GetType() == WebInputEvent::kGestureTap) {
// We only have a use for gesture tap.
WebGestureEvent transformed_event = TransformWebGestureEvent(
@@ -536,9 +682,9 @@ bool InspectorOverlayAgent::HandleInputEvent(const WebInputEvent& input_event) {
handled = HandleGestureEvent(transformed_event);
if (handled)
return true;
-
OverlayMainFrame()->GetEventHandler().HandleGestureEvent(transformed_event);
}
+
if (WebInputEvent::IsMouseEventType(input_event.GetType())) {
WebMouseEvent mouse_event =
TransformWebMouseEvent(frame_impl_->GetFrameView(),
@@ -606,18 +752,37 @@ void InspectorOverlayAgent::InnerHideHighlight() {
highlight_node_.Clear();
event_target_node_.Clear();
highlight_quad_.reset();
+ highlight_node_contrast_ = InspectorHighlightContrastInfo();
ScheduleUpdate();
}
void InspectorOverlayAgent::InnerHighlightNode(
Node* node,
Node* event_target,
+ String selector_list,
const InspectorHighlightConfig& highlight_config,
bool omit_tooltip) {
node_highlight_config_ = highlight_config;
highlight_node_ = node;
+ highlight_selector_list_ = selector_list;
event_target_node_ = event_target;
omit_tooltip_ = omit_tooltip;
+ highlight_node_contrast_ = InspectorHighlightContrastInfo();
+
+ if (node->IsElementNode()) {
+ // Compute the color contrast information here.
+ Vector<Color> bgcolors;
+ String font_size;
+ String font_weight;
+ InspectorCSSAgent::GetBackgroundColors(ToElement(node), &bgcolors,
+ &font_size, &font_weight);
+ if (bgcolors.size() == 1) {
+ highlight_node_contrast_.font_size = font_size;
+ highlight_node_contrast_.font_weight = font_weight;
+ highlight_node_contrast_.background_color = bgcolors[0];
+ }
+ }
+
ScheduleUpdate();
}
@@ -642,20 +807,24 @@ bool InspectorOverlayAgent::IsEmpty() {
highlight_node_ || event_target_node_ || highlight_quad_ ||
(resize_timer_active_ && show_size_on_resize_.Get()) ||
!paused_in_debugger_message_.Get().IsNull();
- return !has_visible_elements && inspect_mode_ == kNotSearching;
+ return !has_visible_elements &&
+ inspect_mode_.Get() == protocol::Overlay::InspectModeEnum::None;
}
void InspectorOverlayAgent::ScheduleUpdate() {
+ auto& client = frame_impl_->GetFrame()->GetPage()->GetChromeClient();
if (IsEmpty()) {
- if (page_overlay_)
- page_overlay_.reset();
+ if (frame_overlay_) {
+ frame_overlay_.reset();
+ client.SetCursorOverridden(false);
+ client.SetCursor(PointerCursor(), frame_impl_->GetFrame());
+ if (auto* frame_view = frame_impl_->GetFrameView())
+ frame_view->SetPaintArtifactCompositorNeedsUpdate();
+ }
return;
}
needs_update_ = true;
- LocalFrame* frame = frame_impl_->GetFrame();
- if (frame) {
- frame->GetPage()->GetChromeClient().ScheduleAnimation(frame->View());
- }
+ client.ScheduleAnimation(frame_impl_->GetFrame()->View());
}
void InspectorOverlayAgent::RebuildOverlayPage() {
@@ -670,7 +839,7 @@ void InspectorOverlayAgent::RebuildOverlayPage() {
OverlayMainFrame()->SetPageZoomFactor(WindowToViewportScale());
Reset(viewport_size);
-
+ DrawMatchingSelector();
DrawNodeHighlight();
DrawQuadHighlight();
DrawPausedInDebuggerMessage();
@@ -687,29 +856,31 @@ static std::unique_ptr<protocol::DictionaryValue> BuildObjectForSize(
return result;
}
-void InspectorOverlayAgent::DrawNodeHighlight() {
- if (!highlight_node_)
+void InspectorOverlayAgent::DrawMatchingSelector() {
+ if (highlight_selector_list_.IsEmpty() || !highlight_node_)
return;
-
- String selectors = node_highlight_config_.selector_list;
- StaticElementList* elements = nullptr;
DummyExceptionStateForTesting exception_state;
ContainerNode* query_base = highlight_node_->ContainingShadowRoot();
if (!query_base)
query_base = highlight_node_->ownerDocument();
- if (selectors.length()) {
- elements =
- query_base->QuerySelectorAll(AtomicString(selectors), exception_state);
- }
- if (elements && !exception_state.HadException()) {
- for (unsigned i = 0; i < elements->length(); ++i) {
- Element* element = elements->item(i);
- InspectorHighlight highlight(element, node_highlight_config_, false);
- std::unique_ptr<protocol::DictionaryValue> highlight_json =
- highlight.AsProtocolValue();
- EvaluateInOverlay("drawHighlight", std::move(highlight_json));
- }
+ StaticElementList* elements = query_base->QuerySelectorAll(
+ AtomicString(highlight_selector_list_), exception_state);
+ if (exception_state.HadException())
+ return;
+
+ for (unsigned i = 0; i < elements->length(); ++i) {
+ Element* element = elements->item(i);
+ InspectorHighlight highlight(element, node_highlight_config_,
+ highlight_node_contrast_, false);
+ std::unique_ptr<protocol::DictionaryValue> highlight_json =
+ highlight.AsProtocolValue();
+ EvaluateInOverlay("drawHighlight", std::move(highlight_json));
}
+}
+
+void InspectorOverlayAgent::DrawNodeHighlight() {
+ if (!highlight_node_)
+ return;
bool append_element_info =
(highlight_node_->IsElementNode() || highlight_node_->IsTextNode()) &&
@@ -717,7 +888,7 @@ void InspectorOverlayAgent::DrawNodeHighlight() {
highlight_node_->GetLayoutObject() &&
highlight_node_->GetDocument().GetFrame();
InspectorHighlight highlight(highlight_node_.Get(), node_highlight_config_,
- append_element_info);
+ highlight_node_contrast_, append_element_info);
if (event_target_node_) {
highlight.AppendEventTargetQuads(event_target_node_.Get(),
node_highlight_config_);
@@ -739,7 +910,7 @@ void InspectorOverlayAgent::DrawQuadHighlight() {
}
void InspectorOverlayAgent::DrawPausedInDebuggerMessage() {
- if (inspect_mode_ == kNotSearching &&
+ if (inspect_mode_.Get() == protocol::Overlay::InspectModeEnum::None &&
!paused_in_debugger_message_.Get().IsNull()) {
EvaluateInOverlay("drawPausedInDebuggerMessage",
paused_in_debugger_message_.Get());
@@ -752,12 +923,15 @@ void InspectorOverlayAgent::DrawViewSize() {
}
void InspectorOverlayAgent::DrawScreenshotBorder() {
- if (!screenshot_mode_)
+ if (screenshot_anchor_ == IntPoint::Zero())
return;
- VisualViewport& visual_viewport =
+ const VisualViewport& visual_viewport =
frame_impl_->GetFrame()->GetPage()->GetVisualViewport();
IntPoint p1 = visual_viewport.RootFrameToViewport(screenshot_anchor_);
IntPoint p2 = visual_viewport.RootFrameToViewport(screenshot_position_);
+ float scale = 1.f / WindowToViewportScale();
+ p1.Scale(scale, scale);
+ p2.Scale(scale, scale);
std::unique_ptr<protocol::DictionaryValue> data =
protocol::DictionaryValue::create();
data->setInteger("x1", p1.X());
@@ -940,10 +1114,10 @@ void InspectorOverlayAgent::ClearInternal() {
}
resize_timer_active_ = false;
paused_in_debugger_message_.Clear();
- inspect_mode_ = kNotSearching;
- screenshot_mode_ = false;
+ inspect_mode_.Set(protocol::Overlay::InspectModeEnum::None);
+ inspect_mode_protocol_config_.Set(String());
timer_.Stop();
- page_overlay_.reset();
+ frame_overlay_.reset();
InnerHideHighlight();
}
@@ -966,22 +1140,14 @@ void InspectorOverlayAgent::PageLayoutInvalidated(bool resized) {
}
bool InspectorOverlayAgent::HandleMouseMove(const WebMouseEvent& event) {
- if (!ShouldSearchForNode())
+ if (!InSomeInspectMode())
return false;
- if (event.GetModifiers() & kCtrlOrMeta) {
- InnerHideHighlight();
- hovered_node_for_inspect_mode_.Clear();
- if (screenshot_mode_) {
- screenshot_position_ = RoundedIntPoint(event.PositionInRootFrame());
- ScheduleUpdate();
- }
- return true;
- }
-
- if (screenshot_mode_) {
- screenshot_mode_ = false;
+ if (inspect_mode_.Get() ==
+ protocol::Overlay::InspectModeEnum::CaptureAreaScreenshot) {
+ screenshot_position_ = RoundedIntPoint(event.PositionInRootFrame());
ScheduleUpdate();
+ return true;
}
LocalFrame* frame = frame_impl_->GetFrame();
@@ -991,7 +1157,8 @@ bool InspectorOverlayAgent::HandleMouseMove(const WebMouseEvent& event) {
frame, event, event.GetModifiers() & WebInputEvent::kShiftKey);
// Do not highlight within user agent shadow root unless requested.
- if (inspect_mode_ != kSearchingForUAShadow) {
+ if (inspect_mode_.Get() !=
+ protocol::Overlay::InspectModeEnum::SearchForUAShadowDOM) {
ShadowRoot* shadow_root = InspectorDOMAgent::UserAgentShadowRoot(node);
if (shadow_root)
node = &shadow_root->host();
@@ -1026,23 +1193,19 @@ bool InspectorOverlayAgent::HandleMouseMove(const WebMouseEvent& event) {
NodeHighlightRequested(node);
bool omit_tooltip = event.GetModifiers() &
(WebInputEvent::kControlKey | WebInputEvent::kMetaKey);
- InnerHighlightNode(node, event_target, *inspect_mode_highlight_config_,
- omit_tooltip);
+ InnerHighlightNode(node, event_target, String(),
+ *inspect_mode_highlight_config_, omit_tooltip);
}
return true;
}
bool InspectorOverlayAgent::HandleMouseDown(const WebMouseEvent& event) {
swallow_next_mouse_up_ = false;
- screenshot_mode_ = false;
- if (!ShouldSearchForNode())
+ if (!InSomeInspectMode())
return false;
- if ((event.GetModifiers() & kCtrlOrMeta) &&
- (event.GetModifiers() & WebInputEvent::kLeftButtonDown)) {
- InnerHideHighlight();
- hovered_node_for_inspect_mode_.Clear();
- screenshot_mode_ = true;
+ if (inspect_mode_.Get() ==
+ protocol::Overlay::InspectModeEnum::CaptureAreaScreenshot) {
screenshot_anchor_ = RoundedIntPoint(event.PositionInRootFrame());
screenshot_position_ = screenshot_anchor_;
ScheduleUpdate();
@@ -1059,42 +1222,55 @@ bool InspectorOverlayAgent::HandleMouseDown(const WebMouseEvent& event) {
}
bool InspectorOverlayAgent::HandleMouseUp(const WebMouseEvent& event) {
- if (screenshot_mode_) {
- screenshot_mode_ = false;
- float scale = 1.0f;
- IntPoint p1 = screenshot_anchor_;
- IntPoint p2 = screenshot_position_;
- if (LocalFrame* frame = frame_impl_->GetFrame()) {
- scale = frame->GetPage()->PageScaleFactor();
- p1 = frame->View()->ConvertFromRootFrame(p1);
- p2 = frame->View()->ConvertFromRootFrame(p2);
- }
- int min_x = std::min(p1.X(), p2.X());
- int max_x = std::max(p1.X(), p2.X());
- int min_y = std::min(p1.Y(), p2.Y());
- int max_y = std::max(p1.Y(), p2.Y());
- GetFrontend()->screenshotRequested(protocol::Page::Viewport::create()
- .setX(min_x)
- .setY(min_y)
- .setWidth(max_x - min_x)
- .setHeight(max_y - min_y)
- .setScale(scale)
- .build());
+ if (inspect_mode_.Get() !=
+ protocol::Overlay::InspectModeEnum::CaptureAreaScreenshot) {
+ return false;
+ }
+
+ if (screenshot_anchor_ == IntPoint::Zero())
return true;
+ float scale = 1.0f;
+ IntPoint p1 = screenshot_anchor_;
+ IntPoint p2 = screenshot_position_;
+ if (LocalFrame* frame = frame_impl_->GetFrame()) {
+ scale = frame->GetPage()->PageScaleFactor();
+ p1 = frame->View()->ConvertFromRootFrame(p1);
+ p2 = frame->View()->ConvertFromRootFrame(p2);
+ if (const RootFrameViewport* root_frame_viewport =
+ frame->View()->GetRootFrameViewport()) {
+ IntSize scroll_offset = FlooredIntSize(
+ root_frame_viewport->LayoutViewport().GetScrollOffset());
+ p1 += scroll_offset;
+ p2 += scroll_offset;
+ }
}
- if (swallow_next_mouse_up_) {
- swallow_next_mouse_up_ = false;
+ float dp_to_dip = 1.f / WindowToViewportScale();
+ p1.Scale(dp_to_dip, dp_to_dip);
+ p2.Scale(dp_to_dip, dp_to_dip);
+ // Points are in device independent pixels (dip) now.
+ IntRect rect =
+ UnionRectEvenIfEmpty(IntRect(p1, IntSize()), IntRect(p2, IntSize()));
+ if (rect.Width() < 5 || rect.Height() < 5) {
+ screenshot_anchor_ = IntPoint::Zero();
return true;
}
- return false;
+ GetFrontend()->screenshotRequested(protocol::Page::Viewport::create()
+ .setX(rect.X())
+ .setY(rect.Y())
+ .setWidth(rect.Width())
+ .setHeight(rect.Height())
+ .setScale(scale)
+ .build());
+ return true;
}
bool InspectorOverlayAgent::HandleGestureEvent(const WebGestureEvent& event) {
- if (!ShouldSearchForNode() || event.GetType() != WebInputEvent::kGestureTap)
+ if (!InSomeInspectMode() || event.GetType() != WebInputEvent::kGestureTap)
return false;
Node* node = HoveredNodeForEvent(frame_impl_->GetFrame(), event, false);
if (node && inspect_mode_highlight_config_) {
- InnerHighlightNode(node, nullptr, *inspect_mode_highlight_config_, false);
+ InnerHighlightNode(node, nullptr, String(), *inspect_mode_highlight_config_,
+ false);
Inspect(node);
return true;
}
@@ -1102,11 +1278,12 @@ bool InspectorOverlayAgent::HandleGestureEvent(const WebGestureEvent& event) {
}
bool InspectorOverlayAgent::HandlePointerEvent(const WebPointerEvent& event) {
- if (!ShouldSearchForNode())
+ if (!InSomeInspectMode())
return false;
Node* node = HoveredNodeForEvent(frame_impl_->GetFrame(), event, false);
if (node && inspect_mode_highlight_config_) {
- InnerHighlightNode(node, nullptr, *inspect_mode_highlight_config_, false);
+ InnerHighlightNode(node, nullptr, String(), *inspect_mode_highlight_config_,
+ false);
Inspect(node);
return true;
}
@@ -1123,8 +1300,8 @@ Response InspectorOverlayAgent::CompositingEnabled() {
return Response::OK();
}
-bool InspectorOverlayAgent::ShouldSearchForNode() {
- return inspect_mode_ != kNotSearching;
+bool InspectorOverlayAgent::InSomeInspectMode() {
+ return inspect_mode_.Get() != protocol::Overlay::InspectModeEnum::None;
}
void InspectorOverlayAgent::Inspect(Node* inspected_node) {
@@ -1163,25 +1340,41 @@ void InspectorOverlayAgent::NodeHighlightRequested(Node* node) {
}
Response InspectorOverlayAgent::SetSearchingForNode(
- SearchMode search_mode,
+ String search_mode,
Maybe<protocol::Overlay::HighlightConfig> highlight_inspector_object) {
- if (search_mode == kNotSearching) {
- inspect_mode_ = search_mode;
- screenshot_mode_ = false;
- ScheduleUpdate();
+ if (search_mode == protocol::Overlay::InspectModeEnum::None) {
+ inspect_mode_.Set(search_mode);
hovered_node_for_inspect_mode_.Clear();
+ screenshot_anchor_ = IntPoint::Zero();
+ screenshot_position_ = IntPoint::Zero();
InnerHideHighlight();
return Response::OK();
}
+ String serialized_config =
+ highlight_inspector_object.isJust()
+ ? highlight_inspector_object.fromJust()->serialize()
+ : String();
std::unique_ptr<InspectorHighlightConfig> config;
Response response = HighlightConfigFromInspectorObject(
std::move(highlight_inspector_object), &config);
if (!response.isSuccess())
return response;
- inspect_mode_ = search_mode;
+ inspect_mode_.Set(search_mode);
+ inspect_mode_protocol_config_.Set(serialized_config);
inspect_mode_highlight_config_ = std::move(config);
- ScheduleUpdate();
+
+ if (search_mode ==
+ protocol::Overlay::InspectModeEnum::CaptureAreaScreenshot) {
+ auto& client = frame_impl_->GetFrame()->GetPage()->GetChromeClient();
+ client.SetCursorOverridden(false);
+ client.SetCursor(CrossCursor(), frame_impl_->GetFrame());
+ client.SetCursorOverridden(true);
+ hovered_node_for_inspect_mode_.Clear();
+ InnerHideHighlight();
+ } else {
+ ScheduleUpdate();
+ }
return Response::OK();
}
@@ -1198,9 +1391,9 @@ Response InspectorOverlayAgent::HighlightConfigFromInspectorObject(
std::unique_ptr<InspectorHighlightConfig> highlight_config =
std::make_unique<InspectorHighlightConfig>();
highlight_config->show_info = config->getShowInfo(false);
+ highlight_config->show_styles = config->getShowStyles(false);
highlight_config->show_rulers = config->getShowRulers(false);
highlight_config->show_extension_lines = config->getShowExtensionLines(false);
- highlight_config->display_as_material = config->getDisplayAsMaterial(false);
highlight_config->content =
InspectorDOMAgent::ParseColor(config->getContentColor(nullptr));
highlight_config->padding =
@@ -1217,10 +1410,17 @@ Response InspectorOverlayAgent::HighlightConfigFromInspectorObject(
InspectorDOMAgent::ParseColor(config->getShapeMarginColor(nullptr));
highlight_config->css_grid =
InspectorDOMAgent::ParseColor(config->getCssGridColor(nullptr));
- highlight_config->selector_list = config->getSelectorList("");
*out_config = std::move(highlight_config);
return Response::OK();
}
+void InspectorOverlayAgent::SetNeedsUnbufferedInput(bool unbuffered) {
+ LocalFrame* frame = frame_impl_->GetFrame();
+ if (frame) {
+ frame->GetPage()->GetChromeClient().SetNeedsUnbufferedInputForDebugger(
+ frame, unbuffered);
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index d84956c95fa..d02a6d4c7a8 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -47,16 +47,20 @@
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+namespace cc {
+class Layer;
+}
+
namespace blink {
class Color;
-class GraphicsLayer;
+class GraphicsContext;
class InspectedFrames;
class InspectorDOMAgent;
class LocalFrame;
class Node;
class Page;
-class PageOverlay;
+class FrameOverlay;
class WebGestureEvent;
class WebMouseEvent;
class WebLocalFrameImpl;
@@ -78,6 +82,7 @@ class CORE_EXPORT InspectorOverlayAgent final
// protocol::Dispatcher::OverlayCommandHandler implementation.
protocol::Response enable() override;
protocol::Response disable() override;
+ protocol::Response setShowAdHighlights(bool) override;
protocol::Response setShowPaintRects(bool) override;
protocol::Response setShowDebugBorders(bool) override;
protocol::Response setShowFPSCounter(bool) override;
@@ -105,7 +110,8 @@ class CORE_EXPORT InspectorOverlayAgent final
std::unique_ptr<protocol::Overlay::HighlightConfig>,
protocol::Maybe<int> node_id,
protocol::Maybe<int> backend_node_id,
- protocol::Maybe<String> object_id) override;
+ protocol::Maybe<String> object_id,
+ protocol::Maybe<String> selector_list) override;
protocol::Response hideHighlight() override;
protocol::Response highlightFrame(
const String& frame_id,
@@ -127,24 +133,21 @@ class CORE_EXPORT InspectorOverlayAgent final
// Update the complete lifecycle (e.g., layout, paint) for the overlay.
void UpdateAllOverlayLifecyclePhases();
+ // For CompositeAfterPaint.
+ void PaintOverlay(GraphicsContext&);
- bool IsInspectorLayer(GraphicsLayer*);
+ bool IsInspectorLayer(const cc::Layer*) const;
private:
class InspectorOverlayChromeClient;
class InspectorPageOverlayDelegate;
- enum SearchMode {
- kNotSearching,
- kSearchingForNormal,
- kSearchingForUAShadow,
- };
-
// InspectorOverlayHost::Listener implementation.
void OverlayResumed() override;
void OverlaySteppedOver() override;
bool IsEmpty();
+ void DrawMatchingSelector();
void DrawNodeHighlight();
void DrawQuadHighlight();
void DrawPausedInDebuggerMessage();
@@ -173,10 +176,10 @@ class CORE_EXPORT InspectorOverlayAgent final
protocol::Response CompositingEnabled();
- bool ShouldSearchForNode();
+ bool InSomeInspectMode();
void NodeHighlightRequested(Node*);
protocol::Response SetSearchingForNode(
- SearchMode,
+ String search_mode,
protocol::Maybe<protocol::Overlay::HighlightConfig>);
protocol::Response HighlightConfigFromInspectorObject(
protocol::Maybe<protocol::Overlay::HighlightConfig>
@@ -187,13 +190,18 @@ class CORE_EXPORT InspectorOverlayAgent final
protocol::Maybe<protocol::DOM::RGBA> outline_color);
void InnerHighlightNode(Node*,
Node* event_target,
+ String selector,
const InspectorHighlightConfig&,
bool omit_tooltip);
void InnerHideHighlight();
+ void SetNeedsUnbufferedInput(bool unbuffered);
+
Member<WebLocalFrameImpl> frame_impl_;
Member<InspectedFrames> inspected_frames_;
Member<Node> highlight_node_;
+ String highlight_selector_list_;
+ InspectorHighlightContrastInfo highlight_node_contrast_;
Member<Node> event_target_node_;
InspectorHighlightConfig node_highlight_config_;
std::unique_ptr<FloatQuad> highlight_quad_;
@@ -210,17 +218,17 @@ class CORE_EXPORT InspectorOverlayAgent final
bool needs_update_;
v8_inspector::V8InspectorSession* v8_session_;
Member<InspectorDOMAgent> dom_agent_;
- std::unique_ptr<PageOverlay> page_overlay_;
+ std::unique_ptr<FrameOverlay> frame_overlay_;
Member<Node> hovered_node_for_inspect_mode_;
bool swallow_next_mouse_up_;
- SearchMode inspect_mode_;
+ bool swallow_next_escape_up_;
std::unique_ptr<InspectorHighlightConfig> inspect_mode_highlight_config_;
DOMNodeId backend_node_id_to_inspect_;
- bool screenshot_mode_ = false;
IntPoint screenshot_anchor_;
IntPoint screenshot_position_;
InspectorAgentState::Boolean enabled_;
InspectorAgentState::Boolean suspended_;
+ InspectorAgentState::Boolean show_ad_highlights_;
InspectorAgentState::Boolean show_debug_borders_;
InspectorAgentState::Boolean show_fps_counter_;
InspectorAgentState::Boolean show_paint_rects_;
@@ -228,6 +236,8 @@ class CORE_EXPORT InspectorOverlayAgent final
InspectorAgentState::Boolean show_hit_test_borders_;
InspectorAgentState::Boolean show_size_on_resize_;
InspectorAgentState::String paused_in_debugger_message_;
+ InspectorAgentState::String inspect_mode_;
+ InspectorAgentState::String inspect_mode_protocol_config_;
DISALLOW_COPY_AND_ASSIGN(InspectorOverlayAgent);
};
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 04bb17da7ee..fb2982364f7 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -33,6 +33,7 @@
#include <memory>
#include "build/build_config.h"
+#include "third_party/blink/public/platform/web_screen_info.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_regexp.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
@@ -88,23 +89,23 @@ using protocol::Response;
namespace {
-String ScheduledNavigationReasonToProtocol(ScheduledNavigation::Reason reason) {
+String ClientNavigationReasonToProtocol(ClientNavigationReason reason) {
using ReasonEnum =
protocol::Page::FrameScheduledNavigationNotification::ReasonEnum;
switch (reason) {
- case ScheduledNavigation::Reason::kFormSubmissionGet:
+ case ClientNavigationReason::kFormSubmissionGet:
return ReasonEnum::FormSubmissionGet;
- case ScheduledNavigation::Reason::kFormSubmissionPost:
+ case ClientNavigationReason::kFormSubmissionPost:
return ReasonEnum::FormSubmissionPost;
- case ScheduledNavigation::Reason::kHttpHeaderRefresh:
+ case ClientNavigationReason::kHttpHeaderRefresh:
return ReasonEnum::HttpHeaderRefresh;
- case ScheduledNavigation::Reason::kFrameNavigation:
+ case ClientNavigationReason::kFrameNavigation:
return ReasonEnum::ScriptInitiated;
- case ScheduledNavigation::Reason::kMetaTagRefresh:
+ case ClientNavigationReason::kMetaTagRefresh:
return ReasonEnum::MetaTagRefresh;
- case ScheduledNavigation::Reason::kPageBlock:
+ case ClientNavigationReason::kPageBlock:
return ReasonEnum::PageBlockInterstitial;
- case ScheduledNavigation::Reason::kReload:
+ case ClientNavigationReason::kReload:
return ReasonEnum::Reload;
default:
NOTREACHED();
@@ -843,7 +844,9 @@ void InspectorPageAgent::DidClearDocumentOfWindowObject(LocalFrame* frame) {
const String source = scripts_to_evaluate_on_load_.Get(key);
const String world_name = worlds_to_evaluate_on_load_.Get(key);
if (world_name.IsEmpty()) {
- frame->GetScriptController().ExecuteScriptInMainWorld(source);
+ frame->GetScriptController().ExecuteScriptInMainWorld(
+ source, ScriptSourceLocationType::kUnknown,
+ ScriptController::kExecuteScriptWhenScriptsDisabled);
continue;
}
@@ -876,7 +879,8 @@ void InspectorPageAgent::DidClearDocumentOfWindowObject(LocalFrame* frame) {
if (!script_to_evaluate_on_load_once_.IsEmpty()) {
frame->GetScriptController().ExecuteScriptInMainWorld(
- script_to_evaluate_on_load_once_);
+ script_to_evaluate_on_load_once_, ScriptSourceLocationType::kUnknown,
+ ScriptController::kExecuteScriptWhenScriptsDisabled);
}
}
@@ -936,11 +940,12 @@ void InspectorPageAgent::FrameStoppedLoading(LocalFrame* frame) {
void InspectorPageAgent::FrameScheduledNavigation(
LocalFrame* frame,
- ScheduledNavigation* scheduled_navigation) {
+ const KURL& url,
+ double delay,
+ ClientNavigationReason reason) {
GetFrontend()->frameScheduledNavigation(
- IdentifiersFactory::FrameId(frame), scheduled_navigation->Delay(),
- ScheduledNavigationReasonToProtocol(scheduled_navigation->GetReason()),
- scheduled_navigation->Url().GetString());
+ IdentifiersFactory::FrameId(frame), delay,
+ ClientNavigationReasonToProtocol(reason), url.GetString());
}
void InspectorPageAgent::FrameClearedScheduledNavigation(LocalFrame* frame) {
@@ -1019,14 +1024,14 @@ void InspectorPageAgent::WindowOpen(Document* document,
std::unique_ptr<protocol::Page::Frame> InspectorPageAgent::BuildObjectForFrame(
LocalFrame* frame) {
DocumentLoader* loader = frame->Loader().GetDocumentLoader();
- KURL url = loader->GetRequest().Url();
std::unique_ptr<protocol::Page::Frame> frame_object =
protocol::Page::Frame::create()
.setId(IdentifiersFactory::FrameId(frame))
.setLoaderId(IdentifiersFactory::LoaderId(loader))
- .setUrl(UrlWithoutFragment(url).GetString())
+ .setUrl(UrlWithoutFragment(loader->Url()).GetString())
.setMimeType(frame->Loader().GetDocumentLoader()->MimeType())
- .setSecurityOrigin(SecurityOrigin::Create(url)->ToRawString())
+ .setSecurityOrigin(
+ SecurityOrigin::Create(loader->Url())->ToRawString())
.build();
Frame* parent_frame = frame->Tree().Parent();
if (parent_frame) {
@@ -1155,7 +1160,13 @@ Response InspectorPageAgent::getLayoutMetrics(
LocalFrameView* frame_view = main_frame->View();
ScrollOffset page_offset = frame_view->GetScrollableArea()->GetScrollOffset();
+ // page_zoom is either CSS-to-DP or CSS-to-DIP depending on
+ // enable-use-zoom-for-dsf flag.
float page_zoom = main_frame->PageZoomFactor();
+ // page_zoom_factor is CSS to DIP (device independent pixels).
+ float page_zoom_factor =
+ page_zoom /
+ main_frame->GetPage()->GetChromeClient().WindowToViewportScalar(1);
FloatRect visible_rect = visual_viewport.VisibleRect();
float scale = visual_viewport.Scale();
@@ -1179,6 +1190,7 @@ Response InspectorPageAgent::getLayoutMetrics(
.setClientWidth(visible_rect.Width())
.setClientHeight(visible_rect.Height())
.setScale(scale)
+ .setZoom(page_zoom_factor)
.build();
return Response::OK();
}
@@ -1334,12 +1346,17 @@ Response InspectorPageAgent::clearCompilationCache() {
return Response::OK();
}
+Response InspectorPageAgent::waitForDebugger() {
+ client_->WaitForDebugger();
+ return Response::OK();
+}
+
protocol::Response InspectorPageAgent::generateTestReport(const String& message,
Maybe<String> group) {
Document* document = inspected_frames_->Root()->GetDocument();
// Construct the test report.
- TestReportBody* body = new TestReportBody(message);
+ TestReportBody* body = MakeGarbageCollected<TestReportBody>(message);
Report* report =
MakeGarbageCollected<Report>("test", document->Url().GetString(), body);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h
index e8109fe51e0..553da2174f9 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
#include "third_party/blink/renderer/core/inspector/protocol/Page.h"
+#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -54,7 +55,6 @@ class DocumentLoader;
class InspectedFrames;
class InspectorResourceContentLoader;
class LocalFrame;
-class ScheduledNavigation;
class ScriptSourceCode;
class SharedBuffer;
enum class ResourceType : uint8_t;
@@ -68,6 +68,7 @@ class CORE_EXPORT InspectorPageAgent final
public:
virtual ~Client() = default;
virtual void PageLayoutInvalidated(bool resized) {}
+ virtual void WaitForDebugger() {}
};
enum ResourceType {
@@ -171,6 +172,7 @@ class CORE_EXPORT InspectorPageAgent final
protocol::Response addCompilationCache(const String& url,
const protocol::Binary& data) override;
protocol::Response clearCompilationCache() override;
+ protocol::Response waitForDebugger() override;
// InspectorInstrumentation API
void DidClearDocumentOfWindowObject(LocalFrame*);
@@ -182,7 +184,10 @@ class CORE_EXPORT InspectorPageAgent final
void FrameDetachedFromParent(LocalFrame*);
void FrameStartedLoading(LocalFrame*);
void FrameStoppedLoading(LocalFrame*);
- void FrameScheduledNavigation(LocalFrame*, ScheduledNavigation*);
+ void FrameScheduledNavigation(LocalFrame*,
+ const KURL&,
+ double delay,
+ ClientNavigationReason);
void FrameClearedScheduledNavigation(LocalFrame*);
void WillRunJavaScriptDialog();
void DidRunJavaScriptDialog();
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json b/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
index 5441041d51d..6ff7bad07a9 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
@@ -73,8 +73,8 @@
},
{
"domain": "Page",
- "exclude": ["getNavigationHistory", "navigateToHistoryEntry", "captureScreenshot", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled",
- "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront", "setDownloadBehavior", "navigate", "crash", "close", "setWebLifecycleState", "captureSnapshot"],
+ "exclude": ["getNavigationHistory", "navigateToHistoryEntry", "resetNavigationHistory", "captureScreenshot", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled",
+ "getAppManifest", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront", "setDownloadBehavior", "navigate", "crash", "close", "setWebLifecycleState", "captureSnapshot"],
"async": ["getResourceContent", "searchInResource"],
"exclude_events": ["screencastFrame", "screencastVisibilityChanged", "colorPicked", "interstitialShown", "interstitialHidden", "javascriptDialogOpening", "javascriptDialogClosed", "navigationRequested"]
},
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
index bb59c3a5f39..057e35ead67 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/inspector/inspector_resource_content_loader.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/css/style_sheet_contents.h"
@@ -88,7 +88,10 @@ void InspectorResourceContentLoader::Start() {
resource_request.SetCacheMode(mojom::FetchCacheMode::kOnlyIfCached);
}
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
- resource_request.SetSkipServiceWorker(true);
+ if (document->Loader() &&
+ document->Loader()->GetResponse().WasFetchedViaServiceWorker()) {
+ resource_request.SetCacheMode(mojom::FetchCacheMode::kDefault);
+ }
if (!resource_request.Url().GetString().IsEmpty()) {
urls_to_fetch.insert(resource_request.Url().GetString());
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.h b/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.h
index 3c5c8c65349..0c7fabe48dc 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.h
@@ -8,7 +8,7 @@
#include <memory>
#include <type_traits>
#include <vector>
-#include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index a2a44cb8792..0069c74cf97 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -131,7 +131,7 @@ void InspectorTraceEvents::DidReceiveResourceResponse(
void InspectorTraceEvents::DidReceiveData(unsigned long identifier,
DocumentLoader* loader,
const char* data,
- int encoded_data_length) {
+ uint64_t encoded_data_length) {
LocalFrame* frame = loader ? loader->GetFrame() : nullptr;
TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceivedData",
TRACE_EVENT_SCOPE_THREAD, "data",
@@ -192,17 +192,11 @@ void InspectorTraceEvents::Did(const probe::ParseHTML& probe) {
}
void InspectorTraceEvents::Will(const probe::CallFunction& probe) {
- if (probe.depth)
- return;
- TRACE_EVENT_BEGIN1(
- "devtools.timeline", "FunctionCall", "data",
- inspector_function_call_event::Data(probe.context, probe.function));
}
void InspectorTraceEvents::Did(const probe::CallFunction& probe) {
if (probe.depth)
return;
- TRACE_EVENT_END0("devtools.timeline", "FunctionCall");
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
"UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data",
inspector_update_counters_event::Data());
@@ -358,10 +352,6 @@ const char* CompileOptionsString(v8::ScriptCompiler::CompileOptions options) {
return "code";
case v8::ScriptCompiler::kEagerCompile:
return "full code";
- // TODO(v8:8252): Remove the default branch once deprecated options are
- // removed from v8::ScriptCompiler::CompileOptions.
- default:
- NOTREACHED();
}
NOTREACHED();
return "";
@@ -830,13 +820,13 @@ std::unique_ptr<TracedValue> inspector_receive_data_event::Data(
DocumentLoader* loader,
unsigned long identifier,
LocalFrame* frame,
- int encoded_data_length) {
+ uint64_t encoded_data_length) {
String request_id = IdentifiersFactory::RequestId(loader, identifier);
std::unique_ptr<TracedValue> value = TracedValue::Create();
value->SetString("requestId", request_id);
value->SetString("frame", IdentifiersFactory::FrameId(frame));
- value->SetInteger("encodedDataLength", encoded_data_length);
+ value->SetDouble("encodedDataLength", encoded_data_length);
return value;
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h
index b52199fda1f..92a8ae80cfa 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h
@@ -96,7 +96,7 @@ class CORE_EXPORT InspectorTraceEvents
void DidReceiveData(unsigned long identifier,
DocumentLoader*,
const char* data,
- int data_length);
+ uint64_t data_length);
void DidFinishLoading(unsigned long identifier,
DocumentLoader*,
TimeTicks monotonic_finish_time,
@@ -286,7 +286,7 @@ namespace inspector_receive_data_event {
std::unique_ptr<TracedValue> Data(DocumentLoader*,
unsigned long identifier,
LocalFrame*,
- int encoded_data_length);
+ uint64_t encoded_data_length);
}
namespace inspector_resource_finish_event {
diff --git a/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc b/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc
index 29613e8a713..838eae759cf 100644
--- a/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc
@@ -45,9 +45,10 @@ static bool IsHTTPErrorStatusCode(int status_code) {
XHRReplayData* XHRReplayData::Create(const AtomicString& method,
const KURL& url,
bool async,
+ scoped_refptr<EncodedFormData> form_data,
bool include_credentials) {
- return MakeGarbageCollected<XHRReplayData>(method, url, async,
- include_credentials);
+ return MakeGarbageCollected<XHRReplayData>(
+ method, url, async, std::move(form_data), include_credentials);
}
void XHRReplayData::AddHeader(const AtomicString& key,
@@ -58,10 +59,12 @@ void XHRReplayData::AddHeader(const AtomicString& key,
XHRReplayData::XHRReplayData(const AtomicString& method,
const KURL& url,
bool async,
+ scoped_refptr<EncodedFormData> form_data,
bool include_credentials)
: method_(method),
url_(url),
async_(async),
+ form_data_(form_data),
include_credentials_(include_credentials) {}
// ResourceData
@@ -156,9 +159,9 @@ void NetworkResourcesData::ResourceData::ClearWeakMembers(Visitor* visitor) {
cached_resource_ = nullptr;
}
-size_t NetworkResourcesData::ResourceData::DataLength() const {
- size_t data_buffer_size = data_buffer_ ? data_buffer_->size() : 0;
- size_t post_data_size = post_data_ ? post_data_->SizeInBytes() : 0;
+uint64_t NetworkResourcesData::ResourceData::DataLength() const {
+ uint64_t data_buffer_size = data_buffer_ ? data_buffer_->size() : 0;
+ uint64_t post_data_size = post_data_ ? post_data_->SizeInBytes() : 0;
return data_buffer_size + post_data_size;
}
@@ -274,7 +277,7 @@ void NetworkResourcesData::SetResourceContent(const String& request_id,
NetworkResourcesData::ResourceData*
NetworkResourcesData::PrepareToAddResourceData(const String& request_id,
- size_t data_length) {
+ uint64_t data_length) {
ResourceData* resource_data = ResourceDataForRequestId(request_id);
if (!resource_data)
return nullptr;
@@ -295,10 +298,10 @@ NetworkResourcesData::PrepareToAddResourceData(const String& request_id,
void NetworkResourcesData::MaybeAddResourceData(const String& request_id,
const char* data,
- size_t data_length) {
+ uint64_t data_length) {
if (ResourceData* resource_data =
PrepareToAddResourceData(request_id, data_length)) {
- resource_data->AppendData(data, data_length);
+ resource_data->AppendData(data, SafeCast<size_t>(data_length));
}
}
@@ -431,7 +434,7 @@ void NetworkResourcesData::EnsureNoDataForRequestId(const String& request_id) {
request_id_to_resource_data_map_.erase(request_id);
}
-bool NetworkResourcesData::EnsureFreeSpace(size_t size) {
+bool NetworkResourcesData::EnsureFreeSpace(uint64_t size) {
if (size > maximum_resources_content_size_)
return false;
diff --git a/chromium/third_party/blink/renderer/core/inspector/network_resources_data.h b/chromium/third_party/blink/renderer/core/inspector/network_resources_data.h
index 0b6b795eb09..3ae0ffe09e4 100644
--- a/chromium/third_party/blink/renderer/core/inspector/network_resources_data.h
+++ b/chromium/third_party/blink/renderer/core/inspector/network_resources_data.h
@@ -54,17 +54,20 @@ class XHRReplayData final : public GarbageCollectedFinalized<XHRReplayData> {
static XHRReplayData* Create(const AtomicString& method,
const KURL&,
bool async,
+ scoped_refptr<EncodedFormData>,
bool include_credentials);
XHRReplayData(const AtomicString& method,
const KURL&,
bool async,
+ scoped_refptr<EncodedFormData>,
bool include_credentials);
void AddHeader(const AtomicString& key, const AtomicString& value);
const AtomicString& Method() const { return method_; }
const KURL& Url() const { return url_; }
bool Async() const { return async_; }
+ EncodedFormData* FormData() const { return form_data_.get(); }
const HTTPHeaderMap& Headers() const { return headers_; }
bool IncludeCredentials() const { return include_credentials_; }
@@ -74,6 +77,7 @@ class XHRReplayData final : public GarbageCollectedFinalized<XHRReplayData> {
AtomicString method_;
KURL url_;
bool async_;
+ scoped_refptr<EncodedFormData> form_data_;
HTTPHeaderMap headers_;
bool include_credentials_;
};
@@ -162,13 +166,13 @@ class NetworkResourcesData final
void SetPostData(scoped_refptr<EncodedFormData> post_data) {
post_data_ = post_data;
}
- scoped_refptr<EncodedFormData> PostData() const { return post_data_; }
+ EncodedFormData* PostData() const { return post_data_.get(); }
ExecutionContext* GetExecutionContext() const { return execution_context_; }
void Trace(blink::Visitor*);
private:
bool HasData() const { return data_buffer_.get(); }
- size_t DataLength() const;
+ uint64_t DataLength() const;
void AppendData(const char* data, size_t data_length);
size_t DecodeDataToContent();
void ClearWeakMembers(Visitor*);
@@ -225,7 +229,7 @@ class NetworkResourcesData final
bool base64_encoded = false);
void MaybeAddResourceData(const String& request_id,
const char* data,
- size_t data_length);
+ uint64_t data_length);
void MaybeDecodeDataToContent(const String& request_id);
void AddResource(const String& request_id, Resource*);
ResourceData const* Data(const String& request_id);
@@ -247,9 +251,9 @@ class NetworkResourcesData final
private:
ResourceData* ResourceDataForRequestId(const String& request_id) const;
void EnsureNoDataForRequestId(const String& request_id);
- bool EnsureFreeSpace(size_t);
+ bool EnsureFreeSpace(uint64_t);
ResourceData* PrepareToAddResourceData(const String& request_id,
- size_t data_length);
+ uint64_t data_length);
void MaybeAddResourceData(const String& request_id,
scoped_refptr<const SharedBuffer>);
diff --git a/chromium/third_party/blink/renderer/core/inspector/resolve_node.cc b/chromium/third_party/blink/renderer/core/inspector/resolve_node.cc
index ba241494949..ad273cda4b6 100644
--- a/chromium/third_party/blink/renderer/core/inspector/resolve_node.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/resolve_node.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
#include "third_party/blink/renderer/core/inspector/v8_inspector_string.h"
namespace blink {
@@ -25,7 +26,8 @@ v8::Local<v8::Value> NodeV8Value(v8::Local<v8::Context> context, Node* node) {
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject> ResolveNode(
v8_inspector::V8InspectorSession* v8_session,
Node* node,
- const String& object_group) {
+ const String& object_group,
+ protocol::Maybe<int> v8_execution_context_id) {
if (!node)
return nullptr;
@@ -35,14 +37,26 @@ std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject> ResolveNode(
if (!frame)
return nullptr;
- ScriptState* script_state = ToScriptStateForMainWorld(frame);
- if (!script_state)
- return nullptr;
-
- ScriptState::Scope scope(script_state);
- return v8_session->wrapObject(
- script_state->GetContext(), NodeV8Value(script_state->GetContext(), node),
- ToV8InspectorStringView(object_group), false /* generatePreview */);
+ v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Context> context;
+ if (v8_execution_context_id.isJust()) {
+ if (!MainThreadDebugger::Instance()
+ ->GetV8Inspector()
+ ->contextById(v8_execution_context_id.fromJust())
+ .ToLocal(&context)) {
+ return nullptr;
+ }
+ } else {
+ ScriptState* script_state = ToScriptStateForMainWorld(frame);
+ if (!script_state)
+ return nullptr;
+ context = script_state->GetContext();
+ }
+ v8::Context::Scope scope(context);
+ return v8_session->wrapObject(context, NodeV8Value(context, node),
+ ToV8InspectorStringView(object_group),
+ false /* generatePreview */);
}
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject>
diff --git a/chromium/third_party/blink/renderer/core/inspector/resolve_node.h b/chromium/third_party/blink/renderer/core/inspector/resolve_node.h
index 4a9d1b10776..b99c628b573 100644
--- a/chromium/third_party/blink/renderer/core/inspector/resolve_node.h
+++ b/chromium/third_party/blink/renderer/core/inspector/resolve_node.h
@@ -21,7 +21,8 @@ v8::Local<v8::Value> NodeV8Value(v8::Local<v8::Context>, Node*);
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject> ResolveNode(
v8_inspector::V8InspectorSession*,
Node*,
- const String& object_group);
+ const String& object_group,
+ protocol::Maybe<int> v8_execution_context_id);
std::unique_ptr<v8_inspector::protocol::Runtime::API::RemoteObject>
NullRemoteObject(v8_inspector::V8InspectorSession* v8_session,
diff --git a/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc b/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc
index 28050e24d87..6d89e11e409 100644
--- a/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/inspector/thread_debugger.h"
#include <memory>
+
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
@@ -12,7 +13,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_dom_token_list.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_event.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_info.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_html_all_collection.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_html_collection.h"
@@ -373,19 +374,14 @@ void ThreadDebugger::SetMonitorEventsCallback(
if (!event_target)
return;
Vector<String> types = NormalizeEventTypes(info);
- EventListener* event_listener = V8EventListenerHelper::GetEventListener(
- ScriptState::Current(info.GetIsolate()),
- v8::Local<v8::Function>::Cast(info.Data()),
- enabled ? kListenerFindOrCreate : kListenerFindOnly);
- if (!event_listener)
- return;
+ DCHECK(!info.Data().IsEmpty() && info.Data()->IsFunction());
+ V8EventListener* event_listener =
+ V8EventListener::Create(info.Data().As<v8::Function>());
for (wtf_size_t i = 0; i < types.size(); ++i) {
if (enabled)
- event_target->addEventListener(AtomicString(types[i]), event_listener,
- false);
+ event_target->addEventListener(AtomicString(types[i]), event_listener);
else
- event_target->removeEventListener(AtomicString(types[i]), event_listener,
- false);
+ event_target->removeEventListener(AtomicString(types[i]), event_listener);
}
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/worker_devtools_params.h b/chromium/third_party/blink/renderer/core/inspector/worker_devtools_params.h
index f42f46550d6..f80f40214a5 100644
--- a/chromium/third_party/blink/renderer/core/inspector/worker_devtools_params.h
+++ b/chromium/third_party/blink/renderer/core/inspector/worker_devtools_params.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_WORKER_DEVTOOLS_PARAMS_H_
#include "base/unguessable_token.h"
-#include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc b/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
index 486bb38c5b6..441e05e761e 100644
--- a/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
@@ -71,7 +71,7 @@ WorkerInspectorController::WorkerInspectorController(
: debugger_(debugger),
thread_(thread),
inspected_frames_(nullptr),
- probe_sink_(new CoreProbeSink()) {
+ probe_sink_(MakeGarbageCollected<CoreProbeSink>()) {
probe_sink_->addInspectorTraceEvents(
MakeGarbageCollected<InspectorTraceEvents>());
if (auto* scope = DynamicTo<WorkerGlobalScope>(thread->GlobalScope())) {
@@ -85,9 +85,9 @@ WorkerInspectorController::WorkerInspectorController(
if (!parent_devtools_token_.is_empty() && io_task_runner) {
// There may be no io task runner in unit tests.
wait_for_debugger_ = devtools_params->wait_for_debugger;
- agent_ = new DevToolsAgent(this, inspected_frames_.Get(), probe_sink_.Get(),
- std::move(inspector_task_runner),
- std::move(io_task_runner));
+ agent_ = MakeGarbageCollected<DevToolsAgent>(
+ this, inspected_frames_.Get(), probe_sink_.Get(),
+ std::move(inspector_task_runner), std::move(io_task_runner));
agent_->BindRequest(std::move(devtools_params->agent_host_ptr_info),
std::move(devtools_params->agent_request),
thread->GetTaskRunner(TaskType::kInternalInspector));
@@ -110,7 +110,7 @@ void WorkerInspectorController::AttachSession(DevToolsSession* session,
session->Append(MakeGarbageCollected<InspectorLogAgent>(
thread_->GetConsoleMessageStorage(), nullptr, session->V8Session()));
if (auto* scope = DynamicTo<WorkerGlobalScope>(thread_->GlobalScope())) {
- DCHECK(scope->EnsureFetcher());
+ scope->EnsureFetcher();
session->Append(MakeGarbageCollected<InspectorNetworkAgent>(
inspected_frames_.Get(), scope, session->V8Session()));
session->Append(MakeGarbageCollected<InspectorEmulationAgent>(nullptr));
diff --git a/chromium/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc b/chromium/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
index 32c028f3380..7462f7f4d2d 100644
--- a/chromium/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
@@ -171,7 +171,8 @@ void WorkerThreadDebugger::runMessageLoopOnPause(int context_group_id) {
WorkerThread* thread = worker_threads_.at(context_group_id);
DCHECK(!thread->GlobalScope()->IsClosing());
thread->GetWorkerInspectorController()->FlushProtocolNotifications();
- thread->GlobalScope()->PauseScheduledTasks();
+ thread->GlobalScope()->PauseScheduledTasks(PauseState::kPaused);
+ auto pause_handle = thread->GetScheduler()->Pause();
if (!nested_runner_)
nested_runner_ = Platform::Current()->CreateNestedMessageLoopRunner();
nested_runner_->Run();
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
index 8b392c7fd10..b1cebeee477 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -73,8 +73,9 @@ void IntersectionObservation::Compute(unsigned flags) {
root_margin[1] = observer_->RightMargin();
root_margin[2] = observer_->BottomMargin();
root_margin[3] = observer_->LeftMargin();
- bool report_root_bounds =
- (flags & kReportImplicitRootBounds) || !observer_->RootIsImplicit();
+ bool report_root_bounds = observer_->AlwaysReportRootBounds() ||
+ (flags & kReportImplicitRootBounds) ||
+ !observer_->RootIsImplicit();
IntersectionGeometry geometry(observer_->root(), *Target(), root_margin,
report_root_bounds);
geometry.ComputeGeometry();
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
index e933ead7541..8c56c625a0f 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
@@ -177,7 +177,7 @@ IntersectionObserver* IntersectionObserver::Create(
return MakeGarbageCollected<IntersectionObserver>(
delegate, root, root_margin, thresholds, kFractionOfTarget, delay,
- track_visibility);
+ track_visibility, false);
}
IntersectionObserver* IntersectionObserver::Create(
@@ -199,12 +199,14 @@ IntersectionObserver* IntersectionObserver::Create(
ThresholdInterpretation semantics,
DOMHighResTimeStamp delay,
bool track_visibility,
+ bool always_report_root_bounds,
ExceptionState& exception_state) {
IntersectionObserverDelegateImpl* intersection_observer_delegate =
- new IntersectionObserverDelegateImpl(document, std::move(callback));
+ MakeGarbageCollected<IntersectionObserverDelegateImpl>(
+ document, std::move(callback));
return MakeGarbageCollected<IntersectionObserver>(
*intersection_observer_delegate, nullptr, root_margin, thresholds,
- semantics, delay, track_visibility);
+ semantics, delay, track_visibility, always_report_root_bounds);
}
IntersectionObserver::IntersectionObserver(
@@ -214,7 +216,8 @@ IntersectionObserver::IntersectionObserver(
const Vector<float>& thresholds,
ThresholdInterpretation semantics,
DOMHighResTimeStamp delay,
- bool track_visibility)
+ bool track_visibility,
+ bool always_report_root_bounds)
: ContextClient(delegate.GetExecutionContext()),
delegate_(&delegate),
root_(root),
@@ -226,7 +229,8 @@ IntersectionObserver::IntersectionObserver(
left_margin_(kFixed),
root_is_implicit_(root ? 0 : 1),
track_visibility_(track_visibility ? 1 : 0),
- track_fraction_of_root_(semantics == kFractionOfRoot) {
+ track_fraction_of_root_(semantics == kFractionOfRoot),
+ always_report_root_bounds_(always_report_root_bounds ? 1 : 0) {
switch (root_margin.size()) {
case 0:
break;
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
index 082a306ec26..128eb703164 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
@@ -81,6 +81,7 @@ class CORE_EXPORT IntersectionObserver final
ThresholdInterpretation semantics = kFractionOfTarget,
DOMHighResTimeStamp delay = 0,
bool track_visbility = false,
+ bool always_report_root_bounds = false,
ExceptionState& = ASSERT_NO_EXCEPTION);
static void ResumeSuspendedObservers();
@@ -91,7 +92,8 @@ class CORE_EXPORT IntersectionObserver final
const Vector<float>& thresholds,
ThresholdInterpretation semantics,
DOMHighResTimeStamp delay,
- bool track_visibility);
+ bool track_visibility,
+ bool always_report_root_bounds);
// API methods.
void observe(Element*, ExceptionState& = ASSERT_NO_EXCEPTION);
@@ -114,6 +116,8 @@ class CORE_EXPORT IntersectionObserver final
// root just because root_ is null. Hence root_is_implicit_.
bool RootIsImplicit() const { return root_is_implicit_; }
+ bool AlwaysReportRootBounds() const { return always_report_root_bounds_; }
+
DOMHighResTimeStamp GetTimeStamp() const;
DOMHighResTimeStamp GetEffectiveDelay() const;
const Length& TopMargin() const { return top_margin_; }
@@ -151,6 +155,7 @@ class CORE_EXPORT IntersectionObserver final
unsigned root_is_implicit_ : 1;
unsigned track_visibility_ : 1;
unsigned track_fraction_of_root_ : 1;
+ unsigned always_report_root_bounds_ : 1;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc
index c8610b5afae..7982aecbee0 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc
@@ -18,15 +18,12 @@ namespace blink {
IntersectionObserverController* IntersectionObserverController::Create(
Document* document) {
- IntersectionObserverController* result =
- MakeGarbageCollected<IntersectionObserverController>(document);
- result->PauseIfNeeded();
- return result;
+ return MakeGarbageCollected<IntersectionObserverController>(document);
}
IntersectionObserverController::IntersectionObserverController(
Document* document)
- : PausableObject(document), callback_fired_while_suspended_(false) {}
+ : ContextClient(document) {}
IntersectionObserverController::~IntersectionObserverController() = default;
@@ -50,15 +47,6 @@ void IntersectionObserverController::ScheduleIntersectionObserverForDelivery(
PostTaskToDeliverObservations();
}
-void IntersectionObserverController::Unpause() {
- // If the callback fired while DOM objects were suspended, notifications might
- // be late, so deliver them right away (rather than waiting to fire again).
- if (callback_fired_while_suspended_) {
- callback_fired_while_suspended_ = false;
- PostTaskToDeliverObservations();
- }
-}
-
void IntersectionObserverController::DeliverIntersectionObservations() {
ExecutionContext* context = GetExecutionContext();
if (!context) {
@@ -68,10 +56,6 @@ void IntersectionObserverController::DeliverIntersectionObservations() {
// TODO(yukishiino): Remove this CHECK once https://crbug.com/809784 gets
// resolved.
CHECK(!context->IsContextDestroyed());
- if (context->IsContextPaused()) {
- callback_fired_while_suspended_ = true;
- return;
- }
pending_intersection_observers_.swap(intersection_observers_being_invoked_);
for (auto& observer : intersection_observers_being_invoked_)
observer->Deliver();
@@ -104,7 +88,7 @@ void IntersectionObserverController::Trace(blink::Visitor* visitor) {
visitor->Trace(tracked_observation_targets_);
visitor->Trace(pending_intersection_observers_);
visitor->Trace(intersection_observers_being_invoked_);
- PausableObject::Trace(visitor);
+ ContextClient::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h
index 9bafb39ba4b..997449c97c4 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_CONTROLLER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_CONTROLLER_H_
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
@@ -21,7 +21,7 @@ class Document;
class IntersectionObserverController
: public GarbageCollectedFinalized<IntersectionObserverController>,
- public PausableObject,
+ public ContextClient,
public NameClient {
USING_GARBAGE_COLLECTED_MIXIN(IntersectionObserverController);
@@ -29,9 +29,7 @@ class IntersectionObserverController
static IntersectionObserverController* Create(Document*);
explicit IntersectionObserverController(Document*);
- ~IntersectionObserverController() override;
-
- void Unpause() override;
+ virtual ~IntersectionObserverController();
void ScheduleIntersectionObserverForDelivery(IntersectionObserver&);
void DeliverIntersectionObservations();
@@ -59,8 +57,6 @@ class IntersectionObserverController
// get supported by either of wrapper-tracing or unified GC.
HeapHashSet<TraceWrapperMember<IntersectionObserver>>
intersection_observers_being_invoked_;
-
- bool callback_fired_while_suspended_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
index ec2a522d617..295aeed752e 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
@@ -82,7 +82,7 @@ TEST_F(IntersectionObserverTest, ObserveSchedulesFrame) {
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -119,7 +119,7 @@ TEST_F(IntersectionObserverTest, NotificationSentWhenRootRemoved) {
observer_init->setRoot(root);
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -173,7 +173,7 @@ TEST_F(IntersectionObserverTest, ReportsFractionOfTargetOrRoot) {
MakeGarbageCollected<IntersectionObserver>(
*target_observer_delegate, nullptr, Vector<Length>(),
Vector<float>{kExpectedFractionOfTarget / 2},
- IntersectionObserver::kFractionOfTarget, 0, false);
+ IntersectionObserver::kFractionOfTarget, 0, false, false);
DummyExceptionStateForTesting exception_state;
target_observer->observe(target, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -184,7 +184,7 @@ TEST_F(IntersectionObserverTest, ReportsFractionOfTargetOrRoot) {
MakeGarbageCollected<IntersectionObserver>(
*root_observer_delegate, nullptr, Vector<Length>(),
Vector<float>{kExpectedFractionOfRoot / 2},
- IntersectionObserver::kFractionOfRoot, 0, false);
+ IntersectionObserver::kFractionOfRoot, 0, false, false);
root_observer->observe(target, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -206,7 +206,7 @@ TEST_F(IntersectionObserverTest, ReportsFractionOfTargetOrRoot) {
}
TEST_F(IntersectionObserverTest, ResumePostsTask) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -218,7 +218,7 @@ TEST_F(IntersectionObserverTest, ResumePostsTask) {
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -243,7 +243,7 @@ TEST_F(IntersectionObserverTest, ResumePostsTask) {
// When a document is suspended, beginFrame() will generate a notification,
// but it will not be delivered. The notification will, however, be
// available via takeRecords();
- GetDocument().PauseScheduledTasks();
+ WebView().GetPage()->SetPaused(true);
GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 0),
kProgrammaticScroll);
Compositor().BeginFrame();
@@ -259,14 +259,14 @@ TEST_F(IntersectionObserverTest, ResumePostsTask) {
Compositor().BeginFrame();
test::RunPendingTasks();
EXPECT_EQ(observer_delegate->CallCount(), 2);
- GetDocument().UnpauseScheduledTasks();
+ WebView().GetPage()->SetPaused(false);
EXPECT_EQ(observer_delegate->CallCount(), 2);
test::RunPendingTasks();
EXPECT_EQ(observer_delegate->CallCount(), 3);
}
TEST_F(IntersectionObserverTest, HitTestAfterMutation) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -278,7 +278,7 @@ TEST_F(IntersectionObserverTest, HitTestAfterMutation) {
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -313,7 +313,7 @@ TEST_F(IntersectionObserverTest, HitTestAfterMutation) {
}
TEST_F(IntersectionObserverTest, DisconnectClearsNotifications) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -325,7 +325,7 @@ TEST_F(IntersectionObserverTest, DisconnectClearsNotifications) {
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -350,7 +350,7 @@ TEST_F(IntersectionObserverTest, DisconnectClearsNotifications) {
TEST_F(IntersectionObserverTest, RootIntersectionWithForceZeroLayoutHeight) {
WebView().GetSettings()->SetForceZeroLayoutHeight(true);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -375,7 +375,7 @@ TEST_F(IntersectionObserverTest, RootIntersectionWithForceZeroLayoutHeight) {
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -410,7 +410,7 @@ TEST_F(IntersectionObserverV2Test, TrackVisibilityInit) {
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -439,7 +439,7 @@ TEST_F(IntersectionObserverV2Test, TrackVisibilityInit) {
}
TEST_F(IntersectionObserverV2Test, BasicOcclusion) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -460,7 +460,7 @@ TEST_F(IntersectionObserverV2Test, BasicOcclusion) {
observer_init->setDelay(100);
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -498,7 +498,7 @@ TEST_F(IntersectionObserverV2Test, BasicOcclusion) {
}
TEST_F(IntersectionObserverV2Test, BasicOpacity) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -518,7 +518,7 @@ TEST_F(IntersectionObserverV2Test, BasicOpacity) {
observer_init->setDelay(100);
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -547,7 +547,7 @@ TEST_F(IntersectionObserverV2Test, BasicOpacity) {
}
TEST_F(IntersectionObserverV2Test, BasicTransform) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
@@ -567,7 +567,7 @@ TEST_F(IntersectionObserverV2Test, BasicTransform) {
observer_init->setDelay(100);
DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate =
- new TestIntersectionObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException());
diff --git a/chromium/third_party/blink/renderer/core/invisible_dom/BUILD.gn b/chromium/third_party/blink/renderer/core/invisible_dom/BUILD.gn
index 683b133e552..724181af307 100644
--- a/chromium/third_party/blink/renderer/core/invisible_dom/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/invisible_dom/BUILD.gn
@@ -9,5 +9,7 @@ blink_core_sources("invisible_dom") {
"activate_invisible_event.cc",
"activate_invisible_event.h",
"activate_invisible_event.idl",
+ "invisible_dom.cc",
+ "invisible_dom.h",
]
}
diff --git a/chromium/third_party/blink/renderer/core/invisible_dom/activate_invisible_event.h b/chromium/third_party/blink/renderer/core/invisible_dom/activate_invisible_event.h
index 050e2663f1b..6a978db01bf 100644
--- a/chromium/third_party/blink/renderer/core/invisible_dom/activate_invisible_event.h
+++ b/chromium/third_party/blink/renderer/core/invisible_dom/activate_invisible_event.h
@@ -16,9 +16,11 @@ class ActivateInvisibleEvent : public Event {
public:
static ActivateInvisibleEvent* Create(Element* activated_element) {
- return new ActivateInvisibleEvent(activated_element);
+ return MakeGarbageCollected<ActivateInvisibleEvent>(activated_element);
}
+ explicit ActivateInvisibleEvent(Element* activated_element);
+
Element* activatedElement() const { return activated_element_.Get(); }
void SetActivatedElement(Element* activated_element) {
@@ -31,8 +33,6 @@ class ActivateInvisibleEvent : public Event {
void Trace(Visitor*) override;
private:
- explicit ActivateInvisibleEvent(Element* activated_element);
-
Member<Element> activated_element_;
};
diff --git a/chromium/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc b/chromium/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc
new file mode 100644
index 00000000000..56771c24304
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc
@@ -0,0 +1,196 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/editing/finder/text_finder.h"
+#include "third_party/blink/renderer/core/frame/find_in_page.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+class InvisibleFindInPageClient : public mojom::blink::FindInPageClient {
+ public:
+ InvisibleFindInPageClient()
+ : binding_(this),
+ active_index_(-1),
+ count_(-1),
+ find_results_are_ready_(false) {}
+
+ ~InvisibleFindInPageClient() override = default;
+
+ void SetFrame(WebLocalFrameImpl* frame) {
+ mojom::blink::FindInPageClientPtr client;
+ binding_.Bind(MakeRequest(&client));
+ frame->GetFindInPage()->SetClient(std::move(client));
+ }
+
+ void SetNumberOfMatches(
+ int request_id,
+ unsigned int current_number_of_matches,
+ mojom::blink::FindMatchUpdateType final_update) final {
+ count_ = current_number_of_matches;
+ find_results_are_ready_ =
+ (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
+ }
+
+ void SetActiveMatch(int request_id,
+ const WebRect& active_match_rect,
+ int active_match_ordinal,
+ mojom::blink::FindMatchUpdateType final_update) final {
+ active_index_ = active_match_ordinal;
+ find_results_are_ready_ =
+ (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
+ }
+
+ bool FindResultsAreReady() const { return find_results_are_ready_; }
+ int Count() const { return count_; }
+ int ActiveIndex() const { return active_index_; }
+
+ void Reset() {
+ find_results_are_ready_ = false;
+ count_ = -1;
+ active_index_ = -1;
+ }
+
+ private:
+ mojo::Binding<mojom::blink::FindInPageClient> binding_;
+ int active_index_;
+ int count_;
+ bool find_results_are_ready_;
+};
+
+class FindInvisibleTest : public ::testing::WithParamInterface<bool>,
+ public testing::Test,
+ private ScopedLayoutNGForTest {
+ protected:
+ FindInvisibleTest() : ScopedLayoutNGForTest(GetParam()) {}
+
+ bool LayoutNGEnabled() const { return GetParam(); }
+
+ void SetUp() override { web_view_helper_.Initialize(); }
+
+ void TearDown() override { web_view_helper_.Reset(); }
+
+ Document& GetDocument() {
+ return *static_cast<Document*>(
+ web_view_helper_.LocalMainFrame()->GetDocument());
+ }
+
+ FindInPage* GetFindInPage() {
+ return web_view_helper_.LocalMainFrame()->GetFindInPage();
+ }
+
+ WebLocalFrameImpl* LocalMainFrame() {
+ return web_view_helper_.LocalMainFrame();
+ }
+
+ void UpdateAllLifecyclePhasesForTest() {
+ GetDocument().View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kTest);
+ }
+
+ void SetInnerHTML(const char* content) {
+ GetDocument().documentElement()->SetInnerHTMLFromString(
+ String::FromUTF8(content));
+ UpdateAllLifecyclePhasesForTest();
+ }
+
+ void ResizeAndFocus() {
+ web_view_helper_.Resize(WebSize(640, 480));
+ web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
+ test::RunPendingTasks();
+ }
+
+ private:
+ frame_test_helpers::WebViewHelper web_view_helper_;
+};
+
+INSTANTIATE_TEST_CASE_P(All, FindInvisibleTest, ::testing::Bool());
+
+TEST_P(FindInvisibleTest, FindingInvisibleTextHasCorrectCount) {
+ ResizeAndFocus();
+ SetInnerHTML(
+ "<div invisible>"
+ " foo1"
+ " <div>foo2</div>"
+ " foo3"
+ "</div>"
+ "<div>"
+ " bar"
+ " <span invisible>foo4</span>"
+ "</div>");
+ auto* find_in_page = GetFindInPage();
+
+ InvisibleFindInPageClient client;
+ client.SetFrame(LocalMainFrame());
+ auto find_options = mojom::blink::FindOptions::New();
+ find_options->run_synchronously_for_testing = true;
+ find_options->find_next = false;
+ find_options->forward = true;
+
+ int current_id = 0;
+ find_in_page->Find(current_id++, "foo", find_options->Clone());
+ EXPECT_FALSE(client.FindResultsAreReady());
+ test::RunPendingTasks();
+ EXPECT_TRUE(client.FindResultsAreReady());
+ EXPECT_EQ(4, client.Count());
+ // Active match is not supported yet for invisible elements.
+ EXPECT_EQ(-1, client.ActiveIndex());
+}
+
+TEST_P(FindInvisibleTest, FindingInvisibleTextHasIncorrectActiveMatch) {
+ ResizeAndFocus();
+ SetInnerHTML(
+ "<div id='div'>1foo<div invisible>22foo</div>333foo</div>"
+ "<div invisible><input id='input' value='4444foo'></div>55555foo");
+ auto* find_in_page = GetFindInPage();
+
+ InvisibleFindInPageClient client;
+ client.SetFrame(LocalMainFrame());
+ auto find_options = mojom::blink::FindOptions::New();
+ find_options->run_synchronously_for_testing = true;
+ find_options->find_next = false;
+ find_options->forward = true;
+
+ int current_id = 0;
+ find_in_page->Find(current_id++, "foo", find_options->Clone());
+ test::RunPendingTasks();
+ find_in_page->StopFinding(
+ mojom::blink::StopFindAction::kStopFindActionKeepSelection);
+ EXPECT_TRUE(client.FindResultsAreReady());
+ EXPECT_EQ(5, client.Count());
+
+ // Finding next focuses on "1foo".
+ WebRange range = LocalMainFrame()->SelectionRange();
+ ASSERT_FALSE(range.IsNull());
+ EXPECT_EQ(1, range.StartOffset());
+ EXPECT_EQ(4, range.EndOffset());
+
+ find_options->find_next = true;
+ find_in_page->Find(current_id++, "foo", find_options->Clone());
+ test::RunPendingTasks();
+ find_in_page->StopFinding(
+ mojom::blink::StopFindAction::kStopFindActionKeepSelection);
+ // Finding next focuses on "333foo", skipping "22foo".
+ range = LocalMainFrame()->SelectionRange();
+ ASSERT_FALSE(range.IsNull());
+ EXPECT_EQ(3, range.StartOffset());
+ EXPECT_EQ(6, range.EndOffset());
+
+ find_options->find_next = true;
+ find_in_page->Find(current_id++, "foo", find_options->Clone());
+ test::RunPendingTasks();
+ find_in_page->StopFinding(
+ mojom::blink::StopFindAction::kStopFindActionKeepSelection);
+ // Finding next focuses on "55555foo", skipping "4444foo".
+ range = LocalMainFrame()->SelectionRange();
+ ASSERT_FALSE(range.IsNull());
+ EXPECT_EQ(5, range.StartOffset());
+ EXPECT_EQ(8, range.EndOffset());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc b/chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc
new file mode 100644
index 00000000000..920e4fc4152
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/invisible_dom/invisible_dom.h"
+
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+
+namespace blink {
+bool InvisibleDOM::IsInsideInvisibleSubtree(const Node& node) {
+ for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
+ if (ancestor.IsElementNode() &&
+ ToElement(ancestor).HasInvisibleAttribute()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Element* InvisibleDOM::InvisibleRoot(const Node& node) {
+ Element* root = nullptr;
+ for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
+ if (ancestor.IsElementNode() &&
+ ToElement(ancestor).HasInvisibleAttribute()) {
+ root = &ToElement(ancestor);
+ }
+ }
+ return root;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.h b/chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.h
new file mode 100644
index 00000000000..b75f2b4e282
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/invisible_dom/invisible_dom.h
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INVISIBLE_DOM_INVISIBLE_DOM_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INVISIBLE_DOM_INVISIBLE_DOM_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+class Node;
+class Element;
+
+class CORE_EXPORT InvisibleDOM {
+ STATIC_ONLY(InvisibleDOM);
+
+ public:
+ static bool IsInsideInvisibleSubtree(const Node& node);
+
+ // Highest inclusive ancestor that has the invisible attribute.
+ static Element* InvisibleRoot(const Node&);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INVISIBLE_DOM_INVISIBLE_DOM_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/BUILD.gn b/chromium/third_party/blink/renderer/core/layout/BUILD.gn
index c3d109daed6..9314c7e66fd 100644
--- a/chromium/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/layout/BUILD.gn
@@ -335,6 +335,8 @@ blink_core_sources("layout") {
"ng/inline/ng_baseline.h",
"ng/inline/ng_bidi_paragraph.cc",
"ng/inline/ng_bidi_paragraph.h",
+ "ng/inline/ng_caret_navigator.cc",
+ "ng/inline/ng_caret_navigator.h",
"ng/inline/ng_caret_position.cc",
"ng/inline/ng_caret_position.h",
"ng/inline/ng_caret_rect.cc",
@@ -351,6 +353,8 @@ blink_core_sources("layout") {
"ng/inline/ng_inline_item.h",
"ng/inline/ng_inline_item_result.cc",
"ng/inline/ng_inline_item_result.h",
+ "ng/inline/ng_inline_item_segment.cc",
+ "ng/inline/ng_inline_item_segment.h",
"ng/inline/ng_inline_items.h",
"ng/inline/ng_inline_items_builder.cc",
"ng/inline/ng_inline_items_builder.h",
@@ -472,7 +476,6 @@ blink_core_sources("layout") {
"ng/ng_text_decoration_offset.cc",
"ng/ng_text_decoration_offset.h",
"ng/ng_unpositioned_float.h",
- "ng/ng_unpositioned_float_vector.h",
"order_iterator.cc",
"order_iterator.h",
"overflow_model.h",
diff --git a/chromium/third_party/blink/renderer/core/layout/OWNERS b/chromium/third_party/blink/renderer/core/layout/OWNERS
index 1d33e93a31b..417ecd8eef3 100644
--- a/chromium/third_party/blink/renderer/core/layout/OWNERS
+++ b/chromium/third_party/blink/renderer/core/layout/OWNERS
@@ -1,3 +1,4 @@
+atotic@chromium.org
cbiesinger@chromium.org
chrishtr@chromium.org
eae@chromium.org
@@ -9,6 +10,7 @@ skobes@chromium.org
svillar@igalia.com
tkent@chromium.org
wangxianzhu@chromium.org
+xiaochengh@chromium.org
# TEAM: layout-dev@chromium.org
# COMPONENT: Blink>Layout
diff --git a/chromium/third_party/blink/renderer/core/layout/api/line_layout_box.h b/chromium/third_party/blink/renderer/core/layout/api/line_layout_box.h
index d288801aae3..4a8fef635d5 100644
--- a/chromium/third_party/blink/renderer/core/layout/api/line_layout_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/api/line_layout_box.h
@@ -74,7 +74,8 @@ class LineLayoutBox : public LineLayoutBoxModel {
ToBox()->Move(width, height);
}
- bool HasOverflowModel() const { return ToBox()->HasOverflowModel(); }
+ bool HasLayoutOverflow() const { return ToBox()->HasLayoutOverflow(); }
+ bool HasVisualOverflow() const { return ToBox()->HasVisualOverflow(); }
LayoutRect LogicalVisualOverflowRectForPropagation() const {
return ToBox()->LogicalVisualOverflowRectForPropagation();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc b/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
index d591ee54a01..223e720150d 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
@@ -120,9 +120,10 @@ bool CSSLayoutDefinition::Instance::Layout(
fixed_block_size = computed_values.extent_;
}
- CustomLayoutConstraints* constraints = new CustomLayoutConstraints(
- layout_custom.LogicalWidth(), fixed_block_size,
- layout_custom.GetConstraintData(), isolate);
+ CustomLayoutConstraints* constraints =
+ MakeGarbageCollected<CustomLayoutConstraints>(
+ layout_custom.LogicalWidth(), fixed_block_size,
+ layout_custom.GetConstraintData(), isolate);
// TODO(ikilpatrick): Instead of creating a new style_map each time here,
// store on LayoutCustom, and update when the style changes.
@@ -327,9 +328,9 @@ void CSSLayoutDefinition::Instance::Trace(blink::Visitor* visitor) {
}
void CSSLayoutDefinition::Trace(Visitor* visitor) {
- visitor->Trace(constructor_.Cast<v8::Value>());
- visitor->Trace(intrinsic_sizes_.Cast<v8::Value>());
- visitor->Trace(layout_.Cast<v8::Value>());
+ visitor->Trace(constructor_);
+ visitor->Trace(intrinsic_sizes_);
+ visitor->Trace(layout_);
visitor->Trace(script_state_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.cc b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.cc
index a992eaab899..b34bd33d017 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.cc
@@ -41,8 +41,8 @@ CustomLayoutFragmentRequest* CustomLayoutChild::layoutNextFragment(
return nullptr;
}
- return new CustomLayoutFragmentRequest(this, options,
- std::move(constraint_data));
+ return MakeGarbageCollected<CustomLayoutFragmentRequest>(
+ this, options, std::move(constraint_data));
}
void CustomLayoutChild::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
index fd45906b1c4..d7b2e8542ea 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
@@ -118,8 +118,8 @@ CustomLayoutFragment* CustomLayoutFragmentRequest::PerformLayout(
LayoutUnit fragment_block_size =
is_parallel_writing_mode ? box->LogicalHeight() : box->LogicalWidth();
- return new CustomLayoutFragment(this, fragment_inline_size,
- fragment_block_size, isolate);
+ return MakeGarbageCollected<CustomLayoutFragment>(
+ this, fragment_inline_size, fragment_block_size, isolate);
}
LayoutBox* CustomLayoutFragmentRequest::GetLayoutBox() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc b/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc
index 5c62e93ddfe..611c30a0573 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc
@@ -266,7 +266,7 @@ bool LayoutCustom::PerformLayout(bool relayout_children,
relayout_children = true;
LayoutPositionedObjects(relayout_children || IsDocumentElement());
- ComputeOverflow(old_client_after_edge);
+ ComputeLayoutOverflow(old_client_after_edge);
}
UpdateAfterLayout();
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc
index 89a5b15d86f..bd07119b991 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc
@@ -41,7 +41,8 @@ LayoutWorkletGlobalScopeProxy::LayoutWorkletGlobalScopeProxy(
worker_clients, frame->Client()->CreateWorkerContentSettingsClient());
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled, document->UserAgent(),
frame->Client()->CreateWorkerFetchContext(),
document->GetContentSecurityPolicy()->Headers(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
diff --git a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index c9b7f5e5c22..d9919e885dc 100644
--- a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -146,7 +146,6 @@ void FlexItem::ComputeStretchedSize() {
// constructor. Then use cross_axis_min_max.ClampSizeToMinAndMax instead of
// relying on legacy in this method.
DCHECK_EQ(Alignment(), ItemPosition::kStretch);
- LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent());
if (MainAxisIsInlineAxis() && box->StyleRef().LogicalHeight().IsAuto()) {
LayoutUnit stretched_logical_height =
std::max(box->BorderAndPaddingLogicalHeight(),
@@ -155,11 +154,14 @@ void FlexItem::ComputeStretchedSize() {
stretched_logical_height, box->IntrinsicContentLogicalHeight());
} else if (!MainAxisIsInlineAxis() &&
box->StyleRef().LogicalWidth().IsAuto()) {
+ // This doesn't work in NG because CrossAxisContentExtent() isn't yet
+ // implemented there.
+ if (box->Parent()->IsLayoutNGFlexibleBox())
+ return;
LayoutUnit child_width =
(Line()->cross_axis_extent - CrossAxisMarginExtent())
.ClampNegativeToZero();
- // This probably doesn't work in NG because flexbox might not yet know its
- // CrossAxisContentExtent()
+ LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent());
cross_axis_size = box->ConstrainLogicalWidthByMinMax(
child_width, flexbox->CrossAxisContentExtent(), flexbox);
}
@@ -360,7 +362,8 @@ void FlexLine::ComputeLineItemsPosition(LayoutUnit main_axis_offset,
LayoutUnit child_main_extent = flex_item.FlexedBorderBoxSize();
// In an RTL column situation, this will apply the margin-right/margin-end
- // on the left. This will be fixed later in flipForRightToLeftColumn.
+ // on the left. This will be fixed later in
+ // LayoutFlexibleBox::FlipForRightToLeftColumn.
flex_item.desired_location = LayoutPoint(
should_flip_main_axis
? container_logical_width - main_axis_offset - child_main_extent
@@ -470,14 +473,21 @@ FlexLayoutAlgorithm::ContentAlignmentNormalBehavior() {
bool FlexLayoutAlgorithm::ShouldApplyMinSizeAutoForChild(
const LayoutBox& child) const {
- // TODO(cbiesinger): For now, we do not handle min-height: auto for nested
- // column flexboxes. See crbug.com/596743
// css-flexbox section 4.5
- Length min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
- : child.StyleRef().MinHeight();
- return min.IsAuto() && !child.ShouldApplySizeContainment() &&
- MainAxisOverflowForChild(child) == EOverflow::kVisible &&
- !(IsColumnFlow() && child.IsFlexibleBox());
+ const Length& min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
+ : child.StyleRef().MinHeight();
+ if (!min.IsAuto())
+ return false;
+
+ // TODO(crbug.com/927066): We calculate an incorrect intrinsic logical height
+ // when percentages are involved, so for now don't apply min-height: auto
+ // in such cases.
+ if (IsColumnFlow() && child.IsFlexibleBox() &&
+ ToLayoutBlock(child).HasPercentHeightDescendants())
+ return false;
+
+ return !child.ShouldApplySizeContainment() &&
+ MainAxisOverflowForChild(child) == EOverflow::kVisible;
}
TransformedWritingMode FlexLayoutAlgorithm::GetTransformedWritingMode() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index 6e0c48e7338..ffb72399d35 100644
--- a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -67,6 +67,7 @@ typedef Vector<FlexItem, 8> FlexItemVector;
class FlexItem {
public:
// flex_base_content_size includes scrollbar width but not border or padding.
+ // min_max_sizes is the min and max size in the main axis direction.
FlexItem(LayoutBox*,
LayoutUnit flex_base_content_size,
MinMaxSize min_max_sizes,
@@ -135,8 +136,7 @@ class FlexItem {
bool frozen;
- // TODO(dgrogan): Change this to NGBlockNode when all items are blockified.
- NGLayoutInputNode ng_input_node;
+ NGBlockNode ng_input_node;
scoped_refptr<NGLayoutResult> layout_result;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/floating_objects.cc b/chromium/third_party/blink/renderer/core/layout/floating_objects.cc
index f5cf1c6dae0..3db8f737b5f 100644
--- a/chromium/third_party/blink/renderer/core/layout/floating_objects.cc
+++ b/chromium/third_party/blink/renderer/core/layout/floating_objects.cc
@@ -101,7 +101,7 @@ std::unique_ptr<FloatingObject> FloatingObject::Create(LayoutBox* layout_object,
// update and still haven't decided who should paint the float. If we've
// decided that the current float owner can paint it that step is unnecessary,
// so we can clear it now.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
new_obj->ShouldPaint() && layout_object->Layer() &&
layout_object->Layer()->SelfPaintingStatusChanged())
layout_object->Layer()->ClearSelfPaintingStatusChanged();
diff --git a/chromium/third_party/blink/renderer/core/layout/grid.cc b/chromium/third_party/blink/renderer/core/layout/grid.cc
index 0b37f2aad6b..324ba58dba7 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid.cc
@@ -452,17 +452,14 @@ std::unique_ptr<GridArea> ListGridIterator::NextEmptyGridArea(
auto& varying_index = is_row_axis ? row_index_ : column_index_;
const size_t fixed_index = is_row_axis ? column_index_ : row_index_;
const size_t end_fixed_span = fixed_index + fixed_track_span - 1;
- size_t last_varying_index = grid_.NumTracks(orthogonal_axis);
auto* track_node = tracks.Head();
while (track_node && track_node->Index() < varying_index)
track_node = track_node->Next();
- do {
- if (!track_node) {
- if (last_varying_index - varying_index >= varying_track_span)
- return CreateUniqueGridArea();
- return nullptr;
- }
+ for (; track_node; track_node = track_node->Next()) {
+ if (!track_node)
+ return CreateUniqueGridArea();
+
if (track_node->Index() - varying_index >= varying_track_span)
return CreateUniqueGridArea();
@@ -473,10 +470,9 @@ std::unique_ptr<GridArea> ListGridIterator::NextEmptyGridArea(
varying_index = track_node->Index() + 1;
else if (track_node->Index() - varying_index >= varying_track_span)
return CreateUniqueGridArea();
- track_node = track_node->Next();
- } while (true); // track_node will eventually be nullptr
+ }
- return nullptr;
+ return CreateUniqueGridArea();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc b/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc
index fbc5ba34e62..ca6ec9e00e4 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc
@@ -46,12 +46,12 @@ static LayoutUnit ComputeMarginLogicalSizeForChild(
LayoutUnit margin_end;
LayoutUnit logical_size =
is_inline_direction ? child.LogicalWidth() : child.LogicalHeight();
- Length margin_start_length = is_inline_direction
- ? child.StyleRef().MarginStart()
- : child.StyleRef().MarginBefore();
- Length margin_end_length = is_inline_direction
- ? child.StyleRef().MarginEnd()
- : child.StyleRef().MarginAfter();
+ const Length& margin_start_length = is_inline_direction
+ ? child.StyleRef().MarginStart()
+ : child.StyleRef().MarginBefore();
+ const Length& margin_end_length = is_inline_direction
+ ? child.StyleRef().MarginEnd()
+ : child.StyleRef().MarginAfter();
child.ComputeMarginsForDirection(
for_direction, &grid, child.ContainingBlockLogicalWidthForContent(),
logical_size, margin_start, margin_end, margin_start_length,
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
index 1348a467789..52095c7eb50 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
@@ -527,7 +527,7 @@ void GridTrackSizingAlgorithmStrategy::DistributeSpaceToTracks(
LayoutUnit GridTrackSizingAlgorithmStrategy::MinLogicalWidthForChild(
LayoutBox& child,
- Length child_min_size,
+ const Length& child_min_size,
LayoutUnit available_size) const {
return child.ComputeLogicalWidthUsing(kMinSize, child_min_size,
available_size, GetLayoutGrid()) +
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
index 0b2bf5e7a85..9542ea5e770 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
@@ -290,7 +290,7 @@ class GridTrackSizingAlgorithmStrategy {
: algorithm_(algorithm) {}
virtual LayoutUnit MinLogicalWidthForChild(LayoutBox&,
- Length child_min_size,
+ const Length& child_min_size,
LayoutUnit available_size) const;
virtual void LayoutGridItemForMinSizeComputation(
LayoutBox&,
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc b/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
index e93774969dc..f6575585052 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -64,6 +64,7 @@ HitTestResult::HitTestResult(const HitTestResult& other)
: hit_test_request_(other.hit_test_request_),
cacheable_(other.cacheable_),
inner_node_(other.InnerNode()),
+ inner_element_(other.InnerElement()),
inner_possibly_pseudo_node_(other.inner_possibly_pseudo_node_),
point_in_inner_node_frame_(other.point_in_inner_node_frame_),
local_point_(other.LocalPoint()),
@@ -90,6 +91,7 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other) {
bool HitTestResult::EqualForCacheability(const HitTestResult& other) const {
return hit_test_request_.EqualForCacheability(other.hit_test_request_) &&
inner_node_ == other.InnerNode() &&
+ inner_element_ == other.InnerElement() &&
inner_possibly_pseudo_node_ == other.InnerPossiblyPseudoNode() &&
point_in_inner_node_frame_ == other.point_in_inner_node_frame_ &&
local_point_ == other.LocalPoint() &&
@@ -105,6 +107,7 @@ void HitTestResult::CacheValues(const HitTestResult& other) {
void HitTestResult::PopulateFromCachedResult(const HitTestResult& other) {
inner_node_ = other.InnerNode();
+ inner_element_ = other.InnerElement();
inner_possibly_pseudo_node_ = other.InnerPossiblyPseudoNode();
point_in_inner_node_frame_ = other.point_in_inner_node_frame_;
local_point_ = other.LocalPoint();
@@ -123,6 +126,7 @@ void HitTestResult::PopulateFromCachedResult(const HitTestResult& other) {
void HitTestResult::Trace(blink::Visitor* visitor) {
visitor->Trace(inner_node_);
+ visitor->Trace(inner_element_);
visitor->Trace(inner_possibly_pseudo_node_);
visitor->Trace(inner_url_element_);
visitor->Trace(scrollbar_);
@@ -191,11 +195,13 @@ HTMLAreaElement* HitTestResult::ImageAreaForImage() const {
}
void HitTestResult::SetInnerNode(Node* n) {
- inner_possibly_pseudo_node_ = n;
if (!n) {
- inner_node_ = n;
+ inner_possibly_pseudo_node_ = nullptr;
+ inner_node_ = nullptr;
+ inner_element_ = nullptr;
return;
}
+ inner_possibly_pseudo_node_ = n;
if (n->IsPseudoElement())
n = ToPseudoElement(n)->InnerNodeForHitTesting();
inner_node_ = n;
@@ -203,6 +209,10 @@ void HitTestResult::SetInnerNode(Node* n) {
inner_node_ = area;
inner_possibly_pseudo_node_ = area;
}
+ if (inner_node_->IsElementNode())
+ inner_element_ = ToElement(inner_node_);
+ else
+ inner_element_ = FlatTreeTraversal::ParentElement(*inner_node_);
}
void HitTestResult::SetURLElement(Element* n) {
@@ -428,6 +438,7 @@ void HitTestResult::Append(const HitTestResult& other) {
if (!inner_node_ && other.InnerNode()) {
inner_node_ = other.InnerNode();
+ inner_element_ = other.InnerElement();
inner_possibly_pseudo_node_ = other.InnerPossiblyPseudoNode();
local_point_ = other.LocalPoint();
point_in_inner_node_frame_ = other.point_in_inner_node_frame_;
@@ -461,8 +472,7 @@ HitTestLocation HitTestResult::ResolveRectBasedTest(
Node* resolved_inner_node,
const LayoutPoint& resolved_point_in_main_frame) {
point_in_inner_node_frame_ = resolved_point_in_main_frame;
- inner_node_ = nullptr;
- inner_possibly_pseudo_node_ = nullptr;
+ SetInnerNode(nullptr);
list_based_test_result_ = nullptr;
// Update the HitTestResult as if the supplied node had been hit in normal
@@ -476,14 +486,6 @@ HitTestLocation HitTestResult::ResolveRectBasedTest(
return HitTestLocation(resolved_point_in_main_frame);
}
-Element* HitTestResult::InnerElement() const {
- if (!inner_node_)
- return nullptr;
- if (inner_node_->IsElementNode())
- return ToElement(inner_node_);
- return FlatTreeTraversal::ParentElement(*inner_node_);
-}
-
Node* HitTestResult::InnerNodeOrImageMapImage() const {
if (!inner_node_)
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_result.h b/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
index cca88dbeb70..54ab7bc75be 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
@@ -83,7 +83,7 @@ class CORE_EXPORT HitTestResult {
Node* InnerPossiblyPseudoNode() const {
return inner_possibly_pseudo_node_.Get();
}
- Element* InnerElement() const;
+ Element* InnerElement() const { return inner_element_.Get(); }
// If innerNode is an image map or image map area, return the associated image
// node.
@@ -186,6 +186,8 @@ class CORE_EXPORT HitTestResult {
bool cacheable_;
Member<Node> inner_node_;
+ // This gets calculated in the first call to InnerElement function.
+ Member<Element> inner_element_;
Member<Node> inner_possibly_pseudo_node_;
// FIXME: Nothing changes this to a value different from m_hitTestLocation!
// The hit-tested point in innerNode frame coordinates.
diff --git a/chromium/third_party/blink/renderer/core/layout/jank_region.cc b/chromium/third_party/blink/renderer/core/layout/jank_region.cc
index 8a0b58081b4..2625c798829 100644
--- a/chromium/third_party/blink/renderer/core/layout/jank_region.cc
+++ b/chromium/third_party/blink/renderer/core/layout/jank_region.cc
@@ -43,7 +43,8 @@ class BasicIntervals {
private:
Vector<int> endpoints_;
- std::map<int, unsigned> endpoint_to_index_;
+ // Avoid WTF::HashMap as key may be 0 or -1.
+ std::unordered_map<int, unsigned> endpoint_to_index_;
#if DCHECK_IS_ON()
bool has_index_ = false;
@@ -143,9 +144,8 @@ class SegmentTree {
};
SegmentTree::SegmentTree(const BasicIntervals& intervals)
- : intervals_(intervals) {
- nodes_.resize(ComputeCapacity(intervals.NumIntervals()));
-}
+ : intervals_(intervals),
+ nodes_(ComputeCapacity(intervals.NumIntervals())) {}
inline void SegmentTree::RefSegment(Segment segment) {
Visit(0, RootSegment(), segment, 1);
diff --git a/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc b/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc
index cbd97b744fe..b246cfc8cfd 100644
--- a/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/frame/location.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
@@ -42,6 +43,9 @@ static float GetMoveDistance(const FloatRect& old_rect,
}
static float RegionGranularityScale(const IntRect& viewport) {
+ if (RuntimeEnabledFeatures::JankTrackingSweepLineEnabled())
+ return 1;
+
return kRegionGranularitySteps /
std::min(viewport.Height(), viewport.Width());
}
@@ -116,6 +120,12 @@ void JankTracker::AccumulateJank(const LayoutObject& source,
SmallerThanRegionGranularity(new_rect, scale))
return;
+ // Ignore layout objects that move (in the coordinate space of the paint
+ // invalidation container) on scroll.
+ // TODO(skobes): Find a way to detect when these objects jank.
+ if (source.IsFixedPositioned() || source.IsStickyPositioned())
+ return;
+
const auto* local_xform = TransformNodeFor(painting_layer.GetLayoutObject());
const auto* root_xform = TransformNodeFor(*source.View());
@@ -206,19 +216,22 @@ void JankTracker::NotifyPrePaintFinished() {
DVLOG(1) << "viewport " << (jank_fraction * 100)
<< "% janked, raising score to " << score_;
+ LocalFrame& frame = frame_view_->GetFrame();
+
TRACE_EVENT_INSTANT2("loading", "FrameLayoutJank", TRACE_EVENT_SCOPE_THREAD,
"data",
PerFrameTraceData(jank_fraction, granularity_scale),
- "frame", ToTraceValue(&frame_view_->GetFrame()));
+ "frame", ToTraceValue(&frame));
- frame_view_->GetFrame().Client()->DidObserveLayoutJank(jank_fraction);
+ frame.Client()->DidObserveLayoutJank(jank_fraction);
- if (RuntimeEnabledFeatures::LayoutJankAPIEnabled() &&
- frame_view_->GetFrame().DomWindow()) {
+ if (origin_trials::LayoutJankAPIEnabled(frame.GetDocument()) &&
+ frame.DomWindow()) {
WindowPerformance* performance =
- DOMWindowPerformance::performance(*frame_view_->GetFrame().DomWindow());
+ DOMWindowPerformance::performance(*frame.DomWindow());
if (performance &&
- performance->HasObserverFor(PerformanceEntry::kLayoutJank)) {
+ (performance->HasObserverFor(PerformanceEntry::kLayoutJank) ||
+ performance->ShouldBufferEntries())) {
performance->AddLayoutJankFraction(jank_fraction);
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc b/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc
index abe86ef53f3..aa8e01e2c84 100644
--- a/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc
@@ -51,6 +51,9 @@ TEST_F(JankTrackerTest, SimpleBlockMovement) {
}
TEST_F(JankTrackerTest, GranularitySnapping) {
+ if (RuntimeEnabledFeatures::JankTrackingSweepLineEnabled())
+ return;
+
SetBodyInnerHTML(R"HTML(
<style>
#j { position: relative; width: 304px; height: 104px; }
@@ -199,4 +202,35 @@ TEST_F(JankTrackerTest, CompositedJankBeforeFirstPaint) {
UpdateAllLifecyclePhases();
}
+TEST_F(JankTrackerTest, IgnoreFixedAndSticky) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { height: 1000px; }
+ #f1, #f2 {
+ position: fixed;
+ width: 300px;
+ height: 100px;
+ left: 100px;
+ }
+ #f1 { top: 0; }
+ #f2 { top: 150px; will-change: transform; }
+ #s1 {
+ position: sticky;
+ width: 200px;
+ height: 100px;
+ left: 450px;
+ top: 0;
+ }
+ </style>
+ <div id='f1'>fixed</div>
+ <div id='f2'>fixed composited</div>
+ <div id='s1'>sticky</div>
+ normal
+ )HTML");
+
+ GetDocument().scrollingElement()->setScrollTop(50);
+ UpdateAllLifecyclePhases();
+ EXPECT_FLOAT_EQ(0, GetJankTracker().Score());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.cc b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
index 09d769f4ca1..99cf3601a80 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
@@ -49,6 +49,7 @@
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/layout_flow_thread.h"
#include "third_party/blink/renderer/core/layout/layout_grid.h"
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
@@ -322,11 +323,13 @@ void LayoutBlock::AddChildBeforeDescendant(LayoutObject* new_child,
// If the requested insertion point is not one of our children, then this is
// because there is an anonymous container within this object that contains
// the beforeDescendant.
- if (before_descendant_container->IsAnonymousBlock()) {
+ if (before_descendant_container->IsAnonymousBlock() ||
+ (before_descendant_container->IsLayoutInline() &&
+ ToLayoutInline(before_descendant_container)->IsFirstLineAnonymous())) {
// Insert the child into the anonymous block box instead of here.
if (new_child->IsInline() ||
- (new_child->IsFloatingOrOutOfFlowPositioned() && !IsFlexibleBox() &&
- !IsLayoutGrid()) ||
+ (new_child->IsFloatingOrOutOfFlowPositioned() &&
+ !IsFlexibleBoxIncludingNG() && !IsLayoutGrid()) ||
before_descendant->Parent()->SlowFirstChild() != before_descendant) {
before_descendant_container->AddChild(new_child, before_descendant);
} else {
@@ -366,8 +369,9 @@ void LayoutBlock::AddChild(LayoutObject* new_child,
// here.
DCHECK(!ChildrenInline());
- if (new_child->IsInline() || (new_child->IsFloatingOrOutOfFlowPositioned() &&
- !IsFlexibleBox() && !IsLayoutGrid())) {
+ if (new_child->IsInline() ||
+ (new_child->IsFloatingOrOutOfFlowPositioned() &&
+ !IsFlexibleBoxIncludingNG() && !IsLayoutGrid())) {
// If we're inserting an inline child but all of our children are blocks,
// then we have to make sure it is put into an anomyous block box. We try to
// use an existing anonymous box if possible, otherwise a new one is created
@@ -434,8 +438,21 @@ void LayoutBlock::UpdateLayout() {
LayoutAnalyzer::Scope analyzer(*this);
- if (LayoutBlockedByDisplayLock())
- return;
+ base::Optional<DisplayLockContext::ScopedPendingFrameRect>
+ scoped_pending_frame_rect;
+ if (auto* context = GetDisplayLockContext()) {
+ // In a display locked element, we might be prevented from doing layout in
+ // which case we should abort.
+ if (LayoutBlockedByDisplayLock())
+ return;
+ // If we're display locked, then our layout should go into a pending frame
+ // rect without updating the frame rect visible to the ancestors. The
+ // following scoped object provides this functionality: it puts in place the
+ // (previously updated) pending frame rect. When the object is destroyed, it
+ // saves the pending frame rect in the DisplayLockContext and restores the
+ // frame rect that was in place at the time the lock was acquired.
+ scoped_pending_frame_rect.emplace(context->GetScopedPendingFrameRect());
+ }
bool needs_scroll_anchoring =
HasOverflowClip() && GetScrollableArea()->ShouldPerformScrollAnchoring();
@@ -450,7 +467,7 @@ void LayoutBlock::UpdateLayout() {
// It's safe to check for control clip here, since controls can never be table
// cells. If we have a lightweight clip, there can never be any overflow from
// children.
- if (HasControlClip() && overflow_)
+ if (HasControlClip() && HasLayoutOverflow())
ClearLayoutOverflow();
height_available_to_children_changed_ = false;
@@ -505,25 +522,16 @@ void LayoutBlock::AddLayoutOverflowFromChildren() {
AddLayoutOverflowFromBlockChildren();
}
-void LayoutBlock::ComputeOverflow(LayoutUnit old_client_after_edge,
- bool recompute_floats) {
+void LayoutBlock::ComputeVisualOverflow(bool) {
LayoutRect previous_visual_overflow_rect = VisualOverflowRect();
- overflow_.reset();
- ComputeLayoutOverflow(old_client_after_edge, recompute_floats);
- ComputeVisualOverflow(previous_visual_overflow_rect, recompute_floats);
-}
-
-void LayoutBlock::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
- bool) {
+ ClearVisualOverflow();
AddVisualOverflowFromChildren();
AddVisualEffectOverflow();
AddVisualOverflowFromTheme();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
+ SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
}
@@ -531,6 +539,8 @@ void LayoutBlock::ComputeVisualOverflow(
DISABLE_CFI_PERF
void LayoutBlock::ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
bool) {
+ ClearSelfNeedsLayoutOverflowRecalc();
+ ClearLayoutOverflow();
AddLayoutOverflowFromChildren();
AddLayoutOverflowFromPositionedObjects();
@@ -551,8 +561,7 @@ void LayoutBlock::ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
(old_client_after_edge - client_rect.X()).ClampNegativeToZero(),
LayoutUnit(1));
AddLayoutOverflow(rect_to_apply);
- if (HasOverflowModel())
- overflow_->SetLayoutClientAfterEdge(old_client_after_edge);
+ SetLayoutClientAfterEdge(old_client_after_edge);
}
}
@@ -570,7 +579,6 @@ void LayoutBlock::AddVisualOverflowFromBlockChildren() {
if (child->IsLayoutBlockFlow() &&
ToLayoutBlockFlow(child)->ContainsInlineWithOutlineAndContinuation())
ToLayoutBlockFlow(child)->AddVisualOverflowFromInlineChildren();
-
AddVisualOverflowFromChild(*child);
}
}
@@ -730,10 +738,8 @@ bool LayoutBlock::SimplifiedLayout() {
// every relayout so it's not a regression. computeOverflow expects the
// bottom edge before we clamp our height. Since this information isn't
// available during simplifiedLayout, we cache the value in m_overflow.
- LayoutUnit old_client_after_edge = HasOverflowModel()
- ? overflow_->LayoutClientAfterEdge()
- : ClientLogicalBottom();
- ComputeOverflow(old_client_after_edge, true);
+ LayoutUnit old_client_after_edge = LayoutClientAfterEdge();
+ ComputeLayoutOverflow(old_client_after_edge, true);
}
UpdateAfterLayout();
@@ -792,8 +798,8 @@ LayoutUnit LayoutBlock::MarginIntrinsicLogicalWidthForChild(
// A margin has three types: fixed, percentage, and auto (variable).
// Auto and percentage margins become 0 when computing min/max width.
// Fixed margins can be added in as is.
- Length margin_left = child.StyleRef().MarginStartUsing(StyleRef());
- Length margin_right = child.StyleRef().MarginEndUsing(StyleRef());
+ const Length& margin_left = child.StyleRef().MarginStartUsing(StyleRef());
+ const Length& margin_right = child.StyleRef().MarginEndUsing(StyleRef());
LayoutUnit margin;
if (margin_left.IsFixed())
margin += margin_left.Value();
@@ -875,6 +881,7 @@ void LayoutBlock::LayoutPositionedObject(LayoutBox* positioned_object,
bool needs_block_direction_location_set_before_layout =
is_paginated &&
positioned_object->GetPaginationBreakability() != kForbidBreaks;
+ bool bogus_logical_top_estimate = false;
if (needs_block_direction_location_set_before_layout) {
// Out-of-flow objects are normally positioned after layout (while in-flow
// objects are positioned before layout). If the child object is paginated
@@ -882,16 +889,35 @@ void LayoutBlock::LayoutPositionedObject(LayoutBox* positioned_object,
// know this up-front, to correctly evaluate if we need to mark for
// relayout, and, if our estimate is correct, we'll even be able to insert
// correct pagination struts on the first attempt.
- LogicalExtentComputedValues computed_values;
- positioned_object->ComputeLogicalHeight(positioned_object->LogicalHeight(),
- positioned_object->LogicalTop(),
- computed_values);
- logical_top_estimate = computed_values.position_;
+ const ComputedStyle& style = positioned_object->StyleRef();
+ if (!style.LogicalBottom().IsAuto() && style.LogicalTop().IsAuto() &&
+ style.LogicalHeight().IsAuto()) {
+ // This child is bottom-aligned with auto block size. We cannot make a
+ // decent estimate before layout. Just estimate something as far above a
+ // fragmentainer break as possible. This is a way to try our best to avoid
+ // hitting fragmentainer breaks, as that could impact the block size of
+ // the child (increase it if contents need to be pushed to the next
+ // fragmentainer, or decrease it if a descendant margin collides into a
+ // fragmentainer boundary), and thus give us a bad block-start offset.
+ logical_top_estimate = -OffsetFromLogicalTopOfFirstPage();
+ bogus_logical_top_estimate = true;
+ } else {
+ LogicalExtentComputedValues computed_values;
+ positioned_object->ComputeLogicalHeight(
+ positioned_object->LogicalHeight(), positioned_object->LogicalTop(),
+ computed_values);
+ logical_top_estimate = computed_values.position_;
+ }
positioned_object->SetLogicalTop(logical_top_estimate);
}
- if (!positioned_object->NeedsLayout())
+ if (!positioned_object->NeedsLayout()) {
MarkChildForPaginationRelayoutIfNeeded(*positioned_object, layout_scope);
+ // If we're not able to set a decent block start estimate, we need to force
+ // layout to figure it out.
+ if (bogus_logical_top_estimate)
+ layout_scope.SetChildNeedsLayout(positioned_object);
+ }
// FIXME: We should be able to do a r->setNeedsPositionedMovementLayout()
// here instead of a full layout. Need to investigate why it does not
@@ -905,6 +931,9 @@ void LayoutBlock::LayoutPositionedObject(LayoutBox* positioned_object,
LayoutObject* parent = positioned_object->Parent();
bool layout_changed = false;
+ // TODO(dgrogan): The NG flexbox implementation doesn't have an analogous
+ // method yet, so abspos children of NG flexboxes that have a legacy
+ // containing block will not be positioned correctly.
if (parent->IsFlexibleBox() &&
ToLayoutFlexibleBox(parent)->SetStaticPositionForPositionedLayout(
*positioned_object)) {
@@ -1028,6 +1057,34 @@ void LayoutBlock::ClearPreviousVisualRects() {
BlockPaintInvalidator(*this).ClearPreviousVisualRects();
}
+void LayoutBlock::ImageChanged(WrappedImagePtr image,
+ CanDeferInvalidation defer) {
+ LayoutBox::ImageChanged(image, defer);
+
+ if (!StyleRef().HasPseudoStyle(kPseudoIdFirstLine))
+ return;
+
+ // ImageChanged() is also called when we add image observers. Don't use
+ // FirstLineStyleRef() here because it will update the first line style cache
+ // too early. We should just access the current cached style and bail out if
+ // it's not ready (and we'll update pending image observer when the cache is
+ // updated).
+ const auto* cached_first_line_style =
+ StyleRef().GetCachedPseudoStyle(kPseudoIdFirstLine);
+ if (!cached_first_line_style)
+ return;
+
+ if (auto* first_line_container = NearestInnerBlockWithFirstLine()) {
+ for (const auto* layer = &cached_first_line_style->BackgroundLayers();
+ layer; layer = layer->Next()) {
+ if (layer->GetImage() && image == layer->GetImage()->Data()) {
+ first_line_container->SetShouldDoFullPaintInvalidationForFirstLine();
+ break;
+ }
+ }
+ }
+}
+
void LayoutBlock::RemovePositionedObjects(
LayoutObject* o,
ContainingBlockState containing_block_state) {
@@ -1046,7 +1103,7 @@ void LayoutBlock::RemovePositionedObjects(
// invalidation container.
// Invalidate it (including non-compositing descendants) on its original
// paint invalidation container.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// This valid because we need to invalidate based on the current
// status.
DisableCompositingQueryAsserts compositing_disabler;
@@ -1549,8 +1606,9 @@ void LayoutBlock::ComputeBlockPreferredLogicalWidths(
// (variable).
// Auto and percentage margins simply become 0 when computing min/max width.
// Fixed margins can be added in as is.
- Length start_margin_length = child_style->MarginStartUsing(style_to_use);
- Length end_margin_length = child_style->MarginEndUsing(style_to_use);
+ const Length& start_margin_length =
+ child_style->MarginStartUsing(style_to_use);
+ const Length& end_margin_length = child_style->MarginEndUsing(style_to_use);
LayoutUnit margin;
LayoutUnit margin_start;
LayoutUnit margin_end;
@@ -1780,6 +1838,9 @@ LayoutUnit LayoutBlock::MinLineHeightForReplacedObject(
LayoutUnit LayoutBlock::FirstLineBoxBaseline() const {
DCHECK(!ChildrenInline());
+ if (ShouldApplyLayoutContainment())
+ return LayoutUnit(-1);
+
if (IsWritingModeRoot() && !IsRubyRun())
return LayoutUnit(-1);
@@ -2071,79 +2132,119 @@ void LayoutBlock::SetCachedConstraintSpace(const NGConstraintSpace& space) {
cached_constraint_space_.reset(new NGConstraintSpace(space));
}
-bool LayoutBlock::RecalcNormalFlowChildOverflowIfNeeded(
+bool LayoutBlock::RecalcNormalFlowChildLayoutOverflowIfNeeded(
LayoutObject* layout_object) {
if (layout_object->IsOutOfFlowPositioned())
return false;
- return layout_object->RecalcOverflow();
+ return layout_object->RecalcLayoutOverflow();
}
-bool LayoutBlock::RecalcChildOverflow() {
+void LayoutBlock::RecalcNormalFlowChildVisualOverflowIfNeeded(
+ LayoutObject* layout_object) {
+ if (layout_object->IsOutOfFlowPositioned() ||
+ (layout_object->HasLayer() &&
+ ToLayoutBoxModelObject(layout_object)->HasSelfPaintingLayer()))
+ return;
+ layout_object->RecalcVisualOverflow();
+}
+
+bool LayoutBlock::RecalcChildLayoutOverflow() {
DCHECK(!IsTable());
- DCHECK(ChildNeedsOverflowRecalc());
+ DCHECK(ChildNeedsLayoutOverflowRecalc());
ClearChildNeedsLayoutOverflowRecalc();
- ClearChildNeedsVisualOverflowRecalc();
- bool children_overflow_changed = false;
+ bool children_layout_overflow_changed = false;
+
+ if (ChildrenInline()) {
+ SECURITY_DCHECK(IsLayoutBlockFlow());
+ children_layout_overflow_changed =
+ ToLayoutBlockFlow(this)->RecalcInlineChildrenLayoutOverflow();
+ } else {
+ for (LayoutBox* box = FirstChildBox(); box; box = box->NextSiblingBox()) {
+ if (RecalcNormalFlowChildLayoutOverflowIfNeeded(box))
+ children_layout_overflow_changed = true;
+ }
+ }
+
+ return RecalcPositionedDescendantsLayoutOverflow() ||
+ children_layout_overflow_changed;
+}
+
+void LayoutBlock::RecalcChildVisualOverflow() {
+ DCHECK(!IsTable());
if (ChildrenInline()) {
SECURITY_DCHECK(IsLayoutBlockFlow());
- children_overflow_changed =
- ToLayoutBlockFlow(this)->RecalcInlineChildrenOverflow();
+ ToLayoutBlockFlow(this)->RecalcInlineChildrenVisualOverflow();
} else {
for (LayoutBox* box = FirstChildBox(); box; box = box->NextSiblingBox()) {
- if (RecalcNormalFlowChildOverflowIfNeeded(box))
- children_overflow_changed = true;
+ RecalcNormalFlowChildVisualOverflowIfNeeded(box);
}
}
- return RecalcPositionedDescendantsOverflow() || children_overflow_changed;
+ RecalcPositionedDescendantsVisualOverflow();
}
-bool LayoutBlock::RecalcPositionedDescendantsOverflow() {
- bool children_overflow_changed = false;
+bool LayoutBlock::RecalcPositionedDescendantsLayoutOverflow() {
+ bool children_layout_overflow_changed = false;
+
+ TrackedLayoutBoxListHashSet* positioned_descendants = PositionedObjects();
+ if (!positioned_descendants)
+ return children_layout_overflow_changed;
+ for (auto* box : *positioned_descendants) {
+ if (box->RecalcLayoutOverflow())
+ children_layout_overflow_changed = true;
+ }
+ return children_layout_overflow_changed;
+}
+
+void LayoutBlock::RecalcPositionedDescendantsVisualOverflow() {
TrackedLayoutBoxListHashSet* positioned_descendants = PositionedObjects();
if (!positioned_descendants)
- return children_overflow_changed;
+ return;
for (auto* box : *positioned_descendants) {
- if (box->RecalcOverflow())
- children_overflow_changed = true;
+ if (box->HasLayer() && box->HasSelfPaintingLayer())
+ continue;
+ box->RecalcVisualOverflow();
}
- return children_overflow_changed;
}
-bool LayoutBlock::RecalcOverflow() {
- bool children_overflow_changed = false;
- if (ChildNeedsOverflowRecalc())
- children_overflow_changed = RecalcChildOverflow();
+bool LayoutBlock::RecalcLayoutOverflow() {
+ bool children_layout_overflow_changed = false;
+ if (ChildNeedsLayoutOverflowRecalc())
+ children_layout_overflow_changed = RecalcChildLayoutOverflow();
- bool self_needs_overflow_recalc = SelfNeedsOverflowRecalc();
- if (!self_needs_overflow_recalc && !children_overflow_changed)
+ bool self_needs_overflow_recalc = SelfNeedsLayoutOverflowRecalc();
+ if (!self_needs_overflow_recalc && !children_layout_overflow_changed)
return false;
- return RecalcSelfOverflow();
+ return RecalcSelfLayoutOverflow();
}
-bool LayoutBlock::RecalcSelfOverflow() {
- bool self_needs_overflow_recalc = SelfNeedsOverflowRecalc();
- ClearSelfNeedsLayoutOverflowRecalc();
- ClearSelfNeedsVisualOverflowRecalc();
+void LayoutBlock::RecalcVisualOverflow() {
+ RecalcChildVisualOverflow();
+ RecalcSelfVisualOverflow();
+}
+
+bool LayoutBlock::RecalcSelfLayoutOverflow() {
+ bool self_needs_layout_overflow_recalc = SelfNeedsLayoutOverflowRecalc();
// If the current block needs layout, overflow will be recalculated during
// layout time anyway. We can safely exit here.
if (NeedsLayout())
return false;
- LayoutUnit old_client_after_edge = HasOverflowModel()
- ? overflow_->LayoutClientAfterEdge()
- : ClientLogicalBottom();
- ComputeOverflow(old_client_after_edge, true);
-
+ LayoutUnit old_client_after_edge = LayoutClientAfterEdge();
+ ComputeLayoutOverflow(old_client_after_edge, true);
if (HasOverflowClip())
Layer()->GetScrollableArea()->UpdateAfterOverflowRecalc();
- return !HasOverflowClip() || self_needs_overflow_recalc;
+ return !HasOverflowClip() || self_needs_layout_overflow_recalc;
+}
+
+void LayoutBlock::RecalcSelfVisualOverflow() {
+ ComputeVisualOverflow(true);
}
// Called when a positioned object moves but doesn't necessarily change size.
@@ -2170,7 +2271,7 @@ bool LayoutBlock::TryLayoutDoingPositionedMovementOnly() {
ComputeLogicalHeight(old_height, LogicalTop(), computed_values);
if (old_height != computed_values.extent_ &&
- (HasPercentHeightDescendants() || IsFlexibleBox())) {
+ (HasPercentHeightDescendants() || IsFlexibleBoxIncludingNG())) {
SetIntrinsicContentLogicalHeight(old_intrinsic_content_logical_height);
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.h b/chromium/third_party/blink/renderer/core/layout/layout_block.h
index 211c5569465..5422b712058 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.h
@@ -324,13 +324,18 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
void SetCachedConstraintSpace(const NGConstraintSpace& space);
protected:
- bool RecalcNormalFlowChildOverflowIfNeeded(LayoutObject*);
- bool RecalcPositionedDescendantsOverflow();
- bool RecalcSelfOverflow();
+ bool RecalcNormalFlowChildLayoutOverflowIfNeeded(LayoutObject*);
+ void RecalcNormalFlowChildVisualOverflowIfNeeded(LayoutObject*);
+ bool RecalcPositionedDescendantsLayoutOverflow();
+ void RecalcPositionedDescendantsVisualOverflow();
+ bool RecalcSelfLayoutOverflow();
+ void RecalcSelfVisualOverflow();
public:
- bool RecalcChildOverflow();
- bool RecalcOverflow() override;
+ bool RecalcChildLayoutOverflow();
+ void RecalcChildVisualOverflow();
+ bool RecalcLayoutOverflow() override;
+ void RecalcVisualOverflow() override;
// An example explaining layout tree structure about first-line style:
// <style>
@@ -395,9 +400,6 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
const LayoutPoint& paint_offset) const;
void UpdateAfterLayout() override;
- void ComputeOverflow(LayoutUnit old_client_after_edge,
- bool recompute_floats = false);
-
protected:
virtual void AdjustInlineDirectionLineBounds(
unsigned /* expansionOpportunityCount */,
@@ -455,10 +457,9 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
protected:
void AddVisualOverflowFromTheme();
virtual void ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
bool recompute_floats);
virtual void ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
- bool recompute_floats);
+ bool recompute_floats = false);
virtual void AddLayoutOverflowFromChildren();
void AddVisualOverflowFromChildren();
@@ -517,9 +518,10 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
protected:
void InvalidatePaint(const PaintInvalidatorContext&) const override;
-
void ClearPreviousVisualRects() override;
+ void ImageChanged(WrappedImagePtr, CanDeferInvalidation) override;
+
private:
LayoutRect LocalCaretRect(
const InlineBox*,
@@ -593,7 +595,7 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
public:
// TODO(loonybear): Temporary in order to ensure compatibility with existing
- // layout test results.
+ // web test results.
virtual void AdjustChildDebugRect(LayoutRect&) const {}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
index b5a5ce372c2..6c5b8516a05 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -390,7 +390,7 @@ bool LayoutBlockFlow::CheckIfIsSelfCollapsingBlock() const {
StyleRef().MarginAfterCollapse() == EMarginCollapse::kSeparate)
return false;
- Length logical_height_length = StyleRef().LogicalHeight();
+ const Length& logical_height_length = StyleRef().LogicalHeight();
bool has_auto_height = logical_height_length.IsAuto();
if (logical_height_length.IsPercentOrCalc() &&
!GetDocument().InQuirksMode()) {
@@ -525,7 +525,7 @@ void LayoutBlockFlow::UpdateBlockLayout(bool relayout_children) {
LayoutPositionedObjects(relayout_children, behavior);
// Add overflow from children.
- ComputeOverflow(unconstrained_client_after_edge);
+ ComputeLayoutOverflow(unconstrained_client_after_edge, false);
descendants_with_floats_marked_for_layout_ = false;
@@ -2560,18 +2560,19 @@ bool LayoutBlockFlow::AreCachedLinesValidFor(const NGConstraintSpace&) const {
return false;
}
-void LayoutBlockFlow::SetPaintFragment(const NGBreakToken*,
+void LayoutBlockFlow::SetPaintFragment(const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset) {}
void LayoutBlockFlow::UpdatePaintFragmentFromCachedLayoutResult(
- const NGBreakToken*,
+ const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset) {}
void LayoutBlockFlow::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
bool recompute_floats) {
+ LayoutRect previous_visual_overflow_rect = VisualOverflowRect();
+ ClearVisualOverflow();
AddVisualOverflowFromChildren();
AddVisualEffectOverflow();
@@ -2580,10 +2581,8 @@ void LayoutBlockFlow::ComputeVisualOverflow(
if (recompute_floats || CreatesNewFormattingContext() ||
HasSelfPaintingLayer())
AddVisualOverflowFromFloats();
-
if (VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
+ SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
}
@@ -3604,6 +3603,7 @@ void LayoutBlockFlow::MakeChildrenNonInline(LayoutObject* insertion_point) {
DCHECK(!insertion_point || insertion_point->Parent() == this);
SetChildrenInline(false);
+ ClearNGInlineNodeData();
LayoutObject* child = FirstChild();
if (!child)
@@ -4367,9 +4367,9 @@ void LayoutBlockFlow::UpdateAncestorShouldPaintFloatingObject(
// However, sometimes a layer's self painting status is affected by its
// compositing status, so we need to call this method during compositing
// update when we find a layer changes self painting status. This doesn't
- // apply to SPv2 in which a layer's self painting status no longer depends on
+ // apply to CAP in which a layer's self painting status no longer depends on
// compositing status.
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
DCHECK(float_box.IsFloating());
bool float_box_is_self_painting_layer =
float_box.HasLayer() && float_box.Layer()->IsSelfPaintingLayer();
@@ -4492,7 +4492,7 @@ void LayoutBlockFlow::PositionSpannerDescendant(
DISABLE_CFI_PERF
bool LayoutBlockFlow::CreatesNewFormattingContext() const {
if (IsInline() || IsFloatingOrOutOfFlowPositioned() || HasOverflowClip() ||
- IsFlexItemIncludingDeprecated() || IsCustomItem() ||
+ IsFlexItemIncludingDeprecatedAndNG() || IsCustomItem() ||
IsDocumentElement() || IsGridItem() || IsWritingModeRoot() ||
StyleRef().Display() == EDisplay::kFlowRoot ||
ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() ||
@@ -4658,15 +4658,17 @@ void LayoutBlockFlow::SimplifiedNormalFlowInlineLayout() {
}
}
-bool LayoutBlockFlow::RecalcInlineChildrenOverflow() {
+bool LayoutBlockFlow::RecalcInlineChildrenLayoutOverflow() {
DCHECK(ChildrenInline());
- bool children_overflow_changed = false;
+ bool children_layout_overflow_changed = false;
ListHashSet<RootInlineBox*> line_boxes;
for (InlineWalker walker(LineLayoutBlockFlow(this)); !walker.AtEnd();
walker.Advance()) {
LayoutObject* layout_object = walker.Current().GetLayoutObject();
- if (RecalcNormalFlowChildOverflowIfNeeded(layout_object)) {
- children_overflow_changed = true;
+ if (RecalcNormalFlowChildLayoutOverflowIfNeeded(layout_object)) {
+ children_layout_overflow_changed = true;
+ // TODO(chrishtr): should this be IsBox()? Non-blocks can be
+ // inline and have line box wrappers.
if (layout_object->IsLayoutBlock()) {
if (InlineBox* inline_box_wrapper =
ToLayoutBlock(layout_object)->InlineBoxWrapper())
@@ -4684,7 +4686,30 @@ bool LayoutBlockFlow::RecalcInlineChildrenOverflow() {
box->ClearKnownToHaveNoOverflow();
box->ComputeOverflow(box->LineTop(), box->LineBottom(), text_box_data_map);
}
- return children_overflow_changed;
+ return children_layout_overflow_changed;
+}
+
+void LayoutBlockFlow::RecalcInlineChildrenVisualOverflow() {
+ DCHECK(ChildrenInline());
+ ListHashSet<RootInlineBox*> line_boxes;
+ for (InlineWalker walker(LineLayoutBlockFlow(this)); !walker.AtEnd();
+ walker.Advance()) {
+ LayoutObject* layout_object = walker.Current().GetLayoutObject();
+ RecalcNormalFlowChildVisualOverflowIfNeeded(layout_object);
+ if (layout_object->IsBox()) {
+ if (InlineBox* inline_box_wrapper =
+ ToLayoutBox(layout_object)->InlineBoxWrapper())
+ line_boxes.insert(&inline_box_wrapper->Root());
+ }
+ }
+
+ // Child inline boxes' self visual overflow is already computed at the same
+ // time as layout overflow. But we need to add replaced children visual rects.
+ for (ListHashSet<RootInlineBox*>::const_iterator it = line_boxes.begin();
+ it != line_boxes.end(); ++it) {
+ RootInlineBox* box = *it;
+ box->AddReplacedChildrenVisualOverflow(box->LineTop(), box->LineBottom());
+ }
}
PositionWithAffinity LayoutBlockFlow::PositionForPoint(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
index 9a000f4cbaa..14a179e2e71 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -59,6 +59,7 @@ class LayoutMultiColumnFlowThread;
class LayoutMultiColumnSpannerPlaceholder;
class LayoutRubyRun;
class MarginInfo;
+class NGBlockBreakToken;
class NGBreakToken;
class NGConstraintSpace;
class NGLayoutResult;
@@ -111,9 +112,9 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
void UpdateBlockLayout(bool relayout_children) override;
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) override;
+ void ComputeVisualOverflow(bool recompute_floats) override;
void ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
- bool recompute_floats) override;
+ bool recompute_floats = false) override;
void DeleteLineBoxTree();
@@ -424,7 +425,8 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
void SetShouldDoFullPaintInvalidationForFirstLine();
void SimplifiedNormalFlowInlineLayout();
- bool RecalcInlineChildrenOverflow();
+ bool RecalcInlineChildrenLayoutOverflow();
+ void RecalcInlineChildrenVisualOverflow();
PositionWithAffinity PositionForPoint(const LayoutPoint&) const override;
@@ -454,6 +456,7 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
virtual NGInlineNodeData* TakeNGInlineNodeData() { return nullptr; }
virtual NGInlineNodeData* GetNGInlineNodeData() const { return nullptr; }
virtual void ResetNGInlineNodeData() {}
+ virtual void ClearNGInlineNodeData() {}
virtual bool HasNGInlineNodeData() const { return false; }
virtual NGPaintFragment* PaintFragment() const { return nullptr; }
virtual scoped_refptr<NGLayoutResult> CachedLayoutResult(
@@ -466,11 +469,11 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
virtual void ClearCachedLayoutResult();
virtual bool AreCachedLinesValidFor(const NGConstraintSpace&) const;
virtual void WillCollectInlines() {}
- virtual void SetPaintFragment(const NGBreakToken*,
+ virtual void SetPaintFragment(const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset);
virtual void UpdatePaintFragmentFromCachedLayoutResult(
- const NGBreakToken*,
+ const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset);
virtual const NGPhysicalBoxFragment* CurrentFragment() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
index 20531ff0e3b..7acd1b77e36 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
@@ -1584,8 +1584,8 @@ static inline void AdjustMarginForInlineReplaced(LayoutObject* child,
LayoutUnit& child_max) {
// Inline replaced elts add in their margins to their min/max values.
const ComputedStyle& child_style = child->StyleRef();
- Length start_margin = child_style.MarginStart();
- Length end_margin = child_style.MarginEnd();
+ const Length& start_margin = child_style.MarginStart();
+ const Length& end_margin = child_style.MarginEnd();
LayoutUnit margins;
if (start_margin.IsFixed())
margins += AdjustFloatForSubPixelLayout(start_margin.Value());
@@ -2482,8 +2482,7 @@ void LayoutBlockFlow::CheckLinesForTextOverflow() {
LogicalRightOffsetForLine(curr->LineTop(), indent_text);
LayoutUnit block_left_edge =
LogicalLeftOffsetForLine(curr->LineTop(), indent_text);
- LayoutUnit line_box_edge = ltr ? curr->LogicalRightLayoutOverflow()
- : curr->LogicalLeftLayoutOverflow();
+ LayoutUnit line_box_edge = ltr ? curr->LogicalRight() : curr->LogicalLeft();
if ((ltr && line_box_edge > block_right_edge) ||
(!ltr && line_box_edge < block_left_edge)) {
// This line spills out of our box in the appropriate direction. Now we
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
index 8afce7ccbae..ce5f73c0eea 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
@@ -400,7 +400,7 @@ void LayoutBox::UpdateShapeOutsideInfoAfterStyleChange(
old_style ? old_style->ShapeOutside()
: ComputedStyleInitialValues::InitialShapeOutside();
- Length shape_margin = style.ShapeMargin();
+ const Length& shape_margin = style.ShapeMargin();
Length old_shape_margin =
old_style ? old_style->ShapeMargin()
: ComputedStyleInitialValues::InitialShapeMargin();
@@ -763,7 +763,7 @@ void LayoutBox::UpdateAfterLayout() {
}
LayoutUnit LayoutBox::LogicalHeightWithVisibleOverflow() const {
- if (!overflow_ || HasOverflowClip())
+ if (!LayoutOverflowIsSet() || HasOverflowClip())
return LogicalHeight();
LayoutRect overflow = LayoutOverflowRect();
if (StyleRef().IsHorizontalWritingMode())
@@ -1566,11 +1566,16 @@ bool LayoutBox::HitTestAllPhases(HitTestResult& result,
// If we have clipping, then we can't have any spillout.
// TODO(pdr): Why is this optimization not valid for the effective root?
if (!IsEffectiveRootScroller()) {
- LayoutRect overflow_box =
- (HasOverflowClip() || ShouldApplyPaintContainment())
- ? BorderBoxRect()
- : VisualOverflowRect();
- FlipForWritingMode(overflow_box);
+ LayoutRect overflow_box;
+ if (result.GetHitTestRequest().GetType() &
+ HitTestRequest::kHitTestVisualOverflow) {
+ overflow_box = VisualOverflowRectIncludingFilters();
+ } else {
+ overflow_box = (HasOverflowClip() || ShouldApplyPaintContainment())
+ ? BorderBoxRect()
+ : VisualOverflowRect();
+ FlipForWritingMode(overflow_box);
+ }
LayoutPoint adjusted_location = accumulated_offset + Location();
overflow_box.MoveBy(adjusted_location);
if (!location_in_container.Intersects(overflow_box))
@@ -1624,7 +1629,8 @@ bool LayoutBox::NodeAtPoint(HitTestResult& result,
LayoutRect bounds_rect;
if (result.GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow) {
- bounds_rect = VisualOverflowRect();
+ bounds_rect = VisualOverflowRectIncludingFilters();
+ FlipForWritingMode(bounds_rect);
} else {
bounds_rect = BorderBoxRect();
}
@@ -2158,7 +2164,7 @@ LayoutUnit LayoutBox::PerpendicularContainingBlockLogicalHeight() const {
return cb->OverrideContentLogicalHeight();
const ComputedStyle& containing_block_style = cb->StyleRef();
- Length logical_height_length = containing_block_style.LogicalHeight();
+ const Length& logical_height_length = containing_block_style.LogicalHeight();
// FIXME: For now just support fixed heights. Eventually should support
// percentage heights as well.
@@ -2628,7 +2634,8 @@ static bool ShouldRecalculateMinMaxWidthsAffectedByAncestor(
return false;
}
if (const LayoutBox* containing_block = box->ContainingBlock()) {
- if (containing_block->NeedsPreferredWidthsRecalculation()) {
+ if (containing_block->NeedsPreferredWidthsRecalculation() &&
+ !containing_block->PreferredLogicalWidthsDirty()) {
// If our containing block also has min/max widths that are affected by
// the ancestry, we have already dealt with this object as well. Avoid
// unnecessary work and O(n^2) time complexity.
@@ -2736,9 +2743,6 @@ void LayoutBox::ComputeLogicalWidth(
(!in_vertical_box || !stretching) &&
(!IsGridItem() || !HasStretchedLogicalWidth());
const ComputedStyle& style_to_use = StyleRef();
- Length logical_width_length =
- treat_as_replaced ? Length(ComputeReplacedLogicalWidth(), kFixed)
- : style_to_use.LogicalWidth();
LayoutBlock* cb = ContainingBlock();
LayoutUnit container_logical_width =
@@ -2752,11 +2756,11 @@ void LayoutBox::ComputeLogicalWidth(
style_to_use.MarginStart(), container_logical_width);
computed_values.margins_.end_ = MinimumValueForLength(
style_to_use.MarginEnd(), container_logical_width);
- if (treat_as_replaced)
- computed_values.extent_ =
- std::max(LayoutUnit(FloatValueForLength(logical_width_length, 0)) +
- BorderAndPaddingLogicalWidth(),
- MinPreferredLogicalWidth());
+ if (treat_as_replaced) {
+ computed_values.extent_ = std::max(
+ ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth(),
+ MinPreferredLogicalWidth());
+ }
return;
}
@@ -2771,8 +2775,8 @@ void LayoutBox::ComputeLogicalWidth(
// Width calculations
if (treat_as_replaced) {
- computed_values.extent_ = LayoutUnit(logical_width_length.Value()) +
- BorderAndPaddingLogicalWidth();
+ computed_values.extent_ =
+ ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth();
} else {
LayoutUnit preferred_width = ComputeLogicalWidthUsing(
kMainOrPreferredSize, style_to_use.LogicalWidth(),
@@ -2791,8 +2795,8 @@ void LayoutBox::ComputeLogicalWidth(
container_logical_width !=
(computed_values.extent_ + computed_values.margins_.start_ +
computed_values.margins_.end_) &&
- !IsFloating() && !IsInline() && !cb->IsFlexibleBoxIncludingDeprecated() &&
- !cb->IsLayoutGrid()) {
+ !IsFloating() && !IsInline() &&
+ !cb->IsFlexibleBoxIncludingDeprecatedAndNG() && !cb->IsLayoutGrid()) {
LayoutUnit new_margin_total =
container_logical_width - computed_values.extent_;
bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
@@ -2958,7 +2962,7 @@ bool LayoutBox::IsStretchingColumnFlexItem() const {
// We don't stretch multiline flexboxes because they need to apply line
// spacing (align-content) first.
- if (parent->IsFlexibleBox() &&
+ if (parent->IsFlexibleBoxIncludingNG() &&
parent->StyleRef().FlexWrap() == EFlexWrap::kNowrap &&
parent->StyleRef().IsColumnFlexDirection() &&
ColumnFlexItemHasStretchAlignment())
@@ -3005,7 +3009,7 @@ bool LayoutBox::SizesLogicalWidthToFitContent(
// intrinsic widths. In the case of columns that have a stretch alignment, we
// go ahead and layout at the stretched size to avoid an extra layout when
// applying alignment.
- if (Parent()->IsFlexibleBox()) {
+ if (Parent()->IsFlexibleBoxIncludingNG()) {
// For multiline columns, we need to apply align-content first, so we can't
// stretch now.
if (!Parent()->StyleRef().IsColumnFlexDirection() ||
@@ -3072,7 +3076,7 @@ void LayoutBox::ComputeMarginsForDirection(MarginDirection flow_direction,
return;
}
- if (containing_block->IsFlexibleBox()) {
+ if (containing_block->IsFlexibleBoxIncludingNG()) {
// We need to let flexbox handle the margin adjustment - otherwise, flexbox
// will think we're wider than we actually are and calculate line sizes
// wrong. See also https://drafts.csswg.org/css-flexbox/#auto-margins
@@ -3181,7 +3185,7 @@ void LayoutBox::UpdateLogicalHeight() {
SetMarginAfter(computed_values.margins_.after_);
}
-static inline Length HeightForDocumentElement(const Document& document) {
+static inline const Length& HeightForDocumentElement(const Document& document) {
return document.documentElement()
->GetLayoutObject()
->StyleRef()
@@ -3645,7 +3649,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
? ContainingBlockLogicalWidthForContent()
: PerpendicularContainingBlockLogicalHeight();
}
- Length container_logical_width =
+ const Length& container_logical_width =
ContainingBlock()->StyleRef().LogicalWidth();
// FIXME: Handle cases when containing block width is calculated or
// viewport percent. https://bugs.webkit.org/show_bug.cgi?id=91071
@@ -3680,8 +3684,9 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeight(LayoutUnit) const {
bool LayoutBox::LogicalHeightComputesAsNone(SizeType size_type) const {
DCHECK(size_type == kMinSize || size_type == kMaxSize);
- Length logical_height = size_type == kMinSize ? StyleRef().LogicalMinHeight()
- : StyleRef().LogicalMaxHeight();
+ const Length& logical_height = size_type == kMinSize
+ ? StyleRef().LogicalMinHeight()
+ : StyleRef().LogicalMaxHeight();
Length initial_logical_height =
size_type == kMinSize ? ComputedStyleInitialValues::InitialMinHeight()
: ComputedStyleInitialValues::InitialMaxHeight();
@@ -3819,7 +3824,7 @@ LayoutUnit LayoutBox::AvailableLogicalHeight(
if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
// LayoutNG code is correct, Legacy code incorrectly ConstrainsMinMax
// when height is -1, and returns 0, not -1.
- // The reason this code is NG-only is that this code causes perfomance
+ // The reason this code is NG-only is that this code causes performance
// regression for nested-percent-height-tables test case.
// This code gets executed 740 times in the test case.
// https://chromium-review.googlesource.com/c/chromium/src/+/1103289
@@ -4197,9 +4202,9 @@ void LayoutBox::ComputePositionedLogicalWidth(
bool is_horizontal = IsHorizontalWritingMode();
const LayoutUnit borders_plus_padding = BorderAndPaddingLogicalWidth();
- const Length margin_logical_left =
+ const Length& margin_logical_left =
is_horizontal ? StyleRef().MarginLeft() : StyleRef().MarginTop();
- const Length margin_logical_right =
+ const Length& margin_logical_right =
is_horizontal ? StyleRef().MarginRight() : StyleRef().MarginBottom();
Length logical_left_length = StyleRef().LogicalLeft();
@@ -4321,7 +4326,7 @@ LayoutUnit LayoutBox::ShrinkToFitLogicalWidth(
void LayoutBox::ComputePositionedLogicalWidthUsing(
SizeType width_size_type,
- Length logical_width,
+ const Length& logical_width,
const LayoutBoxModelObject* container_block,
TextDirection container_direction,
LayoutUnit container_logical_width,
@@ -4608,8 +4613,8 @@ void LayoutBox::ComputePositionedLogicalHeight(
const ComputedStyle& style_to_use = StyleRef();
const LayoutUnit borders_plus_padding = BorderAndPaddingLogicalHeight();
- const Length margin_before = style_to_use.MarginBefore();
- const Length margin_after = style_to_use.MarginAfter();
+ const Length& margin_before = style_to_use.MarginBefore();
+ const Length& margin_after = style_to_use.MarginAfter();
Length logical_top_length = style_to_use.LogicalTop();
Length logical_bottom_length = style_to_use.LogicalBottom();
@@ -5217,8 +5222,8 @@ void LayoutBox::AddVisualEffectOverflow() {
visual_effect_overflow.Expand(outsets);
AddSelfVisualOverflow(visual_effect_overflow);
- if (overflow_) {
- overflow_->SetHasSubpixelVisualEffectOutsets(
+ if (VisualOverflowIsSet()) {
+ overflow_->visual_overflow->SetHasSubpixelVisualEffectOutsets(
!IsIntegerValue(outsets.Top()) || !IsIntegerValue(outsets.Right()) ||
!IsIntegerValue(outsets.Bottom()) || !IsIntegerValue(outsets.Left()));
}
@@ -5285,6 +5290,28 @@ void LayoutBox::AddLayoutOverflowFromChild(const LayoutBox& child,
AddLayoutOverflow(child_layout_overflow_rect);
}
+void LayoutBox::SetLayoutClientAfterEdge(LayoutUnit client_after_edge) {
+ if (LayoutOverflowIsSet())
+ overflow_->layout_overflow->SetLayoutClientAfterEdge(client_after_edge);
+}
+
+LayoutUnit LayoutBox::LayoutClientAfterEdge() const {
+ return LayoutOverflowIsSet()
+ ? overflow_->layout_overflow->LayoutClientAfterEdge()
+ : ClientLogicalBottom();
+}
+
+LayoutRect LayoutBox::VisualOverflowRectIncludingFilters() const {
+ LayoutRect bounds_rect = VisualOverflowRect();
+ FlipForWritingMode(bounds_rect);
+ if (!StyleRef().HasFilter())
+ return bounds_rect;
+ FloatRect float_rect = Layer()->MapRectForFilter(FloatRect(bounds_rect));
+ float_rect.UniteIfNonZero(Layer()->FilterReferenceBox());
+ bounds_rect = EnclosingLayoutRect(float_rect);
+ return bounds_rect;
+}
+
bool LayoutBox::HasTopOverflow() const {
return !StyleRef().IsLeftToRightDirection() && !IsHorizontalWritingMode();
}
@@ -5329,11 +5356,13 @@ void LayoutBox::AddLayoutOverflow(const LayoutRect& rect) {
return;
}
- if (!overflow_) {
- overflow_ = std::make_unique<BoxOverflowModel>(client_box, BorderBoxRect());
+ if (!LayoutOverflowIsSet()) {
+ if (!overflow_)
+ overflow_ = std::make_unique<BoxOverflowModel>();
+ overflow_->layout_overflow.emplace(client_box);
}
- overflow_->AddLayoutOverflow(overflow_rect);
+ overflow_->layout_overflow->AddLayoutOverflow(overflow_rect);
}
void LayoutBox::AddSelfVisualOverflow(const LayoutRect& rect) {
@@ -5344,12 +5373,14 @@ void LayoutBox::AddSelfVisualOverflow(const LayoutRect& rect) {
if (border_box.Contains(rect))
return;
- if (!overflow_) {
- overflow_ =
- std::make_unique<BoxOverflowModel>(NoOverflowRect(), border_box);
+ if (!VisualOverflowIsSet()) {
+ if (!overflow_)
+ overflow_ = std::make_unique<BoxOverflowModel>();
+
+ overflow_->visual_overflow.emplace(border_box);
}
- overflow_->AddSelfVisualOverflow(rect);
+ overflow_->visual_overflow->AddSelfVisualOverflow(rect);
}
void LayoutBox::AddContentsVisualOverflow(const LayoutRect& rect) {
@@ -5365,23 +5396,29 @@ void LayoutBox::AddContentsVisualOverflow(const LayoutRect& rect) {
if (!HasOverflowClip() && border_box.Contains(rect))
return;
- if (!overflow_) {
- overflow_ =
- std::make_unique<BoxOverflowModel>(NoOverflowRect(), border_box);
+ if (!VisualOverflowIsSet()) {
+ if (!overflow_)
+ overflow_ = std::make_unique<BoxOverflowModel>();
+
+ overflow_->visual_overflow.emplace(border_box);
}
- overflow_->AddContentsVisualOverflow(rect);
+ overflow_->visual_overflow->AddContentsVisualOverflow(rect);
}
void LayoutBox::ClearLayoutOverflow() {
if (!overflow_)
return;
+ overflow_->layout_overflow.reset();
+ if (!overflow_->visual_overflow)
+ overflow_.reset();
+}
- if (!HasSelfVisualOverflow() && ContentsVisualOverflowRect().IsEmpty()) {
- ClearAllOverflows();
+void LayoutBox::ClearVisualOverflow() {
+ if (!overflow_)
return;
- }
-
- overflow_->SetLayoutOverflow(NoOverflowRect());
+ overflow_->visual_overflow.reset();
+ if (!overflow_->layout_overflow)
+ overflow_.reset();
}
bool LayoutBox::PercentageLogicalHeightIsResolvable() const {
@@ -5566,12 +5603,12 @@ LayoutRect LayoutBox::NoOverflowRect() const {
}
LayoutRect LayoutBox::VisualOverflowRect() const {
- if (!overflow_)
+ if (!VisualOverflowIsSet())
return BorderBoxRect();
if (HasOverflowClip() || HasMask())
- return overflow_->SelfVisualOverflowRect();
- return UnionRect(overflow_->SelfVisualOverflowRect(),
- overflow_->ContentsVisualOverflowRect());
+ return overflow_->visual_overflow->SelfVisualOverflowRect();
+ return UnionRect(overflow_->visual_overflow->SelfVisualOverflowRect(),
+ overflow_->visual_overflow->ContentsVisualOverflowRect());
}
LayoutPoint LayoutBox::OffsetPoint(const Element* parent) const {
@@ -5980,7 +6017,8 @@ void LayoutBox::AddCustomLayoutChildIfNeeded() {
if (!definition)
return;
- EnsureRareData().layout_child_ = new CustomLayoutChild(*definition, this);
+ EnsureRareData().layout_child_ =
+ MakeGarbageCollected<CustomLayoutChild>(*definition, this);
}
void LayoutBox::ClearCustomLayoutChild() {
@@ -6022,7 +6060,10 @@ float LayoutBox::VisualRectOutsetForRasterEffects() const {
// painted along the pixel-snapped border box, the pixels on the anti-aliased
// edge of the effect may overflow the calculated visual rect. Expand visual
// rect by one pixel in the case.
- return overflow_ && overflow_->HasSubpixelVisualEffectOutsets() ? 1 : 0;
+ return VisualOverflowIsSet() &&
+ overflow_->visual_overflow->HasSubpixelVisualEffectOutsets()
+ ? 1
+ : 0;
}
TextDirection LayoutBox::ResolvedDirection() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.h b/chromium/third_party/blink/renderer/core/layout/layout_box.h
index 9334ec858b3..7454ca65e79 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.h
@@ -389,6 +389,14 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
SetLocation(rect.Location());
SetSize(rect.Size());
}
+ // Similar to SetFrameRect(), except it avoids notifying other code about size
+ // and location changes. This should only be used from a DisplayLockContext to
+ // temporarily put in place a pending frame rect which is restored at the end
+ // of layout. Code outside of layout should not observe location or size
+ // changes.
+ void SetFrameRectForDisplayLock(const LayoutRect& rect) {
+ frame_rect_ = rect;
+ }
// Note that those functions have their origin at this box's CSS border box.
// As such their location doesn't account for 'top'/'left'. About its
@@ -472,7 +480,9 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// in the "physical coordinates in flipped block-flow direction" of the box.
LayoutRect NoOverflowRect() const;
LayoutRect LayoutOverflowRect() const {
- return overflow_ ? overflow_->LayoutOverflowRect() : NoOverflowRect();
+ return LayoutOverflowIsSet()
+ ? overflow_->layout_overflow->LayoutOverflowRect()
+ : NoOverflowRect();
}
LayoutRect PhysicalLayoutOverflowRect() const {
LayoutRect overflow_rect = LayoutOverflowRect();
@@ -485,14 +495,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutSize MaxLayoutOverflow() const {
return LayoutSize(LayoutOverflowRect().MaxX(), LayoutOverflowRect().MaxY());
}
- LayoutUnit LogicalLeftLayoutOverflow() const {
- return StyleRef().IsHorizontalWritingMode() ? LayoutOverflowRect().X()
- : LayoutOverflowRect().Y();
- }
- LayoutUnit LogicalRightLayoutOverflow() const {
- return StyleRef().IsHorizontalWritingMode() ? LayoutOverflowRect().MaxX()
- : LayoutOverflowRect().MaxY();
- }
LayoutRect VisualOverflowRect() const override;
LayoutRect PhysicalVisualOverflowRect() const {
@@ -510,12 +512,20 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
}
LayoutRect SelfVisualOverflowRect() const {
- return overflow_ ? overflow_->SelfVisualOverflowRect() : BorderBoxRect();
+ return VisualOverflowIsSet()
+ ? overflow_->visual_overflow->SelfVisualOverflowRect()
+ : BorderBoxRect();
}
LayoutRect ContentsVisualOverflowRect() const {
- return overflow_ ? overflow_->ContentsVisualOverflowRect() : LayoutRect();
+ return VisualOverflowIsSet()
+ ? overflow_->visual_overflow->ContentsVisualOverflowRect()
+ : LayoutRect();
}
+ // Returns the visual overflow rect, expanded to the area affected by any
+ // filters that paint outside of the box, in physical coordinates.
+ LayoutRect VisualOverflowRectIncludingFilters() const;
+
// These methods don't mean the box *actually* has top/left overflow. They
// mean that *if* the box overflows, it will overflow to the top/left rather
// than the bottom/right. This happens when child content is laid out
@@ -540,8 +550,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
const LayoutSize& delta);
void AddLayoutOverflowFromChild(const LayoutBox& child,
const LayoutSize& delta);
+ void SetLayoutClientAfterEdge(LayoutUnit client_after_edge);
+ LayoutUnit LayoutClientAfterEdge() const;
+
void ClearLayoutOverflow();
- void ClearAllOverflows() { overflow_.reset(); }
+ void ClearVisualOverflow();
virtual void UpdateAfterLayout();
@@ -1192,16 +1205,24 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
bool IsCustomItemShrinkToFit() const;
bool IsDeprecatedFlexItem() const {
- return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() &&
- Parent()->IsDeprecatedFlexibleBox();
+ return IsFlexItemCommon() && Parent()->IsDeprecatedFlexibleBox();
}
- bool IsFlexItemIncludingDeprecated() const {
- return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() &&
- Parent()->IsFlexibleBoxIncludingDeprecated();
+ bool IsFlexItemIncludingDeprecatedAndNG() const {
+ return IsFlexItemCommon() &&
+ Parent()->IsFlexibleBoxIncludingDeprecatedAndNG();
}
+
+ // TODO(dgrogan): Replace the rest of the calls to IsFlexItem with
+ // IsFlexItemIncludingNG when all the callsites can handle an item with an NG
+ // parent.
bool IsFlexItem() const {
- return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() &&
- Parent()->IsFlexibleBox();
+ return IsFlexItemCommon() && Parent()->IsFlexibleBox();
+ }
+ bool IsFlexItemIncludingNG() const {
+ return IsFlexItemCommon() && Parent()->IsFlexibleBoxIncludingNG();
+ }
+ bool IsFlexItemCommon() const {
+ return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent();
}
bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); }
@@ -1285,15 +1306,15 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutObject* container) const;
LayoutRect LayoutOverflowRectForPropagation(LayoutObject* container) const;
- bool HasOverflowModel() const { return overflow_.get(); }
bool HasSelfVisualOverflow() const {
- return overflow_ &&
- !BorderBoxRect().Contains(overflow_->SelfVisualOverflowRect());
- }
- bool HasVisualOverflow() const {
- return overflow_ && !BorderBoxRect().Contains(VisualOverflowRect());
+ return VisualOverflowIsSet() &&
+ !BorderBoxRect().Contains(
+ overflow_->visual_overflow->SelfVisualOverflowRect());
}
+ bool HasVisualOverflow() const { return VisualOverflowIsSet(); }
+ bool HasLayoutOverflow() const { return LayoutOverflowIsSet(); }
+
// Return true if re-laying out the containing block of this object means that
// we need to recalculate the preferred min/max logical widths of this object.
//
@@ -1338,7 +1359,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// container, applying adjustments for the given container offset,
// scrolling, container clipping, and transform (including container
// perspective).
- bool MapVisualRectToContainer(const LayoutObject* container_bject,
+ bool MapVisualRectToContainer(const LayoutObject* container_object,
const LayoutPoint& container_offset,
const LayoutObject* ancestor,
VisualRectFlags,
@@ -1348,20 +1369,22 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
bool HasRelativeLogicalHeight() const;
bool HasHorizontalLayoutOverflow() const {
- if (!overflow_)
+ if (!LayoutOverflowIsSet())
return false;
- LayoutRect layout_overflow_rect = overflow_->LayoutOverflowRect();
+ LayoutRect layout_overflow_rect =
+ overflow_->layout_overflow->LayoutOverflowRect();
LayoutRect no_overflow_rect = NoOverflowRect();
return layout_overflow_rect.X() < no_overflow_rect.X() ||
layout_overflow_rect.MaxX() > no_overflow_rect.MaxX();
}
bool HasVerticalLayoutOverflow() const {
- if (!overflow_)
+ if (!LayoutOverflowIsSet())
return false;
- LayoutRect layout_overflow_rect = overflow_->LayoutOverflowRect();
+ LayoutRect layout_overflow_rect =
+ overflow_->layout_overflow->LayoutOverflowRect();
LayoutRect no_overflow_rect = NoOverflowRect();
return layout_overflow_rect.Y() < no_overflow_rect.Y() ||
layout_overflow_rect.MaxY() > no_overflow_rect.MaxY();
@@ -1641,6 +1664,13 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
TextDirection ResolvedDirection() const;
private:
+ inline bool LayoutOverflowIsSet() const {
+ return overflow_ && overflow_->layout_overflow;
+ }
+ inline bool VisualOverflowIsSet() const {
+ return overflow_ && overflow_->visual_overflow;
+ }
+
void UpdateShapeOutsideInfoAfterStyleChange(const ComputedStyle&,
const ComputedStyle* old_style);
void UpdateGridPositionAfterStyleChange(const ComputedStyle*);
@@ -1659,7 +1689,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LogicalExtentComputedValues&) const;
void ComputePositionedLogicalWidthUsing(
SizeType,
- Length logical_width,
+ const Length& logical_width,
const LayoutBoxModelObject* container_block,
TextDirection container_direction,
LayoutUnit container_logical_width,
@@ -1760,9 +1790,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// See LayoutObject::maxPreferredLogicalWidth() for more details.
LayoutUnit max_preferred_logical_width_;
- // Our overflow information.
- std::unique_ptr<BoxOverflowModel> overflow_;
-
private:
LogicalToPhysicalSetter<LayoutUnit, LayoutBox> LogicalMarginToPhysicalSetter(
const ComputedStyle* override_style) {
@@ -1773,6 +1800,8 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
&LayoutBox::SetMarginBottom, &LayoutBox::SetMarginLeft);
}
+ std::unique_ptr<BoxOverflowModel> overflow_;
+
union {
// The inline box containing this LayoutBox, for atomic inline elements.
// Valid only when !IsInLayoutNGInlineFormattingContext().
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index f1c2dfea9dd..62349166978 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -242,7 +242,7 @@ void LayoutBoxModelObject::StyleWillChange(StyleDifference diff,
StyleRef().IsStackingContext() != new_style.IsStackingContext()) &&
// ObjectPaintInvalidator requires this.
IsRooted()) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
} else {
// We need to invalidate based on the current compositing status.
@@ -404,7 +404,7 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
if (Layer())
Layer()->SetNeedsCompositingInputsUpdate();
- // TODO(pdr): When slimming paint v2 is enabled, we will need to
+ // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
// invalidate the scroll paint property subtree for this so main thread
// scroll reasons are recomputed.
} else {
@@ -423,7 +423,7 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
}
}
- // TODO(pdr): When slimming paint v2 is enabled, we will need to
+ // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
// invalidate the scroll paint property subtree for this so main thread
// scroll reasons are recomputed.
}
@@ -443,7 +443,7 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
// the paint chunk.
Layer()->SetNeedsRepaint();
} else if (diff.TransformChanged() &&
- (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
!Layer()->HasStyleDeterminedDirectCompositingReasons())) {
// PaintLayerPainter::PaintLayerWithAdjustedRoot skips painting of a layer
// whose transform is not invertible, so we need to repaint the layer when
@@ -663,7 +663,7 @@ void LayoutBoxModelObject::UpdateFromStyle() {
}
LayoutBlock* LayoutBoxModelObject::ContainingBlockForAutoHeightDetection(
- Length logical_height) const {
+ const Length& logical_height) const {
// For percentage heights: The percentage is calculated with respect to the
// height of the generated box's containing block. If the height of the
// containing block is not specified explicitly (i.e., it depends on content
@@ -696,16 +696,18 @@ LayoutBlock* LayoutBoxModelObject::ContainingBlockForAutoHeightDetection(
return cb;
}
-bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight()
- const {
+bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight(
+ RegisterPercentageDescendant register_percentage_descendant) const {
// TODO(rego): Check if we can somehow reuse LayoutBlock::
// availableLogicalHeightForPercentageComputation() (see crbug.com/635655).
const LayoutBox* this_box = IsBox() ? ToLayoutBox(this) : nullptr;
- Length logical_height_length = StyleRef().LogicalHeight();
+ const Length& logical_height_length = StyleRef().LogicalHeight();
LayoutBlock* cb =
ContainingBlockForAutoHeightDetection(logical_height_length);
- if (logical_height_length.IsPercentOrCalc() && cb && IsBox())
+ if (register_percentage_descendant == kRegisterPercentageDescendant &&
+ logical_height_length.IsPercentOrCalc() && cb && IsBox()) {
cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(ToLayoutBox(this)));
+ }
if (this_box && this_box->IsFlexItem()) {
const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this_box))
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
index 6b383419fd8..a318f31ba70 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -46,12 +46,6 @@ enum PaintLayerType {
kForcedPaintLayer
};
-enum : uint32_t {
- kBackgroundPaintInGraphicsLayer = 1 << 0,
- kBackgroundPaintInScrollingContents = 1 << 1
-};
-using BackgroundPaintLocation = uint32_t;
-
// Modes for some of the line-related functions.
enum LinePositionMode {
kPositionOnContainingLine,
@@ -455,6 +449,17 @@ class CORE_EXPORT LayoutBoxModelObject : public LayoutObject {
virtual bool HasOverrideContainingBlockContentWidth() const { return false; }
virtual bool HasOverrideContainingBlockContentHeight() const { return false; }
+ // Returns the continuation associated with |this|.
+ // Returns nullptr if no continuation is associated with |this|.
+ //
+ // See the section about CONTINUATIONS AND ANONYMOUS LAYOUTBLOCKFLOWS in
+ // LayoutInline for more details about them.
+ //
+ // Our implementation uses a HashMap to store them to avoid paying the cost
+ // for each LayoutBoxModelObject (|continuationMap| in the cpp file).
+ // public only for NGOutOfFlowLayoutPart, otherwise protected.
+ LayoutBoxModelObject* Continuation() const;
+
protected:
// Compute absolute quads for |this|, but not any continuations. May only be
// called for objects which can be or have continuations, i.e. LayoutInline or
@@ -467,16 +472,6 @@ class CORE_EXPORT LayoutBoxModelObject : public LayoutObject {
LayoutPoint AdjustedPositionRelativeTo(const LayoutPoint&,
const Element*) const;
- // Returns the continuation associated with |this|.
- // Returns nullptr if no continuation is associated with |this|.
- //
- // See the section about CONTINUATIONS AND ANONYMOUS LAYOUTBLOCKFLOWS in
- // LayoutInline for more details about them.
- //
- // Our implementation uses a HashMap to store them to avoid paying the cost
- // for each LayoutBoxModelObject (|continuationMap| in the cpp file).
- LayoutBoxModelObject* Continuation() const;
-
// Set the next link in the continuation chain.
//
// See continuation above for more details.
@@ -489,9 +484,14 @@ class CORE_EXPORT LayoutBoxModelObject : public LayoutObject {
LayoutRect LocalCaretRectForEmptyElement(LayoutUnit width,
LayoutUnit text_indent_offset) const;
- bool HasAutoHeightOrContainingBlockWithAutoHeight() const;
+ enum RegisterPercentageDescendant {
+ kDontRegisterPercentageDescendant,
+ kRegisterPercentageDescendant,
+ };
+ bool HasAutoHeightOrContainingBlockWithAutoHeight(
+ RegisterPercentageDescendant = kRegisterPercentageDescendant) const;
LayoutBlock* ContainingBlockForAutoHeightDetection(
- Length logical_height) const;
+ const Length& logical_height) const;
void AddOutlineRectsForNormalChildren(Vector<LayoutRect>&,
const LayoutPoint& additional_offset,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
index feda6521713..13af1a91127 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
@@ -327,7 +327,7 @@ TEST_P(LayoutBoxTest, ControlClip) {
}
TEST_P(LayoutBoxTest, LocalVisualRectWithMask) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -344,7 +344,7 @@ TEST_P(LayoutBoxTest, LocalVisualRectWithMask) {
}
TEST_P(LayoutBoxTest, LocalVisualRectWithMaskAndOverflowClip) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -362,7 +362,7 @@ TEST_P(LayoutBoxTest, LocalVisualRectWithMaskAndOverflowClip) {
}
TEST_P(LayoutBoxTest, LocalVisualRectWithMaskWithOutset) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -380,7 +380,7 @@ TEST_P(LayoutBoxTest, LocalVisualRectWithMaskWithOutset) {
}
TEST_P(LayoutBoxTest, LocalVisualRectWithMaskWithOutsetAndOverflowClip) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
index 228b90affdf..bdad70e953c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
@@ -303,8 +303,8 @@ static LayoutUnit MarginWidthForChild(LayoutBox* child) {
// A margin basically has three types: fixed, percentage, and auto (variable).
// Auto and percentage margins simply become 0 when computing min/max width.
// Fixed margins can be added in as is.
- Length margin_left = child->StyleRef().MarginLeft();
- Length margin_right = child->StyleRef().MarginRight();
+ const Length& margin_left = child->StyleRef().MarginLeft();
+ const Length& margin_right = child->StyleRef().MarginRight();
LayoutUnit margin;
if (margin_left.IsFixed())
margin += margin_left.Value();
@@ -457,7 +457,7 @@ void LayoutDeprecatedFlexibleBox::UpdateBlockLayout(bool relayout_children) {
LayoutPositionedObjects(relayout_children || IsDocumentElement());
- ComputeOverflow(old_client_after_edge);
+ ComputeLayoutOverflow(old_client_after_edge);
}
UpdateAfterLayout();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
index f70000471da..c311e3576c5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
@@ -44,6 +44,7 @@ class LayoutDeprecatedFlexibleBox final : public LayoutBlock {
void LayoutVerticalBox(bool relayout_children);
bool IsDeprecatedFlexibleBox() const override { return true; }
+ bool IsFlexibleBoxIncludingDeprecatedAndNG() const override { return true; }
bool IsStretchingChildren() const { return stretching_children_; }
void PlaceChild(LayoutBox* child, const LayoutPoint& location);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc
index 2cdbd8328f9..2291e0deac4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc
@@ -92,14 +92,14 @@ void LayoutEmbeddedObject::UpdateLayout() {
UpdateLogicalWidth();
UpdateLogicalHeight();
- overflow_.reset();
- AddVisualEffectOverflow();
+ ClearLayoutOverflow();
UpdateAfterLayout();
if (!GetEmbeddedContentView() && GetFrameView())
GetFrameView()->AddPartToUpdate(*this);
+ ClearSelfNeedsLayoutOverflowRecalc();
ClearNeedsLayout();
}
@@ -111,6 +111,7 @@ CompositingReasons LayoutEmbeddedObject::AdditionalCompositingReasons() const {
void LayoutEmbeddedObject::ComputeIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ DCHECK(!ShouldApplySizeContainment());
FrameView* frame_view = ChildFrameView();
if (frame_view && frame_view->GetIntrinsicSizingInfo(intrinsic_sizing_info)) {
// Handle zoom & vertical writing modes here, as the embedded document
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
index e5b45b1b73f..1877a133795 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -41,8 +41,8 @@ void LayoutFieldset::ComputePreferredLogicalWidths() {
if (LayoutBox* legend = FindInFlowLegend()) {
int legend_min_width = legend->MinPreferredLogicalWidth().ToInt();
- Length legend_margin_left = legend->StyleRef().MarginLeft();
- Length legend_margin_right = legend->StyleRef().MarginRight();
+ const Length& legend_margin_left = legend->StyleRef().MarginLeft();
+ const Length& legend_margin_right = legend->StyleRef().MarginRight();
if (legend_margin_left.IsFixed())
legend_min_width += legend_margin_left.Value();
@@ -173,4 +173,14 @@ void LayoutFieldset::PaintMask(const PaintInfo& paint_info,
FieldsetPainter(*this).PaintMask(paint_info, paint_offset);
}
+bool LayoutFieldset::BackgroundIsKnownToBeOpaqueInRect(
+ const LayoutRect& local_rect) const {
+ // If the field set has a legend, then it probably does not completely fill
+ // its background.
+ if (FindInFlowLegend())
+ return false;
+
+ return LayoutBlockFlow::BackgroundIsKnownToBeOpaqueInRect(local_rect);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h
index af5bfad88c6..9079019c86f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h
@@ -39,6 +39,8 @@ class LayoutFieldset final : public LayoutBlockFlow {
bool CreatesNewFormattingContext() const final { return true; }
+ bool BackgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override;
+
private:
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectFieldset || LayoutBlockFlow::IsOfType(type);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index 8b3de628017..f17f377b405 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -84,6 +84,8 @@ void LayoutFlexibleBox::ComputeIntrinsicLogicalWidths(
LayoutUnit min_preferred_logical_width;
LayoutUnit max_preferred_logical_width;
+ if (child->NeedsPreferredWidthsRecalculation())
+ child->SetPreferredLogicalWidthsDirty();
ComputeChildPreferredLogicalWidths(*child, min_preferred_logical_width,
max_preferred_logical_width);
DCHECK_GE(min_preferred_logical_width, LayoutUnit());
@@ -134,7 +136,7 @@ float LayoutFlexibleBox::CountIntrinsicSizeForAlgorithmChange(
// item.
if (IsColumnFlow())
return previous_max_content_flex_fraction;
- Length flex_basis = child->StyleRef().FlexBasis();
+ const Length& flex_basis = child->StyleRef().FlexBasis();
float flex_grow = child->StyleRef().FlexGrow();
// A flex-basis of auto will lead to a max-content flex fraction of zero, so
// just like an inflexible item it would compute to a size of max-content, so
@@ -280,6 +282,38 @@ void LayoutFlexibleBox::RemoveChild(LayoutObject* child) {
intrinsic_size_along_main_axis_.erase(child);
}
+bool LayoutFlexibleBox::HitTestChildren(
+ HitTestResult& result,
+ const HitTestLocation& location_in_container,
+ const LayoutPoint& accumulated_offset,
+ HitTestAction hit_test_action) {
+ if (hit_test_action != kHitTestForeground)
+ return false;
+
+ LayoutPoint scrolled_offset(HasOverflowClip()
+ ? accumulated_offset - ScrolledContentOffset()
+ : accumulated_offset);
+
+ for (LayoutBox* child = LastChildBox(); child;
+ child = child->PreviousSiblingBox()) {
+ if (child->HasSelfPaintingLayer())
+ continue;
+
+ LayoutPoint child_point =
+ FlipForWritingModeForChild(child, scrolled_offset);
+
+ bool child_hit =
+ child->HitTestAllPhases(result, location_in_container, child_point);
+ if (child_hit) {
+ UpdateHitTestResult(
+ result, FlipForWritingMode(ToLayoutPoint(
+ location_in_container.Point() - accumulated_offset)));
+ return true;
+ }
+ }
+ return false;
+}
+
void LayoutFlexibleBox::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
LayoutBlock::StyleDidChange(diff, old_style);
@@ -353,7 +387,7 @@ void LayoutFlexibleBox::UpdateBlockLayout(bool relayout_children) {
// FIXME: css3/flexbox/repaint-rtl-column.html seems to issue paint
// invalidations for more overflow than it needs to.
- ComputeOverflow(ClientLogicalBottomAfterRepositioning());
+ ComputeLayoutOverflow(ClientLogicalBottomAfterRepositioning());
}
// We have to reset this, because changes to our ancestors' style can affect
@@ -645,17 +679,14 @@ bool LayoutFlexibleBox::UseChildAspectRatio(const LayoutBox& child) const {
// We can't compute a ratio in this case.
return false;
}
- Length cross_size;
- if (IsHorizontalFlow())
- cross_size = child.StyleRef().Height();
- else
- cross_size = child.StyleRef().Width();
+ const Length& cross_size =
+ IsHorizontalFlow() ? child.StyleRef().Height() : child.StyleRef().Width();
return CrossAxisLengthIsDefinite(child, cross_size);
}
LayoutUnit LayoutFlexibleBox::ComputeMainSizeFromAspectRatioUsing(
const LayoutBox& child,
- Length cross_size_length) const {
+ const Length& cross_size_length) const {
DCHECK(HasAspectRatio(child));
DCHECK_NE(child.IntrinsicSize().Height(), 0);
@@ -895,10 +926,11 @@ bool LayoutFlexibleBox::UpdateAutoMarginsInCrossAxis(
DCHECK_GE(available_alignment_space, LayoutUnit());
bool is_horizontal = IsHorizontalFlow();
- Length top_or_left = is_horizontal ? child.StyleRef().MarginTop()
- : child.StyleRef().MarginLeft();
- Length bottom_or_right = is_horizontal ? child.StyleRef().MarginBottom()
- : child.StyleRef().MarginRight();
+ const Length& top_or_left = is_horizontal ? child.StyleRef().MarginTop()
+ : child.StyleRef().MarginLeft();
+ const Length& bottom_or_right = is_horizontal
+ ? child.StyleRef().MarginBottom()
+ : child.StyleRef().MarginRight();
if (top_or_left.IsAuto() && bottom_or_right.IsAuto()) {
AdjustAlignmentForChild(child, available_alignment_space / 2);
if (is_horizontal) {
@@ -947,7 +979,7 @@ bool LayoutFlexibleBox::UpdateAutoMarginsInCrossAxis(
return false;
}
-LayoutUnit LayoutFlexibleBox::ComputeChildMarginValue(Length margin) {
+LayoutUnit LayoutFlexibleBox::ComputeChildMarginValue(const Length& margin) {
// When resolving the margins, we use the content size for resolving percent
// and calc (for percents in calc expressions) margins. Fortunately, percent
// margins are always computed with respect to the block's width, even for
@@ -989,8 +1021,8 @@ MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
const LayoutBox& child) const {
MinMaxSize sizes{LayoutUnit(), LayoutUnit::Max()};
- Length max = IsHorizontalFlow() ? child.StyleRef().MaxWidth()
- : child.StyleRef().MaxHeight();
+ const Length& max = IsHorizontalFlow() ? child.StyleRef().MaxWidth()
+ : child.StyleRef().MaxHeight();
if (max.IsSpecifiedOrIntrinsic()) {
sizes.max_size = ComputeMainAxisExtentForChild(child, kMaxSize, max);
if (sizes.max_size == -1)
@@ -998,8 +1030,8 @@ MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
DCHECK_GE(sizes.max_size, LayoutUnit());
}
- Length min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
- : child.StyleRef().MinHeight();
+ const Length& min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
+ : child.StyleRef().MinHeight();
if (min.IsSpecifiedOrIntrinsic()) {
sizes.min_size = ComputeMainAxisExtentForChild(child, kMinSize, min);
// computeMainAxisExtentForChild can return -1 when the child has a
@@ -1020,8 +1052,8 @@ MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
if (sizes.max_size != -1 && content_size > sizes.max_size)
content_size = sizes.max_size;
- Length main_size = IsHorizontalFlow() ? child.StyleRef().Width()
- : child.StyleRef().Height();
+ const Length& main_size = IsHorizontalFlow() ? child.StyleRef().Width()
+ : child.StyleRef().Height();
if (MainAxisLengthIsDefinite(child, main_size)) {
LayoutUnit resolved_main_size = ComputeMainAxisExtentForChild(
child, kMainOrPreferredSize, main_size);
@@ -1032,9 +1064,9 @@ MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
sizes.min_size = std::min(specified_size, content_size);
} else if (UseChildAspectRatio(child)) {
- Length cross_size_length = IsHorizontalFlow()
- ? child.StyleRef().Height()
- : child.StyleRef().Width();
+ const Length& cross_size_length = IsHorizontalFlow()
+ ? child.StyleRef().Height()
+ : child.StyleRef().Width();
LayoutUnit transferred_size =
ComputeMainSizeFromAspectRatioUsing(child, cross_size_length);
transferred_size = AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
@@ -1094,10 +1126,10 @@ bool LayoutFlexibleBox::UseOverrideLogicalHeightForPerentageResolution(
LayoutUnit LayoutFlexibleBox::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
const LayoutBox& child,
LayoutUnit child_size) const {
- Length cross_min = IsHorizontalFlow() ? child.StyleRef().MinHeight()
- : child.StyleRef().MinWidth();
- Length cross_max = IsHorizontalFlow() ? child.StyleRef().MaxHeight()
- : child.StyleRef().MaxWidth();
+ const Length& cross_min = IsHorizontalFlow() ? child.StyleRef().MinHeight()
+ : child.StyleRef().MinWidth();
+ const Length& cross_max = IsHorizontalFlow() ? child.StyleRef().MaxHeight()
+ : child.StyleRef().MaxWidth();
if (CrossAxisLengthIsDefinite(child, cross_max)) {
LayoutUnit max_value =
@@ -1343,10 +1375,12 @@ bool LayoutFlexibleBox::ChildHasIntrinsicMainAxisSize(
bool result = false;
if (IsHorizontalFlow() != child.StyleRef().IsHorizontalWritingMode()) {
Length child_flex_basis = FlexBasisForChild(child);
- Length child_min_size = IsHorizontalFlow() ? child.StyleRef().MinWidth()
- : child.StyleRef().MinHeight();
- Length child_max_size = IsHorizontalFlow() ? child.StyleRef().MaxWidth()
- : child.StyleRef().MaxHeight();
+ const Length& child_min_size = IsHorizontalFlow()
+ ? child.StyleRef().MinWidth()
+ : child.StyleRef().MinHeight();
+ const Length& child_max_size = IsHorizontalFlow()
+ ? child.StyleRef().MaxWidth()
+ : child.StyleRef().MaxHeight();
if (child_flex_basis.IsIntrinsic() || child_min_size.IsIntrinsicOrAuto() ||
child_max_size.IsIntrinsic())
result = true;
@@ -1481,9 +1515,8 @@ void LayoutFlexibleBox::LayoutColumnReverse(FlexItemVectorView& children,
const StyleContentAlignmentData justify_content =
FlexLayoutAlgorithm::ResolvedJustifyContent(StyleRef());
- // This is similar to the logic in layoutAndPlaceChildren, except we place
- // the children starting from the end of the flexbox. We also don't need to
- // layout anything since we're just moving the children to a new position.
+ // This is similar to the logic in FlexLine::ComputeLineItemsPosition, except
+ // we place the children starting from the end of the flexbox.
LayoutUnit main_axis_offset = LogicalHeight() - FlowAwareContentInsetEnd();
main_axis_offset -= FlexLayoutAlgorithm::InitialContentPositionOffset(
available_free_space, justify_content, children.size());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
index ab18de0f4ba..0d340bb8f49 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -51,6 +51,8 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
const char* GetName() const override { return "LayoutFlexibleBox"; }
bool IsFlexibleBox() const final { return true; }
+ bool IsFlexibleBoxIncludingNG() const final { return true; }
+ bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; }
void UpdateBlockLayout(bool relayout_children) final;
LayoutUnit BaselinePosition(
@@ -101,6 +103,11 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
LayoutUnit& min_logical_width,
LayoutUnit& max_logical_width) const override;
+ bool HitTestChildren(HitTestResult&,
+ const HitTestLocation& location_in_container,
+ const LayoutPoint& accumulated_offset,
+ HitTestAction) override;
+
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void RemoveChild(LayoutObject*) override;
@@ -140,7 +147,7 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
bool UseChildAspectRatio(const LayoutBox& child) const;
LayoutUnit ComputeMainSizeFromAspectRatioUsing(
const LayoutBox& child,
- Length cross_size_length) const;
+ const Length& cross_size_length) const;
void SetFlowAwareLocationForChild(LayoutBox& child, const LayoutPoint&);
LayoutUnit ComputeInnerFlexBaseSizeForChild(
LayoutBox& child,
@@ -165,7 +172,7 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
void RepositionLogicalHeightDependentFlexItems(Vector<FlexLine>&);
LayoutUnit ClientLogicalBottomAfterRepositioning();
- LayoutUnit ComputeChildMarginValue(Length margin);
+ LayoutUnit ComputeChildMarginValue(const Length& margin);
void PrepareOrderIteratorAndMargins();
MinMaxSize ComputeMinAndMaxSizesForChild(const FlexLayoutAlgorithm& algorithm,
const LayoutBox& child) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
index 3c5b54027e1..b43680c3464 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -138,7 +138,7 @@ void LayoutFrameSet::LayOutAxis(GridAxis& axis,
if (grid[i].IsAbsolute()) {
long long temp_product =
static_cast<long long>(grid_layout[i]) * remaining_fixed;
- grid_layout[i] = temp_product / total_fixed;
+ grid_layout[i] = static_cast<int>(temp_product / total_fixed);
remaining_len -= grid_layout[i];
}
}
@@ -158,7 +158,7 @@ void LayoutFrameSet::LayOutAxis(GridAxis& axis,
if (grid[i].IsPercentage()) {
long long temp_product =
static_cast<long long>(grid_layout[i]) * remaining_percent;
- grid_layout[i] = temp_product / total_percent;
+ grid_layout[i] = static_cast<int>(temp_product / total_percent);
remaining_len -= grid_layout[i];
}
}
@@ -208,7 +208,7 @@ void LayoutFrameSet::LayOutAxis(GridAxis& axis,
if (grid[i].IsPercentage()) {
long long temp_product =
static_cast<long long>(grid_layout[i]) * remaining_percent;
- change_percent = temp_product / total_percent;
+ change_percent = static_cast<int>(temp_product / total_percent);
grid_layout[i] += change_percent;
remaining_len -= change_percent;
}
@@ -224,7 +224,7 @@ void LayoutFrameSet::LayOutAxis(GridAxis& axis,
if (grid[i].IsAbsolute()) {
long long temp_product =
static_cast<long long>(grid_layout[i]) * remaining_fixed;
- change_fixed = temp_product / total_fixed;
+ change_fixed = static_cast<int>(temp_product / total_fixed);
grid_layout[i] += change_fixed;
remaining_len -= change_fixed;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
index d67642b5243..0b25873f1dc 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
@@ -520,9 +520,19 @@ TEST_F(LayoutGeometryMapTest, FloatUnderInlineLayer) {
rgm.PushMappingsToAncestor(container->Layer(), nullptr);
rgm.PushMappingsToAncestor(span->Layer(), container->Layer());
rgm.PushMappingsToAncestor(layer_under_float->Layer(), span->Layer());
- EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
- EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
- RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // LayoutNG inline-level floats are children of their inline-level
+ // containers. As such they are positioned relative to their inline-level
+ // container, (and shifted by an additional 200,100 in this case).
+ EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f),
+ RectFromQuad(rgm.MapToAncestor(rect, container)));
+ EXPECT_EQ(FloatRect(263.0f, 154.0f, 10.0f, 8.0f),
+ RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+ } else {
+ EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
+ EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
+ RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+ }
rgm.PopMappingsToAncestor(span->Layer());
EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f),
@@ -531,9 +541,16 @@ TEST_F(LayoutGeometryMapTest, FloatUnderInlineLayer) {
RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
rgm.PushMappingsToAncestor(floating, span);
- EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
- EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
- RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f),
+ RectFromQuad(rgm.MapToAncestor(rect, container)));
+ EXPECT_EQ(FloatRect(263.0f, 154.0f, 10.0f, 8.0f),
+ RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+ } else {
+ EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
+ EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
+ RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_grid.cc b/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
index 7b734e3d506..edf0948c356 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -374,7 +374,7 @@ void LayoutGrid::UpdateBlockLayout(bool relayout_children) {
LayoutPositionedObjects(relayout_children || IsDocumentElement());
- ComputeOverflow(old_client_after_edge);
+ ComputeLayoutOverflow(old_client_after_edge);
}
UpdateAfterLayout();
@@ -614,9 +614,10 @@ size_t LayoutGrid::ComputeAutoRepeatTracksCount(
bool has_definite_max_track_sizing_function =
auto_track_size.MaxTrackBreadth().IsLength() &&
!auto_track_size.MaxTrackBreadth().IsContentSized();
- auto track_length = has_definite_max_track_sizing_function
- ? auto_track_size.MaxTrackBreadth().length()
- : auto_track_size.MinTrackBreadth().length();
+ const Length& track_length =
+ has_definite_max_track_sizing_function
+ ? auto_track_size.MaxTrackBreadth().length()
+ : auto_track_size.MinTrackBreadth().length();
auto_repeat_tracks_size +=
ValueForLength(track_length, available_size.value());
}
@@ -649,13 +650,15 @@ size_t LayoutGrid::ComputeAutoRepeatTracksCount(
// Add gutters as if there where only 1 auto repeat track. Gaps between auto
// repeat tracks will be added later when computing the repetitions.
LayoutUnit gap_size = GridGap(direction, available_size);
- tracks_size += gap_size * track_sizes.size();
+ tracks_size +=
+ gap_size * (track_sizes.size() + auto_repeat_track_list_length - 1);
LayoutUnit free_space = available_size.value() - tracks_size;
if (free_space <= 0)
return auto_repeat_track_list_length;
- LayoutUnit auto_repeat_size_with_gap = auto_repeat_tracks_size + gap_size;
+ LayoutUnit auto_repeat_size_with_gap =
+ auto_repeat_tracks_size + gap_size * auto_repeat_track_list_length;
size_t repetitions = 1 + (free_space / auto_repeat_size_with_gap).ToInt();
free_space -= auto_repeat_size_with_gap * (repetitions - 1);
@@ -918,8 +921,8 @@ void LayoutGrid::PopulateExplicitGridAndOrderIterator(Grid& grid) const {
} else {
// Grow the grid for items with a definite row span, getting the largest
// such span.
- size_t span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
- *Style(), *child, kForRows);
+ size_t span_size =
+ GridPositionsResolver::SpanSizeForAutoPlacedItem(*child, kForRows);
maximum_row_index = std::max(maximum_row_index, span_size);
}
@@ -931,8 +934,8 @@ void LayoutGrid::PopulateExplicitGridAndOrderIterator(Grid& grid) const {
} else {
// Grow the grid for items with a definite column span, getting the
// largest such span.
- size_t span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
- *Style(), *child, kForColumns);
+ size_t span_size =
+ GridPositionsResolver::SpanSizeForAutoPlacedItem(*child, kForColumns);
maximum_column_index = std::max(maximum_column_index, span_size);
}
}
@@ -952,7 +955,7 @@ LayoutGrid::CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
specified_direction == kForColumns ? kForRows : kForColumns;
const size_t end_of_cross_direction = grid.NumTracks(cross_direction);
size_t cross_direction_span_size =
- GridPositionsResolver::SpanSizeForAutoPlacedItem(*Style(), grid_item,
+ GridPositionsResolver::SpanSizeForAutoPlacedItem(grid_item,
cross_direction);
GridSpan cross_direction_positions = GridSpan::TranslatedDefiniteGridSpan(
end_of_cross_direction,
@@ -987,7 +990,7 @@ void LayoutGrid::PlaceSpecifiedMajorAxisItemsOnGrid(
.IsTranslatedDefinite());
size_t minor_axis_span_size =
GridPositionsResolver::SpanSizeForAutoPlacedItem(
- *Style(), *auto_grid_item, AutoPlacementMinorAxisDirection());
+ *auto_grid_item, AutoPlacementMinorAxisDirection());
unsigned major_axis_initial_position = major_axis_positions.StartLine();
auto iterator = grid.CreateIterator(
@@ -997,11 +1000,7 @@ void LayoutGrid::PlaceSpecifiedMajorAxisItemsOnGrid(
: minor_axis_cursors.at(major_axis_initial_position));
std::unique_ptr<GridArea> empty_grid_area = iterator->NextEmptyGridArea(
major_axis_positions.IntegerSpan(), minor_axis_span_size);
- if (!empty_grid_area) {
- empty_grid_area = CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
- grid, *auto_grid_item, AutoPlacementMajorAxisDirection(),
- major_axis_positions);
- }
+ DCHECK(empty_grid_area);
grid.Insert(*auto_grid_item, *empty_grid_area);
@@ -1040,7 +1039,7 @@ void LayoutGrid::PlaceAutoMajorAxisItemOnGrid(
.IsTranslatedDefinite());
size_t major_axis_span_size =
GridPositionsResolver::SpanSizeForAutoPlacedItem(
- *Style(), grid_item, AutoPlacementMajorAxisDirection());
+ grid_item, AutoPlacementMajorAxisDirection());
const size_t end_of_major_axis =
grid.NumTracks(AutoPlacementMajorAxisDirection());
@@ -1076,7 +1075,7 @@ void LayoutGrid::PlaceAutoMajorAxisItemOnGrid(
} else {
size_t minor_axis_span_size =
GridPositionsResolver::SpanSizeForAutoPlacedItem(
- *Style(), grid_item, AutoPlacementMinorAxisDirection());
+ grid_item, AutoPlacementMinorAxisDirection());
for (size_t major_axis_index = major_axis_auto_placement_cursor;
major_axis_index < end_of_major_axis; ++major_axis_index) {
@@ -1085,25 +1084,24 @@ void LayoutGrid::PlaceAutoMajorAxisItemOnGrid(
minor_axis_auto_placement_cursor);
empty_grid_area = iterator->NextEmptyGridArea(major_axis_span_size,
minor_axis_span_size);
+ DCHECK(empty_grid_area);
+
+ // Check that it fits in the minor axis direction, as we shouldn't grow
+ // in that direction here (it was already managed in
+ // populateExplicitGridAndOrderIterator()).
+ size_t minor_axis_final_position_index =
+ AutoPlacementMinorAxisDirection() == kForColumns
+ ? empty_grid_area->columns.EndLine()
+ : empty_grid_area->rows.EndLine();
+ const size_t end_of_minor_axis =
+ grid.NumTracks(AutoPlacementMinorAxisDirection());
+ if (minor_axis_final_position_index <= end_of_minor_axis)
+ break;
- if (empty_grid_area) {
- // Check that it fits in the minor axis direction, as we shouldn't grow
- // in that direction here (it was already managed in
- // populateExplicitGridAndOrderIterator()).
- size_t minor_axis_final_position_index =
- AutoPlacementMinorAxisDirection() == kForColumns
- ? empty_grid_area->columns.EndLine()
- : empty_grid_area->rows.EndLine();
- const size_t end_of_minor_axis =
- grid.NumTracks(AutoPlacementMinorAxisDirection());
- if (minor_axis_final_position_index <= end_of_minor_axis)
- break;
-
- // Discard empty grid area as it does not fit in the minor axis
- // direction. We don't need to create a new empty grid area yet as we
- // might find a valid one in the next iteration.
- empty_grid_area = nullptr;
- }
+ // Discard empty grid area as it does not fit in the minor axis
+ // direction. We don't need to create a new empty grid area yet as we
+ // might find a valid one in the next iteration.
+ empty_grid_area.reset();
// As we're moving to the next track in the major axis we should reset the
// auto-placement cursor in the minor axis.
@@ -1270,7 +1268,7 @@ void LayoutGrid::LayoutGridItems() {
DCHECK_LT(area.rows.StartLine(),
track_sizing_algorithm_.Tracks(kForRows).size());
#endif
- child->SetLogicalLocation(FindChildLogicalPosition(*child));
+ SetLogicalPositionForChild(*child);
// Keep track of children overflowing their grid area as we might need to
// paint them even if the grid-area is not visible. Using physical
@@ -1332,10 +1330,8 @@ void LayoutGrid::LayoutPositionedObjects(bool relayout_children,
LayoutPositionedObject(child, relayout_children, info);
- if (child->IsGridItem() ||
- !HasStaticPositionForChild(*child, kForColumns) ||
- !HasStaticPositionForChild(*child, kForRows))
- child->SetLogicalLocation(FindChildLogicalPosition(*child));
+ SetLogicalOffsetForChild(*child, kForColumns);
+ SetLogicalOffsetForChild(*child, kForRows);
}
}
@@ -1546,8 +1542,8 @@ void LayoutGrid::UpdateAutoMarginsInRowAxisIfNeeded(LayoutBox& child) {
if (available_alignment_space <= 0)
return;
- Length margin_start = child.StyleRef().MarginStartUsing(StyleRef());
- Length margin_end = child.StyleRef().MarginEndUsing(StyleRef());
+ const Length& margin_start = child.StyleRef().MarginStartUsing(StyleRef());
+ const Length& margin_end = child.StyleRef().MarginEndUsing(StyleRef());
if (margin_start.IsAuto() && margin_end.IsAuto()) {
child.SetMarginStart(available_alignment_space / 2, Style());
child.SetMarginEnd(available_alignment_space / 2, Style());
@@ -1570,8 +1566,8 @@ void LayoutGrid::UpdateAutoMarginsInColumnAxisIfNeeded(LayoutBox& child) {
if (available_alignment_space <= 0)
return;
- Length margin_before = child.StyleRef().MarginBeforeUsing(StyleRef());
- Length margin_after = child.StyleRef().MarginAfterUsing(StyleRef());
+ const Length& margin_before = child.StyleRef().MarginBeforeUsing(StyleRef());
+ const Length& margin_after = child.StyleRef().MarginAfterUsing(StyleRef());
if (margin_before.IsAuto() && margin_after.IsAuto()) {
child.SetMarginBefore(available_alignment_space / 2, Style());
child.SetMarginAfter(available_alignment_space / 2, Style());
@@ -1924,16 +1920,6 @@ LayoutUnit LayoutGrid::RowAxisOffsetForChild(const LayoutBox& child) const {
return LayoutUnit();
}
-bool LayoutGrid::GridPositionIsAutoForOutOfFlow(
- GridPosition position,
- GridTrackSizingDirection direction) const {
- return (position.IsAuto() ||
- (position.IsNamedGridArea() &&
- !NamedLineCollection::IsValidNamedLineOrArea(
- position.NamedGridLine(), StyleRef(),
- GridPositionsResolver::InitialPositionSide(direction))));
-}
-
LayoutUnit LayoutGrid::ResolveAutoStartGridPosition(
GridTrackSizingDirection direction) const {
if (direction == kForRows || StyleRef().IsLeftToRightDirection())
@@ -1996,10 +1982,9 @@ LayoutUnit LayoutGrid::GridAreaBreadthForOutOfFlowChild(
: child.StyleRef().GridRowEnd();
bool start_is_auto =
- GridPositionIsAutoForOutOfFlow(start_position, direction) ||
- start_line < 0 || start_line > last_line;
- bool end_is_auto = GridPositionIsAutoForOutOfFlow(end_position, direction) ||
- end_line < 0 || end_line > last_line;
+ start_position.IsAuto() || start_line < 0 || start_line > last_line;
+ bool end_is_auto =
+ end_position.IsAuto() || end_line < 0 || end_line > last_line;
if (start_is_auto && end_is_auto)
return is_row_axis ? ClientLogicalWidth() : ClientLogicalHeight();
@@ -2039,9 +2024,11 @@ LayoutUnit LayoutGrid::GridAreaBreadthForOutOfFlowChild(
return std::max(end - start, LayoutUnit());
}
-LayoutUnit LayoutGrid::LogicalOffsetForChild(const LayoutBox& child,
- GridTrackSizingDirection direction,
- LayoutUnit track_breadth) const {
+LayoutUnit LayoutGrid::LogicalOffsetForOutOfFlowChild(
+ const LayoutBox& child,
+ GridTrackSizingDirection direction,
+ LayoutUnit track_breadth) const {
+ DCHECK(child.IsOutOfFlowPositioned());
if (HasStaticPositionForChild(child, direction))
return LayoutUnit();
@@ -2083,7 +2070,7 @@ void LayoutGrid::GridAreaPositionForOutOfFlowChild(
auto& positions = is_row_axis ? column_positions_ : row_positions_;
start = positions[line.value()];
}
- start += LogicalOffsetForChild(child, direction, track_breadth);
+ start += LogicalOffsetForOutOfFlowChild(child, direction, track_breadth);
end = start + track_breadth;
}
@@ -2307,10 +2294,41 @@ LayoutUnit LayoutGrid::TranslateRTLCoordinate(LayoutUnit coordinate) const {
return right_grid_edge_position + alignment_offset - coordinate;
}
-LayoutPoint LayoutGrid::FindChildLogicalPosition(const LayoutBox& child) const {
- LayoutUnit column_axis_offset = ColumnAxisOffsetForChild(child);
+// TODO: SetLogicalPositionForChild has only one caller, consider its
+// refactoring in the future.
+void LayoutGrid::SetLogicalPositionForChild(LayoutBox& child) const {
+ // "In the positioning phase [...] calculations are performed according to the
+ // writing mode of the containing block of the box establishing the orthogonal
+ // flow." However, 'setLogicalPosition' will only take into account the
+ // child's writing-mode, so the position may need to be transposed.
+ LayoutPoint child_location(LogicalOffsetForChild(child, kForColumns),
+ LogicalOffsetForChild(child, kForRows));
+ child.SetLogicalLocation(GridLayoutUtils::IsOrthogonalChild(*this, child)
+ ? child_location.TransposedPoint()
+ : child_location);
+}
+
+void LayoutGrid::SetLogicalOffsetForChild(
+ LayoutBox& child,
+ GridTrackSizingDirection direction) const {
+ if (!child.IsGridItem() && HasStaticPositionForChild(child, direction))
+ return;
+ // 'SetLogicalLeft' and 'SetLogicalTop' only take into account the child's
+ // writing-mode, that's why 'FlowAwareDirectionForChild' is needed.
+ if (GridLayoutUtils::FlowAwareDirectionForChild(*this, child, direction) ==
+ kForColumns)
+ child.SetLogicalLeft(LogicalOffsetForChild(child, direction));
+ else
+ child.SetLogicalTop(LogicalOffsetForChild(child, direction));
+}
+
+LayoutUnit LayoutGrid::LogicalOffsetForChild(
+ const LayoutBox& child,
+ GridTrackSizingDirection direction) const {
+ if (direction == kForRows) {
+ return ColumnAxisOffsetForChild(child);
+ }
LayoutUnit row_axis_offset = RowAxisOffsetForChild(child);
- bool is_orthogonal_child = GridLayoutUtils::IsOrthogonalChild(*this, child);
// We stored column_position_'s data ignoring the direction, hence we might
// need now to translate positions from RTL to LTR, as it's more convenient
// for painting.
@@ -2319,17 +2337,11 @@ LayoutPoint LayoutGrid::FindChildLogicalPosition(const LayoutBox& child) const {
(child.IsOutOfFlowPositioned()
? TranslateOutOfFlowRTLCoordinate(child, row_axis_offset)
: TranslateRTLCoordinate(row_axis_offset)) -
- (is_orthogonal_child ? child.LogicalHeight() : child.LogicalWidth());
+ (GridLayoutUtils::IsOrthogonalChild(*this, child)
+ ? child.LogicalHeight()
+ : child.LogicalWidth());
}
-
- // "In the positioning phase [...] calculations are performed according to the
- // writing mode of the containing block of the box establishing the orthogonal
- // flow." However, the resulting LayoutPoint will be used in
- // 'setLogicalPosition' in order to set the child's logical position, which
- // will only take into account the child's writing-mode.
- LayoutPoint child_location(row_axis_offset, column_axis_offset);
- return is_orthogonal_child ? child_location.TransposedPoint()
- : child_location;
+ return row_axis_offset;
}
LayoutPoint LayoutGrid::GridAreaLogicalPosition(const GridArea& area) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_grid.h b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
index 8d08fb1feea..2b7897e82b8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
@@ -199,13 +199,11 @@ class LayoutGrid final : public LayoutBlock {
PositionedLayoutBehavior = kDefaultLayout) override;
void PopulateGridPositionsForDirection(GridTrackSizingDirection);
- bool GridPositionIsAutoForOutOfFlow(GridPosition,
- GridTrackSizingDirection) const;
LayoutUnit ResolveAutoStartGridPosition(GridTrackSizingDirection) const;
LayoutUnit ResolveAutoEndGridPosition(GridTrackSizingDirection) const;
- LayoutUnit LogicalOffsetForChild(const LayoutBox&,
- GridTrackSizingDirection,
- LayoutUnit) const;
+ LayoutUnit LogicalOffsetForOutOfFlowChild(const LayoutBox&,
+ GridTrackSizingDirection,
+ LayoutUnit) const;
LayoutUnit GridAreaBreadthForOutOfFlowChild(const LayoutBox&,
GridTrackSizingDirection);
void GridAreaPositionForOutOfFlowChild(const LayoutBox&,
@@ -230,7 +228,10 @@ class LayoutGrid final : public LayoutBlock {
const LayoutUnit& available_free_space,
unsigned number_of_grid_tracks);
LayoutPoint GridAreaLogicalPosition(const GridArea&) const;
- LayoutPoint FindChildLogicalPosition(const LayoutBox&) const;
+ void SetLogicalPositionForChild(LayoutBox&) const;
+ void SetLogicalOffsetForChild(LayoutBox&, GridTrackSizingDirection) const;
+ LayoutUnit LogicalOffsetForChild(const LayoutBox&,
+ GridTrackSizingDirection) const;
LayoutUnit GridAreaBreadthForChildIncludingAlignmentOffsets(
const LayoutBox&,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
index c3e989ede9d..d0d284554d7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
@@ -32,7 +32,7 @@ namespace blink {
class HTMLCanvasElement;
-class LayoutHTMLCanvas final : public LayoutReplaced {
+class CORE_EXPORT LayoutHTMLCanvas final : public LayoutReplaced {
public:
explicit LayoutHTMLCanvas(HTMLCanvasElement*);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc b/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc
index b13a56e2828..ca2683debc5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc
@@ -54,8 +54,7 @@ void LayoutIFrame::UpdateLayout() {
// No kids to layout as a replaced element.
UpdateLogicalHeight();
- overflow_.reset();
- AddVisualEffectOverflow();
+ ClearLayoutOverflow();
UpdateAfterLayout();
ClearNeedsLayout();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image.cc b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
index 44a4204a2f0..23fab7d4521 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
#include "third_party/blink/renderer/core/paint/image_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -57,21 +58,28 @@ bool CheckForOptimizedImagePolicy(const Document& document,
// Render the image as a placeholder image if the document does not have the
// 'legacy-image-formats' feature enabled, and the image is not one of the
// allowed formats.
- if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
- !document.IsFeatureEnabled(
- mojom::FeaturePolicyFeature::kLegacyImageFormats)) {
- if (!new_image->IsAcceptableContentType()) {
+ if (!new_image->IsAcceptableContentType()) {
+ document.CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature::kLegacyImageFormats);
+ if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
+ !document.IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kLegacyImageFormats,
+ ReportOptions::kReportOnFailure)) {
return true;
}
}
// Render the image as a placeholder image if the document does not have the
// 'unoptimized-images' feature enabled and the image is not
// sufficiently-well-compressed.
- if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
- !document.IsFeatureEnabled(
- mojom::FeaturePolicyFeature::kUnoptimizedImages)) {
- if (!new_image->IsAcceptableCompressionRatio())
+ if (!new_image->IsAcceptableCompressionRatio()) {
+ document.CountPotentialFeaturePolicyViolation(
+ mojom::FeaturePolicyFeature::kUnoptimizedImages);
+ if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
+ !document.IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kUnoptimizedImages,
+ ReportOptions::kReportOnFailure)) {
return true;
+ }
}
return false;
}
@@ -127,7 +135,7 @@ LayoutImage::~LayoutImage() = default;
void LayoutImage::WillBeDestroyed() {
DCHECK(image_resource_);
image_resource_->Shutdown();
- if (RuntimeEnabledFeatures::ElementTimingEnabled()) {
+ if (origin_trials::ElementTimingEnabled(&GetDocument())) {
if (LocalDOMWindow* window = GetDocument().domWindow())
ImageElementTiming::From(*window).NotifyWillBeDestroyed(this);
}
@@ -210,6 +218,23 @@ void LayoutImage::UpdateIntrinsicSizeIfNeeded(const LayoutSize& new_size) {
SetIntrinsicSize(new_size);
}
+bool LayoutImage::NeedsLayoutOnIntrinsicSizeChange() const {
+ // If the actual area occupied by the image has changed and it is not
+ // constrained by style then a layout is required.
+ bool image_size_is_constrained =
+ StyleRef().LogicalWidth().IsSpecified() &&
+ StyleRef().LogicalHeight().IsSpecified() &&
+ !HasAutoHeightOrContainingBlockWithAutoHeight(
+ kDontRegisterPercentageDescendant);
+ if (!image_size_is_constrained)
+ return true;
+ // FIXME: We only need to recompute the containing block's preferred size if
+ // the containing block's size depends on the image's size (i.e., the
+ // container uses shrink-to-fit sizing). There's no easy way to detect that
+ // shrink-to-fit is needed, always force a layout.
+ return HasRelativeLogicalWidth();
+}
+
void LayoutImage::InvalidatePaintAndMarkForLayoutIfNeeded(
CanDeferInvalidation defer) {
LayoutSize old_intrinsic_size = IntrinsicSize();
@@ -225,30 +250,14 @@ void LayoutImage::InvalidatePaintAndMarkForLayoutIfNeeded(
if (!ContainingBlock())
return;
- bool image_source_has_changed_size = old_intrinsic_size != new_intrinsic_size;
- if (image_source_has_changed_size)
+ if (old_intrinsic_size != new_intrinsic_size) {
SetPreferredLogicalWidthsDirty();
- // If the actual area occupied by the image has changed and it is not
- // constrained by style then a layout is required.
- bool image_size_is_constrained = StyleRef().LogicalWidth().IsSpecified() &&
- StyleRef().LogicalHeight().IsSpecified();
-
- // FIXME: We only need to recompute the containing block's preferred size if
- // the containing block's size depends on the image's size (i.e., the
- // container uses shrink-to-fit sizing). There's no easy way to detect that
- // shrink-to-fit is needed, always force a layout.
- bool containing_block_needs_to_recompute_preferred_size =
- StyleRef().LogicalWidth().IsPercentOrCalc() ||
- StyleRef().LogicalMaxWidth().IsPercentOrCalc() ||
- StyleRef().LogicalMinWidth().IsPercentOrCalc();
-
- if (image_source_has_changed_size &&
- (!image_size_is_constrained ||
- containing_block_needs_to_recompute_preferred_size)) {
- SetNeedsLayoutAndFullPaintInvalidation(
- layout_invalidation_reason::kSizeChanged);
- return;
+ if (NeedsLayoutOnIntrinsicSizeChange()) {
+ SetNeedsLayoutAndFullPaintInvalidation(
+ layout_invalidation_reason::kSizeChanged);
+ return;
+ }
}
SetShouldDoFullPaintInvalidationWithoutGeometryChange(
@@ -412,6 +421,7 @@ bool LayoutImage::OverrideIntrinsicSizingInfo(
void LayoutImage::ComputeIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ DCHECK(!ShouldApplySizeContainment());
if (!OverrideIntrinsicSizingInfo(intrinsic_sizing_info)) {
if (SVGImage* svg_image = EmbeddedSVGImage()) {
svg_image->GetIntrinsicSizingInfo(intrinsic_sizing_info);
@@ -504,8 +514,8 @@ void LayoutImage::UpdateAfterLayout() {
ValidateImagePolicies();
// Report violation of unsized-media policy.
- if (image_element->IsDefaultIntrinsicSize())
- media_element_parser_helpers::ReportUnsizedMediaViolation(this);
+ media_element_parser_helpers::ReportUnsizedMediaViolation(
+ this, image_element->IsDefaultIntrinsicSize());
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image.h b/chromium/third_party/blink/renderer/core/layout/layout_image.h
index 7db612ea834..a1827913e87 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.h
@@ -136,6 +136,7 @@ class CORE_EXPORT LayoutImage : public LayoutReplaced {
void InvalidatePaintAndMarkForLayoutIfNeeded(CanDeferInvalidation);
void UpdateIntrinsicSizeIfNeeded(const LayoutSize&);
+ bool NeedsLayoutOnIntrinsicSizeChange() const;
// Override intrinsic sizing info by HTMLImageElement "intrinsicsize"
// attribute if enabled and exists.
bool OverrideIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
index 2b2ca04c9c4..c2c301c2f88 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
@@ -144,7 +144,12 @@ void LayoutImageResource::UseBrokenImage() {
}
scoped_refptr<Image> LayoutImageResource::GetImage(
- const LayoutSize& container_size) const {
+ const IntSize& container_size) const {
+ return GetImage(FloatSize(container_size));
+}
+
+scoped_refptr<Image> LayoutImageResource::GetImage(
+ const FloatSize& container_size) const {
if (!cached_image_)
return Image::NullImage();
@@ -170,7 +175,7 @@ scoped_refptr<Image> LayoutImageResource::GetImage(
url = node->GetDocument().CompleteURL(url_string);
}
return SVGImageForContainer::Create(
- ToSVGImage(image), FloatSize(container_size),
+ ToSVGImage(image), container_size,
layout_object_->StyleRef().EffectiveZoom(), url);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
index ffd214d18ec..27ce0cc37a1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
@@ -56,7 +56,8 @@ class CORE_EXPORT LayoutImageResource
void ResetAnimation();
bool MaybeAnimated() const;
- virtual scoped_refptr<Image> GetImage(const LayoutSize&) const;
+ virtual scoped_refptr<Image> GetImage(const FloatSize&) const;
+ scoped_refptr<Image> GetImage(const IntSize&) const;
virtual bool ErrorOccurred() const {
return cached_image_ && cached_image_->ErrorOccurred();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
index d713f05773d..9d633fe790e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
@@ -59,13 +59,13 @@ void LayoutImageResourceStyleImage::Shutdown() {
}
scoped_refptr<Image> LayoutImageResourceStyleImage::GetImage(
- const LayoutSize& size) const {
+ const FloatSize& size) const {
// Generated content may trigger calls to image() while we're still pending,
// don't assert but gracefully exit.
if (style_image_->IsPendingImage())
return nullptr;
return style_image_->GetImage(*layout_object_, layout_object_->GetDocument(),
- layout_object_->StyleRef(), FloatSize(size));
+ layout_object_->StyleRef(), size);
}
FloatSize LayoutImageResourceStyleImage::ImageSize(float multiplier) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
index bdc4d0dbbd2..6cfd1bf9a84 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
@@ -47,7 +47,7 @@ class LayoutImageResourceStyleImage final : public LayoutImageResource {
void Shutdown() override;
bool HasImage() const override { return true; }
- scoped_refptr<Image> GetImage(const LayoutSize&) const override;
+ scoped_refptr<Image> GetImage(const FloatSize&) const override;
bool ErrorOccurred() const override { return style_image_->ErrorOccurred(); }
bool ImageHasRelativeSize() const override {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
index b3c2a8bfec3..93361bcddae 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -437,6 +437,8 @@ void LayoutInline::UpdateShouldCreateBoxFragment() {
if (ComputeInitialShouldCreateBoxFragment()) {
SetShouldCreateBoxFragment();
+ SetNeedsLayoutAndFullPaintInvalidation(
+ layout_invalidation_reason::kStyleChange);
}
}
@@ -1631,7 +1633,8 @@ void LayoutInline::DirtyLinesFromChangedChild(
// TODO(yosin): We should move |SetAncestorLineBoxDirty()| into
// |DirtyLinesFromChangedChild()| like legacy layout.
SetAncestorLineBoxDirty();
- NGPaintFragment::DirtyLinesFromChangedChild(child);
+ if (child->IsInLayoutNGInlineFormattingContext())
+ NGPaintFragment::DirtyLinesFromChangedChild(child);
return;
}
MutableLineBoxes()->DirtyLinesFromChangedChild(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc
index 03d7085b18d..a106d637ab0 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -12,6 +13,8 @@
namespace blink {
+using ::testing::UnorderedElementsAre;
+
class LayoutInlineTest : public RenderingTest {};
// Helper class to run the same test code with and without LayoutNG
@@ -113,11 +116,37 @@ TEST_F(LayoutInlineTest, RegionHitTest) {
HitTestResult hit_result(hit_request, location);
LayoutPoint hit_offset;
- bool hit_outcome =
- lots_of_boxes->HitTestCulledInline(hit_result, location, hit_offset);
- // Assert checks that we both hit something and that the area covered
- // by "something" totally contains the hit region.
- EXPECT_TRUE(hit_outcome);
+ // The return value of HitTestCulledInline() indicates whether the hit test
+ // rect is completely contained by the part of |lots_of_boxes| being hit-
+ // tested. Legacy hit tests the entire LayoutObject all at once while NG hit
+ // tests line by line. Therefore, legacy returns true while NG is false.
+ //
+ // Note: The legacy behavior seems wrong. In a full list-based hit testing,
+ // after testing the node in the last intersecting line, the |true| return
+ // value of HitTestCulledInline() terminates the hit test process, and nodes
+ // in the previous lines are not tested.
+ //
+ // TODO(xiaochengh): Expose this issue in a real Chrome use case.
+
+ if (!lots_of_boxes->IsInLayoutNGInlineFormattingContext()) {
+ bool hit_outcome =
+ lots_of_boxes->HitTestCulledInline(hit_result, location, hit_offset);
+ // Assert checks that we both hit something and that the area covered
+ // by "something" totally contains the hit region.
+ EXPECT_TRUE(hit_outcome);
+ return;
+ }
+
+ const LayoutBlockFlow* div = ToLayoutBlockFlow(lots_of_boxes->Parent());
+ for (const NGPaintFragment* line : div->PaintFragment()->Children()) {
+ DCHECK(line->PhysicalFragment().IsLineBox());
+ bool hit_outcome = lots_of_boxes->HitTestCulledInline(hit_result, location,
+ hit_offset, line);
+ EXPECT_FALSE(hit_outcome);
+ }
+ // Make sure that the inline is hit
+ const Node* span = lots_of_boxes->GetNode();
+ EXPECT_EQ(span, hit_result.InnerNode());
}
// crbug.com/844746
@@ -273,4 +302,78 @@ TEST_P(ParameterizedLayoutInlineTest, VisualRectInDocument) {
EXPECT_EQ(visual_rect.Height(), LayoutUnit(222 + 20 * 2));
}
+// When adding focus ring rects, we should avoid adding duplicated rect for
+// continuations.
+TEST_P(ParameterizedLayoutInlineTest, FocusRingRecursiveContinuations) {
+ // TODO(crbug.com/835484): The test is broken for LayoutNG.
+ if (RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
+
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ font: 20px/20px Ahem;
+ }
+ </style>
+ <span id="target">SPAN0
+ <div>DIV1
+ <span>SPAN1
+ <div>DIV2</div>
+ </span>
+ </div>
+ </span>
+ )HTML");
+
+ Vector<LayoutRect> rects;
+ GetLayoutObjectByElementId("target")->AddOutlineRects(
+ rects, LayoutPoint(), NGOutlineType::kIncludeBlockVisualOverflow);
+
+ EXPECT_THAT(rects,
+ UnorderedElementsAre(LayoutRect(0, 0, 100, 20), // 'SPAN0'
+ LayoutRect(0, 20, 800, 40), // div DIV1
+ LayoutRect(0, 20, 200, 20), // 'DIV1 SPAN1'
+ LayoutRect(0, 40, 800, 20), // div DIV2
+ LayoutRect(0, 40, 80, 20))); // 'DIV2'
+}
+
+// When adding focus ring rects, we should avoid adding line box rects of
+// recursive inlines repeatedly.
+TEST_P(ParameterizedLayoutInlineTest, FocusRingRecursiveInlines) {
+ // TODO(crbug.com/835484): The test is broken for LayoutNG.
+ if (RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
+
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ font: 20px/20px Ahem;
+ }
+ </style>
+ <div style="width: 200px">
+ <span id="target">
+ <b><b><b><i><i><i>INLINE</i></i> <i><i>TEXT</i></i>
+ <div style="position: relative; top: -5px">
+ <b><b>BLOCK</b> <i>CONTENTS</i></b>
+ </div>
+ </i></b></b></b>
+ </span>
+ </div>
+ )HTML");
+
+ Vector<LayoutRect> rects;
+ GetLayoutObjectByElementId("target")->AddOutlineRects(
+ rects, LayoutPoint(), NGOutlineType::kIncludeBlockVisualOverflow);
+
+ EXPECT_THAT(rects,
+ UnorderedElementsAre(LayoutRect(0, 0, 120, 20), // 'INLINE'
+ LayoutRect(0, 20, 80, 20), // 'TEXT'
+ LayoutRect(0, 35, 200, 40), // the inner div
+ LayoutRect(0, 35, 100, 20), // 'BLOCK'
+ LayoutRect(0, 55, 160, 20))); // 'CONTENTS'
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_box.h b/chromium/third_party/blink/renderer/core/layout/layout_list_box.h
index 874f7e5679b..10ebb01e814 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_box.h
@@ -37,7 +37,7 @@ namespace blink {
class HTMLSelectElement;
-class LayoutListBox final : public LayoutBlockFlow {
+class CORE_EXPORT LayoutListBox final : public LayoutBlockFlow {
public:
explicit LayoutListBox(Element*);
~LayoutListBox() override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
index cb6d6172e22..0de549786b8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -190,11 +190,11 @@ bool LayoutListItem::PrepareForBlockDirectionAlign(
// Deal with the situation of layout tree changed.
if (marker_parent && marker_parent->IsAnonymous()) {
// When list-position-style change from outside to inside, we need to
- // restore LogicalHeight. So add IsInside().
+ // restore LogicalHeight to auto. So add IsInside().
if (marker_->IsInside() || marker_->NextSibling()) {
- // Restore old marker_container LogicalHeight.
+ // Set marker_container's LogicalHeight to auto.
if (marker_parent->StyleRef().LogicalHeight().IsZero())
- ForceLogicalHeight(*marker_parent, StyleRef().LogicalHeight());
+ ForceLogicalHeight(*marker_parent, Length());
// If marker_parent isn't the ancestor of line_box_parent, marker might
// generate a new empty line. We need to remove marker here.E.g:
@@ -287,9 +287,15 @@ bool LayoutListItem::UpdateMarkerLocation() {
return false;
}
-void LayoutListItem::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
- bool recompute_floats) {
+void LayoutListItem::RecalcVisualOverflow() {
+ RecalcChildVisualOverflow();
+ RecalcSelfVisualOverflow();
+}
+
+void LayoutListItem::ComputeVisualOverflow(bool recompute_floats) {
+ LayoutRect previous_visual_overflow_rect = VisualOverflowRect();
+ ClearVisualOverflow();
+
AddVisualOverflowFromChildren();
AddVisualEffectOverflow();
@@ -300,20 +306,14 @@ void LayoutListItem::ComputeVisualOverflow(
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
+ SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
}
-void LayoutListItem::AddVisualOverflowFromChildren() {
- LayoutBlockFlow::AddVisualOverflowFromChildren();
- UpdateOverflow(Visual);
-}
-
void LayoutListItem::AddLayoutOverflowFromChildren() {
LayoutBlockFlow::AddLayoutOverflowFromChildren();
- UpdateOverflow(Layout);
+ UpdateOverflow();
}
// Align marker_inline_box in block direction according to line_box_root's
@@ -387,7 +387,7 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
}
}
-void LayoutListItem::UpdateOverflow(OverflowType overflow_type) {
+void LayoutListItem::UpdateOverflow() {
if (!marker_ || !marker_->Parent() || !marker_->Parent()->IsBox() ||
marker_->IsInside() || !marker_->InlineBoxWrapper())
return;
@@ -428,39 +428,39 @@ void LayoutListItem::UpdateOverflow(OverflowType overflow_type) {
kDoNotIndentText, LayoutUnit()));
marker_logical_left = marker_line_offset - line_offset - PaddingStart() -
BorderStart() + marker_->MarginStart();
+
marker_inline_box->MoveInInlineDirection(marker_logical_left -
marker_old_logical_left);
+
for (InlineFlowBox* box = marker_inline_box->Parent(); box;
box = box->Parent()) {
- if (overflow_type == Visual) {
- LayoutRect new_logical_visual_overflow_rect =
- box->LogicalVisualOverflowRect(line_top, line_bottom);
- if (marker_logical_left < new_logical_visual_overflow_rect.X() &&
- !hit_self_painting_layer) {
- new_logical_visual_overflow_rect.SetWidth(
- new_logical_visual_overflow_rect.MaxX() - marker_logical_left);
- new_logical_visual_overflow_rect.SetX(marker_logical_left);
- if (box == root)
- adjust_overflow = true;
- }
- box->OverrideVisualOverflowFromLogicalRect(
- new_logical_visual_overflow_rect, line_top, line_bottom);
-
- if (box->BoxModelObject().HasSelfPaintingLayer())
- hit_self_painting_layer = true;
- } else {
- LayoutRect new_logical_layout_overflow_rect =
- box->LogicalLayoutOverflowRect(line_top, line_bottom);
- if (marker_logical_left < new_logical_layout_overflow_rect.X()) {
- new_logical_layout_overflow_rect.SetWidth(
- new_logical_layout_overflow_rect.MaxX() - marker_logical_left);
- new_logical_layout_overflow_rect.SetX(marker_logical_left);
- if (box == root)
- adjust_overflow = true;
- }
- box->OverrideLayoutOverflowFromLogicalRect(
- new_logical_layout_overflow_rect, line_top, line_bottom);
+ box->AddReplacedChildrenVisualOverflow(line_top, line_bottom);
+ LayoutRect new_logical_visual_overflow_rect =
+ box->LogicalVisualOverflowRect(line_top, line_bottom);
+ if (marker_logical_left < new_logical_visual_overflow_rect.X() &&
+ !hit_self_painting_layer) {
+ new_logical_visual_overflow_rect.SetWidth(
+ new_logical_visual_overflow_rect.MaxX() - marker_logical_left);
+ new_logical_visual_overflow_rect.SetX(marker_logical_left);
+ if (box == root)
+ adjust_overflow = true;
}
+ box->OverrideVisualOverflowFromLogicalRect(
+ new_logical_visual_overflow_rect, line_top, line_bottom);
+
+ if (box->BoxModelObject().HasSelfPaintingLayer())
+ hit_self_painting_layer = true;
+ LayoutRect new_logical_layout_overflow_rect =
+ box->LogicalLayoutOverflowRect(line_top, line_bottom);
+ if (marker_logical_left < new_logical_layout_overflow_rect.X()) {
+ new_logical_layout_overflow_rect.SetWidth(
+ new_logical_layout_overflow_rect.MaxX() - marker_logical_left);
+ new_logical_layout_overflow_rect.SetX(marker_logical_left);
+ if (box == root)
+ adjust_overflow = true;
+ }
+ box->OverrideLayoutOverflowFromLogicalRect(
+ new_logical_layout_overflow_rect, line_top, line_bottom);
}
} else {
LayoutUnit marker_line_offset =
@@ -469,41 +469,41 @@ void LayoutListItem::UpdateOverflow(OverflowType overflow_type) {
kDoNotIndentText, LayoutUnit()));
marker_logical_left = marker_line_offset - line_offset + PaddingStart() +
BorderStart() + marker_->MarginEnd();
+
marker_inline_box->MoveInInlineDirection(marker_logical_left -
marker_old_logical_left);
+
for (InlineFlowBox* box = marker_inline_box->Parent(); box;
box = box->Parent()) {
- if (overflow_type == Visual) {
- LayoutRect new_logical_visual_overflow_rect =
- box->LogicalVisualOverflowRect(line_top, line_bottom);
- if (marker_logical_left + marker_->LogicalWidth() >
- new_logical_visual_overflow_rect.MaxX() &&
- !hit_self_painting_layer) {
- new_logical_visual_overflow_rect.SetWidth(
- marker_logical_left + marker_->LogicalWidth() -
- new_logical_visual_overflow_rect.X());
- if (box == root)
- adjust_overflow = true;
- }
- box->OverrideVisualOverflowFromLogicalRect(
- new_logical_visual_overflow_rect, line_top, line_bottom);
-
- if (box->BoxModelObject().HasSelfPaintingLayer())
- hit_self_painting_layer = true;
- } else {
- LayoutRect new_logical_layout_overflow_rect =
- box->LogicalLayoutOverflowRect(line_top, line_bottom);
- if (marker_logical_left + marker_->LogicalWidth() >
- new_logical_layout_overflow_rect.MaxX()) {
- new_logical_layout_overflow_rect.SetWidth(
- marker_logical_left + marker_->LogicalWidth() -
- new_logical_layout_overflow_rect.X());
- if (box == root)
- adjust_overflow = true;
- }
- box->OverrideLayoutOverflowFromLogicalRect(
- new_logical_layout_overflow_rect, line_top, line_bottom);
+ box->AddReplacedChildrenVisualOverflow(line_top, line_bottom);
+ LayoutRect new_logical_visual_overflow_rect =
+ box->LogicalVisualOverflowRect(line_top, line_bottom);
+ if (marker_logical_left + marker_->LogicalWidth() >
+ new_logical_visual_overflow_rect.MaxX() &&
+ !hit_self_painting_layer) {
+ new_logical_visual_overflow_rect.SetWidth(
+ marker_logical_left + marker_->LogicalWidth() -
+ new_logical_visual_overflow_rect.X());
+ if (box == root)
+ adjust_overflow = true;
+ }
+ box->OverrideVisualOverflowFromLogicalRect(
+ new_logical_visual_overflow_rect, line_top, line_bottom);
+
+ if (box->BoxModelObject().HasSelfPaintingLayer())
+ hit_self_painting_layer = true;
+ LayoutRect new_logical_layout_overflow_rect =
+ box->LogicalLayoutOverflowRect(line_top, line_bottom);
+ if (marker_logical_left + marker_->LogicalWidth() >
+ new_logical_layout_overflow_rect.MaxX()) {
+ new_logical_layout_overflow_rect.SetWidth(
+ marker_logical_left + marker_->LogicalWidth() -
+ new_logical_layout_overflow_rect.X());
+ if (box == root)
+ adjust_overflow = true;
}
+ box->OverrideLayoutOverflowFromLogicalRect(
+ new_logical_layout_overflow_rect, line_top, line_bottom);
}
}
@@ -517,28 +517,25 @@ void LayoutListItem::UpdateOverflow(OverflowType overflow_type) {
marker_->Size());
if (!StyleRef().IsHorizontalWritingMode())
marker_rect = marker_rect.TransposedRect();
- LayoutBox* o = marker_;
-
- if (overflow_type == Visual) {
- do {
- o = o->ParentBox();
- if (o->IsLayoutBlock())
- ToLayoutBlock(o)->AddContentsVisualOverflow(marker_rect);
- if (o->HasOverflowClip() || o->HasSelfPaintingLayer())
- break;
- marker_rect.MoveBy(-o->Location());
- } while (o != this);
- } else {
- do {
- o = o->ParentBox();
- if (o->IsLayoutBlock()) {
- ToLayoutBlock(o)->AddLayoutOverflow(marker_rect);
- }
- if (o->HasOverflowClip())
- break;
- marker_rect.MoveBy(-o->Location());
- } while (o != this);
- }
+ LayoutBox* object = marker_;
+
+ bool found_self_painting_layer = false;
+ do {
+ object = object->ParentBox();
+ if (object->IsLayoutBlock()) {
+ if (!found_self_painting_layer)
+ ToLayoutBlock(object)->AddContentsVisualOverflow(marker_rect);
+ ToLayoutBlock(object)->AddLayoutOverflow(marker_rect);
+ }
+
+ if (object->HasOverflowClip())
+ break;
+
+ if (object->HasSelfPaintingLayer())
+ found_self_painting_layer = true;
+
+ marker_rect.MoveBy(-object->Location());
+ } while (object != this);
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_item.h b/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
index e0d77368362..3984e8ddabc 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
@@ -48,6 +48,8 @@ class LayoutListItem final : public LayoutBlockFlow {
const char* GetName() const override { return "LayoutListItem"; }
+ void RecalcVisualOverflow() override;
+
private:
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectListItem || LayoutBlockFlow::IsOfType(type);
@@ -65,14 +67,12 @@ class LayoutListItem final : public LayoutBlockFlow {
// Returns true if we re-attached and updated the location of the marker.
bool UpdateMarkerLocation();
- enum OverflowType { Layout, Visual };
- void UpdateOverflow(OverflowType);
+ void UpdateOverflow();
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) final;
+ void ComputeVisualOverflow(bool recompute_floats) final;
- void AddVisualOverflowFromChildren();
void AddLayoutOverflowFromChildren() override;
void AlignMarkerInBlockDirection();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
index 9529cd96095..99284c052b4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -150,8 +150,8 @@ void LayoutListMarker::UpdateLayout() {
SetMarginStart(LayoutUnit());
SetMarginEnd(LayoutUnit());
- Length start_margin = StyleRef().MarginStart();
- Length end_margin = StyleRef().MarginEnd();
+ const Length& start_margin = StyleRef().MarginStart();
+ const Length& end_margin = StyleRef().MarginEnd();
if (start_margin.IsFixed())
SetMarginStart(LayoutUnit(start_margin.Value()));
if (end_margin.IsFixed())
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
index 0f53c661aa5..69c6ed6574a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
@@ -33,7 +33,7 @@ class LayoutListItem;
// Used to layout the list item's marker.
// The LayoutListMarker always has to be a child of a LayoutListItem.
-class LayoutListMarker final : public LayoutBox {
+class CORE_EXPORT LayoutListMarker final : public LayoutBox {
public:
static LayoutListMarker* CreateAnonymous(LayoutListItem*);
~LayoutListMarker() override;
@@ -42,7 +42,7 @@ class LayoutListMarker final : public LayoutBox {
const String& GetText() const { return text_; }
// Marker text with suffix, e.g. "1. ", for use in accessibility.
- CORE_EXPORT String TextAlternative() const;
+ String TextAlternative() const;
// A reduced set of list style categories allowing for more concise expression
// of list style specific logic.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_media.cc b/chromium/third_party/blink/renderer/core/layout/layout_media.cc
index 5157116554f..33b61dfe5a1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_media.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_media.cc
@@ -118,7 +118,7 @@ bool LayoutMedia::IsChildAllowed(LayoutObject* child,
// check can be removed if ::-webkit-media-controls is made
// internal.
if (child->GetNode()->IsMediaControls())
- return child->IsFlexibleBox();
+ return child->IsFlexibleBoxIncludingNG();
if (child->GetNode()->IsTextTrackContainer() ||
child->GetNode()->IsMediaRemotingInterstitial() ||
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index f006da14466..258fcaff3c5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -330,7 +330,8 @@ LayoutUnit LayoutMultiColumnFlowThread::MaxColumnLogicalHeight() const {
return column_height_available_;
}
const LayoutBlockFlow* multicol_block = MultiColumnBlockFlow();
- Length logical_max_height = multicol_block->StyleRef().LogicalMaxHeight();
+ const Length& logical_max_height =
+ multicol_block->StyleRef().LogicalMaxHeight();
if (!logical_max_height.IsMaxSizeNone()) {
LayoutUnit resolved_logical_max_height =
multicol_block->ComputeContentLogicalHeight(
@@ -491,7 +492,15 @@ LayoutMultiColumnSet* LayoutMultiColumnFlowThread::ColumnSetAtBlockOffset(
// Avoid returning zero-height column sets, if possible. We found a column set
// based on a flow thread coordinate. If multiple column sets share that
// coordinate (because we have zero-height column sets between column
- // spanners, for instance), look for one that has a height.
+ // spanners, for instance), look for one that has a height. Also look ahead to
+ // find a set that actually contains the coordinate. Note that when we do this
+ // during layout, it means that we might return a column set that hasn't got
+ // its flow thread boundaries updated yet (and thus using those from the
+ // previous layout), but that's the best we can do when our engine doesn't
+ // actually understand fragmentation. This may happen when there's a float
+ // that's split into multiple fragments because of column spanners, and we
+ // still perform all its layout at the position before the first spanner in
+ // question (i.e. where only the first fragment is supposed to be laid out).
for (LayoutMultiColumnSet* walker = column_set; walker;
walker = walker->NextSiblingMultiColumnSet()) {
if (!walker->IsPageLogicalHeightKnown())
@@ -500,11 +509,10 @@ LayoutMultiColumnSet* LayoutMultiColumnFlowThread::ColumnSetAtBlockOffset(
if (walker->LogicalTopInFlowThread() < offset &&
walker->LogicalBottomInFlowThread() >= offset)
return walker;
- }
- if (walker->LogicalTopInFlowThread() <= offset &&
- walker->LogicalBottomInFlowThread() > offset)
+ } else if (walker->LogicalTopInFlowThread() <= offset &&
+ walker->LogicalBottomInFlowThread() > offset) {
return walker;
- break;
+ }
}
return column_set;
}
@@ -1461,45 +1469,4 @@ void LayoutMultiColumnFlowThread::RestoreMultiColumnLayoutState(
last_set_worked_on_ = state.ColumnSet();
}
-unsigned LayoutMultiColumnFlowThread::CalculateActualColumnCountAllowance()
- const {
- // To avoid performance problems, limit the maximum number of columns. Try to
- // identify legitimate reasons for creating many columns, and allow many
- // columns in such cases. The amount of "content" will determine the
- // allowance.
- unsigned allowance = 0;
-
- // This isn't a particularly clever algorithm. For example, we don't account
- // for parallel flows (absolute positioning, floats, visible overflow, table
- // cells, flex items). We just generously add everything together.
- for (const LayoutObject* descendant = this; descendant;) {
- bool examine_children = false;
- if (descendant->IsBox() && !descendant->IsInline() &&
- !ToLayoutBox(descendant)->IsWritingModeRoot()) {
- // Give one point to any kind of block level content.
- allowance++;
- if (descendant->IsLayoutBlockFlow() && descendant->ChildrenInline()) {
- // It's a block-level block container in the same writing mode, and it
- // has inline children. Count the lines and add it to the allowance.
- allowance += ToLayoutBlockFlow(descendant)->LineCount();
- } else {
- // We could examine other types of layout modes (tables, flexbox, etc.)
- // as well, but then again, that might be overkill. Just enter and see
- // what we find.
- examine_children = true;
- }
- }
-
- if (allowance >= ColumnCountClampMax())
- return ColumnCountClampMax();
-
- descendant = examine_children
- ? descendant->NextInPreOrder(this)
- : descendant->NextInPreOrderAfterChildren(this);
- }
-
- DCHECK_LE(allowance, ColumnCountClampMax());
- return std::max(allowance, ColumnCountClampMin());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
index 6b5e6548d48..697e426394f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
@@ -190,18 +190,6 @@ class CORE_EXPORT LayoutMultiColumnFlowThread : public LayoutFlowThread,
unsigned ColumnCount() const { return column_count_; }
- // Calculate and return the actual column count allowance. This method should
- // only be called when we ended up with an actual column count larger than
- // ColumnCountClampMin() in some fragmentainer group.
- unsigned CalculateActualColumnCountAllowance() const;
-
- // Any actual column count value lower than this will be allowed
- // unconditionally.
- static unsigned ColumnCountClampMin() { return 10; }
-
- // The maximum actual column count we're going to allow.
- static unsigned ColumnCountClampMax() { return 2000; }
-
// Total height available to columns and spanners. This is the multicol
// container's content box logical height, or 0 if auto.
LayoutUnit ColumnHeightAvailable() const { return column_height_available_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index 0adaeba0997..178a50b2f12 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -522,8 +522,9 @@ LayoutRect LayoutMultiColumnSet::FragmentsBoundingBox(
}
void LayoutMultiColumnSet::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
bool recompute_floats) {
+ LayoutRect previous_visual_overflow_rect = VisualOverflowRect();
+ ClearVisualOverflow();
AddVisualOverflowFromChildren();
AddVisualEffectOverflow();
@@ -534,8 +535,7 @@ void LayoutMultiColumnSet::ComputeVisualOverflow(
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
+ SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
}
@@ -685,7 +685,7 @@ void LayoutMultiColumnSet::UpdateFromNG() {
DCHECK_EQ(fragmentainer_groups_.size(), 1U);
auto& group = fragmentainer_groups_[0];
group.UpdateFromNG(LogicalHeight());
- ComputeOverflow(LogicalHeight());
+ ComputeLayoutOverflow(LogicalHeight());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h
index 8e66f98b8f0..26348fe300d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h
@@ -255,7 +255,7 @@ class CORE_EXPORT LayoutMultiColumnSet : public LayoutBlockFlow {
void PaintObject(const PaintInfo&,
const LayoutPoint& paint_offset) const override;
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) final;
+ void ComputeVisualOverflow(bool recompute_floats) final;
void AddVisualOverflowFromChildren();
void AddLayoutOverflowFromChildren() override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
index 01c564f4009..b5bd25ccd7b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
@@ -94,6 +94,13 @@ bool LayoutMultiColumnSpannerPlaceholder::NeedsPreferredWidthsRecalculation()
return layout_object_in_flow_thread_->NeedsPreferredWidthsRecalculation();
}
+void LayoutMultiColumnSpannerPlaceholder::RecalcVisualOverflow() {
+ LayoutBox::RecalcVisualOverflow();
+ ClearVisualOverflow();
+ AddContentsVisualOverflow(
+ layout_object_in_flow_thread_->VisualOverflowRect());
+}
+
LayoutUnit LayoutMultiColumnSpannerPlaceholder::MinPreferredLogicalWidth()
const {
return layout_object_in_flow_thread_->MinPreferredLogicalWidth();
@@ -123,9 +130,7 @@ void LayoutMultiColumnSpannerPlaceholder::UpdateLayout() {
// Take the overflow from the spanner, so that it gets propagated to the
// multicol container and beyond.
- overflow_.reset();
- AddContentsVisualOverflow(
- layout_object_in_flow_thread_->VisualOverflowRect());
+ ClearLayoutOverflow();
AddLayoutOverflow(layout_object_in_flow_thread_->LayoutOverflowRect());
ClearNeedsLayout();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
index b1705d538f7..888a6bc2917 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
@@ -55,6 +55,7 @@ class LayoutMultiColumnSpannerPlaceholder final : public LayoutBox {
void InsertedIntoTree() override;
void WillBeRemovedFromTree() override;
bool NeedsPreferredWidthsRecalculation() const override;
+ void RecalcVisualOverflow() override;
LayoutUnit MinPreferredLogicalWidth() const override;
LayoutUnit MaxPreferredLogicalWidth() const override;
void UpdateLayout() override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
index 3bb45426382..161a879c44d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
@@ -179,7 +179,7 @@ struct SameSizeAsLayoutObject : DisplayItemClient {
void* pointers[5];
Member<void*> members[1];
#if DCHECK_IS_ON()
- unsigned debug_bitfields_ : 2;
+ unsigned debug_bitfields_;
#endif
unsigned bitfields_;
unsigned bitfields2_;
@@ -293,6 +293,7 @@ LayoutObject::LayoutObject(Node* node)
#if DCHECK_IS_ON()
has_ax_object_(false),
set_needs_layout_forbidden_(false),
+ as_image_observer_count_(0),
#endif
bitfields_(node) {
InstanceCounters::IncrementCounter(InstanceCounters::kLayoutObjectCounter);
@@ -691,8 +692,12 @@ PaintLayer* LayoutObject::PaintingLayer() const {
// Use containingBlock instead of parentCrossingFrames for floating
// objects to omit any self-painting layers of inline objects that don't
// paint the floating object.
- current = current->IsFloating() ? current->ContainingBlock()
- : current->ParentCrossingFrames()) {
+ // This is only needed for inline-level floats not managed by LayoutNG.
+ // LayoutNG floats are painted by the correct painting layer.
+ current = (current->IsFloating() &&
+ !current->IsInLayoutNGInlineFormattingContext())
+ ? current->ContainingBlock()
+ : current->ParentCrossingFrames()) {
if (current->HasLayer() &&
ToLayoutBoxModelObject(current)->Layer()->IsSelfPaintingLayer()) {
return ToLayoutBoxModelObject(current)->Layer();
@@ -725,6 +730,8 @@ LayoutRect LayoutObject::ScrollRectToVisible(
return rect;
GetDocument().GetFrame()->GetSmoothScrollSequencer().AbortAnimations();
+ GetDocument().GetFrame()->GetSmoothScrollSequencer().SetScrollType(
+ params.GetScrollType());
WebScrollIntoViewParams new_params(params);
new_params.is_for_scroll_sequence |=
params.GetScrollType() == kProgrammaticScroll;
@@ -847,7 +854,7 @@ static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
// In general we can't relayout a flex item independently of its container;
// not only is the result incorrect due to the override size that's set, it
// also messes with the cached main size on the flexbox.
- if (object->IsBox() && ToLayoutBox(object)->IsFlexItem())
+ if (object->IsBox() && ToLayoutBox(object)->IsFlexItemIncludingNG())
return false;
// Inside multicol it's generally problematic to allow relayout roots. The
@@ -943,10 +950,19 @@ void LayoutObject::MarkContainerChainForLayout(bool schedule_relayout,
DCHECK(!object->IsSetNeedsLayoutForbidden());
#endif
+ if (object->HasLayer() &&
+ ToLayoutBoxModelObject(object)->Layer()->IsSelfPaintingLayer())
+ ToLayoutBoxModelObject(object)->Layer()->SetNeedsVisualOverflowRecalc();
+
if (layouter) {
layouter->RecordObjectMarkedForLayout(object);
- if (object == layouter->Root())
+
+ if (object == layouter->Root()) {
+ if (auto* painting_layer = PaintingLayer())
+ painting_layer->SetNeedsVisualOverflowRecalc();
+
return;
+ }
}
last = object;
@@ -1412,16 +1428,27 @@ const LayoutBoxModelObject& LayoutObject::ContainerForPaintInvalidation()
return *layout_view;
}
-bool LayoutObject::RecalcOverflow() {
- if (!ChildNeedsOverflowRecalc())
+bool LayoutObject::RecalcLayoutOverflow() {
+ if (!ChildNeedsLayoutOverflowRecalc())
return false;
- bool children_overflow_changed = false;
+ ClearChildNeedsLayoutOverflowRecalc();
+ bool children_layout_overflow_changed = false;
+ for (LayoutObject* current = SlowFirstChild(); current;
+ current = current->NextSibling()) {
+ if (current->RecalcLayoutOverflow())
+ children_layout_overflow_changed = true;
+ }
+ return children_layout_overflow_changed;
+}
+
+void LayoutObject::RecalcVisualOverflow() {
for (LayoutObject* current = SlowFirstChild(); current;
current = current->NextSibling()) {
- if (current->RecalcOverflow())
- children_overflow_changed = true;
+ if (current->HasLayer() &&
+ ToLayoutBoxModelObject(current)->HasSelfPaintingLayer())
+ continue;
+ current->RecalcVisualOverflow();
}
- return children_overflow_changed;
}
const LayoutBoxModelObject* LayoutObject::EnclosingCompositedContainer() const {
@@ -1604,7 +1631,7 @@ LayoutRect LayoutObject::VisualRectIncludingCompositedScrolling(
}
void LayoutObject::ClearPreviousVisualRects() {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
for (auto* fragment = &fragment_; fragment;
fragment = fragment->NextFragment()) {
@@ -1879,7 +1906,7 @@ StyleDifference LayoutObject::AdjustStyleDifference(
}
// TODO(wangxianzhu): We may avoid subtree paint invalidation on CSS clip
- // change for SPv2.
+ // change for CAP.
if (diff.CssClipChanged())
diff.SetNeedsPaintInvalidationSubtree();
@@ -1939,39 +1966,6 @@ void LayoutObject::SetPseudoStyle(scoped_refptr<ComputedStyle> pseudo_style) {
SetStyle(std::move(pseudo_style));
}
-void LayoutObject::FirstLineStyleDidChange(const ComputedStyle& old_style,
- const ComputedStyle& new_style) {
- StyleDifference diff =
- old_style.VisualInvalidationDiff(GetDocument(), new_style);
-
- if (diff.NeedsFullPaintInvalidation() ||
- diff.TextDecorationOrColorChanged()) {
- // We need to invalidate all inline boxes in the first line, because they
- // need to be repainted with the new style, e.g. background, font style,
- // etc.
- LayoutBlockFlow* first_line_container = nullptr;
- if (BehavesLikeBlockContainer()) {
- // This object is a LayoutBlock having PseudoIdFirstLine pseudo style
- // changed.
- first_line_container =
- ToLayoutBlock(this)->NearestInnerBlockWithFirstLine();
- } else if (IsLayoutInline()) {
- // This object is a LayoutInline having FIRST_LINE_INHERITED pesudo style
- // changed. This method can be called even if the LayoutInline doesn't
- // intersect the first line, but we only need to invalidate if it does.
- if (InlineBox* first_line_box =
- ToLayoutInline(this)->FirstLineBoxIncludingCulling()) {
- if (first_line_box->IsFirstLineStyle())
- first_line_container = ToLayoutBlockFlow(ContainingBlock());
- }
- }
- if (first_line_container)
- first_line_container->SetShouldDoFullPaintInvalidationForFirstLine();
- }
- if (diff.NeedsLayout())
- SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
-}
-
void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded() {
LayoutObject* object = this;
do {
@@ -1983,16 +1977,27 @@ void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded() {
: object->Container();
if (object) {
object->SetChildNeedsLayoutOverflowRecalc();
- object->SetChildNeedsVisualOverflowRecalc();
+
+ if (object->HasLayer()) {
+ auto* box_model_object = ToLayoutBoxModelObject(object);
+ if (box_model_object->HasSelfPaintingLayer())
+ box_model_object->Layer()->SetNeedsVisualOverflowRecalc();
+ }
}
+
} while (object);
}
void LayoutObject::SetNeedsOverflowRecalc() {
- bool needed_recalc = NeedsLayoutOverflowRecalc();
+ bool needed_recalc = SelfNeedsLayoutOverflowRecalc();
SetSelfNeedsLayoutOverflowRecalc();
- SetSelfNeedsVisualOverflowRecalc();
SetShouldCheckForPaintInvalidation();
+
+ if (HasLayer()) {
+ auto* box_model_object = ToLayoutBoxModelObject(this);
+ if (box_model_object->HasSelfPaintingLayer())
+ box_model_object->Layer()->SetNeedsVisualOverflowRecalc();
+ }
if (!needed_recalc)
MarkContainerChainForOverflowRecalcIfNeeded();
}
@@ -2021,39 +2026,8 @@ void LayoutObject::SetStyle(scoped_refptr<ComputedStyle> style) {
scoped_refptr<ComputedStyle> old_style = std::move(style_);
SetStyleInternal(std::move(style));
- UpdateFillImages(old_style ? &old_style->BackgroundLayers() : nullptr,
- style_->BackgroundLayers());
- UpdateFillImages(old_style ? &old_style->MaskLayers() : nullptr,
- style_->MaskLayers());
-
- UpdateImage(old_style ? old_style->BorderImage().GetImage() : nullptr,
- style_->BorderImage().GetImage());
- UpdateImage(old_style ? old_style->MaskBoxImage().GetImage() : nullptr,
- style_->MaskBoxImage().GetImage());
-
- StyleImage* new_content_image =
- style_->GetContentData() && style_->GetContentData()->IsImage()
- ? ToImageContentData(style_->GetContentData())->GetImage()
- : nullptr;
- StyleImage* old_content_image =
- old_style && old_style->GetContentData() &&
- old_style->GetContentData()->IsImage()
- ? ToImageContentData(old_style->GetContentData())->GetImage()
- : nullptr;
- UpdateImage(old_content_image, new_content_image);
-
- StyleImage* new_box_reflect_mask_image =
- style_->BoxReflect() ? style_->BoxReflect()->Mask().GetImage() : nullptr;
- StyleImage* old_box_reflect_mask_image =
- old_style && old_style->BoxReflect()
- ? old_style->BoxReflect()->Mask().GetImage()
- : nullptr;
- UpdateImage(old_box_reflect_mask_image, new_box_reflect_mask_image);
-
- UpdateShapeImage(old_style ? old_style->ShapeOutside() : nullptr,
- style_->ShapeOutside());
- UpdateCursorImages(old_style ? old_style->Cursors() : nullptr,
- style_->Cursors());
+ if (!IsText())
+ UpdateImageObservers(old_style.get(), style_.get());
CheckCounterChanges(old_style.get(), style_.get());
@@ -2133,6 +2107,91 @@ void LayoutObject::SetStyle(scoped_refptr<ComputedStyle> style) {
}
}
+void LayoutObject::UpdateImageObservers(const ComputedStyle* old_style,
+ const ComputedStyle* new_style) {
+ DCHECK(old_style || new_style);
+ DCHECK(!IsText());
+
+ UpdateFillImages(old_style ? &old_style->BackgroundLayers() : nullptr,
+ new_style ? &new_style->BackgroundLayers() : nullptr);
+ UpdateFillImages(old_style ? &old_style->MaskLayers() : nullptr,
+ new_style ? &new_style->MaskLayers() : nullptr);
+
+ UpdateImage(old_style ? old_style->BorderImage().GetImage() : nullptr,
+ new_style ? new_style->BorderImage().GetImage() : nullptr);
+ UpdateImage(old_style ? old_style->MaskBoxImage().GetImage() : nullptr,
+ new_style ? new_style->MaskBoxImage().GetImage() : nullptr);
+
+ StyleImage* old_content_image =
+ old_style && old_style->GetContentData() &&
+ old_style->GetContentData()->IsImage()
+ ? ToImageContentData(old_style->GetContentData())->GetImage()
+ : nullptr;
+ StyleImage* new_content_image =
+ new_style && new_style->GetContentData() &&
+ new_style->GetContentData()->IsImage()
+ ? ToImageContentData(new_style->GetContentData())->GetImage()
+ : nullptr;
+ UpdateImage(old_content_image, new_content_image);
+
+ StyleImage* old_box_reflect_mask_image =
+ old_style && old_style->BoxReflect()
+ ? old_style->BoxReflect()->Mask().GetImage()
+ : nullptr;
+ StyleImage* new_box_reflect_mask_image =
+ new_style && new_style->BoxReflect()
+ ? new_style->BoxReflect()->Mask().GetImage()
+ : nullptr;
+ UpdateImage(old_box_reflect_mask_image, new_box_reflect_mask_image);
+
+ UpdateShapeImage(old_style ? old_style->ShapeOutside() : nullptr,
+ new_style ? new_style->ShapeOutside() : nullptr);
+ UpdateCursorImages(old_style ? old_style->Cursors() : nullptr,
+ new_style ? new_style->Cursors() : nullptr);
+
+ UpdateFirstLineImageObservers(old_style, new_style);
+}
+
+void LayoutObject::UpdateFirstLineImageObservers(
+ const ComputedStyle* old_style,
+ const ComputedStyle* new_style) {
+ bool has_old_first_line_style =
+ old_style && old_style->HasPseudoStyle(kPseudoIdFirstLine);
+ bool has_new_first_line_style =
+ new_style && new_style->HasPseudoStyle(kPseudoIdFirstLine);
+ if (!has_old_first_line_style && !has_new_first_line_style)
+ return;
+
+ // Don't call CacheFirstLineStyle() which will update the cache, because this
+ // function can be called when the object has not been inserted into the tree
+ // and we can't update the pseudo style cache which may depend on ancestors.
+ const auto* cached_old_first_line_style =
+ has_old_first_line_style
+ ? old_style->GetCachedPseudoStyle(kPseudoIdFirstLine)
+ : nullptr;
+ const auto* cached_new_first_line_style =
+ has_new_first_line_style
+ ? new_style->GetCachedPseudoStyle(kPseudoIdFirstLine)
+ : nullptr;
+
+ if (has_new_first_line_style) {
+ // If cached_new_first_line_style is null, it means that the new first line
+ // style has not been cached yet. Will check again when the object's first
+ // line style is actually used and cached.
+ bitfields_.SetPendingUpdateFirstLineImageObservers(
+ !cached_new_first_line_style);
+ }
+
+ if (cached_old_first_line_style || cached_new_first_line_style) {
+ UpdateFillImages(cached_old_first_line_style
+ ? &cached_old_first_line_style->BackgroundLayers()
+ : nullptr,
+ cached_new_first_line_style
+ ? &cached_new_first_line_style->BackgroundLayers()
+ : nullptr);
+ }
+}
+
void LayoutObject::StyleWillChange(StyleDifference diff,
const ComputedStyle& new_style) {
if (style_) {
@@ -2298,11 +2357,6 @@ void LayoutObject::StyleDidChange(StyleDifference diff,
if (NeedsLayout() && old_style->GetPosition() != style_->GetPosition())
MarkContainerChainForLayout();
- // Ditto.
- if (NeedsOverflowRecalc() &&
- old_style->GetPosition() != style_->GetPosition())
- MarkContainerChainForOverflowRecalcIfNeeded();
-
SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
} else if (diff.NeedsPositionedMovementLayout()) {
SetNeedsPositionedMovementLayout();
@@ -2332,8 +2386,7 @@ void LayoutObject::StyleDidChange(StyleDifference diff,
SetBackgroundNeedsFullPaintInvalidation();
}
- if (old_style && old_style->StyleType() == kPseudoIdNone)
- ApplyPseudoStyleChanges(*old_style);
+ ApplyPseudoStyleChanges(old_style);
if (old_style &&
old_style->UsedTransformStyle3D() != StyleRef().UsedTransformStyle3D()) {
@@ -2343,30 +2396,47 @@ void LayoutObject::StyleDidChange(StyleDifference diff,
}
}
-void LayoutObject::ApplyPseudoStyleChanges(const ComputedStyle& old_style) {
- if (old_style.HasPseudoStyle(kPseudoIdFirstLine) ||
- StyleRef().HasPseudoStyle(kPseudoIdFirstLine))
- ApplyFirstLineChanges(old_style);
+void LayoutObject::ApplyPseudoStyleChanges(const ComputedStyle* old_style) {
+ ApplyFirstLineChanges(old_style);
- if (old_style.HasPseudoStyle(kPseudoIdSelection) ||
+ if ((old_style && old_style->HasPseudoStyle(kPseudoIdSelection)) ||
StyleRef().HasPseudoStyle(kPseudoIdSelection))
InvalidateSelectedChildrenOnStyleChange();
}
-void LayoutObject::ApplyFirstLineChanges(const ComputedStyle& old_style) {
- if (old_style.HasPseudoStyle(kPseudoIdFirstLine)) {
- scoped_refptr<const ComputedStyle> old_pseudo_style =
- old_style.GetCachedPseudoStyle(kPseudoIdFirstLine);
- if (StyleRef().HasPseudoStyle(kPseudoIdFirstLine) && old_pseudo_style) {
- scoped_refptr<const ComputedStyle> new_pseudo_style =
- UncachedFirstLineStyle();
- if (new_pseudo_style) {
- FirstLineStyleDidChange(*old_pseudo_style, *new_pseudo_style);
- return;
+void LayoutObject::ApplyFirstLineChanges(const ComputedStyle* old_style) {
+ bool has_old_first_line_style =
+ old_style && old_style->HasPseudoStyle(kPseudoIdFirstLine);
+ bool has_new_first_line_style = StyleRef().HasPseudoStyle(kPseudoIdFirstLine);
+ if (!has_old_first_line_style && !has_new_first_line_style)
+ return;
+
+ StyleDifference diff;
+ bool has_diff = false;
+ if (Parent() && has_old_first_line_style && has_new_first_line_style) {
+ if (const auto* old_first_line_style =
+ old_style->GetCachedPseudoStyle(kPseudoIdFirstLine)) {
+ if (auto new_first_line_style = UncachedFirstLineStyle()) {
+ diff = old_first_line_style->VisualInvalidationDiff(
+ GetDocument(), *new_first_line_style);
+ has_diff = true;
}
}
}
- SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
+ if (!has_diff) {
+ diff.SetNeedsPaintInvalidationObject();
+ diff.SetNeedsFullLayout();
+ }
+
+ if (BehavesLikeBlockContainer() && (diff.NeedsFullPaintInvalidation() ||
+ diff.TextDecorationOrColorChanged())) {
+ if (auto* first_line_container =
+ ToLayoutBlock(this)->NearestInnerBlockWithFirstLine())
+ first_line_container->SetShouldDoFullPaintInvalidationForFirstLine();
+ }
+
+ if (diff.NeedsLayout())
+ SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
}
void LayoutObject::PropagateStyleToAnonymousChildren() {
@@ -2439,25 +2509,40 @@ void LayoutObject::SetStyleWithWritingModeOfParent(
SetStyleWithWritingModeOf(std::move(style), Parent());
}
+void LayoutObject::AddAsImageObserver(StyleImage* image) {
+ if (!image)
+ return;
+#if DCHECK_IS_ON()
+ ++as_image_observer_count_;
+#endif
+ image->AddClient(this);
+}
+
+void LayoutObject::RemoveAsImageObserver(StyleImage* image) {
+ if (!image)
+ return;
+#if DCHECK_IS_ON()
+ SECURITY_DCHECK(as_image_observer_count_ > 0u);
+ --as_image_observer_count_;
+#endif
+ image->RemoveClient(this);
+}
+
void LayoutObject::UpdateFillImages(const FillLayer* old_layers,
- const FillLayer& new_layers) {
+ const FillLayer* new_layers) {
// Optimize the common case
- if (FillLayer::ImagesIdentical(old_layers, &new_layers))
+ if (FillLayer::ImagesIdentical(old_layers, new_layers))
return;
- // Go through the new layers and addClients first, to avoid removing all
- // clients of an image.
- for (const FillLayer* curr_new = &new_layers; curr_new;
- curr_new = curr_new->Next()) {
- if (curr_new->GetImage())
- curr_new->GetImage()->AddClient(this);
- }
+ // Go through the new layers and AddAsImageObserver() first, to avoid removing
+ // all clients of an image.
+ for (const FillLayer* curr_new = new_layers; curr_new;
+ curr_new = curr_new->Next())
+ AddAsImageObserver(curr_new->GetImage());
for (const FillLayer* curr_old = old_layers; curr_old;
- curr_old = curr_old->Next()) {
- if (curr_old->GetImage())
- curr_old->GetImage()->RemoveClient(this);
- }
+ curr_old = curr_old->Next())
+ RemoveAsImageObserver(curr_old->GetImage());
}
void LayoutObject::UpdateCursorImages(const CursorList* old_cursors,
@@ -2466,20 +2551,20 @@ void LayoutObject::UpdateCursorImages(const CursorList* old_cursors,
return;
if (new_cursors) {
- for (const CursorData& cursor_new : *new_cursors) {
- if (cursor_new.GetImage())
- cursor_new.GetImage()->AddClient(this);
- }
+ for (const auto& cursor : *new_cursors)
+ AddAsImageObserver(cursor.GetImage());
+ }
+ if (old_cursors) {
+ for (const auto& cursor : *old_cursors)
+ RemoveAsImageObserver(cursor.GetImage());
}
- RemoveCursorImageClient(old_cursors);
}
void LayoutObject::UpdateImage(StyleImage* old_image, StyleImage* new_image) {
if (old_image != new_image) {
- if (old_image)
- old_image->RemoveClient(this);
- if (new_image)
- new_image->AddClient(this);
+ // AddAsImageObserver first, to avoid removing all clients of an image.
+ AddAsImageObserver(new_image);
+ RemoveAsImageObserver(old_image);
}
}
@@ -3062,7 +3147,7 @@ LayoutObject* LayoutObject::Container(AncestorSkipInfo* skip_info) const {
return multicol_container;
}
- if (IsFloating())
+ if (IsFloating() && !IsInLayoutNGInlineFormattingContext())
return ContainingBlock(skip_info);
return Parent();
@@ -3134,36 +3219,14 @@ void LayoutObject::WillBeDestroyed() {
ClearLayoutRootIfNeeded();
- if (style_) {
- for (const FillLayer* bg_layer = &style_->BackgroundLayers(); bg_layer;
- bg_layer = bg_layer->Next()) {
- if (StyleImage* background_image = bg_layer->GetImage())
- background_image->RemoveClient(this);
- }
-
- for (const FillLayer* mask_layer = &style_->MaskLayers(); mask_layer;
- mask_layer = mask_layer->Next()) {
- if (StyleImage* mask_image = mask_layer->GetImage())
- mask_image->RemoveClient(this);
- }
-
- if (StyleImage* border_image = style_->BorderImage().GetImage())
- border_image->RemoveClient(this);
+ // Remove this object as ImageResourceObserver.
+ if (style_ && !IsText())
+ UpdateImageObservers(style_.get(), nullptr);
- if (StyleImage* mask_box_image = style_->MaskBoxImage().GetImage())
- mask_box_image->RemoveClient(this);
-
- if (style_->GetContentData() && style_->GetContentData()->IsImage())
- ToImageContentData(style_->GetContentData())
- ->GetImage()
- ->RemoveClient(this);
-
- if (style_->BoxReflect() && style_->BoxReflect()->Mask().GetImage())
- style_->BoxReflect()->Mask().GetImage()->RemoveClient(this);
-
- RemoveShapeImageClient(style_->ShapeOutside());
- RemoveCursorImageClient(style_->Cursors());
- }
+#if DCHECK_IS_ON()
+ // We must have removed all image observers.
+ SECURITY_DCHECK(as_image_observer_count_ == 0u);
+#endif
if (GetFrameView())
SetIsBackgroundAttachmentFixedObject(false);
@@ -3385,23 +3448,6 @@ void LayoutObject::Destroy() {
delete this;
}
-DISABLE_CFI_PERF
-void LayoutObject::RemoveShapeImageClient(ShapeValue* shape_value) {
- if (!shape_value)
- return;
- if (StyleImage* shape_image = shape_value->GetImage())
- shape_image->RemoveClient(this);
-}
-
-void LayoutObject::RemoveCursorImageClient(const CursorList* cursor_list) {
- if (!cursor_list)
- return;
- for (const CursorData& cursor : *cursor_list) {
- if (cursor.GetImage())
- cursor.GetImage()->RemoveClient(this);
- }
-}
-
PositionWithAffinity LayoutObject::PositionForPoint(const LayoutPoint&) const {
return CreatePositionWithAffinity(CaretMinOffset());
}
@@ -3597,8 +3643,16 @@ const ComputedStyle* LayoutObject::GetCachedPseudoStyle(
if (!element)
return nullptr;
- return element->CachedStyleForPseudoElement(PseudoStyleRequest(pseudo),
- parent_style);
+ const auto* cached_pseudo_style = element->CachedStyleForPseudoElement(
+ PseudoStyleRequest(pseudo), parent_style);
+ if (cached_pseudo_style && pseudo == kPseudoIdFirstLine &&
+ bitfields_.PendingUpdateFirstLineImageObservers()) {
+ // Update image observers now after we have updated the first line
+ // style cache.
+ const_cast<LayoutObject*>(this)->UpdateFirstLineImageObservers(nullptr,
+ Style());
+ }
+ return cached_pseudo_style;
}
scoped_refptr<ComputedStyle> LayoutObject::GetUncachedPseudoStyle(
@@ -4065,12 +4119,7 @@ void LayoutObject::InvalidateSelectedChildrenOnStyleChange() {
continue;
if (!child->IsSelected())
continue;
- if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
- child->SetShouldDoFullPaintInvalidation(
- PaintInvalidationReason::kSelection);
- } else {
- child->SetShouldInvalidateSelection();
- }
+ child->SetShouldInvalidateSelection();
}
}
@@ -4177,6 +4226,24 @@ LayoutRect LayoutObject::AdjustVisualRectForInlineBox(
return visual_rect;
}
+Vector<LayoutRect> LayoutObject::PhysicalOutlineRects(
+ const LayoutPoint& additional_offset,
+ NGOutlineType outline_type) const {
+ Vector<LayoutRect> outline_rects;
+ AddOutlineRects(outline_rects, additional_offset, outline_type);
+ if (IsSVGChild() || !HasFlippedBlocksWritingMode())
+ return outline_rects;
+
+ const auto* writing_mode_container =
+ IsBox() ? ToLayoutBox(this) : ContainingBlock();
+ for (auto& r : outline_rects) {
+ r.MoveBy(-additional_offset);
+ writing_mode_container->FlipForWritingMode(r);
+ r.MoveBy(additional_offset);
+ }
+ return outline_rects;
+}
+
} // namespace blink
#ifndef NDEBUG
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object.h b/chromium/third_party/blink/renderer/core/layout/layout_object.h
index fecff01ceae..86c9d68434a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.h
@@ -102,6 +102,12 @@ enum MarkingBehavior {
enum ScheduleRelayoutBehavior { kScheduleRelayout, kDontScheduleRelayout };
+enum {
+ kBackgroundPaintInGraphicsLayer = 1 << 0,
+ kBackgroundPaintInScrollingContents = 1 << 1
+};
+using BackgroundPaintLocation = uint8_t;
+
struct AnnotatedRegionValue {
DISALLOW_NEW();
bool operator==(const AnnotatedRegionValue& o) const {
@@ -897,6 +903,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.NeedsPositionedMovementLayout();
}
+ bool NeedsPositionedMovementLayoutOnly() const {
+ return bitfields_.NeedsPositionedMovementLayout() &&
+ !bitfields_.SelfNeedsLayout() &&
+ !bitfields_.NormalChildNeedsLayout() &&
+ !bitfields_.PosChildNeedsLayout() &&
+ !bitfields_.NeedsSimplifiedNormalFlowLayout();
+ }
+
bool SelfNeedsLayout() const { return bitfields_.SelfNeedsLayout(); }
bool NeedsPositionedMovementLayout() const {
return bitfields_.NeedsPositionedMovementLayout();
@@ -915,18 +929,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return bitfields_.PreferredLogicalWidthsDirty();
}
- bool NeedsOverflowRecalc() const {
- return SelfNeedsOverflowRecalc() || ChildNeedsOverflowRecalc();
- }
- bool SelfNeedsOverflowRecalc() const {
- return bitfields_.SelfNeedsLayoutOverflowRecalc() ||
- bitfields_.SelfNeedsVisualOverflowRecalc();
- }
- bool ChildNeedsOverflowRecalc() const {
- return bitfields_.ChildNeedsLayoutOverflowRecalc() ||
- bitfields_.ChildNeedsVisualOverflowRecalc();
- }
-
bool NeedsLayoutOverflowRecalc() const {
return bitfields_.SelfNeedsLayoutOverflowRecalc() ||
bitfields_.ChildNeedsLayoutOverflowRecalc();
@@ -950,29 +952,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetChildNeedsLayoutOverflowRecalc(false);
}
- bool NeedsVisualOverflowRecalc() const {
- return bitfields_.SelfNeedsVisualOverflowRecalc() ||
- bitfields_.ChildNeedsVisualOverflowRecalc();
- }
- bool SelfNeedsVisualOverflowRecalc() const {
- return bitfields_.SelfNeedsVisualOverflowRecalc();
- }
- bool ChildNeedsVisualOverflowRecalc() const {
- return bitfields_.ChildNeedsVisualOverflowRecalc();
- }
- void SetSelfNeedsVisualOverflowRecalc() {
- bitfields_.SetSelfNeedsVisualOverflowRecalc(true);
- }
- void SetChildNeedsVisualOverflowRecalc() {
- bitfields_.SetChildNeedsVisualOverflowRecalc(true);
- }
- void ClearSelfNeedsVisualOverflowRecalc() {
- bitfields_.SetSelfNeedsVisualOverflowRecalc(false);
- }
- void ClearChildNeedsVisualOverflowRecalc() {
- bitfields_.SetChildNeedsVisualOverflowRecalc(false);
- }
-
// CSS clip only applies when position is absolute or fixed. Prefer this check
// over !StyleRef().HasAutoClip().
bool HasClip() const {
@@ -1262,7 +1241,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
virtual void Paint(const PaintInfo&) const;
- virtual bool RecalcOverflow();
+ virtual bool RecalcLayoutOverflow();
+ // Recalculates visual overflow for this object and non-self-painting
+ // PaintLayer descendants.
+ virtual void RecalcVisualOverflow();
// Subclasses must reimplement this method to compute the size and position
// of this object and all its descendants.
@@ -1359,9 +1341,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
LayoutObject* parent);
void SetStyleWithWritingModeOfParent(scoped_refptr<ComputedStyle>);
- void FirstLineStyleDidChange(const ComputedStyle& old_style,
- const ComputedStyle& new_style);
-
void ClearBaseComputedStyle();
// This function returns an enclosing non-anonymous LayoutBlock for this
@@ -1707,9 +1686,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// -webkit-flex).
virtual bool IsFlexibleBox() const { return false; }
- bool IsFlexibleBoxIncludingDeprecated() const {
- return IsFlexibleBox() || IsDeprecatedFlexibleBox();
- }
+ virtual bool IsFlexibleBoxIncludingDeprecatedAndNG() const { return false; }
+
+ virtual bool IsFlexibleBoxIncludingNG() const { return false; }
bool IsListItemIncludingNG() const {
return IsListItem() || IsLayoutNGListItem();
@@ -1790,6 +1769,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
const LayoutPoint& additional_offset,
NGOutlineType) const {}
+ Vector<LayoutRect> PhysicalOutlineRects(const LayoutPoint& additional_offset,
+ NGOutlineType) const;
+
// For history and compatibility reasons, we draw outline:auto (for focus
// rings) and normal style outline differently.
// Focus rings enclose block visual overflows (of line boxes and descendants),
@@ -1805,19 +1787,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetContainsInlineWithOutlineAndContinuation(b);
}
- // Collects rectangles enclosing visual overflows of the DOM subtree under
- // this object.
- // The rects also cover continuations which may be not in the layout subtree
- // of this object.
- // TODO(crbug.com/614781): Currently the result rects don't cover list markers
- // and outlines.
- void AddElementVisualOverflowRects(
- Vector<LayoutRect>& rects,
- const LayoutPoint& additional_offset) const {
- AddOutlineRects(rects, additional_offset,
- NGOutlineType::kIncludeBlockVisualOverflow);
- }
-
// Compute a list of hit-test rectangles per layer rooted at this
// layoutObject with at most the given touch action.
virtual void ComputeLayerHitTestRects(LayerHitTestRects&, TouchAction) const;
@@ -2031,7 +2000,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
void SetPreviousBackgroundObscured(bool b) {
- layout_object_.SetPreviousBackgroundObscured(b);
+ layout_object_.bitfields_.SetPreviousBackgroundObscured(b);
+ }
+ void SetPreviousBackgroundPaintLocation(BackgroundPaintLocation location) {
+ layout_object_.bitfields_.SetPreviousBackgroundPaintLocation(location);
}
void UpdatePreviousOutlineMayBeAffectedByDescendants() {
layout_object_.SetPreviousOutlineMayBeAffectedByDescendants(
@@ -2081,9 +2053,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
friend class PaintPropertyTreeBuilder;
friend class PrePaintTreeWalk;
FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
- canStartElementOnCompositorTransformSPv2);
+ canStartElementOnCompositorTransformCAP);
FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
- canStartElementOnCompositorEffectSPv2);
+ canStartElementOnCompositorEffectCAP);
FRIEND_TEST_ALL_PREFIXES(PrePaintTreeWalkTest, ClipRects);
FRIEND_TEST_ALL_PREFIXES(LayoutObjectTest, VisualRect);
FRIEND_TEST_ALL_PREFIXES(BoxPaintInvalidatorTest,
@@ -2146,8 +2118,8 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool PreviousBackgroundObscured() const {
return bitfields_.PreviousBackgroundObscured();
}
- void SetPreviousBackgroundObscured(bool b) {
- bitfields_.SetPreviousBackgroundObscured(b);
+ BackgroundPaintLocation PreviousBackgroundPaintLocation() const {
+ return bitfields_.PreviousBackgroundPaintLocation();
}
bool IsBackgroundAttachmentFixedObject() const {
@@ -2396,6 +2368,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
context->DidLayout();
}
+ DisplayLockContext* GetDisplayLockContext() const {
+ if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
+ return nullptr;
+ if (!GetNode() || !GetNode()->IsElementNode())
+ return nullptr;
+ return ToElement(GetNode())->GetDisplayLockContext();
+ }
+
private:
// Used only by applyFirstLineChanges to get a first line style based off of a
// given new style, without accessing the cache.
@@ -2416,15 +2396,18 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool IsInert() const;
- void UpdateImage(StyleImage*, StyleImage*);
-
void ScheduleRelayout();
+ void AddAsImageObserver(StyleImage*);
+ void RemoveAsImageObserver(StyleImage*);
+
+ void UpdateImage(StyleImage*, StyleImage*);
void UpdateShapeImage(const ShapeValue*, const ShapeValue*);
void UpdateFillImages(const FillLayer* old_layers,
- const FillLayer& new_layers);
+ const FillLayer* new_layers);
void UpdateCursorImages(const CursorList* old_cursors,
const CursorList* new_cursors);
+
void CheckCounterChanges(const ComputedStyle* old_style,
const ComputedStyle* new_style);
@@ -2446,9 +2429,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
const ComputedStyle* CachedFirstLineStyle() const;
StyleDifference AdjustStyleDifference(StyleDifference) const;
- void RemoveShapeImageClient(ShapeValue*);
- void RemoveCursorImageClient(const CursorList*);
-
// These are helper functions for AbsoluteBoudingBoxRectHandlingEmptyAnchor()
// and AbsoluteBoundingBoxRectForScrollIntoView().
enum class ExpandScrollMargin { kExpand, kIgnore };
@@ -2468,8 +2448,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// LayoutView to return the owning LayoutObject in the containing frame.
inline LayoutObject* ParentCrossingFrames() const;
- void ApplyPseudoStyleChanges(const ComputedStyle& old_style);
- void ApplyFirstLineChanges(const ComputedStyle& old_style);
+ void UpdateImageObservers(const ComputedStyle* old_style,
+ const ComputedStyle* new_style);
+ void UpdateFirstLineImageObservers(const ComputedStyle* old_style,
+ const ComputedStyle* new_style);
+
+ void ApplyPseudoStyleChanges(const ComputedStyle* old_style);
+ void ApplyFirstLineChanges(const ComputedStyle* old_style);
LayoutRect VisualRectForInlineBox() const {
return AdjustVisualRectForInlineBox(VisualRect());
@@ -2479,14 +2464,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
LayoutRect AdjustVisualRectForInlineBox(const LayoutRect&) const;
- DisplayLockContext* GetDisplayLockContext() const {
- if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
- return nullptr;
- if (!GetNode() || !GetNode()->IsElementNode())
- return nullptr;
- return ToElement(GetNode())->GetDisplayLockContext();
- }
-
// This is set by Set[Subtree]ShouldDoFullPaintInvalidation, and cleared
// during PrePaint in this object's InvalidatePaint(). It's different from
// DisplayItemClient::GetPaintInvalidationReason() which is set during
@@ -2507,6 +2484,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
#if DCHECK_IS_ON()
unsigned has_ax_object_ : 1;
unsigned set_needs_layout_forbidden_ : 1;
+ unsigned as_image_observer_count_ : 20;
#endif
#define ADD_BOOLEAN_BITFIELD(field_name_, MethodNameBase) \
@@ -2552,8 +2530,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
needs_simplified_normal_flow_layout_(false),
self_needs_layout_overflow_recalc_(false),
child_needs_layout_overflow_recalc_(false),
- self_needs_visual_overflow_recalc_(false),
- child_needs_visual_overflow_recalc_(false),
preferred_logical_widths_dirty_(false),
needs_collect_inlines_(false),
should_check_for_paint_invalidation_(true),
@@ -2604,11 +2580,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
descendant_effective_whitelisted_touch_action_changed_(false),
is_effective_root_scroller_(false),
is_global_root_scroller_(false),
+ pending_update_first_line_image_observers_(false),
positioned_state_(kIsStaticallyPositioned),
selection_state_(static_cast<unsigned>(SelectionState::kNone)),
background_obscuration_state_(kBackgroundObscurationStatusInvalid),
subtree_paint_property_update_reasons_(
- static_cast<unsigned>(SubtreePaintPropertyUpdateReason::kNone)) {}
+ static_cast<unsigned>(SubtreePaintPropertyUpdateReason::kNone)),
+ previous_background_paint_location_(0) {}
// Self needs layout means that this layout object is marked for a full
// layout. This is the default layout but it is expensive as it recomputes
@@ -2652,12 +2630,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
ADD_BOOLEAN_BITFIELD(child_needs_layout_overflow_recalc_,
ChildNeedsLayoutOverflowRecalc);
- ADD_BOOLEAN_BITFIELD(self_needs_visual_overflow_recalc_,
- SelfNeedsVisualOverflowRecalc);
-
- ADD_BOOLEAN_BITFIELD(child_needs_visual_overflow_recalc_,
- ChildNeedsVisualOverflowRecalc);
-
// This boolean marks preferred logical widths for lazy recomputation.
//
// See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above about those
@@ -2845,6 +2817,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
ADD_BOOLEAN_BITFIELD(is_effective_root_scroller_, IsEffectiveRootScroller);
ADD_BOOLEAN_BITFIELD(is_global_root_scroller_, IsGlobalRootScroller);
+ // First line style is resolvable only after the object is inserted into
+ // the tree, so we should set this flag when the object set a style having
+ // first line style before it is inserted into the tree.
+ ADD_BOOLEAN_BITFIELD(pending_update_first_line_image_observers_,
+ PendingUpdateFirstLineImageObservers);
+
private:
// This is the cached 'position' value of this object
// (see ComputedStyle::position).
@@ -2858,6 +2836,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
unsigned subtree_paint_property_update_reasons_
: kSubtreePaintPropertyUpdateReasonsBitfieldWidth;
+ // BackgroundPaintLocation of previous paint invalidation.
+ unsigned previous_background_paint_location_ : 2;
+
public:
bool IsOutOfFlowPositioned() const {
return positioned_state_ == kIsOutOfFlowPositioned;
@@ -2932,6 +2913,17 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
BackgroundObscurationState s) const {
background_obscuration_state_ = s;
}
+
+ ALWAYS_INLINE BackgroundPaintLocation
+ PreviousBackgroundPaintLocation() const {
+ return static_cast<BackgroundPaintLocation>(
+ previous_background_paint_location_);
+ }
+ ALWAYS_INLINE void SetPreviousBackgroundPaintLocation(
+ BackgroundPaintLocation location) {
+ previous_background_paint_location_ = static_cast<unsigned>(location);
+ DCHECK_EQ(location, PreviousBackgroundPaintLocation());
+ }
};
#undef ADD_BOOLEAN_BITFIELD
@@ -3003,8 +2995,9 @@ inline void LayoutObject::SetNeedsLayout(
#endif
bool already_needed_layout = bitfields_.SelfNeedsLayout();
SetSelfNeedsLayout(true);
+ SetNeedsOverflowRecalc();
MarkContainerNeedsCollectInlines();
- if (!already_needed_layout && !LayoutBlockedByDisplayLock()) {
+ if (!already_needed_layout) {
TRACE_EVENT_INSTANT1(
TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
"LayoutInvalidationTracking", TRACE_EVENT_SCOPE_THREAD, "data",
@@ -3049,6 +3042,7 @@ inline void LayoutObject::SetChildNeedsLayout(MarkingBehavior mark_parents,
DCHECK(!IsSetNeedsLayoutForbidden());
#endif
bool already_needed_layout = NormalChildNeedsLayout();
+ SetNeedsOverflowRecalc();
SetNormalChildNeedsLayout(true);
MarkContainerNeedsCollectInlines();
// FIXME: Replace MarkOnlyThis with the SubtreeLayoutScope code path and
@@ -3060,6 +3054,7 @@ inline void LayoutObject::SetChildNeedsLayout(MarkingBehavior mark_parents,
inline void LayoutObject::SetNeedsPositionedMovementLayout() {
bool already_needed_layout = NeedsPositionedMovementLayout();
+ SetNeedsOverflowRecalc();
SetNeedsPositionedMovementLayout(true);
#if DCHECK_IS_ON()
DCHECK(!IsSetNeedsLayoutForbidden());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
index a520da71068..3541cca6ded 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
@@ -62,7 +62,7 @@ void LayoutObjectChildList::DestroyLeftoverChildren() {
while (FirstChild()) {
// List markers are owned by their enclosing list and so don't get destroyed
// by this container.
- if (FirstChild()->IsListMarker()) {
+ if (FirstChild()->IsListMarkerIncludingNG()) {
FirstChild()->Remove();
continue;
}
@@ -217,6 +217,8 @@ void LayoutObjectChildList::InsertChildNode(LayoutObject* owner,
PaintInvalidationReason::kAppeared);
new_child->AddSubtreePaintPropertyUpdateReason(
SubtreePaintPropertyUpdateReason::kContainerChainMayChange);
+ new_child->SetNeedsOverflowRecalc();
+
if (!owner->NormalChildNeedsLayout()) {
owner->SetChildNeedsLayout(); // We may supply the static position for an
// absolute positioned child.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
index d74784be9e0..674a5dd9351 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -278,8 +278,13 @@ TEST_F(LayoutObjectTest, InlineFloatMismatch) {
ToLayoutBoxModelObject(GetLayoutObjectByElementId("float_obj"));
LayoutObject* span =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("span"));
- // 10px for margin, -40px because float is to the left of the span.
- EXPECT_EQ(LayoutSize(-30, 0), float_obj->OffsetFromAncestor(span));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // 10px for margin.
+ EXPECT_EQ(LayoutSize(10, 0), float_obj->OffsetFromAncestor(span));
+ } else {
+ // 10px for margin, -40px because float is to the left of the span.
+ EXPECT_EQ(LayoutSize(-30, 0), float_obj->OffsetFromAncestor(span));
+ }
}
TEST_F(LayoutObjectTest, FloatUnderInline) {
@@ -303,17 +308,30 @@ TEST_F(LayoutObjectTest, FloatUnderInline) {
EXPECT_EQ(layered_div->Layer(), layered_div->PaintingLayer());
EXPECT_EQ(layered_span->Layer(), layered_span->PaintingLayer());
- EXPECT_EQ(layered_div->Layer(), floating->PaintingLayer());
- EXPECT_EQ(container, floating->Container());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // LayoutNG inline-level floats are children of their inline-level
+ // containers. As such LayoutNG paints these within the correct
+ // inline-level layer.
+ EXPECT_EQ(layered_span->Layer(), floating->PaintingLayer());
+ EXPECT_EQ(layered_span, floating->Container());
+ } else {
+ EXPECT_EQ(layered_div->Layer(), floating->PaintingLayer());
+ EXPECT_EQ(container, floating->Container());
+ }
EXPECT_EQ(container, floating->ContainingBlock());
LayoutObject::AncestorSkipInfo skip_info(layered_span);
- EXPECT_EQ(container, floating->Container(&skip_info));
- EXPECT_TRUE(skip_info.AncestorSkipped());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(layered_span, floating->Container(&skip_info));
+ EXPECT_FALSE(skip_info.AncestorSkipped());
+ } else {
+ EXPECT_EQ(container, floating->Container(&skip_info));
+ EXPECT_TRUE(skip_info.AncestorSkipped());
- skip_info = LayoutObject::AncestorSkipInfo(container);
- EXPECT_EQ(container, floating->Container(&skip_info));
- EXPECT_FALSE(skip_info.AncestorSkipped());
+ skip_info = LayoutObject::AncestorSkipInfo(container);
+ EXPECT_EQ(container, floating->Container(&skip_info));
+ EXPECT_FALSE(skip_info.AncestorSkipped());
+ }
}
TEST_F(LayoutObjectTest, MutableForPaintingClearPaintFlags) {
@@ -809,6 +827,30 @@ TEST_F(LayoutObjectTest, DistortingVisualEffectsUnaliases) {
EXPECT_TRUE(object->HasNonZeroEffectiveOpacity());
}
+TEST_F(LayoutObjectTest, UpdateVisualRectAfterAncestorLayout) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #target {
+ width: 50px;
+ height: 0;
+ position: relative;
+ }
+ </style>
+ <div id=ancestor style="width: 100px; height: 100px; position: relative">
+ <div>
+ <div id=target></div>
+ </div>
+ </div>
+ )HTML");
+
+ auto* target = GetDocument().getElementById("target");
+ target->setAttribute(html_names::kStyleAttr, "height: 300px");
+ UpdateAllLifecyclePhasesForTest();
+ const auto* container = GetLayoutObjectByElementId("ancestor");
+ EXPECT_EQ(LayoutRect(0, 0, 100, 300),
+ ToLayoutBox(container)->VisualOverflowRect());
+}
+
class LayoutObjectSimTest : public SimTest {
public:
bool DocumentHasTouchActionRegion(const EventHandlerRegistry& registry) {
@@ -905,4 +947,102 @@ TEST_F(LayoutObjectSimTest, HitTestForOcclusionInIframe) {
EXPECT_EQ(result.InnerNode(), occluder);
}
+TEST_F(LayoutObjectSimTest, FirstLineBackgroundImage) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete(R"HTML(
+ <style>
+ div::first-line {
+ background-image: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==);
+ }
+ span { background: rgba(0, 255, 0, 0.3); }
+ </style>
+ <div id="target">
+ <span id="first-line1">Text</span><span id="first-line2">Text</span><br>
+ <span id="second-line">Text</span>
+ </div>
+ <div>To keep the image alive when target is set display: none</div>
+ )HTML");
+
+ GetDocument().View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kTest);
+
+ auto* target = GetDocument().getElementById("target");
+ auto* target_object = target->GetLayoutObject();
+ auto* image_resource_content = target_object->FirstLineStyleRef()
+ .BackgroundLayers()
+ .GetImage()
+ ->CachedImage();
+
+ // Simulate an image change notification, and we should invalidate the objects
+ // in the first line.
+ static_cast<ImageObserver*>(image_resource_content)
+ ->Changed(image_resource_content->GetImage());
+
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // The block itself doesn't paint the first line, so we don't need to
+ // invalidate it for the image change in the first line style.
+ EXPECT_FALSE(target_object->ShouldDoFullPaintInvalidation());
+ } else {
+ // In legacy layout mode, the block is the layout object of the first line's
+ // root line box, so we invalidate it.
+ EXPECT_TRUE(target_object->ShouldDoFullPaintInvalidation());
+ }
+ auto* first_line1 =
+ GetDocument().getElementById("first-line1")->GetLayoutObject();
+ EXPECT_TRUE(first_line1->ShouldDoFullPaintInvalidation());
+ EXPECT_TRUE(first_line1->SlowFirstChild()->ShouldDoFullPaintInvalidation());
+ auto* first_line2 =
+ GetDocument().getElementById("first-line2")->GetLayoutObject();
+ EXPECT_TRUE(first_line2->ShouldDoFullPaintInvalidation());
+ EXPECT_TRUE(first_line2->SlowFirstChild()->ShouldDoFullPaintInvalidation());
+ auto* second_line =
+ GetDocument().getElementById("second-line")->GetLayoutObject();
+ EXPECT_FALSE(second_line->ShouldDoFullPaintInvalidation());
+ EXPECT_FALSE(second_line->SlowFirstChild()->ShouldDoFullPaintInvalidation());
+
+ target->setAttribute(html_names::kStyleAttr, "display: none");
+ GetDocument().View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kTest);
+ target_object = target->GetLayoutObject();
+ EXPECT_EQ(nullptr, target_object);
+ // The image is still alive because the other div's first line style still
+ // reference it. The following statement should not crash.
+ static_cast<ImageObserver*>(image_resource_content)
+ ->Changed(image_resource_content->GetImage());
+}
+
+TEST_F(LayoutObjectTest, FirstLineBackgroundImageNestedCrash) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ *::first-line { background-image: linear-gradient(red, blue); }
+ </style>
+ <div><span><div>ABCDE</div></span></div>
+ )HTML");
+
+ // The following code should not crash due to incorrectly paired
+ // StyleImage::AddClient() and RemoveClient().
+ GetDocument().documentElement()->setAttribute(html_names::kStyleAttr,
+ "display: none");
+ UpdateAllLifecyclePhasesForTest();
+}
+
+TEST_F(LayoutObjectTest, FirstLineBackgroundImageAddBlockBackgroundImageCrash) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #target::first-line { background-image: linear-gradient(red, blue); }
+ </style>
+ <div id="target"></div>
+ )HTML");
+
+ // The following code should not crash due to incorrectly paired
+ // StyleImage::AddClient() and RemoveClient().
+ GetDocument().getElementById("target")->setAttribute(
+ html_names::kStyleAttr,
+ "background-image: url(data:image/gif;base64,"
+ "R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)");
+ UpdateAllLifecyclePhasesForTest();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_quote.cc b/chromium/third_party/blink/renderer/core/layout/layout_quote.cc
index 3ab2a8a4164..9b12aa15f70 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_quote.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_quote.cc
@@ -21,14 +21,15 @@
#include "third_party/blink/renderer/core/layout/layout_quote.h"
+#include <algorithm>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include <algorithm>
-
namespace blink {
LayoutQuote::LayoutQuote(PseudoElement& pseudo, QuoteType quote)
@@ -233,7 +234,7 @@ const QuotesData* QuotesDataForLanguage(const AtomicString& lang) {
return nullptr;
// This could be just a hash table, but doing that adds 200k to LayoutQuote.o
- Language* languages_end = g_languages + arraysize(g_languages);
+ Language* languages_end = g_languages + base::size(g_languages);
CString lowercase_lang = lang.DeprecatedLower().Utf8();
Language key = {lowercase_lang.data(), 0, 0, 0, 0, nullptr};
Language* match = std::lower_bound(g_languages, languages_end, key);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
index 6a1daea6062..0cbb9320b12 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -99,8 +99,7 @@ void LayoutReplaced::UpdateLayout() {
UpdateLogicalWidth();
UpdateLogicalHeight();
- overflow_.reset();
- AddVisualEffectOverflow();
+ ClearLayoutOverflow();
UpdateAfterLayout();
ClearNeedsLayout();
@@ -153,8 +152,19 @@ static inline bool LayoutObjectHasAspectRatio(
layout_object->IsVideo();
}
+void LayoutReplaced::RecalcVisualOverflow() {
+ LayoutObject::RecalcVisualOverflow();
+ ClearVisualOverflow();
+ AddVisualEffectOverflow();
+}
+
void LayoutReplaced::ComputeIntrinsicSizingInfoForReplacedContent(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ if (ShouldApplySizeContainment()) {
+ intrinsic_sizing_info.size = FloatSize();
+ return;
+ }
+
ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
// Update our intrinsic size to match what was computed, so that
@@ -648,11 +658,7 @@ LayoutRect LayoutReplaced::PreSnappedRectForPersistentSizing(LayoutRect rect) {
void LayoutReplaced::ComputeIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
- if (ShouldApplySizeContainment()) {
- intrinsic_sizing_info.size = FloatSize();
- return;
- }
-
+ DCHECK(!ShouldApplySizeContainment());
intrinsic_sizing_info.size = FloatSize(IntrinsicLogicalWidth().ToFloat(),
IntrinsicLogicalHeight().ToFloat());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
index 62be25f377f..26824005a41 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -71,6 +71,8 @@ class CORE_EXPORT LayoutReplaced : public LayoutBox {
bool NeedsPreferredWidthsRecalculation() const override;
+ void RecalcVisualOverflow() override;
+
// These values are specified to be 300 and 150 pixels in the CSS 2.1 spec.
// http://www.w3.org/TR/CSS2/visudet.html#inline-replaced-width
static const int kDefaultWidth;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc b/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc
index 8dcbcefd71c..c6e45b40240 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc
@@ -128,8 +128,15 @@ void LayoutRubyBase::MoveBlockChildren(LayoutRubyBase* to_base,
// Move all remaining children normally. If moving all children, include our
// float list.
if (!before_child) {
- MoveAllChildrenIncludingFloatsTo(to_base,
- to_base->HasLayer() || HasLayer());
+ bool full_remove_insert = to_base->HasLayer() || HasLayer();
+ // TODO(kojii): |this| is |!ChildrenInline()| when we enter this function,
+ // but it may turn to |ChildrenInline()| when |anon_block_here| is destroyed
+ // above. Probably the correct fix is to do it earlier and switch to
+ // |MoveInlineChildren()| if this happens. For the short term safe fix,
+ // using |full_remove_insert| can prevent inconsistent LayoutObject tree
+ // that leads to CHECK failures.
+ full_remove_insert |= ChildrenInline();
+ MoveAllChildrenIncludingFloatsTo(to_base, full_remove_insert);
} else {
MoveChildrenTo(to_base, FirstChild(), before_child);
RemoveFloatingObjectsFromDescendants();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_ruby_run.cc b/chromium/third_party/blink/renderer/core/layout/layout_ruby_run.cc
index 699e128ec54..bba4c5c90b8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_ruby_run.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_ruby_run.cc
@@ -261,7 +261,7 @@ void LayoutRubyRun::UpdateLayout() {
}
// Update our overflow to account for the new LayoutRubyText position.
- ComputeOverflow(ClientLogicalBottom());
+ ComputeLayoutOverflow(ClientLogicalBottom());
}
void LayoutRubyRun::GetOverhang(bool first_line,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider.h b/chromium/third_party/blink/renderer/core/layout/layout_slider.h
index 6bfcca82c9a..09d62822dc7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider.h
@@ -29,14 +29,14 @@ namespace blink {
class HTMLInputElement;
class SliderThumbElement;
-class LayoutSlider final : public LayoutFlexibleBox {
+class CORE_EXPORT LayoutSlider final : public LayoutFlexibleBox {
public:
static const int kDefaultTrackLength;
explicit LayoutSlider(HTMLInputElement*);
~LayoutSlider() override;
- CORE_EXPORT bool InDragMode() const;
+ bool InDragMode() const;
const char* GetName() const override { return "LayoutSlider"; }
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table.cc b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
index ffc3ea95d11..7a51f616867 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
@@ -271,7 +271,7 @@ void LayoutTable::RemoveColumn(const LayoutTableCol*) {
}
bool LayoutTable::IsLogicalWidthAuto() const {
- Length style_logical_width = StyleRef().LogicalWidth();
+ const Length& style_logical_width = StyleRef().LogicalWidth();
return (!style_logical_width.IsSpecified() ||
!style_logical_width.IsPositive()) &&
!style_logical_width.IsIntrinsic();
@@ -286,7 +286,7 @@ void LayoutTable::UpdateLogicalWidth() {
if (PreferredLogicalWidthsDirty())
ComputePreferredLogicalWidths();
- if (IsFlexItemIncludingDeprecated() || IsGridItem()) {
+ if (IsFlexItemIncludingDeprecatedAndNG() || IsGridItem()) {
// TODO(jfernandez): Investigate whether the grid layout algorithm provides
// all the logic needed and that we're not skipping anything essential due
// to the early return here.
@@ -314,10 +314,9 @@ void LayoutTable::UpdateLogicalWidth() {
? PerpendicularContainingBlockLogicalHeight()
: available_logical_width;
- Length style_logical_width = StyleRef().LogicalWidth();
if (!IsLogicalWidthAuto()) {
SetLogicalWidth(ConvertStyleLogicalWidthToComputedWidth(
- style_logical_width, container_width_in_inline_direction));
+ StyleRef().LogicalWidth(), container_width_in_inline_direction));
} else {
// Subtract out any fixed margins from our available width for auto width
// tables.
@@ -351,7 +350,7 @@ void LayoutTable::UpdateLogicalWidth() {
}
// Ensure we aren't bigger than our max-width style.
- Length style_max_logical_width = StyleRef().LogicalMaxWidth();
+ const Length& style_max_logical_width = StyleRef().LogicalMaxWidth();
if ((style_max_logical_width.IsSpecified() &&
!style_max_logical_width.IsNegative()) ||
style_max_logical_width.IsIntrinsic()) {
@@ -369,7 +368,7 @@ void LayoutTable::UpdateLogicalWidth() {
LayoutUnit(std::max(LogicalWidth(), MinPreferredLogicalWidth()).Floor()));
// Ensure we aren't smaller than our min-width style.
- Length style_min_logical_width = StyleRef().LogicalMinWidth();
+ const Length& style_min_logical_width = StyleRef().LogicalMinWidth();
if ((style_min_logical_width.IsSpecified() &&
!style_min_logical_width.IsNegative()) ||
style_min_logical_width.IsIntrinsic()) {
@@ -513,7 +512,7 @@ void LayoutTable::LayoutSection(
LayoutUnit LayoutTable::LogicalHeightFromStyle() const {
LayoutUnit computed_logical_height;
- Length logical_height_length = StyleRef().LogicalHeight();
+ const Length& logical_height_length = StyleRef().LogicalHeight();
if (logical_height_length.IsIntrinsic() ||
(logical_height_length.IsSpecified() &&
logical_height_length.IsPositive())) {
@@ -521,7 +520,7 @@ LayoutUnit LayoutTable::LogicalHeightFromStyle() const {
ConvertStyleLogicalHeightToComputedHeight(logical_height_length);
}
- Length logical_max_height_length = StyleRef().LogicalMaxHeight();
+ const Length& logical_max_height_length = StyleRef().LogicalMaxHeight();
if (logical_max_height_length.IsIntrinsic() ||
(logical_max_height_length.IsSpecified() &&
!logical_max_height_length.IsNegative())) {
@@ -531,7 +530,7 @@ LayoutUnit LayoutTable::LogicalHeightFromStyle() const {
std::min(computed_logical_height, computed_max_logical_height);
}
- Length logical_min_height_length = StyleRef().LogicalMinHeight();
+ const Length& logical_min_height_length = StyleRef().LogicalMinHeight();
if (logical_min_height_length.IsIntrinsic() ||
(logical_min_height_length.IsSpecified() &&
!logical_min_height_length.IsNegative())) {
@@ -568,32 +567,47 @@ void LayoutTable::SimplifiedNormalFlowLayout() {
section = SectionBelow(section)) {
section->LayoutIfNeeded();
section->LayoutRows();
- section->ComputeOverflowFromDescendants();
+ section->ComputeLayoutOverflowFromDescendants();
section->UpdateAfterLayout();
- section->AddVisualEffectOverflow();
}
}
-bool LayoutTable::RecalcOverflow() {
- RecalcSelfOverflow();
+bool LayoutTable::RecalcLayoutOverflow() {
+ RecalcSelfLayoutOverflow();
- if (!ChildNeedsOverflowRecalc())
+ if (!ChildNeedsLayoutOverflowRecalc())
return false;
ClearChildNeedsLayoutOverflowRecalc();
- ClearChildNeedsVisualOverflowRecalc();
// If the table sections we keep pointers to have gone away then the table
// will be rebuilt and overflow will get recalculated anyway so return early.
if (NeedsSectionRecalc())
return false;
- bool children_overflow_changed = false;
+ bool children_layout_overflow_changed = false;
for (LayoutTableSection* section = TopSection(); section;
section = SectionBelow(section)) {
- children_overflow_changed =
- section->RecalcOverflow() || children_overflow_changed;
+ children_layout_overflow_changed =
+ section->RecalcLayoutOverflow() || children_layout_overflow_changed;
}
- return RecalcPositionedDescendantsOverflow() || children_overflow_changed;
+ return RecalcPositionedDescendantsLayoutOverflow() ||
+ children_layout_overflow_changed;
+}
+
+void LayoutTable::RecalcVisualOverflow() {
+ for (auto* caption : captions_) {
+ if (!caption->HasSelfPaintingLayer())
+ caption->RecalcVisualOverflow();
+ }
+
+ for (LayoutTableSection* section = TopSection(); section;
+ section = SectionBelow(section)) {
+ if (!section->HasSelfPaintingLayer())
+ section->RecalcVisualOverflow();
+ }
+
+ RecalcPositionedDescendantsVisualOverflow();
+ RecalcSelfVisualOverflow();
}
void LayoutTable::UpdateLayout() {
@@ -794,7 +808,6 @@ void LayoutTable::UpdateLayout() {
SetLogicalHeight(LogicalHeight() + section->LogicalHeight());
section->UpdateAfterLayout();
- section->AddVisualEffectOverflow();
section = SectionBelow(section);
}
@@ -815,7 +828,7 @@ void LayoutTable::UpdateLayout() {
old_logical_height != LogicalHeight();
LayoutPositionedObjects(dimension_changed);
- ComputeOverflow(ClientLogicalBottom());
+ ComputeLayoutOverflow(ClientLogicalBottom());
UpdateAfterLayout();
if (state.IsPaginated() && IsPageLogicalHeightKnown()) {
@@ -909,17 +922,16 @@ void LayoutTable::InvalidateCollapsedBordersForAllCellsIfNeeded() {
}
}
-void LayoutTable::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
- bool recompute_floats) {
+void LayoutTable::ComputeVisualOverflow(bool) {
+ LayoutRect previous_visual_overflow_rect = VisualOverflowRect();
+ ClearVisualOverflow();
AddVisualOverflowFromChildren();
AddVisualEffectOverflow();
AddVisualOverflowFromTheme();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
+ SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
}
@@ -1523,7 +1535,7 @@ LayoutUnit LayoutTable::FirstLineBoxBaseline() const {
// 'inline-table'). This is also needed to properly determine the baseline of
// a cell if it has a table child.
- if (IsWritingModeRoot())
+ if (IsWritingModeRoot() || ShouldApplyLayoutContainment())
return LayoutUnit(-1);
RecalcSectionsIfNeeded();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table.h b/chromium/third_party/blink/renderer/core/layout/layout_table.h
index 5582a244d09..92feaf2f39c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.h
@@ -361,10 +361,10 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
// onto the same compositing layer as the table (which is rare), and the table
// will create one display item for all collapsed borders. Otherwise each row
// will create one display item for collapsed borders.
- // It always returns false for SPv2.
+ // It always returns false for CAP.
bool ShouldPaintAllCollapsedBorders() const {
DCHECK(collapsed_borders_valid_);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
DCHECK(!should_paint_all_collapsed_borders_);
return should_paint_all_collapsed_borders_;
}
@@ -426,7 +426,10 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void SimplifiedNormalFlowLayout() override;
- bool RecalcOverflow() override;
+
+ bool RecalcLayoutOverflow() final;
+ void RecalcVisualOverflow() final;
+
void EnsureIsReadyForPaintInvalidation() override;
void InvalidatePaint(const PaintInvalidatorContext&) const override;
bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
@@ -474,7 +477,7 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
OverlayScrollbarClipBehavior =
kIgnorePlatformOverlayScrollbarSize) const override;
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) final;
+ void ComputeVisualOverflow(bool recompute_floats) final;
void AddVisualOverflowFromChildren();
void AddLayoutOverflowFromChildren() override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
index c4d51b4495e..85607f2cd97 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -139,7 +139,7 @@ void LayoutTableCell::ColSpanOrRowSpanChanged() {
Length LayoutTableCell::LogicalWidthFromColumns(
LayoutTableCol* first_col_for_this_cell,
- Length width_from_style) const {
+ const Length& width_from_style) const {
DCHECK(first_col_for_this_cell);
DCHECK_EQ(first_col_for_this_cell,
Table()
@@ -150,7 +150,7 @@ Length LayoutTableCell::LogicalWidthFromColumns(
unsigned col_span_count = ColSpan();
int col_width_sum = 0;
for (unsigned i = 1; i <= col_span_count; i++) {
- Length col_width = table_col->StyleRef().LogicalWidth();
+ const Length& col_width = table_col->StyleRef().LogicalWidth();
// Percentage value should be returned only for colSpan == 1.
// Otherwise we return original width for the cell.
@@ -383,10 +383,8 @@ void LayoutTableCell::SetIsSpanningCollapsedColumn(
}
void LayoutTableCell::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
bool recompute_floats) {
- LayoutBlockFlow::ComputeVisualOverflow(previous_visual_overflow_rect,
- recompute_floats);
+ LayoutBlockFlow::ComputeVisualOverflow(recompute_floats);
UpdateCollapsedBorderValues();
if (!collapsed_border_values_)
@@ -491,14 +489,14 @@ void LayoutTableCell::StyleDidChange(StyleDifference diff,
if (LayoutTableBoxComponent::DoCellsHaveDirtyWidth(*this, *table, diff,
*old_style)) {
if (PreviousCell()) {
- // TODO(dgrogan) Add a layout test showing that setChildNeedsLayout is
- // needed instead of setNeedsLayout.
+ // TODO(dgrogan) Add a web test showing that SetChildNeedsLayout is
+ // needed instead of SetNeedsLayout.
PreviousCell()->SetChildNeedsLayout();
PreviousCell()->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
}
if (NextCell()) {
- // TODO(dgrogan) Add a layout test showing that setChildNeedsLayout is
- // needed instead of setNeedsLayout.
+ // TODO(dgrogan) Add a web test showing that SetChildNeedsLayout is
+ // needed instead of SetNeedsLayout.
NextCell()->SetChildNeedsLayout();
NextCell()->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h
index 52baeefc2f1..f6bfb601909 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h
@@ -144,7 +144,7 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
}
Length StyleOrColLogicalWidth() const {
- Length style_width = StyleRef().LogicalWidth();
+ const Length& style_width = StyleRef().LogicalWidth();
if (!style_width.IsAuto())
return style_width;
if (LayoutTableCol* first_column =
@@ -156,7 +156,7 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
}
int LogicalHeightFromStyle() const {
- Length height = StyleRef().LogicalHeight();
+ const Length& height = StyleRef().LogicalHeight();
int style_logical_height =
height.IsIntrinsicOrAuto()
? 0
@@ -341,7 +341,7 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
return is_spanning_collapsed_column_;
}
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) override;
+ void ComputeVisualOverflow(bool recompute_floats) override;
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
@@ -482,7 +482,7 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
void UpdateCollapsedBorderValues() const;
Length LogicalWidthFromColumns(LayoutTableCol* first_col_for_this_cell,
- Length width_from_style) const;
+ const Length& width_from_style) const;
void UpdateColAndRowSpanFlags();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc
index 6ee697026fa..e5c441bbfe2 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc
@@ -81,8 +81,8 @@ void LayoutTableRow::StyleDidChange(StyleDifference diff,
child_box = child_box->NextSiblingBox()) {
if (!child_box->IsTableCell())
continue;
- // TODO(dgrogan) Add a layout test showing that setChildNeedsLayout is
- // needed instead of setNeedsLayout.
+ // TODO(dgrogan) Add a web test showing that SetChildNeedsLayout is
+ // needed instead of SetNeedsLayout.
child_box->SetChildNeedsLayout();
child_box->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
}
@@ -205,8 +205,7 @@ void LayoutTableRow::UpdateLayout() {
Section()->UpdateFragmentationInfoForChild(*cell);
}
- overflow_.reset();
- AddVisualEffectOverflow();
+ ClearLayoutOverflow();
// We do not call addOverflowFromCell here. The cell are laid out to be
// measured above and will be sized correctly in a follow-up phase.
@@ -287,17 +286,54 @@ LayoutTableRow* LayoutTableRow::CreateAnonymousWithParent(
return new_row;
}
-void LayoutTableRow::ComputeOverflow() {
- const auto& old_visual_rect = SelfVisualOverflowRect();
- ClearAllOverflows();
+void LayoutTableRow::ComputeLayoutOverflow() {
+ ClearLayoutOverflow();
+ for (LayoutTableCell* cell = FirstCell(); cell; cell = cell->NextCell())
+ AddLayoutOverflowFromCell(cell);
+}
+
+void LayoutTableRow::RecalcVisualOverflow() {
+ unsigned n_cols = Section()->NumCols(RowIndex());
+ for (unsigned c = 0; c < n_cols; c++) {
+ auto* cell = Section()->OriginatingCellAt(RowIndex(), c);
+ if (!cell)
+ continue;
+ if (!cell->HasSelfPaintingLayer())
+ cell->RecalcVisualOverflow();
+ }
+
+ ComputeVisualOverflow();
+}
+
+void LayoutTableRow::ComputeVisualOverflow() {
+ const auto& old_visual_rect = VisualOverflowRect();
+ ClearVisualOverflow();
AddVisualEffectOverflow();
+
for (LayoutTableCell* cell = FirstCell(); cell; cell = cell->NextCell())
- AddOverflowFromCell(cell);
- if (old_visual_rect != SelfVisualOverflowRect())
+ AddVisualOverflowFromCell(cell);
+ if (old_visual_rect != VisualOverflowRect()) {
SetShouldCheckForPaintInvalidation();
+ }
}
-void LayoutTableRow::AddOverflowFromCell(const LayoutTableCell* cell) {
+void LayoutTableRow::AddLayoutOverflowFromCell(const LayoutTableCell* cell) {
+ LayoutRect cell_layout_overflow_rect =
+ cell->LayoutOverflowRectForPropagation(this);
+
+ // The cell and the row share the section's coordinate system. However
+ // the visual overflow should be determined in the coordinate system of
+ // the row, that's why we shift the rects by cell_row_offset below.
+ LayoutSize cell_row_offset = cell->Location() - Location();
+
+ cell_layout_overflow_rect.Move(cell_row_offset);
+ AddLayoutOverflow(cell_layout_overflow_rect);
+}
+
+void LayoutTableRow::AddVisualOverflowFromCell(const LayoutTableCell* cell) {
+ if (cell->HasSelfPaintingLayer())
+ return;
+
// Table row paints its background behind cells. If the cell spans multiple
// rows, the row's visual rect should be expanded to cover the cell.
// Here don't check background existence to avoid requirement to invalidate
@@ -323,20 +359,10 @@ void LayoutTableRow::AddOverflowFromCell(const LayoutTableCell* cell) {
AddSelfVisualOverflow(collapsed_border_rect);
}
- // Should propagate cell's overflow to row if the cell has row span or has
- // overflow.
- if (cell->ResolvedRowSpan() == 1 && !cell->HasOverflowModel())
- return;
-
LayoutRect cell_visual_overflow_rect =
cell->VisualOverflowRectForPropagation();
cell_visual_overflow_rect.Move(cell_row_offset);
AddContentsVisualOverflow(cell_visual_overflow_rect);
-
- LayoutRect cell_layout_overflow_rect =
- cell->LayoutOverflowRectForPropagation(this);
- cell_layout_overflow_rect.Move(cell_row_offset);
- AddLayoutOverflow(cell_layout_overflow_rect);
}
bool LayoutTableRow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_row.h b/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
index f70334f48de..99f2a62c2a7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
@@ -106,7 +106,9 @@ class CORE_EXPORT LayoutTableRow final : public LayoutTableBoxComponent {
PaginationBreakability GetPaginationBreakability() const final;
- void ComputeOverflow();
+ void ComputeLayoutOverflow();
+
+ void RecalcVisualOverflow() override;
const char* GetName() const override { return "LayoutTableRow"; }
@@ -123,7 +125,9 @@ class CORE_EXPORT LayoutTableRow final : public LayoutTableBoxComponent {
bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
private:
- void AddOverflowFromCell(const LayoutTableCell*);
+ void ComputeVisualOverflow();
+ void AddLayoutOverflowFromCell(const LayoutTableCell*);
+ void AddVisualOverflowFromCell(const LayoutTableCell*);
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectTableRow ||
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
index 74d0dbbb3d7..24c0752684e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/core/layout/layout_table_row.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/subtree_layout_scope.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/table_section_painter.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
@@ -54,7 +55,7 @@ void LayoutTableSection::TableGridRow::UpdateLogicalHeightForCell(
if (cell->ResolvedRowSpan() != 1)
return;
- Length cell_logical_height = cell->StyleRef().LogicalHeight();
+ const Length& cell_logical_height = cell->StyleRef().LogicalHeight();
if (cell_logical_height.IsPositive()) {
switch (cell_logical_height.GetType()) {
case kPercent:
@@ -386,7 +387,7 @@ static void UpdatePositionIncreasedWithRowHeight(
int& accumulated_position_increase,
double& remainder) {
// Without the cast we lose enough precision to cause heights to miss pixels
- // (and trigger asserts) in some layout tests.
+ // (and trigger asserts) in some web tests.
double proportional_position_increase =
remainder + (extra_height * double(row_height)) / total_height;
// The epsilon is to push any values that are close to a whole number but
@@ -1273,14 +1274,14 @@ void LayoutTableSection::LayoutRows() {
}
}
if (row)
- row->ComputeOverflow();
+ row->ComputeLayoutOverflow();
}
DCHECK(!NeedsLayout());
SetLogicalHeight(LayoutUnit(row_pos_[total_rows]));
- ComputeOverflowFromDescendants();
+ ComputeLayoutOverflowFromDescendants();
}
void LayoutTableSection::UpdateLogicalWidthForCollapsedCells(
@@ -1316,7 +1317,7 @@ void LayoutTableSection::UpdateLogicalWidthForCollapsedCells(
if (collapsed_width != 0)
cell->SetIsSpanningCollapsedColumn(true);
// Recompute overflow in case overflow clipping is necessary.
- cell->ComputeOverflow(cell->ClientLogicalBottom());
+ cell->ComputeLayoutOverflow(cell->ClientLogicalBottom(), false);
DCHECK_GE(cell->LogicalWidth(), 0);
}
}
@@ -1358,23 +1359,13 @@ int LayoutTableSection::PaginationStrutForRow(LayoutTableRow* row,
return pagination_strut.Ceil();
}
-void LayoutTableSection::ComputeOverflowFromDescendants() {
+void LayoutTableSection::ComputeVisualOverflowFromDescendants() {
auto old_self_visual_overflow_rect = SelfVisualOverflowRect();
- overflow_.reset();
- overflowing_cells_.clear();
- force_full_paint_ = false;
-
- ComputeVisualOverflowFromDescendants();
+ ClearVisualOverflow();
- // Overflow rect contributes to the visual rect, so if it has changed then we
- // need to signal a possible paint invalidation.
- if (old_self_visual_overflow_rect != SelfVisualOverflowRect())
- SetShouldCheckForPaintInvalidation();
-
- ComputeLayoutOverflowFromDescendants();
-}
+ visually_overflowing_cells_.clear();
+ force_full_paint_ = false;
-void LayoutTableSection::ComputeVisualOverflowFromDescendants() {
// These 2 variables are used to balance the memory consumption vs the paint
// time on big sections with overflowing cells:
// 1. For small sections, don't track overflowing cells because for them the
@@ -1397,11 +1388,12 @@ void LayoutTableSection::ComputeVisualOverflowFromDescendants() {
#if DCHECK_IS_ON()
bool has_overflowing_cell = false;
#endif
-
for (auto* row = FirstRow(); row; row = row->NextRow()) {
AddVisualOverflowFromChild(*row);
for (auto* cell = row->FirstCell(); cell; cell = cell->NextCell()) {
+ if (cell->HasSelfPaintingLayer())
+ continue;
// Let the section's self visual overflow cover the cell's whole collapsed
// borders. This ensures correct raster invalidation on section border
// style change.
@@ -1421,55 +1413,74 @@ void LayoutTableSection::ComputeVisualOverflowFromDescendants() {
#if DCHECK_IS_ON()
has_overflowing_cell = true;
#endif
- if (overflowing_cells_.size() >= max_overflowing_cell_count) {
+ if (visually_overflowing_cells_.size() >= max_overflowing_cell_count) {
force_full_paint_ = true;
// The full paint path does not make any use of the overflowing cells
// info, so don't hold on to the memory.
- overflowing_cells_.clear();
+ visually_overflowing_cells_.clear();
continue;
}
- overflowing_cells_.insert(cell);
+ visually_overflowing_cells_.insert(cell);
}
}
#if DCHECK_IS_ON()
- DCHECK_EQ(has_overflowing_cell, HasOverflowingCell());
+ DCHECK_EQ(has_overflowing_cell, HasVisuallyOverflowingCell());
#endif
+
+ // Overflow rect contributes to the visual rect, so if it has changed then we
+ // need to signal a possible paint invalidation.
+ if (old_self_visual_overflow_rect != SelfVisualOverflowRect())
+ SetShouldCheckForPaintInvalidation();
}
void LayoutTableSection::ComputeLayoutOverflowFromDescendants() {
+ ClearLayoutOverflow();
for (auto* row = FirstRow(); row; row = row->NextRow())
AddLayoutOverflowFromChild(*row);
}
-bool LayoutTableSection::RecalcOverflow() {
- if (!ChildNeedsOverflowRecalc())
+bool LayoutTableSection::RecalcLayoutOverflow() {
+ if (!ChildNeedsLayoutOverflowRecalc())
return false;
- ChildNeedsOverflowRecalc();
+ ClearChildNeedsLayoutOverflowRecalc();
unsigned total_rows = grid_.size();
- bool children_overflow_changed = false;
+ bool children_layout_overflow_changed = false;
for (unsigned r = 0; r < total_rows; r++) {
LayoutTableRow* row_layouter = RowLayoutObjectAt(r);
- if (!row_layouter || !row_layouter->ChildNeedsOverflowRecalc())
+ if (!row_layouter || !row_layouter->ChildNeedsLayoutOverflowRecalc())
continue;
row_layouter->ClearChildNeedsLayoutOverflowRecalc();
- row_layouter->ClearChildNeedsVisualOverflowRecalc();
- bool row_children_overflow_changed = false;
+ bool row_children_layout_overflow_changed = false;
unsigned n_cols = NumCols(r);
for (unsigned c = 0; c < n_cols; c++) {
auto* cell = OriginatingCellAt(r, c);
if (!cell)
continue;
- row_children_overflow_changed |= cell->RecalcOverflow();
+ row_children_layout_overflow_changed |= cell->RecalcLayoutOverflow();
}
- if (row_children_overflow_changed)
- row_layouter->ComputeOverflow();
- children_overflow_changed |= row_children_overflow_changed;
+ if (row_children_layout_overflow_changed)
+ row_layouter->ComputeLayoutOverflow();
+ children_layout_overflow_changed |= row_children_layout_overflow_changed;
}
- if (children_overflow_changed)
- ComputeOverflowFromDescendants();
- return children_overflow_changed;
+ if (children_layout_overflow_changed)
+ ComputeLayoutOverflowFromDescendants();
+
+ return children_layout_overflow_changed;
+}
+
+void LayoutTableSection::RecalcVisualOverflow() {
+ unsigned total_rows = grid_.size();
+ for (unsigned r = 0; r < total_rows; r++) {
+ LayoutTableRow* row_layouter = RowLayoutObjectAt(r);
+ if (!row_layouter || (row_layouter->HasLayer() &&
+ row_layouter->Layer()->IsSelfPaintingLayer()))
+ continue;
+ row_layouter->RecalcVisualOverflow();
+ }
+ ComputeVisualOverflowFromDescendants();
+ AddVisualEffectOverflow();
}
void LayoutTableSection::MarkAllCellsWidthsDirtyAndOrNeedsLayout(
@@ -1721,6 +1732,7 @@ void LayoutTableSection::RowLogicalHeightChanged(LayoutTableRow* row) {
void LayoutTableSection::SetNeedsCellRecalc() {
needs_cell_recalc_ = true;
+ SetNeedsOverflowRecalc();
if (LayoutTable* t = Table())
t->SetNeedsSectionRecalc();
}
@@ -1805,7 +1817,7 @@ bool LayoutTableSection::NodeAtPoint(
!location_in_container.Intersects(OverflowClipRect(adjusted_location)))
return false;
- if (HasOverflowingCell()) {
+ if (HasVisuallyOverflowingCell()) {
for (LayoutTableRow* row = LastRow(); row; row = row->PreviousRow()) {
// FIXME: We have to skip over inline flows, since they can show up inside
// table rows at the moment (a demoted inline <form> for example). If we
@@ -1998,7 +2010,9 @@ int LayoutTableSection::LogicalHeightForRow(
if (grid_[row_index].logical_height.IsSpecified()) {
LayoutUnit specified_logical_height =
MinimumValueForLength(grid_[row_index].logical_height, LayoutUnit());
- logical_height = std::max(logical_height, specified_logical_height.ToInt());
+ // We round here to match computations for row_pos_ in
+ // CalcRowLogicalHeight().
+ logical_height = std::max(logical_height, specified_logical_height.Round());
}
return logical_height;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section.h b/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
index 364313c9253..0f4b2719302 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
@@ -120,8 +120,8 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
int VBorderSpacingBeforeFirstRow() const;
int CalcRowLogicalHeight();
void LayoutRows();
- void ComputeOverflowFromDescendants();
- bool RecalcOverflow() override;
+ bool RecalcLayoutOverflow() final;
+ void RecalcVisualOverflow() final;
void MarkAllCellsWidthsDirtyAndOrNeedsLayout(LayoutTable::WhatToMarkAllCells);
@@ -237,11 +237,11 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
CellSpan& rows,
CellSpan& columns) const;
- const HashSet<const LayoutTableCell*>& OverflowingCells() const {
- return overflowing_cells_;
+ const HashSet<const LayoutTableCell*>& VisuallyOverflowingCells() const {
+ return visually_overflowing_cells_;
}
- bool HasOverflowingCell() const {
- return overflowing_cells_.size() || force_full_paint_;
+ bool HasVisuallyOverflowingCell() const {
+ return visually_overflowing_cells_.size() || force_full_paint_;
}
bool HasMultipleCellLevels() const { return has_multiple_cell_levels_; }
@@ -291,6 +291,8 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
void UpdateLogicalWidthForCollapsedCells(
const Vector<int>& col_collapsed_width);
+ void ComputeLayoutOverflowFromDescendants();
+
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
bool NodeAtPoint(HitTestResult&,
@@ -300,7 +302,6 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
private:
void ComputeVisualOverflowFromDescendants();
- void ComputeLayoutOverflowFromDescendants();
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectTableSection || LayoutBox::IsOfType(type);
@@ -450,8 +451,8 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
// This HashSet holds the overflowing cells for the partial paint path. If we
// have too many overflowing cells, it will be empty and force_full_paint_
- // will be set to save memory. See ComputeOverflowFromDescendants().
- HashSet<const LayoutTableCell*> overflowing_cells_;
+ // will be set to save memory. See ComputeVisualOverflowFromDescendants().
+ HashSet<const LayoutTableCell*> visually_overflowing_cells_;
bool force_full_paint_;
// This boolean tracks if we have cells overlapping due to rowspan / colspan
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc
index a06ed4f74f7..9b40a6313d4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc
@@ -332,7 +332,7 @@ TEST_F(LayoutTableSectionTest, OverflowingCells) {
LayoutRect paint_rect(50, 50, 50, 50);
auto* small_section = CreateSection(20, 20);
- EXPECT_FALSE(small_section->HasOverflowingCell());
+ EXPECT_FALSE(small_section->HasVisuallyOverflowingCell());
CellSpan rows;
CellSpan columns;
small_section->DirtiedRowsAndEffectiveColumns(paint_rect, rows, columns);
@@ -340,7 +340,7 @@ TEST_F(LayoutTableSectionTest, OverflowingCells) {
EXPECT_NE(small_section->FullTableEffectiveColumnSpan(), columns);
auto* big_section = CreateSection(80, 80);
- EXPECT_FALSE(big_section->HasOverflowingCell());
+ EXPECT_FALSE(big_section->HasVisuallyOverflowingCell());
big_section->DirtiedRowsAndEffectiveColumns(paint_rect, rows, columns);
EXPECT_NE(big_section->FullSectionRowSpan(), rows);
EXPECT_NE(big_section->FullTableEffectiveColumnSpan(), columns);
@@ -350,15 +350,15 @@ TEST_F(LayoutTableSectionTest, OverflowingCells) {
UpdateAllLifecyclePhasesForTest();
// Small sections with overflowing cells always use the full paint path.
- EXPECT_TRUE(small_section->HasOverflowingCell());
- EXPECT_EQ(0u, small_section->OverflowingCells().size());
+ EXPECT_TRUE(small_section->HasVisuallyOverflowingCell());
+ EXPECT_EQ(0u, small_section->VisuallyOverflowingCells().size());
small_section->DirtiedRowsAndEffectiveColumns(paint_rect, rows, columns);
EXPECT_EQ(small_section->FullSectionRowSpan(), rows);
EXPECT_EQ(small_section->FullTableEffectiveColumnSpan(), columns);
// Big sections with small number of overflowing cells use partial paint path.
- EXPECT_TRUE(big_section->HasOverflowingCell());
- EXPECT_EQ(80u, big_section->OverflowingCells().size());
+ EXPECT_TRUE(big_section->HasVisuallyOverflowingCell());
+ EXPECT_EQ(80u, big_section->VisuallyOverflowingCells().size());
big_section->DirtiedRowsAndEffectiveColumns(paint_rect, rows, columns);
EXPECT_NE(big_section->FullSectionRowSpan(), rows);
EXPECT_NE(big_section->FullTableEffectiveColumnSpan(), columns);
@@ -370,16 +370,16 @@ TEST_F(LayoutTableSectionTest, OverflowingCells) {
UpdateAllLifecyclePhasesForTest();
// Small sections with overflowing cells always use the full paint path.
- EXPECT_TRUE(small_section->HasOverflowingCell());
- EXPECT_EQ(0u, small_section->OverflowingCells().size());
+ EXPECT_TRUE(small_section->HasVisuallyOverflowingCell());
+ EXPECT_EQ(0u, small_section->VisuallyOverflowingCells().size());
small_section->DirtiedRowsAndEffectiveColumns(paint_rect, rows, columns);
EXPECT_EQ(small_section->FullSectionRowSpan(), rows);
EXPECT_EQ(small_section->FullTableEffectiveColumnSpan(), columns);
// Big sections with too many overflowing cells are forced to use the full
// paint path.
- EXPECT_TRUE(big_section->HasOverflowingCell());
- EXPECT_EQ(0u, big_section->OverflowingCells().size());
+ EXPECT_TRUE(big_section->HasVisuallyOverflowingCell());
+ EXPECT_EQ(0u, big_section->VisuallyOverflowingCells().size());
big_section->DirtiedRowsAndEffectiveColumns(paint_rect, rows, columns);
EXPECT_EQ(big_section->FullSectionRowSpan(), rows);
EXPECT_EQ(big_section->FullTableEffectiveColumnSpan(), columns);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
index d43c46e86b4..2e6b9d1fcaf 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
@@ -319,6 +319,24 @@ TEST_F(LayoutTableTest, OutOfOrderHeadFootAndBody) {
table->BottomNonEmptySection());
}
+TEST_F(LayoutTableTest, VisualOverflowCleared) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #table {
+ width: 50px; height: 50px; box-shadow: 5px 5px 5px black;
+ }
+ </style>
+ <table id='table' style='width: 50px; height: 50px'></table>
+ )HTML");
+ auto* table = GetTableByElementId("table");
+ EXPECT_EQ(LayoutRect(-3, -3, 66, 66), table->SelfVisualOverflowRect());
+ ToElement(table->GetNode())
+ ->setAttribute(html_names::kStyleAttr, "box-shadow: initial");
+ GetDocument().View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kTest);
+ EXPECT_EQ(LayoutRect(0, 0, 50, 50), table->SelfVisualOverflowRect());
+}
+
} // anonymous namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
index 6c609ed13e6..a623bc96fbe 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
@@ -59,6 +59,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
#include "third_party/blink/renderer/platform/fonts/character_range.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -217,10 +218,7 @@ void LayoutText::RemoveAndDestroyTextBoxes() {
for (InlineTextBox* box : TextBoxes())
box->Remove();
} else if (Parent()) {
- if (NGPaintFragment* first_fragment = FirstInlineFragment())
- first_fragment->MarkContainingLineBoxDirty();
- else
- Parent()->DirtyLinesFromChangedChild(this);
+ Parent()->DirtyLinesFromChangedChild(this);
}
}
DeleteTextBoxes();
@@ -802,11 +800,17 @@ PositionWithAffinity LayoutText::PositionForPoint(
ShouldAffinityBeDownstream should_affinity_be_downstream;
if (LineDirectionPointFitsInBox(point_line_direction.ToInt(), box,
should_affinity_be_downstream)) {
+ const int offset = box->OffsetForPosition(
+ point_line_direction, IncludePartialGlyphs, BreakGlyphs);
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled()) {
+ return CreatePositionWithAffinityForBox(
+ box, offset + box->Start(),
+ static_cast<unsigned>(offset) == box->Len()
+ ? kAlwaysUpstream
+ : kAlwaysDownstream);
+ }
return CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(
- box,
- box->OffsetForPosition(point_line_direction, IncludePartialGlyphs,
- BreakGlyphs),
- should_affinity_be_downstream);
+ box, offset, should_affinity_be_downstream);
}
}
}
@@ -814,14 +818,20 @@ PositionWithAffinity LayoutText::PositionForPoint(
}
if (last_box) {
+ const int offset = last_box->OffsetForPosition(
+ point_line_direction, IncludePartialGlyphs, BreakGlyphs);
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled()) {
+ return CreatePositionWithAffinityForBox(
+ last_box, offset + last_box->Start(),
+ static_cast<unsigned>(offset) == last_box->Len() ? kAlwaysUpstream
+ : kAlwaysDownstream);
+ }
+
ShouldAffinityBeDownstream should_affinity_be_downstream;
LineDirectionPointFitsInBox(point_line_direction.ToInt(), last_box,
should_affinity_be_downstream);
return CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(
- last_box,
- last_box->OffsetForPosition(point_line_direction, IncludePartialGlyphs,
- BreakGlyphs),
- should_affinity_be_downstream);
+ last_box, offset, should_affinity_be_downstream);
}
return CreatePositionWithAffinity(0);
}
@@ -1606,17 +1616,20 @@ bool LayoutText::CanOptimizeSetText() const {
// If we have only one line of text and "contain: layout size" we can avoid
// doing a layout and only paint in the SetText() operation.
return Parent()->IsLayoutBlockFlow() &&
- (Parent()->ShouldApplyLayoutContainment() &&
- Parent()->ShouldApplySizeContainment()) &&
- FirstTextBox() &&
- (FirstTextBox() == LastTextBox() &&
- // If "line-height" is "normal" we might need to recompute the
- // baseline which is not straight forward.
- !StyleRef().LineHeight().IsNegative() &&
- // We would need to recompute the position if "direction" is "rtl".
- StyleRef().IsLeftToRightDirection() &&
- // We would need to layout the text if it is justified.
- (StyleRef().GetTextAlign(true) != ETextAlign::kJustify));
+ Parent()->ShouldApplyLayoutContainment() &&
+ Parent()->ShouldApplySizeContainment() &&
+ // If we have "text-overflow: ellipsis" we need to check if we need or
+ // not ellipsis in the new text and recompute its position.
+ !ToLayoutBlockFlow(Parent())->ShouldTruncateOverflowingText() &&
+ !PreviousSibling() && !NextSibling() && FirstTextBox() &&
+ FirstTextBox() == LastTextBox() &&
+ // If "line-height" is "normal" we might need to recompute the
+ // baseline which is not straight forward.
+ !StyleRef().LineHeight().IsNegative() &&
+ // We would need to recompute the position if "direction" is "rtl".
+ StyleRef().IsLeftToRightDirection() &&
+ // We would need to layout the text if it is justified.
+ (StyleRef().GetTextAlign(true) != ETextAlign::kJustify);
}
void LayoutText::SetFirstTextBoxLogicalLeft(float text_width) const {
@@ -2050,6 +2063,18 @@ LayoutRect LayoutText::LinesBoundingBox() const {
}
LayoutRect LayoutText::VisualOverflowRect() const {
+ if (IsInLayoutNGInlineFormattingContext()) {
+ LayoutRect rect;
+ auto fragments = NGPaintFragment::InlineFragmentsFor(this);
+ for (const NGPaintFragment* fragment : fragments) {
+ LayoutRect child_rect = fragment->VisualRect();
+ child_rect.MoveBy(fragment->InlineOffsetToContainerBox().ToLayoutPoint());
+ rect.Unite(child_rect);
+ }
+ ContainingBlock()->FlipForWritingMode(rect);
+ return rect;
+ }
+
if (!FirstTextBox())
return LayoutRect();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc
index 4056a1f163d..43fa011a322 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc
@@ -20,6 +20,7 @@
#include "third_party/blink/renderer/core/layout/layout_text_combine.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
namespace blink {
@@ -184,7 +185,7 @@ void LayoutTextCombine::UpdateFontStyleForCombinedText() {
// Need to try compressed glyphs.
static const FontWidthVariant kWidthVariants[] = {kHalfWidth, kThirdWidth,
kQuarterWidth};
- for (size_t i = 0; i < arraysize(kWidthVariants); ++i) {
+ for (size_t i = 0; i < base::size(kWidthVariants); ++i) {
description.SetWidthVariant(kWidthVariants[i]);
Font compressed_font = Font(description);
compressed_font.Update(font_selector);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
index e3074199b92..12a3c452002 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/core/layout/layout_text_control.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
@@ -204,7 +205,7 @@ bool LayoutTextControl::HasValidAvgCharWidth(const SimpleFontData* font_data,
if (!font_families_with_invalid_char_width_map) {
font_families_with_invalid_char_width_map = new HashSet<AtomicString>;
- for (size_t i = 0; i < arraysize(kFontFamiliesWithInvalidCharWidth); ++i)
+ for (size_t i = 0; i < base::size(kFontFamiliesWithInvalidCharWidth); ++i)
font_families_with_invalid_char_width_map->insert(
AtomicString(kFontFamiliesWithInvalidCharWidth[i]));
}
@@ -319,6 +320,9 @@ LayoutObject* LayoutTextControl::LayoutSpecialExcludedChild(
}
LayoutUnit LayoutTextControl::FirstLineBoxBaseline() const {
+ if (ShouldApplyLayoutContainment())
+ return LayoutUnit(-1);
+
LayoutUnit result = LayoutBlock::FirstLineBoxBaseline();
if (result != -1)
return result;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
index 0c6689925fc..4811074eef4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
@@ -129,8 +129,10 @@ void LayoutTextControlSingleLine::UpdateLayout() {
// The placeholder gets layout last, after the parent text control and its
// other children, so in order to get the correct overflow from the
// placeholder we need to recompute it now.
- if (needed_layout)
- ComputeOverflow(ClientLogicalBottom());
+ if (needed_layout) {
+ SetNeedsOverflowRecalc();
+ ComputeLayoutOverflow(ClientLogicalBottom());
+ }
}
}
@@ -317,8 +319,9 @@ HTMLInputElement* LayoutTextControlSingleLine::InputElement() const {
}
void LayoutTextControlSingleLine::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
bool recompute_floats) {
+ LayoutRect previous_visual_overflow_rect = VisualOverflowRect();
+ ClearVisualOverflow();
AddVisualOverflowFromChildren();
AddVisualEffectOverflow();
@@ -329,8 +332,7 @@ void LayoutTextControlSingleLine::ComputeVisualOverflow(
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
+ SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
index 66c2a232863..9685eadb114 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
@@ -78,7 +78,7 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
LayoutUnit line_height,
LayoutUnit non_content_height) const override;
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) override;
+ void ComputeVisualOverflow(bool recompute_floats) override;
// If the INPUT content height is smaller than the font height, the
// inner-editor element overflows the INPUT box intentionally, however it
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc
new file mode 100644
index 00000000000..562474165cc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
+
+#include "build/build_config.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+
+namespace {
+
+class LayoutTextControlSingleLineTest : public RenderingTest {};
+
+TEST_F(LayoutTextControlSingleLineTest, VisualOverflowCleared) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #input {
+ width: 50px; height: 50px; box-shadow: 5px 5px 5px black;
+ }
+ </style>
+ <input id=input type="text"></input.
+ )HTML");
+ auto* input =
+ ToLayoutTextControlSingleLine(GetLayoutObjectByElementId("input"));
+#if defined(OS_MACOSX)
+ EXPECT_EQ(LayoutRect(-3, -3, 72, 72), input->SelfVisualOverflowRect());
+#else
+ EXPECT_EQ(LayoutRect(-3, -3, 70, 72), input->SelfVisualOverflowRect());
+#endif
+ ToElement(input->GetNode())
+ ->setAttribute(html_names::kStyleAttr, "box-shadow: initial");
+ GetDocument().View()->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kTest);
+#if defined(OS_MACOSX)
+ EXPECT_EQ(LayoutRect(0, 0, 56, 56), input->SelfVisualOverflowRect());
+#else
+ EXPECT_EQ(LayoutRect(0, 0, 54, 56), input->SelfVisualOverflowRect());
+#endif
+}
+
+} // anonymous namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
index b5aee03b8c5..1bcc0e99927 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -680,7 +680,7 @@ void LayoutTheme::SetCaretBlinkInterval(TimeDelta interval) {
}
TimeDelta LayoutTheme::CaretBlinkInterval() const {
- // Disable the blinking caret in layout test mode, as it introduces
+ // Disable the blinking caret in web test mode, as it introduces
// a race condition for the pixel tests. http://b/1198440
return WebTestSupport::IsRunningWebTest() ? TimeDelta()
: caret_blink_interval_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_mobile.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme_mobile.cc
index 34ebc54d40c..4a7e186b1eb 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_mobile.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_mobile.cc
@@ -52,7 +52,7 @@ String LayoutThemeMobile::ExtraFullscreenStyleSheet() {
void LayoutThemeMobile::AdjustInnerSpinButtonStyle(ComputedStyle& style) const {
if (WebTestSupport::IsRunningWebTest()) {
- // Match Linux spin button style in layout tests.
+ // Match Linux spin button style in web tests.
// FIXME: Consider removing the conditional if a future Android theme
// matches this.
IntSize size = Platform::Current()->ThemeEngine()->GetSize(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index ab89c956050..d548b367cab 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -683,6 +683,9 @@ static void Write(WTF::TextStream& ts,
}
}
+ if ((behavior & kLayoutAsTextShowPaintProperties) && layer.NeedsRepaint())
+ ts << " needsRepaint";
+
ts << "\n";
if (paint_phase != kLayerPaintPhaseBackground)
@@ -709,13 +712,20 @@ void LayoutTreeAsText::WriteLayers(WTF::TextStream& ts,
// Calculate the clip rects we should use.
LayoutRect layer_bounds;
ClipRect damage_rect, clip_rect_to_apply;
- layer->Clipper(PaintLayer::kUseGeometryMapper)
- .CalculateRects(
- ClipRectsContext(root_layer,
- &root_layer->GetLayoutObject().FirstFragment(),
- kUncachedClipRects),
- &layer->GetLayoutObject().FirstFragment(), nullptr, layer_bounds,
- damage_rect, clip_rect_to_apply);
+ if (layer->GetLayoutObject().FirstFragment().HasLocalBorderBoxProperties()) {
+ layer->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
+ .CalculateRects(
+ ClipRectsContext(root_layer,
+ &root_layer->GetLayoutObject().FirstFragment(),
+ kUncachedClipRects),
+ &layer->GetLayoutObject().FirstFragment(), nullptr, layer_bounds,
+ damage_rect, clip_rect_to_apply);
+ } else {
+ layer->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
+ .CalculateRects(
+ ClipRectsContext(root_layer, nullptr, kUncachedClipRects), nullptr,
+ nullptr, layer_bounds, damage_rect, clip_rect_to_apply);
+ }
LayoutPoint offset_from_root;
layer->ConvertToLayerCoords(root_layer, offset_from_root);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_video.cc b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
index a9a9763ef6c..93c405ef06e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
@@ -200,8 +200,8 @@ void LayoutVideo::UpdateAfterLayout() {
LayoutBox::UpdateAfterLayout();
// Report violation of unsized-media policy.
if (auto* video_element = ToHTMLVideoElementOrNull(GetNode())) {
- if (video_element->IsDefaultIntrinsicSize())
- media_element_parser_helpers::ReportUnsizedMediaViolation(this);
+ media_element_parser_helpers::ReportUnsizedMediaViolation(
+ this, video_element->IsDefaultIntrinsicSize());
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view.cc b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
index 0b71fa97f23..163b6ac98ef 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
@@ -462,7 +462,7 @@ static void SetShouldDoFullPaintInvalidationForViewAndAllDescendantsInternal(
}
void LayoutView::SetShouldDoFullPaintInvalidationForViewAndAllDescendants() {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
SetSubtreeShouldDoFullPaintInvalidation();
else
SetShouldDoFullPaintInvalidationForViewAndAllDescendantsInternal(this);
@@ -859,10 +859,10 @@ void LayoutView::UpdateFromStyle() {
SetHasBoxDecorationBackground(true);
}
-bool LayoutView::RecalcOverflow() {
- if (!NeedsOverflowRecalc())
+bool LayoutView::RecalcLayoutOverflow() {
+ if (!NeedsLayoutOverflowRecalc())
return false;
- bool result = LayoutBlockFlow::RecalcOverflow();
+ bool result = LayoutBlockFlow::RecalcLayoutOverflow();
if (result) {
// Changing overflow should notify scrolling coordinator to ensures that it
// updates non-fast scroll rects even if there is no layout.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view.h b/chromium/third_party/blink/renderer/core/layout/layout_view.h
index 63534044824..ac72bdffb8f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.h
@@ -252,7 +252,7 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
// (which is responsible for painting the tickmarks).
void InvalidatePaintForTickmarks();
- bool RecalcOverflow() override;
+ bool RecalcLayoutOverflow() final;
// The visible background area, in the local coordinates. The view background
// will be painted in this rect. It's also the positioning area of fixed-
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
index 6cda24cf7ad..5cbca2548af 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
@@ -4,11 +4,15 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
-class LayoutViewTest : public RenderingTest {};
+class LayoutViewTest : public RenderingTest {
+ public:
+ LayoutViewTest() : RenderingTest(SingleChildLocalFrameClient::Create()) {}
+};
TEST_F(LayoutViewTest, UpdateCountersLayout) {
SetBodyInnerHTML(R"HTML(
@@ -33,4 +37,30 @@ TEST_F(LayoutViewTest, UpdateCountersLayout) {
EXPECT_TRUE(GetDocument().View()->NeedsLayout());
}
+TEST_F(LayoutViewTest, DisplayNoneFrame) {
+ SetBodyInnerHTML(R"HTML(
+ <iframe id="iframe" style="display:none"></iframe>
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+
+ HTMLIFrameElement* iframe =
+ ToHTMLIFrameElement(GetDocument().getElementById("iframe"));
+ Document* frame_doc = iframe->contentDocument();
+ ASSERT_TRUE(frame_doc);
+ LayoutObject* view = frame_doc->GetLayoutView();
+ ASSERT_TRUE(view);
+ EXPECT_FALSE(view->CanHaveChildren());
+
+ frame_doc->body()->SetInnerHTMLFromString(R"HTML(
+ <div id="div"></div>
+ )HTML");
+
+ frame_doc->Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
+ frame_doc->GetStyleEngine().RecalcStyle(kNoChange);
+
+ Element* div = frame_doc->getElementById("div");
+ EXPECT_FALSE(div->GetNonAttachedStyle());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
index be12bbc0dae..e0a65b1a502 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -87,9 +87,6 @@ class BreakingContext {
floats_fit_on_line_(true),
collapse_white_space_(false),
starting_new_paragraph_(line_info_.PreviousLineBrokeCleanly()),
- allow_images_to_break_(
- !block.GetDocument().InQuirksMode() || !block.IsTableCell() ||
- !block_style_->LogicalWidth().IsIntrinsicOrAuto()),
at_end_(false),
line_midpoint_state_(resolver.GetMidpointState()) {
line_info_.SetPreviousLineBrokeCleanly(false);
@@ -128,6 +125,7 @@ class BreakingContext {
const Font&,
bool apply_word_spacing,
float word_spacing);
+ void TrailingSpacesHang(bool can_break_mid_word);
bool TrailingSpaceExceedsAvailableWidth(bool can_break_mid_word,
const LineLayoutText&,
WordMeasurement&,
@@ -208,6 +206,7 @@ class BreakingContext {
bool at_start_;
bool ignoring_spaces_;
bool current_character_is_space_;
+ bool previous_character_is_space_;
bool single_leading_space_;
unsigned current_start_offset_; // initial offset for the current text
bool applied_start_width_;
@@ -217,7 +216,6 @@ class BreakingContext {
bool floats_fit_on_line_;
bool collapse_white_space_;
bool starting_new_paragraph_;
- bool allow_images_to_break_;
bool at_end_;
LineMidpointState& line_midpoint_state_;
@@ -643,7 +641,6 @@ inline void BreakingContext::HandleReplaced() {
// Break on replaced elements if either has normal white-space,
// or if the replaced element is ruby that can break before.
if ((auto_wrap_ || ComputedStyle::AutoWrap(last_ws_)) &&
- (!current_.GetLineLayoutItem().IsImage() || allow_images_to_break_) &&
(!current_.GetLineLayoutItem().IsRubyRun() ||
LineLayoutRubyRun(current_.GetLineLayoutItem())
.CanBreakBefore(layout_text_info_.line_break_iterator_))) {
@@ -1049,7 +1046,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
layout_text_info_.line_break_iterator_.SecondToLastCharacter();
for (; current_.Offset() < layout_text.TextLength();
current_.FastIncrementInTextNode()) {
- bool previous_character_is_space = current_character_is_space_;
+ previous_character_is_space_ = current_character_is_space_;
UChar c = current_.Current();
SetCurrentCharacterIsSpace(c);
@@ -1111,7 +1108,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
}
PrepareForNextCharacter(layout_text, prohibit_break_inside,
- previous_character_is_space);
+ previous_character_is_space_);
at_start_ = false;
NextCharacter(c, last_character, second_to_last_character);
continue;
@@ -1151,7 +1148,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
// We keep track of the total width contributed by trailing space as we
// often want to exclude it when determining
// if a run fits on a line.
- if (collapse_white_space_ && previous_character_is_space &&
+ if (collapse_white_space_ && previous_character_is_space_ &&
current_character_is_space_ && last_width_measurement)
width_.SetTrailingWhitespaceWidth(last_width_measurement);
@@ -1215,7 +1212,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
if (CanBreakAtWhitespace(
break_words, word_measurement, stopped_ignoring_spaces, char_width,
hyphenated, disable_soft_hyphen, hyphen_width, between_words,
- mid_word_break, can_break_mid_word, previous_character_is_space,
+ mid_word_break, can_break_mid_word, previous_character_is_space_,
last_width_measurement, layout_text, font, apply_word_spacing,
word_spacing))
return false;
@@ -1255,7 +1252,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
// go ahead and break up this run and enter a mode where we start collapsing
// spaces.
if (!ignoring_spaces_ && current_style_->CollapseWhiteSpace()) {
- if (current_character_is_space_ && previous_character_is_space) {
+ if (current_character_is_space_ && previous_character_is_space_) {
ignoring_spaces_ = true;
// We just entered a mode where we are ignoring spaces. Create a
@@ -1268,7 +1265,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
}
PrepareForNextCharacter(layout_text, prohibit_break_inside,
- previous_character_is_space);
+ previous_character_is_space_);
at_start_ = false;
is_line_empty = line_info_.IsEmpty();
NextCharacter(c, last_character, second_to_last_character);
@@ -1422,6 +1419,22 @@ inline WordMeasurement& BreakingContext::CalculateWordWidth(
return word_measurement;
}
+inline void BreakingContext::TrailingSpacesHang(bool can_break_mid_word) {
+ DCHECK(curr_ws_ == EWhiteSpace::kBreakSpaces);
+ // Avoid breaking before the first white-space after a word if there is a
+ // breaking opportunity before.
+ if (single_leading_space_ && !previous_character_is_space_)
+ return;
+
+ line_break_.MoveTo(current_.GetLineLayoutItem(), current_.Offset(),
+ current_.NextBreakablePosition());
+
+ // Avoid breaking before the first white-space after a word, unless
+ // overflow-wrap or word-break allow to.
+ if (!previous_character_is_space_ && !can_break_mid_word)
+ line_break_.Increment();
+}
+
inline bool BreakingContext::TrailingSpaceExceedsAvailableWidth(
bool can_break_mid_word,
const LineLayoutText& layout_text,
@@ -1444,8 +1457,13 @@ inline bool BreakingContext::TrailingSpaceExceedsAvailableWidth(
// then move the line break to the space and skip all
// additional whitespace.
if (!width_.FitsOnLine(char_width)) {
+ if (curr_ws_ == EWhiteSpace::kBreakSpaces) {
+ TrailingSpacesHang(can_break_mid_word);
+ return true;
+ }
line_break_.MoveTo(current_.GetLineLayoutItem(), current_.Offset(),
current_.NextBreakablePosition());
+
SkipTrailingWhitespace(line_break_, line_info_);
return true;
}
@@ -1602,7 +1620,6 @@ inline void BreakingContext::CommitAndUpdateLineBreakIfNeeded() {
if (!current_.GetLineLayoutItem().IsFloatingOrOutOfFlowPositioned()) {
last_object_ = current_.GetLineLayoutItem();
if (last_object_.IsAtomicInlineLevel() && auto_wrap_ &&
- (!last_object_.IsImage() || allow_images_to_break_) &&
(!last_object_.IsListMarker() ||
LineLayoutListMarker(last_object_).IsInside()) &&
!last_object_.IsRubyRun()) {
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_box.h b/chromium/third_party/blink/renderer/core/layout/line/inline_box.h
index 853def8ebd1..9c2f7868ec5 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_box.h
@@ -362,6 +362,9 @@ class CORE_EXPORT InlineBox : public DisplayItemClient {
void FlipForWritingMode(LayoutRect&) const;
LayoutPoint FlipForWritingMode(const LayoutPoint&) const;
+ // Returns trus if it is known that this box has no layout or visual
+ // overflow. This is used as a fast-path to skip expensive overflow
+ // recalc.
bool KnownToHaveNoOverflow() const {
return bitfields_.KnownToHaveNoOverflow();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc b/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
index 6de638ad9a3..16a18e75153 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
@@ -168,7 +168,7 @@ void InlineFlowBox::AddToLine(InlineBox* child) {
should_clear_descendants_have_same_line_height_and_baseline = true;
} else {
if (child->GetLineLayoutItem().IsBR()) {
- // FIXME: This is dumb. We only turn off because current layout test
+ // FIXME: This is dumb. We only turn off because current web test
// results expect the <br> to be 0-height on the baseline.
// Other than making a zillion tests have to regenerate results, there's
// no reason to ditch the optimization here.
@@ -202,7 +202,8 @@ void InlineFlowBox::AddToLine(InlineBox* child) {
child->ClearKnownToHaveNoOverflow();
} else if (child->GetLineLayoutItem().IsAtomicInlineLevel()) {
LineLayoutBox box = LineLayoutBox(child->GetLineLayoutItem());
- if (box.HasOverflowModel() || box.HasSelfPaintingLayer())
+ if (box.HasLayoutOverflow() || box.HasVisualOverflow() ||
+ box.HasSelfPaintingLayer())
child->ClearKnownToHaveNoOverflow();
} else if (!child->GetLineLayoutItem().IsBR() &&
(child->GetLineLayoutItem()
@@ -299,11 +300,12 @@ void InlineFlowBox::Move(const LayoutSize& delta) {
continue;
child->Move(delta);
}
- if (overflow_) {
- // FIXME: Rounding error here since overflow was pixel snapped, but nobody
- // other than list markers passes non-integral values here.
- overflow_->Move(delta.Width(), delta.Height());
- }
+ // FIXME: Rounding error here since overflow was pixel snapped, but nobody
+ // other than list markers passes non-integral values here.
+ if (LayoutOverflowIsSet())
+ overflow_->layout_overflow->Move(delta.Width(), delta.Height());
+ if (VisualOverflowIsSet())
+ overflow_->visual_overflow->Move(delta.Width(), delta.Height());
}
LineBoxList* InlineFlowBox::LineBoxes() const {
@@ -918,15 +920,18 @@ void InlineFlowBox::PlaceBoxesInBlockDirection(
}
}
-void InlineFlowBox::OverrideVisualOverflowFromLogicalRect(
+bool InlineFlowBox::OverrideVisualOverflowFromLogicalRect(
const LayoutRect& logical_visual_overflow,
LayoutUnit line_top,
LayoutUnit line_bottom) {
// If we are setting an overflow, then we can't pretend not to have an
// overflow.
ClearKnownToHaveNoOverflow();
+ LayoutRect old_visual_overflow_rect =
+ VisualOverflowRect(line_top, line_bottom);
SetVisualOverflowFromLogicalRect(logical_visual_overflow, line_top,
line_bottom);
+ return VisualOverflowRect(line_top, line_bottom) != old_visual_overflow_rect;
}
void InlineFlowBox::OverrideLayoutOverflowFromLogicalRect(
@@ -1121,24 +1126,11 @@ inline void InlineFlowBox::AddTextBoxVisualOverflow(
text_box->SetLogicalOverflowRect(logical_visual_overflow);
}
-inline void InlineFlowBox::AddReplacedChildOverflow(
+inline void InlineFlowBox::AddReplacedChildLayoutOverflow(
const InlineBox* inline_box,
- LayoutRect& logical_layout_overflow,
- LayoutRect& logical_visual_overflow) {
+ LayoutRect& logical_layout_overflow) {
LineLayoutBox box = LineLayoutBox(inline_box->GetLineLayoutItem());
- // Visual overflow only propagates if the box doesn't have a self-painting
- // layer. This rectangle does not include transforms or relative positioning
- // (since those objects always have self-painting layers), but it does need to
- // be adjusted for writing-mode differences.
- if (!box.HasSelfPaintingLayer()) {
- LayoutRect child_logical_visual_overflow =
- box.LogicalVisualOverflowRectForPropagation();
- child_logical_visual_overflow.Move(inline_box->LogicalLeft(),
- inline_box->LogicalTop());
- logical_visual_overflow.Unite(child_logical_visual_overflow);
- }
-
// Layout overflow internal to the child box only propagates if the child box
// doesn't have overflow clip set. Otherwise the child border box propagates
// as layout overflow. This rectangle must include transforms and relative
@@ -1150,6 +1142,38 @@ inline void InlineFlowBox::AddReplacedChildOverflow(
logical_layout_overflow.Unite(child_logical_layout_overflow);
}
+void InlineFlowBox::AddReplacedChildrenVisualOverflow(LayoutUnit line_top,
+ LayoutUnit line_bottom) {
+ LayoutRect logical_visual_overflow =
+ VisualOverflowRect(line_top, line_bottom);
+ bool visual_overflow_may_have_changed = false;
+ for (InlineBox* curr = FirstChild(); curr; curr = curr->NextOnLine()) {
+ const LineLayoutItem& item = curr->GetLineLayoutItem();
+ if (item.IsOutOfFlowPositioned() || item.IsText() || item.IsLayoutInline())
+ continue;
+
+ LineLayoutBox box = LineLayoutBox(curr->GetLineLayoutItem());
+
+ // Visual overflow only propagates if the box doesn't have a self-painting
+ // layer. This rectangle does not include transforms or relative positioning
+ // (since those objects always have self-painting layers), but it does need
+ // to be adjusted for writing-mode differences.
+ if (!box.HasSelfPaintingLayer()) {
+ LayoutRect child_logical_visual_overflow =
+ box.LogicalVisualOverflowRectForPropagation();
+ child_logical_visual_overflow.Move(curr->LogicalLeft(),
+ curr->LogicalTop());
+ logical_visual_overflow.Unite(child_logical_visual_overflow);
+ ClearKnownToHaveNoOverflow();
+ visual_overflow_may_have_changed = true;
+ }
+ }
+ if (visual_overflow_may_have_changed) {
+ SetVisualOverflowFromLogicalRect(logical_visual_overflow, line_top,
+ line_bottom);
+ }
+}
+
static void ComputeGlyphOverflow(
InlineTextBox* text,
const LineLayoutText& layout_text,
@@ -1187,12 +1211,11 @@ void InlineFlowBox::ComputeOverflow(
GlyphOverflowAndFallbackFontsMap& text_box_data_map) {
// If we know we have no overflow, we can just bail.
if (KnownToHaveNoOverflow()) {
- DCHECK(!overflow_);
+ DCHECK(!LayoutOverflowIsSet() && !VisualOverflowIsSet());
return;
}
- if (overflow_)
- overflow_.reset();
+ overflow_.reset();
// Visual overflow just includes overflow for stuff we need to issues paint
// invalidations for ourselves. Self-painting layers are ignored.
@@ -1250,8 +1273,7 @@ void InlineFlowBox::ComputeOverflow(
logical_layout_overflow =
LogicalFrameRectIncludingLineHeight(line_top, line_bottom);
}
- AddReplacedChildOverflow(curr, logical_layout_overflow,
- logical_visual_overflow);
+ AddReplacedChildLayoutOverflow(curr, logical_layout_overflow);
}
}
@@ -1267,10 +1289,13 @@ void InlineFlowBox::SetLayoutOverflow(const LayoutRect& rect,
if (frame_box.Contains(rect) || rect.IsEmpty())
return;
- if (!overflow_)
- overflow_ = std::make_unique<SimpleOverflowModel>(frame_box, frame_box);
+ if (!LayoutOverflowIsSet()) {
+ if (!overflow_)
+ overflow_ = std::make_unique<SimpleOverflowModel>();
+ overflow_->layout_overflow.emplace(frame_box);
+ }
- overflow_->SetLayoutOverflow(rect);
+ overflow_->layout_overflow->SetLayoutOverflow(rect);
}
void InlineFlowBox::SetVisualOverflow(const LayoutRect& rect,
@@ -1279,10 +1304,13 @@ void InlineFlowBox::SetVisualOverflow(const LayoutRect& rect,
if (frame_box.Contains(rect) || rect.IsEmpty())
return;
- if (!overflow_)
- overflow_ = std::make_unique<SimpleOverflowModel>(frame_box, frame_box);
+ if (!VisualOverflowIsSet()) {
+ if (!overflow_)
+ overflow_ = std::make_unique<SimpleOverflowModel>();
+ overflow_->visual_overflow.emplace(frame_box);
+ }
- overflow_->SetVisualOverflow(rect);
+ overflow_->visual_overflow->SetVisualOverflow(rect);
}
void InlineFlowBox::SetVisualOverflowFromLogicalRect(
@@ -1479,11 +1507,6 @@ LayoutUnit InlineFlowBox::PlaceEllipsisBox(bool ltr,
// If our flow is ltr then iterate over the boxes from left to right,
// otherwise iterate from right to left. Varying the order allows us to
// correctly hide the boxes following the ellipsis.
- LayoutUnit relative_offset =
- BoxModelObject().IsInline() && BoxModelObject().IsRelPositioned()
- ? BoxModelObject().RelativePositionLogicalOffset().Width()
- : LayoutUnit();
- logical_left_offset += relative_offset;
InlineBox* box = ltr ? FirstChild() : LastChild();
// NOTE: these will cross after foundBox = true.
@@ -1513,7 +1536,7 @@ LayoutUnit InlineFlowBox::PlaceEllipsisBox(bool ltr,
box = box->PrevOnLine();
}
}
- return result + relative_offset;
+ return result;
}
void InlineFlowBox::ClearTruncation() {
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.h b/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.h
index 6c14c1f5e50..996be79df52 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.h
@@ -246,9 +246,16 @@ class InlineFlowBox : public InlineBox {
LayoutUnit ComputeUnderAnnotationAdjustment(
LayoutUnit allowed_position) const;
+ // Computes all layout overflow, plus visual overflow not due to replaced
+ // children. Visual overflow due to replaced children is computed during
+ // the RecalcVisualOverflow tree walk. Other visual overflow is computed
+ // during layout for performance reasons.
void ComputeOverflow(LayoutUnit line_top,
LayoutUnit line_bottom,
GlyphOverflowAndFallbackFontsMap&);
+ // Adds visual flow to the current visual overflow for replaced children.
+ void AddReplacedChildrenVisualOverflow(LayoutUnit line_top,
+ LayoutUnit line_bottom);
void RemoveChild(InlineBox* child, MarkLineBoxes);
@@ -279,19 +286,24 @@ class InlineFlowBox : public InlineBox {
// the right in vertical-rl.
LayoutRect LayoutOverflowRect(LayoutUnit line_top,
LayoutUnit line_bottom) const {
- return overflow_ ? overflow_->LayoutOverflowRect()
- : FrameRectIncludingLineHeight(line_top, line_bottom);
+ return LayoutOverflowIsSet()
+ ? overflow_->layout_overflow->LayoutOverflowRect()
+ : FrameRectIncludingLineHeight(line_top, line_bottom);
}
LayoutUnit LogicalTopLayoutOverflow(LayoutUnit line_top) const {
- if (overflow_)
- return IsHorizontal() ? overflow_->LayoutOverflowRect().Y()
- : overflow_->LayoutOverflowRect().X();
+ if (LayoutOverflowIsSet()) {
+ return IsHorizontal()
+ ? overflow_->layout_overflow->LayoutOverflowRect().Y()
+ : overflow_->layout_overflow->LayoutOverflowRect().X();
+ }
return line_top;
}
LayoutUnit LogicalBottomLayoutOverflow(LayoutUnit line_bottom) const {
- if (overflow_)
- return IsHorizontal() ? overflow_->LayoutOverflowRect().MaxY()
- : overflow_->LayoutOverflowRect().MaxX();
+ if (LayoutOverflowIsSet()) {
+ return IsHorizontal()
+ ? overflow_->layout_overflow->LayoutOverflowRect().MaxY()
+ : overflow_->layout_overflow->LayoutOverflowRect().MaxX();
+ }
return line_bottom;
}
LayoutRect LogicalLayoutOverflowRect(LayoutUnit line_top,
@@ -301,46 +313,41 @@ class InlineFlowBox : public InlineBox {
result = result.TransposedRect();
return result;
}
- LayoutUnit LogicalRightLayoutOverflow() const {
- if (overflow_) {
- return IsHorizontal() ? overflow_->LayoutOverflowRect().MaxX()
- : overflow_->LayoutOverflowRect().MaxY();
- }
- return LogicalRight();
- }
- LayoutUnit LogicalLeftLayoutOverflow() const {
- if (overflow_) {
- return IsHorizontal() ? overflow_->LayoutOverflowRect().X()
- : overflow_->LayoutOverflowRect().Y();
- }
- return LogicalLeft();
- }
LayoutRect VisualOverflowRect(LayoutUnit line_top,
LayoutUnit line_bottom) const {
- return overflow_ ? overflow_->VisualOverflowRect()
- : FrameRectIncludingLineHeight(line_top, line_bottom);
+ return VisualOverflowIsSet()
+ ? overflow_->visual_overflow->VisualOverflowRect()
+ : FrameRectIncludingLineHeight(line_top, line_bottom);
}
LayoutUnit LogicalLeftVisualOverflow() const {
- return overflow_ ? (IsHorizontal() ? overflow_->VisualOverflowRect().X()
- : overflow_->VisualOverflowRect().Y())
- : LogicalLeft();
+ return VisualOverflowIsSet()
+ ? (IsHorizontal()
+ ? overflow_->visual_overflow->VisualOverflowRect().X()
+ : overflow_->visual_overflow->VisualOverflowRect().Y())
+ : LogicalLeft();
}
LayoutUnit LogicalRightVisualOverflow() const {
- return overflow_ ? (IsHorizontal() ? overflow_->VisualOverflowRect().MaxX()
- : overflow_->VisualOverflowRect().MaxY())
- : static_cast<LayoutUnit>(LogicalRight().Ceil());
+ return VisualOverflowIsSet()
+ ? (IsHorizontal()
+ ? overflow_->visual_overflow->VisualOverflowRect().MaxX()
+ : overflow_->visual_overflow->VisualOverflowRect().MaxY())
+ : static_cast<LayoutUnit>(LogicalRight().Ceil());
}
LayoutUnit LogicalTopVisualOverflow(LayoutUnit line_top) const {
- if (overflow_)
- return IsHorizontal() ? overflow_->VisualOverflowRect().Y()
- : overflow_->VisualOverflowRect().X();
+ if (VisualOverflowIsSet()) {
+ return IsHorizontal()
+ ? overflow_->visual_overflow->VisualOverflowRect().Y()
+ : overflow_->visual_overflow->VisualOverflowRect().X();
+ }
return line_top;
}
LayoutUnit LogicalBottomVisualOverflow(LayoutUnit line_bottom) const {
- if (overflow_)
- return IsHorizontal() ? overflow_->VisualOverflowRect().MaxY()
- : overflow_->VisualOverflowRect().MaxX();
+ if (VisualOverflowIsSet()) {
+ return IsHorizontal()
+ ? overflow_->visual_overflow->VisualOverflowRect().MaxY()
+ : overflow_->visual_overflow->VisualOverflowRect().MaxX();
+ }
return line_bottom;
}
LayoutRect LogicalVisualOverflowRect(LayoutUnit line_top,
@@ -378,7 +385,7 @@ class InlineFlowBox : public InlineBox {
is_first_after_page_break_ = is_first_after_page_break;
}
- void OverrideVisualOverflowFromLogicalRect(
+ bool OverrideVisualOverflowFromLogicalRect(
const LayoutRect& logical_visual_overflow,
LayoutUnit line_top,
LayoutUnit line_bottom);
@@ -394,6 +401,12 @@ class InlineFlowBox : public InlineBox {
LayoutUnit current) const;
private:
+ inline bool LayoutOverflowIsSet() const {
+ return overflow_ && overflow_->layout_overflow;
+ }
+ inline bool VisualOverflowIsSet() const {
+ return overflow_ && overflow_->visual_overflow;
+ }
void PlaceBoxRangeInInlineDirection(InlineBox* first_child,
InlineBox* last_child,
LayoutUnit& logical_left,
@@ -419,9 +432,8 @@ class InlineFlowBox : public InlineBox {
void AddTextBoxVisualOverflow(InlineTextBox*,
GlyphOverflowAndFallbackFontsMap&,
LayoutRect& logical_visual_overflow);
- void AddReplacedChildOverflow(const InlineBox*,
- LayoutRect& logical_layout_overflow,
- LayoutRect& logical_visual_overflow);
+ void AddReplacedChildLayoutOverflow(const InlineBox*,
+ LayoutRect& logical_layout_overflow);
bool HasEmphasisMarkBefore(const InlineTextBox*) const;
bool HasEmphasisMarkOver(const InlineTextBox*) const;
bool HasEmphasisMarkUnder(const InlineTextBox*) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
index 70fbce40992..a5e8c94c78d 100644
--- a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
+++ b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
@@ -10,6 +10,15 @@
namespace blink {
+// Limit the maximum column count, to prevent potential performance problems.
+static const unsigned kColumnCountClampMax = 10000;
+
+// Clamp "infinite" clips to a number of pixels that can be losslessly
+// converted to and from floating point, to avoid loss of precision.
+// Note that tables have something similar, see
+// TableLayoutAlgorithm::kTableMaxWidth.
+static const int kMulticolMaxClipPixels = 1000000;
+
MultiColumnFragmentainerGroup::MultiColumnFragmentainerGroup(
const LayoutMultiColumnSet& column_set)
: column_set_(column_set) {}
@@ -62,7 +71,6 @@ LayoutUnit MultiColumnFragmentainerGroup::LogicalHeightInFlowThreadAt(
}
void MultiColumnFragmentainerGroup::ResetColumnHeight() {
- actual_column_count_allowance_ = 0;
max_logical_height_ = CalculateMaxColumnHeight();
LayoutMultiColumnFlowThread* flow_thread =
@@ -138,24 +146,6 @@ bool MultiColumnFragmentainerGroup::RecalculateColumnHeight(
// height.
is_logical_height_known_ = true;
- unsigned column_count = UnclampedActualColumnCount();
- if (column_count > LayoutMultiColumnFlowThread::ColumnCountClampMax() ||
- (column_count > LayoutMultiColumnFlowThread::ColumnCountClampMin() &&
- column_count > column_set_.UsedColumnCount())) {
- // That's a lot of columns! We have either exceeded the maximum value, or we
- // have overflowing columns, and the proposed count is within clamping
- // range. Calculate allowance to make sure we have a legitimate reason for
- // it, or else clamp it. We have quadratic performance complexity for
- // painting columns.
- if (!actual_column_count_allowance_) {
- const auto* flow_thread = column_set_.MultiColumnFlowThread();
- unsigned allowance = flow_thread->CalculateActualColumnCountAllowance();
- DCHECK_GE(allowance, LayoutMultiColumnFlowThread::ColumnCountClampMin());
- DCHECK_LE(allowance, LayoutMultiColumnFlowThread::ColumnCountClampMax());
- actual_column_count_allowance_ = allowance;
- }
- }
-
if (logical_height_ == old_column_height)
return false; // No change. We're done.
@@ -329,8 +319,7 @@ LayoutRect MultiColumnFragmentainerGroup::CalculateOverflow() const {
unsigned MultiColumnFragmentainerGroup::ActualColumnCount() const {
unsigned count = UnclampedActualColumnCount();
- if (actual_column_count_allowance_)
- count = std::min(count, actual_column_count_allowance_);
+ count = std::min(count, kColumnCountClampMax);
DCHECK_GE(count, 1u);
return count;
}
@@ -453,12 +442,6 @@ LayoutRect MultiColumnFragmentainerGroup::FlowThreadPortionRectAt(
column_set_.PageLogicalWidth());
}
-// Clamp "infinite" clips to a number of pixels that can be losslessly
-// converted to and from floating point, to avoid loss of precision.
-// Note that tables have something similar, see
-// TableLayoutAlgorithm::kTableMaxWidth.
-static const int kMulticolMaxClipPixels = 1000000;
-
LayoutRect MultiColumnFragmentainerGroup::FlowThreadPortionOverflowRectAt(
unsigned column_index) const {
// This function determines the portion of the flow thread that paints for the
diff --git a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h
index 72527915c9c..f5f0483c406 100644
--- a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h
+++ b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h
@@ -194,8 +194,6 @@ class CORE_EXPORT MultiColumnFragmentainerGroup {
// Maximum logical height allowed.
LayoutUnit max_logical_height_;
- unsigned actual_column_count_allowance_ = 0;
-
bool is_logical_height_known_ = false;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc
index 1d9420faff2..f86cb314e26 100644
--- a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc
@@ -97,32 +97,6 @@ TEST_F(MultiColumnFragmentainerGroupTest,
EXPECT_EQ(GroupCount(group_list), 1);
}
-// The following test tests that we restrict actual column count, to not run
-// into unnecessary performance problems. The code that applies this limitation
-// is in MultiColumnFragmentainerGroup::ActualColumnCount().
-TEST_F(MultiColumnFragmentainerGroupTest, TallEmptyContent) {
- SetBodyInnerHTML(R"HTML(
- <div id="multicol" style="columns:3; column-gap:1px; width:101px; line-height:50px; height:200px;">
- <div style="height:1000000px;"></div>
- </div>
- )HTML");
- const auto* multicol = GetLayoutObjectByElementId("multicol");
- ASSERT_TRUE(multicol);
- ASSERT_TRUE(multicol->IsLayoutBlockFlow());
- const auto* column_set = multicol->SlowLastChild();
- ASSERT_TRUE(column_set);
- ASSERT_TRUE(column_set->IsLayoutMultiColumnSet());
- const auto& fragmentainer_group =
- ToLayoutMultiColumnSet(column_set)->FirstFragmentainerGroup();
- EXPECT_EQ(fragmentainer_group.ActualColumnCount(), 10U);
- EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(200));
- auto overflow = ToLayoutBox(multicol)->LayoutOverflowRect();
- EXPECT_EQ(ToLayoutBox(multicol)->LogicalWidth(), LayoutUnit(101));
- EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(200));
- EXPECT_EQ(overflow.Width(), LayoutUnit(339));
- EXPECT_EQ(overflow.Height(), LayoutUnit(998200));
-}
-
// The following test tests that we DON'T restrict actual column count, when
// there's a legitimate reason to use many columns. The code that checks the
// allowance and potentially applies this limitation is in
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
index 4a128618a2a..94d59f3b92c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -57,7 +57,7 @@ struct CORE_EXPORT NGBoxStrut {
return *this;
}
- NGBoxStrut operator+(const NGBoxStrut& other) {
+ NGBoxStrut operator+(const NGBoxStrut& other) const {
NGBoxStrut result(*this);
result += other;
return result;
@@ -71,7 +71,7 @@ struct CORE_EXPORT NGBoxStrut {
return *this;
}
- NGBoxStrut operator-(const NGBoxStrut& other) {
+ NGBoxStrut operator-(const NGBoxStrut& other) const {
NGBoxStrut result(*this);
result -= other;
return result;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.cc b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.cc
index c5ec5085e44..8fead03022a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.cc
@@ -77,6 +77,11 @@ NGLogicalOffset& NGLogicalOffset::operator+=(const NGLogicalOffset& other) {
return *this;
}
+NGLogicalOffset& NGLogicalOffset::operator+=(const NGLogicalSize& size) {
+ *this = *this + size;
+ return *this;
+}
+
bool NGLogicalOffset::operator>(const NGLogicalOffset& other) const {
return inline_offset > other.inline_offset &&
block_offset > other.block_offset;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h
index 00d51ca8204..1f3b38af731 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h
@@ -45,6 +45,7 @@ struct CORE_EXPORT NGLogicalOffset {
NGLogicalOffset operator+(const NGLogicalOffset& other) const;
NGLogicalOffset operator+(const NGLogicalSize& size) const;
NGLogicalOffset& operator+=(const NGLogicalOffset& other);
+ NGLogicalOffset& operator+=(const NGLogicalSize& size);
NGLogicalDelta operator-(const NGLogicalOffset& other) const;
NGLogicalOffset& operator-=(const NGLogicalOffset& other);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md b/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md
index 715f1d0e84e..c604426d29e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md
@@ -75,6 +75,7 @@ because the spec prioritizes the simple description than being accurate.
[CSS Text Processing Order of Operations]: https://drafts.csswg.org/css-text-3/#order
### Pre-layout ###
+[Pre-layout]: #pre-layout
For inline layout there is a pre-layout pass that prepares the internal data
structures needed to perform line layout.
@@ -302,6 +303,16 @@ In a bird's‐eye view, it consists of two parts:
This is part of the Line Box Construction phase above.
+### Interface for Editing ###
+
+[NGOffsetMapping] provides functions for converting between offsets in the text
+content of an inline formatting context (computed in [pre-layout]) and DOM
+positions in the context. See [design doc](https://goo.gl/CJbxky) for details.
+
+[NGCaretNavigator] provides functions for inspecting bidi levels and visual
+ordering of text content, and supports visual left/right caret movements in the
+text. See [design doc](http://bit.ly/2QVAwGq) for details.
+
[ICU BiDi]: http://userguide.icu-project.org/transforms/bidi
[UAX#9 Unicode Bidirectional Algorithm]: http://unicode.org/reports/tr9/
@@ -311,6 +322,7 @@ In a bird's‐eye view, it consists of two parts:
[FontBaseline]: ../../../platform/fonts/FontBaseline.h
[NGBaselineAlgorithmType]: ng_baseline.h
[NGBaselineRequest]: ng_baseline.h
+[NGCaretNavigator]: ng_caret_navigator.h
[NGBidiParagraph]: ng_bidi_paragraph.h
[NGBlockNode]: ../ng_block_node.h
[NGBoxFragment]: ../ng_box_fragment.h
@@ -324,6 +336,7 @@ In a bird's‐eye view, it consists of two parts:
[NGInlineLayoutAlgorithm]: ng_inline_layout_algorithm.h
[NGLayoutInputNode]: ../ng_layout_input_node.h
[NGLineBreaker]: ng_line_breaker.h
+[NGOffsetMapping]: ng_offset_mapping.h
[NGPhysicalBoxFragment]: ../ng_physical_box_fragment.h
[NGPhysicalFragment]: ../ng_physical_fragment.h
[NGPhysicalLineBoxFragment]: ng_physical_line_box_fragment.h
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.cc
new file mode 100644
index 00000000000..6ac584f28e4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.cc
@@ -0,0 +1,203 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_bidi_paragraph.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+
+namespace blink {
+
+NGCaretNavigator::~NGCaretNavigator() = default;
+
+NGCaretNavigator::NGCaretNavigator(NGCaretNavigator&& other)
+ : text_(other.text_),
+ bidi_levels_(std::move(other.bidi_levels_)),
+ indices_in_visual_order_(std::move(other.indices_in_visual_order_)),
+ visual_indices_(std::move(other.visual_indices_)),
+ is_bidi_enabled_(other.is_bidi_enabled_),
+ base_direction_(other.base_direction_) {}
+
+NGCaretNavigator::NGCaretNavigator(const NGInlineNodeData& data)
+ : text_(data.text_content),
+ is_bidi_enabled_(data.IsBidiEnabled()),
+ base_direction_(data.BaseDirection()) {
+ if (!is_bidi_enabled_)
+ return;
+
+ bidi_levels_.resize(text_.length());
+ for (const NGInlineItem& item : data.items) {
+ if (!item.Length())
+ continue;
+ for (unsigned i = item.StartOffset(); i < item.EndOffset(); ++i) {
+ DCHECK_LT(i, bidi_levels_.size());
+ bidi_levels_[i] = item.BidiLevel();
+ }
+ }
+
+ indices_in_visual_order_.resize(text_.length());
+ NGBidiParagraph::IndicesInVisualOrder(bidi_levels_,
+ &indices_in_visual_order_);
+
+ visual_indices_.resize(text_.length());
+ for (unsigned i = 0; i < indices_in_visual_order_.size(); ++i)
+ visual_indices_[indices_in_visual_order_[i]] = i;
+}
+
+UBiDiLevel NGCaretNavigator::BidiLevelAt(unsigned index) const {
+ DCHECK_LT(index, text_.length());
+ if (!is_bidi_enabled_)
+ return 0;
+ DCHECK_LT(index, bidi_levels_.size());
+ return bidi_levels_[index];
+}
+
+TextDirection NGCaretNavigator::TextDirectionAt(unsigned index) const {
+ UBiDiLevel level = BidiLevelAt(index);
+ return DirectionFromLevel(level);
+}
+
+bool NGCaretNavigator::OffsetIsBidiBoundary(unsigned offset) const {
+ DCHECK_LE(offset, text_.length());
+ if (!is_bidi_enabled_)
+ return false;
+ if (!offset || offset == text_.length())
+ return false;
+ return BidiLevelAt(offset - 1) != BidiLevelAt(offset);
+}
+
+NGCaretNavigator::Position
+NGCaretNavigator::CaretPositionFromTextContentOffsetAndAffinity(
+ unsigned offset,
+ TextAffinity affinity) const {
+ // Callers sometimes pass in (0, upstream) or (length, downstream), which
+ // originate from legacy callers. Make sure they are fixed up.
+ // TODO(xiaochengh): Catch and eliminate such callers.
+ if (affinity == TextAffinity::kUpstream) {
+ if (offset)
+ return {offset - 1, PositionAnchorType::kAfter};
+ return {0, PositionAnchorType::kBefore};
+ }
+
+ if (offset < text_.length())
+ return {offset, PositionAnchorType::kBefore};
+ return {text_.length() - 1, PositionAnchorType::kAfter};
+}
+
+// static
+NGCaretNavigator::MoveDirection NGCaretNavigator::OppositeDirectionOf(
+ MoveDirection direction) {
+ if (direction == MoveDirection::kTowardsLeft)
+ return MoveDirection::kTowardsRight;
+ return MoveDirection::kTowardsLeft;
+}
+
+// static
+bool NGCaretNavigator::TowardsSameDirection(MoveDirection move_direction,
+ TextDirection text_direction) {
+ if (IsLtr(text_direction))
+ return move_direction == MoveDirection::kTowardsRight;
+ return move_direction == MoveDirection::kTowardsLeft;
+}
+
+NGCaretNavigator::Position NGCaretNavigator::LeftEdgeOf(unsigned index) const {
+ return EdgeOfInternal(index, MoveDirection::kTowardsLeft);
+}
+
+NGCaretNavigator::Position NGCaretNavigator::RightEdgeOf(unsigned index) const {
+ return EdgeOfInternal(index, MoveDirection::kTowardsRight);
+}
+
+NGCaretNavigator::Position NGCaretNavigator::EdgeOfInternal(
+ unsigned index,
+ MoveDirection edge_direction) const {
+ DCHECK_LT(index, text_.length());
+ const TextDirection character_direction = TextDirectionAt(index);
+ return {index, TowardsSameDirection(edge_direction, character_direction)
+ ? PositionAnchorType::kAfter
+ : PositionAnchorType::kBefore};
+}
+
+NGCaretNavigator::VisualCharacterMovementResult
+NGCaretNavigator::LeftCharacterOf(unsigned index) const {
+ return MoveCharacterInternal(index, MoveDirection::kTowardsLeft);
+}
+
+NGCaretNavigator::VisualCharacterMovementResult
+NGCaretNavigator::RightCharacterOf(unsigned index) const {
+ return MoveCharacterInternal(index, MoveDirection::kTowardsRight);
+}
+
+// static
+base::Optional<unsigned> NGCaretNavigator::MoveVisualIndex(
+ unsigned visual_index,
+ unsigned length,
+ MoveDirection move_direction) {
+ if (move_direction == MoveDirection::kTowardsLeft) {
+ if (!visual_index)
+ return base::nullopt;
+ return visual_index - 1;
+ }
+
+ if (visual_index + 1 == length)
+ return base::nullopt;
+ return visual_index + 1;
+}
+
+NGCaretNavigator::VisualCharacterMovementResult
+NGCaretNavigator::MoveCharacterInternal(unsigned index,
+ MoveDirection move_direction) const {
+ DCHECK_LT(index, text_.length());
+ const unsigned visual_index =
+ is_bidi_enabled_ ? visual_indices_[index] : index;
+
+ const base::Optional<unsigned> maybe_result_visual_index =
+ MoveVisualIndex(visual_index, text_.length(), move_direction);
+ if (!maybe_result_visual_index.has_value()) {
+ if (TowardsSameDirection(move_direction, base_direction_))
+ return {VisualMovementResultType::kAfterContext, base::nullopt};
+ return {VisualMovementResultType::kBeforeContext, base::nullopt};
+ }
+
+ const unsigned result_visual_index = maybe_result_visual_index.value();
+ const unsigned result_index =
+ is_bidi_enabled_ ? indices_in_visual_order_[result_visual_index]
+ : result_visual_index;
+ return {VisualMovementResultType::kWithinContext, result_index};
+}
+
+NGCaretNavigator::VisualCaretMovementResult NGCaretNavigator::LeftPositionOf(
+ const Position& caret_position) const {
+ return MoveCaretInternal(caret_position, MoveDirection::kTowardsLeft);
+}
+
+NGCaretNavigator::VisualCaretMovementResult NGCaretNavigator::RightPositionOf(
+ const Position& caret_position) const {
+ return MoveCaretInternal(caret_position, MoveDirection::kTowardsRight);
+}
+
+NGCaretNavigator::VisualCaretMovementResult NGCaretNavigator::MoveCaretInternal(
+ const Position& caret_position,
+ MoveDirection move_direction) const {
+ const unsigned index = caret_position.index;
+ const MoveDirection opposite_direction = OppositeDirectionOf(move_direction);
+ if (caret_position == EdgeOfInternal(index, opposite_direction)) {
+ // TODO(xiaochengh): Consider grapheme cluster
+ return {VisualMovementResultType::kWithinContext,
+ EdgeOfInternal(index, move_direction)};
+ }
+
+ VisualCharacterMovementResult forward_character =
+ MoveCharacterInternal(index, move_direction);
+ if (forward_character.IsWithinContext()) {
+ DCHECK(forward_character.index.has_value());
+ const Position forward_caret =
+ EdgeOfInternal(forward_character.index.value(), opposite_direction);
+ return MoveCaretInternal(forward_caret, move_direction);
+ }
+
+ return {forward_character.type, base::nullopt};
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h
new file mode 100644
index 00000000000..4a2b0181711
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h
@@ -0,0 +1,151 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_NAVIGATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_NAVIGATOR_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/editing/text_affinity.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+#include <unicode/ubidi.h>
+
+namespace blink {
+
+struct NGInlineNodeData;
+
+// Hosts the |text_content| of an inline formatting context and provides
+// bidi-related utilities, including checking bidi levels, computing visual
+// left/right characters and visual left/right caret movements.
+// Design doc: http://bit.ly/2QVAwGq
+class CORE_EXPORT NGCaretNavigator {
+ public:
+ NGCaretNavigator(NGCaretNavigator&&);
+ explicit NGCaretNavigator(const NGInlineNodeData&);
+ ~NGCaretNavigator();
+
+ // Abstraction of a caret position in |text_|.
+ enum class PositionAnchorType { kBefore, kAfter };
+ struct Position {
+ // |index| is character index the |text_| string.
+ unsigned index;
+ PositionAnchorType type;
+
+ bool IsBeforeCharacter() const {
+ return type == PositionAnchorType::kBefore;
+ }
+
+ bool IsAfterCharacter() const { return type == PositionAnchorType::kAfter; }
+
+ bool operator==(const Position& other) const {
+ return index == other.index && type == other.type;
+ }
+ };
+
+ // Returns the bidi level or resolved direction of the character at the given
+ // logical |index|.
+ UBiDiLevel BidiLevelAt(unsigned index) const;
+ TextDirection TextDirectionAt(unsigned index) const;
+
+ // Returns true if the characters at indexes |offset - 1| and |offset| both
+ // exist and are at different bidi levels.
+ bool OffsetIsBidiBoundary(unsigned offset) const;
+
+ // Converts an (offset, affinity) pair into a |Position| type of this class.
+ // Intiontionally long name to indicate the hackiness for handling legacy
+ // callers.
+ Position CaretPositionFromTextContentOffsetAndAffinity(
+ unsigned offset,
+ TextAffinity affinity) const;
+
+ // Returns the visual left/right edge caret position of the character at the
+ // given logical |index|.
+ Position LeftEdgeOf(unsigned index) const;
+ Position RightEdgeOf(unsigned index) const;
+
+ // Left/right visual movements
+ // TODO(xiaochengh): Handle the following
+ // - Grapheme clusters
+ // - Enterable atomic inlines
+ // - Editing-ignored contents
+ // - Multiple lines
+
+ enum class VisualMovementResultType {
+ kWithinContext,
+ kBeforeContext,
+ kAfterContext
+ };
+
+ // Given the character at the logical |index|, returns the logical index of
+ // the character at its left/right side.
+ struct VisualCharacterMovementResult {
+ bool IsWithinContext() const {
+ return type == VisualMovementResultType::kWithinContext;
+ }
+ bool IsBeforeContext() const {
+ return type == VisualMovementResultType::kBeforeContext;
+ }
+ bool IsAfterContext() const {
+ return type == VisualMovementResultType::kAfterContext;
+ }
+
+ VisualMovementResultType type;
+ base::Optional<unsigned> index;
+ };
+ VisualCharacterMovementResult LeftCharacterOf(unsigned index) const;
+ VisualCharacterMovementResult RightCharacterOf(unsigned index) const;
+
+ // Given a caret position, moves it left/right by one grapheme cluster and
+ // returns the result.
+ struct VisualCaretMovementResult {
+ bool IsWithinContext() const {
+ return type == VisualMovementResultType::kWithinContext;
+ }
+ bool IsBeforeContext() const {
+ return type == VisualMovementResultType::kBeforeContext;
+ }
+ bool IsAfterContext() const {
+ return type == VisualMovementResultType::kAfterContext;
+ }
+
+ VisualMovementResultType type;
+ base::Optional<Position> position;
+ };
+ VisualCaretMovementResult LeftPositionOf(const Position&) const;
+ VisualCaretMovementResult RightPositionOf(const Position&) const;
+
+ private:
+ enum class MoveDirection { kTowardsLeft, kTowardsRight };
+ static MoveDirection OppositeDirectionOf(MoveDirection);
+ static bool TowardsSameDirection(MoveDirection, TextDirection);
+ static base::Optional<unsigned> MoveVisualIndex(unsigned index,
+ unsigned length,
+ MoveDirection);
+
+ Position EdgeOfInternal(unsigned index, MoveDirection) const;
+ VisualCharacterMovementResult MoveCharacterInternal(unsigned index,
+ MoveDirection) const;
+ VisualCaretMovementResult MoveCaretInternal(const Position&,
+ MoveDirection) const;
+
+ String text_;
+
+ // TODO(xiaochengh): Add line-aware index.
+ // TODO(xiaochengh): Reduce memory consumption.
+ Vector<UBiDiLevel, 32> bidi_levels_;
+ Vector<int32_t, 32> indices_in_visual_order_;
+ Vector<int32_t, 32> visual_indices_;
+
+ bool is_bidi_enabled_;
+ TextDirection base_direction_;
+
+ DISALLOW_COPY_AND_ASSIGN(NGCaretNavigator);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_NAVIGATOR_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator_test.cc
new file mode 100644
index 00000000000..63dfce30882
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator_test.cc
@@ -0,0 +1,274 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
+
+namespace blink {
+
+class NGCaretNavigatorTest : public RenderingTest,
+ public testing::WithParamInterface<bool>,
+ private ScopedLayoutNGForTest,
+ private ScopedBidiCaretAffinityForTest {
+ public:
+ NGCaretNavigatorTest()
+ : ScopedLayoutNGForTest(GetParam()),
+ ScopedBidiCaretAffinityForTest(true) {}
+
+ void SetupHtml(const char* id, String html) {
+ SetBodyInnerHTML(html);
+
+ LayoutBlockFlow* layout_block_flow =
+ ToLayoutBlockFlow(GetLayoutObjectByElementId(id));
+ DCHECK(layout_block_flow);
+ DCHECK(layout_block_flow->ChildrenInline());
+ DCHECK_EQ(layout_block_flow->IsLayoutNGMixin(), GetParam());
+
+ const NGOffsetMapping* mapping =
+ NGInlineNode::GetOffsetMapping(layout_block_flow, &mapping_storage_);
+ DCHECK(mapping);
+ DCHECK_EQ(!mapping_storage_,
+ GetParam()); // |storage| is used only for legacy.
+
+ caret_navigator_ = mapping->GetCaretNavigator();
+ DCHECK(caret_navigator_);
+ }
+
+ UBiDiLevel BidiLevelAt(unsigned index) const {
+ return caret_navigator_->BidiLevelAt(index);
+ }
+
+ NGCaretNavigator::VisualCharacterMovementResult LeftCharacterOf(
+ unsigned index) const {
+ return caret_navigator_->LeftCharacterOf(index);
+ }
+
+ NGCaretNavigator::VisualCharacterMovementResult RightCharacterOf(
+ unsigned index) const {
+ return caret_navigator_->RightCharacterOf(index);
+ }
+
+ NGCaretNavigator::Position CaretBefore(unsigned index) const {
+ return {index, NGCaretNavigator::PositionAnchorType::kBefore};
+ }
+
+ NGCaretNavigator::Position CaretAfter(unsigned index) const {
+ return {index, NGCaretNavigator::PositionAnchorType::kAfter};
+ }
+
+ NGCaretNavigator::VisualCaretMovementResult LeftPositionOf(
+ const NGCaretNavigator::Position& position) const {
+ return caret_navigator_->LeftPositionOf(position);
+ }
+
+ NGCaretNavigator::VisualCaretMovementResult RightPositionOf(
+ const NGCaretNavigator::Position& position) const {
+ return caret_navigator_->RightPositionOf(position);
+ }
+
+ protected:
+ std::unique_ptr<NGOffsetMapping> mapping_storage_;
+ const NGCaretNavigator* caret_navigator_;
+};
+
+INSTANTIATE_TEST_CASE_P(All, NGCaretNavigatorTest, testing::Bool());
+
+TEST_P(NGCaretNavigatorTest, BidiLevelAtBasic) {
+ SetupHtml("container",
+ "<div id=container>abc&#x05D0;&#x05D1;&#x05D2;123</div>");
+
+ EXPECT_EQ(0u, BidiLevelAt(0));
+ EXPECT_EQ(0u, BidiLevelAt(1));
+ EXPECT_EQ(0u, BidiLevelAt(2));
+ EXPECT_EQ(1u, BidiLevelAt(3));
+ EXPECT_EQ(1u, BidiLevelAt(4));
+ EXPECT_EQ(1u, BidiLevelAt(5));
+ EXPECT_EQ(2u, BidiLevelAt(6));
+ EXPECT_EQ(2u, BidiLevelAt(7));
+ EXPECT_EQ(2u, BidiLevelAt(8));
+}
+
+TEST_P(NGCaretNavigatorTest, LeftCharacterOfBasic) {
+ SetupHtml("container",
+ "<div id=container>abc&#x05D0;&#x05D1;&#x05D2;123</div>");
+
+ EXPECT_TRUE(LeftCharacterOf(0).IsBeforeContext());
+
+ EXPECT_TRUE(LeftCharacterOf(1).IsWithinContext());
+ EXPECT_EQ(0u, *LeftCharacterOf(1).index);
+
+ EXPECT_TRUE(LeftCharacterOf(2).IsWithinContext());
+ EXPECT_EQ(1u, *LeftCharacterOf(2).index);
+
+ EXPECT_TRUE(LeftCharacterOf(3).IsWithinContext());
+ EXPECT_EQ(4u, *LeftCharacterOf(3).index);
+
+ EXPECT_TRUE(LeftCharacterOf(4).IsWithinContext());
+ EXPECT_EQ(5u, *LeftCharacterOf(4).index);
+
+ EXPECT_TRUE(LeftCharacterOf(5).IsWithinContext());
+ EXPECT_EQ(8u, *LeftCharacterOf(5).index);
+
+ EXPECT_TRUE(LeftCharacterOf(6).IsWithinContext());
+ EXPECT_EQ(2u, *LeftCharacterOf(6).index);
+
+ EXPECT_TRUE(LeftCharacterOf(7).IsWithinContext());
+ EXPECT_EQ(6u, *LeftCharacterOf(7).index);
+
+ EXPECT_TRUE(LeftCharacterOf(8).IsWithinContext());
+ EXPECT_EQ(7u, *LeftCharacterOf(8).index);
+}
+
+TEST_P(NGCaretNavigatorTest, RightCharacterOfBasic) {
+ SetupHtml("container",
+ "<div id=container>abc&#x05D0;&#x05D1;&#x05D2;123</div>");
+
+ EXPECT_TRUE(RightCharacterOf(0).IsWithinContext());
+ EXPECT_EQ(1u, *RightCharacterOf(0).index);
+
+ EXPECT_TRUE(RightCharacterOf(1).IsWithinContext());
+ EXPECT_EQ(2u, *RightCharacterOf(1).index);
+
+ EXPECT_TRUE(RightCharacterOf(2).IsWithinContext());
+ EXPECT_EQ(6u, *RightCharacterOf(2).index);
+
+ EXPECT_TRUE(RightCharacterOf(3).IsAfterContext());
+
+ EXPECT_TRUE(RightCharacterOf(4).IsWithinContext());
+ EXPECT_EQ(3u, *RightCharacterOf(4).index);
+
+ EXPECT_TRUE(RightCharacterOf(5).IsWithinContext());
+ EXPECT_EQ(4u, *RightCharacterOf(5).index);
+
+ EXPECT_TRUE(RightCharacterOf(6).IsWithinContext());
+ EXPECT_EQ(7u, *RightCharacterOf(6).index);
+
+ EXPECT_TRUE(RightCharacterOf(7).IsWithinContext());
+ EXPECT_EQ(8u, *RightCharacterOf(7).index);
+
+ EXPECT_TRUE(RightCharacterOf(8).IsWithinContext());
+ EXPECT_EQ(5u, *RightCharacterOf(8).index);
+}
+
+TEST_P(NGCaretNavigatorTest, LeftPositionOfBasic) {
+ SetupHtml("container",
+ "<div id=container>abc&#x05D0;&#x05D1;&#x05D2;123</div>");
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(0)).IsBeforeContext());
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(0)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(0), *LeftPositionOf(CaretAfter(0)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(1)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(0), *LeftPositionOf(CaretBefore(1)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(1)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(1), *LeftPositionOf(CaretAfter(1)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(2)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(1), *LeftPositionOf(CaretBefore(2)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(2)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(2), *LeftPositionOf(CaretAfter(2)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(3)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(3), *LeftPositionOf(CaretBefore(3)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(3)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(4), *LeftPositionOf(CaretAfter(3)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(4)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(4), *LeftPositionOf(CaretBefore(4)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(4)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(5), *LeftPositionOf(CaretAfter(4)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(5)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(5), *LeftPositionOf(CaretBefore(5)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(5)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(8), *LeftPositionOf(CaretAfter(5)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(6)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(2), *LeftPositionOf(CaretBefore(6)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(6)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(6), *LeftPositionOf(CaretAfter(6)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(7)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(6), *LeftPositionOf(CaretBefore(7)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(7)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(7), *LeftPositionOf(CaretAfter(7)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretBefore(8)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(7), *LeftPositionOf(CaretBefore(8)).position);
+
+ EXPECT_TRUE(LeftPositionOf(CaretAfter(8)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(8), *LeftPositionOf(CaretAfter(8)).position);
+}
+
+TEST_P(NGCaretNavigatorTest, RightPositionOfBasic) {
+ SetupHtml("container",
+ "<div id=container>abc&#x05D0;&#x05D1;&#x05D2;123</div>");
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(0)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(0), *RightPositionOf(CaretBefore(0)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(0)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(1), *RightPositionOf(CaretAfter(0)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(1)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(1), *RightPositionOf(CaretBefore(1)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(1)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(2), *RightPositionOf(CaretAfter(1)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(2)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(2), *RightPositionOf(CaretBefore(2)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(2)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(6), *RightPositionOf(CaretAfter(2)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(3)).IsAfterContext());
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(3)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(3), *RightPositionOf(CaretAfter(3)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(4)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(3), *RightPositionOf(CaretBefore(4)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(4)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(4), *RightPositionOf(CaretAfter(4)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(5)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(4), *RightPositionOf(CaretBefore(5)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(5)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(5), *RightPositionOf(CaretAfter(5)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(6)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(6), *RightPositionOf(CaretBefore(6)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(6)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(7), *RightPositionOf(CaretAfter(6)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(7)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(7), *RightPositionOf(CaretBefore(7)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(7)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(8), *RightPositionOf(CaretAfter(7)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretBefore(8)).IsWithinContext());
+ EXPECT_EQ(CaretAfter(8), *RightPositionOf(CaretBefore(8)).position);
+
+ EXPECT_TRUE(RightPositionOf(CaretAfter(8)).IsWithinContext());
+ EXPECT_EQ(CaretBefore(5), *RightPositionOf(CaretAfter(8)).position);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
index d0267eb4142..4ef6185e6f9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
@@ -57,6 +58,8 @@ bool CanResolveCaretPositionBeforeFragment(const NGPaintFragment& fragment,
TextAffinity affinity) {
if (affinity == TextAffinity::kDownstream)
return true;
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return false;
const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
const NGPhysicalLineBoxFragment& current_line =
ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
@@ -74,6 +77,8 @@ bool CanResolveCaretPositionAfterFragment(const NGPaintFragment& fragment,
TextAffinity affinity) {
if (affinity == TextAffinity::kUpstream)
return true;
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return false;
const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
const NGPhysicalLineBoxFragment& current_line =
ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
@@ -208,6 +213,8 @@ CaretPositionResolution TryResolveCaretPositionWithFragment(
}
bool NeedsBidiAdjustment(const NGCaretPosition& caret_position) {
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return false;
if (caret_position.IsNull())
return false;
if (caret_position.position_type != NGCaretPositionType::kAtTextOffset)
@@ -232,6 +239,42 @@ NGCaretPosition AdjustCaretPositionForBidiText(
return BidiAdjustment::AdjustForCaretPositionResolution(caret_position);
}
+bool IsUpstreamAfterLineBreak(const NGCaretPosition& caret_position) {
+ if (caret_position.position_type != NGCaretPositionType::kAtTextOffset)
+ return false;
+
+ DCHECK(caret_position.fragment);
+ DCHECK(caret_position.fragment->PhysicalFragment().IsText());
+ DCHECK(caret_position.text_offset.has_value());
+
+ const NGPhysicalTextFragment& text_fragment =
+ ToNGPhysicalTextFragment(caret_position.fragment->PhysicalFragment());
+ if (!text_fragment.IsLineBreak())
+ return false;
+ return caret_position.text_offset.value() == text_fragment.EndOffset();
+}
+
+NGCaretPosition BetterCandidateBetween(const NGCaretPosition& current,
+ const NGCaretPosition& other,
+ unsigned offset,
+ TextAffinity affinity) {
+ DCHECK(!other.IsNull());
+ if (current.IsNull())
+ return other;
+
+ // There shouldn't be too many cases where we have multiple candidates.
+ // Make sure all of them are captured and handled here.
+
+ // Only known case: either |current| or |other| is upstream after line break.
+ DCHECK_EQ(affinity, TextAffinity::kUpstream);
+ if (IsUpstreamAfterLineBreak(current)) {
+ DCHECK(!IsUpstreamAfterLineBreak(other));
+ return other;
+ }
+ DCHECK(IsUpstreamAfterLineBreak(other));
+ return current;
+}
+
} // namespace
// The main function for compute an NGCaretPosition. See the comments at the top
@@ -258,10 +301,8 @@ NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow& context,
return AdjustCaretPositionForBidiText(resolution.caret_position);
DCHECK_EQ(ResolutionType::kFoundCandidate, resolution.type);
- // TODO(xiaochengh): We are not sure if we can ever find multiple
- // candidates. Handle it once reached.
- DCHECK(candidate.IsNull());
- candidate = resolution.caret_position;
+ candidate = BetterCandidateBetween(candidate, resolution.caret_position,
+ offset, affinity);
}
return AdjustCaretPositionForBidiText(candidate);
@@ -275,7 +316,7 @@ NGCaretPosition ComputeNGCaretPosition(const PositionWithAffinity& position) {
return NGCaretPosition();
const NGOffsetMapping* mapping =
- NGOffsetMapping::GetForContainingBlockFlow(context);
+ NGInlineNode::GetOffsetMapping(context, nullptr);
DCHECK(mapping);
const base::Optional<unsigned> maybe_offset =
mapping->GetTextContentOffset(position.GetPosition());
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
index 9d6fa0a16cf..97038f8294e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
@@ -153,10 +153,49 @@ LocalCaretRect ComputeLocalCaretRect(const NGCaretPosition& caret_position) {
return {layout_object, LayoutRect()};
}
+LocalCaretRect ComputeLocalSelectionRect(
+ const NGCaretPosition& caret_position) {
+ const LocalCaretRect caret_rect = ComputeLocalCaretRect(caret_position);
+ if (!caret_rect.layout_object)
+ return caret_rect;
+
+ const LayoutObject* layout_object = caret_rect.layout_object;
+ const LayoutRect rect = caret_rect.rect;
+
+ const NGPaintFragment& fragment = *caret_position.fragment;
+ const NGPaintFragment* line_box = fragment.ContainerLineBox();
+ // TODO(xiaochengh): We'll hit this DCHECK for caret in empty block if we
+ // enable LayoutNG in contenteditable.
+ DCHECK(line_box);
+
+ if (fragment.Style().IsHorizontalWritingMode()) {
+ const LayoutUnit line_top = line_box->InlineOffsetToContainerBox().top;
+ const LayoutUnit line_height = line_box->Size().height;
+ return LocalCaretRect(layout_object, LayoutRect(rect.X(), line_top,
+ rect.Width(), line_height));
+ }
+
+ const LayoutUnit line_top = line_box->InlineOffsetToContainerBox().left;
+ const LayoutUnit line_height = line_box->Size().width;
+ LayoutRect layout_rect(line_top, rect.Y(), line_height, rect.Height());
+ // For vertical-rl, convert to "flipped block-flow" coordinates space.
+ // See core/layout/README.md#coordinate-spaces for details.
+ if (fragment.Style().IsFlippedBlocksWritingMode()) {
+ const LayoutBlockFlow* container = layout_object->ContainingNGBlockFlow();
+ container->FlipForWritingMode(layout_rect);
+ }
+ return LocalCaretRect(layout_object, layout_rect);
+}
+
} // namespace
LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity& position) {
return ComputeLocalCaretRect(ComputeNGCaretPosition(position));
}
+LocalCaretRect ComputeNGLocalSelectionRect(
+ const PositionWithAffinity& position) {
+ return ComputeLocalSelectionRect(ComputeNGCaretPosition(position));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
index 4215ef0d6f5..d7a1a029e07 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
@@ -20,6 +20,11 @@ struct LocalCaretRect;
// formatting context.
CORE_EXPORT LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity&);
+// Almost the same as ComputeNGLocalCaretRect, except that the returned rect
+// is adjusted to span the containing line box in the block direction.
+CORE_EXPORT LocalCaretRect
+ComputeNGLocalSelectionRect(const PositionWithAffinity&);
+
} // namespace blink
#endif // NGCaretRect_h
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index 19a1adf2d90..0603ca665e3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -101,22 +101,8 @@ bool NGInlineBoxState::CanAddTextOfStyle(
return false;
}
-LayoutObject*
-NGInlineLayoutStateStack::ContainingLayoutObjectForAbsolutePositionObjects()
- const {
- for (unsigned i = stack_.size(); i-- > 1;) {
- const NGInlineBoxState& box = stack_[i];
- DCHECK(box.style);
- if (box.style->CanContainAbsolutePositionObjects()) {
- DCHECK(box.item->GetLayoutObject());
- return box.item->GetLayoutObject();
- }
- }
- return nullptr;
-}
-
NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
- const ComputedStyle* line_style,
+ const ComputedStyle& line_style,
FontBaseline baseline_type,
bool line_height_quirk) {
if (stack_.IsEmpty()) {
@@ -147,14 +133,14 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
// Initialize the box state for the line box.
NGInlineBoxState& line_box = LineBoxState();
- if (line_box.style != line_style) {
- line_box.style = line_style;
+ if (line_box.style != &line_style) {
+ line_box.style = &line_style;
// Use a "strut" (a zero-width inline box with the element's font and
// line height properties) as the initial metrics for the line box.
// https://drafts.csswg.org/css2/visudet.html#strut
if (!line_height_quirk)
- line_box.ComputeTextMetrics(*line_style, baseline_type);
+ line_box.ComputeTextMetrics(line_style, baseline_type);
}
return &stack_.back();
@@ -608,10 +594,19 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
child.layout_result.reset();
} else if (child.fragment) {
box.AddChild(std::move(child.fragment), child.offset - offset);
+ } else if (child.out_of_flow_positioned_box) {
+ DCHECK(item->GetLayoutObject()->IsLayoutInline());
+ NGBlockNode oof_box(ToLayoutBox(child.out_of_flow_positioned_box));
+
+ // child.offset is the static position wrt. the linebox. As we are adding
+ // this as a child of an inline level fragment, we adjust the static
+ // position to be relative to this fragment.
+ NGLogicalOffset static_offset = child.offset - offset;
+
+ box.AddOutOfFlowChildCandidate(oof_box, static_offset,
+ child.container_direction);
+ child.out_of_flow_positioned_box = nullptr;
}
- // Leave out-of-flow fragments. They need to be at the top level so that
- // NGInlineLayoutAlgorithm can handle them later.
- DCHECK(!child.HasInFlowFragment());
}
box.MoveOutOfFlowDescendantCandidatesToDescendants();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index 80d9eb33bf0..cc29536d955 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -15,7 +15,6 @@
namespace blink {
-class LayoutObject;
class NGInlineItem;
struct NGInlineItemResult;
class ShapeResultView;
@@ -117,7 +116,7 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// Initialize the box state stack for a new line.
// @return The initial box state for the line.
- NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle*, FontBaseline, bool);
+ NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle&, FontBaseline, bool);
// Push a box state stack.
NGInlineBoxState* OnOpenTag(const NGInlineItem&,
@@ -135,8 +134,6 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// Compute all the pending positioning at the end of a line.
void OnEndPlaceItems(NGLineBoxFragmentBuilder::ChildList*, FontBaseline);
- LayoutObject* ContainingLayoutObjectForAbsolutePositionObjects() const;
-
bool HasBoxFragments() const { return !box_data_list_.IsEmpty(); }
// This class keeps indexes to fragments in the line box, and that only
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
index f5e73147888..23f9cdbfa28 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
@@ -8,6 +8,19 @@
namespace blink {
+namespace {
+
+struct SameSizeAsNGInlineBreakToken : NGBreakToken {
+ scoped_refptr<const ComputedStyle> style_;
+ unsigned numbers[2];
+};
+
+static_assert(sizeof(NGInlineBreakToken) ==
+ sizeof(SameSizeAsNGInlineBreakToken),
+ "NGInlineBreakToken should stay small");
+
+} // namespace
+
NGInlineBreakToken::NGInlineBreakToken(
NGInlineNode node,
const ComputedStyle* style,
@@ -17,16 +30,14 @@ NGInlineBreakToken::NGInlineBreakToken(
: NGBreakToken(kInlineBreakToken, kUnfinished, node),
style_(style),
item_index_(item_index),
- text_offset_(text_offset),
- flags_(flags),
- ignore_floats_(false) {}
+ text_offset_(text_offset) {
+ flags_ = flags;
+}
NGInlineBreakToken::NGInlineBreakToken(NGLayoutInputNode node)
: NGBreakToken(kInlineBreakToken, kFinished, node),
item_index_(0),
- text_offset_(0),
- flags_(kDefault),
- ignore_floats_(false) {}
+ text_offset_(0) {}
NGInlineBreakToken::~NGInlineBreakToken() = default;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
index ff301ee8364..1a9fd6d96bb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
@@ -93,8 +93,6 @@ class CORE_EXPORT NGInlineBreakToken final : public NGBreakToken {
scoped_refptr<const ComputedStyle> style_;
unsigned item_index_;
unsigned text_offset_;
- unsigned flags_ : 2; // NGInlineBreakTokenFlags
- unsigned ignore_floats_ : 1;
};
DEFINE_TYPE_CASTS(NGInlineBreakToken,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
index 00946fc018e..a22d01ebfe9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
@@ -67,9 +67,7 @@ NGInlineItem::NGInlineItem(NGInlineItemType type,
style_(style),
layout_object_(layout_object),
type_(type),
- script_(0),
- font_fallback_priority_(0),
- render_orientation_(0),
+ segment_data_(0),
bidi_level_(UBIDI_LTR),
shape_options_(kPreContext | kPostContext),
is_empty_item_(false),
@@ -92,9 +90,7 @@ NGInlineItem::NGInlineItem(const NGInlineItem& other,
style_(other.style_),
layout_object_(other.layout_object_),
type_(other.type_),
- script_(other.script_),
- font_fallback_priority_(other.font_fallback_priority_),
- render_orientation_(other.render_orientation_),
+ segment_data_(other.segment_data_),
bidi_level_(other.bidi_level_),
shape_options_(other.shape_options_),
is_empty_item_(other.is_empty_item_),
@@ -151,94 +147,27 @@ const char* NGInlineItem::NGInlineItemTypeToString(int val) const {
return kNGInlineItemTypeStrings[val];
}
-UScriptCode NGInlineItem::Script() const {
- return script_ != kInvalidScript ? static_cast<UScriptCode>(script_)
- : USCRIPT_INVALID_CODE;
-}
-
-FontFallbackPriority NGInlineItem::GetFontFallbackPriority() const {
- return static_cast<enum FontFallbackPriority>(font_fallback_priority_);
-}
-
-OrientationIterator::RenderOrientation NGInlineItem::RenderOrientation() const {
- return static_cast<OrientationIterator::RenderOrientation>(
- render_orientation_);
-}
-
RunSegmenter::RunSegmenterRange NGInlineItem::CreateRunSegmenterRange() const {
- return {start_offset_, end_offset_, Script(), RenderOrientation(),
- GetFontFallbackPriority()};
+ return NGInlineItemSegment::UnpackSegmentData(start_offset_, end_offset_,
+ segment_data_);
}
bool NGInlineItem::EqualsRunSegment(const NGInlineItem& other) const {
- return script_ == other.script_ &&
- font_fallback_priority_ == other.font_fallback_priority_ &&
- render_orientation_ == other.render_orientation_;
+ return segment_data_ == other.segment_data_;
}
-void NGInlineItem::SetRunSegment(const RunSegmenter::RunSegmenterRange& range) {
+void NGInlineItem::SetSegmentData(unsigned segment_data) {
DCHECK_EQ(Type(), NGInlineItem::kText);
-
- // Orientation should be set in a separate pass. See
- // NGInlineNode::SegmentScriptRuns().
- DCHECK_EQ(range.render_orientation, OrientationIterator::kOrientationKeep);
-
- script_ = static_cast<unsigned>(range.script);
- font_fallback_priority_ = static_cast<unsigned>(range.font_fallback_priority);
-
- // Ensure our bit fields are large enough by reading them back.
- DCHECK_EQ(range.script, Script());
- DCHECK_EQ(range.font_fallback_priority, GetFontFallbackPriority());
+ segment_data_ = segment_data;
}
-void NGInlineItem::SetFontOrientation(
- OrientationIterator::RenderOrientation orientation) {
- DCHECK_EQ(Type(), NGInlineItem::kText);
-
- // Ensure the value can fit in the bit field.
- DCHECK_LT(static_cast<unsigned>(orientation), 1u << 1);
-
- render_orientation_ = orientation != 0;
-}
-
-unsigned NGInlineItem::PopulateItemsFromRun(
- Vector<NGInlineItem>& items,
- unsigned index,
- const RunSegmenter::RunSegmenterRange& range) {
- DCHECK_GE(range.end, items[index].start_offset_);
-
- for (;; index++) {
- NGInlineItem& item = items[index];
- DCHECK_LE(item.start_offset_, range.end);
-
+void NGInlineItem::SetSegmentData(const RunSegmenter::RunSegmenterRange& range,
+ Vector<NGInlineItem>* items) {
+ unsigned segment_data = NGInlineItemSegment::PackSegmentData(range);
+ for (NGInlineItem& item : *items) {
if (item.Type() == NGInlineItem::kText)
- item.SetRunSegment(range);
-
- if (range.end == item.end_offset_)
- break;
- if (range.end < item.end_offset_) {
- Split(items, index, range.end);
- break;
- }
+ item.segment_data_ = segment_data;
}
- return index + 1;
-}
-
-unsigned NGInlineItem::PopulateItemsFromFontOrientation(
- Vector<NGInlineItem>& items,
- unsigned index,
- unsigned end_offset,
- OrientationIterator::RenderOrientation orientation) {
- // FontOrientaiton is set per item, end_offset should be within this item.
- NGInlineItem& item = items[index];
- DCHECK_GE(end_offset, item.start_offset_);
- DCHECK_LE(end_offset, item.end_offset_);
-
- item.SetFontOrientation(orientation);
-
- if (end_offset < item.end_offset_)
- Split(items, index, end_offset);
- return index + 1;
}
void NGInlineItem::SetBidiLevel(UBiDiLevel level) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
index 8becfc61e55..7604cd20122 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -6,6 +6,7 @@
#define NGInlineItem_h
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -142,24 +143,14 @@ class CORE_EXPORT NGInlineItem {
static void Split(Vector<NGInlineItem>&, unsigned index, unsigned offset);
- // Get RunSegmenter properties.
- UScriptCode Script() const;
- FontFallbackPriority GetFontFallbackPriority() const;
- OrientationIterator::RenderOrientation RenderOrientation() const;
+ // RunSegmenter properties.
+ unsigned SegmentData() const { return segment_data_; }
+ void SetSegmentData(unsigned segment_data);
+ static void SetSegmentData(const RunSegmenter::RunSegmenterRange& range,
+ Vector<NGInlineItem>* items);
RunSegmenter::RunSegmenterRange CreateRunSegmenterRange() const;
// Whether the other item has the same RunSegmenter properties or not.
bool EqualsRunSegment(const NGInlineItem&) const;
- // Set RunSegmenter properties.
- static unsigned PopulateItemsFromRun(Vector<NGInlineItem>&,
- unsigned index,
- const RunSegmenter::RunSegmenterRange&);
- void SetRunSegment(const RunSegmenter::RunSegmenterRange&);
- static unsigned PopulateItemsFromFontOrientation(
- Vector<NGInlineItem>&,
- unsigned index,
- unsigned end_offset,
- OrientationIterator::RenderOrientation);
- void SetFontOrientation(OrientationIterator::RenderOrientation);
void SetBidiLevel(UBiDiLevel);
static unsigned SetBidiLevel(Vector<NGInlineItem>&,
@@ -184,15 +175,8 @@ class CORE_EXPORT NGInlineItem {
scoped_refptr<const ComputedStyle> style_;
LayoutObject* layout_object_;
- // UScriptCode is -1 (USCRIPT_INVALID_CODE) to 177 as of ICU 60.
- // This can be packed to 8 bits, by handling -1 separately.
- static constexpr unsigned kScriptBits = 8;
- static constexpr unsigned kInvalidScript = (1 << kScriptBits) - 1;
-
unsigned type_ : 4;
- unsigned script_ : kScriptBits;
- unsigned font_fallback_priority_ : 2; // FontFallbackPriority.
- unsigned render_orientation_ : 1; // RenderOrientation (excl. kInvalid.)
+ unsigned segment_data_ : NGInlineItemSegment::kSegmentDataBits;
unsigned bidi_level_ : 8; // UBiDiLevel is defined as uint8_t.
unsigned shape_options_ : 2;
unsigned is_empty_item_ : 1;
@@ -225,6 +209,12 @@ struct CORE_EXPORT NGInlineItemsData {
String text_content;
Vector<NGInlineItem> items;
+ // Cache RunSegmenter segments when at least one item has multiple runs.
+ // Set to nullptr when all items has only single run, which is common case for
+ // most writing systems. However, in multi-script writing systems such as
+ // Japanese, almost every item has multiple runs.
+ std::unique_ptr<NGInlineItemSegments> segments;
+
// The DOM to text content offset mapping of this inline node.
std::unique_ptr<NGOffsetMapping> offset_mapping;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
index 960648adae9..152ca68df5f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
@@ -17,12 +17,16 @@ NGInlineItemResult::NGInlineItemResult(const NGInlineItem* item,
unsigned index,
unsigned start,
unsigned end,
- bool should_create_line_box)
+ bool break_anywhere_if_overflow,
+ bool should_create_line_box,
+ bool has_unpositioned_floats)
: item(item),
item_index(index),
start_offset(start),
end_offset(end),
- should_create_line_box(should_create_line_box) {}
+ break_anywhere_if_overflow(break_anywhere_if_overflow),
+ should_create_line_box(should_create_line_box),
+ has_unpositioned_floats(has_unpositioned_floats) {}
void NGLineInfo::SetLineStyle(const NGInlineNode& node,
const NGInlineItemsData& items_data,
@@ -33,11 +37,11 @@ void NGLineInfo::SetLineStyle(const NGInlineNode& node,
}
#if DCHECK_IS_ON()
-void NGInlineItemResult::CheckConsistency(bool during_line_break) const {
+void NGInlineItemResult::CheckConsistency(bool allow_null_shape_result) const {
DCHECK(item);
if (item->Type() == NGInlineItem::kText) {
DCHECK_LT(start_offset, end_offset);
- if (during_line_break && !shape_result)
+ if (allow_null_shape_result && !shape_result)
return;
DCHECK(shape_result);
DCHECK_EQ(end_offset - start_offset, shape_result->NumCharacters());
@@ -47,6 +51,93 @@ void NGInlineItemResult::CheckConsistency(bool during_line_break) const {
}
#endif
+unsigned NGLineInfo::InflowEndOffset() const {
+ const NGInlineItemResults& item_results = Results();
+ for (auto it = item_results.rbegin(); it != item_results.rend(); ++it) {
+ const NGInlineItemResult& item_result = *it;
+ DCHECK(item_result.item);
+ const NGInlineItem& item = *item_result.item;
+ if (item.Type() == NGInlineItem::kText ||
+ item.Type() == NGInlineItem::kControl ||
+ item.Type() == NGInlineItem::kAtomicInline)
+ return item_result.end_offset;
+ }
+ return StartOffset();
+}
+
+LayoutUnit NGLineInfo::ComputeTrailingSpaceWidth(
+ unsigned* end_offset_out) const {
+ if (!has_trailing_spaces_) {
+ if (end_offset_out)
+ *end_offset_out = InflowEndOffset();
+ return LayoutUnit();
+ }
+
+ const NGInlineItemResults& item_results = Results();
+ LayoutUnit trailing_spaces_width;
+ for (auto it = item_results.rbegin(); it != item_results.rend(); ++it) {
+ const NGInlineItemResult& item_result = *it;
+ DCHECK(item_result.item);
+ const NGInlineItem& item = *item_result.item;
+
+ // If this item is opaque to whitespace collapsing, whitespace before this
+ // item maybe collapsed. Keep looking for previous items.
+ if (item.EndCollapseType() == NGInlineItem::kOpaqueToCollapsing) {
+ continue;
+ }
+ // These items should be opaque-to-collapsing.
+ DCHECK(item.Type() != NGInlineItem::kFloating &&
+ item.Type() != NGInlineItem::kOutOfFlowPositioned &&
+ item.Type() != NGInlineItem::kBidiControl);
+
+ if (item.Type() == NGInlineItem::kControl ||
+ item_result.has_only_trailing_spaces) {
+ trailing_spaces_width += item_result.inline_size;
+ continue;
+ }
+
+ // The last text item may contain trailing spaces if this is a last line,
+ // has a forced break, or is 'white-space: pre'.
+ unsigned end_offset = item_result.end_offset;
+ DCHECK(end_offset);
+ if (item.Type() == NGInlineItem::kText) {
+ const String& text = items_data_->text_content;
+ if (end_offset && text[end_offset - 1] == kSpaceCharacter) {
+ do {
+ --end_offset;
+ } while (end_offset > item_result.start_offset &&
+ text[end_offset - 1] == kSpaceCharacter);
+
+ // If all characters in this item_result are spaces, check next item.
+ if (end_offset == item_result.start_offset) {
+ trailing_spaces_width += item_result.inline_size;
+ continue;
+ }
+
+ // To compute the accurate width, we need to reshape if |end_offset| is
+ // not safe-to-break. We avoid reshaping in this case because the cost
+ // is high and the difference is subtle for the purpose of this
+ // function.
+ // TODO(kojii): Compute this without |CreateShapeResult|.
+ scoped_refptr<ShapeResult> shape_result =
+ item_result.shape_result->CreateShapeResult();
+ float end_position = shape_result->PositionForOffset(
+ end_offset - shape_result->StartIndex());
+ trailing_spaces_width += shape_result->Width() - end_position;
+ }
+ }
+
+ if (end_offset_out)
+ *end_offset_out = end_offset;
+ return trailing_spaces_width;
+ }
+
+ // An empty line, or only trailing spaces.
+ if (end_offset_out)
+ *end_offset_out = StartOffset();
+ return trailing_spaces_width;
+}
+
LayoutUnit NGLineInfo::ComputeWidth() const {
LayoutUnit inline_size = TextIndent();
for (const NGInlineItemResult& item_result : Results())
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
index e10711c4ea3..d982cf9a15e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -49,6 +50,11 @@ struct CORE_EXPORT NGInlineItemResult {
// NGLayoutResult for atomic inline items.
scoped_refptr<NGLayoutResult> layout_result;
+ // NGPositionedFloat for floating inline items. Should only be present for
+ // positioned floats (not unpositioned). It indicates where it was placed
+ // within the BFC.
+ base::Optional<NGPositionedFloat> positioned_float;
+
// Margins, borders, and padding for open tags.
// Margins are set for atomic inlines too.
NGLineBoxStrut margins;
@@ -75,6 +81,11 @@ struct CORE_EXPORT NGInlineItemResult {
// characters.
bool has_only_trailing_spaces = false;
+ // The previous value of |break_anywhere_if_overflow| in the
+ // NGInlineItemResults list. Like |should_create_line_box|, this value is used
+ // to rewind properly.
+ bool break_anywhere_if_overflow = false;
+
// We don't create "certain zero-height line boxes".
// https://drafts.csswg.org/css2/visuren.html#phantom-line-box
// Such line boxes do not prevent two margins being "adjoining", and thus
@@ -91,6 +102,11 @@ struct CORE_EXPORT NGInlineItemResult {
// correctly determine that we don't need a line box.
bool should_create_line_box = false;
+ // This field should be initialized and maintained like
+ // |should_create_line_box|. It indicates if there are (at the current
+ // position) any unpositioned floats.
+ bool has_unpositioned_floats = false;
+
// End effects for text items.
// The effects are included in |shape_result|, but not in text content.
NGTextEndEffect text_end_effect = NGTextEndEffect::kNone;
@@ -100,10 +116,12 @@ struct CORE_EXPORT NGInlineItemResult {
unsigned index,
unsigned start,
unsigned end,
- bool should_create_line_box);
+ bool break_anywhere_if_overflow,
+ bool should_create_line_box,
+ bool has_unpositioned_floats);
#if DCHECK_IS_ON()
- void CheckConsistency(bool during_line_break = false) const;
+ void CheckConsistency(bool allow_null_shape_result = false) const;
#endif
};
@@ -160,10 +178,27 @@ class CORE_EXPORT NGLineInfo {
NGBfcOffset BfcOffset() const { return bfc_offset_; }
LayoutUnit AvailableWidth() const { return available_width_; }
+
+ // The width of this line. Includes trailing spaces if they were preserved.
+ // Negative width created by negative 'text-indent' is clamped to zero.
LayoutUnit Width() const { return width_.ClampNegativeToZero(); }
+ // Same as |Width()| but returns negative value as is.
LayoutUnit WidthForAlignment() const { return width_; }
+ // The width of preserved trailing spaces.
+ LayoutUnit ComputeTrailingSpaceWidth(
+ unsigned* end_offset_out = nullptr) const;
+ // Compute |Width()| from |Results()|. Used during line breaking, before
+ // |Width()| is set. After line breaking, this should match to |Width()|
+ // without clamping.
LayoutUnit ComputeWidth() const;
+ bool HasTrailingSpaces() const { return has_trailing_spaces_; }
+ void SetHasTrailingSpaces() { has_trailing_spaces_ = true; }
+
+ // True if this line has overflow, excluding preserved trailing spaces.
+ bool HasOverflow() const { return has_overflow_; }
+ void SetHasOverflow() { has_overflow_ = true; }
+
void SetBfcOffset(const NGBfcOffset& bfc_offset) { bfc_offset_ = bfc_offset; }
void SetWidth(LayoutUnit available_width, LayoutUnit width) {
available_width_ = available_width;
@@ -173,6 +208,10 @@ class CORE_EXPORT NGLineInfo {
// Start text offset of this line.
unsigned StartOffset() const { return start_offset_; }
void SetStartOffset(unsigned offset) { start_offset_ = offset; }
+ // End text offset of this line, excluding out-of-flow objects such as
+ // floating or positioned.
+ unsigned InflowEndOffset() const;
+ // End item index of this line.
unsigned EndItemIndex() const { return end_item_index_; }
void SetEndItemIndex(unsigned index) { end_item_index_ = index; }
@@ -208,6 +247,8 @@ class CORE_EXPORT NGLineInfo {
bool use_first_line_style_ = false;
bool is_last_line_ = false;
bool is_empty_line_ = false;
+ bool has_overflow_ = false;
+ bool has_trailing_spaces_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc
new file mode 100644
index 00000000000..b8aa6f020d3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc
@@ -0,0 +1,256 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h"
+
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h"
+
+namespace blink {
+
+namespace {
+
+// Constants for PackSegmentData() and UnpackSegmentData().
+//
+// UScriptCode is -1 (USCRIPT_INVALID_CODE) to 177 as of ICU 60.
+// This can be packed to 8 bits, by handling -1 separately.
+static constexpr unsigned kScriptBits = 8;
+static constexpr unsigned kFontFallbackPriorityBits = 2;
+static constexpr unsigned kRenderOrientationBits = 1;
+
+static constexpr unsigned kScriptMask = (1 << kScriptBits) - 1;
+static constexpr unsigned kFontFallbackPriorityMask =
+ (1 << kFontFallbackPriorityBits) - 1;
+static constexpr unsigned kRenderOrientationMask =
+ (1 << kRenderOrientationBits) - 1;
+
+static_assert(NGInlineItemSegment::kSegmentDataBits ==
+ kScriptBits + kRenderOrientationBits +
+ kFontFallbackPriorityBits,
+ "kSegmentDataBits must be the sum of these bits");
+
+unsigned SetRenderOrientation(
+ unsigned value,
+ OrientationIterator::RenderOrientation render_orientation) {
+ DCHECK_NE(render_orientation,
+ OrientationIterator::RenderOrientation::kOrientationInvalid);
+ return (value & ~kRenderOrientationMask) |
+ (render_orientation !=
+ OrientationIterator::RenderOrientation::kOrientationKeep);
+}
+
+} // namespace
+
+NGInlineItemSegment::NGInlineItemSegment(
+ const RunSegmenter::RunSegmenterRange& range)
+ : end_offset_(range.end), segment_data_(PackSegmentData(range)) {}
+
+NGInlineItemSegment::NGInlineItemSegment(unsigned end_offset,
+ const NGInlineItem& item)
+ : end_offset_(end_offset), segment_data_(item.SegmentData()) {}
+
+unsigned NGInlineItemSegment::PackSegmentData(
+ const RunSegmenter::RunSegmenterRange& range) {
+ DCHECK(range.script == USCRIPT_INVALID_CODE ||
+ static_cast<unsigned>(range.script) <= kScriptMask);
+ DCHECK_LE(static_cast<unsigned>(range.font_fallback_priority),
+ kFontFallbackPriorityMask);
+ DCHECK_LE(static_cast<unsigned>(range.render_orientation),
+ kRenderOrientationMask);
+
+ unsigned value =
+ range.script != USCRIPT_INVALID_CODE ? range.script : kScriptMask;
+ value <<= kFontFallbackPriorityBits;
+ value |= static_cast<unsigned>(range.font_fallback_priority);
+ value <<= kRenderOrientationBits;
+ value |= range.render_orientation;
+ return value;
+}
+
+RunSegmenter::RunSegmenterRange NGInlineItemSegment::UnpackSegmentData(
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned value) {
+ unsigned render_orientation = value & kRenderOrientationMask;
+ value >>= kRenderOrientationBits;
+ unsigned font_fallback_priority = value & kFontFallbackPriorityMask;
+ value >>= kFontFallbackPriorityBits;
+ unsigned script = value & kScriptMask;
+ return RunSegmenter::RunSegmenterRange{
+ start_offset, end_offset,
+ script != kScriptMask ? static_cast<UScriptCode>(script)
+ : USCRIPT_INVALID_CODE,
+ static_cast<OrientationIterator::RenderOrientation>(render_orientation),
+ static_cast<FontFallbackPriority>(font_fallback_priority)};
+}
+
+RunSegmenter::RunSegmenterRange NGInlineItemSegment::ToRunSegmenterRange(
+ unsigned start_offset,
+ unsigned end_offset) const {
+ DCHECK_LT(start_offset, end_offset);
+ DCHECK_LT(start_offset, end_offset_);
+ return UnpackSegmentData(start_offset, std::min(end_offset, end_offset_),
+ segment_data_);
+}
+
+unsigned NGInlineItemSegments::OffsetForSegment(
+ const NGInlineItemSegment& segment) const {
+ return &segment == segments_.begin() ? 0 : std::prev(&segment)->EndOffset();
+}
+
+#if DCHECK_IS_ON()
+void NGInlineItemSegments::CheckOffset(
+ unsigned offset,
+ const NGInlineItemSegment* segment) const {
+ DCHECK(segment >= segments_.begin() && segment < segments_.end());
+ DCHECK_GE(offset, OffsetForSegment(*segment));
+ DCHECK_LT(offset, segment->EndOffset());
+}
+#endif
+
+NGInlineItemSegments::Iterator NGInlineItemSegments::Ranges(
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned item_index) const {
+ DCHECK_LT(start_offset, end_offset);
+ DCHECK_LE(end_offset, EndOffset());
+
+ // Find the first segment for |item_index|.
+ unsigned segment_index = items_to_segments_[item_index];
+ const NGInlineItemSegment* segment = &segments_[segment_index];
+ DCHECK_GE(start_offset, OffsetForSegment(*segment));
+ if (start_offset < segment->EndOffset())
+ return Iterator(start_offset, end_offset, segment);
+
+ // The item has multiple segments. Find the segments for |start_offset|.
+ unsigned end_segment_index = item_index + 1 < items_to_segments_.size()
+ ? items_to_segments_[item_index + 1]
+ : segments_.size();
+ CHECK_GT(end_segment_index, segment_index);
+ CHECK_LE(end_segment_index, segments_.size());
+ segment = std::upper_bound(
+ segment, segment + (end_segment_index - segment_index), start_offset,
+ [](unsigned offset, const NGInlineItemSegment& segment) {
+ return offset < segment.EndOffset();
+ });
+ CheckOffset(start_offset, segment);
+ return Iterator(start_offset, end_offset, segment);
+}
+
+void NGInlineItemSegments::ComputeSegments(
+ RunSegmenter* segmenter,
+ RunSegmenter::RunSegmenterRange* range) {
+ segments_.Shrink(0);
+ do {
+ segments_.emplace_back(*range);
+ } while (segmenter->Consume(range));
+}
+
+unsigned NGInlineItemSegments::AppendMixedFontOrientation(
+ const String& text_content,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned segment_index) {
+ DCHECK_LT(start_offset, end_offset);
+ OrientationIterator iterator(text_content.Characters16() + start_offset,
+ end_offset - start_offset,
+ FontOrientation::kVerticalMixed);
+ unsigned original_start_offset = start_offset;
+ OrientationIterator::RenderOrientation orientation;
+ for (; iterator.Consume(&end_offset, &orientation);
+ start_offset = end_offset) {
+ end_offset += original_start_offset;
+ segment_index = PopulateItemsFromFontOrientation(
+ start_offset, end_offset, orientation, segment_index);
+ }
+ return segment_index;
+}
+
+unsigned NGInlineItemSegments::PopulateItemsFromFontOrientation(
+ unsigned start_offset,
+ unsigned end_offset,
+ OrientationIterator::RenderOrientation render_orientation,
+ unsigned segment_index) {
+ DCHECK_LT(start_offset, end_offset);
+ DCHECK_LE(end_offset, segments_.back().EndOffset());
+
+ while (start_offset >= segments_[segment_index].EndOffset())
+ ++segment_index;
+ if (start_offset !=
+ (segment_index ? segments_[segment_index - 1].EndOffset() : 0u)) {
+ Split(segment_index, start_offset);
+ ++segment_index;
+ }
+
+ for (;; ++segment_index) {
+ NGInlineItemSegment& segment = segments_[segment_index];
+ segment.segment_data_ =
+ SetRenderOrientation(segment.segment_data_, render_orientation);
+ if (end_offset == segment.EndOffset()) {
+ ++segment_index;
+ break;
+ }
+ if (end_offset < segment.EndOffset()) {
+ Split(segment_index, end_offset);
+ ++segment_index;
+ break;
+ }
+ }
+
+ return segment_index;
+}
+
+void NGInlineItemSegments::Split(unsigned index, unsigned offset) {
+ NGInlineItemSegment& segment = segments_[index];
+ DCHECK_LT(offset, segment.EndOffset());
+ unsigned end_offset = segment.EndOffset();
+ segment.end_offset_ = offset;
+ segments_.insert(index + 1,
+ NGInlineItemSegment(end_offset, segment.segment_data_));
+}
+
+void NGInlineItemSegments::ComputeItemIndex(const Vector<NGInlineItem>& items) {
+ DCHECK_EQ(items.back().EndOffset(), EndOffset());
+ unsigned segment_index = 0;
+ const NGInlineItemSegment* segment = segments_.begin();
+ unsigned item_index = 0;
+ items_to_segments_.resize(items.size());
+ for (const NGInlineItem& item : items) {
+ while (segment_index < segments_.size() &&
+ item.StartOffset() >= segment->EndOffset()) {
+ ++segment_index;
+ ++segment;
+ }
+ items_to_segments_[item_index++] = segment_index;
+ }
+}
+
+scoped_refptr<ShapeResult> NGInlineItemSegments::ShapeText(
+ HarfBuzzShaper* shaper,
+ const Font* font,
+ TextDirection direction,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned item_index) const {
+ scoped_refptr<ShapeResult> shape_result;
+ for (const RunSegmenter::RunSegmenterRange& range :
+ Ranges(start_offset, end_offset, item_index)) {
+ scoped_refptr<ShapeResult> segment_shape_result =
+ shaper->Shape(font, direction, range.start, range.end, &range);
+ if (!shape_result)
+ shape_result = std::move(segment_shape_result);
+ else
+ segment_shape_result->CopyRange(0, end_offset, shape_result.get());
+ }
+ DCHECK(shape_result);
+ DCHECK_EQ(shape_result->StartIndex(), start_offset);
+ DCHECK_EQ(shape_result->EndIndex(), end_offset);
+ return shape_result;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h
new file mode 100644
index 00000000000..c9510b5d039
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h
@@ -0,0 +1,186 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEM_SEGMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEM_SEGMENT_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+
+#include <unicode/ubidi.h>
+#include <unicode/uscript.h>
+
+namespace blink {
+
+class HarfBuzzShaper;
+class NGInlineItem;
+
+// Represents a segment produced by |RunSegmenter|.
+//
+// |RunSegmenter| is forward-only that this class provides random access to the
+// result by keeping in memory. This class packs the data in a compact form to
+// minimize the memory impact.
+class CORE_EXPORT NGInlineItemSegment {
+ DISALLOW_NEW();
+
+ public:
+ NGInlineItemSegment(unsigned end_offset, unsigned segment_data)
+ : end_offset_(end_offset), segment_data_(segment_data) {}
+ NGInlineItemSegment(const RunSegmenter::RunSegmenterRange& range);
+ NGInlineItemSegment(unsigned end_offset, const NGInlineItem& item);
+
+ RunSegmenter::RunSegmenterRange ToRunSegmenterRange(
+ unsigned start_offset,
+ unsigned end_offset) const;
+
+ unsigned EndOffset() const { return end_offset_; }
+
+ // Pack/unpack utility functions to store in bit fields.
+ static constexpr unsigned kSegmentDataBits = 11;
+
+ static unsigned PackSegmentData(const RunSegmenter::RunSegmenterRange& range);
+ static RunSegmenter::RunSegmenterRange
+ UnpackSegmentData(unsigned start_offset, unsigned end_offset, unsigned value);
+
+ private:
+ unsigned end_offset_;
+ unsigned segment_data_ : kSegmentDataBits;
+
+ friend class NGInlineItemSegments;
+};
+
+// Represents a set of |NGInlineItemSegment| for an inline formatting context
+// represented by |NGInlineItemsData|.
+//
+// The segments/block ratio for Latin is 1.0 to 1.01 in average, while it
+// increases to 1.01 to 1.05 for most other writing systems because it is common
+// to have some Latin words within paragraphs.
+//
+// For writing systems that has multiple native scripts such as Japanese, the
+// ratio jumps to 10-30, or sometimes 300 depends on the length of the block,
+// because the average characters/segment ratio in Japanese is 2-5. This class
+// builds internal indexes for faster access in such cases.
+class CORE_EXPORT NGInlineItemSegments {
+ USING_FAST_MALLOC(NGInlineItemSegments);
+
+ public:
+ unsigned size() const { return segments_.size(); }
+ bool IsEmpty() const { return segments_.IsEmpty(); }
+
+ // Start/end offset of each segment/entire segments.
+ unsigned OffsetForSegment(const NGInlineItemSegment& segment) const;
+ unsigned EndOffset() const { return segments_.back().EndOffset(); }
+
+ void ReserveCapacity(unsigned capacity) {
+ segments_.ReserveCapacity(capacity);
+ }
+
+ // Append a |NGInlineItemSegment| using one of its constructors.
+ template <class... Args>
+ void Append(Args&&... args) {
+ segments_.emplace_back(std::forward<Args>(args)...);
+ }
+
+ // Compute segments from the given |RunSegmenter|.
+ void ComputeSegments(RunSegmenter* segmenter,
+ RunSegmenter::RunSegmenterRange* range);
+
+ // Append mixed-vertical font orientation segments for the specified range.
+ // This is separated from |ComputeSegments| because this result depends on
+ // fonts.
+ unsigned AppendMixedFontOrientation(const String& text_content,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned segment_index);
+
+ // Compute an internal items-to-segments index for faster access.
+ void ComputeItemIndex(const Vector<NGInlineItem>& items);
+
+ // Iterates |RunSegmenterRange| for the given offsets.
+ class Iterator {
+ public:
+ Iterator(unsigned start_offset,
+ unsigned end_offset,
+ const NGInlineItemSegment* segment);
+
+ bool IsDone() const { return range_.start == end_offset_; }
+
+ // This class provides both iterator and range for the simplicity.
+ const Iterator& begin() const { return *this; }
+ const Iterator& end() const { return *this; }
+
+ bool operator!=(const Iterator& other) const { return !IsDone(); }
+ const RunSegmenter::RunSegmenterRange& operator*() const { return range_; }
+ void operator++();
+
+ private:
+ RunSegmenter::RunSegmenterRange range_;
+ const NGInlineItemSegment* segment_;
+ unsigned start_offset_;
+ unsigned end_offset_;
+ };
+ using const_iterator = Iterator;
+
+ // Returns an iterator for the given offsets.
+ //
+ // |item_index| is the index of |NGInlineItem| for the |start_offset|.
+ const_iterator Ranges(unsigned start_offset,
+ unsigned end_offset,
+ unsigned item_index) const;
+
+ // Shape runs in the range and return the concatenated |ShapeResult|.
+ scoped_refptr<ShapeResult> ShapeText(HarfBuzzShaper* shaper,
+ const Font* font,
+ TextDirection direction,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned item_index) const;
+
+ private:
+ unsigned PopulateItemsFromFontOrientation(
+ unsigned start_offset,
+ unsigned end_offset,
+ OrientationIterator::RenderOrientation,
+ unsigned segment_index);
+ void Split(unsigned index, unsigned offset);
+
+#if DCHECK_IS_ON()
+ void CheckOffset(unsigned offset, const NGInlineItemSegment* segment) const;
+#else
+ void CheckOffset(unsigned offset, const NGInlineItemSegment* segment) const {}
+#endif
+
+ Vector<NGInlineItemSegment> segments_;
+ Vector<unsigned> items_to_segments_;
+};
+
+inline NGInlineItemSegments::Iterator::Iterator(
+ unsigned start_offset,
+ unsigned end_offset,
+ const NGInlineItemSegment* segment)
+ : segment_(segment), start_offset_(start_offset), end_offset_(end_offset) {
+ DCHECK_LT(start_offset, end_offset);
+ DCHECK_LT(start_offset, segment->EndOffset());
+ range_ = segment->ToRunSegmenterRange(start_offset_, end_offset_);
+}
+
+inline void NGInlineItemSegments::Iterator::operator++() {
+ DCHECK_LE(range_.end, end_offset_);
+ if (range_.end == end_offset_) {
+ range_.start = end_offset_;
+ return;
+ }
+ start_offset_ = range_.end;
+ ++segment_;
+ range_ = segment_->ToRunSegmenterRange(start_offset_, end_offset_);
+}
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEM_SEGMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index 2fe5b2fd4a1..db23d2e3b17 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -34,6 +34,12 @@ String NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::ToString() {
}
namespace {
+// The spec turned into a discussion that may change. Put this logic on hold
+// until CSSWG resolves the issue.
+// https://github.com/w3c/csswg-drafts/issues/337
+#define SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH 0
+
+#if SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH
// Determine "Ambiguous" East Asian Width is Wide or Narrow.
// Unicode East Asian Width
// http://unicode.org/reports/tr11/
@@ -51,6 +57,7 @@ bool IsEastAsianWidthWide(UChar32 c, const ComputedStyle* style) {
(eaw == U_EA_AMBIGUOUS && style &&
IsAmbiguosEastAsianWidthWide(style));
}
+#endif
// Determine whether a newline should be removed or not.
// CSS Text, Segment Break Transformation Rules
@@ -76,6 +83,7 @@ bool ShouldRemoveNewlineSlow(const StringBuilder& before,
return true;
}
+#if SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH
// Logic below this point requires both before and after be 16 bits.
if (before.Is8Bit() || after.Is8Bit())
return false;
@@ -97,6 +105,7 @@ bool ShouldRemoveNewlineSlow(const StringBuilder& before,
if (!Character::IsHangul(next) && IsEastAsianWidthWide(next, after_style))
return true;
}
+#endif
return false;
}
@@ -245,7 +254,9 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::
typename OffsetMappingBuilder::SourceNodeScope scope(&mapping_builder_,
nullptr);
AppendBreakOpportunity(style, layout_object);
- items_->back().SetIsGenerated();
+ NGInlineItem* item = &items_->back();
+ item->SetIsGenerated();
+ item->SetEndCollapseType(NGInlineItem::kOpaqueToCollapsing);
}
template <typename OffsetMappingBuilder>
@@ -269,6 +280,18 @@ bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
// collapsed.
if (original_string[old_item0.StartOffset()] == kSpaceCharacter)
return false;
+ // If the last item ended with a collapsible space run with segment
+ // breaks, we need to run the full algorithm to apply segment break
+ // rules. This may result in removal of the space in the last item.
+ if (last_item->IsEndCollapsibleNewline()) {
+ const StringView old_item0_view(
+ original_string, old_item0.StartOffset(), old_item0.Length());
+ if (ShouldRemoveNewline(text_, last_item->EndOffset() - 1,
+ last_item->Style(), old_item0_view,
+ &new_style)) {
+ return false;
+ }
+ }
break;
case NGInlineItem::kNotCollapsible: {
// If the start of the original string was collapsed, it may be
@@ -302,6 +325,14 @@ bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
return false;
}
+ if (bidi_context_.size() && new_style.PreserveNewline()) {
+ // We exit and then re-enter all bidi contexts around a forced breaks. We
+ // must go through the full pipeline to ensure that we exit and enter the
+ // contexts in the same in the re-layout.
+ if (layout_text->GetText().Contains(kNewlineCharacter))
+ return false;
+ }
+
for (const NGInlineItem* item : items) {
// Collapsed space item at the start will not be restored, and that not
// needed to add.
@@ -518,7 +549,7 @@ void NGInlineItemsBuilderTemplate<
mapping_builder_.AppendIdentityMapping(i - start_of_non_space);
if (i == string.length()) {
- DCHECK_EQ(end_collapse, NGInlineItem::kNotCollapsible);
+ end_collapse = NGInlineItem::kNotCollapsible;
break;
}
@@ -533,16 +564,19 @@ void NGInlineItemsBuilderTemplate<
DCHECK(start_of_spaces);
// If this space run contains a newline, apply segment break rules.
- if (space_run_has_newline &&
- ShouldRemoveNewline(text_, text_.length(), style,
- StringView(string, i), style)) {
+ bool remove_newline = space_run_has_newline &&
+ ShouldRemoveNewline(text_, text_.length(), style,
+ StringView(string, i), style);
+ if (UNLIKELY(remove_newline)) {
+ // |kNotCollapsible| because the newline is removed, not collapsed.
+ end_collapse = NGInlineItem::kNotCollapsible;
space_run_has_newline = false;
} else {
- // Otherwise, or if the segment break rules did not remove the run,
- // append a space.
+ // If the segment break rules did not remove the run, append a space.
text_.Append(kSpaceCharacter);
mapping_builder_.AppendIdentityMapping(1);
start_of_spaces++;
+ end_collapse = NGInlineItem::kCollapsible;
}
if (i != start_of_spaces)
@@ -551,7 +585,6 @@ void NGInlineItemsBuilderTemplate<
// If this space run is at the end of this item, keep whether the
// collapsible space run has a newline or not in the item.
if (i == string.length()) {
- end_collapse = NGInlineItem::kCollapsible;
break;
}
}
@@ -718,6 +751,20 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendAtomicInline(
}
template <typename OffsetMappingBuilder>
+void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendFloating(
+ LayoutObject* layout_object) {
+ AppendOpaque(NGInlineItem::kFloating, kObjectReplacementCharacter, nullptr,
+ layout_object);
+}
+
+template <typename OffsetMappingBuilder>
+void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::
+ AppendOutOfFlowPositioned(LayoutObject* layout_object) {
+ AppendOpaque(NGInlineItem::kOutOfFlowPositioned, kObjectReplacementCharacter,
+ nullptr, layout_object);
+}
+
+template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendOpaque(
NGInlineItem::NGInlineItemType type,
UChar character,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
index 1a09cfdb092..e8870841bb6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -79,6 +79,12 @@ class NGInlineItemsBuilderTemplate {
void AppendAtomicInline(const ComputedStyle* = nullptr,
LayoutObject* = nullptr);
+ // Append floats and positioned objects in the same way as atomic inlines.
+ // Because these objects need positions, they will be handled in
+ // NGInlineLayoutAlgorithm.
+ void AppendFloating(LayoutObject* layout_object);
+ void AppendOutOfFlowPositioned(LayoutObject* layout_object);
+
// Append a character.
// The character is opaque to space collapsing; i.e., spaces before this
// character and after this character can collapse as if this character does
@@ -110,6 +116,8 @@ class NGInlineItemsBuilderTemplate {
void SetIsSymbolMarker(bool b);
+ bool ShouldAbort() const { return false; }
+
private:
static bool NeedsBoxInfo();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
index bdbc6558e00..86e7f2c619d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
@@ -14,6 +14,11 @@ namespace blink {
namespace {
+// The spec turned into a discussion that may change. Put this logic on hold
+// until CSSWG resolves the issue.
+// https://github.com/w3c/csswg-drafts/issues/337
+#define SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH 0
+
#define EXPECT_ITEM_OFFSET(item, type, start, end) \
EXPECT_EQ(type, (item).Type()); \
EXPECT_EQ(start, (item).StartOffset()); \
@@ -248,7 +253,7 @@ TEST_F(NGInlineItemsBuilderTest, CollapseZeroWidthSpaces) {
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text \n", u"\u200Btext"))
<< "Collapsible space before newline does not affect the result.";
- EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\u200B\n", u" text"))
+ EXPECT_EQ(String(u"text\u200B text"), TestAppend(u"text\u200B\n", u" text"))
<< "Collapsible space after newline is removed even when the "
"newline was removed.";
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\u200B ", u"\ntext"))
@@ -256,6 +261,12 @@ TEST_F(NGInlineItemsBuilderTest, CollapseZeroWidthSpaces) {
"a zero width space is collapsed to a zero width space.";
}
+TEST_F(NGInlineItemsBuilderTest, CollapseZeroWidthSpaceAndNewLineAtEnd) {
+ EXPECT_EQ(String(u"\u200B"), TestAppend(u"\u200B\n"));
+ EXPECT_EQ(NGInlineItem::kNotCollapsible, items_[0].EndCollapseType());
+}
+
+#if SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH
TEST_F(NGInlineItemsBuilderTest, CollapseEastAsianWidth) {
EXPECT_EQ(String(u"\u4E00\u4E00"), TestAppend(u"\u4E00\n\u4E00"))
<< "Newline is removed when both sides are Wide.";
@@ -271,6 +282,7 @@ TEST_F(NGInlineItemsBuilderTest, CollapseEastAsianWidth) {
<< "Newline at the beginning of elements is removed "
"when both sides are Wide.";
}
+#endif
TEST_F(NGInlineItemsBuilderTest, OpaqueToSpaceCollapsing) {
NGInlineItemsBuilder builder(&items_);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 87358fff774..13ed178672c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -35,60 +35,6 @@
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
namespace blink {
-namespace {
-
-// Represents a data struct that are needed for 'text-align' and justifications.
-struct NGLineAlign {
- STACK_ALLOCATED();
-
- public:
- NGLineAlign(const NGLineInfo&);
- NGLineAlign() = delete;
-
- // The space to align or justify. This includes trailing spaces if exists.
- LayoutUnit space;
-
- // The end offset with trailing spaces excluded.
- unsigned end_offset;
- LayoutUnit trailing_spaces_width;
-};
-
-NGLineAlign::NGLineAlign(const NGLineInfo& line_info) {
- // NGLineInfo::WidthForAlignment may return a negative value, as text-indent
- // can accept negative values. We need to use this un-clamped value for
- // alginment, instead of just NGLineInfo::Width.
- space = line_info.AvailableWidth() - line_info.WidthForAlignment();
-
- // Compute the end text offset of this line for the alignment purpose.
- // Trailing spaces are not part of the alignment space even when they are
- // preserved.
- const NGInlineItemResults& item_results = line_info.Results();
- for (auto it = item_results.rbegin(); it != item_results.rend(); ++it) {
- const NGInlineItemResult& item_result = *it;
-
- // If this item is opaque to whitespace collapsing, whitespace before this
- // item maybe collapsed. Keep looking for previous items.
- if (item_result.item && item_result.item->EndCollapseType() ==
- NGInlineItem::kOpaqueToCollapsing) {
- continue;
- }
-
- if (item_result.has_only_trailing_spaces) {
- trailing_spaces_width += item_result.inline_size;
- continue;
- }
-
- end_offset = item_result.end_offset;
- space += trailing_spaces_width;
- return;
- }
-
- // An empty line, or only trailing spaces.
- end_offset = line_info.StartOffset();
- space += trailing_spaces_width;
-}
-
-} // namespace
NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm(
NGInlineNode inline_node,
@@ -192,7 +138,7 @@ void NGInlineLayoutAlgorithm::RebuildBoxStates(
}
// Create box states for tags that are not closed yet.
- box_states->OnBeginPlaceItems(&line_info.LineStyle(), baseline_type_,
+ box_states->OnBeginPlaceItems(line_info.LineStyle(), baseline_type_,
quirks_mode_);
for (const NGInlineItem* item : open_items) {
NGInlineItemResult item_result;
@@ -207,7 +153,7 @@ void NGInlineLayoutAlgorithm::CheckBoxStates(
const NGInlineBreakToken* break_token) const {
NGInlineLayoutStateStack rebuilt;
RebuildBoxStates(line_info, break_token, &rebuilt);
- rebuilt.OnBeginPlaceItems(&line_info.LineStyle(), baseline_type_,
+ rebuilt.OnBeginPlaceItems(line_info.LineStyle(), baseline_type_,
quirks_mode_);
DCHECK(box_states_);
@@ -215,42 +161,40 @@ void NGInlineLayoutAlgorithm::CheckBoxStates(
}
#endif
-void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
- NGExclusionSpace* exclusion_space) {
+void NGInlineLayoutAlgorithm::CreateLine(
+ const NGLineLayoutOpportunity& opportunity,
+ NGLineInfo* line_info,
+ NGExclusionSpace* exclusion_space) {
// Needs MutableResults to move ShapeResult out of the NGLineInfo.
NGInlineItemResults* line_items = line_info->MutableResults();
line_box_.resize(0);
// Apply justification before placing items, because it affects size/position
// of items, which are needed to compute inline static positions.
- const ComputedStyle& line_style = line_info->LineStyle();
- ETextAlign text_align = line_style.GetTextAlign(line_info->IsLastLine());
- if (text_align == ETextAlign::kJustify) {
- if (!ApplyJustify(line_info))
- text_align = ETextAlign::kStart;
- }
-
- NGLineHeightMetrics line_metrics(line_style, baseline_type_);
- NGLineHeightMetrics line_metrics_with_leading = line_metrics;
- line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed());
+ LayoutUnit line_offset_for_text_align = ApplyTextAlign(line_info);
NGTextFragmentBuilder text_builder(Node(),
ConstraintSpace().GetWritingMode());
// Compute heights of all inline items by placing the dominant baseline at 0.
// The baseline is adjusted after the height of the line box is computed.
+ const ComputedStyle& line_style = line_info->LineStyle();
box_states_->SetIsEmptyLine(line_info->IsEmptyLine());
NGInlineBoxState* box =
- box_states_->OnBeginPlaceItems(&line_style, baseline_type_, quirks_mode_);
+ box_states_->OnBeginPlaceItems(line_style, baseline_type_, quirks_mode_);
#if DCHECK_IS_ON()
if (is_box_states_from_context_)
CheckBoxStates(*line_info, BreakToken());
#endif
- // In order to match other browsers when list-style-type: none, pretend
- // there's an invisible marker here.
- if (line_style.Display() == EDisplay::kListItem &&
- line_style.ListStyleType() == EListStyleType::kNone)
+ bool has_out_of_flow_positioned_items = false;
+ bool has_floating_items = false;
+
+ // List items trigger strict line height, i.e. we make room for the line box
+ // strut, for *every* line. This matches other browsers. The intention may
+ // have been to make sure that there's always room for the list item marker,
+ // but that doesn't explain why it's done for every line...
+ if (quirks_mode_ && line_style.Display() == EDisplay::kListItem)
box->ComputeTextMetrics(line_style, baseline_type_);
for (NGInlineItemResult& item_result : *line_items) {
@@ -293,10 +237,25 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
} else if (item.Type() == NGInlineItem::kListMarker) {
PlaceListMarker(item, &item_result, *line_info);
} else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) {
- line_box_.AddChild(
- item.GetLayoutObject(),
- box_states_->ContainingLayoutObjectForAbsolutePositionObjects(),
- item.BidiLevel());
+ // An inline-level OOF child positions itself based on its direction, a
+ // block-level OOF child positions itself based on the direction of its
+ // block-level container.
+ TextDirection direction =
+ item.GetLayoutObject()->StyleRef().IsOriginalDisplayInlineType()
+ ? item.Direction()
+ : ConstraintSpace().Direction();
+
+ line_box_.AddChild(item.GetLayoutObject(), item.BidiLevel(), direction);
+ has_out_of_flow_positioned_items = true;
+ } else if (item.Type() == NGInlineItem::kFloating) {
+ if (item_result.positioned_float) {
+ line_box_.AddChild(
+ std::move(item_result.positioned_float->layout_result),
+ item_result.positioned_float->bfc_offset, item.BidiLevel());
+ } else {
+ line_box_.AddChild(item.GetLayoutObject(), item.BidiLevel());
+ }
+ has_floating_items = true;
} else if (item.Type() == NGInlineItem::kBidiControl) {
line_box_.AddChild(item.BidiLevel());
}
@@ -329,37 +288,52 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
// always positive or 0.
inline_size = inline_size.ClampNegativeToZero();
- // Create box fragmetns if needed. After this point forward, |line_box_| is a
- // tree structure.
- if (box_states_->HasBoxFragments())
- box_states_->CreateBoxFragments(&line_box_);
-
- // Update item index of the box states in the context.
- context_->SetItemIndex(line_info->ItemsData().items,
- line_info->EndItemIndex());
-
- const NGLineHeightMetrics& line_box_metrics =
- box_states_->LineBoxState().metrics;
-
// Other 'text-align' values than 'justify' move line boxes as a whole, but
// indivisual items do not change their relative position to the line box.
- LayoutUnit bfc_line_offset = line_info->BfcOffset().line_offset;
- if (text_align != ETextAlign::kJustify)
- bfc_line_offset += OffsetForTextAlign(*line_info, text_align);
+ LayoutUnit bfc_line_offset =
+ line_info->BfcOffset().line_offset + line_offset_for_text_align;
if (IsLtr(line_info->BaseDirection()))
bfc_line_offset += line_info->TextIndent();
container_builder_.SetBfcLineOffset(bfc_line_offset);
- // Handle out-of-flow positioned objects. They need inline offsets for their
- // static positions.
- PlaceOutOfFlowObjects(*line_info, line_box_metrics, inline_size);
+ const NGLineHeightMetrics& line_box_metrics =
+ box_states_->LineBoxState().metrics;
+
+ // Place out-of-flow positioned objects.
+ // This adjusts the NGLineBoxFragmentBuilder::Child::offset member to contain
+ // the static position of the OOF positioned children relative to the linebox.
+ if (has_out_of_flow_positioned_items)
+ PlaceOutOfFlowObjects(*line_info, line_box_metrics);
+
+ // Place floating objects.
+ // This adjusts the NGLineBoxFragmentBuilder::Child::offset member to
+ // contain the position of the float relative to the linebox.
+ // Additionally it will perform layout on any unpositioned floats which
+ // needed the line height to correctly determine their final position.
+ if (has_floating_items) {
+ PlaceFloatingObjects(*line_info, line_box_metrics, opportunity,
+ exclusion_space);
+ }
+
+ // Create box fragments if needed. After this point forward, |line_box_| is a
+ // tree structure.
+ // The individual children don't move position within the |line_box_|, rather
+ // the children have their layout_result, fragment, (or similar) set to null,
+ // creating a "hole" in the array.
+ if (box_states_->HasBoxFragments())
+ box_states_->CreateBoxFragments(&line_box_);
+
+ // Update item index of the box states in the context.
+ context_->SetItemIndex(line_info->ItemsData().items,
+ line_info->EndItemIndex());
// Even if we have something in-flow, it may just be empty items that
// shouldn't trigger creation of a line. Exit now if that's the case.
if (line_info->IsEmptyLine()) {
container_builder_.SetIsEmptyLineBox();
+ container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.AddChildren(line_box_);
return;
}
@@ -373,9 +347,9 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
if (line_info->UseFirstLineStyle())
container_builder_.SetStyleVariant(NGStyleVariant::kFirstLine);
+ container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.AddChildren(line_box_);
container_builder_.SetInlineSize(inline_size);
- container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.SetMetrics(line_box_metrics);
container_builder_.SetBfcBlockOffset(line_info->BfcOffset().block_offset);
}
@@ -490,56 +464,131 @@ void NGInlineLayoutAlgorithm::PlaceLayoutResult(NGInlineItemResult* item_result,
item_result->inline_size, item.BidiLevel());
}
-// Place all out-of-flow objects in |line_box_| and clear them.
-// @return whether |line_box_| has any in-flow fragments.
+// Place all out-of-flow objects in |line_box_|.
void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects(
const NGLineInfo& line_info,
- const NGLineHeightMetrics& line_box_metrics,
- LayoutUnit inline_size) {
- TextDirection line_direction = line_info.BaseDirection();
+ const NGLineHeightMetrics& line_box_metrics) {
+ DCHECK(line_info.IsEmptyLine() || !line_box_metrics.IsEmpty())
+ << "Non-empty lines must have a valid set of linebox metrics.";
+
+ // All children within the linebox are positioned relative to the baseline,
+ // then shifted later using NGLineBoxFragmentBuilder::MoveInBlockDirection.
+ LayoutUnit baseline_adjustment =
+ line_info.IsEmptyLine() ? LayoutUnit() : -line_box_metrics.ascent;
+
+ LayoutUnit line_height =
+ line_info.IsEmptyLine() ? LayoutUnit() : line_box_metrics.LineHeight();
+
+ // The location of the "next" line.
+ //
+ // This uses NGConstraintSpace::Direction rather than
+ // NGLineInfo::BaseDirection as this is for a block-level object rather than
+ // an inline-level object.
+ //
+ // Similarly this uses the available size to determine which edge to align
+ // to, and *does not* avoid floats.
+ LayoutUnit block_level_line_location =
+ IsLtr(ConstraintSpace().Direction())
+ ? LayoutUnit()
+ : ConstraintSpace().AvailableSize().inline_size;
+
+ // This offset represents the position of the "next" line, relative to the
+ // line we are currently creating, (this takes into account text-indent, etc).
+ LayoutUnit block_level_inline_offset =
+ block_level_line_location - (container_builder_.BfcLineOffset() -
+ ConstraintSpace().BfcOffset().line_offset);
+
+ // To correctly determine which "line" block-level out-of-flow positioned
+ // object is placed on, we need to keep track of if there is any inline-level
+ // content preceeding it.
+ bool has_preceeding_inline_level_content = false;
for (NGLineBoxFragmentBuilder::Child& child : line_box_) {
+ has_preceeding_inline_level_content |= child.HasInFlowFragment();
+
LayoutObject* box = child.out_of_flow_positioned_box;
if (!box)
continue;
- // The static position is at the line-top. Ignore the block_offset.
- NGLogicalOffset static_offset(child.offset.inline_offset, LayoutUnit());
+ NGLogicalOffset static_offset(LayoutUnit(), baseline_adjustment);
+ if (box->StyleRef().IsOriginalDisplayInlineType()) {
+ // An inline-level OOF element positions itself within the line, at the
+ // position it would have been if it was in-flow.
+ static_offset.inline_offset = child.offset.inline_offset;
+ } else {
+ // A block-level OOF element positions itself on the "next" line. However
+ // only shifts down if there is inline-level content.
+ static_offset.inline_offset = block_level_inline_offset;
+ if (has_preceeding_inline_level_content)
+ static_offset.block_offset += line_height;
+ }
- // If a block-level box appears in the middle of a line, move the static
- // position to where the next block will be placed.
- if (!box->StyleRef().IsOriginalDisplayInlineType()) {
- LayoutUnit inline_offset = container_builder_.BfcLineOffset() -
- ConstraintSpace().BfcOffset().line_offset;
+ child.offset = static_offset;
+ }
+}
- // Flip the inline_offset if we are in RTL.
- if (IsRtl(line_direction)) {
- LayoutUnit container_inline_size =
- ConstraintSpace().AvailableSize().inline_size;
- inline_offset = container_inline_size - inline_offset + inline_size;
- }
+void NGInlineLayoutAlgorithm::PlaceFloatingObjects(
+ const NGLineInfo& line_info,
+ const NGLineHeightMetrics& line_box_metrics,
+ const NGLineLayoutOpportunity& opportunity,
+ NGExclusionSpace* exclusion_space) {
+ DCHECK(line_info.IsEmptyLine() || !line_box_metrics.IsEmpty())
+ << "Non-empty lines must have a valid set of linebox metrics.";
+
+ // All children within the linebox are positioned relative to the baseline,
+ // then shifted later using NGLineBoxFragmentBuilder::MoveInBlockDirection.
+ LayoutUnit baseline_adjustment =
+ line_info.IsEmptyLine() ? LayoutUnit() : -line_box_metrics.ascent;
+
+ LayoutUnit line_height =
+ line_info.IsEmptyLine() ? LayoutUnit() : line_box_metrics.LineHeight();
+
+ // Any unpositioned floats we encounter need to be placed on the "next" line.
+ // This BFC block-offset represents the start of the "next" line.
+ LayoutUnit origin_bfc_block_offset =
+ opportunity.bfc_block_offset + line_height;
- inline_offset += line_info.TextIndent();
+ bool is_empty_inline = Node().IsEmptyInline();
+
+ LayoutUnit bfc_block_offset = line_info.BfcOffset().block_offset;
+ if (is_empty_inline && ConstraintSpace().FloatsBfcBlockOffset()) {
+ bfc_block_offset = *ConstraintSpace().FloatsBfcBlockOffset();
+ }
- // We need to subtract the line offset, in order to ignore floats and
- // text-indent.
- static_offset.inline_offset = -inline_offset;
+ LayoutUnit bfc_line_offset = container_builder_.BfcLineOffset();
- if (child.offset.inline_offset && !line_box_metrics.IsEmpty())
- static_offset.block_offset = line_box_metrics.LineHeight();
- } else if (IsRtl(line_direction)) {
- // Our child offset is line-relative, but the static offset is
- // flow-relative, using the direction we give to
- // |AddInlineOutOfFlowChildCandidate|.
- static_offset.inline_offset = inline_size - static_offset.inline_offset;
+ for (NGLineBoxFragmentBuilder::Child& child : line_box_) {
+ // We need to position any floats which should be on the "next" line now.
+ // If this is an empty inline, all floats are positioned during the
+ // PositionLeadingFloats step.
+ if (child.unpositioned_float && !is_empty_inline) {
+ NGPositionedFloat positioned_float = PositionFloat(
+ origin_bfc_block_offset, child.unpositioned_float, exclusion_space);
+
+ child.layout_result = std::move(positioned_float.layout_result);
+ child.bfc_offset = positioned_float.bfc_offset;
+ child.unpositioned_float = nullptr;
}
- container_builder_.AddInlineOutOfFlowChildCandidate(
- NGBlockNode(ToLayoutBox(box)), static_offset, line_direction,
- child.out_of_flow_containing_box);
+ // Skip any children which aren't positioned floats.
+ if (!child.layout_result ||
+ !child.layout_result->PhysicalFragment()->IsFloating())
+ continue;
+
+ LayoutUnit block_offset =
+ child.bfc_offset.block_offset - bfc_block_offset + baseline_adjustment;
+
+ // We need to manually account for the flipped-lines writing mode here :(.
+ if (IsFlippedLinesWritingMode(ConstraintSpace().GetWritingMode())) {
+ NGFragment fragment(
+ ConstraintSpace().GetWritingMode(),
+ ToNGPhysicalBoxFragment(*child.layout_result->PhysicalFragment()));
- child.out_of_flow_positioned_box = nullptr;
- child.out_of_flow_containing_box = nullptr;
+ block_offset = -fragment.BlockSize() - block_offset;
+ }
+
+ child.offset = {child.bfc_offset.line_offset - bfc_line_offset,
+ block_offset};
}
}
@@ -558,27 +607,39 @@ void NGInlineLayoutAlgorithm::PlaceListMarker(const NGInlineItem& item,
// Justify the line. This changes the size of items by adding spacing.
// Returns false if justification failed and should fall back to start-aligned.
-bool NGInlineLayoutAlgorithm::ApplyJustify(NGLineInfo* line_info) {
- NGLineAlign align(*line_info);
- if (align.space <= 0)
- return false; // no expansion is needed.
+bool NGInlineLayoutAlgorithm::ApplyJustify(LayoutUnit space,
+ NGLineInfo* line_info) {
+ // Empty lines should align to start.
+ if (line_info->IsEmptyLine())
+ return false;
+
+ // Justify the end of visible text, ignoring preserved trailing spaces.
+ unsigned end_offset;
+ LayoutUnit trailing_spaces_width =
+ line_info->ComputeTrailingSpaceWidth(&end_offset);
+ space += trailing_spaces_width;
+
+ // If this line overflows, fallback to 'text-align: start'.
+ if (space <= 0)
+ return false;
// Construct the line text to compute spacing for.
String line_text =
StringView(line_info->ItemsData().text_content, line_info->StartOffset(),
- align.end_offset - line_info->StartOffset())
+ end_offset - line_info->StartOffset())
.ToString();
// Append a hyphen if the last word is hyphenated. The hyphen is in
// |ShapeResult|, but not in text. |ShapeResultSpacing| needs the text that
// matches to the |ShapeResult|.
+ DCHECK(!line_info->Results().IsEmpty());
const NGInlineItemResult& last_item_result = line_info->Results().back();
if (last_item_result.text_end_effect == NGTextEndEffect::kHyphen)
line_text.append(last_item_result.item->Style()->HyphenString());
// Compute the spacing to justify.
ShapeResultSpacing<String> spacing(line_text);
- spacing.SetExpansion(align.space, line_info->BaseDirection(),
+ spacing.SetExpansion(space, line_info->BaseDirection(),
line_info->LineStyle().GetTextJustify());
if (!spacing.HasExpansion())
return false; // no expansion opportunities exist.
@@ -614,16 +675,28 @@ bool NGInlineLayoutAlgorithm::ApplyJustify(NGLineInfo* line_info) {
return true;
}
-// Compute the offset to shift the line box for the 'text-align' property.
-LayoutUnit NGInlineLayoutAlgorithm::OffsetForTextAlign(
- const NGLineInfo& line_info,
- ETextAlign text_align) const {
- // Justification is applied in earlier phase, see PlaceItems().
- DCHECK_NE(text_align, ETextAlign::kJustify);
+// Apply the 'text-align' property to |line_info|. Returns the amount to move
+// the line in the inline direction.
+LayoutUnit NGInlineLayoutAlgorithm::ApplyTextAlign(NGLineInfo* line_info) {
+ // NGLineInfo::WidthForAlignment may return a negative value, as text-indent
+ // can accept negative values. We need to use this un-clamped value for
+ // alginment, instead of just NGLineInfo::Width.
+ LayoutUnit space =
+ line_info->AvailableWidth() - line_info->WidthForAlignment();
- NGLineAlign align(line_info);
- return LineOffsetForTextAlign(text_align, line_info.BaseDirection(),
- align.space, align.trailing_spaces_width);
+ const ComputedStyle& line_style = line_info->LineStyle();
+ ETextAlign text_align = line_style.GetTextAlign(line_info->IsLastLine());
+ if (text_align == ETextAlign::kJustify) {
+ // If justification succeeds, no offset is needed. Expansions are set to
+ // each |NGInlineItemResult| in |line_info|.
+ if (ApplyJustify(space, line_info))
+ return LayoutUnit();
+
+ // If justification fails, fallback to 'text-align: start'.
+ text_align = ETextAlign::kStart;
+ }
+
+ return LineOffsetForTextAlign(text_align, line_info->BaseDirection(), space);
}
LayoutUnit NGInlineLayoutAlgorithm::ComputeContentSize(
@@ -681,19 +754,16 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
} else {
DCHECK(ConstraintSpace().MarginStrut().IsEmpty());
- // We need to pre-emptively set the BFC block offset in order for leading
- // floats to be positioned correctly.
- container_builder_.SetBfcBlockOffset(
- ConstraintSpace().BfcOffset().block_offset);
-
// The BFC block offset was determined before entering this algorithm. This
// means that there should be no adjoining floats.
DCHECK(!ConstraintSpace().AdjoiningFloatTypes());
}
// In order to get the correct list of layout opportunities, we need to
- // position any "leading" items (floats) within the exclusion space first.
- unsigned handled_item_index = PositionLeadingFloats(&initial_exclusion_space);
+ // position any "leading" floats within the exclusion space first.
+ NGPositionedFloatVector leading_floats;
+ unsigned handled_leading_floats_index =
+ PositionLeadingFloats(&initial_exclusion_space, &leading_floats);
// We query all the layout opportunities on the initial exclusion space up
// front, as if the line breaker may add floats and change the opportunities.
@@ -702,10 +772,6 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
ConstraintSpace().BfcOffset(),
ConstraintSpace().AvailableSize().inline_size);
- Vector<NGPositionedFloat> positioned_floats;
- // We shouldn't have any unpositioned floats if we aren't empty.
- DCHECK(unpositioned_floats_.IsEmpty() || is_empty_inline);
-
NGExclusionSpace exclusion_space;
const NGInlineBreakToken* break_token = BreakToken();
@@ -734,8 +800,6 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
#endif
// Reset any state that may have been modified in a previous pass.
- positioned_floats.Shrink(0);
- unpositioned_floats_.Shrink(0);
container_builder_.Reset();
exclusion_space = initial_exclusion_space;
@@ -744,16 +808,16 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
line_block_size, block_delta);
NGLineInfo line_info;
- NGLineBreaker line_breaker(
- Node(), NGLineBreakerMode::kContent, constraint_space_,
- &positioned_floats, &unpositioned_floats_, &container_builder_,
- &exclusion_space, handled_item_index, line_opportunity, break_token);
+ NGLineBreaker line_breaker(Node(), NGLineBreakerMode::kContent,
+ constraint_space_, line_opportunity,
+ leading_floats, handled_leading_floats_index,
+ break_token, &exclusion_space);
line_breaker.NextLine(&line_info);
// If this fragment will be larger than the inline-size of the opportunity,
// *and* the opportunity is smaller than the available inline-size, and the
// container autowraps, continue to the next opportunity.
- if (line_info.Width() > line_opportunity.AvailableInlineSize() &&
+ if (line_info.HasOverflow() &&
ConstraintSpace().AvailableSize().inline_size !=
line_opportunity.AvailableFloatInlineSize() &&
Node().Style().AutoWrap()) {
@@ -775,7 +839,7 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
}
PrepareBoxStates(line_info, break_token);
- CreateLine(&line_info, &exclusion_space);
+ CreateLine(line_opportunity, &line_info, &exclusion_space);
// We now can check the block-size of the fragment, and it fits within the
// opportunity.
@@ -819,15 +883,11 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
container_builder_.SetIsPushedByFloats();
// Success!
- positioned_floats_.AppendVector(positioned_floats);
container_builder_.SetBreakToken(line_breaker.CreateBreakToken(line_info));
if (is_empty_inline) {
DCHECK_EQ(container_builder_.BlockSize(), 0);
} else {
- // Place any remaining floats which couldn't fit on the line.
- PositionPendingFloats(line_height, &exclusion_space);
-
// A <br clear=both> will strech the line-box height, such that the
// block-end edge will clear any floats.
// TODO(ikilpatrick): Move this into ng_block_layout_algorithm.
@@ -837,9 +897,6 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
break;
}
- // We shouldn't have any unpositioned floats if we aren't empty.
- DCHECK(unpositioned_floats_.IsEmpty() || is_empty_inline);
- container_builder_.SwapPositionedFloats(&positioned_floats_);
container_builder_.SetExclusionSpace(std::move(exclusion_space));
container_builder_.MoveOutOfFlowDescendantCandidatesToDescendants();
return container_builder_.ToLineBoxFragment();
@@ -848,64 +905,64 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// This positions any "leading" floats within the given exclusion space.
// If we are also an empty inline, it will add any out-of-flow descendants.
unsigned NGInlineLayoutAlgorithm::PositionLeadingFloats(
- NGExclusionSpace* exclusion_space) {
- const Vector<NGInlineItem>& items = Node().ItemsData(false).items;
+ NGExclusionSpace* exclusion_space,
+ NGPositionedFloatVector* positioned_floats) {
+ bool is_empty_inline = Node().IsEmptyInline();
+ bool should_ignore_floats = BreakToken() && BreakToken()->IgnoreFloats();
+
+ const Vector<NGInlineItem>& items =
+ Node().ItemsData(/* is_first_line */ false).items;
unsigned index = BreakToken() ? BreakToken()->ItemIndex() : 0;
for (; index < items.size(); ++index) {
const NGInlineItem& item = items[index];
- if (item.Type() == NGInlineItem::kFloating) {
- NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
-
- AddUnpositionedFloat(&unpositioned_floats_, &container_builder_,
- NGUnpositionedFloat(node, /* break_token */ nullptr),
- ConstraintSpace());
- }
-
// Abort if we've found something that makes this a non-empty inline.
if (!item.IsEmptyItem()) {
- DCHECK(!Node().IsEmptyInline());
+ DCHECK(!is_empty_inline);
break;
}
- }
- if (container_builder_.BfcBlockOffset() ||
- ConstraintSpace().FloatsBfcBlockOffset())
- PositionPendingFloats(/* content_size */ LayoutUnit(), exclusion_space);
+ if (item.Type() != NGInlineItem::kFloating || should_ignore_floats)
+ continue;
- return index;
-}
+ container_builder_.AddAdjoiningFloatTypes(
+ ResolvedFloating(item.GetLayoutObject()->StyleRef().Floating(),
+ ConstraintSpace().Direction()) == EFloat::kLeft
+ ? kFloatTypeLeft
+ : kFloatTypeRight);
+
+ // If we are an empty inline, and don't have the special floats BFC
+ // block-offset yet, there is no way to position any floats.
+ if (is_empty_inline && !ConstraintSpace().FloatsBfcBlockOffset())
+ continue;
-void NGInlineLayoutAlgorithm::PositionPendingFloats(
- LayoutUnit content_size,
- NGExclusionSpace* exclusion_space) {
- DCHECK(container_builder_.BfcBlockOffset() ||
- ConstraintSpace().FloatsBfcBlockOffset())
- << "The floats BFC block offset should be known here";
+ LayoutUnit origin_bfc_block_offset =
+ is_empty_inline ? ConstraintSpace().FloatsBfcBlockOffset().value()
+ : ConstraintSpace().BfcOffset().block_offset;
- if (BreakToken() && BreakToken()->IgnoreFloats()) {
- unpositioned_floats_.Shrink(0);
- return;
+ NGPositionedFloat positioned_float = PositionFloat(
+ origin_bfc_block_offset, item.GetLayoutObject(), exclusion_space);
+ positioned_floats->push_back(std::move(positioned_float));
}
- LayoutUnit bfc_block_offset =
- container_builder_.BfcBlockOffset()
- ? container_builder_.BfcBlockOffset().value()
- : ConstraintSpace().FloatsBfcBlockOffset().value();
-
- NGBfcOffset origin_bfc_offset = {ConstraintSpace().BfcOffset().line_offset,
- bfc_block_offset + content_size};
+ return index;
+}
- NGPositionedFloatVector positioned_floats;
- PositionFloats(ConstraintSpace().AvailableSize(),
- ConstraintSpace().PercentageResolutionSize(),
- ConstraintSpace().ReplacedPercentageResolutionSize(),
- origin_bfc_offset, unpositioned_floats_, ConstraintSpace(),
- Style(), exclusion_space, &positioned_floats);
+NGPositionedFloat NGInlineLayoutAlgorithm::PositionFloat(
+ LayoutUnit origin_bfc_block_offset,
+ LayoutObject* floating_object,
+ NGExclusionSpace* exclusion_space) const {
+ NGUnpositionedFloat unpositioned_float(
+ NGBlockNode(ToLayoutBox(floating_object)), /* break_token */ nullptr);
- positioned_floats_.AppendVector(positioned_floats);
- unpositioned_floats_.Shrink(0);
+ NGBfcOffset origin_bfc_offset = {ConstraintSpace().BfcOffset().line_offset,
+ origin_bfc_block_offset};
+ return ::blink::PositionFloat(
+ ConstraintSpace().AvailableSize(),
+ ConstraintSpace().PercentageResolutionSize(),
+ ConstraintSpace().ReplacedPercentageResolutionSize(), origin_bfc_offset,
+ &unpositioned_float, ConstraintSpace(), Style(), exclusion_space);
}
void NGInlineLayoutAlgorithm::BidiReorder() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
index a65f542436a..5b945065bb4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h"
#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -28,7 +27,6 @@ class NGInlineLayoutStateStack;
class NGLineInfo;
struct NGInlineBoxState;
struct NGInlineItemResult;
-struct NGPositionedFloat;
// A class for laying out an inline formatting context, i.e. a block with inline
// children.
@@ -47,14 +45,17 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
NGInlineChildLayoutContext* context);
~NGInlineLayoutAlgorithm() override;
- void CreateLine(NGLineInfo*, NGExclusionSpace*);
+ void CreateLine(const NGLineLayoutOpportunity&,
+ NGLineInfo*,
+ NGExclusionSpace*);
scoped_refptr<NGLayoutResult> Layout() override;
private:
- unsigned PositionLeadingFloats(NGExclusionSpace*);
-
- void PositionPendingFloats(LayoutUnit content_size, NGExclusionSpace*);
+ unsigned PositionLeadingFloats(NGExclusionSpace*, NGPositionedFloatVector*);
+ NGPositionedFloat PositionFloat(LayoutUnit origin_block_bfc_offset,
+ LayoutObject* floating_object,
+ NGExclusionSpace*) const;
bool IsHorizontalWritingMode() const { return is_horizontal_writing_mode_; }
@@ -88,15 +89,17 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
void PlaceLayoutResult(NGInlineItemResult*,
NGInlineBoxState*,
LayoutUnit inline_offset = LayoutUnit());
- void PlaceOutOfFlowObjects(const NGLineInfo&,
- const NGLineHeightMetrics&,
- LayoutUnit inline_size);
+ void PlaceOutOfFlowObjects(const NGLineInfo&, const NGLineHeightMetrics&);
+ void PlaceFloatingObjects(const NGLineInfo&,
+ const NGLineHeightMetrics&,
+ const NGLineLayoutOpportunity&,
+ NGExclusionSpace*);
void PlaceListMarker(const NGInlineItem&,
NGInlineItemResult*,
const NGLineInfo&);
- LayoutUnit OffsetForTextAlign(const NGLineInfo&, ETextAlign) const;
- bool ApplyJustify(NGLineInfo*);
+ LayoutUnit ApplyTextAlign(NGLineInfo*);
+ bool ApplyJustify(LayoutUnit space, NGLineInfo*);
LayoutUnit ComputeContentSize(const NGLineInfo&,
const NGExclusionSpace&,
@@ -111,9 +114,6 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
unsigned is_horizontal_writing_mode_ : 1;
unsigned quirks_mode_ : 1;
- Vector<NGPositionedFloat> positioned_floats_;
- NGUnpositionedFloatVector unpositioned_floats_;
-
#if DCHECK_IS_ON()
// True if |box_states_| is taken from |context_|, to check the |box_states_|
// is the same as when it is rebuilt.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
index 4585f67824a..49193ed3b40 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -361,8 +361,8 @@ TEST_F(NGInlineLayoutAlgorithmTest, TextFloatsAroundInlineFloatThatFitsOnLine) {
const NGPhysicalBoxFragment* block_box = block_flow->CurrentFragment();
ASSERT_TRUE(block_box);
- // float plus two lines.
- EXPECT_EQ(3u, block_box->Children().size());
+ // Two lines.
+ EXPECT_EQ(2u, block_box->Children().size());
NGPhysicalOffset first_line_offset = block_box->Children()[1].Offset();
// 30 == narrow-float's width.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index a9ee04102d0..4154e5f1c01 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/layout/logical_values.h"
#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_bidi_paragraph.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h"
@@ -81,6 +82,112 @@ void ClearNeedsLayout(LayoutObject* object) {
ToLayoutText(object)->ClearInlineItems();
}
+// This class marks appropriate line box fragments as dirty.
+//
+// |CollectInlinesInternal| calls this class when traversing the LayoutObject
+// tree in pre-order DFS
+class NGLineBoxMarker {
+ STACK_ALLOCATED();
+
+ public:
+ NGLineBoxMarker(NGPaintFragment* block_fragment)
+ : block_fragment_(block_fragment) {
+ DCHECK(block_fragment_);
+ }
+
+ bool HandleText(LayoutText* layout_text) {
+ if (layout_text->SelfNeedsLayout())
+ return Mark();
+ return UpdateLastFragment(layout_text->FirstInlineFragment());
+ }
+
+ bool HandleInlineBox(LayoutInline* layout_inline) {
+ if (layout_inline->SelfNeedsLayout())
+ return Mark();
+
+ // Do not keep fragments of LayoutInline unless it's a leaf, because
+ // the last fragment of LayoutInline is not the previous fragment of its
+ // descendants.
+ if (layout_inline->FirstChild())
+ return false;
+ return UpdateLastFragment(layout_inline->FirstInlineFragment());
+ }
+
+ bool HandleAtomicInline(LayoutBox* layout_box) {
+ if (layout_box->NeedsLayout())
+ return Mark();
+ return UpdateLastFragment(layout_box->FirstInlineFragment());
+ }
+
+ private:
+ bool Mark() {
+ if (last_fragment_) {
+ // Changes in this LayoutObject may affect the line that contains its
+ // previous object. Mark the line box that contains the last fragment
+ // of the previous object.
+ last_fragment_->LastForSameLayoutObject()->MarkContainingLineBoxDirty();
+ } else {
+ // If there were no fragments so far in this pre-order traversal, mark
+ // the first line box dirty.
+ DCHECK(block_fragment_);
+ if (NGPaintFragment* first_line = block_fragment_->FirstLineBox())
+ first_line->MarkLineBoxDirty();
+ }
+ return true;
+ }
+
+ bool UpdateLastFragment(NGPaintFragment* fragment) {
+ if (fragment)
+ last_fragment_ = fragment;
+ return false;
+ }
+
+ NGPaintFragment* block_fragment_;
+ NGPaintFragment* last_fragment_ = nullptr;
+};
+
+// This class has the same interface as NGInlineItemsBuilder but does nothing
+// except tracking if floating or out-of-flow objects are added.
+//
+// |MarkLineBoxesDirty| uses this class to traverse tree without buildling
+// |NGInlineItem|.
+class ItemsBuilderForMarkLineBoxesDirty {
+ public:
+ void Append(const String&, const ComputedStyle*, LayoutText*) {}
+ bool Append(const String&, LayoutText*) { return false; }
+ void AppendOpaque(NGInlineItem::NGInlineItemType,
+ const ComputedStyle*,
+ LayoutObject*) {}
+ void AppendBreakOpportunity(const ComputedStyle*, LayoutObject*) {}
+ void AppendAtomicInline(const ComputedStyle*, LayoutObject*) {}
+ void AppendFloating(LayoutObject*) {
+ has_floating_or_out_of_flow_positioned_ = true;
+ }
+ void AppendOutOfFlowPositioned(LayoutObject*) {
+ has_floating_or_out_of_flow_positioned_ = true;
+ }
+ void SetIsSymbolMarker(bool) {}
+ void EnterBlock(const ComputedStyle*) {}
+ void ExitBlock() {}
+ void EnterInline(LayoutObject*) {}
+ void ExitInline(LayoutObject*) {}
+
+ bool ShouldAbort() const {
+ // Aborting in the middle of the traversal is safe because this function
+ // ClearNeedsLayout() on text and LayoutInline, but since an inline
+ // formatting context is laid out as a whole, these flags don't matter.
+ // For that reason, the traversal should not ClearNeedsLayout() atomic
+ // inlines, floats, or OOF -- objects that need to be laid out separately
+ // from the inline formatting context.
+ // TODO(kojii): This looks a bit tricky, better to come up with clearner
+ // solution if any.
+ return has_floating_or_out_of_flow_positioned_;
+ }
+
+ private:
+ bool has_floating_or_out_of_flow_positioned_ = false;
+};
+
// The function is templated to indicate the purpose of collected inlines:
// - With EmptyOffsetMappingBuilder: updating layout;
// - With NGOffsetMappingBuilder: building offset mapping on clean layout.
@@ -91,21 +198,19 @@ void ClearNeedsLayout(LayoutObject* object) {
//
// There are also performance considerations, since template saves the overhead
// for condition checking and branching.
-template <typename OffsetMappingBuilder>
-void CollectInlinesInternal(
- LayoutBlockFlow* block,
- NGInlineItemsBuilderTemplate<OffsetMappingBuilder>* builder,
- String* previous_text,
- bool update_layout) {
+template <typename ItemsBuilder>
+void CollectInlinesInternal(LayoutBlockFlow* block,
+ ItemsBuilder* builder,
+ String* previous_text,
+ NGLineBoxMarker* marker,
+ bool update_layout) {
builder->EnterBlock(block->Style());
LayoutObject* node = GetLayoutObjectForFirstChildNode(block);
const LayoutObject* symbol =
LayoutNGListItem::FindSymbolMarkerLayoutText(block);
while (node) {
- if (node->IsText()) {
- LayoutText* layout_text = ToLayoutText(node);
-
+ if (LayoutText* layout_text = ToLayoutTextOrNull(node)) {
// If the LayoutText element hasn't changed, reuse the existing items.
// if the last ended with space and this starts with space, do not allow
@@ -125,22 +230,30 @@ void CollectInlinesInternal(
if (symbol == layout_text)
builder->SetIsSymbolMarker(true);
+ if (marker && marker->HandleText(layout_text))
+ marker = nullptr;
+
if (update_layout)
ClearNeedsLayout(layout_text);
} else if (node->IsFloating()) {
- // Add floats and positioned objects in the same way as atomic inlines.
- // Because these objects need positions, they will be handled in
- // NGInlineLayoutAlgorithm.
- builder->AppendOpaque(NGInlineItem::kFloating,
- kObjectReplacementCharacter, nullptr, node);
+ builder->AppendFloating(node);
+ if (builder->ShouldAbort())
+ return;
+
+ if (update_layout)
+ ClearInlineFragment(node);
} else if (node->IsOutOfFlowPositioned()) {
- builder->AppendOpaque(NGInlineItem::kOutOfFlowPositioned,
- kObjectReplacementCharacter, nullptr, node);
+ builder->AppendOutOfFlowPositioned(node);
+ if (builder->ShouldAbort())
+ return;
+
+ if (update_layout)
+ ClearInlineFragment(node);
} else if (node->IsAtomicInlineLevel()) {
- if (node->IsLayoutNGListMarker()) {
+ if (node->IsLayoutNGListMarker() || node->IsListMarker()) {
// LayoutNGListItem produces the 'outside' list marker as an inline
// block. This is an out-of-flow item whose position is computed
// automatically.
@@ -151,6 +264,9 @@ void CollectInlinesInternal(
// algorithm.
builder->AppendAtomicInline(node->Style(), node);
+ if (marker && marker->HandleAtomicInline(ToLayoutBox(node)))
+ marker = nullptr;
+
if (update_layout)
ClearInlineFragment(node);
}
@@ -166,6 +282,9 @@ void CollectInlinesInternal(
builder->EnterInline(layout_inline);
+ if (marker && marker->HandleInlineBox(layout_inline))
+ marker = nullptr;
+
// Traverse to children if they exist.
if (LayoutObject* child = layout_inline->FirstChild()) {
node = child;
@@ -228,6 +347,13 @@ void TruncateOrPadText(String* text, unsigned length) {
}
}
+template <typename OffsetMappingBuilder>
+bool MayBeBidiEnabled(
+ const String& text_content,
+ const NGInlineItemsBuilderTemplate<OffsetMappingBuilder>& builder) {
+ return !text_content.Is8Bit() || builder.HasBidiControls();
+}
+
} // namespace
NGInlineNode::NGInlineNode(LayoutBlockFlow* block)
@@ -310,21 +436,46 @@ void NGInlineNode::ComputeOffsetMapping(LayoutBlockFlow* layout_block_flow,
builder.GetOffsetMappingBuilder().ReserveCapacity(
EstimateOffsetMappingItemsCount(*layout_block_flow));
const bool update_layout = false;
- CollectInlinesInternal(layout_block_flow, &builder, nullptr, update_layout);
-
- // We need the text for non-NG object. Otherwise |data| already has the text
- // from the pre-layout phase, check they match.
- if (data->text_content.IsNull())
+ CollectInlinesInternal(layout_block_flow, &builder, nullptr, nullptr,
+ update_layout);
+
+ // For non-NG object, we need the text, and also the inline items to resolve
+ // bidi levels. Otherwise |data| already has the text from the pre-layout
+ // phase, check they match.
+ if (data->text_content.IsNull()) {
+ DCHECK(!layout_block_flow->IsLayoutNGMixin());
data->text_content = builder.ToString();
- else
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled()) {
+ // Set |is_bidi_enabled_| for all UTF-16 strings for now, because at this
+ // point the string may or may not contain RTL characters.
+ // |SegmentText()| will analyze the text and reset |is_bidi_enabled_| if
+ // it doesn't contain any RTL characters.
+ data->is_bidi_enabled_ = MayBeBidiEnabled(data->text_content, builder);
+ if (data->is_bidi_enabled_) {
+ // |builder| performs some validity checks with |items|, so we can't
+ // simply move them to |data|, but have to copy.
+ // TODO(xiaochengh): Change it into a move.
+ data->items = items;
+ SegmentBidiRunsInternal(data, layout_block_flow->StyleRef());
+ } else {
+ data->SetBaseDirection(TextDirection::kLtr);
+ }
+ }
+ } else {
+ DCHECK(layout_block_flow->IsLayoutNGMixin());
DCHECK_EQ(data->text_content, builder.ToString());
+ }
+
+ std::unique_ptr<NGCaretNavigator> caret_navigator;
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ caret_navigator = std::make_unique<NGCaretNavigator>(*data);
// TODO(xiaochengh): This doesn't compute offset mapping correctly when
// text-transform CSS property changes text length.
NGOffsetMappingBuilder& mapping_builder = builder.GetOffsetMappingBuilder();
mapping_builder.SetDestinationString(data->text_content);
- data->offset_mapping =
- std::make_unique<NGOffsetMapping>(mapping_builder.Build());
+ data->offset_mapping = std::make_unique<NGOffsetMapping>(
+ mapping_builder.Build(std::move(caret_navigator)));
DCHECK(data->offset_mapping);
}
@@ -346,6 +497,7 @@ const NGOffsetMapping* NGInlineNode::GetOffsetMapping(
// If this is not LayoutNG, compute the offset mapping and store in |storage|.
// The caller is responsible to keep |storage| for the life cycle.
+ DCHECK(storage);
NGInlineNodeData data;
ComputeOffsetMapping(layout_block_flow, &data);
*storage = std::move(data.offset_mapping);
@@ -364,20 +516,26 @@ void NGInlineNode::CollectInlines(NGInlineNodeData* data,
LayoutBlockFlow* block = GetLayoutBlockFlow();
block->WillCollectInlines();
+ // If we have PaintFragment, mark line boxes dirty from |NeedsLayout| flag.
+ base::Optional<NGLineBoxMarker> marker;
+ if (NGPaintFragment* block_fragment = block->PaintFragment())
+ marker.emplace(block_fragment);
+
String* previous_text =
previous_data ? &previous_data->text_content : nullptr;
data->items.ReserveCapacity(EstimateInlineItemsCount(*block));
NGInlineItemsBuilder builder(&data->items);
const bool update_layout = true;
- CollectInlinesInternal(block, &builder, previous_text, update_layout);
+ CollectInlinesInternal(block, &builder, previous_text,
+ marker.has_value() ? &marker.value() : nullptr,
+ update_layout);
data->text_content = builder.ToString();
// Set |is_bidi_enabled_| for all UTF-16 strings for now, because at this
// point the string may or may not contain RTL characters.
// |SegmentText()| will analyze the text and reset |is_bidi_enabled_| if it
// doesn't contain any RTL characters.
- data->is_bidi_enabled_ =
- !data->text_content.Is8Bit() || builder.HasBidiControls();
+ data->is_bidi_enabled_ = MayBeBidiEnabled(data->text_content, builder);
data->is_empty_inline_ = builder.IsEmptyInline();
}
@@ -385,32 +543,48 @@ void NGInlineNode::SegmentText(NGInlineNodeData* data) {
SegmentBidiRuns(data);
SegmentScriptRuns(data);
SegmentFontOrientation(data);
+ if (data->segments)
+ data->segments->ComputeItemIndex(data->items);
}
// Segment NGInlineItem by script, Emoji, and orientation using RunSegmenter.
void NGInlineNode::SegmentScriptRuns(NGInlineNodeData* data) {
- if (data->text_content.Is8Bit() && !data->is_bidi_enabled_) {
+ String& text_content = data->text_content;
+ if (text_content.IsEmpty()) {
+ data->segments = nullptr;
+ return;
+ }
+
+ if (text_content.Is8Bit() && !data->is_bidi_enabled_) {
if (data->items.size()) {
RunSegmenter::RunSegmenterRange range = {
0u, data->text_content.length(), USCRIPT_LATIN,
OrientationIterator::kOrientationKeep, FontFallbackPriority::kText};
- NGInlineItem::PopulateItemsFromRun(data->items, 0, range);
+ NGInlineItem::SetSegmentData(range, &data->items);
}
+ data->segments = nullptr;
return;
}
// Segment by script and Emoji.
// Orientation is segmented separately, because it may vary by items.
- Vector<NGInlineItem>& items = data->items;
- String& text_content = data->text_content;
text_content.Ensure16Bit();
RunSegmenter segmenter(text_content.Characters16(), text_content.length(),
FontOrientation::kHorizontal);
RunSegmenter::RunSegmenterRange range = RunSegmenter::NullRange();
- for (unsigned item_index = 0; segmenter.Consume(&range);) {
- DCHECK_EQ(items[item_index].start_offset_, range.start);
- item_index = NGInlineItem::PopulateItemsFromRun(items, item_index, range);
+ bool consumed = segmenter.Consume(&range);
+ DCHECK(consumed);
+ if (range.end == text_content.length()) {
+ NGInlineItem::SetSegmentData(range, &data->items);
+ data->segments = nullptr;
+ return;
}
+
+ // This node has multiple segments.
+ if (!data->segments)
+ data->segments = std::make_unique<NGInlineItemSegments>();
+ data->segments->ComputeSegments(&segmenter, &range);
+ DCHECK_EQ(range.end, text_content.length());
}
void NGInlineNode::SegmentFontOrientation(NGInlineNodeData* data) {
@@ -420,33 +594,40 @@ void NGInlineNode::SegmentFontOrientation(NGInlineNodeData* data) {
return;
Vector<NGInlineItem>& items = data->items;
+ if (items.IsEmpty())
+ return;
String& text_content = data->text_content;
text_content.Ensure16Bit();
- for (unsigned item_index = 0; item_index < items.size();) {
- NGInlineItem& item = items[item_index];
- if (item.Type() != NGInlineItem::kText ||
- item.Style()->GetFont().GetFontDescription().Orientation() !=
+ // If we don't have |NGInlineItemSegments| yet, create a segment for the
+ // entire content.
+ const unsigned capacity = items.size() + text_content.length() / 10;
+ if (!data->segments) {
+ data->segments = std::make_unique<NGInlineItemSegments>();
+ data->segments->ReserveCapacity(capacity);
+ data->segments->Append(text_content.length(), items.front());
+ } else {
+ DCHECK(!data->segments->IsEmpty());
+ data->segments->ReserveCapacity(capacity);
+ }
+ DCHECK_EQ(text_content.length(), data->segments->EndOffset());
+ unsigned segment_index = 0;
+
+ for (const NGInlineItem& item : items) {
+ if (item.Type() == NGInlineItem::kText &&
+ item.Style()->GetFont().GetFontDescription().Orientation() ==
FontOrientation::kVerticalMixed) {
- item_index++;
- continue;
- }
- unsigned start_offset = item.StartOffset();
- OrientationIterator iterator(text_content.Characters16() + start_offset,
- item.Length(),
- FontOrientation::kVerticalMixed);
- unsigned end_offset;
- OrientationIterator::RenderOrientation orientation;
- while (iterator.Consume(&end_offset, &orientation)) {
- item_index = NGInlineItem::PopulateItemsFromFontOrientation(
- items, item_index, end_offset + start_offset, orientation);
+ segment_index = data->segments->AppendMixedFontOrientation(
+ text_content, item.StartOffset(), item.EndOffset(), segment_index);
}
}
}
+// static
// Segment bidi runs by resolving bidi embedding levels.
// http://unicode.org/reports/tr9/#Resolving_Embedding_Levels
-void NGInlineNode::SegmentBidiRuns(NGInlineNodeData* data) {
+void NGInlineNode::SegmentBidiRunsInternal(NGInlineNodeData* data,
+ const ComputedStyle& style) {
if (!data->is_bidi_enabled_) {
data->SetBaseDirection(TextDirection::kLtr);
return;
@@ -454,7 +635,7 @@ void NGInlineNode::SegmentBidiRuns(NGInlineNodeData* data) {
NGBidiParagraph bidi;
data->text_content.Ensure16Bit();
- if (!bidi.SetParagraph(data->text_content, Style())) {
+ if (!bidi.SetParagraph(data->text_content, style)) {
// On failure, give up bidi resolving and reordering.
data->is_bidi_enabled_ = false;
data->SetBaseDirection(TextDirection::kLtr);
@@ -489,19 +670,24 @@ void NGInlineNode::SegmentBidiRuns(NGInlineNodeData* data) {
#endif
}
+void NGInlineNode::SegmentBidiRuns(NGInlineNodeData* data) {
+ SegmentBidiRunsInternal(data, Style());
+}
+
void NGInlineNode::ShapeText(NGInlineItemsData* data,
NGInlineItemsData* previous_data) {
- ShapeText(data->text_content, &data->items,
- previous_data ? &previous_data->text_content : nullptr);
-}
+ const String& text_content = data->text_content;
+ Vector<NGInlineItem>* items = &data->items;
+ const String* previous_text =
+ previous_data ? &previous_data->text_content : nullptr;
-void NGInlineNode::ShapeText(const String& text_content,
- Vector<NGInlineItem>* items,
- const String* previous_text) {
// Provide full context of the entire node to the shaper.
HarfBuzzShaper shaper(text_content);
ShapeResultSpacing<String> spacing(text_content);
+ DCHECK(!data->segments ||
+ data->segments->EndOffset() == text_content.length());
+
for (unsigned index = 0; index < items->size();) {
NGInlineItem& start_item = (*items)[index];
if (start_item.Type() != NGInlineItem::kText) {
@@ -580,17 +766,29 @@ void NGInlineNode::ShapeText(const String& text_content,
}
// Shape each item with the full context of the entire node.
- RunSegmenter::RunSegmenterRange range =
- start_item.CreateRunSegmenterRange();
- range.end = end_offset;
- scoped_refptr<ShapeResult> shape_result = shaper.Shape(
- &font, direction, start_item.StartOffset(), end_offset, &range);
+ scoped_refptr<ShapeResult> shape_result;
+ if (!data->segments) {
+ RunSegmenter::RunSegmenterRange range =
+ start_item.CreateRunSegmenterRange();
+ range.end = end_offset;
+ shape_result = shaper.Shape(&font, direction, start_item.StartOffset(),
+ end_offset, &range);
+ } else {
+ shape_result = data->segments->ShapeText(
+ &shaper, &font, direction, start_item.StartOffset(), end_offset,
+ &start_item - items->begin());
+ }
+
if (UNLIKELY(spacing.SetSpacing(font.GetFontDescription())))
shape_result->ApplySpacing(spacing);
// If the text is from one item, use the ShapeResult as is.
if (end_offset == start_item.EndOffset()) {
start_item.shape_result_ = std::move(shape_result);
+ DCHECK_EQ(start_item.TextShapeResult()->StartIndex(),
+ start_item.StartOffset());
+ DCHECK_EQ(start_item.TextShapeResult()->EndIndex(),
+ start_item.EndOffset());
index++;
continue;
}
@@ -611,8 +809,21 @@ void NGInlineNode::ShapeText(const String& text_content,
// item that has its first code unit keeps the glyph.
item.shape_result_ = shape_result->SubRange(
item.StartOffset(), item.EndOffset(), &opaque_context);
+ DCHECK(item.TextShapeResult());
+ DCHECK_EQ(item.TextShapeResult()->StartIndex(), item.StartOffset());
+ DCHECK_EQ(item.TextShapeResult()->EndIndex(), item.EndOffset());
+ }
+ }
+
+#if DCHECK_IS_ON()
+ for (const NGInlineItem& item : *items) {
+ if (item.Type() == NGInlineItem::kText) {
+ DCHECK(item.TextShapeResult());
+ DCHECK_EQ(item.TextShapeResult()->StartIndex(), item.StartOffset());
+ DCHECK_EQ(item.TextShapeResult()->EndIndex(), item.EndOffset());
}
}
+#endif
}
// Create Vector<NGInlineItem> with :first-line rules applied if needed.
@@ -697,20 +908,48 @@ void NGInlineNode::AssociateItemsWithInlines(NGInlineNodeData* data) {
}
}
-// Clear associated fragments for all LayoutObjects. They are associated when
-// NGPaintFragment is constructed.
void NGInlineNode::ClearAssociatedFragments(
- const NGInlineBreakToken* break_token) {
- if (!IsPrepareLayoutFinished())
+ const NGPhysicalFragment& fragment,
+ const NGBlockBreakToken* block_break_token) {
+ LayoutBlockFlow* block_flow = ToLayoutBlockFlow(fragment.GetLayoutObject());
+ if (!block_flow->ChildrenInline())
return;
+ NGInlineNode node = NGInlineNode(block_flow);
+#if DCHECK_IS_ON()
+ // We assume this function is called for the LayoutObject of an NGInlineNode.
+ NGLayoutInputNode first_child = NGBlockNode(block_flow).FirstChild();
+ DCHECK(first_child && first_child.IsInline());
+ DCHECK(first_child == node);
+#endif
+
+ DCHECK(node.IsPrepareLayoutFinished());
+ const Vector<NGInlineItem>& items = node.MaybeDirtyData().items;
+
+ unsigned start_index;
+ if (!block_break_token) {
+ start_index = 0;
+ } else {
+ // TODO(kojii): Not fully supported, need more logic when the block is
+ // fragmented, because one inline LayoutObject may span across
+ // fragmentainers.
+ // TODO(kojii): Not sure if using |block_break_token->InputNode()| is
+ // correct for multicol. Should verify and somehow get NGInlineNode from it.
+ // Also change |InlineBreakTokenFor| to receive NGInlineNode instead of
+ // NGLayoutInputNode once this is done.
+ const NGInlineBreakToken* inline_break_token =
+ block_break_token->InlineBreakTokenFor(block_break_token->InputNode());
+ // TODO(kojii): This needs to investigate in what case this happens. It's
+ // probably wrong to create NGPaintFragment when there's no inline break
+ // token.
+ if (!inline_break_token)
+ return;
+ start_index = inline_break_token->ItemIndex();
+ }
LayoutObject* last_object = nullptr;
- const Vector<NGInlineItem>& items = Data().items;
- for (unsigned i = break_token ? break_token->ItemIndex() : 0;
- i < items.size(); i++) {
+ for (unsigned i = start_index; i < items.size(); i++) {
const NGInlineItem& item = items[i];
- if (item.Type() == NGInlineItem::kFloating ||
- item.Type() == NGInlineItem::kOutOfFlowPositioned ||
+ if (item.Type() == NGInlineItem::kOutOfFlowPositioned ||
item.Type() == NGInlineItem::kListMarker)
continue;
LayoutObject* object = item.GetLayoutObject();
@@ -725,15 +964,10 @@ scoped_refptr<NGLayoutResult> NGInlineNode::Layout(
const NGConstraintSpace& constraint_space,
const NGBreakToken* break_token,
NGInlineChildLayoutContext* context) {
- bool needs_clear_fragments = IsPrepareLayoutFinished();
PrepareLayoutIfNeeded();
const NGInlineBreakToken* inline_break_token =
ToNGInlineBreakToken(break_token);
- if (needs_clear_fragments && !constraint_space.IsIntermediateLayout()) {
- ClearAssociatedFragments(inline_break_token);
- }
-
NGInlineLayoutAlgorithm algorithm(*this, constraint_space, inline_break_token,
context);
return algorithm.Layout();
@@ -770,87 +1004,11 @@ bool NGInlineNode::PrepareReuseFragments(
// |DirtyLinesFromChangedChild()|, but insertions and style changes are not
// marked yet.
bool NGInlineNode::MarkLineBoxesDirty(LayoutBlockFlow* block_flow) {
- DCHECK(block_flow);
- DCHECK(block_flow->PaintFragment());
- bool has_dirtied_lines = false;
- NGPaintFragment* last_fragment = nullptr;
- for (LayoutObject* layout_object = block_flow->NextInPreOrder(block_flow);
- layout_object;) {
- bool should_dirty_lines = false;
- NGPaintFragment* fragment = nullptr;
- LayoutObject* next = nullptr;
- if (LayoutText* layout_text = ToLayoutTextOrNull(layout_object)) {
- if (!has_dirtied_lines) {
- should_dirty_lines = layout_object->SelfNeedsLayout();
- if (!should_dirty_lines)
- fragment = layout_text->FirstInlineFragment();
- }
- next = layout_object->NextInPreOrderAfterChildren(block_flow);
- layout_object->ClearNeedsLayout();
- } else if (LayoutInline* layout_inline =
- ToLayoutInlineOrNull(layout_object)) {
- if (!has_dirtied_lines) {
- should_dirty_lines = layout_object->SelfNeedsLayout();
- // Do not keep fragments of LayoutInline unless it's a leaf, because
- // the last fragment of LayoutInline is not the previous fragment of its
- // descendants.
- if (!should_dirty_lines && !layout_inline->FirstChild())
- fragment = layout_inline->FirstInlineFragment();
- }
- next = layout_object->NextInPreOrder(block_flow);
- layout_object->ClearNeedsLayout();
- } else if (UNLIKELY(layout_object->IsFloatingOrOutOfFlowPositioned())) {
- // Aborting in the middle of the traversal is safe because this function
- // ClearNeedsLayout() on text and LayoutInline, but since an inline
- // formatting context is laid out as a whole, these flags don't matter.
- // For that reason, this traversal should not ClearNeedsLayout() atomic
- // inlines, floats, or OOF -- objects that need to be laid out separately
- // from the inline formatting context.
- // TODO(kojii): This looks a bit tricky, better to come up with clearner
- // solution if any.
- return false;
- } else if (layout_object->IsAtomicInlineLevel()) {
- if (!has_dirtied_lines) {
- should_dirty_lines = layout_object->NeedsLayout();
- if (!should_dirty_lines)
- fragment = layout_object->FirstInlineFragment();
- }
- next = layout_object->NextInPreOrderAfterChildren(block_flow);
- } else {
- NOTREACHED();
- // With LayoutNGBlockFragmentation, LayoutFlowThread/LayoutMultiColumnSet
- // appear in fast/multicol/paged-becomes-multicol-auto-height.html.
- // crbug.com/897141
- next = layout_object->NextInPreOrder(block_flow);
- }
-
- if (!has_dirtied_lines) {
- if (should_dirty_lines) {
- if (last_fragment) {
- // Changes in this LayoutObject may affect the line that contains its
- // previous object. Mark the line box that contains the last fragment
- // of the previous object.
- last_fragment->LastForSameLayoutObject()
- ->MarkContainingLineBoxDirty();
- } else {
- // If there were no fragments so far in this pre-order traversal, mark
- // the first line box dirty.
- NGPaintFragment* block_fragment = block_flow->PaintFragment();
- DCHECK(block_fragment);
- if (NGPaintFragment* first_line = block_fragment->FirstLineBox())
- first_line->MarkLineBoxDirty();
- }
- has_dirtied_lines = true;
- } else if (fragment) {
- last_fragment = fragment;
- }
- }
-
- ClearInlineFragment(layout_object);
- layout_object = next;
- }
- block_flow->ClearNeedsLayout();
- return true;
+ NGLineBoxMarker marker(block_flow->PaintFragment());
+ ItemsBuilderForMarkLineBoxesDirty builder;
+ const bool update_layout = true;
+ CollectInlinesInternal(block_flow, &builder, nullptr, &marker, update_layout);
+ return !builder.ShouldAbort();
}
static LayoutUnit ComputeContentSize(
@@ -870,24 +1028,25 @@ static LayoutUnit ComputeContentSize(
/* is_new_fc */ false)
.SetTextDirection(style.Direction())
.SetAvailableSize({available_inline_size, NGSizeIndefinite})
+ .SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()})
+ .SetReplacedPercentageResolutionSize({LayoutUnit(), LayoutUnit()})
.SetIsIntermediateLayout(true)
.ToConstraintSpace();
- Vector<NGPositionedFloat> positioned_floats;
- NGUnpositionedFloatVector unpositioned_floats;
-
NGExclusionSpace empty_exclusion_space;
+ NGPositionedFloatVector empty_leading_floats;
+ Vector<LayoutObject*> floats_for_min_max;
NGLineLayoutOpportunity line_opportunity(available_inline_size);
LayoutUnit result;
LayoutUnit previous_floats_inline_size =
input.float_left_inline_size + input.float_right_inline_size;
DCHECK_GE(previous_floats_inline_size, 0);
NGLineBreaker line_breaker(
- node, mode, space, &positioned_floats, &unpositioned_floats,
- nullptr /* container_builder */, &empty_exclusion_space, 0u,
- line_opportunity, nullptr /* break_token */);
+ node, mode, space, line_opportunity, empty_leading_floats,
+ /* handled_leading_floats_index */ 0u,
+ /* break_token */ nullptr, &empty_exclusion_space, &floats_for_min_max);
do {
- unpositioned_floats.Shrink(0);
+ floats_for_min_max.Shrink(0);
NGLineInfo line_info;
line_breaker.NextLine(&line_info);
@@ -897,9 +1056,6 @@ static LayoutUnit ComputeContentSize(
LayoutUnit inline_size = line_info.Width();
DCHECK_EQ(inline_size, line_info.ComputeWidth().ClampNegativeToZero());
- // There should be no positioned floats while determining the min/max sizes.
- DCHECK_EQ(positioned_floats.size(), 0u);
-
// These variables are only used for the max-content calculation.
LayoutUnit floats_inline_size = mode == NGLineBreakerMode::kMaxContent
? previous_floats_inline_size
@@ -910,8 +1066,10 @@ static LayoutUnit ComputeContentSize(
// them now.
previous_floats_inline_size = LayoutUnit();
- for (const auto& unpositioned_float : unpositioned_floats) {
- NGBlockNode float_node = unpositioned_float.node;
+ for (auto* floating_object : floats_for_min_max) {
+ DCHECK(floating_object->IsFloating());
+
+ NGBlockNode float_node(ToLayoutBox(floating_object));
const ComputedStyle& float_style = float_node.Style();
MinMaxSizeInput zero_input; // Floats don't intrude into floats.
@@ -985,6 +1143,11 @@ MinMaxSize NGInlineNode::ComputeMinMaxSize(
return sizes;
}
+bool NGInlineNode::UseFirstLineStyle() const {
+ return GetLayoutBox() &&
+ GetLayoutBox()->GetDocument().GetStyleEngine().UsesFirstLineRules();
+}
+
void NGInlineNode::CheckConsistency() const {
#if DCHECK_IS_ON()
const Vector<NGInlineItem>& items = Data().items;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index 1e38711ccd3..0007417e25a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -13,10 +13,9 @@
namespace blink {
+class NGBlockBreakToken;
class NGConstraintSpace;
-class NGInlineBreakToken;
class NGInlineChildLayoutContext;
-class NGInlineItem;
class NGLayoutResult;
class NGOffsetMapping;
class NGInlineNodeLegacy;
@@ -65,6 +64,12 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
return Data().ItemsData(is_first_line);
}
+ // Clear associated fragments for LayoutObjects.
+ // They are associated when NGPaintFragment is constructed, but when clearing,
+ // NGInlineItem provides easier and faster logic.
+ static void ClearAssociatedFragments(const NGPhysicalFragment& fragment,
+ const NGBlockBreakToken* break_token);
+
// Returns the DOM to text content offset mapping of this block. If it is not
// computed before, compute and store it in NGInlineNodeData.
// This funciton must be called with clean layout.
@@ -72,7 +77,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// Get |NGOffsetMapping| for the |layout_block_flow|. If |layout_block_flow|
// is LayoutNG and it is already laid out, this function is the same as
- // |ComputeOffsetMappingIfNeeded|. |storage| is not used in this case.
+ // |ComputeOffsetMappingIfNeeded|. |storage| is not used in this case, and can
+ // be null.
//
// Otherwise, this function computes |NGOffsetMapping| and store in |storage|
// as well as returning the pointer. The caller is responsible for keeping
@@ -93,6 +99,7 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
return GetLayoutBlockFlow()->CanContainFirstFormattedLine();
}
+ bool UseFirstLineStyle() const;
void CheckConsistency() const;
String ToString() const;
@@ -112,14 +119,9 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
void SegmentBidiRuns(NGInlineNodeData*);
void ShapeText(NGInlineItemsData*,
NGInlineItemsData* previous_data = nullptr);
- void ShapeText(const String& text,
- Vector<NGInlineItem>*,
- const String* previous_text);
void ShapeTextForFirstLineIfNeeded(NGInlineNodeData*);
void AssociateItemsWithInlines(NGInlineNodeData*);
- void ClearAssociatedFragments(const NGInlineBreakToken*);
-
bool MarkLineBoxesDirty(LayoutBlockFlow*);
NGInlineNodeData* MutableData() {
@@ -130,11 +132,21 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
!GetLayoutBlockFlow()->NeedsCollectInlines());
return *ToLayoutBlockFlow(box_)->GetNGInlineNodeData();
}
+ // Same as |Data()| but can access even when |NeedsCollectInlines()| is set.
+ const NGInlineNodeData& MaybeDirtyData() const {
+ DCHECK(IsPrepareLayoutFinished());
+ return *ToLayoutBlockFlow(box_)->GetNGInlineNodeData();
+ }
const NGInlineNodeData& EnsureData();
static void ComputeOffsetMapping(LayoutBlockFlow* layout_block_flow,
NGInlineNodeData* data);
+ // This function shares bidi segmentation code between inline layout algorithm
+ // and |NGCaretNavigator| building, which may run on legacy layout.
+ // TODO(layout-dev): Merge with |SegmentBidiRuns| when we remove legacy layout
+ static void SegmentBidiRunsInternal(NGInlineNodeData*, const ComputedStyle&);
+
friend class NGLineBreakerTest;
friend class NGInlineNodeLegacy;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index dbf328bc9ea..20370223541 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -13,15 +13,18 @@ namespace blink {
// Data which is required for inline nodes.
struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData {
+ public:
+ bool IsBidiEnabled() const { return is_bidi_enabled_; }
+ TextDirection BaseDirection() const {
+ return static_cast<TextDirection>(base_direction_);
+ }
+
private:
const NGInlineItemsData& ItemsData(bool is_first_line) const {
return !is_first_line || !first_line_items_
? (const NGInlineItemsData&)*this
: *first_line_items_;
}
- TextDirection BaseDirection() const {
- return static_cast<TextDirection>(base_direction_);
- }
void SetBaseDirection(TextDirection direction) {
base_direction_ = static_cast<unsigned>(direction);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
index 788aecf9934..82e45844b8b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h"
@@ -21,6 +22,13 @@
namespace blink {
+// The spec turned into a discussion that may change. Put this logic on hold
+// until CSSWG resolves the issue.
+// https://github.com/w3c/csswg-drafts/issues/337
+#define SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH 0
+
+using ::testing::ElementsAre;
+
class NGInlineNodeForTest : public NGInlineNode {
public:
using NGInlineNode::NGInlineNode;
@@ -158,12 +166,34 @@ class NGInlineNodeTest : public NGLayoutTest {
void ForceLayout() { GetDocument().body()->OffsetTop(); }
+ Vector<unsigned> ToEndOffsetList(
+ NGInlineItemSegments::const_iterator segments) {
+ Vector<unsigned> end_offsets;
+ for (const NGInlineItemSegment& segment : segments)
+ end_offsets.push_back(segment.EndOffset());
+ return end_offsets;
+ }
+
scoped_refptr<const ComputedStyle> style_;
LayoutNGBlockFlow* layout_block_flow_ = nullptr;
LayoutObject* layout_object_ = nullptr;
FontCachePurgePreventer purge_preventer_;
};
+class NodeParameterTest : public NGInlineNodeTest,
+ public testing::WithParamInterface<const char*> {};
+
+INSTANTIATE_TEST_CASE_P(
+ NGInlineNodeTest,
+ NodeParameterTest,
+ testing::Values("text",
+ "<span>span</span>",
+ "<span>1234 12345678</span>",
+ "<span style='display: inline-block'>box</span>",
+ "<img>",
+ "<div style='float: left'>float</div>",
+ "<div style='position: absolute'>abs</div>"));
+
#define TEST_ITEM_TYPE_OFFSET(item, type, start, end) \
EXPECT_EQ(NGInlineItem::type, item.Type()); \
EXPECT_EQ(start, item.StartOffset()); \
@@ -393,7 +423,7 @@ TEST_F(NGInlineNodeTest, SegmentBidiIsolate) {
NGInlineNodeForTest node = CreateInlineNode();
node = CreateBidiIsolateNode(node, style_.get(), layout_object_);
Vector<NGInlineItem>& items = node.Items();
- ASSERT_EQ(10u, items.size());
+ EXPECT_EQ(9u, items.size());
TEST_ITEM_OFFSET_DIR(items[0], 0u, 6u, TextDirection::kLtr);
TEST_ITEM_OFFSET_DIR(items[1], 6u, 7u, TextDirection::kLtr);
TEST_ITEM_OFFSET_DIR(items[2], 7u, 13u, TextDirection::kRtl);
@@ -402,8 +432,7 @@ TEST_F(NGInlineNodeTest, SegmentBidiIsolate) {
TEST_ITEM_OFFSET_DIR(items[5], 15u, 16u, TextDirection::kRtl);
TEST_ITEM_OFFSET_DIR(items[6], 16u, 21u, TextDirection::kRtl);
TEST_ITEM_OFFSET_DIR(items[7], 21u, 22u, TextDirection::kLtr);
- TEST_ITEM_OFFSET_DIR(items[8], 22u, 23u, TextDirection::kLtr);
- TEST_ITEM_OFFSET_DIR(items[9], 23u, 28u, TextDirection::kLtr);
+ TEST_ITEM_OFFSET_DIR(items[8], 22u, 28u, TextDirection::kLtr);
}
#define TEST_TEXT_FRAGMENT(fragment, start_offset, end_offset) \
@@ -420,13 +449,12 @@ TEST_F(NGInlineNodeTest, CreateLineBidiIsolate) {
node.ShapeText();
Vector<scoped_refptr<const NGPhysicalTextFragment>> fragments;
CreateLine(node, &fragments);
- ASSERT_EQ(6u, fragments.size());
+ EXPECT_EQ(5u, fragments.size());
TEST_TEXT_FRAGMENT(fragments[0], 0u, 6u);
TEST_TEXT_FRAGMENT(fragments[1], 16u, 21u);
TEST_TEXT_FRAGMENT(fragments[2], 14u, 15u);
TEST_TEXT_FRAGMENT(fragments[3], 7u, 13u);
- TEST_TEXT_FRAGMENT(fragments[4], 22u, 23u);
- TEST_TEXT_FRAGMENT(fragments[5], 23u, 28u);
+ TEST_TEXT_FRAGMENT(fragments[4], 22u, 28u);
}
TEST_F(NGInlineNodeTest, MinMaxSize) {
@@ -745,15 +773,17 @@ TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnRemove) {
}
// Test marking line boxes when removing a span.
-TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnRemoveFirst) {
- SetupHtml("container", R"HTML(
- <div id=container style="font-size: 10px; width: 10ch">
- <span id=t>1234</span>5678
+TEST_P(NodeParameterTest, MarkLineBoxesDirtyOnRemoveFirst) {
+ SetupHtml("container", String(R"HTML(
+ <div id=container style="font-size: 10px; width: 10ch">)HTML") +
+ GetParam() + R"HTML(<span>after</span>
</div>
)HTML");
- Element* span = GetElementById("t");
- span->remove();
+ Element* container = GetElementById("container");
+ Node* node = container->firstChild();
+ ASSERT_TRUE(node);
+ node->remove();
auto lines = MarkLineBoxesDirty();
EXPECT_TRUE(lines[0]->IsDirty());
@@ -776,6 +806,27 @@ TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnRemove2) {
EXPECT_TRUE(lines[1]->IsDirty());
}
+// Test marking line boxes when removing a text node on 2nd line.
+TEST_P(NodeParameterTest, MarkLineBoxesDirtyOnRemoveAfterBR) {
+ SetupHtml("container", String(R"HTML(
+ <div id=container style="font-size: 10px; width: 10ch">
+ line 1
+ <br>)HTML") + GetParam() +
+ "</div>");
+
+ Element* container = GetElementById("container");
+ Node* node = container->lastChild();
+ ASSERT_TRUE(node);
+ node->remove();
+
+ auto lines = MarkLineBoxesDirty();
+ EXPECT_TRUE(lines[0]->IsDirty());
+ // Currently, only the first dirty line is marked.
+ EXPECT_FALSE(lines[1]->IsDirty());
+
+ ForceLayout(); // Ensure running layout does not crash.
+}
+
// Test marking line boxes when the first span has NeedsLayout. The span is
// culled.
TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnNeedsLayoutFirst) {
@@ -864,4 +915,156 @@ TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnChildOfWrappedBox) {
EXPECT_TRUE(lines[0]->IsDirty());
}
+// Test marking line boxes when a span has NeedsLayout. The span has a box
+// fragment.
+TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyInInlineBlock) {
+ SetupHtml("container", R"HTML(
+ <div id=container style="display: inline-block; font-size: 10px">
+ 12345678<br>
+ 12345678<br>
+ </div>
+ )HTML");
+
+ Element* container = GetElementById("container");
+ container->appendChild(GetDocument().createTextNode("append"));
+
+ // Inline block with auto-size calls |ComputeMinMaxSize|, which may call
+ // |CollectInlines|. Emulate it to ensure it does not let tests to fail.
+ GetDocument().UpdateStyleAndLayoutTree();
+ NGInlineNode(layout_block_flow_)
+ .ComputeMinMaxSize(layout_block_flow_->StyleRef().GetWritingMode(), {});
+
+ auto lines = MarkLineBoxesDirty();
+ EXPECT_FALSE(lines[0]->IsDirty());
+ EXPECT_TRUE(lines[1]->IsDirty());
+}
+
+TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockBecomesEmpty1) {
+ SetupHtml("container", "<div id=container><b id=remove><i>foo</i></b></div>");
+ ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
+
+ Element* to_remove = GetElementById("remove");
+ to_remove->remove();
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
+}
+
+TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockBecomesEmpty2) {
+ SetupHtml("container", "<div id=container><b><i>foo</i></b></div>");
+ ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
+
+ GetElementById("container")->SetInnerHTMLFromString("");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
+}
+
+TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockObtainsBlockChild) {
+ SetupHtml("container",
+ "<div id=container><b id=blockify><i>foo</i></b></div>");
+ ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
+
+ GetElementById("blockify")
+ ->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock);
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
+}
+
+// https://crbug.com/911220
+TEST_F(NGInlineNodeTest, PreservedNewlineWithBidiAndRelayout) {
+ SetupHtml("container",
+ "<style>span{unicode-bidi:isolate}</style>"
+ "<pre id=container>foo<span>\n</span>bar<br></pre>");
+ EXPECT_EQ(String(u"foo\u2066\u2069\n\u2066\u2069bar\n"), GetText());
+
+ Node* new_text = Text::Create(GetDocument(), "baz");
+ GetElementById("container")->appendChild(new_text);
+ UpdateAllLifecyclePhasesForTest();
+
+ // The bidi context popping and re-entering should be preserved around '\n'.
+ EXPECT_EQ(String(u"foo\u2066\u2069\n\u2066\u2069bar\nbaz"), GetText());
+}
+
+#if SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH
+// https://crbug.com/879088
+TEST_F(NGInlineNodeTest, RemoveSegmentBreakFromJapaneseInRelayout) {
+ SetupHtml("container",
+ u"<div id=container>"
+ u"<span>\u30ED\u30B0\u30A4\u30F3</span>"
+ u"\n"
+ u"<span>\u767B\u9332</span>"
+ u"<br></div>");
+ EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\n"), GetText());
+
+ Node* new_text = Text::Create(GetDocument(), "foo");
+ GetElementById("container")->appendChild(new_text);
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\nfoo"), GetText());
+}
+
+// https://crbug.com/879088
+TEST_F(NGInlineNodeTest, RemoveSegmentBreakFromJapaneseInRelayout2) {
+ SetupHtml("container",
+ u"<div id=container>"
+ u"<span>\u30ED\u30B0\u30A4\u30F3</span>"
+ u"\n"
+ u"<span> \u767B\u9332</span>"
+ u"<br></div>");
+ EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\n"), GetText());
+
+ Node* new_text = Text::Create(GetDocument(), "foo");
+ GetElementById("container")->appendChild(new_text);
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\nfoo"), GetText());
+}
+#endif
+
+TEST_F(NGInlineNodeTest, SegmentRanges) {
+ SetupHtml("container",
+ "<div id=container>"
+ u"\u306Forange\u304C"
+ "<span>text</span>"
+ "</div>");
+
+ NGInlineItemsData* items_data = layout_block_flow_->GetNGInlineNodeData();
+ ASSERT_TRUE(items_data);
+ NGInlineItemSegments* segments = items_data->segments.get();
+ ASSERT_TRUE(segments);
+
+ // Test EndOffset for the full text. All segment boundaries including the end
+ // of the text content should be returned.
+ Vector<unsigned> expect_0_12 = {1u, 7u, 8u, 12u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(0, 12, 0)), expect_0_12);
+
+ // Test ranges for each segment that start with 1st item.
+ Vector<unsigned> expect_0_1 = {1u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(0, 1, 0)), expect_0_1);
+ Vector<unsigned> expect_2_3 = {3u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(2, 3, 0)), expect_2_3);
+ Vector<unsigned> expect_7_8 = {8u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(7, 8, 0)), expect_7_8);
+
+ // Test ranges that acrosses multiple segments.
+ Vector<unsigned> expect_0_8 = {1u, 7u, 8u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(0, 8, 0)), expect_0_8);
+ Vector<unsigned> expect_2_8 = {7u, 8u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(2, 8, 0)), expect_2_8);
+ Vector<unsigned> expect_2_10 = {7u, 8u, 10u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(2, 10, 0)), expect_2_10);
+ Vector<unsigned> expect_7_10 = {8u, 10u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(7, 10, 0)), expect_7_10);
+
+ // Test ranges that starts with 2nd item.
+ Vector<unsigned> expect_8_9 = {9u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(8, 9, 1)), expect_8_9);
+ Vector<unsigned> expect_8_10 = {10u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(8, 10, 1)), expect_8_10);
+ Vector<unsigned> expect_9_12 = {12u};
+ EXPECT_EQ(ToEndOffsetList(segments->Ranges(9, 12, 1)), expect_9_12);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index d70c22a17f3..cb562a2888f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -78,6 +78,11 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
} else if (child.fragment) {
AddChild(std::move(child.fragment), child.offset);
DCHECK(!child.fragment);
+ } else if (child.out_of_flow_positioned_box) {
+ AddOutOfFlowChildCandidate(
+ NGBlockNode(ToLayoutBox(child.out_of_flow_positioned_box)),
+ child.offset, child.container_direction);
+ child.out_of_flow_positioned_box = nullptr;
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index 4e2cd3e3185..7702b04edcc 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -20,7 +20,6 @@ namespace blink {
class ComputedStyle;
class NGInlineBreakToken;
class NGPhysicalFragment;
-struct NGPositionedFloat;
class CORE_EXPORT NGLineBoxFragmentBuilder final
: public NGContainerFragmentBuilder {
@@ -31,8 +30,10 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
scoped_refptr<const ComputedStyle> style,
WritingMode writing_mode,
TextDirection)
- : NGContainerFragmentBuilder(style, writing_mode, TextDirection::kLtr),
- node_(node),
+ : NGContainerFragmentBuilder(node,
+ style,
+ writing_mode,
+ TextDirection::kLtr),
line_box_type_(NGPhysicalLineBoxFragment::kNormalLineBox),
base_direction_(TextDirection::kLtr) {}
@@ -52,10 +53,6 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
base_direction_ = direction;
}
- void SwapPositionedFloats(Vector<NGPositionedFloat>* positioned_floats) {
- positioned_floats_.swap(*positioned_floats);
- }
-
// Set the break token for the fragment to build.
// A finished break token will be attached if not set.
void SetBreakToken(scoped_refptr<NGInlineBreakToken> break_token) {
@@ -70,10 +67,13 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
scoped_refptr<NGLayoutResult> layout_result;
scoped_refptr<const NGPhysicalFragment> fragment;
LayoutObject* out_of_flow_positioned_box = nullptr;
- LayoutObject* out_of_flow_containing_box = nullptr;
+ LayoutObject* unpositioned_float = nullptr;
// The offset of the border box, initially in this child coordinate system.
// |ComputeInlinePositions()| converts it to the offset within the line box.
NGLogicalOffset offset;
+ // The offset of a positioned float wrt. the root BFC. This should only be
+ // set for positioned floats.
+ NGBfcOffset bfc_offset;
// The inline size of the margin box.
LayoutUnit inline_size;
LayoutUnit margin_line_left;
@@ -81,6 +81,8 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
// |UpdateAfterReorder()| to track children of boxes across BiDi reorder.
unsigned box_data_index = 0;
UBiDiLevel bidi_level = 0xff;
+ // The current text direction for OOF positioned items.
+ TextDirection container_direction = TextDirection::kLtr;
// Empty constructor needed for |resize()|.
Child() = default;
@@ -118,13 +120,31 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
bidi_level(bidi_level) {}
// Create an out-of-flow positioned object.
Child(LayoutObject* out_of_flow_positioned_box,
- LayoutObject* out_of_flow_containing_box,
- UBiDiLevel bidi_level)
+ UBiDiLevel bidi_level,
+ TextDirection container_direction)
: out_of_flow_positioned_box(out_of_flow_positioned_box),
- out_of_flow_containing_box(out_of_flow_containing_box),
+ bidi_level(bidi_level),
+ container_direction(container_direction) {}
+ // Create an unpositioned float.
+ Child(LayoutObject* unpositioned_float, UBiDiLevel bidi_level)
+ : unpositioned_float(unpositioned_float), bidi_level(bidi_level) {}
+ // Create a positioned float.
+ Child(scoped_refptr<NGLayoutResult> layout_result,
+ NGBfcOffset bfc_offset,
+ UBiDiLevel bidi_level)
+ : layout_result(std::move(layout_result)),
+ bfc_offset(bfc_offset),
bidi_level(bidi_level) {}
- bool HasInFlowFragment() const { return layout_result || fragment; }
+ bool HasInFlowFragment() const {
+ if (fragment)
+ return true;
+
+ if (layout_result && !layout_result->PhysicalFragment()->IsFloating())
+ return true;
+
+ return false;
+ }
bool HasOutOfFlowFragment() const { return out_of_flow_positioned_box; }
bool HasFragment() const {
return HasInFlowFragment() || HasOutOfFlowFragment();
@@ -204,11 +224,7 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
scoped_refptr<NGLayoutResult> ToLineBoxFragment();
private:
- NGInlineNode node_;
-
NGLineHeightMetrics metrics_;
- Vector<NGPositionedFloat> positioned_floats_;
-
NGPhysicalLineBoxFragment::NGLineBoxType line_box_type_;
TextDirection base_direction_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index b35d9baa564..0b7c1ae286c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -41,40 +41,56 @@ inline bool ShouldCreateLineBox(const NGInlineItemResults& item_results) {
return !item_results.IsEmpty() && item_results.back().should_create_line_box;
}
+inline bool HasUnpositionedFloats(const NGInlineItemResults& item_results) {
+ return !item_results.IsEmpty() && item_results.back().has_unpositioned_floats;
+}
+
+bool IsImage(const NGInlineItem& item) {
+ if (!item.GetLayoutObject() || !item.GetLayoutObject()->IsLayoutImage())
+ return false;
+ DCHECK(item.Type() == NGInlineItem::kAtomicInline);
+ return true;
+}
+
+LayoutUnit ComputeInlineEndSize(const NGConstraintSpace& space,
+ const ComputedStyle* style) {
+ DCHECK(style);
+ NGBoxStrut margins = ComputeMarginsForSelf(space, *style);
+ NGBoxStrut borders = ComputeBorders(space, *style);
+ NGBoxStrut paddings = ComputePadding(space, *style);
+
+ return margins.inline_end + borders.inline_end + paddings.inline_end;
+}
+
} // namespace
NGLineBreaker::NGLineBreaker(NGInlineNode node,
NGLineBreakerMode mode,
const NGConstraintSpace& space,
- Vector<NGPositionedFloat>* positioned_floats,
- NGUnpositionedFloatVector* unpositioned_floats,
- NGContainerFragmentBuilder* container_builder,
- NGExclusionSpace* exclusion_space,
- unsigned handled_float_index,
const NGLineLayoutOpportunity& line_opportunity,
- const NGInlineBreakToken* break_token)
+ const NGPositionedFloatVector& leading_floats,
+ unsigned handled_leading_floats_index,
+ const NGInlineBreakToken* break_token,
+ NGExclusionSpace* exclusion_space,
+ Vector<LayoutObject*>* out_floats_for_min_max)
: line_opportunity_(line_opportunity),
node_(node),
is_first_formatted_line_((!break_token || (!break_token->ItemIndex() &&
!break_token->TextOffset())) &&
node.CanContainFirstFormattedLine()),
use_first_line_style_(is_first_formatted_line_ &&
- node.GetLayoutBox()
- ->GetDocument()
- .GetStyleEngine()
- .UsesFirstLineRules()),
+ node.UseFirstLineStyle()),
in_line_height_quirks_mode_(node.InLineHeightQuirksMode()),
items_data_(node.ItemsData(use_first_line_style_)),
mode_(mode),
constraint_space_(space),
- positioned_floats_(positioned_floats),
- unpositioned_floats_(unpositioned_floats),
- container_builder_(container_builder),
exclusion_space_(exclusion_space),
break_iterator_(items_data_.text_content),
shaper_(items_data_.text_content),
spacing_(items_data_.text_content),
- handled_floats_end_item_index_(handled_float_index),
+ leading_floats_(leading_floats),
+ handled_leading_floats_index_(handled_leading_floats_index),
+ out_floats_for_min_max_(out_floats_for_min_max),
base_direction_(node_.BaseDirection()) {
break_iterator_.SetBreakSpace(BreakSpaceType::kBeforeSpaceRun);
@@ -87,6 +103,19 @@ NGLineBreaker::NGLineBreaker(NGInlineNode node,
items_data_.AssertOffset(item_index_, offset_);
ignore_floats_ = break_token->IgnoreFloats();
}
+
+ // There's a special intrinsic size measure quirk for images that are direct
+ // children of table cells that have auto inline-size: When measuring
+ // intrinsic min/max inline sizes, we pretend that it's not possible to break
+ // between images, or between text and images. Note that this only applies
+ // when measuring. During actual layout, on the other hand, standard breaking
+ // rules are to be followed.
+ // See https://quirks.spec.whatwg.org/#the-table-cell-width-calculation-quirk
+ if (node.GetDocument().InQuirksMode() &&
+ node.Style().Display() == EDisplay::kTableCell &&
+ node.Style().LogicalWidth().IsIntrinsicOrAuto() &&
+ mode != NGLineBreakerMode::kContent)
+ sticky_images_quirk_ = true;
}
// Define the destructor here, so that we can forward-declare more in the
@@ -97,7 +126,9 @@ inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item,
unsigned end_offset) {
DCHECK_LE(end_offset, item.EndOffset());
return &item_results_->emplace_back(&item, item_index_, offset_, end_offset,
- ShouldCreateLineBox(*item_results_));
+ break_anywhere_if_overflow_,
+ ShouldCreateLineBox(*item_results_),
+ HasUnpositionedFloats(*item_results_));
}
inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item) {
@@ -191,12 +222,11 @@ void NGLineBreaker::NextLine(NGLineInfo* line_info) {
PrepareNextLine();
BreakLine();
- if (!trailing_spaces_collapsed_)
- RemoveTrailingCollapsibleSpace();
+ RemoveTrailingCollapsibleSpace();
#if DCHECK_IS_ON()
for (const auto& result : *item_results_)
- result.CheckConsistency();
+ result.CheckConsistency(mode_ == NGLineBreakerMode::kMinContent);
#endif
// We should create a line-box when:
@@ -215,6 +245,9 @@ void NGLineBreaker::NextLine(NGLineInfo* line_info) {
if (!should_create_line_box)
line_info_->SetIsEmptyLine();
line_info_->SetEndItemIndex(item_index_);
+ DCHECK_NE(trailing_whitespace_, WhitespaceState::kUnknown);
+ if (trailing_whitespace_ == WhitespaceState::kPreserved)
+ line_info_->SetHasTrailingSpaces();
ComputeLineLocation();
@@ -224,7 +257,8 @@ void NGLineBreaker::NextLine(NGLineInfo* line_info) {
void NGLineBreaker::BreakLine() {
const Vector<NGInlineItem>& items = Items();
- state_ = LineBreakState::kLeading;
+ state_ = LineBreakState::kContinue;
+ trailing_whitespace_ = WhitespaceState::kLeading;
while (state_ != LineBreakState::kDone) {
// Check overflow even if |item_index_| is at the end of the block, because
// the last item of the block may have caused overflow. In that case,
@@ -273,6 +307,15 @@ void NGLineBreaker::BreakLine() {
// opportunity if we're trailing.
if (state_ == LineBreakState::kTrailing &&
CanBreakAfterLast(*item_results_)) {
+ if (sticky_images_quirk_ && IsImage(item) &&
+ (trailing_whitespace_ == WhitespaceState::kNone ||
+ trailing_whitespace_ == WhitespaceState::kUnknown)) {
+ // If this is an image that follows text that doesn't end with something
+ // breakable, we cannot break between the two items.
+ HandleAtomicInline(item);
+ continue;
+ }
+
line_info_->SetIsLastLine(false);
return;
}
@@ -341,8 +384,7 @@ void NGLineBreaker::HandleText(const NGInlineItem& item) {
// Skip leading collapsible spaces.
// Most cases such spaces are handled as trailing spaces of the previous line,
// but there are some cases doing so is too complex.
- if (state_ == LineBreakState::kLeading) {
- state_ = LineBreakState::kContinue;
+ if (trailing_whitespace_ == WhitespaceState::kLeading) {
if (item.Style()->CollapseWhiteSpace() &&
Text()[offset_] == kSpaceCharacter) {
// Skipping one whitespace removes all collapsible spaces because
@@ -354,14 +396,20 @@ void NGLineBreaker::HandleText(const NGInlineItem& item) {
return;
}
}
+ // |trailing_whitespace_| will be updated as we read the text.
}
NGInlineItemResult* item_result = AddItem(item);
item_result->should_create_line_box = true;
- LayoutUnit available_width = AvailableWidthToFit();
if (auto_wrap_) {
+ if (mode_ == NGLineBreakerMode::kMinContent &&
+ HandleTextForFastMinContent(item_result, item)) {
+ return;
+ }
+
// Try to break inside of this text item.
+ LayoutUnit available_width = AvailableWidthToFit();
BreakText(item_result, item, available_width - position_);
if (item.IsSymbolMarker()) {
@@ -423,11 +471,22 @@ void NGLineBreaker::BreakText(NGInlineItemResult* item_result,
// expensive?
DCHECK_EQ(item.TextShapeResult()->StartIndex(), item.StartOffset());
DCHECK_EQ(item.TextShapeResult()->EndIndex(), item.EndOffset());
- RunSegmenter::RunSegmenterRange segment_range =
- item.CreateRunSegmenterRange();
- ShapingLineBreaker breaker(&shaper_, &item.Style()->GetFont(),
- item.TextShapeResult(), &break_iterator_,
- &segment_range, &spacing_, hyphenation_);
+ struct ShapeCallbackContext {
+ STACK_ALLOCATED();
+
+ public:
+ NGLineBreaker* line_breaker;
+ const NGInlineItem& item;
+ } shape_callback_context{this, item};
+ const ShapingLineBreaker::ShapeCallback shape_callback =
+ [](void* untyped_context, unsigned start, unsigned end) {
+ ShapeCallbackContext* context =
+ static_cast<ShapeCallbackContext*>(untyped_context);
+ return context->line_breaker->ShapeText(context->item, start, end);
+ };
+ ShapingLineBreaker breaker(item.TextShapeResult(), &break_iterator_,
+ hyphenation_, shape_callback,
+ &shape_callback_context);
if (!enable_soft_hyphen_)
breaker.DisableSoftHyphen();
available_width = std::max(LayoutUnit(0), available_width);
@@ -480,25 +539,139 @@ void NGLineBreaker::BreakText(NGInlineItemResult* item_result,
// beyond the end.
if (item_result->end_offset < item.EndOffset()) {
item_result->can_break_after = true;
+
+ DCHECK_EQ(break_iterator_.BreakSpace(), BreakSpaceType::kBeforeSpaceRun);
+ if (UNLIKELY(break_iterator_.BreakType() ==
+ LineBreakType::kBreakCharacter)) {
+ trailing_whitespace_ = WhitespaceState::kUnknown;
+ } else {
+ DCHECK_NE(Text()[item_result->end_offset - 1], kSpaceCharacter);
+ trailing_whitespace_ = WhitespaceState::kNone;
+ }
} else {
DCHECK_EQ(item_result->end_offset, item.EndOffset());
item_result->can_break_after =
break_iterator_.IsBreakable(item_result->end_offset);
+ trailing_whitespace_ = WhitespaceState::kUnknown;
+ }
+}
+
+// This function handles text item for min-content. The specialized logic is
+// because min-content is very expensive by breaking at every break opportunity
+// and producing as many lines as the number of break opportunities.
+//
+// This function breaks the text in NGInlineItem at every break opportunity,
+// computes the maximum width of all words, and creates one NGInlineItemResult
+// that has the maximum width. For example, for a text item of "1 2 34 5 6",
+// only the width of "34" matters for min-content.
+//
+// The first word and the last word, "1" and "6" in the example above, are
+// handled in normal |HandleText()| because they may form a word with the
+// previous/next item.
+bool NGLineBreaker::HandleTextForFastMinContent(NGInlineItemResult* item_result,
+ const NGInlineItem& item) {
+ DCHECK_EQ(mode_, NGLineBreakerMode::kMinContent);
+ DCHECK(auto_wrap_);
+ DCHECK_EQ(item.Type(), NGInlineItem::kText);
+
+ // If this is the first part of the text, it may form a word with the previous
+ // item. Fallback to |HandleText()|.
+ unsigned start_offset = item_result->start_offset;
+ DCHECK_LT(start_offset, item.EndOffset());
+ if (start_offset != line_info_->StartOffset() &&
+ start_offset == item.StartOffset())
+ return false;
+ // If this is the last part of the text, it may form a word with the next
+ // item. Fallback to |HandleText()|.
+ if (fast_min_content_item_ == &item)
+ return false;
+
+ // Hyphenation is not supported yet.
+ if (hyphenation_)
+ return false;
+
+ base::Optional<LineBreakType> saved_line_break_type;
+ if (break_anywhere_if_overflow_ && !override_break_anywhere_) {
+ saved_line_break_type = break_iterator_.BreakType();
+ break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
+ }
+
+ // Break the text at every break opportunity and measure each word.
+ DCHECK(item.TextShapeResult());
+ const ShapeResult& shape_result = *item.TextShapeResult();
+ DCHECK_EQ(shape_result.StartIndex(), item.StartOffset());
+ DCHECK_GE(start_offset, shape_result.StartIndex());
+ shape_result.EnsurePositionData();
+ const String& text = Text();
+ float min_width = 0;
+ unsigned last_end_offset = 0;
+ while (true) {
+ unsigned end_offset =
+ break_iterator_.NextBreakOpportunity(start_offset + 1);
+ if (end_offset >= item.EndOffset())
+ break;
+
+ // Inserting a hyphenation character is not supported yet.
+ if (text[end_offset - 1] == kSoftHyphenCharacter)
+ return false;
+
+ float start_position = shape_result.CachedPositionForOffset(
+ start_offset - shape_result.StartIndex());
+ float end_position = shape_result.CachedPositionForOffset(
+ end_offset - shape_result.StartIndex());
+ float word_width = IsLtr(shape_result.Direction())
+ ? end_position - start_position
+ : start_position - end_position;
+ min_width = std::max(word_width, min_width);
+
+ last_end_offset = end_offset;
+ start_offset = end_offset;
+ while (start_offset < item.EndOffset() &&
+ text[start_offset] == kSpaceCharacter) {
+ ++start_offset;
+ }
}
+
+ if (saved_line_break_type.has_value())
+ break_iterator_.SetBreakType(saved_line_break_type.value());
+
+ // If there was only one break opportunity in this item, it may form a word
+ // with previous and/or next item. Fallback to |HandleText()|.
+ if (!last_end_offset)
+ return false;
+
+ // Create an NGInlineItemResult that has the max of widths of all words.
+ item_result->end_offset = last_end_offset;
+ item_result->inline_size = LayoutUnit::FromFloatCeil(min_width);
+ item_result->can_break_after = true;
+
+ trailing_whitespace_ = WhitespaceState::kUnknown;
+ position_ += item_result->inline_size;
+ state_ = LineBreakState::kTrailing;
+ fast_min_content_item_ = &item;
+ MoveToNextOf(*item_result);
+ return true;
}
// Re-shape the specified range of |NGInlineItem|.
scoped_refptr<ShapeResult> NGLineBreaker::ShapeText(const NGInlineItem& item,
unsigned start,
unsigned end) {
- RunSegmenter::RunSegmenterRange segment_range =
- item.CreateRunSegmenterRange();
- scoped_refptr<ShapeResult> result = shaper_.Shape(
- &item.Style()->GetFont(), item.TextShapeResult()->Direction(), start, end,
- &segment_range);
+ scoped_refptr<ShapeResult> shape_result;
+ if (!items_data_.segments) {
+ RunSegmenter::RunSegmenterRange segment_range =
+ item.CreateRunSegmenterRange();
+ shape_result = shaper_.Shape(&item.Style()->GetFont(),
+ item.TextShapeResult()->Direction(), start,
+ end, &segment_range);
+ } else {
+ shape_result = items_data_.segments->ShapeText(
+ &shaper_, &item.Style()->GetFont(), item.TextShapeResult()->Direction(),
+ start, end, &item - items_data_.items.begin());
+ }
if (UNLIKELY(spacing_.HasSpacing()))
- result->ApplySpacing(spacing_);
- return result;
+ shape_result->ApplySpacing(spacing_);
+ return shape_result;
}
// Compute a new ShapeResult for the specified end offset.
@@ -561,7 +734,7 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item) {
// Skipping one whitespace removes all collapsible spaces because
// collapsible spaces are collapsed to single space in NGInlineItemBuilder.
offset_++;
- trailing_spaces_collapsed_ = true;
+ trailing_whitespace_ = WhitespaceState::kCollapsed;
// Make the last item breakable after, even if it was nowrap.
DCHECK(!item_results_->IsEmpty());
@@ -570,7 +743,6 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item) {
// Find the end of the run of space characters in this item.
// Other white space characters (e.g., tab) are not included in this item.
DCHECK(style.BreakOnlyAfterWhiteSpace());
- trailing_spaces_collapsed_ = true;
unsigned end = offset_;
while (end < item.EndOffset() && text[end] == kSpaceCharacter)
end++;
@@ -592,6 +764,7 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item) {
item_result->can_break_after =
end < text.length() && !IsBreakableSpace(text[end]);
offset_ = end;
+ trailing_whitespace_ = WhitespaceState::kPreserved;
}
// If non-space characters follow, the line is done.
@@ -608,12 +781,10 @@ void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item) {
// Remove trailing collapsible spaces in |line_info|.
// https://drafts.csswg.org/css-text-3/#white-space-phase-2
void NGLineBreaker::RemoveTrailingCollapsibleSpace() {
- DCHECK(!trailing_spaces_collapsed_);
-
ComputeTrailingCollapsibleSpace();
- trailing_spaces_collapsed_ = true;
- if (!trailing_collapsible_space_.has_value())
+ if (!trailing_collapsible_space_.has_value()) {
return;
+ }
// We have a trailing collapsible space. Remove it.
NGInlineItemResult* item_result = trailing_collapsible_space_->item_result;
@@ -629,13 +800,11 @@ void NGLineBreaker::RemoveTrailingCollapsibleSpace() {
item_results_->erase(item_result);
}
trailing_collapsible_space_.reset();
+ trailing_whitespace_ = WhitespaceState::kCollapsed;
}
// Compute the width of trailing spaces without removing it.
LayoutUnit NGLineBreaker::TrailingCollapsibleSpaceWidth() {
- if (trailing_spaces_collapsed_)
- return LayoutUnit();
-
ComputeTrailingCollapsibleSpace();
if (!trailing_collapsible_space_.has_value())
return LayoutUnit();
@@ -653,35 +822,59 @@ LayoutUnit NGLineBreaker::TrailingCollapsibleSpaceWidth() {
// Find trailing collapsible space if exists. The result is cached to
// |trailing_collapsible_space_|.
void NGLineBreaker::ComputeTrailingCollapsibleSpace() {
- DCHECK(!trailing_spaces_collapsed_);
+ if (trailing_whitespace_ == WhitespaceState::kLeading ||
+ trailing_whitespace_ == WhitespaceState::kNone ||
+ trailing_whitespace_ == WhitespaceState::kCollapsed ||
+ trailing_whitespace_ == WhitespaceState::kPreserved) {
+ trailing_collapsible_space_.reset();
+ return;
+ }
+ DCHECK(trailing_whitespace_ == WhitespaceState::kUnknown ||
+ trailing_whitespace_ == WhitespaceState::kCollapsible);
+ trailing_whitespace_ = WhitespaceState::kNone;
+ const String& text = Text();
for (auto it = item_results_->rbegin(); it != item_results_->rend(); ++it) {
NGInlineItemResult& item_result = *it;
DCHECK(item_result.item);
const NGInlineItem& item = *item_result.item;
if (item.EndCollapseType() == NGInlineItem::kOpaqueToCollapsing)
continue;
- if (item.Type() != NGInlineItem::kText)
- break;
- DCHECK_GT(item_result.end_offset, 0u);
- DCHECK(item.Style());
- if (Text()[item_result.end_offset - 1] != kSpaceCharacter ||
- !item.Style()->CollapseWhiteSpace() ||
- // |shape_result| is nullptr if this is an overflow because BreakText()
- // uses kNoResultIfOverflow option.
- !item_result.shape_result)
- break;
+ if (item.Type() == NGInlineItem::kText) {
+ DCHECK_GT(item_result.end_offset, 0u);
+ DCHECK(item.Style());
+ if (text[item_result.end_offset - 1] != kSpaceCharacter)
+ break;
+ if (!item.Style()->CollapseWhiteSpace()) {
+ trailing_whitespace_ = WhitespaceState::kPreserved;
+ break;
+ }
+ // |shape_result| is nullptr if this is an overflow because BreakText()
+ // uses kNoResultIfOverflow option.
+ if (!item_result.shape_result)
+ break;
- if (!trailing_collapsible_space_.has_value() ||
- trailing_collapsible_space_->item_result != &item_result) {
- trailing_collapsible_space_.emplace();
- trailing_collapsible_space_->item_result = &item_result;
- if (item_result.end_offset - 1 > item_result.start_offset) {
- trailing_collapsible_space_->collapsed_shape_result =
- TruncateLineEndResult(item_result, item_result.end_offset - 1);
+ if (!trailing_collapsible_space_.has_value() ||
+ trailing_collapsible_space_->item_result != &item_result) {
+ trailing_collapsible_space_.emplace();
+ trailing_collapsible_space_->item_result = &item_result;
+ if (item_result.end_offset - 1 > item_result.start_offset) {
+ trailing_collapsible_space_->collapsed_shape_result =
+ TruncateLineEndResult(item_result, item_result.end_offset - 1);
+ }
}
+ trailing_whitespace_ = WhitespaceState::kCollapsible;
+ return;
}
- return;
+ if (item.Type() == NGInlineItem::kControl) {
+ UChar character = text[item.StartOffset()];
+ if (character == kNewlineCharacter)
+ continue;
+ trailing_whitespace_ = WhitespaceState::kPreserved;
+ trailing_collapsible_space_.reset();
+ return;
+ }
+ break;
}
trailing_collapsible_space_.reset();
@@ -817,16 +1010,29 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item) {
// For the inline layout purpose, only inline-margins are needed, computed for
// the line's writing-mode.
- DCHECK(item.Style());
- const ComputedStyle& style = *item.Style();
- item_result->margins =
- ComputeLineMarginsForVisualContainer(constraint_space_, style);
- item_result->inline_size += item_result->margins.InlineSum();
+ if (item.Style()) {
+ const ComputedStyle& style = *item.Style();
+ item_result->margins =
+ ComputeLineMarginsForVisualContainer(constraint_space_, style);
+ item_result->inline_size += item_result->margins.InlineSum();
+ }
- if (state_ == LineBreakState::kLeading)
- state_ = LineBreakState::kContinue;
+ trailing_whitespace_ = WhitespaceState::kNone;
position_ += item_result->inline_size;
ComputeCanBreakAfter(item_result);
+
+ if (sticky_images_quirk_ && IsImage(item)) {
+ const auto& items = Items();
+ if (item_index_ + 1 < items.size()) {
+ DCHECK_EQ(&item, &items[item_index_]);
+ const auto& next_item = items[item_index_ + 1];
+ // This is an image, and we don't want to break after it, unless what
+ // comes after provides a break opportunity. Look ahead. We only want to
+ // break if the next item is an atomic inline that's not an image.
+ if (next_item.Type() != NGInlineItem::kAtomicInline || IsImage(next_item))
+ item_result->can_break_after = false;
+ }
+ }
MoveToNextOf(item);
}
@@ -857,24 +1063,31 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item) {
NGInlineItemResult* item_result = AddItem(item);
ComputeCanBreakAfter(item_result);
MoveToNextOf(item);
- if (item_index_ <= handled_floats_end_item_index_ || ignore_floats_)
+
+ // If we are currently computing our min/max-content size simply append to
+ // the unpositioned floats list and abort.
+ if (mode_ != NGLineBreakerMode::kContent) {
+ DCHECK(out_floats_for_min_max_);
+ out_floats_for_min_max_->push_back(item.GetLayoutObject());
return;
+ }
- NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
+ if (ignore_floats_)
+ return;
- const ComputedStyle& float_style = node.Style();
+ // Make sure we populate the positioned_float inside the |item_result|.
+ if (item_index_ <= handled_leading_floats_index_ &&
+ !leading_floats_.IsEmpty()) {
+ DCHECK_LT(leading_floats_index_, leading_floats_.size());
+ item_result->positioned_float = leading_floats_[leading_floats_index_++];
+ return;
+ }
// TODO(ikilpatrick): Add support for float break tokens inside an inline
// layout context.
- NGUnpositionedFloat unpositioned_float(node, /* break_token */ nullptr);
-
- // If we are currently computing our min/max-content size simply append
- // to the unpositioned floats list and abort.
- if (mode_ != NGLineBreakerMode::kContent) {
- AddUnpositionedFloat(unpositioned_floats_, container_builder_,
- std::move(unpositioned_float), constraint_space_);
- return;
- }
+ NGUnpositionedFloat unpositioned_float(
+ NGBlockNode(ToLayoutBox(item.GetLayoutObject())),
+ /* break_token */ nullptr);
LayoutUnit inline_margin_size =
ComputeMarginBoxInlineSizeForUnpositionedFloat(
@@ -882,18 +1095,18 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item) {
LayoutUnit bfc_block_offset = line_opportunity_.bfc_block_offset;
+ LayoutUnit used_size =
+ position_ + inline_margin_size + ComputeFloatAncestorInlineEndSize();
bool can_fit_float =
- position_ + inline_margin_size <=
- line_opportunity_.AvailableFloatInlineSize().AddEpsilon();
+ used_size <= line_opportunity_.AvailableFloatInlineSize().AddEpsilon();
if (!can_fit_float) {
// Floats need to know the current line width to determine whether to put it
// into the current line or to the next line. Trailing spaces will be
// removed if this line breaks here because they should be collapsed across
// floats, but they are still included in the current line position at this
// point. Exclude it when computing whether this float can fit or not.
- can_fit_float =
- position_ + inline_margin_size - TrailingCollapsibleSpaceWidth() <=
- line_opportunity_.AvailableFloatInlineSize().AddEpsilon();
+ can_fit_float = used_size - TrailingCollapsibleSpaceWidth() <=
+ line_opportunity_.AvailableFloatInlineSize().AddEpsilon();
}
// The float should be positioned after the current line if:
@@ -904,15 +1117,13 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item) {
bool float_after_line =
!can_fit_float ||
exclusion_space_->LastFloatBlockStart() > bfc_block_offset ||
- exclusion_space_->ClearanceOffset(
- ResolvedClear(float_style.Clear(), constraint_space_.Direction())) >
- bfc_block_offset;
+ exclusion_space_->ClearanceOffset(unpositioned_float.ClearType(
+ constraint_space_.Direction())) > bfc_block_offset;
// Check if we already have a pending float. That's because a float cannot be
// higher than any block or floated box generated before.
- if (!unpositioned_floats_->IsEmpty() || float_after_line) {
- AddUnpositionedFloat(unpositioned_floats_, container_builder_,
- std::move(unpositioned_float), constraint_space_);
+ if (HasUnpositionedFloats(*item_results_) || float_after_line) {
+ item_result->has_unpositioned_floats = true;
} else {
NGPositionedFloat positioned_float = PositionFloat(
constraint_space_.AvailableSize(),
@@ -921,7 +1132,8 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item) {
{constraint_space_.BfcOffset().line_offset, bfc_block_offset},
&unpositioned_float, constraint_space_, node_.Style(),
exclusion_space_);
- positioned_floats_->push_back(positioned_float);
+
+ item_result->positioned_float = positioned_float;
NGLayoutOpportunity opportunity = exclusion_space_->FindLayoutOpportunity(
{constraint_space_.BfcOffset().line_offset, bfc_block_offset},
@@ -936,6 +1148,39 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item) {
}
}
+// To correctly determine if a float is allowed to be on the same line as its
+// content, we need to determine if it has any ancestors with inline-end
+// padding, border, or margin.
+// The inline-end size from all of these ancestors contribute to the "used
+// size" of the float, and may cause the float to be pushed down.
+LayoutUnit NGLineBreaker::ComputeFloatAncestorInlineEndSize() const {
+ const Vector<NGInlineItem>& items = Items();
+ wtf_size_t item_index = item_index_;
+
+ LayoutUnit inline_end_size;
+ while (item_index < items.size()) {
+ const NGInlineItem& item = items[item_index++];
+
+ if (item.Type() == NGInlineItem::kCloseTag) {
+ if (item.HasEndEdge()) {
+ inline_end_size +=
+ ComputeInlineEndSize(constraint_space_, item.Style());
+ }
+ continue;
+ }
+
+ // For this calculation, any open tag (even if its empty) stops this
+ // calculation, and allows the float to appear on the same line. E.g.
+ // <span style="padding-right: 20px;"><f></f><span></span></span>
+ //
+ // Any non-empty item also allows the float to be on the same line.
+ if (item.Type() == NGInlineItem::kOpenTag || !item.IsEmptyItem())
+ break;
+ }
+
+ return inline_end_size;
+}
+
bool NGLineBreaker::ComputeOpenTagResult(
const NGInlineItem& item,
const NGConstraintSpace& constraint_space,
@@ -983,15 +1228,11 @@ void NGLineBreaker::HandleOpenTag(const NGInlineItem& item) {
void NGLineBreaker::HandleCloseTag(const NGInlineItem& item) {
NGInlineItemResult* item_result = AddItem(item);
+
item_result->has_edge = item.HasEndEdge();
if (item_result->has_edge) {
- DCHECK(item.Style());
- const ComputedStyle& style = *item.Style();
- NGBoxStrut margins = ComputeMarginsForSelf(constraint_space_, style);
- NGBoxStrut borders = ComputeBorders(constraint_space_, style);
- NGBoxStrut paddings = ComputePadding(constraint_space_, style);
item_result->inline_size =
- margins.inline_end + borders.inline_end + paddings.inline_end;
+ ComputeInlineEndSize(constraint_space_, item.Style());
position_ += item_result->inline_size;
if (!item_result->should_create_line_box && !item.IsEmptyItem())
@@ -1036,14 +1277,21 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item) {
// At this point, item_results does not fit into the current line, and there
// are no break opportunities in item_results.back().
void NGLineBreaker::HandleOverflow() {
+ // Compute the width needing to rewind. When |width_to_rewind| goes negative,
+ // items can fit within the line.
LayoutUnit available_width = AvailableWidthToFit();
LayoutUnit width_to_rewind = position_ - available_width;
DCHECK_GT(width_to_rewind, 0);
+
+ // Indicates positions of items may be changed and need to UpdatePosition().
bool position_maybe_changed = false;
// Keep track of the shortest break opportunity.
unsigned break_before = 0;
+ // True if there is at least one item that has `break-word`.
+ bool has_break_anywhere_if_overflow = break_anywhere_if_overflow_;
+
// Search for a break opportunity that can fit.
for (unsigned i = item_results_->size(); i;) {
NGInlineItemResult* item_result = &(*item_results_)[--i];
@@ -1060,60 +1308,69 @@ void NGLineBreaker::HandleOverflow() {
}
// Try to break inside of this item.
- LayoutUnit next_width_to_rewind =
- width_to_rewind - item_result->inline_size;
+ width_to_rewind -= item_result->inline_size;
DCHECK(item_result->item);
const NGInlineItem& item = *item_result->item;
- if (item.Type() == NGInlineItem::kText && next_width_to_rewind < 0 &&
- (item_result->may_break_inside || override_break_anywhere_)) {
- // When the text fits but its right margin does not, the break point
- // must not be at the end.
- LayoutUnit item_available_width =
- std::min(-next_width_to_rewind, item_result->inline_size - 1);
- SetCurrentStyle(*item.Style());
- BreakText(item_result, item, item_available_width);
+ if (item.Type() == NGInlineItem::kText) {
+ DCHECK(item_result->shape_result ||
+ (item_result->break_anywhere_if_overflow &&
+ !override_break_anywhere_));
+ if (width_to_rewind < 0 && item_result->may_break_inside) {
+ // When the text fits but its right margin does not, the break point
+ // must not be at the end.
+ LayoutUnit item_available_width =
+ std::min(-width_to_rewind, item_result->inline_size - 1);
+ SetCurrentStyle(*item.Style());
+ BreakText(item_result, item, item_available_width);
#if DCHECK_IS_ON()
- item_result->CheckConsistency(true);
+ item_result->CheckConsistency(true);
#endif
- // If BreakText() changed this item small enough to fit, break here.
- if (item_result->inline_size <= item_available_width) {
- DCHECK(item_result->end_offset < item.EndOffset());
- DCHECK(item_result->can_break_after);
- DCHECK_LE(i + 1, item_results_->size());
- if (i + 1 == item_results_->size()) {
- // If this is the last item, adjust states to accomodate the change.
- position_ =
- available_width + next_width_to_rewind + item_result->inline_size;
- if (line_info_->LineEndFragment())
- SetLineEndFragment(nullptr);
- DCHECK_EQ(position_, line_info_->ComputeWidth());
- item_index_ = item_result->item_index;
- offset_ = item_result->end_offset;
- items_data_.AssertOffset(item_index_, offset_);
- } else {
- Rewind(i + 1);
+ // If BreakText() changed this item small enough to fit, break here.
+ if (item_result->inline_size <= item_available_width) {
+ DCHECK(item_result->end_offset < item.EndOffset());
+ DCHECK(item_result->can_break_after);
+ DCHECK_LE(i + 1, item_results_->size());
+ if (i + 1 == item_results_->size()) {
+ // If this is the last item, adjust states to accomodate the change.
+ position_ =
+ available_width + width_to_rewind + item_result->inline_size;
+ if (line_info_->LineEndFragment())
+ SetLineEndFragment(nullptr);
+ DCHECK_EQ(position_, line_info_->ComputeWidth());
+ item_index_ = item_result->item_index;
+ offset_ = item_result->end_offset;
+ items_data_.AssertOffset(item_index_, offset_);
+ } else {
+ Rewind(i + 1);
+ }
+ state_ = LineBreakState::kTrailing;
+ return;
}
- state_ = LineBreakState::kTrailing;
- return;
+ position_maybe_changed = true;
}
- position_maybe_changed = true;
}
- width_to_rewind = next_width_to_rewind;
+ has_break_anywhere_if_overflow |= item_result->break_anywhere_if_overflow;
}
// Reaching here means that the rewind point was not found.
- if (break_anywhere_if_overflow_ && !override_break_anywhere_) {
+ if (!override_break_anywhere_ && has_break_anywhere_if_overflow) {
override_break_anywhere_ = true;
break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
+ // TODO(kojii): Not all items need to rewind, but such case is rare and
+ // rewinding all items simplifes the code.
if (!item_results_->IsEmpty())
Rewind(0);
- state_ = LineBreakState::kLeading;
+ state_ = LineBreakState::kContinue;
+ trailing_whitespace_ = WhitespaceState::kLeading;
+ SetCurrentStyle(line_info_->LineStyle());
return;
}
// Let this line overflow.
+ line_info_->SetHasOverflow();
+
// If there was a break opportunity, the overflow should stop there.
if (break_before) {
Rewind(break_before);
@@ -1122,6 +1379,7 @@ void NGLineBreaker::HandleOverflow() {
}
if (position_maybe_changed) {
+ trailing_whitespace_ = WhitespaceState::kUnknown;
UpdatePosition();
}
@@ -1148,20 +1406,17 @@ void NGLineBreaker::Rewind(unsigned new_end) {
// rewinding them needs to remove from these lists too.
for (unsigned i = item_results.size(); i > new_end;) {
NGInlineItemResult& rewind = item_results[--i];
- if (rewind.item->Type() == NGInlineItem::kFloating) {
- NGBlockNode float_node(ToLayoutBox(rewind.item->GetLayoutObject()));
- if (!RemoveUnpositionedFloat(unpositioned_floats_, float_node)) {
- // TODO(kojii): We do not have mechanism to remove once positioned
- // floats yet, and that rewinding them may lay it out twice. For now,
- // prohibit rewinding positioned floats. This may results in incorrect
- // layout, but still better than rewinding them.
- new_end = i + 1;
- if (new_end == item_results.size()) {
- UpdatePosition();
- return;
- }
- break;
+ if (rewind.positioned_float) {
+ // TODO(kojii): We do not have mechanism to remove once positioned floats
+ // yet, and that rewinding them may lay it out twice. For now, prohibit
+ // rewinding positioned floats. This may results in incorrect layout, but
+ // still better than rewinding them.
+ new_end = i + 1;
+ if (new_end == item_results.size()) {
+ UpdatePosition();
+ return;
}
+ break;
}
}
@@ -1178,7 +1433,7 @@ void NGLineBreaker::Rewind(unsigned new_end) {
item_results.Shrink(new_end);
- trailing_spaces_collapsed_ = false;
+ trailing_whitespace_ = WhitespaceState::kUnknown;
trailing_collapsible_space_.reset();
SetLineEndFragment(nullptr);
UpdatePosition();
@@ -1188,29 +1443,30 @@ void NGLineBreaker::SetCurrentStyle(const ComputedStyle& style) {
auto_wrap_ = style.AutoWrap();
if (auto_wrap_) {
- if (UNLIKELY(override_break_anywhere_)) {
- break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
- } else {
- switch (style.WordBreak()) {
- case EWordBreak::kNormal:
- break_anywhere_if_overflow_ =
- style.OverflowWrap() == EOverflowWrap::kBreakWord;
- break_iterator_.SetBreakType(LineBreakType::kNormal);
- break;
- case EWordBreak::kBreakAll:
- break_anywhere_if_overflow_ = false;
- break_iterator_.SetBreakType(LineBreakType::kBreakAll);
- break;
- case EWordBreak::kBreakWord:
- break_anywhere_if_overflow_ = true;
- break_iterator_.SetBreakType(LineBreakType::kNormal);
- break;
- case EWordBreak::kKeepAll:
- break_anywhere_if_overflow_ = false;
- break_iterator_.SetBreakType(LineBreakType::kKeepAll);
- break;
- }
+ LineBreakType line_break_type;
+ switch (style.WordBreak()) {
+ case EWordBreak::kNormal:
+ break_anywhere_if_overflow_ =
+ style.OverflowWrap() == EOverflowWrap::kBreakWord &&
+ mode_ == NGLineBreakerMode::kContent;
+ line_break_type = LineBreakType::kNormal;
+ break;
+ case EWordBreak::kBreakAll:
+ break_anywhere_if_overflow_ = false;
+ line_break_type = LineBreakType::kBreakAll;
+ break;
+ case EWordBreak::kBreakWord:
+ break_anywhere_if_overflow_ = true;
+ line_break_type = LineBreakType::kNormal;
+ break;
+ case EWordBreak::kKeepAll:
+ break_anywhere_if_overflow_ = false;
+ line_break_type = LineBreakType::kKeepAll;
+ break;
}
+ if (UNLIKELY(override_break_anywhere_ && break_anywhere_if_overflow_))
+ line_break_type = LineBreakType::kBreakCharacter;
+ break_iterator_.SetBreakType(line_break_type);
enable_soft_hyphen_ = style.GetHyphens() != Hyphens::kNone;
hyphenation_ = style.GetHyphenation();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 987037c1666..3fa2b3f4b53 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -18,10 +18,8 @@
namespace blink {
class Hyphenation;
-class NGContainerFragmentBuilder;
class NGInlineBreakToken;
class NGInlineItem;
-struct NGPositionedFloat;
// The line breaker needs to know which mode its in to properly handle floats.
enum class NGLineBreakerMode { kContent, kMinContent, kMaxContent };
@@ -37,13 +35,12 @@ class CORE_EXPORT NGLineBreaker {
NGLineBreaker(NGInlineNode,
NGLineBreakerMode,
const NGConstraintSpace&,
- Vector<NGPositionedFloat>*,
- NGUnpositionedFloatVector*,
- NGContainerFragmentBuilder* container_builder,
- NGExclusionSpace*,
- unsigned handled_float_index,
const NGLineLayoutOpportunity&,
- const NGInlineBreakToken* = nullptr);
+ const NGPositionedFloatVector& leading_floats,
+ unsigned handled_leading_floats_index,
+ const NGInlineBreakToken*,
+ NGExclusionSpace*,
+ Vector<LayoutObject*>* out_floats_for_min_max = nullptr);
~NGLineBreaker();
// Compute the next line break point and produces NGInlineItemResults for
@@ -61,6 +58,20 @@ class CORE_EXPORT NGLineBreaker {
const NGConstraintSpace&,
NGInlineItemResult*);
+ // This enum is private, except for |WhitespaceStateForTesting()|. See
+ // |whitespace_| member.
+ enum class WhitespaceState {
+ kLeading,
+ kNone,
+ kUnknown,
+ kCollapsible,
+ kCollapsed,
+ kPreserved,
+ };
+ WhitespaceState TrailingWhitespaceForTesting() const {
+ return trailing_whitespace_;
+ }
+
private:
const String& Text() const { return items_data_.text_content; }
const Vector<NGInlineItem>& Items() const { return items_data_.items; }
@@ -86,9 +97,6 @@ class CORE_EXPORT NGLineBreaker {
// when it is overflowing.
kTrailing,
- // The initial state, until the first character is found.
- kLeading,
-
// Looking for more items to fit into the current line.
kContinue,
};
@@ -97,6 +105,8 @@ class CORE_EXPORT NGLineBreaker {
void BreakText(NGInlineItemResult*,
const NGInlineItem&,
LayoutUnit available_width);
+ bool HandleTextForFastMinContent(NGInlineItemResult* item_result,
+ const NGInlineItem& item);
scoped_refptr<ShapeResultView> TruncateLineEndResult(
const NGInlineItemResult& item_result,
@@ -118,6 +128,8 @@ class CORE_EXPORT NGLineBreaker {
void HandleAtomicInline(const NGInlineItem&);
void HandleFloat(const NGInlineItem&);
+ LayoutUnit ComputeFloatAncestorInlineEndSize() const;
+
void HandleOpenTag(const NGInlineItem&);
void HandleCloseTag(const NGInlineItem&);
@@ -149,6 +161,10 @@ class CORE_EXPORT NGLineBreaker {
unsigned item_index_ = 0;
unsigned offset_ = 0;
+ // |WhitespaceState| of the current end. When a line is broken, this indicates
+ // the state of trailing whitespaces.
+ WhitespaceState trailing_whitespace_;
+
// The current position from inline_start. Unlike NGInlineLayoutAlgorithm
// that computes position in visual order, this position in logical order.
LayoutUnit position_;
@@ -168,8 +184,9 @@ class CORE_EXPORT NGLineBreaker {
// True when current box has 'word-break/word-wrap: break-word'.
bool break_anywhere_if_overflow_ = false;
- // Force LineBreakType::kBreakCharacter by ignoring the current style.
- // Set to find grapheme cluster boundaries for 'break-word' after overflow.
+ // Force LineBreakType::kBreakCharacter by ignoring the current style if
+ // |break_anywhere_if_overflow_| is set. Set to find grapheme cluster
+ // boundaries for 'break-word' after overflow.
bool override_break_anywhere_ = false;
// True when breaking at soft hyphens (U+00AD) is allowed.
@@ -183,22 +200,20 @@ class CORE_EXPORT NGLineBreaker {
// True when the line we are breaking has a list marker.
bool has_list_marker_ = false;
- // True if trailing collapsible spaces have been collapsed.
- bool trailing_spaces_collapsed_ = false;
-
// Set when the line ended with a forced break. Used to setup the states for
// the next line.
bool is_after_forced_break_ = false;
bool ignore_floats_ = false;
+ // Set in quirks mode when we're not supposed to break inside table cells
+ // between images, and between text and images.
+ bool sticky_images_quirk_ = false;
+
const NGInlineItemsData& items_data_;
NGLineBreakerMode mode_;
const NGConstraintSpace& constraint_space_;
- Vector<NGPositionedFloat>* positioned_floats_;
- NGUnpositionedFloatVector* unpositioned_floats_;
- NGContainerFragmentBuilder* container_builder_; /* May be nullptr */
NGExclusionSpace* exclusion_space_;
scoped_refptr<const ComputedStyle> current_style_;
@@ -217,7 +232,15 @@ class CORE_EXPORT NGLineBreaker {
base::Optional<TrailingCollapsibleSpace> trailing_collapsible_space_;
// Keep track of handled float items. See HandleFloat().
- unsigned handled_floats_end_item_index_;
+ const NGPositionedFloatVector& leading_floats_;
+ unsigned leading_floats_index_ = 0u;
+ unsigned handled_leading_floats_index_;
+
+ Vector<LayoutObject*>* out_floats_for_min_max_;
+
+ // Keep the last item |HandleTextForFastMinContent()| has handled. This is
+ // used to fallback the last word to |HandleText()|.
+ const NGInlineItem* fast_min_content_item_ = nullptr;
// The current base direction for the bidi algorithm.
// This is copied from NGInlineNode, then updated after each forced line break
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index 53f11d1ac57..49d3006ff94 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -17,7 +17,7 @@
namespace blink {
-class NGLineBreakerTest : public NGBaseLayoutAlgorithmTest {
+class NGLineBreakerTest : public NGLayoutTest {
protected:
NGInlineNode CreateInlineNode(const String& html_content) {
SetBodyInnerHTML(html_content);
@@ -28,8 +28,8 @@ class NGLineBreakerTest : public NGBaseLayoutAlgorithmTest {
}
// Break lines using the specified available width.
- Vector<NGInlineItemResults> BreakLines(NGInlineNode node,
- LayoutUnit available_width) {
+ Vector<NGLineInfo> BreakToLineInfo(NGInlineNode node,
+ LayoutUnit available_width) {
DCHECK(node);
node.PrepareLayoutIfNeeded();
@@ -41,32 +41,41 @@ class NGLineBreakerTest : public NGBaseLayoutAlgorithmTest {
.SetAvailableSize({available_width, NGSizeIndefinite})
.ToConstraintSpace();
- Vector<NGPositionedFloat> positioned_floats;
- NGUnpositionedFloatVector unpositioned_floats;
-
scoped_refptr<NGInlineBreakToken> break_token;
- Vector<NGInlineItemResults> lines;
+ Vector<NGLineInfo> line_infos;
+ trailing_whitespaces_.resize(0);
NGExclusionSpace exclusion_space;
+ NGPositionedFloatVector leading_floats;
NGLineLayoutOpportunity line_opportunity(available_width);
while (!break_token || !break_token->IsFinished()) {
- NGLineInfo line_info;
+ NGLineInfo& line_info = line_infos.emplace_back();
NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, space,
- &positioned_floats, &unpositioned_floats,
- /* container_builder */ nullptr,
- &exclusion_space, 0u, line_opportunity,
- break_token.get());
+ line_opportunity, leading_floats, 0u,
+ break_token.get(), &exclusion_space);
line_breaker.NextLine(&line_info);
+ trailing_whitespaces_.push_back(
+ line_breaker.TrailingWhitespaceForTesting());
if (line_info.Results().IsEmpty())
break;
break_token = line_breaker.CreateBreakToken(line_info);
- lines.push_back(std::move(line_info.Results()));
}
+ return line_infos;
+ }
+
+ Vector<NGInlineItemResults> BreakLines(NGInlineNode node,
+ LayoutUnit available_width) {
+ Vector<NGLineInfo> line_infos = BreakToLineInfo(node, available_width);
+ Vector<NGInlineItemResults> lines;
+ for (NGLineInfo& line_info : line_infos)
+ lines.push_back(std::move(line_info.Results()));
return lines;
}
+
+ Vector<NGLineBreaker::WhitespaceState> trailing_whitespaces_;
};
namespace {
@@ -312,6 +321,138 @@ TEST_F(NGLineBreakerTest, BoundaryInFirstWord) {
EXPECT_EQ("789", ToString(lines[1], node));
}
+struct WhitespaceStateTestData {
+ const char* html;
+ const char* white_space;
+ NGLineBreaker::WhitespaceState expected;
+} whitespace_state_test_data[] = {
+ // The most common cases.
+ {"12", "normal", NGLineBreaker::WhitespaceState::kNone},
+ {"1234 5678", "normal", NGLineBreaker::WhitespaceState::kCollapsed},
+ // |NGInlineItemsBuilder| collapses trailing spaces of a block, so
+ // |NGLineBreaker| computes to `none`.
+ {"12 ", "normal", NGLineBreaker::WhitespaceState::kNone},
+ // pre/pre-wrap should preserve trailing spaces if exists.
+ {"1234 5678", "pre-wrap", NGLineBreaker::WhitespaceState::kPreserved},
+ {"12 ", "pre", NGLineBreaker::WhitespaceState::kPreserved},
+ {"12 ", "pre-wrap", NGLineBreaker::WhitespaceState::kPreserved},
+ {"12", "pre", NGLineBreaker::WhitespaceState::kNone},
+ {"12", "pre-wrap", NGLineBreaker::WhitespaceState::kNone},
+ // Empty/space-only cases.
+ {"", "normal", NGLineBreaker::WhitespaceState::kLeading},
+ {" ", "pre", NGLineBreaker::WhitespaceState::kPreserved},
+ {" ", "pre-wrap", NGLineBreaker::WhitespaceState::kPreserved},
+ // Cases needing to rewind.
+ {"12 34<span>56</span>", "normal",
+ NGLineBreaker::WhitespaceState::kCollapsed},
+ {"12 34<span>56</span>", "pre-wrap",
+ NGLineBreaker::WhitespaceState::kPreserved},
+ // Atomic inlines.
+ {"12 <span style='display: inline-block'></span>", "normal",
+ NGLineBreaker::WhitespaceState::kNone},
+ // fast/text/whitespace/inline-whitespace-wrapping-4.html
+ {"<span style='white-space: nowrap'>1234 </span>"
+ "<span style='white-space: normal'> 5678</span>",
+ "pre", NGLineBreaker::WhitespaceState::kCollapsed},
+};
+
+std::ostream& operator<<(std::ostream& os,
+ const WhitespaceStateTestData& data) {
+ return os << static_cast<int>(data.expected) << " for '" << data.html
+ << "' with 'white-space: " << data.white_space << "'";
+}
+
+class NGWhitespaceStateTest
+ : public NGLineBreakerTest,
+ public testing::WithParamInterface<WhitespaceStateTestData> {};
+
+INSTANTIATE_TEST_CASE_P(NGLineBreakerTest,
+ NGWhitespaceStateTest,
+ testing::ValuesIn(whitespace_state_test_data));
+
+TEST_P(NGWhitespaceStateTest, WhitespaceState) {
+ const auto& data = GetParam();
+ LoadAhem();
+ NGInlineNode node = CreateInlineNode(String(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ #container {
+ font: 10px/1 Ahem;
+ width: 50px;
+ white-space: )HTML") + data.white_space +
+ R"HTML(
+ }
+ </style>
+ <div id=container>)HTML" + data.html +
+ R"HTML(</div>
+ )HTML");
+
+ Vector<NGLineInfo> line_infos = BreakToLineInfo(node, LayoutUnit(50));
+ EXPECT_EQ(trailing_whitespaces_[0], data.expected);
+}
+
+struct TrailingSpaceWidthTestData {
+ const char* html;
+ const char* white_space;
+ unsigned trailing_space_width;
+} trailing_space_width_test_data[] = {
+ {" ", "pre", 1},
+ {" ", "pre", 3},
+ {"1 ", "pre", 1},
+ {"1 ", "pre", 2},
+ {"1<span> </span>", "pre", 1},
+ {"<span>1 </span> ", "pre", 2},
+ {"1<span> </span> ", "pre", 2},
+ {"1 <span> </span> ", "pre", 3},
+ {"1 \t", "pre", 3},
+ {"1 \n", "pre", 2},
+ {"1 <br>", "pre", 2},
+
+ {" ", "pre-wrap", 1},
+ {" ", "pre-wrap", 3},
+ {"1 ", "pre-wrap", 1},
+ {"1 ", "pre-wrap", 2},
+ {"1<span> </span>", "pre-wrap", 1},
+ {"<span>1 </span> ", "pre-wrap", 2},
+ {"1<span> </span> ", "pre-wrap", 2},
+ {"1 <span> </span> ", "pre-wrap", 3},
+ {"1 \t", "pre-wrap", 3},
+ {"1 <br>", "pre-wrap", 2},
+ {"12 1234", "pre-wrap", 1},
+ {"12 1234", "pre-wrap", 2},
+};
+
+class NGTrailingSpaceWidthTest
+ : public NGLineBreakerTest,
+ public testing::WithParamInterface<TrailingSpaceWidthTestData> {};
+
+INSTANTIATE_TEST_CASE_P(NGLineBreakerTest,
+ NGTrailingSpaceWidthTest,
+ testing::ValuesIn(trailing_space_width_test_data));
+
+TEST_P(NGTrailingSpaceWidthTest, TrailingSpaceWidth) {
+ const auto& data = GetParam();
+ LoadAhem();
+ NGInlineNode node = CreateInlineNode(String(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ #container {
+ font: 10px/1 Ahem;
+ width: 50px;
+ tab-size: 2;
+ white-space: )HTML") + data.white_space +
+ R"HTML(;
+ }
+ </style>
+ <div id=container>)HTML" + data.html +
+ R"HTML(</div>
+ )HTML");
+
+ Vector<NGLineInfo> line_infos = BreakToLineInfo(node, LayoutUnit(50));
+ EXPECT_EQ(line_infos[0].ComputeTrailingSpaceWidth(),
+ LayoutUnit(10) * data.trailing_space_width);
+}
+
#undef MAYBE_OverflowAtomicInline
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc
index d7bcbb8a951..79b7bba0bc8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc
@@ -12,7 +12,9 @@ NGLineHeightMetrics::NGLineHeightMetrics(const ComputedStyle& style,
FontBaseline baseline_type) {
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
DCHECK(font_data);
- Initialize(font_data->GetFontMetrics(), baseline_type);
+ // TODO(kojii): This should not be null, but it happens. Avoid crash for now.
+ if (font_data)
+ Initialize(font_data->GetFontMetrics(), baseline_type);
}
NGLineHeightMetrics::NGLineHeightMetrics(const ComputedStyle& style)
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
index de77686df59..a478b7fb7e8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
@@ -6,9 +6,11 @@
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/platform/text/character.h"
@@ -17,6 +19,11 @@ namespace blink {
namespace {
+// Note: LayoutFlowThread, used for multicol, can't provide offset mapping.
+bool CanUseNGOffsetMapping(const LayoutObject& object) {
+ return object.IsLayoutBlockFlow() && !object.IsLayoutFlowThread();
+}
+
// Returns true if |node| has style 'display:inline' and can have descendants
// in the inline layout.
bool IsNonAtomicInline(const Node& node) {
@@ -57,12 +64,24 @@ std::pair<const Node&, unsigned> ToNodeOffsetPair(const Position& position) {
LayoutBlockFlow* NGInlineFormattingContextOf(const Position& position) {
if (!RuntimeEnabledFeatures::LayoutNGEnabled())
return nullptr;
- if (!NGOffsetMapping::AcceptsPosition(position))
+ LayoutBlockFlow* block_flow =
+ NGOffsetMapping::GetInlineFormattingContextOf(position);
+ if (!block_flow || !block_flow->IsLayoutNGMixin())
+ return nullptr;
+ return block_flow;
+}
+
+// static
+LayoutBlockFlow* NGOffsetMapping::GetInlineFormattingContextOf(
+ const Position& position) {
+ if (!AcceptsPosition(position))
return nullptr;
const auto node_offset_pair = ToNodeOffsetPair(position);
const LayoutObject* layout_object =
AssociatedLayoutObjectOf(node_offset_pair.first, node_offset_pair.second);
- return layout_object->ContainingNGBlockFlow();
+ if (!layout_object)
+ return nullptr;
+ return GetInlineFormattingContextOf(*layout_object);
}
NGOffsetMappingUnit::NGOffsetMappingUnit(NGOffsetMappingUnitType type,
@@ -167,7 +186,10 @@ const NGOffsetMapping* NGOffsetMapping::GetFor(const Position& position) {
return nullptr;
if (!NGOffsetMapping::AcceptsPosition(position))
return nullptr;
- return GetForContainingBlockFlow(NGInlineFormattingContextOf(position));
+ LayoutBlockFlow* context = NGInlineFormattingContextOf(position);
+ if (!context)
+ return nullptr;
+ return NGInlineNode::GetOffsetMapping(context, nullptr);
}
// static
@@ -177,32 +199,39 @@ const NGOffsetMapping* NGOffsetMapping::GetFor(
return nullptr;
if (!layout_object)
return nullptr;
- return GetForContainingBlockFlow(layout_object->ContainingNGBlockFlow());
+ LayoutBlockFlow* context = layout_object->ContainingNGBlockFlow();
+ if (!context)
+ return nullptr;
+ return NGInlineNode::GetOffsetMapping(context, nullptr);
}
// static
-const NGOffsetMapping* NGOffsetMapping::GetForContainingBlockFlow(
- LayoutBlockFlow* block_flow) {
- if (!block_flow || !block_flow->ChildrenInline())
- return nullptr;
- NGBlockNode block_node = NGBlockNode(block_flow);
- if (!block_node.CanUseNewLayout())
- return nullptr;
- NGLayoutInputNode node = block_node.FirstChild();
- if (node && node.IsInline())
- return ToNGInlineNode(node).ComputeOffsetMappingIfNeeded();
+LayoutBlockFlow* NGOffsetMapping::GetInlineFormattingContextOf(
+ const LayoutObject& object) {
+ for (LayoutObject* runner = object.Parent(); runner;
+ runner = runner->Parent()) {
+ if (!CanUseNGOffsetMapping(*runner))
+ continue;
+ return ToLayoutBlockFlow(runner);
+ }
return nullptr;
}
NGOffsetMapping::NGOffsetMapping(NGOffsetMapping&& other)
: NGOffsetMapping(std::move(other.units_),
std::move(other.ranges_),
- other.text_) {}
-
-NGOffsetMapping::NGOffsetMapping(UnitVector&& units,
- RangeMap&& ranges,
- String text)
- : units_(std::move(units)), ranges_(std::move(ranges)), text_(text) {}
+ other.text_,
+ std::move(other.caret_navigator_)) {}
+
+NGOffsetMapping::NGOffsetMapping(
+ UnitVector&& units,
+ RangeMap&& ranges,
+ String text,
+ std::unique_ptr<NGCaretNavigator> caret_navigator)
+ : units_(std::move(units)),
+ ranges_(std::move(ranges)),
+ text_(text),
+ caret_navigator_(std::move(caret_navigator)) {}
NGOffsetMapping::~NGOffsetMapping() = default;
@@ -443,6 +472,16 @@ Position NGOffsetMapping::GetLastPosition(unsigned offset) const {
return CreatePositionForOffsetMapping(node, dom_offset);
}
+PositionWithAffinity NGOffsetMapping::GetPositionWithAffinity(
+ const NGCaretNavigator::Position& position) const {
+ if (position.IsBeforeCharacter()) {
+ return PositionWithAffinity(GetLastPosition(position.index),
+ TextAffinity::kDownstream);
+ }
+ return PositionWithAffinity(GetLastPosition(position.index + 1),
+ TextAffinity::kUpstream);
+}
+
bool NGOffsetMapping::HasBidiControlCharactersOnly(unsigned start,
unsigned end) const {
DCHECK_LE(start, end);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
index fcea9c0caba..f06d5fe0108 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -105,14 +106,20 @@ class CORE_EXPORT NGOffsetMapping {
HashMap<Persistent<const Node>, std::pair<unsigned, unsigned>>;
NGOffsetMapping(NGOffsetMapping&&);
- NGOffsetMapping(UnitVector&&, RangeMap&&, String);
+ NGOffsetMapping(UnitVector&&,
+ RangeMap&&,
+ String,
+ std::unique_ptr<NGCaretNavigator>);
~NGOffsetMapping();
const UnitVector& GetUnits() const { return units_; }
const RangeMap& GetRanges() const { return ranges_; }
const String& GetText() const { return text_; }
- // ------ Mapping APIs from DOM to text content ------
+ // ------ Static getters for offset mapping objects ------
+
+ // TODO(xiaochengh): Unify the following getters and make them work on both
+ // legacy and LayoutNG.
// NGOffsetMapping APIs only accept the following positions:
// 1. Offset-in-anchor in a text node;
@@ -130,9 +137,16 @@ class CORE_EXPORT NGOffsetMapping {
// a LayoutObject at hand.
static const NGOffsetMapping* GetFor(const LayoutObject*);
- // Returns the mapping object of the inline formatting context the given
- // LayoutBlockFlow has.
- static const NGOffsetMapping* GetForContainingBlockFlow(LayoutBlockFlow*);
+ // Returns the inline formatting context (which is a block flow) where the
+ // given object is laid out -- this is the block flow whose offset mapping
+ // contains the given object. Note that the object can be in either legacy or
+ // NG layout, while NGOffsetMapping is supported on both of them.
+ static LayoutBlockFlow* GetInlineFormattingContextOf(const LayoutObject&);
+
+ // Variants taking position instead of |LayoutObject|.
+ static LayoutBlockFlow* GetInlineFormattingContextOf(const Position&);
+
+ // ------ Mapping APIs from DOM to text content ------
// Returns the NGOffsetMappingUnit whose DOM range contains the position.
// If there are multiple qualifying units, returns the last one.
@@ -185,6 +199,13 @@ class CORE_EXPORT NGOffsetMapping {
Position GetFirstPosition(unsigned) const;
Position GetLastPosition(unsigned) const;
+ // Converts the given caret position on text content to a PositionWithAffinity
+ // in DOM. If |position| is before a character, the function creates a
+ // downstream position before |GetLastPosition()| of the character; otherwise,
+ // it returns an upstream position after |GetFirstPosition()| of the character
+ PositionWithAffinity GetPositionWithAffinity(
+ const NGCaretNavigator::Position& position) const;
+
// Returns all NGOffsetMappingUnits whose text content ranges has non-empty
// (but possibly collapsed) intersection with (start, end). Note that units
// that only "touch" |start| or |end| are excluded.
@@ -200,6 +221,10 @@ class CORE_EXPORT NGOffsetMapping {
// control charcters. Returns true otherwise.
bool HasBidiControlCharactersOnly(unsigned start, unsigned end) const;
+ const NGCaretNavigator* GetCaretNavigator() const {
+ return caret_navigator_.get();
+ }
+
private:
// The NGOffsetMappingUnits of the inline formatting context in osrted order.
UnitVector units_;
@@ -211,6 +236,9 @@ class CORE_EXPORT NGOffsetMapping {
// |NGInlineNodeData::text_content_|.
String text_;
+ // Helper class for caret nagivation on |text_|.
+ std::unique_ptr<NGCaretNavigator> caret_navigator_;
+
DISALLOW_COPY_AND_ASSIGN(NGOffsetMapping);
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.cc
index f80da9ada70..5fa4b9b3386 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_navigator.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
namespace blink {
@@ -198,7 +199,8 @@ void NGOffsetMappingBuilder::SetDestinationString(String string) {
destination_string_ = string;
}
-NGOffsetMapping NGOffsetMappingBuilder::Build() {
+NGOffsetMapping NGOffsetMappingBuilder::Build(
+ std::unique_ptr<NGCaretNavigator> caret_navigator) {
// All mapping units are already built. Scan them to build mapping ranges.
for (unsigned range_start = 0; range_start < mapping_units_.size();) {
const Node* node = &mapping_units_[range_start].GetOwner();
@@ -214,7 +216,7 @@ NGOffsetMapping NGOffsetMappingBuilder::Build() {
}
return NGOffsetMapping(std::move(mapping_units_), std::move(unit_ranges_),
- destination_string_);
+ destination_string_, std::move(caret_navigator));
}
void NGOffsetMappingBuilder::EnterInline(const LayoutObject& layout_object) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
index c24971a7498..545ef36d544 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
@@ -15,6 +15,7 @@
namespace blink {
class LayoutObject;
+class NGCaretNavigator;
// This is the helper class for constructing the DOM-to-TextContent offset
// mapping. It holds an offset mapping, and provides APIs to modify the mapping
@@ -119,7 +120,9 @@ class CORE_EXPORT NGOffsetMappingBuilder {
// Finalize and return the offset mapping.
// This method can only be called once, as it can invalidate the stored data.
- NGOffsetMapping Build();
+ // Also moves the passed-in |NGCaretNavigator| into the result
+ // |NGOffsetMapping|.
+ NGOffsetMapping Build(std::unique_ptr<NGCaretNavigator>);
private:
// Helper function for CollapseTrailingSpace() to maintain unit ranges.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
index 2705012b3d4..b6d5ace7e32 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
@@ -16,6 +16,11 @@
namespace blink {
+// The spec turned into a discussion that may change. Put this logic on hold
+// until CSSWG resolves the issue.
+// https://github.com/w3c/csswg-drafts/issues/337
+#define SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH 0
+
class NGOffsetMappingTest : public NGLayoutTest {
protected:
void SetUp() override {
@@ -292,7 +297,7 @@ TEST_F(NGOffsetMappingTest, CollapseZeroWidthSpaces) {
EXPECT_EQ("{4, 5}{}", TestCollapsing(u"text \n", u"\u200Btext"))
<< "Collapsible space before newline does not affect the result.";
- EXPECT_EQ("{5}{0}", TestCollapsing(u"text\u200B\n", u" text"))
+ EXPECT_EQ("{5}{}", TestCollapsing(u"text\u200B\n", u" text"))
<< "Collapsible space after newline is removed even when the "
"newline was removed.";
EXPECT_EQ("{5}{0}", TestCollapsing(u"text\u200B ", u"\ntext"))
@@ -300,6 +305,7 @@ TEST_F(NGOffsetMappingTest, CollapseZeroWidthSpaces) {
"a zero width space is collapsed to a zero width space.";
}
+#if SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH
TEST_F(NGOffsetMappingTest, CollapseEastAsianWidth) {
EXPECT_EQ("{1}", TestCollapsing(u"\u4E00\n\u4E00"))
<< "Newline is removed when both sides are Wide.";
@@ -315,6 +321,7 @@ TEST_F(NGOffsetMappingTest, CollapseEastAsianWidth) {
<< "Newline at the beginning of elements is removed "
"when both sides are Wide.";
}
+#endif
#define TEST_UNIT(unit, type, owner, dom_start, dom_end, text_content_start, \
text_content_end) \
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index 751766a4c72..24f575f1413 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -73,13 +73,15 @@ NGPhysicalOffsetRect NGPhysicalLineBoxFragment::ContentsInkOverflow() const {
}
NGPhysicalOffsetRect NGPhysicalLineBoxFragment::ScrollableOverflow(
+ const LayoutObject* container,
const ComputedStyle* container_style,
NGPhysicalSize container_physical_size) const {
WritingMode container_writing_mode = container_style->GetWritingMode();
TextDirection container_direction = container_style->Direction();
NGPhysicalOffsetRect overflow({}, Size());
for (const auto& child : Children()) {
- NGPhysicalOffsetRect child_scroll_overflow = child->ScrollableOverflow();
+ NGPhysicalOffsetRect child_scroll_overflow =
+ child->ScrollableOverflowForPropagation(container);
child_scroll_overflow.offset += child.Offset();
// If child has the same style as parent, parent will compute relative
// offset.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
index 57a4a6876a4..cc86bf2435f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
@@ -68,6 +68,7 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
// when LineBox is generated because it needs container dimensions to
// resolve relative position of its children.
NGPhysicalOffsetRect ScrollableOverflow(
+ const LayoutObject* container,
const ComputedStyle* container_style,
NGPhysicalSize container_physical_size) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
index 183f690f962..904ddc7ce72 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
@@ -91,11 +91,15 @@ NGPhysicalTextFragment::NGPhysicalTextFragment(NGTextFragmentBuilder* builder)
DCHECK(shape_result_ || IsFlowControl()) << ToString();
line_orientation_ =
static_cast<unsigned>(ToLineOrientation(builder->GetWritingMode()));
- is_anonymous_text_ =
- IsPhysicalTextFragmentAnonymousText(builder->layout_object_);
- if (UNLIKELY(StyleVariant() == NGStyleVariant::kEllipsis))
+ if (UNLIKELY(StyleVariant() == NGStyleVariant::kEllipsis)) {
EnsureRareData()->style_ = std::move(builder->style_);
+ is_anonymous_text_ = true;
+ } else {
+ is_anonymous_text_ =
+ builder->text_type_ == kGeneratedText ||
+ IsPhysicalTextFragmentAnonymousText(builder->layout_object_);
+ }
UpdateSelfInkOverflow();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
index 0797df848c4..c21e8c0c2e0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
@@ -180,9 +180,11 @@ TEST_F(NGPhysicalTextFragmentTest, Ellipsis) {
const NGPhysicalTextFragment& ellipsis = *text_fragments[1];
EXPECT_EQ(NGPhysicalTextFragment::kNormalText, abcdef.TextType());
EXPECT_FALSE(abcdef.IsGeneratedText());
+ EXPECT_FALSE(abcdef.IsAnonymousText());
EXPECT_EQ(u8"abc", GetText(abcdef));
EXPECT_EQ(NGPhysicalTextFragment::kGeneratedText, ellipsis.TextType());
EXPECT_TRUE(ellipsis.IsGeneratedText());
+ EXPECT_TRUE(ellipsis.IsAnonymousText());
EXPECT_EQ(u8"\u2026", GetText(ellipsis));
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
index a944c30ae0d..a60e9b1bdea 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -30,24 +30,6 @@ bool LayoutNGBlockFlow::IsOfType(LayoutObjectType type) const {
LayoutNGMixin<LayoutBlockFlow>::IsOfType(type);
}
-void LayoutNGBlockFlow::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- NGBlockNode node(const_cast<LayoutNGBlockFlow*>(this));
- if (!node.CanUseNewLayout()) {
- LayoutBlockFlow::ComputeIntrinsicLogicalWidths(min_logical_width,
- max_logical_width);
- return;
- }
- MinMaxSizeInput input;
- // This function returns content-box plus scrollbar.
- input.size_type = NGMinMaxSizeType::kContentBoxSize;
- MinMaxSize sizes = node.ComputeMinMaxSize(StyleRef().GetWritingMode(), input);
- sizes += LayoutUnit(ScrollbarLogicalWidth());
- min_logical_width = sizes.min_size;
- max_logical_width = sizes.max_size;
-}
-
void LayoutNGBlockFlow::UpdateBlockLayout(bool relayout_children) {
LayoutAnalyzer::BlockScope analyzer(*this);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
index 4f552c174ab..f36533ea284 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
@@ -24,11 +24,6 @@ class CORE_EXPORT LayoutNGBlockFlow : public LayoutNGMixin<LayoutBlockFlow> {
protected:
bool IsOfType(LayoutObjectType) const override;
- protected:
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
-
private:
void UpdateOutOfFlowBlockLayout();
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
index 45f1acd810d..3f258fecb3b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
@@ -17,7 +17,8 @@ class CORE_EXPORT LayoutNGFlexibleBox : public LayoutBlock {
void UpdateBlockLayout(bool relayout_children) override;
- bool IsFlexibleBox() const final { return true; }
+ bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; }
+ bool IsFlexibleBoxIncludingNG() const final { return true; }
bool IsLayoutNGObject() const override { return true; }
const char* GetName() const override { return "LayoutNGFlexibleBox"; }
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 2f2abd0bd4a..9a70c3d3f11 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_utils.h"
@@ -54,6 +55,11 @@ void LayoutNGMixin<Base>::ResetNGInlineNodeData() {
ng_inline_node_data_ = std::make_unique<NGInlineNodeData>();
}
+template <typename Base>
+void LayoutNGMixin<Base>::ClearNGInlineNodeData() {
+ ng_inline_node_data_.reset();
+}
+
// The current fragment from the last layout cycle for this box.
// When pre-NG layout calls functions of this block flow, fragment and/or
// LayoutResult are required to compute the result.
@@ -67,15 +73,47 @@ const NGPhysicalBoxFragment* LayoutNGMixin<Base>::CurrentFragment() const {
}
template <typename Base>
-void LayoutNGMixin<Base>::ComputeVisualOverflow(
- const LayoutRect& previous_visual_overflow_rect,
- bool recompute_floats) {
- Base::ComputeVisualOverflow(previous_visual_overflow_rect, recompute_floats);
+void LayoutNGMixin<Base>::ComputeIntrinsicLogicalWidths(
+ LayoutUnit& min_logical_width,
+ LayoutUnit& max_logical_width) const {
+ NGBlockNode node(const_cast<LayoutNGMixin<Base>*>(this));
+ if (!node.CanUseNewLayout()) {
+ Base::ComputeIntrinsicLogicalWidths(min_logical_width, max_logical_width);
+ return;
+ }
+ MinMaxSizeInput input;
+ // This function returns content-box plus scrollbar.
+ input.size_type = NGMinMaxSizeType::kContentBoxSize;
+ MinMaxSize sizes =
+ node.ComputeMinMaxSize(node.Style().GetWritingMode(), input);
+
+ if (Base::IsTableCell()) {
+ // If a table cell, or the column that it belongs to, has a specified fixed
+ // positive inline-size, and the measured intrinsic max size is less than
+ // that, use specified size as max size.
+ LayoutTableCell* cell = ToLayoutTableCell(node.GetLayoutBox());
+ Length table_cell_width = cell->StyleOrColLogicalWidth();
+ if (table_cell_width.IsFixed() && table_cell_width.Value() > 0) {
+ sizes.max_size = std::max(sizes.min_size,
+ Base::AdjustContentBoxLogicalWidthForBoxSizing(
+ LayoutUnit(table_cell_width.Value())));
+ }
+ }
+
+ sizes += LayoutUnit(Base::ScrollbarLogicalWidth());
+ min_logical_width = sizes.min_size;
+ max_logical_width = sizes.max_size;
+}
+
+template <typename Base>
+void LayoutNGMixin<Base>::ComputeVisualOverflow(bool recompute_floats) {
+ LayoutRect previous_visual_overflow_rect = Base::VisualOverflowRect();
+ Base::ClearVisualOverflow();
+ Base::ComputeVisualOverflow(recompute_floats);
AddVisualOverflowFromChildren();
if (Base::VisualOverflowRect() != previous_visual_overflow_rect) {
- if (Base::Layer())
- Base::Layer()->SetNeedsCompositingInputsUpdate();
+ Base::SetShouldCheckForPaintInvalidation();
Base::GetFrameView()->SetIntersectionObservationState(
LocalFrameView::kDesired);
}
@@ -147,12 +185,13 @@ void LayoutNGMixin<Base>::AddScrollingOverflowFromChildren() {
for (const auto& child : physical_fragment->Children()) {
NGPhysicalOffsetRect child_scrollable_overflow;
if (child->IsOutOfFlowPositioned()) {
- child_scrollable_overflow = child->ScrollableOverflow();
+ child_scrollable_overflow =
+ child->ScrollableOverflowForPropagation(this);
} else if (children_inline && child->IsLineBox()) {
DCHECK(child->IsLineBox());
child_scrollable_overflow =
ToNGPhysicalLineBoxFragment(*child).ScrollableOverflow(
- Base::Style(), physical_fragment->Size());
+ this, Base::Style(), physical_fragment->Size());
if (padding_strut)
child_scrollable_overflow.Expand(*padding_strut);
} else {
@@ -227,7 +266,7 @@ scoped_refptr<NGLayoutResult> LayoutNGMixin<Base>::CachedLayoutResult(
if (!RuntimeEnabledFeatures::LayoutNGFragmentCachingEnabled())
return nullptr;
if (!cached_result_ || !Base::cached_constraint_space_ || break_token ||
- Base::NeedsLayout())
+ (Base::NeedsLayout() && !NeedsRelativePositionedLayoutOnly()))
return nullptr;
const NGConstraintSpace& old_space = *Base::cached_constraint_space_;
// If we used to contain abspos items, we can't reuse the fragment, because
@@ -256,7 +295,7 @@ scoped_refptr<NGLayoutResult> LayoutNGMixin<Base>::CachedLayoutResult(
// If the available / percentage sizes have changed in a way that may affect
// layout, we cannot re-use the previous result.
- if (SizeMayChange(Base::StyleRef(), new_space, old_space))
+ if (SizeMayChange(Base::StyleRef(), new_space, old_space, *cached_result_))
return nullptr;
}
@@ -283,6 +322,14 @@ scoped_refptr<NGLayoutResult> LayoutNGMixin<Base>::CachedLayoutResult(
}
}
+ // We can safely re-use this fragment if we are position relative, and only
+ // our position constraints changed (left/top/etc). However we need to clear
+ // the dirty layout bit.
+ if (NeedsRelativePositionedLayoutOnly())
+ Base::ClearNeedsLayout();
+ else
+ DCHECK(!Base::NeedsLayout());
+
// The checks above should be enough to bail if layout is incomplete, but
// let's verify:
DCHECK(IsBlockLayoutComplete(old_space, *cached_result_));
@@ -335,6 +382,11 @@ bool LayoutNGMixin<Base>::AreCachedLinesValidFor(
if (constraint_space.HasFloats() || cached_constraint_space.HasFloats())
return false;
+ // Any floats might need to move, causing lines to wrap differently, needing
+ // re-layout.
+ if (!cached_result_->ExclusionSpace().IsEmpty())
+ return false;
+
// Propagating OOF needs re-layout.
if (!cached_result_->OutOfFlowPositionedDescendants().IsEmpty())
return false;
@@ -344,37 +396,37 @@ bool LayoutNGMixin<Base>::AreCachedLinesValidFor(
template <typename Base>
void LayoutNGMixin<Base>::SetPaintFragment(
- scoped_refptr<const NGPhysicalFragment> fragment,
- NGPhysicalOffset offset,
- scoped_refptr<NGPaintFragment>* current) {
- DCHECK(current);
- *current = fragment ? NGPaintFragment::Create(std::move(fragment), offset,
- std::move(*current))
- : nullptr;
-}
-
-template <typename Base>
-void LayoutNGMixin<Base>::SetPaintFragment(
- const NGBreakToken* break_token,
+ const NGBlockBreakToken* break_token,
scoped_refptr<const NGPhysicalFragment> fragment,
NGPhysicalOffset offset) {
- // TODO(kojii): There are cases where the first call has break_token.
- // Investigate why and handle appropriately.
- // DCHECK(!break_token || paint_fragment_);
+ DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
+
scoped_refptr<NGPaintFragment>* current =
NGPaintFragment::Find(&paint_fragment_, break_token);
- SetPaintFragment(std::move(fragment), offset, current);
+ DCHECK(current);
+ bool has_old = current->get();
+ if (fragment) {
+ *current = NGPaintFragment::Create(std::move(fragment), offset, break_token,
+ std::move(*current));
+ } else {
+ *current = nullptr;
+ }
+
+ if (has_old) {
+ // Painting layer needs repaint when a DisplayItemClient is destroyed.
+ ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
+ }
}
template <typename Base>
void LayoutNGMixin<Base>::UpdatePaintFragmentFromCachedLayoutResult(
- const NGBreakToken* break_token,
+ const NGBlockBreakToken* break_token,
scoped_refptr<const NGPhysicalFragment> fragment,
NGPhysicalOffset fragment_offset) {
DCHECK(fragment);
- // TODO(kojii): There are cases where the first call has break_token.
- // Investigate why and handle appropriately.
- // DCHECK(!break_token || paint_fragment_);
+ DCHECK(fragment->GetLayoutObject() == this);
+ DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
+
scoped_refptr<NGPaintFragment>* current =
NGPaintFragment::Find(&paint_fragment_, break_token);
DCHECK(current);
@@ -464,6 +516,37 @@ PositionWithAffinity LayoutNGMixin<Base>::PositionForPoint(
}
template <typename Base>
+void LayoutNGMixin<Base>::ComputeSelfHitTestRects(
+ Vector<LayoutRect>& rects,
+ const LayoutPoint& layer_offset) const {
+ // Deliberately skipping the LayoutBlockFlow override here. We need to check
+ // for visible overflow (and exit early if it's clipped) here anyway, and it's
+ // pointless to look for legacy line boxes if we're NG.
+ LayoutBlock::ComputeSelfHitTestRects(rects, layer_offset);
+
+ if (!Base::HasHorizontalLayoutOverflow() &&
+ !Base::HasVerticalLayoutOverflow())
+ return;
+
+ NGPaintFragment* block_fragment = PaintFragment();
+ if (!block_fragment)
+ return;
+ for (const NGPaintFragment* line = block_fragment->FirstLineBox(); line;
+ line = line->NextSibling()) {
+ DCHECK(line->PhysicalFragment().IsLineBox());
+ NGPhysicalOffset line_offset = line->Offset();
+ NGPhysicalSize size = line->Size();
+ LayoutRect rect(layer_offset.X() + line_offset.left,
+ layer_offset.Y() + line_offset.top, size.width,
+ size.height);
+ // It's common for this rect to be entirely contained in our box, so exclude
+ // that simple case.
+ if (!rect.IsEmpty() && (rects.IsEmpty() || !rects[0].Contains(rect)))
+ rects.push_back(rect);
+ }
+}
+
+template <typename Base>
void LayoutNGMixin<Base>::DirtyLinesFromChangedChild(
LayoutObject* child,
MarkingBehavior marking_behavior) {
@@ -476,6 +559,12 @@ void LayoutNGMixin<Base>::DirtyLinesFromChangedChild(
NGPaintFragment::DirtyLinesFromChangedChild(child);
}
+template <typename Base>
+bool LayoutNGMixin<Base>::NeedsRelativePositionedLayoutOnly() const {
+ return Base::NeedsPositionedMovementLayoutOnly() &&
+ Base::StyleRef().GetPosition() == EPosition::kRelative;
+}
+
template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCaption>;
template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCell>;
template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlockFlow>;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index eccfd23525d..8dd8445d926 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -39,6 +39,7 @@ class LayoutNGMixin : public Base {
NGInlineNodeData* TakeNGInlineNodeData() final;
NGInlineNodeData* GetNGInlineNodeData() const final;
void ResetNGInlineNodeData() final;
+ void ClearNGInlineNodeData() final;
bool HasNGInlineNodeData() const final { return ng_inline_node_data_.get(); }
LayoutUnit FirstLineBoxBaseline() const final;
@@ -55,6 +56,9 @@ class LayoutNGMixin : public Base {
PositionWithAffinity PositionForPoint(const LayoutPoint&) const final;
+ void ComputeSelfHitTestRects(Vector<LayoutRect>&,
+ const LayoutPoint& layer_offset) const override;
+
// Returns the last layout result for this block flow with the given
// constraint space and break token, or null if it is not up-to-date or
// otherwise unavailable.
@@ -71,29 +75,26 @@ class LayoutNGMixin : public Base {
scoped_refptr<const NGLayoutResult> CachedLayoutResultForTesting() final;
NGPaintFragment* PaintFragment() const final { return paint_fragment_.get(); }
- void SetPaintFragment(const NGBreakToken*,
+ void SetPaintFragment(const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset) final;
void UpdatePaintFragmentFromCachedLayoutResult(
- const NGBreakToken*,
+ const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset) final;
protected:
bool IsOfType(LayoutObject::LayoutObjectType) const override;
- void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) final;
+ void ComputeIntrinsicLogicalWidths(
+ LayoutUnit& min_logical_width,
+ LayoutUnit& max_logical_width) const override;
+
+ void ComputeVisualOverflow(bool recompute_floats) final;
void AddVisualOverflowFromChildren();
void AddLayoutOverflowFromChildren() final;
- private:
- void AddScrollingOverflowFromChildren();
- void SetPaintFragment(scoped_refptr<const NGPhysicalFragment> fragment,
- NGPhysicalOffset offset,
- scoped_refptr<NGPaintFragment>* current);
-
- protected:
void AddOutlineRects(Vector<LayoutRect>&,
const LayoutPoint& additional_offset,
NGOutlineType) const final;
@@ -111,6 +112,10 @@ class LayoutNGMixin : public Base {
scoped_refptr<NGPaintFragment> paint_fragment_;
friend class NGBaseLayoutAlgorithmTest;
+
+ private:
+ void AddScrollingOverflowFromChildren();
+ bool NeedsRelativePositionedLayoutOnly() const;
};
extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
index 196f33775bc..73b4864f313 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
@@ -19,14 +19,14 @@ namespace blink {
namespace {
bool AbsoluteHorizontalNeedsEstimate(const ComputedStyle& style) {
- Length width = style.Width();
+ const Length& width = style.Width();
return width.IsIntrinsic() || style.MinWidth().IsIntrinsic() ||
style.MaxWidth().IsIntrinsic() ||
(width.IsAuto() && (style.Left().IsAuto() || style.Right().IsAuto()));
}
bool AbsoluteVerticalNeedsEstimate(const ComputedStyle& style) {
- Length height = style.Height();
+ const Length& height = style.Height();
return height.IsIntrinsic() || style.MinHeight().IsIntrinsic() ||
style.MaxHeight().IsIntrinsic() ||
(height.IsAuto() && (style.Top().IsAuto() || style.Bottom().IsAuto()));
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
index 69eee903ba2..d785aff2d00 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
@@ -4,10 +4,22 @@
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
+namespace {
+
+struct SameSizeAsNGBlockBreakToken : NGBreakToken {
+ unsigned numbers[2];
+};
+
+static_assert(sizeof(NGBlockBreakToken) == sizeof(SameSizeAsNGBlockBreakToken),
+ "NGBlockBreakToken should stay small");
+
+} // namespace
+
NGBlockBreakToken::NGBlockBreakToken(
NGLayoutInputNode node,
LayoutUnit used_block_size,
@@ -15,8 +27,8 @@ NGBlockBreakToken::NGBlockBreakToken(
bool has_last_resort_break)
: NGBreakToken(kBlockBreakToken, kUnfinished, node),
used_block_size_(used_block_size),
- has_last_resort_break_(has_last_resort_break),
num_children_(child_break_tokens.size()) {
+ has_last_resort_break_ = has_last_resort_break;
for (wtf_size_t i = 0; i < child_break_tokens.size(); ++i) {
child_break_tokens_[i] = child_break_tokens[i].get();
child_break_tokens_[i]->AddRef();
@@ -28,12 +40,38 @@ NGBlockBreakToken::NGBlockBreakToken(NGLayoutInputNode node,
bool has_last_resort_break)
: NGBreakToken(kBlockBreakToken, kFinished, node),
used_block_size_(used_block_size),
- has_last_resort_break_(has_last_resort_break),
- num_children_(0) {}
+ num_children_(0) {
+ has_last_resort_break_ = has_last_resort_break;
+}
NGBlockBreakToken::NGBlockBreakToken(NGLayoutInputNode node)
: NGBreakToken(kBlockBreakToken, kUnfinished, node), num_children_(0) {}
+const NGInlineBreakToken* NGBlockBreakToken::InlineBreakTokenFor(
+ const NGLayoutInputNode& node) const {
+ DCHECK(node.GetLayoutBox());
+ return InlineBreakTokenFor(*node.GetLayoutBox());
+}
+
+const NGInlineBreakToken* NGBlockBreakToken::InlineBreakTokenFor(
+ const LayoutBox& layout_object) const {
+ DCHECK(&layout_object);
+ for (const NGBreakToken* child : ChildBreakTokens()) {
+ switch (child->Type()) {
+ case kBlockBreakToken:
+ // Currently there are no cases where NGInlineBreakToken is stored in
+ // non-direct child descendants.
+ DCHECK(!ToNGBlockBreakToken(child)->InlineBreakTokenFor(layout_object));
+ break;
+ case kInlineBreakToken:
+ if (child->InputNode().GetLayoutBox() == &layout_object)
+ return ToNGInlineBreakToken(child);
+ break;
+ }
+ }
+ return nullptr;
+}
+
#ifndef NDEBUG
String NGBlockBreakToken::ToString() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
index cef4eab54ad..2333863ddc3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
@@ -13,6 +13,8 @@
namespace blink {
+class NGInlineBreakToken;
+
// Represents a break token for a block node.
class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
public:
@@ -107,6 +109,10 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
return ChildTokenList(num_children_, &child_break_tokens_[0]);
}
+ // Find the child NGInlineBreakToken for the specified node.
+ const NGInlineBreakToken* InlineBreakTokenFor(const NGLayoutInputNode&) const;
+ const NGInlineBreakToken* InlineBreakTokenFor(const LayoutBox&) const;
+
#ifndef NDEBUG
String ToString() const override;
#endif
@@ -127,13 +133,6 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
LayoutUnit used_block_size_;
- bool is_break_before_ = false;
-
- // We're attempting to break at an undesirable place. Sometimes that's
- // unavoidable, but we should only break here if we cannot find a better break
- // point further up in the ancestry.
- bool has_last_resort_break_ = false;
-
wtf_size_t num_children_;
// This must be the last member, because it is a flexible array.
NGBreakToken* child_break_tokens_[];
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index c5e715369eb..f0d62089d35 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -828,15 +828,24 @@ void NGBlockLayoutAlgorithm::HandleFloat(
const NGPreviousInflowPosition& previous_inflow_position,
NGBlockNode child,
const NGBlockBreakToken* child_break_token) {
- AddUnpositionedFloat(&unpositioned_floats_, &container_builder_,
- NGUnpositionedFloat(child, child_break_token),
- ConstraintSpace());
-
// If there is a break token for a float we must be resuming layout, we must
// always know our position in the BFC.
DCHECK(!child_break_token || child_break_token->IsBreakBefore() ||
container_builder_.BfcBlockOffset());
+ NGUnpositionedFloat unpositioned_float(child, child_break_token);
+
+ // We shouldn't have seen this float yet.
+ DCHECK(!unpositioned_floats_.Contains(unpositioned_float));
+
+ if (!container_builder_.BfcBlockOffset()) {
+ container_builder_.AddAdjoiningFloatTypes(
+ unpositioned_float.IsLineLeft(ConstraintSpace().Direction())
+ ? kFloatTypeLeft
+ : kFloatTypeRight);
+ }
+ unpositioned_floats_.push_back(std::move(unpositioned_float));
+
// No need to postpone the positioning if we know the correct offset.
if (container_builder_.BfcBlockOffset() ||
ConstraintSpace().FloatsBfcBlockOffset()) {
@@ -1236,6 +1245,8 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
!child_space.FloatsBfcBlockOffset();
bool is_empty_block = IsEmptyBlock(child_space, *layout_result);
+ bool has_clearance = layout_result->IsPushedByFloats();
+
// A child may have aborted its layout if it resolved its BFC block offset.
// If we don't have a BFC block offset yet, we need to propagate the abortion
// up to our parent.
@@ -1249,7 +1260,9 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
DCHECK(child_bfc_block_offset);
abort_when_bfc_block_offset_updated_ = true;
ResolveBfcBlockOffset(previous_inflow_position,
- child_bfc_block_offset.value());
+ has_clearance
+ ? NextBorderEdge(*previous_inflow_position)
+ : child_bfc_block_offset.value());
return false;
}
@@ -1260,7 +1273,6 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
// We try and position the child within the block formatting context. This
// may cause our BFC block offset to be resolved, in which case we should
// abort our layout if needed.
- bool has_clearance = layout_result->IsPushedByFloats();
if (!child_bfc_block_offset) {
if (!has_clearance && child_space.HasClearanceOffset() &&
child.Style().Clear() != EClear::kNone) {
@@ -1391,12 +1403,6 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
container_builder_.SetIsPushedByFloats();
}
- // A line-box may have a list of floats which we add as children.
- if (child.IsInline() && (container_builder_.BfcBlockOffset() ||
- ConstraintSpace().FloatsBfcBlockOffset())) {
- AddPositionedFloats(layout_result->PositionedFloats());
- }
-
// We must have an actual fragment at this stage.
DCHECK(layout_result->PhysicalFragment());
const auto& physical_fragment = *layout_result->PhysicalFragment();
@@ -2214,6 +2220,10 @@ bool NGBlockLayoutAlgorithm::NeedsAbortOnBfcBlockOffsetChange() const {
// Otherwise, we need to abort.
LayoutUnit old_bfc_block_offset =
ConstraintSpace().FloatsBfcBlockOffset().value();
+
+ // In order to determine if the two offsets are equal, we also need to adjust
+ // floats offset by the clearance offset.
+ ApplyClearance(ConstraintSpace(), &old_bfc_block_offset);
return container_builder_.BfcBlockOffset().value() != old_bfc_block_offset;
}
@@ -2221,39 +2231,27 @@ void NGBlockLayoutAlgorithm::PositionPendingFloats(
LayoutUnit origin_block_offset) {
DCHECK(container_builder_.BfcBlockOffset() ||
ConstraintSpace().FloatsBfcBlockOffset())
- << "The parent BFC block offset should be known here";
+ << "The parent BFC block offset should be known here.";
NGBfcOffset origin_bfc_offset = {
ConstraintSpace().BfcOffset().line_offset +
border_scrollbar_padding_.LineLeft(ConstraintSpace().Direction()),
origin_block_offset};
- NGPositionedFloatVector positioned_floats;
- PositionFloats(child_available_size_, child_percentage_size_,
- replaced_child_percentage_size_, origin_bfc_offset,
- unpositioned_floats_, ConstraintSpace(), Style(),
- &exclusion_space_, &positioned_floats);
-
- AddPositionedFloats(positioned_floats);
- unpositioned_floats_.Shrink(0);
-}
-
-template <class Vec>
-void NGBlockLayoutAlgorithm::AddPositionedFloats(const Vec& positioned_floats) {
- DCHECK(container_builder_.BfcBlockOffset() ||
- ConstraintSpace().FloatsBfcBlockOffset())
- << "The parent BFC block offset should be known here";
-
LayoutUnit bfc_block_offset =
container_builder_.BfcBlockOffset()
? container_builder_.BfcBlockOffset().value()
: ConstraintSpace().FloatsBfcBlockOffset().value();
- LayoutUnit bfc_line_offset = ConstraintSpace().BfcOffset().line_offset;
- NGBfcOffset bfc_offset = {bfc_line_offset, bfc_block_offset};
+ NGBfcOffset bfc_offset = {ConstraintSpace().BfcOffset().line_offset,
+ bfc_block_offset};
+
+ for (auto& unpositioned_float : unpositioned_floats_) {
+ NGPositionedFloat positioned_float = PositionFloat(
+ child_available_size_, child_percentage_size_,
+ replaced_child_percentage_size_, origin_bfc_offset, &unpositioned_float,
+ ConstraintSpace(), Style(), &exclusion_space_);
- // TODO(ikilpatrick): Add DCHECK that any positioned floats are children.
- for (const auto& positioned_float : positioned_floats) {
NGFragment child_fragment(
ConstraintSpace().GetWritingMode(),
*positioned_float.layout_result->PhysicalFragment());
@@ -2266,6 +2264,8 @@ void NGBlockLayoutAlgorithm::AddPositionedFloats(const Vec& positioned_floats) {
logical_offset);
container_builder_.PropagateBreak(*positioned_float.layout_result);
}
+
+ unpositioned_floats_.Shrink(0);
}
// In quirks mode, BODY and HTML elements must completely fill initial
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index e8bca18b6f6..bc4d77dcd56 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -16,7 +16,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h"
namespace blink {
@@ -263,10 +262,6 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
// Positions pending floats starting from {@origin_block_offset}.
void PositionPendingFloats(LayoutUnit origin_block_offset);
- // Adds a set of positioned floats as children to the current fragment.
- template <class Vec>
- void AddPositionedFloats(const Vec& positioned_floats);
-
// Positions a list marker for the specified block content.
void PositionOrPropagateListMarker(const NGLayoutResult&, NGLogicalOffset*);
@@ -325,7 +320,7 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
bool has_processed_first_child_ = false;
NGExclusionSpace exclusion_space_;
- NGUnpositionedFloatVector unpositioned_floats_;
+ Vector<NGUnpositionedFloat, 1> unpositioned_floats_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index 20dda1742e4..2f382133a59 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -1077,18 +1077,18 @@ TEST_F(NGBlockLayoutAlgorithmTest, PositionFloatInsideEmptyBlocks) {
// 35 = empty1's padding(20) + empty2's padding(15)
EXPECT_THAT(offset.left, LayoutUnit(35));
- iterator.SetParent(empty2_fragment);
- iterator.NextChild(&offset);
- // inline 25 = empty2's padding(15) + left float's margin(10)
+ const auto* linebox_fragment = empty2_fragment->Children()[0].fragment;
+
+ offset = ToNGPhysicalLineBoxFragment(linebox_fragment)->Children()[0].offset;
+ // inline 10 = left float's margin(10)
// block 10 = left float's margin
- EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(25), LayoutUnit(10)));
+ EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(10), LayoutUnit(10)));
- iterator.NextChild(&offset);
- // inline offset 150 = empty2's padding(15) + right float's margin(10) + right
- // float offset(125)
+ offset = ToNGPhysicalLineBoxFragment(linebox_fragment)->Children()[1].offset;
+ // inline offset 135 = right float's margin(10) + right float offset(125)
// block offset 15 = right float's margin
LayoutUnit right_float_offset = LayoutUnit(125);
- EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(25) + right_float_offset,
+ EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(10) + right_float_offset,
LayoutUnit(15)));
// ** Verify layout tree **
@@ -1914,7 +1914,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentationSmallHeight) {
}
// Tests that float children fragment correctly inside a parallel flow.
-TEST_F(NGBlockLayoutAlgorithmTest, FloatFragmentationParallelFlows) {
+TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationParallelFlows) {
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -2035,18 +2035,18 @@ TEST_F(NGBlockLayoutAlgorithmTest, FloatFragmentationOrthogonalFlows) {
EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(60)), fragment->Size());
ASSERT_TRUE(!fragment->BreakToken() || fragment->BreakToken()->IsFinished());
+ const auto* linebox =
+ ToNGPhysicalBoxFragment(fragment.get())->Children()[0].fragment;
+ const auto* float2 =
+ ToNGPhysicalLineBoxFragment(linebox)->Children()[1].fragment;
+
// float2 should only have one fragment.
- FragmentChildIterator iterator(ToNGPhysicalBoxFragment(fragment.get()));
- NGPhysicalOffset offset;
- const auto* child = iterator.NextChild(&offset);
- child = iterator.NextChild(&offset);
- EXPECT_EQ(NGPhysicalSize(LayoutUnit(60), LayoutUnit(200)), child->Size());
- EXPECT_EQ(NGPhysicalOffset(LayoutUnit(90), LayoutUnit(50)), offset);
- ASSERT_TRUE(!child->BreakToken() || child->BreakToken()->IsFinished());
+ EXPECT_EQ(NGPhysicalSize(LayoutUnit(60), LayoutUnit(200)), float2->Size());
+ ASSERT_TRUE(!float2->BreakToken() || float2->BreakToken()->IsFinished());
}
// Tests that a float child inside a zero height block fragments correctly.
-TEST_F(NGBlockLayoutAlgorithmTest, FloatFragmentationZeroHeight) {
+TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationZeroHeight) {
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style>
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 10fee840917..a5d301568c5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -85,6 +85,38 @@ bool IsFloatFragment(const NGPhysicalFragment& fragment) {
return layout_object && layout_object->IsFloating() && fragment.IsBox();
}
+// Creates a blink::FloatingObject (if needed), and populates it with the
+// position information needed by the existing layout tree.
+void CopyFloatChildFragmentPosition(LayoutBox* floating_box,
+ const NGPhysicalOffset offset,
+ bool has_flipped_x_axis) {
+ DCHECK(floating_box->IsFloating());
+
+ LayoutBlock* containing_block = floating_box->ContainingBlock();
+ DCHECK(containing_block);
+
+ // Floats need an associated FloatingObject for painting.
+ FloatingObject* floating_object =
+ ToLayoutBlockFlow(containing_block)->InsertFloatingObject(*floating_box);
+ floating_object->SetShouldPaint(!floating_box->HasSelfPaintingLayer());
+ LayoutUnit horizontal_margin_edge_offset = offset.left;
+ if (has_flipped_x_axis)
+ horizontal_margin_edge_offset -= floating_box->MarginRight();
+ else
+ horizontal_margin_edge_offset -= floating_box->MarginLeft();
+ floating_object->SetX(horizontal_margin_edge_offset);
+ floating_object->SetY(offset.top - floating_box->MarginTop());
+#if DCHECK_IS_ON()
+ // Being "placed" is a legacy thing. Make sure the flags remain unset in NG.
+ DCHECK(!floating_object->IsPlaced());
+ DCHECK(!floating_object->IsInPlacedTree());
+
+ // Set this flag to tell the float machinery that it's safe to read out
+ // position data.
+ floating_object->SetHasGeometry();
+#endif
+}
+
void UpdateLegacyMultiColumnFlowThread(
NGBlockNode node,
LayoutMultiColumnFlowThread* flow_thread,
@@ -186,6 +218,9 @@ scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
block_flow->IncrementLayoutPassCount();
NGLayoutInputNode first_child = FirstChild();
+ if (block_flow && !first_child)
+ block_flow->ClearNGInlineNodeData();
+
scoped_refptr<NGLayoutResult> layout_result;
if (block_flow) {
layout_result =
@@ -202,7 +237,7 @@ scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
// -dynamic.html
// TODO(layoutng): See if we can optimize this. When we natively
// support relative positioning in NG we can probably remove this,
- box_->SetShouldCheckForPaintInvalidation();
+ box_->SetSubtreeShouldCheckForPaintInvalidation();
// We have to re-set the cached result here, because it is used for
// LayoutNGMixin::CurrentFragment and therefore has to be up-to-date.
@@ -213,7 +248,7 @@ scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
if (!constraint_space.IsIntermediateLayout() && first_child &&
first_child.IsInline()) {
block_flow->UpdatePaintFragmentFromCachedLayoutResult(
- break_token, layout_result->PhysicalFragment(),
+ ToNGBlockBreakToken(break_token), layout_result->PhysicalFragment(),
layout_result->Offset());
}
return layout_result;
@@ -319,13 +354,14 @@ void NGBlockNode::FinishLayout(LayoutBlockFlow* block_flow,
Style().IsFlippedBlocksWritingMode());
}
- block_flow->SetPaintFragment(break_token,
+ block_flow->SetPaintFragment(ToNGBlockBreakToken(break_token),
layout_result->PhysicalFragment(),
layout_result->Offset());
} else {
// We still need to clear paint fragments in case it had inline children,
// and thus had NGPaintFragment.
- block_flow->SetPaintFragment(break_token, nullptr, NGPhysicalOffset());
+ block_flow->SetPaintFragment(ToNGBlockBreakToken(break_token), nullptr,
+ NGPhysicalOffset());
}
}
@@ -592,8 +628,9 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
// |ComputeOverflow()| below calls |AddVisualOverflowFromChildren()|, which
// computes visual overflow from |RootInlineBox| if |ChildrenInline()|
- block->ComputeOverflow(intrinsic_block_size - borders.block_end -
- scrollbars.block_end);
+ block->SetNeedsOverflowRecalc();
+ block->ComputeLayoutOverflow(intrinsic_block_size - borders.block_end -
+ scrollbars.block_end);
}
box_->UpdateAfterLayout();
@@ -703,28 +740,9 @@ void NGBlockNode::CopyChildFragmentPosition(
layout_box->SetLocation(LayoutPoint(
horizontal_offset, fragment_offset.top + additional_offset.top));
- // Floats need an associated FloatingObject for painting.
- if (IsFloatFragment(fragment) && containing_block->IsLayoutBlockFlow()) {
- FloatingObject* floating_object =
- ToLayoutBlockFlow(containing_block)->InsertFloatingObject(*layout_box);
- floating_object->SetShouldPaint(!layout_box->HasSelfPaintingLayer());
- LayoutUnit horizontal_margin_edge_offset = horizontal_offset;
- if (has_flipped_x_axis)
- horizontal_margin_edge_offset -= layout_box->MarginRight();
- else
- horizontal_margin_edge_offset -= layout_box->MarginLeft();
- floating_object->SetX(horizontal_margin_edge_offset);
- floating_object->SetY(fragment_offset.top + additional_offset.top -
- layout_box->MarginTop());
-#if DCHECK_IS_ON()
- // Being "placed" is a legacy thing. Make sure the flags remain unset in NG.
- DCHECK(!floating_object->IsPlaced());
- DCHECK(!floating_object->IsInPlacedTree());
-
- // Set this flag to tell the float machinery that it's safe to read out
- // position data.
- floating_object->SetHasGeometry();
-#endif
+ if (IsFloatFragment(fragment)) {
+ CopyFloatChildFragmentPosition(
+ layout_box, fragment_offset + additional_offset, has_flipped_x_axis);
}
}
@@ -752,6 +770,11 @@ void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
maybe_flipped_offset.left;
}
layout_box.SetLocation(maybe_flipped_offset.ToLayoutPoint());
+
+ if (IsFloatFragment(*child)) {
+ CopyFloatChildFragmentPosition(&layout_box, maybe_flipped_offset,
+ initial_container_is_flipped);
+ }
}
// Legacy compatibility. This flag is used in paint layer for
@@ -867,18 +890,24 @@ scoped_refptr<NGLayoutResult> NGBlockNode::RunOldLayout(
if (constraint_space.IsFixedSizeInline()) {
box_->SetOverrideLogicalWidth(
constraint_space.AvailableSize().inline_size);
+ } else {
+ box_->ClearOverrideLogicalWidth();
}
if (constraint_space.IsFixedSizeBlock()) {
box_->SetOverrideLogicalHeight(
constraint_space.AvailableSize().block_size);
+ } else {
+ box_->ClearOverrideLogicalHeight();
}
box_->ComputeAndSetBlockDirectionMargins(box_->ContainingBlock());
- if (box_->NeedsLayout() && box_->IsLayoutNGMixin()) {
- ToLayoutBlockFlow(box_)->LayoutBlockFlow::UpdateBlockLayout(true);
- } else {
- box_->ForceLayout();
- }
+ // Using |LayoutObject::LayoutIfNeeded| save us a little bit of overhead,
+ // compared to |LayoutObject::ForceChildLayout|.
+ DCHECK(!box_->IsLayoutNGMixin());
+ if (box_->NeedsLayout())
+ box_->LayoutIfNeeded();
+ else
+ box_->ForceChildLayout();
// Reset the containing block size override size, now that we're done with
// subtree layout. Min/max calculation that depends on the block size of the
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index f6d802b5056..d99bdffac8e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -20,6 +20,58 @@
namespace blink {
+using LineBoxPair = std::pair<const NGPhysicalLineBoxFragment*,
+ const NGPhysicalLineBoxFragment*>;
+void GatherInlineContainerFragmentsFromLinebox(
+ NGBoxFragmentBuilder::InlineContainingBlockMap* inline_containing_block_map,
+ HashMap<const LayoutObject*, LineBoxPair>* containing_linebox_map,
+ const NGPhysicalLineBoxFragment* linebox,
+ const NGPhysicalOffset linebox_offset) {
+ for (auto& descendant : NGInlineFragmentTraversal::DescendantsOf(*linebox)) {
+ if (!descendant.fragment->IsBox())
+ continue;
+ LayoutObject* key = descendant.fragment->GetLayoutObject();
+ // TODO(atotic) Is traversing continuations the right thing to do?
+ if (key->IsLayoutInline()) // key for inlines is continuation root.
+ key = key->GetNode()->GetLayoutObject();
+ auto it = inline_containing_block_map->find(key);
+ if (it == inline_containing_block_map->end()) {
+ // Default case, not one of the blocks we are looking for.
+ continue;
+ }
+ base::Optional<NGBoxFragmentBuilder::InlineContainingBlockGeometry>&
+ containing_block_geometry = it->value;
+ LineBoxPair& containing_lineboxes =
+ containing_linebox_map->insert(key, LineBoxPair{nullptr, nullptr})
+ .stored_value->value;
+ DCHECK(containing_block_geometry.has_value() ||
+ !containing_lineboxes.first);
+
+ // |DescendantsOf| returns the offset from the given fragment. Since
+ // we give it the line box, need to add the |linebox_offset|.
+ NGPhysicalOffsetRect fragment_rect(
+ linebox_offset + descendant.offset_to_container_box,
+ descendant.fragment->Size());
+ if (containing_lineboxes.first == linebox) {
+ containing_block_geometry.value().start_fragment_union_rect.Unite(
+ fragment_rect);
+ } else if (!containing_lineboxes.first) {
+ containing_lineboxes.first = linebox;
+ containing_block_geometry =
+ NGBoxFragmentBuilder::InlineContainingBlockGeometry{
+ fragment_rect, NGPhysicalOffsetRect()};
+ }
+ // Skip fragments within an empty line boxes for the end fragment.
+ if (containing_lineboxes.second == linebox) {
+ containing_block_geometry.value().end_fragment_union_rect.Unite(
+ fragment_rect);
+ } else if (!containing_lineboxes.second || !linebox->IsEmptyLineBox()) {
+ containing_lineboxes.second = linebox;
+ containing_block_geometry.value().end_fragment_union_rect = fragment_rect;
+ }
+ }
+}
+
void NGBoxFragmentBuilder::RemoveChildren() {
child_break_tokens_.resize(0);
inline_break_tokens_.resize(0);
@@ -37,7 +89,8 @@ NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddBreakBeforeChild(
// formatting context, rather than concluding that we're done with the
// whole thing.
inline_break_tokens_.push_back(NGInlineBreakToken::Create(
- ToNGInlineNode(child), nullptr, 0, 0, NGInlineBreakToken::kDefault));
+ ToNGInlineNode(child), /* style */ nullptr, /* item_index */ 0,
+ /* text_offset */ 0, NGInlineBreakToken::kDefault));
}
return *this;
}
@@ -202,18 +255,24 @@ scoped_refptr<NGLayoutResult> NGBoxFragmentBuilder::Abort(
return base::AdoptRef(new NGLayoutResult(status, this));
}
-// Finds FragmentPairs that define inline containing blocks.
-// inline_container_fragments is a map whose keys specify which
+// Finds InlineContainingBlockGeometry that define inline containing blocks.
+// |inline_containing_block_map| is a map whose keys specify which
// inline containing blocks are required.
-// Not finding a required block is an unexpected behavior (DCHECK).
void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
- HashMap<const LayoutObject*, FragmentPair>* inline_container_fragments,
- NGLogicalSize* container_size) {
+ InlineContainingBlockMap* inline_containing_block_map) {
+ if (!inline_containing_block_map->size())
+ return;
+
// This function has detailed knowledge of inline fragment tree structure,
// and will break if this changes.
DCHECK_GE(InlineSize(), LayoutUnit());
DCHECK_GE(BlockSize(), LayoutUnit());
- *container_size = Size();
+
+ // std::pair.first points to start linebox fragment.
+ // std::pair.second points to ending linebox fragment.
+ using LineBoxPair = std::pair<const NGPhysicalLineBoxFragment*,
+ const NGPhysicalLineBoxFragment*>;
+ HashMap<const LayoutObject*, LineBoxPair> containing_linebox_map;
for (wtf_size_t i = 0; i < children_.size(); i++) {
if (children_[i]->IsLineBox()) {
@@ -222,43 +281,37 @@ void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
const NGPhysicalOffset linebox_offset = offsets_[i].ConvertToPhysical(
GetWritingMode(), Direction(),
ToNGPhysicalSize(Size(), GetWritingMode()), linebox->Size());
+ GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map,
+ &containing_linebox_map,
+ linebox, linebox_offset);
+ } else if (children_[i]->IsBox()) {
+ const NGPhysicalBoxFragment* box_fragment =
+ ToNGPhysicalBoxFragment(children_[i].get());
+ bool is_anonymous_container =
+ box_fragment->GetLayoutObject() &&
+ box_fragment->GetLayoutObject()->IsAnonymousBlock();
+ if (!is_anonymous_container)
+ continue;
+ // If child is an anonymous container, this might be a special case of
+ // split inlines. The inline container fragments might be inside
+ // anonymous boxes. To find inline container fragments, traverse
+ // lineboxes inside anonymous box.
+ // For more on this special case, see "css container is an inline,
+ // with inline splitting" comment in
+ // NGOutOfFlowLayoutPart::LayoutDescendant.
+ const NGPhysicalOffset box_offset = offsets_[i].ConvertToPhysical(
+ GetWritingMode(), Direction(),
+ ToNGPhysicalSize(Size(), GetWritingMode()), box_fragment->Size());
- for (auto& descendant :
- NGInlineFragmentTraversal::DescendantsOf(*linebox)) {
- LayoutObject* key = {};
- if (descendant.fragment->IsText()) {
- key = descendant.fragment->GetLayoutObject();
- DCHECK(key);
- key = key->Parent();
- DCHECK(key);
- } else if (descendant.fragment->IsBox()) {
- key = descendant.fragment->GetLayoutObject();
- }
- if (!key)
- continue;
- auto it = inline_container_fragments->find(key);
- if (it != inline_container_fragments->end()) {
- NGBoxFragmentBuilder::FragmentPair& value = it->value;
- // |DescendantsOf| returns the offset from the given fragment. Since
- // we give it the line box, need to add the |linebox_offset|.
- NGPhysicalOffsetRect fragment_rect(
- linebox_offset + descendant.offset_to_container_box,
- descendant.fragment->Size());
- if (value.start_linebox_fragment == linebox) {
- value.start_fragment_union_rect.Unite(fragment_rect);
- } else if (!value.start_fragment) {
- value.start_fragment = descendant.fragment.get();
- value.start_fragment_union_rect = fragment_rect;
- value.start_linebox_fragment = linebox;
- }
- // Skip fragments within an empty line boxes for the end fragment.
- if (value.end_linebox_fragment == linebox) {
- value.end_fragment_union_rect.Unite(fragment_rect);
- } else if (!value.end_fragment || !linebox->IsEmptyLineBox()) {
- value.end_fragment = descendant.fragment.get();
- value.end_fragment_union_rect = fragment_rect;
- value.end_linebox_fragment = linebox;
- }
+ // Traverse lineboxes of anonymous box.
+ for (const auto& child : box_fragment->Children()) {
+ if (child->IsLineBox()) {
+ const NGPhysicalLineBoxFragment* linebox =
+ ToNGPhysicalLineBoxFragment(child.get());
+ const NGPhysicalOffset linebox_offset = child.Offset() + box_offset;
+ GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map,
+ &containing_linebox_map,
+ linebox, linebox_offset);
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index a506bffe580..7280a74d390 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -19,7 +19,6 @@
namespace blink {
class NGPhysicalFragment;
-class NGPhysicalLineBoxFragment;
class CORE_EXPORT NGBoxFragmentBuilder final
: public NGContainerFragmentBuilder {
@@ -30,8 +29,10 @@ class CORE_EXPORT NGBoxFragmentBuilder final
scoped_refptr<const ComputedStyle> style,
WritingMode writing_mode,
TextDirection direction)
- : NGContainerFragmentBuilder(std::move(style), writing_mode, direction),
- node_(node),
+ : NGContainerFragmentBuilder(node,
+ std::move(style),
+ writing_mode,
+ direction),
box_type_(NGPhysicalFragment::NGBoxType::kNormalBox),
is_old_layout_root_(false),
did_break_(false) {
@@ -44,8 +45,10 @@ class CORE_EXPORT NGBoxFragmentBuilder final
scoped_refptr<const ComputedStyle> style,
WritingMode writing_mode,
TextDirection direction)
- : NGContainerFragmentBuilder(std::move(style), writing_mode, direction),
- node_(nullptr),
+ : NGContainerFragmentBuilder(nullptr,
+ std::move(style),
+ writing_mode,
+ direction),
box_type_(NGPhysicalFragment::NGBoxType::kNormalBox),
is_old_layout_root_(false),
did_break_(false) {
@@ -206,33 +209,25 @@ class CORE_EXPORT NGBoxFragmentBuilder final
// type pair.
void AddBaseline(NGBaselineRequest, LayoutUnit);
- // Inline containing block geometry is defined by two fragments:
- // start and end. FragmentPair holds the information needed to compute
- // inline containing block geometry wrt enclosing container block.
- struct FragmentPair {
+ // Inline containing block geometry is defined by two rectangles defined
+ // by fragments generated by LayoutInline.
+ struct InlineContainingBlockGeometry {
DISALLOW_NEW();
- // Linebox that contains start_fragment.
- const NGPhysicalLineBoxFragment* start_linebox_fragment;
- // Start fragment of inline containing block.
- const NGPhysicalFragment* start_fragment;
- // Start fragment rect combined with rectangles of all fragments
- // generated by same Element as start_fragment.
+ // Union of fragments generated on the first line.
NGPhysicalOffsetRect start_fragment_union_rect;
- // end_** variables are end fragment counterparts to start fragment.
- const NGPhysicalLineBoxFragment* end_linebox_fragment;
- const NGPhysicalFragment* end_fragment;
+ // Union of fragments generated on the last line.
NGPhysicalOffsetRect end_fragment_union_rect;
};
+ using InlineContainingBlockMap =
+ HashMap<const LayoutObject*,
+ base::Optional<InlineContainingBlockGeometry>>;
void ComputeInlineContainerFragments(
- HashMap<const LayoutObject*, FragmentPair>* inline_container_fragments,
- NGLogicalSize* container_size);
+ InlineContainingBlockMap* inline_container_fragments);
private:
scoped_refptr<NGLayoutResult> ToBoxFragment(WritingMode);
- NGLayoutInputNode node_;
-
LayoutUnit intrinsic_block_size_;
NGBoxStrut borders_;
NGBoxStrut padding_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc
index 75bcf1fff0c..906ae1ada46 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc
@@ -9,6 +9,19 @@
namespace blink {
+namespace {
+
+struct SameSizeAsNGBreakToken : RefCounted<NGBreakToken> {
+ virtual ~SameSizeAsNGBreakToken() = default;
+ void* pointer;
+ unsigned flags;
+};
+
+static_assert(sizeof(NGBreakToken) == sizeof(SameSizeAsNGBreakToken),
+ "NGBreakToken should stay small");
+
+} // namespace
+
#ifndef NDEBUG
namespace {
@@ -36,7 +49,7 @@ void AppendBreakTokenToString(const NGBreakToken* token,
String NGBreakToken::ToString() const {
StringBuilder string_builder;
string_builder.Append("(");
- string_builder.Append(node_.ToString());
+ string_builder.Append(InputNode().ToString());
string_builder.Append(")");
if (IsFinished())
string_builder.Append(" finished");
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h
index 14111476499..62e4d4914ff 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h
@@ -34,7 +34,10 @@ class CORE_EXPORT NGBreakToken : public RefCounted<NGBreakToken> {
public:
virtual ~NGBreakToken() = default;
- enum NGBreakTokenType { kBlockBreakToken, kInlineBreakToken };
+ enum NGBreakTokenType {
+ kBlockBreakToken = NGLayoutInputNode::kBlock,
+ kInlineBreakToken = NGLayoutInputNode::kInline
+ };
NGBreakTokenType Type() const { return static_cast<NGBreakTokenType>(type_); }
bool IsBlockType() const { return Type() == kBlockBreakToken; }
@@ -47,7 +50,10 @@ class CORE_EXPORT NGBreakToken : public RefCounted<NGBreakToken> {
// Returns the node associated with this break token. A break token cannot be
// used with any other node.
- NGLayoutInputNode InputNode() const { return node_; }
+ NGLayoutInputNode InputNode() const {
+ return NGLayoutInputNode::Create(
+ box_, static_cast<NGLayoutInputNode::NGLayoutInputNodeType>(type_));
+ }
#ifndef NDEBUG
virtual String ToString() const;
@@ -58,13 +64,40 @@ class CORE_EXPORT NGBreakToken : public RefCounted<NGBreakToken> {
NGBreakToken(NGBreakTokenType type,
NGBreakTokenStatus status,
NGLayoutInputNode node)
- : type_(type), status_(status), node_(node) {}
+ : box_(node.GetLayoutBox()),
+ type_(type),
+ status_(status),
+ flags_(0),
+ ignore_floats_(false),
+ is_break_before_(false),
+ has_last_resort_break_(false) {
+ DCHECK_EQ(type, static_cast<NGBreakTokenType>(node.Type()));
+ }
private:
+ // Because |NGLayoutInputNode| has a pointer and 1 bit flag, and it's fast to
+ // re-construct, keep |LayoutBox| to save the memory consumed by alignment.
+ LayoutBox* box_;
+
unsigned type_ : 1;
unsigned status_ : 1;
- NGLayoutInputNode node_;
+ protected:
+ // The following bitfields are only to be used by NGInlineBreakToken (it's
+ // defined here to save memory, since that class has no bitfields).
+
+ unsigned flags_ : 2; // NGInlineBreakTokenFlags
+ unsigned ignore_floats_ : 1;
+
+ // The following bitfields are only to be used by NGBlockBreakToken (it's
+ // defined here to save memory, since that class has no bitfields).
+
+ unsigned is_break_before_ : 1;
+
+ // We're attempting to break at an undesirable place. Sometimes that's
+ // unavoidable, but we should only break here if we cannot find a better break
+ // point further up in the ancestry.
+ unsigned has_last_resort_break_ : 1;
};
typedef Vector<scoped_refptr<NGBreakToken>, 16> NGBreakTokenVector;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index 12bc8e69d46..37e4d38cc7d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -329,4 +329,4 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstaintSpaceForBalancing(
return space_builder.ToConstraintSpace();
}
-} // namespace Blink
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
index 93be8b66d22..0133e299cd9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -50,6 +50,6 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
const NGLogicalSize& column_size) const;
};
-} // namespace Blink
+} // namespace blink
#endif // NGColumnLayoutAlgorithm_h
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
index 9c2e939da13..37f15d7c5ad 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -461,7 +461,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, UnusedSpaceInBlock) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, FloatInOneColumn) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInOneColumn) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
@@ -490,7 +491,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, FloatInOneColumn) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInOneColumn) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_TwoFloatsInOneColumn) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
@@ -521,7 +523,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInOneColumn) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInTwoColumns) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_TwoFloatsInTwoColumns) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
@@ -1333,7 +1336,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, LineAtColumnBoundaryInFirstBlock) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, LinesAndFloatsMulticol) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_LinesAndFloatsMulticol) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
@@ -1386,7 +1390,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, LinesAndFloatsMulticol) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, FloatBelowLastLineInColumn) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatBelowLastLineInColumn) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
@@ -1738,7 +1743,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, UnsatisfiableOrphansAndWidows) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, FloatInBlockMovedByOrphans) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInBlockMovedByOrphans) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
@@ -1781,7 +1787,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, FloatInBlockMovedByOrphans) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGColumnLayoutAlgorithmTest, FloatMovedWithWidows) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatMovedWithWidows) {
SetBodyInnerHTML(R"HTML(
<style>
#parent {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 5a75ed36bf2..9c35f94ef42 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -52,30 +52,17 @@ NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild(
}
for (const NGOutOfFlowPositionedDescendant& descendant :
out_of_flow_descendants) {
- // If we are inside the inline algorithm, (and creating a fragment for a
- // <span> or similar), we may add a child (e.g. an atomic-inline) which
- // has OOF descandants.
- //
- // This checks if the object creating this box will be the container for
- // the given descendant.
- if (layout_object_ && layout_object_->IsLayoutInline() &&
- layout_object_->CanContainOutOfFlowPositionedElement(
- descendant.node.Style().GetPosition()) &&
- !descendant.inline_container) {
- NGOutOfFlowPositionedDescendant descendant_copy(descendant);
- descendant_copy.inline_container = layout_object_;
- oof_positioned_candidates_.push_back(
- NGOutOfFlowPositionedCandidate(descendant_copy, top_left_offset));
- } else {
- oof_positioned_candidates_.push_back(
- NGOutOfFlowPositionedCandidate{descendant, top_left_offset});
- }
+ oof_positioned_candidates_.push_back(
+ NGOutOfFlowPositionedCandidate(descendant, top_left_offset));
}
}
if (child.HasOrthogonalFlowRoots())
has_orthogonal_flow_roots_ = true;
+ if (child.DependsOnPercentageBlockSize())
+ has_depends_on_percentage_block_size_child_ = true;
+
return AddChild(child.PhysicalFragment(), child_offset);
}
@@ -106,6 +93,10 @@ NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild(
Style().GetWritingMode()))
has_orthogonal_flow_roots_ = true;
+ // We mark all legacy layout nodes as dependent on percentage block-size.
+ if (child->IsOldLayoutRoot())
+ has_depends_on_percentage_block_size_child_ = true;
+
if (!has_last_resort_break_) {
if (const auto* token = child->BreakToken()) {
if (token->IsBlockType() &&
@@ -118,37 +109,36 @@ NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild(
return *this;
}
-NGContainerFragmentBuilder&
-NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
- NGBlockNode child,
- const NGLogicalOffset& child_offset) {
- DCHECK(child);
- oof_positioned_candidates_.push_back(NGOutOfFlowPositionedCandidate(
- NGOutOfFlowPositionedDescendant{
- child, NGStaticPosition::Create(GetWritingMode(), Direction(),
- NGPhysicalOffset())},
- child_offset));
-
- return *this;
+NGLogicalOffset NGContainerFragmentBuilder::GetChildOffset(
+ const LayoutObject* child) {
+ for (wtf_size_t i = 0; i < children_.size(); ++i) {
+ if (children_[i]->GetLayoutObject() == child)
+ return offsets_[i];
+ }
+ NOTREACHED();
+ return NGLogicalOffset();
}
NGContainerFragmentBuilder&
-NGContainerFragmentBuilder::AddInlineOutOfFlowChildCandidate(
+NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
NGBlockNode child,
const NGLogicalOffset& child_offset,
- TextDirection line_direction,
- LayoutObject* inline_container) {
+ base::Optional<TextDirection> container_direction) {
DCHECK(child);
- // Fixed positioned children are never placed inside inline container.
- if (child.Style().GetPosition() == EPosition::kFixed)
- inline_container = nullptr;
+ DCHECK(layout_object_ && !layout_object_->IsLayoutInline() ||
+ container_direction)
+ << "container_direction must only be set for inline-level OOF children.";
+
+ // As all inline-level fragments are built in the line-logical coordinate
+ // system (Direction() is kLtr), we need to know the direction of the
+ // parent element to correctly determine an OOF childs static position.
+ TextDirection direction = container_direction.value_or(Direction());
+
oof_positioned_candidates_.push_back(NGOutOfFlowPositionedCandidate(
NGOutOfFlowPositionedDescendant(
- child,
- NGStaticPosition::Create(GetWritingMode(), line_direction,
- NGPhysicalOffset()),
- inline_container),
- child_offset, line_direction));
+ child, NGStaticPosition::Create(GetWritingMode(), direction,
+ NGPhysicalOffset())),
+ child_offset));
return *this;
}
@@ -175,19 +165,31 @@ void NGContainerFragmentBuilder::GetAndClearOutOfFlowDescendantCandidates(
ToNGPhysicalSize(Size(), GetWritingMode());
for (NGOutOfFlowPositionedCandidate& candidate : oof_positioned_candidates_) {
- TextDirection direction =
- candidate.is_line_relative ? candidate.line_direction : Direction();
NGPhysicalOffset child_offset = candidate.child_offset.ConvertToPhysical(
- GetWritingMode(), direction, builder_physical_size, NGPhysicalSize());
+ GetWritingMode(), Direction(), builder_physical_size, NGPhysicalSize());
NGStaticPosition builder_relative_position;
builder_relative_position.type = candidate.descendant.static_position.type;
builder_relative_position.offset =
child_offset + candidate.descendant.static_position.offset;
+ // If we are inside the inline algorithm, (and creating a fragment for a
+ // <span> or similar), we may add a child (e.g. an atomic-inline) which has
+ // OOF descandants.
+ //
+ // This checks if the object creating this box will be the container for
+ // the given descendant.
+ const LayoutObject* inline_container =
+ candidate.descendant.inline_container;
+ if (!inline_container && layout_object_ &&
+ layout_object_->IsLayoutInline() &&
+ layout_object_->CanContainOutOfFlowPositionedElement(
+ candidate.descendant.node.Style().GetPosition()))
+ inline_container = layout_object_;
+
descendant_candidates->push_back(NGOutOfFlowPositionedDescendant(
candidate.descendant.node, builder_relative_position,
- candidate.descendant.inline_container));
+ inline_container));
NGLogicalOffset container_offset =
builder_relative_position.offset.ConvertToLogical(
GetWritingMode(), Direction(), builder_physical_size,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 2c2a2cc3f4b..443924478cf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -86,6 +86,10 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
const ChildrenVector& Children() const { return children_; }
+ // Returns offset for given child. DCHECK if child not found.
+ // Warning: Do not call unless necessary.
+ NGLogicalOffset GetChildOffset(const LayoutObject* child);
+
// Builder has non-trivial out-of-flow descendant methods.
// These methods are building blocks for implementation of
// out-of-flow descendants by layout algorithms.
@@ -116,14 +120,8 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
// Pass in direction if candidates direction does not match.
NGContainerFragmentBuilder& AddOutOfFlowChildCandidate(
NGBlockNode,
- const NGLogicalOffset& child_offset);
-
- // Inline candidates are laid out line-relative, not fragment-relative.
- NGContainerFragmentBuilder& AddInlineOutOfFlowChildCandidate(
- NGBlockNode,
- const NGLogicalOffset& child_line_offset,
- TextDirection line_direction,
- LayoutObject* inline_container);
+ const NGLogicalOffset& child_offset,
+ base::Optional<TextDirection> container_direction = base::nullopt);
NGContainerFragmentBuilder& AddOutOfFlowDescendant(
NGOutOfFlowPositionedDescendant descendant);
@@ -166,6 +164,9 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
#endif
protected:
+ friend class NGPhysicalContainerFragment;
+ friend class NGLayoutResult;
+
// An out-of-flow positioned-candidate is a temporary data structure used
// within the NGBoxFragmentBuilder.
//
@@ -184,30 +185,20 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
struct NGOutOfFlowPositionedCandidate {
NGOutOfFlowPositionedDescendant descendant;
NGLogicalOffset child_offset; // Logical offset of child's top left vertex.
- bool is_line_relative; // True if offset is relative to line, not fragment.
- TextDirection line_direction;
-
- NGOutOfFlowPositionedCandidate(
- NGOutOfFlowPositionedDescendant descendant_arg,
- NGLogicalOffset child_offset_arg)
- : descendant(descendant_arg),
- child_offset(child_offset_arg),
- is_line_relative(false) {}
-
- NGOutOfFlowPositionedCandidate(
- NGOutOfFlowPositionedDescendant descendant_arg,
- NGLogicalOffset child_offset_arg,
- TextDirection line_direction_arg)
- : descendant(descendant_arg),
- child_offset(child_offset_arg),
- is_line_relative(true),
- line_direction(line_direction_arg) {}
+
+ NGOutOfFlowPositionedCandidate(NGOutOfFlowPositionedDescendant descendant,
+ NGLogicalOffset child_offset)
+ : descendant(descendant), child_offset(child_offset) {}
};
- NGContainerFragmentBuilder(scoped_refptr<const ComputedStyle> style,
+ NGContainerFragmentBuilder(NGLayoutInputNode node,
+ scoped_refptr<const ComputedStyle> style,
WritingMode writing_mode,
TextDirection direction)
- : NGFragmentBuilder(std::move(style), writing_mode, direction) {}
+ : NGFragmentBuilder(std::move(style), writing_mode, direction),
+ node_(node) {}
+
+ NGLayoutInputNode node_;
LayoutUnit bfc_line_offset_;
base::Optional<LayoutUnit> bfc_block_offset_;
@@ -238,8 +229,7 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
bool is_pushed_by_floats_ = false;
bool has_orthogonal_flow_roots_ = false;
-
- friend class NGPhysicalContainerFragment;
+ bool has_depends_on_percentage_block_size_child_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
index 1172302da6d..a2b06d56827 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -273,9 +273,9 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAutoSize) {
offset:unplaced size:1000x323
offset:0,0 size:126x323
offset:13,0 size:50x200
- offset:0,0 size:25x200
- offset:25,0 size:25x200
offset:50,0 size:0x0
+ offset:-50,0 size:25x200
+ offset:-25,0 size:25x200
offset:3,200 size:120x120
offset:10,10 size:100x100
)DUMP";
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index 2b3e9f641b2..8eebac187d1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -11,7 +11,9 @@
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -20,68 +22,115 @@ namespace blink {
NGFlexLayoutAlgorithm::NGFlexLayoutAlgorithm(NGBlockNode node,
const NGConstraintSpace& space,
const NGBreakToken* break_token)
- : NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {
+ : NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)),
+ border_scrollbar_padding_(
+ CalculateBorderScrollbarPadding(ConstraintSpace(), Node())),
+ borders_(ComputeBorders(ConstraintSpace(), Style())),
+ padding_(ComputePadding(ConstraintSpace(), Style())),
+ is_column_(Style().IsColumnFlexDirection()) {
container_builder_.SetIsNewFormattingContext(space.IsNewFormattingContext());
}
-scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
- DCHECK(!Style().IsColumnFlexDirection())
- << "Column flexboxes aren't supported yet";
- DCHECK(!NeedMinMaxSize(ConstraintSpace(), Style()))
- << "Don't support that yet";
-
- NGLogicalSize flex_container_border_box_size =
- CalculateBorderBoxSize(ConstraintSpace(), Node());
- NGBoxStrut flex_container_border_scrollbar_padding =
- CalculateBorderScrollbarPadding(ConstraintSpace(), Node());
- NGLogicalSize flex_container_content_box_size = ShrinkAvailableSize(
- flex_container_border_box_size, flex_container_border_scrollbar_padding);
- LayoutUnit flex_container_border_box_inline_size =
- flex_container_border_box_size.inline_size;
- LayoutUnit flex_container_content_inline_size =
- flex_container_content_box_size.inline_size;
-
- FlexLayoutAlgorithm algorithm(&Style(), flex_container_content_inline_size);
+bool NGFlexLayoutAlgorithm::MainAxisIsInlineAxis(NGBlockNode child) {
+ return child.Style().IsHorizontalWritingMode() ==
+ FlexLayoutAlgorithm::IsHorizontalFlow(Style());
+}
+
+LayoutUnit NGFlexLayoutAlgorithm::MainAxisContentExtent(
+ LayoutUnit sum_hypothetical_main_size) {
+ if (Style().IsColumnFlexDirection()) {
+ return ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(),
+ sum_hypothetical_main_size + (borders_ + padding_).BlockSum()) -
+ border_scrollbar_padding_.BlockSum();
+ }
+ return content_box_size_.inline_size;
+}
+
+void NGFlexLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode child) {
+ // TODO(dgrogan): There's stuff from
+ // https://www.w3.org/TR/css-flexbox-1/#abspos-items that isn't done here.
+ // Specifically, neither rtl nor alignment is handled here, at least.
+ // Look at LayoutFlexibleBox::PrepareChildForPositionedLayout and
+ // SetStaticPositionForPositionedLayout to see how to statically position
+ // this.
+ container_builder_.AddOutOfFlowChildCandidate(
+ child, {border_scrollbar_padding_.inline_start,
+ border_scrollbar_padding_.block_start});
+}
+
+void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
+ const bool is_horizontal_flow = algorithm->IsHorizontalFlow();
for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child;
generic_child = generic_child.NextSibling()) {
NGBlockNode child = ToNGBlockNode(generic_child);
- if (child.IsOutOfFlowPositioned())
+ if (child.IsOutOfFlowPositioned()) {
+ HandleOutOfFlowPositioned(child);
continue;
+ }
const ComputedStyle& child_style = child.Style();
- NGConstraintSpaceBuilder builder(ConstraintSpace(),
- child_style.GetWritingMode(),
- /* is_new_fc */ true);
- SetOrthogonalFallbackInlineSizeIfNeeded(Style(), child, &builder);
+ NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
+ child_style.GetWritingMode(),
+ /* is_new_fc */ true);
+ SetOrthogonalFallbackInlineSizeIfNeeded(Style(), child, &space_builder);
+ // TODO(dgrogan): Set IsShrinkToFit here when cross axis size is auto, at
+ // least for correctness. For perf, don't set it if the item will later be
+ // stretched or we won't hit the cache later.
NGConstraintSpace child_space =
- builder.SetAvailableSize(flex_container_content_box_size)
- .SetPercentageResolutionSize(flex_container_content_box_size)
+ space_builder.SetAvailableSize(content_box_size_)
+ .SetPercentageResolutionSize(content_box_size_)
.ToConstraintSpace();
+ NGBoxStrut border_padding_in_child_writing_mode =
+ ComputeBorders(child_space, child_style) +
+ ComputePadding(child_space, child_style);
+ NGPhysicalBoxStrut physical_border_padding(
+ border_padding_in_child_writing_mode.ConvertToPhysical(
+ child_style.GetWritingMode(), child_style.Direction()));
LayoutUnit main_axis_border_and_padding =
- ComputeBorders(child_space, child_style).InlineSum() +
- ComputePadding(child_space, child_style).InlineSum();
- // ComputeMinMaxSize will layout the child if it has an orthogonal writing
- // mode. MinMaxSize will be in the container's inline direction.
+ is_horizontal_flow ? physical_border_padding.HorizontalSum()
+ : physical_border_padding.VerticalSum();
+
+ // We want the child's min/max size in its writing mode, not ours. We'll
+ // only ever use it if the child's inline axis is our main axis.
MinMaxSizeInput zero_input;
MinMaxSize min_max_sizes_border_box = child.ComputeMinMaxSize(
- ConstraintSpace().GetWritingMode(), zero_input, &child_space);
+ child_style.GetWritingMode(), zero_input, &child_space);
+ // TODO(dgrogan): Don't layout every time, just when you need to.
+ scoped_refptr<NGLayoutResult> layout_result =
+ child.Layout(child_space, nullptr /*break token*/);
+ NGFragment fragment_in_child_writing_mode(
+ child_style.GetWritingMode(), *layout_result->PhysicalFragment());
LayoutUnit flex_base_border_box;
- if (child_style.FlexBasis().IsAuto() && child_style.Width().IsAuto()) {
- flex_base_border_box = min_max_sizes_border_box.max_size;
+ const Length& length_in_main_axis =
+ is_horizontal_flow ? child_style.Width() : child_style.Height();
+ const Length& flex_basis = child_style.FlexBasis();
+ if (flex_basis.IsAuto() && length_in_main_axis.IsAuto()) {
+ if (MainAxisIsInlineAxis(child))
+ flex_base_border_box = min_max_sizes_border_box.max_size;
+ else
+ flex_base_border_box = fragment_in_child_writing_mode.BlockSize();
} else {
- Length length_to_resolve = child_style.FlexBasis();
- if (length_to_resolve.IsAuto())
- length_to_resolve = child_style.Width();
+ const Length& length_to_resolve =
+ flex_basis.IsAuto() ? length_in_main_axis : flex_basis;
DCHECK(!length_to_resolve.IsAuto());
- // TODO(dgrogan): Use ResolveBlockLength here for column flex boxes.
-
- flex_base_border_box = ResolveInlineLength(
- child_space, child_style, min_max_sizes_border_box, length_to_resolve,
- LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
+ if (MainAxisIsInlineAxis(child)) {
+ flex_base_border_box = ResolveInlineLength(
+ child_space, child_style, min_max_sizes_border_box,
+ length_to_resolve, LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout);
+ } else {
+ // Flex container's main axis is in child's block direction. Child's
+ // flex basis is in child's block direction.
+ flex_base_border_box = ResolveBlockLength(
+ child_space, child_style, length_to_resolve,
+ fragment_in_child_writing_mode.BlockSize(),
+ LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
+ }
}
// Spec calls this "flex base size"
@@ -91,34 +140,78 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
LayoutUnit flex_base_content_size =
flex_base_border_box - main_axis_border_and_padding;
- LayoutUnit main_axis_margin =
- ComputeMarginsForSelf(child_space, child_style).InlineSum();
+ NGPhysicalBoxStrut physical_child_margins =
+ ComputePhysicalMargins(child_space, child_style);
+ LayoutUnit main_axis_margin = is_horizontal_flow
+ ? physical_child_margins.HorizontalSum()
+ : physical_child_margins.VerticalSum();
- // TODO(dgrogan): When child has a min/max-{width,height} set, call
- // Resolve{Inline,Block}Length here with child's style and constraint space.
- // Pass kMinSize, kMaxSize as appropriate.
- // Further, min-width:auto has special meaning for flex items. We'll need to
- // calculate that here by either extracting the logic from legacy or
- // reimplementing. When resolved, pass it here.
- // https://www.w3.org/TR/css-flexbox-1/#min-size-auto
MinMaxSize min_max_sizes_in_main_axis_direction{LayoutUnit(),
LayoutUnit::Max()};
+ const Length& max = is_horizontal_flow ? child.Style().MaxWidth()
+ : child.Style().MaxHeight();
+ if (MainAxisIsInlineAxis(child)) {
+ min_max_sizes_in_main_axis_direction.max_size = ResolveInlineLength(
+ child_space, child_style, min_max_sizes_border_box, max,
+ LengthResolveType::kMaxSize, LengthResolvePhase::kLayout);
+ } else {
+ min_max_sizes_in_main_axis_direction.max_size = ResolveBlockLength(
+ child_space, child_style, max,
+ fragment_in_child_writing_mode.BlockSize(),
+ LengthResolveType::kMaxSize, LengthResolvePhase::kLayout);
+ }
+
+ const Length& min = is_horizontal_flow ? child.Style().MinWidth()
+ : child.Style().MinHeight();
+ if (min.IsAuto()) {
+ if (algorithm->ShouldApplyMinSizeAutoForChild(*child.GetLayoutBox())) {
+ // TODO(dgrogan): Port logic from
+ // https://www.w3.org/TR/css-flexbox-1/#min-size-auto and
+ // LayoutFlexibleBox::ComputeMinAndMaxSizesForChild
+ }
+ } else if (MainAxisIsInlineAxis(child)) {
+ min_max_sizes_in_main_axis_direction.min_size = ResolveInlineLength(
+ child_space, child_style, min_max_sizes_border_box, min,
+ LengthResolveType::kMinSize, LengthResolvePhase::kLayout);
+ } else {
+ min_max_sizes_in_main_axis_direction.min_size = ResolveBlockLength(
+ child_space, child_style, min,
+ fragment_in_child_writing_mode.BlockSize(),
+ LengthResolveType::kMinSize, LengthResolvePhase::kLayout);
+ }
+
algorithm
- .emplace_back(child.GetLayoutBox(), flex_base_content_size,
- min_max_sizes_in_main_axis_direction,
- main_axis_border_and_padding, main_axis_margin)
+ ->emplace_back(child.GetLayoutBox(), flex_base_content_size,
+ min_max_sizes_in_main_axis_direction,
+ main_axis_border_and_padding, main_axis_margin)
.ng_input_node = child;
}
+}
+
+scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
+ // TODO(dgrogan): Pass padding+borders as optimization.
+ border_box_size_ = CalculateBorderBoxSize(ConstraintSpace(), Node());
+ content_box_size_ =
+ ShrinkAvailableSize(border_box_size_, border_scrollbar_padding_);
+
+ const LayoutUnit line_break_length = MainAxisContentExtent(LayoutUnit::Max());
+ algorithm.emplace(&Style(), line_break_length);
+ const bool is_horizontal_flow = algorithm->IsHorizontalFlow();
- LayoutUnit main_axis_offset =
- flex_container_border_scrollbar_padding.inline_start;
- LayoutUnit cross_axis_offset =
- flex_container_border_scrollbar_padding.block_start;
+ ConstructAndAppendFlexItems();
+
+ LayoutUnit main_axis_offset = border_scrollbar_padding_.inline_start;
+ LayoutUnit cross_axis_offset = border_scrollbar_padding_.block_start;
+ if (is_column_) {
+ main_axis_offset = border_scrollbar_padding_.block_start;
+ cross_axis_offset = border_scrollbar_padding_.inline_start;
+ }
FlexLine* line;
- while ((line = algorithm.ComputeNextFlexLine(
- flex_container_border_box_inline_size))) {
- // TODO(dgrogan): This parameter is more complicated for columns.
- line->SetContainerMainInnerSize(flex_container_content_inline_size);
+ LayoutUnit max_main_axis_extent;
+ while (
+ (line = algorithm->ComputeNextFlexLine(border_box_size_.inline_size))) {
+ line->SetContainerMainInnerSize(
+ MainAxisContentExtent(line->sum_hypothetical_main_size));
line->FreezeInflexibleItems();
while (!line->ResolveFlexibleLengths()) {
continue;
@@ -127,24 +220,34 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
FlexItem& flex_item = line->line_items[i];
WritingMode child_writing_mode =
- flex_item.box->StyleRef().GetWritingMode();
- NGConstraintSpaceBuilder builder(ConstraintSpace(), child_writing_mode,
- /* is_new_fc */ true);
+ flex_item.ng_input_node.Style().GetWritingMode();
+ NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
+ child_writing_mode,
+ /* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), flex_item.ng_input_node,
- &builder);
-
- NGLogicalSize available_size(flex_item.flexed_content_size +
- flex_item.main_axis_border_and_padding,
- flex_container_content_box_size.block_size);
- builder.SetAvailableSize(available_size);
- builder.SetPercentageResolutionSize(flex_container_content_box_size);
- builder.SetIsFixedSizeInline(true);
- NGConstraintSpace child_space = builder.ToConstraintSpace();
+ &space_builder);
+
+ NGLogicalSize available_size;
+ if (is_column_) {
+ available_size.inline_size = content_box_size_.inline_size;
+ available_size.block_size = flex_item.flexed_content_size +
+ flex_item.main_axis_border_and_padding;
+ space_builder.SetIsFixedSizeBlock(true);
+ } else {
+ available_size.inline_size = flex_item.flexed_content_size +
+ flex_item.main_axis_border_and_padding;
+ available_size.block_size = content_box_size_.block_size;
+ space_builder.SetIsFixedSizeInline(true);
+ }
+ space_builder.SetAvailableSize(available_size);
+ space_builder.SetPercentageResolutionSize(content_box_size_);
+ NGConstraintSpace child_space = space_builder.ToConstraintSpace();
flex_item.layout_result =
- ToNGBlockNode(flex_item.ng_input_node)
- .Layout(child_space, nullptr /*break token*/);
+ flex_item.ng_input_node.Layout(child_space, nullptr /*break token*/);
flex_item.cross_axis_size =
- flex_item.layout_result->PhysicalFragment()->Size().height;
+ is_horizontal_flow
+ ? flex_item.layout_result->PhysicalFragment()->Size().height
+ : flex_item.layout_result->PhysicalFragment()->Size().width;
// TODO(dgrogan): Port logic from
// LayoutFlexibleBox::CrossAxisIntrinsicExtentForChild?
flex_item.cross_axis_intrinsic_size = flex_item.cross_axis_size;
@@ -152,29 +255,47 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
// cross_axis_offset is updated in each iteration of the loop, for passing
// in to the next iteration.
line->ComputeLineItemsPosition(main_axis_offset, cross_axis_offset);
-
-
- // TODO(dgrogan): For column flex containers, keep track of tallest flex
- // line and pass to ComputeBlockSizeForFragment as content_size.
+ max_main_axis_extent =
+ std::max(max_main_axis_extent, line->main_axis_extent);
}
- LayoutUnit intrinsic_block_content_size = cross_axis_offset;
+ LayoutUnit intrinsic_block_content_size =
+ is_column_ ? max_main_axis_extent
+ : cross_axis_offset - border_scrollbar_padding_.block_start;
LayoutUnit intrinsic_block_size =
- intrinsic_block_content_size +
- flex_container_border_scrollbar_padding.BlockSum();
+ intrinsic_block_content_size + border_scrollbar_padding_.BlockSum();
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), intrinsic_block_size);
- // Apply stretch alignment.
- // TODO(dgrogan): Move this to its own method, which means making some of the
- // container-specific local variables into data members.
- // TODO(dgrogan): Change this to final_content_cross_size when column
- // flexboxes are supported.
- LayoutUnit final_content_block_size =
- block_size - flex_container_border_scrollbar_padding.BlockSum();
- if (!algorithm.IsMultiline() && !algorithm.FlexLines().IsEmpty())
- algorithm.FlexLines()[0].cross_axis_extent = final_content_block_size;
-
- for (FlexLine& line_context : algorithm.FlexLines()) {
+ container_builder_.SetBlockSize(block_size);
+ container_builder_.SetInlineSize(border_box_size_.inline_size);
+ container_builder_.SetBorders(borders_);
+ container_builder_.SetPadding(padding_);
+
+ GiveLinesAndItemsFinalPositionAndSize();
+
+ NGOutOfFlowLayoutPart(&container_builder_, Node().IsAbsoluteContainer(),
+ Node().IsFixedContainer(),
+ borders_ + Node().GetScrollbarSizes(),
+ ConstraintSpace(), Style())
+ .Run();
+
+ return container_builder_.ToBoxFragment();
+}
+
+void NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
+ // TODO(dgrogan): This needs to eventually encompass all of the behavior in
+ // LayoutFlexibleBox::RepositionLogicalHeightDependentFlexItems, but for now
+ // it only does stretch alignment.
+ LayoutUnit final_content_cross_size =
+ container_builder_.BlockSize() - border_scrollbar_padding_.BlockSum();
+ if (is_column_) {
+ final_content_cross_size =
+ border_box_size_.inline_size - border_scrollbar_padding_.InlineSum();
+ }
+ if (!algorithm->IsMultiline() && !algorithm->FlexLines().IsEmpty())
+ algorithm->FlexLines()[0].cross_axis_extent = final_content_cross_size;
+
+ for (FlexLine& line_context : algorithm->FlexLines()) {
for (wtf_size_t child_number = 0;
child_number < line_context.line_items.size(); ++child_number) {
FlexItem& flex_item = line_context.line_items[child_number];
@@ -182,41 +303,91 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
flex_item.ComputeStretchedSize();
WritingMode child_writing_mode =
- flex_item.box->StyleRef().GetWritingMode();
- NGConstraintSpaceBuilder builder(ConstraintSpace(), child_writing_mode,
- /* is_new_fc */ true);
+ flex_item.ng_input_node.Style().GetWritingMode();
+ NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
+ child_writing_mode,
+ /* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(
- Style(), flex_item.ng_input_node, &builder);
+ Style(), flex_item.ng_input_node, &space_builder);
NGLogicalSize available_size(flex_item.flexed_content_size +
flex_item.main_axis_border_and_padding,
flex_item.cross_axis_size);
- builder.SetAvailableSize(available_size);
- builder.SetPercentageResolutionSize(flex_container_content_box_size);
- builder.SetIsFixedSizeInline(true);
- builder.SetIsFixedSizeBlock(true);
- NGConstraintSpace child_space = builder.ToConstraintSpace();
- flex_item.layout_result =
- ToNGBlockNode(flex_item.ng_input_node)
- .Layout(child_space, /* break_token */ nullptr);
+ if (is_column_)
+ available_size.Flip();
+ space_builder.SetAvailableSize(available_size);
+ space_builder.SetPercentageResolutionSize(content_box_size_);
+ space_builder.SetIsFixedSizeInline(true);
+ space_builder.SetIsFixedSizeBlock(true);
+ NGConstraintSpace child_space = space_builder.ToConstraintSpace();
+ flex_item.layout_result = flex_item.ng_input_node.Layout(
+ child_space, /* break_token */ nullptr);
}
+ // TODO(dgrogan): Add an extra pass for kColumnReverse containers like
+ // legacy does in LayoutColumnReverse.
+
+ // AddChild treats location parameter as logical offset from parent rect.
+ // TODO(dgrogan): Does this need to transpose the location for
+ // non-horizontal flexboxes, like
+ // LayoutFlexibleBox::SetFlowAwareLocationForChild does?
container_builder_.AddChild(
*flex_item.layout_result,
{flex_item.desired_location.X(), flex_item.desired_location.Y()});
}
}
-
- container_builder_.SetBlockSize(block_size);
- container_builder_.SetInlineSize(flex_container_border_box_inline_size);
- container_builder_.SetBorders(ComputeBorders(ConstraintSpace(), Style()));
- container_builder_.SetPadding(ComputePadding(ConstraintSpace(), Style()));
- return container_builder_.ToBoxFragment();
}
base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
- // TODO(dgrogan): Implement this.
- return base::nullopt;
+ MinMaxSize sizes;
+ if (Node().ShouldApplySizeContainment()) {
+ // TODO(dgrogan): When this code was written it didn't make any more tests
+ // pass, so it may be wrong or untested.
+ if (input.size_type == NGMinMaxSizeType::kBorderBoxSize)
+ sizes = border_scrollbar_padding_.InlineSum();
+ return sizes;
+ }
+
+ for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child;
+ generic_child = generic_child.NextSibling()) {
+ NGBlockNode child = ToNGBlockNode(generic_child);
+ if (child.IsOutOfFlowPositioned())
+ continue;
+ // Use default MinMaxSizeInput:
+ // - Children of flexbox ignore any specified float properties, so
+ // children never have to take floated siblings into account, and
+ // external floats don't make it through the new formatting context that
+ // flexbox establishes.
+ // - We want the child's border box MinMaxSize, which is the default.
+ MinMaxSize child_min_max_sizes =
+ ComputeMinAndMaxContentContribution(Style(), child, MinMaxSizeInput());
+ NGBoxStrut child_margins = ComputeMinMaxMargins(Style(), child);
+ child_min_max_sizes += child_margins.InlineSum();
+ if (is_column_) {
+ sizes.min_size = std::max(sizes.min_size, child_min_max_sizes.min_size);
+ sizes.max_size = std::max(sizes.max_size, child_min_max_sizes.max_size);
+ } else {
+ sizes.max_size += child_min_max_sizes.max_size;
+ if (IsMultiline())
+ sizes.min_size = std::max(sizes.min_size, child_min_max_sizes.min_size);
+ else
+ sizes.min_size += child_min_max_sizes.min_size;
+ }
+ }
+ sizes.max_size = std::max(sizes.max_size, sizes.min_size);
+
+ // Due to negative margins, it is possible that we calculated a negative
+ // intrinsic width. Make sure that we never return a negative width.
+ sizes.Encompass(LayoutUnit());
+
+ if (input.size_type == NGMinMaxSizeType::kBorderBoxSize)
+ sizes += border_scrollbar_padding_.InlineSum();
+
+ return sizes;
+}
+
+bool NGFlexLayoutAlgorithm::IsMultiline() const {
+ return Style().FlexWrap() != EFlexWrap::kNowrap;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
index bdea54d0137..64867f04ff8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/flexible_box_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
namespace blink {
@@ -29,6 +30,30 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
base::Optional<MinMaxSize> ComputeMinMaxSize(
const MinMaxSizeInput&) const override;
+
+ private:
+ void ConstructAndAppendFlexItems();
+ void GiveLinesAndItemsFinalPositionAndSize();
+ // This is same method as FlexItem but we need that logic before FlexItem is
+ // constructed.
+ bool MainAxisIsInlineAxis(NGBlockNode child);
+ LayoutUnit MainAxisContentExtent(LayoutUnit sum_hypothetical_main_size);
+
+ void HandleOutOfFlowPositioned(NGBlockNode child);
+ // TODO(dgrogan): This is redundant with FlexLayoutAlgorithm.IsMultiline() but
+ // it's needed before the algorithm is instantiated. Figure out how to
+ // not reimplement.
+ bool IsMultiline() const;
+
+ const NGBoxStrut border_scrollbar_padding_;
+ const NGBoxStrut borders_;
+ const NGBoxStrut padding_;
+ const bool is_column_;
+ NGLogicalSize border_box_size_;
+ NGLogicalSize content_box_size_;
+ // This is populated at the top of Layout(), so isn't available in
+ // ComputeMinMaxSize() or anything it calls.
+ base::Optional<FlexLayoutAlgorithm> algorithm;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
index e9472e84174..1c074e2d457 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -312,54 +312,6 @@ NGPositionedFloat PositionFloat(
return NGPositionedFloat(std::move(layout_result), float_bfc_offset);
}
-void PositionFloats(const NGLogicalSize& float_available_size,
- const NGLogicalSize& float_percentage_size,
- const NGLogicalSize& float_replaced_percentage_size,
- const NGBfcOffset& origin_bfc_offset,
- NGUnpositionedFloatVector& unpositioned_floats,
- const NGConstraintSpace& parent_space,
- const ComputedStyle& parent_style,
- NGExclusionSpace* exclusion_space,
- NGPositionedFloatVector* positioned_floats) {
- positioned_floats->ReserveCapacity(positioned_floats->size() +
- unpositioned_floats.size());
-
- for (NGUnpositionedFloat& unpositioned_float : unpositioned_floats) {
- positioned_floats->push_back(PositionFloat(
- float_available_size, float_percentage_size,
- float_replaced_percentage_size, origin_bfc_offset, &unpositioned_float,
- parent_space, parent_style, exclusion_space));
- }
-}
-
-void AddUnpositionedFloat(NGUnpositionedFloatVector* unpositioned_floats,
- NGContainerFragmentBuilder* fragment_builder,
- NGUnpositionedFloat unpositioned_float,
- const NGConstraintSpace& parent_space) {
- // The same float node should not be added more than once.
- DCHECK(
- !RemoveUnpositionedFloat(unpositioned_floats, unpositioned_float.node));
-
- if (fragment_builder && !fragment_builder->BfcBlockOffset()) {
- fragment_builder->AddAdjoiningFloatTypes(
- unpositioned_float.IsLineLeft(parent_space.Direction())
- ? kFloatTypeLeft
- : kFloatTypeRight);
- }
- unpositioned_floats->push_back(std::move(unpositioned_float));
-}
-
-bool RemoveUnpositionedFloat(NGUnpositionedFloatVector* unpositioned_floats,
- NGBlockNode float_node) {
- for (NGUnpositionedFloat& unpositioned_float : *unpositioned_floats) {
- if (unpositioned_float.node == float_node) {
- unpositioned_floats->erase(&unpositioned_float);
- return true;
- }
- }
- return false;
-}
-
NGFloatTypes ToFloatTypes(EClear clear) {
switch (clear) {
default:
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
index 7ccfa6cb82a..554f9791270 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
@@ -7,7 +7,6 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -15,9 +14,7 @@
namespace blink {
class ComputedStyle;
-class NGBlockNode;
class NGConstraintSpace;
-class NGContainerFragmentBuilder;
class NGExclusionSpace;
struct NGBfcOffset;
struct NGLogicalSize;
@@ -53,30 +50,6 @@ PositionFloat(const NGLogicalSize& float_available_size,
const ComputedStyle& parent_style,
NGExclusionSpace* exclusion_space);
-// Positions the list of {@code unpositioned_floats}. Adds them as exclusions to
-// {@code space}.
-CORE_EXPORT void PositionFloats(
- const NGLogicalSize& float_available_size,
- const NGLogicalSize& float_percentage_size,
- const NGLogicalSize& float_replaced_percentage_size,
- const NGBfcOffset& origin_bfc_offset,
- NGUnpositionedFloatVector& unpositioned_floats,
- const NGConstraintSpace& parent_space,
- const ComputedStyle& parent_style,
- NGExclusionSpace* exclusion_space,
- NGPositionedFloatVector* positioned_floats);
-
-// Add a pending float to the list. It will be committed (positioned) once we
-// have resolved the BFC block offset.
-void AddUnpositionedFloat(NGUnpositionedFloatVector* unpositioned_floats,
- NGContainerFragmentBuilder* fragment_builder,
- NGUnpositionedFloat unpositioned_float,
- const NGConstraintSpace& parent_space);
-
-// Remove a pending float from the list.
-bool RemoveUnpositionedFloat(NGUnpositionedFloatVector* unpositioned_floats,
- NGBlockNode float_node);
-
NGFloatTypes ToFloatTypes(EClear clear);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
index f5da6f6bb79..6dd3fe95b12 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -52,7 +52,7 @@ class CORE_EXPORT NGFragmentBuilder {
}
void SetBlockSize(LayoutUnit block_size) { size_.block_size = block_size; }
- LayoutObject* GetLayoutObject() { return layout_object_; }
+ const LayoutObject* GetLayoutObject() { return layout_object_; }
protected:
NGFragmentBuilder(scoped_refptr<const ComputedStyle> style,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
index a52471a7cd2..080066025f5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -80,19 +80,16 @@ MinMaxSize NGLayoutInputNode::ComputeMinMaxSize(
}
void NGLayoutInputNode::IntrinsicSize(
- NGLogicalSize* default_intrinsic_size,
base::Optional<LayoutUnit>* computed_inline_size,
base::Optional<LayoutUnit>* computed_block_size,
NGLogicalSize* aspect_ratio) const {
DCHECK(IsReplaced());
-
- LayoutSize box_intrinsic_size = box_->IntrinsicSize();
- // Transform to logical coordinates if needed.
- if (!Style().IsHorizontalWritingMode())
- box_intrinsic_size = box_intrinsic_size.TransposedSize();
- *default_intrinsic_size =
- NGLogicalSize(box_intrinsic_size.Width(), box_intrinsic_size.Height());
-
+ if (ShouldApplySizeContainment()) {
+ *computed_inline_size = LayoutUnit();
+ *computed_block_size = LayoutUnit();
+ *aspect_ratio = NGLogicalSize(LayoutUnit(), LayoutUnit());
+ return;
+ }
IntrinsicSizingInfo legacy_sizing_info;
ToLayoutReplaced(box_)->ComputeIntrinsicSizingInfo(legacy_sizing_info);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index b7cbcd6206e..1c28ffa95d9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -54,8 +54,17 @@ class CORE_EXPORT NGLayoutInputNode {
// When adding new values, ensure type_ below has enough bits.
};
+ static NGLayoutInputNode Create(LayoutBox* box, NGLayoutInputNodeType type) {
+ // This function should create an instance of the subclass. This works
+ // because subclasses are not virtual and do not add fields.
+ return NGLayoutInputNode(box, type);
+ }
+
NGLayoutInputNode(std::nullptr_t) : box_(nullptr), type_(kBlock) {}
+ NGLayoutInputNodeType Type() const {
+ return static_cast<NGLayoutInputNodeType>(type_);
+ }
bool IsInline() const { return type_ == kInline; }
bool IsBlock() const { return type_ == kBlock; }
@@ -73,7 +82,7 @@ class CORE_EXPORT NGLayoutInputNode {
}
bool IsBody() const { return IsBlock() && box_->IsBody(); }
bool IsDocumentElement() const { return box_->IsDocumentElement(); }
- bool IsFlexItem() const { return IsBlock() && box_->IsFlexItem(); }
+ bool IsFlexItem() const { return IsBlock() && box_->IsFlexItemIncludingNG(); }
bool ShouldBeConsideredAsReplaced() const {
return box_->ShouldBeConsideredAsReplaced();
}
@@ -130,11 +139,8 @@ class CORE_EXPORT NGLayoutInputNode {
// Returns intrinsic sizing information for replaced elements.
// ComputeReplacedSize can use it to compute actual replaced size.
- // The function arguments return values from LegacyLayout intrinsic size
- // computations: LayoutReplaced::IntrinsicSizingInfo,
- // and LayoutReplaced::IntrinsicSize.
- void IntrinsicSize(NGLogicalSize* default_intrinsic_size,
- base::Optional<LayoutUnit>* computed_inline_size,
+ // Corresponds to Legacy's LayoutReplaced::IntrinsicSizingInfo.
+ void IntrinsicSize(base::Optional<LayoutUnit>* computed_inline_size,
base::Optional<LayoutUnit>* computed_block_size,
NGLogicalSize* aspect_ratio) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index c17b1a98d7c..ff4165a8a9b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -30,6 +30,7 @@ NGLayoutResult::NGLayoutResult(
is_pushed_by_floats_(builder->is_pushed_by_floats_),
adjoining_floats_(builder->adjoining_floats_),
has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_),
+ depends_on_percentage_block_size_(DependsOnPercentageBlockSize(*builder)),
status_(kSuccess) {
DCHECK(physical_fragment) << "Use the other constructor for aborting layout";
root_fragment_.fragment_ = std::move(physical_fragment);
@@ -44,9 +45,10 @@ NGLayoutResult::NGLayoutResult(NGLayoutResultStatus status,
initial_break_before_(EBreakBetween::kAuto),
final_break_after_(EBreakBetween::kAuto),
has_forced_break_(false),
- is_pushed_by_floats_(false),
+ is_pushed_by_floats_(builder->is_pushed_by_floats_),
adjoining_floats_(kFloatTypeNone),
has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_),
+ depends_on_percentage_block_size_(false),
status_(status) {
DCHECK_NE(status, kSuccess)
<< "Use the other constructor for successful layout";
@@ -67,10 +69,10 @@ NGLayoutResult::NGLayoutResult(
is_pushed_by_floats_(builder->is_pushed_by_floats_),
adjoining_floats_(builder->adjoining_floats_),
has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_),
+ depends_on_percentage_block_size_(DependsOnPercentageBlockSize(*builder)),
status_(kSuccess) {
root_fragment_.fragment_ = std::move(physical_fragment);
oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
- positioned_floats_ = std::move(builder->positioned_floats_);
}
// We can't use =default here because RefCounted can't be copied.
@@ -78,7 +80,6 @@ NGLayoutResult::NGLayoutResult(const NGLayoutResult& other,
base::Optional<LayoutUnit> bfc_block_offset)
: root_fragment_(other.root_fragment_),
oof_positioned_descendants_(other.oof_positioned_descendants_),
- positioned_floats_(other.positioned_floats_),
unpositioned_list_marker_(other.unpositioned_list_marker_),
exclusion_space_(other.exclusion_space_),
bfc_line_offset_(other.bfc_line_offset_),
@@ -92,10 +93,50 @@ NGLayoutResult::NGLayoutResult(const NGLayoutResult& other,
is_pushed_by_floats_(other.is_pushed_by_floats_),
adjoining_floats_(other.adjoining_floats_),
has_orthogonal_flow_roots_(other.has_orthogonal_flow_roots_),
+ depends_on_percentage_block_size_(
+ other.depends_on_percentage_block_size_),
status_(other.status_) {}
// Define the destructor here, so that we can forward-declare more in the
// header.
NGLayoutResult::~NGLayoutResult() = default;
+bool NGLayoutResult::DependsOnPercentageBlockSize(
+ const NGContainerFragmentBuilder& builder) {
+ NGLayoutInputNode node = builder.node_;
+
+ if (!node || node.IsInline())
+ return builder.has_depends_on_percentage_block_size_child_;
+
+ // NOTE: If an element is OOF positioned, and has top/bottom constraints
+ // which are percentage based, this function will return false.
+ //
+ // This is fine as the top/bottom constraints are computed *before* layout,
+ // and the result is set as a fixed-block-size constraint. (And the caching
+ // logic will never check the result of this function).
+ //
+ // The result of this function still may be used for an OOF positioned
+ // element if it has a percentage block-size however, but this will return
+ // the correct result from below.
+
+ const ComputedStyle& style = builder.Style();
+ if (style.LogicalHeight().IsAuto() &&
+ builder.has_depends_on_percentage_block_size_child_) {
+ // Quirks mode has different %-block-size behaviour, than standards mode.
+ // An arbitrary descendant may depend on the percentage resolution
+ // block-size given.
+ // If this is also an anonymous block we need to mark ourselves dependent
+ // if we have a dependent child.
+ if (node.IsAnonymousBlock() || node.GetDocument().InQuirksMode())
+ return true;
+ }
+
+ if (style.LogicalHeight().IsPercentOrCalc() ||
+ style.LogicalMinHeight().IsPercentOrCalc() ||
+ style.LogicalMaxHeight().IsPercentOrCalc())
+ return true;
+
+ return false;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index 1ed7835c703..3fc57842112 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -21,9 +21,9 @@
namespace blink {
class NGBoxFragmentBuilder;
+class NGContainerFragmentBuilder;
class NGExclusionSpace;
class NGLineBoxFragmentBuilder;
-struct NGPositionedFloat;
// The NGLayoutResult stores the resulting data from layout. This includes
// geometry information in form of a NGPhysicalFragment, which is kept around
@@ -58,14 +58,6 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return oof_positioned_descendants_;
}
- // A line-box can have a list of positioned floats. These should be added to
- // the line-box's parent fragment (as floats which occur within a line-box do
- // not appear a children).
- const Vector<NGPositionedFloat>& PositionedFloats() const {
- DCHECK(root_fragment_->Type() == NGPhysicalFragment::kFragmentLineBox);
- return positioned_floats_;
- }
-
const NGUnpositionedListMarker& UnpositionedListMarker() const {
return unpositioned_list_marker_;
}
@@ -119,6 +111,12 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
bool HasOrthogonalFlowRoots() const { return has_orthogonal_flow_roots_; }
+ // Returns true if we aren't able to re-use this layout result if the
+ // PercentageResolutionBlockSize changes.
+ bool DependsOnPercentageBlockSize() const {
+ return depends_on_percentage_block_size_;
+ }
+
private:
friend class NGBoxFragmentBuilder;
friend class NGLineBoxFragmentBuilder;
@@ -135,11 +133,11 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
// default copy constructor will not work because RefCounted can't be copied.
NGLayoutResult(const NGLayoutResult&) = delete;
+ static bool DependsOnPercentageBlockSize(const NGContainerFragmentBuilder&);
+
NGLink root_fragment_;
Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
- Vector<NGPositionedFloat> positioned_floats_;
-
NGUnpositionedListMarker unpositioned_list_marker_;
const NGExclusionSpace exclusion_space_;
@@ -158,6 +156,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
unsigned adjoining_floats_ : 2; // NGFloatTypes
unsigned has_orthogonal_flow_roots_ : 1;
+ unsigned depends_on_percentage_block_size_ : 1;
unsigned status_ : 1;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index 912a10ee5fa..69be5abdb8e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
@@ -51,7 +52,7 @@ inline EBlockAlignment BlockAlignment(const ComputedStyle& style,
}
}
-inline bool InlineLengthMayChange(Length length,
+inline bool InlineLengthMayChange(const Length& length,
const NGConstraintSpace& new_space,
const NGConstraintSpace& old_space) {
// Percentage inline margins will affect the size if the size is unspecified
@@ -72,24 +73,13 @@ inline bool InlineLengthMayChange(Length length,
return false;
}
-inline bool BlockLengthMayChange(Length length,
+inline bool BlockLengthMayChange(const Length& length,
const NGConstraintSpace& new_space,
const NGConstraintSpace& old_space) {
if (length.IsFillAvailable()) {
if (new_space.AvailableSize().block_size !=
old_space.AvailableSize().block_size)
return true;
- } else if (length.IsAuto() || length.IsPercentOrCalc()) {
- // Note that we check percentage resolution changes for 'auto' values here
- // (in addition to percent values). The reason is that percentage resolution
- // block sizes may be passed through auto-sized blocks, in some cases,
- // e.g. for anonymous blocks, and also in quirks mode.
- if (new_space.PercentageResolutionBlockSize() !=
- old_space.PercentageResolutionBlockSize())
- return true;
- if (new_space.ReplacedPercentageResolutionBlockSize() !=
- old_space.ReplacedPercentageResolutionBlockSize())
- return true;
}
return false;
}
@@ -371,9 +361,9 @@ MinMaxSize ComputeMinAndMaxContentContribution(
min_and_max ? min_and_max->max_size : NGSizeIndefinite;
MinMaxSize computed_sizes;
- Length inline_size = writing_mode == WritingMode::kHorizontalTb
- ? style.Width()
- : style.Height();
+ const Length& inline_size = writing_mode == WritingMode::kHorizontalTb
+ ? style.Width()
+ : style.Height();
if (inline_size.IsAuto() || inline_size.IsPercentOrCalc() ||
inline_size.GetType() == kFillAvailable ||
inline_size.GetType() == kFitContent) {
@@ -391,9 +381,9 @@ MinMaxSize ComputeMinAndMaxContentContribution(
}
}
- Length max_length = writing_mode == WritingMode::kHorizontalTb
- ? style.MaxWidth()
- : style.MaxHeight();
+ const Length& max_length = writing_mode == WritingMode::kHorizontalTb
+ ? style.MaxWidth()
+ : style.MaxHeight();
LayoutUnit max;
if (IsParallelWritingMode(writing_mode, style.GetWritingMode())) {
max = ResolveInlineLength(space, style, min_and_max, max_length,
@@ -406,9 +396,9 @@ MinMaxSize ComputeMinAndMaxContentContribution(
}
computed_sizes.Constrain(max);
- Length min_length = writing_mode == WritingMode::kHorizontalTb
- ? style.MinWidth()
- : style.MinHeight();
+ const Length& min_length = writing_mode == WritingMode::kHorizontalTb
+ ? style.MinWidth()
+ : style.MinHeight();
LayoutUnit min;
if (IsParallelWritingMode(writing_mode, style.GetWritingMode())) {
min = ResolveInlineLength(space, style, min_and_max, min_length,
@@ -492,7 +482,13 @@ LayoutUnit ComputeInlineSizeForFragment(
logical_width = Length(kFitContent);
LayoutBox* box = node.GetLayoutBox();
- if (!box->PreferredLogicalWidthsDirty() && !override_minmax) {
+ // If we have usable cached min/max intrinsic sizes, use those if we can. They
+ // will normally also be constrained to {min,max}-inline-size, but not if
+ // percentages are involved. In such cases we'll have to calculate and apply
+ // the constraints on our own.
+ if (!box->PreferredLogicalWidthsDirty() && !override_minmax &&
+ !style.LogicalMinWidth().IsPercentOrCalc() &&
+ !style.LogicalMaxWidth().IsPercentOrCalc()) {
if (logical_width.GetType() == kFitContent) {
// This is not as easy as {min, max}.ShrinkToFit() because we also need
// to subtract inline margins from the available size. The code in
@@ -584,77 +580,169 @@ NGLogicalSize ComputeReplacedSize(
const NGConstraintSpace& space,
const base::Optional<MinMaxSize>& child_minmax) {
DCHECK(node.IsReplaced());
+ const ComputedStyle& style = node.Style();
- NGLogicalSize replaced_size;
-
- NGLogicalSize default_intrinsic_size;
- base::Optional<LayoutUnit> computed_inline_size;
- base::Optional<LayoutUnit> computed_block_size;
- NGLogicalSize aspect_ratio;
-
- node.IntrinsicSize(&default_intrinsic_size, &computed_inline_size,
- &computed_block_size, &aspect_ratio);
+ NGBoxStrut border_padding =
+ ComputeBorders(space, style) + ComputePadding(space, style);
+ LayoutUnit inline_min = ResolveInlineLength(
+ space, style, child_minmax, style.LogicalMinWidth(),
+ LengthResolveType::kMinSize, LengthResolvePhase::kLayout, border_padding);
+ LayoutUnit inline_max = ResolveInlineLength(
+ space, style, child_minmax, style.LogicalMaxWidth(),
+ LengthResolveType::kMaxSize, LengthResolvePhase::kLayout, border_padding);
+ LayoutUnit block_min = ResolveBlockLength(
+ space, style, style.LogicalMinHeight(), border_padding.BlockSum(),
+ LengthResolveType::kMinSize, LengthResolvePhase::kLayout, border_padding);
+ LayoutUnit block_max = ResolveBlockLength(
+ space, style, style.LogicalMaxHeight(), LayoutUnit::Max(),
+ LengthResolveType::kMaxSize, LengthResolvePhase::kLayout, border_padding);
- const ComputedStyle& style = node.Style();
- Length inline_length = style.LogicalWidth();
- Length block_length = style.LogicalHeight();
-
- // Compute inline size
- if (inline_length.IsAuto()) {
- if (block_length.IsAuto() || aspect_ratio.IsEmpty()) {
- // Use intrinsic values if inline_size cannot be computed from block_size.
- if (computed_inline_size.has_value())
- replaced_size.inline_size = computed_inline_size.value();
- else
- replaced_size.inline_size = default_intrinsic_size.inline_size;
- replaced_size.inline_size +=
- (ComputeBorders(space, style) + ComputePadding(space, style))
- .InlineSum();
- } else {
- // inline_size is computed from block_size.
- replaced_size.inline_size =
- ResolveBlockLength(
- space, style, block_length, default_intrinsic_size.block_size,
- LengthResolveType::kContentSize, LengthResolvePhase::kLayout) *
- aspect_ratio.inline_size / aspect_ratio.block_size;
- }
- } else {
- // inline_size is resolved directly.
- replaced_size.inline_size = ResolveInlineLength(
+ const Length& inline_length = style.LogicalWidth();
+ const Length& block_length = style.LogicalHeight();
+ base::Optional<LayoutUnit> replaced_inline;
+ if (!inline_length.IsAuto()) {
+ replaced_inline = ResolveInlineLength(
space, style, child_minmax, inline_length,
LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
+ replaced_inline =
+ ConstrainByMinMax(*replaced_inline, inline_min, inline_max);
}
+ base::Optional<LayoutUnit> replaced_block;
+ if (!block_length.IsAuto()) {
+ replaced_block = ResolveBlockLength(
+ space, style, block_length, space.AvailableSize().block_size,
+ LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
+ replaced_block = ConstrainByMinMax(*replaced_block, block_min, block_max);
+ }
+ if (replaced_inline && replaced_block)
+ return NGLogicalSize(*replaced_inline, *replaced_block);
+
+ base::Optional<LayoutUnit> intrinsic_inline;
+ base::Optional<LayoutUnit> intrinsic_block;
+ NGLogicalSize aspect_ratio;
- // Compute block size
- if (block_length.IsAuto()) {
- if (inline_length.IsAuto() || aspect_ratio.IsEmpty()) {
- // Use intrinsic values if block_size cannot be computed from inline_size.
- if (computed_block_size.has_value())
- replaced_size.block_size = LayoutUnit(computed_block_size.value());
- else
- replaced_size.block_size = default_intrinsic_size.block_size;
- replaced_size.block_size +=
- (ComputeBorders(space, style) + ComputePadding(space, style))
- .BlockSum();
+ node.IntrinsicSize(&intrinsic_inline, &intrinsic_block, &aspect_ratio);
+ // Computing intrinsic size is complicated by the fact that
+ // intrinsic_inline, intrinsic_block, and aspect_ratio can all
+ // be empty independent of each other.
+ // https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width
+ if (intrinsic_inline)
+ intrinsic_inline = *intrinsic_inline + border_padding.InlineSum();
+ else if (aspect_ratio.IsEmpty())
+ intrinsic_inline = LayoutUnit(300) + border_padding.InlineSum();
+ if (intrinsic_block)
+ intrinsic_block = *intrinsic_block + border_padding.BlockSum();
+ else if (aspect_ratio.IsEmpty())
+ intrinsic_block = LayoutUnit(150) + border_padding.BlockSum();
+ if (!intrinsic_inline) {
+ if (intrinsic_block) {
+ intrinsic_inline = ((*intrinsic_block - border_padding.BlockSum()) *
+ aspect_ratio.inline_size / aspect_ratio.block_size) +
+ border_padding.InlineSum();
} else {
- // block_size is computed from inline_size.
- replaced_size.block_size =
- ResolveInlineLength(space, style, child_minmax, inline_length,
- LengthResolveType::kContentSize,
- LengthResolvePhase::kLayout) *
- aspect_ratio.block_size / aspect_ratio.inline_size;
+ intrinsic_inline = space.AvailableSize().inline_size;
}
+ }
+ if (!intrinsic_block) {
+ intrinsic_block = ((*intrinsic_inline - border_padding.InlineSum()) *
+ aspect_ratio.block_size / aspect_ratio.inline_size) +
+ border_padding.BlockSum();
+ }
+ // At this point, both intrinsic_inline and intrinsic_block have value.
+ // If we only know one length, the other length gets computed wrt one we know.
+ auto ComputeBlockFromInline = [&replaced_inline, &aspect_ratio,
+ &border_padding](LayoutUnit default_block) {
+ DCHECK(default_block >= border_padding.BlockSum());
+ if (aspect_ratio.IsEmpty())
+ return default_block;
+ return ((*replaced_inline - border_padding.InlineSum()) *
+ aspect_ratio.block_size / aspect_ratio.inline_size) +
+ border_padding.BlockSum();
+ };
+
+ auto ComputeInlineFromBlock = [&replaced_block, &aspect_ratio,
+ &border_padding](LayoutUnit default_inline) {
+ DCHECK(default_inline >= border_padding.InlineSum());
+ if (aspect_ratio.IsEmpty())
+ return default_inline;
+ return ((*replaced_block - border_padding.BlockSum()) *
+ aspect_ratio.inline_size / aspect_ratio.block_size) +
+ border_padding.InlineSum();
+ };
+ if (replaced_inline) {
+ DCHECK(!replaced_block);
+ replaced_block = ComputeBlockFromInline(*intrinsic_block);
+ replaced_block = ConstrainByMinMax(*replaced_block, block_min, block_max);
+ } else if (replaced_block) {
+ DCHECK(!replaced_inline);
+ replaced_inline = ComputeInlineFromBlock(*intrinsic_inline);
+ replaced_inline =
+ ConstrainByMinMax(*replaced_inline, inline_min, inline_max);
} else {
- replaced_size.block_size = ResolveBlockLength(
- space, style, block_length, default_intrinsic_size.block_size,
- LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
+ // If both lengths are unknown, they get defined by intrinsic values.
+ DCHECK(!replaced_inline);
+ DCHECK(!replaced_block);
+ replaced_inline = *intrinsic_inline;
+ replaced_block = *intrinsic_block;
+ // If lengths are constrained, keep aspect ratio.
+ // The side that shrank the most defines the other side.
+ LayoutUnit constrained_inline =
+ ConstrainByMinMax(*replaced_inline, inline_min, inline_max);
+ LayoutUnit constrained_block =
+ ConstrainByMinMax(*replaced_block, block_min, block_max);
+ if (constrained_inline != replaced_inline ||
+ constrained_block != replaced_block) {
+ LayoutUnit inline_ratio =
+ (*replaced_inline - border_padding.InlineSum()) == LayoutUnit()
+ ? LayoutUnit::Max()
+ : (constrained_inline - border_padding.InlineSum()) /
+ (*replaced_inline - border_padding.InlineSum());
+ LayoutUnit block_ratio =
+ (*replaced_block - border_padding.BlockSum()) == LayoutUnit()
+ ? LayoutUnit::Max()
+ : (constrained_block - border_padding.BlockSum()) /
+ (*replaced_block - border_padding.BlockSum());
+
+ // The following implements spec table from section 10.4 at
+ // https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
+ // Translating specs to code:
+ // inline_ratio < 1 => w > max_width
+ // inline_ratio > 1 => w < min_width
+ // block_ratio < 1 => h > max_height
+ // block_ratio > 1 => h < min_height
+ LayoutUnit one_unit(1);
+ if (inline_ratio != one_unit || block_ratio != one_unit) {
+ if ((inline_ratio < one_unit && block_ratio > one_unit) ||
+ (inline_ratio > one_unit && block_ratio < one_unit)) {
+ // Constraints caused us to grow in one dimension and shrink in the
+ // other. Use both constrained sizes.
+ replaced_inline = constrained_inline;
+ replaced_block = constrained_block;
+ } else if (block_ratio == one_unit ||
+ (inline_ratio < one_unit && inline_ratio <= block_ratio) ||
+ (inline_ratio > one_unit && inline_ratio >= block_ratio)) {
+ // The inline size got constrained more extremely than the block size.
+ // Use constrained inline size, re-calculate block size from aspect
+ // ratio.
+ replaced_inline = constrained_inline;
+ replaced_block = ComputeBlockFromInline(constrained_block);
+ } else {
+ // The block size got constrained more extremely than the inline size.
+ // Use constrained block size, re-calculate inline size from aspect
+ // ratio.
+ replaced_block = constrained_block;
+ replaced_inline = ComputeInlineFromBlock(constrained_inline);
+ }
+ }
+ }
}
- return replaced_size;
+ return NGLogicalSize(*replaced_inline, *replaced_block);
}
bool SizeMayChange(const ComputedStyle& style,
const NGConstraintSpace& new_space,
- const NGConstraintSpace& old_space) {
+ const NGConstraintSpace& old_space,
+ const NGLayoutResult& layout_result) {
DCHECK_EQ(new_space.IsFixedSizeInline(), old_space.IsFixedSizeInline());
DCHECK_EQ(new_space.IsFixedSizeBlock(), old_space.IsFixedSizeBlock());
@@ -688,6 +776,16 @@ bool SizeMayChange(const ComputedStyle& style,
BlockLengthMayChange(style.LogicalMinHeight(), new_space, old_space) ||
BlockLengthMayChange(style.LogicalMaxHeight(), new_space, old_space))
return true;
+ // We only need to check if the PercentageResolutionBlockSizes match if the
+ // layout result has explicitly marked itself as dependent.
+ if (layout_result.DependsOnPercentageBlockSize()) {
+ if (new_space.PercentageResolutionBlockSize() !=
+ old_space.PercentageResolutionBlockSize())
+ return true;
+ if (new_space.ReplacedPercentageResolutionBlockSize() !=
+ old_space.ReplacedPercentageResolutionBlockSize())
+ return true;
+ }
}
if (new_space.PercentageResolutionInlineSize() !=
@@ -800,9 +898,10 @@ NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
if (child.IsInline())
return NGBoxStrut();
- Length inline_start_margin_length =
+ const Length& inline_start_margin_length =
child.Style().MarginStartUsing(parent_style);
- Length inline_end_margin_length = child.Style().MarginEndUsing(parent_style);
+ const Length& inline_end_margin_length =
+ child.Style().MarginEndUsing(parent_style);
// TODO(ikilpatrick): We may want to re-visit calculated margins at some
// point. Currently "margin-left: calc(10px + 50%)" will resolve to 0px, but
@@ -880,6 +979,14 @@ NGBoxStrut ComputePadding(const NGConstraintSpace& constraint_space,
style.PaddingBefore());
padding.block_end = ResolveMarginPaddingLength(percentage_resolution_size,
style.PaddingAfter());
+
+ if (style.Display() == EDisplay::kTableCell) {
+ // Compatibility hack to mach legacy layout. Legacy layout floors padding on
+ // the block sides, but not on the inline sides. o.O
+ padding.block_start = LayoutUnit(padding.block_start.Floor());
+ padding.block_end = LayoutUnit(padding.block_end.Floor());
+ }
+
return padding;
}
@@ -915,8 +1022,7 @@ void ResolveInlineMargins(const ComputedStyle& style,
LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
TextDirection direction,
- LayoutUnit space_left,
- LayoutUnit trailing_spaces_width) {
+ LayoutUnit space_left) {
bool is_ltr = IsLtr(direction);
if (text_align == ETextAlign::kStart || text_align == ETextAlign::kJustify)
text_align = is_ltr ? ETextAlign::kLeft : ETextAlign::kRight;
@@ -937,7 +1043,7 @@ LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
case ETextAlign::kWebkitRight: {
// In RTL, trailing spaces appear on the left of the line.
if (UNLIKELY(!is_ltr))
- return space_left - trailing_spaces_width;
+ return space_left;
// Wide lines spill out of the block based off direction.
// So even if text-align is right, if direction is LTR, wide lines
// should overflow out of the right side of the block.
@@ -951,9 +1057,9 @@ LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
return (space_left / 2).ClampNegativeToZero();
// In RTL, trailing spaces appear on the left of the line.
if (space_left > LayoutUnit())
- return (space_left / 2).ClampNegativeToZero() - trailing_spaces_width;
+ return (space_left / 2).ClampNegativeToZero();
// In RTL, wide lines should spill out to the left, same as kRight.
- return space_left - trailing_spaces_width;
+ return space_left;
}
default:
NOTREACHED();
@@ -965,7 +1071,7 @@ LayoutUnit InlineOffsetForTextAlign(const ComputedStyle& container_style,
LayoutUnit space_left) {
TextDirection direction = container_style.Direction();
LayoutUnit line_offset = LineOffsetForTextAlign(
- container_style.GetTextAlign(), direction, space_left, LayoutUnit());
+ container_style.GetTextAlign(), direction, space_left);
return IsLtr(direction) ? line_offset : space_left - line_offset;
}
@@ -1009,7 +1115,7 @@ NGLogicalSize CalculateBorderBoxSize(
if (node.Style().LogicalHeight().IsPercentOrCalc() ||
node.Style().LogicalMinHeight().IsPercentOrCalc() ||
node.Style().LogicalMaxHeight().IsPercentOrCalc() ||
- (node.GetLayoutBox()->IsFlexItem() &&
+ (node.GetLayoutBox()->IsFlexItemIncludingNG() &&
node.Style().FlexBasis().IsPercentOrCalc())) {
// This call has the side-effect of setting HasPercentHeightDescendants
// correctly.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 20bb742474f..4ab2a8abd00 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -24,6 +24,7 @@ struct MinMaxSizeInput;
class NGConstraintSpace;
class NGBlockNode;
class NGLayoutInputNode;
+class NGLayoutResult;
// LengthResolvePhase indicates what type of layout pass we are currently in.
// This changes how lengths are resolved. kIntrinsic must be used during the
@@ -130,10 +131,11 @@ MinMaxSize ComputeMinAndMaxContentContribution(
NGLayoutInputNode child,
const MinMaxSizeInput& input);
-// Resolves the computed value in style.logicalWidth (Length) to a layout unit,
-// then constrains the result by the resolved min logical width and max logical
-// width from the ComputedStyle object. Calls Node::ComputeMinMaxSize if needed.
-// override_minmax is provided *solely* for use by unit tests.
+// Returns inline size of the node's border box by resolving the computed value
+// in style.logicalWidth (Length) to a layout unit, adding border and padding,
+// then constraining the result by the resolved min logical width and max
+// logical width from the ComputedStyle object. Calls Node::ComputeMinMaxSize if
+// needed. override_minmax is provided *solely* for use by unit tests.
// border_padding can be passed in as an optimization; otherwise this function
// will compute it itself.
CORE_EXPORT LayoutUnit ComputeInlineSizeForFragment(
@@ -160,7 +162,8 @@ ComputeReplacedSize(const NGLayoutInputNode&,
// computed style and child content remain unchanged.
bool SizeMayChange(const ComputedStyle&,
const NGConstraintSpace& new_space,
- const NGConstraintSpace& old_space);
+ const NGConstraintSpace& old_space,
+ const NGLayoutResult& layout_result);
// Based on available inline size, CSS computed column-width, CSS computed
// column-count and CSS used column-gap, return CSS used column-count.
@@ -305,8 +308,7 @@ CORE_EXPORT void ResolveInlineMargins(
// text-align, direction and amount of unused space.
CORE_EXPORT LayoutUnit LineOffsetForTextAlign(ETextAlign,
TextDirection,
- LayoutUnit space_left,
- LayoutUnit trailing_spaces_width);
+ LayoutUnit space_left);
// Same as |LineOffsetForTextAlign| but returns the logical inline offset
// instead of line-left offset.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 6a8ee5eaedd..be334862956 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -25,7 +25,7 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
NGBoxFragmentBuilder* container_builder,
bool contains_absolute,
bool contains_fixed,
- const NGBoxStrut& borders_and_scrollers,
+ const NGBoxStrut& border_scrollbar,
const NGConstraintSpace& container_space,
const ComputedStyle& container_style,
base::Optional<NGLogicalSize> initial_containing_block_fixed_size)
@@ -34,34 +34,77 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
contains_fixed_(contains_fixed) {
if (!container_builder->HasOutOfFlowDescendantCandidates())
return;
- NGPhysicalBoxStrut physical_borders = borders_and_scrollers.ConvertToPhysical(
- container_style.GetWritingMode(), container_style.Direction());
+
+ NGPhysicalBoxStrut physical_border_scrollbar =
+ border_scrollbar.ConvertToPhysical(container_style.GetWritingMode(),
+ container_style.Direction());
default_containing_block_.style = &container_style;
default_containing_block_.content_size_for_absolute =
container_builder_->Size();
default_containing_block_.content_size_for_absolute.inline_size =
std::max(default_containing_block_.content_size_for_absolute.inline_size -
- borders_and_scrollers.InlineSum(),
+ border_scrollbar.InlineSum(),
LayoutUnit());
default_containing_block_.content_size_for_absolute.block_size =
std::max(default_containing_block_.content_size_for_absolute.block_size -
- borders_and_scrollers.BlockSum(),
+ border_scrollbar.BlockSum(),
LayoutUnit());
default_containing_block_.content_size_for_fixed =
initial_containing_block_fixed_size
? initial_containing_block_fixed_size.value()
: default_containing_block_.content_size_for_absolute;
- default_containing_block_.content_offset = NGLogicalOffset{
- borders_and_scrollers.inline_start, borders_and_scrollers.block_start};
- default_containing_block_.content_physical_offset =
- NGPhysicalOffset(physical_borders.left, physical_borders.top);
+
+ default_containing_block_.container_offset = NGLogicalOffset(
+ border_scrollbar.inline_start, border_scrollbar.block_start);
+ default_containing_block_.physical_container_offset = NGPhysicalOffset(
+ physical_border_scrollbar.left, physical_border_scrollbar.top);
}
void NGOutOfFlowLayoutPart::Run(LayoutBox* only_layout) {
Vector<NGOutOfFlowPositionedDescendant> descendant_candidates;
+ const LayoutObject* current_container = container_builder_->GetLayoutObject();
+
container_builder_->GetAndClearOutOfFlowDescendantCandidates(
- &descendant_candidates, container_builder_->GetLayoutObject());
+ &descendant_candidates, current_container);
+
+ // Special case: containing block is a split inline.
+ // Detailed explanation of what this means is inside
+ // NGOutOfFlowLayoutPart::LayoutDescendant.
+ // This code can be removed once we stop inline splitting.
+ // only_layout is only true when positioning blocks for Legacy.
+ // Cross-anonymous inline containers cannot be done in Legacy.
+ if (descendant_candidates.size() > 0 && current_container && !only_layout &&
+ current_container->IsAnonymousBlock() &&
+ current_container->IsRelPositioned()) {
+ // Comments and code copied from
+ // LayoutBox::ContainingBlockLogicalWidthForPositioned.
+ // Ensure we compute our width based on the width of our rel-pos inline
+ // container rather than any anonymous block created to manage a block-flow
+ // ancestor of ours in the rel-pos inline's inline flow.
+ LayoutBoxModelObject* absolute_containing_block =
+ ToLayoutBox(current_container)->Continuation();
+ // There may be nested parallel inline continuations. We have now found the
+ // innermost inline (which may not be relatively positioned). Locate the
+ // inline that serves as the containing block of this box.
+ while (!absolute_containing_block->CanContainOutOfFlowPositionedElement(
+ EPosition::kAbsolute)) {
+ absolute_containing_block =
+ ToLayoutBoxModelObject(absolute_containing_block->Container());
+ }
+ DCHECK(absolute_containing_block->IsLayoutInline());
+ // Make absolute_containing_block continuation root.
+ absolute_containing_block = ToLayoutBoxModelObject(
+ absolute_containing_block->GetNode()->GetLayoutObject());
+ for (auto& candidate : descendant_candidates) {
+ if (absolute_containing_block->CanContainOutOfFlowPositionedElement(
+ candidate.node.Style().GetPosition())) {
+ candidate.inline_container = absolute_containing_block;
+ container_builder_->AddOutOfFlowDescendant(candidate);
+ }
+ }
+ return;
+ }
while (descendant_candidates.size() > 0) {
ComputeInlineContainingBlocks(descendant_candidates);
@@ -70,7 +113,7 @@ void NGOutOfFlowLayoutPart::Run(LayoutBox* only_layout) {
(!only_layout || candidate.node.GetLayoutBox() == only_layout)) {
NGLogicalOffset offset;
scoped_refptr<NGLayoutResult> result =
- LayoutDescendant(candidate, &offset);
+ LayoutDescendant(candidate, &offset, only_layout);
container_builder_->AddChild(*result, offset);
if (candidate.node.GetLayoutBox() != only_layout)
candidate.node.UseOldOutOfFlowPositioning();
@@ -82,7 +125,7 @@ void NGOutOfFlowLayoutPart::Run(LayoutBox* only_layout) {
// This happens when an absolute container has a fixed child.
descendant_candidates.Shrink(0);
container_builder_->GetAndClearOutOfFlowDescendantCandidates(
- &descendant_candidates, container_builder_->GetLayoutObject());
+ &descendant_candidates, current_container);
}
}
@@ -100,223 +143,185 @@ NGOutOfFlowLayoutPart::GetContainingBlockInfo(
void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
Vector<NGOutOfFlowPositionedDescendant> descendants) {
- HashMap<const LayoutObject*, NGBoxFragmentBuilder::FragmentPair>
- inline_container_fragments;
+ NGBoxFragmentBuilder::InlineContainingBlockMap inline_container_fragments;
for (auto& descendant : descendants) {
if (descendant.inline_container &&
!inline_container_fragments.Contains(descendant.inline_container)) {
- NGBoxFragmentBuilder::FragmentPair fragment_pair = {};
+ NGBoxFragmentBuilder::InlineContainingBlockGeometry inline_geometry = {};
inline_container_fragments.insert(descendant.inline_container,
- fragment_pair);
+ inline_geometry);
}
}
// Fetch start/end fragment info.
- NGLogicalSize container_builder_size;
container_builder_->ComputeInlineContainerFragments(
- &inline_container_fragments, &container_builder_size);
+ &inline_container_fragments);
+ NGLogicalSize container_builder_size = container_builder_->Size();
NGPhysicalSize container_builder_physical_size =
ToNGPhysicalSize(container_builder_size,
default_containing_block_.style->GetWritingMode());
// Translate start/end fragments into ContainingBlockInfo.
for (auto& block_info : inline_container_fragments) {
// Variables needed to describe ContainingBlockInfo
- const ComputedStyle* inline_cb_style;
+ const ComputedStyle* inline_cb_style = block_info.key->Style();
NGLogicalSize inline_cb_size;
- NGLogicalOffset inline_content_offset;
- NGPhysicalOffset inline_content_physical_offset;
- NGLogicalOffset default_container_offset;
- if (!block_info.value.start_fragment) {
+ NGLogicalOffset container_offset;
+ NGPhysicalOffset physical_container_offset;
+
+ if (!block_info.value.has_value()) {
// This happens when Legacy block is the default container.
// In this case, container builder does not have any fragments because
// ng layout algorithm did not run.
DCHECK(block_info.key->IsLayoutInline());
- inline_cb_style = block_info.key->Style();
NOTIMPLEMENTED()
<< "Inline containing block might need geometry information";
// TODO(atotic) ContainingBlockInfo geometry
// must be computed from Legacy algorithm
} else {
- inline_cb_style = &block_info.value.start_fragment->Style();
+ DCHECK(inline_cb_style);
+
+ // TODO Creating dummy constraint space just to get borders feels wrong.
NGConstraintSpace dummy_constraint_space =
NGConstraintSpaceBuilder(inline_cb_style->GetWritingMode(),
inline_cb_style->GetWritingMode(),
/* is_new_fc */ false)
.ToConstraintSpace();
-
- // TODO Creating dummy constraint space just to get borders feels wrong.
NGBoxStrut inline_cb_borders =
ComputeBorders(dummy_constraint_space, *inline_cb_style);
- NGPhysicalBoxStrut physical_borders = inline_cb_borders.ConvertToPhysical(
- inline_cb_style->GetWritingMode(), inline_cb_style->Direction());
- NGBoxStrut inline_cb_padding =
- ComputePadding(dummy_constraint_space, *inline_cb_style);
- // Warning: lots of non-obvious coordinate manipulation ahead.
+ // The calculation below determines the size of the inline containing
+ // block rect.
+ //
+ // To perform this calculation we:
+ // 1. Determine the start_offset "^", this is at the logical-start (wrt.
+ // default containing block), of the start fragment rect.
+ // 2. Determine the end_offset "$", this is at the logical-end (wrt.
+ // default containing block), of the end fragment rect.
+ // 3. Determine the logical rectangle defined by these two offsets.
//
- // High level goal is:
- // - Find logical topleft of start fragment, and logical bottomright
- // of end fragment.
- // - Use these to compute inline-cb geometry:
- // - inline-cb size (content_size)
- // - inline-cb offset from containing block (default_container_offset)
+ // Case 1a: Same direction, overlapping fragments.
+ // +---------------
+ // ---> |^*****-------->
+ // +*----*---------
+ // * *
+ // ------*----*+
+ // ----> *****$| --->
+ // ------------+
//
- // We start with:
- // start_fragment, which has physical offset from start_linebox_fragment,
- // end_fragment, also with physical offset.
- // start_linebox_fragment, which has logical offset from containing box.
- // end_linebox_fragment, which also has logical offset from containing
- // box.
+ // Case 1b: Different direction, overlapping fragments.
+ // +---------------
+ // ---> ^******* <-----|
+ // *------*--------
+ // * *
+ // -----*------*
+ // |<-- *******$ --->
+ // ------------+
//
- // Then magic happens.^H^H^H^H^H^H^H
+ // Case 2a: Same direction, non-overlapping fragments.
+ // +--------
+ // ---------> |^ ----->
+ // +*-------
+ // *
+ // --------+ *
+ // ------->| $ --->
+ // --------+
//
- // Then we do the following:
- // 1. Find start fragment physical topleft wrt containing box.
- // - convert start_fragment offset to logical.
- // - convert start fragment inline/block start to physical.
- // - convert linebox topleft to physical.
- // - add start fragment to linebox topleft
- // 2. Find end fragment bottom right wrt containing box
- // - convert end fragment offset to logical.
- // - convert end fragment inline/block end to physical
- // - convert linebox topleft to physical
- // - add end fragment bottomLeft to linebox topleft
- // 3. Convert both topleft/bottomright to logical, so that we can
- // 4. Enforce logical topLeft < bottomRight
- // 5. Compute size, physical offset
- const NGPhysicalFragment* start_fragment =
- block_info.value.start_fragment;
- const NGPhysicalLineBoxFragment* start_linebox_fragment =
- block_info.value.start_linebox_fragment;
+ // Case 2b: Same direction, non-overlapping fragments.
+ // +--------
+ // ---------> ^ <-----|
+ // *--------
+ // *
+ // --------+ *
+ // | <------ $ --->
+ // --------+
+ //
+ // Note in cases [1a, 2a] we need to account for the inline borders of
+ // the rectangles, where-as in [1b, 2b] we do not. This is handled by the
+ // is_same_direction check(s).
+ //
+ // Note in cases [2a, 2b] we don't allow a "negative" containing block
+ // size, we clamp negative sizes to zero.
WritingMode container_writing_mode =
default_containing_block_.style->GetWritingMode();
TextDirection container_direction =
default_containing_block_.style->Direction();
- // Step 1
- NGLogicalOffset start_fragment_logical_offset =
- block_info.value.start_fragment_union_rect.offset.ConvertToLogical(
- container_writing_mode, container_direction,
- start_linebox_fragment->Size(),
- block_info.value.start_fragment_union_rect.size);
- // Text fragments do not include inline-cb borders and padding.
- if (start_fragment->IsText()) {
- start_fragment_logical_offset -= inline_cb_borders.StartOffset();
- start_fragment_logical_offset -= inline_cb_padding.StartOffset();
- }
- NGPhysicalOffset start_fragment_physical_offset =
- start_fragment_logical_offset.ConvertToPhysical(
- container_writing_mode, container_direction,
- start_linebox_fragment->Size(), NGPhysicalSize());
- // Step 2
- const NGPhysicalLineBoxFragment* end_linebox_fragment =
- block_info.value.end_linebox_fragment;
- const NGPhysicalFragment* end_fragment = block_info.value.end_fragment;
- NGLogicalOffset end_fragment_logical_offset =
- block_info.value.end_fragment_union_rect.offset.ConvertToLogical(
- container_writing_mode, container_direction,
- end_linebox_fragment->Size(),
- block_info.value.end_fragment_union_rect.size);
- // Text fragments do not include inline-cb borders and padding.
- if (end_fragment->IsText()) {
- end_fragment_logical_offset += NGLogicalOffset(
- inline_cb_borders.inline_end, inline_cb_borders.block_end);
- end_fragment_logical_offset += NGLogicalOffset(
- inline_cb_padding.inline_end, inline_cb_padding.block_end);
- }
- NGLogicalOffset end_fragment_bottom_right =
- end_fragment_logical_offset +
- block_info.value.end_fragment_union_rect.size.ConvertToLogical(
- container_writing_mode);
- NGPhysicalOffset end_fragment_physical_offset =
- end_fragment_bottom_right.ConvertToPhysical(
- container_writing_mode, container_direction,
- end_linebox_fragment->Size(), NGPhysicalSize());
- // Step 3
- NGLogicalOffset start_fragment_logical_offset_wrt_box =
- start_fragment_physical_offset.ConvertToLogical(
- inline_cb_style->GetWritingMode(), inline_cb_style->Direction(),
- container_builder_physical_size, NGPhysicalSize());
- NGLogicalOffset end_fragment_logical_offset_wrt_box =
- end_fragment_physical_offset.ConvertToLogical(
- inline_cb_style->GetWritingMode(), inline_cb_style->Direction(),
- container_builder_physical_size, NGPhysicalSize());
-
- // Step 4
- end_fragment_logical_offset_wrt_box.inline_offset =
- std::max(end_fragment_logical_offset_wrt_box.inline_offset,
- start_fragment_logical_offset_wrt_box.inline_offset +
- inline_cb_borders.InlineSum());
- end_fragment_logical_offset_wrt_box.block_offset =
- std::max(end_fragment_logical_offset_wrt_box.block_offset,
- start_fragment_logical_offset_wrt_box.block_offset +
- inline_cb_borders.BlockSum());
-
- // Step 5
- inline_cb_size.inline_size =
- end_fragment_logical_offset_wrt_box.inline_offset -
- start_fragment_logical_offset_wrt_box.inline_offset -
- inline_cb_borders.InlineSum();
- inline_cb_size.block_size =
- end_fragment_logical_offset_wrt_box.block_offset -
- start_fragment_logical_offset_wrt_box.block_offset -
- inline_cb_borders.BlockSum();
+ bool is_same_direction =
+ container_direction == inline_cb_style->Direction();
+
+ // Step 1 - determine the start_offset.
+ const NGPhysicalOffsetRect& start_rect =
+ block_info.value.value().start_fragment_union_rect;
+ NGLogicalOffset start_offset = start_rect.offset.ConvertToLogical(
+ container_writing_mode, container_direction,
+ container_builder_physical_size, start_rect.size);
+
+ // Make sure we add the inline borders, we don't need to do this in the
+ // inline direction if the blocks are in opposite directions.
+ start_offset.block_offset += inline_cb_borders.block_start;
+ if (is_same_direction)
+ start_offset.inline_offset += inline_cb_borders.inline_start;
+
+ // Step 2 - determine the end_offset.
+ const NGPhysicalOffsetRect& end_rect =
+ block_info.value.value().end_fragment_union_rect;
+ NGLogicalOffset end_offset = end_rect.offset.ConvertToLogical(
+ container_writing_mode, container_direction,
+ container_builder_physical_size, end_rect.size);
+
+ // Add in the size of the fragment to get the logical end of the fragment.
+ end_offset += end_rect.size.ConvertToLogical(container_writing_mode);
+
+ // Make sure we substract the inline borders, we don't need to do this in
+ // the inline direction if the blocks are in opposite directions.
+ end_offset.block_offset -= inline_cb_borders.block_end;
+ if (is_same_direction)
+ end_offset.inline_offset -= inline_cb_borders.inline_end;
+
+ // Make sure we don't end up with a rectangle with "negative" size.
+ end_offset.inline_offset =
+ std::max(end_offset.inline_offset, start_offset.inline_offset);
+
+ // Step 3 - determine the logical rectange.
+
+ // Determine the logical size of the containing block.
+ inline_cb_size = {end_offset.inline_offset - start_offset.inline_offset,
+ end_offset.block_offset - start_offset.block_offset};
DCHECK_GE(inline_cb_size.inline_size, LayoutUnit());
DCHECK_GE(inline_cb_size.block_size, LayoutUnit());
- inline_content_offset = NGLogicalOffset{inline_cb_borders.inline_start,
- inline_cb_borders.block_start};
- inline_content_physical_offset =
- NGPhysicalOffset(physical_borders.left, physical_borders.top);
-
- // NGPaint offset is wrt parent fragment.
- default_container_offset = start_fragment_logical_offset_wrt_box -
- default_containing_block_.content_offset;
- default_container_offset += inline_cb_borders.StartOffset();
+ // Determine the container offsets.
+ container_offset = start_offset;
+ physical_container_offset = container_offset.ConvertToPhysical(
+ container_writing_mode, container_direction,
+ container_builder_physical_size,
+ ToNGPhysicalSize(inline_cb_size, container_writing_mode));
}
containing_blocks_map_.insert(
block_info.key,
ContainingBlockInfo{inline_cb_style, inline_cb_size, inline_cb_size,
- inline_content_offset,
- inline_content_physical_offset,
- default_container_offset});
+ container_offset, physical_container_offset});
}
}
scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
const NGOutOfFlowPositionedDescendant& descendant,
- NGLogicalOffset* offset) {
+ NGLogicalOffset* offset,
+ LayoutBox* only_layout) {
ContainingBlockInfo container_info = GetContainingBlockInfo(descendant);
WritingMode container_writing_mode(container_info.style->GetWritingMode());
WritingMode descendant_writing_mode(descendant.node.Style().GetWritingMode());
- // Adjust the static_position origin.
- // The static_position coordinate origin is relative to default_container's
- // border box.
- // ng_absolute_utils expects static position to be relative to
- // the container's padding box.
- // Adjust static position by offset of container from default container,
- // and default_container border width.
+ // Adjust the static_position (which is currently relative to the default
+ // container's border-box). ng_absolute_utils expects the static position to
+ // be relative to the container's padding-box.
NGStaticPosition static_position(descendant.static_position);
- NGPhysicalSize default_containing_block_physical_size =
- ToNGPhysicalSize(default_containing_block_.ContentSize(
- descendant.node.Style().GetPosition()),
- default_containing_block_.style->GetWritingMode());
- NGPhysicalOffset default_container_physical_offset =
- container_info.default_container_offset.ConvertToPhysical(
- default_containing_block_.style->GetWritingMode(),
- default_containing_block_.style->Direction(),
- default_containing_block_physical_size,
- default_containing_block_physical_size);
-
- static_position.offset = static_position.offset -
- default_containing_block_.content_physical_offset -
- default_container_physical_offset;
+ static_position.offset -= container_info.physical_container_offset;
NGLogicalSize container_content_size =
container_info.ContentSize(descendant.node.Style().GetPosition());
- // The block estimate is in the descendant's writing mode.
+
NGConstraintSpace descendant_constraint_space =
NGConstraintSpaceBuilder(container_writing_mode, descendant_writing_mode,
/* is_new_fc */ true)
@@ -324,8 +329,10 @@ scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
.SetAvailableSize(container_content_size)
.SetPercentageResolutionSize(container_content_size)
.ToConstraintSpace();
- base::Optional<MinMaxSize> min_max_size;
+
+ // The block_estimate is in the descendant's writing mode.
base::Optional<LayoutUnit> block_estimate;
+ base::Optional<MinMaxSize> min_max_size;
scoped_refptr<NGLayoutResult> layout_result = nullptr;
@@ -389,19 +396,16 @@ scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
ToLayoutBlock(node.GetLayoutBox())
->SetIsLegacyInitiatedOutOfFlowLayout(false);
}
- // Compute logical offset, NGAbsolutePhysicalPosition is calculated relative
- // to the padding box so add back the container's borders.
+
NGBoxStrut inset = node_position.inset.ConvertToLogical(
- container_writing_mode, container_info.style->Direction());
+ container_writing_mode, default_containing_block_.style->Direction());
+
+ // inset is relative to the container's padding-box. Convert this to being
+ // relative to the default container's border-box.
offset->inline_offset =
- inset.inline_start +
- default_containing_block_.content_offset.inline_offset;
+ inset.inline_start + container_info.container_offset.inline_offset;
offset->block_offset =
- inset.block_start + default_containing_block_.content_offset.block_offset;
-
- offset->inline_offset +=
- container_info.default_container_offset.inline_offset;
- offset->block_offset += container_info.default_container_offset.block_offset;
+ inset.block_start + container_info.container_offset.block_offset;
base::Optional<LayoutUnit> y = ComputeAbsoluteDialogYPosition(
*descendant.node.GetLayoutBox(),
@@ -413,6 +417,47 @@ scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
offset->inline_offset = y.value();
}
+ // Special case: oof css container is a split inline.
+ // When css container spans multiple anonymous blocks, its dimensions
+ // can only be computed by a block that is an ancestor of all fragments
+ // generated by css container. That block is parent of anonymous containing
+ // block.
+ // That is why instead of OOF being placed by its anononymous container,
+ // they get placed by anonymous container's parent.
+ // This is different from all other OOF blocks, and requires special
+ // handling in several places in the OOF code.
+ // There is an exception to special case: if anonymous block is Legacy,
+ // we cannot do the fancy multiple anonymous block traversal, and we handle
+ // it like regular blocks.
+ //
+ // Detailed example:
+ //
+ // If Layout tree looks like this:
+ // LayoutNGBlockFlow#container
+ // LayoutNGBlockFlow (anonymous#1)
+ // LayoutInline#1 (relative)
+ // LayoutNGBlockFlow (anonymous#2 relative)
+ // LayoutNGBlockFlow#oof (positioned)
+ // LayoutNGBlockFlow (anonymous#3)
+ // LayoutInline#3 (continuation)
+ //
+ // The containing block geometry is defined by split inlines,
+ // LayoutInline#1, LayoutInline#3.
+ // Css container anonymous#2 does not have information needed
+ // to compute containing block geometry.
+ // Therefore, #oof cannot be placed by anonymous#2. NG handles this case
+ // by placing #oof in parent of anonymous (#container).
+ //
+ // But, PaintPropertyTreeBuilder expects #oof.Location() to be wrt
+ // css container, #anonymous2. This is why the code below adjusts
+ // the legacy offset from being wrt #container to being wrt #anonymous2.
+
+ const LayoutObject* container = descendant.node.GetLayoutBox()->Container();
+ if (!only_layout && container->IsAnonymousBlock()) {
+ NGLogicalOffset container_offset =
+ container_builder_->GetChildOffset(container);
+ *offset -= container_offset;
+ }
return layout_result;
}
@@ -423,6 +468,11 @@ bool NGOutOfFlowLayoutPart::IsContainingBlockForDescendant(
// Descendants whose containing block is inline are always positioned
// inside closest parent block flow.
if (descendant.inline_container) {
+ DCHECK(
+ descendant.node.Style().GetPosition() == EPosition::kAbsolute &&
+ descendant.inline_container->CanContainAbsolutePositionObjects() ||
+ (descendant.node.Style().GetPosition() == EPosition::kFixed &&
+ descendant.inline_container->CanContainFixedPositionObjects()));
return true;
}
return (contains_absolute_ && position == EPosition::kAbsolute) ||
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
index caa039058f4..fa22a3d6d2e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -75,15 +75,13 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
const ComputedStyle* style;
// Logical in containing block coordinates.
NGLogicalSize content_size_for_absolute;
- // Content size for fixed is different for icb
+ // Content size for fixed is different for the ICB.
NGLogicalSize content_size_for_fixed;
- // Content offset wrt border box.
- NGLogicalOffset content_offset;
- // Physical content offset wrt border box.
- NGPhysicalOffset content_physical_offset;
- // Logical offset of container padding box
- // wrt default containing block padding box.
- NGLogicalOffset default_container_offset;
+
+ // Offsets (both logical and physical) of the container's padding-box, wrt.
+ // the default container's border-box.
+ NGLogicalOffset container_offset;
+ NGPhysicalOffset physical_container_offset;
NGLogicalSize ContentSize(EPosition position) const {
return position == EPosition::kAbsolute ? content_size_for_absolute
@@ -98,7 +96,8 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
scoped_refptr<NGLayoutResult> LayoutDescendant(
const NGOutOfFlowPositionedDescendant&,
- NGLogicalOffset* offset);
+ NGLogicalOffset* offset,
+ LayoutBox* only_layout);
bool IsContainingBlockForDescendant(
const NGOutOfFlowPositionedDescendant& descendant);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h
index 2f38cb50241..69b0ff6c3fb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h
@@ -27,12 +27,12 @@ struct CORE_EXPORT NGOutOfFlowPositionedDescendant {
NGStaticPosition static_position;
const LayoutObject* inline_container;
NGOutOfFlowPositionedDescendant(
- NGBlockNode node_param,
- NGStaticPosition static_position_param,
- const LayoutObject* inline_container_param = nullptr)
- : node(node_param),
- static_position(static_position_param),
- inline_container(inline_container_param) {}
+ NGBlockNode node,
+ NGStaticPosition static_position,
+ const LayoutObject* inline_container = nullptr)
+ : node(node),
+ static_position(static_position),
+ inline_container(inline_container) {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index a9db9c28c9d..bad99f1b978 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
namespace blink {
@@ -115,9 +116,17 @@ NGPhysicalOffsetRect NGPhysicalBoxFragment::ScrollableOverflow() const {
} else if (layout_object->IsLayoutInline()) {
// Inline overflow is a union of child overflows.
NGPhysicalOffsetRect overflow({}, Size());
+ WritingMode container_writing_mode = Style().GetWritingMode();
+ TextDirection container_direction = Style().Direction();
for (const auto& child_fragment : Children()) {
NGPhysicalOffsetRect child_overflow =
- child_fragment->ScrollableOverflow();
+ child_fragment->ScrollableOverflowForPropagation(layout_object);
+ if (child_fragment->Style() != Style()) {
+ NGPhysicalOffset relative_offset = ComputeRelativeOffset(
+ child_fragment->Style(), container_writing_mode,
+ container_direction, Size());
+ child_overflow.offset += relative_offset;
+ }
child_overflow.offset += child_fragment.Offset();
overflow.Unite(child_overflow);
}
@@ -173,30 +182,18 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
const LayoutObject* layout_object = GetLayoutObject();
DCHECK(layout_object);
if (layout_object->IsLayoutInline()) {
- Vector<LayoutRect> blockflow_outline_rects;
- ToLayoutInline(layout_object)
- ->AddOutlineRects(blockflow_outline_rects, LayoutPoint(), outline_type);
+ Vector<LayoutRect> blockflow_outline_rects =
+ layout_object->PhysicalOutlineRects(LayoutPoint(), outline_type);
// The rectangles returned are offset from the containing block. We need the
- // offset from this fragment. Additionally, the rectangles are offset
- // relatively to the block-start of the container (this matters when
- // writing-mode is vertical-rl). We want them to be purely physical. Apply
- // correction.
+ // offset from this fragment.
if (blockflow_outline_rects.size() > 0) {
- const LayoutBlock* block_for_flipping = nullptr;
LayoutPoint first_fragment_offset = blockflow_outline_rects[0].Location();
- if (UNLIKELY(layout_object->HasFlippedBlocksWritingMode())) {
- block_for_flipping = layout_object->ContainingBlock();
- first_fragment_offset.SetX(block_for_flipping->FlipForWritingMode(
- blockflow_outline_rects[0].MaxX()));
- }
LayoutSize corrected_offset = additional_offset - first_fragment_offset;
for (auto& outline : blockflow_outline_rects) {
// Skip if both width and height are zero. Contaning blocks in empty
// linebox is one such case.
if (outline.Size().IsZero())
continue;
- if (UNLIKELY(block_for_flipping))
- block_for_flipping->FlipForWritingMode(outline);
outline.Move(corrected_offset);
outline_rects->push_back(outline);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 7b36ae549e1..b3fa89a3a7c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -401,6 +401,20 @@ NGPhysicalOffsetRect NGPhysicalFragment::ScrollableOverflow() const {
return {{}, Size()};
}
+NGPhysicalOffsetRect NGPhysicalFragment::ScrollableOverflowForPropagation(
+ const LayoutObject* container) const {
+ DCHECK(container);
+ NGPhysicalOffsetRect overflow = ScrollableOverflow();
+ if (GetLayoutObject() &&
+ GetLayoutObject()->ShouldUseTransformFromContainer(container)) {
+ TransformationMatrix transform;
+ GetLayoutObject()->GetTransformFromContainer(container, LayoutSize(),
+ transform);
+ overflow = NGPhysicalOffsetRect(transform.MapRect(overflow.ToLayoutRect()));
+ }
+ return overflow;
+}
+
void NGPhysicalFragment::PropagateContentsInkOverflow(
NGPhysicalOffsetRect* parent_ink_overflow,
NGPhysicalOffset fragment_offset) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 16ccfd8b8e0..39d44105059 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -190,6 +190,10 @@ class CORE_EXPORT NGPhysicalFragment
// Scrollable overflow. including contents, in the local coordinate.
NGPhysicalOffsetRect ScrollableOverflow() const;
+ // ScrollableOverflow(), with transforms applied wrt container if needed.
+ NGPhysicalOffsetRect ScrollableOverflowForPropagation(
+ const LayoutObject* container) const;
+
// Unite visual rect to propagate to parent's ContentsVisualRect.
void PropagateContentsInkOverflow(NGPhysicalOffsetRect*,
NGPhysicalOffset) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
index d8181ab8fa2..ec224406680 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
@@ -29,6 +29,10 @@ struct CORE_EXPORT NGUnpositionedFloat final {
NGUnpositionedFloat& operator=(NGUnpositionedFloat&&) = default;
NGUnpositionedFloat& operator=(const NGUnpositionedFloat&) = default;
+ bool operator==(const NGUnpositionedFloat& other) const {
+ return node == other.node && token == other.token;
+ }
+
NGBlockNode node;
scoped_refptr<const NGBlockBreakToken> token;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h
deleted file mode 100644
index 3863a12cb25..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_UNPOSITIONED_FLOAT_VECTOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_UNPOSITIONED_FLOAT_VECTOR_H_
-
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-struct NGUnpositionedFloat;
-typedef Vector<NGUnpositionedFloat, 1> NGUnpositionedFloatVector;
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_UNPOSITIONED_FLOAT_VECTOR_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/overflow_model.h b/chromium/third_party/blink/renderer/core/layout/overflow_model.h
index 85aec7ad237..467a4e4e862 100644
--- a/chromium/third_party/blink/renderer/core/layout/overflow_model.h
+++ b/chromium/third_party/blink/renderer/core/layout/overflow_model.h
@@ -82,13 +82,12 @@ inline void UniteLayoutOverflowRect(LayoutRect& layout_overflow,
// functions (addLayoutOverflow, addVisualOverflow, etc.) to keep this
// invariant.
-class SimpleOverflowModel {
- USING_FAST_MALLOC(SimpleOverflowModel);
+class SimpleLayoutOverflowModel {
+ USING_FAST_MALLOC(SimpleLayoutOverflowModel);
public:
- SimpleOverflowModel(const LayoutRect& layout_rect,
- const LayoutRect& visual_rect)
- : layout_overflow_(layout_rect), visual_overflow_(visual_rect) {}
+ SimpleLayoutOverflowModel(const LayoutRect& layout_rect)
+ : layout_overflow_(layout_rect) {}
const LayoutRect& LayoutOverflowRect() const { return layout_overflow_; }
void SetLayoutOverflow(const LayoutRect& rect) { layout_overflow_ = rect; }
@@ -96,6 +95,21 @@ class SimpleOverflowModel {
UniteLayoutOverflowRect(layout_overflow_, rect);
}
+ void Move(LayoutUnit dx, LayoutUnit dy) { layout_overflow_.Move(dx, dy); }
+
+ private:
+ LayoutRect layout_overflow_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleLayoutOverflowModel);
+};
+
+class SimpleVisualOverflowModel {
+ USING_FAST_MALLOC(SimpleVisualOverflowModel);
+
+ public:
+ SimpleVisualOverflowModel(const LayoutRect& visual_rect)
+ : visual_overflow_(visual_rect) {}
+
const LayoutRect& VisualOverflowRect() const { return visual_overflow_; }
void SetVisualOverflow(const LayoutRect& rect) { visual_overflow_ = rect; }
void AddVisualOverflow(const LayoutRect& rect) {
@@ -103,15 +117,18 @@ class SimpleOverflowModel {
}
void Move(LayoutUnit dx, LayoutUnit dy) {
- layout_overflow_.Move(dx, dy);
visual_overflow_.Move(dx, dy);
}
private:
- LayoutRect layout_overflow_;
LayoutRect visual_overflow_;
- DISALLOW_COPY_AND_ASSIGN(SimpleOverflowModel);
+ DISALLOW_COPY_AND_ASSIGN(SimpleVisualOverflowModel);
+};
+
+struct SimpleOverflowModel {
+ base::Optional<SimpleLayoutOverflowModel> layout_overflow;
+ base::Optional<SimpleVisualOverflowModel> visual_overflow;
};
// BoxModelOverflow tracks overflows of a LayoutBox. It separates visual
@@ -141,14 +158,12 @@ class SimpleOverflowModel {
// it clips overflow, otherwise union of self visual overflow and contents
// visual overflow.
-class BoxOverflowModel {
- USING_FAST_MALLOC(BoxOverflowModel);
+class BoxLayoutOverflowModel {
+ USING_FAST_MALLOC(BoxLayoutOverflowModel);
public:
- BoxOverflowModel(const LayoutRect& layout_rect,
- const LayoutRect& self_visual_overflow_rect)
- : layout_overflow_(layout_rect),
- self_visual_overflow_(self_visual_overflow_rect) {}
+ BoxLayoutOverflowModel(const LayoutRect& layout_rect)
+ : layout_overflow_(layout_rect) {}
const LayoutRect& LayoutOverflowRect() const { return layout_overflow_; }
void SetLayoutOverflow(const LayoutRect& rect) { layout_overflow_ = rect; }
@@ -156,6 +171,31 @@ class BoxOverflowModel {
UniteLayoutOverflowRect(layout_overflow_, rect);
}
+ void Move(LayoutUnit dx, LayoutUnit dy) { layout_overflow_.Move(dx, dy); }
+
+ LayoutUnit LayoutClientAfterEdge() const { return layout_client_after_edge_; }
+ void SetLayoutClientAfterEdge(LayoutUnit client_after_edge) {
+ layout_client_after_edge_ = client_after_edge;
+ }
+
+ private:
+ LayoutRect layout_overflow_;
+ LayoutUnit layout_client_after_edge_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoxLayoutOverflowModel);
+};
+
+class BoxVisualOverflowModel {
+ USING_FAST_MALLOC(BoxVisualOverflowModel);
+
+ public:
+ BoxVisualOverflowModel(const LayoutRect& self_visual_overflow_rect)
+ : self_visual_overflow_(self_visual_overflow_rect) {}
+
+ void SetSelfVisualOverflow(const LayoutRect& rect) {
+ self_visual_overflow_ = rect;
+ }
+
const LayoutRect& SelfVisualOverflowRect() const {
return self_visual_overflow_;
}
@@ -163,6 +203,10 @@ class BoxOverflowModel {
self_visual_overflow_.Unite(rect);
}
+ void ClearContentsVisualOverflow() {
+ contents_visual_overflow_ = LayoutRect();
+ }
+
const LayoutRect& ContentsVisualOverflowRect() const {
return contents_visual_overflow_;
}
@@ -171,16 +215,10 @@ class BoxOverflowModel {
}
void Move(LayoutUnit dx, LayoutUnit dy) {
- layout_overflow_.Move(dx, dy);
self_visual_overflow_.Move(dx, dy);
contents_visual_overflow_.Move(dx, dy);
}
- LayoutUnit LayoutClientAfterEdge() const { return layout_client_after_edge_; }
- void SetLayoutClientAfterEdge(LayoutUnit client_after_edge) {
- layout_client_after_edge_ = client_after_edge;
- }
-
void SetHasSubpixelVisualEffectOutsets(bool b) {
has_subpixel_visual_effect_outsets_ = b;
}
@@ -189,13 +227,16 @@ class BoxOverflowModel {
}
private:
- LayoutRect layout_overflow_;
LayoutRect self_visual_overflow_;
LayoutRect contents_visual_overflow_;
- LayoutUnit layout_client_after_edge_;
bool has_subpixel_visual_effect_outsets_ = false;
- DISALLOW_COPY_AND_ASSIGN(BoxOverflowModel);
+ DISALLOW_COPY_AND_ASSIGN(BoxVisualOverflowModel);
+};
+
+struct BoxOverflowModel {
+ base::Optional<BoxLayoutOverflowModel> layout_overflow;
+ base::Optional<BoxVisualOverflowModel> visual_overflow;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/overflow_model_test.cc b/chromium/third_party/blink/renderer/core/layout/overflow_model_test.cc
index c039f47981f..f7d918c799a 100644
--- a/chromium/third_party/blink/renderer/core/layout/overflow_model_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/overflow_model_test.cc
@@ -47,178 +47,164 @@ LayoutRect InitialVisualOverflow() {
class SimpleOverflowModelTest : public testing::Test {
protected:
SimpleOverflowModelTest()
- : overflow_(InitialLayoutOverflow(), InitialVisualOverflow()) {}
- SimpleOverflowModel overflow_;
+ : layout_overflow_(InitialLayoutOverflow()),
+ visual_overflow_(InitialVisualOverflow()) {}
+ SimpleLayoutOverflowModel layout_overflow_;
+ SimpleVisualOverflowModel visual_overflow_;
};
TEST_F(SimpleOverflowModelTest, InitialOverflowRects) {
- EXPECT_EQ(InitialLayoutOverflow(), overflow_.LayoutOverflowRect());
- EXPECT_EQ(InitialVisualOverflow(), overflow_.VisualOverflowRect());
+ EXPECT_EQ(InitialLayoutOverflow(), layout_overflow_.LayoutOverflowRect());
+ EXPECT_EQ(InitialVisualOverflow(), visual_overflow_.VisualOverflowRect());
}
TEST_F(SimpleOverflowModelTest, AddLayoutOverflowOutsideExpandsRect) {
- overflow_.AddLayoutOverflow(LayoutRect(0, 10, 30, 10));
- EXPECT_EQ(LayoutRect(0, 10, 90, 80), overflow_.LayoutOverflowRect());
+ layout_overflow_.AddLayoutOverflow(LayoutRect(0, 10, 30, 10));
+ EXPECT_EQ(LayoutRect(0, 10, 90, 80), layout_overflow_.LayoutOverflowRect());
}
TEST_F(SimpleOverflowModelTest, AddLayoutOverflowInsideDoesNotAffectRect) {
- overflow_.AddLayoutOverflow(LayoutRect(50, 50, 10, 20));
- EXPECT_EQ(InitialLayoutOverflow(), overflow_.LayoutOverflowRect());
+ layout_overflow_.AddLayoutOverflow(LayoutRect(50, 50, 10, 20));
+ EXPECT_EQ(InitialLayoutOverflow(), layout_overflow_.LayoutOverflowRect());
}
TEST_F(SimpleOverflowModelTest, AddLayoutOverflowEmpty) {
// This test documents the existing behavior so that we are aware when/if
// it changes. It would also be reasonable for addLayoutOverflow to be
// a no-op in this situation.
- overflow_.AddLayoutOverflow(LayoutRect(200, 200, 0, 0));
- EXPECT_EQ(LayoutRect(10, 10, 190, 190), overflow_.LayoutOverflowRect());
-}
-
-TEST_F(SimpleOverflowModelTest, AddLayoutOverflowDoesNotAffectVisualOverflow) {
- overflow_.AddLayoutOverflow(LayoutRect(300, 300, 300, 300));
- EXPECT_EQ(InitialVisualOverflow(), overflow_.VisualOverflowRect());
+ layout_overflow_.AddLayoutOverflow(LayoutRect(200, 200, 0, 0));
+ EXPECT_EQ(LayoutRect(10, 10, 190, 190),
+ layout_overflow_.LayoutOverflowRect());
}
TEST_F(SimpleOverflowModelTest, AddVisualOverflowOutsideExpandsRect) {
- overflow_.AddVisualOverflow(LayoutRect(150, -50, 10, 10));
- EXPECT_EQ(LayoutRect(0, -50, 160, 150), overflow_.VisualOverflowRect());
+ visual_overflow_.AddVisualOverflow(LayoutRect(150, -50, 10, 10));
+ EXPECT_EQ(LayoutRect(0, -50, 160, 150),
+ visual_overflow_.VisualOverflowRect());
}
TEST_F(SimpleOverflowModelTest, AddVisualOverflowInsideDoesNotAffectRect) {
- overflow_.AddVisualOverflow(LayoutRect(0, 10, 90, 90));
- EXPECT_EQ(InitialVisualOverflow(), overflow_.VisualOverflowRect());
+ visual_overflow_.AddVisualOverflow(LayoutRect(0, 10, 90, 90));
+ EXPECT_EQ(InitialVisualOverflow(), visual_overflow_.VisualOverflowRect());
}
TEST_F(SimpleOverflowModelTest, AddVisualOverflowEmpty) {
- overflow_.SetVisualOverflow(LayoutRect(0, 0, 600, 0));
- overflow_.AddVisualOverflow(LayoutRect(100, -50, 100, 100));
- overflow_.AddVisualOverflow(LayoutRect(300, 300, 0, 10000));
- EXPECT_EQ(LayoutRect(100, -50, 100, 100), overflow_.VisualOverflowRect());
-}
-
-TEST_F(SimpleOverflowModelTest, AddVisualOverflowDoesNotAffectLayoutOverflow) {
- overflow_.AddVisualOverflow(LayoutRect(300, 300, 300, 300));
- EXPECT_EQ(InitialLayoutOverflow(), overflow_.LayoutOverflowRect());
+ visual_overflow_.SetVisualOverflow(LayoutRect(0, 0, 600, 0));
+ visual_overflow_.AddVisualOverflow(LayoutRect(100, -50, 100, 100));
+ visual_overflow_.AddVisualOverflow(LayoutRect(300, 300, 0, 10000));
+ EXPECT_EQ(LayoutRect(100, -50, 100, 100),
+ visual_overflow_.VisualOverflowRect());
}
TEST_F(SimpleOverflowModelTest, MoveAffectsLayoutOverflow) {
- overflow_.Move(LayoutUnit(500), LayoutUnit(100));
- EXPECT_EQ(LayoutRect(510, 110, 80, 80), overflow_.LayoutOverflowRect());
-}
-
-TEST_F(SimpleOverflowModelTest, MoveAffectsVisualOverflow) {
- overflow_.Move(LayoutUnit(500), LayoutUnit(100));
- EXPECT_EQ(LayoutRect(500, 100, 100, 100), overflow_.VisualOverflowRect());
+ layout_overflow_.Move(LayoutUnit(500), LayoutUnit(100));
+ EXPECT_EQ(LayoutRect(510, 110, 80, 80),
+ layout_overflow_.LayoutOverflowRect());
}
class BoxOverflowModelTest : public testing::Test {
protected:
BoxOverflowModelTest()
- : overflow_(InitialLayoutOverflow(), InitialVisualOverflow()) {}
- BoxOverflowModel overflow_;
+ : layout_overflow_(InitialLayoutOverflow()),
+ visual_overflow_(InitialVisualOverflow()) {}
+ BoxLayoutOverflowModel layout_overflow_;
+ BoxVisualOverflowModel visual_overflow_;
};
TEST_F(BoxOverflowModelTest, InitialOverflowRects) {
- EXPECT_EQ(InitialLayoutOverflow(), overflow_.LayoutOverflowRect());
- EXPECT_EQ(InitialVisualOverflow(), overflow_.SelfVisualOverflowRect());
- EXPECT_TRUE(overflow_.ContentsVisualOverflowRect().IsEmpty());
+ EXPECT_EQ(InitialLayoutOverflow(), layout_overflow_.LayoutOverflowRect());
+ EXPECT_EQ(InitialVisualOverflow(), visual_overflow_.SelfVisualOverflowRect());
+ EXPECT_TRUE(visual_overflow_.ContentsVisualOverflowRect().IsEmpty());
}
TEST_F(BoxOverflowModelTest, AddLayoutOverflowOutsideExpandsRect) {
- overflow_.AddLayoutOverflow(LayoutRect(0, 10, 30, 10));
- EXPECT_EQ(LayoutRect(0, 10, 90, 80), overflow_.LayoutOverflowRect());
+ layout_overflow_.AddLayoutOverflow(LayoutRect(0, 10, 30, 10));
+ EXPECT_EQ(LayoutRect(0, 10, 90, 80), layout_overflow_.LayoutOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddLayoutOverflowInsideDoesNotAffectRect) {
- overflow_.AddLayoutOverflow(LayoutRect(50, 50, 10, 20));
- EXPECT_EQ(InitialLayoutOverflow(), overflow_.LayoutOverflowRect());
+ layout_overflow_.AddLayoutOverflow(LayoutRect(50, 50, 10, 20));
+ EXPECT_EQ(InitialLayoutOverflow(), layout_overflow_.LayoutOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddLayoutOverflowEmpty) {
// This test documents the existing behavior so that we are aware when/if
// it changes. It would also be reasonable for addLayoutOverflow to be
// a no-op in this situation.
- overflow_.AddLayoutOverflow(LayoutRect(200, 200, 0, 0));
- EXPECT_EQ(LayoutRect(10, 10, 190, 190), overflow_.LayoutOverflowRect());
-}
-
-TEST_F(BoxOverflowModelTest, AddLayoutOverflowDoesNotAffectSelfVisualOverflow) {
- overflow_.AddLayoutOverflow(LayoutRect(300, 300, 300, 300));
- EXPECT_EQ(InitialVisualOverflow(), overflow_.SelfVisualOverflowRect());
-}
-
-TEST_F(BoxOverflowModelTest,
- AddLayoutOverflowDoesNotAffectContentsVisualOverflow) {
- overflow_.AddLayoutOverflow(LayoutRect(300, 300, 300, 300));
- EXPECT_TRUE(overflow_.ContentsVisualOverflowRect().IsEmpty());
+ layout_overflow_.AddLayoutOverflow(LayoutRect(200, 200, 0, 0));
+ EXPECT_EQ(LayoutRect(10, 10, 190, 190),
+ layout_overflow_.LayoutOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddSelfVisualOverflowOutsideExpandsRect) {
- overflow_.AddSelfVisualOverflow(LayoutRect(150, -50, 10, 10));
- EXPECT_EQ(LayoutRect(0, -50, 160, 150), overflow_.SelfVisualOverflowRect());
+ visual_overflow_.AddSelfVisualOverflow(LayoutRect(150, -50, 10, 10));
+ EXPECT_EQ(LayoutRect(0, -50, 160, 150),
+ visual_overflow_.SelfVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddSelfVisualOverflowInsideDoesNotAffectRect) {
- overflow_.AddSelfVisualOverflow(LayoutRect(0, 10, 90, 90));
- EXPECT_EQ(InitialVisualOverflow(), overflow_.SelfVisualOverflowRect());
+ visual_overflow_.AddSelfVisualOverflow(LayoutRect(0, 10, 90, 90));
+ EXPECT_EQ(InitialVisualOverflow(), visual_overflow_.SelfVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddSelfVisualOverflowEmpty) {
- BoxOverflowModel overflow(LayoutRect(), LayoutRect(0, 0, 600, 0));
- overflow.AddSelfVisualOverflow(LayoutRect(100, -50, 100, 100));
- overflow.AddSelfVisualOverflow(LayoutRect(300, 300, 0, 10000));
- EXPECT_EQ(LayoutRect(100, -50, 100, 100), overflow.SelfVisualOverflowRect());
-}
-
-TEST_F(BoxOverflowModelTest, AddSelfVisualOverflowDoesNotAffectLayoutOverflow) {
- overflow_.AddSelfVisualOverflow(LayoutRect(300, 300, 300, 300));
- EXPECT_EQ(InitialLayoutOverflow(), overflow_.LayoutOverflowRect());
+ BoxVisualOverflowModel visual_overflow(LayoutRect(0, 0, 600, 0));
+ visual_overflow.AddSelfVisualOverflow(LayoutRect(100, -50, 100, 100));
+ visual_overflow.AddSelfVisualOverflow(LayoutRect(300, 300, 0, 10000));
+ EXPECT_EQ(LayoutRect(100, -50, 100, 100),
+ visual_overflow.SelfVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest,
AddSelfVisualOverflowDoesNotAffectContentsVisualOverflow) {
- overflow_.AddSelfVisualOverflow(LayoutRect(300, 300, 300, 300));
- EXPECT_TRUE(overflow_.ContentsVisualOverflowRect().IsEmpty());
+ visual_overflow_.AddSelfVisualOverflow(LayoutRect(300, 300, 300, 300));
+ EXPECT_TRUE(visual_overflow_.ContentsVisualOverflowRect().IsEmpty());
}
TEST_F(BoxOverflowModelTest, AddContentsVisualOverflowFirstCall) {
- overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
- EXPECT_EQ(LayoutRect(0, 0, 10, 10), overflow_.ContentsVisualOverflowRect());
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
+ EXPECT_EQ(LayoutRect(0, 0, 10, 10),
+ visual_overflow_.ContentsVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddContentsVisualOverflowUnitesRects) {
- overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
- overflow_.AddContentsVisualOverflow(LayoutRect(80, 80, 10, 10));
- EXPECT_EQ(LayoutRect(0, 0, 90, 90), overflow_.ContentsVisualOverflowRect());
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(80, 80, 10, 10));
+ EXPECT_EQ(LayoutRect(0, 0, 90, 90),
+ visual_overflow_.ContentsVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddContentsVisualOverflowRectWithinRect) {
- overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
- overflow_.AddContentsVisualOverflow(LayoutRect(2, 2, 5, 5));
- EXPECT_EQ(LayoutRect(0, 0, 10, 10), overflow_.ContentsVisualOverflowRect());
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(2, 2, 5, 5));
+ EXPECT_EQ(LayoutRect(0, 0, 10, 10),
+ visual_overflow_.ContentsVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, AddContentsVisualOverflowEmpty) {
- overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
- overflow_.AddContentsVisualOverflow(LayoutRect(20, 20, 0, 0));
- EXPECT_EQ(LayoutRect(0, 0, 10, 10), overflow_.ContentsVisualOverflowRect());
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(20, 20, 0, 0));
+ EXPECT_EQ(LayoutRect(0, 0, 10, 10),
+ visual_overflow_.ContentsVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, MoveAffectsLayoutOverflow) {
- overflow_.Move(LayoutUnit(500), LayoutUnit(100));
- EXPECT_EQ(LayoutRect(510, 110, 80, 80), overflow_.LayoutOverflowRect());
+ layout_overflow_.Move(LayoutUnit(500), LayoutUnit(100));
+ EXPECT_EQ(LayoutRect(510, 110, 80, 80),
+ layout_overflow_.LayoutOverflowRect());
}
TEST_F(BoxOverflowModelTest, MoveAffectsSelfVisualOverflow) {
- overflow_.Move(LayoutUnit(500), LayoutUnit(100));
- EXPECT_EQ(LayoutRect(500, 100, 100, 100), overflow_.SelfVisualOverflowRect());
+ visual_overflow_.Move(LayoutUnit(500), LayoutUnit(100));
+ EXPECT_EQ(LayoutRect(500, 100, 100, 100),
+ visual_overflow_.SelfVisualOverflowRect());
}
TEST_F(BoxOverflowModelTest, MoveAffectsContentsVisualOverflow) {
- overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
- overflow_.Move(LayoutUnit(500), LayoutUnit(100));
+ visual_overflow_.AddContentsVisualOverflow(LayoutRect(0, 0, 10, 10));
+ visual_overflow_.Move(LayoutUnit(500), LayoutUnit(100));
EXPECT_EQ(LayoutRect(500, 100, 10, 10),
- overflow_.ContentsVisualOverflowRect());
+ visual_overflow_.ContentsVisualOverflowRect());
}
} // anonymous namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
index eb20ced2fae..1502fdf05f7 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
@@ -143,14 +143,13 @@ static const AtomicString UniqueClassnameAmongSiblings(Element* element) {
auto classname_filter = std::make_unique<ClassnameFilter>();
- Element* parent_element = ElementTraversal::FirstAncestor(*element->ToNode());
+ Element* parent_element = ElementTraversal::FirstAncestor(*element);
Element* sibling_element =
- parent_element ? ElementTraversal::FirstChild(*parent_element->ToNode())
- : element;
+ parent_element ? ElementTraversal::FirstChild(*parent_element) : element;
// Add every classname of every sibling to our bloom filter, starting from the
// leftmost sibling, but skipping |element|.
- for (; sibling_element; sibling_element = ElementTraversal::NextSibling(
- *sibling_element->ToNode())) {
+ for (; sibling_element;
+ sibling_element = ElementTraversal::NextSibling(*sibling_element)) {
if (sibling_element->HasClass() && sibling_element != element) {
const SpaceSplitString& class_names = sibling_element->ClassNames();
for (wtf_size_t i = 0; i < class_names.size(); ++i) {
@@ -231,7 +230,7 @@ static const String ComputeUniqueSelector(Node* anchor_node) {
std::vector<String> selector_list;
for (Element* element = ElementTraversal::FirstAncestorOrSelf(*anchor_node);
- element; element = ElementTraversal::FirstAncestor(*element->ToNode())) {
+ element; element = ElementTraversal::FirstAncestor(*element)) {
selector_list.push_back(UniqueSimpleSelectorAmongSiblings(element));
if (element->HasID() &&
!element->GetDocument().ContainsMultipleElementsWithId(
@@ -269,6 +268,9 @@ ScrollAnchor::ExamineResult ScrollAnchor::Examine(
if (candidate == ScrollerLayoutBox(scroller_))
return ExamineResult(kContinue);
+ if (candidate->StyleRef().OverflowAnchor() == EOverflowAnchor::kNone)
+ return ExamineResult(kSkip);
+
if (candidate->IsLayoutInline())
return ExamineResult(kContinue);
@@ -283,9 +285,6 @@ ScrollAnchor::ExamineResult ScrollAnchor::Examine(
if (!CandidateMayMoveWithScroller(candidate, scroller_))
return ExamineResult(kSkip);
- if (candidate->StyleRef().OverflowAnchor() == EOverflowAnchor::kNone)
- return ExamineResult(kSkip);
-
LayoutRect candidate_rect = RelativeBounds(candidate, scroller_);
LayoutRect visible_rect =
ScrollerLayoutBox(scroller_)->OverflowClipRect(LayoutPoint());
@@ -505,7 +504,7 @@ bool ScrollAnchor::RestoreAnchor(const SerializedAnchor& serialized_anchor) {
for (unsigned index = 0; index < found_elements->length(); index++) {
Element* anchor_element = found_elements->item(index);
- LayoutObject* anchor_object = anchor_element->ToNode()->GetLayoutObject();
+ LayoutObject* anchor_object = anchor_element->GetLayoutObject();
if (!anchor_object) {
continue;
diff --git a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
index e26fe4bafb0..a58b560f073 100644
--- a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -158,7 +158,7 @@ class ScrollbarsTestWithVirtualTimer : public ScrollbarsTest {
TEST_F(ScrollbarsTest, DocumentStyleRecalcPreservesScrollbars) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -180,14 +180,17 @@ TEST_F(ScrollbarsTest, DocumentStyleRecalcPreservesScrollbars) {
layout_viewport->HorizontalScrollbar());
}
-class ScrollbarsWebViewClient : public frame_test_helpers::TestWebViewClient {
+class ScrollbarsWebWidgetClient
+ : public frame_test_helpers::TestWebWidgetClient {
public:
+ // WebWidgetClient overrides.
void ConvertWindowToViewport(WebFloatRect* rect) override {
rect->x *= device_scale_factor_;
rect->y *= device_scale_factor_;
rect->width *= device_scale_factor_;
rect->height *= device_scale_factor_;
}
+
void set_device_scale_factor(float device_scale_factor) {
device_scale_factor_ = device_scale_factor;
}
@@ -197,16 +200,16 @@ class ScrollbarsWebViewClient : public frame_test_helpers::TestWebViewClient {
};
TEST_F(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
- ScrollbarsWebViewClient client;
+ ScrollbarsWebWidgetClient client;
client.set_device_scale_factor(1.f);
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl =
- web_view_helper.Initialize(nullptr, &client, nullptr, nullptr);
+ web_view_helper.Initialize(nullptr, nullptr, &client);
// Needed so visual viewport supplies its own scrollbars.
web_view_impl->GetSettings()->SetViewportEnabled(true);
- web_view_impl->Resize(IntSize(800, 600));
+ web_view_impl->MainFrameWidget()->Resize(IntSize(800, 600));
WebURL base_url = url_test_helpers::ToKURL("http://example.com/");
frame_test_helpers::LoadHTMLString(web_view_impl->MainFrameImpl(),
@@ -234,7 +237,7 @@ TEST_F(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
const float device_scale = 3.5f;
client.set_device_scale_factor(device_scale);
- web_view_impl->Resize(IntSize(400, 300));
+ web_view_impl->MainFrameWidget()->Resize(IntSize(400, 300));
EXPECT_EQ(
clampTo<int>(std::floor(horizontal_scrollbar * device_scale)),
@@ -245,7 +248,7 @@ TEST_F(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
visual_viewport.LayerForVerticalScrollbar()->Size().width())));
client.set_device_scale_factor(1.f);
- web_view_impl->Resize(IntSize(800, 600));
+ web_view_impl->MainFrameWidget()->Resize(IntSize(800, 600));
EXPECT_EQ(
horizontal_scrollbar,
@@ -262,7 +265,7 @@ TEST_F(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
// checking whether the scrollbars should be custom - which do take up layout
// space. https://crbug.com/668387.
TEST_F(ScrollbarsTest, CustomScrollbarsCauseLayoutOnExistenceChange) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -313,7 +316,7 @@ TEST_F(ScrollbarsTest, CustomScrollbarsCauseLayoutOnExistenceChange) {
}
TEST_F(ScrollbarsTest, TransparentBackgroundUsesDarkOverlayColorTheme) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
WebView().SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -339,7 +342,7 @@ TEST_F(ScrollbarsTest, TransparentBackgroundUsesDarkOverlayColorTheme) {
TEST_F(ScrollbarsTest, BodyBackgroundChangesOverlayColorTheme) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -367,7 +370,7 @@ TEST_F(ScrollbarsTest, BodyBackgroundChangesOverlayColorTheme) {
// Ensure overlay scrollbar change to display:none correctly.
TEST_F(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -435,7 +438,7 @@ TEST_F(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
}
TEST_F(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -476,7 +479,7 @@ TEST_F(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
}
TEST_F(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -544,7 +547,7 @@ TEST_F(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
// Ensure mouse cursor should be pointer when hovering over the scrollbar.
TEST_F(ScrollbarsTest, MouseOverScrollbarInCustomCursorElement) {
- WebView().Resize(WebSize(250, 250));
+ WebView().MainFrameWidget()->Resize(WebSize(250, 250));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -588,7 +591,7 @@ TEST_F(ScrollbarsTest, MouseOverScrollbarInCustomCursorElement) {
// Ensure mouse cursor should be override when hovering over the custom
// scrollbar.
TEST_F(ScrollbarsTest, MouseOverCustomScrollbarInCustomCursorElement) {
- WebView().Resize(WebSize(250, 250));
+ WebView().MainFrameWidget()->Resize(WebSize(250, 250));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -641,7 +644,7 @@ TEST_F(ScrollbarsTest, MouseOverCustomScrollbarInCustomCursorElement) {
// elements below(except the Element that owns the scrollbar) unless the
// scrollbar is faded out.
TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
- WebView().Resize(WebSize(20, 20));
+ WebView().MainFrameWidget()->Resize(WebSize(20, 20));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -723,7 +726,7 @@ TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
// Makes sure that mouse hover over an custom scrollbar doesn't change the
// activate elements.
TEST_F(ScrollbarsTest, MouseOverCustomScrollbar) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -790,7 +793,7 @@ TEST_F(ScrollbarsTest, MouseOverCustomScrollbar) {
// Makes sure that mouse hover over an overlay scrollbar doesn't hover iframe
// below.
TEST_F(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest main_resource("https://example.com/", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
@@ -874,7 +877,7 @@ TEST_F(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
// scrollbar.
TEST_F(ScrollbarsTest, MouseOverScrollbarAndParentElement) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -962,7 +965,7 @@ TEST_F(ScrollbarsTest, MouseOverScrollbarAndParentElement) {
TEST_F(ScrollbarsTest, MouseOverRootScrollbar) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -994,7 +997,7 @@ TEST_F(ScrollbarsTest, MouseOverRootScrollbar) {
}
TEST_F(ScrollbarsTest, MouseReleaseUpdatesScrollbarHoveredPart) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1059,7 +1062,7 @@ TEST_F(ScrollbarsTest, MouseReleaseUpdatesScrollbarHoveredPart) {
}
TEST_F(ScrollbarsTest, ContextMenuUpdatesScrollbarPressedPart) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1112,7 +1115,7 @@ TEST_F(ScrollbarsTest, ContextMenuUpdatesScrollbarPressedPart) {
TEST_F(ScrollbarsTest,
CustomScrollbarInOverlayScrollbarThemeWillNotCauseDCHECKFails) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1140,7 +1143,7 @@ TEST_F(ScrollbarsTest,
// Make sure root custom scrollbar can change by Emulator but div custom
// scrollbar not.
TEST_F(ScrollbarsTest, CustomScrollbarChangeToMobileByEmulator) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1223,7 +1226,7 @@ TEST_F(ScrollbarsTest, CustomScrollbarChangeToMobileByEmulator) {
// Ensure custom scrollbar recreate when style owner change,
TEST_F(ScrollbarsTest, CustomScrollbarWhenStyleOwnerChange) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1295,7 +1298,7 @@ TEST_F(ScrollbarsTestWithVirtualTimer, TestNonCompositedOverlayScrollbarsFade) {
(ScrollbarThemeOverlayMock&)theme;
mock_overlay_theme.SetOverlayScrollbarFadeOutDelay(kMockOverlayFadeOutDelay);
- WebView().Resize(WebSize(640, 480));
+ WebView().MainFrameWidget()->Resize(WebSize(640, 480));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
RunTasksForPeriod(kMockOverlayFadeOutDelay);
@@ -1432,7 +1435,7 @@ TEST_P(ScrollbarAppearanceTest, NativeScrollbarChangeToMobileByEmulator) {
ScopedTestingPlatformSupport<ScrollbarTestingPlatformSupport> platform;
bool use_overlay_scrollbar = GetParam();
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1526,7 +1529,7 @@ TEST_P(ScrollbarAppearanceTest, ThemeEngineDefinesMinimumThumbLength) {
ScopedTestingPlatformSupport<ScrollbarTestingPlatformSupport> platform;
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1551,7 +1554,7 @@ TEST_P(ScrollbarAppearanceTest, HugeScrollingThumbPosition) {
ScopedTestingPlatformSupport<ScrollbarTestingPlatformSupport> platform;
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(1000, 1000));
+ WebView().MainFrameWidget()->Resize(WebSize(1000, 1000));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1572,8 +1575,8 @@ TEST_P(ScrollbarAppearanceTest, HugeScrollingThumbPosition) {
Scrollbar* scrollbar = scrollable_area->VerticalScrollbar();
ASSERT_TRUE(scrollbar);
- int maximumThumbPosition =
- WebView().Size().height - StubWebThemeEngine::kMinimumVerticalLength;
+ int maximumThumbPosition = WebView().MainFrameWidget()->Size().height -
+ StubWebThemeEngine::kMinimumVerticalLength;
// TODO(bokan): it seems that the scrollbar margin is cached in the static
// ScrollbarTheme, so if another test runs first without our mocked
@@ -1592,7 +1595,7 @@ TEST_F(ScrollbarsTest, WideBodyShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1616,7 +1619,7 @@ TEST_F(ScrollbarsTest, TallBodyShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1641,7 +1644,7 @@ TEST_F(ScrollbarsTest, TallAndWideBodyShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1666,7 +1669,7 @@ TEST_F(ScrollbarsTest, BodySizeEqualWindowSizeShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1691,7 +1694,7 @@ TEST_F(ScrollbarsTest, WidePercentageBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1717,7 +1720,7 @@ TEST_F(ScrollbarsTest, WidePercentageAndTallBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1743,7 +1746,7 @@ TEST_F(ScrollbarsTest, TallPercentageBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1769,7 +1772,7 @@ TEST_F(ScrollbarsTest, TallPercentageAndWideBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1795,7 +1798,7 @@ TEST_F(ScrollbarsTest, TallAndWidePercentageBodyShouldHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1817,7 +1820,7 @@ TEST_F(ScrollbarsTest, TallAndWidePercentageBodyShouldHaveScrollbars) {
TEST_F(ScrollbarsTest, MouseOverIFrameScrollbar) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
@@ -1869,7 +1872,7 @@ TEST_F(ScrollbarsTest, AutosizeTest) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(0, 0));
+ WebView().MainFrameWidget()->Resize(WebSize(0, 0));
SimRequest resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
resource.Complete(R"HTML(
@@ -1970,7 +1973,7 @@ TEST_F(ScrollbarsTest, AutosizeAlmostRemovableScrollbar) {
TEST_F(ScrollbarsTest,
HideTheOverlayScrollbarNotCrashAfterPLSADisposedPaintLayer) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2013,7 +2016,7 @@ TEST_F(ScrollbarsTest,
TEST_F(ScrollbarsTest, PLSADisposeShouldClearPointerInLayers) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2053,7 +2056,7 @@ TEST_F(ScrollbarsTest, PLSADisposeShouldClearPointerInLayers) {
}
TEST_F(ScrollbarsTest, OverlayScrollbarHitTest) {
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest main_resource("https://example.com/", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
@@ -2108,7 +2111,7 @@ TEST_F(ScrollbarsTest, OverlayScrollbarHitTest) {
TEST_F(ScrollbarsTest, AllowMiddleButtonPressOnScrollbar) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2140,7 +2143,7 @@ TEST_F(ScrollbarsTest, AllowMiddleButtonPressOnScrollbar) {
// Ensure Scrollbar not release press by middle button down.
TEST_F(ScrollbarsTest, MiddleDownShouldNotAffectScrollbarPress) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2202,7 +2205,7 @@ TEST_F(ScrollbarsTestWithVirtualTimer,
#endif
TimeAdvance();
GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(false);
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -2269,7 +2272,7 @@ TEST_F(ScrollbarsTestWithVirtualTimer,
class ScrollbarTrackMarginsTest : public ScrollbarsTest {
public:
void PrepareTest(const String& track_style) {
- WebView().Resize(WebSize(200, 200));
+ WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
index 5648f5fbf09..a0dbf337237 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -63,7 +63,8 @@ void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
layout_box_.MarginWidth());
}
- switch (ReferenceBox(*layout_box_.StyleRef().ShapeOutside())) {
+ const ShapeValue& shape_value = *layout_box_.StyleRef().ShapeOutside();
+ switch (ReferenceBox(shape_value)) {
case CSSBoxType::kMargin:
UseCounter::Count(document, WebFeature::kShapeOutsideMarginBox);
if (is_horizontal_writing_mode)
@@ -91,8 +92,12 @@ void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
WebFeature::kShapeOutsidePaddingBoxDifferentFromMarginBox);
}
break;
- case CSSBoxType::kContent:
- UseCounter::Count(document, WebFeature::kShapeOutsideContentBox);
+ case CSSBoxType::kContent: {
+ bool is_shape_image = shape_value.GetType() == ShapeValue::kImage;
+
+ if (!is_shape_image)
+ UseCounter::Count(document, WebFeature::kShapeOutsideContentBox);
+
if (is_horizontal_writing_mode)
new_reference_box_logical_size.Shrink(
layout_box_.BorderAndPaddingWidth(),
@@ -102,12 +107,14 @@ void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
layout_box_.BorderAndPaddingHeight(),
layout_box_.BorderAndPaddingWidth());
- if (new_reference_box_logical_size != margin_box_for_use_counter) {
+ if (!is_shape_image &&
+ new_reference_box_logical_size != margin_box_for_use_counter) {
UseCounter::Count(
document,
WebFeature::kShapeOutsideContentBoxDifferentFromMarginBox);
}
break;
+ }
case CSSBoxType::kMissing:
NOTREACHED();
break;
@@ -139,7 +146,7 @@ static bool CheckShapeImageOrigin(Document& document,
DCHECK(style_image.CachedImage());
ImageResourceContent& image_resource = *(style_image.CachedImage());
- if (image_resource.IsAccessAllowed(document.GetSecurityOrigin()))
+ if (image_resource.IsAccessAllowed())
return true;
const KURL& url = image_resource.Url();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index 8494c388ccb..b05921f101e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -157,8 +157,8 @@ void LayoutSVGImage::UpdateLayout() {
DCHECK(!needs_transform_update_);
if (auto* svg_image_element = ToSVGImageElementOrNull(GetElement())) {
- if (svg_image_element->IsDefaultIntrinsicSize())
- media_element_parser_helpers::ReportUnsizedMediaViolation(this);
+ media_element_parser_helpers::ReportUnsizedMediaViolation(
+ this, svg_image_element->IsDefaultIntrinsicSize());
}
ClearNeedsLayout();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index 62a15b2e2a0..7e4d148ae32 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -95,6 +95,7 @@ void LayoutSVGRoot::UnscaledIntrinsicSizingInfo(
void LayoutSVGRoot::ComputeIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ DCHECK(!ShouldApplySizeContainment());
UnscaledIntrinsicSizingInfo(intrinsic_sizing_info);
intrinsic_sizing_info.size.Scale(StyleRef().EffectiveZoom());
@@ -209,15 +210,8 @@ void LayoutSVGRoot::UpdateLayout() {
}
const auto& old_overflow_rect = VisualOverflowRect();
- overflow_.reset();
- AddVisualEffectOverflow();
-
- if (!ShouldApplyViewportClip()) {
- FloatRect content_visual_rect = VisualRectInLocalSVGCoordinates();
- content_visual_rect =
- local_to_border_box_transform_.MapRect(content_visual_rect);
- AddContentsVisualOverflow(EnclosingLayoutRect(content_visual_rect));
- }
+ ClearSelfNeedsLayoutOverflowRecalc();
+ ClearLayoutOverflow();
// The scale of one or more of the SVG elements may have changed, content
// (the entire SVG) could have moved or new content may have been exposed, so
@@ -248,11 +242,24 @@ bool LayoutSVGRoot::ShouldApplyViewportClip() const {
StyleRef().OverflowX() == EOverflow::kScroll || IsDocumentElement();
}
-LayoutRect LayoutSVGRoot::VisualOverflowRect() const {
- LayoutRect rect = LayoutReplaced::SelfVisualOverflowRect();
+void LayoutSVGRoot::RecalcVisualOverflow() {
+ LayoutReplaced::RecalcVisualOverflow();
+ UpdateCachedBoundaries();
if (!ShouldApplyViewportClip())
- rect.Unite(ContentsVisualOverflowRect());
- return rect;
+ AddContentsVisualOverflow(ComputeContentsVisualOverflow());
+}
+
+LayoutRect LayoutSVGRoot::ComputeContentsVisualOverflow() const {
+ FloatRect content_visual_rect = VisualRectInLocalSVGCoordinates();
+ content_visual_rect =
+ local_to_border_box_transform_.MapRect(content_visual_rect);
+ // Condition the visual overflow rect to avoid being clipped/culled
+ // out if it is huge. This may sacrifice overflow, but usually only
+ // overflow that would never be seen anyway.
+ // To condition, we intersect with something that we oftentimes
+ // consider to be "infinity".
+ return Intersection(EnclosingLayoutRect(content_visual_rect),
+ LayoutRect(LayoutRect::InfiniteIntRect()));
}
void LayoutSVGRoot::PaintReplaced(const PaintInfo& paint_info,
@@ -433,42 +440,6 @@ AffineTransform LayoutSVGRoot::LocalToSVGParentTransform() const {
local_to_border_box_transform_;
}
-LayoutRect LayoutSVGRoot::LocalVisualRectIgnoringVisibility() const {
- // This is an open-coded aggregate of SVGLayoutSupport::localVisualRect
- // and LayoutReplaced::localVisualRect. The reason for this is to optimize/
- // minimize the visual rect when the box is not "decorated" (does not have
- // background/border/etc., see
- // LayoutSVGRootTest.VisualRectMappingWithViewportClipWithoutBorder).
-
- // Return early for any cases where we don't actually paint.
- if (!EnclosingLayer()->HasVisibleContent())
- return LayoutRect();
-
- // Compute the visual rect of the content of the SVG in the border-box
- // coordinate space.
- FloatRect content_visual_rect = VisualRectInLocalSVGCoordinates();
- content_visual_rect =
- local_to_border_box_transform_.MapRect(content_visual_rect);
-
- // Apply initial viewport clip, overflow:visible content is added to
- // visualOverflow but the most common case is that overflow is hidden, so
- // always intersect.
- content_visual_rect.Intersect(PixelSnappedBorderBoxRect());
-
- LayoutRect visual_rect = EnclosingLayoutRect(content_visual_rect);
- // If the box is decorated or is overflowing, extend it to include the
- // border-box and overflow.
- if (has_box_decoration_background_ || HasOverflowModel()) {
- // The selectionRect can project outside of the overflowRect, so take their
- // union for paint invalidation to avoid selection painting glitches.
- LayoutRect decorated_visual_rect =
- UnionRect(LocalSelectionRect(), VisualOverflowRect());
- visual_rect.Unite(decorated_visual_rect);
- }
-
- return LayoutRect(EnclosingIntRect(visual_rect));
-}
-
// This method expects local CSS box coordinates.
// Callers with local SVG viewport coordinates should first apply the
// localToBorderBoxTransform to convert from SVG viewport coordinates to local
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index 91c97212585..8c057a10471 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -85,7 +85,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
bool ShouldApplyViewportClip() const;
- LayoutRect VisualOverflowRect() const override;
+ void RecalcVisualOverflow() override;
bool HasNonIsolatedBlendingDescendants() const final;
@@ -95,6 +95,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
bool ComputeShouldClipOverflow() const override {
return LayoutBox::ComputeShouldClipOverflow() || ShouldApplyViewportClip();
}
+ LayoutRect ComputeContentsVisualOverflow() const;
const LayoutObjectChildList* Children() const { return &children_; }
LayoutObjectChildList* Children() { return &children_; }
@@ -141,8 +142,6 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
const LayoutPoint& accumulated_offset,
HitTestAction) override;
- LayoutRect LocalVisualRectIgnoringVisibility() const override;
-
void MapLocalToAncestor(
const LayoutBoxModelObject* ancestor,
TransformState&,
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
index 1558bb16ad4..0640e4aa5ec 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
@@ -35,12 +35,12 @@ TEST_F(LayoutSVGRootTest, VisualRectMappingWithoutViewportClipWithBorder) {
LayoutRect root_visual_rect =
static_cast<const LayoutObject&>(root).LocalVisualRect();
- // SVG root's overflow includes overflow from descendants.
- EXPECT_EQ(LayoutRect(0, 0, 220, 190), root_visual_rect);
+ // SVG root's local overflow does not include overflow from descendants.
+ EXPECT_EQ(LayoutRect(0, 0, 220, 120), root_visual_rect);
rect = root_visual_rect;
EXPECT_TRUE(root.MapToVisualRectInAncestorSpace(&root, rect));
- EXPECT_EQ(LayoutRect(0, 0, 220, 190), rect);
+ EXPECT_EQ(LayoutRect(0, 0, 220, 120), rect);
}
TEST_F(LayoutSVGRootTest, VisualOverflowExpandsLayer) {
@@ -80,8 +80,6 @@ TEST_F(LayoutSVGRootTest, VisualRectMappingWithViewportClipAndBorder) {
*ToLayoutSVGShape(GetLayoutObjectByElementId("rect"));
LayoutRect rect = SVGLayoutSupport::VisualRectInAncestorSpace(svg_rect, root);
- // (80, 80, 100, 100) added by root's content rect offset from border rect,
- // clipped by (10, 10, 200, 100).
EXPECT_EQ(LayoutRect(90, 90, 100, 20), rect);
LayoutRect root_visual_rect =
@@ -96,34 +94,6 @@ TEST_F(LayoutSVGRootTest, VisualRectMappingWithViewportClipAndBorder) {
EXPECT_EQ(LayoutRect(0, 0, 220, 120), rect);
}
-TEST_F(LayoutSVGRootTest, VisualRectMappingWithViewportClipWithoutBorder) {
- SetBodyInnerHTML(R"HTML(
- <svg id='root' style='width: 200px; height: 100px; overflow: hidden'
- viewBox='0 0 200 100'>
- <rect id='rect' x='80' y='80' width='100' height='100'/>
- </svg>
- )HTML");
-
- const LayoutSVGRoot& root =
- *ToLayoutSVGRoot(GetLayoutObjectByElementId("root"));
- const LayoutSVGShape& svg_rect =
- *ToLayoutSVGShape(GetLayoutObjectByElementId("rect"));
-
- LayoutRect rect = SVGLayoutSupport::VisualRectInAncestorSpace(svg_rect, root);
- // (80, 80, 100, 100) clipped by (0, 0, 200, 100).
- EXPECT_EQ(LayoutRect(80, 80, 100, 20), rect);
-
- LayoutRect root_visual_rect =
- static_cast<const LayoutObject&>(root).LocalVisualRect();
- // SVG root doesn't have box decoration background, so just use clipped
- // overflow of children.
- EXPECT_EQ(LayoutRect(80, 80, 100, 20), root_visual_rect);
-
- rect = root_visual_rect;
- EXPECT_TRUE(root.MapToVisualRectInAncestorSpace(&root, rect));
- EXPECT_EQ(LayoutRect(80, 80, 100, 20), rect);
-}
-
TEST_F(LayoutSVGRootTest,
PaintedOutputOfObjectHasNoEffectRegardlessOfSizeEmpty) {
SetBodyInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 79297b4fae9..42eb744405c 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -283,9 +283,7 @@ void LayoutSVGText::UpdateLayout() {
update_parent_boundaries = true;
}
- overflow_.reset();
- AddSelfVisualOverflow(LayoutRect(new_boundaries));
- AddVisualEffectOverflow();
+ ClearLayoutOverflow();
// Invalidate all resources of this client if our layout changed.
if (EverHadLayout() && SelfNeedsLayout())
@@ -299,9 +297,16 @@ void LayoutSVGText::UpdateLayout() {
DCHECK(!needs_transform_update_);
DCHECK(!needs_text_metrics_update_);
DCHECK(!needs_positioning_values_update_);
+ ClearSelfNeedsLayoutOverflowRecalc();
ClearNeedsLayout();
}
+void LayoutSVGText::RecalcVisualOverflow() {
+ LayoutObject::RecalcVisualOverflow();
+ AddSelfVisualOverflow(LayoutRect(ObjectBoundingBox()));
+ AddVisualEffectOverflow();
+}
+
RootInlineBox* LayoutSVGText::CreateRootInlineBox() {
RootInlineBox* box = new SVGRootInlineBox(LineLayoutItem(this));
box->SetHasVirtualLogicalHeight();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index ce40fa69fe9..bf9845cc258 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -62,6 +62,8 @@ class LayoutSVGText final : public LayoutSVGBlock {
void SubtreeChildWillBeRemoved();
void SubtreeTextDidChange();
+ void RecalcVisualOverflow() override;
+
const char* GetName() const override { return "LayoutSVGText"; }
private:
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
index 9ad37d5e881..f99236e3335 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -418,7 +418,7 @@ static void WriteLayoutSVGTextBox(WTF::TextStream& ts,
return;
// FIXME: Remove this hack, once the new text layout engine is completly
- // landed. We want to preserve the old layout test results for now.
+ // landed. We want to preserve the old web test results for now.
ts << " contains 1 chunk(s)";
if (text.Parent() && (text.Parent()->ResolveColor(GetCSSPropertyColor()) !=
@@ -451,7 +451,7 @@ static inline void WriteSVGInlineTextBox(WTF::TextStream& ts,
unsigned end_offset = fragment.character_offset + fragment.length;
// FIXME: Remove this hack, once the new text layout engine is completly
- // landed. We want to preserve the old layout test results for now.
+ // landed. We want to preserve the old web test results for now.
ts << "chunk 1 ";
ETextAnchor anchor = svg_style.TextAnchor();
bool is_vertical_text =
diff --git a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
index f79f71c4310..9c08a935ed7 100644
--- a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
+++ b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -225,7 +225,7 @@ static bool ShouldScaleColumnsForParent(LayoutTable* table) {
// use ~infinity to make sure we use all available size in the containing
// block. However, this just doesn't work if this is a flex or grid item, so
// disallow scaling in that case.
- if (cb->IsFlexibleBox() || cb->IsLayoutGrid())
+ if (cb->IsFlexibleBoxIncludingNG() || cb->IsLayoutGrid())
return false;
cb = cb->ContainingBlock();
}
@@ -242,7 +242,7 @@ static bool ShouldScaleColumnsForSelf(LayoutTable* table) {
// A special case. If this table is not fixed width and contained inside
// a cell, then don't bloat the maxwidth by examining percentage growth.
while (true) {
- Length tw = table->StyleRef().Width();
+ const Length& tw = table->StyleRef().Width();
if ((!tw.IsAuto() && !tw.IsPercentOrCalc()) ||
table->IsOutOfFlowPositioned())
return true;
@@ -328,7 +328,7 @@ void TableLayoutAlgorithmAuto::ComputeIntrinsicLogicalWidths(
void TableLayoutAlgorithmAuto::ApplyPreferredLogicalWidthQuirks(
LayoutUnit& min_width,
LayoutUnit& max_width) const {
- Length table_logical_width = table_->StyleRef().LogicalWidth();
+ const Length& table_logical_width = table_->StyleRef().LogicalWidth();
if (table_logical_width.IsFixed() && table_logical_width.IsPositive()) {
// |minWidth| is the result of measuring the intrinsic content's size. Keep
// it to make sure we are *never* smaller than the actual content.
diff --git a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
index c6cfd51d039..a29cd3eaa26 100644
--- a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
+++ b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
@@ -98,7 +98,7 @@ int TableLayoutAlgorithmFixed::CalcWidthArray() {
if (col->IsTableColumnGroupWithColumnChildren())
continue;
- Length col_style_logical_width = col->StyleRef().LogicalWidth();
+ const Length& col_style_logical_width = col->StyleRef().LogicalWidth();
int effective_col_width = 0;
if (col_style_logical_width.IsFixed() &&
col_style_logical_width.Value() > 0)
@@ -196,7 +196,7 @@ void TableLayoutAlgorithmFixed::ComputeIntrinsicLogicalWidths(
void TableLayoutAlgorithmFixed::ApplyPreferredLogicalWidthQuirks(
LayoutUnit& min_width,
LayoutUnit& max_width) const {
- Length table_logical_width = table_->StyleRef().LogicalWidth();
+ const Length& table_logical_width = table_->StyleRef().LogicalWidth();
if (table_logical_width.IsFixed() && table_logical_width.IsPositive()) {
min_width = max_width = LayoutUnit(
max(min_width,
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc b/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
index 9ad78dab1af..2d52e2e1c21 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -56,6 +56,7 @@
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/network/network_utils.h"
namespace blink {
@@ -117,7 +118,7 @@ static bool IsIndependentDescendant(const LayoutBlock* layout_object) {
return layout_object->IsLayoutView() || layout_object->IsFloating() ||
layout_object->IsOutOfFlowPositioned() ||
layout_object->IsTableCell() || layout_object->IsTableCaption() ||
- layout_object->IsFlexibleBoxIncludingDeprecated() ||
+ layout_object->IsFlexibleBoxIncludingDeprecatedAndNG() ||
(containing_block && containing_block->IsHorizontalWritingMode() !=
layout_object->IsHorizontalWritingMode()) ||
layout_object->StyleRef().IsDisplayReplacedType() ||
@@ -243,7 +244,8 @@ TextAutosizer::TextAutosizer(const Document* document)
cluster_stack_(),
fingerprint_mapper_(),
page_info_(),
- update_page_info_deferred_(false) {
+ update_page_info_deferred_(false),
+ did_check_cross_site_use_count_(false) {
}
TextAutosizer::~TextAutosizer() = default;
@@ -345,6 +347,8 @@ void TextAutosizer::BeginLayout(LayoutBlock* block,
return;
DCHECK(!cluster_stack_.IsEmpty() || block->IsLayoutView());
+ if (cluster_stack_.IsEmpty())
+ did_check_cross_site_use_count_ = false;
if (Cluster* cluster = MaybeCreateCluster(block))
cluster_stack_.push_back(base::WrapUnique(cluster));
@@ -434,9 +438,10 @@ float TextAutosizer::Inflate(LayoutObject* parent,
has_text_child = true;
// We only calculate this multiplier on-demand to ensure the parent block
// of this text has entered layout.
- if (!multiplier)
+ if (!multiplier) {
multiplier =
cluster->flags_ & SUPPRESSING ? 1.0f : ClusterMultiplier(cluster);
+ }
ApplyMultiplier(child, multiplier, layouter);
if (behavior == kDescendToInnerBlocks) {
@@ -892,11 +897,12 @@ float TextAutosizer::ClusterMultiplier(Cluster* cluster) {
cluster->multiplier_ = SuperclusterMultiplier(cluster);
cluster->supercluster_->inherit_parent_multiplier_ =
kDontInheritMultiplier;
- } else if (ClusterHasEnoughTextToAutosize(cluster))
+ } else if (ClusterHasEnoughTextToAutosize(cluster)) {
cluster->multiplier_ =
MultiplierFromBlock(ClusterWidthProvider(cluster->root_));
- else
+ } else {
cluster->multiplier_ = 1.0f;
+ }
} else {
cluster->multiplier_ =
cluster->parent_ ? ClusterMultiplier(cluster->parent_) : 1.0f;
@@ -1124,6 +1130,37 @@ const LayoutObject* TextAutosizer::FindTextLeaf(
return nullptr;
}
+static bool IsCrossSite(const Frame& frame1, const Frame& frame2) {
+ // Cross-site differs from cross-origin (LocalFrame::IsCrossOriginSubframe).
+ // For example, http://foo.com and http://sub.foo.com are cross-origin but
+ // same-site. Only cross-site text autosizing is impacted by site isolation
+ // (crbug.com/393285).
+
+ const auto* origin1 = frame1.GetSecurityContext()->GetSecurityOrigin();
+ const auto* origin2 = frame2.GetSecurityContext()->GetSecurityOrigin();
+ if (!origin1 || !origin2 || origin1->CanAccess(origin2))
+ return false;
+
+ if (origin1->Protocol() != origin2->Protocol())
+ return true;
+
+ // Compare eTLD+1.
+ return network_utils::GetDomainAndRegistry(
+ origin1->Host(), network_utils::kIncludePrivateRegistries) !=
+ network_utils::GetDomainAndRegistry(
+ origin2->Host(), network_utils::kIncludePrivateRegistries);
+}
+
+void TextAutosizer::ReportIfCrossSiteFrame() {
+ LocalFrame* frame = document_->GetFrame();
+ LocalFrameView* view = document_->View();
+ if (!frame || !view || !view->IsAttached() || !view->IsVisible() ||
+ view->Size().IsEmpty() || !IsCrossSite(*frame, frame->Tree().Top()))
+ return;
+
+ UseCounter::Count(*document_, WebFeature::kTextAutosizedCrossSiteIframe);
+}
+
void TextAutosizer::ApplyMultiplier(LayoutObject* layout_object,
float multiplier,
SubtreeLayoutScope* layouter,
@@ -1151,6 +1188,11 @@ void TextAutosizer::ApplyMultiplier(LayoutObject* layout_object,
scoped_refptr<ComputedStyle> style = ComputedStyle::Clone(current_style);
style->SetTextAutosizingMultiplier(multiplier);
+ if (multiplier > 1 && !did_check_cross_site_use_count_) {
+ ReportIfCrossSiteFrame();
+ did_check_cross_site_use_count_ = true;
+ }
+
switch (relayout_behavior) {
case kAlreadyInLayout:
// Don't free currentStyle until the end of the layout pass. This allows
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer.h b/chromium/third_party/blink/renderer/core/layout/text_autosizer.h
index b549857b343..b5c1c1604b2 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer.h
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer.h
@@ -360,6 +360,8 @@ class CORE_EXPORT TextAutosizer final
// Mark the nearest non-inheritance supercluser
void MarkSuperclusterForConsistencyCheck(LayoutObject*);
+ void ReportIfCrossSiteFrame();
+
Member<const Document> document_;
const LayoutBlock* first_block_to_begin_layout_;
#if DCHECK_IS_ON()
@@ -375,6 +377,11 @@ class CORE_EXPORT TextAutosizer final
// FIXME: All frames should share the same m_pageInfo instance.
PageInfo page_info_;
bool update_page_info_deferred_;
+
+ // Inflate reports a use counter if we're autosizing a cross site iframe.
+ // This flag makes sure we only check it once per layout pass.
+ bool did_check_cross_site_use_count_;
+
DISALLOW_COPY_AND_ASSIGN(TextAutosizer);
};
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc b/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc
index ff3514b6700..557d246bac9 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc
@@ -2,14 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "third_party/blink/renderer/core/layout/text_autosizer.h"
+
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/layout/text_autosizer.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
class TextAutosizerClient : public EmptyChromeClient {
@@ -1065,4 +1070,52 @@ TEST_F(TextAutosizerTest, AfterPrint) {
EXPECT_FLOAT_EQ(20.0f * device_scale,
target->GetLayoutObject()->StyleRef().ComputedFontSize());
}
+
+class TextAutosizerSimTest : public SimTest {
+ private:
+ void SetUp() override {
+ SimTest::SetUp();
+
+ WebSettings* web_settings = WebView().GetSettings();
+ web_settings->SetViewportEnabled(true);
+ web_settings->SetViewportMetaEnabled(true);
+
+ Settings& settings = WebView().GetPage()->GetSettings();
+ settings.SetTextAutosizingEnabled(true);
+ settings.SetTextAutosizingWindowSizeOverride(IntSize(400, 400));
+ }
+};
+
+TEST_F(TextAutosizerSimTest, CrossSiteUseCounter) {
+ WebView().MainFrameWidget()->Resize(WebSize(800, 800));
+
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimRequest child_resource("https://crosssite.com/", "text/html");
+
+ LoadURL("https://example.com/");
+ main_resource.Complete(
+ "<iframe width=700 src='https://crosssite.com/'></iframe>");
+
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+
+ child_resource.Complete(R"HTML(
+ <body style='font-size: 20px'>
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
+ do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco
+ laboris nisi ut aliquip ex ea commodo consequat.
+ </body>
+ )HTML");
+
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+
+ auto* child_frame = ToWebLocalFrameImpl(MainFrame().FirstChild());
+ auto* child_doc = child_frame->GetFrame()->GetDocument();
+
+ EXPECT_TRUE(UseCounter::IsCounted(*child_doc,
+ WebFeature::kTextAutosizedCrossSiteIframe));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index d7de7b34acc..3c1515378d6 100644
--- a/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -33,7 +33,7 @@ class VisualRectMappingTest : public PaintTestConfigurations,
if (object.IsBox())
ToLayoutBox(object).FlipForWritingMode(rect);
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_EQ(&ancestor, &object.ContainerForPaintInvalidation());
CheckVisualRect(object, ancestor, rect, expected_visual_rect_in_ancestor);
@@ -65,7 +65,7 @@ class VisualRectMappingTest : public PaintTestConfigurations,
// The following condition can be false if paintInvalidationContainer is
// a LayoutView and compositing is not enabled.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
ancestor.IsPaintInvalidationContainer()) {
PaintLayer::MapRectInPaintInvalidationContainerToBacking(ancestor,
slow_map_rect);
@@ -486,10 +486,14 @@ TEST_P(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowScroll) {
// (-2, 3, 140, 100) is first clipped by container's overflow clip, to
// (40, 10, 50, 80), then is added by container's offset in LayoutView
// (222, 111).
- // TODO(crbug.com/600039): rect.X() should be 262 (left + border-left), but is
- // offset by extra horizontal border-widths because of layout error.
- CheckPaintInvalidationVisualRect(*target, GetLayoutView(),
- LayoutRect(322, 121, 50, 80));
+
+ LayoutRect expectation(262, 121, 50, 80);
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // TODO(crbug.com/600039): rect.X() should be 262 (left + border-left), but
+ // is offset by extra horizontal border-widths because of layout error.
+ expectation = LayoutRect(322, 121, 50, 80);
+ }
+ CheckPaintInvalidationVisualRect(*target, GetLayoutView(), expectation);
LayoutRect container_local_visual_rect = container->LocalVisualRect();
// Because container has overflow clip, its visual overflow doesn't include
@@ -503,11 +507,13 @@ TEST_P(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowScroll) {
EXPECT_TRUE(container->MapToVisualRectInAncestorSpace(container, rect));
EXPECT_EQ(LayoutRect(0, 0, 110, 120), rect);
- // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by
- // extra horizontal
- // border-widths because of layout error.
- CheckPaintInvalidationVisualRect(*container, GetLayoutView(),
- LayoutRect(282, 111, 110, 120));
+ expectation = LayoutRect(222, 111, 110, 120);
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by
+ // extra horizontal border-widths because of layout error.
+ expectation = LayoutRect(282, 111, 110, 120);
+ }
+ CheckPaintInvalidationVisualRect(*container, GetLayoutView(), expectation);
}
TEST_P(VisualRectMappingTest, ContainerOverflowHidden) {
@@ -657,7 +663,7 @@ TEST_P(VisualRectMappingTest,
LayoutBlock* normal_flow =
ToLayoutBlock(GetLayoutObjectByElementId("normal-flow"));
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_EQ(scroller, &normal_flow->ContainerForPaintInvalidation());
LayoutRect normal_flow_visual_rect = normal_flow->LocalVisualRect();
@@ -765,12 +771,23 @@ TEST_P(VisualRectMappingTest, FloatUnderInline) {
LayoutRect rect = target_visual_rect;
EXPECT_TRUE(target->MapToVisualRectInAncestorSpace(&GetLayoutView(), rect));
- EXPECT_EQ(LayoutRect(66, 55, 33, 44), rect);
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // LayoutNG inline-level floats are children of their inline-level
+ // containers. As such they are positioned relative to their inline-level
+ // container, (and shifted by an additional 200,100 in this case).
+ EXPECT_EQ(LayoutRect(266, 155, 33, 44), rect);
+ } else {
+ EXPECT_EQ(LayoutRect(66, 55, 33, 44), rect);
+ }
EXPECT_EQ(rect, target->FirstFragment().VisualRect());
rect = target_visual_rect;
- CheckVisualRect(*target, *span, rect, LayoutRect(-200, -100, 33, 44));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ CheckVisualRect(*target, *span, rect, LayoutRect(0, 0, 33, 44));
+ } else {
+ CheckVisualRect(*target, *span, rect, LayoutRect(-200, -100, 33, 44));
+ }
}
TEST_P(VisualRectMappingTest, ShouldAccountForPreserve3d) {
diff --git a/chromium/third_party/blink/renderer/core/loader/BUILD.gn b/chromium/third_party/blink/renderer/core/loader/BUILD.gn
index 5ea3adbbe9d..ce57e796305 100644
--- a/chromium/third_party/blink/renderer/core/loader/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/loader/BUILD.gn
@@ -6,14 +6,14 @@ import("//third_party/blink/renderer/core/core.gni")
blink_core_sources("loader") {
sources = [
- "allowed_by_nosniff.cc",
- "allowed_by_nosniff.h",
"appcache/application_cache.cc",
"appcache/application_cache.h",
"appcache/application_cache_host.cc",
"appcache/application_cache_host.h",
"base_fetch_context.cc",
"base_fetch_context.h",
+ "console_logger_impl_base.cc",
+ "console_logger_impl_base.h",
"cookie_jar.cc",
"cookie_jar.h",
"document_load_timing.cc",
@@ -33,6 +33,10 @@ blink_core_sources("loader") {
"frame_loader_state_machine.cc",
"frame_loader_state_machine.h",
"frame_loader_types.h",
+ "frame_or_imported_document.cc",
+ "frame_or_imported_document.h",
+ "frame_resource_fetcher_properties.cc",
+ "frame_resource_fetcher_properties.h",
"history_item.cc",
"history_item.h",
"http_equiv.cc",
@@ -45,6 +49,8 @@ blink_core_sources("loader") {
"importance_attribute.h",
"interactive_detector.cc",
"interactive_detector.h",
+ "link_load_parameters.cc",
+ "link_load_parameters.h",
"link_loader.cc",
"link_loader.h",
"link_loader_client.h",
@@ -80,6 +86,8 @@ blink_core_sources("loader") {
"network_hints_interface.h",
"ping_loader.cc",
"ping_loader.h",
+ "preload_helper.cc",
+ "preload_helper.h",
"prerenderer_client.cc",
"prerenderer_client.h",
"previews_resource_loading_hints.cc",
@@ -129,6 +137,8 @@ blink_core_sources("loader") {
"threadable_loader_client.h",
"worker_fetch_context.cc",
"worker_fetch_context.h",
+ "worker_resource_fetcher_properties.cc",
+ "worker_resource_fetcher_properties.h",
]
public_deps = [
diff --git a/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.h b/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.h
deleted file mode 100644
index 16b4b5ad649..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.h
+++ /dev/null
@@ -1,25 +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 THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_ALLOWED_BY_NOSNIFF_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_ALLOWED_BY_NOSNIFF_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-
-namespace blink {
-
-class ExecutionContext;
-class ResourceResponse;
-
-class CORE_EXPORT AllowedByNosniff {
- public:
- enum class MimeTypeCheck { kStrict, kLax };
-
- static bool MimeTypeAsScript(ExecutionContext*,
- const ResourceResponse&,
- MimeTypeCheck mime_type_check_mode);
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.cc b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.cc
index 9cced5e52dc..16e4a1d32d7 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.cc
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.cc
@@ -25,6 +25,8 @@
#include "third_party/blink/renderer/core/loader/appcache/application_cache.h"
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
+#include "third_party/blink/public/mojom/appcache/appcache_info.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
@@ -55,11 +57,33 @@ ApplicationCacheHost* ApplicationCache::GetApplicationCacheHost() const {
}
unsigned short ApplicationCache::status() const {
+ // Application Cache status numeric values are specified in the HTML5 spec.
+ static_assert(static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_UNCACHED) == 0,
+ "");
+ static_assert(static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_IDLE) == 1,
+ "");
+ static_assert(static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_CHECKING) == 2,
+ "");
+ static_assert(static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_DOWNLOADING) == 3,
+ "");
+ static_assert(static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_UPDATE_READY) == 4,
+ "");
+ static_assert(static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_OBSOLETE) == 5,
+ "");
+
RecordAPIUseType();
ApplicationCacheHost* cache_host = GetApplicationCacheHost();
- if (!cache_host)
- return ApplicationCacheHost::kUncached;
- return cache_host->GetStatus();
+ if (!cache_host) {
+ return static_cast<unsigned short>(
+ mojom::AppCacheStatus::APPCACHE_STATUS_UNCACHED);
+ }
+ return static_cast<unsigned short>(cache_host->GetStatus());
}
void ApplicationCache::update(ExceptionState& exception_state) {
@@ -96,24 +120,23 @@ ExecutionContext* ApplicationCache::GetExecutionContext() const {
return GetFrame() ? GetFrame()->GetDocument() : nullptr;
}
-const AtomicString& ApplicationCache::ToEventType(
- ApplicationCacheHost::EventID id) {
+const AtomicString& ApplicationCache::ToEventType(mojom::AppCacheEventID id) {
switch (id) {
- case ApplicationCacheHost::kCheckingEvent:
+ case mojom::AppCacheEventID::APPCACHE_CHECKING_EVENT:
return event_type_names::kChecking;
- case ApplicationCacheHost::kErrorEvent:
+ case mojom::AppCacheEventID::APPCACHE_ERROR_EVENT:
return event_type_names::kError;
- case ApplicationCacheHost::kNoupdateEvent:
+ case mojom::AppCacheEventID::APPCACHE_NO_UPDATE_EVENT:
return event_type_names::kNoupdate;
- case ApplicationCacheHost::kDownloadingEvent:
+ case mojom::AppCacheEventID::APPCACHE_DOWNLOADING_EVENT:
return event_type_names::kDownloading;
- case ApplicationCacheHost::kProgressEvent:
+ case mojom::AppCacheEventID::APPCACHE_PROGRESS_EVENT:
return event_type_names::kProgress;
- case ApplicationCacheHost::kUpdatereadyEvent:
+ case mojom::AppCacheEventID::APPCACHE_UPDATE_READY_EVENT:
return event_type_names::kUpdateready;
- case ApplicationCacheHost::kCachedEvent:
+ case mojom::AppCacheEventID::APPCACHE_CACHED_EVENT:
return event_type_names::kCached;
- case ApplicationCacheHost::kObsoleteEvent:
+ case mojom::AppCacheEventID::APPCACHE_OBSOLETE_EVENT:
return event_type_names::kObsolete;
}
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.h b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.h
index 0112a5a8016..1f13f7a0e7b 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.h
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_APPCACHE_APPLICATION_CACHE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_APPCACHE_APPLICATION_CACHE_H_
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
@@ -44,8 +45,10 @@ class ApplicationCache final : public EventTargetWithInlineData,
public:
static ApplicationCache* Create(LocalFrame* frame) {
- return new ApplicationCache(frame);
+ return MakeGarbageCollected<ApplicationCache>(frame);
}
+
+ explicit ApplicationCache(LocalFrame*);
~ApplicationCache() override = default;
unsigned short status() const;
@@ -67,13 +70,11 @@ class ApplicationCache final : public EventTargetWithInlineData,
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
- static const AtomicString& ToEventType(ApplicationCacheHost::EventID);
+ static const AtomicString& ToEventType(mojom::AppCacheEventID);
void Trace(blink::Visitor*) override;
private:
- explicit ApplicationCache(LocalFrame*);
-
void RecordAPIUseType() const;
ApplicationCacheHost* GetApplicationCacheHost() const;
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
index ec240a0a3fc..54808bb623b 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-blink.h"
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
+#include "third_party/blink/public/mojom/appcache/appcache_info.mojom-blink.h"
#include "third_party/blink/public/platform/web_application_cache_host.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_error.h"
@@ -90,7 +92,7 @@ void ApplicationCacheHost::WillStartLoading(ResourceRequest& request) {
return;
int host_id = host_->GetHostID();
- if (host_id != WebApplicationCacheHost::kAppCacheNoHostId)
+ if (host_id != mojom::blink::kAppCacheNoHostId)
request.SetAppCacheHostID(host_id);
}
@@ -179,22 +181,6 @@ void ApplicationCacheHost::DidReceiveResponseForMainResource(
}
}
-void ApplicationCacheHost::MainResourceDataReceived(const char* data,
- size_t length) {
- if (host_)
- host_->DidReceiveDataForMainResource(data, length);
-}
-
-void ApplicationCacheHost::FailedLoadingMainResource() {
- if (host_)
- host_->DidFinishLoadingMainResource(false);
-}
-
-void ApplicationCacheHost::FinishedLoadingMainResource() {
- if (host_)
- host_->DidFinishLoadingMainResource(true);
-}
-
void ApplicationCacheHost::SetApplicationCache(
ApplicationCache* dom_application_cache) {
DCHECK(!dom_application_cache_ || !dom_application_cache);
@@ -210,14 +196,14 @@ void ApplicationCacheHost::DetachFromDocumentLoader() {
}
void ApplicationCacheHost::NotifyApplicationCache(
- EventID id,
+ mojom::AppCacheEventID id,
int progress_total,
int progress_done,
- WebApplicationCacheHost::ErrorReason error_reason,
+ mojom::AppCacheErrorReason error_reason,
const String& error_url,
int error_status,
const String& error_message) {
- if (id != kProgressEvent) {
+ if (id != mojom::AppCacheEventID::APPCACHE_PROGRESS_EVENT) {
probe::updateApplicationCacheStatus(document_loader_->GetFrame());
}
@@ -244,7 +230,7 @@ ApplicationCacheHost::CacheInfo ApplicationCacheHost::ApplicationCacheInfo() {
int ApplicationCacheHost::GetHostID() const {
if (!host_)
- return WebApplicationCacheHost::kAppCacheNoHostId;
+ return mojom::blink::kAppCacheNoHostId;
return host_->GetHostID();
}
@@ -276,10 +262,10 @@ void ApplicationCacheHost::StopDeferringEvents() {
}
void ApplicationCacheHost::DispatchDOMEvent(
- EventID id,
+ mojom::AppCacheEventID id,
int progress_total,
int progress_done,
- WebApplicationCacheHost::ErrorReason error_reason,
+ mojom::AppCacheErrorReason error_reason,
const String& error_url,
int error_status,
const String& error_message) {
@@ -291,10 +277,10 @@ void ApplicationCacheHost::DispatchDOMEvent(
if (event_type.IsEmpty())
return;
Event* event = nullptr;
- if (id == kProgressEvent) {
+ if (id == mojom::AppCacheEventID::APPCACHE_PROGRESS_EVENT) {
event =
ProgressEvent::Create(event_type, true, progress_done, progress_total);
- } else if (id == kErrorEvent) {
+ } else if (id == mojom::AppCacheEventID::APPCACHE_ERROR_EVENT) {
event = ApplicationCacheErrorEvent::Create(error_reason, error_url,
error_status, error_message);
} else {
@@ -303,8 +289,9 @@ void ApplicationCacheHost::DispatchDOMEvent(
dom_application_cache_->DispatchEvent(*event);
}
-ApplicationCacheHost::Status ApplicationCacheHost::GetStatus() const {
- return host_ ? static_cast<Status>(host_->GetStatus()) : kUncached;
+mojom::AppCacheStatus ApplicationCacheHost::GetStatus() const {
+ return host_ ? host_->GetStatus()
+ : mojom::AppCacheStatus::APPCACHE_STATUS_UNCACHED;
}
bool ApplicationCacheHost::Update() {
@@ -338,27 +325,28 @@ void ApplicationCacheHost::DidChangeCacheAssociation() {
}
void ApplicationCacheHost::NotifyEventListener(
- WebApplicationCacheHost::EventID event_id) {
- NotifyApplicationCache(static_cast<ApplicationCacheHost::EventID>(event_id),
- 0, 0, WebApplicationCacheHost::kUnknownError, String(),
- 0, String());
+ mojom::AppCacheEventID event_id) {
+ NotifyApplicationCache(event_id, 0, 0,
+ mojom::AppCacheErrorReason::APPCACHE_UNKNOWN_ERROR,
+ String(), 0, String());
}
void ApplicationCacheHost::NotifyProgressEventListener(const WebURL&,
int progress_total,
int progress_done) {
- NotifyApplicationCache(kProgressEvent, progress_total, progress_done,
- WebApplicationCacheHost::kUnknownError, String(), 0,
- String());
+ NotifyApplicationCache(mojom::AppCacheEventID::APPCACHE_PROGRESS_EVENT,
+ progress_total, progress_done,
+ mojom::AppCacheErrorReason::APPCACHE_UNKNOWN_ERROR,
+ String(), 0, String());
}
void ApplicationCacheHost::NotifyErrorEventListener(
- WebApplicationCacheHost::ErrorReason reason,
+ mojom::AppCacheErrorReason reason,
const WebURL& url,
int status,
const WebString& message) {
- NotifyApplicationCache(kErrorEvent, 0, 0, reason, url.GetString(), status,
- message);
+ NotifyApplicationCache(mojom::AppCacheEventID::APPCACHE_ERROR_EVENT, 0, 0,
+ reason, url.GetString(), status, message);
}
void ApplicationCacheHost::Trace(blink::Visitor* visitor) {
@@ -366,32 +354,4 @@ void ApplicationCacheHost::Trace(blink::Visitor* visitor) {
visitor->Trace(document_loader_);
}
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kUncached,
- ApplicationCacheHost::kUncached);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kIdle, ApplicationCacheHost::kIdle);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kChecking,
- ApplicationCacheHost::kChecking);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kDownloading,
- ApplicationCacheHost::kDownloading);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kUpdateReady,
- ApplicationCacheHost::kUpdateready);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kObsolete,
- ApplicationCacheHost::kObsolete);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kCheckingEvent,
- ApplicationCacheHost::kCheckingEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kErrorEvent,
- ApplicationCacheHost::kErrorEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kNoUpdateEvent,
- ApplicationCacheHost::kNoupdateEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kDownloadingEvent,
- ApplicationCacheHost::kDownloadingEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kProgressEvent,
- ApplicationCacheHost::kProgressEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kUpdateReadyEvent,
- ApplicationCacheHost::kUpdatereadyEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kCachedEvent,
- ApplicationCacheHost::kCachedEvent);
-STATIC_ASSERT_ENUM(WebApplicationCacheHost::kObsoleteEvent,
- ApplicationCacheHost::kObsoleteEvent);
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
index ca00e851a15..09dcf870e09 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
@@ -35,6 +35,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
#include "third_party/blink/public/platform/web_application_cache_host_client.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -53,33 +54,13 @@ class CORE_EXPORT ApplicationCacheHost final
public WebApplicationCacheHostClient {
public:
static ApplicationCacheHost* Create(DocumentLoader* loader) {
- return new ApplicationCacheHost(loader);
+ return MakeGarbageCollected<ApplicationCacheHost>(loader);
}
+ explicit ApplicationCacheHost(DocumentLoader*);
~ApplicationCacheHost() override;
void DetachFromDocumentLoader();
- // The Status numeric values are specified in the HTML5 spec.
- enum Status {
- kUncached = 0,
- kIdle = 1,
- kChecking = 2,
- kDownloading = 3,
- kUpdateready = 4,
- kObsolete = 5
- };
-
- enum EventID {
- kCheckingEvent = 0,
- kErrorEvent,
- kNoupdateEvent,
- kDownloadingEvent,
- kProgressEvent,
- kUpdatereadyEvent,
- kCachedEvent,
- kObsoleteEvent // Must remain the last value, this is used to size arrays.
- };
-
struct CacheInfo {
STACK_ALLOCATED();
@@ -135,19 +116,17 @@ class CORE_EXPORT ApplicationCacheHost final
void DidReceiveResponseForMainResource(const ResourceResponse&);
void MainResourceDataReceived(const char* data, size_t length);
- void FinishedLoadingMainResource();
- void FailedLoadingMainResource();
- Status GetStatus() const;
+ mojom::AppCacheStatus GetStatus() const;
bool Update();
bool SwapCache();
void Abort();
void SetApplicationCache(ApplicationCache*);
- void NotifyApplicationCache(EventID,
+ void NotifyApplicationCache(mojom::AppCacheEventID,
int progress_total,
int progress_done,
- WebApplicationCacheHost::ErrorReason,
+ mojom::AppCacheErrorReason,
const String& error_url,
int error_status,
const String& error_message);
@@ -162,17 +141,15 @@ class CORE_EXPORT ApplicationCacheHost final
void Trace(blink::Visitor*);
private:
- explicit ApplicationCacheHost(DocumentLoader*);
-
void WillStartLoadingMainResource(const KURL&, const String&);
// WebApplicationCacheHostClient implementation
void DidChangeCacheAssociation() final;
- void NotifyEventListener(WebApplicationCacheHost::EventID) final;
+ void NotifyEventListener(mojom::AppCacheEventID) final;
void NotifyProgressEventListener(const WebURL&,
int progress_total,
int progress_done) final;
- void NotifyErrorEventListener(WebApplicationCacheHost::ErrorReason,
+ void NotifyErrorEventListener(mojom::AppCacheErrorReason,
const WebURL&,
int status,
const WebString& message) final;
@@ -181,17 +158,17 @@ class CORE_EXPORT ApplicationCacheHost final
DocumentLoader* GetDocumentLoader() const { return document_loader_; }
struct DeferredEvent {
- EventID event_id;
+ mojom::AppCacheEventID event_id;
int progress_total;
int progress_done;
- WebApplicationCacheHost::ErrorReason error_reason;
+ mojom::AppCacheErrorReason error_reason;
String error_url;
int error_status;
String error_message;
- DeferredEvent(EventID id,
+ DeferredEvent(mojom::AppCacheEventID id,
int progress_total,
int progress_done,
- WebApplicationCacheHost::ErrorReason error_reason,
+ mojom::AppCacheErrorReason error_reason,
const String& error_url,
int error_status,
const String& error_message)
@@ -209,10 +186,10 @@ class CORE_EXPORT ApplicationCacheHost final
bool defers_events_; // Events are deferred until after document onload.
Vector<DeferredEvent> deferred_events_;
- void DispatchDOMEvent(EventID,
+ void DispatchDOMEvent(mojom::AppCacheEventID,
int progress_total,
int progress_done,
- WebApplicationCacheHost::ErrorReason,
+ mojom::AppCacheErrorReason,
const String& error_url,
int error_status,
const String& error_message);
diff --git a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc
index ceac85e10cf..040374a5e0e 100644
--- a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/weborigin/origin_access_entry.h"
@@ -89,29 +90,12 @@ const char* GetDestinationFromContext(mojom::RequestContextType context) {
return "";
}
-MessageSource ConvertLogSourceToMessageSource(FetchContext::LogSource source) {
- // When LogSource is extended, this switch statement should be modified to
- // convert LogSource to blink::MessageSource.
- switch (source) {
- case FetchContext::kJSSource:
- return kJSMessageSource;
- case FetchContext::kSecuritySource:
- return kSecurityMessageSource;
- case FetchContext::kOtherSource:
- return kOtherMessageSource;
- }
- NOTREACHED();
- return kOtherMessageSource;
-}
-
} // namespace
-BaseFetchContext::BaseFetchContext(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : FetchContext(std::move(task_runner)) {}
-
void BaseFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request,
FetchResourceType type) {
+ const FetchClientSettingsObject& fetch_client_settings_object =
+ GetResourceFetcherProperties().GetFetchClientSettingsObject();
bool is_main_resource = type == kFetchMainResource;
if (!is_main_resource) {
// TODO(domfarolino): we can probably *just set* the HTTP `Referer` here
@@ -122,24 +106,25 @@ void BaseFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request,
request.GetReferrerPolicy();
if (referrer_to_use == Referrer::ClientReferrerString())
- referrer_to_use = GetFetchClientSettingsObject()->GetOutgoingReferrer();
+ referrer_to_use = fetch_client_settings_object.GetOutgoingReferrer();
if (referrer_policy_to_use == network::mojom::ReferrerPolicy::kDefault) {
referrer_policy_to_use =
- GetFetchClientSettingsObject()->GetReferrerPolicy();
+ fetch_client_settings_object.GetReferrerPolicy();
}
// TODO(domfarolino): Stop storing ResourceRequest's referrer as a header
// and store it elsewhere. See https://crbug.com/850813.
request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer(
referrer_policy_to_use, request.Url(), referrer_to_use));
- request.SetHTTPOriginIfNeeded(GetSecurityOrigin());
+ request.SetHTTPOriginIfNeeded(
+ fetch_client_settings_object.GetSecurityOrigin());
} else {
- DCHECK_EQ(SecurityPolicy::GenerateReferrer(request.GetReferrerPolicy(),
- request.Url(),
- request.HttpReferrer())
- .referrer,
- request.HttpReferrer());
+ CHECK_EQ(SecurityPolicy::GenerateReferrer(request.GetReferrerPolicy(),
+ request.Url(),
+ request.HttpReferrer())
+ .referrer,
+ request.HttpReferrer());
request.SetHTTPOriginToMatchReferrerIfNeeded();
}
}
@@ -162,22 +147,24 @@ void BaseFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request,
request.GetRequestContext() != mojom::RequestContextType::INTERNAL) {
const char* site_value = "cross-site";
if (SecurityOrigin::Create(request.Url())
- ->IsSameSchemeHostPort(GetSecurityOrigin())) {
+ ->IsSameSchemeHostPort(
+ fetch_client_settings_object.GetSecurityOrigin())) {
site_value = "same-origin";
} else {
OriginAccessEntry access_entry(
request.Url().Protocol(), request.Url().Host(),
network::mojom::CorsOriginAccessMatchMode::
kAllowRegisterableDomains);
- if (access_entry.MatchesOrigin(*GetSecurityOrigin()) ==
+ if (access_entry.MatchesOrigin(
+ *fetch_client_settings_object.GetSecurityOrigin()) ==
network::cors::OriginAccessEntry::kMatchesOrigin) {
site_value = "same-site";
}
}
- String value = String::Format("destination=%s, site=%s",
- destination_value, site_value);
- request.AddHTTPHeaderField("Sec-Metadata", AtomicString(value));
+ request.AddHTTPHeaderField("Sec-Fetch-Dest", destination_value);
+ request.AddHTTPHeaderField("Sec-Fetch-Site", site_value);
+ request.AddHTTPHeaderField("Sec-Fetch-User", "?F");
}
}
}
@@ -200,24 +187,6 @@ base::Optional<ResourceRequestBlockedReason> BaseFetchContext::CanRequest(
return blocked_reason;
}
-void BaseFetchContext::AddInfoConsoleMessage(const String& message,
- LogSource source) const {
- AddConsoleMessage(ConsoleMessage::Create(
- ConvertLogSourceToMessageSource(source), kInfoMessageLevel, message));
-}
-
-void BaseFetchContext::AddWarningConsoleMessage(const String& message,
- LogSource source) const {
- AddConsoleMessage(ConsoleMessage::Create(
- ConvertLogSourceToMessageSource(source), kWarningMessageLevel, message));
-}
-
-void BaseFetchContext::AddErrorConsoleMessage(const String& message,
- LogSource source) const {
- AddConsoleMessage(ConsoleMessage::Create(
- ConvertLogSourceToMessageSource(source), kErrorMessageLevel, message));
-}
-
bool BaseFetchContext::IsAdResource(
const KURL& resource_url,
ResourceType type,
@@ -317,8 +286,9 @@ BaseFetchContext::CanRequestInternal(
if (request_mode != network::mojom::FetchRequestMode::kNavigate &&
!origin->CanDisplay(url)) {
if (reporting_policy == SecurityViolationReportingPolicy::kReport) {
- AddErrorConsoleMessage(
- "Not allowed to load local resource: " + url.GetString(), kJSSource);
+ AddConsoleMessage(ConsoleMessage::Create(
+ kJSMessageSource, kErrorMessageLevel,
+ "Not allowed to load local resource: " + url.GetString()));
}
RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::requestResource URL was not "
"allowed by SecurityOrigin::CanDisplay";
@@ -376,8 +346,11 @@ BaseFetchContext::CanRequestInternal(
if (frame_type != network::mojom::RequestContextFrameType::kTopLevel) {
bool is_subresource =
frame_type == network::mojom::RequestContextFrameType::kNone;
+ const FetchClientSettingsObject& fetch_client_settings_object =
+ GetResourceFetcherProperties().GetFetchClientSettingsObject();
const SecurityOrigin* embedding_origin =
- is_subresource ? GetSecurityOrigin() : GetParentSecurityOrigin();
+ is_subresource ? fetch_client_settings_object.GetSecurityOrigin()
+ : GetParentSecurityOrigin();
DCHECK(embedding_origin);
if (SchemeRegistry::ShouldTreatURLSchemeAsLegacy(url.Protocol()) &&
!SchemeRegistry::ShouldTreatURLSchemeAsLegacy(
diff --git a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h
index 59b0488157b..ed614f9815f 100644
--- a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h
+++ b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h
@@ -52,22 +52,16 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
virtual SubresourceFilter* GetSubresourceFilter() const = 0;
virtual PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
const = 0;
- virtual void CountUsage(WebFeature) const = 0;
- virtual void CountDeprecation(WebFeature) const = 0;
virtual bool ShouldBlockWebSocketByMixedContentCheck(const KURL&) const = 0;
virtual std::unique_ptr<WebSocketHandshakeThrottle>
CreateWebSocketHandshakeThrottle() = 0;
- void AddInfoConsoleMessage(const String&, LogSource) const override;
- void AddWarningConsoleMessage(const String&, LogSource) const override;
- void AddErrorConsoleMessage(const String&, LogSource) const override;
bool IsAdResource(const KURL&,
ResourceType,
mojom::RequestContextType) const override;
protected:
- explicit BaseFetchContext(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ BaseFetchContext() = default;
// Used for security checks.
virtual bool AllowScriptFromSource(const KURL&) const = 0;
@@ -95,6 +89,7 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
virtual base::Optional<mojom::IPAddressSpace> GetAddressSpace() const = 0;
virtual const ContentSecurityPolicy* GetContentSecurityPolicy() const = 0;
+ // TODO(yhirano): Remove this.
virtual void AddConsoleMessage(ConsoleMessage*) const = 0;
private:
diff --git a/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc b/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
index afe9fc6fe50..b09e1c18900 100644
--- a/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
@@ -36,6 +36,9 @@
#include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
#include "third_party/blink/renderer/core/testing/null_execution_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
+#include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -43,19 +46,10 @@ namespace blink {
class MockBaseFetchContext final : public BaseFetchContext {
public:
explicit MockBaseFetchContext(ExecutionContext* execution_context)
- : BaseFetchContext(
- execution_context->GetTaskRunner(blink::TaskType::kInternalTest)),
- execution_context_(execution_context),
- fetch_client_settings_object_(
- MakeGarbageCollected<FetchClientSettingsObjectImpl>(
- *execution_context)) {}
+ : execution_context_(execution_context) {}
~MockBaseFetchContext() override = default;
// BaseFetchContext overrides:
- const FetchClientSettingsObject* GetFetchClientSettingsObject()
- const override {
- return fetch_client_settings_object_.Get();
- }
KURL GetSiteForCookies() const override { return KURL(); }
bool AllowScriptFromSource(const KURL&) const override { return false; }
SubresourceFilter* GetSubresourceFilter() const override { return nullptr; }
@@ -95,9 +89,6 @@ class MockBaseFetchContext final : public BaseFetchContext {
}
const KURL& Url() const override { return execution_context_->Url(); }
- const SecurityOrigin* GetSecurityOrigin() const override {
- return fetch_client_settings_object_->GetSecurityOrigin();
- }
const SecurityOrigin* GetParentSecurityOrigin() const override {
return nullptr;
}
@@ -117,7 +108,10 @@ class MockBaseFetchContext final : public BaseFetchContext {
}
bool IsDetached() const override { return is_detached_; }
- void SetIsDetached(bool is_detached) { is_detached_ = is_detached; }
+ FetchContext* Detach() override {
+ is_detached_ = true;
+ return this;
+ }
private:
Member<ExecutionContext> execution_context_;
@@ -133,10 +127,24 @@ class BaseFetchContextTest : public testing::Test {
->SetUpSecurityContext();
fetch_context_ =
MakeGarbageCollected<MockBaseFetchContext>(execution_context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(
+ *MakeGarbageCollected<FetchClientSettingsObjectImpl>(
+ *execution_context_));
+ resource_fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, fetch_context_,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
+ }
+
+ const FetchClientSettingsObject& GetFetchClientSettingsObject() const {
+ return resource_fetcher_->GetProperties().GetFetchClientSettingsObject();
+ }
+ const SecurityOrigin* GetSecurityOrigin() const {
+ return GetFetchClientSettingsObject().GetSecurityOrigin();
}
Persistent<ExecutionContext> execution_context_;
Persistent<MockBaseFetchContext> fetch_context_;
+ Persistent<ResourceFetcher> resource_fetcher_;
};
TEST_F(BaseFetchContextTest, SetIsExternalRequestForPublicContext) {
@@ -305,7 +313,7 @@ TEST_F(BaseFetchContextTest, CanRequest) {
KURL url(NullURL(), "http://baz.test");
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::SCRIPT);
- resource_request.SetRequestorOrigin(fetch_context_->GetSecurityOrigin());
+ resource_request.SetRequestorOrigin(GetSecurityOrigin());
resource_request.SetFetchCredentialsMode(
network::mojom::FetchCredentialsMode::kOmit);
@@ -345,9 +353,9 @@ TEST_F(BaseFetchContextTest, CheckCSPForRequest) {
TEST_F(BaseFetchContextTest, CanRequestWhenDetached) {
KURL url(NullURL(), "http://www.example.com/");
ResourceRequest request(url);
- request.SetRequestorOrigin(fetch_context_->GetSecurityOrigin());
+ request.SetRequestorOrigin(GetSecurityOrigin());
ResourceRequest keepalive_request(url);
- keepalive_request.SetRequestorOrigin(fetch_context_->GetSecurityOrigin());
+ keepalive_request.SetRequestorOrigin(GetSecurityOrigin());
keepalive_request.SetKeepalive(true);
EXPECT_EQ(base::nullopt,
@@ -376,7 +384,7 @@ TEST_F(BaseFetchContextTest, CanRequestWhenDetached) {
SecurityViolationReportingPolicy::kSuppressReporting,
ResourceRequest::RedirectStatus::kFollowedRedirect));
- fetch_context_->SetIsDetached(true);
+ resource_fetcher_->ClearContext();
EXPECT_EQ(ResourceRequestBlockedReason::kOther,
fetch_context_->CanRequest(
@@ -411,7 +419,7 @@ TEST_F(BaseFetchContextTest, UACSSTest) {
KURL data_url("data:image/png;base64,test");
ResourceRequest resource_request(test_url);
- resource_request.SetRequestorOrigin(fetch_context_->GetSecurityOrigin());
+ resource_request.SetRequestorOrigin(GetSecurityOrigin());
ResourceLoaderOptions options;
options.initiator_info.name = fetch_initiator_type_names::kUacss;
@@ -445,7 +453,7 @@ TEST_F(BaseFetchContextTest, UACSSTest_BypassCSP) {
KURL data_url("data:image/png;base64,test");
ResourceRequest resource_request(data_url);
- resource_request.SetRequestorOrigin(fetch_context_->GetSecurityOrigin());
+ resource_request.SetRequestorOrigin(GetSecurityOrigin());
ResourceLoaderOptions options;
options.initiator_info.name = fetch_initiator_type_names::kUacss;
diff --git a/chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.cc b/chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.cc
new file mode 100644
index 00000000000..decf906b2b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/console_logger_impl_base.h"
+
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+
+namespace blink {
+
+ConsoleLoggerImplBase::ConsoleLoggerImplBase() = default;
+ConsoleLoggerImplBase::~ConsoleLoggerImplBase() = default;
+
+void ConsoleLoggerImplBase::AddInfoMessage(Source source,
+ const String& message) {
+ AddConsoleMessage(ConsoleMessage::Create(GetMessageSourceFromSource(source),
+ kInfoMessageLevel, message));
+}
+
+void ConsoleLoggerImplBase::AddWarningMessage(Source source,
+ const String& message) {
+ AddConsoleMessage(ConsoleMessage::Create(GetMessageSourceFromSource(source),
+ kWarningMessageLevel, message));
+}
+
+void ConsoleLoggerImplBase::AddErrorMessage(Source source,
+ const String& message) {
+ AddConsoleMessage(ConsoleMessage::Create(GetMessageSourceFromSource(source),
+ kErrorMessageLevel, message));
+}
+
+MessageSource ConsoleLoggerImplBase::GetMessageSourceFromSource(Source source) {
+ switch (source) {
+ case Source::kScript:
+ return kJSMessageSource;
+ case Source::kSecurity:
+ return kSecurityMessageSource;
+ case Source::kOther:
+ return kOtherMessageSource;
+ }
+ NOTREACHED();
+ return kOtherMessageSource;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.h b/chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.h
new file mode 100644
index 00000000000..ea67327b62b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/console_logger_impl_base.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_CONSOLE_LOGGER_IMPL_BASE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_CONSOLE_LOGGER_IMPL_BASE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/inspector/console_types.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
+
+namespace blink {
+
+class ConsoleMessage;
+
+// A bridge class which translates an Add(Info|Warning|Error)Message call to
+// an AddMessage call.
+class CORE_EXPORT ConsoleLoggerImplBase : public ConsoleLogger {
+ public:
+ ConsoleLoggerImplBase();
+ ~ConsoleLoggerImplBase() override;
+
+ // ConsoleLogger implementation.
+ void AddInfoMessage(Source source, const String& message) override;
+ void AddWarningMessage(Source source, const String& message) override;
+ void AddErrorMessage(Source source, const String& message) override;
+
+ virtual void AddConsoleMessage(ConsoleMessage*) = 0;
+
+ private:
+ static MessageSource GetMessageSourceFromSource(Source);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_CONSOLE_LOGGER_IMPL_BASE_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/document_loader.cc b/chromium/third_party/blink/renderer/core/loader/document_loader.cc
index 521ff8ebc0a..456d1bd8383 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/document_loader.cc
@@ -31,6 +31,8 @@
#include <memory>
#include "base/auto_reset.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/blink/public/common/origin_policy/origin_policy.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/platform.h"
@@ -53,22 +55,19 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
-#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
#include "third_party/blink/renderer/core/loader/frame_fetch_context.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
+#include "third_party/blink/renderer/core/loader/frame_or_imported_document.h"
+#include "third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h"
#include "third_party/blink/renderer/core/loader/idleness_detector.h"
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
-#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/renderer/core/loader/network_hints_interface.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
#include "third_party/blink/renderer/core/loader/progress_tracker.h"
-#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/image_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
@@ -87,6 +86,8 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
+#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
+#include "third_party/blink/renderer/platform/loader/ftp_directory_listing.h"
#include "third_party/blink/renderer/platform/mhtml/archive_resource.h"
#include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h"
@@ -105,56 +106,71 @@
namespace blink {
-// The MHTML mime type should be same as the one we check in the browser
-// process's IsDownload (navigation_url_loader_network_service.cc).
-static bool IsArchiveMIMEType(const String& mime_type) {
- return DeprecatedEqualIgnoringCase("multipart/related", mime_type) ||
- DeprecatedEqualIgnoringCase("message/rfc822", mime_type);
-}
-
DocumentLoader::DocumentLoader(
LocalFrame* frame,
- const ResourceRequest& req,
- const SubstituteData& substitute_data,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params)
- : frame_(frame),
- fetcher_(FrameFetchContext::CreateFetcherFromDocumentLoader(this)),
- original_request_(req),
- substitute_data_(substitute_data),
- request_(req),
- load_type_(load_type),
- is_client_redirect_(client_redirect_policy ==
- ClientRedirectPolicy::kClientRedirect),
+ : request_(navigation_params->request.ToResourceRequest()),
+ frame_(frame),
+ resource_fetcher_properties_(
+ MakeGarbageCollected<FrameResourceFetcherProperties>(
+ *MakeGarbageCollected<FrameOrImportedDocument>(*this))),
+ fetcher_(FrameFetchContext::CreateFetcher(*resource_fetcher_properties_)),
+ original_url_(request_.Url()),
+ original_referrer_(request_.HttpReferrer()),
+ load_type_(navigation_params->frame_load_type),
+ is_client_redirect_(navigation_params->is_client_redirect),
replaces_current_history_item_(false),
data_received_(false),
navigation_type_(navigation_type),
document_load_timing_(*this),
application_cache_host_(ApplicationCacheHost::Create(this)),
service_worker_network_provider_(
- navigation_params
- ? std::move(navigation_params->service_worker_network_provider)
- : nullptr),
+ std::move(navigation_params->service_worker_network_provider)),
was_blocked_after_csp_(false),
state_(kNotStarted),
committed_data_buffer_(nullptr),
in_data_received_(false),
data_buffer_(SharedBuffer::Create()),
- devtools_navigation_token_(devtools_navigation_token),
- had_sticky_activation_(navigation_params &&
- navigation_params->is_user_activated),
+ devtools_navigation_token_(navigation_params->devtools_navigation_token),
+ had_sticky_activation_(navigation_params->is_user_activated),
had_transient_activation_(request_.HasUserGesture()),
use_counter_(frame_->GetChromeClient().IsSVGImageChromeClient()
? UseCounter::kSVGImageContext
: UseCounter::kDefaultContext) {
DCHECK(frame_);
- WebNavigationTimings timings;
- if (navigation_params)
- timings = navigation_params->navigation_timings;
+ if (!navigation_params->data.IsNull()) {
+ substitute_data_ = SubstituteData(
+ navigation_params->data, navigation_params->mime_type,
+ navigation_params->text_encoding, navigation_params->unreachable_url);
+ }
+ if (!substitute_data_.IsValid() && request_.Url().IsAboutSrcdocURL()) {
+ loading_srcdoc_ = true;
+ // TODO(dgozman): instead of reaching to the owner here, we could instead:
+ // - grab the "srcdoc" value when starting a navigation right in the owner;
+ // - pass it around through BeginNavigation to CommitNavigation as |data|;
+ // - use it here instead of re-reading from the owner.
+ // This way we will get rid of extra dependency between starting and
+ // committing navigation.
+ HTMLFrameOwnerElement* owner_element = frame_->DeprecatedLocalOwner();
+ if (!IsHTMLIFrameElement(owner_element) ||
+ !owner_element->FastHasAttribute(html_names::kSrcdocAttr)) {
+ // Cannot retrieve srcdoc content anymore (perhaps, the attribute was
+ // cleared) - load empty instead.
+ substitute_data_ = SubstituteData(SharedBuffer::Create(), "text/html",
+ "UTF-8", NullURL());
+ } else {
+ String srcdoc = owner_element->FastGetAttribute(html_names::kSrcdocAttr);
+ DCHECK(!srcdoc.IsNull());
+ CString encoded_srcdoc = srcdoc.Utf8();
+ substitute_data_ = SubstituteData(
+ SharedBuffer::Create(encoded_srcdoc.data(), encoded_srcdoc.length()),
+ "text/html", "UTF-8", NullURL());
+ }
+ }
+
+ WebNavigationTimings& timings = navigation_params->navigation_timings;
if (!timings.input_start.is_null())
document_load_timing_.SetInputStart(timings.input_start);
if (timings.navigation_start.is_null()) {
@@ -173,12 +189,6 @@ DocumentLoader::DocumentLoader(
}
}
- if (navigation_params && navigation_params->source_location.has_value()) {
- WebSourceLocation& location = navigation_params->source_location.value();
- source_location_ = SourceLocation::Create(
- location.url, location.line_number, location.column_number, nullptr);
- }
-
// TODO(japhet): This is needed because the browser process DCHECKs if the
// first entry we commit in a new frame has replacement set. It's unclear
// whether the DCHECK is right, investigate removing this special case.
@@ -193,6 +203,11 @@ DocumentLoader::DocumentLoader(
// where the redirects originated.
if (is_client_redirect_)
AppendRedirect(frame_->GetDocument()->Url());
+
+ if (!navigation_params->origin_to_commit.IsNull()) {
+ origin_to_commit_ =
+ navigation_params->origin_to_commit.Get()->IsolatedCopy();
+ }
}
FrameLoader& DocumentLoader::GetFrameLoader() const {
@@ -220,6 +235,7 @@ DocumentLoader::~DocumentLoader() {
void DocumentLoader::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
+ visitor->Trace(resource_fetcher_properties_);
visitor->Trace(fetcher_);
visitor->Trace(history_item_);
visitor->Trace(parser_);
@@ -233,20 +249,19 @@ void DocumentLoader::Trace(blink::Visitor* visitor) {
}
unsigned long DocumentLoader::MainResourceIdentifier() const {
- return GetResource() ? GetResource()->Identifier() : 0;
+ return main_resource_identifier_;
}
ResourceTimingInfo* DocumentLoader::GetNavigationTimingInfo() const {
- DCHECK(Fetcher());
- return Fetcher()->GetNavigationTimingInfo();
+ return navigation_timing_info_.get();
}
-const ResourceRequest& DocumentLoader::OriginalRequest() const {
- return original_request_;
+const KURL& DocumentLoader::OriginalUrl() const {
+ return original_url_;
}
-const ResourceRequest& DocumentLoader::GetRequest() const {
- return request_;
+const AtomicString& DocumentLoader::OriginalReferrer() const {
+ return original_referrer_;
}
void DocumentLoader::SetSubresourceFilter(
@@ -258,65 +273,20 @@ const KURL& DocumentLoader::Url() const {
return request_.Url();
}
-Resource* DocumentLoader::StartPreload(ResourceType type,
- FetchParameters& params) {
- Resource* resource = nullptr;
- switch (type) {
- case ResourceType::kImage:
- resource = ImageResource::Fetch(params, Fetcher());
- break;
- case ResourceType::kScript:
- params.SetRequestContext(mojom::RequestContextType::SCRIPT);
- resource = ScriptResource::Fetch(params, Fetcher(), nullptr,
- ScriptResource::kAllowStreaming);
- break;
- case ResourceType::kCSSStyleSheet:
- resource = CSSStyleSheetResource::Fetch(params, Fetcher(), nullptr);
- break;
- case ResourceType::kFont:
- resource = FontResource::Fetch(params, Fetcher(), nullptr);
- break;
- case ResourceType::kAudio:
- case ResourceType::kVideo:
- resource = RawResource::FetchMedia(params, Fetcher(), nullptr);
- break;
- case ResourceType::kTextTrack:
- resource = RawResource::FetchTextTrack(params, Fetcher(), nullptr);
- break;
- case ResourceType::kImportResource:
- resource = RawResource::FetchImport(params, Fetcher(), nullptr);
- break;
- case ResourceType::kRaw:
- resource = RawResource::Fetch(params, Fetcher(), nullptr);
- break;
- default:
- NOTREACHED();
- }
-
- return resource;
-}
-
void DocumentLoader::SetServiceWorkerNetworkProvider(
std::unique_ptr<WebServiceWorkerNetworkProvider> provider) {
service_worker_network_provider_ = std::move(provider);
}
-void DocumentLoader::ResetSourceLocation() {
- source_location_ = nullptr;
-}
-
-std::unique_ptr<SourceLocation> DocumentLoader::CopySourceLocation() const {
- return source_location_ ? source_location_->Clone() : nullptr;
-}
-
void DocumentLoader::DispatchLinkHeaderPreloads(
ViewportDescriptionWrapper* viewport,
- LinkLoader::MediaPreloadPolicy media_policy) {
+ PreloadHelper::MediaPreloadPolicy media_policy) {
DCHECK_GE(state_, kCommitted);
- LinkLoader::LoadLinksFromHeader(
- GetResponse().HttpHeaderField(http_names::kLink), GetResponse().Url(),
- *frame_, frame_->GetDocument(), NetworkHintsInterfaceImpl(),
- LinkLoader::kOnlyLoadResources, media_policy, viewport);
+ PreloadHelper::LoadLinksFromHeader(
+ GetResponse().HttpHeaderField(http_names::kLink),
+ GetResponse().CurrentRequestUrl(), *frame_, frame_->GetDocument(),
+ NetworkHintsInterfaceImpl(), PreloadHelper::kOnlyLoadResources,
+ media_policy, viewport);
}
void DocumentLoader::DidChangePerformanceTiming() {
@@ -366,7 +336,7 @@ void DocumentLoader::UpdateForSameDocumentNavigation(
}
KURL old_url = request_.Url();
- original_request_.SetURL(new_url);
+ original_url_ = new_url;
request_.SetURL(new_url);
SetReplacesCurrentHistoryItem(type != WebFrameLoadType::kStandard);
if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
@@ -402,6 +372,14 @@ const KURL& DocumentLoader::UrlForHistory() const {
return UnreachableURL().IsEmpty() ? Url() : UnreachableURL();
}
+const AtomicString& DocumentLoader::Referrer() const {
+ return request_.HttpReferrer();
+}
+
+EncodedFormData* DocumentLoader::HttpBody() const {
+ return request_.HttpBody();
+}
+
void DocumentLoader::SetHistoryItemStateForCommit(
HistoryItem* old_item,
WebFrameLoadType load_type,
@@ -413,7 +391,16 @@ void DocumentLoader::SetHistoryItemStateForCommit(
history_item_->SetReferrer(SecurityPolicy::GenerateReferrer(
request_.GetReferrerPolicy(), history_item_->Url(),
request_.HttpReferrer()));
- history_item_->SetFormInfoFromRequest(request_);
+ if (DeprecatedEqualIgnoringCase(request_.HttpMethod(), "POST")) {
+ // FIXME: Eventually we have to make this smart enough to handle the case
+ // where we have a stream for the body to handle the "data interspersed with
+ // files" feature.
+ history_item_->SetFormData(request_.HttpBody());
+ history_item_->SetFormContentType(request_.HttpContentType());
+ } else {
+ history_item_->SetFormData(nullptr);
+ history_item_->SetFormContentType(g_null_atom);
+ }
// Don't propagate state from the old item to the new item if there isn't an
// old item (obviously), or if this is a back/forward navigation, since we
@@ -452,17 +439,32 @@ void DocumentLoader::NotifyFinished(Resource* resource) {
DCHECK(GetResource());
if (!resource->ErrorOccurred() && !resource->WasCanceled()) {
+ const ResourceResponse& response = resource->GetResponse();
+ if (response.IsHTTP()) {
+ navigation_timing_info_->SetFinalResponse(response);
+ const int64_t encoded_data_length = response.EncodedDataLength();
+ navigation_timing_info_->AddFinalTransferSize(
+ encoded_data_length == -1 ? 0 : encoded_data_length);
+ if (response.HttpStatusCode() < 400 && report_timing_info_to_parent_) {
+ navigation_timing_info_->SetLoadFinishTime(resource->LoadFinishTime());
+ if (state_ >= kCommitted) {
+ // Note that we currently lose timing info for empty documents,
+ // which will be fixed with synchronous commit.
+ // Main resource timing information is reported through the owner
+ // to be passed to the parent frame, if appropriate.
+ frame_->Owner()->AddResourceTiming(*navigation_timing_info_);
+ }
+ frame_->SetShouldSendResourceTimingInfoToParent(false);
+ }
+ }
FinishedLoading(resource->LoadFinishTime());
return;
}
- if (application_cache_host_)
- application_cache_host_->FailedLoadingMainResource();
-
if (resource->GetResourceError().WasBlockedByResponse()) {
- probe::didReceiveResourceResponse(frame_->GetDocument(),
- MainResourceIdentifier(), this,
- resource->GetResponse(), resource);
+ probe::didReceiveResourceResponse(
+ probe::ToCoreProbeSink(frame_->GetDocument()), MainResourceIdentifier(),
+ this, resource->GetResponse(), resource);
}
LoadFailed(resource->GetResourceError());
@@ -472,7 +474,6 @@ void DocumentLoader::NotifyFinished(Resource* resource) {
void DocumentLoader::LoadFailed(const ResourceError& error) {
if (!error.IsCancellation() && frame_->Owner())
frame_->Owner()->RenderFallbackContent(frame_);
- fetcher_->ClearResourcesFromPreviousFetcher();
WebHistoryCommitType history_commit_type = LoadTypeToCommitType(load_type_);
switch (state_) {
@@ -513,6 +514,13 @@ void DocumentLoader::FinishedLoading(TimeTicks finish_time) {
!frame_->GetPage()->Paused() ||
MainThreadDebugger::Instance()->IsPaused());
+ if (listing_ftp_directory_) {
+ scoped_refptr<SharedBuffer> buffer = GenerateFtpDirectoryListingHtml(
+ response_.CurrentRequestUrl(), data_buffer_.get());
+ for (const auto& span : *buffer)
+ CommitData(span.data(), span.size());
+ }
+
TimeTicks response_end_time = finish_time;
if (response_end_time.is_null())
response_end_time = time_of_last_data_received_;
@@ -520,16 +528,16 @@ void DocumentLoader::FinishedLoading(TimeTicks finish_time) {
response_end_time = CurrentTimeTicks();
GetTiming().SetResponseEnd(response_end_time);
if (!MaybeCreateArchive()) {
- // If this is an empty document, it will not have actually been created yet.
- // Force a commit so that the Document actually gets created.
+ // If this is an empty document, it might not have actually been
+ // committed yet. Force a commit so that the Document actually gets created.
if (state_ == kProvisional)
- CommitData(nullptr, 0);
+ CommitNavigation(response_.MimeType());
}
+ DCHECK_GE(state_, kCommitted);
if (!frame_)
return;
- application_cache_host_->FinishedLoadingMainResource();
if (parser_) {
if (parser_blocked_count_) {
finished_loading_ = true;
@@ -549,23 +557,17 @@ bool DocumentLoader::RedirectReceived(
DCHECK_EQ(resource, GetResource());
DCHECK(!redirect_response.IsNull());
request_ = request;
-
- // If the redirecting url is not allowed to display content from the target
- // origin, then block the redirect.
const KURL& request_url = request_.Url();
- scoped_refptr<const SecurityOrigin> redirecting_origin =
- SecurityOrigin::Create(redirect_response.Url());
- if (!redirecting_origin->CanDisplay(request_url)) {
- frame_->Console().AddMessage(ConsoleMessage::Create(
- kSecurityMessageSource, kErrorMessageLevel,
- "Not allowed to load local resource: " + request_url.GetString()));
- fetcher_->StopFetching();
- return false;
- }
+ navigation_timing_info_->AddRedirect(redirect_response, request_url);
+
+ // Browser process should have already checked that redirecting url is
+ // allowed to display content from the target origin.
+ CHECK(SecurityOrigin::Create(redirect_response.CurrentRequestUrl())
+ ->CanDisplay(request_url));
DCHECK(!GetTiming().FetchStart().is_null());
AppendRedirect(request_url);
- GetTiming().AddRedirect(redirect_response.Url(), request_url);
+ GetTiming().AddRedirect(redirect_response.CurrentRequestUrl(), request_url);
// If a redirection happens during a back/forward navigation, don't restore
// any state from the old HistoryItem. There is a provisional history item for
@@ -608,11 +610,31 @@ bool DocumentLoader::ShouldContinueForResponse() const {
return true;
}
+bool DocumentLoader::ShouldReportTimingInfoToParent() {
+ DCHECK(frame_);
+ // <iframe>s should report the initial navigation requested by the parent
+ // document, but not subsequent navigations.
+ if (!frame_->Owner())
+ return false;
+ // Note that this can be racy since this information is forwarded over IPC
+ // when crossing process boundaries.
+ if (!frame_->should_send_resource_timing_info_to_parent())
+ return false;
+ // Do not report iframe navigation that restored from history, since its
+ // location may have been changed after initial navigation,
+ if (load_type_ == WebFrameLoadType::kBackForward) {
+ // ...and do not report subsequent navigations in the iframe too.
+ frame_->SetShouldSendResourceTimingInfoToParent(false);
+ return false;
+ }
+ return true;
+}
+
void DocumentLoader::CancelLoadAfterCSPDenied(
const ResourceResponse& response) {
- probe::didReceiveResourceResponse(frame_->GetDocument(),
- MainResourceIdentifier(), this, response,
- GetResource());
+ probe::didReceiveResourceResponse(
+ probe::ToCoreProbeSink(frame_->GetDocument()), MainResourceIdentifier(),
+ this, response, GetResource());
SetWasBlockedAfterCSP();
@@ -624,7 +646,7 @@ void DocumentLoader::CancelLoadAfterCSPDenied(
ClearResource();
content_security_policy_.Clear();
KURL blocked_url = SecurityOrigin::UrlWithUniqueOpaqueOrigin();
- original_request_.SetURL(blocked_url);
+ original_url_ = blocked_url;
request_.SetURL(blocked_url);
redirect_chain_.pop_back();
AppendRedirect(blocked_url);
@@ -653,7 +675,7 @@ void DocumentLoader::ResponseReceived(
GetMemoryCache()->Remove(resource);
content_security_policy_ = ContentSecurityPolicy::Create();
- content_security_policy_->SetOverrideURLForSelf(response.Url());
+ content_security_policy_->SetOverrideURLForSelf(response.CurrentRequestUrl());
AtomicString mixed_content_header = response.HttpHeaderField("mixed-content");
if (EqualIgnoringASCIICase(mixed_content_header, "noupgrade")) {
@@ -681,7 +703,8 @@ void DocumentLoader::ResponseReceived(
}
}
}
- if (!content_security_policy_->AllowAncestors(frame_, response.Url())) {
+ if (!content_security_policy_->AllowAncestors(frame_,
+ response.CurrentRequestUrl())) {
CancelLoadAfterCSPDenied(response);
return;
}
@@ -704,13 +727,13 @@ void DocumentLoader::ResponseReceived(
kContentSecurityPolicyHeaderSourceHTTP);
if (!required_csp->Subsumes(*content_security_policy_)) {
String message = "Refused to display '" +
- response.Url().ElidedString() +
+ response.CurrentRequestUrl().ElidedString() +
"' because it has not opted-into the following policy "
"required by its embedder: '" +
GetFrameLoader().RequiredCSP() + "'.";
ConsoleMessage* console_message = ConsoleMessage::CreateForRequest(
- kSecurityMessageSource, kErrorMessageLevel, message, response.Url(),
- this, MainResourceIdentifier());
+ kSecurityMessageSource, kErrorMessageLevel, message,
+ response.CurrentRequestUrl(), this, MainResourceIdentifier());
frame_->GetDocument()->AddConsoleMessage(console_message);
CancelLoadAfterCSPDenied(response);
return;
@@ -727,14 +750,28 @@ void DocumentLoader::ResponseReceived(
response_ = response;
- if (IsArchiveMIMEType(response_.MimeType()) &&
- resource->GetDataBufferingPolicy() != kBufferData)
- resource->SetDataBufferingPolicy(kBufferData);
+ if (response.CurrentRequestUrl().ProtocolIs("ftp") &&
+ response.MimeType() == "text/vnd.chromium.ftp-dir") {
+ if (response.CurrentRequestUrl().Query() == "raw") {
+ // Interpret the FTP LIST command result as text.
+ response_.SetMimeType("text/plain");
+ } else {
+ // FTP directory listing: Make up an HTML for the entries.
+ listing_ftp_directory_ = true;
+ response_.SetMimeType("text/html");
+ }
+ }
+
+ // The MHTML mime type should be same as the one we check in the browser
+ // process's IsDownload (navigation_url_loader_network_service.cc).
+ loading_mhtml_archive_ =
+ DeprecatedEqualIgnoringCase("multipart/related", response_.MimeType()) ||
+ DeprecatedEqualIgnoringCase("message/rfc822", response_.MimeType());
if (!ShouldContinueForResponse()) {
- probe::didReceiveResourceResponse(frame_->GetDocument(),
- resource->Identifier(), this, response_,
- resource);
+ probe::didReceiveResourceResponse(
+ probe::ToCoreProbeSink(frame_->GetDocument()), resource->Identifier(),
+ this, response_, resource);
fetcher_->StopFetching();
return;
}
@@ -768,14 +805,19 @@ void DocumentLoader::CommitNavigation(const AtomicString& mime_type,
// Prepare a DocumentInit before clearing the frame, because it may need to
// inherit an aliased security context.
Document* owner_document = nullptr;
+ scoped_refptr<const SecurityOrigin> initiator_origin =
+ request_.RequestorOrigin();
+
// TODO(dcheng): This differs from the behavior of both IE and Firefox: the
// origin is inherited from the document that loaded the URL.
if (Document::ShouldInheritSecurityOriginFromOwner(Url())) {
Frame* owner_frame = frame_->Tree().Parent();
if (!owner_frame)
owner_frame = frame_->Loader().Opener();
- if (owner_frame && owner_frame->IsLocalFrame())
+ if (owner_frame && owner_frame->IsLocalFrame()) {
owner_document = ToLocalFrame(owner_frame)->GetDocument();
+ initiator_origin = owner_document->GetSecurityOrigin();
+ }
}
DCHECK(frame_->GetPage());
@@ -784,7 +826,7 @@ void DocumentLoader::CommitNavigation(const AtomicString& mime_type,
parsing_policy = kForceSynchronousParsing;
InstallNewDocument(
- Url(), owner_document,
+ Url(), initiator_origin, owner_document,
frame_->ShouldReuseDefaultView(Url(), GetContentSecurityPolicy())
? WebGlobalObjectReusePolicy::kUseExisting
: WebGlobalObjectReusePolicy::kCreateNew,
@@ -797,6 +839,12 @@ void DocumentLoader::CommitNavigation(const AtomicString& mime_type,
response_.HttpHeaderField(http_names::kRefresh),
Document::kHttpRefreshFromHeader);
ReportPreviewsIntervention();
+
+ // If we did commit MediaDocument, we should stop here.
+ if (frame_ && frame_->GetDocument()->IsMediaDocument()) {
+ parser_->Finish();
+ fetcher_->StopFetching();
+ }
}
void DocumentLoader::CommitData(const char* bytes, size_t length) {
@@ -828,6 +876,12 @@ void DocumentLoader::DataReceived(Resource* resource,
DCHECK_EQ(resource, GetResource());
DCHECK(!response_.IsNull());
DCHECK(!frame_->GetPage()->Paused());
+ time_of_last_data_received_ = CurrentTimeTicks();
+
+ if (listing_ftp_directory_ || loading_mhtml_archive_) {
+ data_buffer_->Append(data, length);
+ return;
+ }
if (in_data_received_) {
// If this function is reentered, defer processing of the additional data to
@@ -841,34 +895,20 @@ void DocumentLoader::DataReceived(Resource* resource,
}
base::AutoReset<bool> reentrancy_protector(&in_data_received_, true);
- ProcessData(data, length);
+ CommitData(data, length);
ProcessDataBuffer();
}
void DocumentLoader::ProcessDataBuffer() {
// Process data received in reentrant invocations. Note that the invocations
- // of processData() may queue more data in reentrant invocations, so iterate
+ // of CommitData() may queue more data in reentrant invocations, so iterate
// until it's empty.
for (const auto& span : *data_buffer_)
- ProcessData(span.data(), span.size());
+ CommitData(span.data(), span.size());
// All data has been consumed, so flush the buffer.
data_buffer_->Clear();
}
-void DocumentLoader::ProcessData(const char* data, size_t length) {
- application_cache_host_->MainResourceDataReceived(data, length);
- time_of_last_data_received_ = CurrentTimeTicks();
-
- if (IsArchiveMIMEType(GetResponse().MimeType()))
- return;
- CommitData(data, length);
-
- // If we are sending data to MediaDocument, we should stop here and cancel the
- // request.
- if (frame_ && frame_->GetDocument()->IsMediaDocument())
- fetcher_->StopFetching();
-}
-
void DocumentLoader::ClearRedirectChain() {
redirect_chain_.clear();
}
@@ -883,6 +923,12 @@ void DocumentLoader::StopLoading() {
LoadFailed(ResourceError::CancelledError(Url()));
}
+void DocumentLoader::SetDefersLoading(bool defers) {
+ // TODO(dgozman): defer body loader once we don't use Fetcher()
+ // for the main resource.
+ Fetcher()->SetDefersLoading(defers);
+}
+
void DocumentLoader::DetachFromFrame(bool flush_microtask_queue) {
DCHECK(frame_);
StopLoading();
@@ -917,15 +963,15 @@ void DocumentLoader::DetachFromFrame(bool flush_microtask_queue) {
}
bool DocumentLoader::MaybeCreateArchive() {
- // Give the archive machinery a crack at this document. If the MIME type is
- // not an archive type, it will return 0.
- if (!IsArchiveMIMEType(response_.MimeType()))
+ // Give the archive machinery a crack at this document.
+ if (!loading_mhtml_archive_)
return false;
- DCHECK(GetResource());
- ArchiveResource* main_resource = fetcher_->CreateArchive(GetResource());
+ ArchiveResource* main_resource = fetcher_->CreateArchive(Url(), data_buffer_);
if (!main_resource)
return false;
+
+ data_buffer_ = nullptr;
// The origin is the MHTML file, we need to set the base URL to the document
// encoded in the MHTML so relative URLs are resolved properly.
CommitNavigation(main_resource->MimeType(), main_resource->Url());
@@ -942,12 +988,22 @@ const KURL& DocumentLoader::UnreachableURL() const {
return substitute_data_.FailingURL();
}
+bool DocumentLoader::WillLoadUrlAsEmpty(const KURL& url) {
+ if (url.IsEmpty())
+ return true;
+ // Usually, we load urls with about: scheme as empty.
+ // However, about:srcdoc is only used as a marker for non-existent
+ // url of iframes with srcdoc attribute, which have possibly non-empty
+ // content of the srcdoc attribute used as document's html.
+ if (url.IsAboutSrcdocURL())
+ return false;
+ return SchemeRegistry::ShouldLoadURLSchemeAsEmptyDocument(url.Protocol());
+}
+
bool DocumentLoader::MaybeLoadEmpty() {
- bool should_load_empty = !substitute_data_.IsValid() &&
- (request_.Url().IsEmpty() ||
- SchemeRegistry::ShouldLoadURLSchemeAsEmptyDocument(
- request_.Url().Protocol()));
- if (!should_load_empty)
+ if (substitute_data_.IsValid())
+ return false;
+ if (!WillLoadUrlAsEmpty(request_.Url()))
return false;
if (request_.Url().IsEmpty() &&
@@ -966,33 +1022,46 @@ void DocumentLoader::StartLoading() {
DCHECK_EQ(state_, kNotStarted);
state_ = kProvisional;
- if (MaybeLoadEmpty())
- return;
-
- DCHECK(!GetTiming().NavigationStart().is_null());
- // The fetch has already started in the browser,
- // so we don't MarkFetchStart here.
-
- ResourceLoaderOptions options;
- options.data_buffering_policy = kDoNotBufferData;
- options.initiator_info.name = fetch_initiator_type_names::kDocument;
- FetchParameters fetch_params(request_, options);
- RawResource::FetchMainResource(fetch_params, Fetcher(), this,
- substitute_data_);
- // A bunch of headers are set when the underlying resource load begins, and
- // request_ needs to include those. Even when using a cached resource, we may
- // make some modification to the request, e.g. adding the referer header.
- request_ = GetResource()->IsLoading() ? GetResource()->GetResourceRequest()
- : fetch_params.GetResourceRequest();
+ if (!MaybeLoadEmpty()) {
+ DCHECK(!GetTiming().NavigationStart().is_null());
+ // The fetch has already started in the browser,
+ // so we don't MarkFetchStart here.
+
+ main_resource_identifier_ = CreateUniqueIdentifier();
+
+ // This buffer is created and populated for providing transferSize
+ // and redirect timing opt-in information.
+ navigation_timing_info_ = ResourceTimingInfo::Create(
+ fetch_initiator_type_names::kDocument, GetTiming().NavigationStart(),
+ true /* is_main_resource */);
+ navigation_timing_info_->SetInitialURL(request_.Url());
+ report_timing_info_to_parent_ = ShouldReportTimingInfoToParent();
+
+ ResourceLoaderOptions options;
+ options.data_buffering_policy = kDoNotBufferData;
+ options.initiator_info.name = fetch_initiator_type_names::kDocument;
+ FetchParameters fetch_params(request_, options);
+ RawResource::FetchMainResource(fetch_params, Fetcher(), this,
+ substitute_data_, main_resource_identifier_);
+ // A bunch of headers are set when the underlying resource load begins, and
+ // request_ needs to include those. Even when using a cached resource, we
+ // may make some modification to the request, e.g. adding the referer
+ // header.
+ request_ = GetResource()->IsLoading() ? GetResource()->GetResourceRequest()
+ : fetch_params.GetResourceRequest();
+ base::OnceClosure continue_navigation =
+ GetResource()->TakeContinueNavigationRequestCallback();
+ if (continue_navigation)
+ std::move(continue_navigation).Run();
+ }
}
-void DocumentLoader::DidInstallNewDocument(
- Document* document,
- const ContentSecurityPolicy* previous_csp) {
+void DocumentLoader::DidInstallNewDocument(Document* document) {
document->SetReadyState(Document::kLoading);
if (content_security_policy_) {
- document->InitContentSecurityPolicy(content_security_policy_.Release(),
- nullptr, previous_csp);
+ document->InitContentSecurityPolicy(
+ content_security_policy_.Release(),
+ GetFrameLoader().GetLastOriginDocumentCSP());
}
if (history_item_ && IsBackForwardLoadType(load_type_))
@@ -1101,7 +1170,7 @@ void DocumentLoader::DidCommitNavigation(
// Links with media values need more information (like viewport information).
// This happens after the first chunk is parsed in HTMLDocumentParser.
- DispatchLinkHeaderPreloads(nullptr, LinkLoader::kOnlyLoadNonMedia);
+ DispatchLinkHeaderPreloads(nullptr, PreloadHelper::kOnlyLoadNonMedia);
frame_->GetPage()->DidCommitLoad(frame_);
GetUseCounter().DidCommitLoad(frame_);
@@ -1113,8 +1182,8 @@ void DocumentLoader::DidCommitNavigation(
this, frame_->Tree().Parent()
? WebFeature::kLegacySymantecCertInSubframeMainResource
: WebFeature::kLegacySymantecCertMainFrameResource);
- GetLocalFrameClient().ReportLegacySymantecCert(response_.Url(),
- false /* did_fail */);
+ GetLocalFrameClient().ReportLegacySymantecCert(
+ response_.CurrentRequestUrl(), false /* did_fail */);
}
if (response_.IsLegacyTLSVersion()) {
@@ -1122,7 +1191,11 @@ void DocumentLoader::DidCommitNavigation(
frame_->Tree().Parent()
? WebFeature::kLegacyTLSVersionInSubframeMainResource
: WebFeature::kLegacyTLSVersionInMainFrameResource);
- GetLocalFrameClient().ReportLegacyTLSVersion(response_.Url());
+ GetLocalFrameClient().ReportLegacyTLSVersion(response_.CurrentRequestUrl());
+ if (!frame_->Tree().Parent()) {
+ ukm::builders::Net_LegacyTLSVersion(document->UkmSourceID())
+ .Record(document->UkmRecorder());
+ }
}
}
@@ -1167,6 +1240,7 @@ void MergeFeaturesFromOriginPolicy(WTF::String& feature_policy,
void DocumentLoader::InstallNewDocument(
const KURL& url,
+ const scoped_refptr<const SecurityOrigin> initiator_origin,
Document* owner_document,
WebGlobalObjectReusePolicy global_object_reuse_policy,
const AtomicString& mime_type,
@@ -1182,10 +1256,8 @@ void DocumentLoader::InstallNewDocument(
}
const SecurityOrigin* previous_security_origin = nullptr;
- const ContentSecurityPolicy* previous_csp = nullptr;
if (frame_->GetDocument()) {
previous_security_origin = frame_->GetDocument()->GetSecurityOrigin();
- previous_csp = frame_->GetDocument()->GetContentSecurityPolicy();
}
// In some rare cases, we'll re-use a LocalDOMWindow for a new Document. For
@@ -1208,8 +1280,10 @@ void DocumentLoader::InstallNewDocument(
.WithDocumentLoader(this)
.WithURL(url)
.WithOwnerDocument(owner_document)
- .WithNewRegistrationContext()
- .WithPreviousDocumentCSP(previous_csp),
+ .WithInitiatorOrigin(initiator_origin)
+ .WithOriginToCommit(origin_to_commit_)
+ .WithSrcdocDocument(loading_srcdoc_)
+ .WithNewRegistrationContext(),
false);
// Clear the user activation state.
@@ -1239,13 +1313,26 @@ void DocumentLoader::InstallNewDocument(
if (!overriding_url.IsEmpty())
document->SetBaseURLOverride(overriding_url);
- DidInstallNewDocument(document, previous_csp);
+ DidInstallNewDocument(document);
// This must be called before the document is opened, otherwise HTML parser
// will use stale values from HTMLParserOption.
if (reason == InstallNewDocumentReason::kNavigation)
DidCommitNavigation(global_object_reuse_policy);
+ // TODO(yoichio): This is temporary switch to support chrome internal
+ // components migration from the old web APIs.
+ // After completion of the migration, we should remove this.
+ // See crbug.com/911943 for detail.
+ if (url.Protocol() == "chrome-devtools" || url.Protocol() == "chrome") {
+ OriginTrialContext::FromOrCreate(document)->AddFeature("WebComponentsV0");
+ // CrElementsProfileAvatarSelectorFocusTest, or some Web UI tests need this
+ // RuntimeEnabledFeatures on in addition to the above OriginTrialContext
+ // flag.
+ RuntimeEnabledFeatures::SetShadowDOMV0Enabled(true);
+ RuntimeEnabledFeatures::SetCustomElementsV0Enabled(true);
+ RuntimeEnabledFeatures::SetHTMLImportsEnabled(true);
+ }
// Initializing origin trials might force window proxy initialization,
// which later triggers CHECK when swapping in via WebFrame::Swap().
// We can safely omit installing original trials on initial empty document
@@ -1287,6 +1374,11 @@ void DocumentLoader::InstallNewDocument(
MergeFeaturesFromOriginPolicy(feature_policy, request_.GetOriginPolicy());
document->ApplyFeaturePolicyFromHeader(feature_policy);
+ WTF::String report_only_feature_policy(
+ response_.HttpHeaderField(http_names::kFeaturePolicyReportOnly));
+ // TODO(iclelland): Add Feature-Policy-Report-Only to Origin Policy.
+ document->ApplyReportOnlyFeaturePolicyFromHeader(report_only_feature_policy);
+
GetFrameLoader().DispatchDidClearDocumentOfWindowObject();
}
@@ -1303,7 +1395,7 @@ void DocumentLoader::ReplaceDocumentWhileExecutingJavaScriptURL(
Document* owner_document,
WebGlobalObjectReusePolicy global_object_reuse_policy,
const String& source) {
- InstallNewDocument(url, owner_document, global_object_reuse_policy,
+ InstallNewDocument(url, nullptr, owner_document, global_object_reuse_policy,
MimeType(), response_.TextEncodingName(),
InstallNewDocumentReason::kJavascriptURL,
kForceSynchronousParsing, NullURL());
@@ -1350,6 +1442,11 @@ void DocumentLoader::ResumeParser() {
}
}
+void DocumentLoader::ProvideDocumentToResourceFetcherProperties(
+ Document& document) {
+ resource_fetcher_properties_->UpdateDocument(document);
+}
+
void DocumentLoader::ReportPreviewsIntervention() const {
// Only send reports for main frames.
if (!frame_->IsMainFrame())
diff --git a/chromium/third_party/blink/renderer/core/loader/document_loader.h b/chromium/third_party/blink/renderer/core/loader/document_loader.h
index 5589b3963dc..16bcd737f3c 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/document_loader.h
@@ -42,13 +42,14 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/weak_identifier_map.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/dactyloscoper.h"
#include "third_party/blink/renderer/core/frame/frame_types.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h"
#include "third_party/blink/renderer/core/loader/document_load_timing.h"
#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
-#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/renderer/core/loader/navigation_policy.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
@@ -68,6 +69,7 @@ class ApplicationCacheHost;
class Document;
class DocumentParser;
class FrameLoader;
+class FrameResourceFetcherProperties;
class HistoryItem;
class LocalFrame;
class LocalFrameClient;
@@ -86,15 +88,12 @@ class CORE_EXPORT DocumentLoader
public:
DocumentLoader(LocalFrame*,
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params);
~DocumentLoader() override;
+ static bool WillLoadUrlAsEmpty(const KURL&);
+
LocalFrame* GetFrame() const { return frame_; }
ResourceTimingInfo* GetNavigationTimingInfo() const;
@@ -110,9 +109,8 @@ class CORE_EXPORT DocumentLoader
const AtomicString& MimeType() const;
- const ResourceRequest& OriginalRequest() const;
-
- const ResourceRequest& GetRequest() const;
+ const KURL& OriginalUrl() const;
+ const AtomicString& OriginalReferrer() const;
ResourceFetcher* Fetcher() const { return fetcher_.Get(); }
@@ -133,6 +131,8 @@ class CORE_EXPORT DocumentLoader
const KURL& Url() const;
const KURL& UnreachableURL() const;
const KURL& UrlForHistory() const;
+ const AtomicString& Referrer() const;
+ EncodedFormData* HttpBody() const;
void DidChangePerformanceTiming();
void DidObserveLoadingBehavior(WebLoadingBehaviorFlag);
@@ -181,6 +181,7 @@ class CORE_EXPORT DocumentLoader
void StartLoading();
void StopLoading();
+ void SetDefersLoading(bool defers);
DocumentLoadTiming& GetTiming() { return document_load_timing_; }
const DocumentLoadTiming& GetTiming() const { return document_load_timing_; }
@@ -210,9 +211,7 @@ class CORE_EXPORT DocumentLoader
bool WasBlockedAfterCSP() { return was_blocked_after_csp_; }
void DispatchLinkHeaderPreloads(ViewportDescriptionWrapper*,
- LinkLoader::MediaPreloadPolicy);
-
- Resource* StartPreload(ResourceType, FetchParameters&);
+ PreloadHelper::MediaPreloadPolicy);
void SetServiceWorkerNetworkProvider(
std::unique_ptr<WebServiceWorkerNetworkProvider>);
@@ -224,10 +223,6 @@ class CORE_EXPORT DocumentLoader
return service_worker_network_provider_.get();
}
- // Allows to specify the SourceLocation that triggered the navigation.
- void ResetSourceLocation();
- std::unique_ptr<SourceLocation> CopySourceLocation() const;
-
void LoadFailed(const ResourceError&);
void SetUserActivated();
@@ -263,7 +258,12 @@ class CORE_EXPORT DocumentLoader
return content_security_policy_.Get();
}
+ bool IsListingFtpDirectory() const { return listing_ftp_directory_; }
+
UseCounter& GetUseCounter() { return use_counter_; }
+ Dactyloscoper& GetDactyloscoper() { return dactyloscoper_; }
+
+ void ProvideDocumentToResourceFetcherProperties(Document&);
protected:
static bool ShouldClearWindowName(
@@ -275,21 +275,28 @@ class CORE_EXPORT DocumentLoader
Vector<KURL> redirect_chain_;
+ // The 'working' request. It may be mutated
+ // several times from the original request to include additional
+ // headers, cookie information, canonicalization and redirects.
+ ResourceRequest request_;
+
private:
// installNewDocument() does the work of creating a Document and
// DocumentParser, as well as creating a new LocalDOMWindow if needed. It also
// initalizes a bunch of state on the Document (e.g., the state based on
// response headers).
enum class InstallNewDocumentReason { kNavigation, kJavascriptURL };
- void InstallNewDocument(const KURL&,
- Document* owner_document,
- WebGlobalObjectReusePolicy,
- const AtomicString& mime_type,
- const AtomicString& encoding,
- InstallNewDocumentReason,
- ParserSynchronizationPolicy,
- const KURL& overriding_url);
- void DidInstallNewDocument(Document*, const ContentSecurityPolicy*);
+ void InstallNewDocument(
+ const KURL&,
+ const scoped_refptr<const SecurityOrigin> initiator_origin,
+ Document* owner_document,
+ WebGlobalObjectReusePolicy,
+ const AtomicString& mime_type,
+ const AtomicString& encoding,
+ InstallNewDocumentReason,
+ ParserSynchronizationPolicy,
+ const KURL& overriding_url);
+ void DidInstallNewDocument(Document*);
void WillCommitNavigation();
void DidCommitNavigation(WebGlobalObjectReusePolicy);
@@ -330,13 +337,12 @@ class CORE_EXPORT DocumentLoader
void NotifyFinished(Resource*) final;
String DebugName() const override { return "DocumentLoader"; }
- void ProcessData(const char* data, size_t length);
-
bool MaybeLoadEmpty();
bool IsRedirectAfterPost(const ResourceRequest&, const ResourceResponse&);
bool ShouldContinueForResponse() const;
+ bool ShouldReportTimingInfoToParent();
// Processes the data stored in the data_buffer_, used to avoid appending data
// to the parser in a nested message loop.
@@ -346,6 +352,10 @@ class CORE_EXPORT DocumentLoader
void ReportPreviewsIntervention() const;
Member<LocalFrame> frame_;
+ // This member is held so that we can update the document later. Do not use
+ // this member outside ProvideDocumentToResourceFetcherProperties.
+ // TODO(yhirano): Remove this once https://crbug.com/855189 is done.
+ const Member<FrameResourceFetcherProperties> resource_fetcher_properties_;
Member<ResourceFetcher> fetcher_;
Member<HistoryItem> history_item_;
@@ -360,17 +370,12 @@ class CORE_EXPORT DocumentLoader
// Stores the resource loading hints for this document.
Member<PreviewsResourceLoadingHints> resource_loading_hints_;
- // A reference to actual request used to create the data source.
- // The only part of this request that should change is the url, and
- // that only in the case of a same-document navigation.
- ResourceRequest original_request_;
-
SubstituteData substitute_data_;
- // The 'working' request. It may be mutated
- // several times from the original request to include additional
- // headers, cookie information, canonicalization and redirects.
- ResourceRequest request_;
+ // A reference to actual request's url and referrer used to
+ // inititate this load.
+ KURL original_url_;
+ AtomicString original_referrer_;
ResourceResponse response_;
@@ -381,6 +386,7 @@ class CORE_EXPORT DocumentLoader
bool data_received_;
WebNavigationType navigation_type_;
+ scoped_refptr<SecurityOrigin> origin_to_commit_;
DocumentLoadTiming document_load_timing_;
@@ -397,11 +403,6 @@ class CORE_EXPORT DocumentLoader
bool was_blocked_after_csp_;
- // PlzNavigate: set when committing a navigation. The data has originally been
- // captured when the navigation was sent to the browser process, and it is
- // sent back at commit time.
- std::unique_ptr<SourceLocation> source_location_;
-
enum State { kNotStarted, kProvisional, kCommitted, kSentDidFinishLoad };
State state_;
@@ -420,12 +421,21 @@ class CORE_EXPORT DocumentLoader
// Whether this load request had a user activation when created.
bool had_transient_activation_;
+ bool listing_ftp_directory_ = false;
+ bool loading_mhtml_archive_ = false;
+ bool loading_srcdoc_ = false;
+ unsigned long main_resource_identifier_ = 0;
+ scoped_refptr<ResourceTimingInfo> navigation_timing_info_;
+ bool report_timing_info_to_parent_ = false;
+
// This UseCounter tracks feature usage associated with the lifetime of the
// document load. Features recorded prior to commit will be recorded locally.
// Once commited, feature usage will be piped to the browser side page load
// metrics that aggregates usage from frames to one page load and report
// feature usage to UMA histograms per page load.
UseCounter use_counter_;
+
+ Dactyloscoper dactyloscoper_;
};
DECLARE_WEAK_IDENTIFIER_MAP(DocumentLoader);
diff --git a/chromium/third_party/blink/renderer/core/loader/empty_clients.cc b/chromium/third_party/blink/renderer/core/loader/empty_clients.cc
index 87915944910..56657195998 100644
--- a/chromium/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/chromium/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -109,26 +109,25 @@ void EmptyLocalFrameClient::BeginNavigation(
mojom::blink::BlobURLTokenPtr,
base::TimeTicks,
const String&,
+ WebContentSecurityPolicyList,
mojom::blink::NavigationInitiatorPtr) {}
void EmptyLocalFrameClient::DispatchWillSendSubmitEvent(HTMLFormElement*) {}
DocumentLoader* EmptyLocalFrameClient::CreateDocumentLoader(
LocalFrame* frame,
- const ResourceRequest& request,
- const SubstituteData& substitute_data,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DCHECK(frame);
+ return MakeGarbageCollected<DocumentLoader>(frame, navigation_type,
+ std::move(navigation_params));
+}
- return MakeGarbageCollected<DocumentLoader>(
- frame, request, substitute_data, client_redirect_policy,
- devtools_navigation_token, load_type, navigation_type,
- std::move(navigation_params));
+mojom::blink::DocumentInterfaceBroker*
+EmptyLocalFrameClient::GetDocumentInterfaceBroker() {
+ mojo::MakeRequest(&document_interface_broker_);
+ return document_interface_broker_.get();
}
LocalFrame* EmptyLocalFrameClient::CreateFrame(const AtomicString&,
@@ -136,6 +135,13 @@ LocalFrame* EmptyLocalFrameClient::CreateFrame(const AtomicString&,
return nullptr;
}
+std::pair<RemoteFrame*, base::UnguessableToken>
+EmptyLocalFrameClient::CreatePortal(HTMLPortalElement*,
+ mojom::blink::PortalRequest) {
+ return std::pair<RemoteFrame*, base::UnguessableToken>(
+ nullptr, base::UnguessableToken());
+}
+
WebPluginContainerImpl* EmptyLocalFrameClient::CreatePlugin(
HTMLPlugInElement&,
const KURL&,
diff --git a/chromium/third_party/blink/renderer/core/loader/empty_clients.h b/chromium/third_party/blink/renderer/core/loader/empty_clients.h
index a0592da644f..55bde22d269 100644
--- a/chromium/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/chromium/third_party/blink/renderer/core/loader/empty_clients.h
@@ -34,6 +34,7 @@
#include "base/macros.h"
#include "cc/paint/paint_canvas.h"
#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_focus_type.h"
#include "third_party/blink/public/platform/web_menu_source_type.h"
@@ -208,6 +209,7 @@ class CORE_EXPORT EmptyChromeClient : public ChromeClient {
}
void SetHasScrollEventHandlers(LocalFrame*, bool) override {}
void SetNeedsLowLatencyInput(LocalFrame*, bool) override {}
+ void SetNeedsUnbufferedInputForDebugger(LocalFrame*, bool) override {}
void RequestUnbufferedInputEvents(LocalFrame*) override {}
void SetTouchAction(LocalFrame*, TouchAction) override {}
@@ -256,8 +258,7 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
void DispatchDidHandleOnloadEvents() override {}
void DispatchWillCommitProvisionalLoad() override {}
- void DispatchDidStartProvisionalLoad(DocumentLoader*,
- const ResourceRequest&) override {}
+ void DispatchDidStartProvisionalLoad(DocumentLoader*) override {}
void DispatchDidReceiveTitle(const String&) override {}
void DispatchDidChangeIcons(IconType) override {}
void DispatchDidCommitLoad(HistoryItem*,
@@ -285,6 +286,7 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
mojom::blink::BlobURLTokenPtr,
base::TimeTicks,
const String&,
+ WebContentSecurityPolicyList,
mojom::blink::NavigationInitiatorPtr) override;
void DispatchWillSendSubmitEvent(HTMLFormElement*) override;
@@ -301,11 +303,6 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
DocumentLoader* CreateDocumentLoader(
LocalFrame*,
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType,
WebNavigationType,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) override;
@@ -329,6 +326,9 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
void SelectorMatchChanged(const Vector<String>&,
const Vector<String>&) override {}
LocalFrame* CreateFrame(const AtomicString&, HTMLFrameOwnerElement*) override;
+ std::pair<RemoteFrame*, base::UnguessableToken> CreatePortal(
+ HTMLPortalElement*,
+ mojom::blink::PortalRequest) override;
WebPluginContainerImpl* CreatePlugin(HTMLPlugInElement&,
const KURL&,
const Vector<String>&,
@@ -361,6 +361,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
return &interface_provider_;
}
+ mojom::blink::DocumentInterfaceBroker* GetDocumentInterfaceBroker() override;
+
WebSpellCheckPanelHostClient* SpellCheckPanelHostClient() const override {
return nullptr;
}
@@ -377,7 +379,13 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
WebTextCheckClient* GetTextCheckerClient() const override;
std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override {
- return Platform::Current()->CreateDefaultURLLoaderFactory();
+ // Most consumers of EmptyLocalFrameClient should not make network requests.
+ // If an exception needs to be made (e.g. in test code), then the consumer
+ // should define their own subclass of LocalFrameClient or
+ // EmptyLocalFrameClient and override the CreateURLLoaderFactory method.
+ // See also https://crbug.com/891872.
+ NOTREACHED();
+ return nullptr;
}
void BubbleLogicalScrollInParentFrame(
@@ -399,6 +407,7 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
WebTextCheckClient* text_check_client_;
service_manager::InterfaceProvider interface_provider_;
+ mojom::blink::DocumentInterfaceBrokerPtr document_interface_broker_;
DISALLOW_COPY_AND_ASSIGN(EmptyLocalFrameClient);
};
@@ -423,6 +432,8 @@ class CORE_EXPORT EmptyRemoteFrameClient : public RemoteFrameClient {
// RemoteFrameClient implementation.
void Navigate(const ResourceRequest&,
bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
mojom::blink::BlobURLTokenPtr) override {}
unsigned BackForwardLength() override { return 0; }
void CheckCompleted() override {}
diff --git a/chromium/third_party/blink/renderer/core/loader/form_submission.cc b/chromium/third_party/blink/renderer/core/loader/form_submission.cc
index 77e931a2581..901b1f60287 100644
--- a/chromium/third_party/blink/renderer/core/loader/form_submission.cc
+++ b/chromium/third_party/blink/renderer/core/loader/form_submission.cc
@@ -70,7 +70,8 @@ static void AppendMailtoPostFormDataToURL(KURL& url,
// Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded
// as %20.
body = DecodeURLEscapeSequences(
- body.Replace('&', "\r\n").Replace('+', ' ') + "\r\n");
+ body.Replace('&', "\r\n").Replace('+', ' ') + "\r\n",
+ DecodeURLMode::kUTF8OrIsomorphic);
}
Vector<char> body_data;
@@ -234,11 +235,9 @@ FormSubmission* FormSubmission::Create(HTMLFormElement* form,
? UTF8Encoding()
: FormDataEncoder::EncodingFromAcceptCharset(
copied_attributes.AcceptCharset(), document.Encoding());
- FormData* dom_form_data =
- FormData::Create(data_encoding.EncodingForFormSubmission());
- bool entry_list_result =
- form->ConstructEntryList(submit_button, *dom_form_data);
- DCHECK(entry_list_result);
+ FormData* dom_form_data = form->ConstructEntryList(
+ submit_button, data_encoding.EncodingForFormSubmission());
+ DCHECK(dom_form_data);
scoped_refptr<EncodedFormData> form_data;
String boundary;
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 58bb8b7797d..bc3130ec9dc 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -40,13 +40,14 @@
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/common/client_hints/client_hints.h"
#include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_application_cache_host.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_effective_connection_type.h"
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
+#include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
#include "third_party/blink/public/platform/websocket_handshake_throttle.h"
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_local_frame.h"
@@ -71,6 +72,8 @@
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
+#include "third_party/blink/renderer/core/loader/frame_or_imported_document.h"
+#include "third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h"
#include "third_party/blink/renderer/core/loader/idleness_detector.h"
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
@@ -232,20 +235,20 @@ struct FrameFetchContext::FrozenState final
const base::Optional<mojom::IPAddressSpace>& address_space,
const ContentSecurityPolicy* content_security_policy,
KURL site_for_cookies,
+ scoped_refptr<const SecurityOrigin> top_frame_origin,
const ClientHintsPreferences& client_hints_preferences,
float device_pixel_ratio,
const String& user_agent,
- bool is_main_frame,
bool is_svg_image_chrome_client)
: url(url),
parent_security_origin(std::move(parent_security_origin)),
address_space(address_space),
content_security_policy(content_security_policy),
site_for_cookies(site_for_cookies),
+ top_frame_origin(std::move(top_frame_origin)),
client_hints_preferences(client_hints_preferences),
device_pixel_ratio(device_pixel_ratio),
user_agent(user_agent),
- is_main_frame(is_main_frame),
is_svg_image_chrome_client(is_svg_image_chrome_client) {}
const KURL url;
@@ -253,10 +256,10 @@ struct FrameFetchContext::FrozenState final
const base::Optional<mojom::IPAddressSpace> address_space;
const Member<const ContentSecurityPolicy> content_security_policy;
const KURL site_for_cookies;
+ const scoped_refptr<const SecurityOrigin> top_frame_origin;
const ClientHintsPreferences client_hints_preferences;
const float device_pixel_ratio;
const String user_agent;
- const bool is_main_frame;
const bool is_svg_image_chrome_client;
void Trace(blink::Visitor* visitor) {
@@ -264,87 +267,55 @@ struct FrameFetchContext::FrozenState final
}
};
-ResourceFetcher* FrameFetchContext::CreateFetcher(DocumentLoader* loader,
- Document* document) {
- FrameFetchContext* context =
- MakeGarbageCollected<FrameFetchContext>(loader, document);
- ResourceFetcher* fetcher = ResourceFetcher::Create(context);
-
- if (loader && context->GetSettings()->GetSavePreviousDocumentResources() !=
- SavePreviousDocumentResources::kNever) {
- if (Document* previous_document = context->GetFrame()->GetDocument()) {
- if (previous_document->IsSecureTransitionTo(loader->Url())) {
- fetcher->HoldResourcesFromPreviousFetcher(
- previous_document->Loader()->Fetcher());
- }
- }
- }
-
- return fetcher;
-}
-
-FrameFetchContext::FrameFetchContext(DocumentLoader* loader, Document* document)
- : BaseFetchContext(
- document ? document->GetTaskRunner(blink::TaskType::kNetworking)
- : loader->GetFrame()->GetTaskRunner(
- blink::TaskType::kNetworking)),
- document_loader_(loader),
- document_(document),
- save_data_enabled_(GetNetworkStateNotifier().SaveDataEnabled() &&
- !GetSettings()->GetDataSaverHoldbackWebApi()) {
- if (document_) {
- fetch_client_settings_object_ =
- MakeGarbageCollected<FetchClientSettingsObjectImpl>(*document_);
+ResourceFetcher* FrameFetchContext::CreateFetcher(
+ const FrameResourceFetcherProperties& properties) {
+ const FrameOrImportedDocument& frame_or_imported_document =
+ properties.GetFrameOrImportedDocument();
+ LocalFrame& frame = frame_or_imported_document.GetFrame();
+ ResourceFetcherInit init(
+ properties,
+ MakeGarbageCollected<FrameFetchContext>(frame_or_imported_document),
+ frame.GetTaskRunner(TaskType::kNetworking), frame.Console());
+ // Frame loading should normally start with |kTight| throttling, as the
+ // frame will be in layout-blocking state until the <body> tag is inserted
+ init.initial_throttling_policy =
+ ResourceLoadScheduler::ThrottlingPolicy::kTight;
+ // TODO(nasko): How should this work with OOPIF?
+ // The MHTMLArchive is parsed as a whole, but can be constructed from frames
+ // in multiple processes. In that case, which process should parse it and how
+ // should the output be spread back across multiple processes?
+ if (!init.properties->IsMainFrame() &&
+ frame.Tree().Parent()->IsLocalFrame()) {
+ init.archive = ToLocalFrame(frame.Tree().Parent())
+ ->Loader()
+ .GetDocumentLoader()
+ ->Fetcher()
+ ->Archive();
}
- DCHECK(GetFrame());
+ return MakeGarbageCollected<ResourceFetcher>(init);
}
-void FrameFetchContext::ProvideDocumentToContext(FetchContext& context,
- Document* document) {
+ResourceFetcher* FrameFetchContext::CreateFetcherForImportedDocument(
+ Document* document) {
DCHECK(document);
- CHECK(context.IsFrameFetchContext());
- static_cast<FrameFetchContext&>(context).document_ = document;
- static_cast<FrameFetchContext&>(context).fetch_client_settings_object_ =
- MakeGarbageCollected<FetchClientSettingsObjectImpl>(*document);
-}
-
-FrameFetchContext::~FrameFetchContext() {
- document_loader_ = nullptr;
-}
-
-LocalFrame* FrameFetchContext::FrameOfImportsController() const {
- DCHECK(document_);
- DCHECK(!IsDetached());
-
- // It's guaranteed that imports_controller is not nullptr since:
- // - only ClearImportsController() clears it
- // - ClearImportsController() also calls ClearContext() on this
- // FrameFetchContext() making IsDetached() return false
- HTMLImportsController* imports_controller = document_->ImportsController();
- DCHECK(imports_controller);
-
- // It's guaranteed that Master() is not yet Shutdown()-ed since when Master()
- // is Shutdown()-ed:
- // - Master()'s HTMLImportsController is disposed.
- // - All the HTMLImportLoader instances of the HTMLImportsController are
- // disposed.
- // - ClearImportsController() is called on the Document of the
- // HTMLImportLoader to detach this context which makes IsDetached() return
- // true.
- // HTMLImportsController is created only when the master Document's
- // GetFrame() doesn't return nullptr, this is guaranteed to be not nullptr
- // here.
- LocalFrame* frame = imports_controller->Master()->GetFrame();
- DCHECK(frame);
- return frame;
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-FrameFetchContext::GetLoadingTaskRunner() {
- if (IsDetached())
- return Thread::Current()->GetTaskRunner();
- return FetchContext::GetLoadingTaskRunner();
-}
+ // |document| is detached.
+ DCHECK(!document->GetFrame());
+ auto* frame_or_imported_document =
+ MakeGarbageCollected<FrameOrImportedDocument>(*document);
+ ResourceFetcherInit init(
+ *MakeGarbageCollected<FrameResourceFetcherProperties>(
+ *frame_or_imported_document),
+ MakeGarbageCollected<FrameFetchContext>(*frame_or_imported_document),
+ document->GetTaskRunner(blink::TaskType::kNetworking),
+ frame_or_imported_document->GetFrame().Console());
+ return MakeGarbageCollected<ResourceFetcher>(init);
+}
+
+FrameFetchContext::FrameFetchContext(
+ const FrameOrImportedDocument& frame_or_imported_document)
+ : frame_or_imported_document_(frame_or_imported_document),
+ save_data_enabled_(GetNetworkStateNotifier().SaveDataEnabled() &&
+ !GetSettings()->GetDataSaverHoldbackWebApi()) {}
std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>
FrameFetchContext::CreateResourceLoadingTaskRunnerHandle() {
@@ -363,19 +334,15 @@ FrameScheduler* FrameFetchContext::GetFrameScheduler() const {
return GetFrame()->GetFrameScheduler();
}
-const FetchClientSettingsObject*
-FrameFetchContext::GetFetchClientSettingsObject() const {
- DCHECK(fetch_client_settings_object_);
- return fetch_client_settings_object_.Get();
-}
-
KURL FrameFetchContext::GetSiteForCookies() const {
if (IsDetached())
return frozen_state_->site_for_cookies;
- // Use document_ for subresource or nested frame cases,
+ Document* document = frame_or_imported_document_->GetDocument();
+ // Use |document| for subresource or nested frame cases,
// GetFrame()->GetDocument() otherwise.
- Document* document = document_ ? document_.Get() : GetFrame()->GetDocument();
+ if (!document)
+ document = GetFrame()->GetDocument();
return document->SiteForCookies();
}
@@ -397,14 +364,7 @@ FrameFetchContext::GetPreviewsResourceLoadingHints() const {
}
LocalFrame* FrameFetchContext::GetFrame() const {
- DCHECK(!IsDetached());
-
- if (!document_loader_)
- return FrameOfImportsController();
-
- LocalFrame* frame = document_loader_->GetFrame();
- DCHECK(frame);
- return frame;
+ return &frame_or_imported_document_->GetFrame();
}
LocalFrameClient* FrameFetchContext::GetLocalFrameClient() const {
@@ -497,19 +457,14 @@ mojom::FetchCacheMode FrameFetchContext::ResourceRequestCachePolicy(
return cache_mode;
}
-inline DocumentLoader* FrameFetchContext::MasterDocumentLoader() const {
+DocumentLoader* FrameFetchContext::GetDocumentLoader() const {
DCHECK(!IsDetached());
+ return frame_or_imported_document_->GetDocumentLoader();
+}
- if (document_loader_)
- return document_loader_.Get();
-
- // GetDocumentLoader() here always returns a non-nullptr value that is the
- // DocumentLoader for |document_| because:
- // - A Document is created with a LocalFrame only after the
- // DocumentLoader is committed
- // - When another DocumentLoader is committed, the FrameLoader
- // Shutdown()-s |document_| making IsDetached() return false
- return FrameOfImportsController()->Loader().GetDocumentLoader();
+inline DocumentLoader* FrameFetchContext::MasterDocumentLoader() const {
+ DCHECK(!IsDetached());
+ return &frame_or_imported_document_->GetMasterDocumentLoader();
}
void FrameFetchContext::DispatchDidChangeResourcePriority(
@@ -525,9 +480,15 @@ void FrameFetchContext::DispatchDidChangeResourcePriority(
identifier, load_priority);
}
-void FrameFetchContext::PrepareRequest(ResourceRequest& request,
- RedirectType redirect_type) {
+void FrameFetchContext::PrepareRequest(
+ ResourceRequest& request,
+ WebScopedVirtualTimePauser& virtual_time_pauser,
+ RedirectType redirect_type) {
+ // TODO(yhirano): Clarify which statements are actually needed when
+ // |redirect_type| is |kForRedirect|.
+
SetFirstPartyCookie(request);
+ request.SetTopFrameOrigin(GetTopFrameOrigin());
String user_agent = GetUserAgent();
request.SetHTTPUserAgent(AtomicString(user_agent));
@@ -535,6 +496,12 @@ void FrameFetchContext::PrepareRequest(ResourceRequest& request,
if (IsDetached())
return;
GetLocalFrameClient()->DispatchWillSendRequest(request);
+ if (redirect_type == FetchContext::RedirectType::kNotForRedirect &&
+ GetFrameScheduler()) {
+ virtual_time_pauser = GetFrameScheduler()->CreateWebScopedVirtualTimePauser(
+ request.Url().GetString(),
+ WebScopedVirtualTimePauser::VirtualTaskDuration::kNonInstant);
+ }
// ServiceWorker hook ups.
if (MasterDocumentLoader()->GetServiceWorkerNetworkProvider()) {
@@ -545,9 +512,9 @@ void FrameFetchContext::PrepareRequest(ResourceRequest& request,
// If it's not for redirect, hook up ApplicationCache here too.
if (redirect_type == FetchContext::RedirectType::kNotForRedirect &&
- document_loader_ && !document_loader_->Fetcher()->Archive() &&
+ GetDocumentLoader() && !GetDocumentLoader()->Fetcher()->Archive() &&
request.Url().IsValid()) {
- document_loader_->GetApplicationCacheHost()->WillStartLoading(request);
+ GetDocumentLoader()->GetApplicationCacheHost()->WillStartLoading(request);
}
}
@@ -571,9 +538,9 @@ void FrameFetchContext::DispatchWillSendRequest(
initiator_info, resource_type);
if (IdlenessDetector* idleness_detector = GetFrame()->GetIdlenessDetector())
idleness_detector->OnWillSendRequest(MasterDocumentLoader()->Fetcher());
- if (document_) {
+ if (frame_or_imported_document_->GetDocument()) {
InteractiveDetector* interactive_detector(
- InteractiveDetector::From(*document_));
+ InteractiveDetector::From(*frame_or_imported_document_->GetDocument()));
if (interactive_detector) {
interactive_detector->OnResourceLoadBegin(base::nullopt);
}
@@ -582,24 +549,30 @@ void FrameFetchContext::DispatchWillSendRequest(
void FrameFetchContext::DispatchDidReceiveResponse(
unsigned long identifier,
+ const ResourceRequest& request,
const ResourceResponse& response,
- network::mojom::RequestContextFrameType frame_type,
- mojom::RequestContextType request_context,
Resource* resource,
ResourceResponseType response_type) {
if (IsDetached())
return;
- DCHECK(resource);
+ // Note: resource can be null for navigations.
+ ResourceType resource_type =
+ resource ? resource->GetType() : ResourceType::kMainResource;
- if (GetSubresourceFilter() && resource->GetResourceRequest().IsAdResource())
+ if (GetSubresourceFilter() && resource &&
+ resource->GetResourceRequest().IsAdResource()) {
GetSubresourceFilter()->ReportAdRequestId(response.RequestId());
+ }
- MaybeRecordCTPolicyComplianceUseCounter(GetFrame(), resource->GetType(),
+ MaybeRecordCTPolicyComplianceUseCounter(GetFrame(), resource_type,
response.GetCTPolicyCompliance(),
MasterDocumentLoader());
if (response_type == ResourceResponseType::kFromMemoryCache) {
+ GetLocalFrameClient()->DispatchDidLoadResourceFromMemoryCache(
+ resource->GetResourceRequest(), response);
+
// Note: probe::willSendRequest needs to precede before this probe method.
probe::markResourceAsCached(GetFrame(), MasterDocumentLoader(), identifier);
if (response.IsNull())
@@ -608,62 +581,66 @@ void FrameFetchContext::DispatchDidReceiveResponse(
MixedContentChecker::CheckMixedPrivatePublic(GetFrame(),
response.RemoteIPAddress());
- LinkLoader::CanLoadResources resource_loading_policy =
+ PreloadHelper::CanLoadResources resource_loading_policy =
response_type == ResourceResponseType::kFromMemoryCache
- ? LinkLoader::kDoNotLoadResources
- : LinkLoader::kLoadResourcesAndPreconnect;
- if (document_loader_ &&
- document_loader_ == document_loader_->GetFrame()
- ->Loader()
- .GetProvisionalDocumentLoader()) {
+ ? PreloadHelper::kDoNotLoadResources
+ : PreloadHelper::kLoadResourcesAndPreconnect;
+ if (GetDocumentLoader() &&
+ GetDocumentLoader() == GetDocumentLoader()
+ ->GetFrame()
+ ->Loader()
+ .GetProvisionalDocumentLoader()) {
// When response is received with a provisional docloader, the resource
// haven't committed yet, and we cannot load resources, only preconnect.
- resource_loading_policy = LinkLoader::kDoNotLoadResources;
+ resource_loading_policy = PreloadHelper::kDoNotLoadResources;
}
// Client hints preferences should be persisted only from responses that were
// served by the same host as the host of the document-level origin.
KURL frame_url = Url();
if (frame_url == NullURL())
- frame_url = document_loader_->Url();
+ frame_url = GetDocumentLoader()->Url();
// The accept-ch-lifetime header is honored only on the navigation responses.
// Further, the navigation response should be from a top level frame (i.e.,
// main frame) or the origin of the response should match the origin of the
// top level frame.
- if ((resource->GetType() == ResourceType::kMainResource) &&
- (IsMainFrame() || IsFirstPartyOrigin(response.Url()))) {
+ if (resource_type == ResourceType::kMainResource &&
+ (GetResourceFetcherProperties().IsMainFrame() ||
+ IsFirstPartyOrigin(response.CurrentRequestUrl()))) {
ParseAndPersistClientHints(response);
}
- LinkLoader::LoadLinksFromHeader(
- response.HttpHeaderField(http_names::kLink), response.Url(), *GetFrame(),
- document_, NetworkHintsInterfaceImpl(), resource_loading_policy,
- LinkLoader::kLoadAll, nullptr);
+ PreloadHelper::LoadLinksFromHeader(
+ response.HttpHeaderField(http_names::kLink), response.CurrentRequestUrl(),
+ *GetFrame(), frame_or_imported_document_->GetDocument(),
+ NetworkHintsInterfaceImpl(), resource_loading_policy,
+ PreloadHelper::kLoadAll, nullptr);
if (response.HasMajorCertificateErrors()) {
MixedContentChecker::HandleCertificateError(GetFrame(), response,
- frame_type, request_context);
+ request.GetFrameType(),
+ request.GetRequestContext());
}
if (response.IsLegacySymantecCert()) {
- RecordLegacySymantecCertUseCounter(GetFrame(), resource->GetType());
- GetLocalFrameClient()->ReportLegacySymantecCert(response.Url(),
- false /* did_fail */);
+ RecordLegacySymantecCertUseCounter(GetFrame(), resource_type);
+ GetLocalFrameClient()->ReportLegacySymantecCert(
+ response.CurrentRequestUrl(), false /* did_fail */);
}
if (response.IsLegacyTLSVersion()) {
- if (resource->GetType() != ResourceType::kMainResource) {
+ if (resource_type != ResourceType::kMainResource) {
// Main resources are counted in DocumentLoader.
UseCounter::Count(GetFrame(), WebFeature::kLegacyTLSVersionInSubresource);
}
- GetLocalFrameClient()->ReportLegacyTLSVersion(response.Url());
+ GetLocalFrameClient()->ReportLegacyTLSVersion(response.CurrentRequestUrl());
}
GetFrame()->Loader().Progress().IncrementProgress(identifier, response);
GetLocalFrameClient()->DispatchDidReceiveResponse(response);
DocumentLoader* document_loader = MasterDocumentLoader();
- probe::didReceiveResourceResponse(GetFrame()->GetDocument(), identifier,
- document_loader, response, resource);
+ probe::didReceiveResourceResponse(Probe(), identifier, document_loader,
+ response, resource);
// It is essential that inspector gets resource response BEFORE console.
GetFrame()->Console().ReportResourceResponseReceived(document_loader,
identifier, response);
@@ -671,13 +648,13 @@ void FrameFetchContext::DispatchDidReceiveResponse(
void FrameFetchContext::DispatchDidReceiveData(unsigned long identifier,
const char* data,
- size_t data_length) {
+ uint64_t data_length) {
if (IsDetached())
return;
GetFrame()->Loader().Progress().IncrementProgress(identifier, data_length);
- probe::didReceiveData(GetFrame()->GetDocument(), identifier,
- MasterDocumentLoader(), data, data_length);
+ probe::didReceiveData(Probe(), identifier, MasterDocumentLoader(), data,
+ data_length);
}
void FrameFetchContext::DispatchDidReceiveEncodedData(
@@ -685,9 +662,8 @@ void FrameFetchContext::DispatchDidReceiveEncodedData(
size_t encoded_data_length) {
if (IsDetached())
return;
- probe::didReceiveEncodedDataLength(GetFrame()->GetDocument(),
- MasterDocumentLoader(), identifier,
- encoded_data_length);
+ probe::didReceiveEncodedDataLength(Probe(), MasterDocumentLoader(),
+ identifier, encoded_data_length);
}
void FrameFetchContext::DispatchDidDownloadToBlob(unsigned long identifier,
@@ -695,8 +671,7 @@ void FrameFetchContext::DispatchDidDownloadToBlob(unsigned long identifier,
if (IsDetached() || !blob)
return;
- probe::didReceiveBlob(GetFrame()->GetDocument(), identifier,
- MasterDocumentLoader(), blob);
+ probe::didReceiveBlob(Probe(), identifier, MasterDocumentLoader(), blob);
}
void FrameFetchContext::DispatchDidFinishLoading(
@@ -709,13 +684,12 @@ void FrameFetchContext::DispatchDidFinishLoading(
return;
GetFrame()->Loader().Progress().CompleteProgress(identifier);
- probe::didFinishLoading(GetFrame()->GetDocument(), identifier,
- MasterDocumentLoader(), finish_time,
- encoded_data_length, decoded_body_length,
+ probe::didFinishLoading(Probe(), identifier, MasterDocumentLoader(),
+ finish_time, encoded_data_length, decoded_body_length,
should_report_corb_blocking);
- if (document_) {
+ if (frame_or_imported_document_->GetDocument()) {
InteractiveDetector* interactive_detector(
- InteractiveDetector::From(*document_));
+ InteractiveDetector::From(*frame_or_imported_document_->GetDocument()));
if (interactive_detector) {
interactive_detector->OnResourceLoadEnd(finish_time);
}
@@ -746,11 +720,10 @@ void FrameFetchContext::DispatchDidFail(const KURL& url,
}
GetFrame()->Loader().Progress().CompleteProgress(identifier);
- probe::didFailLoading(GetFrame()->GetDocument(), identifier,
- MasterDocumentLoader(), error);
- if (document_) {
+ probe::didFailLoading(Probe(), identifier, MasterDocumentLoader(), error);
+ if (frame_or_imported_document_->GetDocument()) {
InteractiveDetector* interactive_detector(
- InteractiveDetector::From(*document_));
+ InteractiveDetector::From(*frame_or_imported_document_->GetDocument()));
if (interactive_detector) {
// We have not yet recorded load_finish_time. Pass nullopt here; we will
// call CurrentTimeTicksInSeconds lazily when we need it.
@@ -765,36 +738,12 @@ void FrameFetchContext::DispatchDidFail(const KURL& url,
}
}
-void FrameFetchContext::DispatchDidLoadResourceFromMemoryCache(
- unsigned long identifier,
- const ResourceRequest& resource_request,
- const ResourceResponse& resource_response) {
- if (IsDetached())
- return;
-
- GetLocalFrameClient()->DispatchDidLoadResourceFromMemoryCache(
- resource_request, resource_response);
-}
-
-bool FrameFetchContext::ShouldLoadNewResource(ResourceType type) const {
- if (!document_loader_)
- return true;
-
- if (IsDetached())
- return false;
-
- FrameLoader& loader = document_loader_->GetFrame()->Loader();
- if (type == ResourceType::kMainResource)
- return document_loader_ == loader.GetProvisionalDocumentLoader();
- return document_loader_ == loader.GetDocumentLoader();
-}
-
void FrameFetchContext::RecordLoadingActivity(
const ResourceRequest& request,
ResourceType type,
const AtomicString& fetch_initiator_name) {
- if (!document_loader_ || document_loader_->Fetcher()->Archive() ||
- !request.Url().IsValid())
+ if (IsDetached() || !GetDocumentLoader() ||
+ GetDocumentLoader()->Fetcher()->Archive() || !request.Url().IsValid())
return;
V8DOMActivityLogger* activity_logger = nullptr;
if (fetch_initiator_name == fetch_initiator_type_names::kXmlhttprequest) {
@@ -813,9 +762,10 @@ void FrameFetchContext::RecordLoadingActivity(
}
void FrameFetchContext::DidLoadResource(Resource* resource) {
- if (!document_)
+ if (IsDetached() || !frame_or_imported_document_->GetDocument())
return;
- if (LocalFrame* local_frame = document_->GetFrame()) {
+ if (LocalFrame* local_frame =
+ frame_or_imported_document_->GetDocument()->GetFrame()) {
if (IdlenessDetector* idleness_detector =
local_frame->GetIdlenessDetector()) {
idleness_detector->OnDidLoadResource();
@@ -823,36 +773,30 @@ void FrameFetchContext::DidLoadResource(Resource* resource) {
}
if (resource->IsLoadEventBlockingResourceType())
- document_->CheckCompleted();
+ frame_or_imported_document_->GetDocument()->CheckCompleted();
}
void FrameFetchContext::DidObserveLoadingBehavior(
WebLoadingBehaviorFlag behavior) {
- if (document_loader_)
- document_loader_->DidObserveLoadingBehavior(behavior);
+ if (GetDocumentLoader())
+ GetDocumentLoader()->DidObserveLoadingBehavior(behavior);
}
void FrameFetchContext::AddResourceTiming(const ResourceTimingInfo& info) {
// Normally, |document_| is cleared on Document shutdown. However, Documents
// for HTML imports will also not have a LocalFrame set: in that case, also
// early return, as there is nothing to report the resource timing to.
- if (!document_)
+ if (IsDetached() || !frame_or_imported_document_->GetDocument())
return;
- LocalFrame* frame = document_->GetFrame();
+ LocalFrame* frame = frame_or_imported_document_->GetDocument()->GetFrame();
if (!frame)
return;
- if (info.IsMainResource()) {
- DCHECK(frame->Owner());
- // Main resource timing information is reported through the owner to be
- // passed to the parent frame, if appropriate.
- frame->Owner()->AddResourceTiming(info);
- frame->SetShouldSendResourceTimingInfoToParent(false);
- return;
- }
-
+ // Timing for main resource is handled in DocumentLoader.
+ DCHECK(!info.IsMainResource());
// All other resources are reported to the corresponding Document.
- DOMWindowPerformance::performance(*document_->domWindow())
+ DOMWindowPerformance::performance(
+ *frame_or_imported_document_->GetDocument()->domWindow())
->GenerateAndAddResourceTiming(info);
}
@@ -864,84 +808,6 @@ bool FrameFetchContext::AllowImage(bool images_enabled, const KURL& url) const {
return images_enabled;
}
-blink::mojom::ControllerServiceWorkerMode
-FrameFetchContext::IsControlledByServiceWorker() const {
- if (IsDetached())
- return blink::mojom::ControllerServiceWorkerMode::kNoController;
-
- DCHECK(MasterDocumentLoader());
-
- auto* service_worker_network_provider =
- MasterDocumentLoader()->GetServiceWorkerNetworkProvider();
- if (!service_worker_network_provider)
- return blink::mojom::ControllerServiceWorkerMode::kNoController;
- return service_worker_network_provider->IsControlledByServiceWorker();
-}
-
-int64_t FrameFetchContext::ServiceWorkerID() const {
- DCHECK(IsControlledByServiceWorker() !=
- blink::mojom::ControllerServiceWorkerMode::kNoController);
- DCHECK(MasterDocumentLoader());
- auto* service_worker_network_provider =
- MasterDocumentLoader()->GetServiceWorkerNetworkProvider();
- return service_worker_network_provider
- ? service_worker_network_provider->ControllerServiceWorkerID()
- : -1;
-}
-
-int FrameFetchContext::ApplicationCacheHostID() const {
- if (!document_loader_)
- return WebApplicationCacheHost::kAppCacheNoHostId;
- return document_loader_->GetApplicationCacheHost()->GetHostID();
-}
-
-bool FrameFetchContext::IsMainFrame() const {
- if (IsDetached())
- return frozen_state_->is_main_frame;
- return GetFrame()->IsMainFrame();
-}
-
-bool FrameFetchContext::DefersLoading() const {
- return IsDetached() ? false : GetFrame()->GetPage()->Paused();
-}
-
-bool FrameFetchContext::IsLoadComplete() const {
- if (IsDetached())
- return true;
-
- return document_ && document_->LoadEventFinished();
-}
-
-bool FrameFetchContext::UpdateTimingInfoForIFrameNavigation(
- ResourceTimingInfo* info) {
- if (IsDetached())
- return false;
-
- // <iframe>s should report the initial navigation requested by the parent
- // document, but not subsequent navigations.
- if (!GetFrame()->Owner())
- return false;
- // Note that this can be racy since this information is forwarded over IPC
- // when crossing process boundaries.
- if (!GetFrame()->should_send_resource_timing_info_to_parent())
- return false;
- // Do not report iframe navigation that restored from history, since its
- // location may have been changed after initial navigation,
- if (MasterDocumentLoader()->LoadType() == WebFrameLoadType::kBackForward) {
- // ...and do not report subsequent navigations in the iframe too.
- GetFrame()->SetShouldSendResourceTimingInfoToParent(false);
- return false;
- }
- return true;
-}
-
-const SecurityOrigin* FrameFetchContext::GetSecurityOrigin() const {
- // This can be called before |fetch_client_settings_object_| is set.
- if (!fetch_client_settings_object_)
- return nullptr;
- return fetch_client_settings_object_->GetSecurityOrigin();
-}
-
void FrameFetchContext::ModifyRequestForCSP(ResourceRequest& resource_request) {
if (IsDetached())
return;
@@ -949,7 +815,8 @@ void FrameFetchContext::ModifyRequestForCSP(ResourceRequest& resource_request) {
// Record the latest requiredCSP value that will be used when sending this
// request.
GetFrame()->Loader().RecordLatestRequiredCSP();
- GetFrame()->Loader().ModifyRequestForCSP(resource_request, document_);
+ GetFrame()->Loader().ModifyRequestForCSP(
+ resource_request, frame_or_imported_document_->GetDocument());
}
void FrameFetchContext::AddClientHintsIfNecessary(
@@ -1093,21 +960,6 @@ void FrameFetchContext::SetFirstPartyCookie(ResourceRequest& request) {
}
}
-MHTMLArchive* FrameFetchContext::Archive() const {
- DCHECK(!IsMainFrame());
- // TODO(nasko): How should this work with OOPIF?
- // The MHTMLArchive is parsed as a whole, but can be constructed from frames
- // in multiple processes. In that case, which process should parse it and how
- // should the output be spread back across multiple processes?
- if (IsDetached() || !GetFrame()->Tree().Parent()->IsLocalFrame())
- return nullptr;
- return ToLocalFrame(GetFrame()->Tree().Parent())
- ->Loader()
- .GetDocumentLoader()
- ->Fetcher()
- ->Archive();
-}
-
bool FrameFetchContext::AllowScriptFromSource(const KURL& url) const {
if (AllowScriptFromSourceWithoutNotifying(url))
return true;
@@ -1138,12 +990,22 @@ bool FrameFetchContext::IsFirstPartyOrigin(const KURL& url) const {
->IsSameSchemeHostPort(SecurityOrigin::Create(url).get());
}
+scoped_refptr<const SecurityOrigin> FrameFetchContext::GetTopFrameOrigin()
+ const {
+ if (IsDetached())
+ return frozen_state_->top_frame_origin;
+
+ Document* document = frame_or_imported_document_->GetDocument();
+ if (!document)
+ document = GetFrame()->GetDocument();
+ return document->TopFrameOrigin();
+}
+
bool FrameFetchContext::ShouldBlockRequestByInspector(const KURL& url) const {
if (IsDetached())
return false;
bool should_block_request = false;
- probe::shouldBlockRequest(GetFrame()->GetDocument(), url,
- &should_block_request);
+ probe::shouldBlockRequest(Probe(), url, &should_block_request);
return should_block_request;
}
@@ -1250,7 +1112,10 @@ bool FrameFetchContext::ShouldBlockFetchAsCredentialedSubresource(
// TODO(mkwst): This doesn't work when the subresource is an iframe.
// See https://crbug.com/756846.
if (Url().User() == url.User() && Url().Pass() == url.Pass() &&
- SecurityOrigin::Create(url)->IsSameSchemeHostPort(GetSecurityOrigin())) {
+ SecurityOrigin::Create(url)->IsSameSchemeHostPort(
+ GetResourceFetcherProperties()
+ .GetFetchClientSettingsObject()
+ .GetSecurityOrigin())) {
return false;
}
@@ -1264,9 +1129,9 @@ bool FrameFetchContext::ShouldBlockFetchAsCredentialedSubresource(
const KURL& FrameFetchContext::Url() const {
if (IsDetached())
return frozen_state_->url;
- if (!document_)
+ if (!frame_or_imported_document_->GetDocument())
return NullURL();
- return document_->Url();
+ return frame_or_imported_document_->GetDocument()->Url();
}
const SecurityOrigin* FrameFetchContext::GetParentSecurityOrigin() const {
@@ -1282,9 +1147,9 @@ base::Optional<mojom::IPAddressSpace> FrameFetchContext::GetAddressSpace()
const {
if (IsDetached())
return frozen_state_->address_space;
- if (!document_)
+ if (!frame_or_imported_document_->GetDocument())
return base::nullopt;
- ExecutionContext* context = document_;
+ ExecutionContext* context = frame_or_imported_document_->GetDocument();
return base::make_optional(context->GetSecurityContext().AddressSpace());
}
@@ -1292,18 +1157,20 @@ const ContentSecurityPolicy* FrameFetchContext::GetContentSecurityPolicy()
const {
if (IsDetached())
return frozen_state_->content_security_policy;
- return document_ ? document_->GetContentSecurityPolicy() : nullptr;
+ Document* document = frame_or_imported_document_->GetDocument();
+ return document ? document->GetContentSecurityPolicy() : nullptr;
}
void FrameFetchContext::AddConsoleMessage(ConsoleMessage* message) const {
if (IsDetached())
return;
+ Document* document = frame_or_imported_document_->GetDocument();
// Route the console message through Document if it's attached, so
// that script line numbers can be included. Otherwise, route directly to the
// FrameConsole, to ensure we never drop a message.
- if (document_ && document_->GetFrame())
- document_->AddConsoleMessage(message);
+ if (document && document->GetFrame())
+ document->AddConsoleMessage(message);
else
GetFrame()->Console().AddMessage(message);
}
@@ -1332,23 +1199,25 @@ const ClientHintsPreferences FrameFetchContext::GetClientHintsPreferences()
if (IsDetached())
return frozen_state_->client_hints_preferences;
- if (!document_ || !document_->GetFrame())
+ Document* document = frame_or_imported_document_->GetDocument();
+ if (!document || !document->GetFrame())
return ClientHintsPreferences();
- return document_->GetFrame()->GetClientHintsPreferences();
+ return document->GetFrame()->GetClientHintsPreferences();
}
float FrameFetchContext::GetDevicePixelRatio() const {
if (IsDetached())
return frozen_state_->device_pixel_ratio;
- if (!document_) {
+ Document* document = frame_or_imported_document_->GetDocument();
+ if (!document) {
// Note that this value is not used because the preferences object returned
// by GetClientHintsPreferences() doesn't allow to use it.
return 1.0;
}
- return document_->DevicePixelRatio();
+ return document->DevicePixelRatio();
}
bool FrameFetchContext::ShouldSendClientHint(
@@ -1363,32 +1232,35 @@ void FrameFetchContext::ParseAndPersistClientHints(
const ResourceResponse& response) {
FrameClientHintsPreferencesContext hints_context(GetFrame());
- document_loader_->GetClientHintsPreferences()
+ GetDocumentLoader()
+ ->GetClientHintsPreferences()
.UpdateFromAcceptClientHintsLifetimeHeader(
response.HttpHeaderField(http_names::kAcceptCHLifetime),
- response.Url(), &hints_context);
+ response.CurrentRequestUrl(), &hints_context);
- document_loader_->GetClientHintsPreferences()
+ GetDocumentLoader()
+ ->GetClientHintsPreferences()
.UpdateFromAcceptClientHintsHeader(
- response.HttpHeaderField(http_names::kAcceptCH), response.Url(),
- &hints_context);
+ response.HttpHeaderField(http_names::kAcceptCH),
+ response.CurrentRequestUrl(), &hints_context);
// Notify content settings client of persistent client hints.
TimeDelta persist_duration =
- document_loader_->GetClientHintsPreferences().GetPersistDuration();
+ GetDocumentLoader()->GetClientHintsPreferences().GetPersistDuration();
if (persist_duration.InSeconds() <= 0)
return;
- WebEnabledClientHints enabled_client_hints =
- document_loader_->GetClientHintsPreferences().GetWebEnabledClientHints();
- if (!AllowScriptFromSourceWithoutNotifying(response.Url())) {
+ WebEnabledClientHints enabled_client_hints = GetDocumentLoader()
+ ->GetClientHintsPreferences()
+ .GetWebEnabledClientHints();
+ if (!AllowScriptFromSourceWithoutNotifying(response.CurrentRequestUrl())) {
// Do not persist client hint preferences if the JavaScript is disabled.
return;
}
if (auto* settings_client = GetContentSettingsClient()) {
settings_client->PersistClientHints(enabled_client_hints, persist_duration,
- response.Url());
+ response.CurrentRequestUrl());
}
}
@@ -1418,11 +1290,12 @@ std::unique_ptr<WebURLLoader> FrameFetchContext::CreateURLLoader(
// shared worker loads is okay even with NetworkService/S13nSW disabled).
// TODO(mek): Move the RequestContext check to the worker side's relevant
// callsite when we make Shared Worker loading off-main-thread.
- if (document_ && request.Url().ProtocolIs("blob") &&
+ Document* document = frame_or_imported_document_->GetDocument();
+ if (document && request.Url().ProtocolIs("blob") &&
BlobUtils::MojoBlobURLsEnabled() && !url_loader_factory &&
request.GetRequestContext() != mojom::RequestContextType::SHARED_WORKER) {
- document_->GetPublicURLManager().Resolve(request.Url(),
- MakeRequest(&url_loader_factory));
+ document->GetPublicURLManager().Resolve(request.Url(),
+ MakeRequest(&url_loader_factory));
}
if (url_loader_factory) {
return Platform::Current()
@@ -1446,46 +1319,31 @@ FetchContext* FrameFetchContext::Detach() {
if (IsDetached())
return this;
- if (document_) {
+ if (frame_or_imported_document_->GetDocument()) {
frozen_state_ = MakeGarbageCollected<FrozenState>(
Url(), GetParentSecurityOrigin(), GetAddressSpace(),
- GetContentSecurityPolicy(), GetSiteForCookies(),
+ GetContentSecurityPolicy(), GetSiteForCookies(), GetTopFrameOrigin(),
GetClientHintsPreferences(), GetDevicePixelRatio(), GetUserAgent(),
- IsMainFrame(), IsSVGImageChromeClient());
- fetch_client_settings_object_ =
- document_->CreateFetchClientSettingsObjectSnapshot();
+ IsSVGImageChromeClient());
} else {
// Some getters are unavailable in this case.
frozen_state_ = MakeGarbageCollected<FrozenState>(
NullURL(), GetParentSecurityOrigin(), GetAddressSpace(),
- GetContentSecurityPolicy(), GetSiteForCookies(),
+ GetContentSecurityPolicy(), GetSiteForCookies(), GetTopFrameOrigin(),
GetClientHintsPreferences(), GetDevicePixelRatio(), GetUserAgent(),
- IsMainFrame(), IsSVGImageChromeClient());
- fetch_client_settings_object_ =
- MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
- NullURL(), nullptr, network::mojom::ReferrerPolicy::kDefault,
- String(), HttpsState::kNone);
+ IsSVGImageChromeClient());
}
- // This is needed to break a reference cycle in which off-heap
- // ComputedStyle is involved. See https://crbug.com/383860 for details.
- document_ = nullptr;
-
+ frame_or_imported_document_ = nullptr;
return this;
}
void FrameFetchContext::Trace(blink::Visitor* visitor) {
- visitor->Trace(document_loader_);
- visitor->Trace(document_);
+ visitor->Trace(frame_or_imported_document_);
visitor->Trace(frozen_state_);
- visitor->Trace(fetch_client_settings_object_);
BaseFetchContext::Trace(visitor);
}
-void FrameFetchContext::RecordDataUriWithOctothorpe() {
- UseCounter::Count(GetFrame(), WebFeature::kDataUriHasOctothorpe);
-}
-
ResourceLoadPriority FrameFetchContext::ModifyPriorityForExperiments(
ResourceLoadPriority priority) const {
if (!GetSettings())
@@ -1547,15 +1405,21 @@ base::Optional<ResourceRequestBlockedReason> FrameFetchContext::CanRequest(
const ResourceLoaderOptions& options,
SecurityViolationReportingPolicy reporting_policy,
ResourceRequest::RedirectStatus redirect_status) const {
- if (document_ && document_->IsFreezingInProgress() &&
+ Document* document =
+ IsDetached() ? nullptr : frame_or_imported_document_->GetDocument();
+ if (document && document->IsFreezingInProgress() &&
!resource_request.GetKeepalive()) {
- AddErrorConsoleMessage(
- "Only fetch keepalive is allowed during onfreeze: " + url.GetString(),
- kJSSource);
+ AddConsoleMessage(ConsoleMessage::Create(
+ kJSMessageSource, kErrorMessageLevel,
+ "Only fetch keepalive is allowed during onfreeze: " + url.GetString()));
return ResourceRequestBlockedReason::kOther;
}
return BaseFetchContext::CanRequest(type, resource_request, url, options,
reporting_policy, redirect_status);
}
+CoreProbeSink* FrameFetchContext::Probe() const {
+ return probe::ToCoreProbeSink(GetFrame()->GetDocument());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h
index 42e367df9a2..f5f84c41a81 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -37,21 +37,23 @@ n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/loader/base_fetch_context.h"
-#include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
class ClientHintsPreferences;
+class CoreProbeSink;
class Document;
class DocumentLoader;
+class FrameOrImportedDocument;
+class FrameResourceFetcherProperties;
class LocalFrame;
class LocalFrameClient;
class ResourceError;
@@ -62,24 +64,13 @@ struct WebEnabledClientHints;
class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
public:
- static ResourceFetcher* CreateFetcherFromDocumentLoader(
- DocumentLoader* loader) {
- return CreateFetcher(loader, nullptr);
- }
+ static ResourceFetcher* CreateFetcher(const FrameResourceFetcherProperties&);
// Used for creating a FrameFetchContext for an imported Document.
// |document_loader_| will be set to nullptr.
- static ResourceFetcher* CreateFetcherFromDocument(Document* document) {
- return CreateFetcher(nullptr, document);
- }
+ static ResourceFetcher* CreateFetcherForImportedDocument(Document* document);
- static void ProvideDocumentToContext(FetchContext&, Document*);
-
- FrameFetchContext(DocumentLoader*, Document*);
- ~FrameFetchContext() override;
-
- bool IsFrameFetchContext() override { return true; }
-
- void RecordDataUriWithOctothorpe() override;
+ explicit FrameFetchContext(const FrameOrImportedDocument&);
+ ~FrameFetchContext() override = default;
void AddAdditionalRequestHeaders(ResourceRequest&,
FetchResourceType) override;
@@ -97,25 +88,24 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
void DispatchDidChangeResourcePriority(unsigned long identifier,
ResourceLoadPriority,
int intra_priority_value) override;
- void PrepareRequest(ResourceRequest&, RedirectType) override;
+ void PrepareRequest(ResourceRequest&,
+ WebScopedVirtualTimePauser&,
+ RedirectType) override;
void DispatchWillSendRequest(
unsigned long identifier,
ResourceRequest&,
const ResourceResponse& redirect_response,
ResourceType,
const FetchInitiatorInfo& = FetchInitiatorInfo()) override;
- void DispatchDidLoadResourceFromMemoryCache(unsigned long identifier,
- const ResourceRequest&,
- const ResourceResponse&) override;
+ // Resource* can be null for navigations.
void DispatchDidReceiveResponse(unsigned long identifier,
+ const ResourceRequest&,
const ResourceResponse&,
- network::mojom::RequestContextFrameType,
- mojom::RequestContextType,
Resource*,
ResourceResponseType) override;
void DispatchDidReceiveData(unsigned long identifier,
const char* data,
- size_t data_length) override;
+ uint64_t data_length) override;
void DispatchDidReceiveEncodedData(unsigned long identifier,
size_t encoded_data_length) override;
void DispatchDidDownloadToBlob(unsigned long identifier,
@@ -131,7 +121,6 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
int64_t encoded_data_length,
bool is_internal_request) override;
- bool ShouldLoadNewResource(ResourceType) const override;
void RecordLoadingActivity(const ResourceRequest&,
ResourceType,
const AtomicString& fetch_initiator_name) override;
@@ -140,17 +129,6 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
void AddResourceTiming(const ResourceTimingInfo&) override;
bool AllowImage(bool images_enabled, const KURL&) const override;
- blink::mojom::ControllerServiceWorkerMode IsControlledByServiceWorker()
- const override;
- int64_t ServiceWorkerID() const override;
- int ApplicationCacheHostID() const override;
-
- bool IsMainFrame() const override;
- bool DefersLoading() const override;
- bool IsLoadComplete() const override;
- bool UpdateTimingInfoForIFrameNavigation(ResourceTimingInfo*) override;
-
- const SecurityOrigin* GetSecurityOrigin() const override;
void PopulateResourceRequest(ResourceType,
const ClientHintsPreferences&,
@@ -163,19 +141,10 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
const FetchParameters::ResourceWidth&,
ResourceRequest&);
- MHTMLArchive* Archive() const override;
-
std::unique_ptr<WebURLLoader> CreateURLLoader(
const ResourceRequest&,
const ResourceLoaderOptions&) override;
- ResourceLoadScheduler::ThrottlingPolicy InitialLoadThrottlingPolicy()
- const override {
- // Frame loading should normally start with |kTight| throttling, as the
- // frame will be in layout-blocking state until the <body> tag is inserted.
- return ResourceLoadScheduler::ThrottlingPolicy::kTight;
- }
-
bool IsDetached() const override { return frozen_state_; }
FetchContext* Detach() override;
@@ -187,30 +156,32 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
void DispatchNetworkQuiet() override;
private:
+ class FrameConsoleLogger;
friend class FrameFetchContextTest;
struct FrozenState;
- static ResourceFetcher* CreateFetcher(DocumentLoader*, Document*);
+ // TODO(altimin): This is used when creating a URLLoader, and
+ // FetchContext::GetLoadingTaskRunner is used whenever asynchronous tasks
+ // around resource loading are posted. Modify the code so that all
+ // the tasks related to loading a resource use the resource loader handle's
+ // task runner.
+ std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>
+ CreateResourceLoadingTaskRunnerHandle();
// Convenient accessors below can be used to transparently access the
// relevant document loader or frame in either cases without null-checks.
//
// TODO(kinuko): Remove constness, these return non-const members.
+ DocumentLoader* GetDocumentLoader() const;
DocumentLoader* MasterDocumentLoader() const;
LocalFrame* GetFrame() const;
LocalFrameClient* GetLocalFrameClient() const;
- LocalFrame* FrameOfImportsController() const;
// FetchContext overrides:
FrameScheduler* GetFrameScheduler() const override;
- scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() override;
- std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>
- CreateResourceLoadingTaskRunnerHandle() override;
// BaseFetchContext overrides:
- const FetchClientSettingsObject* GetFetchClientSettingsObject()
- const override;
KURL GetSiteForCookies() const override;
SubresourceFilter* GetSubresourceFilter() const override;
PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
@@ -269,8 +240,12 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
// frame's main resource.
bool IsFirstPartyOrigin(const KURL& url) const;
- Member<DocumentLoader> document_loader_;
- Member<Document> document_;
+ // Returns the origin of the top frame in the document.
+ scoped_refptr<const SecurityOrigin> GetTopFrameOrigin() const;
+
+ CoreProbeSink* Probe() const;
+
+ Member<const FrameOrImportedDocument> frame_or_imported_document_;
// The value of |save_data_enabled_| is read once per frame from
// NetworkStateNotifier, which is guarded by a mutex lock, and cached locally
@@ -279,8 +254,6 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
// Non-null only when detached.
Member<const FrozenState> frozen_state_;
-
- Member<FetchClientSettingsObject> fetch_client_settings_object_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 3703b8e444d..f87adc15f97 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -39,12 +39,13 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_client_hints_type.h"
#include "third_party/blink/public/platform/web_document_subresource_filter.h"
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
#include "third_party/blink/public/platform/web_runtime_features.h"
+#include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/ad_tracker.h"
#include "third_party/blink/renderer/core/frame/frame_owner.h"
@@ -55,11 +56,13 @@
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
+#include "third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
@@ -137,10 +140,8 @@ class FrameFetchContextTest : public testing::Test {
dummy_page_holder = DummyPageHolder::Create(IntSize(500, 500));
dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0);
document = &dummy_page_holder->GetDocument();
- fetch_context =
- static_cast<FrameFetchContext*>(&document->Fetcher()->Context());
owner = DummyFrameOwner::Create();
- FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get());
+ document->Loader()->ProvideDocumentToResourceFetcherProperties(*document);
}
void TearDown() override {
@@ -158,15 +159,19 @@ class FrameFetchContextTest : public testing::Test {
child_document = child_frame->GetDocument();
FrameFetchContext* child_fetch_context = static_cast<FrameFetchContext*>(
&child_frame->Loader().GetDocumentLoader()->Fetcher()->Context());
- FrameFetchContext::ProvideDocumentToContext(*child_fetch_context,
- child_document.Get());
+ child_document->Loader()->ProvideDocumentToResourceFetcherProperties(
+ *document);
return child_fetch_context;
}
+ FrameFetchContext* GetFetchContext() {
+ return static_cast<FrameFetchContext*>(&document->Fetcher()->Context());
+ }
+
// Call the method for the actual test cases as only this fixture is specified
// as a friend class.
void SetFirstPartyCookie(ResourceRequest& request) {
- fetch_context->SetFirstPartyCookie(request);
+ GetFetchContext()->SetFirstPartyCookie(request);
}
std::unique_ptr<DummyPageHolder> dummy_page_holder;
@@ -174,7 +179,6 @@ class FrameFetchContextTest : public testing::Test {
// around as long as the ResourceFetcher and Document live due to indirect
// usage.
Persistent<Document> document;
- Persistent<FrameFetchContext> fetch_context;
Persistent<StubLocalFrameClientWithParent> child_client;
Persistent<LocalFrame> child_frame;
@@ -225,7 +229,7 @@ class FrameFetchContextSubresourceFilterTest : public FrameFetchContextTest {
base::Optional<ResourceRequestBlockedReason> reason =
CanRequestInternal(SecurityViolationReportingPolicy::kReport);
const KURL url("http://example.com/");
- EXPECT_EQ(expect_is_ad, fetch_context->IsAdResource(
+ EXPECT_EQ(expect_is_ad, GetFetchContext()->IsAdResource(
url, ResourceType::kMock,
mojom::RequestContextType::UNSPECIFIED));
return reason;
@@ -236,7 +240,7 @@ class FrameFetchContextSubresourceFilterTest : public FrameFetchContextTest {
ResourceResponse response;
FetchInitiatorInfo initiator_info;
- fetch_context->DispatchWillSendRequest(
+ GetFetchContext()->DispatchWillSendRequest(
1, request, response, ResourceType::kImage, initiator_info);
return request.IsAdResource();
}
@@ -261,9 +265,12 @@ class FrameFetchContextSubresourceFilterTest : public FrameFetchContextTest {
resource_request.SetFetchCredentialsMode(
network::mojom::FetchCredentialsMode::kOmit);
resource_request.SetKeepalive(keepalive);
- resource_request.SetRequestorOrigin(fetch_context->GetSecurityOrigin());
+ resource_request.SetRequestorOrigin(document->Fetcher()
+ ->GetProperties()
+ .GetFetchClientSettingsObject()
+ .GetSecurityOrigin());
ResourceLoaderOptions options;
- return fetch_context->CanRequest(
+ return GetFetchContext()->CanRequest(
ResourceType::kImage, resource_request, input_url, options,
reporting_policy, ResourceRequest::RedirectStatus::kNoRedirect);
}
@@ -280,17 +287,16 @@ class FrameFetchContextMockedLocalFrameClientTest
http_url = KURL("http://example.test/foo");
main_resource_url = KURL("https://example.test");
different_host_url = KURL("https://different.example.test/foo");
- client = new testing::NiceMock<FrameFetchContextMockLocalFrameClient>();
+ client = MakeGarbageCollected<
+ testing::NiceMock<FrameFetchContextMockLocalFrameClient>>();
dummy_page_holder =
DummyPageHolder::Create(IntSize(500, 500), nullptr, client);
dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0);
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
document = &dummy_page_holder->GetDocument();
document->SetURL(main_resource_url);
- fetch_context =
- static_cast<FrameFetchContext*>(&document->Fetcher()->Context());
owner = DummyFrameOwner::Create();
- FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get());
+ document->Loader()->ProvideDocumentToResourceFetcherProperties(*document);
}
KURL url;
@@ -325,7 +331,7 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
resource_request.SetRequestContext(request_context);
resource_request.SetFrameType(frame_type);
- fetch_context->ModifyRequestForCSP(resource_request);
+ GetFetchContext()->ModifyRequestForCSP(resource_request);
EXPECT_EQ(expected_url.GetString(), resource_request.Url().GetString());
EXPECT_EQ(expected_url.Protocol(), resource_request.Url().Protocol());
@@ -345,7 +351,7 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
resource_request.SetRequestContext(mojom::RequestContextType::SCRIPT);
resource_request.SetFrameType(frame_type);
- fetch_context->ModifyRequestForCSP(resource_request);
+ GetFetchContext()->ModifyRequestForCSP(resource_request);
EXPECT_EQ(
should_prefer ? String("1") : String(),
@@ -354,7 +360,7 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
// Calling modifyRequestForCSP more than once shouldn't affect the
// header.
if (should_prefer) {
- fetch_context->ModifyRequestForCSP(resource_request);
+ GetFetchContext()->ModifyRequestForCSP(resource_request);
EXPECT_EQ("1", resource_request.HttpHeaderField(
http_names::kUpgradeInsecureRequests));
}
@@ -370,8 +376,8 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
resource_request.SetFrameType(
network::mojom::RequestContextFrameType::kNone);
- document->SetURL(main_frame_url);
- fetch_context->ModifyRequestForCSP(resource_request);
+ document->SetSecurityOrigin(SecurityOrigin::Create(KURL(main_frame_url)));
+ GetFetchContext()->ModifyRequestForCSP(resource_request);
EXPECT_EQ(expected_value, resource_request.IsAutomaticUpgrade());
}
@@ -385,7 +391,7 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
resource_request.SetRequestContext(mojom::RequestContextType::SCRIPT);
resource_request.SetFrameType(frame_type);
- fetch_context->ModifyRequestForCSP(resource_request);
+ GetFetchContext()->ModifyRequestForCSP(resource_request);
EXPECT_EQ(expected_required_csp,
resource_request.HttpHeaderField(http_names::kSecRequiredCSP));
@@ -431,7 +437,7 @@ TEST_F(FrameFetchContextModifyRequestTest, UpgradeInsecureResourceRequests) {
"ftp://example.test:1212/image.png"},
};
- FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get());
+ document->Loader()->ProvideDocumentToResourceFetcherProperties(*document);
document->SetInsecureRequestPolicy(kUpgradeInsecureRequests);
for (const auto& test : tests) {
@@ -479,7 +485,7 @@ TEST_F(FrameFetchContextModifyRequestTest, UpgradeInsecureResourceRequests) {
TEST_F(FrameFetchContextModifyRequestTest,
DoNotUpgradeInsecureResourceRequests) {
- FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get());
+ document->Loader()->ProvideDocumentToResourceFetcherProperties(*document);
document->SetSecurityOrigin(secure_origin);
document->SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone);
@@ -564,7 +570,7 @@ TEST_F(FrameFetchContextModifyRequestTest, SendUpgradeInsecureRequestHeader) {
test.should_prefer);
}
- FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get());
+ document->Loader()->ProvideDocumentToResourceFetcherProperties(*document);
for (const auto& test : tests) {
document->SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone);
@@ -643,8 +649,8 @@ class FrameFetchContextHintsTest : public FrameFetchContextTest {
const KURL input_url(input);
ResourceRequest resource_request(input_url);
- fetch_context->AddClientHintsIfNecessary(hints_preferences, resource_width,
- resource_request);
+ GetFetchContext()->AddClientHintsIfNecessary(
+ hints_preferences, resource_width, resource_request);
EXPECT_EQ(is_present ? String(header_value) : String(),
resource_request.HttpHeaderField(header_name));
@@ -655,8 +661,8 @@ class FrameFetchContextHintsTest : public FrameFetchContextTest {
FetchParameters::ResourceWidth resource_width;
const KURL input_url(input);
ResourceRequest resource_request(input_url);
- fetch_context->AddClientHintsIfNecessary(hints_preferences, resource_width,
- resource_request);
+ GetFetchContext()->AddClientHintsIfNecessary(
+ hints_preferences, resource_width, resource_request);
return resource_request.HttpHeaderField(header_name);
}
};
@@ -836,21 +842,21 @@ TEST_F(FrameFetchContextTest, MainResourceCachePolicy) {
ResourceRequest request("http://www.example.com");
EXPECT_EQ(
mojom::FetchCacheMode::kDefault,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMainResource, FetchParameters::kNoDefer));
// Post
ResourceRequest post_request("http://www.example.com");
post_request.SetHTTPMethod(http_names::kPOST);
EXPECT_EQ(mojom::FetchCacheMode::kValidateCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
post_request, ResourceType::kMainResource,
FetchParameters::kNoDefer));
// Re-post
document->Loader()->SetLoadType(WebFrameLoadType::kBackForward);
EXPECT_EQ(mojom::FetchCacheMode::kOnlyIfCached,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
post_request, ResourceType::kMainResource,
FetchParameters::kNoDefer));
@@ -858,7 +864,7 @@ TEST_F(FrameFetchContextTest, MainResourceCachePolicy) {
document->Loader()->SetLoadType(WebFrameLoadType::kReload);
EXPECT_EQ(
mojom::FetchCacheMode::kValidateCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMainResource, FetchParameters::kNoDefer));
// Conditional request
@@ -867,27 +873,27 @@ TEST_F(FrameFetchContextTest, MainResourceCachePolicy) {
conditional.SetHTTPHeaderField(http_names::kIfModifiedSince, "foo");
EXPECT_EQ(
mojom::FetchCacheMode::kValidateCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
conditional, ResourceType::kMainResource, FetchParameters::kNoDefer));
// WebFrameLoadType::kReloadBypassingCache
document->Loader()->SetLoadType(WebFrameLoadType::kReloadBypassingCache);
EXPECT_EQ(
mojom::FetchCacheMode::kBypassCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMainResource, FetchParameters::kNoDefer));
// WebFrameLoadType::kReloadBypassingCache with a conditional request
document->Loader()->SetLoadType(WebFrameLoadType::kReloadBypassingCache);
EXPECT_EQ(
mojom::FetchCacheMode::kBypassCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
conditional, ResourceType::kMainResource, FetchParameters::kNoDefer));
// WebFrameLoadType::kReloadBypassingCache with a post request
document->Loader()->SetLoadType(WebFrameLoadType::kReloadBypassingCache);
EXPECT_EQ(mojom::FetchCacheMode::kBypassCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
post_request, ResourceType::kMainResource,
FetchParameters::kNoDefer));
@@ -936,13 +942,13 @@ TEST_F(FrameFetchContextTest, SubResourceCachePolicy) {
// Default case
ResourceRequest request("http://www.example.com/mock");
EXPECT_EQ(mojom::FetchCacheMode::kDefault,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMock, FetchParameters::kNoDefer));
// WebFrameLoadType::kReload should not affect sub-resources
document->Loader()->SetLoadType(WebFrameLoadType::kReload);
EXPECT_EQ(mojom::FetchCacheMode::kDefault,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMock, FetchParameters::kNoDefer));
// Conditional request
@@ -950,31 +956,31 @@ TEST_F(FrameFetchContextTest, SubResourceCachePolicy) {
ResourceRequest conditional("http://www.example.com/mock");
conditional.SetHTTPHeaderField(http_names::kIfModifiedSince, "foo");
EXPECT_EQ(mojom::FetchCacheMode::kValidateCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
conditional, ResourceType::kMock, FetchParameters::kNoDefer));
// WebFrameLoadType::kReloadBypassingCache
document->Loader()->SetLoadType(WebFrameLoadType::kReloadBypassingCache);
EXPECT_EQ(mojom::FetchCacheMode::kBypassCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMock, FetchParameters::kNoDefer));
// WebFrameLoadType::kReloadBypassingCache with a conditional request
document->Loader()->SetLoadType(WebFrameLoadType::kReloadBypassingCache);
EXPECT_EQ(mojom::FetchCacheMode::kBypassCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
conditional, ResourceType::kMock, FetchParameters::kNoDefer));
// Back/forward navigation
document->Loader()->SetLoadType(WebFrameLoadType::kBackForward);
EXPECT_EQ(mojom::FetchCacheMode::kForceCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kMock, FetchParameters::kNoDefer));
// Back/forward navigation with a conditional request
document->Loader()->SetLoadType(WebFrameLoadType::kBackForward);
EXPECT_EQ(mojom::FetchCacheMode::kForceCache,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
conditional, ResourceType::kMock, FetchParameters::kNoDefer));
}
@@ -988,7 +994,7 @@ TEST_F(FrameFetchContextTest, ModifyPriorityForLowPriorityIframes) {
// Experiment is not enabled, expect default values.
EXPECT_EQ(ResourceLoadPriority::kVeryHigh,
- fetch_context->ModifyPriorityForExperiments(
+ GetFetchContext()->ModifyPriorityForExperiments(
ResourceLoadPriority::kVeryHigh));
EXPECT_EQ(ResourceLoadPriority::kVeryHigh,
childFetchContext->ModifyPriorityForExperiments(
@@ -1001,7 +1007,7 @@ TEST_F(FrameFetchContextTest, ModifyPriorityForLowPriorityIframes) {
// values.
settings->SetLowPriorityIframesThreshold(WebEffectiveConnectionType::kType2G);
EXPECT_EQ(ResourceLoadPriority::kVeryHigh,
- fetch_context->ModifyPriorityForExperiments(
+ GetFetchContext()->ModifyPriorityForExperiments(
ResourceLoadPriority::kVeryHigh));
EXPECT_EQ(ResourceLoadPriority::kVeryHigh,
childFetchContext->ModifyPriorityForExperiments(
@@ -1017,7 +1023,7 @@ TEST_F(FrameFetchContextTest, ModifyPriorityForLowPriorityIframes) {
WebEffectiveConnectionType::kType2G, 1 /* http_rtt_msec */,
10.0 /* max_bandwidth_mbps */);
EXPECT_EQ(ResourceLoadPriority::kVeryHigh,
- fetch_context->ModifyPriorityForExperiments(
+ GetFetchContext()->ModifyPriorityForExperiments(
ResourceLoadPriority::kVeryHigh));
// Low priority iframes enabled, everything in child frame should be low
// priority.
@@ -1036,14 +1042,14 @@ TEST_F(FrameFetchContextTest, EnableDataSaver) {
RecreateFetchContext();
ResourceRequest resource_request("http://www.example.com");
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data"));
// Subsequent call to addAdditionalRequestHeaders should not append to the
// save-data header.
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data"));
}
@@ -1054,8 +1060,8 @@ TEST_F(FrameFetchContextTest, DisabledDataSaver) {
RecreateFetchContext();
ResourceRequest resource_request("http://www.example.com");
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ(String(), resource_request.HttpHeaderField("Save-Data"));
}
@@ -1065,35 +1071,35 @@ TEST_F(FrameFetchContextTest, ChangeDataSaverConfig) {
// Recreate the fetch context so that the updated save data settings are read.
RecreateFetchContext();
ResourceRequest resource_request("http://www.example.com");
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data"));
GetNetworkStateNotifier().SetSaveDataEnabledOverride(false);
RecreateFetchContext();
document->Loader()->SetLoadType(WebFrameLoadType::kReload);
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ(String(), resource_request.HttpHeaderField("Save-Data"));
GetNetworkStateNotifier().SetSaveDataEnabledOverride(true);
RecreateFetchContext();
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data"));
GetNetworkStateNotifier().SetSaveDataEnabledOverride(false);
RecreateFetchContext();
document->Loader()->SetLoadType(WebFrameLoadType::kReload);
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ(String(), resource_request.HttpHeaderField("Save-Data"));
}
// Tests that the embedder gets correct notification when a resource is loaded
// from the memory cache.
TEST_F(FrameFetchContextMockedLocalFrameClientTest,
- DispatchDidLoadResourceFromMemoryCache) {
+ LoadResourceFromMemoryCache) {
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::IMAGE);
resource_request.SetFetchCredentialsMode(
@@ -1108,9 +1114,10 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
network::mojom::RequestContextFrameType::kNone),
testing::Property(&ResourceRequest::GetRequestContext,
mojom::RequestContextType::IMAGE)),
- ResourceResponse()));
- fetch_context->DispatchDidLoadResourceFromMemoryCache(
- CreateUniqueIdentifier(), resource_request, resource->GetResponse());
+ testing::Property(&ResourceResponse::IsNull, true)));
+ GetFetchContext()->DispatchDidReceiveResponse(
+ CreateUniqueIdentifier(), resource_request, resource->GetResponse(),
+ resource, FetchContext::ResourceResponseType::kFromMemoryCache);
}
// Tests that when a resource with certificate errors is loaded from the memory
@@ -1126,8 +1133,9 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
Resource* resource = MockResource::Create(resource_request);
resource->SetResponse(response);
EXPECT_CALL(*client, DidDisplayContentWithCertificateErrors());
- fetch_context->DispatchDidLoadResourceFromMemoryCache(
- CreateUniqueIdentifier(), resource_request, resource->GetResponse());
+ GetFetchContext()->DispatchDidReceiveResponse(
+ CreateUniqueIdentifier(), resource_request, resource->GetResponse(),
+ resource, FetchContext::ResourceResponseType::kFromMemoryCache);
}
TEST_F(FrameFetchContextSubresourceFilterTest, Filter) {
@@ -1194,7 +1202,7 @@ TEST_F(FrameFetchContextTest, AddAdditionalRequestHeadersWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->AddAdditionalRequestHeaders(request, kFetchSubresource);
+ GetFetchContext()->AddAdditionalRequestHeaders(request, kFetchSubresource);
EXPECT_EQ(origin, request.HttpHeaderField(http_names::kOrigin));
EXPECT_EQ(String(origin + "/"),
@@ -1208,14 +1216,14 @@ TEST_F(FrameFetchContextTest, ResourceRequestCachePolicyWhenDetached) {
dummy_page_holder = nullptr;
EXPECT_EQ(mojom::FetchCacheMode::kDefault,
- fetch_context->ResourceRequestCachePolicy(
+ GetFetchContext()->ResourceRequestCachePolicy(
request, ResourceType::kRaw, FetchParameters::kNoDefer));
}
TEST_F(FrameFetchContextTest, DispatchDidChangePriorityWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchDidChangeResourcePriority(
+ GetFetchContext()->DispatchDidChangeResourcePriority(
2, ResourceLoadPriority::kLow, 3);
// Should not crash.
}
@@ -1233,8 +1241,10 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
checkpoint.Call(2);
ResourceRequest request(KURL("https://localhost/"));
- fetch_context->PrepareRequest(request,
- FetchContext::RedirectType::kNotForRedirect);
+ WebScopedVirtualTimePauser virtual_time_pauser;
+ GetFetchContext()->PrepareRequest(
+ request, virtual_time_pauser,
+ FetchContext::RedirectType::kNotForRedirect);
EXPECT_EQ("hi", request.HttpHeaderField(http_names::kUserAgent));
}
@@ -1246,20 +1256,8 @@ TEST_F(FrameFetchContextTest, DispatchWillSendRequestWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchWillSendRequest(1, request, response,
- ResourceType::kRaw, initiator_info);
- // Should not crash.
-}
-
-TEST_F(FrameFetchContextTest,
- DispatchDidLoadResourceFromMemoryCacheWhenDetached) {
- ResourceRequest request(KURL("https://www.example.com/"));
- ResourceResponse response;
- FetchInitiatorInfo initiator_info;
-
- dummy_page_holder = nullptr;
-
- fetch_context->DispatchDidLoadResourceFromMemoryCache(8, request, response);
+ GetFetchContext()->DispatchWillSendRequest(
+ 1, request, response, ResourceType::kRaw, initiator_info);
// Should not crash.
}
@@ -1271,9 +1269,8 @@ TEST_F(FrameFetchContextTest, DispatchDidReceiveResponseWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchDidReceiveResponse(
- 3, response, network::mojom::RequestContextFrameType::kTopLevel,
- mojom::RequestContextType::FETCH, resource,
+ GetFetchContext()->DispatchDidReceiveResponse(
+ 3, request, response, resource,
FetchContext::ResourceResponseType::kNotFromMemoryCache);
// Should not crash.
}
@@ -1281,41 +1278,41 @@ TEST_F(FrameFetchContextTest, DispatchDidReceiveResponseWhenDetached) {
TEST_F(FrameFetchContextTest, DispatchDidReceiveDataWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchDidReceiveData(3, "abcd", 4);
+ GetFetchContext()->DispatchDidReceiveData(3, "abcd", 4);
// Should not crash.
}
TEST_F(FrameFetchContextTest, DispatchDidReceiveEncodedDataWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchDidReceiveEncodedData(8, 9);
+ GetFetchContext()->DispatchDidReceiveEncodedData(8, 9);
// Should not crash.
}
TEST_F(FrameFetchContextTest, DispatchDidFinishLoadingWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchDidFinishLoading(4, TimeTicksFromSeconds(0.3), 8, 10,
- false);
+ GetFetchContext()->DispatchDidFinishLoading(4, TimeTicksFromSeconds(0.3), 8,
+ 10, false);
// Should not crash.
}
TEST_F(FrameFetchContextTest, DispatchDidFailWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DispatchDidFail(KURL(), 8, ResourceError::Failure(NullURL()),
- 5, false);
+ GetFetchContext()->DispatchDidFail(
+ KURL(), 8, ResourceError::Failure(NullURL()), 5, false);
// Should not crash.
}
TEST_F(FrameFetchContextTest, ShouldLoadNewResourceWhenDetached) {
dummy_page_holder = nullptr;
- EXPECT_FALSE(fetch_context->ShouldLoadNewResource(ResourceType::kImage));
- EXPECT_FALSE(fetch_context->ShouldLoadNewResource(ResourceType::kRaw));
- EXPECT_FALSE(fetch_context->ShouldLoadNewResource(ResourceType::kScript));
+ EXPECT_FALSE(GetFetchContext()->ShouldLoadNewResource(ResourceType::kImage));
+ EXPECT_FALSE(GetFetchContext()->ShouldLoadNewResource(ResourceType::kRaw));
+ EXPECT_FALSE(GetFetchContext()->ShouldLoadNewResource(ResourceType::kScript));
EXPECT_FALSE(
- fetch_context->ShouldLoadNewResource(ResourceType::kMainResource));
+ GetFetchContext()->ShouldLoadNewResource(ResourceType::kMainResource));
}
TEST_F(FrameFetchContextTest, RecordLoadingActivityWhenDetached) {
@@ -1323,12 +1320,12 @@ TEST_F(FrameFetchContextTest, RecordLoadingActivityWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->RecordLoadingActivity(
+ GetFetchContext()->RecordLoadingActivity(
request, ResourceType::kRaw, fetch_initiator_type_names::kXmlhttprequest);
// Should not crash.
- fetch_context->RecordLoadingActivity(request, ResourceType::kRaw,
- fetch_initiator_type_names::kDocument);
+ GetFetchContext()->RecordLoadingActivity(
+ request, ResourceType::kRaw, fetch_initiator_type_names::kDocument);
// Should not crash.
}
@@ -1339,7 +1336,7 @@ TEST_F(FrameFetchContextTest, DidLoadResourceWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->DidLoadResource(resource);
+ GetFetchContext()->DidLoadResource(resource);
// Should not crash.
}
@@ -1349,7 +1346,7 @@ TEST_F(FrameFetchContextTest, AddResourceTimingWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->AddResourceTiming(*info);
+ GetFetchContext()->AddResourceTiming(*info);
// Should not crash.
}
@@ -1358,67 +1355,8 @@ TEST_F(FrameFetchContextTest, AllowImageWhenDetached) {
dummy_page_holder = nullptr;
- EXPECT_TRUE(fetch_context->AllowImage(true, url));
- EXPECT_TRUE(fetch_context->AllowImage(false, url));
-}
-
-TEST_F(FrameFetchContextTest, IsControlledByServiceWorkerWhenDetached) {
- dummy_page_holder = nullptr;
-
- EXPECT_EQ(blink::mojom::ControllerServiceWorkerMode::kNoController,
- fetch_context->IsControlledByServiceWorker());
-}
-
-TEST_F(FrameFetchContextTest, IsMainFrameWhenDetached) {
- FetchContext* child_fetch_context = CreateChildFrame();
-
- EXPECT_TRUE(fetch_context->IsMainFrame());
- EXPECT_FALSE(child_fetch_context->IsMainFrame());
-
- dummy_page_holder = nullptr;
-
- EXPECT_TRUE(fetch_context->IsMainFrame());
- EXPECT_FALSE(child_fetch_context->IsMainFrame());
-}
-
-TEST_F(FrameFetchContextTest, DefersLoadingWhenDetached) {
- EXPECT_FALSE(fetch_context->DefersLoading());
-}
-
-TEST_F(FrameFetchContextTest, IsLoadCompleteWhenDetached_1) {
- document->open();
- EXPECT_FALSE(fetch_context->IsLoadComplete());
-
- dummy_page_holder = nullptr;
-
- EXPECT_TRUE(fetch_context->IsLoadComplete());
-}
-
-TEST_F(FrameFetchContextTest, IsLoadCompleteWhenDetached_2) {
- EXPECT_TRUE(fetch_context->IsLoadComplete());
-
- dummy_page_holder = nullptr;
-
- EXPECT_TRUE(fetch_context->IsLoadComplete());
-}
-
-TEST_F(FrameFetchContextTest, UpdateTimingInfoForIFrameNavigationWhenDetached) {
- scoped_refptr<ResourceTimingInfo> info =
- ResourceTimingInfo::Create("type", TimeTicksFromSeconds(0.3), false);
-
- dummy_page_holder = nullptr;
-
- fetch_context->UpdateTimingInfoForIFrameNavigation(info.get());
- // Should not crash.
-}
-
-TEST_F(FrameFetchContextTest, GetSecurityOriginWhenDetached) {
- scoped_refptr<SecurityOrigin> origin =
- SecurityOrigin::Create(KURL("https://www.example.com"));
- document->SetSecurityOrigin(origin);
-
- dummy_page_holder = nullptr;
- EXPECT_EQ(origin.get(), fetch_context->GetSecurityOrigin());
+ EXPECT_TRUE(GetFetchContext()->AllowImage(true, url));
+ EXPECT_TRUE(GetFetchContext()->AllowImage(false, url));
}
TEST_F(FrameFetchContextTest, PopulateResourceRequestWhenDetached) {
@@ -1450,7 +1388,7 @@ TEST_F(FrameFetchContextTest, PopulateResourceRequestWhenDetached) {
dummy_page_holder = nullptr;
- fetch_context->PopulateResourceRequest(
+ GetFetchContext()->PopulateResourceRequest(
ResourceType::kRaw, client_hints_preferences, resource_width, request);
// Should not crash.
}
@@ -1472,16 +1410,6 @@ TEST_F(FrameFetchContextTest, SetFirstPartyCookieWhenDetached) {
EXPECT_EQ(document_url.GetString(), request.SiteForCookies().GetString());
}
-TEST_F(FrameFetchContextTest, ArchiveWhenDetached) {
- FetchContext* child_fetch_context = CreateChildFrame();
-
- dummy_page_holder = nullptr;
- child_frame->Detach(FrameDetachType::kRemove);
- child_frame = nullptr;
-
- EXPECT_EQ(nullptr, child_fetch_context->Archive());
-}
-
// Tests if "Intervention" header is added for frame with Client Lo-Fi enabled.
TEST_F(FrameFetchContextMockedLocalFrameClientTest,
ClientLoFiInterventionHeader) {
@@ -1489,15 +1417,15 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
EXPECT_CALL(*client, GetPreviewsStateForFrame())
.WillRepeatedly(testing::Return(WebURLRequest::kPreviewsOff));
ResourceRequest resource_request("http://www.example.com/style.css");
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ(g_null_atom, resource_request.HttpHeaderField("Intervention"));
// Verify header is added if Lo-Fi is active.
EXPECT_CALL(*client, GetPreviewsStateForFrame())
.WillRepeatedly(testing::Return(WebURLRequest::kClientLoFiOn));
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchSubresource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchSubresource);
EXPECT_EQ(
"<https://www.chromestatus.com/features/6072546726248448>; "
"level=\"warning\"",
@@ -1507,8 +1435,8 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
ResourceRequest resource_request2("http://www.example.com/getad.js");
resource_request2.SetHTTPHeaderField("Intervention",
"<https://otherintervention.org>");
- fetch_context->AddAdditionalRequestHeaders(resource_request2,
- kFetchSubresource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request2,
+ kFetchSubresource);
EXPECT_EQ(
"<https://otherintervention.org>, "
"<https://www.chromestatus.com/features/6072546726248448>; "
@@ -1523,15 +1451,15 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
EXPECT_CALL(*client, GetPreviewsStateForFrame())
.WillRepeatedly(testing::Return(WebURLRequest::kPreviewsOff));
ResourceRequest resource_request("http://www.example.com/style.css");
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchMainResource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchMainResource);
EXPECT_EQ(g_null_atom, resource_request.HttpHeaderField("Intervention"));
// Verify header is added if NoScript is active.
EXPECT_CALL(*client, GetPreviewsStateForFrame())
.WillRepeatedly(testing::Return(WebURLRequest::kNoScriptOn));
- fetch_context->AddAdditionalRequestHeaders(resource_request,
- kFetchSubresource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request,
+ kFetchSubresource);
EXPECT_EQ(
"<https://www.chromestatus.com/features/4775088607985664>; "
"level=\"warning\"",
@@ -1541,8 +1469,8 @@ TEST_F(FrameFetchContextMockedLocalFrameClientTest,
ResourceRequest resource_request2("http://www.example.com/getad.js");
resource_request2.SetHTTPHeaderField("Intervention",
"<https://otherintervention.org>");
- fetch_context->AddAdditionalRequestHeaders(resource_request2,
- kFetchSubresource);
+ GetFetchContext()->AddAdditionalRequestHeaders(resource_request2,
+ kFetchSubresource);
EXPECT_EQ(
"<https://otherintervention.org>, "
"<https://www.chromestatus.com/features/4775088607985664>; "
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc b/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc
index fa6fdde3d35..4759315680b 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc
@@ -51,8 +51,7 @@ FrameLoadRequest::FrameLoadRequest(
if (origin_document) {
DCHECK(!resource_request_.RequestorOrigin());
- resource_request_.SetRequestorOrigin(
- SecurityOrigin::Create(origin_document->Url()));
+ resource_request_.SetRequestorOrigin(origin_document->GetSecurityOrigin());
if (resource_request.Url().ProtocolIs("blob") &&
BlobUtils::MojoBlobURLsEnabled()) {
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
index 0501516a6c7..b6bdefc799a 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -42,8 +42,8 @@
#include "base/unguessable_token.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/frame/navigation_initiator.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
@@ -78,7 +78,6 @@
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/form_submission.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
-#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/loader/navigation_scheduler.h"
#include "third_party/blink/renderer/core/loader/network_hints_interface.h"
@@ -87,6 +86,7 @@
#include "third_party/blink/renderer/core/page/create_window.h"
#include "third_party/blink/renderer/core/page/frame_tree.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -97,6 +97,7 @@
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
#include "third_party/blink/renderer/platform/instance_counters.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
@@ -105,15 +106,12 @@
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/plugins/plugin_script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-using blink::WebURLRequest;
-
namespace blink {
using namespace html_names;
@@ -220,6 +218,7 @@ void FrameLoader::Trace(blink::Visitor* visitor) {
visitor->Trace(progress_tracker_);
visitor->Trace(document_loader_);
visitor->Trace(provisional_document_loader_);
+ visitor->Trace(last_origin_document_csp_);
}
void FrameLoader::Init() {
@@ -233,11 +232,10 @@ void FrameLoader::Init() {
initial_request.SetHasUserGesture(
LocalFrame::HasTransientUserActivation(frame_));
+ auto navigation_params = std::make_unique<WebNavigationParams>();
+ navigation_params->request = WrappedResourceRequest(initial_request);
provisional_document_loader_ = CreateDocumentLoader(
- initial_request, SubstituteData(),
- ClientRedirectPolicy::kNotClientRedirect,
- base::UnguessableToken::Create(), WebFrameLoadType::kStandard,
- kWebNavigationTypeOther, nullptr /* navigation_params */,
+ kWebNavigationTypeOther, std::move(navigation_params),
nullptr /* extra_data */);
provisional_document_loader_->StartLoading();
@@ -260,17 +258,19 @@ LocalFrameClient* FrameLoader::Client() const {
}
void FrameLoader::SetDefersLoading(bool defers) {
- if (provisional_document_loader_)
- provisional_document_loader_->Fetcher()->SetDefersLoading(defers);
-
if (Document* document = frame_->GetDocument()) {
document->Fetcher()->SetDefersLoading(defers);
if (defers)
- document->PauseScheduledTasks();
+ document->PauseScheduledTasks(PauseState::kPaused);
else
document->UnpauseScheduledTasks();
}
+ if (document_loader_)
+ document_loader_->SetDefersLoading(defers);
+ if (provisional_document_loader_)
+ provisional_document_loader_->SetDefersLoading(defers);
+
if (!defers)
frame_->GetNavigationScheduler().StartTimer();
}
@@ -392,7 +392,10 @@ void FrameLoader::ReplaceDocumentWhileExecutingJavaScriptURL(
? WebGlobalObjectReusePolicy::kUseExisting
: WebGlobalObjectReusePolicy::kCreateNew;
- StopAllLoaders();
+ document_loader_->StopLoading();
+ DetachDocumentLoader(provisional_document_loader_);
+ frame_->GetNavigationScheduler().Cancel();
+
// Don't allow any new child frames to load in this frame: attaching a new
// child frame during or after detaching children results in an attached
// frame on a detached DOM tree, which is bad.
@@ -650,7 +653,8 @@ void FrameLoader::SetReferrerForFrameRequest(FrameLoadRequest& frame_request) {
}
WebFrameLoadType FrameLoader::DetermineFrameLoadType(
- const ResourceRequest& resource_request,
+ const KURL& url,
+ const AtomicString& http_method,
Document* origin_document,
const KURL& failing_url,
WebFrameLoadType frame_load_type) {
@@ -666,17 +670,13 @@ WebFrameLoadType FrameLoader::DetermineFrameLoadType(
!state_machine_.CommittedFirstRealDocumentLoad())
return WebFrameLoadType::kReplaceCurrentItem;
if (!frame_->Tree().Parent() && !Client()->BackForwardLength()) {
- if (Opener() && resource_request.Url().IsEmpty())
+ if (Opener() && url.IsEmpty())
return WebFrameLoadType::kReplaceCurrentItem;
return WebFrameLoadType::kStandard;
}
}
if (frame_load_type != WebFrameLoadType::kStandard)
return frame_load_type;
- CHECK_NE(mojom::FetchCacheMode::kValidateCache,
- resource_request.GetCacheMode());
- CHECK_NE(mojom::FetchCacheMode::kBypassCache,
- resource_request.GetCacheMode());
// From the HTML5 spec for location.assign():
// "If the browsing context's session history contains only one Document,
// and that was the about:blank Document created when the browsing context
@@ -685,8 +685,8 @@ WebFrameLoadType FrameLoader::DetermineFrameLoadType(
DeprecatedEqualIgnoringCase(frame_->GetDocument()->Url(), BlankURL())))
return WebFrameLoadType::kReplaceCurrentItem;
- if (resource_request.Url() == document_loader_->UrlForHistory()) {
- if (resource_request.HttpMethod() == http_names::kPOST)
+ if (url == document_loader_->UrlForHistory()) {
+ if (http_method == http_names::kPOST)
return WebFrameLoadType::kStandard;
if (!origin_document)
return WebFrameLoadType::kReload;
@@ -697,7 +697,7 @@ WebFrameLoadType FrameLoader::DetermineFrameLoadType(
document_loader_->LoadType() == WebFrameLoadType::kReload)
return WebFrameLoadType::kReload;
- if (resource_request.Url().IsEmpty() && failing_url.IsEmpty()) {
+ if (url.IsEmpty() && failing_url.IsEmpty()) {
return WebFrameLoadType::kReplaceCurrentItem;
}
@@ -714,8 +714,23 @@ bool FrameLoader::PrepareRequestForThisFrame(FrameLoadRequest& request) {
return true;
KURL url = request.GetResourceRequest().Url();
- if (frame_->GetScriptController().ExecuteScriptIfJavaScriptURL(url, nullptr))
- return false;
+ if (url.ProtocolIsJavaScript()) {
+ Document* origin_document = request.OriginDocument();
+ // Check the CSP of the caller (the "source browsing context") if required,
+ // as per https://html.spec.whatwg.org/#javascript-protocol.
+ bool javascript_url_is_allowed =
+ request.ShouldCheckMainWorldContentSecurityPolicy() ==
+ kDoNotCheckContentSecurityPolicy ||
+ origin_document->GetContentSecurityPolicy()->AllowJavaScriptURLs(
+ frame_->DeprecatedLocalOwner(), url.GetString(),
+ origin_document->Url(), OrdinalNumber::First());
+
+ if (!javascript_url_is_allowed)
+ return false;
+
+ if (frame_->Owner() && frame_->Owner()->GetSandboxFlags() & kSandboxOrigin)
+ return false;
+ }
if (!request.OriginDocument()->GetSecurityOrigin()->CanDisplay(url)) {
request.OriginDocument()->AddConsoleMessage(ConsoleMessage::Create(
@@ -864,8 +879,9 @@ void FrameLoader::StartNavigation(const FrameLoadRequest& passed_request,
return;
}
- frame_load_type = DetermineFrameLoadType(resource_request, origin_document,
- KURL(), frame_load_type);
+ frame_load_type = DetermineFrameLoadType(
+ resource_request.Url(), resource_request.HttpMethod(), origin_document,
+ KURL(), frame_load_type);
bool same_document_navigation =
policy == kNavigationPolicyCurrentTab &&
@@ -892,16 +908,23 @@ void FrameLoader::StartNavigation(const FrameLoadRequest& passed_request,
: network::mojom::RequestContextFrameType::kNested);
mojom::blink::NavigationInitiatorPtr navigation_initiator;
+ WebContentSecurityPolicyList initiator_csp;
if (origin_document && origin_document->GetContentSecurityPolicy()
->ExperimentalFeaturesEnabled()) {
- WebContentSecurityPolicyList initiator_csp =
- origin_document->GetContentSecurityPolicy()
- ->ExposeForNavigationalChecks();
- resource_request.SetInitiatorCSP(initiator_csp);
+ initiator_csp = origin_document->GetContentSecurityPolicy()
+ ->ExposeForNavigationalChecks();
auto request = mojo::MakeRequest(&navigation_initiator);
origin_document->BindNavigationInitiatorRequest(std::move(request));
}
+ if (origin_document && origin_document->GetContentSecurityPolicy()) {
+ last_origin_document_csp_ = ContentSecurityPolicy::Create();
+ last_origin_document_csp_->CopyStateFrom(
+ origin_document->GetContentSecurityPolicy());
+ last_origin_document_csp_->CopyPluginTypesFrom(
+ origin_document->GetContentSecurityPolicy());
+ }
+
// Record the latest requiredCSP value that will be used when sending this
// request.
RecordLatestRequiredCSP();
@@ -941,6 +964,12 @@ void FrameLoader::StartNavigation(const FrameLoadRequest& passed_request,
LocalFrame::ConsumeTransientUserActivation(frame_);
}
+ if (url.ProtocolIsJavaScript()) {
+ frame_->GetDocument()->ProcessJavaScriptUrl(
+ url, request.ShouldCheckMainWorldContentSecurityPolicy());
+ return;
+ }
+
Client()->BeginNavigation(
resource_request, origin_document, nullptr /* document_loader */,
navigation_type, policy, has_transient_activation, frame_load_type,
@@ -948,16 +977,11 @@ void FrameLoader::StartNavigation(const FrameLoadRequest& passed_request,
request.TriggeringEventInfo(), request.Form(),
request.ShouldCheckMainWorldContentSecurityPolicy(),
request.GetBlobURLToken(), request.GetInputStartTime(),
- request.HrefTranslate().GetString(), std::move(navigation_initiator));
+ request.HrefTranslate().GetString(), std::move(initiator_csp),
+ std::move(navigation_initiator));
}
void FrameLoader::CommitNavigation(
- const ResourceRequest& request,
- const SubstituteData& substitute_data,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType frame_load_type,
- HistoryItem* history_item,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DCHECK(frame_->GetDocument());
@@ -981,7 +1005,8 @@ void FrameLoader::CommitNavigation(
if (HTMLFrameOwnerElement* element = frame_->DeprecatedLocalOwner())
element->CancelPendingLazyLoad();
- ResourceRequest resource_request = request;
+ ResourceRequest& resource_request =
+ navigation_params->request.ToMutableResourceRequest();
resource_request.SetHasUserGesture(
LocalFrame::HasTransientUserActivation(frame_));
resource_request.SetFetchRequestMode(
@@ -991,9 +1016,10 @@ void FrameLoader::CommitNavigation(
resource_request.SetFetchRedirectMode(
network::mojom::FetchRedirectMode::kManual);
- frame_load_type =
- DetermineFrameLoadType(resource_request, nullptr /* origin_document */,
- substitute_data.FailingURL(), frame_load_type);
+ navigation_params->frame_load_type = DetermineFrameLoadType(
+ resource_request.Url(), resource_request.HttpMethod(),
+ nullptr /* origin_document */, navigation_params->unreachable_url,
+ navigation_params->frame_load_type);
// Note: we might actually classify this navigation as same document
// right here in the following circumstances:
@@ -1007,7 +1033,9 @@ void FrameLoader::CommitNavigation(
RecordLatestRequiredCSP();
if (!CancelProvisionalLoaderForNewNavigation(
- false /* cancel_scheduled_navigations */)) {
+ false /* cancel_scheduled_navigations */,
+ DocumentLoader::WillLoadUrlAsEmpty(
+ navigation_params->request.Url()))) {
return;
}
@@ -1015,7 +1043,8 @@ void FrameLoader::CommitNavigation(
// It seems incorrect to pass |false| for |have_event| and then use
// determined navigation type to update resource request.
WebNavigationType navigation_type = DetermineNavigationType(
- frame_load_type, resource_request.HttpBody(), false /* have_event */);
+ navigation_params->frame_load_type, resource_request.HttpBody(),
+ false /* have_event */);
// TODO(dgozman): should these fields be propagated from StartNavigation
// and/or set by the caller instead?
resource_request.SetRequestContext(
@@ -1024,22 +1053,23 @@ void FrameLoader::CommitNavigation(
frame_->IsMainFrame() ? network::mojom::RequestContextFrameType::kTopLevel
: network::mojom::RequestContextFrameType::kNested);
+ HistoryItem* history_item = nullptr;
+ if (IsBackForwardLoadType(navigation_params->frame_load_type)) {
+ history_item = navigation_params->history_item;
+ DCHECK(history_item);
+ }
+
// TODO(dgozman): get rid of provisional document loader and most of the code
// below. We should probably call DocumentLoader::CommitNavigation directly.
provisional_document_loader_ = CreateDocumentLoader(
- resource_request, substitute_data, client_redirect_policy,
- devtools_navigation_token, frame_load_type, navigation_type,
- std::move(navigation_params), std::move(extra_data));
+ navigation_type, std::move(navigation_params), std::move(extra_data));
provisional_document_loader_->AppendRedirect(
provisional_document_loader_->Url());
- if (IsBackForwardLoadType(frame_load_type)) {
- DCHECK(history_item);
+ if (history_item)
provisional_document_loader_->SetItemForHistoryNavigation(history_item);
- }
frame_->GetFrameScheduler()->DidStartProvisionalLoad(frame_->IsMainFrame());
- Client()->DispatchDidStartProvisionalLoad(provisional_document_loader_,
- resource_request);
+ Client()->DispatchDidStartProvisionalLoad(provisional_document_loader_);
probe::didStartProvisionalLoad(frame_);
virtual_time_pauser_.PauseVirtualTime();
@@ -1096,22 +1126,22 @@ mojom::CommitResult FrameLoader::CommitSameDocumentNavigation(
}
bool FrameLoader::CreatePlaceholderDocumentLoader(
- const ResourceRequest& resource_request,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType frame_load_type,
- WebNavigationType navigation_type,
- std::unique_ptr<WebNavigationParams> navigation_params,
+ const WebNavigationInfo& info,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
if (!CancelProvisionalLoaderForNewNavigation(
- true /* cancel_scheduled_navigations */)) {
+ true /* cancel_scheduled_navigations */,
+ false /* is_starting_blank_navigation */)) {
return false;
}
- provisional_document_loader_ = CreateDocumentLoader(
- resource_request, SubstituteData(), client_redirect_policy,
- devtools_navigation_token, frame_load_type, navigation_type,
- std::move(navigation_params), std::move(extra_data));
+ auto navigation_params = std::make_unique<WebNavigationParams>();
+ navigation_params->request = info.url_request;
+ navigation_params->frame_load_type = info.frame_load_type;
+ navigation_params->is_client_redirect = info.is_client_redirect;
+ navigation_params->navigation_timings.input_start = info.input_start;
+ provisional_document_loader_ =
+ CreateDocumentLoader(info.navigation_type, std::move(navigation_params),
+ std::move(extra_data));
provisional_document_loader_->AppendRedirect(
provisional_document_loader_->Url());
frame_->GetFrameScheduler()->DidStartProvisionalLoad(frame_->IsMainFrame());
@@ -1121,17 +1151,6 @@ bool FrameLoader::CreatePlaceholderDocumentLoader(
return true;
}
-SubstituteData FrameLoader::DefaultSubstituteDataForURL(const KURL& url) {
- if (!ShouldTreatURLAsSrcdocDocument(url))
- return SubstituteData();
- String srcdoc = frame_->DeprecatedLocalOwner()->FastGetAttribute(kSrcdocAttr);
- DCHECK(!srcdoc.IsNull());
- CString encoded_srcdoc = srcdoc.Utf8();
- return SubstituteData(
- SharedBuffer::Create(encoded_srcdoc.data(), encoded_srcdoc.length()),
- "text/html", "UTF-8", NullURL());
-}
-
void FrameLoader::StopAllLoaders() {
if (frame_->GetDocument()->PageDismissalEventBeingDispatched() !=
Document::kNoDismissal)
@@ -1263,7 +1282,17 @@ void FrameLoader::CommitProvisionalLoad() {
Client()->TransitionToCommittedForNewPage();
- frame_->GetNavigationScheduler().Cancel();
+ // If this is an about:blank navigation committing asynchronously, don't
+ // cancel scheduled navigations, so that the scheduled navigation still goes
+ // through. This handles the case where a navigation is scheduled between the
+ // about:blank navigation starting and finishing, where previously it would
+ // have happened after about:blank completed.
+ // TODO(japhet): This is an atrocious hack. Get rid of NavigationScheduler
+ // so it isn't needed.
+ if (!state_machine_.CommittedFirstRealDocumentLoad() ||
+ !DocumentLoader::WillLoadUrlAsEmpty(document_loader_->Url())) {
+ frame_->GetNavigationScheduler().Cancel();
+ }
}
bool FrameLoader::IsLoadingMainFrame() const {
@@ -1376,7 +1405,8 @@ void FrameLoader::RestoreScrollPositionAndViewState(
String FrameLoader::UserAgent() const {
String user_agent = Client()->UserAgent();
- probe::applyUserAgentOverride(frame_->GetDocument(), &user_agent);
+ probe::applyUserAgentOverride(probe::ToCoreProbeSink(frame_->GetDocument()),
+ &user_agent);
return user_agent;
}
@@ -1453,9 +1483,7 @@ void FrameLoader::ProcessFragment(const KURL& url,
GetDocumentLoader()->GetHistoryItem()->ScrollRestorationType() ==
kScrollRestorationManual));
- view->ProcessUrlFragment(url, should_scroll_to_fragment
- ? LocalFrameView::kUrlFragmentScroll
- : LocalFrameView::kUrlFragmentDontScroll);
+ view->ProcessUrlFragment(url, should_scroll_to_fragment);
if (boundary_frame && boundary_frame->IsLocalFrame())
ToLocalFrame(boundary_frame)
@@ -1487,8 +1515,7 @@ bool FrameLoader::ShouldClose(bool is_reload) {
IgnoreOpensDuringUnloadCountIncrementer ignore_opens_during_unload(
frame_->GetDocument());
if (!frame_->GetDocument()->DispatchBeforeUnloadEvent(
- page->GetChromeClient(), is_reload, false /* auto_cancel */,
- did_allow_navigation))
+ &page->GetChromeClient(), is_reload, did_allow_navigation))
return false;
// Then deal with descendent frames.
@@ -1509,8 +1536,7 @@ bool FrameLoader::ShouldClose(bool is_reload) {
ignore_opens_during_unload_descendant(
descendant_frame->GetDocument());
if (!descendant_frame->GetDocument()->DispatchBeforeUnloadEvent(
- page->GetChromeClient(), is_reload, false /* auto_cancel */,
- did_allow_navigation))
+ &page->GetChromeClient(), is_reload, did_allow_navigation))
return false;
}
}
@@ -1545,7 +1571,8 @@ void FrameLoader::MarkAsLoading() {
}
bool FrameLoader::CancelProvisionalLoaderForNewNavigation(
- bool cancel_scheduled_navigations) {
+ bool cancel_scheduled_navigations,
+ bool is_starting_blank_navigation) {
bool had_placeholder_client_document_loader =
provisional_document_loader_ && !provisional_document_loader_->DidStart();
@@ -1573,9 +1600,22 @@ bool FrameLoader::CancelProvisionalLoaderForNewNavigation(
progress_tracker_->ProgressStarted();
+ // If this is an about:blank navigation committing asynchronously, don't
+ // cancel scheduled navigations, so that the scheduled navigation still goes
+ // through. This handles the case where a navigation is scheduled between the
+ // about:blank navigation starting and finishing, where previously it would
+ // have happened after about:blank completed.
+ // TODO(japhet): This is an atrocious hack. Get rid of NavigationScheduler
+ // so it isn't needed.
+ bool skip_cancel_for_about_blank =
+ state_machine_.CommittedFirstRealDocumentLoad() &&
+ is_starting_blank_navigation;
// We need to ensure that script initiated navigations are honored.
- if (!had_placeholder_client_document_loader || cancel_scheduled_navigations)
+ if (!skip_cancel_for_about_blank &&
+ (!had_placeholder_client_document_loader ||
+ cancel_scheduled_navigations)) {
frame_->GetNavigationScheduler().Cancel();
+ }
return true;
}
@@ -1585,15 +1625,6 @@ bool FrameLoader::ShouldTreatURLAsSameAsCurrent(const KURL& url) const {
url == document_loader_->GetHistoryItem()->Url();
}
-bool FrameLoader::ShouldTreatURLAsSrcdocDocument(const KURL& url) const {
- if (!url.IsAboutSrcdocURL())
- return false;
- HTMLFrameOwnerElement* owner_element = frame_->DeprecatedLocalOwner();
- if (!IsHTMLIFrameElement(owner_element))
- return false;
- return owner_element->FastHasAttribute(kSrcdocAttr);
-}
-
void FrameLoader::DispatchDocumentElementAvailable() {
ScriptForbiddenScope forbid_scripts;
Client()->DocumentElementAvailable();
@@ -1608,15 +1639,15 @@ void FrameLoader::DispatchDidClearDocumentOfWindowObject() {
DCHECK(frame_->GetDocument());
if (state_machine_.CreatingInitialEmptyDocument())
return;
- if (!frame_->GetDocument()->CanExecuteScripts(kNotAboutToExecuteScript))
- return;
Settings* settings = frame_->GetSettings();
if (settings && settings->GetForceMainWorldInitialization()) {
- // Forcibly instantiate WindowProxy.
+ // Forcibly instantiate WindowProxy, even if script is disabled.
frame_->GetScriptController().WindowProxy(DOMWrapperWorld::MainWorld());
}
probe::didClearDocumentOfWindowObject(frame_);
+ if (!frame_->GetDocument()->CanExecuteScripts(kNotAboutToExecuteScript))
+ return;
if (dispatching_did_clear_window_object_in_main_world_)
return;
@@ -1702,7 +1733,7 @@ void FrameLoader::UpgradeInsecureRequest(ResourceRequest& resource_request,
resource_request.Url().ProtocolIs("http") &&
!origin_context->GetSecurityContext().GetMixedAutoUpgradeOptOut() &&
MixedContentChecker::ShouldAutoupgrade(
- origin_context->Url(),
+ origin_context->GetHttpsState(),
WebMixedContent::ContextTypeFromRequestContext(context, false))) {
if (origin_context->IsDocument()) {
Document* document = static_cast<Document*>(origin_context);
@@ -1782,20 +1813,12 @@ inline void FrameLoader::TakeObjectSnapshot() const {
}
DocumentLoader* FrameLoader::CreateDocumentLoader(
- const ResourceRequest& request,
- const SubstituteData& substitute_data,
- ClientRedirectPolicy client_redirect_policy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType load_type,
WebNavigationType navigation_type,
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DocumentLoader* loader = Client()->CreateDocumentLoader(
- frame_, request,
- substitute_data.IsValid() ? substitute_data
- : DefaultSubstituteDataForURL(request.Url()),
- client_redirect_policy, devtools_navigation_token, load_type,
- navigation_type, std::move(navigation_params), std::move(extra_data));
+ frame_, navigation_type, std::move(navigation_params),
+ std::move(extra_data));
probe::lifecycleEvent(frame_, loader, "init", CurrentTimeTicksInSeconds());
return loader;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.h b/chromium/third_party/blink/renderer/core/loader/frame_loader.h
index 9cfcee46a44..f7df56fded5 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.h
@@ -39,6 +39,7 @@
#include "third_party/blink/public/web/web_frame_load_type.h"
#include "third_party/blink/public/web/web_navigation_type.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/frame_types.h"
#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
#include "third_party/blink/renderer/core/loader/frame_loader_state_machine.h"
@@ -51,10 +52,6 @@
#include <memory>
-namespace base {
-class UnguessableToken;
-}
-
namespace blink {
class Document;
@@ -67,9 +64,9 @@ class ProgressTracker;
class ResourceError;
class ResourceRequest;
class SerializedScriptValue;
-class SubstituteData;
class TracedValue;
struct FrameLoadRequest;
+struct WebNavigationInfo;
struct WebNavigationParams;
namespace mojom {
@@ -106,19 +103,10 @@ class CORE_EXPORT FrameLoader final {
// Called when the browser process has asked this renderer process to commit
// a navigation in this frame. This method skips most of the checks assuming
// that browser process has already performed any checks necessary.
- // For history navigations, a history item should be provided and
- // an appropriate WebFrameLoadType should be given.
- // See DocumentLoader::devtools_navigation_token_ for documentation on
- // the token.
+ // See WebNavigationParams for details.
void CommitNavigation(
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType = WebFrameLoadType::kStandard,
- HistoryItem* = nullptr,
- std::unique_ptr<WebNavigationParams> navigation_params = nullptr,
- std::unique_ptr<WebDocumentLoader::ExtraData> extra_data = nullptr);
+ std::unique_ptr<WebNavigationParams> navigation_params,
+ std::unique_ptr<WebDocumentLoader::ExtraData> extra_data);
// Called when the browser process has asked this renderer process to commit a
// same document navigation in that frame. Returns false if the navigation
@@ -137,15 +125,8 @@ class CORE_EXPORT FrameLoader final {
// This placeholder document loader will be later abandoned, and only
// lives temporarily so that the rest of Blink code knows the navigation
// is in place.
- // See DocumentLoader::devtools_navigation_token_ for documentation on
- // the token.
bool CreatePlaceholderDocumentLoader(
- const ResourceRequest&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType,
- WebNavigationType,
- std::unique_ptr<WebNavigationParams>,
+ const WebNavigationInfo&,
std::unique_ptr<WebDocumentLoader::ExtraData>);
// This runs the "stop document loading" algorithm in HTML:
@@ -177,7 +158,6 @@ class CORE_EXPORT FrameLoader final {
bool IsLoadingMainFrame() const;
bool ShouldTreatURLAsSameAsCurrent(const KURL&) const;
- bool ShouldTreatURLAsSrcdocDocument(const KURL&) const;
void SetDefersLoading(bool);
@@ -253,15 +233,17 @@ class CORE_EXPORT FrameLoader final {
void ClientDroppedNavigation();
void MarkAsLoading();
+ ContentSecurityPolicy* GetLastOriginDocumentCSP() {
+ return last_origin_document_csp_.Get();
+ }
+
private:
bool PrepareRequestForThisFrame(FrameLoadRequest&);
- WebFrameLoadType DetermineFrameLoadType(
- const ResourceRequest& resource_request,
- Document* origin_document,
- const KURL& failing_url,
- WebFrameLoadType);
-
- SubstituteData DefaultSubstituteDataForURL(const KURL&);
+ WebFrameLoadType DetermineFrameLoadType(const KURL& url,
+ const AtomicString& http_method,
+ Document* origin_document,
+ const KURL& failing_url,
+ WebFrameLoadType);
bool ShouldPerformFragmentNavigation(bool is_form_submission,
const String& http_method,
@@ -271,7 +253,8 @@ class CORE_EXPORT FrameLoader final {
// Returns whether we should continue with new navigation.
bool CancelProvisionalLoaderForNewNavigation(
- bool cancel_scheduled_navigations);
+ bool cancel_scheduled_navigations,
+ bool is_starting_blank_navigation);
void ClearInitialScrollState();
@@ -296,11 +279,6 @@ class CORE_EXPORT FrameLoader final {
void TakeObjectSnapshot() const;
DocumentLoader* CreateDocumentLoader(
- const ResourceRequest&,
- const SubstituteData&,
- ClientRedirectPolicy,
- const base::UnguessableToken& devtools_navigation_token,
- WebFrameLoadType,
WebNavigationType,
std::unique_ptr<WebNavigationParams>,
std::unique_ptr<WebDocumentLoader::ExtraData>);
@@ -336,6 +314,8 @@ class CORE_EXPORT FrameLoader final {
WebScopedVirtualTimePauser virtual_time_pauser_;
+ Member<ContentSecurityPolicy> last_origin_document_csp_;
+
DISALLOW_COPY_AND_ASSIGN(FrameLoader);
};
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h b/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h
index 9f8a0129b04..5e319325325 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h
@@ -72,6 +72,16 @@ enum SinglePageAppNavigationType {
kSPANavTypeOtherFragmentNavigation = 2,
kSPANavTypeCount
};
+
+enum class ClientNavigationReason {
+ kFormSubmissionGet,
+ kFormSubmissionPost,
+ kHttpHeaderRefresh,
+ kFrameNavigation,
+ kMetaTagRefresh,
+ kPageBlock,
+ kReload,
+};
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.cc b/chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.cc
new file mode 100644
index 00000000000..12b944fac4a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.cc
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/frame_or_imported_document.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/frame_loader.h"
+
+namespace blink {
+
+LocalFrame& FrameOrImportedDocument::GetFrame() const {
+ if (document_loader_) {
+ LocalFrame* frame = document_loader_->GetFrame();
+ DCHECK(frame);
+ return *frame;
+ }
+
+ // HTML imports case
+ DCHECK(document_);
+ // It's guaranteed that imports_controller is not nullptr since:
+ // - only ClearImportsController() clears it
+ // - ClearImportsController() also calls ResourceFethcer::ClearContext().
+ HTMLImportsController* imports_controller = document_->ImportsController();
+ DCHECK(imports_controller);
+
+ // It's guaranteed that Master() is not yet Shutdown()-ed since when Master()
+ // is Shutdown()-ed:
+ // - Master()'s HTMLImportsController is disposed.
+ // - All the HTMLImportLoader instances of the HTMLImportsController are
+ // disposed.
+ // - ClearImportsController() is called on the Document.
+ // HTMLImportsController is created only when the master Document's
+ // GetFrame() doesn't return nullptr, this is guaranteed to be not nullptr
+ // here.
+ LocalFrame* frame = imports_controller->Master()->GetFrame();
+ DCHECK(frame);
+ return *frame;
+}
+
+DocumentLoader& FrameOrImportedDocument::GetMasterDocumentLoader() const {
+ if (document_loader_)
+ return *document_loader_;
+
+ // HTML imports case
+ // GetDocumentLoader() here always returns a non-nullptr value that is the
+ // DocumentLoader for |document_| because:
+ // - A Document is created with a LocalFrame only after the
+ // DocumentLoader is committed
+ // - When another DocumentLoader is committed, the FrameLoader
+ // Shutdown()-s |document_|.
+ auto* loader = GetFrame().Loader().GetDocumentLoader();
+ DCHECK(loader);
+ return *loader;
+}
+
+void FrameOrImportedDocument::UpdateDocument(Document& document) {
+ DCHECK(document_loader_);
+ document_ = document;
+}
+
+void FrameOrImportedDocument::Trace(Visitor* visitor) {
+ visitor->Trace(document_loader_);
+ visitor->Trace(document_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.h b/chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.h
new file mode 100644
index 00000000000..b0035afd2f6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/frame_or_imported_document.h
@@ -0,0 +1,81 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_OR_IMPORTED_DOCUMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_OR_IMPORTED_DOCUMENT_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class Document;
+class DocumentLoader;
+class LocalFrame;
+
+// FrameOrImportedDocument is a thin wrapper that represents and absorbs
+// the differences between Document-ish things behind FrameFetchContext:
+// - An imported Document
+// (document_loader_ is null, document_ is non-null),
+// - A DocumentLoader that has not yet committed its navigation
+// (document_loader_ is non-null, document_ is null), or
+// - A DocumentLoader that has committed its navigation
+// (document_loader_ is non-null, document_ is non-null).
+//
+// A FrameOrImportedDocument is indirectly used with a ResourceFetcher, and
+// works until ResourceFetcher::ClearContext is called. Do not use this class
+// outside of core/loader.
+class CORE_EXPORT FrameOrImportedDocument final
+ : public GarbageCollected<FrameOrImportedDocument> {
+ public:
+ // Creates a FrameOrImportedDocument associated with a LocalFrame (which is,
+ // loader.GetFrame() which cannot be null). This object works until the
+ // associated frame is detached.
+ explicit FrameOrImportedDocument(DocumentLoader& loader)
+ : document_loader_(loader) {}
+
+ // Creates a FrameOrImportedDocument associated with an imported document.
+ // This object works until |document| is shut-down.
+ explicit FrameOrImportedDocument(Document& imported_document)
+ : document_(imported_document) {}
+
+ // When this object is associated with a frame, returns it.
+ // When this object is associated with an imported document, returns the
+ // frame associated with the imports controller.
+ LocalFrame& GetFrame() const;
+
+ // When this object is associated with a frame, returns the document loader
+ // given to the constructor (note that there may be multiple document loaders
+ // in a LocalFrame).
+ // When this object is associated with an imported document, returns the
+ // document loader associated with the frame associated with the imports
+ // controller.
+ DocumentLoader& GetMasterDocumentLoader() const;
+
+ // When this object is associated with a frame, returns the document loader
+ // given to the constructor (note that there may be multiple document loaders
+ // in a LocalFrame). Otherwise, returns null.
+ DocumentLoader* GetDocumentLoader() const { return document_loader_; }
+
+ // When this object is associated with a frame with a committed document,
+ // returns it.
+ // When this object is associated with a frame with no committed document,
+ // returns nullptr
+ // When this object is associated with an imported document, returns it.
+ Document* GetDocument() const { return document_; }
+
+ // Provide a committed document to |this|. |this| must be a
+ // FrameOrImportedDocument associated with a frame.
+ void UpdateDocument(Document&);
+
+ void Trace(Visitor* visitor);
+
+ private:
+ const Member<DocumentLoader> document_loader_;
+ Member<Document> document_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_OR_IMPORTED_DOCUMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc b/chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc
new file mode 100644
index 00000000000..7174e5de700
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.cc
@@ -0,0 +1,135 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h"
+
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/frame_or_imported_document.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+
+namespace blink {
+
+FrameResourceFetcherProperties::FrameResourceFetcherProperties(
+ FrameOrImportedDocument& frame_or_imported_document)
+ : frame_or_imported_document_(frame_or_imported_document),
+ fetch_client_settings_object_(
+ CreateFetchClientSettingsObject(frame_or_imported_document)) {}
+
+void FrameResourceFetcherProperties::Trace(Visitor* visitor) {
+ visitor->Trace(frame_or_imported_document_);
+ visitor->Trace(fetch_client_settings_object_);
+ ResourceFetcherProperties::Trace(visitor);
+}
+
+void FrameResourceFetcherProperties::UpdateDocument(Document& document) {
+ frame_or_imported_document_->UpdateDocument(document);
+ fetch_client_settings_object_ =
+ CreateFetchClientSettingsObject(*frame_or_imported_document_);
+}
+
+bool FrameResourceFetcherProperties::IsMainFrame() const {
+ return frame_or_imported_document_->GetFrame().IsMainFrame();
+}
+
+mojom::ControllerServiceWorkerMode
+FrameResourceFetcherProperties::GetControllerServiceWorkerMode() const {
+ auto* service_worker_network_provider =
+ frame_or_imported_document_->GetMasterDocumentLoader()
+ .GetServiceWorkerNetworkProvider();
+ if (!service_worker_network_provider)
+ return blink::mojom::ControllerServiceWorkerMode::kNoController;
+ return service_worker_network_provider->IsControlledByServiceWorker();
+}
+
+int64_t FrameResourceFetcherProperties::ServiceWorkerId() const {
+ DCHECK_NE(GetControllerServiceWorkerMode(),
+ blink::mojom::ControllerServiceWorkerMode::kNoController);
+ auto* service_worker_network_provider =
+ frame_or_imported_document_->GetMasterDocumentLoader()
+ .GetServiceWorkerNetworkProvider();
+ DCHECK(service_worker_network_provider);
+ return service_worker_network_provider->ControllerServiceWorkerID();
+}
+
+bool FrameResourceFetcherProperties::IsPaused() const {
+ return frame_or_imported_document_->GetFrame().GetPage()->Paused();
+}
+
+bool FrameResourceFetcherProperties::IsLoadComplete() const {
+ Document* document = frame_or_imported_document_->GetDocument();
+ return document && document->LoadEventFinished();
+}
+
+bool FrameResourceFetcherProperties::ShouldBlockLoadingMainResource() const {
+ DocumentLoader* document_loader =
+ frame_or_imported_document_->GetDocumentLoader();
+ if (!document_loader)
+ return false;
+
+ FrameLoader& loader = frame_or_imported_document_->GetFrame().Loader();
+ return document_loader != loader.GetProvisionalDocumentLoader();
+}
+
+bool FrameResourceFetcherProperties::ShouldBlockLoadingSubResource() const {
+ DocumentLoader* document_loader =
+ frame_or_imported_document_->GetDocumentLoader();
+ if (!document_loader)
+ return false;
+
+ FrameLoader& loader = frame_or_imported_document_->GetFrame().Loader();
+ return document_loader != loader.GetDocumentLoader();
+}
+
+const FetchClientSettingsObject&
+FrameResourceFetcherProperties::CreateFetchClientSettingsObject(
+ const FrameOrImportedDocument& frame_or_imported_document) {
+ if (frame_or_imported_document.GetDocument()) {
+ // HTML imports case
+ return *MakeGarbageCollected<FetchClientSettingsObjectImpl>(
+ *frame_or_imported_document.GetDocument());
+ }
+
+ // This FetchClientSettingsObject can be used only for navigation, as
+ // at the creation of the corresponding Document a new
+ // FetchClientSettingsObject is set.
+ // Also, currently all the members except for SecurityOrigin are not
+ // used in FrameFetchContext, and therefore we set some safe default
+ // values here.
+ // Once PlzNavigate removes ResourceFetcher usage in navigations, we
+ // might be able to remove this FetchClientSettingsObject at all.
+ return *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ KURL(),
+
+ // SecurityOrigin. This is actually used via
+ // FetchContext::GetSecurityOrigin().
+ // TODO(hiroshige): Assign non-nullptr SecurityOrigin.
+ nullptr,
+
+ // Currently this is not used, and referrer for navigation request
+ // is set based on previous Document's referrer policy, for example
+ // in FrameLoader::SetReferrerForFrameRequest().
+ // If we want to set referrer based on FetchClientSettingsObject,
+ // it should refer to the FetchClientSettingsObject of the previous
+ // Document, probably not this one.
+ network::mojom::ReferrerPolicy::kDefault, String(),
+
+ // MixedContentChecker::ShouldBlockFetch() doesn't check mixed
+ // contents if frame type is not kNone, which is always true in
+ // RawResource::FetchMainResource().
+ // Therefore HttpsState here isn't (and isn't expected to be)
+ // used and thus it's safe to pass a safer default value.
+ HttpsState::kModern,
+
+ // This is only for workers and this value is not (and isn't
+ // expected to be) used.
+ AllowedByNosniff::MimeTypeCheck::kStrict);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h b/chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h
new file mode 100644
index 00000000000..e941e4386b4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h
@@ -0,0 +1,55 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_RESOURCE_FETCHER_PROPERTIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_RESOURCE_FETCHER_PROPERTIES_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
+
+namespace blink {
+
+class Document;
+class FrameOrImportedDocument;
+
+// FrameResourceFetcherProperties is a ResourceFetcherProperties implementation
+// for Frame.
+class FrameResourceFetcherProperties final : public ResourceFetcherProperties {
+ public:
+ explicit FrameResourceFetcherProperties(FrameOrImportedDocument&);
+ ~FrameResourceFetcherProperties() override = default;
+
+ void Trace(Visitor*) override;
+
+ const FrameOrImportedDocument& GetFrameOrImportedDocument() const {
+ return *frame_or_imported_document_;
+ }
+ // Provides a committed document to |this|.
+ void UpdateDocument(Document& document);
+
+ // ResourceFetcherProperties implementation
+ const FetchClientSettingsObject& GetFetchClientSettingsObject()
+ const override {
+ return *fetch_client_settings_object_;
+ }
+ bool IsMainFrame() const override;
+ ControllerServiceWorkerMode GetControllerServiceWorkerMode() const override;
+ int64_t ServiceWorkerId() const override;
+ bool IsPaused() const override;
+ bool IsDetached() const override { return false; }
+ bool IsLoadComplete() const override;
+ bool ShouldBlockLoadingMainResource() const override;
+ bool ShouldBlockLoadingSubResource() const override;
+
+ private:
+ static const FetchClientSettingsObject& CreateFetchClientSettingsObject(
+ const FrameOrImportedDocument&);
+
+ const Member<FrameOrImportedDocument> frame_or_imported_document_;
+ Member<const FetchClientSettingsObject> fetch_client_settings_object_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_RESOURCE_FETCHER_PROPERTIES_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/history_item.cc b/chromium/third_party/blink/renderer/core/loader/history_item.cc
index 13f2c97a366..1fd1e21945b 100644
--- a/chromium/third_party/blink/renderer/core/loader/history_item.cc
+++ b/chromium/third_party/blink/renderer/core/loader/history_item.cc
@@ -137,19 +137,6 @@ const AtomicString& HistoryItem::FormContentType() const {
return form_content_type_;
}
-void HistoryItem::SetFormInfoFromRequest(const ResourceRequest& request) {
- if (DeprecatedEqualIgnoringCase(request.HttpMethod(), "POST")) {
- // FIXME: Eventually we have to make this smart enough to handle the case
- // where we have a stream for the body to handle the "data interspersed with
- // files" feature.
- form_data_ = request.HttpBody();
- form_content_type_ = request.HttpContentType();
- } else {
- form_data_ = nullptr;
- form_content_type_ = g_null_atom;
- }
-}
-
void HistoryItem::SetFormData(scoped_refptr<EncodedFormData> form_data) {
form_data_ = std::move(form_data);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/history_item.h b/chromium/third_party/blink/renderer/core/loader/history_item.h
index e0de5d0d1ad..e5ee75f71dc 100644
--- a/chromium/third_party/blink/renderer/core/loader/history_item.h
+++ b/chromium/third_party/blink/renderer/core/loader/history_item.h
@@ -119,7 +119,6 @@ class CORE_EXPORT HistoryItem final
void SetScrollAnchorData(const ScrollAnchorData&);
- void SetFormInfoFromRequest(const ResourceRequest&);
void SetFormData(scoped_refptr<EncodedFormData>);
void SetFormContentType(const AtomicString&);
diff --git a/chromium/third_party/blink/renderer/core/loader/image_loader.cc b/chromium/third_party/blink/renderer/core/loader/image_loader.cc
index da853f20609..81a68656eef 100644
--- a/chromium/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/image_loader.cc
@@ -25,7 +25,7 @@
#include <memory>
#include <utility>
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_client_hints_type.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
@@ -43,7 +43,6 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
-#include "third_party/blink/renderer/core/html/html_dimension.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/lazy_load_image_observer.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
@@ -52,6 +51,7 @@
#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -69,26 +69,16 @@ namespace blink {
namespace {
-bool GetAbsoluteDimensionValue(const AtomicString& attribute_value,
- double* value) {
- HTMLDimension dimension;
- if (ParseDimensionValue(attribute_value, dimension) &&
- dimension.IsAbsolute()) {
- *value = dimension.Value();
- return true;
- }
- return false;
-}
-
bool IsLazyLoadableImage(const LocalFrame* frame,
- HTMLImageElement* html_image) {
- // Minimum width or height attribute of the image to start lazyloading.
- const unsigned kMinDimensionToLazyLoad = 10;
-
+ HTMLImageElement* html_image,
+ const KURL& url) {
// Do not lazyload image elements created from javascript.
if (!html_image->ElementCreatedByParser())
return false;
+ if (!url.ProtocolIsInHTTPFamily())
+ return false;
+
if (EqualIgnoringASCIICase(
html_image->FastGetAttribute(html_names::kLazyloadAttr), "off") &&
!frame->GetDocument()->IsLazyLoadPolicyEnforced()) {
@@ -96,32 +86,16 @@ bool IsLazyLoadableImage(const LocalFrame* frame,
}
// Avoid lazyloading if width and height attributes are small. This
// heuristic helps avoid double fetching tracking pixels.
- double width, height;
- if (GetAbsoluteDimensionValue(
- html_image->getAttribute(html_names::kWidthAttr), &width) &&
- GetAbsoluteDimensionValue(
- html_image->getAttribute(html_names::kHeightAttr), &height) &&
- width <= kMinDimensionToLazyLoad && height <= kMinDimensionToLazyLoad) {
+ if (HTMLImageElement::IsDimensionSmallAndAbsoluteForLazyLoad(
+ html_image->getAttribute(html_names::kWidthAttr)) &&
+ HTMLImageElement::IsDimensionSmallAndAbsoluteForLazyLoad(
+ html_image->getAttribute(html_names::kHeightAttr))) {
return false;
}
// Avoid lazyloading if width or height is specified in inline style and is
// small enough. This heuristic helps avoid double fetching tracking pixels.
- if (const auto* property_set = html_image->InlineStyle()) {
- const CSSValue* width = property_set->GetPropertyCSSValue(CSSPropertyWidth);
- const CSSValue* height =
- property_set->GetPropertyCSSValue(CSSPropertyHeight);
- if (width && width->IsPrimitiveValue() && height &&
- height->IsPrimitiveValue()) {
- const CSSPrimitiveValue* width_prim = ToCSSPrimitiveValue(width);
- const CSSPrimitiveValue* height_prim = ToCSSPrimitiveValue(height);
- if (height_prim->IsPx() &&
- (height_prim->GetDoubleValue() <= kMinDimensionToLazyLoad) &&
- width_prim->IsPx() &&
- (width_prim->GetDoubleValue() <= kMinDimensionToLazyLoad)) {
- return false;
- }
- }
- }
+ if (HTMLImageElement::IsInlineStyleDimensionsSmall(html_image->InlineStyle()))
+ return false;
return true;
}
@@ -394,7 +368,7 @@ static void ConfigureRequest(
element.GetDocument().GetSecurityOrigin(), cross_origin);
}
- if (RuntimeEnabledFeatures::PriorityHintsEnabled()) {
+ if (origin_trials::PriorityHintsEnabled(&element.GetDocument())) {
mojom::FetchImportanceMode importance_mode =
GetFetchImportanceAttributeValue(
element.FastGetAttribute(html_names::kImportanceAttr));
@@ -537,7 +511,8 @@ void ImageLoader::DoUpdateFromElement(
if (frame->IsClientLoFiAllowed(params.GetResourceRequest())) {
params.SetClientLoFiPlaceholder();
} else if (auto* html_image = ToHTMLImageElementOrNull(GetElement())) {
- if (IsLazyLoadableImage(frame, html_image)) {
+ if (IsLazyLoadableImage(frame, html_image,
+ params.GetResourceRequest().Url())) {
if (frame->GetDocument()->GetSettings()->GetLazyLoadEnabled() &&
frame->IsLazyLoadingImageAllowed()) {
params.SetLazyImagePlaceholder();
@@ -675,10 +650,11 @@ void ImageLoader::UpdateFromElement(
}
}
- // Don't load images for inactive documents. We don't want to slow down the
- // raw HTML parsing case by loading images we don't intend to display.
+ // Don't load images for inactive documents or active documents without V8
+ // context. We don't want to slow down the raw HTML parsing case by loading
+ // images we don't intend to display.
Document& document = element_->GetDocument();
- if (document.IsActive())
+ if (!document.IsContextDestroyed() && document.IsActive())
EnqueueImageLoadingMicroTask(url, update_behavior, referrer_policy);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/importance_attribute.h b/chromium/third_party/blink/renderer/core/loader/importance_attribute.h
index ccb1f9c2ff8..859102e4217 100644
--- a/chromium/third_party/blink/renderer/core/loader/importance_attribute.h
+++ b/chromium/third_party/blink/renderer/core/loader/importance_attribute.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_IMPORTANCE_ATTRIBUTE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_IMPORTANCE_ATTRIBUTE_H_
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc b/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc
index f5f99f49c47..f55d34e50b0 100644
--- a/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc
+++ b/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc
@@ -22,9 +22,9 @@ constexpr auto kTimeToInteractiveWindow = TimeDelta::FromSeconds(5);
// requests for this duration of time.
constexpr int kNetworkQuietMaximumConnections = 2;
-const char kHistogramInputDelay[] = "PageLoad.InteractiveTiming.InputDelay";
+const char kHistogramInputDelay[] = "PageLoad.InteractiveTiming.InputDelay2";
const char kHistogramInputTimestamp[] =
- "PageLoad.InteractiveTiming.InputTimestamp";
+ "PageLoad.InteractiveTiming.InputTimestamp2";
// static
const char InteractiveDetector::kSupplementName[] = "InteractiveDetector";
@@ -54,7 +54,7 @@ InteractiveDetector::InteractiveDetector(
document.GetTaskRunner(TaskType::kInternalDefault),
this,
&InteractiveDetector::TimeToInteractiveTimerFired),
- initial_visibility_(document.GetPageVisibilityState()) {}
+ initially_hidden_(document.hidden()) {}
void InteractiveDetector::SetNavigationStartTime(
TimeTicks navigation_start_time) {
@@ -148,21 +148,19 @@ TimeTicks InteractiveDetector::GetLongestInputTimestamp() const {
bool InteractiveDetector::PageWasBackgroundedSinceEvent(TimeTicks event_time) {
DCHECK(GetSupplementable());
- if (GetSupplementable()->GetPageVisibilityState() ==
- mojom::PageVisibilityState::kHidden) {
+ if (GetSupplementable()->hidden()) {
return true;
}
- mojom::PageVisibilityState curr_visibility = initial_visibility_;
+ bool curr_hidden = initially_hidden_;
TimeTicks visibility_start = page_event_times_.nav_start;
for (auto change_event : visibility_change_events_) {
TimeTicks visibility_end = change_event.timestamp;
- if (curr_visibility == mojom::PageVisibilityState::kHidden &&
- event_time < visibility_end) {
+ if (curr_hidden && event_time < visibility_end) {
// [event_time, now] intersects a backgrounded range.
return true;
}
- curr_visibility = change_event.visibility;
+ curr_hidden = change_event.was_hidden;
visibility_start = visibility_end;
}
@@ -186,6 +184,12 @@ void InteractiveDetector::HandleForInputDelay(const WebInputEvent& event) {
pending_pointerdown_timestamp_ = event.TimeStamp();
return;
}
+ if (event.GetType() == WebInputEvent::kPointerCancel ||
+ event.GetType() == WebInputEvent::kPointerCausedUaAction) {
+ pending_pointerdown_delay_ = base::TimeDelta();
+ pending_pointerdown_timestamp_ = base::TimeTicks();
+ return;
+ }
bool event_is_meaningful =
event.GetType() == WebInputEvent::kMouseDown ||
@@ -365,9 +369,8 @@ void InteractiveDetector::OnInvalidatingInputEvent(
GetSupplementable()->Loader()->DidChangePerformanceTiming();
}
-void InteractiveDetector::OnPageVisibilityChanged(
- mojom::PageVisibilityState visibility) {
- visibility_change_events_.push_back({CurrentTimeTicks(), visibility});
+void InteractiveDetector::OnPageHiddenChanged(bool is_hidden) {
+ visibility_change_events_.push_back({CurrentTimeTicks(), is_hidden});
}
void InteractiveDetector::TimeToInteractiveTimerFired(TimerBase*) {
diff --git a/chromium/third_party/blink/renderer/core/loader/interactive_detector.h b/chromium/third_party/blink/renderer/core/loader/interactive_detector.h
index d13ce52c172..736637a7b72 100644
--- a/chromium/third_party/blink/renderer/core/loader/interactive_detector.h
+++ b/chromium/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/loader/long_task_detector.h"
-#include "third_party/blink/renderer/core/page/page_visibility_state.h"
+#include "third_party/blink/renderer/core/page/page_hidden_state.h"
#include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -74,7 +74,7 @@ class CORE_EXPORT InteractiveDetector
FirstMeaningfulPaintDetector::HadUserInput user_input_before_fmp);
void OnDomContentLoadedEnd(TimeTicks dcl_time);
void OnInvalidatingInputEvent(TimeTicks invalidation_time);
- void OnPageVisibilityChanged(mojom::PageVisibilityState);
+ void OnPageHiddenChanged(bool is_hidden);
// Returns Interactive Time if already detected, or 0.0 otherwise.
TimeTicks GetInteractiveTime() const;
@@ -136,7 +136,7 @@ class CORE_EXPORT InteractiveDetector
struct VisibilityChangeEvent {
TimeTicks timestamp;
- mojom::PageVisibilityState visibility;
+ bool was_hidden;
};
// Stores sufficiently long quiet windows on main thread and network.
@@ -173,7 +173,7 @@ class CORE_EXPORT InteractiveDetector
void OnTimeToInteractiveDetected();
std::vector<VisibilityChangeEvent> visibility_change_events_;
- mojom::PageVisibilityState initial_visibility_;
+ bool initially_hidden_;
// Returns true if page was ever backgrounded in the range
// [event_time, CurrentTimeTicks()].
bool PageWasBackgroundedSinceEvent(TimeTicks event_time);
diff --git a/chromium/third_party/blink/renderer/core/loader/link_load_parameters.cc b/chromium/third_party/blink/renderer/core/loader/link_load_parameters.cc
new file mode 100644
index 00000000000..0bc29e534f3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/link_load_parameters.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
+
+#include "third_party/blink/renderer/platform/loader/link_header.h"
+
+namespace blink {
+
+LinkLoadParameters::LinkLoadParameters(
+ const LinkRelAttribute& rel,
+ const CrossOriginAttributeValue& cross_origin,
+ const String& type,
+ const String& as,
+ const String& media,
+ const String& nonce,
+ const String& integrity,
+ const String& importance,
+ network::mojom::ReferrerPolicy referrer_policy,
+ const KURL& href,
+ const String& image_srcset,
+ const String& image_sizes)
+ : rel(rel),
+ cross_origin(cross_origin),
+ type(type),
+ as(as),
+ media(media),
+ nonce(nonce),
+ integrity(integrity),
+ importance(importance),
+ referrer_policy(referrer_policy),
+ href(href),
+ image_srcset(image_srcset),
+ image_sizes(image_sizes) {}
+
+// TODO(domfarolino)
+// Eventually we'll want to support an |importance| value on
+// LinkHeaders. We can communicate a header's importance value
+// to LinkLoadParameters here, likely after modifying the LinkHeader
+// class. See https://crbug.com/821464 for info on Priority Hints.
+LinkLoadParameters::LinkLoadParameters(const LinkHeader& header,
+ const KURL& base_url)
+ : rel(LinkRelAttribute(header.Rel())),
+ cross_origin(GetCrossOriginAttributeValue(header.CrossOrigin())),
+ type(header.MimeType()),
+ as(header.As()),
+ media(header.Media()),
+ nonce(header.Nonce()),
+ integrity(header.Integrity()),
+ referrer_policy(network::mojom::ReferrerPolicy::kDefault),
+ href(KURL(base_url, header.Url())),
+ image_srcset(header.ImageSrcset()),
+ image_sizes(header.ImageSizes()) {}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/link_load_parameters.h b/chromium/third_party/blink/renderer/core/loader/link_load_parameters.h
new file mode 100644
index 00000000000..d64c1252e68
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/link_load_parameters.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LINK_LOAD_PARAMETERS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LINK_LOAD_PARAMETERS_H_
+
+#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
+#include "third_party/blink/renderer/core/html/link_rel_attribute.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class LinkHeader;
+
+struct CORE_EXPORT LinkLoadParameters {
+ LinkLoadParameters(const LinkRelAttribute&,
+ const CrossOriginAttributeValue&,
+ const String& type,
+ const String& as,
+ const String& media,
+ const String& nonce,
+ const String& integrity,
+ const String& importance,
+ network::mojom::ReferrerPolicy,
+ const KURL& href,
+ const String& image_srcset,
+ const String& image_sizes);
+ LinkLoadParameters(const LinkHeader&, const KURL& base_url);
+
+ LinkRelAttribute rel;
+ CrossOriginAttributeValue cross_origin;
+ String type;
+ String as;
+ String media;
+ String nonce;
+ String integrity;
+ String importance;
+ network::mojom::ReferrerPolicy referrer_policy;
+ KURL href;
+ String image_srcset;
+ String image_sizes;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LINK_LOAD_PARAMETERS_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader.cc b/chromium/third_party/blink/renderer/core/loader/link_loader.cc
index 6aee31d15ba..99f5ce34555 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader.cc
@@ -32,44 +32,30 @@
#include "third_party/blink/renderer/core/loader/link_loader.h"
#include "third_party/blink/public/platform/web_prerender.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/core/css/media_list.h"
-#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
-#include "third_party/blink/renderer/core/css/parser/sizes_attribute_parser.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/frame_console.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
-#include "third_party/blink/renderer/core/html/link_rel_attribute.h"
-#include "third_party/blink/renderer/core/html/parser/html_preload_scanner.h"
-#include "third_party/blink/renderer/core/html/parser/html_srcset_parser.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
-#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
-#include "third_party/blink/renderer/core/loader/network_hints_interface.h"
+#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
+#include "third_party/blink/renderer/core/loader/link_loader_client.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
#include "third_party/blink/renderer/core/loader/private/prerender_handle.h"
#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/link_fetch_resource.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
-#include "third_party/blink/renderer/core/script/module_script.h"
-#include "third_party/blink/renderer/core/script/script_loader.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_finish_observer.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
-#include "third_party/blink/renderer/platform/loader/link_header.h"
#include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
-#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/blink/renderer/platform/prerender.h"
namespace blink {
-static unsigned PrerenderRelTypesFromRelAttribute(
+class NetworkHintsInterface;
+
+namespace {
+
+unsigned PrerenderRelTypesFromRelAttribute(
const LinkRelAttribute& rel_attribute,
Document& document) {
unsigned result = 0;
@@ -85,24 +71,12 @@ static unsigned PrerenderRelTypesFromRelAttribute(
return result;
}
-// TODO(domfarolino)
-// Eventually we'll want to support an |importance| value on
-// LinkHeaders. We can communicate a header's importance value
-// to LinkLoadParameters here, likely after modifying the LinkHeader
-// class. See https://crbug.com/821464 for info on Priority Hints.
-LinkLoadParameters::LinkLoadParameters(const LinkHeader& header,
- const KURL& base_url)
- : rel(LinkRelAttribute(header.Rel())),
- cross_origin(GetCrossOriginAttributeValue(header.CrossOrigin())),
- type(header.MimeType()),
- as(header.As()),
- media(header.Media()),
- nonce(header.Nonce()),
- integrity(header.Integrity()),
- referrer_policy(network::mojom::ReferrerPolicy::kDefault),
- href(KURL(base_url, header.Url())),
- image_srcset(header.ImageSrcset()),
- image_sizes(header.ImageSizes()) {}
+} // namespace
+
+LinkLoader* LinkLoader::Create(LinkLoaderClient* client) {
+ return MakeGarbageCollected<LinkLoader>(client,
+ client->GetLoadingTaskRunner());
+}
class LinkLoader::FinishObserver final
: public GarbageCollectedFinalized<ResourceFinishObserver>,
@@ -191,456 +165,10 @@ void LinkLoader::DidSendDOMContentLoadedForPrerender() {
client_->DidSendDOMContentLoadedForLinkPrerender();
}
-enum LinkCaller {
- kLinkCalledFromHeader,
- kLinkCalledFromMarkup,
-};
-
-static void SendMessageToConsoleForPossiblyNullDocument(
- ConsoleMessage* console_message,
- Document* document,
- LocalFrame* frame) {
- DCHECK(document || frame);
- DCHECK(!document || document->GetFrame() == frame);
- // Route the console message through Document if possible, so that script line
- // numbers can be included. Otherwise, route directly to the FrameConsole, to
- // ensure we never drop a message.
- if (document)
- document->AddConsoleMessage(console_message);
- else
- frame->Console().AddMessage(console_message);
-}
-
-static void DnsPrefetchIfNeeded(
- const LinkLoadParameters& params,
- Document* document,
- LocalFrame* frame,
- const NetworkHintsInterface& network_hints_interface,
- LinkCaller caller) {
- if (params.rel.IsDNSPrefetch()) {
- UseCounter::Count(frame, WebFeature::kLinkRelDnsPrefetch);
- if (caller == kLinkCalledFromHeader)
- UseCounter::Count(frame, WebFeature::kLinkHeaderDnsPrefetch);
- Settings* settings = frame ? frame->GetSettings() : nullptr;
- // FIXME: The href attribute of the link element can be in "//hostname"
- // form, and we shouldn't attempt to complete that as URL
- // <https://bugs.webkit.org/show_bug.cgi?id=48857>.
- if (settings && settings->GetDNSPrefetchingEnabled() &&
- params.href.IsValid() && !params.href.IsEmpty()) {
- if (settings->GetLogDnsPrefetchAndPreconnect()) {
- SendMessageToConsoleForPossiblyNullDocument(
- ConsoleMessage::Create(
- kOtherMessageSource, kVerboseMessageLevel,
- String("DNS prefetch triggered for " + params.href.Host())),
- document, frame);
- }
- network_hints_interface.DnsPrefetchHost(params.href.Host());
- }
- }
-}
-
-static void PreconnectIfNeeded(
- const LinkLoadParameters& params,
- Document* document,
- LocalFrame* frame,
- const NetworkHintsInterface& network_hints_interface,
- LinkCaller caller) {
- if (params.rel.IsPreconnect() && params.href.IsValid() &&
- params.href.ProtocolIsInHTTPFamily()) {
- UseCounter::Count(frame, WebFeature::kLinkRelPreconnect);
- if (caller == kLinkCalledFromHeader)
- UseCounter::Count(frame, WebFeature::kLinkHeaderPreconnect);
- Settings* settings = frame ? frame->GetSettings() : nullptr;
- if (settings && settings->GetLogDnsPrefetchAndPreconnect()) {
- SendMessageToConsoleForPossiblyNullDocument(
- ConsoleMessage::Create(
- kOtherMessageSource, kVerboseMessageLevel,
- String("Preconnect triggered for ") + params.href.GetString()),
- document, frame);
- if (params.cross_origin != kCrossOriginAttributeNotSet) {
- SendMessageToConsoleForPossiblyNullDocument(
- ConsoleMessage::Create(kOtherMessageSource, kVerboseMessageLevel,
- String("Preconnect CORS setting is ") +
- String((params.cross_origin ==
- kCrossOriginAttributeAnonymous)
- ? "anonymous"
- : "use-credentials")),
- document, frame);
- }
- }
- network_hints_interface.PreconnectHost(params.href, params.cross_origin);
- }
-}
-
-base::Optional<ResourceType> LinkLoader::GetResourceTypeFromAsAttribute(
- const String& as) {
- DCHECK_EQ(as.DeprecatedLower(), as);
- if (as == "image") {
- return ResourceType::kImage;
- } else if (as == "script") {
- return ResourceType::kScript;
- } else if (as == "style") {
- return ResourceType::kCSSStyleSheet;
- } else if (as == "video") {
- return ResourceType::kVideo;
- } else if (as == "audio") {
- return ResourceType::kAudio;
- } else if (as == "track") {
- return ResourceType::kTextTrack;
- } else if (as == "font") {
- return ResourceType::kFont;
- } else if (as == "fetch") {
- return ResourceType::kRaw;
- }
- return base::nullopt;
-}
-
Resource* LinkLoader::GetResourceForTesting() {
return finish_observer_ ? finish_observer_->GetResource() : nullptr;
}
-static bool IsSupportedType(ResourceType resource_type,
- const String& mime_type) {
- if (mime_type.IsEmpty())
- return true;
- switch (resource_type) {
- case ResourceType::kImage:
- return MIMETypeRegistry::IsSupportedImagePrefixedMIMEType(mime_type);
- case ResourceType::kScript:
- return MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type);
- case ResourceType::kCSSStyleSheet:
- return MIMETypeRegistry::IsSupportedStyleSheetMIMEType(mime_type);
- case ResourceType::kFont:
- return MIMETypeRegistry::IsSupportedFontMIMEType(mime_type);
- case ResourceType::kAudio:
- case ResourceType::kVideo:
- return MIMETypeRegistry::IsSupportedMediaMIMEType(mime_type, String());
- case ResourceType::kTextTrack:
- return MIMETypeRegistry::IsSupportedTextTrackMIMEType(mime_type);
- case ResourceType::kRaw:
- return true;
- default:
- NOTREACHED();
- }
- return false;
-}
-
-static MediaValues* CreateMediaValues(
- Document& document,
- ViewportDescription* viewport_description) {
- MediaValues* media_values =
- MediaValues::CreateDynamicIfFrameExists(document.GetFrame());
- if (viewport_description) {
- media_values->OverrideViewportDimensions(
- viewport_description->max_width.GetFloatValue(),
- viewport_description->max_height.GetFloatValue());
- }
- return media_values;
-}
-
-static bool MediaMatches(const String& media, MediaValues* media_values) {
- scoped_refptr<MediaQuerySet> media_queries = MediaQuerySet::Create(media);
- MediaQueryEvaluator evaluator(*media_values);
- return evaluator.Eval(*media_queries);
-}
-
-// |base_url| is used in Link HTTP Header based preloads to resolve relative
-// URLs in srcset, which should be based on the resource's URL, not the
-// document's base URL. If |base_url| is a null URL, relative URLs are resolved
-// using |document.CompleteURL()|.
-static Resource* PreloadIfNeeded(const LinkLoadParameters& params,
- Document& document,
- const KURL& base_url,
- LinkCaller caller,
- ViewportDescription* viewport_description,
- ParserDisposition parser_disposition) {
- if (!document.Loader() || !params.rel.IsLinkPreload())
- return nullptr;
-
- base::Optional<ResourceType> resource_type =
- LinkLoader::GetResourceTypeFromAsAttribute(params.as);
-
- MediaValues* media_values = nullptr;
- KURL url;
- if (resource_type == ResourceType::kImage && !params.image_srcset.IsEmpty() &&
- RuntimeEnabledFeatures::PreloadImageSrcSetEnabled()) {
- media_values = CreateMediaValues(document, viewport_description);
- float source_size =
- SizesAttributeParser(media_values, params.image_sizes).length();
- ImageCandidate candidate = BestFitSourceForImageAttributes(
- media_values->DevicePixelRatio(), source_size, params.href,
- params.image_srcset);
- url = base_url.IsNull() ? document.CompleteURL(candidate.ToString())
- : KURL(base_url, candidate.ToString());
- } else {
- url = params.href;
- }
-
- UseCounter::Count(document, WebFeature::kLinkRelPreload);
- if (!url.IsValid() || url.IsEmpty()) {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kWarningMessageLevel,
- String("<link rel=preload> has an invalid `href` value")));
- return nullptr;
- }
-
- // Preload only if media matches
- if (!params.media.IsEmpty()) {
- if (!media_values)
- media_values = CreateMediaValues(document, viewport_description);
- if (!MediaMatches(params.media, media_values))
- return nullptr;
- }
-
- if (caller == kLinkCalledFromHeader)
- UseCounter::Count(document, WebFeature::kLinkHeaderPreload);
- if (resource_type == base::nullopt) {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kWarningMessageLevel,
- String("<link rel=preload> must have a valid `as` value")));
- return nullptr;
- }
-
- if (!IsSupportedType(resource_type.value(), params.type)) {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kWarningMessageLevel,
- String("<link rel=preload> has an unsupported `type` value")));
- return nullptr;
- }
- ResourceRequest resource_request(url);
- resource_request.SetRequestContext(ResourceFetcher::DetermineRequestContext(
- resource_type.value(), ResourceFetcher::kImageNotImageSet, false));
-
- resource_request.SetReferrerPolicy(params.referrer_policy);
-
- resource_request.SetFetchImportanceMode(
- GetFetchImportanceAttributeValue(params.importance));
-
- ResourceLoaderOptions options;
- options.initiator_info.name = fetch_initiator_type_names::kLink;
- options.parser_disposition = parser_disposition;
- FetchParameters link_fetch_params(resource_request, options);
- link_fetch_params.SetCharset(document.Encoding());
-
- if (params.cross_origin != kCrossOriginAttributeNotSet) {
- link_fetch_params.SetCrossOriginAccessControl(document.GetSecurityOrigin(),
- params.cross_origin);
- }
- link_fetch_params.SetContentSecurityPolicyNonce(params.nonce);
- Settings* settings = document.GetSettings();
- if (settings && settings->GetLogPreload()) {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kVerboseMessageLevel,
- String("Preload triggered for " + url.Host() + url.GetPath())));
- }
- link_fetch_params.SetLinkPreload(true);
- return document.Loader()->StartPreload(resource_type.value(),
- link_fetch_params);
-}
-
-// https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload
-static void ModulePreloadIfNeeded(const LinkLoadParameters& params,
- Document& document,
- ViewportDescription* viewport_description,
- LinkLoader* link_loader) {
- if (!document.Loader() || !params.rel.IsModulePreload())
- return;
-
- UseCounter::Count(document, WebFeature::kLinkRelModulePreload);
-
- // Step 1. "If the href attribute's value is the empty string, then return."
- // [spec text]
- if (params.href.IsEmpty()) {
- document.AddConsoleMessage(
- ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel,
- "<link rel=modulepreload> has no `href` value"));
- return;
- }
-
- // Step 2. "Let destination be the current state of the as attribute (a
- // destination), or "script" if it is in no state." [spec text]
- // Step 3. "If destination is not script-like, then queue a task on the
- // networking task source to fire an event named error at the link element,
- // and return." [spec text]
- // Currently we only support as="script".
- if (!params.as.IsEmpty() && params.as != "script") {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kWarningMessageLevel,
- String("<link rel=modulepreload> has an invalid `as` value " +
- params.as)));
- if (link_loader)
- link_loader->DispatchLinkLoadingErroredAsync();
- return;
- }
- mojom::RequestContextType destination = mojom::RequestContextType::SCRIPT;
-
- // Step 4. "Parse the URL given by the href attribute, relative to the
- // element's node document. If that fails, then return. Otherwise, let url be
- // the resulting URL record." [spec text]
- // |href| is already resolved in caller side.
- if (!params.href.IsValid()) {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kWarningMessageLevel,
- "<link rel=modulepreload> has an invalid `href` value " +
- params.href.GetString()));
- return;
- }
-
- // Preload only if media matches.
- // https://html.spec.whatwg.org/#processing-the-media-attribute
- if (!params.media.IsEmpty()) {
- MediaValues* media_values =
- CreateMediaValues(document, viewport_description);
- if (!MediaMatches(params.media, media_values))
- return;
- }
-
- // Step 5. "Let settings object be the link element's node document's relevant
- // settings object." [spec text]
- // |document| is the node document here, and its context document is the
- // relevant settings object.
- Document* context_document = document.ContextDocument();
- auto* settings_object =
- context_document->CreateFetchClientSettingsObjectSnapshot();
-
- Modulator* modulator =
- Modulator::From(ToScriptStateForMainWorld(context_document->GetFrame()));
- DCHECK(modulator);
- if (!modulator)
- return;
-
- // Step 6. "Let credentials mode be the module script credentials mode for the
- // crossorigin attribute." [spec text]
- network::mojom::FetchCredentialsMode credentials_mode =
- ScriptLoader::ModuleScriptCredentialsMode(params.cross_origin);
-
- // Step 7. "Let cryptographic nonce be the value of the nonce attribute, if it
- // is specified, or the empty string otherwise." [spec text]
- // |nonce| parameter is the value of the nonce attribute.
-
- // Step 8. "Let integrity metadata be the value of the integrity attribute, if
- // it is specified, or the empty string otherwise." [spec text]
- IntegrityMetadataSet integrity_metadata;
- if (!params.integrity.IsEmpty()) {
- SubresourceIntegrity::IntegrityFeatures integrity_features =
- SubresourceIntegrityHelper::GetFeatures(&document);
- SubresourceIntegrity::ReportInfo report_info;
- SubresourceIntegrity::ParseIntegrityAttribute(
- params.integrity, integrity_features, integrity_metadata, &report_info);
- SubresourceIntegrityHelper::DoReport(document, report_info);
- }
-
- // Step 9. "Let referrer policy be the current state of the element's
- // referrerpolicy attribute." [spec text]
- // |referrer_policy| parameter is the value of the referrerpolicy attribute.
-
- // Step 10. "Let options be a script fetch options whose cryptographic nonce
- // is cryptographic nonce, integrity metadata is integrity metadata, parser
- // metadata is "not-parser-inserted", credentials mode is credentials mode,
- // and referrer policy is referrer policy." [spec text]
- ModuleScriptFetchRequest request(
- params.href, destination,
- ScriptFetchOptions(params.nonce, integrity_metadata, params.integrity,
- kNotParserInserted, credentials_mode,
- params.referrer_policy),
- Referrer::NoReferrer(), TextPosition::MinimumPosition());
-
- // Step 11. "Fetch a single module script given url, settings object,
- // destination, options, settings object, "client", and with the top-level
- // module fetch flag set. Wait until algorithm asynchronously completes with
- // result." [spec text]
- modulator->FetchSingle(request, settings_object,
- ModuleGraphLevel::kDependentModuleFetch,
- ModuleScriptCustomFetchType::kNone, link_loader);
-
- Settings* settings = document.GetSettings();
- if (settings && settings->GetLogPreload()) {
- document.AddConsoleMessage(
- ConsoleMessage::Create(kOtherMessageSource, kVerboseMessageLevel,
- "Module preload triggered for " +
- params.href.Host() + params.href.GetPath()));
- }
-
- // Asynchronously continue processing after
- // LinkLoader::NotifyModuleLoadFinished() is called.
-}
-
-static Resource* PrefetchIfNeeded(const LinkLoadParameters& params,
- Document& document) {
- if (params.rel.IsLinkPrefetch() && params.href.IsValid() &&
- document.GetFrame()) {
- UseCounter::Count(document, WebFeature::kLinkRelPrefetch);
-
- ResourceRequest resource_request(params.href);
- resource_request.SetReferrerPolicy(params.referrer_policy);
- resource_request.SetFetchImportanceMode(
- GetFetchImportanceAttributeValue(params.importance));
-
- ResourceLoaderOptions options;
- options.initiator_info.name = fetch_initiator_type_names::kLink;
-
- FetchParameters link_fetch_params(resource_request, options);
- if (params.cross_origin != kCrossOriginAttributeNotSet) {
- link_fetch_params.SetCrossOriginAccessControl(
- document.GetSecurityOrigin(), params.cross_origin);
- }
- return LinkFetchResource::Fetch(ResourceType::kLinkPrefetch,
- link_fetch_params, document.Fetcher());
- }
- return nullptr;
-}
-
-void LinkLoader::LoadLinksFromHeader(
- const String& header_value,
- const KURL& base_url,
- LocalFrame& frame,
- Document* document,
- const NetworkHintsInterface& network_hints_interface,
- CanLoadResources can_load_resources,
- MediaPreloadPolicy media_policy,
- ViewportDescriptionWrapper* viewport_description_wrapper) {
- if (header_value.IsEmpty())
- return;
- LinkHeaderSet header_set(header_value);
- for (auto& header : header_set) {
- if (!header.Valid() || header.Url().IsEmpty() || header.Rel().IsEmpty())
- continue;
-
- if (media_policy == kOnlyLoadMedia && header.Media().IsEmpty())
- continue;
- if (media_policy == kOnlyLoadNonMedia && !header.Media().IsEmpty())
- continue;
-
- const LinkLoadParameters params(header, base_url);
- // Sanity check to avoid re-entrancy here.
- if (params.href == base_url)
- continue;
- if (can_load_resources != kOnlyLoadResources) {
- DnsPrefetchIfNeeded(params, document, &frame, network_hints_interface,
- kLinkCalledFromHeader);
-
- PreconnectIfNeeded(params, document, &frame, network_hints_interface,
- kLinkCalledFromHeader);
- }
- if (can_load_resources != kDoNotLoadResources) {
- DCHECK(document);
- ViewportDescription* viewport_description =
- (viewport_description_wrapper && viewport_description_wrapper->set)
- ? &(viewport_description_wrapper->description)
- : nullptr;
-
- PreloadIfNeeded(params, *document, base_url, kLinkCalledFromHeader,
- viewport_description, kNotParserInserted);
- PrefetchIfNeeded(params, *document);
- ModulePreloadIfNeeded(params, *document, viewport_description, nullptr);
- }
- if (params.rel.IsServiceWorker()) {
- UseCounter::Count(&frame, WebFeature::kLinkHeaderServiceWorker);
- }
- // TODO(yoav): Add more supported headers as needed.
- }
-}
-
bool LinkLoader::LoadLink(
const LinkLoadParameters& params,
Document& document,
@@ -651,22 +179,25 @@ bool LinkLoader::LoadLink(
if (!client_->ShouldLoadLink())
return false;
- DnsPrefetchIfNeeded(params, &document, document.GetFrame(),
- network_hints_interface, kLinkCalledFromMarkup);
+ PreloadHelper::DnsPrefetchIfNeeded(params, &document, document.GetFrame(),
+ network_hints_interface,
+ PreloadHelper::kLinkCalledFromMarkup);
- PreconnectIfNeeded(params, &document, document.GetFrame(),
- network_hints_interface, kLinkCalledFromMarkup);
+ PreloadHelper::PreconnectIfNeeded(params, &document, document.GetFrame(),
+ network_hints_interface,
+ PreloadHelper::kLinkCalledFromMarkup);
- Resource* resource = PreloadIfNeeded(
- params, document, NullURL(), kLinkCalledFromMarkup, nullptr,
+ Resource* resource = PreloadHelper::PreloadIfNeeded(
+ params, document, NullURL(), PreloadHelper::kLinkCalledFromMarkup,
+ nullptr,
client_->IsLinkCreatedByParser() ? kParserInserted : kNotParserInserted);
if (!resource) {
- resource = PrefetchIfNeeded(params, document);
+ resource = PreloadHelper::PrefetchIfNeeded(params, document);
}
if (resource)
finish_observer_ = MakeGarbageCollected<FinishObserver>(this, resource);
- ModulePreloadIfNeeded(params, document, nullptr, this);
+ PreloadHelper::ModulePreloadIfNeeded(params, document, nullptr, this);
if (const unsigned prerender_rel_types =
PrerenderRelTypesFromRelAttribute(params.rel, document)) {
@@ -698,7 +229,7 @@ void LinkLoader::LoadStylesheet(const LinkLoadParameters& params,
mojom::FetchImportanceMode importance_mode =
GetFetchImportanceAttributeValue(params.importance);
DCHECK(importance_mode == mojom::FetchImportanceMode::kImportanceAuto ||
- RuntimeEnabledFeatures::PriorityHintsEnabled());
+ origin_trials::PriorityHintsEnabled(&document));
resource_request.SetFetchImportanceMode(importance_mode);
ResourceLoaderOptions options;
@@ -731,12 +262,6 @@ void LinkLoader::LoadStylesheet(const LinkLoadParameters& params,
link_client);
}
-void LinkLoader::DispatchLinkLoadingErroredAsync() {
- client_->GetLoadingTaskRunner()->PostTask(
- FROM_HERE, WTF::Bind(&LinkLoaderClient::LinkLoadingErrored,
- WrapPersistent(client_.Get())));
-}
-
void LinkLoader::Abort() {
if (prerender_) {
prerender_->Cancel();
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader.h b/chromium/third_party/blink/renderer/core/loader/link_loader.h
index 75674849d22..dc9f1eb7d94 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader.h
@@ -32,68 +32,20 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LINK_LOADER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LINK_LOADER_H_
-#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/link_rel_attribute.h"
-#include "third_party/blink/renderer/core/loader/link_loader_client.h"
+#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
#include "third_party/blink/renderer/core/script/modulator.h"
-#include "third_party/blink/renderer/platform/cross_origin_attribute_value.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/prerender_client.h"
namespace blink {
class Document;
-class LinkHeader;
-class LocalFrame;
+class LinkLoaderClient;
class NetworkHintsInterface;
class PrerenderHandle;
class Resource;
-enum class ResourceType : uint8_t;
-struct ViewportDescriptionWrapper;
-
-// The parameter object for LinkLoader::LoadLink().
-struct LinkLoadParameters {
- LinkLoadParameters(const LinkRelAttribute& rel,
- const CrossOriginAttributeValue& cross_origin,
- const String& type,
- const String& as,
- const String& media,
- const String& nonce,
- const String& integrity,
- const String& importance,
- network::mojom::ReferrerPolicy referrer_policy,
- const KURL& href,
- const String& image_srcset,
- const String& image_sizes)
- : rel(rel),
- cross_origin(cross_origin),
- type(type),
- as(as),
- media(media),
- nonce(nonce),
- integrity(integrity),
- importance(importance),
- referrer_policy(referrer_policy),
- href(href),
- image_srcset(image_srcset),
- image_sizes(image_sizes) {}
- LinkLoadParameters(const LinkHeader&, const KURL& base_url);
-
- LinkRelAttribute rel;
- CrossOriginAttributeValue cross_origin;
- String type;
- String as;
- String media;
- String nonce;
- String integrity;
- String importance;
- network::mojom::ReferrerPolicy referrer_policy;
- KURL href;
- String image_srcset;
- String image_sizes;
-};
+class ResourceClient;
// The LinkLoader can load link rel types icon, dns-prefetch, prefetch, and
// prerender.
@@ -102,10 +54,7 @@ class CORE_EXPORT LinkLoader final : public SingleModuleClient,
USING_GARBAGE_COLLECTED_MIXIN(LinkLoader);
public:
- static LinkLoader* Create(LinkLoaderClient* client) {
- return MakeGarbageCollected<LinkLoader>(client,
- client->GetLoadingTaskRunner());
- }
+ static LinkLoader* Create(LinkLoaderClient*);
LinkLoader(LinkLoaderClient*, scoped_refptr<base::SingleThreadTaskRunner>);
~LinkLoader() override;
@@ -126,26 +75,6 @@ class CORE_EXPORT LinkLoader final : public SingleModuleClient,
FetchParameters::DeferOption,
Document&,
ResourceClient*);
- void DispatchLinkLoadingErroredAsync();
-
- enum CanLoadResources {
- kOnlyLoadResources,
- kDoNotLoadResources,
- kLoadResourcesAndPreconnect
- };
- // Media links cannot be preloaded until the first chunk is parsed. The rest
- // can be preloaded at commit time.
- enum MediaPreloadPolicy { kLoadAll, kOnlyLoadNonMedia, kOnlyLoadMedia };
- static void LoadLinksFromHeader(const String& header_value,
- const KURL& base_url,
- LocalFrame&,
- Document*, // can be nullptr
- const NetworkHintsInterface&,
- CanLoadResources,
- MediaPreloadPolicy,
- ViewportDescriptionWrapper*);
- static base::Optional<ResourceType> GetResourceTypeFromAsAttribute(
- const String& as);
Resource* GetResourceForTesting();
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc
index 6d777dd9e09..e5e67c171c1 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -35,9 +35,11 @@ class MockLinkLoaderClient final
public:
static MockLinkLoaderClient* Create(bool should_load) {
- return new MockLinkLoaderClient(should_load);
+ return MakeGarbageCollected<MockLinkLoaderClient>(should_load);
}
+ explicit MockLinkLoaderClient(bool should_load) : should_load_(should_load) {}
+
void Trace(blink::Visitor* visitor) override {
LinkLoaderClient::Trace(visitor);
}
@@ -57,8 +59,6 @@ class MockLinkLoaderClient final
}
private:
- explicit MockLinkLoaderClient(bool should_load) : should_load_(should_load) {}
-
const bool should_load_;
};
@@ -468,12 +468,11 @@ class ModulePreloadTestModulator final : public DummyModulator {
ModulePreloadTestModulator(const ModulePreloadTestParams* params)
: params_(params), fetched_(false) {}
- void FetchSingle(
- const ModuleScriptFetchRequest& request,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- ModuleGraphLevel,
- ModuleScriptCustomFetchType custom_fetch_type,
- SingleModuleClient*) override {
+ void FetchSingle(const ModuleScriptFetchRequest& request,
+ ResourceFetcher*,
+ ModuleGraphLevel,
+ ModuleScriptCustomFetchType custom_fetch_type,
+ SingleModuleClient*) override {
fetched_ = true;
EXPECT_EQ(KURL(NullURL(), params_->href), request.Url());
@@ -500,7 +499,7 @@ TEST_P(LinkLoaderModulePreloadTest, ModulePreload) {
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create();
ModulePreloadTestModulator* modulator =
- new ModulePreloadTestModulator(&test_case);
+ MakeGarbageCollected<ModulePreloadTestModulator>(&test_case);
Modulator::SetModulator(
ToScriptStateForMainWorld(dummy_page_holder->GetDocument().GetFrame()),
modulator);
diff --git a/chromium/third_party/blink/renderer/core/loader/long_task_detector.cc b/chromium/third_party/blink/renderer/core/loader/long_task_detector.cc
index dc9f2876445..a78063e2fd5 100644
--- a/chromium/third_party/blink/renderer/core/loader/long_task_detector.cc
+++ b/chromium/third_party/blink/renderer/core/loader/long_task_detector.cc
@@ -14,7 +14,7 @@ constexpr base::TimeDelta LongTaskDetector::kLongTaskThreshold;
// static
LongTaskDetector& LongTaskDetector::Instance() {
DEFINE_STATIC_LOCAL(Persistent<LongTaskDetector>, long_task_detector,
- (new LongTaskDetector));
+ (MakeGarbageCollected<LongTaskDetector>()));
DCHECK(IsMainThread());
return *long_task_detector;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/long_task_detector.h b/chromium/third_party/blink/renderer/core/loader/long_task_detector.h
index acdff4283ba..f98bc1d430e 100644
--- a/chromium/third_party/blink/renderer/core/loader/long_task_detector.h
+++ b/chromium/third_party/blink/renderer/core/loader/long_task_detector.h
@@ -32,6 +32,8 @@ class CORE_EXPORT LongTaskDetector final
public:
static LongTaskDetector& Instance();
+ LongTaskDetector();
+
void RegisterObserver(LongTaskObserver*);
void UnregisterObserver(LongTaskObserver*);
@@ -41,8 +43,6 @@ class CORE_EXPORT LongTaskDetector final
base::TimeDelta::FromMilliseconds(50);
private:
- LongTaskDetector();
-
// scheduler::TaskTimeObserver implementation
void WillProcessTask(base::TimeTicks start_time) override {}
void DidProcessTask(base::TimeTicks start_time,
diff --git a/chromium/third_party/blink/renderer/core/loader/long_task_detector_test.cc b/chromium/third_party/blink/renderer/core/loader/long_task_detector_test.cc
index 453bf7c96f2..ce980c0726b 100644
--- a/chromium/third_party/blink/renderer/core/loader/long_task_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/long_task_detector_test.cc
@@ -69,7 +69,8 @@ class LongTaskDetectorTest : public testing::Test {
};
TEST_F(LongTaskDetectorTest, DeliversLongTaskNotificationOnlyWhenRegistered) {
- TestLongTaskObserver* long_task_observer = new TestLongTaskObserver();
+ TestLongTaskObserver* long_task_observer =
+ MakeGarbageCollected<TestLongTaskObserver>();
SimulateTask(LongTaskDetector::kLongTaskThreshold +
base::TimeDelta::FromMilliseconds(10));
EXPECT_EQ(long_task_observer->last_long_task_end, TimeTicks());
@@ -92,7 +93,8 @@ TEST_F(LongTaskDetectorTest, DeliversLongTaskNotificationOnlyWhenRegistered) {
}
TEST_F(LongTaskDetectorTest, DoesNotGetNotifiedOfShortTasks) {
- TestLongTaskObserver* long_task_observer = new TestLongTaskObserver();
+ TestLongTaskObserver* long_task_observer =
+ MakeGarbageCollected<TestLongTaskObserver>();
LongTaskDetector::Instance().RegisterObserver(long_task_observer);
SimulateTask(LongTaskDetector::kLongTaskThreshold -
base::TimeDelta::FromMilliseconds(10));
@@ -105,7 +107,8 @@ TEST_F(LongTaskDetectorTest, DoesNotGetNotifiedOfShortTasks) {
}
TEST_F(LongTaskDetectorTest, RegisterSameObserverTwice) {
- TestLongTaskObserver* long_task_observer = new TestLongTaskObserver();
+ TestLongTaskObserver* long_task_observer =
+ MakeGarbageCollected<TestLongTaskObserver>();
LongTaskDetector::Instance().RegisterObserver(long_task_observer);
LongTaskDetector::Instance().RegisterObserver(long_task_observer);
diff --git a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index 1c148e0da03..068ee603b59 100644
--- a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -52,6 +52,7 @@
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_settings.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -474,8 +475,10 @@ bool MixedContentChecker::ShouldBlockFetchOnWorker(
const KURL& url,
SecurityViolationReportingPolicy reporting_policy,
bool is_worklet_global_scope) {
- if (!MixedContentChecker::IsMixedContent(
- *worker_fetch_context.GetFetchClientSettingsObject(), url)) {
+ const FetchClientSettingsObject& fetch_client_settings_object =
+ worker_fetch_context.GetResourceFetcherProperties()
+ .GetFetchClientSettingsObject();
+ if (!MixedContentChecker::IsMixedContent(fetch_client_settings_object, url)) {
return false;
}
@@ -511,10 +514,11 @@ bool MixedContentChecker::ShouldBlockFetchOnWorker(
worker_fetch_context.GetWorkerContentSettingsClient()
->AllowRunningInsecureContent(
settings->GetAllowRunningOfInsecureContent(),
- worker_fetch_context.GetSecurityOrigin(), url);
+ fetch_client_settings_object.GetSecurityOrigin(), url);
if (allowed) {
worker_fetch_context.GetWebWorkerFetchContext()->DidRunInsecureContent(
- WebSecurityOrigin(worker_fetch_context.GetSecurityOrigin()), url);
+ WebSecurityOrigin(fetch_client_settings_object.GetSecurityOrigin()),
+ url);
worker_fetch_context.CountUsage(
WebFeature::kMixedContentBlockableAllowed);
}
@@ -584,8 +588,10 @@ bool MixedContentChecker::IsWebSocketAllowed(
bool MixedContentChecker::IsWebSocketAllowed(
const WorkerFetchContext& worker_fetch_context,
const KURL& url) {
- if (!MixedContentChecker::IsMixedContent(
- *worker_fetch_context.GetFetchClientSettingsObject(), url)) {
+ const FetchClientSettingsObject& fetch_client_settings_object =
+ worker_fetch_context.GetResourceFetcherProperties()
+ .GetFetchClientSettingsObject();
+ if (!MixedContentChecker::IsMixedContent(fetch_client_settings_object, url)) {
return true;
}
@@ -595,7 +601,7 @@ bool MixedContentChecker::IsWebSocketAllowed(
SecurityContext* security_context =
&worker_fetch_context.GetSecurityContext();
const SecurityOrigin* security_origin =
- worker_fetch_context.GetSecurityOrigin();
+ fetch_client_settings_object.GetSecurityOrigin();
bool allowed = IsWebSocketAllowedImpl(worker_fetch_context, security_context,
settings, url);
@@ -651,11 +657,11 @@ bool MixedContentChecker::IsMixedFormAction(
return true;
}
-bool MixedContentChecker::ShouldAutoupgrade(KURL frame_url,
+bool MixedContentChecker::ShouldAutoupgrade(HttpsState context_https_state,
WebMixedContentContextType type) {
if (!base::FeatureList::IsEnabled(
blink::features::kMixedContentAutoupgrade) ||
- !frame_url.ProtocolIs("https") ||
+ context_https_state == HttpsState::kNone ||
type == WebMixedContentContextType::kNotMixedContent) {
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h
index bede62aa0b0..4ee33934563 100644
--- a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h
+++ b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h
@@ -37,6 +37,7 @@
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/weborigin/security_violation_reporting_policy.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -93,7 +94,7 @@ class CORE_EXPORT MixedContentChecker final {
SecurityViolationReportingPolicy =
SecurityViolationReportingPolicy::kReport);
- static bool ShouldAutoupgrade(KURL frame_url,
+ static bool ShouldAutoupgrade(HttpsState context_https_state,
WebMixedContentContextType type);
static void CheckMixedPrivatePublic(LocalFrame*,
diff --git a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
index 8000502b147..2a15a0e240f 100644
--- a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
@@ -121,7 +121,7 @@ class MixedContentCheckerMockLocalFrameClient : public EmptyLocalFrameClient {
TEST(MixedContentCheckerTest, HandleCertificateError) {
MixedContentCheckerMockLocalFrameClient* client =
- new MixedContentCheckerMockLocalFrameClient;
+ MakeGarbageCollected<MixedContentCheckerMockLocalFrameClient>();
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(1, 1), nullptr, client);
@@ -153,7 +153,7 @@ TEST(MixedContentCheckerTest, HandleCertificateError) {
TEST(MixedContentCheckerTest, DetectMixedForm) {
MixedContentCheckerMockLocalFrameClient* client =
- new MixedContentCheckerMockLocalFrameClient;
+ MakeGarbageCollected<MixedContentCheckerMockLocalFrameClient>();
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(1, 1), nullptr, client);
@@ -186,7 +186,7 @@ TEST(MixedContentCheckerTest, DetectMixedForm) {
TEST(MixedContentCheckerTest, DetectMixedFavicon) {
MixedContentCheckerMockLocalFrameClient* client =
- new MixedContentCheckerMockLocalFrameClient;
+ MakeGarbageCollected<MixedContentCheckerMockLocalFrameClient>();
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(1, 1), nullptr, client);
dummy_page_holder->GetFrame().GetSettings()->SetAllowRunningOfInsecureContent(
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
index 9b0da3f68a8..017e155c437 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
@@ -12,23 +12,20 @@
namespace blink {
-DocumentModuleScriptFetcher::DocumentModuleScriptFetcher(
- ResourceFetcher* fetcher)
- : fetcher_(fetcher) {
- DCHECK(fetcher_);
-}
-
-void DocumentModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
- ModuleGraphLevel level,
- ModuleScriptFetcher::Client* client) {
+void DocumentModuleScriptFetcher::Fetch(
+ FetchParameters& fetch_params,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ ModuleGraphLevel level,
+ ModuleScriptFetcher::Client* client) {
+ DCHECK(fetch_client_settings_object_fetcher);
DCHECK(!client_);
client_ = client;
if (FetchIfLayeredAPI(fetch_params))
return;
- ScriptResource::Fetch(fetch_params, fetcher_, this,
- ScriptResource::kNoStreaming);
+ ScriptResource::Fetch(fetch_params, fetch_client_settings_object_fetcher,
+ this, ScriptResource::kNoStreaming);
}
void DocumentModuleScriptFetcher::NotifyFinished(Resource* resource) {
@@ -43,13 +40,13 @@ void DocumentModuleScriptFetcher::NotifyFinished(Resource* resource) {
}
ModuleScriptCreationParams params(
- script_resource->GetResponse().Url(), script_resource->SourceText(),
+ script_resource->GetResponse().CurrentRequestUrl(),
+ script_resource->SourceText(),
script_resource->GetResourceRequest().GetFetchCredentialsMode());
client_->NotifyFetchFinished(params, error_messages);
}
void DocumentModuleScriptFetcher::Trace(blink::Visitor* visitor) {
- visitor->Trace(fetcher_);
visitor->Trace(client_);
ResourceClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h
index 49fb6b6e04a..11123fb036c 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h
@@ -21,11 +21,14 @@ class CORE_EXPORT DocumentModuleScriptFetcher final
USING_GARBAGE_COLLECTED_MIXIN(DocumentModuleScriptFetcher);
public:
- explicit DocumentModuleScriptFetcher(ResourceFetcher*);
+ DocumentModuleScriptFetcher() = default;
~DocumentModuleScriptFetcher() override = default;
// Implements ModuleScriptFetcher.
- void Fetch(FetchParameters&, ModuleGraphLevel, Client*) override;
+ void Fetch(FetchParameters&,
+ ResourceFetcher*,
+ ModuleGraphLevel,
+ Client*) override;
// Implements ResourceClient
void NotifyFinished(Resource*) override;
@@ -36,7 +39,6 @@ class CORE_EXPORT DocumentModuleScriptFetcher final
private:
bool FetchIfLayeredAPI(FetchParameters&);
- const Member<ResourceFetcher> fetcher_;
Member<Client> client_;
};
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc
index a69982edbca..e3b3bb542ec 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc
@@ -17,6 +17,7 @@ InstalledServiceWorkerModuleScriptFetcher::
void InstalledServiceWorkerModuleScriptFetcher::Fetch(
FetchParameters& fetch_params,
+ ResourceFetcher*,
ModuleGraphLevel level,
ModuleScriptFetcher::Client* client) {
DCHECK(global_scope_->IsContextThread());
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h
index 5788aaec6a1..486e5dfa69a 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h
@@ -25,6 +25,7 @@ class CORE_EXPORT InstalledServiceWorkerModuleScriptFetcher final
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client*) override;
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc
index dce66bc435f..1af6cfc2c35 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc
@@ -64,7 +64,8 @@ bool ModuleScriptFetcher::WasModuleLoadSuccessful(
"HTML spec.";
error_messages->push_back(ConsoleMessage::CreateForRequest(
kJSMessageSource, kErrorMessageLevel, message,
- response.Url().GetString(), nullptr, resource->Identifier()));
+ response.CurrentRequestUrl().GetString(), nullptr,
+ resource->Identifier()));
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
index 077fe4bc430..6a57a727ccd 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
@@ -16,6 +16,7 @@
namespace blink {
class ConsoleMessage;
+class ResourceFetcher;
// ModuleScriptFetcher is an abstract class to fetch module scripts. Derived
// classes are expected to fetch a module script for the given FetchParameters
@@ -36,7 +37,10 @@ class CORE_EXPORT ModuleScriptFetcher : public ResourceClient {
// Takes a non-const reference to FetchParameters because
// ScriptResource::Fetch() requires it.
- virtual void Fetch(FetchParameters&, ModuleGraphLevel, Client*) = 0;
+ virtual void Fetch(FetchParameters&,
+ ResourceFetcher*,
+ ModuleGraphLevel,
+ Client*) = 0;
protected:
static bool WasModuleLoadSuccessful(
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
index ef74f6b2702..66cc33955b3 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
@@ -13,6 +13,8 @@
#include "third_party/blink/renderer/core/script/module_script.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -78,7 +80,7 @@ void ModuleScriptLoader::AdvanceState(ModuleScriptLoader::State new_state) {
void ModuleScriptLoader::Fetch(
const ModuleScriptFetchRequest& module_request,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
Modulator* module_map_settings_object,
ModuleScriptCustomFetchType custom_fetch_type,
@@ -87,16 +89,20 @@ void ModuleScriptLoader::Fetch(
ModuleScriptLoader* loader = MakeGarbageCollected<ModuleScriptLoader>(
module_map_settings_object, module_request.Options(), registry, client);
registry->AddLoader(loader);
- loader->FetchInternal(module_request, fetch_client_settings_object, level,
- custom_fetch_type);
+ loader->FetchInternal(module_request, fetch_client_settings_object_fetcher,
+ level, custom_fetch_type);
}
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
void ModuleScriptLoader::FetchInternal(
const ModuleScriptFetchRequest& module_request,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
ModuleScriptCustomFetchType custom_fetch_type) {
+ const FetchClientSettingsObject& fetch_client_settings_object =
+ fetch_client_settings_object_fetcher->GetProperties()
+ .GetFetchClientSettingsObject();
+
// Step 4. "Set moduleMap[url] to "fetching"." [spec text]
AdvanceState(State::kFetching);
@@ -157,20 +163,20 @@ void ModuleScriptLoader::FetchInternal(
network::mojom::ReferrerPolicy referrer_policy =
module_request.Options().GetReferrerPolicy();
if (referrer_policy == network::mojom::ReferrerPolicy::kDefault)
- referrer_policy = fetch_client_settings_object->GetReferrerPolicy();
+ referrer_policy = fetch_client_settings_object.GetReferrerPolicy();
// Step 5. "... mode is "cors", ..."
// [SMSR] "... and its credentials mode to options's credentials mode."
// [spec text]
fetch_params.SetCrossOriginAccessControl(
- fetch_client_settings_object->GetSecurityOrigin(),
+ fetch_client_settings_object.GetSecurityOrigin(),
options_.CredentialsMode());
// Step 5. "... referrer is referrer, ..." [spec text]
// Note: For now this is done below with SetHTTPReferrer()
String referrer_string = module_request.ReferrerString();
if (referrer_string == Referrer::ClientReferrerString())
- referrer_string = fetch_client_settings_object->GetOutgoingReferrer();
+ referrer_string = fetch_client_settings_object.GetOutgoingReferrer();
// TODO(domfarolino): Stop storing ResourceRequest's referrer as a
// blink::Referrer (https://crbug.com/850813).
@@ -179,6 +185,12 @@ void ModuleScriptLoader::FetchInternal(
fetch_params.GetResourceRequest().Url(),
referrer_string));
+ // Priority Hints and a request's "importance" are currently non-standard, but
+ // we can assume the following (see https://crbug.com/821464):
+ // Step 5. "... importance is options's importance ..."
+ fetch_params.MutableResourceRequest().SetFetchImportanceMode(
+ options_.Importance());
+
// Step 5. "... and client is fetch client settings object." [spec text]
// -> set by ResourceFetcher
@@ -209,7 +221,8 @@ void ModuleScriptLoader::FetchInternal(
// steps as part of the fetch's process response for the response response."
// [spec text]
module_fetcher_ = modulator_->CreateModuleScriptFetcher(custom_fetch_type);
- module_fetcher_->Fetch(fetch_params, level, this);
+ module_fetcher_->Fetch(fetch_params, fetch_client_settings_object_fetcher,
+ level, this);
}
void ModuleScriptLoader::NotifyFetchFinished(
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h
index 14c9d7ffb91..223bd92023f 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h
@@ -16,11 +16,11 @@
namespace blink {
-class FetchClientSettingsObjectSnapshot;
class Modulator;
class ModuleScript;
class ModuleScriptLoaderClient;
class ModuleScriptLoaderRegistry;
+class ResourceFetcher;
enum class ModuleGraphLevel;
// ModuleScriptLoader is responsible for loading a new single ModuleScript.
@@ -51,14 +51,13 @@ class CORE_EXPORT ModuleScriptLoader final
ModuleScriptLoaderClient*);
~ModuleScriptLoader();
- static void Fetch(
- const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- ModuleGraphLevel,
- Modulator* module_map_settings_object,
- ModuleScriptCustomFetchType,
- ModuleScriptLoaderRegistry*,
- ModuleScriptLoaderClient*);
+ static void Fetch(const ModuleScriptFetchRequest&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ ModuleGraphLevel,
+ Modulator* module_map_settings_object,
+ ModuleScriptCustomFetchType,
+ ModuleScriptLoaderRegistry*,
+ ModuleScriptLoaderClient*);
// Implements ModuleScriptFetcher::Client.
void NotifyFetchFinished(
@@ -71,11 +70,10 @@ class CORE_EXPORT ModuleScriptLoader final
void Trace(blink::Visitor*) override;
private:
- void FetchInternal(
- const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- ModuleGraphLevel,
- ModuleScriptCustomFetchType);
+ void FetchInternal(const ModuleScriptFetchRequest&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ ModuleGraphLevel,
+ ModuleScriptCustomFetchType);
void AdvanceState(State new_state);
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
index 5f169e71011..d3be41645c6 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/loader/modulescript/module_script_loader.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -23,7 +24,7 @@
#include "third_party/blink/renderer/core/testing/dummy_modulator.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
-#include "third_party/blink/renderer/core/workers/main_thread_worklet_reporting_proxy.h"
+#include "third_party/blink/renderer/core/workers/worker_thread_test_helper.h"
#include "third_party/blink/renderer/core/workers/worklet_global_scope.h"
#include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -31,6 +32,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -66,13 +68,8 @@ class TestModuleScriptLoaderClient final
class ModuleScriptLoaderTestModulator final : public DummyModulator {
public:
- ModuleScriptLoaderTestModulator(
- ScriptState* script_state,
- scoped_refptr<const SecurityOrigin> security_origin,
- ResourceFetcher* fetcher)
- : script_state_(script_state),
- security_origin_(std::move(security_origin)),
- fetcher_(fetcher) {}
+ explicit ModuleScriptLoaderTestModulator(ScriptState* script_state)
+ : script_state_(script_state) {}
~ModuleScriptLoaderTestModulator() override = default;
@@ -101,25 +98,20 @@ class ModuleScriptLoaderTestModulator final : public DummyModulator {
EXPECT_EQ(ModuleScriptCustomFetchType::kWorkletAddModule,
custom_fetch_type);
return MakeGarbageCollected<WorkletModuleScriptFetcher>(
- Fetcher(), scope->GetModuleResponsesMap());
+ scope->GetModuleResponsesMap());
}
EXPECT_EQ(ModuleScriptCustomFetchType::kNone, custom_fetch_type);
- return MakeGarbageCollected<DocumentModuleScriptFetcher>(Fetcher());
+ return MakeGarbageCollected<DocumentModuleScriptFetcher>();
}
- ResourceFetcher* Fetcher() const { return fetcher_.Get(); }
-
void Trace(blink::Visitor*) override;
private:
Member<ScriptState> script_state_;
- scoped_refptr<const SecurityOrigin> security_origin_;
- Member<ResourceFetcher> fetcher_;
Vector<ModuleRequest> requests_;
};
void ModuleScriptLoaderTestModulator::Trace(blink::Visitor* visitor) {
- visitor->Trace(fetcher_);
visitor->Trace(script_state_);
DummyModulator::Trace(visitor);
}
@@ -130,8 +122,7 @@ class ModuleScriptLoaderTest : public PageTestBase {
DISALLOW_COPY_AND_ASSIGN(ModuleScriptLoaderTest);
public:
- ModuleScriptLoaderTest() = default;
- void SetUp() override;
+ ModuleScriptLoaderTest();
void InitializeForDocument();
void InitializeForWorklet();
@@ -147,57 +138,63 @@ class ModuleScriptLoaderTest : public PageTestBase {
ModuleScriptLoaderTestModulator* GetModulator() { return modulator_.Get(); }
void RunUntilIdle() {
- base::SingleThreadTaskRunner* runner =
- GetModulator()->Fetcher()->Context().GetLoadingTaskRunner().get();
- static_cast<scheduler::FakeTaskRunner*>(runner)->RunUntilIdle();
+ static_cast<scheduler::FakeTaskRunner*>(fetcher_->GetTaskRunner().get())
+ ->RunUntilIdle();
}
protected:
+ const KURL url_;
+ const scoped_refptr<const SecurityOrigin> security_origin_;
+
+ Persistent<ResourceFetcher> fetcher_;
+
ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_;
- std::unique_ptr<MainThreadWorkletReportingProxy> reporting_proxy_;
+ std::unique_ptr<MockWorkerReportingProxy> reporting_proxy_;
Persistent<ModuleScriptLoaderTestModulator> modulator_;
Persistent<WorkletGlobalScope> global_scope_;
};
-void ModuleScriptLoaderTest::SetUp() {
+ModuleScriptLoaderTest::ModuleScriptLoaderTest()
+ : url_("https://example.test"),
+ security_origin_(SecurityOrigin::Create(url_)) {
platform_->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
- PageTestBase::SetUp(IntSize(500, 500));
- GetDocument().SetURL(KURL("https://example.test"));
- GetDocument().SetSecurityOrigin(SecurityOrigin::Create(GetDocument().Url()));
}
void ModuleScriptLoaderTest::InitializeForDocument() {
- auto* fetch_context =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- auto* fetcher = ResourceFetcher::Create(fetch_context);
- modulator_ = new ModuleScriptLoaderTestModulator(
- ToScriptStateForMainWorld(&GetFrame()), GetDocument().GetSecurityOrigin(),
- fetcher);
+ auto* fetch_context = MakeGarbageCollected<MockFetchContext>();
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_);
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, fetch_context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
+ modulator_ = MakeGarbageCollected<ModuleScriptLoaderTestModulator>(
+ ToScriptStateForMainWorld(&GetFrame()));
}
void ModuleScriptLoaderTest::InitializeForWorklet() {
- auto* fetch_context =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- auto* fetcher = ResourceFetcher::Create(fetch_context);
- reporting_proxy_ =
- std::make_unique<MainThreadWorkletReportingProxy>(&GetDocument());
+ auto* fetch_context = MakeGarbageCollected<MockFetchContext>();
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_);
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, fetch_context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
+ reporting_proxy_ = std::make_unique<MockWorkerReportingProxy>();
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- GetDocument().Url(), mojom::ScriptType::kModule,
- GetDocument().UserAgent(), nullptr /* web_worker_fetch_context */,
- Vector<CSPHeaderAndType>(), GetDocument().GetReferrerPolicy(),
- GetDocument().GetSecurityOrigin(), GetDocument().IsSecureContext(),
- GetDocument().GetHttpsState(), nullptr /* worker_clients */,
- GetDocument().AddressSpace(),
- OriginTrialContext::GetTokens(&GetDocument()).get(),
- base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap);
+ url_, mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled, "UserAgent",
+ nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
+ network::mojom::ReferrerPolicy::kDefault, security_origin_.get(),
+ true /* is_secure_context */, HttpsState::kModern,
+ nullptr /* worker_clients */, mojom::IPAddressSpace::kLocal,
+ nullptr /* origin_trial_token */, base::UnguessableToken::Create(),
+ nullptr /* worker_settings */, kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>());
global_scope_ = MakeGarbageCollected<WorkletGlobalScope>(
std::move(creation_params), *reporting_proxy_, &GetFrame());
global_scope_->ScriptController()->InitializeContextIfNeeded("Dummy Context",
NullURL());
- modulator_ = new ModuleScriptLoaderTestModulator(
- global_scope_->ScriptController()->GetScriptState(),
- GetDocument().GetSecurityOrigin(), fetcher);
+ modulator_ = MakeGarbageCollected<ModuleScriptLoaderTestModulator>(
+ global_scope_->ScriptController()->GetScriptState());
}
void ModuleScriptLoaderTest::TestFetchDataURL(
@@ -205,17 +202,16 @@ void ModuleScriptLoaderTest::TestFetchDataURL(
TestModuleScriptLoaderClient* client) {
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
KURL url("data:text/javascript,export default 'grapes';");
- auto* fetch_client_settings_object =
- GetDocument().CreateFetchClientSettingsObjectSnapshot();
- ModuleScriptLoader::Fetch(
- ModuleScriptFetchRequest::CreateForTest(url),
- fetch_client_settings_object, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry, client);
+ ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
+ GetModulator(), custom_fetch_type, registry,
+ client);
}
TEST_F(ModuleScriptLoaderTest, FetchDataURL) {
InitializeForDocument();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchDataURL(ModuleScriptCustomFetchType::kNone, client);
// TODO(leszeks): This should finish synchronously, but currently due
@@ -229,7 +225,8 @@ TEST_F(ModuleScriptLoaderTest, FetchDataURL) {
TEST_F(ModuleScriptLoaderTest, FetchDataURL_OnWorklet) {
InitializeForWorklet();
- TestModuleScriptLoaderClient* client1 = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client1 =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchDataURL(ModuleScriptCustomFetchType::kWorkletAddModule, client1);
EXPECT_FALSE(client1->WasNotifyFinished())
@@ -243,7 +240,8 @@ TEST_F(ModuleScriptLoaderTest, FetchDataURL_OnWorklet) {
// Try to fetch the same URL again in order to verify the case where
// WorkletModuleResponsesMap serves a cache.
- TestModuleScriptLoaderClient* client2 = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client2 =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchDataURL(ModuleScriptCustomFetchType::kWorkletAddModule, client2);
EXPECT_FALSE(client2->WasNotifyFinished())
@@ -261,18 +259,17 @@ void ModuleScriptLoaderTest::TestInvalidSpecifier(
TestModuleScriptLoaderClient* client) {
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
KURL url("data:text/javascript,import 'invalid';export default 'grapes';");
- auto* fetch_client_settings_object =
- GetDocument().CreateFetchClientSettingsObjectSnapshot();
GetModulator()->SetModuleRequests({"invalid"});
- ModuleScriptLoader::Fetch(
- ModuleScriptFetchRequest::CreateForTest(url),
- fetch_client_settings_object, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry, client);
+ ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
+ GetModulator(), custom_fetch_type, registry,
+ client);
}
TEST_F(ModuleScriptLoaderTest, InvalidSpecifier) {
InitializeForDocument();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestInvalidSpecifier(ModuleScriptCustomFetchType::kNone, client);
// TODO(leszeks): This should finish synchronously, but currently due
@@ -287,7 +284,8 @@ TEST_F(ModuleScriptLoaderTest, InvalidSpecifier) {
TEST_F(ModuleScriptLoaderTest, InvalidSpecifier_OnWorklet) {
InitializeForWorklet();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestInvalidSpecifier(ModuleScriptCustomFetchType::kWorkletAddModule, client);
EXPECT_FALSE(client->WasNotifyFinished())
@@ -306,17 +304,16 @@ void ModuleScriptLoaderTest::TestFetchInvalidURL(
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
KURL url;
EXPECT_FALSE(url.IsValid());
- auto* fetch_client_settings_object =
- GetDocument().CreateFetchClientSettingsObjectSnapshot();
- ModuleScriptLoader::Fetch(
- ModuleScriptFetchRequest::CreateForTest(url),
- fetch_client_settings_object, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry, client);
+ ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
+ GetModulator(), custom_fetch_type, registry,
+ client);
}
TEST_F(ModuleScriptLoaderTest, FetchInvalidURL) {
InitializeForDocument();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchInvalidURL(ModuleScriptCustomFetchType::kNone, client);
// TODO(leszeks): This should finish synchronously, but currently due
@@ -328,7 +325,8 @@ TEST_F(ModuleScriptLoaderTest, FetchInvalidURL) {
TEST_F(ModuleScriptLoaderTest, FetchInvalidURL_OnWorklet) {
InitializeForWorklet();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchInvalidURL(ModuleScriptCustomFetchType::kWorkletAddModule, client);
EXPECT_FALSE(client->WasNotifyFinished())
@@ -345,19 +343,18 @@ void ModuleScriptLoaderTest::TestFetchURL(
KURL url("https://example.test/module.js");
url_test_helpers::RegisterMockedURLLoad(
url, test::CoreTestDataPath("module.js"), "text/javascript");
- auto* fetch_client_settings_object =
- GetDocument().CreateFetchClientSettingsObjectSnapshot();
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
- ModuleScriptLoader::Fetch(
- ModuleScriptFetchRequest::CreateForTest(url),
- fetch_client_settings_object, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry, client);
+ ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
+ GetModulator(), custom_fetch_type, registry,
+ client);
}
TEST_F(ModuleScriptLoaderTest, FetchURL) {
InitializeForDocument();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchURL(ModuleScriptCustomFetchType::kNone, client);
EXPECT_FALSE(client->WasNotifyFinished())
@@ -373,7 +370,8 @@ TEST_F(ModuleScriptLoaderTest, FetchURL) {
TEST_F(ModuleScriptLoaderTest, FetchURL_OnWorklet) {
InitializeForWorklet();
- TestModuleScriptLoaderClient* client = new TestModuleScriptLoaderClient;
+ TestModuleScriptLoaderClient* client =
+ MakeGarbageCollected<TestModuleScriptLoaderClient>();
TestFetchURL(ModuleScriptCustomFetchType::kWorkletAddModule, client);
EXPECT_FALSE(client->WasNotifyFinished())
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
index 088b7b3b27d..8c91918a854 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/script/layered_api.h"
#include "third_party/blink/renderer/core/script/module_script.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -20,7 +21,7 @@ namespace blink {
void ModuleTreeLinker::Fetch(
const KURL& url,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
const ScriptFetchOptions& options,
Modulator* modulator,
@@ -28,8 +29,8 @@ void ModuleTreeLinker::Fetch(
ModuleTreeLinkerRegistry* registry,
ModuleTreeClient* client) {
ModuleTreeLinker* fetcher = MakeGarbageCollected<ModuleTreeLinker>(
- fetch_client_settings_object, destination, modulator, custom_fetch_type,
- registry, client);
+ fetch_client_settings_object_fetcher, destination, modulator,
+ custom_fetch_type, registry, client);
registry->AddFetcher(fetcher);
fetcher->FetchRoot(url, options);
DCHECK(fetcher->IsFetching());
@@ -37,7 +38,7 @@ void ModuleTreeLinker::Fetch(
void ModuleTreeLinker::FetchDescendantsForInlineScript(
ModuleScript* module_script,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
Modulator* modulator,
ModuleScriptCustomFetchType custom_fetch_type,
@@ -45,21 +46,22 @@ void ModuleTreeLinker::FetchDescendantsForInlineScript(
ModuleTreeClient* client) {
DCHECK(module_script);
ModuleTreeLinker* fetcher = MakeGarbageCollected<ModuleTreeLinker>(
- fetch_client_settings_object, destination, modulator, custom_fetch_type,
- registry, client);
+ fetch_client_settings_object_fetcher, destination, modulator,
+ custom_fetch_type, registry, client);
registry->AddFetcher(fetcher);
fetcher->FetchRootInline(module_script);
DCHECK(fetcher->IsFetching());
}
ModuleTreeLinker::ModuleTreeLinker(
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
Modulator* modulator,
ModuleScriptCustomFetchType custom_fetch_type,
ModuleTreeLinkerRegistry* registry,
ModuleTreeClient* client)
- : fetch_client_settings_object_(fetch_client_settings_object),
+ : fetch_client_settings_object_fetcher_(
+ fetch_client_settings_object_fetcher),
destination_(destination),
modulator_(modulator),
custom_fetch_type_(custom_fetch_type),
@@ -71,7 +73,7 @@ ModuleTreeLinker::ModuleTreeLinker(
}
void ModuleTreeLinker::Trace(blink::Visitor* visitor) {
- visitor->Trace(fetch_client_settings_object_);
+ visitor->Trace(fetch_client_settings_object_fetcher_);
visitor->Trace(modulator_);
visitor->Trace(registry_);
visitor->Trace(client_);
@@ -228,8 +230,8 @@ void ModuleTreeLinker::InitiateInternalModuleScriptGraphFetching(
++num_incomplete_fetches_;
// [IMSGF] Step 2. Fetch a single module script given ...
- modulator_->FetchSingle(request, fetch_client_settings_object_.Get(), level,
- custom_fetch_type_, this);
+ modulator_->FetchSingle(request, fetch_client_settings_object_fetcher_.Get(),
+ level, custom_fetch_type_, this);
// [IMSGF] Step 3-- are executed when NotifyModuleLoadFinished() is called.
}
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
index b4ed117ef38..b7da4df0d0a 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
@@ -25,6 +25,10 @@ class ModuleTreeLinkerRegistry;
// a top-level [FDaI] "fetch the descendants of and instantiate", and all the
// invocations of [IMSGF] and [FD] "fetch the descendants" under that.
//
+// Modulator represents "a module map settings object" and
+// ResourceFetcher represents "a fetch client settings object"
+// by its |Context()->GetFetchClientSettingsObject()|.
+//
// Spec links:
// [IMSGF]
// https://html.spec.whatwg.org/#internal-module-script-graph-fetching-procedure
@@ -37,33 +41,31 @@ class ModuleTreeLinkerRegistry;
class CORE_EXPORT ModuleTreeLinker final : public SingleModuleClient {
public:
// https://html.spec.whatwg.org/#fetch-a-module-script-tree
- static void Fetch(
- const KURL&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType destination,
- const ScriptFetchOptions&,
- Modulator*,
- ModuleScriptCustomFetchType,
- ModuleTreeLinkerRegistry*,
- ModuleTreeClient*);
+ static void Fetch(const KURL&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ mojom::RequestContextType destination,
+ const ScriptFetchOptions&,
+ Modulator*,
+ ModuleScriptCustomFetchType,
+ ModuleTreeLinkerRegistry*,
+ ModuleTreeClient*);
// [FDaI] for an inline script.
static void FetchDescendantsForInlineScript(
ModuleScript*,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
Modulator*,
ModuleScriptCustomFetchType,
ModuleTreeLinkerRegistry*,
ModuleTreeClient*);
- ModuleTreeLinker(
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType destination,
- Modulator*,
- ModuleScriptCustomFetchType,
- ModuleTreeLinkerRegistry*,
- ModuleTreeClient*);
+ ModuleTreeLinker(ResourceFetcher* fetch_client_settings_object_fetcher,
+ mojom::RequestContextType destination,
+ Modulator*,
+ ModuleScriptCustomFetchType,
+ ModuleTreeLinkerRegistry*,
+ ModuleTreeClient*);
~ModuleTreeLinker() override = default;
void Trace(blink::Visitor*) override;
@@ -111,7 +113,8 @@ class CORE_EXPORT ModuleTreeLinker final : public SingleModuleClient {
ScriptValue FindFirstParseError(ModuleScript*,
HeapHashSet<Member<ModuleScript>>*) const;
- const Member<FetchClientSettingsObjectSnapshot> fetch_client_settings_object_;
+ const Member<ResourceFetcher> fetch_client_settings_object_fetcher_;
+
const mojom::RequestContextType destination_;
const Member<Modulator> modulator_;
const ModuleScriptCustomFetchType custom_fetch_type_;
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
index 36a57045c58..290e219a8ab 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
@@ -129,12 +129,11 @@ class ModuleTreeLinkerTestModulator final : public DummyModulator {
return KURL(base_url, module_request);
}
- void FetchSingle(
- const ModuleScriptFetchRequest& request,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- ModuleGraphLevel,
- ModuleScriptCustomFetchType,
- SingleModuleClient* client) override {
+ void FetchSingle(const ModuleScriptFetchRequest& request,
+ ResourceFetcher*,
+ ModuleGraphLevel,
+ ModuleScriptCustomFetchType,
+ SingleModuleClient* client) override {
EXPECT_FALSE(pending_clients_.Contains(request.Url()));
pending_clients_.Set(request.Url(), client);
}
@@ -209,11 +208,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeNoDeps) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -231,11 +230,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeInstantiationFailure) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -257,11 +256,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWithSingleDependency) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -284,11 +283,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -324,11 +323,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps1Fail) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -383,11 +382,11 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyTree) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/depth1.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -409,11 +408,11 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyOfCyclicGraph) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/a.js");
- TestModuleTreeClient* client = new TestModuleTreeClient;
- ModuleTreeLinker::Fetch(
- url, GetDocument().CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, ScriptFetchOptions(), GetModulator(),
- ModuleScriptCustomFetchType::kNone, registry, client);
+ TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
+ ModuleTreeLinker::Fetch(url, GetDocument().Fetcher(),
+ mojom::RequestContextType::SCRIPT,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
index 3e702d88131..c0596eaea99 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
@@ -18,9 +18,11 @@ WorkerModuleScriptFetcher::WorkerModuleScriptFetcher(
: global_scope_(global_scope) {}
// https://html.spec.whatwg.org/multipage/workers.html#worker-processing-model
-void WorkerModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
- ModuleGraphLevel level,
- ModuleScriptFetcher::Client* client) {
+void WorkerModuleScriptFetcher::Fetch(
+ FetchParameters& fetch_params,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ ModuleGraphLevel level,
+ ModuleScriptFetcher::Client* client) {
DCHECK(global_scope_->IsContextThread());
client_ = client;
level_ = level;
@@ -33,8 +35,8 @@ void WorkerModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
// Step 13.2. "Fetch request, and asynchronously wait to run the remaining
// steps as part of fetch's process response for the response response." [spec
// text]
- ScriptResource::Fetch(fetch_params, global_scope_->EnsureFetcher(), this,
- ScriptResource::kNoStreaming);
+ ScriptResource::Fetch(fetch_params, fetch_client_settings_object_fetcher,
+ this, ScriptResource::kNoStreaming);
}
void WorkerModuleScriptFetcher::Trace(blink::Visitor* visitor) {
@@ -65,7 +67,7 @@ void WorkerModuleScriptFetcher::NotifyFinished(Resource* resource) {
// Ensure redirects don't affect SecurityOrigin.
const KURL request_url = resource->Url();
- const KURL response_url = resource->GetResponse().Url();
+ const KURL response_url = resource->GetResponse().CurrentRequestUrl();
if (request_url != response_url &&
!global_scope_->GetSecurityOrigin()->IsSameSchemeHostPort(
SecurityOrigin::Create(response_url).get())) {
@@ -99,7 +101,8 @@ void WorkerModuleScriptFetcher::NotifyFinished(Resource* resource) {
}
ModuleScriptCreationParams params(
- script_resource->GetResponse().Url(), script_resource->SourceText(),
+ script_resource->GetResponse().CurrentRequestUrl(),
+ script_resource->SourceText(),
script_resource->GetResourceRequest().GetFetchCredentialsMode());
// Step 13.7. "Asynchronously complete the perform the fetch steps with
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
index f2fde549724..7819106617b 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
@@ -26,6 +26,7 @@ class CORE_EXPORT WorkerModuleScriptFetcher final
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client*) override;
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
index 74b7850b18d..51d9da86e64 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
@@ -9,21 +9,17 @@
namespace blink {
WorkletModuleScriptFetcher::WorkletModuleScriptFetcher(
- ResourceFetcher* fetcher,
WorkletModuleResponsesMap* module_responses_map)
- : fetcher_(fetcher), module_responses_map_(module_responses_map) {}
+ : module_responses_map_(module_responses_map) {}
-void WorkletModuleScriptFetcher::Trace(blink::Visitor* visitor) {
- ModuleScriptFetcher::Trace(visitor);
- visitor->Trace(fetcher_);
-}
-
-void WorkletModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
- ModuleGraphLevel level,
- ModuleScriptFetcher::Client* client) {
+void WorkletModuleScriptFetcher::Fetch(
+ FetchParameters& fetch_params,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ ModuleGraphLevel level,
+ ModuleScriptFetcher::Client* client) {
if (module_responses_map_->GetEntry(
fetch_params.Url(), client,
- fetcher_->Context().GetLoadingTaskRunner())) {
+ fetch_client_settings_object_fetcher->GetTaskRunner())) {
return;
}
@@ -38,8 +34,8 @@ void WorkletModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
// need to handle that case, maybe by having a way to restart fetches in a
// different global scope?
url_ = fetch_params.Url();
- ScriptResource::Fetch(fetch_params, fetcher_.Get(), this,
- ScriptResource::kNoStreaming);
+ ScriptResource::Fetch(fetch_params, fetch_client_settings_object_fetcher,
+ this, ScriptResource::kNoStreaming);
}
void WorkletModuleScriptFetcher::NotifyFinished(Resource* resource) {
@@ -50,7 +46,8 @@ void WorkletModuleScriptFetcher::NotifyFinished(Resource* resource) {
HeapVector<Member<ConsoleMessage>> error_messages;
if (WasModuleLoadSuccessful(script_resource, &error_messages)) {
params.emplace(
- script_resource->GetResponse().Url(), script_resource->SourceText(),
+ script_resource->GetResponse().CurrentRequestUrl(),
+ script_resource->SourceText(),
script_resource->GetResourceRequest().GetFetchCredentialsMode());
}
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h
index aa8f57baa2e..44c080ad0af 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h
@@ -28,22 +28,19 @@ class CORE_EXPORT WorkletModuleScriptFetcher final
USING_GARBAGE_COLLECTED_MIXIN(WorkletModuleScriptFetcher);
public:
- WorkletModuleScriptFetcher(ResourceFetcher*, WorkletModuleResponsesMap*);
+ explicit WorkletModuleScriptFetcher(WorkletModuleResponsesMap*);
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client*) override;
- void Trace(blink::Visitor*) override;
-
private:
// Implements ResourceClient
void NotifyFinished(Resource*) override;
String DebugName() const override { return "WorkletModuleScriptFetcher"; }
- const Member<ResourceFetcher> fetcher_;
-
// TODO(nhiroki): In general, CrossThreadPersistent is heavy and should not be
// owned by objects that can frequently be created like this class. Instead of
// retaining a reference to WorkletModuleResponsesMap, this class should
diff --git a/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.cc b/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.cc
index 2f9ed7136aa..d3c6f60f822 100644
--- a/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.cc
+++ b/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.cc
@@ -34,7 +34,7 @@
#include <memory>
#include "third_party/blink/public/common/blob/blob_utils.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
@@ -66,7 +66,7 @@ unsigned NavigationDisablerForBeforeUnload::navigation_disable_count_ = 0;
class ScheduledURLNavigation : public ScheduledNavigation {
protected:
- ScheduledURLNavigation(Reason reason,
+ ScheduledURLNavigation(ClientNavigationReason reason,
double delay,
Document* origin_document,
const KURL& url,
@@ -173,17 +173,18 @@ class ScheduledRedirect final : public ScheduledURLNavigation {
}
private:
- static Reason ToReason(Document::HttpRefreshType http_refresh_type) {
+ static ClientNavigationReason ToReason(
+ Document::HttpRefreshType http_refresh_type) {
switch (http_refresh_type) {
case Document::HttpRefreshType::kHttpRefreshFromHeader:
- return Reason::kHttpHeaderRefresh;
+ return ClientNavigationReason::kHttpHeaderRefresh;
case Document::HttpRefreshType::kHttpRefreshFromMetaTag:
- return Reason::kMetaTagRefresh;
+ return ClientNavigationReason::kMetaTagRefresh;
default:
break;
}
NOTREACHED();
- return Reason::kMetaTagRefresh;
+ return ClientNavigationReason::kMetaTagRefresh;
}
};
@@ -201,7 +202,7 @@ class ScheduledFrameNavigation final : public ScheduledURLNavigation {
const KURL& url,
WebFrameLoadType frame_load_type,
base::TimeTicks input_timestamp)
- : ScheduledURLNavigation(Reason::kFrameNavigation,
+ : ScheduledURLNavigation(ClientNavigationReason::kFrameNavigation,
0.0,
origin_document,
url,
@@ -210,47 +211,6 @@ class ScheduledFrameNavigation final : public ScheduledURLNavigation {
input_timestamp) {}
};
-class ScheduledReload final : public ScheduledNavigation {
- public:
- static ScheduledReload* Create(LocalFrame* frame,
- base::TimeTicks input_timestamp) {
- return MakeGarbageCollected<ScheduledReload>(frame, input_timestamp);
- }
-
- explicit ScheduledReload(LocalFrame* frame, base::TimeTicks input_timestamp)
- : ScheduledNavigation(Reason::kReload,
- 0.0,
- nullptr /*origin_document */,
- true,
- input_timestamp),
- frame_(frame) {
- DCHECK(frame->GetDocument());
- }
-
- void Fire(LocalFrame* frame) override {
- std::unique_ptr<UserGestureIndicator> gesture_indicator =
- CreateUserGestureIndicator();
- ResourceRequest resource_request = frame->Loader().ResourceRequestForReload(
- WebFrameLoadType::kReload, ClientRedirectPolicy::kClientRedirect);
- if (resource_request.IsNull())
- return;
- FrameLoadRequest request = FrameLoadRequest(nullptr, resource_request);
- request.SetClientRedirect(ClientRedirectPolicy::kClientRedirect);
- request.SetInputStartTime(InputTimestamp());
- frame->Loader().StartNavigation(request, WebFrameLoadType::kReload);
- }
-
- KURL Url() const override { return frame_->GetDocument()->Url(); }
-
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(frame_);
- ScheduledNavigation::Trace(visitor);
- }
-
- private:
- Member<LocalFrame> frame_;
-};
-
class ScheduledPageBlock final : public ScheduledNavigation {
public:
static ScheduledPageBlock* Create(Document* origin_document, int reason) {
@@ -258,7 +218,7 @@ class ScheduledPageBlock final : public ScheduledNavigation {
}
ScheduledPageBlock(Document* origin_document, int reason)
- : ScheduledNavigation(Reason::kPageBlock,
+ : ScheduledNavigation(ClientNavigationReason::kPageBlock,
0.0,
origin_document,
true,
@@ -290,8 +250,8 @@ class ScheduledFormSubmission final : public ScheduledNavigation {
WebFrameLoadType frame_load_type,
base::TimeTicks input_timestamp)
: ScheduledNavigation(submission->Method() == FormSubmission::kGetMethod
- ? Reason::kFormSubmissionGet
- : Reason::kFormSubmissionPost,
+ ? ClientNavigationReason::kFormSubmissionGet
+ : ClientNavigationReason::kFormSubmissionPost,
0,
document,
true,
@@ -337,29 +297,6 @@ bool NavigationScheduler::IsNavigationScheduledWithin(double interval) const {
return redirect_ && redirect_->Delay() <= interval;
}
-// TODO(dcheng): There are really two different load blocking concepts at work
-// here and they have been incorrectly tangled together.
-//
-// 1. NavigationDisablerForBeforeUnload is for blocking navigation scheduling
-// during a beforeunload events. Scheduled navigations during beforeunload
-// would make it possible to get trapped in an endless loop of beforeunload
-// dialogs.
-//
-// Checking Frame::isNavigationAllowed() doesn't make sense in this context:
-// NavigationScheduler is always cleared when a new load commits, so it's
-// impossible for a scheduled navigation to clobber a navigation that just
-// committed.
-//
-// 2. FrameNavigationDisabler / LocalFrame::isNavigationAllowed() are intended
-// to prevent Documents from being reattached during destruction, since it
-// can cause bugs with security origin confusion. This is primarily intended
-// to block /synchronous/ navigations during things lke
-// Document::detachLayoutTree().
-inline bool NavigationScheduler::ShouldScheduleReload() const {
- return frame_->GetPage() && frame_->IsNavigationAllowed() &&
- NavigationDisablerForBeforeUnload::IsNavigationAllowed();
-}
-
inline bool NavigationScheduler::ShouldScheduleNavigation(
const KURL& url) const {
return frame_->GetPage() && frame_->IsNavigationAllowed() &&
@@ -462,14 +399,6 @@ void NavigationScheduler::ScheduleFormSubmission(Document* document,
frame_load_type, InputTimestamp()));
}
-void NavigationScheduler::ScheduleReload() {
- if (!ShouldScheduleReload())
- return;
- if (frame_->GetDocument()->Url().IsEmpty())
- return;
- Schedule(ScheduledReload::Create(frame_, InputTimestamp()));
-}
-
void NavigationScheduler::NavigateTask() {
if (!frame_->GetPage())
return;
@@ -525,13 +454,16 @@ void NavigationScheduler::StartTimer() {
WTF::Bind(&NavigationScheduler::NavigateTask, WrapWeakPersistent(this)),
TimeDelta::FromSecondsD(redirect_->Delay()));
- probe::frameScheduledNavigation(frame_, redirect_.Get());
+ probe::frameScheduledNavigation(frame_, redirect_->Url(), redirect_->Delay(),
+ redirect_->GetReason());
}
void NavigationScheduler::Cancel() {
if (navigate_task_handle_.IsActive()) {
probe::frameClearedScheduledNavigation(frame_);
}
+ if (frame_->GetDocument())
+ frame_->GetDocument()->CancelPendingJavaScriptUrl();
navigate_task_handle_.Cancel();
redirect_.Clear();
}
diff --git a/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.h b/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.h
index 00acdcb7bb9..d9769b2bc47 100644
--- a/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.h
+++ b/chromium/third_party/blink/renderer/core/loader/navigation_scheduler.h
@@ -70,7 +70,6 @@ class CORE_EXPORT NavigationScheduler final
void ScheduleFrameNavigation(Document*, const KURL&, WebFrameLoadType);
void SchedulePageBlock(Document*, int reason);
void ScheduleFormSubmission(Document*, FormSubmission*);
- void ScheduleReload();
void StartTimer();
void Cancel();
@@ -78,7 +77,6 @@ class CORE_EXPORT NavigationScheduler final
void Trace(blink::Visitor*);
private:
- bool ShouldScheduleReload() const;
bool ShouldScheduleNavigation(const KURL&) const;
void NavigateTask();
diff --git a/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc
index d1528a9941b..5ff8a3d217e 100644
--- a/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc
@@ -11,7 +11,6 @@
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/loader/fetch/substitute_data.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -23,6 +22,10 @@ namespace {
class PingLocalFrameClient : public EmptyLocalFrameClient {
public:
+ std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override {
+ return Platform::Current()->CreateDefaultURLLoaderFactory();
+ }
+
void DispatchWillSendRequest(ResourceRequest& request) override {
if (request.GetKeepalive())
ping_request_ = request;
@@ -37,7 +40,7 @@ class PingLocalFrameClient : public EmptyLocalFrameClient {
class PingLoaderTest : public PageTestBase {
public:
void SetUp() override {
- client_ = new PingLocalFrameClient;
+ client_ = MakeGarbageCollected<PingLocalFrameClient>();
PageTestBase::SetupPageWithClients(nullptr, client_);
}
@@ -49,9 +52,8 @@ class PingLoaderTest : public PageTestBase {
void SetDocumentURL(const KURL& url) {
GetFrame().Loader().CommitNavigation(
- ResourceRequest(url), SubstituteData(SharedBuffer::Create()),
- ClientRedirectPolicy::kNotClientRedirect,
- base::UnguessableToken::Create());
+ WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ nullptr /* extra_data */);
blink::test::RunPendingTasks();
ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
}
diff --git a/chromium/third_party/blink/renderer/core/loader/preload_helper.cc b/chromium/third_party/blink/renderer/core/loader/preload_helper.cc
new file mode 100644
index 00000000000..89dbdcdd9cf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -0,0 +1,531 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/css/media_list.h"
+#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
+#include "third_party/blink/renderer/core/css/parser/sizes_attribute_parser.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/frame_console.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/frame/viewport_data.h"
+#include "third_party/blink/renderer/core/html/parser/html_preload_scanner.h"
+#include "third_party/blink/renderer/core/html/parser/html_srcset_parser.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/importance_attribute.h"
+#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
+#include "third_party/blink/renderer/core/loader/network_hints_interface.h"
+#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/image_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/link_fetch_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
+#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
+#include "third_party/blink/renderer/core/script/modulator.h"
+#include "third_party/blink/renderer/core/script/script_loader.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
+#include "third_party/blink/renderer/platform/loader/link_header.h"
+#include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
+#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
+
+namespace blink {
+
+namespace {
+
+void SendMessageToConsoleForPossiblyNullDocument(
+ ConsoleMessage* console_message,
+ Document* document,
+ LocalFrame* frame) {
+ DCHECK(document || frame);
+ DCHECK(!document || document->GetFrame() == frame);
+ // Route the console message through Document if possible, so that script line
+ // numbers can be included. Otherwise, route directly to the FrameConsole, to
+ // ensure we never drop a message.
+ if (document)
+ document->AddConsoleMessage(console_message);
+ else
+ frame->Console().AddMessage(console_message);
+}
+
+bool IsSupportedType(ResourceType resource_type, const String& mime_type) {
+ if (mime_type.IsEmpty())
+ return true;
+ switch (resource_type) {
+ case ResourceType::kImage:
+ return MIMETypeRegistry::IsSupportedImagePrefixedMIMEType(mime_type);
+ case ResourceType::kScript:
+ return MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type);
+ case ResourceType::kCSSStyleSheet:
+ return MIMETypeRegistry::IsSupportedStyleSheetMIMEType(mime_type);
+ case ResourceType::kFont:
+ return MIMETypeRegistry::IsSupportedFontMIMEType(mime_type);
+ case ResourceType::kAudio:
+ case ResourceType::kVideo:
+ return MIMETypeRegistry::IsSupportedMediaMIMEType(mime_type, String());
+ case ResourceType::kTextTrack:
+ return MIMETypeRegistry::IsSupportedTextTrackMIMEType(mime_type);
+ case ResourceType::kRaw:
+ return true;
+ default:
+ NOTREACHED();
+ }
+ return false;
+}
+
+MediaValues* CreateMediaValues(Document& document,
+ ViewportDescription* viewport_description) {
+ MediaValues* media_values =
+ MediaValues::CreateDynamicIfFrameExists(document.GetFrame());
+ if (viewport_description) {
+ FloatSize initial_viewport(media_values->DeviceWidth(),
+ media_values->DeviceHeight());
+ PageScaleConstraints constraints = viewport_description->Resolve(
+ initial_viewport, document.GetViewportData().ViewportDefaultMinWidth());
+ media_values->OverrideViewportDimensions(constraints.layout_size.Width(),
+ constraints.layout_size.Height());
+ }
+ return media_values;
+}
+
+} // namespace
+
+void PreloadHelper::DnsPrefetchIfNeeded(
+ const LinkLoadParameters& params,
+ Document* document,
+ LocalFrame* frame,
+ const NetworkHintsInterface& network_hints_interface,
+ LinkCaller caller) {
+ if (params.rel.IsDNSPrefetch()) {
+ UseCounter::Count(frame, WebFeature::kLinkRelDnsPrefetch);
+ if (caller == kLinkCalledFromHeader)
+ UseCounter::Count(frame, WebFeature::kLinkHeaderDnsPrefetch);
+ Settings* settings = frame ? frame->GetSettings() : nullptr;
+ // FIXME: The href attribute of the link element can be in "//hostname"
+ // form, and we shouldn't attempt to complete that as URL
+ // <https://bugs.webkit.org/show_bug.cgi?id=48857>.
+ if (settings && settings->GetDNSPrefetchingEnabled() &&
+ params.href.IsValid() && !params.href.IsEmpty()) {
+ if (settings->GetLogDnsPrefetchAndPreconnect()) {
+ SendMessageToConsoleForPossiblyNullDocument(
+ ConsoleMessage::Create(
+ kOtherMessageSource, kVerboseMessageLevel,
+ String("DNS prefetch triggered for " + params.href.Host())),
+ document, frame);
+ }
+ network_hints_interface.DnsPrefetchHost(params.href.Host());
+ }
+ }
+}
+
+void PreloadHelper::PreconnectIfNeeded(
+ const LinkLoadParameters& params,
+ Document* document,
+ LocalFrame* frame,
+ const NetworkHintsInterface& network_hints_interface,
+ LinkCaller caller) {
+ if (params.rel.IsPreconnect() && params.href.IsValid() &&
+ params.href.ProtocolIsInHTTPFamily()) {
+ UseCounter::Count(frame, WebFeature::kLinkRelPreconnect);
+ if (caller == kLinkCalledFromHeader)
+ UseCounter::Count(frame, WebFeature::kLinkHeaderPreconnect);
+ Settings* settings = frame ? frame->GetSettings() : nullptr;
+ if (settings && settings->GetLogDnsPrefetchAndPreconnect()) {
+ SendMessageToConsoleForPossiblyNullDocument(
+ ConsoleMessage::Create(
+ kOtherMessageSource, kVerboseMessageLevel,
+ String("Preconnect triggered for ") + params.href.GetString()),
+ document, frame);
+ if (params.cross_origin != kCrossOriginAttributeNotSet) {
+ SendMessageToConsoleForPossiblyNullDocument(
+ ConsoleMessage::Create(kOtherMessageSource, kVerboseMessageLevel,
+ String("Preconnect CORS setting is ") +
+ String((params.cross_origin ==
+ kCrossOriginAttributeAnonymous)
+ ? "anonymous"
+ : "use-credentials")),
+ document, frame);
+ }
+ }
+ network_hints_interface.PreconnectHost(params.href, params.cross_origin);
+ }
+}
+
+base::Optional<ResourceType> PreloadHelper::GetResourceTypeFromAsAttribute(
+ const String& as) {
+ DCHECK_EQ(as.DeprecatedLower(), as);
+ if (as == "image")
+ return ResourceType::kImage;
+ if (as == "script")
+ return ResourceType::kScript;
+ if (as == "style")
+ return ResourceType::kCSSStyleSheet;
+ if (as == "video")
+ return ResourceType::kVideo;
+ if (as == "audio")
+ return ResourceType::kAudio;
+ if (as == "track")
+ return ResourceType::kTextTrack;
+ if (as == "font")
+ return ResourceType::kFont;
+ if (as == "fetch")
+ return ResourceType::kRaw;
+ return base::nullopt;
+}
+
+static bool MediaMatches(const String& media, MediaValues* media_values) {
+ scoped_refptr<MediaQuerySet> media_queries = MediaQuerySet::Create(media);
+ MediaQueryEvaluator evaluator(*media_values);
+ return evaluator.Eval(*media_queries);
+}
+
+// |base_url| is used in Link HTTP Header based preloads to resolve relative
+// URLs in srcset, which should be based on the resource's URL, not the
+// document's base URL. If |base_url| is a null URL, relative URLs are resolved
+// using |document.CompleteURL()|.
+Resource* PreloadHelper::PreloadIfNeeded(
+ const LinkLoadParameters& params,
+ Document& document,
+ const KURL& base_url,
+ LinkCaller caller,
+ ViewportDescription* viewport_description,
+ ParserDisposition parser_disposition) {
+ if (!document.Loader() || !params.rel.IsLinkPreload())
+ return nullptr;
+
+ base::Optional<ResourceType> resource_type =
+ PreloadHelper::GetResourceTypeFromAsAttribute(params.as);
+
+ MediaValues* media_values = nullptr;
+ KURL url;
+ if (resource_type == ResourceType::kImage && !params.image_srcset.IsEmpty() &&
+ RuntimeEnabledFeatures::PreloadImageSrcSetEnabled()) {
+ media_values = CreateMediaValues(document, viewport_description);
+ float source_size =
+ SizesAttributeParser(media_values, params.image_sizes).length();
+ ImageCandidate candidate = BestFitSourceForImageAttributes(
+ media_values->DevicePixelRatio(), source_size, params.href,
+ params.image_srcset);
+ url = base_url.IsNull() ? document.CompleteURL(candidate.ToString())
+ : KURL(base_url, candidate.ToString());
+ } else {
+ url = params.href;
+ }
+
+ UseCounter::Count(document, WebFeature::kLinkRelPreload);
+ if (!url.IsValid() || url.IsEmpty()) {
+ document.AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kWarningMessageLevel,
+ String("<link rel=preload> has an invalid `href` value")));
+ return nullptr;
+ }
+
+ // Preload only if media matches
+ if (!params.media.IsEmpty()) {
+ if (!media_values)
+ media_values = CreateMediaValues(document, viewport_description);
+ if (!MediaMatches(params.media, media_values))
+ return nullptr;
+ }
+
+ if (caller == kLinkCalledFromHeader)
+ UseCounter::Count(document, WebFeature::kLinkHeaderPreload);
+ if (resource_type == base::nullopt) {
+ document.AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kWarningMessageLevel,
+ String("<link rel=preload> must have a valid `as` value")));
+ return nullptr;
+ }
+
+ if (!IsSupportedType(resource_type.value(), params.type)) {
+ document.AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kWarningMessageLevel,
+ String("<link rel=preload> has an unsupported `type` value")));
+ return nullptr;
+ }
+ ResourceRequest resource_request(url);
+ resource_request.SetRequestContext(ResourceFetcher::DetermineRequestContext(
+ resource_type.value(), ResourceFetcher::kImageNotImageSet, false));
+
+ resource_request.SetReferrerPolicy(params.referrer_policy);
+
+ resource_request.SetFetchImportanceMode(
+ GetFetchImportanceAttributeValue(params.importance));
+
+ ResourceLoaderOptions options;
+ options.initiator_info.name = fetch_initiator_type_names::kLink;
+ options.parser_disposition = parser_disposition;
+ FetchParameters link_fetch_params(resource_request, options);
+ link_fetch_params.SetCharset(document.Encoding());
+
+ if (params.cross_origin != kCrossOriginAttributeNotSet) {
+ link_fetch_params.SetCrossOriginAccessControl(document.GetSecurityOrigin(),
+ params.cross_origin);
+ }
+ link_fetch_params.SetContentSecurityPolicyNonce(params.nonce);
+ Settings* settings = document.GetSettings();
+ if (settings && settings->GetLogPreload()) {
+ document.AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kVerboseMessageLevel,
+ String("Preload triggered for " + url.Host() + url.GetPath())));
+ }
+ link_fetch_params.SetLinkPreload(true);
+ return PreloadHelper::StartPreload(resource_type.value(), link_fetch_params,
+ document.Fetcher());
+}
+
+// https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload
+void PreloadHelper::ModulePreloadIfNeeded(
+ const LinkLoadParameters& params,
+ Document& document,
+ ViewportDescription* viewport_description,
+ SingleModuleClient* client) {
+ if (!document.Loader() || !params.rel.IsModulePreload())
+ return;
+
+ UseCounter::Count(document, WebFeature::kLinkRelModulePreload);
+
+ // Step 1. "If the href attribute's value is the empty string, then return."
+ // [spec text]
+ if (params.href.IsEmpty()) {
+ document.AddConsoleMessage(
+ ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel,
+ "<link rel=modulepreload> has no `href` value"));
+ return;
+ }
+
+ // Step 5. "Let settings object be the link element's node document's relevant
+ // settings object." [spec text]
+ // |document| is the node document here, and its context document is the
+ // relevant settings object.
+ Document* context_document = document.ContextDocument();
+ Modulator* modulator =
+ Modulator::From(ToScriptStateForMainWorld(context_document->GetFrame()));
+ DCHECK(modulator);
+ if (!modulator)
+ return;
+
+ // Step 2. "Let destination be the current state of the as attribute (a
+ // destination), or "script" if it is in no state." [spec text]
+ // Step 3. "If destination is not script-like, then queue a task on the
+ // networking task source to fire an event named error at the link element,
+ // and return." [spec text]
+ // Currently we only support as="script".
+ if (!params.as.IsEmpty() && params.as != "script") {
+ document.AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kWarningMessageLevel,
+ String("<link rel=modulepreload> has an invalid `as` value " +
+ params.as)));
+ // This triggers the same logic as Step 11 asynchronously, which will fire
+ // the error event.
+ if (client) {
+ modulator->TaskRunner()->PostTask(
+ FROM_HERE, WTF::Bind(&SingleModuleClient::NotifyModuleLoadFinished,
+ WrapPersistent(client), nullptr));
+ }
+ return;
+ }
+ mojom::RequestContextType destination = mojom::RequestContextType::SCRIPT;
+
+ // Step 4. "Parse the URL given by the href attribute, relative to the
+ // element's node document. If that fails, then return. Otherwise, let url be
+ // the resulting URL record." [spec text]
+ // |href| is already resolved in caller side.
+ if (!params.href.IsValid()) {
+ document.AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kWarningMessageLevel,
+ "<link rel=modulepreload> has an invalid `href` value " +
+ params.href.GetString()));
+ return;
+ }
+
+ // Preload only if media matches.
+ // https://html.spec.whatwg.org/#processing-the-media-attribute
+ if (!params.media.IsEmpty()) {
+ MediaValues* media_values =
+ CreateMediaValues(document, viewport_description);
+ if (!MediaMatches(params.media, media_values))
+ return;
+ }
+
+ // Step 6. "Let credentials mode be the module script credentials mode for the
+ // crossorigin attribute." [spec text]
+ network::mojom::FetchCredentialsMode credentials_mode =
+ ScriptLoader::ModuleScriptCredentialsMode(params.cross_origin);
+
+ // Step 7. "Let cryptographic nonce be the value of the nonce attribute, if it
+ // is specified, or the empty string otherwise." [spec text]
+ // |nonce| parameter is the value of the nonce attribute.
+
+ // Step 8. "Let integrity metadata be the value of the integrity attribute, if
+ // it is specified, or the empty string otherwise." [spec text]
+ IntegrityMetadataSet integrity_metadata;
+ if (!params.integrity.IsEmpty()) {
+ SubresourceIntegrity::IntegrityFeatures integrity_features =
+ SubresourceIntegrityHelper::GetFeatures(&document);
+ SubresourceIntegrity::ReportInfo report_info;
+ SubresourceIntegrity::ParseIntegrityAttribute(
+ params.integrity, integrity_features, integrity_metadata, &report_info);
+ SubresourceIntegrityHelper::DoReport(document, report_info);
+ }
+
+ // Step 9. "Let referrer policy be the current state of the element's
+ // referrerpolicy attribute." [spec text]
+ // |referrer_policy| parameter is the value of the referrerpolicy attribute.
+
+ // Step 10. "Let options be a script fetch options whose cryptographic nonce
+ // is cryptographic nonce, integrity metadata is integrity metadata, parser
+ // metadata is "not-parser-inserted", credentials mode is credentials mode,
+ // and referrer policy is referrer policy." [spec text]
+ ModuleScriptFetchRequest request(
+ params.href, destination,
+ ScriptFetchOptions(params.nonce, integrity_metadata, params.integrity,
+ kNotParserInserted, credentials_mode,
+ params.referrer_policy),
+ Referrer::NoReferrer(), TextPosition::MinimumPosition());
+
+ // Step 11. "Fetch a single module script given url, settings object,
+ // destination, options, settings object, "client", and with the top-level
+ // module fetch flag set. Wait until algorithm asynchronously completes with
+ // result." [spec text]
+ modulator->FetchSingle(request, context_document->Fetcher(),
+ ModuleGraphLevel::kDependentModuleFetch,
+ ModuleScriptCustomFetchType::kNone, client);
+
+ Settings* settings = document.GetSettings();
+ if (settings && settings->GetLogPreload()) {
+ document.AddConsoleMessage(
+ ConsoleMessage::Create(kOtherMessageSource, kVerboseMessageLevel,
+ "Module preload triggered for " +
+ params.href.Host() + params.href.GetPath()));
+ }
+
+ // Asynchronously continue processing after
+ // client->NotifyModuleLoadFinished() is called.
+}
+
+Resource* PreloadHelper::PrefetchIfNeeded(const LinkLoadParameters& params,
+ Document& document) {
+ if (params.rel.IsLinkPrefetch() && params.href.IsValid() &&
+ document.GetFrame()) {
+ UseCounter::Count(document, WebFeature::kLinkRelPrefetch);
+
+ ResourceRequest resource_request(params.href);
+ resource_request.SetReferrerPolicy(params.referrer_policy);
+ resource_request.SetFetchImportanceMode(
+ GetFetchImportanceAttributeValue(params.importance));
+
+ ResourceLoaderOptions options;
+ options.initiator_info.name = fetch_initiator_type_names::kLink;
+
+ FetchParameters link_fetch_params(resource_request, options);
+ if (params.cross_origin != kCrossOriginAttributeNotSet) {
+ link_fetch_params.SetCrossOriginAccessControl(
+ document.GetSecurityOrigin(), params.cross_origin);
+ }
+ return LinkFetchResource::Fetch(ResourceType::kLinkPrefetch,
+ link_fetch_params, document.Fetcher());
+ }
+ return nullptr;
+}
+
+void PreloadHelper::LoadLinksFromHeader(
+ const String& header_value,
+ const KURL& base_url,
+ LocalFrame& frame,
+ Document* document,
+ const NetworkHintsInterface& network_hints_interface,
+ CanLoadResources can_load_resources,
+ MediaPreloadPolicy media_policy,
+ ViewportDescriptionWrapper* viewport_description_wrapper) {
+ if (header_value.IsEmpty())
+ return;
+ LinkHeaderSet header_set(header_value);
+ for (auto& header : header_set) {
+ if (!header.Valid() || header.Url().IsEmpty() || header.Rel().IsEmpty())
+ continue;
+
+ if (media_policy == kOnlyLoadMedia && !header.IsViewportDependent())
+ continue;
+ if (media_policy == kOnlyLoadNonMedia && header.IsViewportDependent())
+ continue;
+
+ const LinkLoadParameters params(header, base_url);
+ // Sanity check to avoid re-entrancy here.
+ if (params.href == base_url)
+ continue;
+ if (can_load_resources != kOnlyLoadResources) {
+ DnsPrefetchIfNeeded(params, document, &frame, network_hints_interface,
+ kLinkCalledFromHeader);
+
+ PreconnectIfNeeded(params, document, &frame, network_hints_interface,
+ kLinkCalledFromHeader);
+ }
+ if (can_load_resources != kDoNotLoadResources) {
+ DCHECK(document);
+ ViewportDescription* viewport_description =
+ (viewport_description_wrapper && viewport_description_wrapper->set)
+ ? &(viewport_description_wrapper->description)
+ : nullptr;
+
+ PreloadIfNeeded(params, *document, base_url, kLinkCalledFromHeader,
+ viewport_description, kNotParserInserted);
+ PrefetchIfNeeded(params, *document);
+ ModulePreloadIfNeeded(params, *document, viewport_description, nullptr);
+ }
+ if (params.rel.IsServiceWorker()) {
+ UseCounter::Count(&frame, WebFeature::kLinkHeaderServiceWorker);
+ }
+ // TODO(yoav): Add more supported headers as needed.
+ }
+}
+
+Resource* PreloadHelper::StartPreload(ResourceType type,
+ FetchParameters& params,
+ ResourceFetcher* resource_fetcher) {
+ Resource* resource = nullptr;
+ switch (type) {
+ case ResourceType::kImage:
+ resource = ImageResource::Fetch(params, resource_fetcher);
+ break;
+ case ResourceType::kScript:
+ params.SetRequestContext(mojom::RequestContextType::SCRIPT);
+ resource = ScriptResource::Fetch(params, resource_fetcher, nullptr,
+ ScriptResource::kAllowStreaming);
+ break;
+ case ResourceType::kCSSStyleSheet:
+ resource =
+ CSSStyleSheetResource::Fetch(params, resource_fetcher, nullptr);
+ break;
+ case ResourceType::kFont:
+ resource = FontResource::Fetch(params, resource_fetcher, nullptr);
+ break;
+ case ResourceType::kAudio:
+ case ResourceType::kVideo:
+ resource = RawResource::FetchMedia(params, resource_fetcher, nullptr);
+ break;
+ case ResourceType::kTextTrack:
+ resource = RawResource::FetchTextTrack(params, resource_fetcher, nullptr);
+ break;
+ case ResourceType::kImportResource:
+ resource = RawResource::FetchImport(params, resource_fetcher, nullptr);
+ break;
+ case ResourceType::kRaw:
+ resource = RawResource::Fetch(params, resource_fetcher, nullptr);
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ return resource;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/preload_helper.h b/chromium/third_party/blink/renderer/core/loader/preload_helper.h
new file mode 100644
index 00000000000..d4a63ebb78f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/preload_helper.h
@@ -0,0 +1,84 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRELOAD_HELPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRELOAD_HELPER_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
+
+namespace blink {
+
+class Document;
+class LocalFrame;
+class NetworkHintsInterface;
+class SingleModuleClient;
+struct LinkLoadParameters;
+struct ViewportDescription;
+struct ViewportDescriptionWrapper;
+
+// PreloadHelper is a helper class for preload, module preload, prefetch,
+// DNS prefetch, and preconnect triggered by <link> elements and "Link" HTTP
+// response headers.
+class PreloadHelper final {
+ STATIC_ONLY(PreloadHelper);
+
+ public:
+ enum CanLoadResources {
+ kOnlyLoadResources,
+ kDoNotLoadResources,
+ kLoadResourcesAndPreconnect
+ };
+
+ // Media links cannot be preloaded until the first chunk is parsed. The rest
+ // can be preloaded at commit time.
+ enum MediaPreloadPolicy { kLoadAll, kOnlyLoadNonMedia, kOnlyLoadMedia };
+
+ static void LoadLinksFromHeader(const String& header_value,
+ const KURL& base_url,
+ LocalFrame&,
+ Document*, // can be nullptr
+ const NetworkHintsInterface&,
+ CanLoadResources,
+ MediaPreloadPolicy,
+ ViewportDescriptionWrapper*);
+ static Resource* StartPreload(ResourceType,
+ FetchParameters&,
+ ResourceFetcher*);
+
+ // Currently only used for UseCounter.
+ enum LinkCaller {
+ kLinkCalledFromHeader,
+ kLinkCalledFromMarkup,
+ };
+
+ static void DnsPrefetchIfNeeded(const LinkLoadParameters&,
+ Document*,
+ LocalFrame*,
+ const NetworkHintsInterface&,
+ LinkCaller);
+ static void PreconnectIfNeeded(const LinkLoadParameters&,
+ Document*,
+ LocalFrame*,
+ const NetworkHintsInterface&,
+ LinkCaller);
+ static Resource* PrefetchIfNeeded(const LinkLoadParameters&, Document&);
+ static Resource* PreloadIfNeeded(const LinkLoadParameters&,
+ Document&,
+ const KURL& base_url,
+ LinkCaller,
+ ViewportDescription*,
+ ParserDisposition);
+ static void ModulePreloadIfNeeded(const LinkLoadParameters&,
+ Document&,
+ ViewportDescription*,
+ SingleModuleClient*);
+
+ static base::Optional<ResourceType> GetResourceTypeFromAsAttribute(
+ const String& as);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRELOAD_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc b/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
index 8d5b072defe..aa29d3bab19 100644
--- a/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
namespace blink {
@@ -23,7 +24,7 @@ static constexpr WebFeature kWebFeatureMapping[] = {
};
static_assert(static_cast<int>(mojom::WebClientHintsType::kMaxValue) + 1 ==
- arraysize(kWebFeatureMapping),
+ base::size(kWebFeatureMapping),
"unhandled client hint type");
} // namespace
diff --git a/chromium/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc b/chromium/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc
index be0ecb6b10d..9ec575f0e16 100644
--- a/chromium/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc
@@ -52,7 +52,7 @@ TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithScale) {
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view =
web_view_helper.InitializeAndLoad(base_url_ + "long_scroll.html");
- web_view->Resize(WebSize(1000, 1000));
+ web_view->MainFrameWidget()->Resize(WebSize(1000, 1000));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -85,7 +85,7 @@ TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithoutScale) {
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view =
web_view_helper.InitializeAndLoad(base_url_ + "long_scroll.html");
- web_view->Resize(WebSize(1000, 1000));
+ web_view->MainFrameWidget()->Resize(WebSize(1000, 1000));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -115,7 +115,7 @@ TEST_F(ProgrammaticScrollTest, SaveScrollStateClearsAnchor) {
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view =
web_view_helper.InitializeAndLoad(base_url_ + "long_scroll.html");
- web_view->Resize(WebSize(1000, 1000));
+ web_view->MainFrameWidget()->Resize(WebSize(1000, 1000));
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
@@ -141,16 +141,16 @@ TEST_F(ProgrammaticScrollTest, SaveScrollStateClearsAnchor) {
class ProgrammaticScrollSimTest : public SimTest {};
TEST_F(ProgrammaticScrollSimTest, NavigateToHash) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html#target", "text/html");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
LoadURL("https://example.com/test.html#target");
// Finish loading the main document before the stylesheet is loaded so that
// rendering is blocked when parsing finishes. This will delay closing the
// document until the load event.
- main_resource.Start();
main_resource.Write(
"<!DOCTYPE html><link id=link rel=stylesheet href=test.css>");
css_resource.Start();
diff --git a/chromium/third_party/blink/renderer/core/loader/progress_tracker.cc b/chromium/third_party/blink/renderer/core/loader/progress_tracker.cc
index 1e0088c45e1..245a64bd82d 100644
--- a/chromium/third_party/blink/renderer/core/loader/progress_tracker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/progress_tracker.cc
@@ -166,7 +166,7 @@ void ProgressTracker::IncrementProgress(unsigned long identifier,
}
void ProgressTracker::IncrementProgress(unsigned long identifier,
- size_t length) {
+ uint64_t length) {
ProgressItem* item = progress_items_.at(identifier);
if (!item)
return;
diff --git a/chromium/third_party/blink/renderer/core/loader/progress_tracker.h b/chromium/third_party/blink/renderer/core/loader/progress_tracker.h
index 4ff4e18d6d4..55a339c30a7 100644
--- a/chromium/third_party/blink/renderer/core/loader/progress_tracker.h
+++ b/chromium/third_party/blink/renderer/core/loader/progress_tracker.h
@@ -67,7 +67,7 @@ class CORE_EXPORT ProgressTracker final
void WillStartLoading(unsigned long identifier, ResourceLoadPriority);
void IncrementProgress(unsigned long identifier, const ResourceResponse&);
- void IncrementProgress(unsigned long identifier, size_t);
+ void IncrementProgress(unsigned long identifier, uint64_t);
void CompleteProgress(unsigned long identifier);
private:
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc
index 95ce0384ada..07963eb9f72 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc
@@ -93,6 +93,17 @@ void CSSStyleSheetResource::Trace(blink::Visitor* visitor) {
TextResource::Trace(visitor);
}
+void CSSStyleSheetResource::OnMemoryDump(
+ WebMemoryDumpLevelOfDetail level_of_detail,
+ WebProcessMemoryDump* memory_dump) const {
+ Resource::OnMemoryDump(level_of_detail, memory_dump);
+ const String name = GetMemoryDumpName() + "/style_sheets";
+ auto* dump = memory_dump->CreateMemoryAllocatorDump(name);
+ dump->AddScalar("size", "bytes", decoded_sheet_text_.CharactersSizeInBytes());
+ memory_dump->AddSuballocation(
+ dump->Guid(), String(WTF::Partitions::kAllocatedObjectPoolName));
+}
+
network::mojom::ReferrerPolicy CSSStyleSheetResource::GetReferrerPolicy()
const {
network::mojom::ReferrerPolicy referrer_policy =
@@ -164,7 +175,7 @@ bool CSSStyleSheetResource::CanUseSheet(const CSSParserContext* parser_context,
// Though we'll likely change this in the future, for the moment we're going
// to enforce a file-extension requirement on stylesheets loaded from `file:`
// URLs and see how far it gets us.
- KURL sheet_url = GetResponse().Url();
+ KURL sheet_url = GetResponse().CurrentRequestUrl();
if (sheet_url.IsLocalFile()) {
if (parser_context) {
parser_context->Count(WebFeature::kLocalCSSFile);
@@ -222,10 +233,8 @@ StyleSheetContents* CSSStyleSheetResource::CreateParsedStyleSheetFromCache(
// If the stylesheet has a media query, we need to clone the cached sheet
// due to potential differences in the rule set.
- if (RuntimeEnabledFeatures::CacheStyleSheetWithMediaQueriesEnabled() &&
- parsed_style_sheet_cache_->HasMediaQueries()) {
+ if (parsed_style_sheet_cache_->HasMediaQueries())
return parsed_style_sheet_cache_->Copy();
- }
return parsed_style_sheet_cache_;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h
index c149586609f..0253711b206 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h
@@ -53,8 +53,11 @@ class CORE_EXPORT CSSStyleSheetResource final : public TextResource {
CSSStyleSheetResource(const ResourceRequest&,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&);
+
~CSSStyleSheetResource() override;
void Trace(blink::Visitor*) override;
+ void OnMemoryDump(WebMemoryDumpLevelOfDetail,
+ WebProcessMemoryDump*) const override;
const String SheetText(const CSSParserContext*,
MIMETypeCheck = MIMETypeCheck::kStrict) const;
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/document_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/document_resource.cc
index 3434782b942..446eaacd5f3 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/document_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/document_resource.cc
@@ -66,7 +66,7 @@ void DocumentResource::NotifyFinished() {
if (Data() && MimeTypeAllowed()) {
// We don't need to create a new frame because the new document belongs to
// the parent UseElement.
- document_ = CreateDocument(GetResponse().Url());
+ document_ = CreateDocument(GetResponse().CurrentRequestUrl());
document_->SetContent(DecodedText());
}
Resource::NotifyFinished();
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h
index d5f2b7cc6f7..d07e8567953 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h
@@ -106,7 +106,7 @@ class CORE_EXPORT FontResource final : public Resource {
TaskHandle font_load_long_limit_;
friend class MemoryCache;
- FRIEND_TEST_ALL_PREFIXES(FontResourceTest, CacheAwareFontLoading);
+ FRIEND_TEST_ALL_PREFIXES(CacheAwareFontResourceTest, CacheAwareFontLoading);
};
DEFINE_RESOURCE_TYPE_CASTS(Font);
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc b/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
index 89c8c163982..82a304b9d34 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
@@ -4,8 +4,10 @@
#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
+#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/core/css/css_font_face_src_value.h"
@@ -21,12 +23,14 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
class FontResourceTest : public testing::Test {
+ public:
void TearDown() override {
Platform::Current()
->GetURLLoaderMockFactory()
@@ -34,6 +38,18 @@ class FontResourceTest : public testing::Test {
}
};
+class CacheAwareFontResourceTest : public FontResourceTest {
+ public:
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kWebFontsCacheAwareTimeoutAdaption);
+ FontResourceTest::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
// Tests if ResourceFetcher works fine with FontResource that requires defered
// loading supports.
TEST_F(FontResourceTest,
@@ -45,9 +61,10 @@ TEST_F(FontResourceTest,
Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(
url, WrappedResourceResponse(response), "");
- MockFetchContext* context =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- ResourceFetcher* fetcher = ResourceFetcher::Create(context);
+ MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, context, base::MakeRefCounted<scheduler::FakeTaskRunner>()));
// Fetch to cache a resource.
ResourceRequest request1(url);
@@ -60,7 +77,7 @@ TEST_F(FontResourceTest,
EXPECT_FALSE(resource1->ErrorOccurred());
// Set the context as it is on reloads.
- context->SetLoadComplete(true);
+ properties->SetIsLoadComplete(true);
// Revalidate the resource.
ResourceRequest request2(url);
@@ -95,16 +112,13 @@ TEST_F(FontResourceTest,
}
// Tests if cache-aware font loading works correctly.
-TEST_F(FontResourceTest, CacheAwareFontLoading) {
+TEST_F(CacheAwareFontResourceTest, CacheAwareFontLoading) {
KURL url("http://127.0.0.1:8000/font.woff");
ResourceResponse response(url);
response.SetHTTPStatusCode(200);
Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(
url, WrappedResourceResponse(response), "");
- RuntimeEnabledFeatures::Backup features_backup;
- RuntimeEnabledFeatures::SetWebFontsCacheAwareTimeoutAdaptationEnabled(true);
-
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
@@ -163,8 +177,6 @@ TEST_F(FontResourceTest, CacheAwareFontLoading) {
Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
GetMemoryCache()->Remove(&resource);
-
- features_backup.Restore();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc
index 913d8327b1d..889d2d65936 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc
@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
+#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -108,11 +109,10 @@ class ImageResource::ImageResourceInfoImpl final
resource_->ShouldReloadBrokenPlaceholder();
}
bool IsAccessAllowed(
- const SecurityOrigin* security_origin,
DoesCurrentFrameHaveSingleSecurityOrigin
does_current_frame_has_single_security_origin) const override {
return resource_->IsAccessAllowed(
- security_origin, does_current_frame_has_single_security_origin);
+ does_current_frame_has_single_security_origin);
}
bool HasCacheControlNoStoreHeader() const override {
return resource_->HasCacheControlNoStoreHeader();
@@ -313,16 +313,7 @@ void ImageResource::AllClientsAndObserversRemoved() {
// TODO(hiroshige): Make the CHECK condition cleaner.
CHECK(is_during_finish_as_error_ || !GetContent()->HasImage() ||
!ErrorOccurred());
- // If possible, delay the resetting until back at the event loop. Doing so
- // after a conservative GC prevents resetAnimation() from upsetting ongoing
- // animation updates (crbug.com/613709)
- if (!ThreadHeap::WillObjectBeLazilySwept(this)) {
- Thread::Current()->GetTaskRunner()->PostTask(
- FROM_HERE, WTF::Bind(&ImageResourceContent::DoResetAnimation,
- WrapWeakPersistent(GetContent())));
- } else {
- GetContent()->DoResetAnimation();
- }
+ GetContent()->DoResetAnimation();
if (multipart_parser_)
multipart_parser_->Cancel();
Resource::AllClientsAndObserversRemoved();
@@ -483,10 +474,14 @@ void ImageResource::ResponseReceived(
std::unique_ptr<WebDataConsumerHandle> handle) {
DCHECK(!handle);
DCHECK(!multipart_parser_);
- // If there's no boundary, just handle the request normally.
- if (response.IsMultipart() && !response.MultipartBoundary().IsEmpty()) {
- multipart_parser_ = MakeGarbageCollected<MultipartImageResourceParser>(
- response, response.MultipartBoundary(), this);
+ if (response.MimeType() == "multipart/x-mixed-replace") {
+ Vector<char> boundary = network_utils::ParseMultipartBoundary(
+ response.HttpHeaderField(http_names::kContentType));
+ // If there's no boundary, just handle the request normally.
+ if (!boundary.IsEmpty()) {
+ multipart_parser_ = MakeGarbageCollected<MultipartImageResourceParser>(
+ response, boundary, this);
+ }
}
// Notify the base class that a response has been received. Note that after
@@ -704,20 +699,13 @@ void ImageResource::MultipartDataReceived(const char* bytes, size_t size) {
}
bool ImageResource::IsAccessAllowed(
- const SecurityOrigin* security_origin,
ImageResourceInfo::DoesCurrentFrameHaveSingleSecurityOrigin
does_current_frame_has_single_security_origin) const {
- if (GetResponse().WasFetchedViaServiceWorker())
- return GetResponse().IsCorsSameOrigin();
-
if (does_current_frame_has_single_security_origin !=
ImageResourceInfo::kHasSingleSecurityOrigin)
return false;
- if (GetResponse().IsCorsSameOrigin())
- return true;
-
- return security_origin->CanReadContent(GetResponse().Url());
+ return GetResponse().IsCorsSameOrigin();
}
ImageResourceContent* ImageResource::GetContent() {
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h
index f24eef1f2f0..a20b5525718 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h
@@ -39,7 +39,6 @@ class FetchParameters;
class ImageResourceContent;
class ResourceClient;
class ResourceFetcher;
-class SecurityOrigin;
// ImageResource implements blink::Resource interface and image-specific logic
// for loading images.
@@ -127,7 +126,6 @@ class CORE_EXPORT ImageResource final
// Only for ImageResourceInfoImpl.
void DecodeError(bool all_data_received);
bool IsAccessAllowed(
- const SecurityOrigin*,
ImageResourceInfo::DoesCurrentFrameHaveSingleSecurityOrigin) const;
bool HasClientsOrObservers() const override;
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
index 54714676cde..05d7b576689 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -49,7 +49,6 @@ class NullImageResourceInfo final
return false;
}
bool IsAccessAllowed(
- const SecurityOrigin*,
DoesCurrentFrameHaveSingleSecurityOrigin) const override {
return true;
}
@@ -105,7 +104,7 @@ ImageResourceContent::ImageResourceContent(scoped_refptr<blink::Image> image)
has_device_pixel_ratio_header_value_(false),
image_(std::move(image)) {
DEFINE_STATIC_LOCAL(Persistent<NullImageResourceInfo>, null_info,
- (new NullImageResourceInfo()));
+ (MakeGarbageCollected<NullImageResourceInfo>()));
info_ = null_info;
}
@@ -511,7 +510,12 @@ bool ImageResourceContent::IsAcceptableCompressionRatio() {
if (!pixels)
return true;
DCHECK(image_);
- double resource_length = GetResponse().ExpectedContentLength();
+ double resource_length =
+ static_cast<double>(GetResponse().ExpectedContentLength());
+ if (resource_length <= 0 && GetImage() && GetImage()->Data()) {
+ // WPT and LayoutTests server returns -1 or 0 for the content length.
+ resource_length = static_cast<double>(GetImage()->Data()->size());
+ }
// Allow no more than 10 bits per compressed pixel
return (resource_length - 1024) / pixels <= 0.5;
}
@@ -570,12 +574,11 @@ void ImageResourceContent::Changed(const blink::Image* image) {
NotifyObservers(kDoNotNotifyFinish, CanDeferInvalidation::kYes);
}
-bool ImageResourceContent::IsAccessAllowed(
- const SecurityOrigin* security_origin) {
+bool ImageResourceContent::IsAccessAllowed() {
return info_->IsAccessAllowed(
- security_origin, GetImage()->CurrentFrameHasSingleSecurityOrigin()
- ? ImageResourceInfo::kHasSingleSecurityOrigin
- : ImageResourceInfo::kHasMultipleSecurityOrigin);
+ GetImage()->CurrentFrameHasSingleSecurityOrigin()
+ ? ImageResourceInfo::kHasSingleSecurityOrigin
+ : ImageResourceInfo::kHasMultipleSecurityOrigin);
}
void ImageResourceContent::EmulateLoadStartedForInspector(
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h
index a94b30ac7d6..e975f4e12d4 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h
@@ -28,7 +28,6 @@ class ImageResourceObserver;
class ResourceError;
class ResourceFetcher;
class ResourceResponse;
-class SecurityOrigin;
// ImageResourceContent is a container that holds fetch result of
// an ImageResource in a decoded form.
@@ -108,7 +107,7 @@ class CORE_EXPORT ImageResourceContent final
// Redirecting methods to Resource.
const KURL& Url() const;
- bool IsAccessAllowed(const SecurityOrigin*);
+ bool IsAccessAllowed();
const ResourceResponse& GetResponse() const;
base::Optional<ResourceError> GetResourceError() const;
// DEPRECATED: ImageResourceContents consumers shouldn't need to worry about
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_info.h b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_info.h
index c26177bc310..1e8c7d58df9 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_info.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_info.h
@@ -19,7 +19,6 @@ namespace blink {
class ResourceError;
class ResourceFetcher;
class ResourceResponse;
-class SecurityOrigin;
// Delegate class of ImageResource that encapsulates the interface and data
// visible to ImageResourceContent.
@@ -41,7 +40,6 @@ class CORE_EXPORT ImageResourceInfo : public GarbageCollectedMixin {
kHasSingleSecurityOrigin
};
virtual bool IsAccessAllowed(
- const SecurityOrigin*,
DoesCurrentFrameHaveSingleSecurityOrigin) const = 0;
virtual bool HasCacheControlNoStoreHeader() const = 0;
virtual base::Optional<ResourceError> GetResourceError() const = 0;
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
index ca251dbde27..ec34e518f7d 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
@@ -33,7 +33,7 @@
#include <memory>
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
@@ -55,6 +55,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
@@ -352,8 +353,10 @@ void TestThatIsNotPlaceholderRequestAndServeResponse(
}
ResourceFetcher* CreateFetcher() {
- return ResourceFetcher::Create(
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource));
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ return MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, MakeGarbageCollected<MockFetchContext>(),
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
}
TEST(ImageResourceTest, MultipartImage) {
@@ -376,7 +379,8 @@ TEST(ImageResourceTest, MultipartImage) {
// flagged as multipart.
ResourceResponse multipart_response(NullURL());
multipart_response.SetMimeType("multipart/x-mixed-replace");
- multipart_response.SetMultipartBoundary("boundary", strlen("boundary"));
+ multipart_response.SetHTTPHeaderField(
+ http_names::kContentType, "multipart/x-mixed-replace; boundary=boundary");
image_resource->Loader()->DidReceiveResponse(
WrappedResourceResponse(multipart_response), nullptr);
EXPECT_FALSE(image_resource->ResourceBuffer());
@@ -456,7 +460,8 @@ TEST(ImageResourceTest, BitmapMultipartImage) {
ResourceResponse multipart_response(NullURL());
multipart_response.SetMimeType("multipart/x-mixed-replace");
- multipart_response.SetMultipartBoundary("boundary", strlen("boundary"));
+ multipart_response.SetHTTPHeaderField(
+ http_names::kContentType, "multipart/x-mixed-replace; boundary=boundary");
image_resource->Loader()->DidReceiveResponse(
WrappedResourceResponse(multipart_response), nullptr);
EXPECT_FALSE(image_resource->GetContent()->HasImage());
@@ -485,8 +490,7 @@ TEST(ImageResourceTest, CancelOnRemoveObserver) {
ResourceFetcher* fetcher = CreateFetcher();
scheduler::FakeTaskRunner* task_runner =
- static_cast<scheduler::FakeTaskRunner*>(
- fetcher->Context().GetLoadingTaskRunner().get());
+ static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get());
task_runner->SetTime(1);
// Emulate starting a real load.
@@ -521,7 +525,7 @@ class MockFinishObserver : public GarbageCollectedFinalized<MockFinishObserver>,
static MockFinishObserver* Create() {
return
- new testing::StrictMock<MockFinishObserver>;
+ MakeGarbageCollected<testing::StrictMock<MockFinishObserver>>();
}
MOCK_METHOD0(NotifyFinished, void());
String DebugName() const override { return "MockFinishObserver"; }
@@ -548,8 +552,8 @@ TEST(ImageResourceTest, CancelWithImageAndFinishObserver) {
GetMemoryCache()->Add(image_resource);
Persistent<MockFinishObserver> finish_observer = MockFinishObserver::Create();
- image_resource->AddFinishObserver(
- finish_observer, fetcher->Context().GetLoadingTaskRunner().get());
+ image_resource->AddFinishObserver(finish_observer,
+ fetcher->GetTaskRunner().get());
// Send the image response.
ResourceResponse resource_response(NullURL());
@@ -1861,11 +1865,15 @@ TEST(ImageResourceTest, PeriodicFlushTest) {
KURL test_url(kTestURL);
ScopedMockedURLLoad scoped_mocked_url_load(test_url, GetTestFilePath());
- MockFetchContext* context = MockFetchContext::Create(
- MockFetchContext::LoadPolicy::kShouldLoadNewResource,
- page_holder->GetFrame().GetTaskRunner(TaskType::kInternalTest));
- ResourceFetcher* fetcher = ResourceFetcher::Create(context);
- ResourceLoadScheduler* scheduler = ResourceLoadScheduler::Create();
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ page_holder->GetFrame().GetTaskRunner(TaskType::kInternalTest);
+ MockFetchContext* context =
+ MakeGarbageCollected<MockFetchContext>(task_runner);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, task_runner));
+ auto* scheduler = MakeGarbageCollected<ResourceLoadScheduler>(
+ ResourceLoadScheduler::ThrottlingPolicy::kNormal, context);
ImageResource* image_resource = ImageResource::CreateForTest(test_url);
// Ensure that |image_resource| has a loader.
@@ -1986,8 +1994,7 @@ class ImageResourceCounterTest : public testing::Test {
ResourceRequest request = ResourceRequest(test_url);
FetchParameters fetch_params(request);
scheduler::FakeTaskRunner* task_runner =
- static_cast<scheduler::FakeTaskRunner*>(
- fetcher->Context().GetLoadingTaskRunner().get());
+ static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get());
task_runner->SetTime(1);
// Mark it as coming from a UA stylesheet (if needed).
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser.cc b/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser.cc
index 0b032bc99b3..e21397f8c30 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser.cc
@@ -142,7 +142,7 @@ bool MultipartImageResourceParser::ParseHeaders() {
// Create a ResourceResponse based on the original set of headers + the
// replacement headers. We only replace the same few headers that gecko does.
// See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
- ResourceResponse response(original_response_.Url());
+ ResourceResponse response(original_response_.CurrentRequestUrl());
response.SetWasFetchedViaServiceWorker(
original_response_.WasFetchedViaServiceWorker());
response.SetType(original_response_.GetType());
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser_test.cc b/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser_test.cc
index 599e76ae864..2a6b3e22de8 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/multipart_image_resource_parser_test.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <string.h>
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -49,7 +50,7 @@ TEST(MultipartResponseTest, SkippableLength) {
{"\rLine", 0, 0}, {"Line\r\nLine", 4, 2}, {"Line\nLine", 4, 1},
{"Line\n\nLine", 4, 1}, {"Line\rLine", 4, 0}, {"Line\r\rLine", 4, 0},
};
- for (size_t i = 0; i < arraysize(line_tests); ++i) {
+ for (size_t i = 0; i < base::size(line_tests); ++i) {
Vector<char> input;
input.Append(line_tests[i].input,
static_cast<wtf_size_t>(strlen(line_tests[i].input)));
@@ -70,7 +71,7 @@ TEST(MultipartResponseTest, FindBoundary) {
{"foo", "bound", kNotFound}, {"bound", "--boundbound", 0},
};
- for (size_t i = 0; i < arraysize(boundary_tests); ++i) {
+ for (size_t i = 0; i < base::size(boundary_tests); ++i) {
Vector<char> boundary, data;
boundary.Append(boundary_tests[i].boundary,
static_cast<uint32_t>(strlen(boundary_tests[i].boundary)));
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc
index c9b8aa9ad69..84f5e8e3dbd 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc
@@ -29,6 +29,7 @@
#include <utility>
#include "services/network/public/mojom/request_context_frame_type.mojom-blink.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h"
@@ -84,7 +85,7 @@ ScriptResource* ScriptResource::Fetch(FetchParameters& params,
if (streaming_allowed == kAllowStreaming) {
// Start streaming the script as soon as we get it.
if (RuntimeEnabledFeatures::ScriptStreamingOnPreloadEnabled()) {
- resource->StartStreaming(fetcher->Context().GetLoadingTaskRunner());
+ resource->StartStreaming(fetcher->GetTaskRunner());
}
} else {
// Advance the |streaming_state_| to kStreamingNotAllowed by calling
@@ -98,7 +99,7 @@ ScriptResource* ScriptResource::Fetch(FetchParameters& params,
// clients were already finished. If this behaviour becomes necessary, we
// would have to either check that streaming wasn't started (if that would
// be a logic error), or cancel any existing streaming.
- fetcher->Context().GetLoadingTaskRunner()->PostTask(
+ fetcher->GetTaskRunner()->PostTask(
FROM_HERE, WTF::Bind(&ScriptResource::SetClientIsWaitingForFinished,
WrapWeakPersistent(resource)));
}
@@ -126,10 +127,7 @@ void ScriptResource::OnMemoryDump(WebMemoryDumpLevelOfDetail level_of_detail,
WebProcessMemoryDump* memory_dump) const {
Resource::OnMemoryDump(level_of_detail, memory_dump);
const String name = GetMemoryDumpName() + "/decoded_script";
- auto* dump = memory_dump->CreateMemoryAllocatorDump(name);
- dump->AddScalar("size", "bytes", source_text_.CharactersSizeInBytes());
- memory_dump->AddSuballocation(
- dump->Guid(), String(WTF::Partitions::kAllocatedObjectPoolName));
+ source_text_.OnMemoryDump(memory_dump, name);
}
const ParkableString& ScriptResource::SourceText() {
@@ -193,7 +191,7 @@ CachedMetadataHandler* ScriptResource::CreateCachedMetadataHandler(
Encoding(), std::move(send_callback));
}
-void ScriptResource::SetSerializedCachedMetadata(const char* data,
+void ScriptResource::SetSerializedCachedMetadata(const uint8_t* data,
size_t size) {
Resource::SetSerializedCachedMetadata(data, size);
ScriptCachedMetadataHandler* cache_handler =
@@ -290,21 +288,27 @@ void ScriptResource::StreamingFinished() {
TextResource::NotifyFinished();
}
-bool ScriptResource::StartStreaming(
+void ScriptResource::StartStreaming(
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
CheckStreamingState();
if (streamer_) {
- return !streamer_->IsStreamingFinished();
+ return;
}
if (streaming_state_ != StreamingState::kCanStartStreaming) {
- return false;
+ return;
}
// Don't bother streaming if there was an error, it won't work anyway.
if (ErrorOccurred()) {
- return false;
+ return;
+ }
+
+ static bool script_streaming_enabled =
+ base::FeatureList::IsEnabled(features::kScriptStreaming);
+ if (!script_streaming_enabled) {
+ return;
}
CHECK(!IsCacheValidator());
@@ -337,7 +341,7 @@ bool ScriptResource::StartStreaming(
}
CheckStreamingState();
- return streamer_ && !streamer_->IsStreamingFinished();
+ return;
}
void ScriptResource::SetClientIsWaitingForFinished() {
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h
index 6c4759b0aa4..75d10285ae4 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h
@@ -95,14 +95,9 @@ class CORE_EXPORT ScriptResource final : public TextResource {
void OnMemoryDump(WebMemoryDumpLevelOfDetail,
WebProcessMemoryDump*) const override;
- void SetSerializedCachedMetadata(const char*, size_t) override;
+ void SetSerializedCachedMetadata(const uint8_t*, size_t) override;
- // Returns true if streaming was successfully started (or if an active
- // streamer is already running)
- //
- // TODO(leszeks): This value is only used for work stealing, so make this
- // function return void if work stealing is removed.
- bool StartStreaming(
+ void StartStreaming(
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner);
// State that a client of the script resource will no longer try to start
@@ -148,6 +143,7 @@ class CORE_EXPORT ScriptResource final : public TextResource {
// Used in DCHECKs
bool HasStreamer() { return !!streamer_; }
+ bool HasRunningStreamer() { return streamer_ && !streamer_->IsFinished(); }
bool HasFinishedStreamer() { return streamer_ && streamer_->IsFinished(); }
// Visible for tests.
diff --git a/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.cc b/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.cc
index 6b67a44e7a2..fd5037f6604 100644
--- a/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.cc
+++ b/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.cc
@@ -12,7 +12,7 @@
namespace blink {
-ScheduledNavigation::ScheduledNavigation(Reason reason,
+ScheduledNavigation::ScheduledNavigation(ClientNavigationReason reason,
double delay,
Document* origin_document,
bool is_location_change,
diff --git a/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.h b/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.h
index 62f8fdb42c2..2eb0969284e 100644
--- a/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.h
+++ b/chromium/third_party/blink/renderer/core/loader/scheduled_navigation.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
namespace blink {
@@ -18,17 +19,7 @@ class UserGestureToken;
class ScheduledNavigation
: public GarbageCollectedFinalized<ScheduledNavigation> {
public:
- enum class Reason {
- kFormSubmissionGet,
- kFormSubmissionPost,
- kHttpHeaderRefresh,
- kFrameNavigation,
- kMetaTagRefresh,
- kPageBlock,
- kReload,
- };
-
- ScheduledNavigation(Reason,
+ ScheduledNavigation(ClientNavigationReason,
double delay,
Document* origin_document,
bool is_location_change,
@@ -41,7 +32,7 @@ class ScheduledNavigation
virtual bool ShouldStartTimer(LocalFrame*) { return true; }
- Reason GetReason() const { return reason_; }
+ ClientNavigationReason GetReason() const { return reason_; }
double Delay() const { return delay_; }
Document* OriginDocument() const { return origin_document_.Get(); }
bool IsLocationChange() const { return is_location_change_; }
@@ -56,7 +47,7 @@ class ScheduledNavigation
void ClearUserGesture() { user_gesture_token_ = nullptr; }
private:
- Reason reason_;
+ ClientNavigationReason reason_;
double delay_;
Member<Document> origin_document_;
bool is_location_change_;
diff --git a/chromium/third_party/blink/renderer/core/loader/text_resource_decoder_builder.cc b/chromium/third_party/blink/renderer/core/loader/text_resource_decoder_builder.cc
index ecd371321a1..121dc037fbd 100644
--- a/chromium/third_party/blink/renderer/core/loader/text_resource_decoder_builder.cc
+++ b/chromium/third_party/blink/renderer/core/loader/text_resource_decoder_builder.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/core/loader/text_resource_decoder_builder.h"
#include <memory>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_implementation.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -78,7 +80,7 @@ static const WTF::TextEncoding GetEncodingFromDomain(const KURL& url) {
url.Host().Split(".", tokens);
if (!tokens.IsEmpty()) {
auto tld = tokens.back();
- for (size_t i = 0; i < arraysize(kEncodings); i++) {
+ for (size_t i = 0; i < base::size(kEncodings); i++) {
if (tld == kEncodings[i].domain)
return WTF::TextEncoding(kEncodings[i].encoding);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc b/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc
index 3da0485319b..0f683ac68be 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -59,9 +59,11 @@
#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
@@ -199,9 +201,11 @@ ThreadableLoader::CreateAccessControlPreflightRequestForTesting(
ThreadableLoader::ThreadableLoader(
ExecutionContext& execution_context,
ThreadableLoaderClient* client,
- const ResourceLoaderOptions& resource_loader_options)
+ const ResourceLoaderOptions& resource_loader_options,
+ ResourceFetcher* resource_fetcher)
: client_(client),
execution_context_(execution_context),
+ resource_fetcher_(resource_fetcher),
resource_loader_options_(resource_loader_options),
out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCorsEnabled()),
is_using_data_consumer_handle_(false),
@@ -217,8 +221,11 @@ ThreadableLoader::ThreadableLoader(
redirect_mode_(network::mojom::FetchRedirectMode::kFollow),
override_referrer_(false) {
DCHECK(client);
- if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_))
- scope->EnsureFetcher();
+ if (!resource_fetcher_) {
+ if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_))
+ scope->EnsureFetcher();
+ resource_fetcher_ = execution_context_->Fetcher();
+ }
}
void ThreadableLoader::Start(const ResourceRequest& request) {
@@ -289,7 +296,7 @@ void ThreadableLoader::Start(const ResourceRequest& request) {
// is_controlled_by_service_worker is the same as
// ControllerServiceWorkerMode::kControlled, so this code can be simplified.
bool is_controlled_by_service_worker = false;
- switch (execution_context_->Fetcher()->IsControlledByServiceWorker()) {
+ switch (resource_fetcher_->IsControlledByServiceWorker()) {
case blink::mojom::ControllerServiceWorkerMode::kControlled:
is_controlled_by_service_worker = true;
break;
@@ -569,7 +576,7 @@ bool ThreadableLoader::RedirectReceived(
checker_.RedirectReceived();
const KURL& new_url = new_request.Url();
- const KURL& original_url = redirect_response.Url();
+ const KURL& original_url = redirect_response.CurrentRequestUrl();
if (out_of_blink_cors_)
return client_->WillFollowRedirect(new_url, redirect_response);
@@ -696,6 +703,7 @@ bool ThreadableLoader::RedirectReceived(
// |last_request_url_| by destroying |assign_on_scope_exit|.
ResourceRequest cross_origin_request(new_request);
+ cross_origin_request.SetInitialUrlForResourceTiming(initial_request_url_);
// Remove any headers that may have been added by the network layer that cause
// access control to fail.
@@ -733,7 +741,8 @@ void ThreadableLoader::DataSent(Resource* resource,
client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
}
-void ThreadableLoader::DataDownloaded(Resource* resource, int data_length) {
+void ThreadableLoader::DataDownloaded(Resource* resource,
+ unsigned long long data_length) {
DCHECK(client_);
DCHECK_EQ(resource, GetResource());
DCHECK(actual_request_.IsNull());
@@ -763,19 +772,19 @@ void ThreadableLoader::DidDownloadToBlob(Resource* resource,
void ThreadableLoader::HandlePreflightResponse(
const ResourceResponse& response) {
base::Optional<network::CorsErrorStatus> cors_error_status =
- cors::CheckPreflightAccess(response.Url(), response.HttpStatusCode(),
- response.HttpHeaderFields(),
- actual_request_.GetFetchCredentialsMode(),
- *GetSecurityOrigin());
+ cors::CheckPreflightAccess(
+ response.CurrentRequestUrl(), response.HttpStatusCode(),
+ response.HttpHeaderFields(),
+ actual_request_.GetFetchCredentialsMode(), *GetSecurityOrigin());
if (cors_error_status) {
- HandlePreflightFailure(response.Url(), *cors_error_status);
+ HandlePreflightFailure(response.CurrentRequestUrl(), *cors_error_status);
return;
}
base::Optional<network::mojom::CorsError> preflight_error =
cors::CheckPreflight(response.HttpStatusCode());
if (preflight_error) {
- HandlePreflightFailure(response.Url(),
+ HandlePreflightFailure(response.CurrentRequestUrl(),
network::CorsErrorStatus(*preflight_error));
return;
}
@@ -784,7 +793,7 @@ void ThreadableLoader::HandlePreflightResponse(
if (actual_request_.IsExternalRequest()) {
error_status = cors::CheckExternalPreflight(response.HttpHeaderFields());
if (error_status) {
- HandlePreflightFailure(response.Url(), *error_status);
+ HandlePreflightFailure(response.CurrentRequestUrl(), *error_status);
return;
}
}
@@ -796,7 +805,7 @@ void ThreadableLoader::HandlePreflightResponse(
actual_request_.HttpHeaderFields(),
actual_request_.GetFetchCredentialsMode());
if (error_status)
- HandlePreflightFailure(response.Url(), *error_status);
+ HandlePreflightFailure(response.CurrentRequestUrl(), *error_status);
}
void ThreadableLoader::ReportResponseReceived(
@@ -806,8 +815,9 @@ void ThreadableLoader::ReportResponseReceived(
if (!frame)
return;
DocumentLoader* loader = frame->Loader().GetDocumentLoader();
- probe::didReceiveResourceResponse(execution_context_, identifier, loader,
- response, GetResource());
+ probe::didReceiveResourceResponse(probe::ToCoreProbeSink(execution_context_),
+ identifier, loader, response,
+ GetResource());
frame->Console().ReportResourceResponseReceived(loader, identifier, response);
}
@@ -861,9 +871,10 @@ void ThreadableLoader::ResponseReceived(
// https://github.com/w3c/preload/issues/100 is addressed.
if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCors &&
response.GetType() == network::mojom::FetchResponseType::kOpaque) {
- DispatchDidFail(ResourceError(
- response.Url(), network::CorsErrorStatus(
- network::mojom::CorsError::kInvalidResponse)));
+ DispatchDidFail(
+ ResourceError(response.CurrentRequestUrl(),
+ network::CorsErrorStatus(
+ network::mojom::CorsError::kInvalidResponse)));
return;
}
@@ -887,11 +898,13 @@ void ThreadableLoader::ResponseReceived(
if (cors_flag_) {
base::Optional<network::CorsErrorStatus> access_error = cors::CheckAccess(
- response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(),
- fetch_credentials_mode_, *GetSecurityOrigin());
+ response.CurrentRequestUrl(), response.HttpStatusCode(),
+ response.HttpHeaderFields(), fetch_credentials_mode_,
+ *GetSecurityOrigin());
if (access_error) {
ReportResponseReceived(resource->Identifier(), response);
- DispatchDidFail(ResourceError(response.Url(), *access_error));
+ DispatchDidFail(
+ ResourceError(response.CurrentRequestUrl(), *access_error));
return;
}
}
@@ -904,13 +917,14 @@ void ThreadableLoader::ResponseReceived(
}
void ThreadableLoader::SetSerializedCachedMetadata(Resource*,
- const char* data,
+ const uint8_t* data,
size_t size) {
checker_.SetSerializedCachedMetadata();
if (!actual_request_.IsNull())
return;
- client_->DidReceiveCachedMetadata(data, SafeCast<int>(size));
+ client_->DidReceiveCachedMetadata(reinterpret_cast<const char*>(data),
+ SafeCast<int>(size));
}
void ThreadableLoader::DataReceived(Resource* resource,
@@ -1075,25 +1089,26 @@ void ThreadableLoader::LoadRequest(
DCHECK(!GetResource());
checker_.WillAddClient();
- ResourceFetcher* fetcher = execution_context_->Fetcher();
if (request.GetRequestContext() == mojom::RequestContextType::VIDEO ||
request.GetRequestContext() == mojom::RequestContextType::AUDIO) {
DCHECK(async_);
- RawResource::FetchMedia(new_params, fetcher, this);
+ RawResource::FetchMedia(new_params, resource_fetcher_, this);
} else if (request.GetRequestContext() ==
mojom::RequestContextType::MANIFEST) {
DCHECK(async_);
- RawResource::FetchManifest(new_params, fetcher, this);
+ RawResource::FetchManifest(new_params, resource_fetcher_, this);
} else if (async_) {
- RawResource::Fetch(new_params, fetcher, this);
+ RawResource::Fetch(new_params, resource_fetcher_, this);
} else {
- RawResource::FetchSynchronously(new_params, fetcher, this);
+ RawResource::FetchSynchronously(new_params, resource_fetcher_, this);
}
}
const SecurityOrigin* ThreadableLoader::GetSecurityOrigin() const {
return security_origin_ ? security_origin_.get()
- : execution_context_->GetSecurityOrigin();
+ : resource_fetcher_->GetProperties()
+ .GetFetchClientSettingsObject()
+ .GetSecurityOrigin();
}
Document* ThreadableLoader::GetDocument() const {
@@ -1103,6 +1118,7 @@ Document* ThreadableLoader::GetDocument() const {
void ThreadableLoader::Trace(blink::Visitor* visitor) {
visitor->Trace(execution_context_);
visitor->Trace(client_);
+ visitor->Trace(resource_fetcher_);
RawResourceClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader.h b/chromium/third_party/blink/renderer/core/loader/threadable_loader.h
index 2929062fec0..18e266b93bd 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader.h
@@ -97,9 +97,13 @@ class CORE_EXPORT ThreadableLoader final
// also for cancellation happened inside the loader.)
//
// ThreadableLoaderClient methods may call Cancel().
+ //
+ // The specified ResourceFetcher if non-null, or otherwise
+ // ExecutionContext::Fetcher() is used.
ThreadableLoader(ExecutionContext&,
ThreadableLoaderClient*,
- const ResourceLoaderOptions&);
+ const ResourceLoaderOptions&,
+ ResourceFetcher* = nullptr);
~ThreadableLoader() override;
// Exposed for testing. Code outside this class should not call this function.
@@ -152,13 +156,13 @@ class CORE_EXPORT ThreadableLoader final
void ResponseReceived(Resource*,
const ResourceResponse&,
std::unique_ptr<WebDataConsumerHandle>) override;
- void SetSerializedCachedMetadata(Resource*, const char*, size_t) override;
+ void SetSerializedCachedMetadata(Resource*, const uint8_t*, size_t) override;
void DataReceived(Resource*, const char* data, size_t data_length) override;
bool RedirectReceived(Resource*,
const ResourceRequest&,
const ResourceResponse&) override;
void RedirectBlocked() override;
- void DataDownloaded(Resource*, int) override;
+ void DataDownloaded(Resource*, unsigned long long) override;
void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) override;
void DidDownloadToBlob(Resource*, scoped_refptr<BlobDataHandle>) override;
@@ -209,6 +213,7 @@ class CORE_EXPORT ThreadableLoader final
Member<ThreadableLoaderClient> client_;
Member<ExecutionContext> execution_context_;
+ Member<ResourceFetcher> resource_fetcher_;
TimeDelta timeout_;
// Some items may be overridden by m_forceDoNotAllowStoredCredentials and
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h b/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h
index 87016048c35..4b81e6cbd36 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h
@@ -66,7 +66,7 @@ class CORE_EXPORT ThreadableLoaderClient : public GarbageCollectedMixin {
virtual void DidFailRedirectCheck() {}
virtual void DidReceiveResourceTiming(const ResourceTimingInfo&) {}
- virtual void DidDownloadData(int /*dataLength*/) {}
+ virtual void DidDownloadData(unsigned long long /*dataLength*/) {}
// Called for requests that had DownloadToBlob set to true. Can be called with
// null if creating the blob failed for some reason (but the download itself
// otherwise succeeded). Could also not be called at all if the downloaded
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc
index ad8156f493f..fa0f5fd168a 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc
@@ -77,7 +77,7 @@ class MockThreadableLoaderClient final
MOCK_METHOD1(DidFail, void(const ResourceError&));
MOCK_METHOD0(DidFailRedirectCheck, void());
MOCK_METHOD1(DidReceiveResourceTiming, void(const ResourceTimingInfo&));
- MOCK_METHOD1(DidDownloadData, void(int));
+ MOCK_METHOD1(DidDownloadData, void(unsigned long long));
};
bool IsCancellation(const ResourceError& error) {
@@ -127,7 +127,7 @@ void SetUpRedirectURL() {
timing.Initialize();
WebURLResponse response;
- response.SetURL(url);
+ response.SetCurrentRequestUrl(url);
response.SetHTTPStatusCode(301);
response.SetLoadTiming(timing);
response.AddHTTPHeaderField("Location", SuccessURL().GetString());
@@ -144,7 +144,7 @@ void SetUpRedirectLoopURL() {
timing.Initialize();
WebURLResponse response;
- response.SetURL(url);
+ response.SetCurrentRequestUrl(url);
response.SetHTTPStatusCode(301);
response.SetLoadTiming(timing);
response.AddHTTPHeaderField("Location", RedirectLoopURL().GetString());
@@ -424,7 +424,6 @@ TEST_F(ThreadableLoaderTest, DidFail) {
CallCheckpoint(1);
EXPECT_CALL(GetCheckpoint(), Call(2));
- EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _));
EXPECT_CALL(*Client(), DidFail(Truly(IsNotCancellation)));
StartLoader(ErrorURL());
@@ -439,7 +438,6 @@ TEST_F(ThreadableLoaderTest, CancelInDidFail) {
CallCheckpoint(1);
EXPECT_CALL(GetCheckpoint(), Call(2));
- EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _));
EXPECT_CALL(*Client(), DidFail(_))
.WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader));
@@ -455,7 +453,6 @@ TEST_F(ThreadableLoaderTest, ClearInDidFail) {
CallCheckpoint(1);
EXPECT_CALL(GetCheckpoint(), Call(2));
- EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _));
EXPECT_CALL(*Client(), DidFail(_))
.WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader));
diff --git a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index 2da7499c7b5..f14eba4171b 100644
--- a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -19,7 +19,6 @@
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
#include "third_party/blink/renderer/core/workers/worker_content_settings_client.h"
@@ -36,38 +35,18 @@ namespace blink {
WorkerFetchContext::~WorkerFetchContext() = default;
-WorkerFetchContext* WorkerFetchContext::Create(
- WorkerOrWorkletGlobalScope& global_scope,
- scoped_refptr<WebWorkerFetchContext> web_context,
- SubresourceFilter* subresource_filter,
- FetchClientSettingsObject* fetch_client_settings_object) {
- if (!web_context)
- return nullptr;
- return MakeGarbageCollected<WorkerFetchContext>(
- global_scope, std::move(web_context), subresource_filter,
- fetch_client_settings_object);
-}
-
WorkerFetchContext::WorkerFetchContext(
WorkerOrWorkletGlobalScope& global_scope,
scoped_refptr<WebWorkerFetchContext> web_context,
- SubresourceFilter* subresource_filter,
- FetchClientSettingsObject* fetch_client_settings_object)
- : BaseFetchContext(global_scope.GetTaskRunner(TaskType::kInternalLoading)),
- global_scope_(global_scope),
+ SubresourceFilter* subresource_filter)
+ : global_scope_(global_scope),
web_context_(std::move(web_context)),
subresource_filter_(subresource_filter),
- fetch_client_settings_object_(fetch_client_settings_object),
save_data_enabled_(GetNetworkStateNotifier().SaveDataEnabled()) {
DCHECK(global_scope.IsContextThread());
DCHECK(web_context_);
}
-const FetchClientSettingsObject*
-WorkerFetchContext::GetFetchClientSettingsObject() const {
- return fetch_client_settings_object_.Get();
-}
-
KURL WorkerFetchContext::GetSiteForCookies() const {
return web_context_->SiteForCookies();
}
@@ -91,7 +70,7 @@ bool WorkerFetchContext::AllowScriptFromSource(const KURL& url) const {
bool WorkerFetchContext::ShouldBlockRequestByInspector(const KURL& url) const {
bool should_block_request = false;
- probe::shouldBlockRequest(global_scope_, url, &should_block_request);
+ probe::shouldBlockRequest(Probe(), url, &should_block_request);
return should_block_request;
}
@@ -123,6 +102,10 @@ void WorkerFetchContext::CountDeprecation(WebFeature feature) const {
Deprecation::CountDeprecation(global_scope_, feature);
}
+CoreProbeSink* WorkerFetchContext::Probe() const {
+ return probe::ToCoreProbeSink(static_cast<ExecutionContext*>(global_scope_));
+}
+
bool WorkerFetchContext::ShouldBlockWebSocketByMixedContentCheck(
const KURL& url) const {
// Worklets don't support WebSocket.
@@ -191,10 +174,6 @@ void WorkerFetchContext::AddConsoleMessage(ConsoleMessage* message) const {
return global_scope_->AddConsoleMessage(message);
}
-const SecurityOrigin* WorkerFetchContext::GetSecurityOrigin() const {
- return GetFetchClientSettingsObject()->GetSecurityOrigin();
-}
-
std::unique_ptr<WebURLLoader> WorkerFetchContext::CreateURLLoader(
const ResourceRequest& request,
const ResourceLoaderOptions& options) {
@@ -243,19 +222,11 @@ std::unique_ptr<CodeCacheLoader> WorkerFetchContext::CreateCodeCacheLoader() {
return web_context_->CreateCodeCacheLoader();
}
-blink::mojom::ControllerServiceWorkerMode
-WorkerFetchContext::IsControlledByServiceWorker() const {
- return web_context_->IsControlledByServiceWorker();
-}
-
-int WorkerFetchContext::ApplicationCacheHostID() const {
- return web_context_->ApplicationCacheHostID();
-}
-
void WorkerFetchContext::PrepareRequest(ResourceRequest& request,
+ WebScopedVirtualTimePauser&,
RedirectType) {
String user_agent = global_scope_->UserAgent();
- probe::applyUserAgentOverride(global_scope_, &user_agent);
+ probe::applyUserAgentOverride(Probe(), &user_agent);
DCHECK(!user_agent.IsNull());
request.SetHTTPUserAgent(AtomicString(user_agent));
@@ -287,35 +258,35 @@ void WorkerFetchContext::DispatchWillSendRequest(
void WorkerFetchContext::DispatchDidReceiveResponse(
unsigned long identifier,
+ const ResourceRequest& request,
const ResourceResponse& response,
- network::mojom::RequestContextFrameType frame_type,
- mojom::RequestContextType request_context,
Resource* resource,
ResourceResponseType) {
if (response.HasMajorCertificateErrors()) {
WebMixedContentContextType context_type =
WebMixedContent::ContextTypeFromRequestContext(
- request_context, false /* strictMixedContentCheckingForPlugin */);
+ request.GetRequestContext(),
+ false /* strictMixedContentCheckingForPlugin */);
if (context_type == WebMixedContentContextType::kBlockable) {
web_context_->DidRunContentWithCertificateErrors();
} else {
web_context_->DidDisplayContentWithCertificateErrors();
}
}
- probe::didReceiveResourceResponse(global_scope_, identifier, nullptr,
- response, resource);
+ probe::didReceiveResourceResponse(Probe(), identifier, nullptr, response,
+ resource);
}
void WorkerFetchContext::DispatchDidReceiveData(unsigned long identifier,
const char* data,
- size_t data_length) {
- probe::didReceiveData(global_scope_, identifier, nullptr, data, data_length);
+ uint64_t data_length) {
+ probe::didReceiveData(Probe(), identifier, nullptr, data, data_length);
}
void WorkerFetchContext::DispatchDidReceiveEncodedData(
unsigned long identifier,
size_t encoded_data_length) {
- probe::didReceiveEncodedDataLength(global_scope_, nullptr, identifier,
+ probe::didReceiveEncodedDataLength(Probe(), nullptr, identifier,
encoded_data_length);
}
@@ -325,7 +296,7 @@ void WorkerFetchContext::DispatchDidFinishLoading(
int64_t encoded_data_length,
int64_t decoded_body_length,
bool should_report_corb_blocking) {
- probe::didFinishLoading(global_scope_, identifier, nullptr, finish_time,
+ probe::didFinishLoading(Probe(), identifier, nullptr, finish_time,
encoded_data_length, decoded_body_length,
should_report_corb_blocking);
}
@@ -335,7 +306,7 @@ void WorkerFetchContext::DispatchDidFail(const KURL& url,
const ResourceError& error,
int64_t encoded_data_length,
bool is_internal_request) {
- probe::didFailLoading(global_scope_, identifier, nullptr, error);
+ probe::didFailLoading(Probe(), identifier, nullptr, error);
if (network_utils::IsCertificateTransparencyRequiredError(
error.ErrorCode())) {
CountUsage(WebFeature::kCertificateTransparencyRequiredErrorOnResourceLoad);
@@ -366,10 +337,6 @@ void WorkerFetchContext::SetFirstPartyCookie(ResourceRequest& out_request) {
out_request.SetSiteForCookies(GetSiteForCookies());
}
-bool WorkerFetchContext::DefersLoading() const {
- return global_scope_->IsContextPaused();
-}
-
std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
WorkerFetchContext::CreateResourceLoadingTaskRunnerHandle() {
return scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
@@ -393,7 +360,6 @@ WorkerFetchContext::GetWorkerContentSettingsClient() const {
void WorkerFetchContext::Trace(blink::Visitor* visitor) {
visitor->Trace(global_scope_);
visitor->Trace(subresource_filter_);
- visitor->Trace(fetch_client_settings_object_);
BaseFetchContext::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h
index a46ff5479ed..ba2a6db9342 100644
--- a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h
+++ b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h
@@ -15,6 +15,7 @@
namespace blink {
+class CoreProbeSink;
class Resource;
class SubresourceFilter;
class WebURLLoader;
@@ -28,20 +29,12 @@ enum class ResourceType : uint8_t;
// service workers) and threaded worklets (animation and audio worklets).
class WorkerFetchContext final : public BaseFetchContext {
public:
- static WorkerFetchContext* Create(WorkerOrWorkletGlobalScope&,
- scoped_refptr<WebWorkerFetchContext>,
- SubresourceFilter*,
- FetchClientSettingsObject*);
-
WorkerFetchContext(WorkerOrWorkletGlobalScope&,
scoped_refptr<WebWorkerFetchContext>,
- SubresourceFilter*,
- FetchClientSettingsObject*);
+ SubresourceFilter*);
~WorkerFetchContext() override;
// BaseFetchContext implementation:
- const FetchClientSettingsObject* GetFetchClientSettingsObject()
- const override;
KURL GetSiteForCookies() const override;
SubresourceFilter* GetSubresourceFilter() const override;
PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
@@ -67,7 +60,6 @@ class WorkerFetchContext final : public BaseFetchContext {
SecurityViolationReportingPolicy) const override;
bool ShouldBlockFetchAsCredentialedSubresource(const ResourceRequest&,
const KURL&) const override;
- bool ShouldLoadNewResource(ResourceType) const override { return true; }
const KURL& Url() const override;
const SecurityOrigin* GetParentSecurityOrigin() const override;
base::Optional<mojom::IPAddressSpace> GetAddressSpace() const override;
@@ -75,15 +67,13 @@ class WorkerFetchContext final : public BaseFetchContext {
void AddConsoleMessage(ConsoleMessage*) const override;
// FetchContext implementation:
- const SecurityOrigin* GetSecurityOrigin() const override;
std::unique_ptr<WebURLLoader> CreateURLLoader(
const ResourceRequest&,
const ResourceLoaderOptions&) override;
std::unique_ptr<CodeCacheLoader> CreateCodeCacheLoader() override;
- void PrepareRequest(ResourceRequest&, RedirectType) override;
- blink::mojom::ControllerServiceWorkerMode IsControlledByServiceWorker()
- const override;
- int ApplicationCacheHostID() const override;
+ void PrepareRequest(ResourceRequest&,
+ WebScopedVirtualTimePauser&,
+ RedirectType) override;
void AddAdditionalRequestHeaders(ResourceRequest&,
FetchResourceType) override;
void DispatchWillSendRequest(unsigned long,
@@ -92,14 +82,13 @@ class WorkerFetchContext final : public BaseFetchContext {
ResourceType,
const FetchInitiatorInfo&) override;
void DispatchDidReceiveResponse(unsigned long identifier,
+ const ResourceRequest&,
const ResourceResponse&,
- network::mojom::RequestContextFrameType,
- mojom::RequestContextType,
Resource*,
ResourceResponseType) override;
void DispatchDidReceiveData(unsigned long identifier,
const char* data,
- size_t data_length) override;
+ uint64_t data_length) override;
void DispatchDidReceiveEncodedData(unsigned long identifier,
size_t encoded_data_length) override;
void DispatchDidFinishLoading(unsigned long identifier,
@@ -117,10 +106,14 @@ class WorkerFetchContext final : public BaseFetchContext {
const ClientHintsPreferences&,
const FetchParameters::ResourceWidth&,
ResourceRequest&) override;
- bool DefersLoading() const override;
- std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>
- CreateResourceLoadingTaskRunnerHandle() override;
+ // TODO(altimin): This is used when creating a URLLoader, and
+ // FetchContext::GetLoadingTaskRunner is used whenever asynchronous tasks
+ // around resource loading are posted. Modify the code so that all
+ // the tasks related to loading a resource use the resource loader handle's
+ // task runner.
+ std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+ CreateResourceLoadingTaskRunnerHandle();
SecurityContext& GetSecurityContext() const;
WorkerSettings* GetWorkerSettings() const;
@@ -134,13 +127,13 @@ class WorkerFetchContext final : public BaseFetchContext {
private:
void SetFirstPartyCookie(ResourceRequest&);
+ CoreProbeSink* Probe() const;
+
const Member<WorkerOrWorkletGlobalScope> global_scope_;
const scoped_refptr<WebWorkerFetchContext> web_context_;
Member<SubresourceFilter> subresource_filter_;
- const Member<FetchClientSettingsObject> fetch_client_settings_object_;
-
// The value of |save_data_enabled_| is read once per frame from
// NetworkStateNotifier, which is guarded by a mutex lock, and cached locally
// here for performance.
diff --git a/chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.cc b/chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.cc
new file mode 100644
index 00000000000..f413fcbdf33
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.cc
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.h"
+
+#include "third_party/blink/public/platform/web_worker_fetch_context.h"
+#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
+
+namespace blink {
+
+WorkerResourceFetcherProperties::WorkerResourceFetcherProperties(
+ WorkerOrWorkletGlobalScope& global_scope,
+ const FetchClientSettingsObject& fetch_client_settings_object,
+ scoped_refptr<WebWorkerFetchContext> web_context)
+ : global_scope_(global_scope),
+ fetch_client_settings_object_(fetch_client_settings_object),
+ web_context_(std::move(web_context)) {
+ DCHECK(web_context_);
+}
+
+void WorkerResourceFetcherProperties::Trace(Visitor* visitor) {
+ visitor->Trace(global_scope_);
+ visitor->Trace(fetch_client_settings_object_);
+ ResourceFetcherProperties::Trace(visitor);
+}
+
+mojom::ControllerServiceWorkerMode
+WorkerResourceFetcherProperties::GetControllerServiceWorkerMode() const {
+ return web_context_->IsControlledByServiceWorker();
+}
+
+bool WorkerResourceFetcherProperties::IsPaused() const {
+ return global_scope_->IsContextPaused();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.h b/chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.h
new file mode 100644
index 00000000000..ac54710b7e6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_RESOURCE_FETCHER_PROPERTIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_RESOURCE_FETCHER_PROPERTIES_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
+
+namespace blink {
+
+class WebWorkerFetchContext;
+class WorkerOrWorkletGlobalScope;
+
+// WorkerResourceFetcherProperties is a ResourceFetcherProperties implementation
+// for workers and worklets.
+class WorkerResourceFetcherProperties final : public ResourceFetcherProperties {
+ public:
+ WorkerResourceFetcherProperties(
+ WorkerOrWorkletGlobalScope&,
+ const FetchClientSettingsObject& fetch_client_settings_object,
+ scoped_refptr<WebWorkerFetchContext> web_context);
+ ~WorkerResourceFetcherProperties() override = default;
+
+ void Trace(Visitor* visitor) override;
+
+ // ResourceFetcherProperties implementation
+ const FetchClientSettingsObject& GetFetchClientSettingsObject()
+ const override {
+ return *fetch_client_settings_object_;
+ }
+ bool IsMainFrame() const override { return false; }
+ ControllerServiceWorkerMode GetControllerServiceWorkerMode() const override;
+ int64_t ServiceWorkerId() const override {
+ DCHECK_NE(GetControllerServiceWorkerMode(),
+ mojom::ControllerServiceWorkerMode::kNoController);
+ // Currently ServiceWorkerId is used only with MemoryCache which is disabled
+ // on a non-main thread. Hence this value doesn't matter.
+ // TODO(nhiroki): Return the valid service worker ID and make this function
+ // available also on a non-main thread.
+ return -1;
+ }
+ bool IsPaused() const override;
+ bool IsDetached() const override { return false; }
+ bool IsLoadComplete() const override { return false; }
+ bool ShouldBlockLoadingMainResource() const override { return false; }
+ bool ShouldBlockLoadingSubResource() const override { return false; }
+
+ private:
+ const Member<WorkerOrWorkletGlobalScope> global_scope_;
+ const Member<const FetchClientSettingsObject> fetch_client_settings_object_;
+ const scoped_refptr<WebWorkerFetchContext> web_context_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_RESOURCE_FETCHER_PROPERTIES_H_
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
index 5370cb6e8a9..01576683d73 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
@@ -33,7 +33,7 @@ BlinkTransferableMessage ToBlinkTransferableMessage(
mojom::Blob::Version_)));
}
result.sender_stack_trace_id = v8_inspector::V8StackTraceId(
- message.stack_trace_id,
+ static_cast<uintptr_t>(message.stack_trace_id),
std::make_pair(message.stack_trace_debugger_id_first,
message.stack_trace_debugger_id_second));
result.locked_agent_cluster_id = message.locked_agent_cluster_id;
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
index b1e61105f16..5864542788b 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
@@ -37,7 +37,7 @@ scoped_refptr<SerializedScriptValue> BuildSerializedScriptValue(
TEST(BlinkTransferableMessageStructTraitsTest,
ArrayBufferTransferOutOfScopeSucceeds) {
- // More exhaustive tests in LayoutTests/. This is a sanity check.
+ // More exhaustive tests in web_tests/. This is a sanity check.
// Build the original ArrayBuffer in a block scope to simulate situations
// where a buffer may be freed twice.
mojo::Message mojo_message;
@@ -79,7 +79,7 @@ TEST(BlinkTransferableMessageStructTraitsTest,
TEST(BlinkTransferableMessageStructTraitsTest,
ArrayBufferContentsLazySerializationSucceeds) {
- // More exhaustive tests in LayoutTests/. This is a sanity check.
+ // More exhaustive tests in web_tests/. This is a sanity check.
V8TestingScope scope;
v8::Isolate* isolate = scope.GetIsolate();
size_t num_elements = 8;
@@ -125,7 +125,7 @@ ImageBitmap* CreateBitmap() {
TEST(BlinkTransferableMessageStructTraitsTest,
BitmapTransferOutOfScopeSucceeds) {
- // More exhaustive tests in LayoutTests/. This is a sanity check.
+ // More exhaustive tests in web_tests/. This is a sanity check.
// Build the original ImageBitmap in a block scope to simulate situations
// where a buffer may be freed twice.
mojo::Message mojo_message;
@@ -149,7 +149,7 @@ TEST(BlinkTransferableMessageStructTraitsTest,
TEST(BlinkTransferableMessageStructTraitsTest,
BitmapLazySerializationSucceeds) {
- // More exhaustive tests in LayoutTests/. This is a sanity check.
+ // More exhaustive tests in web_tests/. This is a sanity check.
V8TestingScope scope;
ImageBitmap* original_bitmap = CreateBitmap();
// The original bitmap's height and width will be 0 after it is transferred.
diff --git a/chromium/third_party/blink/renderer/core/messaging/message_port.cc b/chromium/third_party/blink/renderer/core/messaging/message_port.cc
index 196ab5f6147..a296a04f7a3 100644
--- a/chromium/third_party/blink/renderer/core/messaging/message_port.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/message_port.cc
@@ -313,7 +313,7 @@ bool MessagePort::Accept(mojo::Message* mojo_message) {
evt = MessageEvent::CreateError();
}
- v8::Isolate* isolate = ToIsolate(GetExecutionContext());
+ v8::Isolate* isolate = GetExecutionContext()->GetIsolate();
ThreadDebugger* debugger = ThreadDebugger::From(isolate);
if (debugger)
debugger->ExternalAsyncTaskStarted(message.sender_stack_trace_id);
diff --git a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 2cfce64c6d2..abd95ee3b6e 100644
--- a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -46,9 +46,6 @@ OffscreenCanvas* OffscreenCanvas::Create(unsigned width, unsigned height) {
}
OffscreenCanvas::~OffscreenCanvas() {
- CanvasRenderingContextHost::RecordCanvasSizeToUMA(
- Size().Width(), Size().Height(),
- CanvasRenderingContextHost::HostType::kOffscreenCanvasHost);
v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
-memory_usage_);
}
@@ -57,6 +54,8 @@ void OffscreenCanvas::Commit(scoped_refptr<CanvasResource> canvas_resource,
const SkIRect& damage_rect) {
if (!HasPlaceholderCanvas() || !canvas_resource)
return;
+ RecordCanvasSizeToUMA(
+ Size(), CanvasRenderingContextHost::HostType::kOffscreenCanvasHost);
base::TimeTicks commit_start_time = WTF::CurrentTimeTicks();
current_frame_damage_rect_.join(damage_rect);
diff --git a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
index d017fa1d2c8..09a5e503f05 100644
--- a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
+++ b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -150,9 +150,7 @@ class CORE_EXPORT OffscreenCanvas final
scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
AccelerationHint,
const FloatSize&) final;
- bool WouldTaintOrigin(const SecurityOrigin*) const final {
- return !origin_clean_;
- }
+ bool WouldTaintOrigin() const final { return !origin_clean_; }
FloatSize ElementSize(const FloatSize& default_object_size) const final {
return FloatSize(width(), height());
}
diff --git a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
index e939cf90ae0..115e1a3e431 100644
--- a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
+++ b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
@@ -14,6 +14,6 @@
attribute [EnforceRange] unsigned long width;
attribute [EnforceRange] unsigned long height;
- [CallWith=ScriptState, RaisesException] ImageBitmap transferToImageBitmap();
- [MeasureAs=OffscreenCanvasConvertToBlob, RaisesException, CallWith=ScriptState] Promise<Blob> convertToBlob(optional ImageEncodeOptions options);
+ [CallWith=ScriptState, HighEntropy, MeasureAs=OffscreenCanvasTransferToImageBitmap, RaisesException] ImageBitmap transferToImageBitmap();
+ [CallWith=ScriptState, HighEntropy, MeasureAs=OffscreenCanvasConvertToBlob, RaisesException] Promise<Blob> convertToBlob(optional ImageEncodeOptions options);
};
diff --git a/chromium/third_party/blink/renderer/core/page/BUILD.gn b/chromium/third_party/blink/renderer/core/page/BUILD.gn
index 612cc878402..5ee83b741dc 100644
--- a/chromium/third_party/blink/renderer/core/page/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/page/BUILD.gn
@@ -34,8 +34,8 @@ blink_core_sources("page") {
"page.h",
"page_animator.cc",
"page_animator.h",
- "page_overlay.cc",
- "page_overlay.h",
+ "page_hidden_state.cc",
+ "page_hidden_state.h",
"page_popup.h",
"page_popup_client.cc",
"page_popup_client.h",
@@ -46,8 +46,6 @@ blink_core_sources("page") {
"page_visibility_notifier.cc",
"page_visibility_notifier.h",
"page_visibility_observer.h",
- "page_visibility_state.cc",
- "page_visibility_state.h",
"page_widget_delegate.cc",
"page_widget_delegate.h",
"plugins_changed_observer.cc",
@@ -59,6 +57,8 @@ blink_core_sources("page") {
"print_context.h",
"scoped_page_pauser.cc",
"scoped_page_pauser.h",
+ "scrolling/fragment_anchor.cc",
+ "scrolling/fragment_anchor.h",
"scrolling/overscroll_controller.cc",
"scrolling/overscroll_controller.h",
"scrolling/root_scroller_controller.cc",
@@ -87,6 +87,8 @@ blink_core_sources("page") {
"slot_scoped_traversal.h",
"spatial_navigation.cc",
"spatial_navigation.h",
+ "spatial_navigation_controller.cc",
+ "spatial_navigation_controller.h",
"touch_adjustment.cc",
"touch_adjustment.h",
"validation_message_client.h",
diff --git a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc
index 5a788580138..944df4f55e5 100644
--- a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc
@@ -78,7 +78,7 @@ static const Cursor& MiddleClickAutoscrollCursor(const FloatSize& velocity) {
}
AutoscrollController* AutoscrollController::Create(Page& page) {
- return new AutoscrollController(page);
+ return MakeGarbageCollected<AutoscrollController>(page);
}
AutoscrollController::AutoscrollController(Page& page) : page_(&page) {}
diff --git a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h
index d41461aecd4..356bb8ebaeb 100644
--- a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h
@@ -67,6 +67,9 @@ class CORE_EXPORT AutoscrollController final
: public GarbageCollected<AutoscrollController> {
public:
static AutoscrollController* Create(Page&);
+
+ explicit AutoscrollController(Page&);
+
void Trace(blink::Visitor*);
// Selection and drag-and-drop autoscroll.
@@ -96,8 +99,6 @@ class CORE_EXPORT AutoscrollController final
bool MiddleClickAutoscrollInProgress() const;
private:
- explicit AutoscrollController(Page&);
-
// For test.
bool IsAutoscrolling() const;
diff --git a/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc b/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
index e3ef9b4e305..cc8cea6e0f5 100644
--- a/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
@@ -22,7 +22,7 @@ class AutoscrollControllerTest : public SimTest {
// Ensure Autoscroll not crash by layout called in UpdateSelectionForMouseDrag.
TEST_F(AutoscrollControllerTest,
CrashWhenLayoutStopAnimationBeforeScheduleAnimation) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
WebView().SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client.h b/chromium/third_party/blink/renderer/core/page/chrome_client.h
index 2d4ca195777..9150ac456b8 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client.h
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client.h
@@ -46,6 +46,7 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
// To avoid conflicts with the CreateWindow macro from the Windows SDK...
@@ -216,6 +217,10 @@ class CORE_EXPORT ChromeClient
return base::nullopt;
}
+ // Returns the scale used to convert incoming input events while emulating
+ // device metics.
+ virtual float InputEventsScaleForEmulation() const { return 1; }
+
virtual void DispatchViewportPropertiesDidChange(
const ViewportDescription&) const {}
@@ -290,6 +295,7 @@ class CORE_EXPORT ChromeClient
cc::EventListenerClass) const = 0;
virtual void SetHasScrollEventHandlers(LocalFrame*, bool) = 0;
virtual void SetNeedsLowLatencyInput(LocalFrame*, bool) = 0;
+ virtual void SetNeedsUnbufferedInputForDebugger(LocalFrame*, bool) = 0;
virtual void RequestUnbufferedInputEvents(LocalFrame*) = 0;
virtual void SetTouchAction(LocalFrame*, TouchAction) = 0;
@@ -346,6 +352,10 @@ class CORE_EXPORT ChromeClient
virtual void RegisterViewportLayers() const {}
+ virtual TransformationMatrix GetDeviceEmulationTransform() const {
+ return TransformationMatrix();
+ }
+
virtual void OnMouseDown(Node&) {}
virtual void DidUpdateBrowserControls() const {}
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc
index c7b9280cc19..939f59cac34 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -157,7 +157,7 @@ ChromeClientImpl::~ChromeClientImpl() {
}
ChromeClientImpl* ChromeClientImpl::Create(WebViewImpl* web_view) {
- return new ChromeClientImpl(web_view);
+ return MakeGarbageCollected<ChromeClientImpl>(web_view);
}
void ChromeClientImpl::Trace(Visitor* visitor) {
@@ -188,8 +188,8 @@ IntRect ChromeClientImpl::RootWindowRect() {
// These numbers will be fairly wrong. The window's x/y coordinates will
// be the top left corner of the screen and the size will be the content
// size instead of the window size.
- rect.width = web_view_->Size().width;
- rect.height = web_view_->Size().height;
+ rect.width = web_view_->MainFrameWidget()->Size().width;
+ rect.height = web_view_->MainFrameWidget()->Size().height;
}
return IntRect(rect);
}
@@ -326,7 +326,7 @@ void ChromeClientImpl::AddMessageToConsole(LocalFrame* local_frame,
WebLocalFrameImpl* frame = WebLocalFrameImpl::FromFrame(local_frame);
if (frame && frame->Client()) {
frame->Client()->DidAddMessageToConsole(
- WebConsoleMessage(static_cast<WebConsoleMessage::Level>(level),
+ WebConsoleMessage(static_cast<mojom::ConsoleMessageLevel>(level),
message),
source_id, line_number, stack_trace);
}
@@ -416,7 +416,10 @@ void ChromeClientImpl::ScheduleAnimation(const LocalFrameView* frame_view) {
// WebFrameWidget needs to be initialized before initializing the core frame?
if (!web_frame->LocalRootFrameWidget())
return;
- web_frame->LocalRootFrameWidget()->ScheduleAnimation();
+ // LocalRootFrameWidget() is a WebWidget, its client is the embedder.
+ WebWidgetClient* web_widget_client =
+ web_frame->LocalRootFrameWidget()->Client();
+ web_widget_client->ScheduleAnimation();
}
IntRect ChromeClientImpl::ViewportToScreen(
@@ -459,6 +462,10 @@ base::Optional<IntRect> ChromeClientImpl::VisibleContentRectForPainting()
return web_view_->GetDevToolsEmulator()->VisibleContentRectForPainting();
}
+float ChromeClientImpl::InputEventsScaleForEmulation() const {
+ return web_view_->GetDevToolsEmulator()->InputEventsScaleForEmulation();
+}
+
void ChromeClientImpl::ContentsSizeChanged(LocalFrame* frame,
const IntSize& size) const {
web_view_->DidChangeContentsSize();
@@ -699,7 +706,7 @@ String ChromeClientImpl::AcceptLanguages() {
void ChromeClientImpl::AttachRootGraphicsLayer(GraphicsLayer* root_layer,
LocalFrame* local_frame) {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
// TODO(dcheng): This seems wrong. Non-local roots shouldn't be calling this
// function.
WebLocalFrameImpl* web_frame =
@@ -734,9 +741,10 @@ void ChromeClientImpl::AttachCompositorAnimationTimeline(
CompositorAnimationTimeline* compositor_timeline,
LocalFrame* local_frame) {
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(local_frame);
- if (CompositorAnimationHost* animation_host =
- web_frame->LocalRootFrameWidget()->AnimationHost())
- animation_host->AddTimeline(*compositor_timeline);
+ if (auto* widget = web_frame->LocalRootFrameWidget()) {
+ if (auto* animation_host = widget->AnimationHost())
+ animation_host->AddTimeline(*compositor_timeline);
+ }
}
void ChromeClientImpl::DetachCompositorAnimationTimeline(
@@ -823,7 +831,7 @@ DOMWindow* ChromeClientImpl::PagePopupWindowForTesting() const {
void ChromeClientImpl::SetBrowserControlsState(float top_height,
float bottom_height,
bool shrinks_layout) {
- WebSize size = web_view_->Size();
+ WebSize size = web_view_->MainFrameWidget()->Size();
if (shrinks_layout)
size.height -= top_height + bottom_height;
@@ -852,8 +860,8 @@ bool ChromeClientImpl::ShouldOpenUIElementDuringPageDismissal(
builder.Append(DismissalTypeToString(dismissal_type));
builder.Append(".");
- WebLocalFrameImpl::FromFrame(frame)->AddMessageToConsole(
- WebConsoleMessage(WebConsoleMessage::kLevelError, builder.ToString()));
+ WebLocalFrameImpl::FromFrame(frame)->AddMessageToConsole(WebConsoleMessage(
+ mojom::ConsoleMessageLevel::kError, builder.ToString()));
return false;
}
@@ -932,10 +940,10 @@ void ChromeClientImpl::SetEventListenerProperties(
void ChromeClientImpl::BeginLifecycleUpdates() {
web_view_->StopDeferringCommits();
-
- if (WebLayerTreeView* tree_view = web_view_->LayerTreeView()) {
- tree_view->SetNeedsBeginFrame();
- }
+ // The WidgetClient is null for some WebViews, in which case they can not
+ // composite.
+ if (web_view_->WidgetClient())
+ web_view_->WidgetClient()->ScheduleAnimation();
}
cc::EventListenerProperties ChromeClientImpl::EventListenerProperties(
@@ -963,9 +971,6 @@ void ChromeClientImpl::SetHasScrollEventHandlers(LocalFrame* frame,
WebFrameWidgetBase* widget =
WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget();
- // While a frame is shutting down, we may get called after the layerTreeView
- // is gone: in this case we always expect |hasEventHandlers| to be false.
- DCHECK(!widget || widget->GetLayerTreeView() || !has_event_handlers);
if (widget && widget->GetLayerTreeView())
widget->GetLayerTreeView()->SetHaveScrollEventHandlers(has_event_handlers);
}
@@ -982,6 +987,18 @@ void ChromeClientImpl::SetNeedsLowLatencyInput(LocalFrame* frame,
client->SetNeedsLowLatencyInput(needs_low_latency);
}
+void ChromeClientImpl::SetNeedsUnbufferedInputForDebugger(LocalFrame* frame,
+ bool unbuffered) {
+ DCHECK(frame);
+ WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
+ WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget();
+ if (!widget)
+ return;
+
+ if (WebWidgetClient* client = widget->Client())
+ client->SetNeedsUnbufferedInputForDebugger(unbuffered);
+}
+
void ChromeClientImpl::RequestUnbufferedInputEvents(LocalFrame* frame) {
DCHECK(frame);
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
@@ -1113,6 +1130,10 @@ void ChromeClientImpl::RegisterViewportLayers() const {
web_view_->RegisterViewportLayersWithCompositor();
}
+TransformationMatrix ChromeClientImpl::GetDeviceEmulationTransform() const {
+ return web_view_->GetDeviceEmulationTransform();
+}
+
void ChromeClientImpl::DidUpdateBrowserControls() const {
web_view_->DidUpdateBrowserControls();
}
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h
index 56efb15ca6b..8f009c01ab0 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -51,6 +51,7 @@ struct WebCursorInfo;
class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
public:
static ChromeClientImpl* Create(WebViewImpl*);
+ explicit ChromeClientImpl(WebViewImpl*);
~ChromeClientImpl() override;
void Trace(Visitor* visitor) override;
@@ -112,6 +113,7 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
float WindowToViewportScalar(const float) const override;
WebScreenInfo GetScreenInfo() const override;
base::Optional<IntRect> VisibleContentRectForPainting() const override;
+ float InputEventsScaleForEmulation() const override;
void ContentsSizeChanged(LocalFrame*, const IntSize&) const override;
bool DoubleTapToZoomEnabled() const override;
void PageScaleFactorChanged() const override;
@@ -148,6 +150,7 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
// appropriate scroll optimizations can be chosen.
void SetHasScrollEventHandlers(LocalFrame*, bool has_event_handlers) override;
void SetNeedsLowLatencyInput(LocalFrame*, bool needs_low_latency) override;
+ void SetNeedsUnbufferedInputForDebugger(LocalFrame*, bool immediate) override;
void RequestUnbufferedInputEvents(LocalFrame*) override;
void SetTouchAction(LocalFrame*, TouchAction) override;
@@ -220,6 +223,8 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
void RegisterViewportLayers() const override;
+ TransformationMatrix GetDeviceEmulationTransform() const override;
+
void OnMouseDown(Node&) override;
void DidUpdateBrowserControls() const override;
void SetOverscrollBehavior(const cc::OverscrollBehavior&) override;
@@ -237,8 +242,6 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
base::OnceCallback<void(bool)>) override;
private:
- explicit ChromeClientImpl(WebViewImpl*);
-
bool IsChromeClientImpl() const override { return true; }
void SetCursor(const WebCursorInfo&, LocalFrame*);
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc b/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
index ed4769d0e73..da6c5b42967 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
@@ -53,21 +53,6 @@
namespace blink {
-namespace {
-
-class TestWebViewClient : public frame_test_helpers::TestWebViewClient {
- public:
- explicit TestWebViewClient(WebNavigationPolicy* target) : target_(target) {}
- ~TestWebViewClient() override = default;
-
- void Show(WebNavigationPolicy policy) override { *target_ = policy; }
-
- private:
- WebNavigationPolicy* target_;
-};
-
-} // anonymous namespace
-
class ViewCreatingClient : public frame_test_helpers::TestWebViewClient {
public:
WebView* CreateView(WebLocalFrame* opener,
diff --git a/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc b/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc
index 62b59a9f0c7..214bb03e067 100644
--- a/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -73,7 +73,7 @@ ContextMenuController::ContextMenuController(Page* page) : page_(page) {}
ContextMenuController::~ContextMenuController() = default;
ContextMenuController* ContextMenuController::Create(Page* page) {
- return new ContextMenuController(page);
+ return MakeGarbageCollected<ContextMenuController>(page);
}
void ContextMenuController::Trace(blink::Visitor* visitor) {
@@ -128,17 +128,12 @@ Node* ContextMenuController::ContextMenuNodeForFrame(LocalFrame* frame) {
: nullptr;
}
-// Figure out the URL of a page or subframe. Returns |page_type| as the type,
-// which indicates page or subframe, or ContextNodeType::kNone if the URL could
-// not be determined for some reason.
+// Figure out the URL of a page or subframe.
static KURL UrlFromFrame(LocalFrame* frame) {
if (frame) {
DocumentLoader* document_loader = frame->Loader().GetDocumentLoader();
- if (document_loader) {
- return document_loader->UnreachableURL().IsEmpty()
- ? document_loader->GetRequest().Url()
- : document_loader->UnreachableURL();
- }
+ if (document_loader)
+ return document_loader->UrlForHistory();
}
return KURL();
}
@@ -264,10 +259,9 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
data.media_type = WebContextMenuData::kMediaTypeVideo;
if (media_element->SupportsPictureInPicture()) {
data.media_flags |= WebContextMenuData::kMediaCanPictureInPicture;
- if (PictureInPictureController::From(media_element->GetDocument())
- .IsPictureInPictureElement(media_element)) {
+ if (PictureInPictureController::IsElementInPictureInPicture(
+ media_element))
data.media_flags |= WebContextMenuData::kMediaPictureInPicture;
- }
}
} else if (IsHTMLAudioElement(*media_element))
data.media_type = WebContextMenuData::kMediaTypeAudio;
diff --git a/chromium/third_party/blink/renderer/core/page/context_menu_controller.h b/chromium/third_party/blink/renderer/core/page/context_menu_controller.h
index 9e46df9891b..702167df286 100644
--- a/chromium/third_party/blink/renderer/core/page/context_menu_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/context_menu_controller.h
@@ -47,6 +47,8 @@ class CORE_EXPORT ContextMenuController final
: public GarbageCollectedFinalized<ContextMenuController> {
public:
static ContextMenuController* Create(Page*);
+
+ explicit ContextMenuController(Page*);
~ContextMenuController();
void Trace(blink::Visitor*);
@@ -67,8 +69,6 @@ class CORE_EXPORT ContextMenuController final
private:
friend class ContextMenuControllerTest;
- explicit ContextMenuController(Page*);
-
// Returns whether a Context Menu was actually shown.
bool ShowContextMenu(LocalFrame*, const LayoutPoint&, WebMenuSourceType);
bool ShouldShowContextMenuFromTouch(const WebContextMenuData&);
diff --git a/chromium/third_party/blink/renderer/core/page/create_window.cc b/chromium/third_party/blink/renderer/core/page/create_window.cc
index cfc96f5cf57..edb9fb83384 100644
--- a/chromium/third_party/blink/renderer/core/page/create_window.cc
+++ b/chromium/third_party/blink/renderer/core/page/create_window.cc
@@ -363,16 +363,17 @@ static Frame* CreateWindowHelper(LocalFrame& opener_frame,
DOMWindow* CreateWindow(const String& url_string,
const AtomicString& frame_name,
const String& window_features_string,
- LocalDOMWindow& calling_window,
- LocalFrame& first_frame,
+ LocalDOMWindow& incumbent_window,
+ LocalFrame& entered_window_frame,
LocalFrame& opener_frame,
ExceptionState& exception_state) {
- LocalFrame* active_frame = calling_window.GetFrame();
+ LocalFrame* active_frame = incumbent_window.GetFrame();
DCHECK(active_frame);
- KURL completed_url = url_string.IsEmpty()
- ? KURL(g_empty_string)
- : first_frame.GetDocument()->CompleteURL(url_string);
+ KURL completed_url =
+ url_string.IsEmpty()
+ ? KURL(g_empty_string)
+ : entered_window_frame.GetDocument()->CompleteURL(url_string);
if (!completed_url.IsEmpty() && !completed_url.IsValid()) {
UseCounter::Count(active_frame, WebFeature::kWindowOpenWithInvalidURL);
exception_state.ThrowDOMException(
@@ -386,7 +387,8 @@ DOMWindow* CreateWindow(const String& url_string,
opener_frame.GetDocument()->GetContentSecurityPolicy() &&
!ContentSecurityPolicy::ShouldBypassMainWorld(
opener_frame.GetDocument())) {
- String script_source = DecodeURLEscapeSequences(completed_url.GetString());
+ String script_source = DecodeURLEscapeSequences(
+ completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
if (!opener_frame.GetDocument()
->GetContentSecurityPolicy()
@@ -400,7 +402,7 @@ DOMWindow* CreateWindow(const String& url_string,
WebWindowFeatures window_features =
GetWindowFeaturesFromString(window_features_string);
- FrameLoadRequest frame_request(calling_window.document(),
+ FrameLoadRequest frame_request(incumbent_window.document(),
ResourceRequest(completed_url), frame_name);
frame_request.SetShouldSetOpener(window_features.noopener ? kNeverSetOpener
: kMaybeSetOpener);
@@ -434,7 +436,7 @@ DOMWindow* CreateWindow(const String& url_string,
false /* force_new_foreground_tab */, created);
if (!new_frame)
return nullptr;
- if (new_frame->DomWindow()->IsInsecureScriptAccess(calling_window,
+ if (new_frame->DomWindow()->IsInsecureScriptAccess(incumbent_window,
completed_url))
return window_features.noopener ? nullptr : new_frame->DomWindow();
@@ -448,7 +450,7 @@ DOMWindow* CreateWindow(const String& url_string,
// causes the navigation to be flagged as a client redirect, which is
// observable via the webNavigation extension api.
if (created) {
- FrameLoadRequest request(calling_window.document(),
+ FrameLoadRequest request(incumbent_window.document(),
ResourceRequest(completed_url));
request.GetResourceRequest().SetHasUserGesture(has_user_gesture);
if (const WebInputEvent* input_event = CurrentInputEvent::Get()) {
@@ -456,7 +458,7 @@ DOMWindow* CreateWindow(const String& url_string,
}
new_frame->Navigate(request, WebFrameLoadType::kStandard);
} else if (!url_string.IsEmpty()) {
- new_frame->ScheduleNavigation(*calling_window.document(), completed_url,
+ new_frame->ScheduleNavigation(*incumbent_window.document(), completed_url,
WebFrameLoadType::kStandard,
has_user_gesture ? UserGestureStatus::kActive
: UserGestureStatus::kNone);
diff --git a/chromium/third_party/blink/renderer/core/page/create_window.h b/chromium/third_party/blink/renderer/core/page/create_window.h
index 2d5afe1dc86..5178d84cd16 100644
--- a/chromium/third_party/blink/renderer/core/page/create_window.h
+++ b/chromium/third_party/blink/renderer/core/page/create_window.h
@@ -44,8 +44,8 @@ struct WebWindowFeatures;
DOMWindow* CreateWindow(const String& url_string,
const AtomicString& frame_name,
const String& window_features_string,
- LocalDOMWindow& calling_window,
- LocalFrame& first_frame,
+ LocalDOMWindow& incumbent_window,
+ LocalFrame& entered_window_frame,
LocalFrame& opener_frame,
ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/core/page/drag_controller.cc b/chromium/third_party/blink/renderer/core/page/drag_controller.cc
index d27010367a1..3b0b20a1f43 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_controller.cc
@@ -932,7 +932,7 @@ bool DragController::PopulateDragDataTransfer(LocalFrame* src,
HitTestResult hit_test_result =
src->GetEventHandler().HitTestResultAtLocation(location);
// FIXME: Can this even happen? I guess it's possible, but should verify
- // with a layout test.
+ // with a web test.
if (!state.drag_src_->IsShadowIncludingInclusiveAncestorOf(
hit_test_result.InnerNode())) {
// The original node being dragged isn't under the drag origin anymore...
@@ -1144,8 +1144,9 @@ std::unique_ptr<DragImage> DragController::DragImageForSelection(
kGlobalPaintSelectionOnly | kGlobalPaintFlattenCompositingLayers;
PaintRecordBuilder builder;
- frame.View()->PaintContents(builder.Context(), paint_flags,
- EnclosingIntRect(painting_rect));
+ frame.View()->PaintContentsOutsideOfLifecycle(
+ builder.Context(), paint_flags,
+ CullRect(EnclosingIntRect(painting_rect)));
PropertyTreeState property_tree_state =
frame.View()->GetLayoutView()->FirstFragment().LocalBorderBoxProperties();
diff --git a/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc b/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc
index 9f2215d644c..111b2481c5a 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc
@@ -46,7 +46,7 @@ class DragControllerTest : public RenderingTest {
DragControllerTest()
: RenderingTest(SingleChildLocalFrameClient::Create()),
- chrome_client_(new DragMockChromeClient) {}
+ chrome_client_(MakeGarbageCollected<DragMockChromeClient>()) {}
LocalFrame& GetFrame() const { return *GetDocument().GetFrame(); }
DragMockChromeClient& GetChromeClient() const override {
return *chrome_client_;
@@ -84,7 +84,7 @@ class DragControllerSimTest : public SimTest {};
// https://crbug.com/733996.
TEST_F(DragControllerSimTest, DropURLOnNonNavigatingClearsState) {
WebView().GetPage()->GetSettings().SetNavigateOnDragDrop(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -124,7 +124,7 @@ TEST_F(DragControllerSimTest, DropURLOnNonNavigatingClearsState) {
// Regression test for https://crbug.com/685030
TEST_F(DragControllerSimTest, ThrottledDocumentHandled) {
WebView().GetPage()->GetSettings().SetNavigateOnDragDrop(false);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
diff --git a/chromium/third_party/blink/renderer/core/page/focus_controller.cc b/chromium/third_party/blink/renderer/core/page/focus_controller.cc
index 0f1ebb0a42c..03a8cd087dc 100644
--- a/chromium/third_party/blink/renderer/core/page/focus_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/focus_controller.cc
@@ -232,17 +232,19 @@ ScopedFocusNavigation::ScopedFocusNavigation(
: current_(current) {
if (HTMLSlotElement* slot = ToHTMLSlotElementOrNull(scoping_root_node)) {
if (slot->AssignedNodes().IsEmpty()) {
- navigation_ = new FocusNavigation(scoping_root_node, *slot, owner_map);
+ navigation_ = MakeGarbageCollected<FocusNavigation>(scoping_root_node,
+ *slot, owner_map);
} else {
// Here, slot->AssignedNodes() are non null, so the slot must be inside
// the shadow tree.
DCHECK(scoping_root_node.ContainingShadowRoot());
- navigation_ =
- new FocusNavigation(scoping_root_node.ContainingShadowRoot()->host(),
- ToHTMLSlotElement(scoping_root_node), owner_map);
+ navigation_ = MakeGarbageCollected<FocusNavigation>(
+ scoping_root_node.ContainingShadowRoot()->host(),
+ ToHTMLSlotElement(scoping_root_node), owner_map);
}
} else {
- navigation_ = new FocusNavigation(scoping_root_node, owner_map);
+ navigation_ =
+ MakeGarbageCollected<FocusNavigation>(scoping_root_node, owner_map);
}
DCHECK(navigation_);
}
@@ -897,12 +899,12 @@ void FocusController::FocusHasChanged() {
ToLocalFrame(FocusedOrMainFrame())->GetEventHandler().StopAutoscroll();
// Do not set a focused frame when being unfocused. This might reset
- // m_isFocused to true.
+ // is_focused_ to true.
if (!focused_frame_ && focused)
SetFocusedFrame(page_->MainFrame());
- // setFocusedFrame above might reject to update m_focusedFrame, or
- // m_focusedFrame might be changed by blur/focus event handlers.
+ // SetFocusedFrame above might reject to update focused_frame_, or
+ // focused_frame_ might be changed by blur/focus event handlers.
if (focused_frame_ && focused_frame_->IsLocalFrame() &&
ToLocalFrame(focused_frame_.Get())->View()) {
ToLocalFrame(focused_frame_.Get())->Selection().SetFrameIsFocused(focused);
@@ -964,11 +966,9 @@ bool FocusController::AdvanceFocus(
return AdvanceFocusInDocumentOrder(starting_frame, nullptr, type,
initial_focus, source_capabilities);
}
- case kWebFocusTypeLeft:
- case kWebFocusTypeRight:
- case kWebFocusTypeUp:
- case kWebFocusTypeDown:
- return AdvanceFocusDirectionally(type);
+ case kWebFocusTypeSpatialNavigation:
+ // Fallthrough - SpatialNavigation should use
+ // SpatialNavigationController.
default:
NOTREACHED();
}
@@ -1229,7 +1229,6 @@ bool FocusController::SetFocusedElement(Element* element,
new_document->FocusedElement() == element)
return true;
-
if (old_document && old_document != new_document)
old_document->ClearFocusedElement();
@@ -1275,224 +1274,6 @@ void FocusController::SetActive(bool active) {
ActiveHasChanged();
}
-static void UpdateFocusCandidateIfNeeded(WebFocusType direction,
- const FocusCandidate& current,
- FocusCandidate& candidate,
- FocusCandidate& closest) {
- DCHECK(candidate.visible_node->IsElementNode());
- DCHECK(candidate.visible_node->GetLayoutObject());
-
- // Ignore iframes that don't have a src attribute
- if (FrameOwnerElement(candidate) &&
- (!FrameOwnerElement(candidate)->ContentFrame() ||
- candidate.rect_in_root_frame.IsEmpty()))
- return;
-
- // Ignore off screen child nodes of containers that do not scroll
- // (overflow:hidden)
- if (candidate.is_offscreen && !CanBeScrolledIntoView(direction, candidate))
- return;
-
- DistanceDataForNode(direction, current, candidate);
- if (candidate.distance == MaxDistance())
- return;
-
- if (candidate.is_offscreen_after_scrolling)
- return;
-
- if (closest.IsNull()) {
- closest = candidate;
- return;
- }
-
- LayoutRect intersection_rect =
- Intersection(candidate.rect_in_root_frame, closest.rect_in_root_frame);
- if (!intersection_rect.IsEmpty() &&
- !AreElementsOnSameLine(closest, candidate) &&
- intersection_rect == candidate.rect_in_root_frame) {
- // If 2 nodes are intersecting, do hit test to find which node in on top.
- LayoutUnit x = intersection_rect.X() + intersection_rect.Width() / 2;
- LayoutUnit y = intersection_rect.Y() + intersection_rect.Height() / 2;
- if (!candidate.visible_node->GetDocument()
- .GetPage()
- ->MainFrame()
- ->IsLocalFrame())
- return;
- HitTestLocation location(IntPoint(x.ToInt(), y.ToInt()));
- HitTestResult result =
- candidate.visible_node->GetDocument()
- .GetPage()
- ->DeprecatedLocalMainFrame()
- ->GetEventHandler()
- .HitTestResultAtLocation(
- location, HitTestRequest::kReadOnly | HitTestRequest::kActive |
- HitTestRequest::kIgnoreClipping);
- if (candidate.visible_node->contains(result.InnerNode())) {
- closest = candidate;
- return;
- }
- if (closest.visible_node->contains(result.InnerNode()))
- return;
- }
-
- if (candidate.distance < closest.distance)
- closest = candidate;
-}
-
-void FocusController::FindFocusCandidateInContainer(
- Node& container,
- const LayoutRect& starting_rect,
- WebFocusType direction,
- FocusCandidate& closest,
- const SkipList& already_checked) {
- if (already_checked.Contains(&container))
- return;
-
- Element* focused_element =
- (FocusedFrame() && FocusedFrame()->GetDocument())
- ? FocusedFrame()->GetDocument()->FocusedElement()
- : nullptr;
-
- Element* element = ElementTraversal::FirstWithin(container);
- FocusCandidate current;
- current.rect_in_root_frame = starting_rect;
- current.focusable_node = focused_element;
- current.visible_node = focused_element;
-
- for (; element;
- element =
- (IsNavigableContainer(element, direction))
- ? ElementTraversal::NextSkippingChildren(*element, &container)
- : ElementTraversal::Next(*element, &container)) {
- if (element == focused_element)
- continue;
-
- if (!element->IsKeyboardFocusable() &&
- !IsNavigableContainer(element, direction))
- continue;
-
- if (HasRemoteFrame(element))
- continue;
-
- if (already_checked.Contains(element))
- continue;
-
- FocusCandidate candidate = FocusCandidate(element, direction);
- if (candidate.IsNull())
- continue;
-
- candidate.enclosing_scrollable_box = &container;
- UpdateFocusCandidateIfNeeded(direction, current, candidate, closest);
- }
-}
-
-bool FocusController::AdvanceFocusDirectionallyInContainer(
- Node* start_container,
- const LayoutRect& starting_rect,
- WebFocusType direction,
- Node* pruned_sub_tree_root) {
- if (!start_container)
- return false;
-
- HeapVector<Member<Node>> stack;
- stack.push_back(start_container);
-
- SkipList already_checked;
- if (pruned_sub_tree_root)
- already_checked.insert(pruned_sub_tree_root);
-
- while (!stack.IsEmpty()) {
- Node* container = stack.back();
-
- FocusCandidate candidate;
- FindFocusCandidateInContainer(*container, starting_rect, direction,
- candidate, already_checked);
-
- if (candidate.IsNull()) {
- // Nothing to focus in this container, scroll if possible.
- // NOTE: If no scrolling is performed (i.e. ScrollInDirection returns
- // false), the spatial navigation algorithm will skip this container.
- if (ScrollInDirection(container, direction))
- return true;
-
- stack.pop_back();
- continue;
- }
-
- if (!IsNavigableContainer(candidate.visible_node, direction)) {
- // We found a new focus node, navigate to it.
- Element* element = ToElement(candidate.focusable_node);
- DCHECK(element);
- element->focus(
- FocusParams(SelectionBehaviorOnFocus::kReset, direction, nullptr));
- return true;
- }
-
- // We now dig into a navigable container.
-
- HTMLFrameOwnerElement* frame_element = FrameOwnerElement(candidate);
- if (frame_element && frame_element->ContentFrame()->IsLocalFrame()) {
- // Navigate into a discovered frame.
- ToLocalFrame(frame_element->ContentFrame())
- ->GetDocument()
- ->UpdateStyleAndLayoutIgnorePendingStylesheets();
-
- // Mark this |already_checked| so we can skip this subtree in case
- // FindFocusCandidateInContainer() returns it again.
- already_checked.insert(candidate.visible_node);
-
- stack.push_back(
- ToLocalFrame(frame_element->ContentFrame())->GetDocument());
- continue;
- }
-
- // Search sub-container.
- stack.push_back(candidate.visible_node);
- }
-
- return ScrollInDirection(start_container, direction);
-}
-
-bool FocusController::AdvanceFocusDirectionally(WebFocusType direction) {
- // FIXME: Directional focus changes don't yet work with RemoteFrames.
- if (!FocusedOrMainFrame()->IsLocalFrame())
- return false;
- const LocalFrame* current_frame = ToLocalFrame(FocusedOrMainFrame());
- DCHECK(current_frame);
-
- Document* focused_document = current_frame->GetDocument();
- if (!focused_document)
- return false;
-
- Element* focused_element = focused_document->FocusedElement();
- Node* container = focused_document;
- if (auto* document = DynamicTo<Document>(container))
- document->UpdateStyleAndLayoutIgnorePendingStylesheets();
- if (focused_element)
- container = ScrollableAreaOrDocumentOf(focused_element);
-
- const LayoutRect visible_rect = RootViewport(current_frame);
- const LayoutRect start_box =
- SearchOrigin(visible_rect, focused_element, direction);
-
- bool consumed = false;
- Node* pruned_sub_tree_root = nullptr;
- while (container) {
- consumed = AdvanceFocusDirectionallyInContainer(
- container, start_box, direction, pruned_sub_tree_root);
- if (consumed)
- break;
-
- // Nothing found in |container| so search the parent container.
- pruned_sub_tree_root = container;
- container = ScrollableAreaOrDocumentOf(container);
- if (auto* document = DynamicTo<Document>(container))
- document->UpdateStyleAndLayoutIgnorePendingStylesheets();
- }
-
- return consumed;
-}
-
void FocusController::RegisterFocusChangedObserver(
FocusChangedObserver* observer) {
DCHECK(observer);
diff --git a/chromium/third_party/blink/renderer/core/page/focus_controller.h b/chromium/third_party/blink/renderer/core/page/focus_controller.h
index ab263394aaa..bb3f9728cde 100644
--- a/chromium/third_party/blink/renderer/core/page/focus_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/focus_controller.h
@@ -36,7 +36,6 @@
namespace blink {
-struct FocusCandidate;
struct FocusParams;
class ContainerNode;
class Document;
@@ -46,7 +45,6 @@ class Frame;
class HTMLFrameOwnerElement;
class InputDeviceCapabilities;
class LocalFrame;
-class Node;
class Page;
class RemoteFrame;
@@ -108,14 +106,12 @@ class CORE_EXPORT FocusController final
void Trace(blink::Visitor*);
private:
- using SkipList = HeapHashSet<Member<Node>>;
Element* FindFocusableElement(WebFocusType, Element&, OwnerMap&);
bool AdvanceFocus(WebFocusType,
bool initial_focus,
InputDeviceCapabilities* source_capabilities = nullptr);
- bool AdvanceFocusDirectionally(WebFocusType);
bool AdvanceFocusInDocumentOrder(
LocalFrame*,
Element* start,
@@ -123,16 +119,6 @@ class CORE_EXPORT FocusController final
bool initial_focus,
InputDeviceCapabilities* source_capabilities);
- bool AdvanceFocusDirectionallyInContainer(Node* start_container,
- const LayoutRect& starting_rect,
- WebFocusType,
- Node* pruned_sub_tree_root);
- void FindFocusCandidateInContainer(Node& container,
- const LayoutRect& starting_rect,
- WebFocusType,
- FocusCandidate& closest,
- const SkipList& already_checked);
-
void NotifyFocusChangedObservers() const;
void ActiveHasChanged();
diff --git a/chromium/third_party/blink/renderer/core/page/page.cc b/chromium/third_party/blink/renderer/core/page/page.cc
index bee3dcd9beb..ff579698b83 100644
--- a/chromium/third_party/blink/renderer/core/page/page.cc
+++ b/chromium/third_party/blink/renderer/core/page/page.cc
@@ -57,13 +57,14 @@
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "third_party/blink/renderer/core/page/drag_controller.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
-#include "third_party/blink/renderer/core/page/page_overlay.h"
+#include "third_party/blink/renderer/core/page/page_hidden_state.h"
#include "third_party/blink/renderer/core/page/plugins_changed_observer.h"
#include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
#include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
#include "third_party/blink/renderer/core/page/scrolling/overscroll_controller.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
#include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
#include "third_party/blink/renderer/core/page/validation_message_client_impl.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
@@ -75,6 +76,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/plugins/plugin_data.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/skia/include/core/SkColor.h"
namespace blink {
@@ -161,7 +163,7 @@ Page::Page(PageClients& page_clients)
page_scale_constraints_set_(PageScaleConstraintsSet::Create(this)),
pointer_lock_controller_(PointerLockController::Create(this)),
browser_controls_(BrowserControls::Create(*this)),
- console_message_storage_(new ConsoleMessageStorage()),
+ console_message_storage_(MakeGarbageCollected<ConsoleMessageStorage>()),
global_root_scroller_controller_(
TopDocumentRootScrollerController::Create(*this)),
visual_viewport_(VisualViewport::Create(*this)),
@@ -175,7 +177,7 @@ Page::Page(PageClients& page_clients)
tab_key_cycles_through_elements_(true),
paused_(false),
device_scale_factor_(1),
- visibility_state_(mojom::PageVisibilityState::kVisible),
+ is_hidden_(false),
page_lifecycle_state_(kDefaultPageLifecycleState),
is_cursor_visible_(true),
subframe_count_(0),
@@ -298,6 +300,13 @@ void Page::SetOpenedByDOM() {
opened_by_dom_ = true;
}
+SpatialNavigationController& Page::GetSpatialNavigationController() {
+ DCHECK(GetSettings().GetSpatialNavigationEnabled());
+ if (!spatial_navigation_controller_)
+ spatial_navigation_controller_ = SpatialNavigationController::Create(*this);
+ return *spatial_navigation_controller_;
+}
+
void Page::PlatformColorsChanged() {
for (const Page* page : AllPages())
for (Frame* frame = page->MainFrame(); frame;
@@ -450,16 +459,15 @@ void Page::VisitedStateChanged(LinkHash link_hash) {
}
}
-void Page::SetVisibilityState(mojom::PageVisibilityState visibility_state,
- bool is_initial_state) {
- if (visibility_state_ == visibility_state)
+void Page::SetIsHidden(bool hidden, bool is_initial_state) {
+ if (is_hidden_ == hidden)
return;
- visibility_state_ = visibility_state;
+ is_hidden_ = hidden;
if (is_initial_state)
return;
- NotifyPageVisibilityChanged();
+ NotifyPageVisibilityChanged();
if (main_frame_) {
if (IsPageVisible())
RestoreSVGImageAnimations();
@@ -467,12 +475,8 @@ void Page::SetVisibilityState(mojom::PageVisibilityState visibility_state,
}
}
-mojom::PageVisibilityState Page::VisibilityState() const {
- return visibility_state_;
-}
-
bool Page::IsPageVisible() const {
- return VisibilityState() == mojom::PageVisibilityState::kVisible;
+ return !is_hidden_;
}
void Page::SetLifecycleState(PageLifecycleState state) {
@@ -651,6 +655,14 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
NotifyPluginsChanged();
break;
}
+ case SettingsDelegate::kHighlightAdsChange: {
+ for (Frame* frame = MainFrame(); frame;
+ frame = frame->Tree().TraverseNext()) {
+ if (frame->IsLocalFrame())
+ ToLocalFrame(frame)->UpdateAdHighlight();
+ }
+ break;
+ }
}
}
@@ -720,6 +732,7 @@ void Page::Trace(blink::Visitor* visitor) {
visitor->Trace(visual_viewport_);
visitor->Trace(overscroll_controller_);
visitor->Trace(link_highlights_);
+ visitor->Trace(spatial_navigation_controller_);
visitor->Trace(main_frame_);
visitor->Trace(plugin_data_);
visitor->Trace(validation_message_client_);
@@ -840,59 +853,6 @@ int32_t Page::AutoplayFlags() const {
return autoplay_flags_;
}
-namespace {
-
-class ColorOverlay final : public PageOverlay::Delegate {
- public:
- explicit ColorOverlay(SkColor color) : color_(color) {}
-
- private:
- void PaintPageOverlay(const PageOverlay& page_overlay,
- GraphicsContext& graphics_context,
- const IntSize& size) const override {
- if (DrawingRecorder::UseCachedDrawingIfPossible(
- graphics_context, page_overlay, DisplayItem::kPageOverlay))
- return;
- FloatRect rect(0, 0, size.Width(), size.Height());
- DrawingRecorder recorder(graphics_context, page_overlay,
- DisplayItem::kPageOverlay);
- graphics_context.FillRect(rect, color_);
- }
-
- SkColor color_;
-};
-
-} // namespace
-
-void Page::SetPageOverlayColor(SkColor color) {
- if (page_color_overlay_)
- page_color_overlay_.reset();
-
- if (color == Color::kTransparent)
- return;
-
- if (!MainFrame() || !MainFrame()->IsLocalFrame())
- return;
- auto* local_frame = ToLocalFrame(MainFrame());
- page_color_overlay_ =
- PageOverlay::Create(local_frame, std::make_unique<ColorOverlay>(color));
-
- // Update compositing which will create graphics layers so the page color
- // update below will be able to attach to the root graphics layer.
- local_frame->View()->UpdateLifecycleToCompositingCleanPlusScrolling();
- page_color_overlay_->Update();
-}
-
-void Page::UpdatePageColorOverlay() {
- if (page_color_overlay_)
- page_color_overlay_->Update();
-}
-
-void Page::PaintPageColorOverlay() {
- if (page_color_overlay_)
- page_color_overlay_->GetGraphicsLayer()->Paint(nullptr);
-}
-
Page::PageClients::PageClients() : chrome_client(nullptr) {}
Page::PageClients::~PageClients() = default;
diff --git a/chromium/third_party/blink/renderer/core/page/page.h b/chromium/third_party/blink/renderer/core/page/page.h
index 676f1c715ea..616470be36d 100644
--- a/chromium/third_party/blink/renderer/core/page/page.h
+++ b/chromium/third_party/blink/renderer/core/page/page.h
@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/page/page_animator.h"
#include "third_party/blink/renderer/core/page/page_visibility_notifier.h"
#include "third_party/blink/renderer/core/page/page_visibility_observer.h"
-#include "third_party/blink/renderer/core/page/page_visibility_state.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -44,13 +43,13 @@
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/skia/include/core/SkColor.h"
namespace blink {
class AutoscrollController;
class BrowserControls;
class ChromeClient;
+class ConsoleMessageStorage;
class ContextMenuController;
class Document;
class DragCaret;
@@ -61,7 +60,6 @@ class LinkHighlights;
class LocalFrame;
class LocalFrameView;
class OverscrollController;
-class PageOverlay;
struct PageScaleConstraints;
class PageScaleConstraintsSet;
class PluginData;
@@ -72,7 +70,7 @@ class ScrollingCoordinator;
class ScrollbarTheme;
class SecurityOrigin;
class Settings;
-class ConsoleMessageStorage;
+class SpatialNavigationController;
class TopDocumentRootScrollerController;
class ValidationMessageClient;
class VisualViewport;
@@ -172,6 +170,7 @@ class CORE_EXPORT Page final : public GarbageCollectedFinalized<Page>,
DragCaret& GetDragCaret() const { return *drag_caret_; }
DragController& GetDragController() const { return *drag_controller_; }
FocusController& GetFocusController() const { return *focus_controller_; }
+ SpatialNavigationController& GetSpatialNavigationController();
ContextMenuController& GetContextMenuController() const {
return *context_menu_controller_;
}
@@ -255,8 +254,7 @@ class CORE_EXPORT Page final : public GarbageCollectedFinalized<Page>,
static void AllVisitedStateChanged(bool invalidate_visited_link_hashes);
static void VisitedStateChanged(LinkHash visited_hash);
- void SetVisibilityState(mojom::PageVisibilityState, bool);
- mojom::PageVisibilityState VisibilityState() const;
+ void SetIsHidden(bool hidden, bool is_initial_state);
bool IsPageVisible() const;
PageLifecycleState LifecycleState() const;
@@ -312,12 +310,6 @@ class CORE_EXPORT Page final : public GarbageCollectedFinalized<Page>,
int32_t AutoplayFlags() const;
- void SetPageOverlayColor(SkColor);
-
- void UpdatePageColorOverlay();
-
- void PaintPageColorOverlay();
-
private:
friend class ScopedPagePauser;
@@ -362,13 +354,12 @@ class CORE_EXPORT Page final : public GarbageCollectedFinalized<Page>,
const Member<VisualViewport> visual_viewport_;
const Member<OverscrollController> overscroll_controller_;
const Member<LinkHighlights> link_highlights_;
+ Member<SpatialNavigationController> spatial_navigation_controller_;
Member<PluginData> plugin_data_;
Member<ValidationMessageClient> validation_message_client_;
- std::unique_ptr<PageOverlay> page_color_overlay_;
-
Deprecation deprecation_;
HostsUsingFeatures hosts_using_features_;
WebWindowFeatures window_features_;
@@ -386,7 +377,7 @@ class CORE_EXPORT Page final : public GarbageCollectedFinalized<Page>,
float device_scale_factor_;
- mojom::PageVisibilityState visibility_state_;
+ bool is_hidden_;
PageLifecycleState page_lifecycle_state_;
diff --git a/chromium/third_party/blink/renderer/core/page/page_visibility_state.cc b/chromium/third_party/blink/renderer/core/page/page_hidden_state.cc
index 0de7a1aa4f5..614cd2c6437 100644
--- a/chromium/third_party/blink/renderer/core/page/page_visibility_state.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_hidden_state.cc
@@ -28,23 +28,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "third_party/blink/renderer/core/page/page_visibility_state.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/core/page/page_hidden_state.h"
namespace blink {
-String PageVisibilityStateString(mojom::PageVisibilityState state) {
- switch (state) {
- case mojom::PageVisibilityState::kVisible:
- return "visible";
- case mojom::PageVisibilityState::kHidden:
- return "hidden";
- case mojom::PageVisibilityState::kPrerender:
- return "prerender";
- }
-
- NOTREACHED();
- return String();
+String PageHiddenStateString(bool hidden) {
+ if (hidden)
+ return "hidden";
+ return "visible";
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/page_visibility_state.h b/chromium/third_party/blink/renderer/core/page/page_hidden_state.h
index aa0fd6e5009..d66d39a40af 100644
--- a/chromium/third_party/blink/renderer/core/page/page_visibility_state.h
+++ b/chromium/third_party/blink/renderer/core/page/page_hidden_state.h
@@ -28,17 +28,16 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_VISIBILITY_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_VISIBILITY_STATE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_HIDDEN_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_HIDDEN_STATE_H_
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-CORE_EXPORT String PageVisibilityStateString(mojom::PageVisibilityState);
+CORE_EXPORT String PageHiddenStateString(bool visible);
} // namespace blink
-#endif // ifndef PageVisibilityState_h
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_HIDDEN_STATE_H_
diff --git a/chromium/third_party/blink/renderer/core/page/page_overlay.cc b/chromium/third_party/blink/renderer/core/page/page_overlay.cc
deleted file mode 100644
index 4be198a3b8a..00000000000
--- a/chromium/third_party/blink/renderer/core/page/page_overlay.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
- * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/page/page_overlay.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "cc/layers/picture_layer.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer_client.h"
-#include "third_party/blink/renderer/platform/scroll/main_thread_scrolling_reason.h"
-
-namespace blink {
-
-std::unique_ptr<PageOverlay> PageOverlay::Create(
- LocalFrame* local_frame,
- std::unique_ptr<PageOverlay::Delegate> delegate) {
- return base::WrapUnique(new PageOverlay(local_frame, std::move(delegate)));
-}
-
-PageOverlay::PageOverlay(LocalFrame* local_frame,
- std::unique_ptr<PageOverlay::Delegate> delegate)
- : frame_(local_frame), delegate_(std::move(delegate)) {}
-
-PageOverlay::~PageOverlay() {
- if (!layer_)
- return;
- layer_->RemoveFromParent();
- layer_ = nullptr;
-}
-
-void PageOverlay::Update() {
- if (!frame_)
- return;
-
- auto* local_root_frame_widget =
- WebLocalFrameImpl::FromFrame(frame_)->LocalRootFrameWidget();
- if (!local_root_frame_widget->IsAcceleratedCompositingActive())
- return;
-
- if (!layer_) {
- GraphicsLayer* parent_layer =
- frame_->IsMainFrame()
- ? frame_->GetPage()->GetVisualViewport().ContainerLayer()
- : local_root_frame_widget->RootGraphicsLayer();
- if (!parent_layer)
- return;
-
- layer_ = GraphicsLayer::Create(*this);
- layer_->SetDrawsContent(true);
- parent_layer->AddChild(layer_.get());
-
- // This is required for contents of overlay to stay in sync with the page
- // while scrolling.
- cc::Layer* cc_layer = layer_->CcLayer();
- cc_layer->AddMainThreadScrollingReasons(
- MainThreadScrollingReason::kPageOverlay);
-
- layer_->SetLayerState(PropertyTreeState(PropertyTreeState::Root()),
- IntPoint());
- }
-
- gfx::Size size(frame_->GetPage()->GetVisualViewport().Size());
- if (size != layer_->Size())
- layer_->SetSize(size);
-
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
- layer_->SetNeedsDisplay();
-}
-
-LayoutRect PageOverlay::VisualRect() const {
- DCHECK(layer_.get());
- return LayoutRect(IntPoint(), IntSize(layer_->Size()));
-}
-
-IntRect PageOverlay::ComputeInterestRect(const GraphicsLayer* graphics_layer,
- const IntRect&) const {
- return IntRect(IntPoint(), IntSize(layer_->Size()));
-}
-
-void PageOverlay::PaintContents(const GraphicsLayer* graphics_layer,
- GraphicsContext& gc,
- GraphicsLayerPaintingPhase phase,
- const IntRect& interest_rect) const {
- DCHECK(layer_);
- delegate_->PaintPageOverlay(*this, gc, interest_rect.Size());
-}
-
-String PageOverlay::DebugName(const GraphicsLayer*) const {
- return "Page Overlay Content Layer";
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/page_overlay_test.cc b/chromium/third_party/blink/renderer/core/page/page_overlay_test.cc
deleted file mode 100644
index 08ce4c6159a..00000000000
--- a/chromium/third_party/blink/renderer/core/page/page_overlay_test.cc
+++ /dev/null
@@ -1,151 +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 "third_party/blink/renderer/core/page/page_overlay.h"
-
-#include <memory>
-
-#include "base/time/time.h"
-#include "cc/paint/paint_canvas.h"
-#include "cc/trees/layer_tree_host.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/web/web_settings.h"
-#include "third_party/blink/renderer/core/exported/web_view_impl.h"
-#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPaint.h"
-
-using testing::_;
-using testing::AtLeast;
-using testing::Property;
-
-namespace blink {
-namespace {
-
-static const int kViewportWidth = 800;
-static const int kViewportHeight = 600;
-
-// These unit tests cover both PageOverlay and PageOverlayList.
-
-// PageOverlay that paints a solid color.
-class SolidColorOverlay : public PageOverlay::Delegate {
- public:
- SolidColorOverlay(Color color) : color_(color) {}
-
- void PaintPageOverlay(const PageOverlay& page_overlay,
- GraphicsContext& graphics_context,
- const IntSize& size) const override {
- if (DrawingRecorder::UseCachedDrawingIfPossible(
- graphics_context, page_overlay, DisplayItem::kPageOverlay))
- return;
- FloatRect rect(0, 0, size.Width(), size.Height());
- DrawingRecorder recorder(graphics_context, page_overlay,
- DisplayItem::kPageOverlay);
- graphics_context.FillRect(rect, color_);
- }
-
- private:
- Color color_;
-};
-
-class PageOverlayTest : public testing::Test {
- protected:
- PageOverlayTest() {
- helper_.Initialize(nullptr /* web_frame_client */,
- nullptr /* web_view_client */,
- nullptr /* web_widget_client */);
- GetWebView()->Resize(WebSize(kViewportWidth, kViewportHeight));
- GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
- }
-
- WebViewImpl* GetWebView() const { return helper_.GetWebView(); }
-
- std::unique_ptr<PageOverlay> CreateSolidYellowOverlay() {
- return PageOverlay::Create(
- GetWebView()->MainFrameImpl()->GetFrame(),
- std::make_unique<SolidColorOverlay>(SK_ColorYELLOW));
- }
-
- void SetViewportSize(const WebSize& size) {
- content::LayerTreeView* layer_tree_view = helper_.GetLayerTreeView();
- layer_tree_view->SetViewportSizeAndScale(
- static_cast<gfx::Size>(size), /*device_scale_factor=*/1.f,
- layer_tree_view->layer_tree_host()
- ->local_surface_id_allocation_from_parent());
- }
-
- template <typename OverlayType>
- void RunPageOverlayTestWithAcceleratedCompositing();
-
- private:
- frame_test_helpers::WebViewHelper helper_;
-};
-
-template <bool (*getter)(), void (*setter)(bool)>
-class RuntimeFeatureChange {
- public:
- RuntimeFeatureChange(bool new_value) : old_value_(getter()) {
- setter(new_value);
- }
- ~RuntimeFeatureChange() { setter(old_value_); }
-
- private:
- bool old_value_;
-};
-
-class MockPageOverlayCanvas : public SkCanvas {
- public:
- MockPageOverlayCanvas(int width, int height) : SkCanvas(width, height) {}
- MOCK_METHOD2(onDrawRect, void(const SkRect&, const SkPaint&));
-};
-
-TEST_F(PageOverlayTest, PageOverlay_AcceleratedCompositing) {
- SetViewportSize(WebSize(kViewportWidth, kViewportHeight));
-
- std::unique_ptr<PageOverlay> page_overlay = CreateSolidYellowOverlay();
- page_overlay->Update();
- GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
-
- GraphicsLayer* graphics_layer = page_overlay->GetGraphicsLayer();
- WebRect rect(0, 0, kViewportWidth, kViewportHeight);
-
- IntRect int_rect = rect;
- graphics_layer->Paint(&int_rect);
-
- // Ideally, we would get results from the compositor that showed that this
- // page overlay actually winds up getting drawn on top of the rest.
- // For now, we just check that the GraphicsLayer will draw the right thing.
- MockPageOverlayCanvas canvas(kViewportWidth, kViewportHeight);
- EXPECT_CALL(canvas, onDrawRect(_, _)).Times(AtLeast(0));
- EXPECT_CALL(canvas,
- onDrawRect(SkRect::MakeWH(kViewportWidth, kViewportHeight),
- Property(&SkPaint::getColor, SK_ColorYELLOW)));
- canvas.drawPicture(
- ToSkPicture(graphics_layer->CapturePaintRecord(), int_rect));
-}
-
-TEST_F(PageOverlayTest, PageOverlay_VisualRect) {
- std::unique_ptr<PageOverlay> page_overlay = CreateSolidYellowOverlay();
- page_overlay->Update();
- GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
- EXPECT_EQ(LayoutRect(0, 0, kViewportWidth, kViewportHeight),
- page_overlay->VisualRect());
-}
-
-} // namespace
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/page_popup_client.h b/chromium/third_party/blink/renderer/core/page/page_popup_client.h
index 3803e555a6b..b220c65f3e6 100644
--- a/chromium/third_party/blink/renderer/core/page/page_popup_client.h
+++ b/chromium/third_party/blink/renderer/core/page/page_popup_client.h
@@ -72,7 +72,7 @@ class CORE_EXPORT PagePopupClient {
virtual void SetValue(const String&) = 0;
// This is called by the content HTML of a PagePopup.
- virtual void ClosePopup() = 0;
+ virtual void CancelPopup() = 0;
// This is called whenever a PagePopup was closed.
virtual void DidClosePopup() = 0;
diff --git a/chromium/third_party/blink/renderer/core/page/page_popup_controller.cc b/chromium/third_party/blink/renderer/core/page/page_popup_controller.cc
index fa7fceee5b1..ab6c8bb1cdc 100644
--- a/chromium/third_party/blink/renderer/core/page/page_popup_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_popup_controller.cc
@@ -61,7 +61,7 @@ void PagePopupController::setValue(const String& value) {
void PagePopupController::closePopup() {
if (popup_client_)
- popup_client_->ClosePopup();
+ popup_client_->CancelPopup();
}
void PagePopupController::selectFontsFromOwnerDocument(
diff --git a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
index 56f1a47f997..50d836f5c75 100644
--- a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
@@ -40,6 +40,7 @@
#include "third_party/blink/renderer/core/layout/jank_tracker.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/autoscroll_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
@@ -73,17 +74,13 @@ void PageWidgetDelegate::UpdateLifecycle(
}
}
-static void PaintContentInternal(Page& page,
- cc::PaintCanvas* canvas,
- const WebRect& rect,
- LocalFrame& root,
- const GlobalPaintFlags global_paint_flags) {
+void PageWidgetDelegate::PaintContent(cc::PaintCanvas* canvas,
+ const WebRect& rect,
+ LocalFrame& root) {
if (rect.IsEmpty())
return;
- // FIXME: device scale factor settings are layering violations and should
- // not be used within Blink paint code.
- float scale_factor = page.DeviceScaleFactorDeprecated();
+ float scale_factor = root.DevicePixelRatio();
canvas->save();
canvas->scale(scale_factor, scale_factor);
@@ -96,8 +93,8 @@ static void PaintContentInternal(Page& page,
PaintRecordBuilder builder;
builder.Context().SetDeviceScaleFactor(scale_factor);
- view->PaintWithLifecycleUpdate(builder.Context(), global_paint_flags,
- CullRect(dirty_rect));
+ view->PaintOutsideOfLifecycle(builder.Context(), kGlobalPaintNormalPhase,
+ CullRect(dirty_rect));
builder.EndRecording(
*canvas,
view->GetLayoutView()->FirstFragment().LocalBorderBoxProperties());
@@ -110,22 +107,6 @@ static void PaintContentInternal(Page& page,
canvas->restore();
}
-void PageWidgetDelegate::PaintContent(Page& page,
- cc::PaintCanvas* canvas,
- const WebRect& rect,
- LocalFrame& root) {
- PaintContentInternal(page, canvas, rect, root, kGlobalPaintNormalPhase);
-}
-
-void PageWidgetDelegate::PaintContentIgnoringCompositing(
- Page& page,
- cc::PaintCanvas* canvas,
- const WebRect& rect,
- LocalFrame& root) {
- PaintContentInternal(page, canvas, rect, root,
- kGlobalPaintFlattenCompositingLayers);
-}
-
WebInputEventResult PageWidgetDelegate::HandleInputEvent(
PageWidgetEventHandler& handler,
const WebCoalescedInputEvent& coalesced_event,
@@ -143,7 +124,7 @@ WebInputEventResult PageWidgetDelegate::HandleInputEvent(
if (interactive_detector)
interactive_detector->HandleForInputDelay(event);
- if (RuntimeEnabledFeatures::JankTrackingEnabled()) {
+ if (origin_trials::JankTrackingEnabled(document)) {
if (LocalFrameView* view = document->View())
view->GetJankTracker().NotifyInput(event);
}
diff --git a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h
index 9d6e0edc761..926e97e2b9a 100644
--- a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h
+++ b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h
@@ -86,14 +86,7 @@ class CORE_EXPORT PageWidgetDelegate {
WebWidget::LifecycleUpdateReason reason);
// See documents of methods with the same names in FrameView class.
- static void PaintContent(Page&,
- cc::PaintCanvas*,
- const WebRect&,
- LocalFrame& root);
- static void PaintContentIgnoringCompositing(Page&,
- cc::PaintCanvas*,
- const WebRect&,
- LocalFrame& root);
+ static void PaintContent(cc::PaintCanvas*, const WebRect&, LocalFrame& root);
// See FIXME in the function body about nullptr |root|.
static WebInputEventResult HandleInputEvent(
PageWidgetEventHandler&,
diff --git a/chromium/third_party/blink/renderer/core/page/print_context.h b/chromium/third_party/blink/renderer/core/page/print_context.h
index a1aa1667a8b..fdceab55c6a 100644
--- a/chromium/third_party/blink/renderer/core/page/print_context.h
+++ b/chromium/third_party/blink/renderer/core/page/print_context.h
@@ -85,7 +85,7 @@ class CORE_EXPORT PrintContext
// Return to screen mode.
virtual void EndPrintMode();
- // The following static methods are used by layout tests:
+ // The following static methods are used by web tests:
// Returns -1 if page isn't found.
static int PageNumberForElement(Element*,
diff --git a/chromium/third_party/blink/renderer/core/page/print_context_test.cc b/chromium/third_party/blink/renderer/core/page/print_context_test.cc
index 6633f491555..2072557f85a 100644
--- a/chromium/third_party/blink/renderer/core/page/print_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/print_context_test.cc
@@ -91,8 +91,8 @@ class PrintContextTest : public PaintTestConfigurations, public RenderingTest {
PaintRecordBuilder builder;
GraphicsContext& context = builder.Context();
context.SetPrinting(true);
- GetDocument().View()->PaintContents(context, kGlobalPaintPrinting,
- page_rect);
+ GetDocument().View()->PaintContentsOutsideOfLifecycle(
+ context, kGlobalPaintPrinting, CullRect(page_rect));
{
DrawingRecorder recorder(
context, *GetDocument().GetLayoutView(),
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
new file mode 100644
index 00000000000..993d6fc5370
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
@@ -0,0 +1,242 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
+
+#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/scroll_into_view_options.h"
+#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+namespace {
+
+constexpr char kCssFragmentIdentifierPrefix[] = "targetElement=";
+constexpr size_t kCssFragmentIdentifierPrefixLength =
+ base::size(kCssFragmentIdentifierPrefix);
+
+bool ParseCSSFragmentIdentifier(const String& fragment, String* selector) {
+ size_t pos = fragment.Find(kCssFragmentIdentifierPrefix);
+ if (pos == 0) {
+ *selector = fragment.Substring(kCssFragmentIdentifierPrefixLength - 1);
+ return true;
+ }
+
+ return false;
+}
+
+Element* FindCSSFragmentAnchor(const AtomicString& selector,
+ Document& document) {
+ DummyExceptionStateForTesting exception_state;
+ return document.QuerySelector(selector, exception_state);
+}
+
+Node* FindAnchorFromFragment(const String& fragment, Document& doc) {
+ Element* anchor_node;
+ String selector;
+ if (RuntimeEnabledFeatures::CSSFragmentIdentifiersEnabled() &&
+ ParseCSSFragmentIdentifier(fragment, &selector)) {
+ anchor_node = FindCSSFragmentAnchor(AtomicString(selector), doc);
+ } else {
+ anchor_node = doc.FindAnchor(fragment);
+ }
+
+ // Implement the rule that "" and "top" both mean top of page as in other
+ // browsers.
+ if (!anchor_node &&
+ (fragment.IsEmpty() || DeprecatedEqualIgnoringCase(fragment, "top")))
+ return &doc;
+
+ return anchor_node;
+}
+
+} // namespace
+
+FragmentAnchor* FragmentAnchor::TryCreate(const KURL& url,
+ bool needs_invoke,
+ LocalFrame& frame) {
+ DCHECK(frame.GetDocument());
+ Document& doc = *frame.GetDocument();
+
+ // If our URL has no ref, then we have no place we need to jump to.
+ // OTOH If CSS target was set previously, we want to set it to 0, recalc
+ // and possibly paint invalidation because :target pseudo class may have been
+ // set (see bug 11321).
+ // Similarly for svg, if we had a previous svgView() then we need to reset
+ // the initial view if we don't have a fragment.
+ if (!url.HasFragmentIdentifier() && !doc.CssTarget() && !doc.IsSVGDocument())
+ return nullptr;
+
+ String fragment = url.FragmentIdentifier();
+
+ Node* anchor_node = nullptr;
+
+ // Try the raw fragment for HTML documents, but skip it for `svgView()`:
+ if (!doc.IsSVGDocument())
+ anchor_node = FindAnchorFromFragment(fragment, doc);
+
+ // https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-indicated-part-of-the-document
+ // 5. Let decodedFragment be the result of running UTF-8 decode without BOM
+ // on fragmentBytes.
+ if (!anchor_node) {
+ fragment = DecodeURLEscapeSequences(fragment, DecodeURLMode::kUTF8);
+ anchor_node = FindAnchorFromFragment(fragment, doc);
+ }
+
+ // Setting to null will clear the current target.
+ Element* target = anchor_node && anchor_node->IsElementNode()
+ ? ToElement(anchor_node)
+ : nullptr;
+ doc.SetCSSTarget(target);
+
+ if (doc.IsSVGDocument()) {
+ if (SVGSVGElement* svg = ToSVGSVGElementOrNull(doc.documentElement()))
+ svg->SetupInitialView(fragment, target);
+ }
+
+ if (target)
+ target->DispatchActivateInvisibleEventIfNeeded();
+
+ if (doc.IsSVGDocument() && !frame.IsMainFrame())
+ return nullptr;
+
+ if (!anchor_node || !needs_invoke)
+ return nullptr;
+
+ auto* anchor = MakeGarbageCollected<FragmentAnchor>(*anchor_node, frame);
+
+ // If rendering isn't ready yet, we'll focus and scroll as part of the
+ // document lifecycle.
+ if (doc.IsRenderingReady()) {
+ anchor->ApplyFocusIfNeeded();
+
+ // Layout needs to be clean for scrolling but if layout is needed, we'll
+ // invoke after layout is completed so no need to do it here. Note, the
+ // view may have been detached by script run during focus() call.
+ if (frame.View() && !frame.View()->NeedsLayout())
+ anchor->Invoke();
+ }
+
+ return anchor;
+}
+
+FragmentAnchor::FragmentAnchor(Node& anchor_node, LocalFrame& frame)
+ : anchor_node_(&anchor_node),
+ frame_(&frame),
+ needs_focus_(!anchor_node.IsDocumentNode()) {
+ DCHECK(frame_->View());
+}
+
+bool FragmentAnchor::Invoke() {
+ if (!frame_ || !anchor_node_)
+ return false;
+
+ // Don't remove the fragment anchor until focus has been applied.
+ if (!needs_invoke_)
+ return needs_focus_;
+
+ Document& doc = *frame_->GetDocument();
+
+ if (!doc.IsRenderingReady() || !frame_->View())
+ return true;
+
+ Frame* boundary_frame = frame_->FindUnsafeParentScrollPropagationBoundary();
+
+ // FIXME: Handle RemoteFrames
+ if (boundary_frame && boundary_frame->IsLocalFrame()) {
+ ToLocalFrame(boundary_frame)
+ ->View()
+ ->SetSafeToPropagateScrollToParent(false);
+ }
+
+ Element* element_to_scroll = anchor_node_->IsElementNode()
+ ? ToElement(anchor_node_)
+ : doc.documentElement();
+ if (element_to_scroll) {
+ ScrollIntoViewOptions* options = ScrollIntoViewOptions::Create();
+ options->setBlock("start");
+ options->setInlinePosition("nearest");
+ element_to_scroll->ScrollIntoViewNoVisualUpdate(options);
+ }
+
+ if (boundary_frame && boundary_frame->IsLocalFrame()) {
+ ToLocalFrame(boundary_frame)
+ ->View()
+ ->SetSafeToPropagateScrollToParent(true);
+ }
+
+ if (AXObjectCache* cache = doc.ExistingAXObjectCache())
+ cache->HandleScrolledToAnchor(anchor_node_);
+
+ // Scroll into view above will cause us to clear needs_invoke_ via the
+ // DidScroll so recompute it here.
+ needs_invoke_ = !doc.IsLoadCompleted() || needs_focus_;
+
+ return needs_invoke_;
+}
+
+void FragmentAnchor::DidScroll(ScrollType type) {
+ if (!IsExplicitScrollType(type))
+ return;
+
+ // If the user/page scrolled, avoid clobbering the scroll offset by removing
+ // the anchor on the next invocation. Note: we may get here as a result of
+ // calling Invoke() because of the ScrollIntoView but that's ok because
+ // needs_invoke_ is recomputed at the end of that method.
+ needs_invoke_ = false;
+}
+
+void FragmentAnchor::DidCompleteLoad() {
+ DCHECK(frame_);
+ DCHECK(frame_->View());
+
+ // If there is a pending layout, the fragment anchor will be cleared when it
+ // finishes.
+ if (!frame_->View()->NeedsLayout())
+ needs_invoke_ = false;
+}
+
+void FragmentAnchor::Trace(blink::Visitor* visitor) {
+ visitor->Trace(anchor_node_);
+ visitor->Trace(frame_);
+}
+
+void FragmentAnchor::PerformPreRafActions() {
+ ApplyFocusIfNeeded();
+}
+
+void FragmentAnchor::ApplyFocusIfNeeded() {
+ // SVG images can load synchronously during style recalc but it's ok to focus
+ // since we disallow scripting. For everything else, focus() could run script
+ // so make sure we're at a valid point to do so.
+ DCHECK(frame_->GetDocument()->IsSVGDocument() ||
+ !ScriptForbiddenScope::IsScriptForbidden());
+
+ if (!needs_focus_)
+ return;
+
+ if (!frame_->GetDocument()->IsRenderingReady())
+ return;
+
+ // If the anchor accepts keyboard focus and fragment scrolling is allowed,
+ // move focus there to aid users relying on keyboard navigation.
+ // If anchorNode is not focusable or fragment scrolling is not allowed,
+ // clear focus, which matches the behavior of other browsers.
+ frame_->GetDocument()->UpdateStyleAndLayoutTree();
+ if (anchor_node_->IsElementNode() && ToElement(anchor_node_)->IsFocusable()) {
+ ToElement(anchor_node_)->focus();
+ } else {
+ frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint(
+ anchor_node_);
+ frame_->GetDocument()->ClearFocusedElement();
+ }
+ needs_focus_ = false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h
new file mode 100644
index 00000000000..32ee9d16142
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h
@@ -0,0 +1,77 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_FRAGMENT_ANCHOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_FRAGMENT_ANCHOR_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
+
+namespace blink {
+
+class LocalFrame;
+class KURL;
+
+// This class encapsulates the behavior of a "fragment anchor". A fragment
+// anchor allows a page to link to a specific part of a page by specifying an
+// element id in the URL fragment. The fragment is the part after the '#'
+// character. E.g. navigating to www.example.com/index.html#section3 will find
+// the element with id "section3" and focus and scroll it into view.
+//
+// While the page is loading, the fragment anchor tries to repeatedly scroll
+// the element into view since it's position may change as a result of layouts.
+// TODO(bokan): Maybe we no longer need the repeated scrolling since that
+// should be handled by scroll-anchoring?
+class CORE_EXPORT FragmentAnchor : public GarbageCollected<FragmentAnchor> {
+ public:
+ // Parses the fragment string and tries to create a FragmentAnchor object. If
+ // an appropriate target was found based on the given fragment, this method
+ // will create and return a FragmentAnchor object that can be used to keep it
+ // in view. Otherwise, this will return nullptr. In either case,
+ // side-effects on the document will be performed, for example,
+ // setting/clearing :target and svgView(). If needs_invoke is false, only the
+ // side effects will be performed, the element won't be scrolled/focused and
+ // this method returns nullptr (e.g. used during history navigation where we
+ // don't want to clobber the history scroll restoration).
+ static FragmentAnchor* TryCreate(const KURL& url,
+ bool needs_invoke,
+ LocalFrame& frame);
+
+ FragmentAnchor(Node& anchor_node, LocalFrame& frame);
+ virtual ~FragmentAnchor() = default;
+
+ // Invoking the fragment anchor scrolls it into view and performs any other
+ // desired actions. This is called repeatedly during loading as the lifecycle
+ // is updated to keep the element in view. If true, the anchor should be kept
+ // alive and invoked again. Otherwise it may be disposed.
+ bool Invoke();
+
+ // Used to let the fragment know the frame's been scrolled and so we should
+ // abort keeping the fragment target in view to avoid fighting with user
+ // scrolls.
+ void DidScroll(ScrollType type);
+
+ void PerformPreRafActions();
+
+ void DidCompleteLoad();
+
+ void Trace(blink::Visitor*);
+
+ private:
+ void ApplyFocusIfNeeded();
+
+ WeakMember<Node> anchor_node_;
+ Member<LocalFrame> frame_;
+ bool needs_focus_;
+
+ // While this is true, the fragment is still "active" in the sense that we
+ // want the owner to continue calling Invoke(). Once this is false, calling
+ // Invoke has no effect and the fragment can be disposed.
+ bool needs_invoke_ = true;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_FRAGMENT_ANCHOR_H_
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc
new file mode 100644
index 00000000000..022d8ba5ad7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/web/web_script_source.h"
+#include "third_party/blink/renderer/core/css/css_style_declaration.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/html/html_anchor_element.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/page/focus_controller.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+namespace {
+
+using test::RunPendingTasks;
+
+class FragmentAnchorTest : public SimTest {};
+
+// Ensure that the focus event handler is run before the rAF callback. We'll
+// change the background color from a rAF set in the focus handler and make
+// sure the computed background color of that frame was changed. See:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/5BJSTl-FMGY/JMtaKqGhBAAJ
+TEST_F(FragmentAnchorTest, FocusHandlerRunBeforeRaf) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ SimSubresourceRequest css_resource("https://example.com/sheet.css",
+ "text/css");
+ LoadURL("https://example.com/test.html");
+
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ background-color: red;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" href="sheet.css">
+ <a id="anchorlink" href="#bottom">Link to bottom of the page</a>
+ <div style="height: 1000px;"></div>
+ <input id="bottom">Bottom of the page</input>
+ )HTML");
+
+ MainFrame().ExecuteScript(WebScriptSource(R"HTML(
+ document.getElementById("bottom").addEventListener('focus', () => {
+ requestAnimationFrame(() => {
+ document.body.style.backgroundColor = '#00FF00';
+ });
+ });
+ )HTML"));
+
+ // Focus handlers aren't run unless the page is focused.
+ GetDocument().GetPage()->GetFocusController().SetFocused(true);
+
+ // We're still waiting on the stylesheet to load so the load event shouldn't
+ // yet dispatch and rendering is deferred.
+ ASSERT_FALSE(GetDocument().IsRenderingReady());
+ ASSERT_FALSE(GetDocument().IsLoadCompleted());
+
+ // Click on the anchor element. This will cause a synchronous same-document
+ // navigation.
+ HTMLAnchorElement* anchor =
+ ToHTMLAnchorElement(GetDocument().getElementById("anchorlink"));
+ anchor->click();
+ ASSERT_EQ(GetDocument().body(), GetDocument().ActiveElement())
+ << "Active element changed while rendering is blocked";
+
+ // Complete the CSS stylesheet load so the document can finish loading. The
+ // fragment should be activated at that point.
+ css_resource.Complete("");
+ Compositor().BeginFrame();
+
+ ASSERT_FALSE(GetDocument().IsLoadCompleted());
+ ASSERT_TRUE(GetDocument().IsRenderingReady());
+ ASSERT_EQ(GetDocument().getElementById("bottom"),
+ GetDocument().ActiveElement())
+ << "Active element wasn't changed after rendering was unblocked.";
+ EXPECT_EQ(GetDocument()
+ .body()
+ ->GetLayoutObject()
+ ->Style()
+ ->VisitedDependentColor(GetCSSPropertyBackgroundColor())
+ .NameForLayoutTreeAsText(),
+ Color(0, 255, 0).NameForLayoutTreeAsText());
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
new file mode 100644
index 00000000000..0ad8b4b8c77
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -0,0 +1,555 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/picture_layer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/html/html_iframe_element.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+
+namespace blink {
+
+class MainThreadScrollingReasonsTest
+ : public testing::Test,
+ public testing::WithParamInterface<bool>,
+ private ScopedBlinkGenPropertyTreesForTest {
+ public:
+ MainThreadScrollingReasonsTest()
+ : ScopedBlinkGenPropertyTreesForTest(GetParam()),
+ base_url_("http://www.test.com/") {
+ helper_.InitializeWithSettings(&ConfigureSettings);
+ GetWebView()->MainFrameWidget()->Resize(IntSize(320, 240));
+
+ // macOS attaches main frame scrollbars to the VisualViewport so the
+ // VisualViewport layers need to be initialized.
+ GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
+ WebWidget::LifecycleUpdateReason::kTest);
+ WebFrameWidgetBase* main_frame_widget =
+ GetWebView()->MainFrameImpl()->FrameWidgetImpl();
+ main_frame_widget->SetRootGraphicsLayer(GetWebView()
+ ->MainFrameImpl()
+ ->GetFrame()
+ ->View()
+ ->GetLayoutView()
+ ->Compositor()
+ ->RootGraphicsLayer());
+ }
+
+ ~MainThreadScrollingReasonsTest() override {
+ Platform::Current()
+ ->GetURLLoaderMockFactory()
+ ->UnregisterAllURLsAndClearMemoryCache();
+ }
+
+ void NavigateTo(const std::string& url) {
+ frame_test_helpers::LoadFrame(GetWebView()->MainFrameImpl(), url);
+ }
+
+ void LoadHTML(const std::string& html) {
+ frame_test_helpers::LoadHTMLString(GetWebView()->MainFrameImpl(), html,
+ url_test_helpers::ToKURL("about:blank"));
+ }
+
+ void ForceFullCompositingUpdate() {
+ GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
+ WebWidget::LifecycleUpdateReason::kTest);
+ }
+
+ void RegisterMockedHttpURLLoad(const std::string& file_name) {
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url_), test::CoreTestDataPath(),
+ WebString::FromUTF8(file_name));
+ }
+
+ uint32_t GetViewMainThreadScrollingReasons() const {
+ // Pre-BlinkGenPropertyTrees, main thread scrolling reasons are set on
+ // cc::Layer in ScrollingCoordinator.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ auto* layer = GetFrame()->View()->LayoutViewport()->LayerForScrolling();
+ return layer->CcLayer()->GetMainThreadScrollingReasons();
+ }
+ // With BlinkGenPropertyTrees, main thread scrolling reasons are calculated
+ // in the blink property tree builder and set on set on scroll nodes.
+ const auto* scroll = GetFrame()
+ ->View()
+ ->GetLayoutView()
+ ->FirstFragment()
+ .PaintProperties()
+ ->Scroll();
+ return scroll->GetMainThreadScrollingReasons();
+ }
+
+ WebViewImpl* GetWebView() const { return helper_.GetWebView(); }
+ LocalFrame* GetFrame() const { return helper_.LocalMainFrame()->GetFrame(); }
+
+ protected:
+ std::string base_url_;
+
+ private:
+ static void ConfigureSettings(WebSettings* settings) {
+ settings->SetPreferCompositingToLCDTextEnabled(true);
+ }
+
+ frame_test_helpers::WebViewHelper helper_;
+};
+
+INSTANTIATE_TEST_CASE_P(All, MainThreadScrollingReasonsTest, testing::Bool());
+
+
+TEST_P(MainThreadScrollingReasonsTest,
+ CustomScrollbarShouldTriggerMainThreadScroll) {
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
+ GetWebView()->SetDeviceScaleFactor(2.f);
+ RegisterMockedHttpURLLoad("custom_scrollbar.html");
+ NavigateTo(base_url_ + "custom_scrollbar.html");
+ ForceFullCompositingUpdate();
+
+ Document* document = GetFrame()->GetDocument();
+ Element* container = document->getElementById("container");
+ Element* content = document->getElementById("content");
+ DCHECK_EQ(container->getAttribute(html_names::kClassAttr),
+ "custom_scrollbar");
+ DCHECK(container);
+ DCHECK(content);
+
+ LayoutObject* layout_object = container->GetLayoutObject();
+ ASSERT_TRUE(layout_object->IsBox());
+ LayoutBox* box = ToLayoutBox(layout_object);
+ ASSERT_TRUE(box->UsesCompositedScrolling());
+ CompositedLayerMapping* composited_layer_mapping =
+ box->Layer()->GetCompositedLayerMapping();
+ // When Blink generates property trees, the main thread reasons are stored in
+ // scroll nodes instead of being set on the custom scrollbar layer, so we use
+ // the scrolling contents layer to access the main thread scrolling reasons.
+ GraphicsLayer* layer =
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()
+ ? composited_layer_mapping->ScrollingContentsLayer()
+ : composited_layer_mapping->LayerForVerticalScrollbar();
+ ASSERT_TRUE(layer);
+ EXPECT_TRUE(layer->CcLayer()->GetMainThreadScrollingReasons());
+ EXPECT_TRUE(layer->CcLayer()->GetMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kCustomScrollbarScrolling);
+
+ // remove custom scrollbar class, the scrollbar is expected to scroll on
+ // impl thread as it is an overlay scrollbar.
+ container->removeAttribute("class");
+ ForceFullCompositingUpdate();
+ layer = RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()
+ ? composited_layer_mapping->ScrollingContentsLayer()
+ : composited_layer_mapping->LayerForVerticalScrollbar();
+ EXPECT_FALSE(layer->CcLayer()->GetMainThreadScrollingReasons());
+ EXPECT_FALSE(layer->CcLayer()->GetMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kCustomScrollbarScrolling);
+}
+
+TEST_P(MainThreadScrollingReasonsTest,
+ BackgroundAttachmentFixedShouldTriggerMainThreadScroll) {
+ RegisterMockedHttpURLLoad("iframe-background-attachment-fixed.html");
+ RegisterMockedHttpURLLoad("iframe-background-attachment-fixed-inner.html");
+ RegisterMockedHttpURLLoad("white-1x1.png");
+ NavigateTo(base_url_ + "iframe-background-attachment-fixed.html");
+ ForceFullCompositingUpdate();
+
+ Element* iframe = GetFrame()->GetDocument()->getElementById("iframe");
+ ASSERT_TRUE(iframe);
+
+ LayoutObject* layout_object = iframe->GetLayoutObject();
+ ASSERT_TRUE(layout_object);
+ ASSERT_TRUE(layout_object->IsLayoutEmbeddedContent());
+
+ LayoutEmbeddedContent* layout_embedded_content =
+ ToLayoutEmbeddedContent(layout_object);
+ ASSERT_TRUE(layout_embedded_content);
+
+ LocalFrameView* inner_frame_view =
+ ToLocalFrameView(layout_embedded_content->ChildFrameView());
+ ASSERT_TRUE(inner_frame_view);
+
+ auto* inner_layout_view = inner_frame_view->GetLayoutView();
+ ASSERT_TRUE(inner_layout_view);
+
+ PaintLayerCompositor* inner_compositor = inner_layout_view->Compositor();
+ ASSERT_TRUE(inner_compositor->InCompositingMode());
+
+ GraphicsLayer* scroll_layer =
+ inner_frame_view->LayoutViewport()->LayerForScrolling();
+ ASSERT_TRUE(scroll_layer);
+
+ cc::Layer* cc_scroll_layer = scroll_layer->CcLayer();
+ ASSERT_TRUE(cc_scroll_layer->scrollable());
+ ASSERT_TRUE(cc_scroll_layer->GetMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
+
+ // Remove fixed background-attachment should make the iframe
+ // scroll on cc.
+ auto* iframe_doc = ToHTMLIFrameElement(iframe)->contentDocument();
+ iframe = iframe_doc->getElementById("scrollable");
+ ASSERT_TRUE(iframe);
+
+ iframe->removeAttribute("class");
+ ForceFullCompositingUpdate();
+
+ layout_object = iframe->GetLayoutObject();
+ ASSERT_TRUE(layout_object);
+
+ scroll_layer =
+ layout_object->GetFrameView()->LayoutViewport()->LayerForScrolling();
+ ASSERT_TRUE(scroll_layer);
+
+ cc_scroll_layer = scroll_layer->CcLayer();
+ ASSERT_TRUE(cc_scroll_layer->scrollable());
+ ASSERT_FALSE(cc_scroll_layer->GetMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
+
+ // Force main frame to scroll on main thread. All its descendants
+ // should scroll on main thread as well.
+ Element* element = GetFrame()->GetDocument()->getElementById("scrollable");
+ element->setAttribute(
+ "style",
+ "background-image: url('white-1x1.png'); background-attachment: fixed;",
+ ASSERT_NO_EXCEPTION);
+
+ ForceFullCompositingUpdate();
+
+ layout_object = iframe->GetLayoutObject();
+ ASSERT_TRUE(layout_object);
+
+ scroll_layer =
+ layout_object->GetFrameView()->LayoutViewport()->LayerForScrolling();
+ ASSERT_TRUE(scroll_layer);
+
+ cc_scroll_layer = scroll_layer->CcLayer();
+ ASSERT_TRUE(cc_scroll_layer->scrollable());
+ ASSERT_TRUE(cc_scroll_layer->GetMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
+}
+
+// Upon resizing the content size, the main thread scrolling reason
+// kHasNonLayerViewportConstrainedObject should be updated on all frames
+TEST_P(MainThreadScrollingReasonsTest,
+ RecalculateMainThreadScrollingReasonsUponResize) {
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+ RegisterMockedHttpURLLoad("has-non-layer-viewport-constrained-objects.html");
+ RegisterMockedHttpURLLoad("white-1x1.png");
+ NavigateTo(base_url_ + "has-non-layer-viewport-constrained-objects.html");
+ ForceFullCompositingUpdate();
+
+ // When the main document is not scrollable, there should be no reasons.
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons());
+
+ // When the div forces the document to be scrollable, it should scroll on main
+ // thread.
+ Element* element = GetFrame()->GetDocument()->getElementById("scrollable");
+ element->setAttribute(
+ "style",
+ "background-image: url('white-1x1.png'); background-attachment: fixed;",
+ ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+
+ EXPECT_TRUE(GetViewMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
+
+ // The main thread scrolling reason should be reset upon the following change.
+ element->setAttribute("style", "", ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons());
+}
+
+TEST_P(MainThreadScrollingReasonsTest, FastScrollingCanBeDisabledWithSetting) {
+ GetWebView()->MainFrameWidget()->Resize(WebSize(800, 600));
+ LoadHTML("<div id='spacer' style='height: 1000px'></div>");
+ GetWebView()->GetSettings()->SetThreadedScrollingEnabled(false);
+ GetFrame()->View()->SetNeedsPaintPropertyUpdate();
+ ForceFullCompositingUpdate();
+
+ // Main scrolling should be enabled with the setting override.
+ EXPECT_TRUE(GetViewMainThreadScrollingReasons());
+
+ // Main scrolling should also propagate to inner viewport layer.
+ cc::Layer* inner_viewport_scroll_layer =
+ GetFrame()->GetPage()->GetVisualViewport().ScrollLayer()->CcLayer();
+ ASSERT_TRUE(inner_viewport_scroll_layer->scrollable());
+ EXPECT_TRUE(inner_viewport_scroll_layer->GetMainThreadScrollingReasons());
+}
+
+TEST_P(MainThreadScrollingReasonsTest, FastScrollingForFixedPosition) {
+ RegisterMockedHttpURLLoad("fixed-position.html");
+ NavigateTo(base_url_ + "fixed-position.html");
+ ForceFullCompositingUpdate();
+
+ // Fixed position should not fall back to main thread scrolling.
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons());
+}
+
+TEST_P(MainThreadScrollingReasonsTest, FastScrollingForStickyPosition) {
+ RegisterMockedHttpURLLoad("sticky-position.html");
+ NavigateTo(base_url_ + "sticky-position.html");
+ ForceFullCompositingUpdate();
+
+ // Sticky position should not fall back to main thread scrolling.
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons());
+}
+
+TEST_P(MainThreadScrollingReasonsTest, FastScrollingByDefault) {
+ GetWebView()->MainFrameWidget()->Resize(WebSize(800, 600));
+ LoadHTML("<div id='spacer' style='height: 1000px'></div>");
+ ForceFullCompositingUpdate();
+
+ // Fast scrolling should be enabled by default.
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons());
+
+ cc::Layer* inner_viewport_scroll_layer =
+ GetFrame()->GetPage()->GetVisualViewport().ScrollLayer()->CcLayer();
+ ASSERT_TRUE(inner_viewport_scroll_layer->scrollable());
+ EXPECT_FALSE(inner_viewport_scroll_layer->GetMainThreadScrollingReasons());
+}
+
+TEST_P(MainThreadScrollingReasonsTest,
+ ScrollbarsForceMainThreadOrHaveCompositorScrollbarLayer) {
+ RegisterMockedHttpURLLoad("trivial-scroller.html");
+ NavigateTo(base_url_ + "trivial-scroller.html");
+ ForceFullCompositingUpdate();
+
+ Document* document = GetFrame()->GetDocument();
+ Element* scrollable_element = document->getElementById("scroller");
+ DCHECK(scrollable_element);
+
+ LayoutObject* layout_object = scrollable_element->GetLayoutObject();
+ ASSERT_TRUE(layout_object->IsBox());
+ LayoutBox* box = ToLayoutBox(layout_object);
+ ASSERT_TRUE(box->UsesCompositedScrolling());
+ CompositedLayerMapping* composited_layer_mapping =
+ box->Layer()->GetCompositedLayerMapping();
+ GraphicsLayer* scrollbar_graphics_layer =
+ composited_layer_mapping->LayerForVerticalScrollbar();
+ ASSERT_TRUE(scrollbar_graphics_layer);
+
+ bool has_cc_scrollbar_layer = !scrollbar_graphics_layer->DrawsContent();
+ EXPECT_TRUE(
+ has_cc_scrollbar_layer ||
+ scrollbar_graphics_layer->CcLayer()->GetMainThreadScrollingReasons());
+}
+
+class NonCompositedMainThreadScrollingReasonsTest
+ : public MainThreadScrollingReasonsTest {
+ static const uint32_t kLCDTextRelatedReasons =
+ MainThreadScrollingReason::kHasOpacityAndLCDText |
+ MainThreadScrollingReason::kHasTransformAndLCDText |
+ MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText |
+ MainThreadScrollingReason::kIsNotStackingContextAndLCDText;
+
+ protected:
+ NonCompositedMainThreadScrollingReasonsTest() {
+ RegisterMockedHttpURLLoad("two_scrollable_area.html");
+ NavigateTo(base_url_ + "two_scrollable_area.html");
+ }
+ void TestNonCompositedReasons(const std::string& target,
+ const uint32_t reason) {
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+ Document* document = GetFrame()->GetDocument();
+ Element* container = document->getElementById("scroller1");
+ container->setAttribute("class", target.c_str(), ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+
+ PaintLayerScrollableArea* scrollable_area =
+ ToLayoutBoxModelObject(container->GetLayoutObject())
+ ->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area);
+ EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ reason);
+
+ Element* container2 = document->getElementById("scroller2");
+ PaintLayerScrollableArea* scrollable_area2 =
+ ToLayoutBoxModelObject(container2->GetLayoutObject())
+ ->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area2);
+ // Different scrollable area should remain unaffected.
+ EXPECT_FALSE(
+ scrollable_area2->GetNonCompositedMainThreadScrollingReasons() &
+ reason);
+
+ LocalFrameView* frame_view = GetFrame()->View();
+ ASSERT_TRUE(frame_view);
+ EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & reason);
+
+ // Remove attribute from the scroller 1 would lead to scroll on impl.
+ container->removeAttribute("class");
+ ForceFullCompositingUpdate();
+
+ EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ reason);
+ EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & reason);
+
+ // Add target attribute would again lead to scroll on main thread
+ container->setAttribute("class", target.c_str(), ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+
+ EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ reason);
+ EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & reason);
+
+ if ((reason & kLCDTextRelatedReasons) &&
+ !(reason & ~kLCDTextRelatedReasons)) {
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
+ ForceFullCompositingUpdate();
+ EXPECT_FALSE(
+ scrollable_area->GetNonCompositedMainThreadScrollingReasons());
+ EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons());
+ }
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(All,
+ NonCompositedMainThreadScrollingReasonsTest,
+ testing::Bool());
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, TransparentTest) {
+ TestNonCompositedReasons("transparent",
+ MainThreadScrollingReason::kHasOpacityAndLCDText);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, TransformTest) {
+ TestNonCompositedReasons("transform",
+ MainThreadScrollingReason::kHasTransformAndLCDText);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, BackgroundNotOpaqueTest) {
+ TestNonCompositedReasons(
+ "background-not-opaque",
+ MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, ClipTest) {
+ TestNonCompositedReasons("clip",
+ MainThreadScrollingReason::kHasClipRelatedProperty);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, ClipPathTest) {
+ uint32_t clip_reason = MainThreadScrollingReason::kHasClipRelatedProperty;
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+ Document* document = GetFrame()->GetDocument();
+ // Test ancestor with ClipPath
+ Element* element = document->body();
+ element->setAttribute(html_names::kStyleAttr,
+ "clip-path:circle(115px at 20px 20px);");
+ Element* container = document->getElementById("scroller1");
+ ASSERT_TRUE(container);
+ ForceFullCompositingUpdate();
+
+ PaintLayerScrollableArea* scrollable_area =
+ ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea();
+ EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ clip_reason);
+
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons() & clip_reason);
+
+ // Remove clip path from ancestor.
+ element->removeAttribute(html_names::kStyleAttr);
+ ForceFullCompositingUpdate();
+
+ EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ clip_reason);
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons() & clip_reason);
+
+ // Test descendant with ClipPath
+ element = document->getElementById("content1");
+ ASSERT_TRUE(element);
+ element->setAttribute(html_names::kStyleAttr,
+ "clip-path:circle(115px at 20px 20px);");
+ ForceFullCompositingUpdate();
+ EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ clip_reason);
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons() & clip_reason);
+
+ // Remove clip path from descendant.
+ element->removeAttribute(html_names::kStyleAttr);
+ ForceFullCompositingUpdate();
+ EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ clip_reason);
+ EXPECT_FALSE(GetViewMainThreadScrollingReasons() & clip_reason);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, LCDTextEnabledTest) {
+ TestNonCompositedReasons("transparent",
+ MainThreadScrollingReason::kHasOpacityAndLCDText);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, BoxShadowTest) {
+ TestNonCompositedReasons(
+ "box-shadow", MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer);
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest, StackingContextTest) {
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+
+ Document* document = GetFrame()->GetDocument();
+ Element* container = document->getElementById("scroller1");
+ ASSERT_TRUE(container);
+
+ ForceFullCompositingUpdate();
+
+ // If a scroller contains all its children, it's not a stacking context.
+ PaintLayerScrollableArea* scrollable_area =
+ ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area);
+ EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kIsNotStackingContextAndLCDText);
+
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
+ ForceFullCompositingUpdate();
+ EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
+ MainThreadScrollingReason::kIsNotStackingContextAndLCDText);
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+
+ // Adding "contain: paint" to force a stacking context leads to promotion.
+ container->setAttribute("style", "contain: paint", ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+
+ EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons());
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest,
+ CompositedWithLCDTextRelatedReasonsTest) {
+ // With "will-change:transform" we composite elements with
+ // LCDTextRelatedReasons only. For elements with other
+ // NonCompositedReasons, we don't create scrollingLayer for their
+ // CompositedLayerMapping therefore they don't get composited.
+ GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+ Document* document = GetFrame()->GetDocument();
+ Element* container = document->getElementById("scroller1");
+ ASSERT_TRUE(container);
+ container->setAttribute("class", "composited transparent",
+ ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+
+ PaintLayerScrollableArea* scrollable_area =
+ ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area);
+ EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons());
+
+ Element* container2 = document->getElementById("scroller2");
+ ASSERT_TRUE(container2);
+ container2->setAttribute("class", "composited border-radius",
+ ASSERT_NO_EXCEPTION);
+ ForceFullCompositingUpdate();
+ PaintLayerScrollableArea* scrollable_area2 =
+ ToLayoutBoxModelObject(container2->GetLayoutObject())
+ ->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area2);
+ ASSERT_TRUE(scrollable_area2->UsesCompositedScrolling());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
index 20099b81087..b7704ebef1b 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
@@ -310,10 +310,8 @@ bool RootScrollerController::IsValidImplicit(const Element& element) const {
PaintLayerScrollableArea* area = ancestor->GetScrollableArea();
DCHECK(area);
- if ((style->ScrollsOverflowX() && area->HasHorizontalOverflow()) ||
- (style->ScrollsOverflowY() && area->HasVerticalOverflow())) {
+ if (style->ScrollsOverflowY() && area->HasVerticalOverflow())
return false;
- }
} else {
if (ancestor->ShouldClipOverflow() || ancestor->HasMask() ||
ancestor->HasClip() || ancestor->HasClipPath()) {
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index 8585499402e..d457d5a8bfe 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -79,7 +79,7 @@ class RootScrollerTest : public testing::Test,
}
WebViewImpl* Initialize(const std::string& page_name,
- frame_test_helpers::TestWebViewClient* client) {
+ frame_test_helpers::TestWebWidgetClient* client) {
return InitializeInternal(base_url_ + page_name, client);
}
@@ -178,8 +178,8 @@ class RootScrollerTest : public testing::Test,
WebViewImpl* InitializeInternal(
const std::string& url,
- frame_test_helpers::TestWebViewClient* client) {
- helper_.InitializeAndLoad(url, nullptr, client, nullptr,
+ frame_test_helpers::TestWebWidgetClient* client) {
+ helper_.InitializeAndLoad(url, nullptr, nullptr, client,
&ConfigureSettings);
// Initialize browser controls to be shown.
@@ -197,6 +197,7 @@ class RootScrollerTest : public testing::Test,
}
std::string base_url_;
+ std::unique_ptr<frame_test_helpers::TestWebViewClient> view_client_;
frame_test_helpers::WebViewHelper helper_;
RuntimeEnabledFeatures::Backup features_backup_;
};
@@ -235,8 +236,8 @@ TEST_F(RootScrollerTest, defaultEffectiveRootScrollerIsDocumentNode) {
EffectiveRootScroller(MainFrame()->GetDocument()));
}
-class OverscrollTestWebViewClient
- : public frame_test_helpers::TestWebViewClient {
+class OverscrollTestWebWidgetClient
+ : public frame_test_helpers::TestWebWidgetClient {
public:
MOCK_METHOD5(DidOverscroll,
void(const WebFloatSize&,
@@ -249,7 +250,7 @@ class OverscrollTestWebViewClient
// Tests that setting an element as the root scroller causes it to control url
// bar hiding and overscroll.
TEST_F(RootScrollerTest, TestSetRootScroller) {
- OverscrollTestWebViewClient client;
+ OverscrollTestWebWidgetClient client;
Initialize("root-scroller.html", &client);
Element* container = MainFrame()->GetDocument()->getElementById("container");
@@ -260,14 +261,14 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
// makes it 400x450 so max scroll is 550px.
double maximum_scroll = 550;
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollBegin));
{
// Scrolling over the #container DIV should cause the browser controls to
// hide.
EXPECT_FLOAT_EQ(1, GetBrowserControls().ShownRatio());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollUpdate, 0,
-GetBrowserControls().TopHeight()));
EXPECT_FLOAT_EQ(0, GetBrowserControls().ShownRatio());
@@ -275,7 +276,7 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
{
// Make sure we're actually scrolling the DIV and not the LocalFrameView.
- GetWebView()->HandleInputEvent(GenerateTouchGestureEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::kGestureScrollUpdate, 0, -100));
EXPECT_FLOAT_EQ(100, container->scrollTop());
EXPECT_FLOAT_EQ(
@@ -288,7 +289,7 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
EXPECT_CALL(client, DidOverscroll(WebFloatSize(0, 50), WebFloatSize(0, 50),
WebFloatPoint(100, 100), WebFloatSize(),
cc::OverscrollBehavior()));
- GetWebView()->HandleInputEvent(GenerateTouchGestureEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::kGestureScrollUpdate, 0, -500));
EXPECT_FLOAT_EQ(maximum_scroll, container->scrollTop());
EXPECT_FLOAT_EQ(
@@ -301,7 +302,7 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
EXPECT_CALL(client, DidOverscroll(WebFloatSize(0, 20), WebFloatSize(0, 70),
WebFloatPoint(100, 100), WebFloatSize(),
cc::OverscrollBehavior()));
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollUpdate, 0, -20));
EXPECT_FLOAT_EQ(maximum_scroll, container->scrollTop());
EXPECT_FLOAT_EQ(
@@ -309,40 +310,40 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
Mock::VerifyAndClearExpectations(&client);
}
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollEnd));
{
// Make sure a new gesture scroll still won't scroll the frameview and
// overscrolls.
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_CALL(client, DidOverscroll(WebFloatSize(0, 30), WebFloatSize(0, 30),
WebFloatPoint(100, 100), WebFloatSize(),
cc::OverscrollBehavior()));
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollUpdate, 0, -30));
EXPECT_FLOAT_EQ(maximum_scroll, container->scrollTop());
EXPECT_FLOAT_EQ(
0, MainFrameView()->LayoutViewport()->GetScrollOffset().Height());
Mock::VerifyAndClearExpectations(&client);
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollEnd));
}
{
// Scrolling up should show the browser controls.
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0, GetBrowserControls().ShownRatio());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollUpdate, 0, 30));
EXPECT_FLOAT_EQ(0.6, GetBrowserControls().ShownRatio());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollEnd));
}
@@ -1033,20 +1034,20 @@ TEST_F(RootScrollerTest, TopControlsAdjustmentAppliedToRootScroller) {
// scroll offset should shrink.
ASSERT_EQ(1000 - 400, container_scroller->MaximumScrollOffset().Height());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollBegin));
ASSERT_EQ(1, GetBrowserControls().ShownRatio());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollUpdate, 0,
-GetBrowserControls().TopHeight()));
ASSERT_EQ(0, GetBrowserControls().ShownRatio());
EXPECT_EQ(1000 - 450, container_scroller->MaximumScrollOffset().Height());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollUpdate, 0, -3000));
EXPECT_EQ(1000 - 450, container_scroller->GetScrollOffset().Height());
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollEnd));
GetWebView()->ResizeWithBrowserControls(IntSize(400, 450), 50, 0, false);
EXPECT_EQ(1000 - 450, container_scroller->MaximumScrollOffset().Height());
@@ -1079,11 +1080,11 @@ TEST_F(RootScrollerTest, RotationAnchoring) {
int scroll_y = 1000 * 4;
GetWebView()->SetPageScaleFactor(2);
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollBegin));
- GetWebView()->HandleInputEvent(GenerateTouchGestureEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::kGestureScrollUpdate, -scroll_x, -scroll_y));
- GetWebView()->HandleInputEvent(
+ GetWebView()->MainFrameWidget()->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::kGestureScrollEnd));
// The visual viewport should be 1.5 screens scrolled so that the target
@@ -1240,7 +1241,7 @@ class RootScrollerSimTest : public SimTest {
// However, until a frame is produced, the effective root scroller should
// not change.
TEST_F(RootScrollerSimTest, SetCausesNeedsBeginFrame) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1281,7 +1282,7 @@ TEST_F(RootScrollerSimTest, SetCausesNeedsBeginFrame) {
// correctly when the Document is the effective root scroller. It becomes the
// root scroller before Document has a LayoutView.
TEST_F(RootScrollerSimTest, DocumentEffectiveSetsCachedBit) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1295,7 +1296,7 @@ TEST_F(RootScrollerSimTest, DocumentEffectiveSetsCachedBit) {
// Test that layout from outside a lifecycle wont select a new effective root
// scroller.
TEST_F(RootScrollerSimTest, NonLifecycleLayoutDoesntCauseReselection) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1347,7 +1348,7 @@ TEST_F(RootScrollerSimTest, NonLifecycleLayoutDoesntCauseReselection) {
// the current one is valid in all ways except that it no longer has a content
// frame. This test passes if it doesn't crash. https://crbug.com/805317.
TEST_F(RootScrollerSimTest, RecomputeEffectiveWithNoContentFrame) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
SimRequest first_request("https://example.com/first.html", "text/html");
SimRequest second_request("https://example.com/second.html", "text/html");
@@ -1415,7 +1416,7 @@ TEST_F(RootScrollerSimTest, RecomputeEffectiveWithNoContentFrame) {
// Test that the element is considered to be viewport filling only if its
// padding box fills the viewport. That means it must have no border.
TEST_F(RootScrollerSimTest, UsePaddingBoxForViewportFillingCondition) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1453,10 +1454,9 @@ TEST_F(RootScrollerSimTest, UsePaddingBoxForViewportFillingCondition) {
// Tests that the root scroller doesn't affect visualViewport pageLeft and
// pageTop.
TEST_F(RootScrollerSimTest, RootScrollerDoesntAffectVisualViewport) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
- request.Start();
request.Write(R"HTML(
<!DOCTYPE html>
<style>
@@ -1515,10 +1515,9 @@ TEST_F(RootScrollerSimTest, ResizeFromResizeAfterLayout) {
WebView().GetSettings()->SetShrinksViewportContentToFit(true);
WebView().SetDefaultPageScaleLimits(0.25f, 5);
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
- request.Start();
request.Write(R"HTML(
<!DOCTYPE html>
<style>
@@ -1579,7 +1578,7 @@ class ImplicitRootScrollerSimTest : public SimTest {
// Tests basic implicit root scroller mode with a <div>.
TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScroller) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1688,7 +1687,7 @@ TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScroller) {
// Test that adding overflow to an element that would otherwise be eligable to
// be implicitly pomoted causes promotion.
TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScrollerAddOverflow) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1734,7 +1733,7 @@ TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScrollerAddOverflow) {
// Tests that we don't crash if an implicit candidate is no longer a box. This
// test passes if it doesn't crash.
TEST_F(ImplicitRootScrollerSimTest, CandidateLosesLayoutBoxDontCrash) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1775,7 +1774,7 @@ TEST_F(ImplicitRootScrollerSimTest, CandidateLosesLayoutBoxDontCrash) {
// Ensure that a plugin view being considered for implicit promotion doesn't
// cause a crash. https://crbug.com/903440.
TEST_F(ImplicitRootScrollerSimTest, ConsiderEmbedCrash) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1795,7 +1794,7 @@ TEST_F(ImplicitRootScrollerSimTest, ConsiderEmbedCrash) {
// the main document has overflow.
TEST_F(ImplicitRootScrollerSimTest,
ImplicitRootScrollerDocumentScrollsOverflow) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1850,7 +1849,7 @@ TEST_F(ImplicitRootScrollerSimTest,
// Test that we'll only implicitly promote an element if its visible.
TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScrollerVisibilityCondition) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1923,7 +1922,7 @@ TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScrollerVisibilityCondition) {
// Tests implicit root scroller mode for iframes.
TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScrollerIframe) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1967,7 +1966,7 @@ TEST_F(ImplicitRootScrollerSimTest, ImplicitRootScrollerIframe) {
// Tests use counter for implicit root scroller. Ensure it's not counted on a
// page without an implicit root scroller.
TEST_F(ImplicitRootScrollerSimTest, UseCounterNegative) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2009,7 +2008,7 @@ TEST_F(ImplicitRootScrollerSimTest, UseCounterNegative) {
// Tests use counter for implicit root scroller. Ensure it's counted on a
// page that loads with an implicit root scroller.
TEST_F(ImplicitRootScrollerSimTest, UseCounterPositive) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2060,7 +2059,7 @@ TEST_F(ImplicitRootScrollerSimTest, UseCounterPositive) {
// Tests use counter for implicit root scroller. Ensure it's counted on a
// page that loads without an implicit root scroller but later gets one.
TEST_F(ImplicitRootScrollerSimTest, UseCounterPositiveAfterLoad) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2111,7 +2110,7 @@ TEST_F(ImplicitRootScrollerSimTest, UseCounterPositiveAfterLoad) {
// Tests that if we have multiple valid candidates for implicit promotion, we
// don't promote either.
TEST_F(ImplicitRootScrollerSimTest, DontPromoteWhenMultipleAreValid) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2165,7 +2164,7 @@ TEST_F(ImplicitRootScrollerSimTest, DontPromoteWhenMultipleAreValid) {
// Test that when a valid iframe becomes loaded and thus should be promoted, it
// becomes the root scroller, without needing an intervening layout.
TEST_F(ImplicitRootScrollerSimTest, IframeLoadedWithoutLayout) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_request("https://example.com/test.html", "text/html");
SimRequest child_request("https://example.com/child.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -2216,7 +2215,7 @@ TEST_F(ImplicitRootScrollerSimTest, IframeLoadedWithoutLayout) {
// causes it to remain the effective root scroller after the navigation (to a
// page where it remains valid) is finished.
TEST_F(ImplicitRootScrollerSimTest, NavigateToValidRemainsRootScroller) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_request("https://example.com/test.html", "text/html");
SimRequest child_request("https://example.com/child.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -2257,11 +2256,10 @@ TEST_F(ImplicitRootScrollerSimTest, NavigateToValidRemainsRootScroller) {
// Ensure that we remain the root scroller even though there's no layout in
// the parent.
SimRequest child_request2("https://example.com/child-next.html", "text/html");
- WebURLRequest request(KURL("https://example.com/child-next.html"));
- WebView().MainFrameImpl()->FirstChild()->ToWebLocalFrame()->StartNavigation(
- request);
+ frame_test_helpers::LoadFrameDontWait(
+ WebView().MainFrameImpl()->FirstChild()->ToWebLocalFrame(),
+ KURL("https://example.com/child-next.html"));
- child_request2.Start();
child_request2.Write(R"HTML(
<!DOCTYPE html>
)HTML");
@@ -2374,7 +2372,7 @@ TEST_F(ImplicitRootScrollerSimTest,
// Tests that implicit is continually reevaluating whether to promote or demote
// a scroller.
TEST_F(ImplicitRootScrollerSimTest, ContinuallyReevaluateImplicitPromotion) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2457,7 +2455,7 @@ TEST_F(ImplicitRootScrollerSimTest, ContinuallyReevaluateImplicitPromotion) {
// Tests that implicit mode correctly recognizes when an iframe becomes
// scrollable.
TEST_F(ImplicitRootScrollerSimTest, IframeScrollingAffectsPromotion) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -2557,8 +2555,8 @@ TEST_F(ImplicitRootScrollerSimTest, PromotionChangesLayoutSize) {
<< "Once loaded, the iframe should be promoted.";
}
-// Test that we don't promote any elements implicitly if the main document have
-// vertical overflow.
+// Test that we don't promote any elements implicitly if the main document has
+// vertical scrolling.
TEST_F(ImplicitRootScrollerSimTest, OverflowInMainDocumentRestrictsImplicit) {
WebView().ResizeWithBrowserControls(IntSize(800, 600), 50, 0, true);
SimRequest main_request("https://example.com/test.html", "text/html");
@@ -2612,15 +2610,6 @@ TEST_F(ImplicitRootScrollerSimTest, OverflowInMainDocumentRestrictsImplicit) {
ASSERT_NO_EXCEPTION);
Compositor().BeginFrame();
- EXPECT_EQ(GetDocument(),
- GetDocument().GetRootScrollerController().EffectiveRootScroller())
- << "iframe still shouldn't be promoted due to horizontal overflow in "
- << "the main document.";
-
- spacer->style()->setProperty(&GetDocument(), "width", "100%", String(),
- ASSERT_NO_EXCEPTION);
- Compositor().BeginFrame();
-
EXPECT_EQ(GetDocument().getElementById("container"),
GetDocument().GetRootScrollerController().EffectiveRootScroller())
<< "Once vertical overflow is removed, the iframe should be promoted.";
@@ -2886,8 +2875,9 @@ class RootScrollerHitTest : public RootScrollerSimTest {
// Do a scroll gesture that hides the top controls and scrolls all the way
// to the bottom.
ASSERT_EQ(1, GetBrowserControls().ShownRatio());
- WebView().ApplyViewportChanges({gfx::ScrollOffset(), gfx::Vector2dF(), 1,
- -1, cc::BrowserControlsState::kBoth});
+ WebView().MainFrameWidget()->ApplyViewportChanges(
+ {gfx::ScrollOffset(), gfx::Vector2dF(), 1, -1,
+ cc::BrowserControlsState::kBoth});
ASSERT_EQ(0, GetBrowserControls().ShownRatio());
Node* scroller = GetDocument()
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc
index c866ff5d488..ab766f46f64 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc
@@ -4,6 +4,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink.h"
+#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/renderer/bindings/core/v8/scroll_into_view_options_or_boolean.h"
#include "third_party/blink/renderer/core/dom/element.h"
@@ -13,6 +14,7 @@
#include "third_party/blink/renderer/core/frame/scroll_to_options.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -25,7 +27,7 @@ class ScrollIntoViewTest : public SimTest {};
TEST_F(ScrollIntoViewTest, InstantScroll) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
@@ -46,7 +48,7 @@ TEST_F(ScrollIntoViewTest, InstantScroll) {
TEST_F(ScrollIntoViewTest, ScrollPaddingOnBodyViewportDefining) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -75,7 +77,7 @@ TEST_F(ScrollIntoViewTest, ScrollPaddingOnBodyViewportDefining) {
TEST_F(ScrollIntoViewTest, ScrollPaddingOnHtmlViewportDefining) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -104,7 +106,7 @@ TEST_F(ScrollIntoViewTest, ScrollPaddingOnHtmlViewportDefining) {
TEST_F(ScrollIntoViewTest, ScrollPaddingBodyOverflowHtmlViewportDefining) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(300, 300));
+ WebView().MainFrameWidget()->Resize(WebSize(300, 300));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -144,7 +146,7 @@ TEST_F(ScrollIntoViewTest, ScrollPaddingBodyOverflowHtmlViewportDefining) {
TEST_F(ScrollIntoViewTest, SmoothScroll) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
@@ -174,7 +176,7 @@ TEST_F(ScrollIntoViewTest, SmoothScroll) {
TEST_F(ScrollIntoViewTest, NestedContainer) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -222,7 +224,7 @@ TEST_F(ScrollIntoViewTest, NestedContainer) {
TEST_F(ScrollIntoViewTest, NewScrollIntoViewAbortsCurrentAnimation) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -287,7 +289,7 @@ TEST_F(ScrollIntoViewTest, NewScrollIntoViewAbortsCurrentAnimation) {
TEST_F(ScrollIntoViewTest, ScrollWindowAbortsCurrentAnimation) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -334,7 +336,7 @@ TEST_F(ScrollIntoViewTest, ScrollWindowAbortsCurrentAnimation) {
TEST_F(ScrollIntoViewTest, BlockAndInlineSettings) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -391,7 +393,7 @@ TEST_F(ScrollIntoViewTest, BlockAndInlineSettings) {
TEST_F(ScrollIntoViewTest, SmoothAndInstantInChain) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -442,7 +444,7 @@ TEST_F(ScrollIntoViewTest, SmoothAndInstantInChain) {
TEST_F(ScrollIntoViewTest, SmoothScrollAnchor) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -476,7 +478,7 @@ TEST_F(ScrollIntoViewTest, SmoothScrollAnchor) {
TEST_F(ScrollIntoViewTest, FindDoesNotScrollOverflowHidden) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -498,7 +500,7 @@ TEST_F(ScrollIntoViewTest, FindDoesNotScrollOverflowHidden) {
TEST_F(ScrollIntoViewTest, ApplyRootElementScrollBehaviorToViewport) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
@@ -529,7 +531,7 @@ TEST_F(ScrollIntoViewTest, ApplyRootElementScrollBehaviorToViewport) {
// This test passes if it doesn't crash/hit an ASAN check.
TEST_F(ScrollIntoViewTest, RemoveSequencedScrollableArea) {
v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -585,6 +587,71 @@ TEST_F(ScrollIntoViewTest, RemoveSequencedScrollableArea) {
Compositor().BeginFrame(1);
}
+TEST_F(ScrollIntoViewTest, SmoothUserScrollNotAbortedByProgrammaticScrolls) {
+ v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(
+ "<div id='space' style='height: 1000px'></div>"
+ "<div id='content' style='height: 1000px'></div>");
+
+ Compositor().BeginFrame();
+ ASSERT_EQ(Window().scrollY(), 0);
+
+ // A smooth UserScroll.
+ Element* content = GetDocument().getElementById("content");
+ content->GetLayoutObject()->ScrollRectToVisible(
+ content->BoundingBoxForScrollIntoView(),
+ {ScrollAlignment::kAlignToEdgeIfNeeded, ScrollAlignment::kAlignTopAlways,
+ kUserScroll, false, kScrollBehaviorSmooth, true});
+
+ // Animating the container
+ Compositor().BeginFrame(); // update run_state_.
+ Compositor().BeginFrame(); // Set start_time = now.
+ Compositor().BeginFrame(0.2);
+ ASSERT_EQ(Window().scrollY(), 299);
+
+ // ProgrammaticScroll that could interrupt the current smooth scroll.
+ Window().scrollTo(0, 0);
+
+ // Finish scrolling the container
+ Compositor().BeginFrame(1);
+ // The programmatic scroll of Window shouldn't abort the user scroll.
+ ASSERT_EQ(Window().scrollY(), content->OffsetTop());
+}
+
+TEST_F(ScrollIntoViewTest, LongDistanceSmoothScrollFinishedInThreeSeconds) {
+ v8::HandleScope HandleScope(v8::Isolate::GetCurrent());
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(
+ "<div id='space' style='height: 100000px'></div>"
+ "<div id='target' style='height: 1000px'></div>");
+
+ Compositor().BeginFrame();
+ ASSERT_EQ(Window().scrollY(), 0);
+
+ Element* target = GetDocument().getElementById("target");
+ ScrollIntoViewOptionsOrBoolean arg;
+ ScrollIntoViewOptions* options = ScrollIntoViewOptions::Create();
+ options->setBlock("start");
+ options->setBehavior("smooth");
+ arg.SetScrollIntoViewOptions(options);
+ target->scrollIntoView(arg);
+
+ // Scrolling the window
+ Compositor().BeginFrame(); // update run_state_.
+ Compositor().BeginFrame(); // Set start_time = now.
+ Compositor().BeginFrame(0.2);
+ ASSERT_EQ(Window().scrollY(), 864);
+
+ // Finish scrolling the container
+ Compositor().BeginFrame(2.8);
+ ASSERT_EQ(Window().scrollY(), target->OffsetTop());
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
index 0285f324cc2..010f14c7c9f 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
@@ -118,7 +118,7 @@ void ScrollMetricsTest::Scroll(Element* element,
}
void ScrollMetricsTest::SetUpHtml(const char* html_content) {
- WebView().Resize(WebSize(800, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(html_content);
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index e03839dd7c2..4a51ef0a0f8 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -152,27 +152,37 @@ void ScrollingCoordinator::NotifyTransformChanged(LocalFrame* frame,
}
}
-void ScrollingCoordinator::DidScroll(const gfx::ScrollOffset& offset,
- const CompositorElementId& element_id) {
+ScrollableArea*
+ScrollingCoordinator::ScrollableAreaWithElementIdInAllLocalFrames(
+ const CompositorElementId& id) {
for (auto* frame = page_->MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
- // Remote frames will receive DidScroll callbacks from their own compositor.
if (!frame->IsLocalFrame())
continue;
- // Find the associated scrollable area using the element id and notify it
- // of the compositor-side scroll. We explicitly do not check the
- // VisualViewport which handles scroll offset differently (see:
- // VisualViewport::didScroll).
+ // Find the associated scrollable area using the element id.
if (LocalFrameView* view = ToLocalFrame(frame)->View()) {
- if (auto* scrollable = view->ScrollableAreaWithElementId(element_id)) {
- scrollable->DidScroll(FloatPoint(offset.x(), offset.y()));
- return;
+ if (auto* scrollable = view->ScrollableAreaWithElementId(id)) {
+ return scrollable;
}
}
}
+ // The ScrollableArea with matching ElementId does not exist in local frames.
+ return nullptr;
+}
+
+void ScrollingCoordinator::DidScroll(const gfx::ScrollOffset& offset,
+ const CompositorElementId& element_id) {
+ // Find the associated scrollable area using the element id and notify it of
+ // the compositor-side scroll. We explicitly do not check the VisualViewport
+ // which handles scroll offset differently (see: VisualViewport::didScroll).
+ // Remote frames will receive DidScroll callbacks from their own compositor.
// The ScrollableArea with matching ElementId may have been deleted and we can
// safely ignore the DidScroll callback.
+ if (auto* scrollable =
+ ScrollableAreaWithElementIdInAllLocalFrames(element_id)) {
+ scrollable->DidScroll(FloatPoint(offset.x(), offset.y()));
+ }
}
void ScrollingCoordinator::UpdateAfterPaint(LocalFrameView* frame_view) {
@@ -225,24 +235,31 @@ void ScrollingCoordinator::UpdateAfterPaint(LocalFrameView* frame_view) {
frame_view->GetScrollingContext()->SetTouchEventTargetRectsAreDirty(false);
}
- // TODO(pdr): Move the should_scroll_on_main_thread logic to use touch action
- // rects. These features are similar and do not need independent
- // implementations.
if (should_scroll_on_main_thread_dirty ||
frame_view->FrameIsScrollableDidChange()) {
- SetShouldUpdateScrollLayerPositionOnMainThread(
- frame, frame_view->GetMainThreadScrollingReasons());
-
- // Need to update scroll on main thread reasons for subframe because
- // subframe (e.g. iframe with background-attachment:fixed) should
- // scroll on main thread while the main frame scrolls on impl.
- frame_view->UpdateSubFrameScrollOnMainReason(*frame, 0);
+ // When blink generates property trees, main thread scrolling reasons are
+ // stored on scroll nodes.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ // TODO(pdr): This also takes over scroll animations if main thread
+ // reasons are present. This needs to be implemented for
+ // BlinkGenPropertyTrees.
+ SetShouldUpdateScrollLayerPositionOnMainThread(
+ frame, frame_view->GetMainThreadScrollingReasons());
+
+ // Need to update scroll on main thread reasons for subframe because
+ // subframe (e.g. iframe with background-attachment:fixed) should
+ // scroll on main thread while the main frame scrolls on impl.
+ frame_view->UpdateSubFrameScrollOnMainReason(*frame, 0);
+ }
frame_view->GetScrollingContext()->SetShouldScrollOnMainThreadIsDirty(
false);
}
frame_view->ClearFrameIsScrollableDidChange();
- UpdateUserInputScrollable(&page_->GetVisualViewport());
+ // When blink generates property trees, the user input scrollable bits are
+ // stored on scroll nodes instead of layers.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ UpdateUserInputScrollable(&page_->GetVisualViewport());
}
template <typename Function>
@@ -257,7 +274,7 @@ static void ForAllGraphicsLayers(GraphicsLayer& layer,
// on the GraphicsLayer's paint chunks.
static void UpdateLayerTouchActionRects(GraphicsLayer& layer) {
DCHECK(RuntimeEnabledFeatures::PaintTouchActionRectsEnabled());
- if (!layer.DrawsContent())
+ if (!layer.PaintsContentOrHitTest())
return;
if (layer.Client().ShouldThrottleRendering()) {
@@ -522,7 +539,8 @@ void ScrollingCoordinator::ScrollableAreaScrollLayerDidChange(
if (!page_ || !page_->MainFrame())
return;
- UpdateUserInputScrollable(scrollable_area);
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ UpdateUserInputScrollable(scrollable_area);
cc::Layer* cc_layer =
GraphicsLayerToCcLayer(scrollable_area->LayerForScrolling());
@@ -788,8 +806,8 @@ void ScrollingCoordinator::UpdateTouchEventTargetRectsIfNeeded(
TRACE_EVENT0("input",
"ScrollingCoordinator::updateTouchEventTargetRectsIfNeeded");
- // TODO(chrishtr): implement touch event target rects for SPv2.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // TODO(chrishtr): implement touch event target rects for CAP.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
@@ -805,6 +823,9 @@ void ScrollingCoordinator::UpdateTouchEventTargetRectsIfNeeded(
void ScrollingCoordinator::UpdateUserInputScrollable(
ScrollableArea* scrollable_area) {
+ // When blink generates property trees, the user input scrollable bits are
+ // stored on scroll nodes instead of layers so this is not needed.
+ DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
cc::Layer* cc_layer =
GraphicsLayerToCcLayer(scrollable_area->LayerForScrolling());
if (cc_layer) {
@@ -959,7 +980,7 @@ void ScrollingCoordinator::SetShouldUpdateScrollLayerPositionOnMainThread(
if (main_thread_scrolling_reasons) {
if (ScrollAnimatorBase* scroll_animator =
scrollable_area->ExistingScrollAnimator()) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
frame->GetDocument()->Lifecycle().GetState() >=
DocumentLifecycle::kCompositingClean);
scroll_animator->TakeOverCompositorAnimation();
@@ -969,7 +990,7 @@ void ScrollingCoordinator::SetShouldUpdateScrollLayerPositionOnMainThread(
if (visual_viewport_scroll_layer) {
if (ScrollAnimatorBase* scroll_animator =
visual_viewport.ExistingScrollAnimator()) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
frame->GetDocument()->Lifecycle().GetState() >=
DocumentLifecycle::kCompositingClean);
scroll_animator->TakeOverCompositorAnimation();
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
index a55c284d0fb..47fb1a9d8a2 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
@@ -166,11 +166,17 @@ class CORE_EXPORT ScrollingCoordinator final
return programmatic_scroll_animator_timeline_.get();
}
+ // Traverses the frame tree to find the scrollable area using the element id.
+ // This function only checks the local frames. This function does not check
+ // the VisualViewport element id.
+ ScrollableArea* ScrollableAreaWithElementIdInAllLocalFrames(
+ const CompositorElementId&);
+
// Callback for compositor-side layer scrolls.
void DidScroll(const gfx::ScrollOffset&, const CompositorElementId&);
// For testing purposes only. This ScrollingCoordinator is reused between
- // layout test, and must be reset for the results to be valid.
+ // web tests, and must be reset for the results to be valid.
void Reset(LocalFrame*);
protected:
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
index 7e7b3bbdcf2..1d0e45c4283 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
@@ -37,6 +37,7 @@
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/css/style_sheet_list.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -65,15 +66,29 @@
namespace blink {
+// kScrollingCoordinatorTestNoFlags runs with BlinkGenPropertyTrees and
+// PaintTouchActionRects disabled. Using
+// (kScrollingCoordinatorTestBlinkGenPropertyTrees |
+// kScrollingCoordinatorTestPaintTouchActionRects) enables both features.
+enum {
+ kScrollingCoordinatorTestNoFlags = 1 << 0,
+ kScrollingCoordinatorTestBlinkGenPropertyTrees = 1 << 1,
+ kScrollingCoordinatorTestPaintTouchActionRects = 1 << 2,
+};
+
class ScrollingCoordinatorTest : public testing::Test,
- public testing::WithParamInterface<bool>,
+ public testing::WithParamInterface<unsigned>,
+ private ScopedBlinkGenPropertyTreesForTest,
private ScopedPaintTouchActionRectsForTest {
public:
ScrollingCoordinatorTest()
- : ScopedPaintTouchActionRectsForTest(GetParam()),
+ : ScopedBlinkGenPropertyTreesForTest(
+ GetParam() & kScrollingCoordinatorTestBlinkGenPropertyTrees),
+ ScopedPaintTouchActionRectsForTest(
+ GetParam() & kScrollingCoordinatorTestPaintTouchActionRects),
base_url_("http://www.test.com/") {
helper_.Initialize(nullptr, nullptr, nullptr, &ConfigureSettings);
- GetWebView()->Resize(IntSize(320, 240));
+ GetWebView()->MainFrameWidget()->Resize(IntSize(320, 240));
// macOS attaches main frame scrollbars to the VisualViewport so the
// VisualViewport layers need to be initialized.
@@ -142,10 +157,17 @@ class ScrollingCoordinatorTest : public testing::Test,
frame_test_helpers::WebViewHelper helper_;
};
-INSTANTIATE_TEST_CASE_P(All, ScrollingCoordinatorTest, ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(
+ All,
+ ScrollingCoordinatorTest,
+ ::testing::Values(kScrollingCoordinatorTestNoFlags,
+ kScrollingCoordinatorTestBlinkGenPropertyTrees,
+ kScrollingCoordinatorTestPaintTouchActionRects,
+ (kScrollingCoordinatorTestBlinkGenPropertyTrees |
+ kScrollingCoordinatorTestPaintTouchActionRects)));
TEST_P(ScrollingCoordinatorTest, fastScrollingByDefault) {
- GetWebView()->Resize(WebSize(800, 600));
+ GetWebView()->MainFrameWidget()->Resize(WebSize(800, 600));
LoadHTML("<div id='spacer' style='height: 1000px'></div>");
ForceFullCompositingUpdate();
@@ -160,7 +182,7 @@ TEST_P(ScrollingCoordinatorTest, fastScrollingByDefault) {
cc::Layer* root_scroll_layer = GetRootScrollLayer();
ASSERT_TRUE(root_scroll_layer);
ASSERT_TRUE(root_scroll_layer->scrollable());
- ASSERT_FALSE(root_scroll_layer->main_thread_scrolling_reasons());
+ ASSERT_FALSE(root_scroll_layer->GetMainThreadScrollingReasons());
ASSERT_EQ(cc::EventListenerProperties::kNone,
GetWebLayerTreeView()->EventListenerProperties(
cc::EventListenerClass::kTouchStartOrMove));
@@ -171,38 +193,17 @@ TEST_P(ScrollingCoordinatorTest, fastScrollingByDefault) {
cc::Layer* inner_viewport_scroll_layer =
page->GetVisualViewport().ScrollLayer()->CcLayer();
ASSERT_TRUE(inner_viewport_scroll_layer->scrollable());
- ASSERT_FALSE(inner_viewport_scroll_layer->main_thread_scrolling_reasons());
-}
-
-TEST_P(ScrollingCoordinatorTest, fastScrollingCanBeDisabledWithSetting) {
- GetWebView()->Resize(WebSize(800, 600));
- LoadHTML("<div id='spacer' style='height: 1000px'></div>");
- GetWebView()->GetSettings()->SetThreadedScrollingEnabled(false);
- ForceFullCompositingUpdate();
-
- // Make sure the scrolling coordinator is active.
- LocalFrameView* frame_view = GetFrame()->View();
- Page* page = GetFrame()->GetPage();
- ASSERT_TRUE(page->GetScrollingCoordinator());
- ASSERT_TRUE(page->GetScrollingCoordinator()->CoordinatesScrollingForFrameView(
- frame_view));
-
- // Main scrolling should be enabled with the setting override.
- cc::Layer* root_scroll_layer = GetRootScrollLayer();
- ASSERT_TRUE(root_scroll_layer);
- ASSERT_TRUE(root_scroll_layer->scrollable());
- ASSERT_TRUE(root_scroll_layer->main_thread_scrolling_reasons());
-
- // Main scrolling should also propagate to inner viewport layer.
- cc::Layer* inner_viewport_scroll_layer =
- page->GetVisualViewport().ScrollLayer()->CcLayer();
- ASSERT_TRUE(inner_viewport_scroll_layer->scrollable());
- ASSERT_TRUE(inner_viewport_scroll_layer->main_thread_scrolling_reasons());
+ ASSERT_FALSE(inner_viewport_scroll_layer->GetMainThreadScrollingReasons());
}
TEST_P(ScrollingCoordinatorTest, fastFractionalScrollingDiv) {
ScopedFractionalScrollOffsetsForTest fractional_scroll_offsets(true);
+ // TODO(920417): Re-enable this test when main thread scrolling supports
+ // fractional scroll offsets.
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ return;
+
RegisterMockedHttpURLLoad("fractional-scroll-div.html");
NavigateTo(base_url_ + "fractional-scroll-div.html");
ForceFullCompositingUpdate();
@@ -263,7 +264,7 @@ TEST_P(ScrollingCoordinatorTest, fastScrollingForFixedPosition) {
// Fixed position should not fall back to main thread scrolling.
cc::Layer* root_scroll_layer = GetRootScrollLayer();
ASSERT_TRUE(root_scroll_layer);
- ASSERT_FALSE(root_scroll_layer->main_thread_scrolling_reasons());
+ ASSERT_FALSE(root_scroll_layer->GetMainThreadScrollingReasons());
Document* document = GetFrame()->GetDocument();
{
@@ -373,7 +374,7 @@ TEST_P(ScrollingCoordinatorTest, fastScrollingForStickyPosition) {
// Sticky position should not fall back to main thread scrolling.
cc::Layer* root_scroll_layer = GetRootScrollLayer();
ASSERT_TRUE(root_scroll_layer);
- EXPECT_FALSE(root_scroll_layer->main_thread_scrolling_reasons());
+ EXPECT_FALSE(root_scroll_layer->GetMainThreadScrollingReasons());
Document* document = GetFrame()->GetDocument();
{
@@ -1056,16 +1057,9 @@ TEST_P(ScrollingCoordinatorTest, WindowTouchEventHandler) {
}
namespace {
-class ScrollingCoordinatorMockEventListener final : public EventListener {
+class ScrollingCoordinatorMockEventListener final : public NativeEventListener {
public:
- ScrollingCoordinatorMockEventListener()
- : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
- void Invoke(ExecutionContext*, Event*) final {}
+ void Invoke(ExecutionContext*, Event*) override {}
};
} // namespace
@@ -1090,7 +1084,8 @@ TEST_P(ScrollingCoordinatorTest, WindowTouchEventHandlerInvalidation) {
EXPECT_TRUE(region.IsEmpty());
// Adding a blocking window event handler should create a touch action region.
- auto* listener = new ScrollingCoordinatorMockEventListener();
+ auto* listener =
+ MakeGarbageCollected<ScrollingCoordinatorMockEventListener>();
AddEventListenerOptionsResolved* resolved_options =
AddEventListenerOptionsResolved::Create();
resolved_options->setPassive(false);
@@ -1137,8 +1132,8 @@ TEST_P(ScrollingCoordinatorTest, overflowScrolling) {
cc::Layer* cc_scroll_layer =
composited_layer_mapping->ScrollingContentsLayer()->CcLayer();
ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableVertical());
#if defined(OS_ANDROID)
// Now verify we've attached impl-side scrollbars onto the scrollbar layers
@@ -1178,8 +1173,8 @@ TEST_P(ScrollingCoordinatorTest, overflowHidden) {
cc::Layer* cc_scroll_layer =
composited_layer_mapping->ScrollingContentsLayer()->CcLayer();
ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_FALSE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_FALSE(cc_scroll_layer->GetUserScrollableVertical());
overflow_element =
GetFrame()->GetDocument()->getElementById("unscrollable-x");
@@ -1200,8 +1195,8 @@ TEST_P(ScrollingCoordinatorTest, overflowHidden) {
cc_scroll_layer =
composited_layer_mapping->ScrollingContentsLayer()->CcLayer();
ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_FALSE(cc_scroll_layer->user_scrollable_horizontal());
- ASSERT_TRUE(cc_scroll_layer->user_scrollable_vertical());
+ ASSERT_FALSE(cc_scroll_layer->GetUserScrollableHorizontal());
+ ASSERT_TRUE(cc_scroll_layer->GetUserScrollableVertical());
}
TEST_P(ScrollingCoordinatorTest, iframeScrolling) {
@@ -1308,32 +1303,6 @@ TEST_P(ScrollingCoordinatorTest, setupScrollbarLayerShouldNotCrash) {
// an empty document by javascript.
}
-TEST_P(ScrollingCoordinatorTest,
- ScrollbarsForceMainThreadOrHaveCompositorScrollbarLayer) {
- RegisterMockedHttpURLLoad("trivial-scroller.html");
- NavigateTo(base_url_ + "trivial-scroller.html");
- ForceFullCompositingUpdate();
-
- Document* document = GetFrame()->GetDocument();
- Element* scrollable_element = document->getElementById("scroller");
- DCHECK(scrollable_element);
-
- LayoutObject* layout_object = scrollable_element->GetLayoutObject();
- ASSERT_TRUE(layout_object->IsBox());
- LayoutBox* box = ToLayoutBox(layout_object);
- ASSERT_TRUE(box->UsesCompositedScrolling());
- CompositedLayerMapping* composited_layer_mapping =
- box->Layer()->GetCompositedLayerMapping();
- GraphicsLayer* scrollbar_graphics_layer =
- composited_layer_mapping->LayerForVerticalScrollbar();
- ASSERT_TRUE(scrollbar_graphics_layer);
-
- bool has_cc_scrollbar_layer = !scrollbar_graphics_layer->DrawsContent();
- ASSERT_TRUE(
- has_cc_scrollbar_layer ||
- scrollbar_graphics_layer->CcLayer()->main_thread_scrolling_reasons());
-}
-
#if defined(OS_MACOSX) || defined(OS_ANDROID)
TEST_P(ScrollingCoordinatorTest,
DISABLED_setupScrollbarLayerShouldSetScrollLayerOpaque)
@@ -1365,214 +1334,6 @@ TEST_P(ScrollingCoordinatorTest, setupScrollbarLayerShouldSetScrollLayerOpaque)
contents_layer->contents_opaque());
}
-TEST_P(ScrollingCoordinatorTest,
- FixedPositionLosingBackingShouldTriggerMainThreadScroll) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
- RegisterMockedHttpURLLoad("fixed-position-losing-backing.html");
- NavigateTo(base_url_ + "fixed-position-losing-backing.html");
- ForceFullCompositingUpdate();
-
- cc::Layer* scroll_layer = GetRootScrollLayer();
- ASSERT_TRUE(scroll_layer);
-
- Document* document = GetFrame()->GetDocument();
- Element* fixed_pos = document->getElementById("fixed");
-
- EXPECT_TRUE(static_cast<LayoutBoxModelObject*>(fixed_pos->GetLayoutObject())
- ->Layer()
- ->HasCompositedLayerMapping());
- EXPECT_FALSE(scroll_layer->main_thread_scrolling_reasons());
-
- fixed_pos->SetInlineStyleProperty(CSSPropertyTransform, CSSValueNone);
- ForceFullCompositingUpdate();
-
- EXPECT_FALSE(static_cast<LayoutBoxModelObject*>(fixed_pos->GetLayoutObject())
- ->Layer()
- ->HasCompositedLayerMapping());
- EXPECT_TRUE(scroll_layer->main_thread_scrolling_reasons());
-}
-
-TEST_P(ScrollingCoordinatorTest, CustomScrollbarShouldTriggerMainThreadScroll) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
- GetWebView()->SetDeviceScaleFactor(2.f);
- RegisterMockedHttpURLLoad("custom_scrollbar.html");
- NavigateTo(base_url_ + "custom_scrollbar.html");
- ForceFullCompositingUpdate();
-
- Document* document = GetFrame()->GetDocument();
- Element* container = document->getElementById("container");
- Element* content = document->getElementById("content");
- DCHECK_EQ(container->getAttribute(html_names::kClassAttr),
- "custom_scrollbar");
- DCHECK(container);
- DCHECK(content);
-
- LayoutObject* layout_object = container->GetLayoutObject();
- ASSERT_TRUE(layout_object->IsBox());
- LayoutBox* box = ToLayoutBox(layout_object);
- ASSERT_TRUE(box->UsesCompositedScrolling());
- CompositedLayerMapping* composited_layer_mapping =
- box->Layer()->GetCompositedLayerMapping();
- GraphicsLayer* scrollbar_graphics_layer =
- composited_layer_mapping->LayerForVerticalScrollbar();
- ASSERT_TRUE(scrollbar_graphics_layer);
- ASSERT_TRUE(
- scrollbar_graphics_layer->CcLayer()->main_thread_scrolling_reasons());
- ASSERT_TRUE(
- scrollbar_graphics_layer->CcLayer()->main_thread_scrolling_reasons() &
- MainThreadScrollingReason::kCustomScrollbarScrolling);
-
- // remove custom scrollbar class, the scrollbar is expected to scroll on
- // impl thread as it is an overlay scrollbar.
- container->removeAttribute("class");
- ForceFullCompositingUpdate();
- scrollbar_graphics_layer =
- composited_layer_mapping->LayerForVerticalScrollbar();
- ASSERT_FALSE(
- scrollbar_graphics_layer->CcLayer()->main_thread_scrolling_reasons());
- ASSERT_FALSE(
- scrollbar_graphics_layer->CcLayer()->main_thread_scrolling_reasons() &
- MainThreadScrollingReason::kCustomScrollbarScrolling);
-}
-
-TEST_P(ScrollingCoordinatorTest,
- BackgroundAttachmentFixedShouldTriggerMainThreadScroll) {
- RegisterMockedHttpURLLoad("iframe-background-attachment-fixed.html");
- RegisterMockedHttpURLLoad("iframe-background-attachment-fixed-inner.html");
- RegisterMockedHttpURLLoad("white-1x1.png");
- NavigateTo(base_url_ + "iframe-background-attachment-fixed.html");
- ForceFullCompositingUpdate();
-
- Element* iframe = GetFrame()->GetDocument()->getElementById("iframe");
- ASSERT_TRUE(iframe);
-
- LayoutObject* layout_object = iframe->GetLayoutObject();
- ASSERT_TRUE(layout_object);
- ASSERT_TRUE(layout_object->IsLayoutEmbeddedContent());
-
- LayoutEmbeddedContent* layout_embedded_content =
- ToLayoutEmbeddedContent(layout_object);
- ASSERT_TRUE(layout_embedded_content);
-
- LocalFrameView* inner_frame_view =
- ToLocalFrameView(layout_embedded_content->ChildFrameView());
- ASSERT_TRUE(inner_frame_view);
-
- auto* inner_layout_view = inner_frame_view->GetLayoutView();
- ASSERT_TRUE(inner_layout_view);
-
- PaintLayerCompositor* inner_compositor = inner_layout_view->Compositor();
- ASSERT_TRUE(inner_compositor->InCompositingMode());
-
- GraphicsLayer* scroll_layer =
- inner_frame_view->LayoutViewport()->LayerForScrolling();
- ASSERT_TRUE(scroll_layer);
-
- cc::Layer* cc_scroll_layer = scroll_layer->CcLayer();
- ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->main_thread_scrolling_reasons() &
- MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
-
- // Remove fixed background-attachment should make the iframe
- // scroll on cc.
- auto* iframe_doc = ToHTMLIFrameElement(iframe)->contentDocument();
- iframe = iframe_doc->getElementById("scrollable");
- ASSERT_TRUE(iframe);
-
- iframe->removeAttribute("class");
- ForceFullCompositingUpdate();
-
- layout_object = iframe->GetLayoutObject();
- ASSERT_TRUE(layout_object);
-
- scroll_layer =
- layout_object->GetFrameView()->LayoutViewport()->LayerForScrolling();
- ASSERT_TRUE(scroll_layer);
-
- cc_scroll_layer = scroll_layer->CcLayer();
- ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_FALSE(cc_scroll_layer->main_thread_scrolling_reasons() &
- MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
-
- // Force main frame to scroll on main thread. All its descendants
- // should scroll on main thread as well.
- Element* element = GetFrame()->GetDocument()->getElementById("scrollable");
- element->setAttribute(
- "style",
- "background-image: url('white-1x1.png'); background-attachment: fixed;",
- ASSERT_NO_EXCEPTION);
-
- ForceFullCompositingUpdate();
-
- layout_object = iframe->GetLayoutObject();
- ASSERT_TRUE(layout_object);
-
- scroll_layer =
- layout_object->GetFrameView()->LayoutViewport()->LayerForScrolling();
- ASSERT_TRUE(scroll_layer);
-
- cc_scroll_layer = scroll_layer->CcLayer();
- ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(cc_scroll_layer->main_thread_scrolling_reasons() &
- MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
-}
-
-// Upon resizing the content size, the main thread scrolling reason
-// kHasNonLayerViewportConstrainedObject should be updated on all frames
-TEST_P(ScrollingCoordinatorTest,
- RecalculateMainThreadScrollingReasonsUponResize) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
- RegisterMockedHttpURLLoad("has-non-layer-viewport-constrained-objects.html");
- NavigateTo(base_url_ + "has-non-layer-viewport-constrained-objects.html");
- ForceFullCompositingUpdate();
-
- Element* element = GetFrame()->GetDocument()->getElementById("scrollable");
- ASSERT_TRUE(element);
-
- LayoutObject* layout_object = element->GetLayoutObject();
- ASSERT_TRUE(layout_object);
-
- // When the div becomes to scrollable it should scroll on main thread
- element->setAttribute("style",
- "overflow:scroll;height:2000px;will-change:transform;",
- ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
-
- layout_object = element->GetLayoutObject();
- ASSERT_TRUE(layout_object);
-
- GraphicsLayer* scroll_layer =
- layout_object->GetFrameView()->LayoutViewport()->LayerForScrolling();
- ASSERT_TRUE(scroll_layer);
-
- cc::Layer* cc_scroll_layer = scroll_layer->CcLayer();
- ASSERT_TRUE(cc_scroll_layer->scrollable());
- ASSERT_TRUE(
- cc_scroll_layer->main_thread_scrolling_reasons() &
- MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
-
- // The main thread scrolling reason should be reset upon the following change
- element->setAttribute("style",
- "overflow:scroll;height:200px;will-change:transform;",
- ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
-
- layout_object = element->GetLayoutObject();
- ASSERT_TRUE(layout_object);
-}
-
-TEST_P(ScrollingCoordinatorTest, StickyTriggersMainThreadScroll) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
- LoadHTML(
- "<body style='height: 1200px'>"
- "<div style='position: sticky; top: 0'>sticky</div>");
- ForceFullCompositingUpdate();
- ScrollableArea* viewport = GetFrame()->View()->LayoutViewport();
- cc::Layer* scroll_layer = viewport->LayerForScrolling()->CcLayer();
- ASSERT_EQ(MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects,
- scroll_layer->main_thread_scrolling_reasons());
-}
-
// LocalFrameView::FrameIsScrollableDidChange is used as a dirty bit and is
// set to clean in ScrollingCoordinator::UpdateAfterPaint. This test ensures
// that the dirty bit is set and unset properly.
@@ -1637,215 +1398,6 @@ TEST_P(ScrollingCoordinatorTest, UpdateUMAMetricUpdated) {
histogram_tester.ExpectTotalCount("Blink.ScrollingCoordinator.UpdateTime", 2);
}
-class NonCompositedMainThreadScrollingReasonTest
- : public ScrollingCoordinatorTest {
- static const uint32_t kLCDTextRelatedReasons =
- MainThreadScrollingReason::kHasOpacityAndLCDText |
- MainThreadScrollingReason::kHasTransformAndLCDText |
- MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText |
- MainThreadScrollingReason::kIsNotStackingContextAndLCDText;
-
- protected:
- NonCompositedMainThreadScrollingReasonTest() {
- RegisterMockedHttpURLLoad("two_scrollable_area.html");
- NavigateTo(base_url_ + "two_scrollable_area.html");
- }
- void TestNonCompositedReasons(const std::string& target,
- const uint32_t reason) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
- Document* document = GetFrame()->GetDocument();
- Element* container = document->getElementById("scroller1");
- container->setAttribute("class", target.c_str(), ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
-
- PaintLayerScrollableArea* scrollable_area =
- ToLayoutBoxModelObject(container->GetLayoutObject())
- ->GetScrollableArea();
- ASSERT_TRUE(scrollable_area);
- EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- reason);
-
- Element* container2 = document->getElementById("scroller2");
- PaintLayerScrollableArea* scrollable_area2 =
- ToLayoutBoxModelObject(container2->GetLayoutObject())
- ->GetScrollableArea();
- ASSERT_TRUE(scrollable_area2);
- // Different scrollable area should remain unaffected.
- EXPECT_FALSE(
- scrollable_area2->GetNonCompositedMainThreadScrollingReasons() &
- reason);
-
- LocalFrameView* frame_view = GetFrame()->View();
- ASSERT_TRUE(frame_view);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & reason);
-
- // Remove attribute from the scroller 1 would lead to scroll on impl.
- container->removeAttribute("class");
- ForceFullCompositingUpdate();
-
- EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- reason);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & reason);
-
- // Add target attribute would again lead to scroll on main thread
- container->setAttribute("class", target.c_str(), ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
-
- EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- reason);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & reason);
-
- if ((reason & kLCDTextRelatedReasons) &&
- !(reason & ~kLCDTextRelatedReasons)) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
- ForceFullCompositingUpdate();
- EXPECT_FALSE(
- scrollable_area->GetNonCompositedMainThreadScrollingReasons());
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons());
- }
- }
-};
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, TransparentTest) {
- TestNonCompositedReasons("transparent",
- MainThreadScrollingReason::kHasOpacityAndLCDText);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, TransformTest) {
- TestNonCompositedReasons("transform",
- MainThreadScrollingReason::kHasTransformAndLCDText);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, BackgroundNotOpaqueTest) {
- TestNonCompositedReasons(
- "background-not-opaque",
- MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, ClipTest) {
- TestNonCompositedReasons("clip",
- MainThreadScrollingReason::kHasClipRelatedProperty);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, ClipPathTest) {
- uint32_t clip_reason = MainThreadScrollingReason::kHasClipRelatedProperty;
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
- Document* document = GetFrame()->GetDocument();
- // Test ancestor with ClipPath
- Element* element = document->body();
- ASSERT_TRUE(element);
- element->setAttribute(html_names::kStyleAttr,
- "clip-path:circle(115px at 20px 20px);");
- Element* container = document->getElementById("scroller1");
- ASSERT_TRUE(container);
- ForceFullCompositingUpdate();
-
- PaintLayerScrollableArea* scrollable_area =
- ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea();
- ASSERT_TRUE(scrollable_area);
- EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- clip_reason);
-
- LocalFrameView* frame_view = GetFrame()->View();
- ASSERT_TRUE(frame_view);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & clip_reason);
-
- // Remove clip path from ancestor.
- element->removeAttribute(html_names::kStyleAttr);
- ForceFullCompositingUpdate();
-
- EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- clip_reason);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & clip_reason);
-
- // Test descendant with ClipPath
- element = document->getElementById("content1");
- ASSERT_TRUE(element);
- element->setAttribute(html_names::kStyleAttr,
- "clip-path:circle(115px at 20px 20px);");
- ForceFullCompositingUpdate();
- EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- clip_reason);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & clip_reason);
-
- // Remove clip path from descendant.
- element->removeAttribute(html_names::kStyleAttr);
- ForceFullCompositingUpdate();
- EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- clip_reason);
- EXPECT_FALSE(frame_view->GetMainThreadScrollingReasons() & clip_reason);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, LCDTextEnabledTest) {
- TestNonCompositedReasons("transparent",
- MainThreadScrollingReason::kHasOpacityAndLCDText);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, BoxShadowTest) {
- TestNonCompositedReasons(
- "box-shadow", MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer);
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest, StackingContextTest) {
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
-
- Document* document = GetFrame()->GetDocument();
- Element* container = document->getElementById("scroller1");
- ASSERT_TRUE(container);
-
- ForceFullCompositingUpdate();
-
- // If a scroller contains all its children, it's not a stacking context.
- PaintLayerScrollableArea* scrollable_area =
- ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea();
- ASSERT_TRUE(scrollable_area);
- EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- MainThreadScrollingReason::kIsNotStackingContextAndLCDText);
-
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
- ForceFullCompositingUpdate();
- EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() &
- MainThreadScrollingReason::kIsNotStackingContextAndLCDText);
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
-
- // Adding "contain: paint" to force a stacking context leads to promotion.
- container->setAttribute("style", "contain: paint", ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
-
- EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons());
-}
-
-TEST_P(NonCompositedMainThreadScrollingReasonTest,
- CompositedWithLCDTextRelatedReasonsTest) {
- // With "will-change:transform" we composite elements with
- // LCDTextRelatedReasons only. For elements with other
- // NonCompositedReasons, we don't create scrollingLayer for their
- // CompositedLayerMapping therefore they don't get composited.
- GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
- Document* document = GetFrame()->GetDocument();
- Element* container = document->getElementById("scroller1");
- ASSERT_TRUE(container);
- container->setAttribute("class", "composited transparent",
- ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
-
- PaintLayerScrollableArea* scrollable_area =
- ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea();
- ASSERT_TRUE(scrollable_area);
- EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons());
-
- Element* container2 = document->getElementById("scroller2");
- ASSERT_TRUE(container2);
- container2->setAttribute("class", "composited border-radius",
- ASSERT_NO_EXCEPTION);
- ForceFullCompositingUpdate();
- PaintLayerScrollableArea* scrollable_area2 =
- ToLayoutBoxModelObject(container2->GetLayoutObject())
- ->GetScrollableArea();
- ASSERT_TRUE(scrollable_area2);
- ASSERT_TRUE(scrollable_area2->UsesCompositedScrolling());
-}
-
class ScrollingCoordinatorTestWithAcceleratedContext
: public ScrollingCoordinatorTest {
public:
@@ -1874,9 +1426,14 @@ class ScrollingCoordinatorTestWithAcceleratedContext
FakeGLES2Interface gl_;
};
-INSTANTIATE_TEST_CASE_P(All,
- ScrollingCoordinatorTestWithAcceleratedContext,
- ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(
+ All,
+ ScrollingCoordinatorTestWithAcceleratedContext,
+ ::testing::Values(kScrollingCoordinatorTestNoFlags,
+ kScrollingCoordinatorTestBlinkGenPropertyTrees,
+ kScrollingCoordinatorTestPaintTouchActionRects,
+ (kScrollingCoordinatorTestBlinkGenPropertyTrees |
+ kScrollingCoordinatorTestPaintTouchActionRects)));
TEST_P(ScrollingCoordinatorTestWithAcceleratedContext, CanvasTouchActionRects) {
LoadHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc b/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc
index 0968175f9a3..fc6a9b3ec7b 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc
@@ -255,16 +255,24 @@ base::Optional<FloatPoint> SnapCoordinator::GetSnapPosition(
return base::nullopt;
}
-bool SnapCoordinator::SnapForEndPosition(const LayoutBox& snap_container,
- bool scrolled_x,
- bool scrolled_y) const {
+bool SnapCoordinator::SnapAtCurrentPosition(const LayoutBox& snap_container,
+ bool scrolled_x,
+ bool scrolled_y) const {
ScrollableArea* scrollable_area = ScrollableAreaForSnapping(snap_container);
if (!scrollable_area)
return false;
FloatPoint current_position = scrollable_area->ScrollPosition();
+ return SnapForEndPosition(snap_container, current_position, scrolled_x,
+ scrolled_y);
+}
+
+bool SnapCoordinator::SnapForEndPosition(const LayoutBox& snap_container,
+ const FloatPoint& end_position,
+ bool scrolled_x,
+ bool scrolled_y) const {
std::unique_ptr<SnapSelectionStrategy> strategy =
SnapSelectionStrategy::CreateForEndPosition(
- gfx::ScrollOffset(current_position), scrolled_x, scrolled_y);
+ gfx::ScrollOffset(end_position), scrolled_x, scrolled_y);
return PerformSnapping(snap_container, *strategy);
}
@@ -281,6 +289,19 @@ bool SnapCoordinator::SnapForDirection(const LayoutBox& snap_container,
return PerformSnapping(snap_container, *strategy);
}
+bool SnapCoordinator::SnapForEndAndDirection(const LayoutBox& snap_container,
+ const ScrollOffset& delta) const {
+ ScrollableArea* scrollable_area = ScrollableAreaForSnapping(snap_container);
+ if (!scrollable_area)
+ return false;
+ FloatPoint current_position = scrollable_area->ScrollPosition();
+ std::unique_ptr<SnapSelectionStrategy> strategy =
+ SnapSelectionStrategy::CreateForEndAndDirection(
+ gfx::ScrollOffset(current_position),
+ gfx::ScrollOffset(delta.Width(), delta.Height()));
+ return PerformSnapping(snap_container, *strategy);
+}
+
bool SnapCoordinator::PerformSnapping(
const LayoutBox& snap_container,
const SnapSelectionStrategy& strategy) const {
@@ -295,7 +316,7 @@ bool SnapCoordinator::PerformSnapping(
scrollable_area->CancelScrollAnimation();
scrollable_area->CancelProgrammaticScrollAnimation();
- if (gfx::ScrollOffset(snap_point.value()) != strategy.current_position()) {
+ if (snap_point.value() != scrollable_area->ScrollPosition()) {
scrollable_area->SetScrollOffset(
scrollable_area->ScrollPositionToOffset(snap_point.value()),
kProgrammaticScroll, kScrollBehaviorSmooth);
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h b/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
index d4e3b0e74f5..3d811bb6bec 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
@@ -53,13 +53,22 @@ class CORE_EXPORT SnapCoordinator final
void UpdateAllSnapContainerData();
void UpdateSnapContainerData(const LayoutBox&);
- // SnapForEndPosition() and SnapForDirection() return true if snapping was
- // performed, and false otherwise.
+ // SnapAtCurrentPosition(), SnapForEndPosition(), SnapForDirection(), and
+ // SnapForEndAndDirection() return true if snapping was performed, and false
+ // otherwise.
+ // SnapAtCurrentPosition() calls SnapForEndPosition() with the current scroll
+ // position.
+ bool SnapAtCurrentPosition(const LayoutBox& snap_container,
+ bool scrolled_x,
+ bool scrolled_y) const;
bool SnapForEndPosition(const LayoutBox& snap_container,
+ const FloatPoint& end_position,
bool scrolled_x,
bool scrolled_y) const;
bool SnapForDirection(const LayoutBox& snap_container,
const ScrollOffset& delta) const;
+ bool SnapForEndAndDirection(const LayoutBox& snap_container,
+ const ScrollOffset& delta) const;
base::Optional<FloatPoint> GetSnapPosition(
const LayoutBox& snap_container,
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h b/chromium/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h
index 42a1494b574..db5b682ec9d 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h
@@ -93,7 +93,7 @@ struct StickyPositionScrollingConstraints final {
//
// This method exists for performance (to avoid recomputing the sticky offset)
// and must only be called when compositing inputs are clean for the sticky
- // element. (Or after prepaint for SlimmingPaintV2).
+ // element. (Or after prepaint for CompositeAfterPaint).
FloatSize GetOffsetForStickyPosition(const StickyConstraintsMap&) const;
bool is_anchored_left : 1;
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc
index 1f2aa290b65..6f5dd1d533e 100644
--- a/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -48,11 +48,9 @@ namespace blink {
static void DeflateIfOverlapped(LayoutRect&, LayoutRect&);
-FocusCandidate::FocusCandidate(Node* node, WebFocusType direction)
+FocusCandidate::FocusCandidate(Node* node, SpatialNavigationDirection direction)
: visible_node(nullptr),
focusable_node(nullptr),
- enclosing_scrollable_box(nullptr),
- distance(MaxDistance()),
is_offscreen(true),
is_offscreen_after_scrolling(true) {
DCHECK(node);
@@ -89,15 +87,15 @@ bool SpatialNavigationIgnoresEventHandlers(const LocalFrame* frame) {
frame->GetSettings()->GetDeviceSupportsTouch());
}
-static bool RectsIntersectOnOrthogonalAxis(WebFocusType direction,
+static bool RectsIntersectOnOrthogonalAxis(SpatialNavigationDirection direction,
const LayoutRect& a,
const LayoutRect& b) {
switch (direction) {
- case kWebFocusTypeLeft:
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kLeft:
+ case SpatialNavigationDirection::kRight:
return a.MaxY() > b.Y() && a.Y() < b.MaxY();
- case kWebFocusTypeUp:
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kUp:
+ case SpatialNavigationDirection::kDown:
return a.MaxX() > b.X() && a.X() < b.MaxX();
default:
NOTREACHED();
@@ -121,17 +119,17 @@ static inline bool RightOf(const LayoutRect& a, const LayoutRect& b) {
a.Y() < b.MaxY() && a.MaxY() > b.Y());
}
-static bool IsRectInDirection(WebFocusType direction,
+static bool IsRectInDirection(SpatialNavigationDirection direction,
const LayoutRect& cur_rect,
const LayoutRect& target_rect) {
switch (direction) {
- case kWebFocusTypeLeft:
+ case SpatialNavigationDirection::kLeft:
return RightOf(cur_rect, target_rect);
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kRight:
return RightOf(target_rect, cur_rect);
- case kWebFocusTypeUp:
+ case SpatialNavigationDirection::kUp:
return Below(cur_rect, target_rect);
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kDown:
return Below(target_rect, cur_rect);
default:
NOTREACHED();
@@ -149,6 +147,8 @@ static bool IsRectInDirection(WebFocusType direction,
// account, spatnav could have called it directly; no need to check the
// LayoutObject's VisibleContentRect.
bool IsOffscreen(const Node* node) {
+ DCHECK(node);
+
LocalFrameView* frame_view = node->GetDocument().View();
if (!frame_view)
return true;
@@ -166,7 +166,8 @@ bool IsOffscreen(const Node* node) {
if (rect.IsEmpty())
return true;
- if (!frame_viewport.Intersects(rect))
+ // A document always intersects with its frame's viewport.
+ if (node != node->GetDocument() && !frame_viewport.Intersects(rect))
return true;
// Now we know that the node is visible in the its own frame's viewport (it is
@@ -176,14 +177,15 @@ bool IsOffscreen(const Node* node) {
IntRect rect_in_root_frame;
if (auto* document = DynamicTo<Document>(node))
node = document->body();
- if (node->IsElementNode())
+ if (node && node->IsElementNode())
rect_in_root_frame = ToElement(*node).VisibleBoundsInVisualViewport();
return rect_in_root_frame.IsEmpty();
}
// As IsOffscreen() but returns visibility through the |node|'s frame's viewport
// after scrolling the frame in |direction|.
-bool IsOffscreenAfterFrameScroll(const Node* node, WebFocusType direction) {
+bool IsOffscreenAfterFrameScroll(const Node* node,
+ SpatialNavigationDirection direction) {
LocalFrameView* frame_view = node->GetDocument().View();
if (!frame_view)
return true;
@@ -201,18 +203,18 @@ bool IsOffscreenAfterFrameScroll(const Node* node, WebFocusType direction) {
int pixels_per_line_step =
ScrollableArea::PixelsPerLineStep(frame_view->GetChromeClient());
switch (direction) {
- case kWebFocusTypeLeft:
+ case SpatialNavigationDirection::kLeft:
frame_viewport.SetX(frame_viewport.X() - pixels_per_line_step);
frame_viewport.SetWidth(frame_viewport.Width() + pixels_per_line_step);
break;
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kRight:
frame_viewport.SetWidth(frame_viewport.Width() + pixels_per_line_step);
break;
- case kWebFocusTypeUp:
+ case SpatialNavigationDirection::kUp:
frame_viewport.SetY(frame_viewport.Y() - pixels_per_line_step);
frame_viewport.SetHeight(frame_viewport.Height() + pixels_per_line_step);
break;
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kDown:
frame_viewport.SetHeight(frame_viewport.Height() + pixels_per_line_step);
break;
default:
@@ -239,83 +241,55 @@ bool HasRemoteFrame(const Node* node) {
ToHTMLFrameOwnerElement(node)->ContentFrame()->IsRemoteFrame();
}
-bool ScrollInDirection(LocalFrame* frame, WebFocusType direction) {
- DCHECK(frame);
-
- if (frame && CanScrollInDirection(frame->GetDocument(), direction)) {
- int dx = 0;
- int dy = 0;
- int pixels_per_line_step =
- ScrollableArea::PixelsPerLineStep(frame->View()->GetChromeClient());
- switch (direction) {
- case kWebFocusTypeLeft:
- dx = -pixels_per_line_step;
- break;
- case kWebFocusTypeRight:
- dx = pixels_per_line_step;
- break;
- case kWebFocusTypeUp:
- dy = -pixels_per_line_step;
- break;
- case kWebFocusTypeDown:
- dy = pixels_per_line_step;
- break;
- default:
- NOTREACHED();
- return false;
- }
-
- frame->View()->GetScrollableArea()->ScrollBy(ScrollOffset(dx, dy),
- kUserScroll);
- return true;
- }
- return false;
-}
-
-bool ScrollInDirection(Node* container, WebFocusType direction) {
+bool ScrollInDirection(Node* container, SpatialNavigationDirection direction) {
DCHECK(container);
- if (auto* document = DynamicTo<Document>(container))
- return ScrollInDirection(document->GetFrame(), direction);
if (!container->GetLayoutBox())
return false;
- if (CanScrollInDirection(container, direction)) {
- int dx = 0;
- int dy = 0;
- // TODO(leviw): Why are these values truncated (toInt) instead of rounding?
- LocalFrameView* frame_view = container->GetDocument().View();
- int pixels_per_line_step = ScrollableArea::PixelsPerLineStep(
- frame_view ? frame_view->GetChromeClient() : nullptr);
- switch (direction) {
- case kWebFocusTypeLeft:
- dx = -pixels_per_line_step;
- break;
- case kWebFocusTypeRight:
- DCHECK_GT(container->GetLayoutBox()->ScrollWidth(),
- (container->GetLayoutBox()->ScrollLeft() +
- container->GetLayoutBox()->ClientWidth()));
- dx = pixels_per_line_step;
- break;
- case kWebFocusTypeUp:
- dy = -pixels_per_line_step;
- break;
- case kWebFocusTypeDown:
- DCHECK(container->GetLayoutBox()->ScrollHeight() -
- (container->GetLayoutBox()->ScrollTop() +
- container->GetLayoutBox()->ClientHeight()));
- dy = pixels_per_line_step;
- break;
- default:
- NOTREACHED();
- return false;
- }
+ if (!container->GetLayoutBox()->GetScrollableArea())
+ return false;
- container->GetLayoutBox()->ScrollByRecursively(ScrollOffset(dx, dy));
- return true;
+ if (!CanScrollInDirection(container, direction))
+ return false;
+
+ int dx = 0;
+ int dy = 0;
+ int pixels_per_line_step = ScrollableArea::PixelsPerLineStep(
+ container->GetDocument().GetFrame()->View()->GetChromeClient());
+ switch (direction) {
+ case SpatialNavigationDirection::kLeft:
+ dx = -pixels_per_line_step;
+ break;
+ case SpatialNavigationDirection::kRight:
+ DCHECK_GT(container->GetLayoutBox()->ScrollWidth(),
+ container->GetLayoutBox()->ScrollLeft() +
+ container->GetLayoutBox()->ClientWidth());
+ dx = pixels_per_line_step;
+ break;
+ case SpatialNavigationDirection::kUp:
+ dy = -pixels_per_line_step;
+ break;
+ case SpatialNavigationDirection::kDown:
+ DCHECK_GT(container->GetLayoutBox()->ScrollHeight(),
+ container->GetLayoutBox()->ScrollTop() +
+ container->GetLayoutBox()->ClientHeight());
+ dy = pixels_per_line_step;
+ break;
+ default:
+ NOTREACHED();
+ return false;
}
- return false;
+ // TODO(crbug.com/914775): Use UserScroll() instead. UserScroll() does a
+ // smooth, animated scroll which might make it easier for users to understand
+ // spatnav's moves. Another advantage of using ScrollableArea::UserScroll() is
+ // that it returns a ScrollResult so we don't need to call
+ // CanScrollInDirection(). Regular arrow-key scrolling (without
+ // --enable-spatial-navigation) already uses smooth scrolling by default.
+ container->GetLayoutBox()->GetScrollableArea()->ScrollBy(ScrollOffset(dx, dy),
+ kUserScroll);
+ return true;
}
static void DeflateIfOverlapped(LayoutRect& a, LayoutRect& b) {
@@ -372,17 +346,8 @@ bool IsScrollableAreaOrDocument(const Node* node) {
IsScrollableNode(node);
}
-bool IsNavigableContainer(const Node* node, WebFocusType direction) {
- if (!node)
- return false;
-
- return node->IsDocumentNode() ||
- (node->IsFrameOwnerElement() &&
- ToHTMLFrameOwnerElement(node)->ContentFrame()) ||
- CanScrollInDirection(node, direction);
-}
-
-bool CanScrollInDirection(const Node* container, WebFocusType direction) {
+bool CanScrollInDirection(const Node* container,
+ SpatialNavigationDirection direction) {
DCHECK(container);
if (auto* document = DynamicTo<Document>(container))
return CanScrollInDirection(document->GetFrame(), direction);
@@ -391,21 +356,21 @@ bool CanScrollInDirection(const Node* container, WebFocusType direction) {
return false;
switch (direction) {
- case kWebFocusTypeLeft:
+ case SpatialNavigationDirection::kLeft:
return (container->GetLayoutObject()->Style()->OverflowX() !=
EOverflow::kHidden &&
container->GetLayoutBox()->ScrollLeft() > 0);
- case kWebFocusTypeUp:
+ case SpatialNavigationDirection::kUp:
return (container->GetLayoutObject()->Style()->OverflowY() !=
EOverflow::kHidden &&
container->GetLayoutBox()->ScrollTop() > 0);
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kRight:
return (container->GetLayoutObject()->Style()->OverflowX() !=
EOverflow::kHidden &&
container->GetLayoutBox()->ScrollLeft() +
container->GetLayoutBox()->ClientWidth() <
container->GetLayoutBox()->ScrollWidth());
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kDown:
return (container->GetLayoutObject()->Style()->OverflowY() !=
EOverflow::kHidden &&
container->GetLayoutBox()->ScrollTop() +
@@ -417,7 +382,8 @@ bool CanScrollInDirection(const Node* container, WebFocusType direction) {
}
}
-bool CanScrollInDirection(const LocalFrame* frame, WebFocusType direction) {
+bool CanScrollInDirection(const LocalFrame* frame,
+ SpatialNavigationDirection direction) {
if (!frame->View())
return false;
LayoutView* layoutView = frame->ContentLayoutObject();
@@ -426,10 +392,12 @@ bool CanScrollInDirection(const LocalFrame* frame, WebFocusType direction) {
ScrollbarMode vertical_mode;
ScrollbarMode horizontal_mode;
layoutView->CalculateScrollbarModes(horizontal_mode, vertical_mode);
- if ((direction == kWebFocusTypeLeft || direction == kWebFocusTypeRight) &&
+ if ((direction == SpatialNavigationDirection::kLeft ||
+ direction == SpatialNavigationDirection::kRight) &&
kScrollbarAlwaysOff == horizontal_mode)
return false;
- if ((direction == kWebFocusTypeUp || direction == kWebFocusTypeDown) &&
+ if ((direction == SpatialNavigationDirection::kUp ||
+ direction == SpatialNavigationDirection::kDown) &&
kScrollbarAlwaysOff == vertical_mode)
return false;
ScrollableArea* scrollable_area = frame->View()->GetScrollableArea();
@@ -438,13 +406,13 @@ bool CanScrollInDirection(const LocalFrame* frame, WebFocusType direction) {
LayoutRect rect(scrollable_area->VisibleContentRect(kIncludeScrollbars));
switch (direction) {
- case kWebFocusTypeLeft:
+ case SpatialNavigationDirection::kLeft:
return offset.Width() > 0;
- case kWebFocusTypeUp:
+ case SpatialNavigationDirection::kUp:
return offset.Height() > 0;
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kRight:
return rect.Width() + offset.Width() < size.Width();
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kDown:
return rect.Height() + offset.Height() < size.Height();
default:
NOTREACHED();
@@ -479,34 +447,34 @@ LayoutRect NodeRectInRootFrame(const Node* node, bool ignore_border) {
// into the candidate rect. The line between those 2 points is the closest
// distance between the 2 rects. Takes care of overlapping rects, defining
// points so that the distance between them is zero where necessary.
-void EntryAndExitPointsForDirection(WebFocusType direction,
+void EntryAndExitPointsForDirection(SpatialNavigationDirection direction,
const LayoutRect& starting_rect,
const LayoutRect& potential_rect,
LayoutPoint& exit_point,
LayoutPoint& entry_point) {
switch (direction) {
- case kWebFocusTypeLeft:
+ case SpatialNavigationDirection::kLeft:
exit_point.SetX(starting_rect.X());
if (potential_rect.MaxX() < starting_rect.X())
entry_point.SetX(potential_rect.MaxX());
else
entry_point.SetX(starting_rect.X());
break;
- case kWebFocusTypeUp:
+ case SpatialNavigationDirection::kUp:
exit_point.SetY(starting_rect.Y());
if (potential_rect.MaxY() < starting_rect.Y())
entry_point.SetY(potential_rect.MaxY());
else
entry_point.SetY(starting_rect.Y());
break;
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kRight:
exit_point.SetX(starting_rect.MaxX());
if (potential_rect.X() > starting_rect.MaxX())
entry_point.SetX(potential_rect.X());
else
entry_point.SetX(starting_rect.MaxX());
break;
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kDown:
exit_point.SetY(starting_rect.MaxY());
if (potential_rect.Y() > starting_rect.MaxY())
entry_point.SetY(potential_rect.Y());
@@ -518,8 +486,8 @@ void EntryAndExitPointsForDirection(WebFocusType direction,
}
switch (direction) {
- case kWebFocusTypeLeft:
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kLeft:
+ case SpatialNavigationDirection::kRight:
if (Below(starting_rect, potential_rect)) {
exit_point.SetY(starting_rect.Y());
if (potential_rect.MaxY() < starting_rect.Y())
@@ -537,8 +505,8 @@ void EntryAndExitPointsForDirection(WebFocusType direction,
entry_point.SetY(exit_point.Y());
}
break;
- case kWebFocusTypeUp:
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kUp:
+ case SpatialNavigationDirection::kDown:
if (RightOf(starting_rect, potential_rect)) {
exit_point.SetX(starting_rect.X());
if (potential_rect.MaxX() < starting_rect.X())
@@ -589,25 +557,26 @@ bool AreElementsOnSameLine(const FocusCandidate& first_candidate,
return true;
}
-void DistanceDataForNode(WebFocusType direction,
- const FocusCandidate& current,
- FocusCandidate& candidate) {
- if (!IsRectInDirection(direction, current.rect_in_root_frame,
+double ComputeDistanceDataForNode(SpatialNavigationDirection direction,
+ const FocusCandidate& current_interest,
+ const FocusCandidate& candidate) {
+ if (!IsRectInDirection(direction, current_interest.rect_in_root_frame,
candidate.rect_in_root_frame))
- return;
-
- if (AreElementsOnSameLine(current, candidate)) {
- if ((direction == kWebFocusTypeUp &&
- current.rect_in_root_frame.Y() > candidate.rect_in_root_frame.Y()) ||
- (direction == kWebFocusTypeDown &&
- candidate.rect_in_root_frame.Y() > current.rect_in_root_frame.Y())) {
- candidate.distance = 0;
- return;
+ return MaxDistance();
+
+ if (AreElementsOnSameLine(current_interest, candidate)) {
+ if ((direction == SpatialNavigationDirection::kUp &&
+ current_interest.rect_in_root_frame.Y() >
+ candidate.rect_in_root_frame.Y()) ||
+ (direction == SpatialNavigationDirection::kDown &&
+ candidate.rect_in_root_frame.Y() >
+ current_interest.rect_in_root_frame.Y())) {
+ return 0.0;
}
}
LayoutRect node_rect = candidate.rect_in_root_frame;
- LayoutRect current_rect = current.rect_in_root_frame;
+ LayoutRect current_rect = current_interest.rect_in_root_frame;
DeflateIfOverlapped(current_rect, node_rect);
LayoutPoint exit_point;
@@ -633,16 +602,16 @@ void DistanceDataForNode(WebFocusType direction,
int orthogonal_bias = 0;
switch (direction) {
- case kWebFocusTypeLeft:
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kLeft:
+ case SpatialNavigationDirection::kRight:
navigation_axis_distance = x_axis;
if (!RectsIntersectOnOrthogonalAxis(direction, current_rect, node_rect))
orthogonal_bias = (current_rect.Height() / 2).ToInt();
weighted_orthogonal_axis_distance =
(y_axis + orthogonal_bias) * kOrthogonalWeightForLeftRight;
break;
- case kWebFocusTypeUp:
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kUp:
+ case SpatialNavigationDirection::kDown:
navigation_axis_distance = y_axis;
if (!RectsIntersectOnOrthogonalAxis(direction, current_rect, node_rect))
orthogonal_bias = (current_rect.Width() / 2).ToInt();
@@ -651,7 +620,7 @@ void DistanceDataForNode(WebFocusType direction,
break;
default:
NOTREACHED();
- return;
+ return MaxDistance();
}
double euclidian_distance_pow2 =
@@ -661,59 +630,27 @@ void DistanceDataForNode(WebFocusType direction,
(intersection_rect.Width() * intersection_rect.Height()).ToDouble();
// Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling
- candidate.distance = sqrt(euclidian_distance_pow2) +
- navigation_axis_distance +
- weighted_orthogonal_axis_distance - sqrt(overlap);
-}
-
-bool CanBeScrolledIntoView(WebFocusType direction,
- const FocusCandidate& candidate) {
- DCHECK(candidate.visible_node);
- DCHECK(candidate.is_offscreen);
- LayoutRect candidate_rect = candidate.rect_in_root_frame;
- // TODO(ecobos@igalia.com): Investigate interaction with Shadow DOM.
- for (Node& parent_node :
- NodeTraversal::AncestorsOf(*candidate.visible_node)) {
- if (UNLIKELY(!parent_node.GetLayoutObject())) {
- DCHECK(parent_node.IsElementNode() &&
- ToElement(parent_node).HasDisplayContentsStyle());
- continue;
- }
-
- LayoutRect parent_rect = NodeRectInRootFrame(&parent_node);
- if (!candidate_rect.Intersects(parent_rect)) {
- if (((direction == kWebFocusTypeLeft ||
- direction == kWebFocusTypeRight) &&
- parent_node.GetLayoutObject()->Style()->OverflowX() ==
- EOverflow::kHidden) ||
- ((direction == kWebFocusTypeUp || direction == kWebFocusTypeDown) &&
- parent_node.GetLayoutObject()->Style()->OverflowY() ==
- EOverflow::kHidden))
- return false;
- }
- if (parent_node == candidate.enclosing_scrollable_box)
- return CanScrollInDirection(&parent_node, direction);
- }
- return true;
+ return sqrt(euclidian_distance_pow2) + navigation_axis_distance +
+ weighted_orthogonal_axis_distance - sqrt(overlap);
}
// Returns a thin rectangle that represents one of box's sides.
-LayoutRect OppositeEdge(WebFocusType side,
+LayoutRect OppositeEdge(SpatialNavigationDirection side,
const LayoutRect& box,
LayoutUnit thickness) {
LayoutRect thin_rect = box;
switch (side) {
- case kWebFocusTypeLeft:
+ case SpatialNavigationDirection::kLeft:
thin_rect.SetX(thin_rect.MaxX() - thickness);
thin_rect.SetWidth(thickness);
break;
- case kWebFocusTypeRight:
+ case SpatialNavigationDirection::kRight:
thin_rect.SetWidth(thickness);
break;
- case kWebFocusTypeDown:
+ case SpatialNavigationDirection::kDown:
thin_rect.SetHeight(thickness);
break;
- case kWebFocusTypeUp:
+ case SpatialNavigationDirection::kUp:
thin_rect.SetY(thin_rect.MaxY() - thickness);
thin_rect.SetHeight(thickness);
break;
@@ -725,7 +662,7 @@ LayoutRect OppositeEdge(WebFocusType side,
}
LayoutRect StartEdgeForAreaElement(const HTMLAreaElement& area,
- WebFocusType direction) {
+ SpatialNavigationDirection direction) {
DCHECK(area.ImageElement());
// Area elements tend to overlap more than other focusable elements. We
// flatten the rect of the area elements to minimize the effect of overlapping
@@ -738,7 +675,7 @@ LayoutRect StartEdgeForAreaElement(const HTMLAreaElement& area,
return rect;
}
-HTMLFrameOwnerElement* FrameOwnerElement(FocusCandidate& candidate) {
+HTMLFrameOwnerElement* FrameOwnerElement(const FocusCandidate& candidate) {
return candidate.IsFrameOwnerElement()
? ToHTMLFrameOwnerElement(candidate.visible_node)
: nullptr;
@@ -759,7 +696,7 @@ LayoutRect RootViewport(const LocalFrame* current_frame) {
// a visible scrollable area.
LayoutRect SearchOrigin(const LayoutRect viewport_rect_of_root_frame,
Node* focus_node,
- const WebFocusType direction) {
+ const SpatialNavigationDirection direction) {
if (!focus_node) {
// Search from one of the visual viewport's edges towards the navigated
// direction. For example, UP makes spatnav search upwards, starting at the
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation.h b/chromium/third_party/blink/renderer/core/page/spatial_navigation.h
index 7fe916358b1..22aefc9819c 100644
--- a/chromium/third_party/blink/renderer/core/page/spatial_navigation.h
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -34,6 +34,8 @@ class LocalFrame;
class HTMLAreaElement;
class HTMLFrameOwnerElement;
+enum class SpatialNavigationDirection { kNone, kUp, kRight, kDown, kLeft };
+
inline double MaxDistance() {
return std::numeric_limits<double>::max();
}
@@ -52,17 +54,12 @@ struct FocusCandidate {
FocusCandidate()
: visible_node(nullptr),
focusable_node(nullptr),
- enclosing_scrollable_box(nullptr),
- distance(MaxDistance()),
is_offscreen(true),
is_offscreen_after_scrolling(true) {}
- FocusCandidate(Node*, WebFocusType);
- explicit FocusCandidate(HTMLAreaElement*, WebFocusType);
+ FocusCandidate(Node*, SpatialNavigationDirection);
+ explicit FocusCandidate(HTMLAreaElement*, SpatialNavigationDirection);
bool IsNull() const { return !visible_node; }
- bool InScrollableContainer() const {
- return visible_node && enclosing_scrollable_box;
- }
bool IsFrameOwnerElement() const {
return visible_node && visible_node->IsFrameOwnerElement();
}
@@ -76,8 +73,6 @@ struct FocusCandidate {
// visibleNode and focusableNode are one and the same.
Member<Node> visible_node;
Member<Node> focusable_node;
- Member<Node> enclosing_scrollable_box;
- double distance;
LayoutRect rect_in_root_frame;
bool is_offscreen;
bool is_offscreen_after_scrolling;
@@ -85,32 +80,32 @@ struct FocusCandidate {
CORE_EXPORT bool HasRemoteFrame(const Node*);
CORE_EXPORT bool IsOffscreen(const Node*);
-CORE_EXPORT bool IsOffscreenAfterFrameScroll(const Node*, WebFocusType);
-bool ScrollInDirection(LocalFrame*, WebFocusType);
-bool ScrollInDirection(Node* container, WebFocusType);
-bool IsNavigableContainer(const Node*, WebFocusType);
+CORE_EXPORT bool IsOffscreenAfterFrameScroll(const Node*,
+ SpatialNavigationDirection);
+bool ScrollInDirection(Node* container, SpatialNavigationDirection);
CORE_EXPORT bool IsScrollableNode(const Node* node);
CORE_EXPORT bool IsScrollableAreaOrDocument(const Node*);
CORE_EXPORT Node* ScrollableAreaOrDocumentOf(Node*);
-bool CanScrollInDirection(const Node* container, WebFocusType);
-bool CanScrollInDirection(const LocalFrame*, WebFocusType);
-bool CanBeScrolledIntoView(WebFocusType, const FocusCandidate&);
+bool CanScrollInDirection(const Node* container, SpatialNavigationDirection);
+bool CanScrollInDirection(const LocalFrame*, SpatialNavigationDirection);
bool AreElementsOnSameLine(const FocusCandidate& first_candidate,
const FocusCandidate& second_candidate);
-void DistanceDataForNode(WebFocusType,
- const FocusCandidate& current,
- FocusCandidate&);
+
+double ComputeDistanceDataForNode(SpatialNavigationDirection,
+ const FocusCandidate& current_interest,
+ const FocusCandidate& candidate);
CORE_EXPORT LayoutRect NodeRectInRootFrame(const Node*,
bool ignore_border = false);
-CORE_EXPORT LayoutRect OppositeEdge(WebFocusType side,
+CORE_EXPORT LayoutRect OppositeEdge(SpatialNavigationDirection side,
const LayoutRect& box,
LayoutUnit thickness = LayoutUnit());
CORE_EXPORT LayoutRect RootViewport(const LocalFrame*);
-LayoutRect StartEdgeForAreaElement(const HTMLAreaElement&, WebFocusType);
-HTMLFrameOwnerElement* FrameOwnerElement(FocusCandidate&);
+LayoutRect StartEdgeForAreaElement(const HTMLAreaElement&,
+ SpatialNavigationDirection);
+HTMLFrameOwnerElement* FrameOwnerElement(const FocusCandidate&);
CORE_EXPORT LayoutRect SearchOrigin(const LayoutRect,
Node*,
- const WebFocusType);
+ const SpatialNavigationDirection);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
new file mode 100644
index 00000000000..dd91af1f49f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -0,0 +1,407 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
+
+#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/layout/hit_test_location.h"
+#include "third_party/blink/renderer/core/layout/hit_test_result.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/page/focus_controller.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation.h"
+#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+
+#include "third_party/blink/renderer/core/css/style_change_reason.h"
+
+namespace blink {
+
+namespace {
+
+SpatialNavigationDirection FocusDirectionForKey(KeyboardEvent* event) {
+ if (event->ctrlKey() || event->metaKey() || event->shiftKey())
+ return SpatialNavigationDirection::kNone;
+
+ SpatialNavigationDirection ret_val = SpatialNavigationDirection::kNone;
+ if (event->key() == "ArrowDown")
+ ret_val = SpatialNavigationDirection::kDown;
+ else if (event->key() == "ArrowUp")
+ ret_val = SpatialNavigationDirection::kUp;
+ else if (event->key() == "ArrowLeft")
+ ret_val = SpatialNavigationDirection::kLeft;
+ else if (event->key() == "ArrowRight")
+ ret_val = SpatialNavigationDirection::kRight;
+
+ // TODO(bokan): We should probably assert that we don't get anything else but
+ // currently KeyboardEventManager sends non-arrow keys here.
+
+ return ret_val;
+}
+
+void ClearFocusInExitedFrames(LocalFrame* old_frame,
+ const LocalFrame* const new_frame) {
+ while (old_frame && new_frame != old_frame) {
+ // Focus is going away from this document, so clear the focused element.
+ old_frame->GetDocument()->ClearFocusedElement();
+ old_frame->GetDocument()->SetSequentialFocusNavigationStartingPoint(
+ nullptr);
+ Frame* parent = old_frame->Tree().Parent();
+ old_frame = parent->IsLocalFrame() ? ToLocalFrame(parent) : nullptr;
+ }
+}
+
+// Determines whether the given candidate is closer to the current interested
+// node (in the given direction) than the current best. If so, it'll replace
+// the current best.
+static void ConsiderForBestCandidate(SpatialNavigationDirection direction,
+ const FocusCandidate& current_interest,
+ const FocusCandidate& candidate,
+ FocusCandidate* best_candidate,
+ double* best_distance) {
+ DCHECK(candidate.visible_node->IsElementNode());
+ DCHECK(candidate.visible_node->GetLayoutObject());
+
+ // Ignore iframes that don't have a src attribute
+ if (FrameOwnerElement(candidate) &&
+ (!FrameOwnerElement(candidate)->ContentFrame() ||
+ candidate.rect_in_root_frame.IsEmpty()))
+ return;
+
+ // Ignore off-screen focusables that are not exposed after one "scroll step"
+ // in the direction.
+ if (candidate.is_offscreen && candidate.is_offscreen_after_scrolling)
+ return;
+
+ double distance =
+ ComputeDistanceDataForNode(direction, current_interest, candidate);
+ if (distance == MaxDistance())
+ return;
+
+ if (best_candidate->IsNull()) {
+ *best_candidate = candidate;
+ *best_distance = distance;
+ return;
+ }
+
+ LayoutRect intersection_rect = Intersection(
+ candidate.rect_in_root_frame, best_candidate->rect_in_root_frame);
+ if (!intersection_rect.IsEmpty() &&
+ !AreElementsOnSameLine(*best_candidate, candidate) &&
+ intersection_rect == candidate.rect_in_root_frame) {
+ // If 2 nodes are intersecting, do hit test to find which node in on top.
+ LayoutUnit x = intersection_rect.X() + intersection_rect.Width() / 2;
+ LayoutUnit y = intersection_rect.Y() + intersection_rect.Height() / 2;
+ if (!candidate.visible_node->GetDocument()
+ .GetPage()
+ ->MainFrame()
+ ->IsLocalFrame())
+ return;
+ HitTestLocation location(IntPoint(x.ToInt(), y.ToInt()));
+ HitTestResult result =
+ candidate.visible_node->GetDocument()
+ .GetPage()
+ ->DeprecatedLocalMainFrame()
+ ->GetEventHandler()
+ .HitTestResultAtLocation(
+ location, HitTestRequest::kReadOnly | HitTestRequest::kActive |
+ HitTestRequest::kIgnoreClipping);
+ if (candidate.visible_node->contains(result.InnerNode())) {
+ *best_candidate = candidate;
+ *best_distance = distance;
+ return;
+ }
+ if (best_candidate->visible_node->contains(result.InnerNode()))
+ return;
+ }
+
+ if (distance < *best_distance) {
+ *best_candidate = candidate;
+ *best_distance = distance;
+ }
+}
+
+} // namespace
+
+// static
+SpatialNavigationController* SpatialNavigationController::Create(Page& page) {
+ return MakeGarbageCollected<SpatialNavigationController>(page);
+}
+
+SpatialNavigationController::SpatialNavigationController(Page& page)
+ : page_(&page) {}
+
+bool SpatialNavigationController::HandleArrowKeyboardEvent(
+ KeyboardEvent* event) {
+ DCHECK(page_->GetSettings().GetSpatialNavigationEnabled());
+
+ SpatialNavigationDirection direction = FocusDirectionForKey(event);
+ if (direction == SpatialNavigationDirection::kNone)
+ return false;
+
+ return Advance(direction);
+}
+
+bool SpatialNavigationController::HandleEnterKeyboardEvent(
+ KeyboardEvent* event) {
+ DCHECK(page_->GetSettings().GetSpatialNavigationEnabled());
+
+ if (interest_element_) {
+ interest_element_->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
+ kWebFocusTypeSpatialNavigation,
+ nullptr));
+ }
+
+ return true;
+}
+
+bool SpatialNavigationController::HandleEscapeKeyboardEvent(
+ KeyboardEvent* event) {
+ DCHECK(page_->GetSettings().GetSpatialNavigationEnabled());
+
+ if (!interest_element_)
+ return false;
+
+ if (interest_element_->IsFocusedElementInDocument())
+ interest_element_->blur();
+ else
+ MoveInterestTo(nullptr);
+
+ return true;
+}
+
+Element* SpatialNavigationController::GetInterestedElement() const {
+ if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled())
+ return interest_element_;
+
+ Frame* frame = page_->GetFocusController().FocusedOrMainFrame();
+ if (!frame->IsLocalFrame())
+ return nullptr;
+
+ Document* document = ToLocalFrame(frame)->GetDocument();
+ if (!document)
+ return nullptr;
+
+ return document->ActiveElement();
+}
+
+void SpatialNavigationController::DidDetachFrameView() {
+ // If the interested element's view was lost (frame detached, navigated,
+ // etc.) then reset navigation.
+ if (interest_element_ && !interest_element_->GetDocument().View())
+ interest_element_ = nullptr;
+}
+
+void SpatialNavigationController::Trace(blink::Visitor* visitor) {
+ visitor->Trace(interest_element_);
+ visitor->Trace(page_);
+}
+
+bool SpatialNavigationController::Advance(
+ SpatialNavigationDirection direction) {
+ Node* interest_node = StartingNode();
+ if (!interest_node)
+ return false;
+
+ interest_node->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
+
+ Node* container = ScrollableAreaOrDocumentOf(interest_node);
+
+ const LayoutRect visible_rect(page_->GetVisualViewport().VisibleRect());
+ const LayoutRect start_box =
+ SearchOrigin(visible_rect, interest_node, direction);
+
+ if (IsScrollableAreaOrDocument(interest_node) &&
+ !IsOffscreen(interest_node)) {
+ // A visible scroller has interest. Search inside of it from one of its
+ // edges.
+ LayoutRect edge = OppositeEdge(direction, start_box);
+ if (AdvanceWithinContainer(*interest_node, edge, direction, nullptr))
+ return true;
+ }
+
+ // The interested scroller had nothing. Let's search outside of it.
+ Node* skipped_tree = interest_node;
+ while (container) {
+ if (AdvanceWithinContainer(*container, start_box, direction, skipped_tree))
+ return true;
+
+ // Containers are not focused “on the way out”. This prevents containers
+ // from acting as “focus traps”. Take <c> <a> </c> <b>. Focus can move from
+ // <a> to <b> but not from <a> to the scroll container <c>. If we'd allow
+ // focus to move from <a> to <c>, the user would never be able to exit <c>.
+ // When the scroll container <c> is focused, we move focus back to <a>...
+ skipped_tree = container;
+ // Nothing found in |container| so search the parent container.
+ container = ScrollableAreaOrDocumentOf(container);
+
+ // TODO(bokan): This needs to update the parent document when the _current_
+ // container is a document since we're crossing the document boundary.
+ // Currently this will fail if we're going from an inner document to a
+ // sub-scroller in a parent document.
+ if (auto* document = DynamicTo<Document>(container))
+ document->UpdateStyleAndLayoutIgnorePendingStylesheets();
+ }
+
+ return false;
+}
+
+FocusCandidate SpatialNavigationController::FindNextCandidateInContainer(
+ Node& container,
+ const LayoutRect& starting_rect_in_root_frame,
+ SpatialNavigationDirection direction,
+ Node* interest_child_in_container) {
+ Element* element = ElementTraversal::FirstWithin(container);
+
+ FocusCandidate current_interest;
+ current_interest.rect_in_root_frame = starting_rect_in_root_frame;
+ current_interest.focusable_node = interest_child_in_container;
+ current_interest.visible_node = interest_child_in_container;
+
+ FocusCandidate best_candidate;
+ double best_distance = MaxDistance();
+ for (; element;
+ element =
+ IsScrollableAreaOrDocument(element)
+ ? ElementTraversal::NextSkippingChildren(*element, &container)
+ : ElementTraversal::Next(*element, &container)) {
+ if (element == interest_child_in_container)
+ continue;
+
+ if (HasRemoteFrame(element))
+ continue;
+
+ if (!IsValidCandidate(*element))
+ continue;
+
+ FocusCandidate candidate = FocusCandidate(element, direction);
+ if (candidate.IsNull())
+ continue;
+
+ ConsiderForBestCandidate(direction, current_interest, candidate,
+ &best_candidate, &best_distance);
+ }
+
+ return best_candidate;
+}
+
+bool SpatialNavigationController::AdvanceWithinContainer(
+ Node& container,
+ const LayoutRect& starting_rect_in_root_frame,
+ SpatialNavigationDirection direction,
+ Node* interest_child_in_container) {
+ DCHECK(IsScrollableAreaOrDocument(&container));
+
+ FocusCandidate candidate =
+ FindNextCandidateInContainer(container, starting_rect_in_root_frame,
+ direction, interest_child_in_container);
+
+ if (candidate.IsNull()) {
+ // Nothing to focus in this container, scroll if possible.
+ // NOTE: If no scrolling is performed (i.e. ScrollInDirection returns
+ // false), the spatial navigation algorithm will skip this container.
+ return ScrollInDirection(&container, direction);
+ }
+
+ Element* element = ToElement(candidate.focusable_node);
+ DCHECK(element);
+ MoveInterestTo(element);
+ return true;
+}
+
+Node* SpatialNavigationController::StartingNode() {
+ if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+ if (interest_element_ && interest_element_->GetDocument().GetFrame()) {
+ // If an iframe is interested, start the search from its document node.
+ // This matches the behavior in the focus case below where focusing a
+ // frame means the focused document doesn't have a focused element and so
+ // we return the document itself.
+ if (interest_element_->IsFrameOwnerElement())
+ return ToHTMLFrameOwnerElement(interest_element_)->contentDocument();
+
+ return interest_element_;
+ }
+
+ Frame* main_frame = page_->MainFrame();
+ if (main_frame && main_frame->IsLocalFrame())
+ return ToLocalFrame(main_frame)->GetDocument();
+
+ return nullptr;
+ }
+
+ // FIXME: Directional focus changes don't yet work with RemoteFrames.
+ Frame* focused_frame = page_->GetFocusController().FocusedOrMainFrame();
+ if (!focused_frame->IsLocalFrame())
+ return nullptr;
+
+ const LocalFrame* current_frame = ToLocalFrame(focused_frame);
+ DCHECK(current_frame);
+
+ Document* focused_document = current_frame->GetDocument();
+ if (!focused_document)
+ return nullptr;
+
+ Node* focused_element = focused_document->FocusedElement();
+ if (!focused_element) // An iframe's document is focused.
+ focused_element = focused_document;
+
+ return focused_element;
+}
+
+void SpatialNavigationController::MoveInterestTo(Node* next_node) {
+ DCHECK(!next_node || next_node->IsElementNode());
+ Element* element = ToElement(next_node);
+
+ if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+ if (interest_element_) {
+ interest_element_->blur();
+ interest_element_->SetNeedsStyleRecalc(
+ kLocalStyleChange, StyleChangeReasonForTracing::Create(
+ style_change_reason::kPseudoClass));
+ }
+
+ interest_element_ = element;
+
+ if (interest_element_) {
+ interest_element_->SetNeedsStyleRecalc(
+ kLocalStyleChange, StyleChangeReasonForTracing::Create(
+ style_change_reason::kPseudoClass));
+
+ LayoutObject* layout_object = interest_element_->GetLayoutObject();
+ DCHECK(layout_object);
+
+ layout_object->ScrollRectToVisible(
+ element->BoundingBoxForScrollIntoView(), WebScrollIntoViewParams());
+ }
+ return;
+ }
+
+ if (!element)
+ return;
+
+ // Before focusing the new element, check if we're leaving an iframe (= moving
+ // focus out of an iframe). In this case, we want the exited [nested] iframes
+ // to lose focus. This is tested in snav-iframe-nested.html.
+ LocalFrame* old_frame = page_->GetFocusController().FocusedFrame();
+ ClearFocusInExitedFrames(old_frame, next_node->GetDocument().GetFrame());
+
+ element->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
+ kWebFocusTypeSpatialNavigation, nullptr));
+}
+
+bool SpatialNavigationController::IsValidCandidate(
+ const Element& element) const {
+ return element.IsKeyboardFocusable();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h
new file mode 100644
index 00000000000..0034de06718
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h
@@ -0,0 +1,90 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SPATIAL_NAVIGATION_CONTROLLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SPATIAL_NAVIGATION_CONTROLLER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+struct FocusCandidate;
+class KeyboardEvent;
+class LayoutRect;
+class Node;
+class Page;
+
+// Encapsulates logic and state related to "spatial navigation". Spatial
+// Navigation is used to move and interact with a page in a purely directional
+// way, e.g. keyboard arrows. We use the term "interest" to specify which
+// element the user is currently on.
+class CORE_EXPORT SpatialNavigationController
+ : public GarbageCollected<SpatialNavigationController> {
+ public:
+ static SpatialNavigationController* Create(Page& page);
+ SpatialNavigationController(Page& page);
+
+ bool HandleArrowKeyboardEvent(KeyboardEvent* event);
+ bool HandleEnterKeyboardEvent(KeyboardEvent* event);
+ bool HandleEscapeKeyboardEvent(KeyboardEvent* event);
+
+ // Returns the element that's currently interested. i.e. the Element that's
+ // currently indicated to the user.
+ Element* GetInterestedElement() const;
+
+ void DidDetachFrameView();
+
+ void Trace(blink::Visitor*);
+
+ private:
+ // Entry-point into SpatialNavigation advancement. Will return true if an
+ // action (moving interest or scrolling), false otherwise.
+ bool Advance(SpatialNavigationDirection direction);
+
+ /*
+ * Advances interest only within the specified container. Returns true if
+ * interest was advanced or the container was scrolled, false if no
+ * advancement was possible within the container.
+ *
+ * container - The scrollable container within which to limit advancement.
+ * starting_rect_in_root_frame - The rect to use to begin searching for the
+ * next node. Intuitively, the interest node's
+ * rect (but sometimes different for scrollers).
+ * direction - Direction of advancement
+ * interest_child_in_container - The inner-most child _within this container_
+ * where interest is located. This may differ
+ * from the starting_rect as the interest node
+ * may be in a nested container.
+ */
+ bool AdvanceWithinContainer(Node& container,
+ const LayoutRect& starting_rect_in_root_frame,
+ SpatialNavigationDirection direction,
+ Node* interest_child_in_container);
+
+ // Parameters have same meanings as method above.
+ FocusCandidate FindNextCandidateInContainer(
+ Node& container,
+ const LayoutRect& starting_rect_in_root_frame,
+ SpatialNavigationDirection direction,
+ Node* interest_child_in_container);
+
+ // Returns which Node we're starting navigation from or nullptr if we should
+ // abort navigation.
+ Node* StartingNode();
+ void MoveInterestTo(Node* next_node);
+
+ // Returns true if the element should be considered for navigation.
+ bool IsValidCandidate(const Element& element) const;
+
+ // The currently indicated element or nullptr if no node is indicated by
+ // spatial navigation.
+ WeakMember<Element> interest_element_;
+ Member<Page> page_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SPATIAL_NAVIGATION_CONTROLLER_H_
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc
index ca2fdfb4ae1..09114a8906c 100644
--- a/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -46,18 +46,18 @@ class SpatialNavigationTest : public RenderingTest {
}
void AssertUseSidesOfVisualViewport(Node* focus_node) {
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), focus_node, kWebFocusTypeUp),
- BottomOfVisualViewport());
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), focus_node, kWebFocusTypeDown),
- TopOfVisualViewport());
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), focus_node, kWebFocusTypeLeft),
- RightSideOfVisualViewport());
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), focus_node, kWebFocusTypeRight),
- LeftSideOfVisualViewport());
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), focus_node,
+ SpatialNavigationDirection::kUp),
+ BottomOfVisualViewport());
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), focus_node,
+ SpatialNavigationDirection::kDown),
+ TopOfVisualViewport());
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), focus_node,
+ SpatialNavigationDirection::kLeft),
+ RightSideOfVisualViewport());
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), focus_node,
+ SpatialNavigationDirection::kRight),
+ LeftSideOfVisualViewport());
}
void UpdateAllLifecyclePhases(LocalFrameView* frame_view) {
@@ -191,7 +191,8 @@ TEST_F(SpatialNavigationTest, StartAtVisibleFocusedElement) {
SetBodyInnerHTML("<button id='b'>hello</button>");
Element* b = GetDocument().getElementById("b");
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeDown),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kDown),
NodeRectInRootFrame(b, true));
}
@@ -212,9 +213,9 @@ TEST_F(SpatialNavigationTest, StartAtVisibleFocusedScroller) {
"</div>");
Element* scroller = GetDocument().getElementById("scroller");
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), scroller, kWebFocusTypeDown),
- NodeRectInRootFrame(scroller, true));
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), scroller,
+ SpatialNavigationDirection::kDown),
+ NodeRectInRootFrame(scroller, true));
}
TEST_F(SpatialNavigationTest, StartAtVisibleFocusedIframe) {
@@ -233,40 +234,48 @@ TEST_F(SpatialNavigationTest, StartAtVisibleFocusedIframe) {
"<div>some text here</div>");
Element* iframe = GetDocument().getElementById("iframe");
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), iframe, kWebFocusTypeDown),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), iframe,
+ SpatialNavigationDirection::kDown),
NodeRectInRootFrame(iframe, true));
}
TEST_F(SpatialNavigationTest, StartAtTopWhenGoingDownwardsWithoutFocus) {
EXPECT_EQ(LayoutRect(0, 0, 111, 0),
- SearchOrigin({0, 0, 111, 222}, nullptr, kWebFocusTypeDown));
+ SearchOrigin({0, 0, 111, 222}, nullptr,
+ SpatialNavigationDirection::kDown));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeDown),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kDown),
TopOfVisualViewport());
}
TEST_F(SpatialNavigationTest, StartAtBottomWhenGoingUpwardsWithoutFocus) {
- EXPECT_EQ(LayoutRect(0, 222, 111, 0),
- SearchOrigin({0, 0, 111, 222}, nullptr, kWebFocusTypeUp));
+ EXPECT_EQ(
+ LayoutRect(0, 222, 111, 0),
+ SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kUp));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeUp),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kUp),
BottomOfVisualViewport());
}
TEST_F(SpatialNavigationTest, StartAtLeftSideWhenGoingEastWithoutFocus) {
EXPECT_EQ(LayoutRect(0, 0, 0, 222),
- SearchOrigin({0, 0, 111, 222}, nullptr, kWebFocusTypeRight));
+ SearchOrigin({0, 0, 111, 222}, nullptr,
+ SpatialNavigationDirection::kRight));
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeRight),
- LeftSideOfVisualViewport());
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kRight),
+ LeftSideOfVisualViewport());
}
TEST_F(SpatialNavigationTest, StartAtRightSideWhenGoingWestWithoutFocus) {
EXPECT_EQ(LayoutRect(111, 0, 0, 222),
- SearchOrigin({0, 0, 111, 222}, nullptr, kWebFocusTypeLeft));
+ SearchOrigin({0, 0, 111, 222}, nullptr,
+ SpatialNavigationDirection::kLeft));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeLeft),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kLeft),
RightSideOfVisualViewport());
}
@@ -279,7 +288,8 @@ TEST_F(SpatialNavigationTest,
Element* b = GetDocument().getElementById("b");
EXPECT_TRUE(IsOffscreen(b));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeUp),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kUp),
BottomOfVisualViewport());
}
@@ -315,27 +325,31 @@ TEST_F(SpatialNavigationTest, StartAtContainersEdge) {
// Go down.
LayoutRect container_top_edge = container_box;
container_top_edge.SetHeight(LayoutUnit(0));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeDown),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kDown),
container_top_edge);
// Go up.
LayoutRect container_bottom_edge = container_box;
container_bottom_edge.SetY(container_bottom_edge.MaxX());
container_bottom_edge.SetHeight(LayoutUnit(0));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeUp),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kUp),
container_bottom_edge);
// Go right.
LayoutRect container_leftmost_edge = container_box;
container_leftmost_edge.SetWidth(LayoutUnit(0));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeRight),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kRight),
container_leftmost_edge);
// Go left.
LayoutRect container_rightmost_edge = container_box;
container_rightmost_edge.SetX(container_bottom_edge.MaxX());
container_rightmost_edge.SetWidth(LayoutUnit(0));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeLeft),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kLeft),
container_rightmost_edge);
}
@@ -364,9 +378,11 @@ TEST_F(SpatialNavigationTest,
EXPECT_TRUE(IsOffscreen(scroller));
EXPECT_TRUE(IsOffscreen(b));
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeUp),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kUp),
BottomOfVisualViewport());
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeDown),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kDown),
TopOfVisualViewport());
}
@@ -414,7 +430,8 @@ TEST_F(SpatialNavigationTest, PartiallyVisible) {
LayoutRect button_in_root_frame = NodeRectInRootFrame(b, true);
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeUp),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kUp),
Intersection(button_in_root_frame, RootViewport(&GetFrame())));
// Do some scrolling.
@@ -428,7 +445,8 @@ TEST_F(SpatialNavigationTest, PartiallyVisible) {
// <button>'s top is clipped.
EXPECT_FALSE(IsOffscreen(b)); // <button> is not completely offscreen.
- EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, kWebFocusTypeUp),
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
+ SpatialNavigationDirection::kUp),
Intersection(button_after_scroll, RootViewport(&GetFrame())));
}
@@ -540,36 +558,36 @@ TEST_F(SpatialNavigationTest, PartiallyVisibleIFrame) {
// When searching downwards we start at activeElement's
// container's (here: the iframe's) topmost visible edge.
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), child_element, kWebFocusTypeDown),
- OppositeEdge(kWebFocusTypeDown,
- Intersection(iframe, RootViewport(&GetFrame()))));
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), child_element,
+ SpatialNavigationDirection::kDown),
+ OppositeEdge(SpatialNavigationDirection::kDown,
+ Intersection(iframe, RootViewport(&GetFrame()))));
// When searching upwards we start at activeElement's
// container's (here: the iframe's) bottommost visible edge.
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), child_element, kWebFocusTypeUp),
- OppositeEdge(kWebFocusTypeUp,
- Intersection(iframe, RootViewport(&GetFrame()))));
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), child_element,
+ SpatialNavigationDirection::kUp),
+ OppositeEdge(SpatialNavigationDirection::kUp,
+ Intersection(iframe, RootViewport(&GetFrame()))));
// When searching eastwards, "to the right", we start at activeElement's
// container's (here: the iframe's) leftmost visible edge.
EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), child_element,
- kWebFocusTypeRight),
- OppositeEdge(kWebFocusTypeRight,
+ SpatialNavigationDirection::kRight),
+ OppositeEdge(SpatialNavigationDirection::kRight,
Intersection(iframe, RootViewport(&GetFrame()))));
// When searching westwards, "to the left", we start at activeElement's
// container's (here: the iframe's) rightmost visible edge.
- EXPECT_EQ(
- SearchOrigin(RootViewport(&GetFrame()), child_element, kWebFocusTypeLeft),
- OppositeEdge(kWebFocusTypeLeft,
- Intersection(iframe, RootViewport(&GetFrame()))));
+ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), child_element,
+ SpatialNavigationDirection::kLeft),
+ OppositeEdge(SpatialNavigationDirection::kLeft,
+ Intersection(iframe, RootViewport(&GetFrame()))));
}
TEST_F(SpatialNavigationTest, BottomOfPinchedViewport) {
- LayoutRect origin =
- SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeUp);
+ LayoutRect origin = SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kUp);
EXPECT_EQ(origin.Height(), 0);
EXPECT_EQ(origin.Width(), GetFrame().View()->Width());
EXPECT_EQ(origin.X(), 0);
@@ -580,7 +598,8 @@ TEST_F(SpatialNavigationTest, BottomOfPinchedViewport) {
VisualViewport& visual_viewport = GetFrame().GetPage()->GetVisualViewport();
visual_viewport.SetScale(2);
visual_viewport.SetLocation(FloatPoint(200, 200));
- origin = SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeUp);
+ origin = SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kUp);
EXPECT_EQ(origin.Height(), 0);
EXPECT_LT(origin.Width(), GetFrame().View()->Width());
EXPECT_GT(origin.X(), 0);
@@ -589,8 +608,8 @@ TEST_F(SpatialNavigationTest, BottomOfPinchedViewport) {
}
TEST_F(SpatialNavigationTest, TopOfPinchedViewport) {
- LayoutRect origin =
- SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeDown);
+ LayoutRect origin = SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kDown);
EXPECT_EQ(origin.Height(), 0);
EXPECT_EQ(origin.Width(), GetFrame().View()->Width());
EXPECT_EQ(origin.X(), 0);
@@ -601,7 +620,8 @@ TEST_F(SpatialNavigationTest, TopOfPinchedViewport) {
VisualViewport& visual_viewport = GetFrame().GetPage()->GetVisualViewport();
visual_viewport.SetScale(2);
visual_viewport.SetLocation(FloatPoint(200, 200));
- origin = SearchOrigin(RootViewport(&GetFrame()), nullptr, kWebFocusTypeDown);
+ origin = SearchOrigin(RootViewport(&GetFrame()), nullptr,
+ SpatialNavigationDirection::kDown);
EXPECT_EQ(origin.Height(), 0);
EXPECT_LT(origin.Width(), GetFrame().View()->Width());
EXPECT_GT(origin.X(), 0);
@@ -611,7 +631,7 @@ TEST_F(SpatialNavigationTest, TopOfPinchedViewport) {
TEST_F(SpatialNavigationTest, HasRemoteFrame) {
frame_test_helpers::WebViewHelper helper;
- helper.InitializeAndLoad("about:blank", nullptr, nullptr, nullptr, nullptr);
+ helper.InitializeAndLoad("about:blank");
WebViewImpl* webview = helper.GetWebView();
WebURL base_url = url_test_helpers::ToKURL("http://www.test.com/");
diff --git a/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc b/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc
index e7bf6013e0a..c12c96c5f1a 100644
--- a/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc
@@ -32,7 +32,7 @@ class TouchAdjustmentTest : public RenderingTest {
protected:
TouchAdjustmentTest()
: RenderingTest(SingleChildLocalFrameClient::Create()),
- chrome_client_(new MockChromeClient) {}
+ chrome_client_(MakeGarbageCollected<MockChromeClient>()) {}
LocalFrame& GetFrame() const { return *GetDocument().GetFrame(); }
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_client.h b/chromium/third_party/blink/renderer/core/page/validation_message_client.h
index 9b9f666152c..6a196315580 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_client.h
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_client.h
@@ -34,6 +34,7 @@ namespace blink {
class Document;
class Element;
+class GraphicsContext;
class ValidationMessageClient : public GarbageCollectedMixin {
public:
@@ -62,6 +63,8 @@ class ValidationMessageClient : public GarbageCollectedMixin {
virtual void LayoutOverlay() {}
virtual void PaintOverlay() {}
+ // For CompositeAfterPaint.
+ virtual void PaintOverlay(GraphicsContext&) {}
void Trace(blink::Visitor* visitor) override {}
};
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc
index 11f810af0a0..273c033d969 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc
@@ -29,8 +29,10 @@
#include <memory>
#include <utility>
+#include "cc/layers/picture_layer.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/web/web_text_direction.h"
+#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -63,7 +65,7 @@ void ValidationMessageClientImpl::ShowValidationMessage(
HideValidationMessage(anchor);
return;
}
- if (!anchor.GetLayoutBox())
+ if (!anchor.GetLayoutObject())
return;
if (current_anchor_)
HideValidationMessageImmediately(*current_anchor_);
@@ -80,13 +82,16 @@ void ValidationMessageClientImpl::ShowValidationMessage(
auto* target_frame = page_->MainFrame() && page_->MainFrame()->IsLocalFrame()
? ToLocalFrame(page_->MainFrame())
- : anchor.GetDocument().GetFrame();
+ : &anchor.GetDocument().GetFrame()->LocalFrameRoot();
+ allow_initial_empty_anchor_ = !target_frame->IsMainFrame();
auto delegate = ValidationMessageOverlayDelegate::Create(
*page_, anchor, message_, message_dir, sub_message, sub_message_dir);
overlay_delegate_ = delegate.get();
- overlay_ = PageOverlay::Create(target_frame, std::move(delegate));
+ overlay_ = FrameOverlay::Create(target_frame, std::move(delegate));
bool success =
target_frame->View()->UpdateLifecycleToCompositingCleanPlusScrolling();
+ ValidationMessageVisibilityChanged(anchor);
+
// The lifecycle update should always succeed, because this is not inside
// of a throttling scope.
DCHECK(success);
@@ -98,8 +103,12 @@ void ValidationMessageClientImpl::HideValidationMessage(const Element& anchor) {
HideValidationMessageImmediately(anchor);
return;
}
- if (!current_anchor_ || !IsValidationMessageVisible(anchor))
+ if (!current_anchor_ || !IsValidationMessageVisible(anchor) ||
+ overlay_delegate_->IsHiding()) {
+ // Do not continue if already hiding, otherwise timer will never complete
+ // and Reset() is never called.
return;
+ }
DCHECK(overlay_);
overlay_delegate_->StartToHide();
timer_ = std::make_unique<TaskRunnerTimer<ValidationMessageClientImpl>>(
@@ -119,6 +128,8 @@ void ValidationMessageClientImpl::HideValidationMessageImmediately(
}
void ValidationMessageClientImpl::Reset(TimerBase*) {
+ const Element& anchor = *current_anchor_;
+
timer_ = nullptr;
current_anchor_ = nullptr;
message_ = String();
@@ -126,6 +137,14 @@ void ValidationMessageClientImpl::Reset(TimerBase*) {
overlay_ = nullptr;
overlay_delegate_ = nullptr;
page_->GetChromeClient().UnregisterPopupOpeningObserver(this);
+ ValidationMessageVisibilityChanged(anchor);
+}
+
+void ValidationMessageClientImpl::ValidationMessageVisibilityChanged(
+ const Element& element) {
+ Document& document = element.GetDocument();
+ if (AXObjectCache* cache = document.ExistingAXObjectCache())
+ cache->HandleValidationMessageVisibilityChanged(&element);
}
bool ValidationMessageClientImpl::IsValidationMessageVisible(
@@ -150,8 +169,15 @@ void ValidationMessageClientImpl::CheckAnchorStatus(TimerBase*) {
IntRect new_anchor_rect_in_viewport =
current_anchor_->VisibleBoundsInVisualViewport();
if (new_anchor_rect_in_viewport.IsEmpty()) {
- HideValidationMessage(*current_anchor_);
- return;
+ // In a remote frame, VisibleBoundsInVisualViewport() returns an empty
+ // rectangle for a while after initial load or scrolling. So we don't
+ // hide the validation bubble until we see a non-empty rectable.
+ if (!allow_initial_empty_anchor_) {
+ HideValidationMessage(*current_anchor_);
+ return;
+ }
+ } else {
+ allow_initial_empty_anchor_ = false;
}
}
@@ -174,8 +200,15 @@ void ValidationMessageClientImpl::LayoutOverlay() {
}
void ValidationMessageClientImpl::PaintOverlay() {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (overlay_ && overlay_->GetGraphicsLayer())
+ overlay_->GetGraphicsLayer()->Paint();
+}
+
+void ValidationMessageClientImpl::PaintOverlay(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
if (overlay_)
- overlay_->GetGraphicsLayer()->Paint(nullptr);
+ overlay_->Paint(context);
}
void ValidationMessageClientImpl::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h
index f328852ea77..ee45e4f35a8 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h
@@ -37,7 +37,7 @@
namespace blink {
class LocalFrameView;
-class PageOverlay;
+class FrameOverlay;
class ValidationMessageOverlayDelegate;
class ValidationMessageClientImpl final
@@ -59,6 +59,7 @@ class ValidationMessageClientImpl final
LocalFrameView* CurrentView();
void HideValidationMessageImmediately(const Element& anchor);
void Reset(TimerBase*);
+ void ValidationMessageVisibilityChanged(const Element& anchor);
void ShowValidationMessage(const Element& anchor,
const String& message,
@@ -71,6 +72,7 @@ class ValidationMessageClientImpl final
void WillBeDestroyed() override;
void LayoutOverlay() override;
void PaintOverlay() override;
+ void PaintOverlay(GraphicsContext&) override;
// PopupOpeningObserver function
void WillOpenPopup() override;
@@ -80,9 +82,10 @@ class ValidationMessageClientImpl final
String message_;
TimeTicks finish_time_;
std::unique_ptr<TimerBase> timer_;
- std::unique_ptr<PageOverlay> overlay_;
+ std::unique_ptr<FrameOverlay> overlay_;
// Raw pointer. This pointer is valid unless overlay_ is nullptr.
ValidationMessageOverlayDelegate* overlay_delegate_ = nullptr;
+ bool allow_initial_empty_anchor_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
index 79883bb529a..32fcefd3599 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
@@ -16,6 +16,9 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/page_popup_client.h"
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
+#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
#include "third_party/blink/renderer/platform/web_test_support.h"
@@ -26,7 +29,7 @@ class ValidationMessageChromeClient : public EmptyChromeClient {
public:
explicit ValidationMessageChromeClient(ChromeClient& main_chrome_client,
LocalFrameView* anchor_view,
- PageOverlay& overlay)
+ FrameOverlay& overlay)
: main_chrome_client_(main_chrome_client),
anchor_view_(anchor_view),
overlay_(overlay) {}
@@ -53,7 +56,7 @@ class ValidationMessageChromeClient : public EmptyChromeClient {
private:
Member<ChromeClient> main_chrome_client_;
Member<LocalFrameView> anchor_view_;
- PageOverlay& overlay_;
+ FrameOverlay& overlay_;
};
inline ValidationMessageOverlayDelegate::ValidationMessageOverlayDelegate(
@@ -92,29 +95,42 @@ LocalFrameView& ValidationMessageOverlayDelegate::FrameView() const {
return *ToLocalFrame(page_->MainFrame())->View();
}
-void ValidationMessageOverlayDelegate::PaintPageOverlay(
- const PageOverlay& overlay,
+void ValidationMessageOverlayDelegate::PaintFrameOverlay(
+ const FrameOverlay& overlay,
GraphicsContext& context,
const IntSize& view_size) const {
if (IsHiding() && !page_)
return;
const_cast<ValidationMessageOverlayDelegate*>(this)->UpdateFrameViewState(
overlay, view_size);
- LocalFrameView& view = FrameView();
- view.PaintWithLifecycleUpdate(
- context, kGlobalPaintNormalPhase,
- CullRect(IntRect(0, 0, view.Width(), view.Height())));
+
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ ScopedPaintChunkProperties properties(context.GetPaintController(),
+ PropertyTreeState::Root(), overlay,
+ DisplayItem::kFrameOverlay);
+ if (DrawingRecorder::UseCachedDrawingIfPossible(context, overlay,
+ DisplayItem::kFrameOverlay))
+ return;
+ DrawingRecorder recorder(context, overlay, DisplayItem::kFrameOverlay);
+ context.Canvas()->drawPicture(FrameView().GetPaintRecord());
+ return;
+ }
+
+ DisplayItemCacheSkipper cache_skipper(context);
+ FrameView().PaintOutsideOfLifecycle(context, kGlobalPaintNormalPhase);
}
void ValidationMessageOverlayDelegate::UpdateFrameViewState(
- const PageOverlay& overlay,
+ const FrameOverlay& overlay,
const IntSize& view_size) {
EnsurePage(overlay, view_size);
if (FrameView().Size() != view_size) {
FrameView().Resize(view_size);
page_->GetVisualViewport().SetSize(view_size);
}
- AdjustBubblePosition(view_size);
+ IntRect intersection = overlay.Frame().RemoteViewportIntersection();
+ AdjustBubblePosition(intersection.IsEmpty() ? IntRect(IntPoint(), view_size)
+ : intersection);
// This manual invalidation is necessary to avoid a DCHECK failure in
// FindVisualRectNeedingUpdateScopeBase::CheckVisualRect().
@@ -124,7 +140,7 @@ void ValidationMessageOverlayDelegate::UpdateFrameViewState(
DocumentLifecycle::LifecycleUpdateReason::kOther);
}
-void ValidationMessageOverlayDelegate::EnsurePage(const PageOverlay& overlay,
+void ValidationMessageOverlayDelegate::EnsurePage(const FrameOverlay& overlay,
const IntSize& view_size) {
if (page_)
return;
@@ -134,7 +150,7 @@ void ValidationMessageOverlayDelegate::EnsurePage(const PageOverlay& overlay,
FillWithEmptyClients(page_clients);
chrome_client_ = MakeGarbageCollected<ValidationMessageChromeClient>(
main_page_->GetChromeClient(), anchor_->GetDocument().View(),
- const_cast<PageOverlay&>(overlay));
+ const_cast<FrameOverlay&>(overlay));
page_clients.chrome_client = chrome_client_;
Settings& main_settings = main_page_->GetSettings();
page_ = Page::Create(page_clients);
@@ -230,23 +246,23 @@ Element& ValidationMessageOverlayDelegate::GetElementById(
}
void ValidationMessageOverlayDelegate::AdjustBubblePosition(
- const IntSize& view_size) {
+ const IntRect& view_rect) {
if (IsHiding())
return;
float zoom_factor = ToLocalFrame(page_->MainFrame())->PageZoomFactor();
IntRect anchor_rect = anchor_->VisibleBoundsInVisualViewport();
bool show_bottom_arrow = false;
double bubble_y = anchor_rect.MaxY();
- if (view_size.Height() - anchor_rect.MaxY() < bubble_size_.Height()) {
+ if (view_rect.MaxY() - anchor_rect.MaxY() < bubble_size_.Height()) {
bubble_y = anchor_rect.Y() - bubble_size_.Height();
show_bottom_arrow = true;
}
double bubble_x =
anchor_rect.X() + anchor_rect.Width() / 2 - bubble_size_.Width() / 2;
- if (bubble_x < 0)
- bubble_x = 0;
- else if (bubble_x + bubble_size_.Width() > view_size.Width())
- bubble_x = view_size.Width() - bubble_size_.Width();
+ if (bubble_x < view_rect.X())
+ bubble_x = view_rect.X();
+ else if (bubble_x + bubble_size_.Width() > view_rect.MaxX())
+ bubble_x = view_rect.MaxX() - bubble_size_.Width();
Element& container = GetElementById("container");
container.SetInlineStyleProperty(CSSPropertyLeft, bubble_x / zoom_factor,
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
index b0d336b14a2..25ad5051b77 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_VALIDATION_MESSAGE_OVERLAY_DELEGATE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_VALIDATION_MESSAGE_OVERLAY_DELEGATE_H_
-#include "third_party/blink/renderer/core/page/page_overlay.h"
+#include "third_party/blink/renderer/core/frame/frame_overlay.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -22,8 +22,8 @@ class Page;
// Lifetime: An instance is created by a ValidationMessageClientImpl when a
// bubble is shown, and deleted when the bubble is closed.
//
-// Ownership: A PageOverlay instance owns a ValidationMessageOverlayDelegate.
-class ValidationMessageOverlayDelegate : public PageOverlay::Delegate {
+// Ownership: A FrameOverlay instance owns a ValidationMessageOverlayDelegate.
+class ValidationMessageOverlayDelegate : public FrameOverlay::Delegate {
public:
static std::unique_ptr<ValidationMessageOverlayDelegate> Create(
Page&,
@@ -34,10 +34,11 @@ class ValidationMessageOverlayDelegate : public PageOverlay::Delegate {
TextDirection sub_message_dir);
~ValidationMessageOverlayDelegate() override;
- void PaintPageOverlay(const PageOverlay&,
- GraphicsContext&,
- const IntSize& view_size) const override;
+ void PaintFrameOverlay(const FrameOverlay&,
+ GraphicsContext&,
+ const IntSize& view_size) const override;
void StartToHide();
+ bool IsHiding() const;
private:
ValidationMessageOverlayDelegate(Page&,
@@ -47,12 +48,11 @@ class ValidationMessageOverlayDelegate : public PageOverlay::Delegate {
const String& sub_message,
TextDirection sub_message_dir);
LocalFrameView& FrameView() const;
- void UpdateFrameViewState(const PageOverlay&, const IntSize& view_size);
- void EnsurePage(const PageOverlay&, const IntSize& view_size);
+ void UpdateFrameViewState(const FrameOverlay&, const IntSize& view_size);
+ void EnsurePage(const FrameOverlay&, const IntSize& view_size);
void WriteDocument(SharedBuffer*);
Element& GetElementById(const AtomicString&) const;
- void AdjustBubblePosition(const IntSize& view_size);
- bool IsHiding() const;
+ void AdjustBubblePosition(const IntRect& view_rect);
// An internal Page and a ChromeClient for it.
Persistent<Page> page_;
diff --git a/chromium/third_party/blink/renderer/core/page/viewport_description.cc b/chromium/third_party/blink/renderer/core/page/viewport_description.cc
index 5d8a3c15cc8..ea6df778111 100644
--- a/chromium/third_party/blink/renderer/core/page/viewport_description.cc
+++ b/chromium/third_party/blink/renderer/core/page/viewport_description.cc
@@ -86,7 +86,7 @@ float ViewportDescription::ResolveViewportLength(
PageScaleConstraints ViewportDescription::Resolve(
const FloatSize& initial_viewport_size,
- Length legacy_fallback_width) const {
+ const Length& legacy_fallback_width) const {
float result_width = kValueAuto;
Length copy_max_width = max_width;
diff --git a/chromium/third_party/blink/renderer/core/page/viewport_description.h b/chromium/third_party/blink/renderer/core/page/viewport_description.h
index 05d1aa071a4..64cf5bf9fe9 100644
--- a/chromium/third_party/blink/renderer/core/page/viewport_description.h
+++ b/chromium/third_party/blink/renderer/core/page/viewport_description.h
@@ -96,7 +96,7 @@ struct CORE_EXPORT ViewportDescription {
// All arguments are in CSS units.
PageScaleConstraints Resolve(const FloatSize& initial_viewport_size,
- Length legacy_fallback_width) const;
+ const Length& legacy_fallback_width) const;
// When --use-zoom-for-dsf is enabled, if the type is kFixed, these Length
// values (i.e., |min_width|, |max_width|, |min_height|, and |max_height|)
diff --git a/chromium/third_party/blink/renderer/core/page/viewport_test.cc b/chromium/third_party/blink/renderer/core/page/viewport_test.cc
index 66afb242ec9..f5b7d911b10 100644
--- a/chromium/third_party/blink/renderer/core/page/viewport_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/viewport_test.cc
@@ -58,8 +58,6 @@
namespace blink {
-using blink::test::RunPendingTasks;
-
class ViewportTest : public testing::Test {
protected:
ViewportTest()
@@ -85,7 +83,7 @@ class ViewportTest : public testing::Test {
void ExecuteScript(WebLocalFrame* frame, const WebString& code) {
frame->ExecuteScript(WebScriptSource(code));
- RunPendingTasks();
+ blink::test::RunPendingTasks();
}
std::string base_url_;
@@ -2949,7 +2947,7 @@ TEST_F(ViewportTest, viewportLimitsAdjustedForUserScale) {
EXPECT_NEAR(1.0f, constraints.minimum_scale, 0.01f);
}
-TEST_F(ViewportTest, viewportTriggersGpuRasterization) {
+TEST_F(ViewportTest, ViewportTriggersGpuRasterization) {
frame_test_helpers::WebViewHelper web_view_helper;
RegisterMockedHttpURLLoad(
@@ -2958,25 +2956,25 @@ TEST_F(ViewportTest, viewportTriggersGpuRasterization) {
base_url_ +
"viewport/viewport-gpu-rasterization-disabled-without-viewport.html",
nullptr, nullptr, nullptr, SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_FALSE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ content::LayerTreeView* compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_FALSE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
// Also test that setting enableViewport to false (as on desktop Chrome)
// supports GPU raster unconditionally.
web_view_helper.InitializeAndLoad(
base_url_ +
"viewport/viewport-gpu-rasterization-disabled-without-viewport.html");
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad("viewport/viewport-gpu-rasterization.html");
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-gpu-rasterization.html", nullptr, nullptr,
nullptr, SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad(
"viewport/viewport-gpu-rasterization-expanded-heuristics.html");
@@ -2984,49 +2982,49 @@ TEST_F(ViewportTest, viewportTriggersGpuRasterization) {
base_url_ +
"viewport/viewport-gpu-rasterization-expanded-heuristics.html",
nullptr, nullptr, nullptr, SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad("viewport/viewport-1.html");
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-1.html",
nullptr, nullptr, nullptr,
SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad("viewport/viewport-15.html");
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-15.html",
nullptr, nullptr, nullptr,
SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad("viewport/viewport-130.html");
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-130.html",
nullptr, nullptr, nullptr,
SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad("viewport/viewport-legacy-handheldfriendly.html");
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-handheldfriendly.html", nullptr,
nullptr, nullptr, SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
RegisterMockedHttpURLLoad("viewport/viewport-legacy-mobileoptimized.html");
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-handheldfriendly.html", nullptr,
nullptr, nullptr, SetViewportSettings);
- web_view_helper.GetWebView()->Resize(WebSize(640, 480));
- EXPECT_TRUE(web_view_helper.GetWebView()
- ->MatchesHeuristicsForGpuRasterizationForTesting());
+ web_view_helper.GetWebView()->MainFrameWidget()->Resize(WebSize(640, 480));
+ compositor = web_view_helper.GetLayerTreeView();
+ EXPECT_TRUE(compositor->layer_tree_host()->has_gpu_rasterization_trigger());
}
class ConsoleMessageWebFrameClient
@@ -3079,7 +3077,7 @@ TEST_F(ViewportTest, viewportWarnings2) {
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
EXPECT_EQ(1U, web_frame_client.messages.size());
- EXPECT_EQ(WebConsoleMessage::kLevelWarning,
+ EXPECT_EQ(mojom::ConsoleMessageLevel::kWarning,
web_frame_client.messages[0].level);
EXPECT_STREQ("The key \"wwidth\" is not recognized and ignored.",
web_frame_client.messages[0].text.Utf8().c_str());
@@ -3106,7 +3104,7 @@ TEST_F(ViewportTest, viewportWarnings3) {
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
EXPECT_EQ(1U, web_frame_client.messages.size());
- EXPECT_EQ(WebConsoleMessage::kLevelWarning,
+ EXPECT_EQ(mojom::ConsoleMessageLevel::kWarning,
web_frame_client.messages[0].level);
EXPECT_STREQ(
"The value \"unrecognized-width\" for key \"width\" is invalid, and has "
@@ -3135,7 +3133,7 @@ TEST_F(ViewportTest, viewportWarnings4) {
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
EXPECT_EQ(1U, web_frame_client.messages.size());
- EXPECT_EQ(WebConsoleMessage::kLevelWarning,
+ EXPECT_EQ(mojom::ConsoleMessageLevel::kWarning,
web_frame_client.messages[0].level);
EXPECT_STREQ(
"The value \"123x456\" for key \"width\" was truncated to its numeric "
@@ -3165,7 +3163,7 @@ TEST_F(ViewportTest, viewportWarnings5) {
EXPECT_EQ(1U, web_frame_client.messages.size());
- EXPECT_EQ(WebConsoleMessage::kLevelWarning,
+ EXPECT_EQ(mojom::ConsoleMessageLevel::kWarning,
web_frame_client.messages[0].level);
EXPECT_STREQ(
"Error parsing a meta element's content: ';' is not a valid key-value "
@@ -3194,7 +3192,7 @@ TEST_F(ViewportTest, viewportWarnings6) {
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
EXPECT_EQ(1U, web_frame_client.messages.size());
- EXPECT_EQ(WebConsoleMessage::kLevelWarning,
+ EXPECT_EQ(mojom::ConsoleMessageLevel::kWarning,
web_frame_client.messages[0].level);
EXPECT_STREQ(
"The value \"\" for key \"width\" is invalid, and has been ignored.",
@@ -3240,21 +3238,22 @@ TEST_F(ViewportTest, viewportWarnings8) {
EXPECT_EQ(0U, web_frame_client.messages.size());
}
-class ViewportClient : public frame_test_helpers::TestWebViewClient {
+class ViewportClient : public frame_test_helpers::TestWebWidgetClient {
public:
- ViewportClient() : device_scale_factor_(1.f) {}
+ // WebWidgetClient overrides.
void ConvertWindowToViewport(WebFloatRect* rect) override {
rect->x *= device_scale_factor_;
rect->y *= device_scale_factor_;
rect->width *= device_scale_factor_;
rect->height *= device_scale_factor_;
}
+
void set_device_scale_factor(float device_scale_factor) {
device_scale_factor_ = device_scale_factor;
}
private:
- float device_scale_factor_;
+ float device_scale_factor_ = 1.f;
};
TEST_F(ViewportTest, viewportUseZoomForDSF1) {
@@ -3265,7 +3264,7 @@ TEST_F(ViewportTest, viewportUseZoomForDSF1) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-merge-quirk-1.html", nullptr,
- &client, nullptr, SetQuirkViewportSettings);
+ nullptr, &client, SetQuirkViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
// Initial width and height must be scaled by DSF when --use-zoom-for-dsf
@@ -3292,7 +3291,7 @@ TEST_F(ViewportTest, viewportUseZoomForDSF2) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-merge-quirk-2.html", nullptr,
- &client, nullptr, SetQuirkViewportSettings);
+ nullptr, &client, SetQuirkViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -3321,7 +3320,7 @@ TEST_F(ViewportTest, viewportUseZoomForDSF3) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-48.html",
- nullptr, &client, nullptr,
+ nullptr, nullptr, &client,
SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -3346,7 +3345,7 @@ TEST_F(ViewportTest, viewportUseZoomForDSF4) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-39.html",
- nullptr, &client, nullptr,
+ nullptr, nullptr, &client,
SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -3375,7 +3374,7 @@ class ViewportHistogramsTest : public SimTest {
WebView().GetSettings()->SetViewportEnabled(true);
WebView().GetSettings()->SetViewportMetaEnabled(true);
- WebView().Resize(WebSize(500, 600));
+ WebView().MainFrameWidget()->Resize(WebSize(500, 600));
}
void UseMetaTag(const String& metaTag) {
@@ -3413,7 +3412,7 @@ class ViewportHistogramsTest : public SimTest {
request.Complete(responseText);
// Pump the task queue so the meta tag gets processed.
- test::RunPendingTasks();
+ blink::test::RunPendingTasks();
}
HistogramTester histogram_tester_;
diff --git a/chromium/third_party/blink/renderer/core/paint/BUILD.gn b/chromium/third_party/blink/renderer/core/paint/BUILD.gn
index 4a8d0dfea01..f95d1ebb01d 100644
--- a/chromium/third_party/blink/renderer/core/paint/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/paint/BUILD.gn
@@ -52,7 +52,6 @@ blink_core_sources("paint") {
"compositing/compositing_requirements_updater.cc",
"compositing/compositing_requirements_updater.h",
"compositing/compositing_state.h",
- "compositing/compositing_triggers.h",
"compositing/graphics_layer_tree_as_text.cc",
"compositing/graphics_layer_tree_as_text.h",
"compositing/graphics_layer_tree_builder.cc",
diff --git a/chromium/third_party/blink/renderer/core/paint/DEPS b/chromium/third_party/blink/renderer/core/paint/DEPS
index bc2165384f9..2e6dc92680e 100644
--- a/chromium/third_party/blink/renderer/core/paint/DEPS
+++ b/chromium/third_party/blink/renderer/core/paint/DEPS
@@ -1,6 +1,6 @@
include_rules = [
- # This goes away after slimming paint v2. For now it violates strict onion
- # soup guidelines.
+ # This goes away after CompositeAfterPaint is enabled. For now it violates
+ # strict onion soup guidelines.
"+cc/layers/picture_layer.h",
# For DCHECK.
"+base/logging.h",
diff --git a/chromium/third_party/blink/renderer/core/paint/README.md b/chromium/third_party/blink/renderer/core/paint/README.md
index 714aa95842a..dbf3dc08122 100644
--- a/chromium/third_party/blink/renderer/core/paint/README.md
+++ b/chromium/third_party/blink/renderer/core/paint/README.md
@@ -98,7 +98,7 @@ are treated in different ways during painting:
container.
* Paint invalidation container: the nearest object on the compositing
- container chain which is composited. Slimming paint V2 doesn't have this
+ container chain which is composited. CompositeAfterPaint doesn't have this
concept.
* Visual rect: the bounding box of all pixels that will be painted by a
@@ -125,9 +125,9 @@ At the time of writing, there are three operation modes that are switched by
### SlimmingPaintV175 (a.k.a. SPv1.75)
-This mode is for incrementally shipping completed features from SPv2. SPv1.75
+This mode is for incrementally shipping completed features from CAP. SPv1.75
reuses layerization from SPv1, but will cherrypick property-tree-based paint
-from SPv2. Meta display items are abandoned in favor of property tree. Each
+from CAP. Meta display items are abandoned in favor of property tree. Each
drawable GraphicsLayer's layer state will be computed by the property tree
builder. During paint, each display item will be associated with a property
tree state. At the end of paint, meta display items will be generated from
@@ -251,10 +251,10 @@ lifecycle update.
### BlinkGenPropertyTrees
-This mode is for incrementally shipping completed features from SPv2. It is
+This mode is for incrementally shipping completed features from CAP. It is
based on SPv1.75 and starts sending a layer list and property trees directly to
the compositor. BlinkGenPropertyTrees still uses the GraphicsLayers from SPv1.75
-and plugs them in as foreign layers to the SPv2 compositor
+and plugs them in as foreign layers to the CAP compositor
(PaintArtifactCompositor).
```
@@ -308,7 +308,7 @@ from layout
v
```
-### SlimmingPaintV2 (a.k.a. SPv2)
+### CompositeAfterPaint (a.k.a. CAP)
This is a new mode under development. In this mode, layerization runs after
pre-paint and paint, and meta display items are abandoned in favor of property
@@ -370,10 +370,10 @@ from layout
### Comparison of the three modes
```
- | SPv175 | BlinkGenPropertyTrees | SPv2
+ | SPv175 | BlinkGenPropertyTrees | CompositeAfterPaint
---------------------------------+--------------------+-----------------------+-------
REF::BlinkGenPropertyTreesEnabled| false | true | false
-REF::SPv2Enabled | false | false | true
+REF::CompositeAfterPaintEnabled | false | false | true
Layerization | PLC/CLM | PLC/CLM | PAC
cc property tree builder | on | off | off
```
@@ -574,7 +574,7 @@ If the first line contains any `LayoutInline`, we compute the style from the
`::first-line` style and the style of the `LayoutInline` and apply the computed
style to the first line part of the `LayoutInline`. In Blink's style
implementation, the combined first line style of `LayoutInline` is identified
-with `FIRST_LINE_INHERITED` pseudo ID.
+with `kPseudoIdFirstLineInherited`.
The normal paint invalidation of texts doesn't work for first line because
* `ComputedStyle::VisualInvalidationDiff()` can't detect first line style
@@ -637,7 +637,7 @@ from its containing self-painting layer to this layer, assuming that this layer
needs all paint phases that its container self-painting layer needs.
We could update the `NeedsPaintPhaseXXX` flags in a separate tree walk, but that
-would regress performance of the first paint. For slimming paint v2, we can
+would regress performance of the first paint. For CompositeAfterPaint, we can
update the flags during the pre-painting tree walk to simplify the logics.
### Hit test painting
diff --git a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
index 7533c6b7600..330c43ea585 100644
--- a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -44,9 +44,9 @@ bool FixedBackgroundPaintsInLocalCoordinates(
const LayoutView& view = ToLayoutView(obj);
- // TODO(wangxianzhu): For SPv2, inline this function into
+ // TODO(wangxianzhu): For CAP, inline this function into
// FixedBackgroundPaintsInLocalCoordinates().
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
return view.GetBackgroundPaintLocation() !=
kBackgroundPaintInScrollingContents;
}
@@ -110,6 +110,8 @@ void BackgroundImageGeometry::SetNoRepeatX(LayoutUnit x_offset,
// Reduce the width of the dest rect to draw only the portion of the
// tile that remains visible after offsetting the image.
+ // TODO(schenney): This might grow the dest rect if the dest rect has
+ // been adjusted for opaque borders.
unsnapped_dest_rect_.SetWidth(tile_size_.Width() + x_offset);
snapped_dest_rect_.SetWidth(tile_size_.Width() + snapped_x_offset);
}
@@ -145,6 +147,8 @@ void BackgroundImageGeometry::SetNoRepeatY(LayoutUnit y_offset,
// Reduce the height of the dest rect to draw only the portion of the
// tile that remains visible after offsetting the image.
+ // TODO(schenney): This might grow the dest rect if the dest rect has
+ // been adjusted for opaque borders.
unsnapped_dest_rect_.SetHeight(tile_size_.Height() + y_offset);
snapped_dest_rect_.SetHeight(tile_size_.Height() + snapped_y_offset);
}
@@ -375,7 +379,7 @@ LayoutRect FixedAttachmentPositioningArea(const LayoutBoxModelObject& obj,
// The LayoutView is the only object that can paint a fixed background into
// its scrolling contents layer, so it gets a special adjustment here.
if (obj.IsLayoutView()) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
DCHECK_EQ(obj.GetBackgroundPaintLocation(),
kBackgroundPaintInScrollingContents);
rect.SetLocation(IntPoint(ToLayoutView(obj).ScrolledContentOffset()));
@@ -696,7 +700,6 @@ void BackgroundImageGeometry::ComputePositioningArea(
snapped_box_offset =
LayoutPoint(snapped_box_outset.Left() - snapped_dest_adjust.Left(),
snapped_box_outset.Top() - snapped_dest_adjust.Top());
-
// For view backgrounds, the input paint rect is specified in root element
// local coordinate (i.e. a transform is applied on the context for
// painting), and is expanded to cover the whole canvas. Since left/top is
@@ -796,14 +799,17 @@ void BackgroundImageGeometry::CalculateFillTileSize(
}
case EFillSizeType::kContain:
case EFillSizeType::kCover: {
+ // Always use the snapped positioning area size for this computation,
+ // so that we resize the image to completely fill the actual painted
+ // area.
float horizontal_scale_factor =
image_intrinsic_size.Width()
- ? positioning_area_size.Width().ToFloat() /
+ ? snapped_positioning_area_size.Width().ToFloat() /
image_intrinsic_size.Width()
: 1.0f;
float vertical_scale_factor =
image_intrinsic_size.Height()
- ? positioning_area_size.Height().ToFloat() /
+ ? snapped_positioning_area_size.Height().ToFloat() /
image_intrinsic_size.Height()
: 1.0f;
// Force the dimension that determines the size to exactly match the
@@ -815,27 +821,27 @@ void BackgroundImageGeometry::CalculateFillTileSize(
// at the edge of the image when we paint it.
if (horizontal_scale_factor < vertical_scale_factor) {
tile_size_ = LayoutSize(
- positioning_area_size.Width(),
+ snapped_positioning_area_size.Width(),
LayoutUnit(std::max(1.0f, roundf(image_intrinsic_size.Height() *
horizontal_scale_factor))));
} else {
tile_size_ = LayoutSize(
LayoutUnit(std::max(1.0f, roundf(image_intrinsic_size.Width() *
vertical_scale_factor))),
- positioning_area_size.Height());
+ snapped_positioning_area_size.Height());
}
return;
}
if (horizontal_scale_factor > vertical_scale_factor) {
tile_size_ =
- LayoutSize(positioning_area_size.Width(),
+ LayoutSize(snapped_positioning_area_size.Width(),
LayoutUnit(std::max(1.0f, image_intrinsic_size.Height() *
horizontal_scale_factor)));
} else {
tile_size_ =
LayoutSize(LayoutUnit(std::max(1.0f, image_intrinsic_size.Width() *
vertical_scale_factor)),
- positioning_area_size.Height());
+ snapped_positioning_area_size.Height());
}
return;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter.cc b/chromium/third_party/blink/renderer/core/paint/block_painter.cc
index 193441f7626..b49f1b9a6da 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter.cc
@@ -39,13 +39,13 @@ void BlockPainter::Paint(const PaintInfo& paint_info) {
local_paint_info.phase = PaintPhase::kDescendantOutlinesOnly;
} else if (ShouldPaintSelfBlockBackground(original_phase)) {
local_paint_info.phase = PaintPhase::kSelfBlockBackgroundOnly;
- // With SlimmingPaintV2 we need to call PaintObject twice: once for the
+ // With CompositeAfterPaint we need to call PaintObject twice: once for the
// background painting that does not scroll, and a second time for the
// background painting that scrolls.
- // Without SlimmingPaintV2, this happens as the main graphics layer
+ // Without CompositeAfterPaint, this happens as the main graphics layer
// paints the background, and then the scrolling contents graphics layer
// paints the background.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
auto paint_location = layout_block_.GetBackgroundPaintLocation();
if (!(paint_location & kBackgroundPaintInGraphicsLayer))
local_paint_info.SetSkipsBackground(true);
@@ -197,7 +197,7 @@ void BlockPainter::PaintInlineBox(const InlineBox& inline_box,
}
void BlockPainter::PaintScrollHitTestDisplayItem(const PaintInfo& paint_info) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
// Scroll hit test display items are only needed for compositing. This flag is
// used for for printing and drag images which do not need hit testing.
@@ -348,46 +348,50 @@ void BlockPainter::PaintCarets(const PaintInfo& paint_info,
}
}
-DISABLE_CFI_PERF
-bool BlockPainter::ShouldPaint(const ScopedPaintState& paint_state) const {
- // If there is no fragment to paint for this block, we still need to continue
- // the paint tree walk in case there are overflowing children that exist in
- // the current painting fragment of the painting layer. In the case we can't
- // check the overflow rect against the cull rect in the case because we don't
- // know the paint offset.
- if (!paint_state.FragmentToPaint())
- return true;
-
+LayoutRect BlockPainter::OverflowRectForCullRectTesting(
+ bool is_printing) const {
LayoutRect overflow_rect;
- if (paint_state.GetPaintInfo().IsPrinting() &&
- layout_block_.IsAnonymousBlock() && layout_block_.ChildrenInline()) {
+ if (is_printing && layout_block_.IsAnonymousBlock() &&
+ layout_block_.ChildrenInline()) {
// For case <a href="..."><div>...</div></a>, when layout_block_ is the
// anonymous container of <a>, the anonymous container's visual overflow is
// empty, but we need to continue painting to output <a>'s PDF URL rect
// which covers the continuations, as if we included <a>'s PDF URL rect into
// layout_block_'s visual overflow.
- Vector<LayoutRect> rects;
- layout_block_.AddElementVisualOverflowRects(rects, LayoutPoint());
+ auto rects = layout_block_.PhysicalOutlineRects(
+ LayoutPoint(), NGOutlineType::kIncludeBlockVisualOverflow);
overflow_rect = UnionRect(rects);
}
overflow_rect.Unite(layout_block_.VisualOverflowRect());
- bool uses_composited_scrolling = layout_block_.HasOverflowModel() &&
- layout_block_.UsesCompositedScrolling();
+ bool include_layout_overflow =
+ layout_block_.ScrollsOverflow() &&
+ (layout_block_.UsesCompositedScrolling() ||
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
- if (uses_composited_scrolling) {
+ if (include_layout_overflow) {
LayoutRect layout_overflow_rect = layout_block_.LayoutOverflowRect();
overflow_rect.Unite(layout_overflow_rect);
- }
- layout_block_.FlipForWritingMode(overflow_rect);
-
- // Scrolling is applied in physical space, which is why it is after the flip
- // above.
- if (uses_composited_scrolling) {
+ layout_block_.FlipForWritingMode(overflow_rect);
overflow_rect.Move(-layout_block_.ScrolledContentOffset());
+ } else {
+ layout_block_.FlipForWritingMode(overflow_rect);
}
+ return overflow_rect;
+}
+
+DISABLE_CFI_PERF
+bool BlockPainter::ShouldPaint(const ScopedPaintState& paint_state) const {
+ // If there is no fragment to paint for this block, we still need to continue
+ // the paint tree walk in case there are overflowing children that exist in
+ // the current painting fragment of the painting layer. In the case we can't
+ // check the overflow rect against the cull rect in the case because we don't
+ // know the paint offset.
+ if (!paint_state.FragmentToPaint())
+ return true;
- return paint_state.LocalRectIntersectsCullRect(overflow_rect);
+ return paint_state.LocalRectIntersectsCullRect(
+ OverflowRectForCullRectTesting(paint_state.GetPaintInfo().IsPrinting()));
}
void BlockPainter::PaintContents(const PaintInfo& paint_info,
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter.h b/chromium/third_party/blink/renderer/core/paint/block_painter.h
index e16f0be0a7a..93966cb354a 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter.h
@@ -5,7 +5,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BLOCK_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BLOCK_PAINTER_H_
+#include "base/gtest_prod_util.h"
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/order_iterator.h"
+#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
@@ -45,6 +48,11 @@ class BlockPainter {
bool ShouldPaint(const ScopedPaintState&) const;
+ CORE_EXPORT LayoutRect OverflowRectForCullRectTesting(bool is_printing) const;
+
+ FRIEND_TEST_ALL_PREFIXES(BlockPainterTest, OverflowRectForCullRectTesting);
+ FRIEND_TEST_ALL_PREFIXES(BlockPainterTest,
+ OverflowRectCompositedScrollingForCullRectTesting);
const LayoutBlock& layout_block_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
index 180c207955b..a4b5a3a9fae 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
@@ -6,7 +6,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
@@ -20,9 +20,11 @@ namespace blink {
using BlockPainterTest = PaintControllerPaintTest;
-INSTANTIATE_SPV2_TEST_CASE_P(BlockPainterTest);
+INSTANTIATE_PAINT_TEST_CASE_P(BlockPainterTest);
TEST_P(BlockPainterTest, ScrollHitTestProperties) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
@@ -115,6 +117,8 @@ TEST_P(BlockPainterTest, ScrollHitTestProperties) {
}
TEST_P(BlockPainterTest, FrameScrollHitTestProperties) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
@@ -182,6 +186,33 @@ TEST_P(BlockPainterTest, FrameScrollHitTestProperties) {
&scroll_hit_test_display_item.scroll_offset_node());
}
+TEST_P(BlockPainterTest, OverflowRectForCullRectTesting) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='scroller' style='width: 50px; height: 50px; overflow: scroll'>
+ <div style='width: 50px; height: 5000px'></div>
+ </div>
+ )HTML");
+ auto* scroller = ToLayoutBlock(GetLayoutObjectByElementId("scroller"));
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(LayoutRect(0, 0, 50, 5000),
+ BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
+ } else {
+ EXPECT_EQ(LayoutRect(0, 0, 50, 50),
+ BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
+ }
+}
+
+TEST_P(BlockPainterTest, OverflowRectCompositedScrollingForCullRectTesting) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='scroller' style='width: 50px; height: 50px; overflow: scroll; will-change: transform'>
+ <div style='width: 50px; height: 5000px'></div>
+ </div>
+ )HTML");
+ auto* scroller = ToLayoutBlock(GetLayoutObjectByElementId("scroller"));
+ EXPECT_EQ(LayoutRect(0, 0, 50, 5000),
+ BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
+}
+
class BlockPainterTestWithPaintTouchAction
: public PaintControllerPaintTestBase,
private ScopedPaintTouchActionRectsForTest {
@@ -477,14 +508,8 @@ TEST_F(BlockPainterTestWithPaintTouchAction, TouchActionRectPaintChunkChanges) {
}
namespace {
-class BlockPainterMockEventListener final : public EventListener {
+class BlockPainterMockEventListener final : public NativeEventListener {
public:
- BlockPainterMockEventListener() : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
void Invoke(ExecutionContext*, Event*) final {}
};
} // namespace
@@ -511,7 +536,8 @@ TEST_F(BlockPainterTestWithPaintTouchAction, TouchHandlerRectsWithoutPaint) {
// Add an event listener to parent and ensure that hit test display items are
// created for both the parent and child.
- BlockPainterMockEventListener* callback = new BlockPainterMockEventListener();
+ BlockPainterMockEventListener* callback =
+ MakeGarbageCollected<BlockPainterMockEventListener>();
auto* parent_element = GetElementById("parent");
parent_element->addEventListener(event_type_names::kTouchstart, callback);
UpdateAllLifecyclePhasesForTest();
diff --git a/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc
index 389a9702899..e3a41fcab38 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc
@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/core/paint/box_border_painter.h"
#include <algorithm>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
@@ -663,7 +665,7 @@ BoxBorderPainter::BoxBorderPainter(const ComputedStyle& style,
}
void BoxBorderPainter::ComputeBorderProperties() {
- for (unsigned i = 0; i < arraysize(edges_); ++i) {
+ for (unsigned i = 0; i < base::size(edges_); ++i) {
const BorderEdge& edge = edges_[i];
if (!edge.ShouldRender()) {
diff --git a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
index 7b320469781..b3c80241f5f 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
@@ -59,8 +59,8 @@ BoxModelObjectPainter::BoxModelObjectPainter(const LayoutBoxModelObject& box,
bool BoxModelObjectPainter::IsPaintingScrollingBackground(
const LayoutBoxModelObject* box_model_,
const PaintInfo& paint_info) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // TODO(wangxianzhu): For SPv2, remove this method and let callers use
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // TODO(wangxianzhu): For CAP, remove this method and let callers use
// PaintInfo::IsPaintScrollingBackground() directly.
return paint_info.IsPaintingScrollingBackground();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
index a9618ef19d3..af885a2fa52 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
@@ -186,7 +186,7 @@ bool BoxPaintInvalidator::BackgroundGeometryDependsOnLayoutOverflowRect() {
bool BoxPaintInvalidator::BackgroundPaintsOntoScrollingContentsLayer() {
if (!HasEffectiveBackground())
return false;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
return box_.GetBackgroundPaintLocation() &
kBackgroundPaintInScrollingContents;
}
@@ -200,7 +200,7 @@ bool BoxPaintInvalidator::BackgroundPaintsOntoScrollingContentsLayer() {
bool BoxPaintInvalidator::BackgroundPaintsOntoMainGraphicsLayer() {
if (!HasEffectiveBackground())
return false;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return box_.GetBackgroundPaintLocation() & kBackgroundPaintInGraphicsLayer;
if (!box_.HasLayer())
return true;
@@ -244,13 +244,8 @@ BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
new_background_rect.Size() != old_background_rect.Size();
if (background_location_changed || background_size_changed) {
for (auto* object :
- layout_view.GetFrameView()->BackgroundAttachmentFixedObjects()) {
- if (background_location_changed ||
- ShouldFullyInvalidateFillLayersOnSizeChange(
- object->StyleRef().BackgroundLayers(), old_background_rect.Size(),
- new_background_rect.Size()))
- object->SetBackgroundNeedsFullPaintInvalidation();
- }
+ layout_view.GetFrameView()->BackgroundAttachmentFixedObjects())
+ object->SetBackgroundNeedsFullPaintInvalidation();
}
if (background_location_changed ||
@@ -282,20 +277,20 @@ BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
BoxPaintInvalidator::BackgroundInvalidationType
BoxPaintInvalidator::ComputeBackgroundInvalidation(
bool& should_invalidate_all_layers) {
- should_invalidate_all_layers = false;
+ // Need to fully invalidate the background on all layers if background paint
+ // location changed.
+ auto new_background_location = box_.GetBackgroundPaintLocation();
+ if (new_background_location != box_.PreviousBackgroundPaintLocation()) {
+ should_invalidate_all_layers = true;
+ box_.GetMutableForPainting().SetPreviousBackgroundPaintLocation(
+ new_background_location);
+ return BackgroundInvalidationType::kFull;
+ }
// If background changed, we may paint the background on different graphics
// layer, so we need to fully invalidate the background on all layers.
if (box_.BackgroundNeedsFullPaintInvalidation()) {
- if (box_.HasLayer() && box_.Layer()->GetCompositedLayerMapping() &&
- box_.Layer()->GetCompositedLayerMapping()->ScrollingContentsLayer())
- should_invalidate_all_layers = true;
-
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
- box_.FirstFragment().PaintProperties() &&
- box_.FirstFragment().PaintProperties()->ScrollTranslation())
- should_invalidate_all_layers = true;
-
+ should_invalidate_all_layers = true;
return BackgroundInvalidationType::kFull;
}
@@ -336,7 +331,7 @@ BoxPaintInvalidator::ComputeBackgroundInvalidation(
}
void BoxPaintInvalidator::InvalidateBackground() {
- bool should_invalidate_all_layers;
+ bool should_invalidate_all_layers = false;
auto background_invalidation_type =
ComputeBackgroundInvalidation(should_invalidate_all_layers);
if (box_.IsLayoutView()) {
@@ -344,17 +339,19 @@ void BoxPaintInvalidator::InvalidateBackground() {
background_invalidation_type, ComputeViewBackgroundInvalidation());
}
- if (should_invalidate_all_layers ||
- (BackgroundPaintsOntoScrollingContentsLayer() &&
- background_invalidation_type != BackgroundInvalidationType::kNone)) {
- auto reason =
- background_invalidation_type == BackgroundInvalidationType::kFull
- ? PaintInvalidationReason::kBackground
- : PaintInvalidationReason::kIncremental;
- context_.painting_layer->SetNeedsRepaint();
- ObjectPaintInvalidator(box_).InvalidateDisplayItemClient(
- box_.GetScrollableArea()->GetScrollingBackgroundDisplayItemClient(),
- reason);
+ if (box_.GetScrollableArea()) {
+ if (should_invalidate_all_layers ||
+ (BackgroundPaintsOntoScrollingContentsLayer() &&
+ background_invalidation_type != BackgroundInvalidationType::kNone)) {
+ auto reason =
+ background_invalidation_type == BackgroundInvalidationType::kFull
+ ? PaintInvalidationReason::kBackground
+ : PaintInvalidationReason::kIncremental;
+ context_.painting_layer->SetNeedsRepaint();
+ ObjectPaintInvalidator(box_).InvalidateDisplayItemClient(
+ box_.GetScrollableArea()->GetScrollingBackgroundDisplayItemClient(),
+ reason);
+ }
}
if (should_invalidate_all_layers ||
diff --git a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
index e4296ac8448..1278853be59 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
@@ -57,7 +57,7 @@ class BoxPaintInvalidatorTest : public PaintControllerPaintTest {
target.setAttribute(
html_names::kStyleAttr,
target.getAttribute(html_names::kStyleAttr) + "; width: 200px");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToCompositingInputsClean();
// Simulate that PaintInvalidator updates visual rect.
box.GetMutableForPainting().SetVisualRect(
LayoutRect(visual_rect.Location(), box.Size()));
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_painter.cc
index 7c6f1ce6709..251668fc0dc 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter.cc
@@ -95,6 +95,12 @@ void BoxPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info,
}
bool BoxPainter::BackgroundIsKnownToBeOpaque(const PaintInfo& paint_info) {
+ // If the box has multiple fragments, its VisualRect is the bounding box of
+ // all fragments' visual rects, which is likely to cover areas that are not
+ // covered by painted background.
+ if (layout_box_.FirstFragment().NextFragment())
+ return false;
+
LayoutRect bounds = BoxModelObjectPainter::IsPaintingScrollingBackground(
&layout_box_, paint_info)
? layout_box_.LayoutOverflowRect()
@@ -134,7 +140,7 @@ void BoxPainter::PaintBoxDecorationBackgroundWithRect(
BoxDecorationData box_decoration_data(layout_box_);
GraphicsContextStateSaver state_saver(paint_info.context, false);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
LayoutRect(EnclosingIntRect(paint_rect)) == paint_rect &&
BackgroundIsKnownToBeOpaque(paint_info))
recorder.SetKnownToBeOpaque();
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
index e0a47c38afa..f84f3cfca71 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -28,8 +28,7 @@ void BoxPainterBase::PaintFillLayers(const PaintInfo& paint_info,
const FillLayer& fill_layer,
const LayoutRect& rect,
BackgroundImageGeometry& geometry,
- BackgroundBleedAvoidance bleed,
- SkBlendMode op) {
+ BackgroundBleedAvoidance bleed) {
FillLayerOcclusionOutputList reversed_paint_list;
bool should_draw_background_in_separate_buffer =
CalculateFillLayerOcclusionCulling(reversed_paint_list, fill_layer);
@@ -43,7 +42,7 @@ void BoxPainterBase::PaintFillLayers(const PaintInfo& paint_info,
for (auto it = reversed_paint_list.rbegin(); it != reversed_paint_list.rend();
++it) {
- PaintFillLayer(paint_info, c, **it, rect, bleed, geometry, op);
+ PaintFillLayer(paint_info, c, **it, rect, bleed, geometry);
}
if (should_draw_background_in_separate_buffer)
@@ -92,10 +91,6 @@ void BoxPainterBase::PaintNormalBoxShadow(const PaintInfo& info,
if (fill_rect.IsEmpty())
continue;
- FloatRect shadow_rect(border.Rect());
- shadow_rect.Inflate(shadow_blur + shadow_spread);
- shadow_rect.Move(shadow_offset);
-
// Save the state and clip, if not already done.
// The clip does not depend on any shadow-specific properties.
if (!state_saver.Saved()) {
@@ -137,14 +132,6 @@ void BoxPainterBase::PaintNormalBoxShadow(const PaintInfo& info,
DrawLooperBuilder::kShadowIgnoresAlpha, kDrawShadowOnly);
if (has_border_radius) {
- FloatRoundedRect influence_rect(
- PixelSnappedIntRect(LayoutRect(shadow_rect)), border.GetRadii());
- float change_amount = 2 * shadow_blur + shadow_spread;
- if (change_amount >= 0)
- influence_rect.ExpandRadii(change_amount);
- else
- influence_rect.ShrinkRadii(-change_amount);
-
FloatRoundedRect rounded_fill_rect = border;
rounded_fill_rect.Inflate(shadow_spread);
@@ -347,7 +334,6 @@ inline bool PaintFastBottomLayer(Node* node,
FloatRoundedRect color_border =
info.is_rounded_fill ? border_rect
: FloatRoundedRect(PixelSnappedIntRect(rect));
-
// When the layer has an image, figure out whether it is covered by a single
// tile. The border for painting images may not be the same as the color due
// to optimizations for the image painting destination that avoid painting
@@ -415,14 +401,18 @@ inline bool PaintFastBottomLayer(Node* node,
// Generated images will be created at the desired tile size, so assume their
// intrinsic size is the requested tile size.
+ bool is_generated_image = image->HasRelativeSize();
const FloatSize intrinsic_tile_size =
- image->HasRelativeSize() ? image_tile.Size() : FloatSize(image->Size());
+ is_generated_image ? image_tile.Size() : FloatSize(image->Size());
// Subset computation needs the same location as was used with
// ComputePhaseForBackground above, but needs the unsnapped destination
- // size to correctly calculate sprite subsets in the presence of zoom.
+ // size to correctly calculate sprite subsets in the presence of zoom. But if
+ // this is a generated image sized according to the tile size (which is a
+ // snapped value), use the snapped dest rect instead.
FloatRect dest_rect_for_subset(
FloatPoint(geometry.SnappedDestRect().Location()),
- FloatSize(geometry.UnsnappedDestRect().Size()));
+ is_generated_image ? FloatSize(geometry.SnappedDestRect().Size())
+ : FloatSize(geometry.UnsnappedDestRect().Size()));
// Content providers almost always choose source pixels at integer locations,
// so snap to integers. This is particuarly important for sprite maps.
// Calculation up to this point, in LayoutUnits, can lead to small variations
@@ -576,6 +566,12 @@ LayoutRectOutsets AdjustOutsetsForEdgeInclusion(
return adjusted;
}
+bool ShouldApplyBlendOperation(const BoxPainterBase::FillLayerInfo& info,
+ const FillLayer& layer) {
+ // For a mask layer, don't use the operator if this is the bottom layer.
+ return !info.is_bottom_layer || layer.GetType() != EFillLayerType::kMask;
+}
+
} // anonymous namespace
LayoutRectOutsets BoxPainterBase::AdjustedBorderOutsets(
@@ -589,7 +585,6 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
const LayoutRect& rect,
BackgroundBleedAvoidance bleed_avoidance,
BackgroundImageGeometry& geometry,
- SkBlendMode op,
bool object_has_multiple_boxes,
const LayoutSize flow_box_size) {
GraphicsContext& context = paint_info.context;
@@ -608,7 +603,7 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
const auto did_adjust_paint_rect = scrolled_paint_rect != rect;
scoped_refptr<Image> image;
- SkBlendMode composite_op = op;
+ SkBlendMode composite_op = SkBlendMode::kSrcOver;
base::Optional<ScopedInterpolationQuality> interpolation_quality_context;
if (info.should_paint_image) {
geometry.Calculate(paint_info.PaintContainer(), paint_info.phase,
@@ -623,10 +618,10 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
if (bg_layer.MaskSourceType() == EMaskSourceType::kLuminance)
context.SetColorFilter(kColorFilterLuminanceToAlpha);
- // If op != SkBlendMode::kSrcOver, a mask is being painted.
- SkBlendMode bg_op = WebCoreCompositeToSkiaComposite(
- bg_layer.Composite(), bg_layer.GetBlendMode());
- composite_op = (op == SkBlendMode::kSrcOver) ? bg_op : op;
+ if (ShouldApplyBlendOperation(info, bg_layer)) {
+ composite_op = WebCoreCompositeToSkiaComposite(bg_layer.Composite(),
+ bg_layer.GetBlendMode());
+ }
}
LayoutRectOutsets border = ComputeBorders();
@@ -637,11 +632,16 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
bleed_avoidance, border_padding_insets);
// Fast path for drawing simple color backgrounds. Do not use the fast
- // path if the dest rect has been adjusted for scrolling backgrounds
- // because correcting the dest rect for this case reduces the accuracy of the
- // destinations rects.
- // TODO(schenney): Still use the fast path if not painting any images.
- if (!did_adjust_paint_rect &&
+ // path with images if the dest rect has been adjusted for scrolling
+ // backgrounds because correcting the dest rect for scrolling reduces the
+ // accuracy of the destination rects. Also disable the fast path for images
+ // if we are shrinking the background for bleed avoidance, because this
+ // adjusts the border rects in a way that breaks the optimization.
+ bool disable_fast_path =
+ info.should_paint_image &&
+ (bleed_avoidance == kBackgroundBleedShrinkBackground ||
+ did_adjust_paint_rect);
+ if (!disable_fast_path &&
PaintFastBottomLayer(node_, paint_info, info, rect, border_rect, geometry,
image.get(), composite_op)) {
return;
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_base.h b/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
index fb43c43caae..19558c4331d 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
@@ -43,8 +43,7 @@ class BoxPainterBase {
const FillLayer&,
const LayoutRect&,
BackgroundImageGeometry&,
- BackgroundBleedAvoidance = kBackgroundBleedNone,
- SkBlendMode = SkBlendMode::kSrcOver);
+ BackgroundBleedAvoidance = kBackgroundBleedNone);
void PaintFillLayer(const PaintInfo&,
const Color&,
@@ -52,7 +51,6 @@ class BoxPainterBase {
const LayoutRect&,
BackgroundBleedAvoidance,
BackgroundImageGeometry&,
- SkBlendMode = SkBlendMode::kSrcOver,
bool object_has_multiple_boxes = false,
const LayoutSize flow_box_size = LayoutSize());
diff --git a/chromium/third_party/blink/renderer/core/paint/collapsed_border_painter.cc b/chromium/third_party/blink/renderer/core/paint/collapsed_border_painter.cc
index b765acdf4c4..0c18791cc09 100644
--- a/chromium/third_party/blink/renderer/core/paint/collapsed_border_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/collapsed_border_painter.cc
@@ -48,7 +48,7 @@ void CollapsedBorderPainter::SetupBorders() {
}
// At first, let all borders paint the joints. This is to keep the current
- // behavior for layout tests e.g. css2.1/t170602-bdr-conflict-w-01-d.html.
+ // behavior for web tests e.g. css2.1/t170602-bdr-conflict-w-01-d.html.
// TODO(crbug.com/672216): Determine the best way to deal with this.
if (start_.value && before_.value) {
start_.begin_outset = before_.outer_width;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 1806c4d07b5..2a182889169 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -51,6 +51,7 @@
#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
@@ -74,6 +75,7 @@
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/transforms/transform_state.h"
@@ -198,22 +200,12 @@ CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
is_main_frame_layout_view_layer_ = true;
CreatePrimaryGraphicsLayer();
-
- // ImagePainter has a micro-optimization to embed object-fit and clip into
- // the drawing so the property nodes were omitted if not composited.
- if (GetLayoutObject().IsLayoutImage())
- GetLayoutObject().SetNeedsPaintPropertyUpdate();
}
CompositedLayerMapping::~CompositedLayerMapping() {
// Hits in compositing/squashing/squash-onto-nephew.html.
DisableCompositingQueryAsserts disabler;
- // ImagePainter has a micro-optimization to embed object-fit and clip into
- // the drawing so the property nodes should be omitted if not composited.
- if (GetLayoutObject().IsLayoutImage())
- GetLayoutObject().SetNeedsPaintPropertyUpdate();
-
// Do not leave the destroyed pointer dangling on any Layers that painted to
// this mapping's squashing layer.
for (wtf_size_t i = 0; i < squashed_layers_.size(); ++i) {
@@ -245,8 +237,10 @@ std::unique_ptr<GraphicsLayer> CompositedLayerMapping::CreateGraphicsLayer(
graphics_layer->SetCompositingReasons(reasons);
graphics_layer->SetSquashingDisallowedReasons(squashing_disallowed_reasons);
- if (Node* owning_node = owning_layer_.GetLayoutObject().GetNode())
- graphics_layer->SetOwnerNodeId(DOMNodeIds::IdForNode(owning_node));
+ if (Node* owning_node = owning_layer_.GetLayoutObject().GetNode()) {
+ graphics_layer->SetOwnerNodeId(
+ static_cast<int>(DOMNodeIds::IdForNode(owning_node)));
+ }
return graphics_layer;
}
@@ -259,6 +253,8 @@ void CompositedLayerMapping::CreatePrimaryGraphicsLayer() {
UpdateHitTestableWithoutDrawsContent(true);
UpdateOpacity(GetLayoutObject().StyleRef());
UpdateTransform(GetLayoutObject().StyleRef());
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ OwningLayer().UpdateFilterReferenceBox();
UpdateFilters();
UpdateBackdropFilters();
UpdateLayerBlendMode(GetLayoutObject().StyleRef());
@@ -308,15 +304,22 @@ void CompositedLayerMapping::UpdateTransform(const ComputedStyle& style) {
}
void CompositedLayerMapping::UpdateFilters() {
+ // Filters will be handled by property tree
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ return;
CompositorFilterOperations operations;
OwningLayer().UpdateCompositorFilterOperationsForFilter(operations);
-
graphics_layer_->SetFilters(std::move(operations));
}
void CompositedLayerMapping::UpdateBackdropFilters() {
- graphics_layer_->SetBackdropFilters(
- OwningLayer().CreateCompositorFilterOperationsForBackdropFilter());
+ // Filters will be handled by property tree
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ return;
+ CompositorFilterOperations backdrop_filters =
+ OwningLayer().CreateCompositorFilterOperationsForBackdropFilter();
+ gfx::RectF filter_bounds = OwningLayer().BackdropFilterBounds();
+ graphics_layer_->SetBackdropFilters(backdrop_filters, filter_bounds);
}
void CompositedLayerMapping::UpdateStickyConstraints(
@@ -650,7 +653,8 @@ void CompositedLayerMapping::
kIgnoreOverflowClip);
ClipRect clip_rect;
- owning_layer_.Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ owning_layer_
+ .Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(clip_rects_context, clip_rect);
if (clip_rect.Rect() == LayoutRect(LayoutRect::InfiniteIntRect()))
return;
@@ -805,7 +809,7 @@ bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
bool has_clip_path =
ClipPathClipper::LocalClipPathBoundingBox(GetLayoutObject()).has_value();
if (UpdateMaskLayer(has_mask || has_clip_path)) {
- graphics_layer_->SetMaskLayer(mask_layer_.get(), false);
+ graphics_layer_->SetMaskLayer(mask_layer_.get());
layer_config_changed = true;
}
@@ -826,11 +830,11 @@ bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
// TODO(trchen): Verify if the 3 cases are mutually exclusive.
GraphicsLayer* first_come_first_served = child_clipping_mask_layer_.get();
if (HasClippingLayer()) {
- ClippingLayer()->SetMaskLayer(first_come_first_served, true);
+ ClippingLayer()->SetMaskLayer(first_come_first_served);
first_come_first_served = nullptr;
}
if (HasScrollingLayer()) {
- ScrollingLayer()->SetMaskLayer(first_come_first_served, true);
+ ScrollingLayer()->SetMaskLayer(first_come_first_served);
first_come_first_served = nullptr;
}
graphics_layer_->SetContentsClippingMaskLayer(first_come_first_served);
@@ -867,19 +871,11 @@ bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
graphics_layer_->SetContentsToCcLayer(
media_element->CcLayer(),
/*prevent_contents_opaque_changes=*/true);
- } else if (IsSurfaceLayerCanvas(layout_object)) {
- HTMLCanvasElement* canvas = ToHTMLCanvasElement(layout_object.GetNode());
+ } else if (layout_object.IsCanvas()) {
graphics_layer_->SetContentsToCcLayer(
- canvas->SurfaceLayerBridge()->GetCcLayer(),
+ ToHTMLCanvasElement(layout_object.GetNode())->ContentsCcLayer(),
/*prevent_contents_opaque_changes=*/false);
layer_config_changed = true;
- } else if (IsTextureLayerCanvas(layout_object)) {
- HTMLCanvasElement* canvas = ToHTMLCanvasElement(layout_object.GetNode());
- if (CanvasRenderingContext* context = canvas->RenderingContext()) {
- graphics_layer_->SetContentsToCcLayer(
- context->CcLayer(), /*prevent_contents_opaque_changes=*/false);
- }
- layer_config_changed = true;
}
if (layout_object.IsLayoutEmbeddedContent()) {
if (PaintLayerCompositor::AttachFrameContentLayersToIframeLayer(
@@ -1172,6 +1168,9 @@ void CompositedLayerMapping::UpdateGraphicsLayerGeometry(
if (!GetLayoutObject().StyleRef().IsRunningOpacityAnimationOnCompositor())
UpdateOpacity(GetLayoutObject().StyleRef());
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ OwningLayer().UpdateFilterReferenceBox();
+
if (!GetLayoutObject().StyleRef().IsRunningFilterAnimationOnCompositor())
UpdateFilters();
@@ -1242,9 +1241,10 @@ void CompositedLayerMapping::UpdateGraphicsLayerGeometry(
invalidate_graphics_layer, invalidate_scrolling_contents_layer);
// This depends on background_paints_onto_graphics_layer_.
- UpdateDrawsContent();
+ UpdateDrawsContentAndPaintsHitTest();
- // These invalidations need to happen after UpdateDrawsContent.
+ // These invalidations need to happen after
+ // |UpdateDrawsContentAndPaintsHitTest|.
if (invalidate_graphics_layer)
graphics_layer_->SetNeedsDisplay();
if (invalidate_scrolling_contents_layer)
@@ -1308,16 +1308,17 @@ void CompositedLayerMapping::UpdateMainGraphicsLayerGeometry(
FloatPoint new_position = FloatPoint(relative_compositing_bounds.Location() -
graphics_layer_parent_location);
IntSize new_size = relative_compositing_bounds.Size();
+ const LayoutObject& layout_object = GetLayoutObject();
// An iframe's main GraphicsLayer is positioned by the CLM for the <iframe>
// element in the parent frame's DOM.
- bool is_iframe_doc = GetLayoutObject().IsLayoutView() &&
- !GetLayoutObject().GetFrame()->IsLocalRoot();
+ bool is_iframe_doc =
+ layout_object.IsLayoutView() && !layout_object.GetFrame()->IsLocalRoot();
if (new_position != old_position && !is_iframe_doc) {
graphics_layer_->SetPosition(new_position);
- if (RuntimeEnabledFeatures::JankTrackingEnabled()) {
- LocalFrameView* frame_view = GetLayoutObject().View()->GetFrameView();
+ if (origin_trials::JankTrackingEnabled(&layout_object.GetDocument())) {
+ LocalFrameView* frame_view = layout_object.View()->GetFrameView();
frame_view->GetJankTracker().NotifyCompositedLayerMoved(
OwningLayer(), FloatRect(old_position, FloatSize(old_size)),
FloatRect(new_position, FloatSize(new_size)));
@@ -1337,9 +1338,14 @@ void CompositedLayerMapping::UpdateMainGraphicsLayerGeometry(
HasVisibleNonCompositingDescendant(&owning_layer_);
graphics_layer_->SetContentsVisible(contents_visible);
- graphics_layer_->SetBackfaceVisibility(
- GetLayoutObject().StyleRef().BackfaceVisibility() ==
- EBackfaceVisibility::kVisible);
+ // In BGPT mode, we do not need to update the backface visibility here, as it
+ // will already be set by PaintArtifactCompsitor based on
+ // TransformPaintPropertyNode::GetBackfaceVisibility.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ graphics_layer_->SetBackfaceVisibility(
+ GetLayoutObject().StyleRef().BackfaceVisibility() ==
+ EBackfaceVisibility::kVisible);
+ }
}
void CompositedLayerMapping::ComputeGraphicsLayerParentLocation(
@@ -1383,7 +1389,8 @@ void CompositedLayerMapping::UpdateAncestorClippingLayerGeometry(
kIgnorePlatformOverlayScrollbarSize, kIgnoreOverflowClipAndScroll);
ClipRect clip_rect;
- owning_layer_.Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ owning_layer_
+ .Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(clip_rects_context, clip_rect);
// Scroll offset is not included in the clip rect returned above
// (see kIgnoreOverflowClipAndScroll), so we need to add it in
@@ -1542,9 +1549,15 @@ void CompositedLayerMapping::UpdateOverflowControlsHostLayerGeometry(
owning_layer_.SubpixelAccumulation());
overflow_controls_host_layer_->SetSize(gfx::Size(border_box.Size()));
overflow_controls_host_layer_->SetMasksToBounds(true);
- overflow_controls_host_layer_->SetBackfaceVisibility(
- owning_layer_.GetLayoutObject().StyleRef().BackfaceVisibility() ==
- EBackfaceVisibility::kVisible);
+
+ // In BGPT mode, we do not need to update the backface visibility here, as it
+ // will already be set by PaintArtifactCompsitor based on
+ // TransformPaintPropertyNode::GetBackfaceVisibility.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ overflow_controls_host_layer_->SetBackfaceVisibility(
+ owning_layer_.GetLayoutObject().StyleRef().BackfaceVisibility() ==
+ EBackfaceVisibility::kVisible);
+ }
}
void CompositedLayerMapping::UpdateChildContainmentLayerGeometry() {
@@ -1833,7 +1846,7 @@ void CompositedLayerMapping::UpdateInternalHierarchy() {
// TODO(pdr): Ensure painting uses the correct GraphicsLayer when root layer
// scrolls is enabled. crbug.com/638719
if (is_main_frame_layout_view_layer_ &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
bottom_layer = GetLayoutObject()
.GetFrame()
->GetPage()
@@ -1896,7 +1909,7 @@ void CompositedLayerMapping::UpdateContentsRect() {
graphics_layer_->SetContentsRect(PixelSnappedIntRect(ContentsBox()));
}
-void CompositedLayerMapping::UpdateDrawsContent() {
+void CompositedLayerMapping::UpdateDrawsContentAndPaintsHitTest() {
bool in_overlay_fullscreen_video = false;
if (GetLayoutObject().IsVideo()) {
HTMLVideoElement* video_element =
@@ -1909,6 +1922,16 @@ void CompositedLayerMapping::UpdateDrawsContent() {
in_overlay_fullscreen_video ? false : ContainsPaintedContent();
graphics_layer_->SetDrawsContent(has_painted_content);
+ // |has_painted_content| is conservative (e.g., will be true if any descendant
+ // paints content, regardless of whether the descendant content is a hit test)
+ // but an exhaustive check of descendants that paint hit tests would be too
+ // expensive.
+ bool paints_hit_test =
+ has_painted_content ||
+ (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled() &&
+ GetLayoutObject().HasEffectiveWhitelistedTouchAction());
+ graphics_layer_->SetPaintsHitTest(paints_hit_test);
+
if (scrolling_layer_) {
// m_scrollingLayer never has backing store.
// m_scrollingContentsLayer only needs backing store if the scrolled
@@ -1918,6 +1941,7 @@ void CompositedLayerMapping::UpdateDrawsContent() {
!(GetLayoutObject().StyleRef().HasBackground() ||
GetLayoutObject().HasBackdropFilter() || PaintsChildren());
scrolling_contents_layer_->SetDrawsContent(!scrolling_contents_are_empty_);
+ scrolling_contents_layer_->SetPaintsHitTest(paints_hit_test);
}
draws_background_onto_content_layer_ = false;
@@ -1939,8 +1963,10 @@ void CompositedLayerMapping::UpdateDrawsContent() {
// FIXME: we could refine this to only allocate backings for one of these
// layers if possible.
- if (foreground_layer_)
+ if (foreground_layer_) {
foreground_layer_->SetDrawsContent(has_painted_content);
+ foreground_layer_->SetPaintsHitTest(paints_hit_test);
+ }
if (decoration_outline_layer_)
decoration_outline_layer_->SetDrawsContent(true);
@@ -1998,13 +2024,13 @@ bool CompositedLayerMapping::UpdateClippingLayers(
ancestor_clipping_mask_layer_->SetPaintingPhase(
kGraphicsLayerPaintAncestorClippingMask);
ancestor_clipping_layer_->SetMaskLayer(
- ancestor_clipping_mask_layer_.get(), true);
+ ancestor_clipping_mask_layer_.get());
layers_changed = true;
}
} else if (ancestor_clipping_mask_layer_) {
ancestor_clipping_mask_layer_->RemoveFromParent();
ancestor_clipping_mask_layer_ = nullptr;
- ancestor_clipping_layer_->SetMaskLayer(nullptr, false);
+ ancestor_clipping_layer_->SetMaskLayer(nullptr);
layers_changed = true;
}
@@ -2441,7 +2467,11 @@ bool CompositedLayerMapping::UpdateScrollingLayers(
bool layer_changed = false;
if (needs_scrolling_layers) {
if (scrolling_layer_) {
- if (scrolling_coordinator) {
+ // When blink generates property trees, the user input scrollable bits are
+ // stored on scroll nodes instead of layers so there is no need to update
+ // them here.
+ if (scrolling_coordinator &&
+ !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
scrolling_coordinator->UpdateUserInputScrollable(
owning_layer_.GetScrollableArea());
}
@@ -2811,6 +2841,8 @@ bool CompositedLayerMapping::IsDirectlyCompositedImage() const {
if (!image->IsBitmapImage())
return false;
+ UseCounter::Count(GetLayoutObject().GetDocument(),
+ WebFeature::kDirectlyCompositedImage);
return true;
}
@@ -2862,7 +2894,7 @@ void CompositedLayerMapping::UpdateImageContents() {
: kLow_SkFilterQuality);
// Prevent double-drawing: https://bugs.webkit.org/show_bug.cgi?id=58632
- UpdateDrawsContent();
+ UpdateDrawsContentAndPaintsHitTest();
// Image animation is "lazy", in that it automatically stops unless someone is
// drawing the image. So we have to kick the animation each time; this has the
@@ -2977,7 +3009,7 @@ GraphicsLayerUpdater::UpdateType CompositedLayerMapping::UpdateTypeForChildren(
struct SetContentsNeedsDisplayFunctor {
void operator()(GraphicsLayer* layer) const {
- if (layer->DrawsContent())
+ if (layer->PaintsContentOrHitTest())
layer->SetNeedsDisplay();
}
};
@@ -3054,7 +3086,8 @@ void CompositedLayerMapping::LocalClipRectForSquashedLayer(
&ancestor_paint_info->paint_layer->GetLayoutObject().FirstFragment(),
kUncachedClipRects);
ClipRect parent_clip_rect;
- paint_info.paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ paint_info.paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(clip_rects_context, parent_clip_rect);
// Convert from ancestor to local coordinates.
@@ -3146,87 +3179,50 @@ IntRect CompositedLayerMapping::RecomputeInterestRect(
const GraphicsLayer* graphics_layer) const {
IntRect graphics_layer_bounds(IntPoint(), IntSize(graphics_layer->Size()));
- FloatSize offset_from_anchor_layout_object;
- const LayoutBoxModelObject* anchor_layout_object;
- bool should_apply_anchor_overflow_clip = false;
- if (graphics_layer == squashing_layer_.get()) {
- // All squashed layers have the same clip and transform space, so we can use
- // the first squashed layer's layoutObject to map the squashing layer's
- // bounds into viewport space, with offsetFromAnchorLayoutObject to
- // translate squashing layer's bounds into the first squashed layer's space.
- anchor_layout_object =
- &owning_layer_.TransformAncestorOrRoot().GetLayoutObject();
- offset_from_anchor_layout_object =
- ToFloatSize(FloatPoint(SquashingOffsetFromTransformedAncestor()));
-
- // SquashingOffsetFromTransformedAncestor does not include scroll
- // offset.
- if (anchor_layout_object->UsesCompositedScrolling()) {
- offset_from_anchor_layout_object -=
- FloatSize(ToLayoutBox(anchor_layout_object)->ScrolledContentOffset());
- }
- } else {
- DCHECK(graphics_layer == graphics_layer_.get() ||
- graphics_layer == scrolling_contents_layer_.get());
- anchor_layout_object = &owning_layer_.GetLayoutObject();
- IntSize offset = graphics_layer->OffsetFromLayoutObject();
- should_apply_anchor_overflow_clip =
- AdjustForCompositedScrolling(graphics_layer, offset);
- offset_from_anchor_layout_object = FloatSize(offset);
- }
+ FloatClipRect mapping_rect((FloatRect(graphics_layer_bounds)));
- LayoutView* root_view = anchor_layout_object->View();
+ PropertyTreeState source_state = graphics_layer->GetPropertyTreeState();
+
+ LayoutView* root_view = owning_layer_.GetLayoutObject().View();
while (root_view->GetFrame()->OwnerLayoutObject())
root_view = root_view->GetFrame()->OwnerLayoutObject()->View();
- // Start with the bounds of the graphics layer in the space of the anchor
- // LayoutObject.
- FloatRect graphics_layer_bounds_in_object_space(graphics_layer_bounds);
- graphics_layer_bounds_in_object_space.Move(offset_from_anchor_layout_object);
- if (should_apply_anchor_overflow_clip && anchor_layout_object != root_view) {
- FloatRect clip_rect(
- ToLayoutBox(anchor_layout_object)->OverflowClipRect(LayoutPoint()));
- graphics_layer_bounds_in_object_space.Intersect(clip_rect);
- }
-
- // Now map the bounds to its visible content rect in root view space,
- // including applying clips along the way.
- LayoutRect graphics_layer_bounds_in_root_view_space(
- graphics_layer_bounds_in_object_space);
-
- anchor_layout_object->MapToVisualRectInAncestorSpace(
- root_view, graphics_layer_bounds_in_root_view_space, kUseGeometryMapper);
-
- // MapToVisualRectInAncestorSpace doesn't account for the root scroll because
- // it earlies out as soon as we reach this ancestor. That is, it only maps to
- // the space of the root_view, not accounting for the fact that the root_view
- // itself can be scrolled. If the root_view is our anchor_layout_object, then
- // this extra offset is counted in offset_from_anchor_layout_object. In other
- // cases, we need to account for it here. Otherwise, the paint clip below
- // might clip the whole (visible) rect out.
- if (root_view != anchor_layout_object) {
- if (auto* scrollable_area = root_view->GetScrollableArea()) {
- graphics_layer_bounds_in_root_view_space.MoveBy(
- -scrollable_area->VisibleContentRect().Location());
- }
- }
+ PropertyTreeState root_view_contents_state =
+ root_view->FirstFragment().ContentsProperties();
+ PropertyTreeState root_view_border_box_state =
+ root_view->FirstFragment().LocalBorderBoxProperties();
+
+ // 1. Move into local transform space.
+ mapping_rect.MoveBy(FloatPoint(graphics_layer->GetOffsetFromTransformNode()));
+ // 2. Map into contents space of the root LayoutView.
+ GeometryMapper::LocalToAncestorVisualRect(
+ source_state, root_view_contents_state, mapping_rect);
+
+ FloatRect visible_content_rect = mapping_rect.Rect();
- FloatRect visible_content_rect(graphics_layer_bounds_in_root_view_space);
+ // 3. Move into local border box transform space of the root LayoutView.
+ // Note that the overflow clip has *not* been applied.
+ GeometryMapper::SourceToDestinationRect(
+ root_view_contents_state.Transform(),
+ root_view_border_box_state.Transform(), visible_content_rect);
+
+ // 4. Apply overflow clip, or adjusted version if necessary.
root_view->GetFrameView()->ClipPaintRect(&visible_content_rect);
- // Map the visible content rect from root view space to local graphics layer
- // space.
FloatRect local_interest_rect;
// If the visible content rect is empty, then it makes no sense to map it back
// since there is nothing to map.
if (!visible_content_rect.IsEmpty()) {
- local_interest_rect = FloatRect(
- anchor_layout_object
- ->AbsoluteToLocalQuad(visible_content_rect,
- kUseTransforms | kTraverseDocumentBoundaries)
- .EnclosingBoundingBox());
- local_interest_rect.Move(-offset_from_anchor_layout_object);
- // TODO(chrishtr): the code below is a heuristic, instead we should detect
+ local_interest_rect = visible_content_rect;
+ // 5. Map the visible content rect from root view space to local graphics
+ // layer space.
+ GeometryMapper::SourceToDestinationRect(
+ root_view_border_box_state.Transform(), source_state.Transform(),
+ local_interest_rect);
+ local_interest_rect.MoveBy(
+ -FloatPoint(graphics_layer->GetOffsetFromTransformNode()));
+
+ // TODO(chrishtr): the code below is a heuristic. Instead we should detect
// and return whether the mapping failed. In some cases,
// absoluteToLocalQuad can fail to map back to the local space, due to
// passing through non-invertible transforms or floating-point accuracy
@@ -3430,8 +3426,9 @@ void CompositedLayerMapping::PaintContents(
} else if (IsScrollableAreaLayer(graphics_layer)) {
PaintScrollableArea(graphics_layer, context, interest_rect);
}
- probe::didPaint(owning_layer_.GetLayoutObject().GetFrame(), graphics_layer,
- context, LayoutRect(interest_rect));
+ probe::didPaint(owning_layer_.GetLayoutObject().GetFrame(),
+ graphics_layer->CcLayer(), context,
+ LayoutRect(interest_rect));
#if DCHECK_IS_ON()
if (Page* page = GetLayoutObject().GetFrame()->GetPage())
page->SetIsPainting(false);
@@ -3468,14 +3465,11 @@ bool CompositedLayerMapping::IsScrollableAreaLayer(
}
bool CompositedLayerMapping::ShouldThrottleRendering() const {
- return GetLayoutObject().View()->GetFrame()->ShouldThrottleRendering();
+ return GetLayoutObject().GetFrame()->ShouldThrottleRendering();
}
bool CompositedLayerMapping::IsTrackingRasterInvalidations() const {
- return GetLayoutObject()
- .View()
- ->GetFrameView()
- ->IsTrackingPaintInvalidations();
+ return GetLayoutObject().GetFrameView()->IsTrackingPaintInvalidations();
}
void CompositedLayerMapping::SetOverlayScrollbarsHidden(bool hidden) {
@@ -3483,6 +3477,12 @@ void CompositedLayerMapping::SetOverlayScrollbarsHidden(bool hidden) {
scrollable_area->SetScrollbarsHiddenIfOverlay(hidden);
}
+void CompositedLayerMapping::SetPaintArtifactCompositorNeedsUpdate() const {
+ LocalFrameView* frame_view = GetLayoutObject().GetFrameView();
+ DCHECK(frame_view);
+ frame_view->SetPaintArtifactCompositorNeedsUpdate();
+}
+
#if DCHECK_IS_ON()
void CompositedLayerMapping::VerifyNotPainting() {
DCHECK(!GetLayoutObject().GetFrame()->GetPage() ||
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index c83e8cc41ff..9deb283702e 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -215,6 +215,7 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
bool ShouldThrottleRendering() const override;
bool IsTrackingRasterInvalidations() const override;
void SetOverlayScrollbarsHidden(bool) override;
+ void SetPaintArtifactCompositorNeedsUpdate() const override;
#if DCHECK_IS_ON()
void VerifyNotPainting() override;
@@ -421,7 +422,7 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
void UpdateScrollParent(const PaintLayer*);
void UpdateClipParent(const PaintLayer* scroll_parent);
bool UpdateSquashingLayers(bool needs_squashing_layers);
- void UpdateDrawsContent();
+ void UpdateDrawsContentAndPaintsHitTest();
void UpdateChildrenTransform();
void UpdateCompositedBounds();
void UpdateOverscrollBehavior();
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 7d2b078394a..662a396c049 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -477,7 +477,7 @@ TEST_F(CompositedLayerMappingTest, ClippedBigLayer) {
}
TEST_F(CompositedLayerMappingTestWithoutBGPT, ClippingMaskLayer) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
const AtomicString style_without_clipping =
@@ -2238,20 +2238,8 @@ TEST_F(CompositedLayerMappingTest, StickyPositionNotSquashed) {
ToLayoutBlock(GetLayoutObjectByElementId("sticky2"))->Layer();
PaintLayer* sticky3 =
ToLayoutBlock(GetLayoutObjectByElementId("sticky3"))->Layer();
- EXPECT_EQ(kPaintsIntoOwnBacking, sticky1->GetCompositingState());
- EXPECT_EQ(kNotComposited, sticky2->GetCompositingState());
- EXPECT_EQ(kNotComposited, sticky3->GetCompositingState());
-
- PaintLayer* scroller =
- ToLayoutBlock(GetLayoutObjectByElementId("scroller"))->Layer();
- PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
- scrollable_area->ScrollToAbsolutePosition(
- FloatPoint(scrollable_area->ScrollPosition().Y(), 100));
- UpdateAllLifecyclePhasesForTest();
-
- // Now that sticky2 and sticky3 overlap sticky1 they will be promoted, but
- // they should not be squashed into the same layer because they scroll with
- // respect to each other.
+ // All three sticky-pos elements are composited, because we composite
+ // all sticky elements which stick to scrollers.
EXPECT_EQ(kPaintsIntoOwnBacking, sticky1->GetCompositingState());
EXPECT_EQ(kPaintsIntoOwnBacking, sticky2->GetCompositingState());
EXPECT_EQ(kPaintsIntoOwnBacking, sticky3->GetCompositingState());
@@ -2628,7 +2616,7 @@ TEST_F(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
}
TEST_F(CompositedLayerMappingTest, SquashingScroll) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetHtmlInnerHTML(R"HTML(
<style>
@@ -2658,7 +2646,7 @@ TEST_F(CompositedLayerMappingTest, SquashingScroll) {
}
TEST_F(CompositedLayerMappingTest, SquashingScrollInterestRect) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetHtmlInnerHTML(R"HTML(
<style>
@@ -2684,7 +2672,7 @@ TEST_F(CompositedLayerMappingTest, SquashingScrollInterestRect) {
TEST_F(CompositedLayerMappingTest,
SquashingBoundsUnderCompositedScrollingWithTransform) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetHtmlInnerHTML(R"HTML(
@@ -2720,7 +2708,7 @@ transform'></div>
}
TEST_F(CompositedLayerMappingTest, ContentsNotOpaqueWithForegroundLayer) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetHtmlInnerHTML(R"HTML(
@@ -2744,8 +2732,30 @@ TEST_F(CompositedLayerMappingTest, ContentsNotOpaqueWithForegroundLayer) {
EXPECT_FALSE(mapping->MainGraphicsLayer()->ContentsOpaque());
}
+TEST_F(CompositedLayerMappingTest, TouchActionRectsWithoutContent) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ SetBodyInnerHTML(
+ "<div id='target' style='will-change: transform; width: 100px;"
+ " height: 100px; touch-action: none;'></div>");
+ auto* box = ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"));
+ auto* mapping = box->Layer()->GetCompositedLayerMapping();
+
+ const auto* layer = mapping->MainGraphicsLayer()->CcLayer();
+ auto expected = gfx::Rect(0, 0, 100, 100);
+ EXPECT_EQ(layer->touch_action_region().region().bounds(), expected);
+
+ EXPECT_TRUE(mapping->MainGraphicsLayer()->PaintsHitTest());
+
+ // The only painted content for the main graphics layer is the touch-action
+ // rect which is not sent to cc, so the cc::layer should not draw content.
+ EXPECT_FALSE(layer->DrawsContent());
+ EXPECT_FALSE(mapping->MainGraphicsLayer()->DrawsContent());
+}
+
TEST_F(CompositedLayerMappingTest, ContentsOpaque) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetHtmlInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
index 0c7bdf68294..48bf5a3e2b3 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
@@ -24,12 +24,8 @@ static const LayoutBoxModelObject* ClippingContainerFromClipChainParent(
: clip_chain_parent->ClippingContainer();
}
-CompositingInputsUpdater::CompositingInputsUpdater(
- PaintLayer* root_layer,
- CompositingReasonFinder& compositing_reason_finder)
- : geometry_map_(kUseTransforms),
- root_layer_(root_layer),
- compositing_reason_finder_(compositing_reason_finder) {}
+CompositingInputsUpdater::CompositingInputsUpdater(PaintLayer* root_layer)
+ : geometry_map_(kUseTransforms), root_layer_(root_layer) {}
CompositingInputsUpdater::~CompositingInputsUpdater() = default;
@@ -80,14 +76,16 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
geometry_map_.PushMappingsToAncestor(layer, layer->Parent());
- PaintLayer* enclosing_composited_layer = info.enclosing_composited_layer;
+ PaintLayer* enclosing_stacking_composited_layer =
+ info.enclosing_stacking_composited_layer;
PaintLayer* enclosing_squashing_composited_layer =
info.enclosing_squashing_composited_layer;
switch (layer->GetCompositingState()) {
case kNotComposited:
break;
case kPaintsIntoOwnBacking:
- enclosing_composited_layer = layer;
+ if (layer->GetLayoutObject().StyleRef().IsStackingContext())
+ enclosing_stacking_composited_layer = layer;
break;
case kPaintsIntoGroupedBacking:
enclosing_squashing_composited_layer =
@@ -96,8 +94,8 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
}
if (layer->NeedsCompositingInputsUpdate()) {
- if (enclosing_composited_layer) {
- enclosing_composited_layer->GetCompositedLayerMapping()
+ if (enclosing_stacking_composited_layer) {
+ enclosing_stacking_composited_layer->GetCompositedLayerMapping()
->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
}
if (enclosing_squashing_composited_layer) {
@@ -121,7 +119,8 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
if (update_type == kForceUpdate)
UpdateAncestorDependentCompositingInputs(layer, info);
- info.enclosing_composited_layer = enclosing_composited_layer;
+ info.enclosing_stacking_composited_layer =
+ enclosing_stacking_composited_layer;
info.enclosing_squashing_composited_layer =
enclosing_squashing_composited_layer;
@@ -223,14 +222,8 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
// child.
// 6. If |layer| is the root, composite if
// DescendantHasDirectCompositingReason is true for |layer|.
- bool ignore_lcd_text =
- (layer->AncestorScrollingLayer() &&
- !layer->AncestorScrollingLayer()->IsRootLayer() &&
- layer->AncestorScrollingLayer()->NeedsCompositedScrolling());
-
layer->SetPotentialCompositingReasonsFromNonStyle(
- compositing_reason_finder_.NonStyleDeterminedDirectReasons(
- layer, ignore_lcd_text));
+ CompositingReasonFinder::NonStyleDeterminedDirectReasons(*layer));
if (layer->GetScrollableArea()) {
layer->GetScrollableArea()->UpdateNeedsCompositedScrolling(
@@ -309,7 +302,7 @@ void CompositingInputsUpdater::UpdateAncestorDependentCompositingInputs(
}
ClipRect clip_rect;
- layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ layer->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(
ClipRectsContext(root_layer_,
&root_layer_->GetLayoutObject().FirstFragment(),
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
index 823f1569c12..04fbc010961 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
@@ -11,15 +11,12 @@
namespace blink {
class PaintLayer;
-class CompositingReasonFinder;
class CompositingInputsUpdater {
STACK_ALLOCATED();
public:
- explicit CompositingInputsUpdater(
- PaintLayer* root_layer,
- CompositingReasonFinder& compositing_reason_finder);
+ explicit CompositingInputsUpdater(PaintLayer* root_layer);
~CompositingInputsUpdater();
void Update();
@@ -35,7 +32,8 @@ class CompositingInputsUpdater {
};
struct AncestorInfo {
- PaintLayer* enclosing_composited_layer = nullptr;
+ // The ancestor composited PaintLayer which is also a stacking context.
+ PaintLayer* enclosing_stacking_composited_layer = nullptr;
// A "squashing composited layer" is a PaintLayer that owns a squashing
// layer. This variable stores the squashing composited layer for the
// nearest PaintLayer ancestor which is squashed.
@@ -71,7 +69,6 @@ class CompositingInputsUpdater {
LayoutGeometryMap geometry_map_;
PaintLayer* root_layer_;
- CompositingReasonFinder& compositing_reason_finder_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
index d8f7858836e..587f66555f4 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
@@ -24,7 +24,7 @@ enum class ScrollbarOrCorner {
namespace blink {
void CompositingLayerPropertyUpdater::Update(const LayoutObject& object) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
if (!object.HasLayer())
@@ -69,7 +69,7 @@ void CompositingLayerPropertyUpdater::Update(const LayoutObject& object) {
// Before BlinkGenPropertyTrees, CSS clip could not be composited so
// we should avoid setting it on the layer itself.
if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (const auto* properties = fragment_data.PaintProperties()) {
if (const auto* css_clip = properties->CssClip()) {
container_layer_state->SetClip(css_clip->Parent());
@@ -152,27 +152,25 @@ void CompositingLayerPropertyUpdater::Update(const LayoutObject& object) {
// reason of adding ScrollOrigin().
auto contents_paint_offset =
snapped_paint_offset + ToLayoutBox(object).ScrollOrigin();
- auto SetContentsLayerState = [&fragment_data, &contents_paint_offset](
- GraphicsLayer* graphics_layer) {
+ auto SetScrollingContentsLayerState = [&fragment_data,
+ &contents_paint_offset](
+ GraphicsLayer* graphics_layer) {
if (graphics_layer) {
graphics_layer->SetLayerState(
fragment_data.ContentsProperties(),
contents_paint_offset + graphics_layer->OffsetFromLayoutObject());
}
};
- SetContentsLayerState(mapping->ScrollingContentsLayer());
- SetContentsLayerState(mapping->ForegroundLayer());
+ SetScrollingContentsLayerState(mapping->ScrollingContentsLayer());
+ SetScrollingContentsLayerState(mapping->ForegroundLayer());
} else {
SetContainerLayerState(mapping->ForegroundLayer());
}
auto* main_graphics_layer = mapping->MainGraphicsLayer();
- if (const auto* contents_layer = main_graphics_layer->ContentsLayer()) {
- auto position = contents_layer->position();
- main_graphics_layer->SetContentsLayerState(
- fragment_data.ContentsProperties(),
- snapped_paint_offset + main_graphics_layer->OffsetFromLayoutObject() +
- IntSize(position.x(), position.y()));
+ if (main_graphics_layer->ContentsLayer()) {
+ main_graphics_layer->SetContentsPropertyTreeState(
+ fragment_data.ContentsProperties());
}
if (auto* squashing_layer = mapping->SquashingLayer()) {
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
index bc5808dac28..b5ec928673c 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -19,63 +19,42 @@
namespace blink {
-CompositingReasonFinder::CompositingReasonFinder(LayoutView& layout_view)
- : layout_view_(layout_view),
- compositing_triggers_(
- static_cast<CompositingTriggerFlags>(kAllCompositingTriggers)) {
- UpdateTriggers();
-}
-
-void CompositingReasonFinder::UpdateTriggers() {
- compositing_triggers_ = 0;
-
- Settings& settings = layout_view_.GetDocument().GetPage()->GetSettings();
- if (settings.GetPreferCompositingToLCDTextEnabled()) {
- compositing_triggers_ |= kScrollableInnerFrameTrigger;
- compositing_triggers_ |= kOverflowScrollTrigger;
- compositing_triggers_ |= kViewportConstrainedPositionedTrigger;
- }
-}
-
-bool CompositingReasonFinder::IsMainFrame() const {
- return layout_view_.GetDocument().IsInMainFrame();
-}
-
CompositingReasons CompositingReasonFinder::DirectReasons(
- const PaintLayer* layer,
- bool ignore_lcd_text) const {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ const PaintLayer& layer) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return CompositingReason::kNone;
- DCHECK_EQ(PotentialCompositingReasonsFromStyle(layer->GetLayoutObject()),
- layer->PotentialCompositingReasonsFromStyle());
+ DCHECK_EQ(PotentialCompositingReasonsFromStyle(layer.GetLayoutObject()),
+ layer.PotentialCompositingReasonsFromStyle());
CompositingReasons style_determined_direct_compositing_reasons =
- layer->PotentialCompositingReasonsFromStyle() &
+ layer.PotentialCompositingReasonsFromStyle() &
CompositingReason::kComboAllDirectStyleDeterminedReasons;
return style_determined_direct_compositing_reasons |
- NonStyleDeterminedDirectReasons(layer, ignore_lcd_text);
+ NonStyleDeterminedDirectReasons(layer);
}
-bool CompositingReasonFinder::RequiresCompositingForScrollableFrame() const {
+bool CompositingReasonFinder::RequiresCompositingForScrollableFrame(
+ const LayoutView& layout_view) {
// Need this done first to determine overflow.
- DCHECK(!layout_view_.NeedsLayout());
- if (IsMainFrame())
+ DCHECK(!layout_view.NeedsLayout());
+ if (layout_view.GetDocument().IsInMainFrame())
return false;
- if (!(compositing_triggers_ & kScrollableInnerFrameTrigger))
+ const auto& settings = *layout_view.GetDocument().GetSettings();
+ if (!settings.GetPreferCompositingToLCDTextEnabled())
return false;
- if (layout_view_.GetFrameView()->Size().IsEmpty())
+ if (layout_view.GetFrameView()->Size().IsEmpty())
return false;
- return layout_view_.GetFrameView()->LayoutViewport()->ScrollsOverflow();
+ return layout_view.GetFrameView()->LayoutViewport()->ScrollsOverflow();
}
CompositingReasons
CompositingReasonFinder::PotentialCompositingReasonsFromStyle(
- LayoutObject& layout_object) const {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ const LayoutObject& layout_object) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return CompositingReason::kNone;
CompositingReasons reasons = CompositingReason::kNone;
@@ -151,35 +130,34 @@ bool CompositingReasonFinder::RequiresCompositingForTransform(
}
CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
- const PaintLayer* layer,
- bool ignore_lcd_text) const {
+ const PaintLayer& layer) {
CompositingReasons direct_reasons = CompositingReason::kNone;
- LayoutObject& layout_object = layer->GetLayoutObject();
+ LayoutObject& layout_object = layer.GetLayoutObject();
// TODO(chrishtr): remove this hammer in favor of something more targeted.
// See crbug.com/749349.
- if (layer->ClipParent() && layer->GetLayoutObject().IsOutOfFlowPositioned())
+ if (layer.ClipParent() && layer.GetLayoutObject().IsOutOfFlowPositioned())
direct_reasons |= CompositingReason::kOutOfFlowClipping;
- if (RequiresCompositingForRootScroller(*layer))
+ if (RequiresCompositingForRootScroller(layer))
direct_reasons |= CompositingReason::kRootScroller;
// Composite |layer| if it is inside of an ancestor scrolling layer, but that
// scrolling layer is not on the stacking context ancestor chain of |layer|.
// See the definition of the scrollParent property in Layer for more detail.
- if (const PaintLayer* scrolling_ancestor = layer->AncestorScrollingLayer()) {
- if (scrolling_ancestor->NeedsCompositedScrolling() && layer->ScrollParent())
+ if (const PaintLayer* scrolling_ancestor = layer.AncestorScrollingLayer()) {
+ if (scrolling_ancestor->NeedsCompositedScrolling() && layer.ScrollParent())
direct_reasons |= CompositingReason::kOverflowScrollingParent;
}
- if (RequiresCompositingForScrollDependentPosition(layer, ignore_lcd_text))
+ if (RequiresCompositingForScrollDependentPosition(layer))
direct_reasons |= CompositingReason::kScrollDependentPosition;
// TODO(crbug.com/839341): Remove once we support main-thread AnimationWorklet
// and don't need to promote the scroll-source.
- if (layer->GetScrollableArea() && layer->GetLayoutObject().GetNode() &&
+ if (layer.GetScrollableArea() && layer.GetLayoutObject().GetNode() &&
ScrollTimeline::HasActiveScrollTimeline(
- layer->GetLayoutObject().GetNode())) {
+ layer.GetLayoutObject().GetNode())) {
direct_reasons |= CompositingReason::kScrollTimelineTarget;
}
@@ -187,12 +165,13 @@ CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
// PaintLayer children and whose children can't use its backing to render
// into. These children (the controls) always need to be promoted into their
// own layers to draw on top of the accelerated video.
- if (layer->CompositingContainer() &&
- layer->CompositingContainer()->GetLayoutObject().IsVideo())
+ if (layer.CompositingContainer() &&
+ layer.CompositingContainer()->GetLayoutObject().IsVideo())
direct_reasons |= CompositingReason::kVideoOverlay;
- if (layer->IsRootLayer() && (RequiresCompositingForScrollableFrame() ||
- layout_view_.GetFrame()->IsLocalRoot())) {
+ if (layer.IsRootLayer() &&
+ (RequiresCompositingForScrollableFrame(*layout_object.View()) ||
+ layout_object.GetFrame()->IsLocalRoot())) {
direct_reasons |= CompositingReason::kRoot;
}
@@ -259,34 +238,26 @@ bool CompositingReasonFinder::RequiresCompositingForRootScroller(
}
bool CompositingReasonFinder::RequiresCompositingForScrollDependentPosition(
- const PaintLayer* layer,
- bool ignore_lcd_text) const {
- if (!layer->GetLayoutObject().StyleRef().HasViewportConstrainedPosition() &&
- !layer->GetLayoutObject().StyleRef().HasStickyConstrainedPosition())
+ const PaintLayer& layer) {
+ const auto& layout_object = layer.GetLayoutObject();
+ if (!layout_object.StyleRef().HasViewportConstrainedPosition() &&
+ !layout_object.StyleRef().HasStickyConstrainedPosition())
return false;
- if (!(ignore_lcd_text ||
- (compositing_triggers_ & kViewportConstrainedPositionedTrigger)) &&
- (!RuntimeEnabledFeatures::CompositeOpaqueFixedPositionEnabled() ||
- !layer->BackgroundIsKnownToBeOpaqueInRect(
- LayoutRect(layer->BoundingBoxForCompositing()), true) ||
- layer->CompositesWithTransform() || layer->CompositesWithOpacity())) {
- return false;
- }
// Don't promote fixed position elements that are descendants of a non-view
// container, e.g. transformed elements. They will stay fixed wrt the
// container rather than the enclosing frame.
- EPosition position = layer->GetLayoutObject().StyleRef().GetPosition();
+ EPosition position = layout_object.StyleRef().GetPosition();
if (position == EPosition::kFixed) {
- return layer->FixedToViewport() &&
- layout_view_.GetFrameView()->LayoutViewport()->ScrollsOverflow();
+ return layer.FixedToViewport() &&
+ layout_object.GetFrameView()->LayoutViewport()->ScrollsOverflow();
}
DCHECK_EQ(position, EPosition::kSticky);
// Don't promote sticky position elements that cannot move with scrolls.
- if (!layer->SticksToScroller())
+ if (!layer.SticksToScroller())
return false;
- return layer->AncestorOverflowLayer()->ScrollsOverflow();
+ return layer.AncestorOverflowLayer()->ScrollsOverflow();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
index 0bf467bf6cb..0eca51b5dfe 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
@@ -7,7 +7,6 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/paint/compositing/compositing_triggers.h"
#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -22,26 +21,17 @@ class CORE_EXPORT CompositingReasonFinder {
DISALLOW_NEW();
public:
- explicit CompositingReasonFinder(LayoutView&);
+ static CompositingReasons PotentialCompositingReasonsFromStyle(
+ const LayoutObject&);
- CompositingReasons PotentialCompositingReasonsFromStyle(LayoutObject&) const;
+ static CompositingReasons NonStyleDeterminedDirectReasons(const PaintLayer&);
- CompositingReasons NonStyleDeterminedDirectReasons(
- const PaintLayer*,
- bool ignore_lcd_text) const;
- LayoutView& layout_view_;
- CompositingTriggerFlags compositing_triggers_;
DISALLOW_COPY_AND_ASSIGN(CompositingReasonFinder);
- // Returns the direct reasons for compositing the given layer. If
- // |ignoreLCDText| is true promotion will not try to preserve subpixel text
- // rendering (i.e. partially transparent layers will be promoted).
- CompositingReasons DirectReasons(const PaintLayer*,
- bool ignore_lcd_text) const;
+ // Returns the direct reasons for compositing the given layer.
+ static CompositingReasons DirectReasons(const PaintLayer&);
- void UpdateTriggers();
-
- bool RequiresCompositingForScrollableFrame() const;
+ static bool RequiresCompositingForScrollableFrame(const LayoutView&);
static CompositingReasons CompositingReasonsForAnimation(
const ComputedStyle&);
static bool RequiresCompositingForOpacityAnimation(const ComputedStyle&);
@@ -52,12 +42,7 @@ class CORE_EXPORT CompositingReasonFinder {
static bool RequiresCompositingForTransform(const LayoutObject&);
static bool RequiresCompositingForRootScroller(const PaintLayer&);
- bool RequiresCompositingForScrollDependentPosition(
- const PaintLayer*,
- bool ignore_lcd_text) const;
-
- private:
- bool IsMainFrame() const;
+ static bool RequiresCompositingForScrollDependentPosition(const PaintLayer&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
index 3dd6e2789a9..263f277230b 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -94,40 +94,6 @@ TEST_F(CompositingReasonFinderTest, PromoteNonTrivial3DByDefault) {
EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
}
-TEST_F(CompositingReasonFinderTest, PromoteOpaqueFixedPosition) {
- ScopedCompositeOpaqueFixedPositionForTest composite_fixed_position(true);
-
- SetBodyInnerHTML(R"HTML(
- <div id='translucent' style='width: 20px; height: 20px; position:
- fixed; top: 100px; left: 100px;'></div>
- <div id='opaque' style='width: 20px; height: 20px; position: fixed;
- top: 100px; left: 200px; background: white;'></div>
- <div id='opaque-with-shadow' style='width: 20px; height: 20px;
- position: fixed; top: 100px; left: 300px; background: white;
- box-shadow: 10px 10px 5px #888888;'></div>
- <div id='spacer' style='height: 2000px'></div>
- )HTML");
-
- // The translucent fixed box should not be promoted.
- Element* element = GetDocument().getElementById("translucent");
- PaintLayer* paint_layer =
- ToLayoutBoxModelObject(element->GetLayoutObject())->Layer();
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-
- // The opaque fixed box should be promoted and be opaque so that text will be
- // drawn with subpixel anti-aliasing.
- element = GetDocument().getElementById("opaque");
- paint_layer = ToLayoutBoxModelObject(element->GetLayoutObject())->Layer();
- EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
- EXPECT_TRUE(paint_layer->GraphicsLayerBacking()->ContentsOpaque());
-
- // The opaque fixed box with shadow should not be promoted because the layer
- // will include the shadow which is not opaque.
- element = GetDocument().getElementById("opaque-with-shadow");
- paint_layer = ToLayoutBoxModelObject(element->GetLayoutObject())->Layer();
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-}
-
TEST_F(CompositingReasonFinderTest, OnlyAnchoredStickyPositionPromoted) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -178,103 +144,6 @@ TEST_F(CompositingReasonFinderTest, OnlyScrollingStickyPositionPromoted) {
->GetCompositingState());
}
-// Tests that a transform on the fixed or an ancestor will prevent promotion
-// TODO(flackr): Allow integer transforms as long as all of the ancestor
-// transforms are also integer.
-TEST_F(CompositingReasonFinderTest, OnlyNonTransformedFixedLayersPromoted) {
- ScopedCompositeOpaqueFixedPositionForTest composite_fixed_position(true);
-
- SetBodyInnerHTML(R"HTML(
- <style>
- #fixed { position: fixed; height: 200px; width: 200px; background:
- white; top: 0; }
- #spacer { height: 3000px; }
- </style>
- <div id="parent">
- <div id="fixed"></div>
- <div id="spacer"></div>
- </div>
- )HTML");
-
- Element* parent = GetDocument().getElementById("parent");
- Element* fixed = GetDocument().getElementById("fixed");
- PaintLayer* paint_layer =
- ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
- EXPECT_TRUE(paint_layer->GraphicsLayerBacking()->ContentsOpaque());
-
- // Change the parent to have a transform.
- parent->setAttribute(html_names::kStyleAttr, "transform: translate(1px, 0);");
- UpdateAllLifecyclePhasesForTest();
- paint_layer = ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-
- // Change the parent to have no transform again.
- parent->removeAttribute(html_names::kStyleAttr);
- UpdateAllLifecyclePhasesForTest();
- paint_layer = ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
- EXPECT_TRUE(paint_layer->GraphicsLayerBacking()->ContentsOpaque());
-
- // Apply a transform to the fixed directly.
- fixed->setAttribute(html_names::kStyleAttr, "transform: translate(1px, 0);");
- UpdateAllLifecyclePhasesForTest();
- paint_layer = ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-}
-
-// Test that opacity applied to the fixed or an ancestor will cause the
-// scrolling contents layer to not be promoted.
-TEST_F(CompositingReasonFinderTest, OnlyOpaqueFixedLayersPromoted) {
- ScopedCompositeOpaqueFixedPositionForTest composite_fixed_position(true);
-
- SetBodyInnerHTML(R"HTML(
- <style>
- #fixed { position: fixed; height: 200px; width: 200px; background:
- white; top: 0}
- #spacer { height: 3000px; }
- </style>
- <div id="parent">
- <div id="fixed"></div>
- <div id="spacer"></div>
- </div>
- )HTML");
-
- Element* parent = GetDocument().getElementById("parent");
- Element* fixed = GetDocument().getElementById("fixed");
- PaintLayer* paint_layer =
- ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
- EXPECT_TRUE(paint_layer->GraphicsLayerBacking()->ContentsOpaque());
-
- // Change the parent to be partially translucent.
- parent->setAttribute(html_names::kStyleAttr, "opacity: 0.5;");
- UpdateAllLifecyclePhasesForTest();
- paint_layer = ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-
- // Change the parent to be opaque again.
- parent->setAttribute(html_names::kStyleAttr, "opacity: 1;");
- UpdateAllLifecyclePhasesForTest();
- paint_layer = ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kPaintsIntoOwnBacking, paint_layer->GetCompositingState());
- EXPECT_TRUE(paint_layer->GraphicsLayerBacking()->ContentsOpaque());
-
- // Make the fixed translucent.
- fixed->setAttribute(html_names::kStyleAttr, "opacity: 0.5");
- UpdateAllLifecyclePhasesForTest();
- paint_layer = ToLayoutBoxModelObject(fixed->GetLayoutObject())->Layer();
- ASSERT_TRUE(paint_layer);
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-}
-
TEST_F(CompositingReasonFinderTest, RequiresCompositingForTransformAnimation) {
scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
style->SetSubtreeWillChangeContents(false);
@@ -362,38 +231,6 @@ TEST_F(CompositingReasonFinderTest, CompositingReasonsForAnimation) {
CompositingReasonFinder::CompositingReasonsForAnimation(*style));
}
-TEST_F(CompositingReasonFinderTest, CompositeNestedSticky) {
- ScopedCompositeOpaqueFixedPositionForTest composite_fixed_position(true);
-
- SetBodyInnerHTML(R"HTML(
- <style>.scroller { overflow: scroll; height: 200px; width: 100px; }
- .container { height: 500px; }
- .opaque { background-color: white; contain: paint; }
- #outerSticky { height: 50px; position: sticky; top: 0px; }
- #innerSticky { height: 20px; position: sticky; top: 25px; }</style>
- <div class='scroller'>
- <div class='container'>
- <div id='outerSticky' class='opaque'>
- <div id='innerSticky' class='opaque'></div>
- </div>
- </div>
- </div>
- )HTML");
-
- Element* outer_sticky = GetDocument().getElementById("outerSticky");
- PaintLayer* outer_sticky_layer =
- ToLayoutBoxModelObject(outer_sticky->GetLayoutObject())->Layer();
- ASSERT_TRUE(outer_sticky_layer);
-
- Element* inner_sticky = GetDocument().getElementById("innerSticky");
- PaintLayer* inner_sticky_layer =
- ToLayoutBoxModelObject(inner_sticky->GetLayoutObject())->Layer();
- ASSERT_TRUE(inner_sticky_layer);
-
- EXPECT_EQ(kPaintsIntoOwnBacking, outer_sticky_layer->GetCompositingState());
- EXPECT_EQ(kPaintsIntoOwnBacking, inner_sticky_layer->GetCompositingState());
-}
-
TEST_F(CompositingReasonFinderTest, DontPromoteEmptyIframe) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index 1fa0a141872..12aa542fa4a 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -167,7 +167,6 @@ static bool RequiresCompositingOrSquashing(CompositingReasons reasons) {
}
static CompositingReasons SubtreeReasonsForCompositing(
- const CompositingReasonFinder& compositing_reason_finder,
PaintLayer* layer,
bool has_composited_descendants,
bool has3d_transformed_descendants) {
@@ -186,19 +185,6 @@ static CompositingReasons SubtreeReasonsForCompositing(
subtree_reasons |= CompositingReason::kIsolateCompositedDescendants;
}
- // We ignore LCD text here because we are required to composite
- // scroll-dependant fixed position elements with composited descendants for
- // correctness - even if we lose LCD.
- //
- // TODO(smcgruer): Only composite fixed if needed (http://crbug.com/742213)
- const bool ignore_lcd_text = true;
- if (layer->GetLayoutObject().StyleRef().GetPosition() == EPosition::kFixed ||
- compositing_reason_finder.RequiresCompositingForScrollDependentPosition(
- layer, ignore_lcd_text)) {
- subtree_reasons |=
- CompositingReason::kPositionFixedOrStickyWithCompositedDescendants;
- }
-
// A layer with preserve-3d or perspective only needs to be composited if
// there are descendant layers that will be affected by the preserve-3d or
// perspective.
@@ -211,10 +197,8 @@ static CompositingReasons SubtreeReasonsForCompositing(
}
CompositingRequirementsUpdater::CompositingRequirementsUpdater(
- LayoutView& layout_view,
- CompositingReasonFinder& compositing_reason_finder)
- : layout_view_(layout_view),
- compositing_reason_finder_(compositing_reason_finder) {}
+ LayoutView& layout_view)
+ : layout_view_(layout_view) {}
CompositingRequirementsUpdater::~CompositingRequirementsUpdater() = default;
@@ -287,38 +271,19 @@ void CompositingRequirementsUpdater::UpdateRecursive(
bool use_clipped_bounding_rect = !has_non_root_composited_scrolling_ancestor;
- // We have to promote the sticky element to work around the bug
- // (https://crbug.com/698358) of not being able to invalidate the ancestor
- // after updating the sticky layer position.
- // TODO(yigu): We should check if we have already lost lcd text. This
- // would require tracking if we think the current compositing ancestor
- // layer meets the requirements (i.e. opaque, integer transform, etc).
- const bool moves_with_respect_to_compositing_ancestor =
- layer->SticksToScroller() &&
- !current_recursion_data.compositing_ancestor_->IsRootLayer();
- const bool ignore_lcd_text = has_non_root_composited_scrolling_ancestor;
-
const bool layer_can_be_composited = compositor->CanBeComposited(layer);
CompositingReasons direct_from_paint_layer = 0;
if (layer_can_be_composited)
direct_from_paint_layer = layer->DirectCompositingReasons();
- if (compositing_reason_finder_.RequiresCompositingForScrollDependentPosition(
- layer,
- ignore_lcd_text || moves_with_respect_to_compositing_ancestor)) {
- direct_from_paint_layer |= CompositingReason::kScrollDependentPosition;
- }
-
#if DCHECK_IS_ON()
if (layer_can_be_composited) {
DCHECK(direct_from_paint_layer ==
- compositing_reason_finder_.DirectReasons(
- layer,
- ignore_lcd_text || moves_with_respect_to_compositing_ancestor))
+ CompositingReasonFinder::DirectReasons(*layer))
<< " Expected: "
<< CompositingReason::ToString(
- compositing_reason_finder_.DirectReasons(layer, ignore_lcd_text))
+ CompositingReasonFinder::DirectReasons(*layer))
<< " Actual: " << CompositingReason::ToString(direct_from_paint_layer);
}
#endif
@@ -591,8 +556,7 @@ void CompositingRequirementsUpdater::UpdateRecursive(
// descendant layers.
CompositingReasons subtree_compositing_reasons =
SubtreeReasonsForCompositing(
- compositing_reason_finder_, layer,
- child_recursion_data.subtree_is_compositing_,
+ layer, child_recursion_data.subtree_is_compositing_,
any_descendant_has3d_transform);
if (layer_can_be_composited)
reasons_to_composite |= subtree_compositing_reasons;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
index 9419f90c76e..81b6e8580a8 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
@@ -34,7 +34,6 @@
namespace blink {
-class CompositingReasonFinder;
class PaintLayer;
class LayoutView;
@@ -42,7 +41,7 @@ class CompositingRequirementsUpdater {
STACK_ALLOCATED();
public:
- CompositingRequirementsUpdater(LayoutView&, CompositingReasonFinder&);
+ CompositingRequirementsUpdater(LayoutView&);
~CompositingRequirementsUpdater();
// Recurse through the layers in z-index and overflow order (which is
@@ -72,7 +71,6 @@ class CompositingRequirementsUpdater {
CompositingReasonsStats&);
LayoutView& layout_view_;
- CompositingReasonFinder& compositing_reason_finder_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
index 5d3bedb33f0..fb10734686d 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
@@ -24,30 +24,6 @@ void CompositingRequirementsUpdaterTest::SetUp() {
EnableCompositing();
}
-TEST_F(CompositingRequirementsUpdaterTest, FixedPosOverlap) {
- SetBodyInnerHTML(R"HTML(
- <div style="position: relative; width: 500px; height: 300px;
- will-change: transform"></div>
- <div id=fixed style="position: fixed; width: 500px; height: 300px;
- top: 300px"></div>
- <div style="width: 200px; height: 3000px"></div>
- )HTML");
-
- LayoutBoxModelObject* fixed =
- ToLayoutBoxModelObject(GetLayoutObjectByElementId("fixed"));
-
- EXPECT_EQ(
- CompositingReason::kOverlap | CompositingReason::kSquashingDisallowed,
- fixed->Layer()->GetCompositingReasons());
-
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 100),
- kUserScroll);
- UpdateAllLifecyclePhasesForTest();
-
- // No longer overlaps the first div.
- EXPECT_EQ(CompositingReason::kNone, fixed->Layer()->GetCompositingReasons());
-}
-
TEST_F(CompositingRequirementsUpdaterTest,
NoOverlapReasonForNonSelfPaintingLayer) {
SetBodyInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_triggers.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_triggers.h
deleted file mode 100644
index 4e2d3786cda..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_triggers.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple, Inc. All rights
- * reserved.
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2012 Samsung Electronics. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_TRIGGERS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_TRIGGERS_H_
-
-namespace blink {
-
-enum CompositingTrigger {
- kScrollableInnerFrameTrigger = 1 << 1,
- kOverflowScrollTrigger = 1 << 2,
- kViewportConstrainedPositionedTrigger = 1 << 3,
- kAllCompositingTriggers = 0xFFFFFFFF,
-};
-
-typedef unsigned CompositingTriggerFlags;
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index 9b5cc2e6066..6111fe693fb 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -68,7 +68,6 @@ namespace blink {
PaintLayerCompositor::PaintLayerCompositor(LayoutView& layout_view)
: layout_view_(layout_view),
- compositing_reason_finder_(layout_view),
pending_update_type_(kCompositingUpdateNone),
has_accelerated_compositing_(true),
compositing_(false),
@@ -132,11 +131,11 @@ bool PaintLayerCompositor::RootShouldAlwaysComposite() const {
if (!has_accelerated_compositing_)
return false;
return layout_view_.GetFrame()->IsLocalRoot() ||
- compositing_reason_finder_.RequiresCompositingForScrollableFrame();
+ CompositingReasonFinder::RequiresCompositingForScrollableFrame(
+ layout_view_);
}
void PaintLayerCompositor::UpdateAcceleratedCompositingSettings() {
- compositing_reason_finder_.UpdateTriggers();
has_accelerated_compositing_ = layout_view_.GetDocument()
.GetSettings()
->GetAcceleratedCompositingEnabled();
@@ -182,10 +181,10 @@ void PaintLayerCompositor::UpdateIfNeededRecursive(
compositing_reasons_stats.active_animation_layers, 1, 100, 5);
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Blink.Compositing.LayerPromotionCount.AssumedOverlap",
- compositing_reasons_stats.assumed_overlap_layers, 1, 100, 5);
+ compositing_reasons_stats.assumed_overlap_layers, 1, 1000, 5);
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Blink.Compositing.LayerPromotionCount.IndirectComposited",
- compositing_reasons_stats.indirect_composited_layers, 1, 100, 5);
+ compositing_reasons_stats.indirect_composited_layers, 1, 1000, 5);
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Blink.Compositing.LayerPromotionCount.TotalComposited",
compositing_reasons_stats.total_composited_layers, 1, 1000, 10);
@@ -233,7 +232,13 @@ void PaintLayerCompositor::UpdateIfNeededRecursiveInternal(
// InCompositingUpdate.
EnableCompositingModeIfNeeded();
+#if DCHECK_IS_ON()
+ view->SetIsUpdatingDescendantDependentFlags(true);
+#endif
RootLayer()->UpdateDescendantDependentFlags();
+#if DCHECK_IS_ON()
+ view->SetIsUpdatingDescendantDependentFlags(false);
+#endif
layout_view_.CommitPendingSelection();
@@ -252,9 +257,9 @@ void PaintLayerCompositor::UpdateIfNeededRecursiveInternal(
if (!layout_view_.GetDocument().Printing() ||
RuntimeEnabledFeatures::PrintBrowserEnabled()) {
// Although BlinkGenPropertyTreesEnabled still uses PaintLayerCompositor to
- // generate the composited layer tree/list, it also has the SPv2 behavior of
+ // generate the composited layer tree/list, it also has the CAP behavior of
// removing layers that do not draw content. As such, we use the same path
- // as SPv2 for updating composited animations once we know the final set of
+ // as CAP for updating composited animations once we know the final set of
// composited elements (see LocalFrameView::UpdateLifecyclePhasesInternal,
// during kPaintClean).
if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
@@ -301,6 +306,10 @@ void PaintLayerCompositor::SetNeedsCompositingUpdate(
pending_update_type_ = std::max(pending_update_type_, update_type);
if (Page* page = GetPage())
page->Animator().ScheduleVisualUpdate(layout_view_.GetFrame());
+
+ if (layout_view_.DocumentBeingDestroyed())
+ return;
+
Lifecycle().EnsureStateAtMost(DocumentLifecycle::kLayoutClean);
}
@@ -367,7 +376,7 @@ void PaintLayerCompositor::UpdateWithoutAcceleratedCompositing(
DCHECK(!HasAcceleratedCompositing());
if (update_type >= kCompositingUpdateAfterCompositingInputChange)
- CompositingInputsUpdater(RootLayer(), compositing_reason_finder_).Update();
+ CompositingInputsUpdater(RootLayer()).Update();
#if DCHECK_IS_ON()
CompositingInputsUpdater::AssertNeedsCompositingInputsUpdateBitsCleared(
@@ -453,7 +462,7 @@ void PaintLayerCompositor::UpdateIfNeeded(
Vector<PaintLayer*> layers_needing_paint_invalidation;
if (update_type >= kCompositingUpdateAfterCompositingInputChange) {
- CompositingInputsUpdater(update_root, compositing_reason_finder_).Update();
+ CompositingInputsUpdater(update_root).Update();
#if DCHECK_IS_ON()
// FIXME: Move this check to the end of the compositing update.
@@ -471,7 +480,7 @@ void PaintLayerCompositor::UpdateIfNeeded(
return;
}
- CompositingRequirementsUpdater(layout_view_, compositing_reason_finder_)
+ CompositingRequirementsUpdater(layout_view_)
.Update(update_root, compositing_reasons_stats);
CompositingLayerAssigner layer_assigner(this);
@@ -545,13 +554,10 @@ void PaintLayerCompositor::UpdateIfNeeded(
layers_needing_paint_invalidation[i]->GetLayoutObject());
}
- if (root_layer_attachment_ == kRootLayerPendingAttachViaChromeClient) {
- if (Page* page = layout_view_.GetFrame()->GetPage()) {
- page->GetChromeClient().AttachRootGraphicsLayer(RootGraphicsLayer(),
- layout_view_.GetFrame());
- root_layer_attachment_ = kRootLayerAttachedViaChromeClient;
- }
- }
+ // When BlinkGenPropertyTrees is enabled, layer attachment, including the root
+ // layer, must occur in the paint lifecycle step.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ AttachRootLayerViaChromeClient();
// Inform the inspector that the layer tree has changed.
if (IsMainFrame())
@@ -560,6 +566,16 @@ void PaintLayerCompositor::UpdateIfNeeded(
Lifecycle().AdvanceTo(DocumentLifecycle::kCompositingClean);
}
+void PaintLayerCompositor::AttachRootLayerViaChromeClient() {
+ if (root_layer_attachment_ == kRootLayerPendingAttachViaChromeClient) {
+ if (Page* page = layout_view_.GetFrame()->GetPage()) {
+ page->GetChromeClient().AttachRootGraphicsLayer(RootGraphicsLayer(),
+ layout_view_.GetFrame());
+ }
+ root_layer_attachment_ = kRootLayerAttachedViaChromeClient;
+ }
+}
+
static void RestartAnimationOnCompositor(const LayoutObject& layout_object) {
Node* node = layout_object.GetNode();
ElementAnimations* element_animations =
@@ -783,9 +799,9 @@ void PaintLayerCompositor::SetIsInWindow(bool is_in_window) {
void PaintLayerCompositor::UpdatePotentialCompositingReasonsFromStyle(
PaintLayer& layer) {
- layer.SetPotentialCompositingReasonsFromStyle(
- compositing_reason_finder_.PotentialCompositingReasonsFromStyle(
- layer.GetLayoutObject()));
+ auto reasons = CompositingReasonFinder::PotentialCompositingReasonsFromStyle(
+ layer.GetLayoutObject());
+ layer.SetPotentialCompositingReasonsFromStyle(reasons);
}
bool PaintLayerCompositor::CanBeComposited(const PaintLayer* layer) const {
@@ -796,7 +812,7 @@ bool PaintLayerCompositor::CanBeComposited(const PaintLayer* layer) const {
return false;
const bool has_compositor_animation =
- compositing_reason_finder_.CompositingReasonsForAnimation(
+ CompositingReasonFinder::CompositingReasonsForAnimation(
*layer->GetLayoutObject().Style()) != CompositingReason::kNone;
return has_accelerated_compositing_ &&
(has_compositor_animation || !layer->SubtreeIsInvisible()) &&
@@ -877,9 +893,9 @@ void PaintLayerCompositor::DestroyRootLayer() {
}
void PaintLayerCompositor::AttachRootLayer() {
- // In Slimming Paint v2, PaintArtifactCompositor is responsible for the root
- // layer.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // With CompositeAfterPaint, PaintArtifactCompositor is responsible for the
+ // root layer.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
if (layout_view_.GetFrame()->IsLocalRoot()) {
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index 7cf3856bd75..9a6efefd298 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -65,7 +65,7 @@ enum CompositingStateTransitionType {
// decides for each PaintLayer whether it should get a CompositedLayerMapping,
// and asks each CLM to set up its GraphicsLayers.
//
-// In Slimming Paint v2, PaintLayerCompositor will be eventually replaced by
+// With CompositeAfterPaint, PaintLayerCompositor will be eventually replaced by
// PaintArtifactCompositor.
class CORE_EXPORT PaintLayerCompositor {
@@ -156,6 +156,8 @@ class CORE_EXPORT PaintLayerCompositor {
bool IsRootScrollerAncestor() const;
+ void AttachRootLayerViaChromeClient();
+
private:
#if DCHECK_IS_ON()
void AssertNoUnresolvedDirtyBits();
@@ -200,8 +202,6 @@ class CORE_EXPORT PaintLayerCompositor {
LayoutView& layout_view_;
- CompositingReasonFinder compositing_reason_finder_;
-
CompositingUpdateType pending_update_type_;
bool has_accelerated_compositing_;
diff --git a/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc b/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc
index 40063a379c1..4c4954f8941 100644
--- a/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc
@@ -60,6 +60,8 @@ sk_sp<PaintRecord> RecordMarker(Color blink_color) {
static const float kMarkerWidth = 4;
static const float kMarkerHeight = 3;
+// Spacing between two dots.
+static const float kMarkerSpacing = 1;
sk_sp<PaintRecord> RecordMarker(Color blink_color) {
const SkColor color = blink_color.Rgb();
@@ -116,10 +118,8 @@ void DrawDocumentMarker(GraphicsContext& context,
#if defined(OS_MACOSX)
// Make sure to draw only complete dots, and finish inside the marked text.
- width -= fmodf(width, kMarkerWidth * zoom);
-#else
- // Offset it vertically by 1 so that there's some space under the text.
- origin_y += 1;
+ float spacing = kMarkerSpacing * zoom;
+ width -= fmodf(width + spacing, kMarkerWidth * zoom) - spacing;
#endif
const auto rect = SkRect::MakeWH(width, kMarkerHeight * zoom);
@@ -164,19 +164,20 @@ void DocumentMarkerPainter::PaintStyleableMarkerUnderline(
start += 1;
width -= 2;
- // Thick marked text underlines are 2px thick as long as there is room for the
- // 2px line under the baseline. All other marked text underlines are 1px
- // thick. If there's not enough space the underline will touch or overlap
- // characters.
- int line_thickness = 1;
+ // Thick marked text underlines are 2px (before zoom) thick as long as there
+ // is room for the 2px line under the baseline. All other marked text
+ // underlines are 1px (before zoom) thick. If there's not enough space the
+ // underline will touch or overlap characters. Line thickness should change
+ // with zoom.
+ int line_thickness = 1 * style.EffectiveZoom();
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
DCHECK(font_data);
int baseline = font_data ? font_data->GetFontMetrics().Ascent() : 0;
- if (marker.HasThicknessThick() && logical_height.ToInt() - baseline >= 2)
- line_thickness = 2;
-
- // Line thickness should change with zoom.
- line_thickness *= style.EffectiveZoom();
+ if (marker.HasThicknessThick()) {
+ int thick_line_thickness = 2 * style.EffectiveZoom();
+ if (logical_height.ToInt() - baseline >= thick_line_thickness)
+ line_thickness = thick_line_thickness;
+ }
Color marker_color =
marker.UseTextColor()
@@ -192,8 +193,6 @@ void DocumentMarkerPainter::PaintStyleableMarkerUnderline(
width);
}
-static const int kMisspellingLineThickness = 3;
-
void DocumentMarkerPainter::PaintDocumentMarker(
GraphicsContext& context,
const LayoutPoint& box_origin,
@@ -208,26 +207,28 @@ void DocumentMarkerPainter::PaintDocumentMarker(
// actually the most useful, and matches what AppKit does. So, we generally
// place the underline at the bottom of the text, but in larger fonts that's
// not so good so we pin to two pixels under the baseline.
- int line_thickness = kMisspellingLineThickness;
+ float zoom = style.EffectiveZoom();
+ int line_thickness = kMarkerHeight * zoom;
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
DCHECK(font_data);
int baseline = font_data->GetFontMetrics().Ascent();
- int descent = (local_rect.Height() - baseline).ToInt();
+ int available_height = (local_rect.Height() - baseline).ToInt();
int underline_offset;
- if (descent <= (line_thickness + 2)) {
+ if (available_height <= line_thickness + 2 * zoom) {
// Place the underline at the very bottom of the text in small/medium fonts.
+ // The underline will overlap with the bottom of the text if
+ // available_height is smaller than line_thickness.
underline_offset = (local_rect.Height() - line_thickness).ToInt();
} else {
// In larger fonts, though, place the underline up near the baseline to
// prevent a big gap.
- underline_offset = baseline + 2;
+ underline_offset = baseline + 2 * zoom;
}
DrawDocumentMarker(context,
FloatPoint((box_origin.X() + local_rect.X()).ToFloat(),
(box_origin.Y() + underline_offset).ToFloat()),
- local_rect.Width().ToFloat(), marker_type,
- style.EffectiveZoom());
+ local_rect.Width().ToFloat(), marker_type, zoom);
}
TextPaintStyle DocumentMarkerPainter::ComputeTextPaintStyleFrom(
diff --git a/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc
index 8af38dfac51..e506970c225 100644
--- a/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/fonts/font_selector.h"
#include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
#include "third_party/blink/renderer/platform/text/text_run.h"
@@ -55,8 +54,6 @@ void EmbeddedObjectPainter::PaintReplaced(const PaintInfo& paint_info,
LayoutRect content_rect(layout_embedded_object_.PhysicalContentBoxRect());
content_rect.MoveBy(paint_offset);
DrawingRecorder recorder(context, layout_embedded_object_, paint_info.phase);
- GraphicsContextStateSaver state_saver(context);
- context.Clip(PixelSnappedIntRect(content_rect));
Font font = ReplacementTextFont();
const SimpleFontData* font_data = font.PrimaryFont();
diff --git a/chromium/third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h b/chromium/third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h
index ae53517b4b4..f916c83c352 100644
--- a/chromium/third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h
+++ b/chromium/third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h
@@ -108,7 +108,7 @@ class FindVisualRectNeedingUpdateScopeBase {
// while we need neither paint invalidation nor raster invalidation
// for the change. This may miss some real subpixel changes of visual
// rects. TODO(wangxianzhu): Look into whether we can tighten this
- // for SPv2.
+ // for CAP.
(InflatedRect(old_visual_rect_).Contains(new_visual_rect) &&
InflatedRect(new_visual_rect).Contains(old_visual_rect_)))
<< "Visual rect changed without needing update"
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
index 6f5f27e01ec..4218e90351d 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -152,8 +152,7 @@ void FirstMeaningfulPaintDetector::OnNetwork2Quiet() {
if (defer_first_meaningful_paint_ == kDoNotDefer) {
// Report FirstMeaningfulPaint when the page reached network 2-quiet if
// we aren't waiting for a swap timestamp.
- SetFirstMeaningfulPaint(first_meaningful_paint2_quiet_,
- first_meaningful_paint2_quiet_swap);
+ SetFirstMeaningfulPaint(first_meaningful_paint2_quiet_swap);
}
}
ReportHistograms();
@@ -248,8 +247,7 @@ void FirstMeaningfulPaintDetector::ReportSwapTime(
if (defer_first_meaningful_paint_ == kDeferOutstandingSwapPromises &&
outstanding_swap_promise_count_ == 0) {
DCHECK(!first_meaningful_paint2_quiet_.is_null());
- SetFirstMeaningfulPaint(first_meaningful_paint2_quiet_,
- provisional_first_meaningful_paint_swap_);
+ SetFirstMeaningfulPaint(provisional_first_meaningful_paint_swap_);
}
}
@@ -257,11 +255,10 @@ void FirstMeaningfulPaintDetector::NotifyFirstContentfulPaint(
TimeTicks swap_stamp) {
if (defer_first_meaningful_paint_ != kDeferFirstContentfulPaintNotSet)
return;
- SetFirstMeaningfulPaint(first_meaningful_paint2_quiet_, swap_stamp);
+ SetFirstMeaningfulPaint(swap_stamp);
}
void FirstMeaningfulPaintDetector::SetFirstMeaningfulPaint(
- TimeTicks stamp,
TimeTicks swap_stamp) {
DCHECK(paint_timing_->FirstMeaningfulPaint().is_null());
DCHECK(!swap_stamp.is_null());
@@ -276,8 +273,7 @@ void FirstMeaningfulPaintDetector::SetFirstMeaningfulPaint(
paint_timing_->SetFirstMeaningfulPaintCandidate(swap_stamp);
paint_timing_->SetFirstMeaningfulPaint(
- stamp, swap_stamp,
- had_user_input_before_provisional_first_meaningful_paint_);
+ swap_stamp, had_user_input_before_provisional_first_meaningful_paint_);
}
void FirstMeaningfulPaintDetector::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index 43af42982ac..27310dcf94b 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -61,7 +61,7 @@ class CORE_EXPORT FirstMeaningfulPaintDetector
int ActiveConnections();
void ReportHistograms();
void RegisterNotifySwapTime(PaintEvent);
- void SetFirstMeaningfulPaint(TimeTicks stamp, TimeTicks swap_stamp);
+ void SetFirstMeaningfulPaint(TimeTicks swap_stamp);
bool next_paint_is_meaningful_ = false;
HadUserInput had_user_input_ = kNoUserInput;
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
index 888ceb29575..5a0f42e3e1d 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
@@ -109,7 +109,6 @@ TEST_F(FirstMeaningfulPaintDetectorTest, NoFirstPaint) {
SimulateLayoutAndPaint(1);
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
SimulateNetworkStable();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
}
@@ -119,14 +118,8 @@ TEST_F(FirstMeaningfulPaintDetectorTest, OneLayout) {
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
ClearProvisionalFirstMeaningfulPaintSwapPromise();
TimeTicks after_paint = AdvanceClockAndGetTime();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
SimulateNetworkStable();
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(),
- GetPaintTiming().FirstPaintRendered());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
- EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_paint);
EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_paint);
}
@@ -141,12 +134,8 @@ TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantSecond) {
ClearProvisionalFirstMeaningfulPaintSwapPromise();
TimeTicks after_layout2 = AdvanceClockAndGetTime();
SimulateNetworkStable();
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_layout1);
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_layout1);
- EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_layout2);
EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_layout2);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantFirst) {
@@ -158,11 +147,8 @@ TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantFirst) {
SimulateLayoutAndPaint(1);
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
SimulateNetworkStable();
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(),
- GetPaintTiming().FirstPaintRendered());
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
GetPaintTiming().FirstPaintRendered());
- EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_layout1);
EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_layout1);
}
@@ -215,14 +201,10 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
ClearProvisionalFirstMeaningfulPaintSwapPromise();
SimulateNetworkStable();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
MarkFirstContentfulPaintAndClearSwapPromise();
SimulateNetworkStable();
- EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -234,12 +216,8 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
platform_->AdvanceClock(TimeDelta::FromMilliseconds(1));
MarkFirstContentfulPaintAndClearSwapPromise();
SimulateNetworkStable();
- EXPECT_GE(GetPaintTiming().FirstMeaningfulPaintRendered(),
- GetPaintTiming().FirstContentfulPaintRendered());
EXPECT_GE(GetPaintTiming().FirstMeaningfulPaint(),
GetPaintTiming().FirstContentfulPaint());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest, Network2QuietThen0Quiet) {
@@ -257,13 +235,9 @@ TEST_F(FirstMeaningfulPaintDetectorTest, Network2QuietThen0Quiet) {
SimulateNetwork0Quiet();
// The first paint is FirstMeaningfulPaint.
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
- EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_first_paint);
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint);
EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint_swap);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest, Network0QuietThen2Quiet) {
@@ -282,15 +256,8 @@ TEST_F(FirstMeaningfulPaintDetectorTest, Network0QuietThen2Quiet) {
SimulateNetwork2Quiet();
// The second paint is FirstMeaningfulPaint.
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), after_first_paint);
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_paint);
- EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(),
- after_second_paint);
EXPECT_LT(GetPaintTiming().FirstMeaningfulPaint(), after_second_paint);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -301,7 +268,6 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
ClearProvisionalFirstMeaningfulPaintSwapPromise();
SimulateNetworkStable();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
}
@@ -312,10 +278,7 @@ TEST_F(FirstMeaningfulPaintDetectorTest, UserInteractionBeforeFirstPaint) {
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
ClearProvisionalFirstMeaningfulPaintSwapPromise();
SimulateNetworkStable();
- EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -324,13 +287,9 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
SimulateLayoutAndPaint(10);
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
SimulateNetworkStable();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
ClearProvisionalFirstMeaningfulPaintSwapPromise();
- EXPECT_NE(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -343,22 +302,17 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 2U);
// Having outstanding swap promises should defer setting FMP.
SimulateNetworkStable();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
// Clearing the first swap promise should have no effect on FMP.
ClearProvisionalFirstMeaningfulPaintSwapPromise();
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
TimeTicks after_first_swap = AdvanceClockAndGetTime();
// Clearing the last outstanding swap promise should set FMP.
ClearProvisionalFirstMeaningfulPaintSwapPromise();
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_swap);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -367,25 +321,16 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
SimulateLayoutAndPaint(10);
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
ClearProvisionalFirstMeaningfulPaintSwapPromise();
- TimeTicks after_first_meaningful_paint_candidate = AdvanceClockAndGetTime();
platform_->AdvanceClock(TimeDelta::FromMilliseconds(1));
GetPaintTiming().MarkFirstContentfulPaint();
// FCP > FMP candidate, but still waiting for FCP swap.
SimulateNetworkStable();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
// Trigger notifying the detector about the FCP swap.
ClearFirstContentfulPaintSwapPromise();
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(),
- GetPaintTiming().FirstContentfulPaintRendered());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(),
GetPaintTiming().FirstContentfulPaint());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(),
- after_first_meaningful_paint_candidate);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
- GetPaintTiming().FirstMeaningfulPaintRendered());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -399,7 +344,6 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
TimeTicks pre_stable_timestamp = AdvanceClockAndGetTime();
platform_->AdvanceClock(TimeDelta::FromMilliseconds(1));
SimulateNetwork2Quiet();
- EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
// Force another FMP candidate while there is a pending swap promise and the
@@ -413,11 +357,8 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
// non-swap timestamp is used.
ClearProvisionalFirstMeaningfulPaintSwapPromise(pre_stable_timestamp);
EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintRendered(), TimeTicks());
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), pre_stable_timestamp);
- EXPECT_LT(GetPaintTiming().FirstMeaningfulPaintRendered(),
- pre_stable_timestamp);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/frame_painter.cc b/chromium/third_party/blink/renderer/core/paint/frame_painter.cc
index 52e06dff7a7..38b39e3dc6c 100644
--- a/chromium/third_party/blink/renderer/core/paint/frame_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/frame_painter.cc
@@ -25,25 +25,25 @@ bool FramePainter::in_paint_contents_ = false;
void FramePainter::Paint(GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
- const CullRect& rect) {
+ const CullRect& cull_rect) {
if (GetFrameView().ShouldThrottleRendering())
return;
GetFrameView().NotifyPageThatContentAreaWillPaint();
- IntRect document_dirty_rect(rect.Rect());
- document_dirty_rect.Intersect(GetFrameView().FrameRect());
- document_dirty_rect.MoveBy(-GetFrameView().Location());
+ CullRect document_cull_rect(
+ Intersection(cull_rect.Rect(), GetFrameView().FrameRect()));
+ document_cull_rect.MoveBy(-GetFrameView().Location());
- if (document_dirty_rect.IsEmpty())
+ if (document_cull_rect.Rect().IsEmpty())
return;
- PaintContents(context, global_paint_flags, document_dirty_rect);
+ PaintContents(context, global_paint_flags, document_cull_rect);
}
void FramePainter::PaintContents(GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
- const IntRect& rect) {
+ const CullRect& cull_rect) {
Document* document = GetFrameView().GetFrame().GetDocument();
if (GetFrameView().ShouldThrottleRendering() || !document->IsActive())
@@ -66,9 +66,9 @@ void FramePainter::PaintContents(GraphicsContext& context,
DocumentLifecycle::kCompositingClean);
FramePaintTiming frame_paint_timing(context, &GetFrameView().GetFrame());
- TRACE_EVENT1(
- "devtools.timeline,rail", "Paint", "data",
- inspector_paint_event::Data(layout_view, LayoutRect(rect), nullptr));
+ TRACE_EVENT1("devtools.timeline,rail", "Paint", "data",
+ inspector_paint_event::Data(
+ layout_view, LayoutRect(cull_rect.Rect()), nullptr));
bool is_top_level_painter = !in_paint_contents_;
in_paint_contents_ = true;
@@ -101,11 +101,11 @@ void FramePainter::PaintContents(GraphicsContext& context,
root_layer->GetLayoutObject().GetFrame());
context.SetDeviceScaleFactor(device_scale_factor);
- layer_painter.Paint(context, CullRect(rect), updated_global_paint_flags,
+ layer_painter.Paint(context, cull_rect, updated_global_paint_flags,
root_layer_paint_flags);
if (root_layer->ContainsDirtyOverlayScrollbars()) {
- layer_painter.PaintOverlayScrollbars(context, CullRect(rect),
+ layer_painter.PaintOverlayScrollbars(context, cull_rect,
updated_global_paint_flags);
}
@@ -121,7 +121,8 @@ void FramePainter::PaintContents(GraphicsContext& context,
in_paint_contents_ = false;
}
- probe::didPaint(layout_view->GetFrame(), nullptr, context, LayoutRect(rect));
+ probe::didPaint(layout_view->GetFrame(), nullptr, context,
+ LayoutRect(cull_rect.Rect()));
}
const LocalFrameView& FramePainter::GetFrameView() {
diff --git a/chromium/third_party/blink/renderer/core/paint/frame_painter.h b/chromium/third_party/blink/renderer/core/paint/frame_painter.h
index cf756c96740..05c33f8fba5 100644
--- a/chromium/third_party/blink/renderer/core/paint/frame_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/frame_painter.h
@@ -13,7 +13,6 @@ namespace blink {
class CullRect;
class GraphicsContext;
-class IntRect;
class LocalFrameView;
class FramePainter {
@@ -24,7 +23,7 @@ class FramePainter {
: frame_view_(&frame_view) {}
void Paint(GraphicsContext&, const GlobalPaintFlags, const CullRect&);
- void PaintContents(GraphicsContext&, const GlobalPaintFlags, const IntRect&);
+ void PaintContents(GraphicsContext&, const GlobalPaintFlags, const CullRect&);
private:
const LocalFrameView& GetFrameView();
diff --git a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc
index a9443b1220c..83786fabdeb 100644
--- a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc
@@ -39,16 +39,18 @@ void HTMLCanvasPainter::PaintReplaced(const PaintInfo& paint_info,
HTMLCanvasElement* canvas =
ToHTMLCanvasElement(layout_html_canvas_.GetNode());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
- canvas->RenderingContext() &&
- canvas->RenderingContext()->IsComposited()) {
- if (cc::Layer* layer = canvas->RenderingContext()->CcLayer()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ if (auto* layer = canvas->ContentsCcLayer()) {
IntRect pixel_snapped_rect = PixelSnappedIntRect(paint_rect);
layer->SetOffsetToTransformParent(
gfx::Vector2dF(pixel_snapped_rect.X(), pixel_snapped_rect.Y()));
layer->SetBounds(gfx::Size(pixel_snapped_rect.Size()));
layer->SetIsDrawable(true);
RecordForeignLayer(context, DisplayItem::kForeignLayerCanvas, layer);
+ if (layout_html_canvas_.GetFrameView()) {
+ layout_html_canvas_.GetFrameView()
+ ->SetPaintArtifactCompositorNeedsUpdate();
+ }
return;
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
index 0e4681dfc81..f32026eb0f5 100644
--- a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
@@ -14,7 +14,7 @@
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
-#include "third_party/blink/renderer/core/paint/stub_chrome_client_for_spv2.h"
+#include "third_party/blink/renderer/core/paint/stub_chrome_client_for_cap.h"
#include "third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
@@ -24,14 +24,14 @@
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
-// Integration tests of canvas painting code (in SPv2 mode).
+// Integration tests of canvas painting code (in CAP mode).
namespace blink {
-class HTMLCanvasPainterTestForSPv2 : public PaintControllerPaintTest {
+class HTMLCanvasPainterTestForCAP : public PaintControllerPaintTest {
public:
- HTMLCanvasPainterTestForSPv2()
- : chrome_client_(new StubChromeClientForSPv2) {}
+ HTMLCanvasPainterTestForCAP()
+ : chrome_client_(MakeGarbageCollected<StubChromeClientForCAP>()) {}
protected:
void SetUp() override {
@@ -72,13 +72,13 @@ class HTMLCanvasPainterTestForSPv2 : public PaintControllerPaintTest {
}
private:
- Persistent<StubChromeClientForSPv2> chrome_client_;
+ Persistent<StubChromeClientForCAP> chrome_client_;
FakeGLES2Interface gl_;
};
-INSTANTIATE_SPV2_TEST_CASE_P(HTMLCanvasPainterTestForSPv2);
+INSTANTIATE_CAP_TEST_CASE_P(HTMLCanvasPainterTestForCAP);
-TEST_P(HTMLCanvasPainterTestForSPv2, Canvas2DLayerAppearsInLayerTree) {
+TEST_P(HTMLCanvasPainterTestForCAP, Canvas2DLayerAppearsInLayerTree) {
// Insert a <canvas> and force it into accelerated mode.
// Not using SetBodyInnerHTML() because we need to test before document
// lifecyle update.
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc b/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
index 346e103cf35..5d57b6d05f5 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_replaced.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -32,7 +33,7 @@ ImageElementTiming& ImageElementTiming::From(LocalDOMWindow& window) {
ImageElementTiming* timing =
Supplement<LocalDOMWindow>::From<ImageElementTiming>(window);
if (!timing) {
- timing = new ImageElementTiming(window);
+ timing = MakeGarbageCollected<ImageElementTiming>(window);
ProvideTo(window, timing);
}
return *timing;
@@ -40,7 +41,7 @@ ImageElementTiming& ImageElementTiming::From(LocalDOMWindow& window) {
ImageElementTiming::ImageElementTiming(LocalDOMWindow& window)
: Supplement<LocalDOMWindow>(window) {
- DCHECK(RuntimeEnabledFeatures::ElementTimingEnabled());
+ DCHECK(origin_trials::ElementTimingEnabled(GetSupplementable()->document()));
}
void ImageElementTiming::NotifyImagePainted(const HTMLImageElement* element,
@@ -60,10 +61,12 @@ void ImageElementTiming::NotifyImagePainted(const HTMLImageElement* element,
if (!layout_image->CachedImage())
return;
- const KURL& url = layout_image->CachedImage()->Url();
DCHECK(GetSupplementable()->document() == &layout_image->GetDocument());
- if (!SecurityOrigin::AreSameSchemeHostPort(layout_image->GetDocument().Url(),
- url))
+ DCHECK(layout_image->GetDocument().GetSecurityOrigin());
+ if (!Performance::PassesTimingAllowCheck(
+ layout_image->CachedImage()->GetResponse(),
+ *layout_image->GetDocument().GetSecurityOrigin(), AtomicString(),
+ &layout_image->GetDocument()))
return;
// Compute the viewport rect.
@@ -121,29 +124,15 @@ void ImageElementTiming::NotifyImagePainted(const HTMLImageElement* element,
void ImageElementTiming::ReportImagePaintSwapTime(WebLayerTreeView::SwapResult,
base::TimeTicks timestamp) {
- Document* document = GetSupplementable()->document();
- DCHECK(document);
- const SecurityOrigin* current_origin = document->GetSecurityOrigin();
- // It suffices to check the current origin against the parent origin since all
- // origins stored in |element_timings_| have been checked against the current
- // origin.
- while (document &&
- current_origin->IsSameSchemeHostPort(document->GetSecurityOrigin())) {
- DCHECK(document->domWindow());
- WindowPerformance* performance =
- DOMWindowPerformance::performance(*document->domWindow());
- if (performance &&
- performance->HasObserverFor(PerformanceEntry::kElement)) {
- for (const auto& element_timing : element_timings_) {
- performance->AddElementTiming(element_timing.name, element_timing.rect,
- timestamp);
- }
+ WindowPerformance* performance =
+ DOMWindowPerformance::performance(*GetSupplementable());
+ if (performance && (performance->HasObserverFor(PerformanceEntry::kElement) ||
+ performance->ShouldBufferEntries())) {
+ for (const auto& element_timing : element_timings_) {
+ performance->AddElementTiming(element_timing.name, element_timing.rect,
+ timestamp);
}
- // Provide the entry to the parent documents for as long as the origin check
- // still holds.
- document = document->ParentDocument();
}
-
element_timings_.clear();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing.h b/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
index 03ec8b1a990..5c24ca16a1b 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
@@ -28,6 +28,7 @@ class CORE_EXPORT ImageElementTiming final
public:
static const char kSupplementName[];
+ explicit ImageElementTiming(LocalDOMWindow&);
virtual ~ImageElementTiming() = default;
static ImageElementTiming& From(LocalDOMWindow&);
@@ -44,8 +45,7 @@ class CORE_EXPORT ImageElementTiming final
void Trace(blink::Visitor*) override;
private:
- explicit ImageElementTiming(LocalDOMWindow&);
-
+ FRIEND_TEST_ALL_PREFIXES(ImageElementTimingTest, ImageInsideSVG);
// Callback for the swap promise. Reports paint timestamps.
void ReportImagePaintSwapTime(WebLayerTreeView::SwapResult,
base::TimeTicks timestamp);
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc b/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
new file mode 100644
index 00000000000..69660fda0dc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/image_element_timing.h"
+
+#include "third_party/blink/renderer/core/layout/layout_image.h"
+#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+namespace blink {
+
+class ImageElementTimingTest : public RenderingTest {
+ protected:
+ // Sets an image resource for the LayoutImage with the given |id| and return
+ // the LayoutImage.
+ LayoutImage* SetImageResource(const char* id, int width, int height) {
+ ImageResourceContent* content = CreateImageForTest(width, height);
+ auto* layout_image = ToLayoutImage(GetLayoutObjectByElementId(id));
+ layout_image->ImageResource()->SetImageResource(content);
+ return layout_image;
+ }
+
+ const ImageElementTiming& GetImageElementTiming() {
+ return ImageElementTiming::From(*GetDocument().domWindow());
+ }
+
+ private:
+ ImageResourceContent* CreateImageForTest(int width, int height) {
+ sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
+ SkImageInfo raster_image_info =
+ SkImageInfo::MakeN32Premul(width, height, src_rgb_color_space);
+ sk_sp<SkSurface> surface(SkSurface::MakeRaster(raster_image_info));
+ sk_sp<SkImage> image = surface->makeImageSnapshot();
+ ImageResourceContent* original_image_resource =
+ ImageResourceContent::CreateLoaded(
+ StaticBitmapImage::Create(image).get());
+ return original_image_resource;
+ }
+};
+
+TEST_F(ImageElementTimingTest, ImageInsideSVG) {
+ GetDocument().SetBaseURLOverride(KURL("http://test.com"));
+ SetBodyInnerHTML(R"HTML(
+ <svg mask="url(#mask)">
+ <mask id="mask">
+ <foreignObject width="100" height="100">
+ <img id="target" style='width: 100px; height: 100px;'/>
+ </foreignObject>
+ </mask>
+ <rect width="100" height="100" fill="green"/>
+ </svg>
+ )HTML");
+ LayoutImage* layout_image = SetImageResource("target", 5, 5);
+ ASSERT_TRUE(layout_image);
+ // Enable compositing and also update document lifecycle.
+ EnableCompositing();
+
+ const ImageElementTiming& timing = GetImageElementTiming();
+ // |layout_image| should have had its paint notified to ImageElementTiming.
+ EXPECT_TRUE(timing.images_notified_.find(layout_image) !=
+ timing.images_notified_.end());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
index f0b454af11e..abaec5e887f 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -24,6 +24,7 @@
namespace blink {
namespace {
+#ifndef NDEBUG
String GetImageUrl(const LayoutObject& object) {
if (object.IsImage()) {
const ImageResourceContent* cached_image =
@@ -55,6 +56,7 @@ String GetImageUrl(const LayoutObject& object) {
}
return concatenated_result.ToString();
}
+#endif
bool AttachedBackgroundImagesAllLoaded(const LayoutObject& object) {
DCHECK(ImagePaintTimingDetector::HasContentfulBackgroundImage(object));
@@ -96,66 +98,67 @@ bool IsLoaded(const LayoutObject& object) {
} // namespace
// Set a big enough limit for the number of nodes to ensure memory usage is
-// capped. Exceeding such limit will deactivate the algorithm.
+// capped. Exceeding such limit will make the detactor stops recording entries.
constexpr size_t kImageNodeNumberLimit = 5000;
-static bool LargeImageOnTop(const base::WeakPtr<ImageRecord>& a,
+static bool LargeImageFirst(const base::WeakPtr<ImageRecord>& a,
const base::WeakPtr<ImageRecord>& b) {
- // null value should be at the bottom of the priority queue, so:
- // * When a == null && b!=null, we treat b as larger, return true.
- // * When a != null && b==null, we treat b as no larger than a, return false.
- // * When a == null && b==null, we treat b as no larger than a, return false.
- return (a && b) ? (a->first_size < b->first_size) : bool(b);
+ DCHECK(a);
+ DCHECK(b);
+ return a->first_size > b->first_size;
}
-static bool LateImageOnTop(const base::WeakPtr<ImageRecord>& a,
+static bool LateImageFirst(const base::WeakPtr<ImageRecord>& a,
const base::WeakPtr<ImageRecord>& b) {
- // null value should be at the bottom of the priority queue, so:
- // * When a == null && b!=null, we treat b as larger, return true.
- // * When a != null && b==null, we treat b as no larger than a, return false.
- // * When a == null && b==null, we treat b as no larger than a, return false.
- return (a && b) ? (a->first_paint_index < b->first_paint_index) : bool(b);
+ DCHECK(a);
+ DCHECK(b);
+ return a->first_paint_index > b->first_paint_index;
}
ImagePaintTimingDetector::ImagePaintTimingDetector(LocalFrameView* frame_view)
- : largest_image_heap_(&LargeImageOnTop),
- latest_image_heap_(&LateImageOnTop),
+ : size_ordered_set_(&LargeImageFirst),
+ time_ordered_set_(&LateImageFirst),
frame_view_(frame_view) {}
void ImagePaintTimingDetector::PopulateTraceValue(
TracedValue& value,
const ImageRecord& first_image_paint,
unsigned candidate_index) const {
- value.SetInteger("DOMNodeId", first_image_paint.node_id);
+ value.SetInteger("DOMNodeId", static_cast<int>(first_image_paint.node_id));
+#ifndef NDEBUG
value.SetString("imageUrl", first_image_paint.image_url);
- value.SetInteger("size", first_image_paint.first_size);
+#endif
+ value.SetInteger("size", static_cast<int>(first_image_paint.first_size));
value.SetInteger("candidateIndex", candidate_index);
value.SetString("frame",
IdentifiersFactory::FrameId(&frame_view_->GetFrame()));
}
void ImagePaintTimingDetector::OnLargestImagePaintDetected(
- const ImageRecord& largest_image_record) {
- largest_image_paint_ = largest_image_record.first_paint_time_after_loaded;
+ ImageRecord* largest_image_record) {
+ DCHECK(largest_image_record);
+ DCHECK(!largest_image_record->first_paint_time_after_loaded.is_null());
+ largest_image_paint_ = largest_image_record;
std::unique_ptr<TracedValue> value = TracedValue::Create();
- PopulateTraceValue(*value, largest_image_record,
+ PopulateTraceValue(*value, *largest_image_record,
++largest_image_candidate_index_max_);
TRACE_EVENT_INSTANT_WITH_TIMESTAMP1(
"loading", "LargestImagePaint::Candidate", TRACE_EVENT_SCOPE_THREAD,
- largest_image_record.first_paint_time_after_loaded, "data",
+ largest_image_record->first_paint_time_after_loaded, "data",
std::move(value));
- frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming();
}
void ImagePaintTimingDetector::OnLastImagePaintDetected(
- const ImageRecord& last_image_record) {
- last_image_paint_ = last_image_record.first_paint_time_after_loaded;
+ ImageRecord* last_image_record) {
+ DCHECK(last_image_record);
+ DCHECK(!last_image_record->first_paint_time_after_loaded.is_null());
+ last_image_paint_ = last_image_record;
std::unique_ptr<TracedValue> value = TracedValue::Create();
- PopulateTraceValue(*value, last_image_record,
+ PopulateTraceValue(*value, *last_image_record,
++last_image_candidate_index_max_);
TRACE_EVENT_INSTANT_WITH_TIMESTAMP1(
"loading", "LastImagePaint::Candidate", TRACE_EVENT_SCOPE_THREAD,
- last_image_record.first_paint_time_after_loaded, "data",
+ last_image_record->first_paint_time_after_loaded, "data",
std::move(value));
frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming();
}
@@ -171,17 +174,16 @@ void ImagePaintTimingDetector::Analyze() {
bool new_candidate_detected = false;
if (largest_image_record &&
!largest_image_record->first_paint_time_after_loaded.is_null() &&
- largest_image_record->first_paint_time_after_loaded !=
- largest_image_paint_) {
+ largest_image_record != largest_image_paint_) {
new_candidate_detected = true;
- OnLargestImagePaintDetected(*largest_image_record);
+ OnLargestImagePaintDetected(largest_image_record);
}
ImageRecord* last_image_record = FindLastPaintCandidate();
if (last_image_record &&
!last_image_record->first_paint_time_after_loaded.is_null() &&
- last_image_record->first_paint_time_after_loaded != last_image_paint_) {
+ last_image_record != last_image_paint_) {
new_candidate_detected = true;
- OnLastImagePaintDetected(*last_image_record);
+ OnLastImagePaintDetected(last_image_record);
}
if (new_candidate_detected) {
frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming();
@@ -195,8 +197,9 @@ void ImagePaintTimingDetector::OnPrePaintFinished() {
// If the last frame index of queue has changed, it means there are new
// records pending timing.
DOMNodeId node_id = records_pending_timing_.back();
- if (!id_record_map_.Contains(node_id))
- return;
+ // As we never remove nodes from |id_record_map_|, all of |id_record_map_|
+ // must exist.
+ DCHECK(id_record_map_.Contains(node_id));
unsigned last_frame_index = id_record_map_.at(node_id)->frame_index;
if (last_frame_index_queued_for_timing_ >= last_frame_index)
return;
@@ -208,24 +211,22 @@ void ImagePaintTimingDetector::OnPrePaintFinished() {
}
void ImagePaintTimingDetector::NotifyNodeRemoved(DOMNodeId node_id) {
+ if (!is_recording_)
+ return;
if (id_record_map_.Contains(node_id)) {
// We assume that the removed node's id wouldn't be recycled, so we don't
- // bother to remove these records from largest_image_heap_ or
- // latest_image_heap_, to reduce computation.
- id_record_map_.erase(node_id);
+ // bother to remove these records from size_ordered_set_ or
+ // time_ordered_set_, to reduce computation.
+ detached_ids_.insert(node_id);
- if (id_record_map_.size() == 0) {
- const bool largest_image_paint_invalidated =
- largest_image_paint_ != base::TimeTicks();
- const bool last_image_paint_invalidated =
- last_image_paint_ != base::TimeTicks();
- if (largest_image_paint_invalidated)
- largest_image_paint_ = base::TimeTicks();
- if (last_image_paint_invalidated)
- last_image_paint_ = base::TimeTicks();
- if (largest_image_paint_invalidated || last_image_paint_invalidated) {
- frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming();
- }
+ if (id_record_map_.size() - detached_ids_.size() == 0) {
+ // If either largest_image_paint_ or last_image_paint_ will change to
+ // nullptr, update performance timing.
+ if (!largest_image_paint_ && !last_image_paint_)
+ return;
+ largest_image_paint_ = nullptr;
+ last_image_paint_ = nullptr;
+ frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming();
}
}
}
@@ -325,6 +326,9 @@ void ImagePaintTimingDetector::RecordImage(const LayoutObject& object,
DOMNodeId node_id = DOMNodeIds::IdForNode(node);
if (size_zero_ids_.Contains(node_id))
return;
+ // The node is reattached.
+ if (id_record_map_.Contains(node_id) && detached_ids_.Contains(node_id))
+ detached_ids_.erase(node_id);
if (!id_record_map_.Contains(node_id) && is_recording_) {
LayoutRect invalidated_rect = object.FirstFragment().VisualRect();
@@ -346,14 +350,21 @@ void ImagePaintTimingDetector::RecordImage(const LayoutObject& object,
// Non-trivial image is found.
std::unique_ptr<ImageRecord> record = std::make_unique<ImageRecord>();
record->node_id = node_id;
+#ifndef NDEBUG
record->image_url = GetImageUrl(object);
+#endif
// Mind that first_size has to be assigned at the push of
- // largest_image_heap_ since it's the sorting key.
+ // size_ordered_set_ since it's the sorting key.
record->first_size = rect_size;
- largest_image_heap_.push(record->AsWeakPtr());
+ size_ordered_set_.insert(record->AsWeakPtr());
id_record_map_.insert(node_id, std::move(record));
- if (id_record_map_.size() + size_zero_ids_.size() > kImageNodeNumberLimit)
- Deactivate();
+ if (id_record_map_.size() + size_zero_ids_.size() > kImageNodeNumberLimit) {
+ TRACE_EVENT_INSTANT2("loading", "ImagePaintTimingDetector::OverNodeLimit",
+ TRACE_EVENT_SCOPE_THREAD, "recorded_node_count",
+ id_record_map_.size(), "size_zero_node_count",
+ size_zero_ids_.size());
+ StopRecordEntries();
+ }
}
if (id_record_map_.Contains(node_id) && !id_record_map_.at(node_id)->loaded &&
@@ -368,46 +379,38 @@ void ImagePaintTimingDetector::RecordImage(const LayoutObject& object,
// image is attached to DOM. This causes last image paint to base its order
// on load time other than attachment time.
// Mind that first_paint_index has to be assigned at the push of
- // latest_image_heap_ since it's the sorting key.
+ // time_ordered_set_ since it's the sorting key.
record->first_paint_index = ++first_paint_index_max_;
- latest_image_heap_.push(record->AsWeakPtr());
+ time_ordered_set_.insert(record->AsWeakPtr());
}
}
-void ImagePaintTimingDetector::Deactivate() {
- TRACE_EVENT_INSTANT2("loading", "ImagePaintTimingDetector::OverNodeLimit",
- TRACE_EVENT_SCOPE_THREAD, "recorded_node_count",
- id_record_map_.size(), "size_zero_node_count",
- size_zero_ids_.size());
+void ImagePaintTimingDetector::StopRecordEntries() {
is_recording_ = false;
}
ImageRecord* ImagePaintTimingDetector::FindLargestPaintCandidate() {
- while (!largest_image_heap_.empty() && !largest_image_heap_.top()) {
- // Discard the elements that have been removed from |id_record_map_|.
- largest_image_heap_.pop();
- }
- // We report the result as the first paint after the largest image finishes
- // loading. If the largest image is still loading, we report nothing and come
- // back later to see if the largest image by then has finished loading.
- if (!largest_image_heap_.empty() && largest_image_heap_.top()->loaded) {
- DCHECK(id_record_map_.Contains(largest_image_heap_.top()->node_id));
- return largest_image_heap_.top().get();
- }
- return nullptr;
+ return FindCandidate(size_ordered_set_);
}
ImageRecord* ImagePaintTimingDetector::FindLastPaintCandidate() {
- while (!latest_image_heap_.empty() && !latest_image_heap_.top()) {
- // Discard the elements that have been removed from |id_record_map_|.
- latest_image_heap_.pop();
- }
- // We report the result as the first paint after the latest image finishes
- // loading. If the latest image is still loading, we report nothing and come
- // back later to see if the latest image at that time has finished loading.
- if (!latest_image_heap_.empty() && latest_image_heap_.top()->loaded) {
- DCHECK(id_record_map_.Contains(latest_image_heap_.top()->node_id));
- return latest_image_heap_.top().get();
+ return FindCandidate(time_ordered_set_);
+}
+
+ImageRecord* ImagePaintTimingDetector::FindCandidate(
+ std::set<base::WeakPtr<ImageRecord>,
+ bool (*)(const base::WeakPtr<ImageRecord>&,
+ const base::WeakPtr<ImageRecord>&)>& ordered_set) {
+ for (auto it = ordered_set.begin(); it != ordered_set.end(); ++it) {
+ if (detached_ids_.Contains((*it)->node_id))
+ continue;
+ DCHECK(id_record_map_.Contains((*it)->node_id));
+ // If the largest/latest image is still loading, we report nothing and come
+ // back later to see if the largest/latest image at that time has finished
+ // loading.
+ if (!(*it)->loaded)
+ return nullptr;
+ return (*it).get();
}
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
index 9bcfd63aa45..52da64837ff 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
@@ -31,7 +31,9 @@ class ImageRecord : public base::SupportsWeakPtr<ImageRecord> {
unsigned frame_index = 0;
base::TimeTicks first_paint_time_after_loaded = base::TimeTicks();
bool loaded = false;
+#ifndef NDEBUG
String image_url = "";
+#endif
};
// ImagePaintTimingDetector contains Largest Image Paint and Last Image Paint.
@@ -67,13 +69,38 @@ class CORE_EXPORT ImagePaintTimingDetector final
static bool HasContentfulBackgroundImage(const LayoutObject& object);
void OnPrePaintFinished();
void NotifyNodeRemoved(DOMNodeId);
- base::TimeTicks LargestImagePaint() const { return largest_image_paint_; }
- base::TimeTicks LastImagePaint() const { return last_image_paint_; }
+ base::TimeTicks LargestImagePaint() const {
+ return !largest_image_paint_
+ ? base::TimeTicks()
+ : largest_image_paint_->first_paint_time_after_loaded;
+ }
+ uint64_t LargestImagePaintSize() const {
+ return !largest_image_paint_ ? 0 : largest_image_paint_->first_size;
+ }
+ base::TimeTicks LastImagePaint() const {
+ return !last_image_paint_
+ ? base::TimeTicks()
+ : last_image_paint_->first_paint_time_after_loaded;
+ }
+ uint64_t LastImagePaintSize() const {
+ return !last_image_paint_ ? 0 : last_image_paint_->first_size;
+ }
+ // After the method being called, the detector stops to record new entries and
+ // node removal. But it still observe the loading status. In other words, if
+ // an image is recorded before stopping recording, and finish loading after
+ // stopping recording, the detector can still observe the loading being
+ // finished.
+ void StopRecordEntries();
+ bool IsRecording() const { return is_recording_; }
void Trace(blink::Visitor*);
private:
ImageRecord* FindLargestPaintCandidate();
ImageRecord* FindLastPaintCandidate();
+ ImageRecord* FindCandidate(
+ std::set<base::WeakPtr<ImageRecord>,
+ bool (*)(const base::WeakPtr<ImageRecord>&,
+ const base::WeakPtr<ImageRecord>&)>& heap);
void PopulateTraceValue(TracedValue&,
const ImageRecord& first_image_paint,
unsigned report_count) const;
@@ -82,8 +109,8 @@ class CORE_EXPORT ImagePaintTimingDetector final
WebLayerTreeView::SwapResult,
base::TimeTicks);
void RegisterNotifySwapTime();
- void OnLargestImagePaintDetected(const ImageRecord&);
- void OnLastImagePaintDetected(const ImageRecord&);
+ void OnLargestImagePaintDetected(ImageRecord*);
+ void OnLastImagePaintDetected(ImageRecord*);
void Deactivate();
void Analyze();
@@ -92,17 +119,18 @@ class CORE_EXPORT ImagePaintTimingDetector final
notify_swap_time_override_for_testing_;
HashSet<DOMNodeId> size_zero_ids_;
+ // We will never destroy the pointers within |id_record_map_|. Once created
+ // they will exist for the whole life cycle of |id_record_map_|.
HashMap<DOMNodeId, std::unique_ptr<ImageRecord>> id_record_map_;
- std::priority_queue<base::WeakPtr<ImageRecord>,
- std::vector<base::WeakPtr<ImageRecord>>,
- bool (*)(const base::WeakPtr<ImageRecord>&,
- const base::WeakPtr<ImageRecord>&)>
- largest_image_heap_;
- std::priority_queue<base::WeakPtr<ImageRecord>,
- std::vector<base::WeakPtr<ImageRecord>>,
- bool (*)(const base::WeakPtr<ImageRecord>&,
- const base::WeakPtr<ImageRecord>&)>
- latest_image_heap_;
+ std::set<base::WeakPtr<ImageRecord>,
+ bool (*)(const base::WeakPtr<ImageRecord>&,
+ const base::WeakPtr<ImageRecord>&)>
+ size_ordered_set_;
+ std::set<base::WeakPtr<ImageRecord>,
+ bool (*)(const base::WeakPtr<ImageRecord>&,
+ const base::WeakPtr<ImageRecord>&)>
+ time_ordered_set_;
+ HashSet<DOMNodeId> detached_ids_;
// Node-ids of records pending swap time are stored in this queue until they
// get a swap time.
@@ -119,10 +147,12 @@ class CORE_EXPORT ImagePaintTimingDetector final
unsigned frame_index_ = 1;
unsigned last_frame_index_queued_for_timing_ = 0;
+ // Used to control if we record new image entries and image removal, but has
+ // no effect on recording the loading status.
bool is_recording_ = true;
- base::TimeTicks largest_image_paint_;
- base::TimeTicks last_image_paint_;
+ ImageRecord* largest_image_paint_ = nullptr;
+ ImageRecord* last_image_paint_ = nullptr;
Member<LocalFrameView> frame_view_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
index 95ca64c2c98..bb93f8faa6d 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -69,16 +70,22 @@ class ImagePaintTimingDetectorTest
.id_record_map_.size();
}
+ void Analyze() {
+ return GetPaintTimingDetector().GetImagePaintTimingDetector().Analyze();
+ }
+
TimeTicks LargestPaintStoredResult() {
- return GetPaintTimingDetector()
- .GetImagePaintTimingDetector()
- .largest_image_paint_;
+ ImageRecord* record = GetPaintTimingDetector()
+ .GetImagePaintTimingDetector()
+ .largest_image_paint_;
+ return !record ? base::TimeTicks() : record->first_paint_time_after_loaded;
}
TimeTicks LastPaintStoredResult() {
- return GetPaintTimingDetector()
- .GetImagePaintTimingDetector()
- .last_image_paint_;
+ ImageRecord* record = GetPaintTimingDetector()
+ .GetImagePaintTimingDetector()
+ .last_image_paint_;
+ return !record ? base::TimeTicks() : record->first_paint_time_after_loaded;
}
void UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() {
@@ -122,6 +129,8 @@ class ImagePaintTimingDetectorTest
WebString::FromUTF8(file_name));
}
+ void SimulateScroll() { GetPaintTimingDetector().NotifyScroll(kUserScroll); }
+
private:
void FakeNotifySwapTime(WebLayerTreeView::ReportTimeCallback callback) {
callback_queue_.push(std::move(callback));
@@ -179,6 +188,7 @@ TEST_F(ImagePaintTimingDetectorTest,
TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_Largest) {
SetBodyInnerHTML(R"HTML(
+ <style>img { display:block }</style>
<img id="smaller"></img>
<img id="medium"></img>
<img id="larger"></img>
@@ -194,22 +204,14 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_Largest) {
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
-#if defined(OS_MACOSX)
- EXPECT_EQ(record->first_size, 90ul);
-#else
EXPECT_EQ(record->first_size, 81ul);
-#endif
EXPECT_TRUE(record->loaded);
SetImageAndPaint("medium", 7, 7);
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
-#if defined(OS_MACOSX)
- EXPECT_EQ(record->first_size, 90ul);
-#else
EXPECT_EQ(record->first_size, 81ul);
-#endif
EXPECT_TRUE(record->loaded);
}
@@ -271,7 +273,9 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_IgnoreReAttached) {
+TEST_F(ImagePaintTimingDetectorTest,
+ LargestImagePaint_ReattachedNodeUseFirstPaint) {
+ WTF::ScopedMockClock clock;
SetBodyInnerHTML(R"HTML(
<div id="parent">
</div>
@@ -280,21 +284,28 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_IgnoreReAttached) {
image->setAttribute("id", "target");
GetDocument().getElementById("parent")->AppendChild(image);
SetImageAndPaint("target", 5, 5);
+ clock.Advance(TimeDelta::FromSecondsD(1));
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
ImageRecord* record;
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
+ EXPECT_EQ(record->first_paint_time_after_loaded,
+ base::TimeTicks() + TimeDelta::FromSecondsD(1));
GetDocument().getElementById("parent")->RemoveChild(image);
+ clock.Advance(TimeDelta::FromSecondsD(1));
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
record = FindLargestPaintCandidate();
EXPECT_FALSE(record);
GetDocument().getElementById("parent")->AppendChild(image);
SetImageAndPaint("target", 5, 5);
+ clock.Advance(TimeDelta::FromSecondsD(1));
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
+ EXPECT_EQ(record->first_paint_time_after_loaded,
+ base::TimeTicks() + TimeDelta::FromSecondsD(1));
}
// This test dipicts a situation when a smaller image has loaded, but a larger
@@ -304,6 +315,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_IgnoreReAttached) {
// This bahavior is the same with Last Image Paint as well.
TEST_F(ImagePaintTimingDetectorTest, DiscardAnalysisWhenLargestIsLoading) {
SetBodyInnerHTML(R"HTML(
+ <style>img { display:block }</style>
<div id="parent">
<img height="5" width="5" id="1"></img>
<img height="9" width="9" id="2"></img>
@@ -321,11 +333,7 @@ TEST_F(ImagePaintTimingDetectorTest, DiscardAnalysisWhenLargestIsLoading) {
InvokeCallback();
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
-#if defined(OS_MACOSX)
- EXPECT_EQ(record->first_size, 90ul);
-#else
EXPECT_EQ(record->first_size, 81ul);
-#endif
EXPECT_FALSE(record->first_paint_time_after_loaded.is_null());
}
@@ -407,6 +415,7 @@ TEST_F(ImagePaintTimingDetectorTest, LastImagePaint_OneImage) {
TEST_F(ImagePaintTimingDetectorTest, LastImagePaint_Last) {
WTF::ScopedMockClock clock;
SetBodyInnerHTML(R"HTML(
+ <style>img { display:block }</style>
<div id="parent">
<img height="10" width="10" id="1"></img>
<img height="5" width="5" id="2"></img>
@@ -433,11 +442,7 @@ TEST_F(ImagePaintTimingDetectorTest, LastImagePaint_Last) {
record = FindLastPaintCandidate();
EXPECT_TRUE(record);
-#if defined(OS_MACOSX)
- EXPECT_EQ(record->first_size, 30ul);
-#else
EXPECT_EQ(record->first_size, 25ul);
-#endif
EXPECT_EQ(record->first_paint_time_after_loaded,
base::TimeTicks() + TimeDelta::FromSecondsD(2));
@@ -520,6 +525,7 @@ TEST_F(ImagePaintTimingDetectorTest,
TEST_F(ImagePaintTimingDetectorTest, LastImagePaint_OneSwapPromiseForOneFrame) {
SetBodyInnerHTML(R"HTML(
+ <style>img { display:block }</style>
<div id="parent">
<img id="1"></img>
<img id="2"></img>
@@ -535,21 +541,13 @@ TEST_F(ImagePaintTimingDetectorTest, LastImagePaint_OneSwapPromiseForOneFrame) {
ImageRecord* record;
record = FindLastPaintCandidate();
EXPECT_TRUE(record);
-#if defined(OS_MACOSX)
- EXPECT_EQ(record->first_size, 90ul);
-#else
EXPECT_EQ(record->first_size, 81ul);
-#endif
EXPECT_TRUE(record->first_paint_time_after_loaded.is_null());
InvokeCallback();
record = FindLastPaintCandidate();
EXPECT_TRUE(record);
-#if defined(OS_MACOSX)
- EXPECT_EQ(record->first_size, 90ul);
-#else
EXPECT_EQ(record->first_size, 81ul);
-#endif
EXPECT_FALSE(record->first_paint_time_after_loaded.is_null());
}
@@ -683,4 +681,25 @@ TEST_F(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreGradient) {
EXPECT_EQ(CountRecords(), 0u);
}
+TEST_F(ImagePaintTimingDetectorTest, DeactivateAfterUserInput) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="parent">
+ <img id="target"></img>
+ </div>
+ )HTML");
+ SimulateScroll();
+ SetImageAndPaint("target", 5, 5);
+ UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
+ EXPECT_EQ(CountRecords(), 0u);
+}
+
+TEST_F(ImagePaintTimingDetectorTest, NullTimeNoCrash) {
+ SetBodyInnerHTML(R"HTML(
+ <img id="target"></img>
+ )HTML");
+ SetImageAndPaint("target", 5, 5);
+ UpdateAllLifecyclePhasesForTest();
+ Analyze();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/image_painter.cc b/chromium/third_party/blink/renderer/core/paint/image_painter.cc
index c8c341eac76..9f5ba5f4b73 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_painter.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_replaced.h"
#include "third_party/blink/renderer/core/layout/text_run_constructor.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
@@ -155,8 +156,8 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
if (pixel_snapped_dest_rect.IsEmpty())
return;
- scoped_refptr<Image> image = layout_image_.ImageResource()->GetImage(
- LayoutSize(pixel_snapped_dest_rect.Size()));
+ scoped_refptr<Image> image =
+ layout_image_.ImageResource()->GetImage(pixel_snapped_dest_rect.Size());
if (!image || image->IsNull())
return;
@@ -202,8 +203,9 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
image.get(), decode_mode, FloatRect(pixel_snapped_dest_rect), &src_rect,
SkBlendMode::kSrcOver,
LayoutObject::ShouldRespectImageOrientation(&layout_image_));
- if (RuntimeEnabledFeatures::ElementTimingEnabled() &&
- IsHTMLImageElement(node) && !context.ContextDisabled()) {
+ if (origin_trials::ElementTimingEnabled(&layout_image_.GetDocument()) &&
+ IsHTMLImageElement(node) && !context.ContextDisabled() &&
+ layout_image_.CachedImage() && layout_image_.CachedImage()->IsLoaded()) {
LocalDOMWindow* window = layout_image_.GetDocument().domWindow();
DCHECK(window);
ImageElementTiming::From(*window).NotifyImagePainted(
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc
index 58427321f36..4483ed5ec2e 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc
@@ -66,16 +66,15 @@ void InlineBoxPainterBase::PaintFillLayers(BoxPainterBase& box_painter,
const FillLayer& layer,
const LayoutRect& rect,
BackgroundImageGeometry& geometry,
- bool object_has_multiple_boxes,
- SkBlendMode op) {
+ bool object_has_multiple_boxes) {
// FIXME: This should be a for loop or similar. It's a little non-trivial to
// do so, however, since the layers need to be painted in reverse order.
if (layer.Next()) {
PaintFillLayers(box_painter, info, c, *layer.Next(), rect, geometry,
- object_has_multiple_boxes, op);
+ object_has_multiple_boxes);
}
PaintFillLayer(box_painter, info, c, layer, rect, geometry,
- object_has_multiple_boxes, op);
+ object_has_multiple_boxes);
}
void InlineBoxPainterBase::PaintFillLayer(BoxPainterBase& box_painter,
@@ -84,15 +83,14 @@ void InlineBoxPainterBase::PaintFillLayer(BoxPainterBase& box_painter,
const FillLayer& fill_layer,
const LayoutRect& paint_rect,
BackgroundImageGeometry& geometry,
- bool object_has_multiple_boxes,
- SkBlendMode op) {
+ bool object_has_multiple_boxes) {
StyleImage* img = fill_layer.GetImage();
bool has_fill_image = img && img->CanRender();
if (!object_has_multiple_boxes ||
(!has_fill_image && !style_.HasBorderRadius())) {
box_painter.PaintFillLayer(paint_info, c, fill_layer, paint_rect,
- kBackgroundBleedNone, geometry, op, false);
+ kBackgroundBleedNone, geometry, false);
return;
}
@@ -105,7 +103,7 @@ void InlineBoxPainterBase::PaintFillLayer(BoxPainterBase& box_painter,
GraphicsContextStateSaver state_saver(paint_info.context);
paint_info.context.Clip(PixelSnappedIntRect(paint_rect));
box_painter.PaintFillLayer(paint_info, c, fill_layer, rect,
- kBackgroundBleedNone, geometry, op, multi_line,
+ kBackgroundBleedNone, geometry, multi_line,
paint_rect.Size());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
index 726ce1ea37c..84520814e46 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
@@ -54,16 +54,14 @@ class InlineBoxPainterBase {
const FillLayer&,
const LayoutRect&,
BackgroundImageGeometry& geometry,
- bool object_has_multiple_boxes,
- SkBlendMode op = SkBlendMode::kSrcOver);
+ bool object_has_multiple_boxes);
void PaintFillLayer(BoxPainterBase&,
const PaintInfo&,
const Color&,
const FillLayer&,
const LayoutRect&,
BackgroundImageGeometry& geometry,
- bool object_has_multiple_boxes,
- SkBlendMode op);
+ bool object_has_multiple_boxes);
virtual void PaintNormalBoxShadow(const PaintInfo&,
const ComputedStyle&,
const LayoutRect& paint_rect) = 0;
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
index bd82f77257b..4867221b856 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/core/paint/inline_flow_box_painter.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
#include "third_party/blink/renderer/core/layout/line/inline_flow_box.h"
#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
@@ -169,8 +171,7 @@ InlineFlowBoxPainter::GetBorderPaintType(const LayoutRect& adjusted_frame_rect,
// The simple case is where we either have no border image or we are the
// only box for this object. In those cases only a single call to draw is
// required.
- if (!has_border_image || (!inline_flow_box_.PrevForSameLayoutObject() &&
- !inline_flow_box_.NextForSameLayoutObject()))
+ if (!has_border_image || !object_has_multiple_boxes)
return kPaintBordersWithoutClip;
// We have a border image that spans multiple lines.
@@ -267,8 +268,7 @@ void InlineFlowBoxPainter::PaintMask(const PaintInfo& paint_info,
// The simple case is where we are the only box for this object. In those
// cases only a single call to draw is required.
- if (!inline_flow_box_.PrevForSameLayoutObject() &&
- !inline_flow_box_.NextForSameLayoutObject()) {
+ if (!object_has_multiple_boxes) {
NinePieceImagePainter::Paint(paint_info.context, box_model,
box_model.GetDocument(), GetNode(&box_model),
paint_rect, box_model.StyleRef(),
@@ -318,6 +318,10 @@ LayoutRect InlineFlowBoxPainter::FrameRectClampedToLineTopAndBottomIfNeeded()
rect.SetX(logical_top);
rect.SetWidth(logical_height);
}
+ if (rect != inline_flow_box_.FrameRect()) {
+ UseCounter::Count(inline_flow_box_.GetLineLayoutItem().GetDocument(),
+ WebFeature::kQuirkyLineBoxBackgroundSize);
+ }
}
return rect;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index d5abae00013..f948711353b 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -185,9 +185,10 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
// capitalizing letters can change the length of the backing string.
// That needs to be taken into account when computing the size of the box
// or its painting.
- length = std::min(length, first_line_string.length() -
- std::min(inline_text_box_.Start(),
- first_line_string.length()));
+ if (inline_text_box_.Start() >= first_line_string.length())
+ return;
+ length =
+ std::min(length, first_line_string.length() - inline_text_box_.Start());
// TODO(szager): Figure out why this CHECK sometimes fails, it shouldn't.
CHECK_LE(inline_text_box_.Start() + length, first_line_string.length());
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index b09c84aa9cb..6ebd9fe82b6 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -54,9 +54,8 @@
#include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
#include "third_party/blink/renderer/platform/animation/compositor_target_property.h"
#include "third_party/blink/renderer/platform/animation/timing_function.h"
-#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
-#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h"
#include "third_party/blink/renderer/platform/web_test_support.h"
@@ -81,17 +80,12 @@ LinkHighlightImpl::LinkHighlightImpl(Node* node)
start_time_(CurrentTimeTicks()),
unique_id_(NewUniqueObjectId()) {
DCHECK(node_);
- content_layer_ = cc::PictureLayer::Create(this);
- content_layer_->SetTransformOrigin(FloatPoint3D());
+ fragments_.emplace_back(element_id());
compositor_animation_ = CompositorAnimation::Create();
DCHECK(compositor_animation_);
compositor_animation_->SetAnimationDelegate(this);
-
compositor_animation_->AttachElement(element_id());
- content_layer_->SetIsDrawable(true);
- content_layer_->SetOpacity(1);
- content_layer_->SetElementId(element_id());
geometry_needs_update_ = true;
}
@@ -111,11 +105,16 @@ void LinkHighlightImpl::ReleaseResources() {
if (auto* layout_object = node_->GetLayoutObject())
layout_object->SetNeedsPaintPropertyUpdate();
+ else
+ SetPaintArtifactCompositorNeedsUpdate();
+
node_.Clear();
}
void LinkHighlightImpl::AttachLinkHighlightToCompositingLayer(
const LayoutBoxModelObject& paint_invalidation_container) {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+
GraphicsLayer* new_graphics_layer =
paint_invalidation_container.Layer()->GraphicsLayerBacking(
node_->GetLayoutObject());
@@ -149,6 +148,8 @@ static void AddQuadToPath(const FloatQuad& quad, Path& path) {
void LinkHighlightImpl::ComputeQuads(const Node& node,
Vector<FloatQuad>& out_quads) const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+
if (!node.GetLayoutObject())
return;
@@ -172,6 +173,8 @@ void LinkHighlightImpl::ComputeQuads(const Node& node,
bool LinkHighlightImpl::ComputeHighlightLayerPathAndPosition(
const LayoutBoxModelObject& paint_invalidation_container) {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+
if (!node_ || !node_->GetLayoutObject() || !current_graphics_layer_)
return false;
@@ -185,7 +188,6 @@ bool LinkHighlightImpl::ComputeHighlightLayerPathAndPosition(
// Get quads for node in absolute coordinates.
Vector<FloatQuad> quads;
ComputeQuads(*node_, quads);
- DCHECK(quads.size());
Path new_path;
for (wtf_size_t quad_index = 0; quad_index < quads.size(); ++quad_index) {
@@ -237,37 +239,56 @@ bool LinkHighlightImpl::ComputeHighlightLayerPathAndPosition(
FloatRect bounding_rect = new_path.BoundingRect();
new_path.Translate(-ToFloatSize(bounding_rect.Location()));
- bool path_has_changed = !(new_path == path_);
+ DCHECK_EQ(1u, fragments_.size());
+ fragments_[0].SetColor(
+ node_->GetLayoutObject()->StyleRef().TapHighlightColor());
+ auto* layer = fragments_[0].Layer();
+
+ bool path_has_changed = new_path != fragments_[0].GetPath();
if (path_has_changed) {
- path_ = new_path;
- content_layer_->SetBounds(
+ fragments_[0].SetPath(new_path);
+ layer->SetBounds(
static_cast<gfx::Size>(EnclosingIntRect(bounding_rect).Size()));
}
- content_layer_->SetPosition(bounding_rect.Location());
+ layer->SetPosition(bounding_rect.Location());
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
FloatPoint offset(current_graphics_layer_->GetOffsetFromTransformNode());
offset.MoveBy(bounding_rect.Location());
- content_layer_->SetOffsetToTransformParent(
- gfx::Vector2dF(offset.X(), offset.Y()));
+ layer->SetOffsetToTransformParent(gfx::Vector2dF(offset.X(), offset.Y()));
+ SetPaintArtifactCompositorNeedsUpdate();
}
return path_has_changed;
}
-gfx::Rect LinkHighlightImpl::PaintableRegion() {
- return gfx::Rect(content_layer_->bounds());
+LinkHighlightImpl::LinkHighlightFragment::LinkHighlightFragment(
+ CompositorElementId element_id) {
+ layer_ = cc::PictureLayer::Create(this);
+ layer_->SetTransformOrigin(FloatPoint3D());
+ layer_->SetIsDrawable(true);
+ layer_->SetOpacity(1);
+
+ // The element id is required for animating layers in layer trees but not
+ // required when using layer lists.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ layer_->SetElementId(element_id);
+}
+
+LinkHighlightImpl::LinkHighlightFragment::~LinkHighlightFragment() {
+ layer_->ClearClient();
+}
+
+gfx::Rect LinkHighlightImpl::LinkHighlightFragment::PaintableRegion() {
+ return gfx::Rect(layer_->bounds());
}
scoped_refptr<cc::DisplayItemList>
-LinkHighlightImpl::PaintContentsToDisplayList(
+LinkHighlightImpl::LinkHighlightFragment::PaintContentsToDisplayList(
PaintingControlSetting painting_control) {
auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
- if (!node_ || !node_->GetLayoutObject()) {
- display_list->Finalize();
- return display_list;
- }
PaintRecorder recorder;
gfx::Rect record_bounds = PaintableRegion();
@@ -277,8 +298,7 @@ LinkHighlightImpl::PaintContentsToDisplayList(
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setAntiAlias(true);
- flags.setColor(
- node_->GetLayoutObject()->StyleRef().TapHighlightColor().Rgb());
+ flags.setColor(color_.Rgb());
canvas->drawPath(path_.GetSkPath(), flags);
display_list->StartPaint();
@@ -299,7 +319,8 @@ void LinkHighlightImpl::StartHighlightAnimationIfNeeded() {
constexpr auto kFadeDuration = TimeDelta::FromMilliseconds(100);
constexpr auto kMinPreFadeDuration = TimeDelta::FromMilliseconds(100);
- content_layer_->SetOpacity(kStartOpacity);
+ for (auto& fragment : fragments_)
+ fragment.Layer()->SetOpacity(kStartOpacity);
std::unique_ptr<CompositorFloatAnimationCurve> curve =
CompositorFloatAnimationCurve::Create();
@@ -326,7 +347,6 @@ void LinkHighlightImpl::StartHighlightAnimationIfNeeded() {
CompositorKeyframeModel::Create(
*curve, compositor_target_property::OPACITY, 0, 0);
- content_layer_->SetIsDrawable(true);
compositor_animation_->AddKeyframeModel(std::move(keyframe_model));
Invalidate();
@@ -348,12 +368,9 @@ void LinkHighlightImpl::NotifyAnimationFinished(double, int) {
ReleaseResources();
}
-class LinkHighlightDisplayItemClientForTracking : public DisplayItemClient {
- String DebugName() const final { return "LinkHighlight"; }
- LayoutRect VisualRect() const final { return LayoutRect(); }
-};
-
void LinkHighlightImpl::UpdateGeometry() {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+
if (!node_ || !node_->GetLayoutObject()) {
ClearGraphicsLayerLinkHighlightPointer();
ReleaseResources();
@@ -374,14 +391,12 @@ void LinkHighlightImpl::UpdateGeometry() {
// We only need to invalidate the layer if the highlight size has changed,
// otherwise we can just re-position the layer without needing to
// repaint.
- content_layer_->SetNeedsDisplay();
+ Layer()->SetNeedsDisplay();
if (current_graphics_layer_) {
- gfx::Rect rect = gfx::ToEnclosingRect(
- gfx::RectF(Layer()->position(), gfx::SizeF(Layer()->bounds())));
+ IntRect rect = IntRect(IntPoint(), IntSize(Layer()->bounds()));
current_graphics_layer_->TrackRasterInvalidation(
- LinkHighlightDisplayItemClientForTracking(), IntRect(rect),
- PaintInvalidationReason::kFullLayer);
+ *this, rect, PaintInvalidationReason::kFullLayer);
}
}
}
@@ -398,18 +413,20 @@ void LinkHighlightImpl::Invalidate() {
}
cc::Layer* LinkHighlightImpl::Layer() {
- return content_layer_.get();
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ DCHECK_EQ(1u, fragments_.size());
+ return fragments_[0].Layer();
}
CompositorAnimation* LinkHighlightImpl::GetCompositorAnimation() const {
return compositor_animation_.get();
}
-CompositorElementId LinkHighlightImpl::element_id() {
+CompositorElementId LinkHighlightImpl::element_id() const {
return CompositorElementIdFromUniqueObjectId(unique_id_);
}
-const EffectPaintPropertyNode* LinkHighlightImpl::effect() {
+const EffectPaintPropertyNode* LinkHighlightImpl::effect() const {
if (!node_)
return nullptr;
@@ -421,4 +438,87 @@ const EffectPaintPropertyNode* LinkHighlightImpl::effect() {
return nullptr;
}
+void LinkHighlightImpl::Paint(GraphicsContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (!node_ || !node_->GetLayoutObject()) {
+ ReleaseResources();
+ return;
+ }
+
+ const auto* object = node_->GetLayoutObject();
+ static const FloatSize rect_rounding_radii(3, 3);
+ auto color = node_->GetLayoutObject()->StyleRef().TapHighlightColor();
+
+ // For now, we'll only use rounded rects if we have a single rect because
+ // otherwise we may sometimes get a chain of adjacent boxes (e.g. for text
+ // nodes) which end up looking like sausage links: these should ideally be
+ // merged into a single rect before creating the path.
+ bool use_rounded_rects = !node_->GetDocument()
+ .GetSettings()
+ ->GetMockGestureTapHighlightsEnabled() &&
+ !object->FirstFragment().NextFragment();
+
+ size_t index = 0;
+ for (const auto* fragment = &object->FirstFragment(); fragment;
+ fragment = fragment->NextFragment(), ++index) {
+ auto rects = object->PhysicalOutlineRects(
+ fragment->PaintOffset(), NGOutlineType::kIncludeBlockVisualOverflow);
+ if (rects.size() > 1)
+ use_rounded_rects = false;
+
+ Path new_path;
+ for (auto& rect : rects) {
+ FloatRect snapped_rect(PixelSnappedIntRect(rect));
+ if (use_rounded_rects)
+ new_path.AddRoundedRect(snapped_rect, rect_rounding_radii);
+ else
+ new_path.AddRect(snapped_rect);
+ }
+
+ if (index == fragments_.size()) {
+ fragments_.emplace_back(element_id());
+ // PaintArtifactCompositor needs update for the new cc::PictureLayer we
+ // just created for the fragment.
+ SetPaintArtifactCompositorNeedsUpdate();
+ }
+
+ auto& link_highlight_fragment = fragments_[index];
+ link_highlight_fragment.SetColor(color);
+
+ auto bounding_rect = new_path.BoundingRect();
+ new_path.Translate(-ToFloatSize(bounding_rect.Location()));
+
+ auto* layer = link_highlight_fragment.Layer();
+ if (link_highlight_fragment.GetPath() != new_path) {
+ link_highlight_fragment.SetPath(new_path);
+ layer->SetBounds(gfx::Size(EnclosingIntRect(bounding_rect).Size()));
+ layer->SetNeedsDisplay();
+ }
+ // Always set offset because it is excluded from the above equality check.
+ layer->SetOffsetToTransformParent(
+ gfx::Vector2dF(bounding_rect.X(), bounding_rect.Y()));
+
+ auto property_tree_state = fragment->LocalBorderBoxProperties();
+ DCHECK(fragment->PaintProperties());
+ DCHECK(fragment->PaintProperties()->LinkHighlightEffect());
+ property_tree_state.SetEffect(
+ fragment->PaintProperties()->LinkHighlightEffect());
+ RecordForeignLayer(context, DisplayItem::kForeignLayerLinkHighlight, layer,
+ property_tree_state);
+ }
+
+ if (index < fragments_.size()) {
+ fragments_.Shrink(index);
+ // PaintArtifactCompositor needs update for the cc::PictureLayers we just
+ // removed for the extra fragments.
+ SetPaintArtifactCompositorNeedsUpdate();
+ }
+}
+
+void LinkHighlightImpl::SetPaintArtifactCompositorNeedsUpdate() {
+ DCHECK(node_);
+ if (auto* frame_view = node_->GetDocument().View())
+ frame_view->SetPaintArtifactCompositorNeedsUpdate();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
index 655d080aefc..8d0ff694063 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/platform/animation/compositor_animation.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_client.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_delegate.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
#include "third_party/blink/renderer/platform/graphics/link_highlight.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
@@ -47,12 +48,12 @@ class PictureLayer;
namespace blink {
+class GraphicsContext;
class GraphicsLayer;
class LayoutBoxModelObject;
class Node;
class CORE_EXPORT LinkHighlightImpl final : public LinkHighlight,
- public cc::ContentLayerClient,
public CompositorAnimationDelegate,
public CompositorAnimationClient {
public:
@@ -67,13 +68,6 @@ class CORE_EXPORT LinkHighlightImpl final : public LinkHighlight,
// invalidation of the owning graphics layer.
void UpdateGeometry();
- // cc::ContentLayerClient implementation.
- gfx::Rect PaintableRegion() override;
- scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
- PaintingControlSetting painting_control) override;
- bool FillsBoundsCompletely() const override { return false; }
- size_t GetApproximateUnsharedMemoryUsage() const override { return 0; }
-
// CompositorAnimationDelegate implementation.
void NotifyAnimationStarted(double monotonic_time, int group) override;
void NotifyAnimationFinished(double monotonic_time, int group) override;
@@ -93,9 +87,16 @@ class CORE_EXPORT LinkHighlightImpl final : public LinkHighlight,
Node* GetNode() const { return node_; }
- CompositorElementId element_id();
+ CompositorElementId element_id() const;
+
+ const EffectPaintPropertyNode* effect() const override;
- const EffectPaintPropertyNode* effect() override;
+ void Paint(GraphicsContext&);
+
+ wtf_size_t FragmentCountForTesting() const { return fragments_.size(); }
+ cc::PictureLayer* LayerForTesting(size_t index) const {
+ return fragments_[index].Layer();
+ }
private:
LinkHighlightImpl(Node*);
@@ -110,8 +111,31 @@ class CORE_EXPORT LinkHighlightImpl final : public LinkHighlight,
// changed size since the last call to this function.
bool ComputeHighlightLayerPathAndPosition(const LayoutBoxModelObject&);
- scoped_refptr<cc::PictureLayer> content_layer_;
- Path path_;
+ void SetPaintArtifactCompositorNeedsUpdate();
+
+ class LinkHighlightFragment : private cc::ContentLayerClient {
+ public:
+ LinkHighlightFragment(CompositorElementId);
+ ~LinkHighlightFragment() override;
+
+ cc::PictureLayer* Layer() const { return layer_.get(); }
+ const Path& GetPath() const { return path_; }
+ void SetPath(const Path& path) { path_ = path; }
+ void SetColor(const Color& color) { color_ = color; }
+
+ private:
+ // cc::ContentLayerClient implementation.
+ gfx::Rect PaintableRegion() override;
+ scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
+ PaintingControlSetting painting_control) override;
+ bool FillsBoundsCompletely() const override { return false; }
+ size_t GetApproximateUnsharedMemoryUsage() const override { return 0; }
+
+ scoped_refptr<cc::PictureLayer> layer_;
+ Path path_;
+ Color color_;
+ };
+ Vector<LinkHighlightFragment> fragments_;
Persistent<Node> node_;
GraphicsLayer* current_graphics_layer_;
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
index 313cc562e8f..d3da48068f3 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -27,6 +27,7 @@
#include <memory>
+#include "cc/layers/picture_layer.h"
#include "cc/trees/layer_tree_host.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
@@ -45,23 +46,21 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
namespace blink {
class LinkHighlightImplTest : public testing::Test,
- public testing::WithParamInterface<bool>,
- private ScopedBlinkGenPropertyTreesForTest {
- public:
- LinkHighlightImplTest() : ScopedBlinkGenPropertyTreesForTest(GetParam()) {}
-
+ public PaintTestConfigurations {
protected:
GestureEventWithHitTestResults GetTargetedEvent(
WebGestureEvent& touch_event) {
@@ -116,13 +115,13 @@ class LinkHighlightImplTest : public testing::Test,
frame_test_helpers::WebViewHelper web_view_helper_;
};
-INSTANTIATE_TEST_CASE_P(All, LinkHighlightImplTest, testing::Bool());
+INSTANTIATE_PAINT_TEST_CASE_P(LinkHighlightImplTest);
TEST_P(LinkHighlightImplTest, verifyWebViewImplIntegration) {
WebViewImpl* web_view_impl = web_view_helper_.GetWebView();
int page_width = 640;
int page_height = 480;
- web_view_impl->Resize(WebSize(page_width, page_height));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
UpdateAllLifecyclePhases();
WebGestureEvent touch_event(WebInputEvent::kGestureShowPress,
@@ -146,7 +145,8 @@ TEST_P(LinkHighlightImplTest, verifyWebViewImplIntegration) {
const auto& highlights =
web_view_impl->GetPage()->GetLinkHighlights().link_highlights_;
EXPECT_TRUE(highlights.at(0));
- EXPECT_TRUE(highlights.at(0)->Layer());
+ EXPECT_EQ(1u, highlights.at(0)->FragmentCountForTesting());
+ EXPECT_TRUE(highlights.at(0)->LayerForTesting(0));
// Find a target inside a scrollable div
touch_event.SetPositionInWidget(WebFloatPoint(20, 100));
@@ -175,7 +175,7 @@ TEST_P(LinkHighlightImplTest, resetDuringNodeRemoval) {
int page_width = 640;
int page_height = 480;
- web_view_impl->Resize(WebSize(page_width, page_height));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
UpdateAllLifecyclePhases();
WebGestureEvent touch_event(WebInputEvent::kGestureShowPress,
@@ -190,16 +190,30 @@ TEST_P(LinkHighlightImplTest, resetDuringNodeRemoval) {
web_view_impl->EnableTapHighlightAtPoint(targeted_event);
const auto& highlights = web_view_impl->GetPage()->GetLinkHighlights();
+ ASSERT_EQ(1u, highlights.link_highlights_.size());
ASSERT_TRUE(highlights.link_highlights_.at(0));
-
- GraphicsLayer* highlight_layer =
- highlights.link_highlights_.at(0)->CurrentGraphicsLayerForTesting();
- ASSERT_TRUE(highlight_layer);
- EXPECT_TRUE(highlight_layer->GetLinkHighlights().at(0));
+ EXPECT_EQ(touch_node, highlights.link_highlights_.at(0)->GetNode());
+
+ GraphicsLayer* highlight_layer;
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ highlight_layer =
+ highlights.link_highlights_.at(0)->CurrentGraphicsLayerForTesting();
+ ASSERT_TRUE(highlight_layer);
+ EXPECT_TRUE(highlight_layer->GetLinkHighlights().at(0));
+ }
touch_node->remove(IGNORE_EXCEPTION_FOR_TESTING);
UpdateAllLifecyclePhases();
- EXPECT_EQ(0U, highlight_layer->GetLinkHighlights().size());
+
+ ASSERT_EQ(1u, highlights.link_highlights_.size());
+ ASSERT_TRUE(highlights.link_highlights_.at(0));
+ EXPECT_FALSE(highlights.link_highlights_.at(0)->GetNode());
+
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(0U, highlight_layer->GetLinkHighlights().size());
+ EXPECT_FALSE(
+ highlights.link_highlights_.at(0)->CurrentGraphicsLayerForTesting());
+ }
}
// A lifetime test: delete LayerTreeView while running LinkHighlights.
@@ -208,7 +222,7 @@ TEST_P(LinkHighlightImplTest, resetLayerTreeView) {
int page_width = 640;
int page_height = 480;
- web_view_impl->Resize(WebSize(page_width, page_height));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
UpdateAllLifecyclePhases();
WebGestureEvent touch_event(WebInputEvent::kGestureShowPress,
@@ -226,21 +240,62 @@ TEST_P(LinkHighlightImplTest, resetLayerTreeView) {
web_view_impl->GetPage()->GetLinkHighlights().link_highlights_;
ASSERT_TRUE(highlights.at(0));
- GraphicsLayer* highlight_layer =
- highlights.at(0)->CurrentGraphicsLayerForTesting();
- ASSERT_TRUE(highlight_layer);
- EXPECT_TRUE(highlight_layer->GetLinkHighlights().at(0));
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ GraphicsLayer* highlight_layer =
+ highlights.at(0)->CurrentGraphicsLayerForTesting();
+ ASSERT_TRUE(highlight_layer);
+ EXPECT_TRUE(highlight_layer->GetLinkHighlights().at(0));
+ }
+}
+
+TEST_P(LinkHighlightImplTest, HighlightInvalidation) {
+ // This test requires GraphicsLayers which are not used in
+ // CompositeAfterPaint.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ WebViewImpl* web_view_impl = web_view_helper_.GetWebView();
+ web_view_impl->MainFrameWidget()->Resize(WebSize(640, 480));
+ UpdateAllLifecyclePhases();
+
+ WebGestureEvent touch_event(WebInputEvent::kGestureShowPress,
+ WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ kWebGestureDeviceTouchscreen);
+ touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
+ GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
+ auto* touch_element = ToElement(web_view_impl->BestTapNode(targeted_event));
+ web_view_impl->EnableTapHighlightAtPoint(targeted_event);
+
+ web_view_helper_.LocalMainFrame()
+ ->GetFrameView()
+ ->SetTracksPaintInvalidations(true);
+
+ // Change the touched element's height to 12px.
+ auto& style = touch_element->getAttribute(html_names::kStyleAttr);
+ String new_style = style.GetString();
+ new_style.append("height: 12px;");
+ touch_element->setAttribute(html_names::kStyleAttr, AtomicString(new_style));
+ UpdateAllLifecyclePhases();
+
+ const auto& highlights =
+ web_view_impl->GetPage()->GetLinkHighlights().link_highlights_;
+ auto* highlight_layer = highlights.at(0)->CurrentGraphicsLayerForTesting();
+ const auto* tracking = highlight_layer->GetRasterInvalidationTracking();
+ // The invalidation rect should fully cover the layer.
+ EXPECT_EQ(tracking->Invalidations().back().rect, IntRect(0, 0, 200, 12));
}
TEST_P(LinkHighlightImplTest, HighlightLayerEffectNode) {
// This is testing the blink->cc layer integration.
- if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
int page_width = 640;
int page_height = 480;
WebViewImpl* web_view_impl = web_view_helper_.GetWebView();
- web_view_impl->Resize(WebSize(page_width, page_height));
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
paint_artifact_compositor()->EnableExtraDataForTesting();
UpdateAllLifecyclePhases();
@@ -265,15 +320,19 @@ TEST_P(LinkHighlightImplTest, HighlightLayerEffectNode) {
ASSERT_TRUE(highlight);
// Check that the link highlight cc layer has a cc effect property tree node.
- auto* layer = highlight->Layer();
+ EXPECT_EQ(1u, highlight->FragmentCountForTesting());
+ auto* layer = highlight->LayerForTesting(0);
+ // We don't set layer's element id.
+ EXPECT_EQ(cc::ElementId(), layer->element_id());
auto effect_tree_index = layer->effect_tree_index();
auto* property_trees = layer->layer_tree_host()->property_trees();
EXPECT_EQ(
effect_tree_index,
- property_trees->element_id_to_effect_node_index[layer->element_id()]);
+ property_trees->element_id_to_effect_node_index[highlight->element_id()]);
// The link highlight cc effect node should correspond to the blink effect
// node.
- EXPECT_EQ(highlight->effect()->GetCompositorElementId(), layer->element_id());
+ EXPECT_EQ(highlight->effect()->GetCompositorElementId(),
+ highlight->element_id());
EXPECT_TRUE(highlight->effect()->RequiresCompositingForAnimation());
touch_node->remove(IGNORE_EXCEPTION_FOR_TESTING);
@@ -282,4 +341,83 @@ TEST_P(LinkHighlightImplTest, HighlightLayerEffectNode) {
EXPECT_EQ(layer_count_before_highlight, ContentLayerCount());
}
+TEST_P(LinkHighlightImplTest, MultiColumn) {
+ // This is testing the blink->cc layer integration.
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ int page_width = 640;
+ int page_height = 480;
+ WebViewImpl* web_view_impl = web_view_helper_.GetWebView();
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
+ UpdateAllLifecyclePhases();
+
+ paint_artifact_compositor()->EnableExtraDataForTesting();
+ UpdateAllLifecyclePhases();
+ size_t layer_count_before_highlight = ContentLayerCount();
+
+ WebGestureEvent touch_event(WebInputEvent::kGestureShowPress,
+ WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ kWebGestureDeviceTouchscreen);
+ // This will touch the link under multicol.
+ touch_event.SetPositionInWidget(WebFloatPoint(20, 300));
+
+ GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
+ Node* touch_node = web_view_impl->BestTapNode(targeted_event);
+ ASSERT_TRUE(touch_node);
+
+ web_view_impl->EnableTapHighlightAtPoint(targeted_event);
+
+ const auto& highlights =
+ web_view_impl->GetPage()->GetLinkHighlights().link_highlights_;
+ EXPECT_EQ(1u, highlights.size());
+ const auto* highlight = highlights.at(0).get();
+ ASSERT_TRUE(highlight);
+
+ // The link highlight cc effect node should correspond to the blink effect
+ // node.
+ const auto* effect = highlight->effect();
+ ASSERT_TRUE(effect);
+ EXPECT_EQ(effect->GetCompositorElementId(), highlight->element_id());
+ EXPECT_TRUE(effect->RequiresCompositingForAnimation());
+
+ const auto& first_fragment = touch_node->GetLayoutObject()->FirstFragment();
+ EXPECT_EQ(effect, first_fragment.PaintProperties()->LinkHighlightEffect());
+ const auto* second_fragment = first_fragment.NextFragment();
+ ASSERT_TRUE(second_fragment);
+ EXPECT_EQ(effect, second_fragment->PaintProperties()->LinkHighlightEffect());
+ EXPECT_FALSE(second_fragment->NextFragment());
+
+ auto check_layer = [&](const cc::PictureLayer* layer) {
+ ASSERT_TRUE(layer);
+ // We don't set layer's element id.
+ EXPECT_EQ(cc::ElementId(), layer->element_id());
+ auto effect_tree_index = layer->effect_tree_index();
+ auto* property_trees = layer->layer_tree_host()->property_trees();
+ EXPECT_EQ(effect_tree_index,
+ property_trees
+ ->element_id_to_effect_node_index[highlight->element_id()]);
+ };
+
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // The highlight should create 2 additional layer, each for each fragment.
+ EXPECT_EQ(layer_count_before_highlight + 2, ContentLayerCount());
+ EXPECT_EQ(2u, highlight->FragmentCountForTesting());
+ check_layer(highlight->LayerForTesting(0));
+ check_layer(highlight->LayerForTesting(1));
+ } else {
+ // The highlight should create 1 additional layer covering both fragments.
+ EXPECT_EQ(layer_count_before_highlight + 1, ContentLayerCount());
+ EXPECT_EQ(1u, highlight->FragmentCountForTesting());
+ check_layer(highlight->LayerForTesting(0));
+ }
+
+ touch_node->remove(IGNORE_EXCEPTION_FOR_TESTING);
+ UpdateAllLifecyclePhases();
+ // Removing the highlight layer should drop the cc layers for highlights.
+ EXPECT_EQ(layer_count_before_highlight, ContentLayerCount());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 226cd35199c..18b2bb8f3f7 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -148,14 +148,18 @@ NGBoxFragmentPainter::NGBoxFragmentPainter(const NGPaintFragment& box)
}
void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) {
+ if (PhysicalFragment().IsAtomicInline())
+ PaintAtomicInline(paint_info);
+ else
+ PaintInternal(paint_info);
+}
+
+void NGBoxFragmentPainter::PaintInternal(const PaintInfo& paint_info) {
ScopedPaintState paint_state(box_fragment_, paint_info);
if (!ShouldPaint(paint_state))
return;
PaintInfo& info = paint_state.MutablePaintInfo();
- if (PhysicalFragment().IsAtomicInline())
- return PaintAtomicInline(info);
-
LayoutPoint paint_offset = paint_state.PaintOffset();
PaintPhase original_phase = info.phase;
@@ -197,20 +201,7 @@ void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) {
void NGBoxFragmentPainter::RecordHitTestData(const PaintInfo& paint_info,
const LayoutPoint& paint_offset) {
- // Hit test display items are only needed for compositing. This flag is used
- // for for printing and drag images which do not need hit testing.
- if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
- return;
-
- // If an object is not visible, it does not participate in hit testing.
- if (box_fragment_.Style().Visibility() != EVisibility::kVisible)
- return;
-
const NGPhysicalFragment& physical_fragment = PhysicalFragment();
- auto touch_action = physical_fragment.EffectiveWhitelistedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
- return;
-
// TODO(pdr): If we are painting the background into the scrolling contents
// layer, we need to use the overflow rect instead of the border box rect. We
// may want to move the call to RecordHitTestRect into
@@ -222,7 +213,20 @@ void NGBoxFragmentPainter::RecordHitTestData(const PaintInfo& paint_info,
border_box.offset += NGPhysicalOffset(paint_offset);
HitTestDisplayItem::Record(
paint_info.context, box_fragment_,
- HitTestRect(border_box.ToLayoutRect(), touch_action));
+ HitTestRect(border_box.ToLayoutRect(),
+ physical_fragment.EffectiveWhitelistedTouchAction()));
+}
+
+void NGBoxFragmentPainter::RecordHitTestDataForLine(
+ const PaintInfo& paint_info,
+ const LayoutPoint& paint_offset,
+ const NGPaintFragment& line) {
+ NGPhysicalOffsetRect border_box = line.PhysicalFragment().LocalRect();
+ border_box.offset += NGPhysicalOffset(paint_offset);
+ HitTestDisplayItem::Record(
+ paint_info.context, line,
+ HitTestRect(border_box.ToLayoutRect(),
+ PhysicalFragment().EffectiveWhitelistedTouchAction()));
}
void NGBoxFragmentPainter::PaintObject(
@@ -241,13 +245,14 @@ void NGBoxFragmentPainter::PaintObject(
if (!suppress_box_decoration_background && is_visible)
PaintBoxDecorationBackground(paint_info, paint_offset);
- if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled())
+ if (NGFragmentPainter::ShouldRecordHitTestData(paint_info,
+ PhysicalFragment()))
RecordHitTestData(paint_info, paint_offset);
// Record the scroll hit test after the background so background squashing
// is not affected. Hit test order would be equivalent if this were
// immediately before the background.
- // if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
// PaintScrollHitTestDisplayItem(paint_info);
// We're done. We don't bother painting any children.
@@ -265,15 +270,15 @@ void NGBoxFragmentPainter::PaintObject(
if (paint_phase != PaintPhase::kSelfOutlineOnly) {
if (PhysicalFragment().ChildrenInline()) {
- if (PhysicalFragment().IsBlockFlow()) {
+ if (PhysicalFragment().IsBlockFlow())
PaintBlockFlowContents(paint_info, paint_offset);
- if (paint_phase == PaintPhase::kFloat ||
- paint_phase == PaintPhase::kSelection ||
- paint_phase == PaintPhase::kTextClip)
- PaintFloats(paint_info);
- } else {
+ else
PaintInlineChildren(box_fragment_.Children(), paint_info, paint_offset);
- }
+
+ if (paint_phase == PaintPhase::kFloat ||
+ paint_phase == PaintPhase::kSelection ||
+ paint_phase == PaintPhase::kTextClip)
+ PaintFloats(paint_info);
} else {
PaintBlockChildren(paint_info);
}
@@ -487,6 +492,13 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackground(
bool NGBoxFragmentPainter::BackgroundIsKnownToBeOpaque(
const PaintInfo& paint_info) {
const LayoutBox& layout_box = ToLayoutBox(*box_fragment_.GetLayoutObject());
+
+ // If the box has multiple fragments, its VisualRect is the bounding box of
+ // all fragments' visual rects, which is likely to cover areas that are not
+ // covered by painted background.
+ if (layout_box.FirstFragment().NextFragment())
+ return false;
+
LayoutRect bounds = IsPaintingScrollingBackground(box_fragment_, paint_info)
? layout_box.LayoutOverflowRect()
: layout_box.SelfVisualOverflowRect();
@@ -533,15 +545,18 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
BoxDecorationData box_decoration_data(PhysicalFragment());
GraphicsContextStateSaver state_saver(paint_info.context, false);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
LayoutRect(EnclosingIntRect(paint_rect)) == paint_rect &&
BackgroundIsKnownToBeOpaque(paint_info))
recorder.SetKnownToBeOpaque();
bool needs_end_layer = false;
if (!painting_overflow_contents) {
+ bool skip_background = layout_box.BackgroundTransfersToView() ||
+ (paint_info.SkipRootBackground() &&
+ paint_info.PaintContainer() == layout_box);
PaintNormalBoxShadow(paint_info, paint_rect, style, border_edges_.line_left,
- border_edges_.line_right);
+ border_edges_.line_right, skip_background);
if (box_fragment_.HasSelfPaintingLayer() && layout_box.IsTableCell() &&
ToLayoutTableCell(layout_box).Table()->ShouldCollapseBorders()) {
@@ -653,53 +668,39 @@ void NGBoxFragmentPainter::PaintInlineChildBoxUsingLegacyFallback(
}
void NGBoxFragmentPainter::PaintAllPhasesAtomically(
- const PaintInfo& paint_info,
- bool is_self_painting) {
- ScopedPaintState paint_state(box_fragment_, paint_info);
- auto paint_offset = paint_state.PaintOffset();
- PaintInfo& local_paint_info = paint_state.MutablePaintInfo();
-
+ const PaintInfo& paint_info) {
// Pass PaintPhaseSelection and PaintPhaseTextClip is handled by the regular
// foreground paint implementation. We don't need complete painting for these
// phases.
PaintPhase phase = paint_info.phase;
if (phase == PaintPhase::kSelection || phase == PaintPhase::kTextClip)
- return PaintObject(local_paint_info, paint_offset);
+ return PaintInternal(paint_info);
- if (paint_info.phase == PaintPhase::kSelfBlockBackgroundOnly &&
- is_self_painting) {
- PaintObject(local_paint_info, paint_offset);
- PaintOverflowControlsIfNeeded(local_paint_info, paint_offset);
- return;
- }
+ // Self-painting AtomicInlines must paint their background in background
+ // phase.
+ bool is_self_painting_atomic_inline =
+ PhysicalFragment().IsAtomicInline() && PhysicalFragment().Layer() &&
+ PhysicalFragment().Layer()->IsSelfPaintingLayer();
+ if (phase == PaintPhase::kSelfBlockBackgroundOnly &&
+ is_self_painting_atomic_inline)
+ return PaintInternal(paint_info);
if (phase != PaintPhase::kForeground)
return;
- if (!is_self_painting) {
+ PaintInfo local_paint_info(paint_info);
+ if (!is_self_painting_atomic_inline) {
local_paint_info.phase = PaintPhase::kBlockBackground;
- PaintObject(local_paint_info, paint_offset);
+ PaintInternal(local_paint_info);
}
local_paint_info.phase = PaintPhase::kFloat;
- PaintObject(local_paint_info, paint_offset);
+ PaintInternal(local_paint_info);
local_paint_info.phase = PaintPhase::kForeground;
- if (box_fragment_.GetLayoutObject()->IsBox()) {
- ScopedBoxContentsPaintState contents_paint_state(
- paint_state, ToLayoutBox(*box_fragment_.GetLayoutObject()));
- PaintObject(contents_paint_state.GetPaintInfo(),
- contents_paint_state.PaintOffset());
- } else {
- PaintObject(local_paint_info, paint_offset);
- }
+ PaintInternal(local_paint_info);
local_paint_info.phase = PaintPhase::kOutline;
- PaintObject(local_paint_info, paint_offset);
-
- if (!is_self_painting) {
- local_paint_info.phase = PaintPhase::kBlockBackground;
- PaintOverflowControlsIfNeeded(local_paint_info, paint_offset);
- }
+ PaintInternal(local_paint_info);
}
void NGBoxFragmentPainter::PaintLineBoxChildren(
@@ -740,6 +741,12 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
}
DCHECK(line->PhysicalFragment().IsLineBox())
<< line->PhysicalFragment().ToString();
+
+ if (paint_info.phase == PaintPhase::kForeground &&
+ NGFragmentPainter::ShouldRecordHitTestData(paint_info,
+ PhysicalFragment()))
+ RecordHitTestDataForLine(paint_info, child_offset, *line);
+
PaintInlineChildren(line->Children(), paint_info, child_offset);
}
}
@@ -778,7 +785,7 @@ void NGBoxFragmentPainter::PaintAtomicInlineChild(const NGPaintFragment& child,
FragmentRequiresLegacyFallback(fragment)) {
PaintInlineChildBoxUsingLegacyFallback(fragment, paint_info);
} else {
- NGBoxFragmentPainter(child).PaintAllPhasesAtomically(paint_info, false);
+ NGBoxFragmentPainter(child).PaintAllPhasesAtomically(paint_info);
}
}
@@ -795,6 +802,17 @@ void NGBoxFragmentPainter::PaintTextChild(const NGPaintFragment& text_fragment,
paint_info.phase != PaintPhase::kMask)
return;
+ // Note: To paint selection for <br>, we don't check intersection with
+ // fragment paint rect and cull rect since computing selection rect is
+ // expensive.
+ if (!text_fragment.Size().IsEmpty()) {
+ LayoutRect physical_visual_overflow = text_fragment.SelfInkOverflow();
+ physical_visual_overflow.MoveBy(text_fragment.Offset().ToLayoutPoint());
+ physical_visual_overflow.MoveBy(paint_offset);
+ if (!paint_info.GetCullRect().Intersects(physical_visual_overflow))
+ return;
+ }
+
// The text clip phase already has a DrawingRecorder. Text clips are initiated
// only in BoxPainterBase::PaintFillLayer, which is already within a
// DrawingRecorder.
@@ -834,20 +852,13 @@ void NGBoxFragmentPainter::PaintSymbol(const NGPaintFragment& fragment,
rect);
}
-// Follows BlockPainter::PaintInlineBox
void NGBoxFragmentPainter::PaintAtomicInline(const PaintInfo& paint_info) {
- if (paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelection &&
- paint_info.phase != PaintPhase::kSelfBlockBackgroundOnly)
- return;
-
// Text clips are painted only for the direct inline children of the object
// that has a text clip style on it, not block children.
- DCHECK(paint_info.phase != PaintPhase::kTextClip);
+ if (paint_info.phase == PaintPhase::kTextClip)
+ return;
- bool is_self_painting = PhysicalFragment().Layer() &&
- PhysicalFragment().Layer()->IsSelfPaintingLayer();
- PaintAllPhasesAtomically(paint_info, is_self_painting);
+ PaintAllPhasesAtomically(paint_info);
}
bool NGBoxFragmentPainter::IsPaintingScrollingBackground(
@@ -977,8 +988,9 @@ bool NGBoxFragmentPainter::NodeAtPoint(
// HitTestOverflowControl(result, location_in_container, physical_offset))
// return true;
- bool skip_children = false;
- if (box_fragment_.ShouldClipOverflow()) {
+ bool skip_children = result.GetHitTestRequest().GetStopNode() ==
+ PhysicalFragment().GetLayoutObject();
+ if (!skip_children && box_fragment_.ShouldClipOverflow()) {
// PaintLayer::HitTestContentsForFragments checked the fragments'
// foreground rect for intersection if a layer is self painting,
// so only do the overflow clip check here for non-self-painting layers.
@@ -1012,6 +1024,11 @@ bool NGBoxFragmentPainter::NodeAtPoint(
// Now hit test ourselves.
if (hit_test_self && VisibleToHitTestRequest(result.GetHitTestRequest())) {
LayoutRect bounds_rect(physical_offset, size);
+ if (UNLIKELY(result.GetHitTestRequest().GetType() &
+ HitTestRequest::kHitTestVisualOverflow)) {
+ bounds_rect = PhysicalFragment().SelfInkOverflow().ToLayoutRect();
+ bounds_rect.MoveBy(physical_offset);
+ }
if (location_in_container.Intersects(bounds_rect)) {
Node* node = box_fragment_.NodeForHitTest();
if (!result.InnerNode() && node) {
@@ -1060,6 +1077,12 @@ bool NGBoxFragmentPainter::HitTestTextFragment(
// TODO(layout-dev): Clip to line-top/bottom.
LayoutRect rect = LayoutRect(PixelSnappedIntRect(border_rect));
+ if (UNLIKELY(result.GetHitTestRequest().GetType() &
+ HitTestRequest::kHitTestVisualOverflow)) {
+ rect = text_paint_fragment.SelfInkOverflow();
+ rect.MoveBy(border_rect.Location());
+ }
+
if (FragmentVisibleToHitTestRequest(text_paint_fragment,
result.GetHitTestRequest()) &&
location_in_container.Intersects(rect)) {
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 440d6ad9892..41a6a376eb9 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -73,8 +73,8 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const LayoutRect&);
bool BackgroundIsKnownToBeOpaque(const PaintInfo&);
- void PaintAllPhasesAtomically(const PaintInfo&,
- bool is_self_painting);
+ void PaintInternal(const PaintInfo&);
+ void PaintAllPhasesAtomically(const PaintInfo&);
void PaintBlockChildren(const PaintInfo&);
void PaintLineBoxChildren(NGPaintFragment::ChildList,
const PaintInfo&,
@@ -114,6 +114,10 @@ class NGBoxFragmentPainter : public BoxPainterBase {
void RecordHitTestData(const PaintInfo& paint_info,
const LayoutPoint& paint_offset);
+ void RecordHitTestDataForLine(const PaintInfo& paint_info,
+ const LayoutPoint& paint_offset,
+ const NGPaintFragment& line);
+
bool IsInSelfHitTestingPhase(HitTestAction) const;
bool VisibleToHitTestRequest(const HitTestRequest&) const;
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
index 80875643be1..068751b0fb8 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -77,4 +78,26 @@ void NGFragmentPainter::AddPDFURLRectIfNeeded(const PaintInfo& paint_info,
paint_info.context.SetURLForRect(url, rect);
}
+bool NGFragmentPainter::ShouldRecordHitTestData(
+ const PaintInfo& paint_info,
+ const NGPhysicalFragment& fragment) {
+ if (!RuntimeEnabledFeatures::PaintTouchActionRectsEnabled())
+ return false;
+
+ // Hit test display items are only needed for compositing. This flag is used
+ // for for printing and drag images which do not need hit testing.
+ if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
+ return false;
+
+ // If an object is not visible, it does not participate in hit testing.
+ if (fragment.Style().Visibility() != EVisibility::kVisible)
+ return false;
+
+ auto touch_action = fragment.EffectiveWhitelistedTouchAction();
+ if (touch_action == TouchAction::kTouchActionAuto)
+ return false;
+
+ return true;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
index 7ab368df028..de46ce700c5 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
@@ -12,6 +12,7 @@ namespace blink {
class LayoutPoint;
class NGPaintFragment;
+class NGPhysicalFragment;
struct PaintInfo;
// Generic fragment painter for paint logic shared between all types of
@@ -27,6 +28,9 @@ class NGFragmentPainter : public ObjectPainterBase {
void AddPDFURLRectIfNeeded(const PaintInfo&, const LayoutPoint& paint_offset);
+ static bool ShouldRecordHitTestData(const PaintInfo&,
+ const NGPhysicalFragment&);
+
private:
const NGPaintFragment& paint_fragment_;
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
index c884762044b..1db51376153 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
@@ -82,7 +82,9 @@ void NGInlineBoxFragmentPainter::PaintBackgroundBorderShadow(
inline_box_fragment_.InlineFragmentsFor(
inline_box_fragment_.GetLayoutObject());
NGPaintFragment::FragmentRange::iterator iter = fragments.begin();
- bool object_has_multiple_boxes = ++iter != fragments.end();
+ DCHECK(iter != fragments.end());
+ bool object_has_multiple_boxes =
+ iter != fragments.end() && ++iter != fragments.end();
// TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry.
BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>(
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
index 881e314410e..1b4a60ea873 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
@@ -8,9 +8,7 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
#include "third_party/blink/renderer/core/paint/inline_box_painter_base.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
-
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/skia/include/core/SkBlendMode.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 81a6fad320b..deb9dc75930 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -14,12 +14,14 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_rect.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_type.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
@@ -286,15 +288,21 @@ scoped_refptr<NGPaintFragment> NGPaintFragment::CreateOrReuse(
scoped_refptr<NGPaintFragment> NGPaintFragment::Create(
scoped_refptr<const NGPhysicalFragment> fragment,
NGPhysicalOffset offset,
+ const NGBlockBreakToken* block_break_token,
scoped_refptr<NGPaintFragment> previous_instance) {
DCHECK(fragment);
bool populate_children = fragment->IsContainer();
+ bool has_previous_instance = previous_instance.get();
scoped_refptr<NGPaintFragment> paint_fragment =
CreateOrReuse(std::move(fragment), offset, nullptr,
std::move(previous_instance), &populate_children);
if (populate_children) {
+ if (has_previous_instance) {
+ NGInlineNode::ClearAssociatedFragments(paint_fragment->PhysicalFragment(),
+ block_break_token);
+ }
HashMap<const LayoutObject*, NGPaintFragment*> last_fragment_map;
paint_fragment->PopulateDescendants(NGPhysicalOffset(), &last_fragment_map);
}
@@ -359,7 +367,7 @@ NGPaintFragment* NGPaintFragment::Last() {
scoped_refptr<NGPaintFragment>* NGPaintFragment::Find(
scoped_refptr<NGPaintFragment>* fragment,
- const NGBreakToken* break_token) {
+ const NGBlockBreakToken* break_token) {
DCHECK(fragment);
if (!break_token)
@@ -459,8 +467,7 @@ void NGPaintFragment::PopulateDescendants(
std::move(previous_child), &populate_children);
if (children_are_inline) {
- if (!child_fragment->IsFloating() &&
- !child_fragment->IsOutOfFlowPositioned() &&
+ if (!child_fragment->IsOutOfFlowPositioned() &&
!child_fragment->IsListMarker()) {
if (LayoutObject* layout_object = child_fragment->GetLayoutObject())
child->AssociateWithLayoutObject(layout_object, last_fragment_map);
@@ -487,17 +494,23 @@ void NGPaintFragment::AssociateWithLayoutObject(
HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) {
DCHECK(layout_object);
DCHECK(!next_for_same_layout_object_);
- DCHECK(layout_object->IsInline());
+ DCHECK(layout_object->IsInline() || layout_object->IsFloating());
auto add_result = last_fragment_map->insert(layout_object, this);
if (add_result.is_new_entry) {
- DCHECK(!layout_object->FirstInlineFragment());
- layout_object->SetFirstInlineFragment(this);
- } else {
- DCHECK(add_result.stored_value->value);
- add_result.stored_value->value->next_for_same_layout_object_ = this;
- add_result.stored_value->value = this;
+ NGPaintFragment* first_fragment = layout_object->FirstInlineFragment();
+ if (!first_fragment) {
+ layout_object->SetFirstInlineFragment(this);
+ return;
+ }
+ // This |layout_object| was fragmented across multiple blocks.
+ NGPaintFragment* last_fragment = first_fragment->LastForSameLayoutObject();
+ last_fragment->next_for_same_layout_object_ = this;
+ return;
}
+ DCHECK(add_result.stored_value->value);
+ add_result.stored_value->value->next_for_same_layout_object_ = this;
+ add_result.stored_value->value = this;
}
NGPaintFragment* NGPaintFragment::GetForInlineContainer(
@@ -539,11 +552,6 @@ NGPaintFragment* NGPaintFragment::LastForSameLayoutObject() {
return fragment;
}
-void NGPaintFragment::DirtyLinesFromChangedChild(LayoutObject* child) {
- if (child->IsInline())
- MarkLineBoxesDirtyFor(*child);
-}
-
bool NGPaintFragment::FlippedLocalVisualRectFor(
const LayoutObject* layout_object,
LayoutRect* visual_rect) {
@@ -629,8 +637,22 @@ NGPaintFragment* NGPaintFragment::FirstLineBox() const {
return nullptr;
}
+void NGPaintFragment::DirtyLinesFromChangedChild(LayoutObject* child) {
+ // This function should be called on every child that has
+ // |IsInLayoutNGInlineFormattingContext()|, meaning it was once collected into
+ // |NGInlineNode|.
+ //
+ // New LayoutObjects will be handled in the next |CollectInline()|.
+ DCHECK(child && child->IsInLayoutNGInlineFormattingContext());
+
+ if (child->IsInline() || child->IsFloatingOrOutOfFlowPositioned())
+ MarkLineBoxesDirtyFor(*child);
+}
+
void NGPaintFragment::MarkLineBoxesDirtyFor(const LayoutObject& layout_object) {
- DCHECK(layout_object.IsInline()) << layout_object;
+ DCHECK(layout_object.IsInline() ||
+ layout_object.IsFloatingOrOutOfFlowPositioned())
+ << layout_object;
// Since |layout_object| isn't in fragment tree, check preceding siblings.
// Note: Once we reuse lines below dirty lines, we should check next siblings.
@@ -774,6 +796,8 @@ PositionWithAffinity NGPaintFragment::PositionForPointInText(
const unsigned text_offset = text_fragment.TextOffsetForPoint(point);
const NGCaretPosition unadjusted_position{
this, NGCaretPositionType::kAtTextOffset, text_offset};
+ if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
+ return unadjusted_position.ToPositionInDOMTreeWithAffinity();
if (text_offset > text_fragment.StartOffset() &&
text_offset < text_fragment.EndOffset()) {
return unadjusted_position.ToPositionInDOMTreeWithAffinity();
@@ -804,6 +828,9 @@ PositionWithAffinity NGPaintFragment::PositionForPointInInlineLevelBox(
LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
for (const NGPaintFragment* child : Children()) {
+ if (child->PhysicalFragment().IsFloating())
+ continue;
+
const LayoutUnit child_inline_min =
ChildLogicalOffsetInParent(*child).inline_offset;
const LayoutUnit child_inline_max =
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index 7d331af509f..ce17ea10560 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -16,6 +16,7 @@
namespace blink {
class LayoutInline;
+class NGBlockBreakToken;
struct LayoutSelectionStatus;
struct PaintInfo;
enum class NGOutlineType;
@@ -47,6 +48,7 @@ class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>,
static scoped_refptr<NGPaintFragment> Create(
scoped_refptr<const NGPhysicalFragment>,
NGPhysicalOffset offset,
+ const NGBlockBreakToken* break_token,
scoped_refptr<NGPaintFragment> previous_instance = nullptr);
const NGPhysicalFragment& PhysicalFragment() const {
@@ -63,7 +65,7 @@ class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>,
NGPaintFragment* Last();
NGPaintFragment* Last(const NGBreakToken&);
static scoped_refptr<NGPaintFragment>* Find(scoped_refptr<NGPaintFragment>*,
- const NGBreakToken*);
+ const NGBlockBreakToken*);
template <typename Traverse>
class List {
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
index c1a1fe50234..2ff8b5d4067 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
@@ -482,9 +482,10 @@ TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveChild) {
Element& target = *GetDocument().getElementById("target");
target.remove();
const NGPaintFragment& container = *GetPaintFragmentByElementId("container");
- EXPECT_TRUE(container.FirstChild()->IsDirty());
- EXPECT_TRUE(ToList(container.Children())[1]->IsDirty());
- EXPECT_FALSE(ToList(container.Children())[2]->IsDirty());
+ auto lines = ToList(container.Children());
+ EXPECT_TRUE(lines[0]->IsDirty());
+ EXPECT_FALSE(lines[1]->IsDirty());
+ EXPECT_FALSE(lines[2]->IsDirty());
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveSpanWithBr) {
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
index 377e5466038..4923bc03057 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
@@ -155,6 +155,7 @@ class CORE_EXPORT NGPaintFragmentTraversal {
static Vector<NGPaintFragmentWithContainerOffset> InlineDescendantsOf(
const NGPaintFragment&);
+ // Deprecated. Use NGPaintFragment::InlineFragmentsFor() instead.
static Vector<NGPaintFragmentWithContainerOffset> SelfFragmentsOf(
const NGPaintFragment&,
const LayoutObject* target);
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
index 8bbcb7b0c2b..460f49e71d5 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
@@ -47,8 +47,7 @@ TEST_P(NGTextFragmentPainterTest, TestTextStyle) {
InvalidateAll(RootPaintController());
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- IntRect interest_rect(0, 0, 640, 480);
- Paint(&interest_rect);
+ Paint(IntRect(0, 0, 640, 480));
const NGPaintFragment& root_fragment = *block_flow.PaintFragment();
EXPECT_EQ(1u, root_fragment.Children().size());
diff --git a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
index 806caccaa65..e5cff41e26b 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
@@ -138,7 +138,7 @@ void ObjectPaintInvalidator::
void ObjectPaintInvalidator::
InvalidatePaintIncludingNonCompositingDescendants() {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
SlowSetPaintingLayerNeedsRepaint();
// This method may be used to invalidate paint of objects changing paint
// invalidation container. Visual rects don't have to be cleared, since they
@@ -178,7 +178,7 @@ bool IsClientNGPaintFragmentForObject(const DisplayItemClient& client,
if (!RuntimeEnabledFeatures::LayoutNGEnabled())
return false;
// TODO(crbug.com/880519): This hack only makes current invalidation tracking
- // layout tests pass with LayoutNG. More work is needed if we want to launch
+ // web tests pass with LayoutNG. More work is needed if we want to launch
// the invalidation tracking feature.
return object.IsLayoutBlockFlow() &&
&client == ToLayoutBlockFlow(object).PaintFragment();
diff --git a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
index f538faee254..8c639ac8c9b 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
@@ -22,7 +22,7 @@ using ::testing::ElementsAre;
TEST_F(ObjectPaintInvalidatorTest,
TraverseNonCompositingDescendantsInPaintOrder) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
EnableCompositing();
@@ -73,7 +73,7 @@ TEST_F(ObjectPaintInvalidatorTest,
}
TEST_F(ObjectPaintInvalidatorTest, TraverseFloatUnderCompositedInline) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
EnableCompositing();
@@ -156,7 +156,7 @@ TEST_F(ObjectPaintInvalidatorTest, TraverseFloatUnderCompositedInline) {
TEST_F(ObjectPaintInvalidatorTest,
TraverseFloatUnderMultiLevelCompositedInlines) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
EnableCompositing();
@@ -220,7 +220,7 @@ TEST_F(ObjectPaintInvalidatorTest,
}
TEST_F(ObjectPaintInvalidatorTest, TraverseStackedFloatUnderCompositedInline) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
EnableCompositing();
diff --git a/chromium/third_party/blink/renderer/core/paint/object_paint_properties.h b/chromium/third_party/blink/renderer/core/paint/object_paint_properties.h
index 4c2f4b3ead3..a0562f50394 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_paint_properties.h
+++ b/chromium/third_party/blink/renderer/core/paint/object_paint_properties.h
@@ -173,6 +173,13 @@ class CORE_EXPORT ObjectPaintProperties {
ADD_EFFECT(LinkHighlightEffect, link_highlight_effect_);
ADD_EFFECT(EffectIsolationNode, effect_isolation_node_);
+ // For a fragmented link highlight, we only need one LinkHighlightEffect node.
+ // PaintPropertyTreeBuilder uses this method to let the subsequent fragments
+ // share the same LinkHighlightEffect node created for the first fragment.
+ void SetLinkHighlightEffect(const EffectPaintPropertyNode* effect) {
+ link_highlight_effect_ = const_cast<EffectPaintPropertyNode*>(effect);
+ }
+
// The hierarchy of the clip subtree created by a LayoutObject is as follows:
// [ fragment clip ]
// | Clips to a fragment's bounds.
diff --git a/chromium/third_party/blink/renderer/core/paint/object_painter.cc b/chromium/third_party/blink/renderer/core/paint/object_painter.cc
index 9445e34562c..112deedc4ef 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_painter.cc
@@ -35,9 +35,8 @@ void ObjectPainter::PaintOutline(const PaintInfo& paint_info,
return;
}
- Vector<LayoutRect> outline_rects;
- layout_object_.AddOutlineRects(
- outline_rects, paint_offset,
+ auto outline_rects = layout_object_.PhysicalOutlineRects(
+ paint_offset,
layout_object_.OutlineRectsShouldIncludeBlockVisualOverflow());
if (outline_rects.IsEmpty())
return;
@@ -46,18 +45,6 @@ void ObjectPainter::PaintOutline(const PaintInfo& paint_info,
paint_info.context, layout_object_, paint_info.phase))
return;
- // The result rects are in coordinates of m_layoutObject's border box.
- // Block flipping is not applied yet if !m_layoutObject.isBox().
- if (!layout_object_.IsBox() &&
- layout_object_.StyleRef().IsFlippedBlocksWritingMode()) {
- LayoutBlock* container = layout_object_.ContainingBlock();
- if (container) {
- layout_object_.LocalToAncestorRects(outline_rects, container,
- -paint_offset, paint_offset);
- if (outline_rects.IsEmpty())
- return;
- }
- }
DrawingRecorder recorder(paint_info.context, layout_object_,
paint_info.phase);
PaintOutlineRects(paint_info, outline_rects, style_to_use);
@@ -87,10 +74,9 @@ void ObjectPainter::AddPDFURLRectIfNeeded(const PaintInfo& paint_info,
if (!url.IsValid())
return;
- Vector<LayoutRect> visual_overflow_rects;
- layout_object_.AddElementVisualOverflowRects(visual_overflow_rects,
- paint_offset);
- IntRect rect = PixelSnappedIntRect(UnionRect(visual_overflow_rects));
+ auto outline_rects = layout_object_.PhysicalOutlineRects(
+ paint_offset, NGOutlineType::kIncludeBlockVisualOverflow);
+ IntRect rect = PixelSnappedIntRect(UnionRect(outline_rects));
if (rect.IsEmpty())
return;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index 96048abd457..53f6c8f6556 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -67,7 +67,7 @@ TEST_P(PaintAndRasterInvalidationTest, TrackingForTracing) {
auto* target = GetDocument().getElementById("target");
auto get_debug_info = [&]() -> std::string {
auto* cc_layer =
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
? GetDocument()
.View()
->GetPaintArtifactCompositorForTesting()
@@ -320,7 +320,7 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedLayoutViewResize) {
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
GetLayoutView().GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto* mapping = GetLayoutView().Layer()->GetCompositedLayerMapping();
EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
@@ -355,7 +355,7 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedLayoutViewGradientResize) {
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
GetLayoutView().GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto* mapping = GetLayoutView().Layer()->GetCompositedLayerMapping();
EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
@@ -419,9 +419,9 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewResize) {
GetDocument().View()->SetTracksPaintInvalidations(true);
iframe->setAttribute(html_names::kStyleAttr, "height: 200px");
UpdateAllLifecyclePhasesForTest();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// TODO(wangxianzhu): This is probably incorrect, but for now we assume
- // any scrolling contents as composited during SPv2 painting. Perhaps we
+ // any scrolling contents as composited during CAP painting. Perhaps we
// need some heuristic about composited scrolling during painting.
EXPECT_FALSE(GetRasterInvalidationTracking()->HasInvalidations());
} else {
@@ -467,9 +467,9 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewGradientResize) {
GetDocument().View()->SetTracksPaintInvalidations(true);
content->setAttribute(html_names::kStyleAttr, "height: 500px");
UpdateAllLifecyclePhasesForTest();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// TODO(wangxianzhu): This is probably incorrect, but for now we assume
- // any scrolling contents as composited during SPv2 painting. Perhaps we
+ // any scrolling contents as composited during CAP painting. Perhaps we
// need some heuristic about composited scrolling during painting.
EXPECT_FALSE(GetRasterInvalidationTracking()->HasInvalidations());
} else {
@@ -485,9 +485,9 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewGradientResize) {
GetDocument().View()->SetTracksPaintInvalidations(true);
iframe->setAttribute(html_names::kStyleAttr, "height: 200px");
UpdateAllLifecyclePhasesForTest();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// TODO(wangxianzhu): This is probably incorrect, but for now we assume
- // any scrolling contents as composited during SPv2 painting. Perhaps we
+ // any scrolling contents as composited during CAP painting. Perhaps we
// need some heuristic about composited scrolling during painting.
EXPECT_FALSE(GetRasterInvalidationTracking()->HasInvalidations());
} else {
@@ -517,7 +517,7 @@ TEST_P(PaintAndRasterInvalidationTest,
auto* target_obj = ToLayoutBoxModelObject(target->GetLayoutObject());
EXPECT_EQ(kBackgroundPaintInScrollingContents,
target_obj->GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto* mapping = target_obj->Layer()->GetCompositedLayerMapping();
EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
@@ -525,7 +525,7 @@ TEST_P(PaintAndRasterInvalidationTest,
auto container_raster_invalidation_tracking =
[&]() -> const RasterInvalidationTracking* {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return GetRasterInvalidationTracking(1);
return target_obj->Layer()
->GraphicsLayerBacking(target_obj)
@@ -533,7 +533,7 @@ TEST_P(PaintAndRasterInvalidationTest,
};
auto contents_raster_invalidation_tracking =
[&]() -> const RasterInvalidationTracking* {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return GetRasterInvalidationTracking(2);
return target_obj->Layer()
->GraphicsLayerBacking()
@@ -585,7 +585,7 @@ TEST_P(PaintAndRasterInvalidationTest,
ToLayoutBoxModelObject(target->GetLayoutObject());
auto container_raster_invalidation_tracking =
[&]() -> const RasterInvalidationTracking* {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return GetRasterInvalidationTracking(1);
return target_obj->Layer()
->GraphicsLayerBacking(target_obj)
@@ -593,7 +593,7 @@ TEST_P(PaintAndRasterInvalidationTest,
};
auto contents_raster_invalidation_tracking =
[&]() -> const RasterInvalidationTracking* {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return GetRasterInvalidationTracking(2);
return target_obj->Layer()
->GraphicsLayerBacking()
@@ -606,7 +606,7 @@ TEST_P(PaintAndRasterInvalidationTest,
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
target_obj->GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto* mapping = target_obj->Layer()->GetCompositedLayerMapping();
EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
@@ -664,9 +664,9 @@ TEST_P(PaintAndRasterInvalidationTest,
GetDocument().View()->SetTracksPaintInvalidations(true);
target->setAttribute(html_names::kStyleAttr, "height: 200px");
UpdateAllLifecyclePhasesForTest();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// TODO(wangxianzhu): This is probably incorrect, but for now we assume
- // any scrolling contents as composited during SPv2 painting. Perhaps we
+ // any scrolling contents as composited during CAP painting. Perhaps we
// need some heuristic about composited scrolling during painting.
EXPECT_FALSE(GetRasterInvalidationTracking()->HasInvalidations());
} else {
@@ -701,14 +701,14 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedSolidBackgroundResize) {
EXPECT_EQ(
kBackgroundPaintInScrollingContents | kBackgroundPaintInGraphicsLayer,
target_object->GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto* mapping = target_object->Layer()->GetCompositedLayerMapping();
EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
EXPECT_TRUE(mapping->BackgroundPaintsOntoGraphicsLayer());
}
const auto* contents_raster_invalidation_tracking =
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
? GetRasterInvalidationTracking(2)
: target_object->Layer()
->GraphicsLayerBacking()
@@ -720,7 +720,7 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedSolidBackgroundResize) {
&client, client.DebugName(), IntRect(50, 0, 50, 500),
PaintInvalidationReason::kIncremental}));
const auto* container_raster_invalidation_tracking =
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
? GetRasterInvalidationTracking(1)
: target_object->Layer()
->GraphicsLayerBacking(target_object)
@@ -877,8 +877,8 @@ TEST_P(PaintAndRasterInvalidationTest, SVGHiddenContainer) {
EXPECT_EQ(LayoutRect(55, 66, 7, 8), real_rect->FirstFragment().VisualRect());
// Should invalidate raster for real_rect only.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // SPv2 creates composited layers for the rect and its mask.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // CAP creates composited layers for the rect and its mask.
EXPECT_THAT(GetRasterInvalidationTracking(1)->Invalidations(),
UnorderedElementsAre(RasterInvalidationInfo{
real_rect, real_rect->DebugName(), IntRect(0, 0, 7, 8),
@@ -1055,7 +1055,7 @@ class PaintInvalidatorCustomClientTest : public RenderingTest {
public:
PaintInvalidatorCustomClientTest()
: RenderingTest(EmptyLocalFrameClient::Create()),
- chrome_client_(new PaintInvalidatorTestClient) {}
+ chrome_client_(MakeGarbageCollected<PaintInvalidatorTestClient>()) {}
PaintInvalidatorTestClient& GetChromeClient() const override {
return *chrome_client_;
@@ -1075,9 +1075,7 @@ TEST_F(PaintInvalidatorCustomClientTest,
NonCompositedInvalidationChangeOpacity) {
// This test runs in a non-composited mode, so invalidations should
// be issued via InvalidateChromeClient.
- SetBodyInnerHTML(R"HTML(
- <div id=target style="opacity: 0.99"></div>
- )HTML");
+ SetBodyInnerHTML("<div id=target style='opacity: 0.99'></div>");
auto* target = GetDocument().getElementById("target");
ASSERT_TRUE(target);
@@ -1090,4 +1088,26 @@ TEST_F(PaintInvalidatorCustomClientTest,
EXPECT_TRUE(InvalidationRecorded());
}
+TEST_F(PaintInvalidatorCustomClientTest,
+ NoInvalidationRepeatedUpdateLifecyleExceptPaint) {
+ SetBodyInnerHTML("<div id=target style='opacity: 0.99'></div>");
+
+ auto* target = GetDocument().getElementById("target");
+ ASSERT_TRUE(target);
+ ResetInvalidationRecorded();
+
+ target->setAttribute(html_names::kStyleAttr, "opacity: 0.98");
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ EXPECT_TRUE(GetDocument().View()->GetLayoutView()->Layer()->NeedsRepaint());
+ EXPECT_TRUE(InvalidationRecorded());
+
+ ResetInvalidationRecorded();
+ // Let PrePaintTreeWalk do something instead of no-op.
+ GetDocument().View()->SetNeedsPaintPropertyUpdate();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ // The layer NeedsRepaint flag is only cleared after paint.
+ EXPECT_TRUE(GetDocument().View()->GetLayoutView()->Layer()->NeedsRepaint());
+ EXPECT_FALSE(InvalidationRecorded());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h
index fd4ee35e43e..4ce2ac4488e 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h
@@ -19,7 +19,7 @@ class PaintAndRasterInvalidationTest : public PaintControllerPaintTest {
protected:
ContentLayerClientImpl* GetContentLayerClient(size_t index = 0) const {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
const auto& clients = GetDocument()
.View()
->GetPaintArtifactCompositorForTesting()
@@ -29,7 +29,7 @@ class PaintAndRasterInvalidationTest : public PaintControllerPaintTest {
const RasterInvalidationTracking* GetRasterInvalidationTracking(
size_t index = 0) const {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (auto* client = GetContentLayerClient(index))
return client->GetRasterInvalidator().GetTracking();
return nullptr;
@@ -43,7 +43,7 @@ class PaintAndRasterInvalidationTest : public PaintControllerPaintTest {
void SetUp() override {
PaintControllerPaintTest::SetUp();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
layer_tree_ = std::make_unique<LayerTreeHostEmbedder>();
layer_tree_->layer_tree_host()->SetRootLayer(
GetDocument()
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
index 40084431197..e0152cd3379 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
@@ -22,8 +22,8 @@ namespace blink {
INSTANTIATE_PAINT_TEST_CASE_P(PaintControllerPaintTest);
-using PaintControllerPaintTestForSPv2 = PaintControllerPaintTest;
-INSTANTIATE_SPV2_TEST_CASE_P(PaintControllerPaintTestForSPv2);
+using PaintControllerPaintTestForCAP = PaintControllerPaintTest;
+INSTANTIATE_CAP_TEST_CASE_P(PaintControllerPaintTestForCAP);
TEST_P(PaintControllerPaintTest, FullDocumentPaintingWithCaret) {
SetBodyInnerHTML(
@@ -134,7 +134,7 @@ TEST_P(PaintControllerPaintTest, CompositingNoFold) {
IsSameId(&sub_div, kBackgroundType)));
}
-TEST_P(PaintControllerPaintTestForSPv2, FrameScrollingContents) {
+TEST_P(PaintControllerPaintTestForCAP, FrameScrollingContents) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none }
@@ -173,7 +173,7 @@ TEST_P(PaintControllerPaintTestForSPv2, FrameScrollingContents) {
IsSameId(&div4, kBackgroundType)));
}
-TEST_P(PaintControllerPaintTestForSPv2, BlockScrollingNonLayeredContents) {
+TEST_P(PaintControllerPaintTestForCAP, BlockScrollingNonLayeredContents) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none }
@@ -218,7 +218,7 @@ TEST_P(PaintControllerPaintTestForSPv2, BlockScrollingNonLayeredContents) {
IsSameId(&div4, kBackgroundType)));
}
-TEST_P(PaintControllerPaintTestForSPv2, ScrollHitTestOrder) {
+TEST_P(PaintControllerPaintTestForCAP, ScrollHitTestOrder) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none }
@@ -253,7 +253,7 @@ TEST_P(PaintControllerPaintTestForSPv2, ScrollHitTestOrder) {
IsSameId(&child, kBackgroundType)));
}
-TEST_P(PaintControllerPaintTestForSPv2, NonStackingScrollHitTestOrder) {
+TEST_P(PaintControllerPaintTestForCAP, NonStackingScrollHitTestOrder) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none }
@@ -299,7 +299,7 @@ TEST_P(PaintControllerPaintTestForSPv2, NonStackingScrollHitTestOrder) {
IsSameId(&pos_z_child, kBackgroundType)));
}
-TEST_P(PaintControllerPaintTestForSPv2, StackingScrollHitTestOrder) {
+TEST_P(PaintControllerPaintTestForCAP, StackingScrollHitTestOrder) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none }
@@ -343,7 +343,7 @@ TEST_P(PaintControllerPaintTestForSPv2, StackingScrollHitTestOrder) {
IsSameId(&pos_z_child, kBackgroundType)));
}
-TEST_P(PaintControllerPaintTestForSPv2,
+TEST_P(PaintControllerPaintTestForCAP,
NonStackingScrollHitTestOrderWithoutBackground) {
SetBodyInnerHTML(R"HTML(
<style>
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
index 10a82a00786..1a42a09c836 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
@@ -27,7 +27,7 @@ class PaintControllerPaintTestBase : public RenderingTest {
protected:
LayoutView& GetLayoutView() const { return *GetDocument().GetLayoutView(); }
PaintController& RootPaintController() const {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return *GetDocument().View()->GetPaintController();
return GetLayoutView()
.Layer()
@@ -40,9 +40,10 @@ class PaintControllerPaintTestBase : public RenderingTest {
EnableCompositing();
}
- bool PaintWithoutCommit(const IntRect* interest_rect = nullptr) {
+ bool PaintWithoutCommit(
+ const base::Optional<IntRect>& interest_rect = base::nullopt) {
GetDocument().View()->Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (GetLayoutView().Layer()->NeedsRepaint()) {
GraphicsContext graphics_context(RootPaintController());
GetDocument().View()->Paint(
@@ -55,8 +56,10 @@ class PaintControllerPaintTestBase : public RenderingTest {
return false;
}
// Only root graphics layer is supported.
- if (!GetLayoutView().Layer()->GraphicsLayerBacking()->PaintWithoutCommit(
- interest_rect)) {
+ if (!GetLayoutView()
+ .Layer()
+ ->GraphicsLayerBacking()
+ ->PaintWithoutCommitForTesting(interest_rect)) {
GetDocument().View()->Lifecycle().AdvanceTo(
DocumentLifecycle::kPaintClean);
return false;
@@ -77,7 +80,7 @@ class PaintControllerPaintTestBase : public RenderingTest {
GetDocument().View()->Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
}
- void Paint(const IntRect* interest_rect = nullptr) {
+ void Paint(const base::Optional<IntRect>& interest_rect = base::nullopt) {
// Only root graphics layer is supported.
if (PaintWithoutCommit(interest_rect))
CommitAndFinishCycle();
@@ -106,7 +109,7 @@ class PaintControllerPaintTestBase : public RenderingTest {
void InvalidateAll(PaintController& paint_controller) {
paint_controller.InvalidateAllForTesting();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
DCHECK_EQ(&paint_controller, GetDocument().View()->GetPaintController());
GetLayoutView().Layer()->SetNeedsRepaint();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_event.h b/chromium/third_party/blink/renderer/core/paint/paint_event.h
index 69ba47b6238..02962212e7f 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_event.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_event.h
@@ -13,7 +13,6 @@ enum class PaintEvent {
kFirstPaint,
kFirstContentfulPaint,
kProvisionalFirstMeaningfulPaint,
- kFirstTextPaint,
kFirstImagePaint,
};
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_info.h b/chromium/third_party/blink/renderer/core/paint/paint_info.h
index fa4838be50b..6ad51c8e7f5 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_info.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_info.h
@@ -113,12 +113,12 @@ struct CORE_EXPORT PaintInfo {
return paint_flags_ & kPaintLayerPaintingRenderingResourceSubtree;
}
- // TODO(wangxianzhu): Rename this function to SkipBackground() for SPv2.
+ // TODO(wangxianzhu): Rename this function to SkipBackground() for CAP.
bool SkipRootBackground() const {
return paint_flags_ & kPaintLayerPaintingSkipRootBackground;
}
void SetSkipsBackground(bool b) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
if (b)
paint_flags_ |= kPaintLayerPaintingSkipRootBackground;
else
@@ -170,11 +170,11 @@ struct CORE_EXPORT PaintInfo {
}
bool IsPaintingScrollingBackground() const {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
return is_painting_scrolling_background_;
}
void SetIsPaintingScrollingBackground(bool b) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
is_painting_scrolling_background_ = b;
}
@@ -197,7 +197,7 @@ struct CORE_EXPORT PaintInfo {
const GlobalPaintFlags global_paint_flags_;
const bool suppress_painting_descendants_;
- // For SPv2 only.
+ // For CAP only.
bool is_painting_scrolling_background_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 83e098a5dc3..745a165a94b 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -14,8 +14,8 @@
#include "third_party/blink/renderer/core/layout/layout_table_section.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
+#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
-#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
#include "third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -35,8 +35,8 @@ void PaintInvalidator::ExcludeCompositedLayerSubpixelAccumulation(
const LayoutObject& object,
const PaintInvalidatorContext& context,
Rect& rect) {
- // TODO(wangxianzhu): How to handle sub-pixel location animation for SPv2?
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // TODO(wangxianzhu): How to handle sub-pixel location animation for CAP?
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
// One of the following conditions happened in crbug.com/837226.
@@ -96,7 +96,7 @@ LayoutRect PaintInvalidator::MapLocalRectToVisualRect(
ToLayoutBox(object).FlipForWritingMode(rect);
} else if (!(context.subtree_flags &
PaintInvalidatorContext::kSubtreeSlowPathRect)) {
- // For SPv2 and the GeometryMapper path, we also need to convert the
+ // For CAP and the GeometryMapper path, we also need to convert the
// rect for non-boxes into physical coordinates before applying paint
// offset. (Otherwise we'll call mapToVisualrectInAncestorSpace() which
// requires physical coordinates for boxes, but "physical coordinates
@@ -162,8 +162,7 @@ LayoutRect PaintInvalidator::ComputeVisualRect(
static LayoutRect ComputeFragmentLocalSelectionRect(
const NGPaintFragment& fragment) {
- if (!fragment.PhysicalFragment().IsText())
- return LayoutRect();
+ DCHECK(fragment.PhysicalFragment().IsText());
const FrameSelection& frame_selection =
fragment.GetLayoutObject()->GetFrame()->Selection();
const LayoutSelectionStatus status =
@@ -193,12 +192,20 @@ void PaintInvalidator::UpdatePaintingLayer(const LayoutObject& object,
context.painting_layer = ToLayoutBoxModelObject(object).Layer();
} else if (object.IsColumnSpanAll() ||
object.IsFloatingWithNonContainingBlockParent()) {
- // See LayoutObject::paintingLayer() for the special-cases of floating under
+ // See |LayoutObject::PaintingLayer| for the special-cases of floating under
// inline and multicolumn.
+ // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
+ // check can be removed as floats will be painted by the correct layer.
context.painting_layer = object.PaintingLayer();
}
- if (object.IsLayoutBlockFlow() && ToLayoutBlockFlow(object).ContainsFloats())
+ if (object.IsLayoutBlockFlow() && !object.IsLayoutNGBlockFlow() &&
+ ToLayoutBlockFlow(object).ContainsFloats())
+ context.painting_layer->SetNeedsPaintPhaseFloat();
+
+ if (object.IsFloating() &&
+ (object.IsInLayoutNGInlineFormattingContext() ||
+ IsLayoutNGContainingBlock(object.ContainingBlock())))
context.painting_layer->SetNeedsPaintPhaseFloat();
// Table collapsed borders are painted in PaintPhaseDescendantBlockBackgrounds
@@ -240,17 +247,20 @@ void PaintInvalidator::UpdatePaintInvalidationContainer(
context.paint_invalidation_container_for_stacked_contents =
ToLayoutBoxModelObject(&object);
} else if (object.IsLayoutView()) {
- // paintInvalidationContainerForStackedContents is only for stacked
+ // paint_invalidation_container_for_stacked_contents is only for stacked
// descendants in its own frame, because it doesn't establish stacking
// context for stacked contents in sub-frames.
// Contents stacked in the root stacking context in this frame should use
- // this frame's paintInvalidationContainer.
+ // this frame's PaintInvalidationContainer.
context.paint_invalidation_container_for_stacked_contents =
- context.paint_invalidation_container;
- } else if (object.IsFloatingWithNonContainingBlockParent() ||
- object.IsColumnSpanAll()) {
+ context.paint_invalidation_container =
+ &object.ContainerForPaintInvalidation();
+ } else if (object.IsColumnSpanAll() ||
+ object.IsFloatingWithNonContainingBlockParent()) {
// In these cases, the object may belong to an ancestor of the current
// paint invalidation container, in paint order.
+ // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
+ // check can be removed as floats will be painted by the correct layer.
context.paint_invalidation_container =
&object.ContainerForPaintInvalidation();
} else if (object.StyleRef().IsStacked() &&
@@ -331,70 +341,52 @@ void PaintInvalidator::UpdateVisualRect(const LayoutObject& object,
// VisualRect for each fragment from |new_visual_rect|.
auto fragments = NGPaintFragment::InlineFragmentsFor(&object);
if (fragments.IsInLayoutNGInlineFormattingContext()) {
- for (NGPaintFragment* fragment : fragments) {
- LayoutRect local_selection_rect =
- ComputeFragmentLocalSelectionRect(*fragment);
- LayoutRect local_visual_rect =
- UnionRect(fragment->SelfInkOverflow(), local_selection_rect);
- fragment->SetVisualRect(MapFragmentLocalRectToVisualRect(
- local_visual_rect, object, *fragment, context));
-
- LayoutRect selection_visual_rect = MapFragmentLocalRectToVisualRect(
- local_selection_rect, object, *fragment, context);
- const bool should_invalidate =
- object.ShouldInvalidateSelection() ||
- selection_visual_rect != fragment->SelectionVisualRect();
- const bool rect_exists = !selection_visual_rect.IsEmpty() ||
- !fragment->SelectionVisualRect().IsEmpty();
- if (should_invalidate && rect_exists) {
- context.painting_layer->SetNeedsRepaint();
- ObjectPaintInvalidator(object).InvalidateDisplayItemClient(
- *fragment, PaintInvalidationReason::kSelection);
- fragment->SetSelectionVisualRect(selection_visual_rect);
+ bool has_selection_in_this_object =
+ object.IsText() && ToLayoutText(object).IsSelected();
+ if (!has_selection_in_this_object) {
+ for (NGPaintFragment* fragment : fragments) {
+ LayoutRect local_visual_rect = fragment->SelfInkOverflow();
+ fragment->SetVisualRect(MapFragmentLocalRectToVisualRect(
+ local_visual_rect, object, *fragment, context));
+
+ if (UNLIKELY(!fragment->SelectionVisualRect().IsEmpty())) {
+ context.painting_layer->SetNeedsRepaint();
+ ObjectPaintInvalidator(object).InvalidateDisplayItemClient(
+ *fragment, PaintInvalidationReason::kSelection);
+ fragment->SetSelectionVisualRect(LayoutRect());
+ }
+ }
+ } else {
+ // TODO(kojii): It's not clear why we need to pre-compute selection rect
+ // for all fragments when legacy can handle it as needed. yoichio will
+ // look into this.
+ for (NGPaintFragment* fragment : fragments) {
+ LayoutRect local_selection_rect =
+ ComputeFragmentLocalSelectionRect(*fragment);
+ LayoutRect local_visual_rect =
+ UnionRect(fragment->SelfInkOverflow(), local_selection_rect);
+ fragment->SetVisualRect(MapFragmentLocalRectToVisualRect(
+ local_visual_rect, object, *fragment, context));
+
+ LayoutRect selection_visual_rect = MapFragmentLocalRectToVisualRect(
+ local_selection_rect, object, *fragment, context);
+ const bool should_invalidate =
+ object.ShouldInvalidateSelection() ||
+ selection_visual_rect != fragment->SelectionVisualRect();
+ const bool rect_exists = !selection_visual_rect.IsEmpty() ||
+ !fragment->SelectionVisualRect().IsEmpty();
+ if (should_invalidate && rect_exists) {
+ context.painting_layer->SetNeedsRepaint();
+ ObjectPaintInvalidator(object).InvalidateDisplayItemClient(
+ *fragment, PaintInvalidationReason::kSelection);
+ fragment->SetSelectionVisualRect(selection_visual_rect);
+ }
}
}
}
}
}
-void PaintInvalidator::InvalidatePaint(
- LocalFrameView& frame_view,
- const PaintPropertyTreeBuilderContext* tree_builder_context,
-
- PaintInvalidatorContext& context) {
- LayoutView* layout_view = frame_view.GetLayoutView();
- CHECK(layout_view);
-
- context.paint_invalidation_container =
- context.paint_invalidation_container_for_stacked_contents =
- &layout_view->ContainerForPaintInvalidation();
- context.painting_layer = layout_view->Layer();
- context.fragment_data = &layout_view->FirstFragment();
- if (tree_builder_context) {
- context.tree_builder_context_ = &tree_builder_context->fragments[0];
-#if DCHECK_IS_ON()
- context.tree_builder_context_actually_needed_ =
- tree_builder_context->is_actually_needed;
-#endif
- }
-}
-
-static void InvalidateChromeClient(
- const LayoutBoxModelObject& paint_invalidation_container) {
- if (paint_invalidation_container.GetDocument().Printing() &&
- !RuntimeEnabledFeatures::PrintBrowserEnabled())
- return;
-
- DCHECK(paint_invalidation_container.IsLayoutView());
- DCHECK(!paint_invalidation_container.IsPaintInvalidationContainer());
-
- auto* frame_view = paint_invalidation_container.GetFrameView();
- DCHECK(!frame_view->GetFrame().OwnerLayoutObject());
- if (auto* client = frame_view->GetChromeClient()) {
- client->InvalidateRect(IntRect(IntPoint(), frame_view->Size()));
- }
-}
-
void PaintInvalidator::UpdateEmptyVisualRectFlag(
const LayoutObject& object,
PaintInvalidatorContext& context) {
@@ -404,7 +396,7 @@ void PaintInvalidator::UpdateEmptyVisualRectFlag(
// Content under transforms needs to invalidate, even if visual
// rects before and after update were the same. This is because
// we don't know whether this transform will end up composited in
- // SPv2, so such transforms are painted even if not visible
+ // CAP, so such transforms are painted even if not visible
// due to ancestor clips. This does not apply in SPv1 mode when
// crossing paint invalidation container boundaries.
if (is_paint_invalidation_container) {
@@ -417,7 +409,7 @@ void PaintInvalidator::UpdateEmptyVisualRectFlag(
}
}
-void PaintInvalidator::InvalidatePaint(
+bool PaintInvalidator::InvalidatePaint(
const LayoutObject& object,
const PaintPropertyTreeBuilderContext* tree_builder_context,
PaintInvalidatorContext& context) {
@@ -425,11 +417,11 @@ void PaintInvalidator::InvalidatePaint(
"PaintInvalidator::InvalidatePaint()", "object",
object.DebugName().Ascii());
- if (object.IsSVGHiddenContainer()) {
+ if (object.IsSVGHiddenContainer())
context.subtree_flags |= PaintInvalidatorContext::kSubtreeNoInvalidation;
- }
+
if (context.subtree_flags & PaintInvalidatorContext::kSubtreeNoInvalidation)
- return;
+ return false;
object.GetMutableForPainting().EnsureIsReadyForPaintInvalidation();
@@ -449,7 +441,7 @@ void PaintInvalidator::InvalidatePaint(
UpdateEmptyVisualRectFlag(object, context);
if (!object.ShouldCheckForPaintInvalidation() && !context.NeedsSubtreeWalk())
- return;
+ return false;
unsigned tree_builder_index = 0;
@@ -521,14 +513,7 @@ void PaintInvalidator::InvalidatePaint(
PaintInvalidatorContext::kSubtreeInvalidationChecking;
}
- // The object is under a frame for WebViewPlugin, SVG images etc. Need to
- // inform the chrome client of the invalidation so that the client will
- // initiate painting of the contents.
- // TODO(wangxianzhu): Do we need this for SPv2?
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
- !context.paint_invalidation_container->IsPaintInvalidationContainer() &&
- reason != PaintInvalidationReason::kNone)
- InvalidateChromeClient(*context.paint_invalidation_container);
+ return reason != PaintInvalidationReason::kNone;
}
void PaintInvalidator::ProcessPendingDelayedPaintInvalidations() {
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h
index cabfa006fe6..870bc8adff3 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h
@@ -138,10 +138,8 @@ struct CORE_EXPORT PaintInvalidatorContext {
class PaintInvalidator {
public:
- void InvalidatePaint(LocalFrameView&,
- const PaintPropertyTreeBuilderContext*,
- PaintInvalidatorContext&);
- void InvalidatePaint(const LayoutObject&,
+ // Returns true if the object is invalidated.
+ bool InvalidatePaint(const LayoutObject&,
const PaintPropertyTreeBuilderContext*,
PaintInvalidatorContext&);
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
index 90810d02437..701e10b3659 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -140,6 +140,7 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
: is_root_layer_(layout_object.IsLayoutView()),
has_visible_content_(false),
needs_descendant_dependent_flags_update_(true),
+ needs_visual_overflow_recalc_(true),
has_visible_descendant_(false),
#if DCHECK_IS_ON()
// The root layer (LayoutView) does not need position update at start
@@ -148,8 +149,10 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
#endif
has3d_transformed_descendant_(false),
contains_dirty_overlay_scrollbars_(false),
- needs_ancestor_dependent_compositing_inputs_update_(true),
- child_needs_compositing_inputs_update_(true),
+ needs_ancestor_dependent_compositing_inputs_update_(
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()),
+ child_needs_compositing_inputs_update_(
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()),
has_compositing_descendant_(false),
should_isolate_composited_descendants_(false),
lost_grouped_mapping_(false),
@@ -167,7 +170,8 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
filter_on_effect_node_dirty_(false),
is_under_svg_hidden_container_(false),
descendant_has_direct_or_scrolling_compositing_reason_(false),
- needs_compositing_reasons_update_(true),
+ needs_compositing_reasons_update_(
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()),
descendant_may_need_compositing_requirements_update_(false),
needs_compositing_layer_assignment_(false),
descendant_needs_compositing_layer_assignment_(false),
@@ -348,26 +352,6 @@ bool PaintLayer::SticksToScroller() const {
bool PaintLayer::FixedToViewport() const {
if (GetLayoutObject().StyleRef().GetPosition() != EPosition::kFixed)
return false;
-
- // TODO(pdr): This approach of calculating the nearest scroll node is O(n).
- // An option for improving this is to cache the nearest scroll node in
- // the local border box properties.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- const auto view_border_box_properties =
- GetLayoutObject().View()->FirstFragment().LocalBorderBoxProperties();
- const auto* view_scroll = view_border_box_properties.Transform()
- ->NearestScrollTranslationNode()
- .ScrollNode();
-
- const auto* scroll = GetLayoutObject()
- .FirstFragment()
- .LocalBorderBoxProperties()
- .Transform()
- ->NearestScrollTranslationNode()
- .ScrollNode();
- return scroll == view_scroll;
- }
-
return GetLayoutObject().Container() == GetLayoutObject().View();
}
@@ -467,7 +451,7 @@ void PaintLayer::UpdateTransform(const ComputedStyle* old_style,
if (had3d_transform != Has3DTransform()) {
SetNeedsCompositingInputsUpdateInternal();
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
}
if (LocalFrameView* frame_view = GetLayoutObject().GetDocument().View())
@@ -611,20 +595,20 @@ void PaintLayer::MapPointInPaintInvalidationContainerToBacking(
if (!paint_invalidation_layer->GroupedMapping())
return;
- LayoutBoxModelObject& transformed_ancestor =
- paint_invalidation_layer->TransformAncestorOrRoot().GetLayoutObject();
+ GraphicsLayer* squashing_layer =
+ paint_invalidation_layer->GroupedMapping()->SquashingLayer();
- // |paintInvalidationContainer| may have a local 2D transform on it, so take
- // that into account when mapping into the space of the transformed ancestor.
- point = paint_invalidation_container.LocalToAncestorPoint(
- point, &transformed_ancestor);
- // Don't include composited scroll offsets, since
- // SquashingOffsetFromTransformedAncestor does not.
- if (transformed_ancestor.UsesCompositedScrolling())
- point.Move(ToLayoutBox(transformed_ancestor).ScrolledContentOffset());
+ PropertyTreeState source_state =
+ paint_invalidation_container.FirstFragment().LocalBorderBoxProperties();
+ PropertyTreeState dest_state = squashing_layer->GetPropertyTreeState();
- point.MoveBy(-paint_invalidation_layer->GroupedMapping()
- ->SquashingOffsetFromTransformedAncestor());
+ // Move the point into the source_state transform space, map to dest_state
+ // transform space, then move into squashing layer state.
+ point.MoveBy(paint_invalidation_container.FirstFragment().PaintOffset());
+ point = GeometryMapper::SourceToDestinationProjection(
+ source_state.Transform(), dest_state.Transform())
+ .MapPoint(point);
+ point.MoveBy(-squashing_layer->GetOffsetFromTransformNode());
}
void PaintLayer::MapRectInPaintInvalidationContainerToBacking(
@@ -634,61 +618,44 @@ void PaintLayer::MapRectInPaintInvalidationContainerToBacking(
if (!paint_invalidation_layer->GroupedMapping())
return;
- LayoutBoxModelObject& transformed_ancestor =
- paint_invalidation_layer->TransformAncestorOrRoot().GetLayoutObject();
+ GraphicsLayer* squashing_layer =
+ paint_invalidation_layer->GroupedMapping()->SquashingLayer();
- // |paintInvalidationContainer| may have a local 2D transform on it, so take
- // that into account when mapping into the space of the transformed ancestor.
- rect = LayoutRect(
- paint_invalidation_container
- .LocalToAncestorQuad(FloatRect(rect), &transformed_ancestor)
- .BoundingBox());
- // Don't include composited scroll offsets, since
- // SquashingOffsetFromTransformedAncestor does not.
- if (transformed_ancestor.UsesCompositedScrolling())
- rect.Move(ToLayoutBox(transformed_ancestor).ScrolledContentOffset());
+ PropertyTreeState source_state =
+ paint_invalidation_container.FirstFragment().LocalBorderBoxProperties();
+ PropertyTreeState dest_state = squashing_layer->GetPropertyTreeState();
- rect.MoveBy(-paint_invalidation_layer->GroupedMapping()
- ->SquashingOffsetFromTransformedAncestor());
-}
-
-void PaintLayer::MapRectToPaintInvalidationBacking(
- const LayoutObject& layout_object,
- const LayoutBoxModelObject& paint_invalidation_container,
- LayoutRect& rect) {
- if (!paint_invalidation_container.Layer()->GroupedMapping()) {
- layout_object.MapToVisualRectInAncestorSpace(&paint_invalidation_container,
- rect);
- return;
- }
-
- // This code adjusts the visual rect to be in the space of the transformed
- // ancestor of the grouped (i.e. squashed) layer. This is because all layers
- // that squash together need to issue paint invalidations w.r.t. a single
- // container that is an ancestor of all of them, in order to properly take
- // into account any local transforms etc.
- // FIXME: remove this special-case code that works around the paint
- // invalidation code structure.
- layout_object.MapToVisualRectInAncestorSpace(&paint_invalidation_container,
- rect);
-
- MapRectInPaintInvalidationContainerToBacking(paint_invalidation_container,
- rect);
+ // Move the point into the source_state transform space, map to dest_state
+ // transform space, then move into squashing layer state.
+ rect.MoveBy(paint_invalidation_container.FirstFragment().PaintOffset());
+ rect = GeometryMapper::SourceToDestinationProjection(source_state.Transform(),
+ dest_state.Transform())
+ .MapRect(rect);
+ rect.MoveBy(-squashing_layer->GetOffsetFromTransformNode());
}
void PaintLayer::DirtyVisibleContentStatus() {
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
// Non-self-painting layers paint into their ancestor layer, and count as part
// of the "visible contents" of the parent, so we need to dirty it.
if (!IsSelfPaintingLayer())
Parent()->DirtyVisibleContentStatus();
}
-void PaintLayer::MarkAncestorChainForDescendantDependentFlagsUpdate() {
+void PaintLayer::MarkAncestorChainForFlagsUpdate(
+ DescendantDependentFlagsUpdateFlag flag) {
+#if DCHECK_IS_ON()
+ DCHECK(flag == DoesNotNeedDescendantDependentUpdate ||
+ !layout_object_.GetDocument()
+ .View()
+ ->IsUpdatingDescendantDependentFlags());
+#endif
for (PaintLayer* layer = this; layer; layer = layer->Parent()) {
- if (layer->needs_descendant_dependent_flags_update_)
+ if (layer->needs_descendant_dependent_flags_update_ &&
+ layer->GetLayoutObject().NeedsPaintPropertyUpdate())
break;
- layer->needs_descendant_dependent_flags_update_ = true;
+ if (flag == NeedsDescendantDependentUpdate)
+ layer->needs_descendant_dependent_flags_update_ = true;
layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
}
}
@@ -765,6 +732,16 @@ void PaintLayer::UpdateDescendantDependentFlags() {
static_cast<bool>(has_non_isolated_descendant_with_blend_mode_))
GetLayoutObject().SetNeedsPaintPropertyUpdate();
needs_descendant_dependent_flags_update_ = false;
+
+ if (IsSelfPaintingLayer() && needs_visual_overflow_recalc_) {
+ LayoutRect old_visual_rect = GetLayoutObject().VisualOverflowRect();
+ GetLayoutObject().RecalcVisualOverflow();
+ if (old_visual_rect != GetLayoutObject().VisualOverflowRect()) {
+ SetNeedsCompositingInputsUpdateInternal();
+ MarkAncestorChainForFlagsUpdate(DoesNotNeedDescendantDependentUpdate);
+ }
+ }
+ needs_visual_overflow_recalc_ = false;
}
bool previously_has_visible_content = has_visible_content_;
@@ -1098,12 +1075,21 @@ void PaintLayer::SetNeedsCompositingInputsUpdate() {
// TODO(chrishtr): These are a bit of a heavy hammer, because not all
// things which require compositing inputs update require a descendant-
- // dependent flags udpate. Reduce call sites after SPv2 launch allows
+ // dependent flags update. Reduce call sites after CAP launch allows
/// removal of CompositingInputsUpdater.
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate(NeedsDescendantDependentUpdate);
+}
+
+void PaintLayer::SetNeedsVisualOverflowRecalc() {
+ DCHECK(IsSelfPaintingLayer());
+ needs_visual_overflow_recalc_ = true;
+ MarkAncestorChainForFlagsUpdate();
}
void PaintLayer::SetNeedsCompositingInputsUpdateInternal() {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
needs_ancestor_dependent_compositing_inputs_update_ = true;
for (PaintLayer* current = this;
@@ -1119,11 +1105,13 @@ void PaintLayer::SetNeedsCompositingInputsUpdateInternal() {
void PaintLayer::UpdateAncestorDependentCompositingInputs(
const AncestorDependentCompositingInputs& compositing_inputs) {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
EnsureAncestorDependentCompositingInputs() = compositing_inputs;
needs_ancestor_dependent_compositing_inputs_update_ = false;
}
void PaintLayer::ClearChildNeedsCompositingInputsUpdate() {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
DCHECK(!NeedsCompositingInputsUpdate());
child_needs_compositing_inputs_update_ = false;
}
@@ -1350,7 +1338,7 @@ void PaintLayer::AddChild(PaintLayer* child, PaintLayer* before_child) {
// building up generated content layers. This is ok, since the lists will
// start off dirty in that case anyway.
PaintLayerStackingNode::DirtyStackingContextZOrderLists(child);
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
}
// Non-self-painting children paint into this layer, so the visible contents
@@ -1358,7 +1346,7 @@ void PaintLayer::AddChild(PaintLayer* child, PaintLayer* before_child) {
if (!child->IsSelfPaintingLayer())
DirtyVisibleContentStatus();
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
// Need to force requirements update, due to change of stacking order.
SetNeedsCompositingRequirementsUpdate();
@@ -1404,7 +1392,7 @@ PaintLayer* PaintLayer::RemoveChild(PaintLayer* old_child) {
old_child->RemoveAncestorOverflowLayer(old_child->AncestorOverflowLayer());
if (old_child->has_visible_content_ || old_child->has_visible_descendant_)
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
if (old_child->EnclosingPaginationLayer())
old_child->ClearPaginationRecursive();
@@ -1413,7 +1401,7 @@ PaintLayer* PaintLayer::RemoveChild(PaintLayer* old_child) {
}
void PaintLayer::ClearClipRects(ClipRectsCacheSlot cache_slot) {
- Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ Clipper(GeometryMapperOption::kDoNotUseGeometryMapper)
.ClearClipRectsIncludingDescendants(cache_slot);
}
@@ -1424,11 +1412,11 @@ void PaintLayer::RemoveOnlyThisLayerAfterStyleChange(
if (old_style && old_style->IsStacked()) {
PaintLayerStackingNode::DirtyStackingContextZOrderLists(this);
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
}
bool did_set_paint_invalidation = false;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// Destructing PaintLayer would cause CompositedLayerMapping and composited
// layers to be destructed and detach from layer tree immediately. Layers
// could have dangling scroll/clip parent if compositing update were
@@ -1497,7 +1485,7 @@ void PaintLayer::InsertOnlyThisLayerAfterStyleChange() {
// this object is stacked content, creating this layer may cause this object
// and its descendants to change paint invalidation container.
bool did_set_paint_invalidation = false;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
!GetLayoutObject().IsLayoutView() && GetLayoutObject().IsRooted() &&
GetLayoutObject().StyleRef().IsStacked()) {
const LayoutBoxModelObject& previous_paint_invalidation_container =
@@ -1672,7 +1660,7 @@ void PaintLayer::AppendSingleFragmentIgnoringPagination(
root_layer, &root_layer->GetLayoutObject().FirstFragment(),
kUncachedClipRects, overlay_scrollbar_clip_behavior,
respect_overflow_clip, sub_pixel_accumulation);
- Clipper(kUseGeometryMapper)
+ Clipper(GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(clip_rects_context, &GetLayoutObject().FirstFragment(),
cull_rect, fragment.layer_bounds,
fragment.background_rect, fragment.foreground_rect,
@@ -1686,7 +1674,7 @@ bool PaintLayer::ShouldFragmentCompositedBounds(
const PaintLayer* compositing_layer) const {
if (!EnclosingPaginationLayer())
return false;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return true;
if (PaintsWithTransform(kGlobalPaintNormalPhase))
return true;
@@ -1770,7 +1758,7 @@ void PaintLayer::CollectFragments(
fragment_cull_rect.emplace(rect);
}
- Clipper(kUseGeometryMapper)
+ Clipper(GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(
clip_rects_context, fragment_data,
fragment_cull_rect ? &*fragment_cull_rect : nullptr,
@@ -1981,6 +1969,9 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
HitTestingTransformState* transform_state,
double* z_offset) {
const LayoutObject& layout_object = GetLayoutObject();
+ if (layout_object.PaintBlockedByDisplayLock())
+ return nullptr;
+
DCHECK_GE(layout_object.GetDocument().Lifecycle().GetState(),
DocumentLifecycle::kCompositingClean);
@@ -2014,7 +2005,7 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
// Make sure the parent's clip rects have been calculated.
if (Parent()) {
ClipRect clip_rect;
- Clipper(PaintLayer::kUseGeometryMapper)
+ Clipper(GeometryMapperOption::kUseGeometryMapper)
.CalculateBackgroundClipRect(
ClipRectsContext(
root_layer, &root_layer->GetLayoutObject().FirstFragment(),
@@ -2442,16 +2433,42 @@ PaintLayer* PaintLayer::HitTestChildren(
return result_layer;
}
-FloatRect PaintLayer::FilterReferenceBox(const FilterOperations& filter,
- float zoom) const {
- if (!filter.HasReferenceFilter())
- return FloatRect();
+void PaintLayer::UpdateFilterReferenceBox() {
+ if (!NeedsFilterReferenceBox())
+ return;
+ FloatRect reference_box =
+ FloatRect(PhysicalBoundingBoxIncludingStackingChildren(
+ LayoutPoint(),
+ PaintLayer::kIncludeTransformsAndCompositedChildLayers));
+ float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
+ if (zoom != 1)
+ reference_box.Scale(1 / zoom);
+ EnsureResourceInfo().SetFilterReferenceBox(reference_box);
+}
- FloatRect reference_box(PhysicalBoundingBoxIncludingStackingChildren(
- LayoutPoint(), PaintLayer::CalculateBoundsOptions::
- kIncludeTransformsAndCompositedChildLayers));
+bool PaintLayer::NeedsFilterReferenceBox() const {
+ if (GetLayoutObject().HasReflection() && GetLayoutObject().IsBox())
+ return true;
+ FilterOperations operations = GetLayoutObject().StyleRef().Filter();
+ if (operations.HasBlurOrReferenceFilter())
+ return true;
+ operations = GetLayoutObject().StyleRef().BackdropFilter();
+ return !operations.IsEmpty();
+}
+
+FloatRect PaintLayer::FilterReferenceBox() const {
+ DCHECK(IsAllowedToQueryCompositingState());
+ if (ResourceInfo())
+ return ResourceInfo()->FilterReferenceBox();
+ return FloatRect();
+}
+
+FloatRect PaintLayer::BackdropFilterBounds() const {
+ FloatRect reference_box(GetLayoutObject().BorderBoundingBox());
+ float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
if (zoom != 1)
reference_box.Scale(1 / zoom);
+ reference_box.Move(-ToFloatSize(FilterReferenceBox().Location()));
return reference_box;
}
@@ -2669,7 +2686,7 @@ LayoutRect PaintLayer::BoundingBoxForCompositingInternal(
// If there is a clip applied by an ancestor to this PaintLayer but below or
// equal to |ancestorLayer|, apply that clip.
- LayoutRect result = Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ LayoutRect result = Clipper(GeometryMapperOption::kDoNotUseGeometryMapper)
.LocalClipRect(composited_layer);
result.Intersect(PhysicalBoundingBox(LayoutPoint()));
@@ -2720,7 +2737,7 @@ CompositingState PaintLayer::GetCompositingState() const {
bool PaintLayer::IsAllowedToQueryCompositingState() const {
if (g_compositing_query_mode == kCompositingQueriesAreAllowed ||
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return true;
return GetLayoutObject().GetDocument().Lifecycle().GetState() >=
DocumentLifecycle::kInCompositingUpdate;
@@ -2753,9 +2770,6 @@ void PaintLayer::EnsureCompositedLayerMapping() {
std::make_unique<CompositedLayerMapping>(*this);
rare_data_->composited_layer_mapping->SetNeedsGraphicsLayerUpdate(
kGraphicsLayerUpdateSubtree);
-
- if (PaintLayerResourceInfo* resource_info = ResourceInfo())
- resource_info->InvalidateFilterChain();
}
void PaintLayer::ClearCompositedLayerMapping(bool layer_being_destroyed) {
@@ -2772,12 +2786,6 @@ void PaintLayer::ClearCompositedLayerMapping(bool layer_being_destroyed) {
if (rare_data_)
rare_data_->composited_layer_mapping.reset();
-
- if (layer_being_destroyed)
- return;
-
- if (PaintLayerResourceInfo* resource_info = ResourceInfo())
- resource_info->InvalidateFilterChain();
}
void PaintLayer::SetGroupedMapping(CompositedLayerMapping* grouped_mapping,
@@ -2870,8 +2878,7 @@ bool PaintLayer::BackgroundIsKnownToBeOpaqueInRect(
if (Transform() && GetCompositingState() != kPaintsIntoOwnBacking)
return false;
- if (!RuntimeEnabledFeatures::CompositeOpaqueFixedPositionEnabled() &&
- GetLayoutObject().StyleRef().GetPosition() == EPosition::kFixed &&
+ if (GetLayoutObject().StyleRef().GetPosition() == EPosition::kFixed &&
GetCompositingState() != kPaintsIntoOwnBacking)
return false;
@@ -2946,8 +2953,11 @@ void PaintLayer::UpdateSelfPaintingLayer() {
// invalidate the new chain in addition to the old one.
MarkCompositingContainerChainForNeedsRepaint();
+ if (is_self_painting_layer)
+ SetNeedsVisualOverflowRecalc();
+
if (PaintLayer* parent = Parent()) {
- parent->MarkAncestorChainForDescendantDependentFlagsUpdate();
+ parent->MarkAncestorChainForFlagsUpdate();
if (PaintLayer* enclosing_self_painting_layer =
parent->EnclosingSelfPaintingLayer()) {
@@ -3016,8 +3026,6 @@ void PaintLayer::UpdateFilters(const ComputedStyle* old_style,
new_style.Filter().AddClient(EnsureResourceInfo());
if (had_resource_info && old_style)
old_style->Filter().RemoveClient(*ResourceInfo());
- if (PaintLayerResourceInfo* resource_info = ResourceInfo())
- resource_info->InvalidateFilterChain();
}
void PaintLayer::UpdateClipPath(const ComputedStyle* old_style,
@@ -3114,7 +3122,7 @@ void PaintLayer::StyleDidChange(StyleDifference diff,
}
if (PaintLayerStackingNode::StyleDidChange(this, old_style))
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
if (RequiresScrollableArea()) {
DCHECK(scrollable_area_);
@@ -3163,7 +3171,7 @@ void PaintLayer::StyleDidChange(StyleDifference diff,
// HasNonContainedAbsolutePositionDescendant depends on position changes.
if (!old_style || old_style->GetPosition() != new_style.GetPosition())
- MarkAncestorChainForDescendantDependentFlagsUpdate();
+ MarkAncestorChainForFlagsUpdate();
UpdateTransform(old_style, new_style);
UpdateFilters(old_style, new_style);
@@ -3176,15 +3184,12 @@ void PaintLayer::StyleDidChange(StyleDifference diff,
// context, in order to generate new paint chunks in the correct order.
// Raster invalidation will be issued if needed during paint.
SetNeedsRepaint();
- } else if (old_style) {
+ } else if (old_style &&
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// Change of PaintedOutputInvisible() will affect existence of paint
// chunks, so needs repaint.
- PaintLayerPainter painter(*this);
- // It's fine for PaintedOutputInvisible() to access the current
- // compositing state.
- DisableCompositingQueryAsserts disable;
- if (painter.PaintedOutputInvisible(*old_style) !=
- painter.PaintedOutputInvisible(new_style))
+ if (PaintLayerPainter::PaintedOutputInvisible(*old_style) !=
+ PaintLayerPainter::PaintedOutputInvisible(new_style))
SetNeedsRepaint();
}
}
@@ -3202,7 +3207,8 @@ LayoutPoint PaintLayer::LocationInternal() const {
PaintLayerClipper PaintLayer::Clipper(
GeometryMapperOption geometry_mapper_option) const {
- return PaintLayerClipper(*this, geometry_mapper_option == kUseGeometryMapper);
+ return PaintLayerClipper(*this, geometry_mapper_option ==
+ GeometryMapperOption::kUseGeometryMapper);
}
bool PaintLayer::ScrollsOverflow() const {
@@ -3225,35 +3231,44 @@ FilterOperations PaintLayer::FilterOperationsIncludingReflection() const {
void PaintLayer::UpdateCompositorFilterOperationsForFilter(
CompositorFilterOperations& operations) const {
- const auto& style = GetLayoutObject().StyleRef();
- float zoom = style.EffectiveZoom();
auto filter = FilterOperationsIncludingReflection();
- FloatRect reference_box = FilterReferenceBox(filter, zoom);
+ FloatRect reference_box = FilterReferenceBox();
if (!operations.IsEmpty() && !filter_on_effect_node_dirty_ &&
reference_box == operations.ReferenceBox())
return;
+ float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
operations =
FilterEffectBuilder(reference_box, zoom).BuildFilterOperations(filter);
}
void PaintLayer::UpdateCompositorFilterOperationsForBackdropFilter(
- CompositorFilterOperations& operations) const {
+ CompositorFilterOperations& operations,
+ gfx::RectF* backdrop_filter_bounds) const {
+ DCHECK(backdrop_filter_bounds);
const auto& style = GetLayoutObject().StyleRef();
- float zoom = style.EffectiveZoom();
- auto filter = FilterOperationsIncludingReflection();
- FloatRect reference_box = FilterReferenceBox(filter, zoom);
- if (!operations.IsEmpty() && reference_box == operations.ReferenceBox())
+ if (style.BackdropFilter().IsEmpty()) {
+ operations.Clear();
return;
- operations = CreateCompositorFilterOperationsForBackdropFilter();
+ }
+ FloatRect reference_box = BackdropFilterBounds();
+ *backdrop_filter_bounds = reference_box;
+ if (operations.IsEmpty() || reference_box != operations.ReferenceBox())
+ operations = CreateCompositorFilterOperationsForBackdropFilter();
}
CompositorFilterOperations
PaintLayer::CreateCompositorFilterOperationsForBackdropFilter() const {
const auto& style = GetLayoutObject().StyleRef();
+ CompositorFilterOperations return_value;
+ if (style.BackdropFilter().IsEmpty()) {
+ return return_value;
+ }
float zoom = style.EffectiveZoom();
- FloatRect reference_box = FilterReferenceBox(style.BackdropFilter(), zoom);
- return FilterEffectBuilder(reference_box, zoom)
- .BuildFilterOperations(style.BackdropFilter());
+ FloatRect reference_box = BackdropFilterBounds();
+ return_value = FilterEffectBuilder(reference_box, zoom)
+ .BuildFilterOperations(style.BackdropFilter());
+ DCHECK(!return_value.IsEmpty());
+ return return_value;
}
PaintLayerResourceInfo& PaintLayer::EnsureResourceInfo() {
@@ -3283,9 +3298,9 @@ void PaintLayer::RemoveAncestorOverflowLayer(const PaintLayer* removed_layer) {
if (PaintLayerScrollableArea* ancestor_scrollable_area =
AncestorOverflowLayer()->GetScrollableArea()) {
- // TODO(pdr): When slimming paint v2 is enabled, we will need to
- // invalidate the scroll paint property subtree for this so main
- // thread scroll reasons are recomputed.
+ // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
+ // invalidate the scroll paint property subtree for this so main thread
+ // scroll reasons are recomputed.
ancestor_scrollable_area->InvalidateStickyConstraintsFor(this);
}
}
@@ -3297,32 +3312,9 @@ void PaintLayer::RemoveAncestorOverflowLayer(const PaintLayer* removed_layer) {
}
}
-FilterEffect* PaintLayer::LastFilterEffect() const {
- // TODO(chrishtr): ensure (and assert) that compositing is clean here.
- if (!PaintsWithFilters())
- return nullptr;
- PaintLayerResourceInfo* resource_info = ResourceInfo();
- DCHECK(resource_info);
-
- if (resource_info->LastEffect())
- return resource_info->LastEffect();
-
- const auto& style = GetLayoutObject().StyleRef();
- float zoom = style.EffectiveZoom();
- FilterEffectBuilder builder(FilterReferenceBox(style.Filter(), zoom), zoom);
- resource_info->SetLastEffect(
- builder.BuildFilterEffect(FilterOperationsIncludingReflection()));
- return resource_info->LastEffect();
-}
-
FloatRect PaintLayer::MapRectForFilter(const FloatRect& rect) const {
if (!HasFilterThatMovesPixels())
return rect;
-
- // Ensure the filter-chain is refreshed wrt reference filters.
- // TODO(fs): Avoid having this side-effect inducing call.
- LastFilterEffect();
-
return FilterOperationsIncludingReflection().MapRect(rect);
}
@@ -3395,6 +3387,13 @@ void PaintLayer::ComputeSelfHitTestRects(
void PaintLayer::SetNeedsRepaint() {
SetNeedsRepaintInternal();
+ // If you need repaint, then you might issue raster invalidations, and in
+ // Composite after Paint mode, we do these in PAC::Update().
+ LocalFrameView* frame_view = GetLayoutObject().GetDocument().View();
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && frame_view) {
+ frame_view->SetPaintArtifactCompositorNeedsUpdate();
+ }
+
// Do this unconditionally to ensure container chain is marked when
// compositing status of the layer changes.
MarkCompositingContainerChainForNeedsRepaint();
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer.h b/chromium/third_party/blink/renderer/core/paint/paint_layer.h
index 232b549fab4..9068cf57d98 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer.h
@@ -346,6 +346,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
void DirtyVisibleContentStatus();
+ // True if this layer paints box decorations or a background. Touch-action
+ // rects are painted as part of the background so these are included here.
bool HasBoxDecorationsOrBackground() const;
bool HasVisibleBoxDecorations() const;
// True if this layer container layoutObjects that paint.
@@ -567,15 +569,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const LayoutBoxModelObject& paint_invalidation_container,
LayoutRect&);
- // Adjusts the given rect (in the coordinate space of the LayoutObject) to the
- // coordinate space of |paintInvalidationContainer|'s GraphicsLayer backing.
- // Should use PaintInvalidatorContext::MapRectToPaintInvalidationBacking()
- // instead if PaintInvalidatorContext.
- static void MapRectToPaintInvalidationBacking(
- const LayoutObject&,
- const LayoutBoxModelObject& paint_invalidation_container,
- LayoutRect&);
-
bool PaintsWithTransparency(GlobalPaintFlags global_paint_flags) const {
return IsTransparent() && !PaintsIntoOwnBacking(global_paint_flags);
}
@@ -614,23 +607,26 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// only if |filter_on_effect_node_dirty_| is true or the reference box has
// changed. Otherwise it will be populated unconditionally.
void UpdateCompositorFilterOperationsForFilter(
- CompositorFilterOperations&) const;
+ CompositorFilterOperations& operations) const;
void SetFilterOnEffectNodeDirty() { filter_on_effect_node_dirty_ = true; }
void ClearFilterOnEffectNodeDirty() { filter_on_effect_node_dirty_ = false; }
+ // |backdrop_filter_bounds| is an out param from both of these functions, and
+ // it represents the clipping bounds for the filtered backdrop image only.
+ // This rect lives in the local transform space of the containing
+ // EffectPaintPropertyNode.
void UpdateCompositorFilterOperationsForBackdropFilter(
- CompositorFilterOperations&) const;
+ CompositorFilterOperations& operations,
+ gfx::RectF* backdrop_filter_bounds) const;
+ CompositorFilterOperations CreateCompositorFilterOperationsForBackdropFilter()
+ const;
void SetIsUnderSVGHiddenContainer(bool value) {
is_under_svg_hidden_container_ = value;
}
bool IsUnderSVGHiddenContainer() { return is_under_svg_hidden_container_; }
- CompositorFilterOperations CreateCompositorFilterOperationsForBackdropFilter()
- const;
-
bool PaintsWithFilters() const;
- FilterEffect* LastFilterEffect() const;
// Maps "forward" to determine which pixels in a destination rect are
// affected by pixels in the source rect.
@@ -647,6 +643,13 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
}
PaintLayerResourceInfo& EnsureResourceInfo();
+ // Filter reference box is the area over which the filter is computed, in the
+ // coordinate system of the object with the filter. Filter bounds is the
+ // reference box, offset by the object's location in the graphics layer.
+ FloatRect FilterReferenceBox() const;
+ FloatRect BackdropFilterBounds() const;
+
+ void UpdateFilterReferenceBox();
void UpdateFilters(const ComputedStyle* old_style,
const ComputedStyle& new_style);
void UpdateClipPath(const ComputedStyle* old_style,
@@ -678,7 +681,10 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
return scrollable_area_.Get();
}
- enum GeometryMapperOption { kUseGeometryMapper, kDoNotUseGeometryMapper };
+ enum class GeometryMapperOption {
+ kUseGeometryMapper,
+ kDoNotUseGeometryMapper
+ };
PaintLayerClipper Clipper(GeometryMapperOption) const;
@@ -757,8 +763,11 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
bool is_under_video = false;
};
-
+ void SetNeedsVisualOverflowRecalc();
void SetNeedsCompositingInputsUpdate();
+
+ // Use this internal method only for cases during the descendant-dependent
+ // tree walk.
bool ChildNeedsCompositingInputsUpdate() const {
return child_needs_compositing_inputs_update_;
}
@@ -1036,11 +1045,11 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// Whether the value of isSelfPaintingLayer() changed since the last clearing
// (which happens after the flag is chedked during compositing update).
bool SelfPaintingStatusChanged() const {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
return self_painting_status_changed_;
}
void ClearSelfPaintingStatusChanged() {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
self_painting_status_changed_ = false;
}
@@ -1175,7 +1184,17 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
bool RequiresScrollableArea() const;
void UpdateScrollableArea();
- void MarkAncestorChainForDescendantDependentFlagsUpdate();
+ // Indicates whether the descendant-dependent tree walk bit should also
+ // be set.
+ enum DescendantDependentFlagsUpdateFlag {
+ NeedsDescendantDependentUpdate,
+ DoesNotNeedDescendantDependentUpdate
+ };
+
+ // Marks the ancestor chain for paint property update, and if
+ // the flag is set, the descendant-dependent tree walk as well.
+ void MarkAncestorChainForFlagsUpdate(
+ DescendantDependentFlagsUpdateFlag = NeedsDescendantDependentUpdate);
bool AttemptDirectCompositingUpdate(const StyleDifference&,
const ComputedStyle* old_style);
@@ -1215,7 +1234,7 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const PaintLayer* stacking_parent,
CalculateBoundsOptions) const;
- FloatRect FilterReferenceBox(const FilterOperations&, float zoom) const;
+ bool NeedsFilterReferenceBox() const;
LayoutPoint LocationInternal() const;
@@ -1238,7 +1257,10 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const unsigned is_root_layer_ : 1;
unsigned has_visible_content_ : 1;
+
unsigned needs_descendant_dependent_flags_update_ : 1;
+ unsigned needs_visual_overflow_recalc_ : 1;
+
unsigned has_visible_descendant_ : 1;
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc
index 31723b02f8d..b068340c278 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc
@@ -48,14 +48,16 @@ TEST_F(PaintLayerClipperTest, ParentBackgroundClipRectSubpixelAccumulation) {
LayoutSize(FloatSize(0.25, 0.35)));
ClipRect background_rect_gm;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateBackgroundClipRect(context, background_rect_gm);
EXPECT_EQ(LayoutRect(FloatRect(8.25, 8.34375, 300, 300)),
background_rect_gm.Rect());
ClipRect background_rect_nogm;
- target_paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(context, background_rect_nogm);
EXPECT_EQ(LayoutRect(FloatRect(8.25, 8.34375, 300, 300)),
@@ -78,14 +80,16 @@ TEST_F(PaintLayerClipperTest, BackgroundClipRectSubpixelAccumulation) {
LayoutSize(FloatSize(0.25, 0.35)));
ClipRect background_rect_gm;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateBackgroundClipRect(context, background_rect_gm);
EXPECT_GE(background_rect_gm.Rect().Size().Width().ToInt(), 33554422);
EXPECT_GE(background_rect_gm.Rect().Size().Height().ToInt(), 33554422);
ClipRect background_rect_nogm;
- target_paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(context, background_rect_nogm);
EXPECT_GE(background_rect_nogm.Rect().Size().Width().ToInt(), 33554422);
@@ -110,14 +114,16 @@ TEST_F(PaintLayerClipperTest, SVGBackgroundClipRectSubpixelAccumulation) {
LayoutSize(FloatSize(0.25, 0.35)));
ClipRect background_rect_gm;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateBackgroundClipRect(context, background_rect_gm);
EXPECT_GE(background_rect_gm.Rect().Size().Width().ToInt(), 33554422);
EXPECT_GE(background_rect_gm.Rect().Size().Height().ToInt(), 33554422);
ClipRect background_rect_nogm;
- target_paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(context, background_rect_nogm);
EXPECT_GE(background_rect_nogm.Rect().Size().Width().ToInt(), 33554422);
@@ -145,7 +151,8 @@ TEST_F(PaintLayerClipperTest, LayoutSVGRoot) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -175,7 +182,8 @@ TEST_F(PaintLayerClipperTest, ControlClip) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -215,7 +223,8 @@ TEST_F(PaintLayerClipperTest, RoundedClip) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -256,7 +265,8 @@ TEST_F(PaintLayerClipperTest, RoundedClipNested) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- child_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ child_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&child_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -293,7 +303,8 @@ TEST_F(PaintLayerClipperTest, ControlClipSelect) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -326,7 +337,8 @@ TEST_F(PaintLayerClipperTest, LayoutSVGRootChild) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -352,7 +364,7 @@ TEST_F(PaintLayerClipperTest, ContainPaintClip) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- layer->Clipper(PaintLayer::kUseGeometryMapper)
+ layer->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
EXPECT_GE(background_rect.Rect().Size().Width().ToInt(), 33554422);
@@ -363,7 +375,7 @@ TEST_F(PaintLayerClipperTest, ContainPaintClip) {
ClipRectsContext context_clip(
layer, &layer->GetLayoutObject().FirstFragment(), kUncachedClipRects);
- layer->Clipper(PaintLayer::kUseGeometryMapper)
+ layer->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context_clip, &layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
EXPECT_EQ(LayoutRect(0, 0, 200, 200), background_rect.Rect());
@@ -389,7 +401,7 @@ TEST_F(PaintLayerClipperTest, NestedContainPaintClip) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- layer->Clipper(PaintLayer::kUseGeometryMapper)
+ layer->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
EXPECT_EQ(LayoutRect(0, 0, 200, 400), background_rect.Rect());
@@ -400,7 +412,7 @@ TEST_F(PaintLayerClipperTest, NestedContainPaintClip) {
layer->Parent(), &layer->Parent()->GetLayoutObject().FirstFragment(),
kUncachedClipRects);
- layer->Clipper(PaintLayer::kUseGeometryMapper)
+ layer->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context_clip, &layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
EXPECT_EQ(LayoutRect(0, 0, 200, 200), background_rect.Rect());
@@ -426,18 +438,19 @@ TEST_F(PaintLayerClipperTest, LocalClipRectFixedUnderTransform) {
PaintLayer* fixed =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("fixed"))->Layer();
- EXPECT_EQ(LayoutRect(0, 0, 100, 100),
- transformed->Clipper(PaintLayer::kUseGeometryMapper)
- .LocalClipRect(*transformed));
+ EXPECT_EQ(
+ LayoutRect(0, 0, 100, 100),
+ transformed->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
+ .LocalClipRect(*transformed));
EXPECT_EQ(LayoutRect(0, 50, 100, 100),
- fixed->Clipper(PaintLayer::kUseGeometryMapper)
+ fixed->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.LocalClipRect(*transformed));
}
TEST_F(PaintLayerClipperTest, ClearClipRectsRecursive) {
- // SPv2 will re-use a global GeometryMapper, so this
+ // CAP will re-use a global GeometryMapper, so this
// logic does not apply.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -462,7 +475,7 @@ TEST_F(PaintLayerClipperTest, ClearClipRectsRecursive) {
EXPECT_TRUE(parent->GetClipRectsCache());
EXPECT_TRUE(child->GetClipRectsCache());
- parent->Clipper(PaintLayer::kUseGeometryMapper)
+ parent->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.ClearClipRectsIncludingDescendants();
EXPECT_FALSE(parent->GetClipRectsCache());
@@ -470,9 +483,9 @@ TEST_F(PaintLayerClipperTest, ClearClipRectsRecursive) {
}
TEST_F(PaintLayerClipperTest, ClearClipRectsRecursiveChild) {
- // SPv2 will re-use a global GeometryMapper, so this
+ // CAP will re-use a global GeometryMapper, so this
// logic does not apply.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -497,7 +510,7 @@ TEST_F(PaintLayerClipperTest, ClearClipRectsRecursiveChild) {
EXPECT_TRUE(parent->GetClipRectsCache());
EXPECT_TRUE(child->GetClipRectsCache());
- child->Clipper(PaintLayer::kUseGeometryMapper)
+ child->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.ClearClipRectsIncludingDescendants();
EXPECT_TRUE(parent->GetClipRectsCache());
@@ -524,7 +537,7 @@ TEST_F(PaintLayerClipperTest, CSSClip) {
LayoutRect layer_bounds(infinite_rect);
ClipRect background_rect(infinite_rect);
ClipRect foreground_rect(infinite_rect);
- target->Clipper(PaintLayer::kUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &target->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -554,7 +567,7 @@ TEST_F(PaintLayerClipperTest, Filter) {
LayoutRect layer_bounds(infinite_rect);
ClipRect background_rect(infinite_rect);
ClipRect foreground_rect(infinite_rect);
- target->Clipper(PaintLayer::kUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &target->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -569,7 +582,7 @@ TEST_F(PaintLayerClipperTest, Filter) {
// Test without GeometryMapper.
background_rect = infinite_rect;
foreground_rect = infinite_rect;
- target->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateRects(context, nullptr, nullptr, layer_bounds, background_rect,
foreground_rect);
// The non-GeometryMapper path applies the immediate filter effect in
@@ -583,7 +596,7 @@ TEST_F(PaintLayerClipperTest, Filter) {
kUncachedClipRects);
background_rect = infinite_rect;
foreground_rect = infinite_rect;
- target->Clipper(PaintLayer::kUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(root_context, &target->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
// This includes the filter effect because it's applied before mapping the
@@ -594,7 +607,7 @@ TEST_F(PaintLayerClipperTest, Filter) {
// Test mapping to the root layer without GeometryMapper.
background_rect = infinite_rect;
foreground_rect = infinite_rect;
- target->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateRects(root_context, nullptr, nullptr, layer_bounds,
background_rect, foreground_rect);
EXPECT_EQ(LayoutRect(38, 41, 204, 304), background_rect.Rect());
@@ -636,7 +649,7 @@ TEST_F(PaintLayerClipperTest, IgnoreRootLayerClipWithCSSClip) {
LayoutRect layer_bounds(infinite_rect);
ClipRect background_rect(infinite_rect);
ClipRect foreground_rect(infinite_rect);
- target->Clipper(PaintLayer::kUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &target->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -672,7 +685,7 @@ TEST_F(PaintLayerClipperTest, IgnoreRootLayerClipWithOverflowClip) {
LayoutRect layer_bounds(infinite_rect);
ClipRect background_rect(infinite_rect);
ClipRect foreground_rect(infinite_rect);
- target->Clipper(PaintLayer::kUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &target->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -709,7 +722,7 @@ TEST_F(PaintLayerClipperTest, IgnoreRootLayerClipWithBothClip) {
LayoutRect layer_bounds(infinite_rect);
ClipRect background_rect(infinite_rect);
ClipRect foreground_rect(infinite_rect);
- target->Clipper(PaintLayer::kUseGeometryMapper)
+ target->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context, &target->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -747,7 +760,8 @@ TEST_F(PaintLayerClipperTest, Fragmentation) {
.NextFragment()
->NextFragment());
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -758,7 +772,8 @@ TEST_F(PaintLayerClipperTest, Fragmentation) {
foreground_rect.Rect());
EXPECT_EQ(LayoutRect(FloatRect(0, 0, 100, 200)), layer_bounds);
- target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ target_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(
context,
target_paint_layer->GetLayoutObject().FirstFragment().NextFragment(),
@@ -798,7 +813,8 @@ TEST_F(PaintLayerClipperTest, ScrollbarClipBehaviorChild) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- child_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ child_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&child_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -808,7 +824,8 @@ TEST_F(PaintLayerClipperTest, ScrollbarClipBehaviorChild) {
EXPECT_EQ(LayoutRect(0, 0, 193, 293), foreground_rect.Rect());
EXPECT_EQ(LayoutRect(0, 0, 500, 500), layer_bounds);
- child_paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ child_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateRects(context, nullptr, nullptr, layer_bounds, background_rect,
foreground_rect);
@@ -842,7 +859,8 @@ TEST_F(PaintLayerClipperTest, ScrollbarClipBehaviorChildScrollBetween) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- child_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ child_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&child_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -852,7 +870,8 @@ TEST_F(PaintLayerClipperTest, ScrollbarClipBehaviorChildScrollBetween) {
EXPECT_EQ(LayoutRect(8, 8, 193, 293), foreground_rect.Rect());
EXPECT_EQ(LayoutRect(8, 8, 500, 500), layer_bounds);
- child_paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ child_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateRects(context, nullptr, nullptr, layer_bounds, background_rect,
foreground_rect);
@@ -884,7 +903,8 @@ TEST_F(PaintLayerClipperTest, ScrollbarClipBehaviorParent) {
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
- parent_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+ parent_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kUseGeometryMapper)
.CalculateRects(context,
&parent_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
@@ -895,7 +915,8 @@ TEST_F(PaintLayerClipperTest, ScrollbarClipBehaviorParent) {
EXPECT_EQ(LayoutRect(0, 0, 193, 293), foreground_rect.Rect());
EXPECT_EQ(LayoutRect(0, 0, 200, 300), layer_bounds);
- parent_paint_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ parent_paint_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateRects(context, nullptr, nullptr, layer_bounds, background_rect,
foreground_rect);
@@ -922,12 +943,13 @@ TEST_F(PaintLayerClipperTest, FixedLayerClipRectInDocumentSpace) {
GetDocument()
.GetLayoutView()
->Layer()
- ->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.ClearClipRectsIncludingDescendants();
{
ClipRect clip_rect;
- target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(
ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
&GetDocument().GetLayoutView()->FirstFragment(),
@@ -942,7 +964,8 @@ TEST_F(PaintLayerClipperTest, FixedLayerClipRectInDocumentSpace) {
{
ClipRect clip_rect;
- target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(
ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
&GetDocument().GetLayoutView()->FirstFragment(),
@@ -974,12 +997,13 @@ TEST_F(PaintLayerClipperTest,
GetDocument()
.GetLayoutView()
->Layer()
- ->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.ClearClipRectsIncludingDescendants();
{
ClipRect clip_rect;
- target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(
ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
&GetDocument().GetLayoutView()->FirstFragment(),
@@ -994,7 +1018,8 @@ TEST_F(PaintLayerClipperTest,
{
ClipRect clip_rect;
- target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+ target_layer
+ ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
.CalculateBackgroundClipRect(
ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
&GetDocument().GetLayoutView()->FirstFragment(),
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index aaca470e4d1..0171009e127 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -58,9 +58,9 @@ static ShouldRespectOverflowClipType ShouldRespectOverflowClip(
: kRespectOverflowClip;
}
-bool PaintLayerPainter::PaintedOutputInvisible(
- const ComputedStyle& style,
- GlobalPaintFlags global_paint_flags) const {
+bool PaintLayerPainter::PaintedOutputInvisible(const ComputedStyle& style) {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+
if (style.HasBackdropFilter())
return false;
@@ -70,29 +70,14 @@ bool PaintLayerPainter::PaintedOutputInvisible(
if (style.HasWillChangeOpacityHint())
return false;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- if (style.Opacity())
- return false;
-
- const auto* effect = paint_layer_.GetLayoutObject()
- .FirstFragment()
- .PaintProperties()
- ->Effect();
- if (effect && effect->RequiresCompositingForAnimation()) {
- return false;
- }
- }
-
// 0.0004f < 1/2048. With 10-bit color channels (only available on the
// newest Macs; otherwise it's 8-bit), we see that an alpha of 1/2048 or
// less leads to a color output of less than 0.5 in all channels, hence
// not visible.
static const float kMinimumVisibleOpacity = 0.0004f;
- if (paint_layer_.PaintsWithTransparency(global_paint_flags)) {
- if (style.Opacity() < kMinimumVisibleOpacity) {
- return true;
- }
- }
+ if (style.Opacity() < kMinimumVisibleOpacity)
+ return true;
+
return false;
}
@@ -132,14 +117,17 @@ PaintResult PaintLayerPainter::Paint(
if (ShouldSuppressPaintingLayer(paint_layer_))
return kFullyPainted;
- // If this layer is totally invisible then there is nothing to paint. In SPv2
+ // If this layer is totally invisible then there is nothing to paint. In CAP
// we simplify this optimization by painting even when effectively invisible
// but skipping the painted content during layerization in
// PaintArtifactCompositor.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
- PaintedOutputInvisible(paint_layer_.GetLayoutObject().StyleRef(),
- painting_info.GetGlobalPaintFlags())) {
- return kFullyPainted;
+ if (paint_layer_.PaintsWithTransparency(
+ painting_info.GetGlobalPaintFlags())) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ PaintedOutputInvisible(paint_layer_.GetLayoutObject().StyleRef()))
+ return kFullyPainted;
+
+ paint_flags |= kPaintLayerHaveTransparency;
}
// If the transform can't be inverted, then don't paint anything.
@@ -149,9 +137,6 @@ PaintResult PaintLayerPainter::Paint(
return kFullyPainted;
}
- if (paint_layer_.PaintsWithTransparency(painting_info.GetGlobalPaintFlags()))
- paint_flags |= kPaintLayerHaveTransparency;
-
paint_flags |= kPaintLayerPaintingCompositingAllPhases;
return PaintLayerContents(context, painting_info, paint_flags);
}
@@ -295,7 +280,7 @@ void PaintLayerPainter::AdjustForPaintProperties(
painting_info.root_layer->GetLayoutObject().FirstFragment();
const auto* source_transform =
first_root_fragment.LocalBorderBoxProperties().Transform();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
IsMainFrameNotClippingContents(*painting_info.root_layer)) {
// Use PostScrollTranslation as the source transform to avoid clipping of
// the scrolling contents in CullRect::ApplyTransforms().
@@ -306,7 +291,7 @@ void PaintLayerPainter::AdjustForPaintProperties(
if (source_transform == destination_transform)
return;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
auto& cull_rect = painting_info.cull_rect;
// CullRect::ApplyTransforms() requires the cull rect in the source
// transform space. Convert cull_rect from the root layer's local space.
@@ -612,7 +597,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
if (should_paint_mask) {
PaintMaskForFragments(layer_fragments, context, local_painting_info,
paint_flags);
- } else if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ } else if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
is_painting_mask &&
!(painting_info.GetGlobalPaintFlags() &
kGlobalPaintFlattenCompositingLayers) &&
@@ -708,6 +693,7 @@ PaintResult PaintLayerPainter::PaintChildren(
return result;
if (!paint_layer_.StackingNode())
return result;
+
#if DCHECK_IS_ON()
LayerListMutationDetector mutation_checker(paint_layer_.StackingNode());
#endif
@@ -717,7 +703,6 @@ PaintResult PaintLayerPainter::PaintChildren(
PaintLayer* child = iterator.Next();
if (!child)
return result;
-
for (; child; child = iterator.Next()) {
// If this Layer should paint into its own backing or a grouped backing,
// that will be done via CompositedLayerMapping::PaintContents() and
@@ -818,7 +803,6 @@ void PaintLayerPainter::PaintFragmentWithPhase(
? fragment.fragment_data->LogicalTopInFlowThread()
: LayoutUnit(),
suppress_painting_descendants);
-
paint_layer_.GetLayoutObject().Paint(paint_info);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
index 4c39e007f2b..11a28177159 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
@@ -55,8 +55,7 @@ class CORE_EXPORT PaintLayerPainter {
// Returns true if the painted output of this PaintLayer and its children is
// invisible and therefore can't impact painted output.
- bool PaintedOutputInvisible(const ComputedStyle&,
- GlobalPaintFlags = kGlobalPaintNormalPhase) const;
+ static bool PaintedOutputInvisible(const ComputedStyle&);
private:
friend class PaintLayerPainterTest;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
index ccafe4bd544..d4683513060 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -20,24 +20,22 @@ class PaintLayerPainterTest : public PaintControllerPaintTest {
USING_FAST_MALLOC(PaintLayerPainterTest);
public:
- void ExpectPaintedOutputInvisible(const char* element_name,
- bool expected_value) {
+ void ExpectPaintedOutputInvisibleAndPaintsWithTransparency(
+ const char* element_name,
+ bool expected_invisible,
+ bool expected_paints_with_transparency) {
// The optimization to skip painting for effectively-invisible content is
- // limited to pre-SPv2.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // limited to pre-CAP.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
PaintLayer* target_layer =
ToLayoutBox(GetLayoutObjectByElementId(element_name))->Layer();
- PaintLayerPaintingInfo painting_info(nullptr, CullRect(),
- kGlobalPaintNormalPhase, LayoutSize());
- bool invisible =
- PaintLayerPainter(*target_layer)
- .PaintedOutputInvisible(target_layer->GetLayoutObject().StyleRef(),
- painting_info.GetGlobalPaintFlags());
- EXPECT_EQ(expected_value, invisible)
- << "Failed painted output visibility, expected=" << expected_value
- << ", actual=" << invisible << "].";
+ bool invisible = PaintLayerPainter::PaintedOutputInvisible(
+ target_layer->GetLayoutObject().StyleRef());
+ EXPECT_EQ(expected_invisible, invisible);
+ EXPECT_EQ(expected_paints_with_transparency,
+ target_layer->PaintsWithTransparency(kGlobalPaintNormalPhase));
}
PaintController& MainGraphicsLayerPaintController() {
@@ -208,8 +206,7 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnCullRectChange) {
DisplayItemClient& content3 = *GetDisplayItemClientFromElementId("content3");
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- IntRect cull_rect(0, 0, 400, 300);
- Paint(&cull_rect);
+ Paint(IntRect(0, 0, 400, 300));
const auto& background_display_item_client = ViewScrollingBackgroundClient();
@@ -228,8 +225,7 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnCullRectChange) {
IsSameId(&content3, kBackgroundType)));
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- IntRect new_cull_rect(0, 100, 300, 1000);
- EXPECT_TRUE(PaintWithoutCommit(&new_cull_rect));
+ EXPECT_TRUE(PaintWithoutCommit(IntRect(0, 100, 300, 1000)));
// Container1 becomes partly in the interest rect, but uses cached subsequence
// because it was fully painted before;
@@ -265,14 +261,12 @@ TEST_P(PaintLayerPainterTest,
// |target| will be fully painted.
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- IntRect cull_rect(0, 0, 400, 300);
- Paint(&cull_rect);
+ Paint(IntRect(0, 0, 400, 300));
// |target| will be partially painted. Should not trigger under-invalidation
// checking DCHECKs.
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- IntRect new_cull_rect(0, 100, 300, 1000);
- Paint(&new_cull_rect);
+ Paint(IntRect(0, 100, 300, 1000));
}
TEST_P(PaintLayerPainterTest,
@@ -291,8 +285,7 @@ TEST_P(PaintLayerPainterTest,
)HTML");
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// PaintResult of all subsequences will be MayBeClippedByCullRect.
- IntRect cull_rect(0, 0, 50, 300);
- Paint(&cull_rect);
+ Paint(IntRect(0, 0, 50, 300));
DisplayItemClient& container1 =
*GetDisplayItemClientFromElementId("container1");
@@ -315,7 +308,7 @@ TEST_P(PaintLayerPainterTest,
"position: absolute; width: 100px; height: 100px; "
"background-color: green");
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- EXPECT_TRUE(PaintWithoutCommit(&cull_rect));
+ EXPECT_TRUE(PaintWithoutCommit(IntRect(0, 0, 50, 300)));
EXPECT_EQ(4, NumCachedNewItems());
CommitAndFinishCycle();
@@ -350,8 +343,8 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
const auto& view_client = ViewScrollingBackgroundClient();
// |target| is partially painted.
EXPECT_EQ(kMayBeClippedByCullRect, target_layer->PreviousPaintResult());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // SPv2 doesn't clip the cull rect by the scrolling contents rect, which
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // CAP doesn't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
target_layer->PreviousCullRect());
@@ -386,8 +379,8 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
// |target| is still partially painted.
EXPECT_EQ(kMayBeClippedByCullRect, target_layer->PreviousPaintResult());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // SPv2 doens't clip the cull rect by the scrolling contents rect, which
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // CAP doens't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
target_layer->PreviousCullRect());
@@ -422,8 +415,8 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
// |target| is still partially painted.
EXPECT_EQ(kMayBeClippedByCullRect, target_layer->PreviousPaintResult());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // SPv2 doens't clip the cull rect by the scrolling contents rect, which
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // CAP doens't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -1000, 8800, 8600)),
target_layer->PreviousCullRect());
@@ -590,7 +583,11 @@ TEST_P(PaintLayerPainterTest, PaintPhaseFloatUnderInlineLayer) {
GetDocument().getElementById("span")->GetLayoutObject());
PaintLayer& span_layer = *span.Layer();
ASSERT_TRUE(&span_layer == float_div.EnclosingLayer());
- ASSERT_FALSE(span_layer.NeedsPaintPhaseFloat());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ ASSERT_TRUE(span_layer.NeedsPaintPhaseFloat());
+ } else {
+ ASSERT_FALSE(span_layer.NeedsPaintPhaseFloat());
+ }
LayoutBoxModelObject& self_painting_layer_object = *ToLayoutBoxModelObject(
GetDocument().getElementById("self-painting-layer")->GetLayoutObject());
PaintLayer& self_painting_layer = *self_painting_layer_object.Layer();
@@ -602,9 +599,14 @@ TEST_P(PaintLayerPainterTest, PaintPhaseFloatUnderInlineLayer) {
->Layer();
ASSERT_FALSE(non_self_painting_layer.IsSelfPaintingLayer());
- EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseFloat());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_FALSE(self_painting_layer.NeedsPaintPhaseFloat());
+ EXPECT_TRUE(span_layer.NeedsPaintPhaseFloat());
+ } else {
+ EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseFloat());
+ EXPECT_FALSE(span_layer.NeedsPaintPhaseFloat());
+ }
EXPECT_FALSE(non_self_painting_layer.NeedsPaintPhaseFloat());
- EXPECT_FALSE(span_layer.NeedsPaintPhaseFloat());
EXPECT_TRUE(DisplayItemListContains(
RootPaintController().GetDisplayItemList(), float_div,
DisplayItem::kBoxDecorationBackground));
@@ -834,21 +836,21 @@ TEST_P(PaintLayerPainterTest,
TEST_P(PaintLayerPainterTest, DontPaintWithTinyOpacity) {
SetBodyInnerHTML(
"<div id='target' style='background: blue; opacity: 0.0001'></div>");
- ExpectPaintedOutputInvisible("target", true);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", true, true);
}
TEST_P(PaintLayerPainterTest, DoPaintWithTinyOpacityAndWillChangeOpacity) {
SetBodyInnerHTML(
"<div id='target' style='background: blue; opacity: 0.0001; "
" will-change: opacity'></div>");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
TEST_P(PaintLayerPainterTest, DoPaintWithTinyOpacityAndBackdropFilter) {
SetBodyInnerHTML(
"<div id='target' style='background: blue; opacity: 0.0001;"
" backdrop-filter: blur(2px);'></div>");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
TEST_P(PaintLayerPainterTest,
@@ -856,20 +858,20 @@ TEST_P(PaintLayerPainterTest,
SetBodyInnerHTML(
"<div id='target' style='background: blue; opacity: 0.0001;"
" backdrop-filter: blur(2px); will-change: opacity'></div>");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
TEST_P(PaintLayerPainterTest, DoPaintWithCompositedTinyOpacity) {
SetBodyInnerHTML(
"<div id='target' style='background: blue; opacity: 0.0001;"
" will-change: transform'></div>");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", true, false);
}
TEST_P(PaintLayerPainterTest, DoPaintWithNonTinyOpacity) {
SetBodyInnerHTML(
"<div id='target' style='background: blue; opacity: 0.1'></div>");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, true);
}
TEST_P(PaintLayerPainterTest, DoPaintWithEffectAnimationZeroOpacity) {
@@ -888,7 +890,7 @@ TEST_P(PaintLayerPainterTest, DoPaintWithEffectAnimationZeroOpacity) {
</style>
<div id='target'></div>
)HTML");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", true, false);
}
TEST_P(PaintLayerPainterTest, DoPaintWithTransformAnimationZeroOpacity) {
@@ -906,7 +908,7 @@ TEST_P(PaintLayerPainterTest, DoPaintWithTransformAnimationZeroOpacity) {
</style>
<div id='target'>x</div></div>
)HTML");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", true, false);
}
TEST_P(PaintLayerPainterTest,
@@ -926,7 +928,7 @@ TEST_P(PaintLayerPainterTest,
</style>
<div id='target'>x</div></div>
)HTML");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
TEST_P(PaintLayerPainterTest, DoPaintWithWillChangeOpacity) {
@@ -940,7 +942,7 @@ TEST_P(PaintLayerPainterTest, DoPaintWithWillChangeOpacity) {
</style>
<div id='target'></div>
)HTML");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
TEST_P(PaintLayerPainterTest, DoPaintWithZeroOpacityAndWillChangeOpacity) {
@@ -955,7 +957,7 @@ TEST_P(PaintLayerPainterTest, DoPaintWithZeroOpacityAndWillChangeOpacity) {
</style>
<div id='target'></div>
)HTML");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
TEST_P(PaintLayerPainterTest,
@@ -971,14 +973,14 @@ TEST_P(PaintLayerPainterTest,
</style>
<div id='target'></div>
)HTML");
- ExpectPaintedOutputInvisible("target", false);
+ ExpectPaintedOutputInvisibleAndPaintsWithTransparency("target", false, false);
}
-using PaintLayerPainterTestSPv2 = PaintLayerPainterTest;
+using PaintLayerPainterTestCAP = PaintLayerPainterTest;
-INSTANTIATE_SPV2_TEST_CASE_P(PaintLayerPainterTestSPv2);
+INSTANTIATE_CAP_TEST_CASE_P(PaintLayerPainterTestCAP);
-TEST_P(PaintLayerPainterTestSPv2, SimpleCullRect) {
+TEST_P(PaintLayerPainterTestCAP, SimpleCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target'
style='width: 200px; height: 200px; position: relative'>
@@ -989,7 +991,7 @@ TEST_P(PaintLayerPainterTestSPv2, SimpleCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, TallLayerCullRect) {
+TEST_P(PaintLayerPainterTestCAP, TallLayerCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target'
style='width: 200px; height: 10000px; position: relative'>
@@ -1001,7 +1003,7 @@ TEST_P(PaintLayerPainterTestSPv2, TallLayerCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, WideLayerCullRect) {
+TEST_P(PaintLayerPainterTestCAP, WideLayerCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target'
style='width: 10000px; height: 200px; position: relative'>
@@ -1013,7 +1015,7 @@ TEST_P(PaintLayerPainterTestSPv2, WideLayerCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, TallScrolledLayerCullRect) {
+TEST_P(PaintLayerPainterTestCAP, TallScrolledLayerCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target' style='width: 200px; height: 10000px; position: relative'>
</div>
@@ -1044,7 +1046,7 @@ TEST_P(PaintLayerPainterTestSPv2, TallScrolledLayerCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, WholeDocumentCullRect) {
+TEST_P(PaintLayerPainterTestCAP, WholeDocumentCullRect) {
GetDocument().GetSettings()->SetMainFrameClipsContent(false);
SetBodyInnerHTML(R"HTML(
<style>
@@ -1100,7 +1102,7 @@ TEST_P(PaintLayerPainterTestSPv2, WholeDocumentCullRect) {
kBackgroundType)));
}
-TEST_P(PaintLayerPainterTestSPv2, VerticalRightLeftWritingModeDocument) {
+TEST_P(PaintLayerPainterTestCAP, VerticalRightLeftWritingModeDocument) {
SetBodyInnerHTML(R"HTML(
<style>
html { writing-mode: vertical-rl; }
@@ -1121,7 +1123,7 @@ TEST_P(PaintLayerPainterTestSPv2, VerticalRightLeftWritingModeDocument) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, ScaledCullRect) {
+TEST_P(PaintLayerPainterTestCAP, ScaledCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
transform: scaleX(2) scaleY(0.5)'>
@@ -1134,7 +1136,7 @@ TEST_P(PaintLayerPainterTestSPv2, ScaledCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, ScaledAndRotatedCullRect) {
+TEST_P(PaintLayerPainterTestCAP, ScaledAndRotatedCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
transform: scaleX(2) scaleY(0.5) rotateZ(45deg)'>
@@ -1147,7 +1149,7 @@ TEST_P(PaintLayerPainterTestSPv2, ScaledAndRotatedCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, 3DRotated90DegreesCullRect) {
+TEST_P(PaintLayerPainterTestCAP, 3DRotated90DegreesCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
transform: rotateY(90deg)'>
@@ -1161,7 +1163,7 @@ TEST_P(PaintLayerPainterTestSPv2, 3DRotated90DegreesCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, 3DRotatedNear90DegreesCullRect) {
+TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
transform: rotateY(89.9999deg)'>
@@ -1177,7 +1179,7 @@ TEST_P(PaintLayerPainterTestSPv2, 3DRotatedNear90DegreesCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, PerspectiveCullRect) {
+TEST_P(PaintLayerPainterTestCAP, PerspectiveCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target'
style='width: 100px; height: 100px; transform: perspective(1000px)'>
@@ -1189,7 +1191,7 @@ TEST_P(PaintLayerPainterTestSPv2, PerspectiveCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().IsInfinite());
}
-TEST_P(PaintLayerPainterTestSPv2, 3D45DegRotatedTallCullRect) {
+TEST_P(PaintLayerPainterTestCAP, 3D45DegRotatedTallCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target'
style='width: 200px; height: 10000px; transform: rotateY(45deg)'>
@@ -1201,7 +1203,7 @@ TEST_P(PaintLayerPainterTestSPv2, 3D45DegRotatedTallCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().IsInfinite());
}
-TEST_P(PaintLayerPainterTestSPv2, FixedPositionCullRect) {
+TEST_P(PaintLayerPainterTestCAP, FixedPositionCullRect) {
SetBodyInnerHTML(R"HTML(
<div id='target' style='width: 1000px; height: 2000px;
position: fixed; top: 100px; left: 200px;'>
@@ -1212,7 +1214,7 @@ TEST_P(PaintLayerPainterTestSPv2, FixedPositionCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, LayerOffscreenNearCullRect) {
+TEST_P(PaintLayerPainterTestCAP, LayerOffscreenNearCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
position: absolute; top: 3000px; left: 0px;'>
@@ -1224,7 +1226,7 @@ TEST_P(PaintLayerPainterTestSPv2, LayerOffscreenNearCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, LayerOffscreenFarCullRect) {
+TEST_P(PaintLayerPainterTestCAP, LayerOffscreenFarCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
position: absolute; top: 9000px'>
@@ -1237,7 +1239,7 @@ TEST_P(PaintLayerPainterTestSPv2, LayerOffscreenFarCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, ScrollingLayerCullRect) {
+TEST_P(PaintLayerPainterTestCAP, ScrollingLayerCullRect) {
SetBodyInnerHTML(R"HTML(
<style>
div::-webkit-scrollbar { width: 5px; }
@@ -1258,7 +1260,7 @@ TEST_P(PaintLayerPainterTestSPv2, ScrollingLayerCullRect) {
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
}
-TEST_P(PaintLayerPainterTestSPv2, ClippedBigLayer) {
+TEST_P(PaintLayerPainterTestCAP, ClippedBigLayer) {
SetBodyInnerHTML(R"HTML(
<div style='width: 1px; height: 1px; overflow: hidden'>
<div id='target'
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc
index 2587cb77fa2..a6149011498 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc
@@ -50,9 +50,6 @@ void PaintLayerResourceInfo::ResourceContentChanged(InvalidationModeMask) {
// to update these properties when filter resources change.
layout_object.SetNeedsPaintPropertyUpdate();
layer_->SetFilterOnEffectNodeDirty();
- const ComputedStyle& style = layout_object.StyleRef();
- if (style.HasFilter() && style.Filter().HasReferenceFilter())
- InvalidateFilterChain();
}
void PaintLayerResourceInfo::ResourceElementChanged() {
@@ -64,26 +61,6 @@ void PaintLayerResourceInfo::ResourceElementChanged() {
// to update these properties when filter resources change.
layout_object.SetNeedsPaintPropertyUpdate();
layer_->SetFilterOnEffectNodeDirty();
- const ComputedStyle& style = layout_object.StyleRef();
- if (style.HasFilter() && style.Filter().HasReferenceFilter())
- InvalidateFilterChain();
-}
-
-void PaintLayerResourceInfo::SetLastEffect(FilterEffect* last_effect) {
- last_effect_ = last_effect;
-}
-
-FilterEffect* PaintLayerResourceInfo::LastEffect() const {
- return last_effect_;
-}
-
-void PaintLayerResourceInfo::InvalidateFilterChain() {
- last_effect_ = nullptr;
-}
-
-void PaintLayerResourceInfo::Trace(blink::Visitor* visitor) {
- visitor->Trace(last_effect_);
- SVGResourceClient::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h
index 2b7a0998399..9de93eca472 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h
@@ -32,6 +32,7 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
@@ -57,21 +58,20 @@ class PaintLayerResourceInfo final
explicit PaintLayerResourceInfo(PaintLayer*);
~PaintLayerResourceInfo() override;
- void SetLastEffect(FilterEffect*);
- FilterEffect* LastEffect() const;
- void InvalidateFilterChain();
+ FloatRect FilterReferenceBox() const { return filter_reference_box_; }
+ void SetFilterReferenceBox(const FloatRect& rect) {
+ filter_reference_box_ = rect;
+ }
void ClearLayer() { layer_ = nullptr; }
void ResourceContentChanged(InvalidationModeMask) override;
void ResourceElementChanged() override;
- void Trace(blink::Visitor*) override;
-
private:
- // |clearLayer| must be called before *m_layer becomes invalid.
+ // |ClearLayer| must be called before *layer_ becomes invalid.
PaintLayer* layer_;
- Member<FilterEffect> last_effect_;
+ FloatRect filter_reference_box_;
DISALLOW_COPY_AND_ASSIGN(PaintLayerResourceInfo);
};
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 5d9cb4586e2..d9d5c3c4c6e 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -80,6 +80,7 @@
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
@@ -487,10 +488,12 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
}
}
+ if (FragmentAnchor* anchor = frame_view->GetFragmentAnchor())
+ anchor->DidScroll(scroll_type);
+
if (IsExplicitScrollType(scroll_type)) {
if (scroll_type != kCompositorScroll)
ShowOverlayScrollbars();
- frame_view->ClearFragmentAnchor();
GetScrollAnchor()->Clear();
}
@@ -520,7 +523,7 @@ void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
// If not composited, background always paints into the main graphics layer.
bool background_paint_in_graphics_layer = true;
bool background_paint_in_scrolling_contents = false;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
UsesCompositedScrolling()) {
auto background_paint_location = box->GetBackgroundPaintLocation();
background_paint_in_graphics_layer =
@@ -545,7 +548,7 @@ void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
// scrollers, this will be taken care of by the interest rect computation
// in CompositedLayerMapping.
// TODO(wangxianzhu): replace this shortcut with interest rects.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
!UsesCompositedScrolling())
Layer()->SetNeedsRepaint();
}
@@ -832,7 +835,7 @@ void PaintLayerScrollableArea::UpdateScrollOrigin() {
LayoutRect scrollable_overflow(overflow_rect_);
scrollable_overflow.Move(-GetLayoutBox()->BorderLeft(),
-GetLayoutBox()->BorderTop());
- IntPoint new_origin(-scrollable_overflow.PixelSnappedLocation() +
+ IntPoint new_origin(FlooredIntPoint(-scrollable_overflow.Location()) +
GetLayoutBox()->OriginAdjustmentForScrollbars());
if (new_origin != scroll_origin_)
scroll_origin_changed_ = true;
@@ -1626,9 +1629,9 @@ void PaintLayerScrollableArea::SnapAfterScrollbarScrolling(
if (!snap_coordinator)
return;
- snap_coordinator->SnapForEndPosition(*GetLayoutBox(),
- orientation == kHorizontalScrollbar,
- orientation == kVerticalScrollbar);
+ snap_coordinator->SnapAtCurrentPosition(*GetLayoutBox(),
+ orientation == kHorizontalScrollbar,
+ orientation == kVerticalScrollbar);
}
void PaintLayerScrollableArea::PositionOverflowControls() {
@@ -1827,7 +1830,7 @@ void PaintLayerScrollableArea::UpdateResizerAreaSet() {
void PaintLayerScrollableArea::UpdateResizerStyle(
const ComputedStyle* old_style) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && old_style &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && old_style &&
old_style->Resize() != GetLayoutBox()->StyleRef().Resize()) {
// Invalidate the composited scroll corner layer on resize style change.
if (auto* graphics_layer = LayerForScrollCorner())
@@ -2156,12 +2159,21 @@ void PaintLayerScrollableArea::UpdateCompositingLayersAfterScroll() {
DCHECK(Layer()->HasCompositedLayerMapping());
ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator();
bool handled_scroll =
- Layer()->IsRootLayer() && scrolling_coordinator &&
+ (Layer()->IsRootLayer() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) &&
+ scrolling_coordinator &&
scrolling_coordinator->UpdateCompositedScrollOffset(this);
if (!handled_scroll) {
- Layer()->GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
- kGraphicsLayerUpdateSubtree);
+ if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ // In non-BGPT mode, we need to do a full sub-tree update here, because
+ // we need to update the position property to compute
+ // offset_to_transform_parent. For more context, see the comment from
+ // chrishtr@ here:
+ // https://chromium-review.googlesource.com/c/chromium/src/+/1403639/6/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+ Layer()->GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
+ kGraphicsLayerUpdateSubtree);
+ }
compositor->SetNeedsCompositingUpdate(
kCompositingUpdateAfterGeometryChange);
}
@@ -2682,7 +2694,7 @@ static LayoutRect InvalidatePaintOfScrollbarIfNeeded(
// container to ensure newly expanded/shrunk areas of the box to be
// invalidated.
needs_paint_invalidation = false;
- DCHECK(!graphics_layer->DrawsContent() ||
+ DCHECK(!graphics_layer->PaintsContentOrHitTest() ||
graphics_layer->GetPaintController().GetPaintArtifact().IsEmpty());
}
@@ -2847,15 +2859,15 @@ LayoutRect
PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::VisualRect()
const {
const auto* box = scrollable_area_->GetLayoutBox();
- auto overflow_clip_rect = box->OverflowClipRect(LayoutPoint());
- auto scroll_size = scrollable_area_->overflow_rect_.Size();
+ const auto& paint_offset = box->FirstFragment().PaintOffset();
+ auto overflow_clip_rect =
+ PixelSnappedIntRect(box->OverflowClipRect(paint_offset));
+ auto scroll_size = scrollable_area_->PixelSnappedContentsSize(paint_offset);
// Ensure scrolling contents are at least as large as the scroll clip
scroll_size = scroll_size.ExpandedTo(overflow_clip_rect.Size());
LayoutRect result(overflow_clip_rect.Location(), scroll_size);
- result.MoveBy(box->FirstFragment().PaintOffset());
- result = LayoutRect(PixelSnappedIntRect(result));
#if DCHECK_IS_ON()
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
DCHECK_EQ(result,
scrollable_area_->layer_->GraphicsLayerBacking()->VisualRect());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index 5a3f1d6c312..fc4a1d509d5 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -35,7 +35,8 @@ class PaintLayerScrollableAreaTestBase : public RenderingTest {
public:
PaintLayerScrollableAreaTestBase()
: RenderingTest(EmptyLocalFrameClient::Create()),
- chrome_client_(new ScrollableAreaMockChromeClient) {}
+ chrome_client_(MakeGarbageCollected<ScrollableAreaMockChromeClient>()) {
+ }
~PaintLayerScrollableAreaTestBase() override {
testing::Mock::VerifyAndClearExpectations(&GetChromeClient());
@@ -856,7 +857,7 @@ TEST_P(PaintLayerScrollableAreaTest,
// Programmatically changing the scroll offset.
scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// No invalidation because the background paints into scrolling contents.
EXPECT_FALSE(scroller->ShouldDoFullPaintInvalidation());
EXPECT_FALSE(scroller->BackgroundNeedsFullPaintInvalidation());
@@ -937,15 +938,8 @@ TEST_P(PaintLayerScrollableAreaTest, ViewScrollWithFixedAttachmentBackground) {
EXPECT_TRUE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_FALSE(fixed_background_div->NeedsPaintPropertyUpdate());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // In SPv2, we assume the view's fixed attachment background is composited
- // at this time and doesn't need paint invalidation on view scroll.
- EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
- EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
- } else {
- EXPECT_TRUE(GetLayoutView().ShouldDoFullPaintInvalidation());
- EXPECT_TRUE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
- }
+ EXPECT_TRUE(GetLayoutView().ShouldDoFullPaintInvalidation());
+ EXPECT_TRUE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
UpdateAllLifecyclePhasesForTest();
@@ -1018,7 +1012,7 @@ TEST_P(PaintLayerScrollableAreaTest, CompositedStickyDescendant) {
auto* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
auto* scrollable_area = scroller->GetScrollableArea();
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_EQ(kPaintsIntoOwnBacking, scroller->Layer()->GetCompositingState());
auto* sticky = ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"));
@@ -1087,4 +1081,75 @@ TEST_P(PaintLayerScrollableAreaTest, ScrollbarMaximum) {
EXPECT_EQ(scrollbar->CurrentPos(), scrollbar->Maximum());
}
+TEST_P(PaintLayerScrollableAreaTest, ScrollingBackgroundDisplayItemClient) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ ::-webkit-scrollbar { display: none; }
+ #scroller {
+ width: 100.7px;
+ height: 100.4px;
+ overflow: scroll;
+ border-top: 2.6px solid blue;
+ border-left: 2.4px solid blue;
+ will-change: transform;
+ }
+ #content {
+ width: 50.7px;
+ height: 200.4px;
+ }
+ </style>
+ <div id="scroller">
+ <div id="content"></div>
+ </div>
+ )HTML");
+
+ EXPECT_EQ(LayoutRect(2, 3, 101, 200),
+ ToLayoutBox(GetLayoutObjectByElementId("scroller"))
+ ->GetScrollableArea()
+ ->GetScrollingBackgroundDisplayItemClient()
+ .VisualRect());
+}
+
+TEST_P(PaintLayerScrollableAreaTest, RtlScrollOriginSnapping) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #container {
+ direction: rtl;
+ display: flex;
+ }
+ #scroller {
+ width: 100%;
+ height: 100px;
+ overflow: hidden;
+ }
+ #scroller-content {
+ width: 200%;
+ height: 200px;
+ }
+ </style>
+ <div id="container">
+ <div id="first-child" style="flex:1; display:none"></div>
+ <div style="flex:2.2">
+ <div id="scroller">
+ <div id ="scroller-content"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ // Test that scroll origin is snapped such that maximum scroll offset is
+ // always zero for an rtl block.
+
+ GetFrame().View()->Resize(795, 600);
+ UpdateAllLifecyclePhasesForTest();
+ LayoutBox* scroller = ToLayoutBox(GetLayoutObjectByElementId("scroller"));
+ PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+ EXPECT_EQ(scrollable_area->MaximumScrollOffsetInt(), IntSize(0, 100));
+
+ Element* first_child = GetElementById("first-child");
+ first_child->RemoveInlineStyleProperty(CSSPropertyDisplay);
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(scrollable_area->MaximumScrollOffsetInt(), IntSize(0, 100));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
index 115dc3c2ba2..cdb169b1c25 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -39,8 +39,8 @@ TEST_P(PaintLayerTest, ChildWithoutPaintLayer) {
}
TEST_P(PaintLayerTest, CompositedBoundsAbsPosGrandchild) {
- // BoundingBoxForCompositing is not used in SPv2 mode.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // BoundingBoxForCompositing is not used in CAP mode.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(
" <div id='parent'><div id='absposparent'><div id='absposchild'>"
@@ -61,8 +61,8 @@ TEST_P(PaintLayerTest, CompositedBoundsAbsPosGrandchild) {
}
TEST_P(PaintLayerTest, CompositedBoundsTransformedChild) {
- // TODO(chrishtr): fix this test for SPv2
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // TODO(chrishtr): fix this test for CAP
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -160,23 +160,6 @@ TEST_P(PaintLayerTest, ScrollsWithViewportFixedPositionInsideTransform) {
EXPECT_FALSE(layer->FixedToViewport());
}
-TEST_P(PaintLayerTest,
- ScrollsWithViewportFixedPositionInsideTransformNoScroll) {
- SetBodyInnerHTML(R"HTML(
- <div style='transform: translateZ(0)'>
- <div id='target' style='position: fixed'></div>
- </div>
- )HTML");
- PaintLayer* layer = GetPaintLayerByElementId("target");
-
- // In SPv2 mode, we correctly determine that the frame doesn't scroll at all,
- // and so return true.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
- EXPECT_TRUE(layer->FixedToViewport());
- else
- EXPECT_FALSE(layer->FixedToViewport());
-}
-
TEST_P(PaintLayerTest, SticksToScrollerStickyPosition) {
SetBodyInnerHTML(R"HTML(
<div style='transform: translateZ(0)'>
@@ -226,7 +209,7 @@ TEST_P(PaintLayerTest, SticksToScrollerStickyPositionInsideScroller) {
}
TEST_P(PaintLayerTest, CompositedScrollingNoNeedsRepaint) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -254,10 +237,10 @@ TEST_P(PaintLayerTest, CompositedScrollingNoNeedsRepaint) {
}
TEST_P(PaintLayerTest, NonCompositedScrollingNeedsRepaint) {
- // SPV2 scrolling raster invalidation decisions are made in
+ // CAP scrolling raster invalidation decisions are made in
// ContentLayerClientImpl::GenerateRasterInvalidations through
// PaintArtifactCompositor.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -779,7 +762,7 @@ TEST_P(PaintLayerTest, DescendantDependentFlagsStopsAtThrottledFrames) {
}
TEST_P(PaintLayerTest, PaintInvalidationOnNonCompositedScroll) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -854,8 +837,8 @@ TEST_P(PaintLayerTest, CompositingContainerStackedFloatUnderStackingInline) {
EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -879,8 +862,8 @@ TEST_P(PaintLayerTest,
EXPECT_EQ(span, target->CompositingContainer());
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(span,
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -899,12 +882,16 @@ TEST_P(PaintLayerTest, CompositingContainerNonStackedFloatUnderStackingInline) {
)HTML");
PaintLayer* target = GetPaintLayerByElementId("target");
- EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
- target->CompositingContainer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+ target->CompositingContainer());
+ }
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -924,14 +911,23 @@ TEST_P(PaintLayerTest,
)HTML");
PaintLayer* target = GetPaintLayerByElementId("target");
- EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
- target->CompositingContainer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+ target->CompositingContainer());
+ }
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
- target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"),
+ target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
+ target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+ }
}
}
@@ -954,8 +950,8 @@ TEST_P(PaintLayerTest,
EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -981,8 +977,8 @@ TEST_P(PaintLayerTest,
EXPECT_EQ(span, target->CompositingContainer());
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(span,
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -1004,12 +1000,16 @@ TEST_P(PaintLayerTest,
)HTML");
PaintLayer* target = GetPaintLayerByElementId("target");
- EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
- target->CompositingContainer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+ target->CompositingContainer());
+ }
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -1031,14 +1031,23 @@ TEST_P(PaintLayerTest,
)HTML");
PaintLayer* target = GetPaintLayerByElementId("target");
- EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
- target->CompositingContainer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+ target->CompositingContainer());
+ }
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
- target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"),
+ target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
+ target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+ }
}
}
@@ -1064,20 +1073,35 @@ TEST_P(PaintLayerTest, FloatLayerAndAbsoluteUnderInlineLayer) {
PaintLayer* container = GetPaintLayerByElementId("container");
EXPECT_EQ(span, floating->Parent());
- EXPECT_EQ(container, floating->ContainingLayer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span, floating->ContainingLayer());
+ } else {
+ EXPECT_EQ(container, floating->ContainingLayer());
+ }
EXPECT_EQ(span, absolute->Parent());
EXPECT_EQ(span, absolute->ContainingLayer());
EXPECT_EQ(container, span->Parent());
EXPECT_EQ(container, span->ContainingLayer());
- EXPECT_EQ(LayoutPoint(83, 83), floating->Location());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(50, 50), floating->Location());
+ } else {
+ EXPECT_EQ(LayoutPoint(83, 83), floating->Location());
+ }
EXPECT_EQ(LayoutPoint(50, 50), absolute->Location());
EXPECT_EQ(LayoutPoint(133, 133), span->Location());
EXPECT_EQ(LayoutPoint(20, 20), container->Location());
- EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(50, 50), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(183, 183),
+ floating->VisualOffsetFromAncestor(container));
+ } else {
+ EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(83, 83),
+ floating->VisualOffsetFromAncestor(container));
+ }
EXPECT_EQ(LayoutPoint(50, 50), absolute->VisualOffsetFromAncestor(span));
- EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(container));
EXPECT_EQ(LayoutPoint(183, 183),
absolute->VisualOffsetFromAncestor(container));
}
@@ -1101,16 +1125,26 @@ TEST_P(PaintLayerTest, FloatLayerUnderInlineLayerScrolled) {
kProgrammaticScroll);
EXPECT_EQ(span, floating->Parent());
- EXPECT_EQ(container, floating->ContainingLayer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span, floating->ContainingLayer());
+ } else {
+ EXPECT_EQ(container, floating->ContainingLayer());
+ }
EXPECT_EQ(container, span->Parent());
EXPECT_EQ(container, span->ContainingLayer());
- EXPECT_EQ(LayoutPoint(50, -350), floating->Location());
EXPECT_EQ(LayoutPoint(100, -300), span->Location());
-
- EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
- EXPECT_EQ(LayoutPoint(50, -350),
- floating->VisualOffsetFromAncestor(container));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(50, 50), floating->Location());
+ EXPECT_EQ(LayoutPoint(50, 50), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(150, -250),
+ floating->VisualOffsetFromAncestor(container));
+ } else {
+ EXPECT_EQ(LayoutPoint(50, -350), floating->Location());
+ EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(50, -350),
+ floating->VisualOffsetFromAncestor(container));
+ }
}
TEST_P(PaintLayerTest, FloatLayerUnderBlockUnderInlineLayer) {
@@ -1154,13 +1188,24 @@ TEST_P(PaintLayerTest, FloatLayerUnderFloatUnderInlineLayer) {
PaintLayer* span = GetPaintLayerByElementId("span");
EXPECT_EQ(span, floating->Parent());
- EXPECT_EQ(span->Parent(), floating->ContainingLayer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span, floating->ContainingLayer());
+ } else {
+ EXPECT_EQ(span->Parent(), floating->ContainingLayer());
+ }
EXPECT_EQ(LayoutPoint(83, 83), floating->Location());
EXPECT_EQ(LayoutPoint(100, 100), span->Location());
- EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
- EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
- GetDocument().GetLayoutView()->Layer()));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(183, 183),
+ floating->VisualOffsetFromAncestor(
+ GetDocument().GetLayoutView()->Layer()));
+ } else {
+ EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
+ GetDocument().GetLayoutView()->Layer()));
+ }
}
TEST_P(PaintLayerTest, FloatLayerUnderFloatLayerUnderInlineLayer) {
@@ -1183,16 +1228,29 @@ TEST_P(PaintLayerTest, FloatLayerUnderFloatLayerUnderInlineLayer) {
EXPECT_EQ(floating_parent, floating->Parent());
EXPECT_EQ(floating_parent, floating->ContainingLayer());
EXPECT_EQ(span, floating_parent->Parent());
- EXPECT_EQ(span->Parent(), floating_parent->ContainingLayer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span, floating_parent->ContainingLayer());
+ } else {
+ EXPECT_EQ(span->Parent(), floating_parent->ContainingLayer());
+ }
EXPECT_EQ(LayoutPoint(50, 50), floating->Location());
EXPECT_EQ(LayoutPoint(33, 33), floating_parent->Location());
EXPECT_EQ(LayoutPoint(100, 100), span->Location());
- EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
- EXPECT_EQ(LayoutPoint(-67, -67),
- floating_parent->VisualOffsetFromAncestor(span));
- EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
- GetDocument().GetLayoutView()->Layer()));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(33, 33),
+ floating_parent->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(183, 183),
+ floating->VisualOffsetFromAncestor(
+ GetDocument().GetLayoutView()->Layer()));
+ } else {
+ EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(-67, -67),
+ floating_parent->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
+ GetDocument().GetLayoutView()->Layer()));
+ }
}
TEST_P(PaintLayerTest, LayerUnderFloatUnderInlineLayer) {
@@ -1212,13 +1270,25 @@ TEST_P(PaintLayerTest, LayerUnderFloatUnderInlineLayer) {
PaintLayer* span = GetPaintLayerByElementId("span");
EXPECT_EQ(span, child->Parent());
- EXPECT_EQ(span->Parent(), child->ContainingLayer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span, child->ContainingLayer());
+ } else {
+ EXPECT_EQ(span->Parent(), child->ContainingLayer());
+ }
EXPECT_EQ(LayoutPoint(83, 83), child->Location());
EXPECT_EQ(LayoutPoint(100, 100), span->Location());
- EXPECT_EQ(LayoutPoint(-17, -17), child->VisualOffsetFromAncestor(span));
- EXPECT_EQ(LayoutPoint(83, 83), child->VisualOffsetFromAncestor(
- GetDocument().GetLayoutView()->Layer()));
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(83, 83), child->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(183, 183),
+ child->VisualOffsetFromAncestor(
+ GetDocument().GetLayoutView()->Layer()));
+
+ } else {
+ EXPECT_EQ(LayoutPoint(-17, -17), child->VisualOffsetFromAncestor(span));
+ EXPECT_EQ(LayoutPoint(83, 83), child->VisualOffsetFromAncestor(
+ GetDocument().GetLayoutView()->Layer()));
+ }
}
TEST_P(PaintLayerTest, CompositingContainerFloatingIframe) {
@@ -1240,14 +1310,18 @@ TEST_P(PaintLayerTest, CompositingContainerFloatingIframe) {
// A non-positioned iframe still gets a PaintLayer because PaintLayers are
// forced for all LayoutEmbeddedContent objects. However, such PaintLayers are
// not stacked.
- PaintLayer* containing_block = GetPaintLayerByElementId("containingBlock");
- EXPECT_EQ(containing_block, target->CompositingContainer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+ } else {
+ EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+ target->CompositingContainer());
+ }
PaintLayer* composited_container =
GetPaintLayerByElementId("compositedContainer");
// enclosingLayerWithCompositedLayerMapping is not needed or applicable to
- // SPv2.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // CAP.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(composited_container,
target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
}
@@ -1269,7 +1343,11 @@ TEST_P(PaintLayerTest, CompositingContainerSelfPaintingNonStackedFloat) {
PaintLayer* container = GetPaintLayerByElementId("container");
PaintLayer* span = GetPaintLayerByElementId("span");
- EXPECT_EQ(container, target->ContainingLayer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span, target->ContainingLayer());
+ } else {
+ EXPECT_EQ(container, target->ContainingLayer());
+ }
EXPECT_EQ(span, target->CompositingContainer());
}
@@ -1352,7 +1430,11 @@ TEST_P(PaintLayerTest, NeedsRepaintOnSelfPaintingStatusChange) {
"overflow: hidden; float: left");
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
EXPECT_FALSE(target_layer->IsSelfPaintingLayer());
- EXPECT_EQ(span_layer->Parent(), target_layer->CompositingContainer());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(span_layer, target_layer->CompositingContainer());
+ } else {
+ EXPECT_EQ(span_layer->Parent(), target_layer->CompositingContainer());
+ }
EXPECT_TRUE(target_layer->NeedsRepaint());
EXPECT_TRUE(target_layer->CompositingContainer()->NeedsRepaint());
EXPECT_TRUE(span_layer->NeedsRepaint());
@@ -1452,7 +1534,7 @@ TEST_P(PaintLayerTest, FragmentedHitTest) {
}
TEST_P(PaintLayerTest, SquashingOffsets) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetHtmlInnerHTML(R"HTML(
<style>
@@ -1759,7 +1841,8 @@ TEST_P(PaintLayerTest, BackgroundIsKnownToBeOpaqueInRectChildren) {
LayoutRect(0, 0, 100, 100), false));
}
-TEST_P(PaintLayerTest, ChangeAlphaNeedsCompositingInputs) {
+TEST_P(PaintLayerTest,
+ ChangeAlphaNeedsCompositingInputsAndPaintPropertyUpdate) {
SetBodyInnerHTML(R"HTML(
<style>
#target {
@@ -1773,10 +1856,20 @@ TEST_P(PaintLayerTest, ChangeAlphaNeedsCompositingInputs) {
</div>
)HTML");
PaintLayer* target = GetPaintLayerByElementId("target");
+ EXPECT_FALSE(target->NeedsCompositingInputsUpdate());
+ EXPECT_FALSE(target->GetLayoutObject().NeedsPaintPropertyUpdate());
+ EXPECT_FALSE(target->Parent()->GetLayoutObject().NeedsPaintPropertyUpdate());
+
StyleDifference diff;
diff.SetHasAlphaChanged();
target->StyleDidChange(diff, target->GetLayoutObject().Style());
- EXPECT_TRUE(target->NeedsCompositingInputsUpdate());
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ EXPECT_FALSE(target->NeedsCompositingInputsUpdate());
+ else
+ EXPECT_TRUE(target->NeedsCompositingInputsUpdate());
+ EXPECT_TRUE(target->GetLayoutObject().NeedsPaintPropertyUpdate());
+ // See the TODO in PaintLayer::SetNeedsCompositingInputsUpdate().
+ EXPECT_TRUE(target->Parent()->GetLayoutObject().NeedsPaintPropertyUpdate());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 1c65f407cff..11a7196cd65 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -212,10 +212,28 @@ class FragmentPaintPropertyTreeBuilder {
full_context_.clip_changed |=
!(result.Unchanged() || only_updated_hit_test_values);
}
+ // Like |OnUpdate| but forces a piercing subtree update if the scroll tree
+ // hierarchy changes because the scroll tree does not have isolation nodes
+ // and non-piercing updates can fail to update scroll descendants.
+ void OnUpdateScroll(const ObjectPaintProperties::UpdateResult& result) {
+ OnUpdate(result);
+ if (result.NewNodeCreated()) {
+ full_context_.force_subtree_update_reasons |=
+ PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationPiercing;
+ }
+ }
void OnClear(bool cleared) {
property_added_or_removed_ |= cleared;
property_changed_ |= cleared;
}
+ // See: |OnUpdateScroll|.
+ void OnClearScroll(bool cleared) {
+ OnClear(cleared);
+ if (cleared) {
+ full_context_.force_subtree_update_reasons |=
+ PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationPiercing;
+ }
+ }
void OnClearClip(bool cleared) {
OnClear(cleared);
full_context_.clip_changed |= cleared;
@@ -252,10 +270,10 @@ static bool NeedsScrollNode(const LayoutObject& object) {
if (!object.HasOverflowClip())
return false;
const LayoutBox& box = ToLayoutBox(object);
- // TODO(pdr): SPV2 has invalidation issues (crbug.com/732611) as well as
+ // TODO(pdr): CAP has invalidation issues (crbug.com/732611) as well as
// subpixel issues (crbug.com/693741) which prevent us from compositing the
// root scroller.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return HasScrollsOverflow(box);
return HasScrollsOverflow(box) || IsRootScroller(box);
}
@@ -293,7 +311,7 @@ static bool NeedsReplacedContentTransform(const LayoutObject& object) {
// to the object-fit box. Note that we don't actually know whether the image
// will be directly composited. This condition is relaxed to stay on the
// safe side.
- // TODO(crbug.com/875110): Figure out the condition for SPv2.
+ // TODO(crbug.com/875110): Figure out the condition for CAP.
bool is_spv1_composited =
object.HasLayer() &&
ToLayoutBoxModelObject(object).Layer()->GetCompositedLayerMapping();
@@ -317,13 +335,16 @@ static bool NeedsIsolationNodes(const LayoutObject& object) {
return false;
// Paint containment establishes isolation.
- if (object.ShouldApplyPaintContainment())
+ // Style & Layout containment also establish isolation.
+ if (object.ShouldApplyPaintContainment() ||
+ (object.ShouldApplyStyleContainment() &&
+ object.ShouldApplyLayoutContainment())) {
return true;
+ }
// Layout view establishes isolation with the exception of local roots (since
// they are already essentially isolated).
- if (RuntimeEnabledFeatures::LayoutViewIsolationNodesEnabled() &&
- object.IsLayoutView()) {
+ if (object.IsLayoutView()) {
const auto* parent_frame = object.GetFrame()->Tree().Parent();
return parent_frame && parent_frame->IsLocalFrame();
}
@@ -381,9 +402,9 @@ static bool NeedsPaintOffsetTranslation(const LayoutObject& object) {
// unnecessary full layer paint/raster invalidation when paint offset in
// ancestor transform node changes which should not affect the descendants
// of the composited layer.
- // TODO(wangxianzhu): For SPv2, we also need a avoid unnecessary paint/raster
+ // TODO(wangxianzhu): For CAP, we also need a avoid unnecessary paint/raster
// invalidation in composited layers when their paint offset changes.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
// For only LayoutBlocks that won't be escaped by floating objects and
// column spans when finding their containing blocks.
// TODO(crbug.com/780242): This can be avoided if we have fully correct
@@ -442,7 +463,7 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
object_.StyleRef().GetPosition() == EPosition::kFixed &&
object_.StyleRef().IsFixedToBottom();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
state.rendering_context_id = context_.current.rendering_context_id;
OnUpdate(properties_->UpdatePaintOffsetTranslation(
@@ -589,14 +610,21 @@ static CompositingReasons CompositingReasonsForTransform(const LayoutBox& box) {
if (CompositingReasonFinder::RequiresCompositingForTransform(box))
compositing_reasons |= CompositingReason::k3DTransform;
- // Currently, we create transform nodes for an element whenever any property
- // is being animated so that the existence of the effect node implies the
- // existence of all nodes.
- // TODO(flackr): Check for nodes for each KeyframeModel target
- // property instead of creating all nodes and only create a transform node
- // if needed, https://crbug.com/900241
- compositing_reasons |=
- CompositingReasonFinder::CompositingReasonsForAnimation(style);
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ // Currently, we create transform nodes for an element whenever any property
+ // is being animated so that the existence of the effect node implies the
+ // existence of all nodes.
+ // TODO(flackr): Check for nodes for each KeyframeModel target
+ // property instead of creating all nodes and only create a transform node
+ // if needed, https://crbug.com/900241
+ compositing_reasons |=
+ CompositingReasonFinder::CompositingReasonsForAnimation(style);
+ } else {
+ if (CompositingReasonFinder::RequiresCompositingForTransformAnimation(
+ style))
+ compositing_reasons |= CompositingReason::kActiveTransformAnimation;
+ }
if (style.HasWillChangeCompositingHint() &&
!style.SubtreeWillChangeContents())
@@ -625,7 +653,7 @@ static FloatPoint3D TransformOrigin(const LayoutBox& box) {
}
static bool NeedsTransform(const LayoutObject& object) {
- if ((RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if ((RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) &&
object.StyleRef().BackfaceVisibility() == EBackfaceVisibility::kHidden)
return true;
@@ -662,7 +690,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
// TODO(trchen): transform-style should only be respected if a
// PaintLayer is created. If a node with transform-style: preserve-3d
@@ -681,7 +709,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
state.flattens_inherited_transform =
context_.current.should_flatten_inherited_transform;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
state.backface_visibility =
object_.HasHiddenBackface()
@@ -783,8 +811,14 @@ static bool NeedsEffect(const LayoutObject& object) {
// TODO(flackr): Check for nodes for each KeyframeModel target
// property instead of creating all nodes and only create an effect node
// if needed, https://crbug.com/900241
- if (CompositingReasonFinder::CompositingReasonsForAnimation(style))
- return true;
+ if ((RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())) {
+ if (CompositingReasonFinder::CompositingReasonsForAnimation(style))
+ return true;
+ } else {
+ if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(style))
+ return true;
+ }
if (object.StyleRef().HasMask())
return true;
@@ -828,6 +862,8 @@ bool FragmentPaintPropertyTreeBuilder::EffectCanUseCurrentClipAsOutputClip()
// Some descendants under a pagination container (e.g. composited objects
// in SPv1 and column spanners) may escape fragment clips.
+ // TODO(crbug.com/803649): Remove this when we fix fragment clip hierarchy
+ // issues.
if (layer->EnclosingPaginationLayer())
return false;
@@ -892,7 +928,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
state.blend_mode = WebCoreCompositeToSkiaComposite(
kCompositeSourceOver, style.GetBlendMode());
}
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
// We may begin to composite our subtree prior to an animation starts,
// but a compositor element ID is only needed when an animation is
@@ -926,7 +962,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
mask_state.output_clip = output_clip;
mask_state.color_filter = CSSMaskPainter::MaskColorFilter(object_);
mask_state.blend_mode = SkBlendMode::kDstIn;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
mask_state.compositor_element_id =
CompositorElementIdFromUniqueObjectId(
@@ -947,7 +983,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
clip_path_state.local_transform_space = context_.current.transform;
clip_path_state.output_clip = output_clip;
clip_path_state.blend_mode = SkBlendMode::kDstIn;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
clip_path_state.compositor_element_id =
CompositorElementIdFromUniqueObjectId(
@@ -982,46 +1018,68 @@ static bool NeedsLinkHighlightEffect(const LayoutObject& object) {
}
void FragmentPaintPropertyTreeBuilder::UpdateLinkHighlightEffect() {
- if (NeedsPaintPropertyUpdate()) {
- if (NeedsLinkHighlightEffect(object_)) {
- // While the link highlight uses the current transform space for
- // positioning, it's parent effect is the root so that it is not affected
- // by enclosing filters.
- const auto& parent = EffectPaintPropertyNode::Root();
- EffectPaintPropertyNode::State link_highlight_state;
- link_highlight_state.local_transform_space = context_.current.transform;
- link_highlight_state.compositor_element_id =
- object_.GetFrame()->GetPage()->GetLinkHighlights().element_id(
- object_);
- link_highlight_state.direct_compositing_reasons =
- CompositingReason::kActiveOpacityAnimation;
- // Unlike other property nodes, link highlight effect nodes are guaranteed
- // to be leaf nodes and do not require subtree invalidation, so we do not
- // call |OnUpdate| here.
- properties_->UpdateLinkHighlightEffect(parent,
- std::move(link_highlight_state));
- } else {
- // Unlike other property nodes, link highlight effect nodes are guaranteed
- // to be leaf nodes and do not require subtree invalidation, so we do not
- // call |OnClear| here.
- properties_->ClearLinkHighlightEffect();
- }
+ if (!NeedsPaintPropertyUpdate())
+ return;
+
+ DCHECK(properties_);
+
+ if (!NeedsLinkHighlightEffect(object_)) {
+ // Unlike other property nodes, link highlight effect nodes are guaranteed
+ // to be leaf nodes and do not require subtree invalidation, so we do not
+ // call |OnClear| here.
+ properties_->ClearLinkHighlightEffect();
+ return;
}
+
+ if (&fragment_data_ != &object_.FirstFragment()) {
+ // All fragments share the same LinkHighlightEffect node.
+ DCHECK(object_.FirstFragment().PaintProperties());
+ DCHECK(object_.FirstFragment().PaintProperties()->LinkHighlightEffect());
+ properties_->SetLinkHighlightEffect(
+ object_.FirstFragment().PaintProperties()->LinkHighlightEffect());
+ return;
+ }
+
+ // While the link highlight uses the current transform space for
+ // positioning, it's parent effect is the root so that it is not affected
+ // by enclosing filters.
+ const auto& parent = EffectPaintPropertyNode::Root();
+ EffectPaintPropertyNode::State link_highlight_state;
+ link_highlight_state.local_transform_space = context_.current.transform;
+ link_highlight_state.compositor_element_id =
+ object_.GetFrame()->GetPage()->GetLinkHighlights().element_id(object_);
+ link_highlight_state.direct_compositing_reasons =
+ CompositingReason::kActiveOpacityAnimation;
+ // Unlike other property nodes, link highlight effect nodes are guaranteed
+ // to be leaf nodes and do not require subtree invalidation, so we do not
+ // call |OnUpdate| here.
+ properties_->UpdateLinkHighlightEffect(parent,
+ std::move(link_highlight_state));
}
static bool NeedsFilter(const LayoutObject& object) {
// Currently, we create filter nodes for an element whenever any property
// is being animated so that the existence of the effect node implies the
// existence of all animation nodes.
+ if (!object.IsBoxModelObject() || !ToLayoutBoxModelObject(object).Layer())
+ return false;
+
+ // TODO(trchen): SVG caches filters in SVGResources. Implement it.
+ if (object.StyleRef().HasFilter() || object.HasReflection() ||
+ object.HasBackdropFilter())
+ return true;
+
// TODO(flackr): Check for nodes for each KeyframeModel target
// property instead of creating all nodes and only create a filter node
// if needed, https://crbug.com/900241
- // TODO(trchen): SVG caches filters in SVGResources. Implement it.
- return (object.IsBoxModelObject() && ToLayoutBoxModelObject(object).Layer() &&
- (object.StyleRef().HasFilter() || object.HasReflection() ||
- object.HasBackdropFilter() ||
- CompositingReasonFinder::CompositingReasonsForAnimation(
- object.StyleRef())));
+ bool needs_compositing_for_animation =
+ (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
+ ? CompositingReasonFinder::CompositingReasonsForAnimation(
+ object.StyleRef())
+ : CompositingReasonFinder::RequiresCompositingForFilterAnimation(
+ object.StyleRef());
+ return needs_compositing_for_animation;
}
void FragmentPaintPropertyTreeBuilder::UpdateFilter() {
@@ -1036,12 +1094,23 @@ void FragmentPaintPropertyTreeBuilder::UpdateFilter() {
if (auto* layer = ToLayoutBoxModelObject(object_).Layer()) {
// Try to use the cached filter.
- if (properties_->Filter())
+ if (properties_->Filter()) {
state.filter = properties_->Filter()->Filter();
+ state.backdrop_filter = properties_->Filter()->BackdropFilter();
+ state.backdrop_filter_bounds =
+ properties_->Filter()->BackdropFilterBounds();
+ }
+ // With BGPT disabled, UpdateFilterReferenceBox gets called from
+ // CompositedLayerMapping::UpdateGraphicsLayerGeometry, but only
+ // for composited layers.
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+ layer->GetCompositingState() != kPaintsIntoOwnBacking) {
+ layer->UpdateFilterReferenceBox();
+ }
layer->UpdateCompositorFilterOperationsForFilter(state.filter);
layer->UpdateCompositorFilterOperationsForBackdropFilter(
- state.backdrop_filter);
+ state.backdrop_filter, &state.backdrop_filter_bounds);
layer->ClearFilterOnEffectNodeDirty();
}
@@ -1069,7 +1138,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateFilter() {
// output pixel may depend on an input pixel outside of the output clip.
// We should generate a special clip node to represent this expansion.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
// We may begin to composite our subtree prior to an animation starts,
// but a compositor element ID is only needed when an animation is
@@ -1207,6 +1276,9 @@ static bool IsPrintingRootLayoutView(const LayoutObject& object) {
return !ToLocalFrame(parent_frame)->GetDocument()->Printing();
}
+// TODO(wangxianzhu): Combine the logic by overriding LayoutBox::
+// ComputeShouldClipOverflow() in LayoutReplaced and subclasses and remove
+// this function.
static bool NeedsOverflowClipForReplacedContents(
const LayoutReplaced& replaced) {
// <svg> may optionally allow overflow. If an overflow clip is required,
@@ -1214,18 +1286,17 @@ static bool NeedsOverflowClipForReplacedContents(
if (replaced.IsSVGRoot())
return ToLayoutSVGRoot(replaced).ShouldApplyViewportClip();
+ // A replaced element with border-radius always clips the content.
if (replaced.StyleRef().HasBorderRadius())
return true;
- // Non-composited images have a micro-optimization to embed clip rects into
- // the drawings instead of using a clip node.
- bool is_spv1_composited =
- replaced.HasLayer() && replaced.Layer()->GetCompositedLayerMapping();
- if (replaced.IsImage() && !is_spv1_composited)
+ // ImagePainter (but not painters for LayoutMedia whose IsImage is also true)
+ // won't paint outside of the content box.
+ if (replaced.IsImage() && !replaced.IsMedia())
return false;
- // Embedded objects are always sized to fit the content rect.
- if (replaced.IsLayoutEmbeddedContent())
+ // Non-plugin embedded contents are always sized to fit the content box.
+ if (replaced.IsLayoutEmbeddedContent() && !replaced.IsEmbeddedObject())
return false;
return true;
@@ -1368,12 +1439,6 @@ static bool CanOmitOverflowClip(const LayoutObject& object) {
return false;
const auto& block = ToLayoutBlock(object);
- // This is a heuristic to avoid costly paint property subtree rebuild on
- // CanOmitOverflowClip() changes, e.g. on selection. This also avoids omitting
- // overflow clip when there is any self-painting descendant which is not
- // covered by ContentsVisualOverflowRect().
- if (block.HasLayer() && block.Layer()->FirstChild())
- return false;
// Selection may overflow.
if (block.IsSelected())
return false;
@@ -1382,15 +1447,6 @@ static bool CanOmitOverflowClip(const LayoutObject& object) {
if (block.HasControlClip() || block.ShouldPaintCarets())
return false;
- if (object.IsLayoutReplaced()) {
- const LayoutReplaced& replaced = ToLayoutReplaced(object);
- if (replaced.StyleRef().HasBorderRadius())
- return false;
- LayoutRect replaced_content_rect = replaced.ReplacedContentRect();
- return replaced_content_rect.IsEmpty() ||
- replaced.PhysicalContentBoxRect().Contains(replaced_content_rect);
- }
-
// We need OverflowClip for hit-testing if the clip rect excluding overlay
// scrollbars is different from the normal clip rect.
auto clip_rect = block.OverflowClipRect(LayoutPoint());
@@ -1398,7 +1454,19 @@ static bool CanOmitOverflowClip(const LayoutObject& object) {
LayoutPoint(), kExcludeOverlayScrollbarSizeForHitTesting);
if (clip_rect != clip_rect_excluding_overlay_scrollbars)
return false;
- return clip_rect.Contains(block.ContentsVisualOverflowRect());
+
+ // Visual overflow extending beyond the clip rect must be clipped.
+ // ContentsVisualOverflowRect() does not include self-painting descendants
+ // (see comment above |BoxOverflowModel|) so, as a simplification, do not
+ // omit the clip if there are any PaintLayer descendants.
+ if (block.HasLayer() && block.Layer()->FirstChild())
+ return false;
+ if (!clip_rect.Contains(block.ContentsVisualOverflowRect()))
+ return false;
+
+ // Content can scroll, and needs to be clipped, if the layout overflow extends
+ // beyond the clip rect.
+ return clip_rect.Contains(block.LayoutOverflowRect());
}
void FragmentPaintPropertyTreeBuilder::UpdateOverflowClip() {
@@ -1442,7 +1510,6 @@ void FragmentPaintPropertyTreeBuilder::UpdateOverflowClip() {
viewport_container.LocalToSVGParentTransform().Inverse().MapRect(
viewport_container.Viewport()));
}
-
const ClipPaintPropertyNode* existing = properties_->OverflowClip();
bool equal_ignoring_hit_test_rects =
!!existing &&
@@ -1486,7 +1553,7 @@ void FragmentPaintPropertyTreeBuilder::UpdatePerspective() {
ToLayoutSize(context_.current.paint_offset);
state.flattens_inherited_transform =
context_.current.should_flatten_inherited_transform;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
state.rendering_context_id = context_.current.rendering_context_id;
OnUpdate(properties_->UpdatePerspective(*context_.current.transform,
@@ -1535,8 +1602,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateReplacedContentTransform() {
LayoutRect layout_replaced_rect = layout_image.ReplacedContentRect();
layout_replaced_rect.MoveBy(context_.current.paint_offset);
IntRect replaced_rect = PixelSnappedIntRect(layout_replaced_rect);
- scoped_refptr<Image> image = layout_image.ImageResource()->GetImage(
- LayoutSize(replaced_rect.Size()));
+ scoped_refptr<Image> image =
+ layout_image.ImageResource()->GetImage(replaced_rect.Size());
if (image && !image->IsNull()) {
IntRect src_rect = image->Rect();
if (ImageWasTransposed(layout_image, *image))
@@ -1575,18 +1642,62 @@ void FragmentPaintPropertyTreeBuilder::UpdateReplacedContentTransform() {
static MainThreadScrollingReasons GetMainThreadScrollingReasons(
const LayoutObject& object,
MainThreadScrollingReasons ancestor_reasons) {
- // The current main thread scrolling reasons implementation only changes
- // reasons at frame boundaries, so we can early-out when not at a LayoutView.
- // TODO(pdr): Need to find a solution to the style-related main thread
- // scrolling reasons such as opacity and transform which violate this.
- if (!object.IsLayoutView())
- return ancestor_reasons;
-
auto reasons = ancestor_reasons;
- if (!object.GetFrame()->GetSettings()->GetThreadedScrollingEnabled())
- reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled;
- if (object.GetFrameView()->HasBackgroundAttachmentFixedObjects())
- reasons |= MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
+ if (!object.IsBox())
+ return reasons;
+
+ if (auto* scrollable_area = ToLayoutBox(object).GetScrollableArea()) {
+ if (scrollable_area->HorizontalScrollbar() &&
+ scrollable_area->HorizontalScrollbar()->IsCustomScrollbar()) {
+ reasons |= MainThreadScrollingReason::kCustomScrollbarScrolling;
+ } else if (scrollable_area->VerticalScrollbar() &&
+ scrollable_area->VerticalScrollbar()->IsCustomScrollbar()) {
+ reasons |= MainThreadScrollingReason::kCustomScrollbarScrolling;
+ }
+ }
+
+ if (object.IsLayoutView()) {
+ if (object.GetFrameView()->HasBackgroundAttachmentFixedObjects()) {
+ reasons |=
+ MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
+ }
+
+ // TODO(pdr): This should apply to all scrollable areas, not just the
+ // viewport. This is not a user-visible bug because the threaded scrolling
+ // setting is only for testing.
+ if (!object.GetFrame()->GetSettings()->GetThreadedScrollingEnabled())
+ reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled;
+
+ // LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects depends
+ // on compositing (LayoutBoxModelObject::IsSlowRepaintConstrainedObject
+ // calls PaintLayer::GetCompositingState, and PaintLayer::SticksToScroller
+ // depends on the ancestor overflow layer) so CompositeAfterPaint cannot
+ // use LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects.
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // Force main-thread scrolling if the frame has uncomposited position:
+ // fixed elements. Note: we care about this not only for input-scrollable
+ // frames but also for overflow: hidden frames, because script can run
+ // composited smooth-scroll animations. For this reason, we use
+ // HasOverflow instead of ScrollsOverflow (which is false for overflow:
+ // hidden).
+ if (ToLayoutBox(object).GetScrollableArea()->HasOverflow() &&
+ object.StyleRef().VisibleToHitTesting() &&
+ object.GetFrameView()
+ ->HasVisibleSlowRepaintViewportConstrainedObjects()) {
+ reasons |=
+ MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects;
+ }
+ } else {
+ // TODO(pdr): CompositeAfterPaint should use an approach like
+ // CompositingReasonFinder::RequiresCompositingForScrollDependentPosition,
+ // adding main thread reasons if compositing was not required. This has
+ // a small behavior change because main thread reasons will be added in
+ // the case where a non-scroll compositing trigger (e.g., transform)
+ // requires compositing, even though a main thread reason is not needed.
+ // CompositingReasonFinder::RequiresCompositingForScrollDependentPosition
+ // will need to be changed to not query PaintLayer::AncestorOverflowLayer.
+ }
+ }
return reasons;
}
@@ -1628,7 +1739,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
}
}
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
state.compositor_element_id = scrollable_area->GetCompositorElementId();
@@ -1643,8 +1754,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
state.snap_container_data = snap_coordinator->GetSnapContainerData(box);
}
- OnUpdate(properties_->UpdateScroll(*context_.current.scroll,
- std::move(state)));
+ OnUpdateScroll(properties_->UpdateScroll(*context_.current.scroll,
+ std::move(state)));
if (scrollable_area->VerticalScrollbar() ||
scrollable_area->HasLayerForVerticalScrollbar()) {
@@ -1674,7 +1785,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
OnClear(properties_->ClearHorizontalScrollbarEffect());
}
} else {
- OnClear(properties_->ClearScroll());
+ OnClearScroll(properties_->ClearScroll());
OnClear(properties_->ClearVerticalScrollbarEffect());
OnClear(properties_->ClearHorizontalScrollbarEffect());
}
@@ -1692,7 +1803,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
context_.current.should_flatten_inherited_transform;
state.is_identity_or_2d_translation = true;
state.direct_compositing_reasons = CompositingReasonsForScroll(box);
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
state.rendering_context_id = context_.current.rendering_context_id;
}
@@ -1854,28 +1965,34 @@ static LayoutRect BoundingBoxInPaginationContainer(
&enclosing_pagination_layer);
}
- // Non-boxes paint in the space of their containing block.
- if (!object.IsBox()) {
- const LayoutBox& containining_block = *object.ContainingBlock();
- LayoutRect bounds_rect;
+ LayoutRect local_bounds;
+ const LayoutBox* local_space_object = nullptr;
+ if (object.IsBox()) {
+ local_space_object = ToLayoutBox(&object);
+ local_bounds = local_space_object->BorderBoxRect();
+ } else {
+ // Non-boxes paint in the space of their containing block.
+ local_space_object = object.ContainingBlock();
// For non-SVG we can get a more accurate result with LocalVisualRect,
// instead of falling back to the bounds of the enclosing block.
if (!object.IsSVG()) {
- bounds_rect = object.LocalVisualRect();
- containining_block.FlipForWritingMode(bounds_rect);
+ local_bounds = object.LocalVisualRect();
+ local_space_object->FlipForWritingMode(local_bounds);
} else {
- bounds_rect = LayoutRect(SVGLayoutSupport::LocalVisualRect(object));
+ local_bounds = LayoutRect(SVGLayoutSupport::LocalVisualRect(object));
}
+ }
- return MapLocalRectToAncestorLayer(containining_block, bounds_rect,
- enclosing_pagination_layer);
+ // The link highlight covers block visual overflows, continuations, etc. which
+ // may intersect with more fragments than the object itself.
+ if (NeedsLinkHighlightEffect(object)) {
+ local_bounds.Unite(UnionRect(object.PhysicalOutlineRects(
+ LayoutPoint(), NGOutlineType::kIncludeBlockVisualOverflow)));
}
// Compute the bounding box without transforms.
- // The object is guaranteed to be a box due to the logic above.
- const LayoutBox& box = ToLayoutBox(object);
- auto bounding_box = MapLocalRectToAncestorLayer(box, box.BorderBoxRect(),
- enclosing_pagination_layer);
+ auto bounding_box = MapLocalRectToAncestorLayer(
+ *local_space_object, local_bounds, enclosing_pagination_layer);
if (!IsRepeatingTableSection(object))
return bounding_box;
@@ -1966,7 +2083,7 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
return;
}
- if (object_.IsFloating())
+ if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
context_.current.paint_offset = context_.paint_offset_for_float;
// Multicolumn spanners are painted starting at the multicolumn container (but
@@ -2073,7 +2190,7 @@ void FragmentPaintPropertyTreeBuilder::SetNeedsPaintPropertyUpdateIfNeeded() {
return;
// CSS mask and clip-path comes with an implicit clip to the border box.
- // Currently only SPv2 generate and take advantage of those.
+ // Currently only CAP generate and take advantage of those.
const bool box_generates_property_nodes_for_mask_and_clip_path =
box.HasMask() || box.HasClipPath();
// The overflow clip paint property depends on the border box rect through
@@ -2267,17 +2384,29 @@ void PaintPropertyTreeBuilder::InitSingleFragmentFromParent(
// should also skip any fragment clip created by the skipped pagination
// container. We also need to skip fragment clip if the object is a paint
// invalidation container which doesn't allow fragmentation.
+ // TODO(crbug.com/803649): This may also skip necessary clips under the
+ // skipped fragment clip.
if (object_.IsColumnSpanAll() ||
- (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
object_.IsPaintInvalidationContainer() &&
ToLayoutBoxModelObject(object_).Layer()->EnclosingPaginationLayer())) {
if (const auto* pagination_layer_in_tree_hierarchy =
object_.Parent()->EnclosingLayer()->EnclosingPaginationLayer()) {
- const auto* properties =
- pagination_layer_in_tree_hierarchy->GetLayoutObject()
- .FirstFragment()
- .PaintProperties();
+ const auto& clip_container =
+ pagination_layer_in_tree_hierarchy->GetLayoutObject();
+ const auto* properties = clip_container.FirstFragment().PaintProperties();
if (properties && properties->FragmentClip()) {
+ // However, because we don't allow an object's clip to escape the
+ // output clip of the object's effect, we can't skip fragment clip if
+ // between this object and the container there is any effect that has
+ // an output clip. TODO(crbug.com/803649): Fix this workaround.
+ const auto* clip_container_effect =
+ clip_container.FirstFragment().PostIsolationEffect();
+ for (const auto* effect = context_.fragments[0].current_effect;
+ effect != clip_container_effect; effect = effect->Parent()) {
+ if (effect->OutputClip())
+ return;
+ }
context_.fragments[0].current.clip =
properties->FragmentClip()->Parent();
}
@@ -2286,7 +2415,7 @@ void PaintPropertyTreeBuilder::InitSingleFragmentFromParent(
}
void PaintPropertyTreeBuilder::UpdateCompositedLayerPaginationOffset() {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
const auto* enclosing_pagination_layer =
@@ -2864,11 +2993,11 @@ bool PaintPropertyTreeBuilder::UpdateFragments() {
object_.StyleRef().ClipPath() || NeedsPaintOffsetTranslation(object_) ||
NeedsStickyTranslation(object_) || NeedsTransform(object_) ||
NeedsClipPathClip(object_) || NeedsEffect(object_) ||
- NeedsLinkHighlightEffect(object_) ||
NeedsTransformForNonRootSVG(object_) || NeedsFilter(object_) ||
NeedsCssClip(object_) || NeedsInnerBorderRadiusClip(object_) ||
NeedsOverflowClip(object_) || NeedsPerspective(object_) ||
NeedsReplacedContentTransform(object_) ||
+ NeedsLinkHighlightEffect(object_) ||
NeedsScrollOrScrollTranslation(object_);
// Need of fragmentation clip will be determined in CreateFragmentContexts().
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 69b19f58c75..91566f3564a 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -147,9 +147,9 @@ TEST_P(PaintPropertyTreeBuilderTest, FixedPosition) {
auto* positioned_scroll_translation =
positioned_scroll_properties->ScrollTranslation();
auto* positioned_scroll_node = positioned_scroll_translation->ScrollNode();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetDocument()
.GetPage()
->GetVisualViewport()
@@ -185,9 +185,9 @@ TEST_P(PaintPropertyTreeBuilderTest, FixedPosition) {
auto* transformed_scroll_translation =
transformed_scroll_properties->ScrollTranslation();
auto* transformed_scroll_node = transformed_scroll_translation->ScrollNode();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetDocument()
.GetPage()
->GetVisualViewport()
@@ -538,9 +538,9 @@ TEST_P(PaintPropertyTreeBuilderTest, Perspective) {
// paint offset.
EXPECT_EQ(FloatPoint3D(250, 250, 0),
perspective_properties->Perspective()->Origin());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
perspective_properties->Perspective()->Parent());
} else {
@@ -567,9 +567,9 @@ TEST_P(PaintPropertyTreeBuilderTest, Perspective) {
perspective_properties->Perspective()->Matrix());
EXPECT_EQ(FloatPoint3D(250, 250, 0),
perspective_properties->Perspective()->Origin());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
perspective_properties->Perspective()->Parent());
} else {
@@ -584,9 +584,9 @@ TEST_P(PaintPropertyTreeBuilderTest, Perspective) {
perspective_properties->Perspective()->Matrix());
EXPECT_EQ(FloatPoint3D(70, 160, 0),
perspective_properties->Perspective()->Origin());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
perspective_properties->Perspective()->Parent());
} else {
@@ -619,7 +619,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Transform) {
EXPECT_EQ(DocScrollTranslation(),
transform_properties->PaintOffsetTranslation()->Parent());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(
transform_properties->Transform()->HasDirectCompositingReasons());
}
@@ -664,7 +664,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Preserve3D3DTransformedDescendant) {
preserve->GetLayoutObject()->FirstFragment().PaintProperties();
EXPECT_TRUE(preserve_properties->Transform());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(
preserve_properties->Transform()->HasDirectCompositingReasons());
}
@@ -686,7 +686,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Perspective3DTransformedDescendant) {
perspective->GetLayoutObject()->FirstFragment().PaintProperties();
EXPECT_TRUE(perspective_properties->Transform());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(
perspective_properties->Transform()->HasDirectCompositingReasons());
}
@@ -694,7 +694,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Perspective3DTransformedDescendant) {
TEST_P(PaintPropertyTreeBuilderTest,
TransformNodeWithActiveAnimationHasDirectCompositingReason) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
LoadTestData("transform-animation.html");
@@ -704,7 +704,24 @@ TEST_P(PaintPropertyTreeBuilderTest,
}
TEST_P(PaintPropertyTreeBuilderTest,
- OpacityAnimationCreatesTransformAndFilterNodes) {
+ OpacityAnimationDoesNotCreateTransformNode) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ return;
+ }
+
+ LoadTestData("opacity-animation.html");
+ EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Transform());
+ EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Filter());
+}
+
+TEST_P(PaintPropertyTreeBuilderTest,
+ BGPTOpacityAnimationCreatesTransformAndFilterNodes) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ return;
+ }
+
LoadTestData("opacity-animation.html");
// TODO(flackr): Verify that after https://crbug.com/900241 is fixed we no
// longer create transform or filter nodes for opacity animations.
@@ -714,7 +731,7 @@ TEST_P(PaintPropertyTreeBuilderTest,
TEST_P(PaintPropertyTreeBuilderTest,
EffectNodeWithActiveAnimationHasDirectCompositingReason) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
LoadTestData("opacity-animation.html");
@@ -742,14 +759,14 @@ TEST_P(PaintPropertyTreeBuilderTest, WillChangeTransform) {
transform_properties->Transform()->Matrix());
// The value is zero without a transform property that needs transform-offset.
EXPECT_EQ(FloatPoint3D(0, 0, 0), transform_properties->Transform()->Origin());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(nullptr, transform_properties->PaintOffsetTranslation());
} else {
// SPv1 creates PaintOffsetTranslation for composited layers.
EXPECT_EQ(TransformationMatrix().Translate(50, 100),
transform_properties->PaintOffsetTranslation()->Matrix());
}
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(
transform_properties->Transform()->HasDirectCompositingReasons());
}
@@ -802,9 +819,9 @@ TEST_P(PaintPropertyTreeBuilderTest, RelativePositionInline) {
inline_block->GetLayoutObject()->FirstFragment().PaintProperties();
EXPECT_EQ(TransformationMatrix().Translate(135, 490),
inline_block_properties->PaintOffsetTranslation()->Matrix());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
inline_block_properties->PaintOffsetTranslation()->Parent());
} else {
@@ -1138,9 +1155,9 @@ TEST_P(PaintPropertyTreeBuilderTest, TransformNodesInSVG) {
EXPECT_EQ(
TransformationMatrix().Translate(70, 25),
svg_root_with3d_transform_properties->PaintOffsetTranslation()->Matrix());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
svg_root_with3d_transform_properties->PaintOffsetTranslation()
->Parent());
@@ -1231,9 +1248,9 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGRootPaintOffsetTransformNode) {
FloatSize(50, 25),
svg_properties->PaintOffsetTranslation()->Matrix().To2DTranslation());
EXPECT_EQ(nullptr, svg_properties->ReplacedContentTransform());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
svg_properties->PaintOffsetTranslation()->Parent());
} else {
@@ -1520,6 +1537,26 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGForeignObjectOverflowClip) {
EXPECT_EQ(nullptr, properties2);
}
+TEST_P(PaintPropertyTreeBuilderTest, OverflowClipWithEmptyVisualOverflow) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0 }
+ ::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+ }
+ </style>
+ <div id='container' style='width: 100px; height: 100px;
+ will-change: transform; overflow: scroll; background: lightblue;'>
+ <div id='forcescroll' style='width: 0; height: 400px;'></div>
+ </div>
+ )HTML");
+
+ const auto* clip = PaintPropertiesForElement("container")->OverflowClip();
+ EXPECT_NE(nullptr, clip);
+ EXPECT_EQ(FloatRect(0, 0, 90, 90), clip->ClipRect().Rect());
+}
+
TEST_P(PaintPropertyTreeBuilderTest,
PaintOffsetTranslationSVGHTMLBoundaryMulticol) {
SetBodyInnerHTML(R"HTML(
@@ -1603,9 +1640,9 @@ TEST_P(PaintPropertyTreeBuilderTest, ControlClip) {
LayoutObject& button = *GetLayoutObjectByElementId("button");
const ObjectPaintProperties* button_properties =
button.FirstFragment().PaintProperties();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(DocPreTranslation());
EXPECT_FALSE(DocScrollTranslation());
EXPECT_EQ(DocPreTranslation(),
@@ -1643,9 +1680,9 @@ TEST_P(PaintPropertyTreeBuilderTest, ControlClipInsideForeignObject) {
LayoutObject& button = *GetLayoutObjectByElementId("button");
const ObjectPaintProperties* button_properties =
button.FirstFragment().PaintProperties();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(DocScrollTranslation());
} else {
// Always create scroll translation for layout view even the document does
@@ -1683,9 +1720,9 @@ TEST_P(PaintPropertyTreeBuilderTest, BorderRadiusClip) {
const ObjectPaintProperties* div_properties =
div.FirstFragment().PaintProperties();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(DocScrollTranslation());
EXPECT_EQ(DocPreTranslation(),
div_properties->OverflowClip()->LocalTransformSpace());
@@ -1703,9 +1740,9 @@ TEST_P(PaintPropertyTreeBuilderTest, BorderRadiusClip) {
div_properties->OverflowClip()->ClipRect());
const ClipPaintPropertyNode* border_radius_clip =
div_properties->OverflowClip()->Parent();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(), border_radius_clip->LocalTransformSpace());
} else {
EXPECT_EQ(DocScrollTranslation(),
@@ -1802,8 +1839,8 @@ TEST_P(PaintPropertyTreeBuilderTest, TransformNodesAcrossSubframes) {
EXPECT_EQ(TransformationMatrix().Translate3d(7, 7, 0),
iframe_pre_translation->Matrix());
// SPv1 composited elements always create paint offset translation,
- // where in SPv2 they don't.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ // where in CAP they don't.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(div_with_transform_properties->Transform(),
iframe_pre_translation->Parent());
} else {
@@ -1820,9 +1857,6 @@ TEST_P(PaintPropertyTreeBuilderTest, TransformNodesAcrossSubframes) {
}
TEST_P(PaintPropertyTreeBuilderTest, FramesEstablishIsolation) {
- if (!RuntimeEnabledFeatures::LayoutViewIsolationNodesEnabled())
- return;
-
SetBodyInnerHTML(R"HTML(
<style>
body { margin: 0; }
@@ -2069,7 +2103,7 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_EQ(DocContentClip(),
child.FirstFragment().LocalBorderBoxProperties().Clip());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocScrollTranslation(),
child.FirstFragment().LocalBorderBoxProperties().Transform());
} else {
@@ -2119,9 +2153,9 @@ TEST_P(PaintPropertyTreeBuilderTest, TableCellLayoutLocation) {
LayoutObject& target = *GetLayoutObjectByElementId("target");
EXPECT_EQ(LayoutPoint(170, 170), target.FirstFragment().PaintOffset());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
target.FirstFragment().LocalBorderBoxProperties().Transform());
} else {
@@ -2164,9 +2198,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipFixedPositionDescendant) {
const ObjectPaintProperties* clip_properties =
clip.FirstFragment().PaintProperties();
EXPECT_EQ(DocContentClip(), clip_properties->CssClip()->Parent());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
clip_properties->CssClip()->LocalTransformSpace());
} else {
@@ -2227,9 +2261,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipAbsPositionDescendant) {
const ObjectPaintProperties* clip_properties =
clip->FirstFragment().PaintProperties();
EXPECT_EQ(DocContentClip(), clip_properties->CssClip()->Parent());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(DocScrollTranslation());
EXPECT_EQ(DocPreTranslation(),
clip_properties->CssClip()->LocalTransformSpace());
@@ -2251,9 +2285,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipAbsPositionDescendant) {
auto* absolute = GetLayoutObjectByElementId("absolute");
EXPECT_EQ(clip_properties->CssClip(),
absolute->FirstFragment().LocalBorderBoxProperties().Clip());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(DocScrollTranslation());
EXPECT_EQ(DocPreTranslation(),
absolute->FirstFragment().LocalBorderBoxProperties().Transform());
@@ -2297,9 +2331,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipSubpixel) {
const ObjectPaintProperties* clip_properties =
clip->FirstFragment().PaintProperties();
EXPECT_EQ(DocContentClip(), clip_properties->CssClip()->Parent());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(DocPreTranslation());
EXPECT_EQ(DocPreTranslation(),
clip_properties->CssClip()->LocalTransformSpace());
@@ -2353,9 +2387,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipFixedPositionDescendantNonShared) {
const ObjectPaintProperties* overflow_properties =
overflow.FirstFragment().PaintProperties();
EXPECT_EQ(DocContentClip(), overflow_properties->OverflowClip()->Parent());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(DocPreTranslation());
EXPECT_EQ(DocPreTranslation(),
overflow_properties->ScrollTranslation()->Parent()->Parent());
@@ -2905,7 +2939,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Preserve3DCreatesSharedRenderingContext) {
b->FirstFragment().PaintProperties();
ASSERT_TRUE(a_properties->Transform() && b_properties->Transform());
EXPECT_NE(a_properties->Transform(), b_properties->Transform());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(a_properties->Transform()->HasRenderingContext());
EXPECT_TRUE(b_properties->Transform()->HasRenderingContext());
EXPECT_EQ(a_properties->Transform()->RenderingContextId(),
@@ -2951,7 +2985,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FlatTransformStyleEndsRenderingContext) {
// #a should participate in a rendering context (due to its parent), but its
// child #b should not.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(a_properties->Transform()->HasRenderingContext());
EXPECT_FALSE(b_properties->Transform()->HasRenderingContext());
}
@@ -2988,7 +3022,7 @@ TEST_P(PaintPropertyTreeBuilderTest, NestedRenderingContexts) {
// child does preserve 3D, but since #a does not, #a's rendering context is
// not passed on to its children. Thus #b ends up in a separate rendering
// context rooted at its parent.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(a_properties->Transform()->HasRenderingContext());
EXPECT_TRUE(b_properties->Transform()->HasRenderingContext());
EXPECT_NE(a_properties->Transform()->RenderingContextId(),
@@ -3364,9 +3398,9 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowClipContentsTreeState) {
clipper->FirstFragment().PaintProperties();
LayoutObject* child = GetLayoutObjectByElementId("child");
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(DocScrollTranslation());
EXPECT_TRUE(DocPreTranslation());
EXPECT_EQ(DocPreTranslation(),
@@ -3384,18 +3418,18 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowClipContentsTreeState) {
auto contents_properties = clipper->FirstFragment().ContentsProperties();
EXPECT_EQ(LayoutPoint(30, 20), clipper->FirstFragment().PaintOffset());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(), contents_properties.Transform());
} else {
EXPECT_EQ(DocScrollTranslation(), contents_properties.Transform());
}
EXPECT_EQ(clip_properties->OverflowClip(), contents_properties.Clip());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
child->FirstFragment().LocalBorderBoxProperties().Transform());
} else {
@@ -3410,106 +3444,121 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowClipContentsTreeState) {
CHECK_EXACT_VISUAL_RECT(LayoutRect(0, 0, 500, 600), child, clipper);
}
-TEST_P(PaintPropertyTreeBuilderTest, ContainsPaintContentsTreeState) {
- SetBodyInnerHTML(R"HTML(
- <style>body { margin: 20px 30px; }</style>
- <div id='clipper'
- style='contain: paint; width: 300px; height: 200px;'>
- <div id='child'
- style='position: relative; width: 400px; height: 500px;'></div>
- </div>
- )HTML");
-
- LayoutBoxModelObject* clipper =
- ToLayoutBoxModelObject(GetLayoutObjectByElementId("clipper"));
- const ObjectPaintProperties* clip_properties =
- clipper->FirstFragment().PaintProperties();
- LayoutObject* child = GetLayoutObjectByElementId("child");
- const auto& clip_local_properties =
- clipper->FirstFragment().LocalBorderBoxProperties();
-
- // Verify that we created isolation nodes.
- EXPECT_TRUE(clip_properties->TransformIsolationNode());
- EXPECT_TRUE(clip_properties->EffectIsolationNode());
- EXPECT_TRUE(clip_properties->ClipIsolationNode());
-
- // Verify parenting:
-
- // Transform isolation node should be parented to the local border box
- // properties transform, which should be the paint offset translation.
- EXPECT_EQ(clip_properties->TransformIsolationNode()->Parent(),
- clip_local_properties.Transform());
- EXPECT_EQ(clip_properties->TransformIsolationNode()->Parent(),
- clip_properties->PaintOffsetTranslation());
- // Similarly, effect isolation node is parented to the local border box
- // properties effect.
- EXPECT_EQ(clip_properties->EffectIsolationNode()->Parent(),
- clip_local_properties.Effect());
- // Clip isolation node, however, is parented to the overflow clip, which is in
- // turn parented to the local border box properties clip.
- EXPECT_EQ(clip_properties->ClipIsolationNode()->Parent(),
- clip_properties->OverflowClip());
- EXPECT_EQ(clip_properties->OverflowClip()->Parent(),
- clip_local_properties.Clip());
-
- // Verify transform:
-
- // Isolation transform node should be identity.
- EXPECT_EQ(clip_properties->TransformIsolationNode()->Matrix(),
- TransformationMatrix());
-
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
- // scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- EXPECT_FALSE(DocScrollTranslation());
- EXPECT_TRUE(DocPreTranslation());
- // Isolation induces paint offset translation, so the node should be
- // different from the doc node, but its parent is the same as the doc node.
- EXPECT_EQ(DocPreTranslation(), clipper->FirstFragment()
- .LocalBorderBoxProperties()
- .Transform()
- ->Parent());
- } else {
- // Always create scroll translation for layout view even the document does
- // not scroll (not enough content).
- EXPECT_TRUE(DocScrollTranslation());
- // Isolation induces paint offset translation, so the node should be
- // different from the doc node, but its parent is the same as the doc node.
- EXPECT_EQ(DocScrollTranslation(), clipper->FirstFragment()
- .LocalBorderBoxProperties()
- .Transform()
- ->Parent());
- }
-
- // Verify clip:
-
- EXPECT_EQ(DocContentClip(),
- clipper->FirstFragment().LocalBorderBoxProperties().Clip());
- // Clip isolation node should be big enough to encompass all other clips,
- // including DocContentClip.
- EXPECT_TRUE(clip_properties->ClipIsolationNode()->ClipRect().Rect().Contains(
- DocContentClip()->ClipRect().Rect()));
+TEST_P(PaintPropertyTreeBuilderTest, ContainPaintOrStyleLayoutTreeState) {
+ for (const char* containment : {"paint", "style layout"}) {
+ SCOPED_TRACE(containment);
+ SetBodyInnerHTML(String::Format(R"HTML(
+ <style>body { margin: 20px 30px; }</style>
+ <div id='clipper'
+ style='contain: %s; width: 300px; height: 200px;'>
+ <div id='child'
+ style='position: relative; width: 400px; height: 500px;'></div>
+ </div>
+ )HTML",
+ containment));
+
+ LayoutBoxModelObject* clipper =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("clipper"));
+ const ObjectPaintProperties* clip_properties =
+ clipper->FirstFragment().PaintProperties();
+ LayoutObject* child = GetLayoutObjectByElementId("child");
+ const auto& clip_local_properties =
+ clipper->FirstFragment().LocalBorderBoxProperties();
+
+ // Verify that we created isolation nodes.
+ EXPECT_TRUE(clip_properties->TransformIsolationNode());
+ EXPECT_TRUE(clip_properties->EffectIsolationNode());
+ EXPECT_TRUE(clip_properties->ClipIsolationNode());
+
+ // Verify parenting:
+
+ // Transform isolation node should be parented to the local border box
+ // properties transform, which should be the paint offset translation.
+ EXPECT_EQ(clip_properties->TransformIsolationNode()->Parent(),
+ clip_local_properties.Transform());
+ EXPECT_EQ(clip_properties->TransformIsolationNode()->Parent(),
+ clip_properties->PaintOffsetTranslation());
+ // Similarly, effect isolation node is parented to the local border box
+ // properties effect.
+ EXPECT_EQ(clip_properties->EffectIsolationNode()->Parent(),
+ clip_local_properties.Effect());
+ if (strcmp(containment, "paint") == 0) {
+ // If we contain paint, then clip isolation node is parented to the
+ // overflow clip, which is in turn parented to the local border box
+ // properties clip.
+ EXPECT_EQ(clip_properties->ClipIsolationNode()->Parent(),
+ clip_properties->OverflowClip());
+ EXPECT_EQ(clip_properties->OverflowClip()->Parent(),
+ clip_local_properties.Clip());
+ } else {
+ // Otherwise, the clip isolation node is parented to the local border box
+ // properties clip directly.
+ EXPECT_EQ(clip_properties->ClipIsolationNode()->Parent(),
+ clip_local_properties.Clip());
+ }
- // Verify contents properties and child properties:
+ // Verify transform:
+
+ // Isolation transform node should be identity.
+ EXPECT_EQ(clip_properties->TransformIsolationNode()->Matrix(),
+ TransformationMatrix());
+
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
+ // scrolling.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_FALSE(DocScrollTranslation());
+ EXPECT_TRUE(DocPreTranslation());
+ // Isolation induces paint offset translation, so the node should be
+ // different from the doc node, but its parent is the same as the doc
+ // node.
+ EXPECT_EQ(DocPreTranslation(), clipper->FirstFragment()
+ .LocalBorderBoxProperties()
+ .Transform()
+ ->Parent());
+ } else {
+ // Always create scroll translation for layout view even the document does
+ // not scroll (not enough content).
+ EXPECT_TRUE(DocScrollTranslation());
+ // Isolation induces paint offset translation, so the node should be
+ // different from the doc node, but its parent is the same as the doc
+ // node.
+ EXPECT_EQ(DocScrollTranslation(), clipper->FirstFragment()
+ .LocalBorderBoxProperties()
+ .Transform()
+ ->Parent());
+ }
- auto contents_properties = clipper->FirstFragment().ContentsProperties();
- // Since the clipper is isolated, its paint offset should be 0, 0.
- EXPECT_EQ(LayoutPoint(0, 0), clipper->FirstFragment().PaintOffset());
- // Ensure that the contents properties match isolation nodes.
- EXPECT_EQ(clip_properties->TransformIsolationNode(),
- contents_properties.Transform());
- EXPECT_EQ(clip_properties->ClipIsolationNode(), contents_properties.Clip());
- EXPECT_EQ(clip_properties->EffectIsolationNode(),
- contents_properties.Effect());
+ // Verify clip:
- // Child should be using isolation nodes as its local border box properties.
- EXPECT_EQ(contents_properties.Transform(),
- child->FirstFragment().LocalBorderBoxProperties().Transform());
- EXPECT_EQ(contents_properties.Clip(),
- child->FirstFragment().LocalBorderBoxProperties().Clip());
- EXPECT_EQ(contents_properties.Effect(),
- child->FirstFragment().LocalBorderBoxProperties().Effect());
- CHECK_EXACT_VISUAL_RECT(LayoutRect(0, 0, 400, 500), child, clipper);
+ EXPECT_EQ(DocContentClip(),
+ clipper->FirstFragment().LocalBorderBoxProperties().Clip());
+ // Clip isolation node should be big enough to encompass all other clips,
+ // including DocContentClip.
+ EXPECT_TRUE(
+ clip_properties->ClipIsolationNode()->ClipRect().Rect().Contains(
+ DocContentClip()->ClipRect().Rect()));
+
+ // Verify contents properties and child properties:
+
+ auto contents_properties = clipper->FirstFragment().ContentsProperties();
+ // Since the clipper is isolated, its paint offset should be 0, 0.
+ EXPECT_EQ(LayoutPoint(0, 0), clipper->FirstFragment().PaintOffset());
+ // Ensure that the contents properties match isolation nodes.
+ EXPECT_EQ(clip_properties->TransformIsolationNode(),
+ contents_properties.Transform());
+ EXPECT_EQ(clip_properties->ClipIsolationNode(), contents_properties.Clip());
+ EXPECT_EQ(clip_properties->EffectIsolationNode(),
+ contents_properties.Effect());
+
+ // Child should be using isolation nodes as its local border box properties.
+ EXPECT_EQ(contents_properties.Transform(),
+ child->FirstFragment().LocalBorderBoxProperties().Transform());
+ EXPECT_EQ(contents_properties.Clip(),
+ child->FirstFragment().LocalBorderBoxProperties().Clip());
+ EXPECT_EQ(contents_properties.Effect(),
+ child->FirstFragment().LocalBorderBoxProperties().Effect());
+ CHECK_EXACT_VISUAL_RECT(LayoutRect(0, 0, 400, 500), child, clipper);
+ }
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollContentsTreeState) {
@@ -3625,9 +3674,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CssClipContentsTreeState) {
clipper->FirstFragment().PaintProperties();
LayoutObject* child = GetLayoutObjectByElementId("child");
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(DocPreTranslation());
EXPECT_EQ(DocPreTranslation(),
clipper->FirstFragment().LocalBorderBoxProperties().Transform());
@@ -3644,9 +3693,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CssClipContentsTreeState) {
auto contents_properties = clipper->FirstFragment().ContentsProperties();
EXPECT_EQ(LayoutPoint(30, 20), clipper->FirstFragment().PaintOffset());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(), contents_properties.Transform());
} else {
EXPECT_EQ(DocScrollTranslation(), contents_properties.Transform());
@@ -3684,9 +3733,9 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_EQ(
paint_offset_translation,
svg_with_view_box.FirstFragment().LocalBorderBoxProperties().Transform());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(), paint_offset_translation->Parent());
} else {
EXPECT_EQ(DocScrollTranslation(), paint_offset_translation->Parent());
@@ -3766,9 +3815,9 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameOverflowHiddenScrollProperties) {
EXPECT_EQ(TransformationMatrix().Translate(0, -37),
DocScrollTranslation()->Matrix());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(nullptr, DocScrollTranslation()->ScrollNode());
EXPECT_EQ(nullptr, DocScroll());
} else {
@@ -3819,9 +3868,9 @@ TEST_P(PaintPropertyTreeBuilderTest, NestedScrollProperties) {
auto* scroll_a_translation =
overflow_a_scroll_properties->ScrollTranslation();
auto* overflow_a_scroll_node = scroll_a_translation->ScrollNode();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetDocument()
.GetPage()
->GetVisualViewport()
@@ -4006,9 +4055,9 @@ TEST_P(PaintPropertyTreeBuilderTest, NestedPositionedScrollProperties) {
auto* scroll_a_translation =
overflow_a_scroll_properties->ScrollTranslation();
auto* overflow_a_scroll_node = scroll_a_translation->ScrollNode();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetDocument()
.GetPage()
->GetVisualViewport()
@@ -4209,10 +4258,19 @@ TEST_P(PaintPropertyTreeBuilderTest,
ASSERT_TRUE(multicol_container->FirstFragment().NextFragment());
ASSERT_FALSE(
multicol_container->FirstFragment().NextFragment()->NextFragment());
- EXPECT_EQ(LayoutPoint(8, 8),
- multicol_container->FirstFragment().PaintOffset());
- EXPECT_EQ(LayoutPoint(59, -12),
- multicol_container->FirstFragment().NextFragment()->PaintOffset());
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(LayoutPoint(8, 8),
+ multicol_container->FirstFragment().PaintOffset());
+ EXPECT_EQ(
+ LayoutPoint(59, -12),
+ multicol_container->FirstFragment().NextFragment()->PaintOffset());
+ } else {
+ EXPECT_EQ(LayoutPoint(0, 0),
+ multicol_container->FirstFragment().PaintOffset());
+ EXPECT_EQ(
+ LayoutPoint(51, -20),
+ multicol_container->FirstFragment().NextFragment()->PaintOffset());
+ }
GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 25),
kUserScroll);
@@ -4222,10 +4280,14 @@ TEST_P(PaintPropertyTreeBuilderTest,
ASSERT_FALSE(
multicol_container->FirstFragment().NextFragment()->NextFragment());
- EXPECT_EQ(LayoutPoint(8, 8),
- multicol_container->FirstFragment().PaintOffset());
- EXPECT_EQ(LayoutPoint(59, -12),
- multicol_container->FirstFragment().NextFragment()->PaintOffset());
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(LayoutPoint(8, 8),
+ multicol_container->FirstFragment().PaintOffset());
+ EXPECT_EQ(
+ LayoutPoint(59, -12),
+ multicol_container->FirstFragment().NextFragment()->PaintOffset());
+ } else {
+ }
}
TEST_P(PaintPropertyTreeBuilderTest, FragmentsUnderMultiColumn) {
@@ -4432,8 +4494,8 @@ TEST_P(PaintPropertyTreeBuilderTest, CompositedUnderMultiColumn) {
GetLayoutObjectByElementId("non-composited-child");
LayoutObject* composited_child =
GetLayoutObjectByElementId("composited-child");
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- // Compositing doesn't affect SPv2 fragmentation.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // Compositing doesn't affect CAP fragmentation.
EXPECT_EQ(2u, NumFragments(composited));
EXPECT_EQ(LayoutPoint(100, 100), FragmentAt(composited, 0).PaintOffset());
EXPECT_EQ(LayoutPoint(100, -200),
@@ -4838,7 +4900,7 @@ TEST_P(PaintPropertyTreeBuilderTest, ChangePositionUpdateDescendantProperties) {
TEST_P(PaintPropertyTreeBuilderTest,
TransformNodeNotAnimatedStillHasCompositorElementId) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML("<div id='target' style='transform: translateX(2em)'></div");
@@ -4850,7 +4912,7 @@ TEST_P(PaintPropertyTreeBuilderTest,
TEST_P(PaintPropertyTreeBuilderTest,
EffectNodeNotAnimatedStillHasCompositorElementId) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML("<div id='target' style='opacity: 0.5'></div");
@@ -4865,7 +4927,7 @@ TEST_P(PaintPropertyTreeBuilderTest,
TEST_P(PaintPropertyTreeBuilderTest,
TransformNodeAnimatedHasCompositorElementId) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
LoadTestData("transform-animation.html");
@@ -4877,7 +4939,7 @@ TEST_P(PaintPropertyTreeBuilderTest,
}
TEST_P(PaintPropertyTreeBuilderTest, EffectNodeAnimatedHasCompositorElementId) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
LoadTestData("opacity-animation.html");
@@ -4906,13 +4968,17 @@ TEST_P(PaintPropertyTreeBuilderTest, FloatUnderInline) {
EXPECT_EQ(0.5f, effect->Opacity());
LayoutObject* target = GetLayoutObjectByElementId("target");
- EXPECT_EQ(LayoutPoint(66, 55), target->FirstFragment().PaintOffset());
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ EXPECT_EQ(LayoutPoint(266, 155), target->FirstFragment().PaintOffset());
+ } else {
+ EXPECT_EQ(LayoutPoint(66, 55), target->FirstFragment().PaintOffset());
+ }
EXPECT_EQ(effect,
target->FirstFragment().LocalBorderBoxProperties().Effect());
}
TEST_P(PaintPropertyTreeBuilderTest, ScrollNodeHasCompositorElementId) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -5064,7 +5130,7 @@ TEST_P(PaintPropertyTreeBuilderTest, MaskEscapeClip) {
EXPECT_EQ(mask_clip, target_properties->Mask()->OutputClip());
const auto* absolute = GetLayoutObjectByElementId("absolute");
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(),
absolute->FirstFragment().LocalBorderBoxProperties().Transform());
} else {
@@ -5268,9 +5334,9 @@ TEST_P(PaintPropertyTreeBuilderTest, ScrollBoundsOffset) {
auto* scroll_translation = scroll_properties->ScrollTranslation();
auto* paint_offset_translation = scroll_properties->PaintOffsetTranslation();
auto* scroll_node = scroll_translation->ScrollNode();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(GetDocument()
.GetPage()
->GetVisualViewport()
@@ -5319,7 +5385,7 @@ TEST_P(PaintPropertyTreeBuilderTest, BackfaceHidden) {
ASSERT_NE(nullptr, target_properties);
const auto* paint_offset_translation =
target_properties->PaintOffsetTranslation();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(nullptr, paint_offset_translation);
EXPECT_EQ(LayoutPoint(60, 50), target->FirstFragment().PaintOffset());
} else {
@@ -5332,7 +5398,7 @@ TEST_P(PaintPropertyTreeBuilderTest, BackfaceHidden) {
}
const auto* transform = target_properties->Transform();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
ASSERT_NE(nullptr, transform);
EXPECT_TRUE(transform->Matrix().IsIdentity());
@@ -5370,9 +5436,9 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameBorderRadius) {
radius, radius),
border_radius_clip->ClipRect());
EXPECT_EQ(DocContentClip(), border_radius_clip->Parent());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(), border_radius_clip->LocalTransformSpace());
} else {
EXPECT_EQ(DocScrollTranslation(),
@@ -5404,9 +5470,9 @@ TEST_P(PaintPropertyTreeBuilderTest, ImageBorderRadius) {
radius),
border_radius_clip->ClipRect());
EXPECT_EQ(DocContentClip(), border_radius_clip->Parent());
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(DocPreTranslation(), border_radius_clip->LocalTransformSpace());
} else {
EXPECT_EQ(DocScrollTranslation(),
@@ -5514,22 +5580,6 @@ TEST_P(PaintPropertyTreeBuilderTest, FragmentPaintOffsetUnderOverflowScroll) {
EXPECT_EQ(LayoutRect(390, -10, 20, 20), second_fragment->VisualRect());
}
-// The following test tests that we restrict actual column count, to not run
-// into unnecessary performance problems. The code that applies this limitation
-// is in MultiColumnFragmentainerGroup::ActualColumnCount().
-TEST_P(PaintPropertyTreeBuilderTest, ShortColumnTallContent) {
- SetBodyInnerHTML(R"HTML(
- <div id="multicol" style="columns:3; column-gap:1px; width:101px; height:1px;">
- <div style="height:1000000px;"></div>
- </div>
- )HTML");
-
- const auto* flow_thread =
- GetLayoutObjectByElementId("multicol")->SlowFirstChild();
- ASSERT_TRUE(flow_thread->IsLayoutFlowThread());
- EXPECT_EQ(10u, NumFragments(flow_thread));
-}
-
TEST_P(PaintPropertyTreeBuilderTest, FragmentClipPixelSnapped) {
SetBodyInnerHTML(R"HTML(
<div id="container" style="columns: 2; column-gap: 0; width: 49.5px">
@@ -5641,16 +5691,16 @@ TEST_P(PaintPropertyTreeBuilderTest, RootHasCompositedScrolling) {
)HTML");
// When the root scrolls, there should be direct compositing reasons.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_TRUE(DocScrollTranslation()->HasDirectCompositingReasons());
// Remove scrolling from the root.
Element* force_scroll_element = GetDocument().getElementById("forceScroll");
force_scroll_element->setAttribute(html_names::kStyleAttr, "");
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- // TODO(crbug.com/732611): SPv2 invalidations are incorrect if there is
+ // TODO(crbug.com/732611): CAP invalidations are incorrect if there is
// scrolling.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(DocScrollTranslation());
} else {
// Always create scroll translation for layout view even the document does
@@ -5669,7 +5719,7 @@ TEST_P(PaintPropertyTreeBuilderTest, IframeDoesNotRequireCompositedScrolling) {
)HTML");
UpdateAllLifecyclePhasesForTest();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_TRUE(DocScrollTranslation()->HasDirectCompositingReasons());
// When the child iframe scrolls, there should not be direct compositing
@@ -5791,7 +5841,7 @@ TEST_P(PaintPropertyTreeBuilderTest, ClipPathInheritanceWithoutMutation) {
}
TEST_P(PaintPropertyTreeBuilderTest, CompositedLayerSkipsFragmentClip) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -6088,52 +6138,6 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_EQ(LayoutPoint(100, 85), paint_offset("float-right-rtl-vlr"));
}
-TEST_P(PaintPropertyTreeBuilderTest, ClipInvalidationForReplacedElement) {
- // Non-composited LayoutImage has a micro-optimization to embed object-fit
- // and clip to the drawing, thus not creating nodes.
- // SPv2 makes everything non-composited essentially.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
- return;
- // This test verifies clip nodes are correctly updated in response to
- // content box mutation.
- SetBodyInnerHTML(R"HTML(
- <style>
- img {
- box-sizing: border-box;
- width: 8px;
- height: 8px;
- object-fit: none;
- will-change: transform;
- }
- </style>
- <!-- An image of 10x10 white pixels. -->
- <img id="target" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAA
- AAKCAIAAAACUFjqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gcVABQvx8CBmA
- AAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFUlEQVQY02P
- 8//8/A27AxIAXjFRpAKXjAxH/0Dm5AAAAAElFTkSuQmCC"/>
- )HTML");
-
- {
- const auto* properties = PaintPropertiesForElement("target");
- ASSERT_TRUE(properties);
- ASSERT_TRUE(properties->OverflowClip());
- EXPECT_EQ(FloatRect(0, 0, 8, 8),
- properties->OverflowClip()->ClipRect().Rect());
- }
-
- GetDocument().getElementById("target")->setAttribute(
- html_names::kStyleAttr, "padding: 1px 2px 3px 4px;");
- UpdateAllLifecyclePhasesForTest();
-
- {
- const auto* properties = PaintPropertiesForElement("target");
- ASSERT_TRUE(properties);
- ASSERT_TRUE(properties->OverflowClip());
- EXPECT_EQ(FloatRect(4, 1, 2, 4),
- properties->OverflowClip()->ClipRect().Rect());
- }
-}
-
TEST_P(PaintPropertyTreeBuilderTest, SubpixelPositionedScrollNode) {
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -6418,11 +6422,11 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGRootCompositedClipPath) {
const auto* transform = properties->Transform();
ASSERT_NE(nullptr, transform);
EXPECT_EQ(properties->PaintOffsetTranslation(), transform->Parent());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
EXPECT_TRUE(transform->HasDirectCompositingReasons());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(nullptr, properties->MaskClip());
const auto* clip_path_clip = properties->ClipPathClip();
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 9938a031839..39c20eb187f 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -600,7 +600,7 @@ TEST_P(PaintPropertyTreeUpdateTest,
Element* target = GetDocument().getElementById("target");
const ObjectPaintProperties* properties =
target->GetLayoutObject()->FirstFragment().PaintProperties();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_TRUE(properties->Transform()->HasDirectCompositingReasons());
// Removing the animation should remove the transform node.
@@ -617,7 +617,7 @@ TEST_P(PaintPropertyTreeUpdateTest,
Element* target = GetDocument().getElementById("target");
const ObjectPaintProperties* properties =
target->GetLayoutObject()->FirstFragment().PaintProperties();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
EXPECT_TRUE(properties->Effect()->HasDirectCompositingReasons());
// Removing the animation should remove the effect node.
@@ -629,7 +629,7 @@ TEST_P(PaintPropertyTreeUpdateTest,
TEST_P(PaintPropertyTreeUpdateTest,
TransformNodeDoesNotLoseCompositorElementIdWhenAnimationRemoved) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
LoadTestData("transform-animation.html");
@@ -652,7 +652,7 @@ TEST_P(PaintPropertyTreeUpdateTest,
TEST_P(PaintPropertyTreeUpdateTest,
EffectNodeDoesNotLoseCompositorElementIdWhenAnimationRemoved) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
LoadTestData("opacity-animation.html");
@@ -1067,7 +1067,7 @@ TEST_P(PaintPropertyTreeUpdateTest, WillTransformChangeAboveFixed) {
}
TEST_P(PaintPropertyTreeUpdateTest, CompositingReasonForAnimation) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -1095,7 +1095,7 @@ TEST_P(PaintPropertyTreeUpdateTest, CompositingReasonForAnimation) {
target->setAttribute(html_names::kStyleAttr, "transform: translateX(11px)");
UpdateAllLifecyclePhasesForTest();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(transform->HasDirectCompositingReasons());
EXPECT_TRUE(transform->RequiresCompositingForAnimation());
}
@@ -1107,7 +1107,7 @@ TEST_P(PaintPropertyTreeUpdateTest, CompositingReasonForAnimation) {
"transform: translateX(11px); filter: opacity(40%)");
UpdateAllLifecyclePhasesForTest();
// The transform animation still continues.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(transform->HasDirectCompositingReasons());
EXPECT_TRUE(transform->RequiresCompositingForAnimation());
// The filter node should have correct direct compositing reasons, not
@@ -1409,4 +1409,153 @@ TEST_P(PaintPropertyTreeUpdateTest, ForwardReferencedSVGElementUpdate) {
svg2_properties->PaintOffsetTranslation()));
}
+TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForImage) {
+ // This test verifies clip nodes are correctly updated in response to
+ // content box mutation.
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ img {
+ box-sizing: border-box;
+ width: 8px;
+ height: 8px;
+ }
+ </style>
+ <!-- An image of 10x10 white pixels. -->
+ <img id="target" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAA
+ AAKCAIAAAACUFjqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gcVABQvx8CBmA
+ AAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFUlEQVQY02P
+ 8//8/A27AxIAXjFRpAKXjAxH/0Dm5AAAAAElFTkSuQmCC">
+ )HTML");
+
+ auto* target = GetDocument().getElementById("target");
+ const auto* properties = PaintPropertiesForElement("target");
+ // We don't need paint properties for object-fit: fill because the content
+ // never overflows.
+ EXPECT_EQ(nullptr, properties);
+
+ target->setAttribute(html_names::kStyleAttr, "object-fit: cover");
+ UpdateAllLifecyclePhasesForTest();
+ properties = PaintPropertiesForElement("target");
+ // We don't need paint properties because image painter always clip to the
+ // content box.
+ EXPECT_EQ(nullptr, properties);
+
+ target->setAttribute(html_names::kStyleAttr, "object-fit: none");
+ UpdateAllLifecyclePhasesForTest();
+ properties = PaintPropertiesForElement("target");
+ // Ditto.
+ EXPECT_EQ(nullptr, properties);
+
+ // We need overflow clip when there is border radius.
+ target->setAttribute(html_names::kStyleAttr,
+ "object-fit: none; border-radius: 2px");
+ UpdateAllLifecyclePhasesForTest();
+ properties = PaintPropertiesForElement("target");
+ ASSERT_TRUE(properties);
+ ASSERT_TRUE(properties->OverflowClip());
+ FloatSize corner(2, 2);
+ FloatRoundedRect::Radii radii(corner, corner, corner, corner);
+ EXPECT_EQ(FloatRoundedRect(FloatRect(8, 8, 8, 8), radii),
+ properties->OverflowClip()->ClipRect());
+
+ // We should update clip rect on border radius change.
+ target->setAttribute(html_names::kStyleAttr,
+ "object-fit: none; border-radius: 3px");
+ UpdateAllLifecyclePhasesForTest();
+ ASSERT_EQ(properties, PaintPropertiesForElement("target"));
+ ASSERT_TRUE(properties->OverflowClip());
+ radii.Expand(1);
+ EXPECT_EQ(FloatRoundedRect(FloatRect(8, 8, 8, 8), radii),
+ properties->OverflowClip()->ClipRect());
+
+ // We should update clip rect on padding change.
+ target->setAttribute(
+ html_names::kStyleAttr,
+ "object-fit: none; border-radius: 3px; padding: 1px 2px 3px 4px");
+ UpdateAllLifecyclePhasesForTest();
+ ASSERT_EQ(properties, PaintPropertiesForElement("target"));
+ ASSERT_TRUE(properties->OverflowClip());
+ // The rounded clip rect is the intersection of the rounded inner border
+ // rect and the content box rect.
+ EXPECT_EQ(
+ FloatRoundedRect(FloatRect(12, 9, 2, 4),
+ FloatRoundedRect::Radii(FloatSize(0, 2), FloatSize(1, 2),
+ FloatSize(), FloatSize(1, 0))),
+ properties->OverflowClip()->ClipRect());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForVideo) {
+ // This test verifies clip nodes are correctly updated in response to
+ // content box mutation.
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ video {
+ box-sizing: border-box;
+ width: 8px;
+ height: 8px;
+ }
+ </style>
+ <video id="target"></video>
+ )HTML");
+
+ auto* target = GetDocument().getElementById("target");
+ const auto* properties = PaintPropertiesForElement("target");
+ // We always create overflow clip for video regardless of object-fit.
+ ASSERT_TRUE(properties);
+ ASSERT_TRUE(properties->OverflowClip());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 8, 8),
+ properties->OverflowClip()->ClipRect());
+
+ target->setAttribute(html_names::kStyleAttr, "object-fit: cover");
+ UpdateAllLifecyclePhasesForTest();
+ ASSERT_EQ(properties, PaintPropertiesForElement("target"));
+ ASSERT_TRUE(properties->OverflowClip());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 8, 8),
+ properties->OverflowClip()->ClipRect());
+
+ // We need OverflowClip for object-fit: cover, too.
+ target->setAttribute(html_names::kStyleAttr, "object-fit: none");
+ UpdateAllLifecyclePhasesForTest();
+ ASSERT_EQ(properties, PaintPropertiesForElement("target"));
+ ASSERT_TRUE(properties->OverflowClip());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 8, 8),
+ properties->OverflowClip()->ClipRect());
+
+ // We should update clip rect on padding change.
+ target->setAttribute(html_names::kStyleAttr,
+ "object-fit: none; padding: 1px 2px 3px 4px");
+ UpdateAllLifecyclePhasesForTest();
+ ASSERT_EQ(properties, PaintPropertiesForElement("target"));
+ ASSERT_TRUE(properties->OverflowClip());
+ EXPECT_EQ(FloatRoundedRect(12, 9, 2, 4),
+ properties->OverflowClip()->ClipRect());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, ChangingClipPath) {
+ GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #content {
+ height: 500px;
+ width: 200px;
+ overflow: scroll;
+ }
+ .aclippath { clip-path: circle(115px at 20px 20px); }
+ .bclippath { clip-path: circle(135px at 22px 20px); }
+ </style>
+ <div id="content"></div>
+ )HTML");
+ auto* content = GetDocument().getElementById("content");
+ content->setAttribute(html_names::kClassAttr, "aclippath");
+ UpdateAllLifecyclePhasesForTest();
+
+ content->setAttribute(html_names::kClassAttr, "bclippath");
+ UpdateAllLifecyclePhasesForTest();
+ // Pass if no crash.
+
+ content->removeAttribute(html_names::kClassAttr);
+ UpdateAllLifecyclePhasesForTest();
+ // Pass if no crash.
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing.cc b/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
index 5cd87b85cec..52b297b6a38 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -72,14 +72,6 @@ void PaintTiming::MarkFirstContentfulPaint() {
SetFirstContentfulPaint(CurrentTimeTicks());
}
-void PaintTiming::MarkFirstTextPaint() {
- if (!first_text_paint_.is_null())
- return;
- first_text_paint_ = CurrentTimeTicks();
- SetFirstContentfulPaint(first_text_paint_);
- RegisterNotifySwapTime(PaintEvent::kFirstTextPaint);
-}
-
void PaintTiming::MarkFirstImagePaint() {
if (!first_image_paint_.is_null())
return;
@@ -98,12 +90,9 @@ void PaintTiming::SetFirstMeaningfulPaintCandidate(TimeTicks timestamp) {
}
void PaintTiming::SetFirstMeaningfulPaint(
- TimeTicks stamp,
TimeTicks swap_stamp,
FirstMeaningfulPaintDetector::HadUserInput had_input) {
- DCHECK(first_meaningful_paint_.is_null());
DCHECK(first_meaningful_paint_swap_.is_null());
- DCHECK(!stamp.is_null());
DCHECK(!swap_stamp.is_null());
TRACE_EVENT_MARK_WITH_TIMESTAMP2(
@@ -119,7 +108,6 @@ void PaintTiming::SetFirstMeaningfulPaint(
// Notify FMP for UMA only if there's no user input before FMP, so that layout
// changes caused by user interactions wouldn't be considered as FMP.
if (had_input == FirstMeaningfulPaintDetector::kNoUserInput) {
- first_meaningful_paint_ = stamp;
first_meaningful_paint_swap_ = swap_stamp;
NotifyPaintTimingChanged();
}
@@ -144,7 +132,7 @@ void PaintTiming::NotifyPaint(bool is_first_paint,
if (is_first_paint)
MarkFirstPaint();
if (text_painted)
- MarkFirstTextPaint();
+ MarkFirstContentfulPaint();
if (image_painted)
MarkFirstImagePaint();
fmp_detector_->NotifyPaint();
@@ -226,9 +214,6 @@ void PaintTiming::ReportSwapTime(PaintEvent event,
case PaintEvent::kFirstContentfulPaint:
SetFirstContentfulPaintSwap(timestamp);
return;
- case PaintEvent::kFirstTextPaint:
- SetFirstTextPaintSwap(timestamp);
- return;
case PaintEvent::kFirstImagePaint:
SetFirstImagePaintSwap(timestamp);
return;
@@ -262,14 +247,6 @@ void PaintTiming::SetFirstContentfulPaintSwap(TimeTicks stamp) {
fmp_detector_->NotifyFirstContentfulPaint(first_contentful_paint_swap_);
}
-void PaintTiming::SetFirstTextPaintSwap(TimeTicks stamp) {
- DCHECK(first_text_paint_swap_.is_null());
- first_text_paint_swap_ = stamp;
- probe::paintTiming(GetSupplementable(), "firstTextPaint",
- TimeTicksInSeconds(first_text_paint_swap_));
- NotifyPaintTimingChanged();
-}
-
void PaintTiming::SetFirstImagePaintSwap(TimeTicks stamp) {
DCHECK(first_image_paint_swap_.is_null());
first_image_paint_swap_ = stamp;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing.h b/chromium/third_party/blink/renderer/core/paint/paint_timing.h
index ea77cacbba4..ca4b35ebdff 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing.h
@@ -46,18 +46,16 @@ class CORE_EXPORT PaintTiming final
// event.
void MarkFirstPaint();
- // MarkFirstTextPaint, MarkFirstImagePaint, and MarkFirstContentfulPaint
+ // MarkFirstImagePaint, and MarkFirstContentfulPaint
// will also record first paint if first paint hasn't been recorded yet.
void MarkFirstContentfulPaint();
- // MarkFirstTextPaint and MarkFirstImagePaint will also record first
- // contentful paint if first contentful paint hasn't been recorded yet.
- void MarkFirstTextPaint();
+ // MarkFirstImagePaint will also record first contentful paint if first
+ // contentful paint hasn't been recorded yet.
void MarkFirstImagePaint();
void SetFirstMeaningfulPaintCandidate(TimeTicks timestamp);
void SetFirstMeaningfulPaint(
- TimeTicks stamp,
TimeTicks swap_stamp,
FirstMeaningfulPaintDetector::HadUserInput had_input);
void NotifyPaint(bool is_first_paint, bool text_painted, bool image_painted);
@@ -77,9 +75,6 @@ class CORE_EXPORT PaintTiming final
return first_contentful_paint_swap_;
}
- // FirstTextPaint returns the first time that text content was painted.
- TimeTicks FirstTextPaint() const { return first_text_paint_swap_; }
-
// FirstImagePaint returns the first time that image content was painted.
TimeTicks FirstImagePaint() const { return first_image_paint_swap_; }
@@ -134,7 +129,6 @@ class CORE_EXPORT PaintTiming final
void SetFirstPaintSwap(TimeTicks stamp);
void SetFirstContentfulPaintSwap(TimeTicks stamp);
void SetFirstImagePaintSwap(TimeTicks stamp);
- void SetFirstTextPaintSwap(TimeTicks stamp);
void RegisterNotifySwapTime(PaintEvent);
void ReportUserInputHistogram(
@@ -146,22 +140,15 @@ class CORE_EXPORT PaintTiming final
return first_contentful_paint_;
}
- TimeTicks FirstMeaningfulPaintRendered() const {
- return first_meaningful_paint_;
- }
-
// TODO(crbug/738235): Non first_*_swap_ variables are only being tracked to
// compute deltas for reporting histograms and should be removed once we
// confirm the deltas and discrepancies look reasonable.
TimeTicks first_paint_;
TimeTicks first_paint_swap_;
- TimeTicks first_text_paint_;
- TimeTicks first_text_paint_swap_;
TimeTicks first_image_paint_;
TimeTicks first_image_paint_swap_;
TimeTicks first_contentful_paint_;
TimeTicks first_contentful_paint_swap_;
- TimeTicks first_meaningful_paint_;
TimeTicks first_meaningful_paint_swap_;
TimeTicks first_meaningful_paint_candidate_;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
index 7b07edff362..23f48306296 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
+#include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -17,8 +18,10 @@ namespace blink {
PaintTimingDetector::PaintTimingDetector(LocalFrameView* frame_view)
: frame_view_(frame_view),
- text_paint_timing_detector_(new TextPaintTimingDetector(frame_view)),
- image_paint_timing_detector_(new ImagePaintTimingDetector(frame_view)){};
+ text_paint_timing_detector_(
+ MakeGarbageCollected<TextPaintTimingDetector>(frame_view)),
+ image_paint_timing_detector_(
+ MakeGarbageCollected<ImagePaintTimingDetector>(frame_view)){};
void PaintTimingDetector::NotifyPrePaintFinished() {
text_paint_timing_detector_->OnPrePaintFinished();
@@ -51,6 +54,28 @@ void PaintTimingDetector::NotifyNodeRemoved(const LayoutObject& object) {
DOMNodeIds::IdForNode(object.GetNode()));
}
+void PaintTimingDetector::NotifyInputEvent(WebInputEvent::Type type) {
+ if (type == WebInputEvent::kMouseMove || type == WebInputEvent::kMouseEnter ||
+ type == WebInputEvent::kMouseLeave ||
+ WebInputEvent::IsPinchGestureEventType(type)) {
+ return;
+ }
+ text_paint_timing_detector_->StopRecordEntries();
+ image_paint_timing_detector_->StopRecordEntries();
+}
+
+void PaintTimingDetector::NotifyScroll(ScrollType scroll_type) {
+ if (scroll_type != kUserScroll && scroll_type != kCompositorScroll)
+ return;
+ text_paint_timing_detector_->StopRecordEntries();
+ image_paint_timing_detector_->StopRecordEntries();
+}
+
+bool PaintTimingDetector::NeedToNotifyInputOrScroll() {
+ return text_paint_timing_detector_->IsRecording() ||
+ image_paint_timing_detector_->IsRecording();
+}
+
void PaintTimingDetector::DidChangePerformanceTiming() {
Document* document = frame_view_->GetFrame().GetDocument();
if (!document)
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
index 4002f0873b2..78e24f289ca 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -5,8 +5,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
+#include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
namespace blink {
@@ -32,6 +34,9 @@ class CORE_EXPORT PaintTimingDetector
const PaintLayer& painting_layer);
void NotifyNodeRemoved(const LayoutObject& object);
void NotifyPrePaintFinished();
+ void NotifyInputEvent(WebInputEvent::Type);
+ bool NeedToNotifyInputOrScroll();
+ void NotifyScroll(ScrollType scroll_type);
void DidChangePerformanceTiming();
uint64_t CalculateVisualSize(const LayoutRect& invalidated_rect,
const PaintLayer& painting_layer) const;
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index d535454c767..b2fc79bf516 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -16,6 +16,8 @@
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.h"
@@ -58,16 +60,23 @@ void PrePaintTreeWalk::WalkTree(LocalFrameView& root_frame_view) {
context_storage_.pop_back();
#if DCHECK_IS_ON()
- if (!needs_tree_builder_context_update)
- return;
- if (VLOG_IS_ON(2) && root_frame_view.GetLayoutView()) {
- LOG(ERROR) << "PrePaintTreeWalk::Walk(root_frame_view=" << &root_frame_view
- << ")\nPaintLayer tree:";
- showLayerTree(root_frame_view.GetLayoutView()->Layer());
+ if (needs_tree_builder_context_update) {
+ if (VLOG_IS_ON(2) && root_frame_view.GetLayoutView()) {
+ LOG(ERROR) << "PrePaintTreeWalk::Walk(root_frame_view="
+ << &root_frame_view << ")\nPaintLayer tree:";
+ showLayerTree(root_frame_view.GetLayoutView()->Layer());
+ }
+ if (VLOG_IS_ON(1))
+ showAllPropertyTrees(root_frame_view);
}
- if (VLOG_IS_ON(1))
- showAllPropertyTrees(root_frame_view);
#endif
+
+ // If the frame is invalidated, we need to inform the frame's chrome client
+ // so that the client will initiate repaint of the contents.
+ if (needs_invalidate_chrome_client_) {
+ if (auto* client = root_frame_view.GetChromeClient())
+ client->InvalidateRect(IntRect(IntPoint(), root_frame_view.Size()));
+ }
}
void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
@@ -107,11 +116,6 @@ void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
if (context().tree_builder_context) {
PaintPropertyTreeBuilder::SetupContextForFrame(
frame_view, *context().tree_builder_context);
- }
- paint_invalidator_.InvalidatePaint(
- frame_view, base::OptionalOrNullptr(context().tree_builder_context),
- context().paint_invalidator_context);
- if (context().tree_builder_context) {
context().tree_builder_context->supports_composited_raster_invalidation =
frame_view.GetFrame().GetSettings()->GetAcceleratedCompositingEnabled();
}
@@ -131,7 +135,7 @@ void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
#endif
}
- if (RuntimeEnabledFeatures::JankTrackingEnabled())
+ if (origin_trials::JankTrackingEnabled(frame_view.GetFrame().GetDocument()))
frame_view.GetJankTracker().NotifyPrePaintFinished();
if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) {
frame_view.GetPaintTimingDetector().NotifyPrePaintFinished();
@@ -227,7 +231,7 @@ void PrePaintTreeWalk::InvalidatePaintForHitTesting(
void PrePaintTreeWalk::UpdateAuxiliaryObjectProperties(
const LayoutObject& object,
PrePaintTreeWalk::PrePaintTreeWalkContext& context) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
if (!object.HasLayer())
@@ -268,7 +272,7 @@ bool PrePaintTreeWalk::NeedsTreeBuilderContextUpdate(
const LocalFrameView& frame_view,
const PrePaintTreeWalkContext& context) {
if ((RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) &&
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) &&
frame_view.GetFrame().IsLocalRoot() &&
frame_view.GetPage()->GetVisualViewport().NeedsPaintPropertyUpdate())
return true;
@@ -339,9 +343,10 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
// depends on the effective whitelisted touch action.
UpdateEffectiveWhitelistedTouchAction(object, context);
- paint_invalidator_.InvalidatePaint(
- object, base::OptionalOrNullptr(context.tree_builder_context),
- paint_invalidator_context);
+ if (paint_invalidator_.InvalidatePaint(
+ object, base::OptionalOrNullptr(context.tree_builder_context),
+ paint_invalidator_context))
+ needs_invalidate_chrome_client_ = true;
InvalidatePaintForHitTesting(object, context);
@@ -350,7 +355,9 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
InvalidatePaintLayerOptimizationsIfNeeded(object, context);
if (property_changed) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ object.GetFrameView()->SetPaintArtifactCompositorNeedsUpdate();
+
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto* paint_invalidation_layer =
paint_invalidator_context.paint_invalidation_container->Layer();
if (!paint_invalidation_layer->NeedsRepaint()) {
@@ -370,7 +377,7 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
CompositingLayerPropertyUpdater::Update(object);
- if (RuntimeEnabledFeatures::JankTrackingEnabled()) {
+ if (origin_trials::JankTrackingEnabled(&object.GetDocument())) {
object.GetFrameView()->GetJankTracker().NotifyObjectPrePaint(
object, paint_invalidator_context.old_visual_rect,
*paint_invalidator_context.painting_layer);
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
index 3a0f2a5792f..5dbf2e9312a 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
@@ -115,6 +115,8 @@ class CORE_EXPORT PrePaintTreeWalk {
PaintInvalidator paint_invalidator_;
Vector<PrePaintTreeWalkContext> context_storage_;
+ bool needs_invalidate_chrome_client_ = false;
+
FRIEND_TEST_ALL_PREFIXES(PrePaintTreeWalkTest, ClipRects);
};
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
index 9e7fd97d66f..542f008a395 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/paint/pre_paint_tree_walk.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/layout/layout_tree_as_text.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -303,14 +303,8 @@ TEST_P(PrePaintTreeWalkTest, ClipChangeHasRadius) {
}
namespace {
-class PrePaintTreeWalkMockEventListener final : public EventListener {
+class PrePaintTreeWalkMockEventListener final : public NativeEventListener {
public:
- PrePaintTreeWalkMockEventListener() : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
void Invoke(ExecutionContext*, Event*) final {}
};
} // namespace
@@ -344,7 +338,7 @@ TEST_P(PrePaintTreeWalkTest, InsideBlockingTouchEventHandlerUpdate) {
EXPECT_FALSE(descendant.InsideBlockingTouchEventHandler());
PrePaintTreeWalkMockEventListener* callback =
- new PrePaintTreeWalkMockEventListener();
+ MakeGarbageCollected<PrePaintTreeWalkMockEventListener>();
auto* handler_element = GetDocument().getElementById("handler");
handler_element->addEventListener(event_type_names::kTouchstart, callback);
diff --git a/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc b/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
index c94a14b0101..363907839c7 100644
--- a/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -56,11 +56,8 @@ ScopedReplacedContentPaintState::ScopedReplacedContentPaintState(
property_changed = true;
}
- bool painter_implements_content_box_clip = replaced.IsLayoutImage();
- if (paint_properties->OverflowClip() &&
- (!painter_implements_content_box_clip ||
- replaced.StyleRef().HasBorderRadius())) {
- new_properties.SetClip(paint_properties->OverflowClip());
+ if (const auto* clip = paint_properties->OverflowClip()) {
+ new_properties.SetClip(clip);
property_changed = true;
}
@@ -157,9 +154,10 @@ void ReplacedPainter::Paint(const PaintInfo& paint_info) {
!layout_replaced_.IsSelected())
return;
- bool skip_clip = layout_replaced_.IsSVGRoot() &&
- !ToLayoutSVGRoot(layout_replaced_).ShouldApplyViewportClip();
- if (skip_clip || !layout_replaced_.PhysicalContentBoxRect().IsEmpty()) {
+ bool has_clip =
+ layout_replaced_.FirstFragment().PaintProperties() &&
+ layout_replaced_.FirstFragment().PaintProperties()->OverflowClip();
+ if (!has_clip || !layout_replaced_.PhysicalContentBoxRect().IsEmpty()) {
ScopedReplacedContentPaintState content_paint_state(paint_state,
layout_replaced_);
layout_replaced_.PaintReplaced(content_paint_state.GetPaintInfo(),
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
index 5c97cec87a4..fd362f8241c 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
@@ -61,9 +61,9 @@ bool ScopedSVGPaintState::ApplyClipMaskAndFilterIfNecessary() {
DCHECK(!apply_clip_mask_and_filter_if_necessary_called_);
apply_clip_mask_and_filter_if_necessary_called_ = true;
#endif
- // In SPv2 we should early exit once the paint property state has been
+ // In CAP we should early exit once the paint property state has been
// applied, because all meta (non-drawing) display items are ignored in
- // SPv2. However we can't simply omit them because there are still
+ // CAP. However we can't simply omit them because there are still
// non-composited painting (e.g. SVG filters in particular) that rely on
// these meta display items.
ApplyPaintPropertyState();
diff --git a/chromium/third_party/blink/renderer/core/paint/stub_chrome_client_for_spv2.h b/chromium/third_party/blink/renderer/core/paint/stub_chrome_client_for_cap.h
index f16792d620f..96db31bf235 100644
--- a/chromium/third_party/blink/renderer/core/paint/stub_chrome_client_for_spv2.h
+++ b/chromium/third_party/blink/renderer/core/paint/stub_chrome_client_for_cap.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 THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_STUB_CHROME_CLIENT_FOR_SPV2_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_STUB_CHROME_CLIENT_FOR_SPV2_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_STUB_CHROME_CLIENT_FOR_CAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_STUB_CHROME_CLIENT_FOR_CAP_H_
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/platform/testing/layer_tree_host_embedder.h"
@@ -17,7 +17,7 @@ namespace blink {
// A simple ChromeClient implementation which forwards painted artifacts to a
// PaintArtifactCompositor attached to a testing cc::LayerTreeHost, and permits
// simple analysis of the results.
-class StubChromeClientForSPv2 : public EmptyChromeClient {
+class StubChromeClientForCAP : public EmptyChromeClient {
public:
bool HasLayer(const cc::Layer& layer) {
return layer.layer_tree_host() == layer_tree_.layer_tree_host();
@@ -34,4 +34,4 @@ class StubChromeClientForSPv2 : public EmptyChromeClient {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_STUB_CHROME_CLIENT_FOR_SPV2_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_STUB_CHROME_CLIENT_FOR_CAP_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
index d077d2e646e..0d47ef45466 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
@@ -56,16 +56,12 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
const LayoutImageResource* image_resource = layout_svg_image_.ImageResource();
- // TODO(fs): Reduce the number of conversions.
- // (FloatSize -> IntSize -> LayoutSize currently.)
- FloatSize float_image_viewport_size = ComputeImageViewportSize();
- float_image_viewport_size.Scale(layout_svg_image_.StyleRef().EffectiveZoom());
- IntSize image_viewport_size = ExpandedIntSize(float_image_viewport_size);
+ FloatSize image_viewport_size = ComputeImageViewportSize();
+ image_viewport_size.Scale(layout_svg_image_.StyleRef().EffectiveZoom());
if (image_viewport_size.IsEmpty())
return;
- scoped_refptr<Image> image =
- image_resource->GetImage(LayoutSize(image_viewport_size));
+ scoped_refptr<Image> image = image_resource->GetImage(image_viewport_size);
FloatRect dest_rect = layout_svg_image_.ObjectBoundingBox();
FloatRect src_rect(0, 0, image->width(), image->height());
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc
index e842ed1e7fd..d3fe7d5945b 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
namespace blink {
@@ -15,7 +16,8 @@ void SVGObjectPainter::PaintResourceSubtree(GraphicsContext& context) {
PaintInfo info(context, LayoutRect::InfiniteIntRect(),
PaintPhase::kForeground, kGlobalPaintNormalPhase,
- kPaintLayerPaintingRenderingResourceSubtree);
+ kPaintLayerPaintingRenderingResourceSubtree,
+ &layout_object_.PaintingLayer()->GetLayoutObject());
layout_object_.Paint(info);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/table_cell_painter.cc b/chromium/third_party/blink/renderer/core/paint/table_cell_painter.cc
index e655bdb0c9b..31e0fc3055b 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_cell_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_cell_painter.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
@@ -61,8 +62,7 @@ void TableCellPainter::PaintBackground(const PaintInfo& paint_info,
}
BackgroundImageGeometry geometry(layout_table_cell_, &background_object);
BoxModelObjectPainter(layout_table_cell_)
- .PaintFillLayers(paint_info, c, bg_layer, paint_rect, geometry,
- kBackgroundBleedNone, SkBlendMode::kSrcOver);
+ .PaintFillLayers(paint_info, c, bg_layer, paint_rect, geometry);
}
}
@@ -76,27 +76,48 @@ void TableCellPainter::PaintBoxDecorationBackground(
!layout_table_cell_.FirstChild())
return;
+ bool is_painting_scrolling_background =
+ BoxModelObjectPainter::IsPaintingScrollingBackground(&layout_table_cell_,
+ paint_info);
+ const DisplayItemClient* client = nullptr;
+ LayoutRect paint_rect;
+ base::Optional<ScopedBoxContentsPaintState> contents_paint_state;
+ if (is_painting_scrolling_background) {
+ // See BoxPainter::PaintBoxDecorationBackground() for explanations.
+ // TODO(wangxianzhu): Perhaps we can merge them for CompositeAfterPaint.
+ paint_rect = layout_table_cell_.PhysicalLayoutOverflowRect();
+ contents_paint_state.emplace(paint_info, paint_offset, layout_table_cell_);
+ paint_rect.MoveBy(contents_paint_state->PaintOffset());
+ paint_rect.Expand(layout_table_cell_.BorderBoxOutsets());
+ client = &layout_table_cell_.GetScrollableArea()
+ ->GetScrollingBackgroundDisplayItemClient();
+ } else {
+ paint_rect = PaintRectNotIncludingVisualOverflow(paint_offset);
+ client = &layout_table_cell_;
+ }
+
bool has_background = style.HasBackground();
- bool has_box_shadow = style.BoxShadow();
- bool needs_to_paint_border =
- style.HasBorderDecoration() && !table->ShouldCollapseBorders();
- if (has_background || has_box_shadow || needs_to_paint_border) {
+ bool should_paint_box_shadow =
+ !is_painting_scrolling_background && style.BoxShadow();
+ bool should_paint_border = !is_painting_scrolling_background &&
+ style.HasBorderDecoration() &&
+ !table->ShouldCollapseBorders();
+
+ if (has_background || should_paint_box_shadow || should_paint_border) {
if (!DrawingRecorder::UseCachedDrawingIfPossible(
- paint_info.context, layout_table_cell_,
+ paint_info.context, *client,
DisplayItem::kBoxDecorationBackground)) {
// TODO(chrishtr): the pixel-snapping here is likely incorrect.
- DrawingRecorder recorder(paint_info.context, layout_table_cell_,
+ DrawingRecorder recorder(paint_info.context, *client,
DisplayItem::kBoxDecorationBackground);
- LayoutRect paint_rect = PaintRectNotIncludingVisualOverflow(paint_offset);
-
- if (has_box_shadow)
+ if (should_paint_box_shadow)
BoxPainterBase::PaintNormalBoxShadow(paint_info, paint_rect, style);
if (has_background)
PaintBackground(paint_info, paint_rect, layout_table_cell_);
- if (has_box_shadow) {
+ if (should_paint_box_shadow) {
// If the table collapses borders, the inner rect is the border box rect
// inset by inner half widths of collapsed borders (which are returned
// from the overriden BorderXXX() methods). Otherwise the following code
@@ -109,7 +130,7 @@ void TableCellPainter::PaintBoxDecorationBackground(
paint_info, inner_rect, layout_table_cell_.StyleRef());
}
- if (needs_to_paint_border) {
+ if (should_paint_border) {
BoxPainterBase::PaintBorder(
layout_table_cell_, layout_table_cell_.GetDocument(),
layout_table_cell_.GeneratingNode(), paint_info, paint_rect, style);
@@ -118,9 +139,8 @@ void TableCellPainter::PaintBoxDecorationBackground(
}
if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
- LayoutRect rect = PaintRectNotIncludingVisualOverflow(paint_offset);
BoxPainter(layout_table_cell_)
- .RecordHitTestData(paint_info, rect, layout_table_cell_);
+ .RecordHitTestData(paint_info, paint_rect, *client);
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
index 200f2aca79f..107bf4fc03f 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
@@ -36,8 +36,7 @@ TEST_P(TablePainterTest, Background) {
InvalidateAll(RootPaintController());
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- IntRect interest_rect(0, 0, 200, 200);
- Paint(&interest_rect);
+ Paint(IntRect(0, 0, 200, 200));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -46,8 +45,7 @@ TEST_P(TablePainterTest, Background) {
IsSameId(&row1, DisplayItem::kBoxDecorationBackground)));
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- interest_rect = IntRect(0, 300, 200, 1000);
- Paint(&interest_rect);
+ Paint(IntRect(0, 300, 200, 1000));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -81,8 +79,7 @@ TEST_P(TablePainterTest, BackgroundWithCellSpacing) {
InvalidateAll(RootPaintController());
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects cell1 and the spacing between cell1 and cell2.
- IntRect interest_rect(0, 200, 200, 150);
- Paint(&interest_rect);
+ Paint(IntRect(0, 200, 200, 150));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -93,8 +90,7 @@ TEST_P(TablePainterTest, BackgroundWithCellSpacing) {
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects the spacing only.
- interest_rect = IntRect(0, 250, 100, 100);
- Paint(&interest_rect);
+ Paint(IntRect(0, 250, 100, 100));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -104,8 +100,7 @@ TEST_P(TablePainterTest, BackgroundWithCellSpacing) {
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects cell2 only.
- interest_rect = IntRect(0, 350, 200, 150);
- Paint(&interest_rect);
+ Paint(IntRect(0, 350, 200, 150));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -137,8 +132,7 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
InvalidateAll(RootPaintController());
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects cell1 and the spacing between cell1 and cell2.
- IntRect interest_rect(200, 0, 200, 200);
- Paint(&interest_rect);
+ Paint(IntRect(200, 0, 200, 200));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -149,8 +143,7 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects the spacing only.
- interest_rect = IntRect(300, 0, 100, 100);
- Paint(&interest_rect);
+ Paint(IntRect(300, 0, 100, 100));
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
@@ -158,8 +151,7 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects cell2 only.
- interest_rect = IntRect(450, 0, 200, 200);
- Paint(&interest_rect);
+ Paint(IntRect(450, 0, 200, 200));
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -183,12 +175,10 @@ TEST_P(TablePainterTest, CollapsedBorderAndOverflow) {
)HTML");
auto& cell = *ToLayoutTableCell(GetLayoutObjectByElementId("cell"));
-
InvalidateAll(RootPaintController());
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
// Intersects the overflowing part of cell but not border box.
- IntRect interest_rect(0, 0, 100, 100);
- Paint(&interest_rect);
+ Paint(IntRect(0, 0, 100, 100));
// We should paint all display items of cell.
EXPECT_THAT(
diff --git a/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc b/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc
index 78f6d2826a8..bd02fbf4c34 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc
@@ -202,15 +202,16 @@ void TableSectionPainter::PaintObject(const PaintInfo& paint_info,
dirtied_columns.Start() >= dirtied_columns.End())
return;
- const auto& overflowing_cells = layout_table_section_.OverflowingCells();
- if (overflowing_cells.IsEmpty()) {
+ const auto& visually_overflowing_cells =
+ layout_table_section_.VisuallyOverflowingCells();
+ if (visually_overflowing_cells.IsEmpty()) {
// This path is for 2 cases:
// 1. Normal partial paint, without overflowing cells;
// 2. Full paint, for small sections or big sections with many overflowing
// cells.
// The difference between the normal partial paint and full paint is that
// whether dirtied_rows and dirtied_columns cover the whole section.
- DCHECK(!layout_table_section_.HasOverflowingCell() ||
+ DCHECK(!layout_table_section_.HasVisuallyOverflowingCell() ||
(dirtied_rows == layout_table_section_.FullSectionRowSpan() &&
dirtied_columns ==
layout_table_section_.FullTableEffectiveColumnSpan()));
@@ -235,7 +236,7 @@ void TableSectionPainter::PaintObject(const PaintInfo& paint_info,
// This is the "partial paint path" for overflowing cells referred in
// LayoutTableSection::ComputeOverflowFromDescendants().
Vector<const LayoutTableCell*> cells;
- CopyToVector(overflowing_cells, cells);
+ CopyToVector(visually_overflowing_cells, cells);
HashSet<const LayoutTableCell*> spanning_cells;
for (unsigned r = dirtied_rows.Start(); r < dirtied_rows.End(); r++) {
@@ -250,7 +251,7 @@ void TableSectionPainter::PaintObject(const PaintInfo& paint_info,
for (unsigned c = dirtied_columns.Start();
c < n_cols && c < dirtied_columns.End(); c++) {
if (const auto* cell = layout_table_section_.OriginatingCellAt(r, c)) {
- if (!overflowing_cells.Contains(cell))
+ if (!visually_overflowing_cells.Contains(cell))
cells.push_back(cell);
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
index 88adcefd481..c5baafdbca7 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -45,9 +45,11 @@ void TextPaintTimingDetector::PopulateTraceValue(
TracedValue& value,
const TextRecord& first_text_paint,
unsigned candidate_index) const {
- value.SetInteger("DOMNodeId", first_text_paint.node_id);
+ value.SetInteger("DOMNodeId", static_cast<int>(first_text_paint.node_id));
+#ifndef NDEBUG
value.SetString("text", first_text_paint.text);
- value.SetInteger("size", first_text_paint.first_size);
+#endif
+ value.SetInteger("size", static_cast<int>(first_text_paint.first_size));
value.SetInteger("candidateIndex", candidate_index);
value.SetString("frame",
IdentifiersFactory::FrameId(&frame_view_->GetFrame()));
@@ -56,7 +58,7 @@ void TextPaintTimingDetector::PopulateTraceValue(
void TextPaintTimingDetector::OnLargestTextDetected(
const TextRecord& largest_text_record) {
largest_text_paint_ = largest_text_record.first_paint_time;
-
+ largest_text_paint_size_ = largest_text_record.first_size;
std::unique_ptr<TracedValue> value = TracedValue::Create();
PopulateTraceValue(*value, largest_text_record,
largest_text_candidate_index_max_++);
@@ -68,6 +70,7 @@ void TextPaintTimingDetector::OnLargestTextDetected(
void TextPaintTimingDetector::OnLastTextDetected(
const TextRecord& last_text_record) {
last_text_paint_ = last_text_record.first_paint_time;
+ last_text_paint_size_ = last_text_record.first_size;
std::unique_ptr<TracedValue> value = TracedValue::Create();
PopulateTraceValue(*value, last_text_record,
@@ -86,12 +89,16 @@ void TextPaintTimingDetector::TimerFired(TimerBase* time) {
void TextPaintTimingDetector::Analyze() {
TextRecord* largest_text_first_paint = FindLargestPaintCandidate();
bool new_candidate_detected = false;
+ DCHECK(!largest_text_first_paint ||
+ !largest_text_first_paint->first_paint_time.is_null());
if (largest_text_first_paint &&
largest_text_first_paint->first_paint_time != largest_text_paint_) {
OnLargestTextDetected(*largest_text_first_paint);
new_candidate_detected = true;
}
TextRecord* last_text_first_paint = FindLastPaintCandidate();
+ DCHECK(!last_text_first_paint ||
+ !last_text_first_paint->first_paint_time.is_null());
if (last_text_first_paint &&
last_text_first_paint->first_paint_time != last_text_paint_) {
OnLastTextDetected(*last_text_first_paint);
@@ -117,6 +124,12 @@ void TextPaintTimingDetector::OnPrePaintFinished() {
}
void TextPaintTimingDetector::NotifyNodeRemoved(DOMNodeId node_id) {
+ if (!is_recording_)
+ return;
+ for (TextRecord& record : texts_to_record_swap_time_) {
+ if (record.node_id == node_id)
+ record.node_id = kInvalidDOMNodeId;
+ }
if (recorded_text_node_ids_.find(node_id) == recorded_text_node_ids_.end())
return;
// We assume that removed nodes' id would not be recycled, and it's expensive
@@ -161,6 +174,8 @@ void TextPaintTimingDetector::ReportSwapTime(
// that only one or zero callback will be called after one OnPrePaintFinished.
DCHECK_GT(texts_to_record_swap_time_.size(), 0UL);
for (TextRecord& record : texts_to_record_swap_time_) {
+ if (record.node_id == kInvalidDOMNodeId)
+ continue;
record.first_paint_time = timestamp;
recorded_text_node_ids_.insert(record.node_id);
largest_text_heap_.push(std::make_unique<TextRecord>(record));
@@ -201,23 +216,27 @@ void TextPaintTimingDetector::RecordText(const LayoutObject& object,
size_zero_node_ids_.insert(node_id);
} else {
// Non-trivial text is found.
- TextRecord record = {node_id, rect_size, base::TimeTicks(),
- ToLayoutText(&object)->GetText()};
+ TextRecord record;
+ record.node_id = node_id;
+ record.first_size = rect_size;
+#ifndef NDEBUG
+ record.text = ToLayoutText(&object)->GetText();
+#endif
texts_to_record_swap_time_.push_back(record);
}
if (recorded_text_node_ids_.size() + size_zero_node_ids_.size() +
texts_to_record_swap_time_.size() >=
kTextNodeNumberLimit) {
- Deactivate();
+ TRACE_EVENT_INSTANT2("loading", "TextPaintTimingDetector::OverNodeLimit",
+ TRACE_EVENT_SCOPE_THREAD, "recorded_node_count",
+ recorded_text_node_ids_.size(), "size_zero_node_count",
+ size_zero_node_ids_.size());
+ StopRecordEntries();
}
}
-void TextPaintTimingDetector::Deactivate() {
- TRACE_EVENT_INSTANT2("loading", "TextPaintTimingDetector::OverNodeLimit",
- TRACE_EVENT_SCOPE_THREAD, "recorded_node_count",
- recorded_text_node_ids_.size(), "size_zero_node_count",
- size_zero_node_ids_.size());
+void TextPaintTimingDetector::StopRecordEntries() {
timer_.Stop();
is_recording_ = false;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
index d009f65a73c..84034207c02 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -22,7 +22,9 @@ struct TextRecord {
DOMNodeId node_id = kInvalidDOMNodeId;
uint64_t first_size = 0;
base::TimeTicks first_paint_time = base::TimeTicks();
+#ifndef NDEBUG
String text = "";
+#endif
};
// TextPaintTimingDetector contains Largest Text Paint and Last Text Paint.
@@ -62,7 +64,11 @@ class CORE_EXPORT TextPaintTimingDetector final
void NotifyNodeRemoved(DOMNodeId);
void Dispose() { timer_.Stop(); }
base::TimeTicks LargestTextPaint() const { return largest_text_paint_; }
+ uint64_t LargestTextPaintSize() const { return largest_text_paint_size_; }
base::TimeTicks LastTextPaint() const { return last_text_paint_; }
+ uint64_t LastTextPaintSize() const { return last_text_paint_size_; }
+ void StopRecordEntries();
+ bool IsRecording() const { return is_recording_; }
void Trace(blink::Visitor*);
private:
@@ -77,7 +83,6 @@ class CORE_EXPORT TextPaintTimingDetector final
void RegisterNotifySwapTime(ReportTimeCallback callback);
void OnLargestTextDetected(const TextRecord&);
void OnLastTextDetected(const TextRecord&);
- void Deactivate();
HashSet<DOMNodeId> recorded_text_node_ids_;
HashSet<DOMNodeId> size_zero_node_ids_;
@@ -100,7 +105,9 @@ class CORE_EXPORT TextPaintTimingDetector final
bool is_recording_ = true;
base::TimeTicks largest_text_paint_;
+ uint64_t largest_text_paint_size_ = 0;
base::TimeTicks last_text_paint_;
+ uint64_t last_text_paint_size_ = 0;
TaskRunnerTimer<TextPaintTimingDetector> timer_;
Member<LocalFrameView> frame_view_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
index 2b2f395d437..496c9a76dcf 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -24,6 +24,19 @@ class TextPaintTimingDetectorTest
return GetFrameView().GetPaintTimingDetector();
}
+ unsigned CountRecords() {
+ return GetPaintTimingDetector()
+ .GetTextPaintTimingDetector()
+ .recorded_text_node_ids_.size();
+ }
+
+ void InvokeCallback() {
+ TextPaintTimingDetector& detector =
+ GetPaintTimingDetector().GetTextPaintTimingDetector();
+ detector.ReportSwapTime(WebLayerTreeView::SwapResult::kDidSwap,
+ CurrentTimeTicks());
+ }
+
TimeTicks LargestPaintStoredResult() {
return GetPaintTimingDetector()
.GetTextPaintTimingDetector()
@@ -50,49 +63,103 @@ class TextPaintTimingDetectorTest
void SimulateAnalyze() {
GetPaintTimingDetector().GetTextPaintTimingDetector().Analyze();
}
+
+ Element* AppendFontElementToBody(String content) {
+ Element* element = GetDocument().CreateRawElement(html_names::kFontTag);
+ element->setAttribute(html_names::kSizeAttr, AtomicString("5"));
+ Text* text = GetDocument().createTextNode(content);
+ element->AppendChild(text);
+ GetDocument().body()->AppendChild(element);
+ return element;
+ }
+
+ Element* AppendDivElementToBody(String content, String style = "") {
+ Element* div = GetDocument().CreateRawElement(html_names::kDivTag);
+ div->setAttribute(html_names::kStyleAttr, AtomicString(style));
+ Text* text = GetDocument().createTextNode(content);
+ div->AppendChild(text);
+ GetDocument().body()->AppendChild(div);
+ return div;
+ }
+
+ DOMNodeId NodeIdOfText(Element* element) {
+ DCHECK_EQ(element->CountChildren(), 1u);
+ DCHECK(element->firstChild()->IsTextNode());
+ DCHECK(!element->firstChild()->hasChildren());
+ return DOMNodeIds::IdForNode(element->firstChild());
+ }
+
+ TextRecord* TextRecordOfLargestTextPaint() {
+ return GetPaintTimingDetector()
+ .GetTextPaintTimingDetector()
+ .FindLargestPaintCandidate();
+ }
+
+ TextRecord* TextRecordOfLastTextPaint() {
+ return GetPaintTimingDetector()
+ .GetTextPaintTimingDetector()
+ .FindLastPaintCandidate();
+ }
+
+ void SetFontSize(Element* font_element, uint8_t font_size) {
+ DCHECK_EQ(font_element->nodeName(), "FONT");
+ font_element->setAttribute(html_names::kSizeAttr,
+ AtomicString(WTF::String::Number(font_size)));
+ }
+
+ void SetElementStyle(Element* element, String style) {
+ element->setAttribute(html_names::kStyleAttr, AtomicString(style));
+ }
+
+ void RemoveElement(Element* element) {
+ element->GetLayoutObject()->Parent()->GetNode()->removeChild(element);
+ }
};
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_NoText) {
SetBodyInnerHTML(R"HTML(
- <div></div>
+ <body></body>
)HTML");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_FALSE(record);
+ EXPECT_FALSE(TextRecordOfLargestTextPaint());
}
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_OneText) {
SetBodyInnerHTML(R"HTML(
- <div>The only text</div>
+ <body></body>
)HTML");
+ Element* only_text = AppendDivElementToBody("The only text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_TRUE(record);
- EXPECT_EQ(record->text, "The only text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(only_text));
+}
+
+TEST_F(TextPaintTimingDetectorTest, NodeRemovedBeforeAssigningSwapTime) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="parent">
+ <div id="remove">The only text</div>
+ </div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+ GetDocument().getElementById("parent")->RemoveChild(
+ GetDocument().getElementById("remove"));
+ InvokeCallback();
+ EXPECT_EQ(CountRecords(), 0u);
}
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_LargestText) {
SetBodyInnerHTML(R"HTML(
- <div>medium text</div>
+ <body></body>
)HTML");
+ AppendDivElementToBody("medium text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- Text* larger_text = GetDocument().createTextNode("a long-long-long text");
- GetDocument().body()->AppendChild(larger_text);
+ Element* large_text = AppendDivElementToBody("a long-long-long text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- Text* tiny_text = GetDocument().createTextNode("small");
- GetDocument().body()->AppendChild(tiny_text);
+ AppendDivElementToBody("small");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_EQ(record->text, "a long-long-long text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(large_text));
}
TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) {
@@ -126,26 +193,24 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) {
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportFirstPaintTime) {
TimeTicks time1 = CurrentTimeTicks();
SetBodyInnerHTML(R"HTML(
- <div>
- <div id='b'>size-changing block</div>
- <div>a long-long-long-long moving text</div>
- </div>
+ <body></body>
)HTML");
+ Element* size_changing_text = AppendFontElementToBody("size-changing text");
+ Element* long_text =
+ AppendFontElementToBody("a long-long-long-long moving text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
TimeTicks time2 = CurrentTimeTicks();
- GetDocument().getElementById("b")->setAttribute(html_names::kStyleAttr,
- AtomicString("height:50px"));
+ SetFontSize(size_changing_text, 50);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- GetDocument().getElementById("b")->setAttribute(html_names::kStyleAttr,
- AtomicString("height:100px"));
+ SetFontSize(long_text, 100);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
TextRecord* record = GetPaintTimingDetector()
.GetTextPaintTimingDetector()
.FindLargestPaintCandidate();
- EXPECT_EQ(record->text, "a long-long-long-long moving text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(long_text));
TimeTicks firing_time = record->first_paint_time;
EXPECT_GE(firing_time, time1);
EXPECT_GE(time2, firing_time);
@@ -173,89 +238,62 @@ TEST_F(TextPaintTimingDetectorTest,
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_IgnoreRemovedText) {
SetBodyInnerHTML(R"HTML(
- <div id='parent'>
- <div id='earlyLargeText'>(large text)(large text)(large text)(large text)(large text)(large text)</div>
- <div>small text</div>
- </div>
+ <body></body>
)HTML");
+ Element* large_text = AppendDivElementToBody(
+ "(large text)(large text)(large text)(large text)(large text)(large "
+ "text)");
+ Element* small_text = AppendDivElementToBody("small text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_TRUE(record);
- EXPECT_EQ(record->text,
- "(large text)(large text)(large text)(large text)(large "
- "text)(large text)");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(large_text));
- GetDocument().getElementById("parent")->RemoveChild(
- GetDocument().getElementById("earlyLargeText"));
+ RemoveElement(large_text);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_EQ(record->text, "small text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(small_text));
}
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) {
SetBodyInnerHTML(R"HTML(
- <div id='parent'>
- <div id='remove'>text</div>
- </div>
+ <body></body>
)HTML");
+ Element* text = AppendDivElementToBody("text to remove");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
SimulateAnalyze();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_TRUE(record);
- EXPECT_EQ(record->text, "text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(text));
EXPECT_NE(LargestPaintStoredResult(), base::TimeTicks());
- GetDocument().getElementById("parent")->RemoveChild(
- GetDocument().getElementById("remove"));
+ RemoveElement(text);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
SimulateAnalyze();
- record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_FALSE(record);
+ EXPECT_FALSE(TextRecordOfLargestTextPaint());
EXPECT_EQ(LargestPaintStoredResult(), base::TimeTicks());
}
TEST_F(TextPaintTimingDetectorTest,
LargestTextPaint_CompareVisualSizeNotActualSize) {
SetBodyInnerHTML(R"HTML(
- <div>
- <div>short</div>
- <div style="position:fixed;left:-10px">a long text</div>
- </div>
+ <body></body>
)HTML");
+ AppendDivElementToBody("a long text", "position:fixed;left:-10px");
+ Element* short_text = AppendDivElementToBody("short");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_EQ(record->text, "short");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(short_text));
}
+// Depite that the l
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_CompareSizesAtFirstPaint) {
SetBodyInnerHTML(R"HTML(
- <div>
- <div id="shorteningText">large-to-small text</div>
- <div>a medium text</div>
- </div>
+ <body></body>
)HTML");
+ Element* shortening_long_text = AppendDivElementToBody("123456789");
+ AppendDivElementToBody("12345678"); // 1 letter shorter than the above.
UpdateAllLifecyclePhasesAndSimulateSwapTime();
// The visual size becomes smaller when less portion intersecting with
// viewport.
- GetDocument()
- .getElementById("shorteningText")
- ->setAttribute(html_names::kStyleAttr,
- AtomicString("position:fixed;left:-10px"));
+ SetElementStyle(shortening_long_text, "position:fixed;left:-10px");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_EQ(record->text, "large-to-small text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
+ NodeIdOfText(shortening_long_text));
}
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_NoText) {
@@ -271,61 +309,49 @@ TEST_F(TextPaintTimingDetectorTest, LastTextPaint_NoText) {
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_OneText) {
SetBodyInnerHTML(R"HTML(
- <div>The only text</div>
+ <body></body>
)HTML");
+ Element* text = AppendDivElementToBody("The only text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLastPaintCandidate();
- EXPECT_EQ(record->text, "The only text");
+ EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(text));
}
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_LastText) {
SetBodyInnerHTML(R"HTML(
<div>1st text</div>
)HTML");
+ AppendDivElementToBody("s");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- Text* larger_text = GetDocument().createTextNode("2nd text");
- GetDocument().body()->AppendChild(larger_text);
+ AppendDivElementToBody("loooooooong");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- Text* tiny_text = GetDocument().createTextNode("3rd text");
- GetDocument().body()->AppendChild(tiny_text);
+ Element* third_text = AppendDivElementToBody("medium");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLastPaintCandidate();
- EXPECT_EQ(record->text, "3rd text");
+ EXPECT_EQ(TextRecordOfLastTextPaint()->node_id, NodeIdOfText(third_text));
}
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_ReportFirstPaintTime) {
SetBodyInnerHTML(R"HTML(
- <div>
- <div id='b'>size-changing block</div>
- </div>
+ <body></body>
)HTML");
+ AppendDivElementToBody("a loooooooooooooooooooong text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
TimeTicks time1 = CurrentTimeTicks();
- Text* tiny_text = GetDocument().createTextNode("latest text");
- GetDocument().body()->AppendChild(tiny_text);
+ Element* latest_text = AppendFontElementToBody("latest text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
TimeTicks time2 = CurrentTimeTicks();
- GetDocument().getElementById("b")->setAttribute(html_names::kStyleAttr,
- AtomicString("height:50px"));
+ SetFontSize(latest_text, 50);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- GetDocument().getElementById("b")->setAttribute(html_names::kStyleAttr,
- AtomicString("height:100px"));
+ SetFontSize(latest_text, 100);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLastPaintCandidate();
- EXPECT_EQ(record->text, "latest text");
+ TextRecord* record = TextRecordOfLastTextPaint();
+ EXPECT_EQ(record->node_id, NodeIdOfText(latest_text));
TimeTicks firing_time = record->first_paint_time;
EXPECT_GE(firing_time, time1);
EXPECT_GE(time2, firing_time);
@@ -333,83 +359,53 @@ TEST_F(TextPaintTimingDetectorTest, LastTextPaint_ReportFirstPaintTime) {
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_IgnoreRemovedText) {
SetBodyInnerHTML(R"HTML(
- <body>
- <div>earliest text</div>
- </body>
+ <body></body>
)HTML");
+ Element* first_text = AppendDivElementToBody("1st text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- Text* tiny_text = GetDocument().createTextNode("latest text");
- GetDocument().body()->AppendChild(tiny_text);
+ Element* second_text = AppendDivElementToBody("2nd text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- GetDocument().body()->RemoveChild(GetDocument().body()->lastChild());
+ RemoveElement(second_text);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLastPaintCandidate();
- EXPECT_EQ(record->text, "earliest text");
+ EXPECT_EQ(TextRecordOfLastTextPaint()->node_id, NodeIdOfText(first_text));
}
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_StopRecordingOverNodeLimit) {
SetBodyInnerHTML(R"HTML(
- <body>
- </body>
+ <body></body>
)HTML");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- for (int i = 1; i <= 4999; i++) {
- Element* div = GetDocument().CreateRawElement(html_names::kDivTag);
- div->appendChild(GetDocument().createTextNode(WTF::String::Number(i)));
- div->setAttribute(html_names::kStyleAttr,
- AtomicString("position:fixed;left:0px"));
- GetDocument().body()->AppendChild(div);
- }
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ for (int i = 1; i <= 4999; i++)
+ AppendDivElementToBody(WTF::String::Number(i), "position:fixed;left:0px");
- TextRecord* record;
- Text* text;
+ UpdateAllLifecyclePhasesAndSimulateSwapTime();
- text = GetDocument().createTextNode(WTF::String::Number(5000));
- GetDocument().body()->AppendChild(text);
+ Element* text_5000 = AppendDivElementToBody(WTF::String::Number(5000));
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLastPaintCandidate();
- EXPECT_EQ(record->text, "5000");
+ EXPECT_EQ(TextRecordOfLastTextPaint()->node_id, NodeIdOfText(text_5000));
- text = GetDocument().createTextNode(WTF::String::Number(5001));
- GetDocument().body()->AppendChild(text);
+ AppendDivElementToBody(WTF::String::Number(5001));
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLastPaintCandidate();
- EXPECT_EQ(record->text, "5000");
+ EXPECT_EQ(TextRecordOfLastTextPaint()->node_id, NodeIdOfText(text_5000));
}
TEST_F(TextPaintTimingDetectorTest, LastTextPaint_ReportLastNullCandidate) {
SetBodyInnerHTML(R"HTML(
- <div id='parent'>
- <div id='remove'>text</div>
- </div>
+ <body></body>
)HTML");
+ Element* text = AppendDivElementToBody("text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
SimulateAnalyze();
- TextRecord* record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_TRUE(record);
- EXPECT_EQ(record->text, "text");
+ EXPECT_EQ(TextRecordOfLastTextPaint()->node_id, NodeIdOfText(text));
EXPECT_NE(LastPaintStoredResult(), base::TimeTicks());
- GetDocument().getElementById("parent")->RemoveChild(
- GetDocument().getElementById("remove"));
+ RemoveElement(text);
UpdateAllLifecyclePhasesAndSimulateSwapTime();
SimulateAnalyze();
- record = GetPaintTimingDetector()
- .GetTextPaintTimingDetector()
- .FindLargestPaintCandidate();
- EXPECT_FALSE(record);
+ EXPECT_FALSE(TextRecordOfLastTextPaint());
EXPECT_EQ(LastPaintStoredResult(), base::TimeTicks());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/video_painter.cc b/chromium/third_party/blink/renderer/core/paint/video_painter.cc
index 4ae8687d6eb..4adf6f23499 100644
--- a/chromium/third_party/blink/renderer/core/paint/video_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/video_painter.cc
@@ -38,8 +38,8 @@ void VideoPainter::PaintReplaced(const PaintInfo& paint_info,
return;
GraphicsContext& context = paint_info.context;
- LayoutRect content_rect = layout_video_.PhysicalContentBoxRect();
- content_rect.MoveBy(paint_offset);
+ LayoutRect content_box_rect = layout_video_.PhysicalContentBoxRect();
+ content_box_rect.MoveBy(paint_offset);
// Video frames are only painted in software for printing or capturing node
// images via web APIs.
@@ -48,21 +48,20 @@ void VideoPainter::PaintReplaced(const PaintInfo& paint_info,
bool paint_with_foreign_layer =
!displaying_poster && !force_software_video_paint &&
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled();
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled();
if (paint_with_foreign_layer) {
if (cc::Layer* layer = layout_video_.MediaElement()->CcLayer()) {
- IntRect pixel_snapped_rect = PixelSnappedIntRect(content_rect);
layer->SetOffsetToTransformParent(
- gfx::Vector2dF(pixel_snapped_rect.X(), pixel_snapped_rect.Y()));
- layer->SetBounds(gfx::Size(pixel_snapped_rect.Size()));
+ gfx::Vector2dF(snapped_replaced_rect.X(), snapped_replaced_rect.Y()));
+ layer->SetBounds(gfx::Size(snapped_replaced_rect.Size()));
layer->SetIsDrawable(true);
RecordForeignLayer(context, DisplayItem::kForeignLayerVideo, layer);
+ if (layout_video_.GetFrameView())
+ layout_video_.GetFrameView()->SetPaintArtifactCompositorNeedsUpdate();
return;
}
}
- // TODO(trchen): Video rect could overflow the content rect due to object-fit.
- // Should apply a clip here like EmbeddedObjectPainter does.
DrawingRecorder recorder(context, layout_video_, paint_info.phase);
if (displaying_poster || !force_software_video_paint) {
@@ -70,7 +69,7 @@ void VideoPainter::PaintReplaced(const PaintInfo& paint_info,
// paint nothing.
DCHECK(paint_info.PaintContainer());
ImagePainter(layout_video_)
- .PaintIntoRect(context, replaced_rect, content_rect,
+ .PaintIntoRect(context, replaced_rect, content_box_rect,
paint_info.PaintContainer()->Layer());
} else {
PaintFlags video_flags = context.FillFlags();
diff --git a/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
index 7a445402b80..1a6fe96c6f0 100644
--- a/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
@@ -9,12 +9,12 @@
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
-#include "third_party/blink/renderer/core/paint/stub_chrome_client_for_spv2.h"
+#include "third_party/blink/renderer/core/paint/stub_chrome_client_for_cap.h"
#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
-// Integration tests of video painting code (in SPv2 mode).
+// Integration tests of video painting code (in CAP mode).
namespace blink {
namespace {
@@ -58,13 +58,14 @@ class VideoStubLocalFrameClient : public EmptyLocalFrameClient {
}
};
-class VideoPainterTestForSPv2 : private ScopedSlimmingPaintV2ForTest,
- public PaintControllerPaintTestBase {
+class VideoPainterTestForCAP : private ScopedCompositeAfterPaintForTest,
+ public PaintControllerPaintTestBase {
public:
- VideoPainterTestForSPv2()
- : ScopedSlimmingPaintV2ForTest(true),
- PaintControllerPaintTestBase(new VideoStubLocalFrameClient),
- chrome_client_(new StubChromeClientForSPv2) {}
+ VideoPainterTestForCAP()
+ : ScopedCompositeAfterPaintForTest(true),
+ PaintControllerPaintTestBase(
+ MakeGarbageCollected<VideoStubLocalFrameClient>()),
+ chrome_client_(MakeGarbageCollected<StubChromeClientForCAP>()) {}
void SetUp() override {
PaintControllerPaintTestBase::SetUp();
@@ -79,12 +80,12 @@ class VideoPainterTestForSPv2 : private ScopedSlimmingPaintV2ForTest,
ChromeClient& GetChromeClient() const override { return *chrome_client_; }
private:
- Persistent<StubChromeClientForSPv2> chrome_client_;
+ Persistent<StubChromeClientForCAP> chrome_client_;
};
-TEST_F(VideoPainterTestForSPv2, VideoLayerAppearsInLayerTree) {
+TEST_F(VideoPainterTestForCAP, VideoLayerAppearsInLayerTree) {
// Insert a <video> and allow it to begin loading.
- SetBodyInnerHTML("<video width=300 height=200 src=test.ogv>");
+ SetBodyInnerHTML("<video width=300 height=300 src=test.ogv>");
test::RunPendingTasks();
// Force the page to paint.
@@ -99,7 +100,9 @@ TEST_F(VideoPainterTestForSPv2, VideoLayerAppearsInLayerTree) {
const cc::Layer* layer = player->GetCcLayer();
ASSERT_TRUE(layer);
EXPECT_TRUE(HasLayerAttached(*layer));
- EXPECT_EQ(gfx::Size(300, 200), layer->bounds());
+ // The layer bounds reflects the aspectn ratio and object-fit of the video.
+ EXPECT_EQ(gfx::Vector2dF(8, 83), layer->offset_to_transform_parent());
+ EXPECT_EQ(gfx::Size(300, 150), layer->bounds());
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/core/paint/view_painter.cc b/chromium/third_party/blink/renderer/core/paint/view_painter.cc
index c81a3325fb5..dc42d8d7144 100644
--- a/chromium/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/view_painter.cc
@@ -224,7 +224,7 @@ void ViewPainter::PaintBoxDecorationBackgroundInternal(
if (combined_background_color.Alpha()) {
if (!combined_background_color.HasAlpha() &&
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
recorder.SetKnownToBeOpaque();
context.FillRect(
background_rect, combined_background_color,
diff --git a/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc
index f217354b9a0..7a725587fec 100644
--- a/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc
@@ -49,7 +49,7 @@ void ViewPainterTest::RunFixedBackgroundTest(
DocumentLifecycle::LifecycleUpdateReason::kTest);
const DisplayItem* background_display_item = nullptr;
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto& display_items = RootPaintController().GetDisplayItemList();
if (prefer_compositing_to_lcd_text) {
EXPECT_THAT(
@@ -106,8 +106,6 @@ void ViewPainterTest::RunFixedBackgroundTest(
SkRect rect = static_cast<const cc::DrawRectOp*>(*it)->rect;
if (prefer_compositing_to_lcd_text) {
EXPECT_EQ(SkRect::MakeXYWH(0, 0, 800, 600), rect);
- } else if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
- EXPECT_EQ(SkRect::MakeXYWH(0, 0, 800, 600), rect);
} else {
EXPECT_EQ(SkRect::MakeXYWH(scroll_offset.Width(), scroll_offset.Height(),
800, 600),
@@ -129,7 +127,7 @@ TEST_P(ViewPainterTest, DocumentBackgroundWithScroll) {
<div style='height: 5000px'></div>
)HTML");
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
@@ -210,7 +208,7 @@ TEST_P(ViewPainterTestWithPaintTouchAction, TouchActionRectScrollingContents) {
html_hit_test_data.touch_action_rects.emplace_back(
LayoutRect(0, 0, 800, 3000));
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
HitTestData non_scrolling_hit_test_data;
non_scrolling_hit_test_data.touch_action_rects.emplace_back(
LayoutRect(0, 0, 800, 600));
@@ -282,7 +280,7 @@ TEST_P(ViewPainterTestWithPaintTouchAction,
LayoutRect(0, 0, 800, 3000));
scrolling_hit_test_data.touch_action_rects.emplace_back(
LayoutRect(0, 0, 800, 3000));
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_THAT(
RootPaintController().PaintChunks(),
ElementsAre(
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.cc b/chromium/third_party/blink/renderer/core/probe/core_probes.cc
index e5592129a75..4ed692746a9 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.cc
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.cc
@@ -51,7 +51,8 @@ AsyncTask::AsyncTask(ExecutionContext* context,
void* task,
const char* step,
bool enabled)
- : debugger_(enabled ? ThreadDebugger::From(ToIsolate(context)) : nullptr),
+ : debugger_(enabled && context ? ThreadDebugger::From(context->GetIsolate())
+ : nullptr),
task_(AsyncId(task)),
recurring_(step) {
if (recurring_) {
@@ -80,8 +81,10 @@ void AsyncTaskScheduled(ExecutionContext* context,
TRACE_EVENT_FLOW_BEGIN1("devtools.timeline.async", "AsyncTask",
TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)),
"data", inspector_async_task::Data(name));
- if (ThreadDebugger* debugger = ThreadDebugger::From(ToIsolate(context)))
- debugger->AsyncTaskScheduled(name, AsyncId(task), true);
+ if (context) {
+ if (ThreadDebugger* debugger = ThreadDebugger::From(context->GetIsolate()))
+ debugger->AsyncTaskScheduled(name, AsyncId(task), true);
+ }
}
void AsyncTaskScheduledBreakable(ExecutionContext* context,
@@ -92,7 +95,7 @@ void AsyncTaskScheduledBreakable(ExecutionContext* context,
}
void AsyncTaskCanceled(ExecutionContext* context, void* task) {
- AsyncTaskCanceled(ToIsolate(context), task);
+ AsyncTaskCanceled(context ? context->GetIsolate() : nullptr, task);
}
void AsyncTaskCanceled(v8::Isolate* isolate, void* task) {
@@ -110,8 +113,10 @@ void AsyncTaskCanceledBreakable(ExecutionContext* context,
}
void AllAsyncTasksCanceled(ExecutionContext* context) {
- if (ThreadDebugger* debugger = ThreadDebugger::From(ToIsolate(context)))
- debugger->AllAsyncTasksCanceled();
+ if (context) {
+ if (ThreadDebugger* debugger = ThreadDebugger::From(context->GetIsolate()))
+ debugger->AllAsyncTasksCanceled();
+ }
}
} // namespace probe
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.h b/chromium/third_party/blink/renderer/core/probe/core_probes.h
index affdc6a8829..1e2a421ff39 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.h
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.h
@@ -81,6 +81,10 @@ inline CoreProbeSink* ToCoreProbeSink(Document* document) {
return document ? ToCoreProbeSink(*document) : nullptr;
}
+inline CoreProbeSink* ToCoreProbeSink(CoreProbeSink* sink) {
+ return sink;
+}
+
inline CoreProbeSink* ToCoreProbeSink(ExecutionContext* context) {
return context ? context->GetProbeSink() : nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.json5 b/chromium/third_party/blink/renderer/core/probe/core_probes.json5
index f295c86f873..40ada2cbdf2 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.json5
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.json5
@@ -9,6 +9,7 @@
"third_party/blink/renderer/core/dom/character_data.h",
"third_party/blink/renderer/core/dom/pseudo_element.h",
"third_party/blink/renderer/core/html/html_slot_element.h",
+ "third_party/blink/renderer/core/loader/frame_loader_types.h",
"third_party/blink/renderer/core/page/chrome_client.h",
"third_party/blink/renderer/core/probe/core_probes.h",
],
@@ -129,10 +130,10 @@
"didReceiveEncodedDataLength",
"didReceiveResourceResponse",
"didReceiveScriptResponse",
- "didReceiveWebSocketFrame",
- "didReceiveWebSocketFrameError",
+ "didReceiveWebSocketMessage",
+ "didReceiveWebSocketMessageError",
"didReceiveWebSocketHandshakeResponse",
- "didSendWebSocketFrame",
+ "didSendWebSocketMessage",
"frameClearedScheduledNavigation",
"frameScheduledNavigation",
"markResourceAsCached",
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.pidl b/chromium/third_party/blink/renderer/core/probe/core_probes.pidl
index 8c9517e9a27..a3e17b50ae1 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.pidl
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -57,7 +57,6 @@ interface CoreProbes {
class FontCustomPlatformData;
class FontFace;
class HTMLDocumentParser;
- class ScheduledNavigation;
class ThreadableLoaderClient;
class WorkerInspectorProxy;
class XMLHttpRequest;
@@ -86,23 +85,23 @@ interface CoreProbes {
void didFireWebGLWarning(Element*);
void didFireWebGLErrorOrWarning(Element*, const String& message);
void didResizeMainFrame(LocalFrame*);
- void didPaint(LocalFrame*, const GraphicsLayer*, GraphicsContext&, const LayoutRect&);
- void applyAcceptLanguageOverride(LocalFrame*, String* acceptLanguage);
- void applyUserAgentOverride(ExecutionContext*, String* userAgent);
+ void didPaint(LocalFrame*, const cc::Layer*, GraphicsContext&, const LayoutRect&);
+ void applyAcceptLanguageOverride(ExecutionContext*, String* acceptLanguage);
+ void applyUserAgentOverride(CoreProbeSink*, String* userAgent);
void didBlockRequest([Keep] ExecutionContext*, const ResourceRequest&, DocumentLoader*, const FetchInitiatorInfo&, ResourceRequestBlockedReason, ResourceType);
void didChangeResourcePriority(LocalFrame*, DocumentLoader*, unsigned long identifier, ResourceLoadPriority loadPriority);
void willSendRequest([Keep] ExecutionContext*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const FetchInitiatorInfo&, ResourceType);
void markResourceAsCached(LocalFrame*, DocumentLoader*, unsigned long identifier);
- void didReceiveResourceResponse(ExecutionContext*, unsigned long identifier, DocumentLoader*, const ResourceResponse&, Resource*);
- void didReceiveData(ExecutionContext*, unsigned long identifier, DocumentLoader*, const char* data, size_t dataLength);
- void didReceiveBlob(ExecutionContext*, unsigned long identifier, DocumentLoader*, BlobDataHandle*);
- void didReceiveEncodedDataLength(ExecutionContext*, DocumentLoader* loader, unsigned long identifier, size_t encodedDataLength);
- void didFinishLoading(ExecutionContext*, unsigned long identifier, DocumentLoader*, TimeTicks finishTime, int64_t encoded_data_length, int64_t decodedBodyLength, bool should_report_corb_blocking);
+ void didReceiveResourceResponse(CoreProbeSink*, unsigned long identifier, DocumentLoader*, const ResourceResponse&, Resource*);
+ void didReceiveData(CoreProbeSink*, unsigned long identifier, DocumentLoader*, const char* data, uint64_t dataLength);
+ void didReceiveBlob(CoreProbeSink*, unsigned long identifier, DocumentLoader*, BlobDataHandle*);
+ void didReceiveEncodedDataLength(CoreProbeSink*, DocumentLoader* loader, unsigned long identifier, size_t encodedDataLength);
+ void didFinishLoading(CoreProbeSink*, unsigned long identifier, DocumentLoader*, TimeTicks finishTime, int64_t encoded_data_length, int64_t decodedBodyLength, bool should_report_corb_blocking);
void didReceiveCorsRedirectResponse(ExecutionContext*, unsigned long identifier, DocumentLoader*, const ResourceResponse&, Resource*);
- void didFailLoading(ExecutionContext*, unsigned long identifier, DocumentLoader*, const ResourceError&);
+ void didFailLoading(CoreProbeSink*, unsigned long identifier, DocumentLoader*, const ResourceError&);
void willSendEventSourceRequest(ExecutionContext*, ThreadableLoaderClient* eventSource);
void willDispatchEventSourceEvent(ExecutionContext*, unsigned long identifier, const AtomicString& eventName, const AtomicString& eventId, const String& data);
- void willLoadXHR(ExecutionContext*, XMLHttpRequest* xhr, ThreadableLoaderClient* client, const AtomicString& method, const KURL& url, bool async, const HTTPHeaderMap& headers, bool includeCredentials);
+ void willLoadXHR(ExecutionContext*, XMLHttpRequest* xhr, ThreadableLoaderClient* client, const AtomicString& method, const KURL& url, bool async, EncodedFormData* form_data, const HTTPHeaderMap& headers, bool includeCredentials);
void didFinishXHR(ExecutionContext*, XMLHttpRequest* xhr);
void scriptImported(ExecutionContext*, unsigned long identifier, const String& sourceString);
void scriptExecutionBlockedByCSP(ExecutionContext*, const String& directiveText);
@@ -120,15 +119,15 @@ interface CoreProbes {
void frameOwnerContentUpdated([Keep] LocalFrame*, HTMLFrameOwnerElement*);
void frameStartedLoading([Keep] LocalFrame*);
void frameStoppedLoading([Keep] LocalFrame*);
- void frameScheduledNavigation([Keep] LocalFrame*, ScheduledNavigation*);
+ void frameScheduledNavigation([Keep] LocalFrame*, const KURL& url, double delay, ClientNavigationReason reason);
void frameClearedScheduledNavigation([Keep] LocalFrame*);
void didCreateWebSocket([Keep] ExecutionContext*, unsigned long identifier, const KURL& requestURL, const String& protocol);
void willSendWebSocketHandshakeRequest([Keep] ExecutionContext*, unsigned long identifier, network::mojom::blink::WebSocketHandshakeRequest* request);
void didReceiveWebSocketHandshakeResponse([Keep] ExecutionContext*, unsigned long identifier, network::mojom::blink::WebSocketHandshakeRequest* request, network::mojom::blink::WebSocketHandshakeResponse* response);
void didCloseWebSocket([Keep] ExecutionContext*, unsigned long identifier);
- void didReceiveWebSocketFrame(ExecutionContext*, unsigned long identifier, int opCode, bool masked, const char* payload, size_t payloadLength);
- void didSendWebSocketFrame(ExecutionContext*, unsigned long identifier, int opCode, bool masked, const char* payload, size_t payloadLength);
- void didReceiveWebSocketFrameError(ExecutionContext*, unsigned long identifier, const String& errorMessage);
+ void didReceiveWebSocketMessage(ExecutionContext*, unsigned long identifier, int opCode, bool masked, const char* payload, size_t payloadLength);
+ void didSendWebSocketMessage(ExecutionContext*, unsigned long identifier, int opCode, bool masked, const char* payload, size_t payloadLength);
+ void didReceiveWebSocketMessageError(ExecutionContext*, unsigned long identifier, const String& errorMessage);
void networkStateChanged([Keep] LocalFrame*, bool online);
void updateApplicationCacheStatus([Keep] LocalFrame*);
void layerTreeDidChange(LocalFrame*);
@@ -152,7 +151,7 @@ interface CoreProbes {
ParseHTML(Document* document, HTMLDocumentParser* parser);
void forcePseudoState([Keep] Element* element, CSSSelector::PseudoType pseudoState, bool* result);
void shouldForceCorsPreflight(ExecutionContext*, bool* result);
- void shouldBlockRequest(ExecutionContext*, const KURL&, bool* result);
+ void shouldBlockRequest(CoreProbeSink*, const KURL&, bool* result);
void shouldBypassServiceWorker(ExecutionContext* context, bool* result);
void consoleTimeStamp(ExecutionContext*, const String& title);
void lifecycleEvent([Keep] LocalFrame*, DocumentLoader*, const char* name, double timestamp);
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h
index 27a6223b702..379cc05381d 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_ENTRY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_ENTRY_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -14,7 +15,7 @@ class Element;
class DOMRectReadOnly;
class LayoutRect;
-class ResizeObserverEntry final : public ScriptWrappable {
+class CORE_EXPORT ResizeObserverEntry final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc
index 1c02202fb10..19eb930d1ff 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc
@@ -59,7 +59,6 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
- main_resource.Start();
main_resource.Write(R"HTML(
<div id='domTarget' style='width:100px;height:100px'>yo</div>
<svg height='200' width='200'>
@@ -69,7 +68,7 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) {
main_resource.Finish();
ResizeObserver::Delegate* delegate =
- new TestResizeObserverDelegate(GetDocument());
+ MakeGarbageCollected<TestResizeObserverDelegate>(GetDocument());
ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate);
Element* dom_target = GetDocument().getElementById("domTarget");
Element* svg_target = GetDocument().getElementById("svgTarget");
diff --git a/chromium/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc b/chromium/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
index 2d91b4240da..c274b606cf2 100644
--- a/chromium/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
+++ b/chromium/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
@@ -43,7 +43,7 @@ class FrameThrottlingTest : public PaintTestConfigurations, public SimTest {
protected:
void SetUp() override {
SimTest::SetUp();
- WebView().Resize(WebSize(640, 480));
+ WebView().MainFrameWidget()->Resize(WebSize(640, 480));
}
SimCanvas::Commands CompositeFrame() {
@@ -286,13 +286,26 @@ TEST_P(FrameThrottlingTest, ThrottledLifecycleUpdate) {
// ran.
frame_element->setAttribute(kWidthAttr, "50");
CompositeFrame();
- EXPECT_EQ(DocumentLifecycle::kPaintClean,
- frame_document->Lifecycle().GetState());
- // A hit test will not force a complete lifecycle update.
- WebView().HitTestResultAt(gfx::Point());
- EXPECT_EQ(DocumentLifecycle::kPaintClean,
- frame_document->Lifecycle().GetState());
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(DocumentLifecycle::kPaintClean,
+ frame_document->Lifecycle().GetState());
+
+ // A hit test will not force a complete lifecycle update.
+ WebView().HitTestResultAt(gfx::Point());
+ EXPECT_EQ(DocumentLifecycle::kPaintClean,
+ frame_document->Lifecycle().GetState());
+ } else {
+ // TODO(chrishtr): fix this test by manually resetting to
+ // kVisualUpdatePending before call to CompositeFrame.
+ EXPECT_EQ(DocumentLifecycle::kPaintClean,
+ frame_document->Lifecycle().GetState());
+
+ // A hit test will not force a complete lifecycle update.
+ WebView().HitTestResultAt(gfx::Point());
+ EXPECT_EQ(DocumentLifecycle::kPaintClean,
+ frame_document->Lifecycle().GetState());
+ }
}
TEST_P(FrameThrottlingTest, UnthrottlingFrameSchedulesAnimation) {
@@ -563,8 +576,8 @@ TEST_P(FrameThrottlingTest, ThrottledFrameWithFocus) {
}
TEST_P(FrameThrottlingTest, ScrollingCoordinatorShouldSkipThrottledFrame) {
- // TODO(crbug.com/809638): Make this test pass for SPv2.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // TODO(crbug.com/809638): Make this test pass for CAP.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
// Create a hidden frame which is throttled.
@@ -722,9 +735,9 @@ TEST_P(FrameThrottlingTest,
// frame.
EXPECT_EQ(DocumentLifecycle::kPaintClean,
frame_element->contentDocument()->Lifecycle().GetState());
- // TODO(szager): Re-enable this check for SPv2 when it properly sets the
+ // TODO(szager): Re-enable this check for CAP when it properly sets the
// bits for composited scrolling.
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_TRUE(frame_element->contentDocument()
->View()
->LayoutViewport()
@@ -759,8 +772,8 @@ TEST_P(FrameThrottlingTest, UnthrottleByTransformingWithoutLayout) {
}
TEST_P(FrameThrottlingTest, ThrottledTopLevelEventHandlerIgnored) {
- // TODO(crbug.com/809638): Make this test pass for SPv2.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // TODO(crbug.com/809638): Make this test pass for CAP.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
WebView().GetSettings()->SetJavaScriptEnabled(true);
@@ -819,8 +832,8 @@ TEST_P(FrameThrottlingTest, ThrottledTopLevelEventHandlerIgnored) {
}
TEST_P(FrameThrottlingTest, ThrottledEventHandlerIgnored) {
- // TODO(crbug.com/809638): Make this test pass for SPv2.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // TODO(crbug.com/809638): Make this test pass for CAP.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
WebView().GetSettings()->SetJavaScriptEnabled(true);
@@ -908,7 +921,7 @@ TEST_P(FrameThrottlingTest, DumpThrottledFrame) {
}
TEST_P(FrameThrottlingTest, PaintingViaGraphicsLayerIsThrottled) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
@@ -944,7 +957,7 @@ TEST_P(FrameThrottlingTest, PaintingViaGraphicsLayerIsThrottled) {
}
TEST_P(FrameThrottlingTest, ThrottleInnerCompositedLayer) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
@@ -1022,6 +1035,10 @@ TEST_P(FrameThrottlingTest, ThrottleInnerCompositedLayer) {
}
TEST_P(FrameThrottlingTest, ThrottleSubtreeAtomically) {
+ // TODO(crbug.com/922419): The test is broken for LayoutNG.
+ if (RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
+
// Create two nested frames which are throttled.
SimRequest main_resource("https://example.com/", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
@@ -1313,7 +1330,7 @@ TEST_P(FrameThrottlingTest, DisplayNoneChildrenRemainThrottled) {
}
TEST_P(FrameThrottlingTest, RebuildCompositedLayerTreeOnLayerRemoval) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
// This test verifies removal of PaintLayer due to style change will force
diff --git a/chromium/third_party/blink/renderer/core/scheduler/throttling_test.cc b/chromium/third_party/blink/renderer/core/scheduler/throttling_test.cc
index 4c9710559c2..2420d3bad75 100644
--- a/chromium/third_party/blink/renderer/core/scheduler/throttling_test.cc
+++ b/chromium/third_party/blink/renderer/core/scheduler/throttling_test.cc
@@ -44,9 +44,7 @@ TEST_F(DisableBackgroundThrottlingIsRespectedTest,
" f(5);"
"</script>)");
- ThreadScheduler::Current()
- ->GetWebMainThreadSchedulerForTest()
- ->SetRendererBackgrounded(true);
+ GetDocument().GetPage()->GetPageScheduler()->SetPageVisible(false);
// Run delayed tasks for 1 second. All tasks should be completed
// with throttling disabled.
@@ -56,9 +54,9 @@ TEST_F(DisableBackgroundThrottlingIsRespectedTest,
"called f", "called f"));
}
-class BackgroundRendererThrottlingTest : public SimTest {};
+class BackgroundPageThrottlingTest : public SimTest {};
-TEST_F(BackgroundRendererThrottlingTest, BackgroundRenderersAreThrottled) {
+TEST_F(BackgroundPageThrottlingTest, BackgroundPagesAreThrottled) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
@@ -73,9 +71,7 @@ TEST_F(BackgroundRendererThrottlingTest, BackgroundRenderersAreThrottled) {
" setTimeout(f, 10, 50);"
"</script>)");
- ThreadScheduler::Current()
- ->GetWebMainThreadSchedulerForTest()
- ->SetRendererBackgrounded(true);
+ GetDocument().GetPage()->GetPageScheduler()->SetPageVisible(false);
// Make sure that we run no more than one task a second.
test::RunDelayedTasks(TimeDelta::FromMilliseconds(3000));
diff --git a/chromium/third_party/blink/renderer/core/scheduler/virtual_time_test.cc b/chromium/third_party/blink/renderer/core/scheduler/virtual_time_test.cc
index 6ee40db1fdb..56df3ae3673 100644
--- a/chromium/third_party/blink/renderer/core/scheduler/virtual_time_test.cc
+++ b/chromium/third_party/blink/renderer/core/scheduler/virtual_time_test.cc
@@ -149,14 +149,13 @@ TEST_F(VirtualTimeTest,
EXPECT_TRUE(WebView().Scheduler()->VirtualTimeAllowedToAdvance());
SimRequest main_resource("https://example.com/test.html", "text/html");
- SimRequest css_resource("https://example.com/test.css", "text/css");
+ SimSubresourceRequest css_resource("https://example.com/test.css",
+ "text/css");
// Loading, virtual time should not advance.
LoadURL("https://example.com/test.html");
EXPECT_FALSE(WebView().Scheduler()->VirtualTimeAllowedToAdvance());
- main_resource.Start();
-
// Still Loading, virtual time should not advance.
main_resource.Write("<!DOCTYPE html><link rel=stylesheet href=test.css>");
EXPECT_FALSE(WebView().Scheduler()->VirtualTimeAllowedToAdvance());
diff --git a/chromium/third_party/blink/renderer/core/script/BUILD.gn b/chromium/third_party/blink/renderer/core/script/BUILD.gn
index ff592b2f241..b02fb078836 100644
--- a/chromium/third_party/blink/renderer/core/script/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/script/BUILD.gn
@@ -26,6 +26,7 @@ blink_core_sources("script") {
"ignore_destructive_write_count_incrementer.h",
"layered_api.cc",
"layered_api.h",
+ "layered_api_resources.h",
"modulator.cc",
"modulator.h",
"modulator_impl_base.cc",
diff --git a/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc b/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc
index 8a92a60c654..65e1def936b 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc
@@ -11,7 +11,6 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/scriptable_document_parser.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/loader/allowed_by_nosniff.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
@@ -19,10 +18,12 @@
#include "third_party/blink/renderer/core/script/script_loader.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/histogram.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -41,9 +42,10 @@ ClassicPendingScript* ClassicPendingScript::Fetch(
FetchParameters params = options.CreateFetchParameters(
url, element_document.GetSecurityOrigin(), cross_origin, encoding, defer);
- ClassicPendingScript* pending_script = new ClassicPendingScript(
- element, TextPosition(), ScriptSourceLocationType::kExternalFile, options,
- true /* is_external */);
+ ClassicPendingScript* pending_script =
+ MakeGarbageCollected<ClassicPendingScript>(
+ element, TextPosition(), ScriptSourceLocationType::kExternalFile,
+ options, true /* is_external */);
// [Intervention]
// For users on slow connections, we want to avoid blocking the parser in
@@ -72,8 +74,9 @@ ClassicPendingScript* ClassicPendingScript::CreateInline(
ScriptSourceLocationType source_location_type,
const ScriptFetchOptions& options) {
ClassicPendingScript* pending_script =
- new ClassicPendingScript(element, starting_position, source_location_type,
- options, false /* is_external */);
+ MakeGarbageCollected<ClassicPendingScript>(element, starting_position,
+ source_location_type, options,
+ false /* is_external */);
pending_script->CheckState();
return pending_script;
}
@@ -93,8 +96,7 @@ ClassicPendingScript::ClassicPendingScript(
source_location_type_(source_location_type),
is_external_(is_external),
ready_state_(is_external ? kWaitingForResource : kReady),
- integrity_failure_(false),
- is_currently_streaming_(false) {
+ integrity_failure_(false) {
CHECK(GetElement());
MemoryCoordinator::Instance().RegisterClient(this);
}
@@ -297,6 +299,7 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url) const {
if (ready_state_ == kErrorOccurred)
return nullptr;
+ TRACE_EVENT0("blink", "ClassicPendingScript::GetSource");
if (!is_external_) {
SingleCachedMetadataHandler* cache_handler = nullptr;
// We only create an inline cache handler for html-embedded scripts, not
@@ -327,10 +330,12 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url) const {
DCHECK(GetResource()->IsLoaded());
ScriptResource* resource = ToScriptResource(GetResource());
+ auto* fetcher = GetElement()->GetDocument().ContextDocument()->Fetcher();
// If the MIME check fails, which is considered as load failure.
if (!AllowedByNosniff::MimeTypeAsScript(
- GetElement()->GetDocument().ContextDocument(),
- resource->GetResponse(), AllowedByNosniff::MimeTypeCheck::kLax)) {
+ fetcher->Context(), fetcher->GetConsoleLogger(),
+ resource->GetResponse(), AllowedByNosniff::MimeTypeCheck::kLax,
+ false)) {
return nullptr;
}
@@ -390,42 +395,9 @@ void ClassicPendingScript::AdvanceReadyState(ReadyState new_ready_state) {
bool old_is_ready = IsReady();
ready_state_ = new_ready_state;
- ScriptResource* resource = ToScriptResource(GetResource());
-
// Did we transition into a 'ready' state?
if (IsReady() && !old_is_ready && IsWatchingForLoad())
PendingScriptFinished();
-
- // Did we finish streaming?
- if (IsCurrentlyStreaming()) {
- if (ready_state_ == kReady || ready_state_ == kErrorOccurred) {
- // Call the streamer_done_ callback. Ensure that is_currently_streaming_
- // is reset only after the callback returns, to prevent accidentally
- // start streaming by work done within the callback. (crbug.com/754360)
- base::OnceClosure done = std::move(streamer_done_);
- if (done)
- std::move(done).Run();
- is_currently_streaming_ = false;
- }
- }
-
- // Streaming-related post conditions:
-
- // To help diagnose crbug.com/78426, we'll temporarily add some DCHECKs
- // that are a subset of the DCHECKs below:
- if (IsCurrentlyStreaming()) {
- DCHECK(resource->HasStreamer());
- DCHECK(!resource->HasFinishedStreamer());
- }
-
- // IsCurrentlyStreaming should match what streamer_ thinks.
- DCHECK_EQ(IsCurrentlyStreaming(),
- resource->HasStreamer() && !resource->HasFinishedStreamer());
- // IsCurrentlyStreaming should match the ready_state_.
- DCHECK_EQ(IsCurrentlyStreaming(),
- resource->HasStreamer() && ready_state_ == kWaitingForResource);
- // We can only have a streamer_done_ callback if we are actually streaming.
- DCHECK(IsCurrentlyStreaming() || !streamer_done_);
}
void ClassicPendingScript::OnPurgeMemory() {
@@ -435,19 +407,15 @@ void ClassicPendingScript::OnPurgeMemory() {
// here.
}
-bool ClassicPendingScript::StartStreamingIfPossible(
- base::OnceClosure done) {
- if (IsCurrentlyStreaming())
- return false;
-
+void ClassicPendingScript::StartStreamingIfPossible() {
// We can start streaming in two states: While still loading
// (kWaitingForResource), or after having loaded (kReady).
if (ready_state_ != kWaitingForResource && ready_state_ != kReady)
- return false;
+ return;
Document* document = &GetElement()->GetDocument();
if (!document || !document->GetFrame())
- return false;
+ return;
// Parser blocking scripts tend to do a lot of work in the 'finished'
// callbacks, while async + in-order scripts all do control-like activities
@@ -457,26 +425,14 @@ bool ClassicPendingScript::StartStreamingIfPossible(
? TaskType::kNetworking
: TaskType::kNetworkingControl;
- DCHECK(!IsCurrentlyStreaming());
- DCHECK(!streamer_done_);
-
ReadyState ready_state_before_stream = ready_state_;
- bool success = ToScriptResource(GetResource())
- ->StartStreaming(document->GetTaskRunner(task_type));
+ ToScriptResource(GetResource())
+ ->StartStreaming(document->GetTaskRunner(task_type));
// We have to make sure that the ready state is not changed by starting
// streaming, just in case we're relying on IsReady being false.
CHECK_EQ(ready_state_before_stream, ready_state_);
- // If we have successfully started streaming, we are required to call the
- // callback.
- is_currently_streaming_ = success;
- if (success)
- streamer_done_ = std::move(done);
- return success;
-}
-
-bool ClassicPendingScript::IsCurrentlyStreaming() const {
- return is_currently_streaming_;
+ return;
}
bool ClassicPendingScript::WasCanceled() const {
diff --git a/chromium/third_party/blink/renderer/core/script/classic_pending_script.h b/chromium/third_party/blink/renderer/core/script/classic_pending_script.h
index 45faa0a04e0..5860329ffb2 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_pending_script.h
+++ b/chromium/third_party/blink/renderer/core/script/classic_pending_script.h
@@ -47,6 +47,11 @@ class CORE_EXPORT ClassicPendingScript final : public PendingScript,
ScriptSourceLocationType,
const ScriptFetchOptions&);
+ ClassicPendingScript(ScriptElementBase*,
+ const TextPosition&,
+ ScriptSourceLocationType,
+ const ScriptFetchOptions&,
+ bool is_external);
~ClassicPendingScript() override;
// ScriptStreamer callbacks.
@@ -65,8 +70,7 @@ class CORE_EXPORT ClassicPendingScript final : public PendingScript,
bool IsReady() const override;
bool IsExternal() const override { return is_external_; }
bool WasCanceled() const override;
- bool StartStreamingIfPossible(base::OnceClosure) override;
- bool IsCurrentlyStreaming() const override;
+ void StartStreamingIfPossible() override;
KURL UrlForTracing() const override;
void DisposeInternal() override;
@@ -84,11 +88,6 @@ class CORE_EXPORT ClassicPendingScript final : public PendingScript,
kErrorOccurred,
};
- ClassicPendingScript(ScriptElementBase*,
- const TextPosition&,
- ScriptSourceLocationType,
- const ScriptFetchOptions&,
- bool is_external);
ClassicPendingScript() = delete;
// Advances the current state of the script, reporting to the client if
@@ -129,22 +128,6 @@ class CORE_EXPORT ClassicPendingScript final : public PendingScript,
// The request is intervened by document.write() intervention.
bool intervened_ = false;
- base::OnceClosure streamer_done_;
-
- // This flag tracks whether streamer_ is currently streaming. It is used
- // mainly to prevent re-streaming a script while it is being streamed.
- //
- // ReadyState unfortunately doesn't contain this information, because
- // 1, the WaitingFor* states can occur with or without streaming, and
- // 2, during the state transition, we need to first transition ready_state_,
- // then run callbacks, and only then consider the streaming done. So
- // during AdvanceReadyState and callback processing, the ready state
- // and is_currently_streaming_ are temporarily different. (They must
- // be consistent before and after AdvanceReadyState.)
- //
- // (See also: crbug.com/754360)
- bool is_currently_streaming_;
-
// Specifies the reason that script was never streamed.
ScriptStreamer::NotStreamingReason not_streamed_reason_;
};
diff --git a/chromium/third_party/blink/renderer/core/script/classic_script.h b/chromium/third_party/blink/renderer/core/script/classic_script.h
index b645f6bf413..25e5e43ab4e 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_script.h
+++ b/chromium/third_party/blink/renderer/core/script/classic_script.h
@@ -20,17 +20,10 @@ class CORE_EXPORT ClassicScript final : public Script {
const KURL& base_url,
const ScriptFetchOptions& fetch_options,
SanitizeScriptErrors sanitize_script_errors) {
- return new ClassicScript(script_source_code, base_url, fetch_options,
- sanitize_script_errors);
+ return MakeGarbageCollected<ClassicScript>(
+ script_source_code, base_url, fetch_options, sanitize_script_errors);
}
- void Trace(blink::Visitor*) override;
-
- const ScriptSourceCode& GetScriptSourceCode() const {
- return script_source_code_;
- }
-
- private:
ClassicScript(const ScriptSourceCode& script_source_code,
const KURL& base_url,
const ScriptFetchOptions& fetch_options,
@@ -39,6 +32,13 @@ class CORE_EXPORT ClassicScript final : public Script {
script_source_code_(script_source_code),
sanitize_script_errors_(sanitize_script_errors) {}
+ void Trace(blink::Visitor*) override;
+
+ const ScriptSourceCode& GetScriptSourceCode() const {
+ return script_source_code_;
+ }
+
+ private:
mojom::ScriptType GetScriptType() const override {
return mojom::ScriptType::kClassic;
}
diff --git a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc
index f8518d64bff..42c7286a4b4 100644
--- a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc
@@ -9,28 +9,17 @@
namespace blink {
-ModulatorImplBase* DocumentModulatorImpl::Create(
- ScriptState* script_state,
- ResourceFetcher* resource_fetcher) {
- return MakeGarbageCollected<DocumentModulatorImpl>(script_state,
- resource_fetcher);
+ModulatorImplBase* DocumentModulatorImpl::Create(ScriptState* script_state) {
+ return MakeGarbageCollected<DocumentModulatorImpl>(script_state);
}
+DocumentModulatorImpl::DocumentModulatorImpl(ScriptState* script_state)
+ : ModulatorImplBase(script_state) {}
+
ModuleScriptFetcher* DocumentModulatorImpl::CreateModuleScriptFetcher(
ModuleScriptCustomFetchType custom_fetch_type) {
DCHECK_EQ(ModuleScriptCustomFetchType::kNone, custom_fetch_type);
- return MakeGarbageCollected<DocumentModuleScriptFetcher>(fetcher_);
-}
-
-void DocumentModulatorImpl::Trace(blink::Visitor* visitor) {
- visitor->Trace(fetcher_);
- ModulatorImplBase::Trace(visitor);
-}
-
-DocumentModulatorImpl::DocumentModulatorImpl(ScriptState* script_state,
- ResourceFetcher* resource_fetcher)
- : ModulatorImplBase(script_state), fetcher_(resource_fetcher) {
- DCHECK(fetcher_);
+ return MakeGarbageCollected<DocumentModuleScriptFetcher>();
}
bool DocumentModulatorImpl::IsDynamicImportForbidden(String* reason) {
diff --git a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h
index 5c34db9ddd4..a090c5d6c3c 100644
--- a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h
@@ -12,7 +12,6 @@
namespace blink {
class ModuleScriptFetcher;
-class ResourceFetcher;
class ScriptState;
// DocumentModulatorImpl is the Modulator implementation used in main documents
@@ -21,21 +20,17 @@ class ScriptState;
// ModulatorImplBase.
class DocumentModulatorImpl final : public ModulatorImplBase {
public:
- static ModulatorImplBase* Create(ScriptState*, ResourceFetcher*);
+ static ModulatorImplBase* Create(ScriptState*);
- DocumentModulatorImpl(ScriptState*, ResourceFetcher*);
+ explicit DocumentModulatorImpl(ScriptState*);
// Implements Modulator.
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType) override;
- void Trace(blink::Visitor*) override;
-
private:
// Implements ModulatorImplBase.
bool IsDynamicImportForbidden(String* reason) override;
-
- Member<ResourceFetcher> fetcher_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/document_write_intervention.cc b/chromium/third_party/blink/renderer/core/script/document_write_intervention.cc
index ed287c4f29f..28896971a6a 100644
--- a/chromium/third_party/blink/renderer/core/script/document_write_intervention.cc
+++ b/chromium/third_party/blink/renderer/core/script/document_write_intervention.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/script/document_write_intervention.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_effective_connection_type.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
diff --git a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
index f7353d1230e..2f5e27fded4 100644
--- a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_script.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
@@ -25,17 +26,18 @@ class DynamicImportTreeClient final : public ModuleTreeClient {
const KURL& url,
Modulator* modulator,
ScriptPromiseResolver* promise_resolver) {
- return new DynamicImportTreeClient(url, modulator, promise_resolver);
+ return MakeGarbageCollected<DynamicImportTreeClient>(url, modulator,
+ promise_resolver);
}
- void Trace(blink::Visitor*) override;
-
- private:
DynamicImportTreeClient(const KURL& url,
Modulator* modulator,
ScriptPromiseResolver* promise_resolver)
: url_(url), modulator_(modulator), promise_resolver_(promise_resolver) {}
+ void Trace(blink::Visitor*) override;
+
+ private:
// Implements ModuleTreeClient:
void NotifyModuleTreeLoadFinished(ModuleScript*) final;
@@ -239,10 +241,11 @@ void DynamicModuleResolver::ResolveDynamically(
// highly discouraged since it breaks layering. Rewrite this.
auto* execution_context =
ExecutionContext::From(modulator_->GetScriptState());
- modulator_->FetchTree(
- url, execution_context->CreateFetchClientSettingsObjectSnapshot(),
- mojom::RequestContextType::SCRIPT, options,
- ModuleScriptCustomFetchType::kNone, tree_client);
+ if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context))
+ scope->EnsureFetcher();
+ modulator_->FetchTree(url, execution_context->Fetcher(),
+ mojom::RequestContextType::SCRIPT, options,
+ ModuleScriptCustomFetchType::kNone, tree_client);
// Steps 2.[5-8] are implemented at
// DynamicImportTreeClient::NotifyModuleLoadFinished.
diff --git a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
index 46f86410254..f9b1995fd40 100644
--- a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -70,7 +70,7 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
}
void FetchTree(const KURL& url,
- FetchClientSettingsObjectSnapshot*,
+ ResourceFetcher*,
mojom::RequestContextType,
const ScriptFetchOptions&,
ModuleScriptCustomFetchType custom_fetch_type,
@@ -131,7 +131,8 @@ class CaptureExportedStringFunction final : public ScriptFunction {
v8::Local<v8::Value> exported_value =
module_namespace->Get(context, V8String(isolate, export_name_))
.ToLocalChecked();
- captured_value_ = ToCoreString(exported_value->ToString(isolate));
+ captured_value_ =
+ ToCoreString(exported_value->ToString(context).ToLocalChecked());
return ScriptValue();
}
@@ -165,11 +166,11 @@ class CaptureErrorFunction final : public ScriptFunction {
v8::Local<v8::Value> name =
error_object->Get(context, V8String(isolate, "name")).ToLocalChecked();
- name_ = ToCoreString(name->ToString(isolate));
+ name_ = ToCoreString(name->ToString(context).ToLocalChecked());
v8::Local<v8::Value> message =
error_object->Get(context, V8String(isolate, "message"))
.ToLocalChecked();
- message_ = ToCoreString(message->ToString(isolate));
+ message_ = ToCoreString(message->ToString(context).ToLocalChecked());
return ScriptValue();
}
@@ -182,14 +183,15 @@ class CaptureErrorFunction final : public ScriptFunction {
class DynamicModuleResolverTestNotReached final : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
- auto* not_reached = new DynamicModuleResolverTestNotReached(script_state);
+ auto* not_reached =
+ MakeGarbageCollected<DynamicModuleResolverTestNotReached>(script_state);
return not_reached->BindToV8Function();
}
- private:
explicit DynamicModuleResolverTestNotReached(ScriptState* script_state)
: ScriptFunction(script_state) {}
+ private:
ScriptValue Call(ScriptValue) override {
ADD_FAILURE();
return ScriptValue();
@@ -200,16 +202,16 @@ class DynamicModuleResolverTestNotReached final : public ScriptFunction {
TEST(DynamicModuleResolverTest, ResolveSuccess) {
V8TestingScope scope;
- auto* modulator =
- new DynamicModuleResolverTestModulator(scope.GetScriptState());
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
modulator->SetExpectedFetchTreeURL(TestDependencyURL());
auto* promise_resolver =
ScriptPromiseResolver::Create(scope.GetScriptState());
ScriptPromise promise = promise_resolver->Promise();
- auto* capture =
- new CaptureExportedStringFunction(scope.GetScriptState(), "foo");
+ auto* capture = MakeGarbageCollected<CaptureExportedStringFunction>(
+ scope.GetScriptState(), "foo");
promise.Then(capture->Bind(),
DynamicModuleResolverTestNotReached::CreateFunction(
scope.GetScriptState()));
@@ -237,15 +239,16 @@ TEST(DynamicModuleResolverTest, ResolveSuccess) {
TEST(DynamicModuleResolverTest, ResolveSpecifierFailure) {
V8TestingScope scope;
- auto* modulator =
- new DynamicModuleResolverTestModulator(scope.GetScriptState());
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
modulator->SetExpectedFetchTreeURL(TestDependencyURL());
auto* promise_resolver =
ScriptPromiseResolver::Create(scope.GetScriptState());
ScriptPromise promise = promise_resolver->Promise();
- auto* capture = new CaptureErrorFunction(scope.GetScriptState());
+ auto* capture =
+ MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
scope.GetScriptState()),
capture->Bind());
@@ -262,15 +265,16 @@ TEST(DynamicModuleResolverTest, ResolveSpecifierFailure) {
TEST(DynamicModuleResolverTest, FetchFailure) {
V8TestingScope scope;
- auto* modulator =
- new DynamicModuleResolverTestModulator(scope.GetScriptState());
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
modulator->SetExpectedFetchTreeURL(TestDependencyURL());
auto* promise_resolver =
ScriptPromiseResolver::Create(scope.GetScriptState());
ScriptPromise promise = promise_resolver->Promise();
- auto* capture = new CaptureErrorFunction(scope.GetScriptState());
+ auto* capture =
+ MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
scope.GetScriptState()),
capture->Bind());
@@ -291,15 +295,16 @@ TEST(DynamicModuleResolverTest, FetchFailure) {
TEST(DynamicModuleResolverTest, ExceptionThrown) {
V8TestingScope scope;
- auto* modulator =
- new DynamicModuleResolverTestModulator(scope.GetScriptState());
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
modulator->SetExpectedFetchTreeURL(TestDependencyURL());
auto* promise_resolver =
ScriptPromiseResolver::Create(scope.GetScriptState());
ScriptPromise promise = promise_resolver->Promise();
- auto* capture = new CaptureErrorFunction(scope.GetScriptState());
+ auto* capture =
+ MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
scope.GetScriptState()),
capture->Bind());
@@ -329,16 +334,16 @@ TEST(DynamicModuleResolverTest, ResolveWithNullReferrerScriptSuccess) {
V8TestingScope scope;
scope.GetDocument().SetURL(KURL("https://example.com"));
- auto* modulator =
- new DynamicModuleResolverTestModulator(scope.GetScriptState());
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
modulator->SetExpectedFetchTreeURL(TestDependencyURL());
auto* promise_resolver =
ScriptPromiseResolver::Create(scope.GetScriptState());
ScriptPromise promise = promise_resolver->Promise();
- auto* capture =
- new CaptureExportedStringFunction(scope.GetScriptState(), "foo");
+ auto* capture = MakeGarbageCollected<CaptureExportedStringFunction>(
+ scope.GetScriptState(), "foo");
promise.Then(capture->Bind(),
DynamicModuleResolverTestNotReached::CreateFunction(
scope.GetScriptState()));
@@ -368,8 +373,8 @@ TEST(DynamicModuleResolverTest, ResolveWithReferrerScriptInfoBaseURL) {
V8TestingScope scope;
scope.GetDocument().SetURL(KURL("https://example.com"));
- auto* modulator =
- new DynamicModuleResolverTestModulator(scope.GetScriptState());
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
modulator->SetExpectedFetchTreeURL(
KURL("https://example.com/correct/dependency.js"));
diff --git a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
index 15af66c2727..461d9172c2f 100644
--- a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
@@ -40,6 +40,27 @@ HttpsState FetchClientSettingsObjectImpl::GetHttpsState() const {
return execution_context_->GetHttpsState();
}
+AllowedByNosniff::MimeTypeCheck
+FetchClientSettingsObjectImpl::MimeTypeCheckForClassicWorkerScript() const {
+ if (execution_context_->IsDocument()) {
+ // For worker creation on a document, don't impose strict MIME-type checks
+ // on the top-level worker script for backward compatibility. Note that
+ // there is a plan to deprecate legacy mime types for workers. See
+ // https://crbug.com/794548.
+ //
+ // For worker creation on a document with off-the-main-thread top-level
+ // worker classic script loading, this value is propagated to
+ // outsideSettings FCSO.
+ return AllowedByNosniff::MimeTypeCheck::kLax;
+ }
+
+ // For importScripts() and nested worker top-level scripts impose the strict
+ // MIME-type checks.
+ // Nested workers is a new feature (enabled by default in M69) and there is no
+ // backward compatibility issue.
+ return AllowedByNosniff::MimeTypeCheck::kStrict;
+}
+
void FetchClientSettingsObjectImpl::Trace(Visitor* visitor) {
visitor->Trace(execution_context_);
FetchClientSettingsObject::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
index 8ea794e2e87..d79ee309500 100644
--- a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
@@ -38,6 +38,9 @@ class CORE_EXPORT FetchClientSettingsObjectImpl final
HttpsState GetHttpsState() const override;
+ AllowedByNosniff::MimeTypeCheck MimeTypeCheckForClassicWorkerScript()
+ const override;
+
void Trace(Visitor* visitor) override;
private:
diff --git a/chromium/third_party/blink/renderer/core/script/generate_lapi_grdp.py b/chromium/third_party/blink/renderer/core/script/generate_lapi_grdp.py
new file mode 100755
index 00000000000..99eff1f6377
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/generate_lapi_grdp.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+# Copyright (c) 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+import os
+
+
+def main():
+ core_script_path = os.path.dirname(sys.argv[0])
+
+ # The path to the directory containing layered API files.
+ input_path = os.path.join(core_script_path, 'resources/layered_api')
+
+ # Relative path from the main grd file; in this case,
+ # third_party/blink/public/blink_resources.grd.
+ input_relative_path = '../renderer/core/script/resources/layered_api'
+
+ # Output .grdp file.
+ output_grdp_file = open(
+ os.path.join(core_script_path, 'resources/layered_api/resources.grdp'),
+ 'w')
+
+ # Output .h file.
+ output_header_file = open(
+ os.path.join(core_script_path, 'layered_api_resources.h'), 'w')
+
+ print >> output_grdp_file, '''<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <!-- Layered API scripts. This file is generated by
+ core/script/generate_lapi_grdp.py and shouldn't modified manually.
+ A corresponding header file (layered_api_resources.h) is also generated.
+ The paths are relative to the main grd file, i.e.
+ third_party/blink/public/blink_resources.grd.
+ -->'''
+
+ print >> output_header_file, '''// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/resources/grit/blink_resources.h"
+#include "third_party/blink/renderer/core/script/layered_api.h"
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_LAYERED_API_RESOURCES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_LAYERED_API_RESOURCES_H_
+
+// This file is generated by
+// core/script/generate_lapi_grdp.py and shouldn't modified manually.
+// A corresponding grdp file (layered_api_resources.grdp) is also generated.
+
+// This file should be included only once from core/script/layered_api.cc.
+
+namespace blink {
+
+namespace layered_api {
+
+namespace {
+
+const LayeredAPIResource kLayeredAPIResources[] = {'''
+
+ for root, _, filenames in sorted(os.walk(input_path)):
+ if root == 'resources/layered_api':
+ # We don't include top-level files under resources/layered_api,
+ # including generated resources.grdp.
+ continue
+ for filename in sorted(filenames):
+ if filename.startswith('.') or filename.startswith(
+ 'README') or filename.startswith('OWNERS'):
+ continue
+ relpath = os.path.relpath(os.path.join(root, filename), input_path)
+ relpath = relpath.replace('\\', '/')
+ resource_id = relpath
+ resource_id = resource_id.replace('/', '_')
+ resource_id = resource_id.replace('-', '_')
+ resource_id = resource_id.replace('.', '_')
+ resource_id = resource_id.upper()
+ resource_id = "IDR_LAYERED_API_" + resource_id
+ print >> output_header_file, (
+ ' {"%s",\n %s},' % (relpath, resource_id))
+ print >> output_grdp_file, (
+ ' <include name="%s" file="%s/%s" type="BINDATA" skip_minify="true" compress="gzip"/>'
+ % (resource_id, input_relative_path, relpath))
+ print >> output_header_file, ''
+ print >> output_grdp_file, '</grit-part>'
+
+ print >> output_header_file, '''};
+
+} // namespace
+
+} // namespace layered_api
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_LAYERED_API_RESOURCES_H_'''
+ output_grdp_file.close()
+ output_header_file.close()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/blink/renderer/core/script/html_parser_script_runner.cc b/chromium/third_party/blink/renderer/core/script/html_parser_script_runner.cc
index 563c7e4a9ac..ca737a21b99 100644
--- a/chromium/third_party/blink/renderer/core/script/html_parser_script_runner.cc
+++ b/chromium/third_party/blink/renderer/core/script/html_parser_script_runner.cc
@@ -478,7 +478,7 @@ void HTMLParserScriptRunner::RequestParsingBlockingScript(
// Callers will attempt to run the m_parserBlockingScript if possible before
// returning control to the parser.
if (!ParserBlockingScript()->IsReady()) {
- parser_blocking_script_->StartStreamingIfPossible(base::OnceClosure());
+ parser_blocking_script_->StartStreamingIfPossible();
parser_blocking_script_->WatchForLoad(this);
}
}
@@ -491,7 +491,7 @@ void HTMLParserScriptRunner::RequestDeferredScript(
return;
if (!pending_script->IsReady()) {
- pending_script->StartStreamingIfPossible(base::OnceClosure());
+ pending_script->StartStreamingIfPossible();
}
DCHECK(pending_script->IsExternalOrModule());
diff --git a/chromium/third_party/blink/renderer/core/script/layered_api.cc b/chromium/third_party/blink/renderer/core/script/layered_api.cc
index 7b406f0fff6..859662023f5 100644
--- a/chromium/third_party/blink/renderer/core/script/layered_api.cc
+++ b/chromium/third_party/blink/renderer/core/script/layered_api.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/core/script/layered_api.h"
#include "base/stl_util.h"
-#include "third_party/blink/public/resources/grit/blink_resources.h"
+#include "third_party/blink/renderer/core/script/layered_api_resources.h"
#include "third_party/blink/renderer/platform/data_resource_helper.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -18,32 +18,6 @@ namespace {
static const char kStdScheme[] = "std";
static const char kInternalScheme[] = "std-internal";
-struct LayeredAPIResource {
- const char* path;
- int resource_id;
-};
-
-const LayeredAPIResource kLayeredAPIResources[] = {
- {"blank/index.js", IDR_LAYERED_API_BLANK_INDEX_JS},
-
- {"async-local-storage/index.js",
- IDR_LAYERED_API_ASYNC_LOCAL_STORAGE_INDEX_JS},
-
- {"virtual-scroller/index.js", IDR_LAYERED_API_VIRTUAL_SCROLLER_INDEX_JS},
- {"virtual-scroller/item-source.js",
- IDR_LAYERED_API_VIRTUAL_SCROLLER_ITEM_SOURCE_JS},
- {"virtual-scroller/layouts/layout-1d-base.js",
- IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_BASE_JS},
- {"virtual-scroller/layouts/layout-1d-grid.js",
- IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_GRID_JS},
- {"virtual-scroller/layouts/layout-1d.js",
- IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_JS},
- {"virtual-scroller/virtual-scroller.js",
- IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_SCROLLER_JS},
- {"virtual-scroller/virtual-repeater.js",
- IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_REPEATER_JS},
-};
-
int GetResourceIDFromPath(const String& path) {
for (size_t i = 0; i < base::size(kLayeredAPIResources); ++i) {
if (path == kLayeredAPIResources[i].path) {
@@ -115,7 +89,7 @@ String GetSourceText(const KURL& url) {
if (resource_id < 0)
return String();
- return GetResourceAsString(resource_id);
+ return UncompressResourceAsString(resource_id);
}
} // namespace layered_api
diff --git a/chromium/third_party/blink/renderer/core/script/layered_api.h b/chromium/third_party/blink/renderer/core/script/layered_api.h
index 37f948c0b93..91977362c6b 100644
--- a/chromium/third_party/blink/renderer/core/script/layered_api.h
+++ b/chromium/third_party/blink/renderer/core/script/layered_api.h
@@ -30,6 +30,11 @@ CORE_EXPORT KURL GetInternalURL(const KURL&);
// Gets source text for std-internal://x/index.js.
CORE_EXPORT String GetSourceText(const KURL&);
+struct LayeredAPIResource {
+ const char* path;
+ int resource_id;
+};
+
} // namespace layered_api
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/layered_api_resources.h b/chromium/third_party/blink/renderer/core/script/layered_api_resources.h
new file mode 100644
index 00000000000..cfd04355a00
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/layered_api_resources.h
@@ -0,0 +1,54 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/resources/grit/blink_resources.h"
+#include "third_party/blink/renderer/core/script/layered_api.h"
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_LAYERED_API_RESOURCES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_LAYERED_API_RESOURCES_H_
+
+// This file is generated by
+// core/script/generate_lapi_grdp.py and shouldn't modified manually.
+// A corresponding grdp file (layered_api_resources.grdp) is also generated.
+
+// This file should be included only once from core/script/layered_api.cc.
+
+namespace blink {
+
+namespace layered_api {
+
+namespace {
+
+const LayeredAPIResource kLayeredAPIResources[] = {
+ {"blank/index.js", IDR_LAYERED_API_BLANK_INDEX_JS},
+
+ {"kv-storage/async_iterator.js",
+ IDR_LAYERED_API_KV_STORAGE_ASYNC_ITERATOR_JS},
+ {"kv-storage/idb_utils.js", IDR_LAYERED_API_KV_STORAGE_IDB_UTILS_JS},
+ {"kv-storage/index.js", IDR_LAYERED_API_KV_STORAGE_INDEX_JS},
+
+ {"virtual-scroller/index.js", IDR_LAYERED_API_VIRTUAL_SCROLLER_INDEX_JS},
+ {"virtual-scroller/item-source.js",
+ IDR_LAYERED_API_VIRTUAL_SCROLLER_ITEM_SOURCE_JS},
+ {"virtual-scroller/virtual-repeater.js",
+ IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_REPEATER_JS},
+ {"virtual-scroller/virtual-scroller.js",
+ IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_SCROLLER_JS},
+
+ {"virtual-scroller/layouts/layout-1d-base.js",
+ IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_BASE_JS},
+ {"virtual-scroller/layouts/layout-1d-grid.js",
+ IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_GRID_JS},
+ {"virtual-scroller/layouts/layout-1d.js",
+ IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_JS},
+
+};
+
+} // namespace
+
+} // namespace layered_api
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_LAYERED_API_RESOURCES_H_
diff --git a/chromium/third_party/blink/renderer/core/script/mock_script_element_base.h b/chromium/third_party/blink/renderer/core/script/mock_script_element_base.h
index 27a94b14d3f..bb7fea10b0e 100644
--- a/chromium/third_party/blink/renderer/core/script/mock_script_element_base.h
+++ b/chromium/third_party/blink/renderer/core/script/mock_script_element_base.h
@@ -19,7 +19,7 @@ class MockScriptElementBase
public:
static MockScriptElementBase* Create() {
- return new testing::StrictMock<MockScriptElementBase>();
+ return MakeGarbageCollected<testing::StrictMock<MockScriptElementBase>>();
}
virtual ~MockScriptElementBase() {}
@@ -33,6 +33,7 @@ class MockScriptElementBase
MOCK_CONST_METHOD0(ForAttributeValue, String());
MOCK_CONST_METHOD0(IntegrityAttributeValue, String());
MOCK_CONST_METHOD0(ReferrerPolicyAttributeValue, String());
+ MOCK_CONST_METHOD0(ImportanceAttributeValue, String());
MOCK_CONST_METHOD0(LanguageAttributeValue, String());
MOCK_CONST_METHOD0(NomoduleAttributeValue, bool());
MOCK_CONST_METHOD0(SourceAttributeValue, String());
diff --git a/chromium/third_party/blink/renderer/core/script/modulator.cc b/chromium/third_party/blink/renderer/core/script/modulator.cc
index dfaba2eac1d..b0561f36349 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator.cc
+++ b/chromium/third_party/blink/renderer/core/script/modulator.cc
@@ -36,8 +36,7 @@ Modulator* Modulator::From(ScriptState* script_state) {
return modulator;
ExecutionContext* execution_context = ExecutionContext::From(script_state);
if (auto* document = DynamicTo<Document>(execution_context)) {
- modulator =
- DocumentModulatorImpl::Create(script_state, document->Fetcher());
+ modulator = DocumentModulatorImpl::Create(script_state);
Modulator::SetModulator(script_state, modulator);
// See comment in LocalDOMWindow::modulator_ for this workaround.
diff --git a/chromium/third_party/blink/renderer/core/script/modulator.h b/chromium/third_party/blink/renderer/core/script/modulator.h
index 5bfa557f487..591b7787496 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator.h
+++ b/chromium/third_party/blink/renderer/core/script/modulator.h
@@ -23,11 +23,11 @@
namespace blink {
-class FetchClientSettingsObjectSnapshot;
class ModuleScript;
class ModuleScriptFetchRequest;
class ModuleScriptFetcher;
class ReferrerScriptInfo;
+class ResourceFetcher;
class ScriptModuleResolver;
class ScriptPromiseResolver;
class ScriptState;
@@ -118,30 +118,33 @@ class CORE_EXPORT Modulator : public GarbageCollectedFinalized<Modulator>,
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-module-script-tree
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-module-worker-script-tree
- // Note that |this| is the "module map settings object" used in the "fetch a
- // module worker script graph" algorithm.
- virtual void FetchTree(
- const KURL&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType destination,
- const ScriptFetchOptions&,
- ModuleScriptCustomFetchType,
- ModuleTreeClient*) = 0;
+ // Note that |this| is the "module map settings object" and
+ // ResourceFetcher represents "fetch client settings object"
+ // used in the "fetch a module worker script graph" algorithm.
+ virtual void FetchTree(const KURL&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ mojom::RequestContextType destination,
+ const ScriptFetchOptions&,
+ ModuleScriptCustomFetchType,
+ ModuleTreeClient*) = 0;
// Asynchronously retrieve a module script from the module map, or fetch it
// and put it in the map if it's not there already.
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
- // Note that |this| is the "module map settings object".
+ // Note that |this| is the "module map settings object" and
+ // |fetch_client_settings_object_fetcher| represents
+ // "fetch client settings object", which can be different from the
+ // ResourceFetcher associated with |this|.
virtual void FetchSingle(
const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel,
ModuleScriptCustomFetchType,
SingleModuleClient*) = 0;
virtual void FetchDescendantsForInlineScript(
ModuleScript*,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
ModuleTreeClient*) = 0;
diff --git a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc
index bbb206dcf4f..c30ee5d431e 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -17,7 +17,6 @@
#include "third_party/blink/renderer/core/script/module_script.h"
#include "third_party/blink/renderer/core/script/script_module_resolver_impl.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
namespace blink {
@@ -51,7 +50,7 @@ bool ModulatorImplBase::IsScriptingDisabled() const {
// href="https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-module-worker-script-tree">
void ModulatorImplBase::FetchTree(
const KURL& url,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
const ScriptFetchOptions& options,
ModuleScriptCustomFetchType custom_fetch_type,
@@ -69,8 +68,8 @@ void ModulatorImplBase::FetchTree(
// of this algorithm specified custom perform the fetch steps, pass those
// along as well.</spec>
- ModuleTreeLinker::Fetch(url, fetch_client_settings_object, destination,
- options, this, custom_fetch_type,
+ ModuleTreeLinker::Fetch(url, fetch_client_settings_object_fetcher,
+ destination, options, this, custom_fetch_type,
tree_linker_registry_, client);
// <spec label="fetch-a-module-script-tree" step="3">When the internal module
@@ -86,22 +85,22 @@ void ModulatorImplBase::FetchTree(
void ModulatorImplBase::FetchDescendantsForInlineScript(
ModuleScript* module_script,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
ModuleTreeClient* client) {
ModuleTreeLinker::FetchDescendantsForInlineScript(
- module_script, fetch_client_settings_object, destination, this,
+ module_script, fetch_client_settings_object_fetcher, destination, this,
ModuleScriptCustomFetchType::kNone, tree_linker_registry_, client);
}
void ModulatorImplBase::FetchSingle(
const ModuleScriptFetchRequest& request,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
ModuleScriptCustomFetchType custom_fetch_type,
SingleModuleClient* client) {
- map_->FetchSingleModuleScript(request, fetch_client_settings_object, level,
- custom_fetch_type, client);
+ map_->FetchSingleModuleScript(request, fetch_client_settings_object_fetcher,
+ level, custom_fetch_type, client);
}
ModuleScript* ModulatorImplBase::GetFetchedModuleScript(const KURL& url) {
diff --git a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h
index a4fe715b94f..8a71af5dcf0 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -49,24 +49,22 @@ class ModulatorImplBase : public Modulator {
return task_runner_.get();
}
- void FetchTree(
- const KURL&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType destination,
- const ScriptFetchOptions&,
- ModuleScriptCustomFetchType,
- ModuleTreeClient*) override;
+ void FetchTree(const KURL&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ mojom::RequestContextType destination,
+ const ScriptFetchOptions&,
+ ModuleScriptCustomFetchType,
+ ModuleTreeClient*) override;
void FetchDescendantsForInlineScript(
ModuleScript*,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::RequestContextType destination,
ModuleTreeClient*) override;
- void FetchSingle(
- const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- ModuleGraphLevel,
- ModuleScriptCustomFetchType,
- SingleModuleClient*) override;
+ void FetchSingle(const ModuleScriptFetchRequest&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ ModuleGraphLevel,
+ ModuleScriptCustomFetchType,
+ SingleModuleClient*) override;
ModuleScript* GetFetchedModuleScript(const KURL&) override;
bool HasValidContext() override;
KURL ResolveModuleSpecifier(const String& module_request,
diff --git a/chromium/third_party/blink/renderer/core/script/module_map.cc b/chromium/third_party/blink/renderer/core/script/module_map.cc
index 4399cb898e8..e8ba2e8ddbf 100644
--- a/chromium/third_party/blink/renderer/core/script/module_map.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_map.cc
@@ -113,7 +113,7 @@ void ModuleMap::Trace(blink::Visitor* visitor) {
// <specdef href="https://html.spec.whatwg.org/#fetch-a-single-module-script">
void ModuleMap::FetchSingleModuleScript(
const ModuleScriptFetchRequest& request,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
ModuleScriptCustomFetchType custom_fetch_type,
SingleModuleClient* client) {
@@ -132,9 +132,9 @@ void ModuleMap::FetchSingleModuleScript(
// Steps 4-9 loads a new single module script.
// Delegates to ModuleScriptLoader via Modulator.
- ModuleScriptLoader::Fetch(request, fetch_client_settings_object, level,
- modulator_, custom_fetch_type, loader_registry_,
- entry);
+ ModuleScriptLoader::Fetch(request, fetch_client_settings_object_fetcher,
+ level, modulator_, custom_fetch_type,
+ loader_registry_, entry);
}
DCHECK(entry);
diff --git a/chromium/third_party/blink/renderer/core/script/module_map.h b/chromium/third_party/blink/renderer/core/script/module_map.h
index 5c5c341fa22..3949ceba032 100644
--- a/chromium/third_party/blink/renderer/core/script/module_map.h
+++ b/chromium/third_party/blink/renderer/core/script/module_map.h
@@ -16,11 +16,11 @@
namespace blink {
-class FetchClientSettingsObjectSnapshot;
class Modulator;
class ModuleScript;
class ModuleScriptFetchRequest;
class ModuleScriptLoaderRegistry;
+class ResourceFetcher;
class SingleModuleClient;
enum class ModuleGraphLevel;
enum class ModuleScriptCustomFetchType;
@@ -44,7 +44,7 @@ class CORE_EXPORT ModuleMap final : public GarbageCollected<ModuleMap>,
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
void FetchSingleModuleScript(
const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel,
ModuleScriptCustomFetchType,
SingleModuleClient*);
diff --git a/chromium/third_party/blink/renderer/core/script/module_map_test.cc b/chromium/third_party/blink/renderer/core/script/module_map_test.cc
index 6b5f0054de8..9497735ba62 100644
--- a/chromium/third_party/blink/renderer/core/script/module_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_map_test.cc
@@ -110,6 +110,7 @@ class ModuleMapTestModulator final : public DummyModulator {
explicit TestModuleScriptFetcher(ModuleMapTestModulator* modulator)
: modulator_(modulator) {}
void Fetch(FetchParameters& request,
+ ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client* client) override {
TestRequest* test_request = MakeGarbageCollected<TestRequest>(
@@ -163,7 +164,8 @@ class ModuleMapTestModulator final : public DummyModulator {
};
ModuleMapTestModulator::ModuleMapTestModulator(ScriptState* script_state)
- : script_state_(script_state), resolver_(new TestScriptModuleResolver) {}
+ : script_state_(script_state),
+ resolver_(MakeGarbageCollected<TestScriptModuleResolver>()) {}
void ModuleMapTestModulator::Trace(blink::Visitor* visitor) {
visitor->Trace(test_requests_);
@@ -208,13 +210,12 @@ TEST_F(ModuleMapTest, sequentialRequests) {
platform->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
KURL url(NullURL(), "https://example.com/foo.js");
- auto* settings_object =
- GetDocument().CreateFetchClientSettingsObjectSnapshot();
// First request
- TestSingleModuleClient* client = new TestSingleModuleClient;
+ TestSingleModuleClient* client =
+ MakeGarbageCollected<TestSingleModuleClient>();
Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- settings_object,
+ GetDocument().Fetcher(),
ModuleGraphLevel::kTopLevelModuleFetch,
ModuleScriptCustomFetchType::kNone, client);
Modulator()->ResolveFetches();
@@ -230,9 +231,10 @@ TEST_F(ModuleMapTest, sequentialRequests) {
EXPECT_TRUE(client->GetModuleScript());
// Secondary request
- TestSingleModuleClient* client2 = new TestSingleModuleClient;
+ TestSingleModuleClient* client2 =
+ MakeGarbageCollected<TestSingleModuleClient>();
Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- settings_object,
+ GetDocument().Fetcher(),
ModuleGraphLevel::kTopLevelModuleFetch,
ModuleScriptCustomFetchType::kNone, client2);
Modulator()->ResolveFetches();
@@ -255,20 +257,20 @@ TEST_F(ModuleMapTest, concurrentRequestsShouldJoin) {
platform->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
KURL url(NullURL(), "https://example.com/foo.js");
- auto* settings_object =
- GetDocument().CreateFetchClientSettingsObjectSnapshot();
// First request
- TestSingleModuleClient* client = new TestSingleModuleClient;
+ TestSingleModuleClient* client =
+ MakeGarbageCollected<TestSingleModuleClient>();
Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- settings_object,
+ GetDocument().Fetcher(),
ModuleGraphLevel::kTopLevelModuleFetch,
ModuleScriptCustomFetchType::kNone, client);
// Secondary request (which should join the first request)
- TestSingleModuleClient* client2 = new TestSingleModuleClient;
+ TestSingleModuleClient* client2 =
+ MakeGarbageCollected<TestSingleModuleClient>();
Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- settings_object,
+ GetDocument().Fetcher(),
ModuleGraphLevel::kTopLevelModuleFetch,
ModuleScriptCustomFetchType::kNone, client2);
diff --git a/chromium/third_party/blink/renderer/core/script/module_pending_script.h b/chromium/third_party/blink/renderer/core/script/module_pending_script.h
index 518bafa16ab..d1c1576448c 100644
--- a/chromium/third_party/blink/renderer/core/script/module_pending_script.h
+++ b/chromium/third_party/blink/renderer/core/script/module_pending_script.h
@@ -79,8 +79,7 @@ class CORE_EXPORT ModulePendingScript : public PendingScript {
bool IsExternal() const override { return is_external_; }
bool WasCanceled() const override { return false; }
- bool StartStreamingIfPossible(base::OnceClosure) override { return false; }
- bool IsCurrentlyStreaming() const override { return false; }
+ void StartStreamingIfPossible() override {}
KURL UrlForTracing() const override { return NullURL(); }
diff --git a/chromium/third_party/blink/renderer/core/script/module_script.h b/chromium/third_party/blink/renderer/core/script/module_script.h
index 071d0cee791..02c3e13682b 100644
--- a/chromium/third_party/blink/renderer/core/script/module_script.h
+++ b/chromium/third_party/blink/renderer/core/script/module_script.h
@@ -54,8 +54,14 @@ class CORE_EXPORT ModuleScript final : public Script, public NameClient {
ScriptModule Record() const;
bool HasEmptyRecord() const;
+ // Note: ParseError-related methods should only be used from ModuleTreeLinker
+ // or unit tests. You probably want to check |*ErrorToRethrow*()|
+ // instead.
+
void SetParseErrorAndClearRecord(ScriptValue error);
bool HasParseError() const { return !parse_error_.IsEmpty(); }
+
+ // CreateParseError() retrieves |parse_error_| as a ScriptValue.
ScriptValue CreateParseError() const;
void SetErrorToRethrow(ScriptValue error);
@@ -93,6 +99,9 @@ class CORE_EXPORT ModuleScript final : public Script, public NameClient {
Member<Modulator> settings_object_;
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-record
+ // TODO(keishi): Visitor only defines a trace method for v8::Value so this
+ // needs to be cast.
+ GC_PLUGIN_IGNORE("757708")
TraceWrapperV8Reference<v8::Module> record_;
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-parse-error
diff --git a/chromium/third_party/blink/renderer/core/script/pending_script.cc b/chromium/third_party/blink/renderer/core/script/pending_script.cc
index 617d7c8d890..9f23c80d4f1 100644
--- a/chromium/third_party/blink/renderer/core/script/pending_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/pending_script.cc
@@ -126,6 +126,7 @@ void PendingScript::MarkParserBlockingLoadStartTime() {
// <specdef href="https://html.spec.whatwg.org/#execute-the-script-block">
void PendingScript::ExecuteScriptBlock(const KURL& document_url) {
+ TRACE_EVENT0("blink", "PendingScript::ExecuteScriptBlock");
Document* context_document = element_->GetDocument().ContextDocument();
if (!context_document) {
Dispose();
diff --git a/chromium/third_party/blink/renderer/core/script/pending_script.h b/chromium/third_party/blink/renderer/core/script/pending_script.h
index 0ab981568b8..31663d11807 100644
--- a/chromium/third_party/blink/renderer/core/script/pending_script.h
+++ b/chromium/third_party/blink/renderer/core/script/pending_script.h
@@ -97,8 +97,7 @@ class CORE_EXPORT PendingScript
virtual bool WasCanceled() const = 0;
// Support for script streaming.
- virtual bool StartStreamingIfPossible(base::OnceClosure) = 0;
- virtual bool IsCurrentlyStreaming() const = 0;
+ virtual void StartStreamingIfPossible() = 0;
// Used only for tracing, and can return a null URL.
// TODO(hiroshige): It's preferable to return the base URL consistently
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/README.md b/chromium/third_party/blink/renderer/core/script/resources/layered_api/README.md
new file mode 100644
index 00000000000..270d8117aa5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/README.md
@@ -0,0 +1,32 @@
+# Layered API resources directory
+
+This directory stores module JavaScript implementation files of
+[Layered APIs](https://github.com/drufball/layered-apis),
+that are to be bundled with the browser.
+
+## Adding/removing files
+
+When adding/removing files, execute
+
+- `core/script/generate_lapi_grdp.py`
+- `git cl format`
+
+to update the following files:
+
+- `core/script/layered_api_resources.h`
+- `core/script/resources/layered_api/resources.grdp`
+
+and commit these files together with the changes under resources/layered_api/.
+
+(This is not needed when the content of the files are modified)
+
+## Which files are bundled
+
+All files under this directory will be included in the grdp and thus bundled
+in the Chromium binary, except for
+
+- Files directly under `core/script/resources/layered_api`, or
+- Files starting with '.', 'README', or 'OWNERS'.
+
+So be careful about binary size increase when you add new files or add more
+contents to existing files.
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium b/chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium
deleted file mode 100644
index 4119a8375c5..00000000000
--- a/chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium
+++ /dev/null
@@ -1,12 +0,0 @@
-Name: async-local-storage Layered API
-URL: https://github.com/valdrinkoshi/virtual-list
-Version: 4bfe22c2d424e3451acfcf809585336f389f6397
-Security Critical: no
-
-Description:
-Temporarily, the files under this directory are authored by Chromium Authors
-on a github repository, and then imported to Chromium repository directly here,
-until a long-term Layered API development plan is settled.
-
-Local Modifications:
-None (except for renaming to index.js)
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js b/chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js
deleted file mode 100644
index b3971d06895..00000000000
--- a/chromium/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js
+++ /dev/null
@@ -1,253 +0,0 @@
-// TODOs/spec-noncompliances:
-// - Susceptible to tampering of built-in prototypes and globals. We want to
-// work on tooling to ameliorate that.
-
-// TODO: Use private fields when those ship.
-const databaseName = new WeakMap();
-const databasePromise = new WeakMap();
-
-if (!self.isSecureContext) {
- throw new DOMException(
- 'Async local storage is only available in secure contexts',
- 'SecurityError');
-}
-
-export class StorageArea {
- constructor(name) {
- databasePromise.set(this, null);
- databaseName.set(this, `async-local-storage:${name}`);
- }
-
- async set(key, value) {
- throwForDisallowedKey(key);
-
- return performDatabaseOperation(this, 'readwrite', (transaction, store) => {
- store.put(value, key);
-
- return new Promise((resolve, reject) => {
- transaction.oncomplete = () => resolve();
- transaction.onabort = () => reject(transaction.error);
- transaction.onerror = () => reject(transaction.error);
- });
- });
- }
-
- async get(key) {
- throwForDisallowedKey(key);
-
- return performDatabaseOperation(this, 'readonly', (transaction, store) => {
- const request = store.get(key);
-
- return new Promise((resolve, reject) => {
- request.onsuccess = () => resolve(request.result);
- request.onerror = () => reject(request.error);
- });
- });
- }
-
- async has(key) {
- throwForDisallowedKey(key);
-
- return performDatabaseOperation(this, 'readonly', (transaction, store) => {
- const request = store.count(key);
-
- return new Promise((resolve, reject) => {
- request.onsuccess = () => resolve(request.result === 0 ? false : true);
- request.onerror = () => reject(request.error);
- });
- });
- }
-
- async delete(key) {
- throwForDisallowedKey(key);
-
- return performDatabaseOperation(this, 'readwrite', (transaction, store) => {
- store.delete(key);
-
- return new Promise((resolve, reject) => {
- transaction.oncomplete = () => resolve();
- transaction.onabort = () => reject(transaction.error);
- transaction.onerror = () => reject(transaction.error);
- });
- });
- }
-
- async clear() {
- if (!databasePromise.has(this)) {
- return Promise.reject(new TypeError('Invalid this value'));
- }
-
- if (databasePromise.get(this) !== null) {
- return databasePromise.get(this).then(
- () => {
- databasePromise.set(this, null);
- return deleteDatabase(databaseName.get(this));
- },
- () => {
- databasePromise.set(this, null);
- return deleteDatabase(databaseName.get(this));
- });
- }
-
- return deleteDatabase(databaseName.get(this));
- }
-
- async keys() {
- return performDatabaseOperation(this, 'readonly', (transaction, store) => {
- const request = store.getAllKeys(undefined);
-
- return new Promise((resolve, reject) => {
- request.onsuccess = () => resolve(request.result);
- request.onerror = () => reject(request.error);
- });
- });
- }
-
- async values() {
- return performDatabaseOperation(this, 'readonly', (transaction, store) => {
- const request = store.getAll(undefined);
-
- return new Promise((resolve, reject) => {
- request.onsuccess = () => resolve(request.result);
- request.onerror = () => reject(request.error);
- });
- });
- }
-
- async entries() {
- return performDatabaseOperation(this, 'readonly', (transaction, store) => {
- const keysRequest = store.getAllKeys(undefined);
- const valuesRequest = store.getAll(undefined);
-
- return new Promise((resolve, reject) => {
- keysRequest.onerror = () => reject(keysRequest.error);
- valuesRequest.onerror = () => reject(valuesRequest.error);
-
- valuesRequest.onsuccess = () => {
- resolve(zip(keysRequest.result, valuesRequest.result));
- };
- });
- });
- }
-
- get backingStore() {
- if (!databasePromise.has(this)) {
- throw new TypeError('Invalid this value');
- }
-
- return {database: databaseName.get(this), store: 'store', version: 1};
- }
-}
-
-export const storage = new StorageArea('default');
-
-function performDatabaseOperation(area, mode, steps) {
- if (!databasePromise.has(area)) {
- return Promise.reject(new TypeError('Invalid this value'));
- }
-
- if (databasePromise.get(area) === null) {
- initializeDatabasePromise(area);
- }
-
- return databasePromise.get(area).then(database => {
- const transaction = database.transaction('store', mode);
- const store = transaction.objectStore('store');
-
- return steps(transaction, store);
- });
-}
-
-function initializeDatabasePromise(area) {
- databasePromise.set(area, new Promise((resolve, reject) => {
- const request = self.indexedDB.open(databaseName.get(area), 1);
-
- request.onsuccess = () => {
- const database = request.result;
- database.onclose = () => databasePromise.set(area, null);
- database.onversionchange = () => {
- database.close();
- databasePromise.set(area, null);
- };
- resolve(database);
- };
-
- request.onerror = () => reject(request.error);
-
- request.onupgradeneeded = () => {
- try {
- request.result.createObjectStore('store');
- } catch (e) {
- reject(e);
- }
- };
- }));
-}
-
-function isAllowedAsAKey(value) {
- if (typeof value === 'number' || typeof value === 'string') {
- return true;
- }
-
- if (Array.isArray(value)) {
- return true;
- }
-
- if (isDate(value)) {
- return true;
- }
-
- if (ArrayBuffer.isView(value)) {
- return true;
- }
-
- if (isArrayBuffer(value)) {
- return true;
- }
-
- return false;
-}
-
-function isDate(value) {
- try {
- Date.prototype.getTime.call(value);
- return true;
- } catch {
- return false;
- }
-}
-
-const byteLengthGetter =
- Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get;
-function isArrayBuffer(value) {
- try {
- byteLengthGetter.call(value);
- return true;
- } catch {
- return false;
- }
-}
-
-function throwForDisallowedKey(key) {
- if (!isAllowedAsAKey(key)) {
- throw new DOMException(
- 'The given value is not allowed as a key', 'DataError');
- }
-}
-
-function zip(a, b) {
- const result = [];
- for (let i = 0; i < a.length; ++i) {
- result.push([a[i], b[i]]);
- }
-
- return result;
-}
-
-function deleteDatabase(name) {
- return new Promise((resolve, reject) => {
- const request = self.indexedDB.deleteDatabase(name);
- request.onsuccess = () => resolve();
- request.onerror = () => reject(request.error);
- });
-}
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/.eslintrc.js b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/.eslintrc.js
new file mode 100644
index 00000000000..7b8fea0b3bf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/.eslintrc.js
@@ -0,0 +1,337 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module.exports = {
+ root: true,
+ env: {
+ es6: true,
+ browser: true
+ },
+ parserOptions: {
+ sourceType: 'module',
+ ecmaVersion: 2019
+ },
+ rules: {
+ 'for-direction': 'error',
+ 'getter-return': 'error',
+ 'no-async-promise-executor': 'error',
+ 'no-await-in-loop': 'error',
+ 'no-compare-neg-zero': 'error',
+ 'no-cond-assign': ['error', 'except-parens'],
+ 'no-console': 'error',
+ 'no-constant-condition': ['error', {checkLoops: false}],
+ 'no-control-regex': 'error',
+ 'no-debugger': 'error',
+ 'no-dupe-args': 'error',
+ 'no-dupe-keys': 'error',
+ 'no-duplicate-case': 'error',
+ 'no-empty': 'error',
+ 'no-empty-character-class': 'error',
+ 'no-ex-assign': 'error',
+ 'no-extra-boolean-cast': 'error',
+ 'no-extra-parens': [
+ 'error',
+ 'all',
+ {
+ conditionalAssign: false,
+ nestedBinaryExpressions: false,
+ returnAssign: false
+ }
+ ],
+ 'no-extra-semi': 'error',
+ 'no-func-assign': 'error',
+ 'no-inner-declarations': 'off',
+ 'no-invalid-regexp': 'error',
+ 'no-irregular-whitespace': 'error',
+ 'no-misleading-character-class': 'error',
+ 'no-obj-calls': 'error',
+ 'no-prototype-builtins': 'error',
+ 'no-regex-spaces': 'error',
+ 'no-sparse-arrays': 'error',
+ 'no-template-curly-in-string': 'error',
+ 'no-unexpected-multiline': 'error',
+ 'no-unreachable': 'error',
+ 'no-unsafe-finally': 'off',
+ 'no-unsafe-negation': 'error',
+ 'use-isnan': 'error',
+ 'valid-typeof': 'error',
+ 'accessor-pairs': 'error',
+ 'array-callback-return': 'error',
+ 'block-scoped-var': 'off',
+ 'class-methods-use-this': 'off',
+ 'complexity': 'off',
+ 'consistent-return': 'error',
+ 'curly': ['error', 'all'],
+ 'default-case': 'off',
+ 'dot-location': ['error', 'property'],
+ 'dot-notation': 'error',
+ 'eqeqeq': 'error',
+ 'guard-for-in': 'off',
+ 'no-alert': 'error',
+ 'no-caller': 'error',
+ 'no-case-declarations': 'error',
+ 'no-div-regex': 'off',
+ 'no-else-return': 'error',
+ 'no-empty-function': 'off',
+ 'no-empty-pattern': 'error',
+ 'no-eq-null': 'error',
+ 'no-eval': 'error',
+ 'no-extend-native': 'error',
+ 'no-extra-bind': 'error',
+ 'no-extra-label': 'error',
+ 'no-fallthrough': 'error',
+ 'no-floating-decimal': 'error',
+ 'no-global-assign': 'error',
+ 'no-implicit-coercion': 'error',
+ 'no-implicit-globals': 'error',
+ 'no-implied-eval': 'error',
+ 'no-invalid-this': 'error',
+ 'no-iterator': 'error',
+ 'no-labels': ['error', {allowLoop: true}],
+ 'no-lone-blocks': 'error',
+ 'no-loop-func': 'error',
+ 'no-magic-numbers': ['error', {ignore: [0, 1]}],
+ 'no-multi-spaces': ['error', {ignoreEOLComments: true}],
+ 'no-multi-str': 'error',
+ 'no-new': 'error',
+ 'no-new-func': 'error',
+ 'no-new-wrappers': 'error',
+ 'no-octal': 'error',
+ 'no-octal-escape': 'error',
+ 'no-param-reassign': 'off',
+ 'no-process-env': 'error',
+ 'no-proto': 'error',
+ 'no-redeclare': 'error',
+ 'no-restricted-properties': 'off',
+ 'no-return-assign': ['error', 'except-parens'],
+ 'no-return-await': 'error',
+ 'no-script-url': 'off',
+ 'no-self-assign': 'error',
+ 'no-self-compare': 'error',
+ 'no-sequences': 'error',
+ 'no-throw-literal': 'error',
+ 'no-unmodified-loop-condition': 'error',
+ 'no-unused-expressions': 'error',
+ 'no-unused-labels': 'error',
+ 'no-useless-call': 'error',
+ 'no-useless-concat': 'error',
+ 'no-useless-escape': 'error',
+ 'no-useless-return': 'error',
+ 'no-void': 'error',
+ 'no-warning-comments': 'off',
+ 'no-with': 'error',
+ 'prefer-promise-reject-errors': 'error',
+ 'radix': ['error', 'as-needed'],
+ 'require-await': 'off',
+ 'vars-on-top': 'off',
+ 'wrap-iife': ['error', 'outside'],
+ 'yoda': ['error', 'never'],
+ 'strict': ['error', 'global'],
+ 'init-declarations': 'off',
+ 'no-delete-var': 'error',
+ 'no-label-var': 'error',
+ 'no-restricted-globals': 'off',
+ 'no-shadow': 'error',
+ 'no-shadow-restricted-names': 'error',
+ 'no-undef': 'error',
+ 'no-undef-init': 'error',
+ 'no-undefined': 'off',
+ 'no-unused-vars': 'error',
+ 'no-use-before-define': ['error', 'nofunc'],
+ 'callback-return': 'off',
+ 'global-require': 'error',
+ 'handle-callback-err': 'error',
+ 'no-buffer-constructor': 'error',
+ 'no-mixed-requires': ['error', true],
+ 'no-new-require': 'error',
+ 'no-path-concat': 'error',
+ 'no-process-exit': 'error',
+ 'no-restricted-modules': 'off',
+ 'no-sync': 'off',
+ 'array-bracket-newline': ['error', {multiline: true}],
+ 'array-bracket-spacing': ['error', 'never'],
+ 'array-element-newline': 'off',
+ 'block-spacing': ['error', 'always'],
+ 'brace-style': [
+ 'error',
+ '1tbs',
+ {allowSingleLine: false}
+ ],
+ camelcase: ['error', {properties: 'always'}],
+ 'capitalized-comments': 'off',
+ 'comma-dangle': ['error', 'always-multiline'],
+ 'comma-spacing': [
+ 'error',
+ {
+ before: false,
+ after: true
+ }
+ ],
+ 'comma-style': ['error', 'last'],
+ 'computed-property-spacing': ['error', 'never'],
+ 'consistent-this': 'off',
+ 'eol-last': 'error',
+ 'func-call-spacing': ['error', 'never'],
+ 'func-name-matching': 'error',
+ 'func-names': 'off',
+ 'func-style': ['error', 'declaration'],
+ 'function-paren-newline': 'off',
+ 'id-blacklist': 'off',
+ 'id-length': 'off',
+ 'id-match': 'off',
+ indent: 'off', // not really compatible with clang-format
+ 'jsx-quotes': 'off',
+ 'key-spacing': [
+ 'error',
+ {
+ beforeColon: false,
+ afterColon: true,
+ mode: 'strict'
+ }
+ ],
+ 'keyword-spacing': [
+ 'error',
+ {
+ before: true,
+ after: true
+ }
+ ],
+ 'line-comment-position': 'off',
+ 'linebreak-style': ['error', 'unix'],
+ 'lines-around-comment': 'off',
+ 'max-depth': 'off',
+ 'max-len': 'off',
+ 'max-lines': 'off',
+ 'max-nested-callbacks': 'off',
+ 'max-params': 'off',
+ 'max-statements': 'off',
+ 'max-statements-per-line': ['error', {max: 1}],
+ 'multiline-ternary': ['error', 'always-multiline'],
+ 'new-cap': 'error',
+ 'new-parens': 'error',
+ 'newline-per-chained-call': 'off',
+ 'no-array-constructor': 'error',
+ 'no-bitwise': 'off',
+ 'no-continue': 'off',
+ 'no-inline-comments': 'off',
+ 'no-lonely-if': 'error',
+ 'no-mixed-operators': [
+ 'error',
+ {
+ groups: [
+ ['&', '|', '^', '~', '<<', '>>', '>>>'],
+ ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
+ ['&&', '||'],
+ ['in', 'instanceof']
+ ]
+ }
+ ],
+ 'no-mixed-spaces-and-tabs': 'error',
+ 'no-multi-assign': 'off',
+ 'no-multiple-empty-lines': 'error',
+ 'no-negated-condition': 'off',
+ 'no-nested-ternary': 'error',
+ 'no-new-object': 'error',
+ 'no-plusplus': 'off',
+ 'no-restricted-syntax': 'off',
+ 'no-tabs': 'error',
+ 'no-ternary': 'off',
+ 'no-trailing-spaces': 'error',
+ 'no-underscore-dangle': 'off',
+ 'no-unneeded-ternary': 'error',
+ 'no-whitespace-before-property': 'error',
+ 'nonblock-statement-body-position': 'error',
+ 'object-curly-newline': ['error', {consistent: true}],
+ 'object-curly-spacing': ['error', 'never'],
+ 'object-property-newline': 'off',
+ 'one-var': ['error', 'never'],
+ 'one-var-declaration-per-line': ['error', 'initializations'],
+ 'operator-assignment': ['error', 'always'],
+ 'operator-linebreak': ['error', 'after'],
+ 'padded-blocks': ['error', 'never'],
+ 'padding-line-between-statements': 'off',
+ 'quote-props': ['error', 'as-needed'],
+ quotes: [
+ 'error',
+ 'single',
+ {
+ avoidEscape: true,
+ allowTemplateLiterals: true
+ }
+ ],
+ semi: ['error', 'always'],
+ 'semi-spacing': 'error',
+ 'semi-style': 'error',
+ 'sort-keys': 'off',
+ 'sort-vars': 'off',
+ 'space-before-blocks': ['error', 'always'],
+ 'space-before-function-paren': [
+ 'error',
+ {
+ anonymous: 'always',
+ named: 'never'
+ }
+ ],
+ 'space-in-parens': ['error', 'never'],
+ 'space-infix-ops': 'error',
+ 'space-unary-ops': [
+ 'error',
+ {
+ words: true,
+ nonwords: false
+ }
+ ],
+ 'spaced-comment': ['error', 'always'],
+ 'switch-colon-spacing': 'error',
+ 'template-tag-spacing': 'error',
+ 'unicode-bom': 'error',
+ 'wrap-regex': 'off',
+ 'arrow-body-style': 'off',
+ 'arrow-parens': ['error', 'as-needed'],
+ 'arrow-spacing': 'error',
+ 'constructor-super': 'error',
+ 'generator-star-spacing': ['error', 'neither'],
+ 'no-class-assign': 'error',
+ 'no-confusing-arrow': 'off',
+ 'no-const-assign': 'error',
+ 'no-dupe-class-members': 'error',
+ 'no-duplicate-imports': 'error',
+ 'no-new-symbol': 'error',
+ 'no-restricted-imports': 'off',
+ 'no-this-before-super': 'error',
+ 'no-useless-computed-key': 'error',
+ 'no-useless-constructor': 'error',
+ 'no-useless-rename': 'error',
+ 'no-var': 'error',
+ 'object-shorthand': 'error',
+ 'prefer-arrow-callback': 'error',
+ 'prefer-const': ['error', {ignoreReadBeforeAssign: true}],
+ 'prefer-destructuring': [
+ 'error',
+ {
+ VariableDeclarator: {
+ array: false,
+ object: true
+ },
+ AssignmentExpression: {
+ array: false,
+ object: false
+ }
+ },
+ {
+ enforceForRenamedProperties: false
+ }
+ ],
+ 'prefer-numeric-literals': 'error',
+ 'prefer-rest-params': 'error',
+ 'prefer-spread': 'error',
+ 'prefer-template': 'off',
+ 'require-yield': 'error',
+ 'rest-spread-spacing': 'error',
+ 'sort-imports': 'off',
+ 'symbol-description': 'error',
+ 'template-curly-spacing': ['error', 'never'],
+ 'yield-star-spacing': ['error', 'after']
+ }
+};
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/OWNERS b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/OWNERS
new file mode 100644
index 00000000000..b891d42816e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/OWNERS
@@ -0,0 +1,5 @@
+jsbell@chromium.org
+pwnall@chromium.org
+
+# TEAM: storage-dev@chromium.org
+# COMPONENT: Blink>Storage>IndexedDB
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/async_iterator.js b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/async_iterator.js
new file mode 100644
index 00000000000..79f35f28fb3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/async_iterator.js
@@ -0,0 +1,88 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {getNextKey, getNextKeyValuePair, HASNT_STARTED_YET} from './idb_utils.js';
+
+const _performDatabaseOperation = new WeakMap();
+const _lastKey = new WeakMap(); // undefined = got to the end;
+ // HASNT_STARTED_YET = not yet started
+const _ongoingPromise = new WeakMap();
+const _mode = new WeakMap();
+
+const AsyncIteratorPrototype = Object.getPrototypeOf(
+ Object.getPrototypeOf(async function*() {}).prototype);
+
+const StorageAreaAsyncIteratorPrototype = {
+ __proto__: AsyncIteratorPrototype,
+
+ next() {
+ const performDatabaseOperation = _performDatabaseOperation.get(this);
+ if (!performDatabaseOperation) {
+ return Promise.reject(new TypeError('Invalid this value'));
+ }
+
+ // We need to avoid multiple concurrent calls into the main logic of next(),
+ // which can happen if you manually manipulate the async iterator, i.e.
+ // `iter.next(); iter.next()` with no `await`s. This is because until we
+ // actually have the last key set correctly, such concurrent calls will use
+ // the wrong value for lastKey.
+
+ const currentOngoingPromise = _ongoingPromise.get(this);
+ let thisNextPromise;
+ if (currentOngoingPromise !== undefined) {
+ thisNextPromise = currentOngoingPromise.then(
+ () => getNextIterResult(this, performDatabaseOperation));
+ } else {
+ thisNextPromise = getNextIterResult(this, performDatabaseOperation);
+ }
+
+ _ongoingPromise.set(this, thisNextPromise);
+ return thisNextPromise;
+ },
+};
+
+function getNextIterResult(iter, performDatabaseOperation) {
+ return performDatabaseOperation(async (transaction, store) => {
+ const lastKey = _lastKey.get(iter);
+ if (lastKey === undefined) {
+ return {value: undefined, done: true};
+ }
+
+ const mode = _mode.get(iter);
+ let key;
+ let value;
+ let iterResultValue;
+ switch (mode) {
+ case 'keys': {
+ key = await getNextKey(store, lastKey);
+ iterResultValue = key;
+ break;
+ }
+ case 'values': {
+ [key, value] = await getNextKeyValuePair(store, lastKey);
+ iterResultValue = value;
+ break;
+ }
+ case 'entries': {
+ [key, value] = await getNextKeyValuePair(store, lastKey);
+ iterResultValue = key === undefined ? undefined : [key, value];
+ break;
+ }
+ }
+
+ _lastKey.set(iter, key);
+ _ongoingPromise.set(iter, undefined);
+
+ return {value: iterResultValue, done: key === undefined};
+ });
+}
+
+export function createStorageAreaAsyncIterator(mode, performDatabaseOperation) {
+ const iter = Object.create(StorageAreaAsyncIteratorPrototype);
+ _mode.set(iter, mode);
+ _performDatabaseOperation.set(iter, performDatabaseOperation);
+ _lastKey.set(iter, HASNT_STARTED_YET);
+ _ongoingPromise.set(iter, undefined);
+ return iter;
+}
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/idb_utils.js b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/idb_utils.js
new file mode 100644
index 00000000000..6c66ab95a02
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/idb_utils.js
@@ -0,0 +1,107 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export function promiseForRequest(request) {
+ return new Promise((resolve, reject) => {
+ request.onsuccess = () => resolve(request.result);
+ request.onerror = () => reject(request.error);
+ });
+}
+
+export function keyValuePairPromise(store, range) {
+ const keyRequest = store.getKey(range);
+ const valueRequest = store.get(range);
+
+ return new Promise((resolve, reject) => {
+ keyRequest.onerror = () => reject(keyRequest.error);
+ valueRequest.onerror = () => reject(valueRequest.error);
+ valueRequest.onsuccess = () =>
+ resolve([keyRequest.result, valueRequest.result]);
+ });
+}
+
+export function promiseForTransaction(transaction) {
+ return new Promise((resolve, reject) => {
+ transaction.oncomplete = () => resolve();
+ transaction.onabort = () => reject(transaction.error);
+ transaction.onerror = () => reject(transaction.error);
+ });
+}
+
+export function throwForDisallowedKey(key) {
+ if (!isAllowedAsAKey(key)) {
+ throw new DOMException(
+ 'The given value is not allowed as a key', 'DataError');
+ }
+}
+
+export const HASNT_STARTED_YET = {};
+
+export function getNextKey(store, lastKey) {
+ const range = getRangeForKey(lastKey);
+ return promiseForRequest(store.getKey(range));
+}
+
+export function getNextKeyValuePair(store, lastKey) {
+ const range = getRangeForKey(lastKey);
+ return keyValuePairPromise(store, range);
+}
+
+function getRangeForKey(key) {
+ if (key === HASNT_STARTED_YET) {
+ // This is a stand-in for the spec's "unbounded" range, which isn't exposed
+ // to JS currently. If we ever get keys that sort below -Infinity, e.g. per
+ // https://github.com/w3c/IndexedDB/issues/76, then this needs to change.
+ // Alternately, if we add better primitives to IDB for getting the first
+ // key, per
+ // https://github.com/WICG/kv-storage/issues/6#issuecomment-452054944, then
+ // we could use those.
+ return IDBKeyRange.lowerBound(-Infinity);
+ }
+ return IDBKeyRange.lowerBound(key, true);
+}
+
+function isAllowedAsAKey(value) {
+ if (typeof value === 'number' || typeof value === 'string') {
+ return true;
+ }
+
+ if (Array.isArray(value)) {
+ return true;
+ }
+
+ if (isDate(value)) {
+ return true;
+ }
+
+ if (ArrayBuffer.isView(value)) {
+ return true;
+ }
+
+ if (isArrayBuffer(value)) {
+ return true;
+ }
+
+ return false;
+}
+
+function isDate(value) {
+ try {
+ Date.prototype.getTime.call(value);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+const byteLengthGetter =
+ Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get;
+function isArrayBuffer(value) {
+ try {
+ byteLengthGetter.call(value);
+ return true;
+ } catch {
+ return false;
+ }
+}
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/index.js b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/index.js
new file mode 100644
index 00000000000..b35752d1021
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/index.js
@@ -0,0 +1,176 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {createStorageAreaAsyncIterator} from './async_iterator.js';
+import {promiseForRequest, promiseForTransaction, throwForDisallowedKey} from './idb_utils.js';
+
+// TODOs/spec-noncompliances:
+// - Susceptible to tampering of built-in prototypes and globals. We want to
+// work on tooling to ameliorate that.
+
+// TODO: Use private fields when those ship.
+// In the meantime we use this hard-to-understand, but effective, pattern:
+// http://2ality.com/2016/01/private-data-classes.html#keeping-private-data-in-weakmaps
+// Of note, the weak map entries will live only as long as the corresponding StorageArea instances.
+//
+// Cheatsheet:
+// x.#y <---> _y.get(x)
+// x.#y = z <---> _y.set(x, z)
+
+const _databaseName = new WeakMap();
+const _databasePromise = new WeakMap();
+
+const DEFAULT_STORAGE_AREA_NAME = 'default';
+const DEFAULT_IDB_STORE_NAME = 'store';
+
+if (!self.isSecureContext) {
+ throw new DOMException(
+ 'KV Storage is only available in secure contexts',
+ 'SecurityError');
+}
+
+export class StorageArea {
+ constructor(name) {
+ _databasePromise.set(this, null);
+ _databaseName.set(this, `kv-storage:${name}`);
+ }
+
+ async set(key, value) {
+ throwForDisallowedKey(key);
+
+ return performDatabaseOperation(this, 'readwrite', (transaction, store) => {
+ if (value === undefined) {
+ store.delete(key);
+ } else {
+ store.put(value, key);
+ }
+
+ return promiseForTransaction(transaction);
+ });
+ }
+
+ async get(key) {
+ throwForDisallowedKey(key);
+
+ return performDatabaseOperation(this, 'readonly', (transaction, store) => {
+ return promiseForRequest(store.get(key));
+ });
+ }
+
+ async delete(key) {
+ throwForDisallowedKey(key);
+
+ return performDatabaseOperation(this, 'readwrite', (transaction, store) => {
+ store.delete(key);
+ return promiseForTransaction(transaction);
+ });
+ }
+
+ async clear() {
+ if (!_databasePromise.has(this)) {
+ throw new TypeError('Invalid this value');
+ }
+
+ const databasePromise = _databasePromise.get(this);
+ if (databasePromise !== null) {
+ // Don't try to delete, and clear the promise, while we're opening the database; wait for that
+ // first.
+ try {
+ await databasePromise;
+ } catch {
+ // If the database failed to initialize, then that's fine, we'll still try to delete it.
+ }
+
+ _databasePromise.set(this, null);
+ }
+
+ return promiseForRequest(self.indexedDB.deleteDatabase(_databaseName.get(this)));
+ }
+
+ keys() {
+ if (!_databasePromise.has(this)) {
+ throw new TypeError('Invalid this value');
+ }
+
+ return createStorageAreaAsyncIterator(
+ 'keys', steps => performDatabaseOperation(this, 'readonly', steps));
+ }
+
+ values() {
+ if (!_databasePromise.has(this)) {
+ throw new TypeError('Invalid this value');
+ }
+
+ return createStorageAreaAsyncIterator(
+ 'values', steps => performDatabaseOperation(this, 'readonly', steps));
+ }
+
+ entries() {
+ if (!_databasePromise.has(this)) {
+ throw new TypeError('Invalid this value');
+ }
+
+ return createStorageAreaAsyncIterator(
+ 'entries', steps => performDatabaseOperation(this, 'readonly', steps));
+ }
+
+ get backingStore() {
+ if (!_databasePromise.has(this)) {
+ throw new TypeError('Invalid this value');
+ }
+
+ return {
+ database: _databaseName.get(this),
+ store: DEFAULT_IDB_STORE_NAME,
+ version: 1,
+ };
+ }
+}
+
+StorageArea.prototype[Symbol.asyncIterator] = StorageArea.prototype.entries;
+
+export const storage = new StorageArea(DEFAULT_STORAGE_AREA_NAME);
+
+async function performDatabaseOperation(area, mode, steps) {
+ if (!_databasePromise.has(area)) {
+ throw new TypeError('Invalid this value');
+ }
+
+ if (_databasePromise.get(area) === null) {
+ initializeDatabasePromise(area);
+ }
+
+ const database = await _databasePromise.get(area);
+ const transaction = database.transaction(DEFAULT_IDB_STORE_NAME, mode);
+ const store = transaction.objectStore(DEFAULT_IDB_STORE_NAME);
+
+ return steps(transaction, store);
+}
+
+function initializeDatabasePromise(area) {
+ _databasePromise.set(
+ area, new Promise((resolve, reject) => {
+ const request = self.indexedDB.open(_databaseName.get(area), 1);
+
+ request.onsuccess = () => {
+ const database = request.result;
+ database.onclose = () => _databasePromise.set(area, null);
+ database.onversionchange = () => {
+ database.close();
+ _databasePromise.set(area, null);
+ };
+ resolve(database);
+ };
+
+ request.onerror = () => reject(request.error);
+
+ request.onupgradeneeded = () => {
+ try {
+ request.result.createObjectStore(DEFAULT_IDB_STORE_NAME);
+ } catch (e) {
+ reject(e);
+ }
+ };
+ }));
+}
diff --git a/chromium/third_party/blink/renderer/core/script/resources/layered_api/resources.grdp b/chromium/third_party/blink/renderer/core/script/resources/layered_api/resources.grdp
new file mode 100644
index 00000000000..c16d09783b3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/resources/layered_api/resources.grdp
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <!-- Layered API scripts. This file is generated by
+ core/script/generate_lapi_grdp.py and shouldn't modified manually.
+ A corresponding header file (layered_api_resources.h) is also generated.
+ The paths are relative to the main grd file, i.e.
+ third_party/blink/public/blink_resources.grd.
+ -->
+ <include name="IDR_LAYERED_API_BLANK_INDEX_JS" file="../renderer/core/script/resources/layered_api/blank/index.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_KV_STORAGE_ASYNC_ITERATOR_JS" file="../renderer/core/script/resources/layered_api/kv-storage/async_iterator.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_KV_STORAGE_IDB_UTILS_JS" file="../renderer/core/script/resources/layered_api/kv-storage/idb_utils.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_KV_STORAGE_INDEX_JS" file="../renderer/core/script/resources/layered_api/kv-storage/index.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_INDEX_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/index.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_ITEM_SOURCE_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/item-source.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_REPEATER_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/virtual-repeater.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_VIRTUAL_SCROLLER_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/virtual-scroller.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_BASE_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/layouts/layout-1d-base.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_GRID_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/layouts/layout-1d-grid.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+ <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_LAYOUTS_LAYOUT_1D_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/layouts/layout-1d.js" type="BINDATA" skip_minify="true" compress="gzip"/>
+</grit-part>
diff --git a/chromium/third_party/blink/renderer/core/script/script_element_base.h b/chromium/third_party/blink/renderer/core/script/script_element_base.h
index 7f6e6fa21c4..23e974d07a0 100644
--- a/chromium/third_party/blink/renderer/core/script/script_element_base.h
+++ b/chromium/third_party/blink/renderer/core/script/script_element_base.h
@@ -51,6 +51,7 @@ class CORE_EXPORT ScriptElementBase : public GarbageCollectedMixin {
virtual String SourceAttributeValue() const = 0;
virtual String TypeAttributeValue() const = 0;
virtual String ReferrerPolicyAttributeValue() const = 0;
+ virtual String ImportanceAttributeValue() const = 0;
virtual String TextFromChildren() = 0;
virtual bool HasSourceAttribute() const = 0;
diff --git a/chromium/third_party/blink/renderer/core/script/script_loader.cc b/chromium/third_party/blink/renderer/core/script/script_loader.cc
index c058625bbcf..c58812ff1d7 100644
--- a/chromium/third_party/blink/renderer/core/script/script_loader.cc
+++ b/chromium/third_party/blink/renderer/core/script/script_loader.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/importance_attribute.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
#include "third_party/blink/renderer/core/script/classic_pending_script.h"
@@ -140,8 +141,8 @@ bool IsValidClassicScriptTypeAndLanguage(
const String& type,
const String& language,
ScriptLoader::LegacyTypeSupport support_legacy_types) {
- // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used
- // here to maintain backwards compatibility with existing layout tests. The
+ // FIXME: IsLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used
+ // here to maintain backwards compatibility with existing web tests. The
// specific violations are:
// - Allowing type=javascript. type= should only support MIME types, such as
// text/javascript.
@@ -382,6 +383,14 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
&referrer_policy);
}
+ // Priority Hints is currently a non-standard feature, but we can assume the
+ // following (see https://crbug.com/821464):
+ // <spec step="21">Let importance be the current state of the element's
+ // importance content attribute.</spec>
+ String importance_attr = element_->ImportanceAttributeValue();
+ mojom::FetchImportanceMode importance =
+ GetFetchImportanceAttributeValue(importance_attr);
+
// <spec step="21">Let parser metadata be "parser-inserted" if the script
// element has been flagged as "parser-inserted", and "not-parser-inserted"
// otherwise.</spec>
@@ -411,14 +420,17 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// parser metadata is parser metadata, credentials mode is module script
// credentials mode, and referrer policy is referrer policy.</spec>
ScriptFetchOptions options(nonce, integrity_metadata, integrity_attr,
- parser_state, credentials_mode, referrer_policy);
+ parser_state, credentials_mode, referrer_policy,
+ importance);
// <spec step="23">Let settings object be the element's node document's
// relevant settings object.</spec>
//
- // Note: We use |element_document| as "settings object" in the steps below.
- auto* settings_object =
- element_document.CreateFetchClientSettingsObjectSnapshot();
+ // In some cases (mainly for classic scripts) |element_document| is used as
+ // the "settings object", while in other cases (mainly for module scripts)
+ // |content_document| is used.
+ // TODO(hiroshige): Use a consistent Document everywhere.
+ auto* fetch_client_settings_object_fetcher = context_document->Fetcher();
// <spec step="24">If the element has a src content attribute, then:</spec>
if (element_->HasSourceAttribute()) {
@@ -490,7 +502,8 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// options.</spec>
Modulator* modulator = Modulator::From(
ToScriptStateForMainWorld(context_document->GetFrame()));
- FetchModuleScriptTree(url, settings_object, modulator, options);
+ FetchModuleScriptTree(url, fetch_client_settings_object_fetcher,
+ modulator, options);
}
// <spec step="24.6">When the chosen algorithm asynchronously completes, set
// the script's script to the result. At that time, the script is ready.
@@ -575,8 +588,8 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// that time, the script is ready.</spec>
auto* module_tree_client = ModulePendingScriptTreeClient::Create();
modulator->FetchDescendantsForInlineScript(
- module_script, settings_object, mojom::RequestContextType::SCRIPT,
- module_tree_client);
+ module_script, fetch_client_settings_object_fetcher,
+ mojom::RequestContextType::SCRIPT, module_tree_client);
prepared_pending_script_ = ModulePendingScript::Create(
element_, module_tree_client, is_external_script_);
break;
@@ -756,7 +769,7 @@ void ScriptLoader::FetchClassicScript(const KURL& url,
// <specdef href="https://html.spec.whatwg.org/#prepare-a-script">
void ScriptLoader::FetchModuleScriptTree(
const KURL& url,
- FetchClientSettingsObjectSnapshot* settings_object,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
Modulator* modulator,
const ScriptFetchOptions& options) {
// <spec step="24.6.B">"module"
@@ -764,9 +777,9 @@ void ScriptLoader::FetchModuleScriptTree(
// Fetch a module script graph given url, settings object, "script", and
// options.</spec>
auto* module_tree_client = ModulePendingScriptTreeClient::Create();
- modulator->FetchTree(url, settings_object, mojom::RequestContextType::SCRIPT,
- options, ModuleScriptCustomFetchType::kNone,
- module_tree_client);
+ modulator->FetchTree(url, fetch_client_settings_object_fetcher,
+ mojom::RequestContextType::SCRIPT, options,
+ ModuleScriptCustomFetchType::kNone, module_tree_client);
prepared_pending_script_ = ModulePendingScript::Create(
element_, module_tree_client, is_external_script_);
}
diff --git a/chromium/third_party/blink/renderer/core/script/script_loader.h b/chromium/third_party/blink/renderer/core/script/script_loader.h
index 95a3a3d70d6..689d62b12a0 100644
--- a/chromium/third_party/blink/renderer/core/script/script_loader.h
+++ b/chromium/third_party/blink/renderer/core/script/script_loader.h
@@ -41,8 +41,8 @@
namespace blink {
-class FetchClientSettingsObjectSnapshot;
class Resource;
+class ResourceFetcher;
class ScriptElementBase;
class Script;
class ScriptResource;
@@ -131,7 +131,7 @@ class CORE_EXPORT ScriptLoader final
const WTF::TextEncoding&);
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-module-script-tree
void FetchModuleScriptTree(const KURL&,
- FetchClientSettingsObjectSnapshot*,
+ ResourceFetcher*,
Modulator*,
const ScriptFetchOptions&);
diff --git a/chromium/third_party/blink/renderer/core/script/script_module_resolver_impl_test.cc b/chromium/third_party/blink/renderer/core/script/script_module_resolver_impl_test.cc
index 9fbfae71b0a..5cc43ce7b99 100644
--- a/chromium/third_party/blink/renderer/core/script/script_module_resolver_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/script_module_resolver_impl_test.cc
@@ -120,7 +120,7 @@ class ScriptModuleResolverImplTest : public testing::Test {
void ScriptModuleResolverImplTest::SetUp() {
platform_->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
- modulator_ = new ScriptModuleResolverImplTestModulator();
+ modulator_ = MakeGarbageCollected<ScriptModuleResolverImplTestModulator>();
}
TEST_F(ScriptModuleResolverImplTest, RegisterResolveSuccess) {
diff --git a/chromium/third_party/blink/renderer/core/script/script_runner.cc b/chromium/third_party/blink/renderer/core/script/script_runner.cc
index 9f5f0b87626..95d55e55f42 100644
--- a/chromium/third_party/blink/renderer/core/script/script_runner.cc
+++ b/chromium/third_party/blink/renderer/core/script/script_runner.cc
@@ -49,7 +49,9 @@ void ScriptRunner::QueueScriptForExecution(PendingScript* pending_script) {
switch (pending_script->GetSchedulingType()) {
case ScriptSchedulingType::kAsync:
pending_async_scripts_.insert(pending_script);
- TryStream(pending_script);
+ if (!is_suspended_) {
+ pending_script->StartStreamingIfPossible();
+ }
break;
case ScriptSchedulingType::kInOrder:
@@ -116,7 +118,6 @@ void ScriptRunner::NotifyScriptReady(PendingScript* pending_script) {
async_scripts_to_execute_soon_.push_back(pending_script);
PostTask(FROM_HERE);
- TryStreamAny();
break;
case ScriptSchedulingType::kInOrder:
@@ -144,11 +145,6 @@ bool ScriptRunner::RemovePendingInOrderScript(PendingScript* pending_script) {
return true;
}
-void ScriptRunner::NotifyScriptStreamerFinished() {
- PostTask(FROM_HERE);
- TryStreamAny();
-}
-
void ScriptRunner::MovePendingScript(Document& old_document,
Document& new_document,
ScriptLoader* script_loader) {
@@ -206,6 +202,7 @@ void ScriptRunner::MovePendingScript(ScriptRunner* new_runner,
}
bool ScriptRunner::ExecuteInOrderTask() {
+ TRACE_EVENT0("blink", "ScriptRunner::ExecuteInOrderTask");
if (in_order_scripts_to_execute_soon_.IsEmpty())
return false;
@@ -221,20 +218,12 @@ bool ScriptRunner::ExecuteInOrderTask() {
}
bool ScriptRunner::ExecuteAsyncTask() {
- // Find an async script loader which is not currently streaming.
- auto it = std::find_if(async_scripts_to_execute_soon_.begin(),
- async_scripts_to_execute_soon_.end(),
- [](PendingScript* pending_script) {
- DCHECK(pending_script);
- return !pending_script->IsCurrentlyStreaming();
- });
- if (it == async_scripts_to_execute_soon_.end()) {
+ TRACE_EVENT0("blink", "ScriptRunner::ExecuteAsyncTask");
+ if (async_scripts_to_execute_soon_.IsEmpty())
return false;
- }
// Remove the async script loader from the ready-to-exec set and execute.
- PendingScript* pending_script = *it;
- async_scripts_to_execute_soon_.erase(it);
+ PendingScript* pending_script = async_scripts_to_execute_soon_.TakeFirst();
DCHECK_EQ(pending_script->GetSchedulingType(), ScriptSchedulingType::kAsync)
<< "Async scripts queue should not contain any in-order script.";
@@ -256,70 +245,12 @@ void ScriptRunner::ExecuteTask() {
return;
#ifndef NDEBUG
- // Extra tasks should be posted only when we resume after suspending,
- // or when we stream a script. These should all be accounted for in
- // number_of_extra_tasks_.
+ // Extra tasks should be posted only when we resume after suspending. These
+ // should all be accounted for in number_of_extra_tasks_.
DCHECK_GT(number_of_extra_tasks_--, 0);
#endif
}
-void ScriptRunner::TryStreamAny() {
- if (is_suspended_)
- return;
-
- if (!RuntimeEnabledFeatures::WorkStealingInScriptRunnerEnabled())
- return;
-
- // Look through async_scripts_to_execute_soon_, and stream any one of them.
- for (auto pending_script : async_scripts_to_execute_soon_) {
- if (DoTryStream(pending_script))
- return;
- }
-}
-
-void ScriptRunner::TryStream(PendingScript* pending_script) {
- if (!is_suspended_)
- DoTryStream(pending_script);
-}
-
-bool ScriptRunner::DoTryStream(PendingScript* pending_script) {
- // Checks that all callers should have already done.
- DCHECK(!is_suspended_);
- DCHECK(pending_script);
-
- // Currently, we stream only async scripts in this function.
- // Note: HTMLParserScriptRunner kicks streaming for deferred or blocking
- // scripts.
- DCHECK(pending_async_scripts_.find(pending_script) !=
- pending_async_scripts_.end() ||
- std::find(async_scripts_to_execute_soon_.begin(),
- async_scripts_to_execute_soon_.end(),
- pending_script) != async_scripts_to_execute_soon_.end());
-
- if (!pending_script)
- return false;
-
- DCHECK_EQ(pending_script->GetSchedulingType(), ScriptSchedulingType::kAsync);
-
-#ifndef NDEBUG
- bool was_already_streaming = pending_script->IsCurrentlyStreaming();
-#endif
-
- bool success = pending_script->StartStreamingIfPossible(
- WTF::Bind(&ScriptRunner::NotifyScriptStreamerFinished,
- WrapWeakPersistent(this)));
-#ifndef NDEBUG
- if (was_already_streaming) {
- DCHECK(!success);
- } else {
- DCHECK_EQ(success, pending_script->IsCurrentlyStreaming());
- }
- if (success)
- number_of_extra_tasks_++;
-#endif
- return success;
-}
-
void ScriptRunner::Trace(blink::Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(pending_in_order_scripts_);
diff --git a/chromium/third_party/blink/renderer/core/script/script_runner.h b/chromium/third_party/blink/renderer/core/script/script_runner.h
index 9a4608e4495..9f44f22abc5 100644
--- a/chromium/third_party/blink/renderer/core/script/script_runner.h
+++ b/chromium/third_party/blink/renderer/core/script/script_runner.h
@@ -60,7 +60,6 @@ class CORE_EXPORT ScriptRunner final
void Suspend();
void Resume();
void NotifyScriptReady(PendingScript*);
- void NotifyScriptStreamerFinished();
static void MovePendingScript(Document&, Document&, ScriptLoader*);
@@ -86,11 +85,6 @@ class CORE_EXPORT ScriptRunner final
void ExecuteTask();
- // Try to start streaming a specific script or any available script.
- void TryStream(PendingScript*);
- void TryStreamAny();
- bool DoTryStream(PendingScript*); // Implementation for both Try* methods.
-
Member<Document> document_;
HeapDeque<TraceWrapperMember<PendingScript>> pending_in_order_scripts_;
@@ -110,9 +104,8 @@ class CORE_EXPORT ScriptRunner final
#ifndef NDEBUG
// We expect to have one posted task in flight for each script in either
// .._to_be_executed_soon_ queue. This invariant will be temporarily violated
- // when the ScriptRunner is suspended, or when we take a Script out the
- // async_scripts_to_be_executed_soon_ queue for streaming. We'll use this
- // variable to account & check this invariant for debugging.
+ // when the ScriptRunner is suspended. We'll use this variable to account &
+ // check this invariant for debugging.
int number_of_extra_tasks_ = 0;
#endif
DISALLOW_COPY_AND_ASSIGN(ScriptRunner);
diff --git a/chromium/third_party/blink/renderer/core/script/script_runner_test.cc b/chromium/third_party/blink/renderer/core/script/script_runner_test.cc
index 7fab1aa0bec..657d8c610f6 100644
--- a/chromium/third_party/blink/renderer/core/script/script_runner_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/script_runner_test.cc
@@ -49,40 +49,9 @@ class MockPendingScript : public PendingScript {
MOCK_METHOD0(RemoveFromMemoryCache, void());
MOCK_METHOD1(ExecuteScriptBlock, void(const KURL&));
- enum class State {
- kStreamingNotReady,
- kReadyToBeStreamed,
- kStreaming,
- kStreamingFinished,
- };
-
- bool IsCurrentlyStreaming() const override {
- return state_ == State::kStreaming;
- }
-
- void PrepareForStreaming() {
- DCHECK_EQ(state_, State::kStreamingNotReady);
- state_ = State::kReadyToBeStreamed;
- }
-
- bool StartStreamingIfPossible(base::OnceClosure closure) override {
- if (state_ != State::kReadyToBeStreamed)
- return false;
-
- state_ = State::kStreaming;
- streaming_finished_callback_ = std::move(closure);
- return true;
- }
+ void StartStreamingIfPossible() override {}
- void SimulateStreamingEnd() {
- DCHECK_EQ(state_, State::kStreaming);
- state_ = State::kStreamingFinished;
- std::move(streaming_finished_callback_).Run();
- }
-
- State state() const { return state_; }
-
- bool IsReady() const { return is_ready_; }
+ bool IsReady() const override { return is_ready_; }
void SetIsReady(bool is_ready) { is_ready_ = is_ready; }
protected:
@@ -101,7 +70,6 @@ class MockPendingScript : public PendingScript {
return pending_script;
}
- State state_ = State::kStreamingNotReady;
bool is_ready_ = false;
base::OnceClosure streaming_finished_callback_;
};
@@ -449,30 +417,4 @@ TEST_F(ScriptRunnerTest, TryStreamWhenEnqueingScript) {
QueueScriptForExecution(pending_script1);
}
-TEST_F(ScriptRunnerTest, DontExecuteWhileStreaming) {
- auto* pending_script = MockPendingScript::CreateAsync(document_);
-
- // Enqueue script.
- QueueScriptForExecution(pending_script);
-
- // Simulate script load and mark the pending script as streaming ready.
- pending_script->SetIsReady(true);
- pending_script->PrepareForStreaming();
- NotifyScriptReady(pending_script);
-
- // ScriptLoader should have started streaming by now.
- EXPECT_EQ(pending_script->state(), MockPendingScript::State::kStreaming);
-
- // Note that there is no expectation for ScriptLoader::Execute() yet,
- // so the mock will fail if it's called anyway.
- platform_->RunUntilIdle();
-
- // Finish streaming.
- pending_script->SimulateStreamingEnd();
-
- // Now that streaming is finished, expect Execute() to be called.
- EXPECT_CALL(*pending_script, ExecuteScriptBlock(_)).Times(1);
- platform_->RunUntilIdle();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc b/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc
index 09f3c14c895..78135bdb98d 100644
--- a/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc
@@ -26,14 +26,14 @@ ModuleScriptFetcher* WorkerModulatorImpl::CreateModuleScriptFetcher(
auto* global_scope = To<WorkerGlobalScope>(GetExecutionContext());
switch (custom_fetch_type) {
case ModuleScriptCustomFetchType::kNone:
- return MakeGarbageCollected<DocumentModuleScriptFetcher>(
- global_scope->EnsureFetcher());
+ return MakeGarbageCollected<DocumentModuleScriptFetcher>();
case ModuleScriptCustomFetchType::kWorkerConstructor:
return MakeGarbageCollected<WorkerModuleScriptFetcher>(global_scope);
case ModuleScriptCustomFetchType::kWorkletAddModule:
break;
case ModuleScriptCustomFetchType::kInstalledServiceWorker:
- return new InstalledServiceWorkerModuleScriptFetcher(global_scope);
+ return MakeGarbageCollected<InstalledServiceWorkerModuleScriptFetcher>(
+ global_scope);
}
NOTREACHED();
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc b/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
index cee9449e2a5..932fc41526a 100644
--- a/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
@@ -22,7 +22,7 @@ ModuleScriptFetcher* WorkletModulatorImpl::CreateModuleScriptFetcher(
WorkletGlobalScope* global_scope =
To<WorkletGlobalScope>(GetExecutionContext());
return MakeGarbageCollected<WorkletModuleScriptFetcher>(
- global_scope->EnsureFetcher(), global_scope->GetModuleResponsesMap());
+ global_scope->GetModuleResponsesMap());
}
bool WorkletModulatorImpl::IsDynamicImportForbidden(String* reason) {
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc b/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc
index 45f9cffbb37..fb8b13a2005 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc
@@ -56,7 +56,7 @@ cc::PictureLayer* ToCcLayer(GraphicsLayer* layer) {
ScrollAnimatorBase* ScrollAnimatorBase::Create(
ScrollableArea* scrollable_area) {
if (scrollable_area && scrollable_area->ScrollAnimatorEnabled())
- return new ScrollAnimator(scrollable_area);
+ return MakeGarbageCollected<ScrollAnimator>(scrollable_area);
return MakeGarbageCollected<ScrollAnimatorBase>(scrollable_area);
}
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
index 26f4275454f..eff1c3cda58 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
@@ -181,7 +181,7 @@ bool ScrollAnimatorCompositorCoordinator::ReattachCompositorAnimationIfNeeded(
CompositorAnimationTimeline* timeline) {
bool reattached = false;
CompositorElementId element_id = GetScrollElementId();
- DCHECK(element_id || (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ DCHECK(element_id || (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
!GetScrollableArea()->LayerForScrolling()));
if (element_id != element_id_) {
@@ -247,7 +247,7 @@ bool ScrollAnimatorCompositorCoordinator::HasImplOnlyAnimationUpdate() const {
CompositorElementId ScrollAnimatorCompositorCoordinator::GetScrollElementId()
const {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return GetScrollableArea()->GetCompositorElementId();
GraphicsLayer* layer = GetScrollableArea()->LayerForScrolling();
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
index d330dd85b71..5a349fe2f93 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
@@ -685,7 +685,7 @@ namespace blink {
ScrollAnimatorBase* ScrollAnimatorBase::Create(
blink::ScrollableArea* scrollable_area) {
- return new ScrollAnimatorMac(scrollable_area);
+ return MakeGarbageCollected<ScrollAnimatorMac>(scrollable_area);
}
ScrollAnimatorMac::ScrollAnimatorMac(blink::ScrollableArea* scrollable_area)
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
index cf548b4ded3..e2db9abf097 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
@@ -64,10 +64,17 @@ class MockScrollableAreaForAnimatorTest
bool scroll_animator_enabled,
const ScrollOffset& min_offset,
const ScrollOffset& max_offset) {
- return new MockScrollableAreaForAnimatorTest(scroll_animator_enabled,
- min_offset, max_offset);
+ return MakeGarbageCollected<MockScrollableAreaForAnimatorTest>(
+ scroll_animator_enabled, min_offset, max_offset);
}
+ explicit MockScrollableAreaForAnimatorTest(bool scroll_animator_enabled,
+ const ScrollOffset& min_offset,
+ const ScrollOffset& max_offset)
+ : scroll_animator_enabled_(scroll_animator_enabled),
+ min_offset_(min_offset),
+ max_offset_(max_offset) {}
+
MOCK_CONST_METHOD0(VisualRectForScrollbarParts, LayoutRect());
MOCK_CONST_METHOD0(IsActive, bool());
MOCK_CONST_METHOD0(IsThrottled, bool());
@@ -140,13 +147,6 @@ class MockScrollableAreaForAnimatorTest
}
private:
- explicit MockScrollableAreaForAnimatorTest(bool scroll_animator_enabled,
- const ScrollOffset& min_offset,
- const ScrollOffset& max_offset)
- : scroll_animator_enabled_(scroll_animator_enabled),
- min_offset_(min_offset),
- max_offset_(max_offset) {}
-
bool scroll_animator_enabled_;
ScrollOffset min_offset_;
ScrollOffset max_offset_;
@@ -195,7 +195,7 @@ TEST(ScrollAnimatorTest, MainThreadStates) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
ScrollAnimator* scroll_animator =
- new ScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<ScrollAnimator>(scrollable_area, GetMockedTime);
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(2);
// Once from userScroll, once from updateCompositorAnimations.
@@ -249,7 +249,7 @@ TEST(ScrollAnimatorTest, MainThreadEnabled) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
ScrollAnimator* scroll_animator =
- new ScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<ScrollAnimator>(scrollable_area, GetMockedTime);
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(9);
EXPECT_CALL(*scrollable_area, RegisterForAnimation()).Times(6);
@@ -329,7 +329,7 @@ TEST(ScrollAnimatorTest, AnimatedScrollAborted) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
ScrollAnimator* scroll_animator =
- new ScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<ScrollAnimator>(scrollable_area, GetMockedTime);
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(3);
EXPECT_CALL(*scrollable_area, RegisterForAnimation()).Times(2);
@@ -377,7 +377,7 @@ TEST(ScrollAnimatorTest, AnimatedScrollTakeover) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
TestScrollAnimator* scroll_animator =
- new TestScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<TestScrollAnimator>(scrollable_area, GetMockedTime);
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(2);
// Called from userScroll, updateCompositorAnimations, then
@@ -429,7 +429,7 @@ TEST(ScrollAnimatorTest, Disabled) {
MockScrollableAreaForAnimatorTest::Create(false, ScrollOffset(),
ScrollOffset(1000, 1000));
ScrollAnimator* scroll_animator =
- new ScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<ScrollAnimator>(scrollable_area, GetMockedTime);
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(8);
EXPECT_CALL(*scrollable_area, RegisterForAnimation()).Times(0);
@@ -462,7 +462,7 @@ TEST(ScrollAnimatorTest, CancellingAnimationResetsState) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
ScrollAnimator* scroll_animator =
- new ScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<ScrollAnimator>(scrollable_area, GetMockedTime);
// Called from first userScroll, setCurrentOffset, and second userScroll.
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(3);
@@ -528,7 +528,7 @@ TEST(ScrollAnimatorTest, CancellingCompositorAnimation) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
TestScrollAnimator* scroll_animator =
- new TestScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<TestScrollAnimator>(scrollable_area, GetMockedTime);
// Called when reset, not setting anywhere else.
EXPECT_CALL(*scrollable_area, UpdateScrollOffset(_, _)).Times(1);
@@ -608,7 +608,7 @@ TEST(ScrollAnimatorTest, ImplOnlyAnimationUpdatesCleared) {
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(),
ScrollOffset(1000, 1000));
TestScrollAnimator* animator =
- new TestScrollAnimator(scrollable_area, GetMockedTime);
+ MakeGarbageCollected<TestScrollAnimator>(scrollable_area, GetMockedTime);
// From calls to adjust/takeoverImplOnlyScrollOffsetAnimation.
EXPECT_CALL(*scrollable_area, RegisterForAnimation()).Times(3);
@@ -645,7 +645,8 @@ TEST(ScrollAnimatorTest, MainThreadAnimationTargetAdjustment) {
MockScrollableAreaForAnimatorTest* scrollable_area =
MockScrollableAreaForAnimatorTest::Create(true, ScrollOffset(-100, -100),
ScrollOffset(1000, 1000));
- ScrollAnimator* animator = new ScrollAnimator(scrollable_area, GetMockedTime);
+ ScrollAnimator* animator =
+ MakeGarbageCollected<ScrollAnimator>(scrollable_area, GetMockedTime);
scrollable_area->SetScrollAnimator(animator);
// Twice from tickAnimation, once from reset, and twice from
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc
index f94fd517bca..260aff12e90 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -34,7 +34,10 @@
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
+#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
@@ -187,10 +190,9 @@ ScrollResult ScrollableArea::UserScroll(ScrollGranularity granularity,
void ScrollableArea::SetScrollOffset(const ScrollOffset& offset,
ScrollType scroll_type,
ScrollBehavior behavior) {
- if (scroll_type != kSequencedScroll && scroll_type != kClampingScroll &&
- scroll_type != kAnchoringScroll) {
- if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
- sequencer->AbortAnimations();
+ if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer()) {
+ if (sequencer->FilterNewScrollOrAbortCurrent(scroll_type))
+ return;
}
ScrollOffset clamped_offset = ClampScrollOffset(offset);
@@ -324,6 +326,18 @@ void ScrollableArea::ScrollOffsetChanged(const ScrollOffset& offset,
GetScrollOffset() - old_offset, scroll_type);
}
+ if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) {
+ if (GetScrollOffset() != old_offset && GetLayoutBox() &&
+ GetLayoutBox()->GetFrameView() &&
+ GetLayoutBox()
+ ->GetFrameView()
+ ->GetPaintTimingDetector()
+ .NeedToNotifyInputOrScroll()) {
+ GetLayoutBox()->GetFrameView()->GetPaintTimingDetector().NotifyScroll(
+ scroll_type);
+ }
+ }
+
GetScrollAnimator().SetCurrentOffset(offset);
}
@@ -568,7 +582,7 @@ void ScrollableArea::CancelProgrammaticScrollAnimation() {
bool ScrollableArea::ShouldScrollOnMainThread() const {
if (GraphicsLayer* layer = LayerForScrolling()) {
- uint32_t reasons = layer->CcLayer()->main_thread_scrolling_reasons();
+ uint32_t reasons = layer->CcLayer()->GetMainThreadScrollingReasons();
// Should scroll on main thread unless the reason is the one that is set
// by the ScrollAnimator, in which case, the animation can still be
// scheduled on the compositor.
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc
index 8a387729a71..8ecccccd160 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc
@@ -19,7 +19,8 @@ TEST_F(ScrollbarThemeOverlayTest, PaintInvalidation) {
platform;
NiceMock<MockScrollableArea>* mock_scrollable_area =
- new NiceMock<MockScrollableArea>(ScrollOffset(100, 100));
+ MakeGarbageCollected<NiceMock<MockScrollableArea>>(
+ ScrollOffset(100, 100));
ScrollbarThemeOverlay theme(14, 0, ScrollbarThemeOverlay::kAllowHitTest);
Scrollbar* vertical_scrollbar = Scrollbar::CreateForTesting(
diff --git a/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.cc b/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.cc
index 4f56b7b7155..6e6cfd627a5 100644
--- a/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.cc
@@ -25,6 +25,7 @@ void SmoothScrollSequencer::QueueAnimation(ScrollableArea* scrollable,
void SmoothScrollSequencer::RunQueuedAnimations() {
if (queue_.IsEmpty()) {
current_scrollable_ = nullptr;
+ scroll_type_ = kProgrammaticScroll;
return;
}
SequencedScroll* sequenced_scroll = queue_.back();
@@ -41,6 +42,25 @@ void SmoothScrollSequencer::AbortAnimations() {
current_scrollable_ = nullptr;
}
queue_.clear();
+ scroll_type_ = kProgrammaticScroll;
+}
+
+bool SmoothScrollSequencer::FilterNewScrollOrAbortCurrent(
+ ScrollType incoming_type) {
+ // Allow the incoming scroll to co-exist if its scroll type is
+ // kSequencedScroll, kClampingScroll, or kAnchoringScroll
+ if (incoming_type == kSequencedScroll || incoming_type == kClampingScroll ||
+ incoming_type == kAnchoringScroll)
+ return false;
+
+ // If the current sequenced scroll is UserScroll, but the incoming scroll is
+ // not, filter the incoming scroll. See crbug.com/913009 for more details.
+ if (scroll_type_ == kUserScroll && incoming_type != kUserScroll)
+ return true;
+
+ // Otherwise, abort the current sequenced scroll.
+ AbortAnimations();
+ return false;
}
void SmoothScrollSequencer::DidDisposeScrollableArea(
diff --git a/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h b/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h
index a5d028e4b7f..ed3018303e8 100644
--- a/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h
+++ b/chromium/third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h
@@ -42,7 +42,9 @@ struct SequencedScroll final : public GarbageCollected<SequencedScroll> {
class CORE_EXPORT SmoothScrollSequencer final
: public GarbageCollected<SmoothScrollSequencer> {
public:
- SmoothScrollSequencer() = default;
+ SmoothScrollSequencer() : scroll_type_(kProgrammaticScroll) {}
+ void SetScrollType(ScrollType type) { scroll_type_ = type; }
+
// Add a scroll offset animation to the back of a queue.
void QueueAnimation(ScrollableArea*, ScrollOffset, ScrollBehavior);
@@ -52,6 +54,10 @@ class CORE_EXPORT SmoothScrollSequencer final
// Abort the currently running animation and all the animations in the queue.
void AbortAnimations();
+ // Given the incoming scroll's scroll type, returns whether to filter the
+ // incoming scroll. It may also abort the current sequenced scroll.
+ bool FilterNewScrollOrAbortCurrent(ScrollType incoming_type);
+
void DidDisposeScrollableArea(const ScrollableArea&);
void Trace(blink::Visitor*);
@@ -59,6 +65,7 @@ class CORE_EXPORT SmoothScrollSequencer final
private:
HeapVector<Member<SequencedScroll>> queue_;
Member<ScrollableArea> current_scrollable_;
+ ScrollType scroll_type_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/BUILD.gn b/chromium/third_party/blink/renderer/core/streams/BUILD.gn
index 4ddb512fda8..1e82808c34a 100644
--- a/chromium/third_party/blink/renderer/core/streams/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/streams/BUILD.gn
@@ -22,5 +22,7 @@ blink_core_sources("streams") {
"underlying_source_base.h",
"writable_stream.cc",
"writable_stream.h",
+ "writable_stream_wrapper.cc",
+ "writable_stream_wrapper.h",
]
}
diff --git a/chromium/third_party/blink/renderer/core/streams/CommonOperations.js b/chromium/third_party/blink/renderer/core/streams/CommonOperations.js
index 266850799a4..9423a115435 100644
--- a/chromium/third_party/blink/renderer/core/streams/CommonOperations.js
+++ b/chromium/third_party/blink/renderer/core/streams/CommonOperations.js
@@ -310,7 +310,7 @@
function isATypeError(object) {
// There doesn't appear to be a 100% reliable way to identify a TypeError
// from JS.
- return getPrototypeOf(object) === TypeError_prototype;
+ return object !== null && getPrototypeOf(object) === TypeError_prototype;
}
function isADOMException(object) {
@@ -329,6 +329,7 @@
switch (typeof reason) {
case 'string':
case 'number':
+ case 'boolean':
return {encoder: 'json', string: JSON_stringify(reason)};
case 'object':
@@ -477,20 +478,17 @@
const {type, value} = callFunction(binding.MessageEvent_data_get, evt);
// assert(type === kChunk || type === kClose || type === kAbort ||
// type=kError);
+ if (finished) {
+ return;
+ }
switch (type) {
case kChunk:
- if (finished) {
- return;
- }
binding.ReadableStreamDefaultControllerEnqueue(controller, value);
resolvePromise(backpressurePromise);
backpressurePromise = v8.createPromise();
break;
case kClose:
- if (finished) {
- return;
- }
finished = true;
binding.ReadableStreamDefaultControllerClose(controller);
callFunction(binding.MessagePort_close, port);
@@ -498,9 +496,6 @@
case kAbort:
case kError:
- if (finished) {
- return;
- }
finished = true;
binding.ReadableStreamDefaultControllerError(
controller, unpackReason(value));
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream.cc
index f71fefdabc0..1d4e81ad22e 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_operations.h"
#include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
@@ -240,6 +241,7 @@ ScriptValue ReadableStream::pipeThrough(ScriptState* script_state,
exception_state);
}
+// https://streams.spec.whatwg.org/#rs-pipe-through
ScriptValue ReadableStream::pipeThrough(ScriptState* script_state,
ScriptValue transform_stream,
ScriptValue options,
@@ -247,57 +249,100 @@ ScriptValue ReadableStream::pipeThrough(ScriptState* script_state,
v8::Local<v8::Value> pair_value = transform_stream.V8Value();
v8::Local<v8::Context> context = script_state->GetContext();
- constexpr char kWritableIsUndefined[] =
- "Failed to execute 'pipeThrough' on 'ReadableStream': "
- "parameter 1's 'writable' property is undefined.";
- constexpr char kReadableIsUndefined[] =
- "Failed to execute 'pipeThrough' on 'ReadableStream': "
- "parameter 1's 'readable' property is undefined.";
+ constexpr char kWritableIsNotWritableStream[] =
+ "parameter 1's 'writable' property is not a WritableStream.";
+ constexpr char kReadableIsNotReadableStream[] =
+ "parameter 1's 'readable' property is not a ReadableStream.";
+ constexpr char kWritableIsLocked[] = "parameter 1's 'writable' is locked.";
v8::Local<v8::Object> pair;
if (!pair_value->ToObject(context).ToLocal(&pair)) {
- exception_state.ThrowTypeError(kWritableIsUndefined);
+ exception_state.ThrowTypeError(kWritableIsNotWritableStream);
return ScriptValue();
}
- v8::TryCatch block(script_state->GetIsolate());
+ v8::Isolate* isolate = script_state->GetIsolate();
v8::Local<v8::Value> writable, readable;
- if (!pair->Get(context, V8String(script_state->GetIsolate(), "writable"))
- .ToLocal(&writable)) {
- exception_state.RethrowV8Exception(block.Exception());
+ {
+ v8::TryCatch block(isolate);
+ if (!pair->Get(context, V8String(isolate, "writable")).ToLocal(&writable)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return ScriptValue();
+ }
+ DCHECK(!block.HasCaught());
+
+ if (!pair->Get(context, V8String(isolate, "readable")).ToLocal(&readable)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return ScriptValue();
+ }
+ DCHECK(!block.HasCaught());
+ }
+
+ // 2. If ! IsWritableStream(_writable_) is *false*, throw a *TypeError*
+ // exception.
+ WritableStream* dom_writable =
+ V8WritableStream::ToImplWithTypeCheck(isolate, writable);
+ if (!dom_writable) {
+ exception_state.ThrowTypeError(kWritableIsNotWritableStream);
return ScriptValue();
}
- DCHECK(!block.HasCaught());
- if (writable->IsUndefined()) {
- exception_state.ThrowTypeError(kWritableIsUndefined);
+ // 3. If ! IsReadableStream(_readable_) is *false*, throw a *TypeError*
+ // exception.
+ if (!V8ReadableStream::HasInstance(readable, isolate)) {
+ exception_state.ThrowTypeError(kReadableIsNotReadableStream);
return ScriptValue();
}
- if (!pair->Get(context, V8String(script_state->GetIsolate(), "readable"))
- .ToLocal(&readable)) {
- exception_state.RethrowV8Exception(block.Exception());
+ // TODO(ricea): When aborting pipes is supported, implement step 5:
+ // 5. If _signal_ is not *undefined*, and _signal_ is not an instance of the
+ // `AbortSignal` interface, throw a *TypeError* exception.
+
+ // 6. If ! IsReadableStreamLocked(*this*) is *true*, throw a *TypeError*
+ // exception.
+ if (IsLocked(script_state, exception_state).value_or(false)) {
+ exception_state.ThrowTypeError("Cannot pipe a locked stream");
+ return ScriptValue();
+ }
+ if (exception_state.HadException()) {
return ScriptValue();
}
- DCHECK(!block.HasCaught());
- if (readable->IsUndefined()) {
- exception_state.ThrowTypeError(kReadableIsUndefined);
+ // 7. If ! IsWritableStreamLocked(_writable_) is *true*, throw a *TypeError*
+ // exception.
+ if (dom_writable->IsLocked(script_state, exception_state).value_or(false)) {
+ exception_state.ThrowTypeError(kWritableIsLocked);
return ScriptValue();
}
+ if (exception_state.HadException()) {
+ return ScriptValue();
+ }
+
+ // This cast is safe because the following code will only be run when the
+ // native version of WritableStream is not in use.
+ // TODO(ricea): Add a CHECK() for the feature flag here.
+ WritableStreamWrapper* writable_wrapper =
+ static_cast<WritableStreamWrapper*>(dom_writable);
+
+ // 8. Let _promise_ be ! ReadableStreamPipeTo(*this*, _writable_,
+ // _preventClose_, _preventAbort_, _preventCancel_,
+ // _signal_).
- ScriptPromise promise =
- pipeTo(script_state, ScriptValue(script_state, writable), options,
- exception_state);
- if (!exception_state.HadException()) {
- // set promise.[[PromiseIsHandled]] to true.
- // We don't have a primitive to do this, so let's attach a catch handler.
- //
- // ScriptPromise::Then(f, g) is a confusing interface, it is actually
- // |promise.then(f).catch(g)|.
- promise.Then(v8::Local<v8::Function>(),
- NoopFunction::CreateFunction(script_state));
+ // TODO(ricea): Maybe change the parameters to
+ // ReadableStreamOperations::PipeTo to match ReadableStreamPipeTo() in the
+ // standard?
+ ScriptPromise promise = ReadableStreamOperations::PipeTo(
+ script_state, GetInternalStream(script_state),
+ writable_wrapper->GetInternalStream(script_state), options,
+ exception_state);
+ if (exception_state.HadException()) {
+ return ScriptValue();
}
+
+ // 9. Set _promise_.[[PromiseIsHandled]] to *true*.
+ promise.MarkAsHandled();
+
+ // 10. Return _readable_.
return ScriptValue(script_state, readable);
}
@@ -336,9 +381,16 @@ ScriptPromise ReadableStream::pipeTo(ScriptState* script_state,
if (exception_state.HadException())
return ScriptPromise();
+ // This cast is safe because the following code will only be run when the
+ // native version of WritableStream is not in use.
+ // TODO(ricea): Add a CHECK() for the feature flag here.
+ WritableStreamWrapper* destination_wrapper =
+ static_cast<WritableStreamWrapper*>(destination);
+
return ReadableStreamOperations::PipeTo(
script_state, GetInternalStream(script_state),
- destination->GetInternalStream(script_state), options, exception_state);
+ destination_wrapper->GetInternalStream(script_state), options,
+ exception_state);
}
ScriptValue ReadableStream::tee(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
index 8ad8e81b3b4..840c87f185b 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
@@ -34,14 +34,15 @@ class ReadableStreamOperationsTestNotReached : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
ReadableStreamOperationsTestNotReached* self =
- new ReadableStreamOperationsTestNotReached(script_state);
+ MakeGarbageCollected<ReadableStreamOperationsTestNotReached>(
+ script_state);
return self->BindToV8Function();
}
- private:
explicit ReadableStreamOperationsTestNotReached(ScriptState* script_state)
: ScriptFunction(script_state) {}
+ private:
ScriptValue Call(ScriptValue) override;
};
@@ -67,7 +68,8 @@ class Iteration final : public GarbageCollectedFinalized<Iteration> {
is_valid_ = false;
return;
}
- value_ = ToCoreString(value->ToString(v.GetScriptState()->GetIsolate()));
+ value_ = ToCoreString(
+ value->ToString(v.GetScriptState()->GetContext()).ToLocalChecked());
}
bool IsSet() const { return is_set_; }
@@ -88,19 +90,20 @@ class ReaderFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
Iteration* iteration) {
- ReaderFunction* self = new ReaderFunction(script_state, iteration);
+ ReaderFunction* self =
+ MakeGarbageCollected<ReaderFunction>(script_state, iteration);
return self->BindToV8Function();
}
+ ReaderFunction(ScriptState* script_state, Iteration* iteration)
+ : ScriptFunction(script_state), iteration_(iteration) {}
+
void Trace(blink::Visitor* visitor) override {
visitor->Trace(iteration_);
ScriptFunction::Trace(visitor);
}
private:
- ReaderFunction(ScriptState* script_state, Iteration* iteration)
- : ScriptFunction(script_state), iteration_(iteration) {}
-
ScriptValue Call(ScriptValue value) override {
iteration_->Set(value);
return value;
@@ -244,8 +247,8 @@ TEST(ReadableStreamOperationsTest, Read) {
scope.GetScriptState(), reader, ASSERT_NO_EXCEPTION)
.value_or(false));
- Iteration* it1 = new Iteration();
- Iteration* it2 = new Iteration();
+ Iteration* it1 = MakeGarbageCollected<Iteration>();
+ Iteration* it2 = MakeGarbageCollected<Iteration>();
ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
.Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1),
ReadableStreamOperationsTestNotReached::CreateFunction(
@@ -283,7 +286,8 @@ TEST(ReadableStreamOperationsTest,
CreateReadableStreamWithCustomUnderlyingSourceAndStrategy) {
V8TestingScope scope;
TryCatchScope try_catch_scope(scope.GetIsolate());
- auto* underlying_source = new TestUnderlyingSource(scope.GetScriptState());
+ auto* underlying_source =
+ MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
ScriptValue strategy = ReadableStreamOperations::CreateCountQueuingStrategy(
scope.GetScriptState(), 10);
@@ -306,9 +310,9 @@ TEST(ReadableStreamOperationsTest,
ASSERT_NO_EXCEPTION);
ASSERT_FALSE(reader.IsEmpty());
- Iteration* it1 = new Iteration();
- Iteration* it2 = new Iteration();
- Iteration* it3 = new Iteration();
+ Iteration* it1 = MakeGarbageCollected<Iteration>();
+ Iteration* it2 = MakeGarbageCollected<Iteration>();
+ Iteration* it3 = MakeGarbageCollected<Iteration>();
ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
.Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1),
ReadableStreamOperationsTestNotReached::CreateFunction(
@@ -350,7 +354,8 @@ TEST(ReadableStreamOperationsTest,
UnderlyingSourceShouldHavePendingActivityWhenLockedAndControllerIsActive) {
V8TestingScope scope;
TryCatchScope try_catch_scope(scope.GetIsolate());
- auto* underlying_source = new TestUnderlyingSource(scope.GetScriptState());
+ auto* underlying_source =
+ MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
ScriptValue strategy = ReadableStreamOperations::CreateCountQueuingStrategy(
scope.GetScriptState(), 10);
@@ -545,8 +550,8 @@ TEST(ReadableStreamOperationsTest, Tee) {
ASSERT_FALSE(reader1.IsEmpty());
ASSERT_FALSE(reader2.IsEmpty());
- Iteration* it1 = new Iteration();
- Iteration* it2 = new Iteration();
+ Iteration* it1 = MakeGarbageCollected<Iteration>();
+ Iteration* it2 = MakeGarbageCollected<Iteration>();
ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader1)
.Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1),
ReadableStreamOperationsTestNotReached::CreateFunction(
@@ -600,7 +605,7 @@ TEST(ReadableStreamOperationsTest, Serialize) {
ScriptValue reader = ReadableStreamOperations::GetReader(
scope.GetScriptState(), transferred, ASSERT_NO_EXCEPTION);
ASSERT_FALSE(reader.IsEmpty());
- Iteration* it = new Iteration();
+ Iteration* it = MakeGarbageCollected<Iteration>();
ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
.Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it),
ReadableStreamOperationsTestNotReached::CreateFunction(
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream.cc b/chromium/third_party/blink/renderer/core/streams/transform_stream.cc
index 066821136b1..77f74ea721d 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream.cc
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream.cc
@@ -12,7 +12,7 @@
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
-#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
@@ -30,16 +30,11 @@ class TransformStream::Algorithm : public ScriptFunction {
static v8::Local<v8::Function> Create(TransformStreamTransformer* transformer,
ScriptState* script_state,
ExceptionState& exception_state) {
- auto* algorithm = new T(transformer, script_state, exception_state);
+ auto* algorithm =
+ MakeGarbageCollected<T>(transformer, script_state, exception_state);
return algorithm->BindToV8Function();
}
- void Trace(Visitor* visitor) override {
- visitor->Trace(transformer_);
- ScriptFunction::Trace(visitor);
- }
-
- protected:
Algorithm(TransformStreamTransformer* transformer,
ScriptState* script_state,
ExceptionState& exception_state)
@@ -48,6 +43,12 @@ class TransformStream::Algorithm : public ScriptFunction {
interface_name_(exception_state.InterfaceName()),
property_name_(exception_state.PropertyName()) {}
+ void Trace(Visitor* visitor) override {
+ visitor->Trace(transformer_);
+ ScriptFunction::Trace(visitor);
+ }
+
+ protected:
// AlgorithmScope holds the stack-allocated objects used by the CallRaw()
// methods for FlushAlgorithm and TransformAlgorithm.
class AlgorithmScope {
@@ -122,6 +123,9 @@ class TransformStream::TransformAlgorithm : public TransformStream::Algorithm {
};
TransformStream::TransformStream() = default;
+TransformStream::TransformStream(ReadableStream* readable,
+ WritableStream* writable)
+ : readable_(readable), writable_(writable) {}
TransformStream::~TransformStream() = default;
@@ -174,8 +178,10 @@ TransformStream* TransformStream::Create(ScriptState* script_state,
}
}
DCHECK(stream->IsObject());
- ts->InitInternal(script_state, stream.As<v8::Object>(), exception_state);
- return ts->stream_.IsEmpty() ? nullptr : ts;
+ if (!ts->InitInternal(script_state, stream.As<v8::Object>(), exception_state))
+ return nullptr;
+
+ return ts;
}
void TransformStream::Init(TransformStreamTransformer* transformer,
@@ -202,13 +208,12 @@ void TransformStream::Init(TransformStreamTransformer* transformer,
}
void TransformStream::Trace(Visitor* visitor) {
- visitor->Trace(stream_);
visitor->Trace(readable_);
visitor->Trace(writable_);
ScriptWrappable::Trace(visitor);
}
-void TransformStream::InitInternal(ScriptState* script_state,
+bool TransformStream::InitInternal(ScriptState* script_state,
v8::Local<v8::Object> stream,
ExceptionState& exception_state) {
v8::Local<v8::Value> readable, writable;
@@ -218,13 +223,13 @@ void TransformStream::InitInternal(ScriptState* script_state,
args)
.ToLocal(&readable)) {
exception_state.RethrowV8Exception(block.Exception());
- return;
+ return false;
}
if (!V8ScriptRunner::CallExtra(script_state, "getTransformStreamWritable",
args)
.ToLocal(&writable)) {
exception_state.RethrowV8Exception(block.Exception());
- return;
+ return false;
}
DCHECK(readable->IsObject());
@@ -232,16 +237,16 @@ void TransformStream::InitInternal(ScriptState* script_state,
script_state, readable.As<v8::Object>(), exception_state);
if (!readable_)
- return;
+ return false;
DCHECK(writable->IsObject());
- writable_ = WritableStream::CreateFromInternalStream(
+ writable_ = WritableStreamWrapper::CreateFromInternalStream(
script_state, writable.As<v8::Object>(), exception_state);
if (!writable_)
- return;
+ return false;
- stream_.Set(script_state->GetIsolate(), stream);
+ return true;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream.h b/chromium/third_party/blink/renderer/core/streams/transform_stream.h
index 45149039855..602a383c707 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream.h
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream.h
@@ -29,7 +29,8 @@ class WritableStream;
// defined in C++. Provides access to the readable and writable streams.
//
// On-heap references to this class must always be via a TraceWrapperMember, and
-// must always have an ancestor in the V8 heap, or |stream_| will be lost.
+// must always have an ancestor in the V8 heap, or the internal JavaScript
+// objects owned by |readable_| and |writable_| will be lost.
//
// To ensure that the JS TransformStream is always referenced, this class uses
// two-stage construction. After calling the constructor, store the reference
@@ -40,6 +41,11 @@ class CORE_EXPORT TransformStream final : public ScriptWrappable {
public:
TransformStream();
+
+ // This constructor produces a TransformStream from an existing {readable,
+ // writable} pair. It cannot fail and does not require calling Init().
+ TransformStream(ReadableStream*, WritableStream*);
+
~TransformStream() override;
// |Create| functions internally call Init().
@@ -76,11 +82,10 @@ class CORE_EXPORT TransformStream final : public ScriptWrappable {
class FlushAlgorithm;
class TransformAlgorithm;
- void InitInternal(ScriptState*,
+ bool InitInternal(ScriptState*,
v8::Local<v8::Object> stream,
ExceptionState&);
- TraceWrapperV8Reference<v8::Value> stream_;
TraceWrapperMember<ReadableStream> readable_;
TraceWrapperMember<WritableStream> writable_;
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc b/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc
index 26d78b97e3b..abeaa2f815b 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc
@@ -45,7 +45,7 @@ class TransformStreamTest : public ::testing::Test {
void Init(TransformStreamTransformer* transformer,
ScriptState* script_state,
ExceptionState& exception_state) {
- holder_ = new Holder(script_state);
+ holder_ = MakeGarbageCollected<Holder>(script_state);
holder_->Stream()->Init(transformer, script_state, exception_state);
}
@@ -135,13 +135,15 @@ class MockTransformStreamTransformer : public TransformStreamTransformer {
// If this doesn't work then nothing else will.
TEST_F(TransformStreamTest, Construct) {
V8TestingScope scope;
- Init(new IdentityTransformer(), scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ Init(MakeGarbageCollected<IdentityTransformer>(), scope.GetScriptState(),
+ ASSERT_NO_EXCEPTION);
EXPECT_TRUE(Stream());
}
TEST_F(TransformStreamTest, Accessors) {
V8TestingScope scope;
- Init(new IdentityTransformer(), scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ Init(MakeGarbageCollected<IdentityTransformer>(), scope.GetScriptState(),
+ ASSERT_NO_EXCEPTION);
ReadableStream* readable = Stream()->Readable();
WritableStream* writable = Stream()->Writable();
EXPECT_TRUE(readable);
@@ -150,7 +152,7 @@ TEST_F(TransformStreamTest, Accessors) {
TEST_F(TransformStreamTest, TransformIsCalled) {
V8TestingScope scope;
- auto* mock = new ::testing::StrictMock<MockTransformStreamTransformer>();
+ auto* mock = MakeGarbageCollected<MockTransformStreamTransformer>();
Init(mock, scope.GetScriptState(), ASSERT_NO_EXCEPTION);
// Need to run microtasks so the startAlgorithm promise resolves.
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
@@ -170,7 +172,7 @@ TEST_F(TransformStreamTest, TransformIsCalled) {
TEST_F(TransformStreamTest, FlushIsCalled) {
V8TestingScope scope;
- auto* mock = new ::testing::StrictMock<MockTransformStreamTransformer>();
+ auto* mock = MakeGarbageCollected<MockTransformStreamTransformer>();
Init(mock, scope.GetScriptState(), ASSERT_NO_EXCEPTION);
// Need to run microtasks so the startAlgorithm promise resolves.
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
@@ -189,14 +191,14 @@ TEST_F(TransformStreamTest, FlushIsCalled) {
class ExpectNotReached : public ScriptFunction {
public:
static v8::Local<v8::Function> Create(ScriptState* script_state) {
- auto* self = new ExpectNotReached(script_state);
+ auto* self = MakeGarbageCollected<ExpectNotReached>(script_state);
return self->BindToV8Function();
}
- private:
explicit ExpectNotReached(ScriptState* script_state)
: ScriptFunction(script_state) {}
+ private:
ScriptValue Call(ScriptValue) override {
ADD_FAILURE() << "ExpectNotReached was reached";
return ScriptValue();
@@ -210,16 +212,17 @@ class ExpectChunkIsString : public ScriptFunction {
static v8::Local<v8::Function> Create(ScriptState* script_state,
const String& expected,
bool* called) {
- auto* self = new ExpectChunkIsString(script_state, expected, called);
+ auto* self = MakeGarbageCollected<ExpectChunkIsString>(script_state,
+ expected, called);
return self->BindToV8Function();
}
- private:
ExpectChunkIsString(ScriptState* script_state,
const String& expected,
bool* called)
: ScriptFunction(script_state), expected_(expected), called_(called) {}
+ private:
ScriptValue Call(ScriptValue value) override {
*called_ = true;
if (!value.IsObject()) {
@@ -248,16 +251,17 @@ class ExpectTypeError : public ScriptFunction {
static v8::Local<v8::Function> Create(ScriptState* script_state,
const String& message,
bool* called) {
- auto* self = new ExpectTypeError(script_state, message, called);
+ auto* self =
+ MakeGarbageCollected<ExpectTypeError>(script_state, message, called);
return self->BindToV8Function();
}
- private:
ExpectTypeError(ScriptState* script_state,
const String& message,
bool* called)
: ScriptFunction(script_state), message_(message), called_(called) {}
+ private:
ScriptValue Call(ScriptValue value) override {
*called_ = true;
EXPECT_TRUE(IsTypeError(GetScriptState(), value, message_));
@@ -298,7 +302,8 @@ class ExpectTypeError : public ScriptFunction {
TEST_F(TransformStreamTest, EnqueueFromTransform) {
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
- Init(new IdentityTransformer(), script_state, ASSERT_NO_EXCEPTION);
+ Init(MakeGarbageCollected<IdentityTransformer>(), script_state,
+ ASSERT_NO_EXCEPTION);
CopyReadableAndWritableToGlobal(scope);
@@ -337,8 +342,8 @@ TEST_F(TransformStreamTest, EnqueueFromFlush) {
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
- Init(new EnqueueFromFlushTransformer(scope.GetContext()->Global(),
- scope.GetIsolate()),
+ Init(MakeGarbageCollected<EnqueueFromFlushTransformer>(
+ scope.GetContext()->Global(), scope.GetIsolate()),
script_state, ASSERT_NO_EXCEPTION);
CopyReadableAndWritableToGlobal(scope);
@@ -370,7 +375,8 @@ TEST_F(TransformStreamTest, ThrowFromTransform) {
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
- Init(new ThrowFromTransformTransformer(), script_state, ASSERT_NO_EXCEPTION);
+ Init(MakeGarbageCollected<ThrowFromTransformTransformer>(), script_state,
+ ASSERT_NO_EXCEPTION);
CopyReadableAndWritableToGlobal(scope);
@@ -410,7 +416,8 @@ TEST_F(TransformStreamTest, ThrowFromFlush) {
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
- Init(new ThrowFromFlushTransformer(), script_state, ASSERT_NO_EXCEPTION);
+ Init(MakeGarbageCollected<ThrowFromFlushTransformer>(), script_state,
+ ASSERT_NO_EXCEPTION);
CopyReadableAndWritableToGlobal(scope);
@@ -436,5 +443,16 @@ TEST_F(TransformStreamTest, ThrowFromFlush) {
EXPECT_TRUE(writableTypeErrorThrown);
}
+TEST_F(TransformStreamTest, CreateFromReadableWritablePair) {
+ V8TestingScope scope;
+ ReadableStream* readable =
+ ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ WritableStream* writable =
+ WritableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ TransformStream transform(readable, writable);
+ EXPECT_EQ(readable, transform.Readable());
+ EXPECT_EQ(writable, transform.Writable());
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl b/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl
index 8e61f0aac31..d943658bcc2 100644
--- a/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl
+++ b/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl
@@ -14,7 +14,7 @@
interface UnderlyingSourceBase {
[CallWith=ScriptState, ImplementedAs=startWrapper] Promise<void> start(any stream);
[CallWith=ScriptState] Promise<void> pull();
- [CallWith=ScriptState, ImplementedAs=cancelWrapper] Promise<void> cancel([Default=Undefined] optional any reason);
+ [CallWith=ScriptState, ImplementedAs=cancelWrapper] Promise<void> cancel([DefaultValue=Undefined] optional any reason);
// This only exists to prevent Object.prototype.type being accessed.
[CallWith=ScriptState] readonly attribute any type;
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream.cc
index 26ea2b2dd08..292fda8738c 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream.cc
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream.cc
@@ -8,32 +8,13 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
-void WritableStream::Init(ScriptState* script_state,
- ScriptValue underlying_sink,
- ScriptValue strategy,
- ExceptionState& exception_state) {
- v8::Local<v8::Object> internal_stream;
- v8::TryCatch block(script_state->GetIsolate());
-
- if (!CreateInternalStream(script_state, underlying_sink.V8Value(),
- strategy.V8Value())
- .ToLocal(&internal_stream)) {
- exception_state.RethrowV8Exception(block.Exception());
- return;
- }
-
- if (!InitInternal(script_state, internal_stream)) {
- exception_state.RethrowV8Exception(block.Exception());
- return;
- }
-}
-
WritableStream* WritableStream::Create(ScriptState* script_state,
ExceptionState& exception_state) {
return Create(
@@ -56,7 +37,8 @@ WritableStream* WritableStream::Create(ScriptState* script_state,
ScriptValue underlying_sink,
ScriptValue strategy,
ExceptionState& exception_state) {
- auto* stream = MakeGarbageCollected<WritableStream>();
+ // TODO(ricea): Switch on Blink feature.
+ auto* stream = MakeGarbageCollected<WritableStreamWrapper>();
stream->Init(script_state, underlying_sink, strategy, exception_state);
if (exception_state.HadException())
return nullptr;
@@ -64,193 +46,13 @@ WritableStream* WritableStream::Create(ScriptState* script_state,
return stream;
}
-WritableStream* WritableStream::CreateFromInternalStream(
- ScriptState* script_state,
- v8::Local<v8::Object> internal_stream,
- ExceptionState& exception_state) {
- v8::TryCatch block(script_state->GetIsolate());
- auto* stream = MakeGarbageCollected<WritableStream>();
- if (!stream->InitInternal(script_state, internal_stream)) {
- exception_state.RethrowV8Exception(block.Exception());
- return nullptr;
- }
- return stream;
-}
-
-bool WritableStream::InitInternal(ScriptState* script_state,
- v8::Local<v8::Object> internal_stream) {
- v8::Isolate* isolate = script_state->GetIsolate();
-
-#if DCHECK_IS_ON()
- v8::Local<v8::Value> args[] = {internal_stream};
- v8::Local<v8::Value> result_value;
-
- if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStream", args)
- .ToLocal(&result_value)) {
- DLOG(FATAL) << "Failing to call IsWritableStream for DCHECK.";
- return false;
- }
- DCHECK(result_value->BooleanValue(isolate));
-#endif // DCHECK_IS_ON()
-
- internal_stream_.Set(isolate, internal_stream);
-
- v8::Local<v8::Value> wrapper = ToV8(this, script_state);
- if (wrapper.IsEmpty())
- return false;
-
- v8::Local<v8::Context> context = script_state->GetContext();
- v8::Local<v8::Object> bindings =
- context->GetExtrasBindingObject().As<v8::Object>();
- v8::Local<v8::Value> symbol_value;
- if (!bindings->Get(context, V8String(isolate, "internalWritableStreamSymbol"))
- .ToLocal(&symbol_value)) {
- return false;
- }
-
- if (wrapper.As<v8::Object>()
- ->Set(context, symbol_value.As<v8::Symbol>(),
- internal_stream_.NewLocal(isolate))
- .IsNothing()) {
- return false;
- }
-
- return RetainWrapperDuringConstruction(this, script_state);
-}
-
-v8::MaybeLocal<v8::Object> WritableStream::CreateInternalStream(
- ScriptState* script_state,
- v8::Local<v8::Value> underlying_sink,
- v8::Local<v8::Value> strategy) {
- v8::Local<v8::Value> args[] = {underlying_sink, strategy};
- v8::Local<v8::Value> stream;
-
- if (!V8ScriptRunner::CallExtra(script_state, "createWritableStream", args)
- .ToLocal(&stream)) {
- return v8::MaybeLocal<v8::Object>();
- }
-
- DCHECK(stream->IsObject());
- return v8::MaybeLocal<v8::Object>(stream.As<v8::Object>());
-}
-
-void WritableStream::Trace(Visitor* visitor) {
- visitor->Trace(internal_stream_);
- ScriptWrappable::Trace(visitor);
-}
-
-bool WritableStream::locked(ScriptState* script_state,
- ExceptionState& exception_state) const {
- auto result = IsLocked(script_state, exception_state);
-
- return !result || *result;
-}
-
-ScriptPromise WritableStream::abort(ScriptState* script_state,
- ExceptionState& exception_state) {
- return abort(
- script_state,
- ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())),
- exception_state);
-}
-
-ScriptPromise WritableStream::abort(ScriptState* script_state,
- ScriptValue reason,
- ExceptionState& exception_state) {
- if (locked(script_state, exception_state) &&
- !exception_state.HadException()) {
- exception_state.ThrowTypeError("Cannot abort a locked stream");
- }
-
- v8::Local<v8::Value> args[] = {
- internal_stream_.NewLocal(script_state->GetIsolate()), reason.V8Value()};
- v8::TryCatch block(script_state->GetIsolate());
- v8::Local<v8::Value> result;
-
- if (!V8ScriptRunner::CallExtra(script_state, "WritableStreamAbort", args)
- .ToLocal(&result)) {
- exception_state.RethrowV8Exception(block.Exception());
- return ScriptPromise();
- }
- return ScriptPromise(script_state, result);
-}
-
-ScriptValue WritableStream::getWriter(ScriptState* script_state,
- ExceptionState& exception_state) {
- v8::TryCatch block(script_state->GetIsolate());
- v8::Local<v8::Value> args[] = {
- internal_stream_.NewLocal(script_state->GetIsolate())};
- v8::Local<v8::Value> result;
-
- if (!V8ScriptRunner::CallExtra(script_state,
- "AcquireWritableStreamDefaultWriter", args)
- .ToLocal(&result)) {
- exception_state.RethrowV8Exception(block.Exception());
- return ScriptValue();
- }
- return ScriptValue(script_state, result);
-}
-
-base::Optional<bool> WritableStream::IsLocked(
- ScriptState* script_state,
- ExceptionState& exception_state) const {
- v8::TryCatch block(script_state->GetIsolate());
- v8::Local<v8::Value> args[] = {
- internal_stream_.NewLocal(script_state->GetIsolate())};
- v8::Local<v8::Value> result_value;
-
- if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStreamLocked", args)
- .ToLocal(&result_value)) {
- exception_state.RethrowV8Exception(block.Exception());
- return base::nullopt;
- }
- return result_value->BooleanValue(script_state->GetIsolate());
-}
-
-void WritableStream::Serialize(ScriptState* script_state,
- MessagePort* port,
- ExceptionState& exception_state) {
- DCHECK(port);
- DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
- v8::TryCatch block(script_state->GetIsolate());
- v8::Local<v8::Value> port_v8_value = ToV8(port, script_state);
- DCHECK(!port_v8_value.IsEmpty());
- v8::Local<v8::Value> args[] = {ToV8(this, script_state), port_v8_value};
- V8ScriptRunner::CallExtra(script_state, "WritableStreamSerialize", args);
- if (block.HasCaught()) {
- exception_state.RethrowV8Exception(block.Exception());
- }
-}
-
// static
WritableStream* WritableStream::Deserialize(ScriptState* script_state,
MessagePort* port,
ExceptionState& exception_state) {
- // We need to execute V8 Extras JavaScript to create the new WritableStream.
- // We will not run author code.
- auto* isolate = script_state->GetIsolate();
- v8::Isolate::AllowJavascriptExecutionScope allow_js(isolate);
- DCHECK(port);
- DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
- v8::TryCatch block(isolate);
- v8::Local<v8::Value> port_v8 = ToV8(port, script_state);
- DCHECK(!port_v8.IsEmpty());
- v8::Local<v8::Value> args[] = {port_v8};
- ScriptValue internal_stream(
- script_state, V8ScriptRunner::CallExtra(
- script_state, "WritableStreamDeserialize", args));
- if (block.HasCaught()) {
- exception_state.RethrowV8Exception(block.Exception());
- return nullptr;
- }
- DCHECK(!internal_stream.IsEmpty());
- return CreateFromInternalStream(script_state, internal_stream,
- exception_state);
-}
-
-ScriptValue WritableStream::GetInternalStream(ScriptState* script_state) const {
- return ScriptValue(script_state,
- internal_stream_.NewLocal(script_state->GetIsolate()));
+ // TODO(ricea): Switch on Blink feature.
+ return WritableStreamWrapper::Deserialize(script_state, port,
+ exception_state);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream.h b/chromium/third_party/blink/renderer/core/streams/writable_stream.h
index c2326c72673..0520505622b 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream.h
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream.h
@@ -22,19 +22,8 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- // Call one of Init functions before using the instance.
- WritableStream() = default;
- ~WritableStream() override = default;
-
- // If an error happens, |exception_state.HadException()| will be true, and
- // |this| will not be usable after that.
- void Init(ScriptState*,
- ScriptValue underlying_sink,
- ScriptValue strategy,
- ExceptionState& exception_state);
-
- // Create* functions call Init* internally and return null when an error
- // happens.
+ // Create function selects an implementation of WritableStream to use at
+ // runtime.
static WritableStream* Create(ScriptState*, ExceptionState&);
static WritableStream* Create(ScriptState*,
ScriptValue underlying_sink,
@@ -43,33 +32,21 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
ScriptValue underlying_sink,
ScriptValue strategy,
ExceptionState&);
- static WritableStream* CreateFromInternalStream(
- ScriptState* script_state,
- ScriptValue internal_stream,
- ExceptionState& exception_state) {
- DCHECK(internal_stream.IsObject());
- return CreateFromInternalStream(script_state,
- internal_stream.V8Value().As<v8::Object>(),
- exception_state);
- }
- static WritableStream* CreateFromInternalStream(
- ScriptState*,
- v8::Local<v8::Object> internal_stream,
- ExceptionState&);
-
- void Trace(Visitor* visitor) override;
// IDL defined functions
- bool locked(ScriptState*, ExceptionState&) const;
- ScriptPromise abort(ScriptState*, ExceptionState&);
- ScriptPromise abort(ScriptState*, ScriptValue reason, ExceptionState&);
- ScriptValue getWriter(ScriptState*, ExceptionState&);
+ virtual bool locked(ScriptState*, ExceptionState&) const = 0;
+ virtual ScriptPromise abort(ScriptState*, ExceptionState&) = 0;
+ virtual ScriptPromise abort(ScriptState*,
+ ScriptValue reason,
+ ExceptionState&) = 0;
+ virtual ScriptValue getWriter(ScriptState*, ExceptionState&) = 0;
- base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const;
+ virtual base::Optional<bool> IsLocked(ScriptState*,
+ ExceptionState&) const = 0;
// Serialize this stream to |port|. The stream will be locked by this
// operation.
- void Serialize(ScriptState*, MessagePort* port, ExceptionState&);
+ virtual void Serialize(ScriptState*, MessagePort* port, ExceptionState&) = 0;
// Given a |port| which is entangled with a MessagePort that was previously
// passed to Serialize(), returns a new WritableStream which behaves like it
@@ -77,18 +54,6 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
static WritableStream* Deserialize(ScriptState*,
MessagePort* port,
ExceptionState&);
-
- ScriptValue GetInternalStream(ScriptState*) const;
-
- private:
- bool InitInternal(ScriptState*, v8::Local<v8::Object> internal_stream);
-
- static v8::MaybeLocal<v8::Object> CreateInternalStream(
- ScriptState* script_state,
- v8::Local<v8::Value> underlying_sink,
- v8::Local<v8::Value> strategy);
-
- TraceWrapperV8Reference<v8::Object> internal_stream_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
new file mode 100644
index 00000000000..e8c7bd1d3d2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
@@ -0,0 +1,230 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
+#include "third_party/blink/renderer/core/messaging/message_port.h"
+#include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+void WritableStreamWrapper::Init(ScriptState* script_state,
+ ScriptValue underlying_sink,
+ ScriptValue strategy,
+ ExceptionState& exception_state) {
+ v8::Local<v8::Object> internal_stream;
+ v8::TryCatch block(script_state->GetIsolate());
+
+ if (!CreateInternalStream(script_state, underlying_sink.V8Value(),
+ strategy.V8Value())
+ .ToLocal(&internal_stream)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+
+ if (!InitInternal(script_state, internal_stream)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+}
+
+WritableStreamWrapper* WritableStreamWrapper::CreateFromInternalStream(
+ ScriptState* script_state,
+ v8::Local<v8::Object> internal_stream,
+ ExceptionState& exception_state) {
+ v8::TryCatch block(script_state->GetIsolate());
+ auto* stream = MakeGarbageCollected<WritableStreamWrapper>();
+ if (!stream->InitInternal(script_state, internal_stream)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return nullptr;
+ }
+ return stream;
+}
+
+bool WritableStreamWrapper::InitInternal(
+ ScriptState* script_state,
+ v8::Local<v8::Object> internal_stream) {
+ v8::Isolate* isolate = script_state->GetIsolate();
+
+#if DCHECK_IS_ON()
+ v8::Local<v8::Value> args[] = {internal_stream};
+ v8::Local<v8::Value> result_value;
+
+ if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStream", args)
+ .ToLocal(&result_value)) {
+ DLOG(FATAL) << "Failing to call IsWritableStream for DCHECK.";
+ return false;
+ }
+ DCHECK(result_value->BooleanValue(isolate));
+#endif // DCHECK_IS_ON()
+
+ internal_stream_.Set(isolate, internal_stream);
+
+ v8::Local<v8::Value> wrapper = ToV8(this, script_state);
+ if (wrapper.IsEmpty())
+ return false;
+
+ v8::Local<v8::Context> context = script_state->GetContext();
+ v8::Local<v8::Object> bindings =
+ context->GetExtrasBindingObject().As<v8::Object>();
+ v8::Local<v8::Value> symbol_value;
+ if (!bindings->Get(context, V8String(isolate, "internalWritableStreamSymbol"))
+ .ToLocal(&symbol_value)) {
+ return false;
+ }
+
+ if (wrapper.As<v8::Object>()
+ ->Set(context, symbol_value.As<v8::Symbol>(),
+ internal_stream_.NewLocal(isolate))
+ .IsNothing()) {
+ return false;
+ }
+
+ return RetainWrapperDuringConstruction(this, script_state);
+}
+
+v8::MaybeLocal<v8::Object> WritableStreamWrapper::CreateInternalStream(
+ ScriptState* script_state,
+ v8::Local<v8::Value> underlying_sink,
+ v8::Local<v8::Value> strategy) {
+ v8::Local<v8::Value> args[] = {underlying_sink, strategy};
+ v8::Local<v8::Value> stream;
+
+ if (!V8ScriptRunner::CallExtra(script_state, "createWritableStream", args)
+ .ToLocal(&stream)) {
+ return v8::MaybeLocal<v8::Object>();
+ }
+
+ DCHECK(stream->IsObject());
+ return v8::MaybeLocal<v8::Object>(stream.As<v8::Object>());
+}
+
+void WritableStreamWrapper::Trace(Visitor* visitor) {
+ visitor->Trace(internal_stream_);
+ ScriptWrappable::Trace(visitor);
+}
+
+bool WritableStreamWrapper::locked(ScriptState* script_state,
+ ExceptionState& exception_state) const {
+ auto result = IsLocked(script_state, exception_state);
+
+ return !result || *result;
+}
+
+ScriptPromise WritableStreamWrapper::abort(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ return abort(
+ script_state,
+ ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())),
+ exception_state);
+}
+
+ScriptPromise WritableStreamWrapper::abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) {
+ if (locked(script_state, exception_state) &&
+ !exception_state.HadException()) {
+ exception_state.ThrowTypeError("Cannot abort a locked stream");
+ }
+
+ v8::Local<v8::Value> args[] = {
+ internal_stream_.NewLocal(script_state->GetIsolate()), reason.V8Value()};
+ v8::TryCatch block(script_state->GetIsolate());
+ v8::Local<v8::Value> result;
+
+ if (!V8ScriptRunner::CallExtra(script_state, "WritableStreamAbort", args)
+ .ToLocal(&result)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return ScriptPromise();
+ }
+ return ScriptPromise(script_state, result);
+}
+
+ScriptValue WritableStreamWrapper::getWriter(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ v8::TryCatch block(script_state->GetIsolate());
+ v8::Local<v8::Value> args[] = {
+ internal_stream_.NewLocal(script_state->GetIsolate())};
+ v8::Local<v8::Value> result;
+
+ if (!V8ScriptRunner::CallExtra(script_state,
+ "AcquireWritableStreamDefaultWriter", args)
+ .ToLocal(&result)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return ScriptValue();
+ }
+ return ScriptValue(script_state, result);
+}
+
+base::Optional<bool> WritableStreamWrapper::IsLocked(
+ ScriptState* script_state,
+ ExceptionState& exception_state) const {
+ v8::TryCatch block(script_state->GetIsolate());
+ v8::Local<v8::Value> args[] = {
+ internal_stream_.NewLocal(script_state->GetIsolate())};
+ v8::Local<v8::Value> result_value;
+
+ if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStreamLocked", args)
+ .ToLocal(&result_value)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return base::nullopt;
+ }
+ return result_value->BooleanValue(script_state->GetIsolate());
+}
+
+void WritableStreamWrapper::Serialize(ScriptState* script_state,
+ MessagePort* port,
+ ExceptionState& exception_state) {
+ DCHECK(port);
+ DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
+ v8::TryCatch block(script_state->GetIsolate());
+ v8::Local<v8::Value> port_v8_value = ToV8(port, script_state);
+ DCHECK(!port_v8_value.IsEmpty());
+ v8::Local<v8::Value> args[] = {GetInternalStream(script_state).V8Value(),
+ port_v8_value};
+ V8ScriptRunner::CallExtra(script_state, "WritableStreamSerialize", args);
+ if (block.HasCaught()) {
+ exception_state.RethrowV8Exception(block.Exception());
+ }
+}
+
+// static
+WritableStreamWrapper* WritableStreamWrapper::Deserialize(
+ ScriptState* script_state,
+ MessagePort* port,
+ ExceptionState& exception_state) {
+ // We need to execute V8 Extras JavaScript to create the new WritableStream.
+ // We will not run author code.
+ auto* isolate = script_state->GetIsolate();
+ v8::Isolate::AllowJavascriptExecutionScope allow_js(isolate);
+ DCHECK(port);
+ DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
+ v8::TryCatch block(isolate);
+ v8::Local<v8::Value> port_v8 = ToV8(port, script_state);
+ DCHECK(!port_v8.IsEmpty());
+ v8::Local<v8::Value> args[] = {port_v8};
+ ScriptValue internal_stream(
+ script_state, V8ScriptRunner::CallExtra(
+ script_state, "WritableStreamDeserialize", args));
+ if (block.HasCaught()) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return nullptr;
+ }
+ DCHECK(!internal_stream.IsEmpty());
+ return CreateFromInternalStream(script_state, internal_stream,
+ exception_state);
+}
+
+ScriptValue WritableStreamWrapper::GetInternalStream(
+ ScriptState* script_state) const {
+ return ScriptValue(script_state,
+ internal_stream_.NewLocal(script_state->GetIsolate()));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h
new file mode 100644
index 00000000000..81f2e96a380
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class MessagePort;
+
+// This is an implementation of the WritableStream interface that delegates to
+// the V8 Extras implementation. Use TraceWrapperMember to hold a reference to
+// an instance of this class.
+class CORE_EXPORT WritableStreamWrapper final : public WritableStream {
+ public:
+ // Call one of Init functions before using the instance.
+ WritableStreamWrapper() = default;
+ ~WritableStreamWrapper() override = default;
+
+ // If an error happens, |exception_state.HadException()| will be true, and
+ // |this| will not be usable after that.
+ void Init(ScriptState*,
+ ScriptValue underlying_sink,
+ ScriptValue strategy,
+ ExceptionState& exception_state);
+
+ static WritableStreamWrapper* CreateFromInternalStream(
+ ScriptState* script_state,
+ ScriptValue internal_stream,
+ ExceptionState& exception_state) {
+ DCHECK(internal_stream.IsObject());
+ return CreateFromInternalStream(script_state,
+ internal_stream.V8Value().As<v8::Object>(),
+ exception_state);
+ }
+ static WritableStreamWrapper* CreateFromInternalStream(
+ ScriptState*,
+ v8::Local<v8::Object> internal_stream,
+ ExceptionState&);
+
+ void Trace(Visitor* visitor) override;
+
+ // IDL defined functions
+ bool locked(ScriptState*, ExceptionState&) const override;
+ ScriptPromise abort(ScriptState*, ExceptionState&) override;
+ ScriptPromise abort(ScriptState*,
+ ScriptValue reason,
+ ExceptionState&) override;
+ ScriptValue getWriter(ScriptState*, ExceptionState&) override;
+
+ base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override;
+
+ // Serialize this stream to |port|. The stream will be locked by this
+ // operation.
+ void Serialize(ScriptState*, MessagePort* port, ExceptionState&) override;
+
+ // Given a |port| which is entangled with a MessagePort that was previously
+ // passed to Serialize(), returns a new WritableStreamWrapper which behaves
+ // like it was the original.
+ static WritableStreamWrapper* Deserialize(ScriptState*,
+ MessagePort* port,
+ ExceptionState&);
+
+ ScriptValue GetInternalStream(ScriptState*) const;
+
+ private:
+ bool InitInternal(ScriptState*, v8::Local<v8::Object> internal_stream);
+
+ static v8::MaybeLocal<v8::Object> CreateInternalStream(
+ ScriptState* script_state,
+ v8::Local<v8::Value> underlying_sink,
+ v8::Local<v8::Value> strategy);
+
+ TraceWrapperV8Reference<v8::Object> internal_stream_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style.cc b/chromium/third_party/blink/renderer/core/style/computed_style.cc
index 2bf035fc166..6bd3651e9fe 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style.cc
+++ b/chromium/third_party/blink/renderer/core/style/computed_style.cc
@@ -84,12 +84,30 @@ ASSERT_SIZE(BorderValue, SameSizeAsBorderValue);
// Since different compilers/architectures pack ComputedStyle differently,
// re-create the same structure for an accurate size comparison.
-struct SameSizeAsComputedStyle : public RefCounted<SameSizeAsComputedStyle> {
- struct ComputedStyleBase {
- void* data_refs[7];
- unsigned bitfields_[4];
- } base_;
+//
+// Keep a separate struct for ComputedStyleBase so that we can recreate the
+// inheritance structure. Make sure the fields have the same access specifiers
+// as in the "real" class since it can affect the layout. Reference the fields
+// so that they are not seen as unused (-Wunused-private-field).
+struct SameSizeAsComputedStyleBase {
+ SameSizeAsComputedStyleBase() {
+ base::debug::Alias(&data_refs);
+ base::debug::Alias(&bitfields);
+ }
+
+ private:
+ void* data_refs[7];
+ unsigned bitfields[5];
+};
+struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase,
+ public RefCounted<SameSizeAsComputedStyle> {
+ SameSizeAsComputedStyle() {
+ base::debug::Alias(&own_ptrs);
+ base::debug::Alias(&data_ref_svg_style);
+ }
+
+ private:
void* own_ptrs[1];
void* data_ref_svg_style;
};
@@ -445,18 +463,6 @@ const ComputedStyle* ComputedStyle::AddCachedPseudoStyle(
return result;
}
-void ComputedStyle::RemoveCachedPseudoStyle(PseudoId pid) {
- if (!cached_pseudo_styles_)
- return;
- for (wtf_size_t i = 0; i < cached_pseudo_styles_->size(); ++i) {
- const ComputedStyle* pseudo_style = cached_pseudo_styles_->at(i).get();
- if (pseudo_style->StyleType() == pid) {
- cached_pseudo_styles_->EraseAt(i);
- return;
- }
- }
-}
-
bool ComputedStyle::InheritedEqual(const ComputedStyle& other) const {
return IndependentInheritedEqual(other) &&
NonIndependentInheritedEqual(other);
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style.h b/chromium/third_party/blink/renderer/core/style/computed_style.h
index 63263e883dd..6948bb1e459 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style.h
+++ b/chromium/third_party/blink/renderer/core/style/computed_style.h
@@ -297,7 +297,6 @@ class ComputedStyle : public ComputedStyleBase,
const ComputedStyle* GetCachedPseudoStyle(PseudoId) const;
const ComputedStyle* AddCachedPseudoStyle(scoped_refptr<ComputedStyle>);
- void RemoveCachedPseudoStyle(PseudoId);
/**
* ComputedStyle properties
@@ -2130,9 +2129,13 @@ class ComputedStyle : public ComputedStyleBase,
}
// Whitespace utility functions.
+ static bool Is(EWhiteSpace a, EWhiteSpace b) {
+ return static_cast<unsigned>(a) & static_cast<unsigned>(b);
+ }
+ static bool IsNot(EWhiteSpace a, EWhiteSpace b) { return !Is(a, b); }
static bool AutoWrap(EWhiteSpace ws) {
// Nowrap and pre don't automatically wrap.
- return ws != EWhiteSpace::kNowrap && ws != EWhiteSpace::kPre;
+ return IsNot(ws, EWhiteSpace::kNowrap | EWhiteSpace::kPre);
}
bool AutoWrap() const { return AutoWrap(WhiteSpace()); }
@@ -2150,7 +2153,8 @@ class ComputedStyle : public ComputedStyleBase,
static bool CollapseWhiteSpace(EWhiteSpace ws) {
// Pre and prewrap do not collapse whitespace.
- return ws != EWhiteSpace::kPre && ws != EWhiteSpace::kPreWrap;
+ return IsNot(ws, EWhiteSpace::kPre | EWhiteSpace::kPreWrap |
+ EWhiteSpace::kBreakSpaces);
}
bool CollapseWhiteSpace() const { return CollapseWhiteSpace(WhiteSpace()); }
@@ -2166,15 +2170,15 @@ class ComputedStyle : public ComputedStyleBase,
return false;
}
bool BreakOnlyAfterWhiteSpace() const {
- return WhiteSpace() == EWhiteSpace::kPreWrap ||
+ return Is(WhiteSpace(),
+ EWhiteSpace::kPreWrap | EWhiteSpace::kBreakSpaces) ||
GetLineBreak() == LineBreak::kAfterWhiteSpace;
}
bool BreakWords() const {
return (WordBreak() == EWordBreak::kBreakWord ||
OverflowWrap() == EOverflowWrap::kBreakWord) &&
- WhiteSpace() != EWhiteSpace::kPre &&
- WhiteSpace() != EWhiteSpace::kNowrap;
+ IsNot(WhiteSpace(), EWhiteSpace::kPre | EWhiteSpace::kNowrap);
}
// Text direction utility functions.
@@ -2488,7 +2492,7 @@ class ComputedStyle : public ComputedStyleBase,
StyleColor DecorationColorIncludingFallback(bool visited_link) const;
- Color StopColor() const { return SvgStyle().StopColor(); }
+ const StyleColor& StopColor() const { return SvgStyle().StopColor(); }
StyleColor FloodColor() const { return SvgStyle().FloodColor(); }
StyleColor LightingColor() const { return SvgStyle().LightingColor(); }
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 4cae09bf50f..0b8ef22f0c0 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -309,6 +309,12 @@
method: "Resize()",
field_dependencies: ["resize"]
},
+ ],
+ predicates_to_test: [
+ {
+ predicate: "a.ClipPathDataEquivalent(b)",
+ field_dependencies: ["clip-path"]
+ }
]
},
{
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 2b3222c2948..eac05089f55 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -1052,5 +1052,14 @@
default_value: "false",
field_group: "*",
},
+ // We only create and store ComputedStyle objects for elements in
+ // display:none subtrees if we need it for e.g. getComputedStyle. This flag
+ // is true for such ComputedStyle objects.
+ {
+ name: "IsEnsuredInDisplayNone",
+ field_template: "monotonic_flag",
+ default_value: "false",
+ custom_compare: true,
+ },
],
}
diff --git a/chromium/third_party/blink/renderer/core/style/content_data.cc b/chromium/third_party/blink/renderer/core/style/content_data.cc
index 71af0bcae23..c9b33620f11 100644
--- a/chromium/third_party/blink/renderer/core/style/content_data.cc
+++ b/chromium/third_party/blink/renderer/core/style/content_data.cc
@@ -43,7 +43,7 @@ ContentData* ContentData::Create(const String& text) {
}
ContentData* ContentData::Create(std::unique_ptr<CounterContent> counter) {
- return new CounterContentData(std::move(counter));
+ return MakeGarbageCollected<CounterContentData>(std::move(counter));
}
ContentData* ContentData::Create(QuoteType quote) {
diff --git a/chromium/third_party/blink/renderer/core/style/content_data.h b/chromium/third_party/blink/renderer/core/style/content_data.h
index 9dfcb0e9f53..b4e89247432 100644
--- a/chromium/third_party/blink/renderer/core/style/content_data.h
+++ b/chromium/third_party/blink/renderer/core/style/content_data.h
@@ -147,14 +147,14 @@ class CounterContentData final : public ContentData {
counter_ = std::move(counter);
}
+ CounterContentData(std::unique_ptr<CounterContent> counter)
+ : counter_(std::move(counter)) {}
+
bool IsCounter() const override { return true; }
LayoutObject* CreateLayoutObject(PseudoElement&,
ComputedStyle&) const override;
private:
- CounterContentData(std::unique_ptr<CounterContent> counter)
- : counter_(std::move(counter)) {}
-
ContentData* CloneInternal() const override {
std::unique_ptr<CounterContent> counter_data =
std::make_unique<CounterContent>(*Counter());
diff --git a/chromium/third_party/blink/renderer/core/style/filter_operation.h b/chromium/third_party/blink/renderer/core/style/filter_operation.h
index bd8ae578dbe..568aeb4829e 100644
--- a/chromium/third_party/blink/renderer/core/style/filter_operation.h
+++ b/chromium/third_party/blink/renderer/core/style/filter_operation.h
@@ -175,9 +175,12 @@ class CORE_EXPORT BasicColorMatrixFilterOperation : public FilterOperation {
public:
static BasicColorMatrixFilterOperation* Create(double amount,
OperationType type) {
- return new BasicColorMatrixFilterOperation(amount, type);
+ return MakeGarbageCollected<BasicColorMatrixFilterOperation>(amount, type);
}
+ BasicColorMatrixFilterOperation(double amount, OperationType type)
+ : FilterOperation(type), amount_(amount) {}
+
double Amount() const { return amount_; }
private:
@@ -191,9 +194,6 @@ class CORE_EXPORT BasicColorMatrixFilterOperation : public FilterOperation {
return amount_ == other->amount_;
}
- BasicColorMatrixFilterOperation(double amount, OperationType type)
- : FilterOperation(type), amount_(amount) {}
-
double amount_;
};
@@ -218,9 +218,13 @@ class CORE_EXPORT BasicComponentTransferFilterOperation
public:
static BasicComponentTransferFilterOperation* Create(double amount,
OperationType type) {
- return new BasicComponentTransferFilterOperation(amount, type);
+ return MakeGarbageCollected<BasicComponentTransferFilterOperation>(amount,
+ type);
}
+ BasicComponentTransferFilterOperation(double amount, OperationType type)
+ : FilterOperation(type), amount_(amount) {}
+
double Amount() const { return amount_; }
bool AffectsOpacity() const override { return type_ == OPACITY; }
@@ -236,9 +240,6 @@ class CORE_EXPORT BasicComponentTransferFilterOperation
return amount_ == other->amount_;
}
- BasicComponentTransferFilterOperation(double amount, OperationType type)
- : FilterOperation(type), amount_(amount) {}
-
double amount_;
};
@@ -259,9 +260,12 @@ DEFINE_TYPE_CASTS(BasicComponentTransferFilterOperation,
class CORE_EXPORT BlurFilterOperation : public FilterOperation {
public:
static BlurFilterOperation* Create(const Length& std_deviation) {
- return new BlurFilterOperation(std_deviation);
+ return MakeGarbageCollected<BlurFilterOperation>(std_deviation);
}
+ BlurFilterOperation(const Length& std_deviation)
+ : FilterOperation(BLUR), std_deviation_(std_deviation) {}
+
const Length& StdDeviation() const { return std_deviation_; }
bool AffectsOpacity() const override { return true; }
@@ -279,9 +283,6 @@ class CORE_EXPORT BlurFilterOperation : public FilterOperation {
return std_deviation_ == other->std_deviation_;
}
- BlurFilterOperation(const Length& std_deviation)
- : FilterOperation(BLUR), std_deviation_(std_deviation) {}
-
Length std_deviation_;
};
@@ -321,9 +322,12 @@ DEFINE_FILTER_OPERATION_TYPE_CASTS(DropShadowFilterOperation, DROP_SHADOW);
class CORE_EXPORT BoxReflectFilterOperation : public FilterOperation {
public:
static BoxReflectFilterOperation* Create(const BoxReflection& reflection) {
- return new BoxReflectFilterOperation(reflection);
+ return MakeGarbageCollected<BoxReflectFilterOperation>(reflection);
}
+ BoxReflectFilterOperation(const BoxReflection& reflection)
+ : FilterOperation(BOX_REFLECT), reflection_(reflection) {}
+
const BoxReflection& Reflection() const { return reflection_; }
bool AffectsOpacity() const override { return true; }
@@ -335,9 +339,6 @@ class CORE_EXPORT BoxReflectFilterOperation : public FilterOperation {
double progress) const override;
bool operator==(const FilterOperation&) const override;
- BoxReflectFilterOperation(const BoxReflection& reflection)
- : FilterOperation(BOX_REFLECT), reflection_(reflection) {}
-
BoxReflection reflection_;
};
DEFINE_FILTER_OPERATION_TYPE_CASTS(BoxReflectFilterOperation, BOX_REFLECT);
diff --git a/chromium/third_party/blink/renderer/core/style/filter_operations.cc b/chromium/third_party/blink/renderer/core/style/filter_operations.cc
index 37c30fcd2af..ad0ddfe2409 100644
--- a/chromium/third_party/blink/renderer/core/style/filter_operations.cc
+++ b/chromium/third_party/blink/renderer/core/style/filter_operations.cc
@@ -70,11 +70,12 @@ bool FilterOperations::CanInterpolateWith(const FilterOperations& other) const {
return true;
}
-bool FilterOperations::HasReferenceFilter() const {
+bool FilterOperations::HasBlurOrReferenceFilter() const {
for (const auto& operation : operations_) {
- if (operation->GetType() == FilterOperation::REFERENCE ||
- operation->GetType() == FilterOperation::BOX_REFLECT)
+ FilterOperation::OperationType type = operation->GetType();
+ if (type == FilterOperation::BLUR || type == FilterOperation::REFERENCE) {
return true;
+ }
}
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/style/filter_operations.h b/chromium/third_party/blink/renderer/core/style/filter_operations.h
index 157ab4e6c6c..f71b3597c02 100644
--- a/chromium/third_party/blink/renderer/core/style/filter_operations.h
+++ b/chromium/third_party/blink/renderer/core/style/filter_operations.h
@@ -70,7 +70,7 @@ class CORE_EXPORT FilterOperations {
bool HasFilterThatAffectsOpacity() const;
bool HasFilterThatMovesPixels() const;
- bool HasReferenceFilter() const;
+ bool HasBlurOrReferenceFilter() const;
void AddClient(SVGResourceClient&) const;
void RemoveClient(SVGResourceClient&) const;
diff --git a/chromium/third_party/blink/renderer/core/style/grid_area.h b/chromium/third_party/blink/renderer/core/style/grid_area.h
index 8c9bb4245e2..a7be249009d 100644
--- a/chromium/third_party/blink/renderer/core/style/grid_area.h
+++ b/chromium/third_party/blink/renderer/core/style/grid_area.h
@@ -138,12 +138,13 @@ struct GridSpan {
private:
enum GridSpanType { kUntranslatedDefinite, kTranslatedDefinite, kIndefinite };
- GridSpan(int start_line, int end_line, GridSpanType type) : type_(type) {
+ template <typename T>
+ GridSpan(T start_line, T end_line, GridSpanType type) : type_(type) {
#if DCHECK_IS_ON()
DCHECK_LT(start_line, end_line);
if (type == kTranslatedDefinite) {
- DCHECK_GE(start_line, 0);
- DCHECK_GT(end_line, 0);
+ DCHECK_GE(start_line, static_cast<T>(0));
+ DCHECK_GT(end_line, static_cast<T>(0));
}
#endif
diff --git a/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.cc b/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.cc
index 6e1d5e5ef69..2d95286bbff 100644
--- a/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.cc
@@ -59,27 +59,6 @@ NamedLineCollection::NamedLineCollection(
: grid_container_style.GridAutoRepeatRows().size();
}
-bool NamedLineCollection::IsValidNamedLineOrArea(
- const String& named_line,
- const ComputedStyle& grid_container_style,
- GridPositionSide side) {
- bool is_row_axis = DirectionFromSide(side) == kForColumns;
- const NamedGridLinesMap& grid_line_names =
- is_row_axis ? grid_container_style.NamedGridColumnLines()
- : grid_container_style.NamedGridRowLines();
- const NamedGridLinesMap& auto_repeat_grid_line_names =
- is_row_axis ? grid_container_style.AutoRepeatNamedGridColumnLines()
- : grid_container_style.AutoRepeatNamedGridRowLines();
-
- if (grid_line_names.Contains(named_line) ||
- auto_repeat_grid_line_names.Contains(named_line))
- return true;
-
- String implicit_name = ImplicitNamedGridLineForSide(named_line, side);
- return grid_line_names.Contains(implicit_name) ||
- auto_repeat_grid_line_names.Contains(implicit_name);
-}
-
bool NamedLineCollection::HasNamedLines() {
return named_lines_indexes_ || auto_repeat_named_lines_indexes_;
}
@@ -161,7 +140,6 @@ GridPositionSide GridPositionsResolver::FinalPositionSide(
}
static void InitialAndFinalPositionsFromStyle(
- const ComputedStyle& grid_container_style,
const LayoutBox& grid_item,
GridTrackSizingDirection direction,
GridPosition& initial_position,
@@ -178,22 +156,6 @@ static void InitialAndFinalPositionsFromStyle(
if (initial_position.IsSpan() && final_position.IsSpan())
final_position.SetAutoPosition();
- if (grid_item.IsOutOfFlowPositioned()) {
- // Early detect the case of non existing named grid lines for positioned
- // items.
- if (initial_position.IsNamedGridArea() &&
- !NamedLineCollection::IsValidNamedLineOrArea(
- initial_position.NamedGridLine(), grid_container_style,
- GridPositionsResolver::InitialPositionSide(direction)))
- initial_position.SetAutoPosition();
-
- if (final_position.IsNamedGridArea() &&
- !NamedLineCollection::IsValidNamedLineOrArea(
- final_position.NamedGridLine(), grid_container_style,
- GridPositionsResolver::FinalPositionSide(direction)))
- final_position.SetAutoPosition();
- }
-
// If the grid item has an automatic position and a grid span for a named line
// in a given dimension, instead treat the grid span as one.
if (initial_position.IsAuto() && final_position.IsSpan() &&
@@ -366,12 +328,11 @@ static GridSpan ResolveGridPositionAgainstOppositePosition(
}
size_t GridPositionsResolver::SpanSizeForAutoPlacedItem(
- const ComputedStyle& grid_container_style,
const LayoutBox& grid_item,
GridTrackSizingDirection direction) {
GridPosition initial_position, final_position;
- InitialAndFinalPositionsFromStyle(grid_container_style, grid_item, direction,
- initial_position, final_position);
+ InitialAndFinalPositionsFromStyle(grid_item, direction, initial_position,
+ final_position);
// This method will only be used when both positions need to be resolved
// against the opposite one.
@@ -457,8 +418,6 @@ static int ResolveGridPositionFromStyle(
if (explicit_lines.HasNamedLines())
return explicit_lines.FirstPosition();
- DCHECK(!NamedLineCollection::IsValidNamedLineOrArea(
- named_grid_line, grid_container_style, side));
// If none of the above works specs mandate to assume that all the lines
// in the implicit grid have this name.
return last_line + 1;
@@ -480,8 +439,8 @@ GridSpan GridPositionsResolver::ResolveGridPositionsFromStyle(
GridTrackSizingDirection direction,
size_t auto_repeat_tracks_count) {
GridPosition initial_position, final_position;
- InitialAndFinalPositionsFromStyle(grid_container_style, grid_item, direction,
- initial_position, final_position);
+ InitialAndFinalPositionsFromStyle(grid_item, direction, initial_position,
+ final_position);
GridPositionSide initial_side = InitialPositionSide(direction);
GridPositionSide final_side = FinalPositionSide(direction);
diff --git a/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.h b/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.h
index a7475699c1b..08ab54dab34 100644
--- a/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.h
+++ b/chromium/third_party/blink/renderer/core/style/grid_positions_resolver.h
@@ -32,10 +32,6 @@ class NamedLineCollection {
size_t last_line,
size_t auto_repeat_tracks_count);
- static bool IsValidNamedLineOrArea(const String& named_line,
- const ComputedStyle&,
- GridPositionSide);
-
bool HasNamedLines();
size_t FirstPosition();
@@ -68,8 +64,7 @@ class GridPositionsResolver {
static GridPositionSide InitialPositionSide(GridTrackSizingDirection);
static GridPositionSide FinalPositionSide(GridTrackSizingDirection);
- static size_t SpanSizeForAutoPlacedItem(const ComputedStyle&,
- const LayoutBox&,
+ static size_t SpanSizeForAutoPlacedItem(const LayoutBox&,
GridTrackSizingDirection);
static GridSpan ResolveGridPositionsFromStyle(
const ComputedStyle&,
diff --git a/chromium/third_party/blink/renderer/core/style/shadow_data.cc b/chromium/third_party/blink/renderer/core/style/shadow_data.cc
index acb6c057697..ea0d0c0e6ce 100644
--- a/chromium/third_party/blink/renderer/core/style/shadow_data.cc
+++ b/chromium/third_party/blink/renderer/core/style/shadow_data.cc
@@ -50,9 +50,11 @@ ShadowData ShadowData::NeutralValue() {
}
FloatRectOutsets ShadowData::RectOutsets() const {
- // 3 * skBlurRadiusToSigma(blur()) is how Skia implements the radius of a
- // blur. See also https://crbug.com/624175.
- float blur_and_spread = ceil(3 * SkBlurRadiusToSigma(Blur())) + Spread();
+ // 3 * sigma is how Skia computes the box blur extent.
+ // See also https://crbug.com/624175.
+ // TODO(fmalita): since the blur extent must reflect rasterization bounds,
+ // its value should be queried from Skia (pending API availability).
+ float blur_and_spread = ceil(3 * BlurRadiusToStdDev(Blur())) + Spread();
return FloatRectOutsets(
blur_and_spread - Y() /* top */, blur_and_spread + X() /* right */,
blur_and_spread + Y() /* bottom */, blur_and_spread - X() /* left */);
diff --git a/chromium/third_party/blink/renderer/core/style/style_image.cc b/chromium/third_party/blink/renderer/core/style/style_image.cc
index b98fb8b3379..3ed867b09e5 100644
--- a/chromium/third_party/blink/renderer/core/style/style_image.cc
+++ b/chromium/third_party/blink/renderer/core/style/style_image.cc
@@ -33,11 +33,8 @@ FloatSize StyleImage::ImageSizeForSVGImage(
const LayoutSize& default_object_size) const {
FloatSize unzoomed_default_object_size(default_object_size);
unzoomed_default_object_size.Scale(1 / multiplier);
- // FIXME(schenney): Remove this rounding hack once background image
- // geometry is converted to handle rounding downstream.
- return FloatSize(RoundedIntSize(
- ApplyZoom(svg_image->ConcreteObjectSize(unzoomed_default_object_size),
- multiplier)));
+ return ApplyZoom(svg_image->ConcreteObjectSize(unzoomed_default_object_size),
+ multiplier);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/style_reflection.h b/chromium/third_party/blink/renderer/core/style/style_reflection.h
index cb2de27864e..68dcb1c2790 100644
--- a/chromium/third_party/blink/renderer/core/style/style_reflection.h
+++ b/chromium/third_party/blink/renderer/core/style/style_reflection.h
@@ -45,7 +45,7 @@ class StyleReflection : public RefCounted<StyleReflection> {
bool operator!=(const StyleReflection& o) const { return !(*this == o); }
CSSReflectionDirection Direction() const { return direction_; }
- Length Offset() const { return offset_; }
+ const Length& Offset() const { return offset_; }
const NinePieceImage& Mask() const { return mask_; }
void SetDirection(CSSReflectionDirection dir) { direction_ = dir; }
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style.h b/chromium/third_party/blink/renderer/core/style/svg_computed_style.h
index 3eb4bc6aad2..c0d4aac3051 100644
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style.h
+++ b/chromium/third_party/blink/renderer/core/style/svg_computed_style.h
@@ -232,7 +232,7 @@ class SVGComputedStyle : public RefCounted<SVGComputedStyle> {
stops.Access()->opacity = obj;
}
- void SetStopColor(const Color& obj) {
+ void SetStopColor(const StyleColor& obj) {
if (!(stops->color == obj))
stops.Access()->color = obj;
}
@@ -320,7 +320,7 @@ class SVGComputedStyle : public RefCounted<SVGComputedStyle> {
const UnzoomedLength& StrokeWidth() const { return stroke->width; }
const Length& StrokeDashOffset() const { return stroke->dash_offset; }
float StopOpacity() const { return stops->opacity; }
- const Color& StopColor() const { return stops->color; }
+ const StyleColor& StopColor() const { return stops->color; }
float FloodOpacity() const { return misc->flood_opacity; }
StyleColor FloodColor() const {
return misc->flood_color_is_current_color ? StyleColor::CurrentColor()
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc b/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
index 95d40a050ac..c6d8ee1ee2a 100644
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
+++ b/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
@@ -93,11 +93,11 @@ bool StyleStrokeData::operator==(const StyleStrokeData& other) const {
}
StyleStopData::StyleStopData()
- : opacity(SVGComputedStyle::InitialStopOpacity()),
- color(SVGComputedStyle::InitialStopColor()) {}
+ : color(SVGComputedStyle::InitialStopColor()),
+ opacity(SVGComputedStyle::InitialStopOpacity()) {}
StyleStopData::StyleStopData(const StyleStopData& other)
- : RefCounted<StyleStopData>(), opacity(other.opacity), color(other.color) {}
+ : RefCounted<StyleStopData>(), color(other.color), opacity(other.opacity) {}
bool StyleStopData::operator==(const StyleStopData& other) const {
return color == other.color && opacity == other.opacity;
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h b/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h
index 5920c752054..915d9bc9447 100644
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h
+++ b/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h
@@ -30,6 +30,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/style_color.h"
#include "third_party/blink/renderer/core/style/style_path.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
@@ -249,8 +250,8 @@ class StyleStopData : public RefCounted<StyleStopData> {
return !(*this == other);
}
+ StyleColor color;
float opacity;
- Color color;
private:
StyleStopData();
diff --git a/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index 4325e7cc096..7f08fdf690c 100644
--- a/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -26,11 +26,12 @@
#include "third_party/blink/renderer/core/svg/animation/svg_smil_element.h"
#include <algorithm>
+
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_event_listener.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/svg/animation/smil_time_container.h"
@@ -75,47 +76,52 @@ inline RepeatEvent* ToRepeatEvent(Event* event) {
// This is used for duration type time values that can't be negative.
static const double kInvalidCachedTime = -1.;
-class ConditionEventListener final : public EventListener {
+class ConditionEventListener final : public NativeEventListener {
public:
static ConditionEventListener* Create(SVGSMILElement* animation,
SVGSMILElement::Condition* condition) {
- return new ConditionEventListener(animation, condition);
+ return MakeGarbageCollected<ConditionEventListener>(animation, condition);
}
- static const ConditionEventListener* Cast(const EventListener* listener) {
- return listener->GetType() == kConditionEventListenerType
- ? static_cast<const ConditionEventListener*>(listener)
- : nullptr;
- }
+ ConditionEventListener(SVGSMILElement* animation,
+ SVGSMILElement::Condition* condition)
+ : animation_(animation), condition_(condition) {}
- bool operator==(const EventListener& other) const override;
+ bool Matches(const EventListener& other) const override;
void DisconnectAnimation() { animation_ = nullptr; }
+ void Invoke(ExecutionContext*, Event*) override;
+
void Trace(blink::Visitor* visitor) override {
visitor->Trace(animation_);
visitor->Trace(condition_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
}
- private:
- ConditionEventListener(SVGSMILElement* animation,
- SVGSMILElement::Condition* condition)
- : EventListener(kConditionEventListenerType),
- animation_(animation),
- condition_(condition) {}
-
- void Invoke(ExecutionContext*, Event*) override;
+ bool IsConditionEventListener() const override { return true; }
+ private:
Member<SVGSMILElement> animation_;
Member<SVGSMILElement::Condition> condition_;
};
-bool ConditionEventListener::operator==(const EventListener& listener) const {
+template <>
+struct DowncastTraits<ConditionEventListener> {
+ static bool AllowFrom(const EventListener& event_listener) {
+ const NativeEventListener* native_event_listener =
+ DynamicTo<NativeEventListener>(event_listener);
+ return native_event_listener &&
+ native_event_listener->IsConditionEventListener();
+ }
+};
+
+bool ConditionEventListener::Matches(const EventListener& listener) const {
if (const ConditionEventListener* condition_event_listener =
- ConditionEventListener::Cast(&listener))
+ DynamicTo<ConditionEventListener>(listener)) {
return animation_ == condition_event_listener->animation_ &&
condition_ == condition_event_listener->condition_;
+ }
return false;
}
@@ -710,9 +716,15 @@ void SVGSMILElement::AddInstanceTime(BeginOrEnd begin_or_end,
SMILTime elapsed = this->Elapsed();
if (elapsed.IsUnresolved())
return;
+ SMILTimeWithOrigin time_with_origin(time, origin);
+ // Ignore new instance times for 'end' if the element is not active
+ // and the origin is script.
+ if (begin_or_end == kEnd && GetActiveState() == kInactive &&
+ time_with_origin.OriginIsScript())
+ return;
Vector<SMILTimeWithOrigin>& list =
begin_or_end == kBegin ? begin_times_ : end_times_;
- list.push_back(SMILTimeWithOrigin(time, origin));
+ list.push_back(time_with_origin);
SortTimeList(list);
if (begin_or_end == kBegin)
BeginListChanged(elapsed);
@@ -720,54 +732,34 @@ void SVGSMILElement::AddInstanceTime(BeginOrEnd begin_or_end,
EndListChanged(elapsed);
}
-inline bool CompareTimes(const SMILTimeWithOrigin& left,
- const SMILTimeWithOrigin& right) {
- return left.Time() < right.Time();
-}
-
SMILTime SVGSMILElement::FindInstanceTime(BeginOrEnd begin_or_end,
SMILTime minimum_time,
bool equals_minimum_ok) const {
const Vector<SMILTimeWithOrigin>& list =
begin_or_end == kBegin ? begin_times_ : end_times_;
- int size_of_list = list.size();
- if (!size_of_list)
+ if (list.IsEmpty())
return begin_or_end == kBegin ? SMILTime::Unresolved()
: SMILTime::Indefinite();
- const SMILTimeWithOrigin dummy_time_with_origin(
- minimum_time, SMILTimeWithOrigin::kParserOrigin);
- const SMILTimeWithOrigin* result = std::lower_bound(
- list.begin(), list.end(), dummy_time_with_origin, CompareTimes);
- int index_of_result = static_cast<int>(result - list.begin());
- if (index_of_result == size_of_list)
+ // If an equal value is not accepted, return the next bigger item in the list,
+ // if any.
+ auto predicate = [equals_minimum_ok](const SMILTimeWithOrigin& instance_time,
+ const SMILTime& time) {
+ return equals_minimum_ok ? instance_time.Time() < time
+ : instance_time.Time() <= time;
+ };
+ auto* item =
+ std::lower_bound(list.begin(), list.end(), minimum_time, predicate);
+ if (item == list.end())
return SMILTime::Unresolved();
- const SMILTime& current_time = list[index_of_result].Time();
// The special value "indefinite" does not yield an instance time in the begin
// list.
- if (current_time.IsIndefinite() && begin_or_end == kBegin)
+ if (item->Time().IsIndefinite() && begin_or_end == kBegin)
return SMILTime::Unresolved();
- if (current_time > minimum_time)
- return current_time;
-
- DCHECK(current_time == minimum_time);
- if (equals_minimum_ok)
- return current_time;
-
- // If the equals is not accepted, return the next bigger item in the list.
- SMILTime next_time = current_time;
- while (index_of_result < size_of_list - 1) {
- next_time = list[index_of_result + 1].Time();
- if (next_time > minimum_time)
- return next_time;
- ++index_of_result;
- }
-
- return begin_or_end == kBegin ? SMILTime::Unresolved()
- : SMILTime::Indefinite();
+ return item->Time();
}
SMILTime SVGSMILElement::RepeatingDuration() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index 59a27fd3ddb..2eecda79e6f 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -78,6 +78,10 @@ class SVGImage::SVGImageLocalFrameClient : public EmptyLocalFrameClient {
void ClearImage() { image_ = nullptr; }
private:
+ std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override {
+ return Platform::Current()->CreateDefaultURLLoaderFactory();
+ }
+
void DispatchDidHandleOnloadEvents() override {
// The SVGImage was destructed before SVG load completion.
if (!image_)
@@ -436,8 +440,8 @@ bool SVGImage::ApplyShaderInternal(PaintFlags& flags,
IntRect bounds(IntPoint(), size);
flags.setShader(PaintShader::MakePaintRecord(
- PaintRecordForCurrentFrame(bounds, url), bounds,
- SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &local_matrix));
+ PaintRecordForCurrentFrame(url), bounds, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode, &local_matrix));
// Animation is normally refreshed in draw() impls, which we don't reach when
// painting via shaders.
@@ -483,10 +487,7 @@ void SVGImage::Draw(
should_respect_image_orientation, clamp_mode, NullURL());
}
-sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(
- const IntRect& bounds,
- const KURL& url,
- cc::PaintCanvas* canvas) {
+sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(const KURL& url) {
DCHECK(page_);
LocalFrameView* view = ToLocalFrame(page_->MainFrame())->View();
view->Resize(ContainerSize());
@@ -503,17 +504,15 @@ sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(
// avoid setting timers from the latter.
FlushPendingTimelineRewind();
- PaintRecordBuilder builder(nullptr, nullptr, paint_controller_.get());
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ view->UpdateAllLifecyclePhases(
+ DocumentLifecycle::LifecycleUpdateReason::kOther);
+ return view->GetPaintRecord();
+ }
view->UpdateAllLifecyclePhasesExceptPaint();
- view->PaintWithLifecycleUpdate(builder.Context(), kGlobalPaintNormalPhase,
- CullRect(bounds));
- DCHECK(!view->NeedsLayout());
-
- if (canvas) {
- builder.EndRecording(*canvas);
- return nullptr;
- }
+ PaintRecordBuilder builder(nullptr, nullptr, paint_controller_.get());
+ view->PaintOutsideOfLifecycle(builder.Context(), kGlobalPaintNormalPhase);
return builder.EndRecording();
}
@@ -545,7 +544,7 @@ void SVGImage::DrawInternal(cc::PaintCanvas* canvas,
canvas->save();
canvas->clipRect(EnclosingIntRect(dst_rect));
canvas->concat(AffineTransformToSkMatrix(transform));
- PaintRecordForCurrentFrame(EnclosingIntRect(src_rect), url, canvas);
+ canvas->drawPicture(PaintRecordForCurrentFrame(url));
canvas->restore();
}
@@ -646,9 +645,9 @@ void SVGImage::ServiceAnimations(
LocalFrameView* frame_view = ToLocalFrame(page_->MainFrame())->View();
frame_view->UpdateAllLifecyclePhasesExceptPaint();
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
- // For SPv2/BGPT we run UpdateAnimations after the paint phase, but per the
+ // For CAP/BGPT we run UpdateAnimations after the paint phase, but per the
// above comment, we don't want to run lifecycle through to paint for SVG
// images. Since we know SVG images never have composited animations we can
// update animations directly without worrying about including
@@ -658,14 +657,6 @@ void SVGImage::ServiceAnimations(
DocumentAnimations::UpdateAnimations(
frame_view->GetLayoutView()->GetDocument(),
DocumentLifecycle::kLayoutClean, composited_element_ids);
-
- // Notify observers for image change. In SPv1 this is done through window
- // rect invalidation during paint invalidation of the SVGImage's frame view.
- auto* layer = frame_view->GetLayoutView()->Layer();
- if (layer->NeedsRepaint()) {
- if (auto* observer = GetImageObserver())
- observer->Changed(this);
- }
}
}
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h
index ad74de97b1a..f9caf52a18c 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h
@@ -181,12 +181,8 @@ class CORE_EXPORT SVGImage final : public Image {
const KURL&,
const IntSize& container_size);
- // Paints the current frame. If a PaintCanvas is passed, paints into that
- // canvas and returns nullptr.
- // Otherwise returns a pointer to the new PaintRecord.
- sk_sp<PaintRecord> PaintRecordForCurrentFrame(const IntRect& bounds,
- const KURL&,
- cc::PaintCanvas* = nullptr);
+ // Paints the current frame. Returns new PaintRecord.
+ sk_sp<PaintRecord> PaintRecordForCurrentFrame(const KURL&);
void DrawInternal(cc::PaintCanvas*,
const cc::PaintFlags&,
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h
index a6177c2c389..5953da2d8b6 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h
@@ -74,8 +74,7 @@ class CORE_EXPORT SVGImageChromeClient final : public EmptyChromeClient {
FRIEND_TEST_ALL_PREFIXES(SVGImageTest, TimelineSuspendAndResume);
FRIEND_TEST_ALL_PREFIXES(SVGImageTest, ResetAnimation);
- FRIEND_TEST_ALL_PREFIXES(SVGImagePageVisibilityTest,
- PageVisibilityHiddenToVisible);
+ FRIEND_TEST_ALL_PREFIXES(SVGImageSimTest, PageVisibilityHiddenToVisible);
};
DEFINE_TYPE_CASTS(SVGImageChromeClient,
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
index c1d26a3b287..77fd083e0cd 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
@@ -197,11 +197,12 @@ TEST_F(SVGImageTest, SetSizeOnVisualViewport) {
GetImage().GetPageForTesting()->GetVisualViewport().Size());
}
-class SVGImagePageVisibilityTest : public SimTest {};
+class SVGImageSimTest : public SimTest {};
-TEST_F(SVGImagePageVisibilityTest, PageVisibilityHiddenToVisible) {
+TEST_F(SVGImageSimTest, PageVisibilityHiddenToVisible) {
SimRequest main_resource("https://example.com/", "text/html");
- SimRequest image_resource("https://example.com/image.svg", "image/svg+xml");
+ SimSubresourceRequest image_resource("https://example.com/image.svg",
+ "image/svg+xml");
LoadURL("https://example.com/");
main_resource.Complete("<img src='image.svg' width='100' id='image'>");
image_resource.Complete(kAnimatedDocument);
@@ -234,7 +235,7 @@ TEST_F(SVGImagePageVisibilityTest, PageVisibilityHiddenToVisible) {
// Set page visibility to 'hidden', and then wait for the animation timer to
// fire. This should suspend the image animation. (Suspend the image's
// animation timeline.)
- WebView().SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
+ WebView().SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
test::RunDelayedTasks(TimeDelta::FromMilliseconds(1) +
timer->NextFireInterval());
@@ -242,7 +243,7 @@ TEST_F(SVGImagePageVisibilityTest, PageVisibilityHiddenToVisible) {
// Set page visibility to 'visible' - this should schedule a new animation
// frame and resume the image animation.
- WebView().SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
+ WebView().SetIsHidden(/*is_hidden=*/false, /*initial_state=*/false);
test::RunDelayedTasks(TimeDelta::FromMilliseconds(1) +
timer->NextFireInterval());
Compositor().BeginFrame();
@@ -250,4 +251,26 @@ TEST_F(SVGImagePageVisibilityTest, PageVisibilityHiddenToVisible) {
EXPECT_FALSE(svg_image_chrome_client.IsSuspended());
}
+TEST_F(SVGImageSimTest, TwoImagesSameSVGImageDifferentSize) {
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimSubresourceRequest image_resource("https://example.com/image.svg",
+ "image/svg+xml");
+ LoadURL("https://example.com/");
+ main_resource.Complete(R"HTML(
+ <img src="image.svg" style="width: 100px">
+ <img src="image.svg" style="width: 200px">
+ )HTML");
+ image_resource.Complete(R"SVG(
+ <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+ <rect fill="green" width="100" height="100"/>
+ </svg>
+ )SVG");
+
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+ // The previous frame should result in a stable state and should not schedule
+ // new visual updates.
+ EXPECT_FALSE(Compositor().NeedsBeginFrame());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_a_element.h b/chromium/third_party/blink/renderer/core/svg/svg_a_element.h
index d6d7e1592cb..b213ac5e749 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_a_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_a_element.h
@@ -37,11 +37,11 @@ class CORE_EXPORT SVGAElement final : public SVGGraphicsElement,
DECLARE_NODE_FACTORY(SVGAElement);
SVGAnimatedString* svgTarget() { return svg_target_.Get(); }
+ explicit SVGAElement(Document&);
+
void Trace(blink::Visitor*) override;
private:
- explicit SVGAElement(Document&);
-
String title() const override;
void SvgAttributeChanged(const QualifiedName&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.h b/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
index 009eb644c04..39f64675874 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
@@ -30,14 +30,13 @@ class SVGAnimateMotionElement final : public SVGAnimationElement {
DEFINE_WRAPPERTYPEINFO();
public:
+ explicit SVGAnimateMotionElement(Document&);
~SVGAnimateMotionElement() override;
DECLARE_NODE_FACTORY(SVGAnimateMotionElement);
void UpdateAnimationPath();
private:
- explicit SVGAnimateMotionElement(Document&);
-
bool HasValidTarget() override;
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h b/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
index 94e0a47cfce..3704f7c933f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
@@ -34,9 +34,9 @@ class SVGAnimateTransformElement final : public SVGAnimateElement {
public:
DECLARE_NODE_FACTORY(SVGAnimateTransformElement);
- private:
explicit SVGAnimateTransformElement(Document&);
+ private:
bool HasValidTarget() override;
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h b/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h
index 4c0c6fd8f8a..18fe18a339a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h
@@ -33,6 +33,8 @@ class SVGCircleElement final : public SVGGeometryElement {
public:
DECLARE_NODE_FACTORY(SVGCircleElement);
+ explicit SVGCircleElement(Document&);
+
Path AsPath() const override;
SVGAnimatedLength* cx() const { return cx_.Get(); }
@@ -42,8 +44,6 @@ class SVGCircleElement final : public SVGGeometryElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGCircleElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h b/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h
index 301c99d17f6..81b4dbaadb6 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h
@@ -35,6 +35,9 @@ class SVGClipPathElement final : public SVGGraphicsElement {
public:
DECLARE_NODE_FACTORY(SVGClipPathElement);
+
+ explicit SVGClipPathElement(Document&);
+
SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>* clipPathUnits() {
return clip_path_units_.Get();
}
@@ -44,8 +47,6 @@ class SVGClipPathElement final : public SVGGraphicsElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGClipPathElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
void ChildrenChanged(const ChildrenChange&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_defs_element.h b/chromium/third_party/blink/renderer/core/svg/svg_defs_element.h
index 2712bc61aed..8121ce1b7e2 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_defs_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_defs_element.h
@@ -31,11 +31,11 @@ class SVGDefsElement final : public SVGGraphicsElement {
public:
DECLARE_NODE_FACTORY(SVGDefsElement);
+ explicit SVGDefsElement(Document&);
+
bool SupportsFocus() const override { return false; }
private:
- explicit SVGDefsElement(Document&);
-
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_desc_element.h b/chromium/third_party/blink/renderer/core/svg/svg_desc_element.h
index 5baff7cacd1..ab3670fb9b0 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_desc_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_desc_element.h
@@ -31,9 +31,9 @@ class SVGDescElement final : public SVGElement {
public:
DECLARE_NODE_FACTORY(SVGDescElement);
- private:
explicit SVGDescElement(Document&);
+ private:
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_discard_element.h b/chromium/third_party/blink/renderer/core/svg/svg_discard_element.h
index 66eba0f8b1a..972f5f0e21d 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_discard_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_discard_element.h
@@ -41,11 +41,11 @@ class SVGDiscardElement final : public SVGSMILElement {
public:
DECLARE_NODE_FACTORY(SVGDiscardElement);
+ explicit SVGDiscardElement(Document&);
+
bool IsSVGDiscardElement() const override { return true; }
private:
- explicit SVGDiscardElement(Document&);
-
void ResetAnimatedType() override {}
void ClearAnimatedType() override {}
void ApplyResultsToTarget() override {}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_element.cc
index c4df89477b8..2da79ce057b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_element.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/svg/svg_element.h"
#include "base/auto_reset.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/script_event_listener.h"
#include "third_party/blink/renderer/core/animation/document_animations.h"
#include "third_party/blink/renderer/core/animation/effect_stack.h"
@@ -315,16 +316,23 @@ static inline bool TransformUsesBoxSize(const ComputedStyle& style) {
return false;
}
-static FloatRect ComputeTransformReferenceBox(const SVGElement& element) {
- const LayoutObject& layout_object = *element.GetLayoutObject();
+FloatRect ComputeSVGTransformReferenceBox(const LayoutObject& layout_object) {
const ComputedStyle& style = layout_object.StyleRef();
- if (style.TransformBox() == ETransformBox::kFillBox)
- return layout_object.ObjectBoundingBox();
- DCHECK_EQ(style.TransformBox(), ETransformBox::kViewBox);
- SVGLengthContext length_context(&element);
- FloatSize viewport_size;
- length_context.DetermineViewport(viewport_size);
- return FloatRect(FloatPoint(), viewport_size);
+ FloatRect reference_box;
+ if (style.TransformBox() == ETransformBox::kFillBox) {
+ reference_box = layout_object.ObjectBoundingBox();
+ } else {
+ DCHECK_EQ(style.TransformBox(), ETransformBox::kViewBox);
+ SVGLengthContext length_context(
+ ToSVGElementOrNull(layout_object.GetNode()));
+ FloatSize viewport_size;
+ length_context.DetermineViewport(viewport_size);
+ reference_box.SetSize(viewport_size);
+ }
+ const float zoom = style.EffectiveZoom();
+ if (zoom != 1)
+ reference_box.Scale(zoom);
+ return reference_box;
}
AffineTransform SVGElement::CalculateTransform(
@@ -336,7 +344,6 @@ AffineTransform SVGElement::CalculateTransform(
// set).
AffineTransform matrix;
if (style && style->HasTransform()) {
- FloatRect reference_box = ComputeTransformReferenceBox(*this);
if (TransformUsesBoxSize(*style))
UseCounter::Count(GetDocument(), WebFeature::kTransformUsesBoxSizeOnSVG);
@@ -344,21 +351,21 @@ AffineTransform SVGElement::CalculateTransform(
// SVG (which applies the zoom factor globally, at the root level) we
//
// * pre-scale the reference box (to bring it into the same space as the
- // other CSS values)
+ // other CSS values) (Handled by ComputeSVGTransformReferenceBox)
// * invert the zoom factor (to effectively compute the CSS transform
// under a 1.0 zoom)
//
// Note: objectBoundingBox is an emptyRect for elements like pattern or
// clipPath. See
// https://svgwg.org/svg2-draft/coords.html#ObjectBoundingBoxUnits
- float zoom = style->EffectiveZoom();
TransformationMatrix transform;
- if (zoom != 1)
- reference_box.Scale(zoom);
+ FloatRect reference_box =
+ ComputeSVGTransformReferenceBox(*GetLayoutObject());
style->ApplyTransform(
transform, reference_box, ComputedStyle::kIncludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
+ const float zoom = style->EffectiveZoom();
if (zoom != 1)
transform.Zoom(1 / zoom);
// Flatten any 3D transform.
@@ -496,7 +503,7 @@ CSSPropertyID SVGElement::CssPropertyIdForSVGAttributeName(
&kWordSpacingAttr,
&kWritingModeAttr,
};
- for (size_t i = 0; i < arraysize(attr_names); i++) {
+ for (size_t i = 0; i < base::size(attr_names); i++) {
CSSPropertyID property_id = cssPropertyID(attr_names[i]->LocalName());
DCHECK_GT(property_id, 0);
property_name_to_id_map->Set(attr_names[i]->LocalName().Impl(),
@@ -780,7 +787,7 @@ AnimatedPropertyType SVGElement::AnimatedPropertyTypeForCSSAttribute(
{kVisibilityAttr, kAnimatedString},
{kWordSpacingAttr, kAnimatedLength},
};
- for (size_t i = 0; i < arraysize(attr_to_types); i++)
+ for (size_t i = 0; i < base::size(attr_to_types); i++)
css_property_map.Set(attr_to_types[i].attr, attr_to_types[i].prop_type);
}
return css_property_map.at(attribute_name);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_element.h b/chromium/third_party/blink/renderer/core/svg/svg_element.h
index 4a0a16c8981..433793dc599 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_element.h
@@ -330,6 +330,8 @@ struct SVGAttributeHashTranslator {
}
};
+FloatRect ComputeSVGTransformReferenceBox(const LayoutObject&);
+
DEFINE_ELEMENT_TYPE_CASTS(SVGElement, IsSVGElement());
template <typename T>
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h b/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h
index ed3de18760e..7de52bb27d8 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h
@@ -33,6 +33,8 @@ class SVGEllipseElement final : public SVGGeometryElement {
public:
DECLARE_NODE_FACTORY(SVGEllipseElement);
+ explicit SVGEllipseElement(Document&);
+
Path AsPath() const override;
SVGAnimatedLength* cx() const { return cx_.Get(); }
@@ -43,8 +45,6 @@ class SVGEllipseElement final : public SVGGeometryElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGEllipseElement(Document&);
-
void CollectStyleForPresentationAttribute(
const QualifiedName&,
const AtomicString&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_enumeration.h b/chromium/third_party/blink/renderer/core/svg/svg_enumeration.h
index 9e70421b56e..069c8b704a7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_enumeration.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_enumeration.h
@@ -106,9 +106,11 @@ template <typename Enum>
class SVGEnumeration : public SVGEnumerationBase {
public:
static SVGEnumeration<Enum>* Create(Enum new_value) {
- return new SVGEnumeration<Enum>(new_value);
+ return MakeGarbageCollected<SVGEnumeration<Enum>>(new_value);
}
+ explicit SVGEnumeration(Enum new_value)
+ : SVGEnumerationBase(new_value, GetEnumerationMap<Enum>()) {}
~SVGEnumeration() override = default;
SVGEnumerationBase* Clone() const override { return Create(EnumValue()); }
@@ -122,10 +124,6 @@ class SVGEnumeration : public SVGEnumerationBase {
value_ = value;
NotifyChange();
}
-
- protected:
- explicit SVGEnumeration(Enum new_value)
- : SVGEnumerationBase(new_value, GetEnumerationMap<Enum>()) {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
index cc6cf833568..66927de4954 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
@@ -51,6 +51,8 @@ class SVGFEBlendElement final : public SVGFilterPrimitiveStandardAttributes {
kModeLuminosity = 16,
};
+ explicit SVGFEBlendElement(Document&);
+
DECLARE_NODE_FACTORY(SVGFEBlendElement);
SVGAnimatedString* in1() { return in1_.Get(); }
SVGAnimatedString* in2() { return in2_.Get(); }
@@ -59,8 +61,6 @@ class SVGFEBlendElement final : public SVGFilterPrimitiveStandardAttributes {
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEBlendElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
void SvgAttributeChanged(const QualifiedName&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
index 6342432ac8b..f886203e927 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
@@ -38,6 +38,8 @@ class SVGFEColorMatrixElement final
public:
DECLARE_NODE_FACTORY(SVGFEColorMatrixElement);
+ explicit SVGFEColorMatrixElement(Document&);
+
SVGAnimatedNumberList* values() { return values_.Get(); }
SVGAnimatedString* in1() { return in1_.Get(); }
SVGAnimatedEnumeration<ColorMatrixType>* type() { return type_.Get(); }
@@ -45,8 +47,6 @@ class SVGFEColorMatrixElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEColorMatrixElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
index 55ad3f67b5a..bc617e6a306 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
@@ -32,13 +32,14 @@ class SVGFEComponentTransferElement final
public:
DECLARE_NODE_FACTORY(SVGFEComponentTransferElement);
+
+ explicit SVGFEComponentTransferElement(Document&);
+
SVGAnimatedString* in1() { return in1_.Get(); }
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEComponentTransferElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
index e3f74eed510..7f4b6d1060c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
@@ -38,6 +38,8 @@ class SVGFECompositeElement final
public:
DECLARE_NODE_FACTORY(SVGFECompositeElement);
+ explicit SVGFECompositeElement(Document&);
+
SVGAnimatedNumber* k1() { return k1_.Get(); }
SVGAnimatedNumber* k2() { return k2_.Get(); }
SVGAnimatedNumber* k3() { return k3_.Get(); }
@@ -51,8 +53,6 @@ class SVGFECompositeElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFECompositeElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
index 2b633845a25..20d5dd83090 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
@@ -42,6 +42,8 @@ class SVGFEConvolveMatrixElement final
public:
DECLARE_NODE_FACTORY(SVGFEConvolveMatrixElement);
+ explicit SVGFEConvolveMatrixElement(Document&);
+
SVGAnimatedBoolean* preserveAlpha() { return preserve_alpha_.Get(); }
SVGAnimatedNumber* divisor() { return divisor_.Get(); }
SVGAnimatedNumber* bias() { return bias_.Get(); }
@@ -62,8 +64,6 @@ class SVGFEConvolveMatrixElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEConvolveMatrixElement(Document&);
-
IntSize MatrixOrder() const;
IntPoint TargetPoint() const;
float ComputeDivisor() const;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
index 70c811406be..a7f9b427c47 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
@@ -35,6 +35,9 @@ class SVGFEDiffuseLightingElement final
public:
DECLARE_NODE_FACTORY(SVGFEDiffuseLightingElement);
+
+ explicit SVGFEDiffuseLightingElement(Document&);
+
void LightElementAttributeChanged(const SVGFELightElement*,
const QualifiedName&);
@@ -51,8 +54,6 @@ class SVGFEDiffuseLightingElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEDiffuseLightingElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
index 29175d2d618..7cc51dabf87 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
@@ -37,6 +37,8 @@ class SVGFEDisplacementMapElement final
public:
DECLARE_NODE_FACTORY(SVGFEDisplacementMapElement);
+ explicit SVGFEDisplacementMapElement(Document&);
+
static ChannelSelectorType StringToChannel(const String&);
SVGAnimatedNumber* scale() { return scale_.Get(); }
@@ -52,8 +54,6 @@ class SVGFEDisplacementMapElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEDisplacementMapElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
void SvgAttributeChanged(const QualifiedName&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h
index fe32c6aee0d..981be2c4047 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h
@@ -30,9 +30,9 @@ class SVGFEDistantLightElement final : public SVGFELightElement {
public:
DECLARE_NODE_FACTORY(SVGFEDistantLightElement);
- private:
explicit SVGFEDistantLightElement(Document&);
+ private:
scoped_refptr<LightSource> GetLightSource(Filter*) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
index d3835af2911..624ab18820a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
@@ -34,6 +34,8 @@ class SVGFEDropShadowElement final
public:
DECLARE_NODE_FACTORY(SVGFEDropShadowElement);
+ explicit SVGFEDropShadowElement(Document&);
+
void setStdDeviation(float std_deviation_x, float std_deviation_y);
SVGAnimatedNumber* dx() { return dx_.Get(); }
@@ -45,8 +47,6 @@ class SVGFEDropShadowElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEDropShadowElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.h
index 9949bd8caff..45af42fc8ef 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.h
@@ -31,9 +31,9 @@ class SVGFEFloodElement final : public SVGFilterPrimitiveStandardAttributes {
public:
DECLARE_NODE_FACTORY(SVGFEFloodElement);
- private:
explicit SVGFEFloodElement(Document&);
+ private:
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h
index bab394c2d27..9cc64d3274c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h
@@ -31,7 +31,6 @@ class SVGFEFuncAElement final : public SVGComponentTransferFunctionElement {
public:
DECLARE_NODE_FACTORY(SVGFEFuncAElement);
- private:
explicit SVGFEFuncAElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h
index 41df5fb00ac..689969547aa 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h
@@ -31,7 +31,6 @@ class SVGFEFuncBElement final : public SVGComponentTransferFunctionElement {
public:
DECLARE_NODE_FACTORY(SVGFEFuncBElement);
- private:
explicit SVGFEFuncBElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h
index 077a92feafd..61884a43334 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h
@@ -31,7 +31,6 @@ class SVGFEFuncGElement final : public SVGComponentTransferFunctionElement {
public:
DECLARE_NODE_FACTORY(SVGFEFuncGElement);
- private:
explicit SVGFEFuncGElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h
index c17bec1bbd2..cc5550c5a35 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h
@@ -31,7 +31,6 @@ class SVGFEFuncRElement final : public SVGComponentTransferFunctionElement {
public:
DECLARE_NODE_FACTORY(SVGFEFuncRElement);
- private:
explicit SVGFEFuncRElement(Document&);
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
index cca688648d0..73a68d1455c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
@@ -34,6 +34,8 @@ class SVGFEGaussianBlurElement final
public:
DECLARE_NODE_FACTORY(SVGFEGaussianBlurElement);
+ explicit SVGFEGaussianBlurElement(Document&);
+
void setStdDeviation(float std_deviation_x, float std_deviation_y);
SVGAnimatedNumber* stdDeviationX() { return std_deviation_->FirstNumber(); }
@@ -43,8 +45,6 @@ class SVGFEGaussianBlurElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEGaussianBlurElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
index 92106996649..6ee1a319c00 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
@@ -163,8 +163,7 @@ FilterEffect* SVGFEImageElement::Build(SVGFilterBuilder*, Filter* filter) {
}
bool SVGFEImageElement::TaintsOrigin(bool inputs_taint_origin) const {
- const SecurityOrigin* security_origin = GetDocument().GetSecurityOrigin();
- if (cached_image_ && cached_image_->IsAccessAllowed(security_origin))
+ if (cached_image_ && cached_image_->IsAccessAllowed())
return inputs_taint_origin;
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h
index 2c9f4eb08bc..8288902e9b2 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h
@@ -42,6 +42,7 @@ class SVGFEImageElement final : public SVGFilterPrimitiveStandardAttributes,
bool CurrentFrameHasSingleSecurityOrigin() const;
+ explicit SVGFEImageElement(Document&);
~SVGFEImageElement() override;
SVGAnimatedPreserveAspectRatio* preserveAspectRatio() {
return preserve_aspect_ratio_.Get();
@@ -52,8 +53,6 @@ class SVGFEImageElement final : public SVGFilterPrimitiveStandardAttributes,
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEImageElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
void ImageNotifyFinished(ImageResourceContent*) override;
String DebugName() const override { return "SVGFEImageElement"; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_element.h
index 29cbf80b856..69a9a2ffe8d 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_element.h
@@ -31,9 +31,9 @@ class SVGFEMergeElement final : public SVGFilterPrimitiveStandardAttributes {
public:
DECLARE_NODE_FACTORY(SVGFEMergeElement);
- private:
explicit SVGFEMergeElement(Document&);
+ private:
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin(bool inputs_taint_origin) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
index 6e6946e3a89..e1bd7717898 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
@@ -32,13 +32,14 @@ class SVGFEMergeNodeElement final : public SVGElement {
public:
DECLARE_NODE_FACTORY(SVGFEMergeNodeElement);
+
+ explicit SVGFEMergeNodeElement(Document&);
+
SVGAnimatedString* in1() { return in1_.Get(); }
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEMergeNodeElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
index 53d796f640b..17c83165feb 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
@@ -37,6 +37,8 @@ class SVGFEMorphologyElement final
public:
DECLARE_NODE_FACTORY(SVGFEMorphologyElement);
+ explicit SVGFEMorphologyElement(Document&);
+
SVGAnimatedNumber* radiusX() { return radius_->FirstNumber(); }
SVGAnimatedNumber* radiusY() { return radius_->SecondNumber(); }
SVGAnimatedString* in1() { return in1_.Get(); }
@@ -47,8 +49,6 @@ class SVGFEMorphologyElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEMorphologyElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
index 681d6efc8df..0263ec9a8cd 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
@@ -33,6 +33,8 @@ class SVGFEOffsetElement final : public SVGFilterPrimitiveStandardAttributes {
public:
DECLARE_NODE_FACTORY(SVGFEOffsetElement);
+ explicit SVGFEOffsetElement(Document&);
+
SVGAnimatedNumber* dx() { return dx_.Get(); }
SVGAnimatedNumber* dy() { return dy_.Get(); }
SVGAnimatedString* in1() { return in1_.Get(); }
@@ -40,8 +42,6 @@ class SVGFEOffsetElement final : public SVGFilterPrimitiveStandardAttributes {
void Trace(blink::Visitor*) override;
private:
- explicit SVGFEOffsetElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h
index 70f95be3668..710c32b9e92 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h
@@ -30,9 +30,9 @@ class SVGFEPointLightElement final : public SVGFELightElement {
public:
DECLARE_NODE_FACTORY(SVGFEPointLightElement);
- private:
explicit SVGFEPointLightElement(Document&);
+ private:
scoped_refptr<LightSource> GetLightSource(Filter*) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
index 3b43fb37d53..8ac45e6adce 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
@@ -36,6 +36,9 @@ class SVGFESpecularLightingElement final
public:
DECLARE_NODE_FACTORY(SVGFESpecularLightingElement);
+
+ explicit SVGFESpecularLightingElement(Document&);
+
void LightElementAttributeChanged(const SVGFELightElement*,
const QualifiedName&);
@@ -53,8 +56,6 @@ class SVGFESpecularLightingElement final
void Trace(blink::Visitor*) override;
private:
- explicit SVGFESpecularLightingElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h
index c26083481af..6fd49e7e829 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h
@@ -30,9 +30,9 @@ class SVGFESpotLightElement final : public SVGFELightElement {
public:
DECLARE_NODE_FACTORY(SVGFESpotLightElement);
- private:
explicit SVGFESpotLightElement(Document&);
+ private:
scoped_refptr<LightSource> GetLightSource(Filter*) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
index bb22e4fea6e..b2c48456133 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
@@ -31,13 +31,14 @@ class SVGFETileElement final : public SVGFilterPrimitiveStandardAttributes {
public:
DECLARE_NODE_FACTORY(SVGFETileElement);
+
+ explicit SVGFETileElement(Document&);
+
SVGAnimatedString* in1() { return in1_.Get(); }
void Trace(blink::Visitor*) override;
private:
- explicit SVGFETileElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
index 3540909aac6..b4b98004f57 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
@@ -47,6 +47,8 @@ class SVGFETurbulenceElement final
public:
DECLARE_NODE_FACTORY(SVGFETurbulenceElement);
+ explicit SVGFETurbulenceElement(Document&);
+
SVGAnimatedNumber* baseFrequencyX() { return base_frequency_->FirstNumber(); }
SVGAnimatedNumber* baseFrequencyY() {
return base_frequency_->SecondNumber();
@@ -65,8 +67,6 @@ class SVGFETurbulenceElement final
bool TaintsOrigin(bool inputs_taint_origin) const override { return false; }
private:
- explicit SVGFETurbulenceElement(Document&);
-
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
void SvgAttributeChanged(const QualifiedName&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h b/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h
index a2bafdbdcc7..f78e53b72fc 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h
@@ -45,6 +45,7 @@ class CORE_EXPORT SVGFilterElement final : public SVGElement,
DECLARE_NODE_FACTORY(SVGFilterElement);
void Trace(blink::Visitor*) override;
+ explicit SVGFilterElement(Document&);
~SVGFilterElement() override;
SVGAnimatedLength* x() const { return x_.Get(); }
@@ -69,8 +70,6 @@ class CORE_EXPORT SVGFilterElement final : public SVGElement,
LocalSVGResource* AssociatedResource() const;
private:
- explicit SVGFilterElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
void ChildrenChanged(const ChildrenChange&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h b/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
index 481cd953954..4717db6604d 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
@@ -32,6 +32,8 @@ class SVGForeignObjectElement final : public SVGGraphicsElement {
public:
DECLARE_NODE_FACTORY(SVGForeignObjectElement);
+ explicit SVGForeignObjectElement(Document&);
+
SVGAnimatedLength* x() const { return x_.Get(); }
SVGAnimatedLength* y() const { return y_.Get(); }
SVGAnimatedLength* width() const { return width_.Get(); }
@@ -40,8 +42,6 @@ class SVGForeignObjectElement final : public SVGGraphicsElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGForeignObjectElement(Document&);
-
void CollectStyleForPresentationAttribute(
const QualifiedName&,
const AtomicString&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_g_element.h b/chromium/third_party/blink/renderer/core/svg/svg_g_element.h
index db483e619e5..01b26095d5b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_g_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_g_element.h
@@ -31,9 +31,9 @@ class CORE_EXPORT SVGGElement final : public SVGGraphicsElement {
public:
DECLARE_NODE_FACTORY(SVGGElement);
- protected:
explicit SVGGElement(Document&, ConstructionType = kCreateSVGElement);
+ protected:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
private:
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.idl b/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.idl
index 445c15b6e94..8145d5c79fa 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.idl
+++ b/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.idl
@@ -34,8 +34,8 @@ interface SVGGeometryElement : SVGGraphicsElement {
[SameObject] readonly attribute SVGAnimatedNumber pathLength;
// TODO(foolip): SVGPoint should be DOMPoint.
- boolean isPointInFill(SVGPoint point);
- boolean isPointInStroke(SVGPoint point);
- float getTotalLength();
- SVGPoint getPointAtLength(float distance);
+ [HighEntropy, Measure] boolean isPointInFill(SVGPoint point);
+ [HighEntropy, Measure] boolean isPointInStroke(SVGPoint point);
+ [HighEntropy, Measure] float getTotalLength();
+ [HighEntropy, Measure] SVGPoint getPointAtLength(float distance);
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_image_element.h b/chromium/third_party/blink/renderer/core/svg/svg_image_element.h
index 333eb0dd6a3..1f69ea66c41 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_image_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_image_element.h
@@ -42,6 +42,9 @@ class CORE_EXPORT SVGImageElement final
public:
DECLARE_NODE_FACTORY(SVGImageElement);
+
+ explicit SVGImageElement(Document&);
+
void Trace(blink::Visitor*) override;
bool CurrentFrameHasSingleSecurityOrigin() const;
@@ -78,8 +81,6 @@ class CORE_EXPORT SVGImageElement final
}
private:
- explicit SVGImageElement(Document&);
-
bool IsStructurallyExternal() const override {
return !HrefString().IsNull();
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_image_element.idl b/chromium/third_party/blink/renderer/core/svg/svg_image_element.idl
index 771e482ba48..b4339886bd5 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_image_element.idl
+++ b/chromium/third_party/blink/renderer/core/svg/svg_image_element.idl
@@ -37,7 +37,8 @@
// https://github.com/ojanvafai/intrinsicsize-attribute/blob/master/README.md
[RuntimeEnabled=ExperimentalProductivityFeatures, CEReactions, Reflect] attribute DOMString intrinsicSize;
- [CallWith=ScriptState, RaisesException] Promise decode();
+ // Follow HTMLImageElement's spec
+ [CallWith=ScriptState, RaisesException] Promise<void> decode();
};
SVGImageElement implements SVGURIReference;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_line_element.h b/chromium/third_party/blink/renderer/core/svg/svg_line_element.h
index 6d5f67fffda..291cc01b612 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_line_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_line_element.h
@@ -33,6 +33,8 @@ class SVGLineElement final : public SVGGeometryElement {
public:
DECLARE_NODE_FACTORY(SVGLineElement);
+ explicit SVGLineElement(Document&);
+
Path AsPath() const override;
SVGAnimatedLength* x1() const { return x1_.Get(); }
@@ -43,8 +45,6 @@ class SVGLineElement final : public SVGGeometryElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGLineElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
bool SelfHasRelativeLengths() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h b/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
index 20094bdbdd1..d96aa75ecca 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
@@ -35,6 +35,8 @@ class SVGLinearGradientElement final : public SVGGradientElement {
public:
DECLARE_NODE_FACTORY(SVGLinearGradientElement);
+ explicit SVGLinearGradientElement(Document&);
+
bool CollectGradientAttributes(LinearGradientAttributes&);
SVGAnimatedLength* x1() const { return x1_.Get(); }
@@ -45,8 +47,6 @@ class SVGLinearGradientElement final : public SVGGradientElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGLinearGradientElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h b/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h
index e667e9f152e..3cdf489124a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h
@@ -58,6 +58,8 @@ class SVGMarkerElement final : public SVGElement, public SVGFitToViewBox {
DECLARE_NODE_FACTORY(SVGMarkerElement);
+ explicit SVGMarkerElement(Document&);
+
AffineTransform ViewBoxToViewTransform(float view_width,
float view_height) const;
@@ -79,8 +81,6 @@ class SVGMarkerElement final : public SVGElement, public SVGFitToViewBox {
void Trace(blink::Visitor*) override;
private:
- explicit SVGMarkerElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
void ChildrenChanged(const ChildrenChange&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h b/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h
index 2ef0ea6ae6b..2db7d962e1c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h
@@ -36,6 +36,8 @@ class SVGMaskElement final : public SVGElement, public SVGTests {
public:
DECLARE_NODE_FACTORY(SVGMaskElement);
+ explicit SVGMaskElement(Document&);
+
SVGAnimatedLength* x() const { return x_.Get(); }
SVGAnimatedLength* y() const { return y_.Get(); }
SVGAnimatedLength* width() const { return width_.Get(); }
@@ -50,8 +52,6 @@ class SVGMaskElement final : public SVGElement, public SVGTests {
void Trace(blink::Visitor*) override;
private:
- explicit SVGMaskElement(Document&);
-
bool IsValid() const override { return SVGTests::IsValid(); }
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_metadata_element.h b/chromium/third_party/blink/renderer/core/svg/svg_metadata_element.h
index 121a3fc1640..0a7d94cc81a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_metadata_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_metadata_element.h
@@ -31,9 +31,9 @@ class SVGMetadataElement final : public SVGElement {
public:
DECLARE_NODE_FACTORY(SVGMetadataElement);
- private:
explicit SVGMetadataElement(Document&);
+ private:
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h b/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h
index 6bd308b33a0..4339ad71663 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h
@@ -34,6 +34,7 @@ class SVGMPathElement final : public SVGElement, public SVGURIReference {
public:
DECLARE_NODE_FACTORY(SVGMPathElement);
+ explicit SVGMPathElement(Document&);
~SVGMPathElement() override;
SVGPathElement* PathElement();
@@ -43,8 +44,6 @@ class SVGMPathElement final : public SVGElement, public SVGURIReference {
void Trace(blink::Visitor*) override;
private:
- explicit SVGMPathElement(Document&);
-
void BuildPendingResource() override;
void ClearResourceReferences();
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_path_element.h b/chromium/third_party/blink/renderer/core/svg/svg_path_element.h
index 3543b903aeb..29cafefe235 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_path_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_path_element.h
@@ -35,6 +35,8 @@ class SVGPathElement final : public SVGGeometryElement {
public:
DECLARE_NODE_FACTORY(SVGPathElement);
+ explicit SVGPathElement(Document&);
+
Path AsPath() const override;
Path AttributePath() const;
@@ -52,8 +54,6 @@ class SVGPathElement final : public SVGGeometryElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGPathElement(Document&);
-
const StylePath* GetStylePath() const;
void SvgAttributeChanged(const QualifiedName&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h b/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h
index 1775ff6ee9e..9374c2cebe4 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h
@@ -47,6 +47,8 @@ class SVGPatternElement final : public SVGElement,
public:
DECLARE_NODE_FACTORY(SVGPatternElement);
+ explicit SVGPatternElement(Document&);
+
void CollectPatternAttributes(PatternAttributes&) const;
AffineTransform LocalCoordinateSpaceTransform(CTMScope) const override;
@@ -83,8 +85,6 @@ class SVGPatternElement final : public SVGElement,
void Trace(blink::Visitor*) override;
private:
- explicit SVGPatternElement(Document&);
-
bool IsValid() const override { return SVGTests::IsValid(); }
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_polygon_element.h b/chromium/third_party/blink/renderer/core/svg/svg_polygon_element.h
index 3b13774a3ac..442f0b09ff2 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_polygon_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_polygon_element.h
@@ -31,10 +31,9 @@ class SVGPolygonElement final : public SVGPolyElement {
public:
DECLARE_NODE_FACTORY(SVGPolygonElement);
- Path AsPath() const override;
-
- private:
explicit SVGPolygonElement(Document&);
+
+ Path AsPath() const override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_polyline_element.h b/chromium/third_party/blink/renderer/core/svg/svg_polyline_element.h
index 671592f93af..e4d98e463c9 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_polyline_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_polyline_element.h
@@ -31,10 +31,9 @@ class SVGPolylineElement final : public SVGPolyElement {
public:
DECLARE_NODE_FACTORY(SVGPolylineElement);
- Path AsPath() const override;
-
- private:
explicit SVGPolylineElement(Document&);
+
+ Path AsPath() const override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h b/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
index 15ebddadca4..52dadb77723 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
@@ -35,6 +35,8 @@ class SVGRadialGradientElement final : public SVGGradientElement {
public:
DECLARE_NODE_FACTORY(SVGRadialGradientElement);
+ explicit SVGRadialGradientElement(Document&);
+
bool CollectGradientAttributes(RadialGradientAttributes&);
SVGAnimatedLength* cx() const { return cx_.Get(); }
@@ -47,8 +49,6 @@ class SVGRadialGradientElement final : public SVGGradientElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGRadialGradientElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h b/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h
index bbeaf633cb4..92d93e97368 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h
@@ -33,6 +33,8 @@ class SVGRectElement final : public SVGGeometryElement {
public:
DECLARE_NODE_FACTORY(SVGRectElement);
+ explicit SVGRectElement(Document&);
+
Path AsPath() const override;
SVGAnimatedLength* x() const { return x_.Get(); }
@@ -45,8 +47,6 @@ class SVGRectElement final : public SVGGeometryElement {
void Trace(blink::Visitor*) override;
private:
- explicit SVGRectElement(Document&);
-
void CollectStyleForPresentationAttribute(
const QualifiedName&,
const AtomicString&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource.cc b/chromium/third_party/blink/renderer/core/svg/svg_resource.cc
index bf7c8a10c7b..d767e45b99c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_resource.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource.cc
@@ -155,8 +155,8 @@ Element* ExternalSVGResource::ResolveTarget() {
Document* external_document = resource_document_->GetDocument();
if (!external_document)
return nullptr;
- AtomicString decoded_fragment(
- DecodeURLEscapeSequences(url_.FragmentIdentifier()));
+ AtomicString decoded_fragment(DecodeURLEscapeSequences(
+ url_.FragmentIdentifier(), DecodeURLMode::kUTF8OrIsomorphic));
return external_document->getElementById(decoded_fragment);
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_script_element.h b/chromium/third_party/blink/renderer/core/svg/svg_script_element.h
index 4525f28fb1c..5fe1cc2b236 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_script_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_script_element.h
@@ -76,6 +76,7 @@ class SVGScriptElement final : public SVGElement,
String ForAttributeValue() const override { return String(); }
String IntegrityAttributeValue() const override { return String(); }
String ReferrerPolicyAttributeValue() const override { return String(); }
+ String ImportanceAttributeValue() const override { return String(); }
String LanguageAttributeValue() const override { return String(); }
bool NomoduleAttributeValue() const override { return false; }
String SourceAttributeValue() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_set_element.h b/chromium/third_party/blink/renderer/core/svg/svg_set_element.h
index 091f3394e30..ab2cd1d9a0b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_set_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_set_element.h
@@ -33,8 +33,9 @@ class CORE_EXPORT SVGSetElement final : public SVGAnimateElement {
public:
DECLARE_NODE_FACTORY(SVGSetElement);
- private:
explicit SVGSetElement(Document&);
+
+ private:
void UpdateAnimationMode() override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc
index 03ecf0e995d..18bf8292453 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc
@@ -80,8 +80,8 @@ Color SVGStopElement::StopColorIncludingOpacity() const {
if (!style)
return Color::kBlack;
- const SVGComputedStyle& svg_style = style->SvgStyle();
- return svg_style.StopColor().CombineWithAlpha(svg_style.StopOpacity());
+ Color base_color = style->VisitedDependentColor(GetCSSPropertyStopColor());
+ return base_color.CombineWithAlpha(style->SvgStyle().StopOpacity());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h
index 7388b4d2754..15aceeee536 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h
@@ -35,6 +35,8 @@ class SVGStopElement final : public SVGElement {
public:
DECLARE_NODE_FACTORY(SVGStopElement);
+ explicit SVGStopElement(Document&);
+
Color StopColorIncludingOpacity() const;
SVGAnimatedNumber* offset() const { return offset_.Get(); }
@@ -45,8 +47,6 @@ class SVGStopElement final : public SVGElement {
void DidRecalcStyle(StyleRecalcChange) override;
private:
- explicit SVGStopElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
// Stop elements don't have associated layout objects
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_string_list.h b/chromium/third_party/blink/renderer/core/svg/svg_string_list.h
index 82178789885..ec8f192f0dc 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_string_list.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_string_list.h
@@ -113,8 +113,10 @@ template <char list_delimiter>
class SVGStringList final : public SVGStringListBase {
public:
static SVGStringList<list_delimiter>* Create() {
- return new SVGStringList<list_delimiter>();
+ return MakeGarbageCollected<SVGStringList<list_delimiter>>();
}
+
+ SVGStringList() = default;
~SVGStringList() override = default;
SVGParsingError SetValueAsString(const String& data) override {
@@ -125,9 +127,6 @@ class SVGStringList final : public SVGStringListBase {
String ValueAsString() const override {
return SVGStringListBase::ValueAsStringWithDelimiter(list_delimiter);
}
-
- private:
- SVGStringList() = default;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h b/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h
index 550b9290cd1..d145053abd0 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h
@@ -49,6 +49,8 @@ class SVGSVGElement final : public SVGGraphicsElement,
public:
DECLARE_NODE_FACTORY(SVGSVGElement);
+ explicit SVGSVGElement(Document&);
+
float IntrinsicWidth() const;
float IntrinsicHeight() const;
FloatSize CurrentViewportSize() const;
@@ -112,7 +114,6 @@ class SVGSVGElement final : public SVGGraphicsElement,
void Trace(blink::Visitor*) override;
private:
- explicit SVGSVGElement(Document&);
~SVGSVGElement() override;
void SetViewSpec(const SVGViewSpec*);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_switch_element.h b/chromium/third_party/blink/renderer/core/svg/svg_switch_element.h
index 3d6e1aee973..b930f457a3e 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_switch_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_switch_element.h
@@ -31,9 +31,9 @@ class SVGSwitchElement final : public SVGGraphicsElement {
public:
DECLARE_NODE_FACTORY(SVGSwitchElement);
- private:
explicit SVGSwitchElement(Document&);
+ private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h b/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h
index 73bfbcb7363..bc4e9b6200b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h
@@ -33,11 +33,11 @@ class SVGSymbolElement final : public SVGElement, public SVGFitToViewBox {
public:
DECLARE_NODE_FACTORY(SVGSymbolElement);
+ explicit SVGSymbolElement(Document&);
+
void Trace(blink::Visitor*) override;
private:
- explicit SVGSymbolElement(Document&);
-
void SvgAttributeChanged(const QualifiedName&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.idl b/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.idl
index 4617f7f3457..6557fcf63d8 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.idl
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.idl
@@ -35,12 +35,12 @@ interface SVGTextContentElement : SVGGraphicsElement {
[MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedEnumeration lengthAdjust;
long getNumberOfChars();
- float getComputedTextLength();
- [RaisesException] float getSubStringLength(unsigned long charnum, unsigned long nchars);
+ [HighEntropy, Measure] float getComputedTextLength();
+ [HighEntropy, Measure, RaisesException] float getSubStringLength(unsigned long charnum, unsigned long nchars);
// TODO(foolip): SVGPoint/SVGRect should be DOMPoint/DOMRect.
- [RaisesException] SVGPoint getStartPositionOfChar(unsigned long charnum);
- [RaisesException] SVGPoint getEndPositionOfChar(unsigned long charnum);
- [RaisesException] SVGRect getExtentOfChar(unsigned long charnum);
+ [HighEntropy, Measure, RaisesException] SVGPoint getStartPositionOfChar(unsigned long charnum);
+ [HighEntropy, Measure, RaisesException] SVGPoint getEndPositionOfChar(unsigned long charnum);
+ [HighEntropy, Measure, RaisesException] SVGRect getExtentOfChar(unsigned long charnum);
[RaisesException] float getRotationOfChar(unsigned long charnum);
[RaisesException] long getCharNumAtPosition(SVGPoint point);
[RaisesException] void selectSubString(unsigned long charnum, unsigned long nchars);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_element.h b/chromium/third_party/blink/renderer/core/svg/svg_text_element.h
index f1a68930f58..6bcf729e4b4 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_element.h
@@ -31,9 +31,9 @@ class SVGTextElement final : public SVGTextPositioningElement {
public:
DECLARE_NODE_FACTORY(SVGTextElement);
- private:
explicit SVGTextElement(Document&);
+ private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h b/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h
index 48a53d9510a..1b271130732 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h
@@ -58,6 +58,8 @@ class SVGTextPathElement final : public SVGTextContentElement,
DECLARE_NODE_FACTORY(SVGTextPathElement);
+ explicit SVGTextPathElement(Document&);
+
SVGAnimatedLength* startOffset() const { return start_offset_.Get(); }
SVGAnimatedEnumeration<SVGTextPathMethodType>* method() {
return method_.Get();
@@ -69,8 +71,6 @@ class SVGTextPathElement final : public SVGTextContentElement,
void Trace(blink::Visitor*) override;
private:
- explicit SVGTextPathElement(Document&);
-
~SVGTextPathElement() override;
void ClearResourceReferences();
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_title_element.h b/chromium/third_party/blink/renderer/core/svg/svg_title_element.h
index 6b662d3de67..38021cb8ac7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_title_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_title_element.h
@@ -31,11 +31,11 @@ class SVGTitleElement final : public SVGElement {
public:
DECLARE_NODE_FACTORY(SVGTitleElement);
+ explicit SVGTitleElement(Document&);
+
void SetText(const String&);
private:
- explicit SVGTitleElement(Document&);
-
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
void ChildrenChanged(const ChildrenChange&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_transform.cc b/chromium/third_party/blink/renderer/core/svg/svg_transform.cc
index 0c8ca92dc36..3aea44c7a54 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_transform.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_transform.cc
@@ -20,6 +20,7 @@
#include "third_party/blink/renderer/core/svg/svg_transform.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/geometry/float_size.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -202,7 +203,7 @@ String SVGTransform::ValueAsString() const {
arguments[argument_count++] = angle_;
break;
}
- DCHECK_LE(argument_count, arraysize(arguments));
+ DCHECK_LE(argument_count, base::size(arguments));
StringBuilder builder;
builder.Append(TransformTypePrefixForParsing(transform_type_));
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_transform_list.cc b/chromium/third_party/blink/renderer/core/svg/svg_transform_list.cc
index f00965a4bdf..dc48edb1706 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_transform_list.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_transform_list.cc
@@ -23,6 +23,7 @@
#include "third_party/blink/renderer/core/svg/svg_transform_list.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/css_function_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
@@ -204,10 +205,10 @@ static_assert(kSvgTransformSkewx == 5,
"index of kSvgTransformSkewx has changed");
static_assert(kSvgTransformSkewy == 6,
"index of kSvgTransformSkewy has changed");
-static_assert(arraysize(kRequiredValuesForType) - 1 == kSvgTransformSkewy,
+static_assert(base::size(kRequiredValuesForType) - 1 == kSvgTransformSkewy,
"the number of transform types have changed");
-static_assert(arraysize(kRequiredValuesForType) ==
- arraysize(kOptionalValuesForType),
+static_assert(base::size(kRequiredValuesForType) ==
+ base::size(kOptionalValuesForType),
"the arrays should have the same number of elements");
const unsigned kMaxTransformArguments = 6;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_tspan_element.h b/chromium/third_party/blink/renderer/core/svg/svg_tspan_element.h
index 7870fee9436..6ffdf83b983 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_tspan_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_tspan_element.h
@@ -31,9 +31,9 @@ class SVGTSpanElement final : public SVGTextPositioningElement {
public:
DECLARE_NODE_FACTORY(SVGTSpanElement);
- private:
explicit SVGTSpanElement(Document&);
+ private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_uri_reference.cc b/chromium/third_party/blink/renderer/core/svg/svg_uri_reference.cc
index bce67926c47..3f4d84ac246 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_uri_reference.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_uri_reference.cc
@@ -90,8 +90,8 @@ bool SVGURLReferenceResolver::IsLocal() const {
AtomicString SVGURLReferenceResolver::FragmentIdentifier() const {
// Use KURL's FragmentIdentifier to ensure that we're handling the
// fragment in a consistent manner.
- return AtomicString(
- DecodeURLEscapeSequences(AbsoluteUrl().FragmentIdentifier()));
+ return AtomicString(DecodeURLEscapeSequences(
+ AbsoluteUrl().FragmentIdentifier(), DecodeURLMode::kUTF8OrIsomorphic));
}
AtomicString SVGURIReference::FragmentIdentifierFromIRIString(
@@ -138,8 +138,8 @@ Element* SVGURIReference::ObserveTarget(Member<IdTargetObserver>& observer,
DCHECK(!observer);
if (id.IsEmpty())
return nullptr;
- observer =
- new SVGElementReferenceObserver(tree_scope, id, std::move(closure));
+ observer = MakeGarbageCollected<SVGElementReferenceObserver>(
+ tree_scope, id, std::move(closure));
return tree_scope.getElementById(id);
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc
index 93c756faa29..46096de8d1e 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -307,8 +307,8 @@ void SVGUseElement::ClearResourceReference() {
Element* SVGUseElement::ResolveTargetElement(ObserveBehavior observe_behavior) {
if (!element_url_.HasFragmentIdentifier())
return nullptr;
- AtomicString element_identifier(
- DecodeURLEscapeSequences(element_url_.FragmentIdentifier()));
+ AtomicString element_identifier(DecodeURLEscapeSequences(
+ element_url_.FragmentIdentifier(), DecodeURLMode::kUTF8OrIsomorphic));
if (!IsStructurallyExternal()) {
if (observe_behavior == kDontAddObserver)
return GetTreeScope().getElementById(element_identifier);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_view_element.h b/chromium/third_party/blink/renderer/core/svg/svg_view_element.h
index c5ec9528c2f..ba9c3388d42 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_view_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_view_element.h
@@ -36,11 +36,12 @@ class SVGViewElement final : public SVGElement,
public:
DECLARE_NODE_FACTORY(SVGViewElement);
- void Trace(blink::Visitor*) override;
- private:
explicit SVGViewElement(Document&);
+ void Trace(blink::Visitor*) override;
+
+ private:
void ParseAttribute(const AttributeModificationParams&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
diff --git a/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc b/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
index f046a182192..3f7faec720d 100644
--- a/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
+++ b/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
@@ -210,11 +210,11 @@ TEST(
<< sanitized_content.Utf8().data();
}
-// Other sanitization integration tests are layout tests that use
+// Other sanitization integration tests are web tests that use
// document.execCommand('Copy') to source content that they later
// paste. However SVG animation elements are not serialized when
// copying, which means we can't test sanitizing these attributes in
-// layout tests: there is nowhere to source the unsafe content from.
+// web tests: there is nowhere to source the unsafe content from.
TEST(UnsafeSVGAttributeSanitizationTest,
pasteAnimatedAnchor_javaScriptHrefIsStripped_caseAndEntityInProtocol) {
std::unique_ptr<DummyPageHolder> page_holder =
diff --git a/chromium/third_party/blink/renderer/core/testing/DEPS b/chromium/third_party/blink/renderer/core/testing/DEPS
index 1cd6cecba86..982d4f4ce4e 100644
--- a/chromium/third_party/blink/renderer/core/testing/DEPS
+++ b/chromium/third_party/blink/renderer/core/testing/DEPS
@@ -3,7 +3,7 @@ include_rules = [
# TODO(crbug.com/838693): Test harnesses use LayerTreeView
# from content instead of a fake WebLayerTreeView implementation, so
# that the Web abstraction can go away.
- "+content/renderer/gpu",
+ "+content/renderer/compositor",
"+content/test",
"+gpu/command_buffer/client/gles2_interface.h",
]
diff --git a/chromium/third_party/blink/renderer/core/testing/callback_function_test.h b/chromium/third_party/blink/renderer/core/testing/callback_function_test.h
index 035b0d2978e..a20bc0fd3bf 100644
--- a/chromium/third_party/blink/renderer/core/testing/callback_function_test.h
+++ b/chromium/third_party/blink/renderer/core/testing/callback_function_test.h
@@ -24,7 +24,9 @@ class CallbackFunctionTest final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static CallbackFunctionTest* Create() { return new CallbackFunctionTest(); }
+ static CallbackFunctionTest* Create() {
+ return MakeGarbageCollected<CallbackFunctionTest>();
+ }
String testCallback(V8TestCallback*,
const String&,
diff --git a/chromium/third_party/blink/renderer/core/testing/data/fixed-position-losing-backing.html b/chromium/third_party/blink/renderer/core/testing/data/fixed-position-losing-backing.html
deleted file mode 100644
index b4c0712c3a3..00000000000
--- a/chromium/third_party/blink/renderer/core/testing/data/fixed-position-losing-backing.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<style>
-#fixed {
- position: fixed;
- width: 100px;
- height: 100px;
- /* Using transparent background color so that fixed position element is not automatically promoted. */
- background-color: rgba(255, 255, 0, 0.5);
- transform: translateZ(0);
-}
-
-#bloat {
- height: 10000px;
-}
-</style>
-<div id="fixed"></div>
-<div id="bloat"></div>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/test_touch_link_highlight.html b/chromium/third_party/blink/renderer/core/testing/data/test_touch_link_highlight.html
index 9669936483b..9254ca5b07d 100644
--- a/chromium/third_party/blink/renderer/core/testing/data/test_touch_link_highlight.html
+++ b/chromium/third_party/blink/renderer/core/testing/data/test_touch_link_highlight.html
@@ -29,20 +29,11 @@
<div style="position: absolute; left: 20px; top: 260px; width: 200px;">
<input type="text"> <!-- This will have an I-beam cursor. -->
</div>
- <a href="http://www.test.com" style="position: absolute; left: 20px; top: 300px; width: 400px;">One link to highlight</a>
- <a href="http://www.test.com" style="position: absolute; left: 20px; top: 320px; width: 400px;">Another link to highlight simultaneously</a>
-<!-- The following is the text for the iframe tag below:
-<html>
-<body>
-<a href="http://www.test.com" position: absolute; left: 50px; top: 30px>
-This is going to be a very long link to force the scrollbars to activate on the iFrame that will contain this page.
-</a>
-</body>
-</html>
--->
-<!--
- <iframe style="scrolling: yes; width : 400px; height : 100px; position: absolute; left: 20px; top: 210px;"
- src="data:text/html,%3Chtml%3E%0A%3Cbody%3E%0A%3Ca%20href%3D%22http%3A%2F%2Fwww.test.com%22%20position%3A%20absolute%3B%20left%3A%2050px%3B%20top%3A%2030px%3E%0AThis%20is%20going%20to%20be%20a%20very%20long%20link%20to%20force%20the%20scrollbars%20to%20activate%20on%20the%20iFrame%20that%20will%20contain%20this%20page.%0A%3C%2Fa%3E%0A%3C%2Fbody%3E%0A%3C%2Fhtml%3E"></iframe>
--->
+ <div style="position: absolute; left: 20px; top: 300px; width: 400px; height: 50px; columns: 2">
+ <a href="http://www.test.com">
+ <div style="display: inline-block; width: 200px; height: 50px">Link in column 1</div>
+ <div style="display: inline-block; width: 200px; height: 50px">Link in column 2</div>
+ </a>
+ </div>
</body>
</html>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/wheel-event-handler.html b/chromium/third_party/blink/renderer/core/testing/data/wheel-event-handler.html
index 7e450a4ece6..51e39d0e625 100644
--- a/chromium/third_party/blink/renderer/core/testing/data/wheel-event-handler.html
+++ b/chromium/third_party/blink/renderer/core/testing/data/wheel-event-handler.html
@@ -3,7 +3,7 @@
<head>
<script type="text/javascript">
window.addEventListener('mousewheel', function(event) {
- });
+ }, {passive: false});
</script>
</head>
diff --git a/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc b/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc
index 3f725f36690..368c08dd3a3 100644
--- a/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc
+++ b/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc
@@ -178,8 +178,10 @@ String DictionaryTest::stringFromIterable(
result.Append(',');
v8::Local<v8::Value> value;
- if (iterator.GetValue().ToLocal(&value))
- result.Append(ToCoreString(value->ToString(script_state->GetIsolate())));
+ if (iterator.GetValue().ToLocal(&value)) {
+ result.Append(ToCoreString(
+ value->ToString(script_state->GetContext()).ToLocalChecked()));
+ }
}
return result.ToString();
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc
index 7c2d2064f42..74459e34c21 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -35,7 +35,8 @@ class EmptyScriptModuleResolver final : public ScriptModuleResolver {
} // namespace
-DummyModulator::DummyModulator() : resolver_(new EmptyScriptModuleResolver()) {}
+DummyModulator::DummyModulator()
+ : resolver_(MakeGarbageCollected<EmptyScriptModuleResolver>()) {}
DummyModulator::~DummyModulator() = default;
@@ -63,7 +64,7 @@ base::SingleThreadTaskRunner* DummyModulator::TaskRunner() {
};
void DummyModulator::FetchTree(const KURL&,
- FetchClientSettingsObjectSnapshot*,
+ ResourceFetcher*,
mojom::RequestContextType,
const ScriptFetchOptions&,
ModuleScriptCustomFetchType,
@@ -72,18 +73,17 @@ void DummyModulator::FetchTree(const KURL&,
}
void DummyModulator::FetchSingle(const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot*,
+ ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptCustomFetchType,
SingleModuleClient*) {
NOTREACHED();
}
-void DummyModulator::FetchDescendantsForInlineScript(
- ModuleScript*,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType,
- ModuleTreeClient*) {
+void DummyModulator::FetchDescendantsForInlineScript(ModuleScript*,
+ ResourceFetcher*,
+ mojom::RequestContextType,
+ ModuleTreeClient*) {
NOTREACHED();
}
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h
index ae6477c7567..de1a0c91ba5 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h
@@ -34,24 +34,21 @@ class DummyModulator : public Modulator {
ScriptState* GetScriptState() override;
bool IsScriptingDisabled() const override;
- void FetchTree(
- const KURL&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType destination,
- const ScriptFetchOptions&,
- ModuleScriptCustomFetchType,
- ModuleTreeClient*) override;
- void FetchSingle(
- const ModuleScriptFetchRequest&,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- ModuleGraphLevel,
- ModuleScriptCustomFetchType,
- SingleModuleClient*) override;
- void FetchDescendantsForInlineScript(
- ModuleScript*,
- FetchClientSettingsObjectSnapshot* fetch_client_settings_object,
- mojom::RequestContextType destination,
- ModuleTreeClient*) override;
+ void FetchTree(const KURL&,
+ ResourceFetcher*,
+ mojom::RequestContextType destination,
+ const ScriptFetchOptions&,
+ ModuleScriptCustomFetchType,
+ ModuleTreeClient*) override;
+ void FetchSingle(const ModuleScriptFetchRequest&,
+ ResourceFetcher*,
+ ModuleGraphLevel,
+ ModuleScriptCustomFetchType,
+ SingleModuleClient*) override;
+ void FetchDescendantsForInlineScript(ModuleScript*,
+ ResourceFetcher*,
+ mojom::RequestContextType destination,
+ ModuleTreeClient*) override;
ModuleScript* GetFetchedModuleScript(const KURL&) override;
KURL ResolveModuleSpecifier(const String&, const KURL&, String*) override;
bool HasValidContext() override;
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc b/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc
index 8c9bfdb5aab..343b8797ba5 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc
@@ -43,6 +43,20 @@
namespace blink {
+namespace {
+
+class DummyLocalFrameClient : public EmptyLocalFrameClient {
+ public:
+ DummyLocalFrameClient() = default;
+
+ private:
+ std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override {
+ return Platform::Current()->CreateDefaultURLLoaderFactory();
+ }
+};
+
+} // namespace
+
std::unique_ptr<DummyPageHolder> DummyPageHolder::Create(
const IntSize& initial_view_size,
Page::PageClients* page_clients,
@@ -69,7 +83,7 @@ DummyPageHolder::DummyPageHolder(
local_frame_client_ = local_frame_client;
if (!local_frame_client_)
- local_frame_client_ = EmptyLocalFrameClient::Create();
+ local_frame_client_ = MakeGarbageCollected<DummyLocalFrameClient>();
frame_ = LocalFrame::Create(local_frame_client_.Get(), *page_, nullptr);
frame_->SetView(LocalFrameView::Create(*frame_, initial_view_size));
diff --git a/chromium/third_party/blink/renderer/core/testing/internals.cc b/chromium/third_party/blink/renderer/core/testing/internals.cc
index 2e5b06872aa..2b0889e0e5a 100644
--- a/chromium/third_party/blink/renderer/core/testing/internals.cc
+++ b/chromium/third_party/blink/renderer/core/testing/internals.cc
@@ -120,6 +120,7 @@
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
#include "third_party/blink/renderer/core/page/scrolling/scroll_state.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_context.h"
+#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.h"
@@ -267,6 +268,15 @@ void Internals::ResetToConsistentState(Page* page) {
// call.
page->SetDefaultPageScaleLimits(1, 4);
page->SetPageScaleFactor(1);
+
+ // Ensure timers are reset so timers such as EventHandler's |hover_timer_| do
+ // not cause additional lifecycle updates.
+ for (Frame* frame = page->MainFrame(); frame;
+ frame = frame->Tree().TraverseNext()) {
+ if (frame->IsLocalFrame())
+ ToLocalFrame(frame)->GetEventHandler().Clear();
+ }
+
LocalFrame* frame = page->DeprecatedLocalMainFrame();
frame->View()->LayoutViewport()->SetScrollOffset(ScrollOffset(),
kProgrammaticScroll);
@@ -363,6 +373,9 @@ unsigned Internals::hitTestCount(Document* doc,
return 0;
}
+ if (!doc->GetLayoutView())
+ return 0;
+
return doc->GetLayoutView()->HitTestCount();
}
@@ -374,6 +387,9 @@ unsigned Internals::hitTestCacheHits(Document* doc,
return 0;
}
+ if (!doc->GetLayoutView())
+ return 0;
+
return doc->GetLayoutView()->HitTestCacheHits();
}
@@ -471,6 +487,15 @@ int Internals::getResourcePriority(const String& url, Document* document) {
return static_cast<int>(resource->GetResourceRequest().Priority());
}
+bool Internals::doesWindowHaveUrlFragment(DOMWindow* window) {
+ if (window->IsRemoteDOMWindow())
+ return false;
+ return ToLocalFrame(window->GetFrame())
+ ->GetDocument()
+ ->Url()
+ .HasFragmentIdentifier();
+}
+
String Internals::getResourceHeader(const String& url,
const String& header,
Document* document) {
@@ -847,7 +872,7 @@ DOMWindow* Internals::pagePopupWindow() const {
LocalDOMWindow* popup =
ToLocalDOMWindow(page->GetChromeClient().PagePopupWindowForTesting());
if (popup) {
- // We need to make the popup same origin so layout tests can access it.
+ // We need to make the popup same origin so web tests can access it.
popup->document()->UpdateSecurityOrigin(
document_->GetMutableSecurityOrigin());
}
@@ -1674,7 +1699,8 @@ static unsigned EventHandlerCount(
unsigned Internals::wheelEventHandlerCount(Document* document) const {
DCHECK(document);
return EventHandlerCount(*document,
- EventHandlerRegistry::kWheelEventBlocking);
+ EventHandlerRegistry::kWheelEventBlocking) +
+ EventHandlerCount(*document, EventHandlerRegistry::kWheelEventPassive);
}
unsigned Internals::scrollEventHandlerCount(Document* document) const {
@@ -1904,7 +1930,7 @@ HitTestLayerRectList* Internals::touchEventTargetLayerRects(
return nullptr;
}
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
auto* pac = document->View()->GetPaintArtifactCompositorForTesting();
pac->EnableExtraDataForTesting();
document->View()->UpdateAllLifecyclePhases(
@@ -1917,7 +1943,8 @@ HitTestLayerRectList* Internals::touchEventTargetLayerRects(
const cc::TouchActionRegion& touch_action_region =
layer->touch_action_region();
if (!touch_action_region.region().IsEmpty()) {
- IntRect layer_rect(RoundedIntPoint(FloatPoint(layer->position())),
+ const auto& offset = layer->offset_to_transform_parent();
+ IntRect layer_rect(RoundedIntPoint(FloatPoint(offset.x(), offset.y())),
IntSize(layer->bounds()));
Vector<IntRect> layer_hit_test_rects;
@@ -3067,14 +3094,14 @@ namespace {
class AddOneFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
- AddOneFunction* self = new AddOneFunction(script_state);
+ AddOneFunction* self = MakeGarbageCollected<AddOneFunction>(script_state);
return self->BindToV8Function();
}
- private:
explicit AddOneFunction(ScriptState* script_state)
: ScriptFunction(script_state) {}
+ private:
ScriptValue Call(ScriptValue value) override {
v8::Local<v8::Value> v8_value = value.V8Value();
DCHECK(v8_value->IsNumber());
@@ -3191,6 +3218,23 @@ bool Internals::ignoreLayoutWithPendingStylesheets(Document* document) {
return document->IgnoreLayoutWithPendingStylesheets();
}
+Element* Internals::interestedElement() {
+ if (!GetFrame() || !GetFrame()->GetPage())
+ return nullptr;
+
+ if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+ return ToLocalFrame(
+ GetFrame()->GetPage()->GetFocusController().FocusedOrMainFrame())
+ ->GetDocument()
+ ->ActiveElement();
+ }
+
+ return GetFrame()
+ ->GetPage()
+ ->GetSpatialNavigationController()
+ .GetInterestedElement();
+}
+
void Internals::setNetworkConnectionInfoOverride(
bool on_line,
const String& type,
@@ -3389,8 +3433,9 @@ ScriptPromise Internals::observeUseCounter(ScriptState* script_state,
return promise;
}
- loader->GetUseCounter().AddObserver(new UseCounterObserverImpl(
- resolver, static_cast<WebFeature>(use_counter_feature)));
+ loader->GetUseCounter().AddObserver(
+ MakeGarbageCollected<UseCounterObserverImpl>(
+ resolver, static_cast<WebFeature>(use_counter_feature)));
return promise;
}
@@ -3402,24 +3447,6 @@ String Internals::unscopableMethod() {
return "unscopableMethod";
}
-DOMRectList* Internals::focusRingRects(Element* element) {
- Vector<LayoutRect> rects;
- if (element && element->GetLayoutObject()) {
- element->GetLayoutObject()->AddOutlineRects(
- rects, LayoutPoint(), NGOutlineType::kIncludeBlockVisualOverflow);
- }
- return DOMRectList::Create(rects);
-}
-
-DOMRectList* Internals::outlineRects(Element* element) {
- Vector<LayoutRect> rects;
- if (element && element->GetLayoutObject()) {
- element->GetLayoutObject()->AddOutlineRects(
- rects, LayoutPoint(), NGOutlineType::kDontIncludeBlockVisualOverflow);
- }
- return DOMRectList::Create(rects);
-}
-
void Internals::setCapsLockState(bool enabled) {
KeyboardEventManager::SetCurrentCapsLockState(
enabled ? OverrideCapsLockState::kOn : OverrideCapsLockState::kOff);
@@ -3445,6 +3472,10 @@ double Internals::monotonicTimeToZeroBasedDocumentTime(
.InSecondsF();
}
+int64_t Internals::currentTimeTicks() {
+ return base::TimeTicks::Now().since_origin().InMicroseconds();
+}
+
String Internals::getScrollAnimationState(Node* node) const {
if (ScrollableArea* scrollable_area = ScrollableAreaForNode(node))
return scrollable_area->GetScrollAnimator().RunStateAsText();
diff --git a/chromium/third_party/blink/renderer/core/testing/internals.h b/chromium/third_party/blink/renderer/core/testing/internals.h
index 3d69d29d086..dd463b87721 100644
--- a/chromium/third_party/blink/renderer/core/testing/internals.h
+++ b/chromium/third_party/blink/renderer/core/testing/internals.h
@@ -108,6 +108,8 @@ class Internals final : public ScriptWrappable {
int getResourcePriority(const String& url, Document*);
String getResourceHeader(const String& url, const String& header, Document*);
+ bool doesWindowHaveUrlFragment(DOMWindow*);
+
CSSStyleDeclaration* computedStyleIncludingVisitedInfo(Node*) const;
void setBrowserControlsState(float top_height,
@@ -493,6 +495,8 @@ class Internals final : public ScriptWrappable {
bool ignoreLayoutWithPendingStylesheets(Document*);
+ Element* interestedElement();
+
void setNetworkConnectionInfoOverride(bool,
const String&,
const String&,
@@ -546,9 +550,6 @@ class Internals final : public ScriptWrappable {
String unscopableAttribute();
String unscopableMethod();
- DOMRectList* focusRingRects(Element*);
- DOMRectList* outlineRects(Element*);
-
void setCapsLockState(bool enabled);
bool setScrollbarVisibilityInScrollableArea(Node*, bool visible);
@@ -557,6 +558,9 @@ class Internals final : public ScriptWrappable {
// document time in seconds
double monotonicTimeToZeroBasedDocumentTime(double, ExceptionState&);
+ // Returns the current time ticks (in microseconds).
+ int64_t currentTimeTicks();
+
// Returns the run state of the node's scroll animator (see
// ScrollAnimatorCompositorCoordinater::RunState), or -1 if the node does not
// have a scrollable area.
diff --git a/chromium/third_party/blink/renderer/core/testing/internals.idl b/chromium/third_party/blink/renderer/core/testing/internals.idl
index 8c575f90721..7099cd94a72 100644
--- a/chromium/third_party/blink/renderer/core/testing/internals.idl
+++ b/chromium/third_party/blink/renderer/core/testing/internals.idl
@@ -44,6 +44,8 @@ enum EffectiveConnectionType {
unsigned long getResourcePriority (DOMString url, Document document);
DOMString getResourceHeader (DOMString url, DOMString header, Document document);
+ bool doesWindowHaveUrlFragment(Window window);
+
CSSStyleDeclaration computedStyleIncludingVisitedInfo(Node node);
ShadowRoot createUserAgentShadowRoot(Element host);
@@ -307,15 +309,15 @@ enum EffectiveConnectionType {
[RaisesException] void setShouldRevealPassword(Element element, boolean reveal);
- [CallWith=ScriptState] Promise createResolvedPromise(any value);
- [CallWith=ScriptState] Promise createRejectedPromise(any reason);
- [CallWith=ScriptState] Promise addOneToPromise(Promise promise);
- [CallWith=ScriptState, RaisesException] Promise promiseCheck(long arg1, boolean arg2, object arg3, DOMString arg4, sequence<DOMString> arg5);
- [CallWith=ScriptState] Promise promiseCheckWithoutExceptionState(object arg1, DOMString arg2, DOMString... variadic);
- [CallWith=ScriptState] Promise promiseCheckRange([EnforceRange] octet arg1);
- [CallWith=ScriptState] Promise promiseCheckOverload(Location arg1);
- [CallWith=ScriptState] Promise promiseCheckOverload(Document arg1);
- [CallWith=ScriptState] Promise promiseCheckOverload(Location arg1, long arg2, long arg3);
+ [CallWith=ScriptState] Promise<any> createResolvedPromise(any value);
+ [CallWith=ScriptState] Promise<any> createRejectedPromise(any reason);
+ [CallWith=ScriptState] Promise<any> addOneToPromise(Promise<any> promise);
+ [CallWith=ScriptState, RaisesException] Promise<any> promiseCheck(long arg1, boolean arg2, object arg3, DOMString arg4, sequence<DOMString> arg5);
+ [CallWith=ScriptState] Promise<any> promiseCheckWithoutExceptionState(object arg1, DOMString arg2, DOMString... variadic);
+ [CallWith=ScriptState] Promise<any> promiseCheckRange([EnforceRange] octet arg1);
+ [CallWith=ScriptState] Promise<any> promiseCheckOverload(Location arg1);
+ [CallWith=ScriptState] Promise<any> promiseCheckOverload(Document arg1);
+ [CallWith=ScriptState] Promise<any> promiseCheckOverload(Location arg1, long arg2, long arg3);
void setValueForUser(HTMLInputElement element, DOMString value);
@@ -324,6 +326,11 @@ enum EffectiveConnectionType {
boolean ignoreLayoutWithPendingStylesheets(Document document);
+ // When the FocuslessSpatialNavigation feature is enabled, spatial
+ // navigation moves "interest" around a page, rather than focus. This
+ // attribute returns the currently interested element on the page.
+ readonly attribute Element? interestedElement;
+
// These functions are for testing NetInfo. You must call clearNetworkConnectionInfoOverride() at the end.
[RaisesException] void setNetworkConnectionInfoOverride(boolean onLine, DOMString type, EffectiveConnectionType effective_type, unsigned long http_rtt_msec, double downlink_max_mbps);
void setSaveDataEnabled(boolean enabled);
@@ -371,8 +378,6 @@ enum EffectiveConnectionType {
[Unscopable] readonly attribute DOMString unscopableAttribute;
[Unscopable] DOMString unscopableMethod();
- DOMRectList focusRingRects(Element element);
- DOMRectList outlineRects(Element element);
void setCapsLockState(boolean enabled);
// Returns whether the scrollbar was able to be shown or hidden; not all platforms
@@ -380,6 +385,7 @@ enum EffectiveConnectionType {
boolean setScrollbarVisibilityInScrollableArea(Node node, boolean visible);
[RaisesException] double monotonicTimeToZeroBasedDocumentTime(double platformTime);
+ long long currentTimeTicks();
DOMString getScrollAnimationState(Node node);
@@ -414,7 +420,7 @@ enum EffectiveConnectionType {
// Disable the 'delay' option for IntersectionObserver, so that observations
// are recomputed on every frame. This eliminates the need to add
- // setTimeout(..., delay_ms) calls to layout tests to wait for notifications
+ // setTimeout(..., delay_ms) calls to web tests to wait for notifications
// to be generated.
void DisableIntersectionObserverThrottleDelay();
diff --git a/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc b/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc
index 1fdf44f8e33..6bcc92f3a60 100644
--- a/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc
+++ b/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc
@@ -30,7 +30,7 @@ bool NullExecutionContext::IsSecureContext(String& error_message) const {
void NullExecutionContext::SetUpSecurityContext() {
ContentSecurityPolicy* policy = ContentSecurityPolicy::Create();
SecurityContext::SetSecurityOrigin(SecurityOrigin::Create(url_));
- policy->BindToExecutionContext(this);
+ policy->BindToDelegate(GetContentSecurityPolicyDelegate());
SecurityContext::SetContentSecurityPolicy(policy);
}
diff --git a/chromium/third_party/blink/renderer/core/testing/page_test_base.cc b/chromium/third_party/blink/renderer/core/testing/page_test_base.cc
index 6f4e35bb4e0..5698d8f08e3 100644
--- a/chromium/third_party/blink/renderer/core/testing/page_test_base.cc
+++ b/chromium/third_party/blink/renderer/core/testing/page_test_base.cc
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/platform/loader/fetch/substitute_data.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc
index 8ea1b96e428..29217bb4175 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc
@@ -87,35 +87,6 @@ void SimCanvas::onDrawImageRect(const SkImage* image,
SkCanvas::onDrawImageRect(image, src, dst, paint, constraint);
}
-void SimCanvas::onDrawText(const void* text,
- size_t byte_length,
- SkScalar x,
- SkScalar y,
- const SkPaint& paint) {
- DrawScope scope;
- AddCommand(CommandType::kText, paint.getColor());
- SkCanvas::onDrawText(text, byte_length, x, y, paint);
-}
-
-void SimCanvas::onDrawPosText(const void* text,
- size_t byte_length,
- const SkPoint pos[],
- const SkPaint& paint) {
- DrawScope scope;
- AddCommand(CommandType::kText, paint.getColor());
- SkCanvas::onDrawPosText(text, byte_length, pos, paint);
-}
-
-void SimCanvas::onDrawPosTextH(const void* text,
- size_t byte_length,
- const SkScalar xpos[],
- SkScalar const_y,
- const SkPaint& paint) {
- DrawScope scope;
- AddCommand(CommandType::kText, paint.getColor());
- SkCanvas::onDrawPosTextH(text, byte_length, xpos, const_y, paint);
-}
-
void SimCanvas::onDrawTextBlob(const SkTextBlob* blob,
SkScalar x,
SkScalar y,
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h
index 4c40108a576..cf086d59a8d 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h
@@ -62,20 +62,6 @@ class SimCanvas : public SkCanvas {
SrcRectConstraint) override;
// Text
- void onDrawText(const void* text,
- size_t byte_length,
- SkScalar x,
- SkScalar y,
- const SkPaint&) override;
- void onDrawPosText(const void* text,
- size_t byte_length,
- const SkPoint pos[],
- const SkPaint&) override;
- void onDrawPosTextH(const void* text,
- size_t byte_length,
- const SkScalar xpos[],
- SkScalar const_y,
- const SkPaint&) override;
void onDrawTextBlob(const SkTextBlob*,
SkScalar x,
SkScalar y,
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
index becc31a0700..0affb2c7d69 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
@@ -29,11 +29,18 @@ SimCompositor::~SimCompositor() {
LocalFrameView::SetInitialTracksPaintInvalidationsForTesting(false);
}
-void SimCompositor::SetWebView(WebViewImpl& web_view,
- content::LayerTreeView& layer_tree_view) {
+void SimCompositor::SetWebView(
+ WebViewImpl& web_view,
+ content::LayerTreeView& layer_tree_view,
+ frame_test_helpers::TestWebViewClient& view_client,
+ frame_test_helpers::TestWebWidgetClient& widget_client) {
web_view_ = &web_view;
layer_tree_view_ = &layer_tree_view;
DCHECK_EQ(&layer_tree_view, web_view_->LayerTreeView());
+ test_web_view_client_ = &view_client;
+ DCHECK_EQ(test_web_view_client_, web_view_->Client());
+ test_web_widget_client_ = &widget_client;
+ DCHECK_EQ(test_web_widget_client_, web_view_->WidgetClient());
// SimCompositor starts with defer commits enabled, but uses synchronous
// compositing which does not use defer commits anyhow, it only uses it for
@@ -44,9 +51,13 @@ void SimCompositor::SetWebView(WebViewImpl& web_view,
SimCanvas::Commands SimCompositor::BeginFrame(double time_delta_in_seconds) {
DCHECK(web_view_);
DCHECK(!layer_tree_view_->layer_tree_host()->defer_main_frame_update());
- DCHECK(layer_tree_view_->layer_tree_host()->RequestedMainFramePending());
+ // Verify that the need for a BeginMainFrame has been registered, and would
+ // have caused the compositor to schedule one if we were using its scheduler.
+ DCHECK(NeedsBeginFrame());
DCHECK_GT(time_delta_in_seconds, 0);
+ test_web_widget_client_->ClearAnimationScheduled();
+
last_frame_time_ += base::TimeDelta::FromSecondsD(time_delta_in_seconds);
SimCanvas::Commands commands;
@@ -65,18 +76,19 @@ SimCanvas::Commands SimCompositor::PaintFrame() {
auto* frame = web_view_->MainFrameImpl()->GetFrame();
DocumentLifecycle::AllowThrottlingScope throttling_scope(
frame->GetDocument()->Lifecycle());
+ frame->View()->UpdateAllLifecyclePhases(DocumentLifecycle::kTest);
PaintRecordBuilder builder;
- auto infinite_rect = LayoutRect::InfiniteIntRect();
- frame->View()->Paint(builder.Context(), kGlobalPaintFlattenCompositingLayers,
- CullRect(infinite_rect));
+ frame->View()->PaintOutsideOfLifecycle(builder.Context(),
+ kGlobalPaintFlattenCompositingLayers);
+ auto infinite_rect = LayoutRect::InfiniteIntRect();
SimCanvas canvas(infinite_rect.Width(), infinite_rect.Height());
builder.EndRecording()->Playback(&canvas);
return canvas.GetCommands();
}
void SimCompositor::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
- web_view_->ApplyViewportChanges(args);
+ web_view_->MainFrameWidget()->ApplyViewportChanges(args);
}
void SimCompositor::RequestNewLayerTreeFrameSink(
@@ -89,7 +101,7 @@ void SimCompositor::RequestNewLayerTreeFrameSink(
void SimCompositor::BeginMainFrame(base::TimeTicks frame_time) {
// There is no WebWidget like RenderWidget would have..? So go right to the
// WebViewImpl.
- web_view_->BeginFrame(last_frame_time_);
+ web_view_->MainFrameWidget()->BeginFrame(last_frame_time_);
web_view_->MainFrameWidget()->UpdateAllLifecyclePhases(
WebWidget::LifecycleUpdateReason::kTest);
*paint_commands_ = PaintFrame();
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h
index 784300e12da..466733ea188 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h
@@ -7,7 +7,7 @@
#include "base/time/time.h"
#include "cc/trees/layer_tree_host.h"
-#include "content/renderer/gpu/layer_tree_view.h"
+#include "content/renderer/compositor/layer_tree_view.h"
#include "content/test/stub_layer_tree_view_delegate.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/testing/sim/sim_canvas.h"
@@ -39,7 +39,16 @@ class SimCompositor final : public content::StubLayerTreeViewDelegate {
// to composite the WebViewImpl is passed separately as the underlying
// content::LayerTreeView type, in order to bypass the Web* API surface
// provided to blink.
- void SetWebView(WebViewImpl&, content::LayerTreeView&);
+ // The WebWidget client is overridden (via the WebViewClient) to control
+ // BeginMainFrame scheduling since this test suite does not use the
+ // compositor's scheduler. The SimCompositor wants to monitor and verify
+ // expectations around this scheduling, so receives the WebViewClient. We
+ // pass it here explicitly to provide type safety, though it is the client
+ // available on the WebViewImpl as well.
+ void SetWebView(WebViewImpl&,
+ content::LayerTreeView&,
+ frame_test_helpers::TestWebViewClient&,
+ frame_test_helpers::TestWebWidgetClient&);
// Executes the BeginMainFrame processing steps, an approximation of what
// cc::ThreadProxy::BeginMainFrame would do.
@@ -57,9 +66,13 @@ class SimCompositor final : public content::StubLayerTreeViewDelegate {
// Helpers to query the state of the compositor from tests.
//
// Returns true if a main frame has been requested from blink, until the
- // BeginFrame() step occurs.
+ // BeginFrame() step occurs. The AnimationScheduled() checks if an explicit
+ // requet for BeginFrame() was made, vs an implicit one by making changes
+ // to the compositor's state.
bool NeedsBeginFrame() const {
- return layer_tree_view_->layer_tree_host()->RequestedMainFramePending();
+ cc::LayerTreeHost* layer_tree_host = layer_tree_view_->layer_tree_host();
+ return test_web_widget_client_->AnimationScheduled() ||
+ layer_tree_host->RequestedMainFramePendingForTesting();
}
// Returns true if commits are deferred in the compositor. Since these tests
// use synchronous compositing through BeginFrame(), the deferred state has no
@@ -87,14 +100,16 @@ class SimCompositor final : public content::StubLayerTreeViewDelegate {
void BeginMainFrame(base::TimeTicks frame_time) override;
WebViewImpl* web_view_ = nullptr;
+ content::LayerTreeView* layer_tree_view_ = nullptr;
+ frame_test_helpers::TestWebViewClient* test_web_view_client_ = nullptr;
+ frame_test_helpers::TestWebWidgetClient* test_web_widget_client_ = nullptr;
+
base::TimeTicks last_frame_time_;
// During BeginFrame(), painting is done, and the result is stored here to
// be returned from BeginFrame().
SimCanvas::Commands* paint_commands_;
- content::LayerTreeView* layer_tree_view_ = nullptr;
-
std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
scoped_defer_main_frame_update_;
};
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_network.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_network.cc
index 45df1df2fcb..22767b377c4 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_network.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_network.cc
@@ -41,7 +41,7 @@ void SimNetwork::ServePendingRequests() {
void SimNetwork::DidReceiveResponse(WebURLLoaderClient* client,
const WebURLResponse& response) {
- auto it = requests_.find(response.Url().GetString());
+ auto it = requests_.find(response.CurrentRequestUrl().GetString());
if (it == requests_.end()) {
client->DidReceiveResponse(response);
return;
@@ -86,12 +86,18 @@ void SimNetwork::DidFinishLoading(WebURLLoaderClient* client,
current_request_ = nullptr;
}
-void SimNetwork::AddRequest(SimRequest& request) {
- requests_.insert(request.Url(), &request);
+void SimNetwork::AddRequest(SimRequestBase& request) {
+ requests_.insert(request.url_.GetString(), &request);
+ WebURLResponse response(request.url_);
+ response.SetMIMEType(request.mime_type_);
+ response.SetHTTPStatusCode(200);
+ Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(request.url_,
+ response, "");
}
-void SimNetwork::RemoveRequest(SimRequest& request) {
- requests_.erase(request.Url());
+void SimNetwork::RemoveRequest(SimRequestBase& request) {
+ requests_.erase(request.url_);
+ Platform::Current()->GetURLLoaderMockFactory()->UnregisterURL(request.url_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_network.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_network.h
index aadd07b7dfe..bce0ac07522 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_network.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_network.h
@@ -13,26 +13,27 @@
namespace blink {
-class SimRequest;
+class SimRequestBase;
class WebURLLoaderClient;
class WebURLResponse;
// Simulates a network with precise flow control so you can make requests
// return, write data, and finish in a specific order in a unit test. One of
-// these must be created before using the SimRequest to issue requests.
+// these must be created before using the SimRequestBase to issue requests.
class SimNetwork final : public WebURLLoaderTestDelegate {
public:
SimNetwork();
~SimNetwork() override;
private:
- friend class SimRequest;
+ friend class SimRequestBase;
+ friend class SimSubresourceRequest;
static SimNetwork& Current();
void ServePendingRequests();
- void AddRequest(SimRequest&);
- void RemoveRequest(SimRequest&);
+ void AddRequest(SimRequestBase&);
+ void RemoveRequest(SimRequestBase&);
// WebURLLoaderTestDelegate
void DidReceiveResponse(WebURLLoaderClient*, const WebURLResponse&) override;
@@ -50,8 +51,8 @@ class SimNetwork final : public WebURLLoaderTestDelegate {
int64_t total_encoded_body_length,
int64_t total_decoded_body_length) override;
- SimRequest* current_request_;
- HashMap<String, SimRequest*> requests_;
+ SimRequestBase* current_request_;
+ HashMap<String, SimRequestBase*> requests_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_request.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_request.cc
index 29db248cf73..4d718251177 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_request.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_request.cc
@@ -4,65 +4,69 @@
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
-#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
-#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/core/testing/sim/sim_network.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
-SimRequest::SimRequest(String url, String mime_type)
+SimRequestBase::SimRequestBase(String url,
+ String mime_type,
+ bool start_immediately)
: url_(url),
+ mime_type_(mime_type),
+ start_immediately_(start_immediately),
+ started_(false),
client_(nullptr),
- total_encoded_data_length_(0),
- is_ready_(false) {
- KURL full_url(url);
- WebURLResponse response(full_url);
- response.SetMIMEType(mime_type);
- response.SetHTTPStatusCode(200);
- Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(full_url,
- response, "");
+ total_encoded_data_length_(0) {
SimNetwork::Current().AddRequest(*this);
}
-SimRequest::~SimRequest() {
- DCHECK(!is_ready_);
+SimRequestBase::~SimRequestBase() {
+ DCHECK(!client_);
}
-void SimRequest::DidReceiveResponse(WebURLLoaderClient* client,
- const WebURLResponse& response) {
+void SimRequestBase::DidReceiveResponse(WebURLLoaderClient* client,
+ const WebURLResponse& response) {
client_ = client;
response_ = response;
- is_ready_ = true;
+ started_ = false;
+ if (start_immediately_)
+ StartInternal();
}
-void SimRequest::DidFail(const WebURLError& error) {
+void SimRequestBase::DidFail(const WebURLError& error) {
error_ = error;
}
-void SimRequest::Start() {
- SimNetwork::Current().ServePendingRequests();
- DCHECK(is_ready_);
+void SimRequestBase::StartInternal() {
+ DCHECK(!started_);
+ started_ = true;
client_->DidReceiveResponse(response_);
}
-void SimRequest::Write(const String& data) {
- DCHECK(is_ready_);
+void SimRequestBase::Write(const String& data) {
+ if (!started_)
+ ServePending();
+ DCHECK(started_);
DCHECK(!error_);
total_encoded_data_length_ += data.length();
client_->DidReceiveData(data.Utf8().data(), data.length());
}
-void SimRequest::Write(const Vector<char>& data) {
- DCHECK(is_ready_);
+void SimRequestBase::Write(const Vector<char>& data) {
+ if (!started_)
+ ServePending();
+ DCHECK(started_);
DCHECK(!error_);
total_encoded_data_length_ += data.size();
client_->DidReceiveData(data.data(), data.size());
}
-void SimRequest::Finish() {
- DCHECK(is_ready_);
+void SimRequestBase::Finish() {
+ if (!started_)
+ ServePending();
+ DCHECK(started_);
if (error_) {
client_->DidFail(*error_, total_encoded_data_length_,
total_encoded_data_length_, total_encoded_data_length_);
@@ -76,26 +80,49 @@ void SimRequest::Finish() {
Reset();
}
-void SimRequest::Complete(const String& data) {
- Start();
+void SimRequestBase::Complete(const String& data) {
+ if (!started_)
+ ServePending();
+ if (!started_)
+ StartInternal();
if (!data.IsEmpty())
Write(data);
Finish();
}
-void SimRequest::Complete(const Vector<char>& data) {
- Start();
+void SimRequestBase::Complete(const Vector<char>& data) {
+ if (!started_)
+ ServePending();
+ if (!started_)
+ StartInternal();
if (!data.IsEmpty())
Write(data);
Finish();
}
-void SimRequest::Reset() {
- is_ready_ = false;
+void SimRequestBase::Reset() {
+ started_ = false;
client_ = nullptr;
- Platform::Current()->GetURLLoaderMockFactory()->UnregisterURL(KURL(url_));
-
SimNetwork::Current().RemoveRequest(*this);
}
+void SimRequestBase::ServePending() {
+ SimNetwork::Current().ServePendingRequests();
+}
+
+SimRequest::SimRequest(String url, String mime_type)
+ : SimRequestBase(url, mime_type, true /* start_immediately */) {}
+
+SimRequest::~SimRequest() = default;
+
+SimSubresourceRequest::SimSubresourceRequest(String url, String mime_type)
+ : SimRequestBase(url, mime_type, false /* start_immediately */) {}
+
+SimSubresourceRequest::~SimSubresourceRequest() = default;
+
+void SimSubresourceRequest::Start() {
+ ServePending();
+ StartInternal();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_request.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_request.h
index 073d0dccafe..e757460d5c0 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_request.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_request.h
@@ -8,6 +8,7 @@
#include "base/optional.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -17,18 +18,11 @@ class SimNetwork;
class WebURLLoaderClient;
// Simulates a single request for a resource from the server. Requires a
-// SimNetwork to have been created first. Use the start(), write() and finish()
-// methods to simulate the response from the server. Note that all started
-// requests must be finished.
-class SimRequest final {
+// SimNetwork to have been created first. Use the Write(), Finish() and
+// Complete() methods to simulate the response from the server.
+// Note that all requests must be finished.
+class SimRequestBase {
public:
- SimRequest(String url, String mime_type);
- ~SimRequest();
-
- // Starts the response from the server, this is as if the headers and 200 OK
- // reply had been received but no response body yet.
- void Start();
-
// Write a chunk of the response body.
void Write(const String& data);
void Write(const Vector<char>& data);
@@ -40,8 +34,12 @@ class SimRequest final {
void Complete(const String& data = String());
void Complete(const Vector<char>& data);
- const String& Url() const { return url_; }
- const WebURLResponse& GetResponse() const { return response_; }
+ protected:
+ SimRequestBase(String url, String mime_type, bool start_immediately);
+ ~SimRequestBase();
+
+ void StartInternal();
+ void ServePending();
private:
friend class SimNetwork;
@@ -52,12 +50,36 @@ class SimRequest final {
void DidReceiveResponse(WebURLLoaderClient*, const WebURLResponse&);
void DidFail(const WebURLError&);
- String url_;
+ KURL url_;
+ String mime_type_;
+ bool start_immediately_;
+ bool started_;
WebURLResponse response_;
base::Optional<WebURLError> error_;
WebURLLoaderClient* client_;
unsigned total_encoded_data_length_;
- bool is_ready_;
+};
+
+// This request can be used as a main resource request for navigation.
+// It does not allow starting asynchronously, because that's not how
+// navigations work in reality.
+// TODO(dgozman): rename this to SimNavigationRequest or something.
+class SimRequest final : public SimRequestBase {
+ public:
+ SimRequest(String url, String mime_type);
+ ~SimRequest();
+};
+
+// This request can be started asynchronously, suited for simulating
+// delayed load of subresources.
+class SimSubresourceRequest final : public SimRequestBase {
+ public:
+ SimSubresourceRequest(String url, String mime_type);
+ ~SimSubresourceRequest();
+
+ // Starts the response from the server, this is as if the headers and 200 OK
+ // reply had been received but no response body yet.
+ void Start();
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc
index ab8aff7cf46..3414e80c210 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/web_test_support.h"
@@ -18,11 +19,10 @@
namespace blink {
SimTest::SimTest()
- : web_frame_client_(*this),
- // SimCompositor overrides the LayerTreeViewDelegate to respond to
- // BeginMainFrame(), which will update and paint the WebViewImpl given to
- // SetWebView().
- web_view_client_(&compositor_) {
+ : // SimCompositor overrides the LayerTreeViewDelegate to respond to
+ // BeginMainFrame(), which will update and paint the main frame of the
+ // WebViewImpl given to SetWebView().
+ web_widget_client_(&compositor_) {
Document::SetThreadedParsingEnabledForTesting(false);
// Use the mock theme to get more predictable code paths, this also avoids
// the OS callbacks in ScrollAnimatorMac which can schedule frames
@@ -55,17 +55,22 @@ SimTest::~SimTest() {
void SimTest::SetUp() {
Test::SetUp();
- web_view_helper_.Initialize(&web_frame_client_, &web_view_client_);
- compositor_.SetWebView(WebView(), *web_view_client_.layer_tree_view());
+ web_view_helper_.Initialize(&web_frame_client_, &web_view_client_,
+ &web_widget_client_);
+ compositor_.SetWebView(WebView(), *web_widget_client_.layer_tree_view(),
+ web_view_client_, web_widget_client_);
page_.SetPage(WebView().GetPage());
}
-void SimTest::LoadURL(const String& url) {
- WebURLRequest request{KURL(url)};
- WebView().MainFrameImpl()->CommitNavigation(
- request, WebFrameLoadType::kStandard, WebHistoryItem(), false,
- base::UnguessableToken::Create(), nullptr /* navigation_params */,
- nullptr /* extra_data */);
+void SimTest::LoadURL(const String& url_string) {
+ KURL url(url_string);
+ frame_test_helpers::LoadFrameDontWait(WebView().MainFrameImpl(), url);
+ if (DocumentLoader::WillLoadUrlAsEmpty(url) || url.ProtocolIsData()) {
+ // Empty documents and data urls are not using mocked out SimRequests,
+ // but instead load data directly.
+ frame_test_helpers::PumpPendingRequestsForFrameToLoad(
+ WebView().MainFrameImpl());
+ }
}
LocalDOMWindow& SimTest::Window() {
@@ -88,22 +93,24 @@ WebLocalFrameImpl& SimTest::MainFrame() {
return *WebView().MainFrameImpl();
}
-const SimWebViewClient& SimTest::WebViewClient() const {
+frame_test_helpers::TestWebViewClient& SimTest::WebViewClient() {
return web_view_client_;
}
-SimCompositor& SimTest::Compositor() {
- return compositor_;
+frame_test_helpers::TestWebWidgetClient& SimTest::WebWidgetClient() {
+ return web_widget_client_;
+}
+
+frame_test_helpers::TestWebFrameClient& SimTest::WebFrameClient() {
+ return web_frame_client_;
}
-void SimTest::SetEffectiveConnectionTypeForTesting(
- WebEffectiveConnectionType effective_connection_type) {
- web_frame_client_.SetEffectiveConnectionTypeForTesting(
- effective_connection_type);
+SimCompositor& SimTest::Compositor() {
+ return compositor_;
}
-void SimTest::AddConsoleMessage(const String& message) {
- console_messages_.push_back(message);
+Vector<String>& SimTest::ConsoleMessages() {
+ return web_frame_client_.ConsoleMessages();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h
index 1d446c0bdad..fc3f6dc848c 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h
@@ -11,8 +11,6 @@
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_network.h"
#include "third_party/blink/renderer/core/testing/sim/sim_page.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_web_frame_client.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_web_view_client.h"
namespace blink {
@@ -38,26 +36,21 @@ class SimTest : public testing::Test {
Document& GetDocument();
WebViewImpl& WebView();
WebLocalFrameImpl& MainFrame();
- const SimWebViewClient& WebViewClient() const;
+ frame_test_helpers::TestWebViewClient& WebViewClient();
+ frame_test_helpers::TestWebWidgetClient& WebWidgetClient();
+ frame_test_helpers::TestWebFrameClient& WebFrameClient();
SimCompositor& Compositor();
- Vector<String>& ConsoleMessages() { return console_messages_; }
-
- void SetEffectiveConnectionTypeForTesting(WebEffectiveConnectionType);
+ Vector<String>& ConsoleMessages();
private:
- friend class SimWebFrameClient;
-
- void AddConsoleMessage(const String&);
-
SimNetwork network_;
SimCompositor compositor_;
- SimWebFrameClient web_frame_client_;
- SimWebViewClient web_view_client_;
+ frame_test_helpers::TestWebFrameClient web_frame_client_;
+ frame_test_helpers::TestWebWidgetClient web_widget_client_;
+ frame_test_helpers::TestWebViewClient web_view_client_;
SimPage page_;
frame_test_helpers::WebViewHelper web_view_helper_;
-
- Vector<String> console_messages_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.cc
deleted file mode 100644
index 9ede2eb44a9..00000000000
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.cc
+++ /dev/null
@@ -1,32 +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 "third_party/blink/renderer/core/testing/sim/sim_web_frame_client.h"
-
-#include "third_party/blink/public/web/web_console_message.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
-
-namespace blink {
-
-SimWebFrameClient::SimWebFrameClient(SimTest& test)
- : test_(&test),
- effective_connection_type_(WebEffectiveConnectionType::kTypeUnknown) {}
-
-void SimWebFrameClient::DidAddMessageToConsole(const WebConsoleMessage& message,
- const WebString& source_name,
- unsigned source_line,
- const WebString& stack_trace) {
- test_->AddConsoleMessage(message.text);
-}
-
-WebEffectiveConnectionType SimWebFrameClient::GetEffectiveConnectionType() {
- return effective_connection_type_;
-}
-
-void SimWebFrameClient::SetEffectiveConnectionTypeForTesting(
- WebEffectiveConnectionType effective_connection_type) {
- effective_connection_type_ = effective_connection_type;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.h
deleted file mode 100644
index c18530954fa..00000000000
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_client.h
+++ /dev/null
@@ -1,41 +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 THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_FRAME_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_FRAME_CLIENT_H_
-
-#include "third_party/blink/public/platform/web_effective_connection_type.h"
-#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
-#include "third_party/blink/renderer/core/testing/fake_web_plugin.h"
-
-namespace blink {
-
-class SimTest;
-
-class SimWebFrameClient final : public frame_test_helpers::TestWebFrameClient {
- public:
- explicit SimWebFrameClient(SimTest&);
-
- // WebLocalFrameClient overrides:
- void DidAddMessageToConsole(const WebConsoleMessage&,
- const WebString& source_name,
- unsigned source_line,
- const WebString& stack_trace) override;
-
- WebEffectiveConnectionType GetEffectiveConnectionType() override;
- void SetEffectiveConnectionTypeForTesting(
- WebEffectiveConnectionType) override;
-
- WebPlugin* CreatePlugin(const WebPluginParams& params) override {
- return new FakeWebPlugin(params);
- }
-
- private:
- SimTest* test_;
- WebEffectiveConnectionType effective_connection_type_;
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.cc
deleted file mode 100644
index f4d26638ed2..00000000000
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.cc
+++ /dev/null
@@ -1,40 +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 "third_party/blink/renderer/core/testing/sim/sim_web_view_client.h"
-
-#include "third_party/blink/public/web/web_local_frame.h"
-
-namespace blink {
-
-SimWebViewClient::SimWebViewClient(content::LayerTreeViewDelegate* delegate)
- : frame_test_helpers::TestWebViewClient(delegate) {}
-
-void SimWebViewClient::DidMeaningfulLayout(
- WebMeaningfulLayout meaningful_layout) {
- switch (meaningful_layout) {
- case WebMeaningfulLayout::kVisuallyNonEmpty:
- visually_non_empty_layout_count_++;
- break;
- case WebMeaningfulLayout::kFinishedParsing:
- finished_parsing_layout_count_++;
- break;
- case WebMeaningfulLayout::kFinishedLoading:
- finished_loading_layout_count_++;
- break;
- }
-}
-
-WebView* SimWebViewClient::CreateView(WebLocalFrame* opener,
- const WebURLRequest&,
- const WebWindowFeatures&,
- const WebString& name,
- WebNavigationPolicy,
- bool,
- WebSandboxFlags,
- const SessionStorageNamespaceId&) {
- return web_view_helper_.InitializeWithOpener(opener);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.h
deleted file mode 100644
index c38e6a7b735..00000000000
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_view_client.h
+++ /dev/null
@@ -1,49 +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 THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_VIEW_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_VIEW_CLIENT_H_
-
-#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
-
-namespace blink {
-
-class SimWebViewClient final : public frame_test_helpers::TestWebViewClient {
- public:
- explicit SimWebViewClient(content::LayerTreeViewDelegate* delegate);
-
- int VisuallyNonEmptyLayoutCount() const {
- return visually_non_empty_layout_count_;
- }
- int FinishedParsingLayoutCount() const {
- return finished_parsing_layout_count_;
- }
- int FinishedLoadingLayoutCount() const {
- return finished_loading_layout_count_;
- }
-
- // WebViewClient implementation.
- WebView* CreateView(WebLocalFrame* opener,
- const WebURLRequest&,
- const WebWindowFeatures&,
- const WebString& name,
- WebNavigationPolicy,
- bool,
- WebSandboxFlags,
- const SessionStorageNamespaceId&) override;
-
- private:
- // WebWidgetClient overrides.
- void DidMeaningfulLayout(WebMeaningfulLayout) override;
-
- int visually_non_empty_layout_count_ = 0;
- int finished_parsing_layout_count_ = 0;
- int finished_loading_layout_count_ = 0;
-
- frame_test_helpers::WebViewHelper web_view_helper_;
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc b/chromium/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
index 71933f2ffab..f8aca2875f8 100644
--- a/chromium/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
+++ b/chromium/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
@@ -92,7 +92,7 @@ void InstallOriginTrialFeaturesForTesting(
ExecutionContext* execution_context = ExecutionContext::From(script_state);
- if (type == &V8OriginTrialsTest::wrapper_type_info) {
+ if (type == V8OriginTrialsTest::GetWrapperTypeInfo()) {
if (origin_trials::OriginTrialsSampleAPIEnabled(execution_context)) {
V8OriginTrialsTest::InstallOriginTrialsSampleAPI(
script_state->GetIsolate(), script_state->World(),
@@ -136,7 +136,7 @@ void InstallPendingOriginTrialFeatureForTesting(
if (feature == origin_trials::kOriginTrialsSampleAPITrialName) {
if (script_state->PerContextData()
->GetExistingConstructorAndPrototypeForType(
- &V8OriginTrialsTest::wrapper_type_info, &prototype_object,
+ V8OriginTrialsTest::GetWrapperTypeInfo(), &prototype_object,
&interface_object)) {
V8OriginTrialsTest::InstallOriginTrialsSampleAPI(
script_state->GetIsolate(), script_state->World(),
@@ -147,7 +147,7 @@ void InstallPendingOriginTrialFeatureForTesting(
if (feature == origin_trials::kOriginTrialsSampleAPIImpliedTrialName) {
if (script_state->PerContextData()
->GetExistingConstructorAndPrototypeForType(
- &V8OriginTrialsTest::wrapper_type_info, &prototype_object,
+ V8OriginTrialsTest::GetWrapperTypeInfo(), &prototype_object,
&interface_object)) {
V8OriginTrialsTest::InstallOriginTrialsSampleAPIImplied(
script_state->GetIsolate(), script_state->World(),
diff --git a/chromium/third_party/blink/renderer/core/timing/event_timing.cc b/chromium/third_party/blink/renderer/core/timing/event_timing.cc
index bd694a31b2c..cca33b2a6ad 100644
--- a/chromium/third_party/blink/renderer/core/timing/event_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/event_timing.cc
@@ -35,21 +35,18 @@ void EventTiming::WillDispatchEvent(const Event& event) {
// we cannot assume that the conditions should still hold true in
// DidDispatchEvent. These conditions have to be re-tested before an entry is
// dispatched.
- if ((performance_->ShouldBufferEventTiming() &&
+ if ((performance_->ShouldBufferEntries() &&
!performance_->IsEventTimingBufferFull()) ||
- performance_->HasObserverFor(PerformanceEntry::kEvent)
- || (performance_->HasObserverFor(PerformanceEntry::kFirstInput)
- && !performance_->FirstInputDetected())) {
+ performance_->HasObserverFor(PerformanceEntry::kEvent) ||
+ !performance_->FirstInputDetected()) {
processing_start_ = CurrentTimeTicks();
finished_will_dispatch_event_ = true;
}
}
void EventTiming::DidDispatchEvent(const Event& event) {
- if (!finished_will_dispatch_event_ ||
- (!event.executedListenerOrDefaultAction() && !event.DefaultHandled())) {
+ if (!finished_will_dispatch_event_)
return;
- }
TimeTicks start_time;
if (event.IsPointerEvent())
diff --git a/chromium/third_party/blink/renderer/core/timing/memory_info.cc b/chromium/third_party/blink/renderer/core/timing/memory_info.cc
index 3c83c4480a6..ebb7951ba04 100644
--- a/chromium/third_party/blink/renderer/core/timing/memory_info.cc
+++ b/chromium/third_party/blink/renderer/core/timing/memory_info.cc
@@ -49,9 +49,15 @@ static constexpr TimeDelta kFiftyMs = TimeDelta::FromMilliseconds(50);
static void GetHeapSize(HeapInfo& info) {
v8::HeapStatistics heap_statistics;
v8::Isolate::GetCurrent()->GetHeapStatistics(&heap_statistics);
- info.used_js_heap_size = heap_statistics.used_heap_size();
- info.total_js_heap_size = heap_statistics.total_physical_size();
+ info.used_js_heap_size =
+ heap_statistics.used_heap_size() + heap_statistics.external_memory();
+ info.total_js_heap_size =
+ heap_statistics.total_physical_size() + heap_statistics.external_memory();
info.js_heap_size_limit = heap_statistics.heap_size_limit();
+ info.used_js_heap_size_without_external_memory =
+ heap_statistics.used_heap_size();
+ info.total_js_heap_size_without_external_memory =
+ heap_statistics.total_physical_size();
}
class HeapSizeCache {
@@ -96,6 +102,10 @@ class HeapSizeCache {
info_.used_js_heap_size = QuantizeMemorySize(info_.used_js_heap_size);
info_.total_js_heap_size = QuantizeMemorySize(info_.total_js_heap_size);
info_.js_heap_size_limit = QuantizeMemorySize(info_.js_heap_size_limit);
+ info_.used_js_heap_size_without_external_memory =
+ QuantizeMemorySize(info_.used_js_heap_size_without_external_memory);
+ info_.total_js_heap_size_without_external_memory =
+ QuantizeMemorySize(info_.total_js_heap_size_without_external_memory);
}
base::Optional<TimeTicks> last_update_time_;
diff --git a/chromium/third_party/blink/renderer/core/timing/memory_info.h b/chromium/third_party/blink/renderer/core/timing/memory_info.h
index ffd71db6c36..af93db28b90 100644
--- a/chromium/third_party/blink/renderer/core/timing/memory_info.h
+++ b/chromium/third_party/blink/renderer/core/timing/memory_info.h
@@ -40,12 +40,13 @@ namespace blink {
struct HeapInfo {
DISALLOW_NEW();
- HeapInfo()
- : used_js_heap_size(0), total_js_heap_size(0), js_heap_size_limit(0) {}
- size_t used_js_heap_size;
- size_t total_js_heap_size;
- size_t js_heap_size_limit;
+ size_t used_js_heap_size = 0;
+ size_t total_js_heap_size = 0;
+ size_t js_heap_size_limit = 0;
+ // Values for origin trial: "Legacy Performance Memory Counters".
+ size_t used_js_heap_size_without_external_memory = 0;
+ size_t total_js_heap_size_without_external_memory = 0;
};
class CORE_EXPORT MemoryInfo final : public ScriptWrappable {
@@ -66,6 +67,12 @@ class CORE_EXPORT MemoryInfo final : public ScriptWrappable {
size_t totalJSHeapSize() const { return info_.total_js_heap_size; }
size_t usedJSHeapSize() const { return info_.used_js_heap_size; }
size_t jsHeapSizeLimit() const { return info_.js_heap_size_limit; }
+ size_t usedJSHeapSizeWithoutExternalMemory() const {
+ return info_.used_js_heap_size_without_external_memory;
+ }
+ size_t totalJSHeapSizeWithoutExternalMemory() const {
+ return info_.total_js_heap_size_without_external_memory;
+ }
private:
HeapInfo info_;
diff --git a/chromium/third_party/blink/renderer/core/timing/memory_info.idl b/chromium/third_party/blink/renderer/core/timing/memory_info.idl
index dbbf246c38d..f3f531e69bc 100644
--- a/chromium/third_party/blink/renderer/core/timing/memory_info.idl
+++ b/chromium/third_party/blink/renderer/core/timing/memory_info.idl
@@ -37,4 +37,6 @@
[Measure] readonly attribute unsigned long long totalJSHeapSize;
[Measure] readonly attribute unsigned long long usedJSHeapSize;
[Measure] readonly attribute unsigned long long jsHeapSizeLimit;
+ [OriginTrialEnabled=LegacyPerformanceMemoryCounters] readonly attribute unsigned long long usedJSHeapSizeWithoutExternalMemory;
+ [OriginTrialEnabled=LegacyPerformanceMemoryCounters] readonly attribute unsigned long long totalJSHeapSizeWithoutExternalMemory;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.cc b/chromium/third_party/blink/renderer/core/timing/performance.cc
index 777788c818e..24a8129d30b 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance.cc
@@ -33,8 +33,7 @@
#include <algorithm>
#include "base/metrics/histogram_macros.h"
-#include "third_party/blink/renderer/bindings/core/v8/double_or_performance_mark_options.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_double_or_performance_measure_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/string_or_performance_measure_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_timing.h"
@@ -43,9 +42,12 @@
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/loader/document_load_timing.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/timing/performance_element_timing.h"
#include "third_party/blink/renderer/core/timing/performance_event_timing.h"
+#include "third_party/blink/renderer/core/timing/performance_layout_jank.h"
#include "third_party/blink/renderer/core/timing/performance_long_task_timing.h"
#include "third_party/blink/renderer/core/timing/performance_mark.h"
+#include "third_party/blink/renderer/core/timing/performance_mark_options.h"
#include "third_party/blink/renderer/core/timing/performance_measure.h"
#include "third_party/blink/renderer/core/timing/performance_measure_options.h"
#include "third_party/blink/renderer/core/timing/performance_observer.h"
@@ -130,32 +132,17 @@ Performance::MeasureParameterType StringToNavigationTimingParameterType(
}
Performance::MeasureParameterType StartOrOptionsToParameterType(
- const StringOrDoubleOrPerformanceMeasureOptions& start_or_options) {
+ const StringOrPerformanceMeasureOptions& start_or_options) {
if (start_or_options.IsString()) {
return StringToNavigationTimingParameterType(
start_or_options.GetAsString());
}
- if (start_or_options.IsDouble())
- return Performance::MeasureParameterType::kNumber;
+ // Since start_or_options cannot be number any more, we don't record number
+ // type as MeasureParameterType in UMA any more.
if (start_or_options.IsPerformanceMeasureOptions())
return Performance::MeasureParameterType::kObjectObject;
// null and undefined are undistinguishable in
- // StringOrDoubleOrPerformanceMeasureOptions.
- return Performance::MeasureParameterType::kUndefinedOrNull;
-}
-
-Performance::MeasureParameterType EndToParameterType(
- const StringOrDouble& end) {
- if (end.IsString()) {
- // When passing an object to |end|, the object will be implicitly converted
- // as the following string.
- if (end.GetAsString() == "[object Object]")
- return Performance::MeasureParameterType::kObjectObject;
- return StringToNavigationTimingParameterType(end.GetAsString());
- }
- if (end.IsDouble())
- return Performance::MeasureParameterType::kNumber;
- // null and undefined are undistinguishable in StringOrDouble.
+ // StringOrPerformanceMeasureOptions.
return Performance::MeasureParameterType::kUndefinedOrNull;
}
@@ -171,21 +158,28 @@ void LogMeasureEndToUma(Performance::MeasureParameterType type) {
using PerformanceObserverVector = HeapVector<Member<PerformanceObserver>>;
-static const size_t kDefaultResourceTimingBufferSize = 250;
+constexpr size_t kDefaultResourceTimingBufferSize = 250;
constexpr size_t kDefaultEventTimingBufferSize = 150;
+constexpr size_t kDefaultElementTimingBufferSize = 150;
+constexpr size_t kDefaultLayoutJankBufferSize = 150;
Performance::Performance(
TimeTicks time_origin,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : resource_timing_buffer_size_(kDefaultResourceTimingBufferSize),
+ : resource_timing_buffer_size_limit_(kDefaultResourceTimingBufferSize),
event_timing_buffer_max_size_(kDefaultEventTimingBufferSize),
+ element_timing_buffer_max_size_(kDefaultElementTimingBufferSize),
user_timing_(nullptr),
time_origin_(time_origin),
observer_filter_options_(PerformanceEntry::kInvalid),
- deliver_observations_timer_(std::move(task_runner),
+ task_runner_(std::move(task_runner)),
+ deliver_observations_timer_(task_runner_,
this,
- &Performance::DeliverObservationsTimerFired) {
-}
+ &Performance::DeliverObservationsTimerFired),
+ resource_timing_buffer_full_timer_(
+ task_runner_,
+ this,
+ &Performance::FireResourceTimingBufferFull) {}
Performance::~Performance() = default;
@@ -220,6 +214,8 @@ PerformanceEntryVector Performance::getEntries() {
entries.AppendVector(resource_timing_buffer_);
entries.AppendVector(event_timing_buffer_);
+ entries.AppendVector(element_timing_buffer_);
+ entries.AppendVector(layout_jank_buffer_);
if (first_input_timing_)
entries.push_back(first_input_timing_);
if (!navigation_timing_)
@@ -255,6 +251,12 @@ PerformanceEntryVector Performance::getEntriesByType(
for (const auto& resource : resource_timing_buffer_)
entries.push_back(resource);
break;
+ case PerformanceEntry::kElement:
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kElementTimingExplicitlyRequested);
+ for (const auto& element : element_timing_buffer_)
+ entries.push_back(element);
+ break;
case PerformanceEntry::kEvent:
UseCounter::Count(GetExecutionContext(),
WebFeature::kEventTimingExplicitlyRequested);
@@ -296,10 +298,11 @@ PerformanceEntryVector Performance::getEntriesByType(
break;
case PerformanceEntry::kTaskAttribution:
break;
- // TODO(npm): decide which element timing and layout jank entries are
- // accessible via the performance buffer.
- case PerformanceEntry::kElement:
case PerformanceEntry::kLayoutJank:
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kLayoutJankExplicitlyRequested);
+ for (const auto& layout_jank : layout_jank_buffer_)
+ entries.push_back(layout_jank);
break;
case PerformanceEntry::kInvalid:
break;
@@ -327,6 +330,27 @@ PerformanceEntryVector Performance::getEntriesByName(
}
}
+ if (entry_type.IsNull() || type == PerformanceEntry::kLayoutJank) {
+ for (const auto& layout_jank : layout_jank_buffer_) {
+ if (layout_jank->name() == name)
+ entries.push_back(layout_jank);
+ }
+ }
+ if (type == PerformanceEntry::kLayoutJank) {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kLayoutJankExplicitlyRequested);
+ }
+ if (entry_type.IsNull() || type == PerformanceEntry::kElement) {
+ for (const auto& element : element_timing_buffer_) {
+ if (element->name() == name)
+ entries.push_back(element);
+ }
+ }
+ if (type == PerformanceEntry::kElement) {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kElementTimingExplicitlyRequested);
+ }
+
if (entry_type.IsNull() || type == PerformanceEntry::kEvent) {
for (const auto& event : event_timing_buffer_) {
if (event->name() == name)
@@ -379,9 +403,7 @@ void Performance::clearResourceTimings() {
}
void Performance::setResourceTimingBufferSize(unsigned size) {
- resource_timing_buffer_size_ = size;
- if (IsResourceTimingBufferFull())
- DispatchEvent(*Event::Create(event_type_names::kResourcetimingbufferfull));
+ resource_timing_buffer_size_limit_ = size;
}
bool Performance::PassesTimingAllowCheck(
@@ -389,9 +411,7 @@ bool Performance::PassesTimingAllowCheck(
const SecurityOrigin& initiator_security_origin,
const AtomicString& original_timing_allow_origin,
ExecutionContext* context) {
- const KURL& response_url = response.WasFetchedViaServiceWorker()
- ? response.OriginalURLViaServiceWorker()
- : response.Url();
+ const KURL& response_url = response.ResponseUrl();
scoped_refptr<const SecurityOrigin> resource_origin =
SecurityOrigin::Create(response_url);
if (resource_origin->IsSameSchemeHostPort(&initiator_security_origin))
@@ -454,10 +474,6 @@ bool Performance::AllowsTimingRedirect(
void Performance::GenerateAndAddResourceTiming(
const ResourceTimingInfo& info,
const AtomicString& initiator_type) {
- if (IsResourceTimingBufferFull() &&
- !HasObserverFor(PerformanceEntry::kResource))
- return;
-
ExecutionContext* context = GetExecutionContext();
const SecurityOrigin* security_origin = GetSecurityOrigin(context);
if (!security_origin)
@@ -520,6 +536,8 @@ WebResourceTimingInfo Performance::GenerateResourceTiming(
result.encoded_body_size = final_response.EncodedBodyLength();
result.decoded_body_size = final_response.DecodedBodyLength();
result.did_reuse_connection = final_response.ConnectionReused();
+ result.is_secure_context =
+ SecurityOrigin::IsSecure(final_response.ResponseUrl());
result.allow_negative_values = info.NegativeAllowed();
if (result.allow_timing_details) {
@@ -535,15 +553,20 @@ WebResourceTimingInfo Performance::GenerateResourceTiming(
void Performance::AddResourceTiming(const WebResourceTimingInfo& info,
const AtomicString& initiator_type) {
- if (IsResourceTimingBufferFull() &&
- !HasObserverFor(PerformanceEntry::kResource))
- return;
-
PerformanceEntry* entry =
PerformanceResourceTiming::Create(info, time_origin_, initiator_type);
NotifyObserversOfEntry(*entry);
- if (!IsResourceTimingBufferFull())
- AddResourceTimingBuffer(*entry);
+ // https://w3c.github.io/resource-timing/#dfn-add-a-performanceresourcetiming-entry
+ if (CanAddResourceTimingEntry() &&
+ !resource_timing_buffer_full_event_pending_) {
+ resource_timing_buffer_.push_back(entry);
+ return;
+ }
+ if (!resource_timing_buffer_full_event_pending_) {
+ resource_timing_buffer_full_event_pending_ = true;
+ resource_timing_buffer_full_timer_.StartOneShot(TimeDelta(), FROM_HERE);
+ }
+ resource_timing_secondary_buffer_.push_back(entry);
}
// Called after loadEventEnd happens.
@@ -554,10 +577,50 @@ void Performance::NotifyNavigationTimingToObservers() {
NotifyObserversOfEntry(*navigation_timing_);
}
+bool Performance::IsElementTimingBufferFull() const {
+ return element_timing_buffer_.size() >= element_timing_buffer_max_size_;
+}
+
bool Performance::IsEventTimingBufferFull() const {
return event_timing_buffer_.size() >= event_timing_buffer_max_size_;
}
+void Performance::CopySecondaryBuffer() {
+ // https://w3c.github.io/resource-timing/#dfn-copy-secondary-buffer
+ while (resource_timing_secondary_buffer_.size() &&
+ CanAddResourceTimingEntry()) {
+ PerformanceEntry* entry = resource_timing_secondary_buffer_.front();
+ DCHECK(entry);
+ resource_timing_secondary_buffer_.pop_front();
+ resource_timing_buffer_.push_back(entry);
+ }
+}
+
+void Performance::FireResourceTimingBufferFull(TimerBase*) {
+ // https://w3c.github.io/resource-timing/#dfn-fire-a-buffer-full-event
+ while (resource_timing_secondary_buffer_.size()) {
+ int excess_entries_before = resource_timing_secondary_buffer_.size();
+ if (!CanAddResourceTimingEntry()) {
+ DispatchEvent(
+ *Event::Create(event_type_names::kResourcetimingbufferfull));
+ }
+ CopySecondaryBuffer();
+ int excess_entries_after = resource_timing_secondary_buffer_.size();
+ if (excess_entries_after >= excess_entries_before) {
+ resource_timing_secondary_buffer_.clear();
+ break;
+ }
+ }
+ resource_timing_buffer_full_event_pending_ = false;
+}
+
+void Performance::AddElementTimingBuffer(PerformanceElementTiming& entry) {
+ element_timing_buffer_.push_back(&entry);
+
+ if (IsElementTimingBufferFull())
+ DispatchEvent(*Event::Create(event_type_names::kElementtimingbufferfull));
+}
+
void Performance::AddEventTimingBuffer(PerformanceEventTiming& entry) {
event_timing_buffer_.push_back(&entry);
@@ -565,14 +628,36 @@ void Performance::AddEventTimingBuffer(PerformanceEventTiming& entry) {
DispatchEvent(*Event::Create(event_type_names::kEventtimingbufferfull));
}
+void Performance::AddLayoutJankBuffer(PerformanceLayoutJank& entry) {
+ if (layout_jank_buffer_.size() < kDefaultLayoutJankBufferSize)
+ layout_jank_buffer_.push_back(&entry);
+}
+
+unsigned Performance::ElementTimingBufferSize() const {
+ return element_timing_buffer_.size();
+}
+
unsigned Performance::EventTimingBufferSize() const {
return event_timing_buffer_.size();
}
+void Performance::clearElementTimings() {
+ element_timing_buffer_.clear();
+}
+
void Performance::clearEventTimings() {
event_timing_buffer_.clear();
}
+// TODO(crbug.com/72556): remove Element Timing buffering when shipping the
+// 'buffered' flag.
+void Performance::setElementTimingBufferMaxSize(unsigned size) {
+ element_timing_buffer_max_size_ = size;
+ if (IsElementTimingBufferFull())
+ DispatchEvent(*Event::Create(event_type_names::kElementtimingbufferfull));
+}
+
+// TODO(yoav): EventTiming should follow a simpler buffering model.
void Performance::setEventTimingBufferMaxSize(unsigned size) {
event_timing_buffer_max_size_ = size;
if (IsEventTimingBufferFull())
@@ -600,15 +685,9 @@ void Performance::AddPaintTiming(PerformancePaintTiming::PaintType type,
NotifyObserversOfEntry(*entry);
}
-void Performance::AddResourceTimingBuffer(PerformanceEntry& entry) {
- resource_timing_buffer_.push_back(&entry);
-
- if (IsResourceTimingBufferFull())
- DispatchEvent(*Event::Create(event_type_names::kResourcetimingbufferfull));
-}
-
-bool Performance::IsResourceTimingBufferFull() {
- return resource_timing_buffer_.size() >= resource_timing_buffer_size_;
+bool Performance::CanAddResourceTimingEntry() {
+ // https://w3c.github.io/resource-timing/#dfn-can-add-resource-timing-entry
+ return resource_timing_buffer_.size() < resource_timing_buffer_size_limit_;
}
void Performance::AddLongTaskTiming(
@@ -638,19 +717,17 @@ void Performance::AddLongTaskTiming(
PerformanceMark* Performance::mark(ScriptState* script_state,
const AtomicString& mark_name,
ExceptionState& exception_state) {
- DoubleOrPerformanceMarkOptions startOrOptions;
- return mark(script_state, mark_name, startOrOptions, exception_state);
+ return mark(script_state, mark_name, nullptr, exception_state);
}
-PerformanceMark* Performance::mark(
- ScriptState* script_state,
- const AtomicString& mark_name,
- DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
- ExceptionState& exception_state) {
+PerformanceMark* Performance::mark(ScriptState* script_state,
+ const AtomicString& mark_name,
+ PerformanceMarkOptions* mark_options,
+ ExceptionState& exception_state) {
if (!user_timing_)
user_timing_ = UserTiming::Create(*this);
PerformanceMark* performance_mark = user_timing_->Mark(
- script_state, mark_name, start_time_or_mark_options, exception_state);
+ script_state, mark_name, mark_options, exception_state);
if (performance_mark)
NotifyObserversOfEntry(*performance_mark);
if (RuntimeEnabledFeatures::CustomUserTimingEnabled())
@@ -671,32 +748,31 @@ PerformanceMeasure* Performance::measure(ScriptState* script_state,
LogMeasureEndToUma(MeasureParameterType::kUnprovided);
return MeasureInternal(
script_state, measure_name,
- NativeValueTraits<StringOrDoubleOrPerformanceMeasureOptions>::NullValue(),
- NativeValueTraits<StringOrDouble>::NullValue(), exception_state);
+ NativeValueTraits<StringOrPerformanceMeasureOptions>::NullValue(),
+ base::nullopt, exception_state);
}
PerformanceMeasure* Performance::measure(
ScriptState* script_state,
const AtomicString& measure_name,
- const StringOrDoubleOrPerformanceMeasureOptions& start_or_options,
+ const StringOrPerformanceMeasureOptions& start_or_options,
ExceptionState& exception_state) {
LogMeasureStartToUma(StartOrOptionsToParameterType(start_or_options));
LogMeasureEndToUma(MeasureParameterType::kUnprovided);
return MeasureInternal(script_state, measure_name, start_or_options,
- NativeValueTraits<StringOrDouble>::NullValue(),
- exception_state);
+ base::nullopt, exception_state);
}
PerformanceMeasure* Performance::measure(
ScriptState* script_state,
const AtomicString& measure_name,
- const StringOrDoubleOrPerformanceMeasureOptions& start_or_options,
- const StringOrDouble& end,
+ const StringOrPerformanceMeasureOptions& start_or_options,
+ const String& end,
ExceptionState& exception_state) {
LogMeasureStartToUma(StartOrOptionsToParameterType(start_or_options));
- LogMeasureEndToUma(EndToParameterType(end));
- return MeasureInternal(script_state, measure_name, start_or_options, end,
- exception_state);
+ LogMeasureEndToUma(StringToNavigationTimingParameterType(end));
+ return MeasureInternal(script_state, measure_name, start_or_options,
+ base::Optional<String>(end), exception_state);
}
// |start_or_options|: while in options type, the value is an object {start,
@@ -719,12 +795,13 @@ PerformanceMeasure* Performance::measure(
PerformanceMeasure* Performance::MeasureInternal(
ScriptState* script_state,
const AtomicString& measure_name,
- const StringOrDoubleOrPerformanceMeasureOptions& start_or_options,
- const StringOrDouble& end,
+ const StringOrPerformanceMeasureOptions& start_or_options,
+ base::Optional<String> end,
ExceptionState& exception_state) {
if (RuntimeEnabledFeatures::CustomUserTimingEnabled()) {
if (start_or_options.IsPerformanceMeasureOptions()) {
- if (!end.IsNull()) {
+ // measure("name", {}, *)
+ if (end) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"If a PerformanceMeasureOptions object was passed, |end| must be "
@@ -737,11 +814,9 @@ PerformanceMeasure* Performance::MeasureInternal(
options->endTime(), options->detail(),
exception_state);
} else {
+ // measure("name", "mark1", *)
StringOrDouble converted_start;
- if (start_or_options.IsDouble()) {
- converted_start =
- StringOrDouble::FromDouble(start_or_options.GetAsDouble());
- } else if (start_or_options.IsString()) {
+ if (start_or_options.IsString()) {
converted_start =
StringOrDouble::FromString(start_or_options.GetAsString());
} else {
@@ -750,9 +825,11 @@ PerformanceMeasure* Performance::MeasureInternal(
}
// We let |end| behave the same whether it's empty, undefined or null in
// JS, as long as |end| is null in C++.
- return MeasureWithDetail(script_state, measure_name, converted_start, end,
- ScriptValue::CreateNull(script_state),
- exception_state);
+ return MeasureWithDetail(
+ script_state, measure_name, converted_start,
+ end ? StringOrDouble::FromString(*end)
+ : NativeValueTraits<StringOrDouble>::NullValue(),
+ ScriptValue::CreateNull(script_state), exception_state);
}
} else {
// For consistency with UserTimingL2: the L2 API took |start| as a string,
@@ -761,9 +838,6 @@ PerformanceMeasure* Performance::MeasureInternal(
StringOrDouble converted_start;
if (start_or_options.IsPerformanceMeasureOptions()) {
converted_start = StringOrDouble::FromString("[object Object]");
- } else if (start_or_options.IsDouble()) {
- converted_start = StringOrDouble::FromString(
- String::NumberToStringECMAScript(start_or_options.GetAsDouble()));
} else if (start_or_options.IsString()) {
converted_start =
StringOrDouble::FromString(start_or_options.GetAsString());
@@ -772,19 +846,10 @@ PerformanceMeasure* Performance::MeasureInternal(
DCHECK(converted_start.IsNull());
}
- StringOrDouble converted_end;
- if (end.IsString()) {
- converted_end = StringOrDouble::FromString(end.GetAsString());
- } else if (end.IsDouble()) {
- converted_end = StringOrDouble::FromString(
- String::NumberToStringECMAScript(end.GetAsDouble()));
- } else {
- DCHECK(end.IsNull());
- DCHECK(converted_end.IsNull());
- }
MeasureWithDetail(script_state, measure_name, converted_start,
- converted_end, ScriptValue::CreateNull(script_state),
- exception_state);
+ end ? StringOrDouble::FromString(*end)
+ : NativeValueTraits<StringOrDouble>::NullValue(),
+ ScriptValue::CreateNull(script_state), exception_state);
// Return nullptr to distinguish from L3.
return nullptr;
}
@@ -938,7 +1003,10 @@ void Performance::BuildJSONValue(V8ObjectBuilder& builder) const {
void Performance::Trace(blink::Visitor* visitor) {
visitor->Trace(resource_timing_buffer_);
+ visitor->Trace(resource_timing_secondary_buffer_);
+ visitor->Trace(element_timing_buffer_);
visitor->Trace(event_timing_buffer_);
+ visitor->Trace(layout_jank_buffer_);
visitor->Trace(navigation_timing_);
visitor->Trace(user_timing_);
visitor->Trace(first_paint_timing_);
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.h b/chromium/third_party/blink/renderer/core/timing/performance.h
index 96344f02a0b..f4a1310341c 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance.h
@@ -53,26 +53,29 @@
namespace blink {
-class DoubleOrPerformanceMarkOptions;
+class PerformanceMarkOptions;
class ExceptionState;
class MemoryInfo;
-class PerformanceNavigation;
-class PerformanceObserver;
+class PerformanceElementTiming;
+class PerformanceEventTiming;
+class PerformanceLayoutJank;
class PerformanceMark;
class PerformanceMeasure;
+class PerformanceNavigation;
+class PerformanceObserver;
class PerformanceTiming;
class ResourceResponse;
class ResourceTimingInfo;
-class SecurityOrigin;
-class UserTiming;
class ScriptState;
class ScriptValue;
+class SecurityOrigin;
+class StringOrPerformanceMeasureOptions;
class SubTaskAttribution;
+class UserTiming;
class V8ObjectBuilder;
-class PerformanceEventTiming;
-class StringOrDoubleOrPerformanceMeasureOptions;
-using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>;
+using PerformanceEntryVector = HeapVector<TraceWrapperMember<PerformanceEntry>>;
+using PerformanceEntryDeque = HeapDeque<TraceWrapperMember<PerformanceEntry>>;
class CORE_EXPORT Performance : public EventTargetWithInlineData {
DEFINE_WRAPPERTYPEINFO();
@@ -147,7 +150,7 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
const ResourceTimingInfo&,
ExecutionContext& context_for_use_counter);
void AddResourceTiming(const WebResourceTimingInfo&,
- const AtomicString& initiator_type = g_null_atom);
+ const AtomicString& initiator_type);
void NotifyNavigationTimingToObservers();
@@ -155,6 +158,14 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
void AddFirstContentfulPaintTiming(TimeTicks start_time);
+ bool IsElementTimingBufferFull() const;
+ void AddElementTimingBuffer(PerformanceElementTiming&);
+ unsigned ElementTimingBufferSize() const;
+ void clearElementTimings();
+ void setElementTimingBufferMaxSize(unsigned);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(elementtimingbufferfull,
+ kElementtimingbufferfull);
+
bool IsEventTimingBufferFull() const;
void AddEventTimingBuffer(PerformanceEventTiming&);
unsigned EventTimingBufferSize() const;
@@ -163,15 +174,16 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
DEFINE_ATTRIBUTE_EVENT_LISTENER(eventtimingbufferfull,
kEventtimingbufferfull);
+ void AddLayoutJankBuffer(PerformanceLayoutJank&);
+
PerformanceMark* mark(ScriptState*,
const AtomicString& mark_name,
ExceptionState&);
- PerformanceMark* mark(
- ScriptState*,
- const AtomicString& mark_name,
- DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
- ExceptionState&);
+ PerformanceMark* mark(ScriptState*,
+ const AtomicString& mark_name,
+ PerformanceMarkOptions* mark_options,
+ ExceptionState&);
void clearMarks(const AtomicString& mark_name);
@@ -193,7 +205,8 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
kLoadEventEnd = 8,
kOther = 9,
kUndefinedOrNull = 10,
- kNumber = 11,
+ // Intentionally leaves out kNumber = 11 since number has been casted to
+ // string when users pass number into the API.
kUnprovided = 12,
kNavigationStart = 13,
kRedirectStart = 14,
@@ -218,14 +231,14 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
PerformanceMeasure* measure(
ScriptState*,
const AtomicString& measure_name,
- const StringOrDoubleOrPerformanceMeasureOptions& start_or_options,
+ const StringOrPerformanceMeasureOptions& start_or_options,
ExceptionState&);
PerformanceMeasure* measure(
ScriptState*,
const AtomicString& measure_name,
- const StringOrDoubleOrPerformanceMeasureOptions& start_or_options,
- const StringOrDouble& end,
+ const StringOrPerformanceMeasureOptions& start_or_options,
+ const String& end,
ExceptionState&);
void clearMeasures(const AtomicString& measure_name);
@@ -238,6 +251,12 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
bool HasObserverFor(PerformanceEntry::EntryType) const;
+ // TODO(npm): is the AtomicString parameter here actually needed?
+ static bool PassesTimingAllowCheck(const ResourceResponse&,
+ const SecurityOrigin&,
+ const AtomicString&,
+ ExecutionContext*);
+
static bool AllowsTimingRedirect(const Vector<ResourceResponse>&,
const ResourceResponse&,
const SecurityOrigin&,
@@ -248,18 +267,13 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
void Trace(blink::Visitor*) override;
private:
- static bool PassesTimingAllowCheck(const ResourceResponse&,
- const SecurityOrigin&,
- const AtomicString&,
- ExecutionContext*);
-
void AddPaintTiming(PerformancePaintTiming::PaintType, TimeTicks start_time);
PerformanceMeasure* MeasureInternal(
ScriptState*,
const AtomicString& measure_name,
- const StringOrDoubleOrPerformanceMeasureOptions& start,
- const StringOrDouble& end,
+ const StringOrPerformanceMeasureOptions& start,
+ base::Optional<String> end,
ExceptionState&);
PerformanceMeasure* MeasureWithDetail(ScriptState*,
@@ -269,6 +283,8 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
const ScriptValue& detail,
ExceptionState&);
+ void CopySecondaryBuffer();
+
protected:
Performance(TimeTicks time_origin,
scoped_refptr<base::SingleThreadTaskRunner>);
@@ -279,8 +295,8 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
return nullptr;
}
- bool IsResourceTimingBufferFull();
- void AddResourceTimingBuffer(PerformanceEntry&);
+ bool CanAddResourceTimingEntry();
+ void FireResourceTimingBufferFull(TimerBase*);
void NotifyObserversOfEntry(PerformanceEntry&) const;
void NotifyObserversOfEntries(PerformanceEntryVector&);
@@ -290,11 +306,20 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
virtual void BuildJSONValue(V8ObjectBuilder&) const;
PerformanceEntryVector resource_timing_buffer_;
- unsigned resource_timing_buffer_size_;
+ // The secondary RT buffer, used to store incoming entries after the main
+ // buffer is full, until the resourcetimingbufferfull event fires.
+ PerformanceEntryDeque resource_timing_secondary_buffer_;
+ unsigned resource_timing_buffer_size_limit_;
+ // A flag indicating that the buffer became full, the appropriate event was
+ // queued, but haven't yet fired.
+ bool resource_timing_buffer_full_event_pending_ = false;
PerformanceEntryVector event_timing_buffer_;
unsigned event_timing_buffer_max_size_;
+ PerformanceEntryVector element_timing_buffer_;
+ unsigned element_timing_buffer_max_size_;
+ PerformanceEntryVector layout_jank_buffer_;
Member<PerformanceEntry> navigation_timing_;
- Member<UserTiming> user_timing_;
+ TraceWrapperMember<UserTiming> user_timing_;
Member<PerformanceEntry> first_paint_timing_;
Member<PerformanceEntry> first_contentful_paint_timing_;
Member<PerformanceEventTiming> first_input_timing_;
@@ -305,7 +330,9 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
HeapLinkedHashSet<TraceWrapperMember<PerformanceObserver>> observers_;
HeapLinkedHashSet<Member<PerformanceObserver>> active_observers_;
HeapLinkedHashSet<Member<PerformanceObserver>> suspended_observers_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
TaskRunnerTimer<Performance> deliver_observations_timer_;
+ TaskRunnerTimer<Performance> resource_timing_buffer_full_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.idl b/chromium/third_party/blink/renderer/core/timing/performance.idl
index ae021aaaaae..29110432b60 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance.idl
@@ -51,6 +51,13 @@ interface Performance : EventTarget {
void setResourceTimingBufferSize(unsigned long maxSize);
attribute EventHandler onresourcetimingbufferfull;
+ // Element Timing
+ // https://github.com/npm1/Element-Timing
+ [MeasureAs=ElementTimingExplicitlyRequested, OriginTrialEnabled=ElementTiming] void clearElementTimings();
+ [MeasureAs=ElementTimingExplicitlyRequested, OriginTrialEnabled=ElementTiming] void setElementTimingBufferMaxSize(unsigned long maxSize);
+ [MeasureAs=ElementTimingExplicitlyRequested, OriginTrialEnabled=ElementTiming] attribute EventHandler onelementtimingbufferfull;
+
+
// Event Timing
// https://github.com/wicg/event-timing
[MeasureAs=PerformanceEventTimingBuffer, OriginTrialEnabled=EventTiming] void clearEventTimings();
@@ -65,21 +72,22 @@ interface Performance : EventTarget {
// User Timing
// https://w3c.github.io/user-timing/#extensions-performance-interface
// We use the returned value for feature detection:
- // * L2 API returns null.
+ // * L2 API returns null but this is a bug: crbug.com/914441.
// * L3 API returns the created entry.
[MeasureAs=UserTiming, CallWith=ScriptState, RaisesException] PerformanceMark? mark(DOMString markName);
- [MeasureAs=UserTiming, CallWith=ScriptState, RuntimeEnabled=CustomUserTiming, RaisesException] PerformanceMark? mark(DOMString markName, (DOMHighResTimeStamp or PerformanceMarkOptions) startTimeOrPerformanceMarkOptions);
+ // TODO(maxlg): PerformanceMarkOptions will be changed to optional after L3 is default to be enabled.
+ [MeasureAs=UserTiming, CallWith=ScriptState, RuntimeEnabled=CustomUserTiming, RaisesException] PerformanceMark? mark(DOMString markName, PerformanceMarkOptions markOptions);
[MeasureAs=UserTiming] void clearMarks(optional DOMString markName = null);
// Doing either of the following requires enabling CustomUserTiming:
// * passing PerformanceMeasureOptions to |startOrOptions|
// * passing timestamps to |startOrOptions| or |end|
// We use the returned value for feature detection:
- // * L2 API returns null.
+ // * L2 API returns null but this is a bug: crbug.com/914441.
// * L3 API returns the created entry.
// Custom User Timing (or User Timing L3) explainer:
// https://docs.google.com/document/d/1hltt8z9C4PaI5Qu1YMIp1wOGdbJPJPoJwBarEeCY6xQ/edit#heading=h.ejti6qhmjv0b
- [MeasureAs=UserTiming, CallWith=ScriptState, RaisesException] PerformanceMeasure? measure(DOMString measureName, optional (DOMString or DOMHighResTimeStamp or PerformanceMeasureOptions)? startOrOptions, optional (DOMString or DOMHighResTimeStamp)? end);
+ [MeasureAs=UserTiming, CallWith=ScriptState, RaisesException] PerformanceMeasure? measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions)? startOrOptions, optional DOMString end);
[MeasureAs=UserTiming] void clearMeasures(optional DOMString measureName = null);
// TODO(foolip): There is no spec for the Memory Info API, see blink-dev:
@@ -89,5 +97,5 @@ interface Performance : EventTarget {
// TODO(npm): This is an experimental attribute with no current plan to standardize. Remove once experiment has concluded. Only exposed to Window because we do not consider worker threads to contain high priority work.
[Exposed=Window, RuntimeEnabled=ExperimentalShouldYield] readonly attribute boolean shouldYield;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_element_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_element_timing.cc
index a2917af0760..0d74d8ef4d5 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_element_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_element_timing.cc
@@ -14,7 +14,8 @@ PerformanceElementTiming* PerformanceElementTiming::Create(
const AtomicString& name,
const IntRect& intersection_rect,
DOMHighResTimeStamp start_time) {
- return new PerformanceElementTiming(name, intersection_rect, start_time);
+ return MakeGarbageCollected<PerformanceElementTiming>(name, intersection_rect,
+ start_time);
}
PerformanceElementTiming::PerformanceElementTiming(
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_element_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_element_timing.h
index ca497b002af..35c0c91354c 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_element_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_element_timing.h
@@ -24,6 +24,9 @@ class CORE_EXPORT PerformanceElementTiming final : public PerformanceEntry {
const IntRect& intersection_rect,
DOMHighResTimeStamp start_time);
+ PerformanceElementTiming(const AtomicString& name,
+ const IntRect& intersection_rect,
+ DOMHighResTimeStamp start_time);
~PerformanceElementTiming() override;
AtomicString entryType() const override;
@@ -34,10 +37,6 @@ class CORE_EXPORT PerformanceElementTiming final : public PerformanceEntry {
void Trace(blink::Visitor*) override;
private:
- PerformanceElementTiming(const AtomicString& name,
- const IntRect& intersection_rect,
- DOMHighResTimeStamp start_time);
-
void BuildJSONValue(V8ObjectBuilder&) const override;
Member<DOMRectReadOnly> intersection_rect_;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_element_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_element_timing.idl
index 3e0bebb7f28..ef9982f5525 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_element_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_element_timing.idl
@@ -3,8 +3,10 @@
// found in the LICENSE file.
// https://docs.google.com/document/d/1blFeMVdqxB0V3BAJh60ptOBFY7cJSXnf7VyW3wspbZ8
-[RuntimeEnabled=ElementTiming]
+[OriginTrialEnabled=ElementTiming]
interface PerformanceElementTiming : PerformanceEntry {
readonly attribute DOMRectReadOnly intersectionRect;
- serializer = {inherit, attribute};
+
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_entry.idl b/chromium/third_party/blink/renderer/core/timing/performance_entry.idl
index 9432257041f..f20ea7b618d 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_entry.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_entry.idl
@@ -36,5 +36,5 @@ interface PerformanceEntry {
readonly attribute DOMString entryType;
readonly attribute DOMHighResTimeStamp startTime;
readonly attribute DOMHighResTimeStamp duration;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl
index 6bc00fb6446..ef577a5af70 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl
@@ -4,10 +4,13 @@
// https://github.com/wicg/event-timing
[
+ Exposed=Window,
OriginTrialEnabled=EventTiming
] interface PerformanceEventTiming : PerformanceEntry {
readonly attribute DOMHighResTimeStamp processingStart;
readonly attribute DOMHighResTimeStamp processingEnd;
readonly attribute boolean cancelable;
- serializer = {inherit, attribute};
+
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.cc b/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.cc
index 46344267703..1dce5236ad3 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.cc
@@ -12,7 +12,7 @@ namespace blink {
// static
PerformanceLayoutJank* PerformanceLayoutJank::Create(double fraction) {
- return new PerformanceLayoutJank(fraction);
+ return MakeGarbageCollected<PerformanceLayoutJank>(fraction);
}
PerformanceLayoutJank::PerformanceLayoutJank(double fraction)
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.h b/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.h
index 09751fb0fe5..4ff99271a2f 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.h
@@ -21,6 +21,7 @@ class CORE_EXPORT PerformanceLayoutJank final : public PerformanceEntry {
public:
static PerformanceLayoutJank* Create(double fraction);
+ PerformanceLayoutJank(double fraction);
~PerformanceLayoutJank() override;
AtomicString entryType() const override;
@@ -31,8 +32,6 @@ class CORE_EXPORT PerformanceLayoutJank final : public PerformanceEntry {
void Trace(blink::Visitor*) override;
private:
- PerformanceLayoutJank(double fraction);
-
void BuildJSONValue(V8ObjectBuilder&) const override;
double fraction_;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.idl b/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.idl
index 1d6f0752786..a50bfc4a3b1 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_layout_jank.idl
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://docs.google.com/document/d/1723wu4GZa8x8zSK0vb4NYg9xGtyVISEtGSGHcyL1tko/edit
-[RuntimeEnabled=LayoutJankAPI]
+// https://gist.github.com/skobes/2f296da1b0a88cc785a4bf10a42bca07
+[Exposed=Window, OriginTrialEnabled=LayoutJankAPI]
interface PerformanceLayoutJank : PerformanceEntry {
readonly attribute double fraction;
- serializer = {inherit, attribute};
+
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.idl
index d9017f7d377..10296dbd97f 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.idl
@@ -5,5 +5,7 @@
// https://w3c.github.io/longtasks/#sec-PerformanceLongTaskTiming
interface PerformanceLongTaskTiming : PerformanceEntry {
[SameObject, SaveSameObject] readonly attribute FrozenArray<TaskAttributionTiming> attribution;
- serializer = {inherit, attribute};
+
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation.idl b/chromium/third_party/blink/renderer/core/timing/performance_navigation.idl
index a516f3b4932..d87ffad6b21 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation.idl
@@ -41,5 +41,5 @@
const unsigned short TYPE_RESERVED = 255;
readonly attribute unsigned short type;
readonly attribute unsigned short redirectCount;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index 69bd24b4744..7a41bc3e514 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/timing/performance_navigation_timing.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_timing.h"
@@ -23,7 +22,8 @@ PerformanceNavigationTiming::PerformanceNavigationTiming(
TimeTicks time_origin,
const WebVector<WebServerTimingInfo>& server_timing)
: PerformanceResourceTiming(
- info ? AtomicString(info->FinalResponse().Url().GetString())
+ info ? AtomicString(
+ info->FinalResponse().CurrentRequestUrl().GetString())
: g_empty_atom,
time_origin,
server_timing),
@@ -99,10 +99,6 @@ unsigned long long PerformanceNavigationTiming::GetDecodedBodySize() const {
AtomicString PerformanceNavigationTiming::GetNavigationType(
WebNavigationType type,
const Document* document) {
- if (document && document->GetPageVisibilityState() ==
- mojom::PageVisibilityState::kPrerender) {
- return "prerender";
- }
switch (type) {
case kWebNavigationTypeReload:
return "reload";
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.idl
index 10c89e787d8..c61dcc86277 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.idl
@@ -23,5 +23,5 @@ enum NavigationType {
readonly attribute DOMHighResTimeStamp loadEventEnd;
readonly attribute NavigationType type;
readonly attribute unsigned short redirectCount;
- serializer = {inherit, attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_test.cc b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_test.cc
index 686ab54bfb4..c0ff332e3d5 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_test.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/core/timing/performance_navigation_timing.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
@@ -18,17 +17,12 @@ class PerformanceNavigationTimingTest : public PageTestBase {
};
TEST_F(PerformanceNavigationTimingTest, GetNavigationType) {
- GetPage().SetVisibilityState(mojom::PageVisibilityState::kPrerender, false);
+ GetPage().SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
AtomicString returned_type =
GetNavigationType(kWebNavigationTypeBackForward, &GetDocument());
- EXPECT_EQ(returned_type, "prerender");
-
- GetPage().SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
- returned_type =
- GetNavigationType(kWebNavigationTypeBackForward, &GetDocument());
EXPECT_EQ(returned_type, "back_forward");
- GetPage().SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
+ GetPage().SetIsHidden(/*is_hidden=*/false, /*initial_state=*/false);
returned_type =
GetNavigationType(kWebNavigationTypeFormResubmitted, &GetDocument());
EXPECT_EQ(returned_type, "navigate");
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer.cc b/chromium/third_party/blink/renderer/core/timing/performance_observer.cc
index 669310693dc..d3899254c65 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer.cc
@@ -11,6 +11,9 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
+#include "third_party/blink/renderer/core/performance_entry_names.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/performance_entry.h"
#include "third_party/blink/renderer/core/timing/performance_observer_entry_list.h"
@@ -47,6 +50,33 @@ PerformanceObserver* PerformanceObserver::Create(
return nullptr;
}
+// static
+Vector<AtomicString> PerformanceObserver::supportedEntryTypes(
+ ScriptState* script_state) {
+ // The list of supported types, in alphabetical order.
+ Vector<AtomicString> supportedEntryTypes;
+ auto* execution_context = ExecutionContext::From(script_state);
+ if (execution_context->IsDocument()) {
+ if (origin_trials::ElementTimingEnabled(execution_context))
+ supportedEntryTypes.push_back(performance_entry_names::kElement);
+ if (origin_trials::EventTimingEnabled(execution_context)) {
+ supportedEntryTypes.push_back(performance_entry_names::kEvent);
+ supportedEntryTypes.push_back(performance_entry_names::kFirstInput);
+ }
+ if (origin_trials::LayoutJankAPIEnabled(execution_context))
+ supportedEntryTypes.push_back(performance_entry_names::kLayoutJank);
+ supportedEntryTypes.push_back(performance_entry_names::kLongtask);
+ }
+ supportedEntryTypes.push_back(performance_entry_names::kMark);
+ supportedEntryTypes.push_back(performance_entry_names::kMeasure);
+ if (execution_context->IsDocument()) {
+ supportedEntryTypes.push_back(performance_entry_names::kNavigation);
+ supportedEntryTypes.push_back(performance_entry_names::kPaint);
+ }
+ supportedEntryTypes.push_back(performance_entry_names::kResource);
+ return supportedEntryTypes;
+}
+
PerformanceObserver::PerformanceObserver(
ExecutionContext* execution_context,
Performance* performance,
@@ -77,12 +107,18 @@ void PerformanceObserver::observe(const PerformanceObserverInit* observer_init,
}
}
if (entry_types == PerformanceEntry::kInvalid) {
- exception_state.ThrowTypeError(
+ String message =
"A Performance Observer MUST have at least one valid entryType in its "
- "entryTypes attribute.");
+ "entryTypes attribute.";
+ GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
+ kJSMessageSource, kWarningMessageLevel, message));
return;
}
filter_options_ = entry_types;
+ if (filter_options_ & PerformanceEntry::kLayoutJank) {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kLayoutJankExplicitlyRequested);
+ }
if (is_registered_)
performance_->UpdatePerformanceObserverFilterOptions();
else
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer.h b/chromium/third_party/blink/renderer/core/timing/performance_observer.h
index b23b07a7a4d..c104376ce64 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer.h
@@ -22,7 +22,7 @@ class PerformanceObserver;
class PerformanceObserverInit;
class V8PerformanceObserverCallback;
-using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>;
+using PerformanceEntryVector = HeapVector<TraceWrapperMember<PerformanceEntry>>;
class CORE_EXPORT PerformanceObserver final
: public ScriptWrappable,
@@ -37,7 +37,7 @@ class CORE_EXPORT PerformanceObserver final
public:
static PerformanceObserver* Create(ScriptState*,
V8PerformanceObserverCallback*);
- static void ResumeSuspendedObservers();
+ static Vector<AtomicString> supportedEntryTypes(ScriptState*);
PerformanceObserver(ExecutionContext*,
Performance*,
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer.idl b/chromium/third_party/blink/renderer/core/timing/performance_observer.idl
index c16e1a2e8cf..23e069db9cc 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer.idl
@@ -15,4 +15,5 @@ callback PerformanceObserverCallback = void (PerformanceObserverEntryList entrie
[RaisesException] void observe(PerformanceObserverInit options);
void disconnect();
PerformanceEntryList takeRecords();
+ [CallWith=ScriptState] static readonly attribute FrozenArray<DOMString> supportedEntryTypes;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.cc b/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.cc
index 61a622316c3..f24035559c8 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include "third_party/blink/renderer/core/timing/performance_entry.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.h b/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.h
index f7b6a54b484..bdc0aa7d0e2 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer_entry_list.h
@@ -13,7 +13,7 @@
namespace blink {
class PerformanceEntry;
-using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>;
+using PerformanceEntryVector = HeapVector<TraceWrapperMember<PerformanceEntry>>;
class PerformanceObserverEntryList : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.cc
index b80b0629e53..bb8cb0d3c4e 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.cc
@@ -72,6 +72,7 @@ PerformanceResourceTiming::PerformanceResourceTiming(
allow_timing_details_(info.allow_timing_details),
allow_redirect_details_(info.allow_redirect_details),
allow_negative_value_(info.allow_negative_values),
+ is_secure_context_(info.is_secure_context),
server_timing_(
PerformanceServerTiming::FromParsedServerTiming(info.server_timing)) {
}
@@ -255,12 +256,19 @@ DOMHighResTimeStamp PerformanceResourceTiming::connectEnd() const {
}
DOMHighResTimeStamp PerformanceResourceTiming::secureConnectionStart() const {
- if (!AllowTimingDetails())
+ if (!AllowTimingDetails() || !is_secure_context_)
return 0.0;
+
+ // Step 2 of
+ // https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-secureconnectionstart.
+ if (DidReuseConnection())
+ return fetchStart();
+
ResourceLoadTiming* timing = GetResourceLoadTiming();
- // SslStart will be zero when a secure connection is not negotiated.
- if (!timing || timing->SslStart().is_null())
+ if (!timing || timing->SslStart().is_null()) {
+ // TODO(yoav): add DCHECK or use counter to make sure this never happens.
return 0.0;
+ }
return Performance::MonotonicTimeToDOMHighResTimeStamp(
time_origin_, timing->SslStart(), allow_negative_value_);
@@ -284,10 +292,14 @@ DOMHighResTimeStamp PerformanceResourceTiming::responseStart() const {
if (!timing)
return requestStart();
- // FIXME: This number isn't exactly correct. See the notes in
- // PerformanceTiming::responseStart().
+ TimeTicks response_start = timing->ReceiveHeadersStart();
+ if (response_start.is_null())
+ response_start = timing->ReceiveHeadersEnd();
+ if (response_start.is_null())
+ return requestStart();
+
return Performance::MonotonicTimeToDOMHighResTimeStamp(
- time_origin_, timing->ReceiveHeadersEnd(), allow_negative_value_);
+ time_origin_, response_start, allow_negative_value_);
}
DOMHighResTimeStamp PerformanceResourceTiming::responseEnd() const {
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.h
index 919c4167cea..6057885ad3e 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.h
@@ -58,10 +58,9 @@ class CORE_EXPORT PerformanceResourceTiming : public PerformanceEntry {
TimeTicks time_origin,
const AtomicString& initiator_type);
~PerformanceResourceTiming() override;
- static PerformanceResourceTiming* Create(
- const WebResourceTimingInfo& info,
- TimeTicks time_origin,
- const AtomicString& initiator_type = g_null_atom) {
+ static PerformanceResourceTiming* Create(const WebResourceTimingInfo& info,
+ TimeTicks time_origin,
+ const AtomicString& initiator_type) {
return MakeGarbageCollected<PerformanceResourceTiming>(info, time_origin,
initiator_type);
}
@@ -127,6 +126,7 @@ class CORE_EXPORT PerformanceResourceTiming : public PerformanceEntry {
bool allow_timing_details_;
bool allow_redirect_details_;
bool allow_negative_value_;
+ bool is_secure_context_ = false;
HeapVector<Member<PerformanceServerTiming>> server_timing_;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.idl
index 068e2415d67..64cfd01542f 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_resource_timing.idl
@@ -50,5 +50,5 @@ interface PerformanceResourceTiming : PerformanceEntry {
[MeasureAs=PerformanceResourceTimingSizes] readonly attribute unsigned long long encodedBodySize;
[MeasureAs=PerformanceResourceTimingSizes] readonly attribute unsigned long long decodedBodySize;
readonly attribute FrozenArray<PerformanceServerTiming> serverTiming;
- serializer = {inherit, attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_server_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_server_timing.idl
index b5b34606b09..36e3c086990 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_server_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_server_timing.idl
@@ -10,5 +10,5 @@
readonly attribute DOMString name;
readonly attribute DOMHighResTimeStamp duration;
readonly attribute DOMString description;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_test.cc b/chromium/third_party/blink/renderer/core/timing/performance_test.cc
index 794d21431f0..76a8ef16c7a 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_test.cc
@@ -8,7 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_double.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_double_or_performance_measure_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/string_or_performance_measure_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_performance_observer_callback.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -201,10 +201,10 @@ TEST_F(PerformanceTest, MeasureParameters_StartProvidedEndUnprovided) {
DummyExceptionStateForTesting exception_state;
Initialize(scope.GetScriptState());
base_->measure(scope.GetScriptState(), "name",
- StringOrDoubleOrPerformanceMeasureOptions::FromDouble(1.1),
+ StringOrPerformanceMeasureOptions::FromString("string"),
exception_state);
histograms.ExpectBucketCount("Performance.MeasureParameter.StartMark",
- Performance::MeasureParameterType::kNumber, 1);
+ Performance::MeasureParameterType::kOther, 1);
histograms.ExpectBucketCount("Performance.MeasureParameter.EndMark",
Performance::MeasureParameterType::kUnprovided,
1);
@@ -216,12 +216,12 @@ TEST_F(PerformanceTest, MeasureParameters_StartEndBothProvided) {
DummyExceptionStateForTesting exception_state;
Initialize(scope.GetScriptState());
base_->measure(scope.GetScriptState(), "name",
- StringOrDoubleOrPerformanceMeasureOptions::FromDouble(1.1),
- StringOrDouble::FromDouble(1.1), exception_state);
+ StringOrPerformanceMeasureOptions::FromString("string"),
+ "string", exception_state);
histograms.ExpectBucketCount("Performance.MeasureParameter.StartMark",
- Performance::MeasureParameterType::kNumber, 1);
+ Performance::MeasureParameterType::kOther, 1);
histograms.ExpectBucketCount("Performance.MeasureParameter.EndMark",
- Performance::MeasureParameterType::kNumber, 1);
+ Performance::MeasureParameterType::kOther, 1);
}
TEST_F(PerformanceTest, MeasureParameters_ObjectType) {
@@ -231,7 +231,7 @@ TEST_F(PerformanceTest, MeasureParameters_ObjectType) {
Initialize(scope.GetScriptState());
base_->measure(
scope.GetScriptState(), "name",
- StringOrDoubleOrPerformanceMeasureOptions::FromPerformanceMeasureOptions(
+ StringOrPerformanceMeasureOptions::FromPerformanceMeasureOptions(
PerformanceMeasureOptions::Create()),
exception_state);
histograms.ExpectBucketCount("Performance.MeasureParameter.StartMark",
@@ -249,7 +249,7 @@ TEST_F(PerformanceTest, MeasureParameters_NavigationTiming) {
Initialize(scope.GetScriptState());
base_->measure(
scope.GetScriptState(), "name",
- StringOrDoubleOrPerformanceMeasureOptions::FromString("unloadEventStart"),
+ StringOrPerformanceMeasureOptions::FromString("unloadEventStart"),
exception_state);
histograms.ExpectBucketCount(
"Performance.MeasureParameter.StartMark",
@@ -264,10 +264,9 @@ TEST_F(PerformanceTest, MeasureParameters_Other) {
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
Initialize(scope.GetScriptState());
- base_->measure(
- scope.GetScriptState(), "name",
- StringOrDoubleOrPerformanceMeasureOptions::FromString("aRandomString"),
- exception_state);
+ base_->measure(scope.GetScriptState(), "name",
+ StringOrPerformanceMeasureOptions::FromString("aRandomString"),
+ exception_state);
histograms.ExpectBucketCount("Performance.MeasureParameter.StartMark",
Performance::MeasureParameterType::kOther, 1);
histograms.ExpectBucketCount("Performance.MeasureParameter.EndMark",
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
index 6df8d5123a4..d334819e09f 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/core/dom/document_parser_timing.h"
#include "third_party/blink/renderer/core/dom/document_timing.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/loader/document_load_timing.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
@@ -233,16 +234,16 @@ unsigned long long PerformanceTiming::requestStart() const {
unsigned long long PerformanceTiming::responseStart() const {
ResourceLoadTiming* timing = GetResourceLoadTiming();
- if (!timing || timing->ReceiveHeadersEnd().is_null())
+ if (!timing)
+ return requestStart();
+
+ TimeTicks response_start = timing->ReceiveHeadersStart();
+ if (response_start.is_null())
+ response_start = timing->ReceiveHeadersEnd();
+ if (response_start.is_null())
return requestStart();
- // FIXME: Response start needs to be the time of the first received byte.
- // However, the ResourceLoadTiming API currently only supports the time
- // the last header byte was received. For many responses with reasonable
- // sized cookies, the HTTP headers fit into a single packet so this time
- // is basically equivalent. But for some responses, particularly those with
- // headers larger than a single packet, this time will be too late.
- return MonotonicTimeToIntegerMilliseconds(timing->ReceiveHeadersEnd());
+ return MonotonicTimeToIntegerMilliseconds(response_start);
}
unsigned long long PerformanceTiming::responseEnd() const {
@@ -326,14 +327,6 @@ unsigned long long PerformanceTiming::FirstPaint() const {
return MonotonicTimeToIntegerMilliseconds(timing->FirstPaint());
}
-unsigned long long PerformanceTiming::FirstTextPaint() const {
- const PaintTiming* timing = GetPaintTiming();
- if (!timing)
- return 0;
-
- return MonotonicTimeToIntegerMilliseconds(timing->FirstTextPaint());
-}
-
unsigned long long PerformanceTiming::FirstImagePaint() const {
const PaintTiming* timing = GetPaintTiming();
if (!timing)
@@ -376,6 +369,15 @@ unsigned long long PerformanceTiming::LargestImagePaint() const {
paint_timing_detector->GetImagePaintTimingDetector().LargestImagePaint());
}
+uint64_t PerformanceTiming::LargestImagePaintSize() const {
+ PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
+ if (!paint_timing_detector)
+ return 0;
+
+ return paint_timing_detector->GetImagePaintTimingDetector()
+ .LargestImagePaintSize();
+}
+
unsigned long long PerformanceTiming::LastImagePaint() const {
PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
if (!paint_timing_detector)
@@ -385,6 +387,15 @@ unsigned long long PerformanceTiming::LastImagePaint() const {
paint_timing_detector->GetImagePaintTimingDetector().LastImagePaint());
}
+uint64_t PerformanceTiming::LastImagePaintSize() const {
+ PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
+ if (!paint_timing_detector)
+ return 0;
+
+ return paint_timing_detector->GetImagePaintTimingDetector()
+ .LastImagePaintSize();
+}
+
unsigned long long PerformanceTiming::LargestTextPaint() const {
PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
if (!paint_timing_detector)
@@ -394,6 +405,15 @@ unsigned long long PerformanceTiming::LargestTextPaint() const {
paint_timing_detector->GetTextPaintTimingDetector().LargestTextPaint());
}
+uint64_t PerformanceTiming::LargestTextPaintSize() const {
+ PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
+ if (!paint_timing_detector)
+ return 0;
+
+ return paint_timing_detector->GetTextPaintTimingDetector()
+ .LargestTextPaintSize();
+}
+
unsigned long long PerformanceTiming::LastTextPaint() const {
PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
if (!paint_timing_detector)
@@ -403,6 +423,15 @@ unsigned long long PerformanceTiming::LastTextPaint() const {
paint_timing_detector->GetTextPaintTimingDetector().LastTextPaint());
}
+uint64_t PerformanceTiming::LastTextPaintSize() const {
+ PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
+ if (!paint_timing_detector)
+ return 0;
+
+ return paint_timing_detector->GetTextPaintTimingDetector()
+ .LastTextPaintSize();
+}
+
unsigned long long PerformanceTiming::PageInteractive() const {
InteractiveDetector* interactive_detector = GetInteractiveDetector();
if (!interactive_detector)
@@ -598,6 +627,13 @@ PaintTimingDetector* PerformanceTiming::GetPaintTimingDetector() const {
return &view->GetPaintTimingDetector();
}
+std::unique_ptr<TracedValue> PerformanceTiming::GetNavigationTracingData() {
+ std::unique_ptr<TracedValue> data = TracedValue::Create();
+ data->SetString("navigationId",
+ IdentifiersFactory::LoaderId(GetDocumentLoader()));
+ return data;
+}
+
ScriptValue PerformanceTiming::toJSONForBinding(
ScriptState* script_state) const {
V8ObjectBuilder result(script_state);
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_timing.h
index 3fdb85a9478..d8b4fd4c1f3 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.h
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
@@ -94,8 +95,6 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
unsigned long long FirstLayout() const;
// The time the first paint operation was performed.
unsigned long long FirstPaint() const;
- // The time the first paint operation for visible text was performed.
- unsigned long long FirstTextPaint() const;
// The time the first paint operation for image was performed.
unsigned long long FirstImagePaint() const;
// The time of the first 'contentful' paint. A contentful paint is a paint
@@ -111,16 +110,27 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
// TODO(crbug.com/848639): This function is exposed as an experiment, and if
// not useful, this function can be removed.
unsigned long long FirstMeaningfulPaintCandidate() const;
- // The time of the first paint after the largest image within viewport being
- // fully loaded.
+ // Largest Image Paint is the first paint after the largest image within
+ // viewport being fully loaded. LargestImagePaint and LargestImagePaintSize
+ // are the time and size of it.
unsigned long long LargestImagePaint() const;
- // The time of the first paint after the last image within viewport being
- // fully loaded.
+ uint64_t LargestImagePaintSize() const;
+ // Last Image Paint is the first paint after the last image within viewport
+ // being fully loaded. LastImagePaint and LastImagePaintSize are the time and
+ // size of it.
unsigned long long LastImagePaint() const;
+ uint64_t LastImagePaintSize() const;
// The time of the first paint of the largest text within viewport.
+ // Largest Text Paint is the first paint after the largest text within
+ // viewport being painted. LargestTextPaint and LargestTextPaintSize
+ // are the time and size of it.
unsigned long long LargestTextPaint() const;
- // The time of the first paint of the last text within viewport.
+ uint64_t LargestTextPaintSize() const;
+ // Last Text Paint is the first paint after the last text within viewport
+ // being painted. LastTextPaint and LastTextPaintSize are the time and
+ // size of it.
unsigned long long LastTextPaint() const;
+ uint64_t LastTextPaintSize() const;
// The first time the page is considered 'interactive'. This is determined
// using heuristics based on main thread and network activity.
unsigned long long PageInteractive() const;
@@ -157,6 +167,8 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
unsigned long long MonotonicTimeToIntegerMilliseconds(TimeTicks) const;
+ std::unique_ptr<TracedValue> GetNavigationTracingData();
+
private:
const DocumentTiming* GetDocumentTiming() const;
const CSSTiming* CssTiming() const;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_timing.idl
index cefa9ed61cf..ac2138bdb81 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.idl
@@ -56,5 +56,5 @@
readonly attribute unsigned long long domComplete;
readonly attribute unsigned long long loadEventStart;
readonly attribute unsigned long long loadEventEnd;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
index 82e9b3a6295..efec9b14eee 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -26,9 +26,9 @@
#include "third_party/blink/renderer/core/timing/performance_user_timing.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/double_or_performance_mark_options.h"
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/core/timing/performance_mark.h"
+#include "third_party/blink/renderer/core/timing/performance_mark_options.h"
#include "third_party/blink/renderer/core/timing/performance_measure.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/histogram.h"
@@ -100,30 +100,24 @@ static void ClearPeformanceEntries(PerformanceEntryMap& performance_entry_map,
performance_entry_map.erase(name);
}
-PerformanceMark* UserTiming::Mark(
- ScriptState* script_state,
- const AtomicString& mark_name,
- DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
- ExceptionState& exception_state) {
+PerformanceMark* UserTiming::Mark(ScriptState* script_state,
+ const AtomicString& mark_name,
+ PerformanceMarkOptions* mark_options,
+ ExceptionState& exception_state) {
if (!RuntimeEnabledFeatures::CustomUserTimingEnabled())
- DCHECK(start_time_or_mark_options.IsNull());
+ DCHECK(!mark_options);
DOMHighResTimeStamp start = 0.0;
- if (start_time_or_mark_options.IsDouble()) {
- start = start_time_or_mark_options.GetAsDouble();
- } else if (start_time_or_mark_options.IsPerformanceMarkOptions() &&
- start_time_or_mark_options.GetAsPerformanceMarkOptions()
- ->hasStartTime()) {
- start =
- start_time_or_mark_options.GetAsPerformanceMarkOptions()->startTime();
+ if (mark_options && mark_options->hasStartTime()) {
+ start = mark_options->startTime();
} else {
start = performance_->now();
}
// Pass in a null ScriptValue if the mark's detail doesn't exist.
ScriptValue detail = ScriptValue::CreateNull(script_state);
- if (start_time_or_mark_options.IsPerformanceMarkOptions())
- detail = start_time_or_mark_options.GetAsPerformanceMarkOptions()->detail();
+ if (mark_options)
+ detail = mark_options->detail();
return MarkInternal(script_state, mark_name, start, detail, exception_state);
}
@@ -133,7 +127,11 @@ PerformanceMark* UserTiming::MarkInternal(ScriptState* script_state,
const DOMHighResTimeStamp& start_time,
const ScriptValue& detail,
ExceptionState& exception_state) {
- if (GetRestrictedKeyMap().Contains(mark_name)) {
+ DCHECK(performance_);
+ bool is_worker_global_scope =
+ performance_->GetExecutionContext() &&
+ performance_->GetExecutionContext()->IsWorkerGlobalScope();
+ if (!is_worker_global_scope && GetRestrictedKeyMap().Contains(mark_name)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"'" + mark_name +
@@ -142,7 +140,12 @@ PerformanceMark* UserTiming::MarkInternal(ScriptState* script_state,
return nullptr;
}
- TRACE_EVENT_COPY_MARK("blink.user_timing", mark_name.Utf8().data());
+ if (performance_->timing()) {
+ TRACE_EVENT_COPY_MARK1("blink.user_timing", mark_name.Utf8().data(), "data",
+ performance_->timing()->GetNavigationTracingData());
+ } else {
+ TRACE_EVENT_COPY_MARK("blink.user_timing", mark_name.Utf8().data());
+ }
PerformanceMark* mark =
PerformanceMark::Create(script_state, mark_name, start_time, detail);
InsertPerformanceEntry(marks_map_, *mark);
@@ -183,16 +186,14 @@ double UserTiming::FindExistingMarkStartTime(const AtomicString& mark_name,
return 0.0;
}
-double UserTiming::FindStartMarkOrTime(const StringOrDouble& start,
- ExceptionState& exception_state) {
- if (start.IsString()) {
- return FindExistingMarkStartTime(AtomicString(start.GetAsString()),
+double UserTiming::GetTimeOrFindMarkTime(const StringOrDouble& mark_or_time,
+ ExceptionState& exception_state) {
+ if (mark_or_time.IsString()) {
+ return FindExistingMarkStartTime(AtomicString(mark_or_time.GetAsString()),
exception_state);
}
- if (start.IsDouble())
- return start.GetAsDouble();
- NOTREACHED();
- return 0;
+ DCHECK(mark_or_time.IsDouble());
+ return mark_or_time.GetAsDouble();
}
PerformanceMeasure* UserTiming::Measure(ScriptState* script_state,
@@ -201,24 +202,15 @@ PerformanceMeasure* UserTiming::Measure(ScriptState* script_state,
const StringOrDouble& end,
const ScriptValue& detail,
ExceptionState& exception_state) {
- double start_time = 0.0;
- double end_time = 0.0;
-
- if (start.IsNull()) {
- end_time = performance_->now();
- } else if (end.IsNull()) {
- end_time = performance_->now();
- start_time = FindStartMarkOrTime(start, exception_state);
- if (exception_state.HadException())
- return nullptr;
- } else {
- end_time = FindStartMarkOrTime(end, exception_state);
- if (exception_state.HadException())
- return nullptr;
- start_time = FindStartMarkOrTime(start, exception_state);
- if (exception_state.HadException())
- return nullptr;
- }
+ double start_time =
+ start.IsNull() ? 0.0 : GetTimeOrFindMarkTime(start, exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ double end_time = end.IsNull() ? performance_->now()
+ : GetTimeOrFindMarkTime(end, exception_state);
+ if (exception_state.HadException())
+ return nullptr;
// User timing events are stored as integer milliseconds from the start of
// navigation, whereas trace events accept double seconds based off of
@@ -226,14 +218,15 @@ PerformanceMeasure* UserTiming::Measure(ScriptState* script_state,
double start_time_monotonic =
performance_->GetTimeOrigin() + start_time / 1000.0;
double end_time_monotonic = performance_->GetTimeOrigin() + end_time / 1000.0;
+ unsigned hash = WTF::StringHash::GetHash(measure_name);
+ WTF::AddFloatToHash(hash, start_time);
+ WTF::AddFloatToHash(hash, end_time);
TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
- "blink.user_timing", measure_name.Utf8().data(),
- WTF::StringHash::GetHash(measure_name),
+ "blink.user_timing", measure_name.Utf8().data(), hash,
trace_event::ToTraceTimestamp(start_time_monotonic));
TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
- "blink.user_timing", measure_name.Utf8().data(),
- WTF::StringHash::GetHash(measure_name),
+ "blink.user_timing", measure_name.Utf8().data(), hash,
trace_event::ToTraceTimestamp(end_time_monotonic));
PerformanceMeasure* measure = PerformanceMeasure::Create(
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h
index 98e0b6728d3..c78ed095fb2 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h
@@ -49,11 +49,10 @@ class UserTiming final : public GarbageCollected<UserTiming> {
explicit UserTiming(Performance&);
- PerformanceMark* Mark(
- ScriptState* script_state,
- const AtomicString& mark_name,
- DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
- ExceptionState& exception_state);
+ PerformanceMark* Mark(ScriptState* script_state,
+ const AtomicString& mark_name,
+ PerformanceMarkOptions* mark_options,
+ ExceptionState& exception_state);
void ClearMarks(const AtomicString& mark_name);
@@ -81,7 +80,8 @@ class UserTiming final : public GarbageCollected<UserTiming> {
ExceptionState&);
double FindExistingMarkStartTime(const AtomicString& mark_name,
ExceptionState&);
- double FindStartMarkOrTime(const StringOrDouble& start, ExceptionState&);
+ double GetTimeOrFindMarkTime(const StringOrDouble& mark_or_time,
+ ExceptionState&);
Member<Performance> performance_;
PerformanceEntryMap marks_map_;
diff --git a/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.idl b/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.idl
index 27109b6300c..f1684d5eed1 100644
--- a/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.idl
@@ -9,5 +9,7 @@ interface TaskAttributionTiming : PerformanceEntry {
readonly attribute DOMString containerSrc;
readonly attribute DOMString containerId;
readonly attribute DOMString containerName;
- serializer = {inherit, attribute};
+
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.cc b/chromium/third_party/blink/renderer/core/timing/window_performance.cc
index 9004cc77168..6adbb7ac66e 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.cc
@@ -327,9 +327,9 @@ void WindowPerformance::ReportLongTask(
}
}
-// We buffer long-latency events until onload, i.e., LoadEventStart is not
-// reached yet.
-bool WindowPerformance::ShouldBufferEventTiming() {
+// We buffer Element Timing and Event Timing (long-latency events) entries until
+// onload, i.e., LoadEventStart is not reached yet.
+bool WindowPerformance::ShouldBufferEntries() {
return !timing() || !timing()->loadEventStart();
}
@@ -340,7 +340,7 @@ void WindowPerformance::RegisterEventTiming(const AtomicString& event_type,
bool cancelable) {
DCHECK(origin_trials::EventTimingEnabled(GetExecutionContext()));
- DCHECK(!start_time.is_null());
+ // |start_time| could be null in some tests that inject input.
DCHECK(!processing_start.is_null());
DCHECK(!processing_end.is_null());
DCHECK_GE(processing_end, processing_start);
@@ -374,7 +374,7 @@ void WindowPerformance::ReportEventTimings(WebLayerTreeView::SwapResult result,
for (const auto& entry : event_timings_) {
int duration_in_ms = std::ceil((end_time - entry->startTime()) / 8) * 8;
entry->SetDuration(duration_in_ms);
- if (!first_input_detected_) {
+ if (!first_input_timing_) {
if (entry->name() == "pointerdown") {
first_pointer_down_event_timing_ =
PerformanceEventTiming::CreateFirstInputTiming(entry);
@@ -395,7 +395,7 @@ void WindowPerformance::ReportEventTimings(WebLayerTreeView::SwapResult result,
NotifyObserversOfEntry(*entry);
}
- if (ShouldBufferEventTiming() && !IsEventTimingBufferFull())
+ if (ShouldBufferEntries() && !IsEventTimingBufferFull())
AddEventTimingBuffer(*entry);
}
event_timings_.clear();
@@ -404,16 +404,21 @@ void WindowPerformance::ReportEventTimings(WebLayerTreeView::SwapResult result,
void WindowPerformance::AddElementTiming(const AtomicString& name,
const IntRect& rect,
TimeTicks timestamp) {
- DCHECK(RuntimeEnabledFeatures::ElementTimingEnabled());
- PerformanceEntry* entry = PerformanceElementTiming::Create(
+ DCHECK(origin_trials::ElementTimingEnabled(GetExecutionContext()));
+ PerformanceElementTiming* entry = PerformanceElementTiming::Create(
name, rect, MonotonicTimeToDOMHighResTimeStamp(timestamp));
- NotifyObserversOfEntry(*entry);
+ if (HasObserverFor(PerformanceEntry::kElement)) {
+ UseCounter::Count(GetFrame(),
+ WebFeature::kElementTimingExplicitlyRequested);
+ NotifyObserversOfEntry(*entry);
+ }
+ if (ShouldBufferEntries() && !IsElementTimingBufferFull())
+ AddElementTimingBuffer(*entry);
}
void WindowPerformance::DispatchFirstInputTiming(
PerformanceEventTiming* entry) {
DCHECK(origin_trials::EventTimingEnabled(GetExecutionContext()));
- first_input_detected_ = true;
if (!entry)
return;
@@ -424,14 +429,16 @@ void WindowPerformance::DispatchFirstInputTiming(
}
DCHECK(!first_input_timing_);
- if (ShouldBufferEventTiming())
- first_input_timing_ = entry;
+ first_input_timing_ = entry;
}
void WindowPerformance::AddLayoutJankFraction(double jank_fraction) {
- DCHECK(RuntimeEnabledFeatures::LayoutJankAPIEnabled());
- PerformanceEntry* entry = PerformanceLayoutJank::Create(jank_fraction);
- NotifyObserversOfEntry(*entry);
+ DCHECK(origin_trials::LayoutJankAPIEnabled(GetExecutionContext()));
+ PerformanceLayoutJank* entry = PerformanceLayoutJank::Create(jank_fraction);
+ if (HasObserverFor(PerformanceEntry::kLayoutJank))
+ NotifyObserversOfEntry(*entry);
+ if (ShouldBufferEntries())
+ AddLayoutJankBuffer(*entry);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.h b/chromium/third_party/blink/renderer/core/timing/window_performance.h
index 086795e57aa..0d23bad5cef 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.h
@@ -69,9 +69,9 @@ class CORE_EXPORT WindowPerformance final : public Performance,
void UpdateLongTaskInstrumentation() override;
- bool ShouldBufferEventTiming();
+ bool ShouldBufferEntries();
- bool FirstInputDetected() const { return first_input_detected_; }
+ bool FirstInputDetected() const { return !!first_input_timing_; }
// This method creates a PerformanceEventTiming and if needed creates a swap
// promise to calculate the |duration| attribute when such promise is
@@ -119,10 +119,6 @@ class CORE_EXPORT WindowPerformance final : public Performance,
// dispatch has been completed but the swap promise used to determine
// |duration| has not been resolved.
HeapVector<Member<PerformanceEventTiming>> event_timings_;
- // We use a bool separate from |first_input_timing_| because if the first
- // input does not happen before onload then |first_input_timing_| will never
- // be populated since it should not be accessible from the performance buffer.
- bool first_input_detected_ = false;
Member<PerformanceEventTiming> first_pointer_down_event_timing_;
mutable Member<PerformanceNavigation> navigation_;
mutable Member<PerformanceTiming> timing_;
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc b/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
index a1b0e2691e8..9086d51f91c 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -6,7 +6,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_double.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_double_or_performance_measure_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
index 995d8149198..fc33951f0f8 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
@@ -8,7 +8,7 @@ typedef (DOMString or TrustedHTML) HTMLString;
[
Exposed=Window,
- RuntimeEnabled=TrustedDOMTypes
+ OriginTrialEnabled=TrustedDOMTypes
] interface TrustedHTML {
stringifier;
};
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
index a8f86e4e2a5..77610362add 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
@@ -8,7 +8,7 @@ typedef (DOMString or TrustedScript) ScriptString;
[
Exposed=Window,
- RuntimeEnabled=TrustedDOMTypes
+ OriginTrialEnabled=TrustedDOMTypes
] interface TrustedScript {
stringifier;
};
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc
index a1d527dc942..dd91ac50ee5 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc
@@ -4,14 +4,12 @@
#include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
namespace blink {
-TrustedScriptURL::TrustedScriptURL(const KURL& url) : url_(url) {}
+TrustedScriptURL::TrustedScriptURL(const String& url) : url_(url) {}
String TrustedScriptURL::toString() const {
- return url_.GetString();
+ return url_;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
index 0ea47303791..1dba54128d1 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
@@ -7,13 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-
-namespace WTF {
-
-class String;
-
-} // namespace WTF
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -21,17 +15,17 @@ class CORE_EXPORT TrustedScriptURL final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static TrustedScriptURL* Create(const KURL& url) {
+ static TrustedScriptURL* Create(const String& url) {
return MakeGarbageCollected<TrustedScriptURL>(url);
}
- TrustedScriptURL(const KURL&);
+ TrustedScriptURL(const String& url);
// TrustedScriptURL.idl
String toString() const;
private:
- KURL url_;
+ const String url_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
index 3a4faeeaf2f..e1a4c0cc379 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
@@ -8,7 +8,7 @@ typedef (DOMString or TrustedScriptURL) ScriptURLString;
[
Exposed=Window,
- RuntimeEnabled=TrustedDOMTypes
+ OriginTrialEnabled=TrustedDOMTypes
] interface TrustedScriptURL {
stringifier;
};
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
index 468f1ec5cf7..c439848ba4d 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
@@ -113,7 +113,7 @@ TrustedScriptURL* TrustedTypePolicy::CreateScriptURL(
exception_state.RethrowV8Exception(try_catch.Exception());
return nullptr;
}
- return TrustedScriptURL::Create(KURL(script_url));
+ return TrustedScriptURL::Create(script_url);
}
TrustedURL* TrustedTypePolicy::CreateURL(v8::Isolate* isolate,
@@ -132,7 +132,7 @@ TrustedURL* TrustedTypePolicy::CreateURL(v8::Isolate* isolate,
exception_state.RethrowV8Exception(try_catch.Exception());
return nullptr;
}
- return TrustedURL::Create(KURL(url));
+ return TrustedURL::Create(url);
}
String TrustedTypePolicy::name() const {
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
index 60f712be382..b6985b33382 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
@@ -8,7 +8,7 @@ typedef (DOMString or TrustedHTML or TrustedScript or TrustedScriptURL or Truste
[
Exposed=Window,
- RuntimeEnabled=TrustedDOMTypes
+ OriginTrialEnabled=TrustedDOMTypes
] interface TrustedTypePolicy {
[Unforgeable] readonly attribute DOMString name;
[CallWith=ScriptState, RaisesException, Unforgeable] TrustedHTML createHTML(DOMString input);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
index 5b9676c5605..b62f1296a64 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h"
+#include "third_party/blink/public/platform/web_feature.mojom-shared.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_trusted_html.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_trusted_script.h"
@@ -12,9 +13,10 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
namespace blink {
@@ -24,8 +26,10 @@ TrustedTypePolicy* TrustedTypePolicyFactory::createPolicy(
const TrustedTypePolicyOptions* policy_options,
bool exposed,
ExceptionState& exception_state) {
- if (!GetFrame()
- ->GetDocument()
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kTrustedTypesCreatePolicy);
+ if (origin_trials::TrustedDOMTypesEnabled(GetExecutionContext()) &&
+ !GetExecutionContext()
->GetContentSecurityPolicy()
->AllowTrustedTypePolicy(policy_name)) {
exception_state.ThrowTypeError("Policy " + policy_name + " disallowed.");
@@ -43,6 +47,10 @@ TrustedTypePolicy* TrustedTypePolicyFactory::createPolicy(
"The default policy must be exposed.");
return nullptr;
}
+ if (policy_name == "default") {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kTrustedTypesDefaultPolicyUsed);
+ }
TrustedTypePolicy* policy = TrustedTypePolicy::Create(
policy_name, const_cast<TrustedTypePolicyOptions*>(policy_options),
exposed);
@@ -59,8 +67,10 @@ TrustedTypePolicy* TrustedTypePolicyFactory::getExposedPolicy(
return nullptr;
}
-TrustedTypePolicyFactory::TrustedTypePolicyFactory(LocalFrame* frame)
- : DOMWindowClient(frame) {}
+TrustedTypePolicyFactory::TrustedTypePolicyFactory(ExecutionContext* context)
+ : ContextClient(context) {
+ UseCounter::Count(context, WebFeature::kTrustedTypesEnabled);
+}
Vector<String> TrustedTypePolicyFactory::getPolicyNames() const {
Vector<String> policyNames;
@@ -75,11 +85,10 @@ TrustedTypePolicyFactory::GetWrapperTypeInfoFromScriptValue(
ScriptState* script_state,
const ScriptValue& script_value) {
v8::Local<v8::Value> value = script_value.V8Value();
- v8::Isolate* isolate = script_state->GetIsolate();
if (value.IsEmpty() || !value->IsObject() ||
- !V8DOMWrapper::IsWrapper(isolate, value))
+ !V8DOMWrapper::IsWrapper(script_state->GetIsolate(), value))
return nullptr;
- v8::Local<v8::Object> object = script_value.V8Value()->ToObject(isolate);
+ v8::Local<v8::Object> object = value.As<v8::Object>();
return ToWrapperTypeInfo(object);
}
@@ -88,7 +97,7 @@ bool TrustedTypePolicyFactory::isHTML(ScriptState* script_state,
const WrapperTypeInfo* wrapper_type_info =
GetWrapperTypeInfoFromScriptValue(script_state, script_value);
return wrapper_type_info &&
- wrapper_type_info->Equals(&V8TrustedHTML::wrapper_type_info);
+ wrapper_type_info->Equals(V8TrustedHTML::GetWrapperTypeInfo());
}
bool TrustedTypePolicyFactory::isScript(ScriptState* script_state,
@@ -96,7 +105,7 @@ bool TrustedTypePolicyFactory::isScript(ScriptState* script_state,
const WrapperTypeInfo* wrapper_type_info =
GetWrapperTypeInfoFromScriptValue(script_state, script_value);
return wrapper_type_info &&
- wrapper_type_info->Equals(&V8TrustedScript::wrapper_type_info);
+ wrapper_type_info->Equals(V8TrustedScript::GetWrapperTypeInfo());
}
bool TrustedTypePolicyFactory::isScriptURL(ScriptState* script_state,
@@ -104,7 +113,7 @@ bool TrustedTypePolicyFactory::isScriptURL(ScriptState* script_state,
const WrapperTypeInfo* wrapper_type_info =
GetWrapperTypeInfoFromScriptValue(script_state, script_value);
return wrapper_type_info &&
- wrapper_type_info->Equals(&V8TrustedScriptURL::wrapper_type_info);
+ wrapper_type_info->Equals(V8TrustedScriptURL::GetWrapperTypeInfo());
}
bool TrustedTypePolicyFactory::isURL(ScriptState* script_state,
@@ -112,12 +121,20 @@ bool TrustedTypePolicyFactory::isURL(ScriptState* script_state,
const WrapperTypeInfo* wrapper_type_info =
GetWrapperTypeInfoFromScriptValue(script_state, script_value);
return wrapper_type_info &&
- wrapper_type_info->Equals(&V8TrustedURL::wrapper_type_info);
+ wrapper_type_info->Equals(V8TrustedURL::GetWrapperTypeInfo());
+}
+
+void TrustedTypePolicyFactory::CountTrustedTypeAssignmentError() {
+ if (!hadAssignmentError) {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kTrustedTypesAssignmentError);
+ hadAssignmentError = true;
+ }
}
void TrustedTypePolicyFactory::Trace(blink::Visitor* visitor) {
ScriptWrappable::Trace(visitor);
- DOMWindowClient::Trace(visitor);
+ ContextClient::Trace(visitor);
visitor->Trace(policy_map_);
}
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
index 88a6a37c249..c103e7d062a 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_options.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -15,22 +14,22 @@
namespace blink {
class ExceptionState;
-class LocalFrame;
class ScriptState;
class ScriptValue;
class TrustedTypePolicy;
+class TrustedTypePolicyOptions;
class CORE_EXPORT TrustedTypePolicyFactory final : public ScriptWrappable,
- public DOMWindowClient {
+ public ContextClient {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(TrustedTypePolicyFactory);
public:
- static TrustedTypePolicyFactory* Create(LocalFrame* frame) {
- return MakeGarbageCollected<TrustedTypePolicyFactory>(frame);
+ static TrustedTypePolicyFactory* Create(ExecutionContext* context) {
+ return MakeGarbageCollected<TrustedTypePolicyFactory>(context);
}
- explicit TrustedTypePolicyFactory(LocalFrame*);
+ explicit TrustedTypePolicyFactory(ExecutionContext*);
// TrustedTypePolicyFactory.idl
TrustedTypePolicy* createPolicy(const String&,
@@ -47,6 +46,11 @@ class CORE_EXPORT TrustedTypePolicyFactory final : public ScriptWrappable,
bool isScriptURL(ScriptState*, const ScriptValue&);
bool isURL(ScriptState*, const ScriptValue&);
+ // Count whether a Trusted Type error occured during DOM operations.
+ // (We aggregate this here to get a count per document, so that we can
+ // relate it to the total number of TT enabled documents.)
+ void CountTrustedTypeAssignmentError();
+
void Trace(blink::Visitor*) override;
private:
@@ -54,6 +58,8 @@ class CORE_EXPORT TrustedTypePolicyFactory final : public ScriptWrappable,
const ScriptValue&);
HeapHashMap<String, Member<TrustedTypePolicy>> policy_map_;
+
+ bool hadAssignmentError = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
index 2174192ee9b..29c5c1670ad 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
@@ -5,8 +5,8 @@
// https://github.com/wicg/trusted-types
[
- Exposed=Window,
- RuntimeEnabled=TrustedDOMTypes
+ Exposed=(Window, Worker),
+ OriginTrialEnabled=TrustedDOMTypes
] interface TrustedTypePolicyFactory {
[RaisesException, Unforgeable] TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypePolicyOptions policyOptions, optional boolean exposed = false);
[Unforgeable] TrustedTypePolicy getExposedPolicy(DOMString policyName);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
index 068d0750e15..ce9921c712a 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
@@ -27,12 +28,17 @@ String GetStringFromTrustedType(
const Document* doc,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_type.IsString() ||
- RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ origin_trials::TrustedDOMTypesEnabled(doc));
DCHECK(!string_or_trusted_type.IsNull());
if (string_or_trusted_type.IsString() && doc && doc->RequireTrustedTypes()) {
exception_state.ThrowTypeError(
"This document requires a Trusted Type assignment.");
+
+ // Test case docs (Document::CreateForTest) might not have a window.
+ if (doc->ExecutingWindow())
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
+
return g_empty_string;
}
@@ -65,11 +71,65 @@ String GetStringFromTrustedTypeWithoutCheck(
return g_empty_string;
}
+String GetStringFromSpecificTrustedType(
+ const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
+ string_or_trusted_type,
+ SpecificTrustedType specific_trusted_type,
+ const Document* doc,
+ ExceptionState& exception_state) {
+ switch (specific_trusted_type) {
+ case SpecificTrustedType::kTrustedHTML: {
+ StringOrTrustedHTML string_or_trusted_html =
+ string_or_trusted_type.IsTrustedHTML()
+ ? StringOrTrustedHTML::FromTrustedHTML(
+ string_or_trusted_type.GetAsTrustedHTML())
+ : StringOrTrustedHTML::FromString(
+ GetStringFromTrustedTypeWithoutCheck(
+ string_or_trusted_type));
+ return GetStringFromTrustedHTML(string_or_trusted_html, doc,
+ exception_state);
+ }
+ case SpecificTrustedType::kTrustedScript: {
+ StringOrTrustedScript string_or_trusted_script =
+ string_or_trusted_type.IsTrustedScript()
+ ? StringOrTrustedScript::FromTrustedScript(
+ string_or_trusted_type.GetAsTrustedScript())
+ : StringOrTrustedScript::FromString(
+ GetStringFromTrustedTypeWithoutCheck(
+ string_or_trusted_type));
+ return GetStringFromTrustedScript(string_or_trusted_script, doc,
+ exception_state);
+ }
+ case SpecificTrustedType::kTrustedScriptURL: {
+ StringOrTrustedScriptURL string_or_trusted_script_url =
+ string_or_trusted_type.IsTrustedScriptURL()
+ ? StringOrTrustedScriptURL::FromTrustedScriptURL(
+ string_or_trusted_type.GetAsTrustedScriptURL())
+ : StringOrTrustedScriptURL::FromString(
+ GetStringFromTrustedTypeWithoutCheck(
+ string_or_trusted_type));
+ return GetStringFromTrustedScriptURL(string_or_trusted_script_url, doc,
+ exception_state);
+ }
+ case SpecificTrustedType::kTrustedURL: {
+ USVStringOrTrustedURL string_or_trusted_url =
+ string_or_trusted_type.IsTrustedURL()
+ ? USVStringOrTrustedURL::FromTrustedURL(
+ string_or_trusted_type.GetAsTrustedURL())
+ : USVStringOrTrustedURL::FromUSVString(
+ GetStringFromTrustedTypeWithoutCheck(
+ string_or_trusted_type));
+ return GetStringFromTrustedURL(string_or_trusted_url, doc,
+ exception_state);
+ }
+ }
+}
+
String GetStringFromTrustedHTML(StringOrTrustedHTML string_or_trusted_html,
const Document* doc,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_html.IsString() ||
- RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ origin_trials::TrustedDOMTypesEnabled(doc));
DCHECK(!string_or_trusted_html.IsNull());
bool require_trusted_type = doc && doc->RequireTrustedTypes();
@@ -86,16 +146,18 @@ String GetStringFromTrustedHTML(StringOrTrustedHTML string_or_trusted_html,
if (!default_policy) {
exception_state.ThrowTypeError(
"This document requires `TrustedHTML` assignment.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
TrustedHTML* result = default_policy->CreateHTML(
- ToIsolate(doc), string_or_trusted_html.GetAsString(), exception_state);
+ doc->GetIsolate(), string_or_trusted_html.GetAsString(), exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
exception_state.ThrowTypeError(
"This document requires `TrustedHTML` assignment and 'default' policy "
"failed to execute.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
@@ -107,7 +169,7 @@ String GetStringFromTrustedScript(
const Document* doc,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_script.IsString() ||
- RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ origin_trials::TrustedDOMTypesEnabled(doc));
// To remain compatible with legacy behaviour, HTMLElement uses extended IDL
// attributes to allow for nullable union of (DOMString or TrustedScript).
@@ -138,6 +200,7 @@ String GetStringFromTrustedScript(
if (!default_policy) {
exception_state.ThrowTypeError(
"This document requires `TrustedScript` assignment.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
@@ -146,7 +209,7 @@ String GetStringFromTrustedScript(
? g_empty_string
: string_or_trusted_script.GetAsString();
TrustedScript* result = default_policy->CreateScript(
- ToIsolate(doc), string_value_or_empty, exception_state);
+ doc->GetIsolate(), string_value_or_empty, exception_state);
DCHECK_EQ(!result, exception_state.HadException());
if (exception_state.HadException()) {
exception_state.ClearException();
@@ -154,6 +217,7 @@ String GetStringFromTrustedScript(
"This document requires `TrustedScript` assignment and 'default' "
"policy "
"failed to execute.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
@@ -165,10 +229,12 @@ String GetStringFromTrustedScriptURL(
const Document* doc,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_script_url.IsString() ||
- RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ origin_trials::TrustedDOMTypesEnabled(doc));
DCHECK(!string_or_trusted_script_url.IsNull());
- bool require_trusted_type = doc && doc->RequireTrustedTypes();
+ bool require_trusted_type = doc &&
+ origin_trials::TrustedDOMTypesEnabled(doc) &&
+ doc->RequireTrustedTypes();
if (!require_trusted_type && string_or_trusted_script_url.IsString()) {
return string_or_trusted_script_url.GetAsString();
}
@@ -182,11 +248,12 @@ String GetStringFromTrustedScriptURL(
if (!default_policy) {
exception_state.ThrowTypeError(
"This document requires `TrustedScriptURL` assignment.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
TrustedScriptURL* result = default_policy->CreateScriptURL(
- ToIsolate(doc), string_or_trusted_script_url.GetAsString(),
+ doc->GetIsolate(), string_or_trusted_script_url.GetAsString(),
exception_state);
if (exception_state.HadException()) {
@@ -195,6 +262,7 @@ String GetStringFromTrustedScriptURL(
"This document requires `TrustedScriptURL` assignment and 'default' "
"policy "
"failed to execute.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
@@ -205,7 +273,7 @@ String GetStringFromTrustedURL(USVStringOrTrustedURL string_or_trusted_url,
const Document* doc,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_url.IsUSVString() ||
- RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+ origin_trials::TrustedDOMTypesEnabled(doc));
DCHECK(!string_or_trusted_url.IsNull());
bool require_trusted_type = doc && doc->RequireTrustedTypes();
@@ -222,16 +290,19 @@ String GetStringFromTrustedURL(USVStringOrTrustedURL string_or_trusted_url,
if (!default_policy) {
exception_state.ThrowTypeError(
"This document requires `TrustedURL` assignment.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
TrustedURL* result = default_policy->CreateURL(
- ToIsolate(doc), string_or_trusted_url.GetAsUSVString(), exception_state);
+ doc->GetIsolate(), string_or_trusted_url.GetAsUSVString(),
+ exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
exception_state.ThrowTypeError(
"This document requires `TrustedURL` assignment and 'default' policy "
"failed to execute.");
+ doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
return g_empty_string;
}
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h
index c86ca1769fb..5adb8cc309c 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.h
@@ -18,6 +18,13 @@ class StringOrTrustedScript;
class StringOrTrustedScriptURL;
class USVStringOrTrustedURL;
+enum class SpecificTrustedType {
+ kTrustedHTML,
+ kTrustedScript,
+ kTrustedScriptURL,
+ kTrustedURL,
+};
+
String CORE_EXPORT GetStringFromTrustedType(
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&,
const Document*,
@@ -26,6 +33,12 @@ String CORE_EXPORT GetStringFromTrustedType(
String CORE_EXPORT GetStringFromTrustedTypeWithoutCheck(
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&);
+String CORE_EXPORT GetStringFromSpecificTrustedType(
+ const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&,
+ SpecificTrustedType,
+ const Document*,
+ ExceptionState&);
+
String CORE_EXPORT GetStringFromTrustedHTML(StringOrTrustedHTML,
const Document*,
ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
index f17780dbc1b..ea709f98217 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
@@ -26,7 +26,7 @@ void GetStringFromTrustedTypeThrows(
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
string_or_trusted_type) {
Document* document = Document::CreateForTest();
- document->SetRequireTrustedTypes();
+ document->SetRequireTrustedTypesForTesting();
DummyExceptionStateForTesting exception_state;
ASSERT_FALSE(exception_state.HadException());
String s = GetStringFromTrustedType(string_or_trusted_type, document,
@@ -41,7 +41,7 @@ void GetStringFromTrustedHTMLThrows(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
ASSERT_FALSE(exception_state.HadException());
@@ -57,7 +57,7 @@ void GetStringFromTrustedScriptThrows(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
ASSERT_FALSE(exception_state.HadException());
@@ -73,7 +73,7 @@ void GetStringFromTrustedScriptURLThrows(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
ASSERT_FALSE(exception_state.HadException());
@@ -89,7 +89,7 @@ void GetStringFromTrustedURLThrows(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
ASSERT_FALSE(exception_state.HadException());
@@ -106,7 +106,7 @@ void GetStringFromTrustedTypeWorks(
string_or_trusted_type,
String expected) {
Document* document = Document::CreateForTest();
- document->SetRequireTrustedTypes();
+ document->SetRequireTrustedTypesForTesting();
DummyExceptionStateForTesting exception_state;
String s = GetStringFromTrustedType(string_or_trusted_type, document,
exception_state);
@@ -119,7 +119,7 @@ void GetStringFromTrustedHTMLWorks(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
String s = GetStringFromTrustedHTML(string_or_trusted_html, &document,
@@ -133,7 +133,7 @@ void GetStringFromTrustedScriptWorks(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
String s = GetStringFromTrustedScript(string_or_trusted_script, &document,
@@ -147,7 +147,7 @@ void GetStringFromTrustedScriptURLWorks(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
String s = GetStringFromTrustedScriptURL(string_or_trusted_script_url,
@@ -161,7 +161,7 @@ void GetStringFromTrustedURLWorks(
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
- document.SetRequireTrustedTypes();
+ document.SetRequireTrustedTypesForTesting();
V8TestingScope scope;
DummyExceptionStateForTesting exception_state;
String s = GetStringFromTrustedURL(string_or_trusted_url, &document,
@@ -189,7 +189,7 @@ TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedScript) {
}
TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedScriptURL) {
- KURL url_address("http://www.example.com/");
+ String url_address = "http://www.example.com/";
TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
trusted_value =
@@ -198,8 +198,18 @@ TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedScriptURL) {
GetStringFromTrustedTypeWorks(trusted_value, "http://www.example.com/");
}
+TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedScriptURL_Relative) {
+ String url_address = "relative/url.html";
+ TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
+ StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
+ trusted_value =
+ StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL::
+ FromTrustedScriptURL(script_url);
+ GetStringFromTrustedTypeWorks(trusted_value, "relative/url.html");
+}
+
TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedURL) {
- KURL url_address("http://www.example.com/");
+ String url_address = "http://www.example.com/";
TrustedURL* url = TrustedURL::Create(url_address);
StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
trusted_value =
@@ -208,6 +218,16 @@ TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedURL) {
GetStringFromTrustedTypeWorks(trusted_value, "http://www.example.com/");
}
+TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedURL_Relative) {
+ String url_address = "relative/url.html";
+ TrustedURL* url = TrustedURL::Create(url_address);
+ StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
+ trusted_value =
+ StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL::
+ FromTrustedURL(url);
+ GetStringFromTrustedTypeWorks(trusted_value, "relative/url.html");
+}
+
TEST(TrustedTypesUtilTest, GetStringFromTrustedType_String) {
StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
string_value =
@@ -239,7 +259,7 @@ TEST(TrustedTypesUtilTest, GetStringFromTrustedTypeWithoutCheck_TrustedScript) {
TEST(TrustedTypesUtilTest,
GetStringFromTrustedTypeWithoutCheck_TrustedScriptURL) {
- KURL url_address("http://www.example.com/");
+ String url_address = "http://www.example.com/";
TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
trusted_value =
@@ -250,7 +270,7 @@ TEST(TrustedTypesUtilTest,
}
TEST(TrustedTypesUtilTest, GetStringFromTrustedTypeWithoutCheck_TrustedURL) {
- KURL url_address("http://www.example.com/");
+ String url_address = "http://www.example.com/";
TrustedURL* url = TrustedURL::Create(url_address);
StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
trusted_value =
@@ -306,7 +326,7 @@ TEST(TrustedTypesUtilTest, GetStringFromTrustedScript_String) {
// GetStringFromTrustedScriptURL tests
TEST(TrustedTypesUtilTest, GetStringFromTrustedScriptURL_TrustedScriptURL) {
- KURL url_address("http://www.example.com/");
+ String url_address = "http://www.example.com/";
TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
StringOrTrustedScriptURL trusted_value =
StringOrTrustedScriptURL::FromTrustedScriptURL(script_url);
@@ -321,7 +341,7 @@ TEST(TrustedTypesUtilTest, GetStringFromTrustedScriptURL_String) {
// GetStringFromTrustedURL tests
TEST(TrustedTypesUtilTest, GetStringFromTrustedURL_TrustedURL) {
- KURL url_address("http://www.example.com/");
+ String url_address = "http://www.example.com/";
TrustedURL* url = TrustedURL::Create(url_address);
USVStringOrTrustedURL trusted_value =
USVStringOrTrustedURL::FromTrustedURL(url);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.cc
index 0093775b285..b8b46e32482 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.cc
@@ -4,14 +4,12 @@
#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
namespace blink {
-TrustedURL::TrustedURL(const KURL& url) : url_(url) {}
+TrustedURL::TrustedURL(const String& url) : url_(url) {}
String TrustedURL::toString() const {
- return url_.GetString();
+ return url_;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.h
index df18273aa9d..d2f8ee2ae0b 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.h
@@ -7,13 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-
-namespace WTF {
-
-class String;
-
-} // namespace WTF
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -21,17 +15,17 @@ class CORE_EXPORT TrustedURL final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static TrustedURL* Create(const KURL& url) {
+ static TrustedURL* Create(const String& url) {
return MakeGarbageCollected<TrustedURL>(url);
}
- TrustedURL(const KURL&);
+ TrustedURL(const String& url);
// TrustedURL.idl
String toString() const;
private:
- KURL url_;
+ const String url_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.idl
index b6115635157..d11a566cd40 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_url.idl
@@ -8,7 +8,7 @@ typedef (USVString or TrustedURL) URLString;
[
Exposed=Window,
- RuntimeEnabled=TrustedDOMTypes
+ OriginTrialEnabled=TrustedDOMTypes
] interface TrustedURL {
stringifier;
};
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
index db878ac323e..ffa5a83e779 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
@@ -71,8 +71,8 @@ DEFINE_DOMTYPEDARRAY_TRAITS(DOMFloat64Array, V8Float64Array);
template <typename WTFTypedArray, typename V8TypedArray>
const WrapperTypeInfo*
DOMTypedArray<WTFTypedArray, V8TypedArray>::GetWrapperTypeInfo() const {
- return &DOMTypedArrayTraits<
- DOMTypedArray<WTFTypedArray, V8TypedArray>>::Type::wrapper_type_info;
+ return DOMTypedArrayTraits<
+ DOMTypedArray<WTFTypedArray, V8TypedArray>>::Type::GetWrapperTypeInfo();
}
template class CORE_TEMPLATE_EXPORT
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
index 8b720409f99..750d1a525a6 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
@@ -33,7 +33,7 @@ class DOMTypedArray final : public DOMArrayBufferView {
typedef typename WTFTypedArray::ValueType ValueType;
static ThisType* Create(scoped_refptr<WTFTypedArray> buffer_view) {
- return new ThisType(std::move(buffer_view));
+ return MakeGarbageCollected<ThisType>(std::move(buffer_view));
}
static ThisType* Create(unsigned length) {
return Create(WTFTypedArray::Create(length));
@@ -52,7 +52,7 @@ class DOMTypedArray final : public DOMArrayBufferView {
unsigned length) {
scoped_refptr<WTFTypedArray> buffer_view =
WTFTypedArray::Create(buffer->Buffer(), byte_offset, length);
- return new ThisType(std::move(buffer_view), buffer);
+ return MakeGarbageCollected<ThisType>(std::move(buffer_view), buffer);
}
static ThisType* CreateOrNull(unsigned length) {
@@ -61,6 +61,12 @@ class DOMTypedArray final : public DOMArrayBufferView {
return buffer ? Create(std::move(buffer), 0, length) : nullptr;
}
+ explicit DOMTypedArray(scoped_refptr<WTFTypedArray> buffer_view)
+ : DOMArrayBufferView(std::move(buffer_view)) {}
+ DOMTypedArray(scoped_refptr<WTFTypedArray> buffer_view,
+ DOMArrayBufferBase* dom_array_buffer)
+ : DOMArrayBufferView(std::move(buffer_view), dom_array_buffer) {}
+
const WTFTypedArray* View() const {
return static_cast<const WTFTypedArray*>(DOMArrayBufferView::View());
}
@@ -77,13 +83,6 @@ class DOMTypedArray final : public DOMArrayBufferView {
v8::Local<v8::Object> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override;
-
- private:
- explicit DOMTypedArray(scoped_refptr<WTFTypedArray> buffer_view)
- : DOMArrayBufferView(std::move(buffer_view)) {}
- DOMTypedArray(scoped_refptr<WTFTypedArray> buffer_view,
- DOMArrayBufferBase* dom_array_buffer)
- : DOMArrayBufferView(std::move(buffer_view), dom_array_buffer) {}
};
extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h b/chromium/third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h
index ae2828225ab..2bdf8870a72 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h
@@ -19,7 +19,7 @@ class CORE_EXPORT FlexibleArrayBufferView {
FlexibleArrayBufferView() : small_data_(nullptr), small_length_(0) {}
void SetFull(DOMArrayBufferView* full) { full_ = full; }
- void SetSmall(void* data, size_t length) {
+ void SetSmall(void* data, uint32_t length) {
small_data_ = data;
small_length_ = length;
}
@@ -62,7 +62,7 @@ class CORE_EXPORT FlexibleArrayBufferView {
Member<DOMArrayBufferView> full_;
void* small_data_;
- size_t small_length_;
+ uint32_t small_length_;
DISALLOW_COPY_AND_ASSIGN(FlexibleArrayBufferView);
};
diff --git a/chromium/third_party/blink/renderer/core/url/url_search_params.cc b/chromium/third_party/blink/renderer/core/url/url_search_params.cc
index e29f88a5abd..fd43bb89e4d 100644
--- a/chromium/third_party/blink/renderer/core/url/url_search_params.cc
+++ b/chromium/third_party/blink/renderer/core/url/url_search_params.cc
@@ -133,7 +133,8 @@ void URLSearchParams::RunUpdateSteps() {
}
static String DecodeString(String input) {
- return DecodeURLEscapeSequences(input.Replace('+', ' '));
+ return DecodeURLEscapeSequences(input.Replace('+', ' '),
+ DecodeURLMode::kUTF8OrIsomorphic);
}
void URLSearchParams::SetInputWithoutUpdate(const String& query_string) {
@@ -260,7 +261,7 @@ scoped_refptr<EncodedFormData> URLSearchParams::ToEncodedFormData() const {
PairIterable<String, String>::IterationSource* URLSearchParams::StartIteration(
ScriptState*,
ExceptionState&) {
- return new URLSearchParamsIterationSource(this);
+ return MakeGarbageCollected<URLSearchParamsIterationSource>(this);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/BUILD.gn b/chromium/third_party/blink/renderer/core/workers/BUILD.gn
index eef62db95d7..28acb5029e5 100644
--- a/chromium/third_party/blink/renderer/core/workers/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/workers/BUILD.gn
@@ -41,13 +41,16 @@ blink_core_sources("workers") {
"parent_execution_context_task_runners.h",
"shared_worker.cc",
"shared_worker.h",
+ "shared_worker_client.cc",
+ "shared_worker_client.h",
+ "shared_worker_client_holder.cc",
+ "shared_worker_client_holder.h",
"shared_worker_content_settings_proxy.cc",
"shared_worker_content_settings_proxy.h",
"shared_worker_global_scope.cc",
"shared_worker_global_scope.h",
"shared_worker_reporting_proxy.cc",
"shared_worker_reporting_proxy.h",
- "shared_worker_repository_client.h",
"shared_worker_thread.cc",
"shared_worker_thread.h",
"threaded_messaging_proxy_base.cc",
diff --git a/chromium/third_party/blink/renderer/core/workers/OWNERS b/chromium/third_party/blink/renderer/core/workers/OWNERS
index eb8bfba6870..aaadbd31dca 100644
--- a/chromium/third_party/blink/renderer/core/workers/OWNERS
+++ b/chromium/third_party/blink/renderer/core/workers/OWNERS
@@ -1,3 +1,6 @@
+falken@chromium.org
+hiroshige@chromium.org
+japhet@chromium.org
nhiroki@chromium.org
# TEAM: worker-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/workers/abstract_worker.h b/chromium/third_party/blink/renderer/core/workers/abstract_worker.h
index 0806f823087..81e64fa457e 100644
--- a/chromium/third_party/blink/renderer/core/workers/abstract_worker.h
+++ b/chromium/third_party/blink/renderer/core/workers/abstract_worker.h
@@ -31,7 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_ABSTRACT_WORKER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_ABSTRACT_WORKER_H_
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc
index 9a26e641af3..e93a4a1e707 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -9,7 +9,7 @@
#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
#include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
-#include "third_party/blink/public/platform/dedicated_worker_factory.mojom-blink.h"
+#include "third_party/blink/public/mojom/worker/dedicated_worker_factory.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_layer_tree_view.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h"
@@ -21,6 +21,9 @@
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
+#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
#include "third_party/blink/renderer/core/messaging/post_message_options.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
@@ -34,8 +37,10 @@
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
namespace blink {
@@ -55,6 +60,46 @@ ConnectToWorkerInterfaceProvider(
return interface_provider_ptr;
}
+// Indicates whether the origin of worker top-level script's request URL is
+// same-origin as the parent execution context's origin or not.
+// This is used for UMA and thus the existing values should not be changed.
+enum class WorkerTopLevelScriptOriginType {
+ kSameOrigin = 0,
+ kDataUrl = 1,
+
+ // Cross-origin worker request URL (e.g. https://example.com/worker.js)
+ // from an chrome-extension: page.
+ kCrossOriginFromExtension = 2,
+
+ // Cross-origin worker request URL from a non chrome-extension: page.
+ // There are no known cases for this, and we investigate whether there are
+ // really no occurrences.
+ kCrossOriginOthers = 3,
+
+ kMaxValue = kCrossOriginOthers
+};
+
+void CountTopLevelScriptRequestUrlOriginType(
+ const SecurityOrigin& context_origin,
+ const KURL& request_url) {
+ WorkerTopLevelScriptOriginType origin_type;
+ if (request_url.ProtocolIsData()) {
+ origin_type = WorkerTopLevelScriptOriginType::kDataUrl;
+ } else if (context_origin.IsSameSchemeHostPort(
+ SecurityOrigin::Create(request_url).get())) {
+ origin_type = WorkerTopLevelScriptOriginType::kSameOrigin;
+ } else if (context_origin.Protocol() == "chrome-extension") {
+ // Note: using "chrome-extension" scheme check here is a layering
+ // violation. Do not use this except for UMA purpose.
+ origin_type = WorkerTopLevelScriptOriginType::kCrossOriginFromExtension;
+ } else {
+ origin_type = WorkerTopLevelScriptOriginType::kCrossOriginOthers;
+ }
+ UMA_HISTOGRAM_ENUMERATION(
+ "Worker.TopLevelScript.OriginType.RequestUrl.DedicatedWorker",
+ origin_type);
+}
+
} // namespace
DedicatedWorker* DedicatedWorker::Create(ExecutionContext* context,
@@ -164,18 +209,25 @@ void DedicatedWorker::Start() {
DCHECK(GetExecutionContext()->IsContextThread());
v8_inspector::V8StackTraceId stack_id =
- ThreadDebugger::From(ToIsolate(GetExecutionContext()))
+ ThreadDebugger::From(GetExecutionContext()->GetIsolate())
->StoreCurrentStackTrace("Worker Created");
+ if (auto* scope = DynamicTo<WorkerGlobalScope>(*GetExecutionContext()))
+ scope->EnsureFetcher();
if (RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled() ||
options_->type() == "module") {
// Specify empty source code here because scripts will be fetched on the
// worker thread.
auto* outside_settings_object =
- GetExecutionContext()->CreateFetchClientSettingsObjectSnapshot();
+ MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ GetExecutionContext()
+ ->Fetcher()
+ ->GetProperties()
+ .GetFetchClientSettingsObject());
context_proxy_->StartWorkerGlobalScope(
CreateGlobalScopeCreationParams(
- script_request_url_, network::mojom::ReferrerPolicy::kDefault),
+ script_request_url_, OffMainThreadWorkerScriptFetchOption::kEnabled,
+ network::mojom::ReferrerPolicy::kDefault),
options_, script_request_url_, outside_settings_object, stack_id,
String() /* source_code */);
return;
@@ -186,12 +238,11 @@ void DedicatedWorker::Start() {
// thread.
classic_script_loader_ = MakeGarbageCollected<WorkerClassicScriptLoader>();
classic_script_loader_->LoadTopLevelScriptAsynchronously(
- *GetExecutionContext(), script_request_url_,
- mojom::RequestContextType::WORKER,
+ *GetExecutionContext(), GetExecutionContext()->Fetcher(),
+ script_request_url_, mojom::RequestContextType::WORKER,
network::mojom::FetchRequestMode::kSameOrigin,
network::mojom::FetchCredentialsMode::kSameOrigin,
GetExecutionContext()->GetSecurityContext().AddressSpace(),
- GetExecutionContext()->IsWorkerGlobalScope(),
WTF::Bind(&DedicatedWorker::OnResponse, WrapPersistent(this)),
WTF::Bind(&DedicatedWorker::OnFinished, WrapPersistent(this),
stack_id));
@@ -242,6 +293,12 @@ bool DedicatedWorker::HasPendingActivity() const {
return context_proxy_->HasPendingActivity() || classic_script_loader_;
}
+void DedicatedWorker::DispatchErrorEventForScriptFetchFailure() {
+ DCHECK(!GetExecutionContext() || GetExecutionContext()->IsContextThread());
+ // TODO(nhiroki): Add a console error message.
+ DispatchEvent(*Event::CreateCancelable(event_type_names::kError));
+}
+
const String DedicatedWorker::Name() const {
return options_->name();
}
@@ -280,8 +337,11 @@ void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) {
if (classic_script_loader_->Canceled()) {
// Do nothing.
} else if (classic_script_loader_->Failed()) {
- DispatchEvent(*Event::CreateCancelable(event_type_names::kError));
+ context_proxy_->DidFailToFetchScript();
} else {
+ CountTopLevelScriptRequestUrlOriginType(
+ *GetExecutionContext()->GetSecurityOrigin(), script_request_url_);
+
network::mojom::ReferrerPolicy referrer_policy =
network::mojom::ReferrerPolicy::kDefault;
if (!classic_script_loader_->GetReferrerPolicy().IsNull()) {
@@ -294,9 +354,15 @@ void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) {
SecurityOrigin::AreSameSchemeHostPort(script_request_url_,
script_response_url));
auto* outside_settings_object =
- GetExecutionContext()->CreateFetchClientSettingsObjectSnapshot();
+ MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ GetExecutionContext()
+ ->Fetcher()
+ ->GetProperties()
+ .GetFetchClientSettingsObject());
context_proxy_->StartWorkerGlobalScope(
- CreateGlobalScopeCreationParams(script_response_url, referrer_policy),
+ CreateGlobalScopeCreationParams(
+ script_response_url,
+ OffMainThreadWorkerScriptFetchOption::kDisabled, referrer_policy),
options_, script_response_url, outside_settings_object, stack_id,
classic_script_loader_->SourceText());
probe::scriptImported(GetExecutionContext(),
@@ -309,6 +375,7 @@ void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) {
std::unique_ptr<GlobalScopeCreationParams>
DedicatedWorker::CreateGlobalScopeCreationParams(
const KURL& script_url,
+ OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option,
network::mojom::ReferrerPolicy referrer_policy) {
base::UnguessableToken parent_devtools_token;
std::unique_ptr<WorkerSettings> settings;
@@ -333,7 +400,10 @@ DedicatedWorker::CreateGlobalScopeCreationParams(
LocalFrame* frame = document->GetFrame();
web_worker_fetch_context = frame->Client()->CreateWorkerFetchContext();
web_worker_fetch_context->SetApplicationCacheHostID(
- GetExecutionContext()->Fetcher()->Context().ApplicationCacheHostID());
+ frame->Loader()
+ .GetDocumentLoader()
+ ->GetApplicationCacheHost()
+ ->GetHostID());
web_worker_fetch_context->SetIsOnSubframe(!frame->IsMainFrame());
} else if (auto* scope =
DynamicTo<WorkerGlobalScope>(GetExecutionContext())) {
@@ -344,8 +414,8 @@ DedicatedWorker::CreateGlobalScopeCreationParams(
}
return std::make_unique<GlobalScopeCreationParams>(
- script_url, script_type, GetExecutionContext()->UserAgent(),
- std::move(web_worker_fetch_context),
+ script_url, script_type, off_main_thread_fetch_option,
+ GetExecutionContext()->UserAgent(), std::move(web_worker_fetch_context),
GetExecutionContext()->GetContentSecurityPolicy()->Headers(),
referrer_policy, GetExecutionContext()->GetSecurityOrigin(),
GetExecutionContext()->IsSecureContext(),
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h
index 294f9bf904b..0a17083dca5 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h
@@ -10,9 +10,9 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/workers/abstract_worker.h"
+#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
#include "third_party/blink/renderer/core/workers/worker_options.h"
#include "third_party/blink/renderer/platform/graphics/begin_frame_provider.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -31,7 +31,6 @@ class PostMessageOptions;
class ScriptState;
class WorkerClassicScriptLoader;
class WorkerClients;
-struct GlobalScopeCreationParams;
// Implementation of the Worker interface defined in the WebWorker HTML spec:
// https://html.spec.whatwg.org/multipage/workers.html#worker
@@ -76,6 +75,8 @@ class CORE_EXPORT DedicatedWorker final
// (via AbstractWorker -> EventTargetWithInlineData -> EventTarget).
bool HasPendingActivity() const final;
+ void DispatchErrorEventForScriptFetchFailure();
+
// Returns the name specified by WorkerOptions.
const String Name() const;
@@ -89,6 +90,7 @@ class CORE_EXPORT DedicatedWorker final
std::unique_ptr<GlobalScopeCreationParams> CreateGlobalScopeCreationParams(
const KURL& script_url,
+ OffMainThreadWorkerScriptFetchOption,
network::mojom::ReferrerPolicy);
WorkerClients* CreateWorkerClients();
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
index 08de75ba6b2..ef6e4512c8b 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
@@ -65,10 +65,6 @@ const AtomicString& DedicatedWorkerGlobalScope::InterfaceName() const {
return event_target_names::kDedicatedWorkerGlobalScope;
}
-bool DedicatedWorkerGlobalScope::IsNestedWorker() const {
- return static_cast<DedicatedWorkerThread*>(GetThread())->IsNestedWorker();
-}
-
// https://html.spec.whatwg.org/multipage/workers.html#worker-processing-model
void DedicatedWorkerGlobalScope::ImportModuleScript(
const KURL& module_url_record,
@@ -139,4 +135,9 @@ void DedicatedWorkerGlobalScope::Trace(blink::Visitor* visitor) {
WorkerGlobalScope::Trace(visitor);
}
+mojom::RequestContextType
+DedicatedWorkerGlobalScope::GetDestinationForMainScript() {
+ return mojom::RequestContextType::WORKER;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
index c73d796d278..4b36b39d07e 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
@@ -62,7 +62,6 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
const AtomicString& InterfaceName() const override;
// WorkerGlobalScope
- bool IsNestedWorker() const override;
void ImportModuleScript(
const KURL& module_url_record,
FetchClientSettingsObjectSnapshot* outside_settings_object,
@@ -87,6 +86,8 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
DedicatedWorkerObjectProxy& WorkerObjectProxy() const;
private:
+ mojom::RequestContextType GetDestinationForMainScript() override;
+
const String name_;
};
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
index f849cbac796..0663b31f295 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
@@ -51,24 +51,32 @@ void DedicatedWorkerMessagingProxy::StartWorkerGlobalScope(
return;
}
+ OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option =
+ creation_params->off_main_thread_fetch_option;
+
InitializeWorkerThread(
std::move(creation_params),
- CreateBackingThreadStartupData(ToIsolate(GetExecutionContext())));
+ CreateBackingThreadStartupData(GetExecutionContext()->GetIsolate()));
// Step 13: "Obtain script by switching on the value of options's type
// member:"
if (options->type() == "classic") {
// "classic: Fetch a classic worker script given url, outside settings,
// destination, and inside settings."
- if (RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled()) {
- GetWorkerThread()->ImportClassicScript(script_url,
- outside_settings_object, stack_id);
- } else {
- // Legacy code path (to be deprecated, see https://crbug.com/835717):
- GetWorkerThread()->EvaluateClassicScript(
- script_url, source_code, nullptr /* cached_meta_data */, stack_id);
+ switch (off_main_thread_fetch_option) {
+ case OffMainThreadWorkerScriptFetchOption::kEnabled:
+ GetWorkerThread()->ImportClassicScript(
+ script_url, outside_settings_object, stack_id);
+ break;
+ case OffMainThreadWorkerScriptFetchOption::kDisabled:
+ // Legacy code path (to be deprecated, see https://crbug.com/835717):
+ GetWorkerThread()->EvaluateClassicScript(
+ script_url, source_code, nullptr /* cached_meta_data */, stack_id);
+ break;
}
} else if (options->type() == "module") {
+ DCHECK_EQ(off_main_thread_fetch_option,
+ OffMainThreadWorkerScriptFetchOption::kEnabled);
// "module: Fetch a module worker script graph given url, outside settings,
// destination, the value of the credentials member of options, and inside
// settings."
@@ -106,6 +114,13 @@ bool DedicatedWorkerMessagingProxy::HasPendingActivity() const {
return !AskedToTerminate();
}
+void DedicatedWorkerMessagingProxy::DidFailToFetchScript() {
+ DCHECK(IsParentContextThread());
+ if (!worker_object_ || AskedToTerminate())
+ return;
+ worker_object_->DispatchErrorEventForScriptFetchFailure();
+}
+
void DedicatedWorkerMessagingProxy::DidEvaluateScript(bool success) {
DCHECK(IsParentContextThread());
was_script_evaluated_ = true;
@@ -140,7 +155,7 @@ void DedicatedWorkerMessagingProxy::PostMessageToWorkerObject(
return;
ThreadDebugger* debugger =
- ThreadDebugger::From(ToIsolate(GetExecutionContext()));
+ ThreadDebugger::From(GetExecutionContext()->GetIsolate());
MessagePortArray* ports = MessagePort::EntanglePorts(
*GetExecutionContext(), std::move(message.ports));
debugger->ExternalAsyncTaskStarted(message.sender_stack_trace_id);
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
index 4c1627943bc..1467031a2d9 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
@@ -46,6 +46,11 @@ class CORE_EXPORT DedicatedWorkerMessagingProxy
bool HasPendingActivity() const;
+ // This is called from DedicatedWorkerObjectProxy when off-the-main-thread
+ // worker script fetch is enabled. Otherwise, this is called from
+ // DedicatedWorker.
+ void DidFailToFetchScript();
+
// These methods come from worker context thread via
// DedicatedWorkerObjectProxy and are called on the parent context thread.
void DidEvaluateScript(bool success);
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc
index 84d3d4a0b12..efac7685ed8 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc
@@ -77,7 +77,7 @@ void DedicatedWorkerObjectProxy::ProcessMessageFromWorkerObject(
BlinkTransferableMessage message,
WorkerThread* worker_thread) {
To<WorkerGlobalScope>(worker_thread->GlobalScope())
- ->ReceiveMessagePausable(std::move(message));
+ ->ReceiveMessage(std::move(message));
}
void DedicatedWorkerObjectProxy::ProcessUnhandledException(
@@ -100,6 +100,22 @@ void DedicatedWorkerObjectProxy::ReportException(
WTF::Passed(location->Clone()), exception_id));
}
+void DedicatedWorkerObjectProxy::DidFailToFetchClassicScript() {
+ PostCrossThreadTask(
+ *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalDefault),
+ FROM_HERE,
+ CrossThreadBind(&DedicatedWorkerMessagingProxy::DidFailToFetchScript,
+ messaging_proxy_weak_ptr_));
+}
+
+void DedicatedWorkerObjectProxy::DidFailToFetchModuleScript() {
+ PostCrossThreadTask(
+ *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalDefault),
+ FROM_HERE,
+ CrossThreadBind(&DedicatedWorkerMessagingProxy::DidFailToFetchScript,
+ messaging_proxy_weak_ptr_));
+}
+
void DedicatedWorkerObjectProxy::DidEvaluateClassicScript(bool success) {
PostCrossThreadTask(
*GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalDefault),
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.h
index 3d78c12a8a1..b374607f736 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.h
@@ -68,6 +68,8 @@ class CORE_EXPORT DedicatedWorkerObjectProxy : public ThreadedObjectProxyBase {
void ReportException(const String& error_message,
std::unique_ptr<SourceLocation>,
int exception_id) override;
+ void DidFailToFetchClassicScript() final;
+ void DidFailToFetchModuleScript() final;
void DidEvaluateClassicScript(bool success) override;
void DidEvaluateModuleScript(bool success) override;
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
index ab02737ead1..6ee8ad39211 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
@@ -134,7 +134,8 @@ class DedicatedWorkerMessagingProxyForTest
To<Document>(GetExecutionContext())->GetSettings());
InitializeWorkerThread(
std::make_unique<GlobalScopeCreationParams>(
- script_url, mojom::ScriptType::kClassic, "fake user agent",
+ script_url, mojom::ScriptType::kClassic,
+ OffMainThreadWorkerScriptFetchOption::kDisabled, "fake user agent",
nullptr /* web_worker_fetch_context */, headers,
network::mojom::ReferrerPolicy::kDefault, security_origin_.get(),
false /* starter_secure_context */,
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc
index 273c6da15f0..9d0ce4702c1 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc
@@ -59,8 +59,7 @@ DedicatedWorkerThread::DedicatedWorkerThread(
DedicatedWorkerObjectProxy& worker_object_proxy)
: WorkerThread(worker_object_proxy),
name_(name.IsolatedCopy()),
- worker_object_proxy_(worker_object_proxy),
- is_nested_worker_(parent_execution_context->IsWorkerGlobalScope()) {
+ worker_object_proxy_(worker_object_proxy) {
FrameOrWorkerScheduler* scheduler =
parent_execution_context ? parent_execution_context->GetScheduler()
: nullptr;
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h
index b506d3f6802..01466db33d7 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h
@@ -54,8 +54,6 @@ class CORE_EXPORT DedicatedWorkerThread : public WorkerThread {
return worker_object_proxy_;
}
- bool IsNestedWorker() const { return is_nested_worker_; }
-
private:
friend class DedicatedWorkerThreadForTest;
@@ -72,7 +70,6 @@ class CORE_EXPORT DedicatedWorkerThread : public WorkerThread {
std::unique_ptr<WorkerBackingThread> worker_backing_thread_;
const String name_;
DedicatedWorkerObjectProxy& worker_object_proxy_;
- const bool is_nested_worker_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/task.cc b/chromium/third_party/blink/renderer/core/workers/experimental/task.cc
index 45d838463b1..01a57b73b7e 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/task.cc
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/task.cc
@@ -23,18 +23,20 @@ class TaskBase::AsyncFunctionCompleted : public ScriptFunction {
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
TaskBase* task,
State state) {
- return (new AsyncFunctionCompleted(script_state, task, state))
+ return (MakeGarbageCollected<AsyncFunctionCompleted>(script_state, task,
+ state))
->BindToV8Function();
}
+ AsyncFunctionCompleted(ScriptState* script_state, TaskBase* task, State state)
+ : ScriptFunction(script_state), task_(task), state_(state) {}
+
ScriptValue Call(ScriptValue v) override {
task_->TaskCompletedOnWorkerThread(v.V8Value(), state_);
return ScriptValue();
}
private:
- AsyncFunctionCompleted(ScriptState* script_state, TaskBase* task, State state)
- : ScriptFunction(script_state), task_(task), state_(state) {}
CrossThreadPersistent<TaskBase> task_;
const State state_;
};
@@ -168,7 +170,7 @@ scoped_refptr<SerializedScriptValue> TaskBase::GetSerializedResult() {
DCHECK(v8_result_);
ScriptState::Scope scope(
worker_thread_->GlobalScope()->ScriptController()->GetScriptState());
- v8::Isolate* isolate = ToIsolate(worker_thread_->GlobalScope());
+ v8::Isolate* isolate = worker_thread_->GlobalScope()->GetIsolate();
serialized_result_ = SerializedScriptValue::SerializeAndSwallowExceptions(
isolate, v8_result_->GetResult(isolate));
}
@@ -247,8 +249,8 @@ bool TaskBase::WillStartTaskOnWorkerThread() {
void TaskBase::TaskCompletedOnWorkerThread(v8::Local<v8::Value> v8_result,
State state) {
DCHECK(worker_thread_->IsCurrentThread());
- v8_result_ =
- new V8ResultHolder(ToIsolate(worker_thread_->GlobalScope()), v8_result);
+ v8_result_ = MakeGarbageCollected<V8ResultHolder>(
+ worker_thread_->GlobalScope()->GetIsolate(), v8_result);
function_ = nullptr;
arguments_.clear();
@@ -276,7 +278,7 @@ void TaskBase::RunTaskOnWorkerThread() {
// so no mutex needed while actually running the task.
WorkerOrWorkletGlobalScope* global_scope = worker_thread_->GlobalScope();
ScriptState::Scope scope(global_scope->ScriptController()->GetScriptState());
- v8::Isolate* isolate = ToIsolate(global_scope);
+ v8::Isolate* isolate = global_scope->GetIsolate();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Function> script_function;
@@ -399,7 +401,7 @@ void Task::StartTaskOnWorkerThread() {
DCHECK(worker_thread_->IsCurrentThread());
if (!WillStartTaskOnWorkerThread()) {
WorkerOrWorkletGlobalScope* global_scope = worker_thread_->GlobalScope();
- v8::Isolate* isolate = ToIsolate(global_scope);
+ v8::Isolate* isolate = global_scope->GetIsolate();
ScriptState::Scope scope(
global_scope->ScriptController()->GetScriptState());
TaskCompletedOnWorkerThread(V8String(isolate, "Task aborted"),
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.cc b/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.cc
index 8cdafe2afa6..159a008ca78 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.cc
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.cc
@@ -38,7 +38,7 @@ TaskWorklet* TaskWorklet::From(LocalDOMWindow& window) {
TaskWorklet* task_worklet =
Supplement<LocalDOMWindow>::From<TaskWorklet>(window);
if (!task_worklet) {
- task_worklet = new TaskWorklet(window.document());
+ task_worklet = MakeGarbageCollected<TaskWorklet>(window.document());
Supplement<LocalDOMWindow>::ProvideTo(window, task_worklet);
}
return task_worklet;
@@ -55,14 +55,15 @@ Task* TaskWorklet::postTask(ScriptState* script_state,
// TODO(japhet): Here and below: it's unclear what task type should be used,
// and whether the API should allow it to be configured. Using kIdleTask as a
// placeholder for now.
- return new Task(this, script_state, function, arguments, TaskType::kIdleTask);
+ return MakeGarbageCollected<Task>(this, script_state, function, arguments,
+ TaskType::kIdleTask);
}
Task* TaskWorklet::postTask(ScriptState* script_state,
const String& function_name,
const Vector<ScriptValue>& arguments) {
- return new Task(this, script_state, function_name, arguments,
- TaskType::kIdleTask);
+ return MakeGarbageCollected<Task>(this, script_state, function_name,
+ arguments, TaskType::kIdleTask);
}
ThreadPoolThread* TaskWorklet::GetLeastBusyThread() {
@@ -101,7 +102,7 @@ bool TaskWorklet::NeedsToCreateGlobalScope() {
WorkletGlobalScopeProxy* TaskWorklet::CreateGlobalScope() {
DCHECK_LT(GetNumberOfGlobalScopes(), kMaxTaskWorkletThreads);
TaskWorkletMessagingProxy* proxy =
- new TaskWorkletMessagingProxy(GetExecutionContext());
+ MakeGarbageCollected<TaskWorkletMessagingProxy>(GetExecutionContext());
proxy->Initialize(WorkerClients::Create(), ModuleResponsesMap(),
WorkerBackingThreadStartupData::CreateDefault());
return proxy;
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.h b/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.h
index 49c367ab2e9..9e6e1bb28e6 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.h
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet.h
@@ -33,10 +33,11 @@ class TaskWorklet final : public Worklet,
ThreadPoolThread* GetLeastBusyThread() override;
+ explicit TaskWorklet(Document*);
+
void Trace(blink::Visitor*) override;
private:
- explicit TaskWorklet(Document*);
~TaskWorklet() override = default;
bool NeedsToCreateGlobalScope() final;
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet_global_scope.cc
index efec929d9f6..72aea63a342 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/task_worklet_global_scope.cc
@@ -27,8 +27,8 @@ class TaskDefinition final : public GarbageCollectedFinalized<TaskDefinition> {
}
void Trace(blink::Visitor* visitor) {
- visitor->Trace(instance_.Cast<v8::Value>());
- visitor->Trace(process_.Cast<v8::Value>());
+ visitor->Trace(instance_);
+ visitor->Trace(process_);
}
private:
@@ -92,7 +92,8 @@ void TaskWorkletGlobalScope::registerTask(const String& name,
return;
}
- TaskDefinition* definition = new TaskDefinition(isolate, instance, process);
+ TaskDefinition* definition =
+ MakeGarbageCollected<TaskDefinition>(isolate, instance, process);
task_definitions_.Set(name, definition);
}
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.cc b/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.cc
index bf4e433a239..93e729cbc3c 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.cc
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/core/workers/experimental/thread_pool.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/public/platform/dedicated_worker_factory.mojom-blink.h"
+#include "third_party/blink/public/mojom/worker/dedicated_worker_factory.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
@@ -78,7 +78,7 @@ const char ThreadPool::kSupplementName[] = "ThreadPool";
ThreadPool* ThreadPool::From(Document& document) {
ThreadPool* thread_pool = Supplement<Document>::From<ThreadPool>(document);
if (!thread_pool) {
- thread_pool = new ThreadPool(document);
+ thread_pool = MakeGarbageCollected<ThreadPool>(document);
Supplement<Document>::ProvideTo(document, thread_pool);
}
return thread_pool;
@@ -104,14 +104,16 @@ ThreadPoolThread* ThreadPool::CreateNewThread() {
: base::UnguessableToken::Create();
ExecutionContext* context = GetExecutionContext();
- ThreadPoolMessagingProxy* proxy = new ThreadPoolMessagingProxy(context);
+ ThreadPoolMessagingProxy* proxy =
+ MakeGarbageCollected<ThreadPoolMessagingProxy>(context);
std::unique_ptr<WorkerSettings> settings =
std::make_unique<WorkerSettings>(GetFrame()->GetSettings());
// WebWorkerFetchContext is provided later in
// ThreadedMessagingProxyBase::InitializeWorkerThread().
proxy->StartWorker(std::make_unique<GlobalScopeCreationParams>(
- context->Url(), mojom::ScriptType::kClassic, context->UserAgent(),
+ context->Url(), mojom::ScriptType::kClassic,
+ OffMainThreadWorkerScriptFetchOption::kDisabled, context->UserAgent(),
nullptr /* web_worker_fetch_context */,
context->GetContentSecurityPolicy()->Headers(),
network::mojom::ReferrerPolicy::kDefault, context->GetSecurityOrigin(),
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.h b/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.h
index ff651fa06cc..9e4b4e55549 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.h
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool.h
@@ -22,6 +22,8 @@ class ThreadPool final : public GarbageCollectedFinalized<ThreadPool>,
public:
static const char kSupplementName[];
static ThreadPool* From(Document&);
+
+ ThreadPool(Document&);
~ThreadPool();
ThreadPoolThread* GetLeastBusyThread() override;
@@ -29,8 +31,6 @@ class ThreadPool final : public GarbageCollectedFinalized<ThreadPool>,
void Trace(blink::Visitor*) final;
private:
- ThreadPool(Document&);
-
ThreadPoolThread* CreateNewThread();
HeapHashSet<Member<ThreadPoolMessagingProxy>> thread_proxies_;
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc b/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc
index a6371c7adb4..b7c67eceb36 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc
@@ -45,6 +45,11 @@ class ThreadPoolWorkerGlobalScope final : public WorkerGlobalScope {
}
void ExceptionThrown(ErrorEvent*) override {}
+
+ mojom::RequestContextType GetDestinationForMainScript() override {
+ // TODO(nhiroki): Return an appropriate destination.
+ return mojom::RequestContextType::WORKER;
+ }
};
} // anonymous namespace
@@ -61,9 +66,12 @@ ThreadPoolThread::ThreadPoolThread(ExecutionContext* parent_execution_context,
WorkerOrWorkletGlobalScope* ThreadPoolThread::CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) {
- if (backing_policy_ == kWorker)
- return new ThreadPoolWorkerGlobalScope(std::move(creation_params), this);
- return new TaskWorkletGlobalScope(std::move(creation_params), this);
+ if (backing_policy_ == kWorker) {
+ return MakeGarbageCollected<ThreadPoolWorkerGlobalScope>(
+ std::move(creation_params), this);
+ }
+ return MakeGarbageCollected<TaskWorkletGlobalScope>(
+ std::move(creation_params), this);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.cc b/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.cc
index 45c42286143..f88f0acab61 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.cc
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.cc
@@ -31,7 +31,7 @@ WorkerTaskQueue* WorkerTaskQueue::Create(ExecutionContext* context,
DCHECK(type == "user-interaction" || type == "background");
TaskType task_type = type == "user-interaction" ? TaskType::kUserInteraction
: TaskType::kIdleTask;
- return new WorkerTaskQueue(document, task_type);
+ return MakeGarbageCollected<WorkerTaskQueue>(document, task_type);
}
WorkerTaskQueue::WorkerTaskQueue(Document* document, TaskType task_type)
@@ -45,8 +45,9 @@ ScriptPromise WorkerTaskQueue::postFunction(
DCHECK(document_->IsContextThread());
DCHECK(function.IsFunction());
- Task* task = new Task(ThreadPool::From(*document_), script_state, function,
- arguments, task_type_);
+ Task* task =
+ MakeGarbageCollected<Task>(ThreadPool::From(*document_), script_state,
+ function, arguments, task_type_);
if (signal)
signal->AddAlgorithm(WTF::Bind(&Task::cancel, WrapWeakPersistent(task)));
return task->result(script_state);
@@ -57,8 +58,8 @@ Task* WorkerTaskQueue::postTask(ScriptState* script_state,
const Vector<ScriptValue>& arguments) {
DCHECK(document_->IsContextThread());
DCHECK(function.IsFunction());
- return new Task(ThreadPool::From(*document_), script_state, function,
- arguments, task_type_);
+ return MakeGarbageCollected<Task>(ThreadPool::From(*document_), script_state,
+ function, arguments, task_type_);
}
void WorkerTaskQueue::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.h b/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.h
index 0872c73a929..8608af162db 100644
--- a/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.h
+++ b/chromium/third_party/blink/renderer/core/workers/experimental/worker_task_queue.h
@@ -27,6 +27,8 @@ class CORE_EXPORT WorkerTaskQueue : public ScriptWrappable {
static WorkerTaskQueue* Create(ExecutionContext*,
const String&,
ExceptionState&);
+
+ WorkerTaskQueue(Document*, TaskType);
~WorkerTaskQueue() override = default;
ScriptPromise postFunction(ScriptState*,
@@ -41,8 +43,6 @@ class CORE_EXPORT WorkerTaskQueue : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
- WorkerTaskQueue(Document*, TaskType);
-
Member<Document> document_;
const TaskType task_type_;
};
diff --git a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
index 51b2c32b5e8..0e51209ff06 100644
--- a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
+++ b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
@@ -6,12 +6,14 @@
#include <memory>
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
GlobalScopeCreationParams::GlobalScopeCreationParams(
const KURL& script_url,
mojom::ScriptType script_type,
+ OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option,
const String& user_agent,
scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context,
const Vector<CSPHeaderAndType>& content_security_policy_parsed_headers,
@@ -33,6 +35,7 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
base::UnguessableToken agent_cluster_id)
: script_url(script_url.Copy()),
script_type(script_type),
+ off_main_thread_fetch_option(off_main_thread_fetch_option),
user_agent(user_agent.IsolatedCopy()),
web_worker_fetch_context(std::move(web_worker_fetch_context)),
referrer_policy(referrer_policy),
@@ -54,6 +57,19 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
ParsedFeaturePolicy() /* container_policy */,
starter_origin->ToUrlOrigin())),
agent_cluster_id(agent_cluster_id) {
+ switch (this->script_type) {
+ case mojom::ScriptType::kClassic:
+ if (this->off_main_thread_fetch_option ==
+ OffMainThreadWorkerScriptFetchOption::kEnabled) {
+ DCHECK(RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled());
+ }
+ break;
+ case mojom::ScriptType::kModule:
+ DCHECK_EQ(this->off_main_thread_fetch_option,
+ OffMainThreadWorkerScriptFetchOption::kEnabled);
+ break;
+ }
+
this->content_security_policy_parsed_headers.ReserveInitialCapacity(
content_security_policy_parsed_headers.size());
for (const auto& header : content_security_policy_parsed_headers) {
diff --git a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h
index 113e5d0773b..af7ed99bf53 100644
--- a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h
+++ b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h
@@ -7,7 +7,6 @@
#include <memory>
#include "base/macros.h"
-#include "base/optional.h"
#include "base/unguessable_token.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
@@ -18,14 +17,11 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/core/script/script.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
#include "third_party/blink/renderer/core/workers/worker_settings.h"
#include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h"
#include "third_party/blink/renderer/platform/graphics/begin_frame_provider.h"
#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
-#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
-#include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -33,6 +29,10 @@ namespace blink {
class WorkerClients;
+// TODO(nhiroki): Remove this option after off-the-main-thread worker script
+// fetch is enabled for all worker types (https://crbug.com/835717).
+enum class OffMainThreadWorkerScriptFetchOption { kDisabled, kEnabled };
+
// GlobalScopeCreationParams contains parameters for initializing
// WorkerGlobalScope or WorkletGlobalScope.
struct CORE_EXPORT GlobalScopeCreationParams final {
@@ -42,6 +42,7 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
GlobalScopeCreationParams(
const KURL& script_url,
mojom::ScriptType script_type,
+ OffMainThreadWorkerScriptFetchOption,
const String& user_agent,
scoped_refptr<WebWorkerFetchContext>,
const Vector<CSPHeaderAndType>& content_security_policy_parsed_headers,
@@ -78,17 +79,13 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
KURL script_url;
mojom::ScriptType script_type;
+ OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option;
+
String user_agent;
scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context;
- // |content_security_policy_parsed_headers| and
- // |content_security_policy_raw_headers| are mutually exclusive.
- // |content_security_policy_parsed_headers| is an empty vector
- // when |content_security_policy_raw_headers| is set.
Vector<CSPHeaderAndType> content_security_policy_parsed_headers;
- base::Optional<ContentSecurityPolicyResponseHeaders>
- content_security_policy_raw_headers;
network::mojom::ReferrerPolicy referrer_policy;
std::unique_ptr<Vector<String>> origin_trial_tokens;
diff --git a/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc b/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
index 6e9e5b9d44a..9231b4dd750 100644
--- a/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
+++ b/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
@@ -13,7 +13,7 @@ namespace blink {
InstalledScriptsManager::ScriptData::ScriptData(
const KURL& script_url,
String source_text,
- std::unique_ptr<Vector<char>> meta_data,
+ std::unique_ptr<Vector<uint8_t>> meta_data,
std::unique_ptr<CrossThreadHTTPHeaderMapData> header_data)
: script_url_(script_url),
source_text_(std::move(source_text)),
diff --git a/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.h b/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.h
index 6e267a056d8..6aa7363b0a1 100644
--- a/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.h
+++ b/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.h
@@ -25,13 +25,13 @@ class InstalledScriptsManager {
ScriptData() = default;
ScriptData(const KURL& script_url,
String source_text,
- std::unique_ptr<Vector<char>> meta_data,
+ std::unique_ptr<Vector<uint8_t>> meta_data,
std::unique_ptr<CrossThreadHTTPHeaderMapData>);
ScriptData(ScriptData&& other) = default;
ScriptData& operator=(ScriptData&& other) = default;
String TakeSourceText() { return std::move(source_text_); }
- std::unique_ptr<Vector<char>> TakeMetaData() {
+ std::unique_ptr<Vector<uint8_t>> TakeMetaData() {
return std::move(meta_data_);
}
@@ -43,7 +43,7 @@ class InstalledScriptsManager {
private:
KURL script_url_;
String source_text_;
- std::unique_ptr<Vector<char>> meta_data_;
+ std::unique_ptr<Vector<uint8_t>> meta_data_;
HTTPHeaderMap headers_;
DISALLOW_COPY_AND_ASSIGN(ScriptData);
diff --git a/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc b/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
index 4df15f6fadb..70fc818364b 100644
--- a/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
@@ -64,7 +64,8 @@ class MainThreadWorkletTest : public PageTestBase {
reporting_proxy_ =
std::make_unique<MainThreadWorkletReportingProxyForTest>(document);
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled, document->UserAgent(),
nullptr /* web_worker_fetch_context */,
document->GetContentSecurityPolicy()->Headers(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
@@ -72,7 +73,8 @@ class MainThreadWorkletTest : public PageTestBase {
nullptr /* worker_clients */, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap);
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>());
global_scope_ = MakeGarbageCollected<WorkletGlobalScope>(
std::move(creation_params), *reporting_proxy_, &GetFrame());
EXPECT_TRUE(global_scope_->IsMainThreadWorkletGlobalScope());
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker.cc
index 4433a999d5f..f499d3123ff 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker.cc
@@ -34,13 +34,11 @@
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/messaging/message_channel.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/workers/shared_worker_repository_client.h"
+#include "third_party/blink/renderer/core/workers/shared_worker_client_holder.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -87,11 +85,18 @@ SharedWorker* SharedWorker::Create(ExecutionContext* context,
MakeRequest(&blob_url_token));
}
- if (document->GetFrame()->Client()->GetSharedWorkerRepositoryClient()) {
- document->GetFrame()->Client()->GetSharedWorkerRepositoryClient()->Connect(
- worker, std::move(remote_port), script_url, std::move(blob_url_token),
- name);
- }
+ // |name| should not be null according to the HTML spec, but the current impl
+ // wrongly allows it when |name| is omitted. See TODO comment in
+ // shared_worker.idl.
+ // TODO(nhiroki): Stop assigning null to |name| as a default value, and remove
+ // this hack.
+ String worker_name = "";
+ if (!name.IsNull())
+ worker_name = name;
+
+ SharedWorkerClientHolder::From(*document)->Connect(
+ worker, std::move(remote_port), script_url, std::move(blob_url_token),
+ worker_name);
return worker;
}
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker.idl b/chromium/third_party/blink/renderer/core/workers/shared_worker.idl
index e5b88eb9e39..c5b5399414a 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker.idl
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker.idl
@@ -33,7 +33,8 @@
[
ActiveScriptWrappable,
- // TODO(foolip): The name argument should not have a default null value.
+ // TODO(nhiroki): The second argument should be |optional (DOMString or
+ // WorkerOptions) options)|.
Constructor(DOMString scriptURL, optional DOMString name = null),
ConstructorCallWith=ExecutionContext,
// TODO(foolip): Exposed=(Window,Worker),
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_client.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_client.cc
new file mode 100644
index 00000000000..984bbf3b21a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_client.cc
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/workers/shared_worker_client.h"
+
+#include "base/logging.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/workers/shared_worker.h"
+
+namespace blink {
+
+SharedWorkerClient::SharedWorkerClient(SharedWorker* worker)
+ : worker_(worker) {}
+
+SharedWorkerClient::~SharedWorkerClient() {
+ // We have lost our connection to the worker. If this happens before
+ // OnConnected() is called, then it suggests that the document is gone or
+ // going away.
+}
+
+void SharedWorkerClient::OnCreated(
+ mojom::SharedWorkerCreationContextType creation_context_type) {
+ worker_->SetIsBeingConnected(true);
+
+ // No nested workers (for now) - connect() can only be called from a
+ // document context.
+ DCHECK(worker_->GetExecutionContext()->IsDocument());
+ DCHECK_EQ(creation_context_type,
+ worker_->GetExecutionContext()->IsSecureContext()
+ ? mojom::SharedWorkerCreationContextType::kSecure
+ : mojom::SharedWorkerCreationContextType::kNonsecure);
+}
+
+void SharedWorkerClient::OnConnected(
+ const Vector<mojom::WebFeature>& features_used) {
+ worker_->SetIsBeingConnected(false);
+ for (auto feature : features_used)
+ OnFeatureUsed(feature);
+}
+
+void SharedWorkerClient::OnScriptLoadFailed() {
+ worker_->DispatchEvent(*Event::CreateCancelable(event_type_names::kError));
+ worker_->SetIsBeingConnected(false);
+}
+
+void SharedWorkerClient::OnFeatureUsed(mojom::WebFeature feature) {
+ UseCounter::Count(worker_->GetExecutionContext(), feature);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_client.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_client.h
new file mode 100644
index 00000000000..c9404f21950
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_client.h
@@ -0,0 +1,37 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CLIENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CLIENT_H_
+
+#include "third_party/blink/public/mojom/worker/shared_worker_client.mojom-blink.h"
+
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+class SharedWorker;
+
+// This is a client that connects with a SharedWorkerHost in the browser
+// process. There can be multiple clients (including in different renderer
+// processes) per shared worker. Clients are managed by the owning document's
+// SharedWorkerClientHolder.
+class SharedWorkerClient final : public mojom::blink::SharedWorkerClient {
+ public:
+ explicit SharedWorkerClient(SharedWorker*);
+ ~SharedWorkerClient() override;
+
+ // mojom::blink::SharedWorkerClient overrides.
+ void OnCreated(mojom::SharedWorkerCreationContextType) override;
+ void OnConnected(const Vector<mojom::WebFeature>& features_used) override;
+ void OnScriptLoadFailed() override;
+ void OnFeatureUsed(mojom::WebFeature feature) override;
+
+ private:
+ Persistent<SharedWorker> worker_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc
new file mode 100644
index 00000000000..eab1ce5258c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "third_party/blink/renderer/core/workers/shared_worker_client_holder.h"
+
+#include <memory>
+#include <utility>
+#include "base/logging.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/mojom/worker/shared_worker_info.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_security_policy.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/blink.h"
+#include "third_party/blink/public/web/web_shared_worker.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/workers/shared_worker.h"
+#include "third_party/blink/renderer/core/workers/shared_worker_client.h"
+
+namespace blink {
+
+const char SharedWorkerClientHolder::kSupplementName[] =
+ "SharedWorkerClientHolder";
+
+SharedWorkerClientHolder* SharedWorkerClientHolder::From(Document& document) {
+ DCHECK(IsMainThread());
+ SharedWorkerClientHolder* holder =
+ Supplement<Document>::From<SharedWorkerClientHolder>(document);
+ if (!holder) {
+ holder = MakeGarbageCollected<SharedWorkerClientHolder>(document);
+ Supplement<Document>::ProvideTo(document, holder);
+ }
+ return holder;
+}
+
+SharedWorkerClientHolder::SharedWorkerClientHolder(Document& document)
+ : ContextLifecycleObserver(&document) {
+ DCHECK(IsMainThread());
+ document.GetInterfaceProvider()->GetInterface(mojo::MakeRequest(&connector_));
+}
+
+void SharedWorkerClientHolder::Connect(
+ SharedWorker* worker,
+ MessagePortChannel port,
+ const KURL& url,
+ mojom::blink::BlobURLTokenPtr blob_url_token,
+ const String& name) {
+ DCHECK(IsMainThread());
+ DCHECK(!name.IsNull());
+
+ // TODO(estark): this is broken, as it only uses the first header
+ // when multiple might have been sent. Fix by making the
+ // mojom::blink::SharedWorkerInfo take a map that can contain multiple
+ // headers.
+ Vector<CSPHeaderAndType> headers =
+ worker->GetExecutionContext()->GetContentSecurityPolicy()->Headers();
+ WebString header = "";
+ auto header_type = mojom::ContentSecurityPolicyType::kReport;
+ if (headers.size() > 0) {
+ header = headers[0].first;
+ header_type =
+ static_cast<mojom::ContentSecurityPolicyType>(headers[0].second);
+ }
+
+ mojom::blink::SharedWorkerInfoPtr info(mojom::blink::SharedWorkerInfo::New(
+ url, name, header, header_type,
+ worker->GetExecutionContext()->GetSecurityContext().AddressSpace()));
+
+ mojom::blink::SharedWorkerClientPtr client_ptr;
+ client_set_.AddBinding(std::make_unique<SharedWorkerClient>(worker),
+ mojo::MakeRequest(&client_ptr));
+
+ connector_->Connect(
+ std::move(info), std::move(client_ptr),
+ worker->GetExecutionContext()->IsSecureContext()
+ ? mojom::SharedWorkerCreationContextType::kSecure
+ : mojom::SharedWorkerCreationContextType::kNonsecure,
+ port.ReleaseHandle(),
+ mojom::blink::BlobURLTokenPtr(mojom::blink::BlobURLTokenPtrInfo(
+ blob_url_token.PassInterface().PassHandle(),
+ mojom::blink::BlobURLToken::Version_)));
+}
+
+void SharedWorkerClientHolder::ContextDestroyed(ExecutionContext*) {
+ DCHECK(IsMainThread());
+ // Close mojo connections which will signal disinterest in the associated
+ // shared worker.
+ client_set_.CloseAllBindings();
+}
+
+void SharedWorkerClientHolder::Trace(Visitor* visitor) {
+ Supplement<Document>::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.h
new file mode 100644
index 00000000000..64aabbc2a19
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CLIENT_HOLDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CLIENT_HOLDER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink.h"
+#include "third_party/blink/public/mojom/worker/shared_worker_client.mojom-blink.h"
+#include "third_party/blink/public/mojom/worker/shared_worker_connector.mojom-blink.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class MessagePortChannel;
+class KURL;
+class SharedWorker;
+
+// This holds SharedWorkerClients connecting with SharedWorkerHosts in the
+// browser process. Every call of SharedWorkerClientHolder::Connect() creates a
+// new client instance regardless of existing connections, and keeps it until
+// the connection gets lost.
+//
+// SharedWorkerClientHolder is a per-Document object and owned by Document via
+// Supplement<Document>.
+class CORE_EXPORT SharedWorkerClientHolder final
+ : public GarbageCollectedFinalized<SharedWorkerClientHolder>,
+ public Supplement<Document>,
+ public ContextLifecycleObserver {
+ USING_GARBAGE_COLLECTED_MIXIN(SharedWorkerClientHolder);
+
+ public:
+ static const char kSupplementName[];
+ static SharedWorkerClientHolder* From(Document& document);
+
+ explicit SharedWorkerClientHolder(Document&);
+ virtual ~SharedWorkerClientHolder() = default;
+
+ // Establishes a connection with SharedWorkerHost in the browser process.
+ void Connect(SharedWorker*,
+ MessagePortChannel,
+ const KURL&,
+ mojom::blink::BlobURLTokenPtr,
+ const String& name);
+
+ // Overrides ContextLifecycleObserver.
+ void ContextDestroyed(ExecutionContext*) override;
+
+ void Trace(Visitor* visitor) override;
+
+ private:
+ mojom::blink::SharedWorkerConnectorPtr connector_;
+ mojo::StrongBindingSet<mojom::blink::SharedWorkerClient> client_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedWorkerClientHolder);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CLIENT_HOLDER_H_
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h
index f1a3f2eec1e..77014004999 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h
@@ -5,9 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CONTENT_SETTINGS_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_CONTENT_SETTINGS_PROXY_H_
+#include "third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/web/worker_content_settings_proxy.mojom-blink.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
index c68d18e1b3d..3dfd2d97c97 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
@@ -72,13 +72,8 @@ void SharedWorkerGlobalScope::ImportModuleScript(
NOTREACHED();
}
-void SharedWorkerGlobalScope::ConnectPausable(MessagePortChannel channel) {
- if (IsContextPaused()) {
- AddPausedCall(WTF::Bind(&SharedWorkerGlobalScope::ConnectPausable,
- WrapWeakPersistent(this), std::move(channel)));
- return;
- }
-
+void SharedWorkerGlobalScope::Connect(MessagePortChannel channel) {
+ DCHECK(!IsContextPaused());
MessagePort* port = MessagePort::Create(*this);
port->Entangle(std::move(channel));
MessageEvent* event =
@@ -99,4 +94,9 @@ void SharedWorkerGlobalScope::Trace(blink::Visitor* visitor) {
WorkerGlobalScope::Trace(visitor);
}
+mojom::RequestContextType
+SharedWorkerGlobalScope::GetDestinationForMainScript() {
+ return mojom::RequestContextType::SHARED_WORKER;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
index 8b5a667f308..4f37a3ddd71 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
@@ -42,7 +42,7 @@ namespace blink {
class SharedWorkerThread;
-class SharedWorkerGlobalScope final : public WorkerGlobalScope {
+class CORE_EXPORT SharedWorkerGlobalScope final : public WorkerGlobalScope {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -67,12 +67,13 @@ class SharedWorkerGlobalScope final : public WorkerGlobalScope {
DEFINE_ATTRIBUTE_EVENT_LISTENER(connect, kConnect);
String name() const { return name_; }
- void ConnectPausable(MessagePortChannel channel);
+ void Connect(MessagePortChannel channel);
void Trace(blink::Visitor*) override;
private:
void ExceptionThrown(ErrorEvent*) override;
+ mojom::RequestContextType GetDestinationForMainScript() override;
const String name_;
};
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.cc
index a1def054e31..e9b606991f1 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.cc
@@ -47,7 +47,11 @@ void SharedWorkerReportingProxy::ReportException(
std::unique_ptr<SourceLocation>,
int exception_id) {
DCHECK(!IsMainThread());
- // Not suppported in SharedWorker.
+ // TODO(nhiroki): Implement the "runtime script errors" algorithm in the HTML
+ // spec:
+ // "For shared workers, if the error is still not handled afterwards, the
+ // error may be reported to a developer console."
+ // https://html.spec.whatwg.org/multipage/workers.html#runtime-script-errors-2
}
void SharedWorkerReportingProxy::ReportConsoleMessage(MessageSource,
@@ -58,6 +62,19 @@ void SharedWorkerReportingProxy::ReportConsoleMessage(MessageSource,
// Not supported in SharedWorker.
}
+void SharedWorkerReportingProxy::DidFailToFetchClassicScript() {
+ DCHECK(!IsMainThread());
+ // TODO(nhiroki): Dispatch an error event at the SharedWorker object in the
+ // parent document.
+}
+
+void SharedWorkerReportingProxy::DidFailToFetchModuleScript() {
+ DCHECK(!IsMainThread());
+ // TODO(nhiroki): Implement module scripts for shared workers.
+ // (https://crbug.com/824646)
+ NOTIMPLEMENTED();
+}
+
void SharedWorkerReportingProxy::DidCloseWorkerGlobalScope() {
DCHECK(!IsMainThread());
PostCrossThreadTask(
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.h
index ad84445fe28..fa0941ff05f 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.h
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_reporting_proxy.h
@@ -35,6 +35,8 @@ class SharedWorkerReportingProxy final
MessageLevel,
const String& message,
SourceLocation*) override;
+ void DidFailToFetchClassicScript() override;
+ void DidFailToFetchModuleScript() override;
void DidEvaluateClassicScript(bool success) override {}
void DidCloseWorkerGlobalScope() override;
void WillDestroyWorkerGlobalScope() override {}
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_repository_client.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_repository_client.h
deleted file mode 100644
index 16f7c62d1a8..00000000000
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_repository_client.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_REPOSITORY_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_REPOSITORY_CLIENT_H_
-
-#include "base/macros.h"
-#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-
-namespace blink {
-
-class Document;
-class MessagePortChannel;
-class KURL;
-class SharedWorker;
-
-class CORE_EXPORT SharedWorkerRepositoryClient {
- DISALLOW_NEW();
-
- public:
- SharedWorkerRepositoryClient() = default;
- virtual ~SharedWorkerRepositoryClient() = default;
-
- virtual void Connect(SharedWorker*,
- MessagePortChannel,
- const KURL&,
- mojom::blink::BlobURLTokenPtr,
- const String& name) = 0;
-
- virtual void DocumentDetached(Document*) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SharedWorkerRepositoryClient);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_REPOSITORY_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
index dc7d022c400..6eeb1fcade8 100644
--- a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
@@ -54,7 +54,8 @@ void ThreadedWorkletMessagingProxy::Initialize(
auto global_scope_creation_params =
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled, document->UserAgent(),
document->GetFrame()->Client()->CreateWorkerFetchContext(),
csp->Headers(), document->GetReferrerPolicy(),
document->GetSecurityOrigin(), document->IsSecureContext(),
diff --git a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
index 052cdb7a446..45198d0e030 100644
--- a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -203,15 +203,17 @@ class ThreadedWorkletMessagingProxyForTest
std::unique_ptr<WorkerSettings> worker_settings = nullptr;
InitializeWorkerThread(
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
- nullptr /* web_worker_fetch_context */,
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled,
+ document->UserAgent(), nullptr /* web_worker_fetch_context */,
document->GetContentSecurityPolicy()->Headers(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
document->IsSecureContext(), document->GetHttpsState(),
worker_clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), std::move(worker_settings),
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap),
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>()),
base::nullopt);
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
index c0cec745454..c404b0a5966 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -36,6 +36,9 @@
#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
@@ -47,21 +50,62 @@
namespace blink {
+namespace {
+
+// CheckSameOriginEnforcement() functions return non-null String on error.
+//
+// WorkerGlobalScope's SecurityOrigin is initialized to request URL's
+// origin at the construction of WorkerGlobalScope, while
+// WorkerGlobalScope's URL is set to response URL
+// (ResourceResponse::ResponseURL()).
+// These functions are used to ensure the SecurityOrigin and the URL to be
+// consistent. https://crbug.com/861564
+//
+// TODO(hiroshige): Merge with similar code in other places.
+String CheckSameOriginEnforcement(const KURL& request_url,
+ const KURL& response_url) {
+ if (request_url != response_url &&
+ !SecurityOrigin::AreSameSchemeHostPort(request_url, response_url)) {
+ return "Refused to load the top-level worker script from '" +
+ response_url.ElidedString() +
+ "' because it doesn't match the origin of the request URL '" +
+ request_url.ElidedString() + "'";
+ }
+ return String();
+}
+
+String CheckSameOriginEnforcement(const KURL& request_url,
+ const ResourceResponse& response) {
+ // While this check is not strictly necessary as CurrentRequestUrl() is not
+ // used as WorkerGlobalScope's URL, it is probably safer to reject cases like
+ // Origin A(request_url)
+ // =(cross-origin redirects)=> Origin B(CurrentRequestUrl())
+ // =(ServiceWorker interception)=> Origin A(ResponseUrl())
+ // which doesn't seem to have valid use cases.
+ String error =
+ CheckSameOriginEnforcement(request_url, response.CurrentRequestUrl());
+ if (!error.IsNull())
+ return error;
+
+ // This check is directly required to ensure the consistency between
+ // WorkerGlobalScope's SecurityOrigin and URL.
+ return CheckSameOriginEnforcement(request_url, response.ResponseUrl());
+}
+
+} // namespace
+
WorkerClassicScriptLoader::WorkerClassicScriptLoader()
- : response_address_space_(mojom::IPAddressSpace::kPublic),
- mime_type_check_mode_(AllowedByNosniff::MimeTypeCheck::kStrict) {}
+ : response_address_space_(mojom::IPAddressSpace::kPublic) {}
void WorkerClassicScriptLoader::LoadSynchronously(
ExecutionContext& execution_context,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
const KURL& url,
mojom::RequestContextType request_context,
mojom::IPAddressSpace creation_address_space) {
+ DCHECK(fetch_client_settings_object_fetcher);
url_ = url;
- execution_context_ = &execution_context;
-
- // Impose strict MIME-type checks on importScripts(). See
- // https://crbug.com/794548.
- mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kStrict;
+ fetch_client_settings_object_fetcher_ = fetch_client_settings_object_fetcher;
ResourceRequest request(url);
request.SetHTTPMethod(http_names::kGET);
@@ -77,50 +121,30 @@ void WorkerClassicScriptLoader::LoadSynchronously(
resource_loader_options.synchronous_policy = kRequestSynchronously;
threadable_loader_ = MakeGarbageCollected<ThreadableLoader>(
- execution_context, this, resource_loader_options);
+ execution_context, this, resource_loader_options,
+ fetch_client_settings_object_fetcher);
threadable_loader_->Start(request);
}
void WorkerClassicScriptLoader::LoadTopLevelScriptAsynchronously(
ExecutionContext& execution_context,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
const KURL& url,
mojom::RequestContextType request_context,
network::mojom::FetchRequestMode fetch_request_mode,
network::mojom::FetchCredentialsMode fetch_credentials_mode,
mojom::IPAddressSpace creation_address_space,
- bool is_nested_worker,
base::OnceClosure response_callback,
base::OnceClosure finished_callback) {
+ DCHECK(fetch_client_settings_object_fetcher);
DCHECK(response_callback || finished_callback);
response_callback_ = std::move(response_callback);
finished_callback_ = std::move(finished_callback);
url_ = url;
- execution_context_ = &execution_context;
- forbid_cross_origin_redirects_ = true;
-
- if (execution_context.IsDocument()) {
- // For worker creation on a document, don't impose strict MIME-type checks
- // on the top-level worker script for backward compatibility. Note that
- // there is a plan to deprecate legacy mime types for workers. See
- // https://crbug.com/794548.
- mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kLax;
- } else {
- DCHECK(execution_context.IsWorkerGlobalScope());
- if (is_nested_worker) {
- // For nested workers, impose the strict MIME-type checks because the
- // feature is new (enabled by default in M69) and there is no backward
- // compatibility issue.
- mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kStrict;
- } else {
- // For worker creation on a document with off-the-main-thread top-level
- // worker classic script loading, don't impose strict MIME-type checks for
- // backward compatibility.
- // TODO(nhiroki): Always impose strict MIME-type checks on all web
- // workers (https://crbug.com/794548).
- DCHECK(RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled());
- mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kLax;
- }
- }
+ fetch_client_settings_object_fetcher_ = fetch_client_settings_object_fetcher;
+ is_top_level_script_ = true;
+
+ is_worker_global_scope_ = execution_context.IsWorkerGlobalScope();
ResourceRequest request(url);
request.SetHTTPMethod(http_names::kGET);
@@ -132,7 +156,8 @@ void WorkerClassicScriptLoader::LoadTopLevelScriptAsynchronously(
need_to_cancel_ = true;
threadable_loader_ = MakeGarbageCollected<ThreadableLoader>(
- execution_context, this, ResourceLoaderOptions());
+ execution_context, this, ResourceLoaderOptions(),
+ fetch_client_settings_object_fetcher);
threadable_loader_->Start(request);
if (failed_)
NotifyFinished();
@@ -152,31 +177,29 @@ void WorkerClassicScriptLoader::DidReceiveResponse(
NotifyError();
return;
}
- if (!AllowedByNosniff::MimeTypeAsScript(execution_context_, response,
- mime_type_check_mode_)) {
+ if (!AllowedByNosniff::MimeTypeAsScript(
+ fetch_client_settings_object_fetcher_->Context(),
+ fetch_client_settings_object_fetcher_->GetConsoleLogger(), response,
+ fetch_client_settings_object_fetcher_->GetProperties()
+ .GetFetchClientSettingsObject()
+ .MimeTypeCheckForClassicWorkerScript(),
+ is_worker_global_scope_)) {
NotifyError();
return;
}
- if (forbid_cross_origin_redirects_ && url_ != response.Url() &&
- !SecurityOrigin::AreSameSchemeHostPort(url_, response.Url())) {
- // Forbid cross-origin redirects to ensure the request and response URLs
- // have the same SecurityOrigin.
- execution_context_->AddConsoleMessage(ConsoleMessage::Create(
- kSecurityMessageSource, kErrorMessageLevel,
- "Refused to cross-origin redirects of the top-level worker script."));
- NotifyError();
- return;
+ if (is_top_level_script_) {
+ String error = CheckSameOriginEnforcement(url_, response);
+ if (!error.IsNull()) {
+ fetch_client_settings_object_fetcher_->GetConsoleLogger()
+ ->AddErrorMessage(ConsoleLogger::Source::kSecurity, error);
+ NotifyError();
+ return;
+ }
}
identifier_ = identifier;
- if (response.WasFetchedViaServiceWorker() &&
- !response.OriginalURLViaServiceWorker().IsEmpty()) {
- response_url_ = response.OriginalURLViaServiceWorker();
- } else {
- response_url_ = response.Url();
- }
-
+ response_url_ = response.ResponseUrl();
response_encoding_ = response.TextEncodingName();
app_cache_id_ = response.AppCacheID();
@@ -215,7 +238,7 @@ void WorkerClassicScriptLoader::DidReceiveData(const char* data, unsigned len) {
void WorkerClassicScriptLoader::DidReceiveCachedMetadata(const char* data,
int size) {
- cached_metadata_ = std::make_unique<Vector<char>>(size);
+ cached_metadata_ = std::make_unique<Vector<uint8_t>>(size);
memcpy(cached_metadata_->data(), data, size);
}
@@ -242,7 +265,7 @@ void WorkerClassicScriptLoader::DidFailRedirectCheck() {
void WorkerClassicScriptLoader::Trace(Visitor* visitor) {
visitor->Trace(threadable_loader_);
visitor->Trace(content_security_policy_);
- visitor->Trace(execution_context_);
+ visitor->Trace(fetch_client_settings_object_fetcher_);
ThreadableLoaderClient::Trace(visitor);
}
@@ -284,11 +307,12 @@ void WorkerClassicScriptLoader::ProcessContentSecurityPolicy(
// directly. Otherwise, the Worker inherits the policy from the parent
// document (which is implemented in WorkerMessagingProxy, and
// m_contentSecurityPolicy should be left as nullptr to inherit the policy).
- if (!response.Url().ProtocolIs("blob") &&
- !response.Url().ProtocolIs("file") &&
- !response.Url().ProtocolIs("filesystem")) {
+ if (!response.CurrentRequestUrl().ProtocolIs("blob") &&
+ !response.CurrentRequestUrl().ProtocolIs("file") &&
+ !response.CurrentRequestUrl().ProtocolIs("filesystem")) {
content_security_policy_ = ContentSecurityPolicy::Create();
- content_security_policy_->SetOverrideURLForSelf(response.Url());
+ content_security_policy_->SetOverrideURLForSelf(
+ response.CurrentRequestUrl());
content_security_policy_->DidReceiveHeaders(
ContentSecurityPolicyResponseHeaders(response));
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
index 55810312926..c12b7dd4936 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
@@ -35,9 +35,9 @@
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/core/loader/allowed_by_nosniff.h"
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -62,21 +62,26 @@ class CORE_EXPORT WorkerClassicScriptLoader final
// For importScript().
void LoadSynchronously(ExecutionContext&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
const KURL&,
mojom::RequestContextType,
mojom::IPAddressSpace);
// Note that callbacks could be invoked before
// LoadTopLevelScriptAsynchronously() returns.
- void LoadTopLevelScriptAsynchronously(ExecutionContext&,
- const KURL&,
- mojom::RequestContextType,
- network::mojom::FetchRequestMode,
- network::mojom::FetchCredentialsMode,
- mojom::IPAddressSpace,
- bool is_nested_worker,
- base::OnceClosure response_callback,
- base::OnceClosure finished_callback);
+ //
+ // |fetch_client_settings_object_fetcher| is different from
+ // ExecutionContext::Fetcher() in off-the-main-thread fetch.
+ void LoadTopLevelScriptAsynchronously(
+ ExecutionContext&,
+ ResourceFetcher* fetch_client_settings_object_fetcher,
+ const KURL&,
+ mojom::RequestContextType,
+ network::mojom::FetchRequestMode,
+ network::mojom::FetchCredentialsMode,
+ mojom::IPAddressSpace,
+ base::OnceClosure response_callback,
+ base::OnceClosure finished_callback);
// This will immediately invoke |finishedCallback| if
// LoadTopLevelScriptAsynchronously() is in progress.
@@ -90,7 +95,7 @@ class CORE_EXPORT WorkerClassicScriptLoader final
unsigned long Identifier() const { return identifier_; }
long long AppCacheID() const { return app_cache_id_; }
- std::unique_ptr<Vector<char>> ReleaseCachedMetadata() {
+ std::unique_ptr<Vector<uint8_t>> ReleaseCachedMetadata() {
return std::move(cached_metadata_);
}
@@ -142,19 +147,20 @@ class CORE_EXPORT WorkerClassicScriptLoader final
bool canceled_ = false;
bool need_to_cancel_ = false;
- bool forbid_cross_origin_redirects_ = false;
+ // true when LoadTopLevelScriptAsynchronously() is called,
+ // false when LoadSynchronously() is called i.e. for importScripts().
+ bool is_top_level_script_ = false;
unsigned long identifier_ = 0;
long long app_cache_id_ = 0;
- std::unique_ptr<Vector<char>> cached_metadata_;
+ std::unique_ptr<Vector<uint8_t>> cached_metadata_;
Member<ContentSecurityPolicy> content_security_policy_;
- Member<ExecutionContext> execution_context_;
mojom::IPAddressSpace response_address_space_;
std::unique_ptr<Vector<String>> origin_trial_tokens_;
String referrer_policy_;
- // TODO(nhiroki): Move this to FetchClientSettingsObject.
- AllowedByNosniff::MimeTypeCheck mime_type_check_mode_;
+ bool is_worker_global_scope_ = false;
+ Member<ResourceFetcher> fetch_client_settings_object_fetcher_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 78d29e65477..016a33da903 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -32,13 +32,13 @@
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script_url.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/core/css/font_face_set_worker.h"
#include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/core/events/error_event.h"
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/frame/dom_timer_coordinator.h"
@@ -50,7 +50,10 @@
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h"
#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
#include "third_party/blink/renderer/core/workers/installed_scripts_manager.h"
#include "third_party/blink/renderer/core/workers/worker_classic_script_loader.h"
@@ -103,7 +106,6 @@ KURL WorkerGlobalScope::CompleteURL(const String& url) const {
void WorkerGlobalScope::Dispose() {
DCHECK(IsContextThread());
closing_ = true;
- paused_calls_.clear();
WorkerOrWorkletGlobalScope::Dispose();
}
@@ -123,7 +125,7 @@ WorkerLocation* WorkerGlobalScope::location() const {
WorkerNavigator* WorkerGlobalScope::navigator() const {
if (!navigator_)
- navigator_ = WorkerNavigator::Create(user_agent_);
+ navigator_ = WorkerNavigator::Create(user_agent_, GetExecutionContext());
return navigator_.Get();
}
@@ -137,10 +139,26 @@ String WorkerGlobalScope::origin() const {
return GetSecurityOrigin()->ToString();
}
+void WorkerGlobalScope::importScripts(
+ const HeapVector<StringOrTrustedScriptURL>& urls,
+ ExceptionState& exception_state) {
+ Vector<String> string_urls;
+ for (const StringOrTrustedScriptURL& stringOrUrl : urls) {
+ // TODO(vogelheim): Re-implement Trusted Types logic when supported by
+ // workers.
+ String string_url = stringOrUrl.IsString()
+ ? stringOrUrl.GetAsString()
+ : stringOrUrl.GetAsTrustedScriptURL()->toString();
+ string_urls.push_back(string_url);
+ }
+ importScriptsFromStrings(string_urls, exception_state);
+}
+
// Implementation of the "importScripts()" algorithm:
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerglobalscope-importscripts
-void WorkerGlobalScope::importScripts(const Vector<String>& urls,
- ExceptionState& exception_state) {
+void WorkerGlobalScope::importScriptsFromStrings(
+ const Vector<String>& urls,
+ ExceptionState& exception_state) {
DCHECK(GetContentSecurityPolicy());
DCHECK(GetExecutionContext());
@@ -175,7 +193,7 @@ void WorkerGlobalScope::importScripts(const Vector<String>& urls,
for (const KURL& complete_url : completed_urls) {
KURL response_url;
String source_code;
- std::unique_ptr<Vector<char>> cached_meta_data;
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data;
LoadResult result = LoadResult::kNotHandled;
result = LoadScriptFromInstalledScriptsManager(
complete_url, &response_url, &source_code, &cached_meta_data);
@@ -229,7 +247,7 @@ WorkerGlobalScope::LoadScriptFromInstalledScriptsManager(
const KURL& script_url,
KURL* out_response_url,
String* out_source_code,
- std::unique_ptr<Vector<char>>* out_cached_meta_data) {
+ std::unique_ptr<Vector<uint8_t>>* out_cached_meta_data) {
if (!GetThread()->GetInstalledScriptsManager() ||
!GetThread()->GetInstalledScriptsManager()->IsScriptInstalled(
script_url)) {
@@ -251,12 +269,14 @@ WorkerGlobalScope::LoadScriptFromClassicScriptLoader(
const KURL& script_url,
KURL* out_response_url,
String* out_source_code,
- std::unique_ptr<Vector<char>>* out_cached_meta_data) {
+ std::unique_ptr<Vector<uint8_t>>* out_cached_meta_data) {
ExecutionContext* execution_context = GetExecutionContext();
WorkerClassicScriptLoader* classic_script_loader =
MakeGarbageCollected<WorkerClassicScriptLoader>();
+ EnsureFetcher();
classic_script_loader->LoadSynchronously(
- *execution_context, script_url, mojom::RequestContextType::SCRIPT,
+ *execution_context, Fetcher(), script_url,
+ mojom::RequestContextType::SCRIPT,
execution_context->GetSecurityContext().AddressSpace());
// If the fetching attempt failed, throw a NetworkError exception and
@@ -315,61 +335,33 @@ ExecutionContext* WorkerGlobalScope::GetExecutionContext() const {
return const_cast<WorkerGlobalScope*>(this);
}
-void WorkerGlobalScope::TasksWereUnpaused() {
- WorkerOrWorkletGlobalScope::TasksWereUnpaused();
- // We cannot run the paused tasks right away, as there might be some other
- // code that still needs to be run synchronously.
- GetTaskRunner(TaskType::kInternalWorker)
- ->PostTask(FROM_HERE, WTF::Bind(&WorkerGlobalScope::MaybeRunPausedTasks,
- WrapWeakPersistent(this)));
-}
-
-void WorkerGlobalScope::MaybeRunPausedTasks() {
- if (IsContextPaused())
- return;
- Vector<base::OnceClosure> calls;
- paused_calls_.swap(calls);
- for (auto& call : calls)
- std::move(call).Run();
-}
-
-void WorkerGlobalScope::EvaluateClassicScriptPausable(
+void WorkerGlobalScope::EvaluateClassicScript(
const KURL& script_url,
String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
const v8_inspector::V8StackTraceId& stack_id) {
- if (IsContextPaused()) {
- AddPausedCall(WTF::Bind(&WorkerGlobalScope::EvaluateClassicScriptPausable,
- WrapWeakPersistent(this), script_url, source_code,
- WTF::Passed(std::move(cached_meta_data)),
- stack_id));
- return;
- }
+ DCHECK(!IsContextPaused());
ThreadDebugger* debugger = ThreadDebugger::From(GetThread()->GetIsolate());
if (debugger)
debugger->ExternalAsyncTaskStarted(stack_id);
- EvaluateClassicScript(script_url, source_code, std::move(cached_meta_data));
+ EvaluateClassicScriptInternal(script_url, source_code,
+ std::move(cached_meta_data));
if (debugger)
debugger->ExternalAsyncTaskFinished(stack_id);
}
// https://html.spec.whatwg.org/multipage/workers.html#worker-processing-model
-void WorkerGlobalScope::ImportClassicScriptPausable(
+void WorkerGlobalScope::ImportClassicScript(
const KURL& script_url,
FetchClientSettingsObjectSnapshot* outside_settings_object,
const v8_inspector::V8StackTraceId& stack_id) {
DCHECK(RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled());
- if (IsContextPaused()) {
- AddPausedCall(WTF::Bind(&WorkerGlobalScope::ImportClassicScriptPausable,
- WrapWeakPersistent(this), script_url,
- WrapPersistent(outside_settings_object), stack_id));
- return;
- }
+ DCHECK(!IsContextPaused());
// Step 12. "Fetch a classic worker script given url, outside settings,
// destination, and inside settings."
- // TODO(nhiroki): Load a main script using |outside_settings_object|.
- // (https://crbug.com/835717, https://crbug.com/880027)
+ mojom::RequestContextType destination = GetDestinationForMainScript();
+ DCHECK_EQ(mojom::RequestContextType::WORKER, destination);
// Step 12.1. "Set request's reserved client to inside settings."
// The browesr process takes care of this.
@@ -380,10 +372,10 @@ void WorkerGlobalScope::ImportClassicScriptPausable(
WorkerClassicScriptLoader* classic_script_loader =
MakeGarbageCollected<WorkerClassicScriptLoader>();
classic_script_loader->LoadTopLevelScriptAsynchronously(
- *execution_context, script_url, mojom::RequestContextType::WORKER,
- network::mojom::FetchRequestMode::kSameOrigin,
+ *execution_context, CreateOutsideSettingsFetcher(outside_settings_object),
+ script_url, destination, network::mojom::FetchRequestMode::kSameOrigin,
network::mojom::FetchCredentialsMode::kSameOrigin,
- GetSecurityContext().AddressSpace(), IsNestedWorker(),
+ GetSecurityContext().AddressSpace(),
WTF::Bind(&WorkerGlobalScope::DidReceiveResponseForClassicScript,
WrapWeakPersistent(this),
WrapPersistent(classic_script_loader)),
@@ -411,9 +403,7 @@ void WorkerGlobalScope::DidImportClassicScript(
// Step 12.1. "Queue a task to fire an event named error at worker."
// Step 12.2. "Run the environment discarding steps for inside settings."
// Step 12.3. "Return."
- ExceptionThrown(ErrorEvent::Create(
- "Failed to load a worker script: " + url_.GetString(),
- SourceLocation::Capture(), nullptr /* world */));
+ ReportingProxy().DidFailToFetchClassicScript();
return;
}
@@ -439,33 +429,13 @@ void WorkerGlobalScope::DidImportClassicScript(
// Step 13.7. "Asynchronously complete the perform the fetch steps with
// response."
-
- EvaluateClassicScriptPausable(
+ EvaluateClassicScript(
classic_script_loader->ResponseURL(), classic_script_loader->SourceText(),
classic_script_loader->ReleaseCachedMetadata(), stack_id);
}
-void WorkerGlobalScope::ImportModuleScriptPausable(
- const KURL& module_url_record,
- FetchClientSettingsObjectSnapshot* outside_settings_object,
- network::mojom::FetchCredentialsMode mode) {
- if (IsContextPaused()) {
- AddPausedCall(WTF::Bind(&WorkerGlobalScope::ImportModuleScriptPausable,
- WrapWeakPersistent(this), module_url_record,
- WrapPersistent(outside_settings_object), mode));
- return;
- }
- ImportModuleScript(module_url_record, outside_settings_object, mode);
-}
-
-void WorkerGlobalScope::ReceiveMessagePausable(
- BlinkTransferableMessage message) {
- if (IsContextPaused()) {
- AddPausedCall(WTF::Bind(&WorkerGlobalScope::ReceiveMessagePausable,
- WrapWeakPersistent(this), std::move(message)));
- return;
- }
-
+void WorkerGlobalScope::ReceiveMessage(BlinkTransferableMessage message) {
+ DCHECK(!IsContextPaused());
MessagePortArray* ports =
MessagePort::EntanglePorts(*this, std::move(message.ports));
ThreadDebugger* debugger = ThreadDebugger::From(GetThread()->GetIsolate());
@@ -483,10 +453,10 @@ void WorkerGlobalScope::ReceiveMessagePausable(
debugger->ExternalAsyncTaskFinished(message.sender_stack_trace_id);
}
-void WorkerGlobalScope::EvaluateClassicScript(
+void WorkerGlobalScope::EvaluateClassicScriptInternal(
const KURL& script_url,
String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data) {
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data) {
DCHECK(IsContextThread());
SingleCachedMetadataHandler* handler =
CreateWorkerScriptCachedMetadataHandler(script_url,
@@ -504,10 +474,6 @@ void WorkerGlobalScope::EvaluateClassicScript(
ReportingProxy().DidEvaluateClassicScript(success);
}
-void WorkerGlobalScope::AddPausedCall(base::OnceClosure closure) {
- paused_calls_.push_back(std::move(closure));
-}
-
WorkerGlobalScope::WorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params,
WorkerThread* thread,
@@ -555,7 +521,8 @@ WorkerGlobalScope::WorkerGlobalScope(
// Set the referrer policy here for workers whose script is fetched on the
// main thread. For off-the-main-thread fetches, it is instead set after the
// script is fetched.
- if (IsScriptFetchedOnMainThread())
+ if (creation_params->off_main_thread_fetch_option ==
+ OffMainThreadWorkerScriptFetchOption::kDisabled)
SetReferrerPolicy(creation_params->referrer_policy);
SetAddressSpace(creation_params->address_space);
@@ -583,7 +550,8 @@ void WorkerGlobalScope::ApplyContentSecurityPolicyFromHeaders(
SetContentSecurityPolicy(csp);
}
GetContentSecurityPolicy()->DidReceiveHeaders(headers);
- GetContentSecurityPolicy()->BindToExecutionContext(GetExecutionContext());
+ GetContentSecurityPolicy()->BindToDelegate(
+ GetContentSecurityPolicyDelegate());
}
void WorkerGlobalScope::ExceptionThrown(ErrorEvent* event) {
@@ -635,18 +603,11 @@ void WorkerGlobalScope::SetWorkerSettings(
worker_settings_->GetGenericFontFamilySettings());
}
-bool WorkerGlobalScope::IsScriptFetchedOnMainThread() {
- if (script_type_ == mojom::ScriptType::kModule)
- return false;
- // It's now supported only for dedicated workers to load top-level classic
- // worker script off the main thread.
- // TODO(nhiroki): Support loading top-level classic worker script off the main
- // thread for shared workers and service workers.
- if (IsDedicatedWorkerGlobalScope() &&
- RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled()) {
- return false;
+TrustedTypePolicyFactory* WorkerGlobalScope::trustedTypes() {
+ if (!trusted_types_) {
+ trusted_types_ = TrustedTypePolicyFactory::Create(this);
}
- return true;
+ return trusted_types_.Get();
}
void WorkerGlobalScope::Trace(blink::Visitor* visitor) {
@@ -656,6 +617,7 @@ void WorkerGlobalScope::Trace(blink::Visitor* visitor) {
visitor->Trace(pending_error_events_);
visitor->Trace(font_selector_);
visitor->Trace(animation_frame_provider_);
+ visitor->Trace(trusted_types_);
WorkerOrWorkletGlobalScope::Trace(visitor);
Supplementable<WorkerGlobalScope>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h
index 8b45870c385..92c77ed01c0 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -61,6 +61,8 @@ class FontFaceSet;
class OffscreenFontSelector;
class V8VoidFunction;
class WorkerClassicScriptLoader;
+class StringOrTrustedScriptURL;
+class TrustedTypePolicyFactory;
class WorkerLocation;
class WorkerNavigator;
class WorkerThread;
@@ -79,7 +81,7 @@ class CORE_EXPORT WorkerGlobalScope
// Returns null if caching is not supported.
virtual SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
const KURL& script_url,
- const Vector<char>* meta_data) {
+ const Vector<uint8_t>* meta_data) {
return nullptr;
}
@@ -93,7 +95,7 @@ class CORE_EXPORT WorkerGlobalScope
// WorkerGlobalScope
WorkerGlobalScope* self() { return this; }
WorkerLocation* location() const;
- WorkerNavigator* navigator() const;
+ WorkerNavigator* navigator() const override;
void close();
bool isSecureContextForBindings() const {
return ExecutionContext::IsSecureContext();
@@ -102,11 +104,13 @@ class CORE_EXPORT WorkerGlobalScope
String origin() const;
DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(languagechange, kLanguagechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(rejectionhandled, kRejectionhandled);
DEFINE_ATTRIBUTE_EVENT_LISTENER(unhandledrejection, kUnhandledrejection);
// WorkerUtils
- virtual void importScripts(const Vector<String>& urls, ExceptionState&);
+ virtual void importScripts(const HeapVector<StringOrTrustedScriptURL>& urls,
+ ExceptionState&);
// ExecutionContext
const KURL& Url() const final { return url_; }
@@ -137,23 +141,24 @@ class CORE_EXPORT WorkerGlobalScope
ExecutionContext* GetExecutionContext() const final;
bool IsWindowOrWorkerGlobalScope() const final { return true; }
- // The following methods implement PausbaleObject semantic
- // so that WorkerGlobalScope can be paused.
- void EvaluateClassicScriptPausable(
- const KURL& script_url,
- String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data,
- const v8_inspector::V8StackTraceId& stack_id);
- void ImportClassicScriptPausable(
+ // These methods should be called in the scope of a pausable
+ // task runner. ie. They should not be called when the context
+ // is paused.
+ void EvaluateClassicScript(const KURL& script_url,
+ String source_code,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
+ const v8_inspector::V8StackTraceId& stack_id);
+ void ImportClassicScript(
const KURL& script_url,
FetchClientSettingsObjectSnapshot* outside_settings_object,
const v8_inspector::V8StackTraceId& stack_id);
- void ImportModuleScriptPausable(
+ // Imports the top-level module script for |module_url_record|.
+ virtual void ImportModuleScript(
const KURL& module_url_record,
FetchClientSettingsObjectSnapshot* outside_settings_object,
- network::mojom::FetchCredentialsMode);
- void ReceiveMessagePausable(BlinkTransferableMessage);
+ network::mojom::FetchCredentialsMode) = 0;
+ void ReceiveMessage(BlinkTransferableMessage);
base::TimeTicks TimeOrigin() const { return time_origin_; }
WorkerSettings* GetWorkerSettings() const { return worker_settings_.get(); }
@@ -173,8 +178,7 @@ class CORE_EXPORT WorkerGlobalScope
return animation_frame_provider_;
}
- // Returns true when this is a nested worker.
- virtual bool IsNestedWorker() const { return false; }
+ TrustedTypePolicyFactory* trustedTypes();
protected:
WorkerGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
@@ -188,29 +192,18 @@ class CORE_EXPORT WorkerGlobalScope
void RemoveURLFromMemoryCache(const KURL&) final;
// Evaluates the given top-level classic script.
- virtual void EvaluateClassicScript(
+ virtual void EvaluateClassicScriptInternal(
const KURL& script_url,
String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data);
-
- // Imports the top-level module script for |module_url_record|.
- virtual void ImportModuleScript(
- const KURL& module_url_record,
- FetchClientSettingsObjectSnapshot* outside_settings_object,
- network::mojom::FetchCredentialsMode) = 0;
-
- void AddPausedCall(base::OnceClosure closure);
-
- void MaybeRunPausedTasks();
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data);
mojom::ScriptType GetScriptType() const { return script_type_; }
private:
- void SetWorkerSettings(std::unique_ptr<WorkerSettings>);
+ virtual void importScriptsFromStrings(const Vector<String>& urls,
+ ExceptionState&);
- // Returns true if this worker script is supposed to be fetched on the main
- // thread and passed to the worker thread.
- bool IsScriptFetchedOnMainThread();
+ void SetWorkerSettings(std::unique_ptr<WorkerSettings>);
void DidReceiveResponseForClassicScript(
WorkerClassicScriptLoader* classic_script_loader);
@@ -233,7 +226,7 @@ class CORE_EXPORT WorkerGlobalScope
const KURL& script_url,
KURL* out_response_url,
String* out_source_code,
- std::unique_ptr<Vector<char>>* out_cached_meta_data);
+ std::unique_ptr<Vector<uint8_t>>* out_cached_meta_data);
// Tries to load the script synchronously from the WorkerClassicScriptLoader,
// which requests the script from the browser. This blocks until the script is
@@ -242,11 +235,10 @@ class CORE_EXPORT WorkerGlobalScope
const KURL& script_url,
KURL* out_response_url,
String* out_source_code,
- std::unique_ptr<Vector<char>>* out_cached_meta_data);
+ std::unique_ptr<Vector<uint8_t>>* out_cached_meta_data);
// ExecutionContext
EventTarget* ErrorEventTarget() final { return this; }
- void TasksWereUnpaused() override;
const KURL url_;
const mojom::ScriptType script_type_;
@@ -257,6 +249,7 @@ class CORE_EXPORT WorkerGlobalScope
mutable Member<WorkerLocation> location_;
mutable TraceWrapperMember<WorkerNavigator> navigator_;
+ Member<TrustedTypePolicyFactory> trusted_types_;
WorkerThread* thread_;
@@ -277,8 +270,6 @@ class CORE_EXPORT WorkerGlobalScope
const base::UnguessableToken agent_cluster_id_;
HttpsState https_state_;
-
- Vector<base::OnceClosure> paused_calls_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.idl b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.idl
index 5926174c80e..23c7f0cbfa0 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.idl
+++ b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.idl
@@ -36,12 +36,12 @@
// TODO(foolip): onerror should be an OnErrorEventHandler.
attribute EventHandler onerror;
- // attribute EventHandler onlanguagechange;
+ attribute EventHandler onlanguagechange;
// attribute EventHandler onoffline;
// attribute EventHandler ononline;
// https://html.spec.whatwg.org/#apis-available-to-workers
- [RaisesException] void importScripts(DOMString... urls);
+ [RaisesException] void importScripts(ScriptURLString... urls);
readonly attribute WorkerNavigator navigator;
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_module_tree_client.cc b/chromium/third_party/blink/renderer/core/workers/worker_module_tree_client.cc
index c68d2f9e8a7..f6d9ab022ba 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_module_tree_client.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_module_tree_client.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/core/workers/worker_module_tree_client.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/events/error_event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/script/module_script.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -29,11 +28,7 @@ void WorkerModuleTreeClient::NotifyModuleTreeLoadFinished(
if (!module_script) {
// Step 12: "If the algorithm asynchronously completes with null, queue
// a task to fire an event named error at worker, and return."
- // This ErrorEvent object is just used for passing error information to a
- // worker object on the parent context thread and not dispatched directly.
- execution_context->ExceptionThrown(
- ErrorEvent::Create("Failed to load a module script.",
- SourceLocation::Capture(), nullptr /* world */));
+ worker_reporting_proxy.DidFailToFetchModuleScript();
return;
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc b/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc
index 166d2fdf592..b44d9ecf401 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc
@@ -25,11 +25,20 @@
*/
#include "third_party/blink/renderer/core/workers/worker_navigator.h"
+#include "third_party/blink/public/platform/web_worker_fetch_context.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
+#include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
namespace blink {
-WorkerNavigator::WorkerNavigator(const String& user_agent)
- : user_agent_(user_agent) {}
+WorkerNavigator::WorkerNavigator(const String& user_agent,
+ ExecutionContext* context)
+ : NavigatorLanguage(context), user_agent_(user_agent) {}
WorkerNavigator::~WorkerNavigator() = default;
@@ -37,8 +46,27 @@ String WorkerNavigator::userAgent() const {
return user_agent_;
}
+String WorkerNavigator::GetAcceptLanguages() {
+ WorkerOrWorkletGlobalScope* global_scope =
+ To<WorkerOrWorkletGlobalScope>(context_.Get());
+ WebWorkerFetchContext* worker_fetch_context =
+ static_cast<WorkerFetchContext*>(
+ (&global_scope->EnsureFetcher()->Context()))
+ ->GetWebWorkerFetchContext();
+ return worker_fetch_context->GetAcceptLanguages();
+}
+
+void WorkerNavigator::NotifyUpdate() {
+ SetLanguagesDirty();
+ WorkerOrWorkletGlobalScope* global_scope =
+ To<WorkerOrWorkletGlobalScope>(context_.Get());
+ global_scope->DispatchEvent(
+ *Event::Create(event_type_names::kLanguagechange));
+}
+
void WorkerNavigator::Trace(blink::Visitor* visitor) {
ScriptWrappable::Trace(visitor);
+ NavigatorLanguage::Trace(visitor);
Supplementable<WorkerNavigator>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_navigator.h b/chromium/third_party/blink/renderer/core/workers/worker_navigator.h
index 376f5995f97..9bf27656551 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_navigator.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_navigator.h
@@ -26,10 +26,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_NAVIGATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_NAVIGATOR_H_
+#include "third_party/blink/public/platform/web_worker_fetch_context.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h"
#include "third_party/blink/renderer/core/frame/navigator_device_memory.h"
#include "third_party/blink/renderer/core/frame/navigator_id.h"
+#include "third_party/blink/renderer/core/frame/navigator_language.h"
#include "third_party/blink/renderer/core/frame/navigator_on_line.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -40,24 +43,34 @@ namespace blink {
class CORE_EXPORT WorkerNavigator final
: public ScriptWrappable,
+ public AcceptLanguagesWatcher,
public NavigatorConcurrentHardware,
public NavigatorDeviceMemory,
public NavigatorID,
+ public NavigatorLanguage,
public NavigatorOnLine,
public Supplementable<WorkerNavigator> {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(WorkerNavigator);
public:
- static WorkerNavigator* Create(const String& user_agent) {
- return MakeGarbageCollected<WorkerNavigator>(user_agent);
+ static WorkerNavigator* Create(const String& user_agent,
+ ExecutionContext* context) {
+ return MakeGarbageCollected<WorkerNavigator>(user_agent, context);
}
- explicit WorkerNavigator(const String&);
+ explicit WorkerNavigator(const String&, ExecutionContext* context);
~WorkerNavigator() override;
+ // NavigatorID override
String userAgent() const override;
+ // NavigatorLanguage override
+ String GetAcceptLanguages() override;
+
+ // AcceptLanguagesWatcher override
+ void NotifyUpdate() override;
+
void Trace(blink::Visitor*) override;
private:
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_navigator.idl b/chromium/third_party/blink/renderer/core/workers/worker_navigator.idl
index ee7b34b2d15..db30f30c0ba 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_navigator.idl
+++ b/chromium/third_party/blink/renderer/core/workers/worker_navigator.idl
@@ -36,5 +36,5 @@
WorkerNavigator implements NavigatorConcurrentHardware;
WorkerNavigator implements NavigatorDeviceMemory;
WorkerNavigator implements NavigatorID;
-// TODO(foolip): WorkerNavigator implements NavigatorLanguage;
+WorkerNavigator implements NavigatorLanguage;
WorkerNavigator implements NavigatorOnLine;
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 4189e13ae0a..36c79b8e99c 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -13,11 +13,15 @@
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
+#include "third_party/blink/renderer/core/loader/worker_resource_fetcher_properties.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+#include "third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -108,7 +112,7 @@ void WorkerOrWorkletGlobalScope::InitializeWebFetchContextIfNeeded() {
return;
DCHECK(!subresource_filter_);
- web_worker_fetch_context_->InitializeOnWorkerThread();
+ web_worker_fetch_context_->InitializeOnWorkerThread(navigator());
std::unique_ptr<blink::WebDocumentSubresourceFilter> web_filter =
web_worker_fetch_context_->TakeSubresourceFilter();
if (web_filter) {
@@ -129,11 +133,23 @@ ResourceFetcher* WorkerOrWorkletGlobalScope::EnsureFetcher() {
ResourceFetcher* WorkerOrWorkletGlobalScope::CreateFetcherInternal(
FetchClientSettingsObject* fetch_client_settings_object) {
DCHECK(IsContextThread());
+ DCHECK(fetch_client_settings_object);
InitializeWebFetchContextIfNeeded();
- WorkerFetchContext* fetch_context = WorkerFetchContext::Create(
- *this, web_worker_fetch_context_, subresource_filter_,
- fetch_client_settings_object);
- ResourceFetcher* resource_fetcher = ResourceFetcher::Create(fetch_context);
+ ResourceFetcherProperties* properties = nullptr;
+ FetchContext* context = nullptr;
+ if (web_worker_fetch_context_) {
+ properties = MakeGarbageCollected<WorkerResourceFetcherProperties>(
+ *this, *fetch_client_settings_object, web_worker_fetch_context_);
+ context = MakeGarbageCollected<WorkerFetchContext>(
+ *this, web_worker_fetch_context_, subresource_filter_);
+ } else {
+ // This code path is for unittests.
+ properties = MakeGarbageCollected<NullResourceFetcherProperties>();
+ context = &FetchContext::NullInstance();
+ }
+ auto* resource_fetcher =
+ MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, context, GetTaskRunner(TaskType::kNetworking), *this));
if (IsContextPaused())
resource_fetcher->SetDefersLoading(true);
resource_fetchers_.insert(resource_fetcher);
@@ -209,7 +225,8 @@ void WorkerOrWorkletGlobalScope::InitContentSecurityPolicyFromVector(
void WorkerOrWorkletGlobalScope::BindContentSecurityPolicyToExecutionContext() {
DCHECK(IsContextThread());
- GetContentSecurityPolicy()->BindToExecutionContext(GetExecutionContext());
+ GetContentSecurityPolicy()->BindToDelegate(
+ GetContentSecurityPolicyDelegate());
}
// Implementation of the "fetch a module worker script graph" algorithm in the
@@ -237,8 +254,10 @@ void WorkerOrWorkletGlobalScope::FetchModuleScript(
Modulator* modulator = Modulator::From(ScriptController()->GetScriptState());
// Step 3. "Perform the internal module script graph fetching procedure ..."
- modulator->FetchTree(module_url_record, fetch_client_settings_object,
- destination, options, custom_fetch_type, client);
+ modulator->FetchTree(
+ module_url_record,
+ CreateOutsideSettingsFetcher(fetch_client_settings_object), destination,
+ options, custom_fetch_type, client);
}
void WorkerOrWorkletGlobalScope::TasksWerePaused() {
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
index 83c26870289..ae3878af56c 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/core/frame/web_feature_forward.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
+#include "third_party/blink/renderer/core/workers/worker_navigator.h"
#include "third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/bit_vector.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -91,6 +92,9 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
// WorkletGlobalScope for the main thread) or after Dispose() is called.
virtual WorkerThread* GetThread() const = 0;
+ // Returns nullptr if this global scope is a WorkletGlobalScope
+ virtual WorkerNavigator* navigator() const { return nullptr; }
+
ResourceFetcher* Fetcher() const override;
ResourceFetcher* EnsureFetcher();
@@ -134,6 +138,8 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
void TasksWerePaused() override;
void TasksWereUnpaused() override;
+ virtual mojom::RequestContextType GetDestinationForMainScript() = 0;
+
private:
void InitializeWebFetchContextIfNeeded();
ResourceFetcher* CreateFetcherInternal(FetchClientSettingsObject*);
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_reporting_proxy.h b/chromium/third_party/blink/renderer/core/workers/worker_reporting_proxy.h
index c4a1f1c8adb..8d53e771750 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_reporting_proxy.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_reporting_proxy.h
@@ -79,6 +79,10 @@ class CORE_EXPORT WorkerReportingProxy {
// InstalledScriptsManager.
virtual void DidFailToLoadInstalledClassicScript() {}
+ // Invoked on failure to fetch the worker's classic script from network. This
+ // is not called when the script is loaded from InstalledScriptsManager.
+ virtual void DidFailToFetchClassicScript() {}
+
// Invoked on failure to fetch the worker's module script (either from network
// or InstalledScriptsManager).
virtual void DidFailToFetchModuleScript() {}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread.cc b/chromium/third_party/blink/renderer/core/workers/worker_thread.cc
index dfe382cdefb..d4549efdf24 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -156,11 +156,11 @@ void WorkerThread::Start(
void WorkerThread::EvaluateClassicScript(
const KURL& script_url,
const String& source_code,
- std::unique_ptr<Vector<char>> cached_meta_data,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
const v8_inspector::V8StackTraceId& stack_id) {
DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
PostCrossThreadTask(
- *GetTaskRunner(TaskType::kInternalWorker), FROM_HERE,
+ *GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
CrossThreadBind(&WorkerThread::EvaluateClassicScriptOnWorkerThread,
CrossThreadUnretained(this), script_url, source_code,
WTF::Passed(std::move(cached_meta_data)), stack_id));
@@ -172,7 +172,7 @@ void WorkerThread::ImportClassicScript(
const v8_inspector::V8StackTraceId& stack_id) {
DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
PostCrossThreadTask(
- *GetTaskRunner(TaskType::kInternalWorker), FROM_HERE,
+ *GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
CrossThreadBind(&WorkerThread::ImportClassicScriptOnWorkerThread,
CrossThreadUnretained(this), script_url,
WTF::Passed(outside_settings_object->CopyData()),
@@ -185,7 +185,7 @@ void WorkerThread::ImportModuleScript(
network::mojom::FetchCredentialsMode credentials_mode) {
DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
PostCrossThreadTask(
- *GetTaskRunner(TaskType::kInternalWorker), FROM_HERE,
+ *GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
CrossThreadBind(&WorkerThread::ImportModuleScriptOnWorkerThread,
CrossThreadUnretained(this), script_url,
WTF::Passed(outside_settings_object->CopyData()),
@@ -449,7 +449,7 @@ void WorkerThread::InitializeOnWorkerThread(
const KURL url_for_debugger = global_scope_creation_params->script_url;
- console_message_storage_ = new ConsoleMessageStorage();
+ console_message_storage_ = MakeGarbageCollected<ConsoleMessageStorage>();
global_scope_ =
CreateWorkerGlobalScope(std::move(global_scope_creation_params));
worker_reporting_proxy_.DidCreateWorkerGlobalScope(GlobalScope());
@@ -497,11 +497,11 @@ void WorkerThread::InitializeOnWorkerThread(
void WorkerThread::EvaluateClassicScriptOnWorkerThread(
const KURL& script_url,
String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
const v8_inspector::V8StackTraceId& stack_id) {
To<WorkerGlobalScope>(GlobalScope())
- ->EvaluateClassicScriptPausable(script_url, std::move(source_code),
- std::move(cached_meta_data), stack_id);
+ ->EvaluateClassicScript(script_url, std::move(source_code),
+ std::move(cached_meta_data), stack_id);
}
void WorkerThread::ImportClassicScriptOnWorkerThread(
@@ -510,7 +510,7 @@ void WorkerThread::ImportClassicScriptOnWorkerThread(
outside_settings_object,
const v8_inspector::V8StackTraceId& stack_id) {
To<WorkerGlobalScope>(GlobalScope())
- ->ImportClassicScriptPausable(
+ ->ImportClassicScript(
script_url,
MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
std::move(outside_settings_object)),
@@ -526,7 +526,7 @@ void WorkerThread::ImportModuleScriptOnWorkerThread(
// TODO(nhiroki): Consider excluding this code path from WorkerThread like
// Worklets.
To<WorkerGlobalScope>(GlobalScope())
- ->ImportModuleScriptPausable(
+ ->ImportModuleScript(
script_url,
MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
std::move(outside_settings_object)),
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread.h b/chromium/third_party/blink/renderer/core/workers/worker_thread.h
index a7a03d2f5cd..da78755d4d7 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread.h
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h"
#include "third_party/blink/renderer/core/workers/worker_backing_thread_startup_data.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
@@ -108,7 +109,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
// Called on the main thread after Start().
void EvaluateClassicScript(const KURL& script_url,
const String& source_code,
- std::unique_ptr<Vector<char>> cached_meta_data,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
const v8_inspector::V8StackTraceId& stack_id);
// Posts a task to import a top-level classic script on the worker thread.
@@ -183,11 +184,12 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
// adds the current WorkerThread* as the first parameter |function|.
template <typename FunctionType, typename... Parameters>
static void CallOnAllWorkerThreads(FunctionType function,
+ TaskType task_type,
Parameters&&... parameters) {
MutexLocker lock(ThreadSetMutex());
for (WorkerThread* thread : WorkerThreads()) {
PostCrossThreadTask(
- *thread->GetTaskRunner(TaskType::kInternalWorker), FROM_HERE,
+ *thread->GetTaskRunner(task_type), FROM_HERE,
CrossThreadBind(function, WTF::CrossThreadUnretained(thread),
parameters...));
}
@@ -291,7 +293,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
void EvaluateClassicScriptOnWorkerThread(
const KURL& script_url,
String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
const v8_inspector::V8StackTraceId& stack_id);
void ImportClassicScriptOnWorkerThread(
const KURL& script_url,
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc b/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc
index 05edaaf7074..0df86febbc8 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc
@@ -30,43 +30,17 @@ using ExitCode = WorkerThread::ExitCode;
namespace {
-class MockWorkerReportingProxy final : public WorkerReportingProxy {
- public:
- MockWorkerReportingProxy() = default;
- ~MockWorkerReportingProxy() override = default;
-
- MOCK_METHOD1(DidCreateWorkerGlobalScope, void(WorkerOrWorkletGlobalScope*));
- MOCK_METHOD0(DidInitializeWorkerContext, void());
- MOCK_METHOD2(WillEvaluateClassicScriptMock,
- void(size_t scriptSize, size_t cachedMetadataSize));
- MOCK_METHOD1(DidEvaluateClassicScript, void(bool success));
- MOCK_METHOD0(DidCloseWorkerGlobalScope, void());
- MOCK_METHOD0(WillDestroyWorkerGlobalScope, void());
- MOCK_METHOD0(DidTerminateWorkerThread, void());
-
- void WillEvaluateClassicScript(size_t script_size,
- size_t cached_metadata_size) override {
- script_evaluation_event_.Signal();
- WillEvaluateClassicScriptMock(script_size, cached_metadata_size);
- }
-
- void WaitUntilScriptEvaluation() { script_evaluation_event_.Wait(); }
-
- private:
- WaitableEvent script_evaluation_event_;
-};
-
// Used as a debugger task. Waits for a signal from the main thread.
void WaitForSignalTask(WorkerThread* worker_thread,
WaitableEvent* waitable_event) {
EXPECT_TRUE(worker_thread->IsCurrentThread());
+ worker_thread->DebuggerTaskStarted();
// Notify the main thread that the debugger task is waiting for the signal.
PostCrossThreadTask(
*worker_thread->GetParentExecutionContextTaskRunners()->Get(
TaskType::kInternalTest),
FROM_HERE, CrossThreadBind(&test::ExitRunLoop));
- worker_thread->DebuggerTaskStarted();
waitable_event->Wait();
worker_thread->DebuggerTaskFinished();
}
@@ -390,7 +364,8 @@ TEST_F(WorkerThreadTest, Terminate_WhileDebuggerTaskIsRunningOnInitialization) {
auto global_scope_creation_params =
std::make_unique<GlobalScopeCreationParams>(
KURL("http://fake.url/"), mojom::ScriptType::kClassic,
- "fake user agent", nullptr /* web_worker_fetch_context */, headers,
+ OffMainThreadWorkerScriptFetchOption::kDisabled, "fake user agent",
+ nullptr /* web_worker_fetch_context */, headers,
network::mojom::ReferrerPolicy::kDefault, security_origin_.get(),
false /* starter_secure_context */,
CalculateHttpsState(security_origin_.get()), WorkerClients::Create(),
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
index 590fb8729f1..05ecd5fa712 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -65,6 +65,10 @@ class FakeWorkerGlobalScope : public WorkerGlobalScope {
}
void ExceptionThrown(ErrorEvent*) override {}
+
+ mojom::RequestContextType GetDestinationForMainScript() override {
+ return mojom::RequestContextType::WORKER;
+ }
};
class WorkerThreadForTest : public WorkerThread {
@@ -91,7 +95,8 @@ class WorkerThreadForTest : public WorkerThread {
Vector<CSPHeaderAndType> headers{
{"contentSecurityPolicy", kContentSecurityPolicyHeaderTypeReport}};
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- script_url, mojom::ScriptType::kClassic, "fake user agent",
+ script_url, mojom::ScriptType::kClassic,
+ OffMainThreadWorkerScriptFetchOption::kDisabled, "fake user agent",
nullptr /* web_worker_fetch_context */, headers,
network::mojom::ReferrerPolicy::kDefault, security_origin,
false /* starter_secure_context */,
@@ -132,6 +137,32 @@ class WorkerThreadForTest : public WorkerThread {
std::unique_ptr<WorkerBackingThread> worker_backing_thread_;
};
+class MockWorkerReportingProxy final : public WorkerReportingProxy {
+ public:
+ MockWorkerReportingProxy() = default;
+ ~MockWorkerReportingProxy() override = default;
+
+ MOCK_METHOD1(DidCreateWorkerGlobalScope, void(WorkerOrWorkletGlobalScope*));
+ MOCK_METHOD0(DidInitializeWorkerContext, void());
+ MOCK_METHOD2(WillEvaluateClassicScriptMock,
+ void(size_t scriptSize, size_t cachedMetadataSize));
+ MOCK_METHOD1(DidEvaluateClassicScript, void(bool success));
+ MOCK_METHOD0(DidCloseWorkerGlobalScope, void());
+ MOCK_METHOD0(WillDestroyWorkerGlobalScope, void());
+ MOCK_METHOD0(DidTerminateWorkerThread, void());
+
+ void WillEvaluateClassicScript(size_t script_size,
+ size_t cached_metadata_size) override {
+ script_evaluation_event_.Signal();
+ WillEvaluateClassicScriptMock(script_size, cached_metadata_size);
+ }
+
+ void WaitUntilScriptEvaluation() { script_evaluation_event_.Wait(); }
+
+ private:
+ WaitableEvent script_evaluation_event_;
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_THREAD_TEST_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet.cc b/chromium/third_party/blink/renderer/core/workers/worklet.cc
index 0739eea7373..9f6ba6a5171 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worklet.cc
@@ -16,13 +16,15 @@
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/workers/worklet_pending_tasks.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
namespace blink {
Worklet::Worklet(Document* document)
: ContextLifecycleObserver(document),
- module_responses_map_(new WorkletModuleResponsesMap) {
+ module_responses_map_(MakeGarbageCollected<WorkletModuleResponsesMap>()) {
DCHECK(IsMainThread());
}
@@ -123,7 +125,11 @@ void Worklet::FetchAndInvokeScript(const KURL& module_url_record,
// Step 7: "Let outsideSettings be the relevant settings object of this."
auto* outside_settings_object =
- GetExecutionContext()->CreateFetchClientSettingsObjectSnapshot();
+ MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ GetExecutionContext()
+ ->Fetcher()
+ ->GetProperties()
+ .GetFetchClientSettingsObject());
// Specify TaskType::kInternalLoading because it's commonly used for module
// loading.
scoped_refptr<base::SingleThreadTaskRunner> outside_settings_task_runner =
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc
index 88da265e145..0256de0dcfa 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -209,11 +209,8 @@ void WorkletGlobalScope::FetchAndInvokeScript(
MakeGarbageCollected<WorkletModuleTreeClient>(
modulator, std::move(outside_settings_task_runner), pending_tasks);
- // TODO(nhiroki): Specify an appropriate destination defined in each worklet
- // spec (e.g., "paint worklet", "audio worklet").
- mojom::RequestContextType destination = mojom::RequestContextType::SCRIPT;
- FetchModuleScript(module_url_record, outside_settings_object, destination,
- credentials_mode,
+ FetchModuleScript(module_url_record, outside_settings_object,
+ GetDestinationForMainScript(), credentials_mode,
ModuleScriptCustomFetchType::kWorkletAddModule, client);
}
@@ -241,6 +238,13 @@ void WorkletGlobalScope::BindContentSecurityPolicyToExecutionContext() {
GetContentSecurityPolicy()->SetupSelf(*document_security_origin_);
}
+mojom::RequestContextType WorkletGlobalScope::GetDestinationForMainScript() {
+ // TODO(nhiroki): Return an appropriate destination defined in each worklet
+ // spec (e.g., "paint worklet", "audio worklet") (https://crbug.com/843980,
+ // https://crbug.com/843982)
+ return mojom::RequestContextType::SCRIPT;
+}
+
void WorkletGlobalScope::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_);
WorkerOrWorkletGlobalScope::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h
index 2b748a33752..62b75e957e1 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -157,6 +157,8 @@ class CORE_EXPORT WorkletGlobalScope
void BindContentSecurityPolicyToExecutionContext() override;
+ mojom::RequestContextType GetDestinationForMainScript() override;
+
// The |url_| and |user_agent_| are inherited from the parent Document.
const KURL url_;
const String user_agent_;
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc
index 880426c2298..a1920183a56 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/workers/worker_fetch_test_helper.h"
#include "third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -22,13 +23,13 @@ namespace blink {
class WorkletModuleResponsesMapTest : public testing::Test {
public:
- WorkletModuleResponsesMapTest() = default;
-
- void SetUp() override {
+ WorkletModuleResponsesMapTest() {
platform_->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
- auto* context =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- fetcher_ = ResourceFetcher::Create(context);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* context = MakeGarbageCollected<MockFetchContext>();
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
map_ = MakeGarbageCollected<WorkletModuleResponsesMap>();
}
@@ -39,22 +40,21 @@ class WorkletModuleResponsesMapTest : public testing::Test {
resource_request.SetRequestContext(mojom::RequestContextType::SCRIPT);
FetchParameters fetch_params(resource_request);
WorkletModuleScriptFetcher* module_fetcher =
- MakeGarbageCollected<WorkletModuleScriptFetcher>(fetcher_.Get(),
- map_.Get());
- module_fetcher->Fetch(fetch_params, ModuleGraphLevel::kTopLevelModuleFetch,
- client);
+ MakeGarbageCollected<WorkletModuleScriptFetcher>(map_.Get());
+ module_fetcher->Fetch(fetch_params, fetcher_.Get(),
+ ModuleGraphLevel::kTopLevelModuleFetch, client);
}
void RunUntilIdle() {
- base::SingleThreadTaskRunner* runner =
- fetcher_->Context().GetLoadingTaskRunner().get();
- static_cast<scheduler::FakeTaskRunner*>(runner)->RunUntilIdle();
+ static_cast<scheduler::FakeTaskRunner*>(fetcher_->GetTaskRunner().get())
+ ->RunUntilIdle();
}
protected:
ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_;
Persistent<ResourceFetcher> fetcher_;
Persistent<WorkletModuleResponsesMap> map_;
+ const scoped_refptr<scheduler::FakeTaskRunner> task_runner_;
};
TEST_F(WorkletModuleResponsesMapTest, Basic) {
@@ -64,18 +64,18 @@ TEST_F(WorkletModuleResponsesMapTest, Basic) {
HeapVector<Member<ClientImpl>> clients;
// An initial read call initiates a fetch request.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
EXPECT_FALSE(clients[0]->GetParams().has_value());
// The entry is now being fetched. Following read calls should wait for the
// completion.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[1]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[2]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
@@ -94,18 +94,18 @@ TEST_F(WorkletModuleResponsesMapTest, Failure) {
HeapVector<Member<ClientImpl>> clients;
// An initial read call initiates a fetch request.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
EXPECT_FALSE(clients[0]->GetParams().has_value());
// The entry is now being fetched. Following read calls should wait for the
// completion.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[1]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[2]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
@@ -127,26 +127,26 @@ TEST_F(WorkletModuleResponsesMapTest, Isolation) {
HeapVector<Member<ClientImpl>> clients;
// An initial read call for |kUrl1| initiates a fetch request.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl1, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
EXPECT_FALSE(clients[0]->GetParams().has_value());
// The entry is now being fetched. Following read calls for |kUrl1| should
// wait for the completion.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl1, clients[1]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
// An initial read call for |kUrl2| initiates a fetch request.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl2, clients[2]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
EXPECT_FALSE(clients[2]->GetParams().has_value());
// The entry is now being fetched. Following read calls for |kUrl2| should
// wait for the completion.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl2, clients[3]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[3]->GetResult());
@@ -169,7 +169,7 @@ TEST_F(WorkletModuleResponsesMapTest, Isolation) {
TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
const KURL kEmptyURL;
ASSERT_TRUE(kEmptyURL.IsEmpty());
- ClientImpl* client1 = new ClientImpl;
+ ClientImpl* client1 = MakeGarbageCollected<ClientImpl>();
Fetch(kEmptyURL, client1);
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, client1->GetResult());
@@ -177,7 +177,7 @@ TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
const KURL kNullURL = NullURL();
ASSERT_TRUE(kNullURL.IsNull());
- ClientImpl* client2 = new ClientImpl;
+ ClientImpl* client2 = MakeGarbageCollected<ClientImpl>();
Fetch(kNullURL, client2);
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, client2->GetResult());
@@ -185,7 +185,7 @@ TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
const KURL kInvalidURL;
ASSERT_FALSE(kInvalidURL.IsValid());
- ClientImpl* client3 = new ClientImpl;
+ ClientImpl* client3 = MakeGarbageCollected<ClientImpl>();
Fetch(kInvalidURL, client3);
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, client3->GetResult());
@@ -203,27 +203,27 @@ TEST_F(WorkletModuleResponsesMapTest, Dispose) {
// An initial read call for |kUrl1| creates a placeholder entry and asks the
// client to fetch a module script.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl1, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
EXPECT_FALSE(clients[0]->GetParams().has_value());
// The entry is now being fetched. Following read calls for |kUrl1| should
// wait for the completion.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl1, clients[1]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
// An initial read call for |kUrl2| also creates a placeholder entry and asks
// the client to fetch a module script.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl2, clients[2]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
EXPECT_FALSE(clients[2]->GetParams().has_value());
// The entry is now being fetched. Following read calls for |kUrl2| should
// wait for the completion.
- clients.push_back(new ClientImpl);
+ clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl2, clients[3]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[3]->GetResult());
diff --git a/chromium/third_party/blink/renderer/core/xml/OWNERS b/chromium/third_party/blink/renderer/core/xml/OWNERS
index 381e75ddaa0..5c2ac186c8c 100644
--- a/chromium/third_party/blink/renderer/core/xml/OWNERS
+++ b/chromium/third_party/blink/renderer/core/xml/OWNERS
@@ -2,4 +2,4 @@
# a CL to add yourself here.
# COMPONENT: Blink>XML
dcheng@chromium.org
-scottmg@chromium.org
+palmer@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/xml/document_xslt.cc b/chromium/third_party/blink/renderer/core/xml/document_xslt.cc
index 9b44551cab0..3dc474582a3 100644
--- a/chromium/third_party/blink/renderer/core/xml/document_xslt.cc
+++ b/chromium/third_party/blink/renderer/core/xml/document_xslt.cc
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/processing_instruction.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -21,7 +21,7 @@
namespace blink {
class DOMContentLoadedListener final
- : public EventListener,
+ : public NativeEventListener,
public ProcessingInstruction::DetachableEventListener {
USING_GARBAGE_COLLECTED_MIXIN(DOMContentLoadedListener);
@@ -31,12 +31,7 @@ class DOMContentLoadedListener final
}
DOMContentLoadedListener(ProcessingInstruction* pi)
- : EventListener(EventListener::kCPPEventListenerType),
- processing_instruction_(pi) {}
-
- bool operator==(const EventListener& rhs) const override {
- return this == &rhs;
- }
+ : processing_instruction_(pi) {}
void Invoke(ExecutionContext* execution_context, Event* event) override {
DCHECK(RuntimeEnabledFeatures::XSLTEnabled());
@@ -64,7 +59,7 @@ class DOMContentLoadedListener final
void Trace(blink::Visitor* visitor) override {
visitor->Trace(processing_instruction_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
ProcessingInstruction::DetachableEventListener::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/xml/dom_parser.idl b/chromium/third_party/blink/renderer/core/xml/dom_parser.idl
index b478df5d8e8..5f9b2abe8bf 100644
--- a/chromium/third_party/blink/renderer/core/xml/dom_parser.idl
+++ b/chromium/third_party/blink/renderer/core/xml/dom_parser.idl
@@ -18,9 +18,6 @@
*/
// https://w3c.github.io/DOM-Parsing/#the-domparser-interface
-// The `HTMLString` reference below is from Trusted Types:
-// https://github.com/WICG/trusted-types/, which is still WIP.
-// https://crbug.com/739170.
enum SupportedType {
"text/html",
diff --git a/chromium/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc b/chromium/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
index 914c7d768e7..b55b9558a47 100644
--- a/chromium/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
+++ b/chromium/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
@@ -37,6 +37,7 @@
#include <memory>
#include "base/auto_reset.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/dom/cdata_section.h"
#include "third_party/blink/renderer/core/dom/comment.h"
@@ -610,7 +611,7 @@ static void* OpenFunc(const char* uri) {
RawResource::FetchSynchronously(params, document->Fetcher());
if (!resource->ErrorOccurred()) {
data = resource->ResourceBuffer();
- final_url = resource->GetResponse().Url();
+ final_url = resource->GetResponse().CurrentRequestUrl();
}
}
@@ -1371,7 +1372,7 @@ static xmlEntityPtr GetXHTMLEntity(const xmlChar* name) {
return nullptr;
constexpr size_t kSharedXhtmlEntityResultLength =
- arraysize(g_shared_xhtml_entity_result);
+ base::size(g_shared_xhtml_entity_result);
size_t entity_length_in_utf8;
// Unlike HTML parser, XML parser parses the content of named
// entities. So we need to escape '&' and '<'.
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_functions.cc b/chromium/third_party/blink/renderer/core/xml/xpath_functions.cc
index 833388cd3f1..136776dd0c3 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_functions.cc
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_functions.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/xml/xpath_functions.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/dom/attr.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/processing_instruction.h"
@@ -48,7 +49,7 @@ static inline bool IsWhitespace(UChar c) {
}
#define DEFINE_FUNCTION_CREATOR(Class) \
- static Function* Create##Class() { return new Class; }
+ static Function* Create##Class() { return MakeGarbageCollected<Class>(); }
class Interval {
public:
@@ -742,7 +743,7 @@ static void CreateFunctionMap() {
};
g_function_map = new HashMap<String, FunctionRec>;
- for (size_t i = 0; i < arraysize(functions); ++i)
+ for (size_t i = 0; i < base::size(functions); ++i)
g_function_map->Set(functions[i].name, functions[i].function);
}
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_functions_test.cc b/chromium/third_party/blink/renderer/core/xml/xpath_functions_test.cc
index e89e4dbadfa..1ba9e00ff82 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_functions_test.cc
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_functions_test.cc
@@ -44,16 +44,16 @@ static String Substring(XPathArguments& args) {
static String Substring(const char* string, double pos) {
XPathArguments args;
- args.push_back(new xpath::StringExpression(string));
- args.push_back(new xpath::Number(pos));
+ args.push_back(MakeGarbageCollected<xpath::StringExpression>(string));
+ args.push_back(MakeGarbageCollected<xpath::Number>(pos));
return Substring(args);
}
static String Substring(const char* string, double pos, double len) {
XPathArguments args;
- args.push_back(new xpath::StringExpression(string));
- args.push_back(new xpath::Number(pos));
- args.push_back(new xpath::Number(len));
+ args.push_back(MakeGarbageCollected<xpath::StringExpression>(string));
+ args.push_back(MakeGarbageCollected<xpath::Number>(pos));
+ args.push_back(MakeGarbageCollected<xpath::Number>(len));
return Substring(args);
}
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y b/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y
index fcd33e5c16b..17d0b89685d 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y
@@ -138,7 +138,7 @@ LocationPath:
AbsoluteLocationPath:
'/'
{
- $$ = new blink::xpath::LocationPath;
+ $$ = blink::MakeGarbageCollected<blink::xpath::LocationPath>();
}
|
'/' RelativeLocationPath
@@ -156,7 +156,7 @@ AbsoluteLocationPath:
RelativeLocationPath:
Step
{
- $$ = new blink::xpath::LocationPath;
+ $$ = blink::MakeGarbageCollected<blink::xpath::LocationPath>();
$$->AppendStep($1);
}
|
@@ -176,9 +176,9 @@ Step:
NodeTest OptionalPredicateList
{
if ($2)
- $$ = new Step(Step::kChildAxis, *$1, *$2);
+ $$ = blink::MakeGarbageCollected<Step>(Step::kChildAxis, *$1, *$2);
else
- $$ = new Step(Step::kChildAxis, *$1);
+ $$ = blink::MakeGarbageCollected<Step>(Step::kChildAxis, *$1);
}
|
NAMETEST OptionalPredicateList
@@ -191,18 +191,18 @@ Step:
}
if ($2)
- $$ = new Step(Step::kChildAxis, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri), *$2);
+ $$ = blink::MakeGarbageCollected<Step>(Step::kChildAxis, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri), *$2);
else
- $$ = new Step(Step::kChildAxis, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri));
+ $$ = blink::MakeGarbageCollected<Step>(Step::kChildAxis, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri));
parser->DeleteString($1);
}
|
AxisSpecifier NodeTest OptionalPredicateList
{
if ($3)
- $$ = new Step($1, *$2, *$3);
+ $$ = blink::MakeGarbageCollected<Step>($1, *$2, *$3);
else
- $$ = new Step($1, *$2);
+ $$ = blink::MakeGarbageCollected<Step>($1, *$2);
}
|
AxisSpecifier NAMETEST OptionalPredicateList
@@ -215,9 +215,9 @@ Step:
}
if ($3)
- $$ = new Step($1, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri), *$3);
+ $$ = blink::MakeGarbageCollected<Step>($1, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri), *$3);
else
- $$ = new Step($1, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri));
+ $$ = blink::MakeGarbageCollected<Step>($1, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri));
parser->DeleteString($2);
}
|
@@ -237,24 +237,24 @@ NodeTest:
NODETYPE '(' ')'
{
if (*$1 == "node")
- $$ = new Step::NodeTest(Step::NodeTest::kAnyNodeTest);
+ $$ = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kAnyNodeTest);
else if (*$1 == "text")
- $$ = new Step::NodeTest(Step::NodeTest::kTextNodeTest);
+ $$ = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kTextNodeTest);
else if (*$1 == "comment")
- $$ = new Step::NodeTest(Step::NodeTest::kCommentNodeTest);
+ $$ = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kCommentNodeTest);
parser->DeleteString($1);
}
|
PI '(' ')'
{
- $$ = new Step::NodeTest(Step::NodeTest::kProcessingInstructionNodeTest);
+ $$ = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kProcessingInstructionNodeTest);
parser->DeleteString($1);
}
|
PI '(' LITERAL ')'
{
- $$ = new Step::NodeTest(Step::NodeTest::kProcessingInstructionNodeTest, $3->StripWhiteSpace());
+ $$ = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kProcessingInstructionNodeTest, $3->StripWhiteSpace());
parser->DeleteString($1);
parser->DeleteString($3);
}
@@ -273,12 +273,12 @@ PredicateList:
Predicate
{
$$ = blink::MakeGarbageCollected<blink::HeapVector<blink::Member<blink::xpath::Predicate>>>();
- $$->push_back(new blink::xpath::Predicate($1));
+ $$->push_back(blink::MakeGarbageCollected<blink::xpath::Predicate>($1));
}
|
PredicateList Predicate
{
- $$->push_back(new blink::xpath::Predicate($2));
+ $$->push_back(blink::MakeGarbageCollected<blink::xpath::Predicate>($2));
}
;
@@ -292,26 +292,26 @@ Predicate:
DescendantOrSelf:
SLASHSLASH
{
- $$ = new Step(Step::kDescendantOrSelfAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
+ $$ = blink::MakeGarbageCollected<Step>(Step::kDescendantOrSelfAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
}
;
AbbreviatedStep:
'.'
{
- $$ = new Step(Step::kSelfAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
+ $$ = blink::MakeGarbageCollected<Step>(Step::kSelfAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
}
|
DOTDOT
{
- $$ = new Step(Step::kParentAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
+ $$ = blink::MakeGarbageCollected<Step>(Step::kParentAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
}
;
PrimaryExpr:
VARIABLEREFERENCE
{
- $$ = new blink::xpath::VariableReference(*$1);
+ $$ = blink::MakeGarbageCollected<blink::xpath::VariableReference>(*$1);
parser->DeleteString($1);
}
|
@@ -322,13 +322,13 @@ PrimaryExpr:
|
LITERAL
{
- $$ = new blink::xpath::StringExpression(*$1);
+ $$ = blink::MakeGarbageCollected<blink::xpath::StringExpression>(*$1);
parser->DeleteString($1);
}
|
NUMBER
{
- $$ = new blink::xpath::Number($1->ToDouble());
+ $$ = blink::MakeGarbageCollected<blink::xpath::Number>($1->ToDouble());
parser->DeleteString($1);
}
|
@@ -375,7 +375,7 @@ UnionExpr:
|
UnionExpr '|' PathExpr
{
- $$ = new blink::xpath::Union;
+ $$ = blink::MakeGarbageCollected<blink::xpath::Union>();
$$->AddSubExpression($1);
$$->AddSubExpression($3);
}
@@ -392,14 +392,14 @@ PathExpr:
FilterExpr '/' RelativeLocationPath
{
$3->SetAbsolute(true);
- $$ = new blink::xpath::Path($1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::Path>($1, $3);
}
|
FilterExpr DescendantOrSelf RelativeLocationPath
{
$3->InsertFirstStep($2);
$3->SetAbsolute(true);
- $$ = new blink::xpath::Path($1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::Path>($1, $3);
}
;
@@ -408,7 +408,7 @@ FilterExpr:
|
PrimaryExpr PredicateList
{
- $$ = new blink::xpath::Filter($1, *$2);
+ $$ = blink::MakeGarbageCollected<blink::xpath::Filter>($1, *$2);
}
;
@@ -417,7 +417,7 @@ OrExpr:
|
OrExpr OR AndExpr
{
- $$ = new blink::xpath::LogicalOp(blink::xpath::LogicalOp::kOP_Or, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::LogicalOp>(blink::xpath::LogicalOp::kOP_Or, $1, $3);
}
;
@@ -426,7 +426,7 @@ AndExpr:
|
AndExpr AND EqualityExpr
{
- $$ = new blink::xpath::LogicalOp(blink::xpath::LogicalOp::kOP_And, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::LogicalOp>(blink::xpath::LogicalOp::kOP_And, $1, $3);
}
;
@@ -435,7 +435,7 @@ EqualityExpr:
|
EqualityExpr EQOP RelationalExpr
{
- $$ = new blink::xpath::EqTestOp($2, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::EqTestOp>($2, $1, $3);
}
;
@@ -444,7 +444,7 @@ RelationalExpr:
|
RelationalExpr RELOP AdditiveExpr
{
- $$ = new blink::xpath::EqTestOp($2, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::EqTestOp>($2, $1, $3);
}
;
@@ -453,12 +453,12 @@ AdditiveExpr:
|
AdditiveExpr PLUS MultiplicativeExpr
{
- $$ = new blink::xpath::NumericOp(blink::xpath::NumericOp::kOP_Add, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::NumericOp>(blink::xpath::NumericOp::kOP_Add, $1, $3);
}
|
AdditiveExpr MINUS MultiplicativeExpr
{
- $$ = new blink::xpath::NumericOp(blink::xpath::NumericOp::kOP_Sub, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::NumericOp>(blink::xpath::NumericOp::kOP_Sub, $1, $3);
}
;
@@ -467,7 +467,7 @@ MultiplicativeExpr:
|
MultiplicativeExpr MULOP UnaryExpr
{
- $$ = new blink::xpath::NumericOp($2, $1, $3);
+ $$ = blink::MakeGarbageCollected<blink::xpath::NumericOp>($2, $1, $3);
}
;
@@ -476,7 +476,7 @@ UnaryExpr:
|
MINUS UnaryExpr
{
- $$ = new blink::xpath::Negative;
+ $$ = blink::MakeGarbageCollected<blink::xpath::Negative>();
$$->AddSubExpression($2);
}
;
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl b/chromium/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl
index cb45d0366a1..5d2a030e180 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl
@@ -28,5 +28,5 @@
[
NoInterfaceObject
] interface XPathNSResolver {
- DOMString? lookupNamespaceURI([Default=Undefined] optional DOMString prefix);
+ DOMString? lookupNamespaceURI([DefaultValue=Undefined] optional DOMString prefix);
};
diff --git a/chromium/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc b/chromium/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc
index 3ddf37bc50a..b97d69c71ac 100644
--- a/chromium/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc
+++ b/chromium/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc
@@ -235,7 +235,7 @@ void XSLStyleSheet::LoadChildSheet(const String& href) {
return;
XSLStyleSheet* style_sheet = MakeGarbageCollected<XSLStyleSheet>(
- this, url_string, resource->GetResponse().Url());
+ this, url_string, resource->GetResponse().CurrentRequestUrl());
children_.push_back(style_sheet);
style_sheet->ParseString(resource->Sheet());
CheckLoaded();
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index a5dbae754b1..87bdb5990ef 100644
--- a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -26,7 +26,9 @@
#include <memory>
#include "base/auto_reset.h"
+#include "base/feature_list.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_document_or_string_or_form_data_or_url_search_params.h"
@@ -262,24 +264,18 @@ XMLHttpRequest* XMLHttpRequest::Create(ScriptState* script_state) {
DOMWrapperWorld& world = script_state->World();
v8::Isolate* isolate = script_state->GetIsolate();
- XMLHttpRequest* xml_http_request =
- world.IsIsolatedWorld()
- ? MakeGarbageCollected<XMLHttpRequest>(
- context, isolate, true, world.IsolatedWorldSecurityOrigin())
- : MakeGarbageCollected<XMLHttpRequest>(context, isolate, false,
- nullptr);
- xml_http_request->PauseIfNeeded();
- return xml_http_request;
+ return world.IsIsolatedWorld()
+ ? MakeGarbageCollected<XMLHttpRequest>(
+ context, isolate, true, world.IsolatedWorldSecurityOrigin())
+ : MakeGarbageCollected<XMLHttpRequest>(context, isolate, false,
+ nullptr);
}
XMLHttpRequest* XMLHttpRequest::Create(ExecutionContext* context) {
- v8::Isolate* isolate = ToIsolate(context);
+ v8::Isolate* isolate = context->GetIsolate();
CHECK(isolate);
- XMLHttpRequest* xml_http_request =
- MakeGarbageCollected<XMLHttpRequest>(context, isolate, false, nullptr);
- xml_http_request->PauseIfNeeded();
- return xml_http_request;
+ return MakeGarbageCollected<XMLHttpRequest>(context, isolate, false, nullptr);
}
XMLHttpRequest::XMLHttpRequest(
@@ -287,7 +283,7 @@ XMLHttpRequest::XMLHttpRequest(
v8::Isolate* isolate,
bool is_isolated_world,
scoped_refptr<SecurityOrigin> isolated_world_security_origin)
- : PausableObject(context),
+ : ContextLifecycleObserver(context),
progress_event_throttle_(
XMLHttpRequestProgressEventThrottle::Create(this)),
isolate_(isolate),
@@ -359,7 +355,7 @@ void XMLHttpRequest::InitResponseDocument() {
DocumentInit init = DocumentInit::Create()
.WithContextDocument(GetDocument()->ContextDocument())
- .WithURL(response_.Url());
+ .WithURL(response_.ResponseUrl());
if (is_html)
response_document_ = HTMLDocument::Create(init);
else
@@ -544,7 +540,7 @@ String XMLHttpRequest::responseType() {
}
String XMLHttpRequest::responseURL() {
- KURL response_url(response_.Url());
+ KURL response_url(response_.ResponseUrl());
if (!response_url.IsNull())
response_url.RemoveFragmentIdentifier();
return response_url.GetString();
@@ -1005,6 +1001,16 @@ void XMLHttpRequest::CreateRequest(scoped_refptr<EncodedFormData> http_body,
return;
}
+ if (url_.ProtocolIs("ftp")) {
+ LogConsoleError(GetExecutionContext(), "FTP is not supported.");
+ HandleNetworkError();
+ if (!async_) {
+ ThrowForLoadFailureIfNeeded(
+ exception_state, "Making a request to a FTP URL is not supported.");
+ }
+ return;
+ }
+
DCHECK(GetExecutionContext());
ExecutionContext& execution_context = *GetExecutionContext();
@@ -1061,7 +1067,7 @@ void XMLHttpRequest::CreateRequest(scoped_refptr<EncodedFormData> http_body,
execution_context.GetSecurityContext().AddressSpace());
probe::willLoadXHR(&execution_context, this, this, method_, url_, async_,
- request_headers_, with_credentials_);
+ http_body.get(), request_headers_, with_credentials_);
if (http_body) {
DCHECK_NE(method_, http_names::kGET);
@@ -1095,9 +1101,6 @@ void XMLHttpRequest::CreateRequest(scoped_refptr<EncodedFormData> http_body,
resource_loader_options.data_buffering_policy = kDoNotBufferData;
}
- exception_code_ = DOMExceptionCode::kNoError;
- error_ = false;
-
if (async_) {
UseCounter::Count(&execution_context,
WebFeature::kXMLHttpRequestAsynchronous);
@@ -1125,15 +1128,34 @@ void XMLHttpRequest::CreateRequest(scoped_refptr<EncodedFormData> http_body,
// Update histogram for usage of sync xhr within pagedismissal.
auto pagedismissal = GetDocument()->PageDismissalEventBeingDispatched();
if (pagedismissal != Document::kNoDismissal) {
- UseCounter::Count(GetDocument(), WebFeature::kSyncXhrInPageDismissal);
- DEFINE_STATIC_LOCAL(EnumerationHistogram, syncxhr_pagedismissal_histogram,
- ("XHR.Sync.PageDismissal", 5));
- syncxhr_pagedismissal_histogram.Count(pagedismissal);
+ // Disallow synchronous requests on page dismissal
+ if (base::FeatureList::IsEnabled(
+ features::kForbidSyncXHRInPageDismissal)) {
+ UseCounter::Count(GetDocument(),
+ WebFeature::kForbiddenSyncXhrInPageDismissal);
+ DEFINE_STATIC_LOCAL(EnumerationHistogram,
+ forbidden_syncxhr_pagedismissal_histogram,
+ ("XHR.Sync.PageDismissal_forbidden", 5));
+ forbidden_syncxhr_pagedismissal_histogram.Count(pagedismissal);
+ HandleNetworkError();
+ ThrowForLoadFailureIfNeeded(exception_state,
+ "Synchronous XHR in page dismissal.");
+ return;
+ } else {
+ UseCounter::Count(GetDocument(), WebFeature::kSyncXhrInPageDismissal);
+ DEFINE_STATIC_LOCAL(EnumerationHistogram,
+ syncxhr_pagedismissal_histogram,
+ ("XHR.Sync.PageDismissal", 5));
+ syncxhr_pagedismissal_histogram.Count(pagedismissal);
+ }
}
}
resource_loader_options.synchronous_policy = kRequestSynchronously;
}
+ exception_code_ = DOMExceptionCode::kNoError;
+ error_ = false;
+
loader_ = MakeGarbageCollected<ThreadableLoader>(execution_context, this,
resource_loader_options);
loader_->SetTimeout(timeout_);
@@ -1797,6 +1819,8 @@ std::unique_ptr<TextResourceDecoder> XMLHttpRequest::CreateDecoder() const {
if (!final_response_charset.IsEmpty()) {
// If the final charset is given, use the charset without sniffing the
// content.
+ // TODO(crbug/905968): If WTF::TextEncoding::IsValid() is false, this
+ // currently falls back to Latin1Encoding(). Fallback to UTF-8 instead.
return TextResourceDecoder::Create(TextResourceDecoderOptions(
TextResourceDecoderOptions::kPlainTextContent,
WTF::TextEncoding(final_response_charset)));
@@ -1881,7 +1905,7 @@ void XMLHttpRequest::DidReceiveData(const char* data, unsigned len) {
TrackProgress(len);
}
-void XMLHttpRequest::DidDownloadData(int data_length) {
+void XMLHttpRequest::DidDownloadData(unsigned long long data_length) {
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
if (error_)
return;
@@ -1953,14 +1977,6 @@ void XMLHttpRequest::HandleDidTimeout() {
expected_length);
}
-void XMLHttpRequest::Pause() {
- progress_event_throttle_->Pause();
-}
-
-void XMLHttpRequest::Unpause() {
- progress_event_throttle_->Unpause();
-}
-
void XMLHttpRequest::ContextDestroyed(ExecutionContext*) {
Dispose();
@@ -1986,7 +2002,7 @@ const AtomicString& XMLHttpRequest::InterfaceName() const {
}
ExecutionContext* XMLHttpRequest::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
+ return ContextLifecycleObserver::GetExecutionContext();
}
void XMLHttpRequest::ReportMemoryUsageToV8() {
@@ -2019,7 +2035,7 @@ void XMLHttpRequest::Trace(blink::Visitor* visitor) {
XMLHttpRequestEventTarget::Trace(visitor);
ThreadableLoaderClient::Trace(visitor);
DocumentParserClient::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
std::ostream& operator<<(std::ostream& ostream, const XMLHttpRequest* xhr) {
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
index 813044ebc4a..40835852d36 100644
--- a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
@@ -28,8 +28,8 @@
#include "base/memory/scoped_refptr.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/document_parser_client.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
#include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request_event_target.h"
#include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h"
@@ -73,7 +73,7 @@ class XMLHttpRequest final : public XMLHttpRequestEventTarget,
public ThreadableLoaderClient,
public DocumentParserClient,
public ActiveScriptWrappable<XMLHttpRequest>,
- public PausableObject {
+ public ContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(XMLHttpRequest);
@@ -105,11 +105,9 @@ class XMLHttpRequest final : public XMLHttpRequestEventTarget,
kResponseTypeArrayBuffer,
};
- // PausableObject
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
ExecutionContext* GetExecutionContext() const override;
- void Pause() override;
- void Unpause() override;
// ScriptWrappable
bool HasPendingActivity() const final;
@@ -191,7 +189,7 @@ class XMLHttpRequest final : public XMLHttpRequestEventTarget,
void DidReceiveData(const char* data, unsigned data_length) override;
// When responseType is set to "blob", didDownloadData() is called instead
// of didReceiveData().
- void DidDownloadData(int data_length) override;
+ void DidDownloadData(unsigned long long data_length) override;
void DidDownloadToBlob(scoped_refptr<BlobDataHandle>) override;
void DidFinishLoading(unsigned long identifier) override;
void DidFail(const ResourceError&) override;
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.cc b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.cc
index ca7c69fe881..6655c124ac8 100644
--- a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.cc
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.cc
@@ -172,20 +172,6 @@ void XMLHttpRequestProgressEventThrottle::Fired() {
StartOneShot(kMinimumProgressEventDispatchingInterval, FROM_HERE);
}
-void XMLHttpRequestProgressEventThrottle::Pause() {
- Stop();
-}
-
-void XMLHttpRequestProgressEventThrottle::Unpause() {
- if (!deferred_.IsSet())
- return;
-
- // Do not dispatch events inline here, since ExecutionContext is iterating
- // over the list of PausableObjects to resume them, and any activated JS
- // event-handler could insert new PausableObjects to the list.
- StartOneShot(TimeDelta(), FROM_HERE);
-}
-
void XMLHttpRequestProgressEventThrottle::Trace(blink::Visitor* visitor) {
visitor->Trace(target_);
}
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h
index d96f80546dc..d3c13afa72f 100644
--- a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h
@@ -85,9 +85,6 @@ class XMLHttpRequestProgressEventThrottle final
// depending on the value of the ProgressEventAction argument.
void DispatchReadyStateChangeEvent(Event*, DeferredEventAction);
- void Pause();
- void Unpause();
-
// Need to promptly stop this timer when it is deemed finalizable.
EAGERLY_FINALIZE();
void Trace(blink::Visitor*);
diff --git a/chromium/third_party/blink/renderer/devtools/BUILD.gn b/chromium/third_party/blink/renderer/devtools/BUILD.gn
index 4437d101415..6c85481b532 100644
--- a/chromium/third_party/blink/renderer/devtools/BUILD.gn
+++ b/chromium/third_party/blink/renderer/devtools/BUILD.gn
@@ -38,7 +38,7 @@ all_devtools_files = [
"front_end/audits2_worker.js",
"front_end/audits2_worker.json",
"front_end/audits2_worker/Audits2Service.js",
- "front_end/audits2_worker/lighthouse/lighthouse-background.js",
+ "front_end/audits2_worker/lighthouse/lighthouse-dt-bundle.js",
"front_end/audits2_worker/module.json",
"front_end/audits2/Audits2Panel.js",
"front_end/audits2/Audits2Controller.js",
@@ -55,6 +55,7 @@ all_devtools_files = [
"front_end/audits2/lighthouse/renderer/details-renderer.js",
"front_end/audits2/lighthouse/renderer/category-renderer.js",
"front_end/audits2/lighthouse/renderer/performance-category-renderer.js",
+ "front_end/audits2/lighthouse/renderer/pwa-category-renderer.js",
"front_end/audits2/lighthouse/renderer/crc-details-renderer.js",
"front_end/audits2/lighthouse/renderer/report-renderer.js",
"front_end/audits2/lighthouse/renderer/util.js",
@@ -104,10 +105,13 @@ all_devtools_files = [
"front_end/changes/ChangesSidebar.js",
"front_end/changes/module.json",
"front_end/cm/activeline.js",
+ "front_end/cm/brace-fold.js",
"front_end/cm/closebrackets.js",
"front_end/cm/codemirror.css",
"front_end/cm/codemirror.js",
"front_end/cm/comment.js",
+ "front_end/cm/foldcode.js",
+ "front_end/cm/foldgutter.js",
"front_end/cm/markselection.js",
"front_end/cm/matchbrackets.js",
"front_end/cm/module.json",
@@ -269,6 +273,8 @@ all_devtools_files = [
"front_end/emulation/devicesSettingsTab.css",
"front_end/emulation/DevicesSettingsTab.js",
"front_end/emulation/EmulatedDevices.js",
+ "front_end/emulation/geolocationsSettingsTab.css",
+ "front_end/emulation/GeolocationsSettingsTab.js",
"front_end/emulation/inspectedPagePlaceholder.css",
"front_end/emulation/InspectedPagePlaceholder.js",
"front_end/emulation/mediaQueryInspector.css",
@@ -355,7 +361,6 @@ all_devtools_files = [
"front_end/inspector_main/nodeIcon.css",
"front_end/inspector_main/renderingOptions.css",
"front_end/inspector_main/RenderingOptions.js",
- "front_end/inspector_main/RequestAppBannerActionDelegate.js",
"front_end/integration_test_runner.js",
"front_end/integration_test_runner.json",
"front_end/javascript_metadata/module.json",
@@ -874,6 +879,71 @@ all_devtools_files = [
"front_end/workspace_diff/module.json",
]
+devtools_test_files = [
+ "front_end/accessibility_test_runner/AccessibilityPaneTestRunner.js",
+ "front_end/accessibility_test_runner/module.json",
+ "front_end/application_test_runner/AppcacheTestRunner.js",
+ "front_end/application_test_runner/CacheStorageTestRunner.js",
+ "front_end/application_test_runner/IndexedDBTestRunner.js",
+ "front_end/application_test_runner/module.json",
+ "front_end/application_test_runner/ResourcesTestRunner.js",
+ "front_end/application_test_runner/ResourceTreeTestRunner.js",
+ "front_end/application_test_runner/ServiceWorkersTestRunner.js",
+ "front_end/audits2_test_runner/Audits2TestRunner.js",
+ "front_end/audits2_test_runner/module.json",
+ "front_end/bindings_test_runner/AutomappingTestRunner.js",
+ "front_end/bindings_test_runner/BindingsTestRunner.js",
+ "front_end/bindings_test_runner/IsolatedFilesystemTestRunner.js",
+ "front_end/bindings_test_runner/module.json",
+ "front_end/bindings_test_runner/OverridesTestRunner.js",
+ "front_end/bindings_test_runner/PersistenceTestRunner.js",
+ "front_end/console_test_runner/ConsoleTestRunner.js",
+ "front_end/console_test_runner/module.json",
+ "front_end/coverage_test_runner/CoverageTestRunner.js",
+ "front_end/coverage_test_runner/module.json",
+ "front_end/cpu_profiler_test_runner/module.json",
+ "front_end/cpu_profiler_test_runner/ProfilerTestRunner.js",
+ "front_end/data_grid_test_runner/DataGridTestRunner.js",
+ "front_end/data_grid_test_runner/module.json",
+ "front_end/device_mode_test_runner/DeviceModeTestRunner.js",
+ "front_end/device_mode_test_runner/module.json",
+ "front_end/elements_test_runner/EditDOMTestRunner.js",
+ "front_end/elements_test_runner/ElementsPanelShadowSelectionOnRefreshTestRunner.js",
+ "front_end/elements_test_runner/ElementsTestRunner.js",
+ "front_end/elements_test_runner/module.json",
+ "front_end/elements_test_runner/SetOuterHTMLTestRunner.js",
+ "front_end/elements_test_runner/StylesUpdateLinksTestRunner.js",
+ "front_end/extensions_test_runner/ExtensionsNetworkTestRunner.js",
+ "front_end/extensions_test_runner/ExtensionsTestRunner.js",
+ "front_end/extensions_test_runner/module.json",
+ "front_end/heap_profiler_test_runner/HeapProfilerTestRunner.js",
+ "front_end/heap_profiler_test_runner/module.json",
+ "front_end/integration_test_runner.html",
+ "front_end/integration_test_runner.js",
+ "front_end/integration_test_runner.json",
+ "front_end/layers_test_runner/LayersTestRunner.js",
+ "front_end/layers_test_runner/module.json",
+ "front_end/network_test_runner/module.json",
+ "front_end/network_test_runner/NetworkTestRunner.js",
+ "front_end/network_test_runner/ProductRegistryTestRunner.js",
+ "front_end/performance_test_runner/module.json",
+ "front_end/performance_test_runner/TimelineDataTestRunner.js",
+ "front_end/performance_test_runner/TimelineTestRunner.js",
+ "front_end/sdk_test_runner/module.json",
+ "front_end/sdk_test_runner/PageMockTestRunner.js",
+ "front_end/security_test_runner/module.json",
+ "front_end/security_test_runner/SecurityTestRunner.js",
+ "front_end/sources_test_runner/AutocompleteTestRunner.js",
+ "front_end/sources_test_runner/DebuggerTestRunner.js",
+ "front_end/sources_test_runner/EditorTestRunner.js",
+ "front_end/sources_test_runner/LiveEditTestRunner.js",
+ "front_end/sources_test_runner/module.json",
+ "front_end/sources_test_runner/SearchTestRunner.js",
+ "front_end/sources_test_runner/SourcesTestRunner.js",
+ "front_end/test_runner/module.json",
+ "front_end/test_runner/TestRunner.js",
+]
+
devtools_embedder_scripts = [
"front_end/devtools_compatibility.js",
"front_end/Tests.js",
@@ -919,9 +989,9 @@ devtools_emulated_devices_images = [
]
devtools_image_files = [
- "front_end/Images/accelerometer-back.png",
+ "front_end/Images/accelerometer-back.svg",
"front_end/Images/accelerometer-bottom.png",
- "front_end/Images/accelerometer-front.png",
+ "front_end/Images/accelerometer-front.svg",
"front_end/Images/accelerometer-left.png",
"front_end/Images/accelerometer-right.png",
"front_end/Images/accelerometer-top.png",
@@ -938,7 +1008,6 @@ devtools_image_files = [
"front_end/Images/chromeRight.png",
"front_end/Images/chromeSelect.png",
"front_end/Images/chromeSelect_2x.png",
- "front_end/Images/deleteIcon.png",
"front_end/Images/errorWave.png",
"front_end/Images/errorWave_2x.png",
"front_end/Images/ic_info_black_18dp.svg",
@@ -1076,6 +1145,30 @@ generated_remote_modules = [
"$resources_out_dir/product_registry_impl/product_registry_impl_module.js",
]
+generated_test_modules = [
+ "$resources_out_dir/accessibility_test_runner/accessibility_test_runner_module.js",
+ "$resources_out_dir/application_test_runner/application_test_runner_module.js",
+ "$resources_out_dir/audits2_test_runner/audits2_test_runner_module.js",
+ "$resources_out_dir/bindings_test_runner/bindings_test_runner_module.js",
+ "$resources_out_dir/console_test_runner/console_test_runner_module.js",
+ "$resources_out_dir/coverage_test_runner/coverage_test_runner_module.js",
+ "$resources_out_dir/cpu_profiler_test_runner/cpu_profiler_test_runner_module.js",
+ "$resources_out_dir/data_grid_test_runner/data_grid_test_runner_module.js",
+ "$resources_out_dir/device_mode_test_runner/device_mode_test_runner_module.js",
+ "$resources_out_dir/elements_test_runner/elements_test_runner_module.js",
+ "$resources_out_dir/extensions_test_runner/extensions_test_runner_module.js",
+ "$resources_out_dir/heap_profiler_test_runner/heap_profiler_test_runner_module.js",
+ "$resources_out_dir/heap_snapshot_worker/heap_snapshot_worker_module.js",
+ "$resources_out_dir/integration_test_runner.html",
+ "$resources_out_dir/integration_test_runner.js",
+ "$resources_out_dir/layers_test_runner/layers_test_runner_module.js",
+ "$resources_out_dir/network_test_runner/network_test_runner_module.js",
+ "$resources_out_dir/performance_test_runner/performance_test_runner_module.js",
+ "$resources_out_dir/sdk_test_runner/sdk_test_runner_module.js",
+ "$resources_out_dir/security_test_runner/security_test_runner_module.js",
+ "$resources_out_dir/sources_test_runner/sources_test_runner_module.js",
+]
+
devtools_applications = [
"audits2_worker",
"devtools_app",
@@ -1124,6 +1217,7 @@ copy("copy_embedder_scripts") {
outputs = [
"$resources_out_dir/{{source_file_part}}",
]
+ data = process_file_template(sources, outputs)
}
copy("copy_htaccess") {
@@ -1133,6 +1227,7 @@ copy("copy_htaccess") {
outputs = [
"$resources_out_dir/.htaccess",
]
+ data = outputs
}
copy("copy_inspector_images") {
@@ -1140,6 +1235,7 @@ copy("copy_inspector_images") {
outputs = [
"$resources_out_dir/Images/{{source_file_part}}",
]
+ data = process_file_template(sources, outputs)
}
copy("copy_emulated_devices_images") {
@@ -1147,6 +1243,7 @@ copy("copy_emulated_devices_images") {
outputs = [
"$resources_out_dir/emulated_devices/{{source_file_part}}",
]
+ data = process_file_template(sources, outputs)
}
action("generate_devtools_grd") {
@@ -1195,6 +1292,7 @@ action("devtools_extension_api") {
outputs = [
"$resources_out_dir/devtools_extension_api.js",
]
+ data = outputs
args = rebase_path(outputs, root_build_dir) +
rebase_path(devtools_extension_api_files, root_build_dir)
@@ -1210,6 +1308,7 @@ action("supported_css_properties") {
outputs = [
"$resources_out_dir/SupportedCSSProperties.js",
]
+ data = outputs
args =
rebase_path(inputs, root_build_dir) + rebase_path(outputs, root_build_dir)
@@ -1225,6 +1324,7 @@ action("aria_properties") {
outputs = [
"$resources_out_dir/accessibility/ARIAProperties.js",
]
+ data = outputs
args =
rebase_path(inputs, root_build_dir) + rebase_path(outputs, root_build_dir)
@@ -1241,6 +1341,7 @@ action("frontend_protocol_sources") {
outputs = [
"$resources_out_dir/InspectorBackendCommands.js",
]
+ data = outputs
args = rebase_path(inputs, root_build_dir) + [
"--output_js_dir",
@@ -1262,11 +1363,12 @@ action("build_release_devtools") {
"scripts/build/rjsmin.py",
]
- inputs = helper_scripts + all_devtools_files + generated_scripts +
- generated_aria_properties + application_templates
+ inputs = helper_scripts + all_devtools_files + devtools_test_files +
+ generated_scripts + generated_aria_properties + application_templates
outputs =
generated_applications + generated_non_autostart_non_remote_modules +
- generated_remote_modules
+ generated_remote_modules + generated_test_modules
+ data = outputs
args = devtools_applications + [
"--input_path",
@@ -1297,6 +1399,7 @@ if (debug_devtools) {
"$resources_out_debug_dir/toolbox.html",
"$resources_out_debug_dir/worker_app.html",
]
+ data = outputs
args = devtools_applications + [
"--input_path",
@@ -1315,6 +1418,7 @@ if (debug_devtools) {
outputs = [
"$resources_out_debug_dir/{{source_file_part}}",
]
+ data = process_file_template(sources, outputs)
}
copy("copy_aria_properties") {
@@ -1328,6 +1432,7 @@ if (debug_devtools) {
outputs = [
"$resources_out_debug_dir/accessibility/{{source_file_part}}",
]
+ data = process_file_template(sources, outputs)
}
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.png b/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.png
deleted file mode 100644
index e300cb9a5c9..00000000000
--- a/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.png
+++ /dev/null
Binary files differ
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.svg b/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.svg
new file mode 100644
index 00000000000..603a0942ab5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-back.svg
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 770.00001 1580"
+ version="1.1"
+ width="770"
+ height="1580"
+ id="svg11071">
+ <defs
+ id="defs3775" />
+ <metadata
+ id="metadata11076">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(-1,0,0,1,770.5,0)"
+ id="layer3">
+ <path
+ style="fill:none;stroke:#ff8800;stroke-width:9"
+ d="M 766,366 V 466"
+ id="path11635" />
+ <path
+ style="fill:none;stroke:#888888;stroke-width:9"
+ d="M 766,768 V 568"
+ id="path11637" />
+ <g
+ style="fill-rule:evenodd"
+ id="g3764">
+ <rect
+ style="fill:#222222"
+ x="0"
+ y="0"
+ width="767"
+ height="1580"
+ ry="80"
+ rx="80"
+ id="rect11633" />
+ </g>
+ <g
+ style="fill:#ffffff;fill-rule:evenodd"
+ id="g3769">
+ <rect
+ style="fill-opacity:0.13332998"
+ x="273.5"
+ y="1526"
+ width="220"
+ height="15"
+ ry="5"
+ rx="5"
+ id="rect11707" />
+ <path
+ style="fill-opacity:0.86667002"
+ d="M 70.36319,6.9493575 C 28.332124,5.755102 4.8083241,47.982906 4.8378685,83.222978 L 6.032124,1507.7128 c 0.025949,30.952 32.037776,68.2787 64.633409,68.2161 l 622.086167,-1.1942 c 30.87325,-0.059 68.21618,-37.2632 68.21618,-64.6334 V 76.057445 c 0,-31.282766 -24.68851,-66.7195765 -63.13681,-70.302343 C 456.89848,4.61017 269.72229,6.9493575 70.36319,6.9493575 Z"
+ id="path11722" />
+ </g>
+ </g>
+</svg>
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.png b/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.png
deleted file mode 100644
index e78de3e3f81..00000000000
--- a/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.png
+++ /dev/null
Binary files differ
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.svg b/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.svg
new file mode 100644
index 00000000000..564eb7b296d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/Images/accelerometer-front.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg id="svg11071" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="1580" width="770" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 770.00001 1580">
+ <metadata id="metadata11076">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ <dc:title/>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g id="layer3">
+ <path id="path11635" d="m766 366v100" stroke="#f80" stroke-width="9" fill="none"/>
+ <path id="path11637" d="m766 768v-200" stroke="#888" stroke-width="9" fill="none"/>
+ <g fill-rule="evenodd">
+ <rect id="rect11633" rx="80" ry="80" height="1580" width="767" y="0" x="0" fill="#222"/>
+ <rect id="rect11061" fill-opacity=".13333" rx="5" ry="5" height="18" width="80" y="80" x="343.5" fill="#fff"/>
+ <circle id="path11063" cx="459" fill-opacity=".26667" cy="76.25" r="15" fill="#00f"/>
+ <circle id="path11069" cx="297.25" fill-opacity=".26667" cy="74" r="17.5" fill="#00f"/>
+ </g>
+ <g fill-rule="evenodd" fill="#fff">
+ <rect id="rect11705" fill-opacity=".13333" rx="10" ry="10" height="25" width="50" y="34" x="358.5"/>
+ <rect id="rect11707" fill-opacity=".13333" rx="5" ry="5" height="15" width="220" y="1526" x="273.5"/>
+ <path id="path11722" d="m83.5 38c-27.7 0-50 22.3-50 50v1360c0 16.62 13.38 30 30 30h640c16.62 0 30-13.38 30-30v-1360c0-27.7-22.3-50-50-50h-90-50c-19.39 0-35 15.61-35 35v4c0 24.93-20.07 45-45 45h-160c-24.93 0-45-20.07-45-45v-4c0-19.39-15.61-35-35-35h-70z" fill-opacity=".86667"/>
+ </g>
+ </g>
+</svg>
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/Images/deleteIcon.png b/chromium/third_party/blink/renderer/devtools/front_end/Images/deleteIcon.png
deleted file mode 100644
index f0dd0db138e..00000000000
--- a/chromium/third_party/blink/renderer/devtools/front_end/Images/deleteIcon.png
+++ /dev/null
Binary files differ
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/Images/whatsnew.png b/chromium/third_party/blink/renderer/devtools/front_end/Images/whatsnew.png
index 47735c156da..bb96abe42f6 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/Images/whatsnew.png
+++ b/chromium/third_party/blink/renderer/devtools/front_end/Images/whatsnew.png
Binary files differ
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js
index 34708e0c70d..9075c5e80eb 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js
@@ -112,7 +112,7 @@ Accessibility.AXBreadcrumbsPane = class extends Accessibility.AccessibilitySubPa
_onKeyDown(event) {
if (!this._preselectedBreadcrumb)
return;
- if (!event.path.some(element => element === this._preselectedBreadcrumb.element()))
+ if (!event.composedPath().some(element => element === this._preselectedBreadcrumb.element()))
return;
if (event.shiftKey || event.metaKey || event.ctrlKey)
return;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityModel.js b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityModel.js
index 6dd0923f285..9d64b087e0b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityModel.js
@@ -151,13 +151,6 @@ Accessibility.AccessibilityNode = class {
// Highlight node in page.
this.deferredDOMNode().highlight();
-
- // Highlight node in Elements tree.
- this.deferredDOMNode().resolvePromise().then(node => {
- if (!node)
- return;
- node.domModel().overlayModel().nodeHighlightRequested(node.id);
- });
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js
index 0706be5c305..f7776e3e938 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js
@@ -151,7 +151,7 @@ Accessibility.AXNodePropertyTreeElement = class extends UI.TreeElement {
* @return {!Element}
*/
static createExclamationMark(tooltip) {
- const exclamationElement = createElement('label', 'dt-icon-label');
+ const exclamationElement = createElement('span', 'dt-icon-label');
exclamationElement.type = 'smallicon-warning';
exclamationElement.title = tooltip;
return exclamationElement;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css
index a6e59cac7ee..7b624a9e021 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css
@@ -47,7 +47,7 @@ span.ax-value-undefined {
padding-left: 4px;
}
-.tree-outline label[is=dt-icon-label] {
+.tree-outline span[is=dt-icon-label] {
position: relative;
left: -11px;
}
@@ -74,7 +74,7 @@ span.ax-value-undefined {
left: -2px;
}
-.tree-outline label[is=dt-icon-label] + .ax-name {
+.tree-outline span[is=dt-icon-label] + .ax-name {
margin-left: -11px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/CacheStorageTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/CacheStorageTestRunner.js
index a0b90cbf450..8773a5dba56 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/CacheStorageTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/CacheStorageTestRunner.js
@@ -7,17 +7,33 @@
* @suppress {accessControls}
*/
-ApplicationTestRunner.dumpCacheTree = async function() {
+ApplicationTestRunner.dumpCacheTree = async function(pathFilter) {
UI.panels.resources._sidebar.cacheStorageListTreeElement.expand();
const promise = TestRunner.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, '_updateCacheNames');
UI.panels.resources._sidebar.cacheStorageListTreeElement._refreshCaches();
await promise;
- await ApplicationTestRunner.dumpCacheTreeNoRefresh();
+ await ApplicationTestRunner.dumpCacheTreeNoRefresh(pathFilter);
};
-ApplicationTestRunner.dumpCacheTreeNoRefresh = async function() {
+ApplicationTestRunner.dumpCacheTreeNoRefresh = async function(pathFilter) {
+ function _dumpDataGrid(dataGrid, indentSpaces) {
+ for (const node of dataGrid.rootNode().children) {
+ const children = Array.from(node.element().children).filter(function(element) {
+ return !element.classList.contains('responseTime-column');
+ });
+
+ const entries = Array.from(children, td => td.textContent).filter(text => text);
+ TestRunner.addResult(' '.repeat(8) + entries.join(', '));
+ }
+ }
+
UI.panels.resources._sidebar.cacheStorageListTreeElement.expand();
- TestRunner.addResult('Dumping CacheStorage tree:');
+
+ if (!pathFilter)
+ TestRunner.addResult('Dumping CacheStorage tree:');
+ else
+ TestRunner.addResult('Dumping CacheStorage tree with URL path filter string "' + pathFilter + '"');
+
const cachesTreeElement = UI.panels.resources._sidebar.cacheStorageListTreeElement;
if (!cachesTreeElement.childCount()) {
@@ -29,31 +45,29 @@ ApplicationTestRunner.dumpCacheTreeNoRefresh = async function() {
const cacheTreeElement = cachesTreeElement.childAt(i);
TestRunner.addResult(' cache: ' + cacheTreeElement.title);
let view = cacheTreeElement._view;
- promise = TestRunner.addSnifferPromise(Resources.ServiceWorkerCacheView.prototype, '_updateDataCallback');
if (!view)
cacheTreeElement.onselect(false);
- else
- view._updateData(true);
-
view = cacheTreeElement._view;
- await promise;
-
- if (view._entriesForTest.length === 0) {
+ await view._updateData(true);
+ if (cacheTreeElement._view._entriesForTest.length === 0) {
TestRunner.addResult(' (cache empty)');
continue;
}
- const dataGrid = view._dataGrid;
-
- for (const node of dataGrid.rootNode().children) {
- const children = Array.from(node.element().children).filter(function(element) {
- return !element.classList.contains('responseTime-column');
- });
+ if (!pathFilter) {
+ _dumpDataGrid(view._dataGrid);
+ continue;
+ }
- const entries = Array.from(children, td => td.textContent).filter(text => text);
- TestRunner.addResult(' ' + entries.join(', '));
+ cacheTreeElement._view._entryPathFilter = pathFilter;
+ await view._updateData(true);
+ if (cacheTreeElement._view._entriesForTest.length === 0) {
+ TestRunner.addResult(' (no matching entries)');
+ continue;
}
+
+ _dumpDataGrid(cacheTreeElement._view._dataGrid);
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/IndexedDBTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/IndexedDBTestRunner.js
index 0ab404b2530..9cb4080c83e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/IndexedDBTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/IndexedDBTestRunner.js
@@ -104,6 +104,10 @@ ApplicationTestRunner.createDatabase = function(frameId, databaseName, callback)
ApplicationTestRunner.evaluateWithCallback(frameId, 'createDatabase', [databaseName], callback);
};
+ApplicationTestRunner.createDatabaseWithVersion = function(frameId, databaseName, version, callback) {
+ ApplicationTestRunner.evaluateWithCallback(frameId, 'createDatabaseWithVersion', [databaseName, version], callback);
+};
+
ApplicationTestRunner.deleteDatabase = function(frameId, databaseName, callback) {
ApplicationTestRunner.evaluateWithCallback(frameId, 'deleteDatabase', [databaseName], callback);
};
@@ -256,6 +260,17 @@ const __indexedDBHelpers = `
}
}
+ function createDatabaseWithVersion(callback, databaseName, version) {
+ let request = indexedDB.open(databaseName, version);
+ request.onerror = onIndexedDBError;
+ request.onsuccess = closeDatabase;
+
+ function closeDatabase() {
+ request.result.close();
+ callback();
+ }
+ }
+
function deleteDatabase(callback, databaseName) {
let request = indexedDB.deleteDatabase(databaseName);
request.onerror = onIndexedDBError;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/ServiceWorkersTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/ServiceWorkersTestRunner.js
index f83e6d9df15..320b6e21c0c 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/ServiceWorkersTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/application_test_runner/ServiceWorkersTestRunner.js
@@ -47,6 +47,8 @@ ApplicationTestRunner.dumpServiceWorkersView = function() {
return swView._currentWorkersView._sectionList.childTextNodes()
.concat(swView._otherWorkersView._sectionList.childTextNodes())
.map(function(node) {
+ if (node.textContent === 'Received ' + (new Date(0)).toLocaleString())
+ return 'Invalid scriptResponseTime (unix epoch)';
return node.textContent.replace(/Received.*/, 'Received').replace(/#\d+/, '#N');
})
.join('\n');
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/category-renderer.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/category-renderer.js
index 973526c5ef4..c20523bcf26 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/category-renderer.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/category-renderer.js
@@ -22,6 +22,7 @@
/** @typedef {import('./report-renderer.js')} ReportRenderer */
/** @typedef {import('./details-renderer.js')} DetailsRenderer */
/** @typedef {import('./util.js')} Util */
+/** @typedef {'failed'|'warning'|'manual'|'passed'|'notApplicable'} TopLevelClumpId */
class CategoryRenderer {
/**
@@ -40,6 +41,18 @@ class CategoryRenderer {
}
/**
+ * Display info per top-level clump. Define on class to avoid race with Util init.
+ */
+ get _clumpTitles() {
+ return {
+ warning: Util.UIStrings.warningAuditsGroupTitle,
+ manual: Util.UIStrings.manualAuditsGroupTitle,
+ passed: Util.UIStrings.passedAuditsGroupTitle,
+ notApplicable: Util.UIStrings.notApplicableAuditsGroupTitle,
+ };
+ }
+
+ /**
* @param {LH.ReportResult.AuditRef} audit
* @param {number} index
* @return {Element}
@@ -129,19 +142,20 @@ class CategoryRenderer {
*/
_setRatingClass(element, score, scoreDisplayMode) {
const rating = Util.calculateRating(score, scoreDisplayMode);
- element.classList.add(`lh-audit--${rating}`, `lh-audit--${scoreDisplayMode}`);
+ element.classList.add(`lh-audit--${rating}`, `lh-audit--${scoreDisplayMode.toLowerCase()}`);
return element;
}
/**
* @param {LH.ReportResult.Category} category
+ * @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
* @return {Element}
*/
- renderCategoryHeader(category) {
+ renderCategoryHeader(category, groupDefinitions) {
const tmpl = this.dom.cloneTemplate('#tmpl-lh-category-header', this.templateContext);
const gaugeContainerEl = this.dom.find('.lh-score__gauge', tmpl);
- const gaugeEl = this.renderScoreGauge(category);
+ const gaugeEl = this.renderScoreGauge(category, groupDefinitions);
gaugeContainerEl.appendChild(gaugeEl);
this.dom.find('.lh-category-header__title', tmpl).appendChild(
@@ -158,19 +172,13 @@ class CategoryRenderer {
* Renders the group container for a group of audits. Individual audit elements can be added
* directly to the returned element.
* @param {LH.Result.ReportGroup} group
- * @param {{expandable: boolean, itemCount?: number}} opts
* @return {Element}
*/
- renderAuditGroup(group, opts) {
- const expandable = opts.expandable;
- const groupEl = this.dom.createElement(expandable ? 'details' : 'div', 'lh-audit-group');
- const summmaryEl = this.dom.createChildOf(groupEl, 'summary', 'lh-audit-group__summary');
- const headerEl = this.dom.createChildOf(summmaryEl, 'div', 'lh-audit-group__header');
- const itemCountEl = this.dom.createChildOf(summmaryEl, 'div', 'lh-audit-group__itemcount');
- if (expandable) {
- const chevronEl = summmaryEl.appendChild(this._createChevron());
- chevronEl.title = Util.UIStrings.auditGroupExpandTooltip;
- }
+ renderAuditGroup(group) {
+ const groupEl = this.dom.createElement('div', 'lh-audit-group');
+ const summaryEl = this.dom.createChildOf(groupEl, 'div');
+ const summaryInnerEl = this.dom.createChildOf(summaryEl, 'div', 'lh-audit-group__summary');
+ const headerEl = this.dom.createChildOf(summaryInnerEl, 'div', 'lh-audit-group__header');
if (group.description) {
const auditGroupDescription = this.dom.createElement('div', 'lh-audit-group__description');
@@ -179,84 +187,112 @@ class CategoryRenderer {
}
headerEl.textContent = group.title;
- if (opts.itemCount) {
- // TODO(i18n): support multiple locales here
- itemCountEl.textContent = `${opts.itemCount} audits`;
- }
return groupEl;
}
/**
- * Find the total number of audits contained within a section.
- * Accounts for nested subsections like Accessibility.
- * @param {Array<Element>} elements
- * @return {number}
+ * Takes an array of auditRefs, groups them if requested, then returns an
+ * array of audit and audit-group elements.
+ * @param {Array<LH.ReportResult.AuditRef>} auditRefs
+ * @param {Object<string, LH.Result.ReportGroup>} groupDefinitions
+ * @return {Array<Element>}
*/
- _getTotalAuditsLength(elements) {
- // Create a scratch element to append sections to so we can reuse querySelectorAll().
- const scratch = this.dom.createElement('div');
- elements.forEach(function(element) {
- scratch.appendChild(element);
- });
- const subAudits = scratch.querySelectorAll('.lh-audit');
- if (subAudits.length) {
- return subAudits.length;
- } else {
- return elements.length;
+ _renderGroupedAudits(auditRefs, groupDefinitions) {
+ // Audits grouped by their group (or under notAGroup).
+ /** @type {Map<string, Array<LH.ReportResult.AuditRef>>} */
+ const grouped = new Map();
+
+ // Add audits without a group first so they will appear first.
+ const notAGroup = 'NotAGroup';
+ grouped.set(notAGroup, []);
+
+ for (const auditRef of auditRefs) {
+ const groupId = auditRef.group || notAGroup;
+ const groupAuditRefs = grouped.get(groupId) || [];
+ groupAuditRefs.push(auditRef);
+ grouped.set(groupId, groupAuditRefs);
}
- }
- /**
- * @param {Array<Element>} elements
- * @return {Element}
- */
- _renderFailedAuditsSection(elements) {
- const failedElem = this.dom.createElement('div');
- failedElem.classList.add('lh-failed-audits');
- elements.forEach(elem => failedElem.appendChild(elem));
- return failedElem;
- }
+ /** @type {Array<Element>} */
+ const auditElements = [];
+ // Continuous numbering across all groups.
+ let index = 0;
- /**
- * @param {Array<Element>} elements
- * @return {Element}
- */
- renderPassedAuditsSection(elements) {
- const passedElem = this.renderAuditGroup({
- title: Util.UIStrings.passedAuditsGroupTitle,
- }, {expandable: true, itemCount: this._getTotalAuditsLength(elements)});
- passedElem.classList.add('lh-passed-audits');
- elements.forEach(elem => passedElem.appendChild(elem));
- return passedElem;
+ for (const [groupId, groupAuditRefs] of grouped) {
+ if (groupId === notAGroup) {
+ // Push not-grouped audits individually.
+ for (const auditRef of groupAuditRefs) {
+ auditElements.push(this.renderAudit(auditRef, index++));
+ }
+ continue;
+ }
+
+ // Push grouped audits as a group.
+ const groupDef = groupDefinitions[groupId];
+ const auditGroupElem = this.renderAuditGroup(groupDef);
+ for (const auditRef of groupAuditRefs) {
+ auditGroupElem.appendChild(this.renderAudit(auditRef, index++));
+ }
+ auditGroupElem.classList.add(`lh-audit-group--${groupId}`);
+ auditElements.push(auditGroupElem);
+ }
+
+ return auditElements;
}
/**
- * @param {Array<Element>} elements
+ * Take a set of audits, group them if they have groups, then render in a top-level
+ * clump that can't be expanded/collapsed.
+ * @param {Array<LH.ReportResult.AuditRef>} auditRefs
+ * @param {Object<string, LH.Result.ReportGroup>} groupDefinitions
* @return {Element}
*/
- _renderNotApplicableAuditsSection(elements) {
- const notApplicableElem = this.renderAuditGroup({
- title: Util.UIStrings.notApplicableAuditsGroupTitle,
- }, {expandable: true, itemCount: this._getTotalAuditsLength(elements)});
- notApplicableElem.classList.add('lh-audit-group--not-applicable');
- elements.forEach(elem => notApplicableElem.appendChild(elem));
- return notApplicableElem;
+ renderUnexpandableClump(auditRefs, groupDefinitions) {
+ const clumpElement = this.dom.createElement('div');
+ const elements = this._renderGroupedAudits(auditRefs, groupDefinitions);
+ elements.forEach(elem => clumpElement.appendChild(elem));
+ return clumpElement;
}
/**
- * @param {Array<LH.ReportResult.AuditRef>} manualAudits
- * @param {string} [manualDescription]
+ * Take a set of audits and render in a top-level, expandable clump that starts
+ * in a collapsed state.
+ * @param {Exclude<TopLevelClumpId, 'failed'>} clumpId
+ * @param {{auditRefs: Array<LH.ReportResult.AuditRef>, description?: string}} clumpOpts
* @return {Element}
*/
- _renderManualAudits(manualAudits, manualDescription) {
- const group = {title: Util.UIStrings.manualAuditsGroupTitle, description: manualDescription};
- const auditGroupElem = this.renderAuditGroup(group,
- {expandable: true, itemCount: manualAudits.length});
- auditGroupElem.classList.add('lh-audit-group--manual');
- manualAudits.forEach((audit, i) => {
- auditGroupElem.appendChild(this.renderAudit(audit, i));
- });
- return auditGroupElem;
+ renderClump(clumpId, {auditRefs, description}) {
+ const clumpTmpl = this.dom.cloneTemplate('#tmpl-lh-clump', this.templateContext);
+ const clumpElement = this.dom.find('.lh-clump', clumpTmpl);
+
+ if (clumpId === 'warning') {
+ clumpElement.setAttribute('open', '');
+ }
+
+ const summaryInnerEl = this.dom.find('.lh-audit-group__summary', clumpElement);
+ const chevronEl = summaryInnerEl.appendChild(this._createChevron());
+ chevronEl.title = Util.UIStrings.auditGroupExpandTooltip;
+
+ const headerEl = this.dom.find('.lh-audit-group__header', clumpElement);
+ const title = this._clumpTitles[clumpId];
+ headerEl.textContent = title;
+ if (description) {
+ const markdownDescriptionEl = this.dom.convertMarkdownLinkSnippets(description);
+ const auditGroupDescription = this.dom.createElement('div', 'lh-audit-group__description');
+ auditGroupDescription.appendChild(markdownDescriptionEl);
+ clumpElement.appendChild(auditGroupDescription);
+ }
+
+ const itemCountEl = this.dom.find('.lh-audit-group__itemcount', clumpElement);
+ // TODO(i18n): support multiple locales here
+ itemCountEl.textContent = `${auditRefs.length} audits`;
+
+ // Add all audit results to the clump.
+ const auditElements = auditRefs.map(this.renderAudit.bind(this));
+ clumpElement.append(...auditElements);
+
+ clumpElement.classList.add(`lh-clump--${clumpId.toLowerCase()}`);
+ return clumpElement;
}
/**
@@ -269,9 +305,10 @@ class CategoryRenderer {
/**
* @param {LH.ReportResult.Category} category
+ * @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
* @return {DocumentFragment}
*/
- renderScoreGauge(category) {
+ renderScoreGauge(category, groupDefinitions) { // eslint-disable-line no-unused-vars
const tmpl = this.dom.cloneTemplate('#tmpl-lh-gauge', this.templateContext);
const wrapper = /** @type {HTMLAnchorElement} */ (this.dom.find('.lh-gauge__wrapper', tmpl));
wrapper.href = `#${category.id}`;
@@ -302,104 +339,93 @@ class CategoryRenderer {
}
/**
- * @param {LH.ReportResult.Category} category
- * @param {Object<string, LH.Result.ReportGroup>} [groupDefinitions]
- * @return {Element}
+ * @param {LH.ReportResult.AuditRef} audit
+ * @return {boolean}
*/
- render(category, groupDefinitions) {
- const element = this.dom.createElement('div', 'lh-category');
- this.createPermalinkSpan(element, category.id);
- element.appendChild(this.renderCategoryHeader(category));
-
- const auditRefs = category.auditRefs;
- const manualAudits = auditRefs.filter(audit => audit.result.scoreDisplayMode === 'manual');
- const nonManualAudits = auditRefs.filter(audit => !manualAudits.includes(audit));
-
- /** @type {Object<string, {passed: Array<LH.ReportResult.AuditRef>, failed: Array<LH.ReportResult.AuditRef>, notApplicable: Array<LH.ReportResult.AuditRef>}>} */
- const auditsGroupedByGroup = {};
- const auditsUngrouped = {passed: [], failed: [], notApplicable: []};
-
- nonManualAudits.forEach(auditRef => {
- let group;
-
- if (auditRef.group) {
- const groupId = auditRef.group;
+ _auditHasWarning(audit) {
+ return Boolean(audit.result.warnings && audit.result.warnings.length);
+ }
- if (auditsGroupedByGroup[groupId]) {
- group = auditsGroupedByGroup[groupId];
- } else {
- group = {passed: [], failed: [], notApplicable: []};
- auditsGroupedByGroup[groupId] = group;
- }
- } else {
- group = auditsUngrouped;
- }
+ /**
+ * Returns the id of the top-level clump to put this audit in.
+ * @param {LH.ReportResult.AuditRef} auditRef
+ * @return {TopLevelClumpId}
+ */
+ _getClumpIdForAuditRef(auditRef) {
+ const scoreDisplayMode = auditRef.result.scoreDisplayMode;
+ if (scoreDisplayMode === 'manual' || scoreDisplayMode === 'notApplicable') {
+ return scoreDisplayMode;
+ }
- if (auditRef.result.scoreDisplayMode === 'not-applicable') {
- group.notApplicable.push(auditRef);
- } else if (Util.showAsPassed(auditRef.result)) {
- group.passed.push(auditRef);
+ if (Util.showAsPassed(auditRef.result)) {
+ if (this._auditHasWarning(auditRef)) {
+ return 'warning';
} else {
- group.failed.push(auditRef);
- }
- });
-
- const failedElements = /** @type {Array<Element>} */ ([]);
- const passedElements = /** @type {Array<Element>} */ ([]);
- const notApplicableElements = /** @type {Array<Element>} */ ([]);
-
- auditsUngrouped.failed.forEach((audit, i) => failedElements.push(this.renderAudit(audit, i)));
- auditsUngrouped.passed.forEach((audit, i) => passedElements.push(this.renderAudit(audit, i)));
- auditsUngrouped.notApplicable.forEach((audit, i) => notApplicableElements.push(
- this.renderAudit(audit, i)));
-
- Object.keys(auditsGroupedByGroup).forEach(groupId => {
- if (!groupDefinitions) return; // We never reach here if there aren't groups, but TSC needs convincing
-
- const group = groupDefinitions[groupId];
- const groups = auditsGroupedByGroup[groupId];
-
- if (groups.failed.length) {
- const auditGroupElem = this.renderAuditGroup(group, {expandable: false});
- groups.failed.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i)));
- auditGroupElem.classList.add('lh-audit-group--unadorned');
- failedElements.push(auditGroupElem);
+ return 'passed';
}
-
- if (groups.passed.length) {
- const auditGroupElem = this.renderAuditGroup(group, {expandable: true});
- groups.passed.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i)));
- auditGroupElem.classList.add('lh-audit-group--unadorned');
- passedElements.push(auditGroupElem);
- }
-
- if (groups.notApplicable.length) {
- const auditGroupElem = this.renderAuditGroup(group, {expandable: true});
- groups.notApplicable.forEach((item, i) =>
- auditGroupElem.appendChild(this.renderAudit(item, i)));
- auditGroupElem.classList.add('lh-audit-group--unadorned');
- notApplicableElements.push(auditGroupElem);
- }
- });
-
- if (failedElements.length) {
- const failedElem = this._renderFailedAuditsSection(failedElements);
- element.appendChild(failedElem);
+ } else {
+ return 'failed';
}
+ }
- if (manualAudits.length) {
- const manualEl = this._renderManualAudits(manualAudits, category.manualDescription);
- element.appendChild(manualEl);
+ /**
+ * Renders a set of top level sections (clumps), under a status of failed, warning,
+ * manual, passed, or notApplicable. The result ends up something like:
+ *
+ * failed clump
+ * ├── audit 1 (w/o group)
+ * ├── audit 2 (w/o group)
+ * ├── audit group
+ * | ├── audit 3
+ * | └── audit 4
+ * └── audit group
+ * ├── audit 5
+ * └── audit 6
+ * other clump (e.g. 'manual')
+ * ├── audit 1
+ * ├── audit 2
+ * ├── …
+ * ⋮
+ * @param {LH.ReportResult.Category} category
+ * @param {Object<string, LH.Result.ReportGroup>} [groupDefinitions]
+ * @return {Element}
+ */
+ render(category, groupDefinitions = {}) {
+ const element = this.dom.createElement('div', 'lh-category');
+ this.createPermalinkSpan(element, category.id);
+ element.appendChild(this.renderCategoryHeader(category, groupDefinitions));
+
+ // Top level clumps for audits, in order they will appear in the report.
+ /** @type {Map<TopLevelClumpId, Array<LH.ReportResult.AuditRef>>} */
+ const clumps = new Map();
+ clumps.set('failed', []);
+ clumps.set('warning', []);
+ clumps.set('manual', []);
+ clumps.set('passed', []);
+ clumps.set('notApplicable', []);
+
+ // Sort audits into clumps.
+ for (const auditRef of category.auditRefs) {
+ const clumpId = this._getClumpIdForAuditRef(auditRef);
+ const clump = /** @type {Array<LH.ReportResult.AuditRef>} */ (clumps.get(clumpId)); // already defined
+ clump.push(auditRef);
+ clumps.set(clumpId, clump);
}
- if (passedElements.length) {
- const passedElem = this.renderPassedAuditsSection(passedElements);
- element.appendChild(passedElem);
- }
+ // Render each clump.
+ for (const [clumpId, auditRefs] of clumps) {
+ if (auditRefs.length === 0) continue;
+
+ if (clumpId === 'failed') {
+ const clumpElem = this.renderUnexpandableClump(auditRefs, groupDefinitions);
+ clumpElem.classList.add(`lh-clump--failed`);
+ element.appendChild(clumpElem);
+ continue;
+ }
- if (notApplicableElements.length) {
- const notApplicableElem = this._renderNotApplicableAuditsSection(notApplicableElements);
- element.appendChild(notApplicableElem);
+ const description = clumpId === 'manual' ? category.manualDescription : undefined;
+ const clumpElem = this.renderClump(clumpId, {auditRefs, description});
+ element.appendChild(clumpElem);
}
return element;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/crc-details-renderer.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/crc-details-renderer.js
index 0ab374132e3..9ffde229528 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/crc-details-renderer.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/crc-details-renderer.js
@@ -59,7 +59,7 @@ class CriticalRequestChainRenderer {
const node = parent[id];
const siblings = Object.keys(parent);
const isLastChild = siblings.indexOf(id) === (siblings.length - 1);
- const hasChildren = Object.keys(node.children).length > 0;
+ const hasChildren = !!node.children && Object.keys(node.children).length > 0;
// Copy the tree markers so that we don't change by reference.
const newTreeMarkers = Array.isArray(treeMarkers) ? treeMarkers.slice(0) : [];
@@ -149,11 +149,12 @@ class CriticalRequestChainRenderer {
*/
static buildTree(dom, tmpl, segment, elem, details) {
elem.appendChild(CriticalRequestChainRenderer.createChainNode(dom, tmpl, segment));
-
- for (const key of Object.keys(segment.node.children)) {
- const childSegment = CriticalRequestChainRenderer.createSegment(segment.node.children, key,
- segment.startTime, segment.transferSize, segment.treeMarkers, segment.isLastChild);
- CriticalRequestChainRenderer.buildTree(dom, tmpl, childSegment, elem, details);
+ if (segment.node.children) {
+ for (const key of Object.keys(segment.node.children)) {
+ const childSegment = CriticalRequestChainRenderer.createSegment(segment.node.children, key,
+ segment.startTime, segment.transferSize, segment.treeMarkers, segment.isLastChild);
+ CriticalRequestChainRenderer.buildTree(dom, tmpl, childSegment, elem, details);
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/details-renderer.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/details-renderer.js
index a5cf44b33b7..b440662f3b8 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/details-renderer.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/details-renderer.js
@@ -80,6 +80,8 @@ class DetailsRenderer {
case 'opportunity':
// @ts-ignore - TODO(bckenny): Fix type hierarchy
return this._renderOpportunityTable(details);
+ case 'numeric':
+ return this._renderNumeric(/** @type {StringDetailsJSON} */ (details));
default: {
throw new Error(`Unknown type: ${details.type}`);
}
@@ -124,14 +126,11 @@ class DetailsRenderer {
displayedPath = parsed.file === '/' ? parsed.origin : parsed.file;
displayedHost = parsed.file === '/' ? '' : `(${parsed.hostname})`;
title = url;
- } catch (/** @type {!Error} */ e) {
- if (!e.name.startsWith('TypeError')) {
- throw e;
- }
+ } catch (e) {
displayedPath = url;
}
- const element = /** @type {HTMLElement} */ (this._dom.createElement('div', 'lh-text__url'));
+ const element = this._dom.createElement('div', 'lh-text__url');
element.appendChild(this._renderText({
value: displayedPath,
}));
@@ -162,7 +161,7 @@ class DetailsRenderer {
});
}
- const a = /** @type {HTMLAnchorElement} */ (this._dom.createElement('a'));
+ const a = this._dom.createElement('a');
a.rel = 'noopener';
a.target = '_blank';
a.textContent = details.text;
@@ -182,13 +181,23 @@ class DetailsRenderer {
}
/**
+ * @param {{value: string}} text
+ * @return {Element}
+ */
+ _renderNumeric(text) {
+ const element = this._dom.createElement('div', 'lh-numeric');
+ element.textContent = text.value;
+ return element;
+ }
+
+ /**
* Create small thumbnail with scaled down image asset.
* If the supplied details doesn't have an image/* mimeType, then an empty span is returned.
* @param {{value: string}} details
* @return {Element}
*/
_renderThumbnail(details) {
- const element = /** @type {HTMLImageElement}*/ (this._dom.createElement('img', 'lh-thumbnail'));
+ const element = this._dom.createElement('img', 'lh-thumbnail');
const strValue = details.value;
element.src = strValue;
element.title = strValue;
@@ -337,7 +346,7 @@ class DetailsRenderer {
* @protected
*/
renderNode(item) {
- const element = /** @type {HTMLSpanElement} */ (this._dom.createElement('span', 'lh-node'));
+ const element = this._dom.createElement('span', 'lh-node');
if (item.snippet) {
element.textContent = item.snippet;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/dom.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/dom.js
index fa1d564720d..3c10ca6476d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/dom.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/dom.js
@@ -18,6 +18,8 @@
/* globals URL self */
+/** @typedef {HTMLElementTagNameMap & {[id: string]: HTMLElement}} HTMLElmentByTagName */
+
class DOM {
/**
* @param {Document} document
@@ -27,14 +29,14 @@ class DOM {
this._document = document;
}
- // TODO(bckenny): can pass along `createElement`'s inferred type
/**
- * @param {string} name
+ * @template {string} T
+ * @param {T} name
* @param {string=} className
* @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
* Note: if an attribute key has an undefined value, this method does not
* set the attribute on the node.
- * @return {Element}
+ * @return {HTMLElmentByTagName[T]}
*/
createElement(name, className, attrs = {}) {
const element = this._document.createElement(name);
@@ -58,13 +60,14 @@ class DOM {
}
/**
+ * @template {string} T
* @param {Element} parentElem
- * @param {string} elementName
+ * @param {T} elementName
* @param {string=} className
* @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
* Note: if an attribute key has an undefined value, this method does not
* set the attribute on the node.
- * @return {Element}
+ * @return {HTMLElmentByTagName[T]}
*/
createChildOf(parentElem, elementName, className, attrs) {
const element = this.createElement(elementName, className, attrs);
@@ -122,7 +125,7 @@ class DOM {
// Append link if there are any.
if (linkText && linkHref) {
- const a = /** @type {HTMLAnchorElement} */ (this.createElement('a'));
+ const a = this.createElement('a');
a.rel = 'noopener';
a.target = '_blank';
a.textContent = linkText;
@@ -147,7 +150,7 @@ class DOM {
const [preambleText, codeText] = parts.splice(0, 2);
element.appendChild(this._document.createTextNode(preambleText));
if (codeText) {
- const pre = /** @type {HTMLPreElement} */ (this.createElement('code'));
+ const pre = this.createElement('code');
pre.textContent = codeText;
element.appendChild(pre);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/logger.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/logger.js
new file mode 100644
index 00000000000..5fea0543e4c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/logger.js
@@ -0,0 +1,81 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+/**
+ * Logs messages via a UI butter.
+ */
+class Logger {
+ /**
+ * @param {Element} element
+ */
+ constructor(element) {
+ /** @type {Element} */
+ this.el = element;
+ this._id = undefined;
+ }
+
+ /**
+ * Shows a butter bar.
+ * @param {string} msg The message to show.
+ * @param {boolean=} autoHide True to hide the message after a duration.
+ * Default is true.
+ */
+ log(msg, autoHide = true) {
+ this._id && clearTimeout(this._id);
+
+ this.el.textContent = msg;
+ this.el.classList.add('show');
+ if (autoHide) {
+ this._id = setTimeout(_ => {
+ this.el.classList.remove('show');
+ }, 7000);
+ }
+ }
+
+ /**
+ * @param {string} msg
+ */
+ warn(msg) {
+ this.log('Warning: ' + msg);
+ }
+
+ /**
+ * @param {string} msg
+ */
+ error(msg) {
+ this.log(msg);
+
+ // Rethrow to make sure it's auditable as an error, but in a setTimeout so page
+ // recovers gracefully and user can try loading a report again.
+ setTimeout(_ => {
+ throw new Error(msg);
+ }, 0);
+ }
+
+ /**
+ * Explicitly hides the butter bar.
+ */
+ hide() {
+ this._id && clearTimeout(this._id);
+ this.el.classList.remove('show');
+ }
+}
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = Logger;
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/performance-category-renderer.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/performance-category-renderer.js
index 873c0b765c5..870bdfc4e79 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/performance-category-renderer.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/performance-category-renderer.js
@@ -120,16 +120,16 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
const element = this.dom.createElement('div', 'lh-category');
if (environment === 'PSI') {
const gaugeEl = this.dom.createElement('div', 'lh-score__gauge');
- gaugeEl.appendChild(this.renderScoreGauge(category));
+ gaugeEl.appendChild(this.renderScoreGauge(category, groups));
element.appendChild(gaugeEl);
} else {
this.createPermalinkSpan(element, category.id);
- element.appendChild(this.renderCategoryHeader(category));
+ element.appendChild(this.renderCategoryHeader(category, groups));
}
// Metrics
const metricAudits = category.auditRefs.filter(audit => audit.group === 'metrics');
- const metricAuditsEl = this.renderAuditGroup(groups.metrics, {expandable: false});
+ const metricAuditsEl = this.renderAuditGroup(groups.metrics);
const keyMetrics = metricAudits.filter(a => a.weight >= 3);
const otherMetrics = metricAudits.filter(a => a.weight < 3);
@@ -176,7 +176,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
const wastedMsValues = opportunityAudits.map(audit => this._getWastedMs(audit));
const maxWaste = Math.max(...wastedMsValues);
const scale = Math.max(Math.ceil(maxWaste / 1000) * 1000, minimumScale);
- const groupEl = this.renderAuditGroup(groups['load-opportunities'], {expandable: false});
+ const groupEl = this.renderAuditGroup(groups['load-opportunities']);
const tmpl = this.dom.cloneTemplate('#tmpl-lh-opportunity-header', this.templateContext);
this.dom.find('.lh-load-opportunity__col--one', tmpl).textContent =
@@ -188,7 +188,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
groupEl.appendChild(headerEl);
opportunityAudits.forEach((item, i) =>
groupEl.appendChild(this._renderOpportunity(item, i, scale)));
- groupEl.classList.add('lh-audit-group--opportunities');
+ groupEl.classList.add('lh-audit-group--load-opportunities');
element.appendChild(groupEl);
}
@@ -202,21 +202,24 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
});
if (diagnosticAudits.length) {
- const groupEl = this.renderAuditGroup(groups['diagnostics'], {expandable: false});
+ const groupEl = this.renderAuditGroup(groups['diagnostics']);
diagnosticAudits.forEach((item, i) => groupEl.appendChild(this.renderAudit(item, i)));
groupEl.classList.add('lh-audit-group--diagnostics');
element.appendChild(groupEl);
}
// Passed audits
- const passedElements = category.auditRefs
+ const passedAudits = category.auditRefs
.filter(audit => (audit.group === 'load-opportunities' || audit.group === 'diagnostics') &&
- Util.showAsPassed(audit.result))
- .map((audit, i) => this.renderAudit(audit, i));
+ Util.showAsPassed(audit.result));
- if (!passedElements.length) return element;
+ if (!passedAudits.length) return element;
- const passedElem = this.renderPassedAuditsSection(passedElements);
+ const clumpOpts = {
+ auditRefs: passedAudits,
+ groupDefinitions: groups,
+ };
+ const passedElem = this.renderClump('passed', clumpOpts);
element.appendChild(passedElem);
return element;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/psi.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/psi.js
new file mode 100644
index 00000000000..a1b063cc729
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/psi.js
@@ -0,0 +1,84 @@
+/**
+ * @license
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+/* globals self DOM PerformanceCategoryRenderer Util DetailsRenderer */
+
+
+/**
+ * Returns all the elements that PSI needs to render the report
+ * We expose this helper method to minimize the 'public' API surface of the renderer
+ * and allow us to refactor without two-sided patches.
+ *
+ * const {scoreGaugeEl, perfCategoryEl, finalScreenshotDataUri} = prepareLabData(
+ * LHResultJsonString,
+ * document
+ * );
+ *
+ * @param {LH.Result | string} LHResult The stringified version of {LH.Result}
+ * @param {Document} document The host page's window.document
+ * @return {{scoreGaugeEl: Element, perfCategoryEl: Element, finalScreenshotDataUri: string|null}}
+ */
+function prepareLabData(LHResult, document) {
+ const lhResult = (typeof LHResult === 'string') ?
+ /** @type {LH.Result} */ (JSON.parse(LHResult)) : LHResult;
+
+ const dom = new DOM(document);
+
+ // Assume fresh styles needed on every call, so mark all template styles as unused.
+ dom.resetTemplates();
+
+ const reportLHR = Util.prepareReportResult(lhResult);
+ const perfCategory = reportLHR.reportCategories.find(cat => cat.id === 'performance');
+ if (!perfCategory) throw new Error(`No performance category. Can't make lab data section`);
+ if (!reportLHR.categoryGroups) throw new Error(`No category groups found.`);
+
+ // Use custom title and description.
+ reportLHR.categoryGroups.metrics.title = lhResult.i18n.rendererFormattedStrings.labDataTitle;
+ reportLHR.categoryGroups.metrics.description =
+ lhResult.i18n.rendererFormattedStrings.lsPerformanceCategoryDescription;
+
+ const perfRenderer = new PerformanceCategoryRenderer(dom, new DetailsRenderer(dom));
+ // PSI environment string will ensure the categoryHeader and permalink elements are excluded
+ const perfCategoryEl = perfRenderer.render(perfCategory, reportLHR.categoryGroups, 'PSI');
+
+ const scoreGaugeEl = dom.find('.lh-score__gauge', perfCategoryEl);
+ scoreGaugeEl.remove();
+ const scoreGaugeWrapperEl = dom.find('.lh-gauge__wrapper', scoreGaugeEl);
+ scoreGaugeWrapperEl.classList.add('lh-gauge__wrapper--huge');
+ // Remove navigation link on gauge
+ scoreGaugeWrapperEl.removeAttribute('href');
+
+ const finalScreenshotDataUri = _getFinalScreenshot(perfCategory);
+ return {scoreGaugeEl, perfCategoryEl, finalScreenshotDataUri};
+}
+
+/**
+ * @param {LH.ReportResult.Category} perfCategory
+ * @return {null|string}
+ */
+function _getFinalScreenshot(perfCategory) {
+ const auditRef = perfCategory.auditRefs.find(audit => audit.id === 'final-screenshot');
+ if (!auditRef || !auditRef.result || auditRef.result.scoreDisplayMode === 'error') return null;
+ return auditRef.result.details.data;
+}
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = prepareLabData;
+} else {
+ self.prepareLabData = prepareLabData;
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/pwa-category-renderer.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/pwa-category-renderer.js
new file mode 100644
index 00000000000..7e07206f3eb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/pwa-category-renderer.js
@@ -0,0 +1,156 @@
+/**
+ * @license
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+/* globals self, Util, CategoryRenderer */
+
+class PwaCategoryRenderer extends CategoryRenderer {
+ /**
+ * @param {LH.ReportResult.Category} category
+ * @param {Object<string, LH.Result.ReportGroup>} [groupDefinitions]
+ * @return {Element}
+ */
+ render(category, groupDefinitions = {}) {
+ const categoryElem = this.dom.createElement('div', 'lh-category');
+ this.createPermalinkSpan(categoryElem, category.id);
+ categoryElem.appendChild(this.renderCategoryHeader(category, groupDefinitions));
+
+ const auditRefs = category.auditRefs;
+
+ // Regular audits aren't split up into pass/fail/notApplicable clumps, they're
+ // all put in a top-level clump that isn't expandable/collapsable.
+ const regularAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode !== 'manual');
+ const auditsElem = this._renderAudits(regularAuditRefs, groupDefinitions);
+ categoryElem.appendChild(auditsElem);
+
+ // Manual audits are still in a manual clump.
+ const manualAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode === 'manual');
+ const manualElem = this.renderClump('manual',
+ {auditRefs: manualAuditRefs, description: category.manualDescription});
+ categoryElem.appendChild(manualElem);
+
+ return categoryElem;
+ }
+
+ /**
+ * @param {LH.ReportResult.Category} category
+ * @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
+ * @return {DocumentFragment}
+ */
+ renderScoreGauge(category, groupDefinitions) {
+ // Defer to parent-gauge style if category error.
+ if (category.score === null) {
+ return super.renderScoreGauge(category, groupDefinitions);
+ }
+
+ const tmpl = this.dom.cloneTemplate('#tmpl-lh-gauge--pwa', this.templateContext);
+ const wrapper = /** @type {HTMLAnchorElement} */ (this.dom.find('.lh-gauge--pwa__wrapper',
+ tmpl));
+ wrapper.href = `#${category.id}`;
+
+ const allGroups = this._getGroupIds(category.auditRefs);
+ const passingGroupIds = this._getPassingGroupIds(category.auditRefs);
+
+ if (passingGroupIds.size === allGroups.size) {
+ wrapper.classList.add('lh-badged--all');
+ } else {
+ for (const passingGroupId of passingGroupIds) {
+ wrapper.classList.add(`lh-badged--${passingGroupId}`);
+ }
+ }
+
+ this.dom.find('.lh-gauge__label', tmpl).textContent = category.title;
+ wrapper.title = this._getGaugeTooltip(category.auditRefs, groupDefinitions);
+ return tmpl;
+ }
+
+ /**
+ * Returns the group IDs found in auditRefs.
+ * @param {Array<LH.ReportResult.AuditRef>} auditRefs
+ * @return {Set<string>}
+ */
+ _getGroupIds(auditRefs) {
+ const groupIds = auditRefs.map(ref => ref.group).filter(/** @return {g is string} */ g => !!g);
+ return new Set(groupIds);
+ }
+
+ /**
+ * Returns the group IDs whose audits are all considered passing.
+ * @param {Array<LH.ReportResult.AuditRef>} auditRefs
+ * @return {Set<string>}
+ */
+ _getPassingGroupIds(auditRefs) {
+ const uniqueGroupIds = this._getGroupIds(auditRefs);
+
+ // Remove any that have a failing audit.
+ for (const auditRef of auditRefs) {
+ if (!Util.showAsPassed(auditRef.result) && auditRef.group) {
+ uniqueGroupIds.delete(auditRef.group);
+ }
+ }
+
+ return uniqueGroupIds;
+ }
+
+ /**
+ * Returns a tooltip string summarizing group pass rates.
+ * @param {Array<LH.ReportResult.AuditRef>} auditRefs
+ * @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
+ * @return {string}
+ */
+ _getGaugeTooltip(auditRefs, groupDefinitions) {
+ const groupIds = this._getGroupIds(auditRefs);
+
+ const tips = [];
+ for (const groupId of groupIds) {
+ const groupAuditRefs = auditRefs.filter(ref => ref.group === groupId);
+ const auditCount = groupAuditRefs.length;
+ const passedCount = groupAuditRefs.filter(ref => Util.showAsPassed(ref.result)).length;
+
+ const title = groupDefinitions[groupId].title;
+ tips.push(`${title}: ${passedCount}/${auditCount}`);
+ }
+
+ return tips.join(', ');
+ }
+
+ /**
+ * Render non-manual audits in groups, giving a badge to any group that has
+ * all passing audits.
+ * @param {Array<LH.ReportResult.AuditRef>} auditRefs
+ * @param {Object<string, LH.Result.ReportGroup>} groupDefinitions
+ * @return {Element}
+ */
+ _renderAudits(auditRefs, groupDefinitions) {
+ const auditsElem = this.renderUnexpandableClump(auditRefs, groupDefinitions);
+
+ // Add a 'badged' class to group if all audits in that group pass.
+ const passsingGroupIds = this._getPassingGroupIds(auditRefs);
+ for (const groupId of passsingGroupIds) {
+ const groupElem = this.dom.find(`.lh-audit-group--${groupId}`, auditsElem);
+ groupElem.classList.add('lh-badged');
+ }
+
+ return auditsElem;
+ }
+}
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = PwaCategoryRenderer;
+} else {
+ self.PwaCategoryRenderer = PwaCategoryRenderer;
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-renderer.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-renderer.js
index 23e772fb3f5..e04dbcc33f9 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-renderer.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-renderer.js
@@ -26,7 +26,7 @@
/** @typedef {import('./dom.js')} DOM */
/** @typedef {import('./details-renderer.js').DetailsJSON} DetailsJSON */
-/* globals self, Util, DetailsRenderer, CategoryRenderer, PerformanceCategoryRenderer */
+/* globals self, Util, DetailsRenderer, CategoryRenderer, PerformanceCategoryRenderer, PwaCategoryRenderer */
class ReportRenderer {
/**
@@ -42,6 +42,7 @@ class ReportRenderer {
/**
* @param {LH.Result} result
* @param {Element} container Parent element to render the report into.
+ * @return {Element}
*/
renderReport(result, container) {
// Mutate the UIStrings if necessary (while saving originals)
@@ -55,7 +56,7 @@ class ReportRenderer {
// put the UIStrings back into original state
Util.updateAllUIStrings(originalUIStrings);
- return /** @type {Element} **/ (container);
+ return container;
}
/**
@@ -188,24 +189,48 @@ class ReportRenderer {
const detailsRenderer = new DetailsRenderer(this._dom);
const categoryRenderer = new CategoryRenderer(this._dom, detailsRenderer);
categoryRenderer.setTemplateContext(this._templateContext);
- const perfCategoryRenderer = new PerformanceCategoryRenderer(this._dom, detailsRenderer);
- perfCategoryRenderer.setTemplateContext(this._templateContext);
+
+ /** @type {Record<string, CategoryRenderer>} */
+ const specificCategoryRenderers = {
+ performance: new PerformanceCategoryRenderer(this._dom, detailsRenderer),
+ pwa: new PwaCategoryRenderer(this._dom, detailsRenderer),
+ };
+ Object.values(specificCategoryRenderers).forEach(renderer => {
+ renderer.setTemplateContext(this._templateContext);
+ });
const categories = reportSection.appendChild(this._dom.createElement('div', 'lh-categories'));
for (const category of report.reportCategories) {
- if (scoreHeader) {
- scoreHeader.appendChild(categoryRenderer.renderScoreGauge(category));
- }
-
- let renderer = categoryRenderer;
- if (category.id === 'performance') {
- renderer = perfCategoryRenderer;
- }
+ const renderer = specificCategoryRenderers[category.id] || categoryRenderer;
categories.appendChild(renderer.render(category, report.categoryGroups));
}
+ // Fireworks
+ const scoresAll100 = report.reportCategories.every(cat => cat.score === 1);
+ if (scoresAll100 && !this._dom.isDevTools()) {
+ headerContainer.classList.add('score100');
+ this._dom.find('.lh-header', headerContainer).addEventListener('click', _ => {
+ headerContainer.classList.toggle('fireworks-paused');
+ });
+ }
+
if (scoreHeader) {
+ const defaultGauges = [];
+ const customGauges = [];
+ for (const category of report.reportCategories) {
+ const renderer = specificCategoryRenderers[category.id] || categoryRenderer;
+ const categoryGauge = renderer.renderScoreGauge(category, report.categoryGroups || {});
+
+ // Group gauges that aren't default at the end of the header
+ if (renderer.renderScoreGauge === categoryRenderer.renderScoreGauge) {
+ defaultGauges.push(categoryGauge);
+ } else {
+ customGauges.push(categoryGauge);
+ }
+ }
+ scoreHeader.append(...defaultGauges, ...customGauges);
+
const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext);
this._dom.find('.lh-scorescale-label', scoreScale).textContent =
Util.UIStrings.scorescaleLabel;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-ui-features.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-ui-features.js
new file mode 100644
index 00000000000..bfc1b627c52
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/report-ui-features.js
@@ -0,0 +1,492 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+/**
+ * @fileoverview Adds export button, print, and other dynamic functionality to
+ * the report.
+ */
+
+/* globals self URL Blob CustomEvent getFilenamePrefix window */
+
+/** @typedef {import('./dom.js')} DOM */
+
+class ReportUIFeatures {
+ /**
+ * @param {DOM} dom
+ */
+ constructor(dom) {
+ /** @type {LH.ReportResult} */
+ this.json; // eslint-disable-line no-unused-expressions
+ /** @type {DOM} */
+ this._dom = dom;
+ /** @type {Document} */
+ this._document = this._dom.document();
+ /** @type {boolean} */
+ this._copyAttempt = false;
+ /** @type {HTMLElement} */
+ this.exportButton; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.headerSticky; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.headerBackground; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.headerContent; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.lighthouseIcon; // eslint-disable-line no-unused-expressions
+ /** @type {!HTMLElement} */
+ this.scoresWrapperBg; // eslint-disable-line no-unused-expressions
+ /** @type {!HTMLElement} */
+ this.productInfo; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.toolbar; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.toolbarMetadata; // eslint-disable-line no-unused-expressions
+ /** @type {HTMLElement} */
+ this.env; // eslint-disable-line no-unused-expressions
+ /** @type {number} */
+ this.headerOverlap = 0;
+ /** @type {number} */
+ this.headerHeight = 0;
+ /** @type {number} */
+ this.latestKnownScrollY = 0;
+ /** @type {boolean} */
+ this.isAnimatingHeader = false;
+
+ this.onMediaQueryChange = this.onMediaQueryChange.bind(this);
+ this.onCopy = this.onCopy.bind(this);
+ this.onExportButtonClick = this.onExportButtonClick.bind(this);
+ this.onExport = this.onExport.bind(this);
+ this.onKeyDown = this.onKeyDown.bind(this);
+ this.printShortCutDetect = this.printShortCutDetect.bind(this);
+ this.onScroll = this.onScroll.bind(this);
+ this.onChevronClick = this.onChevronClick.bind(this);
+ }
+
+ /**
+ * Adds export button, print, and other functionality to the report. The method
+ * should be called whenever the report needs to be re-rendered.
+ * @param {LH.ReportResult} report
+ */
+ initFeatures(report) {
+ if (this._dom.isDevTools()) return;
+
+ this.json = report;
+ this._setupMediaQueryListeners();
+ this._setupExportButton();
+ this._setUpCollapseDetailsAfterPrinting();
+ this._setupHeaderAnimation();
+ this._resetUIState();
+ this._document.addEventListener('keydown', this.printShortCutDetect);
+ this._document.addEventListener('copy', this.onCopy);
+ }
+
+ /**
+ * Fires a custom DOM event on target.
+ * @param {string} name Name of the event.
+ * @param {Node=} target DOM node to fire the event on.
+ * @param {*=} detail Custom data to include.
+ */
+ _fireEventOn(name, target = this._document, detail) {
+ const event = new CustomEvent(name, detail ? {detail} : undefined);
+ target.dispatchEvent(event);
+ }
+
+ _setupMediaQueryListeners() {
+ const mediaQuery = self.matchMedia('(max-width: 500px)');
+ mediaQuery.addListener(this.onMediaQueryChange);
+ // Ensure the handler is called on init
+ this.onMediaQueryChange(mediaQuery);
+ }
+
+ /**
+ * Handle media query change events.
+ * @param {MediaQueryList|MediaQueryListEvent} mql
+ */
+ onMediaQueryChange(mql) {
+ const root = this._dom.find('.lh-root', this._document);
+ root.classList.toggle('lh-narrow', mql.matches);
+ }
+
+ _setupExportButton() {
+ this.exportButton = this._dom.find('.lh-export__button', this._document);
+ this.exportButton.addEventListener('click', this.onExportButtonClick);
+
+ const dropdown = this._dom.find('.lh-export__dropdown', this._document);
+ dropdown.addEventListener('click', this.onExport);
+ }
+
+ _setupHeaderAnimation() {
+ const scoresWrapper = this._dom.find('.lh-scores-wrapper', this._document);
+ const computedMarginTop = window.getComputedStyle(scoresWrapper).marginTop;
+ this.headerOverlap = parseFloat(computedMarginTop || '0');
+ this.headerSticky = this._dom.find('.lh-header-sticky', this._document);
+ this.headerBackground = this._dom.find('.lh-header-bg', this._document);
+ this.headerContent = this._dom.find('.lh-header', this._document);
+ this.lighthouseIcon = this._dom.find('.lh-lighthouse', this._document);
+ this.scoresWrapperBg = this._dom.find('.lh-scores-wrapper__background', this._document);
+ this.productInfo = this._dom.find('.lh-product-info', this._document);
+ this.toolbar = this._dom.find('.lh-toolbar', this._document);
+ this.toolbarMetadata = this._dom.find('.lh-toolbar__metadata', this._document);
+ const computedHeight = window.getComputedStyle(this.headerBackground).height;
+ this.headerHeight = parseFloat(computedHeight || '0');
+
+ this._document.addEventListener('scroll', this.onScroll, {passive: true});
+
+ const toolbarChevron = this._dom.find('.lh-toggle-arrow', this.toolbar);
+ toolbarChevron.addEventListener('click', this.onChevronClick);
+ }
+
+ /**
+ * Handle copy events.
+ * @param {ClipboardEvent} e
+ */
+ onCopy(e) {
+ // Only handle copy button presses (e.g. ignore the user copying page text).
+ if (this._copyAttempt) {
+ // We want to write our own data to the clipboard, not the user's text selection.
+ e.preventDefault();
+ e.clipboardData.setData('text/plain', JSON.stringify(this.json, null, 2));
+
+ this._fireEventOn('lh-log', this._document, {
+ cmd: 'log', msg: 'Report JSON copied to clipboard',
+ });
+ }
+
+ this._copyAttempt = false;
+ }
+
+ /**
+ * Copies the report JSON to the clipboard (if supported by the browser).
+ */
+ onCopyButtonClick() {
+ this._fireEventOn('lh-analytics', this._document, {
+ cmd: 'send',
+ fields: {hitType: 'event', eventCategory: 'report', eventAction: 'copy'},
+ });
+
+ try {
+ if (this._document.queryCommandSupported('copy')) {
+ this._copyAttempt = true;
+
+ // Note: In Safari 10.0.1, execCommand('copy') returns true if there's
+ // a valid text selection on the page. See http://caniuse.com/#feat=clipboard.
+ if (!this._document.execCommand('copy')) {
+ this._copyAttempt = false; // Prevent event handler from seeing this as a copy attempt.
+
+ this._fireEventOn('lh-log', this._document, {
+ cmd: 'warn', msg: 'Your browser does not support copy to clipboard.',
+ });
+ }
+ }
+ } catch (/** @type {Error} */ e) {
+ this._copyAttempt = false;
+ this._fireEventOn('lh-log', this._document, {cmd: 'log', msg: e.message});
+ }
+ }
+
+ onScroll() {
+ this.latestKnownScrollY = window.scrollY;
+
+ if (!this.isAnimatingHeader) {
+ window.requestAnimationFrame(this.animateHeader.bind(this));
+ }
+ this.isAnimatingHeader = true;
+ }
+
+ onChevronClick() {
+ const toggle = this._dom.find('.lh-config__settings-toggle', this._document);
+
+ if (toggle.hasAttribute('open')) {
+ toggle.removeAttribute('open');
+ } else {
+ toggle.setAttribute('open', 'true');
+ }
+ }
+
+ animateHeader() {
+ const collapsedHeaderHeight = 50;
+ const heightDiff = this.headerHeight - collapsedHeaderHeight + this.headerOverlap;
+ const scrollPct = Math.max(0, Math.min(1,
+ this.latestKnownScrollY / (this.headerHeight - collapsedHeaderHeight)));
+
+ const scoresContainer = /** @type {HTMLElement} */ (this.scoresWrapperBg.parentElement);
+
+ this.headerSticky.style.transform = `translateY(${heightDiff * scrollPct * -1}px)`;
+ this.headerBackground.style.transform = `translateY(${scrollPct * this.headerOverlap}px)`;
+ this.lighthouseIcon.style.transform =
+ `translate3d(0,` +
+ `-${scrollPct * this.headerOverlap * -1}px, 0) scale(${1 - scrollPct})`;
+ this.headerContent.style.opacity = (1 - scrollPct).toString();
+
+ // Switch up the score background & shadows
+ this.scoresWrapperBg.style.opacity = (1 - scrollPct).toString();
+ this.scoresWrapperBg.style.transform = `scaleY(${1 - scrollPct * 0.2})`;
+ const scoreShadow = this._dom.find('.lh-scores-wrapper__shadow', scoresContainer);
+ scoreShadow.style.opacity = scrollPct.toString();
+ scoreShadow.style.transform = `scaleY(${1 - scrollPct * 0.2})`;
+
+ // Fade & move the scorescale
+ try {
+ const scoreScalePositionDelta = 32;
+ const scoreScale = this._dom.find('.lh-scorescale', scoresContainer);
+ scoreScale.style.opacity = `${1 - scrollPct}`;
+ scoreScale.style.transform = `translateY(${scrollPct * -scoreScalePositionDelta}px)`;
+ } catch (e) {}
+
+ // Move the toolbar & export
+ this.toolbar.style.transform = `translateY(${heightDiff * scrollPct}px)`;
+ const exportParent = this.exportButton.parentElement;
+ if (exportParent) {
+ exportParent.style.transform = `translateY(${heightDiff * scrollPct}px)`;
+ }
+ this.exportButton.style.transform = `scale(${1 - 0.2 * scrollPct})`;
+ // Start showing the productinfo when we are at the 50% mark of our animation
+ const opacity = scrollPct < 0.5 ? 0 : (scrollPct - 0.5) * 2;
+ this.productInfo.style.opacity = this.toolbarMetadata.style.opacity = opacity.toString();
+
+ this.isAnimatingHeader = false;
+ }
+
+ closeExportDropdown() {
+ this.exportButton.classList.remove('active');
+ }
+
+ /**
+ * Click handler for export button.
+ * @param {Event} e
+ */
+ onExportButtonClick(e) {
+ e.preventDefault();
+ const el = /** @type {Element} */ (e.target);
+ el.classList.toggle('active');
+ this._document.addEventListener('keydown', this.onKeyDown);
+ }
+
+ /**
+ * Resets the state of page before capturing the page for export.
+ * When the user opens the exported HTML page, certain UI elements should
+ * be in their closed state (not opened) and the templates should be unstamped.
+ */
+ _resetUIState() {
+ this.closeExportDropdown();
+ this._dom.resetTemplates();
+ }
+
+ /**
+ * Handler for "export as" button.
+ * @param {Event} e
+ */
+ onExport(e) {
+ e.preventDefault();
+
+ const el = /** @type {?Element} */ (e.target);
+
+ if (!el || !el.hasAttribute('data-action')) {
+ return;
+ }
+
+ switch (el.getAttribute('data-action')) {
+ case 'copy':
+ this.onCopyButtonClick();
+ break;
+ case 'print-summary':
+ this.collapseAllDetails();
+ this.closeExportDropdown();
+ self.print();
+ break;
+ case 'print-expanded':
+ this.expandAllDetails();
+ this.closeExportDropdown();
+ self.print();
+ break;
+ case 'save-json': {
+ const jsonStr = JSON.stringify(this.json, null, 2);
+ this._saveFile(new Blob([jsonStr], {type: 'application/json'}));
+ break;
+ }
+ case 'save-html': {
+ const htmlStr = this.getReportHtml();
+ try {
+ this._saveFile(new Blob([htmlStr], {type: 'text/html'}));
+ } catch (/** @type {Error} */ e) {
+ this._fireEventOn('lh-log', this._document, {
+ cmd: 'error', msg: 'Could not export as HTML. ' + e.message,
+ });
+ }
+ break;
+ }
+ case 'open-viewer': {
+ const viewerPath = '/lighthouse/viewer/';
+ ReportUIFeatures.openTabAndSendJsonReport(this.json, viewerPath);
+ break;
+ }
+ case 'save-gist': {
+ this.saveAsGist();
+ break;
+ }
+ }
+
+ this.closeExportDropdown();
+ this._document.removeEventListener('keydown', this.onKeyDown);
+ }
+
+ /**
+ * Keydown handler for the document.
+ * @param {KeyboardEvent} e
+ */
+ onKeyDown(e) {
+ if (e.keyCode === 27) { // ESC
+ this.closeExportDropdown();
+ }
+ }
+
+ /**
+ * Opens a new tab to the online viewer and sends the local page's JSON results
+ * to the online viewer using postMessage.
+ * @param {LH.ReportResult} reportJson
+ * @param {string} viewerPath
+ * @protected
+ */
+ static openTabAndSendJsonReport(reportJson, viewerPath) {
+ const VIEWER_ORIGIN = 'https://googlechrome.github.io';
+ // Chrome doesn't allow us to immediately postMessage to a popup right
+ // after it's created. Normally, we could also listen for the popup window's
+ // load event, however it is cross-domain and won't fire. Instead, listen
+ // for a message from the target app saying "I'm open".
+ const json = reportJson;
+ window.addEventListener('message', function msgHandler(messageEvent) {
+ if (messageEvent.origin !== VIEWER_ORIGIN) {
+ return;
+ }
+ if (popup && messageEvent.data.opened) {
+ popup.postMessage({lhresults: json}, VIEWER_ORIGIN);
+ window.removeEventListener('message', msgHandler);
+ }
+ });
+
+ // The popup's window.name is keyed by version+url+fetchTime, so we reuse/select tabs correctly
+ // @ts-ignore - If this is a v2 LHR, use old `generatedTime`.
+ const fallbackFetchTime = /** @type {string} */ (json.generatedTime);
+ const fetchTime = json.fetchTime || fallbackFetchTime;
+ const windowName = `${json.lighthouseVersion}-${json.requestedUrl}-${fetchTime}`;
+ const popup = window.open(`${VIEWER_ORIGIN}${viewerPath}`, windowName);
+ }
+
+ /**
+ * Expands audit details when user prints via keyboard shortcut.
+ * @param {KeyboardEvent} e
+ */
+ printShortCutDetect(e) {
+ if ((e.ctrlKey || e.metaKey) && e.keyCode === 80) { // Ctrl+P
+ this.closeExportDropdown();
+ }
+ }
+
+ /**
+ * Expands all audit `<details>`.
+ * Ideally, a print stylesheet could take care of this, but CSS has no way to
+ * open a `<details>` element.
+ */
+ expandAllDetails() {
+ const details = /** @type {Array<HTMLDetailsElement>} */ (this._dom.findAll(
+ '.lh-categories details', this._document));
+ details.map(detail => detail.open = true);
+ }
+
+ /**
+ * Collapses all audit `<details>`.
+ * open a `<details>` element.
+ */
+ collapseAllDetails() {
+ const details = /** @type {Array<HTMLDetailsElement>} */ (this._dom.findAll(
+ '.lh-categories details', this._document));
+ details.map(detail => detail.open = false);
+ }
+
+ /**
+ * Sets up listeners to collapse audit `<details>` when the user closes the
+ * print dialog, all `<details>` are collapsed.
+ */
+ _setUpCollapseDetailsAfterPrinting() {
+ // FF and IE implement these old events.
+ if ('onbeforeprint' in self) {
+ self.addEventListener('afterprint', this.collapseAllDetails);
+ } else {
+ const win = /** @type {Window} */ (self);
+ // Note: FF implements both window.onbeforeprint and media listeners. However,
+ // it doesn't matchMedia doesn't fire when matching 'print'.
+ win.matchMedia('print').addListener(mql => {
+ if (mql.matches) {
+ this.expandAllDetails();
+ } else {
+ this.collapseAllDetails();
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns the html that recreates this report.
+ * @return {string}
+ * @protected
+ */
+ getReportHtml() {
+ this._resetUIState();
+ // @ts-ignore - technically documentElement can be null, but that's dumb - https://dom.spec.whatwg.org/#document-element
+ return this._document.documentElement.outerHTML;
+ }
+
+ /**
+ * Save json as a gist. Unimplemented in base UI features.
+ * @protected
+ */
+ saveAsGist() {
+ throw new Error('Cannot save as gist from base report');
+ }
+
+ /**
+ * Downloads a file (blob) using a[download].
+ * @param {Blob|File} blob The file to save.
+ * @private
+ */
+ _saveFile(blob) {
+ const filename = getFilenamePrefix({
+ finalUrl: this.json.finalUrl,
+ fetchTime: this.json.fetchTime,
+ });
+
+ const ext = blob.type.match('json') ? '.json' : '.html';
+ const href = URL.createObjectURL(blob);
+
+ const a = this._dom.createElement('a');
+ a.download = `${filename}${ext}`;
+ a.href = href;
+ this._document.body.appendChild(a); // Firefox requires anchor to be in the DOM.
+ a.click();
+
+ // cleanup.
+ this._document.body.removeChild(a);
+ setTimeout(_ => URL.revokeObjectURL(href), 500);
+ }
+}
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = ReportUIFeatures;
+} else {
+ self.ReportUIFeatures = ReportUIFeatures;
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/util.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/util.js
index 2b1996a1da8..6a752d517f3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/util.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/renderer/util.js
@@ -62,6 +62,16 @@ class Util {
if (typeof clone.categories !== 'object') throw new Error('No categories provided.');
clone.reportCategories = Object.values(clone.categories);
+ // Turn 'not-applicable' and 'not_applicable' into 'notApplicable' to support old reports.
+ // TODO: remove when underscore/hyphen proto issue is resolved. See #6371, #6201, #6783.
+ for (const audit of Object.values(clone.audits)) {
+ // @ts-ignore tsc rightly flags that this value shouldn't occur.
+ // eslint-disable-next-line max-len
+ if (audit.scoreDisplayMode === 'not_applicable' || audit.scoreDisplayMode === 'not-applicable') {
+ audit.scoreDisplayMode = 'notApplicable';
+ }
+ }
+
// For convenience, smoosh all AuditResults into their auditDfn (which has just weight & group)
for (const category of clone.reportCategories) {
category.auditRefs.forEach(auditMeta => {
@@ -134,7 +144,7 @@ class Util {
static showAsPassed(audit) {
switch (audit.scoreDisplayMode) {
case 'manual':
- case 'not-applicable':
+ case 'notApplicable':
return true;
case 'error':
case 'informative':
@@ -154,7 +164,7 @@ class Util {
*/
static calculateRating(score, scoreDisplayMode) {
// Handle edge cases first, manual and not applicable receive 'pass', errored audits receive 'error'
- if (scoreDisplayMode === 'manual' || scoreDisplayMode === 'not-applicable') {
+ if (scoreDisplayMode === 'manual' || scoreDisplayMode === 'notApplicable') {
return RATINGS.PASS.label;
} else if (scoreDisplayMode === 'error') {
return RATINGS.ERROR.label;
@@ -398,7 +408,7 @@ class Util {
networkThrottling = `${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, ` +
`${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, ` +
`${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
- summary = 'Throttled Fast 3G network';
+ summary = 'Throttled Slow 4G network';
break;
}
case 'simulate': {
@@ -406,7 +416,7 @@ class Util {
cpuThrottling = `${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
networkThrottling = `${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, ` +
`${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
- summary = 'Simulated Fast 3G network';
+ summary = 'Simulated Slow 4G network';
break;
}
default:
@@ -467,6 +477,8 @@ Util.UIStrings = {
warningHeader: 'Warnings: ',
/** The tooltip text on an expandable chevron icon. Clicking the icon expands a section to reveal a list of audit results that was hidden by default. */
auditGroupExpandTooltip: 'Show audits',
+ /** Section heading shown above a list of passed audits that contain warnings. Audits under this section do not negatively impact the score, but Lighthouse has generated some potentially actionable suggestions that should be reviewed. This section is expanded by default and displays after the failing audits. */
+ warningAuditsGroupTitle: 'Passed audits but with warnings',
/** Section heading shown above a list of audits that are passing. 'Passed' here refers to a passing grade. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list. */
passedAuditsGroupTitle: 'Passed audits',
/** Section heading shown above a list of audits that do not apply to the page. For example, if an audit is 'Are images optimized?', but the page has no images on it, the audit will be marked as not applicable. This is neither passing or failing. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list. */
@@ -484,8 +496,8 @@ Util.UIStrings = {
/** Label of value shown in the summary of critical request chains. Refers to the total amount of time (milliseconds) of the longest critical path chain/sequence of network requests. Example value: 2310 ms */
crcLongestDurationLabel: 'Maximum critical path latency:',
- /** Explanation shown to users below performance results to inform them that the test was done with a 3G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation. */
- lsPerformanceCategoryDescription: '[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on emulated 3G. Values are estimated and may vary.',
+ /** Explanation shown to users below performance results to inform them that the test was done with a 4G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation. */
+ lsPerformanceCategoryDescription: '[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.',
/** Title of the lab data section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. "Lab" is an abbreviated form of "laboratory", and refers to the fact that the data is from a controlled test of a website, not measurements from real users visiting that site. */
labDataTitle: 'Lab Data',
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/report-styles.css b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/report-styles.css
index c65e8e5359d..8ece38dc6be 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/report-styles.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/report-styles.css
@@ -54,6 +54,9 @@
--metric-timeline-rule-color: #b3b3b3;
--display-value-gray: hsl(216, 5%, 39%);
--report-width: calc(60 * var(--body-font-size));
+ --report-min-width: 400px;
+ /* Edge doesn't support calc(var(calc())) */
+ --report-width-half: calc(30 * var(--body-font-size));
--report-header-height: 161px;
--report-header-color: #202124;
--navitem-font-size: var(--body-font-size);
@@ -62,6 +65,7 @@
--navitem-vpadding: calc(var(--navitem-line-height) / 2);
--lh-score-highlight-bg: hsla(0, 0%, 90%, 0.2);
--lh-score-icon-background-size: 24px;
+ --lh-group-icon-background-size: var(--lh-score-icon-background-size);
--lh-score-margin: 12px;
--lh-table-header-bg: #f8f9fa;
--lh-table-higlight-bg: hsla(0, 0%, 75%, 0.1);
@@ -76,22 +80,30 @@
--lh-audit-group-vpadding: 8px;
--lh-section-vpadding: 12px;
--chevron-size: 12px;
+ --circle-size: calc(3 * var(--header-font-size));
- /* Voodoo magic here to get narrow columns. 0 doesn't size the column like our friend 1px does */
- --bytes-col-width: 1px;
- --pass-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>check</title><path fill="hsl(139, 70%, 30%)" d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z"/></svg>');
- --average-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>info</title><path fill="hsl(31, 100%, 45%)" d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm2 30h-4V22h4v12zm0-16h-4v-4h4v4z"/></svg>');
- --fail-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>warn</title><path fill="hsl(1, 73%, 45%)" d="M2 42h44L24 4 2 42zm24-6h-4v-4h4v4zm0-8h-4v-8h4v8z"/></svg>');
-
- --content-paste-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="hsl(216, 5%, 39%)" d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
- --av-timer-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="hsl(216, 5%, 39%)"><path d="M0 0h24v24H0z" fill="none"/><path d="M15 1H9v2h6V1zm-4 13h2V8h-2v6zm8.03-6.61l1.42-1.42c-.43-.51-.9-.99-1.41-1.41l-1.42 1.42A8.962 8.962 0 0 0 12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9a8.994 8.994 0 0 0 7.03-14.61zM12 20c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></svg>');
- --photo-filter-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path fill="none" d="M0 0h48v48H0V0z"/><path d="M38.04 20v18H10V10h18V6H10.04c-2.2 0-4 1.8-4 4v28c0 2.2 1.8 4 4 4h28c2.2 0 4-1.8 4-4V20h-4zM34 20l1.88-4.12L40 14l-4.12-1.88L34 8l-1.88 4.12L28 14l4.12 1.88zm-7.5 1.5L24 16l-2.5 5.5L16 24l5.5 2.5L24 32l2.5-5.5L32 24z" fill="hsl(216, 5%, 39%)"/></svg>');
- --visibility-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 9C14 9 5.46 15.22 2 24c3.46 8.78 12 15 22 15 10.01 0 18.54-6.22 22-15-3.46-8.78-11.99-15-22-15zm0 25c-5.52 0-10-4.48-10-10s4.48-10 10-10 10 4.48 10 10-4.48 10-10 10zm0-16c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z" fill="hsl(216, 5%, 39%)"/></svg>');
- --check-circle-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z" fill="hsl(216, 5%, 39%)"/></svg>');
+ --pass-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>check</title><path fill="%23178239" d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z"/></svg>');
+ --average-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>info</title><path fill="%23E67700" d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm2 30h-4V22h4v12zm0-16h-4v-4h4v4z"/></svg>');
+ --fail-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>warn</title><path fill="%23C7221F" d="M2 42h44L24 4 2 42zm24-6h-4v-4h4v4zm0-8h-4v-8h4v8z"/></svg>');
+
+ --content-paste-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="%235E6268" d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
+ --av-timer-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="%235E6268"><path d="M0 0h24v24H0z" fill="none"/><path d="M15 1H9v2h6V1zm-4 13h2V8h-2v6zm8.03-6.61l1.42-1.42c-.43-.51-.9-.99-1.41-1.41l-1.42 1.42A8.962 8.962 0 0 0 12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9a8.994 8.994 0 0 0 7.03-14.61zM12 20c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></svg>');
+ --photo-filter-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path fill="none" d="M0 0h48v48H0V0z"/><path d="M38.04 20v18H10V10h18V6H10.04c-2.2 0-4 1.8-4 4v28c0 2.2 1.8 4 4 4h28c2.2 0 4-1.8 4-4V20h-4zM34 20l1.88-4.12L40 14l-4.12-1.88L34 8l-1.88 4.12L28 14l4.12 1.88zm-7.5 1.5L24 16l-2.5 5.5L16 24l5.5 2.5L24 32l2.5-5.5L32 24z" fill="%235E6268"/></svg>');
+ --visibility-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 9C14 9 5.46 15.22 2 24c3.46 8.78 12 15 22 15 10.01 0 18.54-6.22 22-15-3.46-8.78-11.99-15-22-15zm0 25c-5.52 0-10-4.48-10-10s4.48-10 10-10 10 4.48 10 10-4.48 10-10 10zm0-16c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z" fill="%235E6268"/></svg>');
+ --check-circle-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z" fill="%235E6268"/></svg>');
--check-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M18 32.34L9.66 24l-2.83 2.83L18 38l24-24-2.83-2.83z"/></svg>');
- --search-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55.55V31l10 9.98L40.98 38 31 28zm-12 0a9 9 0 1 1 .001-18.001A9 9 0 0 1 19 28z" fill="hsl(216, 5%, 39%)"/><path d="M0 0h48v48H0z" fill="none" /></svg>');
- --remove-circle-icon-url: url('data:image/svg+xml;utf8,<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="hsl(216, 5%, 39%)"/></svg>');
+ --warning-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>warn</title><path fill="%235E6268" d="M2 42h44L24 4 2 42zm24-6h-4v-4h4v4zm0-8h-4v-8h4v8z"/></svg>');
+ --search-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55.55V31l10 9.98L40.98 38 31 28zm-12 0a9 9 0 1 1 .001-18.001A9 9 0 0 1 19 28z" fill="%235E6268"/><path d="M0 0h48v48H0z" fill="none" /></svg>');
+ --remove-circle-icon-url: url('data:image/svg+xml;utf8,<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="%235E6268"/></svg>');
+
+ --pwa-fast-reliable-gray-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="nonzero"><circle fill="%23DAE0E3" cx="12" cy="12" r="12"/><path d="M12.3 4l6.3 2.8V11c0 3.88-2.69 7.52-6.3 8.4C8.69 18.52 6 14.89 6 11V6.8L12.3 4zm-.56 12.88l3.3-5.79.04-.08c.05-.1.01-.29-.26-.29h-1.96l.56-3.92h-.56L9.6 12.52c0 .03.07-.12-.03.07-.11.2-.12.37.2.37h1.97l-.56 3.92h.56z" fill="%23FFF"/></g></svg>');
+ --pwa-installable-gray-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="nonzero"><circle fill="%23DAE0E3" cx="12" cy="12" r="12"/><path d="M12 5a7 7 0 1 0 0 14 7 7 0 0 0 0-14zm3.5 7.7h-2.8v2.8h-1.4v-2.8H8.5v-1.4h2.8V8.5h1.4v2.8h2.8v1.4z" fill="%23FFF"/></g></svg>');
+ --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><rect fill="%23DAE0E3" width="24" height="24" rx="12"/><path fill="%23FFF" d="M12 15.07l3.6 2.18-.95-4.1 3.18-2.76-4.2-.36L12 6.17l-1.64 3.86-4.2.36 3.2 2.76-.96 4.1z"/><path d="M5 5h14v14H5z"/></g></svg>');
+
+ --pwa-fast-reliable-color-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero" fill="none"><circle fill="%23CCE3F6" cx="12" cy="12" r="12"/><path d="M12 4.3l6.3 2.8v4.2c0 3.88-2.69 7.52-6.3 8.4-3.61-.88-6.3-4.51-6.3-8.4V7.1L12 4.3zm-.56 12.88l3.3-5.79.04-.08c.05-.1.01-.29-.26-.29h-1.96l.56-3.92h-.56L9.3 12.82c0 .03.07-.12-.03.07-.11.2-.12.37.2.37h1.97l-.56 3.92h.56z" fill="%23304FFE"/></g></svg>');
+ --pwa-installable-color-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero" fill="none"><circle fill="%23D4ECD5" cx="12" cy="12" r="12"/><path d="M12 5a7 7 0 1 0 0 14 7 7 0 0 0 0-14zm3.5 7.7h-2.8v2.8h-1.4v-2.8H8.5v-1.4h2.8V8.5h1.4v2.8h2.8v1.4z" fill="%23009688"/></g></svg>');
+ --pwa-optimized-color-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><rect fill="%23FCE4EC" width="24" height="24" rx="12"/><path d="M5 5h14v14H5z"/><path fill="%23EC3F7A" d="M12 15.07l3.6 2.18-.95-4.1 3.18-2.76-4.2-.36L12 6.17l-1.64 3.86-4.2.36 3.2 2.76-.96 4.1z"/></g></svg>');
}
.lh-vars.lh-devtools {
@@ -312,8 +324,18 @@
background-color: #F8F9FA;
}
-.lh-audit-group__summary::-webkit-details-marker,
-.lh-expandable-details__summary::-webkit-details-marker {
+/* Hide the expandable arrow icon, three ways: via the CSS Counter Styles spec, for webkit/blink browsers, hiding the polyfilled icon */
+/* https://github.com/javan/details-element-polyfill/blob/master/src/details-element-polyfill/polyfill.sass */
+.lh-audit-group > summary,
+.lh-expandable-details > summary {
+ list-style-type: none;
+}
+.lh-audit-group > summary::-webkit-details-marker,
+.lh-expandable-details > summary::-webkit-details-marker {
+ display: none;
+}
+.lh-audit-group > summary:before,
+.lh-expandable-details > summary:before {
display: none;
}
@@ -360,7 +382,7 @@
.lh-metric__innerwrap {
display: flex;
justify-content: space-between;
- padding: 11px var(--text-indent);
+ padding: 8px var(--text-indent);
}
.lh-metric__details {
@@ -508,7 +530,7 @@
.lh-filmstrip-container {
padding: 0 var(--expandable-indent);
/* smaller gap between metrics and filmstrip */
- margin: -16px auto 0 auto;
+ margin: -8px auto 0 auto;
}
.lh-filmstrip {
@@ -564,7 +586,8 @@
}
.lh-audit-group__header::before {
- content: '';
+ /* By default, groups don't get an icon */
+ content: none;
width: calc(var(--subheader-font-size) / 14 * 24);
height: calc(var(--subheader-font-size) / 14 * 24);
margin-right: calc(var(--subheader-font-size) / 2);
@@ -574,29 +597,59 @@
vertical-align: middle;
}
-/* A11y/Seo groups within Passed don't get an icon */
-.lh-audit-group--unadorned .lh-audit-group__header::before {
- content: none;
+.lh-clump--warning > summary .lh-audit-group__header::before {
+ content: '';
+ background-image: var(--warning-icon-url);
}
-
-
-.lh-audit-group--manual .lh-audit-group__header::before {
+.lh-clump--manual > summary .lh-audit-group__header::before {
+ content: '';
background-image: var(--search-icon-url);
}
-.lh-passed-audits .lh-audit-group__header::before {
+.lh-clump--passed > summary .lh-audit-group__header::before {
+ content: '';
background-image: var(--check-icon-url);
}
+.lh-clump--notapplicable > summary .lh-audit-group__header::before {
+ content: '';
+ background-image: var(--remove-circle-icon-url);
+}
+
.lh-audit-group--diagnostics .lh-audit-group__header::before {
+ content: '';
background-image: var(--content-paste-icon-url);
}
-.lh-audit-group--opportunities .lh-audit-group__header::before {
+.lh-audit-group--load-opportunities .lh-audit-group__header::before {
+ content: '';
background-image: var(--photo-filter-icon-url);
}
.lh-audit-group--metrics .lh-audit-group__header::before {
+ content: '';
background-image: var(--av-timer-icon-url);
}
-.lh-audit-group--not-applicable .lh-audit-group__header::before {
- background-image: var(--remove-circle-icon-url);
+
+.lh-audit-group--pwa-fast-reliable .lh-audit-group__header::before {
+ content: '';
+ background-image: var(--pwa-fast-reliable-gray-url);
+ background-size: var(--lh-group-icon-background-size);
+}
+.lh-audit-group--pwa-installable .lh-audit-group__header::before {
+ content: '';
+ background-image: var(--pwa-installable-gray-url);
+ background-size: var(--lh-group-icon-background-size);
+}
+.lh-audit-group--pwa-optimized .lh-audit-group__header::before {
+ content: '';
+ background-image: var(--pwa-optimized-gray-url);
+ background-size: var(--lh-group-icon-background-size);
+}
+.lh-audit-group--pwa-fast-reliable.lh-badged .lh-audit-group__header::before {
+ background-image: var(--pwa-fast-reliable-color-url);
+}
+.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {
+ background-image: var(--pwa-installable-color-url);
+}
+.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {
+ background-image: var(--pwa-optimized-color-url);
}
/* Removing too much whitespace */
@@ -604,11 +657,17 @@
margin-top: calc(var(--circle-size)/2 * -1);
border-bottom: none;
}
+.lh-audit-group--metrics .lh-audit-group__summary {
+ margin-top: 0;
+ margin-bottom: 0;
+}
.lh-audit-group__summary {
display: flex;
justify-content: space-between;
padding-right: var(--text-indent);
+ margin-top: calc(var(--section-padding) * 1.5);
+ margin-bottom: var(--section-padding);
}
.lh-audit-group__itemcount {
@@ -622,11 +681,17 @@
.lh-audit-group__description {
font-size: var(--body-font-size);
color: var(--medium-75-gray);
- margin: var(--lh-audit-group-vpadding) 0;
+ margin: 0 0 var(--lh-audit-group-vpadding);
}
-.lh-audit-group--unadorned .lh-audit-group__description {
- margin-top: 0;
+.lh-clump > .lh-audit-group__description,
+.lh-audit-group--diagnostics .lh-audit-group__description,
+.lh-audit-group--load-opportunities .lh-audit-group__description,
+.lh-audit-group--metrics .lh-audit-group__description,
+.lh-audit-group--pwa-fast-reliable .lh-audit-group__description,
+.lh-audit-group--pwa-installable .lh-audit-group__description,
+.lh-audit-group--pwa-optimized .lh-audit-group__description {
+ margin-top: var(--lh-audit-group-vpadding);
}
.lh-audit-explanation {
@@ -648,9 +713,11 @@
}
.lh-header-sticky {
+ position: -webkit-sticky;
position: sticky;
top: 0;
width: 100%;
+ min-width: var(--report-min-width);
z-index: 2;
will-change: transform;
}
@@ -668,6 +735,7 @@
.lh-report {
background-color: #fff;
+ min-width: var(--report-min-width);
}
@media screen {
.lh-report {
@@ -723,8 +791,13 @@
border: 0;
}
-.lh-scores-header .lh-gauge__wrapper {
- margin: 0 4px;
+.lh-scores-header .lh-gauge__wrapper,
+.lh-scores-header .lh-gauge--pwa__wrapper {
+ padding: 0 4px;
+}
+
+.lh-scores-header .lh-gauge--pwa__wrapper {
+ border-left: 1px solid var(--report-secondary-border-color)
}
.lh-scorescale {
@@ -773,7 +846,6 @@
}
.lh-category {
- --circle-size: calc(2.5 * var(--header-font-size));
padding: var(--section-padding);
}
@@ -820,19 +892,6 @@
line-height: var(--header-line-height);
}
-.lh-passed-audits[open] summary.lh-passed-audits-summary {
- margin-bottom: calc(var(--default-padding) * 2);
-}
-
-summary.lh-passed-audits-summary {
- margin: calc(var(--default-padding) * 2) var(--default-padding);
- margin-left: var(--default-padding);
- margin-bottom: 0;
- font-size: 15px;
- display: flex;
- align-items: center;
-}
-
#lh-log {
position: fixed;
background-color: #323232;
@@ -864,7 +923,6 @@ summary.lh-passed-audits-summary {
.lh-report {
margin-left: 0;
width: 100%;
- min-width: 400px;
}
}
@@ -895,6 +953,7 @@ summary.lh-passed-audits-summary {
.lh-table thead th {
color: var(--medium-75-gray);
font-weight: normal;
+ word-wrap: normal;
}
.lh-table tbody tr:nth-child(even) {
@@ -918,7 +977,8 @@ summary.lh-passed-audits-summary {
.lh-table-column--bytes,
.lh-table-column--timespanMs,
-.lh-table-column--ms {
+.lh-table-column--ms,
+.lh-table-column--numeric {
text-align: right;
}
@@ -930,18 +990,16 @@ summary.lh-passed-audits-summary {
.lh-table-column--url {
min-width: 250px;
white-space: nowrap;
- max-width: 0;
}
-/* Keep bytes columns narrow if they follow the URL column */
+/* Keep columns narrow if they follow the URL column */
+/* 12% was determined to be a decent narrow width, but wide enough for column headings */
.lh-table-column--url + th.lh-table-column--bytes,
.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,
+.lh-table-column--url + .lh-table-column--ms,
+.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,
.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {
- max-width: var(--bytes-col-width);
-}
-
-.lh-table-column--code {
- max-width: var(--url-col-max-width);
+ width: 12%;
}
.lh-text__url {
@@ -975,6 +1033,8 @@ summary.lh-passed-audits-summary {
*/
.lh-chevron {
--chevron-angle: 42deg;
+ /* Edge doesn't support transform: rotate(calc(...)), so we define it here */
+ --chevron-angle-right: -42deg;
width: var(--chevron-size);
height: var(--chevron-size);
margin-top: calc((var(--body-line-height) - 12px) / 2);
@@ -993,19 +1053,19 @@ summary.lh-passed-audits-summary {
transition: transform 300ms, stroke 300ms;
}
-.lh-audit-group > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-right,
-.lh-audit-group[open] > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-left,
+.lh-audit-group > summary > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-right,
+.lh-audit-group[open] > summary > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-left,
.lh-audit > .lh-expandable-details .lh-chevron__line-right,
.lh-audit > .lh-expandable-details[open] .lh-chevron__line-left {
- transform: rotate(calc(var(--chevron-angle) * -1));
+ transform: rotate(var(--chevron-angle-right));
}
-.lh-audit-group[open] > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-right,
+.lh-audit-group[open] > summary > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-right,
.lh-audit > .lh-expandable-details[open] .lh-chevron__line-right {
transform: rotate(var(--chevron-angle));
}
-.lh-audit-group[open] > .lh-audit-group__summary > .lh-chevron .lh-chevron__lines,
+.lh-audit-group[open] > summary > .lh-audit-group__summary > .lh-chevron .lh-chevron__lines,
.lh-audit > .lh-expandable-details[open] .lh-chevron__lines {
transform: translateY(calc(var(--chevron-size) * -1));
}
@@ -1051,6 +1111,7 @@ summary.lh-passed-audits-summary {
z-index: 1;
will-change: opacity;
right: 0;
+ pointer-events: none;
}
.tooltip::before {
@@ -1068,5 +1129,5 @@ summary.lh-passed-audits-summary {
@keyframes fadeInTooltip {
0% { opacity: 0; }
75% { opacity: 1; }
- 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); }
+ 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/templates.html b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/templates.html
index 29e93cb1131..1f90384b387 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/templates.html
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/lighthouse/templates.html
@@ -27,9 +27,9 @@ limitations under the License.
<template id="tmpl-lh-scorescale">
<div class="lh-scorescale">
<span class="lh-scorescale-label"></span>
- <span class="lh-scorescale-range lh-scorescale-range--fail">0-49</span>
- <span class="lh-scorescale-range lh-scorescale-range--average">50-89</span>
<span class="lh-scorescale-range lh-scorescale-range--pass">90-100</span>
+ <span class="lh-scorescale-range lh-scorescale-range--average">50-89</span>
+ <span class="lh-scorescale-range lh-scorescale-range--fail">0-49</span>
</div>
</template>
@@ -37,8 +37,8 @@ limitations under the License.
<template id="tmpl-lh-chevron">
<svg class="lh-chevron" title="See audits" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100">
<g class="lh-chevron__lines">
- <path class="lh-chevron__line lh-chevron__line-left" d="M10 50h40" stroke="#707173"/>
- <path class="lh-chevron__line lh-chevron__line-right" d="M90 50H50" stroke="#707173"/>
+ <path class="lh-chevron__line lh-chevron__line-left" d="M10 50h40" stroke="#707173"></path>
+ <path class="lh-chevron__line lh-chevron__line-right" d="M90 50H50" stroke="#707173"></path>
</g>
</svg>
</template>
@@ -52,16 +52,32 @@ limitations under the License.
</div>
</template>
+<!-- Lighthouse clump -->
+<template id="tmpl-lh-clump">
+ <!-- TODO: group classes shouldn't be reused for clumps. -->
+ <details class="lh-clump lh-audit-group">
+ <summary>
+ <div class="lh-audit-group__summary">
+ <div class="lh-audit-group__header"></div>
+ <div class="lh-audit-group__itemcount"></div>
+ <div class=""></div>
+ </div>
+ </summary>
+ </details>
+</template>
+
<!-- Lighthouse audit -->
<template id="tmpl-lh-audit">
<div class="lh-audit">
<details class="lh-expandable-details">
- <summary class="lh-audit__header lh-expandable-details__summary">
- <span class="lh-audit__index"></span>
- <span class="lh-audit__title"></span>
- <span class="lh-audit__display-text"></span>
- <div class="lh-audit__score-icon"></div>
- <div class="lh-chevron-container"></div>
+ <summary>
+ <div class="lh-audit__header lh-expandable-details__summary">
+ <span class="lh-audit__index"></span>
+ <span class="lh-audit__title"></span>
+ <span class="lh-audit__display-text"></span>
+ <div class="lh-audit__score-icon"></div>
+ <div class="lh-chevron-container"></div>
+ </div>
</summary>
<div class="lh-audit__description"></div>
</details>
@@ -83,21 +99,23 @@ limitations under the License.
<template id="tmpl-lh-opportunity">
<div class="lh-audit lh-audit--load-opportunity">
<details class="lh-expandable-details">
- <summary class="lh-audit__header lh-expandable-details__summary">
- <div class="lh-load-opportunity__cols">
- <div class="lh-load-opportunity__col lh-load-opportunity__col--one">
- <span class="lh-audit__index"></span>
- <div class="lh-audit__title"></div>
- </div>
- <div class="lh-load-opportunity__col lh-load-opportunity__col--two">
- <div class="lh-load-opportunity__sparkline">
- <div class="lh-sparkline"><div class="lh-sparkline__bar"></div></div>
+ <summary>
+ <div class="lh-audit__header lh-expandable-details__summary">
+ <div class="lh-load-opportunity__cols">
+ <div class="lh-load-opportunity__col lh-load-opportunity__col--one">
+ <span class="lh-audit__index"></span>
+ <div class="lh-audit__title"></div>
+ </div>
+ <div class="lh-load-opportunity__col lh-load-opportunity__col--two">
+ <div class="lh-load-opportunity__sparkline">
+ <div class="lh-sparkline"><div class="lh-sparkline__bar"></div></div>
+ </div>
+ <div class="lh-audit__display-text"></div>
+ <div class="lh-chevron-container" title="See resources"></div>
+ </div>
</div>
- <div class="lh-audit__display-text"></div>
- <div class="lh-chevron-container" title="See resources"></div>
</div>
- </div>
- </summary>
+ </summary>
<div class="lh-audit__description"></div>
</details>
</div>
@@ -159,12 +177,12 @@ limitations under the License.
top: 0;
width: 100%;
will-change: transform;
+ contain: strict;
}
.lh-lighthouse {
position: absolute;
- top: var(--report-header-height);
- right: 50%;
- transform: translate3d(calc(var(--report-width) / 2), -100%, 0);
+ bottom: -4px;
+ right: 0;
opacity: 1;
transform-origin: bottom right;
will-change: transform, opacity;
@@ -183,6 +201,7 @@ limitations under the License.
color: var(--report-header-color);
z-index: 1;
position: relative;
+ max-width: 60%;
}
.lh-metadata__results {
text-overflow: ellipsis;
@@ -193,7 +212,6 @@ limitations under the License.
}
.lh-scores-wrapper {
margin-top: -30px;
- transform: translateZ(1px);
}
.lh-scores-wrapper__shadow {
opacity: 0;
@@ -349,37 +367,124 @@ limitations under the License.
77.0001% { transform: translateX(195px); }
100% { transform: translateX(0px); }
} */
+
+ .score100 .lh-header-bg {
+ background-color: hsl(234, 64%, 19%);
+ }
+ .score100 .lh-metadata, .score100 .lh-toolbar__metadata, .score100 .lh-product-info {
+ color: #fff;
+ }
+ .score100 .lh-config {
+ color: #eee;
+ }
+
+ /* CSS Fireworks. Originally by Eddie Lin
+ https://codepen.io/paulirish/pen/yEVMbP
+ */
+ .pyro {
+ display: none;
+ }
+ .score100 .pyro {
+ display: block;
+ }
+ .score100 .lh-lighthouse stop:first-child {
+ stop-color: hsla(200, 12%, 95%, 0);
+ }
+ .score100 .lh-lighthouse stop:last-child {
+ stop-color: hsla(65, 81%, 76%, 1);
+ }
+
+ .pyro > .before, .pyro > .after {
+ position: absolute;
+ width: 5px;
+ height: 5px;
+ border-radius: 2.5px;
+ box-shadow: 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff;
+ animation: 1s bang ease-out infinite backwards, 1s gravity ease-in infinite backwards, 5s position linear infinite backwards;
+ animation-delay: 1s, 1s, 1s;
+ }
+
+ .pyro > .after {
+ animation-delay: 2.25s, 2.25s, 2.25s;
+ animation-duration: 1.25s, 1.25s, 6.25s;
+ }
+ .fireworks-paused .pyro > div {
+ animation-play-state: paused;
+ }
+
+ @keyframes bang {
+ to {
+ box-shadow: -70px -115.67px #47ebbc, -28px -99.67px #eb47a4, 58px -31.67px #7eeb47, 13px -141.67px #eb47c5, -19px 6.33px #7347eb, -2px -74.67px #ebd247, 24px -151.67px #eb47e0, 57px -138.67px #b4eb47, -51px -104.67px #479eeb, 62px 8.33px #ebcf47, -93px 0.33px #d547eb, -16px -118.67px #47bfeb, 53px -84.67px #47eb83, 66px -57.67px #eb47bf, -93px -65.67px #91eb47, 30px -13.67px #86eb47, -2px -59.67px #83eb47, -44px 1.33px #eb47eb, 61px -58.67px #47eb73, 5px -22.67px #47e8eb, -66px -28.67px #ebe247, 42px -123.67px #eb5547, -75px 26.33px #7beb47, 15px -52.67px #a147eb, 36px -51.67px #eb8347, -38px -12.67px #eb5547, -46px -59.67px #47eb81, 78px -114.67px #eb47ba, 15px -156.67px #eb47bf, -36px 1.33px #eb4783, -72px -86.67px #eba147, 31px -46.67px #ebe247, -68px 29.33px #47e2eb, -55px 19.33px #ebe047, -56px 27.33px #4776eb, -13px -91.67px #eb5547, -47px -138.67px #47ebc7, -18px -96.67px #eb47ac, 11px -88.67px #4783eb, -67px -28.67px #47baeb, 53px 10.33px #ba47eb, 11px 19.33px #5247eb, -5px -11.67px #eb4791, -68px -4.67px #47eba7, 95px -37.67px #eb478b, -67px -162.67px #eb5d47, -54px -120.67px #eb6847, 49px -12.67px #ebe047, 88px 8.33px #47ebda, 97px 33.33px #eb8147, 6px -71.67px #ebbc47;
+ }
+ }
+ @keyframes gravity {
+ to {
+ transform: translateY(80px);
+ opacity: 0;
+ }
+ }
+ @keyframes position {
+ 0%, 19.9% {
+ margin-top: 4%;
+ margin-left: 47%;
+ }
+ 20%, 39.9% {
+ margin-top: 7%;
+ margin-left: 30%;
+ }
+ 40%, 59.9% {
+ margin-top: 6%;
+ margin-left: 70%;
+ }
+ 60%, 79.9% {
+ margin-top: 3%;
+ margin-left: 20%;
+ }
+ 80%, 99.9% {
+ margin-top: 3%;
+ margin-left: 80%;
+ }
+ }
</style>
- <div class="lh-header-bg"></div>
- <div class="lh-lighthouse">
- <svg width="217" height="148" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <mask id="a" x="-56" y="-54" width="284" height="202" maskUnits="userSpaceOnUse">
- <path d="M-56-54h284v202H-56z" fill="#fff"/>
- </mask>
- <linearGradient id="b" x1="-525.16" y1="560.08" x2="-524.23" y2="560.08" gradientTransform="matrix(91 0 0 -77 47797 43181)" gradientUnits="userSpaceOnUse">
- <stop offset="0" stop-color="#f1f3f4"/>
- <stop offset="1" stop-color="#fff"/>
- </linearGradient>
- </defs>
- <g mask="url(#a)">
- <path d="M95 47h24v2H95z" fill="#ec5548"/>
- <path d="M98 49h18v11H98z" fill="#fbc21b"/>
- <path d="M95 59h24v7H95z" fill="#ec5548"/>
- <path d="M97.63 66h19.74l2.63 47H95z" fill="#fff"/>
- <path d="M107 38a10 10 0 0 1 10 10v1H97v-1a10 10 0 0 1 10-10zM96.77 82.23l21-10.7.63 11.87-22.31 11.87zM95 110.8L119.1 98l.9 14H95z" fill="#ec5548"/>
- <path d="M0 148a177.58 177.58 0 0 1 217 0z" fill="#e8eaed"/>
- <path d="M103 49a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5z" fill="#fef0c8"/>
- <path d="M7 16l91 33.18v10L7 93z" fill="url(#b)"/>
- </g>
- <g mask="url(#a)" class="lh-lighthouse__clouds">
- <path d="M60 .19A9.77 9.77 0 0 1 61.93 0a9.44 9.44 0 0 1 9.24 7.83A7.24 7.24 0 0 1 79 14.45v.73A7.37 7.37 0 0 1 76.2 21h-31a7.44 7.44 0 0 1-1.2-4.09 7.31 7.31 0 0 1 7.26-7.36 6.84 6.84 0 0 1 1.28.1v-.11A9.51 9.51 0 0 1 60 .19m79.78 22.31h-17.9a4.37 4.37 0 0 1-.63-2.25 4.2 4.2 0 0 1 4.16-4.25 4.37 4.37 0 0 1 .72.06V16a5.35 5.35 0 0 1 10.64-1h.33a4.2 4.2 0 0 1 4.15 4.25 4.29 4.29 0 0 1-1.47 3.25zM163 62h-24.15a5.1 5.1 0 0 1-.85-2.81 5.65 5.65 0 0 1 6.59-5.19v-.08a7.07 7.07 0 0 1 7.24-6.92 7.15 7.15 0 0 1 7.17 5.64h.44a5.46 5.46 0 0 1 5.6 5.32A5.19 5.19 0 0 1 163 62z" fill="#fff"/>
- </g>
- </svg>
+ <div class="lh-header-bg">
+ <div class="pyro">
+ <div class="before"></div>
+ <div class="after"></div>
+ </div>
</div>
+
<div class="lh-header-container">
<div class="lh-header">
+ <div class="lh-lighthouse">
+ <svg width="217" height="148" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <mask id="a" x="-56" y="-54" width="284" height="202" maskUnits="userSpaceOnUse">
+ <path d="M-56-54h284v202H-56z" fill="#fff"></path>
+ </mask>
+ <linearGradient id="b" x1="-525.16" y1="560.08" x2="-524.23" y2="560.08" gradientTransform="matrix(91 0 0 -77 47797 43181)" gradientUnits="userSpaceOnUse">
+ <stop offset="0" stop-color="#FFFFFF00"/>
+ <stop offset="1" stop-color="#FFFFFF"/>
+ </linearGradient>
+ </defs>
+ <g mask="url(#a)">
+ <!-- lighthouse building elements -->
+ <path d="M95 47h24v2H95z" fill="#ec5548"/>
+ <path d="M95 59h24v7H95z" fill="#ec5548"/>
+ <path d="M97.63 66h19.74l2.63 47H95z" fill="#fff"/>
+ <path d="M107 38a10 10 0 0 1 10 10v1H97v-1a10 10 0 0 1 10-10zM96.77 82.23l21-10.7.63 11.87-22.31 11.87zM95 110.8L119.1 98l.9 14H95z" fill="#ec5548"/>
+ <path d="M0 148a177.58 177.58 0 0 1 217 0z" fill="#e8eaed"/>
+ <!-- lighthouse beam elements -->
+ <path d="M98 49h18v11H98z" fill="#fbc21b"/>
+ <path d="M103 49a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5z" fill="#fef0c8"/>
+ <path d="M7 16l91 33.18v10L7 93z" fill="url(#b)"/>
+ </g>
+ <g mask="url(#a)" class="lh-lighthouse__clouds">
+ <path d="M60 .19A9.77 9.77 0 0 1 61.93 0a9.44 9.44 0 0 1 9.24 7.83A7.24 7.24 0 0 1 79 14.45v.73A7.37 7.37 0 0 1 76.2 21h-31a7.44 7.44 0 0 1-1.2-4.09 7.31 7.31 0 0 1 7.26-7.36 6.84 6.84 0 0 1 1.28.1v-.11A9.51 9.51 0 0 1 60 .19m79.78 22.31h-17.9a4.37 4.37 0 0 1-.63-2.25 4.2 4.2 0 0 1 4.16-4.25 4.37 4.37 0 0 1 .72.06V16a5.35 5.35 0 0 1 10.64-1h.33a4.2 4.2 0 0 1 4.15 4.25 4.29 4.29 0 0 1-1.47 3.25zM163 62h-24.15a5.1 5.1 0 0 1-.85-2.81 5.65 5.65 0 0 1 6.59-5.19v-.08a7.07 7.07 0 0 1 7.24-6.92 7.15 7.15 0 0 1 7.17 5.64h.44a5.46 5.46 0 0 1 5.6 5.32A5.19 5.19 0 0 1 163 62z" fill="#fff"/>
+ </g>
+ </svg>
+ </div>
+
<div class="lh-metadata">
<div class="lh-metadata__results"><a href="" class="lh-metadata__url" target="_blank" rel="noopener"></a></div>
<div class="lh-config">
@@ -474,7 +579,6 @@ limitations under the License.
<template id="tmpl-lh-gauge">
<style>
.lh-gauge__wrapper {
- --circle-size: calc(3 * var(--header-font-size));
--circle-size-half: calc(var(--circle-size) / 2);
--circle-background: hsl(216, 12%, 92%);
--circle-border-width: 9;
@@ -570,6 +674,147 @@ limitations under the License.
</a>
</template>
+
+<!-- Lighthouse PWA badge gauge -->
+<template id="tmpl-lh-gauge--pwa">
+ <style>
+ .lh-gauge--pwa__wrapper {
+ display: inline-flex;
+ align-items: center;
+ flex-direction: column;
+ text-decoration: none;
+ flex: 1;
+ min-width: auto;
+ position: relative;
+ }
+ .lh-gauge--pwa {
+ width: var(--circle-size);
+ height: var(--circle-size);
+ }
+ .lh-gauge--pwa .lh-gauge--pwa__component {
+ display: none;
+ }
+ .lh-gauge--pwa__wrapper:not(.lh-badged--all) .lh-gauge--pwa__logo > path {
+ /* Gray logo unless everything is passing. */
+ fill: #B0B0B0;
+ }
+
+ /* No passing groups. */
+ .lh-gauge--pwa__wrapper:not([class*='lh-badged--']) .lh-gauge--pwa__na-line {
+ display: inline;
+ }
+ /* Just optimized. Same n/a line as no passing groups. */
+ .lh-gauge--pwa__wrapper.lh-badged--pwa-optimized .lh-gauge--pwa__na-line {
+ display: inline;
+ }
+
+ /* Just fast and reliable. */
+ .lh-gauge--pwa__wrapper.lh-badged--pwa-fast-reliable:not(.lh-badged--pwa-installable) .lh-gauge--pwa__fast-reliable-badge {
+ display: inline;
+ }
+
+ /* Just installable. */
+ .lh-gauge--pwa__wrapper.lh-badged--pwa-installable:not(.lh-badged--pwa-fast-reliable) .lh-gauge--pwa__installable-badge {
+ display: inline;
+ }
+
+ /* Fast and reliable and installable. */
+ .lh-gauge--pwa__wrapper.lh-badged--pwa-fast-reliable.lh-badged--pwa-installable .lh-gauge--pwa__fast-reliable-installable-badges {
+ display: inline;
+ }
+
+ /* All passing groups. */
+ .lh-gauge--pwa__wrapper.lh-badged--all .lh-gauge--pwa__check-circle {
+ display: inline;
+ }
+
+ .lh-gauge__label {
+ font-size: var(--body-font-size);
+ line-height: var(--body-line-height);
+ margin-top: calc(0.5 * var(--body-line-height));
+ text-align: center;
+ color: black;
+ }
+ </style>
+
+ <a href="#" class="lh-gauge--pwa__wrapper">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" class="lh-gauge--pwa">
+ <defs>
+ <linearGradient id="lh-gauge--pwa__bg-disk__gradient" x1="50%" y1="2.15%" x2="50%" y2="97.645%">
+ <stop stop-color="#F1F3F4" offset="0%"></stop>
+ <stop stop-color="#DEE6EA" offset="100%"></stop>
+ </linearGradient>
+ <linearGradient id="lh-gauge--pwa__check-circle__gradient" x1="50%" y1="0%" x2="50%" y2="100%">
+ <stop stop-color="#00C852" offset="0%"></stop>
+ <stop stop-color="#009688" offset="100%"></stop>
+ </linearGradient>
+ <linearGradient id="lh-gauge--pwa__installable__shadow-gradient" x1="76.056%" x2="24.111%" y1="82.995%" y2="24.735%">
+ <stop stop-color="#A5D6A7" offset="0%"></stop>
+ <stop stop-color="#80CBC4" offset="100%"></stop>
+ </linearGradient>
+ <linearGradient id="lh-gauge--pwa__fast-reliable__shadow-gradient" x1="76.056%" y1="82.995%" x2="25.678%" y2="26.493%">
+ <stop stop-color="#64B5F6" offset="0%"></stop>
+ <stop stop-color="#2979FF" offset="100%"></stop>
+ </linearGradient>
+
+ <g id="lh-gauge--pwa__fast-reliable-badge">
+ <circle fill="#FFFFFF" cx="10" cy="10" r="10"></circle>
+ <path fill="#304FFE" d="M10 3.58l5.25 2.34v3.5c0 3.23-2.24 6.26-5.25 7-3.01-.74-5.25-3.77-5.25-7v-3.5L10 3.58zm-.47 10.74l2.76-4.83.03-.07c.04-.08 0-.24-.22-.24h-1.64l.47-3.26h-.47l-2.7 4.77c-.02.01.05-.1-.04.05-.09.16-.1.31.18.31h1.63l-.47 3.27h.47z"/>
+ </g>
+ <g id="lh-gauge--pwa__installable-badge">
+ <circle fill="#FFFFFF" cx="10" cy="10" r="10"></circle>
+ <path fill="#009688" d="M10 4.167A5.835 5.835 0 0 0 4.167 10 5.835 5.835 0 0 0 10 15.833 5.835 5.835 0 0 0 15.833 10 5.835 5.835 0 0 0 10 4.167zm2.917 6.416h-2.334v2.334H9.417v-2.334H7.083V9.417h2.334V7.083h1.166v2.334h2.334v1.166z"/>
+ </g>
+ </defs>
+
+ <g stroke="none" fill-rule="nonzero">
+ <!-- Background and PWA logo (color by default) -->
+ <circle fill="url(#lh-gauge--pwa__bg-disk__gradient)" cx="30" cy="30" r="30"></circle>
+ <g class="lh-gauge--pwa__logo">
+ <path fill="#3D3D3D" d="M35.66 19.39l.7-1.75h2L37.4 15 38.6 12l3.4 9h-2.51l-.58-1.61z"/>
+ <path fill="#304FFE" d="M33.52 21l3.65-9h-2.42l-2.5 5.82L30.5 12h-1.86l-1.9 5.82-1.35-2.65-1.21 3.72L25.4 21h2.38l1.72-5.2 1.64 5.2z"/>
+ <path fill="#3D3D3D" fill-rule="nonzero" d="M20.3 17.91h1.48c.45 0 .85-.05 1.2-.15l.39-1.18 1.07-3.3a2.64 2.64 0 0 0-.28-.37c-.55-.6-1.36-.91-2.42-.91H18v9h2.3V17.9zm1.96-3.84c.22.22.33.5.33.87 0 .36-.1.65-.29.87-.2.23-.59.35-1.15.35h-.86v-2.41h.87c.52 0 .89.1 1.1.32z"/>
+ </g>
+
+ <!-- No badges. -->
+ <rect class="lh-gauge--pwa__component lh-gauge--pwa__na-line" fill="#FFFFFF" x="20" y="32" width="20" height="4" rx="2"></rect>
+
+ <!-- Just fast and reliable. -->
+ <g class="lh-gauge--pwa__component lh-gauge--pwa__fast-reliable-badge" transform="translate(20, 29)">
+ <path fill="url(#lh-gauge--pwa__fast-reliable__shadow-gradient)" d="M33.63 19.49A30 30 0 0 1 16.2 30.36L3 17.14 17.14 3l16.49 16.49z"/>
+ <use xlink:href="#lh-gauge--pwa__fast-reliable-badge" />
+ </g>
+
+ <!-- Just installable. -->
+ <g class="lh-gauge--pwa__component lh-gauge--pwa__installable-badge" transform="translate(20, 29)">
+ <path fill="url(#lh-gauge--pwa__installable__shadow-gradient)" d="M33.629 19.487c-4.272 5.453-10.391 9.39-17.415 10.869L3 17.142 17.142 3 33.63 19.487z"/>
+ <use xlink:href="#lh-gauge--pwa__installable-badge" />
+ </g>
+
+ <!-- Fast and reliable and installable. -->
+ <g class="lh-gauge--pwa__component lh-gauge--pwa__fast-reliable-installable-badges">
+ <g transform="translate(8, 29)"> <!-- fast and reliable -->
+ <path fill="url(#lh-gauge--pwa__fast-reliable__shadow-gradient)" d="M16.321 30.463L3 17.143 17.142 3l22.365 22.365A29.864 29.864 0 0 1 22 31c-1.942 0-3.84-.184-5.679-.537z"/>
+ <use xlink:href="#lh-gauge--pwa__fast-reliable-badge" />
+ </g>
+ <g transform="translate(32, 29)"> <!-- installable -->
+ <path fill="url(#lh-gauge--pwa__installable__shadow-gradient)" d="M25.982 11.84a30.107 30.107 0 0 1-13.08 15.203L3 17.143 17.142 3l8.84 8.84z"/>
+ <use xlink:href="#lh-gauge--pwa__installable-badge" />
+ </g>
+ </g>
+
+ <!-- Full PWA. -->
+ <g class="lh-gauge--pwa__component lh-gauge--pwa__check-circle" transform="translate(18, 28)">
+ <circle fill="#FFFFFF" cx="12" cy="12" r="12"></circle>
+ <path fill="url(#lh-gauge--pwa__check-circle__gradient)" d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path>
+ </g>
+ </g>
+ </svg>
+
+ <div class="lh-gauge__label"></div>
+ </a>
+</template>
+
<!-- Lighthouse crtiical request chains component -->
<template id="tmpl-lh-crc">
<div class="lh-crc-container">
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2/module.json b/chromium/third_party/blink/renderer/devtools/front_end/audits2/module.json
index b1f07d06d19..61b44db117d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2/module.json
@@ -24,6 +24,7 @@
"lighthouse/renderer/dom.js",
"lighthouse/renderer/category-renderer.js",
"lighthouse/renderer/performance-category-renderer.js",
+ "lighthouse/renderer/pwa-category-renderer.js",
"lighthouse/renderer/details-renderer.js",
"lighthouse/renderer/crc-details-renderer.js",
"lighthouse/renderer/report-renderer.js",
@@ -48,6 +49,7 @@
"lighthouse/renderer/dom.js",
"lighthouse/renderer/category-renderer.js",
"lighthouse/renderer/performance-category-renderer.js",
+ "lighthouse/renderer/pwa-category-renderer.js",
"lighthouse/renderer/details-renderer.js",
"lighthouse/renderer/crc-details-renderer.js",
"lighthouse/renderer/report-renderer.js"
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/Audits2Service.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/Audits2Service.js
index 9d0bfb1a674..75848997d94 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/Audits2Service.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/Audits2Service.js
@@ -40,8 +40,10 @@ var Audits2Service = class { // eslint-disable-line
* @return {!Promise<!ReportRenderer.RunnerResult>}
*/
start(params) {
- if (Runtime.queryParam('isUnderTest'))
+ if (Runtime.queryParam('isUnderTest')) {
this._disableLoggingForTest();
+ params.flags.maxWaitForLoad = 2 * 1000;
+ }
self.listenForStatus(message => {
this.statusUpdate(message[1]);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-background.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-background.js
deleted file mode 100644
index abda888289a..00000000000
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-background.js
+++ /dev/null
@@ -1,84205 +0,0 @@
-// lighthouse, browserified. 3.2.0 (081864eb30869df28f5ec05e28ca046b79b630cb)
-require=function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o;}return r;}()({"../audits/accessibility/accesskeys":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class Accesskeys extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'accesskeys',
-title:'`[accesskey]` values are unique',
-failureTitle:'`[accesskey]` values are not unique',
-description:'Access keys let users quickly focus a part of the page. For proper '+
-'navigation, each access key must be unique. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/accesskeys?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=Accesskeys;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-allowed-attr":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ARIAAllowedAttr extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-allowed-attr',
-title:'`[aria-*]` attributes match their roles',
-failureTitle:'`[aria-*]` attributes do not match their roles',
-description:'Each ARIA `role` supports a specific subset of `aria-*` attributes. '+
-'Mismatching these invalidates the `aria-*` attributes. [Learn '+
-'more](https://dequeuniversity.com/rules/axe/2.2/aria-allowed-attr?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ARIAAllowedAttr;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-required-attr":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ARIARequiredAttr extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-required-attr',
-title:'`[role]`s have all required `[aria-*]` attributes',
-failureTitle:'`[role]`s do not have all required `[aria-*]` attributes',
-description:'Some ARIA roles have required attributes that describe the state '+
-'of the element to screen readers. [Learn more](https://dequeuniversity.com/rules/axe/2.2/aria-required-attr?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ARIARequiredAttr;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-required-children":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class AriaRequiredChildren extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-required-children',
-title:'Elements with `[role]` that require specific children `[role]`s, are present',
-failureTitle:'Elements with `[role]` that require specific children `[role]`s, '+
-'are missing.',
-description:'Some ARIA parent roles must contain specific child roles to perform '+
-'their intended accessibility functions. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/aria-required-children?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=AriaRequiredChildren;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-required-parent":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class AriaRequiredParent extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-required-parent',
-title:'`[role]`s are contained by their required parent element',
-failureTitle:'`[role]`s are not contained by their required parent element',
-description:'Some ARIA child roles must be contained by specific parent roles to '+
-'properly perform their intended accessibility functions. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/aria-required-parent?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=AriaRequiredParent;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-roles":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class AriaRoles extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-roles',
-title:'`[role]` values are valid',
-failureTitle:'`[role]` values are not valid',
-description:'ARIA roles must have valid values in order to perform their '+
-'intended accessibility functions. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/aria-roles?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=AriaRoles;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-valid-attr-value":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ARIAValidAttr extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-valid-attr-value',
-title:'`[aria-*]` attributes have valid values',
-failureTitle:'`[aria-*]` attributes do not have valid values',
-description:'Assistive technologies, like screen readers, can\'t interpret ARIA '+
-'attributes with invalid values. [Learn '+
-'more](https://dequeuniversity.com/rules/axe/2.2/aria-valid-attr-value?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ARIAValidAttr;
-
-},{"./axe-audit":1}],"../audits/accessibility/aria-valid-attr":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ARIAValidAttr extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'aria-valid-attr',
-title:'`[aria-*]` attributes are valid and not misspelled',
-failureTitle:'`[aria-*]` attributes are not valid or misspelled',
-description:'Assistive technologies, like screen readers, can\'t interpret ARIA '+
-'attributes with invalid names. [Learn '+
-'more](https://dequeuniversity.com/rules/axe/2.2/aria-valid-attr?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ARIAValidAttr;
-
-},{"./axe-audit":1}],"../audits/accessibility/audio-caption":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class AudioCaption extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'audio-caption',
-title:'`<audio>` elements contain a `<track>` element with `[kind="captions"]`',
-failureTitle:'`<audio>` elements are missing a `<track>` element with '+
-'`[kind="captions"]`.',
-description:'Captions make audio elements usable for deaf or hearing-impaired users, '+
-'providing critical information such as who is talking, what they\'re saying, '+
-'and other non-speech information. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/audio-caption?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=AudioCaption;
-
-},{"./axe-audit":1}],"../audits/accessibility/button-name":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ButtonName extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'button-name',
-title:'Buttons have an accessible name',
-failureTitle:'Buttons do not have an accessible name',
-description:'When a button doesn\'t have an accessible name, screen readers announce it '+
-'as "button", making it unusable for users who rely on screen readers. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/button-name?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ButtonName;
-
-},{"./axe-audit":1}],"../audits/accessibility/bypass":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class Bypass extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'bypass',
-title:'The page contains a heading, skip link, or landmark region',
-failureTitle:'The page does not contain a heading, skip link, or landmark region',
-description:'Adding ways to bypass repetitive content lets keyboard users navigate the '+
-'page more efficiently. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/bypass?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=Bypass;
-
-},{"./axe-audit":1}],"../audits/accessibility/color-contrast":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ColorContrast extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'color-contrast',
-title:'Background and foreground colors have a sufficient contrast ratio',
-failureTitle:'Background and foreground colors do not have a '+
-'sufficient contrast ratio.',
-description:'Low-contrast text is difficult or impossible for many users to read. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/color-contrast?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ColorContrast;
-
-},{"./axe-audit":1}],"../audits/accessibility/definition-list":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class DefinitionList extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'definition-list',
-title:'`<dl>`\'s contain only properly-ordered `<dt>` and `<dd>` groups, `<script>` '+
-'or `<template>` elements.',
-failureTitle:'`<dl>`\'s do not contain only properly-ordered `<dt>` and `<dd>` '+
-'groups, `<script>` or `<template>` elements.',
-description:'When definition lists are not properly marked up, screen readers may produce '+
-'confusing or inaccurate output. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/definition-list?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=DefinitionList;
-
-},{"./axe-audit":1}],"../audits/accessibility/dlitem":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class DLItem extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'dlitem',
-title:'Definition list items are wrapped in `<dl>` elements',
-failureTitle:'Definition list items are not wrapped in `<dl>` elements',
-description:'Definition list items (`<dt>` and `<dd>`) must be wrapped in a '+
-'parent `<dl>` element to ensure that screen readers can properly announce them. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/dlitem?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=DLItem;
-
-},{"./axe-audit":1}],"../audits/accessibility/document-title":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class DocumentTitle extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'document-title',
-title:'Document has a `<title>` element',
-failureTitle:'Document doesn\'t have a `<title>` element',
-description:'The title gives screen reader users an overview of the page, and search '+
-'engine users rely on it heavily to determine if a page is relevant to their search. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/title).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=DocumentTitle;
-
-},{"./axe-audit":1}],"../audits/accessibility/duplicate-id":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class DuplicateId extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'duplicate-id',
-title:'`[id]` attributes on the page are unique',
-failureTitle:'`[id]` attributes on the page are not unique',
-description:'The value of an id attribute must be unique to prevent '+
-'other instances from being overlooked by assistive technologies. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/duplicate-id?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=DuplicateId;
-
-},{"./axe-audit":1}],"../audits/accessibility/frame-title":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class FrameTitle extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'frame-title',
-title:'`<frame>` or `<iframe>` elements have a title',
-failureTitle:'`<frame>` or `<iframe>` elements do not have a title',
-description:'Screen reader users rely on frame titles to describe the contents of frames. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/frame-title?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=FrameTitle;
-
-},{"./axe-audit":1}],"../audits/accessibility/html-has-lang":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class HTMLHasLang extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'html-has-lang',
-title:'`<html>` element has a `[lang]` attribute',
-failureTitle:'`<html>` element does not have a `[lang]` attribute',
-description:'If a page doesn\'t specify a lang attribute, a screen reader assumes '+
-'that the page is in the default language that the user chose when setting up the '+
-'screen reader. If the page isn\'t actually in the default language, then the screen '+
-'reader might not announce the page\'s text correctly. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/html-lang?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=HTMLHasLang;
-
-},{"./axe-audit":1}],"../audits/accessibility/html-lang-valid":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class HTMLLangValid extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'html-lang-valid',
-title:'`<html>` element has a valid value for its `[lang]` attribute',
-failureTitle:'`<html>` element does not have a valid value for '+
-'its `[lang]` attribute.',
-description:'Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) '+
-'helps screen readers announce text properly. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/valid-lang?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=HTMLLangValid;
-
-},{"./axe-audit":1}],"../audits/accessibility/image-alt":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ImageAlt extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'image-alt',
-title:'Image elements have `[alt]` attributes',
-failureTitle:'Image elements do not have `[alt]` attributes',
-description:'Informative elements should aim for short, descriptive alternate text. '+
-'Decorative elements can be ignored with an empty alt attribute. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/image-alt?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ImageAlt;
-
-},{"./axe-audit":1}],"../audits/accessibility/input-image-alt":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class InputImageAlt extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'input-image-alt',
-title:'`<input type="image">` elements have `[alt]` text',
-failureTitle:'`<input type="image">` elements do not have `[alt]` text',
-description:'When an image is being used as an `<input>` button, providing alternative '+
-'text can help screen reader users understand the purpose of the button. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/input-image-alt?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=InputImageAlt;
-
-},{"./axe-audit":1}],"../audits/accessibility/label":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class Label extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'label',
-title:'Form elements have associated labels',
-failureTitle:'Form elements do not have associated labels',
-description:'Labels ensure that form controls are announced properly by assistive '+
-'technologies, like screen readers. [Learn '+
-'more](https://dequeuniversity.com/rules/axe/2.2/label?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=Label;
-
-},{"./axe-audit":1}],"../audits/accessibility/layout-table":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class LayoutTable extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'layout-table',
-title:'Presentational `<table>` elements avoid using `<th>`, `<caption>` or the '+
-'`[summary]` attribute.',
-failureTitle:'Presentational `<table>` elements do not avoid using `<th>`, '+
-'`<caption>` or the `[summary]` attribute.',
-description:'A table being used for layout purposes should not include data elements, '+
-'such as the th or caption elements or the summary attribute, because this can '+
-'create a confusing experience for screen reader users. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/layout-table?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=LayoutTable;
-
-},{"./axe-audit":1}],"../audits/accessibility/link-name":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class LinkName extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'link-name',
-title:'Links have a discernible name',
-failureTitle:'Links do not have a discernible name',
-description:'Link text (and alternate text for images, when used as links) that is '+
-'discernible, unique, and focusable improves the navigation experience for '+
-'screen reader users. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/link-name?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=LinkName;
-
-},{"./axe-audit":1}],"../audits/accessibility/listitem":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ListItem extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'listitem',
-title:'List items (`<li>`) are contained within `<ul>` or `<ol>` parent elements',
-failureTitle:'List items (`<li>`) are not contained within `<ul>` '+
-'or `<ol>` parent elements.',
-description:'Screen readers require list items (`<li>`) to be contained within a '+
-'parent `<ul>` or `<ol>` to be announced properly. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/listitem?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ListItem;
-
-},{"./axe-audit":1}],"../audits/accessibility/list":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class List extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'list',
-title:'Lists contain only `<li>` elements and script supporting elements '+
-'(`<script>` and `<template>`).',
-failureTitle:'Lists do not contain only `<li>` elements and script '+
-'supporting elements (`<script>` and `<template>`).',
-description:'Screen readers have a specific way of announcing lists. Ensuring proper list '+
-'structure aids screen reader output. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/list?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=List;
-
-},{"./axe-audit":1}],"../audits/accessibility/manual/custom-controls-labels":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class CustomControlsLabels extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'custom-controls-labels',
-description:'Custom interactive controls have associated labels, provided by aria-label or aria-labelledby. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
-title:'Custom controls have associated labels'},
-super.partialMeta);
-}}
-
-
-module.exports=CustomControlsLabels;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/custom-controls-roles":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class CustomControlsRoles extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'custom-controls-roles',
-description:'Custom interactive controls have appropriate ARIA roles. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
-title:'Custom controls have ARIA roles'},
-super.partialMeta);
-}}
-
-
-module.exports=CustomControlsRoles;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/focus-traps":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class FocusTraps extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'focus-traps',
-description:'A user can tab into and out of any control or region without accidentally trapping their focus. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
-title:'User focus is not accidentally trapped in a region'},
-super.partialMeta);
-}}
-
-
-module.exports=FocusTraps;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/focusable-controls":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class FocusableControls extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'focusable-controls',
-description:'Custom interactive controls are keyboard focusable and display a focus indicator. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
-title:'Interactive controls are keyboard focusable'},
-super.partialMeta);
-}}
-
-
-module.exports=FocusableControls;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/heading-levels":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class HeadingLevels extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'heading-levels',
-description:'Headings are used to create an outline for the page and heading levels are not skipped. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#take_advantage_of_headings_and_landmarks).',
-title:'Headings don\'t skip levels'},
-super.partialMeta);
-}}
-
-
-module.exports=HeadingLevels;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/interactive-element-affordance":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class InteractiveElementAffordance extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'interactive-element-affordance',
-description:'Interactive elements, such as links and buttons, should indicate their state and be distinguishable from non-interactive elements. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#interactive_elements_like_links_and_buttons_should_indicate_their_purpose_and_state).',
-title:'Interactive elements indicate their purpose and state'},
-super.partialMeta);
-}}
-
-
-module.exports=InteractiveElementAffordance;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/logical-tab-order":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class LogicalTabOrder extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'logical-tab-order',
-description:'Tabbing through the page follows the visual layout. Users cannot focus elements that are offscreen. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
-title:'The page has a logical tab order'},
-super.partialMeta);
-}}
-
-
-module.exports=LogicalTabOrder;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/managed-focus":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class ManagedFocus extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'managed-focus',
-description:'If new content, such as a dialog, is added to the page, the user\'s focus is directed to it. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
-title:'The user\'s focus is directed to new content added to the page'},
-super.partialMeta);
-}}
-
-
-module.exports=ManagedFocus;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/offscreen-content-hidden":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-
-class OffscreenContentHidden extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'offscreen-content-hidden',
-description:'Offscreen content is hidden with display: none or aria-hidden=true. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
-title:'Offscreen content is hidden from assistive technology'},
-super.partialMeta);
-}}
-
-
-module.exports=OffscreenContentHidden;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/use-landmarks":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class UseLandmarks extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'use-landmarks',
-description:'Landmark elements (<main>, <nav>, etc.) are used to improve the keyboard navigation of the page for assistive technology. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#take_advantage_of_headings_and_landmarks).',
-title:'HTML5 landmark elements are used to improve navigation'},
-super.partialMeta);
-}}
-
-
-module.exports=UseLandmarks;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/manual/visual-order-follows-dom":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class VisualOrderFollowsDOM extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'visual-order-follows-dom',
-description:'DOM order matches the visual order, improving navigation for assistive technology. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
-title:'Visual order on the page follows DOM order'},
-super.partialMeta);
-}}
-
-
-module.exports=VisualOrderFollowsDOM;
-
-},{"../../manual/manual-audit":4}],"../audits/accessibility/meta-refresh":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class MetaRefresh extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'meta-refresh',
-title:'The document does not use `<meta http-equiv="refresh">`',
-failureTitle:'The document uses `<meta http-equiv="refresh">`',
-description:'Users do not expect a page to refresh automatically, and doing so will move '+
-'focus back to the top of the page. This may create a frustrating or '+
-'confusing experience. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/meta-refresh?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=MetaRefresh;
-
-},{"./axe-audit":1}],"../audits/accessibility/meta-viewport":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class MetaViewport extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'meta-viewport',
-title:'`[user-scalable="no"]` is not used in the `<meta name="viewport">` '+
-'element and the `[maximum-scale]` attribute is not less than 5.',
-failureTitle:'`[user-scalable="no"]` is used in the `<meta name="viewport">` '+
-'element or the `[maximum-scale]` attribute is less than 5.',
-description:'Disabling zooming is problematic for users with low vision who rely on '+
-'screen magnification to properly see the contents of a web page. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/meta-viewport?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=MetaViewport;
-
-},{"./axe-audit":1}],"../audits/accessibility/object-alt":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ObjectAlt extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'object-alt',
-title:'`<object>` elements have `[alt]` text',
-failureTitle:'`<object>` elements do not have `[alt]` text',
-description:'Screen readers cannot translate non-text content. Adding alt text to '+
-'`<object>` elements helps screen readers convey meaning to users. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/object-alt?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ObjectAlt;
-
-},{"./axe-audit":1}],"../audits/accessibility/tabindex":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class TabIndex extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'tabindex',
-title:'No element has a `[tabindex]` value greater than 0',
-failureTitle:'Some elements have a `[tabindex]` value greater than 0',
-description:'A value greater than 0 implies an explicit navigation ordering. '+
-'Although technically valid, this often creates frustrating experiences '+
-'for users who rely on assistive technologies. [Learn more](https://dequeuniversity.com/rules/axe/2.2/tabindex?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=TabIndex;
-
-},{"./axe-audit":1}],"../audits/accessibility/td-headers-attr":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class TDHeadersAttr extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'td-headers-attr',
-title:'Cells in a `<table>` element that use the `[headers]` attribute only refer '+
-'to other cells of that same table.',
-failureTitle:'Cells in a `<table>` element that use the `[headers]` '+
-'attribute refers to other cells of that same table.',
-description:'Screen readers have features to make navigating tables easier. Ensuring '+
-'`<td>` cells using the `[headers]` attribute only refer to other cells in the same '+
-'table may improve the experience for screen reader users. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/td-headers-attr?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=TDHeadersAttr;
-
-},{"./axe-audit":1}],"../audits/accessibility/th-has-data-cells":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class THHasDataCells extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'th-has-data-cells',
-title:'`<th>` elements and elements with `[role="columnheader"/"rowheader"]` have '+
-'data cells they describe.',
-failureTitle:'`<th>` elements and elements with '+
-'`[role="columnheader"/"rowheader"]` do not have data cells they describe.',
-description:'Screen readers have features to make navigating tables easier. Ensuring '+
-'table headers always refer to some set of cells may improve the experience for screen '+
-'reader users. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/th-has-data-cells?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=THHasDataCells;
-
-},{"./axe-audit":1}],"../audits/accessibility/valid-lang":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class ValidLang extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'valid-lang',
-title:'`[lang]` attributes have a valid value',
-failureTitle:'`[lang]` attributes do not have a valid value',
-description:'Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) '+
-'on elements helps ensure that text is pronounced correctly by a screen reader. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/valid-lang?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=ValidLang;
-
-},{"./axe-audit":1}],"../audits/accessibility/video-caption":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class VideoCaption extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'video-caption',
-title:'`<video>` elements contain a `<track>` element with `[kind="captions"]`',
-failureTitle:'`<video>` elements do not contain a `<track>` element '+
-'with `[kind="captions"]`.',
-description:'When a video provides a caption it is easier for deaf and hearing impaired '+
-'users to access its information. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/video-caption?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=VideoCaption;
-
-},{"./axe-audit":1}],"../audits/accessibility/video-description":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const AxeAudit=require('./axe-audit');
-
-class VideoDescription extends AxeAudit{
-
-
-
-static get meta(){
-return{
-id:'video-description',
-title:'`<video>` elements contain a `<track>` element with `[kind="description"]`',
-failureTitle:'`<video>` elements do not contain a `<track>` element with '+
-'`[kind="description"]`.',
-description:'Audio descriptions provide relevant information for videos that dialogue '+
-'cannot, such as facial expressions and scenes. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/video-description?application=lighthouse).',
-requiredArtifacts:['Accessibility']};
-
-}}
-
-
-module.exports=VideoDescription;
-
-},{"./axe-audit":1}],"../audits/bootup-time":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const NetworkRequest=require('../lib/network-request');
-const{taskGroups}=require('../lib/task-groups');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'JavaScript execution time',
-
-failureTitle:'Reduce JavaScript execution time',
-
-description:'Consider reducing the time spent parsing, compiling, and executing JS. '+
-'You may find delivering smaller JS payloads helps with this. [Learn '+
-'more](https://developers.google.com/web/tools/lighthouse/audits/bootup).',
-
-columnTotal:'Total',
-
-columnScriptEval:'Script Evaluation',
-
-columnScriptParse:'Script Parse',
-
-chromeExtensionsWarning:'Chrome extensions negatively affected this page\'s load performance. '+
-'Try auditing the page in incognito mode or from a Chrome profile without extensions.'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class BootupTime extends Audit{
-
-
-
-static get meta(){
-return{
-id:'bootup-time',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-scorePODR:600,
-scoreMedian:3500,
-thresholdInMs:50};
-
-}
-
-
-
-
-static getJavaScriptURLs(records){
-
-const urls=new Set();
-for(const record of records){
-if(record.resourceType===NetworkRequest.TYPES.Script){
-urls.add(record.url);
-}
-}
-
-return urls;
-}
-
-
-
-
-
-
-static getExecutionTimingsByURL(tasks,jsURLs){
-
-const result=new Map();
-
-for(const task of tasks){
-const jsURL=task.attributableURLs.find(url=>jsURLs.has(url));
-const fallbackURL=task.attributableURLs[0];
-const attributableURL=jsURL||fallbackURL;
-if(!attributableURL||attributableURL==='about:blank')continue;
-
-const timingByGroupId=result.get(attributableURL)||{};
-const originalTime=timingByGroupId[task.group.id]||0;
-timingByGroupId[task.group.id]=originalTime+task.selfTime;
-result.set(attributableURL,timingByGroupId);
-}
-
-return result;
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const settings=context.settings||{};
-const trace=artifacts.traces[BootupTime.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[BootupTime.DEFAULT_PASS];
-const networkRecords=await artifacts.requestNetworkRecords(devtoolsLog);
-const tasks=await artifacts.requestMainThreadTasks(trace);
-const multiplier=settings.throttlingMethod==='simulate'?
-settings.throttling.cpuSlowdownMultiplier:1;
-
-const jsURLs=BootupTime.getJavaScriptURLs(networkRecords);
-const executionTimings=BootupTime.getExecutionTimingsByURL(tasks,jsURLs);
-
-let hadExcessiveChromeExtension=false;
-let totalBootupTime=0;
-const results=Array.from(executionTimings).
-map(([url,timingByGroupId])=>{
-
-let bootupTimeForURL=0;
-for(const[groupId,timespanMs]of Object.entries(timingByGroupId)){
-timingByGroupId[groupId]=timespanMs*multiplier;
-bootupTimeForURL+=timespanMs*multiplier;
-}
-
-
-if(bootupTimeForURL>=context.options.thresholdInMs){
-totalBootupTime+=bootupTimeForURL;
-}
-
-const scriptingTotal=timingByGroupId[taskGroups.scriptEvaluation.id]||0;
-const parseCompileTotal=timingByGroupId[taskGroups.scriptParseCompile.id]||0;
-
-hadExcessiveChromeExtension=hadExcessiveChromeExtension||
-url.startsWith('chrome-extension:')&&scriptingTotal>100;
-
-return{
-url:url,
-total:bootupTimeForURL,
-
-scripting:scriptingTotal,
-scriptParseCompile:parseCompileTotal};
-
-}).
-filter(result=>result.total>=context.options.thresholdInMs).
-sort((a,b)=>b.total-a.total);
-
-
-
-if(hadExcessiveChromeExtension){
-context.LighthouseRunWarnings.push(str_(UIStrings.chromeExtensionsWarning));
-}
-
-const summary={wastedMs:totalBootupTime};
-
-const headings=[
-{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
-{key:'total',granularity:1,itemType:'ms',text:str_(UIStrings.columnTotal)},
-{key:'scripting',granularity:1,itemType:'ms',text:str_(UIStrings.columnScriptEval)},
-{key:'scriptParseCompile',granularity:1,itemType:'ms',
-text:str_(UIStrings.columnScriptParse)}];
-
-
-const details=BootupTime.makeTableDetails(headings,results,summary);
-
-const score=Audit.computeLogNormalScore(
-totalBootupTime,
-context.options.scorePODR,
-context.options.scoreMedian);
-
-
-return{
-score,
-rawValue:totalBootupTime,
-displayValue:totalBootupTime>0?
-str_(i18n.UIStrings.seconds,{timeInMs:totalBootupTime}):'',
-details};
-
-}}
-
-
-module.exports=BootupTime;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/bootup-time.js");
-},{"../lib/i18n/i18n.js":36,"../lib/network-request":88,"../lib/task-groups":93,"./audit":2}],"../audits/byte-efficiency/efficient-animated-content":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-'use strict';
-
-const NetworkRequest=require('../../lib/network-request');
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Use video formats for animated content',
-
-description:'Large GIFs are inefficient for delivering animated content. Consider using '+
-'MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save '+
-'network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-
-const GIF_BYTE_THRESHOLD=100*1024;
-
-class EfficientAnimatedContent extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'efficient-animated-content',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-
-static getPercentSavings(bytes){
-return Math.round(29.1*Math.log10(bytes)-100.7)/100;
-}
-
-
-
-
-
-
-static audit_(artifacts,networkRecords){
-const unoptimizedContent=networkRecords.filter(
-record=>record.mimeType==='image/gif'&&
-record.resourceType===NetworkRequest.TYPES.Image&&
-(record.resourceSize||0)>GIF_BYTE_THRESHOLD);
-
-
-
-const items=unoptimizedContent.map(record=>{
-const resourceSize=record.resourceSize||0;
-return{
-url:record.url,
-totalBytes:resourceSize,
-wastedBytes:Math.round(resourceSize*
-EfficientAnimatedContent.getPercentSavings(resourceSize))};
-
-});
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-items,
-headings};
-
-}}
-
-
-module.exports=EfficientAnimatedContent;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/efficient-animated-content.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/network-request":88,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/offscreen-images":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const Sentry=require('../../lib/sentry');
-const URL=require('../../lib/url-shim');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Defer offscreen images',
-
-description:
-'Consider lazy-loading offscreen and hidden images after all critical resources have '+
-'finished loading to lower time to interactive. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const ALLOWABLE_OFFSCREEN_X=100;
-const ALLOWABLE_OFFSCREEN_Y=200;
-
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-const IGNORE_THRESHOLD_IN_PERCENT=75;
-const IGNORE_THRESHOLD_IN_MS=50;
-
-
-
-class OffscreenImages extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'offscreen-images',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['ImageUsage','ViewportDimensions','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-static computeVisiblePixels(imageRect,viewportDimensions){
-const innerWidth=viewportDimensions.innerWidth;
-const innerHeight=viewportDimensions.innerHeight;
-
-const top=Math.max(imageRect.top,-1*ALLOWABLE_OFFSCREEN_Y);
-const right=Math.min(imageRect.right,innerWidth+ALLOWABLE_OFFSCREEN_X);
-const bottom=Math.min(imageRect.bottom,innerHeight+ALLOWABLE_OFFSCREEN_Y);
-const left=Math.max(imageRect.left,-1*ALLOWABLE_OFFSCREEN_X);
-
-return Math.max(right-left,0)*Math.max(bottom-top,0);
-}
-
-
-
-
-
-
-static computeWaste(image,viewportDimensions){
-if(!image.networkRecord){
-return null;
-}
-
-const url=URL.elideDataURI(image.src);
-const totalPixels=image.clientWidth*image.clientHeight;
-const visiblePixels=this.computeVisiblePixels(image.clientRect,viewportDimensions);
-
-const wastedRatio=totalPixels===0?1:1-visiblePixels/totalPixels;
-const totalBytes=image.networkRecord.resourceSize;
-const wastedBytes=Math.round(totalBytes*wastedRatio);
-
-if(!Number.isFinite(wastedRatio)){
-return new Error(`Invalid image sizing information ${url}`);
-}
-
-return{
-url,
-requestStartTime:image.networkRecord.startTime,
-totalBytes,
-wastedBytes,
-wastedPercent:100*wastedRatio};
-
-}
-
-
-
-
-
-
-
-static filterLanternResults(images,lanternMetricData){
-const nodeTimings=lanternMetricData.pessimisticEstimate.nodeTimings;
-
-
-let lastLongTaskStartTime=0;
-
-
-const startTimesByURL=new Map();
-for(const[node,timing]of nodeTimings){
-if(node.type==='cpu'&&timing.duration>=50){
-lastLongTaskStartTime=Math.max(lastLongTaskStartTime,timing.startTime);
-}else if(node.type==='network'){
-const networkNode=node;
-startTimesByURL.set(networkNode.record.url,timing.startTime);
-}
-}
-
-return images.filter(image=>{
-
-if(image.wastedBytes<IGNORE_THRESHOLD_IN_BYTES)return false;
-if(image.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT)return false;
-
-const imageRequestStartTime=startTimesByURL.get(image.url)||0;
-return imageRequestStartTime<lastLongTaskStartTime-IGNORE_THRESHOLD_IN_MS;
-});
-}
-
-
-
-
-
-
-
-static filterObservedResults(images,interactiveTimestamp){
-return images.filter(image=>{
-if(image.wastedBytes<IGNORE_THRESHOLD_IN_BYTES)return false;
-if(image.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT)return false;
-return image.requestStartTime<interactiveTimestamp/1e6-IGNORE_THRESHOLD_IN_MS/1000;
-});
-}
-
-
-
-
-
-
-
-
-
-
-
-static computeWasteWithTTIGraph(results,graph,simulator){
-return super.computeWasteWithTTIGraph(results,graph,simulator,
-{includeLoad:false});
-}
-
-
-
-
-
-
-
-static audit_(artifacts,networkRecords,context){
-const images=artifacts.ImageUsage;
-const viewportDimensions=artifacts.ViewportDimensions;
-const trace=artifacts.traces[ByteEfficiencyAudit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
-
-
-const warnings=[];
-const resultsMap=images.reduce((results,image)=>{
-const processed=OffscreenImages.computeWaste(image,viewportDimensions);
-if(processed===null){
-return results;
-}
-
-if(processed instanceof Error){
-warnings.push(processed.message);
-Sentry.captureException(processed,{tags:{audit:this.meta.id},level:'warning'});
-return results;
-}
-
-
-const existing=results.get(processed.url);
-if(!existing||existing.wastedBytes>processed.wastedBytes){
-results.set(processed.url,processed);
-}
-
-return results;
-},new Map());
-
-const settings=context.settings;
-return artifacts.requestInteractive({trace,devtoolsLog,settings}).then(interactive=>{
-const unfilteredResults=Array.from(resultsMap.values());
-const lanternInteractive=interactive;
-
-const items=context.settings.throttlingMethod==='simulate'?
-OffscreenImages.filterLanternResults(unfilteredResults,lanternInteractive):
-
-OffscreenImages.filterObservedResults(unfilteredResults,interactive.timestamp);
-
-
-const headings=[
-{key:'url',valueType:'thumbnail',label:''},
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-warnings,
-items,
-headings};
-
-});
-}}
-
-
-module.exports=OffscreenImages;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/offscreen-images.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/sentry":90,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/render-blocking-resources":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-const BaseNode=require('../../lib/dependency-graph/base-node');
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const UnusedCSS=require('./unused-css-rules');
-const NetworkRequest=require('../../lib/network-request');
-
-
-
-
-
-
-
-
-
-const MINIMUM_WASTED_MS=50;
-
-const UIStrings={
-
-title:'Eliminate render-blocking resources',
-
-description:'Resources are blocking the first paint of your page. Consider '+
-'delivering critical JS/CSS inline and deferring all non-critical '+
-'JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-
-
-
-
-function getNodesAndTimingByUrl(nodeTimings){
-
-const urlMap={};
-const nodes=Array.from(nodeTimings.keys());
-nodes.forEach(node=>{
-if(node.type!=='network')return;
-const nodeTiming=nodeTimings.get(node);
-if(!nodeTiming)return;
-
-urlMap[node.record.url]={node,nodeTiming};
-});
-
-return urlMap;
-}
-
-class RenderBlockingResources extends Audit{
-
-
-
-static get meta(){
-return{
-id:'render-blocking-resources',
-title:str_(UIStrings.title),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-description:str_(UIStrings.description),
-
-
-
-requiredArtifacts:['URL','TagsBlockingFirstPaint','traces']};
-
-}
-
-
-
-
-
-
-static async computeResults(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const simulatorData={devtoolsLog,settings:context.settings};
-const traceOfTab=await artifacts.requestTraceOfTab(trace);
-const simulator=await artifacts.requestLoadSimulator(simulatorData);
-const wastedCssBytes=await RenderBlockingResources.computeWastedCSSBytes(artifacts,context);
-
-const metricSettings={throttlingMethod:'simulate'};
-const metricComputationData={trace,devtoolsLog,simulator,settings:metricSettings};
-
-const fcpSimulation=await artifacts.requestFirstContentfulPaint(metricComputationData);
-const fcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
-
-const nodesByUrl=getNodesAndTimingByUrl(fcpSimulation.optimisticEstimate.nodeTimings);
-
-const results=[];
-const deferredNodeIds=new Set();
-for(const resource of artifacts.TagsBlockingFirstPaint){
-
-if(resource.endTime*1000>fcpTsInMs)continue;
-
-if(!nodesByUrl[resource.tag.url])continue;
-
-const{node,nodeTiming}=nodesByUrl[resource.tag.url];
-
-
-
-
-node.traverse(node=>deferredNodeIds.add(node.id));
-
-
-const wastedMs=Math.round(nodeTiming.duration);
-if(wastedMs<MINIMUM_WASTED_MS)continue;
-
-results.push({
-url:resource.tag.url,
-totalBytes:resource.transferSize,
-wastedMs});
-
-}
-
-if(!results.length){
-return{results,wastedMs:0};
-}
-
-const wastedMs=RenderBlockingResources.estimateSavingsWithGraphs(
-simulator,
-fcpSimulation.optimisticGraph,
-deferredNodeIds,
-wastedCssBytes);
-
-
-return{results,wastedMs};
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-static estimateSavingsWithGraphs(simulator,fcpGraph,deferredIds,wastedCssBytesByUrl){
-const originalEstimate=simulator.simulate(fcpGraph).timeInMs;
-
-let totalChildNetworkBytes=0;
-const minimalFCPGraph=fcpGraph.cloneWithRelationships(node=>{
-
-const canDeferRequest=deferredIds.has(node.id);
-if(node.type!==BaseNode.TYPES.NETWORK)return!canDeferRequest;
-
-const isStylesheet=
-node.record.resourceType===NetworkRequest.TYPES.Stylesheet;
-if(canDeferRequest&&isStylesheet){
-
-const wastedBytes=wastedCssBytesByUrl.get(node.record.url)||0;
-totalChildNetworkBytes+=(node.record.transferSize||0)-wastedBytes;
-}
-return!canDeferRequest;
-});
-
-
-const originalTransferSize=minimalFCPGraph.record.transferSize;
-const safeTransferSize=originalTransferSize||0;
-minimalFCPGraph.record.transferSize=safeTransferSize+totalChildNetworkBytes;
-const estimateAfterInline=simulator.simulate(minimalFCPGraph).timeInMs;
-minimalFCPGraph.record.transferSize=originalTransferSize;
-return Math.round(Math.max(originalEstimate-estimateAfterInline,0));
-}
-
-
-
-
-
-
-static async computeWastedCSSBytes(artifacts,context){
-const wastedBytesByUrl=new Map();
-try{
-
-const results=await UnusedCSS.audit(artifacts,context);
-
-for(const item of results.details.items){
-wastedBytesByUrl.set(item.url,item.wastedBytes);
-}
-}catch(_){}
-
-return wastedBytesByUrl;
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const{results,wastedMs}=await RenderBlockingResources.computeResults(artifacts,context);
-
-let displayValue='';
-if(results.length>0){
-displayValue=str_(i18n.UIStrings.displayValueMsSavings,{wastedMs});
-}
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnWastedMs)}];
-
-
-const details=Audit.makeOpportunityDetails(headings,results,wastedMs);
-
-return{
-displayValue,
-score:ByteEfficiencyAudit.scoreForWastedMs(wastedMs),
-rawValue:wastedMs,
-details};
-
-}}
-
-
-module.exports=RenderBlockingResources;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/render-blocking-resources.js");
-},{"../../lib/dependency-graph/base-node":25,"../../lib/i18n/i18n.js":36,"../../lib/network-request":88,"../audit":2,"./byte-efficiency-audit":3,"./unused-css-rules":"../audits/byte-efficiency/unused-css-rules"}],"../audits/byte-efficiency/total-byte-weight":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Avoids enormous network payloads',
-
-failureTitle:'Avoid enormous network payloads',
-
-description:
-'Large network payloads cost users real money and are highly correlated with '+
-'long load times. [Learn '+
-'more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).',
-
-displayValue:'Total size was {totalBytes, number, bytes}\xa0KB'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class TotalByteWeight extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'total-byte-weight',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['devtoolsLogs','traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-scorePODR:2500*1024,
-scoreMedian:4000*1024};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const devtoolsLogs=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
-const[networkRecords,networkThroughput]=await Promise.all([
-artifacts.requestNetworkRecords(devtoolsLogs),
-artifacts.requestNetworkThroughput(devtoolsLogs)]);
-
-
-let totalBytes=0;
-
-let results=[];
-networkRecords.forEach(record=>{
-
-
-if(record.parsedURL.scheme==='data'||!record.finished)return;
-
-const result={
-url:record.url,
-totalBytes:record.transferSize,
-totalMs:ByteEfficiencyAudit.bytesToMs(record.transferSize,networkThroughput)};
-
-
-totalBytes+=result.totalBytes;
-results.push(result);
-});
-const totalCompletedRequests=results.length;
-results=results.sort((itemA,itemB)=>itemB.totalBytes-itemA.totalBytes).slice(0,10);
-
-const score=ByteEfficiencyAudit.computeLogNormalScore(
-totalBytes,
-context.options.scorePODR,
-context.options.scoreMedian);
-
-
-const headings=[
-{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',itemType:'bytes',text:str_(i18n.UIStrings.columnSize)}];
-
-
-const tableDetails=ByteEfficiencyAudit.makeTableDetails(headings,results);
-
-return{
-score,
-rawValue:totalBytes,
-displayValue:str_(UIStrings.displayValue,{totalBytes}),
-extendedInfo:{
-value:{
-results,
-totalCompletedRequests}},
-
-
-details:tableDetails};
-
-}}
-
-
-module.exports=TotalByteWeight;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/total-byte-weight.js");
-},{"../../lib/i18n/i18n.js":36,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/unminified-css":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const UnusedCSSRules=require('./unused-css-rules');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Minify CSS',
-
-description:'Minifying CSS files can reduce network payload sizes. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/minify-css).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_PERCENT=5;
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-
-
-
-
-class UnminifiedCSS extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'unminified-css',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['CSSUsage','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-
-static computeTokenLength(content){
-let totalTokenLength=0;
-let isInComment=false;
-let isInLicenseComment=false;
-let isInString=false;
-let stringOpenChar=null;
-
-for(let i=0;i<content.length;i++){
-const twoChars=content.substr(i,2);
-const char=twoChars.charAt(0);
-
-const isWhitespace=char===' '||char==='\n'||char==='\t';
-const isAStringOpenChar=char===`'`||char==='"';
-
-if(isInComment){
-if(isInLicenseComment)totalTokenLength++;
-
-if(twoChars==='*/'){
-if(isInLicenseComment)totalTokenLength++;
-isInComment=false;
-i++;
-}
-}else if(isInString){
-totalTokenLength++;
-if(char==='\\'){
-totalTokenLength++;
-i++;
-}else if(char===stringOpenChar){
-isInString=false;
-}
-}else{
-if(twoChars==='/*'){
-isInComment=true;
-isInLicenseComment=content.charAt(i+2)==='!';
-if(isInLicenseComment)totalTokenLength+=2;
-i++;
-}else if(isAStringOpenChar){
-isInString=true;
-stringOpenChar=char;
-totalTokenLength++;
-}else if(!isWhitespace){
-totalTokenLength++;
-}
-}
-}
-
-
-
-if(isInComment||isInString){
-return content.length;
-}
-
-return totalTokenLength;
-}
-
-
-
-
-
-
-
-static computeWaste(stylesheet,networkRecord,pageUrl){
-const content=stylesheet.content;
-const totalTokenLength=UnminifiedCSS.computeTokenLength(content);
-
-let url=stylesheet.header.sourceURL;
-if(!url||url===pageUrl){
-const contentPreview=UnusedCSSRules.determineContentPreview(stylesheet.content);
-url=contentPreview;
-}
-
-const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,content.length,
-'Stylesheet');
-const wastedRatio=1-totalTokenLength/content.length;
-const wastedBytes=Math.round(totalBytes*wastedRatio);
-
-return{
-url,
-totalBytes,
-wastedBytes,
-wastedPercent:100*wastedRatio};
-
-}
-
-
-
-
-
-
-static audit_(artifacts,networkRecords){
-const pageUrl=artifacts.URL.finalUrl;
-const items=[];
-for(const stylesheet of artifacts.CSSUsage.stylesheets){
-const networkRecord=networkRecords.
-find(record=>record.url===stylesheet.header.sourceURL);
-if(!stylesheet.content)continue;
-
-const result=UnminifiedCSS.computeWaste(stylesheet,networkRecord,pageUrl);
-
-
-
-if(result.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT||
-result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES||
-!Number.isFinite(result.wastedBytes))continue;
-items.push(result);
-}
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{items,headings};
-}}
-
-
-module.exports=UnminifiedCSS;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/unminified-css.js");
-},{"../../lib/i18n/i18n.js":36,"./byte-efficiency-audit":3,"./unused-css-rules":"../audits/byte-efficiency/unused-css-rules"}],"../audits/byte-efficiency/unminified-javascript":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const esprima=require('esprima');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Minify JavaScript',
-
-description:'Minifying JavaScript files can reduce payload sizes and script parse time. '+
-'[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_PERCENT=10;
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-
-
-
-
-
-
-
-
-
-
-
-class UnminifiedJavaScript extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'unminified-javascript',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['Scripts','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-static computeWaste(scriptContent,networkRecord){
-const contentLength=scriptContent.length;
-let totalTokenLength=0;
-
-
-const tokens=esprima.tokenize(scriptContent,{tolerant:true});
-if(!tokens.length&&tokens.errors&&tokens.errors.length){
-throw tokens.errors[0];
-}
-
-for(const token of tokens){
-totalTokenLength+=token.value.length;
-}
-
-const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,contentLength,
-'Script');
-const wastedRatio=1-totalTokenLength/contentLength;
-const wastedBytes=Math.round(totalBytes*wastedRatio);
-
-return{
-url:networkRecord.url,
-totalBytes,
-wastedBytes,
-wastedPercent:100*wastedRatio};
-
-}
-
-
-
-
-
-
-static audit_(artifacts,networkRecords){
-
-const items=[];
-const warnings=[];
-for(const requestId of Object.keys(artifacts.Scripts)){
-const scriptContent=artifacts.Scripts[requestId];
-const networkRecord=networkRecords.find(record=>record.requestId===requestId);
-if(!networkRecord||!scriptContent)continue;
-
-try{
-const result=UnminifiedJavaScript.computeWaste(scriptContent,networkRecord);
-
-
-if(result.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT||
-result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES||
-!Number.isFinite(result.wastedBytes))continue;
-items.push(result);
-}catch(err){
-warnings.push(`Unable to process ${networkRecord.url}: ${err.message}`);
-}
-}
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-items,
-warnings,
-headings};
-
-}}
-
-
-module.exports=UnminifiedJavaScript;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/unminified-javascript.js");
-},{"../../lib/i18n/i18n.js":36,"./byte-efficiency-audit":3,"esprima":162}],"../audits/byte-efficiency/unused-css-rules":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Defer unused CSS',
-
-description:'Remove unused rules from stylesheets to reduce unnecessary '+
-'bytes consumed by network activity. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-const PREVIEW_LENGTH=100;
-
-
-
-class UnusedCSSRules extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'unused-css-rules',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['CSSUsage','URL','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-static indexStylesheetsById(styles,networkRecords){
-const indexedNetworkRecords=networkRecords.
-reduce((indexed,record)=>{
-indexed[record.url]=record;
-return indexed;
-},{});
-
-return styles.reduce((indexed,stylesheet)=>{
-indexed[stylesheet.header.styleSheetId]=Object.assign({
-usedRules:[],
-networkRecord:indexedNetworkRecords[stylesheet.header.sourceURL]},
-stylesheet);
-return indexed;
-},{});
-}
-
-
-
-
-
-
-static indexUsedRules(rules,indexedStylesheets){
-rules.forEach(rule=>{
-const stylesheetInfo=indexedStylesheets[rule.styleSheetId];
-
-if(!stylesheetInfo){
-return;
-}
-
-if(rule.used){
-stylesheetInfo.usedRules.push(rule);
-}
-});
-}
-
-
-
-
-
-static computeUsage(stylesheetInfo){
-let usedUncompressedBytes=0;
-const totalUncompressedBytes=stylesheetInfo.content.length;
-
-for(const usedRule of stylesheetInfo.usedRules){
-usedUncompressedBytes+=usedRule.endOffset-usedRule.startOffset;
-}
-
-const totalTransferredBytes=ByteEfficiencyAudit.estimateTransferSize(
-stylesheetInfo.networkRecord,totalUncompressedBytes,'Stylesheet');
-const percentUnused=(totalUncompressedBytes-usedUncompressedBytes)/totalUncompressedBytes;
-const wastedBytes=Math.round(percentUnused*totalTransferredBytes);
-
-return{
-wastedBytes,
-wastedPercent:percentUnused*100,
-totalBytes:totalTransferredBytes};
-
-}
-
-
-
-
-
-
-static determineContentPreview(content){
-let preview=(content||'').
-slice(0,PREVIEW_LENGTH*5).
-replace(/( {2,}|\t)+/g,' ').
-replace(/\n\s+}/g,'\n}').
-trim();
-
-if(preview.length>PREVIEW_LENGTH){
-const firstRuleStart=preview.indexOf('{');
-const firstRuleEnd=preview.indexOf('}');
-
-if(firstRuleStart===-1||firstRuleEnd===-1||
-firstRuleStart>firstRuleEnd||
-firstRuleStart>PREVIEW_LENGTH){
-
-preview=preview.slice(0,PREVIEW_LENGTH)+'...';
-}else if(firstRuleEnd<PREVIEW_LENGTH){
-
-preview=preview.slice(0,firstRuleEnd+1)+' ...';
-}else{
-
-const lastSemicolonIndex=preview.slice(0,PREVIEW_LENGTH).lastIndexOf(';');
-preview=lastSemicolonIndex<firstRuleStart?
-preview.slice(0,PREVIEW_LENGTH)+'... } ...':
-preview.slice(0,lastSemicolonIndex+1)+' ... } ...';
-}
-}
-
-return preview;
-}
-
-
-
-
-
-
-static mapSheetToResult(stylesheetInfo,pageUrl){
-let url=stylesheetInfo.header.sourceURL;
-if(!url||url===pageUrl){
-const contentPreview=UnusedCSSRules.determineContentPreview(stylesheetInfo.content);
-url=contentPreview;
-}
-
-const usage=UnusedCSSRules.computeUsage(stylesheetInfo);
-
-return Object.assign({url},usage);
-}
-
-
-
-
-
-static audit_(artifacts){
-const styles=artifacts.CSSUsage.stylesheets;
-const usage=artifacts.CSSUsage.rules;
-const pageUrl=artifacts.URL.finalUrl;
-
-const devtoolsLogs=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
-const indexedSheets=UnusedCSSRules.indexStylesheetsById(styles,networkRecords);
-UnusedCSSRules.indexUsedRules(usage,indexedSheets);
-
-const items=Object.keys(indexedSheets).
-map(sheetId=>UnusedCSSRules.mapSheetToResult(indexedSheets[sheetId],pageUrl)).
-filter(sheet=>sheet&&sheet.wastedBytes>IGNORE_THRESHOLD_IN_BYTES);
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-items,
-headings};
-
-});
-}}
-
-
-module.exports=UnusedCSSRules;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/unused-css-rules.js");
-},{"../../lib/i18n/i18n.js":36,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/unused-javascript":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Remove unused JavaScript',
-
-description:'Remove unused JavaScript to reduce bytes consumed by network activity.'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-
-class UnusedJavaScript extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'unused-javascript',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['JsUsage','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-static computeWaste(script){
-let maximumEndOffset=0;
-for(const func of script.functions){
-for(const range of func.ranges){
-maximumEndOffset=Math.max(maximumEndOffset,range.endOffset);
-}
-}
-
-
-
-const unusedByIndex=new Uint8Array(maximumEndOffset);
-for(const func of script.functions){
-for(const range of func.ranges){
-if(range.count===0){
-for(let i=range.startOffset;i<range.endOffset;i++){
-unusedByIndex[i]=1;
-}
-}
-}
-}
-
-let unused=0;
-for(const x of unusedByIndex){
-unused+=x;
-}
-
-return{
-unusedLength:unused,
-contentLength:maximumEndOffset};
-
-}
-
-
-
-
-
-
-static mergeWaste(wasteData,networkRecord){
-let unusedLength=0;
-let contentLength=0;
-for(const usage of wasteData){
-unusedLength+=usage.unusedLength;
-contentLength+=usage.contentLength;
-}
-
-const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,contentLength,
-'Script');
-const wastedRatio=unusedLength/contentLength||0;
-const wastedBytes=Math.round(totalBytes*wastedRatio);
-
-return{
-url:networkRecord.url,
-totalBytes,
-wastedBytes,
-wastedPercent:100*wastedRatio};
-
-}
-
-
-
-
-
-
-static audit_(artifacts,networkRecords){
-
-const scriptsByUrl=new Map();
-for(const script of artifacts.JsUsage){
-const scripts=scriptsByUrl.get(script.url)||[];
-scripts.push(script);
-scriptsByUrl.set(script.url,scripts);
-}
-
-const items=[];
-for(const[url,scripts]of scriptsByUrl.entries()){
-const networkRecord=networkRecords.find(record=>record.url===url);
-if(!networkRecord)continue;
-const wasteData=scripts.map(UnusedJavaScript.computeWaste);
-const item=UnusedJavaScript.mergeWaste(wasteData,networkRecord);
-if(item.wastedBytes<=IGNORE_THRESHOLD_IN_BYTES)continue;
-items.push(item);
-}
-
-return{
-items,
-headings:[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}]};
-
-
-}}
-
-
-module.exports=UnusedJavaScript;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/unused-javascript.js");
-},{"../../lib/i18n/i18n.js":36,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-long-cache-ttl":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const assert=require('assert');
-
-const parseCacheControl=require('parse-cache-control');
-const Audit=require('../audit');
-const NetworkRequest=require('../../lib/network-request');
-const URL=require('../../lib/url-shim');
-const linearInterpolation=require('../../lib/statistics').linearInterpolation;
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Uses efficient cache policy on static assets',
-
-failureTitle:'Serve static assets with an efficient cache policy',
-
-description:
-'A long cache lifetime can speed up repeat visits to your page. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/cache-policy).',
-
-displayValue:`{itemCount, plural,
- =1 {1 resource found}
- other {# resources found}
- }`};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-const IGNORE_THRESHOLD_IN_PERCENT=0.925;
-
-class CacheHeaders extends Audit{
-
-
-
-static get meta(){
-return{
-id:'uses-long-cache-ttl',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['devtoolsLogs','traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:4*1024,
-scoreMedian:128*1024};
-
-}
-
-
-
-
-
-
-
-static getCacheHitProbability(maxAgeInSeconds){
-
-
-
-
-
-const RESOURCE_AGE_IN_HOURS_DECILES=[0,0.2,1,3,8,12,24,48,72,168,8760,Infinity];
-assert.ok(RESOURCE_AGE_IN_HOURS_DECILES.length===12,'deciles 0-10 and 1 for overflow');
-
-const maxAgeInHours=maxAgeInSeconds/3600;
-const upperDecileIndex=RESOURCE_AGE_IN_HOURS_DECILES.findIndex(
-decile=>decile>=maxAgeInHours);
-
-
-
-if(upperDecileIndex===RESOURCE_AGE_IN_HOURS_DECILES.length-1)return 1;
-if(upperDecileIndex===0)return 0;
-
-
-const upperDecileValue=RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex];
-const lowerDecileValue=RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex-1];
-const upperDecile=upperDecileIndex/10;
-const lowerDecile=(upperDecileIndex-1)/10;
-
-
-return linearInterpolation(
-lowerDecileValue,
-lowerDecile,
-upperDecileValue,
-upperDecile,
-maxAgeInHours);
-
-}
-
-
-
-
-
-
-
-
-
-static computeCacheLifetimeInSeconds(headers,cacheControl){
-if(cacheControl){
-
-if(cacheControl['no-cache']||cacheControl['no-store'])return 0;
-const maxAge=cacheControl['max-age'];
-if(maxAge!==undefined&&Number.isFinite(maxAge))return Math.max(maxAge,0);
-}else if((headers.get('pragma')||'').includes('no-cache')){
-
-return 0;
-}
-
-const expiresHeaders=headers.get('expires');
-if(expiresHeaders){
-const expires=new Date(expiresHeaders).getTime();
-
-if(!expires)return 0;
-return Math.max(0,Math.ceil((expires-Date.now())/1000));
-}
-
-return null;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-static isCacheableAsset(record){
-const CACHEABLE_STATUS_CODES=new Set([200,203,206]);
-
-
-const STATIC_RESOURCE_TYPES=new Set([
-NetworkRequest.TYPES.Font,
-NetworkRequest.TYPES.Image,
-NetworkRequest.TYPES.Media,
-NetworkRequest.TYPES.Script,
-NetworkRequest.TYPES.Stylesheet]);
-
-
-const resourceUrl=record.url;
-return(
-CACHEABLE_STATUS_CODES.has(record.statusCode)&&
-STATIC_RESOURCE_TYPES.has(record.resourceType||'Other')&&
-!resourceUrl.includes('data:'));
-
-}
-
-
-
-
-
-
-static audit(artifacts,context){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLogs).then(records=>{
-const results=[];
-let queryStringCount=0;
-let totalWastedBytes=0;
-
-for(const record of records){
-if(!CacheHeaders.isCacheableAsset(record))continue;
-
-
-const headers=new Map();
-for(const header of record.responseHeaders||[]){
-if(headers.has(header.name.toLowerCase())){
-const previousHeaderValue=headers.get(header.name.toLowerCase());
-headers.set(header.name.toLowerCase(),
-`${previousHeaderValue}, ${header.value}`);
-}else{
-headers.set(header.name.toLowerCase(),header.value);
-}
-}
-
-const cacheControl=parseCacheControl(headers.get('cache-control'));
-let cacheLifetimeInSeconds=CacheHeaders.computeCacheLifetimeInSeconds(
-headers,
-cacheControl);
-
-
-
-if(cacheLifetimeInSeconds===0)continue;
-cacheLifetimeInSeconds=cacheLifetimeInSeconds||0;
-
-const cacheHitProbability=CacheHeaders.getCacheHitProbability(cacheLifetimeInSeconds);
-if(cacheHitProbability>IGNORE_THRESHOLD_IN_PERCENT)continue;
-
-const url=URL.elideDataURI(record.url);
-const totalBytes=record.transferSize||0;
-const wastedBytes=(1-cacheHitProbability)*totalBytes;
-
-totalWastedBytes+=wastedBytes;
-if(url.includes('?'))queryStringCount++;
-
-results.push({
-url,
-cacheControl,
-cacheLifetimeMs:cacheLifetimeInSeconds*1000,
-cacheHitProbability,
-totalBytes,
-wastedBytes});
-
-}
-
-results.sort(
-(a,b)=>a.cacheLifetimeMs-b.cacheLifetimeMs||b.totalBytes-a.totalBytes);
-
-
-const score=Audit.computeLogNormalScore(
-totalWastedBytes,
-context.options.scorePODR,
-context.options.scoreMedian);
-
-
-const headings=[
-{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
-
-{key:'cacheLifetimeMs',itemType:'ms',text:str_(i18n.UIStrings.columnCacheTTL),
-displayUnit:'duration'},
-{key:'totalBytes',itemType:'bytes',text:str_(i18n.UIStrings.columnSize),
-displayUnit:'kb',granularity:1}];
-
-
-const summary={wastedBytes:totalWastedBytes};
-const details=Audit.makeTableDetails(headings,results,summary);
-
-return{
-score,
-rawValue:totalWastedBytes,
-displayValue:str_(UIStrings.displayValue,{itemCount:results.length}),
-extendedInfo:{
-value:{
-results,
-queryStringCount}},
-
-
-details};
-
-});
-}}
-
-
-module.exports=CacheHeaders;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/network-request":88,"../../lib/statistics":91,"../../lib/url-shim":"url","../audit":2,"assert":102,"parse-cache-control":181}],"../audits/byte-efficiency/uses-optimized-images":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const URL=require('../../lib/url-shim');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Efficiently encode images',
-
-description:'Optimized images load faster and consume less cellular data. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_BYTES=4096;
-
-class UsesOptimizedImages extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'uses-optimized-images',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['OptimizedImages','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-static computeSavings(image){
-const bytes=image.originalSize-image.jpegSize;
-const percent=100*bytes/image.originalSize;
-return{bytes,percent};
-}
-
-
-
-
-
-static audit_(artifacts){
-const images=artifacts.OptimizedImages;
-
-
-const items=[];
-const warnings=[];
-for(const image of images){
-if(image.failed){
-warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
-continue;
-}else if(/(jpeg|bmp)/.test(image.mimeType)===false||
-image.originalSize<image.jpegSize+IGNORE_THRESHOLD_IN_BYTES){
-continue;
-}
-
-const url=URL.elideDataURI(image.url);
-const jpegSavings=UsesOptimizedImages.computeSavings(image);
-
-items.push({
-url,
-fromProtocol:image.fromProtocol,
-isCrossOrigin:!image.isSameOrigin,
-totalBytes:image.originalSize,
-wastedBytes:jpegSavings.bytes});
-
-}
-
-
-const headings=[
-{key:'url',valueType:'thumbnail',label:''},
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-warnings,
-items,
-headings};
-
-}}
-
-
-module.exports=UsesOptimizedImages;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/uses-optimized-images.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-responsive-images":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const Sentry=require('../../lib/sentry');
-const URL=require('../../lib/url-shim');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Properly size images',
-
-description:
-'Serve images that are appropriately-sized to save cellular data '+
-'and improve load time. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-
-class UsesResponsiveImages extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'uses-responsive-images',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['ImageUsage','ViewportDimensions','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-static computeWaste(image,DPR){
-
-if(!image.networkRecord){
-return null;
-}
-
-const url=URL.elideDataURI(image.src);
-const actualPixels=image.naturalWidth*image.naturalHeight;
-const usedPixels=image.clientWidth*image.clientHeight*Math.pow(DPR,2);
-const wastedRatio=1-usedPixels/actualPixels;
-const totalBytes=image.networkRecord.resourceSize;
-const wastedBytes=Math.round(totalBytes*wastedRatio);
-
-
-
-if(!usedPixels){
-return null;
-}
-
-if(!Number.isFinite(wastedRatio)){
-return new Error(`Invalid image sizing information ${url}`);
-}
-
-return{
-url,
-totalBytes,
-wastedBytes,
-wastedPercent:100*wastedRatio};
-
-}
-
-
-
-
-
-static audit_(artifacts){
-const images=artifacts.ImageUsage;
-const DPR=artifacts.ViewportDimensions.devicePixelRatio;
-
-
-const warnings=[];
-
-const resultsMap=new Map();
-images.forEach(image=>{
-
-if(!image.networkRecord||image.networkRecord.mimeType==='image/svg+xml'){
-return;
-}
-
-const processed=UsesResponsiveImages.computeWaste(image,DPR);
-if(!processed)return;
-
-if(processed instanceof Error){
-warnings.push(processed.message);
-Sentry.captureException(processed,{tags:{audit:this.meta.id},level:'warning'});
-return;
-}
-
-
-const existing=resultsMap.get(processed.url);
-if(!existing||existing.wastedBytes>processed.wastedBytes){
-resultsMap.set(processed.url,processed);
-}
-});
-
-const items=Array.from(resultsMap.values()).
-filter(item=>item.wastedBytes>IGNORE_THRESHOLD_IN_BYTES);
-
-
-const headings=[
-{key:'url',valueType:'thumbnail',label:''},
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-warnings,
-items,
-headings};
-
-}}
-
-
-module.exports=UsesResponsiveImages;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/uses-responsive-images.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/sentry":90,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-text-compression":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const URL=require('../../lib/url-shim');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Enable text compression',
-
-description:'Text-based resources should be served with compression (gzip, deflate or'+
-' brotli) to minimize total network bytes.'+
-' [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_BYTES=1400;
-const IGNORE_THRESHOLD_IN_PERCENT=0.1;
-
-class ResponsesAreCompressed extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'uses-text-compression',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['ResponseCompression','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-static audit_(artifacts){
-const uncompressedResponses=artifacts.ResponseCompression;
-
-
-const items=[];
-uncompressedResponses.forEach(record=>{
-
-if(!record.gzipSize||record.gzipSize<0)return;
-
-const originalSize=record.resourceSize;
-const gzipSize=record.gzipSize;
-const gzipSavings=originalSize-gzipSize;
-
-
-
-if(1-gzipSize/originalSize<IGNORE_THRESHOLD_IN_PERCENT||
-gzipSavings<IGNORE_THRESHOLD_IN_BYTES||
-record.transferSize<gzipSize)
-{
-return;
-}
-
-
-const url=URL.elideDataURI(record.url);
-const isDuplicate=items.find(item=>item.url===url&&
-item.totalBytes===record.resourceSize);
-if(isDuplicate){
-return;
-}
-
-items.push({
-url,
-totalBytes:originalSize,
-wastedBytes:gzipSavings});
-
-});
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-items,
-headings};
-
-}}
-
-
-module.exports=ResponsesAreCompressed;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/uses-text-compression.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-webp-images":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const URL=require('../../lib/url-shim');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Serve images in next-gen formats',
-
-description:'Image formats like JPEG 2000, JPEG XR, and WebP often provide better '+
-'compression than PNG or JPEG, which means faster downloads and less data consumption. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const IGNORE_THRESHOLD_IN_BYTES=8192;
-
-class UsesWebPImages extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-id:'uses-webp-images',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['OptimizedImages','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-static computeSavings(image){
-const bytes=image.originalSize-image.webpSize;
-const percent=100*bytes/image.originalSize;
-return{bytes,percent};
-}
-
-
-
-
-
-static audit_(artifacts){
-const images=artifacts.OptimizedImages;
-
-
-const items=[];
-const warnings=[];
-for(const image of images){
-if(image.failed){
-warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
-continue;
-}else if(image.originalSize<image.webpSize+IGNORE_THRESHOLD_IN_BYTES){
-continue;
-}
-
-const url=URL.elideDataURI(image.url);
-const webpSavings=UsesWebPImages.computeSavings(image);
-
-items.push({
-url,
-fromProtocol:image.fromProtocol,
-isCrossOrigin:!image.isSameOrigin,
-totalBytes:image.originalSize,
-wastedBytes:webpSavings.bytes});
-
-}
-
-
-const headings=[
-{key:'url',valueType:'thumbnail',label:''},
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
-{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
-
-
-return{
-warnings,
-items,
-headings};
-
-}}
-
-
-module.exports=UsesWebPImages;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/uses-webp-images.js");
-},{"../../lib/i18n/i18n.js":36,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/content-width":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-class ContentWidth extends Audit{
-
-
-
-static get meta(){
-return{
-id:'content-width',
-title:'Content is sized correctly for the viewport',
-failureTitle:'Content is not sized correctly for the viewport',
-description:'If the width of your app\'s content doesn\'t match the width '+
-'of the viewport, your app might not be optimized for mobile screens. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/content-sized-correctly-for-viewport).',
-requiredArtifacts:['ViewportDimensions','HostUserAgent']};
-
-}
-
-
-
-
-
-
-static audit(artifacts,context){
-const userAgent=artifacts.HostUserAgent;
-const viewportWidth=artifacts.ViewportDimensions.innerWidth;
-const windowWidth=artifacts.ViewportDimensions.outerWidth;
-const widthsMatch=viewportWidth===windowWidth;
-
-
-const isMobileHost=userAgent.includes('Android')||userAgent.includes('Mobile');
-const isMobile=context.settings.emulatedFormFactor==='mobile'||
-context.settings.emulatedFormFactor!=='desktop'&&isMobileHost;
-
-if(isMobile){
-return{
-rawValue:widthsMatch,
-explanation:this.createExplanation(widthsMatch,artifacts.ViewportDimensions)};
-
-}else{
-return{
-rawValue:true,
-notApplicable:true};
-
-}
-}
-
-
-
-
-
-
-static createExplanation(match,artifact){
-if(match){
-return'';
-}
-
-return'The viewport size is '+artifact.innerWidth+'px, '+
-'whereas the window size is '+artifact.outerWidth+'px.';
-}}
-
-
-module.exports=ContentWidth;
-
-},{"./audit":2}],"../audits/critical-request-chains":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Minimize Critical Requests Depth',
-
-description:'The Critical Request Chains below show you what resources are '+
-'loaded with a high priority. Consider reducing '+
-'the length of chains, reducing the download size of resources, or '+
-'deferring the download of unnecessary resources to improve page load. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).',
-
-displayValue:`{itemCount, plural,
- =1 {1 chain found}
- other {# chains found}
- }`};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class CriticalRequestChains extends Audit{
-
-
-
-static get meta(){
-return{
-id:'critical-request-chains',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
-requiredArtifacts:['devtoolsLogs','URL']};
-
-}
-
-
-
-
-
-
-
-static _traverse(tree,cb){
-
-
-
-
-
-
-function walk(node,depth,startTime,transferSize=0){
-const children=Object.keys(node);
-if(children.length===0){
-return;
-}
-children.forEach(id=>{
-const child=node[id];
-if(!startTime){
-startTime=child.request.startTime;
-}
-
-
-cb({
-depth,
-id,
-node:child,
-chainDuration:(child.request.endTime-startTime)*1000,
-chainTransferSize:transferSize+child.request.transferSize});
-
-
-
-walk(child.children,depth+1,startTime);
-},'');
-}
-
-walk(tree,0);
-}
-
-
-
-
-
-
-static _getLongestChain(tree){
-const longest={
-duration:0,
-length:0,
-transferSize:0};
-
-CriticalRequestChains._traverse(tree,opts=>{
-const duration=opts.chainDuration;
-if(duration>longest.duration){
-longest.duration=duration;
-longest.transferSize=opts.chainTransferSize;
-longest.length=opts.depth;
-}
-});
-
-longest.length++;
-return longest;
-}
-
-
-
-
-
-static flattenRequests(tree){
-
-const flattendChains={};
-
-const chainMap=new Map();
-
-
-function flatten(opts){
-const request=opts.node.request;
-const simpleRequest={
-url:request.url,
-startTime:request.startTime,
-endTime:request.endTime,
-responseReceivedTime:request.responseReceivedTime,
-transferSize:request.transferSize};
-
-
-let chain=chainMap.get(opts.id);
-if(chain){
-chain.request=simpleRequest;
-}else{
-chain={
-request:simpleRequest,
-children:{}};
-
-flattendChains[opts.id]=chain;
-}
-
-for(const chainId of Object.keys(opts.node.children)){
-
-const childChain={
-request:{},
-children:{}};
-
-chainMap.set(chainId,childChain);
-chain.children[chainId]=childChain;
-}
-
-chainMap.set(opts.id,chain);
-}
-
-CriticalRequestChains._traverse(tree,flatten);
-
-return flattendChains;
-}
-
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const URL=artifacts.URL;
-return artifacts.requestCriticalRequestChains({devtoolsLog,URL}).then(chains=>{
-let chainCount=0;
-
-
-
-
-function walk(node,depth){
-const children=Object.keys(node);
-
-
-
-if(children.length===0){
-chainCount++;
-}
-
-children.forEach(id=>{
-const child=node[id];
-walk(child.children,depth+1);
-},'');
-}
-
-const flattenedChains=CriticalRequestChains.flattenRequests(chains);
-
-
-const initialNavKey=Object.keys(flattenedChains)[0];
-const initialNavChildren=initialNavKey&&flattenedChains[initialNavKey].children;
-if(initialNavChildren&&Object.keys(initialNavChildren).length>0){
-walk(initialNavChildren,0);
-}
-
-const longestChain=CriticalRequestChains._getLongestChain(flattenedChains);
-
-return{
-rawValue:chainCount===0,
-notApplicable:chainCount===0,
-displayValue:chainCount?str_(UIStrings.displayValue,{itemCount:chainCount}):'',
-extendedInfo:{
-value:{
-chains:flattenedChains,
-longestChain}},
-
-
-details:{
-type:'criticalrequestchain',
-chains:flattenedChains,
-longestChain}};
-
-
-});
-}}
-
-
-module.exports=CriticalRequestChains;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/critical-request-chains.js");
-},{"../lib/i18n/i18n.js":36,"./audit":2}],"../audits/deprecations":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const Audit=require('./audit');
-const Util=require('../report/html/renderer/util');
-
-class Deprecations extends Audit{
-
-
-
-static get meta(){
-return{
-id:'deprecations',
-title:'Avoids deprecated APIs',
-failureTitle:'Uses deprecated APIs',
-description:'Deprecated APIs will eventually be removed from the browser. '+
-'[Learn more](https://www.chromestatus.com/features#deprecated).',
-requiredArtifacts:['ChromeConsoleMessages']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const entries=artifacts.ChromeConsoleMessages;
-
-const deprecations=entries.filter(log=>log.entry.source==='deprecation').map(log=>{
-return{
-value:log.entry.text,
-url:log.entry.url||'',
-source:log.entry.source,
-lineNumber:log.entry.lineNumber};
-
-});
-
-const headings=[
-{key:'value',itemType:'code',text:'Deprecation / Warning'},
-{key:'url',itemType:'url',text:'URL'},
-{key:'lineNumber',itemType:'text',text:'Line'}];
-
-const details=Audit.makeTableDetails(headings,deprecations);
-
-let displayValue='';
-if(deprecations.length>1){
-displayValue=`${Util.formatNumber(deprecations.length)} warnings found`;
-}else if(deprecations.length===1){
-displayValue=`${deprecations.length} warning found`;
-}
-
-return{
-rawValue:deprecations.length===0,
-displayValue,
-extendedInfo:{
-value:deprecations},
-
-details};
-
-}}
-
-
-module.exports=Deprecations;
-
-},{"../report/html/renderer/util":97,"./audit":2}],"../audits/dobetterweb/appcache-manifest":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-
-class AppCacheManifestAttr extends Audit{
-
-
-
-static get meta(){
-return{
-id:'appcache-manifest',
-title:'Avoids Application Cache',
-failureTitle:'Uses Application Cache',
-description:'Application Cache is deprecated. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/appcache).',
-requiredArtifacts:['AppCacheManifest']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const usingAppcache=artifacts.AppCacheManifest!==null;
-const displayValue=usingAppcache?`Found "${artifacts.AppCacheManifest}"`:'';
-
-return{
-rawValue:!usingAppcache,
-displayValue};
-
-}}
-
-
-module.exports=AppCacheManifestAttr;
-
-},{"../audit":2}],"../audits/dobetterweb/doctype":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-
-class Doctype extends Audit{
-
-
-
-static get meta(){
-return{
-id:'doctype',
-title:'Page has the HTML doctype',
-failureTitle:'Page is missing the HTML doctype',
-description:'Specifying a doctype prevents the browser from switching to quirks-mode.'+
-'Read more on the '+
-'[MDN Web Docs page](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)',
-requiredArtifacts:['Doctype']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-if(!artifacts.Doctype){
-return{
-rawValue:false,
-explanation:'Document must contain a doctype'};
-
-}
-
-
-const doctypeName=artifacts.Doctype.name.trim();
-const doctypePublicId=artifacts.Doctype.publicId;
-const doctypeSystemId=artifacts.Doctype.systemId;
-
-if(doctypePublicId!==''){
-return{
-rawValue:false,
-explanation:'Expected publicId to be an empty string'};
-
-}
-
-if(doctypeSystemId!==''){
-return{
-rawValue:false,
-explanation:'Expected systemId to be an empty string'};
-
-}
-
-
-
-
-if(doctypeName==='html'){
-return{
-rawValue:true};
-
-}else{
-return{
-rawValue:false,
-explanation:'Doctype name must be the lowercase string `html`'};
-
-}
-}}
-
-
-module.exports=Doctype;
-
-},{"../audit":2}],"../audits/dobetterweb/dom-size":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const Util=require('../../report/html/renderer/util.js');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const MAX_DOM_NODES=1500;
-const MAX_DOM_TREE_WIDTH=60;
-const MAX_DOM_TREE_DEPTH=32;
-
-const UIStrings={
-
-title:'Avoids an excessive DOM size',
-
-failureTitle:'Avoid an excessive DOM size',
-
-description:'Browser engineers recommend pages contain fewer than '+
-`~${MAX_DOM_NODES.toLocaleString()} DOM nodes. The sweet spot is a tree `+
-`depth < ${MAX_DOM_TREE_DEPTH} elements and fewer than ${MAX_DOM_TREE_WIDTH} `+
-'children/parent element. A large DOM can increase memory usage, cause longer '+
-'[style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), '+
-'and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size).',
-
-columnStatistic:'Statistic',
-
-columnElement:'Element',
-
-columnValue:'Value',
-
-displayValue:`{itemCount, plural,
- =1 {1 node}
- other {# nodes}
- }`,
-
-statisticDOMNodes:'Total DOM Nodes',
-
-statisticDOMDepth:'Maximum DOM Depth',
-
-statisticDOMWidth:'Maximum Child Elements'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-class DOMSize extends Audit{
-static get MAX_DOM_NODES(){
-return MAX_DOM_NODES;
-}
-
-
-
-
-static get meta(){
-return{
-id:'dom-size',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['DOMStats']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:700,
-scoreMedian:1400};
-
-}
-
-
-
-
-
-
-
-static audit(artifacts,context){
-const stats=artifacts.DOMStats;
-
-const score=Audit.computeLogNormalScore(
-stats.totalDOMNodes,
-context.options.scorePODR,
-context.options.scoreMedian);
-
-
-const headings=[
-{key:'statistic',itemType:'text',text:str_(UIStrings.columnStatistic)},
-{key:'element',itemType:'code',text:str_(UIStrings.columnElement)},
-{key:'value',itemType:'text',text:str_(UIStrings.columnValue)}];
-
-
-
-const items=[
-{
-statistic:str_(UIStrings.statisticDOMNodes),
-element:'',
-value:Util.formatNumber(stats.totalDOMNodes)},
-
-{
-statistic:str_(UIStrings.statisticDOMDepth),
-element:{
-type:'code',
-value:stats.depth.snippet},
-
-value:Util.formatNumber(stats.depth.max)},
-
-{
-statistic:str_(UIStrings.statisticDOMWidth),
-element:{
-type:'code',
-value:stats.width.snippet},
-
-value:Util.formatNumber(stats.width.max)}];
-
-
-
-return{
-score,
-rawValue:stats.totalDOMNodes,
-displayValue:str_(UIStrings.displayValue,{itemCount:stats.totalDOMNodes}),
-extendedInfo:{
-value:items},
-
-details:Audit.makeTableDetails(headings,items)};
-
-}}
-
-
-module.exports=DOMSize;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/dobetterweb/dom-size.js");
-},{"../../lib/i18n/i18n.js":36,"../../report/html/renderer/util.js":97,"../audit":2}],"../audits/dobetterweb/external-anchors-use-rel-noopener":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const URL=require('../../lib/url-shim');
-const Audit=require('../audit');
-
-class ExternalAnchorsUseRelNoopenerAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'external-anchors-use-rel-noopener',
-title:'Links to cross-origin destinations are safe',
-failureTitle:'Links to cross-origin destinations are unsafe',
-description:'Add `rel="noopener"` or `rel="noreferrer"` to any external links to improve '+
-'performance and prevent security vulnerabilities. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/noopener).',
-requiredArtifacts:['URL','AnchorsWithNoRelNoopener']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-
-const warnings=[];
-const pageHost=new URL(artifacts.URL.finalUrl).host;
-
-const failingAnchors=artifacts.AnchorsWithNoRelNoopener.
-filter(anchor=>{
-try{
-return new URL(anchor.href).host!==pageHost;
-}catch(err){
-warnings.push(`Unable to determine the destination for anchor (${anchor.outerHTML}). `+
-'If not used as a hyperlink, consider removing target=_blank.');
-return true;
-}
-}).
-filter(anchor=>{
-return!anchor.href||anchor.href.toLowerCase().startsWith('http');
-}).
-map(anchor=>{
-return{
-href:anchor.href||'Unknown',
-target:anchor.target||'',
-rel:anchor.rel||'',
-outerHTML:anchor.outerHTML||''};
-
-});
-
-const headings=[
-{key:'href',itemType:'url',text:'URL'},
-{key:'target',itemType:'text',text:'Target'},
-{key:'rel',itemType:'text',text:'Rel'}];
-
-
-const details=Audit.makeTableDetails(headings,failingAnchors);
-
-return{
-rawValue:failingAnchors.length===0,
-extendedInfo:{
-value:failingAnchors},
-
-details,
-warnings};
-
-}}
-
-
-module.exports=ExternalAnchorsUseRelNoopenerAudit;
-
-},{"../../lib/url-shim":"url","../audit":2}],"../audits/dobetterweb/geolocation-on-start":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ViolationAudit=require('../violation-audit');
-
-class GeolocationOnStart extends ViolationAudit{
-
-
-
-static get meta(){
-return{
-id:'geolocation-on-start',
-title:'Avoids requesting the geolocation permission on page load',
-failureTitle:'Requests the geolocation permission on page load',
-description:'Users are mistrustful of or confused by sites that request their '+
-'location without context. Consider tying the request to user gestures instead. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/geolocation-on-load).',
-requiredArtifacts:['ChromeConsoleMessages']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-
-const results=ViolationAudit.getViolationResults(artifacts,/geolocation/);
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'label',itemType:'text',text:'Location'}];
-
-
-
-const details=ViolationAudit.makeTableDetails(headings,results);
-
-return{
-rawValue:results.length===0,
-extendedInfo:{
-value:results},
-
-details};
-
-}}
-
-
-module.exports=GeolocationOnStart;
-
-},{"../violation-audit":6}],"../audits/dobetterweb/js-libraries":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-
-class JsLibrariesAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'js-libraries',
-title:'Detected JavaScript libraries',
-description:'All front-end JavaScript libraries detected on the page.',
-requiredArtifacts:['JSLibraries']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const libDetails=artifacts.JSLibraries.map(lib=>({
-name:lib.name,
-version:lib.version,
-npm:lib.npmPkgName||null}));
-
-
-const headings=[
-{key:'name',itemType:'text',text:'Name'},
-{key:'version',itemType:'text',text:'Version'}];
-
-const details=Audit.makeTableDetails(headings,libDetails,{});
-
-return{
-rawValue:true,
-details};
-
-}}
-
-
-module.exports=JsLibrariesAudit;
-
-},{"../audit":2}],"../audits/dobetterweb/no-document-write":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ViolationAudit=require('../violation-audit');
-
-class NoDocWriteAudit extends ViolationAudit{
-
-
-
-static get meta(){
-return{
-id:'no-document-write',
-title:'Avoids `document.write()`',
-failureTitle:'Uses `document.write()`',
-description:'For users on slow connections, external scripts dynamically injected via '+
-'`document.write()` can delay page load by tens of seconds. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/document-write).',
-requiredArtifacts:['ChromeConsoleMessages']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const results=ViolationAudit.getViolationResults(artifacts,/document\.write/);
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'label',itemType:'text',text:'Location'}];
-
-
-const details=ViolationAudit.makeTableDetails(headings,results);
-
-return{
-rawValue:results.length===0,
-extendedInfo:{
-value:results},
-
-details};
-
-}}
-
-
-module.exports=NoDocWriteAudit;
-
-},{"../violation-audit":6}],"../audits/dobetterweb/no-vulnerable-libraries":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const Sentry=require('../../lib/sentry');
-const semver=require('semver');
-const snykDatabase=require('../../../third-party/snyk/snapshot.json');
-
-const SEMVER_REGEX=/^(\d+\.\d+\.\d+)[^-0-9]+/;
-
-
-
-
-class NoVulnerableLibrariesAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'no-vulnerable-libraries',
-title:'Avoids front-end JavaScript libraries'+
-' with known security vulnerabilities',
-failureTitle:'Includes front-end JavaScript libraries'+
-' with known security vulnerabilities',
-description:'Some third-party scripts may contain known security vulnerabilities '+
-'that are easily identified and exploited by attackers. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/vulnerabilities).',
-requiredArtifacts:['JSLibraries']};
-
-}
-
-
-
-
-static get snykDB(){
-return snykDatabase;
-}
-
-
-
-
-static get severityMap(){
-return{
-high:3,
-medium:2,
-low:1};
-
-}
-
-
-
-
-
-
-static normalizeVersion(version){
-if(!version)return version;
-if(semver.valid(version))return version;
-
-
-if(/^\d+\.\d+$/.test(version))return`${version}.0`;
-
-const versionMatch=version.match(SEMVER_REGEX);
-if(versionMatch)return versionMatch[1];
-
-return version;
-}
-
-
-
-
-
-
-static getVulnerabilities(normalizedVersion,lib){
-const snykDB=NoVulnerableLibrariesAudit.snykDB;
-if(!lib.npmPkgName||!snykDB.npm[lib.npmPkgName]){
-return[];
-}
-
-try{
-semver.satisfies(normalizedVersion,'*');
-}catch(err){
-err.pkgName=lib.npmPkgName;
-
-Sentry.captureException(err,{level:'warning'});
-return[];
-}
-
-const snykInfo=snykDB.npm[lib.npmPkgName];
-const vulns=snykInfo.
-filter(vuln=>semver.satisfies(normalizedVersion,vuln.semver.vulnerable[0])).
-
-map(vuln=>{
-return{
-severity:vuln.severity,
-numericSeverity:this.severityMap[vuln.severity],
-library:`${lib.name}@${normalizedVersion}`,
-url:'https://snyk.io/vuln/'+vuln.id};
-
-});
-
-return vulns;
-}
-
-
-
-
-
-static highestSeverity(vulnerabilities){
-const sortedVulns=vulnerabilities.
-sort((a,b)=>b.numericSeverity-a.numericSeverity);
-return sortedVulns[0].severity;
-}
-
-
-
-
-
-static audit(artifacts){
-const foundLibraries=artifacts.JSLibraries;
-if(!foundLibraries.length){
-return{
-rawValue:true};
-
-}
-
-let totalVulns=0;
-
-const vulnerabilityResults=[];
-
-const libraryVulns=foundLibraries.map(lib=>{
-const version=this.normalizeVersion(lib.version)||'';
-const vulns=this.getVulnerabilities(version,lib);
-const vulnCount=vulns.length;
-totalVulns+=vulnCount;
-
-let highestSeverity;
-if(vulns.length>0){
-highestSeverity=this.highestSeverity(vulns).replace(/^\w/,l=>l.toUpperCase());
-
-vulnerabilityResults.push({
-highestSeverity,
-vulnCount,
-detectedLib:{
-text:lib.name+'@'+version,
-url:`https://snyk.io/vuln/npm:${lib.npmPkgName}?lh=${version}`,
-type:'link'}});
-
-
-}
-
-return{
-name:lib.name,
-npmPkgName:lib.npmPkgName,
-version,
-vulns,
-highestSeverity};
-
-});
-
-let displayValue='';
-if(totalVulns>1){
-displayValue=`${totalVulns} vulnerabilities detected`;
-}else if(totalVulns===1){
-displayValue=`${totalVulns} vulnerability detected`;
-}
-
-const headings=[
-{key:'detectedLib',itemType:'link',text:'Library Version'},
-{key:'vulnCount',itemType:'text',text:'Vulnerability Count'},
-{key:'highestSeverity',itemType:'text',text:'Highest Severity'}];
-
-const details=Audit.makeTableDetails(headings,vulnerabilityResults,{});
-
-return{
-rawValue:totalVulns===0,
-displayValue,
-extendedInfo:{
-jsLibs:libraryVulns,
-vulnerabilities:vulnerabilityResults},
-
-details};
-
-}}
-
-
-module.exports=NoVulnerableLibrariesAudit;
-
-},{"../../../third-party/snyk/snapshot.json":189,"../../lib/sentry":90,"../audit":2,"semver":184}],"../audits/dobetterweb/no-websql":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-
-class NoWebSQLAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'no-websql',
-title:'Avoids WebSQL DB',
-failureTitle:'Uses WebSQL DB',
-description:'Web SQL is deprecated. Consider using IndexedDB instead. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/web-sql).',
-requiredArtifacts:['WebSQL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const db=artifacts.WebSQL;
-const displayValue=db?
-`Found "${db.name}" (v${db.version})`:'';
-
-return{
-rawValue:!db,
-displayValue};
-
-}}
-
-
-module.exports=NoWebSQLAudit;
-
-},{"../audit":2}],"../audits/dobetterweb/notification-on-start":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ViolationAudit=require('../violation-audit');
-
-class NotificationOnStart extends ViolationAudit{
-
-
-
-static get meta(){
-return{
-id:'notification-on-start',
-title:'Avoids requesting the notification permission on page load',
-failureTitle:'Requests the notification permission on page load',
-description:'Users are mistrustful of or confused by sites that request to send '+
-'notifications without context. Consider tying the request to user gestures '+
-'instead. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/notifications-on-load).',
-requiredArtifacts:['ChromeConsoleMessages']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const results=ViolationAudit.getViolationResults(artifacts,/notification permission/);
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'label',itemType:'text',text:'Location'}];
-
-
-const details=ViolationAudit.makeTableDetails(headings,results);
-
-return{
-rawValue:results.length===0,
-extendedInfo:{
-value:results},
-
-details};
-
-}}
-
-
-module.exports=NotificationOnStart;
-
-},{"../violation-audit":6}],"../audits/dobetterweb/password-inputs-can-be-pasted-into":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-
-class PasswordInputsCanBePastedIntoAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'password-inputs-can-be-pasted-into',
-title:'Allows users to paste into password fields',
-failureTitle:'Prevents users to paste into password fields',
-description:'Preventing password pasting undermines good security policy. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/password-pasting).',
-requiredArtifacts:['PasswordInputsWithPreventedPaste']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const passwordInputsWithPreventedPaste=artifacts.PasswordInputsWithPreventedPaste;
-
-
-const items=[];
-passwordInputsWithPreventedPaste.forEach(input=>{
-items.push({
-node:{type:'node',snippet:input.snippet}});
-
-});
-
-const headings=[
-{key:'node',itemType:'node',text:'Failing Elements'}];
-
-
-return{
-rawValue:passwordInputsWithPreventedPaste.length===0,
-extendedInfo:{
-value:passwordInputsWithPreventedPaste},
-
-details:Audit.makeTableDetails(headings,items)};
-
-}}
-
-
-module.exports=PasswordInputsCanBePastedIntoAudit;
-
-},{"../audit":2}],"../audits/dobetterweb/uses-http2":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const URL=require('../../lib/url-shim');
-const Audit=require('../audit');
-const Util=require('../../report/html/renderer/util.js');
-
-class UsesHTTP2Audit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'uses-http2',
-title:'Uses HTTP/2 for its own resources',
-failureTitle:'Does not use HTTP/2 for all of its resources',
-description:'HTTP/2 offers many benefits over HTTP/1.1, including binary headers, '+
-'multiplexing, and server push. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/http2).',
-requiredArtifacts:['URL','devtoolsLogs']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
-const finalHost=new URL(artifacts.URL.finalUrl).host;
-
-const seenURLs=new Set();
-
-const resources=networkRecords.filter(record=>{
-
-const isOldHttp=/HTTP\/[01][.\d]?/i.test(record.protocol);
-if(!isOldHttp)return false;
-const requestHost=new URL(record.url).host;
-return requestHost===finalHost;
-}).map(record=>{
-return{
-protocol:record.protocol,
-url:record.url};
-
-}).filter(record=>{
-if(seenURLs.has(record.url))return false;
-seenURLs.add(record.url);
-return true;
-});
-
-let displayValue='';
-if(resources.length>1){
-displayValue=
-`${Util.formatNumber(resources.length)} requests not served via HTTP/2`;
-}else if(resources.length===1){
-displayValue=`${resources.length} request not served via HTTP/2`;
-}
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'protocol',itemType:'text',text:'Protocol'}];
-
-const details=Audit.makeTableDetails(headings,resources);
-
-return{
-rawValue:resources.length===0,
-displayValue:displayValue,
-extendedInfo:{
-value:{
-results:resources}},
-
-
-details};
-
-});
-}}
-
-
-module.exports=UsesHTTP2Audit;
-
-},{"../../lib/url-shim":"url","../../report/html/renderer/util.js":97,"../audit":2}],"../audits/dobetterweb/uses-passive-event-listeners":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ViolationAudit=require('../violation-audit');
-
-class PassiveEventsAudit extends ViolationAudit{
-
-
-
-static get meta(){
-return{
-id:'uses-passive-event-listeners',
-title:'Uses passive listeners to improve scrolling performance',
-failureTitle:'Does not use passive listeners to improve scrolling performance',
-description:'Consider marking your touch and wheel event listeners as `passive` '+
-'to improve your page\'s scroll performance. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners).',
-requiredArtifacts:['ChromeConsoleMessages']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const results=ViolationAudit.getViolationResults(artifacts,/passive event listener/);
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'label',itemType:'text',text:'Location'}];
-
-
-const details=ViolationAudit.makeTableDetails(headings,results);
-
-return{
-rawValue:results.length===0,
-extendedInfo:{
-value:results},
-
-details};
-
-}}
-
-
-module.exports=PassiveEventsAudit;
-
-},{"../violation-audit":6}],"../audits/errors-in-console":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const Audit=require('./audit');
-
-class ErrorLogs extends Audit{
-
-
-
-static get meta(){
-return{
-id:'errors-in-console',
-title:'No browser errors logged to the console',
-description:'Errors logged to the console indicate unresolved problems. '+
-'They can come from network request failures and other browser concerns.',
-failureTitle:'Browser errors were logged to the console',
-requiredArtifacts:['ChromeConsoleMessages','RuntimeExceptions']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const consoleEntries=artifacts.ChromeConsoleMessages;
-const runtimeExceptions=artifacts.RuntimeExceptions;
-
-const consoleRows=
-consoleEntries.filter(log=>log.entry&&log.entry.level==='error').
-map(item=>{
-return{
-source:item.entry.source,
-description:item.entry.text,
-url:item.entry.url};
-
-});
-
-const runtimeExRows=
-runtimeExceptions.filter(entry=>entry.exceptionDetails!==undefined).
-map(entry=>{
-const description=entry.exceptionDetails.exception?
-entry.exceptionDetails.exception.description:entry.exceptionDetails.text;
-
-return{
-source:'Runtime.exception',
-description,
-url:entry.exceptionDetails.url};
-
-});
-
-const tableRows=consoleRows.concat(runtimeExRows);
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'description',itemType:'code',text:'Description'}];
-
-
-const details=Audit.makeTableDetails(headings,tableRows);
-const numErrors=tableRows.length;
-
-return{
-score:Number(numErrors===0),
-rawValue:numErrors,
-details};
-
-}}
-
-
-module.exports=ErrorLogs;
-
-},{"./audit":2}],"../audits/final-screenshot":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const LHError=require('../lib/lh-error');
-
-class FinalScreenshot extends Audit{
-
-
-
-static get meta(){
-return{
-id:'final-screenshot',
-scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
-title:'Final Screenshot',
-description:'The last screenshot captured of the pageload.',
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-
-static async audit(artifacts){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const screenshots=await artifacts.requestScreenshots(trace);
-const finalScreenshot=screenshots[screenshots.length-1];
-
-if(!finalScreenshot){
-throw new LHError(LHError.errors.NO_SCREENSHOTS);
-}
-
-return{
-rawValue:true,
-details:{
-type:'screenshot',
-timestamp:finalScreenshot.timestamp,
-data:finalScreenshot.datauri}};
-
-
-}}
-
-
-module.exports=FinalScreenshot;
-
-},{"../lib/lh-error":85,"./audit":2}],"../audits/font-display":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const NetworkRequest=require('../lib/network-request');
-const allowedFontFaceDisplays=['block','fallback','optional','swap'];
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'All text remains visible during webfont loads',
-
-failureTitle:'Ensure text remains visible during webfont load',
-
-description:'Leverage the font-display CSS feature to ensure text is user-visible while '+
-'webfonts are loading. '+
-'[Learn more](https://developers.google.com/web/updates/2016/02/font-display).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class FontDisplay extends Audit{
-
-
-
-static get meta(){
-return{
-id:'font-display',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-requiredArtifacts:['devtoolsLogs','Fonts']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[this.DEFAULT_PASS];
-const fontFaces=artifacts.Fonts;
-
-
-const fontsWithoutProperDisplay=fontFaces.filter(fontFace=>
-!fontFace.display||!allowedFontFaceDisplays.includes(fontFace.display));
-
-
-return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
-const results=networkRecords.filter(record=>{
-const isFont=record.resourceType===NetworkRequest.TYPES.Font;
-
-return isFont;
-}).
-filter(fontRecord=>{
-
-return!!fontsWithoutProperDisplay.find(fontFace=>{
-return!!fontFace.src&&!!fontFace.src.find(src=>fontRecord.url===src);
-});
-}).
-
-map(record=>{
-
-
-const wastedMs=Math.min((record.endTime-record.startTime)*1000,3000);
-
-return{
-url:record.url,
-wastedMs};
-
-});
-
-const headings=[
-{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
-{key:'wastedMs',itemType:'ms',text:str_(i18n.UIStrings.columnWastedMs)}];
-
-const details=Audit.makeTableDetails(headings,results);
-
-return{
-score:Number(results.length===0),
-rawValue:results.length===0,
-details};
-
-});
-}}
-
-
-module.exports=FontDisplay;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/font-display.js");
-},{"../lib/i18n/i18n.js":36,"../lib/network-request":88,"./audit":2}],"../audits/image-aspect-ratio":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-const URL=require('../lib/url-shim');
-const THRESHOLD_PX=2;
-
-
-
-class ImageAspectRatio extends Audit{
-
-
-
-static get meta(){
-return{
-id:'image-aspect-ratio',
-title:'Displays images with correct aspect ratio',
-failureTitle:'Displays images with incorrect aspect ratio',
-description:'Image display dimensions should match natural aspect ratio. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/aspect-ratio).',
-requiredArtifacts:['ImageUsage']};
-
-}
-
-
-
-
-
-static computeAspectRatios(image){
-const url=URL.elideDataURI(image.src);
-const actualAspectRatio=image.naturalWidth/image.naturalHeight;
-const displayedAspectRatio=image.width/image.height;
-
-const targetDisplayHeight=image.width/actualAspectRatio;
-const doRatiosMatch=Math.abs(targetDisplayHeight-image.height)<THRESHOLD_PX;
-
-if(!Number.isFinite(actualAspectRatio)||
-!Number.isFinite(displayedAspectRatio)){
-return new Error(`Invalid image sizing information ${url}`);
-}
-
-return{
-url,
-displayedAspectRatio:`${image.width} x ${image.height}
- (${displayedAspectRatio.toFixed(2)})`,
-actualAspectRatio:`${image.naturalWidth} x ${image.naturalHeight}
- (${actualAspectRatio.toFixed(2)})`,
-doRatiosMatch};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const images=artifacts.ImageUsage;
-
-
-const warnings=[];
-
-const results=[];
-images.filter(image=>{
-
-
-
-return image.networkRecord&&
-image.networkRecord.mimeType!=='image/svg+xml'&&
-image.width&&
-image.height&&
-!image.usesObjectFit;
-}).forEach(image=>{
-const wellDefinedImage=image;
-const processed=ImageAspectRatio.computeAspectRatios(wellDefinedImage);
-if(processed instanceof Error){
-warnings.push(processed.message);
-return;
-}
-
-if(!processed.doRatiosMatch)results.push(processed);
-});
-
-const headings=[
-{key:'url',itemType:'thumbnail',text:''},
-{key:'url',itemType:'url',text:'URL'},
-{key:'displayedAspectRatio',itemType:'text',text:'Aspect Ratio (Displayed)'},
-{key:'actualAspectRatio',itemType:'text',text:'Aspect Ratio (Actual)'}];
-
-
-return{
-rawValue:results.length===0,
-warnings,
-details:Audit.makeTableDetails(headings,results)};
-
-}}
-
-
-module.exports=ImageAspectRatio;
-
-},{"../lib/url-shim":"url","./audit":2}],"../audits/is-on-https":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const URL=require('../lib/url-shim');
-const Util=require('../report/html/renderer/util');
-
-const SECURE_SCHEMES=['data','https','wss','blob','chrome','chrome-extension','about'];
-const SECURE_DOMAINS=['localhost','127.0.0.1'];
-
-class HTTPS extends Audit{
-
-
-
-static get meta(){
-return{
-id:'is-on-https',
-title:'Uses HTTPS',
-failureTitle:'Does not use HTTPS',
-description:'All sites should be protected with HTTPS, even ones that don\'t handle '+
-'sensitive data. HTTPS prevents intruders from tampering with or passively listening '+
-'in on the communications between your app and your users, and is a prerequisite for '+
-'HTTP/2 and many new web platform APIs. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/https).',
-requiredArtifacts:['devtoolsLogs']};
-
-}
-
-
-
-
-
-static isSecureRecord(record){
-return SECURE_SCHEMES.includes(record.parsedURL.scheme)||
-SECURE_SCHEMES.includes(record.protocol)||
-SECURE_DOMAINS.includes(record.parsedURL.host);
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
-const insecureURLs=networkRecords.
-filter(record=>!HTTPS.isSecureRecord(record)).
-map(record=>URL.elideDataURI(record.url));
-
-let displayValue='';
-if(insecureURLs.length>1){
-displayValue=`${Util.formatNumber(insecureURLs.length)} insecure requests found`;
-}else if(insecureURLs.length===1){
-displayValue=`${insecureURLs.length} insecure request found`;
-}
-
-const items=Array.from(new Set(insecureURLs)).map(url=>({url}));
-
-const headings=[
-{key:'url',itemType:'url',text:'Insecure URL'}];
-
-
-return{
-rawValue:items.length===0,
-displayValue,
-extendedInfo:{
-value:items},
-
-details:Audit.makeTableDetails(headings,items)};
-
-});
-}}
-
-
-module.exports=HTTPS;
-
-},{"../lib/url-shim":"url","../report/html/renderer/util":97,"./audit":2}],"../audits/load-fast-enough-for-pwa":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const isDeepEqual=require('lodash.isequal');
-const Audit=require('./audit');
-const mobile3GThrottling=require('../config/constants').throttling.mobile3G;
-
-
-
-const MAXIMUM_TTI=10*1000;
-
-class LoadFastEnough4Pwa extends Audit{
-
-
-
-static get meta(){
-return{
-id:'load-fast-enough-for-pwa',
-title:'Page load is fast enough on 3G',
-failureTitle:'Page load is not fast enough on 3G',
-description:
-'A fast page load over a 3G network ensures a good mobile user experience. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/fast-3g).',
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-
-
-
-const settingOverrides={throttlingMethod:'simulate',throttling:mobile3GThrottling};
-const settings=
-context.settings.throttlingMethod!=='provided'&&
-isDeepEqual(context.settings.throttling,mobile3GThrottling)?
-context.settings:
-Object.assign({},context.settings,settingOverrides);
-
-const metricComputationData={trace,devtoolsLog,settings};
-const tti=await artifacts.requestInteractive(metricComputationData);
-
-const score=Number(tti.timing<MAXIMUM_TTI);
-
-
-let displayValue;
-
-let explanation;
-if(!score){
-displayValue=[`Interactive at %d\xa0s`,tti.timing/1000];
-explanation='Your page loads too slowly and is not interactive within 10 seconds. '+
-'Look at the opportunities and diagnostics in the "Performance" section to learn how to '+
-'improve.';
-}
-
-return{
-score,
-displayValue,
-explanation,
-rawValue:tti.timing};
-
-}}
-
-
-module.exports=LoadFastEnough4Pwa;
-
-},{"../config/constants":8,"./audit":2,"lodash.isequal":178}],"../audits/mainthread-work-breakdown":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const{taskGroups}=require('../lib/task-groups');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Minimizes main-thread work',
-
-failureTitle:'Minimize main-thread work',
-
-description:'Consider reducing the time spent parsing, compiling and executing JS. '+
-'You may find delivering smaller JS payloads helps with this.',
-
-columnCategory:'Category'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-
-class MainThreadWorkBreakdown extends Audit{
-
-
-
-static get meta(){
-return{
-id:'mainthread-work-breakdown',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-scorePODR:1500,
-scoreMedian:4000};
-
-}
-
-
-
-
-
-static getExecutionTimingsByGroup(tasks){
-
-const result=new Map();
-
-for(const task of tasks){
-const originalTime=result.get(task.group.id)||0;
-result.set(task.group.id,originalTime+task.selfTime);
-}
-
-return result;
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const settings=context.settings||{};
-const trace=artifacts.traces[MainThreadWorkBreakdown.DEFAULT_PASS];
-
-const tasks=await artifacts.requestMainThreadTasks(trace);
-const multiplier=settings.throttlingMethod==='simulate'?
-settings.throttling.cpuSlowdownMultiplier:1;
-
-const executionTimings=MainThreadWorkBreakdown.getExecutionTimingsByGroup(tasks);
-
-let totalExecutionTime=0;
-
-const categoryTotals={};
-const results=Array.from(executionTimings).map(([groupId,rawDuration])=>{
-const duration=rawDuration*multiplier;
-totalExecutionTime+=duration;
-
-const categoryTotal=categoryTotals[groupId]||0;
-categoryTotals[groupId]=categoryTotal+duration;
-
-return{
-group:groupId,
-groupLabel:taskGroups[groupId].label,
-duration:duration};
-
-});
-
-const headings=[
-{key:'groupLabel',itemType:'text',text:str_(UIStrings.columnCategory)},
-{key:'duration',itemType:'ms',granularity:1,text:str_(i18n.UIStrings.columnTimeSpent)}];
-
-
-results.sort((a,b)=>categoryTotals[b.group]-categoryTotals[a.group]);
-const tableDetails=MainThreadWorkBreakdown.makeTableDetails(headings,results);
-
-const score=Audit.computeLogNormalScore(
-totalExecutionTime,
-context.options.scorePODR,
-context.options.scoreMedian);
-
-
-return{
-score,
-rawValue:totalExecutionTime,
-displayValue:str_(i18n.UIStrings.seconds,{timeInMs:totalExecutionTime}),
-details:tableDetails};
-
-}}
-
-
-module.exports=MainThreadWorkBreakdown;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/mainthread-work-breakdown.js");
-},{"../lib/i18n/i18n.js":36,"../lib/task-groups":93,"./audit":2}],"../audits/manifest-short-name-length":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const ManifestValues=require('../gather/computed/manifest-values');
-
-class ManifestShortNameLength extends Audit{
-
-
-
-static get meta(){
-return{
-id:'manifest-short-name-length',
-title:'The `short_name` won\'t be truncated on the homescreen',
-failureTitle:'The `short_name` will be truncated on the homescreen',
-description:'Make your app\'s `short_name` fewer than 12 characters to '+
-'ensure that it\'s not truncated on homescreens. [Learn '+
-'more](https://developers.google.com/web/tools/lighthouse/audits/manifest-short_name-is-not-truncated).',
-requiredArtifacts:['Manifest']};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const manifestValues=await ManifestValues.request(context,artifacts.Manifest);
-
-if(manifestValues.isParseFailure){
-return{
-rawValue:true,
-notApplicable:true};
-
-}
-
-const shortNameCheck=manifestValues.allChecks.find(i=>i.id==='hasShortName');
-const shortNameLengthCheck=manifestValues.allChecks.find(i=>i.id==='shortNameLength');
-
-
-if(shortNameCheck&&!shortNameCheck.passing){
-return{
-rawValue:true,
-notApplicable:true};
-
-}
-
-if(shortNameLengthCheck&&!shortNameLengthCheck.passing){
-return{
-rawValue:false,
-explanation:`Failure: ${shortNameLengthCheck.failureText}.`};
-
-}
-
-return{
-rawValue:true};
-
-}}
-
-
-module.exports=ManifestShortNameLength;
-
-},{"../gather/computed/manifest-values":12,"./audit":2}],"../audits/manual/pwa-cross-browser":[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('./manual-audit');
-
-
-
-
-
-class PWACrossBrowser extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'pwa-cross-browser',
-description:'To reach the most number of users, sites should work across '+
-'every major browser. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#site-works-cross-browser).',
-title:'Site works cross-browser'},
-super.partialMeta);
-}}
-
-
-module.exports=PWACrossBrowser;
-
-},{"./manual-audit":4}],"../audits/manual/pwa-each-page-has-url":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('./manual-audit');
-
-
-
-
-
-class PWAEachPageHasURL extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'pwa-each-page-has-url',
-description:'Ensure individual pages are deep linkable via the URLs and that URLs are '+
-'unique for the purpose of shareability on social media. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#each-page-has-a-url).',
-title:'Each page has a URL'},
-super.partialMeta);
-}}
-
-
-module.exports=PWAEachPageHasURL;
-
-},{"./manual-audit":4}],"../audits/manual/pwa-page-transitions":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('./manual-audit');
-
-
-
-
-
-class PWAPageTransitions extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'pwa-page-transitions',
-description:'Transitions should feel snappy as you tap around, even on a slow network, a '+
-'key to perceived performance. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#page-transitions-dont-feel-like-they-block-on-the-network).',
-title:'Page transitions don\'t feel like they block on the network'},
-super.partialMeta);
-}}
-
-
-module.exports=PWAPageTransitions;
-
-},{"./manual-audit":4}],"../audits/metrics/estimated-input-latency":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Estimated Input Latency',
-
-description:'The score above is an estimate of how long your app takes to respond to user '+
-'input, in milliseconds, during the busiest 5s window of page load. If your '+
-'latency is higher than 50 ms, users may perceive your app as laggy. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class EstimatedInputLatency extends Audit{
-
-
-
-static get meta(){
-return{
-id:'estimated-input-latency',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-scorePODR:50,
-scoreMedian:100};
-
-}
-
-
-
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const metricResult=await artifacts.requestEstimatedInputLatency(metricComputationData);
-
-return{
-score:Audit.computeLogNormalScore(
-metricResult.timing,
-context.options.scorePODR,
-context.options.scoreMedian),
-
-rawValue:metricResult.timing,
-displayValue:str_(i18n.UIStrings.ms,{timeInMs:metricResult.timing})};
-
-}}
-
-
-module.exports=EstimatedInputLatency;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/metrics/estimated-input-latency.js");
-},{"../../lib/i18n/i18n.js":36,"../audit":2}],"../audits/metrics/first-contentful-paint":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'First Contentful Paint',
-
-description:'First Contentful Paint marks the time at which the first text or image is '+
-`painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint).`};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class FirstContentfulPaint extends Audit{
-
-
-
-static get meta(){
-return{
-id:'first-contentful-paint',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:2000,
-scoreMedian:4000};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const metricResult=await artifacts.requestFirstContentfulPaint(metricComputationData);
-
-return{
-score:Audit.computeLogNormalScore(
-metricResult.timing,
-context.options.scorePODR,
-context.options.scoreMedian),
-
-rawValue:metricResult.timing,
-displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
-
-}}
-
-
-module.exports=FirstContentfulPaint;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/metrics/first-contentful-paint.js");
-},{"../../lib/i18n/i18n.js":36,"../audit":2}],"../audits/metrics/first-cpu-idle":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'First CPU Idle',
-
-description:'First CPU Idle marks the first time at which the page\'s main thread is '+
-'quiet enough to handle input. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class FirstCPUIdle extends Audit{
-
-
-
-static get meta(){
-return{
-id:'first-cpu-idle',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:2900,
-scoreMedian:6500};
-
-}
-
-
-
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const metricResult=await artifacts.requestFirstCPUIdle(metricComputationData);
-
-return{
-score:Audit.computeLogNormalScore(
-metricResult.timing,
-context.options.scorePODR,
-context.options.scoreMedian),
-
-rawValue:metricResult.timing,
-displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
-
-}}
-
-
-module.exports=FirstCPUIdle;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/metrics/first-cpu-idle.js");
-},{"../../lib/i18n/i18n.js":36,"../audit":2}],"../audits/metrics/first-meaningful-paint":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'First Meaningful Paint',
-
-description:'First Meaningful Paint measures when the primary content of a page is '+
-'visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class FirstMeaningfulPaint extends Audit{
-
-
-
-static get meta(){
-return{
-id:'first-meaningful-paint',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:2000,
-scoreMedian:4000};
-
-}
-
-
-
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const metricResult=await artifacts.requestFirstMeaningfulPaint(metricComputationData);
-
-return{
-score:Audit.computeLogNormalScore(
-metricResult.timing,
-context.options.scorePODR,
-context.options.scoreMedian),
-
-rawValue:metricResult.timing,
-displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
-
-}}
-
-
-module.exports=FirstMeaningfulPaint;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/metrics/first-meaningful-paint.js");
-},{"../../lib/i18n/i18n.js":36,"../audit":2}],"../audits/metrics/interactive":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Time to Interactive',
-
-description:'Interactive marks the time at which the page is fully interactive. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-
-
-
-
-
-class InteractiveMetric extends Audit{
-
-
-
-static get meta(){
-return{
-id:'interactive',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:2900,
-scoreMedian:7300};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const metricResult=await artifacts.requestInteractive(metricComputationData);
-const timeInMs=metricResult.timing;
-const extendedInfo={
-timeInMs,
-timestamp:metricResult.timestamp,
-
-optimistic:metricResult.optimisticEstimate&&metricResult.optimisticEstimate.timeInMs,
-
-pessimistic:metricResult.pessimisticEstimate&&metricResult.pessimisticEstimate.timeInMs};
-
-
-return{
-score:Audit.computeLogNormalScore(
-timeInMs,
-context.options.scorePODR,
-context.options.scoreMedian),
-
-rawValue:timeInMs,
-displayValue:str_(i18n.UIStrings.seconds,{timeInMs}),
-extendedInfo:{
-value:extendedInfo}};
-
-
-}}
-
-
-module.exports=InteractiveMetric;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/metrics/interactive.js");
-},{"../../lib/i18n/i18n.js":36,"../audit":2}],"../audits/metrics/speed-index":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Speed Index',
-
-description:'Speed Index shows how quickly the contents of a page are visibly populated. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class SpeedIndex extends Audit{
-
-
-
-static get meta(){
-return{
-id:'speed-index',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-static get defaultOptions(){
-return{
-
-
-
-scorePODR:2900,
-scoreMedian:5800};
-
-}
-
-
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const metricResult=await artifacts.requestSpeedIndex(metricComputationData);
-
-return{
-score:Audit.computeLogNormalScore(
-metricResult.timing,
-context.options.scorePODR,
-context.options.scoreMedian),
-
-rawValue:metricResult.timing,
-displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
-
-}}
-
-
-module.exports=SpeedIndex;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/metrics/speed-index.js");
-},{"../../lib/i18n/i18n.js":36,"../audit":2}],"../audits/metrics":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-class Metrics extends Audit{
-
-
-
-static get meta(){
-return{
-id:'metrics',
-scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
-title:'Metrics',
-description:'Collects all available metrics.',
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-
-const traceOfTab=await artifacts.requestTraceOfTab(trace);
-const speedline=await artifacts.requestSpeedline(trace);
-const firstContentfulPaint=await artifacts.requestFirstContentfulPaint(metricComputationData);
-const firstMeaningfulPaint=await artifacts.requestFirstMeaningfulPaint(metricComputationData);
-const firstCPUIdle=await artifacts.requestFirstCPUIdle(metricComputationData);
-const interactive=await artifacts.requestInteractive(metricComputationData);
-const speedIndex=await artifacts.requestSpeedIndex(metricComputationData);
-const estimatedInputLatency=await artifacts.requestEstimatedInputLatency(metricComputationData);
-
-
-const metrics={
-
-firstContentfulPaint:firstContentfulPaint.timing,
-firstContentfulPaintTs:firstContentfulPaint.timestamp,
-firstMeaningfulPaint:firstMeaningfulPaint.timing,
-firstMeaningfulPaintTs:firstMeaningfulPaint.timestamp,
-firstCPUIdle:firstCPUIdle.timing,
-firstCPUIdleTs:firstCPUIdle.timestamp,
-interactive:interactive.timing,
-interactiveTs:interactive.timestamp,
-speedIndex:speedIndex.timing,
-speedIndexTs:speedIndex.timestamp,
-estimatedInputLatency:estimatedInputLatency.timing,
-estimatedInputLatencyTs:estimatedInputLatency.timestamp,
-
-
-observedNavigationStart:traceOfTab.timings.navigationStart,
-observedNavigationStartTs:traceOfTab.timestamps.navigationStart,
-observedFirstPaint:traceOfTab.timings.firstPaint,
-observedFirstPaintTs:traceOfTab.timestamps.firstPaint,
-observedFirstContentfulPaint:traceOfTab.timings.firstContentfulPaint,
-observedFirstContentfulPaintTs:traceOfTab.timestamps.firstContentfulPaint,
-observedFirstMeaningfulPaint:traceOfTab.timings.firstMeaningfulPaint,
-observedFirstMeaningfulPaintTs:traceOfTab.timestamps.firstMeaningfulPaint,
-observedTraceEnd:traceOfTab.timings.traceEnd,
-observedTraceEndTs:traceOfTab.timestamps.traceEnd,
-observedLoad:traceOfTab.timings.load,
-observedLoadTs:traceOfTab.timestamps.load,
-observedDomContentLoaded:traceOfTab.timings.domContentLoaded,
-observedDomContentLoadedTs:traceOfTab.timestamps.domContentLoaded,
-
-
-observedFirstVisualChange:speedline.first,
-observedFirstVisualChangeTs:(speedline.first+speedline.beginning)*1000,
-observedLastVisualChange:speedline.complete,
-observedLastVisualChangeTs:(speedline.complete+speedline.beginning)*1000,
-observedSpeedIndex:speedline.speedIndex,
-observedSpeedIndexTs:(speedline.speedIndex+speedline.beginning)*1000};
-
-
-for(const[name,value]of Object.entries(metrics)){
-const key=name;
-if(typeof value!=='undefined'){
-metrics[key]=Math.round(value);
-}
-}
-
-
-const details={items:[metrics]};
-
-return{
-score:1,
-rawValue:interactive.timing,
-details};
-
-}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-module.exports=Metrics;
-
-},{"./audit":2}],"../audits/mixed-content":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const URL=require('../lib/url-shim');
-const Util=require('../report/html/renderer/util');
-
-
-
-
-
-
-
-class MixedContent extends Audit{
-
-
-
-static get meta(){
-return{
-id:'mixed-content',
-title:'All resources loaded are secure',
-failureTitle:'Some insecure resources can be upgraded to HTTPS',
-description:`Mixed content warnings can prevent you from upgrading to HTTPS.
- This audit shows which insecure resources this page uses that can be
- upgraded to HTTPS. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/mixed-content)`,
-requiredArtifacts:['devtoolsLogs','MixedContent']};
-
-}
-
-
-
-
-
-
-
-static upgradeURL(url){
-const parsedURL=new URL(url);
-parsedURL.protocol='https:';
-return parsedURL.href;
-}
-
-
-
-
-
-
-
-static simplifyURL(url){
-const parsedURL=new URL(url);
-parsedURL.hash='';
-parsedURL.search='';
-return parsedURL.href;
-}
-
-
-
-
-
-
-
-static displayURL(url=''){
-const displayOptions={
-numPathParts:4,
-preserveQuery:false,
-preserveHost:true};
-
-return URL.getURLDisplayName(url,displayOptions);
-}
-
-
-
-
-
-static audit(artifacts){
-const defaultLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const upgradeLogs=artifacts.devtoolsLogs['mixedContentPass'];
-const baseHostname=new URL(artifacts.MixedContent.url).host;
-
-const computedArtifacts=[
-artifacts.requestNetworkRecords(defaultLogs),
-artifacts.requestNetworkRecords(upgradeLogs)];
-
-
-return Promise.all(computedArtifacts).then(([defaultRecords,upgradedRecords])=>{
-const insecureRecords=defaultRecords.filter(
-record=>!record.isSecure);
-const secureRecords=defaultRecords.filter(
-record=>record.isSecure);
-
-const upgradePassHosts=new Set();
-const upgradePassSecureHosts=new Set();
-upgradedRecords.forEach(record=>{
-upgradePassHosts.add(new URL(record.url).hostname);
-if(record.isSecure&&record.finished&&!record.failed){
-upgradePassSecureHosts.add(new URL(record.url).hostname);
-}
-});
-
-
-
-
-const seen=new Set();
-const upgradeableResources=[];
-
-for(const record of insecureRecords){
-const simpleUrl=this.simplifyURL(record.url);
-if(seen.has(simpleUrl))continue;
-seen.add(simpleUrl);
-
-const resource={
-host:new URL(record.url).hostname,
-fullUrl:record.url,
-referrerDocUrl:this.displayURL(record.documentURL)};
-
-
-if(!upgradePassSecureHosts.has(resource.host))continue;
-
-if(!resource.referrerDocUrl.includes(baseHostname))continue;
-
-upgradeableResources.push(resource);
-}
-
-const displayValue=`${Util.formatNumber(upgradeableResources.length)}
- ${upgradeableResources.length===1?'request':'requests'}`;
-
-const headings=[
-{key:'fullUrl',itemType:'url',text:'URL'}];
-
-const details=Audit.makeTableDetails(headings,upgradeableResources);
-
-const totalRecords=defaultRecords.length;
-const score=(secureRecords.length+0.5*upgradeableResources.length)/totalRecords;
-
-return{
-rawValue:upgradeableResources.length===0,
-score,
-displayValue:displayValue,
-details};
-
-});
-}}
-
-
-module.exports=MixedContent;
-
-},{"../lib/url-shim":"url","../report/html/renderer/util":97,"./audit":2}],"../audits/network-requests":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const URL=require('../lib/url-shim');
-
-class NetworkRequests extends Audit{
-
-
-
-static get meta(){
-return{
-id:'network-requests',
-scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
-title:'Network Requests',
-description:'Lists the network requests that were made during page load.',
-requiredArtifacts:['devtoolsLogs']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLog).then(records=>{
-const earliestStartTime=records.reduce(
-(min,record)=>Math.min(min,record.startTime),
-Infinity);
-
-
-
-const timeToMs=time=>time<earliestStartTime||!Number.isFinite(time)?
-undefined:(time-earliestStartTime)*1000;
-
-const results=records.map(record=>{
-return{
-url:URL.elideDataURI(record.url),
-startTime:timeToMs(record.startTime),
-endTime:timeToMs(record.endTime),
-transferSize:record.transferSize,
-statusCode:record.statusCode,
-mimeType:record.mimeType,
-resourceType:record.resourceType};
-
-});
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'startTime',itemType:'ms',granularity:1,text:'Start Time'},
-{key:'endTime',itemType:'ms',granularity:1,text:'End Time'},
-{
-key:'transferSize',
-itemType:'bytes',
-displayUnit:'kb',
-granularity:1,
-text:'Transfer Size'},
-
-{key:'statusCode',itemType:'text',text:'Status Code'},
-{key:'mimeType',itemType:'text',text:'MIME Type'},
-{key:'resourceType',itemType:'text',text:'Resource Type'}];
-
-
-const tableDetails=Audit.makeTableDetails(headings,results);
-
-return{
-score:1,
-rawValue:results.length,
-details:tableDetails};
-
-});
-}}
-
-
-module.exports=NetworkRequests;
-
-},{"../lib/url-shim":"url","./audit":2}],"../audits/predictive-perf":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const Util=require('../report/html/renderer/util');
-
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=1700;
-const SCORING_MEDIAN=10000;
-
-class PredictivePerf extends Audit{
-
-
-
-static get meta(){
-return{
-id:'predictive-perf',
-title:'Predicted Performance (beta)',
-description:
-'Predicted performance evaluates how your site will perform under '+
-'a 3G connection on a mobile device.',
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-
-static async audit(artifacts){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-
-
-const settings={};
-const fcp=await artifacts.requestLanternFirstContentfulPaint({trace,devtoolsLog,settings});
-const fmp=await artifacts.requestLanternFirstMeaningfulPaint({trace,devtoolsLog,settings});
-const tti=await artifacts.requestLanternInteractive({trace,devtoolsLog,settings});
-const ttfcpui=await artifacts.requestLanternFirstCPUIdle({trace,devtoolsLog,settings});
-const si=await artifacts.requestLanternSpeedIndex({trace,devtoolsLog,settings});
-const eil=await artifacts.requestLanternEstimatedInputLatency({trace,devtoolsLog,settings});
-
-const values={
-roughEstimateOfFCP:fcp.timing,
-optimisticFCP:fcp.optimisticEstimate.timeInMs,
-pessimisticFCP:fcp.pessimisticEstimate.timeInMs,
-
-roughEstimateOfFMP:fmp.timing,
-optimisticFMP:fmp.optimisticEstimate.timeInMs,
-pessimisticFMP:fmp.pessimisticEstimate.timeInMs,
-
-roughEstimateOfTTI:tti.timing,
-optimisticTTI:tti.optimisticEstimate.timeInMs,
-pessimisticTTI:tti.pessimisticEstimate.timeInMs,
-
-roughEstimateOfTTFCPUI:ttfcpui.timing,
-optimisticTTFCPUI:ttfcpui.optimisticEstimate.timeInMs,
-pessimisticTTFCPUI:ttfcpui.pessimisticEstimate.timeInMs,
-
-roughEstimateOfSI:si.timing,
-optimisticSI:si.optimisticEstimate.timeInMs,
-pessimisticSI:si.pessimisticEstimate.timeInMs,
-
-roughEstimateOfEIL:eil.timing,
-optimisticEIL:eil.optimisticEstimate.timeInMs,
-pessimisticEIL:eil.pessimisticEstimate.timeInMs};
-
-
-const score=Audit.computeLogNormalScore(
-values.roughEstimateOfTTI,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
-
-
-return{
-score,
-rawValue:values.roughEstimateOfTTI,
-displayValue:Util.formatMilliseconds(values.roughEstimateOfTTI),
-details:{items:[values]}};
-
-}}
-
-
-module.exports=PredictivePerf;
-
-},{"../report/html/renderer/util":97,"./audit":2}],"../audits/redirects-http":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-class RedirectsHTTP extends Audit{
-
-
-
-static get meta(){
-return{
-id:'redirects-http',
-title:'Redirects HTTP traffic to HTTPS',
-failureTitle:'Does not redirect HTTP traffic to HTTPS',
-description:'If you\'ve already set up HTTPS, make sure that you redirect all HTTP '+
-'traffic to HTTPS. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/http-redirects-to-https).',
-requiredArtifacts:['HTTPRedirect']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-return{
-rawValue:artifacts.HTTPRedirect.value};
-
-}}
-
-
-module.exports=RedirectsHTTP;
-
-},{"./audit":2}],"../audits/redirects":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Avoid multiple page redirects',
-
-description:'Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class Redirects extends Audit{
-
-
-
-static get meta(){
-return{
-id:'redirects',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['URL','devtoolsLogs','traces']};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const settings=context.settings;
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-
-const traceOfTab=await artifacts.requestTraceOfTab(trace);
-const networkRecords=await artifacts.requestNetworkRecords(devtoolsLog);
-const mainResource=await artifacts.requestMainResource({URL:artifacts.URL,devtoolsLog});
-
-const metricComputationData={trace,devtoolsLog,traceOfTab,networkRecords,settings};
-const metricResult=await artifacts.requestLanternInteractive(metricComputationData);
-
-
-const nodeTimingsByUrl=new Map();
-for(const[node,timing]of metricResult.pessimisticEstimate.nodeTimings.entries()){
-if(node.type==='network'){
-const networkNode=node;
-nodeTimingsByUrl.set(networkNode.record.url,timing);
-}
-}
-
-
-const redirectRequests=Array.from(mainResource.redirects||[]);
-
-
-redirectRequests.push(mainResource);
-
-let totalWastedMs=0;
-const pageRedirects=[];
-
-
-if(redirectRequests.length>1){
-pageRedirects.push({
-url:`(Initial: ${redirectRequests[0].url})`,
-wastedMs:0});
-
-}
-
-for(let i=1;i<redirectRequests.length;i++){
-const initialRequest=redirectRequests[i-1];
-const redirectedRequest=redirectRequests[i];
-
-const initialTiming=nodeTimingsByUrl.get(initialRequest.url);
-const redirectedTiming=nodeTimingsByUrl.get(redirectedRequest.url);
-if(!initialTiming||!redirectedTiming){
-throw new Error('Could not find redirects in graph');
-}
-
-const wastedMs=redirectedTiming.startTime-initialTiming.startTime;
-totalWastedMs+=wastedMs;
-
-pageRedirects.push({
-url:redirectedRequest.url,
-wastedMs});
-
-}
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnTimeSpent)}];
-
-const details=Audit.makeOpportunityDetails(headings,pageRedirects,totalWastedMs);
-
-return{
-
-score:redirectRequests.length<=2?1:UnusedBytes.scoreForWastedMs(totalWastedMs),
-rawValue:totalWastedMs,
-displayValue:totalWastedMs?
-str_(i18n.UIStrings.displayValueMsSavings,{wastedMs:totalWastedMs}):
-'',
-extendedInfo:{
-value:{
-wastedMs:totalWastedMs}},
-
-
-details};
-
-}}
-
-
-module.exports=Redirects;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/redirects.js");
-},{"../lib/i18n/i18n.js":36,"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/screenshot-thumbnails":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const LHError=require('../lib/lh-error');
-const jpeg=require('jpeg-js');
-
-const NUMBER_OF_THUMBNAILS=10;
-const THUMBNAIL_WIDTH=120;
-
-
-
-class ScreenshotThumbnails extends Audit{
-
-
-
-static get meta(){
-return{
-id:'screenshot-thumbnails',
-scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
-title:'Screenshot Thumbnails',
-description:'This is what the load of your site looked like.',
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-
-
-
-
-static scaleImageToThumbnail(imageData){
-const scaledWidth=THUMBNAIL_WIDTH;
-const scaleFactor=imageData.width/scaledWidth;
-const scaledHeight=Math.floor(imageData.height/scaleFactor);
-
-const outPixels=new Uint8Array(scaledWidth*scaledHeight*4);
-
-for(let i=0;i<scaledWidth;i++){
-for(let j=0;j<scaledHeight;j++){
-const origX=Math.floor(i*scaleFactor);
-const origY=Math.floor(j*scaleFactor);
-
-const origPos=(origY*imageData.width+origX)*4;
-const outPos=(j*scaledWidth+i)*4;
-
-outPixels[outPos]=imageData.data[origPos];
-outPixels[outPos+1]=imageData.data[origPos+1];
-outPixels[outPos+2]=imageData.data[origPos+2];
-outPixels[outPos+3]=imageData.data[origPos+3];
-}
-}
-
-return{
-width:scaledWidth,
-height:scaledHeight,
-data:outPixels};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-
-const cachedThumbnails=new Map();
-
-const speedline=await artifacts.requestSpeedline(trace);
-
-
-let minimumTimelineDuration=context.options.minimumTimelineDuration||3000;
-
-if(context.settings.throttlingMethod!=='simulate'){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const metricComputationData={trace,devtoolsLog,settings:context.settings};
-const tti=artifacts.requestInteractive(metricComputationData);
-try{
-minimumTimelineDuration=Math.max((await tti).timing,minimumTimelineDuration);
-}catch(_){}
-}
-
-const thumbnails=[];
-const analyzedFrames=speedline.frames.filter(frame=>!frame.isProgressInterpolated());
-const maxFrameTime=
-speedline.complete||
-Math.max(...speedline.frames.map(frame=>frame.getTimeStamp()-speedline.beginning));
-const timelineEnd=Math.max(maxFrameTime,minimumTimelineDuration);
-
-if(!analyzedFrames.length||!Number.isFinite(timelineEnd)){
-throw new LHError(LHError.errors.INVALID_SPEEDLINE);
-}
-
-for(let i=1;i<=NUMBER_OF_THUMBNAILS;i++){
-const targetTimestamp=speedline.beginning+timelineEnd*i/NUMBER_OF_THUMBNAILS;
-
-
-
-let frameForTimestamp=null;
-if(i===NUMBER_OF_THUMBNAILS){
-frameForTimestamp=analyzedFrames[analyzedFrames.length-1];
-}else{
-analyzedFrames.forEach(frame=>{
-if(frame.getTimeStamp()<=targetTimestamp){
-frameForTimestamp=frame;
-}
-});
-}
-let base64Data;
-if(cachedThumbnails.has(frameForTimestamp)){
-base64Data=cachedThumbnails.get(frameForTimestamp);
-}else{
-const imageData=frameForTimestamp.getParsedImage();
-const thumbnailImageData=ScreenshotThumbnails.scaleImageToThumbnail(imageData);
-base64Data=jpeg.encode(thumbnailImageData,90).data.toString('base64');
-cachedThumbnails.set(frameForTimestamp,base64Data);
-}
-thumbnails.push({
-timing:Math.round(targetTimestamp-speedline.beginning),
-timestamp:targetTimestamp*1000,
-data:base64Data});
-
-}
-
-return{
-score:1,
-rawValue:thumbnails.length>0,
-details:{
-type:'filmstrip',
-scale:timelineEnd,
-items:thumbnails}};
-
-
-}}
-
-
-module.exports=ScreenshotThumbnails;
-
-},{"../lib/lh-error":85,"./audit":2,"jpeg-js":175}],"../audits/seo/canonical":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const LinkHeader=require('http-link-header');
-const URL=require('../../lib/url-shim');
-const LINK_HEADER='link';
-
-
-
-
-
-function getCanonicalLinksFromHeader(headerValue){
-const linkHeader=LinkHeader.parse(headerValue);
-
-return linkHeader.get('rel','canonical').map(c=>c.uri);
-}
-
-
-
-
-
-function getHreflangsFromHeader(headerValue){
-const linkHeader=LinkHeader.parse(headerValue);
-
-return linkHeader.get('rel','alternate').map(h=>h.uri);
-}
-
-
-
-
-
-
-function isValidRelativeOrAbsoluteURL(url){
-try{
-new URL(url,'https://example.com/');
-return true;
-}catch(e){
-return false;
-}
-}
-
-
-
-
-
-
-
-function getPrimaryDomain(url){
-return url.hostname.split('.').slice(-2).join('.');
-}
-
-class Canonical extends Audit{
-
-
-
-static get meta(){
-return{
-id:'canonical',
-title:'Document has a valid `rel=canonical`',
-failureTitle:'Document does not have a valid `rel=canonical`',
-description:'Canonical links suggest which URL to show in search results. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/canonical).',
-requiredArtifacts:['Canonical','Hreflang','URL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-
-return artifacts.requestMainResource({devtoolsLog,URL:artifacts.URL}).
-then(mainResource=>{
-const baseURL=new URL(mainResource.url);
-
-let canonicals=[];
-
-let hreflangs=[];
-
-mainResource.responseHeaders&&mainResource.responseHeaders.
-filter(h=>h.name.toLowerCase()===LINK_HEADER).
-forEach(h=>{
-canonicals=canonicals.concat(getCanonicalLinksFromHeader(h.value));
-hreflangs=hreflangs.concat(getHreflangsFromHeader(h.value));
-});
-
-for(const canonical of artifacts.Canonical){
-if(canonical!==null){
-canonicals.push(canonical);
-}
-}
-
-
-canonicals=Array.from(new Set(canonicals));
-
-artifacts.Hreflang.forEach(({href})=>hreflangs.push(href));
-
-hreflangs=hreflangs.
-filter(href=>isValidRelativeOrAbsoluteURL(href)).
-map(href=>new URL(href,baseURL).href);
-
-if(canonicals.length===0){
-return{
-rawValue:true,
-notApplicable:true};
-
-}
-
-if(canonicals.length>1){
-return{
-rawValue:false,
-explanation:`Multiple conflicting URLs (${canonicals.join(', ')})`};
-
-}
-
-const canonical=canonicals[0];
-
-if(!isValidRelativeOrAbsoluteURL(canonical)){
-return{
-rawValue:false,
-explanation:`Invalid URL (${canonical})`};
-
-}
-
-if(!URL.isValid(canonical)){
-return{
-rawValue:false,
-explanation:`Relative URL (${canonical})`};
-
-}
-
-const canonicalURL=new URL(canonical);
-
-
-if(hreflangs.includes(baseURL.href)&&hreflangs.includes(canonicalURL.href)&&
-baseURL.href!==canonicalURL.href){
-return{
-rawValue:false,
-explanation:`Points to another hreflang location (${baseURL.href})`};
-
-}
-
-
-
-if(getPrimaryDomain(canonicalURL)!==getPrimaryDomain(baseURL)){
-return{
-rawValue:false,
-explanation:`Points to a different domain (${canonicalURL})`};
-
-}
-
-
-if(canonicalURL.origin===baseURL.origin&&
-canonicalURL.pathname==='/'&&baseURL.pathname!=='/'){
-return{
-rawValue:false,
-explanation:'Points to a root of the same origin'};
-
-}
-
-return{
-rawValue:true};
-
-});
-}}
-
-
-module.exports=Canonical;
-
-},{"../../lib/url-shim":"url","../audit":2,"http-link-header":163}],"../audits/seo/font-size":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-const URL=require('../../lib/url-shim');
-const Audit=require('../audit');
-const ViewportAudit=require('../viewport');
-const MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT=60;
-
-
-
-
-
-function getUniqueFailingRules(fontSizeArtifact){
-
-const failingRules=new Map();
-
-fontSizeArtifact.forEach(({cssRule,fontSize,textLength,node})=>{
-const artifactId=getFontArtifactId(cssRule,node);
-const failingRule=failingRules.get(artifactId);
-
-if(!failingRule){
-failingRules.set(artifactId,{
-node,
-cssRule,
-fontSize,
-textLength});
-
-}else{
-failingRule.textLength+=textLength;
-}
-});
-
-return[...failingRules.values()];
-}
-
-
-
-
-
-function getAttributeMap(attributes=[]){
-const map=new Map();
-
-for(let i=0;i<attributes.length;i+=2){
-const name=attributes[i].toLowerCase();
-const value=attributes[i+1].trim();
-
-if(value){
-map.set(name,value);
-}
-}
-
-return map;
-}
-
-
-
-
-
-
-function getSelector(node){
-const attributeMap=getAttributeMap(node.attributes);
-
-if(attributeMap.has('id')){
-return'#'+attributeMap.get('id');
-}else{
-const attrClass=attributeMap.get('class');
-if(attrClass){
-return'.'+attrClass.split(/\s+/).join('.');
-}
-}
-
-return node.localName.toLowerCase();
-}
-
-
-
-
-
-function nodeToTableNode(node){
-const attributes=node.attributes||[];
-const attributesString=attributes.map((value,idx)=>
-idx%2===0?` ${value}`:`="${value}"`).
-join('');
-
-return{
-type:'node',
-selector:node.parentNode?getSelector(node.parentNode):'',
-snippet:`<${node.localName}${attributesString}>`};
-
-}
-
-
-
-
-
-
-
-function findStyleRuleSource(baseURL,styleDeclaration,node){
-if(
-!styleDeclaration||
-styleDeclaration.type==='Attributes'||
-styleDeclaration.type==='Inline')
-{
-return{
-selector:nodeToTableNode(node),
-source:baseURL};
-
-}
-
-if(styleDeclaration.parentRule&&
-styleDeclaration.parentRule.origin==='user-agent'){
-return{
-selector:styleDeclaration.parentRule.selectors.map(item=>item.text).join(', '),
-source:'User Agent Stylesheet'};
-
-}
-
-if(styleDeclaration.type==='Regular'&&styleDeclaration.parentRule){
-const rule=styleDeclaration.parentRule;
-const stylesheet=styleDeclaration.stylesheet;
-
-if(stylesheet){
-let source;
-const selector=rule.selectors.map(item=>item.text).join(', ');
-
-if(stylesheet.sourceURL){
-const url=new URL(stylesheet.sourceURL,baseURL);
-const range=styleDeclaration.range;
-source=`${url.href}`;
-
-if(range){
-
-
-const absoluteStartLine=range.startLine+stylesheet.startLine+1;
-const absoluteStartColumn=range.startColumn+stylesheet.startColumn+1;
-
-source+=`:${absoluteStartLine}:${absoluteStartColumn}`;
-}
-}else{
-
-source='dynamic';
-}
-
-return{
-selector,
-source};
-
-}
-}
-
-return{
-selector:'',
-source:'Unknown'};
-
-}
-
-
-
-
-
-
-function getFontArtifactId(styleDeclaration,node){
-if(styleDeclaration&&styleDeclaration.type==='Regular'){
-const startLine=styleDeclaration.range?styleDeclaration.range.startLine:0;
-const startColumn=styleDeclaration.range?styleDeclaration.range.startColumn:0;
-return`${styleDeclaration.styleSheetId}@${startLine}:${startColumn}`;
-}else{
-return`node_${node.nodeId}`;
-}
-}
-
-class FontSize extends Audit{
-
-
-
-static get meta(){
-return{
-id:'font-size',
-title:'Document uses legible font sizes',
-failureTitle:'Document doesn\'t use legible font sizes',
-description:'Font sizes less than 12px are too small to be legible and require mobile '+
-'visitors to “pinch to zoom” in order to read. Strive to have >60% of page text ≥12px. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/font-sizes).',
-requiredArtifacts:['FontSize','URL','Viewport']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const hasViewportSet=ViewportAudit.audit(artifacts).rawValue;
-if(!hasViewportSet){
-return{
-rawValue:false,
-explanation:'Text is illegible because of a missing viewport config'};
-
-}
-
-const{
-analyzedFailingNodesData,
-analyzedFailingTextLength,
-failingTextLength,
-visitedTextLength,
-totalTextLength}=
-artifacts.FontSize;
-
-if(totalTextLength===0){
-return{
-rawValue:true};
-
-}
-
-const failingRules=getUniqueFailingRules(analyzedFailingNodesData);
-const percentageOfPassingText=
-(visitedTextLength-failingTextLength)/visitedTextLength*100;
-const pageUrl=artifacts.URL.finalUrl;
-
-const headings=[
-{key:'source',itemType:'url',text:'Source'},
-{key:'selector',itemType:'code',text:'Selector'},
-{key:'coverage',itemType:'text',text:'% of Page Text'},
-{key:'fontSize',itemType:'text',text:'Font Size'}];
-
-
-const tableData=failingRules.sort((a,b)=>b.textLength-a.textLength).
-map(({cssRule,textLength,fontSize,node})=>{
-const percentageOfAffectedText=textLength/visitedTextLength*100;
-const origin=findStyleRuleSource(pageUrl,cssRule,node);
-
-return{
-source:origin.source,
-selector:origin.selector,
-coverage:`${percentageOfAffectedText.toFixed(2)}%`,
-fontSize:`${fontSize}px`};
-
-});
-
-
-if(analyzedFailingTextLength<failingTextLength){
-const percentageOfUnanalyzedFailingText=
-(failingTextLength-analyzedFailingTextLength)/visitedTextLength*100;
-
-tableData.push({
-source:'Add\'l illegible text',
-selector:'',
-coverage:`${percentageOfUnanalyzedFailingText.toFixed(2)}%`,
-fontSize:'< 12px'});
-
-}
-
-if(percentageOfPassingText>0){
-tableData.push({
-source:'Legible text',
-selector:'',
-coverage:`${percentageOfPassingText.toFixed(2)}%`,
-fontSize:'≥ 12px'});
-
-}
-
-
-const displayValue=['%.1d% legible text',percentageOfPassingText];
-const details=Audit.makeTableDetails(headings,tableData);
-const passed=percentageOfPassingText>=MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT;
-
-let explanation;
-if(!passed){
-const percentageOfFailingText=parseFloat((100-percentageOfPassingText).toFixed(2));
-let disclaimer='';
-
-
-if(visitedTextLength<totalTextLength){
-const percentageOfVisitedText=visitedTextLength/totalTextLength*100;
-disclaimer=` (based on ${percentageOfVisitedText.toFixed()}% sample)`;
-}
-
-explanation=`${percentageOfFailingText}% of text is too small${disclaimer}.`;
-}
-
-return{
-rawValue:passed,
-details,
-displayValue,
-explanation};
-
-}}
-
-
-module.exports=FontSize;
-
-},{"../../lib/url-shim":"url","../audit":2,"../viewport":"../audits/viewport"}],"../audits/seo/hreflang":[function(require,module,exports){
-(function(global){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const LinkHeader=require('http-link-header');
-const VALID_LANGS=importValidLangs();
-const LINK_HEADER='link';
-const NO_LANGUAGE='x-default';
-
-
-
-
-
-
-
-function importValidLangs(){
-
-const axeCache=global.axe;
-
-global.axe={utils:{}};
-
-require('axe-core/lib/commons/utils/valid-langs.js');
-
-const validLangs=global.axe.utils.validLangs();
-
-global.axe=axeCache;
-
-return validLangs;
-}
-
-
-
-
-
-function isValidHreflang(hreflang){
-if(hreflang.toLowerCase()===NO_LANGUAGE){
-return true;
-}
-
-
-const[lang]=hreflang.split('-');
-return VALID_LANGS.includes(lang.toLowerCase());
-}
-
-
-
-
-
-function headerHasValidHreflangs(headerValue){
-const linkHeader=LinkHeader.parse(headerValue);
-
-return linkHeader.get('rel','alternate').
-every(link=>!!link.hreflang&&isValidHreflang(link.hreflang));
-}
-
-class Hreflang extends Audit{
-
-
-
-static get meta(){
-return{
-id:'hreflang',
-title:'Document has a valid `hreflang`',
-failureTitle:'Document doesn\'t have a valid `hreflang`',
-description:'hreflang links tell search engines what version of a page they should '+
-'list in search results for a given language or region. [Learn more]'+
-'(https://developers.google.com/web/tools/lighthouse/audits/hreflang).',
-requiredArtifacts:['Hreflang','URL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const URL=artifacts.URL;
-
-return artifacts.requestMainResource({devtoolsLog,URL}).
-then(mainResource=>{
-
-const invalidHreflangs=[];
-
-if(artifacts.Hreflang){
-artifacts.Hreflang.forEach(({href,hreflang})=>{
-if(!isValidHreflang(hreflang)){
-invalidHreflangs.push({
-source:{
-type:'node',
-snippet:`<link name="alternate" hreflang="${hreflang}" href="${href}" />`}});
-
-
-}
-});
-}
-
-mainResource.responseHeaders&&mainResource.responseHeaders.
-filter(h=>h.name.toLowerCase()===LINK_HEADER&&!headerHasValidHreflangs(h.value)).
-forEach(h=>invalidHreflangs.push({source:`${h.name}: ${h.value}`}));
-
-const headings=[
-{key:'source',itemType:'code',text:'Source'}];
-
-const details=Audit.makeTableDetails(headings,invalidHreflangs);
-
-return{
-rawValue:invalidHreflangs.length===0,
-details};
-
-});
-}}
-
-
-module.exports=Hreflang;
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"../audit":2,"axe-core/lib/commons/utils/valid-langs.js":152,"http-link-header":163}],"../audits/seo/http-status-code":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const HTTP_UNSUCCESSFUL_CODE_LOW=400;
-const HTTP_UNSUCCESSFUL_CODE_HIGH=599;
-
-class HTTPStatusCode extends Audit{
-
-
-
-static get meta(){
-return{
-id:'http-status-code',
-title:'Page has successful HTTP status code',
-failureTitle:'Page has unsuccessful HTTP status code',
-description:'Pages with unsuccessful HTTP status codes may not be indexed properly. '+
-'[Learn more]'+
-'(https://developers.google.com/web/tools/lighthouse/audits/successful-http-code).',
-requiredArtifacts:['devtoolsLogs','URL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const URL=artifacts.URL;
-
-return artifacts.requestMainResource({devtoolsLog,URL}).
-then(mainResource=>{
-const statusCode=mainResource.statusCode;
-
-if(statusCode>=HTTP_UNSUCCESSFUL_CODE_LOW&&
-statusCode<=HTTP_UNSUCCESSFUL_CODE_HIGH){
-return{
-rawValue:false,
-displayValue:`${statusCode}`};
-
-}
-
-return{
-rawValue:true};
-
-});
-}}
-
-
-module.exports=HTTPStatusCode;
-
-},{"../audit":2}],"../audits/seo/is-crawlable":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const robotsParser=require('robots-parser');
-const URL=require('../../lib/url-shim');
-const BLOCKLIST=new Set([
-'noindex',
-'none']);
-
-const ROBOTS_HEADER='x-robots-tag';
-const UNAVAILABLE_AFTER='unavailable_after';
-
-
-
-
-
-
-function isUnavailable(directive){
-const parts=directive.split(':');
-
-if(parts.length<=1||parts[0]!==UNAVAILABLE_AFTER){
-return false;
-}
-
-const date=Date.parse(parts.slice(1).join(':'));
-
-return!isNaN(date)&&date<Date.now();
-}
-
-
-
-
-
-
-function hasBlockingDirective(directives){
-return directives.split(',').
-map(d=>d.toLowerCase().trim()).
-some(d=>BLOCKLIST.has(d)||isUnavailable(d));
-}
-
-
-
-
-
-
-function hasUserAgent(directives){
-const parts=directives.match(/^([^,:]+):/);
-
-
-
-return!!parts&&parts[1].toLowerCase()!==UNAVAILABLE_AFTER;
-}
-
-class IsCrawlable extends Audit{
-
-
-
-static get meta(){
-return{
-id:'is-crawlable',
-title:'Page isn’t blocked from indexing',
-failureTitle:'Page is blocked from indexing',
-description:'Search engines are unable to include your pages in search results '+
-'if they don\'t have permission to crawl them. [Learn '+
-'more](https://developers.google.com/web/tools/lighthouse/audits/indexing).',
-requiredArtifacts:['MetaRobots','RobotsTxt','URL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-
-return artifacts.requestMainResource({devtoolsLog,URL:artifacts.URL}).
-then(mainResource=>{
-
-const blockingDirectives=[];
-
-if(artifacts.MetaRobots){
-const isBlocking=hasBlockingDirective(artifacts.MetaRobots);
-
-if(isBlocking){
-blockingDirectives.push({
-source:{
-type:'node',
-snippet:`<meta name="robots" content="${artifacts.MetaRobots}" />`}});
-
-
-}
-}
-
-mainResource.responseHeaders&&mainResource.responseHeaders.
-filter(h=>h.name.toLowerCase()===ROBOTS_HEADER&&!hasUserAgent(h.value)&&
-hasBlockingDirective(h.value)).
-forEach(h=>blockingDirectives.push({source:`${h.name}: ${h.value}`}));
-
-if(artifacts.RobotsTxt.content){
-const robotsFileUrl=new URL('/robots.txt',mainResource.url);
-const robotsTxt=robotsParser(robotsFileUrl.href,artifacts.RobotsTxt.content);
-
-if(!robotsTxt.isAllowed(mainResource.url)){
-blockingDirectives.push({
-source:{
-type:'url',
-value:robotsFileUrl.href}});
-
-
-}
-}
-
-const headings=[
-{key:'source',itemType:'code',text:'Blocking Directive Source'}];
-
-const details=Audit.makeTableDetails(headings,blockingDirectives);
-
-return{
-rawValue:blockingDirectives.length===0,
-details};
-
-});
-}}
-
-
-module.exports=IsCrawlable;
-
-},{"../../lib/url-shim":"url","../audit":2,"robots-parser":183}],"../audits/seo/link-text":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const URL=require('../../lib/url-shim');
-const BLOCKLIST=new Set([
-'click here',
-'click this',
-'go',
-'here',
-'this',
-'start',
-'right here',
-'more',
-'learn more']);
-
-
-class LinkText extends Audit{
-
-
-
-static get meta(){
-return{
-id:'link-text',
-title:'Links have descriptive text',
-failureTitle:'Links do not have descriptive text',
-description:'Descriptive link text helps search engines understand your content. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/descriptive-link-text).',
-requiredArtifacts:['URL','CrawlableLinks']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const failingLinks=artifacts.CrawlableLinks.
-filter(link=>{
-if(
-link.href.toLowerCase().startsWith('javascript:')||
-URL.equalWithExcludedFragments(link.href,artifacts.URL.finalUrl))
-{
-return false;
-}
-
-return BLOCKLIST.has(link.text.trim().toLowerCase());
-});
-
-const headings=[
-{key:'href',itemType:'url',text:'Link destination'},
-{key:'text',itemType:'text',text:'Link Text'}];
-
-
-const details=Audit.makeTableDetails(headings,failingLinks,{});
-let displayValue;
-
-if(failingLinks.length){
-displayValue=failingLinks.length>1?
-`${failingLinks.length} links found`:'1 link found';
-}
-
-return{
-rawValue:failingLinks.length===0,
-details,
-displayValue};
-
-}}
-
-
-module.exports=LinkText;
-
-},{"../../lib/url-shim":"url","../audit":2}],"../audits/seo/manual/mobile-friendly":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class MobileFriendly extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'mobile-friendly',
-description:'Take the [Mobile-Friendly Test](https://search.google.com/test/mobile-friendly) to check for audits not covered by Lighthouse, like sizing tap targets appropriately. [Learn more](https://developers.google.com/search/mobile-sites/).',
-title:'Page is mobile friendly'},
-super.partialMeta);
-}}
-
-
-module.exports=MobileFriendly;
-
-},{"../../manual/manual-audit":4}],"../audits/seo/manual/structured-data":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ManualAudit=require('../../manual/manual-audit');
-
-
-
-
-
-class StructuredData extends ManualAudit{
-
-
-
-static get meta(){
-return Object.assign({
-id:'structured-data',
-description:'Run the [Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/) and the [Structured Data Linter](http://linter.structured-data.org/) to validate structured data. [Learn more](https://developers.google.com/search/docs/guides/mark-up-content).',
-title:'Structured data is valid'},
-super.partialMeta);
-}}
-
-
-module.exports=StructuredData;
-
-},{"../../manual/manual-audit":4}],"../audits/seo/meta-description":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-
-class Description extends Audit{
-
-
-
-static get meta(){
-return{
-id:'meta-description',
-title:'Document has a meta description',
-failureTitle:'Document does not have a meta description',
-description:'Meta descriptions may be included in search results to concisely summarize '+
-'page content. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/description).',
-requiredArtifacts:['MetaDescription']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-if(artifacts.MetaDescription===null){
-return{
-rawValue:false};
-
-}
-
-if(artifacts.MetaDescription.trim().length===0){
-return{
-rawValue:false,
-explanation:'Description text is empty.'};
-
-}
-
-return{
-rawValue:true};
-
-}}
-
-
-module.exports=Description;
-
-},{"../audit":2}],"../audits/seo/plugins":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const URL=require('../../lib/url-shim');
-
-const JAVA_APPLET_TYPE='application/x-java-applet';
-const JAVA_BEAN_TYPE='application/x-java-bean';
-const TYPE_BLOCKLIST=new Set([
-'application/x-shockwave-flash',
-
-JAVA_APPLET_TYPE,
-JAVA_BEAN_TYPE,
-
-'application/x-silverlight',
-'application/x-silverlight-2']);
-
-const FILE_EXTENSION_BLOCKLIST=new Set([
-'swf',
-'flv',
-'class',
-'xap']);
-
-const SOURCE_PARAMS=new Set([
-'code',
-'movie',
-'source',
-'src']);
-
-
-
-
-
-
-
-function isPluginType(type){
-type=type.trim().toLowerCase();
-
-return TYPE_BLOCKLIST.has(type)||
-type.startsWith(JAVA_APPLET_TYPE)||
-type.startsWith(JAVA_BEAN_TYPE);
-}
-
-
-
-
-
-
-function isPluginURL(url){
-try{
-
-const filePath=new URL(url,'http://example.com').pathname;
-const parts=filePath.split('.');
-
-if(parts.length<2){
-return false;
-}
-const part=parts.pop();
-return FILE_EXTENSION_BLOCKLIST.has(part.trim().toLowerCase());
-}catch(e){
-return false;
-}
-}
-
-class Plugins extends Audit{
-
-
-
-static get meta(){
-return{
-id:'plugins',
-title:'Document avoids plugins',
-failureTitle:'Document uses plugins',
-description:'Search engines can\'t index plugin content, and '+
-'many devices restrict plugins or don\'t support them. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/plugins).',
-requiredArtifacts:['EmbeddedContent']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const plugins=artifacts.EmbeddedContent.
-filter(item=>{
-if(item.tagName==='APPLET'){
-return true;
-}
-
-if(
-(item.tagName==='EMBED'||item.tagName==='OBJECT')&&
-item.type&&
-isPluginType(item.type))
-{
-return true;
-}
-
-const embedSrc=item.src||item.code;
-if(item.tagName==='EMBED'&&embedSrc&&isPluginURL(embedSrc)){
-return true;
-}
-
-if(item.tagName==='OBJECT'&&item.data&&isPluginURL(item.data)){
-return true;
-}
-
-const failingParams=item.params.filter(param=>
-SOURCE_PARAMS.has(param.name.trim().toLowerCase())&&isPluginURL(param.value));
-
-
-return failingParams.length>0;
-}).
-map(plugin=>{
-const tagName=plugin.tagName.toLowerCase();
-
-const attributeKeys=['src','data','code','type'];
-const attributes=attributeKeys.
-reduce((result,attr)=>{
-if(plugin[attr]!==null){
-result+=` ${attr}="${plugin[attr]}"`;
-}
-return result;
-},'');
-const params=plugin.params.
-filter(param=>SOURCE_PARAMS.has(param.name.trim().toLowerCase())).
-map(param=>`<param ${param.name}="${param.value}" />`).
-join('');
-
-return{
-source:{
-type:'node',
-snippet:`<${tagName}${attributes}>${params}</${tagName}>`}};
-
-
-});
-
-const headings=[
-{key:'source',itemType:'code',text:'Element source'}];
-
-
-const details=Audit.makeTableDetails(headings,plugins);
-
-return{
-rawValue:plugins.length===0,
-details};
-
-}}
-
-
-module.exports=Plugins;
-
-},{"../../lib/url-shim":"url","../audit":2}],"../audits/seo/robots-txt":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-const Audit=require('../audit');
-const URL=require('../../lib/url-shim');
-
-const HTTP_CLIENT_ERROR_CODE_LOW=400;
-const HTTP_SERVER_ERROR_CODE_LOW=500;
-
-const DIRECTIVE_SITEMAP='sitemap';
-const DIRECTIVE_USER_AGENT='user-agent';
-const DIRECTIVE_ALLOW='allow';
-const DIRECTIVE_DISALLOW='disallow';
-const DIRECTIVES_GROUP_MEMBERS=new Set([DIRECTIVE_ALLOW,DIRECTIVE_DISALLOW]);
-const DIRECTIVE_SAFELIST=new Set([
-DIRECTIVE_USER_AGENT,DIRECTIVE_DISALLOW,
-DIRECTIVE_ALLOW,DIRECTIVE_SITEMAP,
-'crawl-delay',
-'clean-param','host',
-'request-rate','visit-time','noindex']);
-
-const SITEMAP_VALID_PROTOCOLS=new Set(['https:','http:','ftp:']);
-
-
-
-
-
-
-function verifyDirective(directiveName,directiveValue){
-if(!DIRECTIVE_SAFELIST.has(directiveName)){
-throw new Error('Unknown directive');
-}
-
-if(directiveName===DIRECTIVE_SITEMAP){
-let sitemapUrl;
-
-try{
-sitemapUrl=new URL(directiveValue);
-}catch(e){
-throw new Error('Invalid sitemap URL');
-}
-
-if(!SITEMAP_VALID_PROTOCOLS.has(sitemapUrl.protocol)){
-throw new Error('Invalid sitemap URL protocol');
-}
-}
-
-if(directiveName===DIRECTIVE_USER_AGENT&&!directiveValue){
-throw new Error('No user-agent specified');
-}
-
-if(directiveName===DIRECTIVE_ALLOW||directiveName===DIRECTIVE_DISALLOW){
-if(directiveValue!==''&&directiveValue[0]!=='/'&&directiveValue[0]!=='*'){
-throw new Error('Pattern should either be empty, start with "/" or "*"');
-}
-
-const dollarIndex=directiveValue.indexOf('$');
-
-if(dollarIndex!==-1&&dollarIndex!==directiveValue.length-1){
-throw new Error('"$" should only be used at the end of the pattern');
-}
-}
-}
-
-
-
-
-
-
-function parseLine(line){
-const hashIndex=line.indexOf('#');
-
-if(hashIndex!==-1){
-line=line.substr(0,hashIndex);
-}
-
-line=line.trim();
-
-if(line.length===0){
-return null;
-}
-
-const colonIndex=line.indexOf(':');
-
-if(colonIndex===-1){
-throw new Error('Syntax not understood');
-}
-
-const directiveName=line.slice(0,colonIndex).trim().toLowerCase();
-const directiveValue=line.slice(colonIndex+1).trim();
-
-verifyDirective(directiveName,directiveValue);
-
-return{
-directive:directiveName,
-value:directiveValue};
-
-}
-
-
-
-
-
-function validateRobots(content){
-
-
-
-const errors=[];
-let inGroup=false;
-
-content.
-split(/\r\n|\r|\n/).
-forEach((line,index)=>{
-let parsedLine;
-
-try{
-parsedLine=parseLine(line);
-}catch(e){
-errors.push({
-index:(index+1).toString(),
-line:line,
-message:e.message.toString()});
-
-}
-
-if(!parsedLine){
-return;
-}
-
-
-
-if(parsedLine.directive===DIRECTIVE_USER_AGENT){
-inGroup=true;
-}else if(!inGroup&&DIRECTIVES_GROUP_MEMBERS.has(parsedLine.directive)){
-errors.push({
-index:(index+1).toString(),
-line:line,
-message:'No user-agent specified'});
-
-}
-});
-
-return errors;
-}
-
-class RobotsTxt extends Audit{
-
-
-
-static get meta(){
-return{
-id:'robots-txt',
-title:'robots.txt is valid',
-failureTitle:'robots.txt is not valid',
-description:'If your robots.txt file is malformed, crawlers may not be able to understand '+
-'how you want your website to be crawled or indexed.',
-requiredArtifacts:['RobotsTxt']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const{
-status,
-content}=
-artifacts.RobotsTxt;
-
-if(!status){
-return{
-rawValue:false,
-explanation:'Lighthouse was unable to download your robots.txt file'};
-
-}
-
-if(status>=HTTP_SERVER_ERROR_CODE_LOW){
-return{
-rawValue:false,
-displayValue:`request for robots.txt returned HTTP${status}`};
-
-}else if(status>=HTTP_CLIENT_ERROR_CODE_LOW||content===''){
-return{
-rawValue:true,
-notApplicable:true};
-
-}
-
-
-if(content===null){
-throw new Error(`Status ${status} was valid, but content was null`);
-}
-
-const validationErrors=validateRobots(content);
-
-const headings=[
-{key:'index',itemType:'text',text:'Line #'},
-{key:'line',itemType:'code',text:'Content'},
-{key:'message',itemType:'code',text:'Error'}];
-
-
-const details=Audit.makeTableDetails(headings,validationErrors,{});
-let displayValue;
-
-if(validationErrors.length){
-displayValue=validationErrors.length>1?
-`${validationErrors.length} errors found`:'1 error found';
-}
-
-return{
-rawValue:validationErrors.length===0,
-details,
-displayValue};
-
-}}
-
-
-module.exports=RobotsTxt;
-
-},{"../../lib/url-shim":"url","../audit":2}],"../audits/service-worker":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const URL=require('../lib/url-shim');
-const Audit=require('./audit');
-
-class ServiceWorker extends Audit{
-
-
-
-static get meta(){
-return{
-id:'service-worker',
-title:'Registers a service worker',
-failureTitle:'Does not register a service worker',
-description:'The service worker is the technology that enables your app to use many '+
-'Progressive Web App features, such as offline, add to homescreen, and push '+
-'notifications. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/registered-service-worker).',
-requiredArtifacts:['URL','ServiceWorker']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-
-
-const versions=artifacts.ServiceWorker.versions;
-const url=artifacts.URL.finalUrl;
-
-const origin=new URL(url).origin;
-const matchingSW=versions.filter(v=>v.status==='activated').
-find(v=>new URL(v.scriptURL).origin===origin);
-
-return{
-rawValue:!!matchingSW};
-
-}}
-
-
-module.exports=ServiceWorker;
-
-},{"../lib/url-shim":"url","./audit":2}],"../audits/splash-screen":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MultiCheckAudit=require('./multi-check-audit');
-const ManifestValues=require('../gather/computed/manifest-values');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class SplashScreen extends MultiCheckAudit{
-
-
-
-static get meta(){
-return{
-id:'splash-screen',
-title:'Configured for a custom splash screen',
-failureTitle:'Is not configured for a custom splash screen',
-description:'A themed splash screen ensures a high-quality experience when '+
-'users launch your app from their homescreens. [Learn '+
-'more](https://developers.google.com/web/tools/lighthouse/audits/custom-splash-screen).',
-requiredArtifacts:['Manifest']};
-
-}
-
-
-
-
-
-static assessManifest(manifestValues,failures){
-if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
-failures.push(manifestValues.parseFailureReason);
-return;
-}
-
-const splashScreenCheckIds=[
-'hasName',
-'hasBackgroundColor',
-'hasThemeColor',
-'hasIconsAtLeast512px'];
-
-
-manifestValues.allChecks.
-filter(item=>splashScreenCheckIds.includes(item.id)).
-forEach(item=>{
-if(!item.passing){
-failures.push(item.failureText);
-}
-});
-}
-
-
-
-
-
-
-static async audit_(artifacts,context){
-
-const failures=[];
-
-const manifestValues=await ManifestValues.request(context,artifacts.Manifest);
-SplashScreen.assessManifest(manifestValues,failures);
-
-return{
-failures,
-manifestValues};
-
-}}
-
-
-module.exports=SplashScreen;
-
-},{"../gather/computed/manifest-values":12,"./multi-check-audit":5}],"../audits/themed-omnibox":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MultiCheckAudit=require('./multi-check-audit');
-const ManifestValues=require('../gather/computed/manifest-values');
-const cssParsers=require('cssstyle/lib/parsers');
-
-
-
-
-
-
-
-
-
-
-
-class ThemedOmnibox extends MultiCheckAudit{
-
-
-
-static get meta(){
-return{
-id:'themed-omnibox',
-title:'Address bar matches brand colors',
-failureTitle:'Address bar does not match brand colors',
-description:'The browser address bar can be themed to match your site. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/address-bar).',
-requiredArtifacts:['Manifest','ThemeColor']};
-
-}
-
-
-
-
-
-static isValidColor(color){
-return cssParsers.valueType(color)===cssParsers.TYPES.COLOR;
-}
-
-
-
-
-
-static assessMetaThemecolor(themeColorMeta,failures){
-if(themeColorMeta===null){
-failures.push('No `<meta name="theme-color">` tag found');
-}else if(!ThemedOmnibox.isValidColor(themeColorMeta)){
-failures.push('The theme-color meta tag did not contain a valid CSS color');
-}
-}
-
-
-
-
-
-static assessManifest(manifestValues,failures){
-if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
-failures.push(manifestValues.parseFailureReason);
-return;
-}
-
-const themeColorCheck=manifestValues.allChecks.find(i=>i.id==='hasThemeColor');
-if(themeColorCheck&&!themeColorCheck.passing){
-failures.push(themeColorCheck.failureText);
-}
-}
-
-
-
-
-
-
-static async audit_(artifacts,context){
-
-const failures=[];
-
-const manifestValues=await ManifestValues.request(context,artifacts.Manifest);
-ThemedOmnibox.assessManifest(manifestValues,failures);
-ThemedOmnibox.assessMetaThemecolor(artifacts.ThemeColor,failures);
-
-return{
-failures,
-manifestValues,
-themeColor:artifacts.ThemeColor};
-
-}}
-
-
-module.exports=ThemedOmnibox;
-
-},{"../gather/computed/manifest-values":12,"./multi-check-audit":5,"cssstyle/lib/parsers":161}],"../audits/time-to-first-byte":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Server response times are low (TTFB)',
-
-failureTitle:'Reduce server response times (TTFB)',
-
-description:'Time To First Byte identifies the time at which your server sends a response.'+
-' [Learn more](https://developers.google.com/web/tools/lighthouse/audits/ttfb).',
-
-displayValue:`Root document took {timeInMs, number, milliseconds}\xa0ms`};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const TTFB_THRESHOLD=600;
-
-class TTFBMetric extends Audit{
-
-
-
-static get meta(){
-return{
-id:'time-to-first-byte',
-title:str_(UIStrings.title),
-failureTitle:str_(UIStrings.failureTitle),
-description:str_(UIStrings.description),
-requiredArtifacts:['devtoolsLogs','URL']};
-
-}
-
-
-
-
-static caclulateTTFB(record){
-const timing=record.timing;
-return timing?timing.receiveHeadersEnd-timing.sendEnd:0;
-}
-
-
-
-
-
-static async audit(artifacts){
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const mainResource=await artifacts.requestMainResource({devtoolsLog,URL:artifacts.URL});
-
-const ttfb=TTFBMetric.caclulateTTFB(mainResource);
-const passed=ttfb<TTFB_THRESHOLD;
-const displayValue=str_(UIStrings.displayValue,{timeInMs:ttfb});
-
-
-const details={
-type:'opportunity',
-overallSavingsMs:ttfb-TTFB_THRESHOLD,
-headings:[],
-items:[]};
-
-
-return{
-rawValue:ttfb,
-score:Number(passed),
-displayValue,
-details,
-extendedInfo:{
-value:{
-wastedMs:ttfb-TTFB_THRESHOLD}}};
-
-
-
-}}
-
-
-module.exports=TTFBMetric;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/time-to-first-byte.js");
-},{"../lib/i18n/i18n.js":36,"./audit":2}],"../audits/user-timings":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'User Timing marks and measures',
-
-description:'Consider instrumenting your app with the User Timing API to measure your '+
-'app\'s real-world performance during key user experiences. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/user-timing).',
-
-displayValue:`{itemCount, plural,
- =1 {1 user timing}
- other {# user timings}
- }`,
-
-columnName:'Name',
-
-columnType:'Type',
-
-columnStartTime:'Start Time',
-
-columnDuration:'Duration'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-
-
-class UserTimings extends Audit{
-
-
-
-static get meta(){
-return{
-id:'user-timings',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
-requiredArtifacts:['traces']};
-
-}
-
-
-
-
-
-static filterTrace(tabTrace){
-
-const userTimings=[];
-
-const measuresStartTimes={};
-
-
-
-
-
-tabTrace.processEvents.filter(evt=>{
-if(!evt.cat.includes('blink.user_timing')){
-return false;
-}
-
-
-
-return evt.name!=='requestStart'&&
-evt.name!=='navigationStart'&&
-evt.name!=='paintNonDefaultBackgroundColor'&&
-evt.args.frame===undefined;
-}).
-forEach(ut=>{
-
-if(ut.ph==='R'||ut.ph.toUpperCase()==='I'){
-userTimings.push({
-name:ut.name,
-isMark:true,
-args:ut.args,
-startTime:ut.ts});
-
-
-
-}else if(ut.ph.toLowerCase()==='b'){
-measuresStartTimes[ut.name]=ut.ts;
-
-
-}else if(ut.ph.toLowerCase()==='e'){
-userTimings.push({
-name:ut.name,
-isMark:false,
-args:ut.args,
-startTime:measuresStartTimes[ut.name],
-endTime:ut.ts,
-duration:ut.ts-measuresStartTimes[ut.name]});
-
-}
-});
-
-
-userTimings.forEach(ut=>{
-ut.startTime=(ut.startTime-tabTrace.navigationStartEvt.ts)/1000;
-if(!ut.isMark){
-ut.endTime=(ut.endTime-tabTrace.navigationStartEvt.ts)/1000;
-ut.duration=ut.duration/1000;
-}
-});
-
-return userTimings;
-}
-
-
-
-
-static get blacklistedPrefixes(){
-return['goog_'];
-}
-
-
-
-
-
-
-static excludeBlacklisted(evt){
-return UserTimings.blacklistedPrefixes.every(prefix=>!evt.name.startsWith(prefix));
-}
-
-
-
-
-
-static audit(artifacts){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-return artifacts.requestTraceOfTab(trace).then(tabTrace=>{
-const userTimings=this.filterTrace(tabTrace).filter(UserTimings.excludeBlacklisted);
-const tableRows=userTimings.map(item=>{
-return{
-name:item.name,
-startTime:item.startTime,
-duration:item.isMark?undefined:item.duration,
-timingType:item.isMark?'Mark':'Measure'};
-
-}).sort((itemA,itemB)=>{
-if(itemA.timingType===itemB.timingType){
-
-return itemA.startTime-itemB.startTime;
-}else if(itemA.timingType==='Measure'){
-
-return-1;
-}else{
-return 1;
-}
-});
-
-const headings=[
-{key:'name',itemType:'text',text:str_(UIStrings.columnName)},
-{key:'timingType',itemType:'text',text:str_(UIStrings.columnType)},
-{key:'startTime',itemType:'ms',granularity:0.01,
-text:str_(UIStrings.columnStartTime)},
-{key:'duration',itemType:'ms',granularity:0.01,text:str_(UIStrings.columnDuration)}];
-
-
-const details=Audit.makeTableDetails(headings,tableRows);
-
-
-let displayValue;
-if(userTimings.length){
-displayValue=str_(UIStrings.displayValue,{itemCount:userTimings.length});
-}
-
-return{
-
-rawValue:userTimings.length===0,
-notApplicable:userTimings.length===0,
-displayValue,
-extendedInfo:{
-value:userTimings},
-
-details};
-
-});
-}}
-
-
-module.exports=UserTimings;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/user-timings.js");
-},{"../lib/i18n/i18n.js":36,"./audit":2}],"../audits/uses-rel-preconnect":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
-const i18n=require('../lib/i18n/i18n.js');
-
-
-
-
-
-const PRECONNECT_SOCKET_MAX_IDLE=15;
-
-const IGNORE_THRESHOLD_IN_MS=50;
-
-const UIStrings={
-
-title:'Preconnect to required origins',
-
-description:
-'Consider adding preconnect or dns-prefetch resource hints to establish early '+
-`connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect).`};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-class UsesRelPreconnectAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'uses-rel-preconnect',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-requiredArtifacts:['devtoolsLogs','URL'],
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC};
-
-}
-
-
-
-
-
-
-static hasValidTiming(record){
-return!!record.timing&&record.timing.connectEnd>0&&record.timing.connectStart>0;
-}
-
-
-
-
-
-
-static hasAlreadyConnectedToOrigin(record){
-return(
-!!record.timing&&
-record.timing.dnsEnd-record.timing.dnsStart===0&&
-record.timing.connectEnd-record.timing.connectStart===0);
-
-}
-
-
-
-
-
-
-
-static socketStartTimeIsBelowThreshold(record,mainResource){
-return Math.max(0,record.startTime-mainResource.endTime)<PRECONNECT_SOCKET_MAX_IDLE;
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const devtoolsLog=artifacts.devtoolsLogs[UsesRelPreconnectAudit.DEFAULT_PASS];
-const URL=artifacts.URL;
-const settings=context.settings;
-let maxWasted=0;
-
-const[networkRecords,mainResource,loadSimulator]=await Promise.all([
-artifacts.requestNetworkRecords(devtoolsLog),
-artifacts.requestMainResource({devtoolsLog,URL}),
-artifacts.requestLoadSimulator({devtoolsLog,settings})]);
-
-
-const{rtt,additionalRttByOrigin}=loadSimulator.getOptions();
-
-
-const origins=new Map();
-networkRecords.
-forEach(record=>{
-if(
-
-!UsesRelPreconnectAudit.hasValidTiming(record)||
-
-record.initiator.url===mainResource.url||
-
-!record.parsedURL||!record.parsedURL.securityOrigin||
-
-mainResource.parsedURL.securityOrigin===record.parsedURL.securityOrigin||
-
-UsesRelPreconnectAudit.hasAlreadyConnectedToOrigin(record)||
-
-!UsesRelPreconnectAudit.socketStartTimeIsBelowThreshold(record,mainResource))
-{
-return;
-}
-
-const securityOrigin=record.parsedURL.securityOrigin;
-const records=origins.get(securityOrigin)||[];
-records.push(record);
-origins.set(securityOrigin,records);
-});
-
-
-let results=[];
-origins.forEach(records=>{
-
-
-const firstRecordOfOrigin=records.reduce((firstRecord,record)=>{
-return record.startTime<firstRecord.startTime?record:firstRecord;
-});
-
-
-if(!firstRecordOfOrigin.timing)return;
-
-const securityOrigin=firstRecordOfOrigin.parsedURL.securityOrigin;
-
-
-
-
-const additionalRtt=additionalRttByOrigin.get(securityOrigin)||0;
-let connectionTime=rtt+additionalRtt;
-
-if(firstRecordOfOrigin.parsedURL.scheme==='https')connectionTime=connectionTime*2;
-
-const timeBetweenMainResourceAndDnsStart=
-firstRecordOfOrigin.startTime*1000-
-mainResource.endTime*1000+
-firstRecordOfOrigin.timing.dnsStart;
-
-const wastedMs=Math.min(connectionTime,timeBetweenMainResourceAndDnsStart);
-if(wastedMs<IGNORE_THRESHOLD_IN_MS)return;
-
-maxWasted=Math.max(wastedMs,maxWasted);
-results.push({
-url:securityOrigin,
-wastedMs:wastedMs});
-
-});
-
-results=results.
-sort((a,b)=>b.wastedMs-a.wastedMs);
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnWastedMs)}];
-
-
-const details=Audit.makeOpportunityDetails(headings,results,maxWasted);
-
-return{
-score:UnusedBytes.scoreForWastedMs(maxWasted),
-rawValue:maxWasted,
-displayValue:maxWasted?
-str_(i18n.UIStrings.displayValueMsSavings,{wastedMs:maxWasted}):
-'',
-extendedInfo:{
-value:results},
-
-details};
-
-}}
-
-
-module.exports=UsesRelPreconnectAudit;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/uses-rel-preconnect.js");
-},{"../lib/i18n/i18n.js":36,"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/uses-rel-preload":[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const URL=require('../lib/url-shim');
-const Audit=require('./audit');
-const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
-const CriticalRequestChains=require('../gather/computed/critical-request-chains');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-title:'Preload key requests',
-
-description:'Consider using <link rel=preload> to prioritize fetching resources that are '+
-'currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-const THRESHOLD_IN_MS=100;
-
-class UsesRelPreloadAudit extends Audit{
-
-
-
-static get meta(){
-return{
-id:'uses-rel-preload',
-title:str_(UIStrings.title),
-description:str_(UIStrings.description),
-requiredArtifacts:['devtoolsLogs','traces','URL'],
-scoreDisplayMode:Audit.SCORING_MODES.NUMERIC};
-
-}
-
-
-
-
-
-
-static getURLsToPreload(mainResource,graph){
-
-const urls=new Set();
-
-graph.traverse((node,traversalPath)=>{
-if(node.type!=='network')return;
-
-const path=traversalPath.slice(1).filter(initiator=>initiator.type==='network');
-if(!UsesRelPreloadAudit.shouldPreloadRequest(node.record,mainResource,path))return;
-urls.add(node.record.url);
-});
-
-return urls;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-static shouldPreloadRequest(request,mainResource,initiatorPath){
-const mainResourceDepth=mainResource.redirects?mainResource.redirects.length:0;
-
-
-if(request.isLinkPreload)return false;
-
-if(!CriticalRequestChains.isCritical(request,mainResource))return false;
-
-if(URL.NON_NETWORK_PROTOCOLS.includes(request.protocol))return false;
-
-if(initiatorPath.length!==mainResourceDepth+2)return false;
-
-return URL.rootDomainsMatch(request.url,mainResource.url);
-}
-
-
-
-
-
-
-
-
-static computeWasteWithGraph(urls,graph,simulator){
-if(!urls.size){
-return{wastedMs:0,results:[]};
-}
-
-
-
-const simulationBeforeChanges=simulator.simulate(graph,{flexibleOrdering:true});
-const modifiedGraph=graph.cloneWithRelationships();
-
-
-const nodesToPreload=[];
-
-let mainDocumentNode=null;
-modifiedGraph.traverse(node=>{
-if(node.type!=='network')return;
-
-const networkNode=node;
-if(node.isMainDocument()){
-mainDocumentNode=networkNode;
-}else if(networkNode.record&&urls.has(networkNode.record.url)){
-nodesToPreload.push(networkNode);
-}
-});
-
-if(!mainDocumentNode){
-
-throw new Error('Could not find main document node');
-}
-
-
-
-for(const node of nodesToPreload){
-node.removeAllDependencies();
-node.addDependency(mainDocumentNode);
-}
-
-
-const simulationAfterChanges=simulator.simulate(modifiedGraph,{flexibleOrdering:true});
-const originalNodesByRecord=Array.from(simulationBeforeChanges.nodeTimings.keys()).
-
-reduce((map,node)=>map.set(node.record,node),new Map());
-
-const results=[];
-for(const node of nodesToPreload){
-const originalNode=originalNodesByRecord.get(node.record);
-const timingAfter=simulationAfterChanges.nodeTimings.get(node);
-const timingBefore=simulationBeforeChanges.nodeTimings.get(originalNode);
-if(!timingBefore||!timingAfter)throw new Error('Missing preload node');
-
-const wastedMs=Math.round(timingBefore.endTime-timingAfter.endTime);
-if(wastedMs<THRESHOLD_IN_MS)continue;
-results.push({url:node.record.url,wastedMs});
-}
-
-if(!results.length){
-return{wastedMs:0,results};
-}
-
-return{
-
-
-wastedMs:Math.max(...results.map(item=>item.wastedMs)),
-results};
-
-}
-
-
-
-
-
-
-static async audit(artifacts,context){
-const trace=artifacts.traces[UsesRelPreloadAudit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS];
-const URL=artifacts.URL;
-const simulatorOptions={trace,devtoolsLog,settings:context.settings};
-
-const[mainResource,graph,simulator]=await Promise.all([
-artifacts.requestMainResource({devtoolsLog,URL}),
-artifacts.requestPageDependencyGraph({trace,devtoolsLog}),
-artifacts.requestLoadSimulator(simulatorOptions)]);
-
-
-const urls=UsesRelPreloadAudit.getURLsToPreload(mainResource,graph);
-const{results,wastedMs}=UsesRelPreloadAudit.computeWasteWithGraph(urls,graph,simulator);
-
-results.sort((a,b)=>b.wastedMs-a.wastedMs);
-
-
-const headings=[
-{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
-{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnWastedMs)}];
-
-const details=Audit.makeOpportunityDetails(headings,results,wastedMs);
-
-return{
-score:UnusedBytes.scoreForWastedMs(wastedMs),
-rawValue:wastedMs,
-displayValue:wastedMs?
-str_(i18n.UIStrings.displayValueMsSavings,{wastedMs}):
-'',
-extendedInfo:{
-value:results},
-
-details};
-
-}}
-
-
-module.exports=UsesRelPreloadAudit;
-module.exports.UIStrings=UIStrings;
-
-}).call(this,"/../lighthouse-core/audits/uses-rel-preload.js");
-},{"../gather/computed/critical-request-chains":"./gather/computed/critical-request-chains","../lib/i18n/i18n.js":36,"../lib/url-shim":"url","./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/viewport":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const Parser=require('metaviewport-parser');
-
-class Viewport extends Audit{
-
-
-
-static get meta(){
-return{
-id:'viewport',
-title:'Has a `<meta name="viewport">` tag with `width` or `initial-scale`',
-failureTitle:'Does not have a `<meta name="viewport">` tag with `width` '+
-'or `initial-scale`',
-description:'Add a viewport meta tag to optimize your app for mobile screens. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/has-viewport-meta-tag).',
-requiredArtifacts:['Viewport']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-if(artifacts.Viewport===null){
-return{
-explanation:'No viewport meta tag found',
-rawValue:false};
-
-}
-
-const warnings=[];
-const parsedProps=Parser.parseMetaViewPortContent(artifacts.Viewport);
-
-if(Object.keys(parsedProps.unknownProperties).length){
-warnings.push(`Invalid properties found: ${JSON.stringify(parsedProps.unknownProperties)}`);
-}
-if(Object.keys(parsedProps.invalidValues).length){
-warnings.push(`Invalid values found: ${JSON.stringify(parsedProps.invalidValues)}`);
-}
-
-const viewportProps=parsedProps.validProperties;
-const hasMobileViewport=viewportProps.width||viewportProps['initial-scale'];
-
-return{
-rawValue:!!hasMobileViewport,
-warnings};
-
-}}
-
-
-module.exports=Viewport;
-
-},{"./audit":2,"metaviewport-parser":180}],"../audits/webapp-install-banner":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MultiCheckAudit=require('./multi-check-audit');
-const SWAudit=require('./service-worker');
-const ManifestValues=require('../gather/computed/manifest-values');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class WebappInstallBanner extends MultiCheckAudit{
-
-
-
-static get meta(){
-return{
-id:'webapp-install-banner',
-title:'User can be prompted to Install the Web App',
-failureTitle:'User will not be prompted to Install the Web App',
-description:'Browsers can proactively prompt users to add your app to their homescreen, '+
-'which can lead to higher engagement. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/install-prompt).',
-requiredArtifacts:['URL','ServiceWorker','Manifest','StartUrl']};
-
-}
-
-
-
-
-
-static assessManifest(manifestValues){
-if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
-return[manifestValues.parseFailureReason];
-}
-
-
-const failures=[];
-const bannerCheckIds=[
-'hasName',
-
-
-
-
-
-
-'hasShortName',
-'hasStartUrl',
-'hasPWADisplayValue',
-'hasIconsAtLeast192px'];
-
-manifestValues.allChecks.
-filter(item=>bannerCheckIds.includes(item.id)).
-forEach(item=>{
-if(!item.passing){
-failures.push(item.failureText);
-}
-});
-
-return failures;
-}
-
-
-
-
-
-static assessServiceWorker(artifacts){
-const failures=[];
-const hasServiceWorker=SWAudit.audit(artifacts).rawValue;
-if(!hasServiceWorker){
-failures.push('Site does not register a service worker');
-}
-
-return failures;
-}
-
-
-
-
-
-static assessOfflineStartUrl(artifacts){
-const failures=[];
-const warnings=[];
-const hasOfflineStartUrl=artifacts.StartUrl.statusCode===200;
-
-if(!hasOfflineStartUrl){
-failures.push('Service worker does not successfully serve the manifest\'s start_url');
-if(artifacts.StartUrl.explanation){
-failures.push(artifacts.StartUrl.explanation);
-}
-}
-
-if(artifacts.StartUrl.explanation){
-warnings.push(artifacts.StartUrl.explanation);
-}
-
-return{failures,warnings};
-}
-
-
-
-
-
-
-static async audit_(artifacts,context){
-
-let offlineFailures=[];
-
-let offlineWarnings=[];
-
-const manifestValues=await ManifestValues.request(context,artifacts.Manifest);
-const manifestFailures=WebappInstallBanner.assessManifest(manifestValues);
-const swFailures=WebappInstallBanner.assessServiceWorker(artifacts);
-if(!swFailures.length){
-const{failures,warnings}=WebappInstallBanner.assessOfflineStartUrl(artifacts);
-offlineFailures=failures;
-offlineWarnings=warnings;
-}
-
-return{
-warnings:offlineWarnings,
-failures:[
-...manifestFailures,
-...swFailures,
-...offlineFailures],
-
-manifestValues};
-
-}}
-
-
-module.exports=WebappInstallBanner;
-
-},{"../gather/computed/manifest-values":12,"./multi-check-audit":5,"./service-worker":"../audits/service-worker"}],"../audits/without-javascript":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-class WithoutJavaScript extends Audit{
-
-
-
-static get meta(){
-return{
-id:'without-javascript',
-title:'Contains some content when JavaScript is not available',
-failureTitle:'Does not provide fallback content when JavaScript is not available',
-description:'Your app should display some content when JavaScript is disabled, even if '+
-'it\'s just a warning to the user that JavaScript is required to use the app. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/no-js).',
-requiredArtifacts:['HTMLWithoutJavaScript']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const artifact=artifacts.HTMLWithoutJavaScript;
-
-
-if(artifact.bodyText.trim()===''&&!artifact.hasNoScript){
-return{
-rawValue:false,
-explanation:'The page body should render some content if its scripts are not available.'};
-
-}
-
-return{
-rawValue:true};
-
-}}
-
-
-module.exports=WithoutJavaScript;
-
-},{"./audit":2}],"../audits/works-offline":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const URL=require('../lib/url-shim');
-const Audit=require('./audit');
-
-class WorksOffline extends Audit{
-
-
-
-static get meta(){
-return{
-id:'works-offline',
-title:'Responds with a 200 when offline',
-failureTitle:'Does not respond with a 200 when offline',
-description:'If you\'re building a Progressive Web App, consider using a service worker '+
-'so that your app can work offline. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/http-200-when-offline).',
-requiredArtifacts:['Offline','URL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const warnings=[];
-const passed=artifacts.Offline===200;
-if(!passed&&
-!URL.equalWithExcludedFragments(artifacts.URL.requestedUrl,artifacts.URL.finalUrl)){
-warnings.push('You may be not loading offline because your test URL '+
-`(${artifacts.URL.requestedUrl}) was redirected to "${artifacts.URL.finalUrl}". `+
-'Try testing the second URL directly.');
-}
-
-return{
-rawValue:passed,
-warnings};
-
-}}
-
-
-module.exports=WorksOffline;
-
-},{"../lib/url-shim":"url","./audit":2}],"../gather/gatherers/accessibility":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-const Gatherer=require('./gatherer');
-
-const axeLibSource="/*! aXe v3.0.0-beta.2\n * Copyright (c) 2018 Deque Systems, Inc.\n *\n * Your use of this Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This entire copyright notice must appear in every copy of this file you\n * distribute or in any file that contains substantial portions of this source\n * code.\n */\n!function a(window){function b(a){this.name=\"SupportError\",this.cause=a.cause,this.message=\"`\"+a.cause+\"` - feature unsupported in your environment.\",a.ruleId&&(this.ruleId=a.ruleId,this.message+=\" Skipping \"+this.ruleId+\" rule.\"),this.stack=(new Error).stack}function c(a){\"use strict\";var b;return a?(b=axe.utils.clone(a),b.commons=a.commons):b={},b.reporter=b.reporter||null,b.rules=b.rules||[],b.checks=b.checks||[],b.data=Object.assign({checks:{},rules:{}},b.data),b}function d(a,b,c){\"use strict\";var d,e;for(d=0,e=a.length;d<e;d++)b[c](a[d])}function e(a){this.brand=\"axe\",this.application=\"axeAPI\",this.tagExclude=[\"experimental\"],this.defaultConfig=a,this._init()}function f(a,b,c){var d=a.brand,e=a.application;return axe.constants.helpUrlBase+d+\"/\"+(c||axe.version.substring(0,axe.version.lastIndexOf(\".\")))+\"/\"+b+\"?application=\"+e}function g(a){\"use strict\";this.id=a.id,this.data=null,this.relatedNodes=[],this.result=null}function h(a){\"use strict\";return\"string\"==typeof a?new Function(\"return \"+a+\";\")():a}function i(a){a&&(this.id=a.id,this.configure(a))}function j(a,b){\"use strict\";if(!axe.utils.isHidden(b)){axe.utils.findBy(a,\"node\",b)||a.push({node:b,include:[],exclude:[]})}}function k(a,b,c){\"use strict\";a.frames=a.frames||[];var d,e,f=document.querySelectorAll(c.shift());a:for(var g=0,h=f.length;g<h;g++){e=f[g];for(var i=0,j=a.frames.length;i<j;i++)if(a.frames[i].node===e){a.frames[i][b].push(c);break a}d={node:e,include:[],exclude:[]},c&&d[b].push(c),a.frames.push(d)}}function l(a){\"use strict\";if(a&&\"object\"===(void 0===a?\"undefined\":za(a))||a instanceof NodeList){if(a instanceof Node)return{include:[a],exclude:[]};if(a.hasOwnProperty(\"include\")||a.hasOwnProperty(\"exclude\"))return{include:a.include&&+a.include.length?a.include:[document],exclude:a.exclude||[]};if(a.length===+a.length)return{include:a,exclude:[]}}return\"string\"==typeof a?{include:[a],exclude:[]}:{include:[document],exclude:[]}}function m(a,b){\"use strict\";for(var c,d,e=[],f=0,g=a[b].length;f<g;f++){if(\"string\"==typeof(c=a[b][f])){d=Array.from(document.querySelectorAll(c)),e=e.concat(d.map(function(a){return axe.utils.getFlattenedTree(a)[0]}));break}!c||!c.length||c instanceof Node?c instanceof Node&&e.push(axe.utils.getFlattenedTree(c)[0]):c.length>1?k(a,b,c):(d=Array.from(document.querySelectorAll(c[0])),e=e.concat(d.map(function(a){return axe.utils.getFlattenedTree(a)[0]})))}return e.filter(function(a){return a})}function n(a){\"use strict\";if(0===a.include.length){if(0===a.frames.length){var b=axe.utils.respondable.isInFrame()?\"frame\":\"page\";return new Error(\"No elements found for include in \"+b+\" Context\")}a.frames.forEach(function(a,b){if(0===a.include.length)return new Error(\"No elements found for include in Context of frame \"+b)})}}function o(a){\"use strict\";var b=this;this.frames=[],this.initiator=!a||\"boolean\"!=typeof a.initiator||a.initiator,this.page=!1,a=l(a),this.exclude=a.exclude,this.include=a.include,this.include=m(this,\"include\"),this.exclude=m(this,\"exclude\"),axe.utils.select(\"frame, iframe\",this).forEach(function(a){wa(a,b)&&j(b.frames,a.actualNode)}),1===this.include.length&&this.include[0].actualNode===document.documentElement&&(this.page=!0);var c=n(this);if(c instanceof Error)throw c;Array.isArray(this.include)||(this.include=Array.from(this.include)),this.include.sort(axe.utils.nodeSorter)}function p(a){\"use strict\";this.id=a.id,this.result=axe.constants.NA,this.pageLevel=a.pageLevel,this.impact=null,this.nodes=[]}function q(a,b){\"use strict\";this._audit=b,this.id=a.id,this.selector=a.selector||\"*\",this.excludeHidden=\"boolean\"!=typeof a.excludeHidden||a.excludeHidden,this.enabled=\"boolean\"!=typeof a.enabled||a.enabled,this.pageLevel=\"boolean\"==typeof a.pageLevel&&a.pageLevel,this.any=a.any||[],this.all=a.all||[],this.none=a.none||[],this.tags=a.tags||[],a.matches&&(this.matches=h(a.matches))}function r(a){\"use strict\";return axe.utils.getAllChecks(a).map(function(b){var c=a._audit.checks[b.id||b];return c&&\"function\"==typeof c.after?c:null}).filter(Boolean)}function s(a,b){\"use strict\";var c=[];return a.forEach(function(a){axe.utils.getAllChecks(a).forEach(function(a){a.id===b&&c.push(a)})}),c}function t(a){\"use strict\";return a.filter(function(a){return!0!==a.filtered})}function u(a){\"use strict\";var b=[\"any\",\"all\",\"none\"],c=a.nodes.filter(function(a){var c=0;return b.forEach(function(b){a[b]=t(a[b]),c+=a[b].length}),c>0});return a.pageLevel&&c.length&&(c=[c.reduce(function(a,c){if(a)return b.forEach(function(b){a[b].push.apply(a[b],c[b])}),a})]),c}function v(a,b){\"use strict\";if(a=a||function(){},b=b||axe.log,!axe._audit)throw new Error(\"No audit configured\");var c=axe.utils.queue(),d=[];Object.keys(axe.plugins).forEach(function(a){c.defer(function(b){var c=function(a){d.push(a),b()};try{axe.plugins[a].cleanup(b,c)}catch(a){c(a)}})});var e=axe.utils.getFlattenedTree(document.body);axe.utils.querySelectorAll(e,\"iframe, frame\").forEach(function(a){c.defer(function(b,c){return axe.utils.sendCommandToFrame(a.actualNode,{command:\"cleanup-plugin\"},b,c)})}),c.then(function(c){0===d.length?a(c):b(d)}).catch(b)}function w(a){\"use strict\";var b;if(!(b=axe._audit))throw new Error(\"No audit configured\");a.reporter&&(\"function\"==typeof a.reporter||Ca[a.reporter])&&(b.reporter=a.reporter),a.checks&&a.checks.forEach(function(a){b.addCheck(a)});var c=[];a.rules&&a.rules.forEach(function(a){c.push(a.id),b.addRule(a)}),a.disableOtherRules&&b.rules.forEach(function(a){!1===c.includes(a.id)&&(a.enabled=!1)}),void 0!==a.branding?b.setBranding(a.branding):b._constructHelpUrls(),a.tagExclude&&(b.tagExclude=a.tagExclude)}function x(a,b,c){\"use strict\";var d=c,e=function(a){a instanceof Error==!1&&(a=new Error(a)),c(a)},f=a&&a.context||{};f.hasOwnProperty(\"include\")&&!f.include.length&&(f.include=[document]);var g=a&&a.options||{};switch(a.command){case\"rules\":return A(f,g,d,e);case\"cleanup-plugin\":return v(d,e);default:if(axe._audit&&axe._audit.commands&&axe._audit.commands[a.command])return axe._audit.commands[a.command](a,c)}}function y(a){\"use strict\";this._run=a.run,this._collect=a.collect,this._registry={},a.commands.forEach(function(a){axe._audit.registerCommand(a)})}function z(){\"use strict\";var a=axe._audit;if(!a)throw new Error(\"No audit configured\");a.resetRulesAndChecks()}function A(a,b,c,d){\"use strict\";try{a=new o(a)}catch(a){return d(a)}var e=axe.utils.queue(),f=axe._audit;b.performanceTimer&&axe.utils.performanceTimer.auditStart(),a.frames.length&&!1!==b.iframes&&e.defer(function(c,d){axe.utils.collectResultsFromFrames(a,b,\"rules\",null,c,d)});var g=void 0;e.defer(function(c,d){b.restoreScroll&&(g=axe.utils.getScrollState()),f.run(a,b,c,d)}),e.then(function(e){try{g&&axe.utils.setScrollState(g),b.performanceTimer&&axe.utils.performanceTimer.auditEnd();var h=axe.utils.mergeResults(e.map(function(a){return{results:a}}));a.initiator&&(h=f.after(h,b),h.forEach(axe.utils.publishMetaData),h=h.map(axe.utils.finalizeRuleResult));try{c(h)}catch(a){axe.log(a)}}catch(a){d(a)}}).catch(d)}function B(a){\"use strict\";switch(!0){case\"string\"==typeof a:case Array.isArray(a):case Node&&a instanceof Node:case NodeList&&a instanceof NodeList:return!0;case\"object\"!==(void 0===a?\"undefined\":za(a)):return!1;case void 0!==a.include:case void 0!==a.exclude:case\"number\"==typeof a.length:return!0;default:return!1}}function C(a,b,c){\"use strict\";var d=new TypeError(\"axe.run arguments are invalid\");if(!B(a)){if(void 0!==c)throw d;c=b,b=a,a=document}if(\"object\"!==(void 0===b?\"undefined\":za(b))){if(void 0!==c)throw d;c=b,b={}}if(\"function\"!=typeof c&&void 0!==c)throw d;return{context:a,options:b,callback:c||Da}}function D(a,b){\"use strict\";[\"any\",\"all\",\"none\"].forEach(function(c){Array.isArray(a[c])&&a[c].filter(function(a){return Array.isArray(a.relatedNodes)}).forEach(function(a){a.relatedNodes=a.relatedNodes.map(function(a){var c={html:a.source};return b.elementRef&&!a.fromFrame&&(c.element=a.element),(!1!==b.selectors||a.fromFrame)&&(c.target=a.selector),b.xpath&&(c.xpath=a.xpath),c})})})}function E(a,b){return Ja.reduce(function(c,d){return c[d]=(a[d]||[]).map(function(a){return b(a,d)}),c},{})}function F(a,b,c){var d=Object.assign({},b);d.nodes=(d[c]||[]).concat(),axe.constants.resultGroups.forEach(function(a){delete d[a]}),a[c].push(d)}function G(a,b,c){\"use strict\";var d=window.getComputedStyle(a,null),e=!1;return!!d&&(b.forEach(function(a){d.getPropertyValue(a.property)===a.value&&(e=!0)}),!!e||!(a.nodeName.toUpperCase()===c.toUpperCase()||!a.parentNode)&&G(a.parentNode,b,c))}function H(a,b){\"use strict\";var c;return axe._tree&&(c=axe.utils.getSelector(b)),new Error(a+\": \"+(c||b))}function I(a,b,c,d,e,f){\"use strict\";var g=axe.utils.queue();a.frames.forEach(function(e){var f={options:b,command:c,parameter:d,context:{initiator:!1,page:a.page,include:e.include||[],exclude:e.exclude||[]}};g.defer(function(a,b){var c=e.node;axe.utils.sendCommandToFrame(c,f,function(b){if(b)return a({results:b,frameElement:c,frame:axe.utils.getSelector(c)});a(null)},b)})}),g.then(function(a){e(axe.utils.mergeResults(a,b))}).catch(f)}function J(a,b){if(b=b||300,a.length>b){var c=a.indexOf(\">\");a=a.substring(0,c+1)}return a}function K(a){var b=a.outerHTML;return b||\"function\"!=typeof XMLSerializer||(b=(new XMLSerializer).serializeToString(a)),J(b||\"\")}function L(a,b,c){this._fromFrame=!!c,this.spec=c||{},b&&b.absolutePaths&&(this._options={toRoot:!0}),this.source=void 0!==this.spec.source?this.spec.source:K(a),this._element=a}function M(a,b){return{shadowId:b,children:[],actualNode:a}}function N(a){var b=[];for(a=a.firstChild;a;)b.push(a),a=a.nextSibling;return b}function O(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\";return 0!==a.length&&(a.match(/[0-9]/g)||\"\").length>=a.length/2}function P(a,b){return[a.substring(0,b),a.substring(b)]}function Q(a){var b=a,c=\"\",d=\"\",e=\"\",f=\"\",g=\"\",h=\"\";if(a.includes(\"#\")){var i=P(a,a.indexOf(\"#\")),j=Ka(i,2);a=j[0],h=j[1]}if(a.includes(\"?\")){var k=P(a,a.indexOf(\"?\")),l=Ka(k,2);a=l[0],g=l[1]}if(a.includes(\"://\")){var m=a.split(\"://\"),n=Ka(m,2);c=n[0],a=n[1];var o=P(a,a.indexOf(\"/\")),p=Ka(o,2);d=p[0],a=p[1]}else if(\"//\"===a.substr(0,2)){a=a.substr(2);var q=P(a,a.indexOf(\"/\")),r=Ka(q,2);d=r[0],a=r[1]}if(\"www.\"===d.substr(0,4)&&(d=d.substr(4)),d&&d.includes(\":\")){var s=P(d,d.indexOf(\":\")),t=Ka(s,2);d=t[0],e=t[1]}return f=a,{original:b,protocol:c,domain:d,port:e,path:f,query:g,hash:h}}function R(a,b){var c=b.name,d=void 0;if(-1!==c.indexOf(\"href\")||-1!==c.indexOf(\"src\")){var e=encodeURI(axe.utils.getFriendlyUriEnd(a.getAttribute(c)));if(!e)return;d=La(b.name)+'$=\"'+e+'\"'}else d=La(c)+'=\"'+La(b.value)+'\"';return d}function S(a,b){return a.count<b.count?-1:a.count===b.count?0:1}function T(a){return!Na.includes(a.name)&&-1===a.name.indexOf(\":\")&&(!a.value||a.value.length<Oa)}function U(a,b){var c=[],d=b.classes,e=b.tags;return a.classList&&Array.from(a.classList).forEach(function(b){var f=La(b);d[f]<e[a.nodeName]&&c.push({name:f,count:d[f],species:\"class\"})}),c.sort(S)}function V(a,b){var c=a.parentNode&&Array.from(a.parentNode.children||\"\")||[];if(c.find(function(c){return c!==a&&axe.utils.matchesSelector(c,b)}))return\":nth-child(\"+(1+c.indexOf(a))+\")\";return\"\"}function W(a){if(a.getAttribute(\"id\")){var b=a.getRootNode&&a.getRootNode()||document,c=\"#\"+La(a.getAttribute(\"id\")||\"\");return c.match(/player_uid_/)||1!==b.querySelectorAll(c).length?void 0:c}}function X(a){return void 0===Ma&&(Ma=axe.utils.isXHTML(document)),La(Ma?a.localName:a.nodeName.toLowerCase())}function Y(a,b){var c=[],d=b.attributes,e=b.tags;return a.attributes&&Array.from(a.attributes).filter(T).forEach(function(b){var f=R(a,b);f&&d[f]<e[a.nodeName]&&c.push({name:f,count:d[f],species:\"attribute\"})}),c.sort(S)}function Z(a,b){var c=\"\",d=void 0,e=U(a,b),f=Y(a,b);return e.length&&1===e[0].count?d=[e[0]]:f.length&&1===f[0].count?(d=[f[0]],c=X(a)):(d=e.concat(f),d.sort(S),d=d.slice(0,3),d.some(function(a){return\"class\"===a.species})?d.sort(function(a,b){return a.species!==b.species&&\"class\"===a.species?-1:a.species===b.species?0:1}):c=X(a)),c+=d.reduce(function(a,b){switch(b.species){case\"class\":return a+\".\"+b.name;case\"attribute\":return a+\"[\"+b.name+\"]\"}return a},\"\")}function $(a,b,c){axe._selectorData||(axe._selectorData=axe.utils.getSelectorData(axe._tree));var d=b.toRoot,e=void 0!==d&&d,f=void 0,g=void 0;do{var h=W(a);h||(h=Z(a,axe._selectorData),h+=V(a,h)),f=f?h+\" > \"+f:h,g=g?g.filter(function(a){return axe.utils.matchesSelector(a,f)}):Array.from(c.querySelectorAll(f)),a=a.parentElement}while((g.length>1||e)&&a&&11!==a.nodeType);return 1===g.length?f:-1!==f.indexOf(\" > \")?\":root\"+f.substring(f.indexOf(\" > \")):\":root\"}function _(a,b){var c,d;if(!a)return[];if(!b&&9===a.nodeType)return b=[{str:\"html\"}];if(b=b||[],a.parentNode&&a.parentNode!==a&&(b=_(a.parentNode,b)),a.previousSibling){d=1,c=a.previousSibling;do{1===c.nodeType&&c.nodeName===a.nodeName&&d++,c=c.previousSibling}while(c);1===d&&(d=null)}else if(a.nextSibling){c=a.nextSibling;do{1===c.nodeType&&c.nodeName===a.nodeName?(d=1,c=null):(d=null,c=c.previousSibling)}while(c)}if(1===a.nodeType){var e={};e.str=a.nodeName.toLowerCase();var f=a.getAttribute&&axe.utils.escapeSelector(a.getAttribute(\"id\"));f&&1===a.ownerDocument.querySelectorAll(\"#\"+f).length&&(e.id=a.getAttribute(\"id\")),d>1&&(e.count=d),b.push(e)}return b}function aa(a){return a.reduce(function(a,b){return b.id?\"/\"+b.str+\"[@id='\"+b.id+\"']\":a+\"/\"+b.str+(b.count>0?\"[\"+b.count+\"]\":\"\")},\"\")}function ba(a){\"use strict\";if(Pa&&Pa.parentNode)return void 0===Pa.styleSheet?Pa.appendChild(document.createTextNode(a)):Pa.styleSheet.cssText+=a,Pa;if(a){var b=document.head||document.getElementsByTagName(\"head\")[0];return Pa=document.createElement(\"style\"),Pa.type=\"text/css\",void 0===Pa.styleSheet?Pa.appendChild(document.createTextNode(a)):Pa.styleSheet.cssText=a,b.appendChild(Pa),Pa}}function ca(a,b,c,d){\"use strict\";var e=axe.utils.getXpath(c),f={element:c,selector:d,xpath:e};a.forEach(function(a){a.node=axe.utils.DqElement.fromFrame(a.node,b,f);var c=axe.utils.getAllChecks(a);c.length&&c.forEach(function(a){a.relatedNodes=a.relatedNodes.map(function(a){return axe.utils.DqElement.fromFrame(a,b,f)})})})}function da(a,b){\"use strict\";for(var c,d,e=b[0].node,f=0,g=a.length;f<g;f++)if(d=a[f].node,(c=axe.utils.nodeSorter({actualNode:d.element},{actualNode:e.element}))>0||0===c&&e.selector.length<d.selector.length)return void a.splice.apply(a,[f,0].concat(b));a.push.apply(a,b)}function ea(a){\"use strict\";return a&&a.results?Array.isArray(a.results)?a.results.length?a.results:null:[a.results]:null}function fa(a,b){function c(a){return a.incomplete&&a.incomplete.default?a.incomplete.default:Aa.incompleteFallbackMessage()}if(!a||!a.missingData)return c(b);try{var d=b.incomplete[a.missingData[0].reason];if(!d)throw new Error;return d}catch(d){return\"string\"==typeof a.missingData?b.incomplete[a.missingData]:c(b)}}function ga(a,b){\"use strict\";return function(c){var d=a[c.id]||{},e=d.messages||{},f=Object.assign({},d);delete f.messages,void 0===c.result?\"object\"===za(e.incomplete)?f.message=function(){return fa(c.data,e)}:f.message=e.incomplete:f.message=c.result===b?e.pass:e.fail,axe.utils.extendMetaData(c,f)}}function ha(a,b){return 1===a.nodeType&&(\"*\"===b.tag||a.nodeName.toLowerCase()===b.tag)}function ia(a,b){return!b.classes||b.classes.reduce(function(b,c){return b&&a.className&&a.className.match(c.regexp)},!0)}function ja(a,b){return!b.attributes||b.attributes.reduce(function(b,c){var d=a.getAttribute(c.key);return b&&null!==d&&(!c.value||c.test(d))},!0)}function ka(a,b){return!b.id||a.id===b.id}function la(a,b){return!(b.pseudos&&!b.pseudos.reduce(function(b,c){if(\"not\"===c.name)return b&&!Sa([a],c.expressions,!1).length;throw new Error(\"the pseudo selector \"+c.name+\" has not yet been implemented\")},!0))}function ma(a){/*! Credit Mootools Copyright Mootools, MIT License */\nif(a)return a.map(function(a){var b,c,d=a.name.replace(Ua,\"\"),e=(a.value||\"\").replace(Ua,\"\");switch(a.operator){case\"^=\":c=new RegExp(\"^\"+Ta(e));break;case\"$=\":c=new RegExp(Ta(e)+\"$\");break;case\"~=\":c=new RegExp(\"(^|\\\\s)\"+Ta(e)+\"(\\\\s|$)\");break;case\"|=\":c=new RegExp(\"^\"+Ta(e)+\"(-|$)\");break;case\"=\":b=function(a){return e===a};break;case\"*=\":b=function(a){return a&&a.includes(e)};break;case\"!=\":b=function(a){return e!==a};break;default:b=function(a){return!!a}}return\"\"===e&&/^[*$^]=$/.test(a.operator)&&(b=function(){return!1}),b||(b=function(a){return a&&c.test(a)}),{key:d,value:e,test:b}})}function na(a){if(a)return a.map(function(a){return a=a.replace(Ua,\"\"),{value:a,regexp:new RegExp(\"(^|\\\\s)\"+Ta(a)+\"(\\\\s|$)\")}})}function oa(a){if(a)return a.map(function(a){var b;return\"not\"===a.name&&(b=axe.utils.cssParser.parse(a.value),b=b.selectors?b.selectors:[b],b=Ra(b)),{name:a.name,expressions:b,value:a.value}})}function pa(a,b,c,d){var e={nodes:a.slice(),anyLevel:b,thisLevel:c,parentShadowId:d};return e.nodes.reverse(),e}function qa(a,b){return ha(a.actualNode,b[0])&&ia(a.actualNode,b[0])&&ja(a.actualNode,b[0])&&ka(a.actualNode,b[0])&&la(a,b[0])}function ra(a,b){\"use strict\";var c,d,e=axe._audit&&axe._audit.tagExclude?axe._audit.tagExclude:[];return b.hasOwnProperty(\"include\")||b.hasOwnProperty(\"exclude\")?(c=b.include||[],c=Array.isArray(c)?c:[c],d=b.exclude||[],d=Array.isArray(d)?d:[d],d=d.concat(e.filter(function(a){return-1===c.indexOf(a)}))):(c=Array.isArray(b)?b:[b],d=e.filter(function(a){return-1===c.indexOf(a)})),!!(c.some(function(b){return-1!==a.tags.indexOf(b)})||0===c.length&&!1!==a.enabled)&&d.every(function(b){return-1===a.tags.indexOf(b)})}function sa(a){var b=window.getComputedStyle(a),c=\"visible\"===b.getPropertyValue(\"overflow-y\"),d=\"visible\"===b.getPropertyValue(\"overflow-x\");if(!c&&a.scrollHeight>a.clientHeight||!d&&a.scrollWidth>a.clientWidth)return{elm:a,top:a.scrollTop,left:a.scrollLeft}}function ta(a,b,c){if(a===window)return a.scroll(b,c);a.scrollTop=b,a.scrollLeft=c}function ua(a){return Array.from(a.children).reduce(function(a,b){var c=sa(b);return c&&a.push(c),a.concat(ua(b))},[])}function va(a){\"use strict\";return a.sort(function(a,b){return axe.utils.contains(a,b)?1:-1})[0]}function wa(a,b){\"use strict\";var c=b.include&&va(b.include.filter(function(b){return axe.utils.contains(b,a)})),d=b.exclude&&va(b.exclude.filter(function(b){return axe.utils.contains(b,a)}));return!!(!d&&c||d&&axe.utils.contains(d,c))}function xa(a,b){\"use strict\";var c;if(0===a.length)return b;a.length<b.length&&(c=a,a=b,b=c);for(var d=0,e=b.length;d<e;d++)a.includes(b[d])||a.push(b[d]);return a}function ya(a){return a.reduce(function(a,b){return a.length&&a[a.length-1].actualNode.contains(b.actualNode)||a.push(b),a},[])}var document=window.document,za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},axe=axe||{};axe.version=\"3.0.0-beta.2\",\"function\"==typeof define&&define.amd&&define([],function(){\"use strict\";return axe}),\"object\"===(\"undefined\"==typeof module?\"undefined\":za(module))&&module.exports&&\"function\"==typeof a.toString&&(axe.source=\"(\"+a.toString()+')(typeof window === \"object\" ? window : this);',module.exports=axe),\"function\"==typeof window.getComputedStyle&&(window.axe=axe);var commons;b.prototype=Object.create(Error.prototype),b.prototype.constructor=b;var utils=axe.utils={},Aa={},za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};e.prototype._init=function(){var a=c(this.defaultConfig);axe.commons=commons=a.commons,this.reporter=a.reporter,this.commands={},this.rules=[],this.checks={},d(a.rules,this,\"addRule\"),d(a.checks,this,\"addCheck\"),this.data={},this.data.checks=a.data&&a.data.checks||{},this.data.rules=a.data&&a.data.rules||{},this.data.failureSummaries=a.data&&a.data.failureSummaries||{},this.data.incompleteFallbackMessage=a.data&&a.data.incompleteFallbackMessage||\"\",this._constructHelpUrls()},e.prototype.registerCommand=function(a){\"use strict\";this.commands[a.id]=a.callback},e.prototype.addRule=function(a){\"use strict\";a.metadata&&(this.data.rules[a.id]=a.metadata);var b=this.getRule(a.id);b?b.configure(a):this.rules.push(new q(a,this))},e.prototype.addCheck=function(a){\"use strict\";var b=a.metadata;\"object\"===(void 0===b?\"undefined\":za(b))&&(this.data.checks[a.id]=b,\"object\"===za(b.messages)&&Object.keys(b.messages).filter(function(a){return b.messages.hasOwnProperty(a)&&\"string\"==typeof b.messages[a]}).forEach(function(a){0===b.messages[a].indexOf(\"function\")&&(b.messages[a]=new Function(\"return \"+b.messages[a]+\";\")())})),this.checks[a.id]?this.checks[a.id].configure(a):this.checks[a.id]=new i(a)},e.prototype.run=function(a,b,c,d){\"use strict\";this.validateOptions(b),axe._tree=axe.utils.getFlattenedTree(document.documentElement),axe._selectCache=[];var e=axe.utils.queue();this.rules.forEach(function(c){if(axe.utils.ruleShouldRun(c,a,b)){if(b.performanceTimer){var d=\"mark_rule_end_\"+c.id,f=\"mark_rule_start_\"+c.id;axe.utils.performanceTimer.mark(f)}e.defer(function(e,g){c.run(a,b,function(a){b.performanceTimer&&(axe.utils.performanceTimer.mark(d),axe.utils.performanceTimer.measure(\"rule_\"+c.id,f,d)),e(a)},function(a){if(b.debug)g(a);else{var d=Object.assign(new p(c),{result:axe.constants.CANTTELL,description:\"An error occured while running this rule\",message:a.message,stack:a.stack,error:a});e(d)}})})}}),e.then(function(a){axe._selectCache=void 0,c(a.filter(function(a){return!!a}))}).catch(d)},e.prototype.after=function(a,b){\"use strict\";var c=this.rules;return a.map(function(a){return axe.utils.findBy(c,\"id\",a.id).after(a,b)})},e.prototype.getRule=function(a){return this.rules.find(function(b){return b.id===a})},e.prototype.validateOptions=function(a){\"use strict\";var b=this;if(\"object\"===za(a.runOnly)){var c=a.runOnly;if(\"rule\"===c.type&&Array.isArray(c.value))c.value.forEach(function(a){if(!b.getRule(a))throw new Error(\"unknown rule `\"+a+\"` in options.runOnly\")});else if(Array.isArray(c.value)&&c.value.length>0){var d=[].concat(c.value);if(b.rules.forEach(function(a){var b,c,e;if(d)for(c=0,e=a.tags.length;c<e;c++)-1!==(b=d.indexOf(a.tags[c]))&&d.splice(b,1)}),0!==d.length)throw new Error(\"could not find tags `\"+d.join(\"`, `\")+\"`\")}}return\"object\"===za(a.rules)&&Object.keys(a.rules).forEach(function(a){if(!b.getRule(a))throw new Error(\"unknown rule `\"+a+\"` in options.rules\")}),a},e.prototype.setBranding=function(a){\"use strict\";var b={brand:this.brand,application:this.application};a&&a.hasOwnProperty(\"brand\")&&a.brand&&\"string\"==typeof a.brand&&(this.brand=a.brand),a&&a.hasOwnProperty(\"application\")&&a.application&&\"string\"==typeof a.application&&(this.application=a.application),this._constructHelpUrls(b)},e.prototype._constructHelpUrls=function(){var a=this,b=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,c=(axe.version.match(/^[1-9][0-9]*\\.[0-9]+/)||[\"x.y\"])[0];this.rules.forEach(function(d){a.data.rules[d.id]||(a.data.rules[d.id]={});var e=a.data.rules[d.id];(\"string\"!=typeof e.helpUrl||b&&e.helpUrl===f(b,d.id,c))&&(e.helpUrl=f(a,d.id,c))})},e.prototype.resetRulesAndChecks=function(){\"use strict\";this._init()},i.prototype.enabled=!0,i.prototype.run=function(a,b,c,d){\"use strict\";b=b||{};var e=b.hasOwnProperty(\"enabled\")?b.enabled:this.enabled,f=b.options||this.options;if(e){var h,i=new g(this),j=axe.utils.checkHelper(i,b,c,d);try{h=this.evaluate.call(j,a.actualNode,f,a)}catch(a){return void d(a)}j.isAsync||(i.result=h,setTimeout(function(){c(i)},0))}else c(null)},i.prototype.configure=function(a){var b=this;[\"options\",\"enabled\"].filter(function(b){return a.hasOwnProperty(b)}).forEach(function(c){return b[c]=a[c]}),[\"evaluate\",\"after\"].filter(function(b){return a.hasOwnProperty(b)}).forEach(function(c){return b[c]=h(a[c])})};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};q.prototype.matches=function(){\"use strict\";return!0},q.prototype.gather=function(a){\"use strict\";var b=axe.utils.select(this.selector,a);return this.excludeHidden?b.filter(function(a){return!axe.utils.isHidden(a.actualNode)}):b},q.prototype.runChecks=function(a,b,c,d,e){\"use strict\";var f=this,g=axe.utils.queue();this[a].forEach(function(a){var d=f._audit.checks[a.id||a],e=axe.utils.getCheckOption(d,f.id,c);g.defer(function(a,c){d.run(b,e,a,c)})}),g.then(function(b){b=b.filter(function(a){return a}),d({type:a,results:b})}).catch(e)},q.prototype.run=function(a,c,d,e){var f=this,g=axe.utils.queue(),h=new p(this),i=\"mark_runchecks_start_\"+this.id,j=\"mark_runchecks_end_\"+this.id,k=void 0;try{k=this.gather(a).filter(function(a){return f.matches(a.actualNode,a)})}catch(a){return void e(new b({cause:a,ruleId:this.id}))}c.performanceTimer&&(axe.log(\"gather (\",k.length,\"):\",axe.utils.performanceTimer.timeElapsed()+\"ms\"),axe.utils.performanceTimer.mark(i)),k.forEach(function(a){g.defer(function(b,d){var e=axe.utils.queue();e.defer(function(b,d){f.runChecks(\"any\",a,c,b,d)}),e.defer(function(b,d){f.runChecks(\"all\",a,c,b,d)}),e.defer(function(b,d){f.runChecks(\"none\",a,c,b,d)}),e.then(function(d){if(d.length){var e=!1,f={};d.forEach(function(a){var b=a.results.filter(function(a){return a});f[a.type]=b,b.length&&(e=!0)}),e&&(f.node=new axe.utils.DqElement(a.actualNode,c),h.nodes.push(f))}b()}).catch(function(a){return d(a)})})}),c.performanceTimer&&(axe.utils.performanceTimer.mark(j),axe.utils.performanceTimer.measure(\"runchecks_\"+this.id,i,j)),g.then(function(){return d(h)}).catch(function(a){return e(a)})},q.prototype.after=function(a,b){\"use strict\";var c=r(this),d=this.id;return c.forEach(function(c){var e=s(a.nodes,c.id),f=axe.utils.getCheckOption(c,d,b),g=c.after(e,f);e.forEach(function(a){-1===g.indexOf(a)&&(a.filtered=!0)})}),a.nodes=u(a),a},q.prototype.configure=function(a){\"use strict\";a.hasOwnProperty(\"selector\")&&(this.selector=a.selector),a.hasOwnProperty(\"excludeHidden\")&&(this.excludeHidden=\"boolean\"!=typeof a.excludeHidden||a.excludeHidden),a.hasOwnProperty(\"enabled\")&&(this.enabled=\"boolean\"!=typeof a.enabled||a.enabled),a.hasOwnProperty(\"pageLevel\")&&(this.pageLevel=\"boolean\"==typeof a.pageLevel&&a.pageLevel),a.hasOwnProperty(\"any\")&&(this.any=a.any),a.hasOwnProperty(\"all\")&&(this.all=a.all),a.hasOwnProperty(\"none\")&&(this.none=a.none),a.hasOwnProperty(\"tags\")&&(this.tags=a.tags),a.hasOwnProperty(\"matches\")&&(\"string\"==typeof a.matches?this.matches=new Function(\"return \"+a.matches+\";\")():this.matches=a.matches)},function(axe){var a=[{name:\"NA\",value:\"inapplicable\",priority:0,group:\"inapplicable\"},{name:\"PASS\",value:\"passed\",priority:1,group:\"passes\"},{name:\"CANTTELL\",value:\"cantTell\",priority:2,group:\"incomplete\"},{name:\"FAIL\",value:\"failed\",priority:3,group:\"violations\"}],b={helpUrlBase:\"https://dequeuniversity.com/rules/\",results:[],resultGroups:[],resultGroupMap:{},impact:Object.freeze([\"minor\",\"moderate\",\"serious\",\"critical\"])};a.forEach(function(a){var c=a.name,d=a.value,e=a.priority,f=a.group;b[c]=d,b[c+\"_PRIO\"]=e,b[c+\"_GROUP\"]=f,b.results[e]=d,b.resultGroups[e]=f,b.resultGroupMap[d]=f}),Object.freeze(b.results),Object.freeze(b.resultGroups),Object.freeze(b.resultGroupMap),Object.freeze(b),Object.defineProperty(axe,\"constants\",{value:b,enumerable:!0,configurable:!1,writable:!1})}(axe);var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.log=function(){\"use strict\";\"object\"===(\"undefined\"==typeof console?\"undefined\":za(console))&&console.log&&Function.prototype.apply.call(console.log,console,arguments)},axe.cleanup=v,axe.configure=w,axe.getRules=function(a){\"use strict\";a=a||[];var b=a.length?axe._audit.rules.filter(function(b){return!!a.filter(function(a){return-1!==b.tags.indexOf(a)}).length}):axe._audit.rules,c=axe._audit.data.rules||{};return b.map(function(a){var b=c[a.id]||{};return{ruleId:a.id,description:b.description,help:b.help,helpUrl:b.helpUrl,tags:a.tags}})},axe._load=function(a){\"use strict\";axe.utils.respondable.subscribe(\"axe.ping\",function(a,b,c){c({axe:!0})}),axe.utils.respondable.subscribe(\"axe.start\",x),axe._audit=new e(a)};var axe=axe||{};axe.plugins={},y.prototype.run=function(){\"use strict\";return this._run.apply(this,arguments)},y.prototype.collect=function(){\"use strict\";return this._collect.apply(this,arguments)},y.prototype.cleanup=function(a){\"use strict\";var b=axe.utils.queue(),c=this;Object.keys(this._registry).forEach(function(a){b.defer(function(b){c._registry[a].cleanup(b)})}),b.then(function(){a()})},y.prototype.add=function(a){\"use strict\";this._registry[a.id]=a},axe.registerPlugin=function(a){\"use strict\";axe.plugins[a.id]=new y(a)};var Ba,Ca={};axe.getReporter=function(a){\"use strict\";return\"string\"==typeof a&&Ca[a]?Ca[a]:\"function\"==typeof a?a:Ba},axe.addReporter=function(a,b,c){\"use strict\";Ca[a]=b,c&&(Ba=b)},axe.reset=z,axe._runRules=A;var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},Da=function(){};axe.run=function(a,b,c){\"use strict\";if(!axe._audit)throw new Error(\"No audit configured\");var d=C(a,b,c);a=d.context,b=d.options,c=d.callback,b.reporter=b.reporter||axe._audit.reporter||\"v1\",b.performanceTimer&&axe.utils.performanceTimer.start();var e=void 0,f=Da,g=Da;return window.Promise&&c===Da&&(e=new Promise(function(a,b){f=b,g=a})),axe._runRules(a,b,function(a){var d=function(a){try{c(null,a)}catch(a){axe.log(a)}g(a)};b.performanceTimer&&axe.utils.performanceTimer.end();try{var e=axe.getReporter(b.reporter),h=e(a,b,d);axe._selectorData=void 0,axe._tree=void 0,void 0!==h&&d(h)}catch(a){c(a),f(a)}},function(a){c(a),f(a)}),e},Aa.failureSummary=function(a){\"use strict\";var b={};return b.none=a.none.concat(a.all),b.any=a.any,Object.keys(b).map(function(a){if(b[a].length){var c=axe._audit.data.failureSummaries[a];return c&&\"function\"==typeof c.failureMessage?c.failureMessage(b[a].map(function(a){return a.message||\"\"})):void 0}}).filter(function(a){return void 0!==a}).join(\"\\n\\n\")},Aa.incompleteFallbackMessage=function(){\"use strict\";return axe._audit.data.incompleteFallbackMessage()};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},Ea=axe.constants.resultGroups;Aa.processAggregate=function(a,b){var c=axe.utils.aggregateResult(a);return c.timestamp=(new Date).toISOString(),c.url=window.location.href,Ea.forEach(function(a){b.resultTypes&&!b.resultTypes.includes(a)&&(c[a]||[]).forEach(function(a){Array.isArray(a.nodes)&&a.nodes.length>0&&(a.nodes=[a.nodes[0]])}),c[a]=(c[a]||[]).map(function(a){return a=Object.assign({},a),Array.isArray(a.nodes)&&a.nodes.length>0&&(a.nodes=a.nodes.map(function(a){return\"object\"===za(a.node)&&(a.html=a.node.source,b.elementRef&&!a.node.fromFrame&&(a.element=a.node.element),(!1!==b.selectors||a.node.fromFrame)&&(a.target=a.node.selector),b.xpath&&(a.xpath=a.node.xpath)),delete a.result,delete a.node,D(a,b),a})),Ea.forEach(function(b){return delete a[b]}),delete a.pageLevel,delete a.result,a})}),c},axe.addReporter(\"na\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=Aa.processAggregate(a,b);c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"no-passes\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),b.resultTypes=[\"violations\"];var d=Aa.processAggregate(a,b);c({violations:d.violations,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"raw\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),c(a)}),axe.addReporter(\"v1\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=Aa.processAggregate(a,b);d.violations.forEach(function(a){return a.nodes.forEach(function(a){a.failureSummary=Aa.failureSummary(a)})}),c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"v2\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=Aa.processAggregate(a,b);c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})},!0),axe.utils.aggregate=function(a,b,c){b=b.slice(),c&&b.push(c);var d=b.map(function(b){return a.indexOf(b)}).sort();return a[d.pop()]};var Fa=axe.constants,Ga=Fa.CANTTELL_PRIO,Ha=Fa.FAIL_PRIO,Ia=[];Ia[axe.constants.PASS_PRIO]=!0,Ia[axe.constants.CANTTELL_PRIO]=null,Ia[axe.constants.FAIL_PRIO]=!1;var Ja=[\"any\",\"all\",\"none\"];axe.utils.aggregateChecks=function(a){var b=Object.assign({},a);E(b,function(a,b){var c=Ia.indexOf(a.result);a.priority=-1!==c?c:axe.constants.CANTTELL_PRIO,\"none\"===b&&(a.priority=4-a.priority)});var c={all:b.all.reduce(function(a,b){return Math.max(a,b.priority)},0),none:b.none.reduce(function(a,b){return Math.max(a,b.priority)},0),any:b.any.reduce(function(a,b){return Math.min(a,b.priority)},4)%4};b.priority=Math.max(c.all,c.none,c.any);var d=[];return Ja.forEach(function(a){b[a]=b[a].filter(function(d){return d.priority===b.priority&&d.priority===c[a]}),b[a].forEach(function(a){return d.push(a.impact)})}),[Ga,Ha].includes(b.priority)?b.impact=axe.utils.aggregate(axe.constants.impact,d):b.impact=null,E(b,function(a){delete a.result,delete a.priority}),b.result=axe.constants.results[b.priority],delete b.priority,b},function(){axe.utils.aggregateNodeResults=function(a){var b={};if((a=a.map(function(a){if(a.any&&a.all&&a.none)return axe.utils.aggregateChecks(a);if(Array.isArray(a.node))return axe.utils.finalizeRuleResult(a);throw new TypeError(\"Invalid Result type\")}))&&a.length){var c=a.map(function(a){return a.result});b.result=axe.utils.aggregate(axe.constants.results,c,b.result)}else b.result=\"inapplicable\";axe.constants.resultGroups.forEach(function(a){return b[a]=[]}),a.forEach(function(a){var c=axe.constants.resultGroupMap[a.result];b[c].push(a)});var d=axe.constants.FAIL_GROUP;if(0===b[d].length&&(d=axe.constants.CANTTELL_GROUP),b[d].length>0){var e=b[d].map(function(a){return a.impact});b.impact=axe.utils.aggregate(axe.constants.impact,e)||null}else b.impact=null;return b}}(),axe.utils.aggregateResult=function(a){var b={};return axe.constants.resultGroups.forEach(function(a){return b[a]=[]}),a.forEach(function(a){a.error?F(b,a,axe.constants.CANTTELL_GROUP):a.result===axe.constants.NA?F(b,a,axe.constants.NA_GROUP):axe.constants.resultGroups.forEach(function(c){Array.isArray(a[c])&&a[c].length>0&&F(b,a,c)})}),b},axe.utils.areStylesSet=G,axe.utils.checkHelper=function(a,b,c,d){\"use strict\";return{isAsync:!1,async:function(){return this.isAsync=!0,function(b){b instanceof Error==!1?(a.result=b,c(a)):d(b)}},data:function(b){a.data=b},relatedNodes:function(c){c=c instanceof Node?[c]:axe.utils.toArray(c),a.relatedNodes=c.map(function(a){return new axe.utils.DqElement(a,b)})}}};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.clone=function(a){\"use strict\";var b,c,d=a;if(null!==a&&\"object\"===(void 0===a?\"undefined\":za(a)))if(Array.isArray(a))for(d=[],b=0,c=a.length;b<c;b++)d[b]=axe.utils.clone(a[b]);else{d={};for(b in a)d[b]=axe.utils.clone(a[b])}return d},axe.utils.sendCommandToFrame=function(a,b,c,d){\"use strict\";var e=a.contentWindow;if(!e)return axe.log(\"Frame does not have a content window\",a),void c(null);var f=setTimeout(function(){f=setTimeout(function(){var e=H(\"No response from frame\",a);b.debug?d(e):(axe.log(e),c(null))},0)},500);axe.utils.respondable(e,\"axe.ping\",null,void 0,function(){clearTimeout(f);var g=b.options&&b.options.frameWaitTime||6e4;f=setTimeout(function(){d(H(\"Axe in frame timed out\",a))},g),axe.utils.respondable(e,\"axe.start\",b,void 0,function(a){clearTimeout(f),a instanceof Error==!1?c(a):d(a)})})},axe.utils.collectResultsFromFrames=I,axe.utils.contains=function(a,b){\"use strict\";function c(a,b){return a.shadowId===b.shadowId||!!a.children.find(function(a){return c(a,b)})}return a.shadowId||b.shadowId?c(a,b):\"function\"==typeof a.actualNode.contains?a.actualNode.contains(b.actualNode):!!(16&a.actualNode.compareDocumentPosition(b.actualNode))},function(axe){/*!\n * The copyright below covers the code within this function block only\n *\n * Copyright (c) 2013 Dulin Marat\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\nfunction a(){this.pseudos={},this.attrEqualityMods={},this.ruleNestingOperators={},this.substitutesEnabled=!1}function b(a){return a>=\"a\"&&a<=\"z\"||a>=\"A\"&&a<=\"Z\"||\"-\"===a||\"_\"===a}function c(a){return a>=\"a\"&&a<=\"z\"||a>=\"A\"&&a<=\"Z\"||a>=\"0\"&&a<=\"9\"||\"-\"===a||\"_\"===a}function d(a){return a>=\"a\"&&a<=\"f\"||a>=\"A\"&&a<=\"F\"||a>=\"0\"&&a<=\"9\"}function e(a,e,g,j,k,l){var m,n,o,p,q;return p=a.length,m=null,o=function(b,c){var f,g,h;for(h=\"\",e++,m=a.charAt(e);e<p;){if(m===b)return e++,h;if(\"\\\\\"===m)if(e++,(m=a.charAt(e))===b)h+=b;else if(f=c[m])h+=f;else{if(d(m)){for(g=m,e++,m=a.charAt(e);d(m);)g+=m,e++,m=a.charAt(e);\" \"===m&&(e++,m=a.charAt(e)),h+=String.fromCharCode(parseInt(g,16));continue}h+=m}else h+=m;e++,m=a.charAt(e)}return h},n=function(){var b=\"\";for(m=a.charAt(e);e<p;){if(c(m))b+=m;else{if(\"\\\\\"!==m)return b;if(++e>=p)throw Error(\"Expected symbol but end of file reached.\");if(m=a.charAt(e),f[m])b+=m;else{if(d(m)){var g=m;for(e++,m=a.charAt(e);d(m);)g+=m,e++,m=a.charAt(e);\" \"===m&&(e++,m=a.charAt(e)),b+=String.fromCharCode(parseInt(g,16));continue}b+=m}}e++,m=a.charAt(e)}return b},q=function(){m=a.charAt(e);for(var b=!1;\" \"===m||\"\\t\"===m||\"\\n\"===m||\"\\r\"===m||\"\\f\"===m;)b=!0,e++,m=a.charAt(e);return b},this.parse=function(){var b=this.parseSelector();if(e<p)throw Error('Rule expected but \"'+a.charAt(e)+'\" found.');return b},this.parseSelector=function(){var b,c=b=this.parseSingleSelector();for(m=a.charAt(e);\",\"===m;){if(e++,q(),\"selectors\"!==b.type&&(b={type:\"selectors\",selectors:[c]}),!(c=this.parseSingleSelector()))throw Error('Rule expected after \",\".');b.selectors.push(c)}return b},this.parseSingleSelector=function(){q();var b={type:\"ruleSet\"},c=this.parseRule();if(!c)return null;for(var d=b;c&&(c.type=\"rule\",d.rule=c,d=c,q(),m=a.charAt(e),!(e>=p||\",\"===m||\")\"===m));)if(k[m]){var f=m;if(e++,q(),!(c=this.parseRule()))throw Error('Rule expected after \"'+f+'\".');c.nestingOperator=f}else(c=this.parseRule())&&(c.nestingOperator=null);return b},this.parseRule=function(){for(var c=null;e<p;)if(\"*\"===(m=a.charAt(e)))e++,(c=c||{}).tagName=\"*\";else if(b(m)||\"\\\\\"===m)(c=c||{}).tagName=n();else if(\".\"===m)e++,c=c||{},(c.classNames=c.classNames||[]).push(n());else if(\"#\"===m)e++,(c=c||{}).id=n();else if(\"[\"===m){e++,q();var d={name:n()};if(q(),\"]\"===m)e++;else{var f=\"\";if(j[m]&&(f=m,e++,m=a.charAt(e)),e>=p)throw Error('Expected \"=\" but end of file reached.');if(\"=\"!==m)throw Error('Expected \"=\" but \"'+m+'\" found.');d.operator=f+\"=\",e++,q();var k=\"\";if(d.valueType=\"string\",'\"'===m)k=o('\"',i);else if(\"'\"===m)k=o(\"'\",h);else if(l&&\"$\"===m)e++,k=n(),d.valueType=\"substitute\";else{for(;e<p&&\"]\"!==m;)k+=m,e++,m=a.charAt(e);k=k.trim()}if(q(),e>=p)throw Error('Expected \"]\" but end of file reached.');if(\"]\"!==m)throw Error('Expected \"]\" but \"'+m+'\" found.');e++,d.value=k}c=c||{},(c.attrs=c.attrs||[]).push(d)}else{if(\":\"!==m)break;e++;var r=n(),s={name:r};if(\"(\"===m){e++;var t=\"\";if(q(),\"selector\"===g[r])s.valueType=\"selector\",t=this.parseSelector();else{if(s.valueType=g[r]||\"string\",'\"'===m)t=o('\"',i);else if(\"'\"===m)t=o(\"'\",h);else if(l&&\"$\"===m)e++,t=n(),s.valueType=\"substitute\";else{for(;e<p&&\")\"!==m;)t+=m,e++,m=a.charAt(e);t=t.trim()}q()}if(e>=p)throw Error('Expected \")\" but end of file reached.');if(\")\"!==m)throw Error('Expected \")\" but \"'+m+'\" found.');e++,s.value=t}c=c||{},(c.pseudos=c.pseudos||[]).push(s)}return c},this}a.prototype.registerSelectorPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.pseudos[a]=\"selector\";return this},a.prototype.unregisterSelectorPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.pseudos[a];return this},a.prototype.registerNumericPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.pseudos[a]=\"numeric\";return this},a.prototype.unregisterNumericPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.pseudos[a];return this},a.prototype.registerNestingOperators=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.ruleNestingOperators[a]=!0;return this},a.prototype.unregisterNestingOperators=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.ruleNestingOperators[a];return this},a.prototype.registerAttrEqualityMods=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.attrEqualityMods[a]=!0;return this},a.prototype.unregisterAttrEqualityMods=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.attrEqualityMods[a];return this},a.prototype.enableSubstitutes=function(){return this.substitutesEnabled=!0,this},a.prototype.disableSubstitutes=function(){return this.substitutesEnabled=!1,this};var f={\"!\":!0,'\"':!0,\"#\":!0,$:!0,\"%\":!0,\"&\":!0,\"'\":!0,\"(\":!0,\")\":!0,\"*\":!0,\"+\":!0,\",\":!0,\".\":!0,\"/\":!0,\";\":!0,\"<\":!0,\"=\":!0,\">\":!0,\"?\":!0,\"@\":!0,\"[\":!0,\"\\\\\":!0,\"]\":!0,\"^\":!0,\"`\":!0,\"{\":!0,\"|\":!0,\"}\":!0,\"~\":!0},g={\"\\n\":\"\\\\n\",\"\\r\":\"\\\\r\",\"\\t\":\"\\\\t\",\"\\f\":\"\\\\f\",\"\\v\":\"\\\\v\"},h={n:\"\\n\",r:\"\\r\",t:\"\\t\",f:\"\\f\",\"\\\\\":\"\\\\\",\"'\":\"'\"},i={n:\"\\n\",r:\"\\r\",t:\"\\t\",f:\"\\f\",\"\\\\\":\"\\\\\",'\"':'\"'};a.prototype.parse=function(a){return new e(a,0,this.pseudos,this.attrEqualityMods,this.ruleNestingOperators,this.substitutesEnabled).parse()},a.prototype.escapeIdentifier=function(a){for(var b=\"\",c=0,d=a.length;c<d;){var e=a.charAt(c);if(f[e])b+=\"\\\\\"+e;else if(\"_\"===e||\"-\"===e||e>=\"A\"&&e<=\"Z\"||e>=\"a\"&&e<=\"z\"||0!==c&&e>=\"0\"&&e<=\"9\")b+=e;else{var g=e.charCodeAt(0);if(55296==(63488&g)){var h=a.charCodeAt(c++);if(55296!=(64512&g)||56320!=(64512&h))throw Error(\"UCS-2(decode): illegal sequence\");g=((1023&g)<<10)+(1023&h)+65536}b+=\"\\\\\"+g.toString(16)+\" \"}c++}return b},a.prototype.escapeStr=function(a){for(var b,c,d=\"\",e=0,f=a.length;e<f;)b=a.charAt(e),'\"'===b?b='\\\\\"':\"\\\\\"===b?b=\"\\\\\\\\\":(c=g[b])&&(b=c),d+=b,e++;return'\"'+d+'\"'},a.prototype.render=function(a){return this._renderEntity(a).trim()},a.prototype._renderEntity=function(a){var b,c,d;switch(d=\"\",a.type){case\"ruleSet\":for(b=a.rule,c=[];b;)b.nestingOperator&&c.push(b.nestingOperator),c.push(this._renderEntity(b)),b=b.rule;d=c.join(\" \");break;case\"selectors\":d=a.selectors.map(this._renderEntity,this).join(\", \");break;case\"rule\":a.tagName&&(d=\"*\"===a.tagName?\"*\":this.escapeIdentifier(a.tagName)),a.id&&(d+=\"#\"+this.escapeIdentifier(a.id)),a.classNames&&(d+=a.classNames.map(function(a){return\".\"+this.escapeIdentifier(a)},this).join(\"\")),a.attrs&&(d+=a.attrs.map(function(a){return a.operator?\"substitute\"===a.valueType?\"[\"+this.escapeIdentifier(a.name)+a.operator+\"$\"+a.value+\"]\":\"[\"+this.escapeIdentifier(a.name)+a.operator+this.escapeStr(a.value)+\"]\":\"[\"+this.escapeIdentifier(a.name)+\"]\"},this).join(\"\")),a.pseudos&&(d+=a.pseudos.map(function(a){return a.valueType?\"selector\"===a.valueType?\":\"+this.escapeIdentifier(a.name)+\"(\"+this._renderEntity(a.value)+\")\":\"substitute\"===a.valueType?\":\"+this.escapeIdentifier(a.name)+\"($\"+a.value+\")\":\"numeric\"===a.valueType?\":\"+this.escapeIdentifier(a.name)+\"(\"+a.value+\")\":\":\"+this.escapeIdentifier(a.name)+\"(\"+this.escapeIdentifier(a.value)+\")\":\":\"+this.escapeIdentifier(a.name)},this).join(\"\"));break;default:throw Error('Unknown entity type: \"'+a.type(NaN))}return d};var j=new a;j.registerNestingOperators(\">\"),axe.utils.cssParser=j}(axe),L.prototype={get selector(){return this.spec.selector||[axe.utils.getSelector(this.element,this._options)]},get xpath(){return this.spec.xpath||[axe.utils.getXpath(this.element)]},get element(){return this._element},get fromFrame(){return this._fromFrame},toJSON:function(){\"use strict\";return{selector:this.selector,source:this.source,xpath:this.xpath}}},L.fromFrame=function(a,b,c){return a.selector.unshift(c.selector),a.xpath.unshift(c.xpath),new axe.utils.DqElement(c.element,b,a)},axe.utils.DqElement=L,axe.utils.matchesSelector=function(){\"use strict\";function a(a){var b,c,d=a.Element.prototype,e=[\"matches\",\"matchesSelector\",\"mozMatchesSelector\",\"webkitMatchesSelector\",\"msMatchesSelector\"],f=e.length;for(b=0;b<f;b++)if(c=e[b],d[c])return c}var b;return function(c,d){return b&&c[b]||(b=a(c.ownerDocument.defaultView)),c[b](d)}}(),axe.utils.escapeSelector=function(a){\"use strict\";for(var b,c=String(a),d=c.length,e=-1,f=\"\",g=c.charCodeAt(0);++e<d;){if(0==(b=c.charCodeAt(e)))throw new Error(\"INVALID_CHARACTER_ERR\");b>=1&&b<=31||b>=127&&b<=159||0==e&&b>=48&&b<=57||1==e&&b>=48&&b<=57&&45==g?f+=\"\\\\\"+b.toString(16)+\" \":f+=(1!=e||45!=b||45!=g)&&(b>=128||45==b||95==b||b>=48&&b<=57||b>=65&&b<=90||b>=97&&b<=122)?c.charAt(e):\"\\\\\"+c.charAt(e)}return f},axe.utils.extendMetaData=function(a,b){Object.assign(a,b),Object.keys(b).filter(function(a){return\"function\"==typeof b[a]}).forEach(function(c){a[c]=null;try{a[c]=b[c](a)}catch(a){}})},axe.utils.finalizeRuleResult=function(a){return Object.assign(a,axe.utils.aggregateNodeResults(a.nodes)),delete a.nodes,a};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.findBy=function(a,b,c){if(Array.isArray(a))return a.find(function(a){return\"object\"===(void 0===a?\"undefined\":za(a))&&a[b]===c})};var axe=axe||{utils:{}};axe.utils.getFlattenedTree=function(a,b){function c(a,c){var d=axe.utils.getFlattenedTree(c,b);return d&&(a=a.concat(d)),a}var d,e,f;if(a.documentElement&&(a=a.documentElement),f=a.nodeName.toLowerCase(),axe.utils.isShadowRoot(a))return d=M(a,b),b=\"a\"+Math.random().toString().substring(2),e=Array.from(a.shadowRoot.childNodes),d.children=e.reduce(c,[]),[d];if(\"content\"===f)return e=Array.from(a.getDistributedNodes()),e.reduce(c,[]);if(\"slot\"===f){e=Array.from(a.assignedNodes()),e.length||(e=N(a));window.getComputedStyle(a);return e.reduce(c,[])}return 1===a.nodeType?(d=M(a,b),e=Array.from(a.childNodes),d.children=e.reduce(c,[]),[d]):3===a.nodeType?[M(a)]:void 0},axe.utils.getNodeFromTree=function(a,b){var c;return a.actualNode===b?a:(a.children.forEach(function(a){var d;a.actualNode===b?c=a:(d=axe.utils.getNodeFromTree(a,b))&&(c=d)}),c)},axe.utils.getAllChecks=function(a){\"use strict\";return[].concat(a.any||[]).concat(a.all||[]).concat(a.none||[])},axe.utils.getCheckOption=function(a,b,c){var d=((c.rules&&c.rules[b]||{}).checks||{})[a.id],e=(c.checks||{})[a.id],f=a.enabled,g=a.options;return e&&(e.hasOwnProperty(\"enabled\")&&(f=e.enabled),e.hasOwnProperty(\"options\")&&(g=e.options)),d&&(d.hasOwnProperty(\"enabled\")&&(f=d.enabled),d.hasOwnProperty(\"options\")&&(g=d.options)),{enabled:f,options:g,absolutePaths:c.absolutePaths}};var Ka=function(){function a(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g,h=a[Symbol.iterator]();!(d=(g=h.next()).done)&&(c.push(g.value),!b||c.length!==b);d=!0);}catch(a){e=!0,f=a}finally{try{!d&&h.return&&h.return()}finally{if(e)throw f}}return c}return function(b,c){if(Array.isArray(b))return b;if(Symbol.iterator in Object(b))return a(b,c);throw new TypeError(\"Invalid attempt to destructure non-iterable instance\")}}();axe.utils.getFriendlyUriEnd=function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\",b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!(a.length<=1||\"data:\"===a.substr(0,5)||\"javascript:\"===a.substr(0,11)||a.includes(\"?\"))){var c=b.currentDomain,d=b.maxLength,e=void 0===d?25:d,f=Q(a),g=f.path,h=f.domain,i=f.hash,j=g.substr(g.substr(0,g.length-2).lastIndexOf(\"/\")+1);if(i)return j&&(j+i).length<=e?j+i:j.length<2&&i.length>2&&i.length<=e?i:void 0;if(h&&h.length<e&&g.length<=1)return h+g;if(g===\"/\"+j&&h&&c&&h!==c&&(h+g).length<=e)return h+g;var k=j.lastIndexOf(\".\");return(-1===k||k>1)&&(-1!==k||j.length>2)&&j.length<=e&&!j.match(/index(\\.[a-zA-Z]{2-4})?/)&&!O(j)?j:void 0}};var La=axe.utils.escapeSelector,Ma=void 0,Na=[\"class\",\"style\",\"id\",\"selected\",\"checked\",\"disabled\",\"tabindex\",\"aria-checked\",\"aria-selected\",\"aria-invalid\",\"aria-activedescendant\",\"aria-busy\",\"aria-disabled\",\"aria-expanded\",\"aria-grabbed\",\"aria-pressed\",\"aria-valuenow\"],Oa=31;axe.utils.getSelectorData=function(a){var b={classes:{},tags:{},attributes:{}};a=Array.isArray(a)?a:[a];for(var c=a.slice(),d=[];c.length;)!function(){var a=c.pop(),e=a.actualNode;if(e.querySelectorAll){var f=e.nodeName;b.tags[f]?b.tags[f]++:b.tags[f]=1,e.classList&&Array.from(e.classList).forEach(function(a){var c=La(a);b.classes[c]?b.classes[c]++:b.classes[c]=1}),e.attributes&&Array.from(e.attributes).filter(T).forEach(function(a){var c=R(e,a);c&&(b.attributes[c]?b.attributes[c]++:b.attributes[c]=1)})}for(a.children.length&&(d.push(c),c=a.children.slice());!c.length&&d.length;)c=d.pop()}();return b},axe.utils.getSelector=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!a)return\"\";var c=a.getRootNode&&a.getRootNode()||document;if(11===c.nodeType){for(var d=[];11===c.nodeType;)d.push({elm:a,doc:c}),a=c.host,c=a.getRootNode();return d.push({elm:a,doc:c}),d.reverse().map(function(a){return $(a.elm,b,a.doc)})}return $(a,b,c)},axe.utils.getXpath=function(a){return aa(_(a))};var Pa;axe.utils.injectStyle=ba,axe.utils.isHidden=function(a,b){\"use strict\";var c;if(9===a.nodeType)return!1;11===a.nodeType&&(a=a.host);var d=window.getComputedStyle(a,null);return!d||!a.parentNode||\"none\"===d.getPropertyValue(\"display\")||!b&&\"hidden\"===d.getPropertyValue(\"visibility\")||\"true\"===a.getAttribute(\"aria-hidden\")||(c=a.assignedSlot?a.assignedSlot:a.parentNode,axe.utils.isHidden(c,!0))};var Qa=[\"article\",\"aside\",\"blockquote\",\"body\",\"div\",\"footer\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"main\",\"nav\",\"p\",\"section\",\"span\"];axe.utils.isShadowRoot=function(a){var b=a.nodeName.toLowerCase();return!(!a.shadowRoot||!/^[a-z][a-z0-9_.-]*-[a-z0-9_.-]*$/.test(b)&&!Qa.includes(b))},axe.utils.isXHTML=function(a){\"use strict\";return!!a.createElement&&\"A\"===a.createElement(\"A\").localName},axe.utils.mergeResults=function(a,b){\"use strict\";var c=[];return a.forEach(function(a){var d=ea(a);d&&d.length&&d.forEach(function(d){d.nodes&&a.frame&&ca(d.nodes,b,a.frameElement,a.frame);var e=axe.utils.findBy(c,\"id\",d.id);e?d.nodes.length&&da(e.nodes,d.nodes):c.push(d)})}),c},axe.utils.nodeSorter=function(a,b){\"use strict\";return a.actualNode===b.actualNode?0:4&a.actualNode.compareDocumentPosition(b.actualNode)?-1:1},utils.performanceTimer=function(){\"use strict\";function a(){if(window.performance&&window.performance)return window.performance.now()}var b=null,c=a();return{start:function(){this.mark(\"mark_axe_start\")},end:function(){this.mark(\"mark_axe_end\"),this.measure(\"axe\",\"mark_axe_start\",\"mark_axe_end\"),this.logMeasures(\"axe\")},auditStart:function(){this.mark(\"mark_audit_start\")},auditEnd:function(){this.mark(\"mark_audit_end\"),this.measure(\"audit_start_to_end\",\"mark_audit_start\",\"mark_audit_end\"),this.logMeasures()},mark:function(a){window.performance&&void 0!==window.performance.mark&&window.performance.mark(a)},measure:function(a,b,c){window.performance&&void 0!==window.performance.measure&&window.performance.measure(a,b,c)},logMeasures:function(a){function b(a){axe.log(\"Measure \"+a.name+\" took \"+a.duration+\"ms\")}if(window.performance&&void 0!==window.performance.getEntriesByType)for(var c=window.performance.getEntriesByType(\"measure\"),d=0;d<c.length;++d){var e=c[d];if(e.name===a)return void b(e);b(e)}},timeElapsed:function(){return a()-c},reset:function(){b||(b=a()),c=a()}}}(),\"function\"!=typeof Object.assign&&function(){Object.assign=function(a){\"use strict\";if(void 0===a||null===a)throw new TypeError(\"Cannot convert undefined or null to object\");for(var b=Object(a),c=1;c<arguments.length;c++){var d=arguments[c];if(void 0!==d&&null!==d)for(var e in d)d.hasOwnProperty(e)&&(b[e]=d[e])}return b}}(),Array.prototype.find||Object.defineProperty(Array.prototype,\"find\",{value:function(a){if(null===this)throw new TypeError(\"Array.prototype.find called on null or undefined\");if(\"function\"!=typeof a)throw new TypeError(\"predicate must be a function\");for(var b,c=Object(this),d=c.length>>>0,e=arguments[1],f=0;f<d;f++)if(b=c[f],a.call(e,b,f,c))return b}}),axe.utils.pollyfillElementsFromPoint=function(){if(document.elementsFromPoint)return document.elementsFromPoint;if(document.msElementsFromPoint)return document.msElementsFromPoint;var a=function(){var a=document.createElement(\"x\");return a.style.cssText=\"pointer-events:auto\",\"auto\"===a.style.pointerEvents}(),b=a?\"pointer-events\":\"visibility\",c=a?\"none\":\"hidden\",d=document.createElement(\"style\");return d.innerHTML=a?\"* { pointer-events: all }\":\"* { visibility: visible }\",function(a,e){var f,g,h,i=[],j=[];for(document.head.appendChild(d);(f=document.elementFromPoint(a,e))&&-1===i.indexOf(f);)i.push(f),j.push({value:f.style.getPropertyValue(b),priority:f.style.getPropertyPriority(b)}),f.style.setProperty(b,c,\"important\");for(i.indexOf(document.documentElement)<i.length-1&&(i.splice(i.indexOf(document.documentElement),1),i.push(document.documentElement)),g=j.length;h=j[--g];)i[g].style.setProperty(b,h.value?h.value:\"\",h.priority);return document.head.removeChild(d),i}},\"function\"==typeof window.addEventListener&&(document.elementsFromPoint=axe.utils.pollyfillElementsFromPoint()),Array.prototype.includes||Object.defineProperty(Array.prototype,\"includes\",{value:function(a){\"use strict\";var b=Object(this),c=parseInt(b.length,10)||0;if(0===c)return!1;var d,e=parseInt(arguments[1],10)||0;e>=0?d=e:(d=c+e)<0&&(d=0);for(var f;d<c;){if(f=b[d],a===f||a!==a&&f!==f)return!0;d++}return!1}}),Array.prototype.some||Object.defineProperty(Array.prototype,\"some\",{value:function(a){\"use strict\";if(null==this)throw new TypeError(\"Array.prototype.some called on null or undefined\");if(\"function\"!=typeof a)throw new TypeError;for(var b=Object(this),c=b.length>>>0,d=arguments.length>=2?arguments[1]:void 0,e=0;e<c;e++)if(e in b&&a.call(d,b[e],e,b))return!0;return!1}}),Array.from||Object.defineProperty(Array,\"from\",{value:function(){var a=Object.prototype.toString,b=function(b){return\"function\"==typeof b||\"[object Function]\"===a.call(b)},c=function(a){var b=Number(a);return isNaN(b)?0:0!==b&&isFinite(b)?(b>0?1:-1)*Math.floor(Math.abs(b)):b},d=Math.pow(2,53)-1,e=function(a){var b=c(a);return Math.min(Math.max(b,0),d)};return function(a){var c=this,d=Object(a);if(null==a)throw new TypeError(\"Array.from requires an array-like object - not null or undefined\");var f,g=arguments.length>1?arguments[1]:void 0;if(void 0!==g){if(!b(g))throw new TypeError(\"Array.from: when provided, the second argument must be a function\");arguments.length>2&&(f=arguments[2])}for(var h,i=e(d.length),j=b(c)?Object(new c(i)):new Array(i),k=0;k<i;)h=d[k],j[k]=g?void 0===f?g(h,k):g.call(f,h,k):h,k+=1;return j.length=i,j}}()}),String.prototype.includes||(String.prototype.includes=function(a,b){return\"number\"!=typeof b&&(b=0),!(b+a.length>this.length)&&-1!==this.indexOf(a,b)});var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.publishMetaData=function(a){\"use strict\";var b=axe._audit.data.checks||{},c=axe._audit.data.rules||{},d=axe.utils.findBy(axe._audit.rules,\"id\",a.id)||{};a.tags=axe.utils.clone(d.tags||[]);var e=ga(b,!0),f=ga(b,!1);a.nodes.forEach(function(a){a.any.forEach(e),a.all.forEach(e),a.none.forEach(f)}),axe.utils.extendMetaData(a,axe.utils.clone(c[a.id]||{}))};var Ra=function(){},Sa=function(){},Ta=function(){/*! Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License */\nvar a=/(?=[\\-\\[\\]{}()*+?.\\\\\\^$|,#\\s])/g;return function(b){return b.replace(a,\"\\\\\")}}(),Ua=/\\\\/g;Ra=function(a){return a.map(function(a){for(var b=[],c=a.rule;c;)b.push({tag:c.tagName?c.tagName.toLowerCase():\"*\",combinator:c.nestingOperator?c.nestingOperator:\" \",id:c.id,attributes:ma(c.attrs),classes:na(c.classNames),pseudos:oa(c.pseudos)}),c=c.rule;return b})},Sa=function(a,b,c,d){for(var e=[],f=Array.isArray(a)?a:[a],g=pa(f,b,[],a[0].shadowId),h=[];g.nodes.length;){for(var i=g.nodes.pop(),j=[],k=[],l=g.anyLevel.slice().concat(g.thisLevel),m=!1,n=0;n<l.length;n++){var o=l[n];if(qa(i,o)&&(!o[0].id||i.shadowId===g.parentShadowId))if(1===o.length)m||d&&!d(i)||(h.push(i),m=!0);else{var p=o.slice(1);if(!1===[\" \",\">\"].includes(p[0].combinator))throw new Error(\"axe.utils.querySelectorAll does not support the combinator: \"+o[1].combinator);\">\"===p[0].combinator?j.push(p):k.push(p)}!g.anyLevel.includes(o)||o[0].id&&i.shadowId!==g.parentShadowId||k.push(o)}for(i.children&&i.children.length&&c&&(e.push(g),g=pa(i.children,k,j,i.shadowId));!g.nodes.length&&e.length;)g=e.pop()}return h},axe.utils.querySelectorAll=function(a,b){return axe.utils.querySelectorAllFilter(a,b)},axe.utils.querySelectorAllFilter=function(a,b,c){a=Array.isArray(a)?a:[a];var d=axe.utils.cssParser.parse(b);return d=d.selectors?d.selectors:[d],d=Ra(d),Sa(a,d,!0,c)};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};!function(){\"use strict\";function a(){}function b(a){if(\"function\"!=typeof a)throw new TypeError(\"Queue methods require functions as arguments\")}function c(){function c(b){return function(c){g[b]=c,(i-=1)||j===a||(k=!0,j(g))}}function d(b){return j=a,m(b),g}function e(){for(var a=g.length;h<a;h++){var b=g[h];try{b.call(null,c(h),d)}catch(a){d(a)}}}var f,g=[],h=0,i=0,j=a,k=!1,l=function(a){f=a,setTimeout(function(){void 0!==f&&null!==f&&axe.log(\"Uncaught error (of queue)\",f)},1)},m=l,n={defer:function(a){if(\"object\"===(void 0===a?\"undefined\":za(a))&&a.then&&a.catch){var c=a;a=function(a,b){c.then(a).catch(b)}}if(b(a),void 0===f){if(k)throw new Error(\"Queue already completed\");return g.push(a),++i,e(),n}},then:function(c){if(b(c),j!==a)throw new Error(\"queue `then` already set\");return f||(j=c,i||(k=!0,j(g))),n},catch:function(a){if(b(a),m!==l)throw new Error(\"queue `catch` already set\");return f?(a(f),f=null):m=a,n},abort:d};return n}axe.utils.queue=c}();var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};!function(a){\"use strict\";function b(){var a=\"axe\",b=\"\";return void 0!==axe&&axe._audit&&!axe._audit.application&&(a=axe._audit.application),void 0!==axe&&(b=axe.version),a+\".\"+b}function c(a){if(\"object\"===(void 0===a?\"undefined\":za(a))&&\"string\"==typeof a.uuid&&!0===a._respondable){var c=b();return a._source===c||\"axe.x.y.z\"===a._source||\"axe.x.y.z\"===c}return!1}function d(a,c,d,e,f,g){var h;d instanceof Error&&(h={name:d.name,message:d.message,stack:d.stack},d=void 0);var i={uuid:e,topic:c,message:d,error:h,_respondable:!0,_source:b(),_keepalive:f};\"function\"==typeof g&&(j[e]=g),a.postMessage(JSON.stringify(i),\"*\")}function e(a,b,c,e,f){d(a,b,c,Va.v1(),e,f)}function f(a,b,c){return function(e,f,g){d(a,b,e,c,f,g)}}function g(a,b,c){var d=b.topic,e=k[d];if(e){var g=f(a,null,b.uuid);e(b.message,c,g)}}function h(a){var b=a.message||\"Unknown error occurred\",c=l.includes(a.name)?a.name:\"Error\",d=window[c]||Error;return a.stack&&(b+=\"\\n\"+a.stack.replace(a.message,\"\")),new d(b)}function i(a){var b;if(\"string\"==typeof a){try{b=JSON.parse(a)}catch(a){}if(c(b))return\"object\"===za(b.error)?b.error=h(b.error):b.error=void 0,b}}var j={},k={},l=Object.freeze([\"EvalError\",\"RangeError\",\"ReferenceError\",\"SyntaxError\",\"TypeError\",\"URIError\"]);e.subscribe=function(a,b){k[a]=b},e.isInFrame=function(a){return a=a||window,!!a.frameElement},\"function\"==typeof window.addEventListener&&window.addEventListener(\"message\",function(a){var b=i(a.data);if(b){var c=b.uuid,e=b._keepalive,h=j[c];if(h){h(b.error||b.message,e,f(a.source,b.topic,c)),e||delete j[c]}if(!b.error)try{g(a.source,b,e)}catch(e){d(a.source,b.topic,e,c,!1)}}},!1),a.respondable=e}(utils),axe.utils.ruleShouldRun=function(a,b,c){\"use strict\";var d=c.runOnly||{},e=(c.rules||{})[a.id];return!(a.pageLevel&&!b.page)&&(\"rule\"===d.type?-1!==d.values.indexOf(a.id):e&&\"boolean\"==typeof e.enabled?e.enabled:\"tag\"===d.type&&d.values?ra(a,d.values):ra(a,[]))},axe.utils.getScrollState=function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window,b=a.document.documentElement;return[void 0!==a.pageXOffset?{elm:a,top:a.pageYOffset,left:a.pageXOffset}:{elm:b,top:b.scrollTop,left:b.scrollLeft}].concat(ua(document.body))},axe.utils.setScrollState=function(a){a.forEach(function(a){return ta(a.elm,a.top,a.left)})},axe.utils.select=function(a,b){\"use strict\";var c,d=[];if(axe._selectCache)for(var e=0,f=axe._selectCache.length;e<f;e++){var g=axe._selectCache[e];if(g.selector===a)return g.result}for(var h=function(a){return function(b){return wa(b,a)}}(b),i=ya(b.include),j=0;j<i.length;j++)c=i[j],c.actualNode.nodeType===c.actualNode.ELEMENT_NODE&&axe.utils.matchesSelector(c.actualNode,a)&&h(c)&&(d=xa(d,[c])),d=xa(d,axe.utils.querySelectorAllFilter(c,a,h));return axe._selectCache&&axe._selectCache.push({selector:a,result:d}),d},axe.utils.toArray=function(a){\"use strict\";return Array.prototype.slice.call(a)},axe.utils.uniqueArray=function(a,b){return a.concat(b).filter(function(a,b,c){return c.indexOf(a)===b})};var Va;!function(a){function b(a,b,c){var d=b&&c||0,e=0;for(b=b||[],a.toLowerCase().replace(/[0-9a-f]{2}/g,function(a){e<16&&(b[d+e++]=l[a])});e<16;)b[d+e++]=0;return b}function c(a,b){var c=b||0,d=k;return d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]}function d(a,b,d){var e=b&&d||0,f=b||[];a=a||{};var g=null!=a.clockseq?a.clockseq:p,h=null!=a.msecs?a.msecs:(new Date).getTime(),i=null!=a.nsecs?a.nsecs:r+1,j=h-q+(i-r)/1e4;if(j<0&&null==a.clockseq&&(g=g+1&16383),(j<0||h>q)&&null==a.nsecs&&(i=0),i>=1e4)throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");q=h,r=i,p=g,h+=122192928e5;var k=(1e4*(268435455&h)+i)%4294967296;f[e++]=k>>>24&255,f[e++]=k>>>16&255,f[e++]=k>>>8&255,f[e++]=255&k;var l=h/4294967296*1e4&268435455;f[e++]=l>>>8&255,f[e++]=255&l,f[e++]=l>>>24&15|16,f[e++]=l>>>16&255,f[e++]=g>>>8|128,f[e++]=255&g;for(var m=a.node||o,n=0;n<6;n++)f[e+n]=m[n];return b||c(f)}function e(a,b,d){var e=b&&d||0;\"string\"==typeof a&&(b=\"binary\"==a?new j(16):null,a=null),a=a||{};var g=a.random||(a.rng||f)();if(g[6]=15&g[6]|64,g[8]=63&g[8]|128,b)for(var h=0;h<16;h++)b[e+h]=g[h];return b||c(g)}var f,g=a.crypto||a.msCrypto;if(!f&&g&&g.getRandomValues){var h=new Uint8Array(16);f=function(){return g.getRandomValues(h),h}}if(!f){var i=new Array(16);f=function(){for(var a,b=0;b<16;b++)0==(3&b)&&(a=4294967296*Math.random()),i[b]=a>>>((3&b)<<3)&255;return i}}for(var j=\"function\"==typeof a.Buffer?a.Buffer:Array,k=[],l={},m=0;m<256;m++)k[m]=(m+256).toString(16).substr(1),l[k[m]]=m;var n=f(),o=[1|n[0],n[1],n[2],n[3],n[4],n[5]],p=16383&(n[6]<<8|n[7]),q=0,r=0;Va=e,Va.v1=d,Va.v4=e,Va.parse=b,Va.unparse=c,Va.BufferClass=j}(window),axe._load({data:{rules:{accesskeys:{description:\"Ensures every accesskey attribute value is unique\",help:\"accesskey attribute value must be unique\"},\"area-alt\":{description:\"Ensures <area> elements of image maps have alternate text\",help:\"Active <area> elements must have alternate text\"},\"aria-allowed-attr\":{description:\"Ensures ARIA attributes are allowed for an element's role\",help:\"Elements must only use allowed ARIA attributes\"},\"aria-hidden-body\":{description:\"Ensures aria-hidden='true' is not present on the document body.\",help:\"aria-hidden='true' must not be present on the document body\"},\"aria-required-attr\":{description:\"Ensures elements with ARIA roles have all required ARIA attributes\",help:\"Required ARIA attributes must be provided\"},\"aria-required-children\":{description:\"Ensures elements with an ARIA role that require child roles contain them\",help:\"Certain ARIA roles must contain particular children\"},\"aria-required-parent\":{description:\"Ensures elements with an ARIA role that require parent roles are contained by them\",help:\"Certain ARIA roles must be contained by particular parents\"},\"aria-roles\":{description:\"Ensures all elements with a role attribute use a valid value\",help:\"ARIA roles used must conform to valid values\"},\"aria-valid-attr-value\":{description:\"Ensures all ARIA attributes have valid values\",help:\"ARIA attributes must conform to valid values\"},\"aria-valid-attr\":{description:\"Ensures attributes that begin with aria- are valid ARIA attributes\",help:\"ARIA attributes must conform to valid names\"},\"audio-caption\":{description:\"Ensures <audio> elements have captions\",help:\"<audio> elements must have a captions track\"},blink:{description:\"Ensures <blink> elements are not used\",help:\"<blink> elements are deprecated and must not be used\"},\"button-name\":{description:\"Ensures buttons have discernible text\",help:\"Buttons must have discernible text\"},bypass:{description:\"Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content\",help:\"Page must have means to bypass repeated blocks\"},checkboxgroup:{description:'Ensures related <input type=\"checkbox\"> elements have a group and that that group designation is consistent',help:\"Checkbox inputs with the same name attribute value must be part of a group\"},\"color-contrast\":{description:\"Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds\",help:\"Elements must have sufficient color contrast\"},\"definition-list\":{description:\"Ensures <dl> elements are structured correctly\",help:\"<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script> or <template> elements\"},dlitem:{description:\"Ensures <dt> and <dd> elements are contained by a <dl>\",help:\"<dt> and <dd> elements must be contained by a <dl>\"},\"document-title\":{description:\"Ensures each HTML document contains a non-empty <title> element\",help:\"Documents must have <title> element to aid in navigation\"},\"duplicate-id\":{description:\"Ensures every id attribute value is unique\",help:\"id attribute value must be unique\"},\"empty-heading\":{description:\"Ensures headings have discernible text\",help:\"Headings must not be empty\"},\"focus-order-semantics\":{description:\"Ensures elements in the focus order have an appropriate role\",help:\"Elements in the focus order need a role appropriate for interactive content\"},\"frame-title-unique\":{description:\"Ensures <iframe> and <frame> elements contain a unique title attribute\",help:\"Frames must have a unique title attribute\"},\"frame-title\":{description:\"Ensures <iframe> and <frame> elements contain a non-empty title attribute\",help:\"Frames must have title attribute\"},\"heading-order\":{description:\"Ensures the order of headings is semantically correct\",help:\"Heading levels should only increase by one\"},\"hidden-content\":{description:\"Informs users about hidden content.\",help:\"Hidden content on the page cannot be analyzed\"},\"html-has-lang\":{description:\"Ensures every HTML document has a lang attribute\",help:\"<html> element must have a lang attribute\"},\"html-lang-valid\":{description:\"Ensures the lang attribute of the <html> element has a valid value\",help:\"<html> element must have a valid value for the lang attribute\"},\"image-alt\":{description:\"Ensures <img> elements have alternate text or a role of none or presentation\",help:\"Images must have alternate text\"},\"image-redundant-alt\":{description:\"Ensure button and link text is not repeated as image alternative\",help:\"Text of buttons and links should not be repeated in the image alternative\"},\"input-image-alt\":{description:'Ensures <input type=\"image\"> elements have alternate text',help:\"Image buttons must have alternate text\"},\"label-title-only\":{description:\"Ensures that every form element is not solely labeled using the title or aria-describedby attributes\",help:\"Form elements should have a visible label\"},label:{description:\"Ensures every form element has a label\",help:\"Form elements must have labels\"},\"landmark-main-is-top-level\":{description:\"The main landmark should not be contained in another landmark\",help:\"Main landmark is not at top level\"},\"landmark-one-main\":{description:\"Ensures a navigation point to the primary content of the page. If the page contains iframes, each iframe should contain either no main landmarks or just one.\",help:\"Page must contain one main landmark.\"},\"layout-table\":{description:\"Ensures presentational <table> elements do not use <th>, <caption> elements or the summary attribute\",help:\"Layout tables must not use data table elements\"},\"link-in-text-block\":{description:\"Links can be distinguished without relying on color\",help:\"Links must be distinguished from surrounding text in a way that does not rely on color\"},\"link-name\":{description:\"Ensures links have discernible text\",help:\"Links must have discernible text\"},list:{description:\"Ensures that lists are structured correctly\",help:\"<ul> and <ol> must only directly contain <li>, <script> or <template> elements\"},listitem:{description:\"Ensures <li> elements are used semantically\",help:\"<li> elements must be contained in a <ul> or <ol>\"},marquee:{description:\"Ensures <marquee> elements are not used\",help:\"<marquee> elements are deprecated and must not be used\"},\"meta-refresh\":{description:'Ensures <meta http-equiv=\"refresh\"> is not used',help:\"Timed refresh must not exist\"},\"meta-viewport-large\":{description:'Ensures <meta name=\"viewport\"> can scale a significant amount',help:\"Users should be able to zoom and scale the text up to 500%\"},\"meta-viewport\":{description:'Ensures <meta name=\"viewport\"> does not disable text scaling and zooming',help:\"Zooming and scaling must not be disabled\"},\"object-alt\":{description:\"Ensures <object> elements have alternate text\",help:\"<object> elements must have alternate text\"},\"p-as-heading\":{description:\"Ensure p elements are not used to style headings\",help:\"Bold, italic text and font-size are not used to style p elements as a heading\"},radiogroup:{description:'Ensures related <input type=\"radio\"> elements have a group and that the group designation is consistent',help:\"Radio inputs with the same name attribute value must be part of a group\"},region:{description:\"Ensures all content is contained within a landmark region\",help:\"Content should be contained in a landmark region\"},\"scope-attr-valid\":{description:\"Ensures the scope attribute is used correctly on tables\",help:\"scope attribute should be used correctly\"},\"server-side-image-map\":{description:\"Ensures that server-side image maps are not used\",help:\"Server-side image maps must not be used\"},\"skip-link\":{description:\"Ensure all skip links have a focusable target\",help:\"The skip-link target should exist and be focusable\"},tabindex:{description:\"Ensures tabindex attribute values are not greater than 0\",help:\"Elements should not have tabindex greater than zero\"},\"table-duplicate-name\":{description:\"Ensure that tables do not have the same summary and caption\",help:\"The <caption> element should not contain the same text as the summary attribute\"},\"table-fake-caption\":{description:\"Ensure that tables with a caption use the <caption> element.\",help:\"Data or header cells should not be used to give caption to a data table.\"},\"td-has-header\":{description:\"Ensure that each non-empty data cell in a large table has one or more table headers\",help:\"All non-empty td element in table larger than 3 by 3 must have an associated table header\"},\"td-headers-attr\":{description:\"Ensure that each cell in a table using the headers refers to another cell in that table\",help:\"All cells in a table element that use the headers attribute must only refer to other cells of that same table\"},\"th-has-data-cells\":{description:\"Ensure that each table header in a data table refers to data cells\",help:\"All th elements and elements with role=columnheader/rowheader must have data cells they describe\"},\"valid-lang\":{description:\"Ensures lang attributes have valid values\",help:\"lang attribute must have a valid value\"},\"video-caption\":{description:\"Ensures <video> elements have captions\",help:\"<video> elements must have captions\"},\"video-description\":{description:\"Ensures <video> elements have audio descriptions\",help:\"<video> elements must have an audio description track\"}},checks:{accesskeys:{impact:\"serious\",messages:{pass:function(a){return\"Accesskey attribute value is unique\"},fail:function(a){return\"Document has multiple elements with the same accesskey\"}}},\"non-empty-alt\":{impact:\"critical\",messages:{pass:function(a){return\"Element has a non-empty alt attribute\"},fail:function(a){return\"Element has no alt attribute or the alt attribute is empty\"}}},\"non-empty-title\":{impact:\"serious\",messages:{pass:function(a){return\"Element has a title attribute\"},fail:function(a){return\"Element has no title attribute or the title attribute is empty\"}}},\"aria-label\":{impact:\"serious\",messages:{pass:function(a){return\"aria-label attribute exists and is not empty\"},fail:function(a){return\"aria-label attribute does not exist or is empty\"}}},\"aria-labelledby\":{impact:\"serious\",messages:{pass:function(a){return\"aria-labelledby attribute exists and references elements that are visible to screen readers\"},fail:function(a){return\"aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty or not visible\"}}},\"aria-allowed-attr\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attributes are used correctly for the defined role\"},fail:function(a){var b=\"ARIA attribute\"+(a.data&&a.data.length>1?\"s are\":\" is\")+\" not allowed:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-hidden-body\":{impact:\"critical\",messages:{pass:function(a){return\"No aria-hidden attribute is present on document body\"},fail:function(a){return\"aria-hidden=true should not be present on the document body\"}}},\"aria-required-attr\":{impact:\"critical\",messages:{pass:function(a){return\"All required ARIA attributes are present\"},fail:function(a){var b=\"Required ARIA attribute\"+(a.data&&a.data.length>1?\"s\":\"\")+\" not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-required-children\":{impact:\"critical\",messages:{pass:function(a){return\"Required ARIA children are present\"},fail:function(a){var b=\"Required ARIA \"+(a.data&&a.data.length>1?\"children\":\"child\")+\" role not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-required-parent\":{impact:\"critical\",messages:{pass:function(a){return\"Required ARIA parent role present\"},fail:function(a){var b=\"Required ARIA parent\"+(a.data&&a.data.length>1?\"s\":\"\")+\" role not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},invalidrole:{impact:\"critical\",messages:{pass:function(a){return\"ARIA role is valid\"},fail:function(a){return\"Role must be one of the valid ARIA roles\"}}},abstractrole:{impact:\"serious\",messages:{pass:function(a){return\"Abstract roles are not used\"},fail:function(a){return\"Abstract roles cannot be directly used\"}}},\"aria-valid-attr-value\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attribute values are valid\"},fail:function(a){var b=\"Invalid ARIA attribute value\"+(a.data&&a.data.length>1?\"s\":\"\")+\":\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-errormessage\":{impact:\"critical\",messages:{pass:function(a){return\"Uses a supported aria-errormessage technique\"},fail:function(a){var b=\"aria-errormessage value\"+(a.data&&a.data.length>1?\"s\":\"\")+\" \",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" `\"+d;return b+=\"` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)\"}}},\"aria-valid-attr\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attribute name\"+(a.data&&a.data.length>1?\"s\":\"\")+\" are valid\"},fail:function(a){var b=\"Invalid ARIA attribute name\"+(a.data&&a.data.length>1?\"s\":\"\")+\":\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},caption:{impact:\"critical\",messages:{pass:function(a){return\"The multimedia element has a captions track\"},fail:function(a){return\"The multimedia element does not have a captions track\"},incomplete:function(a){return\"A captions track for this element could not be found\"}}},\"is-on-screen\":{impact:\"serious\",messages:{pass:function(a){return\"Element is not visible\"},fail:function(a){return\"Element is visible\"}}},\"non-empty-if-present\":{impact:\"critical\",messages:{pass:function(a){var b=\"Element \";return a.data?b+=\"has a non-empty value attribute\":b+=\"does not have a value attribute\",b},fail:function(a){return\"Element has a value attribute and the value attribute is empty\"}}},\"non-empty-value\":{impact:\"critical\",messages:{pass:function(a){return\"Element has a non-empty value attribute\"},fail:function(a){return\"Element has no value attribute or the value attribute is empty\"}}},\"button-has-visible-text\":{impact:\"critical\",messages:{pass:function(a){return\"Element has inner text that is visible to screen readers\"},fail:function(a){return\"Element does not have inner text that is visible to screen readers\"}}},\"role-presentation\":{impact:\"minor\",messages:{pass:function(a){return'Element\\'s default semantics were overriden with role=\"presentation\"'},fail:function(a){return'Element\\'s default semantics were not overridden with role=\"presentation\"'}}},\"role-none\":{impact:\"minor\",messages:{pass:function(a){return'Element\\'s default semantics were overriden with role=\"none\"'},fail:function(a){return'Element\\'s default semantics were not overridden with role=\"none\"'}}},\"focusable-no-name\":{impact:\"serious\",messages:{pass:function(a){return\"Element is not in tab order or has accessible text\"},fail:function(a){return\"Element is in tab order and does not have accessible text\"}}},\"internal-link-present\":{impact:\"serious\",messages:{pass:function(a){return\"Valid skip link found\"},fail:function(a){return\"No valid skip link found\"}}},\"header-present\":{impact:\"serious\",messages:{pass:function(a){return\"Page has a header\"},fail:function(a){return\"Page does not have a header\"}}},landmark:{impact:\"serious\",messages:{pass:function(a){return\"Page has a landmark region\"},fail:function(a){return\"Page does not have a landmark region\"}}},\"group-labelledby\":{impact:\"critical\",messages:{pass:function(a){return'All elements with the name \"'+a.data.name+'\" reference the same element with aria-labelledby'},fail:function(a){return'All elements with the name \"'+a.data.name+'\" do not reference the same element with aria-labelledby'}}},fieldset:{impact:\"critical\",messages:{pass:function(a){return\"Element is contained in a fieldset\"},fail:function(a){var b=\"\",c=a.data&&a.data.failureCode;return b+=\"no-legend\"===c?\"Fieldset does not have a legend as its first child\":\"empty-legend\"===c?\"Legend does not have text that is visible to screen readers\":\"mixed-inputs\"===c?\"Fieldset contains unrelated inputs\":\"no-group-label\"===c?\"ARIA group does not have aria-label or aria-labelledby\":\"group-mixed-inputs\"===c?\"ARIA group contains unrelated inputs\":\"Element does not have a containing fieldset or ARIA group\"}}},\"color-contrast\":{impact:\"serious\",messages:{pass:function(a){return\"Element has sufficient color contrast of \"+a.data.contrastRatio},fail:function(a){return\"Element has insufficient color contrast of \"+a.data.contrastRatio+\" (foreground color: \"+a.data.fgColor+\", background color: \"+a.data.bgColor+\", font size: \"+a.data.fontSize+\", font weight: \"+a.data.fontWeight+\"). Expected contrast ratio of \"+a.data.expectedContrastRatio},incomplete:{bgImage:\"Element's background color could not be determined due to a background image\",bgGradient:\"Element's background color could not be determined due to a background gradient\",imgNode:\"Element's background color could not be determined because element contains an image node\",bgOverlap:\"Element's background color could not be determined because it is overlapped by another element\",fgAlpha:\"Element's foreground color could not be determined because of alpha transparency\",elmPartiallyObscured:\"Element's background color could not be determined because it's partially obscured by another element\",elmPartiallyObscuring:\"Element's background color could not be determined because it partially overlaps other elements\",outsideViewport:\"Element's background color could not be determined because it's outside the viewport\",equalRatio:\"Element has a 1:1 contrast ratio with the background\",default:\"Unable to determine contrast ratio\"}}},\"structured-dlitems\":{impact:\"serious\",messages:{pass:function(a){return\"When not empty, element has both <dt> and <dd> elements\"},fail:function(a){return\"When not empty, element does not have at least one <dt> element followed by at least one <dd> element\"}}},\"only-dlitems\":{impact:\"serious\",messages:{pass:function(a){return\"List element only has direct children that are allowed inside <dt> or <dd> elements\"},fail:function(a){return\"List element has direct children that are not allowed inside <dt> or <dd> elements\"}}},dlitem:{impact:\"serious\",messages:{pass:function(a){return\"Description list item has a <dl> parent element\"},fail:function(a){return\"Description list item does not have a <dl> parent element\"}}},\"doc-has-title\":{impact:\"serious\",messages:{pass:function(a){return\"Document has a non-empty <title> element\"},fail:function(a){return\"Document does not have a non-empty <title> element\"}}},\"duplicate-id\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has no elements that share the same id attribute\"},fail:function(a){return\"Document has multiple elements with the same id attribute: \"+a.data}}},\"has-visible-text\":{impact:\"minor\",messages:{pass:function(a){return\"Element has text that is visible to screen readers\"},fail:function(a){return\"Element does not have text that is visible to screen readers\"}}},\"has-widget-role\":{impact:\"minor\",messages:{pass:function(a){return\"Element has a widget role.\"},fail:function(a){return\"Element does not have a widget role.\"}}},\"valid-scrollable-semantics\":{impact:\"minor\",messages:{pass:function(a){return\"Element has valid semantics for an element in the focus order.\"},fail:function(a){return\"Element has invalid semantics for an element in the focus order.\"}}},\"unique-frame-title\":{impact:\"serious\",messages:{pass:function(a){return\"Element's title attribute is unique\"},fail:function(a){return\"Element's title attribute is not unique\"}}},\"heading-order\":{impact:\"moderate\",messages:{pass:function(a){return\"Heading order valid\"},fail:function(a){return\"Heading order invalid\"}}},\"hidden-content\":{impact:\"minor\",messages:{pass:function(a){return\"All content on the page has been analyzed.\"},fail:function(a){return\"There were problems analyzing the content on this page.\"},incomplete:function(a){return\"There is hidden content on the page that was not analyzed. You will need to trigger the display of this content in order to analyze it.\"}}},\"has-lang\":{impact:\"serious\",messages:{pass:function(a){return\"The <html> element has a lang attribute\"},fail:function(a){return\"The <html> element does not have a lang attribute\"}}},\"valid-lang\":{impact:\"serious\",messages:{pass:function(a){return\"Value of lang attribute is included in the list of valid languages\"},fail:function(a){return\"Value of lang attribute not included in the list of valid languages\"}}},\"has-alt\":{impact:\"critical\",messages:{pass:function(a){return\"Element has an alt attribute\"},fail:function(a){return\"Element does not have an alt attribute\"}}},\"duplicate-img-label\":{impact:\"minor\",messages:{pass:function(a){return\"Element does not duplicate existing text in <img> alt text\"},fail:function(a){return\"Element contains <img> element with alt text that duplicates existing text\"}}},\"title-only\":{impact:\"serious\",messages:{pass:function(a){return\"Form element does not solely use title attribute for its label\"},fail:function(a){return\"Only title used to generate label for form element\"}}},\"implicit-label\":{impact:\"critical\",messages:{pass:function(a){return\"Form element has an implicit (wrapped) <label>\"},fail:function(a){return\"Form element does not have an implicit (wrapped) <label>\"}}},\"explicit-label\":{impact:\"critical\",messages:{pass:function(a){return\"Form element has an explicit <label>\"},fail:function(a){return\"Form element does not have an explicit <label>\"}}},\"help-same-as-label\":{impact:\"minor\",messages:{pass:function(a){return\"Help text (title or aria-describedby) does not duplicate label text\"},fail:function(a){return\"Help text (title or aria-describedby) text is the same as the label text\"}}},\"multiple-label\":{impact:\"serious\",messages:{pass:function(a){return\"Form element does not have multiple <label> elements\"},fail:function(a){return\"Form element has multiple <label> elements\"}}},\"main-is-top-level\":{impact:\"moderate\",messages:{pass:function(a){return\"The main landmark is at the top level.\"},fail:function(a){return\"The main landmark is contained in another landmark.\"}}},\"has-at-least-one-main\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has at least one main landmark\"},fail:function(a){return\"Document has no main landmarks\"}}},\"has-no-more-than-one-main\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has no more than one main landmark\"},fail:function(a){return\"Document has more than one main landmark\"}}},\"has-th\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use <th> elements\"},fail:function(a){return\"Layout table uses <th> elements\"}}},\"has-caption\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use <caption> element\"},fail:function(a){return\"Layout table uses <caption> element\"}}},\"has-summary\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use summary attribute\"},fail:function(a){return\"Layout table uses summary attribute\"}}},\"link-in-text-block\":{impact:\"serious\",messages:{pass:function(a){return\"Links can be distinguished from surrounding text in some way other than by color\"},fail:function(a){return\"Links need to be distinguished from surrounding text in some way other than by color\"},incomplete:{bgContrast:\"Element's contrast ratio could not be determined. Check for a distinct hover/focus style\",bgImage:\"Element's contrast ratio could not be determined due to a background image\",bgGradient:\"Element's contrast ratio could not be determined due to a background gradient\",imgNode:\"Element's contrast ratio could not be determined because element contains an image node\",bgOverlap:\"Element's contrast ratio could not be determined because of element overlap\",default:\"Unable to determine contrast ratio\"}}},\"only-listitems\":{impact:\"serious\",messages:{pass:function(a){return\"List element only has direct children that are allowed inside <li> elements\"},fail:function(a){return\"List element has direct children that are not allowed inside <li> elements\"}}},listitem:{impact:\"serious\",messages:{pass:function(a){return'List item has a <ul>, <ol> or role=\"list\" parent element'},fail:function(a){return'List item does not have a <ul>, <ol> or role=\"list\" parent element'}}},\"meta-refresh\":{impact:\"critical\",messages:{pass:function(a){return\"<meta> tag does not immediately refresh the page\"},fail:function(a){return\"<meta> tag forces timed refresh of page\"}}},\"meta-viewport-large\":{impact:\"minor\",messages:{pass:function(a){\nreturn\"<meta> tag does not prevent significant zooming on mobile devices\"},fail:function(a){return\"<meta> tag limits zooming on mobile devices\"}}},\"meta-viewport\":{impact:\"critical\",messages:{pass:function(a){return\"<meta> tag does not disable zooming on mobile devices\"},fail:function(a){return\"<meta> tag disables zooming on mobile devices\"}}},\"p-as-heading\":{impact:\"serious\",messages:{pass:function(a){return\"<p> elements are not styled as headings\"},fail:function(a){return\"Heading elements should be used instead of styled p elements\"}}},region:{impact:\"moderate\",messages:{pass:function(a){return\"Content contained by ARIA landmark\"},fail:function(a){return\"Content not contained by an ARIA landmark\"}}},\"html5-scope\":{impact:\"moderate\",messages:{pass:function(a){return\"Scope attribute is only used on table header elements (<th>)\"},fail:function(a){return\"In HTML 5, scope attributes may only be used on table header elements (<th>)\"}}},\"scope-value\":{impact:\"critical\",messages:{pass:function(a){return\"Scope attribute is used correctly\"},fail:function(a){return\"The value of the scope attribute may only be 'row' or 'col'\"}}},exists:{impact:\"minor\",messages:{pass:function(a){return\"Element does not exist\"},fail:function(a){return\"Element exists\"}}},\"skip-link\":{impact:\"moderate\",messages:{pass:function(a){return\"Skip link target exists\"},incomplete:function(a){return\"Skip link target should become visible on activation\"},fail:function(a){return\"No skip link target\"}}},tabindex:{impact:\"serious\",messages:{pass:function(a){return\"Element does not have a tabindex greater than 0\"},fail:function(a){return\"Element has a tabindex greater than 0\"}}},\"same-caption-summary\":{impact:\"minor\",messages:{pass:function(a){return\"Content of summary attribute and <caption> are not duplicated\"},fail:function(a){return\"Content of summary attribute and <caption> element are identical\"}}},\"caption-faked\":{impact:\"serious\",messages:{pass:function(a){return\"The first row of a table is not used as a caption\"},fail:function(a){return\"The first row of the table should be a caption instead of a table cell\"}}},\"td-has-header\":{impact:\"critical\",messages:{pass:function(a){return\"All non-empty data cells have table headers\"},fail:function(a){return\"Some non-empty data cells do not have table headers\"}}},\"td-headers-attr\":{impact:\"serious\",messages:{pass:function(a){return\"The headers attribute is exclusively used to refer to other cells in the table\"},fail:function(a){return\"The headers attribute is not exclusively used to refer to other cells in the table\"}}},\"th-has-data-cells\":{impact:\"serious\",messages:{pass:function(a){return\"All table header cells refer to data cells\"},fail:function(a){return\"Not all table header cells refer to data cells\"},incomplete:function(a){return\"Table data cells are missing or empty\"}}},description:{impact:\"critical\",messages:{pass:function(a){return\"The multimedia element has an audio description track\"},fail:function(a){return\"The multimedia element does not have an audio description track\"},incomplete:function(a){return\"An audio description track for this element could not be found\"}}}},failureSummaries:{any:{failureMessage:function(a){var b=\"Fix any of the following:\",c=a;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\"\\n \"+d.split(\"\\n\").join(\"\\n \");return b}},none:{failureMessage:function(a){var b=\"Fix all of the following:\",c=a;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\"\\n \"+d.split(\"\\n\").join(\"\\n \");return b}}},incompleteFallbackMessage:function(a){return\"aXe couldn't tell the reason. Time to break out the element inspector!\"}},rules:[{id:\"accesskeys\",selector:\"[accesskey]\",excludeHidden:!1,tags:[\"wcag2a\",\"wcag211\",\"cat.keyboard\"],all:[],any:[],none:[\"accesskeys\"]},{id:\"area-alt\",selector:\"map area[href]\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"non-empty-title\",\"aria-label\",\"aria-labelledby\"],none:[]},{id:\"aria-allowed-attr\",matches:function(a,b){var c=a.getAttribute(\"role\");c||(c=axe.commons.aria.implicitRole(a));var d=axe.commons.aria.allowedAttr(c);if(c&&d){var e=/^aria-/;if(a.hasAttributes())for(var f=a.attributes,g=0,h=f.length;g<h;g++)if(e.test(f[g].name))return!0}return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag411\",\"wcag412\"],all:[],any:[\"aria-allowed-attr\"],none:[]},{id:\"aria-hidden-body\",selector:\"body\",excludeHidden:!1,tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[\"aria-hidden-body\"],none:[]},{id:\"aria-required-attr\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag411\",\"wcag412\"],all:[],any:[\"aria-required-attr\"],none:[]},{id:\"aria-required-children\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-children\"],none:[]},{id:\"aria-required-parent\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-parent\"],none:[]},{id:\"aria-roles\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag411\",\"wcag412\"],all:[],any:[],none:[\"invalidrole\",\"abstractrole\"]},{id:\"aria-valid-attr-value\",matches:function(a,b){var c=/^aria-/;if(a.hasAttributes())for(var d=a.attributes,e=0,f=d.length;e<f;e++)if(c.test(d[e].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag411\",\"wcag412\"],all:[{options:[],id:\"aria-valid-attr-value\"},\"aria-errormessage\"],any:[],none:[]},{id:\"aria-valid-attr\",matches:function(a,b){var c=/^aria-/;if(a.hasAttributes())for(var d=a.attributes,e=0,f=d.length;e<f;e++)if(c.test(d[e].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag411\"],all:[],any:[{options:[],id:\"aria-valid-attr\"}],none:[]},{id:\"audio-caption\",selector:\"audio\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag121\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"blink\",selector:\"blink\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag222\",\"section508\",\"section508.22.j\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"button-name\",selector:'button, [role=\"button\"], input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"]',tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-if-present\",\"non-empty-value\",\"button-has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"bypass\",selector:\"html\",pageLevel:!0,matches:function(a,b){return!!a.querySelector(\"a[href]\")},tags:[\"cat.keyboard\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.o\"],all:[],any:[\"internal-link-present\",\"header-present\",\"landmark\"],none:[]},{id:\"checkboxgroup\",selector:\"input[type=checkbox][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"color-contrast\",matches:function(a,b){var c=a.nodeName.toUpperCase(),d=a.type;if(\"true\"===a.getAttribute(\"aria-disabled\")||axe.commons.dom.findUpVirtual(b,'[aria-disabled=\"true\"]'))return!1;if(\"INPUT\"===c)return-1===[\"hidden\",\"range\",\"color\",\"checkbox\",\"radio\",\"image\"].indexOf(d)&&!a.disabled;if(\"SELECT\"===c)return!!a.options.length&&!a.disabled;if(\"TEXTAREA\"===c)return!a.disabled;if(\"OPTION\"===c)return!1;if(\"BUTTON\"===c&&a.disabled||axe.commons.dom.findUpVirtual(b,\"button[disabled]\"))return!1;if(\"FIELDSET\"===c&&a.disabled||axe.commons.dom.findUpVirtual(b,\"fieldset[disabled]\"))return!1;var e=axe.commons.dom.findUpVirtual(b,\"label\");if(\"LABEL\"===c||e){var f=a,g=b;e&&(f=e,g=axe.utils.getNodeFromTree(axe._tree[0],e));var h=axe.commons.dom.getRootNode(f),i=f.htmlFor&&h.getElementById(f.htmlFor);if(i&&i.disabled)return!1;var i=axe.utils.querySelectorAll(g,'input:not([type=\"hidden\"]):not([type=\"image\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]), select, textarea');if(i.length&&i[0].actualNode.disabled)return!1}if(a.getAttribute(\"id\")){var j=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),k=axe.commons.dom.getRootNode(a),i=k.querySelector(\"[aria-labelledby~=\"+j+\"]\");if(i&&i.disabled)return!1}if(\"\"===axe.commons.text.visibleVirtual(b,!1,!0))return!1;var l,m,n=document.createRange(),o=b.children,p=o.length;for(m=0;m<p;m++)l=o[m],3===l.actualNode.nodeType&&\"\"!==axe.commons.text.sanitize(l.actualNode.nodeValue)&&n.selectNodeContents(l.actualNode);var q=n.getClientRects();for(p=q.length,m=0;m<p;m++)if(axe.commons.dom.visuallyOverlaps(q[m],a))return!0;return!1},excludeHidden:!1,options:{noScroll:!1},tags:[\"cat.color\",\"wcag2aa\",\"wcag143\"],all:[],any:[\"color-contrast\"],none:[]},{id:\"definition-list\",selector:\"dl\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"structured-dlitems\",\"only-dlitems\"]},{id:\"dlitem\",selector:\"dd, dt\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"dlitem\"],none:[]},{id:\"document-title\",selector:\"html\",matches:function(a,b){return a.ownerDocument.defaultView.self===a.ownerDocument.defaultView.top},tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag242\"],all:[],any:[\"doc-has-title\"],none:[]},{id:\"duplicate-id\",selector:\"[id]\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag411\"],all:[],any:[\"duplicate-id\"],none:[]},{id:\"empty-heading\",selector:'h1, h2, h3, h4, h5, h6, [role=\"heading\"]',matches:function(a,b){var c=void 0;return a.hasAttribute(\"role\")&&(c=a.getAttribute(\"role\").split(/\\s+/i).filter(axe.commons.aria.isValidRole)),c&&c.length>0?c.includes(\"heading\"):\"heading\"===axe.commons.aria.implicitRole(a)},tags:[\"cat.name-role-value\",\"best-practice\"],all:[],any:[\"has-visible-text\"],none:[]},{id:\"focus-order-semantics\",selector:\"div, h1, h2, h3, h4, h5, h6, [role=heading], p, span\",matches:function(a,b){return axe.commons.dom.insertedIntoFocusOrder(a)},tags:[\"cat.keyboard\",\"best-practice\",\"experimental\"],all:[],any:[{options:[],id:\"has-widget-role\"},{options:[],id:\"valid-scrollable-semantics\"}],none:[]},{id:\"frame-title-unique\",selector:\"frame[title], iframe[title]\",matches:function(a,b){var c=a.getAttribute(\"title\");return!!(c?axe.commons.text.sanitize(c).trim():\"\")},tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"unique-frame-title\"]},{id:\"frame-title\",selector:\"frame, iframe\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.i\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"heading-order\",selector:\"h1, h2, h3, h4, h5, h6, [role=heading]\",matches:function(a,b){var c=void 0;return a.hasAttribute(\"role\")&&(c=a.getAttribute(\"role\").split(/\\s+/i).filter(axe.commons.aria.isValidRole)),c&&c.length>0?c.includes(\"heading\"):\"heading\"===axe.commons.aria.implicitRole(a)},tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"heading-order\"],none:[]},{id:\"hidden-content\",selector:\"*\",excludeHidden:!1,tags:[\"experimental\",\"review-item\"],all:[],any:[\"hidden-content\"],none:[]},{id:\"html-has-lang\",selector:\"html\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[\"has-lang\"],none:[]},{id:\"html-lang-valid\",selector:\"html[lang]\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"image-alt\",selector:\"img, [role='img']:not(svg)\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"image-redundant-alt\",selector:'button, [role=\"button\"], a[href], p, li, td, th',tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"duplicate-img-label\"]},{id:\"input-image-alt\",selector:'input[type=\"image\"]',tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"label-title-only\",selector:\"input, select, textarea\",matches:function(a,b){return\"input\"!==a.nodeName.toLowerCase()||!1===a.hasAttribute(\"type\")||!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(a.getAttribute(\"type\").toLowerCase())},tags:[\"cat.forms\",\"best-practice\"],all:[],any:[],none:[\"title-only\"]},{id:\"label\",selector:\"input, select, textarea\",matches:function(a,b){return\"input\"!==a.nodeName.toLowerCase()||!1===a.hasAttribute(\"type\")||!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(a.getAttribute(\"type\").toLowerCase())},tags:[\"cat.forms\",\"wcag2a\",\"wcag332\",\"wcag131\",\"section508\",\"section508.22.n\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"implicit-label\",\"explicit-label\",\"non-empty-title\"],none:[\"help-same-as-label\",\"multiple-label\"]},{id:\"landmark-main-is-top-level\",selector:\"main, [role=main]\",tags:[\"best-practice\"],all:[],any:[\"main-is-top-level\"],none:[]},{id:\"landmark-one-main\",selector:\"html\",tags:[\"best-practice\"],all:[\"has-at-least-one-main\",\"has-no-more-than-one-main\"],any:[],none:[]},{id:\"layout-table\",selector:\"table\",matches:function(a,b){return!axe.commons.table.isDataTable(a)},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"has-th\",\"has-caption\",\"has-summary\"]},{id:\"link-in-text-block\",selector:\"a[href], [role=link]\",matches:function(a,b){var c=axe.commons.text.sanitize(a.textContent),d=a.getAttribute(\"role\");return(!d||\"link\"===d)&&(!!c&&(!!axe.commons.dom.isVisible(a,!1)&&axe.commons.dom.isInTextBlock(a)))},excludeHidden:!1,tags:[\"cat.color\",\"experimental\",\"wcag2a\",\"wcag141\"],all:[\"link-in-text-block\"],any:[],none:[]},{id:\"link-name\",selector:\"a[href], [role=link][href]\",matches:function(a,b){return\"button\"!==a.getAttribute(\"role\")},tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag111\",\"wcag412\",\"wcag244\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"list\",selector:\"ul, ol\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"only-listitems\"]},{id:\"listitem\",selector:\"li\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"listitem\"],none:[]},{id:\"marquee\",selector:\"marquee\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag222\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"meta-refresh\",selector:'meta[http-equiv=\"refresh\"]',excludeHidden:!1,tags:[\"cat.time\",\"wcag2a\",\"wcag2aaa\",\"wcag221\",\"wcag224\",\"wcag325\"],all:[],any:[\"meta-refresh\"],none:[]},{id:\"meta-viewport-large\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"best-practice\"],all:[],any:[{options:{scaleMinimum:5,lowerBound:2},id:\"meta-viewport-large\"}],none:[]},{id:\"meta-viewport\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"wcag2aa\",\"wcag144\"],all:[],any:[{options:{scaleMinimum:2},id:\"meta-viewport\"}],none:[]},{id:\"object-alt\",selector:\"object\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"p-as-heading\",selector:\"p\",matches:function(a,b){var c=Array.from(a.parentNode.childNodes),d=a.textContent.trim(),e=/[.!?:;](?![.!?:;])/g;return!(0===d.length||(d.match(e)||[]).length>=2)&&0!==c.slice(c.indexOf(a)+1).filter(function(a){return\"P\"===a.nodeName.toUpperCase()&&\"\"!==a.textContent.trim()}).length},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\",\"experimental\"],all:[{options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]},id:\"p-as-heading\"}],any:[],none:[]},{id:\"radiogroup\",selector:\"input[type=radio][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"region\",selector:\"html\",pageLevel:!0,tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"region\"],none:[]},{id:\"scope-attr-valid\",selector:\"td[scope], th[scope]\",tags:[\"cat.tables\",\"best-practice\"],all:[\"html5-scope\",\"scope-value\"],any:[],none:[]},{id:\"server-side-image-map\",selector:\"img[ismap]\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag211\",\"section508\",\"section508.22.f\"],all:[],any:[],none:[\"exists\"]},{id:\"skip-link\",selector:\"a[href]\",matches:function(a,b){var c=a.getAttribute(\"href\");return\"#\"===c[0]&&c.length>1},tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"skip-link\"],none:[]},{id:\"tabindex\",selector:\"[tabindex]\",tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"tabindex\"],none:[]},{id:\"table-duplicate-name\",selector:\"table\",tags:[\"cat.tables\",\"best-practice\"],all:[],any:[],none:[\"same-caption-summary\"]},{id:\"table-fake-caption\",selector:\"table\",matches:function(a,b){return axe.commons.table.isDataTable(a)},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"caption-faked\"],any:[],none:[]},{id:\"td-has-header\",selector:\"table\",matches:function(a,b){if(axe.commons.table.isDataTable(a)){var c=axe.commons.table.toArray(a);return c.length>=3&&c[0].length>=3&&c[1].length>=3&&c[2].length>=3}return!1},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-has-header\"],any:[],none:[]},{id:\"td-headers-attr\",selector:\"table\",tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-headers-attr\"],any:[],none:[]},{id:\"th-has-data-cells\",selector:\"table\",matches:function(a,b){return axe.commons.table.isDataTable(a)},tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"th-has-data-cells\"],any:[],none:[]},{id:\"valid-lang\",selector:\"[lang], [xml\\\\:lang]\",matches:function(a,b){return\"html\"!==a.nodeName.toLowerCase()},tags:[\"cat.language\",\"wcag2aa\",\"wcag312\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"video-caption\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag122\",\"wcag123\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"video-description\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2aa\",\"wcag125\",\"section508\",\"section508.22.b\"],all:[],any:[],none:[\"description\"]}],checks:[{id:\"abstractrole\",evaluate:function(a,b,c){return\"abstract\"===axe.commons.aria.getRoleType(a.getAttribute(\"role\"))}},{id:\"aria-allowed-attr\",evaluate:function(a,b,c){b=b||{};var d,e,f,g=[],h=a.getAttribute(\"role\"),i=a.attributes;if(h||(h=axe.commons.aria.implicitRole(a)),f=axe.commons.aria.allowedAttr(h),Array.isArray(b[h])&&(f=axe.utils.uniqueArray(b[h].concat(f))),h&&f)for(var j=0,k=i.length;j<k;j++)d=i[j],e=d.name,axe.commons.aria.validateAttr(e)&&!f.includes(e)&&g.push(e+'=\"'+d.nodeValue+'\"');return!g.length||(this.data(g),!1)}},{id:\"aria-hidden-body\",evaluate:function(a,b,c){return\"true\"!==a.getAttribute(\"aria-hidden\")}},{id:\"aria-errormessage\",evaluate:function(a,b,c){b=Array.isArray(b)?b:[];var d=a.getAttribute(\"aria-errormessage\"),e=a.hasAttribute(\"aria-errormessage\"),f=axe.commons.dom.getRootNode(a);return!(-1===b.indexOf(d)&&e&&!function(){var b=d&&f.getElementById(d);if(b)return\"alert\"===b.getAttribute(\"role\")||\"assertive\"===b.getAttribute(\"aria-live\")||axe.utils.tokenList(a.getAttribute(\"aria-describedby\")||\"\").indexOf(d)>-1}())||(this.data(d),!1)}},{id:\"has-widget-role\",evaluate:function(a,b,c){var d=a.getAttribute(\"role\");if(null===d)return!1;var e=axe.commons.aria.getRoleType(d);return\"widget\"===e||\"composite\"===e},options:[]},{id:\"invalidrole\",evaluate:function(a,b,c){return!axe.commons.aria.isValidRole(a.getAttribute(\"role\"))}},{id:\"aria-required-attr\",evaluate:function(a,b,c){b=b||{};var d=[];if(a.hasAttributes()){var e,f=a.getAttribute(\"role\"),g=axe.commons.aria.requiredAttr(f);if(Array.isArray(b[f])&&(g=axe.utils.uniqueArray(b[f],g)),f&&g)for(var h=0,i=g.length;h<i;h++)e=g[h],a.getAttribute(e)||d.push(e)}return!d.length||(this.data(d),!1)}},{id:\"aria-required-children\",evaluate:function(a,b,c){function d(a,b,c,d){if(null===a)return!1;var e=g(c),f=['[role=\"'+c+'\"]'];return e&&(f=f.concat(e)),f=f.join(\",\"),d?h(a,f)||!!axe.utils.querySelectorAll(b,f)[0]:!!axe.utils.querySelectorAll(b,f)[0]}function e(a,b){var c,e;for(c=0,e=a.length;c<e;c++)if(null!==a[c]){var f=axe.utils.getNodeFromTree(axe._tree[0],a[c]);if(d(a[c],f,b,!0))return!0}return!1}var f=axe.commons.aria.requiredOwned,g=axe.commons.aria.implicitNodes,h=axe.commons.utils.matchesSelector,i=axe.commons.dom.idrefs,j=a.getAttribute(\"role\"),k=f(j);if(!k)return!0;var l=!1,m=k.one;if(!m){var l=!0;m=k.all}var n=function(a,b,f,g){var h,j=b.length,k=[],l=i(a,\"aria-owns\");for(h=0;h<j;h++){var m=b[h];if(d(a,c,m)||e(l,m)){if(!f)return null}else f&&k.push(m)}if(\"combobox\"===g){var n=k.indexOf(\"textbox\"),o=[\"text\",\"search\",\"email\",\"url\",\"tel\"];n>=0&&\"INPUT\"===a.tagName&&o.includes(a.type)&&k.splice(n,1);var p=k.indexOf(\"listbox\"),q=a.getAttribute(\"aria-expanded\");p>=0&&(!q||\"false\"===q)&&k.splice(p,1)}return k.length?k:!f&&b.length?b:null}(a,m,l,j);return!n||(this.data(n),!1)}},{id:\"aria-required-parent\",evaluate:function(a,b,c){function d(a){return(axe.commons.aria.implicitNodes(a)||[]).concat('[role=\"'+a+'\"]').join(\",\")}function e(a,b,c){var e,f,g=a.actualNode.getAttribute(\"role\"),h=[];if(b||(b=axe.commons.aria.requiredContext(g)),!b)return null;for(e=0,f=b.length;e<f;e++){if(c&&axe.utils.matchesSelector(a.actualNode,d(b[e])))return null;if(axe.commons.dom.findUpVirtual(a,d(b[e])))return null;h.push(b[e])}return h}var f=e(c);if(!f)return!0;var g=function(a){for(var b=[],c=null;a;){if(a.getAttribute(\"id\")){var d=axe.commons.utils.escapeSelector(a.getAttribute(\"id\"));c=axe.commons.dom.getRootNode(a).querySelector(\"[aria-owns~=\"+d+\"]\"),c&&b.push(c)}a=a.parentElement}return b.length?b:null}(a);if(g)for(var h=0,i=g.length;h<i;h++)if(!(f=e(axe.utils.getNodeFromTree(axe._tree[0],g[h]),f,!0)))return!0;return this.data(f),!1}},{id:\"aria-valid-attr-value\",evaluate:function(a,b,c){b=Array.isArray(b)?b:[];for(var d,e,f=[],g=/^aria-/,h=a.attributes,i=[\"aria-errormessage\"],j=0,k=h.length;j<k;j++)d=h[j],e=d.name,i.includes(e)||-1===b.indexOf(e)&&g.test(e)&&!axe.commons.aria.validateAttrValue(a,e)&&f.push(e+'=\"'+d.nodeValue+'\"');return!f.length||(this.data(f),!1)},options:[]},{id:\"aria-valid-attr\",evaluate:function(a,b,c){b=Array.isArray(b)?b:[];for(var d,e=[],f=/^aria-/,g=a.attributes,h=0,i=g.length;h<i;h++)d=g[h].name,-1===b.indexOf(d)&&f.test(d)&&!axe.commons.aria.validateAttr(d)&&e.push(d);return!e.length||(this.data(e),!1)},options:[]},{id:\"valid-scrollable-semantics\",evaluate:function(a,b,c){function d(a){var b=a.tagName.toUpperCase();return f[b]||!1}function e(a){var b=a.getAttribute(\"role\");return!!b&&(g[b.toLowerCase()]||!1)}var f={ARTICLE:!0,ASIDE:!0,NAV:!0,SECTION:!0},g={banner:!1,complementary:!0,contentinfo:!0,form:!0,main:!0,navigation:!0,region:!0,search:!1};return function(a){return e(a)||d(a)}(a)},options:[]},{id:\"color-contrast\",evaluate:function(a,b,c){if(!axe.commons.dom.isVisible(a,!1))return!0;var d,e=!!(b||{}).noScroll,f=[],g=axe.commons.color.getBackgroundColor(a,f,e),h=axe.commons.color.getForegroundColor(a,e),i=window.getComputedStyle(a),j=parseFloat(i.getPropertyValue(\"font-size\")),k=i.getPropertyValue(\"font-weight\"),l=-1!==[\"bold\",\"bolder\",\"600\",\"700\",\"800\",\"900\"].indexOf(k),m=axe.commons.color.hasValidContrastRatio(g,h,j,l),n=Math.floor(100*m.contrastRatio)/100;null===g&&(d=axe.commons.color.incompleteData.get(\"bgColor\"));var o=!1;1===n&&(o=!0,d=axe.commons.color.incompleteData.set(\"bgColor\",\"equalRatio\"));var p={fgColor:h?h.toHexString():void 0,bgColor:g?g.toHexString():void 0,contrastRatio:m?n:void 0,fontSize:(72*j/96).toFixed(1)+\"pt\",fontWeight:l?\"bold\":\"normal\",missingData:d,expectedContrastRatio:m.expectedContrastRatio+\":1\"};return this.data(p),null===h||null===g||o?(d=null,axe.commons.color.incompleteData.clear(),void this.relatedNodes(f)):(m.isValid||this.relatedNodes(f),m.isValid)}},{id:\"link-in-text-block\",evaluate:function(a,b,c){function d(a,b){var c=a.getRelativeLuminance(),d=b.getRelativeLuminance();return(Math.max(c,d)+.05)/(Math.min(c,d)+.05)}function e(a){var b=window.getComputedStyle(a).getPropertyValue(\"display\");return-1!==i.indexOf(b)||\"table-\"===b.substr(0,6)}var f=axe.commons,g=f.color,h=f.dom,i=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];if(e(a))return!1;for(var j=h.getComposedParent(a);1===j.nodeType&&!e(j);)j=h.getComposedParent(j);if(this.relatedNodes([j]),g.elementIsDistinct(a,j))return!0;var k,l;if(k=g.getForegroundColor(a),l=g.getForegroundColor(j),k&&l){var m=d(k,l);if(1===m)return!0;if(m>=3)return axe.commons.color.incompleteData.set(\"fgColor\",\"bgContrast\"),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear();if(k=g.getBackgroundColor(a),l=g.getBackgroundColor(j),!k||!l||d(k,l)>=3){var n=void 0;return n=k&&l?\"bgContrast\":axe.commons.color.incompleteData.get(\"bgColor\"),axe.commons.color.incompleteData.set(\"fgColor\",n),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear()}return!1}}},{id:\"fieldset\",evaluate:function(a,b,c){function d(a,b){return axe.commons.utils.toArray(a.querySelectorAll('select,textarea,button,input:not([name=\"'+b+'\"]):not([type=\"hidden\"])'))}function e(a,b){var c=a.firstElementChild;if(!c||\"LEGEND\"!==c.nodeName.toUpperCase())return i.relatedNodes([a]),h=\"no-legend\",!1;if(!axe.commons.text.accessibleText(c))return i.relatedNodes([c]),h=\"empty-legend\",!1;var e=d(a,b);return!e.length||(i.relatedNodes(e),h=\"mixed-inputs\",!1)}function f(a,b){var c=axe.commons.dom.idrefs(a,\"aria-labelledby\").some(function(a){return a&&axe.commons.text.accessibleText(a)}),e=a.getAttribute(\"aria-label\");if(!(c||e&&axe.commons.text.sanitize(e)))return i.relatedNodes(a),h=\"no-group-label\",!1;var f=d(a,b);return!f.length||(i.relatedNodes(f),h=\"group-mixed-inputs\",!1)}function g(a,b){return axe.commons.utils.toArray(a).filter(function(a){return a!==b})}var h,i=this,j={name:a.getAttribute(\"name\"),type:a.getAttribute(\"type\")},k=function(a){var b=axe.commons.utils.escapeSelector(a.actualNode.name),c=axe.commons.dom.getRootNode(a.actualNode),d=c.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(a.actualNode.type)+'\"][name=\"'+b+'\"]');if(d.length<2)return!0;var j=axe.commons.dom.findUpVirtual(a,\"fieldset\"),k=axe.commons.dom.findUpVirtual(a,'[role=\"group\"]'+(\"radio\"===a.actualNode.type?',[role=\"radiogroup\"]':\"\"));return k||j?j?e(j,b):f(k,b):(h=\"no-group\",i.relatedNodes(g(d,a.actualNode)),!1)}(c);return k||(j.failureCode=h),this.data(j),k},after:function(a,b){var c={};return a.filter(function(a){if(a.result)return!0;var b=a.data;if(b){if(c[b.type]=c[b.type]||{},!c[b.type][b.name])return c[b.type][b.name]=[b],!0;var d=c[b.type][b.name].some(function(a){return a.failureCode===b.failureCode});return d||c[b.type][b.name].push(b),!d}return!1})}},{id:\"group-labelledby\",evaluate:function(a,b,c){this.data({name:a.getAttribute(\"name\"),type:a.getAttribute(\"type\")});var d=axe.commons.dom.getRootNode(a),e=d.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(a.type)+'\"][name=\"'+axe.commons.utils.escapeSelector(a.name)+'\"]');return e.length<=1||0!==[].map.call(e,function(a){var b=a.getAttribute(\"aria-labelledby\");return b?b.split(/\\s+/):[]}).reduce(function(a,b){return a.filter(function(a){return b.includes(a)})}).filter(function(a){var b=d.getElementById(a);return b&&axe.commons.text.accessibleText(b,!0)}).length},after:function(a,b){var c={};return a.filter(function(a){var b=a.data;return!(!b||(c[b.type]=c[b.type]||{},c[b.type][b.name]))&&(c[b.type][b.name]=!0,!0)})}},{id:\"accesskeys\",evaluate:function(a,b,c){return axe.commons.dom.isVisible(a,!1)&&(this.data(a.getAttribute(\"accesskey\")),this.relatedNodes([a])),!0},after:function(a,b){var c={};return a.filter(function(a){if(!a.data)return!1;var b=a.data.toUpperCase();return c[b]?(c[b].relatedNodes.push(a.relatedNodes[0]),!1):(c[b]=a,a.relatedNodes=[],!0)}).map(function(a){return a.result=!!a.relatedNodes.length,a})}},{id:\"focusable-no-name\",evaluate:function(a,b,c){var d=a.getAttribute(\"tabindex\");return!!(axe.commons.dom.isFocusable(a)&&d>-1)&&!axe.commons.text.accessibleTextVirtual(c)}},{id:\"has-at-least-one-main\",evaluate:function(a,b,c){var d=axe.utils.querySelectorAll(c,\"main,[role=main]\");return this.data(!!d[0]),!!d[0]},after:function(a,b){for(var c=!1,d=0;d<a.length&&!c;d++)c=a[d].data;for(var d=0;d<a.length;d++)a[d].result=c;return a}},{id:\"has-no-more-than-one-main\",evaluate:function(a,b,c){return axe.utils.querySelectorAll(c,\"main,[role=main]\").length<=1}},{id:\"main-is-top-level\",evaluate:function(a,b,c){for(var d=axe.commons.aria.getRolesByType(\"landmark\"),e=axe.commons.dom.getComposedParent(a);e;){var f=e.getAttribute(\"role\");if(f||\"form\"===e.tagName.toLowerCase()||(f=axe.commons.aria.implicitRole(e)),f&&d.includes(f))return!1;e=axe.commons.dom.getComposedParent(e)}return!0}},{id:\"tabindex\",evaluate:function(a,b,c){return a.tabIndex<=0}},{id:\"duplicate-img-label\",evaluate:function(a,b,c){var d=axe.commons.text.visibleVirtual(c,!0).toLowerCase();return\"\"!==d&&axe.utils.querySelectorAll(c,\"img\").filter(function(a){var b=a.actualNode;return axe.commons.dom.isVisible(b)&&![\"none\",\"presentation\"].includes(b.getAttribute(\"role\"))}).some(function(a){return d===axe.commons.text.accessibleTextVirtual(a).toLowerCase()})}},{id:\"explicit-label\",evaluate:function(a,b,c){if(a.getAttribute(\"id\")){var d=axe.commons.dom.getRootNode(a),e=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),f=d.querySelector('label[for=\"'+e+'\"]');if(f)return!!axe.commons.text.accessibleText(f)}return!1}},{id:\"help-same-as-label\",evaluate:function(a,b,c){var d=axe.commons.text.labelVirtual(c),e=a.getAttribute(\"title\");if(!d)return!1;if(!e&&(e=\"\",a.getAttribute(\"aria-describedby\"))){e=axe.commons.dom.idrefs(a,\"aria-describedby\").map(function(a){return a?axe.commons.text.accessibleText(a):\"\"}).join(\"\")}return axe.commons.text.sanitize(e)===axe.commons.text.sanitize(d)},enabled:!1},{id:\"implicit-label\",evaluate:function(a,b,c){var d=axe.commons.dom.findUpVirtual(c,\"label\");return!!d&&!!axe.commons.text.accessibleTextVirtual(d)}},{id:\"multiple-label\",evaluate:function(a,b,c){var d=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),e=Array.from(document.querySelectorAll('label[for=\"'+d+'\"]')),f=a.parentNode;for(e.length&&(e=e.filter(function(a,b){if(0===b&&!axe.commons.dom.isVisible(a,!0)||axe.commons.dom.isVisible(a,!0))return a}));f;)\"LABEL\"===f.tagName&&-1===e.indexOf(f)&&e.push(f),f=f.parentNode;return this.relatedNodes(e),e.length>1}},{id:\"title-only\",evaluate:function(a,b,c){return!(axe.commons.text.labelVirtual(c)||!a.getAttribute(\"title\")&&!a.getAttribute(\"aria-describedby\"))}},{id:\"has-lang\",evaluate:function(a,b,c){return!!(a.getAttribute(\"lang\")||a.getAttribute(\"xml:lang\")||\"\").trim()}},{id:\"valid-lang\",evaluate:function(a,b,c){function d(a){return a.trim().split(\"-\")[0].toLowerCase()}var e,f;return e=(b||axe.commons.utils.validLangs()).map(d),f=[\"lang\",\"xml:lang\"].reduce(function(b,c){var f=a.getAttribute(c);if(\"string\"!=typeof f)return b;var g=d(f);return\"\"!==g&&-1===e.indexOf(g)&&b.push(c+'=\"'+a.getAttribute(c)+'\"'),b},[]),!!f.length&&(this.data(f),!0)}},{id:\"dlitem\",evaluate:function(a,b,c){return\"DL\"===axe.commons.dom.getComposedParent(a).nodeName.toUpperCase()}},{id:\"has-listitem\",evaluate:function(a,b,c){return c.children.every(function(a){return\"LI\"!==a.actualNode.nodeName.toUpperCase()})}},{id:\"listitem\",evaluate:function(a,b,c){var d=axe.commons.dom.getComposedParent(a);return[\"UL\",\"OL\"].includes(d.nodeName.toUpperCase())||\"list\"===(d.getAttribute(\"role\")||\"\").toLowerCase()}},{id:\"only-dlitems\",evaluate:function(a,b,c){var d=[],e=[\"STYLE\",\"META\",\"LINK\",\"MAP\",\"AREA\",\"SCRIPT\",\"DATALIST\",\"TEMPLATE\"],f=!1;return c.children.forEach(function(a){var b=a.actualNode,c=b.nodeName.toUpperCase();1===b.nodeType&&\"DT\"!==c&&\"DD\"!==c&&-1===e.indexOf(c)?d.push(b):3===b.nodeType&&\"\"!==b.nodeValue.trim()&&(f=!0)}),d.length&&this.relatedNodes(d),!!d.length||f}},{id:\"only-listitems\",evaluate:function(a,b,c){var d=[],e=[\"STYLE\",\"META\",\"LINK\",\"MAP\",\"AREA\",\"SCRIPT\",\"DATALIST\",\"TEMPLATE\"],f=!1;return c.children.forEach(function(a){var b=a.actualNode,c=b.nodeName.toUpperCase();1===b.nodeType&&\"LI\"!==c&&-1===e.indexOf(c)?d.push(b):3===b.nodeType&&\"\"!==b.nodeValue.trim()&&(f=!0)}),d.length&&this.relatedNodes(d),!!d.length||f}},{id:\"structured-dlitems\",\nevaluate:function(a,b,c){var d=c.children;if(!d||!d.length)return!1;for(var e,f=!1,g=!1,h=0;h<d.length;h++){if(e=d[h].actualNode.nodeName.toUpperCase(),\"DT\"===e&&(f=!0),f&&\"DD\"===e)return!1;\"DD\"===e&&(g=!0)}return f||g}},{id:\"caption\",evaluate:function(a,b,c){var d=axe.utils.querySelectorAll(c,\"track\");if(d.length)return!d.some(function(a){return\"captions\"===(a.actualNode.getAttribute(\"kind\")||\"\").toLowerCase()})}},{id:\"description\",evaluate:function(a,b,c){var d=axe.utils.querySelectorAll(c,\"track\");if(d.length){return!d.some(function(a){return\"descriptions\"===(a.actualNode.getAttribute(\"kind\")||\"\").toLowerCase()})}}},{id:\"meta-viewport-large\",evaluate:function(a,b,c){b=b||{};for(var d,e=a.getAttribute(\"content\")||\"\",f=e.split(/[;,]/),g={},h=b.scaleMinimum||2,i=b.lowerBound||!1,j=0,k=f.length;j<k;j++){d=f[j].split(\"=\");var l=d.shift().toLowerCase();l&&d.length&&(g[l.trim()]=d.shift().trim().toLowerCase())}return!!(i&&g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<i)||!(!i&&\"no\"===g[\"user-scalable\"])&&!(g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<h)},options:{scaleMinimum:5,lowerBound:2}},{id:\"meta-viewport\",evaluate:function(a,b,c){b=b||{};for(var d,e=a.getAttribute(\"content\")||\"\",f=e.split(/[;,]/),g={},h=b.scaleMinimum||2,i=b.lowerBound||!1,j=0,k=f.length;j<k;j++){d=f[j].split(\"=\");var l=d.shift().toLowerCase();l&&d.length&&(g[l.trim()]=d.shift().trim().toLowerCase())}return!!(i&&g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<i)||!(!i&&\"no\"===g[\"user-scalable\"])&&!(g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<h)},options:{scaleMinimum:2}},{id:\"header-present\",evaluate:function(a,b,c){return!!axe.utils.querySelectorAll(c,'h1, h2, h3, h4, h5, h6, [role=\"heading\"]')[0]}},{id:\"heading-order\",evaluate:function(a,b,c){var d=a.getAttribute(\"aria-level\");if(null!==d)return this.data(parseInt(d,10)),!0;var e=a.tagName.match(/H(\\d)/);return!e||(this.data(parseInt(e[1],10)),!0)},after:function(a,b){if(a.length<2)return a;for(var c=a[0].data,d=1;d<a.length;d++)a[d].result&&a[d].data>c+1&&(a[d].result=!1),c=a[d].data;return a}},{id:\"internal-link-present\",evaluate:function(a,b,c){return axe.utils.querySelectorAll(c,\"a[href]\").some(function(a){return\"#\"===a.actualNode.getAttribute(\"href\")[0]})}},{id:\"landmark\",evaluate:function(a,b,c){return axe.utils.querySelectorAll(c,'main, [role=\"main\"]').length>0}},{id:\"meta-refresh\",evaluate:function(a,b,c){var d=a.getAttribute(\"content\")||\"\",e=d.split(/[;,]/);return\"\"===d||\"0\"===e[0]}},{id:\"p-as-heading\",evaluate:function(a,b,c){function d(a){for(var b=a,c=a.textContent.trim(),d=c;d===c&&void 0!==b;){var e=-1;if(a=b,0===a.children.length)return a;do{e++,d=a.children[e].textContent.trim()}while(\"\"===d&&e+1<a.children.length);b=a.children[e]}return a}function e(a){switch(a){case\"lighter\":return 100;case\"normal\":return 400;case\"bold\":return 700;case\"bolder\":return 900}return a=parseInt(a),isNaN(a)?400:a}function f(a){var b=window.getComputedStyle(d(a));return{fontWeight:e(b.getPropertyValue(\"font-weight\")),fontSize:parseInt(b.getPropertyValue(\"font-size\")),isItalic:\"italic\"===b.getPropertyValue(\"font-style\")}}function g(a,b,c){return c.reduce(function(c,d){return c||(!d.size||a.fontSize/d.size>b.fontSize)&&(!d.weight||a.fontWeight-d.weight>b.fontWeight)&&(!d.italic||a.isItalic&&!b.isItalic)},!1)}var h=Array.from(a.parentNode.children),i=h.indexOf(a);b=b||{};var j=b.margins||[],k=h.slice(i+1).find(function(a){return\"P\"===a.nodeName.toUpperCase()}),l=h.slice(0,i).reverse().find(function(a){return\"P\"===a.nodeName.toUpperCase()}),m=f(a),n=k?f(k):null,o=l?f(l):null;if(!n||!g(m,n,j))return!0;var p=axe.commons.dom.findUpVirtual(c,\"blockquote\");return!!(p&&\"BLOCKQUOTE\"===p.nodeName.toUpperCase()||o&&!g(m,o,j))&&void 0},options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]}},{id:\"region\",evaluate:function(a,b,c){function d(a){return j&&j===a}function e(a){return a.hasAttribute(\"role\")?k.includes(a.getAttribute(\"role\").toLowerCase()):l.some(function(b){return axe.utils.matchesSelector(a,b)})}function f(a){var b=a.actualNode;return e(b)||d(b)||!h.isVisible(b,!0)?[]:h.hasContent(b,!0)?[b]:a.children.filter(function(a){return 1===a.actualNode.nodeType}).map(f).reduce(function(a,b){return a.concat(b)},[])}var g=axe.commons,h=g.dom,i=g.aria,j=function(a){var b=axe.utils.querySelectorAll(a,\"a[href]\")[0];if(b&&axe.commons.dom.getElementByReference(b.actualNode,\"href\"))return b.actualNode}(c),k=i.getRolesByType(\"landmark\"),l=k.reduce(function(a,b){return a.concat(i.implicitNodes(b))},[]).filter(function(a){return null!==a}),m=f(c);return this.relatedNodes(m),0===m.length},after:function(a,b){return[a[0]]}},{id:\"skip-link\",evaluate:function(a,b,c){var d=axe.commons.dom.getElementByReference(a,\"href\");return!!d&&(axe.commons.dom.isVisible(d,!0)||void 0)}},{id:\"unique-frame-title\",evaluate:function(a,b,c){var d=axe.commons.text.sanitize(a.title).trim().toLowerCase();return this.data(d),!0},after:function(a,b){var c={};return a.forEach(function(a){c[a.data]=void 0!==c[a.data]?++c[a.data]:0}),a.forEach(function(a){a.result=!!c[a.data]}),a}},{id:\"aria-label\",evaluate:function(a,b,c){var d=a.getAttribute(\"aria-label\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"aria-labelledby\",evaluate:function(a,b,c){return(0,axe.commons.dom.idrefs)(a,\"aria-labelledby\").some(function(a){return a&&axe.commons.text.accessibleText(a,!0)})}},{id:\"button-has-visible-text\",evaluate:function(a,b,c){var d=a.nodeName.toUpperCase(),e=a.getAttribute(\"role\"),f=void 0;return(\"BUTTON\"===d||\"button\"===e&&\"INPUT\"!==d)&&(f=axe.commons.text.accessibleTextVirtual(c),this.data(f),!!f)}},{id:\"doc-has-title\",evaluate:function(a,b,c){var d=document.title;return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"duplicate-id\",evaluate:function(a,b,c){var d=a.getAttribute(\"id\").trim();if(!d)return!0;var e=axe.commons.dom.getRootNode(a),f=Array.from(e.querySelectorAll('[id=\"'+axe.commons.utils.escapeSelector(d)+'\"]')).filter(function(b){return b!==a});return f.length&&this.relatedNodes(f),this.data(d),0===f.length},after:function(a,b){var c=[];return a.filter(function(a){return-1===c.indexOf(a.data)&&(c.push(a.data),!0)})}},{id:\"exists\",evaluate:function(a,b,c){return!0}},{id:\"has-alt\",evaluate:function(a,b,c){var d=a.nodeName.toLowerCase();return a.hasAttribute(\"alt\")&&(\"img\"===d||\"input\"===d||\"area\"===d)}},{id:\"has-visible-text\",evaluate:function(a,b,c){return axe.commons.text.accessibleTextVirtual(c).length>0}},{id:\"is-on-screen\",evaluate:function(a,b,c){return axe.commons.dom.isVisible(a,!1)&&!axe.commons.dom.isOffscreen(a)}},{id:\"non-empty-alt\",evaluate:function(a,b,c){var d=a.getAttribute(\"alt\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"non-empty-if-present\",evaluate:function(a,b,c){var d=a.nodeName.toUpperCase(),e=(a.getAttribute(\"type\")||\"\").toLowerCase(),f=a.getAttribute(\"value\");return this.data(f),!(\"INPUT\"!==d||![\"submit\",\"reset\"].includes(e))&&null===f}},{id:\"non-empty-title\",evaluate:function(a,b,c){var d=a.getAttribute(\"title\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"non-empty-value\",evaluate:function(a,b,c){var d=a.getAttribute(\"value\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"role-none\",evaluate:function(a,b,c){return\"none\"===a.getAttribute(\"role\")}},{id:\"role-presentation\",evaluate:function(a,b,c){return\"presentation\"===a.getAttribute(\"role\")}},{id:\"caption-faked\",evaluate:function(a,b,c){var d=axe.commons.table.toGrid(a),e=d[0];return d.length<=1||e.length<=1||a.rows.length<=1||e.reduce(function(a,b,c){return a||b!==e[c+1]&&void 0!==e[c+1]},!1)}},{id:\"has-caption\",evaluate:function(a,b,c){return!!a.caption}},{id:\"has-summary\",evaluate:function(a,b,c){return!!a.summary}},{id:\"has-th\",evaluate:function(a,b,c){for(var d,e,f=[],g=0,h=a.rows.length;g<h;g++){d=a.rows[g];for(var i=0,j=d.cells.length;i<j;i++)e=d.cells[i],\"TH\"!==e.nodeName.toUpperCase()&&-1===[\"rowheader\",\"columnheader\"].indexOf(e.getAttribute(\"role\"))||f.push(e)}return!!f.length&&(this.relatedNodes(f),!0)}},{id:\"html5-scope\",evaluate:function(a,b,c){return!axe.commons.dom.isHTML5(document)||\"TH\"===a.nodeName.toUpperCase()}},{id:\"same-caption-summary\",evaluate:function(a,b,c){return!(!a.summary||!a.caption)&&a.summary===axe.commons.text.accessibleText(a.caption)}},{id:\"scope-value\",evaluate:function(a,b,c){b=b||{};var d=a.getAttribute(\"scope\").toLowerCase();return-1!==([\"row\",\"col\",\"rowgroup\",\"colgroup\"]||b.values).indexOf(d)}},{id:\"td-has-header\",evaluate:function(a,b,c){var d=axe.commons.table,e=[];return d.getAllCells(a).forEach(function(a){if(axe.commons.dom.hasContent(a)&&d.isDataCell(a)&&!axe.commons.aria.label(a)){var b=d.getHeaders(a);(b=b.reduce(function(a,b){return a||null!==b&&!!axe.commons.dom.hasContent(b)},!1))||e.push(a)}}),!e.length||(this.relatedNodes(e),!1)}},{id:\"td-headers-attr\",evaluate:function(a,b,c){for(var d=[],e=0,f=a.rows.length;e<f;e++)for(var g=a.rows[e],h=0,i=g.cells.length;h<i;h++)d.push(g.cells[h]);var j=d.reduce(function(a,b){return b.getAttribute(\"id\")&&a.push(b.getAttribute(\"id\")),a},[]),k=d.reduce(function(a,b){var c,d,e=(b.getAttribute(\"headers\")||\"\").split(/\\s/).reduce(function(a,b){return b=b.trim(),b&&a.push(b),a},[]);return 0!==e.length&&(b.getAttribute(\"id\")&&(c=-1!==e.indexOf(b.getAttribute(\"id\").trim())),d=e.reduce(function(a,b){return a||-1===j.indexOf(b)},!1),(c||d)&&a.push(b)),a},[]);return!(k.length>0)||(this.relatedNodes(k),!1)}},{id:\"th-has-data-cells\",evaluate:function(a,b,c){var d=axe.commons.table,e=d.getAllCells(a),f=this,g=[];e.forEach(function(a){var b=a.getAttribute(\"headers\");b&&(g=g.concat(b.split(/\\s+/)));var c=a.getAttribute(\"aria-labelledby\");c&&(g=g.concat(c.split(/\\s+/)))});var h=e.filter(function(a){return\"\"!==axe.commons.text.sanitize(a.textContent)&&(\"TH\"===a.nodeName.toUpperCase()||-1!==[\"rowheader\",\"columnheader\"].indexOf(a.getAttribute(\"role\")))}),i=d.toGrid(a);return!!h.reduce(function(a,b){if(b.getAttribute(\"id\")&&g.includes(b.getAttribute(\"id\")))return!!a||a;var c=!1,e=d.getCellPosition(b,i);return d.isColumnHeader(b)&&(c=d.traverse(\"down\",e,i).reduce(function(a,b){return a||axe.commons.dom.hasContent(b)&&!d.isColumnHeader(b)},!1)),!c&&d.isRowHeader(b)&&(c=d.traverse(\"right\",e,i).reduce(function(a,b){return a||axe.commons.dom.hasContent(b)&&!d.isRowHeader(b)},!1)),c||f.relatedNodes(b),a&&c},!0)||void 0}},{id:\"hidden-content\",evaluate:function(a,b,c){if(![\"SCRIPT\",\"HEAD\",\"TITLE\",\"NOSCRIPT\",\"STYLE\",\"TEMPLATE\"].includes(a.tagName.toUpperCase())&&axe.commons.dom.hasContentVirtual(c)){var d=window.getComputedStyle(a);if(\"none\"===d.getPropertyValue(\"display\"))return;if(\"hidden\"===d.getPropertyValue(\"visibility\")){var e=axe.commons.dom.getComposedParent(a),f=e&&window.getComputedStyle(e);if(!f||\"hidden\"!==f.getPropertyValue(\"visibility\"))return}}return!0}}],commons:function(){function a(a){return a.getPropertyValue(\"font-family\").split(/[,;]/g).map(function(a){return a.trim().toLowerCase()})}function b(b,c){var d=window.getComputedStyle(b);if(\"none\"!==d.getPropertyValue(\"background-image\"))return!0;if([\"border-bottom\",\"border-top\",\"outline\"].reduce(function(a,b){var c=new C.Color;return c.parseRgbString(d.getPropertyValue(b+\"-color\")),a||\"none\"!==d.getPropertyValue(b+\"-style\")&&parseFloat(d.getPropertyValue(b+\"-width\"))>0&&0!==c.alpha},!1))return!0;var e=window.getComputedStyle(c);if(a(d)[0]!==a(e)[0])return!0;var f=[\"text-decoration-line\",\"text-decoration-style\",\"font-weight\",\"font-style\",\"font-size\"].reduce(function(a,b){return a||d.getPropertyValue(b)!==e.getPropertyValue(b)},!1),g=d.getPropertyValue(\"text-decoration\");return g.split(\" \").length<3&&(f=f||g!==e.getPropertyValue(\"text-decoration\")),f}function c(a,b){var c=a.nodeName.toUpperCase();if(G.includes(c))return axe.commons.color.incompleteData.set(\"bgColor\",\"imgNode\"),!0;b=b||window.getComputedStyle(a);var d=b.getPropertyValue(\"background-image\"),e=\"none\"!==d;if(e){var f=/gradient/.test(d);axe.commons.color.incompleteData.set(\"bgColor\",f?\"bgGradient\":\"bgImage\")}return e}function d(a,b){b=b||window.getComputedStyle(a);var c=new C.Color;if(c.parseRgbString(b.getPropertyValue(\"background-color\")),0!==c.alpha){var d=b.getPropertyValue(\"opacity\");c.alpha=c.alpha*d}return c}function e(a,b){var c=a.getClientRects()[0],d=D.shadowElementsFromPoint(c.left,c.top);if(d)for(var e=0;e<d.length;e++)if(d[e]!==a&&d[e]===b)return!0;return!1}function f(a,b,c){var f=0;if(a>0)for(var g=a-1;g>=0;g--){var h=b[g],i=window.getComputedStyle(h),j=d(h,i);j.alpha&&e(c,h)?f+=j.alpha:b.splice(g,1)}return f}function g(a,b,c){var d=a!==b&&!D.visuallyContains(a,b)&&0!==c.alpha;return d&&axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscured\"),d}function h(a,b){var c={TD:[\"TR\",\"TBODY\"],TH:[\"TR\",\"THEAD\"],INPUT:[\"LABEL\"]},d=a.map(function(a){return a.tagName}),e=a;for(var f in c)if(d.includes(f))for(var g in c[f])if(f.hasOwnProperty(g)){var h=axe.commons.dom.findUp(b,c[f][g]);if(h&&-1===a.indexOf(h)){var i=axe.commons.dom.visuallyOverlaps(b.getBoundingClientRect(),h);i&&e.splice(d.indexOf(f)+1,0,h)}b.tagName===c[f][g]&&-1===d.indexOf(b.tagName)&&e.splice(d.indexOf(f)+1,0,b)}return e}function i(a){var b=a.indexOf(document.body),e=a;return b>1&&!c(document.documentElement)&&0===d(document.documentElement).alpha&&(e.splice(b,1),e.splice(a.indexOf(document.documentElement),1),e.push(document.body)),e}function j(a){if(!H.includes(a.actualNode.nodeName.toUpperCase()))return a.children.some(function(a){var b=a.actualNode;return 3===b.nodeType&&b.nodeValue.trim()})}function k(a){return a.disabled||!D.isVisible(a,!0)&&\"AREA\"!==a.nodeName.toUpperCase()}function l(a,b){!1!==b(a.actualNode)&&a.children.forEach(function(a){return l(a,b)})}function m(a){var b=window.getComputedStyle(a).getPropertyValue(\"display\");return I.includes(b)||\"table-\"===b.substr(0,6)}function n(a){for(var b=D.getComposedParent(a);b&&!m(b);)b=D.getComposedParent(b);return axe.utils.getNodeFromTree(axe._tree[0],b)}function o(a,b){for(a=D.getComposedParent(a);a&&\"html\"!==a.nodeName.toLowerCase();){if(a.scrollTop&&(b+=a.scrollTop)>=0)return!1;a=D.getComposedParent(a)}return!0}function p(a){\"use strict\";var b=a.match(/rect\\s*\\(([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px\\s*\\)/);return!(!b||5!==b.length)&&(b[3]-b[1]<=0&&b[2]-b[4]<=0)}function q(a){var b=void 0;return b=a.actualNode.id?D.findElmsInContext({elm:\"label\",attr:\"for\",value:a.actualNode.id,context:a.actualNode})[0]:D.findUpVirtual(a,\"label\"),axe.utils.getNodeFromTree(axe._tree[0],b)}function r(a){return[\"button\",\"reset\",\"submit\"].includes(a.actualNode.type.toLowerCase())}function s(a){var b=a.actualNode,c=b.nodeName.toUpperCase();return\"TEXTAREA\"===c||\"SELECT\"===c||\"INPUT\"===c&&\"hidden\"!==b.type.toLowerCase()}function t(a){return[\"BUTTON\",\"SUMMARY\",\"A\"].includes(a.actualNode.nodeName.toUpperCase())}function u(a){return[\"TABLE\",\"FIGURE\"].includes(a.actualNode.nodeName.toUpperCase())}function v(a){var b=a.actualNode,c=b.nodeName.toUpperCase();if(\"INPUT\"===c)return!b.hasAttribute(\"type\")||L.includes(b.type.toLowerCase())?b.value:\"\";if(\"SELECT\"===c){var d=b.options;if(d&&d.length){for(var e=\"\",f=0;f<d.length;f++)d[f].selected&&(e+=\" \"+d[f].text);return F.sanitize(e)}return\"\"}return\"TEXTAREA\"===c&&b.value?b.value:\"\"}function w(a,b){var c=a.actualNode,d=c.querySelector(b.toLowerCase());return d?F.accessibleText(d):\"\"}function x(a){if(!a)return!1;var b=a.actualNode;switch(b.nodeName.toUpperCase()){case\"SELECT\":case\"TEXTAREA\":return!0;case\"INPUT\":return!b.hasAttribute(\"type\")||L.includes(b.getAttribute(\"type\").toLowerCase());default:return!1}}function y(a){var b=a.actualNode,c=b.nodeName.toUpperCase();return[\"IMG\",\"APPLET\",\"AREA\"].includes(c)||\"INPUT\"===c&&\"image\"===b.type.toLowerCase()}function z(a){return!!F.sanitize(a)}var commons={},A=commons.aria={},B=A.lookupTable={};B.attributes={\"aria-activedescendant\":{type:\"idref\"},\"aria-atomic\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-autocomplete\":{type:\"nmtoken\",values:[\"inline\",\"list\",\"both\",\"none\"]},\"aria-busy\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-checked\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-colcount\":{type:\"int\"},\"aria-colindex\":{type:\"int\"},\"aria-colspan\":{type:\"int\"},\"aria-controls\":{type:\"idrefs\"},\"aria-current\":{type:\"nmtoken\",values:[\"page\",\"step\",\"location\",\"date\",\"time\",\"true\",\"false\"]},\"aria-describedby\":{type:\"idrefs\"},\"aria-disabled\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-dropeffect\":{type:\"nmtokens\",values:[\"copy\",\"move\",\"reference\",\"execute\",\"popup\",\"none\"]},\"aria-errormessage\":{type:\"idref\"},\"aria-expanded\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-flowto\":{type:\"idrefs\"},\"aria-grabbed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-haspopup\":{type:\"nmtoken\",values:[\"true\",\"false\",\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"]},\"aria-hidden\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-invalid\":{type:\"nmtoken\",values:[\"true\",\"false\",\"spelling\",\"grammar\"]},\"aria-keyshortcuts\":{type:\"string\"},\"aria-label\":{type:\"string\"},\"aria-labelledby\":{type:\"idrefs\"},\"aria-level\":{type:\"int\"},\"aria-live\":{type:\"nmtoken\",values:[\"off\",\"polite\",\"assertive\"]},\"aria-modal\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiline\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiselectable\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-orientation\":{type:\"nmtoken\",values:[\"horizontal\",\"vertical\"]},\"aria-owns\":{type:\"idrefs\"},\"aria-placeholder\":{type:\"string\"},\"aria-posinset\":{type:\"int\"},\"aria-pressed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-readonly\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-relevant\":{type:\"nmtokens\",values:[\"additions\",\"removals\",\"text\",\"all\"]},\"aria-required\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-rowcount\":{type:\"int\"},\"aria-rowindex\":{type:\"int\"},\"aria-rowspan\":{type:\"int\"},\"aria-selected\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-setsize\":{type:\"int\"},\"aria-sort\":{type:\"nmtoken\",values:[\"ascending\",\"descending\",\"other\",\"none\"]},\"aria-valuemax\":{type:\"decimal\"},\"aria-valuemin\":{type:\"decimal\"},\"aria-valuenow\":{type:\"decimal\"},\"aria-valuetext\":{type:\"string\"}},B.globalAttributes=[\"aria-atomic\",\"aria-busy\",\"aria-controls\",\"aria-current\",\"aria-describedby\",\"aria-disabled\",\"aria-dropeffect\",\"aria-flowto\",\"aria-grabbed\",\"aria-haspopup\",\"aria-hidden\",\"aria-invalid\",\"aria-keyshortcuts\",\"aria-label\",\"aria-labelledby\",\"aria-live\",\"aria-owns\",\"aria-relevant\"],B.role={alert:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},alertdialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\"]},owned:null,nameFrom:[\"author\"],context:null},application:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},article:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"article\"]},banner:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"header\"]},button:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-pressed\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"button\",'input[type=\"button\"]','input[type=\"image\"]','input[type=\"reset\"]','input[type=\"submit\"]',\"summary\"]},cell:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-rowindex\",\"aria-rowspan\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"]},checkbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"checkbox\"]']},columnheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"]},combobox:{type:\"composite\",attributes:{allowed:[\"aria-expanded\",\"aria-autocomplete\",\"aria-required\",\"aria-activedescendant\",\"aria-orientation\"]},owned:{all:[\"listbox\",\"textbox\"]},nameFrom:[\"author\"],context:null},command:{nameFrom:[\"author\"],type:\"abstract\"},complementary:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"aside\"]},composite:{nameFrom:[\"author\"],type:\"abstract\"},contentinfo:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"footer\"]},definition:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dd\",\"dfn\"]},dialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dialog\"]},directory:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},document:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"body\"]},feed:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:{one:[\"article\"]},nameFrom:[\"author\"],context:null},form:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"form\"]},grid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-colcount\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-rowcount\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"]},gridcell:{type:\"widget\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\",\"aria-readonly\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"]},group:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"details\",\"optgroup\"]},heading:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]},img:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"img\"]},input:{nameFrom:[\"author\"],type:\"abstract\"},landmark:{nameFrom:[\"author\"],type:\"abstract\"},link:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"a[href]\"]},list:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:{all:[\"listitem\"]},nameFrom:[\"author\"],context:null,implicit:[\"ol\",\"ul\",\"dl\"]},listbox:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\"]},owned:{all:[\"option\"]},nameFrom:[\"author\"],context:null,implicit:[\"select\"]},listitem:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"list\"],implicit:[\"li\",\"dt\"]},log:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},main:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"main\"]},marquee:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},math:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"math\"]},menu:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"]},owned:{one:[\"menuitem\",\"menuitemradio\",\"menuitemcheckbox\"]},nameFrom:[\"author\"],context:null,implicit:['menu[type=\"context\"]']},menubar:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null},menuitem:{type:\"widget\",attributes:{allowed:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"command\"]']},menuitemcheckbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"checkbox\"]']},menuitemradio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"radio\"]']},navigation:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"nav\"]},none:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null},note:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},option:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"listbox\"],implicit:[\"option\"]},presentation:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null},progressbar:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"progress\"]},radio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"radio\"]']},radiogroup:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-required\",\"aria-expanded\"]},owned:{all:[\"radio\"]},nameFrom:[\"author\"],context:null},range:{nameFrom:[\"author\"],type:\"abstract\"},region:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"section[aria-label]\",\"section[aria-labelledby]\",\"section[title]\"]},roletype:{type:\"abstract\"},row:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colindex\",\"aria-expanded\",\"aria-level\",\"aria-selected\",\"aria-rowindex\"]},owned:{one:[\"cell\",\"columnheader\",\"rowheader\",\"gridcell\"]},nameFrom:[\"author\",\"contents\"],context:[\"rowgroup\",\"grid\",\"treegrid\",\"table\"],implicit:[\"tr\"]},rowgroup:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:{all:[\"row\"]},nameFrom:[\"author\",\"contents\"],context:[\"grid\",\"table\"],implicit:[\"tbody\",\"thead\",\"tfoot\"]},rowheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"]},scrollbar:{type:\"widget\",attributes:{required:[\"aria-controls\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"],allowed:[\"aria-valuetext\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null},search:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},searchbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"search\"]']},section:{nameFrom:[\"author\",\"contents\"],type:\"abstract\"},sectionhead:{nameFrom:[\"author\",\"contents\"],type:\"abstract\"},select:{nameFrom:[\"author\"],type:\"abstract\"},separator:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"hr\"]},slider:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-orientation\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"range\"]']},spinbutton:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-required\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"number\"]']},status:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"output\"]},structure:{type:\"abstract\"},switch:{type:\"widget\",attributes:{required:[\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},tab:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-expanded\",\"aria-setsize\",\"aria-posinset\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"tablist\"]},table:{type:\"structure\",attributes:{allowed:[\"aria-colcount\",\"aria-rowcount\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"]},tablist:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-orientation\"]},owned:{all:[\"tab\"]},nameFrom:[\"author\"],context:null},tabpanel:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},term:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"dt\"]},text:{type:\"structure\",owned:null,nameFrom:[\"author\",\"contents\"],context:null},textbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"text\"]','input[type=\"email\"]','input[type=\"password\"]','input[type=\"tel\"]','input[type=\"url\"]',\"input:not([type])\",\"textarea\"]},timer:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},toolbar:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['menu[type=\"toolbar\"]']},tooltip:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},tree:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\"]},owned:{all:[\"treeitem\"]},nameFrom:[\"author\"],context:null},treegrid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-required\",\"aria-rowcount\",\"aria-orientation\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null},treeitem:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"group\",\"tree\"]},widget:{type:\"abstract\"},window:{nameFrom:[\"author\"],type:\"abstract\"}};var C={};commons.color=C;var D=commons.dom={},E=commons.table={},F=commons.text={EdgeFormDefaults:{}};commons.utils=axe.utils;A.requiredAttr=function(a){\"use strict\";var b=A.lookupTable.role[a];return b&&b.attributes&&b.attributes.required||[]},A.allowedAttr=function(a){\"use strict\";var b=A.lookupTable.role[a],c=b&&b.attributes&&b.attributes.allowed||[],d=b&&b.attributes&&b.attributes.required||[];return c.concat(A.lookupTable.globalAttributes).concat(d)},A.validateAttr=function(a){\"use strict\";return!!A.lookupTable.attributes[a]},A.validateAttrValue=function(a,b){\"use strict\";var c,d,e=a.getAttribute(b),f=A.lookupTable.attributes[b],g=D.getRootNode(a);if(!f)return!0;switch(f.type){case\"boolean\":case\"nmtoken\":return\"string\"==typeof e&&-1!==f.values.indexOf(e.toLowerCase());case\"nmtokens\":return d=axe.utils.tokenList(e),d.reduce(function(a,b){return a&&-1!==f.values.indexOf(b)},0!==d.length);case\"idref\":return!(!e||!g.getElementById(e));case\"idrefs\":return d=axe.utils.tokenList(e),d.reduce(function(a,b){return!(!a||!g.getElementById(b))},0!==d.length);case\"string\":return!0;case\"decimal\":return!(!(c=e.match(/^[-+]?([0-9]*)\\.?([0-9]*)$/))||!c[1]&&!c[2]);case\"int\":return/^[-+]?[0-9]+$/.test(e)}},A.labelVirtual=function(a){var b=a.actualNode,c=void 0,d=void 0;return b.getAttribute(\"aria-labelledby\")&&(c=D.idrefs(b,\"aria-labelledby\"),d=c.map(function(a){\nvar b=axe.utils.getNodeFromTree(axe._tree[0],a);return b?F.visibleVirtual(b,!0):\"\"}).join(\" \").trim())?d:(d=b.getAttribute(\"aria-label\"),d&&(d=F.sanitize(d).trim())?d:null)},A.label=function(a){return a=axe.utils.getNodeFromTree(axe._tree[0],a),A.labelVirtual(a)},A.isValidRole=function(a){\"use strict\";return!!A.lookupTable.role[a]},A.getRolesWithNameFromContents=function(){return Object.keys(A.lookupTable.role).filter(function(a){return A.lookupTable.role[a].nameFrom&&-1!==A.lookupTable.role[a].nameFrom.indexOf(\"contents\")})},A.getRolesByType=function(a){return Object.keys(A.lookupTable.role).filter(function(b){return A.lookupTable.role[b].type===a})},A.getRoleType=function(a){var b=A.lookupTable.role[a];return b&&b.type||null},A.requiredOwned=function(a){\"use strict\";var b=null,c=A.lookupTable.role[a];return c&&(b=axe.utils.clone(c.owned)),b},A.requiredContext=function(a){\"use strict\";var b=null,c=A.lookupTable.role[a];return c&&(b=axe.utils.clone(c.context)),b},A.implicitNodes=function(a){\"use strict\";var b=null,c=A.lookupTable.role[a];return c&&c.implicit&&(b=axe.utils.clone(c.implicit)),b},A.implicitRole=function(a){\"use strict\";var b=function(b,c){var d=function(b){return axe.utils.matchesSelector(a,b)};return c.implicit&&c.implicit.some(d)&&b.push(c.name),b},c=Object.keys(A.lookupTable.role).map(function(a){var b=A.lookupTable.role[a];return{name:a,implicit:b&&b.implicit}}),d=c.reduce(b,[]);if(!d.length)return null;for(var e=a.attributes,f=[],g=0,h=e.length;g<h;g++){var i=e[g];i.name.match(/^aria-/)&&f.push(i.name)}return function(a,b){var c=function(a){return A.allowedAttr(a).reduce(function(a,c){return a+(b.indexOf(c)>-1?1:0)},0)};return a.map(function(a){return{score:c(a),name:a}}).sort(function(a,b){return b.score-a.score}).map(function(a){return a.name})}(d,f).shift()},C.Color=function(a,b,c,d){this.red=a,this.green=b,this.blue=c,this.alpha=d,this.toHexString=function(){var a=Math.round(this.red).toString(16),b=Math.round(this.green).toString(16),c=Math.round(this.blue).toString(16);return\"#\"+(this.red>15.5?a:\"0\"+a)+(this.green>15.5?b:\"0\"+b)+(this.blue>15.5?c:\"0\"+c)};var e=/^rgb\\((\\d+), (\\d+), (\\d+)\\)$/,f=/^rgba\\((\\d+), (\\d+), (\\d+), (\\d*(\\.\\d+)?)\\)/;this.parseRgbString=function(a){if(\"transparent\"===a)return this.red=0,this.green=0,this.blue=0,void(this.alpha=0);var b=a.match(e);return b?(this.red=parseInt(b[1],10),this.green=parseInt(b[2],10),this.blue=parseInt(b[3],10),void(this.alpha=1)):(b=a.match(f),b?(this.red=parseInt(b[1],10),this.green=parseInt(b[2],10),this.blue=parseInt(b[3],10),void(this.alpha=parseFloat(b[4]))):void 0)},this.getRelativeLuminance=function(){var a=this.red/255,b=this.green/255,c=this.blue/255;return.2126*(a<=.03928?a/12.92:Math.pow((a+.055)/1.055,2.4))+.7152*(b<=.03928?b/12.92:Math.pow((b+.055)/1.055,2.4))+.0722*(c<=.03928?c/12.92:Math.pow((c+.055)/1.055,2.4))}},C.flattenColors=function(a,b){var c=a.alpha,d=(1-c)*b.red+c*a.red,e=(1-c)*b.green+c*a.green,f=(1-c)*b.blue+c*a.blue,g=a.alpha+b.alpha*(1-a.alpha);return new C.Color(d,e,f,g)},C.getContrast=function(a,b){if(!b||!a)return null;b.alpha<1&&(b=C.flattenColors(b,a));var c=a.getRelativeLuminance(),d=b.getRelativeLuminance();return(Math.max(d,c)+.05)/(Math.min(d,c)+.05)},C.hasValidContrastRatio=function(a,b,c,d){var e=C.getContrast(a,b),f=d&&Math.ceil(72*c)/96<14||!d&&Math.ceil(72*c)/96<18,g=f?4.5:3;return{isValid:e>g,contrastRatio:e,expectedContrastRatio:g}},C.elementIsDistinct=b;var G=[\"IMG\",\"CANVAS\",\"OBJECT\",\"IFRAME\",\"VIDEO\",\"SVG\"];C.getCoords=function(a){var b=void 0,c=void 0;if(!(a.left>window.innerWidth||a.top>window.innerHeight))return b=Math.min(Math.ceil(a.left+a.width/2),window.innerWidth-1),c=Math.min(Math.ceil(a.top+a.height/2),window.innerHeight-1),{x:b,y:c}},C.getRectStack=function(a){var b=C.getCoords(a.getBoundingClientRect());if(b){var c=D.shadowElementsFromPoint(b.x,b.y),d=Array.from(a.getClientRects());if(d&&d.length>1){var e=d.filter(function(a){return a.width&&a.width>0}).map(function(a){var b=C.getCoords(a);if(b)return D.shadowElementsFromPoint(b.x,b.y)});return e.splice(0,0,c),e}return[c]}return null},C.filteredRectStack=function(a){var b=C.getRectStack(a);if(b&&1===b.length)return b[0];if(b&&b.length>1){var c=b.shift(),d=void 0;return b.forEach(function(e,f){if(0!==f){var g=b[f-1],h=b[f];d=g.every(function(a,b){return a===h[b]})||c.includes(a)}}),d?b[0]:(axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscuring\"),null)}return axe.commons.color.incompleteData.set(\"bgColor\",\"outsideViewport\"),null},C.getBackgroundStack=function(a){var b=C.filteredRectStack(a);if(null===b)return null;b=h(b,a),b=D.reduceToElementsBelowFloating(b,a),b=i(b);var c=b.indexOf(a);return f(c,b,a)>=.99?(axe.commons.color.incompleteData.set(\"bgColor\",\"bgOverlap\"),null):-1!==c?b:null},C.getBackgroundColor=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];if(!0!==(arguments.length>2&&void 0!==arguments[2]&&arguments[2])){var e=a.clientHeight-2>=2*window.innerHeight;a.scrollIntoView(e)}var f=[],h=C.getBackgroundStack(a);if((h||[]).some(function(e){var h=window.getComputedStyle(e),i=d(e,h);return g(a,e,i)||c(e,h)?(f=null,b.push(e),!0):0!==i.alpha&&(b.push(e),f.push(i),1===i.alpha)}),null!==f&&null!==h){f.push(new C.Color(255,255,255,1));return f.reduce(C.flattenColors)}return null},D.isOpaque=function(a){var b=window.getComputedStyle(a);return c(a,b)||1===d(a,b).alpha},C.getForegroundColor=function(a,b){var c=window.getComputedStyle(a),d=new C.Color;d.parseRgbString(c.getPropertyValue(\"color\"));var e=c.getPropertyValue(\"opacity\");if(d.alpha=d.alpha*e,1===d.alpha)return d;var f=C.getBackgroundColor(a,[],b);if(null===f){var g=axe.commons.color.incompleteData.get(\"bgColor\");return axe.commons.color.incompleteData.set(\"fgColor\",g),null}return C.flattenColors(d,f)},C.incompleteData=function(){var a={};return{set:function(b,c){if(\"string\"!=typeof b)throw new Error(\"Incomplete data: key must be a string\");return c&&(a[b]=c),a[b]},get:function(b){return a[b]},clear:function(){a={}}}}(),D.reduceToElementsBelowFloating=function(a,b){var c,d,e,f=[\"fixed\",\"sticky\"],g=[],h=!1;for(c=0;c<a.length;++c)d=a[c],d===b&&(h=!0),e=window.getComputedStyle(d),h||-1===f.indexOf(e.position)?g.push(d):g=[];return g},D.findElmsInContext=function(a){var b=a.context,c=a.value,d=a.attr,e=a.elm,f=void 0===e?\"\":e,g=void 0,h=axe.utils.escapeSelector(c);return g=9===b.nodeType||11===b.nodeType?b:D.getRootNode(b),Array.from(g.querySelectorAll(f+\"[\"+d+\"=\"+h+\"]\"))},D.findUp=function(a,b){return D.findUpVirtual(axe.utils.getNodeFromTree(axe._tree[0],a),b)},D.findUpVirtual=function(a,b){var c=void 0;if(c=a.actualNode,!a.shadowId&&\"function\"==typeof a.actualNode.closest){var d=a.actualNode.closest(b);return d||null}do{(c=c.assignedSlot?c.assignedSlot:c.parentNode)&&11===c.nodeType&&(c=c.host)}while(c&&!axe.utils.matchesSelector(c,b)&&c!==document.documentElement);return axe.utils.matchesSelector(c,b)?c:null},D.getComposedParent=function a(b){if(b.assignedSlot)return a(b.assignedSlot);if(b.parentNode){var c=b.parentNode;if(1===c.nodeType)return c;if(c.host)return c.host}return null},D.getElementByReference=function(a,b){var c=a.getAttribute(b);if(c&&\"#\"===c.charAt(0)){c=c.substring(1);var d=document.getElementById(c);if(d)return d;if(d=document.getElementsByName(c),d.length)return d[0]}return null},D.getElementCoordinates=function(a){\"use strict\";var b=D.getScrollOffset(document),c=b.left,d=b.top,e=a.getBoundingClientRect();return{top:e.top+d,right:e.right+c,bottom:e.bottom+d,left:e.left+c,width:e.right-e.left,height:e.bottom-e.top}},D.getRootNode=function(a){var b=a.getRootNode&&a.getRootNode()||document;return b===a&&(b=document),b},D.getScrollOffset=function(a){\"use strict\";if(!a.nodeType&&a.document&&(a=a.document),9===a.nodeType){var b=a.documentElement,c=a.body;return{left:b&&b.scrollLeft||c&&c.scrollLeft||0,top:b&&b.scrollTop||c&&c.scrollTop||0}}return{left:a.scrollLeft,top:a.scrollTop}},D.getViewportSize=function(a){\"use strict\";var b,c=a.document,d=c.documentElement;return a.innerWidth?{width:a.innerWidth,height:a.innerHeight}:d?{width:d.clientWidth,height:d.clientHeight}:(b=c.body,{width:b.clientWidth,height:b.clientHeight})};var H=[\"HEAD\",\"TITLE\",\"TEMPLATE\",\"SCRIPT\",\"STYLE\",\"IFRAME\",\"OBJECT\",\"VIDEO\",\"AUDIO\",\"NOSCRIPT\"];D.hasContentVirtual=function(a,b){return j(a)||D.isVisualContent(a.actualNode)||!!A.labelVirtual(a)||!b&&a.children.some(function(a){return 1===a.actualNode.nodeType&&D.hasContentVirtual(a)})},D.hasContent=function(a,b){return a=axe.utils.getNodeFromTree(axe._tree[0],a),D.hasContentVirtual(a,b)},D.idrefs=function(a,b){\"use strict\";var c,d,e=D.getRootNode(a),f=[],g=a.getAttribute(b);if(g)for(g=axe.utils.tokenList(g),c=0,d=g.length;c<d;c++)f.push(e.getElementById(g[c]));return f},D.isFocusable=function(a){\"use strict\";if(k(a))return!1;if(D.isNativelyFocusable(a))return!0;var b=a.getAttribute(\"tabindex\");return!(!b||isNaN(parseInt(b,10)))},D.isNativelyFocusable=function(a){\"use strict\";if(!a||k(a))return!1;switch(a.nodeName.toUpperCase()){case\"A\":case\"AREA\":if(a.href)return!0;break;case\"INPUT\":return\"hidden\"!==a.type;case\"TEXTAREA\":case\"SELECT\":case\"DETAILS\":case\"BUTTON\":return!0}return!1},D.insertedIntoFocusOrder=function(a){return a.tabIndex>-1&&D.isFocusable(a)&&!D.isNativelyFocusable(a)},D.isHTML5=function(a){var b=a.doctype;return null!==b&&(\"html\"===b.name&&!b.publicId&&!b.systemId)};var I=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];D.isInTextBlock=function(a){if(m(a))return!1;var b=n(a),c=\"\",d=\"\",e=0;return l(b,function(b){if(2===e)return!1;if(3===b.nodeType&&(c+=b.nodeValue),1===b.nodeType){var f=(b.nodeName||\"\").toUpperCase();if([\"BR\",\"HR\"].includes(f))0===e?(c=\"\",d=\"\"):e=2;else{if(\"none\"===b.style.display||\"hidden\"===b.style.overflow||![\"\",null,\"none\"].includes(b.style.float)||![\"\",null,\"relative\"].includes(b.style.position))return!1;if(\"A\"===f&&b.href||\"link\"===(b.getAttribute(\"role\")||\"\").toLowerCase())return b===a&&(e=1),d+=b.textContent,!1}}}),c=axe.commons.text.sanitize(c),d=axe.commons.text.sanitize(d),c.length>d.length},D.isNode=function(a){\"use strict\";return a instanceof Node},D.isOffscreen=function(a){var b=void 0,c=document.documentElement,d=window.getComputedStyle(a),e=window.getComputedStyle(document.body||c).getPropertyValue(\"direction\"),f=D.getElementCoordinates(a);if(f.bottom<0&&(o(a,f.bottom)||\"absolute\"===d.position))return!0;if(0===f.left&&0===f.right)return!1;if(\"ltr\"===e){if(f.right<=0)return!0}else if(b=Math.max(c.scrollWidth,D.getViewportSize(window).width),f.left>=b)return!0;return!1},D.isVisible=function(a,b,c){\"use strict\";var d,e,f;return 9===a.nodeType||(11===a.nodeType&&(a=a.host),null!==(d=window.getComputedStyle(a,null))&&(e=a.nodeName.toUpperCase(),!(\"none\"===d.getPropertyValue(\"display\")||\"STYLE\"===e.toUpperCase()||\"SCRIPT\"===e.toUpperCase()||!b&&p(d.getPropertyValue(\"clip\"))||!c&&(\"hidden\"===d.getPropertyValue(\"visibility\")||!b&&D.isOffscreen(a))||b&&\"true\"===a.getAttribute(\"aria-hidden\"))&&(!!(f=a.assignedSlot?a.assignedSlot:a.parentNode)&&D.isVisible(f,b,!0))))};var J=[\"checkbox\",\"img\",\"radio\",\"range\",\"slider\",\"spinbutton\",\"textbox\"];D.isVisualContent=function(a){var b=a.getAttribute(\"role\");if(b)return-1!==J.indexOf(b);switch(a.tagName.toUpperCase()){case\"IMG\":case\"IFRAME\":case\"OBJECT\":case\"VIDEO\":case\"AUDIO\":case\"CANVAS\":case\"SVG\":case\"MATH\":case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":case\"KEYGEN\":case\"PROGRESS\":case\"METER\":return!0;case\"INPUT\":return\"hidden\"!==a.type;default:return!1}},D.shadowElementsFromPoint=function(a,b){return(arguments.length>2&&void 0!==arguments[2]?arguments[2]:document).elementsFromPoint(a,b).reduce(function(c,d){if(axe.utils.isShadowRoot(d)){var e=D.shadowElementsFromPoint(a,b,d.shadowRoot);c=c.concat(e),c.length&&axe.commons.dom.visuallyContains(c[0],d)&&c.push(d)}else c.push(d);return c},[])},D.visuallyContains=function(a,b){var c=a.getBoundingClientRect(),d={top:c.top+.01,bottom:c.bottom-.01,left:c.left+.01,right:c.right-.01},e=b.getBoundingClientRect(),f=e.top,g=e.left,h={top:f-b.scrollTop,bottom:f-b.scrollTop+b.scrollHeight,left:g-b.scrollLeft,right:g-b.scrollLeft+b.scrollWidth},i=window.getComputedStyle(b);return\"inline\"===i.getPropertyValue(\"display\")||!(d.left<h.left&&d.left<e.left||d.top<h.top&&d.top<e.top||d.right>h.right&&d.right>e.right||d.bottom>h.bottom&&d.bottom>e.bottom)&&(!(d.right>e.right||d.bottom>e.bottom)||(\"scroll\"===i.overflow||\"auto\"===i.overflow||\"hidden\"===i.overflow||b instanceof HTMLBodyElement||b instanceof HTMLHtmlElement))},D.visuallyOverlaps=function(a,b){var c=b.getBoundingClientRect(),d=c.top,e=c.left,f={top:d-b.scrollTop,bottom:d-b.scrollTop+b.scrollHeight,left:e-b.scrollLeft,right:e-b.scrollLeft+b.scrollWidth};if(a.left>f.right&&a.left>c.right||a.top>f.bottom&&a.top>c.bottom||a.right<f.left&&a.right<c.left||a.bottom<f.top&&a.bottom<c.top)return!1;var g=window.getComputedStyle(b);return!(a.left>c.right||a.top>c.bottom)||(\"scroll\"===g.overflow||\"auto\"===g.overflow||b instanceof HTMLBodyElement||b instanceof HTMLHtmlElement)},E.getAllCells=function(a){var b,c,d,e,f=[];for(b=0,d=a.rows.length;b<d;b++)for(c=0,e=a.rows[b].cells.length;c<e;c++)f.push(a.rows[b].cells[c]);return f},E.getCellPosition=function(a,b){var c,d;for(b||(b=E.toGrid(D.findUp(a,\"table\"))),c=0;c<b.length;c++)if(b[c]&&-1!==(d=b[c].indexOf(a)))return{x:d,y:c}},E.getHeaders=function(a){if(a.hasAttribute(\"headers\"))return commons.dom.idrefs(a,\"headers\");var b=commons.table.toGrid(commons.dom.findUp(a,\"table\")),c=commons.table.getCellPosition(a,b);return[].concat(E.traverse(\"left\",c,b).filter(function(a){return E.isRowHeader(a)}),E.traverse(\"up\",c,b).filter(function(a){return E.isColumnHeader(a)})).reverse()},E.getScope=function(a){var b=a.getAttribute(\"scope\"),c=a.getAttribute(\"role\");if(a instanceof Element==!1||-1===[\"TD\",\"TH\"].indexOf(a.nodeName.toUpperCase()))throw new TypeError(\"Expected TD or TH element\");if(\"columnheader\"===c)return\"col\";if(\"rowheader\"===c)return\"row\";if(\"col\"===b||\"row\"===b)return b;if(\"TH\"!==a.nodeName.toUpperCase())return!1;var d=E.toGrid(D.findUp(a,\"table\")),e=E.getCellPosition(a);return d[e.y].reduce(function(a,b){return a&&\"TH\"===b.nodeName.toUpperCase()},!0)?\"col\":d.map(function(a){return a[e.x]}).reduce(function(a,b){return a&&\"TH\"===b.nodeName.toUpperCase()},!0)?\"row\":\"auto\"},E.isColumnHeader=function(a){return-1!==[\"col\",\"auto\"].indexOf(E.getScope(a))},E.isDataCell=function(a){return!(!a.children.length&&!a.textContent.trim())&&\"TD\"===a.nodeName.toUpperCase()},E.isDataTable=function(a){var b=(a.getAttribute(\"role\")||\"\").toLowerCase();if((\"presentation\"===b||\"none\"===b)&&!D.isFocusable(a))return!1;if(\"true\"===a.getAttribute(\"contenteditable\")||D.findUp(a,'[contenteditable=\"true\"]'))return!0;if(\"grid\"===b||\"treegrid\"===b||\"table\"===b)return!0;if(\"landmark\"===commons.aria.getRoleType(b))return!0;if(\"0\"===a.getAttribute(\"datatable\"))return!1;if(a.getAttribute(\"summary\"))return!0;if(a.tHead||a.tFoot||a.caption)return!0;for(var c=0,d=a.children.length;c<d;c++)if(\"COLGROUP\"===a.children[c].nodeName.toUpperCase())return!0;for(var e,f,g=0,h=a.rows.length,i=!1,j=0;j<h;j++){e=a.rows[j];for(var k=0,l=e.cells.length;k<l;k++){if(f=e.cells[k],\"TH\"===f.nodeName.toUpperCase())return!0;if(i||f.offsetWidth===f.clientWidth&&f.offsetHeight===f.clientHeight||(i=!0),f.getAttribute(\"scope\")||f.getAttribute(\"headers\")||f.getAttribute(\"abbr\"))return!0;if([\"columnheader\",\"rowheader\"].includes((f.getAttribute(\"role\")||\"\").toLowerCase()))return!0;if(1===f.children.length&&\"ABBR\"===f.children[0].nodeName.toUpperCase())return!0;g++}}if(a.getElementsByTagName(\"table\").length)return!1;if(h<2)return!1;var m=a.rows[Math.ceil(h/2)];if(1===m.cells.length&&1===m.cells[0].colSpan)return!1;if(m.cells.length>=5)return!0;if(i)return!0;var n,o;for(j=0;j<h;j++){if(e=a.rows[j],n&&n!==window.getComputedStyle(e).getPropertyValue(\"background-color\"))return!0;if(n=window.getComputedStyle(e).getPropertyValue(\"background-color\"),o&&o!==window.getComputedStyle(e).getPropertyValue(\"background-image\"))return!0;o=window.getComputedStyle(e).getPropertyValue(\"background-image\")}return h>=20||!(D.getElementCoordinates(a).width>.95*D.getViewportSize(window).width)&&(!(g<10)&&!a.querySelector(\"object, embed, iframe, applet\"))},E.isHeader=function(a){if(E.isColumnHeader(a)||E.isRowHeader(a))return!0;if(a.getAttribute(\"id\")){var b=axe.utils.escapeSelector(a.getAttribute(\"id\"));return!!document.querySelector('[headers~=\"'+b+'\"]')}return!1},E.isRowHeader=function(a){return[\"row\",\"auto\"].includes(E.getScope(a))},E.toGrid=function(a){for(var b=[],c=a.rows,d=0,e=c.length;d<e;d++){var f=c[d].cells;b[d]=b[d]||[];for(var g=0,h=0,i=f.length;h<i;h++)for(var j=0;j<f[h].colSpan;j++){for(var k=0;k<f[h].rowSpan;k++){for(b[d+k]=b[d+k]||[];b[d+k][g];)g++;b[d+k][g]=f[h]}g++}}return b},E.toArray=E.toGrid,function(a){var b=function a(b,c,d,e){var f,g=d[c.y]?d[c.y][c.x]:void 0;return g?\"function\"==typeof e&&!0===(f=e(g,c,d))?[g]:(f=a(b,{x:c.x+b.x,y:c.y+b.y},d,e),f.unshift(g),f):[]};a.traverse=function(a,c,d,e){if(Array.isArray(c)&&(e=d,d=c,c={x:0,y:0}),\"string\"==typeof a)switch(a){case\"left\":a={x:-1,y:0};break;case\"up\":a={x:0,y:-1};break;case\"right\":a={x:1,y:0};break;case\"down\":a={x:0,y:1}}return b(a,{x:c.x+a.x,y:c.y+a.y},d,e)}}(E);var K={submit:\"Submit\",reset:\"Reset\"},L=[\"text\",\"search\",\"tel\",\"url\",\"email\",\"date\",\"time\",\"number\",\"range\",\"color\"],M=[\"A\",\"EM\",\"STRONG\",\"SMALL\",\"MARK\",\"ABBR\",\"DFN\",\"I\",\"B\",\"S\",\"U\",\"CODE\",\"VAR\",\"SAMP\",\"KBD\",\"SUP\",\"SUB\",\"Q\",\"CITE\",\"SPAN\",\"BDO\",\"BDI\",\"BR\",\"WBR\",\"INS\",\"DEL\",\"IMG\",\"EMBED\",\"OBJECT\",\"IFRAME\",\"MAP\",\"AREA\",\"SCRIPT\",\"NOSCRIPT\",\"RUBY\",\"VIDEO\",\"AUDIO\",\"INPUT\",\"TEXTAREA\",\"SELECT\",\"BUTTON\",\"LABEL\",\"OUTPUT\",\"DATALIST\",\"KEYGEN\",\"PROGRESS\",\"COMMAND\",\"CANVAS\",\"TIME\",\"METER\"];F.accessibleText=function(a,b){var c=axe.utils.getNodeFromTree(axe._tree[0],a);return axe.commons.text.accessibleTextVirtual(c,b)},F.accessibleTextVirtual=function(a,b){function c(a,b,c){return a.children.reduce(function(a,d){var e=d.actualNode;return 3===e.nodeType?a+=e.nodeValue:1===e.nodeType&&(M.includes(e.nodeName.toUpperCase())||(a+=\" \"),a+=g(d,b,c)),a},\"\")}function d(a){return axe.commons.table.isDataTable(a.actualNode)||1!==axe.commons.table.getAllCells(a.actualNode).length?\"\":c(a,!1,!1).trim()}function e(a,b,e){var f=\"\",h=a.actualNode,i=h.nodeName.toUpperCase();if(t(a)&&(f=c(a,!1,!1)||\"\",z(f)))return f;if(\"FIGURE\"===i&&(f=w(a,\"figcaption\"),z(f)))return f;if(\"TABLE\"===i){if(f=w(a,\"caption\"),z(f))return f;if(f=h.getAttribute(\"title\")||h.getAttribute(\"summary\")||d(a)||\"\",z(f))return f}if(y(a))return h.getAttribute(\"alt\")||\"\";if(s(a)&&!e){if(r(a))return h.value||h.title||K[h.type]||\"\";var j=q(a);if(j)return g(j,b,!0)}return\"\"}function f(a,b,c){var d=\"\",e=a.actualNode;return!b&&e.hasAttribute(\"aria-labelledby\")&&(d=F.sanitize(D.idrefs(e,\"aria-labelledby\").map(function(a){if(null!==a){e===a&&h.pop();var b=axe.utils.getNodeFromTree(axe._tree[0],a);return g(b,!0,e!==a)}return\"\"}).join(\" \"))),d||c&&x(a)||!e.hasAttribute(\"aria-label\")?d:F.sanitize(e.getAttribute(\"aria-label\"))}var g=void 0,h=[];return a instanceof Node&&(a=axe.utils.getNodeFromTree(axe._tree[0],a)),g=function(a,b,d){var g=void 0;if(!a||h.includes(a))return\"\";if(null!==a&&a.actualNode instanceof Node!=!0)throw new Error(\"Invalid argument. Virtual Node must be provided\");if(!b&&!D.isVisible(a.actualNode,!0))return\"\";h.push(a);var i=a.actualNode.getAttribute(\"role\");return g=f(a,b,d),z(g)?g:(g=e(a,b,d),z(g)?g:d&&(g=v(a),z(g))?g:u(a)||i&&-1===A.getRolesWithNameFromContents().indexOf(i)||(g=c(a,b,d),!z(g))?a.actualNode.hasAttribute(\"title\")?a.actualNode.getAttribute(\"title\"):\"\":g)},F.sanitize(g(a,b))},F.labelVirtual=function(a){var b,c,d;if(c=A.labelVirtual(a))return c;if(a.actualNode.id){var e=axe.commons.utils.escapeSelector(a.actualNode.getAttribute(\"id\"));if(d=axe.commons.dom.getRootNode(a.actualNode),b=d.querySelector('label[for=\"'+e+'\"]'),c=b&&F.visible(b,!0))return c}return b=D.findUpVirtual(a,\"label\"),(c=b&&F.visible(b,!0))||null},F.label=function(a){return a=axe.utils.getNodeFromTree(axe._tree[0],a),F.labelVirtual(a)},F.sanitize=function(a){\"use strict\";return a.replace(/\\r\\n/g,\"\\n\").replace(/\\u00A0/g,\" \").replace(/[\\s]{2,}/g,\" \").trim()},F.visibleVirtual=function(a,b,c){var d=a.children.map(function(d){if(3===d.actualNode.nodeType){var e=d.actualNode.nodeValue;if(e&&D.isVisible(a.actualNode,b))return e}else if(!c)return F.visibleVirtual(d,b)}).join(\"\");return F.sanitize(d)},F.visible=function(a,b,c){return a=axe.utils.getNodeFromTree(axe._tree[0],a),F.visibleVirtual(a,b,c)},axe.utils.tokenList=function(a){\"use strict\";return a.trim().replace(/\\s{2,}/g,\" \").split(\" \")}\n;var N=[\"aa\",\"ab\",\"ae\",\"af\",\"ak\",\"am\",\"an\",\"ar\",\"as\",\"av\",\"ay\",\"az\",\"ba\",\"be\",\"bg\",\"bh\",\"bi\",\"bm\",\"bn\",\"bo\",\"br\",\"bs\",\"ca\",\"ce\",\"ch\",\"co\",\"cr\",\"cs\",\"cu\",\"cv\",\"cy\",\"da\",\"de\",\"dv\",\"dz\",\"ee\",\"el\",\"en\",\"eo\",\"es\",\"et\",\"eu\",\"fa\",\"ff\",\"fi\",\"fj\",\"fo\",\"fr\",\"fy\",\"ga\",\"gd\",\"gl\",\"gn\",\"gu\",\"gv\",\"ha\",\"he\",\"hi\",\"ho\",\"hr\",\"ht\",\"hu\",\"hy\",\"hz\",\"ia\",\"id\",\"ie\",\"ig\",\"ii\",\"ik\",\"in\",\"io\",\"is\",\"it\",\"iu\",\"iw\",\"ja\",\"ji\",\"jv\",\"jw\",\"ka\",\"kg\",\"ki\",\"kj\",\"kk\",\"kl\",\"km\",\"kn\",\"ko\",\"kr\",\"ks\",\"ku\",\"kv\",\"kw\",\"ky\",\"la\",\"lb\",\"lg\",\"li\",\"ln\",\"lo\",\"lt\",\"lu\",\"lv\",\"mg\",\"mh\",\"mi\",\"mk\",\"ml\",\"mn\",\"mo\",\"mr\",\"ms\",\"mt\",\"my\",\"na\",\"nb\",\"nd\",\"ne\",\"ng\",\"nl\",\"nn\",\"no\",\"nr\",\"nv\",\"ny\",\"oc\",\"oj\",\"om\",\"or\",\"os\",\"pa\",\"pi\",\"pl\",\"ps\",\"pt\",\"qu\",\"rm\",\"rn\",\"ro\",\"ru\",\"rw\",\"sa\",\"sc\",\"sd\",\"se\",\"sg\",\"sh\",\"si\",\"sk\",\"sl\",\"sm\",\"sn\",\"so\",\"sq\",\"sr\",\"ss\",\"st\",\"su\",\"sv\",\"sw\",\"ta\",\"te\",\"tg\",\"th\",\"ti\",\"tk\",\"tl\",\"tn\",\"to\",\"tr\",\"ts\",\"tt\",\"tw\",\"ty\",\"ug\",\"uk\",\"ur\",\"uz\",\"ve\",\"vi\",\"vo\",\"wa\",\"wo\",\"xh\",\"yi\",\"yo\",\"za\",\"zh\",\"zu\",\"aaa\",\"aab\",\"aac\",\"aad\",\"aae\",\"aaf\",\"aag\",\"aah\",\"aai\",\"aak\",\"aal\",\"aam\",\"aan\",\"aao\",\"aap\",\"aaq\",\"aas\",\"aat\",\"aau\",\"aav\",\"aaw\",\"aax\",\"aaz\",\"aba\",\"abb\",\"abc\",\"abd\",\"abe\",\"abf\",\"abg\",\"abh\",\"abi\",\"abj\",\"abl\",\"abm\",\"abn\",\"abo\",\"abp\",\"abq\",\"abr\",\"abs\",\"abt\",\"abu\",\"abv\",\"abw\",\"abx\",\"aby\",\"abz\",\"aca\",\"acb\",\"acd\",\"ace\",\"acf\",\"ach\",\"aci\",\"ack\",\"acl\",\"acm\",\"acn\",\"acp\",\"acq\",\"acr\",\"acs\",\"act\",\"acu\",\"acv\",\"acw\",\"acx\",\"acy\",\"acz\",\"ada\",\"adb\",\"add\",\"ade\",\"adf\",\"adg\",\"adh\",\"adi\",\"adj\",\"adl\",\"adn\",\"ado\",\"adp\",\"adq\",\"adr\",\"ads\",\"adt\",\"adu\",\"adw\",\"adx\",\"ady\",\"adz\",\"aea\",\"aeb\",\"aec\",\"aed\",\"aee\",\"aek\",\"ael\",\"aem\",\"aen\",\"aeq\",\"aer\",\"aes\",\"aeu\",\"aew\",\"aey\",\"aez\",\"afa\",\"afb\",\"afd\",\"afe\",\"afg\",\"afh\",\"afi\",\"afk\",\"afn\",\"afo\",\"afp\",\"afs\",\"aft\",\"afu\",\"afz\",\"aga\",\"agb\",\"agc\",\"agd\",\"age\",\"agf\",\"agg\",\"agh\",\"agi\",\"agj\",\"agk\",\"agl\",\"agm\",\"agn\",\"ago\",\"agp\",\"agq\",\"agr\",\"ags\",\"agt\",\"agu\",\"agv\",\"agw\",\"agx\",\"agy\",\"agz\",\"aha\",\"ahb\",\"ahg\",\"ahh\",\"ahi\",\"ahk\",\"ahl\",\"ahm\",\"ahn\",\"aho\",\"ahp\",\"ahr\",\"ahs\",\"aht\",\"aia\",\"aib\",\"aic\",\"aid\",\"aie\",\"aif\",\"aig\",\"aih\",\"aii\",\"aij\",\"aik\",\"ail\",\"aim\",\"ain\",\"aio\",\"aip\",\"aiq\",\"air\",\"ais\",\"ait\",\"aiw\",\"aix\",\"aiy\",\"aja\",\"ajg\",\"aji\",\"ajn\",\"ajp\",\"ajt\",\"aju\",\"ajw\",\"ajz\",\"akb\",\"akc\",\"akd\",\"ake\",\"akf\",\"akg\",\"akh\",\"aki\",\"akj\",\"akk\",\"akl\",\"akm\",\"ako\",\"akp\",\"akq\",\"akr\",\"aks\",\"akt\",\"aku\",\"akv\",\"akw\",\"akx\",\"aky\",\"akz\",\"ala\",\"alc\",\"ald\",\"ale\",\"alf\",\"alg\",\"alh\",\"ali\",\"alj\",\"alk\",\"all\",\"alm\",\"aln\",\"alo\",\"alp\",\"alq\",\"alr\",\"als\",\"alt\",\"alu\",\"alv\",\"alw\",\"alx\",\"aly\",\"alz\",\"ama\",\"amb\",\"amc\",\"ame\",\"amf\",\"amg\",\"ami\",\"amj\",\"amk\",\"aml\",\"amm\",\"amn\",\"amo\",\"amp\",\"amq\",\"amr\",\"ams\",\"amt\",\"amu\",\"amv\",\"amw\",\"amx\",\"amy\",\"amz\",\"ana\",\"anb\",\"anc\",\"and\",\"ane\",\"anf\",\"ang\",\"anh\",\"ani\",\"anj\",\"ank\",\"anl\",\"anm\",\"ann\",\"ano\",\"anp\",\"anq\",\"anr\",\"ans\",\"ant\",\"anu\",\"anv\",\"anw\",\"anx\",\"any\",\"anz\",\"aoa\",\"aob\",\"aoc\",\"aod\",\"aoe\",\"aof\",\"aog\",\"aoh\",\"aoi\",\"aoj\",\"aok\",\"aol\",\"aom\",\"aon\",\"aor\",\"aos\",\"aot\",\"aou\",\"aox\",\"aoz\",\"apa\",\"apb\",\"apc\",\"apd\",\"ape\",\"apf\",\"apg\",\"aph\",\"api\",\"apj\",\"apk\",\"apl\",\"apm\",\"apn\",\"apo\",\"app\",\"apq\",\"apr\",\"aps\",\"apt\",\"apu\",\"apv\",\"apw\",\"apx\",\"apy\",\"apz\",\"aqa\",\"aqc\",\"aqd\",\"aqg\",\"aql\",\"aqm\",\"aqn\",\"aqp\",\"aqr\",\"aqt\",\"aqz\",\"arb\",\"arc\",\"ard\",\"are\",\"arh\",\"ari\",\"arj\",\"ark\",\"arl\",\"arn\",\"aro\",\"arp\",\"arq\",\"arr\",\"ars\",\"art\",\"aru\",\"arv\",\"arw\",\"arx\",\"ary\",\"arz\",\"asa\",\"asb\",\"asc\",\"asd\",\"ase\",\"asf\",\"asg\",\"ash\",\"asi\",\"asj\",\"ask\",\"asl\",\"asn\",\"aso\",\"asp\",\"asq\",\"asr\",\"ass\",\"ast\",\"asu\",\"asv\",\"asw\",\"asx\",\"asy\",\"asz\",\"ata\",\"atb\",\"atc\",\"atd\",\"ate\",\"atg\",\"ath\",\"ati\",\"atj\",\"atk\",\"atl\",\"atm\",\"atn\",\"ato\",\"atp\",\"atq\",\"atr\",\"ats\",\"att\",\"atu\",\"atv\",\"atw\",\"atx\",\"aty\",\"atz\",\"aua\",\"aub\",\"auc\",\"aud\",\"aue\",\"auf\",\"aug\",\"auh\",\"aui\",\"auj\",\"auk\",\"aul\",\"aum\",\"aun\",\"auo\",\"aup\",\"auq\",\"aur\",\"aus\",\"aut\",\"auu\",\"auw\",\"aux\",\"auy\",\"auz\",\"avb\",\"avd\",\"avi\",\"avk\",\"avl\",\"avm\",\"avn\",\"avo\",\"avs\",\"avt\",\"avu\",\"avv\",\"awa\",\"awb\",\"awc\",\"awd\",\"awe\",\"awg\",\"awh\",\"awi\",\"awk\",\"awm\",\"awn\",\"awo\",\"awr\",\"aws\",\"awt\",\"awu\",\"awv\",\"aww\",\"awx\",\"awy\",\"axb\",\"axe\",\"axg\",\"axk\",\"axl\",\"axm\",\"axx\",\"aya\",\"ayb\",\"ayc\",\"ayd\",\"aye\",\"ayg\",\"ayh\",\"ayi\",\"ayk\",\"ayl\",\"ayn\",\"ayo\",\"ayp\",\"ayq\",\"ayr\",\"ays\",\"ayt\",\"ayu\",\"ayx\",\"ayy\",\"ayz\",\"aza\",\"azb\",\"azc\",\"azd\",\"azg\",\"azj\",\"azm\",\"azn\",\"azo\",\"azt\",\"azz\",\"baa\",\"bab\",\"bac\",\"bad\",\"bae\",\"baf\",\"bag\",\"bah\",\"bai\",\"baj\",\"bal\",\"ban\",\"bao\",\"bap\",\"bar\",\"bas\",\"bat\",\"bau\",\"bav\",\"baw\",\"bax\",\"bay\",\"baz\",\"bba\",\"bbb\",\"bbc\",\"bbd\",\"bbe\",\"bbf\",\"bbg\",\"bbh\",\"bbi\",\"bbj\",\"bbk\",\"bbl\",\"bbm\",\"bbn\",\"bbo\",\"bbp\",\"bbq\",\"bbr\",\"bbs\",\"bbt\",\"bbu\",\"bbv\",\"bbw\",\"bbx\",\"bby\",\"bbz\",\"bca\",\"bcb\",\"bcc\",\"bcd\",\"bce\",\"bcf\",\"bcg\",\"bch\",\"bci\",\"bcj\",\"bck\",\"bcl\",\"bcm\",\"bcn\",\"bco\",\"bcp\",\"bcq\",\"bcr\",\"bcs\",\"bct\",\"bcu\",\"bcv\",\"bcw\",\"bcy\",\"bcz\",\"bda\",\"bdb\",\"bdc\",\"bdd\",\"bde\",\"bdf\",\"bdg\",\"bdh\",\"bdi\",\"bdj\",\"bdk\",\"bdl\",\"bdm\",\"bdn\",\"bdo\",\"bdp\",\"bdq\",\"bdr\",\"bds\",\"bdt\",\"bdu\",\"bdv\",\"bdw\",\"bdx\",\"bdy\",\"bdz\",\"bea\",\"beb\",\"bec\",\"bed\",\"bee\",\"bef\",\"beg\",\"beh\",\"bei\",\"bej\",\"bek\",\"bem\",\"beo\",\"bep\",\"beq\",\"ber\",\"bes\",\"bet\",\"beu\",\"bev\",\"bew\",\"bex\",\"bey\",\"bez\",\"bfa\",\"bfb\",\"bfc\",\"bfd\",\"bfe\",\"bff\",\"bfg\",\"bfh\",\"bfi\",\"bfj\",\"bfk\",\"bfl\",\"bfm\",\"bfn\",\"bfo\",\"bfp\",\"bfq\",\"bfr\",\"bfs\",\"bft\",\"bfu\",\"bfw\",\"bfx\",\"bfy\",\"bfz\",\"bga\",\"bgb\",\"bgc\",\"bgd\",\"bge\",\"bgf\",\"bgg\",\"bgi\",\"bgj\",\"bgk\",\"bgl\",\"bgm\",\"bgn\",\"bgo\",\"bgp\",\"bgq\",\"bgr\",\"bgs\",\"bgt\",\"bgu\",\"bgv\",\"bgw\",\"bgx\",\"bgy\",\"bgz\",\"bha\",\"bhb\",\"bhc\",\"bhd\",\"bhe\",\"bhf\",\"bhg\",\"bhh\",\"bhi\",\"bhj\",\"bhk\",\"bhl\",\"bhm\",\"bhn\",\"bho\",\"bhp\",\"bhq\",\"bhr\",\"bhs\",\"bht\",\"bhu\",\"bhv\",\"bhw\",\"bhx\",\"bhy\",\"bhz\",\"bia\",\"bib\",\"bic\",\"bid\",\"bie\",\"bif\",\"big\",\"bij\",\"bik\",\"bil\",\"bim\",\"bin\",\"bio\",\"bip\",\"biq\",\"bir\",\"bit\",\"biu\",\"biv\",\"biw\",\"bix\",\"biy\",\"biz\",\"bja\",\"bjb\",\"bjc\",\"bjd\",\"bje\",\"bjf\",\"bjg\",\"bjh\",\"bji\",\"bjj\",\"bjk\",\"bjl\",\"bjm\",\"bjn\",\"bjo\",\"bjp\",\"bjq\",\"bjr\",\"bjs\",\"bjt\",\"bju\",\"bjv\",\"bjw\",\"bjx\",\"bjy\",\"bjz\",\"bka\",\"bkb\",\"bkc\",\"bkd\",\"bkf\",\"bkg\",\"bkh\",\"bki\",\"bkj\",\"bkk\",\"bkl\",\"bkm\",\"bkn\",\"bko\",\"bkp\",\"bkq\",\"bkr\",\"bks\",\"bkt\",\"bku\",\"bkv\",\"bkw\",\"bkx\",\"bky\",\"bkz\",\"bla\",\"blb\",\"blc\",\"bld\",\"ble\",\"blf\",\"blg\",\"blh\",\"bli\",\"blj\",\"blk\",\"bll\",\"blm\",\"bln\",\"blo\",\"blp\",\"blq\",\"blr\",\"bls\",\"blt\",\"blv\",\"blw\",\"blx\",\"bly\",\"blz\",\"bma\",\"bmb\",\"bmc\",\"bmd\",\"bme\",\"bmf\",\"bmg\",\"bmh\",\"bmi\",\"bmj\",\"bmk\",\"bml\",\"bmm\",\"bmn\",\"bmo\",\"bmp\",\"bmq\",\"bmr\",\"bms\",\"bmt\",\"bmu\",\"bmv\",\"bmw\",\"bmx\",\"bmy\",\"bmz\",\"bna\",\"bnb\",\"bnc\",\"bnd\",\"bne\",\"bnf\",\"bng\",\"bni\",\"bnj\",\"bnk\",\"bnl\",\"bnm\",\"bnn\",\"bno\",\"bnp\",\"bnq\",\"bnr\",\"bns\",\"bnt\",\"bnu\",\"bnv\",\"bnw\",\"bnx\",\"bny\",\"bnz\",\"boa\",\"bob\",\"boe\",\"bof\",\"bog\",\"boh\",\"boi\",\"boj\",\"bok\",\"bol\",\"bom\",\"bon\",\"boo\",\"bop\",\"boq\",\"bor\",\"bot\",\"bou\",\"bov\",\"bow\",\"box\",\"boy\",\"boz\",\"bpa\",\"bpb\",\"bpd\",\"bpg\",\"bph\",\"bpi\",\"bpj\",\"bpk\",\"bpl\",\"bpm\",\"bpn\",\"bpo\",\"bpp\",\"bpq\",\"bpr\",\"bps\",\"bpt\",\"bpu\",\"bpv\",\"bpw\",\"bpx\",\"bpy\",\"bpz\",\"bqa\",\"bqb\",\"bqc\",\"bqd\",\"bqf\",\"bqg\",\"bqh\",\"bqi\",\"bqj\",\"bqk\",\"bql\",\"bqm\",\"bqn\",\"bqo\",\"bqp\",\"bqq\",\"bqr\",\"bqs\",\"bqt\",\"bqu\",\"bqv\",\"bqw\",\"bqx\",\"bqy\",\"bqz\",\"bra\",\"brb\",\"brc\",\"brd\",\"brf\",\"brg\",\"brh\",\"bri\",\"brj\",\"brk\",\"brl\",\"brm\",\"brn\",\"bro\",\"brp\",\"brq\",\"brr\",\"brs\",\"brt\",\"bru\",\"brv\",\"brw\",\"brx\",\"bry\",\"brz\",\"bsa\",\"bsb\",\"bsc\",\"bse\",\"bsf\",\"bsg\",\"bsh\",\"bsi\",\"bsj\",\"bsk\",\"bsl\",\"bsm\",\"bsn\",\"bso\",\"bsp\",\"bsq\",\"bsr\",\"bss\",\"bst\",\"bsu\",\"bsv\",\"bsw\",\"bsx\",\"bsy\",\"bta\",\"btb\",\"btc\",\"btd\",\"bte\",\"btf\",\"btg\",\"bth\",\"bti\",\"btj\",\"btk\",\"btl\",\"btm\",\"btn\",\"bto\",\"btp\",\"btq\",\"btr\",\"bts\",\"btt\",\"btu\",\"btv\",\"btw\",\"btx\",\"bty\",\"btz\",\"bua\",\"bub\",\"buc\",\"bud\",\"bue\",\"buf\",\"bug\",\"buh\",\"bui\",\"buj\",\"buk\",\"bum\",\"bun\",\"buo\",\"bup\",\"buq\",\"bus\",\"but\",\"buu\",\"buv\",\"buw\",\"bux\",\"buy\",\"buz\",\"bva\",\"bvb\",\"bvc\",\"bvd\",\"bve\",\"bvf\",\"bvg\",\"bvh\",\"bvi\",\"bvj\",\"bvk\",\"bvl\",\"bvm\",\"bvn\",\"bvo\",\"bvp\",\"bvq\",\"bvr\",\"bvt\",\"bvu\",\"bvv\",\"bvw\",\"bvx\",\"bvy\",\"bvz\",\"bwa\",\"bwb\",\"bwc\",\"bwd\",\"bwe\",\"bwf\",\"bwg\",\"bwh\",\"bwi\",\"bwj\",\"bwk\",\"bwl\",\"bwm\",\"bwn\",\"bwo\",\"bwp\",\"bwq\",\"bwr\",\"bws\",\"bwt\",\"bwu\",\"bww\",\"bwx\",\"bwy\",\"bwz\",\"bxa\",\"bxb\",\"bxc\",\"bxd\",\"bxe\",\"bxf\",\"bxg\",\"bxh\",\"bxi\",\"bxj\",\"bxk\",\"bxl\",\"bxm\",\"bxn\",\"bxo\",\"bxp\",\"bxq\",\"bxr\",\"bxs\",\"bxu\",\"bxv\",\"bxw\",\"bxx\",\"bxz\",\"bya\",\"byb\",\"byc\",\"byd\",\"bye\",\"byf\",\"byg\",\"byh\",\"byi\",\"byj\",\"byk\",\"byl\",\"bym\",\"byn\",\"byo\",\"byp\",\"byq\",\"byr\",\"bys\",\"byt\",\"byv\",\"byw\",\"byx\",\"byy\",\"byz\",\"bza\",\"bzb\",\"bzc\",\"bzd\",\"bze\",\"bzf\",\"bzg\",\"bzh\",\"bzi\",\"bzj\",\"bzk\",\"bzl\",\"bzm\",\"bzn\",\"bzo\",\"bzp\",\"bzq\",\"bzr\",\"bzs\",\"bzt\",\"bzu\",\"bzv\",\"bzw\",\"bzx\",\"bzy\",\"bzz\",\"caa\",\"cab\",\"cac\",\"cad\",\"cae\",\"caf\",\"cag\",\"cah\",\"cai\",\"caj\",\"cak\",\"cal\",\"cam\",\"can\",\"cao\",\"cap\",\"caq\",\"car\",\"cas\",\"cau\",\"cav\",\"caw\",\"cax\",\"cay\",\"caz\",\"cba\",\"cbb\",\"cbc\",\"cbd\",\"cbe\",\"cbg\",\"cbh\",\"cbi\",\"cbj\",\"cbk\",\"cbl\",\"cbn\",\"cbo\",\"cbq\",\"cbr\",\"cbs\",\"cbt\",\"cbu\",\"cbv\",\"cbw\",\"cby\",\"cca\",\"ccc\",\"ccd\",\"cce\",\"ccg\",\"cch\",\"ccj\",\"ccl\",\"ccm\",\"ccn\",\"cco\",\"ccp\",\"ccq\",\"ccr\",\"ccs\",\"cda\",\"cdc\",\"cdd\",\"cde\",\"cdf\",\"cdg\",\"cdh\",\"cdi\",\"cdj\",\"cdm\",\"cdn\",\"cdo\",\"cdr\",\"cds\",\"cdy\",\"cdz\",\"cea\",\"ceb\",\"ceg\",\"cek\",\"cel\",\"cen\",\"cet\",\"cfa\",\"cfd\",\"cfg\",\"cfm\",\"cga\",\"cgc\",\"cgg\",\"cgk\",\"chb\",\"chc\",\"chd\",\"chf\",\"chg\",\"chh\",\"chj\",\"chk\",\"chl\",\"chm\",\"chn\",\"cho\",\"chp\",\"chq\",\"chr\",\"cht\",\"chw\",\"chx\",\"chy\",\"chz\",\"cia\",\"cib\",\"cic\",\"cid\",\"cie\",\"cih\",\"cik\",\"cim\",\"cin\",\"cip\",\"cir\",\"ciw\",\"ciy\",\"cja\",\"cje\",\"cjh\",\"cji\",\"cjk\",\"cjm\",\"cjn\",\"cjo\",\"cjp\",\"cjr\",\"cjs\",\"cjv\",\"cjy\",\"cka\",\"ckb\",\"ckh\",\"ckl\",\"ckn\",\"cko\",\"ckq\",\"ckr\",\"cks\",\"ckt\",\"cku\",\"ckv\",\"ckx\",\"cky\",\"ckz\",\"cla\",\"clc\",\"cld\",\"cle\",\"clh\",\"cli\",\"clj\",\"clk\",\"cll\",\"clm\",\"clo\",\"clt\",\"clu\",\"clw\",\"cly\",\"cma\",\"cmc\",\"cme\",\"cmg\",\"cmi\",\"cmk\",\"cml\",\"cmm\",\"cmn\",\"cmo\",\"cmr\",\"cms\",\"cmt\",\"cna\",\"cnb\",\"cnc\",\"cng\",\"cnh\",\"cni\",\"cnk\",\"cnl\",\"cno\",\"cns\",\"cnt\",\"cnu\",\"cnw\",\"cnx\",\"coa\",\"cob\",\"coc\",\"cod\",\"coe\",\"cof\",\"cog\",\"coh\",\"coj\",\"cok\",\"col\",\"com\",\"con\",\"coo\",\"cop\",\"coq\",\"cot\",\"cou\",\"cov\",\"cow\",\"cox\",\"coy\",\"coz\",\"cpa\",\"cpb\",\"cpc\",\"cpe\",\"cpf\",\"cpg\",\"cpi\",\"cpn\",\"cpo\",\"cpp\",\"cps\",\"cpu\",\"cpx\",\"cpy\",\"cqd\",\"cqu\",\"cra\",\"crb\",\"crc\",\"crd\",\"crf\",\"crg\",\"crh\",\"cri\",\"crj\",\"crk\",\"crl\",\"crm\",\"crn\",\"cro\",\"crp\",\"crq\",\"crr\",\"crs\",\"crt\",\"crv\",\"crw\",\"crx\",\"cry\",\"crz\",\"csa\",\"csb\",\"csc\",\"csd\",\"cse\",\"csf\",\"csg\",\"csh\",\"csi\",\"csj\",\"csk\",\"csl\",\"csm\",\"csn\",\"cso\",\"csq\",\"csr\",\"css\",\"cst\",\"csu\",\"csv\",\"csw\",\"csy\",\"csz\",\"cta\",\"ctc\",\"ctd\",\"cte\",\"ctg\",\"cth\",\"ctl\",\"ctm\",\"ctn\",\"cto\",\"ctp\",\"cts\",\"ctt\",\"ctu\",\"ctz\",\"cua\",\"cub\",\"cuc\",\"cug\",\"cuh\",\"cui\",\"cuj\",\"cuk\",\"cul\",\"cum\",\"cuo\",\"cup\",\"cuq\",\"cur\",\"cus\",\"cut\",\"cuu\",\"cuv\",\"cuw\",\"cux\",\"cvg\",\"cvn\",\"cwa\",\"cwb\",\"cwd\",\"cwe\",\"cwg\",\"cwt\",\"cya\",\"cyb\",\"cyo\",\"czh\",\"czk\",\"czn\",\"czo\",\"czt\",\"daa\",\"dac\",\"dad\",\"dae\",\"daf\",\"dag\",\"dah\",\"dai\",\"daj\",\"dak\",\"dal\",\"dam\",\"dao\",\"dap\",\"daq\",\"dar\",\"das\",\"dau\",\"dav\",\"daw\",\"dax\",\"day\",\"daz\",\"dba\",\"dbb\",\"dbd\",\"dbe\",\"dbf\",\"dbg\",\"dbi\",\"dbj\",\"dbl\",\"dbm\",\"dbn\",\"dbo\",\"dbp\",\"dbq\",\"dbr\",\"dbt\",\"dbu\",\"dbv\",\"dbw\",\"dby\",\"dcc\",\"dcr\",\"dda\",\"ddd\",\"dde\",\"ddg\",\"ddi\",\"ddj\",\"ddn\",\"ddo\",\"ddr\",\"dds\",\"ddw\",\"dec\",\"ded\",\"dee\",\"def\",\"deg\",\"deh\",\"dei\",\"dek\",\"del\",\"dem\",\"den\",\"dep\",\"deq\",\"der\",\"des\",\"dev\",\"dez\",\"dga\",\"dgb\",\"dgc\",\"dgd\",\"dge\",\"dgg\",\"dgh\",\"dgi\",\"dgk\",\"dgl\",\"dgn\",\"dgo\",\"dgr\",\"dgs\",\"dgt\",\"dgu\",\"dgw\",\"dgx\",\"dgz\",\"dha\",\"dhd\",\"dhg\",\"dhi\",\"dhl\",\"dhm\",\"dhn\",\"dho\",\"dhr\",\"dhs\",\"dhu\",\"dhv\",\"dhw\",\"dhx\",\"dia\",\"dib\",\"dic\",\"did\",\"dif\",\"dig\",\"dih\",\"dii\",\"dij\",\"dik\",\"dil\",\"dim\",\"din\",\"dio\",\"dip\",\"diq\",\"dir\",\"dis\",\"dit\",\"diu\",\"diw\",\"dix\",\"diy\",\"diz\",\"dja\",\"djb\",\"djc\",\"djd\",\"dje\",\"djf\",\"dji\",\"djj\",\"djk\",\"djl\",\"djm\",\"djn\",\"djo\",\"djr\",\"dju\",\"djw\",\"dka\",\"dkk\",\"dkl\",\"dkr\",\"dks\",\"dkx\",\"dlg\",\"dlk\",\"dlm\",\"dln\",\"dma\",\"dmb\",\"dmc\",\"dmd\",\"dme\",\"dmg\",\"dmk\",\"dml\",\"dmm\",\"dmn\",\"dmo\",\"dmr\",\"dms\",\"dmu\",\"dmv\",\"dmw\",\"dmx\",\"dmy\",\"dna\",\"dnd\",\"dne\",\"dng\",\"dni\",\"dnj\",\"dnk\",\"dnn\",\"dnr\",\"dnt\",\"dnu\",\"dnv\",\"dnw\",\"dny\",\"doa\",\"dob\",\"doc\",\"doe\",\"dof\",\"doh\",\"doi\",\"dok\",\"dol\",\"don\",\"doo\",\"dop\",\"doq\",\"dor\",\"dos\",\"dot\",\"dov\",\"dow\",\"dox\",\"doy\",\"doz\",\"dpp\",\"dra\",\"drb\",\"drc\",\"drd\",\"dre\",\"drg\",\"drh\",\"dri\",\"drl\",\"drn\",\"dro\",\"drq\",\"drr\",\"drs\",\"drt\",\"dru\",\"drw\",\"dry\",\"dsb\",\"dse\",\"dsh\",\"dsi\",\"dsl\",\"dsn\",\"dso\",\"dsq\",\"dta\",\"dtb\",\"dtd\",\"dth\",\"dti\",\"dtk\",\"dtm\",\"dtn\",\"dto\",\"dtp\",\"dtr\",\"dts\",\"dtt\",\"dtu\",\"dty\",\"dua\",\"dub\",\"duc\",\"dud\",\"due\",\"duf\",\"dug\",\"duh\",\"dui\",\"duj\",\"duk\",\"dul\",\"dum\",\"dun\",\"duo\",\"dup\",\"duq\",\"dur\",\"dus\",\"duu\",\"duv\",\"duw\",\"dux\",\"duy\",\"duz\",\"dva\",\"dwa\",\"dwl\",\"dwr\",\"dws\",\"dwu\",\"dww\",\"dwy\",\"dya\",\"dyb\",\"dyd\",\"dyg\",\"dyi\",\"dym\",\"dyn\",\"dyo\",\"dyu\",\"dyy\",\"dza\",\"dzd\",\"dze\",\"dzg\",\"dzl\",\"dzn\",\"eaa\",\"ebg\",\"ebk\",\"ebo\",\"ebr\",\"ebu\",\"ecr\",\"ecs\",\"ecy\",\"eee\",\"efa\",\"efe\",\"efi\",\"ega\",\"egl\",\"ego\",\"egx\",\"egy\",\"ehu\",\"eip\",\"eit\",\"eiv\",\"eja\",\"eka\",\"ekc\",\"eke\",\"ekg\",\"eki\",\"ekk\",\"ekl\",\"ekm\",\"eko\",\"ekp\",\"ekr\",\"eky\",\"ele\",\"elh\",\"eli\",\"elk\",\"elm\",\"elo\",\"elp\",\"elu\",\"elx\",\"ema\",\"emb\",\"eme\",\"emg\",\"emi\",\"emk\",\"emm\",\"emn\",\"emo\",\"emp\",\"ems\",\"emu\",\"emw\",\"emx\",\"emy\",\"ena\",\"enb\",\"enc\",\"end\",\"enf\",\"enh\",\"enl\",\"enm\",\"enn\",\"eno\",\"enq\",\"enr\",\"enu\",\"env\",\"enw\",\"enx\",\"eot\",\"epi\",\"era\",\"erg\",\"erh\",\"eri\",\"erk\",\"ero\",\"err\",\"ers\",\"ert\",\"erw\",\"ese\",\"esg\",\"esh\",\"esi\",\"esk\",\"esl\",\"esm\",\"esn\",\"eso\",\"esq\",\"ess\",\"esu\",\"esx\",\"esy\",\"etb\",\"etc\",\"eth\",\"etn\",\"eto\",\"etr\",\"ets\",\"ett\",\"etu\",\"etx\",\"etz\",\"euq\",\"eve\",\"evh\",\"evn\",\"ewo\",\"ext\",\"eya\",\"eyo\",\"eza\",\"eze\",\"faa\",\"fab\",\"fad\",\"faf\",\"fag\",\"fah\",\"fai\",\"faj\",\"fak\",\"fal\",\"fam\",\"fan\",\"fap\",\"far\",\"fat\",\"fau\",\"fax\",\"fay\",\"faz\",\"fbl\",\"fcs\",\"fer\",\"ffi\",\"ffm\",\"fgr\",\"fia\",\"fie\",\"fil\",\"fip\",\"fir\",\"fit\",\"fiu\",\"fiw\",\"fkk\",\"fkv\",\"fla\",\"flh\",\"fli\",\"fll\",\"fln\",\"flr\",\"fly\",\"fmp\",\"fmu\",\"fnb\",\"fng\",\"fni\",\"fod\",\"foi\",\"fom\",\"fon\",\"for\",\"fos\",\"fox\",\"fpe\",\"fqs\",\"frc\",\"frd\",\"frk\",\"frm\",\"fro\",\"frp\",\"frq\",\"frr\",\"frs\",\"frt\",\"fse\",\"fsl\",\"fss\",\"fub\",\"fuc\",\"fud\",\"fue\",\"fuf\",\"fuh\",\"fui\",\"fuj\",\"fum\",\"fun\",\"fuq\",\"fur\",\"fut\",\"fuu\",\"fuv\",\"fuy\",\"fvr\",\"fwa\",\"fwe\",\"gaa\",\"gab\",\"gac\",\"gad\",\"gae\",\"gaf\",\"gag\",\"gah\",\"gai\",\"gaj\",\"gak\",\"gal\",\"gam\",\"gan\",\"gao\",\"gap\",\"gaq\",\"gar\",\"gas\",\"gat\",\"gau\",\"gav\",\"gaw\",\"gax\",\"gay\",\"gaz\",\"gba\",\"gbb\",\"gbc\",\"gbd\",\"gbe\",\"gbf\",\"gbg\",\"gbh\",\"gbi\",\"gbj\",\"gbk\",\"gbl\",\"gbm\",\"gbn\",\"gbo\",\"gbp\",\"gbq\",\"gbr\",\"gbs\",\"gbu\",\"gbv\",\"gbw\",\"gbx\",\"gby\",\"gbz\",\"gcc\",\"gcd\",\"gce\",\"gcf\",\"gcl\",\"gcn\",\"gcr\",\"gct\",\"gda\",\"gdb\",\"gdc\",\"gdd\",\"gde\",\"gdf\",\"gdg\",\"gdh\",\"gdi\",\"gdj\",\"gdk\",\"gdl\",\"gdm\",\"gdn\",\"gdo\",\"gdq\",\"gdr\",\"gds\",\"gdt\",\"gdu\",\"gdx\",\"gea\",\"geb\",\"gec\",\"ged\",\"geg\",\"geh\",\"gei\",\"gej\",\"gek\",\"gel\",\"gem\",\"geq\",\"ges\",\"gev\",\"gew\",\"gex\",\"gey\",\"gez\",\"gfk\",\"gft\",\"gfx\",\"gga\",\"ggb\",\"ggd\",\"gge\",\"ggg\",\"ggk\",\"ggl\",\"ggn\",\"ggo\",\"ggr\",\"ggt\",\"ggu\",\"ggw\",\"gha\",\"ghc\",\"ghe\",\"ghh\",\"ghk\",\"ghl\",\"ghn\",\"gho\",\"ghr\",\"ghs\",\"ght\",\"gia\",\"gib\",\"gic\",\"gid\",\"gie\",\"gig\",\"gih\",\"gil\",\"gim\",\"gin\",\"gio\",\"gip\",\"giq\",\"gir\",\"gis\",\"git\",\"giu\",\"giw\",\"gix\",\"giy\",\"giz\",\"gji\",\"gjk\",\"gjm\",\"gjn\",\"gjr\",\"gju\",\"gka\",\"gke\",\"gkn\",\"gko\",\"gkp\",\"gku\",\"glc\",\"gld\",\"glh\",\"gli\",\"glj\",\"glk\",\"gll\",\"glo\",\"glr\",\"glu\",\"glw\",\"gly\",\"gma\",\"gmb\",\"gmd\",\"gme\",\"gmg\",\"gmh\",\"gml\",\"gmm\",\"gmn\",\"gmq\",\"gmu\",\"gmv\",\"gmw\",\"gmx\",\"gmy\",\"gmz\",\"gna\",\"gnb\",\"gnc\",\"gnd\",\"gne\",\"gng\",\"gnh\",\"gni\",\"gnk\",\"gnl\",\"gnm\",\"gnn\",\"gno\",\"gnq\",\"gnr\",\"gnt\",\"gnu\",\"gnw\",\"gnz\",\"goa\",\"gob\",\"goc\",\"god\",\"goe\",\"gof\",\"gog\",\"goh\",\"goi\",\"goj\",\"gok\",\"gol\",\"gom\",\"gon\",\"goo\",\"gop\",\"goq\",\"gor\",\"gos\",\"got\",\"gou\",\"gow\",\"gox\",\"goy\",\"goz\",\"gpa\",\"gpe\",\"gpn\",\"gqa\",\"gqi\",\"gqn\",\"gqr\",\"gqu\",\"gra\",\"grb\",\"grc\",\"grd\",\"grg\",\"grh\",\"gri\",\"grj\",\"grk\",\"grm\",\"gro\",\"grq\",\"grr\",\"grs\",\"grt\",\"gru\",\"grv\",\"grw\",\"grx\",\"gry\",\"grz\",\"gse\",\"gsg\",\"gsl\",\"gsm\",\"gsn\",\"gso\",\"gsp\",\"gss\",\"gsw\",\"gta\",\"gti\",\"gtu\",\"gua\",\"gub\",\"guc\",\"gud\",\"gue\",\"guf\",\"gug\",\"guh\",\"gui\",\"guk\",\"gul\",\"gum\",\"gun\",\"guo\",\"gup\",\"guq\",\"gur\",\"gus\",\"gut\",\"guu\",\"guv\",\"guw\",\"gux\",\"guz\",\"gva\",\"gvc\",\"gve\",\"gvf\",\"gvj\",\"gvl\",\"gvm\",\"gvn\",\"gvo\",\"gvp\",\"gvr\",\"gvs\",\"gvy\",\"gwa\",\"gwb\",\"gwc\",\"gwd\",\"gwe\",\"gwf\",\"gwg\",\"gwi\",\"gwj\",\"gwm\",\"gwn\",\"gwr\",\"gwt\",\"gwu\",\"gww\",\"gwx\",\"gxx\",\"gya\",\"gyb\",\"gyd\",\"gye\",\"gyf\",\"gyg\",\"gyi\",\"gyl\",\"gym\",\"gyn\",\"gyr\",\"gyy\",\"gza\",\"gzi\",\"gzn\",\"haa\",\"hab\",\"hac\",\"had\",\"hae\",\"haf\",\"hag\",\"hah\",\"hai\",\"haj\",\"hak\",\"hal\",\"ham\",\"han\",\"hao\",\"hap\",\"haq\",\"har\",\"has\",\"hav\",\"haw\",\"hax\",\"hay\",\"haz\",\"hba\",\"hbb\",\"hbn\",\"hbo\",\"hbu\",\"hca\",\"hch\",\"hdn\",\"hds\",\"hdy\",\"hea\",\"hed\",\"heg\",\"heh\",\"hei\",\"hem\",\"hgm\",\"hgw\",\"hhi\",\"hhr\",\"hhy\",\"hia\",\"hib\",\"hid\",\"hif\",\"hig\",\"hih\",\"hii\",\"hij\",\"hik\",\"hil\",\"him\",\"hio\",\"hir\",\"hit\",\"hiw\",\"hix\",\"hji\",\"hka\",\"hke\",\"hkk\",\"hks\",\"hla\",\"hlb\",\"hld\",\"hle\",\"hlt\",\"hlu\",\"hma\",\"hmb\",\"hmc\",\"hmd\",\"hme\",\"hmf\",\"hmg\",\"hmh\",\"hmi\",\"hmj\",\"hmk\",\"hml\",\"hmm\",\"hmn\",\"hmp\",\"hmq\",\"hmr\",\"hms\",\"hmt\",\"hmu\",\"hmv\",\"hmw\",\"hmx\",\"hmy\",\"hmz\",\"hna\",\"hnd\",\"hne\",\"hnh\",\"hni\",\"hnj\",\"hnn\",\"hno\",\"hns\",\"hnu\",\"hoa\",\"hob\",\"hoc\",\"hod\",\"hoe\",\"hoh\",\"hoi\",\"hoj\",\"hok\",\"hol\",\"hom\",\"hoo\",\"hop\",\"hor\",\"hos\",\"hot\",\"hov\",\"how\",\"hoy\",\"hoz\",\"hpo\",\"hps\",\"hra\",\"hrc\",\"hre\",\"hrk\",\"hrm\",\"hro\",\"hrp\",\"hrr\",\"hrt\",\"hru\",\"hrw\",\"hrx\",\"hrz\",\"hsb\",\"hsh\",\"hsl\",\"hsn\",\"hss\",\"hti\",\"hto\",\"hts\",\"htu\",\"htx\",\"hub\",\"huc\",\"hud\",\"hue\",\"huf\",\"hug\",\"huh\",\"hui\",\"huj\",\"huk\",\"hul\",\"hum\",\"huo\",\"hup\",\"huq\",\"hur\",\"hus\",\"hut\",\"huu\",\"huv\",\"huw\",\"hux\",\"huy\",\"huz\",\"hvc\",\"hve\",\"hvk\",\"hvn\",\"hvv\",\"hwa\",\"hwc\",\"hwo\",\"hya\",\"hyx\",\"iai\",\"ian\",\"iap\",\"iar\",\"iba\",\"ibb\",\"ibd\",\"ibe\",\"ibg\",\"ibh\",\"ibi\",\"ibl\",\"ibm\",\"ibn\",\"ibr\",\"ibu\",\"iby\",\"ica\",\"ich\",\"icl\",\"icr\",\"ida\",\"idb\",\"idc\",\"idd\",\"ide\",\"idi\",\"idr\",\"ids\",\"idt\",\"idu\",\"ifa\",\"ifb\",\"ife\",\"iff\",\"ifk\",\"ifm\",\"ifu\",\"ify\",\"igb\",\"ige\",\"igg\",\"igl\",\"igm\",\"ign\",\"igo\",\"igs\",\"igw\",\"ihb\",\"ihi\",\"ihp\",\"ihw\",\"iin\",\"iir\",\"ijc\",\"ije\",\"ijj\",\"ijn\",\"ijo\",\"ijs\",\"ike\",\"iki\",\"ikk\",\"ikl\",\"iko\",\"ikp\",\"ikr\",\"iks\",\"ikt\",\"ikv\",\"ikw\",\"ikx\",\"ikz\",\"ila\",\"ilb\",\"ilg\",\"ili\",\"ilk\",\"ill\",\"ilm\",\"ilo\",\"ilp\",\"ils\",\"ilu\",\"ilv\",\"ilw\",\"ima\",\"ime\",\"imi\",\"iml\",\"imn\",\"imo\",\"imr\",\"ims\",\"imy\",\"inb\",\"inc\",\"ine\",\"ing\",\"inh\",\"inj\",\"inl\",\"inm\",\"inn\",\"ino\",\"inp\",\"ins\",\"int\",\"inz\",\"ior\",\"iou\",\"iow\",\"ipi\",\"ipo\",\"iqu\",\"iqw\",\"ira\",\"ire\",\"irh\",\"iri\",\"irk\",\"irn\",\"iro\",\"irr\",\"iru\",\"irx\",\"iry\",\"isa\",\"isc\",\"isd\",\"ise\",\"isg\",\"ish\",\"isi\",\"isk\",\"ism\",\"isn\",\"iso\",\"isr\",\"ist\",\"isu\",\"itb\",\"itc\",\"itd\",\"ite\",\"iti\",\"itk\",\"itl\",\"itm\",\"ito\",\"itr\",\"its\",\"itt\",\"itv\",\"itw\",\"itx\",\"ity\",\"itz\",\"ium\",\"ivb\",\"ivv\",\"iwk\",\"iwm\",\"iwo\",\"iws\",\"ixc\",\"ixl\",\"iya\",\"iyo\",\"iyx\",\"izh\",\"izi\",\"izr\",\"izz\",\"jaa\",\"jab\",\"jac\",\"jad\",\"jae\",\"jaf\",\"jah\",\"jaj\",\"jak\",\"jal\",\"jam\",\"jan\",\"jao\",\"jaq\",\"jar\",\"jas\",\"jat\",\"jau\",\"jax\",\"jay\",\"jaz\",\"jbe\",\"jbi\",\"jbj\",\"jbk\",\"jbn\",\"jbo\",\"jbr\",\"jbt\",\"jbu\",\"jbw\",\"jcs\",\"jct\",\"jda\",\"jdg\",\"jdt\",\"jeb\",\"jee\",\"jeg\",\"jeh\",\"jei\",\"jek\",\"jel\",\"jen\",\"jer\",\"jet\",\"jeu\",\"jgb\",\"jge\",\"jgk\",\"jgo\",\"jhi\",\"jhs\",\"jia\",\"jib\",\"jic\",\"jid\",\"jie\",\"jig\",\"jih\",\"jii\",\"jil\",\"jim\",\"jio\",\"jiq\",\"jit\",\"jiu\",\"jiv\",\"jiy\",\"jje\",\"jjr\",\"jka\",\"jkm\",\"jko\",\"jkp\",\"jkr\",\"jku\",\"jle\",\"jls\",\"jma\",\"jmb\",\"jmc\",\"jmd\",\"jmi\",\"jml\",\"jmn\",\"jmr\",\"jms\",\"jmw\",\"jmx\",\"jna\",\"jnd\",\"jng\",\"jni\",\"jnj\",\"jnl\",\"jns\",\"job\",\"jod\",\"jog\",\"jor\",\"jos\",\"jow\",\"jpa\",\"jpr\",\"jpx\",\"jqr\",\"jra\",\"jrb\",\"jrr\",\"jrt\",\"jru\",\"jsl\",\"jua\",\"jub\",\"juc\",\"jud\",\"juh\",\"jui\",\"juk\",\"jul\",\"jum\",\"jun\",\"juo\",\"jup\",\"jur\",\"jus\",\"jut\",\"juu\",\"juw\",\"juy\",\"jvd\",\"jvn\",\"jwi\",\"jya\",\"jye\",\"jyy\",\"kaa\",\"kab\",\"kac\",\"kad\",\"kae\",\"kaf\",\"kag\",\"kah\",\"kai\",\"kaj\",\"kak\",\"kam\",\"kao\",\"kap\",\"kaq\",\"kar\",\"kav\",\"kaw\",\"kax\",\"kay\",\"kba\",\"kbb\",\"kbc\",\"kbd\",\"kbe\",\"kbf\",\"kbg\",\"kbh\",\"kbi\",\"kbj\",\"kbk\",\"kbl\",\"kbm\",\"kbn\",\"kbo\",\"kbp\",\"kbq\",\"kbr\",\"kbs\",\"kbt\",\"kbu\",\"kbv\",\"kbw\",\"kbx\",\"kby\",\"kbz\",\"kca\",\"kcb\",\"kcc\",\"kcd\",\"kce\",\"kcf\",\"kcg\",\"kch\",\"kci\",\"kcj\",\"kck\",\"kcl\",\"kcm\",\"kcn\",\"kco\",\"kcp\",\"kcq\",\"kcr\",\"kcs\",\"kct\",\"kcu\",\"kcv\",\"kcw\",\"kcx\",\"kcy\",\"kcz\",\"kda\",\"kdc\",\"kdd\",\"kde\",\"kdf\",\"kdg\",\"kdh\",\"kdi\",\"kdj\",\"kdk\",\"kdl\",\"kdm\",\"kdn\",\"kdo\",\"kdp\",\"kdq\",\"kdr\",\"kdt\",\"kdu\",\"kdv\",\"kdw\",\"kdx\",\"kdy\",\"kdz\",\"kea\",\"keb\",\"kec\",\"ked\",\"kee\",\"kef\",\"keg\",\"keh\",\"kei\",\"kej\",\"kek\",\"kel\",\"kem\",\"ken\",\"keo\",\"kep\",\"keq\",\"ker\",\"kes\",\"ket\",\"keu\",\"kev\",\"kew\",\"kex\",\"key\",\"kez\",\"kfa\",\"kfb\",\"kfc\",\"kfd\",\"kfe\",\"kff\",\"kfg\",\"kfh\",\"kfi\",\"kfj\",\"kfk\",\"kfl\",\"kfm\",\"kfn\",\"kfo\",\"kfp\",\"kfq\",\"kfr\",\"kfs\",\"kft\",\"kfu\",\"kfv\",\"kfw\",\"kfx\",\"kfy\",\"kfz\",\"kga\",\"kgb\",\"kgc\",\"kgd\",\"kge\",\"kgf\",\"kgg\",\"kgh\",\"kgi\",\"kgj\",\"kgk\",\"kgl\",\"kgm\",\"kgn\",\"kgo\",\"kgp\",\"kgq\",\"kgr\",\"kgs\",\"kgt\",\"kgu\",\"kgv\",\"kgw\",\"kgx\",\"kgy\",\"kha\",\"khb\",\"khc\",\"khd\",\"khe\",\"khf\",\"khg\",\"khh\",\"khi\",\"khj\",\"khk\",\"khl\",\"khn\",\"kho\",\"khp\",\"khq\",\"khr\",\"khs\",\"kht\",\"khu\",\"khv\",\"khw\",\"khx\",\"khy\",\"khz\",\"kia\",\"kib\",\"kic\",\"kid\",\"kie\",\"kif\",\"kig\",\"kih\",\"kii\",\"kij\",\"kil\",\"kim\",\"kio\",\"kip\",\"kiq\",\"kis\",\"kit\",\"kiu\",\"kiv\",\"kiw\",\"kix\",\"kiy\",\"kiz\",\"kja\",\"kjb\",\"kjc\",\"kjd\",\"kje\",\"kjf\",\"kjg\",\"kjh\",\"kji\",\"kjj\",\"kjk\",\"kjl\",\"kjm\",\"kjn\",\"kjo\",\"kjp\",\"kjq\",\"kjr\",\"kjs\",\"kjt\",\"kju\",\"kjv\",\"kjx\",\"kjy\",\"kjz\",\"kka\",\"kkb\",\"kkc\",\"kkd\",\"kke\",\"kkf\",\"kkg\",\"kkh\",\"kki\",\"kkj\",\"kkk\",\"kkl\",\"kkm\",\"kkn\",\"kko\",\"kkp\",\"kkq\",\"kkr\",\"kks\",\"kkt\",\"kku\",\"kkv\",\"kkw\",\"kkx\",\"kky\",\"kkz\",\"kla\",\"klb\",\"klc\",\"kld\",\"kle\",\"klf\",\"klg\",\"klh\",\"kli\",\"klj\",\"klk\",\"kll\",\"klm\",\"kln\",\"klo\",\"klp\",\"klq\",\"klr\",\"kls\",\"klt\",\"klu\",\"klv\",\"klw\",\"klx\",\"kly\",\"klz\",\"kma\",\"kmb\",\"kmc\",\"kmd\",\"kme\",\"kmf\",\"kmg\",\"kmh\",\"kmi\",\"kmj\",\"kmk\",\"kml\",\"kmm\",\"kmn\",\"kmo\",\"kmp\",\"kmq\",\"kmr\",\"kms\",\"kmt\",\"kmu\",\"kmv\",\"kmw\",\"kmx\",\"kmy\",\"kmz\",\"kna\",\"knb\",\"knc\",\"knd\",\"kne\",\"knf\",\"kng\",\"kni\",\"knj\",\"knk\",\"knl\",\"knm\",\"knn\",\"kno\",\"knp\",\"knq\",\"knr\",\"kns\",\"knt\",\"knu\",\"knv\",\"knw\",\"knx\",\"kny\",\"knz\",\"koa\",\"koc\",\"kod\",\"koe\",\"kof\",\"kog\",\"koh\",\"koi\",\"koj\",\"kok\",\"kol\",\"koo\",\"kop\",\"koq\",\"kos\",\"kot\",\"kou\",\"kov\",\"kow\",\"kox\",\"koy\",\"koz\",\"kpa\",\"kpb\",\"kpc\",\"kpd\",\"kpe\",\"kpf\",\"kpg\",\"kph\",\"kpi\",\"kpj\",\"kpk\",\"kpl\",\"kpm\",\"kpn\",\"kpo\",\"kpp\",\"kpq\",\"kpr\",\"kps\",\"kpt\",\"kpu\",\"kpv\",\"kpw\",\"kpx\",\"kpy\",\"kpz\",\"kqa\",\"kqb\",\"kqc\",\"kqd\",\"kqe\",\"kqf\",\"kqg\",\"kqh\",\"kqi\",\"kqj\",\"kqk\",\"kql\",\"kqm\",\"kqn\",\"kqo\",\"kqp\",\"kqq\",\"kqr\",\"kqs\",\"kqt\",\"kqu\",\"kqv\",\"kqw\",\"kqx\",\"kqy\",\"kqz\",\"kra\",\"krb\",\"krc\",\"krd\",\"kre\",\"krf\",\"krh\",\"kri\",\"krj\",\"krk\",\"krl\",\"krm\",\"krn\",\"kro\",\"krp\",\"krr\",\"krs\",\"krt\",\"kru\",\"krv\",\"krw\",\"krx\",\"kry\",\"krz\",\"ksa\",\"ksb\",\"ksc\",\"ksd\",\"kse\",\"ksf\",\"ksg\",\"ksh\",\"ksi\",\"ksj\",\"ksk\",\"ksl\",\"ksm\",\"ksn\",\"kso\",\"ksp\",\"ksq\",\"ksr\",\"kss\",\"kst\",\"ksu\",\"ksv\",\"ksw\",\"ksx\",\"ksy\",\"ksz\",\"kta\",\"ktb\",\"ktc\",\"ktd\",\"kte\",\"ktf\",\"ktg\",\"kth\",\"kti\",\"ktj\",\"ktk\",\"ktl\",\"ktm\",\"ktn\",\"kto\",\"ktp\",\"ktq\",\"ktr\",\"kts\",\"ktt\",\"ktu\",\"ktv\",\"ktw\",\"ktx\",\"kty\",\"ktz\",\"kub\",\"kuc\",\"kud\",\"kue\",\"kuf\",\"kug\",\"kuh\",\"kui\",\"kuj\",\"kuk\",\"kul\",\"kum\",\"kun\",\"kuo\",\"kup\",\"kuq\",\"kus\",\"kut\",\"kuu\",\"kuv\",\"kuw\",\"kux\",\"kuy\",\"kuz\",\"kva\",\"kvb\",\"kvc\",\"kvd\",\"kve\",\"kvf\",\"kvg\",\"kvh\",\"kvi\",\"kvj\",\"kvk\",\"kvl\",\"kvm\",\"kvn\",\"kvo\",\"kvp\",\"kvq\",\"kvr\",\"kvs\",\"kvt\",\"kvu\",\"kvv\",\"kvw\",\"kvx\",\"kvy\",\"kvz\",\"kwa\",\"kwb\",\"kwc\",\"kwd\",\"kwe\",\"kwf\",\"kwg\",\"kwh\",\"kwi\",\"kwj\",\"kwk\",\"kwl\",\"kwm\",\"kwn\",\"kwo\",\"kwp\",\"kwq\",\"kwr\",\"kws\",\"kwt\",\"kwu\",\"kwv\",\"kww\",\"kwx\",\"kwy\",\"kwz\",\"kxa\",\"kxb\",\"kxc\",\"kxd\",\"kxe\",\"kxf\",\"kxh\",\"kxi\",\"kxj\",\"kxk\",\"kxl\",\"kxm\",\"kxn\",\"kxo\",\"kxp\",\"kxq\",\"kxr\",\"kxs\",\"kxt\",\"kxu\",\"kxv\",\"kxw\",\"kxx\",\"kxy\",\"kxz\",\"kya\",\"kyb\",\"kyc\",\"kyd\",\"kye\",\"kyf\",\"kyg\",\"kyh\",\"kyi\",\"kyj\",\"kyk\",\"kyl\",\"kym\",\"kyn\",\"kyo\",\"kyp\",\"kyq\",\"kyr\",\"kys\",\"kyt\",\"kyu\",\"kyv\",\"kyw\",\"kyx\",\"kyy\",\"kyz\",\"kza\",\"kzb\",\"kzc\",\"kzd\",\"kze\",\"kzf\",\"kzg\",\"kzh\",\"kzi\",\"kzj\",\"kzk\",\"kzl\",\"kzm\",\"kzn\",\"kzo\",\"kzp\",\"kzq\",\"kzr\",\"kzs\",\"kzt\",\"kzu\",\"kzv\",\"kzw\",\"kzx\",\"kzy\",\"kzz\",\"laa\",\"lab\",\"lac\",\"lad\",\"lae\",\"laf\",\"lag\",\"lah\",\"lai\",\"laj\",\"lak\",\"lal\",\"lam\",\"lan\",\"lap\",\"laq\",\"lar\",\"las\",\"lau\",\"law\",\"lax\",\"lay\",\"laz\",\"lba\",\"lbb\",\"lbc\",\"lbe\",\"lbf\",\"lbg\",\"lbi\",\"lbj\",\"lbk\",\"lbl\",\"lbm\",\"lbn\",\"lbo\",\"lbq\",\"lbr\",\"lbs\",\"lbt\",\"lbu\",\"lbv\",\"lbw\",\"lbx\",\"lby\",\"lbz\",\"lcc\",\"lcd\",\"lce\",\"lcf\",\"lch\",\"lcl\",\"lcm\",\"lcp\",\"lcq\",\"lcs\",\"lda\",\"ldb\",\"ldd\",\"ldg\",\"ldh\",\"ldi\",\"ldj\",\"ldk\",\"ldl\",\"ldm\",\"ldn\",\"ldo\",\"ldp\",\"ldq\",\"lea\",\"leb\",\"lec\",\"led\",\"lee\",\"lef\",\"leg\",\"leh\",\"lei\",\"lej\",\"lek\",\"lel\",\"lem\",\"len\",\"leo\",\"lep\",\"leq\",\"ler\",\"les\",\"let\",\"leu\",\"lev\",\"lew\",\"lex\",\"ley\",\"lez\",\"lfa\",\"lfn\",\"lga\",\"lgb\",\"lgg\",\"lgh\",\"lgi\",\"lgk\",\"lgl\",\"lgm\",\"lgn\",\"lgq\",\"lgr\",\"lgt\",\"lgu\",\"lgz\",\"lha\",\"lhh\",\"lhi\",\"lhl\",\"lhm\",\"lhn\",\"lhp\",\"lhs\",\"lht\",\"lhu\",\"lia\",\"lib\",\"lic\",\"lid\",\"lie\",\"lif\",\"lig\",\"lih\",\"lii\",\"lij\",\"lik\",\"lil\",\"lio\",\"lip\",\"liq\",\"lir\",\"lis\",\"liu\",\"liv\",\"liw\",\"lix\",\"liy\",\"liz\",\"lja\",\"lje\",\"lji\",\"ljl\",\"ljp\",\"ljw\",\"ljx\",\"lka\",\"lkb\",\"lkc\",\"lkd\",\"lke\",\"lkh\",\"lki\",\"lkj\",\"lkl\",\"lkm\",\"lkn\",\"lko\",\"lkr\",\"lks\",\"lkt\",\"lku\",\"lky\",\"lla\",\"llb\",\"llc\",\"lld\",\"lle\",\"llf\",\"llg\",\"llh\",\"lli\",\"llj\",\"llk\",\"lll\",\"llm\",\"lln\",\"llo\",\"llp\",\"llq\",\"lls\",\"llu\",\"llx\",\"lma\",\"lmb\",\"lmc\",\"lmd\",\"lme\",\"lmf\",\"lmg\",\"lmh\",\"lmi\",\"lmj\",\"lmk\",\"lml\",\"lmm\",\"lmn\",\"lmo\",\"lmp\",\"lmq\",\"lmr\",\"lmu\",\"lmv\",\"lmw\",\"lmx\",\"lmy\",\"lmz\",\"lna\",\"lnb\",\"lnd\",\"lng\",\"lnh\",\"lni\",\"lnj\",\"lnl\",\"lnm\",\"lnn\",\"lno\",\"lns\",\"lnu\",\"lnw\",\"lnz\",\"loa\",\"lob\",\"loc\",\"loe\",\"lof\",\"log\",\"loh\",\"loi\",\"loj\",\"lok\",\"lol\",\"lom\",\"lon\",\"loo\",\"lop\",\"loq\",\"lor\",\"los\",\"lot\",\"lou\",\"lov\",\"low\",\"lox\",\"loy\",\"loz\",\"lpa\",\"lpe\",\"lpn\",\"lpo\",\"lpx\",\"lra\",\"lrc\",\"lre\",\"lrg\",\"lri\",\"lrk\",\"lrl\",\"lrm\",\"lrn\",\"lro\",\"lrr\",\"lrt\",\"lrv\",\"lrz\",\"lsa\",\"lsd\",\"lse\",\"lsg\",\"lsh\",\"lsi\",\"lsl\",\"lsm\",\"lso\",\"lsp\",\"lsr\",\"lss\",\"lst\",\"lsy\",\"ltc\",\"ltg\",\"lth\",\"lti\",\"ltn\",\"lto\",\"lts\",\"ltu\",\"lua\",\"luc\",\"lud\",\"lue\",\"luf\",\"lui\",\"luj\",\"luk\",\"lul\",\"lum\",\"lun\",\"luo\",\"lup\",\"luq\",\"lur\",\"lus\",\"lut\",\"luu\",\"luv\",\"luw\",\"luy\",\"luz\",\"lva\",\"lvk\",\"lvs\",\"lvu\",\"lwa\",\"lwe\",\"lwg\",\"lwh\",\"lwl\",\"lwm\",\"lwo\",\"lwt\",\"lwu\",\"lww\",\"lya\",\"lyg\",\"lyn\",\"lzh\",\"lzl\",\"lzn\",\"lzz\",\"maa\",\"mab\",\"mad\",\"mae\",\"maf\",\"mag\",\"mai\",\"maj\",\"mak\",\"mam\",\"man\",\"map\",\"maq\",\"mas\",\"mat\",\"mau\",\"mav\",\"maw\",\"max\",\"maz\",\"mba\",\"mbb\",\"mbc\",\"mbd\",\"mbe\",\"mbf\",\"mbh\",\"mbi\",\"mbj\",\"mbk\",\"mbl\",\"mbm\",\"mbn\",\"mbo\",\"mbp\",\"mbq\",\"mbr\",\"mbs\",\"mbt\",\"mbu\",\"mbv\",\"mbw\",\"mbx\",\"mby\",\"mbz\",\"mca\",\"mcb\",\"mcc\",\"mcd\",\"mce\",\"mcf\",\"mcg\",\"mch\",\"mci\",\"mcj\",\"mck\",\"mcl\",\"mcm\",\"mcn\",\"mco\",\"mcp\",\"mcq\",\"mcr\",\"mcs\",\"mct\",\"mcu\",\"mcv\",\"mcw\",\"mcx\",\"mcy\",\"mcz\",\"mda\",\"mdb\",\"mdc\",\"mdd\",\"mde\",\"mdf\",\"mdg\",\"mdh\",\"mdi\",\"mdj\",\"mdk\",\"mdl\",\"mdm\",\"mdn\",\"mdp\",\"mdq\",\"mdr\",\"mds\",\"mdt\",\"mdu\",\"mdv\",\"mdw\",\"mdx\",\"mdy\",\"mdz\",\"mea\",\"meb\",\"mec\",\"med\",\"mee\",\"mef\",\"meg\",\"meh\",\"mei\",\"mej\",\"mek\",\"mel\",\"mem\",\"men\",\"meo\",\"mep\",\"meq\",\"mer\",\"mes\",\"met\",\"meu\",\"mev\",\"mew\",\"mey\",\"mez\",\"mfa\",\"mfb\",\"mfc\",\"mfd\",\"mfe\",\"mff\",\"mfg\",\"mfh\",\"mfi\",\"mfj\",\"mfk\",\"mfl\",\"mfm\",\"mfn\",\"mfo\",\"mfp\",\"mfq\",\"mfr\",\"mfs\",\"mft\",\"mfu\",\"mfv\",\"mfw\",\"mfx\",\"mfy\",\"mfz\",\"mga\",\"mgb\",\"mgc\",\"mgd\",\"mge\",\"mgf\",\"mgg\",\"mgh\",\"mgi\",\"mgj\",\"mgk\",\"mgl\",\"mgm\",\"mgn\",\"mgo\",\"mgp\",\"mgq\",\"mgr\",\"mgs\",\"mgt\",\"mgu\",\"mgv\",\"mgw\",\"mgx\",\"mgy\",\"mgz\",\"mha\",\"mhb\",\"mhc\",\"mhd\",\"mhe\",\"mhf\",\"mhg\",\"mhh\",\"mhi\",\"mhj\",\"mhk\",\"mhl\",\"mhm\",\"mhn\",\"mho\",\"mhp\",\"mhq\",\"mhr\",\"mhs\",\"mht\",\"mhu\",\"mhw\",\"mhx\",\"mhy\",\"mhz\",\"mia\",\"mib\",\"mic\",\"mid\",\"mie\",\"mif\",\"mig\",\"mih\",\"mii\",\"mij\",\"mik\",\"mil\",\"mim\",\"min\",\"mio\",\"mip\",\"miq\",\"mir\",\"mis\",\"mit\",\"miu\",\"miw\",\"mix\",\"miy\",\"miz\",\"mja\",\"mjb\",\"mjc\",\"mjd\",\"mje\",\"mjg\",\"mjh\",\"mji\",\"mjj\",\"mjk\",\"mjl\",\"mjm\",\"mjn\",\"mjo\",\"mjp\",\"mjq\",\"mjr\",\"mjs\",\"mjt\",\"mju\",\"mjv\",\"mjw\",\"mjx\",\"mjy\",\"mjz\",\"mka\",\"mkb\",\"mkc\",\"mke\",\"mkf\",\"mkg\",\"mkh\",\"mki\",\"mkj\",\"mkk\",\"mkl\",\"mkm\",\"mkn\",\"mko\",\"mkp\",\"mkq\",\"mkr\",\"mks\",\"mkt\",\"mku\",\"mkv\",\"mkw\",\"mkx\",\"mky\",\"mkz\",\"mla\",\"mlb\",\"mlc\",\"mld\",\"mle\",\"mlf\",\"mlh\",\"mli\",\"mlj\",\"mlk\",\"mll\",\"mlm\",\"mln\",\"mlo\",\"mlp\",\"mlq\",\"mlr\",\"mls\",\"mlu\",\"mlv\",\"mlw\",\"mlx\",\"mlz\",\"mma\",\"mmb\",\"mmc\",\"mmd\",\"mme\",\"mmf\",\"mmg\",\"mmh\",\"mmi\",\"mmj\",\"mmk\",\"mml\",\"mmm\",\"mmn\",\"mmo\",\"mmp\",\"mmq\",\"mmr\",\"mmt\",\"mmu\",\"mmv\",\"mmw\",\"mmx\",\"mmy\",\"mmz\",\"mna\",\"mnb\",\"mnc\",\"mnd\",\"mne\",\"mnf\",\"mng\",\"mnh\",\"mni\",\"mnj\",\"mnk\",\"mnl\",\"mnm\",\"mnn\",\"mno\",\"mnp\",\"mnq\",\"mnr\",\"mns\",\"mnt\",\"mnu\",\"mnv\",\"mnw\",\"mnx\",\"mny\",\"mnz\",\"moa\",\"moc\",\"mod\",\"moe\",\"mof\",\"mog\",\"moh\",\"moi\",\"moj\",\"mok\",\"mom\",\"moo\",\"mop\",\"moq\",\"mor\",\"mos\",\"mot\",\"mou\",\"mov\",\"mow\",\"mox\",\"moy\",\"moz\",\"mpa\",\"mpb\",\"mpc\",\"mpd\",\"mpe\",\"mpg\",\"mph\",\"mpi\",\"mpj\",\"mpk\",\"mpl\",\"mpm\",\"mpn\",\"mpo\",\"mpp\",\"mpq\",\"mpr\",\"mps\",\"mpt\",\"mpu\",\"mpv\",\"mpw\",\"mpx\",\"mpy\",\"mpz\",\"mqa\",\"mqb\",\"mqc\",\"mqe\",\"mqf\",\"mqg\",\"mqh\",\"mqi\",\"mqj\",\"mqk\",\"mql\",\"mqm\",\"mqn\",\"mqo\",\"mqp\",\"mqq\",\"mqr\",\"mqs\",\"mqt\",\"mqu\",\"mqv\",\"mqw\",\"mqx\",\"mqy\",\"mqz\",\"mra\",\"mrb\",\"mrc\",\"mrd\",\"mre\",\"mrf\",\"mrg\",\"mrh\",\"mrj\",\"mrk\",\"mrl\",\"mrm\",\"mrn\",\"mro\",\"mrp\",\"mrq\",\"mrr\",\"mrs\",\"mrt\",\"mru\",\"mrv\",\"mrw\",\"mrx\",\"mry\",\"mrz\",\"msb\",\"msc\",\"msd\",\"mse\",\"msf\",\"msg\",\"msh\",\"msi\",\"msj\",\"msk\",\"msl\",\"msm\",\"msn\",\"mso\",\"msp\",\"msq\",\"msr\",\"mss\",\"mst\",\"msu\",\"msv\",\"msw\",\"msx\",\"msy\",\"msz\",\"mta\",\"mtb\",\"mtc\",\"mtd\",\"mte\",\"mtf\",\"mtg\",\"mth\",\"mti\",\"mtj\",\"mtk\",\"mtl\",\"mtm\",\"mtn\",\"mto\",\"mtp\",\"mtq\",\"mtr\",\"mts\",\"mtt\",\"mtu\",\"mtv\",\"mtw\",\"mtx\",\"mty\",\"mua\",\"mub\",\"muc\",\"mud\",\"mue\",\"mug\",\"muh\",\"mui\",\"muj\",\"muk\",\"mul\",\"mum\",\"mun\",\"muo\",\"mup\",\"muq\",\"mur\",\"mus\",\"mut\",\"muu\",\"muv\",\"mux\",\"muy\",\"muz\",\"mva\",\"mvb\",\"mvd\",\"mve\",\"mvf\",\"mvg\",\"mvh\",\"mvi\",\"mvk\",\"mvl\",\"mvm\",\"mvn\",\"mvo\",\"mvp\",\"mvq\",\"mvr\",\"mvs\",\"mvt\",\"mvu\",\"mvv\",\"mvw\",\"mvx\",\"mvy\",\"mvz\",\"mwa\",\"mwb\",\"mwc\",\"mwd\",\"mwe\",\"mwf\",\"mwg\",\"mwh\",\"mwi\",\"mwj\",\"mwk\",\"mwl\",\"mwm\",\"mwn\",\"mwo\",\"mwp\",\"mwq\",\"mwr\",\"mws\",\"mwt\",\"mwu\",\"mwv\",\"mww\",\"mwx\",\"mwy\",\"mwz\",\"mxa\",\"mxb\",\"mxc\",\"mxd\",\"mxe\",\"mxf\",\"mxg\",\"mxh\",\"mxi\",\"mxj\",\"mxk\",\"mxl\",\"mxm\",\"mxn\",\"mxo\",\"mxp\",\"mxq\",\"mxr\",\"mxs\",\"mxt\",\"mxu\",\"mxv\",\"mxw\",\"mxx\",\"mxy\",\"mxz\",\"myb\",\"myc\",\"myd\",\"mye\",\"myf\",\"myg\",\"myh\",\"myi\",\"myj\",\"myk\",\"myl\",\"mym\",\"myn\",\"myo\",\"myp\",\"myq\",\"myr\",\"mys\",\"myt\",\"myu\",\"myv\",\"myw\",\"myx\",\"myy\",\"myz\",\"mza\",\"mzb\",\"mzc\",\"mzd\",\"mze\",\"mzg\",\"mzh\",\"mzi\",\"mzj\",\"mzk\",\"mzl\",\"mzm\",\"mzn\",\"mzo\",\"mzp\",\"mzq\",\"mzr\",\"mzs\",\"mzt\",\"mzu\",\"mzv\",\"mzw\",\"mzx\",\"mzy\",\"mzz\",\"naa\",\"nab\",\"nac\",\"nad\",\"nae\",\"naf\",\"nag\",\"nah\",\"nai\",\"naj\",\"nak\",\"nal\",\"nam\",\"nan\",\"nao\",\"nap\",\"naq\",\"nar\",\"nas\",\"nat\",\"naw\",\"nax\",\"nay\",\"naz\",\"nba\",\"nbb\",\"nbc\",\"nbd\",\"nbe\",\"nbf\",\"nbg\",\"nbh\",\"nbi\",\"nbj\",\"nbk\",\"nbm\",\"nbn\",\"nbo\",\"nbp\",\"nbq\",\"nbr\",\"nbs\",\"nbt\",\"nbu\",\"nbv\",\"nbw\",\"nbx\",\"nby\",\"nca\",\"ncb\",\"ncc\",\"ncd\",\"nce\",\"ncf\",\"ncg\",\"nch\",\"nci\",\"ncj\",\"nck\",\"ncl\",\"ncm\",\"ncn\",\"nco\",\"ncp\",\"ncq\",\"ncr\",\"ncs\",\"nct\",\"ncu\",\"ncx\",\"ncz\",\"nda\",\"ndb\",\"ndc\",\"ndd\",\"ndf\",\"ndg\",\"ndh\",\"ndi\",\"ndj\",\"ndk\",\"ndl\",\"ndm\",\"ndn\",\"ndp\",\"ndq\",\"ndr\",\"nds\",\"ndt\",\"ndu\",\"ndv\",\"ndw\",\"ndx\",\"ndy\",\"ndz\",\"nea\",\"neb\",\"nec\",\"ned\",\"nee\",\"nef\",\"neg\",\"neh\",\"nei\",\"nej\",\"nek\",\"nem\",\"nen\",\"neo\",\"neq\",\"ner\",\"nes\",\"net\",\"neu\",\"nev\",\"new\",\"nex\",\"ney\",\"nez\",\"nfa\",\"nfd\",\"nfl\",\"nfr\",\"nfu\",\"nga\",\"ngb\",\"ngc\",\"ngd\",\"nge\",\"ngf\",\"ngg\",\"ngh\",\"ngi\",\"ngj\",\"ngk\",\"ngl\",\"ngm\",\"ngn\",\"ngo\",\"ngp\",\"ngq\",\"ngr\",\"ngs\",\"ngt\",\"ngu\",\"ngv\",\"ngw\",\"ngx\",\"ngy\",\"ngz\",\"nha\",\"nhb\",\"nhc\",\"nhd\",\"nhe\",\"nhf\",\"nhg\",\"nhh\",\"nhi\",\"nhk\",\"nhm\",\"nhn\",\"nho\",\"nhp\",\"nhq\",\"nhr\",\"nht\",\"nhu\",\"nhv\",\"nhw\",\"nhx\",\"nhy\",\"nhz\",\"nia\",\"nib\",\"nic\",\"nid\",\"nie\",\"nif\",\"nig\",\"nih\",\"nii\",\"nij\",\"nik\",\"nil\",\"nim\",\"nin\",\"nio\",\"niq\",\"nir\",\"nis\",\"nit\",\"niu\",\"niv\",\"niw\",\"nix\",\"niy\",\"niz\",\"nja\",\"njb\",\"njd\",\"njh\",\"nji\",\"njj\",\"njl\",\"njm\",\"njn\",\"njo\",\"njr\",\"njs\",\"njt\",\"nju\",\"njx\",\"njy\",\"njz\",\"nka\",\"nkb\",\"nkc\",\"nkd\",\"nke\",\"nkf\",\"nkg\",\"nkh\",\"nki\",\"nkj\",\"nkk\",\"nkm\",\"nkn\",\"nko\",\"nkp\",\"nkq\",\"nkr\",\"nks\",\"nkt\",\"nku\",\"nkv\",\"nkw\",\"nkx\",\"nkz\",\"nla\",\"nlc\",\"nle\",\"nlg\",\"nli\",\"nlj\",\"nlk\",\"nll\",\"nln\",\"nlo\",\"nlq\",\"nlr\",\"nlu\",\"nlv\",\"nlw\",\"nlx\",\"nly\",\"nlz\",\"nma\",\"nmb\",\"nmc\",\"nmd\",\"nme\",\"nmf\",\"nmg\",\"nmh\",\"nmi\",\"nmj\",\"nmk\",\"nml\",\"nmm\",\"nmn\",\"nmo\",\"nmp\",\"nmq\",\"nmr\",\"nms\",\"nmt\",\"nmu\",\"nmv\",\"nmw\",\"nmx\",\"nmy\",\"nmz\",\"nna\",\"nnb\",\"nnc\",\"nnd\",\"nne\",\"nnf\",\"nng\",\"nnh\",\"nni\",\"nnj\",\"nnk\",\"nnl\",\"nnm\",\"nnn\",\"nnp\",\"nnq\",\"nnr\",\"nns\",\"nnt\",\"nnu\",\"nnv\",\"nnw\",\"nnx\",\"nny\",\"nnz\",\"noa\",\"noc\",\"nod\",\"noe\",\"nof\",\"nog\",\"noh\",\"noi\",\"noj\",\"nok\",\"nol\",\"nom\",\"non\",\"noo\",\"nop\",\"noq\",\"nos\",\"not\",\"nou\",\"nov\",\"now\",\"noy\",\"noz\",\"npa\",\"npb\",\"npg\",\"nph\",\"npi\",\"npl\",\"npn\",\"npo\",\"nps\",\"npu\",\"npx\",\"npy\",\"nqg\",\"nqk\",\"nql\",\"nqm\",\"nqn\",\"nqo\",\"nqq\",\"nqy\",\"nra\",\"nrb\",\"nrc\",\"nre\",\"nrf\",\"nrg\",\"nri\",\"nrk\",\"nrl\",\"nrm\",\"nrn\",\"nrp\",\"nrr\",\"nrt\",\"nru\",\"nrx\",\"nrz\",\"nsa\",\"nsc\",\"nsd\",\"nse\",\"nsf\",\"nsg\",\"nsh\",\"nsi\",\"nsk\",\"nsl\",\"nsm\",\"nsn\",\"nso\",\"nsp\",\"nsq\",\"nsr\",\"nss\",\"nst\",\"nsu\",\"nsv\",\"nsw\",\"nsx\",\"nsy\",\"nsz\",\"ntd\",\"nte\",\"ntg\",\"nti\",\"ntj\",\"ntk\",\"ntm\",\"nto\",\"ntp\",\"ntr\",\"nts\",\"ntu\",\"ntw\",\"ntx\",\"nty\",\"ntz\",\"nua\",\"nub\",\"nuc\",\"nud\",\"nue\",\"nuf\",\"nug\",\"nuh\",\"nui\",\"nuj\",\"nuk\",\"nul\",\"num\",\"nun\",\"nuo\",\"nup\",\"nuq\",\"nur\",\"nus\",\"nut\",\"nuu\",\"nuv\",\"nuw\",\"nux\",\"nuy\",\"nuz\",\"nvh\",\"nvm\",\"nvo\",\"nwa\",\"nwb\",\"nwc\",\"nwe\",\"nwg\",\"nwi\",\"nwm\",\"nwo\",\"nwr\",\"nwx\",\"nwy\",\"nxa\",\"nxd\",\"nxe\",\"nxg\",\"nxi\",\"nxk\",\"nxl\",\"nxm\",\"nxn\",\"nxo\",\"nxq\",\"nxr\",\"nxu\",\"nxx\",\"nyb\",\"nyc\",\"nyd\",\"nye\",\"nyf\",\"nyg\",\"nyh\",\"nyi\",\"nyj\",\"nyk\",\"nyl\",\"nym\",\"nyn\",\"nyo\",\"nyp\",\"nyq\",\"nyr\",\"nys\",\"nyt\",\"nyu\",\"nyv\",\"nyw\",\"nyx\",\"nyy\",\"nza\",\"nzb\",\"nzi\",\"nzk\",\"nzm\",\"nzs\",\"nzu\",\"nzy\",\"nzz\",\"oaa\",\"oac\",\"oar\",\"oav\",\"obi\",\"obk\",\"obl\",\"obm\",\"obo\",\"obr\",\"obt\",\"obu\",\"oca\",\"och\",\"oco\",\"ocu\",\"oda\",\"odk\",\"odt\",\"odu\",\"ofo\",\"ofs\",\"ofu\",\"ogb\",\"ogc\",\"oge\",\"ogg\",\"ogo\",\"ogu\",\"oht\",\"ohu\",\"oia\",\"oin\",\"ojb\",\"ojc\",\"ojg\",\"ojp\",\"ojs\",\"ojv\",\"ojw\",\"oka\",\"okb\",\"okd\",\"oke\",\"okg\",\"okh\",\"oki\",\"okj\",\"okk\",\"okl\",\"okm\",\"okn\",\"oko\",\"okr\",\"oks\",\"oku\",\"okv\",\"okx\",\"ola\",\"old\",\"ole\",\"olk\",\"olm\",\"olo\",\"olr\",\"olt\",\"olu\",\"oma\",\"omb\",\"omc\",\"ome\",\"omg\",\"omi\",\"omk\",\"oml\",\"omn\",\"omo\",\"omp\",\"omq\",\"omr\",\"omt\",\"omu\",\"omv\",\"omw\",\"omx\",\"ona\",\"onb\",\"one\",\"ong\",\"oni\",\"onj\",\"onk\",\"onn\",\"ono\",\"onp\",\"onr\",\"ons\",\"ont\",\"onu\",\"onw\",\"onx\",\"ood\",\"oog\",\"oon\",\"oor\",\"oos\",\"opa\",\"opk\",\"opm\",\"opo\",\"opt\",\"opy\",\"ora\",\"orc\",\"ore\",\"org\",\"orh\",\"orn\",\"oro\",\"orr\",\"ors\",\"ort\",\"oru\",\"orv\",\"orw\",\"orx\",\"ory\",\"orz\",\"osa\",\"osc\",\"osi\",\"oso\",\"osp\",\"ost\",\"osu\",\"osx\",\"ota\",\"otb\",\"otd\",\"ote\",\"oti\",\"otk\",\"otl\",\"otm\",\"otn\",\"oto\",\"otq\",\"otr\",\"ots\",\"ott\",\"otu\",\"otw\",\"otx\",\"oty\",\"otz\",\"oua\",\"oub\",\"oue\",\"oui\",\"oum\",\"oun\",\"ovd\",\"owi\",\"owl\",\"oyb\",\"oyd\",\"oym\",\"oyy\",\"ozm\",\"paa\",\"pab\",\"pac\",\"pad\",\"pae\",\"paf\",\"pag\",\"pah\",\"pai\",\"pak\",\"pal\",\"pam\",\"pao\",\"pap\",\"paq\",\"par\",\"pas\",\"pat\",\"pau\",\"pav\",\"paw\",\"pax\",\"pay\",\"paz\",\"pbb\",\"pbc\",\"pbe\",\"pbf\",\"pbg\",\"pbh\",\"pbi\",\"pbl\",\"pbn\",\"pbo\",\"pbp\",\"pbr\",\"pbs\",\"pbt\",\"pbu\",\"pbv\",\"pby\",\"pbz\",\"pca\",\"pcb\",\"pcc\",\"pcd\",\"pce\",\"pcf\",\"pcg\",\"pch\",\"pci\",\"pcj\",\"pck\",\"pcl\",\"pcm\",\"pcn\",\"pcp\",\"pcr\",\"pcw\",\"pda\",\"pdc\",\"pdi\",\"pdn\",\"pdo\",\"pdt\",\"pdu\",\"pea\",\"peb\",\"ped\",\"pee\",\"pef\",\"peg\",\"peh\",\"pei\",\"pej\",\"pek\",\"pel\",\"pem\",\"peo\",\"pep\",\"peq\",\"pes\",\"pev\",\"pex\",\"pey\",\"pez\",\"pfa\",\"pfe\",\"pfl\",\"pga\",\"pgd\",\"pgg\",\"pgi\",\"pgk\",\"pgl\",\"pgn\",\"pgs\",\"pgu\",\"pgy\",\"pgz\",\"pha\",\"phd\",\"phg\",\"phh\",\"phi\",\"phk\",\"phl\",\"phm\",\"phn\",\"pho\",\"phq\",\"phr\",\"pht\",\"phu\",\"phv\",\"phw\",\"pia\",\"pib\",\"pic\",\"pid\",\"pie\",\"pif\",\"pig\",\"pih\",\"pii\",\"pij\",\"pil\",\"pim\",\"pin\",\"pio\",\"pip\",\"pir\",\"pis\",\"pit\",\"piu\",\"piv\",\"piw\",\"pix\",\"piy\",\"piz\",\"pjt\",\"pka\",\"pkb\",\"pkc\",\"pkg\",\"pkh\",\"pkn\",\"pko\",\"pkp\",\"pkr\",\"pks\",\"pkt\",\"pku\",\"pla\",\"plb\",\"plc\",\"pld\",\"ple\",\"plf\",\"plg\",\"plh\",\"plj\",\"plk\",\"pll\",\"pln\",\"plo\",\"plp\",\"plq\",\"plr\",\"pls\",\"plt\",\"plu\",\"plv\",\"plw\",\"ply\",\"plz\",\"pma\",\"pmb\",\"pmc\",\"pmd\",\"pme\",\"pmf\",\"pmh\",\"pmi\",\"pmj\",\"pmk\",\"pml\",\"pmm\",\"pmn\",\"pmo\",\"pmq\",\"pmr\",\"pms\",\"pmt\",\"pmu\",\"pmw\",\"pmx\",\"pmy\",\"pmz\",\"pna\",\"pnb\",\"pnc\",\"pne\",\"png\",\"pnh\",\"pni\",\"pnj\",\"pnk\",\"pnl\",\"pnm\",\"pnn\",\"pno\",\"pnp\",\"pnq\",\"pnr\",\"pns\",\"pnt\",\"pnu\",\"pnv\",\"pnw\",\"pnx\",\"pny\",\"pnz\",\"poc\",\"pod\",\"poe\",\"pof\",\"pog\",\"poh\",\"poi\",\"pok\",\"pom\",\"pon\",\"poo\",\"pop\",\"poq\",\"pos\",\"pot\",\"pov\",\"pow\",\"pox\",\"poy\",\"poz\",\"ppa\",\"ppe\",\"ppi\",\"ppk\",\"ppl\",\"ppm\",\"ppn\",\"ppo\",\"ppp\",\"ppq\",\"ppr\",\"pps\",\"ppt\",\"ppu\",\"pqa\",\"pqe\",\"pqm\",\"pqw\",\"pra\",\"prb\",\"prc\",\"prd\",\"pre\",\"prf\",\"prg\",\"prh\",\"pri\",\"prk\",\"prl\",\"prm\",\"prn\",\"pro\",\"prp\",\"prq\",\"prr\",\"prs\",\"prt\",\"pru\",\"prw\",\"prx\",\"pry\",\"prz\",\"psa\",\"psc\",\"psd\",\"pse\",\"psg\",\"psh\",\"psi\",\"psl\",\"psm\",\"psn\",\"pso\",\"psp\",\"psq\",\"psr\",\"pss\",\"pst\",\"psu\",\"psw\",\"psy\",\"pta\",\"pth\",\"pti\",\"ptn\",\"pto\",\"ptp\",\"ptq\",\"ptr\",\"ptt\",\"ptu\",\"ptv\",\"ptw\",\"pty\",\"pua\",\"pub\",\"puc\",\"pud\",\"pue\",\"puf\",\"pug\",\"pui\",\"puj\",\"puk\",\"pum\",\"puo\",\"pup\",\"puq\",\"pur\",\"put\",\"puu\",\"puw\",\"pux\",\"puy\",\"puz\",\"pwa\",\"pwb\",\"pwg\",\"pwi\",\"pwm\",\"pwn\",\"pwo\",\"pwr\",\"pww\",\"pxm\",\"pye\",\"pym\",\"pyn\",\"pys\",\"pyu\",\"pyx\",\"pyy\",\"pzn\",\"qaa..qtz\",\"qua\",\"qub\",\"quc\",\"qud\",\"quf\",\"qug\",\"quh\",\"qui\",\"quk\",\"qul\",\"qum\",\"qun\",\"qup\",\"quq\",\"qur\",\"qus\",\"quv\",\"quw\",\"qux\",\"quy\",\"quz\",\"qva\",\"qvc\",\"qve\",\"qvh\",\"qvi\",\"qvj\",\"qvl\",\"qvm\",\"qvn\",\"qvo\",\"qvp\",\"qvs\",\"qvw\",\"qvy\",\"qvz\",\"qwa\",\"qwc\",\"qwe\",\"qwh\",\"qwm\",\"qws\",\"qwt\",\"qxa\",\"qxc\",\"qxh\",\"qxl\",\"qxn\",\"qxo\",\"qxp\",\"qxq\",\"qxr\",\"qxs\",\"qxt\",\"qxu\",\"qxw\",\"qya\",\"qyp\",\"raa\",\"rab\",\"rac\",\"rad\",\"raf\",\"rag\",\"rah\",\"rai\",\"raj\",\"rak\",\"ral\",\"ram\",\"ran\",\"rao\",\"rap\",\"raq\",\"rar\",\"ras\",\"rat\",\"rau\",\"rav\",\"raw\",\"rax\",\"ray\",\"raz\",\"rbb\",\"rbk\",\"rbl\",\"rbp\",\"rcf\",\"rdb\",\"rea\",\"reb\",\"ree\",\"reg\",\"rei\",\"rej\",\"rel\",\"rem\",\"ren\",\"rer\",\"res\",\"ret\",\"rey\",\"rga\",\"rge\",\"rgk\",\"rgn\",\"rgr\",\"rgs\",\"rgu\",\"rhg\",\"rhp\",\"ria\",\"rie\",\"rif\",\"ril\",\"rim\",\"rin\",\"rir\",\"rit\",\"riu\",\"rjg\",\"rji\",\"rjs\",\"rka\",\"rkb\",\"rkh\",\"rki\",\"rkm\",\"rkt\",\"rkw\",\"rma\",\"rmb\",\"rmc\",\"rmd\",\"rme\",\"rmf\",\"rmg\",\"rmh\",\"rmi\",\"rmk\",\"rml\",\"rmm\",\"rmn\",\"rmo\",\"rmp\",\"rmq\",\"rmr\",\"rms\",\"rmt\",\"rmu\",\"rmv\",\"rmw\",\"rmx\",\"rmy\",\"rmz\",\"rna\",\"rnd\",\"rng\",\"rnl\",\"rnn\",\"rnp\",\"rnr\",\"rnw\",\"roa\",\"rob\",\"roc\",\"rod\",\"roe\",\"rof\",\"rog\",\"rol\",\"rom\",\"roo\",\"rop\",\"ror\",\"rou\",\"row\",\"rpn\",\"rpt\",\"rri\",\"rro\",\"rrt\",\"rsb\",\"rsi\",\"rsl\",\"rsm\",\"rtc\",\"rth\",\"rtm\",\"rts\",\"rtw\",\"rub\",\"ruc\",\"rue\",\"ruf\",\"rug\",\"ruh\",\"rui\",\"ruk\",\"ruo\",\"rup\",\"ruq\",\"rut\",\"ruu\",\"ruy\",\"ruz\",\"rwa\",\"rwk\",\"rwm\",\"rwo\",\"rwr\",\"rxd\",\"rxw\",\"ryn\",\"rys\",\"ryu\",\"rzh\",\"saa\",\"sab\",\"sac\",\"sad\",\"sae\",\"saf\",\"sah\",\"sai\",\"saj\",\"sak\",\"sal\",\"sam\",\"sao\",\"sap\",\"saq\",\"sar\",\"sas\",\"sat\",\"sau\",\"sav\",\"saw\",\"sax\",\"say\",\"saz\",\"sba\",\"sbb\",\"sbc\",\"sbd\",\"sbe\",\"sbf\",\"sbg\",\"sbh\",\"sbi\",\"sbj\",\"sbk\",\"sbl\",\"sbm\",\"sbn\",\"sbo\",\"sbp\",\"sbq\",\"sbr\",\"sbs\",\"sbt\",\"sbu\",\"sbv\",\"sbw\",\"sbx\",\"sby\",\"sbz\",\"sca\",\"scb\",\"sce\",\"scf\",\"scg\",\"sch\",\"sci\",\"sck\",\"scl\",\"scn\",\"sco\",\"scp\",\"scq\",\"scs\",\"sct\",\"scu\",\"scv\",\"scw\",\"scx\",\"sda\",\"sdb\",\"sdc\",\"sde\",\"sdf\",\"sdg\",\"sdh\",\"sdj\",\"sdk\",\"sdl\",\"sdm\",\"sdn\",\"sdo\",\"sdp\",\"sdr\",\"sds\",\"sdt\",\"sdu\",\"sdv\",\"sdx\",\"sdz\",\"sea\",\"seb\",\"sec\",\"sed\",\"see\",\"sef\",\"seg\",\"seh\",\"sei\",\"sej\",\"sek\",\"sel\",\"sem\",\"sen\",\"seo\",\"sep\",\"seq\",\"ser\",\"ses\",\"set\",\"seu\",\"sev\",\"sew\",\"sey\",\"sez\",\"sfb\",\"sfe\",\"sfm\",\"sfs\",\"sfw\",\"sga\",\"sgb\",\"sgc\",\"sgd\",\"sge\",\"sgg\",\"sgh\",\"sgi\",\"sgj\",\"sgk\",\"sgl\",\"sgm\",\"sgn\",\"sgo\",\"sgp\",\"sgr\",\"sgs\",\"sgt\",\"sgu\",\"sgw\",\"sgx\",\"sgy\",\"sgz\",\"sha\",\"shb\",\"shc\",\"shd\",\"she\",\"shg\",\"shh\",\"shi\",\"shj\",\"shk\",\"shl\",\"shm\",\"shn\",\"sho\",\"shp\",\"shq\",\"shr\",\"shs\",\"sht\",\"shu\",\"shv\",\"shw\",\"shx\",\"shy\",\"shz\",\"sia\",\"sib\",\"sid\",\"sie\",\"sif\",\"sig\",\"sih\",\"sii\",\"sij\",\"sik\",\"sil\",\"sim\",\"sio\",\"sip\",\"siq\",\"sir\",\"sis\",\"sit\",\"siu\",\"siv\",\"siw\",\"six\",\"siy\",\"siz\",\"sja\",\"sjb\",\"sjd\",\"sje\",\"sjg\",\"sjk\",\"sjl\",\"sjm\",\"sjn\",\"sjo\",\"sjp\",\"sjr\",\"sjs\",\"sjt\",\"sju\",\"sjw\",\"ska\",\"skb\",\"skc\",\"skd\",\"ske\",\"skf\",\"skg\",\"skh\",\"ski\",\"skj\",\"skk\",\"skm\",\"skn\",\"sko\",\"skp\",\"skq\",\"skr\",\"sks\",\"skt\",\"sku\",\"skv\",\"skw\",\"skx\",\"sky\",\"skz\",\"sla\",\"slc\",\"sld\",\"sle\",\"slf\",\"slg\",\"slh\",\"sli\",\"slj\",\"sll\",\"slm\",\"sln\",\"slp\",\"slq\",\"slr\",\"sls\",\"slt\",\"slu\",\"slw\",\"slx\",\"sly\",\"slz\",\"sma\",\"smb\",\"smc\",\"smd\",\"smf\",\"smg\",\"smh\",\"smi\",\"smj\",\"smk\",\"sml\",\"smm\",\"smn\",\"smp\",\"smq\",\"smr\",\"sms\",\"smt\",\"smu\",\"smv\",\"smw\",\"smx\",\"smy\",\"smz\",\"snb\",\"snc\",\"sne\",\"snf\",\"sng\",\"snh\",\"sni\",\"snj\",\"snk\",\"snl\",\"snm\",\"snn\",\"sno\",\"snp\",\"snq\",\"snr\",\"sns\",\"snu\",\"snv\",\"snw\",\"snx\",\"sny\",\"snz\",\"soa\",\"sob\",\"soc\",\"sod\",\"soe\",\"sog\",\"soh\",\"soi\",\"soj\",\"sok\",\"sol\",\"son\",\"soo\",\"sop\",\"soq\",\"sor\",\"sos\",\"sou\",\"sov\",\"sow\",\"sox\",\"soy\",\"soz\",\"spb\",\"spc\",\"spd\",\"spe\",\"spg\",\"spi\",\"spk\",\"spl\",\"spm\",\"spn\",\"spo\",\"spp\",\"spq\",\"spr\",\"sps\",\"spt\",\"spu\",\"spv\",\"spx\",\"spy\",\"sqa\",\"sqh\",\"sqj\",\"sqk\",\"sqm\",\"sqn\",\"sqo\",\"sqq\",\"sqr\",\"sqs\",\"sqt\",\"squ\",\"sra\",\"srb\",\"src\",\"sre\",\"srf\",\"srg\",\"srh\",\"sri\",\"srk\",\"srl\",\"srm\",\"srn\",\"sro\",\"srq\",\"srr\",\"srs\",\"srt\",\"sru\",\"srv\",\"srw\",\"srx\",\"sry\",\"srz\",\"ssa\",\"ssb\",\"ssc\",\"ssd\",\"sse\",\"ssf\",\"ssg\",\"ssh\",\"ssi\",\"ssj\",\"ssk\",\"ssl\",\"ssm\",\"ssn\",\"sso\",\"ssp\",\"ssq\",\"ssr\",\"sss\",\"sst\",\"ssu\",\"ssv\",\"ssx\",\"ssy\",\"ssz\",\"sta\",\"stb\",\"std\",\"ste\",\"stf\",\"stg\",\"sth\",\"sti\",\"stj\",\"stk\",\"stl\",\"stm\",\"stn\",\"sto\",\"stp\",\"stq\",\"str\",\"sts\",\"stt\",\"stu\",\"stv\",\"stw\",\"sty\",\"sua\",\"sub\",\"suc\",\"sue\",\"sug\",\"sui\",\"suj\",\"suk\",\"sul\",\"sum\",\"suq\",\"sur\",\"sus\",\"sut\",\"suv\",\"suw\",\"sux\",\"suy\",\"suz\",\"sva\",\"svb\",\"svc\",\"sve\",\"svk\",\"svm\",\"svr\",\"svs\",\"svx\",\"swb\",\"swc\",\"swf\",\"swg\",\"swh\",\"swi\",\"swj\",\"swk\",\"swl\",\"swm\",\"swn\",\"swo\",\"swp\",\"swq\",\"swr\",\"sws\",\"swt\",\"swu\",\"swv\",\"sww\",\"swx\",\"swy\",\"sxb\",\"sxc\",\"sxe\",\"sxg\",\"sxk\",\"sxl\",\"sxm\",\"sxn\",\"sxo\",\"sxr\",\"sxs\",\"sxu\",\"sxw\",\"sya\",\"syb\",\"syc\",\"syd\",\"syi\",\"syk\",\"syl\",\"sym\",\"syn\",\"syo\",\"syr\",\"sys\",\"syw\",\"syx\",\"syy\",\"sza\",\"szb\",\"szc\",\"szd\",\"sze\",\"szg\",\"szl\",\"szn\",\"szp\",\"szs\",\"szv\",\"szw\",\"taa\",\"tab\",\"tac\",\"tad\",\"tae\",\"taf\",\"tag\",\"tai\",\"taj\",\"tak\",\"tal\",\"tan\",\"tao\",\"tap\",\"taq\",\"tar\",\"tas\",\"tau\",\"tav\",\"taw\",\"tax\",\"tay\",\"taz\",\"tba\",\"tbb\",\"tbc\",\"tbd\",\"tbe\",\"tbf\",\"tbg\",\"tbh\",\"tbi\",\"tbj\",\"tbk\",\"tbl\",\"tbm\",\"tbn\",\"tbo\",\"tbp\",\"tbq\",\"tbr\",\"tbs\",\"tbt\",\"tbu\",\"tbv\",\"tbw\",\"tbx\",\"tby\",\"tbz\",\"tca\",\"tcb\",\"tcc\",\"tcd\",\"tce\",\"tcf\",\"tcg\",\"tch\",\"tci\",\"tck\",\"tcl\",\"tcm\",\"tcn\",\"tco\",\"tcp\",\"tcq\",\"tcs\",\"tct\",\"tcu\",\"tcw\",\"tcx\",\"tcy\",\"tcz\",\"tda\",\"tdb\",\"tdc\",\"tdd\",\"tde\",\"tdf\",\"tdg\",\"tdh\",\"tdi\",\"tdj\",\"tdk\",\"tdl\",\"tdm\",\"tdn\",\"tdo\",\"tdq\",\"tdr\",\"tds\",\"tdt\",\"tdu\",\"tdv\",\"tdx\",\"tdy\",\"tea\",\"teb\",\"tec\",\"ted\",\"tee\",\"tef\",\"teg\",\"teh\",\"tei\",\"tek\",\"tem\",\"ten\",\"teo\",\"tep\",\"teq\",\"ter\",\"tes\",\"tet\",\"teu\",\"tev\",\"tew\",\"tex\",\"tey\",\"tfi\",\"tfn\",\"tfo\",\"tfr\",\"tft\",\"tga\",\"tgb\",\"tgc\",\"tgd\",\"tge\",\"tgf\",\"tgg\",\"tgh\",\"tgi\",\"tgj\",\"tgn\",\"tgo\",\"tgp\",\"tgq\",\"tgr\",\"tgs\",\"tgt\",\"tgu\",\"tgv\",\"tgw\",\"tgx\",\"tgy\",\"tgz\",\"thc\",\"thd\",\"the\",\"thf\",\"thh\",\"thi\",\"thk\",\"thl\",\"thm\",\"thn\",\"thp\",\"thq\",\"thr\",\"ths\",\"tht\",\"thu\",\"thv\",\"thw\",\"thx\",\"thy\",\"thz\",\"tia\",\"tic\",\"tid\",\"tie\",\"tif\",\"tig\",\"tih\",\"tii\",\"tij\",\"tik\",\"til\",\"tim\",\"tin\",\"tio\",\"tip\",\"tiq\",\"tis\",\"tit\",\"tiu\",\"tiv\",\"tiw\",\"tix\",\"tiy\",\"tiz\",\"tja\",\"tjg\",\"tji\",\"tjl\",\"tjm\",\"tjn\",\"tjo\",\"tjs\",\"tju\",\"tjw\",\"tka\",\"tkb\",\"tkd\",\"tke\",\"tkf\",\"tkg\",\"tkk\",\"tkl\",\"tkm\",\"tkn\",\"tkp\",\"tkq\",\"tkr\",\"tks\",\"tkt\",\"tku\",\"tkv\",\"tkw\",\"tkx\",\"tkz\",\"tla\",\"tlb\",\"tlc\",\"tld\",\"tlf\",\"tlg\",\"tlh\",\"tli\",\"tlj\",\"tlk\",\"tll\",\"tlm\",\"tln\",\"tlo\",\"tlp\",\"tlq\",\"tlr\",\"tls\",\"tlt\",\"tlu\",\"tlv\",\"tlw\",\"tlx\",\"tly\",\"tma\",\"tmb\",\"tmc\",\"tmd\",\"tme\",\"tmf\",\"tmg\",\"tmh\",\"tmi\",\"tmj\",\"tmk\",\"tml\",\"tmm\",\"tmn\",\"tmo\",\"tmp\",\"tmq\",\"tmr\",\"tms\",\"tmt\",\"tmu\",\"tmv\",\"tmw\",\"tmy\",\"tmz\",\"tna\",\"tnb\",\"tnc\",\"tnd\",\"tne\",\"tnf\",\"tng\",\"tnh\",\"tni\",\"tnk\",\"tnl\",\"tnm\",\"tnn\",\"tno\",\"tnp\",\"tnq\",\"tnr\",\"tns\",\"tnt\",\"tnu\",\"tnv\",\"tnw\",\"tnx\",\"tny\",\"tnz\",\"tob\",\"toc\",\"tod\",\"toe\",\"tof\",\"tog\",\"toh\",\"toi\",\"toj\",\"tol\",\"tom\",\"too\",\"top\",\"toq\",\"tor\",\"tos\",\"tou\",\"tov\",\"tow\",\"tox\",\"toy\",\"toz\",\"tpa\",\"tpc\",\"tpe\",\"tpf\",\"tpg\",\"tpi\",\"tpj\",\"tpk\",\"tpl\",\"tpm\",\"tpn\",\"tpo\",\"tpp\",\"tpq\",\"tpr\",\"tpt\",\"tpu\",\"tpv\",\"tpw\",\"tpx\",\"tpy\",\"tpz\",\"tqb\",\"tql\",\"tqm\",\"tqn\",\"tqo\",\"tqp\",\"tqq\",\"tqr\",\"tqt\",\"tqu\",\"tqw\",\"tra\",\"trb\",\"trc\",\"trd\",\"tre\",\"trf\",\"trg\",\"trh\",\"tri\",\"trj\",\"trk\",\"trl\",\"trm\",\"trn\",\"tro\",\"trp\",\"trq\",\"trr\",\"trs\",\"trt\",\"tru\",\"trv\",\"trw\",\"trx\",\"try\",\"trz\",\"tsa\",\"tsb\",\"tsc\",\"tsd\",\"tse\",\"tsf\",\"tsg\",\"tsh\",\"tsi\",\"tsj\",\"tsk\",\"tsl\",\"tsm\",\"tsp\",\"tsq\",\"tsr\",\"tss\",\"tst\",\"tsu\",\"tsv\",\"tsw\",\"tsx\",\"tsy\",\"tsz\",\"tta\",\"ttb\",\"ttc\",\"ttd\",\"tte\",\"ttf\",\"ttg\",\"tth\",\"tti\",\"ttj\",\"ttk\",\"ttl\",\"ttm\",\"ttn\",\"tto\",\"ttp\",\"ttq\",\"ttr\",\"tts\",\"ttt\",\"ttu\",\"ttv\",\"ttw\",\"tty\",\"ttz\",\"tua\",\"tub\",\"tuc\",\"tud\",\"tue\",\"tuf\",\"tug\",\"tuh\",\"tui\",\"tuj\",\"tul\",\"tum\",\"tun\",\"tuo\",\"tup\",\"tuq\",\"tus\",\"tut\",\"tuu\",\"tuv\",\"tuw\",\"tux\",\"tuy\",\"tuz\",\"tva\",\"tvd\",\"tve\",\"tvk\",\"tvl\",\"tvm\",\"tvn\",\"tvo\",\"tvs\",\"tvt\",\"tvu\",\"tvw\",\"tvy\",\"twa\",\"twb\",\"twc\",\"twd\",\"twe\",\"twf\",\"twg\",\"twh\",\"twl\",\"twm\",\"twn\",\"two\",\"twp\",\"twq\",\"twr\",\"twt\",\"twu\",\"tww\",\"twx\",\"twy\",\"txa\",\"txb\",\"txc\",\"txe\",\"txg\",\"txh\",\"txi\",\"txj\",\"txm\",\"txn\",\"txo\",\"txq\",\"txr\",\"txs\",\"txt\",\"txu\",\"txx\",\"txy\",\"tya\",\"tye\",\"tyh\",\"tyi\",\"tyj\",\"tyl\",\"tyn\",\"typ\",\"tyr\",\"tys\",\"tyt\",\"tyu\",\"tyv\",\"tyx\",\"tyz\",\"tza\",\"tzh\",\"tzj\",\"tzl\",\"tzm\",\"tzn\",\"tzo\",\"tzx\",\"uam\",\"uan\",\"uar\",\"uba\",\"ubi\",\"ubl\",\"ubr\",\"ubu\",\"uby\",\"uda\",\"ude\",\"udg\",\"udi\",\"udj\",\"udl\",\"udm\",\"udu\",\"ues\",\"ufi\",\"uga\",\"ugb\",\"uge\",\"ugn\",\"ugo\",\"ugy\",\"uha\",\"uhn\",\"uis\",\"uiv\",\"uji\",\"uka\",\"ukg\",\"ukh\",\"ukk\",\"ukl\",\"ukp\",\"ukq\",\"uks\",\"uku\",\"ukw\",\"uky\",\"ula\",\"ulb\",\"ulc\",\"ule\",\"ulf\",\"uli\",\"ulk\",\"ull\",\"ulm\",\"uln\",\"ulu\",\"ulw\",\"uma\",\"umb\",\"umc\",\"umd\",\"umg\",\"umi\",\"umm\",\"umn\",\"umo\",\"ump\",\"umr\",\"ums\",\"umu\",\"una\",\"und\",\"une\",\"ung\",\"unk\",\"unm\",\"unn\",\"unp\",\"unr\",\"unu\",\"unx\",\"unz\",\"uok\",\"upi\",\"upv\",\"ura\",\"urb\",\"urc\",\"ure\",\"urf\",\"urg\",\"urh\",\"uri\",\"urj\",\"urk\",\"url\",\"urm\",\"urn\",\"uro\",\"urp\",\"urr\",\"urt\",\"uru\",\"urv\",\"urw\",\"urx\",\"ury\",\"urz\",\"usa\",\"ush\",\"usi\",\"usk\",\"usp\",\"usu\",\"uta\",\"ute\",\"utp\",\"utr\",\"utu\",\"uum\",\"uun\",\"uur\",\"uuu\",\"uve\",\"uvh\",\"uvl\",\"uwa\",\"uya\",\"uzn\",\"uzs\",\"vaa\",\"vae\",\"vaf\",\"vag\",\"vah\",\"vai\",\"vaj\",\"val\",\"vam\",\"van\",\"vao\",\"vap\",\"var\",\"vas\",\"vau\",\"vav\",\"vay\",\"vbb\",\"vbk\",\"vec\",\"ved\",\"vel\",\"vem\",\"veo\",\"vep\",\"ver\",\"vgr\",\"vgt\",\"vic\",\"vid\",\"vif\",\"vig\",\"vil\",\"vin\",\"vis\",\"vit\",\"viv\",\"vka\",\"vki\",\"vkj\",\"vkk\",\"vkl\",\"vkm\",\"vko\",\"vkp\",\"vkt\",\"vku\",\"vlp\",\"vls\",\"vma\",\"vmb\",\"vmc\",\"vmd\",\"vme\",\"vmf\",\"vmg\",\"vmh\",\"vmi\",\"vmj\",\"vmk\",\"vml\",\"vmm\",\"vmp\",\"vmq\",\"vmr\",\"vms\",\"vmu\",\"vmv\",\"vmw\",\"vmx\",\"vmy\",\"vmz\",\"vnk\",\"vnm\",\"vnp\",\"vor\",\"vot\",\"vra\",\"vro\",\"vrs\",\"vrt\",\"vsi\",\"vsl\",\"vsv\",\"vto\",\"vum\",\"vun\",\"vut\",\"vwa\",\"waa\",\"wab\",\"wac\",\"wad\",\"wae\",\"waf\",\"wag\",\"wah\",\"wai\",\"waj\",\"wak\",\"wal\",\"wam\",\"wan\",\"wao\",\"wap\",\"waq\",\"war\",\"was\",\"wat\",\"wau\",\"wav\",\"waw\",\"wax\",\"way\",\"waz\",\"wba\",\"wbb\",\"wbe\",\"wbf\",\"wbh\",\"wbi\",\"wbj\",\"wbk\",\"wbl\",\"wbm\",\"wbp\",\"wbq\",\"wbr\",\"wbs\",\"wbt\",\"wbv\",\"wbw\",\"wca\",\"wci\",\"wdd\",\"wdg\",\"wdj\",\"wdk\",\"wdu\",\"wdy\",\"wea\",\"wec\",\"wed\",\"weg\",\"weh\",\"wei\",\"wem\",\"wen\",\"weo\",\"wep\",\"wer\",\"wes\",\"wet\",\"weu\",\"wew\",\"wfg\",\"wga\",\"wgb\",\"wgg\",\"wgi\",\"wgo\",\"wgu\",\"wgw\",\"wgy\",\"wha\",\"whg\",\"whk\",\"whu\",\"wib\",\"wic\",\"wie\",\"wif\",\"wig\",\"wih\",\"wii\",\"wij\",\"wik\",\"wil\",\"wim\",\"win\",\"wir\",\"wit\",\"wiu\",\"wiv\",\"wiw\",\"wiy\",\"wja\",\"wji\",\"wka\",\"wkb\",\"wkd\",\"wkl\",\"wku\",\"wkw\",\"wky\",\"wla\",\"wlc\",\"wle\",\"wlg\",\"wli\",\"wlk\",\"wll\",\"wlm\",\"wlo\",\"wlr\",\"wls\",\"wlu\",\"wlv\",\"wlw\",\"wlx\",\"wly\",\"wma\",\"wmb\",\"wmc\",\"wmd\",\"wme\",\"wmh\",\"wmi\",\"wmm\",\"wmn\",\"wmo\",\"wms\",\"wmt\",\"wmw\",\"wmx\",\"wnb\",\"wnc\",\"wnd\",\"wne\",\"wng\",\"wni\",\"wnk\",\"wnm\",\"wnn\",\"wno\",\"wnp\",\"wnu\",\"wnw\",\"wny\",\"woa\",\"wob\",\"woc\",\"wod\",\"woe\",\"wof\",\"wog\",\"woi\",\"wok\",\"wom\",\"won\",\"woo\",\"wor\",\"wos\",\"wow\",\"woy\",\"wpc\",\"wra\",\"wrb\",\"wrd\",\"wrg\",\"wrh\",\"wri\",\"wrk\",\"wrl\",\"wrm\",\"wrn\",\"wro\",\"wrp\",\"wrr\",\"wrs\",\"wru\",\"wrv\",\"wrw\",\"wrx\",\"wry\",\"wrz\",\"wsa\",\"wsg\",\"wsi\",\"wsk\",\"wsr\",\"wss\",\"wsu\",\"wsv\",\"wtf\",\"wth\",\"wti\",\"wtk\",\"wtm\",\"wtw\",\"wua\",\"wub\",\"wud\",\"wuh\",\"wul\",\"wum\",\"wun\",\"wur\",\"wut\",\"wuu\",\"wuv\",\"wux\",\"wuy\",\"wwa\",\"wwb\",\"wwo\",\"wwr\",\"www\",\"wxa\",\"wxw\",\"wya\",\"wyb\",\"wyi\",\"wym\",\"wyr\",\"wyy\",\"xaa\",\"xab\",\"xac\",\"xad\",\"xae\",\"xag\",\"xai\",\"xaj\",\"xak\",\"xal\",\"xam\",\"xan\",\"xao\",\"xap\",\"xaq\",\"xar\",\"xas\",\"xat\",\"xau\",\"xav\",\"xaw\",\"xay\",\"xba\",\"xbb\",\"xbc\",\"xbd\",\"xbe\",\"xbg\",\"xbi\",\"xbj\",\"xbm\",\"xbn\",\"xbo\",\"xbp\",\"xbr\",\"xbw\",\"xbx\",\"xby\",\"xcb\",\"xcc\",\"xce\",\"xcg\",\"xch\",\"xcl\",\"xcm\",\"xcn\",\"xco\",\"xcr\",\"xct\",\"xcu\",\"xcv\",\"xcw\",\"xcy\",\"xda\",\"xdc\",\"xdk\",\"xdm\",\"xdo\",\"xdy\",\"xeb\",\"xed\",\"xeg\",\"xel\",\"xem\",\"xep\",\"xer\",\"xes\",\"xet\",\"xeu\",\"xfa\",\"xga\",\"xgb\",\"xgd\",\"xgf\",\"xgg\",\"xgi\",\"xgl\",\"xgm\",\"xgn\",\"xgr\",\"xgu\",\"xgw\",\"xha\",\"xhc\",\"xhd\",\"xhe\",\"xhr\",\"xht\",\"xhu\",\"xhv\",\"xia\",\"xib\",\"xii\",\"xil\",\"xin\",\"xip\",\"xir\",\"xis\",\"xiv\",\"xiy\",\"xjb\",\"xjt\",\"xka\",\"xkb\",\"xkc\",\"xkd\",\"xke\",\"xkf\",\"xkg\",\"xkh\",\"xki\",\"xkj\",\"xkk\",\"xkl\",\"xkn\",\"xko\",\"xkp\",\"xkq\",\"xkr\",\"xks\",\"xkt\",\"xku\",\"xkv\",\"xkw\",\"xkx\",\"xky\",\"xkz\",\"xla\",\"xlb\",\"xlc\",\"xld\",\"xle\",\"xlg\",\"xli\",\"xln\",\"xlo\",\"xlp\",\"xls\",\"xlu\",\"xly\",\"xma\",\"xmb\",\"xmc\",\"xmd\",\"xme\",\"xmf\",\"xmg\",\"xmh\",\"xmj\",\"xmk\",\"xml\",\"xmm\",\"xmn\",\"xmo\",\"xmp\",\"xmq\",\"xmr\",\"xms\",\"xmt\",\"xmu\",\"xmv\",\"xmw\",\"xmx\",\"xmy\",\"xmz\",\"xna\",\"xnb\",\"xnd\",\"xng\",\"xnh\",\"xni\",\"xnk\",\"xnn\",\"xno\",\"xnr\",\"xns\",\"xnt\",\"xnu\",\"xny\",\"xnz\",\"xoc\",\"xod\",\"xog\",\"xoi\",\"xok\",\"xom\",\"xon\",\"xoo\",\"xop\",\"xor\",\"xow\",\"xpa\",\"xpc\",\"xpe\",\"xpg\",\"xpi\",\"xpj\",\"xpk\",\"xpm\",\"xpn\",\"xpo\",\"xpp\",\"xpq\",\"xpr\",\"xps\",\"xpt\",\"xpu\",\"xpy\",\"xqa\",\"xqt\",\"xra\",\"xrb\",\"xrd\",\"xre\",\"xrg\",\"xri\",\"xrm\",\"xrn\",\"xrq\",\"xrr\",\"xrt\",\"xru\",\"xrw\",\"xsa\",\"xsb\",\"xsc\",\"xsd\",\"xse\",\"xsh\",\"xsi\",\"xsj\",\"xsl\",\"xsm\",\"xsn\",\"xso\",\"xsp\",\"xsq\",\"xsr\",\"xss\",\"xsu\",\"xsv\",\"xsy\",\"xta\",\"xtb\",\"xtc\",\"xtd\",\"xte\",\"xtg\",\"xth\",\"xti\",\"xtj\",\"xtl\",\"xtm\",\"xtn\",\"xto\",\"xtp\",\"xtq\",\"xtr\",\"xts\",\"xtt\",\"xtu\",\"xtv\",\"xtw\",\"xty\",\"xtz\",\"xua\",\"xub\",\"xud\",\"xug\",\"xuj\",\"xul\",\"xum\",\"xun\",\"xuo\",\"xup\",\"xur\",\"xut\",\"xuu\",\"xve\",\"xvi\",\"xvn\",\"xvo\",\"xvs\",\"xwa\",\"xwc\",\"xwd\",\"xwe\",\"xwg\",\"xwj\",\"xwk\",\"xwl\",\"xwo\",\"xwr\",\"xwt\",\"xww\",\"xxb\",\"xxk\",\"xxm\",\"xxr\",\"xxt\",\"xya\",\"xyb\",\"xyj\",\"xyk\",\"xyl\",\"xyt\",\"xyy\",\"xzh\",\"xzm\",\"xzp\",\"yaa\",\"yab\",\"yac\",\"yad\",\"yae\",\"yaf\",\"yag\",\"yah\",\"yai\",\"yaj\",\"yak\",\"yal\",\"yam\",\"yan\",\"yao\",\"yap\",\"yaq\",\"yar\",\"yas\",\"yat\",\"yau\",\"yav\",\"yaw\",\"yax\",\"yay\",\"yaz\",\"yba\",\"ybb\",\"ybd\",\"ybe\",\"ybh\",\"ybi\",\"ybj\",\"ybk\",\"ybl\",\"ybm\",\"ybn\",\"ybo\",\"ybx\",\"yby\",\"ych\",\"ycl\",\"ycn\",\"ycp\",\"yda\",\"ydd\",\"yde\",\"ydg\",\"ydk\",\"yds\",\"yea\",\"yec\",\"yee\",\"yei\",\"yej\",\"yel\",\"yen\",\"yer\",\"yes\",\"yet\",\"yeu\",\"yev\",\"yey\",\"yga\",\"ygi\",\"ygl\",\"ygm\",\"ygp\",\"ygr\",\"ygs\",\"ygu\",\"ygw\",\"yha\",\"yhd\",\"yhl\",\"yhs\",\"yia\",\"yif\",\"yig\",\"yih\",\"yii\",\"yij\",\"yik\",\"yil\",\"yim\",\"yin\",\"yip\",\"yiq\",\"yir\",\"yis\",\"yit\",\"yiu\",\"yiv\",\"yix\",\"yiy\",\"yiz\",\"yka\",\"ykg\",\"yki\",\"ykk\",\"ykl\",\"ykm\",\"ykn\",\"yko\",\"ykr\",\"ykt\",\"yku\",\"yky\",\"yla\",\"ylb\",\"yle\",\"ylg\",\"yli\",\"yll\",\"ylm\",\"yln\",\"ylo\",\"ylr\",\"ylu\",\"yly\",\"yma\",\"ymb\",\"ymc\",\"ymd\",\"yme\",\"ymg\",\"ymh\",\"ymi\",\"ymk\",\"yml\",\"ymm\",\"ymn\",\"ymo\",\"ymp\",\"ymq\",\"ymr\",\"yms\",\"ymt\",\"ymx\",\"ymz\",\"yna\",\"ynd\",\"yne\",\"yng\",\"ynh\",\"ynk\",\"ynl\",\"ynn\",\"yno\",\"ynq\",\"yns\",\"ynu\",\"yob\",\"yog\",\"yoi\",\"yok\",\"yol\",\"yom\",\"yon\",\"yos\",\"yot\",\"yox\",\"yoy\",\"ypa\",\"ypb\",\"ypg\",\"yph\",\"ypk\",\"ypm\",\"ypn\",\"ypo\",\"ypp\",\"ypz\",\"yra\",\"yrb\",\"yre\",\"yri\",\"yrk\",\"yrl\",\"yrm\",\"yrn\",\"yro\",\"yrs\",\"yrw\",\"yry\",\"ysc\",\"ysd\",\"ysg\",\"ysl\",\"ysn\",\"yso\",\"ysp\",\"ysr\",\"yss\",\"ysy\",\"yta\",\"ytl\",\"ytp\",\"ytw\",\"yty\",\"yua\",\"yub\",\"yuc\",\"yud\",\"yue\",\"yuf\",\"yug\",\"yui\",\"yuj\",\"yuk\",\"yul\",\"yum\",\"yun\",\"yup\",\"yuq\",\"yur\",\"yut\",\"yuu\",\"yuw\",\"yux\",\"yuy\",\"yuz\",\"yva\",\"yvt\",\"ywa\",\"ywg\",\"ywl\",\"ywn\",\"ywq\",\"ywr\",\"ywt\",\"ywu\",\"yww\",\"yxa\",\"yxg\",\"yxl\",\"yxm\",\"yxu\",\"yxy\",\"yyr\",\"yyu\",\"yyz\",\"yzg\",\"yzk\",\"zaa\",\"zab\",\"zac\",\"zad\",\"zae\",\"zaf\",\"zag\",\"zah\",\"zai\",\"zaj\",\"zak\",\"zal\",\"zam\",\"zao\",\"zap\",\"zaq\",\"zar\",\"zas\",\"zat\",\"zau\",\"zav\",\"zaw\",\"zax\",\"zay\",\"zaz\",\"zbc\",\"zbe\",\"zbl\",\"zbt\",\"zbw\",\"zca\",\"zch\",\"zdj\",\"zea\",\"zeg\",\"zeh\",\"zen\",\"zga\",\"zgb\",\"zgh\",\"zgm\",\"zgn\",\"zgr\",\"zhb\",\"zhd\",\"zhi\",\"zhn\",\"zhw\",\"zhx\",\"zia\",\"zib\",\"zik\",\"zil\",\"zim\",\"zin\",\"zir\",\"ziw\",\"ziz\",\"zka\",\"zkb\",\"zkd\",\"zkg\",\"zkh\",\"zkk\",\"zkn\",\"zko\",\"zkp\",\"zkr\",\"zkt\",\"zku\",\"zkv\",\"zkz\",\"zle\",\"zlj\",\"zlm\",\"zln\",\"zlq\",\"zls\",\"zlw\",\"zma\",\"zmb\",\"zmc\",\"zmd\",\"zme\",\"zmf\",\"zmg\",\"zmh\",\"zmi\",\"zmj\",\"zmk\",\"zml\",\"zmm\",\"zmn\",\"zmo\",\"zmp\",\"zmq\",\"zmr\",\"zms\",\"zmt\",\"zmu\",\"zmv\",\"zmw\",\"zmx\",\"zmy\",\"zmz\",\"zna\",\"znd\",\"zne\",\"zng\",\"znk\",\"zns\",\"zoc\",\"zoh\",\"zom\",\"zoo\",\"zoq\",\"zor\",\"zos\",\"zpa\",\"zpb\",\"zpc\",\"zpd\",\"zpe\",\"zpf\",\"zpg\",\"zph\",\"zpi\",\"zpj\",\"zpk\",\"zpl\",\"zpm\",\"zpn\",\"zpo\",\"zpp\",\"zpq\",\"zpr\",\"zps\",\"zpt\",\"zpu\",\"zpv\",\"zpw\",\"zpx\",\"zpy\",\"zpz\",\"zqe\",\"zra\",\"zrg\",\"zrn\",\"zro\",\"zrp\",\"zrs\",\"zsa\",\"zsk\",\"zsl\",\"zsm\",\"zsr\",\"zsu\",\"zte\",\"ztg\",\"ztl\",\"ztm\",\"ztn\",\"ztp\",\"ztq\",\"zts\",\"ztt\",\"ztu\",\"ztx\",\"zty\",\"zua\",\"zuh\",\"zum\",\"zun\",\"zuy\",\"zwa\",\"zxx\",\"zyb\",\"zyg\",\"zyj\",\"zyn\",\"zyp\",\"zza\",\"zzj\"]\n;return axe.utils.validLangs=function(){\"use strict\";return N},commons}()})}(\"object\"==typeof window?window:this);";
-const pageFunctions=require('../../lib/page-functions');
-
-
-
-
-
-
-
-
-function runA11yChecks(){
-
-return window.axe.run(document,{
-elementRef:true,
-runOnly:{
-type:'tag',
-values:[
-'wcag2a',
-'wcag2aa']},
-
-
-resultTypes:['violations','inapplicable'],
-rules:{
-'tabindex':{enabled:true},
-'table-fake-caption':{enabled:true},
-'td-has-header':{enabled:true},
-'area-alt':{enabled:false},
-'blink':{enabled:false},
-'server-side-image-map':{enabled:false}}}).
-
-
-then(axeResult=>{
-
-
-axeResult.violations.forEach(v=>v.nodes.forEach(node=>{
-node.path=getNodePath(node.element);
-
-node.snippet=getOuterHTMLSnippet(node.element);
-
-node.element=node.any=node.all=node.none=undefined;
-}));
-
-
-axeResult={violations:axeResult.violations,notApplicable:axeResult.inapplicable};
-return axeResult;
-});
-
-
-
-
-
-
-
-function getNodePath(node){
-
-function getNodeIndex(node){
-let index=0;
-let prevNode;
-while(prevNode=node.previousSibling){
-node=prevNode;
-
-if(node.nodeType===Node.TEXT_NODE&&node.textContent&&
-node.textContent.trim().length===0)continue;
-index++;
-}
-return index;
-}
-
-const path=[];
-while(node&&node.parentNode){
-const index=getNodeIndex(node);
-path.push([index,node.nodeName]);
-node=node.parentNode;
-}
-path.reverse();
-return path.join(',');
-}
-}
-
-class Accessibility extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-const expression=`(function () {
- ${pageFunctions.getOuterHTMLSnippetString};
- ${axeLibSource};
- return (${runA11yChecks.toString()}());
- })()`;
-
-return driver.evaluateAsync(expression,{useIsolation:true}).then(returnedValue=>{
-if(!returnedValue){
-throw new Error('No axe-core results returned');
-}
-if(!Array.isArray(returnedValue.violations)){
-throw new Error('Unable to parse axe results'+returnedValue);
-}
-return returnedValue;
-});
-}}
-
-
-module.exports=Accessibility;
-
-},{"../../lib/page-functions":89,"./gatherer":21}],"../gather/gatherers/cache-contents":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-const Gatherer=require('./gatherer');
-
-
-
-
-
-
-function getCacheContents(){
-
-return caches.keys().
-
-
-then(cacheNames=>Promise.all(cacheNames.map(cacheName=>caches.open(cacheName)))).
-
-then(caches=>{
-
-const requests=[];
-
-
-return Promise.all(caches.map(cache=>{
-return cache.keys().
-then(reqs=>{
-requests.push(...reqs.map(r=>r.url));
-});
-})).then(_=>{
-return requests;
-});
-});
-}
-
-class CacheContents extends Gatherer{
-
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-
-
-const cacheUrls=await driver.evaluateAsync(`(${getCacheContents.toString()}())`);
-if(!cacheUrls||!Array.isArray(cacheUrls)){
-throw new Error('Unable to retrieve cache contents');
-}
-
-return cacheUrls;
-}}
-
-
-module.exports=CacheContents;
-
-},{"./gatherer":21}],"../gather/gatherers/chrome-console-messages":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-class ChromeConsoleMessages extends Gatherer{
-constructor(){
-super();
-
-this._logEntries=[];
-this._onConsoleEntryAdded=this.onConsoleEntry.bind(this);
-}
-
-
-
-
-onConsoleEntry(entry){
-this._logEntries.push(entry);
-}
-
-
-
-
-async beforePass(passContext){
-const driver=passContext.driver;
-driver.on('Log.entryAdded',this._onConsoleEntryAdded);
-await driver.sendCommand('Log.enable');
-await driver.sendCommand('Log.startViolationsReport',{
-config:[{name:'discouragedAPIUse',threshold:-1}]});
-
-}
-
-
-
-
-
-async afterPass(passContext){
-await passContext.driver.sendCommand('Log.stopViolationsReport');
-await passContext.driver.off('Log.entryAdded',this._onConsoleEntryAdded);
-await passContext.driver.sendCommand('Log.disable');
-return this._logEntries;
-}}
-
-
-module.exports=ChromeConsoleMessages;
-
-},{"./gatherer":21}],"../gather/gatherers/css-usage":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-
-
-
-class CSSUsage extends Gatherer{
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-
-
-const stylesheets=[];
-
-const onStylesheetAdded=sheet=>stylesheets.push(sheet);
-driver.on('CSS.styleSheetAdded',onStylesheetAdded);
-
-await driver.sendCommand('DOM.enable');
-await driver.sendCommand('CSS.enable');
-await driver.sendCommand('CSS.startRuleUsageTracking');
-await driver.evaluateAsync('getComputedStyle(document.body)');
-driver.off('CSS.styleSheetAdded',onStylesheetAdded);
-
-
-const promises=stylesheets.map(sheet=>{
-const styleSheetId=sheet.header.styleSheetId;
-return driver.sendCommand('CSS.getStyleSheetText',{styleSheetId}).then(content=>{
-return{
-header:sheet.header,
-content:content.text};
-
-});
-});
-const styleSheetInfo=await Promise.all(promises);
-
-const ruleUsageResponse=await driver.sendCommand('CSS.stopRuleUsageTracking');
-await driver.sendCommand('CSS.disable');
-await driver.sendCommand('DOM.disable');
-
-const dedupedStylesheets=new Map(styleSheetInfo.map(sheet=>{
-return[sheet.content,sheet];
-}));
-return{
-rules:ruleUsageResponse.ruleUsage,
-stylesheets:Array.from(dedupedStylesheets.values())};
-
-}}
-
-
-module.exports=CSSUsage;
-
-},{"./gatherer":21}],"../gather/gatherers/dobetterweb/anchors-with-no-rel-noopener":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const pageFunctions=require('../../../lib/page-functions.js');
-
-class AnchorsWithNoRelNoopener extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const expression=`(function() {
- ${pageFunctions.getOuterHTMLSnippetString};
- ${pageFunctions.getElementsInDocumentString}; // define function on page
- const selector = 'a[target="_blank"]:not([rel~="noopener"]):not([rel~="noreferrer"])';
- const elements = getElementsInDocument(selector);
- return elements.map(node => ({
- href: node.href,
- rel: node.getAttribute('rel'),
- target: node.getAttribute('target'),
- outerHTML: getOuterHTMLSnippet(node),
- }));
- })()`;
-
-return passContext.driver.evaluateAsync(expression);
-}}
-
-
-module.exports=AnchorsWithNoRelNoopener;
-
-},{"../../../lib/page-functions.js":89,"../gatherer":21}],"../gather/gatherers/dobetterweb/appcache":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-class AppCacheManifest extends Gatherer{
-
-
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-
-return driver.querySelector('html').
-then(node=>node&&node.getAttribute('manifest'));
-}}
-
-
-module.exports=AppCacheManifest;
-
-},{"../gatherer":21}],"../gather/gatherers/dobetterweb/doctype":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-
-
-
-
-
-function getDoctype(){
-
-if(!document.doctype){
-return null;
-}
-
-const{name,publicId,systemId}=document.doctype;
-return{name,publicId,systemId};
-}
-
-class Doctype extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-return driver.evaluateAsync(`(${getDoctype.toString()}())`);
-}}
-
-
-module.exports=Doctype;
-
-},{"../gatherer":21}],"../gather/gatherers/dobetterweb/domstats":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const pageFunctions=require('../../../lib/page-functions');
-
-
-
-
-
-
-
-
-function createSelectorsLabel(element){
-let name=element.localName||'';
-const idAttr=element.getAttribute&&element.getAttribute('id');
-if(idAttr){
-name+=`#${idAttr}`;
-}
-
-
-if(element.classList){
-const className=element.classList.toString();
-if(className){
-name+=`.${className.trim().replace(/\s+/g,'.')}`;
-}
-}else if(ShadowRoot.prototype.isPrototypeOf(element)){
-name+='#shadow-root';
-}
-
-return name;
-}
-
-
-
-
-
-
-function elementPathInDOM(element){
-const visited=new Set();
-const path=[createSelectorsLabel(element)];
-let node=element;
-while(node){
-visited.add(node);
-
-
-
-if(ShadowRoot.prototype.isPrototypeOf(node)){
-const isShadowHost=node.host&&node.localName!=='a';
-node=isShadowHost?node.host:node.parentElement;
-}else{
-const isShadowHost=node.parentNode&&node.parentNode.host&&
-node.parentNode.localName!=='a';
-node=isShadowHost?node.parentNode.host:node.parentElement;
-}
-
-if(visited.has(node)){
-node=null;
-}
-
-if(node){
-path.unshift(createSelectorsLabel(node));
-}
-}
-return path;
-}
-
-
-
-
-
-
-
-
-function getDOMStats(element,deep=true){
-let deepestNode=null;
-let maxDepth=0;
-let maxWidth=0;
-let parentWithMostChildren=null;
-
-
-
-
-
-const _calcDOMWidthAndHeight=function(element,depth=1){
-if(depth>maxDepth){
-deepestNode=element;
-maxDepth=depth;
-}
-if(element.children.length>maxWidth){
-parentWithMostChildren=element;
-maxWidth=element.children.length;
-}
-
-let child=element.firstElementChild;
-while(child){
-_calcDOMWidthAndHeight(child,depth+1);
-
-if(deep&&child.shadowRoot){
-_calcDOMWidthAndHeight(child.shadowRoot,depth+1);
-}
-child=child.nextElementSibling;
-}
-
-return{maxDepth,maxWidth};
-};
-
-const result=_calcDOMWidthAndHeight(element);
-
-return{
-depth:{
-max:result.maxDepth,
-pathToElement:elementPathInDOM(deepestNode),
-
-snippet:getOuterHTMLSnippet(deepestNode,['style'])},
-
-width:{
-max:result.maxWidth,
-pathToElement:elementPathInDOM(parentWithMostChildren),
-snippet:getOuterHTMLSnippet(parentWithMostChildren,['style'])}};
-
-
-}
-
-class DOMStats extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const expression=`(function() {
- ${pageFunctions.getOuterHTMLSnippetString};
- ${createSelectorsLabel.toString()};
- ${elementPathInDOM.toString()};
- return (${getDOMStats.toString()}(document.documentElement));
- })()`;
-return passContext.driver.sendCommand('DOM.enable').
-then(()=>passContext.driver.evaluateAsync(expression,{useIsolation:true})).
-then(results=>passContext.driver.getElementsInDocument().then(allNodes=>{
-results.totalDOMNodes=allNodes.length;
-return passContext.driver.sendCommand('DOM.disable').then(()=>results);
-}));
-}}
-
-
-module.exports=DOMStats;
-
-},{"../../../lib/page-functions":89,"../gatherer":21}],"../gather/gatherers/dobetterweb/js-libraries":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-const libDetectorSource="var UNKNOWN_VERSION = null;\nvar d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests = {\n\n 'GWT': {\n icon: 'gwt',\n url: 'http://www.gwtproject.org/',\n test: function(win) {\n // pretty complicated, many possible tell tales\n var doc = win.document,\n hasHistFrame = doc.getElementById('__gwt_historyFrame'),\n hasGwtUid = doc.gwt_uid,\n hasBodyListener = doc.body.__listener,\n hasBodyEventBits = doc.body.__eventBits,\n hasModules = win.__gwt_activeModules,\n hasJsonP = win.__gwt_jsonp__,\n hasRootWinApp = win.__gwt_scriptsLoaded || win.__gwt_stylesLoaded || win.__gwt_activeModules;\n\n // use the many possible indicators\n if(hasHistFrame || hasGwtUid || hasBodyListener || hasBodyEventBits || hasModules || hasJsonP || hasRootWinApp) {\n\n // carefully look at frames, but only if certain is GWT frame\n var frames = doc.getElementsByTagName('iframe'),\n gwtVersion = UNKNOWN_VERSION;\n for(var n=0; n<frames.length; n++) {\n // catch security access errors\n try {\n var hasNegativeTabIndex = frames[n].tabIndex < 0; // on for GWT\n if(hasNegativeTabIndex && frames[n].contentWindow && frames[n].contentWindow.$gwt_version) {\n gwtVersion = frames[n].contentWindow.$gwt_version;\n break;\n }\n }\n catch(e) {}\n }\n\n if(gwtVersion=='0.0.999') {\n gwtVersion = 'Google Internal';\n }\n\n return { version: gwtVersion };\n }\n return false;\n }\n },\n\n 'Ink': {\n icon: 'ink',\n url: 'http://ink.sapo.pt/',\n test: function(win) {\n if (win.Ink && win.Ink.createModule) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Vaadin': {\n icon: 'vaadin',\n url: 'https://vaadin.com/',\n test: function(win) {\n if (win.vaadin && win.vaadin.registerWidgetset) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Bootstrap': {\n icon: 'bootstrap',\n url: 'http://getbootstrap.com/',\n npm: 'bootstrap',\n // look for a function Boostrap has added to jQuery - regex for BS 2 & 3\n test: function(win) {\n var jQueryAvailable = win.$ && win.$.fn,\n RE_PREFIX_V2 = '\\\\$this\\\\.data\\\\((?:\\'|\")',\n RE_PREFIX_V3 = '\\\\$this\\\\.data\\\\((?:\\'|\")(?:bs\\\\.){1}',\n bootstrapComponents = [\n 'affix', 'alert', 'button', 'carousel', 'collapse', 'dropdown',\n 'modal', 'popover', 'scrollspy', 'tab', 'tooltip'\n ];\n\n if(jQueryAvailable) {\n var bootstrapVersion;\n\n bootstrapComponents.some(function(component) {\n if(win.$.fn[component]) {\n // Bootstrap >= 3.2.0 detection\n if(win.$.fn[component].Constructor && win.$.fn[component].Constructor.VERSION) {\n bootstrapVersion = win.$.fn[component].Constructor.VERSION;\n return true;\n // Bootstrap >= 2.0.0 and <= 3.1.0 detection\n } else if(new RegExp(RE_PREFIX_V3 + component).test(win.$.fn[component].toString())) {\n bootstrapVersion = '>= 3.0.0 & <= 3.1.1';\n return true;\n // Bootstrap < 3.1.0 detection\n } else if(new RegExp(RE_PREFIX_V2 + component).test(win.$.fn[component].toString())) {\n bootstrapVersion = '>= 2.0.0 & <= 2.3.2';\n return true;\n }\n }\n\n return false;\n });\n\n if (bootstrapVersion) {\n return { version: bootstrapVersion };\n }\n }\n\n return false;\n }\n },\n\n 'Zurb': {\n icon: 'zurb',\n url: 'https://foundation.zurb.com/',\n npm: 'foundation-sites',\n test: function(win) {\n if(win.Foundation && win.Foundation.Toggler) {\n return { version: win.Foundation.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Polymer': {\n icon: 'polymer',\n url: 'https://www.polymer-project.org/',\n npm: '@polymer/polymer',\n test: function(win) {\n if(win.Polymer && win.Polymer.dom) {\n return { version: win.Polymer.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Highcharts': {\n icon: 'highcharts',\n url: 'http://www.highcharts.com',\n npm: 'highcharts',\n test: function(win) {\n if(win.Highcharts && win.Highcharts.Point) {\n return { version: win.Highcharts.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'InfoVis': {\n icon: 'jit',\n url: 'http://philogb.github.com/jit/',\n test: function test(win) {\n if(win.$jit && win.$jit.PieChart) {\n return { version: win.$jit.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'FlotCharts': {\n icon: 'flotcharts',\n url: 'http://www.flotcharts.org/',\n npm: 'flot',\n test: function(win) {\n if(win.$ && win.$.plot) {\n return { version: win.$.plot.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'CreateJS': {\n icon: 'createjs',\n url: 'https://createjs.com/',\n npm: 'createjs',\n test: function(win) {\n if(win.createjs && win.createjs.promote) {\n return { version: UNKNOWN_VERSION}; // no version info available\n }\n return false;\n }\n },\n\n 'Google Maps': {\n icon: 'gmaps',\n url: 'https://developers.google.com/maps/',\n test: function(win) {\n if (win.google && win.google.maps) {\n return { version: win.google.maps.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'jQuery': {\n icon: 'jquery',\n url: 'http://jquery.com',\n npm: 'jquery',\n test: function(win) {\n var jq = win.jQuery || win.$;\n if (jq && jq.fn) {\n return { version: jq.fn.jquery.replace(/[^\\d+\\.+]/g, '') || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'jQuery UI': {\n icon: 'jquery_ui',\n url: 'http://jqueryui.com',\n npm: 'jquery-ui',\n test: function(win) {\n var jq = win.jQuery || win.$ || win.$jq || win.$j;\n if(jq && jq.fn && jq.fn.jquery && jq.ui) {\n var plugins = 'accordion,datepicker,dialog,draggable,droppable,progressbar,resizable,selectable,slider,menu,grid,tabs'.split(','), concat = [];\n for (var i=0; i < plugins.length; i++) { if(jq.ui[plugins[i]]) concat.push(plugins[i].substr(0,1).toUpperCase() + plugins[i].substr(1)); }\n return { version: jq.ui.version || UNKNOWN_VERSION, details: concat.length ? 'Plugins used: '+concat.join(',') : '' };\n }\n return false;\n }\n },\n\n 'Dojo': {\n icon: 'dojo',\n url: 'http://dojotoolkit.org',\n npm: 'dojo',\n test: function(win) {\n if(win.dojo && win.dojo.delegate) {\n var version = win.dojo.version ? win.dojo.version.toString() : UNKNOWN_VERSION;\n return { version: version, details: 'Details: '+(win.dijit ? 'Uses Dijit' : 'none') };\n }\n return false;\n }\n },\n\n 'Prototype': {\n icon: 'prototype',\n url: 'http://prototypejs.org',\n test: function(win) {\n if(win.Prototype && win.Prototype.BrowserFeatures) {\n return { version: win.Prototype.Version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Scriptaculous': {\n icon: 'scriptaculous',\n url: 'http://script.aculo.us',\n test: function(win) {\n if(win.Scriptaculous && win.Scriptaculous.load) {\n return { version: win.Scriptaculous.Version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'MooTools': {\n icon: 'mootools',\n url: 'https://mootools.net/',\n test: function(win) {\n if(win.MooTools && win.MooTools.build) {\n return { version: win.MooTools.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Spry': {\n icon: 'spry',\n url: 'http://labs.adobe.com/technologies/spry',\n test: function(win) {\n if (win.Spry && win.Spry.Data) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'YUI 2': {\n icon: 'yui',\n url: 'http://developer.yahoo.com/yui/2/',\n test: function(win) {\n if (win.YAHOO && win.YAHOO.util) {\n return { version: win.YAHOO.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'YUI 3': {\n icon: 'yui3',\n url: 'https://yuilibrary.com/',\n npm: 'yui',\n test: function(win) {\n if (win.YUI && win.YUI.Env) {\n return { version: win.YUI.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Qooxdoo': {\n icon: 'qooxdoo',\n url: 'http://www.qooxdoo.org/',\n npm: 'qooxdoo',\n test: function(win) {\n if(win.qx && win.qx.Bootstrap) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Ext JS': {\n icon: 'extjs',\n url: 'https://www.sencha.com/products/extjs/',\n test: function(win) {\n if (win.Ext && win.Ext.versions) {\n return { version: win.Ext.versions.core.version };\n }\n else if(win.Ext) {\n return { version: win.Ext.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'base2': {\n icon: 'base2',\n url: 'http://code.google.com/p/base2',\n test: function(win) {\n if(win.base2 && win.base2.dom) {\n return { version: win.base2.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Closure Library': {\n icon: 'closure',\n url: 'https://developers.google.com/closure/library/',\n npm: 'google-closure-library',\n test: function(win) {\n if(win.goog && win.goog.provide) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Rapha&euml;l': {\n icon: 'raphael',\n url: 'http://dmitrybaranovskiy.github.io/raphael/',\n test: function(win) {\n if (win.Raphael && win.Raphael.circle) {\n return { version: win.Raphael.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'React': {\n icon: 'react',\n url: 'https://reactjs.org/',\n npm: 'react',\n test: function(win) {\n function isReactNode(node) {\n return node._reactRootContainer!=null;\n }\n var reactRoot = document.getElementById('react-root');\n var altHasReact = document.querySelector('*[data-reactroot]');\n var bodyReactRoot = isReactNode(document.body) || isReactNode(document.body.firstElementChild || {});\n var hasReactRoot = bodyReactRoot|| document.createTreeWalker(document.body, 3, isReactNode).nextNode() != null;\n if (hasReactRoot || reactRoot && reactRoot.innerText.length > 0 || altHasReact || win.React && win.React.Component) {\n return { version: win.React && win.React.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Preact': {\n icon: 'preact',\n url: 'https://preactjs.com/',\n npm: 'preact',\n test: function(win) {\n var expando = typeof Symbol!='undefined' && Symbol.for && Symbol.for('preactattr');\n function isPreactNode(node) {\n if (node._component!=null || node.__preactattr_!=null || expando && node[expando]!=null) {\n return node;\n }\n return null;\n }\n var preactRoot = isPreactNode(document.body) || isPreactNode(document.body.firstElementChild || {});\n if (!preactRoot) {\n preactRoot = document.createTreeWalker(document.body, 3, isPreactNode).nextNode();\n }\n if (preactRoot || win.preact) {\n var version = UNKNOWN_VERSION;\n if (expando && preactRoot && preactRoot[expando]!=null) {\n version = '7';\n }\n return { version: version };\n }\n return false;\n }\n },\n\n 'Modernizr': {\n icon: 'modernizr',\n url: 'https://modernizr.com/',\n npm: 'modernizr',\n test: function(win) {\n if (win.Modernizr && win.Modernizr.addTest) {\n return { version: win.Modernizr._version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Processing.js': {\n icon: 'processingjs',\n url: 'http://processingjs.org',\n npm: 'processing-js',\n test: function(win) {\n if(win.Processing && win.Processing.box) {\n return { version: Processing.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Backbone': {\n icon: 'backbone',\n url: 'http://backbonejs.org/',\n npm: 'backbone',\n test: function(win) {\n if (win.Backbone && win.Backbone.Model.extend) {\n return {version: win.Backbone.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Leaflet': {\n icon: 'leaflet',\n url: 'http://leafletjs.com',\n npm: 'leaflet',\n test: function(win) {\n // Leaflet 3.1 uses L.Marker and L.VERSION; later versions use L.marker and L.version\n if (win.L && win.L.GeoJSON && (win.L.marker || win.L.Marker)) {\n return { version: win.L.version || win.L.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Mapbox': {\n icon: 'mapbox',\n url: 'https://www.mapbox.com/',\n npm: 'mapbox-gl',\n test: function(win) {\n if (win.L && win.L.mapbox && win.L.mapbox.geocoder) {\n return { version: win.L.mapbox.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Lo-Dash': {\n icon: 'lodash',\n url: 'https://lodash.com/',\n npm: 'lodash',\n test: function(win) {\n var _ = typeof (_ = win._) == 'function' && _,\n chain = typeof (chain = _ && _.chain) == 'function' && chain,\n wrapper = (chain || _ || function() { return {}; })(1);\n\n if (_ && wrapper.__wrapped__) {\n return { version: _.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Underscore': {\n icon: 'underscore',\n url: 'http://underscorejs.org/',\n npm: 'underscore',\n test: function(win) {\n if (win._ && typeof win._.tap === 'function' &&\n !d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests['Lo-Dash'].test(win)) {\n return {version: win._.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Sammy': {\n icon: 'sammy',\n url: 'http://sammyjs.org',\n test: function(win) {\n if (win.Sammy && win.Sammy.Application.curry) {\n return {version: win.Sammy.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Rico': {\n icon: 'rico',\n url: 'http://openrico.sourceforge.net/examples/index.html',\n test: function(win) {\n if (win.Rico && window.Rico.checkIfComplete) {\n return {version: win.Rico.Version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'MochiKit': {\n icon: 'mochikit',\n url: 'https://mochi.github.io/mochikit/',\n test: function(win) {\n if (win.MochiKit && win.MochiKit.Base.module) {\n return {version: MochiKit.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'gRapha&euml;l': {\n icon: 'graphael',\n url: 'https://github.com/DmitryBaranovskiy/g.raphael',\n test: function(win) {\n if (win.Raphael && win.Raphael.fn.g) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Glow': {\n icon: 'glow',\n url: 'http://www.bbc.co.uk/glow/',\n test: function(win) {\n if (win.gloader && win.gloader.getRequests) {\n return {version: UNKNOWN_VERSION};\n }\n else if (win.glow && win.glow.dom) {\n return {version: win.glow.VERSION || UNKNOWN_VERSION};\n }\n else if (win.Glow) {\n return {version: win.Glow.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Socket.IO': {\n icon: 'socketio', // currently has no icon\n url: 'https://socket.io/',\n npm: 'socket.io',\n test: function(win) {\n // version 0.6.2 uses only io.Socket; more recent versions also have io.sockets\n if (win.io && (win.io.sockets || win.io.Socket)) {\n return {version: win.io.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Mustache': {\n icon: 'mustache',\n url: 'http://mustache.github.io/',\n npm: 'mustache',\n test: function(win) {\n if (win.Mustache && win.Mustache.to_html) {\n return {version: win.Mustache.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Fabric.js': {\n icon: 'icon38', // currently has no icon\n url: 'http://fabricjs.com/',\n npm: 'fabric',\n test: function(win) {\n if (win.fabric && win.fabric.util) {\n return {version: win.fabric.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'FuseJS': {\n icon: 'fusejs',\n url: 'http://fusejs.io/',\n npm: 'fuse.js',\n test: function(win) {\n if (win.Fuse) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Tween.js': {\n icon: 'icon38', // currently has no icon\n url: 'https://github.com/tweenjs/tween.js',\n npm: 'tween.js',\n test: function(win) {\n if (win.TWEEN && win.TWEEN.Easing) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'SproutCore': {\n icon: 'sproutcore',\n url: 'http://sproutcore.com/',\n test: function(win) {\n if (win.SC && win.SC.Application) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Zepto.js': {\n icon: 'zepto',\n url: 'http://zeptojs.com',\n npm: 'zepto',\n test: function(win) {\n if (win.Zepto && win.Zepto.fn) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'three.js': {\n icon: 'icon38', // currently has no icon\n url: 'https://threejs.org/',\n npm: 'three',\n test: function(win) {\n if (win.THREE && win.THREE.REVISION) {\n return {version: 'r' + win.THREE.REVISION};\n }\n else if (win.THREE) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'PhiloGL': {\n icon: 'philogl',\n url: 'http://www.senchalabs.org/philogl/',\n npm: 'philogl',\n test: function(win) {\n if (win.PhiloGL && win.PhiloGL.Camera) {\n return {version: win.PhiloGL.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'CamanJS': {\n icon: 'camanjs',\n url: 'http://camanjs.com/',\n npm: 'caman',\n test: function(win) {\n if (win.Caman && win.Caman.version) {\n return {version: win.Caman.version.release};\n }\n else if (win.Caman) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'yepnope': {\n icon: 'yepnope',\n url: 'http://yepnopejs.com/',\n test: function(win) {\n if (win.yepnope && win.yepnope.injectJs) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'LABjs': {\n icon: 'icon38',\n url: 'https://github.com/getify/LABjs',\n test: function(win) {\n if (win.$LAB && win.$LAB.setOptions) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Head JS': {\n icon: 'headjs',\n url: 'http://headjs.com/',\n npm: 'headjs',\n test: function(win) {\n if (win.head && win.head.js) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'ControlJS': {\n icon: 'icon38',\n url: 'http://stevesouders.com/controljs/',\n test: function(win) {\n if (win.CJS && win.CJS.start) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'RequireJS': {\n icon: 'requirejs',\n url: 'http://requirejs.org/',\n npm: 'requirejs',\n test: function(win) {\n var req = win.require || win.requirejs;\n if (req && (req.load || (req.s && req.s.contexts && req.s.contexts._ && (req.s.contexts._.loaded || req.s.contexts._.load)))) {\n return { version: req.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'RightJS': {\n icon: 'rightjs',\n url: 'http://rightjs.org/',\n test: function(win) {\n if (win.RightJS && win.RightJS.isNode) {\n return { version: win.RightJS.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'jQuery Tools': {\n icon: 'jquerytools',\n url: 'http://jquerytools.github.io/',\n test: function(win) {\n var jq = win.jQuery || win.$;\n if(jq && jq.tools) {\n return { version: jq.tools.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Pusher': {\n icon: 'pusher',\n url: 'https://pusher.com/docs/',\n npm: 'pusher-js',\n test: function(win) {\n if(win.Pusher && win.Pusher.Channel) {\n return { version: win.Pusher.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Paper.js': {\n icon: 'paperjs',\n url: 'http://paperjs.org/',\n npm: 'paper',\n test: function(win) {\n if(win.paper && win.paper.Point) {\n return { version: win.paper.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Swiffy': {\n icon: 'icon38',\n url: 'https://developers.google.com/swiffy/',\n test: function(win) {\n if(win.swiffy && win.swiffy.Stage) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Move': {\n icon: 'move',\n url: 'https://github.com/rsms/move',\n npm: 'move',\n test: function(win) {\n if(win.move && win.move.compile) {\n return { version: win.move.version() || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'AmplifyJS': {\n icon: 'amplifyjs',\n url: 'http://amplifyjs.com/',\n npm: 'amplifyjs',\n test: function(win) {\n if(win.amplify && win.amplify.publish) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Popcorn.js': {\n icon: 'popcornjs',\n url: 'https://github.com/mozilla/popcorn-js/',\n test: function(win) {\n if (win.Popcorn && win.Popcorn.Events) {\n return { version: win.Popcorn.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'D3': {\n icon: 'd3',\n url: 'https://d3js.org/',\n npm: 'd3',\n test: function(win) {\n if (win.d3 && win.d3.select) {\n return { version: win.d3.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Handlebars': {\n icon: 'handlebars',\n url: 'http://handlebarsjs.com/',\n npm: 'handlebars',\n test: function(win) {\n if(win.Handlebars && win.Handlebars.compile) {\n return { version: win.Handlebars.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Knockout': {\n icon: 'knockout',\n url: 'http://knockoutjs.com/',\n npm: 'knockout',\n test: function(win) {\n if (win.ko && win.ko.applyBindings) {\n return { version: win.ko.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Spine': {\n icon: 'icon38',\n url: 'http://spine.github.io/',\n test: function(win) {\n if (win.Spine && win.Spine.Controller) {\n return {version: win.Spine.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'jQuery Mobile': {\n icon: 'jquery_mobile',\n url: 'http://jquerymobile.com/',\n npm: 'jquery-mobile',\n test: function(win) {\n var jq = win.jQuery || win.$ || win.$jq || win.$j;\n if(jq && jq.fn && jq.fn.jquery && jq.mobile) {\n return { version: jq.mobile.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'WebFont Loader': {\n icon: 'icon38',\n url: 'https://github.com/typekit/webfontloader',\n npm: 'webfontloader',\n test: function(win) {\n if(win.WebFont && win.WebFont.load) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Angular': {\n icon: 'angular',\n url: 'https://angular.io/',\n npm: '@angular/core',\n test: function(win) {\n var ng = win.document.querySelector('[ng-version]');\n if (ng) {\n return { version: ng.getAttribute('ng-version') || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'AngularJS': {\n icon: 'angularjs',\n url: 'https://angularjs.org/',\n npm: 'angular',\n test: function(win) {\n var ng = win.angular;\n if(ng && ng.version && ng.version.full) {\n return { version: ng.version.full };\n }\n else if (ng) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Ember.js': {\n icon: 'emberjs',\n url: 'https://emberjs.com/',\n npm: 'ember-source',\n test: function(win) {\n var ember = win.Ember || win.Em;\n if (ember && ember.propertyDidChange) {\n return { version: ember.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Hammer.js': {\n icon: 'hammerjs',\n url: 'http://eightmedia.github.io/hammer.js/',\n npm: 'hammerjs',\n test: function(win) {\n if(win.Hammer && win.Hammer.Pinch) {\n // Hammer.VERSION available in 1.0.10+\n return { version: win.Hammer.VERSION || \"&lt; 1.0.10\" };\n }\n return false;\n }\n },\n\n 'Visibility.js': {\n icon: 'icon38',\n url: 'https://github.com/ai/visibilityjs',\n npm: 'visibilityjs',\n test: function(win) {\n if(win.Visibility && win.Visibility.every) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Velocity.js': {\n icon: 'icon38',\n url: 'http://velocityjs.org/',\n npm: 'velocity-animate',\n test: function(win) {\n var jq = win.jQuery || win.$,\n velocity = jq ? jq.Velocity : win.Velocity;\n\n if(velocity && velocity.RegisterEffect && velocity.version) {\n return {\n version:\n velocity.version.major + \".\" +\n velocity.version.minor + \".\" +\n velocity.version.patch\n };\n }\n else if (velocity && velocity.RegisterEffect) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'IfVisible.js': {\n icon: 'icon38',\n url: 'http://serkanyersen.github.io/ifvisible.js/',\n npm: 'ifvisible.js',\n test: function(win) {\n var iv = win.ifvisible;\n if(iv && iv.__ceGUID === \"ifvisible.object.event.identifier\") {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Pixi.js': {\n icon: 'pixi',\n url: 'http://www.pixijs.com/',\n npm: 'pixi.js',\n test: function(win) {\n var px = win.PIXI;\n if(px && px.WebGLRenderer && px.VERSION) {\n // version 4.4.3 returns simply \"4.4.3\"; version 1.5.2 returns \"v1.5.2\"\n return { version: px.VERSION.replace('v', '') || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'DC.js': {\n icon: 'dcjs',\n url: 'http://dc-js.github.io/dc.js/',\n npm: 'dc',\n test: function(win) {\n var dc = win.dc;\n if(dc && dc.registerChart) {\n return { version: dc.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'GreenSock JS': {\n icon: 'greensock',\n url: 'https://greensock.com/gsap',\n npm: 'gsap',\n test: function(win) {\n if (win.TweenMax && win.TweenMax.pauseAll) {\n return { version: win.TweenMax.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'FastClick': {\n icon: 'fastclick',\n url: 'https://github.com/ftlabs/fastclick',\n npm: 'fastclick',\n test: function(win) {\n if(win.FastClick && win.FastClick.notNeeded) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Isotope': {\n icon: 'isotope',\n url: 'https://isotope.metafizzy.co/',\n npm: 'isotope-layout',\n test: function(win) {\n if(win.Isotope || (win.$ != null && win.$.Isotope)) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Marionette': {\n icon: 'marionette',\n url: 'https://marionettejs.com/',\n npm: 'backbone.marionette',\n test: function(win) {\n if(win.Marionette && win.Marionette.Application) {\n return { version: win.Marionette.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Can': {\n icon: 'canjs',\n url: 'https://canjs.com/',\n npm: 'can',\n test: function (win) {\n if (win.can && win.can.Construct) {\n return { version: win.can.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Vue': {\n icon: 'vue',\n url: 'https://vuejs.org/',\n npm: 'vue',\n test: function(win) {\n if (win.Vue && win.Vue.nextTick) {\n return { version: win.Vue.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Two': {\n icon: 'two',\n url: 'https://two.js.org/',\n npm: 'two.js',\n test: function(win) {\n if (win.Two && win.Two.Utils) {\n return { version: win.Two.Version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Brewser': {\n icon: 'brewser',\n url: 'https://robertpataki.github.io/brewser/',\n npm: 'brewser',\n test: function(win) {\n if(win.BREWSER && win.BREWSER.ua) {\n return { version: BREWSER.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Material Design Lite': {\n icon: 'mdl',\n url: 'https://getmdl.io/',\n npm: 'material-design-lite',\n test: function(win) {\n if(win.componentHandler && win.componentHandler.upgradeElement) {\n return { version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'Kendo UI': {\n icon: 'kendoui',\n url: 'https://github.com/telerik/kendo-ui-core',\n npm: 'kendo-ui-core',\n test: function(win) {\n if (win.kendo && win.kendo.View && win.kendo.View.extend) {\n return {version: win.kendo.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'Matter.js': {\n icon: 'matter-js',\n url: 'http://brm.io/matter-js/',\n npm: 'matter-js',\n test: function(win) {\n if (win.Matter && win.Matter.Engine) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'Riot': {\n icon: 'riot',\n url: 'http://riotjs.com/',\n npm: 'riot',\n test: function(win) {\n if (win.riot && win.riot.mixin) {\n return { version: win.riot.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Sea.js': {\n icon: 'icon38',\n url: 'https://seajs.github.io/seajs/docs/',\n npm: 'seajs',\n test: function(win) {\n if(win.seajs && win.seajs.use) {\n return { version: win.seajs.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Moment.js': {\n icon: 'momentjs',\n url: 'http://momentjs.com/',\n npm: 'moment',\n test: function(win) {\n if(win.moment && (win.moment.isMoment || win.moment.lang)) {\n // version 1.0.0 has neither \"isMoment\" nor \"version\"\n return { version: win.moment.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Moment Timezone': {\n icon: 'momentjs',\n url: 'http://momentjs.com/timezone/',\n npm: 'moment-timezone',\n test: function(win) {\n if (win.moment && win.moment.tz) {\n return { version: win.moment.tz.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'ScrollMagic': {\n icon: 'scrollmagic',\n url: 'http://scrollmagic.io/',\n npm: 'scrollmagic',\n test: function(win) {\n if (win.ScrollMagic && win.ScrollMagic.Controller) {\n return {version: ScrollMagic.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'SWFObject': {\n icon: 'icon38', // currently has no icon\n url: 'https://github.com/swfobject/swfobject',\n test: function(win) {\n if (win.swfobject && win.swfobject.embedSWF) {\n // 2.x - exact version only for 2.3\n return { version: win.swfobject.version || UNKNOWN_VERSION };\n } else if(win.deconcept && win.deconcept.SWFObject) {\n // 1.x\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'FlexSlider': {\n icon: 'icon38', // currently has no icon\n url: 'https://woocommerce.com/flexslider/',\n npm: 'flexslider',\n test: function(win) {\n var jq = win.jQuery || win.$ || win.$jq || win.$j;\n if (jq && jq.fn && jq.fn.jquery && jq.flexslider){\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'SPF': {\n icon: 'icon38', // currently has no icon\n url: 'https://youtube.github.io/spfjs/',\n npm: 'spf',\n test: function(win) {\n if (win.spf && win.spf.init) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Numeral.js': {\n icon: 'icon38', // currently has no icon\n url: 'http://numeraljs.com/',\n npm: 'numeraljs',\n test: function(win) {\n if (win.numeral && win.isNumeral) {\n return { version: win.numeral.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'boomerang.js': {\n icon: 'icon38', // currently has no icon\n url: 'https://soasta.github.io/boomerang/',\n npm: 'boomerangjs',\n test: function(win) {\n if (win.BOOMR && win.BOOMR.utils && win.BOOMR.init) {\n return { version: win.BOOMR.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Framer': {\n icon: 'framer',\n url: 'https://framer.com/',\n npm: 'framerjs',\n test: function(win) {\n if (win.Framer && win.Framer.Layer) {\n return { version: win.Framer.Version.build || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Marko': {\n icon: 'marko',\n url: 'https://markojs.com/',\n npm: 'marko',\n test: function (win) {\n var selector = '[data-marko-key], [data-marko]';\n var markoElement = document.querySelector(selector);\n if (markoElement) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'AMP': {\n icon: 'amp',\n url: 'https://ampproject.org/',\n npm: null,\n test: function (win) {\n var version = win.document.documentElement.getAttribute(\"amp-version\");\n return version ? { version: version } : false;\n }\n },\n 'Workbox': {\n icon: 'workbox',\n url: 'https://developers.google.com/web/tools/workbox/',\n npm: 'workbox-sw',\n test: async function (win) {\n var nav = win.navigator;\n // Service Workers not supported\n if (!('serviceWorker' in nav)) {\n return false;\n }\n return nav.serviceWorker.getRegistration()\n .then(function(registration) {\n var scriptURL = nav.serviceWorker.controller.scriptURL;\n return fetch(scriptURL, { credentials: 'include',\n headers: { 'service-worker': 'script' }\n })\n .then(function(response) {\n return response.text();\n })\n .then(function(scriptContent) {\n var workboxRegExp = /new Workbox|new workbox|workbox\\.precaching\\.|workbox\\.strategies/gm;\n if (workboxRegExp.test(scriptContent)) {\n // Adapted from\n // https://github.com/semver/semver/issues/232#issue-48635632\n var semVerRegExp = /workbox.*?\\b((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?)\\b/gim;\n var matches = semVerRegExp.exec(scriptContent);\n var version = UNKNOWN_VERSION;\n if (Array.isArray(matches) && matches.length > 1 && matches[1]) {\n version = matches[1];\n }\n return { version: version };\n }\n return false;\n });\n }).catch(function(exception) {\n return false;\n });\n }\n }\n};\n";
-
-
-
-
-
-function detectLibraries(){
-
-const libraries=[];
-
-
-
-
-Object.entries(d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests).forEach(([name,lib])=>{
-try{
-const result=lib.test(window);
-if(result){
-libraries.push({
-name:name,
-version:result.version,
-npmPkgName:lib.npm});
-
-}
-}catch(e){}
-});
-
-return libraries;
-}
-
-class JSLibraries extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const expression=`(function () {
- ${libDetectorSource};
- return (${detectLibraries.toString()}());
- })()`;
-
-return passContext.driver.evaluateAsync(expression);
-}}
-
-
-module.exports=JSLibraries;
-
-},{"../gatherer":21}],"../gather/gatherers/dobetterweb/optimized-images":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const URL=require('../../../lib/url-shim');
-const NetworkRequest=require('../../../lib/network-request');
-const Sentry=require('../../../lib/sentry');
-const Driver=require('../../driver.js');
-
-const JPEG_QUALITY=0.92;
-const WEBP_QUALITY=0.85;
-
-const MINIMUM_IMAGE_SIZE=4096;
-
-const IMAGE_REGEX=/^image\/((x|ms|x-ms)-)?(png|bmp|jpeg)$/;
-
-
-
-
-
-
-
-
-
-
-
-function getOptimizedNumBytes(url){
-return new Promise(function(resolve,reject){
-const img=new Image();
-const canvas=document.createElement('canvas');
-const context=canvas.getContext('2d');
-if(!context){
-return reject(new Error('unable to create canvas context'));
-}
-
-
-
-
-
-
-function getTypeStats(type,quality){
-const dataURI=canvas.toDataURL(type,quality);
-const base64=dataURI.slice(dataURI.indexOf(',')+1);
-return{base64:base64.length,binary:atob(base64).length};
-}
-
-img.addEventListener('error',reject);
-img.addEventListener('load',()=>{
-try{
-canvas.height=img.height;
-canvas.width=img.width;
-context.drawImage(img,0,0);
-
-const jpeg=getTypeStats('image/jpeg',0.92);
-const webp=getTypeStats('image/webp',0.85);
-
-resolve({jpeg,webp});
-}catch(err){
-reject(err);
-}
-},false);
-
-img.src=url;
-});
-}
-
-class OptimizedImages extends Gatherer{
-
-
-
-
-
-static filterImageRequests(pageUrl,networkRecords){
-
-const seenUrls=new Set();
-return networkRecords.reduce((prev,record)=>{
-if(seenUrls.has(record.url)||!record.finished){
-return prev;
-}
-
-seenUrls.add(record.url);
-const isOptimizableImage=record.resourceType===NetworkRequest.TYPES.Image&&
-IMAGE_REGEX.test(record.mimeType);
-const isSameOrigin=URL.originsMatch(pageUrl,record.url);
-const isBase64DataUri=/^data:.{2,40}base64\s*,/.test(record.url);
-
-const actualResourceSize=Math.min(record.resourceSize||0,record.transferSize||0);
-if(isOptimizableImage&&actualResourceSize>MINIMUM_IMAGE_SIZE){
-prev.push({
-isSameOrigin,
-isBase64DataUri,
-requestId:record.requestId,
-url:record.url,
-mimeType:record.mimeType,
-resourceSize:actualResourceSize});
-
-}
-
-return prev;
-},[]);
-}
-
-
-
-
-
-
-
-_getEncodedResponse(driver,requestId,encoding){
-requestId=NetworkRequest.getRequestIdForBackend(requestId);
-
-const quality=encoding==='jpeg'?JPEG_QUALITY:WEBP_QUALITY;
-const params={requestId,encoding,quality,sizeOnly:true};
-return driver.sendCommand('Audits.getEncodedResponse',params);
-}
-
-
-
-
-
-
-calculateImageStats(driver,networkRecord){
-
-
-return Promise.resolve(networkRecord.requestId).then(requestId=>{
-if(this._getEncodedResponseUnsupported)return;
-return this._getEncodedResponse(driver,requestId,'jpeg').then(jpegData=>{
-return this._getEncodedResponse(driver,requestId,'webp').then(webpData=>{
-return{
-fromProtocol:true,
-originalSize:networkRecord.resourceSize,
-jpegSize:jpegData.encodedSize,
-webpSize:webpData.encodedSize};
-
-});
-}).catch(err=>{
-if(/wasn't found/.test(err.message)){
-
-this._getEncodedResponseUnsupported=true;
-}else{
-throw err;
-}
-});
-}).then(result=>{
-if(result)return result;
-
-
-
-if(!networkRecord.isSameOrigin&&!networkRecord.isBase64DataUri)return null;
-
-const script=`(${getOptimizedNumBytes.toString()})(${JSON.stringify(networkRecord.url)})`;
-return driver.evaluateAsync(script).then(stats=>{
-if(!stats)return null;
-const isBase64DataUri=networkRecord.isBase64DataUri;
-const base64Length=networkRecord.url.length-networkRecord.url.indexOf(',')-1;
-return{
-fromProtocol:false,
-originalSize:isBase64DataUri?base64Length:networkRecord.resourceSize,
-jpegSize:isBase64DataUri?stats.jpeg.base64:stats.jpeg.binary,
-webpSize:isBase64DataUri?stats.webp.base64:stats.webp.binary};
-
-});
-});
-}
-
-
-
-
-
-
-async computeOptimizedImages(driver,imageRecords){
-
-const results=[];
-
-for(const record of imageRecords){
-try{
-const stats=await this.calculateImageStats(driver,record);
-if(stats===null){
-continue;
-}
-
-
-const image={failed:false,...stats,...record};
-results.push(image);
-}catch(err){
-
-
-Sentry.captureException(err,{
-tags:{gatherer:'OptimizedImages'},
-extra:{imageUrl:URL.elideDataURI(record.url)},
-level:'warning'});
-
-
-
-const imageError={failed:true,errMsg:err.message,...record};
-results.push(imageError);
-}
-}
-
-return results;
-}
-
-
-
-
-
-
-afterPass(passContext,loadData){
-const networkRecords=loadData.networkRecords;
-const imageRecords=OptimizedImages.filterImageRequests(passContext.url,networkRecords);
-
-return Promise.resolve().
-then(_=>this.computeOptimizedImages(passContext.driver,imageRecords)).
-then(results=>{
-const successfulResults=results.filter(result=>!result.failed);
-if(results.length&&!successfulResults.length){
-throw new Error('All image optimizations failed');
-}
-
-return results;
-});
-}}
-
-
-module.exports=OptimizedImages;
-
-},{"../../../lib/network-request":88,"../../../lib/sentry":90,"../../../lib/url-shim":"url","../../driver.js":19,"../gatherer":21}],"../gather/gatherers/dobetterweb/password-inputs-with-prevented-paste":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-const Gatherer=require('../gatherer');
-const pageFunctions=require('../../../lib/page-functions');
-
-
-
-
-
-
-function findPasswordInputsWithPreventedPaste(){
-return Array.from(document.querySelectorAll('input[type="password"]')).
-filter(passwordInput=>
-!passwordInput.dispatchEvent(
-new ClipboardEvent('paste',{cancelable:true}))).
-
-
-map(passwordInput=>({
-
-snippet:getOuterHTMLSnippet(passwordInput)}));
-
-}
-
-class PasswordInputsWithPreventedPaste extends Gatherer{
-
-
-
-
-afterPass(passContext){
-return passContext.driver.evaluateAsync(`(() => {
- ${pageFunctions.getOuterHTMLSnippetString};
- return (${findPasswordInputsWithPreventedPaste.toString()}());
- })()`);
-}}
-
-
-
-module.exports=PasswordInputsWithPreventedPaste;
-
-},{"../../../lib/page-functions":89,"../gatherer":21}],"../gather/gatherers/dobetterweb/response-compression":[function(require,module,exports){
-(function(Buffer){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const URL=require('../../../lib/url-shim');
-const Sentry=require('../../../lib/sentry');
-const NetworkRequest=require('../../../lib/network-request');
-const gzip=require('zlib').gzip;
-
-const CHROME_EXTENSION_PROTOCOL='chrome-extension:';
-const compressionHeaders=['content-encoding','x-original-content-encoding'];
-const compressionTypes=['gzip','br','deflate'];
-const binaryMimeTypes=['image','audio','video'];
-
-const textResourceTypes=[
-NetworkRequest.TYPES.Document,
-NetworkRequest.TYPES.Script,
-NetworkRequest.TYPES.Stylesheet,
-NetworkRequest.TYPES.XHR,
-NetworkRequest.TYPES.Fetch,
-NetworkRequest.TYPES.EventSource];
-
-
-class ResponseCompression extends Gatherer{
-
-
-
-
-static filterUnoptimizedResponses(networkRecords){
-
-const unoptimizedResponses=[];
-
-networkRecords.forEach(record=>{
-const mimeType=record.mimeType;
-const resourceType=record.resourceType||NetworkRequest.TYPES.Other;
-const resourceSize=record.resourceSize;
-
-const isBinaryResource=mimeType&&binaryMimeTypes.some(type=>mimeType.startsWith(type));
-const isTextResource=!isBinaryResource&&textResourceTypes.includes(resourceType);
-const isChromeExtensionResource=record.url.startsWith(CHROME_EXTENSION_PROTOCOL);
-
-if(!isTextResource||!resourceSize||!record.finished||
-isChromeExtensionResource||!record.transferSize||record.statusCode===304){
-return;
-}
-
-const isContentEncoded=(record.responseHeaders||[]).find(header=>
-compressionHeaders.includes(header.name.toLowerCase())&&
-compressionTypes.includes(header.value));
-
-
-if(!isContentEncoded){
-unoptimizedResponses.push({
-requestId:record.requestId,
-url:record.url,
-mimeType:mimeType,
-transferSize:record.transferSize,
-resourceSize:resourceSize,
-gzipSize:0});
-
-}
-});
-
-return unoptimizedResponses;
-}
-
-
-
-
-
-
-afterPass(passContext,loadData){
-const networkRecords=loadData.networkRecords;
-const textRecords=ResponseCompression.filterUnoptimizedResponses(networkRecords);
-
-const driver=passContext.driver;
-return Promise.all(textRecords.map(record=>{
-return driver.getRequestContent(record.requestId).then(content=>{
-
-if(!content){
-return record;
-}
-
-return new Promise((resolve,reject)=>{
-return gzip(content,(err,res)=>{
-if(err){
-return reject(err);
-}
-
-
-record.gzipSize=Buffer.byteLength(res,'utf8');
-
-resolve(record);
-});
-});
-}).catch(err=>{
-Sentry.captureException(err,{
-tags:{gatherer:'ResponseCompression'},
-extra:{url:URL.elideDataURI(record.url)},
-level:'warning'});
-
-
-record.gzipSize=undefined;
-return record;
-});
-}));
-}}
-
-
-module.exports=ResponseCompression;
-
-}).call(this,require("buffer").Buffer);
-},{"../../../lib/network-request":88,"../../../lib/sentry":90,"../../../lib/url-shim":"url","../gatherer":21,"buffer":109,"zlib":106}],"../gather/gatherers/dobetterweb/tags-blocking-first-paint":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const Driver=require('../../driver.js');
-
-
-
-
-function installMediaListener(){
-window.___linkMediaChanges=[];
-Object.defineProperty(HTMLLinkElement.prototype,'media',{
-set:function(val){
-window.___linkMediaChanges.push({
-href:this.href,
-media:val,
-msSinceHTMLEnd:Date.now()-window.performance.timing.responseEnd,
-matches:window.matchMedia(val).matches});
-
-
-return this.setAttribute('media',val);
-}});
-
-}
-
-
-
-
-
-function collectTagsThatBlockFirstPaint(){
-return new Promise((resolve,reject)=>{
-try{
-const tagList=[...document.querySelectorAll('link, head script[src]')].
-filter(tag=>{
-if(tag.tagName==='SCRIPT'){
-const scriptTag=tag;
-return(
-!scriptTag.hasAttribute('async')&&
-!scriptTag.hasAttribute('defer')&&
-!/^data:/.test(scriptTag.src)&&
-scriptTag.getAttribute('type')!=='module');
-
-}else if(tag.tagName==='LINK'){
-
-
-
-const linkTag=tag;
-const blockingStylesheet=linkTag.rel==='stylesheet'&&
-window.matchMedia(linkTag.media).matches&&!linkTag.disabled;
-const blockingImport=linkTag.rel==='import'&&!linkTag.hasAttribute('async');
-return blockingStylesheet||blockingImport;
-}
-
-return false;
-}).
-map(tag=>{
-return{
-tagName:tag.tagName,
-url:tag.tagName==='LINK'?tag.href:tag.src,
-src:tag.src,
-href:tag.href,
-rel:tag.rel,
-media:tag.media,
-disabled:tag.disabled,
-mediaChanges:window.___linkMediaChanges.filter(item=>item.href===tag.href)};
-
-});
-resolve(tagList);
-}catch(e){
-const friendly='Unable to gather Scripts/Stylesheets/HTML Imports on the page';
-reject(new Error(`${friendly}: ${e.message}`));
-}
-});
-}
-
-class TagsBlockingFirstPaint extends Gatherer{
-
-
-
-static _filteredAndIndexedByUrl(networkRecords){
-
-const result={};
-
-return networkRecords.reduce((prev,record)=>{
-if(!record.finished){
-return prev;
-}
-
-const isParserGenerated=record.initiator.type==='parser';
-
-
-const isParserScriptOrStyle=/(css|script)/.test(record.mimeType)&&isParserGenerated;
-const isFailedRequest=record._failed;
-const isHtml=record.mimeType&&record.mimeType.includes('html');
-
-
-
-if(isHtml||isParserScriptOrStyle||isFailedRequest&&isParserGenerated){
-prev[record.url]={
-isLinkPreload:!!record.isLinkPreload,
-transferSize:record.transferSize,
-startTime:record.startTime,
-endTime:record.endTime};
-
-}
-
-return prev;
-},result);
-}
-
-
-
-
-
-static findBlockingTags(driver,networkRecords){
-const scriptSrc=`(${collectTagsThatBlockFirstPaint.toString()}())`;
-const firstRequestEndTime=networkRecords.reduce(
-(min,record)=>Math.min(min,record.endTime),
-Infinity);
-
-return driver.evaluateAsync(scriptSrc).then(tags=>{
-const requests=TagsBlockingFirstPaint._filteredAndIndexedByUrl(networkRecords);
-
-return tags.reduce((prev,tag)=>{
-const request=requests[tag.url];
-if(request&&!request.isLinkPreload){
-
-
-
-const timesResourceBecameNonBlocking=(tag.mediaChanges||[]).
-filter(change=>!change.matches).
-map(change=>change.msSinceHTMLEnd);
-const earliestNonBlockingTime=Math.min(...timesResourceBecameNonBlocking);
-const lastTimeResourceWasBlocking=Math.max(
-request.startTime,
-firstRequestEndTime+earliestNonBlockingTime/1000);
-
-
-prev.push({
-tag,
-transferSize:request.transferSize||0,
-startTime:request.startTime,
-endTime:Math.min(request.endTime,lastTimeResourceWasBlocking)});
-
-
-
-requests[tag.url]=null;
-}
-
-return prev;
-},[]);
-});
-}
-
-
-
-
-beforePass(passContext){
-return passContext.driver.evaluateScriptOnNewDocument(`(${installMediaListener.toString()})()`);
-}
-
-
-
-
-
-
-afterPass(passContext,loadData){
-return TagsBlockingFirstPaint.findBlockingTags(passContext.driver,loadData.networkRecords);
-}}
-
-
-module.exports=TagsBlockingFirstPaint;
-
-},{"../../driver.js":19,"../gatherer":21}],"../gather/gatherers/dobetterweb/websql":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const Driver=require('../../driver.js');
-
-const MAX_WAIT_TIMEOUT=500;
-
-class WebSQL extends Gatherer{
-
-
-
-
-listenForDatabaseEvents(driver){
-
-let timeout;
-
-return new Promise((resolve,reject)=>{
-driver.once('Database.addDatabase',db=>{
-clearTimeout(timeout);
-driver.sendCommand('Database.disable').then(_=>resolve(db),reject);
-});
-
-driver.sendCommand('Database.enable').catch(reject);
-
-
-
-
-timeout=setTimeout(function(){
-resolve(null);
-},MAX_WAIT_TIMEOUT);
-});
-}
-
-
-
-
-
-
-afterPass(passContext){
-return this.listenForDatabaseEvents(passContext.driver).
-then(result=>{
-return result&&result.database;
-});
-}}
-
-
-module.exports=WebSQL;
-
-},{"../../driver.js":19,"../gatherer":21}],"../gather/gatherers/fonts":[function(require,module,exports){
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const Sentry=require('../../lib/sentry');
-
-
-
-
-
-
-
-const fontFaceDescriptors=[
-'display',
-'family',
-'featureSettings',
-'stretch',
-'style',
-'unicodeRange',
-'variant',
-'weight'];
-
-
-
-
-
-
-
-
-
-function getAllLoadedFonts(descriptors){
-
-const getFont=fontFace=>{
-
-const fontRule={
-src:[]};
-
-descriptors.forEach(descriptor=>{
-fontRule[descriptor]=fontFace[descriptor];
-});
-
-return fontRule;
-};
-
-return document.fonts.ready.then(()=>{
-return Array.from(document.fonts).filter(fontFace=>fontFace.status==='loaded').
-map(getFont);
-});
-}
-
-
-
-
-
-
-function getFontFaceFromStylesheets(){
-
-
-
-
-
-function getSheetsFontFaces(stylesheet){
-const fontUrlRegex='url\\((?:")([^"]+)(?:"|\')\\)';
-const fontFaceRules=[];
-
-if(stylesheet.cssRules){
-for(const rule of Array.from(stylesheet.cssRules)){
-if(rule instanceof CSSFontFaceRule){
-const fontsObject={
-
-
-display:rule.style.fontDisplay||'auto',
-family:rule.style.fontFamily?rule.style.fontFamily.replace(/"|'/g,''):'',
-stretch:rule.style.fontStretch||'normal',
-style:rule.style.fontStyle||'normal',
-weight:rule.style.fontWeight||'normal',
-variant:rule.style.fontVariant||'normal',
-
-unicodeRange:rule.style.unicodeRange||'U+0-10FFFF',
-
-featureSettings:rule.style.featureSettings||'normal',
-
-src:[]};
-
-
-
-
-const src=rule.style.src;
-if(src){
-const matches=src.match(new RegExp(fontUrlRegex,'g'));
-if(matches){
-matches.forEach(match=>{
-const res=new RegExp(fontUrlRegex).exec(match);
-if(res){
-fontsObject.src.push(new URL(res[1],location.href).href);
-}
-});
-}
-}
-
-fontFaceRules.push(fontsObject);
-}
-}
-}
-
-return fontFaceRules;
-}
-
-
-
-
-
-
-
-function loadStylesheetWithCORS(oldNode){
-const newNode=oldNode.cloneNode(true);
-
-return new Promise(resolve=>{
-newNode.addEventListener('load',function onload(){
-newNode.removeEventListener('load',onload);
-try{
-const stylesheet=Array.from(document.styleSheets).find(s=>s.ownerNode===newNode);
-if(stylesheet){
-const cssStylesheet=stylesheet;
-resolve(getSheetsFontFaces(cssStylesheet));
-}else{
-resolve([{err:{message:'Could not load stylesheet with CORS'}}]);
-}
-}catch(err){
-resolve([{err:{message:err.message,stack:err.stack}}]);
-}
-});
-newNode.crossOrigin='anonymous';
-oldNode.parentNode&&oldNode.parentNode.insertBefore(newNode,oldNode);
-oldNode.remove();
-
-
-setTimeout(()=>resolve([{err:{message:'Could not load stylesheet (timeout)'}}]),5000);
-});
-}
-
-
-const data=[];
-
-const corsDataPromises=[];
-
-for(const stylesheet of Array.from(document.styleSheets)){
-const cssStylesheet=stylesheet;
-
-try{
-
-if(!cssStylesheet.cssRules){
-throw new Error('Failed to read cssRules');
-}
-
-data.push(...getSheetsFontFaces(cssStylesheet));
-}catch(err){
-const failedToReadRules=/Failed to read.*cssRules/.test(err.message);
-
-const alreadyCORS=!cssStylesheet.ownerNode||!!cssStylesheet.ownerNode.crossOrigin;
-
-if(failedToReadRules&&!alreadyCORS&&cssStylesheet.href){
-
-const ownerLinkEl=cssStylesheet.ownerNode;
-corsDataPromises.push(loadStylesheetWithCORS(ownerLinkEl));
-}else{
-
-data.push({err:{message:err.message,stack:err.stack}});
-}
-}
-}
-
-return Promise.all(corsDataPromises).then(corsFontFaces=>data.concat(...corsFontFaces));
-}
-
-
-class Fonts extends Gatherer{
-
-
-
-
-
-_findSameFontFamily(fontFace,fontFacesList){
-return fontFacesList.find(fontItem=>{
-return!fontFaceDescriptors.find(descriptor=>{
-return fontFace[descriptor]!==fontItem[descriptor];
-});
-});
-}
-
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-const args=JSON.stringify(fontFaceDescriptors);
-
-const fontData=Promise.all(
-[
-driver.evaluateAsync(`(${getAllLoadedFonts.toString()})(${args})`),
-driver.evaluateAsync(`(${getFontFaceFromStylesheets.toString()})()`)]);
-
-
-return fontData.then(([loadedFonts,fontsAndErrors])=>{
-
-const fontFaces=fontsAndErrors.filter(
-fontOrError=>!('err'in fontOrError));
-
-const firstFontError=fontsAndErrors.find(fontOrError=>'err'in fontOrError);
-if(firstFontError){
-
-const dataError=firstFontError;
-if(dataError.err){
-const err=new Error(dataError.err.message);
-err.stack=dataError.err.stack||err.stack;
-Sentry.captureException(err,{tags:{gatherer:'Fonts'},level:'warning'});
-}
-}
-
-return loadedFonts.map(loadedFont=>{
-const fontFaceItem=this._findSameFontFamily(loadedFont,fontFaces);
-loadedFont.src=fontFaceItem&&fontFaceItem.src||[];
-
-return loadedFont;
-});
-});
-}}
-
-
-module.exports=Fonts;
-
-},{"../../lib/sentry":90,"./gatherer":21}],"../gather/gatherers/html-without-javascript":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-
-
-
-
-
-
-
-
-function getBodyText(){
-
-const body=document.querySelector('body');
-return Promise.resolve({
-bodyText:body?body.innerText:'',
-hasNoScript:!!document.querySelector('noscript')});
-
-}
-
-class HTMLWithoutJavaScript extends Gatherer{
-
-
-
-beforePass(passContext){
-passContext.disableJavaScript=true;
-}
-
-
-
-
-
-async afterPass(passContext){
-
-passContext.disableJavaScript=false;
-
-const expression=`(${getBodyText.toString()}())`;
-const{bodyText,hasNoScript}=await passContext.driver.evaluateAsync(expression);
-if(typeof bodyText!=='string'){
-throw new Error('document body innerText returned by protocol was not a string');
-}
-
-return{
-bodyText,
-hasNoScript};
-
-}}
-
-
-module.exports=HTMLWithoutJavaScript;
-
-},{"./gatherer":21}],"../gather/gatherers/http-redirect":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-
-
-
-
-
-class HTTPRedirect extends Gatherer{
-constructor(){
-super();
-this._preRedirectURL='';
-}
-
-
-
-
-beforePass(passContext){
-this._preRedirectURL=passContext.url;
-passContext.url=this._preRedirectURL.replace(/^https/,'http');
-}
-
-
-
-
-
-async afterPass(passContext){
-
-passContext.url=this._preRedirectURL;
-
-const expression=`new URL(window.location).protocol === 'https:'`;
-const isHttps=await passContext.driver.evaluateAsync(expression,{useIsolation:true});
-return{
-value:isHttps};
-
-}}
-
-
-module.exports=HTTPRedirect;
-
-},{"./gatherer":21}],"../gather/gatherers/image-usage":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const pageFunctions=require('../../lib/page-functions.js');
-const Driver=require('../driver.js');
-
-
-
-
-
-function collectImageElementInfo(){
-
-function getClientRect(element){
-const clientRect=element.getBoundingClientRect();
-return{
-
-top:clientRect.top,
-bottom:clientRect.bottom,
-left:clientRect.left,
-right:clientRect.right};
-
-}
-
-
-
-const allElements=getElementsInDocument();
-const allImageElements=allElements.filter(element=>{
-return element.localName==='img';
-});
-
-
-const htmlImages=allImageElements.map(element=>{
-const computedStyle=window.getComputedStyle(element);
-return{
-
-
-src:element.currentSrc,
-width:element.width,
-height:element.height,
-clientWidth:element.clientWidth,
-clientHeight:element.clientHeight,
-clientRect:getClientRect(element),
-naturalWidth:element.naturalWidth,
-naturalHeight:element.naturalHeight,
-isCss:false,
-isPicture:!!element.parentElement&&element.parentElement.tagName==='PICTURE',
-usesObjectFit:computedStyle.getPropertyValue('object-fit')==='cover'||
-computedStyle.getPropertyValue('object-fit')==='contain'};
-
-});
-
-
-
-const CSS_URL_REGEX=/^url\("([^"]+)"\)$/;
-
-const CSS_SIZE_REGEX=/(auto|contain|cover)/;
-
-const cssImages=allElements.reduce((images,element)=>{
-const style=window.getComputedStyle(element);
-if(!style.backgroundImage||!CSS_URL_REGEX.test(style.backgroundImage)||
-!style.backgroundSize||!CSS_SIZE_REGEX.test(style.backgroundSize)){
-return images;
-}
-
-const imageMatch=style.backgroundImage.match(CSS_URL_REGEX);
-
-const url=imageMatch[1];
-
-
-const differentImages=images.filter(image=>image.src!==url);
-if(images.length-differentImages.length>2){
-return differentImages;
-}
-
-images.push({
-src:url,
-clientWidth:element.clientWidth,
-clientHeight:element.clientHeight,
-clientRect:getClientRect(element),
-
-naturalWidth:Number.MAX_VALUE,
-naturalHeight:Number.MAX_VALUE,
-isCss:true,
-isPicture:false,
-usesObjectFit:false});
-
-
-return images;
-},[]);
-
-return htmlImages.concat(cssImages);
-}
-
-
-
-
-
-
-function determineNaturalSize(url){
-return new Promise((resolve,reject)=>{
-const img=new Image();
-img.addEventListener('error',_=>reject(new Error('determineNaturalSize failed img load')));
-img.addEventListener('load',()=>{
-resolve({
-naturalWidth:img.naturalWidth,
-naturalHeight:img.naturalHeight});
-
-});
-
-img.src=url;
-});
-}
-
-class ImageUsage extends Gatherer{
-
-
-
-
-
-async fetchElementWithSizeInformation(driver,element){
-const url=JSON.stringify(element.src);
-try{
-
-const size=await driver.evaluateAsync(`(${determineNaturalSize.toString()})(${url})`);
-return Object.assign(element,size);
-}catch(_){
-
-return Object.assign(element,{naturalWidth:0,naturalHeight:0});
-}
-}
-
-
-
-
-
-
-async afterPass(passContext,loadData){
-const driver=passContext.driver;
-const indexedNetworkRecords=loadData.networkRecords.reduce((map,record)=>{
-if(/^image/.test(record.mimeType)&&record.finished){
-map[record.url]={
-url:record.url,
-resourceSize:Math.min(record.resourceSize||0,record.transferSize),
-startTime:record.startTime,
-endTime:record.endTime,
-responseReceivedTime:record.responseReceivedTime,
-mimeType:record.mimeType};
-
-}
-
-return map;
-},{});
-
-const expression=`(function() {
- ${pageFunctions.getElementsInDocumentString}; // define function on page
- return (${collectImageElementInfo.toString()})();
- })()`;
-
-
-const elements=await driver.evaluateAsync(expression);
-
-const imageUsage=[];
-for(let element of elements){
-
-element.networkRecord=indexedNetworkRecords[element.src];
-
-
-
-
-if((element.isPicture||element.isCss)&&element.networkRecord){
-element=await this.fetchElementWithSizeInformation(driver,element);
-}
-
-imageUsage.push(element);
-}
-
-return imageUsage;
-}}
-
-
-module.exports=ImageUsage;
-
-},{"../../lib/page-functions.js":89,"../driver.js":19,"./gatherer":21}],"../gather/gatherers/js-usage":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-
-
-
-class JsUsage extends Gatherer{
-
-
-
-async beforePass(passContext){
-await passContext.driver.sendCommand('Profiler.enable');
-await passContext.driver.sendCommand('Profiler.startPreciseCoverage');
-}
-
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-
-const coverageResponse=await driver.sendCommand('Profiler.takePreciseCoverage');
-await driver.sendCommand('Profiler.stopPreciseCoverage');
-await driver.sendCommand('Profiler.disable');
-return coverageResponse.result;
-}}
-
-
-module.exports=JsUsage;
-
-},{"./gatherer":21}],"../gather/gatherers/manifest":[function(require,module,exports){
-(function(Buffer){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const manifestParser=require('../../lib/manifest-parser');
-const BOM_LENGTH=3;
-const BOM_FIRSTCHAR=65279;
-
-
-
-
-
-
-
-class Manifest extends Gatherer{
-
-
-
-
-
-
-
-async afterPass(passContext){
-const manifestPromise=passContext.driver.getAppManifest();
-
-const timeoutPromise=new Promise(resolve=>setTimeout(resolve,3000));
-
-const response=await Promise.race([manifestPromise,timeoutPromise]);
-if(!response){
-return null;
-}
-
-const isBomEncoded=response.data.charCodeAt(0)===BOM_FIRSTCHAR;
-if(isBomEncoded){
-response.data=Buffer.from(response.data).slice(BOM_LENGTH).toString();
-}
-
-return manifestParser(response.data,response.url,passContext.url);
-}}
-
-
-module.exports=Manifest;
-
-}).call(this,require("buffer").Buffer);
-},{"../../lib/manifest-parser":86,"./gatherer":21,"buffer":109}],"../gather/gatherers/mixed-content":[function(require,module,exports){
-(function(Buffer){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const URL=require('../../lib/url-shim');
-
-const Driver=require('../driver.js');
-
-
-
-
-
-
-
-
-
-
-
-
-
-class MixedContent extends Gatherer{
-constructor(){
-super();
-this.ids=new Set();
-this.url=undefined;
-this._onRequestIntercepted=undefined;
-}
-
-
-
-
-
-upgradeURL(url){
-const parsedURL=new URL(url);
-parsedURL.protocol='https:';
-return parsedURL.href;
-}
-
-
-
-
-
-downgradeURL(url){
-const parsedURL=new URL(url);
-parsedURL.protocol='http:';
-return parsedURL.href;
-}
-
-
-
-
-
-_getRequestInterceptor(pageUrl,driver){
-
-const onRequestIntercepted=event=>{
-
-
-
-if(new URL(event.request.url).protocol==='http:'&&
-!URL.equalWithExcludedFragments(event.request.url,pageUrl)&&
-!this.ids.has(event.interceptionId)){
-this.ids.add(event.interceptionId);
-event.request.url=this.upgradeURL(event.request.url);
-driver.sendCommand('Network.continueInterceptedRequest',{
-interceptionId:event.interceptionId,
-rawResponse:Buffer.from(
-`HTTP/1.1 302 Found\r\nLocation: ${event.request.url}\r\n\r\n`,
-'utf8').toString('base64')});
-
-}else{
-driver.sendCommand('Network.continueInterceptedRequest',{
-interceptionId:event.interceptionId});
-
-}
-};
-
-return onRequestIntercepted;
-}
-
-
-
-
-async beforePass(passContext){
-const driver=passContext.driver;
-
-
-
-
-
-passContext.url=this.downgradeURL(passContext.url);
-this.url=passContext.url;
-this._onRequestIntercepted=this._getRequestInterceptor(this.url,driver);
-
-await driver.sendCommand('Network.enable');
-driver.on('Network.requestIntercepted',this._onRequestIntercepted);
-await driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:true});
-await driver.sendCommand('Network.setRequestInterception',{patterns:[{urlPattern:'*'}]});
-}
-
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-await driver.sendCommand('Network.setRequestInterception',{patterns:[]});
-if(this._onRequestIntercepted){
-driver.off('Network.requestIntercepted',this._onRequestIntercepted);
-}
-await driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:false});
-
-return{url:passContext.url};
-}}
-
-
-module.exports=MixedContent;
-
-}).call(this,require("buffer").Buffer);
-},{"../../lib/url-shim":"url","../driver.js":19,"./gatherer":21,"buffer":109}],"../gather/gatherers/offline":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const URL=require('../../lib/url-shim');
-
-class Offline extends Gatherer{
-
-
-
-beforePass(passContext){
-return passContext.driver.goOffline();
-}
-
-
-
-
-
-
-afterPass(passContext,loadData){
-const navigationRecord=loadData.networkRecords.filter(record=>{
-return URL.equalWithExcludedFragments(record.url,passContext.url)&&
-record.fetchedViaServiceWorker;
-}).pop();
-
-return passContext.driver.goOnline(passContext).
-then(_=>navigationRecord?navigationRecord.statusCode:-1);
-}}
-
-
-module.exports=Offline;
-
-},{"../../lib/url-shim":"url","./gatherer":21}],"../gather/gatherers/runtime-exceptions":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-class RuntimeExceptions extends Gatherer{
-constructor(){
-super();
-
-this._exceptions=[];
-this._onRuntimeExceptionThrown=this.onRuntimeExceptionThrown.bind(this);
-}
-
-
-
-
-onRuntimeExceptionThrown(entry){
-this._exceptions.push(entry);
-}
-
-
-
-
-beforePass(passContext){
-const driver=passContext.driver;
-driver.on('Runtime.exceptionThrown',this._onRuntimeExceptionThrown);
-}
-
-
-
-
-
-async afterPass(passContext){
-await passContext.driver.off('Runtime.exceptionThrown',this._onRuntimeExceptionThrown);
-return this._exceptions;
-}}
-
-
-module.exports=RuntimeExceptions;
-
-},{"./gatherer":21}],"../gather/gatherers/scripts":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const NetworkRequest=require('../../lib/network-request');
-
-
-
-
-class Scripts extends Gatherer{
-
-
-
-
-
-async afterPass(passContext,loadData){
-const driver=passContext.driver;
-
-
-const scriptContentMap={};
-const scriptRecords=loadData.networkRecords.
-filter(record=>record.resourceType===NetworkRequest.TYPES.Script);
-
-for(const record of scriptRecords){
-try{
-const content=await driver.getRequestContent(record.requestId);
-if(content){
-scriptContentMap[record.requestId]=content;
-}
-}catch(e){}
-}
-
-return scriptContentMap;
-}}
-
-
-module.exports=Scripts;
-
-},{"../../lib/network-request":88,"./gatherer":21}],"../gather/gatherers/seo/canonical":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-class Canonical extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-
-return driver.querySelectorAll('head link[rel="canonical" i]').
-then(nodes=>Promise.all(nodes.map(node=>node.getAttribute('href'))));
-}}
-
-
-module.exports=Canonical;
-
-
-},{"../gatherer":21}],"../gather/gatherers/seo/crawlable-links":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const pageFunctions=require('../../../lib/page-functions.js');
-
-class CrawlableLinks extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const expression=`(function() {
- ${pageFunctions.getElementsInDocumentString}; // define function on page
- const selector = 'a[href]:not([rel~="nofollow"])';
- const elements = getElementsInDocument(selector);
- return elements
- .map(node => ({
- href: node.href,
- text: node.innerText
- }));
- })()`;
-
-return passContext.driver.evaluateAsync(expression);
-}}
-
-
-module.exports=CrawlableLinks;
-
-
-},{"../../../lib/page-functions.js":89,"../gatherer":21}],"../gather/gatherers/seo/embedded-content":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-const pageFunctions=require('../../../lib/page-functions.js');
-
-class EmbeddedContent extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const expression=`(function() {
- ${pageFunctions.getElementsInDocumentString}; // define function on page
- const selector = 'object, embed, applet';
- const elements = getElementsInDocument(selector);
- return elements
- .map(node => ({
- tagName: node.tagName,
- type: node.getAttribute('type'),
- src: node.getAttribute('src'),
- data: node.getAttribute('data'),
- code: node.getAttribute('code'),
- params: Array.from(node.children)
- .filter(el => el.tagName === 'PARAM')
- .map(el => ({
- name: el.getAttribute('name') || '',
- value: el.getAttribute('value') || '',
- })),
- }));
- })()`;
-
-return passContext.driver.evaluateAsync(expression);
-}}
-
-
-module.exports=EmbeddedContent;
-
-},{"../../../lib/page-functions.js":89,"../gatherer":21}],"../gather/gatherers/seo/font-size":[function(require,module,exports){
-(function(global){
-
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-const CSSMatchedStyles=require('../../../lib/web-inspector').CSSMatchedStyles;
-const Gatherer=require('../gatherer');
-const FONT_SIZE_PROPERTY_NAME='font-size';
-const TEXT_NODE_BLOCK_LIST=new Set(['SCRIPT','STYLE','NOSCRIPT']);
-const MINIMAL_LEGIBLE_FONT_SIZE_PX=12;
-
-const MAX_NODES_VISITED=500;
-const MAX_NODES_ANALYZED=50;
-
-const Driver=require('../../driver.js');
-
-
-
-
-
-function nodeInBody(node){
-if(!node){
-return false;
-}
-if(node.nodeName==='BODY'){
-return true;
-}
-return nodeInBody(node.parentNode);
-}
-
-
-
-
-
-
-
-function getAllNodesFromBody(driver){
-return driver.getNodesInDocument().
-then(nodes=>{
-const nodeMap=new Map();
-nodes.forEach(node=>nodeMap.set(node.nodeId,node));
-nodes.forEach(node=>node.parentNode=nodeMap.get(node.parentId));
-return nodes.filter(nodeInBody);
-});
-}
-
-
-
-
-
-
-
-
-
-function getEffectiveRule(property,node,{
-inlineStyle,
-attributesStyle,
-matchedCSSRules,
-inherited})
-{
-const cssModel={
-styleSheetHeaderForId:id=>({id})};
-
-
-const nodeType=node.nodeType;
-node.nodeType=()=>nodeType;
-const matchedStyles=new CSSMatchedStyles(
-cssModel,
-node,
-inlineStyle,
-attributesStyle,
-matchedCSSRules,
-null,
-inherited,
-null);
-
-
-const nodeStyles=matchedStyles.nodeStyles();
-const matchingRule=nodeStyles.
-find(style=>
-
-style.allProperties().some(item=>item.name===property&&
-matchedStyles.propertyState(item)!==CSSMatchedStyles.PropertyState.Overloaded));
-
-
-return matchingRule;
-}
-
-
-
-
-
-function getNodeTextLength(node){
-return!node.nodeValue?0:node.nodeValue.trim().length;
-}
-
-
-
-
-
-
-function getFontSizeSourceRule(driver,node){
-return driver.sendCommand('CSS.getMatchedStylesForNode',{nodeId:node.nodeId}).
-then(matchedRules=>getEffectiveRule(FONT_SIZE_PROPERTY_NAME,node,matchedRules));
-}
-
-
-
-
-
-
-function getFontSizeInformation(driver,node){
-return driver.sendCommand('CSS.getComputedStyleForNode',{nodeId:node.parentId}).
-then(result=>{
-const{computedStyle}=result;
-const fontSizeProperty=computedStyle.find(({name})=>name===FONT_SIZE_PROPERTY_NAME);
-
-return{
-fontSize:parseInt(fontSizeProperty.value,10),
-textLength:getNodeTextLength(node),
-node:node.parentNode};
-
-}).
-catch(err=>{
-require('../../../lib/sentry.js').captureException(err);
-return null;
-});
-}
-
-
-
-
-
-function isNonEmptyTextNode(node){
-return node.nodeType===global.Node.TEXT_NODE&&
-!TEXT_NODE_BLOCK_LIST.has(node.parentNode.nodeName)&&
-getNodeTextLength(node)>0;
-}
-
-class FontSize extends Gatherer{
-
-
-
-
-afterPass(passContext){
-
-const stylesheets=new Map();
-
-const onStylesheetAdd=sheet=>stylesheets.set(sheet.header.styleSheetId,sheet.header);
-passContext.driver.on('CSS.styleSheetAdded',onStylesheetAdd);
-
-const enableDOM=passContext.driver.sendCommand('DOM.enable');
-const enableCSS=passContext.driver.sendCommand('CSS.enable');
-
-let failingTextLength=0;
-let visitedTextLength=0;
-let totalTextLength=0;
-
-return Promise.all([enableDOM,enableCSS]).
-then(()=>getAllNodesFromBody(passContext.driver)).
-then(nodes=>{
-const textNodes=nodes.filter(isNonEmptyTextNode);
-totalTextLength=textNodes.reduce((sum,node)=>sum+=getNodeTextLength(node),0);
-const nodesToVisit=textNodes.
-sort((a,b)=>getNodeTextLength(b)-getNodeTextLength(a)).
-slice(0,MAX_NODES_VISITED);
-
-return nodesToVisit;
-}).
-then(textNodes=>
-Promise.all(textNodes.map(node=>getFontSizeInformation(passContext.driver,node)))).
-then(fontSizeInfo=>{
-const visitedNodes=fontSizeInfo.filter(Boolean);
-visitedTextLength=visitedNodes.reduce((sum,{textLength})=>sum+=textLength,0);
-const failingNodes=visitedNodes.
-filter(({fontSize})=>fontSize<MINIMAL_LEGIBLE_FONT_SIZE_PX);
-failingTextLength=failingNodes.reduce((sum,{textLength})=>sum+=textLength,0);
-
-return Promise.all(failingNodes.
-sort((a,b)=>b.textLength-a.textLength).
-slice(0,MAX_NODES_ANALYZED).
-map(info=>
-getFontSizeSourceRule(passContext.driver,info.node).
-then(sourceRule=>{
-if(sourceRule){
-info.cssRule={
-type:sourceRule.type,
-range:sourceRule.range,
-styleSheetId:sourceRule.styleSheetId};
-
-
-if(sourceRule.parentRule){
-info.cssRule.parentRule={
-origin:sourceRule.parentRule.origin,
-selectors:sourceRule.parentRule.selectors};
-
-}
-}
-return info;
-})));
-
-
-}).
-then(analyzedFailingNodesData=>{
-passContext.driver.off('CSS.styleSheetAdded',onStylesheetAdd);
-
-const analyzedFailingTextLength=analyzedFailingNodesData.
-reduce((sum,{textLength})=>sum+=textLength,0);
-
-analyzedFailingNodesData.
-filter(data=>data.cssRule&&data.cssRule.styleSheetId).
-forEach(data=>data.cssRule.stylesheet=stylesheets.get(data.cssRule.styleSheetId));
-
-return Promise.all([
-passContext.driver.sendCommand('DOM.disable'),
-passContext.driver.sendCommand('CSS.disable')]).
-then(_=>({
-analyzedFailingNodesData,
-analyzedFailingTextLength,
-failingTextLength,
-visitedTextLength,
-totalTextLength}));
-
-});
-}}
-
-
-module.exports=FontSize;
-
-
-
-
-
-
-
-
-
-
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"../../../lib/sentry.js":90,"../../../lib/web-inspector":96,"../../driver.js":19,"../gatherer":21}],"../gather/gatherers/seo/hreflang":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-class Hreflang extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-
-return driver.querySelectorAll('head link[rel="alternate" i][hreflang]').
-then(nodes=>Promise.all(nodes.map(node=>
-Promise.all([node.getAttribute('href'),node.getAttribute('hreflang')])))).
-
-then(attributeValues=>attributeValues&&
-attributeValues.map(values=>{
-const[href,hreflang]=values;
-return{
-href:href||'',
-hreflang:hreflang||''};
-
-}));
-
-}}
-
-
-module.exports=Hreflang;
-
-
-},{"../gatherer":21}],"../gather/gatherers/seo/meta-description":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-class MetaDescription extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-
-return driver.querySelector('head meta[name="description" i]').
-then(node=>node&&node.getAttribute('content'));
-}}
-
-
-module.exports=MetaDescription;
-
-
-},{"../gatherer":21}],"../gather/gatherers/seo/meta-robots":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-class MetaRobots extends Gatherer{
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-
-return driver.querySelector('head meta[name="robots" i]').
-then(node=>node&&node.getAttribute('content'));
-}}
-
-
-module.exports=MetaRobots;
-
-},{"../gatherer":21}],"../gather/gatherers/seo/robots-txt":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('../gatherer');
-
-
-
-
-
-async function getRobotsTxtContent(){
-try{
-const response=await fetch(new URL('/robots.txt',location.href).href);
-if(!response.ok){
-return{status:response.status,content:null};
-}
-
-const content=await response.text();
-return{status:response.status,content};
-}catch(_){
-return{status:null,content:null};
-}
-}
-
-
-class RobotsTxt extends Gatherer{
-
-
-
-
-afterPass(passContext){
-return passContext.driver.evaluateAsync(`(${getRobotsTxtContent.toString()}())`);
-}}
-
-
-module.exports=RobotsTxt;
-
-},{"../gatherer":21}],"../gather/gatherers/service-worker":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-class ServiceWorker extends Gatherer{
-
-
-
-
-async beforePass(passContext){
-const{versions}=await passContext.driver.getServiceWorkerVersions();
-return{
-versions};
-
-}}
-
-
-module.exports=ServiceWorker;
-
-},{"./gatherer":21}],"../gather/gatherers/start-url":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-const manifestParser=require('../../lib/manifest-parser');
-const Driver=require('../driver.js');
-
-class StartUrl extends Gatherer{
-
-
-
-
-
-afterPass(passContext){
-const driver=passContext.driver;
-return driver.goOnline(passContext).
-then(()=>driver.getAppManifest()).
-then(response=>driver.goOffline().then(()=>response)).
-then(response=>response&&manifestParser(response.data,response.url,passContext.url)).
-then(manifest=>{
-const startUrlInfo=this._readManifestStartUrl(manifest);
-if(startUrlInfo.isReadFailure){
-return{statusCode:-1,explanation:startUrlInfo.reason};
-}
-
-return this._attemptManifestFetch(passContext.driver,startUrlInfo.startUrl);
-}).catch(()=>{
-return{statusCode:-1,explanation:'Unable to fetch start URL via service worker'};
-});
-}
-
-
-
-
-
-
-_readManifestStartUrl(manifest){
-if(!manifest||!manifest.value){
-const detailedMsg=manifest&&manifest.warning;
-
-if(detailedMsg){
-return{isReadFailure:true,reason:`Error fetching web app manifest: ${detailedMsg}`};
-}else{
-return{isReadFailure:true,reason:`No usable web app manifest found on page`};
-}
-}
-
-
-
-if(manifest.value.start_url.warning){
-return{isReadFailure:true,reason:manifest.value.start_url.warning};
-}
-
-
-return{isReadFailure:false,startUrl:manifest.value.start_url.value};
-}
-
-
-
-
-
-
-
-
-_attemptManifestFetch(driver,startUrl){
-
-const timeoutPromise=new Promise(resolve=>
-setTimeout(
-()=>resolve({statusCode:-1,explanation:'Timed out waiting for fetched start_url'}),
-3000));
-
-
-
-const fetchPromise=new Promise(resolve=>{
-driver.on('Network.responseReceived',onResponseReceived);
-
-
-function onResponseReceived(responseEvent){
-const{response}=responseEvent;
-
-if(response.url!==startUrl)return;
-driver.off('Network.responseReceived',onResponseReceived);
-
-if(!response.fromServiceWorker){
-return resolve({
-statusCode:-1,
-explanation:'Unable to fetch start URL via service worker'});
-
-}
-
-return resolve({statusCode:response.status});
-}
-});
-
-return driver.
-evaluateAsync(`window.location = '${startUrl}'`).
-then(()=>Promise.race([fetchPromise,timeoutPromise]));
-}}
-
-
-module.exports=StartUrl;
-
-},{"../../lib/manifest-parser":86,"../driver.js":19,"./gatherer":21}],"../gather/gatherers/theme-color":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-class ThemeColor extends Gatherer{
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-
-const metaEl=await driver.querySelector('head meta[name="theme-color" i]');
-return metaEl&&metaEl.getAttribute('content');
-}}
-
-
-module.exports=ThemeColor;
-
-},{"./gatherer":21}],"../gather/gatherers/viewport-dimensions":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-
-
-
-
-
-
-function getViewportDimensions(){
-
-
-
-return Promise.resolve({
-innerWidth:window.innerWidth,
-innerHeight:window.innerHeight,
-outerWidth:window.outerWidth,
-outerHeight:window.outerHeight,
-devicePixelRatio:window.devicePixelRatio});
-
-}
-
-class ViewportDimensions extends Gatherer{
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-
-
-const dimensions=await driver.evaluateAsync(`(${getViewportDimensions.toString()}())`,
-{useIsolation:true});
-
-const allNumeric=Object.values(dimensions).every(Number.isFinite);
-if(!allNumeric){
-const results=JSON.stringify(dimensions);
-throw new Error(`ViewportDimensions results were not numeric: ${results}`);
-}
-
-return dimensions;
-}}
-
-
-module.exports=ViewportDimensions;
-
-},{"./gatherer":21}],"../gather/gatherers/viewport":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-class Viewport extends Gatherer{
-
-
-
-
-async afterPass(passContext){
-const driver=passContext.driver;
-
-const metaEl=await driver.querySelector('head meta[name="viewport" i]');
-return metaEl&&metaEl.getAttribute('content');
-}}
-
-
-module.exports=Viewport;
-
-},{"./gatherer":21}],"./gather/computed/critical-request-chains":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const NetworkRequest=require('../../lib/network-request');
-const assert=require('assert');
-
-class CriticalRequestChains extends ComputedArtifact{
-get name(){
-return'CriticalRequestChains';
-}
-
-
-
-
-
-
-
-
-
-static isCritical(request,mainResource){
-assert.ok(mainResource,'mainResource not provided');
-
-
-if(request.isLinkPreload){
-return false;
-}
-
-
-const isIframe=request.resourceType===NetworkRequest.TYPES.Document&&
-request.frameId!==mainResource.frameId;
-
-
-
-
-const nonCriticalResourceTypes=[
-NetworkRequest.TYPES.Image,
-NetworkRequest.TYPES.XHR,
-NetworkRequest.TYPES.Fetch,
-NetworkRequest.TYPES.EventSource];
-
-if(nonCriticalResourceTypes.includes(request.resourceType||'Other')||
-isIframe||
-request.mimeType&&request.mimeType.startsWith('image/')){
-return false;
-}
-
-return['VeryHigh','High','Medium'].includes(request.priority);
-}
-
-
-
-
-
-
-static extractChain(networkRecords,mainResource){
-networkRecords=networkRecords.filter(req=>req.finished);
-
-
-
-const requestIdToRequests=new Map();
-for(const request of networkRecords){
-requestIdToRequests.set(request.requestId,request);
-}
-
-
-
-const criticalRequests=networkRecords.filter(request=>
-CriticalRequestChains.isCritical(request,mainResource));
-
-
-
-const criticalRequestChains={};
-for(const request of criticalRequests){
-
-
-
-
-const ancestors=[];
-let ancestorRequest=request.initiatorRequest;
-
-let node=criticalRequestChains;
-while(ancestorRequest){
-const ancestorIsCritical=CriticalRequestChains.isCritical(ancestorRequest,mainResource);
-
-
-
-
-
-if(!ancestorIsCritical||ancestors.includes(ancestorRequest.requestId)){
-
-
-ancestors.length=0;
-node=undefined;
-break;
-}
-ancestors.push(ancestorRequest.requestId);
-ancestorRequest=ancestorRequest.initiatorRequest;
-}
-
-
-
-let ancestor=ancestors.pop();
-while(ancestor&&node){
-const parentRequest=requestIdToRequests.get(ancestor);
-if(!parentRequest){
-throw new Error(`request with id ${ancestor} not found.`);
-}
-
-const parentRequestId=parentRequest.requestId;
-if(!node[parentRequestId]){
-node[parentRequestId]={
-request:parentRequest,
-children:{}};
-
-}
-
-
-ancestor=ancestors.pop();
-node=node[parentRequestId].children;
-}
-
-if(!node){
-continue;
-}
-
-
-if(node[request.requestId]){
-continue;
-}
-
-
-node[request.requestId]={
-request,
-children:{}};
-
-}
-
-return criticalRequestChains;
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const[networkRecords,mainResource]=await Promise.all([
-artifacts.requestNetworkRecords(data.devtoolsLog),
-artifacts.requestMainResource(data)]);
-
-
-return CriticalRequestChains.extractChain(networkRecords,mainResource);
-}}
-
-
-module.exports=CriticalRequestChains;
-
-},{"../../lib/network-request":88,"./computed-artifact":11,"assert":102}],"./gather/computed/load-simulator":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const constants=require('../../config/constants');
-const Simulator=require('../../lib/dependency-graph/simulator/simulator');
-
-class LoadSimulatorArtifact extends ComputedArtifact{
-get name(){
-return'LoadSimulator';
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const{throttlingMethod,throttling}=data.settings;
-const networkAnalysis=await artifacts.requestNetworkAnalysis(data.devtoolsLog);
-
-
-const options={
-additionalRttByOrigin:networkAnalysis.additionalRttByOrigin,
-serverResponseTimeByOrigin:networkAnalysis.serverResponseTimeByOrigin};
-
-
-switch(throttlingMethod){
-case'provided':
-options.rtt=networkAnalysis.rtt;
-options.throughput=networkAnalysis.throughput;
-options.cpuSlowdownMultiplier=1;
-options.layoutTaskMultiplier=1;
-break;
-case'devtools':
-if(throttling){
-options.rtt=
-throttling.requestLatencyMs/constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR;
-options.throughput=
-throttling.downloadThroughputKbps*1024/
-constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR;
-}
-
-options.cpuSlowdownMultiplier=1;
-options.layoutTaskMultiplier=1;
-break;
-case'simulate':
-if(throttling){
-options.rtt=throttling.rttMs;
-options.throughput=throttling.throughputKbps*1024;
-options.cpuSlowdownMultiplier=throttling.cpuSlowdownMultiplier;
-}
-break;
-default:
-
-break;}
-
-
-return new Simulator(options);
-}}
-
-
-module.exports=LoadSimulatorArtifact;
-
-},{"../../config/constants":8,"../../lib/dependency-graph/simulator/simulator":31,"./computed-artifact":11}],"./gather/computed/main-resource":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const URL=require('../../lib/url-shim');
-
-
-
-
-
-class MainResource extends ComputedArtifact{
-get name(){
-return'MainResource';
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const finalUrl=data.URL.finalUrl;
-const requests=await artifacts.requestNetworkRecords(data.devtoolsLog);
-
-const mainResource=requests.find(request=>finalUrl.startsWith(request.url)&&
-URL.equalWithExcludedFragments(request.url,finalUrl));
-
-if(!mainResource){
-throw new Error('Unable to identify the main resource');
-}
-
-return mainResource;
-}}
-
-
-module.exports=MainResource;
-
-},{"../../lib/url-shim":"url","./computed-artifact":11}],"./gather/computed/main-thread-tasks":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const{taskGroups,taskNameToGroup}=require('../../lib/task-groups');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class MainThreadTasks extends ComputedArtifact{
-get name(){
-return'MainThreadTasks';
-}
-
-
-
-
-
-
-static _createNewTaskNode(event,parent){
-const newTask={
-event,
-startTime:event.ts,
-endTime:event.ph==='X'?event.ts+Number(event.dur||0):NaN,
-parent:parent,
-children:[],
-
-
-attributableURLs:[],
-group:taskGroups.other,
-duration:NaN,
-selfTime:NaN};
-
-
-if(parent){
-parent.children.push(newTask);
-}
-
-return newTask;
-}
-
-
-
-
-
-static _createTasksFromEvents(mainThreadEvents){
-
-const tasks=[];
-
-let currentTask;
-
-for(const event of mainThreadEvents){
-
-if(event.ph!=='X'&&event.ph!=='B'&&event.ph!=='E')continue;
-
-
-
-while(
-currentTask&&
-Number.isFinite(currentTask.endTime)&&
-currentTask.endTime<=event.ts)
-{
-currentTask=currentTask.parent;
-}
-
-
-if(!currentTask){
-
-if(event.ph==='E'){
-throw new Error('Fatal trace logic error');
-}
-
-currentTask=MainThreadTasks._createNewTaskNode(event);
-tasks.push(currentTask);
-
-continue;
-}
-
-if(event.ph==='X'||event.ph==='B'){
-
-const newTask=MainThreadTasks._createNewTaskNode(event,currentTask);
-tasks.push(newTask);
-currentTask=newTask;
-}else{
-if(currentTask.event.ph!=='B'){
-throw new Error('Fatal trace logic error');
-}
-
-
-currentTask.endTime=event.ts;
-currentTask=currentTask.parent;
-}
-}
-
-return tasks;
-}
-
-
-
-
-
-static _computeRecursiveSelfTime(task){
-const childTime=task.children.
-map(MainThreadTasks._computeRecursiveSelfTime).
-reduce((sum,child)=>sum+child,0);
-task.duration=task.endTime-task.startTime;
-task.selfTime=task.duration-childTime;
-return task.duration;
-}
-
-
-
-
-
-static _computeRecursiveAttributableURLs(task,parentURLs){
-const argsData=task.event.args.data||{};
-const stackFrameURLs=(argsData.stackTrace||[]).map(entry=>entry.url);
-
-let taskURLs=[];
-switch(task.event.name){
-
-
-
-
-
-case'v8.compile':
-case'EvaluateScript':
-case'FunctionCall':
-taskURLs=[argsData.url].concat(stackFrameURLs);
-break;
-case'v8.compileModule':
-taskURLs=[task.event.args.fileName].concat(stackFrameURLs);
-break;
-default:
-taskURLs=stackFrameURLs;
-break;}
-
-
-
-const attributableURLs=Array.from(parentURLs);
-for(const url of taskURLs){
-
-if(!url)continue;
-
-if(attributableURLs[attributableURLs.length-1]===url)continue;
-attributableURLs.push(url);
-}
-
-task.attributableURLs=attributableURLs;
-task.children.forEach(child=>
-MainThreadTasks._computeRecursiveAttributableURLs(child,attributableURLs));
-}
-
-
-
-
-
-static _computeRecursiveTaskGroup(task,parentGroup){
-const group=taskNameToGroup[task.event.name];
-task.group=group||parentGroup||taskGroups.other;
-task.children.forEach(child=>MainThreadTasks._computeRecursiveTaskGroup(child,task.group));
-}
-
-
-
-
-
-static getMainThreadTasks(traceEvents){
-const tasks=MainThreadTasks._createTasksFromEvents(traceEvents);
-
-
-for(const task of tasks){
-if(task.parent)continue;
-
-MainThreadTasks._computeRecursiveSelfTime(task);
-MainThreadTasks._computeRecursiveAttributableURLs(task,[]);
-MainThreadTasks._computeRecursiveTaskGroup(task);
-}
-
-
-const firstTs=(tasks[0]||{startTime:0}).startTime;
-for(const task of tasks){
-task.startTime=(task.startTime-firstTs)/1000;
-task.endTime=(task.endTime-firstTs)/1000;
-task.duration/=1000;
-task.selfTime/=1000;
-
-
-if(!Number.isFinite(task.selfTime)){
-throw new Error('Invalid task timing data');
-}
-}
-
-return tasks;
-}
-
-
-
-
-
-
-async compute_(trace,artifacts){
-const{mainThreadEvents}=await artifacts.requestTraceOfTab(trace);
-return MainThreadTasks.getMainThreadTasks(mainThreadEvents);
-}}
-
-
-module.exports=MainThreadTasks;
-
-},{"../../lib/task-groups":93,"./computed-artifact":11}],"./gather/computed/metrics/estimated-input-latency":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./metric');
-const LHError=require('../../../lib/lh-error');
-const TracingProcessor=require('../../../lib/traces/tracing-processor');
-
-const ROLLING_WINDOW_SIZE=5000;
-
-
-
-
-
-
-class EstimatedInputLatency extends MetricArtifact{
-get name(){
-return'EstimatedInputLatency';
-}
-
-
-
-
-
-static calculateRollingWindowEIL(events){
-const candidateStartEvts=events.filter(evt=>evt.duration>=10);
-
-let worst90thPercentileLatency=16;
-for(const startEvt of candidateStartEvts){
-const latencyPercentiles=TracingProcessor.getRiskToResponsiveness(
-events,
-startEvt.start,
-startEvt.start+ROLLING_WINDOW_SIZE,
-[0.9]);
-
-
-worst90thPercentileLatency=Math.max(latencyPercentiles[0].time,worst90thPercentileLatency);
-}
-
-return worst90thPercentileLatency;
-}
-
-
-
-
-
-computeObservedMetric(data){
-const{firstMeaningfulPaint}=data.traceOfTab.timings;
-if(!firstMeaningfulPaint){
-throw new LHError(LHError.errors.NO_FMP);
-}
-
-const events=TracingProcessor.getMainThreadTopLevelEvents(
-data.traceOfTab,
-firstMeaningfulPaint).
-filter(evt=>evt.duration>=1);
-
-return Promise.resolve({
-timing:EstimatedInputLatency.calculateRollingWindowEIL(events)});
-
-}}
-
-
-module.exports=EstimatedInputLatency;
-
-},{"../../../lib/lh-error":85,"../../../lib/traces/tracing-processor":95,"./metric":14}],"./gather/computed/metrics/first-contentful-paint":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./metric');
-
-class FirstContentfulPaint extends MetricArtifact{
-get name(){
-return'FirstContentfulPaint';
-}
-
-
-
-
-
-async computeObservedMetric(data){
-const{traceOfTab}=data;
-
-return{
-timing:traceOfTab.timings.firstContentfulPaint,
-timestamp:traceOfTab.timestamps.firstContentfulPaint};
-
-}}
-
-
-module.exports=FirstContentfulPaint;
-
-},{"./metric":14}],"./gather/computed/metrics/first-cpu-idle":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-const MetricArtifact=require('./metric');
-const TracingProcessor=require('../../../lib/traces/tracing-processor');
-const LHError=require('../../../lib/lh-error');
-
-const LONG_TASK_THRESHOLD=50;
-
-const MAX_TASK_CLUSTER_DURATION=250;
-const MIN_TASK_CLUSTER_PADDING=1000;
-const MIN_TASK_CLUSTER_FMP_DISTANCE=5000;
-
-const MAX_QUIET_WINDOW_SIZE=5000;
-
-
-const EXPONENTIATION_COEFFICIENT=-Math.log(3-1)/15;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class FirstCPUIdle extends MetricArtifact{
-get name(){
-return'FirstCPUIdle';
-}
-
-
-
-
-
-static getRequiredWindowSizeInMs(t){
-const tInSeconds=t/1000;
-const exponentiationComponent=Math.exp(EXPONENTIATION_COEFFICIENT*tInSeconds);
-return(4*exponentiationComponent+1)*1000;
-}
-
-
-
-
-
-
-
-
-
-
-static getTaskClustersInWindow(tasks,startIndex,windowEnd){
-const clusters=[];
-
-let previousTaskEndTime=-Infinity;
-
-let currentCluster=[];
-
-
-
-
-
-const clusteringWindowEnd=windowEnd+MIN_TASK_CLUSTER_PADDING;
-
-const isInClusteringWindow=task=>task.start<clusteringWindowEnd;
-for(let i=startIndex;i<tasks.length;i++){
-if(!isInClusteringWindow(tasks[i])){
-break;
-}
-
-const task=tasks[i];
-
-
-if(task.start-previousTaskEndTime>MIN_TASK_CLUSTER_PADDING){
-currentCluster=[];
-clusters.push(currentCluster);
-}
-
-currentCluster.push(task);
-previousTaskEndTime=task.end;
-}
-
-return clusters.
-
-map(tasks=>{
-const start=tasks[0].start;
-const end=tasks[tasks.length-1].end;
-const duration=end-start;
-return{start,end,duration};
-}).
-
-filter(cluster=>cluster.start<windowEnd);
-}
-
-
-
-
-
-
-
-
-
-
-static findQuietWindow(FMP,traceEnd,longTasks){
-
-if(longTasks.length===0||
-longTasks[0].start>FMP+FirstCPUIdle.getRequiredWindowSizeInMs(0)){
-return FMP;
-}
-
-
-const isTooCloseToFMP=cluster=>cluster.start<FMP+MIN_TASK_CLUSTER_FMP_DISTANCE;
-
-const isTooLong=cluster=>cluster.duration>MAX_TASK_CLUSTER_DURATION;
-
-const isBadCluster=cluster=>isTooCloseToFMP(cluster)||isTooLong(cluster);
-
-
-
-for(let i=0;i<longTasks.length;i++){
-const windowStart=longTasks[i].end;
-const windowSize=FirstCPUIdle.getRequiredWindowSizeInMs(windowStart-FMP);
-const windowEnd=windowStart+windowSize;
-
-
-if(windowEnd>traceEnd){
-throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
-}
-
-
-if(i+1<longTasks.length&&
-longTasks[i+1].start-windowStart<=MIN_TASK_CLUSTER_PADDING){
-continue;
-}
-
-const taskClusters=FirstCPUIdle.getTaskClustersInWindow(longTasks,i+1,windowEnd);
-const hasBadTaskClusters=taskClusters.some(isBadCluster);
-
-if(!hasBadTaskClusters){
-return windowStart;
-}
-}
-
-throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
-}
-
-
-
-
-
-computeObservedMetric(data){
-const{traceOfTab}=data;
-const navStart=traceOfTab.timestamps.navigationStart;
-const FMP=traceOfTab.timings.firstMeaningfulPaint;
-const DCL=traceOfTab.timings.domContentLoaded;
-const traceEnd=traceOfTab.timings.traceEnd;
-
-if(!FMP||!DCL){
-throw new LHError(FMP?LHError.errors.NO_DCL:LHError.errors.NO_FMP);
-}
-
-if(traceEnd-FMP<MAX_QUIET_WINDOW_SIZE){
-throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
-}
-
-const longTasksAfterFMP=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab,FMP).
-filter(evt=>evt.duration>=LONG_TASK_THRESHOLD);
-const firstInteractive=FirstCPUIdle.findQuietWindow(FMP,traceEnd,longTasksAfterFMP);
-
-const valueInMs=Math.max(firstInteractive,DCL);
-
-return Promise.resolve({
-timing:valueInMs,
-timestamp:valueInMs*1000+navStart});
-
-}}
-
-
-
-
-
-
-
-module.exports=FirstCPUIdle;
-
-},{"../../../lib/lh-error":85,"../../../lib/traces/tracing-processor":95,"./metric":14}],"./gather/computed/metrics/first-meaningful-paint":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./metric');
-const LHError=require('../../../lib/lh-error');
-
-class FirstMeaningfulPaint extends MetricArtifact{
-get name(){
-return'FirstMeaningfulPaint';
-}
-
-
-
-
-
-async computeObservedMetric(data){
-const{traceOfTab}=data;
-if(!traceOfTab.timestamps.firstMeaningfulPaint){
-throw new LHError(LHError.errors.NO_FMP);
-}
-
-return{
-
-timing:traceOfTab.timings.firstMeaningfulPaint,
-timestamp:traceOfTab.timestamps.firstMeaningfulPaint};
-
-}}
-
-
-module.exports=FirstMeaningfulPaint;
-
-},{"../../../lib/lh-error":85,"./metric":14}],"./gather/computed/metrics/interactive":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./metric');
-
-const NetworkRecorder=require('../../../lib/network-recorder');
-const TracingProcessor=require('../../../lib/traces/tracing-processor');
-const LHError=require('../../../lib/lh-error');
-
-const REQUIRED_QUIET_WINDOW=5000;
-const ALLOWED_CONCURRENT_REQUESTS=2;
-
-
-
-
-
-
-class Interactive extends MetricArtifact{
-get name(){
-return'Interactive';
-}
-
-
-
-
-
-
-
-
-static _findNetworkQuietPeriods(networkRecords,traceOfTab){
-const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
-
-const filteredNetworkRecords=networkRecords.filter(record=>{
-return record.finished&&record.requestMethod==='GET'&&!record.failed&&
-
-record.statusCode<400;
-});
-return NetworkRecorder.findNetworkQuietPeriods(filteredNetworkRecords,
-ALLOWED_CONCURRENT_REQUESTS,traceEndTsInMs);
-}
-
-
-
-
-
-
-
-static _findCPUQuietPeriods(longTasks,traceOfTab){
-const navStartTsInMs=traceOfTab.timestamps.navigationStart/1000;
-const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
-if(longTasks.length===0){
-return[{start:0,end:traceEndTsInMs}];
-}
-
-
-const quietPeriods=[];
-longTasks.forEach((task,index)=>{
-if(index===0){
-quietPeriods.push({
-start:0,
-end:task.start+navStartTsInMs});
-
-}
-
-if(index===longTasks.length-1){
-quietPeriods.push({
-start:task.end+navStartTsInMs,
-end:traceEndTsInMs});
-
-}else{
-quietPeriods.push({
-start:task.end+navStartTsInMs,
-end:longTasks[index+1].start+navStartTsInMs});
-
-}
-});
-
-return quietPeriods;
-}
-
-
-
-
-
-
-
-
-static findOverlappingQuietPeriods(longTasks,networkRecords,traceOfTab){
-const FcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
-
-
-const isLongEnoughQuietPeriod=period=>
-period.end>FcpTsInMs+REQUIRED_QUIET_WINDOW&&
-period.end-period.start>=REQUIRED_QUIET_WINDOW;
-const networkQuietPeriods=this._findNetworkQuietPeriods(networkRecords,traceOfTab).
-filter(isLongEnoughQuietPeriod);
-const cpuQuietPeriods=this._findCPUQuietPeriods(longTasks,traceOfTab).
-filter(isLongEnoughQuietPeriod);
-
-const cpuQueue=cpuQuietPeriods.slice();
-const networkQueue=networkQuietPeriods.slice();
-
-
-let cpuCandidate=cpuQueue.shift();
-let networkCandidate=networkQueue.shift();
-while(cpuCandidate&&networkCandidate){
-if(cpuCandidate.start>=networkCandidate.start){
-
-if(networkCandidate.end>=cpuCandidate.start+REQUIRED_QUIET_WINDOW){
-return{
-cpuQuietPeriod:cpuCandidate,
-networkQuietPeriod:networkCandidate,
-cpuQuietPeriods,
-networkQuietPeriods};
-
-}else{
-networkCandidate=networkQueue.shift();
-}
-}else{
-
-if(cpuCandidate.end>=networkCandidate.start+REQUIRED_QUIET_WINDOW){
-return{
-cpuQuietPeriod:cpuCandidate,
-networkQuietPeriod:networkCandidate,
-cpuQuietPeriods,
-networkQuietPeriods};
-
-}else{
-cpuCandidate=cpuQueue.shift();
-}
-}
-}
-
-throw new LHError(
-cpuCandidate?
-LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD:
-LHError.errors.NO_TTI_CPU_IDLE_PERIOD);
-
-}
-
-
-
-
-
-computeObservedMetric(data){
-const{traceOfTab,networkRecords}=data;
-
-if(!traceOfTab.timestamps.domContentLoaded){
-throw new LHError(LHError.errors.NO_DCL);
-}
-
-const longTasks=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab).
-filter(event=>event.duration>=50);
-const quietPeriodInfo=Interactive.findOverlappingQuietPeriods(
-longTasks,
-networkRecords,
-traceOfTab);
-
-
-const cpuQuietPeriod=quietPeriodInfo.cpuQuietPeriod;
-
-const timestamp=Math.max(
-cpuQuietPeriod.start,
-traceOfTab.timestamps.firstContentfulPaint/1000,
-traceOfTab.timestamps.domContentLoaded/1000)*
-1000;
-const timing=(timestamp-traceOfTab.timestamps.navigationStart)/1000;
-return Promise.resolve({timing,timestamp});
-}}
-
-
-module.exports=Interactive;
-
-
-
-
-
-
-
-},{"../../../lib/lh-error":85,"../../../lib/network-recorder":87,"../../../lib/traces/tracing-processor":95,"./metric":14}],"./gather/computed/metrics/lantern-estimated-input-latency":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const LanternMetricArtifact=require('./lantern-metric');
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-const EstimatedInputLatency=require('./estimated-input-latency');
-
-
-
-class LanternEstimatedInputLatency extends LanternMetricArtifact{
-get name(){
-return'LanternEstimatedInputLatency';
-}
-
-
-
-
-get COEFFICIENTS(){
-return{
-intercept:0,
-optimistic:0.4,
-pessimistic:0.4};
-
-}
-
-
-
-
-
-getOptimisticGraph(dependencyGraph){
-return dependencyGraph;
-}
-
-
-
-
-
-getPessimisticGraph(dependencyGraph){
-return dependencyGraph;
-}
-
-
-
-
-
-
-getEstimateFromSimulation(simulation,extras){
-
-
-const fmpTimeInMs=extras.optimistic?
-extras.fmpResult.pessimisticEstimate.timeInMs:
-extras.fmpResult.optimisticEstimate.timeInMs;
-
-const events=LanternEstimatedInputLatency.getEventsAfterFMP(
-simulation.nodeTimings,
-fmpTimeInMs);
-
-
-return{
-timeInMs:EstimatedInputLatency.calculateRollingWindowEIL(events),
-nodeTimings:simulation.nodeTimings};
-
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const fmpResult=await artifacts.requestLanternFirstMeaningfulPaint(data);
-return this.computeMetricWithGraphs(data,artifacts,{fmpResult});
-}
-
-
-
-
-
-static getEventsAfterFMP(nodeTimings,fmpTimeInMs){
-
-const events=[];
-for(const[node,timing]of nodeTimings.entries()){
-if(node.type!==BaseNode.TYPES.CPU)continue;
-if(timing.endTime<fmpTimeInMs)continue;
-
-events.push({
-start:timing.startTime,
-end:timing.endTime,
-duration:timing.duration});
-
-}
-
-return events;
-}}
-
-
-module.exports=LanternEstimatedInputLatency;
-
-},{"../../../lib/dependency-graph/base-node":25,"./estimated-input-latency":"./gather/computed/metrics/estimated-input-latency","./lantern-metric":13}],"./gather/computed/metrics/lantern-first-contentful-paint":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./lantern-metric');
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-
-
-
-class FirstContentfulPaint extends MetricArtifact{
-get name(){
-return'LanternFirstContentfulPaint';
-}
-
-
-
-
-get COEFFICIENTS(){
-return{
-intercept:0,
-optimistic:0.5,
-pessimistic:0.5};
-
-}
-
-
-
-
-
-
-getOptimisticGraph(dependencyGraph,traceOfTab){
-const fcp=traceOfTab.timestamps.firstContentfulPaint;
-const blockingScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
-return(
-node.endTime<=fcp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
-
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fcp&&!node.isMainDocument())return false;
-
-if(node.type===BaseNode.TYPES.CPU){
-return node.isEvaluateScriptFor(blockingScriptUrls);
-}
-
-
-return node.hasRenderBlockingPriority()&&node.initiatorType!=='script';
-});
-}
-
-
-
-
-
-
-getPessimisticGraph(dependencyGraph,traceOfTab){
-const fcp=traceOfTab.timestamps.firstContentfulPaint;
-const blockingScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
-return node.endTime<=fcp&&node.hasRenderBlockingPriority();
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fcp&&!node.isMainDocument())return false;
-
-if(node.type===BaseNode.TYPES.CPU){
-return node.isEvaluateScriptFor(blockingScriptUrls);
-}
-
-
-return node.hasRenderBlockingPriority();
-});
-}}
-
-
-module.exports=FirstContentfulPaint;
-
-},{"../../../lib/dependency-graph/base-node":25,"./lantern-metric":13}],"./gather/computed/metrics/lantern-first-cpu-idle":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-const FirstCPUIdle=require('./first-cpu-idle');
-const LanternInteractive=require('./lantern-interactive');
-
-class LanternFirstCPUIdle extends LanternInteractive{
-get name(){
-return'LanternFirstCPUIdle';
-}
-
-
-
-
-get COEFFICIENTS(){
-return{
-intercept:0,
-optimistic:1,
-pessimistic:0};
-
-}
-
-
-
-
-
-
-
-getEstimateFromSimulation(simulation,extras){
-const fmpTimeInMs=extras.optimistic?
-extras.fmpResult.optimisticEstimate.timeInMs:
-extras.fmpResult.pessimisticEstimate.timeInMs;
-
-return{
-timeInMs:LanternFirstCPUIdle.getFirstCPUIdleWindowStart(simulation.nodeTimings,fmpTimeInMs),
-nodeTimings:simulation.nodeTimings};
-
-}
-
-
-
-
-
-
-static getFirstCPUIdleWindowStart(nodeTimings,fmpTimeInMs,longTaskLength=50){
-
-const longTasks=[];
-for(const[node,timing]of nodeTimings.entries()){
-if(node.type!==BaseNode.TYPES.CPU)continue;
-if(timing.duration<longTaskLength)continue;
-longTasks.push({start:timing.startTime,end:timing.endTime});
-}
-
-return FirstCPUIdle.findQuietWindow(fmpTimeInMs,Infinity,longTasks);
-}}
-
-
-module.exports=LanternFirstCPUIdle;
-
-},{"../../../lib/dependency-graph/base-node":25,"./first-cpu-idle":"./gather/computed/metrics/first-cpu-idle","./lantern-interactive":"./gather/computed/metrics/lantern-interactive"}],"./gather/computed/metrics/lantern-first-meaningful-paint":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./lantern-metric');
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-const LHError=require('../../../lib/lh-error');
-
-
-
-class FirstMeaningfulPaint extends MetricArtifact{
-get name(){
-return'LanternFirstMeaningfulPaint';
-}
-
-
-
-
-get COEFFICIENTS(){
-return{
-intercept:0,
-optimistic:0.5,
-pessimistic:0.5};
-
-}
-
-
-
-
-
-
-getOptimisticGraph(dependencyGraph,traceOfTab){
-const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
-if(!fmp){
-throw new LHError(LHError.errors.NO_FMP);
-}
-
-const blockingScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
-return(
-node.endTime<=fmp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
-
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fmp&&!node.isMainDocument())return false;
-
-if(node.type===BaseNode.TYPES.CPU){
-return node.isEvaluateScriptFor(blockingScriptUrls);
-}
-
-
-return node.hasRenderBlockingPriority()&&node.initiatorType!=='script';
-});
-}
-
-
-
-
-
-
-getPessimisticGraph(dependencyGraph,traceOfTab){
-const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
-if(!fmp){
-throw new LHError(LHError.errors.NO_FMP);
-}
-
-const requiredScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
-return node.endTime<=fmp&&node.hasRenderBlockingPriority();
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fmp&&!node.isMainDocument())return false;
-
-
-if(node.type===BaseNode.TYPES.CPU){
-return node.didPerformLayout()||node.isEvaluateScriptFor(requiredScriptUrls);
-}
-
-
-return node.hasRenderBlockingPriority();
-});
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const fcpResult=await artifacts.requestLanternFirstContentfulPaint(data);
-const metricResult=await this.computeMetricWithGraphs(data,artifacts);
-metricResult.timing=Math.max(metricResult.timing,fcpResult.timing);
-return metricResult;
-}}
-
-
-module.exports=FirstMeaningfulPaint;
-
-},{"../../../lib/dependency-graph/base-node":25,"../../../lib/lh-error":85,"./lantern-metric":13}],"./gather/computed/metrics/lantern-interactive":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./lantern-metric');
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-const NetworkRequest=require('../../../lib/network-request');
-
-
-
-
-const CRITICAL_LONG_TASK_THRESHOLD=20;
-
-class Interactive extends MetricArtifact{
-get name(){
-return'LanternInteractive';
-}
-
-
-
-
-get COEFFICIENTS(){
-return{
-intercept:0,
-optimistic:0.5,
-pessimistic:0.5};
-
-}
-
-
-
-
-
-getOptimisticGraph(dependencyGraph){
-
-const minimumCpuTaskDuration=CRITICAL_LONG_TASK_THRESHOLD*1000;
-
-return dependencyGraph.cloneWithRelationships(node=>{
-
-if(node.type===BaseNode.TYPES.CPU){
-return node.event.dur>minimumCpuTaskDuration;
-}
-
-
-const isImage=node.record.resourceType===NetworkRequest.TYPES.Image;
-const isScript=node.record.resourceType===NetworkRequest.TYPES.Script;
-return(
-!isImage&&(
-isScript||
-node.record.priority==='High'||
-node.record.priority==='VeryHigh'));
-
-});
-}
-
-
-
-
-
-getPessimisticGraph(dependencyGraph){
-return dependencyGraph;
-}
-
-
-
-
-
-
-getEstimateFromSimulation(simulationResult,extras){
-const lastTaskAt=Interactive.getLastLongTaskEndTime(simulationResult.nodeTimings);
-const minimumTime=extras.optimistic?
-extras.fmpResult.optimisticEstimate.timeInMs:
-extras.fmpResult.pessimisticEstimate.timeInMs;
-return{
-timeInMs:Math.max(minimumTime,lastTaskAt),
-nodeTimings:simulationResult.nodeTimings};
-
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const fmpResult=await artifacts.requestLanternFirstMeaningfulPaint(data);
-const metricResult=await this.computeMetricWithGraphs(data,artifacts,{fmpResult});
-metricResult.timing=Math.max(metricResult.timing,fmpResult.timing);
-return metricResult;
-}
-
-
-
-
-
-static getLastLongTaskEndTime(nodeTimings,duration=50){
-
-return Array.from(nodeTimings.entries()).
-filter(([node,timing])=>{
-if(node.type!==BaseNode.TYPES.CPU)return false;
-return timing.duration>duration;
-}).
-map(([_,timing])=>timing.endTime).
-reduce((max,x)=>Math.max(max||0,x||0),0);
-}}
-
-
-module.exports=Interactive;
-
-},{"../../../lib/dependency-graph/base-node":25,"../../../lib/network-request":88,"./lantern-metric":13}],"./gather/computed/metrics/lantern-speed-index":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./lantern-metric');
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-
-
-
-class SpeedIndex extends MetricArtifact{
-get name(){
-return'LanternSpeedIndex';
-}
-
-
-
-
-get COEFFICIENTS(){
-return{
-
-
-
-intercept:-250,
-optimistic:1.4,
-pessimistic:0.65};
-
-}
-
-
-
-
-
-getOptimisticGraph(dependencyGraph){
-return dependencyGraph;
-}
-
-
-
-
-
-getPessimisticGraph(dependencyGraph){
-return dependencyGraph;
-}
-
-
-
-
-
-
-getEstimateFromSimulation(simulationResult,extras){
-const fcpTimeInMs=extras.fcpResult.pessimisticEstimate.timeInMs;
-const estimate=extras.optimistic?
-extras.speedline.speedIndex:
-SpeedIndex.computeLayoutBasedSpeedIndex(simulationResult.nodeTimings,fcpTimeInMs);
-return{
-timeInMs:estimate,
-nodeTimings:simulationResult.nodeTimings};
-
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const speedline=await artifacts.requestSpeedline(data.trace);
-const fcpResult=await artifacts.requestLanternFirstContentfulPaint(data);
-const metricResult=await this.computeMetricWithGraphs(data,artifacts,{
-speedline,
-fcpResult});
-
-metricResult.timing=Math.max(metricResult.timing,fcpResult.timing);
-return metricResult;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-static computeLayoutBasedSpeedIndex(nodeTimings,fcpTimeInMs){
-
-const layoutWeights=[];
-for(const[node,timing]of nodeTimings.entries()){
-if(node.type!==BaseNode.TYPES.CPU)continue;
-
-if(node.childEvents.some(x=>x.name==='Layout')){
-const timingWeight=Math.max(Math.log2(timing.endTime-timing.startTime),0);
-layoutWeights.push({time:timing.endTime,weight:timingWeight});
-}
-}
-
-if(!layoutWeights.length){
-return fcpTimeInMs;
-}
-
-const totalWeightedTime=layoutWeights.
-map(evt=>evt.weight*Math.max(evt.time,fcpTimeInMs)).
-reduce((a,b)=>a+b,0);
-const totalWeight=layoutWeights.map(evt=>evt.weight).reduce((a,b)=>a+b,0);
-return totalWeightedTime/totalWeight;
-}}
-
-
-module.exports=SpeedIndex;
-
-},{"../../../lib/dependency-graph/base-node":25,"./lantern-metric":13}],"./gather/computed/metrics/speed-index":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const MetricArtifact=require('./metric');
-
-class SpeedIndex extends MetricArtifact{
-get name(){
-return'SpeedIndex';
-}
-
-
-
-
-
-
-async computeObservedMetric(data,artifacts){
-const speedline=await artifacts.requestSpeedline(data.trace);
-const timing=Math.round(speedline.speedIndex);
-const timestamp=(timing+speedline.beginning)*1000;
-return Promise.resolve({timing,timestamp});
-}}
-
-
-module.exports=SpeedIndex;
-
-},{"./metric":14}],"./gather/computed/network-analysis":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const NetworkAnalyzer=require('../../lib/dependency-graph/simulator/network-analyzer');
-
-class NetworkAnalysis extends ComputedArtifact{
-get name(){
-return'NetworkAnalysis';
-}
-
-
-
-
-
-static computeRTTAndServerResponseTime(records){
-
-
-const rttByOrigin=new Map();
-for(const[origin,summary]of NetworkAnalyzer.estimateRTTByOrigin(records).entries()){
-rttByOrigin.set(origin,summary.min);
-}
-
-
-
-const minimumRtt=Math.min(...Array.from(rttByOrigin.values()));
-
-const responseTimeSummaries=NetworkAnalyzer.estimateServerResponseTimeByOrigin(records,{
-rttByOrigin});
-
-
-
-const additionalRttByOrigin=new Map();
-
-const serverResponseTimeByOrigin=new Map();
-for(const[origin,summary]of responseTimeSummaries.entries()){
-
-
-const rttForOrigin=rttByOrigin.get(origin);
-additionalRttByOrigin.set(origin,rttForOrigin-minimumRtt);
-serverResponseTimeByOrigin.set(origin,summary.median);
-}
-
-return{rtt:minimumRtt,additionalRttByOrigin,serverResponseTimeByOrigin,throughput:0};
-}
-
-
-
-
-
-
-async compute_(devtoolsLog,computedArtifacts){
-const records=await computedArtifacts.requestNetworkRecords(devtoolsLog);
-const throughput=await computedArtifacts.requestNetworkThroughput(devtoolsLog);
-const rttAndServerResponseTime=NetworkAnalysis.computeRTTAndServerResponseTime(records);
-rttAndServerResponseTime.throughput=throughput*8;
-return rttAndServerResponseTime;
-}}
-
-
-module.exports=NetworkAnalysis;
-
-},{"../../lib/dependency-graph/simulator/network-analyzer":30,"./computed-artifact":11}],"./gather/computed/network-records":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const NetworkRecorder=require('../../lib/network-recorder');
-
-class NetworkRecords extends ComputedArtifact{
-get name(){
-return'NetworkRecords';
-}
-
-
-
-
-
-async compute_(devtoolsLog){
-return NetworkRecorder.recordsFromLogs(devtoolsLog);
-}}
-
-
-module.exports=NetworkRecords;
-
-},{"../../lib/network-recorder":87,"./computed-artifact":11}],"./gather/computed/network-throughput":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-
-class NetworkThroughput extends ComputedArtifact{
-get name(){
-return'NetworkThroughput';
-}
-
-
-
-
-
-
-
-
-
-static getThroughput(networkRecords){
-let totalBytes=0;
-const timeBoundaries=networkRecords.reduce((boundaries,record)=>{
-const scheme=record.parsedURL&&record.parsedURL.scheme;
-if(scheme==='data'||record.failed||!record.finished||
-record.statusCode>300||!record.transferSize){
-return boundaries;
-}
-
-totalBytes+=record.transferSize;
-boundaries.push({time:record.responseReceivedTime,isStart:true});
-boundaries.push({time:record.endTime,isStart:false});
-return boundaries;
-},[]).sort((a,b)=>a.time-b.time);
-
-if(!timeBoundaries.length){
-return Infinity;
-}
-
-let inflight=0;
-let currentStart=0;
-let totalDuration=0;
-timeBoundaries.forEach(boundary=>{
-if(boundary.isStart){
-if(inflight===0){
-currentStart=boundary.time;
-}
-inflight++;
-}else{
-inflight--;
-if(inflight===0){
-totalDuration+=boundary.time-currentStart;
-}
-}
-});
-
-return totalBytes/totalDuration;
-}
-
-
-
-
-
-
-compute_(devtoolsLog,computedArtifacts){
-
-return computedArtifacts.requestNetworkRecords(devtoolsLog).
-then(NetworkThroughput.getThroughput);
-}}
-
-
-module.exports=NetworkThroughput;
-
-},{"./computed-artifact":11}],"./gather/computed/page-dependency-graph":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const NetworkNode=require('../../lib/dependency-graph/network-node');
-const CPUNode=require('../../lib/dependency-graph/cpu-node');
-const NetworkAnalyzer=require('../../lib/dependency-graph/simulator/network-analyzer');
-const TracingProcessor=require('../../lib/traces/tracing-processor');
-const NetworkRequest=require('../../lib/network-request');
-
-
-
-
-const MINIMUM_TASK_DURATION_OF_INTEREST=10;
-
-
-const IGNORED_MIME_TYPES_REGEX=/^video/;
-
-class PageDependencyGraphArtifact extends ComputedArtifact{
-get name(){
-return'PageDependencyGraph';
-}
-
-
-
-
-
-static getNetworkInitiators(record){
-if(!record.initiator)return[];
-if(record.initiator.url)return[record.initiator.url];
-if(record.initiator.type==='script'&&record.initiator.stack){
-const frames=record.initiator.stack.callFrames;
-return Array.from(new Set(frames.map(frame=>frame.url))).filter(Boolean);
-}
-
-return[];
-}
-
-
-
-
-
-static getNetworkNodeOutput(networkRecords){
-
-const nodes=[];
-const idToNodeMap=new Map();
-const urlToNodeMap=new Map();
-
-networkRecords.forEach(record=>{
-if(IGNORED_MIME_TYPES_REGEX.test(record.mimeType))return;
-
-
-
-
-
-while(idToNodeMap.has(record.requestId)){
-record.requestId+=':duplicate';
-}
-
-const node=new NetworkNode(record);
-nodes.push(node);
-
-const list=urlToNodeMap.get(record.url)||[];
-list.push(node);
-
-idToNodeMap.set(record.requestId,node);
-urlToNodeMap.set(record.url,list);
-});
-
-return{nodes,idToNodeMap,urlToNodeMap};
-}
-
-
-
-
-
-static getCPUNodes(traceOfTab){
-
-const nodes=[];
-let i=0;
-
-TracingProcessor.assertHasToplevelEvents(traceOfTab.mainThreadEvents);
-
-const minimumEvtDur=MINIMUM_TASK_DURATION_OF_INTEREST*1000;
-while(i<traceOfTab.mainThreadEvents.length){
-const evt=traceOfTab.mainThreadEvents[i];
-
-
-if(
-!TracingProcessor.isScheduleableTask(evt)||
-!evt.dur||
-evt.dur<minimumEvtDur)
-{
-i++;
-continue;
-}
-
-
-
-const children=[];
-i++;
-for(
-const endTime=evt.ts+evt.dur;
-i<traceOfTab.mainThreadEvents.length&&traceOfTab.mainThreadEvents[i].ts<endTime;
-i++)
-{
-children.push(traceOfTab.mainThreadEvents[i]);
-}
-
-nodes.push(new CPUNode(evt,children));
-}
-
-return nodes;
-}
-
-
-
-
-
-static linkNetworkNodes(rootNode,networkNodeOutput){
-networkNodeOutput.nodes.forEach(node=>{
-const initiators=PageDependencyGraphArtifact.getNetworkInitiators(node.record);
-if(initiators.length){
-initiators.forEach(initiator=>{
-const parentCandidates=networkNodeOutput.urlToNodeMap.get(initiator)||[rootNode];
-
-const parent=parentCandidates.length===1?parentCandidates[0]:rootNode;
-node.addDependency(parent);
-});
-}else if(node!==rootNode){
-rootNode.addDependent(node);
-}
-
-const redirects=Array.from(node.record.redirects||[]);
-redirects.push(node.record);
-
-for(let i=1;i<redirects.length;i++){
-const redirectNode=networkNodeOutput.idToNodeMap.get(redirects[i-1].requestId);
-const actualNode=networkNodeOutput.idToNodeMap.get(redirects[i].requestId);
-if(actualNode&&redirectNode){
-actualNode.addDependency(redirectNode);
-}
-}
-});
-}
-
-
-
-
-
-
-static linkCPUNodes(rootNode,networkNodeOutput,cpuNodes){
-
-function addDependentNetworkRequest(cpuNode,reqId){
-const networkNode=networkNodeOutput.idToNodeMap.get(reqId);
-if(!networkNode||
-
-networkNode.record.resourceType!==NetworkRequest.TYPES.XHR||
-
-
-networkNode.startTime<=cpuNode.startTime)return;
-cpuNode.addDependent(networkNode);
-}
-
-
-function addDependencyOnUrl(cpuNode,url){
-if(!url)return;
-
-
-const minimumAllowableTimeSinceNetworkNodeEnd=-100*1000;
-const candidates=networkNodeOutput.urlToNodeMap.get(url)||[];
-
-let minCandidate=null;
-let minDistance=Infinity;
-
-for(const candidate of candidates){
-
-
-if(cpuNode.startTime<=candidate.startTime)return;
-
-const distance=cpuNode.startTime-candidate.endTime;
-if(distance>=minimumAllowableTimeSinceNetworkNodeEnd&&distance<minDistance){
-minCandidate=candidate;
-minDistance=distance;
-}
-}
-
-if(!minCandidate)return;
-cpuNode.addDependency(minCandidate);
-}
-
-
-const timers=new Map();
-for(const node of cpuNodes){
-for(const evt of node.childEvents){
-if(!evt.args.data)continue;
-
-const argsUrl=evt.args.data.url;
-const stackTraceUrls=(evt.args.data.stackTrace||[]).map(l=>l.url).filter(Boolean);
-
-switch(evt.name){
-case'TimerInstall':
-
-timers.set(evt.args.data.timerId,node);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-case'TimerFire':{
-
-const installer=timers.get(evt.args.data.timerId);
-if(!installer)break;
-installer.addDependent(node);
-break;
-}
-
-case'InvalidateLayout':
-case'ScheduleStyleRecalculation':
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-
-case'EvaluateScript':
-
-addDependencyOnUrl(node,argsUrl);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-
-case'XHRReadyStateChange':
-
-
-if(evt.args.data.readyState!==4)break;
-
-
-addDependencyOnUrl(node,argsUrl);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-
-case'FunctionCall':
-case'v8.compile':
-
-addDependencyOnUrl(node,argsUrl);
-break;
-
-case'ParseAuthorStyleSheet':
-
-addDependencyOnUrl(node,evt.args.data.styleSheetUrl);
-break;
-
-case'ResourceSendRequest':
-
-addDependentNetworkRequest(node,evt.args.data.requestId);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;}
-
-}
-
-if(node.getNumberOfDependencies()===0){
-node.addDependency(rootNode);
-}
-}
-}
-
-
-
-
-
-
-static createGraph(traceOfTab,networkRecords){
-const networkNodeOutput=PageDependencyGraphArtifact.getNetworkNodeOutput(networkRecords);
-const cpuNodes=PageDependencyGraphArtifact.getCPUNodes(traceOfTab);
-
-const rootRequest=networkRecords.reduce((min,r)=>min.startTime<r.startTime?min:r);
-const rootNode=networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
-const mainDocumentRequest=NetworkAnalyzer.findMainDocument(networkRecords);
-const mainDocumentNode=networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
-
-if(!rootNode||!mainDocumentNode){
-
-throw new Error(`${rootNode?'mainDocument':'root'}Node not found.`);
-}
-
-PageDependencyGraphArtifact.linkNetworkNodes(rootNode,networkNodeOutput);
-PageDependencyGraphArtifact.linkCPUNodes(rootNode,networkNodeOutput,cpuNodes);
-mainDocumentNode.setIsMainDocument(true);
-
-if(NetworkNode.hasCycle(rootNode)){
-throw new Error('Invalid dependency graph created, cycle detected');
-}
-
-return rootNode;
-}
-
-
-
-
-
-static printGraph(rootNode,widthInCharacters=100){
-
-function padRight(str,target,padChar=' '){
-return str+padChar.repeat(Math.max(target-str.length,0));
-}
-
-
-const nodes=[];
-rootNode.traverse(node=>nodes.push(node));
-nodes.sort((a,b)=>a.startTime-b.startTime);
-
-const min=nodes[0].startTime;
-const max=nodes.reduce((max,node)=>Math.max(max,node.endTime),0);
-
-const totalTime=max-min;
-const timePerCharacter=totalTime/widthInCharacters;
-nodes.forEach(node=>{
-const offset=Math.round((node.startTime-min)/timePerCharacter);
-const length=Math.ceil((node.endTime-node.startTime)/timePerCharacter);
-const bar=padRight('',offset)+padRight('',length,'=');
-
-
-const displayName=node.record?node.record.url:node.type;
-
-console.log(padRight(bar,widthInCharacters),`| ${displayName.slice(0,30)}`);
-});
-}
-
-
-
-
-
-
-async compute_(data,artifacts){
-const trace=data.trace;
-const devtoolsLog=data.devtoolsLog;
-const[traceOfTab,networkRecords]=await Promise.all([
-artifacts.requestTraceOfTab(trace),
-artifacts.requestNetworkRecords(devtoolsLog)]);
-
-
-return PageDependencyGraphArtifact.createGraph(traceOfTab,networkRecords);
-}}
-
-
-module.exports=PageDependencyGraphArtifact;
-
-
-
-
-
-
-
-
-},{"../../lib/dependency-graph/cpu-node":26,"../../lib/dependency-graph/network-node":27,"../../lib/dependency-graph/simulator/network-analyzer":30,"../../lib/network-request":88,"../../lib/traces/tracing-processor":95,"./computed-artifact":11}],"./gather/computed/pushed-requests":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-
-class PushedRequests extends ComputedArtifact{
-get name(){
-return'PushedRequests';
-}
-
-
-
-
-
-
-
-compute_(devtoolsLog,artifacts){
-return artifacts.requestNetworkRecords(devtoolsLog).then(records=>{
-const pushedRecords=records.filter(r=>r.timing&&!!r.timing.pushStart);
-return pushedRecords;
-});
-}}
-
-
-module.exports=PushedRequests;
-
-},{"./computed-artifact":11}],"./gather/computed/screenshots":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-
-const SCREENSHOT_TRACE_NAME='Screenshot';
-
-class ScreenshotFilmstrip extends ComputedArtifact{
-get name(){
-return'Screenshots';
-}
-
-
-
-
-
-async compute_(trace){
-return trace.traceEvents.
-filter(evt=>evt.name===SCREENSHOT_TRACE_NAME).
-map(evt=>{
-return{
-timestamp:evt.ts/1000,
-datauri:`data:image/jpeg;base64,${evt.args.snapshot}`};
-
-});
-}}
-
-
-module.exports=ScreenshotFilmstrip;
-
-},{"./computed-artifact":11}],"./gather/computed/speedline":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const speedline=require('speedline-core');
-const LHError=require('../../lib/lh-error');
-
-class Speedline extends ComputedArtifact{
-get name(){
-return'Speedline';
-}
-
-
-
-
-
-
-compute_(trace,computedArtifacts){
-
-
-return computedArtifacts.requestTraceOfTab(trace).then(traceOfTab=>{
-
-
-const traceEvents=trace.traceEvents.slice();
-
-
-const navStart=traceOfTab.timestamps.navigationStart;
-return speedline(traceEvents,{
-timeOrigin:navStart,
-fastMode:true,
-include:'speedIndex'});
-
-}).catch(err=>{
-if(/No screenshots found in trace/.test(err.message)){
-throw new LHError(LHError.errors.NO_SCREENSHOTS);
-}
-
-throw err;
-}).then(speedline=>{
-if(speedline.frames.length===0){
-throw new LHError(LHError.errors.NO_SPEEDLINE_FRAMES);
-}
-
-if(speedline.speedIndex===0){
-throw new LHError(LHError.errors.SPEEDINDEX_OF_ZERO);
-}
-
-return speedline;
-});
-}}
-
-
-module.exports=Speedline;
-
-},{"../../lib/lh-error":85,"./computed-artifact":11,"speedline-core":186}],"./gather/computed/trace-of-tab":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-const ComputedArtifact=require('./computed-artifact');
-const log=require('lighthouse-logger');
-const TracingProcessor=require('../../lib/traces/tracing-processor');
-const LHError=require('../../lib/lh-error');
-const Sentry=require('../../lib/sentry');
-
-const ACCEPTABLE_NAVIGATION_URL_REGEX=/^(chrome|https?):/;
-
-class TraceOfTab extends ComputedArtifact{
-get name(){
-return'TraceOfTab';
-}
-
-
-
-
-
-
-static isNavigationStartOfInterest(event){
-return event.name==='navigationStart'&&(
-!event.args.data||!event.args.data.documentLoaderURL||
-ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL));
-}
-
-
-
-
-
-static filteredStableSort(traceEvents,filter){
-
-const indices=[];
-for(let srcIndex=0;srcIndex<traceEvents.length;srcIndex++){
-if(filter(traceEvents[srcIndex])){
-indices.push(srcIndex);
-}
-}
-
-
-indices.sort((indexA,indexB)=>{
-const result=traceEvents[indexA].ts-traceEvents[indexB].ts;
-return result?result:indexA-indexB;
-});
-
-
-const sorted=[];
-for(let i=0;i<indices.length;i++){
-sorted.push(traceEvents[indices[i]]);
-}
-
-return sorted;
-}
-
-
-
-
-
-
-
-
-async compute_(trace){
-
-
-const keyEvents=TraceOfTab.filteredStableSort(trace.traceEvents,e=>{
-return e.cat.includes('blink.user_timing')||
-e.cat.includes('loading')||
-e.cat.includes('devtools.timeline')||
-e.cat==='__metadata';
-});
-
-
-const{startedInPageEvt,frameId}=TracingProcessor.findTracingStartedEvt(keyEvents);
-
-
-const frameEvents=keyEvents.filter(e=>e.args.frame===frameId);
-
-
-const navigationStart=frameEvents.filter(TraceOfTab.isNavigationStartOfInterest).pop();
-if(!navigationStart)throw new LHError(LHError.errors.NO_NAVSTART);
-
-
-const firstPaint=frameEvents.find(e=>e.name==='firstPaint'&&e.ts>navigationStart.ts);
-
-
-const firstContentfulPaint=frameEvents.find(
-e=>e.name==='firstContentfulPaint'&&e.ts>navigationStart.ts);
-
-if(!firstContentfulPaint)throw new LHError(LHError.errors.NO_FCP);
-
-
-let firstMeaningfulPaint=frameEvents.find(
-e=>e.name==='firstMeaningfulPaint'&&e.ts>navigationStart.ts);
-
-let fmpFellBack=false;
-
-
-
-
-
-if(!firstMeaningfulPaint){
-
-Sentry.captureMessage('No firstMeaningfulPaint found, using fallback',{level:'warning'});
-
-const fmpCand='firstMeaningfulPaintCandidate';
-fmpFellBack=true;
-log.verbose('trace-of-tab',`No firstMeaningfulPaint found, falling back to last ${fmpCand}`);
-const lastCandidate=frameEvents.filter(e=>e.name===fmpCand).pop();
-if(!lastCandidate){
-log.verbose('trace-of-tab','No `firstMeaningfulPaintCandidate` events found in trace');
-}
-firstMeaningfulPaint=lastCandidate;
-}
-
-const load=frameEvents.find(e=>e.name==='loadEventEnd'&&e.ts>navigationStart.ts);
-const domContentLoaded=frameEvents.find(
-e=>e.name==='domContentLoadedEventEnd'&&e.ts>navigationStart.ts);
-
-
-
-
-const processEvents=TraceOfTab.
-filteredStableSort(trace.traceEvents,e=>e.pid===startedInPageEvt.pid);
-
-const mainThreadEvents=processEvents.
-filter(e=>e.tid===startedInPageEvt.tid);
-
-
-const traceEnd=trace.traceEvents.reduce((max,evt)=>{
-return max.ts>evt.ts?max:evt;
-});
-const fakeEndOfTraceEvt={ts:traceEnd.ts+(traceEnd.dur||0)};
-
-
-const getTimestamp=event=>event&&event.ts;
-
-const timestamps={
-navigationStart:navigationStart.ts,
-firstPaint:getTimestamp(firstPaint),
-firstContentfulPaint:firstContentfulPaint.ts,
-firstMeaningfulPaint:getTimestamp(firstMeaningfulPaint),
-traceEnd:fakeEndOfTraceEvt.ts,
-load:getTimestamp(load),
-domContentLoaded:getTimestamp(domContentLoaded)};
-
-
-
-
-const getTiming=ts=>(ts-navigationStart.ts)/1000;
-
-const maybeGetTiming=ts=>ts===undefined?undefined:getTiming(ts);
-
-const timings={
-navigationStart:0,
-firstPaint:maybeGetTiming(timestamps.firstPaint),
-firstContentfulPaint:getTiming(timestamps.firstContentfulPaint),
-firstMeaningfulPaint:maybeGetTiming(timestamps.firstMeaningfulPaint),
-traceEnd:getTiming(timestamps.traceEnd),
-load:maybeGetTiming(timestamps.load),
-domContentLoaded:maybeGetTiming(timestamps.domContentLoaded)};
-
-
-return{
-timings,
-timestamps,
-processEvents,
-mainThreadEvents,
-startedInPageEvt,
-navigationStartEvt:navigationStart,
-firstPaintEvt:firstPaint,
-firstContentfulPaintEvt:firstContentfulPaint,
-firstMeaningfulPaintEvt:firstMeaningfulPaint,
-loadEvt:load,
-domContentLoadedEvt:domContentLoaded,
-fmpFellBack};
-
-}}
-
-
-module.exports=TraceOfTab;
-
-},{"../../lib/lh-error":85,"../../lib/sentry":90,"../../lib/traces/tracing-processor":95,"./computed-artifact":11,"lighthouse-logger":147}],1:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const Audit=require('../audit');
-
-class AxeAudit extends Audit{
-
-
-
-
-
-static audit(artifacts){
-
-
-
-const notApplicables=artifacts.Accessibility.notApplicable||[];
-const isNotApplicable=notApplicables.find(result=>result.id===this.meta.id);
-if(isNotApplicable){
-return{
-rawValue:true,
-notApplicable:true};
-
-}
-
-const violations=artifacts.Accessibility.violations||[];
-const rule=violations.find(result=>result.id===this.meta.id);
-const impact=rule&&rule.impact;
-const tags=rule&&rule.tags;
-
-
-let items=[];
-if(rule&&rule.nodes){
-items=rule.nodes.map(node=>({
-node:{
-type:'node',
-selector:Array.isArray(node.target)?node.target.join(' '):'',
-path:node.path,
-snippet:node.html||node.snippet,
-explanation:node.failureSummary}}));
-
-
-}
-
-const headings=[
-{key:'node',itemType:'node',text:'Failing Elements'}];
-
-
-return{
-rawValue:typeof rule==='undefined',
-extendedInfo:{
-value:rule},
-
-details:{...Audit.makeTableDetails(headings,items),impact,tags}};
-
-}}
-
-
-module.exports=AxeAudit;
-
-},{"../audit":2}],2:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const statistics=require('../lib/statistics');
-const Util=require('../report/html/renderer/util');
-
-const DEFAULT_PASS='defaultPass';
-
-
-
-
-
-
-const clampTo2Decimals=val=>Math.round(val*100)/100;
-
-class Audit{
-
-
-
-static get DEFAULT_PASS(){
-return DEFAULT_PASS;
-}
-
-
-
-
-static get SCORING_MODES(){
-return{
-NUMERIC:'numeric',
-BINARY:'binary',
-MANUAL:'manual',
-INFORMATIVE:'informative',
-NOT_APPLICABLE:'not-applicable',
-ERROR:'error'};
-
-}
-
-
-
-
-static get meta(){
-throw new Error('Audit meta information must be overridden.');
-}
-
-
-
-
-static get defaultOptions(){
-return{};
-}
-
-
-
-
-
-
-
-
-
-static audit(artifacts,context){
-throw new Error('audit() method must be overriden');
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-static computeLogNormalScore(measuredValue,diminishingReturnsValue,medianValue){
-const distribution=statistics.getLogNormalDistribution(
-medianValue,
-diminishingReturnsValue);
-
-
-let score=distribution.computeComplementaryPercentile(measuredValue);
-score=Math.min(1,score);
-score=Math.max(0,score);
-return clampTo2Decimals(score);
-}
-
-
-
-
-
-
-static generateErrorAuditResult(audit,errorMessage){
-return Audit.generateAuditResult(audit,{
-rawValue:null,
-errorMessage});
-
-}
-
-
-
-
-
-
-
-static makeTableDetails(headings,results,summary){
-if(results.length===0){
-return{
-type:'table',
-headings:[],
-items:[],
-summary};
-
-}
-
-return{
-type:'table',
-headings:headings,
-items:results,
-summary};
-
-}
-
-
-
-
-
-
-
-
-static makeOpportunityDetails(headings,items,overallSavingsMs,overallSavingsBytes){
-return{
-type:'opportunity',
-headings:items.length===0?[]:headings,
-items,
-overallSavingsMs,
-overallSavingsBytes};
-
-}
-
-
-
-
-
-
-static _normalizeAuditScore(audit,result){
-
-let score=result.score===undefined?Number(result.rawValue):result.score;
-
-if(!Number.isFinite(score))throw new Error(`Invalid score: ${score}`);
-if(score>1)throw new Error(`Audit score for ${audit.meta.id} is > 1`);
-if(score<0)throw new Error(`Audit score for ${audit.meta.id} is < 0`);
-
-score=clampTo2Decimals(score);
-
-const scoreDisplayMode=audit.meta.scoreDisplayMode||Audit.SCORING_MODES.BINARY;
-
-return{
-score,
-scoreDisplayMode};
-
-}
-
-
-
-
-
-
-static generateAuditResult(audit,result){
-if(typeof result.rawValue==='undefined'){
-throw new Error('generateAuditResult requires a rawValue');
-}
-
-
-let{score,scoreDisplayMode}=Audit._normalizeAuditScore(audit,result);
-
-
-if(result.notApplicable){
-scoreDisplayMode=Audit.SCORING_MODES.NOT_APPLICABLE;
-result.rawValue=true;
-}
-
-if(result.errorMessage){
-scoreDisplayMode=Audit.SCORING_MODES.ERROR;
-}
-
-let auditTitle=audit.meta.title;
-if(audit.meta.failureTitle){
-if(Number(score)<Util.PASS_THRESHOLD){
-auditTitle=audit.meta.failureTitle;
-}
-}
-
-if(scoreDisplayMode!==Audit.SCORING_MODES.BINARY&&
-scoreDisplayMode!==Audit.SCORING_MODES.NUMERIC){
-score=null;
-}
-
-return{
-id:audit.meta.id,
-title:auditTitle,
-description:audit.meta.description,
-
-score,
-scoreDisplayMode,
-rawValue:result.rawValue,
-
-displayValue:result.displayValue,
-explanation:result.explanation,
-errorMessage:result.errorMessage,
-warnings:result.warnings,
-
-details:result.details};
-
-}}
-
-
-module.exports=Audit;
-
-},{"../lib/statistics":91,"../report/html/renderer/util":97}],3:[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const linearInterpolation=require('../../lib/statistics').linearInterpolation;
-const Interactive=require('../../gather/computed/metrics/lantern-interactive');
-const i18n=require('../../lib/i18n/i18n.js');
-
-const str_=i18n.createMessageInstanceIdFn(__filename,{});
-
-
-
-
-const KB_IN_BYTES=1024;
-
-const WASTED_MS_FOR_AVERAGE=300;
-const WASTED_MS_FOR_POOR=750;
-const WASTED_MS_FOR_SCORE_OF_ZERO=5000;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class UnusedBytes extends Audit{
-
-
-
-
-
-
-static scoreForWastedMs(wastedMs){
-if(wastedMs===0){
-return 1;
-}else if(wastedMs<WASTED_MS_FOR_AVERAGE){
-return linearInterpolation(0,1,WASTED_MS_FOR_AVERAGE,0.75,wastedMs);
-}else if(wastedMs<WASTED_MS_FOR_POOR){
-return linearInterpolation(WASTED_MS_FOR_AVERAGE,0.75,WASTED_MS_FOR_POOR,0.5,wastedMs);
-}else{
-return Math.max(
-0,
-linearInterpolation(WASTED_MS_FOR_POOR,0.5,WASTED_MS_FOR_SCORE_OF_ZERO,0,wastedMs));
-
-}
-}
-
-
-
-
-
-
-static bytesToMs(bytes,networkThroughput){
-const milliseconds=bytes/networkThroughput*1000;
-return milliseconds;
-}
-
-
-
-
-
-
-
-
-
-
-
-static estimateTransferSize(networkRecord,totalBytes,resourceType,compressionRatio=0.5){
-if(!networkRecord){
-
-
-
-return Math.round(totalBytes*compressionRatio);
-}else if(networkRecord.resourceType===resourceType){
-
-return networkRecord.transferSize||0;
-}else{
-
-
-const transferSize=networkRecord.transferSize||0;
-const resourceSize=networkRecord.resourceSize;
-const compressionRatio=resourceSize!==undefined?transferSize/resourceSize:1;
-return Math.round(totalBytes*compressionRatio);
-}
-}
-
-
-
-
-
-
-static audit(artifacts,context){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const settings=context&&context.settings||{};
-const simulatorOptions={
-devtoolsLog,
-settings};
-
-
-return artifacts.
-requestNetworkRecords(devtoolsLog).
-then(networkRecords=>
-Promise.all([
-this.audit_(artifacts,networkRecords,context),
-artifacts.requestPageDependencyGraph({trace,devtoolsLog}),
-artifacts.requestLoadSimulator(simulatorOptions)])).
-
-
-then(([result,graph,simulator])=>this.createAuditProduct(result,graph,simulator));
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-static computeWasteWithTTIGraph(results,graph,simulator,options){
-options=Object.assign({includeLoad:true,label:this.meta.id},options);
-const beforeLabel=`${options.label}-before`;
-const afterLabel=`${options.label}-after`;
-
-const simulationBeforeChanges=simulator.simulate(graph,{label:beforeLabel});
-
-const resultsByUrl=new Map();
-for(const result of results){
-resultsByUrl.set(result.url,result);
-}
-
-
-
-const originalTransferSizes=new Map();
-graph.traverse(node=>{
-if(node.type!=='network')return;
-const result=resultsByUrl.get(node.record.url);
-if(!result)return;
-
-const original=node.record.transferSize;
-originalTransferSizes.set(node.record.requestId,original);
-
-const wastedBytes=result.wastedBytes;
-node.record.transferSize=Math.max(original-wastedBytes,0);
-});
-
-const simulationAfterChanges=simulator.simulate(graph,{label:afterLabel});
-
-
-graph.traverse(node=>{
-if(node.type!=='network')return;
-const originalTransferSize=originalTransferSizes.get(node.record.requestId);
-if(originalTransferSize===undefined)return;
-node.record.transferSize=originalTransferSize;
-});
-
-const savingsOnOverallLoad=simulationBeforeChanges.timeInMs-simulationAfterChanges.timeInMs;
-const savingsOnTTI=Interactive.getLastLongTaskEndTime(simulationBeforeChanges.nodeTimings)-
-Interactive.getLastLongTaskEndTime(simulationAfterChanges.nodeTimings);
-
-let savings=savingsOnTTI;
-if(options.includeLoad)savings=Math.max(savings,savingsOnOverallLoad);
-
-
-return Math.round(Math.max(savings,0)/10)*10;
-}
-
-
-
-
-
-
-
-static createAuditProduct(result,graph,simulator){
-const results=result.items.sort((itemA,itemB)=>itemB.wastedBytes-itemA.wastedBytes);
-
-const wastedBytes=results.reduce((sum,item)=>sum+item.wastedBytes,0);
-const wastedKb=Math.round(wastedBytes/KB_IN_BYTES);
-const wastedMs=this.computeWasteWithTTIGraph(results,graph,simulator);
-
-
-let displayValue=result.displayValue||'';
-if(typeof result.displayValue==='undefined'&&wastedBytes){
-displayValue=str_(i18n.UIStrings.displayValueByteSavings,{wastedBytes});
-}
-
-const details=Audit.makeOpportunityDetails(result.headings,results,wastedMs,wastedBytes);
-
-return{
-explanation:result.explanation,
-warnings:result.warnings,
-displayValue,
-rawValue:wastedMs,
-score:UnusedBytes.scoreForWastedMs(wastedMs),
-extendedInfo:{
-value:{
-wastedMs,
-wastedKb,
-results}},
-
-
-details};
-
-}
-
-
-
-
-
-
-
-
-
-static audit_(artifacts,networkRecords,context){
-throw new Error('audit_ unimplemented');
-}}
-
-
-
-
-module.exports=UnusedBytes;
-
-}).call(this,"/../lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js");
-},{"../../gather/computed/metrics/lantern-interactive":"./gather/computed/metrics/lantern-interactive","../../lib/i18n/i18n.js":36,"../../lib/statistics":91,"../audit":2}],4:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const Audit=require('../audit');
-
-class ManualAudit extends Audit{
-
-
-
-static get partialMeta(){
-return{
-scoreDisplayMode:Audit.SCORING_MODES.MANUAL,
-requiredArtifacts:[]};
-
-}
-
-
-
-
-static audit(){
-return{
-rawValue:false};
-
-
-}}
-
-
-module.exports=ManualAudit;
-
-},{"../audit":2}],5:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-const Audit=require('./audit');
-
-class MultiCheckAudit extends Audit{
-
-
-
-
-
-static async audit(artifacts,context){
-const multiProduct=await this.audit_(artifacts,context);
-return this.createAuditProduct(multiProduct);
-}
-
-
-
-
-
-static createAuditProduct(result){
-
-const detailsItem={
-...result,
-...result.manifestValues,
-manifestValues:undefined,
-warnings:undefined,
-allChecks:undefined};
-
-
-if(result.manifestValues&&result.manifestValues.allChecks){
-result.manifestValues.allChecks.forEach(check=>{
-detailsItem[check.id]=check.passing;
-});
-}
-
-const details={items:[detailsItem]};
-
-
-if(result.failures.length>0){
-return{
-rawValue:false,
-explanation:`Failures: ${result.failures.join(',\n')}.`,
-details};
-
-}
-
-
-return{
-rawValue:true,
-details,
-warnings:result.warnings};
-
-}
-
-
-
-
-
-
-
-
-static audit_(artifacts,context){
-throw new Error('audit_ unimplemented');
-}}
-
-
-
-
-module.exports=MultiCheckAudit;
-
-},{"./audit":2}],6:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-class ViolationAudit extends Audit{
-
-
-
-
-
-static getViolationResults(artifacts,pattern){
-const seen=new Set();
-return artifacts.ChromeConsoleMessages.
-map(message=>message.entry).
-filter(entry=>entry.url&&entry.source==='violation'&&pattern.test(entry.text)).
-map(entry=>({label:`line: ${entry.lineNumber}`,url:entry.url})).
-filter(entry=>{
-
-
-const key=`${entry.url}!${entry.label}`;
-if(seen.has(key))return false;
-seen.add(key);
-return true;
-});
-}}
-
-
-module.exports=ViolationAudit;
-
-},{"./audit":2}],7:[function(require,module,exports){
-(function(__dirname){
-
-
-
-
-
-'use strict';
-
-const defaultConfigPath='./default-config.js';
-const defaultConfig=require('./default-config.js');
-const fullConfig=require('./full-config.js');
-const constants=require('./constants.js');
-const i18n=require('./../lib/i18n/i18n.js');
-
-const isDeepEqual=require('lodash.isequal');
-const log=require('lighthouse-logger');
-const path=require('path');
-const Audit=require('../audits/audit.js');
-const Runner=require('../runner.js');
-
-
-
-
-
-
-
-
-function validatePasses(passes,audits){
-if(!Array.isArray(passes)){
-return;
-}
-
-const requiredGatherers=Config.getGatherersNeededByAudits(audits);
-
-
-passes.forEach(pass=>{
-pass.gatherers.forEach(gathererDefn=>{
-const gatherer=gathererDefn.instance;
-const isGatherRequiredByAudits=requiredGatherers.has(gatherer.name);
-if(!isGatherRequiredByAudits){
-const msg=`${gatherer.name} gatherer requested, however no audit requires it.`;
-log.warn('config',msg);
-}
-});
-});
-
-
-const usedNames=new Set();
-passes.forEach(pass=>{
-const passName=pass.passName;
-if(usedNames.has(passName)){
-throw new Error(`Passes must have unique names (repeated passName: ${passName}.`);
-}
-usedNames.add(passName);
-});
-}
-
-
-
-
-
-
-function validateCategories(categories,audits,groups){
-if(!categories){
-return;
-}
-
-Object.keys(categories).forEach(categoryId=>{
-categories[categoryId].auditRefs.forEach((auditRef,index)=>{
-if(!auditRef.id){
-throw new Error(`missing an audit id at ${categoryId}[${index}]`);
-}
-
-const audit=audits&&audits.find(a=>a.implementation.meta.id===auditRef.id);
-if(!audit){
-throw new Error(`could not find ${auditRef.id} audit for category ${categoryId}`);
-}
-
-const auditImpl=audit.implementation;
-const isManual=auditImpl.meta.scoreDisplayMode==='manual';
-if(categoryId==='accessibility'&&!auditRef.group&&!isManual){
-throw new Error(`${auditRef.id} accessibility audit does not have a group`);
-}
-
-if(auditRef.weight>0&&isManual){
-throw new Error(`${auditRef.id} is manual but has a positive weight`);
-}
-
-if(auditRef.group&&(!groups||!groups[auditRef.group])){
-throw new Error(`${auditRef.id} references unknown group ${auditRef.group}`);
-}
-});
-});
-}
-
-
-
-
-
-function assertValidAudit(auditDefinition,auditPath){
-const auditName=auditPath||
-auditDefinition&&auditDefinition.meta&&auditDefinition.meta.id;
-
-if(typeof auditDefinition.audit!=='function'||auditDefinition.audit===Audit.audit){
-throw new Error(`${auditName} has no audit() method.`);
-}
-
-if(typeof auditDefinition.meta.id!=='string'){
-throw new Error(`${auditName} has no meta.id property, or the property is not a string.`);
-}
-
-if(typeof auditDefinition.meta.title!=='string'){
-throw new Error(
-`${auditName} has no meta.title property, or the property is not a string.`);
-
-}
-
-
-if(typeof auditDefinition.meta.failureTitle!=='string'&&
-auditDefinition.meta.scoreDisplayMode===Audit.SCORING_MODES.BINARY){
-throw new Error(`${auditName} has no failureTitle and should.`);
-}
-
-if(typeof auditDefinition.meta.description!=='string'){
-throw new Error(
-`${auditName} has no meta.description property, or the property is not a string.`);
-
-}else if(auditDefinition.meta.description===''){
-throw new Error(
-`${auditName} has an empty meta.description string. Please add a description for the UI.`);
-
-}
-
-if(!Array.isArray(auditDefinition.meta.requiredArtifacts)){
-throw new Error(
-`${auditName} has no meta.requiredArtifacts property, or the property is not an array.`);
-
-}
-}
-
-
-
-
-
-function assertValidGatherer(gathererInstance,gathererName){
-gathererName=gathererName||gathererInstance.name||'gatherer';
-
-if(typeof gathererInstance.beforePass!=='function'){
-throw new Error(`${gathererName} has no beforePass() method.`);
-}
-
-if(typeof gathererInstance.pass!=='function'){
-throw new Error(`${gathererName} has no pass() method.`);
-}
-
-if(typeof gathererInstance.afterPass!=='function'){
-throw new Error(`${gathererName} has no afterPass() method.`);
-}
-}
-
-
-
-
-
-
-
-function cleanFlagsForSettings(flags={}){
-
-const settings={};
-
-for(const key of Object.keys(flags)){
-
-if(typeof constants.defaultSettings[key]!=='undefined'){
-
-const safekey=key;
-settings[safekey]=flags[safekey];
-}
-}
-
-return settings;
-}
-
-
-
-
-
-
-
-
-function _merge(base,extension,overwriteArrays=false){
-
-if(typeof base==='undefined'||base===null){
-return extension;
-}else if(typeof extension==='undefined'){
-return base;
-}else if(Array.isArray(extension)){
-if(overwriteArrays)return extension;
-if(!Array.isArray(base))throw new TypeError(`Expected array but got ${typeof base}`);
-const merged=base.slice();
-extension.forEach(item=>{
-if(!merged.some(candidate=>isDeepEqual(candidate,item)))merged.push(item);
-});
-
-return merged;
-}else if(typeof extension==='object'){
-if(typeof base!=='object')throw new TypeError(`Expected object but got ${typeof base}`);
-if(Array.isArray(base))throw new TypeError('Expected object but got Array');
-Object.keys(extension).forEach(key=>{
-const localOverwriteArrays=overwriteArrays||
-key==='settings'&&typeof base[key]==='object';
-base[key]=_merge(base[key],extension[key],localOverwriteArrays);
-});
-return base;
-}
-
-return extension;
-}
-
-
-
-
-
-
-const merge=_merge;
-
-
-
-
-
-
-function cloneArrayWithPluginSafety(array){
-return array.map(item=>{
-if(typeof item==='object'){
-
-return Object.assign(
-Object.create(
-Object.getPrototypeOf(item)),
-
-item);
-
-}
-
-return item;
-});
-}
-
-
-
-
-
-
-
-
-function deepClone(json){
-return JSON.parse(JSON.stringify(json));
-}
-
-
-
-
-
-
-
-function deepCloneConfigJson(json){
-const cloned=deepClone(json);
-
-
-
-if(Array.isArray(cloned.passes)&&Array.isArray(json.passes)){
-for(let i=0;i<cloned.passes.length;i++){
-const pass=cloned.passes[i];
-pass.gatherers=cloneArrayWithPluginSafety(json.passes[i].gatherers||[]);
-}
-}
-
-if(Array.isArray(json.audits)){
-cloned.audits=cloneArrayWithPluginSafety(json.audits);
-}
-
-return cloned;
-}
-
-
-
-
-
-
-
-
-
-const mergeOptionsOfItems=function(items){
-
-const mergedItems=[];
-
-for(const item of items){
-const existingItem=item.path&&mergedItems.find(candidate=>candidate.path===item.path);
-if(!existingItem){
-mergedItems.push(item);
-continue;
-}
-
-existingItem.options=Object.assign({},existingItem.options,item.options);
-}
-
-return mergedItems;
-};
-
-class Config{
-
-
-
-
-
-
-constructor(configJSON,flags){
-let configPath=flags&&flags.configPath;
-
-if(!configJSON){
-configJSON=defaultConfig;
-configPath=path.resolve(__dirname,defaultConfigPath);
-}
-
-if(configPath&&!path.isAbsolute(configPath)){
-throw new Error('configPath must be an absolute path.');
-}
-
-
-configJSON=deepCloneConfigJson(configJSON);
-
-
-if(configJSON.extends==='lighthouse:full'){
-const explodedFullConfig=Config.extendConfigJSON(deepCloneConfigJson(defaultConfig),
-deepCloneConfigJson(fullConfig));
-configJSON=Config.extendConfigJSON(explodedFullConfig,configJSON);
-}else if(configJSON.extends){
-configJSON=Config.extendConfigJSON(deepCloneConfigJson(defaultConfig),configJSON);
-}
-
-
-const configDir=configPath?path.dirname(configPath):undefined;
-
-const settings=Config.initSettings(configJSON.settings,flags);
-
-
-const passesWithDefaults=Config.augmentPassesWithDefaults(configJSON.passes);
-Config.adjustDefaultPassForThrottling(settings,passesWithDefaults);
-const passes=Config.requireGatherers(passesWithDefaults,configDir);
-
-
-this.settings=settings;
-
-this.passes=passes;
-
-this.audits=Config.requireAudits(configJSON.audits,configDir);
-
-this.categories=configJSON.categories||null;
-
-this.groups=configJSON.groups||null;
-
-Config.filterConfigIfNeeded(this);
-
-validatePasses(this.passes,this.audits);
-validateCategories(this.categories,this.audits,this.groups);
-
-
-
-const configJson=this;
-}
-
-
-
-
-
-
-getPrintString(){
-const jsonConfig=deepClone(this);
-
-if(jsonConfig.passes){
-for(const pass of jsonConfig.passes){
-for(const gathererDefn of pass.gatherers){
-gathererDefn.implementation=undefined;
-
-gathererDefn.instance=undefined;
-if(Object.keys(gathererDefn.options).length===0){
-
-gathererDefn.options=undefined;
-}
-}
-}
-}
-
-if(jsonConfig.audits){
-for(const auditDefn of jsonConfig.audits){
-
-auditDefn.implementation=undefined;
-if(Object.keys(auditDefn.options).length===0){
-
-auditDefn.options=undefined;
-}
-}
-}
-
-
-i18n.replaceIcuMessageInstanceIds(jsonConfig,jsonConfig.settings.locale);
-
-return JSON.stringify(jsonConfig,null,2);
-}
-
-
-
-
-
-
-static extendConfigJSON(baseJSON,extendJSON){
-if(extendJSON.passes&&baseJSON.passes){
-for(const pass of extendJSON.passes){
-
-const passName=pass.passName||constants.defaultPassConfig.passName;
-const basePass=baseJSON.passes.find(candidate=>candidate.passName===passName);
-
-if(!basePass){
-baseJSON.passes.push(pass);
-}else{
-merge(basePass,pass);
-}
-}
-
-delete extendJSON.passes;
-}
-
-return merge(baseJSON,extendJSON);
-}
-
-
-
-
-
-static augmentPassesWithDefaults(passes){
-if(!passes){
-return null;
-}
-
-const{defaultPassConfig}=constants;
-return passes.map(pass=>merge(deepClone(defaultPassConfig),pass));
-}
-
-
-
-
-
-
-static initSettings(settingsJson={},flags){
-
-
-
-const locale=i18n.lookupLocale(flags&&flags.locale||settingsJson.locale);
-
-
-const{defaultSettings}=constants;
-const settingWithDefaults=merge(deepClone(defaultSettings),settingsJson,true);
-
-
-const settingsWithFlags=merge(settingWithDefaults||{},cleanFlagsForSettings(flags),true);
-
-
-settingsWithFlags.locale=locale;
-
-return settingsWithFlags;
-}
-
-
-
-
-
-
-static expandAuditShorthand(audits){
-if(!audits){
-return null;
-}
-
-const newAudits=audits.map(audit=>{
-if(typeof audit==='string'){
-
-return{path:audit,options:{}};
-}else if('implementation'in audit&&typeof audit.implementation.audit==='function'){
-
-return audit;
-}else if('path'in audit&&typeof audit.path==='string'){
-
-return audit;
-}else if('audit'in audit&&typeof audit.audit==='function'){
-
-return{implementation:audit,options:{}};
-}else{
-throw new Error('Invalid Audit type '+JSON.stringify(audit));
-}
-});
-
-return newAudits;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-static expandGathererShorthand(gatherers){
-const expanded=gatherers.map(gatherer=>{
-if(typeof gatherer==='string'){
-
-return{path:gatherer,options:{}};
-}else if('implementation'in gatherer||'instance'in gatherer){
-
-return gatherer;
-}else if('path'in gatherer){
-
-if(typeof gatherer.path!=='string'){
-throw new Error('Invalid Gatherer type '+JSON.stringify(gatherer));
-}
-return gatherer;
-}else if(typeof gatherer==='function'){
-
-return{implementation:gatherer,options:{}};
-}else if(gatherer&&typeof gatherer.beforePass==='function'){
-
-return{instance:gatherer,options:{}};
-}else{
-throw new Error('Invalid Gatherer type '+JSON.stringify(gatherer));
-}
-});
-
-return expanded;
-}
-
-
-
-
-
-
-
-static adjustDefaultPassForThrottling(settings,passes){
-if(!passes||
-settings.throttlingMethod!=='devtools'&&settings.throttlingMethod!=='provided'){
-return;
-}
-
-const defaultPass=passes.find(pass=>pass.passName==='defaultPass');
-if(!defaultPass)return;
-const overrides=constants.nonSimulatedPassConfigOverrides;
-defaultPass.pauseAfterLoadMs=
-Math.max(overrides.pauseAfterLoadMs,defaultPass.pauseAfterLoadMs);
-defaultPass.cpuQuietThresholdMs=
-Math.max(overrides.cpuQuietThresholdMs,defaultPass.cpuQuietThresholdMs);
-defaultPass.networkQuietThresholdMs=
-Math.max(overrides.networkQuietThresholdMs,defaultPass.networkQuietThresholdMs);
-}
-
-
-
-
-
-static filterConfigIfNeeded(config){
-const settings=config.settings;
-if(!settings.onlyCategories&&!settings.onlyAudits&&!settings.skipAudits){
-return;
-}
-
-
-const{categories,requestedAuditNames}=Config.filterCategoriesAndAudits(config.categories,
-settings);
-
-
-const audits=config.audits&&config.audits.filter(auditDefn=>
-requestedAuditNames.has(auditDefn.implementation.meta.id));
-
-
-const requiredGathererIds=Config.getGatherersNeededByAudits(audits);
-
-
-const passes=Config.generatePassesNeededByGatherers(config.passes,requiredGathererIds);
-
-config.categories=categories;
-config.audits=audits;
-config.passes=passes;
-}
-
-
-
-
-
-
-
-static filterCategoriesAndAudits(oldCategories,settings){
-if(!oldCategories){
-return{categories:null,requestedAuditNames:new Set()};
-}
-
-if(settings.onlyAudits&&settings.skipAudits){
-throw new Error('Cannot set both skipAudits and onlyAudits');
-}
-
-
-const categories={};
-const filterByIncludedCategory=!!settings.onlyCategories;
-const filterByIncludedAudit=!!settings.onlyAudits;
-const categoryIds=settings.onlyCategories||[];
-const auditIds=settings.onlyAudits||[];
-const skipAuditIds=settings.skipAudits||[];
-
-
-categoryIds.forEach(categoryId=>{
-if(!oldCategories[categoryId]){
-log.warn('config',`unrecognized category in 'onlyCategories': ${categoryId}`);
-}
-});
-
-
-const auditsToValidate=new Set(auditIds.concat(skipAuditIds));
-for(const auditId of auditsToValidate){
-const foundCategory=Object.keys(oldCategories).find(categoryId=>{
-const auditRefs=oldCategories[categoryId].auditRefs;
-return!!auditRefs.find(candidate=>candidate.id===auditId);
-});
-
-if(!foundCategory){
-const parentKeyName=skipAuditIds.includes(auditId)?'skipAudits':'onlyAudits';
-log.warn('config',`unrecognized audit in '${parentKeyName}': ${auditId}`);
-}else if(auditIds.includes(auditId)&&categoryIds.includes(foundCategory)){
-log.warn('config',`${auditId} in 'onlyAudits' is already included by `+
-`${foundCategory} in 'onlyCategories'`);
-}
-}
-
-const includedAudits=new Set(auditIds);
-skipAuditIds.forEach(id=>includedAudits.delete(id));
-
-Object.keys(oldCategories).forEach(categoryId=>{
-const category=deepClone(oldCategories[categoryId]);
-
-if(filterByIncludedCategory&&filterByIncludedAudit){
-
-if(!categoryIds.includes(categoryId)){
-category.auditRefs=category.auditRefs.filter(audit=>auditIds.includes(audit.id));
-}
-}else if(filterByIncludedCategory){
-
-if(!categoryIds.includes(categoryId)){
-return;
-}
-}else if(filterByIncludedAudit){
-category.auditRefs=category.auditRefs.filter(audit=>auditIds.includes(audit.id));
-}
-
-
-category.auditRefs=category.auditRefs.filter(audit=>!skipAuditIds.includes(audit.id));
-
-if(category.auditRefs.length){
-categories[categoryId]=category;
-category.auditRefs.forEach(audit=>includedAudits.add(audit.id));
-}
-});
-
-return{categories,requestedAuditNames:includedAudits};
-}
-
-
-
-
-
-static getCategories(config){
-const categories=config.categories;
-if(!categories){
-return[];
-}
-
-return Object.keys(categories).map(id=>{
-const title=categories[id].title;
-return{id,title};
-});
-}
-
-
-
-
-
-
-static getGatherersNeededByAudits(audits){
-
-
-if(!audits){
-return new Set();
-}
-
-return audits.reduce((list,auditDefn)=>{
-auditDefn.implementation.meta.requiredArtifacts.forEach(artifact=>list.add(artifact));
-return list;
-},new Set());
-}
-
-
-
-
-
-
-
-static generatePassesNeededByGatherers(passes,requiredGatherers){
-if(!passes){
-return null;
-}
-
-const auditsNeedTrace=requiredGatherers.has('traces');
-const filteredPasses=passes.map(pass=>{
-
-pass.gatherers=pass.gatherers.filter(gathererDefn=>{
-const gatherer=gathererDefn.instance;
-return requiredGatherers.has(gatherer.name);
-});
-
-
-if(pass.recordTrace&&!auditsNeedTrace){
-const passName=pass.passName||'unknown pass';
-log.warn('config',`Trace not requested by an audit, dropping trace in ${passName}`);
-pass.recordTrace=false;
-}
-
-return pass;
-}).filter(pass=>{
-
-if(pass.recordTrace)return true;
-
-if(pass.passName==='defaultPass')return true;
-return pass.gatherers.length>0;
-});
-return filteredPasses;
-}
-
-
-
-
-
-
-
-
-
-static requireAudits(audits,configPath){
-const expandedAudits=Config.expandAuditShorthand(audits);
-if(!expandedAudits){
-return null;
-}
-
-const coreList=Runner.getAuditList();
-const auditDefns=expandedAudits.map(audit=>{
-let implementation;
-if('implementation'in audit){
-implementation=audit.implementation;
-}else{
-
-const auditPathJs=`${audit.path}.js`;
-const coreAudit=coreList.find(a=>a===auditPathJs);
-let requirePath=`../audits/${audit.path}`;
-if(!coreAudit){
-
-requirePath=Runner.resolvePlugin(audit.path,configPath,'audit');
-}
-implementation=require(requirePath);
-}
-
-return{
-implementation,
-path:audit.path,
-options:audit.options||{}};
-
-});
-
-const mergedAuditDefns=mergeOptionsOfItems(auditDefns);
-mergedAuditDefns.forEach(audit=>assertValidAudit(audit.implementation,audit.path));
-return mergedAuditDefns;
-}
-
-
-
-
-
-
-
-
-static requireGathererFromPath(path,options,coreAuditList,configPath){
-const coreGatherer=coreAuditList.find(a=>a===`${path}.js`);
-
-let requirePath=`../gather/gatherers/${path}`;
-if(!coreGatherer){
-
-requirePath=Runner.resolvePlugin(path,configPath,'gatherer');
-}
-
-const GathererClass=require(requirePath);
-
-return{
-instance:new GathererClass(),
-implementation:GathererClass,
-path,
-options:options||{}};
-
-}
-
-
-
-
-
-
-
-
-
-static requireGatherers(passes,configPath){
-if(!passes){
-return null;
-}
-
-const coreList=Runner.getGathererList();
-const fullPasses=passes.map(pass=>{
-const gathererDefns=Config.expandGathererShorthand(pass.gatherers).map(gathererDefn=>{
-if(gathererDefn.instance){
-return{
-instance:gathererDefn.instance,
-implementation:gathererDefn.implementation,
-path:gathererDefn.path,
-options:gathererDefn.options||{}};
-
-}else if(gathererDefn.implementation){
-const GathererClass=gathererDefn.implementation;
-return{
-instance:new GathererClass(),
-implementation:gathererDefn.implementation,
-path:gathererDefn.path,
-options:gathererDefn.options||{}};
-
-}else if(gathererDefn.path){
-const path=gathererDefn.path;
-const options=gathererDefn.options;
-return Config.requireGathererFromPath(path,options,coreList,configPath);
-}else{
-throw new Error('Invalid expanded Gatherer: '+JSON.stringify(gathererDefn));
-}
-});
-
-const mergedDefns=mergeOptionsOfItems(gathererDefns);
-mergedDefns.forEach(gatherer=>assertValidGatherer(gatherer.instance,gatherer.path));
-
-return Object.assign(pass,{gatherers:mergedDefns});
-});
-
-return fullPasses;
-}}
-
-
-module.exports=Config;
-
-}).call(this,"/../lighthouse-core/config");
-},{"../audits/audit.js":2,"../runner.js":99,"./../lib/i18n/i18n.js":36,"./constants.js":8,"./default-config.js":9,"./full-config.js":10,"lighthouse-logger":147,"lodash.isequal":178,"path":124}],8:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const DEVTOOLS_RTT_ADJUSTMENT_FACTOR=3.75;
-const DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR=0.9;
-
-const throttling={
-DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
-DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
-mobile3G:{
-rttMs:150,
-throughputKbps:1.6*1024,
-requestLatencyMs:150*DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
-downloadThroughputKbps:1.6*1024*DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
-uploadThroughputKbps:750*DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
-cpuSlowdownMultiplier:4}};
-
-
-
-
-const defaultSettings={
-output:'json',
-maxWaitForLoad:45*1000,
-throttlingMethod:'simulate',
-throttling:throttling.mobile3G,
-auditMode:false,
-gatherMode:false,
-disableStorageReset:false,
-disableDeviceEmulation:false,
-emulatedFormFactor:'mobile',
-
-
-
-locale:'en-US',
-blockedUrlPatterns:null,
-additionalTraceCategories:null,
-extraHeaders:null,
-onlyAudits:null,
-onlyCategories:null,
-skipAudits:null};
-
-
-
-const defaultPassConfig={
-passName:'defaultPass',
-recordTrace:false,
-useThrottling:false,
-pauseAfterLoadMs:0,
-networkQuietThresholdMs:0,
-cpuQuietThresholdMs:0,
-blockedUrlPatterns:[],
-blankPage:'about:blank',
-blankDuration:300,
-gatherers:[]};
-
-
-const nonSimulatedPassConfigOverrides={
-pauseAfterLoadMs:5250,
-networkQuietThresholdMs:5250,
-cpuQuietThresholdMs:5250};
-
-
-module.exports={
-throttling,
-defaultSettings,
-defaultPassConfig,
-nonSimulatedPassConfigOverrides};
-
-
-},{}],9:[function(require,module,exports){
-(function(__filename){
-
-
-
-
-
-'use strict';
-
-
-
-const constants=require('./constants');
-const i18n=require('../lib/i18n/i18n.js');
-
-const UIStrings={
-
-performanceCategoryTitle:'Performance',
-
-metricGroupTitle:'Metrics',
-
-loadOpportunitiesGroupTitle:'Opportunities',
-
-loadOpportunitiesGroupDescription:'These optimizations can speed up your page load.',
-
-firstPaintImprovementsGroupTitle:'First Paint Improvements',
-
-firstPaintImprovementsGroupDescription:'The most critical aspect of performance is how quickly pixels are rendered onscreen. Key metrics: First Contentful Paint, First Meaningful Paint',
-
-overallImprovementsGroupTitle:'Overall Improvements',
-
-overallImprovementsGroupDescription:'Enhance the overall loading experience, so the page is responsive and ready to use as soon as possible. Key metrics: Time to Interactive, Speed Index',
-
-diagnosticsGroupTitle:'Diagnostics',
-
-diagnosticsGroupDescription:'More information about the performance of your application.'};
-
-
-const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
-
-
-const defaultConfig={
-settings:constants.defaultSettings,
-passes:[{
-passName:'defaultPass',
-recordTrace:true,
-useThrottling:true,
-pauseAfterLoadMs:1000,
-networkQuietThresholdMs:1000,
-cpuQuietThresholdMs:1000,
-gatherers:[
-'scripts',
-'css-usage',
-'viewport',
-'viewport-dimensions',
-'theme-color',
-'manifest',
-'runtime-exceptions',
-'chrome-console-messages',
-'image-usage',
-'accessibility',
-'dobetterweb/anchors-with-no-rel-noopener',
-'dobetterweb/appcache',
-'dobetterweb/doctype',
-'dobetterweb/domstats',
-'dobetterweb/js-libraries',
-'dobetterweb/optimized-images',
-'dobetterweb/password-inputs-with-prevented-paste',
-'dobetterweb/response-compression',
-'dobetterweb/tags-blocking-first-paint',
-'dobetterweb/websql',
-'seo/meta-description',
-'seo/font-size',
-'seo/crawlable-links',
-'seo/meta-robots',
-'seo/hreflang',
-'seo/embedded-content',
-'seo/canonical',
-'seo/robots-txt',
-'fonts']},
-
-
-{
-passName:'offlinePass',
-gatherers:[
-'service-worker',
-'offline',
-'start-url']},
-
-
-{
-passName:'redirectPass',
-
-blockedUrlPatterns:['*.css','*.jpg','*.jpeg','*.png','*.gif','*.svg','*.ttf','*.woff','*.woff2'],
-gatherers:[
-'http-redirect',
-'html-without-javascript']}],
-
-
-audits:[
-'is-on-https',
-'redirects-http',
-'service-worker',
-'works-offline',
-'viewport',
-'without-javascript',
-'metrics/first-contentful-paint',
-'metrics/first-meaningful-paint',
-'load-fast-enough-for-pwa',
-'metrics/speed-index',
-'screenshot-thumbnails',
-'final-screenshot',
-'metrics/estimated-input-latency',
-'errors-in-console',
-'time-to-first-byte',
-'metrics/first-cpu-idle',
-'metrics/interactive',
-'user-timings',
-'critical-request-chains',
-'redirects',
-'webapp-install-banner',
-'splash-screen',
-'themed-omnibox',
-'manifest-short-name-length',
-'content-width',
-'image-aspect-ratio',
-'deprecations',
-'mainthread-work-breakdown',
-'bootup-time',
-'uses-rel-preload',
-'uses-rel-preconnect',
-'font-display',
-'network-requests',
-'metrics',
-'manual/pwa-cross-browser',
-'manual/pwa-page-transitions',
-'manual/pwa-each-page-has-url',
-'accessibility/accesskeys',
-'accessibility/aria-allowed-attr',
-'accessibility/aria-required-attr',
-'accessibility/aria-required-children',
-'accessibility/aria-required-parent',
-'accessibility/aria-roles',
-'accessibility/aria-valid-attr-value',
-'accessibility/aria-valid-attr',
-'accessibility/audio-caption',
-'accessibility/button-name',
-'accessibility/bypass',
-'accessibility/color-contrast',
-'accessibility/definition-list',
-'accessibility/dlitem',
-'accessibility/document-title',
-'accessibility/duplicate-id',
-'accessibility/frame-title',
-'accessibility/html-has-lang',
-'accessibility/html-lang-valid',
-'accessibility/image-alt',
-'accessibility/input-image-alt',
-'accessibility/label',
-'accessibility/layout-table',
-'accessibility/link-name',
-'accessibility/list',
-'accessibility/listitem',
-'accessibility/meta-refresh',
-'accessibility/meta-viewport',
-'accessibility/object-alt',
-'accessibility/tabindex',
-'accessibility/td-headers-attr',
-'accessibility/th-has-data-cells',
-'accessibility/valid-lang',
-'accessibility/video-caption',
-'accessibility/video-description',
-'accessibility/manual/custom-controls-labels',
-'accessibility/manual/custom-controls-roles',
-'accessibility/manual/focus-traps',
-'accessibility/manual/focusable-controls',
-'accessibility/manual/heading-levels',
-'accessibility/manual/interactive-element-affordance',
-'accessibility/manual/logical-tab-order',
-'accessibility/manual/managed-focus',
-'accessibility/manual/offscreen-content-hidden',
-'accessibility/manual/use-landmarks',
-'accessibility/manual/visual-order-follows-dom',
-'byte-efficiency/uses-long-cache-ttl',
-'byte-efficiency/total-byte-weight',
-'byte-efficiency/offscreen-images',
-'byte-efficiency/render-blocking-resources',
-'byte-efficiency/unminified-css',
-'byte-efficiency/unminified-javascript',
-'byte-efficiency/unused-css-rules',
-'byte-efficiency/uses-webp-images',
-'byte-efficiency/uses-optimized-images',
-'byte-efficiency/uses-text-compression',
-'byte-efficiency/uses-responsive-images',
-'byte-efficiency/efficient-animated-content',
-'dobetterweb/appcache-manifest',
-'dobetterweb/doctype',
-'dobetterweb/dom-size',
-'dobetterweb/external-anchors-use-rel-noopener',
-'dobetterweb/geolocation-on-start',
-'dobetterweb/no-document-write',
-'dobetterweb/no-vulnerable-libraries',
-'dobetterweb/js-libraries',
-'dobetterweb/no-websql',
-'dobetterweb/notification-on-start',
-'dobetterweb/password-inputs-can-be-pasted-into',
-'dobetterweb/uses-http2',
-'dobetterweb/uses-passive-event-listeners',
-'seo/meta-description',
-'seo/http-status-code',
-'seo/font-size',
-'seo/link-text',
-'seo/is-crawlable',
-'seo/robots-txt',
-'seo/hreflang',
-'seo/plugins',
-'seo/canonical',
-'seo/manual/mobile-friendly',
-'seo/manual/structured-data'],
-
-
-groups:{
-'metrics':{
-title:str_(UIStrings.metricGroupTitle)},
-
-'load-opportunities':{
-title:str_(UIStrings.loadOpportunitiesGroupTitle),
-description:str_(UIStrings.loadOpportunitiesGroupDescription)},
-
-'diagnostics':{
-title:str_(UIStrings.diagnosticsGroupTitle),
-description:str_(UIStrings.diagnosticsGroupDescription)},
-
-'a11y-color-contrast':{
-title:'Color Contrast Is Satisfactory',
-description:'These are opportunities to improve the legibility of your content.'},
-
-'a11y-describe-contents':{
-title:'Elements Describe Contents Well',
-description:'These are opportunities to make your content easier to understand for a user of assistive technology, like a screen reader.'},
-
-'a11y-well-structured':{
-title:'Elements Are Well Structured',
-description:'These are opportunities to make sure your HTML is appropriately structured.'},
-
-'a11y-aria':{
-title:'ARIA Attributes Follow Best Practices',
-description:'These are opportunities to improve the usage of ARIA in your application which may enhance the experience for users of assistive technology, like a screen reader.'},
-
-'a11y-correct-attributes':{
-title:'Elements Use Attributes Correctly',
-description:'These are opportunities to improve the configuration of your HTML elements.'},
-
-'a11y-element-names':{
-title:'Elements Have Discernible Names',
-description:'These are opportunities to improve the semantics of the controls in your application. This may enhance the experience for users of assistive technology, like a screen reader.'},
-
-'a11y-language':{
-title:'Page Specifies Valid Language',
-description:'These are opportunities to improve the interpretation of your content by users in different locales.'},
-
-'a11y-meta':{
-title:'Meta Tags Used Properly',
-description:'These are opportunities to improve the user experience of your site.'},
-
-'seo-mobile':{
-title:'Mobile Friendly',
-description:'Make sure your pages are mobile friendly so users don’t have to pinch or zoom '+
-'in order to read the content pages. [Learn more](https://developers.google.com/search/mobile-sites/).'},
-
-'seo-content':{
-title:'Content Best Practices',
-description:'Format your HTML in a way that enables crawlers to better understand your app’s content.'},
-
-'seo-crawl':{
-title:'Crawling and Indexing',
-description:'To appear in search results, crawlers need access to your app.'}},
-
-
-categories:{
-'performance':{
-title:str_(UIStrings.performanceCategoryTitle),
-auditRefs:[
-{id:'first-contentful-paint',weight:3,group:'metrics'},
-{id:'first-meaningful-paint',weight:1,group:'metrics'},
-{id:'speed-index',weight:4,group:'metrics'},
-{id:'interactive',weight:5,group:'metrics'},
-{id:'first-cpu-idle',weight:2,group:'metrics'},
-{id:'estimated-input-latency',weight:0,group:'metrics'},
-
-{id:'render-blocking-resources',weight:0,group:'load-opportunities'},
-{id:'uses-responsive-images',weight:0,group:'load-opportunities'},
-{id:'offscreen-images',weight:0,group:'load-opportunities'},
-{id:'unminified-css',weight:0,group:'load-opportunities'},
-{id:'unminified-javascript',weight:0,group:'load-opportunities'},
-{id:'unused-css-rules',weight:0,group:'load-opportunities'},
-{id:'uses-optimized-images',weight:0,group:'load-opportunities'},
-{id:'uses-webp-images',weight:0,group:'load-opportunities'},
-{id:'uses-text-compression',weight:0,group:'load-opportunities'},
-{id:'uses-rel-preconnect',weight:0,group:'load-opportunities'},
-{id:'time-to-first-byte',weight:0,group:'load-opportunities'},
-{id:'redirects',weight:0,group:'load-opportunities'},
-{id:'uses-rel-preload',weight:0,group:'load-opportunities'},
-{id:'efficient-animated-content',weight:0,group:'load-opportunities'},
-{id:'total-byte-weight',weight:0,group:'diagnostics'},
-{id:'uses-long-cache-ttl',weight:0,group:'diagnostics'},
-{id:'dom-size',weight:0,group:'diagnostics'},
-{id:'critical-request-chains',weight:0,group:'diagnostics'},
-{id:'network-requests',weight:0},
-{id:'metrics',weight:0},
-{id:'user-timings',weight:0,group:'diagnostics'},
-{id:'bootup-time',weight:0,group:'diagnostics'},
-{id:'screenshot-thumbnails',weight:0},
-{id:'final-screenshot',weight:0},
-{id:'mainthread-work-breakdown',weight:0,group:'diagnostics'},
-{id:'font-display',weight:0,group:'diagnostics'}]},
-
-
-'pwa':{
-title:'Progressive Web App',
-description:'These checks validate the aspects of a Progressive Web App, as specified by the baseline [PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist).',
-manualDescription:'These checks are required by the baseline '+
-'[PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are '+
-'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
-auditRefs:[
-
-{id:'load-fast-enough-for-pwa',weight:7},
-{id:'works-offline',weight:5},
-
-{id:'webapp-install-banner',weight:3},
-
-{id:'is-on-https',weight:2},
-{id:'redirects-http',weight:2},
-{id:'viewport',weight:2},
-
-{id:'service-worker',weight:1},
-{id:'without-javascript',weight:1},
-{id:'splash-screen',weight:1},
-{id:'themed-omnibox',weight:1},
-{id:'content-width',weight:1},
-{id:'manifest-short-name-length',weight:0},
-
-{id:'pwa-cross-browser',weight:0},
-{id:'pwa-page-transitions',weight:0},
-{id:'pwa-each-page-has-url',weight:0}]},
-
-
-'accessibility':{
-title:'Accessibility',
-description:'These checks highlight opportunities to [improve the accessibility of your web app](https://developers.google.com/web/fundamentals/accessibility). Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.',
-manualDescription:'These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://developers.google.com/web/fundamentals/accessibility/how-to-review).',
-auditRefs:[
-{id:'accesskeys',weight:1,group:'a11y-correct-attributes'},
-{id:'aria-allowed-attr',weight:3,group:'a11y-aria'},
-{id:'aria-required-attr',weight:2,group:'a11y-aria'},
-{id:'aria-required-children',weight:5,group:'a11y-aria'},
-{id:'aria-required-parent',weight:2,group:'a11y-aria'},
-{id:'aria-roles',weight:3,group:'a11y-aria'},
-{id:'aria-valid-attr-value',weight:2,group:'a11y-aria'},
-{id:'aria-valid-attr',weight:5,group:'a11y-aria'},
-{id:'audio-caption',weight:4,group:'a11y-correct-attributes'},
-{id:'button-name',weight:10,group:'a11y-element-names'},
-{id:'bypass',weight:10,group:'a11y-describe-contents'},
-{id:'color-contrast',weight:6,group:'a11y-color-contrast'},
-{id:'definition-list',weight:1,group:'a11y-well-structured'},
-{id:'dlitem',weight:1,group:'a11y-well-structured'},
-{id:'document-title',weight:2,group:'a11y-describe-contents'},
-{id:'duplicate-id',weight:5,group:'a11y-well-structured'},
-{id:'frame-title',weight:5,group:'a11y-describe-contents'},
-{id:'html-has-lang',weight:4,group:'a11y-language'},
-{id:'html-lang-valid',weight:1,group:'a11y-language'},
-{id:'image-alt',weight:8,group:'a11y-correct-attributes'},
-{id:'input-image-alt',weight:1,group:'a11y-correct-attributes'},
-{id:'label',weight:10,group:'a11y-describe-contents'},
-{id:'layout-table',weight:1,group:'a11y-describe-contents'},
-{id:'link-name',weight:9,group:'a11y-element-names'},
-{id:'list',weight:5,group:'a11y-well-structured'},
-{id:'listitem',weight:4,group:'a11y-well-structured'},
-{id:'meta-refresh',weight:1,group:'a11y-meta'},
-{id:'meta-viewport',weight:3,group:'a11y-meta'},
-{id:'object-alt',weight:4,group:'a11y-describe-contents'},
-{id:'tabindex',weight:4,group:'a11y-correct-attributes'},
-{id:'td-headers-attr',weight:1,group:'a11y-correct-attributes'},
-{id:'th-has-data-cells',weight:1,group:'a11y-correct-attributes'},
-{id:'valid-lang',weight:1,group:'a11y-language'},
-{id:'video-caption',weight:4,group:'a11y-describe-contents'},
-{id:'video-description',weight:3,group:'a11y-describe-contents'},
-
-{id:'logical-tab-order',weight:0},
-{id:'focusable-controls',weight:0},
-{id:'interactive-element-affordance',weight:0},
-{id:'managed-focus',weight:0},
-{id:'focus-traps',weight:0},
-{id:'custom-controls-labels',weight:0},
-{id:'custom-controls-roles',weight:0},
-{id:'visual-order-follows-dom',weight:0},
-{id:'offscreen-content-hidden',weight:0},
-{id:'heading-levels',weight:0},
-{id:'use-landmarks',weight:0}]},
-
-
-'best-practices':{
-title:'Best Practices',
-auditRefs:[
-{id:'appcache-manifest',weight:1},
-{id:'no-websql',weight:1},
-{id:'is-on-https',weight:1},
-{id:'uses-http2',weight:1},
-{id:'uses-passive-event-listeners',weight:1},
-{id:'no-document-write',weight:1},
-{id:'external-anchors-use-rel-noopener',weight:1},
-{id:'geolocation-on-start',weight:1},
-{id:'doctype',weight:1},
-{id:'no-vulnerable-libraries',weight:1},
-{id:'js-libraries',weight:0},
-{id:'notification-on-start',weight:1},
-{id:'deprecations',weight:1},
-{id:'password-inputs-can-be-pasted-into',weight:1},
-{id:'errors-in-console',weight:1},
-{id:'image-aspect-ratio',weight:1}]},
-
-
-'seo':{
-title:'SEO',
-description:'These checks ensure that your page is optimized for search engine results ranking. '+
-'There are additional factors Lighthouse does not check that may affect your search ranking. '+
-'[Learn more](https://support.google.com/webmasters/answer/35769).',
-manualDescription:'Run these additional validators on your site to check additional SEO best practices.',
-auditRefs:[
-{id:'viewport',weight:1,group:'seo-mobile'},
-{id:'document-title',weight:1,group:'seo-content'},
-{id:'meta-description',weight:1,group:'seo-content'},
-{id:'http-status-code',weight:1,group:'seo-crawl'},
-{id:'link-text',weight:1,group:'seo-content'},
-{id:'is-crawlable',weight:1,group:'seo-crawl'},
-{id:'robots-txt',weight:1,group:'seo-crawl'},
-{id:'hreflang',weight:1,group:'seo-content'},
-{id:'canonical',weight:1,group:'seo-content'},
-{id:'font-size',weight:1,group:'seo-mobile'},
-{id:'plugins',weight:1,group:'seo-content'},
-
-{id:'mobile-friendly',weight:0},
-{id:'structured-data',weight:0}]}}};
-
-
-
-
-
-module.exports=defaultConfig;
-
-
-Object.defineProperty(module.exports,'UIStrings',{
-enumerable:false,
-get:()=>UIStrings});
-
-
-}).call(this,"/../lighthouse-core/config/default-config.js");
-},{"../lib/i18n/i18n.js":36,"./constants":8}],10:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-const fullConfig={
-extends:'lighthouse:default',
-settings:{},
-passes:[
-{
-passName:'extraPass',
-gatherers:[
-'js-usage']}],
-
-
-
-audits:[
-'byte-efficiency/unused-javascript'],
-
-
-categories:{
-'performance':{
-auditRefs:[
-{id:'unused-javascript',weight:0,group:'load-opportunities'}]}}};
-
-
-
-
-
-module.exports=fullConfig;
-
-},{}],11:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ArbitraryEqualityMap=require('../../lib/arbitrary-equality-map');
-
-class ComputedArtifact{
-
-
-
-constructor(allComputedArtifacts){
-const cache=new ArbitraryEqualityMap();
-cache.setEqualityFn(ArbitraryEqualityMap.deepEquals);
-
-
-
-this._cache=cache;
-
-
-this._allComputedArtifacts=allComputedArtifacts;
-}
-
-
-
-
-get name(){
-throw new Error('name getter not implemented for computed artifact '+this.constructor.name);
-}
-
-
-
-
-
-
-
-
-
-
-
-async compute_(artifact,allComputedArtifacts){
-throw new Error('compute_() not implemented for computed artifact '+this.name);
-}
-
-
-
-
-
-
-
-
-
-
-async request(requiredArtifacts){
-const computed=this._cache.get(requiredArtifacts);
-if(computed){
-return computed;
-}
-
-
-
-const artifactPromise=
-this.compute_(requiredArtifacts,this._allComputedArtifacts);
-this._cache.set(requiredArtifacts,artifactPromise);
-
-return artifactPromise;
-}}
-
-
-module.exports=ComputedArtifact;
-
-},{"../../lib/arbitrary-equality-map":23}],12:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const makeComputedArtifact=require('./new-computed-artifact');
-const icons=require('../../lib/icons');
-
-const PWA_DISPLAY_VALUES=['minimal-ui','fullscreen','standalone'];
-
-
-
-const SUGGESTED_SHORTNAME_LENGTH=12;
-
-class ManifestValues{
-static get validityIds(){
-return['hasManifest','hasParseableManifest'];
-}
-
-
-
-
-
-
-static get manifestChecks(){
-return[
-{
-id:'hasStartUrl',
-failureText:'Manifest does not contain a `start_url`',
-validate:manifestValue=>!!manifestValue.start_url.value},
-
-{
-id:'hasIconsAtLeast192px',
-failureText:'Manifest does not have a PNG icon of at least 192px',
-validate:manifestValue=>icons.doExist(manifestValue)&&
-icons.pngSizedAtLeast(192,manifestValue).length>0},
-
-{
-id:'hasIconsAtLeast512px',
-failureText:'Manifest does not have a PNG icon of at least 512px',
-validate:manifestValue=>icons.doExist(manifestValue)&&
-icons.pngSizedAtLeast(512,manifestValue).length>0},
-
-{
-id:'hasPWADisplayValue',
-failureText:'Manifest\'s `display` value is not one of: '+PWA_DISPLAY_VALUES.join(' | '),
-validate:manifestValue=>PWA_DISPLAY_VALUES.includes(manifestValue.display.value)},
-
-{
-id:'hasBackgroundColor',
-failureText:'Manifest does not have `background_color`',
-validate:manifestValue=>!!manifestValue.background_color.value},
-
-{
-id:'hasThemeColor',
-failureText:'Manifest does not have `theme_color`',
-validate:manifestValue=>!!manifestValue.theme_color.value},
-
-{
-id:'hasShortName',
-failureText:'Manifest does not have `short_name`',
-validate:manifestValue=>!!manifestValue.short_name.value},
-
-{
-id:'shortNameLength',
-failureText:`Manifest's \`short_name\` is too long (>${SUGGESTED_SHORTNAME_LENGTH} `+
-`characters) to be displayed on a homescreen without truncation`,
-
-validate:manifestValue=>!!manifestValue.short_name.value&&
-manifestValue.short_name.value.length<=SUGGESTED_SHORTNAME_LENGTH},
-
-{
-id:'hasName',
-failureText:'Manifest does not have `name`',
-validate:manifestValue=>!!manifestValue.name.value}];
-
-
-}
-
-
-
-
-
-
-static async compute_(manifest){
-
-let parseFailureReason;
-
-if(manifest===null){
-return{
-isParseFailure:true,
-parseFailureReason:'No manifest was fetched',
-allChecks:[]};
-
-}
-const manifestValue=manifest.value;
-if(manifestValue===undefined){
-return{
-isParseFailure:true,
-parseFailureReason:'Manifest failed to parse as valid JSON',
-allChecks:[]};
-
-}
-
-
-const remainingChecks=ManifestValues.manifestChecks.map(item=>{
-return{
-id:item.id,
-failureText:item.failureText,
-passing:item.validate(manifestValue)};
-
-});
-
-return{
-isParseFailure:false,
-parseFailureReason,
-allChecks:remainingChecks};
-
-}}
-
-
-module.exports=makeComputedArtifact(ManifestValues);
-
-},{"../../lib/icons":83,"./new-computed-artifact":15}],13:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('../computed-artifact');
-const BaseNode=require('../../../lib/dependency-graph/base-node');
-const NetworkRequest=require('../../../lib/network-request');
-
-
-
-
-
-class LanternMetricArtifact extends ComputedArtifact{
-
-
-
-
-
-static getScriptUrls(dependencyGraph,condition){
-
-const scriptUrls=new Set();
-
-dependencyGraph.traverse(node=>{
-if(node.type===BaseNode.TYPES.CPU)return;
-if(node.record.resourceType!==NetworkRequest.TYPES.Script)return;
-if(condition&&!condition(node))return;
-scriptUrls.add(node.record.url);
-});
-
-return scriptUrls;
-}
-
-
-
-
-get COEFFICIENTS(){
-throw new Error('COEFFICIENTS unimplemented!');
-}
-
-
-
-
-
-
-getOptimisticGraph(dependencyGraph,traceOfTab){
-throw new Error('Optimistic graph unimplemented!');
-}
-
-
-
-
-
-
-getPessimisticGraph(dependencyGraph,traceOfTab){
-throw new Error('Pessmistic graph unimplemented!');
-}
-
-
-
-
-
-
-getEstimateFromSimulation(simulationResult,extras){
-return simulationResult;
-}
-
-
-
-
-
-
-
-async computeMetricWithGraphs(data,artifacts,extras){
-const{trace,devtoolsLog,settings}=data;
-const metricName=this.name.replace('Lantern','');
-const graph=await artifacts.requestPageDependencyGraph({trace,devtoolsLog});
-const traceOfTab=await artifacts.requestTraceOfTab(trace);
-
-const simulator=data.simulator||(
-await artifacts.requestLoadSimulator({devtoolsLog,settings}));
-
-const optimisticGraph=this.getOptimisticGraph(graph,traceOfTab);
-const pessimisticGraph=this.getPessimisticGraph(graph,traceOfTab);
-
-
-let simulateOptions={label:`optimistic${metricName}`};
-const optimisticSimulation=simulator.simulate(optimisticGraph,simulateOptions);
-
-simulateOptions={label:`optimisticFlex${metricName}`,flexibleOrdering:true};
-const optimisticFlexSimulation=simulator.simulate(optimisticGraph,simulateOptions);
-
-simulateOptions={label:`pessimistic${metricName}`};
-const pessimisticSimulation=simulator.simulate(pessimisticGraph,simulateOptions);
-
-const optimisticEstimate=this.getEstimateFromSimulation(
-optimisticSimulation.timeInMs<optimisticFlexSimulation.timeInMs?
-optimisticSimulation:optimisticFlexSimulation,
-Object.assign({},extras,{optimistic:true}));
-
-
-const pessimisticEstimate=this.getEstimateFromSimulation(
-pessimisticSimulation,
-Object.assign({},extras,{optimistic:false}));
-
-
-
-const interceptMultiplier=this.COEFFICIENTS.intercept>0?
-Math.min(1,optimisticEstimate.timeInMs/1000):1;
-const timing=
-this.COEFFICIENTS.intercept*interceptMultiplier+
-this.COEFFICIENTS.optimistic*optimisticEstimate.timeInMs+
-this.COEFFICIENTS.pessimistic*pessimisticEstimate.timeInMs;
-
-return{
-timing,
-optimisticEstimate,
-pessimisticEstimate,
-optimisticGraph,
-pessimisticGraph};
-
-}
-
-
-
-
-
-
-compute_(data,computedArtifacts){
-return this.computeMetricWithGraphs(data,computedArtifacts);
-}}
-
-
-module.exports=LanternMetricArtifact;
-
-},{"../../../lib/dependency-graph/base-node":25,"../../../lib/network-request":88,"../computed-artifact":11}],14:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('../computed-artifact');
-const TracingProcessor=require('../../../lib/traces/tracing-processor');
-
-
-
-
-
-
-
-
-
-
-
-class ComputedMetric extends ComputedArtifact{
-
-get name(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-
-
-computeSimulatedMetric(data,artifacts){
-
-return artifacts[`requestLantern${this.name}`](data);
-}
-
-
-
-
-
-
-computeObservedMetric(data,artifacts){
-throw new Error('Unimplemented');
-}
-
-
-
-
-
-
-async compute_(data,computedArtifacts){
-const{trace,devtoolsLog,settings}=data;
-if(!trace||!devtoolsLog||!settings){
-throw new Error('Did not provide necessary metric computation data');
-}
-
-const augmentedData=Object.assign({
-networkRecords:await computedArtifacts.requestNetworkRecords(devtoolsLog),
-traceOfTab:await computedArtifacts.requestTraceOfTab(trace)},
-data);
-
-TracingProcessor.assertHasToplevelEvents(augmentedData.traceOfTab.mainThreadEvents);
-
-switch(settings.throttlingMethod){
-case'simulate':
-return this.computeSimulatedMetric(augmentedData,computedArtifacts);
-case'provided':
-case'devtools':
-return this.computeObservedMetric(augmentedData,computedArtifacts);
-default:
-throw new TypeError(`Unrecognized throttling method: ${settings.throttlingMethod}`);}
-
-}}
-
-
-module.exports=ComputedMetric;
-
-},{"../../../lib/traces/tracing-processor":95,"../computed-artifact":11}],15:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ArbitraryEqualityMap=require('../../lib/arbitrary-equality-map.js');
-
-
-
-
-
-
-
-
-function makeComputedArtifact(computableArtifact){
-
-
-
-
-const request=({computedCache},artifact)=>{
-const cache=computedCache.get(computableArtifact.name)||new ArbitraryEqualityMap();
-computedCache.set(computableArtifact.name,cache);
-
-const computed=cache.get(artifact);
-if(computed){
-return computed;
-}
-
-const artifactPromise=computableArtifact.compute_(artifact);
-cache.set(artifact,artifactPromise);
-
-return artifactPromise;
-};
-
-return Object.assign(computableArtifact,{request});
-}
-
-module.exports=makeComputedArtifact;
-
-},{"../../lib/arbitrary-equality-map.js":23}],16:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const EventEmitter=require('events').EventEmitter;
-const log=require('lighthouse-logger');
-const LHError=require('../../lib/lh-error');
-
-
-
-
-
-
-
-
-
-
-class Connection{
-constructor(){
-this._lastCommandId=0;
-
-this._callbacks=new Map();
-
-this._eventEmitter=new EventEmitter();
-}
-
-
-
-
-connect(){
-return Promise.reject(new Error('Not implemented'));
-}
-
-
-
-
-disconnect(){
-return Promise.reject(new Error('Not implemented'));
-}
-
-
-
-
-wsEndpoint(){
-return Promise.reject(new Error('Not implemented'));
-}
-
-
-
-
-
-
-
-
-sendCommand(method,...paramArgs){
-
-const params=paramArgs.length?paramArgs[0]:undefined;
-
-log.formatProtocol('method => browser',{method,params},'verbose');
-const id=++this._lastCommandId;
-const message=JSON.stringify({id,method,params});
-this.sendRawMessage(message);
-
-return new Promise(resolve=>{
-this._callbacks.set(id,{method,resolve});
-});
-}
-
-
-
-
-
-
-on(eventName,cb){
-if(eventName!=='protocolevent'){
-throw new Error('Only supports "protocolevent" events');
-}
-
-if(!this._eventEmitter){
-throw new Error('Attempted to add event listener after connection disposed.');
-}
-this._eventEmitter.on(eventName,cb);
-}
-
-
-
-
-
-
-
-sendRawMessage(message){
-throw new Error('Not implemented');
-}
-
-
-
-
-
-
-
-
-handleRawMessage(message){
-const object=JSON.parse(message);
-
-
-if(!('id'in object)){
-log.formatProtocol('<= event',
-{method:object.method,params:object.params},'verbose');
-this.emitProtocolEvent(object);
-return;
-}
-
-const callback=this._callbacks.get(object.id);
-if(callback){
-this._callbacks.delete(object.id);
-
-return callback.resolve(Promise.resolve().then(_=>{
-if(object.error){
-log.formatProtocol('method <= browser ERR',{method:callback.method},'error');
-throw LHError.fromProtocolMessage(callback.method,object.error);
-}
-
-log.formatProtocol('method <= browser OK',
-{method:callback.method,params:object.result},'verbose');
-return object.result;
-}));
-}else{
-
-
-const error=object.error&&object.error.message;
-log.formatProtocol(`disowned method <= browser ${error?'ERR':'OK'}`,
-{method:'UNKNOWN',params:error||object.result},'verbose');
-}
-}
-
-
-
-
-emitProtocolEvent(eventMessage){
-if(!this._eventEmitter){
-throw new Error('Attempted to emit event after connection disposed.');
-}
-
-this._eventEmitter.emit('protocolevent',eventMessage);
-}
-
-
-
-
-dispose(){
-if(this._eventEmitter){
-this._eventEmitter.removeAllListeners();
-this._eventEmitter=null;
-}
-}}
-
-
-module.exports=Connection;
-
-},{"../../lib/lh-error":85,"events":111,"lighthouse-logger":147}],17:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Connection=require('./connection.js');
-
-
-
-
-
-
-
-
-
-
-
-
-class RawConnection extends Connection{
-
-
-
-constructor(port){
-super();
-this._port=port;
-this._port.on('message',this.handleRawMessage.bind(this));
-this._port.on('close',this.dispose.bind(this));
-}
-
-
-
-
-
-connect(){
-return Promise.resolve();
-}
-
-
-
-
-disconnect(){
-this._port.close();
-return Promise.resolve();
-}
-
-
-
-
-
-
-sendRawMessage(message){
-this._port.send(message);
-}}
-
-
-module.exports=RawConnection;
-
-},{"./connection.js":16}],18:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-class DevtoolsLog{
-
-
-
-constructor(regexFilter){
-this._filter=regexFilter;
-
-
-this._messages=[];
-this._isRecording=false;
-}
-
-
-
-
-get messages(){
-return this._messages;
-}
-
-reset(){
-this._messages=[];
-}
-
-beginRecording(){
-this._isRecording=true;
-}
-
-endRecording(){
-this._isRecording=false;
-}
-
-
-
-
-
-record(message){
-if(this._isRecording&&(!this._filter||this._filter.test(message.method))){
-this._messages.push(message);
-}
-}}
-
-
-module.exports=DevtoolsLog;
-
-},{}],19:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const NetworkRecorder=require('../lib/network-recorder');
-const emulation=require('../lib/emulation');
-const Element=require('../lib/element');
-const LHError=require('../lib/lh-error');
-const NetworkRequest=require('../lib/network-request');
-const EventEmitter=require('events').EventEmitter;
-const URL=require('../lib/url-shim');
-const constants=require('../config/constants');
-
-const log=require('lighthouse-logger');
-const DevtoolsLog=require('./devtools-log');
-
-const pageFunctions=require('../lib/page-functions.js');
-
-
-
-const Connection=require('./connections/connection.js');
-
-
-const DEFAULT_PAUSE_AFTER_LOAD=0;
-
-const DEFAULT_NETWORK_QUIET_THRESHOLD=5000;
-
-const DEFAULT_CPU_QUIET_THRESHOLD=0;
-
-
-
-
-
-class Driver{
-
-
-
-constructor(connection){
-this._traceCategories=Driver.traceCategories;
-
-
-
-this._eventEmitter=new EventEmitter();
-this._connection=connection;
-
-this._devtoolsLog=new DevtoolsLog(/^(Page|Network)\./);
-this.online=true;
-
-this._domainEnabledCounts=new Map();
-
-this._isolatedExecutionContextId=undefined;
-
-
-
-
-
-
-this._networkStatusMonitor=null;
-
-
-
-
-
-
-this._monitoredUrl=null;
-
-connection.on('protocolevent',event=>{
-this._devtoolsLog.record(event);
-if(this._networkStatusMonitor){
-this._networkStatusMonitor.dispatch(event);
-}
-
-
-
-
-this._eventEmitter.emit(event.method,event.params);
-});
-}
-
-static get traceCategories(){
-return[
-'-*',
-'toplevel',
-'v8.execute',
-'blink.console',
-'blink.user_timing',
-'benchmark',
-'loading',
-'latencyInfo',
-'devtools.timeline',
-'disabled-by-default-devtools.timeline',
-'disabled-by-default-devtools.timeline.frame',
-'disabled-by-default-devtools.timeline.stack',
-
-
-
-'disabled-by-default-devtools.screenshot'];
-
-}
-
-
-
-
-getUserAgent(){
-
-return this.evaluateAsync('navigator.userAgent');
-}
-
-
-
-
-
-getBenchmarkIndex(){
-return this.evaluateAsync(`(${pageFunctions.ultradumbBenchmarkString})()`);
-}
-
-
-
-
-connect(){
-return this._connection.connect();
-}
-
-
-
-
-disconnect(){
-return this._connection.disconnect();
-}
-
-
-
-
-
-
-wsEndpoint(){
-return this._connection.wsEndpoint();
-}
-
-
-
-
-
-
-
-on(eventName,cb){
-if(this._eventEmitter===null){
-throw new Error('connect() must be called before attempting to listen to events.');
-}
-
-
-log.formatProtocol('listen for event =>',{method:eventName},'verbose');
-this._eventEmitter.on(eventName,cb);
-}
-
-
-
-
-
-
-
-
-once(eventName,cb){
-if(this._eventEmitter===null){
-throw new Error('connect() must be called before attempting to listen to events.');
-}
-
-log.formatProtocol('listen once for event =>',{method:eventName},'verbose');
-this._eventEmitter.once(eventName,cb);
-}
-
-
-
-
-
-
-
-off(eventName,cb){
-if(this._eventEmitter===null){
-throw new Error('connect() must be called before attempting to remove an event listener.');
-}
-
-this._eventEmitter.removeListener(eventName,cb);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-_shouldToggleDomain(domain,enable){
-const enabledCount=this._domainEnabledCounts.get(domain)||0;
-const newCount=enabledCount+(enable?1:-1);
-this._domainEnabledCounts.set(domain,Math.max(0,newCount));
-
-
-if(enable&&newCount===1||!enable&&newCount===0){
-log.verbose('Driver',`${domain}.${enable?'enable':'disable'}`);
-return true;
-}else{
-if(newCount<0){
-log.error('Driver',`Attempted to disable domain '${domain}' when already disabled.`);
-}
-return false;
-}
-}
-
-
-
-
-
-
-
-
-sendCommand(method,...params){
-const domainCommand=/^(\w+)\.(enable|disable)$/.exec(method);
-if(domainCommand){
-const enable=domainCommand[2]==='enable';
-if(!this._shouldToggleDomain(domainCommand[1],enable)){
-return Promise.resolve();
-}
-}
-
-return this._connection.sendCommand(method,...params);
-}
-
-
-
-
-
-
-isDomainEnabled(domain){
-
-return!!this._domainEnabledCounts.get(domain);
-}
-
-
-
-
-
-
-evaluateScriptOnNewDocument(scriptSource){
-return this.sendCommand('Page.addScriptToEvaluateOnLoad',{
-scriptSource});
-
-}
-
-
-
-
-
-
-
-
-
-
-evaluateAsync(expression,options={}){
-
-
-
-const contextIdPromise=options.useIsolation?
-this._getOrCreateIsolatedContextId():
-Promise.resolve(undefined);
-return contextIdPromise.then(contextId=>this._evaluateInContext(expression,contextId));
-}
-
-
-
-
-
-
-
-
-_evaluateInContext(expression,contextId){
-return new Promise((resolve,reject)=>{
-
-const asyncTimeout=setTimeout(
-_=>reject(new Error('The asynchronous expression exceeded the allotted time of 60s')),
-60000);
-
-
-const evaluationParams={
-
-
-
-
-
-expression:`(function wrapInNativePromise() {
- const __nativePromise = window.__nativePromise || Promise;
- const URL = window.__nativeURL || window.URL;
- return new __nativePromise(function (resolve) {
- return __nativePromise.resolve()
- .then(_ => ${expression})
- .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString})
- .then(resolve);
- });
- }())`,
-includeCommandLineAPI:true,
-awaitPromise:true,
-returnByValue:true,
-contextId};
-
-
-this.sendCommand('Runtime.evaluate',evaluationParams).then(response=>{
-clearTimeout(asyncTimeout);
-
-if(response.exceptionDetails){
-
-return reject(new Error(`Evaluation exception: ${response.exceptionDetails.text}`));
-}
-
-
-if(response.result===undefined){
-return reject(new Error('Runtime.evaluate response did not contain a "result" object'));
-}
-
-const value=response.result.value;
-
-if(value&&value.__failedInBrowser){
-return reject(Object.assign(new Error(),value));
-}else{
-resolve(value);
-}
-}).catch(err=>{
-clearTimeout(asyncTimeout);
-reject(err);
-});
-});
-}
-
-
-
-
-getAppManifest(){
-return this.sendCommand('Page.getAppManifest').
-then(response=>{
-
-
-
-if(!response.data){
-
-return null;
-}
-
-return response;
-});
-}
-
-
-
-
-getServiceWorkerVersions(){
-return new Promise((resolve,reject)=>{
-
-
-
-const versionUpdatedListener=data=>{
-
-
-const activateCandidates=data.versions.filter(sw=>{
-return sw.status!=='redundant';
-});
-const hasActiveServiceWorker=activateCandidates.find(sw=>{
-return sw.status==='activated';
-});
-
-if(!activateCandidates.length||hasActiveServiceWorker){
-this.off('ServiceWorker.workerVersionUpdated',versionUpdatedListener);
-this.sendCommand('ServiceWorker.disable').
-then(_=>resolve(data),reject);
-}
-};
-
-this.on('ServiceWorker.workerVersionUpdated',versionUpdatedListener);
-
-this.sendCommand('ServiceWorker.enable').catch(reject);
-});
-}
-
-
-
-
-getServiceWorkerRegistrations(){
-return new Promise((resolve,reject)=>{
-this.once('ServiceWorker.workerRegistrationUpdated',data=>{
-this.sendCommand('ServiceWorker.disable').
-then(_=>resolve(data),reject);
-});
-
-this.sendCommand('ServiceWorker.enable').catch(reject);
-});
-}
-
-
-
-
-
-
-
-
-assertNoSameOriginServiceWorkerClients(pageUrl){
-
-let registrations;
-
-let versions;
-
-return this.getServiceWorkerRegistrations().then(data=>{
-registrations=data.registrations;
-}).then(_=>this.getServiceWorkerVersions()).then(data=>{
-versions=data.versions;
-}).then(_=>{
-const origin=new URL(pageUrl).origin;
-
-registrations.
-filter(reg=>{
-const swOrigin=new URL(reg.scopeURL).origin;
-
-return origin===swOrigin;
-}).
-forEach(reg=>{
-versions.forEach(ver=>{
-
-if(ver.registrationId!==reg.registrationId){
-return;
-}
-
-
-if(ver.controlledClients&&ver.controlledClients.length>0){
-throw new Error('You probably have multiple tabs open to the same origin.');
-}
-});
-});
-});
-}
-
-
-
-
-
-
-
-
-_waitForNetworkIdle(networkQuietThresholdMs){
-
-let idleTimeout;
-
-let cancel=()=>{
-throw new Error('_waitForNetworkIdle.cancel() called before it was defined');
-};
-
-
-
-if(!this._networkStatusMonitor){
-throw new Error('Driver._waitForNetworkIdle called with no networkStatusMonitor');
-}
-const networkStatusMonitor=this._networkStatusMonitor;
-
-const promise=new Promise((resolve,reject)=>{
-const onIdle=()=>{
-
-networkStatusMonitor.once('network-2-busy',onBusy);
-idleTimeout=setTimeout(_=>{
-cancel();
-resolve();
-},networkQuietThresholdMs);
-};
-
-const onBusy=()=>{
-networkStatusMonitor.once('network-2-idle',onIdle);
-idleTimeout&&clearTimeout(idleTimeout);
-};
-
-const domContentLoadedListener=()=>{
-if(networkStatusMonitor.is2Idle()){
-onIdle();
-}else{
-onBusy();
-}
-};
-
-this.once('Page.domContentEventFired',domContentLoadedListener);
-cancel=()=>{
-idleTimeout&&clearTimeout(idleTimeout);
-this.off('Page.domContentEventFired',domContentLoadedListener);
-networkStatusMonitor.removeListener('network-2-busy',onBusy);
-networkStatusMonitor.removeListener('network-2-idle',onIdle);
-};
-});
-
-return{
-promise,
-cancel};
-
-}
-
-
-
-
-
-
-_waitForCPUIdle(waitForCPUQuiet){
-if(!waitForCPUQuiet){
-return{
-promise:Promise.resolve(),
-cancel:()=>undefined};
-
-}
-
-
-let lastTimeout;
-let cancelled=false;
-
-const checkForQuietExpression=`(${pageFunctions.checkTimeSinceLastLongTaskString})()`;
-
-
-
-
-function checkForQuiet(driver,resolve){
-if(cancelled)return;
-
-return driver.evaluateAsync(checkForQuietExpression).
-then(timeSinceLongTask=>{
-if(cancelled)return;
-
-if(typeof timeSinceLongTask==='number'){
-if(timeSinceLongTask>=waitForCPUQuiet){
-log.verbose('Driver',`CPU has been idle for ${timeSinceLongTask} ms`);
-resolve();
-}else{
-log.verbose('Driver',`CPU has been idle for ${timeSinceLongTask} ms`);
-const timeToWait=waitForCPUQuiet-timeSinceLongTask;
-lastTimeout=setTimeout(()=>checkForQuiet(driver,resolve),timeToWait);
-}
-}
-});
-}
-
-
-let cancel=()=>{
-throw new Error('_waitForCPUIdle.cancel() called before it was defined');
-};
-const promise=new Promise((resolve,reject)=>{
-checkForQuiet(this,resolve);
-cancel=()=>{
-cancelled=true;
-if(lastTimeout)clearTimeout(lastTimeout);
-reject(new Error('Wait for CPU idle cancelled'));
-};
-});
-
-return{
-promise,
-cancel};
-
-}
-
-
-
-
-
-
-
-
-_waitForLoadEvent(pauseAfterLoadMs){
-
-let cancel=()=>{
-throw new Error('_waitForLoadEvent.cancel() called before it was defined');
-};
-
-const promise=new Promise((resolve,reject)=>{
-
-let loadTimeout;
-const loadListener=function(){
-loadTimeout=setTimeout(resolve,pauseAfterLoadMs);
-};
-this.once('Page.loadEventFired',loadListener);
-
-cancel=()=>{
-this.off('Page.loadEventFired',loadListener);
-loadTimeout&&clearTimeout(loadTimeout);
-};
-});
-
-return{
-promise,
-cancel};
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-async _waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
-maxWaitForLoadedMs){
-
-let maxTimeoutHandle;
-
-
-const waitForLoadEvent=this._waitForLoadEvent(pauseAfterLoadMs);
-
-const waitForNetworkIdle=this._waitForNetworkIdle(networkQuietThresholdMs);
-
-
-let waitForCPUIdle=null;
-
-
-
-const loadPromise=Promise.all([
-waitForLoadEvent.promise,
-waitForNetworkIdle.promise]).
-then(()=>{
-waitForCPUIdle=this._waitForCPUIdle(cpuQuietThresholdMs);
-return waitForCPUIdle.promise;
-}).then(()=>{
-return function(){
-log.verbose('Driver','loadEventFired and network considered idle');
-maxTimeoutHandle&&clearTimeout(maxTimeoutHandle);
-};
-});
-
-
-
-const maxTimeoutPromise=new Promise((resolve,reject)=>{
-maxTimeoutHandle=setTimeout(resolve,maxWaitForLoadedMs);
-}).then(_=>{
-return function(){
-log.warn('Driver','Timed out waiting for page load. Moving on...');
-waitForLoadEvent.cancel();
-waitForNetworkIdle.cancel();
-waitForCPUIdle&&waitForCPUIdle.cancel();
-};
-});
-
-
-const cleanupFn=await Promise.race([
-loadPromise,
-maxTimeoutPromise]);
-
-cleanupFn();
-}
-
-
-
-
-
-
-
-
-
-_beginNetworkStatusMonitoring(startingUrl){
-this._networkStatusMonitor=new NetworkRecorder();
-
-
-this._monitoredUrl=startingUrl;
-
-const requestLoadedListener=redirectRequest=>{
-
-if(!redirectRequest.redirectSource){
-return;
-}
-const earlierRequest=redirectRequest.redirectSource;
-if(earlierRequest.url===this._monitoredUrl){
-this._monitoredUrl=redirectRequest.url;
-}
-};
-this._networkStatusMonitor.on('requestloaded',requestLoadedListener);
-
-return this.sendCommand('Network.enable');
-}
-
-
-
-
-
-
-
-_endNetworkStatusMonitoring(){
-this._networkStatusMonitor=null;
-const finalUrl=this._monitoredUrl;
-this._monitoredUrl=null;
-
-if(!finalUrl){
-throw new Error('Network Status Monitoring ended with an undefined finalUrl');
-}
-
-return finalUrl;
-}
-
-
-
-
-
-
-
-async _getOrCreateIsolatedContextId(){
-if(typeof this._isolatedExecutionContextId==='number'){
-return this._isolatedExecutionContextId;
-}
-
-const resourceTreeResponse=await this.sendCommand('Page.getResourceTree');
-const mainFrameId=resourceTreeResponse.frameTree.frame.id;
-
-const isolatedWorldResponse=await this.sendCommand('Page.createIsolatedWorld',{
-frameId:mainFrameId,
-worldName:'lighthouse_isolated_context'});
-
-
-this._isolatedExecutionContextId=isolatedWorldResponse.executionContextId;
-return isolatedWorldResponse.executionContextId;
-}
-
-_clearIsolatedContextId(){
-this._isolatedExecutionContextId=undefined;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-async gotoURL(url,options={}){
-const waitForLoad=options.waitForLoad||false;
-const passContext=options.passContext||{};
-const disableJS=passContext.disableJavaScript||false;
-
-await this._beginNetworkStatusMonitoring(url);
-await this._clearIsolatedContextId();
-
-
-
-
-this.sendCommand('Page.enable');
-this.sendCommand('Emulation.setScriptExecutionDisabled',{value:disableJS});
-this.sendCommand('Page.navigate',{url});
-
-if(waitForLoad){
-const passConfig=passContext.passConfig||{};
-let{pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs}=passConfig;
-let maxWaitMs=passContext.settings&&passContext.settings.maxWaitForLoad;
-
-
-if(typeof pauseAfterLoadMs!=='number')pauseAfterLoadMs=DEFAULT_PAUSE_AFTER_LOAD;
-if(typeof networkQuietThresholdMs!=='number')networkQuietThresholdMs=DEFAULT_NETWORK_QUIET_THRESHOLD;
-if(typeof cpuQuietThresholdMs!=='number')cpuQuietThresholdMs=DEFAULT_CPU_QUIET_THRESHOLD;
-if(typeof maxWaitMs!=='number')maxWaitMs=constants.defaultSettings.maxWaitForLoad;
-
-
-await this._waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
-maxWaitMs);
-}
-
-return this._endNetworkStatusMonitoring();
-}
-
-
-
-
-
-
-async getObjectProperty(objectId,propName){
-const propertiesResponse=await this.sendCommand('Runtime.getProperties',{
-objectId,
-accessorPropertiesOnly:true,
-generatePreview:false,
-ownProperties:false});
-
-
-const propertyForName=propertiesResponse.result.
-find(property=>property.name===propName);
-
-if(propertyForName&&propertyForName.value){
-return propertyForName.value.value;
-}else{
-return null;
-}
-}
-
-
-
-
-
-
-
-
-getRequestContent(requestId,timeout=1000){
-requestId=NetworkRequest.getRequestIdForBackend(requestId);
-
-return new Promise((resolve,reject)=>{
-
-
-const err=new LHError(LHError.errors.REQUEST_CONTENT_TIMEOUT);
-const asyncTimeout=setTimeout(_=>reject(err),timeout);
-
-this.sendCommand('Network.getResponseBody',{requestId}).then(result=>{
-clearTimeout(asyncTimeout);
-
-resolve(result.body);
-}).catch(e=>{
-clearTimeout(asyncTimeout);
-reject(e);
-});
-});
-}
-
-
-
-
-
-
-queryPermissionState(name){
-const expressionToEval=`
- navigator.permissions.query({name: '${name}'}).then(result => {
- return result.state;
- })
- `;
-
-return this.evaluateAsync(expressionToEval);
-}
-
-
-
-
-
-async querySelector(selector){
-const documentResponse=await this.sendCommand('DOM.getDocument');
-const rootNodeId=documentResponse.root.nodeId;
-
-const targetNode=await this.sendCommand('DOM.querySelector',{
-nodeId:rootNodeId,
-selector});
-
-
-if(targetNode.nodeId===0){
-return null;
-}
-return new Element(targetNode,this);
-}
-
-
-
-
-
-async querySelectorAll(selector){
-const documentResponse=await this.sendCommand('DOM.getDocument');
-const rootNodeId=documentResponse.root.nodeId;
-
-const targetNodeList=await this.sendCommand('DOM.querySelectorAll',{
-nodeId:rootNodeId,
-selector});
-
-
-
-const elementList=[];
-targetNodeList.nodeIds.forEach(nodeId=>{
-if(nodeId!==0){
-elementList.push(new Element({nodeId},this));
-}
-});
-return elementList;
-}
-
-
-
-
-
-
-
-getElementsInDocument(pierce=true){
-return this.getNodesInDocument(pierce).
-then(nodes=>nodes.
-filter(node=>node.nodeType===1).
-map(node=>new Element({nodeId:node.nodeId},this)));
-
-}
-
-
-
-
-
-
-
-async getNodesInDocument(pierce=true){
-const flattenedDocument=await this.sendCommand('DOM.getFlattenedDocument',
-{depth:-1,pierce});
-
-return flattenedDocument.nodes?flattenedDocument.nodes:[];
-}
-
-
-
-
-
-beginTrace(settings){
-const additionalCategories=settings&&settings.additionalTraceCategories&&
-settings.additionalTraceCategories.split(',')||[];
-const traceCategories=this._traceCategories.concat(additionalCategories);
-const uniqueCategories=Array.from(new Set(traceCategories));
-
-
-if(this.isDomainEnabled('Debugger')){
-throw new Error('Debugger domain enabled when starting trace');
-}
-if(this.isDomainEnabled('CSS')){
-throw new Error('CSS domain enabled when starting trace');
-}
-if(this.isDomainEnabled('DOM')){
-throw new Error('DOM domain enabled when starting trace');
-}
-
-
-return this.sendCommand('Page.enable').
-then(_=>this.sendCommand('Tracing.start',{
-categories:uniqueCategories.join(','),
-options:'sampling-frequency=10000'}));
-
-}
-
-
-
-
-endTrace(){
-
-const traceEvents=[];
-
-
-
-
-
-const dataListener=function(data){
-traceEvents.push(...data.value);
-};
-this.on('Tracing.dataCollected',dataListener);
-
-return new Promise((resolve,reject)=>{
-this.once('Tracing.tracingComplete',_=>{
-this.off('Tracing.dataCollected',dataListener);
-resolve({traceEvents});
-});
-
-return this.sendCommand('Tracing.end').catch(reject);
-});
-}
-
-
-
-
-beginDevtoolsLog(){
-this._devtoolsLog.reset();
-this._devtoolsLog.beginRecording();
-}
-
-
-
-
-
-endDevtoolsLog(){
-this._devtoolsLog.endRecording();
-return this._devtoolsLog.messages;
-}
-
-
-
-
-enableRuntimeEvents(){
-return this.sendCommand('Runtime.enable');
-}
-
-
-
-
-
-async beginEmulation(settings){
-
-if(!settings.disableDeviceEmulation){
-if(settings.emulatedFormFactor==='mobile'){
-await emulation.enableNexus5X(this);
-}else if(settings.emulatedFormFactor==='desktop'){
-await emulation.enableDesktop(this);
-}
-}
-
-await this.setThrottling(settings,{useThrottling:true});
-}
-
-
-
-
-
-
-async setThrottling(settings,passConfig){
-if(settings.throttlingMethod!=='devtools'){
-return emulation.clearAllNetworkEmulation(this);
-}
-
-const cpuPromise=passConfig.useThrottling?
-emulation.enableCPUThrottling(this,settings.throttling):
-emulation.disableCPUThrottling(this);
-const networkPromise=passConfig.useThrottling?
-emulation.enableNetworkThrottling(this,settings.throttling):
-emulation.clearAllNetworkEmulation(this);
-
-await Promise.all([cpuPromise,networkPromise]);
-}
-
-
-
-
-
-async goOffline(){
-await this.sendCommand('Network.enable');
-await emulation.goOffline(this);
-this.online=false;
-}
-
-
-
-
-
-
-async goOnline(options){
-await this.setThrottling(options.settings,options.passConfig);
-this.online=true;
-}
-
-
-
-
-
-cleanBrowserCaches(){
-
-return this.sendCommand('Network.clearBrowserCache').
-
-then(_=>this.sendCommand('Network.setCacheDisabled',{cacheDisabled:true})).
-then(_=>this.sendCommand('Network.setCacheDisabled',{cacheDisabled:false}));
-}
-
-
-
-
-
-async setExtraHTTPHeaders(headers){
-if(!headers){
-return;
-}
-
-return this.sendCommand('Network.setExtraHTTPHeaders',{headers});
-}
-
-
-
-
-
-clearDataForOrigin(url){
-const origin=new URL(url).origin;
-
-
-
-const typesToClear=[
-'appcache',
-
-'file_systems',
-'indexeddb',
-'local_storage',
-'shader_cache',
-'websql',
-'service_workers',
-'cache_storage'].
-join(',');
-
-return this.sendCommand('Storage.clearDataForOrigin',{
-origin:origin,
-storageTypes:typesToClear});
-
-}
-
-
-
-
-
-
-async cacheNatives(){
-await this.evaluateScriptOnNewDocument(`window.__nativePromise = Promise;
- window.__nativeError = Error;
- window.__nativeURL = URL;`);
-}
-
-
-
-
-
-async registerPerformanceObserver(){
-const scriptStr=`(${pageFunctions.registerPerformanceObserverInPageString})()`;
-await this.evaluateScriptOnNewDocument(scriptStr);
-}
-
-
-
-
-
-blockUrlPatterns(urls){
-return this.sendCommand('Network.setBlockedURLs',{urls}).
-catch(err=>{
-
-if(!/wasn't found/.test(err.message)){
-throw err;
-}
-});
-}
-
-
-
-
-
-
-async dismissJavaScriptDialogs(){
-await this.sendCommand('Page.enable');
-
-this.on('Page.javascriptDialogOpening',data=>{
-log.warn('Driver',`${data.type} dialog opened by the page automatically suppressed.`);
-
-
-this.sendCommand('Page.handleJavaScriptDialog',{
-accept:true,
-promptText:'Lighthouse prompt response'});
-
-});
-}}
-
-
-module.exports=Driver;
-
-},{"../config/constants":8,"../lib/element":33,"../lib/emulation":34,"../lib/lh-error":85,"../lib/network-recorder":87,"../lib/network-request":88,"../lib/page-functions.js":89,"../lib/url-shim":"url","./connections/connection.js":16,"./devtools-log":18,"events":111,"lighthouse-logger":147}],20:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const log=require('lighthouse-logger');
-const LHError=require('../lib/lh-error');
-const URL=require('../lib/url-shim');
-const NetworkRecorder=require('../lib/network-recorder.js');
-const constants=require('../config/constants');
-
-const Driver=require('../gather/driver.js');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class GatherRunner{
-
-
-
-
-
-
-
-
-
-
-static async loadBlank(
-driver,
-url=constants.defaultPassConfig.blankPage,
-duration=constants.defaultPassConfig.blankDuration)
-{
-await driver.gotoURL(url);
-await new Promise(resolve=>setTimeout(resolve,duration));
-}
-
-
-
-
-
-
-
-
-
-
-static async loadPage(driver,passContext){
-const finalUrl=await driver.gotoURL(passContext.url,{
-waitForLoad:true,
-passContext});
-
-passContext.url=finalUrl;
-}
-
-
-
-
-
-
-static async setupDriver(driver,options){
-log.log('status','Initializing…');
-const resetStorage=!options.settings.disableStorageReset;
-
-await driver.assertNoSameOriginServiceWorkerClients(options.requestedUrl);
-await driver.beginEmulation(options.settings);
-await driver.enableRuntimeEvents();
-await driver.cacheNatives();
-await driver.registerPerformanceObserver();
-await driver.dismissJavaScriptDialogs();
-if(resetStorage)await driver.clearDataForOrigin(options.requestedUrl);
-}
-
-
-
-
-
-static disposeDriver(driver){
-log.log('status','Disconnecting from browser...');
-return driver.disconnect().catch(err=>{
-
-
-if(!/close\/.*status: 500$/.test(err.message)){
-log.error('GatherRunner disconnect',err.message);
-}
-});
-}
-
-
-
-
-
-
-
-static recoverOrThrow(promise){
-return promise.catch(err=>{
-if(err.fatal){
-throw err;
-}
-});
-}
-
-
-
-
-
-
-
-static getPageLoadError(url,networkRecords){
-const mainRecord=networkRecords.find(record=>{
-
-return URL.equalWithExcludedFragments(record.url,url);
-});
-
-let errorDef;
-if(!mainRecord){
-errorDef=LHError.errors.NO_DOCUMENT_REQUEST;
-}else if(mainRecord.failed){
-errorDef={...LHError.errors.FAILED_DOCUMENT_REQUEST};
-errorDef.message+=` ${mainRecord.localizedFailDescription}.`;
-}else if(mainRecord.hasErrorStatusCode()){
-errorDef={...LHError.errors.ERRORED_DOCUMENT_REQUEST};
-errorDef.message+=` Status code: ${mainRecord.statusCode}.`;
-}
-
-if(errorDef){
-return new LHError(errorDef);
-}
-}
-
-
-
-
-
-
-
-
-static async beforePass(passContext,gathererResults){
-const blockedUrls=(passContext.passConfig.blockedUrlPatterns||[]).
-concat(passContext.settings.blockedUrlPatterns||[]);
-const blankPage=passContext.passConfig.blankPage;
-const blankDuration=passContext.passConfig.blankDuration;
-await GatherRunner.loadBlank(passContext.driver,blankPage,blankDuration);
-
-
-
-await passContext.driver.blockUrlPatterns(blockedUrls);
-await passContext.driver.setExtraHTTPHeaders(passContext.settings.extraHeaders);
-
-for(const gathererDefn of passContext.passConfig.gatherers){
-const gatherer=gathererDefn.instance;
-
-passContext.options=gathererDefn.options||{};
-const artifactPromise=Promise.resolve().then(_=>gatherer.beforePass(passContext));
-gathererResults[gatherer.name]=[artifactPromise];
-await GatherRunner.recoverOrThrow(artifactPromise);
-}
-}
-
-
-
-
-
-
-
-
-static async pass(passContext,gathererResults){
-const driver=passContext.driver;
-const config=passContext.passConfig;
-const settings=passContext.settings;
-const gatherers=config.gatherers;
-
-const recordTrace=config.recordTrace;
-const isPerfRun=!settings.disableStorageReset&&recordTrace&&config.useThrottling;
-
-const gatherernames=gatherers.map(g=>g.instance.name).join(', ');
-const status='Loading page & waiting for onload';
-log.log('status',status,gatherernames);
-
-
-if(isPerfRun)await driver.cleanBrowserCaches();
-
-await driver.beginDevtoolsLog();
-
-if(recordTrace)await driver.beginTrace(settings);
-
-
-await GatherRunner.loadPage(driver,passContext);
-log.log('statusEnd',status);
-
-for(const gathererDefn of gatherers){
-const gatherer=gathererDefn.instance;
-
-passContext.options=gathererDefn.options||{};
-const artifactPromise=Promise.resolve().then(_=>gatherer.pass(passContext));
-
-const gathererResult=gathererResults[gatherer.name]||[];
-gathererResult.push(artifactPromise);
-gathererResults[gatherer.name]=gathererResult;
-await GatherRunner.recoverOrThrow(artifactPromise);
-}
-}
-
-
-
-
-
-
-
-
-
-static async afterPass(passContext,gathererResults){
-const driver=passContext.driver;
-const config=passContext.passConfig;
-const gatherers=config.gatherers;
-
-let trace;
-if(config.recordTrace){
-log.log('status','Retrieving trace');
-trace=await driver.endTrace();
-log.verbose('statusEnd','Retrieving trace');
-}
-
-const status='Retrieving devtoolsLog and network records';
-log.log('status',status);
-const devtoolsLog=driver.endDevtoolsLog();
-const networkRecords=NetworkRecorder.recordsFromLogs(devtoolsLog);
-log.verbose('statusEnd',status);
-
-let pageLoadError=GatherRunner.getPageLoadError(passContext.url,networkRecords);
-
-if(!driver.online)pageLoadError=undefined;
-
-if(pageLoadError){
-log.error('GatherRunner',pageLoadError.message,passContext.url);
-passContext.LighthouseRunWarnings.push(pageLoadError.friendlyMessage);
-}
-
-
-
-const passData={
-networkRecords,
-devtoolsLog,
-trace};
-
-
-
-await driver.setThrottling(passContext.settings,{useThrottling:false});
-
-for(const gathererDefn of gatherers){
-const gatherer=gathererDefn.instance;
-const status=`Retrieving: ${gatherer.name}`;
-log.log('status',status);
-
-
-passContext.options=gathererDefn.options||{};
-
-
-const artifactPromise=pageLoadError?
-Promise.reject(pageLoadError):
-
-Promise.resolve().then(_=>gatherer.afterPass(passContext,passData));
-
-const gathererResult=gathererResults[gatherer.name]||[];
-gathererResult.push(artifactPromise);
-gathererResults[gatherer.name]=gathererResult;
-await GatherRunner.recoverOrThrow(artifactPromise);
-log.verbose('statusEnd',status);
-}
-
-
-return passData;
-}
-
-
-
-
-
-
-
-
-
-
-static async collectArtifacts(gathererResults,baseArtifacts){
-
-const gathererArtifacts={};
-
-const resultsEntries=Object.entries(gathererResults);
-for(const[gathererName,phaseResultsPromises]of resultsEntries){
-if(gathererArtifacts[gathererName]!==undefined)continue;
-
-try{
-const phaseResults=await Promise.all(phaseResultsPromises);
-
-const definedResults=phaseResults.filter(element=>element!==undefined);
-const artifact=definedResults[definedResults.length-1];
-
-gathererArtifacts[gathererName]=artifact;
-}catch(err){
-
-
-gathererArtifacts[gathererName]=err;
-}
-
-if(gathererArtifacts[gathererName]===undefined){
-throw new Error(`${gathererName} failed to provide an artifact.`);
-}
-}
-
-
-baseArtifacts.LighthouseRunWarnings=Array.from(new Set(baseArtifacts.LighthouseRunWarnings));
-
-
-return{...baseArtifacts,...gathererArtifacts};
-}
-
-
-
-
-
-static async getBaseArtifacts(options){
-return{
-fetchTime:new Date().toJSON(),
-LighthouseRunWarnings:[],
-HostUserAgent:await options.driver.getUserAgent(),
-NetworkUserAgent:'',
-BenchmarkIndex:0,
-traces:{},
-devtoolsLogs:{},
-settings:options.settings,
-URL:{requestedUrl:options.requestedUrl,finalUrl:''}};
-
-}
-
-
-
-
-
-
-static async run(passes,options){
-const driver=options.driver;
-
-
-const gathererResults={};
-
-try{
-await driver.connect();
-const baseArtifacts=await GatherRunner.getBaseArtifacts(options);
-await GatherRunner.loadBlank(driver);
-baseArtifacts.BenchmarkIndex=await options.driver.getBenchmarkIndex();
-await GatherRunner.setupDriver(driver,options);
-
-
-let firstPass=true;
-for(const passConfig of passes){
-const passContext={
-driver:options.driver,
-
-url:options.requestedUrl,
-settings:options.settings,
-passConfig,
-
-LighthouseRunWarnings:baseArtifacts.LighthouseRunWarnings};
-
-
-await driver.setThrottling(options.settings,passConfig);
-await GatherRunner.beforePass(passContext,gathererResults);
-await GatherRunner.pass(passContext,gathererResults);
-const passData=await GatherRunner.afterPass(passContext,gathererResults);
-
-
-baseArtifacts.devtoolsLogs[passConfig.passName]=passData.devtoolsLog;
-
-const userAgentEntry=passData.devtoolsLog.find(entry=>
-entry.method==='Network.requestWillBeSent'&&
-!!entry.params.request.headers['User-Agent']);
-
-
-if(userAgentEntry&&!baseArtifacts.NetworkUserAgent){
-
-baseArtifacts.NetworkUserAgent=userAgentEntry.params.request.headers['User-Agent'];
-}
-
-
-if(passData.trace){
-baseArtifacts.traces[passConfig.passName]=passData.trace;
-}
-
-if(firstPass){
-
-baseArtifacts.URL.finalUrl=passContext.url;
-firstPass=false;
-}
-}
-const resetStorage=!options.settings.disableStorageReset;
-if(resetStorage)await driver.clearDataForOrigin(options.requestedUrl);
-await GatherRunner.disposeDriver(driver);
-return GatherRunner.collectArtifacts(gathererResults,baseArtifacts);
-}catch(err){
-
-GatherRunner.disposeDriver(driver);
-throw err;
-}
-}}
-
-
-module.exports=GatherRunner;
-
-},{"../config/constants":8,"../gather/driver.js":19,"../lib/lh-error":85,"../lib/network-recorder.js":87,"../lib/url-shim":"url","lighthouse-logger":147}],21:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class Gatherer{
-
-
-
-get name(){
-
-return this.constructor.name;
-}
-
-
-
-
-
-
-
-
-beforePass(passContext){}
-
-
-
-
-
-
-
-pass(passContext){}
-
-
-
-
-
-
-
-
-
-afterPass(passContext,loadData){}}
-
-
-
-
-module.exports=Gatherer;
-
-},{}],22:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Runner=require('./runner');
-const log=require('lighthouse-logger');
-const ChromeProtocol=require('./gather/connections/cri.js');
-const Config=require('./config/config');
-
-const URL=require('./lib/url-shim.js');
-const LHError=require('./lib/lh-error.js');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-async function lighthouse(url,flags={},configJSON,connection){
-
-if(url&&(!URL.isValid(url)||!URL.isProtocolAllowed(url))){
-throw new LHError(LHError.errors.INVALID_URL);
-}
-
-
-flags.logLevel=flags.logLevel||'error';
-log.setLevel(flags.logLevel);
-
-const config=generateConfig(configJSON,flags);
-
-connection=connection||new ChromeProtocol(flags.port,flags.hostname);
-
-
-return Runner.run(connection,{url,config});
-}
-
-
-
-
-
-
-
-
-
-function generateConfig(configJson,flags){
-return new Config(configJson,flags);
-}
-
-lighthouse.generateConfig=generateConfig;
-lighthouse.getAuditList=Runner.getAuditList;
-lighthouse.traceCategories=require('./gather/driver').traceCategories;
-lighthouse.Audit=require('./audits/audit');
-lighthouse.Gatherer=require('./gather/gatherers/gatherer');
-
-module.exports=lighthouse;
-
-},{"./audits/audit":2,"./config/config":7,"./gather/connections/cri.js":107,"./gather/driver":19,"./gather/gatherers/gatherer":21,"./lib/lh-error.js":85,"./lib/url-shim.js":"url","./runner":99,"lighthouse-logger":147}],23:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const isEqual=require('lodash.isequal');
-
-
-
-
-
-
-class ArbitraryEqualityMap{
-constructor(){
-this._equalsFn=(a,b)=>a===b;
-
-this._entries=[];
-}
-
-
-
-
-setEqualityFn(equalsFn){
-this._equalsFn=equalsFn;
-}
-
-
-
-
-
-has(key){
-return this._findIndexOf(key)!==-1;
-}
-
-
-
-
-
-get(key){
-const entry=this._entries[this._findIndexOf(key)];
-return entry&&entry.value;
-}
-
-
-
-
-
-set(key,value){
-let index=this._findIndexOf(key);
-if(index===-1)index=this._entries.length;
-this._entries[index]={key,value};
-}
-
-
-
-
-
-_findIndexOf(key){
-for(let i=0;i<this._entries.length;i++){
-if(this._equalsFn(key,this._entries[i].key))return i;
-}
-
-return-1;
-}
-
-
-
-
-
-
-
-
-
-static deepEquals(objA,objB){
-return isEqual(objA,objB);
-}}
-
-
-module.exports=ArbitraryEqualityMap;
-
-},{"lodash.isequal":178}],24:[function(require,module,exports){
-(function(process){
-
-
-
-
-
-'use strict';
-
-
-const path=require('path');
-const log=require('lighthouse-logger');
-const stream=require('stream');
-const Simulator=require('./dependency-graph/simulator/simulator');
-const lanternTraceSaver=require('./lantern-trace-saver');
-const Metrics=require('./traces/pwmetrics-events');
-const rimraf=require('rimraf');
-const mkdirp=require('mkdirp');
-
-const artifactsFilename='artifacts.json';
-const traceSuffix='.trace.json';
-const devtoolsLogSuffix='.devtoolslog.json';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-async function loadArtifacts(basePath){
-log.log('Reading artifacts from disk:',basePath);
-
-if(!fs.existsSync(basePath)){
-throw new Error('No saved artifacts found at '+basePath);
-}
-
-
-
-const artifacts=JSON.parse(fs.readFileSync(path.join(basePath,artifactsFilename),'utf8'));
-
-const filenames=fs.readdirSync(basePath);
-
-
-artifacts.devtoolsLogs={};
-filenames.filter(f=>f.endsWith(devtoolsLogSuffix)).forEach(filename=>{
-const passName=filename.replace(devtoolsLogSuffix,'');
-const devtoolsLog=JSON.parse(fs.readFileSync(path.join(basePath,filename),'utf8'));
-artifacts.devtoolsLogs[passName]=devtoolsLog;
-});
-
-
-artifacts.traces={};
-filenames.filter(f=>f.endsWith(traceSuffix)).forEach(filename=>{
-const file=fs.readFileSync(path.join(basePath,filename),{encoding:'utf-8'});
-const trace=JSON.parse(file);
-const passName=filename.replace(traceSuffix,'');
-artifacts.traces[passName]=Array.isArray(trace)?{traceEvents:trace}:trace;
-});
-
-return artifacts;
-}
-
-
-
-
-
-
-
-
-async function saveArtifacts(artifacts,basePath){
-mkdirp.sync(basePath);
-rimraf.sync(`${basePath}/*${traceSuffix}`);
-rimraf.sync(`${basePath}/${artifactsFilename}`);
-
-const{traces,devtoolsLogs,...restArtifacts}=artifacts;
-
-
-for(const[passName,trace]of Object.entries(traces)){
-await saveTrace(trace,`${basePath}/${passName}${traceSuffix}`);
-}
-
-
-for(const[passName,devtoolsLog]of Object.entries(devtoolsLogs)){
-const log=JSON.stringify(devtoolsLog);
-fs.writeFileSync(`${basePath}/${passName}${devtoolsLogSuffix}`,log,'utf8');
-}
-
-
-const restArtifactsString=JSON.stringify(restArtifacts,null,2);
-fs.writeFileSync(`${basePath}/${artifactsFilename}`,restArtifactsString,'utf8');
-log.log('Artifacts saved to disk in folder:',basePath);
-}
-
-
-
-
-
-
-
-async function prepareAssets(artifacts,audits){
-const passNames=Object.keys(artifacts.traces);
-
-const assets=[];
-
-for(const passName of passNames){
-const trace=artifacts.traces[passName];
-const devtoolsLog=artifacts.devtoolsLogs[passName];
-
-const traceData=Object.assign({},trace);
-if(audits){
-const evts=new Metrics(traceData.traceEvents,audits).generateFakeEvents();
-traceData.traceEvents=traceData.traceEvents.concat(evts);
-}
-
-assets.push({
-passName,
-traceData,
-devtoolsLog});
-
-}
-
-return assets;
-}
-
-
-
-
-
-
-
-
-function*traceJsonGenerator(traceData){
-const EVENTS_PER_ITERATION=500;
-const keys=Object.keys(traceData);
-
-yield'{\n';
-
-
-yield'"traceEvents": [\n';
-if(traceData.traceEvents.length>0){
-const eventsIterator=traceData.traceEvents[Symbol.iterator]();
-
-const firstEvent=eventsIterator.next().value;
-yield` ${JSON.stringify(firstEvent)}`;
-
-let eventsRemaining=EVENTS_PER_ITERATION;
-let eventsJSON='';
-for(const event of eventsIterator){
-eventsJSON+=`,\n ${JSON.stringify(event)}`;
-eventsRemaining--;
-if(eventsRemaining===0){
-yield eventsJSON;
-eventsRemaining=EVENTS_PER_ITERATION;
-eventsJSON='';
-}
-}
-yield eventsJSON;
-}
-yield'\n]';
-
-
-if(keys.length>1){
-for(const key of keys){
-if(key==='traceEvents')continue;
-
-yield`,\n"${key}": ${JSON.stringify(traceData[key],null,2)}`;
-}
-}
-
-yield'}\n';
-}
-
-
-
-
-
-
-
-function saveTrace(traceData,traceFilename){
-return new Promise((resolve,reject)=>{
-const traceIter=traceJsonGenerator(traceData);
-
-
-const traceStream=new stream.Readable({
-read(){
-const next=traceIter.next();
-this.push(next.done?null:next.value);
-}});
-
-
-const writeStream=fs.createWriteStream(traceFilename);
-writeStream.on('finish',resolve);
-writeStream.on('error',reject);
-
-traceStream.pipe(writeStream);
-});
-}
-
-
-
-
-
-async function saveLanternDebugTraces(pathWithBasename){
-if(!process.env.LANTERN_DEBUG)return;
-
-for(const[label,nodeTimings]of Simulator.ALL_NODE_TIMINGS){
-if(lanternTraceSaver.simulationNamesToIgnore.includes(label))continue;
-
-const traceFilename=`${pathWithBasename}-${label}${traceSuffix}`;
-await saveTrace(lanternTraceSaver.convertNodeTimingsToTrace(nodeTimings),traceFilename);
-log.log('saveAssets',`${label} lantern trace file streamed to disk: ${traceFilename}`);
-}
-}
-
-
-
-
-
-
-
-
-async function saveAssets(artifacts,audits,pathWithBasename){
-const allAssets=await prepareAssets(artifacts,audits);
-const saveAll=allAssets.map(async(passAssets,index)=>{
-const devtoolsLogFilename=`${pathWithBasename}-${index}${devtoolsLogSuffix}`;
-fs.writeFileSync(devtoolsLogFilename,JSON.stringify(passAssets.devtoolsLog,null,2));
-log.log('saveAssets','devtools log saved to disk: '+devtoolsLogFilename);
-
-const streamTraceFilename=`${pathWithBasename}-${index}${traceSuffix}`;
-log.log('saveAssets','streaming trace file to disk: '+streamTraceFilename);
-await saveTrace(passAssets.traceData,streamTraceFilename);
-log.log('saveAssets','trace file streamed to disk: '+streamTraceFilename);
-});
-
-await Promise.all(saveAll);
-await saveLanternDebugTraces(pathWithBasename);
-}
-
-
-
-
-
-
-
-async function logAssets(artifacts,audits){
-const allAssets=await prepareAssets(artifacts,audits);
-allAssets.map(passAssets=>{
-const dtlogdata=JSON.stringify(passAssets.devtoolsLog);
-
-console.log(`loggedAsset %%% devtoolslog-${passAssets.passName}.json %%% ${dtlogdata}`);
-const traceIter=traceJsonGenerator(passAssets.traceData);
-let traceJson='';
-for(const trace of traceIter){
-traceJson+=trace;
-}
-
-console.log(`loggedAsset %%% trace-${passAssets.passName}.json %%% ${traceJson}`);
-});
-}
-
-module.exports={
-saveArtifacts,
-loadArtifacts,
-saveAssets,
-prepareAssets,
-saveTrace,
-logAssets};
-
-
-}).call(this,require('_process'));
-},{"./dependency-graph/simulator/simulator":31,"./lantern-trace-saver":84,"./traces/pwmetrics-events":94,"_process":126,"lighthouse-logger":147,"mkdirp":107,"path":124,"rimraf":107,"stream":141}],25:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class BaseNode{
-
-
-
-constructor(id){
-this._id=id;
-this._isMainDocument=false;
-
-this._dependents=[];
-
-this._dependencies=[];
-}
-
-
-
-
-get id(){
-return this._id;
-}
-
-
-
-
-get type(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-get startTime(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-get endTime(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-setIsMainDocument(value){
-this._isMainDocument=value;
-}
-
-
-
-
-isMainDocument(){
-return this._isMainDocument;
-}
-
-
-
-
-getDependents(){
-return this._dependents.slice();
-}
-
-
-
-
-getDependencies(){
-return this._dependencies.slice();
-}
-
-
-
-
-getNumberOfDependencies(){
-return this._dependencies.length;
-}
-
-
-
-
-getRootNode(){
-let rootNode=this;
-while(rootNode._dependencies.length){
-rootNode=rootNode._dependencies[0];
-}
-
-return rootNode;
-}
-
-
-
-
-addDependent(node){
-node.addDependency(this);
-}
-
-
-
-
-addDependency(node){
-if(this._dependencies.includes(node)){
-return;
-}
-
-node._dependents.push(this);
-this._dependencies.push(node);
-}
-
-
-
-
-removeDependent(node){
-node.removeDependency(this);
-}
-
-
-
-
-removeDependency(node){
-if(!this._dependencies.includes(node)){
-return;
-}
-
-const thisIndex=node._dependents.indexOf(this);
-node._dependents.splice(thisIndex,1);
-this._dependencies.splice(this._dependencies.indexOf(node),1);
-}
-
-removeAllDependencies(){
-for(const node of this._dependencies.slice()){
-this.removeDependency(node);
-}
-}
-
-
-
-
-
-cloneWithoutRelationships(){
-const node=new BaseNode(this.id);
-node.setIsMainDocument(this._isMainDocument);
-return node;
-}
-
-
-
-
-
-
-
-
-cloneWithRelationships(predicate){
-const rootNode=this.getRootNode();
-
-
-let shouldIncludeNode=()=>true;
-if(predicate){
-const idsToInclude=new Set();
-rootNode.traverse(node=>{
-if(predicate(node)){
-node.traverse(
-node=>idsToInclude.add(node.id),
-node=>node._dependencies.filter(parent=>!idsToInclude.has(parent)));
-
-}
-});
-
-shouldIncludeNode=node=>idsToInclude.has(node.id);
-}
-
-const idToNodeMap=new Map();
-rootNode.traverse(originalNode=>{
-if(!shouldIncludeNode(originalNode))return;
-const clonedNode=originalNode.cloneWithoutRelationships();
-idToNodeMap.set(clonedNode.id,clonedNode);
-});
-
-rootNode.traverse(originalNode=>{
-if(!shouldIncludeNode(originalNode))return;
-const clonedNode=idToNodeMap.get(originalNode.id);
-
-for(const dependency of originalNode._dependencies){
-const clonedDependency=idToNodeMap.get(dependency.id);
-clonedNode.addDependency(clonedDependency);
-}
-});
-
-if(!idToNodeMap.has(this.id))throw new Error(`Cloned graph missing node ${this.id}`);
-return idToNodeMap.get(this.id);
-}
-
-
-
-
-
-
-
-_traversePaths(iterator,getNext){
-const stack=[[this]];
-while(stack.length){
-
-
-const path=stack.shift();
-const node=path[0];
-iterator(node,path);
-
-const nodesToAdd=getNext(node);
-for(const nextNode of nodesToAdd){
-stack.push([nextNode].concat(path));
-}
-}
-}
-
-
-
-
-
-
-
-traverse(iterator,getNext){
-if(!getNext){
-getNext=node=>node.getDependents();
-}
-
-const visited=new Set();
-const originalGetNext=getNext;
-
-getNext=node=>{
-visited.add(node.id);
-const allNodesToVisit=originalGetNext(node);
-const nodesToVisit=allNodesToVisit.filter(nextNode=>!visited.has(nextNode.id));
-nodesToVisit.forEach(nextNode=>visited.add(nextNode.id));
-return nodesToVisit;
-};
-
-this._traversePaths(iterator,getNext);
-}
-
-
-
-
-
-
-
-static hasCycle(node,direction='both'){
-
-if(direction==='both'){
-return BaseNode.hasCycle(node,'dependents')||BaseNode.hasCycle(node,'dependencies');
-}
-
-const visited=new Set();
-
-const currentPath=[];
-const toVisit=[node];
-const depthAdded=new Map([[node,0]]);
-
-
-while(toVisit.length){
-
-
-
-const currentNode=toVisit.pop();
-
-
-if(currentPath.includes(currentNode))return true;
-
-if(visited.has(currentNode))continue;
-
-
-
-while(currentPath.length>depthAdded.get(currentNode))currentPath.pop();
-
-
-visited.add(currentNode);
-currentPath.push(currentNode);
-
-
-const nodesToExplore=direction==='dependents'?
-currentNode._dependents:
-currentNode._dependencies;
-for(const nextNode of nodesToExplore){
-if(toVisit.includes(nextNode))continue;
-toVisit.push(nextNode);
-depthAdded.set(nextNode,currentPath.length);
-}
-}
-
-return false;
-}}
-
-
-BaseNode.TYPES={
-NETWORK:'network',
-CPU:'cpu'};
-
-
-module.exports=BaseNode;
-
-},{}],26:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const BaseNode=require('./base-node');
-
-class CPUNode extends BaseNode{
-
-
-
-
-constructor(parentEvent,childEvents=[]){
-const nodeId=`${parentEvent.tid}.${parentEvent.ts}`;
-super(nodeId);
-
-this._event=parentEvent;
-this._childEvents=childEvents;
-}
-
-get type(){
-return BaseNode.TYPES.CPU;
-}
-
-
-
-
-get startTime(){
-return this._event.ts;
-}
-
-
-
-
-get endTime(){
-return this._event.ts+this._event.dur;
-}
-
-
-
-
-get event(){
-return this._event;
-}
-
-
-
-
-get childEvents(){
-return this._childEvents;
-}
-
-
-
-
-
-didPerformLayout(){
-return this._childEvents.some(evt=>evt.name==='Layout');
-}
-
-
-
-
-
-
-isEvaluateScriptFor(urls){
-return this._childEvents.some(evt=>{
-return evt.name==='EvaluateScript'&&
-!!evt.args.data&&!!evt.args.data.url&&
-urls.has(evt.args.data.url);
-});
-}
-
-
-
-
-cloneWithoutRelationships(){
-return new CPUNode(this._event,this._childEvents);
-}}
-
-
-module.exports=CPUNode;
-
-},{"./base-node":25}],27:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const BaseNode=require('./base-node');
-const NetworkRequest=require('../network-request');
-
-class NetworkNode extends BaseNode{
-
-
-
-constructor(networkRecord){
-super(networkRecord.requestId);
-
-this._record=networkRecord;
-}
-
-get type(){
-return BaseNode.TYPES.NETWORK;
-}
-
-
-
-
-get startTime(){
-return this._record.startTime*1000*1000;
-}
-
-
-
-
-get endTime(){
-return this._record.endTime*1000*1000;
-}
-
-
-
-
-get record(){
-return this._record;
-}
-
-
-
-
-get initiatorType(){
-return this._record.initiator&&this._record.initiator.type;
-}
-
-
-
-
-get fromDiskCache(){
-return!!this._record.fromDiskCache;
-}
-
-
-
-
-hasRenderBlockingPriority(){
-const priority=this._record.priority;
-const isScript=this._record.resourceType===NetworkRequest.TYPES.Script;
-const isDocument=this._record.resourceType===NetworkRequest.TYPES.Document;
-const isBlockingScript=priority==='High'&&isScript;
-const isBlockingHtmlImport=priority==='High'&&isDocument;
-return priority==='VeryHigh'||isBlockingScript||isBlockingHtmlImport;
-}
-
-
-
-
-cloneWithoutRelationships(){
-const node=new NetworkNode(this._record);
-node.setIsMainDocument(this._isMainDocument);
-return node;
-}}
-
-
-module.exports=NetworkNode;
-
-},{"../network-request":88,"./base-node":25}],28:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const NetworkAnalyzer=require('./network-analyzer');
-const TcpConnection=require('./tcp-connection');
-
-const DEFAULT_SERVER_RESPONSE_TIME=30;
-const TLS_SCHEMES=['https','wss'];
-
-
-
-const CONNECTIONS_PER_ORIGIN=6;
-
-module.exports=class ConnectionPool{
-
-
-
-
-constructor(records,options){
-this._options=Object.assign(
-{
-rtt:undefined,
-throughput:undefined,
-additionalRttByOrigin:new Map(),
-serverResponseTimeByOrigin:new Map()},
-
-options);
-
-
-if(!this._options.rtt||!this._options.throughput){
-throw new Error('Cannot create pool with no rtt or throughput');
-}
-
-this._records=records;
-
-this._connectionsByOrigin=new Map();
-
-this._connectionsByRecord=new Map();
-this._connectionsInUse=new Set();
-this._connectionReusedByRequestId=NetworkAnalyzer.estimateIfConnectionWasReused(records,{
-forceCoarseEstimates:true});
-
-
-this._initializeConnections();
-}
-
-
-
-
-connectionsInUse(){
-return Array.from(this._connectionsInUse);
-}
-
-_initializeConnections(){
-const connectionReused=this._connectionReusedByRequestId;
-const additionalRttByOrigin=this._options.additionalRttByOrigin;
-const serverResponseTimeByOrigin=this._options.serverResponseTimeByOrigin;
-
-const recordsByOrigin=NetworkAnalyzer.groupByOrigin(this._records);
-for(const[origin,records]of recordsByOrigin.entries()){
-const connections=[];
-const additionalRtt=additionalRttByOrigin.get(origin)||0;
-const responseTime=serverResponseTimeByOrigin.get(origin)||DEFAULT_SERVER_RESPONSE_TIME;
-
-for(const record of records){
-if(connectionReused.get(record.requestId))continue;
-
-const isTLS=TLS_SCHEMES.includes(record.parsedURL.scheme);
-const isH2=record.protocol==='h2';
-const connection=new TcpConnection(
-this._options.rtt+additionalRtt,
-this._options.throughput,
-responseTime,
-isTLS,
-isH2);
-
-
-connections.push(connection);
-}
-
-if(!connections.length){
-throw new Error(`Could not find a connection for origin: ${origin}`);
-}
-
-
-while(connections.length<CONNECTIONS_PER_ORIGIN)connections.push(connections[0].clone());
-
-this._connectionsByOrigin.set(origin,connections);
-}
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-acquire(record,options={}){
-if(this._connectionsByRecord.has(record)){
-
-return this._connectionsByRecord.get(record);
-}
-
-const origin=String(record.parsedURL.securityOrigin);
-
-const connections=this._connectionsByOrigin.get(origin)||[];
-
-const availableConnections=connections.
-filter(connection=>!this._connectionsInUse.has(connection)).
-sort((a,b)=>b.congestionWindow-a.congestionWindow);
-
-const observedConnectionWasReused=!!this._connectionReusedByRequestId.get(record.requestId);
-
-
-let connectionToUse=availableConnections[0];
-if(!options.ignoreConnectionReused){
-connectionToUse=availableConnections.find(
-connection=>connection.isWarm()===observedConnectionWasReused);
-
-}
-
-if(!connectionToUse)return null;
-
-this._connectionsInUse.add(connectionToUse);
-this._connectionsByRecord.set(record,connectionToUse);
-return connectionToUse;
-}
-
-
-
-
-release(record){
-const connection=this._connectionsByRecord.get(record);
-this._connectionsByRecord.delete(record);
-this._connectionsInUse.delete(connection);
-}};
-
-
-},{"./network-analyzer":30,"./tcp-connection":32}],29:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-const DNS_RESOLUTION_RTT_MULTIPLIER=2;
-
-class DNSCache{
-
-
-
-constructor(options){
-this._options=Object.assign(
-{
-rtt:undefined},
-
-options);
-
-
-if(!this._options.rtt){
-throw new Error('Cannot create DNS cache with no rtt');
-}
-
-this._rtt=this._options.rtt;
-
-this._resolvedDomainNames=new Map();
-}
-
-
-
-
-
-
-getTimeUntilResolution(request,options){
-const{requestedAt=0,shouldUpdateCache=false}=options||{};
-
-const domain=request.parsedURL.host;
-const cacheEntry=this._resolvedDomainNames.get(domain);
-let timeUntilResolved=this._rtt*DNSCache.RTT_MULTIPLIER;
-if(cacheEntry){
-const timeUntilCachedIsResolved=Math.max(cacheEntry.resolvedAt-requestedAt,0);
-timeUntilResolved=Math.min(timeUntilCachedIsResolved,timeUntilResolved);
-}
-
-const resolvedAt=requestedAt+timeUntilResolved;
-if(shouldUpdateCache)this._updateCacheResolvedAtIfNeeded(request,resolvedAt);
-
-return timeUntilResolved;
-}
-
-
-
-
-
-_updateCacheResolvedAtIfNeeded(request,resolvedAt){
-const domain=request.parsedURL.host;
-const cacheEntry=this._resolvedDomainNames.get(domain)||{resolvedAt};
-cacheEntry.resolvedAt=Math.min(cacheEntry.resolvedAt,resolvedAt);
-this._resolvedDomainNames.set(domain,cacheEntry);
-}
-
-
-
-
-
-
-
-
-setResolvedAt(domain,resolvedAt){
-this._resolvedDomainNames.set(domain,{resolvedAt});
-}}
-
-
-DNSCache.RTT_MULTIPLIER=DNS_RESOLUTION_RTT_MULTIPLIER;
-
-module.exports=DNSCache;
-
-},{}],30:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const INITIAL_CWD=14*1024;
-const NetworkRequest=require('../../network-request');
-
-
-const DEFAULT_SERVER_RESPONSE_PERCENTAGE=0.4;
-
-
-
-
-
-
-const SERVER_RESPONSE_PERCENTAGE_OF_TTFB={
-Document:0.9,
-XHR:0.9,
-Fetch:0.9};
-
-
-class NetworkAnalyzer{
-
-
-
-static get SUMMARY(){
-return'__SUMMARY__';
-}
-
-
-
-
-
-static groupByOrigin(records){
-const grouped=new Map();
-records.forEach(item=>{
-const key=item.parsedURL.securityOrigin;
-const group=grouped.get(key)||[];
-group.push(item);
-grouped.set(key,group);
-});
-return grouped;
-}
-
-
-
-
-
-static getSummary(values){
-values.sort((a,b)=>a-b);
-
-return{
-min:values[0],
-max:values[values.length-1],
-avg:values.reduce((a,b)=>a+b,0)/values.length,
-median:values[Math.floor((values.length-1)/2)]};
-
-}
-
-
-
-
-
-static summarize(values){
-const summaryByKey=new Map();
-const allEstimates=[];
-for(const[key,estimates]of values){
-summaryByKey.set(key,NetworkAnalyzer.getSummary(estimates));
-allEstimates.push(...estimates);
-}
-
-summaryByKey.set(NetworkAnalyzer.SUMMARY,NetworkAnalyzer.getSummary(allEstimates));
-return summaryByKey;
-}
-
-
-
-
-
-
-
-
-static _estimateValueByOrigin(records,iteratee){
-const connectionWasReused=NetworkAnalyzer.estimateIfConnectionWasReused(records);
-const groupedByOrigin=NetworkAnalyzer.groupByOrigin(records);
-
-const estimates=new Map();
-for(const[origin,originRecords]of groupedByOrigin.entries()){
-
-let originEstimates=[];
-
-for(const record of originRecords){
-const timing=record.timing;
-if(!timing)continue;
-
-const value=iteratee({
-record,
-timing,
-connectionReused:connectionWasReused.get(record.requestId)});
-
-if(typeof value!=='undefined'){
-originEstimates=originEstimates.concat(value);
-}
-}
-
-if(!originEstimates.length)continue;
-estimates.set(origin,originEstimates);
-}
-
-return estimates;
-}
-
-
-
-
-
-
-
-
-static _estimateRTTByOriginViaTCPTiming(records){
-return NetworkAnalyzer._estimateValueByOrigin(records,({timing,connectionReused})=>{
-if(connectionReused)return;
-
-
-
-if(timing.sslStart>0&&timing.sslEnd>0){
-return[timing.connectEnd-timing.sslStart,timing.sslStart-timing.connectStart];
-}else if(timing.connectStart>0&&timing.connectEnd>0){
-return timing.connectEnd-timing.connectStart;
-}
-});
-}
-
-
-
-
-
-
-
-
-
-static _estimateRTTByOriginViaDownloadTiming(records){
-return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
-if(connectionReused)return;
-
-if(record.transferSize<=INITIAL_CWD)return;
-if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
-
-
-const totalTime=(record.endTime-record.startTime)*1000;
-const downloadTimeAfterFirstByte=totalTime-timing.receiveHeadersEnd;
-const numberOfRoundTrips=Math.log2(record.transferSize/INITIAL_CWD);
-
-
-
-if(numberOfRoundTrips>5)return;
-return downloadTimeAfterFirstByte/numberOfRoundTrips;
-});
-}
-
-
-
-
-
-
-
-
-
-
-static _estimateRTTByOriginViaSendStartTiming(records){
-return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
-if(connectionReused)return;
-if(!Number.isFinite(timing.sendStart)||timing.sendStart<0)return;
-
-
-
-let roundTrips=2;
-if(record.parsedURL.scheme==='https')roundTrips+=1;
-return timing.sendStart/roundTrips;
-});
-}
-
-
-
-
-
-
-
-
-
-
-static _estimateRTTByOriginViaHeadersEndTiming(records){
-return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
-if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
-if(!record.resourceType)return;
-
-const serverResponseTimePercentage=SERVER_RESPONSE_PERCENTAGE_OF_TTFB[record.resourceType]||
-DEFAULT_SERVER_RESPONSE_PERCENTAGE;
-const estimatedServerResponseTime=timing.receiveHeadersEnd*serverResponseTimePercentage;
-
-
-
-let roundTrips=1;
-
-
-
-if(!connectionReused){
-roundTrips+=1;
-if(record.parsedURL.scheme==='https')roundTrips+=1;
-roundTrips+=1;
-}
-
-
-return Math.max((timing.receiveHeadersEnd-estimatedServerResponseTime)/roundTrips,3);
-});
-}
-
-
-
-
-
-
-
-
-static _estimateResponseTimeByOrigin(records,rttByOrigin){
-return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing})=>{
-if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
-if(!Number.isFinite(timing.sendEnd)||timing.sendEnd<0)return;
-
-const ttfb=timing.receiveHeadersEnd-timing.sendEnd;
-const origin=record.parsedURL.securityOrigin;
-const rtt=rttByOrigin.get(origin)||rttByOrigin.get(NetworkAnalyzer.SUMMARY)||0;
-return Math.max(ttfb-rtt,0);
-});
-}
-
-
-
-
-
-static canTrustConnectionInformation(records){
-const connectionIdWasStarted=new Map();
-for(const record of records){
-const started=connectionIdWasStarted.get(record.connectionId)||!record.connectionReused;
-connectionIdWasStarted.set(record.connectionId,started);
-}
-
-
-if(connectionIdWasStarted.size<=1)return false;
-
-return Array.from(connectionIdWasStarted.values()).every(started=>started);
-}
-
-
-
-
-
-
-
-
-
-static estimateIfConnectionWasReused(records,options){
-options=Object.assign({forceCoarseEstimates:false},options);
-
-
-if(!options.forceCoarseEstimates&&NetworkAnalyzer.canTrustConnectionInformation(records)){
-
-return new Map(records.map(record=>[record.requestId,!!record.connectionReused]));
-}
-
-
-
-
-
-const connectionWasReused=new Map();
-const groupedByOrigin=NetworkAnalyzer.groupByOrigin(records);
-for(const[_,originRecords]of groupedByOrigin.entries()){
-const earliestReusePossible=originRecords.
-map(record=>record.endTime).
-reduce((a,b)=>Math.min(a,b),Infinity);
-
-for(const record of originRecords){
-connectionWasReused.set(
-record.requestId,
-record.startTime>=earliestReusePossible||record.protocol==='h2');
-
-}
-
-
-
-const firstRecord=originRecords.reduce((a,b)=>a.startTime>b.startTime?b:a);
-connectionWasReused.set(firstRecord.requestId,false);
-}
-
-return connectionWasReused;
-}
-
-
-
-
-
-
-
-
-
-
-static estimateRTTByOrigin(records,options){
-options=Object.assign(
-{
-
-
-forceCoarseEstimates:false,
-
-
-coarseEstimateMultiplier:0.3,
-
-useDownloadEstimates:true,
-useSendStartEstimates:true,
-useHeadersEndEstimates:true},
-
-options);
-
-
-let estimatesByOrigin=NetworkAnalyzer._estimateRTTByOriginViaTCPTiming(records);
-if(!estimatesByOrigin.size||options.forceCoarseEstimates){
-estimatesByOrigin=new Map();
-const estimatesViaDownload=NetworkAnalyzer._estimateRTTByOriginViaDownloadTiming(records);
-const estimatesViaSendStart=NetworkAnalyzer._estimateRTTByOriginViaSendStartTiming(records);
-const estimatesViaTTFB=NetworkAnalyzer._estimateRTTByOriginViaHeadersEndTiming(records);
-
-for(const[origin,estimates]of estimatesViaDownload.entries()){
-if(!options.useDownloadEstimates)continue;
-estimatesByOrigin.set(origin,estimates);
-}
-
-for(const[origin,estimates]of estimatesViaSendStart.entries()){
-if(!options.useSendStartEstimates)continue;
-const existing=estimatesByOrigin.get(origin)||[];
-estimatesByOrigin.set(origin,existing.concat(estimates));
-}
-
-for(const[origin,estimates]of estimatesViaTTFB.entries()){
-if(!options.useHeadersEndEstimates)continue;
-const existing=estimatesByOrigin.get(origin)||[];
-estimatesByOrigin.set(origin,existing.concat(estimates));
-}
-
-for(const estimates of estimatesByOrigin.values()){
-estimates.forEach((x,i)=>estimates[i]=x*options.coarseEstimateMultiplier);
-}
-}
-
-if(!estimatesByOrigin.size)throw new Error('No timing information available');
-return NetworkAnalyzer.summarize(estimatesByOrigin);
-}
-
-
-
-
-
-
-
-
-
-static estimateServerResponseTimeByOrigin(records,options){
-options=Object.assign(
-{
-rttByOrigin:null},
-
-options);
-
-
-let rttByOrigin=options.rttByOrigin;
-if(!rttByOrigin){
-rttByOrigin=NetworkAnalyzer.estimateRTTByOrigin(records,options);
-for(const[origin,summary]of rttByOrigin.entries()){
-rttByOrigin.set(origin,summary.min);
-}
-}
-
-const estimatesByOrigin=NetworkAnalyzer._estimateResponseTimeByOrigin(records,rttByOrigin);
-return NetworkAnalyzer.summarize(estimatesByOrigin);
-}
-
-
-
-
-
-static findMainDocument(records){
-
-const documentRequests=records.filter(record=>record.resourceType===
-NetworkRequest.TYPES.Document);
-return documentRequests.sort((a,b)=>a.startTime-b.startTime)[0];
-}}
-
-
-module.exports=NetworkAnalyzer;
-
-
-
-
-
-
-
-
-
-},{"../../network-request":88}],31:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const BaseNode=require('../base-node');
-const TcpConnection=require('./tcp-connection');
-const ConnectionPool=require('./connection-pool');
-const DNSCache=require('./dns-cache');
-const mobile3G=require('../../../config/constants').throttling.mobile3G;
-
-
-
-
-
-
-const DEFAULT_MAXIMUM_CONCURRENT_REQUESTS=10;
-
-const DEFAULT_LAYOUT_TASK_MULTIPLIER=0.5;
-
-const DEFAULT_MAXIMUM_CPU_TASK_DURATION=10000;
-
-const NodeState={
-NotReadyToStart:0,
-ReadyToStart:1,
-InProgress:2,
-Complete:3};
-
-
-
-const ALL_SIMULATION_NODE_TIMINGS=new Map();
-
-class Simulator{
-
-
-
-constructor(options){
-
-this._options=Object.assign(
-{
-rtt:mobile3G.rttMs,
-throughput:mobile3G.throughputKbps*1024,
-maximumConcurrentRequests:DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,
-cpuSlowdownMultiplier:mobile3G.cpuSlowdownMultiplier,
-layoutTaskMultiplier:DEFAULT_LAYOUT_TASK_MULTIPLIER,
-additionalRttByOrigin:new Map(),
-serverResponseTimeByOrigin:new Map()},
-
-options);
-
-
-this._rtt=this._options.rtt;
-this._throughput=this._options.throughput;
-this._maximumConcurrentRequests=Math.max(Math.min(
-TcpConnection.maximumSaturatedConnections(this._rtt,this._throughput),
-this._options.maximumConcurrentRequests),
-1);
-this._cpuSlowdownMultiplier=this._options.cpuSlowdownMultiplier;
-this._layoutTaskMultiplier=this._cpuSlowdownMultiplier*this._options.layoutTaskMultiplier;
-
-
-this._flexibleOrdering=false;
-
-this._nodeTimings=new Map();
-
-this._numberInProgressByType=new Map();
-
-this._nodes={};
-this._dns=new DNSCache({rtt:this._rtt});
-
-this._connectionPool=null;
-}
-
-
-
-
-_initializeConnectionPool(graph){
-
-const records=[];
-graph.getRootNode().traverse(node=>{
-if(node.type===BaseNode.TYPES.NETWORK){
-records.push(node.record);
-}
-});
-
-this._connectionPool=new ConnectionPool(records,this._options);
-}
-
-
-
-
-_initializeAuxiliaryData(){
-this._nodeTimings=new Map();
-this._numberInProgressByType=new Map();
-
-this._nodes={};
-for(const state of Object.values(NodeState)){
-this._nodes[state]=new Set();
-}
-}
-
-
-
-
-
-_numberInProgress(type){
-return this._numberInProgressByType.get(type)||0;
-}
-
-
-
-
-
-_setTimingData(node,values){
-const timingData=this._nodeTimings.get(node)||{};
-Object.assign(timingData,values);
-this._nodeTimings.set(node,timingData);
-}
-
-
-
-
-
-_getTimingData(node){
-const timingData=this._nodeTimings.get(node);
-if(!timingData)throw new Error(`Unable to get timing data for node ${node.id}`);
-return timingData;
-}
-
-
-
-
-
-_markNodeAsReadyToStart(node,queuedTime){
-this._nodes[NodeState.ReadyToStart].add(node);
-this._nodes[NodeState.NotReadyToStart].delete(node);
-this._setTimingData(node,{queuedTime});
-}
-
-
-
-
-
-_markNodeAsInProgress(node,startTime){
-this._nodes[NodeState.InProgress].add(node);
-this._nodes[NodeState.ReadyToStart].delete(node);
-this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)+1);
-this._setTimingData(node,{startTime});
-}
-
-
-
-
-
-_markNodeAsComplete(node,endTime){
-this._nodes[NodeState.Complete].add(node);
-this._nodes[NodeState.InProgress].delete(node);
-this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)-1);
-this._setTimingData(node,{endTime});
-
-
-for(const dependent of node.getDependents()){
-
-const dependencies=dependent.getDependencies();
-if(dependencies.some(dep=>!this._nodes[NodeState.Complete].has(dep)))continue;
-
-
-this._markNodeAsReadyToStart(dependent,endTime);
-}
-}
-
-
-
-
-
-_acquireConnection(record){
-return this._connectionPool.acquire(record,{
-ignoreConnectionReused:this._flexibleOrdering});
-
-}
-
-
-
-
-
-_startNodeIfPossible(node,totalElapsedTime){
-if(node.type===BaseNode.TYPES.CPU){
-
-if(this._numberInProgress(node.type)===0){
-this._markNodeAsInProgress(node,totalElapsedTime);
-this._setTimingData(node,{timeElapsed:0});
-}
-
-return;
-}
-
-if(node.type!==BaseNode.TYPES.NETWORK)throw new Error('Unsupported');
-
-
-if(!node.fromDiskCache){
-
-const numberOfActiveRequests=this._numberInProgress(node.type);
-if(numberOfActiveRequests>=this._maximumConcurrentRequests)return;
-const connection=this._acquireConnection(node.record);
-if(!connection)return;
-}
-
-this._markNodeAsInProgress(node,totalElapsedTime);
-this._setTimingData(node,{
-timeElapsed:0,
-timeElapsedOvershoot:0,
-bytesDownloaded:0});
-
-}
-
-
-
-
-
-_updateNetworkCapacity(){
-for(const connection of this._connectionPool.connectionsInUse()){
-connection.setThroughput(this._throughput/this._nodes[NodeState.InProgress].size);
-}
-}
-
-
-
-
-
-
-_estimateTimeRemaining(node){
-if(node.type===BaseNode.TYPES.CPU){
-return this._estimateCPUTimeRemaining(node);
-}else if(node.type===BaseNode.TYPES.NETWORK){
-return this._estimateNetworkTimeRemaining(node);
-}else{
-throw new Error('Unsupported');
-}
-}
-
-
-
-
-
-_estimateCPUTimeRemaining(cpuNode){
-const timingData=this._getTimingData(cpuNode);
-const multiplier=cpuNode.didPerformLayout()?
-this._layoutTaskMultiplier:
-this._cpuSlowdownMultiplier;
-const totalDuration=Math.min(
-Math.round(cpuNode.event.dur/1000*multiplier),
-DEFAULT_MAXIMUM_CPU_TASK_DURATION);
-
-const estimatedTimeElapsed=totalDuration-timingData.timeElapsed;
-this._setTimingData(cpuNode,{estimatedTimeElapsed});
-return estimatedTimeElapsed;
-}
-
-
-
-
-
-_estimateNetworkTimeRemaining(networkNode){
-const record=networkNode.record;
-const timingData=this._getTimingData(networkNode);
-
-let timeElapsed=0;
-if(networkNode.fromDiskCache){
-
-
-const sizeInMb=(record.resourceSize||0)/1024/1024;
-timeElapsed=8+20*sizeInMb-timingData.timeElapsed;
-}else{
-
-const connection=this._acquireConnection(record);
-const dnsResolutionTime=this._dns.getTimeUntilResolution(record,{
-requestedAt:timingData.startTime,
-shouldUpdateCache:true});
-
-const timeAlreadyElapsed=timingData.timeElapsed;
-const calculation=connection.simulateDownloadUntil(
-record.transferSize-timingData.bytesDownloaded,
-{timeAlreadyElapsed,dnsResolutionTime,maximumTimeToElapse:Infinity});
-
-
-timeElapsed=calculation.timeElapsed;
-}
-
-const estimatedTimeElapsed=timeElapsed+timingData.timeElapsedOvershoot;
-this._setTimingData(networkNode,{estimatedTimeElapsed});
-return estimatedTimeElapsed;
-}
-
-
-
-
-
-_findNextNodeCompletionTime(){
-let minimumTime=Infinity;
-for(const node of this._nodes[NodeState.InProgress]){
-minimumTime=Math.min(minimumTime,this._estimateTimeRemaining(node));
-}
-
-return minimumTime;
-}
-
-
-
-
-
-
-
-_updateProgressMadeInTimePeriod(node,timePeriodLength,totalElapsedTime){
-const timingData=this._getTimingData(node);
-const isFinished=timingData.estimatedTimeElapsed===timePeriodLength;
-
-if(node.type===BaseNode.TYPES.CPU||node.fromDiskCache){
-return isFinished?
-this._markNodeAsComplete(node,totalElapsedTime):
-timingData.timeElapsed+=timePeriodLength;
-}
-
-if(node.type!==BaseNode.TYPES.NETWORK)throw new Error('Unsupported');
-
-const record=node.record;
-
-const connection=this._acquireConnection(record);
-const dnsResolutionTime=this._dns.getTimeUntilResolution(record,{
-requestedAt:timingData.startTime,
-shouldUpdateCache:true});
-
-const calculation=connection.simulateDownloadUntil(
-record.transferSize-timingData.bytesDownloaded,
-{
-dnsResolutionTime,
-timeAlreadyElapsed:timingData.timeElapsed,
-maximumTimeToElapse:timePeriodLength-timingData.timeElapsedOvershoot});
-
-
-
-connection.setCongestionWindow(calculation.congestionWindow);
-connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);
-
-if(isFinished){
-connection.setWarmed(true);
-this._connectionPool.release(record);
-this._markNodeAsComplete(node,totalElapsedTime);
-}else{
-timingData.timeElapsed+=calculation.timeElapsed;
-timingData.timeElapsedOvershoot+=calculation.timeElapsed-timePeriodLength;
-timingData.bytesDownloaded+=calculation.bytesDownloaded;
-}
-}
-
-_computeFinalNodeTimings(){
-
-const nodeTimings=new Map();
-for(const[node,timing]of this._nodeTimings){
-nodeTimings.set(node,{
-startTime:timing.startTime,
-endTime:timing.endTime,
-duration:timing.endTime-timing.startTime});
-
-}
-
-return nodeTimings;
-}
-
-
-
-
-getOptions(){
-return this._options;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-simulate(graph,options){
-if(BaseNode.hasCycle(graph)){
-throw new Error('Cannot simulate graph with cycle');
-}
-
-options=Object.assign({
-label:undefined,
-flexibleOrdering:false},
-options);
-
-
-this._flexibleOrdering=!!options.flexibleOrdering;
-this._dns=new DNSCache({rtt:this._rtt});
-this._initializeConnectionPool(graph);
-this._initializeAuxiliaryData();
-
-const nodesNotReadyToStart=this._nodes[NodeState.NotReadyToStart];
-const nodesReadyToStart=this._nodes[NodeState.ReadyToStart];
-const nodesInProgress=this._nodes[NodeState.InProgress];
-
-const rootNode=graph.getRootNode();
-rootNode.traverse(node=>nodesNotReadyToStart.add(node));
-let totalElapsedTime=0;
-let iteration=0;
-
-
-this._markNodeAsReadyToStart(rootNode,totalElapsedTime);
-
-
-while(nodesReadyToStart.size||nodesInProgress.size){
-
-for(const node of nodesReadyToStart){
-this._startNodeIfPossible(node,totalElapsedTime);
-}
-
-if(!nodesInProgress.size){
-
-
-if(this._flexibleOrdering)throw new Error('Failed to start a node');
-this._flexibleOrdering=true;
-continue;
-}
-
-
-this._updateNetworkCapacity();
-
-
-const minimumTime=this._findNextNodeCompletionTime();
-totalElapsedTime+=minimumTime;
-
-
-if(!Number.isFinite(minimumTime)||iteration>100000){
-throw new Error('Graph creation failed, depth exceeded');
-}
-
-iteration++;
-
-for(const node of nodesInProgress){
-this._updateProgressMadeInTimePeriod(node,minimumTime,totalElapsedTime);
-}
-}
-
-const nodeTimings=this._computeFinalNodeTimings();
-ALL_SIMULATION_NODE_TIMINGS.set(options.label||'unlabeled',nodeTimings);
-
-return{
-timeInMs:totalElapsedTime,
-nodeTimings};
-
-}
-
-
-static get ALL_NODE_TIMINGS(){
-return ALL_SIMULATION_NODE_TIMINGS;
-}}
-
-
-module.exports=Simulator;
-
-
-
-
-
-
-
-
-
-
-
-
-},{"../../../config/constants":8,"../base-node":25,"./connection-pool":28,"./dns-cache":29,"./tcp-connection":32}],32:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const INITIAL_CONGESTION_WINDOW=10;
-const TCP_SEGMENT_SIZE=1460;
-
-class TcpConnection{
-
-
-
-
-
-
-
-constructor(rtt,throughput,serverLatency=0,ssl=true,h2=false){
-this._warmed=false;
-this._ssl=ssl;
-this._h2=h2;
-this._rtt=rtt;
-this._throughput=throughput;
-this._serverLatency=serverLatency;
-this._congestionWindow=INITIAL_CONGESTION_WINDOW;
-this._h2OverflowBytesDownloaded=0;
-}
-
-
-
-
-
-
-static maximumSaturatedConnections(rtt,availableThroughput){
-const roundTripsPerSecond=1000/rtt;
-const bytesPerRoundTrip=TCP_SEGMENT_SIZE;
-const bytesPerSecond=roundTripsPerSecond*bytesPerRoundTrip;
-const minimumThroughputRequiredPerRequest=bytesPerSecond*8;
-return Math.floor(availableThroughput/minimumThroughputRequiredPerRequest);
-}
-
-
-
-
-_computeMaximumCongestionWindowInSegments(){
-const bytesPerSecond=this._throughput/8;
-const secondsPerRoundTrip=this._rtt/1000;
-const bytesPerRoundTrip=bytesPerSecond*secondsPerRoundTrip;
-return Math.floor(bytesPerRoundTrip/TCP_SEGMENT_SIZE);
-}
-
-
-
-
-setThroughput(throughput){
-this._throughput=throughput;
-}
-
-
-
-
-setCongestionWindow(congestion){
-this._congestionWindow=congestion;
-}
-
-
-
-
-setWarmed(warmed){
-this._warmed=warmed;
-}
-
-
-
-
-isWarm(){
-return this._warmed;
-}
-
-
-
-
-isH2(){
-return this._h2;
-}
-
-
-
-
-get congestionWindow(){
-return this._congestionWindow;
-}
-
-
-
-
-
-
-setH2OverflowBytesDownloaded(bytes){
-if(!this._h2)return;
-this._h2OverflowBytesDownloaded=bytes;
-}
-
-
-
-
-clone(){
-return Object.assign(new TcpConnection(this._rtt,this._throughput),this);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-simulateDownloadUntil(bytesToDownload,options){
-const{timeAlreadyElapsed=0,maximumTimeToElapse=Infinity,dnsResolutionTime=0}=
-options||{};
-
-if(this._warmed&&this._h2){
-bytesToDownload-=this._h2OverflowBytesDownloaded;
-}
-const twoWayLatency=this._rtt;
-const oneWayLatency=twoWayLatency/2;
-const maximumCongestionWindow=this._computeMaximumCongestionWindowInSegments();
-
-let handshakeAndRequest=oneWayLatency;
-if(!this._warmed){
-handshakeAndRequest=
-
-dnsResolutionTime+
-
-oneWayLatency+
-
-oneWayLatency+
-
-oneWayLatency+(
-
-this._ssl?twoWayLatency:0);
-}
-
-let roundTrips=Math.ceil(handshakeAndRequest/twoWayLatency);
-let timeToFirstByte=handshakeAndRequest+this._serverLatency+oneWayLatency;
-if(this._warmed&&this._h2)timeToFirstByte=0;
-
-const timeElapsedForTTFB=Math.max(timeToFirstByte-timeAlreadyElapsed,0);
-const maximumDownloadTimeToElapse=maximumTimeToElapse-timeElapsedForTTFB;
-
-let congestionWindow=Math.min(this._congestionWindow,maximumCongestionWindow);
-let totalBytesDownloaded=0;
-if(timeElapsedForTTFB>0){
-totalBytesDownloaded=congestionWindow*TCP_SEGMENT_SIZE;
-}else{
-roundTrips=0;
-}
-
-let downloadTimeElapsed=0;
-let bytesRemaining=bytesToDownload-totalBytesDownloaded;
-while(bytesRemaining>0&&downloadTimeElapsed<=maximumDownloadTimeToElapse){
-roundTrips++;
-downloadTimeElapsed+=twoWayLatency;
-congestionWindow=Math.max(Math.min(maximumCongestionWindow,congestionWindow*2),1);
-
-const bytesDownloadedInWindow=congestionWindow*TCP_SEGMENT_SIZE;
-totalBytesDownloaded+=bytesDownloadedInWindow;
-bytesRemaining-=bytesDownloadedInWindow;
-}
-
-const timeElapsed=timeElapsedForTTFB+downloadTimeElapsed;
-const extraBytesDownloaded=this._h2?Math.max(totalBytesDownloaded-bytesToDownload,0):0;
-const bytesDownloaded=Math.max(Math.min(totalBytesDownloaded,bytesToDownload),0);
-
-return{
-roundTrips,
-timeElapsed,
-bytesDownloaded,
-extraBytesDownloaded,
-congestionWindow};
-
-}}
-
-
-module.exports=TcpConnection;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-},{}],33:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Driver=require('../gather/driver.js');
-
-class Element{
-
-
-
-
-constructor(element,driver){
-if(!element||!driver){
-throw Error('Driver and element required to create Element');
-}
-this.driver=driver;
-this.element=element;
-}
-
-
-
-
-
-getAttribute(name){
-return this.driver.
-sendCommand('DOM.getAttributes',{
-nodeId:this.element.nodeId}).
-
-
-
-
-then(resp=>{
-const attrIndex=resp.attributes.indexOf(name);
-if(attrIndex===-1){
-return null;
-}
-
-return resp.attributes[attrIndex+1];
-});
-}
-
-
-
-
-getNodeId(){
-return this.element.nodeId;
-}
-
-
-
-
-
-getProperty(propName){
-return this.driver.
-sendCommand('DOM.resolveNode',{
-nodeId:this.element.nodeId}).
-
-then(resp=>{
-if(!resp.object.objectId){
-return null;
-}
-return this.driver.getObjectProperty(resp.object.objectId,propName);
-}).
-catch(()=>null);
-}}
-
-
-module.exports=Element;
-
-},{"../gather/driver.js":19}],34:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const NEXUS5X_EMULATION_METRICS={
-mobile:true,
-screenWidth:412,
-screenHeight:732,
-width:412,
-height:732,
-positionX:0,
-positionY:0,
-scale:1,
-deviceScaleFactor:2.625,
-screenOrientation:{
-angle:0,
-type:'portraitPrimary'}};
-
-
-
-
-
-
-
-const DESKTOP_EMULATION_METRICS={
-mobile:false,
-width:1366,
-height:768,
-deviceScaleFactor:1};
-
-
-const NEXUS5X_USERAGENT={
-userAgent:'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36'+
-'(KHTML, like Gecko) Chrome/71.0.3559.0 Mobile Safari/537.36'};
-
-
-const DESKTOP_USERAGENT={
-userAgent:'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 '+
-'(KHTML, like Gecko) Chrome/71.0.3559.0 Safari/537.36'};
-
-
-const OFFLINE_METRICS={
-offline:true,
-
-latency:0,
-downloadThroughput:0,
-uploadThroughput:0};
-
-
-const NO_THROTTLING_METRICS={
-latency:0,
-downloadThroughput:0,
-uploadThroughput:0,
-offline:false};
-
-
-const NO_CPU_THROTTLE_METRICS={
-rate:1};
-
-
-
-
-
-
-async function enableNexus5X(driver){
-await Promise.all([
-driver.sendCommand('Emulation.setDeviceMetricsOverride',NEXUS5X_EMULATION_METRICS),
-
-driver.sendCommand('Network.enable'),
-driver.sendCommand('Network.setUserAgentOverride',NEXUS5X_USERAGENT),
-driver.sendCommand('Emulation.setTouchEmulationEnabled',{enabled:true})]);
-
-}
-
-
-
-
-
-async function enableDesktop(driver){
-await Promise.all([
-driver.sendCommand('Emulation.setDeviceMetricsOverride',DESKTOP_EMULATION_METRICS),
-
-driver.sendCommand('Network.enable'),
-driver.sendCommand('Network.setUserAgentOverride',DESKTOP_USERAGENT),
-driver.sendCommand('Emulation.setTouchEmulationEnabled',{enabled:false})]);
-
-}
-
-
-
-
-
-
-function enableNetworkThrottling(driver,throttlingSettings){
-
-const conditions={
-offline:false,
-latency:throttlingSettings.requestLatencyMs||0,
-downloadThroughput:throttlingSettings.downloadThroughputKbps||0,
-uploadThroughput:throttlingSettings.uploadThroughputKbps||0};
-
-
-
-conditions.downloadThroughput=Math.floor(conditions.downloadThroughput*1024/8);
-conditions.uploadThroughput=Math.floor(conditions.uploadThroughput*1024/8);
-return driver.sendCommand('Network.emulateNetworkConditions',conditions);
-}
-
-
-
-
-
-function clearAllNetworkEmulation(driver){
-return driver.sendCommand('Network.emulateNetworkConditions',NO_THROTTLING_METRICS);
-}
-
-
-
-
-
-function goOffline(driver){
-return driver.sendCommand('Network.emulateNetworkConditions',OFFLINE_METRICS);
-}
-
-
-
-
-
-
-function enableCPUThrottling(driver,throttlingSettings){
-const rate=throttlingSettings.cpuSlowdownMultiplier;
-return driver.sendCommand('Emulation.setCPUThrottlingRate',{rate});
-}
-
-
-
-
-
-function disableCPUThrottling(driver){
-return driver.sendCommand('Emulation.setCPUThrottlingRate',NO_CPU_THROTTLE_METRICS);
-}
-
-module.exports={
-enableNexus5X,
-enableDesktop,
-enableNetworkThrottling,
-clearAllNetworkEmulation,
-enableCPUThrottling,
-disableCPUThrottling,
-goOffline};
-
-
-},{}],35:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome extensions negatively affected this page's load performance. Try auditing the page in incognito mode or from a Chrome profile without extensions.",
-"description":"A message displayed in a Lighthouse audit result warning that Chrome extensions on the user's system substantially affected Lighthouse's measurements and instructs the user on how to run again without those extensions."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Script Evaluation",
-"description":"Label for a time column in a data table; entries will be the number of milliseconds spent evaluating script for every script loaded by the page."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Script Parse",
-"description":"Label for a time column in a data table; entries will be the number of milliseconds spent parsing script files for every script loaded by the page."},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total",
-"description":"Label for the total time column in a data table; entries will be the number of milliseconds spent executing per resource loaded by the page."},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Consider reducing the time spent parsing, compiling, and executing JS. You may find delivering smaller JS payloads helps with this. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/bootup).",
-"description":"Description of a Lighthouse audit that tells the user that they should reduce the amount of time spent executing javascript and one method of doing so. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reduce JavaScript execution time",
-"description":"Title of a diagnostic audit that provides detail on the time spent executing javascript files during the load. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript execution time",
-"description":"Title of a diagnostic audit that provides detail on the time spent executing javascript files during the load. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Large GIFs are inefficient for delivering animated content. Consider using MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)",
-"description":"Description of a Lighthouse audit that tells the user *why* they should use video instead of GIF format for delivering animated content. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Use video formats for animated content",
-"description":"Imperative title of a Lighthouse audit that tells the user to use video formats rather than animated GIFs, which are wasteful. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Consider lazy-loading offscreen and hidden images after all critical resources have finished loading to lower time to interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should defer loading offscreen images. Offscreen images are images located outside of the visible browser viewport. As they are unseen by the user and slow down page load, they should be loaded later, closer to when the user is going to see them. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Defer offscreen images",
-"description":"Imperative title of a Lighthouse audit that tells the user to defer loading offscreen images. Offscreen images are images located outside of the visible browser viewport. As they are unseen by the user and slow down page load, they should be loaded later, closer to when the user is going to see them. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resources are blocking the first paint of your page. Consider delivering critical JS/CSS inline and deferring all non-critical JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should reduce or remove network resources that block the initial render of the page. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Eliminate render-blocking resources",
-"description":"Imperative title of a Lighthouse audit that tells the user to reduce or remove network resources that block the initial render of the page. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Large network payloads cost users real money and are highly correlated with long load times. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the size of the network resources required by the page. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Total size was {totalBytes, number, bytes} KB",
-"description":"Used to summarize the total byte size of the page and all its network requests. The `{totalBytes}` placeholder will be replaced with the total byte sizes, shown in kilobytes (e.g. 142 KB)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Avoid enormous network payloads",
-"description":"Title of a diagnostic audit that provides detail on large network resources required during page load. 'Payloads' is roughly equivalent to 'resources'. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Avoids enormous network payloads",
-"description":"Title of a diagnostic audit that provides detail on large network resources required during page load. 'Payloads' is roughly equivalent to 'resources'. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Minifying CSS files can reduce network payload sizes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/minify-css).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should minify (remove whitespace) the page's CSS code. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minify CSS",
-"description":"Imperative title of a Lighthouse audit that tells the user to minify (remove whitespace) the page's CSS code. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Minifying JavaScript files can reduce payload sizes and script parse time. [Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should minify the page’s JS code to reduce file size. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minify JavaScript",
-"description":"Imperative title of a Lighthouse audit that tells the user to minify the page’s JS code to reduce file size. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Remove unused rules from stylesheets to reduce unnecessary bytes consumed by network activity. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should defer loading any content in CSS that isn’t needed at page load. This is displayed after a user expands the section to see more. No word length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Defer unused CSS",
-"description":"Imperative title of a Lighthouse audit that tells the user to remove content from their CSS that isn’t needed immediately and instead load that content at a later time. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Remove unused JavaScript to reduce bytes consumed by network activity.",
-"description":"Description of a Lighthouse audit that tells the user *why* they should remove JavaScript that is never needed/evaluated by the browser. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Remove unused JavaScript",
-"description":"Imperative title of a Lighthouse audit that tells the user to remove JavaScript that is never evaluated during page load. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"A long cache lifetime can speed up repeat visits to your page. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/cache-policy).",
-"description":"Description of a Lighthouse audit that tells the user *why* they need to adopt a long cache lifetime policy. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount, plural,\n =1 {1 resource found}\n other {# resources found}\n }",
-"description":"[ICU Syntax] Label for the audit identifying network resources with inefficient cache values. Clicking this will expand the audit to show the resources."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Serve static assets with an efficient cache policy",
-"description":"Title of a diagnostic audit that provides details on the any page resources that could have been served with more efficient cache policies. Cache refers to browser disk cache, which keeps old versions of network resources around for future use. This imperative title is shown to users when there is a significant amount of assets served with poor cache policies."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Uses efficient cache policy on static assets",
-"description":"Title of a diagnostic audit that provides detail on the cache policy applies to the page's static assets. Cache refers to browser disk cache, which keeps old versions of network resources around for future use. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimized images load faster and consume less cellular data. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).",
-"description":"Description of a Lighthouse audit that tells the user *why* they need to efficiently encode images. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Efficiently encode images",
-"description":"Imperative title of a Lighthouse audit that tells the user to encode images with optimization (better compression). This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Serve images that are appropriately-sized to save cellular data and improve load time. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images).",
-"description":"Description of a Lighthouse audit that tells the user *why* they need to serve appropriately sized images. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Properly size images",
-"description":"Imperative title of a Lighthouse audit that tells the user to resize images to match the display dimensions. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Text-based resources should be served with compression (gzip, deflate or brotli) to minimize total network bytes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression).",
-"description":"Description of a Lighthouse audit that tells the user *why* their text-based resources should be served with compression (like gzip). This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Enable text compression",
-"description":"Imperative title of a Lighthouse audit that tells the user to enable text compression (like gzip) in order to enhance the performance of a page. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Image formats like JPEG 2000, JPEG XR, and WebP often provide better compression than PNG or JPEG, which means faster downloads and less data consumption. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should use newer and more efficient image formats. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Serve images in next-gen formats",
-"description":"Imperative title of a Lighthouse audit that tells the user to serve images in newer and more efficient image formats in order to enhance the performance of a page. A non-modern image format was designed 20+ years ago. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"The Critical Request Chains below show you what resources are loaded with a high priority. Consider reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the depth of critical network requests to enhance initial load of a page . This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount, plural,\n =1 {1 chain found}\n other {# chains found}\n }",
-"description":"[ICU Syntax] Label for an audit identifying the number of sequences of dependent network requests used to load the page."},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimize Critical Requests Depth",
-"description":"Imperative title of a Lighthouse audit that tells the user to reduce the depth of critical network requests to enhance initial load of a page. Critical request chains are series of dependent network requests that are important for page rendering. For example, here's a 4-request-deep chain: The biglogo.jpg image is required, but is requested via the styles.css style code, which is requested by the initialize.js javascript, which is requested by the page's HTML. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element",
-"description":"Table column header for the DOM element. Each DOM element is described with its HTML representation."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic",
-"description":"Table column header for the type of statistic. These statistics describe how big the DOM is (count of DOM nodes, children, depth)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value",
-"description":"Table column header for the observed value of the DOM statistic."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer [style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM nodes and greatest DOM depth. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount, plural,\n =1 {1 node}\n other {# nodes}\n }",
-"description":"[ICU Syntax] Label for an audit identifying the number of DOM nodes found in the page."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Avoid an excessive DOM size",
-"description":"Title of a diagnostic audit that provides detail on the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM nodes and greatest DOM depth. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximum DOM Depth",
-"description":"Label for the numeric value of the maximum depth in the page's DOM tree."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total DOM Nodes",
-"description":"Label for the total number of DOM nodes found in the page."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements",
-"description":"Label for the numeric value of the maximum number of children any DOM element in the page has. The element described will have the most children in the page."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Avoids an excessive DOM size",
-"description":"Title of a diagnostic audit that provides detail on the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM nodes and greatest DOM depth. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Leverage the font-display CSS feature to ensure text is user-visible while webfonts are loading. [Learn more](https://developers.google.com/web/updates/2016/02/font-display).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should use the font-display CSS feature. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Ensure text remains visible during webfont load",
-"description":"Title of a diagnostic audit that provides detail on the load of the page's webfonts. Often the text is invisible for seconds before the webfont resource is loaded. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"All text remains visible during webfont loads",
-"description":"Title of a diagnostic audit that provides detail on if all the text on a webpage was visible while the page was loading its webfonts. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Category",
-"description":"Label for the Main Thread Category column in data tables, rows will have a main thread Category and main thread Task Name."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this.",
-"description":"Description of a Lighthouse audit that tells the user *why* they should reduce JS execution times. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimize main-thread work",
-"description":"Title of a diagnostic audit that provides detail on the main thread work the browser did to load the page. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimizes main-thread work",
-"description":"Title of a diagnostic audit that provides detail on the main thread work the browser did to load the page. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"The score above is an estimate of how long your app takes to respond to user input, in milliseconds, during the busiest 5s window of page load. If your latency is higher than 50 ms, users may perceive your app as laggy. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).",
-"description":"Description of the Estimated Input Latency metric that estimates the amount of time, in milliseconds, that the app takes to respond to user input. This description is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Estimated Input Latency",
-"description":"The name of the metric that marks the estimated time between the page receiving input (a user clicking, tapping, or typing) and the page responding. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint).",
-"description":"Description of the First Contentful Paint (FCP) metric, which marks the time at which the first text or image is painted by the browser. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"First Contentful Paint",
-"description":"The name of the metric that marks the time at which the first text or image is painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"First CPU Idle marks the first time at which the page's main thread is quiet enough to handle input. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).",
-"description":"Description of the First CPU Idle metric, which marks the time at which the page has displayed content and the CPU is not busy executing the page's scripts. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"First CPU Idle",
-"description":"The name of the metric that marks when the page has displayed content and the CPU is not busy executing the page's scripts. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"First Meaningful Paint measures when the primary content of a page is visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).",
-"description":"Description of the First Meaningful Paint (FMP) metric, which marks the time at which a majority of the content has been painted by the browser. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"First Meaningful Paint",
-"description":"The name of the metric that marks the time at which a majority of the content has been painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interactive marks the time at which the page is fully interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).",
-"description":"Description of the Time to Interactive (TTI) metric, which evaluates when a page has completed its primary network activity and main thread work. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Time to Interactive",
-"description":"The name of the metric that marks the time at which the page is fully loaded and is able to quickly respond to user input (clicks, taps, and keypresses feel responsive). Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index).",
-"description":"Description of the Speed Index metric, which summarizes how quickly the page looked visually complete. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Speed Index",
-"description":"The name of the metric that summarizes how quickly the page looked visually complete. The name of this metric is largely abstract and can be loosely translated. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects).",
-"description":"Description of a Lighthouse audit that tells users why they should reduce the number of server-side redirects on their page. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Avoid multiple page redirects",
-"description":"Imperative title of a Lighthouse audit that tells the user to eliminate the redirects taken through multiple URLs to load the page. This is shown in a list of audits that Lighthouse generates."},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Time To First Byte identifies the time at which your server sends a response. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/ttfb).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the amount of time it takes their server to start responding to requests. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Root document took {timeInMs, number, milliseconds} ms",
-"description":"Used to summarize the total Time to First Byte duration for the primary HTML response. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 210 ms)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reduce server response times (TTFB)",
-"description":"Title of a diagnostic audit that provides detail on how long it took from starting a request to when the server started responding. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Server response times are low (TTFB)",
-"description":"Title of a diagnostic audit that provides detail on how long it took from starting a request to when the server started responding. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Duration",
-"description":"Label for the Duration column in the User Timing event data table. User Timing API entries are added by the developer of the web page. Durations are only provided for 'Measure' entries. Durations are the number of total number milliseconds from Start Time to their ending point. e.g. '2,020.64 ms'"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Name",
-"description":"Label for the Name column in the User Timing event data table. User Timing API entries are added by the developer of the web page. An example user timing event name: 'pageload_logoimage_done'"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Start Time",
-"description":"Label for the Start Time column in the User Timing event data table. User Timing API entries are added by the developer of the web page. Start Times are the number of milliseconds since the page started loading, e.g. '380.26 ms'"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Type",
-"description":"Label for the Type column in the User Timing event data table. User Timing API entries are added by the developer of the web page. The only possible types are 'Mark' and Measure'."},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Consider instrumenting your app with the User Timing API to measure your app's real-world performance during key user experiences. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/user-timing).",
-"description":"Description of a Lighthouse audit that tells the user they may want to use the User Timing API to help measure the performance of aspects of their page load and interaction. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount, plural,\n =1 {1 user timing}\n other {# user timings}\n }",
-"description":"[ICU Syntax] Label for an audit identifying the number of User Timing timestamps present in the page."},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing marks and measures",
-"description":"Descriptive title of a diagnostic audit that provides details on any timestamps generated by the page. User Timing refers to the 'User Timing API', which enables a website to record specific times as 'marks', or spans of time as 'measures'."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Consider adding preconnect or dns-prefetch resource hints to establish early connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect).",
-"description":"Description of a Lighthouse audit that tells the user how to connect early to third-party domains that will be used to load page resources. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Preconnect to required origins",
-"description":"Imperative title of a Lighthouse audit that tells the user to connect early to internet domains that will be used to load page resources. Origin is the correct term, however 'domain name' could be used if neccsesary. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Consider using <link rel=preload> to prioritize fetching resources that are currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).",
-"description":"Description of a Lighthouse audit that tells the user *why* they should preload important network requests. The associated network requests are started halfway through pageload (or later) but should be started at the beginning. This is displayed after a user expands the section to see more. No character length limits. '<link rel=preload>' is the html code the user would include in their page and shouldn't be translated. 'Learn More' becomes link text to additional documentation."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Preload key requests",
-"description":"Imperative title of a Lighthouse audit that tells the user to use <link rel=preload> to initiate important network requests earlier during page load. This is displayed in a list of audit titles that Lighthouse generates."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"More information about the performance of your application.",
-"description":"Description of the diagnostics section of the Performance category. Within this section are audits with non-imperative titles that provide more detail on the page's page load performance characteristics. Whereas the 'Opportunities' suggest an action along with expected time savings, diagnostics do not. Within this section, the user may read the details and deduce additional actions they could take."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostics",
-"description":"Title of the diagnostics section of the Performance category. Within this section are audits with non-imperative titles that provide more detail on the page's page load performance characteristics. Whereas the 'Opportunities' suggest an action along with expected time savings, diagnostics do not. Within this section, the user may read the details and deduce additional actions they could take."},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"The most critical aspect of performance is how quickly pixels are rendered onscreen. Key metrics: First Contentful Paint, First Meaningful Paint",
-"description":"Description of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage."},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"First Paint Improvements",
-"description":"Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"These optimizations can speed up your page load.",
-"description":"Description of the opportunity section of the Performance category. 'Optimizations' could also be 'recommendations' or 'suggestions'. Within this section are audits with imperative titles that suggest actions the user can take to improve the loading performance of their web page."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Opportunities",
-"description":"Title of the opportunity section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the loading performance of their web page. 'Suggestion'/'Optimization'/'Recommendation' are reasonable synonyms for 'opportunity' in this case."},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrics",
-"description":"Title of the speed metrics section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds."},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Enhance the overall loading experience, so the page is responsive and ready to use as soon as possible. Key metrics: Time to Interactive, Speed Index",
-"description":"Description of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the overall loading performance of their web page."},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Overall Improvements",
-"description":"Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the overall loading performance of their web page."},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performance",
-"description":"Title of the Performance category of audits. Equivalent to 'Web performance', this term is inclusive of all web page speed and loading optimization topics. Also used as a label of a score gauge; try to limit to 20 characters."},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache TTL",
-"description":"Label for the TTL column in data tables, entries will be the time to live value of the cache header on a web resource"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Size (KB)",
-"description":"Label for the size column in data tables, entries will be the size of a web resource in kilobytes"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Time Spent",
-"description":"Label for the time spent column in data tables, entries will be the number of milliseconds spent during a particular activity"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL",
-"description":"Label for the URL column in data tables, entries will be the URL of a web resource"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potential Savings (KB)",
-"description":"Label for the wasted bytes column in data tables, entries will be the number of kilobytes the user could reduce their page by if they implemented the suggestions"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potential Savings (ms)",
-"description":"Label for the wasted bytes column in data tables, entries will be the number of milliseconds the user could reduce page load by if they implemented the suggestions"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potential savings of {wastedBytes, number, bytes} KB",
-"description":"Label shown per-audit to show how many bytes smaller the page could be if the user implemented the suggestions. The `{wastedBytes}` placeholder will be replaced with the number of bytes, shown in kilobytes (e.g. 148 KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potential savings of {wastedMs, number, milliseconds} ms",
-"description":"Label shown per-audit to show how many milliseconds faster the page load could be if the user implemented the suggestions. The `{wastedMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 140 ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms",
-"description":"Used to show the duration in milliseconds that something lasted. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 63 ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s",
-"description":"Used to show the duration in seconds that something lasted. The {timeInMs} placeholder will be replaced with the time duration, shown in seconds (e.g. 5.2 s)"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Show audits",
-"description":"The tooltip text on an expandable chevron icon. Clicking the icon expands a section to reveal a list of audit results that was hidden by default."},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Initial Navigation",
-"description":"String of text shown in a graphical representation of the flow of network requests for the web page. This label represents the initial network request that fetches an HTML page. This navigation may be redirected (eg. Initial navigation to http://example.com redirects to https://www.example.com)."},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximum critical path latency:",
-"description":"Label of value shown in the summary of critical request chains. Refers to the total amount of time (milliseconds) of the longest critical path chain/sequence of network requests. Example value: 2310 ms"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Error!",
-"description":"A label, shown next to an audit title or metric title, indicating that there was an error computing it. The user can hover on the label to reveal a tooltip with the extended error message. Translation should be short (< 20 characters)."},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Report error: no audit information",
-"description":"An error string displayed next to a particular audit when it has errored, but not provided any specific error message."},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Lab Data",
-"description":"Title of the lab data section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. \"Lab\" is an abbreviated form of \"laboratory\", and refers to the fact that the data is from a controlled test of a website, not measurements from real users visiting that site."},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on emulated 3G. Values are estimated and may vary.",
-"description":"Explanation shown to users below performance results to inform them that the test was done with a 3G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Additional items to manually check",
-"description":"Section heading shown above a list of audits that were not computed by Lighthouse. They serve as a list of suggestions for the user to go and manually check. For example, Lighthouse can't automate testing cross-browser compatibility, so that is listed within this section, so the user is reminded to test it themselves. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list."},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Not applicable",
-"description":"Section heading shown above a list of audits that do not apply to the page. For example, if an audit is 'Are images optimized?', but the page has no images on it, the audit will be marked as not applicable. This is neither passing or failing. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list."},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Opportunity",
-"description":"Column heading label for the listing of opportunity audits. Each audit title represents an opportunity. There are only 2 columns, so no strict character limit."},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Estimated Savings",
-"description":"Column heading label for the estimated page load savings of opportunity audits. Estimated Savings is the total amount of time (in seconds) that Lighthouse computed could be reduced from the total page load time, if the suggested action is taken. There are only 2 columns, so no strict character limit."},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Passed audits",
-"description":"Section heading shown above a list of audits that are passing. 'Passed' here refers to a passing grade. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list."},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Score scale:",
-"description":"Label preceding a pictorial explanation of the scoring scale: 0-50 is red (bad), 50-90 is orange (ok), 90-100 is green (good). These colors are used throughout the report to provide context for how good/bad a particular result is."},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"There were issues affecting this run of Lighthouse:",
-"description":"Label shown preceding any important warnings that may have invalidated the entire report. For example, if the user has Chrome extensions installed, they may add enough performance overhead that Lighthouse's performance metrics are unreliable. If shown, this will be displayed at the top of the report UI."},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Values are estimated and may vary.",
-"description":"Disclaimer shown to users below the metric values (First Contentful Paint, Time to Interactive, etc) to warn them that the numbers they see will likely change slightly the next time they run Lighthouse."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Warnings: ",
-"description":"This label is shown above a bulleted list of warnings. It is shown directly below an audit that produced warnings. Warnings describe situations the user should be aware of, as Lighthouse was unable to complete all the work required on this audit. For example, The 'Unable to decode image (biglogo.jpg)' warning may show up below an image encoding audit."}};
-
-
-
-},{}],36:[function(require,module,exports){
-(function(__filename,__dirname){
-
-
-
-
-
-'use strict';
-
-const path=require('path');
-const isDeepEqual=require('lodash.isequal');
-const log=require('lighthouse-logger');
-const MessageFormat=require('intl-messageformat').default;
-const MessageParser=require('intl-messageformat-parser');
-const lookupClosestLocale=require('lookup-closest-locale');
-const LOCALES=require('./locales.js');
-
-const LH_ROOT=path.join(__dirname,'../../../');
-const MESSAGE_INSTANCE_ID_REGEX=/(.* \| .*) # (\d+)$/;
-
-const MESSAGE_INSTANCE_ID_QUICK_REGEX=/ # \d+$/;
-
-(()=>{
-
-
-try{
-
-const IntlPolyfill=require('intl');
-
-if(!IntlPolyfill.NumberFormat)return;
-
-Intl.NumberFormat=IntlPolyfill.NumberFormat;
-Intl.DateTimeFormat=IntlPolyfill.DateTimeFormat;
-}catch(_){
-log.warn('i18n','Failed to install `intl` polyfill');
-}
-})();
-
-
-const UIStrings={
-
-ms:'{timeInMs, number, milliseconds}\xa0ms',
-
-seconds:'{timeInMs, number, seconds}\xa0s',
-
-displayValueByteSavings:'Potential savings of {wastedBytes, number, bytes}\xa0KB',
-
-displayValueMsSavings:'Potential savings of {wastedMs, number, milliseconds}\xa0ms',
-
-columnURL:'URL',
-
-columnSize:'Size (KB)',
-
-columnCacheTTL:'Cache TTL',
-
-columnWastedBytes:'Potential Savings (KB)',
-
-columnWastedMs:'Potential Savings (ms)',
-
-columnTimeSpent:'Time Spent'};
-
-
-const formats={
-number:{
-bytes:{
-maximumFractionDigits:0},
-
-milliseconds:{
-maximumFractionDigits:0},
-
-seconds:{
-
-minimumFractionDigits:1,
-maximumFractionDigits:1}}};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function lookupLocale(locale){
-
-const canonicalLocale=Intl.getCanonicalLocales(locale)[0];
-
-const closestLocale=lookupClosestLocale(canonicalLocale,LOCALES);
-return closestLocale||'en';
-}
-
-
-
-
-
-function _preprocessMessageValues(icuMessage,values){
-if(!values)return;
-
-const clonedValues=JSON.parse(JSON.stringify(values));
-const parsed=MessageParser.parse(icuMessage);
-
-parsed.elements.
-filter(el=>el.type==='argumentElement').
-forEach(el=>{
-if(el.id&&el.id in values===false){
-throw new Error('ICU Message contains a value reference that wasn\'t provided');
-}
-});
-
-
-parsed.elements.
-filter(el=>el.format&&el.format.style==='milliseconds').
-
-forEach(el=>clonedValues[el.id]=Math.round(clonedValues[el.id]/10)*10);
-
-
-parsed.elements.
-filter(el=>el.format&&el.format.style==='seconds'&&el.id==='timeInMs').
-
-forEach(el=>clonedValues[el.id]=Math.round(clonedValues[el.id]/100)/10);
-
-
-parsed.elements.
-filter(el=>el.format&&el.format.style==='bytes').
-
-forEach(el=>clonedValues[el.id]=clonedValues[el.id]/1024);
-
-return clonedValues;
-}
-
-
-
-
-
-
-
-
-
-const _icuMessageInstanceMap=new Map();
-
-
-
-
-
-
-
-
-
-function _formatIcuMessage(locale,icuMessageId,icuMessage,values){
-const localeMessages=LOCALES[locale];
-const localeMessage=localeMessages[icuMessageId]&&localeMessages[icuMessageId].message;
-
-
-const messageForMessageFormat=localeMessage||icuMessage;
-
-const localeForMessageFormat=locale==='en-XA'?'de-DE':locale;
-
-const valuesForMessageFormat=_preprocessMessageValues(icuMessage,values);
-
-const formatter=new MessageFormat(messageForMessageFormat,localeForMessageFormat,formats);
-const formattedString=formatter.format(valuesForMessageFormat);
-
-return{formattedString,icuMessage:messageForMessageFormat};
-}
-
-
-function _formatPathAsString(pathInLHR){
-let pathAsString='';
-for(const property of pathInLHR){
-if(/^[a-z]+$/i.test(property)){
-if(pathAsString.length)pathAsString+='.';
-pathAsString+=property;
-}else{
-if(/]|"|'|\s/.test(property))throw new Error(`Cannot handle "${property}" in i18n`);
-pathAsString+=`[${property}]`;
-}
-}
-
-return pathAsString;
-}
-
-
-
-
-
-function getRendererFormattedStrings(locale){
-const icuMessageIds=Object.keys(LOCALES[locale]).filter(f=>f.includes('core/report/html/'));
-
-const strings={};
-for(const icuMessageId of icuMessageIds){
-const[filename,varName]=icuMessageId.split(' | ');
-if(!filename.endsWith('util.js'))throw new Error(`Unexpected message: ${icuMessageId}`);
-strings[varName]=LOCALES[locale][icuMessageId].message;
-}
-
-return strings;
-}
-
-
-
-
-
-function createMessageInstanceIdFn(filename,fileStrings){
-
-const mergedStrings={...UIStrings,...fileStrings};
-
-
-const getMessageInstanceIdFn=(icuMessage,values)=>{
-const keyname=Object.keys(mergedStrings).find(key=>mergedStrings[key]===icuMessage);
-if(!keyname)throw new Error(`Could not locate: ${icuMessage}`);
-
-const filenameToLookup=keyname in fileStrings?filename:__filename;
-const unixStyleFilename=path.relative(LH_ROOT,filenameToLookup).replace(/\\/g,'/');
-const icuMessageId=`${unixStyleFilename} | ${keyname}`;
-const icuMessageInstances=_icuMessageInstanceMap.get(icuMessageId)||[];
-
-let indexOfInstance=icuMessageInstances.findIndex(inst=>isDeepEqual(inst.values,values));
-if(indexOfInstance===-1){
-icuMessageInstances.push({icuMessageId,icuMessage,values});
-indexOfInstance=icuMessageInstances.length-1;
-}
-
-_icuMessageInstanceMap.set(icuMessageId,icuMessageInstances);
-
-return`${icuMessageId} # ${indexOfInstance}`;
-};
-
-return getMessageInstanceIdFn;
-}
-
-
-
-
-
-
-function isIcuMessage(icuMessageIdOrRawString){
-return MESSAGE_INSTANCE_ID_QUICK_REGEX.test(icuMessageIdOrRawString)&&
-MESSAGE_INSTANCE_ID_REGEX.test(icuMessageIdOrRawString);
-}
-
-
-
-
-
-
-function getFormatted(icuMessageIdOrRawString,locale){
-if(isIcuMessage(icuMessageIdOrRawString)){
-return _resolveIcuMessageInstanceId(icuMessageIdOrRawString,locale).formattedString;
-}
-
-return icuMessageIdOrRawString;
-}
-
-
-
-
-
-
-function _resolveIcuMessageInstanceId(icuMessageInstanceId,locale){
-const matches=icuMessageInstanceId.match(MESSAGE_INSTANCE_ID_REGEX);
-if(!matches)throw new Error(`${icuMessageInstanceId} is not a valid message instance ID`);
-
-const[_,icuMessageId,icuMessageInstanceIndex]=matches;
-const icuMessageInstances=_icuMessageInstanceMap.get(icuMessageId)||[];
-const icuMessageInstance=icuMessageInstances[Number(icuMessageInstanceIndex)];
-
-const{formattedString}=_formatIcuMessage(locale,icuMessageId,
-icuMessageInstance.icuMessage,icuMessageInstance.values);
-
-return{icuMessageInstance,formattedString};
-}
-
-
-
-
-
-
-
-
-
-function replaceIcuMessageInstanceIds(inputObject,locale){
-
-
-
-
-
-function replaceInObject(subObject,icuMessagePaths,pathInLHR=[]){
-if(typeof subObject!=='object'||!subObject)return;
-
-for(const[property,value]of Object.entries(subObject)){
-const currentPathInLHR=pathInLHR.concat([property]);
-
-
-if(typeof value==='string'&&isIcuMessage(value)){
-const{icuMessageInstance,formattedString}=_resolveIcuMessageInstanceId(value,locale);
-const messageInstancesInLHR=icuMessagePaths[icuMessageInstance.icuMessageId]||[];
-const currentPathAsString=_formatPathAsString(currentPathInLHR);
-
-messageInstancesInLHR.push(
-icuMessageInstance.values?
-{values:icuMessageInstance.values,path:currentPathAsString}:
-currentPathAsString);
-
-
-subObject[property]=formattedString;
-icuMessagePaths[icuMessageInstance.icuMessageId]=messageInstancesInLHR;
-}else{
-replaceInObject(value,icuMessagePaths,currentPathInLHR);
-}
-}
-}
-
-
-const icuMessagePaths={};
-replaceInObject(inputObject,icuMessagePaths);
-return icuMessagePaths;
-}
-
-module.exports={
-_formatPathAsString,
-UIStrings,
-lookupLocale,
-getRendererFormattedStrings,
-createMessageInstanceIdFn,
-getFormatted,
-replaceIcuMessageInstanceIds,
-isIcuMessage};
-
-
-}).call(this,"/../lighthouse-core/lib/i18n/i18n.js","/../lighthouse-core/lib/i18n");
-},{"./locales.js":37,"intl":107,"intl-messageformat":168,"intl-messageformat-parser":166,"lighthouse-logger":147,"lodash.isequal":178,"lookup-closest-locale":179,"path":124}],37:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-const locales={
-'en-US':require('./en-US.json'),
-
-'en':require('./en-US.json'),
-
-
-'en-AU':require('./locales/en-GB.json'),
-'en-GB':require('./locales/en-GB.json'),
-'en-IE':require('./locales/en-GB.json'),
-'en-SG':require('./locales/en-GB.json'),
-'en-ZA':require('./locales/en-GB.json'),
-'en-IN':require('./locales/en-GB.json'),
-
-
-'ar-XB':require('./locales/ar-XB.json'),
-'ar':require('./locales/ar.json'),
-'bg':require('./locales/bg.json'),
-'bs':require('./locales/hr.json'),
-'ca':require('./locales/ca.json'),
-'cs':require('./locales/cs.json'),
-'da':require('./locales/da.json'),
-'de':require('./locales/de.json'),
-'el':require('./locales/el.json'),
-'en-XA':require('./locales/en-XA.json'),
-'es':require('./locales/es.json'),
-'fi':require('./locales/fi.json'),
-'fil':require('./locales/fil.json'),
-'fr':require('./locales/fr.json'),
-'he':require('./locales/he.json'),
-'hi':require('./locales/hi.json'),
-'hr':require('./locales/hr.json'),
-'hu':require('./locales/hu.json'),
-'gsw':require('./locales/de.json'),
-'id':require('./locales/id.json'),
-'in':require('./locales/id.json'),
-'it':require('./locales/it.json'),
-'iw':require('./locales/he.json'),
-'ja':require('./locales/ja.json'),
-'ko':require('./locales/ko.json'),
-'ln':require('./locales/fr.json'),
-'lt':require('./locales/lt.json'),
-'lv':require('./locales/lv.json'),
-'mo':require('./locales/ro.json'),
-'nl':require('./locales/nl.json'),
-'nb':require('./locales/no.json'),
-'no':require('./locales/no.json'),
-'pl':require('./locales/pl.json'),
-'pt':require('./locales/pt.json'),
-'pt-PT':require('./locales/pt-PT.json'),
-'ro':require('./locales/ro.json'),
-'ru':require('./locales/ru.json'),
-'sk':require('./locales/sk.json'),
-'sl':require('./locales/sl.json'),
-'sr':require('./locales/sr.json'),
-'sr-Latn':require('./locales/sr-Latn.json'),
-'sv':require('./locales/sv.json'),
-'ta':require('./locales/ta.json'),
-'te':require('./locales/te.json'),
-'th':require('./locales/th.json'),
-'tl':require('./locales/fil.json'),
-'tr':require('./locales/tr.json'),
-'uk':require('./locales/uk.json'),
-'vi':require('./locales/vi.json'),
-'zh':require('./locales/zh.json'),
-'zh-HK':require('./locales/zh-HK.json'),
-'zh-TW':require('./locales/zh-TW.json')};
-
-
-module.exports=locales;
-
-},{"./en-US.json":35,"./locales/ar-XB.json":38,"./locales/ar.json":39,"./locales/bg.json":40,"./locales/ca.json":41,"./locales/cs.json":42,"./locales/da.json":43,"./locales/de.json":44,"./locales/el.json":45,"./locales/en-GB.json":46,"./locales/en-XA.json":47,"./locales/es.json":48,"./locales/fi.json":49,"./locales/fil.json":50,"./locales/fr.json":51,"./locales/he.json":52,"./locales/hi.json":53,"./locales/hr.json":54,"./locales/hu.json":55,"./locales/id.json":56,"./locales/it.json":57,"./locales/ja.json":58,"./locales/ko.json":59,"./locales/lt.json":60,"./locales/lv.json":61,"./locales/nl.json":62,"./locales/no.json":63,"./locales/pl.json":64,"./locales/pt-PT.json":65,"./locales/pt.json":66,"./locales/ro.json":67,"./locales/ru.json":68,"./locales/sk.json":69,"./locales/sl.json":70,"./locales/sr-Latn.json":71,"./locales/sr.json":72,"./locales/sv.json":73,"./locales/ta.json":74,"./locales/te.json":75,"./locales/th.json":76,"./locales/tr.json":77,"./locales/uk.json":78,"./locales/vi.json":79,"./locales/zh-HK.json":80,"./locales/zh-TW.json":81,"./locales/zh.json":82}],38:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"‏‮Chrome‬‏ ‏‮extensions‬‏ ‏‮negatively‬‏ ‏‮affected‬‏ ‏‮this‬‏ ‏‮page‬‏'‏‮s‬‏ ‏‮load‬‏ ‏‮performance‬‏. ‏‮Try‬‏ ‏‮auditing‬‏ ‏‮the‬‏ ‏‮page‬‏ ‏‮in‬‏ ‏‮incognito‬‏ ‏‮mode‬‏ ‏‮or‬‏ ‏‮from‬‏ ‏‮a‬‏ ‏‮Chrome‬‏ ‏‮profile‬‏ ‏‮without‬‏ ‏‮extensions‬‏."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"‏‮Script‬‏ ‏‮Evaluation‬‏"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"‏‮Script‬‏ ‏‮Parse‬‏"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"‏‮Total‬‏"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"‏‮Consider‬‏ ‏‮reducing‬‏ ‏‮the‬‏ ‏‮time‬‏ ‏‮spent‬‏ ‏‮parsing‬‏, ‏‮compiling‬‏, ‏‮and‬‏ ‏‮executing‬‏ ‏‮JS‬‏. ‏‮You‬‏ ‏‮may‬‏ ‏‮find‬‏ ‏‮delivering‬‏ ‏‮smaller‬‏ ‏‮JS‬‏ ‏‮payloads‬‏ ‏‮helps‬‏ ‏‮with‬‏ ‏‮this‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮bootup‬‏)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"‏‮Reduce‬‏ ‏‮JavaScript‬‏ ‏‮execution‬‏ ‏‮time‬‏"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"‏‮JavaScript‬‏ ‏‮execution‬‏ ‏‮time‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"‏‮Large‬‏ ‏‮GIFs‬‏ ‏‮are‬‏ ‏‮inefficient‬‏ ‏‮for‬‏ ‏‮delivering‬‏ ‏‮animated‬‏ ‏‮content‬‏. ‏‮Consider‬‏ ‏‮using‬‏ ‏‮MPEG‬‏4/‏‮WebM‬‏ ‏‮videos‬‏ ‏‮for‬‏ ‏‮animations‬‏ ‏‮and‬‏ ‏‮PNG‬‏/‏‮WebP‬‏ ‏‮for‬‏ ‏‮static‬‏ ‏‮images‬‏ ‏‮instead‬‏ ‏‮of‬‏ ‏‮GIF‬‏ ‏‮to‬‏ ‏‮save‬‏ ‏‮network‬‏ ‏‮bytes‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮fundamentals‬‏/‏‮performance‬‏/‏‮optimizing‬‏-‏‮content‬‏-‏‮efficiency‬‏/‏‮replace‬‏-‏‮animated‬‏-‏‮gifs‬‏-‏‮with‬‏-‏‮video‬‏/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"‏‮Use‬‏ ‏‮video‬‏ ‏‮formats‬‏ ‏‮for‬‏ ‏‮animated‬‏ ‏‮content‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"‏‮Consider‬‏ ‏‮lazy‬‏-‏‮loading‬‏ ‏‮offscreen‬‏ ‏‮and‬‏ ‏‮hidden‬‏ ‏‮images‬‏ ‏‮after‬‏ ‏‮all‬‏ ‏‮critical‬‏ ‏‮resources‬‏ ‏‮have‬‏ ‏‮finished‬‏ ‏‮loading‬‏ ‏‮to‬‏ ‏‮lower‬‏ ‏‮time‬‏ ‏‮to‬‏ ‏‮interactive‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮offscreen‬‏-‏‮images‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"‏‮Defer‬‏ ‏‮offscreen‬‏ ‏‮images‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"‏‮Resources‬‏ ‏‮are‬‏ ‏‮blocking‬‏ ‏‮the‬‏ ‏‮first‬‏ ‏‮paint‬‏ ‏‮of‬‏ ‏‮your‬‏ ‏‮page‬‏. ‏‮Consider‬‏ ‏‮delivering‬‏ ‏‮critical‬‏ ‏‮JS‬‏/‏‮CSS‬‏ ‏‮inline‬‏ ‏‮and‬‏ ‏‮deferring‬‏ ‏‮all‬‏ ‏‮non‬‏-‏‮critical‬‏ ‏‮JS‬‏/‏‮styles‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮blocking‬‏-‏‮resources‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"‏‮Eliminate‬‏ ‏‮render‬‏-‏‮blocking‬‏ ‏‮resources‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"‏‮Large‬‏ ‏‮network‬‏ ‏‮payloads‬‏ ‏‮cost‬‏ ‏‮users‬‏ ‏‮real‬‏ ‏‮money‬‏ ‏‮and‬‏ ‏‮are‬‏ ‏‮highly‬‏ ‏‮correlated‬‏ ‏‮with‬‏ ‏‮long‬‏ ‏‮load‬‏ ‏‮times‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮network‬‏-‏‮payloads‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"‏‮Total‬‏ ‏‮size‬‏ ‏‮was‬‏ {‏‮totalBytes‬‏} ‏‮KB‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"‏‮Avoid‬‏ ‏‮enormous‬‏ ‏‮network‬‏ ‏‮payloads‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"‏‮Avoids‬‏ ‏‮enormous‬‏ ‏‮network‬‏ ‏‮payloads‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"‏‮Minifying‬‏ ‏‮CSS‬‏ ‏‮files‬‏ ‏‮can‬‏ ‏‮reduce‬‏ ‏‮network‬‏ ‏‮payload‬‏ ‏‮sizes‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮minify‬‏-‏‮css‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"‏‮Minify‬‏ ‏‮CSS‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"‏‮Minifying‬‏ ‏‮JavaScript‬‏ ‏‮files‬‏ ‏‮can‬‏ ‏‮reduce‬‏ ‏‮payload‬‏ ‏‮sizes‬‏ ‏‮and‬‏ ‏‮script‬‏ ‏‮parse‬‏ ‏‮time‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮speed‬‏/‏‮docs‬‏/‏‮insights‬‏/‏‮MinifyResources‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"‏‮Minify‬‏ ‏‮JavaScript‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"‏‮Remove‬‏ ‏‮unused‬‏ ‏‮rules‬‏ ‏‮from‬‏ ‏‮stylesheets‬‏ ‏‮to‬‏ ‏‮reduce‬‏ ‏‮unnecessary‬‏ ‏‮bytes‬‏ ‏‮consumed‬‏ ‏‮by‬‏ ‏‮network‬‏ ‏‮activity‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮unused‬‏-‏‮css‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"‏‮Defer‬‏ ‏‮unused‬‏ ‏‮CSS‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"‏‮Remove‬‏ ‏‮unused‬‏ ‏‮JavaScript‬‏ ‏‮to‬‏ ‏‮reduce‬‏ ‏‮bytes‬‏ ‏‮consumed‬‏ ‏‮by‬‏ ‏‮network‬‏ ‏‮activity‬‏."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"‏‮Remove‬‏ ‏‮unused‬‏ ‏‮JavaScript‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"‏‮A‬‏ ‏‮long‬‏ ‏‮cache‬‏ ‏‮lifetime‬‏ ‏‮can‬‏ ‏‮speed‬‏ ‏‮up‬‏ ‏‮repeat‬‏ ‏‮visits‬‏ ‏‮to‬‏ ‏‮your‬‏ ‏‮page‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮cache‬‏-‏‮policy‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ‏‮resource‬‏ ‏‮found‬‏}zero{# ‏‮resources‬‏ ‏‮found‬‏}two{# ‏‮resources‬‏ ‏‮found‬‏}few{# ‏‮resources‬‏ ‏‮found‬‏}many{# ‏‮resources‬‏ ‏‮found‬‏}other{# ‏‮resources‬‏ ‏‮found‬‏}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"‏‮Serve‬‏ ‏‮static‬‏ ‏‮assets‬‏ ‏‮with‬‏ ‏‮an‬‏ ‏‮efficient‬‏ ‏‮cache‬‏ ‏‮policy‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"‏‮Uses‬‏ ‏‮efficient‬‏ ‏‮cache‬‏ ‏‮policy‬‏ ‏‮on‬‏ ‏‮static‬‏ ‏‮assets‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"‏‮Optimized‬‏ ‏‮images‬‏ ‏‮load‬‏ ‏‮faster‬‏ ‏‮and‬‏ ‏‮consume‬‏ ‏‮less‬‏ ‏‮cellular‬‏ ‏‮data‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮optimize‬‏-‏‮images‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"‏‮Efficiently‬‏ ‏‮encode‬‏ ‏‮images‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"‏‮Serve‬‏ ‏‮images‬‏ ‏‮that‬‏ ‏‮are‬‏ ‏‮appropriately‬‏-‏‮sized‬‏ ‏‮to‬‏ ‏‮save‬‏ ‏‮cellular‬‏ ‏‮data‬‏ ‏‮and‬‏ ‏‮improve‬‏ ‏‮load‬‏ ‏‮time‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮oversized‬‏-‏‮images‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"‏‮Properly‬‏ ‏‮size‬‏ ‏‮images‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"‏‮Text‬‏-‏‮based‬‏ ‏‮resources‬‏ ‏‮should‬‏ ‏‮be‬‏ ‏‮served‬‏ ‏‮with‬‏ ‏‮compression‬‏ (‏‮gzip‬‏, ‏‮deflate‬‏ ‏‮or‬‏ ‏‮brotli‬‏) ‏‮to‬‏ ‏‮minimize‬‏ ‏‮total‬‏ ‏‮network‬‏ ‏‮bytes‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮text‬‏-‏‮compression‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"‏‮Enable‬‏ ‏‮text‬‏ ‏‮compression‬‏"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"‏‮Image‬‏ ‏‮formats‬‏ ‏‮like‬‏ ‏‮JPEG‬‏ 2000, ‏‮JPEG‬‏ ‏‮XR‬‏, ‏‮and‬‏ ‏‮WebP‬‏ ‏‮often‬‏ ‏‮provide‬‏ ‏‮better‬‏ ‏‮compression‬‏ ‏‮than‬‏ ‏‮PNG‬‏ ‏‮or‬‏ ‏‮JPEG‬‏, ‏‮which‬‏ ‏‮means‬‏ ‏‮faster‬‏ ‏‮downloads‬‏ ‏‮and‬‏ ‏‮less‬‏ ‏‮data‬‏ ‏‮consumption‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮webp‬‏)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"‏‮Serve‬‏ ‏‮images‬‏ ‏‮in‬‏ ‏‮next‬‏-‏‮gen‬‏ ‏‮formats‬‏"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"‏‮The‬‏ ‏‮Critical‬‏ ‏‮Request‬‏ ‏‮Chains‬‏ ‏‮below‬‏ ‏‮show‬‏ ‏‮you‬‏ ‏‮what‬‏ ‏‮resources‬‏ ‏‮are‬‏ ‏‮loaded‬‏ ‏‮with‬‏ ‏‮a‬‏ ‏‮high‬‏ ‏‮priority‬‏. ‏‮Consider‬‏ ‏‮reducing‬‏ ‏‮the‬‏ ‏‮length‬‏ ‏‮of‬‏ ‏‮chains‬‏, ‏‮reducing‬‏ ‏‮the‬‏ ‏‮download‬‏ ‏‮size‬‏ ‏‮of‬‏ ‏‮resources‬‏, ‏‮or‬‏ ‏‮deferring‬‏ ‏‮the‬‏ ‏‮download‬‏ ‏‮of‬‏ ‏‮unnecessary‬‏ ‏‮resources‬‏ ‏‮to‬‏ ‏‮improve‬‏ ‏‮page‬‏ ‏‮load‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮critical‬‏-‏‮request‬‏-‏‮chains‬‏)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ‏‮chain‬‏ ‏‮found‬‏}zero{# ‏‮chains‬‏ ‏‮found‬‏}two{# ‏‮chains‬‏ ‏‮found‬‏}few{# ‏‮chains‬‏ ‏‮found‬‏}many{# ‏‮chains‬‏ ‏‮found‬‏}other{# ‏‮chains‬‏ ‏‮found‬‏}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"‏‮Minimize‬‏ ‏‮Critical‬‏ ‏‮Requests‬‏ ‏‮Depth‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"‏‮Element‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"‏‮Statistic‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"‏‮Value‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"‏‮Browser‬‏ ‏‮engineers‬‏ ‏‮recommend‬‏ ‏‮pages‬‏ ‏‮contain‬‏ ‏‮fewer‬‏ ‏‮than‬‏ ~1,500 ‏‮DOM‬‏ ‏‮nodes‬‏. ‏‮The‬‏ ‏‮sweet‬‏ ‏‮spot‬‏ ‏‮is‬‏ ‏‮a‬‏ ‏‮tree‬‏ ‏‮depth‬‏ < 32 ‏‮elements‬‏ ‏‮and‬‏ ‏‮fewer‬‏ ‏‮than‬‏ 60 ‏‮children‬‏/‏‮parent‬‏ ‏‮element‬‏. ‏‮A‬‏ ‏‮large‬‏ ‏‮DOM‬‏ ‏‮can‬‏ ‏‮increase‬‏ ‏‮memory‬‏ ‏‮usage‬‏, ‏‮cause‬‏ ‏‮longer‬‏ [‏‮style‬‏ ‏‮calculations‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮fundamentals‬‏/‏‮performance‬‏/‏‮rendering‬‏/‏‮reduce‬‏-‏‮the‬‏-‏‮scope‬‏-‏‮and‬‏-‏‮complexity‬‏-‏‮of‬‏-‏‮style‬‏-‏‮calculations‬‏), ‏‮and‬‏ ‏‮produce‬‏ ‏‮costly‬‏ [‏‮layout‬‏ ‏‮reflows‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮speed‬‏/‏‮articles‬‏/‏‮reflow‬‏). [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮dom‬‏-‏‮size‬‏)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ‏‮node‬‏}zero{# ‏‮nodes‬‏}two{# ‏‮nodes‬‏}few{# ‏‮nodes‬‏}many{# ‏‮nodes‬‏}other{# ‏‮nodes‬‏}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"‏‮Avoid‬‏ ‏‮an‬‏ ‏‮excessive‬‏ ‏‮DOM‬‏ ‏‮size‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"‏‮Maximum‬‏ ‏‮DOM‬‏ ‏‮Depth‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"‏‮Total‬‏ ‏‮DOM‬‏ ‏‮Nodes‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"‏‮Maximum‬‏ ‏‮Child‬‏ ‏‮Elements‬‏"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"‏‮Avoids‬‏ ‏‮an‬‏ ‏‮excessive‬‏ ‏‮DOM‬‏ ‏‮size‬‏"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"‏‮Leverage‬‏ ‏‮the‬‏ ‏‮font‬‏-‏‮display‬‏ ‏‮CSS‬‏ ‏‮feature‬‏ ‏‮to‬‏ ‏‮ensure‬‏ ‏‮text‬‏ ‏‮is‬‏ ‏‮user‬‏-‏‮visible‬‏ ‏‮while‬‏ ‏‮webfonts‬‏ ‏‮are‬‏ ‏‮loading‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮updates‬‏/2016/02/‏‮font‬‏-‏‮display‬‏)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"‏‮Ensure‬‏ ‏‮text‬‏ ‏‮remains‬‏ ‏‮visible‬‏ ‏‮during‬‏ ‏‮webfont‬‏ ‏‮load‬‏"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"‏‮All‬‏ ‏‮text‬‏ ‏‮remains‬‏ ‏‮visible‬‏ ‏‮during‬‏ ‏‮webfont‬‏ ‏‮loads‬‏"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"‏‮Category‬‏"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"‏‮Consider‬‏ ‏‮reducing‬‏ ‏‮the‬‏ ‏‮time‬‏ ‏‮spent‬‏ ‏‮parsing‬‏, ‏‮compiling‬‏ ‏‮and‬‏ ‏‮executing‬‏ ‏‮JS‬‏. ‏‮You‬‏ ‏‮may‬‏ ‏‮find‬‏ ‏‮delivering‬‏ ‏‮smaller‬‏ ‏‮JS‬‏ ‏‮payloads‬‏ ‏‮helps‬‏ ‏‮with‬‏ ‏‮this‬‏."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"‏‮Minimize‬‏ ‏‮main‬‏-‏‮thread‬‏ ‏‮work‬‏"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"‏‮Minimizes‬‏ ‏‮main‬‏-‏‮thread‬‏ ‏‮work‬‏"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"‏‮The‬‏ ‏‮score‬‏ ‏‮above‬‏ ‏‮is‬‏ ‏‮an‬‏ ‏‮estimate‬‏ ‏‮of‬‏ ‏‮how‬‏ ‏‮long‬‏ ‏‮your‬‏ ‏‮app‬‏ ‏‮takes‬‏ ‏‮to‬‏ ‏‮respond‬‏ ‏‮to‬‏ ‏‮user‬‏ ‏‮input‬‏, ‏‮in‬‏ ‏‮milliseconds‬‏, ‏‮during‬‏ ‏‮the‬‏ ‏‮busiest‬‏ 5‏‮s‬‏ ‏‮window‬‏ ‏‮of‬‏ ‏‮page‬‏ ‏‮load‬‏. ‏‮If‬‏ ‏‮your‬‏ ‏‮latency‬‏ ‏‮is‬‏ ‏‮higher‬‏ ‏‮than‬‏ 50 ‏‮ms‬‏, ‏‮users‬‏ ‏‮may‬‏ ‏‮perceive‬‏ ‏‮your‬‏ ‏‮app‬‏ ‏‮as‬‏ ‏‮laggy‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮estimated‬‏-‏‮input‬‏-‏‮latency‬‏)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"‏‮Estimated‬‏ ‏‮Input‬‏ ‏‮Latency‬‏"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"‏‮First‬‏ ‏‮Contentful‬‏ ‏‮Paint‬‏ ‏‮marks‬‏ ‏‮the‬‏ ‏‮time‬‏ ‏‮at‬‏ ‏‮which‬‏ ‏‮the‬‏ ‏‮first‬‏ ‏‮text‬‏ ‏‮or‬‏ ‏‮image‬‏ ‏‮is‬‏ ‏‮painted‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮first‬‏-‏‮contentful‬‏-‏‮paint‬‏)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"‏‮First‬‏ ‏‮Contentful‬‏ ‏‮Paint‬‏"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"‏‮First‬‏ ‏‮CPU‬‏ ‏‮Idle‬‏ ‏‮marks‬‏ ‏‮the‬‏ ‏‮first‬‏ ‏‮time‬‏ ‏‮at‬‏ ‏‮which‬‏ ‏‮the‬‏ ‏‮page‬‏'‏‮s‬‏ ‏‮main‬‏ ‏‮thread‬‏ ‏‮is‬‏ ‏‮quiet‬‏ ‏‮enough‬‏ ‏‮to‬‏ ‏‮handle‬‏ ‏‮input‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮first‬‏-‏‮interactive‬‏)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"‏‮First‬‏ ‏‮CPU‬‏ ‏‮Idle‬‏"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"‏‮First‬‏ ‏‮Meaningful‬‏ ‏‮Paint‬‏ ‏‮measures‬‏ ‏‮when‬‏ ‏‮the‬‏ ‏‮primary‬‏ ‏‮content‬‏ ‏‮of‬‏ ‏‮a‬‏ ‏‮page‬‏ ‏‮is‬‏ ‏‮visible‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮first‬‏-‏‮meaningful‬‏-‏‮paint‬‏)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"‏‮First‬‏ ‏‮Meaningful‬‏ ‏‮Paint‬‏"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"‏‮Interactive‬‏ ‏‮marks‬‏ ‏‮the‬‏ ‏‮time‬‏ ‏‮at‬‏ ‏‮which‬‏ ‏‮the‬‏ ‏‮page‬‏ ‏‮is‬‏ ‏‮fully‬‏ ‏‮interactive‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮consistently‬‏-‏‮interactive‬‏)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"‏‮Time‬‏ ‏‮to‬‏ ‏‮Interactive‬‏"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"‏‮Speed‬‏ ‏‮Index‬‏ ‏‮shows‬‏ ‏‮how‬‏ ‏‮quickly‬‏ ‏‮the‬‏ ‏‮contents‬‏ ‏‮of‬‏ ‏‮a‬‏ ‏‮page‬‏ ‏‮are‬‏ ‏‮visibly‬‏ ‏‮populated‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮speed‬‏-‏‮index‬‏)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"‏‮Speed‬‏ ‏‮Index‬‏"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"‏‮Redirects‬‏ ‏‮introduce‬‏ ‏‮additional‬‏ ‏‮delays‬‏ ‏‮before‬‏ ‏‮the‬‏ ‏‮page‬‏ ‏‮can‬‏ ‏‮be‬‏ ‏‮loaded‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮redirects‬‏)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"‏‮Avoid‬‏ ‏‮multiple‬‏ ‏‮page‬‏ ‏‮redirects‬‏"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"‏‮Time‬‏ ‏‮To‬‏ ‏‮First‬‏ ‏‮Byte‬‏ ‏‮identifies‬‏ ‏‮the‬‏ ‏‮time‬‏ ‏‮at‬‏ ‏‮which‬‏ ‏‮your‬‏ ‏‮server‬‏ ‏‮sends‬‏ ‏‮a‬‏ ‏‮response‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮ttfb‬‏)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"‏‮Root‬‏ ‏‮document‬‏ ‏‮took‬‏ {‏‮timeInMs‬‏} ‏‮ms‬‏"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"‏‮Reduce‬‏ ‏‮server‬‏ ‏‮response‬‏ ‏‮times‬‏ (‏‮TTFB‬‏)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"‏‮Server‬‏ ‏‮response‬‏ ‏‮times‬‏ ‏‮are‬‏ ‏‮low‬‏ (‏‮TTFB‬‏)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"‏‮Duration‬‏"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"‏‮Name‬‏"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"‏‮Start‬‏ ‏‮Time‬‏"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"‏‮Type‬‏"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"‏‮Consider‬‏ ‏‮instrumenting‬‏ ‏‮your‬‏ ‏‮app‬‏ ‏‮with‬‏ ‏‮the‬‏ ‏‮User‬‏ ‏‮Timing‬‏ ‏‮API‬‏ ‏‮to‬‏ ‏‮measure‬‏ ‏‮your‬‏ ‏‮app‬‏'‏‮s‬‏ ‏‮real‬‏-‏‮world‬‏ ‏‮performance‬‏ ‏‮during‬‏ ‏‮key‬‏ ‏‮user‬‏ ‏‮experiences‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮user‬‏-‏‮timing‬‏)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ‏‮user‬‏ ‏‮timing‬‏}zero{# ‏‮user‬‏ ‏‮timings‬‏}two{# ‏‮user‬‏ ‏‮timings‬‏}few{# ‏‮user‬‏ ‏‮timings‬‏}many{# ‏‮user‬‏ ‏‮timings‬‏}other{# ‏‮user‬‏ ‏‮timings‬‏}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"‏‮User‬‏ ‏‮Timing‬‏ ‏‮marks‬‏ ‏‮and‬‏ ‏‮measures‬‏"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"‏‮Consider‬‏ ‏‮adding‬‏ ‏‮preconnect‬‏ ‏‮or‬‏ ‏‮dns‬‏-‏‮prefetch‬‏ ‏‮resource‬‏ ‏‮hints‬‏ ‏‮to‬‏ ‏‮establish‬‏ ‏‮early‬‏ ‏‮connections‬‏ ‏‮to‬‏ ‏‮important‬‏ ‏‮third‬‏-‏‮party‬‏ ‏‮origins‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮fundamentals‬‏/‏‮performance‬‏/‏‮resource‬‏-‏‮prioritization‬‏#‏‮preconnect‬‏)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"‏‮Preconnect‬‏ ‏‮to‬‏ ‏‮required‬‏ ‏‮origins‬‏"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"‏‮Consider‬‏ ‏‮using‬‏ <link rel=preload> ‏‮to‬‏ ‏‮prioritize‬‏ ‏‮fetching‬‏ ‏‮resources‬‏ ‏‮that‬‏ ‏‮are‬‏ ‏‮currently‬‏ ‏‮requested‬‏ ‏‮later‬‏ ‏‮in‬‏ ‏‮page‬‏ ‏‮load‬‏. [‏‮Learn‬‏ ‏‮more‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/‏‮audits‬‏/‏‮preload‬‏)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"‏‮Preload‬‏ ‏‮key‬‏ ‏‮requests‬‏"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"‏‮More‬‏ ‏‮information‬‏ ‏‮about‬‏ ‏‮the‬‏ ‏‮performance‬‏ ‏‮of‬‏ ‏‮your‬‏ ‏‮application‬‏."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"‏‮Diagnostics‬‏"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"‏‮The‬‏ ‏‮most‬‏ ‏‮critical‬‏ ‏‮aspect‬‏ ‏‮of‬‏ ‏‮performance‬‏ ‏‮is‬‏ ‏‮how‬‏ ‏‮quickly‬‏ ‏‮pixels‬‏ ‏‮are‬‏ ‏‮rendered‬‏ ‏‮onscreen‬‏. ‏‮Key‬‏ ‏‮metrics‬‏: ‏‮First‬‏ ‏‮Contentful‬‏ ‏‮Paint‬‏, ‏‮First‬‏ ‏‮Meaningful‬‏ ‏‮Paint‬‏"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"‏‮First‬‏ ‏‮Paint‬‏ ‏‮Improvements‬‏"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"‏‮These‬‏ ‏‮optimizations‬‏ ‏‮can‬‏ ‏‮speed‬‏ ‏‮up‬‏ ‏‮your‬‏ ‏‮page‬‏ ‏‮load‬‏."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"‏‮Opportunities‬‏"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"‏‮Metrics‬‏"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"‏‮Enhance‬‏ ‏‮the‬‏ ‏‮overall‬‏ ‏‮loading‬‏ ‏‮experience‬‏, ‏‮so‬‏ ‏‮the‬‏ ‏‮page‬‏ ‏‮is‬‏ ‏‮responsive‬‏ ‏‮and‬‏ ‏‮ready‬‏ ‏‮to‬‏ ‏‮use‬‏ ‏‮as‬‏ ‏‮soon‬‏ ‏‮as‬‏ ‏‮possible‬‏. ‏‮Key‬‏ ‏‮metrics‬‏: ‏‮Time‬‏ ‏‮to‬‏ ‏‮Interactive‬‏, ‏‮Speed‬‏ ‏‮Index‬‏"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"‏‮Overall‬‏ ‏‮Improvements‬‏"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"‏‮Performance‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"‏‮Cache‬‏ ‏‮TTL‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"‏‮Size‬‏ (‏‮KB‬‏)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"‏‮Time‬‏ ‏‮Spent‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"‏‮URL‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"‏‮Potential‬‏ ‏‮Savings‬‏ (‏‮KB‬‏)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"‏‮Potential‬‏ ‏‮Savings‬‏ (‏‮ms‬‏)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"‏‮Potential‬‏ ‏‮savings‬‏ ‏‮of‬‏ {‏‮wastedBytes‬‏} ‏‮KB‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"‏‮Potential‬‏ ‏‮savings‬‏ ‏‮of‬‏ {‏‮wastedMs‬‏} ‏‮ms‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{‏‮timeInMs‬‏} ‏‮ms‬‏"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{‏‮timeInMsSec‬‏} ‏‮s‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"‏‮Show‬‏ ‏‮audits‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"‏‮Initial‬‏ ‏‮Navigation‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"‏‮Maximum‬‏ ‏‮critical‬‏ ‏‮path‬‏ ‏‮latency‬‏:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"‏‮Error‬‏!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"‏‮Report‬‏ ‏‮error‬‏: ‏‮no‬‏ ‏‮audit‬‏ ‏‮information‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"‏‮Lab‬‏ ‏‮Data‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[‏‮Lighthouse‬‏](‏‮https‬‏://‏‮developers‬‏.‏‮google‬‏.‏‮com‬‏/‏‮web‬‏/‏‮tools‬‏/‏‮lighthouse‬‏/) ‏‮analysis‬‏ ‏‮of‬‏ ‏‮the‬‏ ‏‮current‬‏ ‏‮page‬‏ ‏‮on‬‏ ‏‮emulated‬‏ 3‏‮G‬‏. ‏‮Values‬‏ ‏‮are‬‏ ‏‮estimated‬‏ ‏‮and‬‏ ‏‮may‬‏ ‏‮vary‬‏."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"‏‮Additional‬‏ ‏‮items‬‏ ‏‮to‬‏ ‏‮manually‬‏ ‏‮check‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"‏‮Not‬‏ ‏‮applicable‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"‏‮Opportunity‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"‏‮Estimated‬‏ ‏‮Savings‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"‏‮Passed‬‏ ‏‮audits‬‏"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"‏‮Score‬‏ ‏‮scale‬‏:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"‏‮There‬‏ ‏‮were‬‏ ‏‮issues‬‏ ‏‮affecting‬‏ ‏‮this‬‏ ‏‮run‬‏ ‏‮of‬‏ ‏‮Lighthouse‬‏:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"‏‮Values‬‏ ‏‮are‬‏ ‏‮estimated‬‏ ‏‮and‬‏ ‏‮may‬‏ ‏‮vary‬‏."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"‏‮Warnings‬‏: "}};
-
-
-},{}],39:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"أثّرت \"إضافات Chrome\" بشكلٍ سلبي في أداء التحميل لهذه الصفحة. ويمكنك تجربة تدقيق الصفحة في وضع التصفُّح المُتخفّي أو من ملف شخصي على Chrome بدون الإضافات."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"تقييم النص البرمجي"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"تحليل النص البرمجي"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"الإجمالي"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"يمكنك تقليل الوقت المستغرق في تحليل جافا سكريبت وإنشائه وتنفيذه. قد يتبين لك أن تسليم أحمال جافا سكريبت بحجم أصغر يساعد في ذلك. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"تقليل وقت تنفيذ جافا سكريبت"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"وقت تنفيذ جافا سكريبت"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"لا تكفي ملفات GIF الكبيرة لتسليم محتوى صور متحركة. لذا يمكنك استخدام فيديوهات MPEG4 / WebM للصور المتحركة وملفات PNG / WebP للصور الثابتة بدلاً من ملفات GIF لحفظ وحدات البايت للشبكة. [مزيد من المعلومات](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"استخدام تنسيقات الفيديو لمحتوى الصور المتحركة"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"خُذ بعين الاعتبار التحميل البطئ خارج الشاشة والصور المخفية بعد الانتهاء من تحميل جميع الموارد المهمة في وقت أقل تفاعلية. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"تأجيل الصور خارج الشاشة"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"تحظر الموارد العرض الأول لصفحتك. ويمكنك تسليم تضمين JS / CSS المهم وتأجيل كل الأنماط/جافا سكريبت غير المهمة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"استبعاد موارد حظر العرض"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"تُكلِّف أحمال الشبكة الكبيرة المستخدمين الكثير من الأموال وترتبط مباشرةً بأوقات التحميل الطويلة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"كان إجمالي الحجم {totalBytes, number, bytes} كيلوبايت"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"تجنُّب الأحمال الضخمة للشبكة"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"تجنُّب الأحمال الضخمة للشبكة"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"يمكن أن يؤدي تصغير ملفات CSS إلى تقليل أحجام حمولة الشبكة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"تصغير CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"يمكن أن يؤدي تصغير ملفات جافا سكريبت إلى تقليل أحجام الأحمال ووقت تحليل النص البرمجي. [مزيد من المعلومات](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"تصغير جافا سكريبت"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"يمكنك إزالة القواعد غير المُستخدَمة من ورق الأنماط لتقليل وحدات البايت غير الضرورية التي يستهلكها نشاط الشبكة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"تأجيل CSS غير المُستخدَم"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"يمكنك إزالة جافا سكريبت غير المُستخدَم لتقليل وحدات البايت التي يستهلكها نشاط الشبكة."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"إزالة جافا سكريبت غير المستخدم"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"يمكن لفترة التخزين المؤقت الطويلة تسريع عملية تكرار الزيارات إلى صفحتك. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{تم العثور على مورد واحد}zero{تم العثور على # مورد}two{تم العثور على مورديْنِ (#)}few{تم العثور على # موارد}many{تم العثور على # موردًا}other{تم العثور على # مورد}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"عرض الأصول الثابتة من خلال سياسة ذاكرة التخزين المؤقت الفعالة"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"استخدام سياسة ذاكرة التخزين المؤقت الفعالة على الأصول الثابتة"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"يتم تحميل الصور المحسَّنة بشكلٍ أسرع وتستهلك بيانات أقل لشبكة الجوّال. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"تشفير الصور بكفاءة"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"يمكنك عرض صور بحجم مناسب لحفظ بيانات شبكة الجوّال وتحسين وقت التحميل. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"الصور ذات الحجم المناسب"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"يجب عرض الموارد المستندة إلى النص باستخدام الضغط (gzip أو الانكماش أو brotli) لتقليل إجمالي وحدات البايت للشبكة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"تفعيل ضغط النص"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"غالبًا ما توفِّر تنسيقات الصور، مثل JPEG 2000 وJPEG XR وWebP، ضغطًا أفضل من تنسيق PNG أو JPEG، وهذا بدوره يعني تنزيلاً أسرع واستهلاكًا أقل للبيانات. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"عرض الصور بتنسيقات الجيل القادم"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"توضح لك \"سلاسل الطلبات المهمة\" أدناه الموارد التي تم تحميلها بأولوية عالية. ويمكنك تقليل طول السلاسل أو تقليل حجم تنزيل الموارد أو تأجيل تنزيل الموارد غير الضرورية لتحسين تحميل الصفحة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{تم العثور على سلسلة واحدة}zero{تم العثور على # سلسلة}two{تم العثور على سلسلتيْنِ (#)}few{تم العثور على # سلاسل}many{تم العثور على # سلسلةً}other{تم العثور على # سلسلة}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"تقليل عمق الطلبات المهمة"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"يوصي مهندسو المتصفّح بالصفحات التي تحتوي على أقل من ~1500 عُقدة DOM. وتمثل sweet spot شبكة عمقها < 32 عنصرًا ولا تزيد عن 60 عنصرًا فرعيًا/رئيسيًا. ويمكن أن تزيد عُقدة DOM الكبيرة من استخدام الذاكرة، وتسبب [عمليات حسابية نمطية] أطول (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations)، وتنتج [عمليات إعادة عرض للتنسيق] مُكلفة (https://developers.google.com/speed/articles/reflow). [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{عقدة واحدة}zero{# عقدة}two{عقدتان (#)}few{# عُقَد}many{# عقدةً}other{# عقدة}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"تجنُب حجم DOM الزائد"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"الحد الأقصى لعمق DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"إجمالى عُقَدْ DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"تجنُب حجم DOM الزائد"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"يمكنك الاستفادة من ميزة CSS لعرض الخطوط لضمان أن يكون النص مرئيًا للمستخدم أثناء تحميل خطوط موقع ويب. [مزيد من المعلومات](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"التأكد من بقاء النص مرئيًا أثناء تحميل خط موقع ويب"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"تظل جميع النصوص مرئية أثناء تحميل خط موقع ويب"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"الفئة"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"يمكنك تقليل الوقت المستغرق في تحليل جافا سكريبت وإنشائه وتنفيذه. قد يتبين لك أن تسليم أحمال جافا سكريبت بحجم أصغر يساعد في ذلك."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"تقليل سلسلة العمل الرئيسية"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"تقليل سلسلة العمل الرئيسية"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"إن النتيجة الواردة أعلاه تمثل تقديرًا لطول المدة التي يستغرقها تطبيقك في الاستجابة لإدخال المستخدم، بالمللي ثانية، أثناء فترة تحميل الصفحة الأكثر انشغالاً خلال 5 ثوانٍ. إذا كان وقت الاستجابة أكثر من 50 مللي ثانية، يمكن للمستخدمين اعتبار تطبيقك بأنه \"بطيء في التفاعل\". [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"وقت الاستجابة المُقدّر للإدخال"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"تحدد \"سرعة عرض المحتوى على الصفحة\" الوقت الذي يُعرَض فيه أول صورة أو نص. [مزيد من المعلومات](https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#first_paint_and_first_contentful_paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"First Contentful Paint"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"تشير \"وحدة المعالجة المركزية الأولى الخاملة\" إلى المرة الأولى التي تكون فيها السلسلة الرئيسية للصفحة كافية للتعامل مع الإدخال. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"وحدة المعالجة المركزية الأولى الخاملة"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"يقيس First Meaningful Paint الوقت الذي يكون فيه المحتوى الأساسي لصفحة مرئيًا. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"First Meaningful Paint"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"يميّز \"الوضع التفاعلي\" الوقت الذي تكون فيه الصفحة تفاعلية بالكامل. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"وقت التفاعل"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"يوضح مؤشر السرعة مدى سرعة تعبئة محتوى الصفحة بشكلٍ واضح. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"مؤشر السرعة"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"تؤدي عمليات إعادة التوجيه إلى حدوث تأخيرات إضافية قبل أن يتم تحميل الصفحة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"تجنُب عمليات إعادة توجيه الصفحات المتعددة"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"يحدد \"وقت وصول أول بايت\" الوقت الذي يُرسل فيه الخادم استجابة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"استغرق مستند الجذر {timeInMs, number, milliseconds} مللي ثانية."},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"تقليل أوقات استجابة الخادم (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"أوقات استجابة الخادم منخفضة (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"المدة"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"الاسم"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"وقت البدء"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"النوع"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"يمكنك توجيه تطبيقك باستخدام \"واجهة برمجة التطبيقات لأوقات المستخدم\" لقياس الأداء الفعلي لتطبيقك أثناء التجارب الأساسية للمستخدمين. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{وقت واحد للمستخدم}zero{# وقت للمستخدم}two{وقتا (#) المستخدم}few{# أوقات للمستخدم}many{# وقتًا للمستخدم}other{# وقت للمستخدم}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"علامات أوقات المستخدم وقياساتها"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"يمكنك إضافة الاتصال المسبق أو تعديلات موارد الجلب المسبق لنظام أسماء النطاقات لإنشاء اتصالات مبكرة بأصول مهمة تابعة لجهة خارجية. [مزيد من المعلومات](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"الاتصال المسبق للأصول المطلوبة"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"يمكنك استخدام <link rel = preload> لتحديد أولويات جلب الموارد المطلوبة حاليًا في وقتٍ لاحق في تحميل الصفحة. [مزيد من المعلومات](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"التحميل المسبق للطلبات الأساسية"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"مزيد من المعلومات حول أداء تطبيقك."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"بيانات التشخيص"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"يمثل الجانب الأكثر أهمية للأداء مدى السرعة التي يتم بها عرض وحدات البكسل على الشاشة. المقاييس الرئيسية: First Contentful Paint وFirst Meaningful Paint"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"تحسينات العرض الأول"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"يمكن لهذه التحسينات تسريع عملية تحميل الصفحة."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"فرص تحسين الأداء"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"المقاييس"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"يمكنك تحسين تجربة التحميل العامة لتصبح هذه الصفحة سريعة الاستجابة وجاهزة للاستخدام في أقرب وقت ممكن. المقاييس الأساسية: وقت التفاعل ومؤشر السرعة."},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"التحسينات العامة"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"الأداء"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"ذاكرة التخزين المؤقت TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"الحجم (كيلوبايت)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"الوقت المستغرَق"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"عنوان URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"التوفيرات المحتملة (كيلوبايت)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"التوفيرات المحتملة (مللي ثانية)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"التوفيرات المحتملة من {wastedBytes, number, bytes} كيلوبايت"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"التوفيرات المحتملة لـ {wastedMs, number, milliseconds} مللي ثانية"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} مللي ثانية"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} ثانية"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"عرض عمليات التدقيق"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"التنقل الأوّلي"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"الحد الأقصى لوقت استجابة المسار المهم:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"خطأ!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"الإبلاغ عن خطأ: لا تتوفَّر معلومات تدقيق"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"بيانات المختبَر"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) تحليل الصفحة الحالية على شبكة الجيل الثالث في وضع المحاكاة. القيم تقديرية وقابلة للتغيير."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"عناصر إضافية للتحقُّق يدويًا"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"غير سارٍ"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"فرصة تحسين الأداء"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"التوفيرات المُقدرة"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"اجتياز عمليات التدقيق بنجاح"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"مقياس النتيجة:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"حدثت مشاكل تؤثر في تشغيل Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"القيم تقديرية وقابلة للتغير"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"التحذيرات: "}};
-
-
-},{}],40:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Зареждането на тази страница се забавя от разширения за Chrome. Опитайте да я проверите в режим „инкогнито“ или от потребителски профил в Chrome без инсталирани разширения."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Проверка на скрипта"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Синтактичен анализ на скрипта"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Общо"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Препоръчваме да намалите времето, прекарвано в синтактичен анализ, компилиране и изпълнение на JS. Използването на JS ресурси с по-малък размер може да помогне за това. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Намалете времето за изпълнение на JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Време за изпълнение на JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Големите GIF файлове не са ефективни за показване на анимирано съдържание. Вместо това препоръчваме да използвате видеоклипове във формат MPEG4/WebM за анимации и PNG/WebP за статични изображения, за да намалите преноса на данни. [Научете повече](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Използвайте видеоформати за анимираното съдържание"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"За да намалите времето до интерактивност, препоръчваме скритите изображения и тези извън видимата част на екрана да се зареждат след всички критични ресурси. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Отложете зареждането на изображенията извън видимата част на екрана"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ресурси блокират първото изобразяване на страницата ви. Препоръчваме да вградите критичните JS/CSS елементи и да отложите зареждането на всички некритични JS/стилове. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Елиминирайте ресурсите, които блокират изобразяването"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Мрежовите ресурси с голям размер струват пари на потребителите и са тясно свързани с бавното зареждане. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Общият размер бе {totalBytes, number, bytes} КБ"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Не използвайте мрежови ресурси с голям размер"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Не се използват мрежови ресурси с голям размер"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Минимизирането на файловете със CSS може да намали размера на мрежовите ресурси. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Минимизирайте CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Минимизирането на файловете с JavaScript може да намали размера на ресурсите и времето за синтактичен анализ на скрипта. [Научете повече](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Минимизирайте JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Премахнете неизползваните правила от стиловите листове, за да намалите ненужния пренос на данни при мрежовата активност. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Отложете зареждането на неизползваните CSS стилове"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Премахнете неизползвания JavaScript, за да намалите преноса на данни при мрежовата активност."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Премахнете неизползвания JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Продължителното съхраняване на кеша може да ускори повторните посещения на страницата ви. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Намерен е 1 ресурс}other{Намерени са # ресурса}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Използвайте ефективни правила за кеша, за да улесните показването на статичните активи"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Използват се ефективни правила за кеширане на статичните активи"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Оптимизираните изображения се зареждат по-бързо и използват по-малко мобилни данни. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Кодирайте изображенията ефективно"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Показвайте правилно оразмерени изображения, за да пестите мобилни данни и да ускорите зареждането. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Оразмерете изображенията правилно"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"При показването на текстови ресурси трябва да се използва компресиране (gzip, deflate или brotli), за да се намали общият пренос на данни. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Активирайте компресирането на текста"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Графичните формати, като JPEG 2000, JPEG XR и WebP, често осигуряват по-ефективно компресиране от PNG или JPEG. Това означава по-бързо изтегляне и използване на по-малко данни. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Използвайте съвременни формати за показване на изображения"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Веригите от критични заявки по-долу ви показват кои ресурси се зареждат с висок приоритет. За да ускорите зареждането на страницата, препоръчваме да скъсите веригите, да намалите размера за изтегляне на ресурсите или да отложите изтеглянето на ненужните от тях. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Намерена е 1 верига}other{Намерени са # вериги}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Намалете дълбочината на критичните заявки"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Браузърните инженери препоръчват страниците да съдържат под ~ 1500 възела на DOM. Най-добре е йерархичната структура да е с дълбочина под 32 елемента и всеки родителски елемент да има по-малко от 60 дъщерни. Големият размер на DOM може да доведе до използване на повече памет, удължаване на [стиловите изчисления](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) и забавяне поради [преоформяне](https://developers.google.com/speed/articles/reflow). [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 възел}other{# възела}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Не използвайте DOM с твърде голям размер"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Максимална дълбочина на DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Общ брой възли на DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Не се използва DOM с твърде голям размер"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Използвайте функцията font-display на CSS, така че текстът да е видим за потребителите при зареждането на уеб шрифтовете. [Научете повече](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Уверете се, че текстът остава видим при зареждането на уеб шрифтовете"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Целият текст остава видим при зареждането на уеб шрифтовете"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Категория"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Препоръчваме да намалите времето, прекарвано в синтактичен анализ, компилиране и изпълнение на JS. Използването на JS ресурси с по-малък размер може да помогне за това."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Сведете до минимум работата по основната нишка"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Работата по основната нишка е сведена до минимум"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Резултатът по-горе показва приблизително колко време (в милисекунди) е необходимо на приложението ви, за да реагира на входящо потребителско действие по време на най-натоварения 5-секунден период от зареждането на страницата. Ако забавянето е над 50 мсек, приложението ви може да се стори бавно на потребителите. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Прогнозно забавяне при входящо действие"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Показателят „Първо изобразяване на съдържание (FCP)“ указва след колко време се изобразява първият текстов или графичен елемент. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Първо изобразяване на съдържание"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Показателят „Първи момент на неактивност на процесора“ указва първия момент, в който основната нишка на страницата е достатъчно свободна, за да обработва входящи действия. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Първи момент на неактивност на процесора"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Показателят „Първо значимо изобразяване“ измерва времето, за което основното съдържание на страницата става видимо. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Първо значимо изобразяване"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Показателят „Време до интерактивност“ указва колко време отнема постигането на пълна интерактивност за страницата. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Време до интерактивност"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Индексът на скоростта показва колко бързо се постига визуална завършеност на страницата. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Индекс на скоростта"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Пренасочванията водят до допълнително забавяне на зареждането на страницата. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Не използвайте пренасочвания през няколко страници"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Показателят „Време до първия байт“ указва след колко време сървърът изпраща отговор. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Основният документ отне {timeInMs, number, milliseconds} мсек"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Намалете времето за отговор от сървъра (време до първия байт)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Сървърът отговаря бързо (време до първия байт)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Продължителност"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Име"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Начален час"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Тип"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Препоръчваме да използвате API за разбивка на потребителските времена за приложението си, за да измервате действителната му ефективност по време на ключови аспекти от практическата работа на потребителите. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 потребителско време}other{# потребителски времена}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Точки и измервания в разбивката на потребителските времена"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Препоръчваме да добавите подсказки за предварително свързване или предварително извличане на DNS за ресурсите с цел ранно установяване на връзка с важни източници на трети страни. [Научете повече](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Осигурете предварително свързване с необходимите източници"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Препоръчваме да използвате <link rel=preload>, за да укажете най-напред да се извличат ресурсите, които понастоящем се заявяват на по-късен етап от зареждането на страницата. [Научете повече](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Задайте ключовите заявки да се зареждат предварително"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Повече информация за ефективността на приложението ви."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Диагностика"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Най-критичният аспект на ефективността е времето, за което пикселите се изобразяват на екрана. Ключови показатели: първо изобразяване на съдържание, първо значимо изобразяване"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Подобрения, свързани с първото изобразяване"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Тези оптимизации могат да ускорят зареждането на страницата."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Възможности"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Показатели"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Подобрете зареждането като цяло, така че страницата да реагира бързо и да е готова за използване възможно най-скоро. Ключови показатели: време до интерактивност, индекс на скоростта"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Цялостни подобрения"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Ефективност"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Време на валидност на кеша"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Размер (КБ)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Прекарано време"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL адрес"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Потенциална икономия (КБ)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Потенциална икономия (мсек)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Потенциално спестяване на {wastedBytes, number, bytes} КБ"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Потенциално спестяване на {wastedMs, number, milliseconds} мсек"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} мсек"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} сек"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Показване на проверките"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Първоначална навигация"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Максимално забавяне в критичния път:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Грешка!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Грешка в отчета: няма информация за проверката"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Данни от контролиран тест"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Анализът с [Lighthouse](https://developers.google.com/web/tools/lighthouse/) на текущата страница бе извършен през емулирана 3G връзка. Стойностите са прогнозни и може да варират."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Допълнителни елементи, които да проверите ръчно"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Не е приложимо"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Възможност"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Прогнозна икономия"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Успешно преминати проверки"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Скала на резултата:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Възникнаха проблеми при изготвянето на този отчет от Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Стойностите са прогнозни и може да варират."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Предупреждения: "}};
-
-
-},{}],41:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Les extensions de Chrome han afectat negativament el rendiment de càrrega de la pàgina. Audita la pàgina en mode d'incògnit o des d'un perfil de Chrome sense extensions."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Avaluació de scripts"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Anàlisi de scripts"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Et recomanem que redueixis el temps dedicat a analitzar, compilar i executar JavaScript. Et pot ajudar utilitzar càrregues útils de JavaScript més petites. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Redueix el temps d'execució de JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Temps d'execució de JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Els GIF grans no són eficients a l'hora de publicar contingut animat. Per estalviar bytes de la xarxa, pots substituir-los per vídeos MPEG4/WebM en el cas d'animacions i per PNG/WebP en el cas d'imatges estàtiques. [Més informació] (https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Utilitza formats de vídeo per al contingut animat"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Et recomanem que utilitzis la càrrega diferida de les imatges ocultes i que no es mostren a la pantalla un cop s'acabin de carregar tots els recursos crítics a fi de reduir el temps necessari perquè la pàgina sigui interactiva. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Ajorna les imatges fora de pantalla"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Els recursos estan bloquejant la primera renderització de la pàgina. Et recomanem que publiquis els fitxers JavaScript o CSS inserits i ajornis tots els estils i els fitxers JavaScript que no siguin crítics. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Elimina els recursos que bloquegen la renderització"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Si la càrrega útil de la xarxa és molt gran, els usuaris consumeixen més dades mòbils i els temps de càrrega són més llargs. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Mida total: {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Evita càrregues útils de xarxa enormes"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Evita càrregues útils de xarxa enormes"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Reduir els fitxers CSS pot disminuir les mides de càrrega útil a la xarxa. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Redueix els CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Reduir els fitxers JavaScript pot disminuir les mides de càrrega i els temps d'anàlisi de scripts. [Més informació] (https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Redueix els fitxers JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Suprimeix dels fulls d'estil les regles que no s'utilitzen per reduir els bytes que es consumeixen de manera innecessària durant l'activitat de la xarxa. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Ajorna els CSS no utilitzats"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Suprimeix els fitxers JavaScript que no s'utilitzen per reduir els bytes que es consumeixen durant l'activitat de la xarxa."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Suprimeix els fitxers JavaScript no utilitzats"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Si la memòria cau té una vida llarga, es poden accelerar les visites repetides a la teva pàgina. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{S'ha trobat 1 recurs}other{S'han trobat # recursos}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Publica recursos estàtics amb una política de memòria cau eficient"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Utilitza una política de memòria cau eficient per als recursos estàtics"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Les imatges optimitzades es carreguen més ràpidament i utilitzen menys dades mòbils. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codifica les imatges amb eficiència"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Publica imatges amb la mida correcta per estalviar dades mòbils i millorar el temps de càrrega. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Adapta la mida de les imatges"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Els recursos basats en text s'han de publicar comprimits (gzip, deflate o brotli) per minimitzar el total de bytes a la xarxa. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Activa la compressió de text"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Els formats d'imatge com JPEG 2000, JPEG XR i WebP solen oferir millors resultats de compressió que PNG o JPEG. Això implica baixades més ràpides i menys consum de dades. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Publica imatges en format d'última generació"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Les cadenes de sol·licituds crítiques de sota et mostren quins recursos es carreguen amb prioritat alta. Et recomanem que escurcis les cadenes, redueixis la mida de baixada dels recursos o ajornis la baixada de recursos innecessaris per millorar la càrrega de pàgines. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{S'ha trobat 1 cadena}other{S'han trobat # cadenes}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimitza la profunditat de les sol·licituds crítiques"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Els enginyers de navegadors recomanen que les pàgines continguin menys d'uns 1.500 nodes de DOM. La situació ideal és una profunditat d'arbre inferior a 32 elements i menys de 60 elements superiors o secundaris. Un DOM gran pot augmentar l'ús de la memòria, provocar [càlculs d'estil] més llargs (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) i produir costosos [reinicis de reflux del disseny] (https://developers.google.com/speed/articles/reflow). [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 node}other{# nodes}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Evita una mida de DOM excessiva"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Profunditat màxima de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total de nodes de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Evita una mida excessiva de DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Aprofita la funció CSS que permet mostrar els tipus de lletra per assegurar-te que els usuaris puguin veure el text mentre es carreguen els tipus de lletra per a llocs web. [Més informació] (https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Assegura't que el text continuï visible durant la càrrega dels tipus de lletra per a llocs web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Tot el text continua visible durant les càrregues dels tipus de lletra per a llocs web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categoria"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Et recomanem que redueixis el temps dedicat a analitzar, compilar i executar JavaScript. Et pot ajudar utilitzar càrregues útils de JavaScript més petites."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimitza el treball al fil principal"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimitza el treball al fil principal"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"La puntuació de més amunt és una estimació de quant tarda en mil·lisegons la teva aplicació a respondre a una acció de l'usuari durant el període de 5 segons amb més càrregues de pàgines. Si la latència és superior a 50 ms, és possible que els usuaris considerin que l'aplicació és lenta. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Latència estimada de les accions"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"La primera renderització de contingut marca el moment en què es renderitza el primer text o la primera imatge. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Primera renderització de contingut"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"La mètrica Primera inactivitat de la CPU marca el primer moment en què el fil principal de la pàgina està suficientment inactiu per gestionar accions. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Primera inactivitat de la CPU"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"La mètrica Primera renderització significativa mesura el moment en què el contingut principal d'una pàgina està visible. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Primera renderització significativa"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"La mètrica Temps fins que és interactiva marca el moment en què la pàgina és completament interactiva. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Temps fins que és interactiva"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"L'índex de velocitat mostra la rapidesa amb què s'emplena el contingut d'una pàgina. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Índex de velocitat"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"La mètrica Redireccions introdueix retards addicionals abans de poder carregar la pàgina. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Evita les redireccions múltiples a pàgines"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"La mètrica Temps fins al primer byte identifica el moment en què el teu servidor envia una resposta. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"El document arrel ha tardat {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Redueix els temps de resposta del servidor (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Els temps de resposta del servidor són baixos (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Durada"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nom"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Hora d'inici"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tipus"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Et recomanem que utilitzis l'API Temps d'usuari amb la teva aplicació per mesurar-ne el rendiment al món real durant experiències clau dels usuaris. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 temps d'usuari}other{# temps d'usuari}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Marques i mesures de Temps d'usuari"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Et recomanem que afegeixis suggeriments de recursos per connectar-se prèviament o per obtenir el DNS prèviament a fi d'establir connexions anticipades a orígens importants de tercers. [Més informació] (https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Connecta't prèviament als orígens necessaris"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Et recomanem que utilitzis <link rel=preload> per prioritzar l'obtenció de recursos que en aquests moments se sol·liciten en un moment posterior de la càrrega de pàgines. [Més informació] (https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Carrega prèviament les sol·licituds de clau"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Més informació sobre el rendiment de la teva aplicació."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnòstic"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"L'aspecte més crític del rendiment és la velocitat amb què es renderitzen els píxels en pantalla. Mètriques clau: Primera renderització de contigut, Primera renderització significativa"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Millores de la primera renderització"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Aquestes optimitzacions poden accelerar la càrrega de la pàgina."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Oportunitats"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Mètriques"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Millora l'experiència general de càrrega, de manera que la pàgina respongui i estigui preparada per utilitzar-se al més aviat possible. Mètriques clau: Temps fins que és interactiva, Índex de velocitat"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Millores generals"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Rendiment"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL de la memòria cau"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Mida (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Temps invertit"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Possible estalvi (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Possible estalvi (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Possible estalvi de {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Possible estalvi de {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Mostra les auditories"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navegació inicial"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latència de camí crítica màxima:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Error"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Error de l'informe: no hi ha informació d'auditoria"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Dades de laboratori"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Anàlisi amb [Lighthouse] (https://developers.google.com/web/tools/lighthouse/) de la pàgina actual mitjançant una connexió 3G emulada. Els valors són estimacions i poden variar."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Elements addicionals per comprovar manualment"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"No aplicable"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Oportunitat"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Estalvi estimat"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Auditories aprovades"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Escala de puntuació:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Hi ha hagut problemes que afecten aquesta execució de Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Els valors són estimacions i poden variar."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Advertiments: "}};
-
-
-},{}],42:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Rychlost načítání této stránky byla negativně ovlivněna rozšířeními pro Chrome. Zkuste stránku zkontrolovat v anonymním režimu nebo profilu Chromu bez rozšíření."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Vyhodnocování skriptů"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Analýza skriptů"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Celkem"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Pokuste se zkrátit dobu analyzování, kompilování a spouštění JavaScriptu. Mohlo by pomoci odesílat menší soubory JavaScript. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Zkraťte dobu provádění JavaScriptu"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Doba provádění JavaScriptu"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Velké soubory GIF nejsou efektivní k zobrazování animovaného obsahu. Zvažte, zda byste namísto souborů GIF nemohli pro animace použít videa MPEG4/WebM a pro statické obrázky soubory PNG/WebP. Snížíte tak množství přenášených dat. [Další informace](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Pro animovaný obsah používejte formáty videa"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Zvažte možnost načítat obrázky mimo obrazovku a skryté obrázky „líně“ až po načtení všech kritických zdrojů, abyste zkrátili dobu k dosažení interaktivnosti. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Odložte načítání obrázků mimo obrazovku"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"První vykreslení stránky blokují zdroje. Zvažte, zda byste kriticky důležité zdroje JavaScript a CSS nemohli poskytovat přímo v kódu a stahování veškerého nekritického JavaScriptu a stylů odložit. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Eliminujte zdroje, které blokují vykreslení"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Přenášení velkého množství dat po síti je pro uživatele finančně nákladné a obvykle vede k pomalému načítání. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Celková velikost byla {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Předejděte přenášení enormního množství dat"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Nepřenáší enormní množství dat"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Minifikací souborů CSS lze snížit množství přenášených dat. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minifikujte kód CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Minifikací souborů JavaScript lze snížit množství přenášených dat a zrychlit analýzu skriptů. [Další informace](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minifikujte JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Odstraňte z tabulek stylů nepoužívaná pravidla, abyste snížili množství přenášených nepotřebných dat. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Odložte načítání nevyužitých stylů CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Odstraněním nepoužívaného JavaScriptu zmenšíte množství přenášených dat."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Odstraňte nepoužívaný JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Dlouhá platnost mezipaměti může zrychlit opakované návštěvy stránky. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Byl nalezen 1 zdroj}few{Byly nalezeny # zdroje}many{Bylo nalezeno # zdroje}other{Bylo nalezeno # zdrojů}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Statické podklady zobrazujte s efektivními zásadami pro mezipaměť"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Používá u statických podkladů efektivní zásady pro mezipaměť"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimalizované obrázky se načítají rychle a spotřebovávají méně mobilních dat. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Používejte efektivní kódování obrázků"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Zobrazujte obrázky s vhodnou velikostí, abyste ušetřili mobilní data a zrychlili načítání. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Používejte správnou velikost obrázků"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Textové zdroje by se měly odesílat komprimované (gzip, deflate nebo brotli), aby se minimalizovalo množství přenášených dat. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Zapněte kompresi textu"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formáty obrázků JPEG 2000, JPEG XR a WebP často poskytují lepší kompresi než formáty PNG a JPEG, což znamená rychlejší stahování a menší spotřebu dat. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Zobrazujte obrázky ve formátech nové generace"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Řetězce kritických požadavků níže ukazují, které zdroje se načítají s vysokou prioritou. Zvažte, zda byste načítání stránky nemohli vylepšit tím, že řetězce zkrátíte, zmenšíte zdroje nebo odložíte stahování zdrojů, které nejsou nezbytné. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Byl nalezen 1 řetězec}few{Byly nalezeny # řetězce}many{Bylo nalezeno # řetězce}other{Bylo nalezeno # řetězců}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimalizujte hloubku kritických požadavků"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Vývojáři prohlížečů doporučují, aby stránky obsahovaly méně než cca. 1 500 uzlů modelu DOM. Ideálně by hloubka stromu měla být menší než 32 prvků a každý nadřazený prvek by měl mít méně než 60 podřízených prvků. Velký model DOM může vést k většímu využití paměti, delším [výpočtům stylů](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) a náročným [přeformátováváním rozvržení](https://developers.google.com/speed/articles/reflow). [Další informace](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 uzel}few{# uzly}many{# uzlu}other{# uzlů}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Nepoužívejte příliš velký model DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximální hloubka modelu DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Celkový počet uzlů v modelu DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Nepoužívá příliš velký model DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Pomocí funkce font-display stylů CSS zajistěte, aby byl text při načítání webfontů viditelný uživatelům. [Další informace](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Zajistěte, aby text při načítání webfontů zůstal viditelný"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Při načítání webfontů zůstává veškerý text viditelný"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorie"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Pokuste se zkrátit dobu analyzování, kompilování a spouštění JavaScriptu. Mohlo by pomoci odesílat menší soubory JavaScript."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimalizujte práci v hlavním podprocesu"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimalizuje práci v hlavním podprocesu"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Výše uvedené skóre je odhad (v milisekundách), jak rychle bude aplikace během nejvytíženějších pěti sekund načítání stránky reagovat na vstup uživatele. Pokud je latence větší než 50 ms, mohou uživatelé chování aplikace vnímat jako přerušované. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Odhadovaná latence vstupu"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"První vykreslení obsahu je okamžik vykreslení prvního textu nebo obrázku. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"První vykreslení obsahu"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"První nečinnost procesoru udává čas, kdy je hlavní podproces stránky dostatečně nečinný na to, aby bylo možné zpracovat vstup. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"První nečinnost procesoru"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"První smysluplné vykreslení udává, kdy začne být viditelný primární obsah stránky. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"První smysluplné vykreslení"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktivitou se označuje čas, kdy je stránka plně interaktivní. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Doba do interaktivity"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Index rychlosti ukazuje, jak rychle se viditelně vyplní obsah stránky. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Index rychlosti"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Přesměrování způsobují další prodlevy před načtením stránky. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Nepoužívejte několik přesměrování stránky"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Doba do načtení prvního bajtu udává, jak dlouho vašemu serveru trvá, než odešle odpověď. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Hlavní dokument trval {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Zkraťte doby odezvy serverů (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Doby odezvy serveru jsou krátké (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Trvání"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Název"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Čas zahájení"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Typ"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Zkuste v aplikaci pomocí rozhraní User Timing API implementovat měření reálného výkonu při událostech zásadních pro uživatelský dojem. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 časování uživatelů}few{# časování uživatelů}many{# časování uživatelů}other{# časování uživatelů}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Hodnoty časování uživatelů"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Zvažte přidání signálů pro předběžné připojení nebo načtení, aby bylo možné včas se připojit k důležitým zdrojům třetích stran. [Další informace](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"K potřebným zdrojům se připojujte předem"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Zvažte použití značky <link rel=preload> k prioritnímu načtení zdrojů, o které se nyní žádá později během načítání stránky. [Další informace](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Klíčové požadavky načítejte předběžně"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Další informace o výkonu vaší aplikace."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Nejkritičtějším aspektem výkonu je rychlost vykreslení pixelů na obrazovce. Klíčové metriky: První vykreslení obsahu, První smysluplné vykreslení"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Vylepšení prvního vykreslení"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Tyto optimalizace mohou zrychlit načítání vaší stránky."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Příležitosti"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metriky"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Vylepšete celkové chování při načítání, aby byla stránka co nejdříve responzivní a připravena k používání. Klíčové metriky: Doba dosažení interaktivity, Index rychlosti"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Celková vylepšení"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Výkon"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Hodnota TTL (Time to Live) mezipaměti"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Velikost (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Strávený čas"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Možná úspora (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Možná úspora (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Lze uspořit {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Lze uspořit {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Zobrazit audity"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Počáteční navigace"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximální latence kritické trasy:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Chyba!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Chyba přehledu: žádné informace o auditu"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratorní data"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analýza aktuální stránky nástrojem [Lighthouse](https://developers.google.com/web/tools/lighthouse/) při emulovaném připojení 3G. Hodnoty jsou odhady a mohou být proměnlivé."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Další položky k ruční kontrole"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Není relevantní"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Příležitost"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Odhadovaná úspora"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Úspěšné audity"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Škála skóre:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Při tomto spuštění nástroje Lighthouse se vyskytly problémy:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Hodnoty jsou odhady a mohou se lišit."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Upozornění: "}};
-
-
-},{}],43:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome-udvidelser påvirkede denne sides indlæsning negativt. Prøv at revidere siden i inkognitotilstand eller fra en Chrome-profil uden udvidelser."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Scriptevaluering"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Scriptparsing"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"I alt"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Overvej at reducere den tid, der bruges på at parse, kompilere og udføre JavaScript. Levering af mindre JavaScript-datapakker kan hjælpe med dette. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reducer udførelsestiden for JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Udførelsestid for JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Store giffer er ikke tilstrækkelige til at levere animeret indhold. Overvej at bruge MPEG4-/WebM-videoer til animationer og PNG/WebP til statiske billeder i stedet for giffer for at spare netværksbytes. [Få flere oplysninger](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Brug videoformater til animeret indhold"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Overvej at udskyde indlæsningen af skjulte billeder og billeder, der ikke er på skærmen, til efter alle kritiske ressourcer er blevet indlæst for at reducere den tid, der går, inden siden er interaktiv. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Udskyd billeder, der ikke er på skærmen"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ressourcer blokerer første udfyldning af din side. Overvej at levere kritisk JavaScript/CSS indlejret og udskyde alle ikke-kritiske JavaScript-elementer/typografier. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Fjern ressourcer til blokering af gengivelse"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Store datapakker på netværk koster brugerne mange penge og er forbundet med lang indlæsningstid. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Den samlede størrelse var {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Undgå kæmpe datapakker på netværk"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Undgår kæmpe datapakker på netværk"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Formindskelse af CSS-filer kan reducere størrelsen på datapakker på netværk. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Formindsk CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Formindskelse af JavaScript-filer kan reducere størrelsen på datapakker og varigheden af scriptparsing. [Få flere oplysninger](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Formindsk JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Fjern regler, som ikke bruges, fra typografiark for at skære ned på antallet af unødvendige bytes, der anvendes ved netværksaktivitet. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Udskyd CSS, som ikke bruges"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Fjern JavaScript, der ikke bruges, for at skære ned på antallet af bytes, der anvendes ved netværksaktivitet."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Fjern JavaScript, som ikke bruges"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"En lang cachelevetid kan gøre indlæsningen hurtigere for tilbagevendende besøgende på din side. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Der blev fundet 1 ressource}one{Der blev fundet # ressource}other{Der blev fundet # ressourcer}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Vis statiske aktiver med en effektiv cachepolitik"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Anvender effektiv cachepolitik på statiske aktiver"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimerede billeder indlæses hurtigere og bruger mindre mobildata. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Kryptér billeder effektivt"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Vis billeder i korrekte størrelser for at spare mobildata og forbedre indlæsningstiden. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Brug korrekte billedstørrelser"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Tekstbaserede ressourcer bør vises i komprimeret format (gzip, Deflate eller Brotli), så netværkets samlede antal bytes formindskes. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Aktivér tekstkomprimering"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Billedformater såsom JPEG 2000, JPEG XR og WebP giver ofte en bedre komprimering end PNG og JPEG, hvilket betyder hurtigere downloads og mindre dataforbrug. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Vis billeder i formater af næste generation"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Kæderne med kritiske anmodninger nedenfor viser dig, hvilke ressourcer der indlæses med høj prioritet. Du kan også vælge at reducere kædernes længde, så ressourcernes downloadstørrelse bliver mindre, eller at udskyde download af unødvendige ressourcer, så sideindlæsningen forbedres. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Der blev fundet 1 kæde}one{Der blev fundet # kæde}other{Der blev fundet # kæder}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimer dybden for kritiske anmodninger"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Browserudviklere anbefaler, at sider højst indeholder 1.500 DOM-noder. Det bedste er en træstrukturdybde med under 32 elementer og mindre end 60 underordnede/overordnede elementer. En stor DOM kan øge hukommelsesforbruget, medføre længere [beregninger af typografi](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) og producere dyre [omformateringer af layout](https://developers.google.com/speed/articles/reflow). [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 node}one{# node}other{# noder}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Undgå en overdreven DOM-størrelse"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimal DOM-dybde"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Samlet antal DOM-noder"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Undgår en overdreven DOM-størrelse"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Udnyt CSS-funktionen til skrifttypevisning for at sikre dig, at teksten kan ses af brugerne, mens webfonts indlæses. [Få flere oplysninger](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Sørg for, at tekst forbliver synlig under indlæsning af webfont"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Al tekst forbliver synlig under indlæsning af webfont"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategori"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Overvej at reducere den tid, der bruges på at parse, kompilere og udføre JavaScript. Levering af mindre JavaScript-datapakker kan hjælpe med dette."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Formindsk primært trådarbejde"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Formindsker primært trådarbejde"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Resultatet ovenfor er et estimat af, hvor længe din app er om at svare på brugerinput (i millisekunder) i de første 5 travleste sekunder med vindue under en sideindlæsning. Hvis din forsinkelse er større end 50 ms, kan brugerne opfatte din app som langsom. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Estimeret inputforsinkelse"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Første udfyldning af indhold markerer tidspunktet, hvor den første tekst eller det første billede udfyldes. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Første udfyldning af indhold"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Første stillestående CPU markerer det tidspunkt, hvor sidens primære tråd er stabil nok til at behandle input. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Første stillestående CPU"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Første betydningsfulde udfyldning måler, hvornår det primære indhold på en side kan ses. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Første betydningsfulde udfyldning"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktiv tilstand markerer det tidspunkt, hvor siden er helt interaktiv. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tid inden interaktiv tilstand"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Hastighedsindekset viser, hvor hurtigt indholdet på en side udfyldes, så det kan ses. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Hastighedsindeks"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Omdirigeringer medfører yderligere forsinkelser, inden siden kan indlæses. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Undgå mange sideomdirigeringer"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"TTFB (Time To First Byte) identificerer tidspunktet for, hvornår din server sender et svar. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Roddokumentet tog {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reducer serversvartider (TTFB, Time To First Byte)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Serversvartiderne er korte (TTFB, Time To First Byte)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Varighed"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Navn"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Starttidspunkt"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Type"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Du kan også vælge at bruge User Timing API som værktøj til din app for at måle appens effektivitet i den virkelige verden i forbindelse med vigtige brugeroplevelser. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 brugstid}one{# brugstid}other{# brugstider}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Brugstider markerer og måler"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Overvej at tilføje ressourcehints til forbindelse på forhånd eller DNS-forudhentning for at oprette tidlige forbindelser til vigtige tredjepartswebsites. [Få flere oplysninger](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Opret forbindelse på forhånd til påkrævede websites"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Overvej at bruge <link rel=preload> til at prioritere hentning af ressourcer, som der i øjeblikket anmodes om senere i sideindlæsningen. [Få flere oplysninger](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Forudindlæs vigtige anmodninger"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Få flere oplysninger om din apps effektivitet."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostik"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Det vigtigste aspekt af effektivitet er, hvor hurtigt pixels gengives på skærmen. Vigtige metrics: Første udfyldning af indhold, Første betydningsfulde udfyldning"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Forbedringer af første udfyldning"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Disse optimeringer kan gøre din sideindlæsning hurtigere."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Muligheder"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrics"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Gør den overordnede indlæsning bedre, så siden hurtigst muligt bliver responsiv og klar til brug. Vigtige metrics: Tid inden interaktiv tilstand, Hastighedsindeks"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Overordnede forbedringer"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Effektivitet"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache-TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Størrelse (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Tidsforbrug"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"Webadresse"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potentiel databesparelse (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potentiel tidsbesparelse (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potentiel databesparelse på {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potentiel tidsbesparelse på {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} sek."},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Se revisioner"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Indledende navigation"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksimal forsinkelse for kritisk sti:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Der opstod en fejl"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Rapportfejl: Der er ingen revisionsoplysninger"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratoriedata"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/)-analyse af den aktuelle side på et emuleret 3G-netværk. Værdierne er estimerede og kan variere."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Yderligere elementer, der skal tjekkes manuelt"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Ikke relevant"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Mulighed"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Estimeret tidsbesparelse"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Beståede revisioner"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Resultatskala:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Der blev registreret problemer, som påvirkede denne kørsel af Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Værdierne er estimater og kan variere."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Advarsler! "}};
-
-
-},{}],44:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome-Erweiterungen haben die Ladegeschwindigkeit dieser Seite beeinträchtigt. Versuchen Sie, die Seite im Inkognito-Modus oder mit einem Chrome-Profil ohne Erweiterungen zu überprüfen."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Skriptauswertung"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Parsen von Skripten"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Gesamt"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Versuchen Sie, die Zeit für das Parsen, Kompilieren und Ausführen von JS zu reduzieren. Die Bereitstellung kleinerer JS-Nutzlasten kann dabei helfen. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Ausführungszeit von JavaScript reduzieren"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript-Ausführungszeit"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Große GIF-Dateien sind nur bedingt für die Bereitstellung animierter Inhalte geeignet. Sie können statt GIF MPEG4- oder WebM-Videos für Animationen und PNG oder WebP für statische Bilder verwenden und so die Netzwerk-Datenmenge reduzieren. [Weitere Informationen](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Videoformate für animierte Inhalte verwenden"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Versuchen Sie, nicht sichtbare und versteckte Bilder erst laden zu lassen, nachdem wichtige Ressourcen geladen wurden, um die Zeit bis zur Interaktivität zu reduzieren. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Nicht sichtbare Bilder aufschieben"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ressourcen blockieren das erste Zeichnen Ihrer Seite. Versuchen Sie, wichtiges JS und wichtige CSS inline bereitzustellen und alle nicht kritischen JS und Stile aufzuschieben. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Ressourcen beseitigen, die das Rendering blockieren"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Große Netzwerknutzlasten kosten Nutzer bares Geld und hängen eng mit langen Ladezeiten zusammen. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Die Gesamtgröße war {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Sehr große Netzwerknutzlasten vermeiden"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Vermeidet sehr große Netzwerknutzlasten"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Durch die Komprimierung von CSS-Dateien kann die Größe von Netzwerknutzlasten reduziert werden. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSS komprimieren"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Durch die Komprimierung von JavaScript-Dateien können Nutzlastgrößen und die Zeit zum Parsen von Skripts reduziert werden. [Weitere Informationen](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScript komprimieren"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Entfernen Sie nicht verwendete Regeln aus Stylesheets, um unnötige Daten bei Netzwerkaktivitäten zu reduzieren. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Nicht verwendete CSS aufschieben"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Entfernen Sie nicht verwendetes JavaScript, um die Datenmenge bei Netzwerkaktivitäten zu reduzieren."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Nicht genutztes JavaScript entfernen"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Eine lange Lebensdauer des Cache kann wiederholte Besuche Ihrer Seite beschleunigen. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 Ressource gefunden}other{# Ressourcen gefunden}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Statische Inhalte mit einer effizienten Cache-Richtlinie bereitstellen"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Verwendet eine effiziente Cache-Richtlinie für statische Inhalte"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimierte Bilder werden schneller geladen und verbrauchen weniger mobile Daten. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Bilder effizient codieren"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Stellen Sie Bilder bereit, die eine angemessene Größe haben, um mobile Daten zu sparen und die Ladezeit zu verbessern. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Bilder richtig dimensionieren"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Textbasierte Ressourcen sollten mit Komprimierung (gzip, Deflate oder Brotli) bereitgestellt werden, um die Datenmenge im Netzwerk insgesamt zu minimieren. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Textkomprimierung aktivieren"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Bildformate wie JPEG 2000, JPEG XR und WebP bieten oft eine bessere Komprimierung als PNG oder JPEG, was schnellere Downloads und einen geringeren Datenverbrauch ermöglicht. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Bilder in modernen Formaten bereitstellen"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"In den unten aufgeführten Ketten kritischer Anfragen können Sie sehen, welche Ressourcen mit einer hohen Priorität geladen werden. Versuchen Sie, die Ketten zu verkürzen, die Downloadgröße von Ressourcen zu reduzieren oder das Herunterladen unnötiger Ressourcen aufzuschieben, um den Seitenaufbau zu beschleunigen. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 Kette gefunden}other{# Ketten gefunden}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Tiefe kritischer Anforderungen minimieren"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Laut der Empfehlung von Browserentwicklern sollten Seiten nicht mehr als ungefähr 1.500 DOM-Knoten enthalten. Die ideale Strukturtiefe liegt bei unter 32 Elementen und weniger als 60 unter- und übergeordneten Elementen. Ein großes DOM kann zu hohem Speicherverbrauch, langwierigen [Stilberechnungen](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) und kostspieligen [dynamischen Umbrüchen im Layout](https://developers.google.com/speed/articles/reflow) führen. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 Knoten}other{# Knoten}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Übermäßige DOM-Größe vermeiden"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximale DOM-Tiefe"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Gesamtzahl der DOM-Knoten"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Vermeidet eine übermäßige DOM-Größe"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Sie können Gebrauch von der CSS-Funktion \"font-display\" machen, um sicherzugehen, dass der Text für Nutzer sichtbar ist, während Webfonts geladen werden. [Weitere Informationen](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Darauf achten, dass der Text während der Webfont-Ladevorgänge sichtbar bleibt"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Der gesamte Text bleibt während der Webfont-Ladevorgänge sichtbar"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorie"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Versuchen Sie, die Zeit für das Parsen, Kompilieren und Ausführen von JS zu reduzieren. Die Bereitstellung kleinerer JS-Nutzlasten kann dabei helfen."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Aufwand für Hauptthread minimieren"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimiert den Aufwand für den Hauptthread"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Beim Ergebnis oben handelt es sich um eine Schätzung dessen, wie viele Millisekunden Ihre App benötigt, um während des 5-s-Fensters mit der stärksten Auslastung beim Seitenaufbau auf Nutzereingaben zu reagieren. Wenn die Latenz bei Ihnen über 50 ms liegt, empfinden Nutzer Ihre App möglicherweise als langsam. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Geschätzte Eingabelatenz"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"\"Erste Inhalte gezeichnet\" gibt an, wann der erste Text oder das erste Bild gezeichnet wird. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Erste Inhalte gezeichnet"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"\"Erster CPU-Leerlauf\" gibt den Zeitpunkt an, an dem die Aktivität des Hauptthreads der Seite das erste Mal gering genug ist, um Eingaben zu verarbeiten. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Erster CPU-Leerlauf"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"\"Inhalte weitgehend gezeichnet\" gibt an, wann die Hauptinhalte einer Seite sichtbar sind. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Inhalte weitgehend gezeichnet"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"\"Zeit bis Interaktivität\" gibt den Zeitpunkt an, an dem die Seite voll interaktionsfähig ist. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Zeit bis Interaktivität"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Der Geschwindigkeitsindex zeigt an, wie schnell die Inhalte einer Seite sichtbar dargestellt werden. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Geschwindigkeitsindex"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Weiterleitungen führen zu zusätzlichen Verzögerungen, bevor die Seite geladen werden kann. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Mehrere Weiterleitungen auf die Seite vermeiden"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"TTFB (Time To First Byte) erkennt den Zeitpunkt, an dem Ihr Server eine Antwort sendet. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Stammdokument brauchte {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Serverantwortzeiten reduzieren (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Serverantwortzeiten sind niedrig (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Dauer"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Name"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Beginn"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Typ"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Sie können die User Timing API in Ihre App integrieren. Damit lässt sich die Leistung Ihrer App in der Praxis messen, beispielsweise während Seitenladevorgängen oder wichtigen Nutzerinteraktionen. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 Nutzertiming}other{# Nutzertimings}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Markierungen und Messungen für das Nutzertiming"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Versuchen Sie, Hinweise auf Ressourcen für eine Vorverbindung oder einen DNS-Vorabruf hinzuzufügen, damit möglichst frühzeitig eine Verbindung zu wichtigen Drittanbieterursprüngen hergestellt wird. [Weitere Informationen](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Vorverbindung zu erforderlichen Ursprüngen aufbauen"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Mit <link rel=preload> können Sie das Abrufen von Ressourcen priorisieren, die aktuell später beim Seitenaufbau angefordert werden. [Weitere Informationen](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Wichtige Anforderungen vorab laden"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Weitere Informationen zur Leistung Ihrer App."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnose"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Der wichtigste Faktor bei der Leistung ist, wie schnell Pixel auf dem Bildschirm gerendert werden. Wichtige Messwerte: \"Erste Inhalte gezeichnet\", \"Inhalte weitgehend gezeichnet\""},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Verbesserungen beim Zeichnen der ersten Inhalte"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Diese Optimierungen können den Seitenaufbau beschleunigen."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Empfehlungen"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Messwerte"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Hier können Sie die Ladezeiten verkürzen, damit die Seite so schnell wie möglich reagiert und Einsatzbereit ist. Wichtige Messwerte: \"Zeit bis Interaktivität\", \"Geschwindigkeitsindex\""},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Allgemeine Verbesserungen"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Leistung"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache-TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Größe (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Zeitaufwand"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Mögliche Einsparung (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Mögliche Einsparung (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Mögliche Einsparung von {wastedBytes, number, bytes} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Mögliche Einsparung von {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Überprüfungen ansehen"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Anfangsnavigation"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximale Latenz für kritischen Pfad:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Fehler."},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Fehler gemeldet: keine Informationen zur Überprüfung"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Labdaten"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/)-Analyse der aktuellen Seite in einem emulierten 3G-Netz. Die Werte sind geschätzt und können variieren."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Zusätzliche Elemente zur manuellen Überprüfung"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nicht zutreffend"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Empfehlung"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Geschätzte Einsparung"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Bestandene Prüfungen"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Ergebnisskala:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Einige Probleme haben diese Ausführung von Lighthouse beeinträchtigt:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Die Werte sind geschätzt und können variieren."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Warnungen: "}};
-
-
-},{}],45:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Οι επεκτάσεις του Chrome επηρέασαν αρνητικά την απόδοση φόρτωσης αυτής της σελίδας. Δοκιμάστε να ελέγξετε τη σελίδα σε κατάσταση ανώνυμης περιήγησης ή από ένα προφίλ του Chrome χωρίς επεκτάσεις."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Αξιολόγηση σεναρίου"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Ανάλυση σεναρίου"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Σύνολο"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Εξετάστε το ενδεχόμενο μείωσης του χρόνου ανάλυσης, σύνθεσης και εκτέλεσης JS. Μπορεί να διαπιστώσετε ότι η προβολή μικρότερων φορτίων δεδομένων JS συμβάλλει προς αυτήν την κατεύθυνση. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Μείωση χρόνου εκτέλεσης JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Χρόνος εκτέλεσης JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Οι μεγάλες εικόνες GIF δεν είναι αποδοτικές για την προβολή περιεχομένου κινούμενων εικόνων. Εξετάστε το ενδεχόμενο χρήσης βίντεο MPEG4/WebM για κινούμενες εικόνες και PNG/WebP για στατικές εικόνες αντί για τη χρήση εικόνων GIF, με στόχο την εξοικονόμηση byte δικτύου. [Μάθετε περισσότερα](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Χρήση μορφών βίντεο για περιεχόμενο κινούμενων εικόνων"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Εξετάστε τη φόρτωση εικόνων εκτός οθόνης και κρυφών εικόνων με καθυστέρηση μετά την ολοκλήρωση της φόρτωσης όλων των σημαντικών πόρων, προκειμένου να ελαττωθεί ο χρόνος μετάβασης σε κατάσταση αλληλεπίδρασης. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Καθυστέρηση φόρτωσης εικόνων εκτός οθόνης"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Υπάρχουν πόροι οι οποίοι αποκλείουν την πρώτη μορφή της σελίδας σας. Εξετάστε το ενδεχόμενο προβολής σημαντικών ενσωματωμένων JS/CSS και καθυστέρησης όλων των μη σημαντικών JS/στυλ. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Εξάλειψη πόρων που αποκλείουν την απόδοση"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Τα μεγάλα φορτία δεδομένων δικτύου συνεπάγονται υψηλό χρηματικό κόστος για τους χρήστες και συσχετίζονται σε μεγάλο βαθμό με εκτενείς χρόνους φόρτωσης. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Το συνολικό μέγεθος ήταν {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Αποφύγετε τα πολύ μεγάλα φορτία δεδομένων δικτύου"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Αποφεύγει τα πολύ μεγάλα φορτία δεδομένων δικτύου"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Με την ελαχιστοποίηση των αρχείων CSS, μπορεί να ελαττωθούν τα μεγέθη φορτίου δεδομένων δικτύου. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Ελαχιστοποίηση CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Με την ελαχιστοποίηση των αρχείων JavaScript, μπορεί να μειωθούν τα μεγέθη φορτίου δεδομένων και να ελαττωθεί ο χρόνος ανάλυσης σεναρίου. [Μάθετε περισσότερα](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Ελαχιστοποίηση JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Καταργήστε κανόνες που δεν χρησιμοποιούνται από τα φύλλα στυλ, για να μειώσετε τον αριθμό των μη απαραίτητων byte που καταναλώνονται από τη δραστηριότητα δικτύου. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Καθυστέρηση μη χρησιμοποιούμενων CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Καταργήστε τυχόν JavaScript που δεν χρησιμοποιείται, για να ελαττώσετε τα byte που καταναλώνονται από τη δραστηριότητα δικτύου."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Κατάργηση JavaScript που δεν χρησιμοποιείται"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Η μεγάλη διάρκεια ζωής της κρυφής μνήμης μπορεί να επιταχύνει τις επαναλαμβανόμενες επισκέψεις στη σελίδα σας. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Βρέθηκε 1 πόρος}other{Βρέθηκαν # πόροι}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Προβολή στατικών στοιχείων με επαρκή πολιτική κρυφής μνήμης"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Χρησιμοποιεί αποδοτική πολιτική κρυφής μνήμης σε στατικά στοιχεία"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Οι βελτιστοποιημένες εικόνες φορτώνονται πιο γρήγορα και καταναλώνουν λιγότερα δεδομένα κινητής τηλεφωνίας. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Αποδοτική κωδικοποίηση εικόνων"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Προβάλετε εικόνες κατάλληλου μεγέθους, για την εξοικονόμηση δεδομένων κινητής τηλεφωνίας και τη βελτίωση του χρόνου φόρτωσης. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Κατάλληλη προσαρμογή μεγέθους εικόνων"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Οι πόροι που βασίζονται σε κείμενο θα πρέπει να προβάλλονται με συμπίεση (gzip, deflate ή brotli), προκειμένου να ελαχιστοποιούνται τα byte δικτύου. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Ενεργοποίηση συμπίεσης κειμένου"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Οι μορφές εικόνας όπως JPEG 2000, JPEG XR και WebP συχνά παρέχουν καλύτερη συμπίεση από ό,τι οι μορφές PNG και JPEG. Αυτό σημαίνει γρηγορότερες λήψεις και μικρότερη κατανάλωση δεδομένων. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Προβολή εικόνων σε μορφές επόμενης γενιάς"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Οι Αλυσίδες κρίσιμων αιτημάτων που ακολουθούν δείχνουν τους πόρους που φορτώνονται με υψηλή προτεραιότητα. Εξετάστε το ενδεχόμενο μείωσης του μεγέθους των αλυσίδων, μείωσης του μεγέθους λήψης πόρων ή καθυστέρησης της λήψης μη απαραίτητων πόρων, για τη βελτίωση της φόρτωσης σελίδας. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Βρέθηκε 1 αλυσίδα}other{Βρέθηκαν # αλυσίδες}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Ελαχιστοποίηση βάθους κρίσιμων αιτημάτων"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Οι μηχανικοί προγραμμάτων περιήγησης συνιστούν να περιέχουν οι σελίδες λιγότερους από ~1.500 κόμβους DOM. Το ιδανικό είναι ένα βάθος δέντρου με < 32 στοιχεία και λιγότερα από 60 θυγατρικά/γονικά στοιχεία. Ένα μεγάλο DOM μπορεί να αυξήσει τη χρήση της μνήμης, να προκαλέσει [υπολογισμούς στυλ] μεγαλύτερης διάρκειας (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) και να δημιουργήσει [επαναληπτικές ροές διάταξης] υψηλού κόστους (https://developers.google.com/speed/articles/reflow). [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 κόμβος}other{# κόμβοι}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Αποφύγετε τα υπερβολικά μεγάλα μεγέθη DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Μέγιστο βάθος DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Σύνολο κόμβων DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Αποφεύγει τα υπερβολικά μεγάλα μεγέθη DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Χρησιμοποιήστε τη λειτουργία CSS προβολής γραμματοσειράς, για να διασφαλίσετε ότι το κείμενο είναι ορατό στους χρήστες κατά τη φόρτωση των γραμματοσειρών ιστοτόπου. [Μάθετε περισσότερα](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Βεβαιωθείτε ότι το κείμενο παραμένει ορατό κατά τη διάρκεια της φόρτωσης γραμματοσειράς ιστοτόπου"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Όλο το κείμενο παραμένει ορατό κατά τη διάρκεια φορτώσεων γραμματοσειράς ιστοτόπου"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Κατηγορία"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Εξετάστε το ενδεχόμενο ελάττωσης του χρόνου ανάλυσης, σύνθεσης και εκτέλεσης JS. Μπορεί να διαπιστώσετε ότι η προβολή μικρότερων φορτίων δεδομένων JS συμβάλλει προς αυτήν την κατεύθυνση."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Ελαχιστοποίηση εργασίας κύριου νήματος"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Ελαχιστοποιεί την εργασία κύριου νήματος"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Η παραπάνω βαθμολογία αποτελεί εκτίμηση του χρόνου που απαιτείται προκειμένου η εφαρμογή σας να ανταποκριθεί στα στοιχεία εισόδου χρήστη, σε χιλιοστά του δευτερολέπτου, κατά τη διάρκεια εκτέλεσης του παραθύρου φόρτωσης σελίδας 5 δευτ. με τη μεγαλύτερη κινητικότητα. Εάν ο λανθάνων χρόνος είναι μεγαλύτερος από 50 ms, οι χρήστες μπορεί να θεωρήσουν ότι η εφαρμογή σας είναι αργή. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Εκτιμώμενος λανθάνων χρόνος στοιχείων εισόδου"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Η Πρώτη σχεδίαση περιεχομένου (FCP) υποδεικνύει πότε μορφοποιείται το πρώτο κείμενο ή η πρώτη εικόνα. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Πρώτη μορφή με περιεχόμενο"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Η Πρώτη αδράνεια CPU υποδεικνύει την πρώτη φορά που το κύριο νήμα μιας σελίδας παρουσιάζει αρκετά χαμηλή κινητικότητα έτσι ώστε να διαχειριστεί στοιχεία εισόδου. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Πρώτη αδράνεια CPU"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Η Πρώτη χρήσιμη μορφή υπολογίζει πότε είναι ορατό το κύριο περιεχόμενο μιας σελίδας. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Πρώτη χρήσιμη μορφή"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Η Αλληλεπίδραση υποδεικνύει πότε η σελίδα είναι πλήρως διαδραστική. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Χρόνος για Αλληλεπίδραση"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Το Ευρετήριο ταχύτητας δείχνει πόσο γρήγορα γίνονται ορατά τα περιεχόμενα μιας σελίδας. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Ευρετήριο ταχύτητας"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Οι ανακατευθύνσεις δημιουργούν επιπλέον καθυστερήσεις προτού να είναι δυνατή η φόρτωση της σελίδας. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Αποφυγή ανακατευθύνσεων πολλών σελίδων"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Ο Χρόνος μέχρι το πρώτο byte προσδιορίζει πότε ο διακομιστής σας στέλνει μια απόκριση. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Το αρχείο ρίζας χρειάστηκε {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Μείωση χρόνων απόκρισης διακομιστή (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Οι χρόνοι απόκρισης διακομιστή είναι χαμηλοί (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Διάρκεια"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Όνομα"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Ώρα έναρξης"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Τύπος"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Εξετάστε το ενδεχόμενο ενίσχυσης της εφαρμογής σας με το User Timing API, για να καταμετράτε την πραγματική απόδοση της εφαρμογής σας κατά τη διάρκεια σημαντικών εμπειριών χρήστη. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 χρόνος χρήστη}other{# χρόνοι χρήστη}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Ενδείξεις και μετρήσεις Χρόνων χρήστη"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Εξετάστε το ενδεχόμενο προσθήκης υποδείξεων πόρου προσύνδεσης ή προανάλυσης dns, για τη δημιουργία πρώιμων συνδέσεων σε σημαντικές προελεύσεις τρίτου μέρους. [Μάθετε περισσότερα](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Προσύνδεση σε απαιτούμενες προελεύσεις"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Εξετάστε το ενδεχόμενο χρήσης <link rel=φορτίου δεδομένων>, για να δώσετε προτεραιότητα στην ανάλυση πόρων των οποίων το αίτημα εμφανίζεται αργότερα στη σελίδα. [Μάθετε περισσότερα](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Σημαντικά αιτήματα προφόρτωσης"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Περισσότερες πληροφορίες σχετικά με την απόδοση της εφαρμογής σας"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Διαγνωστικά στοιχεία"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Η πιο σημαντική πτυχή της απόδοσης είναι η ταχύτητα με την οποία αποδίδονται τα pixel στην οθόνη. Σημαντικές μετρήσεις: Πρώτη μορφή με περιεχόμενο, Πρώτη χρήσιμη μορφή"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Βελτιώσεις πρώτης μορφής"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Αυτοί οι οργανισμοί μπορούν να επιταχύνουν τη φόρτωση της σελίδας σας."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Ευκαιρίες"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Μετρήσεις"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Βελτιώστε τη συνολική εμπειρία φόρτωσης, για να μπορεί η σελίδα να ανταποκρίνεται και να είναι έτοιμη για χρήση το συντομότερο δυνατό. Σημαντικές μετρήσεις: Χρόνος για Αλληλεπίδραση, Ευρετήριο ταχύτητας"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Συνολικές βελτιώσεις"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Απόδοση"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL κρυφής μνήμης"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Μέγεθος (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Χρόνος χρήσης"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Δυνητικές εξοικονομήσεις (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Δυνητικές εξοικονομήσεις (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Δυνητικές εξοικονομήσεις {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Δυνητικές εξοικονομήσεις {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} δ."},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Εμφάνιση ελέγχων"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Αρχική πλοήγηση"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Μέγιστος λανθάνων χρόνος κρίσιμης διαδρομής:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Σφάλμα!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Σφάλμα αναφοράς: Δεν υπάρχουν πληροφορίες ελέγχου"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Εργαστηριακά δεδομένα"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Φάρος](https://developers.google.com/web/tools/lighthouse/) ανάλυση της τρέχουσας σελίδας σε προσομοιωμένο 3G. Οι τιμές αποτελούν εκτιμήσεις και μπορεί να ποικίλουν."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Επιπλέον στοιχεία για μη αυτόματο έλεγχο"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Δεν ισχύει"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Ευκαιρία"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Εκτιμώμενες εξοικονομήσεις"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Έλεγχοι που ολοκληρώθηκαν επιτυχώς"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Κλίμακα βαθμολογίας:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Παρουσιάστηκαν ορισμένα ζητήματα τα οποία επηρεάζουν αυτήν την εκτέλεση του Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Οι τιμές εκτιμώνται και μπορεί να ποικίλουν."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Προειδοποιήσεις: "}};
-
-
-},{}],46:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome extensions negatively affected this page's load performance. Try auditing the page in incognito mode or from a Chrome profile without extensions."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Script Evaluation"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Script Parse"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reduce JavaScript execution time"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript execution time"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Large GIFs are inefficient for delivering animated content. Consider using MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Use video formats for animated content"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Consider lazy-loading off-screen and hidden images after all critical resources have finished loading to lower time to interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Defer off-screen images"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resources are blocking the first paint of your page. Consider delivering critical JS/CSS inline and deferring all non-critical JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Eliminate render-blocking resources"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Large network payloads cost users real money and are highly correlated with long load times. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Total size was {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Avoid enormous network payloads"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Avoids enormous network payloads"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Minifying CSS files can reduce network payload sizes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minify CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Minifying JavaScript files can reduce payload sizes and script parse time. [Learn more](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minify JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Remove unused rules from stylesheets to reduce unnecessary bytes consumed by network activity. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Defer unused CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Remove unused JavaScript to reduce bytes consumed by network activity."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Remove unused JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"A long cache lifetime can speed up repeat visits to your page. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 resource found}other{# resources found}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Serve static assets with an efficient cache policy"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Uses efficient cache policy on static assets"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimised images load faster and consume less mobile data. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Efficiently encode images"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Serve images that are appropriately-sized to save mobile data and improve load time. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Properly size images"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Text-based resources should be served with compression (gzip, deflate or brotli) to minimise total network bytes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Enable text compression"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Image formats like JPEG 2000, JPEG XR and WebP often provide better compression than PNG or JPEG, which means faster downloads and less data consumption. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Serve images in next-gen formats"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"The Critical Request Chains below show you what resources are loaded with a high priority. Consider reducing the length of chains, reducing the download size of resources or deferring the download of unnecessary resources to improve page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 chain found}other{# chains found}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimise Critical Requests Depth"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer [style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 node}other{# nodes}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Avoid an excessive DOM size"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximum DOM Depth"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total DOM Nodes"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Avoids an excessive DOM size"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Leverage the font-display CSS feature to ensure text is user-visible while webfonts are loading. [Learn more](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Ensure text remains visible during webfont load"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"All text remains visible during webfont loads"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Category"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimise main-thread work"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimises main-thread work"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"The score above is an estimate of how long your app takes to respond to user input, in milliseconds, during the busiest 5-second window of page load. If your latency is higher than 50 ms, users may perceive your app as laggy. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Estimated Input Latency"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"First Contentful Paint"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"First CPU Idle marks the first time at which the page's main thread is quiet enough to handle input. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"First CPU Idle"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"First Meaningful Paint measures when the primary content of a page is visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"First Meaningful Paint"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interactive marks the time at which the page is fully interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Time to Interactive"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Speed Index"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Avoid multiple page redirects"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Time To First Byte identifies the time at which your server sends a response. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Root document took {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reduce server response times (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Server response times are low (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Duration"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Name"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Start Time"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Type"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Consider instrumenting your app with the User Timing API to measure your app's real-world performance during key user experiences. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 user timing}other{# user timings}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing marks and measures"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Consider adding pre-connect or DNS-prefetch resource hints to establish early connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Pre-connect to required origins"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Consider using <link rel=preload> to prioritise fetching resources that are currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Pre-load key requests"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"More information about the performance of your application."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostics"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"The most critical aspect of performance is how quickly pixels are rendered onscreen. Key metrics: First Contentful Paint, First Meaningful Paint"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"First Paint Improvements"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"These optimisations can speed up your page load."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Opportunities"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrics"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Enhance the overall loading experience, so the page is responsive and ready to use as soon as possible. Key metrics: Time to Interactive, Speed Index"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Overall Improvements"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performance"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Size (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Time Spent"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potential Savings (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potential Savings (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potential savings of {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potential savings of {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Show audits"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Initial Navigation"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximum critical path latency:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Error!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Report error: no audit information"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Lab Data"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on emulated 3G. Values are estimated and may vary."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Additional items to manually check"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Not applicable"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Opportunity"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Estimated Savings"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Passed audits"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Score scale:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"There were issues affecting this run of Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Values are estimated and may vary."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Warnings: "}};
-
-
-},{}],47:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"[Çĥŕömé éxţéñšîöñš ñéĝåţîvéļý 僃éçţéð ţĥîš þåĝé'š ļöåð þéŕƒöŕmåñçé. Ţŕý åûðîţîñĝ ţĥé þåĝé îñ îñçöĝñîţö möðé öŕ ƒŕöm å Çĥŕömé þŕöƒîļé ŵîţĥöûţ éxţéñšîöñš. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"[Šçŕîþţ Évåļûåţîöñ one two three]"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"[Šçŕîþţ Þåŕšé one two]"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"[Ţöţåļ one]"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"[Çöñšîðéŕ ŕéðûçîñĝ ţĥé ţîmé šþéñţ þåŕšîñĝ, çömþîļîñĝ, åñð éxéçûţîñĝ ĴŠ. Ýöû måý ƒîñð ðéļîvéŕîñĝ šmåļļéŕ ĴŠ þåýļöåðš ĥéļþš ŵîţĥ ţĥîš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/бööţûþ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight]"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"[Ŕéðûçé ĴåvåŠçŕîþţ éxéçûţîöñ ţîmé one two three four five six seven]"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"[ĴåvåŠçŕîþţ éxéçûţîöñ ţîmé one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"[Ļåŕĝé ĜÎFš åŕé îñ郃îçîéñţ ƒöŕ ðéļîvéŕîñĝ åñîmåţéð çöñţéñţ. Çöñšîðéŕ ûšîñĝ MÞÉĜ4/ŴéбM vîðéöš ƒöŕ åñîmåţîöñš åñð ÞÑĜ/ŴéбÞ ƒöŕ šţåţîç îmåĝéš îñšţéåð öƒ ĜÎF ţö šåvé ñéţŵöŕķ бýţéš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ƒûñðåméñţåļš/þéŕƒöŕmåñçé/öþţîmîžîñĝ-çöñţéñţ-郃îçîéñçý/ŕéþļåçé-åñîmåţéð-ĝ-ŵîţĥ-vîðéö/) one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine thirty thirtyone thirtytwo thirtythree thirtyfour thirtyfive thirtysix thirtyseven]"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"[Ûšé vîðéö ƒöŕmåţš ƒöŕ åñîmåţéð çöñţéñţ one two three four five six seven eight]"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"[Çöñšîðéŕ ļåžý-ļöåðîñĝ öƒƒšçŕééñ åñð ĥîððéñ îmåĝéš åƒţéŕ åļļ çŕîţîçåļ ŕéšöûŕçéš ĥåvé ƒîñîšĥéð ļöåðîñĝ ţö ļöŵéŕ ţîmé ţö îñţéŕåçţîvé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/öƒƒšçŕééñ-îmåĝéš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight]"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"[Ðéƒéŕ öƒƒšçŕééñ îmåĝéš one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"[Ŕéšöûŕçéš åŕé бļöçķîñĝ ţĥé ƒîŕšţ þåîñţ öƒ ýöûŕ þåĝé. Çöñšîðéŕ ðéļîvéŕîñĝ çŕîţîçåļ ĴŠ/ÇŠŠ îñļîñé åñð ðéƒéŕŕîñĝ åļļ ñöñ-çŕîţîçåļ ĴŠ/šţýļéš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/бļöçķîñĝ-ŕéšöûŕçéš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine]"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"[Éļîmîñåţé ŕéñðéŕ-бļöçķîñĝ ŕéšöûŕçéš one two three four]"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"[Ļåŕĝé ñéţŵöŕķ þåýļöåðš çöšţ ûšéŕš ŕéåļ möñéý åñð åŕé ĥîĝĥļý çöŕŕéļåţéð ŵîţĥ ļöñĝ ļöåð ţîméš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ñéţŵöŕķ-þåýļöåðš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive]"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"[Ţöţåļ šîžé ŵåš {ţöţåļБýţéš} ĶБ one two three four five six seven]"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"[Åvöîð éñöŕmöûš ñéţŵöŕķ þåýļöåðš one two three four five six seven]"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"[Åvöîðš éñöŕmöûš ñéţŵöŕķ þåýļöåðš one two three four five six seven]"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"[Mîñîƒýîñĝ ÇŠŠ ƒîļéš çåñ ŕéðûçé ñéţŵöŕķ þåýļöåð šîžéš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/mîñîƒý-çšš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone]"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"[Mîñîƒý ÇŠŠ one two]"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"[Mîñîƒýîñĝ ĴåvåŠçŕîþţ ƒîļéš çåñ ŕéðûçé þåýļöåð šîžéš åñð šçŕîþţ þåŕšé ţîmé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/šþééð/ðöçš/îñšîĝĥţš/MîñîƒýŔéšöûŕçéš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree]"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"[Mîñîƒý ĴåvåŠçŕîþţ one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"[Ŕémövé ûñûšéð ŕûļéš ƒŕöm šţýļéšĥééţš ţö ŕéðûçé ûññéçéššåŕý бýţéš çöñšûméð бý ñéţŵöŕķ åçţîvîţý. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ûñûšéð-çšš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive]"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"[Ðéƒéŕ ûñûšéð ÇŠŠ one two]"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"[Ŕémövé ûñûšéð ĴåvåŠçŕîþţ ţö ŕéðûçé бýţéš çöñšûméð бý ñéţŵöŕķ åçţîvîţý. one two three four five six seven eight nine ten eleven twelve thirteen]"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"[Ŕémövé ûñûšéð ĴåvåŠçŕîþţ one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"[Å ļöñĝ çåçĥé ļîƒéţîmé çåñ šþééð ûþ ŕéþéåţ vîšîţš ţö ýöûŕ þåĝé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/çåçĥé-þöļîçý). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{[1 ŕéšöûŕçé ƒöûñð one two]}other{[# ŕéšöûŕçéš ƒöûñð one two three]}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"[Šéŕvé šţåţîç åššéţš ŵîţĥ åñ 郃îçîéñţ çåçĥé þöļîçý one two three four five six seven eight nine ten eleven]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"[Ûšéš éƒƒîçîéñţ çåçĥé þöļîçý öñ šţåţîç åššéţš one two three four five six seven eight nine]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"[Öþţîmîžéð îmåĝéš ļöåð ƒåšţéŕ åñð çöñšûmé ļéšš çéļļûļåŕ ðåţå. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/öþţîmîžé-îmåĝéš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"[Ƀƒîçîéñţļý éñçöðé îmåĝéš one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"[Šéŕvé îmåĝéš ţĥåţ åŕé åþþŕöþŕîåţéļý-šîžéð ţö šåvé çéļļûļåŕ ðåţå åñð îmþŕövé ļöåð ţîmé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/övéŕšîžéð-îmåĝéš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"[Þŕöþéŕļý šîžé îmåĝéš one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"[Ţéxţ-бåšéð ŕéšöûŕçéš šĥöûļð бé šéŕvéð ŵîţĥ çömþŕéššîöñ (ĝžîþ, ðéƒļåţé öŕ бŕöţļî) ţö mîñîmîžé ţöţåļ ñéţŵöŕķ бýţéš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ţéxţ-çömþŕéššîöñ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"[Éñåбļé ţéxţ çömþŕéššîöñ one two three]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"[Îmåĝé ƒöŕmåţš ļîķé ĴÞÉĜ 2000, ĴÞÉĜ XŔ, åñð ŴéбÞ öƒţéñ þŕövîðé бéţţéŕ çömþŕéššîöñ ţĥåñ ÞÑĜ öŕ ĴÞÉĜ, ŵĥîçĥ méåñš ƒåšţéŕ ðöŵñļöåðš åñð ļéšš ðåţå çöñšûmþţîöñ. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ŵéбþ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine thirty]"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"[Šéŕvé îmåĝéš îñ ñéxţ-ĝéñ ƒöŕmåţš one two three four five six seven]"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"[Ţĥé Çŕîţîçåļ Ŕéqûéšţ Çĥåîñš бéļöŵ šĥöŵ ýöû ŵĥåţ ŕéšöûŕçéš åŕé ļöåðéð ŵîţĥ å ĥîĝĥ þŕîöŕîţý. Çöñšîðéŕ ŕéðûçîñĝ ţĥé ļéñĝţĥ öƒ çĥåîñš, ŕéðûçîñĝ ţĥé ðöŵñļöåð šîžé öƒ ŕéšöûŕçéš, öŕ ðéƒéŕŕîñĝ ţĥé ðöŵñļöåð öƒ ûññéçéššåŕý ŕéšöûŕçéš ţö îmþŕövé þåĝé ļöåð. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/çŕîţîçåļ-ŕéqûéšţ-çĥåîñš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine thirty thirtyone thirtytwo thirtythree thirtyfour thirtyfive thirtysix thirtyseven thirtyeight thirtynine forty]"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{[1 çĥåîñ ƒöûñð one two]}other{[# çĥåîñš ƒöûñð one two]}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"[Mîñîmîžé Çŕîţîçåļ Ŕéqûéšţš Ðéþţĥ one two three four five six seven]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"[Éļéméñţ one]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"[Šţåţîšţîç one two]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"[Våļûé one]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"[Бŕöŵšéŕ éñĝîñééŕš ŕéçömméñð þåĝéš çöñţåîñ ƒéŵéŕ ţĥåñ ~1,500 ÐÖM ñöðéš. Ţĥé šŵééţ šþöţ îš å ţŕéé ðéþţĥ < 32 éļéméñţš åñð ƒéŵéŕ ţĥåñ 60 çĥîļðŕéñ/þåŕéñţ éļéméñţ. Å ļåŕĝé ÐÖM çåñ îñçŕéåšé mémöŕý ûšåĝé, çåûšé ļöñĝéŕ [šţýļé çåļçûļåţîöñš](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ƒûñðåméñţåļš/þéŕƒöŕmåñçé/ŕéñðéŕîñĝ/ŕéðûçé-ţĥé-šçöþé-åñð-çömþļéxîţý-öƒ-šţýļé-çåļçûļåţîöñš), åñð þŕöðûçé çöšţļý [ļåýöûţ ŕéƒļöŵš](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/šþééð/åŕţîçļéš/ŕéƒļöŵ). [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ðöm-šîžé). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine thirty thirtyone thirtytwo thirtythree thirtyfour thirtyfive thirtysix thirtyseven thirtyeight thirtynine forty one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{[1 ñöðé one]}other{[# ñöðéš one]}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"[Åvöîð åñ éxçéššîvé ÐÖM šîžé one two three four five six]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"[Måxîmûm ÐÖM Ðéþţĥ one two three]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"[Ţöţåļ ÐÖM Ñöðéš one two]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"[Måxîmûm Çĥîļð Éļéméñţš one two three]"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"[Åvöîðš åñ éxçéššîvé ÐÖM šîžé one two three four five six]"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"[Ļévéŕåĝé ţĥé ƒöñţ-ðîšþļåý ÇŠŠ ƒéåţûŕé ţö éñšûŕé ţéxţ îš ûšéŕ-vîšîбļé ŵĥîļé ŵéбƒöñţš åŕé ļöåðîñĝ. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ûþðåţéš/2016/02/ƒöñţ-ðîšþļåý). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour]"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"[Éñšûŕé ţéxţ ŕémåîñš vîšîбļé ðûŕîñĝ ŵéбƒöñţ ļöåð one two three four five six seven eight nine ten]"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"[Åļļ ţéxţ ŕémåîñš vîšîбļé ðûŕîñĝ ŵéбƒöñţ ļöåðš one two three four five six seven eight nine]"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"[Çåţéĝöŕý one]"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"[Çöñšîðéŕ ŕéðûçîñĝ ţĥé ţîmé šþéñţ þåŕšîñĝ, çömþîļîñĝ åñð éxéçûţîñĝ ĴŠ. Ýöû måý ƒîñð ðéļîvéŕîñĝ šmåļļéŕ ĴŠ þåýļöåðš ĥéļþš ŵîţĥ ţĥîš. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty]"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"[Mîñîmîžé måîñ-ţĥŕéåð ŵöŕķ one two three]"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"[Mîñîmîžéš måîñ-ţĥŕéåð ŵöŕķ one two three]"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"[Ţĥé šçöŕé åбövé îš åñ éšţîmåţé öƒ ĥöŵ ļöñĝ ýöûŕ åþþ ţåķéš ţö ŕéšþöñð ţö ûšéŕ îñþûţ, îñ mîļļîšéçöñðš, ðûŕîñĝ ţĥé бûšîéšţ 5š ŵîñðöŵ öƒ þåĝé ļöåð. ΃ ýöûŕ ļåţéñçý îš ĥîĝĥéŕ ţĥåñ 50 mš, ûšéŕš måý þéŕçéîvé ýöûŕ åþþ åš ļåĝĝý. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/éšţîmåţéð-îñþûţ-ļåţéñçý). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine thirty thirtyone thirtytwo thirtythree thirtyfour thirtyfive thirtysix thirtyseven thirtyeight]"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"[Éšţîmåţéð Îñþûţ Ļåţéñçý one two three]"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"[Fîŕšţ Çöñţéñţƒûļ Þåîñţ måŕķš ţĥé ţîmé åţ ŵĥîçĥ ţĥé ƒîŕšţ ţéxţ öŕ îmåĝé îš þåîñţéð. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ƒîŕšţ-çöñţéñţƒûļ-þåîñţ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive]"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"[Fîŕšţ Çöñţéñţƒûļ Þåîñţ one two three]"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"[Fîŕšţ ÇÞÛ Îðļé måŕķš ţĥé ƒîŕšţ ţîmé åţ ŵĥîçĥ ţĥé þåĝé'š måîñ ţĥŕéåð îš qûîéţ éñöûĝĥ ţö ĥåñðļé îñþûţ. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ƒîŕšţ-îñţéŕåçţîvé). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix]"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"[Fîŕšţ ÇÞÛ Îðļé one two]"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"[Fîŕšţ Méåñîñĝƒûļ Þåîñţ méåšûŕéš ŵĥéñ ţĥé þŕîmåŕý çöñţéñţ öƒ å þåĝé îš vîšîбļé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ƒîŕšţ-méåñîñĝƒûļ-þåîñţ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour]"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"[Fîŕšţ Méåñîñĝƒûļ Þåîñţ one two three]"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"[Îñţéŕåçţîvé måŕķš ţĥé ţîmé åţ ŵĥîçĥ ţĥé þåĝé îš ƒûļļý îñţéŕåçţîvé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/çöñšîšţéñţļý-îñţéŕåçţîvé). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree]"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"[Ţîmé ţö Îñţéŕåçţîvé one two three]"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"[Šþééð Îñðéx šĥöŵš ĥöŵ qûîçķļý ţĥé çöñţéñţš öƒ å þåĝé åŕé vîšîбļý þöþûļåţéð. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/šþééð-îñðéx). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree]"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"[Šþééð Îñðéx one two]"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"[Ŕéðîŕéçţš îñţŕöðûçé åððîţîöñåļ ðéļåýš бéƒöŕé ţĥé þåĝé çåñ бé ļöåðéð. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ŕéðîŕéçţš). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"[Åvöîð mûļţîþļé þåĝé ŕéðîŕéçţš one two three four five six seven]"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"[Ţîmé Ţö Fîŕšţ Бýţé îðéñţîƒîéš ţĥé ţîmé åţ ŵĥîçĥ ýöûŕ šéŕvéŕ šéñðš å ŕéšþöñšé. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ţţƒб). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree]"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"[Ŕööţ ðöçûméñţ ţööķ {ţîméÎñMš} mš one two three four five six seven]"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"[Ŕéðûçé šéŕvéŕ ŕéšþöñšé ţîméš (ŢŢFБ) one two three four five six seven eight]"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"[Šéŕvéŕ ŕéšþöñšé ţîméš åŕé ļöŵ (ŢŢFБ) one two three four five six seven eight]"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"[Ðûŕåţîöñ one]"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"[Ñåmé one]"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"[Šţåŕţ Ţîmé one two]"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"[Ţýþé one]"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"[Çöñšîðéŕ îñšţŕûméñţîñĝ ýöûŕ åþþ ŵîţĥ ţĥé Ûšéŕ Ţîmîñĝ ÅÞÎ ţö méåšûŕé ýöûŕ åþþ'š ŕéåļ-ŵöŕļð þéŕƒöŕmåñçé ðûŕîñĝ ķéý ûšéŕ éxþéŕîéñçéš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/ûšéŕ-ţîmîñĝ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight]"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{[1 ûšéŕ ţîmîñĝ one two]}other{[# ûšéŕ ţîmîñĝš one two]}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"[Ûšéŕ Ţîmîñĝ måŕķš åñð méåšûŕéš one two three four five six seven]"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"[Çöñšîðéŕ åððîñĝ þŕéçöññéçţ öŕ ðñš-þŕéƒéţçĥ ŕéšöûŕçé ĥîñţš ţö éšţåбļîšĥ éåŕļý çöññéçţîöñš ţö îmþöŕţåñţ ţĥîŕð-þåŕţý öŕîĝîñš. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ƒûñðåméñţåļš/þéŕƒöŕmåñçé/ŕéšöûŕçé-þŕîöŕîţîžåţîöñ#þŕéçöññéçţ). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive twentysix twentyseven twentyeight twentynine]"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"[Þŕéçöññéçţ ţö ŕéqûîŕéð öŕîĝîñš one two three four five six seven]"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"[Çöñšîðéŕ ûšîñĝ <link rel=preload> ţö þŕîöŕîţîžé ƒéţçĥîñĝ ŕéšöûŕçéš ţĥåţ åŕé çûŕŕéñţļý ŕéqûéšţéð ļåţéŕ îñ þåĝé ļöåð. [Ļéåŕñ möŕé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/åûðîţš/þŕéļöåð). one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo twentythree twentyfour twentyfive]"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"[Þŕéļöåð ķéý ŕéqûéšţš one two three]"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"[Möŕé îñƒöŕmåţîöñ åбöûţ ţĥé þéŕƒöŕmåñçé öƒ ýöûŕ åþþļîçåţîöñ. one two three four five six seven eight nine ten eleven twelve]"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"[Ðîåĝñöšţîçš one two]"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"[Ţĥé möšţ çŕîţîçåļ åšþéçţ öƒ þéŕƒöŕmåñçé îš ĥöŵ qûîçķļý þîxéļš åŕé ŕéñðéŕéð öñšçŕééñ. Ķéý méţŕîçš: Fîŕšţ Çöñţéñţƒûļ Þåîñţ, Fîŕšţ Méåñîñĝƒûļ Þåîñţ one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"[Fîŕšţ Þåîñţ Îmþŕövéméñţš one two three]"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"[Ţĥéšé öþţîmîžåţîöñš çåñ šþééð ûþ ýöûŕ þåĝé ļöåð. one two three four five six seven eight nine ten]"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"[Öþþöŕţûñîţîéš one two]"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"[Méţŕîçš one]"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"[Éñĥåñçé ţĥé övéŕåļļ ļöåðîñĝ éxþéŕîéñçé, šö ţĥé þåĝé îš ŕéšþöñšîvé åñð ŕéåðý ţö ûšé åš šööñ åš þöššîбļé. Ķéý méţŕîçš: Ţîmé ţö Îñţéŕåçţîvé, Šþééð Îñðéx one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"[Övéŕåļļ Îmþŕövéméñţš one two three]"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"[Þéŕƒöŕmåñçé one two]"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"[Çåçĥé ŢŢĻ one two]"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"[Šîžé (ĶБ) one two]"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"[Ţîmé Šþéñţ one two]"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"[ÛŔĻ one]"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"[Þöţéñţîåļ Šåvîñĝš (ĶБ) one two three]"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"[Þöţéñţîåļ Šåvîñĝš (mš) one two three]"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"[Þöţéñţîåļ šåvîñĝš öƒ {ŵåšţéðБýţéš} ĶБ one two three four five six seven eight]"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"[Þöţéñţîåļ šåvîñĝš öƒ {ŵåšţéðMš} mš one two three four five six seven]"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"[{ţîméÎñMš} mš one two]"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"[{ţîméÎñMšŠéç} š one two]"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"[Šĥöŵ åûðîţš one two]"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"[Îñîţîåļ Ñåvîĝåţîöñ one two three]"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"[Måxîmûm çŕîţîçåļ þåţĥ ļåţéñçý: one two three four five six seven]"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"[Éŕŕöŕ¡ one]"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"[Ŕéþöŕţ éŕŕöŕ: ñö åûðîţ îñƒöŕmåţîöñ one two three four five six seven]"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"[Ļåб Ðåţå one]"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[[Ļîĝĥţĥöûšé](ĥţţþš://ðévéļöþéŕš.ĝööĝļé.çöm/ŵéб/ţööļš/ļîĝĥţĥöûšé/) åñåļýšîš öƒ ţĥé çûŕŕéñţ þåĝé öñ émûļåţéð 3Ĝ. Våļûéš åŕé éšţîmåţéð åñð måý våŕý. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twentyone twentytwo]"},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"[Åððîţîöñåļ îţémš ţö måñûåļļý çĥéçķ one two three four five six seven]"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"[Ñöţ åþþļîçåбļé one two]"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"[Öþþöŕţûñîţý one two]"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"[Éšţîmåţéð Šåvîñĝš one two three]"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"[Þåššéð åûðîţš one two]"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"[Šçöŕé šçåļé: one two]"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"[Ţĥéŕé ŵéŕé îššûéš åƒƒéçţîñĝ ţĥîš ŕûñ öƒ Ļîĝĥţĥöûšé: one two three four five six seven eight nine ten eleven]"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"[Våļûéš åŕé éšţîmåţéð åñð måý våŕý. one two three four five six seven]"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"[Ŵåŕñîñĝš: one two]"}};
-
-
-},{}],48:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Las extensiones de Chrome han afectado de forma negativa al rendimiento de carga de esta página. Prueba a auditarla en modo incógnito o desde un perfil de Chrome sin extensiones."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Evaluación de la secuencia de comandos"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Análisis de la secuencia de comandos"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Te recomendamos que reduzcas el tiempo de análisis, compilación y ejecución de JavaScript. Para ello, puedes utilizar cargas útiles de JS más pequeñas. [Más información](https://developers.google.com/web/tools/lighthouse/audits/bootup)"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reduce el tiempo de ejecución de JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Tiempo de ejecución de JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Los GIF de gran tamaño no son eficaces para mostrar contenido animado. Para usar menos bytes de la red, te recomendamos que utilices los formatos de vídeo PEG4/WebM para incluir animaciones y los formatos PNG/WebP para añadir imágenes estáticas en lugar de GIFs. [Más información](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Usa formatos de vídeo para incluir contenido animado"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Te recomendamos que uses la carga diferida con imágenes ocultas y que no aparecen en pantalla una vez que todos los recursos críticos hayan terminado de cargarse para reducir el tiempo hasta que la página es interactiva. [Más información](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Pospón la carga de imágenes que no aparecen en pantalla"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Hay recursos que bloquean el primer renderizado de la página. Te recomendamos que muestres los elementos JS/CSS críticos insertados y pospongas todos los JS/styles que no sean críticos. [Más información](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Elimina los recursos que bloqueen el renderizado"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Si la carga útil de la red es muy grande, los usuarios consumen más datos móviles y las páginas tardan más en cargarse. [Más información](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Tamaño total: {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Evita cargas útiles de red de gran tamaño"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Evita cargas útiles de red de gran tamaño"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Si minificas los archivos CSS, se puede reducir el tamaño de la carga útil de la red. [Más información](https://developers.google.com/web/tools/lighthouse/audits/minify-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minifica los archivos CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Si minificas los archivos JavaScript, se puede reducir el tamaño de la carga útil y el tiempo de análisis de la secuencia de comandos. [Más información](https://developers.google.com/speed/docs/insights/MinifyResources)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minifica los recursos JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Quita las reglas que no se usen de las hojas de estilo para reducir el número de bytes innecesarios que consume la actividad de red. [Más información](https://developers.google.com/web/tools/lighthouse/audits/unused-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Pospón la carga de archivos CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Quita el contenido JavaScript que no se use para reducir el número de bytes que consume la actividad de red."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Quita los recursos JavaScript que no se usen"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Una duración en caché más larga puede aumentar el número de visitas repetidas a tu página. [Más información](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Se ha encontrado 1 recurso}other{Se han encontrado # recursos}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Publica recursos estáticos con una política de caché eficaz"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Usa una política de caché eficaz en recursos estáticos"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Las imágenes optimizadas se cargan más rápido y consumen menos datos móviles. [Más información](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codifica las imágenes de forma eficaz"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Muestra imágenes con un tamaño adecuado para ahorrar datos móviles y mejorar el tiempo de carga. [Más información](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Usa un tamaño adecuado para las imágenes"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Los recursos basados en texto se deberían publicar comprimidos (gzip, deflate o brotli) para minimizar el total de bytes de la red. [Más información](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Habilita la compresión de texto"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Los formatos como JPEG 2000, JPEG XR y WebP comprimen mejor las imágenes que los formatos PNG o JPEG, lo que hace que se descarguen más rápido y consuman menos datos. [Más información](https://developers.google.com/web/tools/lighthouse/audits/webp)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Publica imágenes con formatos de próxima generación"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Las cadenas de solicitud crítica que se muestran a continuación indican qué recursos son de alta prioridad. Te recomendamos que reduzcas la longitud de las cadenas, disminuyas el tamaño de los recursos o pospongas la descarga de recursos innecesarios para mejorar la carga de la página. [Más información](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Se ha encontrado 1 cadena}other{Se han encontrado # cadenas}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimiza la profundidad de las solicitudes críticas"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Los ingenieros que desarrollan navegadores recomiendan que las páginas contengan menos de ~1500 nodos de DOM. Lo ideal es conseguir una profundidad de árbol de < 32 elementos y menos de 60 elementos secundarios por cada nodo principal. Los DOM de gran tamaño aumentan el uso de la memoria, hacen que los [cálculos de estilo](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) sean más largos y producen [reinicios de flujo](https://developers.google.com/speed/articles/reflow) más caros. [Más información](https://developers.google.com/web/tools/lighthouse/audits/dom-size)"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nodo}other{# nodos}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Evita un tamaño excesivo de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Profundidad máxima de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Nodos totales de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Evita un tamaño excesivo de DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Utiliza la función de CSS font-display para que los usuarios vean el texto mientras se carga la fuente web. [Más información](https://developers.google.com/web/updates/2016/02/font-display)"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Asegúrate de que el texto permanece visible mientras se carga la fuente web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Todo el texto permanece visible mientras se carga la fuente web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categoría"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Te recomendamos que reduzcas el tiempo de análisis, compilación y ejecución de JavaScript. Para ello, puedes utilizar cargas útiles de JS más pequeñas."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimiza el trabajo del hilo principal"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimiza el trabajo del hilo principal"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"La puntuación anterior es una estimación de cuánto tarda tu aplicación en responder a las acciones de los usuarios (en milisegundos) durante el periodo de 5 s más activo de la carga de la página. Si la latencia es superior a 50 ms, es posible que los usuarios noten que la aplicación funciona con lentitud. [Más información](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Latencia de entrada estimada"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"El primer renderizado con contenido indica el momento en el que se renderiza el primer texto o la primera imagen. [Más información](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Primer renderizado con contenido"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"El primer tiempo inactivo de la CPU indica la primera vez que el hilo principal de la página está lo suficientemente inactivo para recibir acciones del usuario. [Más información](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Primer tiempo inactivo de la CPU"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"El primer renderizado significativo mide el momento en que se muestra el contenido principal de la página. [Más información](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Primer renderizado significativo"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"La métrica Tiempo hasta que está interactiva indica el momento en el que la página es totalmente interactiva. [Más información](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tiempo hasta que está interactiva"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"El índice de velocidad indica la rapidez con la que se puede ver el contenido de una página. [Más información](https://developers.google.com/web/tools/lighthouse/audits/speed-index)"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Índice de velocidad"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Las redirecciones provocan retrasos adicionales antes de que la página se pueda cargar. [Más información](https://developers.google.com/web/tools/lighthouse/audits/redirects)"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Evita que haya varias redirecciones de página"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"El tiempo hasta el primer byte indica el momento en el que el servidor envía una respuesta. [Más información](https://developers.google.com/web/tools/lighthouse/audits/ttfb)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"El documento raíz ha tardado {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reduce los tiempos de respuesta del servidor (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Los tiempos de respuesta del servidor son rápidos (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Duración"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nombre"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Hora de inicio"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tipo"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Te recomendamos que uses la API User Timing en tu aplicación para calcular su rendimiento real durante las principales experiencias de usuario. [Más información](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 tiempo de usuario}other{# tiempos de usuario}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Medidas y marcas de User Timing"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Te recomendamos que añadas sugerencias de recursos preconnect o dns-prefetch para establecer conexiones previas con orígenes externos. [Más información](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Establece conexión previamente con los orígenes necesarios"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Te recomendamos que uses <link rel=preload> para dar prioridad a los recursos que se solicitan más tarde al cargar la página. [Más información](https://developers.google.com/web/tools/lighthouse/audits/preload)"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Carga previamente las solicitudes clave"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Consulta más información sobre el rendimiento de tu aplicación."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnósticos"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"El aspecto más importante del rendimiento es la rapidez con la que se renderizan los píxeles en la pantalla. Métricas clave: Primer renderizado con contenido y Primer renderizado significativo"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Mejoras del primer renderizado"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Estas optimizaciones pueden hacer que tus páginas se carguen más rápido."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Oportunidades"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Métricas"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Mejora la experiencia de carga general para que la página responda bien y se pueda usar lo antes posible. Métricas clave: Tiempo hasta que está interactiva, Índice de velocidad"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Mejoras generales"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Rendimiento"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Tiempo de vida en caché"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Tamaño (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Duración"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Ahorro potencial (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Ahorro potencial (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Ahorro potencial de {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Ahorro potencial de {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Mostrar auditorías"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navegación inicial"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latencia de ruta crítica máxima:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Error"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Error del informe: no hay información de la auditoría"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Datos de prueba"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) ha analizado la página actual mediante una emulación de 3G. Los valores son estimaciones y pueden variar."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Elementos adicionales que se deben comprobar manualmente"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"No aplicable"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Oportunidad"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Ahorro estimado"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Auditorías aprobadas"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Escala de puntuación:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Algunos problemas han afectado a la ejecución de Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Los valores son estimados y pueden variar."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Advertencias: "}};
-
-
-},{}],49:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chromen laajennukset heikensivät tämän sivun latausnopeutta. Yritä tarkastaa sivu incognito-tilassa tai Chrome-profiililla, johon ei ole lisätty laajennuksia."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Skriptin arviointi"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Skriptin jäsennys"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Yhteensä"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Suosittelemme vähentämään JS:n jäsentämiseen, kääntämiseen ja suorittamiseen kuluvaa aikaa. Pienempien JS-resurssien jakeleminen voi helpottaa tätä. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Vähennä JavaScriptin suorittamiseen kuluvaa aikaa"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScriptin suorittamiseen kuluva aika"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Suuret GIFit eivät ole tehokas tapa jaella animoitua sisältöä. Voit pienentää ladattavien tavujen määrää jakelemalla animaatioita MPEG4- tai WebM-muodossa ja staattisia kuvia PNG- tai WebP-muodossa. [Lue lisää](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Jakele animaatiosisältöä videomuodossa"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Suosittelemme lykkäämään poissa näkyvistä olevien ja piilotettujen kuvien lataamista, kunnes kaikki kriittiset resurssit on ladattu. Tämä lyhentää interaktiivisuutta edeltävää aikaa. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Lykkää kuvien lataamista, jos ne eivät ole näkyvissä"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resurssit estävät sivun ensimmäisen renderöinnin. Suosittelemme jakelemaan kriittiset JS- ja CSS-osat sivuun upotettuina ja lykkäämään kaikkien ei-kriittisten JS- tai tyyliosien lataamista. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Poista renderöinnin estävät resurssit"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Suuret verkkoresurssit aiheuttavat kuluja käyttäjille ja liittyvät vahvasti pitkiin latausaikoihin. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Yhteenlaskettu koko oli {totalBytes, number, bytes} kt"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Vältä valtavia verkkoresursseja"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Välttää valtavia verkkoresursseja"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS-tiedostojen pienentäminen voi auttaa pienentämään verkkoresurssien kokoa. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Pienennä CSS-tiedostoja"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"JavaScript-tiedostojen pienentäminen voi auttaa pienentämään resurssien kokoa ja lyhentämään skriptin jäsentämiseen kuluvaa aikaa. [Lue lisää](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Pienennä JavaScript-tiedostoja"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Poista käyttämättömät säännöt tyylitiedostoista, jotta voit vähentää verkkotoiminnan tarpeettomasti kuluttamia tavuja. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Lykkää tarpeettoman CSS:n lataamista"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Poista käyttämättömät JavaScript-osat, jotta voit vähentää verkkotoiminnan kuluttamia tavuja."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Poista käyttämätön JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Pitkä välimuistin käyttöikä voi nopeuttaa sivun lataamista, kun käyttäjä avaa sen uudelleen. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 resurssi löydetty}other{# resurssia löydetty}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Käytä tehokasta välimuistikäytäntöä staattisten resurssien jakelemiseen"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Käyttää tehokasta välimuistikäytäntöä staattisten resurssien käsittelyyn"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimoidut kuvat latautuvat nopeammin ja kuluttavat vähemmän mobiilidataa. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Koodaa kuvat tehokkaasti"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Näytä sopivan kokoisia kuvia, jotta voit pienentää mobiilidatan kulutusta ja latausaikoja. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Määritä kuvien koko oikein"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Tekstipohjaiset resurssit on hyvä pakata ennen jakelua (gzip, deflate tai brotli), jotta ladattavien tavujen määrä voidaan minimoida. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Ota tekstin pakkaus käyttöön"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Kuvamuodot, kuten JPEG 2000, JPEG XR ja WebP, pakkaavat sisältöä usein paremmin kuin PNG tai JPEG, minkä vuoksi ne auttavat nopeuttamaan latauksia ja vähentämään datan kulutusta. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Jakele kuvat seuraavan sukupolven muodoissa"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Alla olevat kriittiset pyyntöketjut kertovat, minkä resurssien lataaminen priorisoidaan. Suosittelemme parantamaan sivun latausaikaa lyhentämällä ketjuja, pienentämällä resurssien latauskokoa ja lykkäämällä tarpeettomien resurssien lataamista. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ketju löydetty}other{# ketjua löydetty}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimoi kriittisten pyyntöjen syvyys"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Selainten kehittäjät suosittelevat käyttämään sivulla enintään noin 1 500:aa DOM-noodia. Sopiva puun syvyys on korkeintaan 32 elementtiä ja alle 60 ala- tai ylätason elementtiä. Suuri DOM voi lisätä muistin käyttöä, pidentää [tyylilaskelmia](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) ja aiheuttaa työläitä [asettelun uudelleenjuoksutuksia](https://developers.google.com/speed/articles/reflow). [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 noodi}other{# noodia}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Vältä liian suurta DOM:ää"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"DOM:n enimmäissyvyys"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"DOM-noodien kokonaismäärä"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Välttää liian suurta DOM:ää"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Käytä CSS:n kirjasimennäyttöominaisuutta, jotta voit varmistaa, että käyttäjä näkee tekstin myös verkkofonttien lataamisen aikana. [Lue lisää](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Varmista, että teksti pysyy näkyvissä verkkofontin lataamisen aikana"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Kaikki teksti pysyy näkyvissä verkkofontin lataamisen aikana"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Luokka"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Suosittelemme vähentämään JS:n jäsentämiseen, kääntämiseen ja suorittamiseen kuluvaa aikaa. Pienempien JS-resurssien jakaminen voi helpottaa tätä."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimoi pääsäikeen työkuorma"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimoi pääsäikeen työkuorman"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Yllä oleva tulos on millisekunteina annettu arvio siitä, kuinka kauan sovelluksellasi kestää vastata käyttäjän syötteeseen sivun lataamisen kiireisimmän, viiden sekunnin mittaisen jakson aikana. Jos viive on yli 50 ms, sovelluksesi voi toimia käyttäjien mielestä hitaasti. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Arvioitu syöttöviive"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Ensimmäinen merkityksellinen piirtäminen kertoo, milloin sivun ensisijainen sisältö tulee näkyviin. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Ensimmäinen sisällön renderöinti"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"CPU:n ensimmäinen toimettomuusjakso kertoo, milloin sivun pääsäikeen tilanne sallii syötteiden käsittelyn. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU:n ensimmäinen toimettomuusjakso"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Ensimmäinen merkityksellinen renderöinti kertoo, milloin sivun ensisijainen sisältö tulee näkyviin. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Ensimmäinen merkityksellinen renderöinti"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktiivisuutta edeltävä aika kertoo, milloin sivun kaikki osat ovat käytettävissä. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Interaktiivisuutta edeltävä aika"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Nopeusindeksi kertoo, kuinka nopeasti sivun sisältö tulee näkyviin. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Nopeusindeksi"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Uudellenohjaukset viivästyttävät sivun lataamista. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Vältä useita uudelleenohjauksia"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Ensimmäistä tavua edeltävä aika kertoo, kuinka kauan kestää, ennen kuin palvelimesi lähettää vastauksen. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Päädokumentti käytti {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Lyhennä palvelimen vastausaikoja (ensimmäistä tavua edeltävä aika)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Palvelimen vastausajat ovat lyhyitä (ensimmäistä tavua edeltävä aika)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Kesto"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nimi"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Aloitusaika"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tyyppi"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Suosittelemme käyttämään sovelluksen kehittämisessä User Timing ‑sovellusliittymää mittaamaan todellista toimivuutta tärkeiden käyttökokemuksien aikana. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 käyttäjän ajankäyttömerkintä}other{# käyttäjän ajankäyttömerkintää}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing ‑merkinnät ja ‑mitat"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Suosittelemme lisäämään sivulle yhteyttä tai DNS:n noutamista edeltäviä resurssivihjeitä, joiden avulla yhteydet tärkeisiin kolmannen osapuolen kohteisiin voidaan muodostaa etukäteen. [Lue lisää](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Muodosta yhteydet pakollisiin kohteisiin etukäteen"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Suosittelemme käyttämään <link rel=preload>-tagia, jotta voit priorisoida resursseja, joiden noutamista pyydetään sivun lataamisen myöhemmässä vaiheessa. [Lue lisää](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Lataa tärkeät pyynnöt etukäteen"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Lisätietoja sovelluksen toiminnasta"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostiikka"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Tehokkuuden tärkein osa-alue on se, kuinka nopeasti pikselit renderöidään näytölle. Tärkeimmät mittarit ovat ensimmäinen sisällön renderöinti ja ensimmäinen merkityksellinen renderöinti."},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Ensimmäistä renderöintiä koskevat parannusehdotukset"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Nämä optimointikeinot voivat nopeuttaa sivun lataamista."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Suositukset"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Tiedot"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Paranna latauskokemusta kokonaisuutena, jotta sivu on responsiivisempi ja käytettävissä mahdollisimman pian. Tärkeimmät mittarit ovat interaktiivisuutta edeltävä aika ja nopeusindeksi."},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Yleiset parannusehdotukset"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Tehokkuus"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Välimuistin käyttöikä"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Koko (kt)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Käytetty aika"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL-osoite"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potentiaalinen säästö (kt)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potentiaalinen säästö (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potentiaalinen säästö: {wastedBytes, number, bytes} kt"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potentiaalinen säästö: {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Näytä tarkastukset"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Ensimmäinen navigointi"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Kriittisen polun enimmäisviive:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Virhe!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Raporttivirhe: ei tarkastustietoja"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratoriodata"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysoi nykyisen sivun 3G-emulaation avulla. Arvot ovat arvioita ja voivat vaihdella."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Lisää manuaalisesti tarkistettavia kohteita"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Ei sovellu"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Suositus"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Arvioitu säästö"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Hyväksytyt tarkastukset"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Pisteasteikko:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Lighthousen suorituksessa havaittiin ongelmia:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Arvot ovat arvioita ja voivat vaihdella."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Varoitukset: "}};
-
-
-},{}],50:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Nagkaroon ng negatibong epekto ang mga extension ng Chrome sa performance ng pag-load ng page na ito. Subukang i-audit ang page sa incognito mode o mula sa isang profile sa Chrome nang walang extension."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Pagsusuri ng Script"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Pag-parse ng Script"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Kabuuan"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Pag-isipang bawasan ang oras na ginugugol sa pag-parse, pag-compile, at pagpapagana ng JS. Maaaring mapansin mong nakakatulong dito ang paghahatid ng mas maliliit na payload ng JS. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Pabilisin ang pagpapagana ng JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Bilis ng pagpapagana ng JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Hindi mahusay ang malalaking GIF sa paghahatid ng animated na content. Pag-isipang gumamit ng mga MPEG4/WebM na video para sa mga animation at PNG/WebP para sa mga static na larawan sa halip na GIF para makatipid sa mga byte ng network. [Matuto pa](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Gumamit ng mga format ng video para sa animated na content"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Pag-isipang i-lazy load ang mga larawang wala sa screen at nakatago kapag tapos nang mag-load ang lahat ng mahalagang resource para mapabilis ang time to interactive. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Ipagpaliban ang mga larawang wala sa screen"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Bina-block ng mga resource ang first paint ng iyong page. Pag-isipang ihatid ang mahalagang JS/CSS inline at ipagpaliban ang lahat ng hindi mahalagang JS/istilo. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Alisin ang mga resource na nagba-block ng pag-render"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Malaki ang nagagastos ng mga user sa malalaking payload ng network, at malaki ang kaugnayan ng mga ito sa matagal na pag-load. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Ang kabuuang laki ay {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Iwasan ang malalaking payload ng network"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Umiiwas sa malalaking payload ng network"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Kapag pinaliit ang mga CSS file, maaaring lumiit ang payload ng network. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Paliitin ang CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Kapag pinaliit ang mga JavaScript file, maaaring lumiit ang payload at bumilis ang pag-parse ng script. [Matuto pa](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Paliitin ang JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Alisin ang mga hindi nagamit na panuntunan mula sa mga stylesheet para mabawasan ang mga hindi kinakailangang byte na nakokonsumo ng aktibidad sa network. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Ipagpaliban ang hindi nagamit na CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Alisin ang hindi nagamit na JavaScript para mabawasan ang mga byte na nakokonsumo ng aktibidad sa network."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Alisin ang hindi nagamit na JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Maaaring mapabilis ng mahabang lifetime ng cache ang mga umuulit na pagbisita sa iyong page. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Nakakita ng 1 resource}one{Nakakita ng # resource}other{Nakakita ng # na resource}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Maghatid ng mga static na asset nang may mahusay na patakaran sa cache"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Gumagamit ng mahusay na patakaran sa cache sa mga static na asset"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Mas mabilis mag-load ang mga na-optimize na page at mas kaunti ang nakokonsumong cellular data ng mga ito. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Mahusay na mag-encode ng mga larawan"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Maghatid ng mga larawang naaangkop ang laki para makatipid sa cellular data at mapabilis ang pag-load. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Iangkop ang laki ng mga larawan"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Dapat ihatid ang mga text-based na resource nang may compression (gzip, deflate, o brotli) para mabawasan ang kabuuang byte ng network. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"I-enable ang compression ng text"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Kadalasan, mas mahusay ang compression ng mga format ng imahe gaya ng JPEG 2000, JPEG XR, at WebP kaysa sa compression ng PNG o JPEG, kaya mas mabilis ang pag-download at mas kaunti ang nakokonsumong data ng mga ito. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Maghatid ng mga larawan sa mga makabagong format"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Ipinapakita sa iyo ng Critical Request Chains sa ibaba kung anong mga resource ang nilo-load nang may mataas na priyoridad. Pag-isipang paikliin ang mga chain, paliitin ang mga dina-download sa mga resource, o ipagpaliban ang pag-download ng mga hindi kinakailangang resource para mapabilis ang pag-load ng page [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Nakakita ng 1 chain}one{Nakakita ng # chain}other{Nakakita ng # na chain}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"I-minimize ang Lalim ng Mahahalagang Kahilingan"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Inirerekomenda ng mga engineer ng browser na hindi umabot sa ~1,500 ang mga node ng DOM sa mga page. Ang pinakamainam ay isang lalim ng tree na < 32 elemento at wala pang 60 child/parent na elemento. Ang malaking DOM ay maaaring magresulta sa mas malakas na paggamit ng memory, at magpahaba ng [mga pagkalkula ng istilo](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), at gumawa ng mga magastos na [reflow ng layout](https://developers.google.com/speed/articles/reflow). [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 node}one{# node}other{# na node}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Umiwas sa masyadong malaking DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximum na Lalim ng DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Kabuuang Bilang ng Mga Node ng DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Umiiwas sa masyadong malaking DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Gamitin ang feature na font-display ng CSS para matiyak na nakikita ng user ang text sa pag-load ng mga webfont. [Matuto pa](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Tiyaking patuloy na nakikita ang text sa pag-load ng webfont"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Patuloy na nakikita ang lahat ng text sa pag-load ng webfont"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorya"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Pag-isipang bawasan ang oras na ginugugol sa pag-parse, pag-compile, at pagpapagana ng JS. Maaaring mapansin mong nakakatulong dito ang paghahatid ng mas maliliit na payload ng JS."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Bawasan ang gawain sa pangunahing thread"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Binabawasan ang gawain sa pangunahing thread"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Ang marka sa itaas ay isang pagtataya ng bilis ng pagtugon ng iyong app sa input ng user, na nasa milliseconds, sa pinakaabalang 5 segundong window ng pag-load ng page. Kung mas mataas sa 50 ms ang iyong latency, maaaring ituring ng mga user na mabagal ang app mo. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Tinatayang Latency ng Input"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Minamarkahan ng First Contentful Paint ang oras ng pag-paint sa unang text o larawan. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"First Contentful Paint"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Minamarkahan ng First CPU Idle ang unang beses kung kailan hindi abala ang pangunahing thread ng page at maaari itong mangasiwa ng input. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"First CPU Idle"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Sinusukat ng First Meaningful Paint ang bilis ng pagpapakita sa pangunahing content ng isang page. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"First Meaningful Paint"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Minamarkahan ng Interactive ang oras kung kailan ganap na naging interactive ang page. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Time to Interactive"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Ipinapakita ng Speed Index ang bilis ng pag-populate ng mga content ng isang page. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Speed Index"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Nagpapasimula ang mga pag-redirect ng mga karagdagang pagkaantala bago ma-load ang page. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Iwasan ang mga pag-redirect sa maraming page"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Tinutukoy ng Time To First Byte ang oras kung kailan nagpapadala ng tugon ang iyong server. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Inabot nang {timeInMs, number, milliseconds} ms ang root na dokumento"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Pabilisin ang pagtugon ng server (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Masyadong matagal ang pagtugon ng server (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Tagal"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Pangalan"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Oras ng Pagsisimula"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Uri"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Pag-isipang gumamit ng User Timing API sa iyong app para sukatin ang makatotohanang performance ng app mo sa mahahalagang karanasan ng user. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 timing ng user}one{# timing ng user}other{# na timing ng user}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Mga marka at sukat ng User Timing"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Pag-isipang magdagdag ng resource hint na preconnect o dns-prefetch para makapagtakda ng mga paunang koneksyon sa mahahalagang third-party na origin. [Matuto pa](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Mag-preconnect sa mga kinakailangang origin"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Pag-isipang gumamit ng <link rel=preload> para mabigyang-priyoridad ang pagkuha ng mga resource na kasalukuyang hinihiling, sa pag-load ng page, para sa ibang pagkakataon. [Matuto pa](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"I-preload ang mahahalagang kahilingan"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Higit pang impormasyon tungkol sa performance ng iyong application."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Mga Diagnostic"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Ang pinakamahalagang aspeto ng performance ay ang bilis ng pag-render ng mga pixel sa screen. Mahahalagang sukatan: First Contentful Paint, First Meaningful Paint"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Mga Pagpapahusay sa First Paint"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Maaaring mapabilis ng mga pag-optimize na ito ang pag-load ng iyong page."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Mga Pagkakataon"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Mga Sukatan"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Pagandahin ang pangkalahatang karanasan sa pag-load para bumilis ang pagtugon ng page at magamit ito kaagad. Mahahalagang sukatan: Time to Interactive, Speed Index"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Mga Pangkalahatang Pagpapahusay"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performance"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL ng Cache"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Laki (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Oras na Ginugol"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Maaaring Matipid (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Maaaring Matipid (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Maaaring makatipid ng {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Maaaring makatipid ng {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Ipakita ang mga pag-audit"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Unang Navigation"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximum na latency ng critical path:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Nagka-error!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Error sa ulat: walang impormasyon sa pag-audit"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Data ng Lab"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Ang pagsusuri ng [Lighthouse](https://developers.google.com/web/tools/lighthouse/) sa kasalukuyang page sa ginayang 3G. Tinatantya at maaaring mag-iba ang mga value."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Mga karagdagang item na manual na susuriin"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Hindi naaangkop"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Pagkakataon"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Tinatayang Matitipid"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Mga pumasang pag-audit"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Sukatan ng marka:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"May mga isyung nakakaapekto sa pagpapatakbong ito ng Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Tinataya lang at maaaring mag-iba ang mga value."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Mga Babala: "}};
-
-
-},{}],51:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Les extensions Chrome ont eu un impact négatif sur les performances de chargement de la page. Essayez de contrôler la page en mode navigation privée ou depuis un profil Chrome sans extensions."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Évaluation des scripts"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Analyse des scripts"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Envisagez de réduire le temps consacré à l'analyse, la compilation et l'exécution de JS. La livraison de charges utiles JS plus petites peut vous aider. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Réduisez le temps d'exécution de JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Délai d'exécution de JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Les grandes images GIF sont inefficaces pour diffuser du contenu animé. Envisagez d'utiliser des vidéos MPEG4/WebM pour les animations et PNG/WebP pour les images statiques au lieu d'images GIF afin d'économiser des octets réseau. [En savoir plus](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Utilisez des formats vidéo pour le contenu animé"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Envisagez de charger des images masquées ou hors écran après le chargement de toutes les ressources essentielles afin de réduire le délai avant interactivité. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Différez le chargement des images hors écran"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Des ressources bloquent la première visualisation (first paint) de votre page. Envisagez de diffuser des feuilles JS/CSS essentielles en ligne et de différer la diffusion de toutes les feuilles JS/de style non essentielles. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Éliminez les ressources qui bloquent le rendu"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Les charges utiles des grands réseaux coûtent de l'argent réel aux utilisateurs et sont fortement corrélées aux délais de chargement interminables. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"La taille totale était de {totalBytes, number, bytes} Ko"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Évitez d'énormes charges utiles de réseau"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Éviter d'énormes charges utiles de réseau"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"La réduction des fichiers CSS peut réduire la taille des charges utiles de réseau. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Réduisez la taille des ressources CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"La minimisation des fichiers JavaScript peut réduire la taille des charges utiles et la durée d'analyse des scripts. [En savoir plus](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Réduisez la taille des ressources JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Supprimez les règles inutilisées des feuilles de style afin de réduire la quantité d'octets utilisés inutilement par l'activité réseau. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Différez le chargement des ressources CSS inutilisées"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Supprimez les ressources JavaScript inutilisées pour réduire la quantité d'octets consommés par l'activité réseau."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Supprimez les ressources JavaScript inutilisées"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Une longue durée de vie du cache peut accélérer les visites répétées sur votre page. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ressource trouvée}one{# ressource trouvée}other{# ressources trouvées}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Diffusez des éléments statiques grâce à des règles de cache efficaces"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Utiliser des règles de cache efficaces sur les éléments statiques"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Les images optimisées se chargent plus rapidement et consomment moins de données mobiles. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Encodez les images de manière efficace"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Diffusez des images de taille appropriée afin d'économiser des données mobiles et réduire le temps de chargement. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Dimensionnez correctement les images"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Les ressources textuelles doivent être diffusées compressées (Gzip, Deflate ou Brotli) pour réduire le nombre total d'octets du réseau. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Activez la compression de texte"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Les formats d'image comme JPEG 2000, JPEG XR et WebP proposent souvent une meilleure compression que les formats PNG ou JPEG. Par conséquent, les téléchargements sont plus rapides et la consommation de données est réduite. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Diffusez des images aux formats nouvelle génération"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Les Chaînes de demandes critiques ci-dessous vous montrent quelles ressources sont chargées avec une priorité élevée. Envisagez de réduire la longueur des chaînes et la taille de téléchargement des ressources ou de reporter le téléchargement de ressources inutiles afin d'améliorer le chargement des pages. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 chaîne trouvée}one{# chaîne trouvée}other{# chaînes trouvées}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Réduisez la profondeur des demandes critiques"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Les ingénieurs en navigation recommandent que les pages contiennent moins de 1 500 nœuds de DOM environ. La zone d'écoute idéale est une profondeur d'arborescence inférieure à 32 éléments et contenant moins de 60 éléments enfant/parent. Un grand DOM peut accroître l'utilisation de la mémoire, entraîner de plus longs [calculs de style](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) et des [redispositions] coûteuses (https://developers.google.com/speed/articles/reflow). [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nœud}one{# nœud}other{# nœuds}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Évitez une taille excessive de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Profondeur maximum de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total des nœuds de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Éviter une taille excessive de DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Utilisez la fonction d'affichage de la police CSS afin que le texte soit visible par l'utilisateur pendant le chargement des polices Web. [En savoir plus](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Assurez-vous que le texte reste visible pendant le chargement des polices Web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"La totalité du texte reste visible pendant le chargement des polices Web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Catégorie"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Envisagez de réduire le temps consacré à l'analyse, la compilation et l'exécution de JavaScript. La livraison de charges utiles JavaScript plus petites peut vous aider."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Réduisez le travail du thread principal"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Réduire le travail du thread principal"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Le score ci-dessus est une estimation du temps en millisecondes que prend votre application pour réagir à l'intervention de l'utilisateur, pendant la fenêtre de pointe de 5 s de chargement de page. Si le temps de latence est supérieur à 50 ms, les utilisateurs peuvent percevoir votre application comme étant lente. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Estimation du temps de latence avant intervention"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"La statistique \"first contentful paint\" indique le moment où le premier texte ou la première image sont affichés. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"First Contentful Paint"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"La statistique \"Premier processeur inactif\" marque la première fois que le thread principal de la page est suffisamment silencieux pour gérer l'entrée. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Premier processeur inactif"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"La statistique \"Premier passage significatif\" mesure quand le contenu principal d'une page est visible. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Premier passage significatif"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"La statistique \"Temps avant interactivité\" indique quand la page est entièrement interactive. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Délai avant interactivité"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"L'indice de vitesse indique la rapidité avec laquelle le contenu d'une page est disponible. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indice de vitesse"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Les redirections entraînent des retards supplémentaires avant que la page ne puisse être chargée. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Évitez les redirections de page multiples"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"La valeur \"Délai avant premier octet\" (Time To First Byte) identifie l'heure à laquelle votre serveur envoie une réponse. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Le document racine a pris {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Réduisez les délais de réponse du serveur (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Les délais de réponse du serveur sont faibles (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Durée"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nom"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Heure de début"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Type"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Envisagez de doter votre application de l'API User Timing pour mesurer les performances réelles de votre application lors d'expériences utilisateur clés. [En savoir plus](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{[=1]1 temps utilisateur}one{# temps utilisateur}other{# temps utilisateur}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Marques et mesures du temps utilisateur"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Envisagez d'ajouter des indices de ressources de préconnexion ou dns-prefetch pour établir les premières connexions avec des origines tierces importantes. [En savoir plus](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Connectez-vous à l'avance aux origines souhaitées"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Envisagez d'utiliser <link rel=preload> pour hiérarchiser la récupération des ressources actuellement requises pour le chargement ultérieur de la page. [En savoir plus](https://developers.google.com/web/ntools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Préchargez les demandes clés"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Plus d'informations sur les performances de votre application."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostics"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"L'aspect le plus essentiel des performances est la rapidité avec laquelle les pixels sont affichés à l'écran. Statistiques clés : First Contentful Paint, First Meaningful Paint"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Amélioration de First Paint"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Ces optimisations peuvent accélérer le chargement de votre page."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Opportunités"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Statistiques"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Améliorez l'expérience globale de chargement, afin que la page soit réactive et disponible dès que possible. Statistiques clés : délai avant interactivité, indice de vitesse"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Améliorations générales"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performances"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache de la valeur TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Taille (Ko)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Temps passé"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Économies potentielles (Ko)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Économies potentielles (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Économies potentielles de {wastedBytes, number, bytes} Ko"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Économies potentielles de {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Afficher les audits"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navigation initiale"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latence de chemin d'accès critique maximale :"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Erreur"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Erreur de rapport : pas d'information d'audit"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Données de test"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analyse [Lighthouse](https://developers.google.com/web/tools/lighthouse/) de la page actuelle sur 3G émulée. Les valeurs sont des estimations et peuvent varier."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Autres éléments à vérifier manuellement"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Non applicable"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Opportunité"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Estimation des économies"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Audits réussis"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Échelle de score :"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Cette exécution de Lighthouse a rencontré des problèmes :"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Les valeurs sont estimées et peuvent varier."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Avertissements : "}};
-
-
-},{}],52:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"תוספים ל-Chrome השפיעו לרעה על ביצועי הטעינה של הדף הזה. כדאי לבדוק את הדף במצב גלישה בסתר או באמצעות פרופיל Chrome שאינו כולל תוספים."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"הערכת סקריפט"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"ניתוח סקריפט"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"סה\"כ"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"כדאי לשקול את האפשרות לקצר את הזמן הדרוש לניתוח, הידור וביצוע JS. לשם כך כדאי להשתמש במטענים ייעודיים (payload) קטנים יותר של JS. [מידע נוסף] (https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"יש לקצר את זמן הביצוע של JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"זמן ביצוע של JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"קובצי GIF גדולים לא מעבירים תוכן אנימציה בצורה יעילה. כדי לצמצם את מספר הבייטים שמועברים ברשת, במקום קובצי GIF כדאי לשקול את האפשרות להשתמש בסרטוני MPEG4/WebM בשביל אנימציות ובקובצי PNG/WebP בשביל תמונות סטטיות. [מידע נוסף](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"יש להשתמש בפורמטים של וידאו כדי להציג תוכן אנימציה"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"כדי לקצר את הזמן עד לאינטראקטיביות (Time to Interactive) כדאי לשקול את האפשרות לבצע טעינה הדרגתית של תוכן שאינו מופיע במסך ושל תמונות מוסתרות, אחרי שכל המשאבים הקריטיים סיימו להיטען. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"יש לעכב טעינה של תמונות שאינן מופיעות במסך"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"משאבים חוסמים את העיבוד הראשון (First Paint) בדף. כדאי לשקול את האפשרות לספק תוכן JS/CSS קריטי באופן מוטבע ולעכב את כל תוכן ה-JS/סגנונות שאינם קריטיים. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"יש להימנע ממשאבים שחוסמים עיבוד"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"מטענים ייעודיים (payload) בנפח גדול המועברים ברשת עולים למשתמשים כסף ולרוב מאריכים את זמני הטעינה. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"הגודל הכולל היה {totalBytes, number, bytes} ‏KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"יש להימנע מהעברה של מטענים ייעודיים ענקיים (payload) ברשת"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"נמנע מהעברה של מטענים ייעודיים ענקיים (payload) ברשת"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"הקטנת קובצי CSS יכולה לצמצם את הגודל של מטענים ייעודיים (payload) שמועברים ברשת. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"יש להקטין קובצי CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"הקטנת קובצי JavaScript יכולה לצמצם את המטען הייעודי (payload) ולקצר את משך הזמן הנדרש לניתוח סקריפט. [מידע נוסף](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"יש לקצר את קוד JavaScript למינימום ההכרחי"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"כדי לצמצם צריכה לא נחוצה של בייטים בפעילות ברשת, יש להסיר מגיליונות סגנון כללים שאינם בשימוש. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"יש לעכב טעינה של CSS שאינו בשימוש"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"יש להסיר JavaScript שאינו בשימוש כדי לצמצם צריכת בייטים על-ידי פעילות ברשת."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"יש להסיר JavaScript שאינו בשימוש"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"משך חיים ארוך של מטמון יכול לזרז את הביקורים החוזרים בדף. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{נמצא משאב אחד}two{נמצאו # משאבים}many{נמצאו # משאבים}other{נמצאו # משאבים}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"יש להציג נכסים סטטיים בעזרת מדיניות מטמון יעילה"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"יש להשתמש במדיניות מטמון יעילה בנכסים סטטיים"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"תמונות שעברו אופטימיזציה נטענות מהר יותר וצורכות פחות נתונים בחבילת הגלישה. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"יש לקודד תמונות בצורה יעילה"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"הצגת תמונות שהגודל שלהן הוגדר בצורה נכונה חוסכת צריכת נתונים בחבילת הגלישה ומקצרת את זמן הטעינה. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"יש להגדיר את גודל התמונות בצורה נכונה"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"הצגת משאבים המבוססים על טקסט צריכה להתבצע עם דחיסה (gzip‏, deflate או brotli) כדי לצמצם את סך הבייטים שמועברים ברשת. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"יש להפעיל דחיסת טקסט"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"לעתים קרובות, פורמטים של תמונות כמו JPEG 2000‏, JPEG XR ו-WebP מספקים דחיסה טובה יותר מאשר PNG או JPEG. שימוש בפורמטים האלה מקצר את זמן ההורדות ומצמצם את צריכת הנתונים. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"יש להציג תמונות בפורמטים עדכניים"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"בקטע 'שרשראות בקשה קריטיות' שבהמשך מוצגים המשאבים שנטענים עם עדיפות גבוהה. כדי לשפר את מהירות טעינת הדף, מומלץ לקצר את השרשראות, להקטין את גודל ההורדה של משאבים או לעכב את ההורדה של משאבים לא נחוצים. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{נמצאה שרשרת אחת}two{נמצאו # שרשראות}many{נמצאו # שרשראות}other{נמצאו # שרשראות}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"יש לצמצם את העומק של בקשות קריטיות"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"מפתחי דפדפנים ממליצים שדפים יכילו פחות מכ-1,500 צומתי DOM. המצב האופטימלי הוא עץ בעומק של פחות מ-32 אלמנטים ופחות מ-60 אלמנטים ברמת צאצא/אב. DOM גדול יכול להגדיל את צריכת הזיכרון, להאריך [חישובי סגנון](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) ולגרום לזרימות חוזרות של פריסה שצורכות נתונים רבים [layout reflows](https://developers.google.com/speed/articles/reflow). [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{צומת אחד}two{# צמתים}many{# צמתים}other{# צמתים}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"יש להימנע מ-DOM גדול מדי"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"עומק DOM מרבי"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"המספר הכולל של צומתי DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"נמנע מ-DOM גדול מדי"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"שימוש בתכונת תצוגת הגופן של CSS מבטיח שהטקסט מוצג למשתמש בזמן טעינה של webfonts. [מידע נוסף](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"יש לוודא שטקסט ממשיך להופיע במהלך טעינת webfont"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"כל הטקסט ממשיך להופיע במהלך טעינות של webfont"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"קטגוריה"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"כדאי לשקול את האפשרות לקצר את הזמן הדרוש לניתוח, הידור וביצוע JS. לשם כך כדאי להשתמש במטענים ייעודיים (payload) קטנים יותר של JS."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"צריך לצמצם את העבודה על התהליכון הראשי"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"מצמצם את העבודה על התהליכון הראשי"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"הערך שלמעלה הוא אומדן של משך הזמן הנדרש לאפליקציה כדי להגיב לקלט של משתמש. הערך מצוין באלפיות שנייה ומתייחס ל-5 השניות העמוסות ביותר בטעינת דף. אם זמן האחזור ארוך מ-50 אלפיות שנייה, המשתמשים עלולים להגיע למסקנה שהאפליקציה איטית. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"אומדן זמן האחזור של קלט"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"המדד 'הצגת תוכן ראשוני' (FCP) מציין את הזמן שבו הטקסט או התמונה הראשונים מוצגים. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"הצגת התוכן הראשוני"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"הערך 'מצב ראשון של חוסר פעילות ב-CPU' ‏(First CPU Idle) מציין את הפעם הראשונה שבה התהליכון הראשי של הדף פנוי מספיק בשביל להגיב לקלט. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"מצב ראשון של חוסר פעילות ב-CPU"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"הערך 'הצגת התוכן העיקרי' מציין מתי התוכן העיקרי של הדף מוצג. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"הצגת התוכן העיקרי"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"'אינטראקטיבי' מציין את הזמן שבו הדף הופך להיות לגמרי אינטראקטיבי. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"זמן עד לאינטראקטיביות"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"מדד המהירות (Speed Index) מראה באיזו מהירות מתמלא התוכן המוצג בדף. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"מדד מהירות (Speed Index)"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"הפניות אוטומטיות מוסיפות עיכובים לטעינת הדף. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"יש להימנע מהפניות אוטומטיות מרובות"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"'זמן עד בייט ראשון' (Time To First Byte) הוא פרק הזמן שחולף עד שהשרת שולח תגובה. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"טעינת מסמך השורש ארכה {timeInMs, number, milliseconds} אלפיות שנייה"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"יש לקצר את זמני התגובה של השרת (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"זמני התגובה של השרת ארוכים (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"משך זמן"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"שם"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"שעת התחלה"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"סוג"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"כדי למדוד את ביצועי האפליקציה בפועל במהלך חוויות משתמש חשובות, מומלץ להוסיף לאפליקציה את User Timing API. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{תזמון משתמש אחד}two{# תזמוני משתמש}many{# תזמוני משתמש}other{# תזמוני משתמש}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"סימונים ומדידות של User Timing"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"כדאי לשקול את האפשרות להוסיף את רמזי המשאבים preconnect או dns-prefetch כדי ליצור מראש קישורים אל מקורות חשובים של צד שלישי. [מידע נוסף](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"יש להתחבר מראש למקורות נדרשים"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"כדאי לשקול את האפשרות להשתמש ב-<link rel=preload> כדי לקבוע את סדר העדיפויות של אחזור משאבים שנדרשים בשלב מאוחר יותר של טעינת הדף. [מידע נוסף](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"יש לטעון מראש בקשות עיקריות"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"מידע נוסף לגבי ביצועי האפליקציה."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"ניתוחים"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"היבט הביצועים הקריטי ביותר הוא מהירות העיבוד של פיקסלים במסך. ערכי מפתח: הצגת התוכן הראשוני, הצגת התוכן העיקרי"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"שיפורים בעיבוד ראשון"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"האופטימיזציות האלה יכולות לקצר את זמני טעינת הדף."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"הזדמנויות"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"ערכים"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"צריך לשפר את חוויית הטעינה הכללית, כך שהדף יגיב ויהיה מוכן לשימוש במהירות האפשרית. ערכי מפתח: זמן עד לאינטראקטיביות (Time to Interactive), מדד מהירות (Speed Index)"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"סך השיפורים"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"ביצועים"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"אורך חיים (TTL) של מטמון"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"גודל (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"משך הזמן שנדרש"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"כתובת אתר"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"חיסכון פוטנציאלי (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"פוטנציאל חיסכון (אלפיות שנייה)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"חיסכון פוטנציאלי של {wastedBytes, number, bytes} ‏KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"חיסכון פוטנציאלי של {wastedMs, number, milliseconds} אלפיות שנייה"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} אלפיות שנייה"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} שניות"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"הצגת בדיקות"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"ניווט התחלתי"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"זמן אחזור מקסימלי של נתיב קריטי:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"שגיאה!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"שגיאה בדוח: אין מידע על הבדיקה"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"נתוני בדיקה"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"ניתוח הדף הנוכחי בהדמיית 3G באמצעות [Lighthouse]‏(https://developers.google.com/web/tools/lighthouse/). הערכים הם אומדנים, והם עשויים להשתנות."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"פריטים נוספים שיש לבדוק באופן ידני"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"לא רלוונטי"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"הזדמנות"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"אומדן חיסכון"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"בדיקות עם ציון 'עובר'"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"סולם תוצאות:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"היו בעיות שהשפיעו על ההרצה הזו של Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"הערכים מהווים אומדן והם עשויים להשתנות."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"אזהרות: "}};
-
-
-},{}],53:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome एक्सटेंशन ने इस पेज के लोड परफ़ॉर्मेंस पर नकारात्मक रूप से असर डाला है. 'गुप्त मोड' में या बिना किसी एक्सटेंशन के Chrome प्रोफ़ाइल से पेज ऑडिट करके देखें."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"स्क्रिप्ट मूल्यांकन"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"स्क्रिप्ट पार्स"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"कुल"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"JS को पार्स करने, कंपाइल करने और एक्ज़ीक्यूट करने में लगने वाला समय कम करने पर विचार करें. आप पाएंगे कि इसके ज़रिए छोटे-छोटे JS पेलोड डिलीवर करने में मदद मिलती है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"JavaScript क्रियान्वयन समय कम करें"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript क्रियान्वयन समय"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"बड़े जीआईएफ़ ऐनिमेटेड सामग्री डिलीवर करने में नाकाफ़ी होते हैं. नेटवर्क बाइट बचाने के इरादे से जीआईएफ़ का इस्तेमाल करने के बजाय, ऐनिमेशन के लिए MPEG4/WebM वीडियो और स्थिर इमेज के लिए PNG/WebP का इस्तेमाल करने पर विचार करें. [ज़्यादा जानें](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"ऐनिमेट की गई सामग्री के लिए वीडियो फ़ॉर्मेट का इस्तेमाल करें"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"इंटरेक्टिव में लगने वाला समय कम करने के लिए, सभी अहम संसाधन लोड हो जाने के बाद ऑफ़स्क्रीन और छिपी हुई इमेज को धीरे-धीरे लोड करने पर विचार करें. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"ऑफ़स्क्रीन इमेज टालें"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"संसाधन आपके पेज के पहले पेंट को ब्लॉक कर रहे हैं. अहम JS/CSS इनलाइन वितरित करने और सभी गैर-अहम JS/शैलियों को टालने पर विचार करें. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"रेंडर ब्लॉक करने वाले संसाधनों को खत्म करें"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"बड़े नेटवर्क वाले पेलोड के लिए उपयोगकर्ताओं को ज़्यादा रकम खर्च करनी पड़ती है और उन पर लोड होने में ज़्यादा समय भी लगता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"कुल आकार {totalBytes, number, bytes} केबी था"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"बहुत ज़्यादा नेटवर्क पेलोड से बचें"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"भारी नेटवर्क पेलोड से बचाता है"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS फ़ाइलों का आकार कम करने से नेटवर्क पेलोड आकार कम किए जा सकते हैं. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSS कम करें"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"JavaScript फ़ाइलों को छोटा करने से पेलोड का आकार और स्क्रिप्ट पार्स करने का समय कम हो सकता है. [ज़्यादा जानें](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScript का आकार कम करें"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"नेटवर्क गतिविधि में खर्च होने वाले गैर-ज़रूरी बाइट कम करने के लिए स्टाइल-शीट से इस्तेमाल नहीं किए गए नियमों को हटाएं. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"इस्तेमाल नहीं किए गए CSS को टालें"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"नेटवर्क गतिविधि में खर्च होने वाले बाइट में कमी करने के लिए इस्तेमाल नहीं किया गया JavaScript हटाएं."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"इस्तेमाल नहीं किया गया JavaScript हटाएं"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"लंबे कैश लाइफ़टाइम से आपके पेज पर दोहराए जाने वाले विज़िट की गति बढ़ सकती है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 संसाधन मिला}one{# संसाधन मिले}other{# संसाधन मिले}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"कुशल कैश नीति के साथ स्थिर एसेट ऑफ़र करें"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"स्थिर एसेट पर कुशल कैश नीति का इस्तेमाल करता है"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"ऑप्टिमाइज़ की गई इमेज तेज़ी से लोड होती हैं और इसमें कम सेल्युलर डेटा खर्च होता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"इमेज को कुशलता से एन्कोड करें"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"ऐसी इमेज ऑफ़र करें जिनका आकार सही हो ताकि सेल्युलर डेटा बचाया जा सके और लोड समय को बेहतर बनाया जा सके. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"सही तरीके के आकार वाली इमेज"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"कुल नेटवर्क बाइट को कम से कम करने के लिए, लेख आधारित संसाधन कंप्रेशन (gzip, deflate या brotli) के साथ ऑफ़र किए जाने चाहिए. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"लेख कंप्रेशन चालू करें"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000, JPEG XR और WebP जैसे इमेज फ़ॉर्मेट में अक्सर PNG या JPEG के मुकाबले बेहतर कंप्रेशन मिलता है, जिसका मतलब है कि डाउनलोड तेज़ी से होते हैं और इनमें कम डेटा खर्च होता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"इमेज अगली जेनरेशन के फ़ॉर्मेट में ऑफ़र करें"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"नीचे दी गई अहम अनुरोध शृंखलाएं आपको वे संसाधन दिखाती हैं जो उच्च प्राथमिकता से भरपूर हैं. शृंखलाओं की अवधि कम करने पर विचार करें, जिससे संसाधनों का डाउनलोड आकार कम हो जाएगा या पेज लोड को बेहतर बनाने के लिए गैर-ज़रूरी संसाधनों का डाउनलोड टल जाएगा. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 शृंखला मिली}one{# शृंखलाएं मिलीं}other{# शृंखलाएं मिलीं}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"अहम अनुरोधों की गहराई कम से कम करें"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"ब्राउज़र इंजीनियर सुझाव देते हैं कि पेज में ~1,500 से कम DOM नोड होने चाहिए. सबसे सही आंकड़ा है < 32 एलीमेंट वाली ट्री गहराई और 60 से कम चिल्ड्रन/पेरेंट एलीमेंट. ज़्यादा बड़े DOM से मेमोरी का इस्तेमाल बढ़ सकता है, जिससे ज़्यादा लंबे [स्टाइल कैल्युलेशन](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) हो सकते हैं और इनसे महंगे [लेआउट रीफ़्लो](https://developers.google.com/speed/articles/reflow) बन सकते हैं. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 नोड}one{# नोड}other{# नोड}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"बहुत ज़्यादा बड़े DOM आकार से बचें"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"सबसे ज़्यादा DOM गहराई"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"कुल DOM नोड"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"बहुत ज़्यादा बड़े DOM आकार से बचता है"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"यह पक्का करने के लिए फ़ॉन्ट-डिसप्ले CSS फ़ीचर का फ़ायदा उठाएं कि वेबफ़ॉन्ट लोड होने के दौरान उपयोगकर्ता को लेख दिखाई देता रहे. [ज़्यादा जानें](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"पक्का करें कि वेबफ़ॉन्ट लोड होने के दौरान लेख दिखाई देता रहे"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"वेबफ़ॉन्ट लोड होने के दौरान सभी लेख दिखाई देते रहते हैं"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"श्रेणी"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"JS को पार्स करने, कंपाइल करने और एक्ज़ीक्यूट करने में लगने वाला समय कम करने पर विचार करें. आप देखेंगे कि इसके ज़रिए छोटे-छोटे JS पेलोड डिलीवर करने में मदद मिलती है."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"मुख्य थ्रेड के काम को कम करना"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"मुख्य थ्रेड के काम को कम करता है"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"ऊपर दिया गया स्कोर एक अनुमान है कि पेज लोड होने की सबसे व्यस्त 5 सेकंड की विंडो में आपके ऐप्लिकेशन को उपयोगकर्ता इनपुट का जवाब देने में, मिलीसेकंड में कितना समय लगेगा. अगर आपकी प्रतीक्षा अवधि 60 मिलीसेकंड से ज़्यादा है, तो उपयोगकर्ता आपके ऐप्लिकेशन को धीमा मान सकते हैं. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"अनुमानित इनपुट प्रतीक्षा समय"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"फ़र्स्ट कॉन्टेंटफ़ुल पेंट वह समय चिह्नित करता है जब पहले लेख या इमेज को पेंट किया गया हो. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"उपयोगी सामग्री वाला पहला पेंट"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"इस्तेमाल में नहीं पहला सीपीयू (CPU), वह पहला समय चिह्नित करता है जब पेज का मुख्य थ्रेड इनपुट को संभालने के लिए काफ़ी होता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"पहला सीपीयू (CPU) इस्तेमाल में नहीं"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"पहला सार्थक पेंट उस समय का मापन करता है जब किसी पेज की शुरुआती सामग्री दिखाई देती है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"पहला सार्थक पेंट"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"इंटरेक्टिव वह समय चिह्नित करता है जब पेज पूरी तरह इंटरेक्टिव हो जाता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"इंटरएक्टिव में लगने वाला समय"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"गति इंडेक्स दिखाता है कि किसी पेज की सामग्री विज़ुअल रूप से कितनी तेज़ी से पॉपुलेट होती हैं. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"गति इंडेक्स"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"'रीडायरेक्ट' पेज लोड किए जाने से पहले और ज़्यादा प्रतीक्षा जोड़ता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"एक से ज़्यादा पेज रीडायरेक्ट करने से बचें"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"पहली बाइट का समय, उस समय की पहचान करता है जब आपका सर्वर कोई जवाब भेजता है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"रूट दस्तावेज़ को {timeInMs, number, milliseconds} मिलीसेकंड लगे"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"सर्वर प्रतिक्रिया समय घटाएं (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"सर्वर के जवाब देने के समय धीमे हैं (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"कुल समय"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"नाम"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"शुरुआत का समय"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"प्रकार"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"प्रमुख उपयोगकर्ता अनुभवों के दौरान, असली दुनिया के माप तैयार करने के लिए अपने ऐप्लिकेशन को 'उपयोगकर्ता समय API (एपीआई)' के ज़रिए तैयार करने पर विचार करें. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 उपयोगकर्ता समय}one{# उपयोगकर्ता समय}other{# उपयोगकर्ता समय}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"उपयोगकर्ता समय अंक और मापन"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"तीसरे पक्ष के अहम मूल से जल्दी कनेक्शन बनाने के लिए प्री-कनेक्ट या dns-प्रीफ़ेच संसाधन संकेत जोड़ने पर विचार करें. [ज़्यादा जानें](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"ज़रूरी मूल से प्री-कनेक्ट करें"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"ऐसे संसाधन फ़ेच करने को प्राथमिकता देने के लिए <link rel=preload> का इस्तेमाल करने पर विचार करें जिनका फ़िलहाल पेज लोड में बाद में अनुरोध किया गया है. [ज़्यादा जानें](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"प्रमुख अनुरोधों को पहले से लोड करें"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"आपके ऐप्लिकेशन के परफ़ॉर्मेंस के बारे में ज़्यादा जानकारी."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"निदान"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"परफ़ॉर्मेंस का सबसे अहम पहलू यह है कि स्क्रीन पर पिक्सेल कितनी तेज़ी से रेंडर होते हैं. प्रमुख मेट्रिक: उपयोगी सामग्री वाला पहला पेंट, पहला उपयोगी पेंट"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"पहले पेंट के सुधार"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"इन ऑप्टिमाइज़ेशन से आपका पेज लोड होने की गति बढ़ सकती है."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"अवसर"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"मेट्रिक"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"पूरे लोडिंग अनुभव को बेहतर बनाएं ताकि पेज जवाब दे और जल्दी से जल्दी इस्तेमाल के लिए तैयार हो जाए. प्रमुख मेट्रिक: इंटरेक्टिव में लगने वाला समय, गति इंडेक्स"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"समस्त सुधार"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"परफ़ॉर्मेंस"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"कैश TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"आकार (केबी)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"बिताया गया समय"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"यूआरएल"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"हो सकने वाली बचत (केबी)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"हो सकने वाली बचत (‍मिली सेकंड)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"{wastedBytes, number, bytes} केबी की हो सकने वाली बचत"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"{wastedMs, number, milliseconds} मिलीसेकंड की हो सकने वाली बचत"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} मिलीसेकंड"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} सेकंड"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"ऑडिट दिखाएं"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"शुरुआती नेविगेशन"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"पाथ का ज़्यादा से ज़्यादा अहम प्रतीक्षा समय:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"गड़बड़ी!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"गड़बड़ी की रिपोर्ट करें: कोई ऑडिट जानकारी नहीं"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"किसी नई या दुबारा जाँची जाने वाली ऐप्लिकेशन के लिए तैयार किया गया डेटा"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"एम्युलेट किए गए 3G पर मौजूदा पेज का [लाइटहाउस](https://developers.google.com/web/tools/lighthouse/) विश्लेषण. मान अनुमानित हैं और इनमें अंतर हो सकता है."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"मैन्युअल रूप से देखे जाने वाले और ज़्यादा आइटम"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"लागू नहीं"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"अवसर"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"अनुमानित बचत"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"पास हुए ऑडिट"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"स्कोर स्केल:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"कुछ समस्याएं आने के कारण Lighthouse के इस रन पर असर पड़ा है:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"मान अनुमानित हैं और इनमें अंतर हो सकता है."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"चेतावनियां: "}};
-
-
-},{}],54:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chromeova proširenja negativno su utjecala na izvedbu učitavanja ove stranice. Pokušajte pregledati stranicu anonimno ili putem Chromeovog profila bez proširenja."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Procjena skripte"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Raščlamba skripte"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Ukupno"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Savjetujemo vam da skratite vrijeme potrebno za raščlambu, kompiliranje i izvršavanje JS-a. Isporuka manjih JS-ova mogla bi vam pomoći da to postignete. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Skratite vrijeme izvršavanja JavaScripta"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Vrijeme izvršavanja JavaScripta"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Veliki GIF-ovi nisu učinkoviti za isporuku animiranog sadržaja. Savjetujemo vam da umjesto GIF-a upotrebljavate MPEG4/WebM videozapise za animacije i PNG/WebP za statične slike da biste smanjili količinu mrežnih bajtova. [Saznajte više](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Upotrebljavajte formate videozapisa za animirani sadržaj"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Za slike izvan zaslona i skrivene slike savjetujemo odgođeno učitavanje nakon što se učitaju svi kritični resursi da biste skratili vrijeme do interaktivnosti. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Odgodite slike izvan zaslona"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resursi blokiraju prvo bojenje stranice. Savjetujemo vam da kritičan JS/CSS isporučite umetnuto i da odgodite sve nekritične JS-ove/stilove. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Uklonite resurse koji blokiraju generiranje"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Veliki mrežni resursi korisnicima uzrokuju stvarne novčane troškove i usko koreliraju s dugim vremenom učitavanja. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Ukupna veličina bila je {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Izbjegavajte ogromne mrežne resurse"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Izbjegava ogromne mrežne resurse"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Umanjenjem CSS datoteka mogu se smanjiti veličine mrežnih resursa. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Umanjite CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Umanjenjem JavaScript datoteka mogu se smanjiti veličine resursa i skratiti vrijeme raščlambe skripte. [Saznajte više](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Umanjite JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Iz stilskih tablica uklonite nekorištena pravila da biste smanjili nepotrebnu potrošnju bajtova u mrežnoj aktivnosti. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Odgodite nekorišteni CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Uklonite JavaScript koji se ne koristi da biste smanjili potrošnju bajtova u mrežnoj aktivnosti."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Uklonite nekorišteni JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Dugotrajno predmemoriranje može ubrzati ponovljene posjete vašoj stranici. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Pronađen je jedan resurs}one{Pronađen je # resurs}few{Pronađena su # resursa}other{Pronađeno je # resursa}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Poslužite statične elemente s pravilima učinkovitog predmemoriranja"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Upotrebljava pravila učinkovitog predmemoriranja za statične elemente"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimizirane slike učitavaju se brže i troše manje mobilnih podataka. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Kodirajte slike učinkovito"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Poslužite slike prikladnih veličina da biste uštedjeli mobilne podatke i poboljšali vrijeme učitavanja. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Postavite slike u odgovarajućoj veličini"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Tekstualni resursi trebaju se posluživati s kompresijom (gzip, deflate ili brotli) radi minimiziranja ukupne količine mrežnih bajtova. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Omogućite sažimanje teksta"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formati slike kao što su JPEG 2000, JPEG XR i WebP često pružaju bolje sažimanje nego PNG ili JPEG, što znači brža preuzimanja i manju potrošnju podataka. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Poslužite slike u modernim formatima"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Lanci kritičkih zahtjeva u nastavku prikazuju koji se resursi učitavaju s visokim prioritetom. Savjetujemo vam da skratite duljinu lanaca, smanjite veličinu resursa za preuzimanje ili odgodite preuzimanje resursa koji nisu nužni kako biste poboljšali učitavanje stranice. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Pronađen je jedan lanac}one{Pronađen je # lanac}few{Pronađena su # lanca}other{Pronađeno je # lanaca}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimizirajte dubinu kritičnih zahtjeva"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Inženjeri preglednika preporučuju da stranice sadrže manje od ~1500 čvorova DOM-a. Idealno je da je dubina stabla manja od 32 elementa i da ima manje od 60 elemenata podređenih/nadređenih jedinica. Veliki DOM može pojačati upotrebu memorije, uzrokovati dulje [izračune stilova](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) i proizvesti zahtjevna [preoblikovanja izgleda](https://developers.google.com/speed/articles/reflow). [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{Jedan čvor}one{# čvor}few{# čvora}other{# čvorova}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Izbjegavajte pretjeranu veličinu DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimalna dubina DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Ukupan broj čvorova DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Izbjegava pretjeranu veličinu DOM-a"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Iskoristite CSS značajku za prikaz fontova kako bi tekst bio vidljiv korisnicima dok se web-fontovi učitavaju. [Saznajte više](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Neka tekst ostaje vidljiv tijekom učitavanja web-fontova"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Sav tekst ostaje vidljiv tijekom učitavanja web-fontova"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorija"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Savjetujemo vam da skratite vrijeme potrebno za raščlambu, kompiliranje i izvršavanje JS-a. Isporuka manjih JS-ova mogla bi vam pomoći da to postignete."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimizirajte rad glavne niti"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimizira rad glavne niti"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Prethodni je rezultat procjena vremena koje je potrebno da vaša aplikacija reagira na korisnički unos, u milisekundama, tijekom najintenzivnijih pet sekundi učitavanja stranice. Ako je latencija viša od 50 ms, korisnici mogu doživjeti vašu aplikaciju kao usporenu. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Procijenjena latencija unosa"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Prvo renderiranje sadržaja označava vrijeme renderiranja prvog teksta ili slike. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Prvo bojenje sadržaja"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Prvi procesor u mirovanju označava prvi trenutak u kojem je glavna nit stranice dovoljno neopterećena da bi obradila unos. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Prvi procesor u mirovanju"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Prvo smisleno bojenje mjeri kada je vidljiv primarni sadržaj stranice. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Prvo smisleno bojenje"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktivnost označava vrijeme u kojem stranica postaje potpuno interaktivna. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Vrijeme do interaktivnosti"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Indeks brzine prikazuje koliko se brzo sadržaj stranice vidljivo popunjava. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indeks brzine"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Preusmjeravanja uvode dodatna kašnjenja prije nego što se stranica može učitati. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Izbjegavajte višestruka preusmjeravanja stranica"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Vrijeme do prvog bajta navodi vrijeme u koje poslužitelj šalje odgovor. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Za korijenski dokument bilo je potrebno {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Skratite vremena odgovora poslužitelja (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Poslužitelj odgovara sporo (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Trajanje"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Naziv"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Vrijeme početka"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Vrsta"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Savjetujemo vam da na aplikaciju primijenite API za praćenje korisničkog vremena radi mjerenja izvedbe aplikacije u stvarnom vremenu tijekom važnih korisničkih doživljaja. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{Jedno praćenje korisničkog vremena}one{# praćenje korisničkog vremena}few{# praćenja korisničkog vremena}other{# praćenja korisničkog vremena}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Oznake i izmjere Praćenja korisničkog vremena"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Savjetujemo vam da dodate nagovještaje resursa za rano povezivanje ili prethodno dohvaćanje DNS-a radi uspostavljanja ranih veza s važnim izvorima trećih strana. [Saznajte više](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Rano se povežite s potrebnim izvorima"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Savjetujemo vam da koristite <link rel=preload> da biste dali prednost dohvaćanju resursa koji se trenutačno traže kasnije u učitavanju stranice. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Unaprijed učitajte ključne zahtjeve"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Više informacija o izvedbi vaše aplikacije."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Dijagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Najkritičniji je aspekt izvedbe brzina kojom se pikseli generiraju na zaslonu. Ključni mjerni podaci: Prvo bojenje sadržaja, Prvo smisleno bojenje"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Poboljšanja prvog bojenja"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Ove optimizacije mogu ubrzati učitavanje stranice."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Prilike"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Mjerni podaci"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Poboljšajte općeniti doživljaj učitavanja tako da stranica bude responzivna i spremna za upotrebu što je prije moguće. Ključni mjerni podaci: Vrijeme do interaktivnosti, Indeks brzine"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Općenita poboljšanja"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Izvedba"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL predmemoriranja"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Veličina (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Utrošeno vrijeme"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potencijalna ušteda (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potencijalna ušteda (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potencijalna ušteda {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potencijalna ušteda {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Prikažite preglede"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Početna navigacija"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksimalna latencija kritičkog puta:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Pogreška!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Pogreška izvješća: nema podataka o pregledu"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratorijski podaci"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analiza trenutačne stranice na emuliranoj 3G mreži. Vrijednosti su procijenjene i mogu varirati."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Dodatne stavke za ručnu provjeru"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nije primjenjivo"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Prilika"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Procijenjena ušteda"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Uspješni pregledi"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Ljestvica rezultata:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Na ovo izvođenje Lighthousea utjecale su neke poteškoće:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Vrijednosti se procjenjuju i mogu se razlikovati."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Upozorenja: "}};
-
-
-},{}],55:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Egyes Chrome-bővítmények kedvezőtlenül befolyásolták az oldal betöltési teljesítményét. Próbálkozzon az oldal inkognitómódban vagy bővítmények nélküli Chrome-profilból történő ellenőrzésével."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Szkriptértékelés"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Szkriptelemzés"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Összes"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Érdemes csökkenteni a JS elemzésére, összeállítására és végrehajtására fordított időt. Ebben segítségére lehet a kisebb JS-hasznosadat-forgalom. [További információ](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Csökkentse a JavaScript végrehajtási idejét"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript végrehajtási ideje"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"A nagy méretű GIF-ek nem megfelelők az animált tartalmak megjelenítéséhez. Érdemes MPEG4/WebM formátumú videókat használni az animációkhoz, illetve a PNG/WebP formátumot a statikus képekhez a GIF-ek helyett, hiszen így csökkenteni tudja a hálózati adatforgalmat. [További információ](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)."},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Használjon videoformátumot az animált tartalmakhoz"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Vegye fontolóra a képernyőn kívüli és a rejtett képek késleltetett, a kritikus erőforrások betöltődésének végét követő betöltését, az interaktivitásig tartó idő csökkentése érdekében. [További információ](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Késleltesse a képernyőn kívüli képek betöltését"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Az erőforrások blokkolják az oldal első leképezését. Fontolja meg a kritikus JS/CSS beillesztését, továbbá az összes nem kritikus JS/stílus késleltetését. [További információ](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Távolítsa el a megjelenítést gátló erőforrásokat"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"A nagy hálózati terhelés valódi költséggel jár a felhasználóknak, és jelentősen megnöveli a betöltési időt. [További információ](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"A teljes méret {totalBytes, number, bytes} kB volt"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Kerülje a nagyon nagy hálózati hasznosadat-forgalmat"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"A nagyon nagy hálózati terhelés elkerülése"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"A CSS-fájlok minimalizálása csökkentheti a hálózati hasznosadat-forgalmat. [További információ](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minimalizálja a CSS-fájlokat"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"A JavaScript-fájlok minimalizálásával csökkenthető a hasznosadat-forgalom és a szkriptelemzési idő. [További információ](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minimalizálja a JavaScript-kódot"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Távolítsa el a nem használt szabályokat a stíluslapokból a hálózati tevékenység adatforgalmának csökkentése érdekében. [További információ](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Késleltesse a felhasználatlan CSS-t"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"A nem használt JavaScript-kód eltávolítása a hálózati tevékenység adatforgalmának csökkentéséhez."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Távolítsa el a nem használt JavaScript-kódot"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"A hosszú gyorsítótári élettartam felgyorsíthatja az oldal ismételt látogatását. [További információ](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 erőforrás található}other{# erőforrás található}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Jelenítse meg a statikus eszközöket hatékony gyorsítótár-házirend használatával"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Használjon hatékony gyorsítótár-házirendet a statikus eszközöknél"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Az optimalizált képek gyorsabban töltődnek be, és kisebb mobiladat-forgalommal járnak. [További információ](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Kódolja hatékonyan a képeket"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Használjon olyan képeket, amelyek megfelelő méretükkel elősegítik a mobiladat-forgalom csökkentését és a betöltési idő javulását. [További információ](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Méretezze megfelelően a képeket"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"A szöveges alapú erőforrásokat tömörítéssel (gzip, Deflate vagy Brotli) célszerű megjeleníteni a teljes hálózati adatforgalom minimalizálása érdekében. [További információ](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Engedélyezze a szövegtömörítést"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Az olyan képformátumok, mint a JPEG 2000, a JPEG XR és a WebP gyakran jobb tömörítést biztosítanak a PNG vagy a JPEG formátumnál, ami gyorsabb letöltést és kisebb adatforgalmat jelent. [További információ](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Jelenítse meg a képeket következő generációs formátumokban"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Az alábbi kritikuslekérdezés-láncok megmutatják, hogy milyen források töltődnek be prioritással. Az oldalbetöltés javítása érdekében fontolja meg a láncok hosszának csökkentését, a letöltött erőforrások méretének csökkentését, vagy a felesleges erőforrások letöltésének késleltetését. [További információ.](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 lánc található}other{# lánc található}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimalizálja a kritikus lekérdezések mélységét"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"A böngészőket fejlesztő mérnökök azt javasolják, hogy az oldalakon ~1500 DOM-csomópontnál kevesebb legyen. A legkedvezőbb a 32 elemnél kisebb és a 60 alárendelt/fölérendelt elemnél kisebb famélység. A nagy DOM növelheti a memóriahasználatot, és hosszabb [stílusszámítást](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), valamint költséges [elrendezés-újraszámítást](https://developers.google.com/speed/articles/reflow) eredményezhet. [További információ](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 csomópont}other{# csomópont}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Kerülje a túl nagy DOM-méretet"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximális DOM-mélység"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Összes DOM-csomópont"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Kerüli a túlzó DOM-méretet"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Használja a betűtípus-megjelenítő CSS-funkciót annak biztosításához, hogy a szöveg már a webes betűtípusok betöltődése alatt látható legyen a felhasználó számára. [További információ](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Biztosítsa, hogy a szöveg látható marad a webes betűtípusok betöltése során"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Az összes szöveg látható marad a webes betűtípusok betöltésekor"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategória"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Érdemes csökkenteni a JS elemzésére, összeállítására és végrehajtására fordított időt. Ebben segítségére lehet a kisebb JS-hasznosadat-forgalom."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimalizálja a fő szál terhelését"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimalizálja a fő szál terhelését"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"A fenti pontszám annak a becsült értéke, hogy az alkalmazás mennyi idő alatt reagál – ezredmásodpercben (ms) megadva – a felhasználói adatbevitelre az oldalbetöltés legforgalmasabb 5 másodperces időkeretében. Ha a várakozási idő meghaladja az 50 ms-ot, a felhasználók késlekedést észlelhetnek az alkalmazás használata közben. [További információ](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Becsült bemeneti késés"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Az első vizuális tartalomválasz azt az időpontot jelöli, amikor a rendszer megkezdi az első szöveg vagy kép megjelenítését. [További információ.](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Első, tartalommal rendelkező leképezés"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Az első processzor-üresjárat mutató az első olyan alkalmat jelöli, amikor az oldal főszálának aktivitása elég alacsony ahhoz, hogy kezelni lehessen a bevitt mennyiséget. [További információ](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Első processzor-üresjárat"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Az első releváns leképezés azt méri, hogy mikor válik láthatóvá az adott oldal elsődleges tartalma. [További információ](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Első releváns leképezés"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Az „Interaktív” mutató azt az időt jelzi, amíg az oldal teljesen interaktívvá nem válik. [További információ](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Interaktivitásig eltelt idő"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"A Sebességindex mutató azt jelzi, hogy az adott oldal tartalmai milyen gyorsan válnak láthatóvá. [További információ](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Sebességindex"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Az átirányítások még azelőtt eredményeznek további késéseket, hogy az oldal betöltődhetne. [További információ](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Kerülje a többszörös oldalátirányítást"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Az „első bájtig eltelt idő” mutató az Ön szervere válaszidejét jelöli. [További információ](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"A gyökérdokumentum betöltése ennyi időt vett igénybe: {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Csökkentse a szerver válaszidejét (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Alacsony a szerver válaszideje (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Időtartam"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Név"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Kezdés ideje"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Típus"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Érdemes felhasználnia alkalmazásában a User Timing API-t, amellyel valós használat során mért teljesítményadatokat kaphat a legfontosabb felhasználói műveletekről. [További információ.](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 felhasználói időmérés}other{# felhasználói időmérés}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Felhasználói időzítőjelek és intézkedések"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Vegye fontolóra előcsatlakozási vagy előzetes DNS-lehívási erőforrástippek hozzáadását, hogy korai kapcsolatokat hozhasson létre harmadik felek fontos forrásaival. [További információ](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Csatlakozzon előre a szükséges forrásokhoz"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Fontolja meg a <link rel=preload> parancs használatát az olyan erőforrások lekérdezésének rangsorolásához, amelyek az adott pillanatban az oldal betöltése során később következőként szerepelnek. [További információ](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Töltse be előre a kulcsfontosságú kéréseket"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"További információ alkalmazása teljesítményéről."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnosztika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"A teljesítmény legfontosabb szempontja az, hogy milyen gyorsan jelennek meg a képpontok a képernyőn. Legfontosabb mutatók: Első, tartalommal rendelkező leképezés, Első releváns leképezés"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Az első leképezést érintő fejlesztések"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Ezek az optimalizációk felgyorsíthatják oldala betöltési idejét."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Lehetőségek"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Mutatók"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Növelje az átfogó betöltési élményt annak érdekében, hogy az oldal reszponzív legyen, és a lehető legrövidebb időn belül használhatóvá váljon. Főbb mutatók: interaktivitásig eltelt idő, sebességindex"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Átfogó javítások"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Teljesítmény"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Gyorsítótár-TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Méret (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Eltöltött idő"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potenciális megtakarítás (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potenciális megtakarítás (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"{wastedBytes, number, bytes} kB potenciális megtakarítás"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potenciális megtakarítás értéke: {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Ellenőrzések megjelenítése"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Kezdeti navigáció"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Kritikus elérési út maximális várakozási ideje:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Hiba!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Jelentési hiba: nincs ellenőrzési információ"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboradatok"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Az aktuális oldal [Lighthouse](https://developers.google.com/web/tools/lighthouse/)-elemzése emulált 3G-n. Az értékek becslések, legközelebb eltérhetnek."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"További manuálisan elemzendő elemek"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nem alkalmazható"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Lehetőség"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Becsült megtakarítás"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Sikeresen teljesített ellenőrzések"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Pontozási skála:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"A Lighthouse-futtatást befolyásoló problémák fordultak elő:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Az értékek becsültek és változhatnak."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Figyelmeztetések: "}};
-
-
-},{}],56:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Ekstensi Chrome berpengaruh negatif terhadap performa pemuatan halaman ini. Coba audit halaman dalam mode penyamaran atau dari profil Chrome tanpa ekstensi."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Evaluasi Skrip"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Penguraian Skrip"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Pertimbangkan mengurangi waktu yang dihabiskan untuk mengurai, mengompilasi, dan mengeksekusi JS. Anda mungkin menemukan bahwa mengirim payload JS yang lebih kecil akan membantu mengurangi waktu. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Mengurangi waktu eksekusi JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Waktu eksekusi JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"GIF berukuran besar tidak efisien untuk menayangkan konten animasi. Pertimbangkan untuk menggunakan video MPEG4/WebM sebagai animasi dan PNG/WebP sebagai gambar statis untuk menggantikan GIF guna menghemat byte jaringan. [Pelajari lebih lanjut](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Gunakan format video untuk konten animasi"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Pertimbangkan pemuatan lambat di balik layar dan gambar tersembunyi setelah semua resource kritis selesai dimuat untuk mengurangi waktu interaktif. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Tunda gambar di balik layar"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resource memblokir paint pertama halaman. Pertimbangkan mengirim inline JS/CSS kritis dan menunda semua JS/gaya yang tidak kritis. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Hilangkan resource yang memblokir render"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Payload jaringan yang besar menimbulkan biaya yang tinggi bagi pengguna dan berkorelasi erat dengan waktu pemuatan yang lama. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Ukuran total {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Menghindari payload jaringan yang sangat besar"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Menghindari payload jaringan yang sangat besar"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Mengecilkan file CSS dapat mengurangi ukuran payload jaringan. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Kecilkan CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Mengecilkan file JavaScript dapat mengurangi ukuran payload dan waktu penguraian skrip. [Pelajari lebih lanjut](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Kecilkan ukuran JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Menghapus aturan yang tidak digunakan dari stylesheet untuk mengurangi byte yang tidak diperlukan tetapi digunakan oleh aktivitas jaringan. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Tunda CSS yang tidak digunakan"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Menghapus JavaScript yang tidak digunakan untuk mengurangi byte yang digunakan oleh aktivitas jaringan."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Hapus JavaScript yang tidak digunakan"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Durasi cache yang panjang dapat mempercepat kunjungan berulang ke halaman. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 resource ditemukan}other{# resource ditemukan}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Tayangkan aset statis dengan kebijakan cache yang efisien"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Menggunakan kebijakan cache yang efisien pada aset statis"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Gambar yang dioptimalkan dimuat lebih cepat dan menghabiskan lebih sedikit kuota. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Enkode gambar secara efisien"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Menayangkan gambar yang berukuran sesuai untuk menghemat kuota dan meningkatkan waktu pemuatan. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Ubah ukuran gambar dengan tepat"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Resource berbasis teks harus ditayangkan dengan kompresi (gzip, deflate, atau brotli) untuk meminimalkan total byte jaringan. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Aktifkan kompresi teks"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Format gambar seperti JPEG 2000, JPEG XR, dan WebP biasanya memberikan kompresi yang lebih baik daripada PNG atau JPEG, sehingga download lebih cepat dan konsumsi kuota lebih kecil. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Tayangkan gambar dalam format generasi berikutnya"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Rantai Permintaan Penting di bawah menampilkan resource apa saja yang dimuat dengan prioritas tinggi. Pertimbangkan mengurangi panjang rantai, mengurangi ukuran download resource, atau menunda download resource yang tidak penting untuk mempercepat pemuatan halaman. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 rantai ditemukan}other{# rantai ditemukan}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimalkan Kedalaman Permintaan Penting"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Engineer browser merekomendasikan halaman berisi kurang dari ~1.500 node DOM. Titik yang efektif adalah kedalaman hierarki < 32 elemen dan kurang dari 60 elemen turunan/induk. DOM yang besar dapat meningkatkan penggunaan memori, menyebabkan [penghitungan gaya] yang lebih lama(https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), dan menghasilkan [penyesuaian tata letak] yang mahal(https://developers.google.com/speed/articles/reflow). [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 node}other{# node}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Menghindari ukuran DOM yang berlebihan"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Kedalaman DOM Maksimum"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total Node DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Menghindari ukuran DOM yang berlebihan"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Memanfaatkan fitur CSS tampilan font untuk memastikan teks terlihat oleh pengguna saat font web sedang dimuat. [Pelajari lebih lanjut](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Pastikan teks tetap terlihat selama pemuatan font web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Semua teks tetap terlihat selama pemuatan font web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategori"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Pertimbangkan mengurangi waktu yang dihabiskan untuk mengurai, mengompilasi, dan mengeksekusi JS. Anda mungkin menemukan bahwa mengirim payload JS yang lebih kecil akan membantu mengurangi waktu."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimalkan pekerjaan thread utama"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Meminimalkan pekerjaan thread utama"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Skor di atas adalah perkiraan durasi yang diperlukan aplikasi untuk merespons masukan pengguna, dalam milidetik, selama durasi 5 detik tersibuk saat pemuatan halaman. Jika latensi di atas 50 md, pengguna dapat menganggap aplikasi lambat. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Perkiraan Latensi Masukan"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"First Contentful Paint menandai waktu saat teks atau gambar pertama di-paint. [Pelajari lebih lanjut] (https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"First Contentful Paint"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"CPU Pertama Tidak Ada Aktivitas menandai waktu pertama kalinya thread utama halaman menjadi agak tenang untuk menangani masukan. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU Pertama Tidak Ada Aktivitas"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"First Meaningful Paint mengukur waktu saat konten utama halaman terlihat. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"First Meaningful Paint"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Metrik Interaktif menandai waktu halaman menjadi interaktif sepenuhnya. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Waktu untuk Interaktif"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Indeks Kecepatan menunjukkan seberapa cepat konten halaman terlihat terisi lengkap. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indeks Kecepatan"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Pengalihan mencakup penundaan tambahan sebelum halaman dapat dimuat. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Hindari pengalihan lebih dari satu halaman"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Time To First Byte mengidentifikasi waktu saat server mengirim respons. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Dokumen root memerlukan waktu {timeInMs, number, milliseconds} md"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Mengurangi waktu respons server (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Waktu respons server sedikit (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Durasi"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nama"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Waktu Mulai"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Jenis"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Pertimbangkan melengkapi aplikasi dengan User Timing API untuk mengukur performa sebenarnya aplikasi Anda selama pengalaman pengguna utama. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 waktu pengguna}other{# waktu pengguna}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Tanda dan ukuran Waktu Pengguna"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Pertimbangkan menambahkan petunjuk menyambungkan terlebih dahulu atau mengambil terlebih dahulu dns resource untuk melakukan sambungan awal ke nama domain pihak ketiga yang penting. [Pelajari lebih lanjut](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Sambungkan terlebih dahulu ke nama domain yang diperlukan"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Pertimbangkan menggunakan <link rel=preload> untuk memprioritaskan pengambilan resource yang saat ini diminta selama pemuatan halaman. [Pelajari lebih lanjut](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Muat permintaan utama terlebih dahulu"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Informasi selengkapnya tentang performa aplikasi Anda."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostik"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Aspek terpenting dari performa adalah seberapa cepat piksel dirender di layar. Metrik utama: First Contentful Paint, First Meaningful Paint"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Penyempurnaan First Paint"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Pengoptimalan ini dapat mempercepat pemuatan halaman."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Peluang"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrik"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Menyempurnakan pengalaman pemuatan halaman keseluruhan, sehingga halaman responsif dan siap untuk digunakan secepatnya. Metrik utama: Waktu untuk Interaktif, Indeks Kecepatan"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Penyempurnaan Keseluruhan"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performa"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL Cache"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Ukuran (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Waktu yang Dihabiskan"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potensi Penghematan (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potensi Penghematan (md)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potensi penghematan {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potensi penghematan {wastedMs, number, milliseconds} md"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} md"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} d"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Tampilkan audit"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navigasi Awal"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latensi lokasi kritis maksimal:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Error!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Error laporan: tidak ada informasi audit"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Data Lab"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analisis halaman saat ini pada 3G teremulasi. Nilai adalah hasil perkiraan dan dapat bervariasi."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Item tambahan untuk diperiksa secara manual"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Tidak berlaku"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Peluang"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Perkiraan Penghematan"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Lulus audit"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Skala skor:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Ada masalah yang memengaruhi jalannya Lighthouse ini:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Nilai adalah hasil perkiraan dan dapat bervariasi."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Peringatan: "}};
-
-
-},{}],57:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Le estensioni di Chrome incidono negativamente sulle prestazioni di caricamento di questa pagina. Prova a controllare la pagina in modalità di navigazione in incognito o da un profilo Chrome senza estensioni."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Valutazione degli script"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Analisi script"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Totale"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Potresti ridurre i tempi di analisi, compilazione ed esecuzione di JS. A tale scopo potrebbe essere utile pubblicare payload JS di dimensioni inferiori. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Riduci il tempo di esecuzione di JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Tempo di esecuzione JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Le GIF di grandi dimensioni non sono efficaci per pubblicare contenuti animati. Anziché le GIF potresti usare video MPEG4/WebM per le animazioni e PNG/WebP per le immagini statiche. In questo modo userai meno byte di rete. [Ulteriori informazioni](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Usa formati video per i contenuti animati"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Potresti caricare in modo differito le immagini fuori schermo e nascoste al termine del caricamento di tutte le risorse fondamentali per ridurre il tempo necessario per la completa interattività. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Rimanda immagini fuori schermo"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Alcune risorse bloccano la prima visualizzazione della pagina. Potresti pubblicare le risorse JS/CSS fondamentali incorporate e rimandare tutte le risorse JS/styles non fondamentali. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Elimina le risorse di blocco della visualizzazione"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"I payload di rete di grandi dimensioni comportano costi reali per gli utenti e sono strettamente correlati a lunghi tempi di caricamento. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Dimensioni totali: {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Evita payload di rete enormi"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Vengono evitati payload di rete enormi"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Minimizza i file CSS per ridurre le dimensioni dei payload di rete. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minimizza CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Minimizza i file JavaScript per ridurre le dimensioni dei payload e i tempi di analisi degli script. [Ulteriori informazioni](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minimizza JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Rimuovi dai fogli di stile le regole inutilizzate per ridurre i byte superflui consumati dall'attività di rete. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Rimanda codice CSS inutilizzato"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Rimuovi il codice JavaScript inutilizzato per ridurre i byte consumati dall'attività di rete."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Rimuovi il codice JavaScript inutilizzato"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Una lunga durata della cache può velocizzare le visite abituali della tua pagina. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 risorsa trovata}other{# risorse trovate}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Pubblica le risorse statiche con criteri della cache efficaci"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Vengono usati criteri della cache efficaci per le risorse statiche"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Le immagini ottimizzate vengono caricate più velocemente e consumano meno traffico della rete dati. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codifica in modo efficace le immagini"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Pubblica immagini di dimensioni adeguate per consumare meno traffico della rete dati e ridurre i tempi di caricamento. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Usa immagini di dimensioni adeguate"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Le risorse basate sul testo dovrebbero essere pubblicate con compressione (gzip, deflate o brotli) per ridurre al minimo il numero totale di byte di rete. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Attiva la compressione del testo"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"I formati delle immagini come JPEG 2000, JPEG XR e WebP spesso consentono una compressione migliore rispetto a quella dei formati PNG o JPEG, che comporta download più veloci e un minor consumo di dati. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Pubblica immagini in formati più recenti"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Nella sezione Catene di richieste fondamentali indicata di seguito vengono mostrate le risorse caricate con priorità elevata. Potresti ridurre la lunghezza delle catene e le dimensioni del download delle risorse oppure posticipare il download delle risorse non necessarie per migliorare il caricamento della pagina. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 catena trovata}other{# catene trovate}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Riduci al minimo la profondità delle richieste fondamentali"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Gli ingegneri che si occupano dei browser consigliano di usare meno di ~1500 nodi DOM per le pagine. L'ideale sarebbe una struttura ad albero con profondità di < 32 elementi e meno di 60 elementi secondari/principali. Un DOM di grandi dimensioni può aumentare l'utilizzo di memoria, causare [calcoli di stile] più lunghi (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) e generare costosi [adattamenti dinamici del layout](https://developers.google.com/speed/articles/reflow). [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nodo}other{# nodi}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Evita di usare un DOM di dimensioni eccessive"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Profondità massima DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Nodi DOM totali"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Viene evitato un DOM di dimensioni eccessive"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Usa la funzione CSS font-display per assicurarti che il testo sia visibile agli utenti durante il caricamento dei caratteri web. [Ulteriori informazioni](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Assicurati che il testo rimanga visibile durante il caricamento dei caratteri web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Tutto il testo rimane visibile durante il caricamento dei caratteri web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categoria"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Potresti ridurre i tempi di analisi, compilazione ed esecuzione di JS. A tale scopo potrebbe essere utile pubblicare payload JS di dimensioni inferiori."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Riduci al minimo il lavoro del thread principale"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Il lavoro del thread principale è ridotto al minimo"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"La valutazione in alto è una stima del tempo impiegato dall'app, espresso in millisecondi, per rispondere all'input dell'utente durante il periodo di 5 s più impegnativo del caricamento della pagina. Se la latenza è superiore a 50 ms, gli utenti potrebbero considerare lenta la tua app. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Latenza input stimata"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"La metrica Prima visualizzazione con contenuti indica il momento in cui vengono visualizzati il primo testo o la prima immagine. [Ulteriori informazioni] (https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Visualizzazione dei primi contenuti"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"La metrica Prima inattività CPU indica la prima volta in cui il thread principale della pagina è abbastanza tranquillo da poter gestire l'input. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Prima inattività CPU"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"La metrica Visualizzazione primi contenuti utili indica quando diventano visibili i contenuti principali di una pagina. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Visualizzazione primi contenuti utili"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"La metrica Tempo per interattività indica il momento in cui la pagina diventa completamente interattiva. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tempo per interattività"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"La metrica Indice velocità mostra la velocità con cui diventano visibili i contenuti di una pagina. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indice velocità"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"I reindirizzamenti comportano ulteriori ritardi prima del caricamento della pagina. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Evita i reindirizzamenti tra più pagine"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"La metrica Tempo per primo byte identifica il momento in cui il server invia una risposta. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Il documento root ha richiesto {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Riduci i tempi di risposta del server (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"I tempi di risposta del server sono brevi (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Durata"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nome"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Inizio"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tipo"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Potresti dotare la tua app dell'API User Timing per misurare le prestazioni reali durante le esperienze utente chiave. [Ulteriori informazioni] (https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 tempo utente}other{# tempi utente}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Indicatori e misure User Timing"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Potresti aggiungere hint di precollegamento o prelettura DNS delle risorse per collegarti anticipatamente a importanti origini di terze parti. [Ulteriori informazioni](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Precollegati alle origini necessarie"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Potresti usare <link rel=preload> per dare la priorità al recupero delle risorse attualmente richieste in un secondo momento nel caricamento della pagina. [Ulteriori informazioni](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Precarica le richieste fondamentali"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Ulteriori informazioni sulle prestazioni della tua applicazione."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostica"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"L'aspetto più importante delle prestazioni è la velocità di visualizzazione dei pixel sullo schermo. Metriche chiave: Visualizzazione dei primi contenuti, Visualizzazione primi contenuti utili"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Miglioramenti della prima visualizzazione"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Queste ottimizzazioni possono velocizzare il caricamento della pagina."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Opportunità"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metriche"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Migliora l'esperienza di caricamento generale per fare in modo che la pagina diventi reattiva e pronta all'uso nel più breve tempo possibile. Metriche chiave: Tempo per interattività, Indice velocità"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Miglioramenti generali"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Prestazioni"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL cache"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Dimensioni (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Tempo trascorso"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potenziali risparmi (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potenziali risparmi (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potenziali risparmi di {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potenziali risparmi di {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Mostra controlli"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navigazione iniziale"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latenza massima del percorso critico:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Errore"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Errore segnalato: nessuna informazione sul controllo"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Dati di prova controllati"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse] (https://developers.google.com/web/tools/lighthouse/) analizza la pagina corrente su 3G emulato. I valori sono delle stime e potrebbero variare."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Ulteriori elementi da controllare manualmente"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Non applicabile"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Opportunità"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Risparmi stimati"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Controlli superati"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Scala di valutazione:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Si sono verificati dei problemi che incidono su questa esecuzione di Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"I valori sono delle stime e potrebbero variare."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Avvisi: "}};
-
-
-},{}],58:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome 拡張機能がこのページの読み込みに悪影響を及ぼしています。シークレット モードで、または拡張機能なしの Chrome プロファイルからページを監査してみてください。"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"スクリプトの評価"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"スクリプトの解析"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"合計"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"JS の解析、コンパイル、実行にかかる時間の短縮をご検討ください。配信する JS ペイロードのサイズを抑えると効果が見込めます。[詳細](https://developers.google.com/web/tools/lighthouse/audits/bootup)"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"JavaScript の実行にかかる時間の低減"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript の実行にかかる時間"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"サイズの大きい GIF は、アニメーション コンテンツの配信方法として効率的ではありません。ネットワークの通信量を抑えるため、GIF を使用する代わりに、アニメーションには MPEG4/WebM 動画、静止画像には PNG/WebP を使用することをご検討ください。[詳細](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"アニメーション コンテンツでの動画フォーマットの使用"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"オフスクリーンの非表示の画像は、クリティカルなリソースをすべて読み込んだ後に遅れて読み込むようにして、インタラクティブになるまでの時間を短縮することをご検討ください。[Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"オフスクリーン画像の遅延読み込み"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"ページの初回ペイントをリソースが阻害しています。クリティカルな JS や CSS はインラインで配信し、それ以外の JS やスタイルはすべて遅らせることをご検討ください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"レンダリングを妨げるリソースの除外"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"ネットワーク ペイロードのサイズが大きいと、ユーザーの金銭的負担が大きくなり、多くの場合、読み込み時間が長くなります。[詳細](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"合計サイズは {totalBytes, number, bytes} KB でした"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"過大なネットワーク ペイロードの回避"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"過大なネットワーク ペイロードの回避"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS ファイルを最小化すると、ネットワーク ペイロードのサイズを抑えることができます。[詳細](https://developers.google.com/web/tools/lighthouse/audits/minify-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSS の最小化"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"JavaScript ファイルを最小化すると、ペイロード サイズとスクリプトの解析時間を抑えることができます。[詳細](https://developers.google.com/speed/docs/insights/MinifyResources)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScript の最小化"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"使用していないルールをスタイルシートから削除して、データ通信量を減らしてください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/unused-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"使用していない CSS の遅延読み込み"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"使用していない JavaScript を削除して、データ通信量を減らしてください。"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"使用していない JavaScript の削除"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"キャッシュの有効期間を長くすると、再訪問したユーザーへのページの読み込み速度を向上できます。[詳細](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 件のリソースが見つかりました}other{# 件のリソースが見つかりました}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"静的なアセットと効率的なキャッシュ ポリシーの配信"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"静的なアセットでの効率的なキャッシュ ポリシーの使用"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"画像を最適化すると、読み込み時間を速くして、モバイルデータ量を抑えることができます。[詳細](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"効率的な画像フォーマット"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"適切なサイズの画像を配信して、モバイルデータ量と読み込み時間を抑えてください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"適切なサイズの画像"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"テキストベースのリソースは圧縮(gzip、deflate、または brotli)して配信し、ネットワークの全体的な通信量を最小限に抑えてください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"テキスト圧縮の有効化"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000、JPEG XR、WebP などの画像フォーマットは、PNG や JPEG より圧縮性能が高く、ダウンロード時間やデータ使用量を抑えることができます。[詳細](https://developers.google.com/web/tools/lighthouse/audits/webp)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"次世代フォーマットでの画像の配信"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"下のクリティカル リクエスト チェーンでは、高い優先度で読み込まれたリソースを確認できます。チェーンの長さを縮小する、リソースのダウンロード サイズを抑える、不要なリソースのダウンロードを遅らせるなどしてページの読み込み速度を改善することをご検討ください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 件のチェーンが見つかりました}other{# 件のチェーンが見つかりました}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"クリティカルなリクエストの深さの最小化"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"ブラウザ エンジニアは、ページに含まれる DOM のノード数が 1,500 個を超えないようにすることを推奨しています。ツリーの深さは 32 要素まで、子や親の要素数は 60 個までにするのが最適です。DOM サイズが大きいと、メモリの使用量が増え、[スタイルの計算](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations)に時間がかかり、[レイアウトのリフロー](https://developers.google.com/speed/articles/reflow)というコストが発生します。[詳細](https://developers.google.com/web/tools/lighthouse/audits/dom-size)"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 個のノード}other{# 個のノード}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"過大な DOM サイズの回避"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"DOM の最大深さ"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"合計 DOM ノード数"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"過大な DOM サイズの回避"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"フォント表示の CSS 機能を使用して、ウェブフォントの読み込み中にユーザーがテキストを見られるようにしてください。[詳細](https://developers.google.com/web/updates/2016/02/font-display)"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"ウェブフォント読み込み中のテキストの表示"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"ウェブフォント読み込み中の全テキストの表示"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"カテゴリ"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"JS の解析、コンパイル、実行にかかる時間の短縮をご検討ください。配信する JS ペイロードのサイズを抑えると効果が見込めます。"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"メインスレッド処理の最小化"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"メインスレッド処理の最小化"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"上のスコアは、ページ読み込みの最もビジーな 5 秒間における、ユーザーの入力に対するアプリの応答時間(ミリ秒)です。待ち時間が 50 ミリ秒より長い場合、アプリの反応が悪いと思われる可能性があります。[詳細](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"入力の推定待ち時間"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"コンテンツの初回ペイントは、テキストまたは画像が初めてペイントされるまでにかかった時間です。[詳細](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"コンテンツの初回ペイント"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"CPU の初回アイドルは、ページのメインスレッド処理が静止し、初めて入力の処理が可能になるまでにかかった時間です。[詳細](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU の初回アイドル"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"意味のあるコンテンツの初回ペイントは、ページの主要なコンテンツが可視化されるまでにかかった時間です。[詳細](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"意味のあるコンテンツの初回ペイント"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"ページが完全にインタラクティブになるまでの時間です。[詳細](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"インタラクティブになるまでの時間"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"速度インデックスは、ページのコンテンツが取り込まれて表示される速さを表します。[詳細](https://developers.google.com/web/tools/lighthouse/audits/speed-index)"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"速度インデックス"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"リダイレクトを行うと、ページの読み込みにさらに時間がかかる可能性があります。[詳細](https://developers.google.com/web/tools/lighthouse/audits/redirects)"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"複数のページ リダイレクトの回避"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"最初の 1 バイトまでの時間は、サーバーが応答を返すまでにかかった時間を表しています。[詳細](https://developers.google.com/web/tools/lighthouse/audits/ttfb)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"ルート ドキュメントの読み込みに {timeInMs, number, milliseconds} ミリ秒かかりました"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"サーバー応答時間の短縮(TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"サーバーの応答時間が遅い(TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"継続時間"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"名前"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"開始時間"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"タイプ"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"User Timing API を使用してアプリをインストルメント化し、主要なユーザー エクスペリエンスでのアプリの実際のパフォーマンスを測定できるようにしてください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/user-timing)"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 件のカスタム速度}other{# 件のカスタム速度}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"カスタム速度の記録と計測"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"事前接続または DNS プリフェッチのリソースヒントを追加して、重要な第三者ドメインへの接続を早期に確立できるようにすることをご検討ください。[詳細](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"必須のドメインへの事前接続"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"<link rel=preload> を使用して、現在ページ読み込みの後のほうでリクエストしているリソースを優先的に取得することをご検討ください。[詳細](https://developers.google.com/web/tools/lighthouse/audits/preload)"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"キー リクエストのプリロード"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"アプリケーションのパフォーマンスに関する詳細。"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"診断"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"パフォーマンスの最も重要な点は、ピクセルをどのくらい速く画面にレンダリングできるかです。主要な指標: コンテンツの初回ペイント、意味のあるコンテンツの初回ペイント"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"初回ペイントの改善点"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"これらの項目を改善すると、ページの読み込み時間を短縮できます。"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"改善できる項目"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"指標"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"読み込みの全体的なパフォーマンスを改善して、ページの反応性や操作性を高めましょう。主要な指標: インタラクティブになるまでの時間、速度インデックス"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"全体的な改善点"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"パフォーマンス"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"キャッシュの TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"サイズ(KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"かかった時間"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"減らせるデータ量(KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"短縮できる時間(ミリ秒)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"{wastedBytes, number, bytes} KB 減らせます"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"{wastedMs, number, milliseconds} ミリ秒短縮できます"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ミリ秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} 秒"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"監査を表示"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"最初の移動先"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"クリティカル パスの最大待ち時間:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"エラー"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"レポートエラー: 監査情報はありません"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"ラボデータ"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"エミュレート済み 3G での現在のページに関する [Lighthouse](https://developers.google.com/web/tools/lighthouse/) 分析です。推定値のため変動する可能性があります。"},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"個別の検証が必要な他の項目"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"該当なし"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"改善できる項目"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"短縮できる時間(推定)"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"合格した監査"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"スコア評価:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Lighthouse の実行に影響する問題が発生しました。"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"推定値のため変動する可能性があります。"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"警告: "}};
-
-
-},{}],59:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome 확장 프로그램이 이 페이지의 로드 성능에 부정적인 영향을 미쳤습니다. 시크릿 모드나 확장 프로그램이 없는 Chrome 프로필에서 페이지를 검사해 보세요."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"스크립트 평가"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"스크립트 파싱"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"합계"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"JS 파싱, 컴파일, 실행에 소요되는 시간을 줄이세요. 용량이 적은 JS 페이로드를 제공하는 것이 도움이 될 수 있습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/bootup)"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"자바스크립트 실행 시간 단축"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"자바스크립트 실행 시간"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"대용량 GIF는 애니메이션 콘텐츠를 전달하는 데 비효율적입니다. 애니메이션에는 MPEG4/WebM 동영상을, 정적인 이미지에는 PNG/WebP를 GIF 대신 사용하여 네트워크 바이트를 절약하세요. [자세히 알아보기](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"애니메이션 콘텐츠에 동영상 형식 사용하기"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"중요한 리소스의 로드가 모두 완료된 후에는 오프스크린 및 숨겨진 이미지를 지연 로드함으로써 상호작용 시간을 줄이는 것이 좋습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"오프스크린 이미지 지연하기"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"리소스가 페이지의 첫 번째 페인트를 차단하고 있습니다. 중요한 JS/CSS를 인라인으로 전달하고 중요하지 않은 모든 JS/style을 지연하는 것이 좋습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"렌더링 차단 리소스 제거하기"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"네트워크 페이로드가 커지면 사용자에게 실제 비용 부담이 되며 로드 시간이 길어질 수 있습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"총 크기: {totalBytes, number, bytes}KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"네트워크 페이로드가 커지지 않도록 관리하기"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"대규모 네트워크 페이로드 방지하기"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS 파일을 축소하면 네트워크 페이로드의 크기가 줄어들 수 있습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/minify-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSS 축소하기"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"자바스크립트 파일을 줄이면 페이로드 크기 및 스크립트 파싱 시간이 줄어들 수 있습니다. [자세히 알아보기](https://developers.google.com/speed/docs/insights/MinifyResources)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"자바스크립트 줄이기"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"스타일시트에서 사용되지 않는 규칙을 삭제하여 네트워크 활동에 불필요하게 소비되는 바이트를 줄이세요. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/unused-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"사용하지 않는 CSS 지연하기"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"사용하지 않는 자바스크립트를 삭제하고 네트워크 활동에 소비되는 바이트를 줄이세요."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"사용하지 않는 자바스크립트 삭제하기"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"캐시 수명이 길면 페이지를 반복해서 방문하는 속도가 빨라질 수 있습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{리소스 1개 발견됨}other{리소스 #개 발견됨}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"효율적인 캐시 정책을 사용하여 정적인 애셋 제공하기"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"정적인 애셋에 효율적인 캐시 정책 사용하기"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"최적화된 이미지는 빨리 로드되며 모바일 데이터를 적게 소비합니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"효율적으로 이미지 인코딩하기"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"알맞은 크기의 이미지를 게재하여 모바일 데이터를 절약하고 로드 시간을 단축하세요. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"이미지 크기 적절하게 설정하기"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"총 네트워크 바이트를 최소화하려면 텍스트 기반 리소스를 압축(gzip, deflate, brotli)하여 제공해야 합니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"텍스트 압축 사용"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000, JPEG XR, WebP와 같은 이미지 형식을 사용하면 PNG 또는 JPEG보다 압축률이 높기 때문에 다운로드 속도가 빠르고 데이터 소비량도 줄어듭니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/webp)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"차세대 형식을 사용해 이미지 제공하기"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"다음의 크리티컬 요청 체인(Critical Request Chains)은 로드 시 우선순위가 높은 리소스를 보여줍니다. 체인의 길이를 줄이고, 리소스의 다운로드 크기를 줄이거나 불필요한 리소스의 다운로드를 지연하여 페이지 로드 속도를 높이는 것이 좋습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1개 체인 발견됨}other{#개 체인 발견됨}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"중요 요청 깊이 최소화하기"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"브라우저 엔지니어들은 페이지에 포함된 DOM 노드의 수가 1,500개 미만인 것이 바람직하다고 말합니다. 최적의 값은 트리 깊이가 요소 32개 미만이고 하위/상위 요소 60개 미만일 때입니다. DOM이 크면 메모리 사용량이 늘어나고 [스타일 계산](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) 시간이 길어질 수 있으며, 큰 비용이 드는 [레이아웃 리플로](https://developers.google.com/speed/articles/reflow)가 발생할 수 있습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/dom-size)"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{노드 1개}other{노드 #개}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"과도한 DOM 크기 지양하기"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"최대 DOM 깊이"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"총 DOM 노드"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"과도한 DOM 크기 지양하기"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"웹폰트가 로드되는 동안 사용자에게 텍스트가 표시되도록 글꼴 표시 CSS 기능을 사용하세요. [자세히 알아보기](https://developers.google.com/web/updates/2016/02/font-display)"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"웹폰트가 로드되는 동안 텍스트가 계속 표시되는지 확인하기"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"웹폰트가 로드되는 동안 모든 텍스트가 계속 표시됩니다"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"카테고리"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"JS 파싱, 컴파일, 실행에 소요되는 시간을 줄이세요. 용량이 적은 JS 페이로드를 제공하면 도움이 될 수 있습니다."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"기본 스레드 작업 최소화하기"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"기본 스레드 작업 최소화하기"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"위의 점수는 페이지 로드가 가장 많은 5초 동안 앱이 사용자 입력에 응답하는 데 걸리는 시간(ms)의 추정치입니다. 지연 시간이 50ms보다 길면 사용자가 앱이 느리다고 인식할 수 있습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"예상 입력 대기시간"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"콘텐츠가 포함된 첫 페인트는 첫 번째 텍스트 또는 이미지가 표시되는 시간을 나타냅니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"최초 만족 페인트"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"최초 CPU 유휴 상태는 페이지의 기본 스레드가 입력을 처리할 수 있을 만큼 조용한 상태가 된 첫 번째 시간을 표시합니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"최초 CPU 유휴 상태"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"최초 유의미 페인트는 페이지의 기본 콘텐츠가 표시되는 경우를 측정합니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"최초 유의미 페인트"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"상호작용은 페이지가 완전히 상호작용하는 시간을 표시합니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"상호작용 시간"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"속도 색인은 페이지 콘텐츠가 얼마나 빨리 표시되는지 보여줍니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/speed-index)"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"속도 색인"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"리디렉션을 사용하면 페이지가 로드되기 전 추가적인 지연이 발생합니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/redirects)"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"여러 차례의 페이지 리디렉션 피하기"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Time To First Byte는 서버가 응답을 보내는 시간을 식별합니다. [자세히 알아보기] (https://developers.google.com/web/tools/lighthouse/audits/ttfb)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"루트 문서에 {timeInMs, number, milliseconds}ms 소요됨"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"서버 응답 시간(TTFB) 단축"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"서버 응답 시간 낮음(TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"시간"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"이름"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"시작 시간"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"유형"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"앱에 User Timing API를 사용하여 중요 사용자 경험이 이루어지는 동안의 실적을 측정하세요. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{사용자 시간 1회}other{사용자 시간 #회}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"사용자 타이밍 표시 및 측정 값"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"사전 연결 또는 DNS 프리페치 리소스 힌트를 추가하여 중요한 타사 원본에 대한 조기 연결을 수립하는 것이 좋습니다. [자세히 알아보기](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"필수 원본 미리 연결하기"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"<link rel=preload>를 사용하여 페이지 로드에서 현재 나중에 요청되는 리소스를 가져오는 데 우선순위를 두는 것이 좋습니다. [자세히 알아보기](https://developers.google.com/web/tools/lighthouse/audits/preload)"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"중요한 요청을 미리 로드하기"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"애플리케이션 성능 관련 추가 정보"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"진단"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"성능에서 가장 중요한 측면은 픽셀이 화면에 렌더링되는 속도입니다. 주요 측정항목: 최초 만족 페인트, 최초 유의미 페인트"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"최초 페인트 개선"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"다음의 최적화 방법을 사용하면 페이지 로드 속도를 높일 수 있습니다."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"추천"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"측정항목"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"페이지가 빠르게 반응하고 가능한 한 빨리 사용할 수 있는 준비가 되도록 전반적인 로드 환경을 강화하세요. 주요 측정항목: 상호작용 시간, 속도 색인"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"전반적인 개선사항"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"성능"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"캐시 TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"크기(KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"소요 시간"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"절감 가능치(KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"절감 가능한 페이지 로드 시간(ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"절감 가능치: {wastedBytes, number, bytes}KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"절감 가능 {wastedMs, number, milliseconds}ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds}ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds}초"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"감사 보기"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"초기 탐색"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"최상 경로 최대 지연 시간:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"오류!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"보고 오류: 감사 정보 없음"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"실험실 데이터"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"에뮬레이트된 3G 환경에서의 현재 페이지 [Lighthouse](https://developers.google.com/web/tools/lighthouse/) 분석 결과입니다. 값은 추정치이며 달라질 수 있습니다."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"직접 확인해야 하는 추가 항목"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"해당 사항 없음"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"추천"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"예상 절감치"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"통과한 감사"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"점수 척도:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Lighthouse 실행에 영향을 미치는 문제가 발생했습니다."},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"값은 추정치이며 달라질 수 있습니다."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"경고: "}};
-
-
-},{}],60:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"„Chrome“ plėtiniai neigiamai paveikė šio puslapio įkėlimo našumą. Pabandykite patikrinti puslapį inkognito režimu arba naudodami „Chrome“ profilį be plėtinių."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Scenarijaus įvertinimas"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Scenarijaus analizė"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Iš viso"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Apsvarstykite, ar neverta sutrumpinti JS analizei, kompiliavimui ir vykdymui skiriamo laiko. Mažesnės JS naudingosios apkrovos gali padėti tai padaryti. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Sutrumpinkite „JavaScript“ vykdymo laiką"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"„JavaScript“ vykdymo laikas"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Dideli GIF failai nėra efektyvus animuoto turinio pateikimo būdas. Vietoje GIF galite naudoti MPEG4 ar „WebM“ vaizdo įrašų animacijai ir PNG ar „WebP“ statiniams vaizdams pateikti, kad sutaupytumėte tinklo baitų. [Sužinokite daugiau](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Naudokite vaizdo įrašo formatus animuotam turiniui pateikti"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Galbūt verta įkelti ne ekraninius ir paslėptus vaizdus tik tada, kai bus įkelti visi svarbiausi ištekliai, kad sutrumpėtų laikas iki sąveikos. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Atidėkite ne ekraninius vaizdus"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ištekliai blokuoja pirmąjį puslapio parodymą. Galbūt verta pateikti svarbiausius JS ar CSS kaip eilutinius elementus ir atidėti visus nesvarbius JS ar stilius. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Pašalinkite pateikimą blokuojančius išteklius"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Dėl didelių tinklo naudingųjų apkrovų naudotojai praranda pinigus ir jos glaudžiai susijusios su ilgu įkėlimo laiku. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Bendras dydis: {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Išvenkite didelių tinklo naudingųjų apkrovų"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Išvengiama didelių tinklo naudingųjų apkrovų"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Sumažinus CSS failų dydį, gali sumažėti tinklo naudingosios apkrovos. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Sumažinkite CSS failus"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Sumažinus „JavaScript“ failus, galima sumažinti naudingąsias apkrovas ir sutrumpinti scenarijaus analizavimo laiką. [Sužinokite daugiau](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Sumažinkite „JavaScript“"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Pašalinkite nenaudojamas taisykles iš stiliaus failų, kad tinklo veikla sunaudotų mažiau nereikalingų baitų. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Atidėkite nenaudojamus CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Pašalinkite nenaudojamą „JavaScript“, kad tinklo veikla sunaudotų mažiau baitų."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Pašalinkite nenaudojamą „JavaScript“"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Jei talpykla galios ilgiau, pakartotiniai apsilankymai puslapyje gali pagreitėti. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Rastas 1 išteklius}one{Rastas # išteklius}few{Rasti # ištekliai}many{Rasta # ištekliaus}other{Rasta # išteklių}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Statiniams ištekliams taikykite efektyvią talpyklos politiką"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Naudojama efektyvi statinių išteklių talpyklos politika"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimizuoti vaizdai įkeliami greičiau ir sunaudoja mažiau mobiliojo ryšio duomenų. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Efektyviai koduokite vaizdus"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Teikite tinkamo dydžio vaizdus, kad būtų taupomi mobiliojo ryšio duomenys ir puslapis būtų įkeliamas greičiau. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Pasirinkite tinkamo dydžio vaizdus"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Tekstinius išteklius reikėtų suglaudinti (Naudojant „Gzip“, „Deflate“ arba „Brotli“), kad bendrai būtų sunaudojama kuo mažiau tinklo baitų. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Įgalinkite teksto glaudinimą"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Tokių formatų kaip JPEG 2000, JPEG XR ir „WebP“ vaizdai dažniausiai glaudinami geriau nei PNG ar JPEG vaizdai, todėl yra atsisiunčiami greičiau ir sunaudoja mažiau duomenų. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Pateikite naujos kartos formatų vaizdus"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Toliau pateiktose svarbiausių užklausų grandinėse nurodoma, kurie ištekliai įkelti nurodant aukštą prioritetą. Kad puslapio įkėlimas būtų sklandesnis, galbūt verta sutrumpinti grandines, sumažinti atsisiunčiamų išteklių dydį arba atidėti nereikalingų išteklių atsisiuntimą. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Rasta 1 grandinė}one{Rasta # grandinė}few{Rastos # grandinės}many{Rasta # grandinės}other{Rasta # grandinių}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Sumažinkite svarbiausių užklausų gylį"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Naršyklių inžinieriai rekomenduoja puslapiuose turėti ne daugiau nei apytiksliai 1,5 tūkst. DOM mazgų. Optimaliausias medžio gylis – mažiau nei 32 elementai ir mažiau nei 60 poelemenčių bei viršelemenčių. Dėl didelio DOM gali būti sunaudojama daugiau atminties, ilgiau skaičiuojami stiliai (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) ir reikia brangių išdėstymo perskaičiavimų (https://developers.google.com/speed/articles/reflow). [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 mazgas}one{# mazgas}few{# mazgai}many{# mazgo}other{# mazgų}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Venkite per didelių DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimalus DOM gylis"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Bendras DOM mazgų skaičius"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Išvengiama per didelių DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Pasinaudokite šriftų pateikimo CSS funkcija, kad tekstas būtų matomas naudotojui, kol įkeliami žiniatinklio šriftai. [Sužinokite daugiau](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Užtikrinkite, kad įkeliant žiniatinklio šriftą būtų matomas tekstas"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Įkeliant žiniatinklio šriftą matomas visas tekstas"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorija"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Apsvarstykite, ar neverta sutrumpinti JS analizei, kompiliavimui ir vykdymui skiriamo laiko. Mažesnės JS naudingosios apkrovos gali padėti tai padaryti."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Pagrindinės grupės veikimo sutrumpinimas"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Sutrumpinamas pagrindinės grupės veikimas"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Toliau nurodytas rezultatas yra įvertintas laikas milisekundėmis, per kurį programa atsako į naudotojo įvestį per labiausiai užimtas puslapio įkėlimo 5 sekundes. Jei delsa ilgesnė nei 50 ms, naudotojams gali pasirodyti, kad programa veikia lėtai. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Įvertinta įvesties delsa"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Pirmas turiningas žymėjimas nurodo laiką, kada pažymimas pirmasis tekstas ar vaizdas. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Pirmasis „Contentful“ parodymas"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Pirmas cent. procesoriaus laisvas laikas nurodo pirmą laiką, kai pagrindinė puslapio grupė buvo pakankamai neaktyvi, kad galėtų apdoroti įvestį. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Pirmas cent. procesoriaus laisvas laikas"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Pirmasis reikšmingas parodymas nurodo, kada parodomas pagrindinis puslapio turinys. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Pirmasis reikšmingas parodymas"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Sąveika nurodo laiką, per kurį puslapis tampa visiškai sąveikus. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Laikas iki sąveikos"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Greičio rodiklis parodo, kaip greitai pavaizduojamas puslapio turinys. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Greičio rodiklis"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Peradresuojant puslapio įkėlimas dar labiau delsia. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Venkite kelių puslapio peradresavimų"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Laikas iki pirmojo baito nurodo laiką, per kurį serveris atsako. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Šakninio dokumento įkėlimas užtruko {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Serverio atsako laiko sutrumpinimas (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Serverio atsako laikas yra trumpas (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Trukmė"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Pavadinimas"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Pradžios laikas"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tipas"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Galbūt verta apdoroti programą naudojant naudotojo laiko API ir įvertinti programos realų našumą atsižvelgiant į pagrindines naudotojo funkcijas. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 naudotojo laikas}one{# naudotojo laikas}few{# naudotojo laikai}many{# naudotojo laiko}other{# naudotojo laikų}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Naudotojo laiko žymės ir matavimas"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Galbūt verta pridėti išankstinio prijungimo arba DNS išankstinės iškvietos ištekliaus nurodymus, kad ryšys su svarbiais trečiųjų šalių šaltiniais būtų užmezgamas iš anksto. [Sužinokite daugiau](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Iš anksto prisijunkite prie reikiamų šaltinių"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Galbūt verta naudoti <link rel=preload> ir suteikti prioritetą gaunamiems ištekliams, kurių užklausos šiuo metu teikiamos vėliau įkeliant puslapį. [Sužinokite daugiau](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Iš anksto įkelkite svarbiausias užklausas"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Daugiau informacijos apie jūsų programos našumą."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Svarbiausias našumo rodiklis – kaip greitai taškai pateikiami ekrane. Svarbiausia metrika: pirmasis „Contentful“ parodymas, pirmasis reikšmingas parodymas"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Pirmojo parodymo patobulinimai"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Toks optimizavimas gali padėti pagreitinti puslapio įkėlimą."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Galimybės"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrika"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Pagerinkite bendrą įkėlimo našumą, kad puslapis reaguotų ir būtų parengtas naudoti kuo greičiau. Svarbiausia metrika: laikas iki sąveikos, greičio rodiklis"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Bendri patobulinimai"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Našumas"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Talpyklos TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Dydis (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Sugaištas laikas"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Galima sutaupyti (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Galima sutaupyti (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Galima sutaupyti {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Galima sutaupyti {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} sek."},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Rodyti patikras"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Pradinis naršymas"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Didžiausia svarbiausio kelio delsa:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Klaida!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Ataskaitos klaida: nėra patikros informacijos"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratorijos duomenys"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Dabartinio puslapio [„Lighthouse“](https://developers.google.com/web/tools/lighthouse/) analizė naudojant emuliuotą 3G. Vertės yra numatytos ir gali skirtis."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Papildomi elementai, kuriuos reikia patikrinti neautomatiškai"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Netaikoma"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Galimybė"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Numatomos santaupos"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Sėkmingos patikros"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Rezultatų skalė:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Paleidžiant „Lighthouse“ kilo problemų."},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Vertės yra numatytos ir gali skirtis."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Įspėjimai: "}};
-
-
-},{}],61:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome paplašinājumi negatīvi ietekmē šīs lapas ielādes veiktspēju. Mēģiniet lapas pārbaudi veikt inkognito režīmā vai no Chrome profila bez paplašinājumiem."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Skripta novērtēšana"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Skriptu parsēšana"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Kopā"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Ieteicams samazināt laiku, kas tiek izmantots JS parsēšanai, kompilēšanai un izpildei. Iespējams, konstatēsiet, ka ir noderīgi izmantot mazākas JS lietderīgās slodzes. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"JavaScript izpildes laika samazināšana"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript izpildes laiks"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Lieli GIF attēli nav efektīvi animēta satura rādīšanai. Animācijām ir ieteicams izmantot MPEG4/WebM video, bet statiskiem attēliem — PNG/WebP, nevis GIF, lai samazinātu tīkla lietojumu (baitos). [Uzzināt] vairāk(https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Izmantojiet video failu formātus animētam saturam"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Lai samazinātu laiku līdz interaktivitātei, ārpus ekrāna un paslēptos attēlus ar lēnu ielādi ieteicams atlikt līdz visu svarīgo resursu ielādes pabeigšanai. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Ārpus ekrāna esošo attēlu atlikšana"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resursi bloķē jūsu lapas pirmo satura atveidojumu. Ieteicams rādīt svarīgos JS/CSS iekļautā veidā un atteikties no visiem nesvarīgajiem JS/stiliem. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Samaziniet resursus, kas bloķē renderēšanu"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Lielas tīkla lietderīgās slodzes izmaksā lietotājiem īstu naudu un ir cieša saistītas ar ilgu ielādes laiku. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Kopējais lielums bija {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Pārāk lielas tīkla lietderīgās slodzes nepieļaušana"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Nepieļauj pārāk lielu tīkla lietderīgo slodzi"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Samazinot CSS failus, var samazināties tīkla lietderīgā slodze. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Samaziniet CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Samazinot JavaScript failus, var samazināties lietderīgās slodzes apjomi un skriptu parsēšanas laiks. [Uzzināt vairāk](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScript·samazināšana"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Noņemiet no stila lapām neizmantotās kārtulas, lai samazinātu tīkla aktivitātei nevajadzīgo baitu izmantošanu. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Atlieciet neizmantoto CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Noņemiet neizmantoto JavaScript, lai samazinātu tīkla aktivitātes izmantoto baitu apjomu."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Noņemiet neizmantoto JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Iestatot ilgu kešatmiņas mūžu, lapas atkārtoti apmeklējumi varētu paātrināties. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Atrasts 1 resurss}zero{Atrasti # resursi}one{Atrasts # resurss}other{Atrasti # resursi}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Statisko elementu noteikšana, izmantojot efektīvu kešatmiņas politiku"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Efektīvas kešatmiņas politikas izmantošana statiskiem elementiem"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimizēti attēli tiek ielādēti ātrāk un izmanto mazāku mobilo datu apjomu. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Efektīva attēlu kodēšana"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Rādiet atbilstoša izmēra attēlus, lai tiktu izmantots mazāks mobilo datu apjoms un tiktu uzlabots ielādes laiks. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Atbilstoša lieluma attēli"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Lai samazinātu kopējo tīkla lietojumu (baitos), iesakām izmantot saspiešanu (Gzip, Deflate or Brotli). [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Iespējojiet teksta saspiešanu"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Tādi attēlu formāti kā JPEG 2000, JPEG XR un WebP bieži ir veiksmīgāk saspiežami nekā PNG vai JPEG — tas nozīmē ātrāku lejupielādi un mazāku datu patēriņu. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Rādiet attēlus nākamās paaudzes formātos"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Metrika “Kritisko pieprasījumu ķēdes” tālāk parāda, kuri resursi ir ielādēti ar augstāko prioritāti. Lai uzlabotu lapas ielādi, ieteicams samazināt ķēžu garumu, samazināt resursu lejupielādes apjomu vai atlikt nevajadzīgo resursu lejupielādi.[Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Atrasta 1 ķēde}zero{Atrastas # ķēdes}one{Atrasta # ķēde}other{Atrastas # ķēdes}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Kritisko pieprasījumu dziļuma samazināšana"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Pārlūka inženieri iesaka, lai lapā nebūtu vairāk par 1500 DOM mezgliem. Ieteicams, lai koka dziļums nepārsniegtu 32 elementus un 60 bērnelementus/vecākelementus. Liels DOM var palielināt atmiņas lietojumu, izraisīt ilgākus [stila aprēķinus](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) un radīt dārgu [izkārtojuma plūduma sakārtošanu](https://developers.google.com/speed/articles/reflow). [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 mezgls}zero{# mezglu}one{# mezgls}other{# mezgli}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Pārāk lielu DOM izmēru nepieļaušana"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimālais DOM dziļums"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"DOM mezglu kopskaits"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Nepieļauj pārāk lielus DOM izmērus"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Izmantojiet fonta rādīšanas CSS funkciju, lai nodrošinātu, ka lietotāji tīmekļa fontu ielādes laikā var redzēt tekstu. [Uzzināt vairāk](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Visa teksta redzamības nodrošināšana tīmekļa fonta ielādes laikā"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Tīmekļa fonta ielādes laikā viss teksts paliek redzams"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorija"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Ieteicams samazināt laiku, kas tiek izmantots JS parsēšanai, kompilēšanai un izpildei. Iespējams, konstatēsiet, ka ir noderīgi izmantot mazākas JS lietderīgās slodzes."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Samaziniet galvenā pavediena darbu"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Galvenā pavediena darba samazināšana"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Iepriekš redzamais rādītājs aptuveni norāda, pēc cik ilga laika (milisekundēs) uz lietotāja ievadi reaģēs jūsu lietotne aizņemtākajā lapas ielādes 5 s periodā. Ja latentums pārsniedz 50 ms, iespējams, lietotāji jūsu lietotnes saņems novēloti. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Paredzētais ievades latentums"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Metrika \"Pirmais satura marķējums\" atzīmē laiku, kad tiek marķēts pirmais teksts vai attēls. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Pirmais saturīgais satura atveidojums"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Metrika “Pirmā CPU dīkstāve” norāda laiku, kad lapas galvenais pavediens ir kļuvis pietiekami mazs, lai varētu apstrādāt ievadi. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Pirmā CPU dīkstāve"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Metrika “Pirmais nozīmīgais satura atveidojums” norāda, kad kļūst redzams lapas galvenais saturs. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Pirmais nozīmīgais satura atveidojums"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktivitātes metrika norāda laiku, kad lapa ir pilnībā interaktīva. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Laiks līdz interaktivitātei"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Metrika “Ātruma rādītājs” norāda, cik ātri tiek parādīts lapas saturs. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Ātruma rādītājs"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Novirzīšana rada papildu aizkaves pirms lapas ielādes. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Nepieļaujiet vairākas lapas novirzīšanas"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Metrika “Laiks līdz pirmajam baitam” norāda laiku, kad jūsu serveris nosūta atbildi. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Saknes dokumentam nepieciešamais laiks: {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Servera atbildes laika samazināšana (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Servera atbildes laiks ir mazs (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Ilgums"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Vārds"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Sākuma laiks"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Veids"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Ieteicams pievienot lietotnei Lietotāju laika API, lai noteiktu lietotnes aktuālo veiktspēju lietotāju pamata darbības laikā. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 lietotāja laiks}zero{# lietotāju laiks}one{# lietotāja laiks}other{# lietotāju laiks}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Lietotāju laika atzīmes un mērījumi"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Ieteicams pievienot iepriekš pieslēgtu vai DNS sākotnējo datu iegūšanas resursa norādes, lai izveidotu laicīgus savienojumus ar svarīgiem trešās puses sākumpunktiem. [Uzzināt vairāk](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Veiciet iepriekšēju pieslēgšanu obligātajiem sākumpunktiem"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Ieteicams izmantot <link rel=preload>, lai noteiktu prioritāti tādu resursu iegūšanai, kas pašlaik lapas ielādē tiek pieprasīti vēlāk. [Uzzināt vairāk](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Veiciet svarīgāko pieprasījumu iepriekšēju ielādi"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Plašāka informācija par jūsu lietojumprogrammas veiktspēju"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Vissvarīgākais veiktspējas aspekts ir pikseļu renderēšanas ātrums ekrānā. Galvenās metrikas: “Pirmais saturīgais satura atveidojums”, “Pirmais nozīmīgais satura atveidojums”"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Pirmā satura atveidojuma uzlabojumi"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Šīs optimizācijas var paātrināt lapas ielādi."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Iespējas"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrikas"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Uzlabojiet vispārējo ielādes darbību, lai lapa reaģētu un būtu gatava izmantošanai pēc iespējas ātrāk. Galvenās metrikas: “Laiks līdz interaktivitātei”, “Ātruma rādītājs”"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Vispārēji uzlabojumi"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Veiktspēja"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Kešatmiņas TTL vērtība"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Lielums (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Iztērētais laiks"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potenciālais ietaupījums (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potenciālais ietaupījums (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potenciālais ietaupījums: {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potenciālais ietaupījums: {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Rādīt pārbaudes"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Sākotnējā navigācija"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksimālais kritiskais ceļa latentums:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Kļūda!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Pārskata kļūda: nav pārbaudes informācijas"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratorijas dati"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse] (https://developers.google.com/web/tools/lighthouse/) pašreizējās lapas analīze emulētajā 3G. Vērtības ir aptuvenas un var atšķirties."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Papildu vienumi manuālai pārbaudei"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nav piemērojams"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Iespēja"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Aptuvenais ietaupījums"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Izpildītās pārbaudes"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Rādītāja mērogs:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Radās problēmas, kas ietekmēja šo Lighthouse palaišanu:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Vērtības ir aptuvenas un var atšķirties."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Brīdinājumi: "}};
-
-
-},{}],62:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome-extensies hadden een negatieve invloed op de laadprestaties van deze pagina. Controleer de pagina in de incognitomodus of via een Chrome-profiel zonder extensies."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Scriptevaluatie"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Script parseren"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Totaal"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Overweeg minder tijd te besteden aan het parseren, compileren en uitvoeren van JS. Het leveren van kleinere JS-payloads kan hierbij helpen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Verkort de JavaScript-uitvoeringstijd"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript-uitvoeringstijd"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Grote gif's zijn niet efficiënt om content met animaties te leveren. Overweeg in plaats van gif's MPEG4-/WebM-video's voor animaties en PNG/WebP voor statische afbeeldingen en bespaar zo netwerkbytes. [Meer informatie](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Gebruik video-indelingen voor content met animaties"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Overweeg afbeeldingen die niet in beeld zijn en verborgen afbeeldingen via 'lazy loading' te laden nadat alle kritieke bronnen zijn geladen om zo de tijd tot interactief te verlagen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Laad afbeeldingen die niet in beeld zijn nog niet"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Bronnen blokkeren de eerste tekenbewerking voor je pagina. Overweeg kritieke JS/css inline te leveren en alle niet-kritieke JS/stijlen uit te stellen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Verwijder bronnen die de weergave blokkeren"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Grote netwerkpayloads kosten gebruikers veel geld en hebben vaak lange laadtijden. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Totale grootte was {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Vermijd enorme netwerkpayloads"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Vermijdt enorme netwerkpayloads"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Als je css-bestanden verkleint, kun je de omvang van netwerkpayloads verkleinen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Verklein de css"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Als je JavaScript-bestanden verkleint, kunnen de omvang van de payload en de parseringstijd van het script worden verkleind. [Meer informatie](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Verklein JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Verwijder niet-gebruikte regels uit stylesheets om het aantal onnodige bytes te verminderen die worden verbruikt door netwerkactiviteit. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Stel niet-gebruikte css uit"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Verwijder ongebruikt JavaScript om het aantal bytes te verminderen dat wordt verbruikt door netwerkactiviteit."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Verwijder ongebruikt JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Een lange levensduur voor het cachegeheugen kan herhaalde bezoeken aan je pagina versnellen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 bron gevonden}other{# bronnen gevonden}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Lever statische items met een efficiënt cachebeleid"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Gebruikt een efficiënt cachebeleid voor statische items"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Geoptimaliseerde afbeeldingen worden sneller geladen en verbruiken minder mobiele data. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codeer afbeeldingen op een efficiënte manier"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Lever afbeeldingen met het juiste formaat om mobiele data te besparen en de laadtijd te verbeteren. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Geef afbeeldingen het juiste formaat"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Tekstgebaseerde bronnen moeten worden geleverd met compressie (gzip, deflate of brotli) om het totale aantal netwerkbytes te minimaliseren. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Schakel tekstcompressie in"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Afbeeldingsindelingen zoals JPEG 2000, JPEG XR en WebP bieden vaak betere compressie dan PNG of JPEG. Dit resulteert in snellere downloads en minder dataverbruik. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Lever afbeeldingen in moderne indelingen"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"De onderstaande kritieke verzoekketens laten zien welke bronnen met een hoge prioriteit worden geladen. Overweeg de lengte van ketens te verkleinen, de downloadgrootte van bronnen te beperken of het downloaden van onnodige bronnen uit te stellen om de laadtijd van de pagina te verbeteren. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 keten gevonden}other{# ketens gevonden}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimaliseer de diepte van kritieke verzoeken"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Browser-engineers bevelen aan dat pagina's minder dan ~1500 DOM-knooppunten bevatten. De perfecte balans is een structuurdiepte van minder dan 32 elementen en minder dan 60 onderliggende/bovenliggende elementen. Een grote DOM kan ervoor zorgen dat het geheugengebruik toeneemt. Dit leidt tot langere [stijlberekeningen](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) en produceert dure [dynamische lay-outaanpassingen](https://developers.google.com/speed/articles/reflow). [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 knooppunt}other{# knooppunten}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Vermijd een overmatig grote DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximum DOM-diepte"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Totaal aantal DOM-knooppunten"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Vermijdt een overmatige grote DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Maak gebruik van de css-functie 'font-display' om ervoor te zorgen dat tekst zichtbaar is voor gebruikers terwijl weblettertypen worden geladen. [Meer informatie](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Zorg ervoor dat tekst zichtbaar blijft tijdens het laden van weblettertypen"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Alle tekst blijft zichtbaar tijdens het laden van weblettertypen"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categorie"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Overweeg minder tijd te besteden aan het parseren, compileren en uitvoeren van JS. Het leveren van kleinere JS-payloads kan hierbij helpen."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Primaire threadbewerkingen minimaliseren"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Primaire threadbewerkingen minimaliseren"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"De bovenstaande score is een schatting van hoelang het duurt voordat je app reageert op gebruikersinvoer (in milliseconden) gedurende de drukste periode van 5 seconden tijdens het laden van de pagina. Als de wachttijd langer dan 50 ms is, kunnen gebruikers je app als traag beschouwen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Geschatte invoerwachttijd"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"'Eerste tekenbewerking met content' geeft het tijdstip aan waarop de eerste tekst of afbeelding is weergegeven. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Eerste tekenbewerking met content"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"'Eerste keer dat CPU inactief was' geeft de eerste keer aan dat de primaire thread van de pagina rustig genoeg was om invoer te verwerken. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Eerste keer dat CPU inactief was"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"'Eerste zinvolle tekenbewerking' meet wanneer de primaire content van een pagina zichtbaar is. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Eerste zinvolle tekenbewerking"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interactief geeft het tijdstip aan waarop de pagina volledig interactief is. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tijd tot interactief"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Snelheidsindex laat zien hoe snel de content van een pagina zichtbaar is. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Snelheidsindex"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Omleidingen zorgen voor extra vertraging voordat de pagina kan worden geladen. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Vermijd meerdere pagina-omleidingen"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"'Tijd tot eerste byte' identificeert het tijdstip waarop je server een reactie stuurt. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Hoofddocument duurde {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Beperk serverreactietijden (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Serverreactietijden zijn laag (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Duur"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Naam"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Begintijd"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Type"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Overweeg je app te voorzien van de API voor gebruikerstiming om de daadwerkelijke prestaties van je app tijdens belangrijke gebruikerservaringen te meten. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 gebruikerstiming}other{# gebruikerstimings}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Markeringen en metingen voor gebruikerstiming"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Overweeg hints voor het vooraf verbinden of dns-prefetchen van bronnen toe te voegen om vroege verbindingen met belangrijke externe herkomsten tot stand te brengen. [Meer informatie](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Maak vooraf verbinding met vereiste herkomsten"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Overweeg <link rel=preload> te gebruiken om prioriteit te geven aan het ophalen van bronnen die momenteel later tijdens het laden van de pagina worden opgehaald. [Meer informatie](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Laad belangrijke verzoeken vooraf"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Meer informatie over de prestaties van je app."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostische gegevens"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Het meest essentiële aspect van de prestaties is hoe snel pixels worden weergegeven op het scherm. Belangrijkste statistieken: Eerste tekenbewerking met content, Eerste zinvolle tekenbewerking"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Verbeteringen voor eerste tekenbewerking"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Deze optimalisaties kunnen het laden van je pagina versnellen."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Aanbevelingen"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Statistieken"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Verbeter de algemene laadfunctionaliteit, zodat de pagina zo snel mogelijk reageert en gebruiksklaar is. Belangrijkste statistieken: Tijd tot interactief, Snelheidsindex"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Algemene verbeteringen"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Prestaties"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache-TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Grootte (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Bestede tijd"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potentiële besparing (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potentiële besparing (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potentiële besparing van {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potentiële besparing van {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Controles weergeven"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Beginnavigatie"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximum wachttijd voor kritiek pad:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Fout"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Rapportfout: geen controlegegevens"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Labgegevens"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analyse met [Lighthouse](https://developers.google.com/web/tools/lighthouse/) van de huidige pagina bij een 3G-emulatie. Waarden worden geschat en kunnen variëren."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Aanvullende items om handmatig te controleren"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"N.v.t."},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Aanbeveling"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Geschatte besparing"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Geslaagde controles"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Scoreschaal:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Er zijn problemen opgetreden bij deze uitvoering van Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Waarden worden geschat en kunnen variëren."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Waarschuwingen: "}};
-
-
-},{}],63:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome-utvidelser gjør innlastingen av denne siden tregere. Prøv å revidere siden i inkognitomodus eller fra en Chrome-profil uten utvidelser."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Skriptevaluering"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Skriptparsing"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Totalt"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Vurder å redusere tiden som brukes til parsing, kompilering og kjøring i JS. Levering av mindre JS-nyttelaster kan bidra til dette. [Finn ut mer] (https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reduser JavaScript-kjøretiden"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript-kjøretid"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Store GIF-er er mindre effektive for levering av animert innhold. I stedet for GIF bør du vurdere bruk av MPEG4/WebM-videoer for animasjon og PNG/WebP for statiske bilder, da dette belaster nettverket mindre. [Finn ut mer] (https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Bruk videoformat for animert innhold"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Vurder «lat» innlasting av bilder som er utenfor skjermen eller skjult, etter at alle kritiske ressurser er ferdig innlastet, for å redusere tiden det tar før siden blir interaktiv. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Utsett bilder utenfor skjermen"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ressurser blokkerer den første opptegningen av siden din. Vurder å levere kritisk JS/CSS innebygd og utsette all JS / alle stiler som ikke er kritiske. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Eliminer ressurser som blokkerer gjengivelse"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Store nettverksressurser koster brukerne mer og er hovedgrunnen til lange innlastingstider. [Finn ut mer] (https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Den totale størrelsen var {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Unngå enorme nettverksressurser"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Unngår enorme nettverksbelastninger"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Forminskede CSS-filer kan redusere nettverksbelastningen. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Forminsk CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Forminsking av JavaScript-filer kan redusere nyttelaststørrelser og parsetiden for skript. [Finn ut mer](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Forminsk JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Fjern ubrukte regler fra stilark for å redusere unødvendige byte som brukes av nettverksaktiviteten. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Utsett ubrukt CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Fjern ubrukt JavaScript for å redusere antall byte som brukes av nettverksaktiviteten."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Fjern ubrukt JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"En lang bufferlevetid kan øke antall gjentatte besøk på siden din. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ressurs funnet}other{# ressurser funnet}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Vis statiske ressurser med effektive buffer-retningslinjer"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Bruker effektive buffer-retningslinjer på statiske ressurser"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimaliserte bilder lastes inn raskere og bruker mindre mobildata [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Effektiviser omgjøring av bilder til kode"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Vis bilder som har passende størrelse, for å spare mobildata og få kortere innlastingstid. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Velg riktige bildestørrelser"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Tekstbaserte ressurser bør leveres komprimert (gzip, deflate eller brotli) for å minimerer antall byte gjennom nettverket. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Aktiver tekstkomprimering"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Bildeformater som JPEG 2000, JPEG XR og WebP gir ofte bedre komprimering enn PNG eller JPEG, noe som betyr raskere nedlasting og mindre databruk. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Bruk nyere bildeformater"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"De kritiske forespørselskjedene nedenfor viser hvilke ressurser som er utstedt med høy prioritet. Vurder å redusere lengden på kjedene, redusere nedlastingsstørrelsen på ressurser eller utsette nedlasting av unødvendige ressurser for å bedre sideinnlastingen. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 kjede funnet}other{# kjeder funnet}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimer dybden på kritiske forespørsler"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Nettlesereksperter anbefaler at sider inneholder mindre enn ca. 1500 DOM-noder. Den perfekte verdien er en tredybde på mindre enn 32 elementer og mindre enn 60 underordnede/overordnede elementer. En stor DOM-struktur kan øke minnebruken, føre til at [stilberegninger](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) tar lengre tid, og forårsake kostbare [gjenoppbygginger av sidevisningen](https://developers.google.com/speed/articles/reflow). [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 node}other{# noder}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Unngå for stor DOM-struktur"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimal DOM-dybde"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Totalt antall DOM-noder"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Unngå for stor DOM-struktur"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Bruk CSS-funksjonen font-display til å forsikre deg om at brukerne ser teksten mens skrifttypen for nettet lastes inn. [Finn ut mer](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Sørg for at teksten forblir synlig under innlasting av skrifttyper for nettet"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"All tekst forblir synlig under innlasting av skrifttype for nettet"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategori"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Vurder å redusere tiden som brukes til parsing, kompilering og kjøring i JS. Levering av mindre JS-ressurser kan bidra til dette."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimer arbeidet på hovedtråden"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimerer arbeidet på hovedtråden"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Poengsummen ovenfor er et estimat av hvor lang tid (i millisekunder) det tar for appen din å svare på brukerinndata i det travleste 5-sekunders vinduet av sideinnlastingen. Hvis tidsforsinkelsen er høyere enn 50 ms, kan brukeren oppleve appen din som treg. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Anslått tidsforsinkelse for inndata"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Den første innholdsrike opptegningen (FCP) markerer den første gangen tekst eller bilder tegnes opp. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Første innholdsrike opptegning"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Første prosessor ledig markerer den første gangen sidens hovedtråd er stille nok til å klare å håndtere inndata. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Første prosessor ledig"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Første vesentlige opptegning måler når hovedinnholdet på en side er synlig. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Første vesentlige opptegning"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Tid til interaktiv markerer tiden når siden er helt interaktiv. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tid til interaktiv"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Hastighetsindeksen viser hvor raskt innhold på en side blir synlig. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Hastighetsindeks"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Viderekoblinger fører til flere forsinkelser før siden kan lastes inn. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Unngå flere viderekoblinger av siden"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Tid til første byte identifiserer tidspunktet da tjeneren sendte et svar. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Root-dokumentet brukte {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reduser responstiden for tjener (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Svartiden til tjeneren er lav (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Varighet"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Navn"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Starttid"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Type"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Vurder å utstyre appen din med User Timing API for å måle appens reelle ytelse under viktige brukeropplevelser. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{ 1 brukertiming}other{# brukertiminger}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing – merker og intervaller"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Vurder å legge til ressurshint (preconnect eller dns-prefetch) for å opprette tidlige tilkoblinger til viktige tredjepartsplasseringer. [Finn ut mer] (https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Opprett forhåndstilkobling til nødvendige domenenavn"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Vurder bruk av <link rel=preload> for å prioritere henting av ressurser som for øyeblikket er forespurt senere i sideinnlastingen. [Finn ut mer](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Forhåndsinnlast (preload) nøkkelforespørsler"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Mer informasjon om ytelsen til appen din."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostikk"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Det mest kritiske aspektet for ytelse er hvor raskt piksler blir gjengitt på skjermen. Nøkkelberegninger: Første innholdsrike opptegning, Første vesentlige opptegning"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Forbedringer av første opptegning"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Disse optimaliseringene kan gjøre sideinnlastingen raskere."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Muligheter"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Beregninger"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Gjør den totale innlastingsopplevelsen bedre, slik at siden reagerer og er klar til bruk så snart som mulig. Nøkkelberegninger: Tid til interaktiv, Hastighetsindeks"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Forbedringsmuligheter"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Resultater"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Buffer-TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Størrelse (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Brukt tid"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"Nettadresse"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potensielle besparelser (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potensielle besparelser (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potensielle besparelser på {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potensiell besparelse på {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Vis revisjoner"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navigasjonsstart"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksimum kritisk baneforsinkelse:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Feil!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Rapportfeil: ingen revisjonsinformasjon"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Prøvefunksjonsdata"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse]-analyse (https://developers.google.com/web/tools/lighthouse/) av den gjeldende siden på emulert 3G. Verdiene er anslått og kan variere."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Tilleggselementer for manuell kontroll"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Ikke relevant"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Mulighet"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Estimerte besparelser"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Beståtte revisjoner"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Poengskala:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Det oppsto problemer som påvirker denne kjøringen av Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Verdiene er anslått og kan variere."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Advarsler: "}};
-
-
-},{}],64:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Rozszerzenia Chrome pogorszyły szybkość ładowania tej strony. Przeprowadź audyt strony w trybie incognito lub w profilu Chrome bez rozszerzeń."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Ocena skryptu"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Analiza skryptów"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Razem"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Pomyśl o skróceniu czasu poświęcanego na analizowanie, kompilowanie i wykonywanie kodu JS. Może w tym pomóc dostarczanie mniejszych ładunków JS. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/bootup)"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Skróć czas wykonywania JavaScriptu"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Czas wykonania JavaScriptu"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Duże pliki GIF są nieefektywnym sposobem dostarczania animacji. Proponujemy użyć zamiast nich filmów MPEG4/WebM (animacje) lub plików PNG/WebP (obrazy statyczne), by zmniejszyć ilość przesyłanych danych. [Więcej informacji](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Użyj formatów wideo dla animacji"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Rozważ opóźnione (leniwe) ładowanie obrazów ukrytych i znajdujących się poza ekranem dopiero po zakończeniu ładowania wszystkich zasobów kluczowych, by skrócić czas do pełnej interaktywności. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Odłóż ładowanie obrazów poza ekranem"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Zasoby blokują pierwsze wyrenderowanie strony. Rozważ umieszczenie krytycznego kodu JS/CSS w kodzie strony i opóźnienie ładowania wszystkich niekrytycznych plików JS i stylów. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Wyeliminuj zasoby blokujące renderowanie"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Duże ładunki sieciowe powodują wyższe koszty dla użytkowników i są mocno powiązane z długim czasem ładowania. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Łączny rozmiar to {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Unikaj bardzo dużych ładunków sieciowych"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Unikaj bardzo dużych ładunków sieciowych"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Minifikacja plików CSS może zmniejszyć ładunki sieciowe. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/minify-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minifikuj CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Minifikacja plików JavaScript może zmniejszyć ładunki i skrócić czas analizowania skryptów. [Więcej informacji](https://developers.google.com/speed/docs/insights/MinifyResources)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minifikuj JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Usuń nieużywane reguły z arkuszy stylów, by zmniejszyć ilość danych przesyłanych w sieci. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/unused-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Opóźnij ładowanie nieużywanego kodu CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Usuń nieużywany kod JavaScript, by zmniejszyć ilość danych przesyłanych w sieci."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Usuń nieużywany JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Długi czas przechowywania w pamięci podręcznej może przyspieszyć ponowne otwarcie strony. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Znaleziono 1 zasób}few{Znaleziono # zasoby}many{Znaleziono # zasobów}other{Znaleziono # zasobu}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Wyświetlaj zasoby statyczne, stosując efektywne zasady pamięci podręcznej"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Stosuje efektywne zasady pamięci podręcznej dla zasobów statycznych"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Zoptymalizowane obrazy ładują się szybciej i wykorzystują mniej komórkowej transmisji danych. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Użyj efektywnego kodowania obrazów"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Wyświetlaj obrazy o odpowiednim rozmiarze, by oszczędzać komórkową transmisję danych i przyspieszyć ładowanie. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Zmień rozmiar obrazów"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Zasoby tekstowe powinny być kompresowane (gzip, deflate lub brotli), by zminimalizować ilość danych przesyłanych w sieci. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Włącz kompresję tekstu"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formaty obrazów, takie jak JPEG 2000, JPEG XR i WebP, często dają lepszą kompresję niż PNG czy JPEG, co przekłada się na szybsze pobieranie i mniejsze wykorzystanie danych. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/webp)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Wyświetlaj obrazy w formatach nowej generacji"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Poniższe łańcuchy żądań krytycznych pokazują zasoby ładowane z wysokim priorytetem. Aby przyspieszyć ładowanie strony, możesz skrócić łańcuchy, zmniejszyć rozmiar pobieranych zasobów lub opóźnić pobieranie zasobów, które nie są niezbędne. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Znaleziono 1 łańcuch}few{Znaleziono # łańcuchy}many{Znaleziono # łańcuchów}other{Znaleziono # łańcucha}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Zminimalizuj głębię żądań krytycznych"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Twórcy przeglądarek zalecają, by strony zawierały mniej niż około 1500 węzłów DOM. Optymalne jest drzewo o głębokości mniejszej niż 32 elementy i zawierające mniej niż 60 elementów podrzędnych/nadrzędnych. Duży DOM może zwiększyć wykorzystanie pamięci, wydłużyć [obliczanie stylów](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) i powodować kosztowne [przeformatowanie układu](https://developers.google.com/speed/articles/reflow). [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/dom-size)"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 węzeł}few{# węzły}many{# węzłów}other{# węzła}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Unikaj zbyt dużego DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksymalna głębokość DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Łączna liczba węzłów DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Unika zbyt dużego DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Użyj funkcji CSS „font-display”, by zapewnić widoczność tekstu dla użytkownika podczas ładowania czcionek internetowych. [Więcej informacji](https://developers.google.com/web/updates/2016/02/font-display)"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Zapewnij widoczność tekstu podczas ładowania czcionek internetowych"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Cały tekst pozostaje widoczny podczas ładowania czcionek internetowych"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategoria"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Pomyśl o skróceniu czasu poświęcanego na analizowanie, kompilowanie i wykonywanie kodu JS. Może w tym pomóc dostarczanie mniejszych ładunków JS."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Zminimalizuj aktywność głównego wątku"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimalizuje aktywność głównego wątku"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Powyższy wynik jest szacunkowym czasem (w milisekundach), po którym aplikacja reaguje na działanie użytkownika w trakcie najbardziej intensywnego, pięciosekundowego okresu ładowania strony. Jeśli opóźnienie jest większe niż 50 ms, użytkownicy mogą uznać aplikację za powolną. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Szacowane opóźnienie reakcji"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Pierwsze wyrenderowanie treści oznacza czas wyrenderowania pierwszego tekstu lub obrazu. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Pierwsze wyrenderowanie treści"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"CPU bezczynny po raz pierwszy oznacza czas, gdy wątek główny jest po raz pierwszy na tyle mało obciążony, że może obsługiwać działania użytkownika. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU bezczynny po raz pierwszy"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Pierwsze wyrenderowanie czegoś znaczącego oznacza czas pojawienia się na ekranie głównej zawartości strony. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Pierwsze wyrenderowanie czegoś znaczącego"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Czas do pełnej interaktywności oznacza czas, po którym strona jest całkowicie interaktywna. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Czas do pełnej interaktywności"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Indeks szybkości wskazuje, jak szybko strona zapełnia się widocznymi treściami. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/speed-index)"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indeks szybkości"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Przekierowania wprowadzają dodatkowe opóźnienia przed rozpoczęciem ładowania strony. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/redirects)"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Unikaj wielokrotnych przekierowań"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Czas do pierwszego bajtu oznacza czas wysłania odpowiedzi przez serwer. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/ttfb)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Czas odpowiedzi głównego dokumentu: {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Skróć czasy reakcji serwera (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Czasy odpowiedzi serwera są krótkie (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Czas trwania"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nazwa"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Czas rozpoczęcia"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Typ"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Do aplikacji możesz dodać obsługę interfejsu User Timing API, by mierzyć rzeczywistą szybkość aplikacji z punktu widzenia użytkownika. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/user-timing)"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 czas działań użytkownika}few{# czasy działań użytkownika}many{# czasów działań użytkownika}other{# czasu działań użytkownika}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Znaczniki i odcinki Czasu działań użytkownika"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Rozważ dodanie wskazówek „preconnect” lub „dns-prefetch”, by wcześniej nawiązać połączenia z ważnymi źródłami w innych domenach. [Więcej informacji](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Wcześniej nawiąż połączenia z wymaganymi źródłami"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Pomyśl o użyciu deklaracji <link rel=preload>, by szybciej pobierały się zasoby, które są obecnie żądane na dalszym etapie ładowania strony. [Więcej informacji](https://developers.google.com/web/tools/lighthouse/audits/preload)"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Załaduj wstępnie kluczowe żądania"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Więcej informacji o wydajności aplikacji."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostyka"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Najważniejszym aspektem wydajności jest to, jak szybko piksele zostaną wyświetlone na ekranie. Kluczowe wskaźniki: Pierwsze wyrenderowanie treści, Pierwsze wyrenderowanie czegoś znaczącego"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Ulepszenia pierwszego renderowania"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Te optymalizacje mogą przyspieszyć ładowanie stron."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Możliwości"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Dane"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Usprawnij całe ładowanie, by strona jak najszybciej była gotowa do używania i reagowała na działania użytkownika. Główne wskaźniki: Czas do pełnej interaktywności, Indeks szybkości"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Ogólne usprawnienia"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Wydajność"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Czas przechowywania danych w pamięci podręcznej"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Rozmiar (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Spędzony czas"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potencjalne oszczędności (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potencjalne oszczędności (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potencjalna oszczędność: {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potencjalne przyspieszenie o {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Pokaż audyty"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Początkowa nawigacja"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksymalne opóźnienie ścieżki krytycznej:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Błąd"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Błąd raportu: brak informacji o audycie"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Dane laboratoryjne"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analiza [Lighthouse](https://developers.google.com/web/tools/lighthouse/) bieżącej strony przy emulowanym połączeniu 3G. Wartości są szacunkowe i mogą się zmieniać."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Dodatkowe elementy do ręcznego sprawdzenia"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nie dotyczy"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Możliwość"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Szacowane oszczędności"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Zaliczone audyty"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Skala wyników:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Podczas tego uruchomienia Lighthouse wystąpiły problemy:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Wartości są szacunkowe i mogą się zmieniać."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Ostrzeżenia "}};
-
-
-},{}],65:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"As extensões do Chrome afetam negativamente o desempenho de carregamento desta página. Experimente efetuar uma auditoria à página no modo de navegação anónima ou com um perfil do Chrome sem extensões."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Avaliação do script"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Análise do script"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Considere reduzir o tempo despendido a analisar, compilar e executar JS. Poderá descobrir que é útil fornecer payloads de JS mais pequenos. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reduza o tempo de execução de JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Tempo de execução de JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Os GIFs grandes são ineficientes para publicar conteúdo animado. Para poupar bytes de rede, considere utilizar vídeos MPEG4/WebM para animações e ficheiros PNG/WebP para imagens estáticas em vez de GIFs. [Saiba mais](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)."},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Utilize formatos de vídeo para conteúdo animado"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Considere utilizar imagens de carregamento lento não visíveis e ocultas após a conclusão do carregamento de todos os recursos críticos, para reduzir o tempo até à interação. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Adie as imagens não visíveis"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"O primeiro preenchimento da sua página está a ser bloqueado por recursos. Considere publicar JS/CSS críticos inline e adiar todos os JS/estilos não críticos. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Elimine recursos que bloqueiam o processamento"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Os grandes payloads de rede têm custos reais para os utilizadores e estão fortemente correlacionados com tempos de carregamento demorados. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"O tamanho total foi de {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Evite enormes payloads de rede"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Evita enormes payloads de rede"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Reduzir os ficheiros CSS pode reduzir os tamanhos dos payloads de rede. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Reduza o CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Reduzir os ficheiros JavaScript pode reduzir os tamanhos dos payloads e o tempo de análise de scripts. [Saiba mais](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Reduza o JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Remova regras não utilizadas das folhas de estilos para reduzir a quantidade de bytes desnecessários consumidos pela atividade da rede. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Adie o CSS não utilizado"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Remova o JavaScript não utilizado para reduzir os bytes consumidos pela atividade da rede."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Remova o JavaScript não utilizado"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Uma duração total longa da cache pode acelerar as visitas repetidas à sua página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 recurso encontrado}other{# recursos encontrados}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Publique recursos estáticos com uma política de cache eficiente"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Utiliza uma política de cache eficiente em recursos estáticos"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"As imagens otimizadas são carregadas mais rapidamente e consomem menos dados móveis. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codifique as imagens de forma eficiente"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Publique imagens com um tamanho adequado para poupar dados móveis e melhorar o tempo de carregamento. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Dimensione adequadamente as imagens"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Os recursos baseados em texto devem ser publicados com compressão (gzip, Deflate ou Brotli) para reduzir o total de bytes de rede. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Ative a compressão de texto"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Muitas vezes, os formatos de imagem como JPEG 2000, JPEG XR e WebP proporcionam uma melhor compressão do que os formatos PNG ou JPEG, o que se traduz em transferências mais rápidas e num menor consumo de dados. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Publique imagens em formatos de última geração"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"As Cadeias de pedidos críticos abaixo apresentam os recursos que são carregados com uma prioridade elevada. Pondere reduzir o comprimento das cadeias, reduzir o tamanho de transferência dos recursos ou adiar a transferência de recursos desnecessários para melhorar o carregamento da página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 cadeia encontrada}other{# cadeias encontradas}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Reduza a profundidade de pedidos críticos"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Os engenheiros de navegadores recomendam que as páginas contenham menos de ~1500 nós de DOM. O ideal é uma árvore com uma profundidade < 32 elementos e menos de 60 elementos superiores/secundários. Um DOM grande pode aumentar a utilização da memória, gerar [cálculos de estilo](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) mais demorados e produzir [ajustes de esquema](https://developers.google.com/speed/articles/reflow) dispendiosos. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nó}other{# nós}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Evite um tamanho excessivo do DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Profundidade máxima do DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total de nós do DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Evita um tamanho excessivo do DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Tire partido da funcionalidade CSS de apresentação de tipos de letra para garantir que o texto é visível para o utilizador enquanto os tipos de letra para Websites são carregados. [Saiba mais](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Garanta que o texto permanece visível durante o carregamento de tipos de letra para Websites"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Todo o texto permanece visível durante os carregamentos de tipos de letra para Websites"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categoria"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Considere reduzir o tempo despendido a analisar, compilar e executar JS. Poderá descobrir que é útil fornecer payloads de JS mais pequenos."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Reduzir as operações do thread principal"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Reduz as operações do thread principal"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"A pontuação acima é uma estimativa do tempo que a sua aplicação demora a responder a ações do utilizador, em milissegundos, durante a janela dos 5 segundos mais ativos de carregamento de página. Se a latência for superior a 50 ms, os utilizadores poderão considerar que a sua aplicação é lenta. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Latência estimada das ações"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"O Primeiro preenchimento com conteúdo assinala o momento de preenchimento com o primeiro texto ou a primeira imagem. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Primeiro preenchimento com conteúdo"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"A métrica Primeira CPU inativa indica quando é que o thread principal da página está suficientemente inativo pela primeira vez para processar ações. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Primeira CPU inativa"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"A métrica Primeiro preenchimento significativo mede quando é que o conteúdo principal de uma página fica visível. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Primeiro preenchimento significativo"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"A métrica Tempo até à interação indica quando é que a página fica completamente interativa. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tempo até à interação"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"A métrica Índice de velocidade apresenta a rapidez de preenchimento visível dos conteúdos de uma página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Índice de velocidade"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"A auditoria Redirecionamentos introduz atrasos adicionais antes do carregamento da página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Evite vários redirecionamentos de página"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"A auditoria Tempo até ao primeiro byte indica o tempo de envio de uma resposta pelo seu servidor. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"O documento de raiz demorou {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reduza os tempos de resposta do servidor (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Os tempos de resposta do servidor são curtos (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Duração"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nome"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Hora de início"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tipo"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Pondere a possibilidade de complementar a sua aplicação com a API Tempos do utilizador para analisar o desempenho da aplicação no mundo real durante as principais experiências do utilizador. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 tempo do utilizador}other{# tempos do utilizador}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Marcas e medições de Tempos do utilizador"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Considere adicionar instruções para recursos de pré-ligação ou de obtenção prévia de DNS para estabelecer ligações antecipadamente a origens de terceiros importantes. [Saiba mais](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Efetue a pré-ligação às origens necessárias"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Considere utilizar <link rel=preload> para dar prioridade à obtenção de recursos que são atualmente solicitados mais tarde no carregamento de página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Pré-carregue pedidos-chave"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Mais informações sobre o desempenho da sua aplicação."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnósticos"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"O aspeto mais importante do desempenho é a rapidez de renderização dos píxeis no ecrã. Métricas principais: Primeiro preenchimento com conteúdo, Primeiro preenchimento significativo."},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Melhorias no primeiro preenchimento"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Estas otimizações podem acelerar o carregamento da sua página."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Oportunidades"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Métricas"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Melhore a experiência de carregamento geral para que a página responda e fique pronta a utilizar logo que possível. Métricas principais: Tempo até à interação, Índice de velocidade."},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Melhorias gerais"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Desempenho"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL da cache"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Tamanho (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Tempo gasto"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Poupança potencial (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Poupança potencial (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Poupança potencial de {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Poupança potencial de {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} seg"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Mostrar auditorias"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navegação inicial"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latência crítica máxima do caminho:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Erro!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Erro de relatório: sem informações de auditoria"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Dados laboratoriais"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) análise da página atual em rede 3G emulada. Os valores são aproximados e podem variar."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Itens adicionais a verificar manualmente"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Não aplicável"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Oportunidade"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Poupança estimada"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Auditorias aprovadas"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Escala da pontuação:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Ocorreram problemas que afetaram esta execução do Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Os valores são estimados e podem variar."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Avisos: "}};
-
-
-},{}],66:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"As extensões do Chrome afetaram negativamente o desempenho de carregamento desta página. Tente fazer a auditoria da página no modo de navegação anônima ou em um perfil do Chrome sem extensões."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Avaliação de script"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Análise de script"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Reduza o tempo gasto com análise, compilação e execução de JS. Você perceberá que exibir payloads de JS menores ajuda a fazer isso. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Reduza o tempo de execução de JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Tempo de execução de JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"GIFs grandes são ineficazes para exibir conteúdo animado. Use vídeos MPEG4/WebM para animações e PNG/WebP para imagens estáticas em vez de GIF, para economizar bytes de rede. [Saiba mais](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Use formatos de vídeo para conteúdo animado"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Use o carregamento lento para imagens fora da tela e ocultas depois que todos os recursos críticos já estiverem carregados, para reduzir o tempo necessário até que a página se torne interativa. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Adie imagens fora da tela"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Alguns recursos estão bloqueando o primeiro aparecimento da sua página. Considere exibir JS/CSS crítico inline e adiar todos os JS/estilos não críticos. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Elimine recursos que impedem a renderização"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Grandes payloads de rede geram custos para os usuários e estão altamente relacionados a tempos maiores de carregamento. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"O tamanho total foi de {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Evite payloads de rede muito grandes"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Evita payloads de rede muito grandes"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"A redução de arquivos CSS pode diminuir o tamanho do payload de rede. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Reduza o CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"A redução de arquivos JavaScript pode diminuir o tamanho de payloads e o tempo de análise de scripts. [Saiba mais](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Reduza o JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Remova regras não utilizadas das folhas de estilos para reduzir o consumo desnecessário de bytes da atividade de rede. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Adie CSS não utilizado"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Remova o JavaScript não utilizado para reduzir o consumo de bytes da atividade de rede."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Remova o JavaScript não utilizado"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Um cache com ciclo de vida longo pode acelerar visitas repetidas à sua página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 recurso encontrado}one{# recurso encontrado}other{# recursos encontrados}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Disponibilize recursos estáticos com uma política de cache eficiente"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Usa uma política de cache eficiente em recursos estáticos"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Imagens otimizadas são carregadas mais rapidamente e consomem menos dados da rede celular. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codifique as imagens com eficiência"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Disponibilize imagens de tamanho adequado para economizar dados da rede celular e melhorar o tempo de carregamento. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Defina um tamanho adequado para as imagens"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Os recursos baseados em texto precisam ser disponibilizados com compactação (gzip, deflate ou brotli) para reduzir o total de bytes da rede. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Ative a compactação de texto"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formatos de imagem como JPEG 2000, JPEG XR e WebP geralmente resultam em uma compactação melhor em comparação a PNG ou JPEG, o que significa downloads mais rápidos e menor consumo de dados. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Disponibilize imagens em formatos de última geração"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"As redes de solicitações críticas abaixo mostram os recursos carregados com alta prioridade. Reduza o tamanho das redes ao diminuir o tamanho do download dos recursos ou ao adiar o download de recursos desnecessários para melhorar o carregamento de página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 rede encontrada}one{# rede encontrada}other{# redes encontradas}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Reduza a profundidade de solicitações críticas"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Os engenheiros de navegador recomendam que as páginas tenham menos de ~1.500 nós de DOM. O ideal é uma profundidade de árvore com < 32 elementos e menos de 60 elementos filhos/pais. Um DOM grande pode aumentar o uso da memória, causar [cálculos de estilo] mais longos (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) e produzir [reflows de layout] de alto custo (https://developers.google.com/speed/articles/reflow). [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nó}one{# nó}other{# nós}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Evite DOM de tamanho excessivo"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Profundidade máxima de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Total de nós de DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Evita DOM de tamanho excessivo"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Use o recurso CSS de exibição de fonte para garantir que o texto possa ser visto pelo usuário enquanto as webfonts são carregadas. [Saiba mais](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Garanta que o texto continue visível durante o carregamento da webfont"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Todo o texto continua visível durante o carregamento da webfont"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categoria"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Reduza o tempo gasto com análise, compilação e execução de JS. Você perceberá que exibir payloads de JS menores ajuda a fazer isso."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimize o trabalho da thread principal"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimiza o trabalho da thread principal"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"A pontuação acima é uma estimativa do tempo que seu aplicativo leva para responder à atividade do usuário, em milésimos de segundo, durante a janela de carregamento de página mais movimentada de cinco segundos. Se a latência for superior a 50 ms, o usuário poderá notar lentidão no aplicativo. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Latência de entrada estimada"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"A primeira exibição de conteúdo marca o momento em que o primeiro texto ou imagem é disponibilizado. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Primeiro aparecimento com conteúdo"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"\"Primeira CPU ociosa\" marca a primeira vez que a thread principal da página fica silenciosa o suficiente para lidar com a entrada. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Primeira CPU ociosa"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"\"Primeiro aparecimento importante\" marca o momento em que o conteúdo principal de uma página se torna visível. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Primeiro aparecimento importante"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"\"Interativa\" marca o momento em que a página se torna totalmente interativa. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tempo até ficar interativa"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"O Índice de velocidade mostra a rapidez com que o conteúdo de uma página é preenchido visivelmente. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Índice de velocidade"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Os redirecionamentos causam mais atrasos antes do carregamento da página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Evite redirecionamentos múltiplos de página"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"\"Tempo até o primeiro byte\" identifica o momento em que seu servidor envia uma resposta. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"O documento raiz levou {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Reduza os tempos de resposta do servidor (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Os tempos de resposta do servidor são baixos (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Duração"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nome"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Horário de início"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tipo"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Instrumente seu app com a User Timing API para medir o desempenho real do app durante as principais experiências do usuário. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 velocidade do usuário}one{# velocidade do usuário}other{# velocidades do usuário}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Marcações e medições de User Timing"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Adicione dicas de recursos de pré-conexão ou pré-busca de DNS para estabelecer conexões antecipadas a origens importantes de terceiros. [Saiba mais](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Pré-conecte às origens necessárias"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Use <link rel=preload> para priorizar a busca posterior de recursos solicitados atualmente no carregamento de página. [Saiba mais](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Pré-carregue as principais solicitações"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Mais informações sobre o desempenho do seu aplicativo."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnóstico"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"O aspecto de desempenho mais importante é a rapidez com que os pixels são renderizados na tela. Principais métricas: Primeiro aparecimento com conteúdo, Primeiro aparecimento importante"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Melhorias do primeiro aparecimento"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Essas otimizações podem acelerar o carregamento de página."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Oportunidades"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Métricas"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Aprimore a experiência geral de carregamento, para que a página seja responsiva e esteja pronta para ser usada assim que possível. Principais métricas: Tempo até fica interativa, Índice de velocidade"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Melhorias gerais"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Desempenho"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Cache TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Tamanho (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Tempo gasto"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Possível economia (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Possível economia (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Possível economia de {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Possível economia de {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Mostrar auditorias"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navegação inicial"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latência máxima do caminho crítico:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Erro!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Informar erro: nenhuma informação de auditoria"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Dados de laboratório"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Análise do [Lighthouse](https://developers.google.com/web/tools/lighthouse/) da página atual em emulação de 3G. Os valores indicados são estimativas e podem variar."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Outros itens para verificação manual"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Não aplicável"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Oportunidade"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Economia estimada"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Auditorias aprovadas"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Escala de pontuação:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Alguns problemas afetaram esta execução do Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Os valores são estimados e podem variar."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Avisos: "}};
-
-
-},{}],67:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Extensiile Chrome au afectat performanța de încărcare a acestei pagini. Încearcă să auditezi pagina în modul incognito sau dintr-un profil Chrome fără extensii."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Evaluarea scripturilor"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Analizarea scripturilor"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Total"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Poți reduce timpul petrecut cu analizarea, compilarea și executarea JS. Livrarea unor sarcini JS mai mici poate ajuta în acest sens. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Redu timpul de execuție JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Timpul de executare JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"GIF-urile mari nu sunt eficiente pentru difuzarea conținutului animat. Folosește videoclipuri MPEG4/WebM pentru animații și PNG/WebP pentru imagini statice în locul GIF-urilor ca să economisești date în rețea. [Află mai multe](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Folosește formate video pentru conținut animat"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Poți încărca lent imaginile ascunse sau pe cele din afara ecranului după ce toate resursele esențiale s-au încărcat, pentru a micșora durata până la interactivitate. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Amână imaginile din afara ecranului"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resursele blochează prima redare a paginii. Poți să livrezi conținutul JS/CSS esențial inline și să amâni toate elementele JS/stilurile neesențiale. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Elimină resursele care blochează redarea"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Sarcinile mari de rețea îi costă pe utilizatori și sunt corelate cu timpi de încărcare îndelungați. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Dimensiunea totală a fost de {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Evită sarcinile uriașe de rețea"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Evită sarcinile uriașe de rețea"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Comprimarea fișierelor CSS poate reduce dimensiunea sarcinilor de rețea. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Comprimă codul CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Comprimarea fișierelor JavaScript poate reduce dimensiunea sarcinilor și timpul de analizare a scripturilor. [Află mai multe](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Comprimă codul JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Elimină regulile nefolosite din foile de stil pentru a reduce byții inutili consumați de activitatea rețelei. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Amână conținutul CSS nefolosit"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Elimină codul JavaScript nefolosit pentru a reduce byții consumați de activitatea rețelei."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Elimină codul JavaScript nefolosit"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"O durată lungă a memoriei cache poate grăbi accesările repetate ale paginii. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{o resursă găsită}few{# resurse găsite}other{# de resurse găsite}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Difuzează elementele statice cu o politică eficientă de stocare în memoria cache"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Folosește o politică eficientă de stocare în memoria cache pentru elementele statice"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Imaginile optimizate se încarcă mai repede și consumă mai puține date mobile. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Codifică eficient imaginile"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Difuzează imagini de dimensiuni corespunzătoare ca să economisești date mobile și să obții o încărcare mai rapidă. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Dimensionează corect imaginile"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Înainte de difuzare, resursele bazate pe text trebuie comprimate (gzip, deflate sau brotli) pentru a minimiza numărul total de byți în rețea. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Activează comprimarea textului"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formatele de imagine ca JPEG 2000, JPEG XR și WebP oferă adesea o comprimare mai bună decât PNG sau JPEG, ceea ce înseamnă descărcări mai rapide și mai puțin consum de date. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Difuzează imagini în formate moderne"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Lanțurile de solicitări esențiale de mai jos îți arată ce resurse sunt încărcate cu prioritate ridicată. Poți să reduci lungimea lanțurilor, să reduci dimensiunea de descărcare a resurselor sau să amâni descărcarea de resurse inutile pentru a îmbunătăți încărcarea paginilor. [Află mai multe] (https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{un lanț găsit}few{# lanțuri găsite}other{# de lanțuri găsite}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Redu profunzimea solicitărilor esențiale"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Specialiștii în browsere recomandă ca paginile să conțină mai puțin de ~1.500 de noduri DOM. Ideal este ca arborele să aibă o profunzime mai mică de 32 de elemente și mai puțin de 60 de elemente principale/subordonate. Un DOM mare poate crește folosirea memoriei, poate produce [calcule de stil] (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) mai lungi și poate produce [rearanjări ale aspectului](https://developers.google.com/speed/articles/reflow). [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{un nod}few{# noduri}other{# de noduri}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Evită o dimensiune DOM excesivă"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Adâncimea DOM maximă"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Numărul total de noduri DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Evită o dimensiune DOM excesivă"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Poți folosi funcția CSS de afișare a fonturilor pentru a verifica dacă textul este vizibil pentru utilizatori în timp ce se încarcă fonturile web. [Află mai multe](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Asigură-te că textul rămâne vizibil în timpul încărcării fonturilor web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Tot textul rămâne vizibil în timpul încărcării fonturilor web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Categorie"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Poți reduce timpul petrecut cu analizarea, compilarea și executarea JS. Livrarea unor sarcini JS mai mici poate ajuta în acest sens."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimizează procesarea firului principal"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimizează procesarea firului principal"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Scorul de mai sus reprezintă o estimare a duratei necesare pentru ca aplicația să răspundă la comanda utilizatorului, în milisecunde, în cea mai aglomerată fereastră de 5 secunde de încărcare a paginii. Dacă latența este mai mare de 50 ms, utilizatorii îți pot percepe aplicația ca fiind lentă. [Află mai multe] (https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Latența estimată a comenzilor"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Prima redare de conținut arată momentul când se redă primul text sau prima imagine. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Prima redare de conținut"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Primul „CPU inactiv” semnalează primul moment în care firul principal al paginii este suficient de liber pentru a accepta comenzi. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Primul „CPU inactiv”"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Prima redare semnificativă arată momentul când este vizibil conținutul principal al unei pagini. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Prima redare semnificativă"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interactivitatea semnalează momentul când pagina este complet interactivă. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Timpul până la interactivitate"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Indexul de viteză arată cât de repede se completează vizibil conținutul unei pagini. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Index de viteză"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Redirecționările introduc întârzieri suplimentare înainte ca pagina să se poată încărca. [Află mai multe] (https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Evită mai multe redirecționări ale paginii"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Timpul până la primul byte identifică timpul în care serverul trimite un răspuns. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Documentul rădăcină a avut nevoie de {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Redu timpii de răspuns ai serverului (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Serverul răspunde repede (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Durată"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Nume"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Ora de începere"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tip"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Îți poți îmbunătăți aplicația cu API-ul User Timing ca să măsori performanța reală a acesteia în timpul experiențelor de utilizare principale. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{o durată a utilizării}few{# durate ale utilizărilor}other{# de durate ale utilizărilor}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Mărci și dimensiuni pentru Duratele utilizărilor"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Poți adăuga indicii de resurse de preconectare sau dns-prefetch pentru a stabili conexiuni inițiale cu originile terță parte importante. [Află mai multe](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Preconectează la originile necesare"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Poți folosi <link rel=preload> ca să acorzi prioritate preluării resurselor care sunt momentan solicitate mai târziu la încărcarea paginii. [Află mai multe](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Preîncarcă solicitările importante"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Mai multe informații despre performanța aplicației tale."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnosticare"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Cel mai important aspect al performanței este cât de repede se redau pixelii pe ecran. Valori cheie: prima redare de conținut, prima redare semnificativă"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Îmbunătățirile pentru prima redare"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Aceste optimizări pot accelera încărcarea paginii."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Oportunități"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Valori"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Îmbunătățește experiența globală de încărcare, astfel ca pagina să se afișeze și să fie gata de utilizare cât mai curând posibil. Valori cheie: timpul până la interactivitate, indexul de viteză"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Îmbunătățiri generale"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performanță"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL cache"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Dimensiune (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Timp petrecut"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"Adresa URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Economii potențiale (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Economii potențiale (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Poți economisi {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Poți economisi {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Afișează audituri"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Navigare inițială"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Latența maximă a căii critice:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Eroare!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Eroare de raport: nu există informații de auditare"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Datele testului"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analiza în [Lighthouse](https://developers.google.com/web/tools/lighthouse/) a paginii actuale cu o conexiune 3G emulată. Valorile sunt estimate și pot varia."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Elemente suplimentare de verificat manual"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nu se aplică"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Oportunitate"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Economii estimate"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Auditări trecute"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Scala scorului:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Au apărut probleme care au afectat această rulare Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Valorile sunt estimate și pot varia."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Avertismente: "}};
-
-
-},{}],68:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Расширения Chrome замедляют загрузку этой страницы. Попробуйте использовать режим инкогнито или профиль Chrome без расширений."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Время оценки скриптов"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Время анализа скриптов"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Всего"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Рекомендуем сократить время на анализ, компиляцию и выполнение скриптов JS. Для этого вы можете уменьшить размер фрагментов кода JS. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Сократите время выполнения кода JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Время выполнения кода JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Большие GIF-файлы – неэффективный способ представления анимации. Чтобы сэкономить трафик в сети, используйте видео в формате MPEG4/WebM для анимированного контента и изображения в формате PNG/WebP – для статического. [Подробнее…](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Используйте видеоформаты для анимированного контента"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Чтобы уменьшить время до начала взаимодействия, рекомендуем использовать принцип lazy loading для скрытых изображений после того, как все важные ресурсы будут загружены. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Отложите загрузку скрытых изображений"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Некоторые ресурсы препятствуют загрузке контента страницы. Рекомендуем настроить загрузку необходимых ресурсов JS/CSS в первую очередь и отложить загрузку остальных ресурсов. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Устраните ресурсы, блокирующие отображение"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Чрезмерная нагрузка на сеть стоит пользователям реальных денег и может стать причиной долгого ожидания при работе в Интернете. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Общий размер достиг {totalBytes, number, bytes} КБ"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Предотвратите чрезмерную нагрузку на сеть"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Предотвращение чрезмерной нагрузки на сеть"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Уменьшение CSS-файлов может сократить нагрузку на сеть. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Уменьшите размер кода CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Уменьшение файлов JavaScript может сократить размер фрагментов кода и время анализа скриптов. [Подробнее…](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Уменьшите размер кода JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Чтобы сократить расход трафика, удалите неиспользуемые правила из таблиц стилей. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Отложите загрузку неиспользуемого контента CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Чтобы сократить расход трафика, удалите неиспользуемый код JavaScript."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Удалите неиспользуемый код JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Длительное время хранения кеша может ускорить загрузку при повторных посещениях страницы. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Найден 1 ресурс}one{Найден # ресурс}few{Найдено # ресурса}many{Найдено # ресурсов}other{Найдено # ресурса}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Задайте правила эффективного использования кеша для статических объектов"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Настройка правил эффективного использования кеша для статических объектов"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Оптимизированные изображения загружаются быстрее и расходуют меньше мобильных данных. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Настройте эффективную кодировку изображений"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Чтобы сэкономить мобильные данные и ускорить загрузку, настройте подходящий размер изображений на странице. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Настройте подходящий размер изображений"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Чтобы уменьшить расход трафика в сети, рекомендуем использовать сжатие для текстовых ресурсов (gzip, deflate или brotli). [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Включите сжатие текста"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Для изображений в форматах JPEG 2000, JPEG XR и WebP используется более эффективное сжатие, поэтому они загружаются быстрее и потребляют меньше трафика, чем изображения PNG и JPEG. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Используйте современные форматы изображений"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Приведенные ниже цепочки критических запросов показывают, какие ресурсы загружаются с высоким приоритетом. Чтобы ускорить загрузку страниц, рекомендуем сократить длину цепочек, уменьшить размер скачиваемых ресурсов или отложить скачивание ненужных ресурсов. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Найдена 1 цепочка}one{Найдена # цепочка}few{Найдено # цепочки}many{Найдено # цепочек}other{Найдено # цепочки}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Сократите глубину вложенности критических запросов"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Разработчики браузеров рекомендуют, чтобы на странице было не более 1500 узлов DOM. Наилучшие показатели: глубина вложенности менее 32 элементов, количество дочерних и родительских элементов – менее 60. Сложная структура DOM может увеличить использование памяти, замедлить [вычисление стилей](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) и повысить затраты на [компоновку шаблонов](https://developers.google.com/speed/articles/reflow). [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 узел}one{# узел}few{# узла}many{# узлов}other{# узла}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Сократите размер структуры DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Максимальная глубина вложенности DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Общее количество узлов DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Сокращение размера структуры DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Чтобы пользователь мог видеть текст, пока веб-шрифты не загрузились, используйте функцию отображения шрифтов CSS. [Подробнее…](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Настройте показ всего текста во время загрузки веб-шрифтов"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Показ всего текста во время загрузки веб-шрифтов"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Категория"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Рекомендуем сократить время на анализ, компиляцию и выполнение скриптов JS. Для этого вы можете уменьшить размер фрагментов кода JS."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Минимизируйте работу в основном потоке"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Минимизация работы в основном потоке"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Это значение показывает время в миллисекундах, которое занимает реакция приложения на действия пользователя в течение самых занятых 5 с загрузки страницы. Если это время превышает 50 мс, пользователям может показаться, что ваше приложение работает с задержками. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Приблизительное время задержки при вводе"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Первая отрисовка контента – показатель, который определяет интервал времени между началом загрузки страницы и появлением первого изображения или блока текста. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Время загрузки первого контента"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Этот параметр показывается время, в которое основной поток страницы становится достаточно свободен для обработки ручного ввода. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Время окончания работы ЦП"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Этот параметр показывает время, по истечении которого становится виден основной контент страницы. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Время загрузки достаточной части контента"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Этот параметр представляет собой отметку времени, когда страница становится полностью готова к взаимодействию с пользователем. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Время загрузки для взаимодействия"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Индекс скорости загрузки показывает, насколько быстро контент страницы становится доступен для просмотра. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Индекс скорости загрузки"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Переадресация может стать причиной дополнительной задержки при загрузке страницы. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Избегайте большого количества переадресаций"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Время до получения первого байта показывает задержку, после которой с вашего сервера отправляется ответ на запрос. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Загрузка корневого документа заняла {timeInMs, number, milliseconds} мс"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Сократите время ответа сервера (время до получения первого байта)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Короткое время ответа сервера (время до получения первого байта)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Длительность"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Название"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Время начала"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Тип"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Используйте User Timing API, чтобы измерить реальную производительность своего приложения во время ключевых моментов взаимодействия с пользователями. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 временная метка}one{# временная метка}few{# временные метки}many{# временных меток}other{# временной метки}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Метки и промежутки пользовательского времени"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Чтобы быстро устанавливать соединение с необходимыми сторонними доменами, рекомендуем добавить ресурсные подсказки preconnect или dns-prefetch. [Подробнее…](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Используйте предварительное подключение к необходимым доменам"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Чтобы загружать требуемые ресурсы в порядке приоритета, вам следует использовать <link rel=предварительную загрузку>. [Подробнее…](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Настройте предварительную загрузку ключевых запросов"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Подробная информация о производительности вашего приложения."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Диагностика"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Один из самых важных параметров производительности – насколько быстро пиксели отображаются на экране. Ключевые показатели: \"Время загрузки первого контента\" и \"Время загрузки достаточной части контента\"."},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Уменьшение времени загрузки контента"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Эти действия по оптимизации могут ускорить загрузку страницы."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Оптимизация"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Показатели"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Улучшите параметры загрузки, чтобы страница была готова для работы как можно скорее. Ключевые показатели: \"Время загрузки для взаимодействия\" и \"Индекс скорости загрузки\"."},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Общие улучшения"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Производительность"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Время жизни кеша"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Размер (КБ)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Потраченное время"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Потенциальная экономия данных (КБ)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Потенциальная экономия времени (мс)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Потенциальная экономия данных: {wastedBytes, number, bytes} КБ"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Потенциальная экономия времени: {wastedMs, number, milliseconds} мс"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} мс"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} сек."},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Показать аудиты"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Начальная навигация"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Максимальная задержка критического пути:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Ошибка"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Ошибка отчета: информация аудита отсутствует"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Лабораторные данные"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Анализ [Lighthouse](https://developers.google.com/web/tools/lighthouse/) для текущей страницы в условиях эмулированной 3G-сети. Значения приблизительные и могут изменяться."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Дополнительные объекты для проверки вручную"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Неприменимо"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Возможности"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Приблизительная экономия"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Успешные аудиты"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Легенда:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Во время работы Lighthouse возникли следующие проблемы:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Значения приблизительные и могут изменяться."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Предупреждения: "}};
-
-
-},{}],69:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Rozšírenia pre Chrome negatívne ovplyvnili výkonnosť načítania tejto stránky. Skúste stránku skontrolovať v režime inkognito alebo profile Chrome bez rozšírení."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Hodnotenie skriptu"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Analýza skriptu"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Celkovo"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Zvážte skrátenie času stráveného analýzou, zostavovaním a spustením JavaScriptu. Možno vám s tým pomôže zobrazovanie menších prenášaných dát JavaScriptu. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Skráťte čas spustenia JavaScriptu"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Čas spustenia JavaScriptu"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Veľké GIFy nie sú vhodné na zobrazovanie animovaného obsahu. Namiesto nich odporúčame použiť videá MPEG4/WebM pre animácie a PNG/WebP pre statické obrázky, aby ste ušetrili spotrebu bajtov v sieti. [Ďalšie informácie](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Pre animovaný obsah použite formáty videa"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Zvážte oneskorené načítanie obrázkov, ktoré sú mimo obrazovky alebo skryté, a to až po dokončení načítania všetkých podstatných zdrojov, čím skrátite čas do interaktívneho vykreslenia. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Oddiaľte načítanie obrázkov mimo obrazovky"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Zdroje blokujú prvé vyfarbenie stránky. Zvážte zobrazovanie podstatných JavaScriptov alebo šablón CSS v texte a oddialenie všetkých nepodstatných JavaScriptov alebo štýlov. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Odstráňte zdroje blokujúce vykreslenie"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Veľké sieťové prenosy dát stoja používateľov mnoho peňazí a často sú spájané s dlhými časmi načítania. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Celková veľkosť bola {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Zabráňte nadmerným sieťovým prenosom dát"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Zabráni nadmerným sieťovým prenosom dát"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Minifikáciou súborov šablón CSS môžete znížiť veľkosti sieťových prenosov dát. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minifikujte súbory CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Minifikáciou súborov JavaScriptu môžete znížiť veľkosti prenášaných dát a čas analýzy skriptu. [Ďalšie informácie](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minifikujte JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Odstráňte nepoužívané pravidlá zo šablón štýlov a znížte tak zbytočnú spotrebu bajtov sieťovou aktivitou. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Oddiaľte nepoužívané šablóny CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Odstráňte nepoužívaný JavaScript a znížte tak spotrebu bajtov sieťovou aktivitou."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Odstráňte nepoužívaný JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Dlhá životnosť vyrovnávacej pamäte môže urýchliť opakované návštevy stránky. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Našiel sa 1 zdroj}few{Našli sa # zdroje}many{# resources found}other{Našlo sa # zdrojov}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Zobrazujte statické podklady s účinnými pravidlami ukladania do vyrovnávacej pamäte"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Používa účinné pravidlá ukladania do vyrovnávacej pamäte pre statické podklady"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimalizované obrázky sa načítavajú rýchlejšie a spotrebúvajú menej mobilných dát. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Účinne zakódujte obrázky"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Zobrazujte obrázky s primeranou veľkosťou, čím ušetríte mobilné dáta a skrátite čas načítania. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Nastavte primeranú veľkosť obrázkov"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Textové zdroje by sa mali zobrazovať komprimované (gzip, deflate alebo brotli), aby sa minimalizovala celková spotreba bajtov v sieti. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Povoľte kompresiu textu"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formáty obrázka, napríklad JPEG 2000, JPEG XR a WebP, zvyčajne poskytujú lepšiu kompresiu než PNG alebo JPEG, čo znamená rýchlejšie sťahovanie a nižšiu spotrebu dát. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Zobrazujte obrázky vo formátoch ďalšej generácie"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Reťazce podstatných žiadostí uvedené nižšie znázorňujú, ktoré zdroje sú načítané s vysokou prioritou. Zvážte skrátenie dĺžky reťazcov, aby ste znížili veľkosť sťahovaných zdrojov, alebo odložte sťahovanie nepotrebných zdrojov, čím zlepšíte načítanie stránky. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Našiel sa 1 reťazec}few{Našli sa # reťazce}many{# chains found}other{Našlo sa # reťazcov}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minimalizujte hĺbku podstatných žiadostí"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Inžinieri prehliadača odporúčajú, aby stránky obsahovali menej ako ~1 500 uzlov DOM. Optimálna hodnota je hĺbka stromovej štruktúry menšia ako 32 prvkov a menej ako 60 podradených/nadradených prvkov. Veľký prvok DOM môže zvýšiť spotrebu pamäte, predĺžiť [výpočty štýlov](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) a spôsobiť nákladné [preformátovania rozložení](https://developers.google.com/speed/articles/reflow). [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 uzol}few{# uzle}many{# nodes}other{# uzlov}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Nepoužívajte nadmerne veľký prvok DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maximálna hĺbka prvku DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Celkový počet uzlov DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Zabráni použitiu nadmerne veľkého prvku DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Využite funkciu CSS zobrazenia písma, ktorá pomôže zaistiť, aby bol text viditeľný používateľom počas načítavania webfontov. [Ďalšie informácie](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Zaistite, aby text zostal počas načítania webfontov viditeľný"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Všetok text zostane počas načítania webfontov viditeľný"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategória"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Zvážte skrátenie času stráveného analýzou, zostavovaním a spustením JavaScriptu. Možno vám s tým pomôže zobrazovanie menších prenášaných dát JavaScriptu."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimalizujte prácu hlavného vlákna"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimalizuje prácu hlavného vlákna"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Skóre uvedené vyššie je odhadovaný čas odozvy na vstup používateľa v milisekundách počas najrušnejších 5 sekúnd načítania stránky. Ak latencia prevyšuje 50 ms, používateľom sa môžu zdať odozvy aplikácie oneskorené. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Odhadovaná latencia vstupu"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Prvé obsahové vyfarbenie označuje čas, za ktorý je vyfarbený prvý text alebo obrázok. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Prvé obsahové vyfarbenie"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Prvá nečinnosť procesora označuje, kedy je hlavné vlákno stránky prvýkrát dostatočne nečinné na spracovanie vstupu. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Prvá nečinnosť procesora"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Prvé účelné vyfarbenie meria, kedy je hlavný obsah stránky viditeľný. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Prvé účelné vyfarbenie"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktívne vykreslenie označuje čas, za ktorý sa stránka stane úplne interaktívnou. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Čas do interaktívneho vykreslenia"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Index rýchlosti znázorňuje, za aký čas sa viditeľne doplní obsah stránky. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Index rýchlosti"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Presmerovania spôsobujú ďalšie oneskorenia pri načítavaní stránky. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Vyhnite sa viacnásobným presmerovaniam stránky"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Čas do prvého bajtu určuje čas, za ktorý váš server odošle odpoveď. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Hlavný dokument trval {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Znížte časy odpovede servera (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Časy odozvy servera sú krátke (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Trvanie"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Názov"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Čas začatia"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Typ"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Zvážte vybavenie aplikácie rozhraním User Timing API a odmerajte tak skutočnú výkonnosť svojej aplikácie počas kľúčových dojmov používateľov. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 trvanie aktivít používateľov}few{# trvania aktivít používateľov}many{# user timings}other{# trvaní aktivít používateľov}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Značky a merania trvania aktivít používateľov"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Zvážte pridanie indikátorov zdrojov predbežného pripojenia alebo predbežného načítania DNS, ktoré vám pomôžu zriadiť predbežné pripojenia k dôležitým zdrojom tretích strán. [Ďalšie informácie](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Nastavte predbežné pripojenie k požadovaným zdrojom"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Zvážte použitie funkcie <link rel=preload>, čím uprednostníte načítanie zdrojov, o ktoré sa momentálne žiada v neskoršej fáze načítania stránky. [Ďalšie informácie](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Predbežne načítavajte kľúčové žiadosti"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Ďalšie informácie o výkonnosti vašej aplikácie"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Najpodstatnejší aspekt výkonnosti je čas, za ktorý sa pixely vykreslia na obrazovke. Kľúčové metriky: Prvé obsahové vyfarbenie, Prvé účelné vyfarbenie."},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Vylepšenia prvého vyfarbenia"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Týmito optimalizáciami môžete zrýchliť načítanie stránky."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Príležitosti"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metriky"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Vylepšite celkové načítavanie, aby bola stránka čo najskôr responzívna a pripravená na použitie. Kľúčové metriky: Čas do interaktívneho vykreslenia, Index rýchlosti"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Celkové vylepšenia"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Výkonnosť"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL vyrovnávacej pamäte"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Veľkosť (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Strávený čas"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"Webová adresa"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potenciálna úspora (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potenciálna úspora (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potenciálna úspora: {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potenciálna úspora: {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Zobraziť kontroly"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Počiatočná navigácia"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maximálna latencia cesty dôležitých žiadostí:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Chyba!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Nahlásenie chyby: žiadne informácie o kontrole"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Údaje laboratória"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analýza aktuálnej stránky nástrojom [Lighthouse](https://developers.google.com/web/tools/lighthouse/) v emulovanom sieťovom pripojení 3G. Hodnoty sú odhadované a môžu sa líšiť."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Ďalšie položky na manuálnu kontrolu"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nehodí sa"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Príležitosti"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Odhadovaná úspora"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Absolvované kontroly"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Hodnotiaca škála:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Vyskytli sa problémy ovplyvňujúce funkčnosť nástroja Lighthouse:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Hodnoty sú odhady, ktoré sa môžu líšiť."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Upozornenia: "}};
-
-
-},{}],70:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Razširitve za Chrome so negativno vplivale na nalaganje te strani. Poskusite pregledati to stran v načinu brez beleženja zgodovine ali v profilu za Chrome brez razširitev."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Ocenjevanje skripta"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Razčlenitev skripta"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Skupno"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Razmislite o skrajšanju časa, ki ga porabite za razčlenjevanje, prevajanje in izvajanje JavaScripta. Ugotovili boste, da vam lahko pri tem pomaga dostavljanje manjših paketov koristne vsebine JavaScript. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Skrajšajte čas izvajanja JavaScripta"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Čas izvajanja JavaScripta"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Veliki GIF-i so neučinkoviti za dostavljanje animirane vsebine. Razmislite o uporabi videoposnetkov MPEG4/WebM za animacije in slik PNG/WebP za statične slike namesto GIF-ov, s čimer prihranite omrežne bajte. [Več o tem](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Uporabite oblike zapisa videoposnetkov za animirano vsebino"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Razmislite o odloženem nalaganju slik zunaj zaslona in skritih slik po dokončanem nalaganju kritičnih sredstev zaradi skrajšanja časa do interaktivnosti strani. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Odložite nalaganje slik, ki so zunaj zaslona"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Sredstva blokirajo prvo barvanje strani. Razmislite o sprotnem dostavljanju kritičnega JavaScripta/CSS-ja in odlaganju JavaScripta/slogov, ki ni oziroma niso kritični. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Izločite sredstva, ki blokirajo upodabljanje"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Veliki omrežni paketi koristne vsebine uporabnikom povzročajo dejanske stroške in so tesno povezani z dolgimi časi nalaganja. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Skupna velikost je bila {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Izogibajte se velikanskim omrežnim paketom koristne vsebine"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Izogiba se velikanskim omrežnim paketom koristne vsebine"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Z zmanjšanjem datotek CSS-ja lahko zmanjšate velikosti paketov koristne vsebine. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Zmanjšajte CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Z zmanjšanjem datotek JavaScript lahko zmanjšate velikosti paketov koristne vsebine in skrajšate čas razčlenjevanja skriptov. [Več o tem](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Pomanjšajte JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Odstranite neuporabljena pravila iz datotek s slogi, da zmanjšate število nepotrebno uporabljenih bajtov v omrežni dejavnosti. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Odložite neuporabljeni CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Odstranite neuporabljeni JavaScript, če želite zmanjšati število bajtov, uporabljenih v omrežni dejavnosti."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Odstranite neuporabljeni JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Dolgotrajno predpomnjenje lahko pospeši vnovične obiske strani. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Najdeno je bilo 1 sredstvo}one{Najdeno je bilo # sredstvo}two{Najdeni sta bili # sredstvi}few{Najdena so bila # sredstva}other{Najdenih je bilo # sredstev}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Dostavljajte statična sredstva z učinkovitim pravilnikom o predpomnjenju"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Uporaba pravilnika o učinkovitem predpomnjenju za statična sredstva"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimizirane slike se nalagajo hitreje in terjajo manj prenesenih podatkov v mobilnih omrežjih. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Učinkovito kodirajte slike"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Prikazujte slike primerne velikosti, s čimer poskrbite za prihranek prenesenih podatkov v mobilnih omrežjih in izboljšate čas nalaganja. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Uporabite slike ustrezne velikosti"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Pri dostavi besedilnih sredstev uporabite stiskanje (gzip, deflate ali brotli) zaradi zmanjšanja skupnega števila omrežnih bajtov. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Omogočite stiskanje besedila"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Oblike zapisa slik, kot so JPEG 2000, JPEG XR in WebP, pogosto omogočajo učinkovitejše stiskanje kot oblika zapisa PNG ali JPEG, kar pomeni hitrejše prenose in manjšo porabo podatkov. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Dostavljajte slike v sodobnih oblikah zapisa"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Verige kritičnih zahtev spodaj vam prikazujejo, katera sredstva so naložena z visoko prednostjo. Razmislite o skrajšanju verig, zmanjšanju velikosti sredstev ali odlaganju prenosa nepotrebnih sredstev zaradi izboljšanja nalaganja strani. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Najdena je bila 1 veriga}one{Najdena je bila # veriga}two{Najdeni sta bili # verigi}few{Najdene so bile # verige}other{Najdenih je bilo # verig}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Zmanjšajte globino kritičnih zahtev"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Inženirji za brskalnike priporočajo, da strani vsebujejo manj kot približno 1500 vozlišč DOM-a. Idealna vrednost je globina drevesa z manj kot 32 elementi in manj kot 60 podrejenimi/nadrejenimi elementi. Velik DOM lahko povzroči povečano uporabo pomnilnika, daljše [slogovne izračune](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) in drage [prilagoditve postavitve](https://developers.google.com/speed/articles/reflow). [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 vozlišče}one{# vozlišče}two{# vozlišči}few{# vozlišča}other{# vozlišč}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Izogibajte se prekomerni velikosti DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Največja globina DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Skupno število vozlišč DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Izogiba se prekomerni velikosti DOM-a"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Izkoristite funkcijo CSS-ja za prikaz pisave, s čimer poskrbite, da je med nalaganjem spletne pisave besedilo vidno uporabnikom. [Več o tem](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Poskrbite, da bo med nalaganjem spletne pisave besedilo ostalo vidno"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Vse besedilo ostaja vidno med nalaganjem spletne pisave"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorija"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Razmislite o skrajšanju časa, ki ga porabite za razčlenjevanje, prevajanje in izvajanje JavaScripta. Ugotovili boste, da vam lahko pri tem pomaga dostavljanje manjših paketov koristne vsebine JavaScript."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minimizirajte delo glavne niti"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minimizira delo glavne niti"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Zgornji rezultat je ocena, koliko milisekund potrebuje vaša aplikacija za odziv na uporabnikovo dejavnost med najaktivnejšimi 5 sekundami pri nalaganju strani. Če je zakasnitev večja od 50 ms, se lahko uporabnikom zdi, da se aplikacija zatika. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Ocenjena zakasnitev vnosa"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Prvo vsebinsko barvanje označuje čas, ko je pobarvano prvo besedilo oziroma je pobarvana prva slika. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Prvo vsebinsko barvanje"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Prva nedejavnost CPE-ja označuje čas, po katerem je glavna nit strani dovolj neobremenjena, da lahko obravnava vnos. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Prva nedejavnost CPE-ja"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Prvo smiselno barvanje meri, kdaj je vidna glavna vsebina strani. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Prvo smiselno barvanje"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interaktivnost označuje čas, po katerem je stran v celoti interaktivna. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Čas do interaktivnosti"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Indeks hitrosti prikazuje, kako hitro je vsebina strani vidno izpolnjena. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indeks hitrosti"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Preusmeritve vnašajo dodatne zakasnitve nalaganja strani. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Izogibajte se preusmeritvam na več strani"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"»Čas do prvega bajta« navaja čas, v katerem vaš strežnik pošlje odziv. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Korenski dokument je terjal {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Skrajšajte odzivne čase strežnika (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Odzivni časi strežnika so nizki (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Trajanje"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Ime"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Začetni čas"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Vrsta"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Razmislite o uporabi API-ja za merjenje dejanskih izvedb uporabniških dogodkov (User Timing API), če želite izmeriti dejansko delovanje aplikacije med ključnimi uporabniškimi izkušnjami. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 trajanje izvedbe uporabniških dogodkov}one{# trajanje izvedbe uporabniških dogodkov}two{# trajanji izvedbe uporabniških dogodkov}few{# trajanja izvedbe uporabniških dogodkov}other{# trajanj izvedbe uporabniških dogodkov}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Oznake in merjenja trajanj izvedbe uporabniških dogodkov"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Razmislite o dodajanju namigov za sredstva za vnaprejšnje povezovanje ali vnaprejšnji prenos DNS-ja zaradi vzpostavljanja zgodnjih povezav s pomembnimi izvori tretjih oseb. [Več o tem](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Vnaprej se povežite z zahtevanimi izvori"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Razmislite o uporabi oznake <link rel=preload> za dodeljevanje višje stopnje prednosti pri pridobivanju sredstev, ki so trenutno zahtevana pri nadaljnjem nalaganju strani. [Več o tem](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Vnaprej nalagajte ključne zahteve"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Več informacij o delovanju aplikacije."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Bistveni vidik delovanja je, kako hitro se upodabljajo slikovne pike na zaslonu. Ključni meritvi: Prvo vsebinsko barvanje, Prvo smiselno barvanje"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Izboljšave prvega barvanja"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Te optimizacije lahko pospešijo nalaganje strani."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Priložnosti"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Meritve"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Izboljšajte splošno izkušnjo nalaganja, da bo stran odzivna in čim prej pripravljena na uporabo. Ključni meritvi: Čas do interaktivnosti, Indeks hitrosti"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Splošne izboljšave"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Delovanje"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL predpomnjenja"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Velikost (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Porabljeni čas"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Morebitni prihranek (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Morebitni prihranki (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"{wastedBytes, number, bytes} KB morebitnega prihranka"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"{wastedMs, number, milliseconds} ms morebitnega prihranka"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Pokaži preglede"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Začetno krmarjenje"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Največja zakasnitev kritične poti:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Napaka"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Napaka sporočila: ni podatkov o pregledu"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Laboratorijski podatki"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Analiza storitve [Lighthouse](https://developers.google.com/web/tools/lighthouse/) za trenutno stran z emulirano povezavo 3G. Vrednosti so ocenjene in lahko odstopajo."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Dodatni elementi za ročno preverjanje"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Se ne uporablja"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Priložnost"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Ocenjeni prihranek"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Uspešni pregledi"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Rezultatska lestvica:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Na to izvedbo storitve Lighthouse so vplivale težave:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Vrednosti so ocenjene in lahko odstopajo."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Opozorila: "}};
-
-
-},{}],71:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Dodaci za Chrome su negativno uticali na brzinu učitavanja ove stranice. Probajte da proverite stranicu u režimu bez arhiviranja ili sa Chrome profila bez dodataka."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Procena skripta"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Raščlanjivanje skripta"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Ukupno"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Razmislite o tome da smanjite vreme potrebno za raščlanjivanje, kompajliranje i izvršavanje JS datoteka. Prikazivanje manjih JS resursa će vam možda pomoći u tome. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Smanjite vreme izvršavanja JavaScript datoteka"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Vreme izvršavanja JavaScript-a"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Veliki GIF-ovi nisu korisni za prikazivanje animiranog sadržaja. Razmislite o tome da umesto GIF-ova koristite MPEG4/WebM video snimke za animacije i PNG/WebP za statične slike da biste uštedeli mrežne podatke. [Saznajte više](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Koristite video formate za animirani sadržaj"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Razmislite o tome da odložite učitavanje slika van ekrana i skrivenih slika dok se svi veoma važni resursi ne učitaju kako biste smanjili vreme do početka interakcije. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Odložite slike van ekrana"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Resursi blokiraju prvo prikazivanje stranice. Razmislite o tome da prikazujete sve važne JS/CSS datoteke u tekstu i da odložite sve JS datoteke/stilove koji nisu toliko važni. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Eliminišite resurse koji blokiraju prikazivanje"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Velike mrežne resurse korisnici moraju da plate stvarnim novcem i oni su veoma povezani sa dugim vremenima učitavanja. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Ukupna veličina je bila {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Izbegavajte ogromne mrežne resurse"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Izbegava ogromne mrežne resurse"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Umanjivanjem CSS datoteka možete da smanjite veličine mrežnih resursa. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Umanjite CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Umanjivanje JavaScript datoteka može da smanji veličine resursa i vreme raščlanjivanja skripta. [Saznajte više](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Umanjite JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Uklonite nekorišćena pravila iz opisa stilova da biste smanjili nepotrebnu potrošnju podataka tokom mrežnih aktivnosti. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Odložite nekorišćeni CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Uklonite nekorišćeni JavaScript da biste smanjili potrošnju podataka tokom mrežnih aktivnosti."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Uklonite nekorišćeni JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Dugo trajanje keša može da ubrza ponovne posete stranici. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Pronađen je 1 resurs}one{Pronađen je # resurs}few{Pronađena su # resursa}other{Pronađeno je # resursa}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Prikazujte statične elemente sa efikasnim smernicama keša"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Koristi efikasne smernice keša na statičnim elementima"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimizovane slike se učitavaju brže i troše manje mobilnih podataka. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Efikasno kodirajte slike"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Prikazujte slike odgovarajuće veličine da biste uštedeli mobilne podatke i poboljšali vreme učitavanja. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Odredite odgovarajuću veličinu slika"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Resurse zasnovane na tekstu treba da prikazujete u komprimovanom formatu (gzip, deflate ili brotli) da biste smanjili ukupnu količinu potrošenih mrežnih podataka. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Omogućite kompresiju teksta"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Formati slika kao što su JPEG 2000, JPEG XR i WebP često pružaju bolju kompresiju nego PNG ili JPEG, što znači brža preuzimanja i manju potrošnju podataka. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Prikazujte slike u formatima sledeće generacije"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Lanci veoma važnih zahteva u nastavku vam prikazuju koji resursi se učitavaju sa visokim prioritetom. Razmislite o tome da smanjite dužinu lanaca, da smanjite veličinu preuzimanja za resurse ili da odložite preuzimanje resursa koji nisu neophodni radi bržeg učitavanja stranice. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Pronađen je 1 lanac}one{Pronađen je # lanac}few{Pronađena su # lanca}other{Pronađeno je # lanaca}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Smanjite broj veoma važnih zahteva"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Inženjeri za pregledače preporučuju da stranice sadrže manje od približno 1500 DOM čvorova. Najbolje bi bilo da dubina stabla bude ispod 32 elementa i da ima manje od 60 podređenih/nadređenih elemenata. Veliki DOM može da poveća potrošnju memorije, da izazove duža [izračunavanja stilova](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) i da dovede do skupih [preoblikovanja izgleda](https://developers.google.com/speed/articles/reflow). [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 čvor}one{# čvor}few{# čvora}other{# čvorova}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Izbegavajte preveliku veličinu DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimalna dubina DOM-a"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Ukupan broj DOM čvorova"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Izbegava preveliku veličinu DOM-a"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Iskoristite CSS funkciju za prikaz fontova da biste bili sigurni da korisnik može da vidi tekst dok se veb-fontovi učitavaju. [Saznajte više](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Pobrinite se da tekst ostane vidljiv tokom učitavanja veb-fontova"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Sav tekst ostaje vidljiv tokom učitavanja veb-fontova"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategorija"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Razmislite o tome da smanjite vreme potrebno za raščlanjivanje, kompajliranje i izvršavanje JS datoteka. Prikazivanje manjih JS resursa će vam možda pomoći u tome."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Smanjite rad glavne niti"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Smanjuje rad glavne niti"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Rezultat iznad je procena vremena koje je aplikaciji potrebno da odgovori na unos korisnika, u milisekundama, tokom najprometnijeg roka od 5 sekundi za učitavanje stranice. Ako je kašnjenje veće od 50 ms, korisnici će možda smatrati da aplikacija radi sporo. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Procenjeno kašnjenje unosa"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Prvo prikazivanje sadržaja označava vreme kada se prikazuju prvi tekst ili slika. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Prvo prikazivanje sadržaja"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Vreme prvog neaktivnog procesora označava prvi trenutak u kome je glavna nit stranice dovoljno neaktivna da bi obradila unos. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Vreme prvog neaktivnog procesora"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Prvo značajno prikazivanje označava vreme kada primarni sadržaj stranice postaje vidljiv. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Prvo značajno prikazivanje"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Interakcija označava vreme kada stranica postaje potpuno interaktivna. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Vreme početka interakcije"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Indeks brzine prikazuje koliko brzo sadržaj stranice postaje vidljiv za korisnike. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Indeks brzine"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Preusmeravanja dovode do dodatnih kašnjenja pre učitavanja stranice. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Izbegavajte višestruka preusmeravanja stranice"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Vreme prvog odgovora određuje vreme u koje server šalje odgovor. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Osnovnom dokumentu je trebalo {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Smanjite vremena odgovora servera (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Vremena odgovora servera su kratka (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Trajanje"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Naziv"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Vreme početka"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tip"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Razmislite o tome da opremite aplikaciju API-jem za vreme korisnika da biste izmerili učinak aplikacije u realnom svetu tokom ključnih korisničkih doživljaja. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 vreme korisnika}one{# vreme korisnika}few{# vremena korisnika}other{# vremena korisnika}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Oznake i mere Vremena korisnika"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Razmislite o tome da dodate savete za resurse za povezivanje unapred ili pripremu učitavanja DNS-a kako biste uspostavili rane veze sa važnim izvorima trećih strana. [Saznajte više](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Povežite se unapred sa potrebnim izvorima"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Razmislite o tome da koristite <link rel=preload> kako biste kasnije tokom učitavanja stranice dali prioritet preuzimanju resursa koji se trenutno traže. [Saznajte više](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Unapred učitajte najvažnije zahteve"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Više informacija o učinku aplikacije."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Dijagnostika"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Najvažniji aspekt učinka je brzina kojom se pikseli prikazuju na ekranu. Ključni pokazatelji: Prvo prikazivanje sadržaja, Prvo značajno prikazivanje"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Poboljšanja prvog prikazivanja"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Ove optimizacije mogu da ubrzaju učitavanje stranice."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Mogućnosti"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Pokazatelji"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Poboljšajte opšti doživljaj učitavanja da bi stranica počela da se odaziva i da bi bila spremna za korišćenje u najkraćem mogućem roku. Ključni pokazatelji: Vreme početka interakcije, Indeks brzine"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Opšta poboljšanja"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Učinak"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Vreme preživljavanja keša"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Veličina (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Provedeno vreme"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potencijalna ušteda (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potencijalna ušteda (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Potencijalna ušteda od {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Potencijalna ušteda od {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} sek"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Prikaži provere"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Početna navigacija"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksimalno kašnjenje kritične putanje:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Greška!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Prijavljivanje greške: nema informacija o proveri"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Podaci o eksperimentalnim funkcijama"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analiza aktuelne stranice emulirane pomoću 3G mreže. Vrednosti su procenjene i mogu da se razlikuju."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Dodatne stavke za ručnu proveru"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Nije primenjivo"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Mogućnost"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Procenjena ušteda"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Provere sa zadovoljavajućom ocenom"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Skala rezultata:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Bilo je izvesnih problema koji su uticali na ovo pokretanje Lighthouse-a:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Vrednosti predstavljaju procene i mogu da variraju."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Upozorenja: "}};
-
-
-},{}],72:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Додаци за Chrome су негативно утицали на брзину учитавања ове странице. Пробајте да проверите страницу у режиму без архивирања или са Chrome профила без додатака."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Процена скрипта"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Рашчлањивање скрипта"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Укупно"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Размислите о томе да смањите време потребно за рашчлањивање, компајлирање и извршавање JS датотека. Приказивање мањих JS ресурса ће вам можда помоћи у томе. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Смањите време извршавања JavaScript датотека"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Време извршавања JavaScript-а"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Велики GIF-ови нису корисни за приказивање анимираног садржаја. Размислите о томе да уместо GIF-ова користите MPEG4/WebM видео снимке за анимације и PNG/WebP за статичне слике да бисте уштедели мрежне податке. [Сазнајте више](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Користите видео формате за анимирани садржај"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Размислите о томе да одложите учитавање слика ван екрана и скривених слика док се сви веома важни ресурси не учитају како бисте смањили време до почетка интеракције. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Одложите слике ван екрана"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ресурси блокирају прво приказивање странице. Размислите о томе да приказујете све важне JS/CSS датотеке у тексту и да одложите све JS датотеке/стилове који нису толико важни. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Елиминишите ресурсе који блокирају приказивање"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Велике мрежне ресурсе корисници морају да плате стварним новцем и они су веома повезани са дугим временима учитавања. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Укупна величина је била {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Избегавајте огромне мрежне ресурсе"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Избегава огромне мрежне ресурсе"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Умањивањем CSS датотека можете да смањите величине мрежних ресурса. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Умањите CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Умањивање JavaScript датотека може да смањи величине ресурса и време рашчлањивања скрипта. [Сазнајте више](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Умањите JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Уклоните некоришћена правила из описа стилова да бисте смањили непотребну потрошњу података током мрежних активности. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Одложите некоришћени CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Уклоните некоришћени JavaScript да бисте смањили потрошњу података током мрежних активности."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Уклоните некоришћени JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Дуго трајање кеша може да убрза поновне посете страници. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Пронађен је 1 ресурс}one{Пронађен је # ресурс}few{Пронађена су # ресурса}other{Пронађено је # ресурса}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Приказујте статичне елементе са ефикасним смерницама кеша"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Користи ефикасне смернице кеша на статичним елементима"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Оптимизоване слике се учитавају брже и троше мање мобилних података. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Ефикасно кодирајте слике"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Приказујте слике одговарајуће величине да бисте уштедели мобилне податке и побољшали време учитавања. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Одредите одговарајућу величину слика"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Ресурсе засноване на тексту треба да приказујете у компримованом формату (gzip, deflate или brotli) да бисте смањили укупну количину потрошених мрежних података. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Омогућите компресију текста"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Формати слика као што су JPEG 2000, JPEG XR и WebP често пружају бољу компресију него PNG или JPEG, што значи бржа преузимања и мању потрошњу података. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Приказујте слике у форматима следеће генерације"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Ланци веома важних захтева у наставку вам приказују који ресурси се учитавају са високим приоритетом. Размислите о томе да смањите дужину ланаца, да смањите величину преузимања за ресурсе или да одложите преузимање ресурса који нису неопходни ради бржег учитавања странице. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Пронађен је 1 ланац}one{Пронађен је # ланац}few{Пронађена су # ланца}other{Пронађено је # ланаца}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Смањите број веома важних захтева"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Инжењери за прегледаче препоручују да странице садрже мање од приближно 1500 DOM чворова. Најбоље би било да дубина стабла буде испод 32 елемента и да има мање од 60 подређених/надређених елемената. Велики DOM може да повећа потрошњу меморије, да изазове дужа [израчунавања стилова](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) и да доведе до скупих [преобликовања изгледа](https://developers.google.com/speed/articles/reflow). [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 чвор}one{# чвор}few{# чвора}other{# чворова}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Избегавајте превелику величину DOM-а"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Максимална дубина DOM-а"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Укупан број DOM чворова"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Избегава превелику величину DOM-а"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Искористите CSS функцију за приказ фонтова да бисте били сигурни да корисник може да види текст док се веб-фонтови учитавају. [Сазнајте више](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Побрините се да текст остане видљив током учитавања веб-фонтова"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Сав текст остаје видљив током учитавања веб-фонтова"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Категорија"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Размислите о томе да смањите време потребно за рашчлањивање, компајлирање и извршавање JS датотека. Приказивање мањих JS ресурса ће вам можда помоћи у томе."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Смањите рад главне нити"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Смањује рад главне нити"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Резултат изнад је процена времена које је апликацији потребно да одговори на унос корисника, у милисекундама, током најпрометнијег рока од 5 секунди за учитавање странице. Ако је кашњење веће од 50 ms, корисници ће можда сматрати да апликација ради споро. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Процењено кашњење уноса"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Прво приказивање садржаја означава време када се приказују први текст или слика. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Прво приказивање садржаја"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Време првог неактивног процесора означава први тренутак у коме је главна нит странице довољно неактивна да би обрадила унос. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Време првог неактивног процесора"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Прво значајно приказивање означава време када примарни садржај странице постаје видљив. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Прво значајно приказивање"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Интеракција означава време када страница постаје потпуно интерактивна. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Време почетка интеракције"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Индекс брзине приказује колико брзо садржај странице постаје видљив за кориснике. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Индекс брзине"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Преусмеравања доводе до додатних кашњења пре учитавања странице. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Избегавајте вишеструка преусмеравања странице"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Време првог одговора одређује време у које сервер шаље одговор. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Основном документу је требало {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Смањите времена одговора сервера (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Времена одговора сервера су кратка (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Трајање"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Назив"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Време почетка"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Тип"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Размислите о томе да опремите апликацију API-јем за време корисника да бисте измерили учинак апликације у реалном свету током кључних корисничких доживљаја. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 време корисника}one{# време корисника}few{# времена корисника}other{# времена корисника}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Ознаке и мере Времена корисника"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Размислите о томе да додате савете за ресурсе за повезивање унапред или припрему учитавања DNS-а како бисте успоставили ране везе са важним изворима трећих страна. [Сазнајте више](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Повежите се унапред са потребним изворима"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Размислите о томе да користите <link rel=preload> како бисте касније током учитавања странице дали приоритет преузимању ресурса који се тренутно траже. [Сазнајте више](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Унапред учитајте најважније захтеве"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Више информација о учинку апликације."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Дијагностика"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Најважнији аспект учинка је брзина којом се пиксели приказују на екрану. Кључни показатељи: Прво приказивање садржаја, Прво значајно приказивање"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Побољшања првог приказивања"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Ове оптимизације могу да убрзају учитавање странице."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Могућности"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Показатељи"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Побољшајте општи доживљај учитавања да би страница почела да се одазива и да би била спремна за коришћење у најкраћем могућем року. Кључни показатељи: Време почетка интеракције, Индекс брзине"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Општа побољшања"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Учинак"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Време преживљавања кеша"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Величина (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Проведено време"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Потенцијална уштеда (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Потенцијална уштеда (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Потенцијална уштеда од {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Потенцијална уштеда од {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} сек"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Прикажи провере"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Почетна навигација"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Максимално кашњење критичне путање:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Грешка!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Пријављивање грешке: нема информација о провери"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Подаци о експерименталним функцијама"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) анализа актуелне странице емулиране помоћу 3G мреже. Вредности су процењене и могу да се разликују."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Додатне ставке за ручну проверу"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Није примењиво"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Могућност"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Процењена уштеда"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Провере са задовољавајућом оценом"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Скала резултата:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Било је извесних проблема који су утицали на ово покретање Lighthouse-а:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Вредности представљају процене и могу да варирају."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Упозорења: "}};
-
-
-},{}],73:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Inläsningen av den här sidan påverkas negativt av tillägg i Chrome. Testa att granska sidan i inkognitoläge eller med en Chrome-profil utan tillägg."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Utvärdering av skript"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Skriptanalys"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Totalt"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Minska tiden det tar att tolka, kompilera och köra JS-kod. Det brukar hjälpa att minska storleken på JS-resurserna som skickas. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Minska körningstiden för JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Körningstid för JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Stora GIF-bilder är ett ineffektivt sätt att visa animationer på. I stället för GIF kan du använda videor i MPEG4-/WebM-format för animationer och PNG-/WebP-format för statiska bilder, vilket minskar antalet byte som skickas via nätverket. [Läs mer](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Använd videoformat för animationer"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Låt bilder utanför skärmen och dolda bilder läsas in med lat inläsning efter att alla viktiga resurser är inlästa så att tiden till interaktivt tillstånd minskar. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Skjut upp inläsningen av bilder som inte visas på skärmen"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Den första uppritningen av sidan på skärmen blockeras av resurser. Infoga nödvändig JS-/CSS-kod direkt på sidan och skjut upp inläsningen av JS-kod/formatmallar som är mindre viktiga. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Ta bort resurser som blockerar renderingen"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Hög nätverksbelastning kostar användarna pengar och har ett starkt samband med lång inläsningstid. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Storleken totalt var {totalBytes, number, bytes} kB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Undvik enorm nätverksbelastning"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Undviker enorm nätverksbelastning"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Att minifiera CSS-filer kan minska nätverksbelastningen. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Minifiera CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Att minifiera JavaScript-filer kan minska nätverksbelastningen och tiden det tar att tolka skript. [Läs mer](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Minifiera JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Ta bort regler som inte används från formatmallarna, så att färre byte skickas via nätverket i onödan. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Skjut upp CSS som inte används"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Ta bort JavaScript som inte används så att färre byte skickas via nätverket."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Ta bort JavaScript som inte används"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Om filerna cachelagras under längre tid kan upprepade besök på sidan gå snabbare. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 resurs hittades}other{# resurser hittades}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Skicka statiska tillgångar med en effektiv cachelagringspolicy"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Använder en effektiv cachelagringspolicy för statiska tillgångar"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimerade bilder läses in snabbare och förbrukar mindre mobildata. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Koda bilder effektivt"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Minska mobildataförbrukningen och förbättra inläsningstiden genom att skicka bilder i rätt storlek. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Använd bilder med rätt storlek"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Textresurser bör skickas komprimerade (gzip, deflate eller brotli) så att färre byte skickas via nätverket. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Aktivera textkomprimering"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Bildformat som JPEG 2000, JPEG XR och WebP ger ofta bättre komprimering än PNG eller JPEG. Det gör att nedladdningen går snabbare och ger minskad dataförbrukning. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Skicka bilder i modernare bildformat"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Orderkedjorna nedan visar vilka resurser som läses in med hög prioritet. Se om du kan förbättra sidinläsningstiden genom att göra kedjorna kortare, minska storleken på resurser som laddas ned eller skjuta upp nedladdningen av onödiga resurser. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 kedja hittades}other{# kedjor hittades}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Minska antalet steg i viktiga orderkedjor"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Webbläsarutvecklare rekommenderar att en sidas DOM ska ha färre än ca 1 500 noder. Ett träd där djupet är mindre än 32 element och det finns högst 60 underordnade/överordnade element är idealiskt. Stora DOM-träd kan medföra ökad minnesförbrukning, längre [formatmallsberäkningar](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) och resurskrävande [omflödning av layouten](https://developers.google.com/speed/articles/reflow). [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nod}other{# noder}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Undvik ett onödigt stort DOM-träd"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Största DOM-djup"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Totalt antal noder i DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Undviker ett onödigt stort DOM-träd"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Använd funktionen font-display i CSS så att texten är synlig för användaren medan webbteckensnitten läses in. [Läs mer](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Se till att all text förblir synlig medan webbteckensnitten läses in"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"All text förblir synlig medan webbteckensnitten läses in"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategori"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Minska tiden det tar att tolka, kompilera och köra JS-kod. Det brukar hjälpa att minska storleken på JS-resurserna som skickas."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Minska arbetsbelastningen på modertråden"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Minskar arbetsbelastningen på modertråden"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Värdet ovan är en uppskattning av hur lång tid (i millisekunder) det tar innan appen svarar på användarens inmatning under den mest aktiva femsekundersperioden av sidinläsningen. Om latensen är högre än 50 ms kan användarna uppfatta det som att appen laggar. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Beräknad inmatningslatens"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Första innehållsrendering anger tidpunkten när den första texten eller bilden ritades upp. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Första uppritningen av innehåll"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Första CPU-avbrottet anger tidpunkten då sidans modertråd först blev inaktiv nog att hantera indata. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Första CPU-inaktivitet"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Första meningsfulla skärmuppritningen anger när sidans primära innehåll var synligt. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Första meningsfulla skärmuppritningen"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Tiden till interaktivt tillstånd anger tidpunkten när sidan blivit helt interaktiv. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Tid till interaktivt tillstånd"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Sidans hastighetsindex visar hur snabbt sidan fylls med synligt innehåll. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Hastighetsindex"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Omdirigeringar medför en ytterligare fördröjning innan sidan kan läsas in. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Undvik upprepade omdirigeringar"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Mätvärdet Tid till första byte anger när servern svarade. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Rotdokumentet tog {timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Minska svarstiderna från servern (tid till första byte)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Servern svarar snabbt (tid till första byte)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Varaktighet"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Namn"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Starttid"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Typ"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Om du bygger in User Timing API i appen kan du mäta appens prestanda i realtid i samband med viktiga användarupplevelser. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 användartimer}other{# användartimer}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing API – tidsstämplar och mått"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Lägg till signaler för förhandsanslutning eller DNS-förhandshämtning så att viktiga anslutningar till tredje part upprättas tidigt. [Läs mer](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Föranslut till obligatoriska källor"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Prioritera upp resurser som för närvarande hämtas senare under sidinläsningen med <link rel=preload>. [Läs mer](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Läs in viktiga resurser i förväg"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Mer information om appens prestanda."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Diagnostik"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Den viktigaste delen av sidans prestanda är hur snabbt pixlarna renderas på skärmen. Viktiga mätvärden: Första uppritningen av innehåll, Första meningsfulla skärmuppritningen"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Förbättringar av första skärmuppritningen"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"De här optimeringarna kan göra inläsningen av sidan snabbare."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Möjligheter"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Mätvärden"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Förbättra inläsningstiden överlag så att sidan upplevs som responsiv och blir klar att använda så snabbt som möjligt. Viktiga mätvärden: Tid till interaktivt tillstånd, Hastighetsindex"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Övergripande förbättringar"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Prestanda"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Lagringstid i cacheminnet"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Storlek (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Tid som använts"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"Webbadress"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Möjlig databesparing (kB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Möjlig tidsbesparing (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Möjlig databesparing: {wastedBytes, number, bytes} kB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Möjlig tidsbesparing: {wastedMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} s"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Visa granskningar"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Första navigering"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Högsta latens för kritisk kedja:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Fel."},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Rapportfel: ingen granskningsinformation"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Labbdata"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/)-analys av den aktuella sidan med 3G-emulering. Värdena är uppskattningar och kan variera."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Fler saker att kolla manuellt"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Ej tillämpligt"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Möjlighet"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Uppskattad tidsbesparing"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Godkända granskningar"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Poängskala:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Problem uppstod med den här körningen av Lighthouse."},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Värdena är uppskattningar och kan variera."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Varningar: "}};
-
-
-},{}],74:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome நீட்டிப்புகள் இந்தப் பக்கத்தின் ஏற்றுதல் செயல்திறனை எதிர்மறையாகப் பாதிக்கின்றன. மறைநிலையிலோ, நீட்டிப்புகள் இல்லாத ஒரு Chrome கணக்கிலிருந்தோ பக்கத்தைத் தணிக்கை செய்ய முயலவும்."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"ஸ்கிரிப்ட் மதிப்பாய்வு"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"ஸ்கிரிப்ட் பாகுபடுத்துதல்"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"மொத்தம்"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"JSஸைப் பாகுபடுத்துதல், தொகுத்தல் மற்றும் இயக்குவதில் செலவழிக்கும் நேரத்தைக் குறைக்க முயற்சி செய்யவும். இதற்கு, சிறிய அளவிலான JS ஆதாரங்களை வழங்குவது உதவக்கூடும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"JavaScript செயல்பாட்டு நேரத்தைக் குறைக்கவும்"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript செயல்பாட்டு நேரம்"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"அனிமேஷன் செய்யப்பட்ட உள்ளடக்கத்தை வழங்குவதற்குப் பெரிய அளவிலான GIFகள் பொருத்தமானவை அல்ல. நெட்வொர்க் பைட்களைச் சேமிப்பதற்கு, GIFக்குப் பதிலாக அனிமேஷன்களுக்கு MPEG4/WebM வீடியோக்களையும் நிலையான படங்களுக்கு PNG/WebP வடிவமைப்புகளையும் பயன்படுத்தலாம். [மேலும் அறிக](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"அனிமேஷன் செய்யப்பட்ட உள்ளடக்கங்களுக்கு வீடியோ வடிவமைப்புகளைப் பயன்படுத்தவும்"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"எதிர்வினையாற்றும் நேரத்தைக் குறைப்பதற்கு, முக்கியமான அனைத்து ஆதாரங்களும் ஏற்றப்பட்ட பின்னர், திரைக்கு வெளியிலுள்ள மற்றும் மறைக்கப்பட்ட படங்களை மெதுவாக ஏற்றுமாறு அமைக்கவும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"திரைக்கு வெளியிலுள்ள படங்களைத் தவிர்க்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"ஆதாரங்கள் உங்கள் பக்கத்தின் முதல் தோற்றத்தைத் தடுக்கின்றன. முக்கிய JS/CSSஸை இன்லைனில் வழங்கவும். முக்கியமல்லாத அனைத்து JS/ஸ்டைல்களையும் தவிர்க்கவும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"ரென்டரிங்கைத் தடுக்கும் ஆதாரங்களை நீக்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"அதிகளவிலான நெட்வொர்க் ஆதாரங்கள், பயனர்களுக்குப் பண இழப்பை ஏற்படுத்துவதோடு, பக்கங்கள் ஏற்றப்பட நீண்ட நேரமாவதற்கும் காரணமாகின்றன. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"மொத்த அளவு {totalBytes, number, bytes} கி.பை."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"அபரிமிதமான நெட்வொர்க் ஆதாரங்களைத் தவிர்க்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"அபரிமிதமான நெட்வொர்க் ஆதாரங்களைத் தவிர்க்கிறது"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS கோப்புகளைச் சிறிதாக்கினால் நெட்வொர்க் ஆதாரங்களின் அளவுகள் குறையலாம். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSSஸைச் சிறிதாக்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"JavaScript கோப்புகளைச் சிறிதாக்கினால், ஆதாரங்களின் அளவுகளும் ஸ்கிரிப்ட் பாகுபடுத்தப்படும் நேரமும் குறையலாம். [மேலும் அறிக](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScriptடைச் சிறிதாக்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"நெட்வொர்க் செயல்பாட்டின்போது பயன்படுத்தப்படும் தேவையற்ற பைட்களைக் குறைக்க, பயன்படுத்தப்படாத விதிகளை ஸ்டைல்ஷீட்களிலிருந்து அகற்றவும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"பயன்படுத்தப்படாத CSSஸைத் தவிர்க்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"நெட்வொர்க் செயல்பாடு பயன்படுத்தும் பைட்களைக் குறைப்பதற்கு, பயன்படுத்தப்படாத JavaScriptடை அகற்றவும்."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"பயன்படுத்தப்படாத JavaScriptடை அகற்றவும்"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"தற்காலிக நினைவகத்தின் ஆயுட்காலம் நீண்டதாக இருந்தால், அது மீண்டும் மீண்டும் திறக்கப்படும் உங்கள் இணையப் பக்கங்களை விரைவாக ஏற்றக்கூடும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 ஆதாரம் கண்டறியப்பட்டது}other{# ஆதாரங்கள் கண்டறியப்பட்டன}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"திறனுள்ள தற்காலிக நினைவகக் கொள்கையுடன் நிலையான உள்ளடக்கத்தை வழங்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"நிலையான உள்ளடக்கத்தில் திறனுள்ள தற்காலிக நினைவகக் கொள்கையைப் பயன்படுத்துகிறது"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"மேம்படுத்தப்பட்ட படங்கள் மேலும் விரைவாக ஏற்றப்படுவதோடு குறைவான செல்லுலார் டேட்டாவைப் பயன்படுத்தும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"படங்களைத் திறம்பட என்கோடிங் செய்யவும்"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"செல்லுலார் டேட்டாவைச் சேமிக்கவும், பக்கத்தை விரைவாக ஏற்றவும் படங்களைச் சரியான அளவில் வழங்கவும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"படங்களைச் சரியான அளவுக்கு மாற்றவும்"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"மொத்த நெட்வொர்க் பைட்களைக் குறைப்பதற்கு, உரை அடிப்படையிலான ஆதாரங்கள் சுருக்கப்பட்டு (gzip, deflate அல்லது brotli) வழங்கப்பட வேண்டும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"உரைச் சுருக்கத்தை இயக்கவும்"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000, JPEG XR, WebP போன்ற பட வடிவமைப்புகள், PNG அல்லது JPEGயைக் காட்டிலும் சிறந்த அளவுச் சுருக்கத்தை வழங்குகின்றன, இதன் மூலம் பதிவிறக்கங்கள் வேகமாக நடைபெறும், அத்துடன் டேட்டா பயன்பாடும் குறையும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"படங்களை நவீன வடிவமைப்புகளில் வழங்கவும்"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"கீழுள்ள 'முக்கியக் கோரிக்கை வரிசைகள்', எந்தெந்த ஆதாரங்கள் உயர் முன்னுரிமையுடன் ஏற்றப்பட்டன என்பதைக் காண்பிக்கின்றன. பக்கம் ஏற்றப்படுவதன் வேகத்தை அதிகரிக்க, வரிசைகளின் நீளத்தைக் குறைத்தல், ஆதாரங்களின் பதிவிறக்க அளவைக் குறைத்தல் அல்லது தேவையற்ற ஆதாரங்களைப் பதிவிறக்குவதைத் தவிர்த்தல் போன்றவற்றை முயற்சி செய்யவும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 வரிசை கண்டறியப்பட்டது}other{# வரிசைகள் கண்டறியப்பட்டன}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"'முக்கியக் கோரிக்கைகளின் அடுக்கைக்' குறைக்கவும்"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"~1,500 DOM கணுக்களுக்குக் குறைவான கணுக்களைக் கொண்ட பக்கங்களை உலாவிப் பொறியாளர்கள் பரிந்துரைக்கின்றனர். 32 உறுப்புகளுக்குக் குறைவான கிளை அடுக்குகளும் 60க்குக் குறைவான துணைக்கிளை/கிளை உறுப்புகளும் இருப்பது உகந்தது. ஒரு பெரிய DOM, நினைவகப் பயன்பாட்டை அதிகரிக்கலாம், [ஸ்டைல் கணக்கீடுகளை] நீட்டிக்கலாம், மேலும் (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) அதிகச் செலவு பிடிக்கும் [தளவமைப்பு மறுசீராக்கங்களை] ஏற்படுத்தலாம் (https://developers.google.com/speed/articles/reflow). [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 கணு}other{# கணுக்கள்}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"அபரிமிதமான DOM அளவைத் தவிர்க்கவும்"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"அதிகபட்ச DOM கிளை அடுக்கு"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"மொத்த DOM கணுக்கள்"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"அபரிமிதமான DOM அளவைத் தவிர்க்கிறது"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"இணைய எழுத்துருக்கள் ஏற்றப்படும்போது உரை எழுத்துகள் பயனருக்குத் தெரிவதை உறுதிசெய்வதற்கு, எழுத்துருக் காட்சியின் CSS அம்சத்தைச் சேர்க்கவும். [மேலும் அறிக](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"இணைய எழுத்துரு ஏற்றப்படும்போது உரை எழுத்துகள் தெரிவதை உறுதிசெய்யவும்"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"இணைய எழுத்துருக்கள் ஏற்றப்படும்போது உரை எழுத்துகள் அனைத்தும் தெரிகின்றன"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"வகை"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"JSஸைப் பாகுபடுத்துதல், தொகுத்தல் மற்றும் இயக்குவதில் செலவழிக்கும் நேரத்தைக் குறைக்க முயற்சி செய்யவும். இதற்கு, சிறிய அளவிலான JS ஆதாரங்களை வழங்குவது உதவக்கூடும்."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"முக்கியத் தொடரிழையின் பணியைக் குறைக்கவும்"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"முக்கியத் தொடரிழையின் பணியைக் குறைக்கிறது"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"மேலுள்ள ஸ்கோர், பக்கம் ஏற்றப்படும் பிஸியான 5 வினாடி காலஅளவின்போது பயனரின் உள்ளீட்டுக்குப் பதிலளிக்க உங்கள் ஆப்ஸ் எவ்வளவு நேரம் எடுத்துக் கொள்கிறது என்பதற்கான தோராய மதிப்பாகும், இது மில்லிவினாடிகளில் கணக்கிடப்படுகிறது. பதிலளிப்பதற்கு 50 மி.வி.க்கு அதிகமாகத் தாமதமானால், பயனர்கள் உங்கள் ஆப்ஸை “மெதுவானது” என்று கருதக்கூடும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"தோராயமான உள்ளீட்டுத் தாமதம்"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"'உள்ளடக்கத்துடன் முதல் தோற்றம்' என்பது, முதல் உரை அல்லது படம் தோன்றும் நேரத்தைக் குறிக்கிறது. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"உள்ளடக்கமுள்ள முதல் தோற்றம்"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"'CPU செயல்படாநிலையின் தொடக்க நேரம்' என்பது, உள்ளீட்டை பக்கத்தின் முக்கியத் தொடரிழை கையாள்வதற்குத் தயாராக, செயல்படாநிலையில் இருக்கும் நேரத்தின் தொடக்கத்தைக் குறிக்கிறது. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU செயல்படாநிலையின் தொடக்க நேரம்"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"'அர்த்தமுள்ள முதல் தோற்றம்' என்பது பக்கத்தின் முதன்மை உள்ளடக்கம் எப்போது தெரிகிறது என்பதை அளவிடுகிறது. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"அர்த்தமுள்ள முதல் தோற்றம்"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"'எதிர்வினை' என்பது பக்கம் முழுமையாக எதிர்வினையாற்றும் நேரத்தைக் குறிப்பிடுகிறது. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"எதிர்வினை நேரம்"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"பக்கத்திலுள்ள உள்ளடக்கங்கள் எவ்வளவு விரைவாகத் தெரிகின்றன என்பதை 'வேக அட்டவணை' காண்பிக்கிறது. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"வேக அட்டவணை"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"'திசைதிருப்புதல்கள்' பக்கம் ஏற்றப்படுவதற்கு முன்பு கூடுதல் தாமதங்களை ஏற்படுத்தலாம். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"பல பக்கங்களுக்குத் திசைதிருப்புவதைத் தவிர்க்கவும்"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"'முதல் பைட்டின் நேரம்' என்பது உங்கள் சேவையகம் ஒரு பதிலை அனுப்பும் நேரத்தைச் சுட்டிக்காட்டுகிறது. [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"மூல ஆவணம் ஏற்றப்படுவதற்கு {timeInMs, number, milliseconds} மி.வி. ஆனது"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"சேவையக எதிர்வினை நேரங்களைக் குறைக்கவும் (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"சேவையகம் எதிர்வினையாற்றும் நேரங்கள் குறைவாக உள்ளன (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"கால அளவு"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"பெயர்"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"தொடக்க நேரம்"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"வகை"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"முக்கியப் பயனர் அனுபவங்களின்போது உங்கள் ஆப்ஸின் நிகழ்நேர செயல்திறனை அளவிடுவதற்கு, உங்கள் ஆப்ஸில் User Timing APIஐப் பயன்படுத்தலாம். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 பயனர் நேரம்}other{# பயனர் நேரங்கள்}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"பயனர் நேரக் குறிப்புகளும் அளவீடுகளும்"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"முக்கியமான மூன்றாம் தரப்பு டொமைன்களுடன் விரைவான இணைப்புகளை ஏற்படுத்த, ப்ரீகனெக்ட் அல்லது dns-ப்ரீஃபெட்ச் ஆதாரக் குறிப்புகளைச் சேர்க்கலாம். [மேலும் அறிக](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"தேவைப்படும் டொமைன் பெயர்களுக்கு முன்கூட்டியே இணைப்பு வழங்கவும்"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"பக்கம் ஏற்றப்படும்போது, தற்போது பின்னர் கோரப்படும் ஆதாரங்களை முன்னதாகப் பெறுவதற்கு முன்னுரிமைப்படுத்த, <link rel=preload>ஐப் பயன்படுத்தவும். [மேலும் அறிக](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"முக்கியக் கோரிக்கைகளை முன்கூட்டியே ஏற்றவும்"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"உங்கள் ஆப்ஸின் செயல்திறன் பற்றிய மேலும் சில தகவல்கள்."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"பகுப்பாய்வு"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"திரையில் பிக்சல்கள் எவ்வளவு விரைவாக ரென்டரிங் செய்யப்படுகின்றன என்பது செயல்திறனின் மிக முக்கிய அம்சமாகும். முக்கிய அளவீடுகள்: 'உள்ளடக்கமுள்ள முதல் தோற்றம்', 'அர்த்தமுள்ள முதல் தோற்றம்'"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"முதல் தோற்ற மேம்பாடுகள்"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"இந்த மேம்படுத்ததுதல்கள் உங்கள் பக்கத்தை வேகமாக ஏற்றலாம்."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"பரிந்துரைகள்"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"அளவீடுகள்"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"ஒட்டுமொத்தமாகப் பக்கம் ஏற்றப்படும் அனுபவத்தை மேம்படுத்தவும், இதனால் பக்கம் விரைவாக எதிர்வினையாற்றும், அத்துடன் முடிந்தளவு விரைவாகப் பயன்படுத்தத் தயாராக இருக்கும். முக்கிய அளவீடுகள்: 'எதிர்வினை நேரம்', 'வேக அட்டவணை'"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"ஒட்டுமொத்த மேம்பாடுகள்"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"இணையச் செயல்திறன்"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"தற்காலிக நினைவக TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"அளவு (கி.பை.)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"செலவிட்ட நேரம்"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"தோராயமான சேமிப்பு (கி.பை.)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"தோராயமான சேமிப்புகள் (மி.வி.)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"சேமிக்கக்கூடிய அளவு: {wastedBytes, number, bytes} கி.பை."},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"சேமிக்கக்கூடிய நேரம்: {wastedMs, number, milliseconds} மி.வி."},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} மி.வி."},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} வி"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"தணிக்கைகளைக் காட்டு"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"துவக்க நெட்வொர்க் கோரிக்கை"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"முக்கியக் கோரிக்கைத் தடத்தின் அதிகபட்சத் தாமதம்:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"பிழை!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"அறிக்கைப் பிழை: தணிக்கைத் தகவல் இல்லை"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"ஆய்வகத் தரவு"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"எமுலேட்டட் 3G இல் தற்போதைய பக்கத்தின் [Lighthouse](https://developers.google.com/web/tools/lighthouse/) பகுப்பாய்வு. மதிப்புகள் தோராயமானவை, மாறுபடக்கூடியவை."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"கைமுறையாகச் சரிபார்க்க வேண்டிய கூடுதல் விஷயங்கள்"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"பொருந்தாதது"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"பரிந்துரை"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"தோராயமான சேமிப்பு"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"தேர்ச்சி பெற்ற தணிக்கைகள்"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"ஸ்கோர் அளவு:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Lighthouseஸின் இந்த இயக்கத்தைச் சில சிக்கல்கள் பாதிக்கின்றன:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"மதிப்புகள் தோராயமானவை மற்றும் மாறுபடக்கூடியவை."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"எச்சரிக்கைகள்: "}};
-
-
-},{}],75:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome ఎక్స్‌టెన్షన్‌లు ఈ పేజీ లోడ్ పనితీరును ప్రతికూలంగా ప్రభావితం చేసాయి. ఎక్స్టెన్షన్‌లు లేకుండా పేజీని అజ్ఞాత మోడ్‌లో లేదా ఎక్స్‌టెన్షన్‌లు లేని Chrome ప్రొఫైల్‌లో ఆడిట్ చేయడాన్ని ప్రయత్నించండి."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"స్క్రిప్ట్ మూల్యనిర్ధారణ"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"స్క్రిప్ట్ అన్వయింపు"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"మొత్తం"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"అన్వయించడం, సంగ్రహణ చేయడం మరియు JSను అమలు చేయడానికి వెచ్చించే సమయాన్ని తగ్గించడాన్ని పరిగణించండి. చిన్న JS పేలోడ్‌లను అందించడం ఈ విషయంలో మీకు సహాయకరంగా అనిపించవచ్చు. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"JavaScript అమలు సమయాన్ని తగ్గించండి"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript అమలు సమయం"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"యానిమేట్ చేయబడిన కంటెంట్‌ను అందించడంలో పెద్ద GIFలు సమర్థవంతంగా పనిచేయవు. నెట్‌వర్క్ బైట్‌లను పొదుపు చేయడానికి GIFకి బదులుగా యానిమేషన్ కోసం MPEG4/WebM వీడియోలను, నిశ్చల చిత్రాల కోసం PNG/WebPను ఉపయోగించడాన్ని పరిగణించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"యానిమేటెడ్ కంటెంట్ కోసం వీడియో ఫార్మాట్‌లను ఉపయోగించండి"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"పేజీలో పూర్తి పరస్పర చర్యకు పట్టే సమయం తక్కువగా ఉన్నప్పుడు అన్ని క్లిష్టమైన వనరులు లోడ్ అవ్వడం పూర్తి చేసి, ఆ తర్వాతే ఆఫ్‌స్క్రీన్ మరియు దాగి ఉన్న చిత్రాలను నెమ్మదిగా లోడ్ చేయడాన్ని పరిగణించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"ఆఫ్‌స్క్రీన్ చిత్రాలను వాయిదా వేయండి"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"వనరులు మీ పేజీ మొదటి పెయింట్‌ను బ్లాక్ చేస్తున్నాయి. క్లిష్టమైన JS/CSSలను ఇన్‌లైన్‌లో పంపించడం మరియు క్లిష్టం-కాని అన్ని JS/శైలులను తీసివేయడాన్ని పరిగణించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"రెండర్-బ్లాకింగ్ వనరులను నివారించండి"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"పెద్ద నెట్‌వర్క్ పేలోడ్‌లకు వినియోగదారులు నిజమైన డబ్బును చెల్లించాలి మరియు అవి అధికంగా సుదీర్ఘ లోడ్ సమయాలతో ముడిపడి ఉంటాయి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"మొత్తం పరిమాణం {totalBytes, number, bytes} KBగా ఉండేది"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"అతి పెద్ద నెట్‌వర్క్ పేలోడ్‌లను నివారించండి"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"అతి పెద్ద నెట్‌వర్క్ పేలోడ్‌లను నివారిస్తుంది"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS ఫైల్‌లను చిన్నవిగా చేయడం నెట్‌వర్క్ పేలోడ్ పరిమాణాలను తగ్గించవచ్చు. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSSని చిన్నదిగా చేయండి"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"JavaScript ఫైల్‌లను చిన్నవిగా చేయడం పేలోడ్ పరిమాణాలని మరియు స్క్రిప్ట్‌ను అన్వయించడానికి పట్టే సమయాన్ని తగ్గించగలదు. [మరింత తెలుసుకోండి](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScriptను చిన్నదిగా చేయండి"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"నెట్‌వర్క్ కార్యకలాపం ఉపయోగిస్తున్న అనవసర బైట్‌లను తగ్గించడానికి శైలిషీట్‌ల నుండి ఉపయోగించని నియమాలను తీసివేయండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"ఉపయోగించని CSSను వాయిదా వేయండి"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"నెట్‌వర్క్ కార్యకలాపం వినియోగించే బైట్‌లను తగ్గించడానికి ఉపయోగించని JavaScriptను తీసివేయండి."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"ఉపయోగించని JavaScriptను తీసివేయండి"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"దీర్ఘమైన కాష్ జీవితకాలం మీ పేజీకి పునరావృత సందర్శనలను వేగవంతం చేయవచ్చు. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 వనరు కనుగొనబడింది}other{ # వనరులు కనుగొనబడ్డాయి}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"నిశ్చల ఆస్తులను సమర్ధవంతమైన కాష్ విధానంతో అందించండి"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"నిశ్చలమైన ఆస్తులపై సమర్ధవంతమైన కాష్ విధానాన్ని ఉపయోగిస్తుంది"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"ఆప్టిమైజ్ చేయబడిన చిత్రాలు త్వరగా లోడ్ అవుతాయి మరియు తక్కువ సెల్యులార్ డేటాను ఉపయోగిస్తాయి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"చిత్రాలను సమర్థవంతంగా ఎన్‌కోడ్ చేయండి"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"సెల్యులార్ డేటాను పొదుపు చేయడానికి మరియు లోడ్ సమయాన్ని మెరుగుపరచడానికి తగిన-పరిమాణానికి మార్చబడిన చిత్రాలను అందించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"చిత్రాల పరిమాణాన్ని సరిగ్గా మార్చండి"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"మొత్తం నెట్‌వర్క్ బైట్‌లను తగ్గించడానికి వచనం-ఆధారిత వనరులు ఖచ్చితంగా కుదింపు (gzip, deflate లేదా brotli)తో అందించబడాలి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"వచనం కుదింపును ప్రారంభించండి"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000, JPEG XR, మరియు WebP వంటి చిత్రం ఫార్మాట్‌లు తరచుగా PNG లేదా JPEG కంటే మెరుగైన కుదింపును అందిస్తాయి, దీనర్ధం వేగవంతమైన డౌన్‌లోడ్‌లు మరియు తక్కువ డేటా వినియోగం. [మరింత తెలుసుకోండి] (https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"చిత్రాలను తర్వాతి-తరం ఫార్మాట్‌లలో అందించండి"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"కింది క్లిష్టమైన అభ్యర్ధన గొలుసులు ఏ వనరులు అధిక ప్రాధాన్యతతో లోడ్ అయ్యాయో చూపిస్తాయి. పేజీ లోడ్‌ను మెరుగుపరచడానికి గొలుసుల పొడవును తగ్గించడం, వనరుల డౌన్‌లోడ్ పరిమాణాన్ని తగ్గించడం, లేదా అనవసర వనరులను డౌన్‌లోడ్ చేయడాన్ని వాయిదా వేయడం పరిగణించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 గొలుసు కనుగొనబడింది}other{# గొలుసులు కనుగొనబడ్డాయి}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"క్లిష్టమైన అభ్యర్ధనల గాఢత్వమును తగ్గించండి"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"పేజీలలో ~1,500 కన్నా తక్కువ DOM నోడ్‌లు ఉండాలని బ్రౌజర్ ఇంజినీర్లు సిఫార్సు చేస్తారు. ఉత్తమమైన స్థాయి < 32 అంశాల ట్రీ గాఢత మరియు 60 పిల్లలు/తల్లి/తండ్రి అంశం కన్నా తక్కువ ఉండడం. పెద్ద DOM మెమరీ వినియోగాన్ని పెంచవచ్చు, సుదీర్ఘ [శైలి గణనలు] కు దారి తీయవచ్చు (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), మరియు ఖరీదైన [లేఅవుట్ రీఫ్లోలు]ను ఉత్పత్తి చేయవచ్చు (https://developers.google.com/speed/articles/reflow). [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 నోడ్}other{# నోడ్‌లు}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"అధిక DOM పరిమాణాన్ని నివారించండి"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"DOM గరిష్ట గాఢత్వము"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"మొత్తం DOM నోడ్‌లు"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"అధిక DOM పరిమాణాన్ని నివారిస్తుంది"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"వెబ్ ఫాంట్‌లు లోడ్ అవుతున్నప్పుడు వచనం వినియోగదారుకు కనిపించేలా ఉందని నిర్ధారించుకోవడానికి ఫాంట్-ప్రదర్శన CSS ఫీచర్‌ను శక్తివంతం చేయండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"వెబ్ ఫాంట్ లోడ్ సమయంలో వచనం కనిపించేటట్లు నిర్ధారించుకోండి"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"వెబ్ ఫాంట్ లోడ్‌ల సమయంలో వచనం మొత్తం కనిపిస్తూ ఉంటుంది"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"వర్గం"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"అన్వయించడం, సంగ్రహణ చేయడం మరియు JSను అమలు చేయడానికి వెచ్చించే సమయాన్ని తగ్గించడాన్ని పరిగణించండి. చిన్న JS పేలోడ్‌లను అందించడం ఈ విషయంలో మీకు సహాయకరంగా అనిపించవచ్చు."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"ప్రధాన థ్రెడ్ పనిని తగ్గించండి"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"ప్రధాన థ్రెడ్ పనిని తగ్గిస్తుంది"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"పేజీ లోడ్‌కు అత్యంత రద్దీ అయిన 5 సెకన్ల విండో సమయంలో, వినియోగదారు ఇన్‌పుట్‌కు ప్రతిస్పందిచడానికి, మిల్లీ సెకండ్లలో, మీ యాప్ తీసుకునే సమయం యొక్క అంచనాని పైన పేర్కొన్న స్కోర్ అందిస్తుంది. మీ ప్రతి స్పందన సమయం 50మి. సె కన్నా ఎక్కువ అయితే, మీ యాప్ వేగవంతంగా పని చేయట్లేదని వినియోగదారులు భావించవచ్చు. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"అంచనా వేయబడిన ఇన్‌పుట్ ప్రతిస్పందన సమయం"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"మొదటి కంటెంట్ సహిత పెయింట్ ఏదైనా వచనం లేదా చిత్రం మొదటిసారి పెయింట్ చేయబడిన సమయాన్ని గుర్తిస్తుంది. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"మొదటి కంటెంట్ సహిత పెయింట్"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"మొదటి CPU ఖాళీ సమయం మొదటి సారిగా పేజీ యొక్క ప్రధాన థ్రెడ్ ఇన్‌పుట్‌ను నిర్వహించడానికి సరిపోయినంత ఖాళీగా ఉన్న సమయాన్ని గుర్తిస్తుంది. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU మొదటి ఖాళీ సమయం"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"మొదటి అర్ధవంతమైన పెయింట్ ఒక పేజీ ప్రాథమిక కంటెంట్ ఎప్పుడు కనిపించింది అనేదానికి ఒక కొలమానం. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"మొదటి అర్థవంతమైన పెయింట్"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"పేజీలో పూర్తి పరస్పర చర్యకు పట్టే సమయం, ఆ పేజీ పరస్పర చర్యకు పూర్తిగా సిద్దమయ్యేందుకు తీసుకున్న సమయాన్ని గుర్తిస్తుంది. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"పేజీలో పూర్తి పరస్పర చర్యకు పట్టే సమయం"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"వేగం సూచిక ఒక పేజీ కంటెంట్‌లు ఎంత వేగంగా ప్రత్యక్షంగా చూపించబడతాయో చూపిస్తుంది. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"వేగం సూచిక"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"మళ్లింపులు పేజీ లోడ్ అవ్వడానికి ముందు అదనపు ఆలస్యాలను కలగచేస్తాయి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"అనేక పేజీ మళ్లింపులను నివారించండి"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"మొదటి బైట్ సమయం మీ సర్వర్ ప్రతిస్పందనను పంపించిన సమయాన్ని గుర్తిస్తుంది. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"రూట్ పత్రం {timeInMs, number, milliseconds} మి. సె తీసుకుంది"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"సర్వర్ ప్రతిస్పందన సమయాలను తగ్గించండి (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"సర్వర్ ప్రతిస్పందన సమయాలు తక్కువగా ఉన్నాయి (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"వ్యవధి"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"పేరు"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"ప్రారంభ సమయం"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"రకం"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"కీలక వినియోగదారు అనుభవాల సమయంలో మీ యాప్ వాస్తవ ప్రపంచ పనితీరును అంచనా వేయడానికి, మీ యాప్ కోసం వినియోగదారు సమయానుకూల APIని కొలమానంగా చేసుకుని పరిశీలించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 వినియోగదారు సమయం}other{# వినియోగదారు సమయాలు}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"వినియోగదారు సమయం మార్కులు మరియు కొలమానాలు"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"ముఖ్యమైన మూడవ-పక్ష మూలాలకు ముందస్తు కనెక్ష్‌లను స్థాపించడానికి ముందుగా కనెక్ట్ చేయి లేదా dns ప్రి-ఫెచింగ్ వనరు సూచనలను జోడించడాన్ని పరిగణించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"అవసరమైన మూలాలకు ముందుగా కనెక్ట్ చేయండి"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"ప్రస్తుతం పేజీ లోడ్‌లో తర్వాత అభ్యర్ధించబడిన వనరులను పొందడాన్ని ప్రాధాన్యపరచడానికి <link rel=preload>ను ఉపయోగించడాన్ని పరిగణించండి. [మరింత తెలుసుకోండి](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"కీలక అభ్యర్ధనలను ముందుగా లోడ్ చేయండి"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"మీ అప్లికేషన్ పనితీరు గురించి మరింత సమాచారం."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"సమస్య విశ్లేషణ"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"పిక్సెల్‌లు ఎంత వేగంగా స్క్రీన్ పై ప్రదర్శింపబడతాయి అనేది పనితీరులో అతి క్లష్టమైన అంశం. కీలక గణంకాలు: మొదటి కంటెంట్ సహిత పెయింట్, మొదటి అర్ధవంతమైన పెయింట్"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"మొదటి పెయింట్ మెరుగుదలలు"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"ఈ ఆప్టిమైజేషన్‌లు మీ పేజీ లోడ్‌ అవ్వడాన్ని వేగవంతం చేయవచ్చు."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"అవకాశాలు"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"గణాంకాలు"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"పేజీ ఎంత త్వరగా వీలైతే అంత త్వరగా ప్రతిస్పందించి, ఉపయోగించడానికి సిద్దంగా ఉండడానికి, మొత్తం లోడింగ్ అనుభవాన్ని మెరుగుపరచండి. కీలక గణాంకాలు: పేజీలో పూర్తి పరస్పర చర్యకు పట్టే సమయం, వేగం సూచిక"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"మొత్తం మొరుగుదలలు"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"పనితీరు"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"కాష్ TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"పరిమాణం (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"వెచ్చించిన సమయం"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"ఆదా చేయగల పరిమాణం (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"ఆదా చేయగల వ్యవధి (మి. సె)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"ఆదా చేయగల పరిమాణం {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"ఆదా చేయగల వ్యవధి {wastedMs, number, milliseconds} మి. సెలు"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} మి. సె"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} సె"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"ఆడిట్‌లను చూపించండి"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"ప్రారంభ నావిగేషన్"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"గరిష్ట క్లిష్టమైన మార్గ ప్రతిస్పందన సమయం:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"ఎర్రర్ ఏర్పడింది!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"నివేదిక ఎర్రర్: ఆడిట్ సమాచారం లేదు"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"ల్యాబ్ డేటా"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"ఎములేటెడ్ 3Gలో ప్రస్తుత పేజీ [లైట్‌హౌస్](https://developers.google.com/web/tools/lighthouse/) విశ్లేషణ. విలువలు అంచనా ప్రకారం అందించినవి, కనుక తేడాలు ఉండవచ్చు."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"మాన్యువల్‌గా తనిఖీ చేయవలసిన అదనపు అంశాలు"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"వర్తించదు"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"అవకాశం"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"అంచనా వేసిన పొదుపులు"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"ఉత్తీర్ణత సాధించిన ఆడిట్‌లు"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"స్కోర్ స్థాయి:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Lighthouse యొక్క ఈ అమలును ప్రభావితం చేసిన సమస్యలు ఉన్నాయి:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"విలువలు అంచనా వేయబడ్డాయి మరియు మారవచ్చు."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"హెచ్చరికలు: "}};
-
-
-},{}],76:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"ส่วนขยาย Chrome ส่งผลเสียต่อประสิทธิภาพในการโหลดของหน้านี้ ลองตรวจสอบหน้าในโหมดไม่ระบุตัวตนหรือจากโปรไฟล์ Chrome ที่ไม่มีส่วนขยาย"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"การประเมินสคริปต์"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"การแยกวิเคราะห์สคริปต์"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"รวม"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"พิจารณาลดเวลาที่ใช้ในการแยกวิเคราะห์ แปลโปรแกรม และดำเนินการกับ JS การส่งเปย์โหลด JS ปริมาณน้อยอาจช่วยในเรื่องนี้ได้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/bootup)"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"ลดเวลาในการดำเนินการกับ JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"เวลาในการดำเนินการกับ JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"GIF ขนาดใหญ่ไม่มีประสิทธิภาพในการแสดงเนื้อหาภาพเคลื่อนไหว พิจารณาใช้วิดีโอ MPEG4/WebM สำหรับภาพเคลื่อนไหวและใช้ PNG/WebP สำหรับภาพนิ่งแทน GIF เพื่อประหยัดไบต์ของเครือข่าย [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"ใช้รูปแบบวิดีโอสำหรับเนื้อหาภาพเคลื่อนไหว"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"พิจารณาโหลดรูปภาพนอกหน้าจอและรูปภาพที่ซ่อนไว้เท่าที่จำเป็นหลังจากที่ทรัพยากรที่สำคัญทั้งหมดโหลดเสร็จแล้วเพื่อลดเวลาในการโต้ตอบ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"เลื่อนเวลาโหลดรูปภาพนอกจอภาพ"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"ทรัพยากรบล็อกการแสดงผลครั้งแรกของหน้าเว็บอยู่ พิจารณาแสดง JS/CSS ที่สำคัญในหน้าและเลื่อนเวลาแสดง JS/สไตล์ที่ไม่สำคัญทั้งหมดออกไป [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"กำจัดทรัพยากรที่บล็อกการแสดงผล"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"เปย์โหลดปริมาณมากของเครือข่ายทำให้ผู้ใช้เสียค่าใช้จ่ายสูงและสัมพันธ์กับเวลาการโหลดนานเป็นอย่างมาก [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"ขนาดรวมเดิมคือ {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"หลีกเลี่ยงเปย์โหลดเครือข่ายปริมาณมาก"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"หลีกเลี่ยงเปย์โหลดเครือข่ายปริมาณมาก"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"การลดขนาดไฟล์ CSS ช่วยลดขนาดเปย์โหลดของเครือข่ายได้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/minify-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"ลดขนาด CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"การลดขนาดไฟล์ JavaScript ช่วยลดขนาดเปย์โหลดและเวลาในการแยกวิเคราะห์สคริปต์ได้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/speed/docs/insights/MinifyResources)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"ลดขนาด JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"นำกฎที่ไม่ได้ใช้ออกจากสไตล์ชีตเพื่อลดจำนวนไบต์ที่ไม่จำเป็นที่กิจกรรมเครือข่ายใช้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/unused-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"เลื่อนเวลาโหลด CSS ที่ไม่ได้ใช้"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"นำ JavaScript ที่ไม่ได้ใช้ออกเพื่อลดจำนวนไบต์ที่กิจกรรมเครือข่ายใช้"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"นำ JavaScript ที่ไม่ได้ใช้ออก"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"อายุการใช้งานแคชที่ยาวนานช่วยเพิ่มการเข้าชมหน้าเว็บซ้ำได้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{พบทรัพยากร 1 รายการ}other{พบทรัพยากร # รายการ}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"แสดงเนื้อหาคงที่ที่มีนโยบายแคชที่มีประสิทธิภาพ"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"ใช้นโยบายแคชที่มีประสิทธิภาพกับเนื้อหาคงที่"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"รูปภาพที่ได้รับการเพิ่มประสิทธิภาพจะโหลดได้เร็วขึ้นและใช้อินเทอร์เน็ตมือถือน้อยลง [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"เข้ารหัสรูปภาพอย่างมีประสิทธิภาพ"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"แสดงรูปภาพที่มีขนาดเหมาะสมเพื่อประหยัดอินเทอร์เน็ตมือถือและปรับปรุงเวลาในการโหลด [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"ปรับขนาดรูปภาพให้เหมาะสม"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"ทรัพยากรแบบข้อความควรแสดงผลโดยมีการบีบอัด (Gzip, Deflate หรือ Brotli) เพื่อลดจำนวนไบต์เครือข่ายทั้งหมด [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"เปิดใช้การบีบอัดข้อความ"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"รูปแบบรูปภาพอย่างเช่น JPEG 2000, JPEG XR และ WebP มักบีบอัดได้ดีกว่า PNG หรือ JPEG ซึ่งหมายความว่าจะดาวน์โหลดได้เร็วขึ้นและใช้อินเทอร์เน็ตน้อยลง [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/webp)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"แสดงรูปภาพในรูปแบบสมัยใหม่"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"ห่วงโซ่คำขอที่สำคัญด้านล่างแสดงให้เห็นทรัพยากรที่โหลดโดยมีลำดับความสำคัญสูง พิจารณาลดความยาวของห่วงโซ่ ลดขนาดการดาวน์โหลดของทรัพยากร หรือเลื่อนเวลาการดาวน์โหลดทรัพยากรที่ไม่จำเป็นเพื่อปรับปรุงการโหลดหน้าเว็บ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{พบห่วงโซ่ 1 รายการ}other{พบห่วงโซ่ # รายการ}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"ลดความลึกของคำขอที่สำคัญ"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"วิศวกรเบราว์เซอร์แนะนำให้ใช้หน้าเว็บที่มีโหนด DOM น้อยกว่าประมาณ 1,500 รายการ ความลึกที่เหมาะที่สุดคือแบบต้นไม้ซึ่งมีองค์ประกอบน้อยกว่า 32 รายการและมีองค์ประกอบย่อย/หลักน้อยกว่า 60 รายการ DOM ขนาดใหญ่อาจใช้หน่วยความจำเพิ่มขึ้น ทำให้[การคำนวณสไตล์](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations)ยาวนานขึ้น และสร้าง[การจัดเรียงการออกแบบใหม่](https://developers.google.com/speed/articles/reflow)ที่ต้องใช้ค่าใช้จ่ายสูง [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/dom-size)"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 โหนด}other{# โหนด}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"หลีกเลี่ยง DOM ที่มีขนาดใหญ่เกินไป"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"ความลึก DOM สูงสุด"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"โหนด DOM ทั้งหมด"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"หลีกเลี่ยง DOM ที่มีขนาดใหญ่เกินไป"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"ใช้ประโยชน์จากฟีเจอร์ CSS สำหรับแสดงแบบอักษรเพื่อให้ผู้ใช้มองเห็นข้อความได้ในขณะที่กำลังโหลดเว็บฟอนต์ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/updates/2016/02/font-display)"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"ตรวจสอบว่าข้อความจะยังมองเห็นได้ในระหว่างการโหลดเว็บฟอนต์"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"ข้อความทั้งหมดจะยังมองเห็นได้ในระหว่างการโหลดเว็บฟอนต์"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"หมวดหมู่"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"พิจารณาลดเวลาที่ใช้ในการแยกวิเคราะห์ แปลโปรแกรม และดำเนินการกับ JS การส่งเปย์โหลด JS ปริมาณน้อยอาจช่วยในเรื่องนี้ได้"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"ลดการทำงานของเธรดหลัก"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"ลดการทำงานของเธรดหลัก"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"คะแนนข้างต้นเป็นระยะเวลาโดยประมาณที่แอปใช้เพื่อตอบสนองอินพุตของผู้ใช้ระหว่างการโหลดหน้าเว็บในกรอบเวลา 5 วินาทีที่ทำงานหนักที่สุด มีหน่วยเป็นมิลลิวินาที หากเวลาในการตอบสนองนานกว่า 50 มิลลิวินาที ผู้ใช้อาจรู้สึกว่าแอปช้า [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"เวลาในการตอบสนองต่ออินพุตโดยประมาณ"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"First Contentful Paint ระบุเวลาที่มีการแสดงผลข้อความหรือรูปภาพครั้งแรก [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"การแสดงผลที่มีเนื้อหาเต็มครั้งแรก"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"CPU ไม่ได้ใช้งานครั้งแรกระบุครั้งแรกที่เธรดหลักของหน้าเว็บว่างพอที่จะจัดการกับอินพุต [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU ไม่ได้ใช้งานครั้งแรก"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"การแสดงผลที่มีความหมายครั้งแรกวัดเมื่อเนื้อหาหลักของหน้าเว็บปรากฏ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"การแสดงผลที่มีความหมายครั้งแรก"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"การโต้ตอบระบุเวลาที่หน้าเว็บโต้ตอบได้อย่างสมบูรณ์ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"เวลาในการโต้ตอบ"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"ดัชนีความเร็วแสดงให้เห็นความเร็วที่เนื้อหาของหน้าปรากฏจนดูสมบูรณ์ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/speed-index)"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"ดัชนีความเร็ว"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"การเปลี่ยนเส้นทางทำให้เกิดความล่าช้ามากขึ้นก่อนที่หน้าเว็บจะโหลดได้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/redirects)"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"หลีกเลี่ยงการเปลี่ยนเส้นทางหลายหน้า"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"เวลาที่ใช้ไบต์แรกระบุเวลาที่เซิร์ฟเวอร์ส่งการตอบกลับ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/ttfb)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"เอกสารรากใช้เวลา {timeInMs, number, milliseconds} มิลลิวินาที"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"ลดเวลาในการตอบกลับของเซิร์ฟเวอร์ (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"เวลาตอบสนองของเซิร์ฟเวอร์ต่ำ (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"ระยะเวลา"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"ชื่อ"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"เวลาเริ่มต้น"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"ประเภท"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"พิจารณาติดตั้ง User Timing API ในแอปเพื่อวัดประสิทธิภาพในระหว่างประสบการณ์สำคัญของผู้ใช้ในชีวิตจริงได้ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/user-timing)"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{ระยะเวลาของผู้ใช้ 1 รายการ}other{ระยะเวลาของผู้ใช้ # รายการ}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"ระยะเวลาที่เจาะจงของผู้ใช้และระยะเวลาทั่วไป"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"พิจารณาเพิ่มการเชื่อมต่อล่วงหน้าหรือดึงข้อมูล DNS ล่วงหน้าสำหรับการเปลี่ยนแปลงทรัพยากรเพื่อสร้างการเชื่อมต่อกับต้นทางที่สำคัญของบุคคลที่สามตั้งแต่เนิ่นๆ [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"เชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"พิจารณาใช้ <link rel=preload> เพื่อจัดลำดับความสำคัญในการเรียกทรัพยากรที่มีการขอให้โหลดหน้าเว็บภายหลัง [ดูข้อมูลเพิ่มเติม](https://developers.google.com/web/tools/lighthouse/audits/preload)"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"โหลดคำขอสำคัญล่วงหน้า"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"ข้อมูลเพิ่มเติมเกี่ยวกับประสิทธิภาพของแอปพลิเคชัน"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"การวินิจฉัย"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"ประสิทธิภาพที่สำคัญที่สุดคือความเร็วที่พิกเซลแสดงผลในหน้าจอ เมตริกที่สำคัญ ได้แก่ การแสดงผลที่มีเนื้อหาเต็มครั้งแรก การแสดงผลที่มีความหมายครั้งแรก"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"การปรับปรุงการแสดงผลครั้งแรก"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"การเพิ่มประสิทธิภาพเหล่านี้เพิ่มความเร็วในการโหลดหน้าเว็บได้"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"โอกาส"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"เมตริก"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"ปรับปรุงประสบการณ์ในการโหลดโดยรวมเพื่อให้หน้าเว็บตอบสนองและพร้อมใช้งานโดยเร็วที่สุด เมตริกที่สำคัญ ได้แก่ เวลาในการโต้ตอบ ดัชนีความเร็ว"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"การปรับปรุงโดยรวม"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"ประสิทธิภาพ"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"แคช TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"ขนาด (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"เวลาที่ใช้"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"ไบต์ที่อาจประหยัดได้ (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"เวลาที่อาจประหยัดได้ (มิลลิวินาที)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"อาจประหยัดได้ {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"อาจประหยัดเวลาได้ {wastedMs, number, milliseconds} มิลลิวินาที"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} มิลลิวินาที"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} วินาที"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"แสดงการตรวจสอบ"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"การนำทางเริ่มต้น"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"เวลาในการตอบสนองของเส้นทางสำคัญที่ยาวที่สุด"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"ข้อผิดพลาด!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"ข้อผิดพลาดในรายงาน: ไม่มีข้อมูลการตรวจสอบ"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"ข้อมูลในห้องทดลอง"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) การวิเคราะห์หน้าปัจจุบันบน 3G จำลอง ค่าต่างๆ เป็นค่าประมาณและอาจแตกต่างกันไป"},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"รายการเพิ่มเติมที่ควรตรวจสอบด้วยตนเอง"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"ไม่เกี่ยวข้อง"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"โอกาส"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"เวลาที่ประหยัดได้โดยประมาณ"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"การตรวจสอบที่ผ่านแล้ว"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"ระดับคะแนน"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"เกิดปัญหาที่มีผลต่อการทำงานนี้ของ Lighthouse"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"ค่ามาจากการประมาณและอาจแตกต่างกันไป"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"คำเตือน "}};
-
-
-},{}],77:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome uzantıları bu sayfanın yükleme performansını olumsuz etkilemiştir. Sayfayı gizli modda veya uzantı içermeyen bir Chrome profilinden denetlemeyi deneyin."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Komut Dosyası Değerlendirmesi"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Komut Dosyası Ayrıştırma"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Toplam"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"JS'yi ayrıştırma, derleme ve yürütme için harcanan zamanı azaltma seçeneğini değerlendirin. Daha küçük JS yüklerinin sağlanmasının bu konuda yardımcı olduğunu fark edebilirsiniz. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"JavaScript yürütme süresini azaltın"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript yürütme süresi"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Büyük GIF'ler, animasyonlu içeriğin sunulmasında verimli olmaz. Ağ veri miktarından tasarruf etmek üzere animasyonlar için MPEG4/WebM videoları ve statik resimler için GIF yerine PNG/WebP kullanma seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Animasyonlu içerik için video biçimleri kullanın"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Etkileşimli hale gelme süresini kısaltmak için ekran dışındaki ve gizli resimleri, tüm kritik kaynakların yüklenmesi bittikten sonra gecikmeli olarak yükleme seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Ekran dışındaki resimleri ertele"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Kaynaklar, sayfanızda ilk boyayı engelliyor. Kritik JS/CSS'yi satır içinde yayınlama ve kritik olmayan tüm JS/stilleri erteleme seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Oluşturmayı engelleyen kaynakları ortadan kaldırın"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Büyük ağ yüklerinin kullanıcılara maddi anlamda maliyeti vardır ve bu ağ yükleri, uzun yükleme süreleriyle yakından ilişkilidir. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Toplam boyut: {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Çok büyük ağ yüklerinden kaçının"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Çok büyük ağ yüklerini önler"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"CSS dosyalarının küçültülmesi ağ yükü boyutlarını azaltabilir. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"CSS'yi küçültün"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"JavaScript dosyalarının küçültülmesi yük boyutlarını azaltabilir ve komut dosyası ayrıştırma süresini kısaltabilir. [Daha fazla bilgi](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"JavaScript'i küçült"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Ağ etkinliğiyle tüketilen gereksiz bayt sayısını azaltmak için kullanılmayan kuralları stil sayfalarından kaldırın. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Kullanılmayan CSS'yi erteleyin"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Ağ etkinliğinin kullandığı bayt sayısını azaltmak için kullanılmayan JavaScript'i kaldırın."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Kullanılmayan JavaScript'i kaldırın"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Uzun önbellek ömrü, sayfanızın tekrar ziyaret edilmesi sürecini hızlandırabilir. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{1 kaynak bulundu}other{# kaynak bulundu}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Statik öğeleri verimli bir önbellek politikasıyla yayınlayın"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Statik öğelerde verimli önbellek politikası kullanır"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Optimize edilmiş resimler daha hızlı yüklenir ve daha az hücresel veri kullanır. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Resimleri verimli bir şekilde kodlayın"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Hücresel veriden tasarruf etmek ve yükleme süresini iyileştirmek için uygun boyutlu resimler sunun. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Doğru boyuta sahip resimler"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Metne dayalı kaynaklar, toplam ağ baytı sayısını en aza indirmek için sıkıştırılarak (gizp, deflate veya brotli) yayınlanmalıdır. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Metin sıkıştırmayı etkinleştirin"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000, JPEG XR ve WebP gibi resim biçimleri genellikle PNG veya JPEG'den daha iyi sıkıştırma sağlar. Böylece indirme işlemleri daha hızlı tamamlanır ve veri tüketimi daha az olur. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Resimleri yeni nesil biçimlerde yayınlayın"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Aşağıdaki Kritik İstek Zincirleri, hangi kaynakların yüksek öncelikle yüklendiğini göstermektedir. Sayfa yüklemesini iyileştirmek için zincir uzunluğunu azaltma, kaynakların indirme boyutunu küçültme veya gereksiz kaynakların indirilmesini erteleme seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{1 zincir bulundu}other{# zincir bulundu}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Kritik İsteklerin Derinliğini En Aza İndirin"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Tarayıcı mühendisleri, sayfaların yaklaşık olarak 1500'den az DOM düğümü içermesini önerir. En etkili nokta, 32 öğeden ve 60 alt/üst öğeden az olan bir ağaç derinliğidir. Büyük bir DOM, bellek kullanımını artırarak daha uzun [stil hesaplamalarına] (https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) yol açabilir ve yüksek maliyetli [düzen yeniden düzenlemeleri](https://developers.google.com/speed/articles/reflow) oluşturabilir. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 düğüm}other{# düğüm}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Aşırı büyük bir DOM boyutundan kaçının"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Maksimum DOM Derinliği"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Toplam DOM Düğümü"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Aşırı büyük bir DOM boyutunu önler"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Web yazı tipleri yüklenirken kullanıcının metni görebilmesini sağlamak için yazı tipi görüntüleme CSS özelliğinden yararlanın. [Daha fazla bilgi](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Web yazı tipi yüklemesi sırasında metnin görünür halde kalmasını sağlayın"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Web yazı tipi yüklenirken tüm metin görünür halde kalır"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Kategori"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"JS'yi ayrıştırma, derleme ve yürütme için harcanan zamanı kısaltma seçeneğini değerlendirin. Daha küçük JS yüklerinin sağlanması bu konuda yardımcı olabilir."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Ana iş parçacığı çalışmasını en aza indir"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Ana iş parçacığının çalışmasını en aza indirir"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Yukarıdaki puan, sayfa yüklemesinin en yoğun olduğu 5 saniyelik zaman aralığında uygulamanızın kullanıcı girişine kaç milisaniye içinde yanıt vereceğine dair bir tahmindir. Gecikmeniz 50 ms'nin üzerinde olursa kullanıcılar uygulamanızın durakladığını düşünebilir. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Tahmini Giriş Gecikmesi"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"İlk Zengin İçerikli Boyama, ilk metnin veya resmin boyandığı zamanı işaret eder. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"İlk Zengin İçerikli Boya"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"İlk CPU Boşta metriği, sayfanın ana iş parçacığının girişi işlemek için yeterli olduğu ilk anı işaret eder. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"İlk CPU Boşta"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"İlk Anlamlı Boya, bir sayfanın ana içeriğinin ne zaman görünür hale geldiğini ölçer. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"İlk Anlamlı Boya"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Etkileşimli metriği, sayfanın tam olarak etkileşimli hale gelme süresini işaret eder. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Etkileşim Süresi"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Hız İndeksi, bir sayfa içeriğinin görsel olarak ne kadar hızlı doldurulabildiğini gösterir. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Hız İndeksi"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Yönlendirmeler, sayfanın yüklenmesinden önce ek gecikmelere neden olur. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Birden çok sayfa yönlendirmesini önleyin"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"İlk Bayt Zamanı, sunucunuzun bir yanıt gönderme zamanını tanımlar. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Root dokümanı {timeInMs, number, milliseconds} ms sürdü"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Sunucu yanıt sürelerini kısaltın (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Sunucu yanıt süreleri düşük (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Süre"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Ad"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Başlangıç Zamanı"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Tür"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Önemli kullanıcı deneyimleri esnasında uygulamanızın gerçek dünya performansını ölçmek için uygulamanıza User Timing API'si ekleme seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 kullanıcı zamanlaması}other{# kullanıcı zamanlaması}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Kullanıcı Zamanlaması işaretleri ve ölçüleri"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Önemli üçüncü taraf kaynaklarına erken bağlantılar oluşturmak için önceden bağlanma veya DNS önceden getirme kaynak ipuçları ekleme seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Gerekli kaynaklara önceden bağlan"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Şu anda istenen kaynakları sayfa yüklemenin sonraki aşamalarında getirmeye öncelik tanımak için <link rel=preload> öğesini kullanma seçeneğini değerlendirin. [Daha fazla bilgi](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Önemli istekleri önceden yükleyin"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Uygulamanızın performansı hakkında daha fazla bilgi."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Teşhis"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Performansın en kritik unsuru, piksellerin ekranda oluşturulma hızıdır. Önemli metrikler: İlk Zengin İçerikli Boya, İlk Anlamlı Boya"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"İlk Boya İyileştirmeleri"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Bu optimizasyonlar, sayfanızın yüklenmesini hızlandırabilir."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Fırsatlar"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Metrikler"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Toplam yükleme deneyimini geliştirerek sayfanın mümkün olan en kısa sürede duyarlı ve kullanıma hazır olmasını sağlayın. Önemli metrikler: Etkileşim Süresi, Hız İndeksi"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Toplam İyileştirmeler"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Performans"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL'yi Önbelleğe Alma"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Boyut (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Harcanan Süre"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Potansiyel Tasarruflar (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Potansiyel Tasarruf (ms)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"{wastedBytes, number, bytes} KB potansiyel tasarruf"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"{wastedMs, number, milliseconds} ms potansiyel tasarruf"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} ms"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} sn."},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Denetimleri göster"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"İlk Gezinme"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Maksimum kritik yol gecikmesi:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Hata!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Bildirme hatası: denetim bilgisi yok"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Test Verileri"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Mevcut sayfanın 3G kullanılarak gerçekleştirilen [Lighthouse](https://developers.google.com/web/tools/lighthouse/) analizi. Değerler tahmini olup değişiklik gösterebilir."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Manuel olarak kontrol edilecek ek öğeler"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Geçerli değil"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Fırsat"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Tahmini Tasarruf Miktarı"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Başarılı denetimler"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Puan ölçeği:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Şu Lighthouse çalışmasını etkileyen sorunlar vardı:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Değerler tahminidir ve değişiklik gösterebilir."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Uyarılar: "}};
-
-
-},{}],78:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Розширення Chrome негативно впливають на завантаження цієї сторінки. Спробуйте перевірити сторінку в режимі анонімного перегляду або в профілі Chrome без розширень."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Оцінка сценарію"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Синтаксичний аналіз сценарію"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Усього"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Радимо зменшити час синтаксичного аналізу, компілювання й запуску сценаріїв JavaScript. Завантажувати менші обсяги даних JavaScript може бути корисно. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Зменште час виконання JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Час виконання JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Великі файли GIF неефективні для передавання анімованого вмісту. Щоб заощадити байти мережі, радимо замість формату GIF використовувати MPEG4 або WebM для анімацій і PNG чи WebP для статичних зображень. [Докладніше](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Використовуйте формати відео для анімованого вмісту"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Щоб пришвидшити взаємодію, використовуйте закадрові й приховані зображення, коли завантажаться всі важливі ресурси. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Відкладіть закадрові зображення"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Ресурси блокують перше відображення сторінки. Вбудовуйте важливі файли JavaScript або CSS і відкладайте всі некритичні файли JavaScript чи стилі. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Вилучіть ресурси, які блокують відображення"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Великі обсяги мережевих даних дорогі для користувачів і довго завантажуються. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Загальний розмір – {totalBytes, number, bytes} KБ"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Уникайте великих обсягів даних у мережі"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Уникається великий обсяг даних мережі"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Стиснення файлів CSS може зменшити обсяг даних у мережі. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Зменште СSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Стиснення файлів JavaScript може зменшити обсяг даних і час синтаксичного аналізу сценарію. [Докладніше](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Зменште файл JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Видаліть із таблиць стилів правила, які ви не використовуєте, щоб зменшити кількість зайвих байтів під час активності в мережі. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Відкладіть вміст CSS, який не використовується"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Видаліть файли JavaScript, які ви не використовуєте, щоб зменшити кількість байтів під час активності в мережі."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Вилучіть файли JavaScript, які ви не використовуєте"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Збереження кешу за довгий час може пришвидшити завантаження сторінки під час повторних відвідувань. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Знайдено 1 ресурс}one{Знайдено # ресурс}few{Знайдено # ресурси}many{Знайдено # ресурсів}other{Знайдено # ресурсу}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Показуйте статичні об’єкти за допомогою ефективних правил кешування"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Використовуються ефективні правила кешування статичних об’єктів"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Оптимізовані зображення завантажуються швидше й використовують менше мобільного трафіку. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Ефективно кодуйте зображення"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Показуйте зображення правильного розміру, щоб заощадити мобільний трафік і покращити час завантаження. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Правильно виберіть розмір зображень"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Текстові ресурси потрібно відображати зі стисненням (Gzip, Deflate чи Brotli), щоб мінімізувати загальну кількість байтів у мережі. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Увімкніть стиснення тексту"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Формати зображень JPEG 2000, JPEG XR і WebP часто краще стискаються, ніж PNG чи JPEG. Тому вони швидше завантажуються й використовують менше даних. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Показуйте зображення в нових форматах"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Ланцюжки важливих запитів нижче показують, які ресурси мають високий пріоритет. Щоб пришвидшити завантаження сторінки, зменште довжину ланцюжків і розмір завантажень або відкладіть завантаження непотрібних ресурсів. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Знайдено 1 ланцюжок}one{Знайдено # ланцюжок}few{Знайдено # ланцюжки}many{Знайдено # ланцюжків}other{Знайдено # ланцюжка}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Мінімізуйте глибину важливих запитів"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Розробники веб-переглядачів радять, щоб сторінки містили до ~1500 вузлів DOM. Зона найкращого сприйняття – глибина дерева < 32 елементів і до 60 дитячих чи батьківських елементів. Великий файл DOM може збільшувати використання пам’яті, спричиняти довше [обчислення стилів](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) і створювати дороге [перекомпонування макетів](https://developers.google.com/speed/articles/reflow). [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 вузол}one{# вузол}few{# вузли}many{# вузлів}other{# вузла}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Уникайте надмірного розміру DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Максимальна глибина DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Загальна кількість вузлів DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Уникається надмірний розмір DOM"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Використовуйте функцію відображення шрифтів CSS, щоб текст було видно під час завантаження шрифтів. [Докладніше](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Переконайтеся, що текст залишається видимим під час завантаження веб-шрифту"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Увесь текст залишається видимим під час завантаження веб-шрифтів"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Категорія"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Зменште час виконання синтаксичного аналізу, компілювання й запуску сценаріїв JavaScript. Завантажувати менші обсяги даних JavaScript може бути корисно."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Мінімізуйте роботу основного потоку"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Мінімізується робота основного потоку"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Результат вище показує, скільки часу в мілісекундах додаток відповідає на ввід користувача під час п’ятисекундного періоду завантаження сторінки. Якщо затримка перевищує 50 мс, користувачі можуть вважати ваш додаток повільним. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Приблизна затримка введення"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Час завантаження першого вмісту показує, коли з’являється текст чи зображення. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Перше відображення всього вмісту"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Перший простій ЦП вказує, коли основний ланцюжок сторінки вперше може обробити введення. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"Перший простій ЦП"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Перше значне відображення вказує, коли видно основний вміст сторінки. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Перше значне відображення"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Показник взаємодії позначає час повної активності сторінки. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Час до повної взаємодії"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Індекс швидкості показує, через скільки часу відображається вміст сторінки. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Індекс швидкості"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Переспрямування додають затримки під час завантаження сторінки. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Уникайте переспрямувань кількох сторінок"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Час до першого байта визначає швидкість реакції сервера. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Кореневий документ відповів через {timeInMs, number, milliseconds} мс"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Зменште час відповіді сервера (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Сервер довго відповідає (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Тривалість"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Назва"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Час початку"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Тип"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Використовуйте в додатку User Timing API, щоб отримувати показники ефективності додатка під час взаємодії з користувачами. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 позначка часу користувача}one{# позначка часу користувача}few{# позначки часу користувача}many{# позначок часу користувача}other{# позначки часу користувача}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Показники й мітки часу користувача"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Додайте в ресурси корективи для попереднього з’єднання чи виклику DNS, щоб заздалегідь установлювати з’єднання з важливими джерелами третіх сторін. [Докладніше](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Попередньо під’єднуйтеся до потрібних джерел"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Використовуйте <link rel=preload>, щоб указати пріоритетність завантаження ресурсів, які наразі запитуються пізніше під час завантаження сторінки. [Докладніше](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Попередньо завантажуйте основні запити"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Докладніше про ефективність додатка."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Діагностика"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Найважливішим аспектом ефективності є швидкість відображення пікселів на екрані. Основні показники: перше відображення вмісту, перше значне відображення"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Покращення першого відображення"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Ці оптимізації можуть пришвидшити завантаження сторінки."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Можливості"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Показники"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Покращте загальну ефективність завантаження, щоб сторінка швидко реагувала й завантажувалася. Основні показники: час до повної взаємодії, індекс швидкості"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Загальні покращення"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Ефективність"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"TTL кешу"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Розмір (КБ)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Витрачений час"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL-адреса"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Потенційне заощадження (КБ)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Потенційне заощадження (мс)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Потенційне заощадження – {wastedBytes, number, bytes} КБ"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Потенційне заощадження – {wastedMs, number, milliseconds} мс"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} мс"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} c"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Показати перевірки"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Початкова навігація"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Максимальна критична затримка шляху:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Помилка."},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Повідомлення про помилку: немає інформації про перевірку"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Дані тестів"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Аналіз [Lighthouse](https://developers.google.com/web/tools/lighthouse/) поточної сторінки в імітованій мережі 3G. Значення приблизні й можуть відрізнятися."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Додаткові елементи, які потрібно перевірити вручну"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Не застосовуються"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Можливість"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Приблизне заощадження"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Виконані перевірки"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Шкала результатів:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Під час запуску Lighthouse виникли перелічені нижче проблеми."},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Значення приблизні й можуть відрізнятися."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Застереження. "}};
-
-
-},{}],79:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Các tiện ích của Chrome ảnh hưởng tiêu cực đến hiệu suất tải của trang này. Hãy thử kiểm tra trang ở chế độ ẩn danh hoặc từ một hồ sơ trên Chrome không có tiện ích."},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"Đánh giá tập lệnh"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"Phân tích cú pháp tập lệnh"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"Tổng"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"Hãy xem xét giảm thời gian dùng để phân tích cú pháp, biên soạn và thực thi JS. Bạn có thể giải quyết vấn đề này bằng cách phân phối các tải trọng JS nhỏ hơn. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/bootup)."},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"Giảm thời gian thực thi JavaScript"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"Thời gian thực thi JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"Các ảnh GIF lớn không hiệu quả trong việc phân phối nội dung động. Hãy xem xét sử dụng video MPEG4/WebM cho ảnh động và PNG/WebP cho ảnh tĩnh thay vì ảnh GIF để tiết kiệm dữ liệu mạng (số byte mạng). [Tìm hiểu thêm](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"Sử dụng các định dạng video cho nội dung động"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"Xem xét trì hoãn tải các hình ảnh ẩn và ngoài màn hình sau khi tất cả tài nguyên quan trọng tải xong để giảm thời gian tương tác. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)."},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"Trì hoãn tải các hình ảnh ngoài màn hình"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"Các tài nguyên đang chặn hình ảnh đầu tiên trang của bạn. Hãy xem xét phân phối nội dòng JS/CSS quan trọng và trì hoãn mọi JS/kiểu không quan trọng. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)."},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"Loại bỏ các tài nguyên chặn hiển thị"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"Tải trọng mạng lớn gây tốn tiền cho người dùng và thường dẫn đến thời gian tải lâu. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)."},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"Tổng kích thước là {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"Tránh các tài nguyên lớn trên mạng"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"Tránh tài nguyên lớn trên mạng"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"Việc giảm kích thước tệp CSS có thể giảm kích thước tài nguyên trên mạng. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/minify-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"Rút gọn CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"Việc giảm kích thước tệp JavaScript có thể giảm kích thước tải trọng và thời gian phân tích cú pháp tập lệnh. [Tìm hiểu thêm](https://developers.google.com/speed/docs/insights/MinifyResources)."},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"Rút gọn JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"Xóa các quy tắc không dùng khỏi tờ mẫu để giảm số byte không cần thiết tiêu tốn vào hoạt động mạng. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/unused-css)."},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"Trì hoãn tải CSS không dùng"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"Xóa JavaScript không dùng để giảm số byte tiêu tốn vào hoạt động mạng."},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"Xóa JavaScript không dùng"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"Tuổi thọ lâu dài của bộ nhớ đệm có thể tăng tốc số lượt truy cập lặp lại vào trang của bạn. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{Đã tìm thấy 1 tài nguyên}other{Đã tìm thấy # tài nguyên}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"Phân phối các nội dung tĩnh bằng chính sách bộ nhớ đệm hiệu quả"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"Sử dụng chính sách bộ nhớ đệm hiệu quả cho các nội dung tĩnh"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"Hình ảnh được tối ưu hóa sẽ tải nhanh hơn và tiêu tốn ít dữ liệu di động hơn. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"Mã hóa hình ảnh hiệu quả"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"Phân phối hình ảnh có kích thước phù hợp để tiết kiệm dữ liệu di động và cải thiện thời gian tải. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"Thay đổi kích thước hình ảnh cho phù hợp"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"Các tài nguyên dựa trên văn bản phải được phân phối ở định dạng nén (gzip, deflate hoặc brotli) để giảm thiểu tổng số byte mạng. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/text-compression)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"Bật tính năng nén văn bản"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"Các định dạng hình ảnh như JPEG 2000, JPEG XR và WebP thường nén tốt hơn so với các định dạng PNG hoặc JPEG. Điều này có nghĩa là tốc độ tải xuống nhanh hơn và tiêu tốn ít dữ liệu hơn. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/webp)."},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"Phân phối hình ảnh ở định dạng mới và hiệu quả hơn"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"Các chuỗi yêu cầu quan trọng dưới đây cho bạn biết những tài nguyên có mức độ ưu tiên cao sẽ được tải. Hãy cân nhắc giảm độ dài chuỗi, giảm kích thước tài nguyên tải xuống hoặc trì hoãn tải xuống các tài nguyên không cần thiết để cải thiện tốc độ tải trang. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)."},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{Đã tìm thấy 1 chuỗi}other{Đã tìm thấy # chuỗi}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"Giảm thiểu độ sâu của các yêu cầu quan trọng"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"Các công cụ của trình duyệt đề xuất các trang nên chứa ít hơn 1.500 nút DOM. Điểm ngọt là độ sâu của cây có ít hơn 32 thành phần và 60 thành phần con/cấp độ gốc. Một DOM lớn có thể tăng mức sử dụng bộ nhớ, khiến [các phép tính về kiểu](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations) dài hơn đồng thời tạo ra [các chỉnh sửa bố cục](https://developers.google.com/speed/articles/reflow) tốn kém. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/dom-size)."},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 nút}other{# nút}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"Tránh kích thước DOM quá lớn"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"Độ sâu DOM tối đa"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"Tổng số nút DOM"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"Tránh kích thước DOM quá lớn"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"Sử dụng tính năng CSS hiển thị phông chữ để đảm bảo văn bản hiển thị với người dùng khi phông chữ web đang tải. [Tìm hiểu thêm](https://developers.google.com/web/updates/2016/02/font-display)."},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"Đảm bảo văn bản vẫn hiển thị trong khi tải phông chữ web"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"Tất cả văn bản vẫn hiển thị trong khi tải phông chữ web"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"Danh mục"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"Hãy xem xét giảm thời gian dùng để phân tích cú pháp, biên soạn và thực thi JS. Bạn có thể giải quyết vấn đề này bằng cách phân phối các tải trọng JS nhỏ hơn."},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"Giảm thiểu công việc theo chuỗi chính"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"Giảm thiểu công việc theo chuỗi chính"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"Điểm số ở trên là điểm số ước tính về khoảng thời gian tính bằng mili giây mà ứng dụng của bạn cần để phản hồi thông tin người dùng nhập vào trong cửa sổ tải trang 5 giây bận rộn nhất. Nếu thời gian chờ lớn hơn 50 mili giây, người dùng có thể coi ứng dụng của bạn là chạy chậm. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)."},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"Thời gian chờ nhập thông tin theo ước tính"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"Chỉ số Hình ảnh có nội dung đầu tiên đánh dấu thời điểm hiển thị văn bản hoặc hình ảnh đầu tiên. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)."},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"Hình ảnh có nội dung đầu tiên"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"Chỉ số CPU nhàn rỗi đầu tiên đánh dấu thời điểm đầu tiên chuỗi chính của trang đủ yên tĩnh để xử lý thông tin nhập vào. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)."},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"CPU nhàn rỗi đầu tiên"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"Chỉ số Hình ảnh có ý nghĩa đầu tiên đo lường thời điểm nội dung chính của trang hiển thị. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)."},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"Hình ảnh có ý nghĩa đầu tiên"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"Chỉ số Thời điểm tương tác đánh dấu thời điểm trang tương tác hoàn toàn. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)."},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"Thời điểm tương tác"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"Chỉ mục tốc độ cho biết nội dung của một trang hiển thị nhanh chóng đến mức nào. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/speed-index)."},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"Chỉ mục tốc độ"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"Các lần chuyển hướng sẽ làm tốc độ tải trang chậm hơn. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/redirects)."},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"Tránh chuyển hướng trang nhiều lần"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"Chỉ số Thời gian cho byte đầu tiên xác định thời gian máy chủ của bạn gửi một phản hồi. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/ttfb)."},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"Tài liệu gốc mất {timeInMs, number, milliseconds} mili giây"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"Giảm thời gian phản hồi của máy chủ (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"Thời gian phản hồi của máy chủ chậm (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"Thời lượng"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"Tên"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"Thời gian bắt đầu"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"Loại"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"Cân nhắc trang bị API Thời gian người dùng cho ứng dụng để đo lường hiệu suất thực tế của ứng dụng trong trải nghiệm người dùng chính. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/user-timing)."},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 dấu thời gian người dùng}other{# dấu thời gian người dùng}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"Các thời điểm cụ thể và khoảng thời gian được ghi lại bằng API Thời gian người dùng"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"Xem xét thêm các gợi ý về tài nguyên kết nối trước hoặc tìm nạp DNS trước để thiết lập các kết nối sớm tới các miền quan trọng của bên thứ ba. [Tìm hiểu thêm](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)."},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"Kết nối trước với các tên miền bắt buộc"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"Hãy xem xét sử dụng <link rel=preload> để ưu tiên tìm nạp tài nguyên đang được yêu cầu vào một thời điểm khác trong quá trình tải trang. [Tìm hiểu thêm](https://developers.google.com/web/tools/lighthouse/audits/preload)."},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"Tải trước các yêu cầu chính"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"Thông tin khác về hiệu suất ứng dụng của bạn."},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"Chẩn đoán"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"Khía cạnh quan trọng nhất của hiệu suất là tốc độ hiển thị pixel nhanh chóng trên màn hình. Các chỉ số chính: Hình ảnh có nội dung đầu tiên, Hình ảnh có ý nghĩa đầu tiên"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"Các thao tác để cải thiện thời gian hiển thị hình ảnh đầu tiên"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"Những đề xuất tối ưu hóa này có thể tăng tốc độ tải trang của bạn."},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"Cơ hội"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"Các chỉ số"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"Cải thiện trải nghiệm tải tổng thể để trang phản hồi và sẵn sàng cho bạn sử dụng sớm nhất có thể. Các số liệu chính: Thời điểm tương tác, Chỉ mục tốc độ"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"Các thao tác để cải thiện hiệu suất tổng thể"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"Hiệu suất"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"Thời gian tồn tại (TTL) của bộ nhớ đệm"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"Kích thước (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"Thời gian sử dụng"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"URL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"Số byte có thể tiết kiệm được (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"Thời lượng có thể tiết kiệm được (mili giây)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"Số byte có thể tiết kiệm được là {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"Thời lượng có thể tiết kiệm được là {wastedMs, number, milliseconds} mili giây"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} mili giây"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} giây"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"Hiển thị kết quả kiểm tra"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"Điều hướng ban đầu"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"Độ trễ tối đa của đường dẫn quan trọng:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"Lỗi!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"Lỗi báo cáo: không có thông tin kiểm tra"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"Dữ liệu của phòng thí nghiệm"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"Số liệu phân tích về [Lighthouse](https://developers.google.com/web/tools/lighthouse/) của trang hiện tại trên mạng 3G mô phỏng. Đây là các giá trị ước tính và có thể thay đổi."},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"Các mục bổ sung cần kiểm tra theo cách thủ công"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"Không áp dụng"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"Cơ hội"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"Thời lượng tiết kiệm được theo ước tính"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"Số lần kiểm tra đạt yêu cầu"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"Thang điểm:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"Đã xảy ra sự cố ảnh hưởng đến lần chạy Lighthouse này:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"Các giá trị chỉ là ước tính và có thể thay đổi."},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"Cảnh báo: "}};
-
-
-},{}],80:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome 擴充程式會對此頁面的載入效能產生負面影響。建議透過無痕模式或使用未安裝擴充程式的 Chrome 設定檔來審核頁面。"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"指令碼評估"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"指令碼剖析"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"總計"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"建議減少剖析、編譯和執行 JS 所用的時間。傳送較小的 JS 負載可能有所幫助。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/bootup)。"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"縮短 JavaScript 執行時間"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript 執行時間"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"大型 GIF 放送動畫內容效率往往不佳。建議改用 MPEG4/WebM 格式的動畫影片和 PNG/WebP 格式的靜態圖片,以節省網絡位元組。[瞭解詳情](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"使用影片格式的動畫內容"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"建議延遲載入螢幕外的項目並隱藏圖片,直到重要資源全部載入後再開始操作,以縮短可互動時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)。"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"延遲載入螢幕外圖片"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"過多資源往往會阻止系統首次繪製頁面。建議內嵌重要的 JS/CSS,延遲所有不重要的 JS/樣式。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)。"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"排除阻止呈現的資源"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"網絡負載過大會造成使用者的費用負擔,且往往與過長載入時間息息相關。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)。"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"總大小為 {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"避免網絡負載過大"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"避免網絡負載過大"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"壓縮 CSS 檔案可減少網絡負載大小。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/minify-css)。"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"壓縮 CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"壓縮 JavaScript 檔案可減少負載大小和指令碼剖析時間。[瞭解詳情](https://developers.google.com/speed/docs/insights/MinifyResources)。"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"壓縮 Javascript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"從樣式表中移除未使用的規則,減少網絡活動耗用的不必要位元組。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/unused-css)。"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"延遲未使用的 CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"移除未使用的 JavaScript,以減少網絡活動耗用的位元組。"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"移除未使用的 JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"延長快取期限可加快重覆瀏覽頁面的速度。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{已找到 1 項資源}other{已找到 # 項資源}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"採用有效的快取政策提供靜態資產"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"使用有效的快取政策處理靜態資產"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"優化圖片以加快載入速度,減少流動數據用量。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"有效地進行圖片編碼"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"提供適當大小的圖片有助節省流動數據用量,並縮短載入時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"適當調整圖片大小"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"文字資源應經過 (gzip、deflate 或 brotli) 壓縮,以將網絡位元總數減至最少。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/text-compression)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"啟用文字壓縮"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000、JPEG XR 和 WebP 等圖片格式通常比 PNG 或 JPEG 有更好的壓縮效果,能夠更快完成下載及減少數據用量。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/webp)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"提供 next-gen 格式的圖片"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"下方的「關鍵要求鏈結」顯示以高優先次序發佈的資源。為了提高頁面載入速度,建議您縮短鏈結長度,縮減下載資源的大小,或延遲下載不必要資源。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)。"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{已找到 1 個鏈結}other{已找到 # 個鏈結}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"將重要要求深度降至最低"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"瀏覽器工程師建議,頁面包含的 DOM 節點數量應少於 1,500 個左右。理想樹狀深度應包含少於 32 個元素,且少於 60 個子/父元素。大型 DOM 會增加記憶體用量、導致[樣式運算](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations)所用時間延長並產生昂貴的[版面配置自動重排](https://developers.google.com/speed/articles/reflow)費用。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/dom-size)。"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 個節點}other{# 個節點}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"避免 DOM 過大"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"DOM 深度上限"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"DOM 節點總數"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"避免 DOM 過大"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"運用顯示字型的 CSS 功能,確保使用者可在網頁字型載入時看到文字。[瞭解詳情](https://developers.google.com/web/updates/2016/02/font-display)。"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"確保文字在網頁字型載入時仍然顯示"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"在網頁字型載入時,所有文字仍然顯示"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"類別"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"建議減少剖析、編譯和執行 JS 所用的時間。傳送較小的 JS 負載可能有所幫助。"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"將主要執行緒的工作減至最少"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"將主要執行緒的工作減至最少"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"上方的分數是在頁面載入視窗最忙碌的 5 秒期間,您的應用程式對使用者輸入動作的預計回應時間 (以毫秒為單位)。如果延遲超過 50 毫秒,使用者可能會認為應用程式的速度緩慢。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)。"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"預計輸入延遲時間"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"「首次內容繪製時間」標示繪製首個文字/首張圖片的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)。"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"首次內容繪製時間"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"「首次 CPU 閒置時間」標示頁面的主要執行緒首次有空處理輸入的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)。"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"首次 CPU 閒置時間"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"「首次有效繪製時間」評估頁面主要內容顯示的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)。"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"首次有效繪製時間"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"「可互動所需時間」用於標示頁面可進行完整互動前所需的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)。"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"可互動所需時間"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"「速度指數」會顯示頁面內容的展現速度。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/speed-index)。"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"速度指數"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"重新導向會導致頁面延遲載入。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/redirects)。"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"避免多次頁面重新導向"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"「首個字節時間」會指出您的伺服器傳送回應的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/ttfb)。"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"根文件用了 {timeInMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"縮短伺服器回應時間 (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"伺服器回應時間短 (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"時間長度"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"名稱"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"開始時間"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"類別"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"建議使用「用戶使用時間」檢測您的應用程式,評估其在關鍵使用者體驗期間的實際成效。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/user-timing)。"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 個用戶使用時間標記}other{# 個用戶使用時間標記}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"用戶使用時間標記和測量結果"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"建議新增預先連線或預先擷取 DNS 的資源提示,及早連線至重要的第三方來源。[瞭解詳情](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)。"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"預先連接至必要來源"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"建議使用 <link rel=preload> 來指定優先需要的網絡要求,並預先擷取資源。[瞭解詳情(https://developers.google.com/web/tools/lighthouse/audits/preload)。"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"預先載入關鍵要求"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"進一步瞭解應用程式效能。"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"診斷"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"評估效能的最重要指標在於像素在畫面上的呈現速度。關鍵數據:「首次內容繪製時間」、「首次有效繪製時間」"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"首次繪製改進"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"這些優化建議可提高您的頁面載入速度。"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"優化建議"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"數據"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"改善整體載入體驗,令網頁反應更靈敏快捷,盡快可供用戶使用。關鍵數據:可互動時間、速度指數"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"整體改進"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"效能"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"快取 TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"大小 (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"所用的時間"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"網址"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"可節省的用量 (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"可節省的時間 (毫秒)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"可節省 {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"可節省 {wastedMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} 秒"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"顯示審核結果"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"初始導覽"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"關鍵路徑延遲時間上限:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"發生錯誤!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"報告錯誤:無審核資料"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"實驗室數據"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) 在 3G 模擬網絡上分析目前網頁。此為預計值,可能與實際值有所不同。"},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"其他手動檢查項目"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"不適用"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"優化建議"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"預計節省的時間"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"已通過的審核"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"分數等級:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"導致這次 Lighthouse 無法順利執行的問題:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"此為預計值,可能與實際值有所不同。"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"警告: "}};
-
-
-},{}],81:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome 擴充功能對這個頁面的載入效能有負面影響。建議透過無痕模式或不含擴充功能的 Chrome 設定檔來稽核頁面。"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"指令碼評估"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"指令碼剖析"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"總計"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"建議減少剖析、編譯和執行 JS 所耗費的時間。提供較小的 JS 酬載可能會有幫助。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/bootup)"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"減少 JavaScript 執行時間"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript 執行時間"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"使用大型 GIF 檔案來呈現動畫內容會降低網路傳輸效率,建議改用 MPEG4/WebM 影片格式來呈現動畫效果,或是使用 PNG/WebP 格式來顯示靜態圖片,以減少網路傳輸的資料量。[瞭解詳情](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"使用影片格式的動畫內容"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"建議延遲載入畫面外的項目並隱藏圖片,直到重要資源全部載入後再開始作業,以減少可互動時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"延後載入畫面外圖片"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"資源過多會妨礙首次繪製頁面。建議內嵌重要的 JS/CSS,延遲所有不重要的 JS/樣式。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"排除禁止轉譯的資源"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"大量網路酬載會造成使用者的費用負擔,而且往往會導致載入耗時過長。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"總大小為 {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"避免耗用大量網路資源"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"避免耗用大量網路資源"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"壓縮 CSS 檔案可以減少網路酬載大小。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/minify-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"壓縮 CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"壓縮 JavaScript 檔案可以減少酬載大小和指令碼剖析時間。[瞭解詳情](https://developers.google.com/speed/docs/insights/MinifyResources)"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"壓縮 JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"移除樣式表中的無用規則,盡量避免網路活動消耗不必要的流量。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/unused-css)"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"延後未使用的 CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"移除未使用的 JavaScript,減少網路活動消耗的流量。"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"移除未使用的 JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"快取效期越長,增加造訪您頁面的頻率就越高。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{找到 1 項資源}other{找到 # 項資源}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"運用有效的快取政策提供靜態資產"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"使用有效的快取政策處理靜態資產"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"最佳化圖片載入速度,減少行動數據用量。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"圖片編碼有效率"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"提供適當大小的圖片有助於節省行動數據用量、縮短載入時間。[Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"使用合適的圖片大小"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"提供的文字資源應經過 (gzip、deflate 或 brotli) 壓縮,將網路傳輸的資料量降至最低。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/text-compression)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"啟用文字壓縮"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000、JPEG XR 和 WebP 等圖片格式通常壓縮效率優於 PNG 或 JPEG,能夠更快下載完成及減少數據用量。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/webp)"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"提供 next-gen 格式的圖片"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"下方的「關鍵要求鏈結」顯示的是以高優先順序載入的資源。為了提高頁面載入速度,建議你縮短鏈結長度,降低下載資源的大小,或是延後下載非必要資源。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)。"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{找到 1 個鏈結}other{找到 # 個鏈結}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"將關鍵要求層級降至最低"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"瀏覽器工程師建議,頁面包含的 DOM 節點數量應少於 1,500 個左右。理想樹狀層級應包含少於 32 個元素,以及少於 60 個下層/上層元素。大型的 DOM 可能造成記憶體用量增加、延長[樣式運算](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations)的過程,還會導致費工的[版面配置重排](https://developers.google.com/speed/articles/reflow)。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/dom-size)"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 個節點}other{# 個節點}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"避免 DOM 過大"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"DOM 層級上限"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"DOM 節點總數"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"避免 DOM 過大"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"運用顯示字型的 CSS 功能,確保使用者可以在載入網路字型時看到文字。[瞭解詳情](https://developers.google.com/web/updates/2016/02/font-display)"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"確認載入網站字型時文字不會消失"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"載入網站字型時沒有任何文字消失"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"類別"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"建議減少剖析、編譯和執行 JS 所耗費的時間。提供較小的 JS 酬載可能會有幫助。"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"將主要執行緒的工作降到最低"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"將主要執行緒的工作降到最低"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"上方的分數是在頁面載入視窗最忙碌的 5 秒期間,您的應用程式對於使用者輸入動作的預計回應時間 (以毫秒為單位)。如果延遲超過 50 毫秒,使用者可能會感覺應用程式的速度很慢。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"預估輸入延遲"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"「首次顯示內容所需時間」會標記寫下第一個文字或繪製第一張圖片的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)。"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"首次內容繪製"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"首次 CPU 閒置標記的是頁面的主要執行緒在第一次處理輸入作業前所需的閒置時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"首次 CPU 閒置"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"首次有效繪製可供衡量頁面主要內容顯示的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"首次有效繪製"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"可互動時間標記的是頁面提供完整互動功能的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"可互動時間"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"速度指數會顯示頁面內容填入的速度。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/speed-index)"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"速度指數"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"重新導向會導致頁面延遲載入。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/redirects)"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"避免進行多次頁面重新導向"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"第一個位元組時間會指出您的伺服器傳送回應的時間。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/ttfb)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"根文件用時 {timeInMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"減少伺服器回應時間 (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"伺服器回應時間低 (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"時間長度"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"名稱"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"開始時間"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"類型"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"建議你使用 User Timing API 檢測應用程式在關鍵使用者體驗期間的實際成效。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/user-timing)。"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 個 User Timing 標記}other{# 個 User Timing 標記}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing 標記和測量結果"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"建議新增預先連線或預先擷取 DNS 的資源提示,及早連線至重要的第三方來源。[瞭解詳情](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"預先連上必要來源"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"建議使用 <link rel=preload> 指定在頁面載入後立即需要的資源,以優先擷取這類資源。[瞭解詳情](https://developers.google.com/web/tools/lighthouse/audits/preload)"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"預先載入重要要求"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"關於您應用程式效能的更多資訊。"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"診斷"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"像素呈現在畫面上的速度是最重要的效能層面。重要指標:首次內容繪製、首次有效繪製"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"改進首次繪製程序"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"這些最佳化建議可以提高您的頁面載入速度。"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"最佳化建議"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"指標"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"改進整體載入體驗,採用回應式頁面設計,儘快為使用者提供服務。重要指標:可互動時間、速度指數"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"整體改進"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"效能"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"快取 TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"大小 (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"花費的時間"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"網址"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"潛在減少量 (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"潛在減少量 (毫秒)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"可減少 {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"可減少 {wastedMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} 秒"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"顯示稽核結果"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"起始導覽"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"關鍵路徑延遲時間上限:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"發生錯誤!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"回報錯誤:無稽核資訊"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"研究資料"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) 在 3G 模擬網路上分析目前網頁。分析結果為預估值,可能與實際情況有所出入。"},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"其他手動檢查項目"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"不適用"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"最佳化建議"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"預估減少量"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"通過稽核項目"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"分數量尺:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"有問題導致 Lighthouse 無法順利執行這項作業:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"此為預估值,可能與實際情況有所出入。"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"警告: "}};
-
-
-},{}],82:[function(require,module,exports){
-module.exports={
-"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
-"message":"Chrome 扩展程序对此网页的加载性能产生了负面影响。请尝试在无痕模式下或使用未安装这些扩展程序的 Chrome 个人资料审核此网页。"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
-"message":"脚本评估"},
-
-"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
-"message":"脚本解析"},
-
-"lighthouse-core/audits/bootup-time.js | columnTotal":{
-"message":"总计"},
-
-"lighthouse-core/audits/bootup-time.js | description":{
-"message":"考虑减少为解析、编译和执行 JS 而花费的时间。您可能会发现,提供较小的 JS 负载有助于实现此目标。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/bootup)。"},
-
-"lighthouse-core/audits/bootup-time.js | failureTitle":{
-"message":"缩短 JavaScript 执行用时"},
-
-"lighthouse-core/audits/bootup-time.js | title":{
-"message":"JavaScript 执行用时"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
-"message":"使用大型 GIF 提供动画内容会导致效率低下。不妨考虑改用 MPEG4/WebM 视频(来提供动画)和 PNG/WebP(来提供静态图片)以减少网络活动消耗的字节数。[了解详情](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)"},
-
-"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
-"message":"使用视频格式提供动画内容"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
-"message":"考虑在所有关键资源加载完毕后推迟加载屏幕外图片和处于隐藏状态的图片,从而缩短可交互前的耗时。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images)。"},
-
-"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
-"message":"推迟加载屏幕外图片"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
-"message":"资源阻止了系统对您网页的首次绘制。请考虑以内嵌方式提供关键的 JS/CSS 并推迟提供所有非关键的 JS/样式。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources)。"},
-
-"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
-"message":"移除阻塞渲染的资源"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
-"message":"网络负载过大不仅会让用户付出真金白银,还极有可能会延长加载用时。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/network-payloads)。"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
-"message":"总大小为 {totalBytes, number, bytes} KB"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
-"message":"避免网络负载过大"},
-
-"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
-"message":"避免网络负载过大"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
-"message":"缩减 CSS 文件大小可缩减网络负载规模。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/minify-css)。"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
-"message":"缩减 CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
-"message":"如果缩减 JavaScript 文件大小,则既能缩减负载规模,又能缩短脚本解析用时。[了解详情](https://developers.google.com/speed/docs/insights/MinifyResources)。"},
-
-"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
-"message":"缩减 JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
-"message":"从样式表中移除未使用的规则,以减少网络活动消耗的不必要的字节数。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/unused-css)。"},
-
-"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
-"message":"推迟加载未使用的 CSS"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
-"message":"移除未使用的 JavaScript 可减少网络活动消耗的字节数。"},
-
-"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
-"message":"移除未使用的 JavaScript"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
-"message":"延长缓存期限可加快重访您网页的速度。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/cache-policy)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
-"message":"{itemCount,plural, =1{找到了 1 项资源}other{找到了 # 项资源}}"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
-"message":"采用高效的缓存策略提供静态资源"},
-
-"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
-"message":"针对静态资源使用高效的缓存策略"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
-"message":"如果图片经过了优化,则加载速度会更快,且消耗的移动数据网络流量会更少。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/optimize-images)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
-"message":"对图片进行高效编码"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
-"message":"提供适当大小的图片可节省移动数据网络流量并缩短加载用时。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/oversized-images)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
-"message":"适当调整图片大小"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
-"message":"对于文本资源,应先压缩(gzip、deflate 或 brotli),然后再提供,以最大限度地减少网络活动消耗的字节总数。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/text-compression)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
-"message":"启用文本压缩"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
-"message":"JPEG 2000、JPEG XR 和 WebP 等图片格式的压缩效果通常比 PNG 或 JPEG 好,因此下载速度更快,消耗的数据流量更少。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/webp)。"},
-
-"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
-"message":"采用新一代格式提供图片"},
-
-"lighthouse-core/audits/critical-request-chains.js | description":{
-"message":"下面的关键请求链显示了以高优先级加载的资源。请考虑缩短链长、缩减资源的下载文件大小,或者推迟下载不必要的资源,从而提高网页加载速度。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains)。"},
-
-"lighthouse-core/audits/critical-request-chains.js | displayValue":{
-"message":"{itemCount,plural, =1{找到了 1 条请求链}other{找到了 # 条请求链}}"},
-
-"lighthouse-core/audits/critical-request-chains.js | title":{
-"message":"最大限度地缩短关键请求深度"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
-"message":"Element"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
-"message":"Statistic"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
-"message":"Value"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
-"message":"浏览器工程师建议,网页包含的 DOM 节点最好少于 1500 个左右。理想状况是,树深度少于 32 个元素,且少于 60 个子/父元素。大型 DOM 可能会增加内存使用量、导致[样式计算](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations)用时延长并产生高昂的[布局重排](https://developers.google.com/speed/articles/reflow)费用。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/dom-size)。"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
-"message":"{itemCount,plural, =1{1 个节点}other{# 个节点}}"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
-"message":"避免 DOM 规模过大"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
-"message":"最大 DOM 深度"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
-"message":"DOM 节点总数"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
-"message":"Maximum Child Elements"},
-
-"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
-"message":"避免 DOM 规模过大"},
-
-"lighthouse-core/audits/font-display.js | description":{
-"message":"利用 font-display 这项 CSS 功能,确保文本在网页字体加载期间始终对用户可见。[了解详情](https://developers.google.com/web/updates/2016/02/font-display)。"},
-
-"lighthouse-core/audits/font-display.js | failureTitle":{
-"message":"确保文本在网页字体加载期间保持可见状态"},
-
-"lighthouse-core/audits/font-display.js | title":{
-"message":"在网页字体加载期间,所有文本都保持可见状态"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
-"message":"类别"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
-"message":"考虑减少为解析、编译和执行 JS 而花费的时间。您可能会发现,提供较小的 JS 负载有助于实现此目标。"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
-"message":"最大限度地减少主线程工作"},
-
-"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
-"message":"最大限度地减少主线程工作"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
-"message":"上面的分数是估算值,表示您的应用在网页加载最繁忙的 5 秒期间大概需要花费多长时间(以毫秒为单位)才能对用户输入做出响应。如果您的延迟时间超过了 50 毫秒,用户可能会感觉您的应用运行迟缓。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)。"},
-
-"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
-"message":"输入延迟(估算值)"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
-"message":"首次内容绘制时间标记了绘制出首个文本或首张图片的时间。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint)。"},
-
-"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
-"message":"首次内容绘制时间"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
-"message":"首次 CPU 闲置时间标记了网页的主线程首次有空处理输入操作的时间。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/first-interactive)。"},
-
-"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
-"message":"首次 CPU 闲置时间"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
-"message":"首次有效绘制时间测量了网页主要内容开始对用户可见的时间。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)。"},
-
-"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
-"message":"首次有效绘制时间"},
-
-"lighthouse-core/audits/metrics/interactive.js | description":{
-"message":"可交互前的耗时标记了网页提供完整交互功能的时间。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive)。"},
-
-"lighthouse-core/audits/metrics/interactive.js | title":{
-"message":"可交互前的耗时"},
-
-"lighthouse-core/audits/metrics/speed-index.js | description":{
-"message":"速度指数表明了网页内容的可见填充速度。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/speed-index)。"},
-
-"lighthouse-core/audits/metrics/speed-index.js | title":{
-"message":"速度指数"},
-
-"lighthouse-core/audits/redirects.js | description":{
-"message":"重定向会在网页可加载前引入更多延迟。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/redirects)。"},
-
-"lighthouse-core/audits/redirects.js | title":{
-"message":"避免多次网页重定向"},
-
-"lighthouse-core/audits/time-to-first-byte.js | description":{
-"message":"首字节显示前的耗时表明了服务器发出响应的时间。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/ttfb)。"},
-
-"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
-"message":"根文档花费了 {timeInMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
-"message":"缩短服务器响应用时 (TTFB)"},
-
-"lighthouse-core/audits/time-to-first-byte.js | title":{
-"message":"服务器响应用时较短 (TTFB)"},
-
-"lighthouse-core/audits/user-timings.js | columnDuration":{
-"message":"时长"},
-
-"lighthouse-core/audits/user-timings.js | columnName":{
-"message":"名称"},
-
-"lighthouse-core/audits/user-timings.js | columnStartTime":{
-"message":"开始时间"},
-
-"lighthouse-core/audits/user-timings.js | columnType":{
-"message":"类型"},
-
-"lighthouse-core/audits/user-timings.js | description":{
-"message":"考虑使用 User Timing API 检测您的应用,从而衡量应用在关键用户体验中的实际性能。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/user-timing)。"},
-
-"lighthouse-core/audits/user-timings.js | displayValue":{
-"message":"{itemCount,plural, =1{1 项 User Timing 结果}other{# 项 User Timing 结果}}"},
-
-"lighthouse-core/audits/user-timings.js | title":{
-"message":"User Timing 标记和测量结果"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | description":{
-"message":"考虑添加 preconnect 或 dns-prefetch 资源提示,以尽早与重要的第三方来源建立连接。[了解详情](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect)。"},
-
-"lighthouse-core/audits/uses-rel-preconnect.js | title":{
-"message":"预先连接到必要的来源"},
-
-"lighthouse-core/audits/uses-rel-preload.js | description":{
-"message":"考虑使用 <link rel=preload> 来优先提取当前在网页加载后期请求的资源。[了解详情](https://developers.google.com/web/tools/lighthouse/audits/preload)。"},
-
-"lighthouse-core/audits/uses-rel-preload.js | title":{
-"message":"预加载关键请求"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
-"message":"详细了解您的应用的性能。"},
-
-"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
-"message":"诊断结果"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
-"message":"像素在屏幕上的呈现速度是性能的最重要方面。关键指标:首次内容绘制时间、首次有效绘制时间"},
-
-"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
-"message":"改进首次绘制"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
-"message":"这些优化建议可以加快网页加载速度。"},
-
-"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
-"message":"优化建议"},
-
-"lighthouse-core/config/default-config.js | metricGroupTitle":{
-"message":"指标"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
-"message":"改善整体的加载体验,使该网页响应迅速且可尽快投入使用。关键指标:可交互前的耗时、速度指数"},
-
-"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
-"message":"整体改进"},
-
-"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
-"message":"性能"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
-"message":"缓存 TTL"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnSize":{
-"message":"大小 (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
-"message":"花费的时间"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnURL":{
-"message":"网址"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
-"message":"有望节省的流量 (KB)"},
-
-"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
-"message":"有望节省的时间(毫秒)"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
-"message":"有望节省 {wastedBytes, number, bytes} KB"},
-
-"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
-"message":"有望节省 {wastedMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | ms":{
-"message":"{timeInMs, number, milliseconds} 毫秒"},
-
-"lighthouse-core/lib/i18n/i18n.js | seconds":{
-"message":"{timeInMs, number, seconds} 秒"},
-
-"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
-"message":"显示审核结果"},
-
-"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
-"message":"初始导航"},
-
-"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
-"message":"关键路径延迟时间上限:"},
-
-"lighthouse-core/report/html/renderer/util.js | errorLabel":{
-"message":"出错了!"},
-
-"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
-"message":"报告错误:没有任何审核信息"},
-
-"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
-"message":"实验室数据"},
-
-"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
-"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) 使用模拟 3G 网络对当前页面进行的分析。这些值都是估算值,且可能会因时而异。"},
-
-"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
-"message":"待手动检查的其他项"},
-
-"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
-"message":"不适用"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
-"message":"优化建议"},
-
-"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
-"message":"有望节省的总时间(估算值)"},
-
-"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
-"message":"已通过的审核"},
-
-"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
-"message":"分数等级:"},
-
-"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
-"message":"此次 Lighthouse 运行并不顺利,原因如下:"},
-
-"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
-"message":"这些值都是估算值,且可能会因时而异。"},
-
-"lighthouse-core/report/html/renderer/util.js | warningHeader":{
-"message":"警告: "}};
-
-
-},{}],83:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const URL=require('./url-shim.js');
-
-
-
-
-
-function doExist(manifest){
-if(!manifest||!manifest.icons){
-return false;
-}
-if(manifest.icons.value.length===0){
-return false;
-}
-return true;
-}
-
-
-
-
-
-
-function pngSizedAtLeast(sizeRequirement,manifest){
-
-
-const iconValues=manifest.icons.value;
-
-const flattenedSizes=[];
-iconValues.
-
-filter(icon=>!icon.value.type.value||
-icon.value.type.value&&
-icon.value.type.value==='image/png').
-
-filter(icon=>icon.value.src.value&&
-new URL(icon.value.src.value).pathname.endsWith('.png')).
-forEach(icon=>{
-
-if(icon.value.sizes.value){
-flattenedSizes.push(...icon.value.sizes.value);
-}
-});
-
-return flattenedSizes.
-
-filter(size=>/\d+x\d+/.test(size)).
-filter(size=>{
-
-const sizeStrs=size.split(/x/i);
-
-const sizeNums=[parseFloat(sizeStrs[0]),parseFloat(sizeStrs[1])];
-
-const areIconsBigEnough=sizeNums[0]>=sizeRequirement&&sizeNums[1]>=sizeRequirement;
-
-const areIconsSquare=sizeNums[0]===sizeNums[1];
-return areIconsBigEnough&&areIconsSquare;
-});
-}
-
-module.exports={
-doExist,
-pngSizedAtLeast};
-
-
-},{"./url-shim.js":"url"}],84:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-function convertNodeTimingsToTrace(nodeTimings){
-
-const traceEvents=[];
-const baseTs=1e9;
-const baseEvent={pid:1,tid:1,cat:'devtools.timeline'};
-const frame='A00001';
-
-const toMicroseconds=ms=>baseTs+ms*1000;
-
-traceEvents.push(createFakeTracingStartedEvent());
-traceEvents.push({...createFakeTracingStartedEvent(),name:'TracingStartedInBrowser'});
-
-
-let requestId=1;
-let lastEventEndTime=0;
-for(const[node,timing]of nodeTimings.entries()){
-lastEventEndTime=Math.max(lastEventEndTime,timing.endTime);
-if(node.type==='cpu'){
-
-const cpuNode=node;
-traceEvents.push(...createFakeTaskEvents(cpuNode,timing));
-}else{
-const networkNode=node;
-
-if(/^data/.test(networkNode.record.url))continue;
-traceEvents.push(...createFakeNetworkEvents(networkNode.record,timing));
-}
-}
-
-
-traceEvents.push(
-...createFakeTaskEvents(
-
-{childEvents:[],event:{}},
-{
-startTime:lastEventEndTime+1000,
-endTime:lastEventEndTime+1001}));
-
-
-
-
-return{traceEvents};
-
-
-
-
-function createFakeTracingStartedEvent(){
-const argsData={
-frameTreeNodeId:1,
-sessionId:'1.1',
-page:frame,
-persistentIds:true,
-frames:[{frame,url:'about:blank',name:'',processId:1}]};
-
-
-return{
-...baseEvent,
-ts:baseTs-1e5,
-ph:'I',
-s:'t',
-cat:'disabled-by-default-devtools.timeline',
-name:'TracingStartedInPage',
-args:{data:argsData},
-dur:0};
-
-}
-
-
-
-
-
-
-function createFakeTaskEvents(cpuNode,timing){
-const argsData={
-url:'',
-frame,
-lineNumber:0,
-columnNumber:0};
-
-
-const eventTs=toMicroseconds(timing.startTime);
-
-
-const events=[
-{
-...baseEvent,
-ph:'X',
-name:'Task',
-ts:eventTs,
-dur:(timing.endTime-timing.startTime)*1000,
-args:{data:argsData}}];
-
-
-
-const nestedBaseTs=cpuNode.event.ts||0;
-const multiplier=(timing.endTime-timing.startTime)*1000/cpuNode.event.dur;
-
-const netReqEvents=new Set(['ResourceSendRequest','ResourceFinish',
-'ResourceReceiveResponse','ResourceReceivedData']);
-for(const event of cpuNode.childEvents){
-if(netReqEvents.has(event.name))continue;
-const ts=eventTs+(event.ts-nestedBaseTs)*multiplier;
-const newEvent={...event,...{pid:baseEvent.pid,tid:baseEvent.tid},ts};
-if(event.dur)newEvent.dur=event.dur*multiplier;
-events.push(newEvent);
-}
-
-return events;
-}
-
-
-
-
-
-
-function createFakeNetworkEvents(record,timing){
-requestId++;
-
-
-
-let{startTime,endTime}=timing;
-if(startTime===endTime)endTime+=0.3;
-
-const requestData={requestId:requestId.toString(),frame};
-
-const baseRequestEvent={...baseEvent,ph:'I',s:'t',dur:0};
-
-const sendRequestData={
-...requestData,
-requestMethod:record.requestMethod,
-url:record.url,
-priority:record.priority};
-
-
-const receiveResponseData={
-...requestData,
-statusCode:record.statusCode,
-mimeType:record.mimeType,
-encodedDataLength:record.transferSize,
-fromCache:record.fromDiskCache,
-fromServiceWorker:record.fetchedViaServiceWorker};
-
-
-const resourceFinishData={
-...requestData,
-decodedBodyLength:record.resourceSize,
-didFail:!!record.failed,
-finishTime:endTime};
-
-
-
-const events=[
-{
-...baseRequestEvent,
-name:'ResourceSendRequest',
-ts:toMicroseconds(startTime),
-args:{data:sendRequestData}},
-
-{
-...baseRequestEvent,
-name:'ResourceFinish',
-ts:toMicroseconds(endTime),
-args:{data:resourceFinishData}}];
-
-
-
-if(!record.failed){
-events.push({
-...baseRequestEvent,
-name:'ResourceReceiveResponse',
-ts:toMicroseconds((startTime+endTime)/2),
-args:{data:receiveResponseData}});
-
-}
-
-return events;
-}
-}
-
-module.exports={
-simulationNamesToIgnore:[
-'unlabeled',
-
-'optimisticFirstCPUIdle',
-'optimisticFlexFirstCPUIdle',
-'pessimisticFirstCPUIdle',
-'optimisticSpeedIndex',
-'optimisticFlexSpeedIndex',
-'pessimisticSpeedIndex',
-'optimisticEstimatedInputLatency',
-'optimisticFlexEstimatedInputLatency',
-'pessimisticEstimatedInputLatency'],
-
-convertNodeTimingsToTrace};
-
-
-},{}],85:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const strings=require('./strings');
-
-
-
-
-
-
-
-
-
-class LighthouseError extends Error{
-
-
-
-
-constructor(errorDefinition,properties){
-super(errorDefinition.code);
-this.name='LHError';
-this.code=errorDefinition.code;
-this.friendlyMessage=errorDefinition.message;
-this.lhrRuntimeError=!!errorDefinition.lhrRuntimeError;
-if(properties)Object.assign(this,properties);
-
-Error.captureStackTrace(this,LighthouseError);
-}
-
-
-
-
-
-static fromLighthouseError(err){
-const{code,friendlyMessage:message,...rest}=err;
-
-return new LighthouseError({code,message},{...rest});
-}
-
-
-
-
-
-
-static fromProtocolMessage(method,protocolError){
-
-const protocolErrors=Object.values(LighthouseError.errors).filter(e=>e.pattern);
-
-const matchedErrorDefinition=protocolErrors.find(e=>e.pattern.test(protocolError.message));
-if(matchedErrorDefinition){
-return new LighthouseError(matchedErrorDefinition,{
-protocolMethod:method,
-protocolError:protocolError.message});
-
-}
-
-
-let errMsg=`(${method}): ${protocolError.message}`;
-if(protocolError.data)errMsg+=` (${protocolError.data})`;
-const error=new Error(`Protocol error ${errMsg}`);
-return Object.assign(error,{protocolMethod:method,protocolError:protocolError.message});
-}}
-
-
-const ERRORS={
-
-NO_SPEEDLINE_FRAMES:{
-code:'NO_SPEEDLINE_FRAMES',
-message:strings.didntCollectScreenshots,
-lhrRuntimeError:true},
-
-SPEEDINDEX_OF_ZERO:{
-code:'SPEEDINDEX_OF_ZERO',
-message:strings.didntCollectScreenshots,
-lhrRuntimeError:true},
-
-NO_SCREENSHOTS:{
-code:'NO_SCREENSHOTS',
-message:strings.didntCollectScreenshots,
-lhrRuntimeError:true},
-
-INVALID_SPEEDLINE:{
-code:'INVALID_SPEEDLINE',
-message:strings.didntCollectScreenshots,
-lhrRuntimeError:true},
-
-
-
-NO_TRACING_STARTED:{
-code:'NO_TRACING_STARTED',
-message:strings.badTraceRecording,
-lhrRuntimeError:true},
-
-NO_NAVSTART:{
-code:'NO_NAVSTART',
-message:strings.badTraceRecording,
-lhrRuntimeError:true},
-
-NO_FCP:{
-code:'NO_FCP',
-message:strings.badTraceRecording,
-lhrRuntimeError:true},
-
-NO_DCL:{
-code:'NO_DCL',
-message:strings.badTraceRecording,
-lhrRuntimeError:true},
-
-NO_FMP:{
-code:'NO_FMP',
-message:strings.badTraceRecording},
-
-
-
-FMP_TOO_LATE_FOR_FCPUI:{code:'FMP_TOO_LATE_FOR_FCPUI',message:strings.pageLoadTookTooLong},
-NO_FCPUI_IDLE_PERIOD:{code:'NO_FCPUI_IDLE_PERIOD',message:strings.pageLoadTookTooLong},
-NO_TTI_CPU_IDLE_PERIOD:{code:'NO_TTI_CPU_IDLE_PERIOD',message:strings.pageLoadTookTooLong},
-NO_TTI_NETWORK_IDLE_PERIOD:{
-code:'NO_TTI_NETWORK_IDLE_PERIOD',
-message:strings.pageLoadTookTooLong},
-
-
-
-NO_DOCUMENT_REQUEST:{
-code:'NO_DOCUMENT_REQUEST',
-message:strings.pageLoadFailed,
-lhrRuntimeError:true},
-
-
-FAILED_DOCUMENT_REQUEST:{
-code:'FAILED_DOCUMENT_REQUEST',
-message:strings.pageLoadFailed,
-lhrRuntimeError:true},
-
-
-ERRORED_DOCUMENT_REQUEST:{
-code:'ERRORED_DOCUMENT_REQUEST',
-message:strings.pageLoadFailed,
-lhrRuntimeError:true},
-
-
-
-TRACING_ALREADY_STARTED:{
-code:'TRACING_ALREADY_STARTED',
-message:strings.internalChromeError,
-pattern:/Tracing.*started/,
-lhrRuntimeError:true},
-
-PARSING_PROBLEM:{
-code:'PARSING_PROBLEM',
-message:strings.internalChromeError,
-pattern:/Parsing problem/,
-lhrRuntimeError:true},
-
-READ_FAILED:{
-code:'READ_FAILED',
-message:strings.internalChromeError,
-pattern:/Read failed/,
-lhrRuntimeError:true},
-
-
-
-REQUEST_CONTENT_TIMEOUT:{
-code:'REQUEST_CONTENT_TIMEOUT',
-message:strings.requestContentTimeout},
-
-
-
-INVALID_URL:{
-code:'INVALID_URL',
-message:strings.urlInvalid}};
-
-
-
-
-LighthouseError.errors=ERRORS;
-LighthouseError.NO_ERROR='NO_ERROR';
-LighthouseError.UNKNOWN_ERROR='UNKNOWN_ERROR';
-module.exports=LighthouseError;
-
-
-},{"./strings":92}],86:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const URL=require('./url-shim');
-const cssParsers=require('cssstyle/lib/parsers');
-
-const ALLOWED_DISPLAY_VALUES=[
-'fullscreen',
-'standalone',
-'minimal-ui',
-'browser'];
-
-
-
-
-
-const DEFAULT_DISPLAY_MODE='browser';
-
-const ALLOWED_ORIENTATION_VALUES=[
-'any',
-'natural',
-'landscape',
-'portrait',
-'portrait-primary',
-'portrait-secondary',
-'landscape-primary',
-'landscape-secondary'];
-
-
-
-
-
-
-function isValidColor(color){
-return cssParsers.valueType(color)===cssParsers.TYPES.COLOR;
-}
-
-
-
-
-
-function parseString(raw,trim){
-let value;
-let warning;
-
-if(typeof raw==='string'){
-value=trim?raw.trim():raw;
-}else{
-if(raw!==undefined){
-warning='ERROR: expected a string.';
-}
-value=undefined;
-}
-
-return{
-raw,
-value,
-warning};
-
-}
-
-
-
-
-function parseColor(raw){
-const color=parseString(raw);
-
-
-if(color.value===undefined){
-return color;
-}
-
-
-if(!isValidColor(color.raw)){
-color.value=undefined;
-color.warning='ERROR: color parsing failed.';
-}
-
-return color;
-}
-
-
-
-
-function parseName(jsonInput){
-return parseString(jsonInput.name,true);
-}
-
-
-
-
-function parseShortName(jsonInput){
-return parseString(jsonInput.short_name,true);
-}
-
-
-
-
-
-
-
-function checkSameOrigin(url1,url2){
-const parsed1=new URL(url1);
-const parsed2=new URL(url2);
-
-return parsed1.origin===parsed2.origin;
-}
-
-
-
-
-
-
-
-function parseStartUrl(jsonInput,manifestUrl,documentUrl){
-const raw=jsonInput.start_url;
-
-
-if(raw===''){
-return{
-raw,
-value:documentUrl,
-warning:'ERROR: start_url string empty'};
-
-}
-const parsedAsString=parseString(raw);
-if(!parsedAsString.value){
-parsedAsString.value=documentUrl;
-return parsedAsString;
-}
-
-
-let startUrl;
-try{
-startUrl=new URL(raw,manifestUrl).href;
-}catch(e){
-
-return{
-raw,
-value:documentUrl,
-warning:'ERROR: invalid start_url relative to ${manifestUrl}'};
-
-}
-
-
-if(!checkSameOrigin(startUrl,documentUrl)){
-return{
-raw,
-value:documentUrl,
-warning:'ERROR: start_url must be same-origin as document'};
-
-}
-
-return{
-raw,
-value:startUrl};
-
-}
-
-
-
-
-function parseDisplay(jsonInput){
-const parsedString=parseString(jsonInput.display,true);
-const stringValue=parsedString.value;
-
-if(!stringValue){
-return{
-raw:jsonInput,
-value:DEFAULT_DISPLAY_MODE,
-warning:parsedString.warning};
-
-}
-
-const displayValue=stringValue.toLowerCase();
-if(!ALLOWED_DISPLAY_VALUES.includes(displayValue)){
-return{
-raw:jsonInput,
-value:DEFAULT_DISPLAY_MODE,
-warning:'ERROR: \'display\' has invalid value '+displayValue+
-`. will fall back to ${DEFAULT_DISPLAY_MODE}.`};
-
-}
-
-return{
-raw:jsonInput,
-value:displayValue,
-warning:undefined};
-
-}
-
-
-
-
-function parseOrientation(jsonInput){
-const orientation=parseString(jsonInput.orientation,true);
-
-if(orientation.value&&
-!ALLOWED_ORIENTATION_VALUES.includes(orientation.value.toLowerCase())){
-orientation.value=undefined;
-orientation.warning='ERROR: \'orientation\' has an invalid value, will be ignored.';
-}
-
-return orientation;
-}
-
-
-
-
-
-function parseIcon(raw,manifestUrl){
-
-const src=parseString(raw.src,true);
-
-if(src.value===''){
-src.value=undefined;
-}
-if(src.value){
-
-src.value=new URL(src.value,manifestUrl).href;
-}
-
-const type=parseString(raw.type,true);
-
-const density={
-raw:raw.density,
-value:1,
-
-warning:undefined};
-
-if(density.raw!==undefined){
-density.value=parseFloat(density.raw);
-if(isNaN(density.value)||!isFinite(density.value)||density.value<=0){
-density.value=1;
-density.warning='ERROR: icon density cannot be NaN, +∞, or less than or equal to +0.';
-}
-}
-
-let sizes;
-const parsedSizes=parseString(raw.sizes);
-if(parsedSizes.value!==undefined){
-
-const set=new Set();
-parsedSizes.value.trim().split(/\s+/).forEach(size=>set.add(size.toLowerCase()));
-sizes={
-raw:raw.sizes,
-value:set.size>0?Array.from(set):undefined,
-warning:undefined};
-
-}else{
-sizes={...parsedSizes,value:undefined};
-}
-
-return{
-raw,
-value:{
-src,
-type,
-density,
-sizes},
-
-warning:undefined};
-
-}
-
-
-
-
-
-function parseIcons(jsonInput,manifestUrl){
-const raw=jsonInput.icons;
-
-if(raw===undefined){
-return{
-raw,
-
-value:[],
-warning:undefined};
-
-}
-
-if(!Array.isArray(raw)){
-return{
-raw,
-
-value:[],
-warning:'ERROR: \'icons\' expected to be an array but is not.'};
-
-}
-
-
-
-const value=raw.
-
-filter(icon=>icon.src!==undefined).
-
-map(icon=>parseIcon(icon,manifestUrl)).
-
-filter(parsedIcon=>parsedIcon.value.src.value!==undefined);
-
-return{
-raw,
-value,
-warning:undefined};
-
-}
-
-
-
-
-function parseApplication(raw){
-const platform=parseString(raw.platform,true);
-const id=parseString(raw.id,true);
-
-
-const appUrl=parseString(raw.url,true);
-if(appUrl.value){
-try{
-
-appUrl.value=new URL(appUrl.value).href;
-}catch(e){
-appUrl.value=undefined;
-appUrl.warning='ERROR: invalid application URL ${raw.url}';
-}
-}
-
-return{
-raw,
-value:{
-platform,
-id,
-url:appUrl},
-
-warning:undefined};
-
-}
-
-
-
-
-function parseRelatedApplications(jsonInput){
-const raw=jsonInput.related_applications;
-
-if(raw===undefined){
-return{
-raw,
-value:undefined,
-warning:undefined};
-
-}
-
-if(!Array.isArray(raw)){
-return{
-raw,
-value:undefined,
-warning:'ERROR: \'related_applications\' expected to be an array but is not.'};
-
-}
-
-
-
-const value=raw.
-filter(application=>!!application.platform).
-map(parseApplication).
-filter(parsedApp=>!!parsedApp.value.id.value||!!parsedApp.value.url.value);
-
-return{
-raw,
-value,
-warning:undefined};
-
-}
-
-
-
-
-function parsePreferRelatedApplications(jsonInput){
-const raw=jsonInput.prefer_related_applications;
-let value;
-let warning;
-
-if(typeof raw==='boolean'){
-value=raw;
-}else{
-if(raw!==undefined){
-warning='ERROR: \'prefer_related_applications\' expected to be a boolean.';
-}
-value=undefined;
-}
-
-return{
-raw,
-value,
-warning};
-
-}
-
-
-
-
-function parseThemeColor(jsonInput){
-return parseColor(jsonInput.theme_color);
-}
-
-
-
-
-function parseBackgroundColor(jsonInput){
-return parseColor(jsonInput.background_color);
-}
-
-
-
-
-
-
-
-function parse(string,manifestUrl,documentUrl){
-if(manifestUrl===undefined||documentUrl===undefined){
-throw new Error('Manifest and document URLs required for manifest parsing.');
-}
-
-let jsonInput;
-
-try{
-jsonInput=JSON.parse(string);
-}catch(e){
-return{
-raw:string,
-value:undefined,
-warning:'ERROR: file isn\'t valid JSON: '+e};
-
-}
-
-
-const manifest={
-name:parseName(jsonInput),
-short_name:parseShortName(jsonInput),
-start_url:parseStartUrl(jsonInput,manifestUrl,documentUrl),
-display:parseDisplay(jsonInput),
-orientation:parseOrientation(jsonInput),
-icons:parseIcons(jsonInput,manifestUrl),
-related_applications:parseRelatedApplications(jsonInput),
-prefer_related_applications:parsePreferRelatedApplications(jsonInput),
-theme_color:parseThemeColor(jsonInput),
-background_color:parseBackgroundColor(jsonInput)};
-
-
-
-return{
-raw:string,
-value:manifest,
-warning:undefined};
-
-}
-
-module.exports=parse;
-
-},{"./url-shim":"url","cssstyle/lib/parsers":161}],87:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const NetworkRequest=require('./network-request');
-const EventEmitter=require('events').EventEmitter;
-const log=require('lighthouse-logger');
-
-const IGNORED_NETWORK_SCHEMES=['data','ws'];
-
-
-
-class NetworkRecorder extends EventEmitter{
-
-
-
-constructor(){
-super();
-
-
-this._records=[];
-
-this._recordsById=new Map();
-}
-
-getRecords(){
-return Array.from(this._records);
-}
-
-
-
-
-
-on(event,listener){
-return super.on(event,listener);
-}
-
-
-
-
-
-once(event,listener){
-return super.once(event,listener);
-}
-
-isIdle(){
-return!!this._getActiveIdlePeriod(0);
-}
-
-is2Idle(){
-return!!this._getActiveIdlePeriod(2);
-}
-
-
-
-
-_getActiveIdlePeriod(allowedRequests){
-const quietPeriods=NetworkRecorder.findNetworkQuietPeriods(this._records,allowedRequests);
-return quietPeriods.find(period=>!Number.isFinite(period.end));
-}
-
-_emitNetworkStatus(){
-const zeroQuiet=this._getActiveIdlePeriod(0);
-const twoQuiet=this._getActiveIdlePeriod(2);
-
-if(twoQuiet&&zeroQuiet){
-log.verbose('NetworkRecorder','network fully-quiet');
-this.emit('network-2-idle');
-this.emit('networkidle');
-}else if(twoQuiet&&!zeroQuiet){
-log.verbose('NetworkRecorder','network semi-quiet');
-this.emit('network-2-idle');
-this.emit('networkbusy');
-}else{
-log.verbose('NetworkRecorder','network busy');
-this.emit('network-2-busy');
-this.emit('networkbusy');
-}
-}
-
-
-
-
-
-
-
-static _isQUICAndFinished(record){
-const isQUIC=record.responseHeaders&&record.responseHeaders.
-some(header=>header.name.toLowerCase()==='alt-svc'&&/quic/.test(header.value));
-const receivedHeaders=record.timing&&record.timing.receiveHeadersEnd>0;
-return!!(isQUIC&&receivedHeaders&&record.endTime);
-}
-
-
-
-
-
-
-
-static _isFrameRootRequestAndFinished(record){
-const isFrameRootRequest=record.url===record.documentURL;
-const responseReceived=record.responseReceivedTime>0;
-return!!(isFrameRootRequest&&responseReceived&&record.endTime);
-}
-
-
-
-
-
-
-
-
-
-static findNetworkQuietPeriods(networkRecords,allowedConcurrentRequests,endTime=Infinity){
-
-
-let timeBoundaries=[];
-networkRecords.forEach(record=>{
-const scheme=record.parsedURL&&record.parsedURL.scheme;
-if(IGNORED_NETWORK_SCHEMES.includes(scheme)){
-return;
-}
-
-
-timeBoundaries.push({time:record.startTime*1000,isStart:true});
-if(record.finished||
-NetworkRecorder._isQUICAndFinished(record)||
-NetworkRecorder._isFrameRootRequestAndFinished(record)){
-timeBoundaries.push({time:record.endTime*1000,isStart:false});
-}
-});
-
-timeBoundaries=timeBoundaries.
-filter(boundary=>boundary.time<=endTime).
-sort((a,b)=>a.time-b.time);
-
-let numInflightRequests=0;
-let quietPeriodStart=0;
-
-const quietPeriods=[];
-timeBoundaries.forEach(boundary=>{
-if(boundary.isStart){
-
-if(numInflightRequests===allowedConcurrentRequests){
-quietPeriods.push({start:quietPeriodStart,end:boundary.time});
-}
-numInflightRequests++;
-}else{
-numInflightRequests--;
-
-if(numInflightRequests===allowedConcurrentRequests){
-quietPeriodStart=boundary.time;
-}
-}
-});
-
-
-if(numInflightRequests<=allowedConcurrentRequests){
-quietPeriods.push({start:quietPeriodStart,end:endTime});
-}
-
-return quietPeriods.filter(period=>period.start!==period.end);
-}
-
-
-
-
-
-
-
-onRequestStarted(request){
-this._records.push(request);
-this._recordsById.set(request.requestId,request);
-
-this._emitNetworkStatus();
-}
-
-
-
-
-
-
-
-onRequestFinished(request){
-this.emit('requestloaded',request);
-this._emitNetworkStatus();
-}
-
-
-
-
-
-
-
-onRequestWillBeSent(data){
-const originalRequest=this._findRealRequest(data.requestId);
-
-if(!originalRequest){
-const request=new NetworkRequest();
-request.onRequestWillBeSent(data);
-this.onRequestStarted(request);
-return;
-}
-
-
-if(!data.redirectResponse){
-return;
-}
-
-
-
-const modifiedData={
-...data,
-
-
-initiator:originalRequest.initiator,
-requestId:`${originalRequest.requestId}:redirect`};
-
-const redirectedRequest=new NetworkRequest();
-
-redirectedRequest.onRequestWillBeSent(modifiedData);
-originalRequest.onRedirectResponse(data);
-
-originalRequest.redirectDestination=redirectedRequest;
-redirectedRequest.redirectSource=originalRequest;
-
-
-this.onRequestStarted(redirectedRequest);
-this.onRequestFinished(originalRequest);
-}
-
-
-
-
-onRequestServedFromCache(data){
-const request=this._findRealRequest(data.requestId);
-if(!request)return;
-request.onRequestServedFromCache();
-}
-
-
-
-
-onResponseReceived(data){
-const request=this._findRealRequest(data.requestId);
-if(!request)return;
-request.onResponseReceived(data);
-}
-
-
-
-
-onDataReceived(data){
-const request=this._findRealRequest(data.requestId);
-if(!request)return;
-request.onDataReceived(data);
-}
-
-
-
-
-onLoadingFinished(data){
-const request=this._findRealRequest(data.requestId);
-if(!request)return;
-request.onLoadingFinished(data);
-this.onRequestFinished(request);
-}
-
-
-
-
-onLoadingFailed(data){
-const request=this._findRealRequest(data.requestId);
-if(!request)return;
-request.onLoadingFailed(data);
-this.onRequestFinished(request);
-}
-
-
-
-
-onResourceChangedPriority(data){
-const request=this._findRealRequest(data.requestId);
-if(!request)return;
-request.onResourceChangedPriority(data);
-}
-
-
-
-
-
-dispatch(event){
-if(!event.method.startsWith('Network.')){
-return;
-}
-
-switch(event.method){
-case'Network.requestWillBeSent':return this.onRequestWillBeSent(event.params);
-case'Network.requestServedFromCache':return this.onRequestServedFromCache(event.params);
-case'Network.responseReceived':return this.onResponseReceived(event.params);
-case'Network.dataReceived':return this.onDataReceived(event.params);
-case'Network.loadingFinished':return this.onLoadingFinished(event.params);
-case'Network.loadingFailed':return this.onLoadingFailed(event.params);
-case'Network.resourceChangedPriority':return this.onResourceChangedPriority(event.params);
-default:return;}
-
-}
-
-
-
-
-
-
-
-
-
-
-_findRealRequest(requestId){
-let request=this._recordsById.get(requestId);
-if(!request)return undefined;
-
-while(request.redirectDestination){
-request=request.redirectDestination;
-}
-
-return request;
-}
-
-
-
-
-
-
-static recordsFromLogs(devtoolsLog){
-const networkRecorder=new NetworkRecorder();
-
-devtoolsLog.forEach(message=>networkRecorder.dispatch(message));
-
-
-const records=networkRecorder.getRecords();
-
-
-const recordsByURL=new Map();
-for(const record of records){
-if(recordsByURL.has(record.url))continue;
-recordsByURL.set(record.url,record);
-}
-
-
-for(const record of records){
-const stackFrames=record.initiator.stack&&record.initiator.stack.callFrames||[];
-const initiatorURL=record.initiator.url||stackFrames[0]&&stackFrames[0].url;
-const initiator=recordsByURL.get(initiatorURL)||record.redirectSource;
-if(initiator){
-record.setInitiatorRequest(initiator);
-}
-
-let finalRecord=record;
-while(finalRecord.redirectDestination)finalRecord=finalRecord.redirectDestination;
-if(finalRecord===record||finalRecord.redirects)continue;
-
-const redirects=[];
-for(
-let redirect=finalRecord.redirectSource;
-redirect;
-redirect=redirect.redirectSource)
-{
-redirects.unshift(redirect);
-}
-
-finalRecord.redirects=redirects;
-}
-
-return records;
-}}
-
-
-module.exports=NetworkRecorder;
-
-},{"./network-request":88,"events":111,"lighthouse-logger":147}],88:[function(require,module,exports){
-(function(global){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const URL=require('./url-shim');
-
-const SECURE_SCHEMES=['data','https','wss','blob','chrome','chrome-extension','about'];
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const RESOURCE_TYPES={
-XHR:'XHR',
-Fetch:'Fetch',
-EventSource:'EventSource',
-Script:'Script',
-Stylesheet:'Stylesheet',
-Image:'Image',
-Media:'Media',
-Font:'Font',
-Document:'Document',
-TextTrack:'TextTrack',
-WebSocket:'WebSocket',
-Other:'Other',
-Manifest:'Manifest',
-SignedExchange:'SignedExchange',
-Ping:'Ping',
-CSPViolationReport:'CSPViolationReport'};
-
-
-module.exports=class NetworkRequest{
-constructor(){
-this.requestId='';
-
-this.connectionId='0';
-this.connectionReused=false;
-
-this.url='';
-this.protocol='';
-this.isSecure=false;
-this.parsedURL={scheme:''};
-this.documentURL='';
-
-this.startTime=-1;
-
-this.endTime=-1;
-
-this.responseReceivedTime=-1;
-
-this.transferSize=0;
-this.resourceSize=0;
-this.fromDiskCache=false;
-this.fromMemoryCache=false;
-
-this.finished=false;
-this.requestMethod='';
-this.statusCode=-1;
-
-this.redirectSource=undefined;
-
-this.redirectDestination=undefined;
-
-this.redirects=undefined;
-this.failed=false;
-this.localizedFailDescription='';
-
-this.initiator={type:'other'};
-
-this.timing=undefined;
-
-this.resourceType=undefined;
-this.mimeType='';
-
-this.priority='Low';
-
-this.initiatorRequest=undefined;
-
-this.responseHeaders=[];
-
-this.responseHeadersText='';
-
-this.fetchedViaServiceWorker=false;
-
-this.frameId='';
-this.isLinkPreload=false;
-}
-
-
-
-
-hasErrorStatusCode(){
-return this.statusCode>=400;
-}
-
-
-
-
-setInitiatorRequest(initiator){
-this.initiatorRequest=initiator;
-}
-
-
-
-
-onRequestWillBeSent(data){
-this.requestId=data.requestId;
-
-const url=new URL(data.request.url);
-this.url=data.request.url;
-this.documentURL=data.documentURL;
-this.parsedURL={
-scheme:url.protocol.split(':')[0],
-
-host:url.hostname,
-securityOrigin:url.origin};
-
-this.isSecure=SECURE_SCHEMES.includes(this.parsedURL.scheme);
-
-this.startTime=data.timestamp;
-
-this.requestMethod=data.request.method;
-
-this.initiator=data.initiator;
-this.resourceType=data.type&&RESOURCE_TYPES[data.type];
-this.priority=data.request.initialPriority;
-
-this.frameId=data.frameId;
-this.isLinkPreload=data.initiator.type==='preload'||!!data.request.isLinkPreload;
-}
-
-onRequestServedFromCache(){
-this.fromMemoryCache=true;
-}
-
-
-
-
-onResponseReceived(data){
-this._onResponse(data.response,data.timestamp,data.type);
-this.frameId=data.frameId;
-}
-
-
-
-
-onDataReceived(data){
-this.resourceSize+=data.dataLength;
-if(data.encodedDataLength!==-1){
-this.transferSize+=data.encodedDataLength;
-}
-}
-
-
-
-
-onLoadingFinished(data){
-
-if(this.finished)return;
-
-this.finished=true;
-this.endTime=data.timestamp;
-if(data.encodedDataLength>=0){
-this.transferSize=data.encodedDataLength;
-}
-
-this._updateResponseReceivedTimeIfNecessary();
-this._updateTransferSizeForLightRiderIfNecessary();
-}
-
-
-
-
-onLoadingFailed(data){
-
-if(this.finished)return;
-
-this.finished=true;
-this.endTime=data.timestamp;
-
-this.failed=true;
-this.resourceType=data.type&&RESOURCE_TYPES[data.type];
-this.localizedFailDescription=data.errorText;
-
-this._updateResponseReceivedTimeIfNecessary();
-}
-
-
-
-
-onResourceChangedPriority(data){
-this.priority=data.newPriority;
-}
-
-
-
-
-onRedirectResponse(data){
-if(!data.redirectResponse)throw new Error('Missing redirectResponse data');
-this._onResponse(data.redirectResponse,data.timestamp,data.type);
-this.resourceType=undefined;
-this.finished=true;
-this.endTime=data.timestamp;
-
-this._updateResponseReceivedTimeIfNecessary();
-}
-
-
-
-
-
-
-_onResponse(response,timestamp,resourceType){
-this.url=response.url;
-
-this.connectionId=String(response.connectionId);
-this.connectionReused=response.connectionReused;
-
-if(response.protocol)this.protocol=response.protocol;
-
-this.responseReceivedTime=timestamp;
-
-this.transferSize=response.encodedDataLength;
-if(typeof response.fromDiskCache==='boolean')this.fromDiskCache=response.fromDiskCache;
-
-this.statusCode=response.status;
-
-this.timing=response.timing;
-if(resourceType)this.resourceType=RESOURCE_TYPES[resourceType];
-this.mimeType=response.mimeType;
-this.responseHeadersText=response.headersText||'';
-this.responseHeaders=NetworkRequest._headersDictToHeadersArray(response.headers);
-
-this.fetchedViaServiceWorker=!!response.fromServiceWorker;
-
-if(this.fromMemoryCache)this.timing=undefined;
-if(this.timing)this._recomputeTimesWithResourceTiming(this.timing);
-
-this._updateTransferSizeForLightRiderIfNecessary();
-}
-
-
-
-
-
-
-_recomputeTimesWithResourceTiming(timing){
-
-
-this.startTime=timing.requestTime;
-const headersReceivedTime=timing.requestTime+timing.receiveHeadersEnd/1000;
-if(!this.responseReceivedTime||this.responseReceivedTime<0){
-this.responseReceivedTime=headersReceivedTime;
-}
-
-this.responseReceivedTime=Math.min(this.responseReceivedTime,headersReceivedTime);
-this.responseReceivedTime=Math.max(this.responseReceivedTime,this.startTime);
-this.endTime=Math.max(this.endTime,this.responseReceivedTime);
-}
-
-
-
-
-
-_updateResponseReceivedTimeIfNecessary(){
-this.responseReceivedTime=Math.min(this.endTime,this.responseReceivedTime);
-}
-
-
-
-
-_updateTransferSizeForLightRiderIfNecessary(){
-
-if(!global.isLightRider)return;
-
-if(this.transferSize)return;
-
-const totalFetchedSize=this.responseHeaders.find(item=>item.name==='X-TotalFetchedSize');
-
-if(!totalFetchedSize)return;
-this.transferSize=parseFloat(totalFetchedSize.value);
-}
-
-
-
-
-
-
-
-static getRequestIdForBackend(requestId){
-return requestId.replace(/(:redirect)+$/,'');
-}
-
-
-
-
-
-
-
-static _headersDictToHeadersArray(headersDict){
-const result=[];
-for(const name of Object.keys(headersDict)){
-const values=headersDict[name].split('\n');
-for(let i=0;i<values.length;++i){
-result.push({name:name,value:values[i]});
-}
-}
-return result;
-}
-
-static get TYPES(){
-return RESOURCE_TYPES;
-}};
-
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"./url-shim":"url"}],89:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function wrapRuntimeEvalErrorInBrowser(err){
-err=err||new Error();
-const fallbackMessage=typeof err==='string'?err:'unknown error';
-
-return{
-__failedInBrowser:true,
-name:err.name||'Error',
-message:err.message||fallbackMessage,
-stack:err.stack||new Error().stack};
-
-}
-
-
-
-
-
-
-function registerPerformanceObserverInPage(){
-window.____lastLongTask=window.performance.now();
-const observer=new window.PerformanceObserver(entryList=>{
-const entries=entryList.getEntries();
-for(const entry of entries){
-if(entry.entryType==='longtask'){
-const taskEnd=entry.startTime+entry.duration;
-window.____lastLongTask=Math.max(window.____lastLongTask,taskEnd);
-}
-}
-});
-
-observer.observe({entryTypes:['longtask']});
-
-
-
-
-
-window.____lhPerformanceObserver=observer;
-}
-
-
-
-
-
-function checkTimeSinceLastLongTask(){
-
-
-return new Promise(resolve=>{
-const timeoutRequested=window.performance.now()+50;
-
-setTimeout(()=>{
-
-const timeoutFired=window.performance.now();
-const timeSinceLongTask=timeoutFired-timeoutRequested<50?
-timeoutFired-window.____lastLongTask:0;
-resolve(timeSinceLongTask);
-},50);
-});
-}
-
-
-
-
-
-
-
-function getElementsInDocument(selector){
-
-const results=[];
-
-
-const _findAllElements=nodes=>{
-for(let i=0,el;el=nodes[i];++i){
-if(!selector||el.matches(selector)){
-results.push(el);
-}
-
-if(el.shadowRoot){
-_findAllElements(el.shadowRoot.querySelectorAll('*'));
-}
-}
-};
-_findAllElements(document.querySelectorAll('*'));
-
-return results;
-}
-
-
-
-
-
-
-
-
-function getOuterHTMLSnippet(element,ignoreAttrs=[]){
-const clone=element.cloneNode();
-
-ignoreAttrs.forEach(attribute=>{
-clone.removeAttribute(attribute);
-});
-
-const reOpeningTag=/^.*?>/;
-const match=clone.outerHTML.match(reOpeningTag);
-
-return match&&match[0]||'';
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function ultradumbBenchmark(){
-const start=Date.now();
-let iterations=0;
-
-while(Date.now()-start<500){
-let s='';
-for(let j=0;j<100000;j++)s+='a';
-
-iterations++;
-}
-
-const durationInSeconds=(Date.now()-start)/1000;
-return iterations/durationInSeconds;
-}
-
-module.exports={
-wrapRuntimeEvalErrorInBrowserString:wrapRuntimeEvalErrorInBrowser.toString(),
-registerPerformanceObserverInPageString:registerPerformanceObserverInPage.toString(),
-checkTimeSinceLastLongTaskString:checkTimeSinceLastLongTask.toString(),
-getElementsInDocumentString:getElementsInDocument.toString(),
-getOuterHTMLSnippetString:getOuterHTMLSnippet.toString(),
-getOuterHTMLSnippet:getOuterHTMLSnippet,
-ultradumbBenchmark:ultradumbBenchmark,
-ultradumbBenchmarkString:ultradumbBenchmark.toString()};
-
-
-},{}],90:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const log=require('lighthouse-logger');
-
-
-
-
-const SENTRY_URL='https://a6bb0da87ee048cc9ae2a345fc09ab2e:63a7029f46f74265981b7e005e0f69f8@sentry.io/174697';
-
-
-const SAMPLE_RATE=0.01;
-
-
-const SAMPLED_ERRORS=[];
-
-
-
-
-const noop=()=>{};
-
-
-
-
-
-const sentryDelegate={
-init,
-
-captureMessage:noop,
-
-captureBreadcrumb:noop,
-
-getContext:noop,
-
-captureException:async()=>{}};
-
-
-
-
-
-
-function init(opts){
-
-if(!opts.flags.enableErrorReporting){
-return;
-}
-
-
-if(SAMPLE_RATE<=Math.random()){
-return;
-}
-
-try{
-const Sentry=require('raven');
-const sentryConfig=Object.assign({},opts.environmentData,
-{captureUnhandledRejections:true});
-Sentry.config(SENTRY_URL,sentryConfig).install();
-
-
-sentryDelegate.captureMessage=(...args)=>Sentry.captureMessage(...args);
-sentryDelegate.captureBreadcrumb=(...args)=>Sentry.captureBreadcrumb(...args);
-sentryDelegate.getContext=()=>Sentry.getContext();
-
-
-sentryDelegate.captureException=async(err,opts={})=>{
-
-if(!err)return;
-
-
-
-if(err.expected)return;
-
-
-const sampledErrorMatch=SAMPLED_ERRORS.find(sample=>sample.pattern.test(err.message));
-if(sampledErrorMatch&&sampledErrorMatch.rate<=Math.random())return;
-
-
-
-if(err.protocolMethod){
-
-opts.fingerprint=['{{ default }}',err.protocolMethod,err.protocolError];
-}
-
-return new Promise(resolve=>{
-Sentry.captureException(err,opts,()=>resolve());
-});
-};
-
-const context=Object.assign({
-url:opts.url,
-deviceEmulation:!opts.flags.disableDeviceEmulation,
-emulatedFormFactor:opts.flags.emulatedFormFactor,
-throttlingMethod:opts.flags.throttlingMethod},
-opts.flags.throttling);
-Sentry.mergeContext({extra:Object.assign({},opts.environmentData.extra,context)});
-}catch(e){
-log.warn(
-'sentry',
-'Could not load raven library, errors will not be reported.');
-
-}
-}
-
-module.exports=sentryDelegate;
-
-},{"lighthouse-logger":147,"raven":107}],91:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-function erf(x){
-
-const sign=Math.sign(x);
-x=Math.abs(x);
-
-const a1=0.254829592;
-const a2=-0.284496736;
-const a3=1.421413741;
-const a4=-1.453152027;
-const a5=1.061405429;
-const p=0.3275911;
-const t=1/(1+p*x);
-const y=t*(a1+t*(a2+t*(a3+t*(a4+t*a5))));
-return sign*(1-y*Math.exp(-x*x));
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function getLogNormalDistribution(median,falloff){
-const location=Math.log(median);
-
-
-
-
-const logRatio=Math.log(falloff/median);
-const shape=Math.sqrt(1-3*logRatio-Math.sqrt((logRatio-3)*(logRatio-3)-8))/2;
-
-return{
-computeComplementaryPercentile(x){
-const standardizedX=(Math.log(x)-location)/(Math.SQRT2*shape);
-return(1-erf(standardizedX))/2;
-}};
-
-}
-
-
-
-
-
-
-
-
-
-
-function linearInterpolation(x0,y0,x1,y1,x){
-const slope=(y1-y0)/(x1-x0);
-return y0+(x-x0)*slope;
-}
-
-module.exports={
-linearInterpolation,
-getLogNormalDistribution};
-
-
-},{}],92:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-module.exports={
-didntCollectScreenshots:`Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse.`,
-badTraceRecording:`Something went wrong with recording the trace over your page load. Please run Lighthouse again.`,
-pageLoadTookTooLong:`Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse.`,
-pageLoadFailed:`Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.`,
-internalChromeError:`An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.`,
-requestContentTimeout:'Fetching resource content has exceeded the allotted time',
-urlInvalid:`The URL you have provided appears to be invalid.`};
-
-
-},{}],93:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const taskGroups={
-parseHTML:{
-id:'parseHTML',
-label:'Parse HTML & CSS',
-traceEventNames:['ParseHTML','ParseAuthorStyleSheet']},
-
-styleLayout:{
-id:'styleLayout',
-label:'Style & Layout',
-traceEventNames:[
-'ScheduleStyleRecalculation',
-'RecalculateStyles',
-'UpdateLayoutTree',
-'InvalidateLayout',
-'Layout']},
-
-
-paintCompositeRender:{
-id:'paintCompositeRender',
-label:'Rendering',
-traceEventNames:[
-'Animation',
-'RequestMainThreadFrame',
-'ActivateLayerTree',
-'DrawFrame',
-'HitTest',
-'PaintSetup',
-'Paint',
-'PaintImage',
-'Rasterize',
-'RasterTask',
-'ScrollLayer',
-'UpdateLayer',
-'UpdateLayerTree',
-'CompositeLayers']},
-
-
-scriptParseCompile:{
-id:'scriptParseCompile',
-label:'Script Parsing & Compilation',
-traceEventNames:['v8.compile','v8.compileModule','v8.parseOnBackground']},
-
-scriptEvaluation:{
-id:'scriptEvaluation',
-label:'Script Evaluation',
-traceEventNames:[
-'EventDispatch',
-'EvaluateScript',
-'v8.evaluateModule',
-'FunctionCall',
-'TimerFire',
-'FireIdleCallback',
-'FireAnimationFrame',
-'RunMicrotasks',
-'V8.Execute']},
-
-
-garbageCollection:{
-id:'garbageCollection',
-label:'Garbage Collection',
-traceEventNames:[
-'GCEvent',
-'MinorGC',
-'MajorGC',
-'ThreadState::performIdleLazySweep',
-'ThreadState::completeSweep',
-'BlinkGCMarking']},
-
-
-other:{
-id:'other',
-label:'Other',
-traceEventNames:[
-'MessageLoop::RunTask',
-'TaskQueueManager::ProcessTaskFromWorkQueue',
-'ThreadControllerImpl::DoWork']}};
-
-
-
-
-
-const taskNameToGroup={};
-for(const group of Object.values(taskGroups)){
-for(const traceEventName of group.traceEventNames){
-taskNameToGroup[traceEventName]=group;
-}
-}
-
-module.exports={
-taskGroups,
-taskNameToGroup};
-
-
-},{}],94:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const log=require('lighthouse-logger');
-
-
-
-function findValueInMetricsAuditFn(metricName){
-return auditResults=>{
-const metricsAudit=auditResults.metrics;
-if(!metricsAudit||!metricsAudit.details||!metricsAudit.details.items)return;
-
-const values=metricsAudit.details.items[0];
-return values&&values[metricName];
-};
-}
-
-class Metrics{
-constructor(traceEvents,auditResults){
-this._traceEvents=traceEvents;
-this._auditResults=auditResults;
-}
-
-
-
-
-
-static get metricsDefinitions(){
-return[
-{
-name:'Navigation Start',
-id:'navstart',
-getTs:findValueInMetricsAuditFn('observedNavigationStartTs'),
-getTiming:findValueInMetricsAuditFn('observedNavigationStart')},
-
-{
-name:'First Contentful Paint',
-id:'ttfcp',
-getTs:findValueInMetricsAuditFn('observedFirstContentfulPaintTs'),
-getTiming:findValueInMetricsAuditFn('observedFirstContentfulPaint')},
-
-{
-name:'First Meaningful Paint',
-id:'ttfmp',
-getTs:findValueInMetricsAuditFn('observedFirstMeaningfulPaintTs'),
-getTiming:findValueInMetricsAuditFn('observedFirstMeaningfulPaint')},
-
-{
-name:'Speed Index',
-id:'si',
-getTs:findValueInMetricsAuditFn('observedSpeedIndexTs'),
-getTiming:findValueInMetricsAuditFn('observedSpeedIndex')},
-
-{
-name:'First Visual Change',
-id:'fv',
-getTs:findValueInMetricsAuditFn('observedFirstVisualChangeTs'),
-getTiming:findValueInMetricsAuditFn('observedFirstVisualChange')},
-
-{
-name:'Visually Complete 100%',
-id:'vc100',
-getTs:findValueInMetricsAuditFn('observedLastVisualChangeTs'),
-getTiming:findValueInMetricsAuditFn('observedLastVisualChange')},
-
-{
-name:'First CPU Idle',
-id:'ttfi',
-getTs:findValueInMetricsAuditFn('firstCPUIdleTs'),
-getTiming:findValueInMetricsAuditFn('firstCPUIdle')},
-
-{
-name:'Interactive',
-id:'tti',
-getTs:findValueInMetricsAuditFn('interactiveTs'),
-getTiming:findValueInMetricsAuditFn('interactive')},
-
-{
-name:'End of Trace',
-id:'eot',
-getTs:findValueInMetricsAuditFn('observedTraceEndTs'),
-getTiming:findValueInMetricsAuditFn('observedTraceEnd')},
-
-{
-name:'On Load',
-id:'onload',
-getTs:findValueInMetricsAuditFn('observedLoadTs'),
-getTiming:findValueInMetricsAuditFn('observedLoad')},
-
-{
-name:'DOM Content Loaded',
-id:'dcl',
-getTs:findValueInMetricsAuditFn('observedDomContentLoadedTs'),
-getTiming:findValueInMetricsAuditFn('observedDomContentLoaded')}];
-
-
-}
-
-
-
-
-
-gatherMetrics(){
-const metricDfns=Metrics.metricsDefinitions;
-const resolvedMetrics=[];
-metricDfns.forEach(metric=>{
-
-try{
-resolvedMetrics.push({
-id:metric.id,
-name:metric.name,
-ts:metric.getTs(this._auditResults)});
-
-}catch(e){
-log.error('pwmetrics-events',`${metric.name} timestamp not found: ${e.message}`);
-}
-});
-return resolvedMetrics;
-}
-
-
-
-
-
-identifyNavigationStartEvt(metrics){
-const navStartMetric=metrics.find(e=>e.id==='navstart');
-if(!navStartMetric)return;
-this._navigationStartEvt=this._traceEvents.find(
-e=>e.name==='navigationStart'&&e.ts===navStartMetric.ts);
-
-}
-
-
-
-
-
-
-
-
-synthesizeEventPair(metric){
-
-const eventBase={
-pid:this._navigationStartEvt.pid,
-tid:this._navigationStartEvt.tid,
-cat:'blink.user_timing',
-name:metric.name,
-args:{},
-
-id:`0x${(Math.random()*1000000|0).toString(16)}`};
-
-const fakeMeasureStartEvent=Object.assign({},eventBase,{
-ts:this._navigationStartEvt.ts,
-ph:'b'});
-
-const fakeMeasureEndEvent=Object.assign({},eventBase,{
-ts:metric.ts,
-ph:'e'});
-
-return[fakeMeasureStartEvent,fakeMeasureEndEvent];
-}
-
-
-
-
-generateFakeEvents(){
-const fakeEvents=[];
-const metrics=this.gatherMetrics();
-if(metrics.length===0){
-log.error('metrics-events','Metrics collection had errors, not synthetizing trace events');
-return[];
-}
-
-this.identifyNavigationStartEvt(metrics);
-if(!this._navigationStartEvt){
-log.error('pwmetrics-events','Reference navigationStart not found');
-return[];
-}
-
-metrics.forEach(metric=>{
-if(metric.id==='navstart'){
-return;
-}
-if(!metric.ts){
-log.error('pwmetrics-events',`(${metric.name}) missing timestamp. Skipping…`);
-return;
-}
-log.verbose('pwmetrics-events',`Sythesizing trace events for ${metric.name}`);
-fakeEvents.push(...this.synthesizeEventPair(metric));
-});
-return fakeEvents;
-}}
-
-
-module.exports=Metrics;
-
-},{"lighthouse-logger":147}],95:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-const BASE_RESPONSE_LATENCY=16;
-
-const SCHEDULABLE_TASK_TITLE='TaskQueueManager::ProcessTaskFromWorkQueue';
-
-const SCHEDULABLE_TASK_TITLE_ALT1='ThreadControllerImpl::DoWork';
-
-const SCHEDULABLE_TASK_TITLE_ALT2='ThreadControllerImpl::RunTask';
-const LHError=require('../lh-error');
-
-class TraceProcessor{
-
-
-
-
-
-
-static assertHasToplevelEvents(events){
-const hasToplevelTask=events.some(TraceProcessor.isScheduleableTask);
-if(!hasToplevelTask){
-throw new Error('Could not find any top level events');
-}
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-static _riskPercentiles(durations,totalTime,percentiles,clippedLength=0){
-let busyTime=0;
-for(let i=0;i<durations.length;i++){
-busyTime+=durations[i];
-}
-busyTime-=clippedLength;
-
-
-let completedTime=totalTime-busyTime;
-let duration=0;
-let cdfTime=completedTime;
-const results=[];
-
-let durationIndex=-1;
-let remainingCount=durations.length+1;
-if(clippedLength>0){
-
-remainingCount--;
-}
-
-
-for(const percentile of percentiles){
-
-
-const percentileTime=percentile*totalTime;
-while(cdfTime<percentileTime&&durationIndex<durations.length-1){
-completedTime+=duration;
-remainingCount-=duration<0?-1:1;
-
-if(clippedLength>0&&clippedLength<durations[durationIndex+1]){
-duration=-clippedLength;
-clippedLength=0;
-}else{
-durationIndex++;
-duration=durations[durationIndex];
-}
-
-
-cdfTime=completedTime+Math.abs(duration)*remainingCount;
-}
-
-
-results.push({
-percentile,
-time:Math.max(0,(percentileTime-completedTime)/remainingCount)+
-BASE_RESPONSE_LATENCY});
-
-}
-
-return results;
-}
-
-
-
-
-
-
-
-
-
-
-
-static getRiskToResponsiveness(
-events,
-startTime,
-endTime,
-percentiles=[0.5,0.75,0.9,0.99,1])
-{
-const totalTime=endTime-startTime;
-percentiles.sort((a,b)=>a-b);
-
-const ret=TraceProcessor.getMainThreadTopLevelEventDurations(events,startTime,endTime);
-return TraceProcessor._riskPercentiles(ret.durations,totalTime,percentiles,
-ret.clippedLength);
-}
-
-
-
-
-
-
-
-
-static getMainThreadTopLevelEventDurations(topLevelEvents,startTime=0,endTime=Infinity){
-
-
-const durations=[];
-let clippedLength=0;
-
-for(const event of topLevelEvents){
-if(event.end<startTime||event.start>endTime){
-continue;
-}
-
-let duration=event.duration;
-let eventStart=event.start;
-if(eventStart<startTime){
-
-eventStart=startTime;
-duration=event.end-startTime;
-}
-
-if(event.end>endTime){
-
-clippedLength=duration-(endTime-eventStart);
-}
-
-durations.push(duration);
-}
-durations.sort((a,b)=>a-b);
-
-return{
-durations,
-clippedLength};
-
-}
-
-
-
-
-
-
-
-
-
-static getMainThreadTopLevelEvents(tabTrace,startTime=0,endTime=Infinity){
-const topLevelEvents=[];
-
-for(const event of tabTrace.mainThreadEvents){
-if(!TraceProcessor.isScheduleableTask(event)||!event.dur)continue;
-
-const start=(event.ts-tabTrace.navigationStartEvt.ts)/1000;
-const end=(event.ts+event.dur-tabTrace.navigationStartEvt.ts)/1000;
-if(start>endTime||end<startTime)continue;
-
-topLevelEvents.push({
-start,
-end,
-duration:event.dur/1000});
-
-}
-
-return topLevelEvents;
-}
-
-
-
-
-
-static findTracingStartedEvt(events){
-
-let startedInPageEvt;
-
-
-const startedInBrowserEvt=events.find(e=>e.name==='TracingStartedInBrowser');
-if(startedInBrowserEvt&&startedInBrowserEvt.args.data&&
-startedInBrowserEvt.args.data.frames){
-const mainFrame=startedInBrowserEvt.args.data.frames.find(frame=>!frame.parent);
-const pid=mainFrame&&mainFrame.processId;
-const threadNameEvt=events.find(e=>e.pid===pid&&e.ph==='M'&&
-e.cat==='__metadata'&&e.name==='thread_name'&&e.args.name==='CrRendererMain');
-startedInPageEvt=mainFrame&&threadNameEvt?
-Object.assign({},startedInBrowserEvt,{
-pid,tid:threadNameEvt.tid,name:'TracingStartedInPage',
-args:{data:{page:mainFrame.frame}}}):
-undefined;
-}
-
-
-if(!startedInPageEvt){
-
-
-startedInPageEvt=events.find(e=>e.name==='TracingStartedInPage');
-}
-
-if(!startedInPageEvt)throw new LHError(LHError.errors.NO_TRACING_STARTED);
-
-
-const frameId=startedInPageEvt.args.data.page;
-return{startedInPageEvt,frameId};
-}
-
-
-
-
-
-static isScheduleableTask(evt){
-return evt.name===SCHEDULABLE_TASK_TITLE||
-evt.name===SCHEDULABLE_TASK_TITLE_ALT1||
-evt.name===SCHEDULABLE_TASK_TITLE_ALT2;
-}}
-
-
-
-
-
-
-
-
-
-module.exports=TraceProcessor;
-
-},{"../lh-error":85}],96:[function(require,module,exports){
-(function(global){
-
-
-
-
-
-
-'use strict';
-
-
-
-
-
-module.exports=function(){
-if(global.SDK){
-return global.SDK;
-}
-
-
-global.SDK={};
-global.TextUtils={};
-global.Node={
-ELEMENT_NODE:1,
-TEXT_NODE:3};
-
-global.Protocol={
-CSS:{
-StyleSheetOrigin:{
-Injected:'injected',
-UserAgent:'user-agent',
-Inspector:'inspector',
-Regular:'regular'}}};
-
-
-
-
-
-
-
-
-String.prototype.computeLineEndings=function(){
-const endings=[];
-for(let i=0;i<this.length;i++){
-if(this.charAt(i)==='\n'){
-endings.push(i);
-}
-}
-endings.push(this.length);
-return endings;
-};
-
-require('chrome-devtools-frontend/front_end/text_utils/Text.js');
-require('chrome-devtools-frontend/front_end/text_utils/TextRange.js');
-require('chrome-devtools-frontend/front_end/sdk/CSSMatchedStyles.js');
-require('chrome-devtools-frontend/front_end/sdk/CSSMedia.js');
-require('chrome-devtools-frontend/front_end/sdk/CSSMetadata.js');
-require('chrome-devtools-frontend/front_end/sdk/CSSProperty.js');
-require('chrome-devtools-frontend/front_end/sdk/CSSRule.js');
-require('chrome-devtools-frontend/front_end/sdk/CSSStyleDeclaration.js');
-
-return global.SDK;
-}();
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"chrome-devtools-frontend/front_end/sdk/CSSMatchedStyles.js":153,"chrome-devtools-frontend/front_end/sdk/CSSMedia.js":154,"chrome-devtools-frontend/front_end/sdk/CSSMetadata.js":155,"chrome-devtools-frontend/front_end/sdk/CSSProperty.js":156,"chrome-devtools-frontend/front_end/sdk/CSSRule.js":157,"chrome-devtools-frontend/front_end/sdk/CSSStyleDeclaration.js":158,"chrome-devtools-frontend/front_end/text_utils/Text.js":159,"chrome-devtools-frontend/front_end/text_utils/TextRange.js":160}],97:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-
-
-const ELLIPSIS='\u2026';
-const NBSP='\xa0';
-const PASS_THRESHOLD=0.9;
-
-const RATINGS={
-PASS:{label:'pass',minScore:PASS_THRESHOLD},
-AVERAGE:{label:'average',minScore:0.5},
-FAIL:{label:'fail'},
-ERROR:{label:'error'}};
-
-
-class Util{
-static get PASS_THRESHOLD(){
-return PASS_THRESHOLD;
-}
-
-static get MS_DISPLAY_VALUE(){
-return`%10d${NBSP}ms`;
-}
-
-
-
-
-
-
-
-
-
-static prepareReportResult(result){
-
-const clone=JSON.parse(JSON.stringify(result));
-
-
-if(!clone.configSettings.locale){
-clone.configSettings.locale='en';
-}
-Util.setNumberDateLocale(clone.configSettings.locale);
-if(clone.i18n&&clone.i18n.rendererFormattedStrings){
-Util.updateAllUIStrings(clone.i18n.rendererFormattedStrings);
-}
-
-if(typeof clone.categories!=='object')throw new Error('No categories provided.');
-clone.reportCategories=Object.values(clone.categories);
-
-
-for(const category of clone.reportCategories){
-category.auditRefs.forEach(auditMeta=>{
-const result=clone.audits[auditMeta.id];
-auditMeta.result=result;
-});
-}
-
-return clone;
-}
-
-
-
-
-
-static updateAllUIStrings(rendererFormattedStrings){
-
-for(const[key,value]of Object.entries(rendererFormattedStrings)){
-Util.UIStrings[key]=value;
-}
-}
-
-
-
-
-
-static formatDisplayValue(displayValue){
-if(typeof displayValue==='string')return displayValue;
-if(!displayValue)return'';
-
-const replacementRegex=/%([0-9]*(\.[0-9]+)?d|s)/;
-const template=displayValue[0];
-if(typeof template!=='string'){
-
-
-return'UNKNOWN';
-}
-
-let output=template;
-for(const replacement of displayValue.slice(1)){
-if(!replacementRegex.test(output)){
-
-console.warn('Too many replacements given');
-break;
-}
-
-output=output.replace(replacementRegex,match=>{
-const granularity=Number(match.match(/[0-9.]+/))||1;
-return match==='%s'?
-replacement.toLocaleString():
-(Math.round(Number(replacement)/granularity)*granularity).toLocaleString();
-});
-}
-
-if(replacementRegex.test(output)){
-
-console.warn('Not enough replacements given');
-}
-
-return output;
-}
-
-
-
-
-
-
-
-
-static showAsPassed(audit){
-switch(audit.scoreDisplayMode){
-case'manual':
-case'not-applicable':
-return true;
-case'error':
-case'informative':
-return false;
-case'numeric':
-case'binary':
-default:
-return Number(audit.score)>=RATINGS.PASS.minScore;}
-
-}
-
-
-
-
-
-
-
-static calculateRating(score,scoreDisplayMode){
-
-if(scoreDisplayMode==='manual'||scoreDisplayMode==='not-applicable'){
-return RATINGS.PASS.label;
-}else if(scoreDisplayMode==='error'){
-return RATINGS.ERROR.label;
-}else if(score===null){
-return RATINGS.FAIL.label;
-}
-
-
-let rating=RATINGS.FAIL.label;
-if(score>=RATINGS.PASS.minScore){
-rating=RATINGS.PASS.label;
-}else if(score>=RATINGS.AVERAGE.minScore){
-rating=RATINGS.AVERAGE.label;
-}
-return rating;
-}
-
-
-
-
-
-
-
-static formatNumber(number,granularity=0.1){
-const coarseValue=Math.round(number/granularity)*granularity;
-return coarseValue.toLocaleString(Util.numberDateLocale);
-}
-
-
-
-
-
-
-static formatBytesToKB(size,granularity=0.1){
-const kbs=(Math.round(size/1024/granularity)*granularity).
-toLocaleString(Util.numberDateLocale);
-return`${kbs}${NBSP}KB`;
-}
-
-
-
-
-
-
-static formatMilliseconds(ms,granularity=10){
-const coarseTime=Math.round(ms/granularity)*granularity;
-return`${coarseTime.toLocaleString(Util.numberDateLocale)}${NBSP}ms`;
-}
-
-
-
-
-
-
-static formatSeconds(ms,granularity=0.1){
-const coarseTime=Math.round(ms/1000/granularity)*granularity;
-return`${coarseTime.toLocaleString(Util.numberDateLocale)}${NBSP}s`;
-}
-
-
-
-
-
-
-static formatDateTime(date){
-
-const options={
-month:'short',day:'numeric',year:'numeric',
-hour:'numeric',minute:'numeric',timeZoneName:'short'};
-
-let formatter=new Intl.DateTimeFormat(Util.numberDateLocale,options);
-
-
-
-const tz=formatter.resolvedOptions().timeZone;
-if(!tz||tz.toLowerCase()==='etc/unknown'){
-options.timeZone='UTC';
-formatter=new Intl.DateTimeFormat(Util.numberDateLocale,options);
-}
-return formatter.format(new Date(date));
-}
-
-
-
-
-
-static formatDuration(timeInMilliseconds){
-let timeInSeconds=timeInMilliseconds/1000;
-if(Math.round(timeInSeconds)===0){
-return'None';
-}
-
-
-const parts=[];
-const unitLabels={
-d:60*60*24,
-h:60*60,
-m:60,
-s:1};
-
-
-Object.keys(unitLabels).forEach(label=>{
-const unit=unitLabels[label];
-const numberOfUnits=Math.floor(timeInSeconds/unit);
-if(numberOfUnits>0){
-timeInSeconds-=numberOfUnits*unit;
-parts.push(`${numberOfUnits}\xa0${label}`);
-}
-});
-
-return parts.join(' ');
-}
-
-
-
-
-
-
-static getURLDisplayName(parsedUrl,options){
-
-options=options||{numPathParts:undefined,preserveQuery:undefined,
-preserveHost:undefined};
-const numPathParts=options.numPathParts!==undefined?options.numPathParts:2;
-const preserveQuery=options.preserveQuery!==undefined?options.preserveQuery:true;
-const preserveHost=options.preserveHost||false;
-
-let name;
-
-if(parsedUrl.protocol==='about:'||parsedUrl.protocol==='data:'){
-
-name=parsedUrl.href;
-}else{
-name=parsedUrl.pathname;
-const parts=name.split('/').filter(part=>part.length);
-if(numPathParts&&parts.length>numPathParts){
-name=ELLIPSIS+parts.slice(-1*numPathParts).join('/');
-}
-
-if(preserveHost){
-name=`${parsedUrl.host}/${name.replace(/^\//,'')}`;
-}
-if(preserveQuery){
-name=`${name}${parsedUrl.search}`;
-}
-}
-
-const MAX_LENGTH=64;
-
-name=name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,`$1${ELLIPSIS}`);
-
-name=name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,
-`$1${ELLIPSIS}`);
-
-name=name.replace(/(\d{3})\d{6,}/g,`$1${ELLIPSIS}`);
-
-name=name.replace(/\u2026+/g,ELLIPSIS);
-
-
-if(name.length>MAX_LENGTH&&name.includes('?')){
-
-name=name.replace(/\?([^=]*)(=)?.*/,`?$1$2${ELLIPSIS}`);
-
-
-if(name.length>MAX_LENGTH){
-name=name.replace(/\?.*/,`?${ELLIPSIS}`);
-}
-}
-
-
-if(name.length>MAX_LENGTH){
-const dotIndex=name.lastIndexOf('.');
-if(dotIndex>=0){
-name=name.slice(0,MAX_LENGTH-1-(name.length-dotIndex))+
-
-`${ELLIPSIS}${name.slice(dotIndex)}`;
-}else{
-name=name.slice(0,MAX_LENGTH-1)+ELLIPSIS;
-}
-}
-
-return name;
-}
-
-
-
-
-
-
-static parseURL(url){
-const parsedUrl=new URL(url);
-return{
-file:Util.getURLDisplayName(parsedUrl),
-hostname:parsedUrl.hostname,
-origin:parsedUrl.origin};
-
-}
-
-
-
-
-
-static getEnvironmentDisplayValues(settings){
-const emulationDesc=Util.getEmulationDescriptions(settings);
-
-return[
-{
-name:'Device',
-description:emulationDesc.deviceEmulation},
-
-{
-name:'Network throttling',
-description:emulationDesc.networkThrottling},
-
-{
-name:'CPU throttling',
-description:emulationDesc.cpuThrottling}];
-
-
-}
-
-
-
-
-
-static getEmulationDescriptions(settings){
-let cpuThrottling;
-let networkThrottling;
-let summary;
-
-const throttling=settings.throttling;
-
-switch(settings.throttlingMethod){
-case'provided':
-cpuThrottling='Provided by environment';
-networkThrottling='Provided by environment';
-summary='No throttling applied';
-break;
-case'devtools':{
-const{cpuSlowdownMultiplier,requestLatencyMs}=throttling;
-cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;
-networkThrottling=`${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, `+
-`${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, `+
-`${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
-summary='Throttled Fast 3G network';
-break;
-}
-case'simulate':{
-const{cpuSlowdownMultiplier,rttMs,throughputKbps}=throttling;
-cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
-networkThrottling=`${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, `+
-`${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
-summary='Simulated Fast 3G network';
-break;
-}
-default:
-cpuThrottling='Unknown';
-networkThrottling='Unknown';
-summary='Unknown';}
-
-
-let deviceEmulation='No emulation';
-if(!settings.disableDeviceEmulation){
-if(settings.emulatedFormFactor==='mobile')deviceEmulation='Emulated Nexus 5X';
-if(settings.emulatedFormFactor==='desktop')deviceEmulation='Emulated Desktop';
-}
-
-return{
-deviceEmulation,
-cpuThrottling,
-networkThrottling,
-summary:`${deviceEmulation}, ${summary}`};
-
-}
-
-
-
-
-
-static setNumberDateLocale(locale){
-Util.numberDateLocale=locale;
-
-
-if(Util.numberDateLocale==='en-XA')Util.numberDateLocale='de';
-}}
-
-
-
-
-
-
-Util.numberDateLocale='en';
-
-
-
-
-
-Util.UIStrings={
-
-varianceDisclaimer:'Values are estimated and may vary.',
-
-opportunityResourceColumnLabel:'Opportunity',
-
-opportunitySavingsColumnLabel:'Estimated Savings',
-
-
-errorMissingAuditInfo:'Report error: no audit information',
-
-errorLabel:'Error!',
-
-warningHeader:'Warnings: ',
-
-auditGroupExpandTooltip:'Show audits',
-
-passedAuditsGroupTitle:'Passed audits',
-
-notApplicableAuditsGroupTitle:'Not applicable',
-
-manualAuditsGroupTitle:'Additional items to manually check',
-
-
-toplevelWarningsMessage:'There were issues affecting this run of Lighthouse:',
-
-scorescaleLabel:'Score scale:',
-
-
-crcInitialNavigation:'Initial Navigation',
-
-crcLongestDurationLabel:'Maximum critical path latency:',
-
-
-lsPerformanceCategoryDescription:'[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on emulated 3G. Values are estimated and may vary.',
-
-labDataTitle:'Lab Data'};
-
-
-if(typeof module!=='undefined'&&module.exports){
-module.exports=Util;
-}else{
-self.Util=Util;
-}
-
-},{}],98:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const htmlReportAssets=require('./html/html-report-assets');
-
-class ReportGenerator{
-
-
-
-
-
-
-static replaceStrings(source,replacements){
-if(replacements.length===0){
-return source;
-}
-
-const firstReplacement=replacements[0];
-const nextReplacements=replacements.slice(1);
-return source.
-split(firstReplacement.search).
-map(part=>ReportGenerator.replaceStrings(part,nextReplacements)).
-join(firstReplacement.replacement);
-}
-
-
-
-
-
-
-static generateReportHtml(lhr){
-const sanitizedJson=JSON.stringify(lhr).
-replace(/</g,'\\u003c').
-replace(/\u2028/g,'\\u2028').
-replace(/\u2029/g,'\\u2029');
-const sanitizedJavascript=htmlReportAssets.REPORT_JAVASCRIPT.replace(/<\//g,'\\u003c/');
-
-return ReportGenerator.replaceStrings(htmlReportAssets.REPORT_TEMPLATE,[
-{search:'%%LIGHTHOUSE_JSON%%',replacement:sanitizedJson},
-{search:'%%LIGHTHOUSE_JAVASCRIPT%%',replacement:sanitizedJavascript},
-{search:'/*%%LIGHTHOUSE_CSS%%*/',replacement:htmlReportAssets.REPORT_CSS},
-{search:'%%LIGHTHOUSE_TEMPLATES%%',replacement:htmlReportAssets.REPORT_TEMPLATES}]);
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-static generateReportCSV(lhr){
-
-
-const CRLF='\r\n';
-const separator=',';
-
-const escape=value=>`"${value.replace(/"/g,'""')}"`;
-
-
-const header=['category','name','title','type','score'];
-const table=Object.values(lhr.categories).map(category=>{
-return category.auditRefs.map(auditRef=>{
-const audit=lhr.audits[auditRef.id];
-
-const numericScore=audit.score===null?-1:audit.score;
-return[category.title,audit.id,audit.title,audit.scoreDisplayMode,numericScore].
-map(value=>value.toString()).
-map(escape);
-});
-});
-
-
-const flattedTable=[].concat(...table);
-return[header,...flattedTable].map(row=>row.join(separator)).join(CRLF);
-}
-
-
-
-
-
-
-
-static generateReport(lhr,outputModes){
-const outputAsArray=Array.isArray(outputModes);
-if(typeof outputModes==='string')outputModes=[outputModes];
-
-const output=outputModes.map(outputMode=>{
-
-if(outputMode==='html'){
-return ReportGenerator.generateReportHtml(lhr);
-}
-
-if(outputMode==='csv'){
-return ReportGenerator.generateReportCSV(lhr);
-}
-
-if(outputMode==='json'){
-return JSON.stringify(lhr,null,2);
-}
-
-throw new Error('Invalid output mode: '+outputMode);
-});
-
-return outputAsArray?output:output[0];
-}}
-
-
-module.exports=ReportGenerator;
-
-},{"./html/html-report-assets":107}],99:[function(require,module,exports){
-(function(process,__dirname){
-
-
-
-
-
-'use strict';
-
-const isDeepEqual=require('lodash.isequal');
-const Driver=require('./gather/driver.js');
-const GatherRunner=require('./gather/gather-runner');
-const ReportScoring=require('./scoring');
-const Audit=require('./audits/audit');
-const log=require('lighthouse-logger');
-const i18n=require('./lib/i18n/i18n.js');
-const assetSaver=require('./lib/asset-saver');
-
-const path=require('path');
-const URL=require('./lib/url-shim');
-const Sentry=require('./lib/sentry');
-const generateReport=require('./report/report-generator').generateReport;
-const LHError=require('./lib/lh-error.js');
-
-
-
-
-class Runner{
-
-
-
-
-
-static async run(connection,runOpts){
-try{
-const startTime=Date.now();
-const settings=runOpts.config.settings;
-
-
-
-
-
-const lighthouseRunWarnings=[];
-
-const sentryContext=Sentry.getContext();
-Sentry.captureBreadcrumb({
-message:'Run started',
-category:'lifecycle',
-data:sentryContext&&sentryContext.extra});
-
-
-
-
-
-
-
-
-let artifacts;
-let requestedUrl;
-if(settings.auditMode&&!settings.gatherMode){
-
-const path=Runner._getArtifactsPath(settings);
-artifacts=await assetSaver.loadArtifacts(path);
-requestedUrl=artifacts.URL.requestedUrl;
-
-if(!requestedUrl){
-throw new Error('Cannot run audit mode on empty URL');
-}
-if(runOpts.url&&!URL.equalWithExcludedFragments(runOpts.url,requestedUrl)){
-throw new Error('Cannot run audit mode on different URL');
-}
-}else{
-if(typeof runOpts.url!=='string'||runOpts.url.length===0){
-throw new Error(`You must provide a url to the runner. '${runOpts.url}' provided.`);
-}
-
-try{
-
-requestedUrl=new URL(runOpts.url).href;
-}catch(e){
-throw new Error('The url provided should have a proper protocol and hostname.');
-}
-
-artifacts=await Runner._gatherArtifactsFromBrowser(requestedUrl,runOpts,connection);
-
-if(settings.gatherMode){
-const path=Runner._getArtifactsPath(settings);
-await assetSaver.saveArtifacts(artifacts,path);
-}
-}
-
-
-if(settings.gatherMode&&!settings.auditMode)return;
-
-
-if(!runOpts.config.audits){
-throw new Error('No audits to evaluate.');
-}
-const auditResults=await Runner._runAudits(settings,runOpts.config.audits,artifacts,
-lighthouseRunWarnings);
-
-
-log.log('status','Generating results...');
-
-if(artifacts.LighthouseRunWarnings){
-lighthouseRunWarnings.push(...artifacts.LighthouseRunWarnings);
-}
-
-
-const lighthouseVersion=require('../package.json').version;
-
-
-const resultsById={};
-for(const audit of auditResults){
-resultsById[audit.id]=audit;
-}
-
-
-let categories={};
-if(runOpts.config.categories){
-categories=ReportScoring.scoreAllCategories(runOpts.config.categories,resultsById);
-}
-
-
-const lhr={
-userAgent:artifacts.HostUserAgent,
-environment:{
-networkUserAgent:artifacts.NetworkUserAgent,
-hostUserAgent:artifacts.HostUserAgent,
-benchmarkIndex:artifacts.BenchmarkIndex},
-
-lighthouseVersion,
-fetchTime:artifacts.fetchTime,
-requestedUrl:requestedUrl,
-finalUrl:artifacts.URL.finalUrl,
-runWarnings:lighthouseRunWarnings,
-runtimeError:Runner.getArtifactRuntimeError(artifacts),
-audits:resultsById,
-configSettings:settings,
-categories,
-categoryGroups:runOpts.config.groups||undefined,
-timing:{total:Date.now()-startTime},
-i18n:{
-rendererFormattedStrings:i18n.getRendererFormattedStrings(settings.locale),
-icuMessagePaths:{}}};
-
-
-
-
-lhr.i18n.icuMessagePaths=i18n.replaceIcuMessageInstanceIds(lhr,settings.locale);
-
-const report=generateReport(lhr,settings.output);
-return{lhr,artifacts,report};
-}catch(err){
-await Sentry.captureException(err,{level:'fatal'});
-throw err;
-}
-}
-
-
-
-
-
-
-
-
-static async _gatherArtifactsFromBrowser(requestedUrl,runnerOpts,connection){
-if(!runnerOpts.config.passes){
-throw new Error('No browser artifacts are either provided or requested.');
-}
-
-const driver=runnerOpts.driverMock||new Driver(connection);
-const gatherOpts={
-driver,
-requestedUrl,
-settings:runnerOpts.config.settings};
-
-const artifacts=await GatherRunner.run(runnerOpts.config.passes,gatherOpts);
-return artifacts;
-}
-
-
-
-
-
-
-
-
-
-static async _runAudits(settings,audits,artifacts,runWarnings){
-log.log('status','Analyzing and running audits...');
-artifacts=Object.assign({},Runner.instantiateComputedArtifacts(),artifacts);
-
-if(artifacts.settings){
-const overrides={
-locale:undefined,
-gatherMode:undefined,
-auditMode:undefined,
-output:undefined};
-
-const normalizedGatherSettings=Object.assign({},artifacts.settings,overrides);
-const normalizedAuditSettings=Object.assign({},settings,overrides);
-
-
-if(!isDeepEqual(normalizedGatherSettings,normalizedAuditSettings)){
-throw new Error('Cannot change settings between gathering and auditing');
-}
-}
-
-
-const sharedAuditContext={
-settings,
-LighthouseRunWarnings:runWarnings,
-computedCache:new Map()};
-
-
-
-const auditResults=[];
-for(const auditDefn of audits){
-const auditResult=await Runner._runAudit(auditDefn,artifacts,sharedAuditContext);
-auditResults.push(auditResult);
-}
-
-return auditResults;
-}
-
-
-
-
-
-
-
-
-
-
-static async _runAudit(auditDefn,artifacts,sharedAuditContext){
-const audit=auditDefn.implementation;
-const status=`Evaluating: ${i18n.getFormatted(audit.meta.title,'en-US')}`;
-
-log.log('status',status);
-let auditResult;
-try{
-
-for(const artifactName of audit.meta.requiredArtifacts){
-const noArtifact=artifacts[artifactName]===undefined;
-
-
-
-const noTrace=artifactName==='traces'&&!artifacts.traces[Audit.DEFAULT_PASS];
-
-if(noArtifact||noTrace){
-log.warn('Runner',
-`${artifactName} gatherer, required by audit ${audit.meta.id}, did not run.`);
-throw new Error(`Required ${artifactName} gatherer did not run.`);
-}
-
-
-
-if(artifacts[artifactName]instanceof Error){
-
-
-const artifactError=artifacts[artifactName];
-
-Sentry.captureException(artifactError,{
-tags:{gatherer:artifactName},
-level:'error'});
-
-
-log.warn('Runner',`${artifactName} gatherer, required by audit ${audit.meta.id},`+
-` encountered an error: ${artifactError.message}`);
-
-
-const error=new Error(
-`Required ${artifactName} gatherer encountered an error: ${artifactError.message}`);
-
-error.expected=true;
-throw error;
-}
-}
-
-
-const auditOptions=Object.assign({},audit.defaultOptions,auditDefn.options);
-const auditContext={
-options:auditOptions,
-...sharedAuditContext};
-
-
-const product=await audit.audit(artifacts,auditContext);
-auditResult=Audit.generateAuditResult(audit,product);
-}catch(err){
-log.warn(audit.meta.id,`Caught exception: ${err.message}`);
-if(err.fatal){
-throw err;
-}
-
-Sentry.captureException(err,{tags:{audit:audit.meta.id},level:'error'});
-
-const errorMessage=err.friendlyMessage?
-`${err.friendlyMessage} (${err.message})`:
-`Audit error: ${err.message}`;
-auditResult=Audit.generateErrorAuditResult(audit,errorMessage);
-}
-
-log.verbose('statusEnd',status);
-return auditResult;
-}
-
-
-
-
-
-
-static getArtifactRuntimeError(artifacts){
-for(const possibleErrorArtifact of Object.values(artifacts)){
-if(possibleErrorArtifact instanceof LHError&&possibleErrorArtifact.lhrRuntimeError){
-const errorMessage=possibleErrorArtifact.friendlyMessage||possibleErrorArtifact.message;
-
-return{
-code:possibleErrorArtifact.code,
-message:errorMessage};
-
-}
-}
-
-return{
-code:LHError.NO_ERROR,
-message:''};
-
-}
-
-
-
-
-
-static getAuditList(){
-const ignoredFiles=[
-'audit.js',
-'violation-audit.js',
-'accessibility/axe-audit.js',
-'multi-check-audit.js',
-'byte-efficiency/byte-efficiency-audit.js',
-'manual/manual-audit.js'];
-
-
-const fileList=[
-...["accessibility","audit.js","bootup-time.js","byte-efficiency","content-width.js","critical-request-chains.js","deprecations.js","dobetterweb","errors-in-console.js","final-screenshot.js","font-display.js","image-aspect-ratio.js","is-on-https.js","load-fast-enough-for-pwa.js","mainthread-work-breakdown.js","manifest-short-name-length.js","manual","metrics","metrics.js","mixed-content.js","multi-check-audit.js","network-requests.js","predictive-perf.js","redirects-http.js","redirects.js","screenshot-thumbnails.js","seo","service-worker.js","splash-screen.js","themed-omnibox.js","time-to-first-byte.js","user-timings.js","uses-rel-preconnect.js","uses-rel-preload.js","viewport.js","violation-audit.js","webapp-install-banner.js","without-javascript.js","works-offline.js"],
-...["appcache-manifest.js","doctype.js","dom-size.js","external-anchors-use-rel-noopener.js","geolocation-on-start.js","js-libraries.js","no-document-write.js","no-vulnerable-libraries.js","no-websql.js","notification-on-start.js","password-inputs-can-be-pasted-into.js","uses-http2.js","uses-passive-event-listeners.js"].map(f=>`dobetterweb/${f}`),
-...["estimated-input-latency.js","first-contentful-paint.js","first-cpu-idle.js","first-meaningful-paint.js","interactive.js","speed-index.js"].map(f=>`metrics/${f}`),
-...["canonical.js","font-size.js","hreflang.js","http-status-code.js","is-crawlable.js","link-text.js","manual","meta-description.js","plugins.js","robots-txt.js"].map(f=>`seo/${f}`),
-...["mobile-friendly.js","structured-data.js"].map(f=>`seo/manual/${f}`),
-...["accesskeys.js","aria-allowed-attr.js","aria-required-attr.js","aria-required-children.js","aria-required-parent.js","aria-roles.js","aria-valid-attr-value.js","aria-valid-attr.js","audio-caption.js","axe-audit.js","button-name.js","bypass.js","color-contrast.js","definition-list.js","dlitem.js","document-title.js","duplicate-id.js","frame-title.js","html-has-lang.js","html-lang-valid.js","image-alt.js","input-image-alt.js","label.js","layout-table.js","link-name.js","list.js","listitem.js","manual","meta-refresh.js","meta-viewport.js","object-alt.js","tabindex.js","td-headers-attr.js","th-has-data-cells.js","valid-lang.js","video-caption.js","video-description.js"].
-map(f=>`accessibility/${f}`),
-...["custom-controls-labels.js","custom-controls-roles.js","focus-traps.js","focusable-controls.js","heading-levels.js","interactive-element-affordance.js","logical-tab-order.js","managed-focus.js","offscreen-content-hidden.js","use-landmarks.js","visual-order-follows-dom.js"].
-map(f=>`accessibility/manual/${f}`),
-...["byte-efficiency-audit.js","efficient-animated-content.js","offscreen-images.js","render-blocking-resources.js","total-byte-weight.js","unminified-css.js","unminified-javascript.js","unused-css-rules.js","unused-javascript.js","uses-long-cache-ttl.js","uses-optimized-images.js","uses-responsive-images.js","uses-text-compression.js","uses-webp-images.js"].
-map(f=>`byte-efficiency/${f}`),
-...["manual-audit.js","pwa-cross-browser.js","pwa-each-page-has-url.js","pwa-page-transitions.js"].map(f=>`manual/${f}`)];
-
-return fileList.filter(f=>{
-return /\.js$/.test(f)&&!ignoredFiles.includes(f);
-}).sort();
-}
-
-
-
-
-
-static getGathererList(){
-const fileList=[
-...["accessibility.js","cache-contents.js","chrome-console-messages.js","css-usage.js","dobetterweb","fonts.js","gatherer.js","html-without-javascript.js","http-redirect.js","image-usage.js","js-usage.js","manifest.js","mixed-content.js","offline.js","runtime-exceptions.js","scripts.js","seo","service-worker.js","start-url.js","theme-color.js","viewport-dimensions.js","viewport.js"],
-...["canonical.js","crawlable-links.js","embedded-content.js","font-size.js","hreflang.js","meta-description.js","meta-robots.js","robots-txt.js"].map(f=>`seo/${f}`),
-...["anchors-with-no-rel-noopener.js","appcache.js","doctype.js","domstats.js","js-libraries.js","optimized-images.js","password-inputs-with-prevented-paste.js","response-compression.js","tags-blocking-first-paint.js","websql.js"].
-map(f=>`dobetterweb/${f}`)];
-
-return fileList.filter(f=>/\.js$/.test(f)&&f!=='gatherer.js').sort();
-}
-
-
-
-
-
-static getComputedGathererList(){
-const filenamesToSkip=[
-'computed-artifact.js',
-'metrics',
-'metrics/lantern-metric.js',
-'metrics/metric.js',
-
-
-'new-computed-artifact.js',
-'manifest-values.js'];
-
-
-const fileList=[
-...["computed-artifact.js","critical-request-chains.js","load-simulator.js","main-resource.js","main-thread-tasks.js","manifest-values.js","metrics","network-analysis.js","network-records.js","network-throughput.js","new-computed-artifact.js","page-dependency-graph.js","pushed-requests.js","screenshots.js","speedline.js","trace-of-tab.js"],
-...["estimated-input-latency.js","first-contentful-paint.js","first-cpu-idle.js","first-meaningful-paint.js","interactive.js","lantern-estimated-input-latency.js","lantern-first-contentful-paint.js","lantern-first-cpu-idle.js","lantern-first-meaningful-paint.js","lantern-interactive.js","lantern-metric.js","lantern-speed-index.js","metric.js","speed-index.js"].map(f=>`metrics/${f}`)];
-
-
-return fileList.filter(f=>/\.js$/.test(f)&&!filenamesToSkip.includes(f)).sort();
-}
-
-
-
-
-
-static instantiateComputedArtifacts(){
-const computedArtifacts={};
-Runner.getComputedGathererList().forEach(function(filename){
-
-filename=filename.replace(/\.js$/,'');
-const ArtifactClass=require('./gather/computed/'+filename);
-const artifact=new ArtifactClass(computedArtifacts);
-
-
-computedArtifacts['request'+artifact.name]=artifact.request.bind(artifact);
-});
-
-return computedArtifacts;
-}
-
-
-
-
-
-
-
-
-
-
-
-static resolvePlugin(plugin,configDir,category){
-
-
-
-
-try{
-return require.resolve(plugin);
-}catch(e){}
-
-
-
-
-const cwdPath=path.resolve(process.cwd(),plugin);
-try{
-return require.resolve(cwdPath);
-}catch(e){}
-
-const errorString='Unable to locate '+(
-category?`${category}: `:'')+
-`${plugin} (tried to require() from '${__dirname}' and load from '${cwdPath}'`;
-
-if(!configDir){
-throw new Error(errorString+')');
-}
-
-
-
-
-const relativePath=path.resolve(configDir,plugin);
-try{
-return require.resolve(relativePath);
-}catch(requireError){}
-
-throw new Error(errorString+` and '${relativePath}')`);
-}
-
-
-
-
-
-
-static _getArtifactsPath(settings){
-const{auditMode,gatherMode}=settings;
-
-
-if(typeof auditMode==='string')return path.resolve(process.cwd(),auditMode);
-if(typeof gatherMode==='string')return path.resolve(process.cwd(),gatherMode);
-
-return path.join(process.cwd(),'latest-run');
-}}
-
-
-module.exports=Runner;
-
-}).call(this,require('_process'),"/../lighthouse-core");
-},{"../package.json":188,"./audits/audit":2,"./gather/driver.js":19,"./gather/gather-runner":20,"./lib/asset-saver":24,"./lib/i18n/i18n.js":36,"./lib/lh-error.js":85,"./lib/sentry":90,"./lib/url-shim":"url","./report/report-generator":98,"./scoring":100,"_process":126,"lighthouse-logger":147,"lodash.isequal":178,"path":124}],100:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audits/audit');
-
-
-
-
-
-
-const clampTo2Decimals=val=>Math.round(val*100)/100;
-
-class ReportScoring{
-
-
-
-
-
-static arithmeticMean(items){
-
-items=items.filter(item=>item.weight>0);
-
-if(items.some(item=>item.score===null))return null;
-
-const results=items.reduce(
-(result,item)=>{
-const score=item.score;
-const weight=item.weight;
-
-return{
-weight:result.weight+weight,
-sum:result.sum+score*weight};
-
-},
-{weight:0,sum:0});
-
-
-return clampTo2Decimals(results.sum/results.weight||0);
-}
-
-
-
-
-
-
-
-static scoreAllCategories(configCategories,resultsByAuditId){
-
-const scoredCategories={};
-
-for(const[categoryId,configCategory]of Object.entries(configCategories)){
-
-const auditRefs=configCategory.auditRefs.map(configMember=>{
-const member={...configMember};
-
-
-
-
-
-const result=resultsByAuditId[member.id];
-if(result.scoreDisplayMode===Audit.SCORING_MODES.NOT_APPLICABLE||
-result.scoreDisplayMode===Audit.SCORING_MODES.INFORMATIVE||
-result.scoreDisplayMode===Audit.SCORING_MODES.MANUAL){
-member.weight=0;
-}
-
-return member;
-});
-
-const scores=auditRefs.map(auditRef=>({
-score:resultsByAuditId[auditRef.id].score,
-weight:auditRef.weight}));
-
-const score=ReportScoring.arithmeticMean(scores);
-
-scoredCategories[categoryId]={
-...configCategory,
-auditRefs,
-id:categoryId,
-score};
-
-}
-
-return scoredCategories;
-}}
-
-
-module.exports=ReportScoring;
-
-},{"./audits/audit":2}],101:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const lighthouse=require('../../../lighthouse-core/index');
-const RawProtocol=require('../../../lighthouse-core/gather/connections/raw');
-const Config=require('../../../lighthouse-core/config/config');
-const defaultConfig=require('../../../lighthouse-core/config/default-config.js');
-const i18n=require('../../../lighthouse-core/lib/i18n/i18n.js');
-const log=require('lighthouse-logger');
-
-
-
-
-
-
-
-
-
-function getDefaultConfigForCategories(categoryIDs){
-return{
-extends:'lighthouse:default',
-settings:{
-onlyCategories:categoryIDs}};
-
-
-}
-
-
-
-
-
-
-
-
-function runLighthouseInWorker(port,url,flags,categoryIDs){
-
-flags.logLevel=flags.logLevel||'info';
-const config=getDefaultConfigForCategories(categoryIDs);
-const connection=new RawProtocol(port);
-
-return lighthouse(url,flags,config,connection);
-}
-
-
-
-
-
-function getDefaultCategories(){
-const categories=Config.getCategories(defaultConfig);
-categories.forEach(cat=>cat.title=i18n.getFormatted(cat.title,'en-US'));
-return categories;
-}
-
-
-function listenForStatus(listenCallback){
-log.events.addListener('status',listenCallback);
-}
-
-if(typeof module!=='undefined'&&module.exports){
-
-module.exports={
-getDefaultConfigForCategories,
-runLighthouseInWorker,
-getDefaultCategories,
-listenForStatus};
-
-}
-
-
-
-if(typeof self!=='undefined'&&self instanceof self.WorkerGlobalScope){
-
-self.runLighthouseInWorker=runLighthouseInWorker;
-
-self.listenForStatus=listenForStatus;
-}
-
-},{"../../../lighthouse-core/config/config":7,"../../../lighthouse-core/config/default-config.js":9,"../../../lighthouse-core/gather/connections/raw":17,"../../../lighthouse-core/index":22,"../../../lighthouse-core/lib/i18n/i18n.js":36,"lighthouse-logger":147}],102:[function(require,module,exports){
-(function(global){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-function compare(a,b){
-if(a===b){
-return 0;
-}
-
-var x=a.length;
-var y=b.length;
-
-for(var i=0,len=Math.min(x,y);i<len;++i){
-if(a[i]!==b[i]){
-x=a[i];
-y=b[i];
-break;
-}
-}
-
-if(x<y){
-return-1;
-}
-if(y<x){
-return 1;
-}
-return 0;
-}
-function isBuffer(b){
-if(global.Buffer&&typeof global.Buffer.isBuffer==='function'){
-return global.Buffer.isBuffer(b);
-}
-return!!(b!=null&&b._isBuffer);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var util=require('util/');
-var hasOwn=Object.prototype.hasOwnProperty;
-var pSlice=Array.prototype.slice;
-var functionsHaveNames=function(){
-return function foo(){}.name==='foo';
-}();
-function pToString(obj){
-return Object.prototype.toString.call(obj);
-}
-function isView(arrbuf){
-if(isBuffer(arrbuf)){
-return false;
-}
-if(typeof global.ArrayBuffer!=='function'){
-return false;
-}
-if(typeof ArrayBuffer.isView==='function'){
-return ArrayBuffer.isView(arrbuf);
-}
-if(!arrbuf){
-return false;
-}
-if(arrbuf instanceof DataView){
-return true;
-}
-if(arrbuf.buffer&&arrbuf.buffer instanceof ArrayBuffer){
-return true;
-}
-return false;
-}
-
-
-
-
-var assert=module.exports=ok;
-
-
-
-
-
-
-var regex=/\s*function\s+([^\(\s]*)\s*/;
-
-function getName(func){
-if(!util.isFunction(func)){
-return;
-}
-if(functionsHaveNames){
-return func.name;
-}
-var str=func.toString();
-var match=str.match(regex);
-return match&&match[1];
-}
-assert.AssertionError=function AssertionError(options){
-this.name='AssertionError';
-this.actual=options.actual;
-this.expected=options.expected;
-this.operator=options.operator;
-if(options.message){
-this.message=options.message;
-this.generatedMessage=false;
-}else{
-this.message=getMessage(this);
-this.generatedMessage=true;
-}
-var stackStartFunction=options.stackStartFunction||fail;
-if(Error.captureStackTrace){
-Error.captureStackTrace(this,stackStartFunction);
-}else{
-
-var err=new Error();
-if(err.stack){
-var out=err.stack;
-
-
-var fn_name=getName(stackStartFunction);
-var idx=out.indexOf('\n'+fn_name);
-if(idx>=0){
-
-
-var next_line=out.indexOf('\n',idx+1);
-out=out.substring(next_line+1);
-}
-
-this.stack=out;
-}
-}
-};
-
-
-util.inherits(assert.AssertionError,Error);
-
-function truncate(s,n){
-if(typeof s==='string'){
-return s.length<n?s:s.slice(0,n);
-}else{
-return s;
-}
-}
-function inspect(something){
-if(functionsHaveNames||!util.isFunction(something)){
-return util.inspect(something);
-}
-var rawname=getName(something);
-var name=rawname?': '+rawname:'';
-return'[Function'+name+']';
-}
-function getMessage(self){
-return truncate(inspect(self.actual),128)+' '+
-self.operator+' '+
-truncate(inspect(self.expected),128);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-function fail(actual,expected,message,operator,stackStartFunction){
-throw new assert.AssertionError({
-message:message,
-actual:actual,
-expected:expected,
-operator:operator,
-stackStartFunction:stackStartFunction});
-
-}
-
-
-assert.fail=fail;
-
-
-
-
-
-
-
-
-function ok(value,message){
-if(!value)fail(value,true,message,'==',assert.ok);
-}
-assert.ok=ok;
-
-
-
-
-
-assert.equal=function equal(actual,expected,message){
-if(actual!=expected)fail(actual,expected,message,'==',assert.equal);
-};
-
-
-
-
-assert.notEqual=function notEqual(actual,expected,message){
-if(actual==expected){
-fail(actual,expected,message,'!=',assert.notEqual);
-}
-};
-
-
-
-
-assert.deepEqual=function deepEqual(actual,expected,message){
-if(!_deepEqual(actual,expected,false)){
-fail(actual,expected,message,'deepEqual',assert.deepEqual);
-}
-};
-
-assert.deepStrictEqual=function deepStrictEqual(actual,expected,message){
-if(!_deepEqual(actual,expected,true)){
-fail(actual,expected,message,'deepStrictEqual',assert.deepStrictEqual);
-}
-};
-
-function _deepEqual(actual,expected,strict,memos){
-
-if(actual===expected){
-return true;
-}else if(isBuffer(actual)&&isBuffer(expected)){
-return compare(actual,expected)===0;
-
-
-
-}else if(util.isDate(actual)&&util.isDate(expected)){
-return actual.getTime()===expected.getTime();
-
-
-
-
-}else if(util.isRegExp(actual)&&util.isRegExp(expected)){
-return actual.source===expected.source&&
-actual.global===expected.global&&
-actual.multiline===expected.multiline&&
-actual.lastIndex===expected.lastIndex&&
-actual.ignoreCase===expected.ignoreCase;
-
-
-
-}else if((actual===null||typeof actual!=='object')&&(
-expected===null||typeof expected!=='object')){
-return strict?actual===expected:actual==expected;
-
-
-
-
-
-
-
-}else if(isView(actual)&&isView(expected)&&
-pToString(actual)===pToString(expected)&&
-!(actual instanceof Float32Array||
-actual instanceof Float64Array)){
-return compare(new Uint8Array(actual.buffer),
-new Uint8Array(expected.buffer))===0;
-
-
-
-
-
-
-
-}else if(isBuffer(actual)!==isBuffer(expected)){
-return false;
-}else{
-memos=memos||{actual:[],expected:[]};
-
-var actualIndex=memos.actual.indexOf(actual);
-if(actualIndex!==-1){
-if(actualIndex===memos.expected.indexOf(expected)){
-return true;
-}
-}
-
-memos.actual.push(actual);
-memos.expected.push(expected);
-
-return objEquiv(actual,expected,strict,memos);
-}
-}
-
-function isArguments(object){
-return Object.prototype.toString.call(object)=='[object Arguments]';
-}
-
-function objEquiv(a,b,strict,actualVisitedObjects){
-if(a===null||a===undefined||b===null||b===undefined)
-return false;
-
-if(util.isPrimitive(a)||util.isPrimitive(b))
-return a===b;
-if(strict&&Object.getPrototypeOf(a)!==Object.getPrototypeOf(b))
-return false;
-var aIsArgs=isArguments(a);
-var bIsArgs=isArguments(b);
-if(aIsArgs&&!bIsArgs||!aIsArgs&&bIsArgs)
-return false;
-if(aIsArgs){
-a=pSlice.call(a);
-b=pSlice.call(b);
-return _deepEqual(a,b,strict);
-}
-var ka=objectKeys(a);
-var kb=objectKeys(b);
-var key,i;
-
-
-if(ka.length!==kb.length)
-return false;
-
-ka.sort();
-kb.sort();
-
-for(i=ka.length-1;i>=0;i--){
-if(ka[i]!==kb[i])
-return false;
-}
-
-
-for(i=ka.length-1;i>=0;i--){
-key=ka[i];
-if(!_deepEqual(a[key],b[key],strict,actualVisitedObjects))
-return false;
-}
-return true;
-}
-
-
-
-
-assert.notDeepEqual=function notDeepEqual(actual,expected,message){
-if(_deepEqual(actual,expected,false)){
-fail(actual,expected,message,'notDeepEqual',assert.notDeepEqual);
-}
-};
-
-assert.notDeepStrictEqual=notDeepStrictEqual;
-function notDeepStrictEqual(actual,expected,message){
-if(_deepEqual(actual,expected,true)){
-fail(actual,expected,message,'notDeepStrictEqual',notDeepStrictEqual);
-}
-}
-
-
-
-
-
-assert.strictEqual=function strictEqual(actual,expected,message){
-if(actual!==expected){
-fail(actual,expected,message,'===',assert.strictEqual);
-}
-};
-
-
-
-
-assert.notStrictEqual=function notStrictEqual(actual,expected,message){
-if(actual===expected){
-fail(actual,expected,message,'!==',assert.notStrictEqual);
-}
-};
-
-function expectedException(actual,expected){
-if(!actual||!expected){
-return false;
-}
-
-if(Object.prototype.toString.call(expected)=='[object RegExp]'){
-return expected.test(actual);
-}
-
-try{
-if(actual instanceof expected){
-return true;
-}
-}catch(e){
-
-}
-
-if(Error.isPrototypeOf(expected)){
-return false;
-}
-
-return expected.call({},actual)===true;
-}
-
-function _tryBlock(block){
-var error;
-try{
-block();
-}catch(e){
-error=e;
-}
-return error;
-}
-
-function _throws(shouldThrow,block,expected,message){
-var actual;
-
-if(typeof block!=='function'){
-throw new TypeError('"block" argument must be a function');
-}
-
-if(typeof expected==='string'){
-message=expected;
-expected=null;
-}
-
-actual=_tryBlock(block);
-
-message=(expected&&expected.name?' ('+expected.name+').':'.')+(
-message?' '+message:'.');
-
-if(shouldThrow&&!actual){
-fail(actual,expected,'Missing expected exception'+message);
-}
-
-var userProvidedMessage=typeof message==='string';
-var isUnwantedException=!shouldThrow&&util.isError(actual);
-var isUnexpectedException=!shouldThrow&&actual&&!expected;
-
-if(isUnwantedException&&
-userProvidedMessage&&
-expectedException(actual,expected)||
-isUnexpectedException){
-fail(actual,expected,'Got unwanted exception'+message);
-}
-
-if(shouldThrow&&actual&&expected&&
-!expectedException(actual,expected)||!shouldThrow&&actual){
-throw actual;
-}
-}
-
-
-
-
-assert.throws=function(block,error,message){
-_throws(true,block,error,message);
-};
-
-
-assert.doesNotThrow=function(block,error,message){
-_throws(false,block,error,message);
-};
-
-assert.ifError=function(err){if(err)throw err;};
-
-var objectKeys=Object.keys||function(obj){
-var keys=[];
-for(var key in obj){
-if(hasOwn.call(obj,key))keys.push(key);
-}
-return keys;
-};
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"util/":146}],103:[function(require,module,exports){
-'use strict';
-
-exports.byteLength=byteLength;
-exports.toByteArray=toByteArray;
-exports.fromByteArray=fromByteArray;
-
-var lookup=[];
-var revLookup=[];
-var Arr=typeof Uint8Array!=='undefined'?Uint8Array:Array;
-
-var code='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-for(var i=0,len=code.length;i<len;++i){
-lookup[i]=code[i];
-revLookup[code.charCodeAt(i)]=i;
-}
-
-
-
-revLookup['-'.charCodeAt(0)]=62;
-revLookup['_'.charCodeAt(0)]=63;
-
-function getLens(b64){
-var len=b64.length;
-
-if(len%4>0){
-throw new Error('Invalid string. Length must be a multiple of 4');
-}
-
-
-
-var validLen=b64.indexOf('=');
-if(validLen===-1)validLen=len;
-
-var placeHoldersLen=validLen===len?
-0:
-4-validLen%4;
-
-return[validLen,placeHoldersLen];
-}
-
-
-function byteLength(b64){
-var lens=getLens(b64);
-var validLen=lens[0];
-var placeHoldersLen=lens[1];
-return(validLen+placeHoldersLen)*3/4-placeHoldersLen;
-}
-
-function _byteLength(b64,validLen,placeHoldersLen){
-return(validLen+placeHoldersLen)*3/4-placeHoldersLen;
-}
-
-function toByteArray(b64){
-var tmp;
-var lens=getLens(b64);
-var validLen=lens[0];
-var placeHoldersLen=lens[1];
-
-var arr=new Arr(_byteLength(b64,validLen,placeHoldersLen));
-
-var curByte=0;
-
-
-var len=placeHoldersLen>0?
-validLen-4:
-validLen;
-
-for(var i=0;i<len;i+=4){
-tmp=
-revLookup[b64.charCodeAt(i)]<<18|
-revLookup[b64.charCodeAt(i+1)]<<12|
-revLookup[b64.charCodeAt(i+2)]<<6|
-revLookup[b64.charCodeAt(i+3)];
-arr[curByte++]=tmp>>16&0xFF;
-arr[curByte++]=tmp>>8&0xFF;
-arr[curByte++]=tmp&0xFF;
-}
-
-if(placeHoldersLen===2){
-tmp=
-revLookup[b64.charCodeAt(i)]<<2|
-revLookup[b64.charCodeAt(i+1)]>>4;
-arr[curByte++]=tmp&0xFF;
-}
-
-if(placeHoldersLen===1){
-tmp=
-revLookup[b64.charCodeAt(i)]<<10|
-revLookup[b64.charCodeAt(i+1)]<<4|
-revLookup[b64.charCodeAt(i+2)]>>2;
-arr[curByte++]=tmp>>8&0xFF;
-arr[curByte++]=tmp&0xFF;
-}
-
-return arr;
-}
-
-function tripletToBase64(num){
-return lookup[num>>18&0x3F]+
-lookup[num>>12&0x3F]+
-lookup[num>>6&0x3F]+
-lookup[num&0x3F];
-}
-
-function encodeChunk(uint8,start,end){
-var tmp;
-var output=[];
-for(var i=start;i<end;i+=3){
-tmp=
-(uint8[i]<<16&0xFF0000)+(
-uint8[i+1]<<8&0xFF00)+(
-uint8[i+2]&0xFF);
-output.push(tripletToBase64(tmp));
-}
-return output.join('');
-}
-
-function fromByteArray(uint8){
-var tmp;
-var len=uint8.length;
-var extraBytes=len%3;
-var parts=[];
-var maxChunkLength=16383;
-
-
-for(var i=0,len2=len-extraBytes;i<len2;i+=maxChunkLength){
-parts.push(encodeChunk(
-uint8,i,i+maxChunkLength>len2?len2:i+maxChunkLength));
-
-}
-
-
-if(extraBytes===1){
-tmp=uint8[len-1];
-parts.push(
-lookup[tmp>>2]+
-lookup[tmp<<4&0x3F]+
-'==');
-
-}else if(extraBytes===2){
-tmp=(uint8[len-2]<<8)+uint8[len-1];
-parts.push(
-lookup[tmp>>10]+
-lookup[tmp>>4&0x3F]+
-lookup[tmp<<2&0x3F]+
-'=');
-
-}
-
-return parts.join('');
-}
-
-},{}],104:[function(require,module,exports){
-
-},{}],105:[function(require,module,exports){
-(function(process,Buffer){
-'use strict';
-
-
-var assert=require('assert');
-
-var Zstream=require('pako/lib/zlib/zstream');
-var zlib_deflate=require('pako/lib/zlib/deflate.js');
-var zlib_inflate=require('pako/lib/zlib/inflate.js');
-var constants=require('pako/lib/zlib/constants');
-
-for(var key in constants){
-exports[key]=constants[key];
-}
-
-
-exports.NONE=0;
-exports.DEFLATE=1;
-exports.INFLATE=2;
-exports.GZIP=3;
-exports.GUNZIP=4;
-exports.DEFLATERAW=5;
-exports.INFLATERAW=6;
-exports.UNZIP=7;
-
-var GZIP_HEADER_ID1=0x1f;
-var GZIP_HEADER_ID2=0x8b;
-
-
-
-
-function Zlib(mode){
-if(typeof mode!=='number'||mode<exports.DEFLATE||mode>exports.UNZIP){
-throw new TypeError('Bad argument');
-}
-
-this.dictionary=null;
-this.err=0;
-this.flush=0;
-this.init_done=false;
-this.level=0;
-this.memLevel=0;
-this.mode=mode;
-this.strategy=0;
-this.windowBits=0;
-this.write_in_progress=false;
-this.pending_close=false;
-this.gzip_id_bytes_read=0;
-}
-
-Zlib.prototype.close=function(){
-if(this.write_in_progress){
-this.pending_close=true;
-return;
-}
-
-this.pending_close=false;
-
-assert(this.init_done,'close before init');
-assert(this.mode<=exports.UNZIP);
-
-if(this.mode===exports.DEFLATE||this.mode===exports.GZIP||this.mode===exports.DEFLATERAW){
-zlib_deflate.deflateEnd(this.strm);
-}else if(this.mode===exports.INFLATE||this.mode===exports.GUNZIP||this.mode===exports.INFLATERAW||this.mode===exports.UNZIP){
-zlib_inflate.inflateEnd(this.strm);
-}
-
-this.mode=exports.NONE;
-
-this.dictionary=null;
-};
-
-Zlib.prototype.write=function(flush,input,in_off,in_len,out,out_off,out_len){
-return this._write(true,flush,input,in_off,in_len,out,out_off,out_len);
-};
-
-Zlib.prototype.writeSync=function(flush,input,in_off,in_len,out,out_off,out_len){
-return this._write(false,flush,input,in_off,in_len,out,out_off,out_len);
-};
-
-Zlib.prototype._write=function(async,flush,input,in_off,in_len,out,out_off,out_len){
-assert.equal(arguments.length,8);
-
-assert(this.init_done,'write before init');
-assert(this.mode!==exports.NONE,'already finalized');
-assert.equal(false,this.write_in_progress,'write already in progress');
-assert.equal(false,this.pending_close,'close is pending');
-
-this.write_in_progress=true;
-
-assert.equal(false,flush===undefined,'must provide flush value');
-
-this.write_in_progress=true;
-
-if(flush!==exports.Z_NO_FLUSH&&flush!==exports.Z_PARTIAL_FLUSH&&flush!==exports.Z_SYNC_FLUSH&&flush!==exports.Z_FULL_FLUSH&&flush!==exports.Z_FINISH&&flush!==exports.Z_BLOCK){
-throw new Error('Invalid flush value');
-}
-
-if(input==null){
-input=Buffer.alloc(0);
-in_len=0;
-in_off=0;
-}
-
-this.strm.avail_in=in_len;
-this.strm.input=input;
-this.strm.next_in=in_off;
-this.strm.avail_out=out_len;
-this.strm.output=out;
-this.strm.next_out=out_off;
-this.flush=flush;
-
-if(!async){
-
-this._process();
-
-if(this._checkError()){
-return this._afterSync();
-}
-return;
-}
-
-
-var self=this;
-process.nextTick(function(){
-self._process();
-self._after();
-});
-
-return this;
-};
-
-Zlib.prototype._afterSync=function(){
-var avail_out=this.strm.avail_out;
-var avail_in=this.strm.avail_in;
-
-this.write_in_progress=false;
-
-return[avail_in,avail_out];
-};
-
-Zlib.prototype._process=function(){
-var next_expected_header_byte=null;
-
-
-
-
-switch(this.mode){
-case exports.DEFLATE:
-case exports.GZIP:
-case exports.DEFLATERAW:
-this.err=zlib_deflate.deflate(this.strm,this.flush);
-break;
-case exports.UNZIP:
-if(this.strm.avail_in>0){
-next_expected_header_byte=this.strm.next_in;
-}
-
-switch(this.gzip_id_bytes_read){
-case 0:
-if(next_expected_header_byte===null){
-break;
-}
-
-if(this.strm.input[next_expected_header_byte]===GZIP_HEADER_ID1){
-this.gzip_id_bytes_read=1;
-next_expected_header_byte++;
-
-if(this.strm.avail_in===1){
-
-break;
-}
-}else{
-this.mode=exports.INFLATE;
-break;
-}
-
-
-case 1:
-if(next_expected_header_byte===null){
-break;
-}
-
-if(this.strm.input[next_expected_header_byte]===GZIP_HEADER_ID2){
-this.gzip_id_bytes_read=2;
-this.mode=exports.GUNZIP;
-}else{
-
-
-this.mode=exports.INFLATE;
-}
-
-break;
-default:
-throw new Error('invalid number of gzip magic number bytes read');}
-
-
-
-case exports.INFLATE:
-case exports.GUNZIP:
-case exports.INFLATERAW:
-this.err=zlib_inflate.inflate(this.strm,this.flush);
-
-
-if(this.err===exports.Z_NEED_DICT&&this.dictionary){
-
-this.err=zlib_inflate.inflateSetDictionary(this.strm,this.dictionary);
-if(this.err===exports.Z_OK){
-
-this.err=zlib_inflate.inflate(this.strm,this.flush);
-}else if(this.err===exports.Z_DATA_ERROR){
-
-
-
-this.err=exports.Z_NEED_DICT;
-}
-}
-while(this.strm.avail_in>0&&this.mode===exports.GUNZIP&&this.err===exports.Z_STREAM_END&&this.strm.next_in[0]!==0x00){
-
-
-
-
-
-this.reset();
-this.err=zlib_inflate.inflate(this.strm,this.flush);
-}
-break;
-default:
-throw new Error('Unknown mode '+this.mode);}
-
-};
-
-Zlib.prototype._checkError=function(){
-
-switch(this.err){
-case exports.Z_OK:
-case exports.Z_BUF_ERROR:
-if(this.strm.avail_out!==0&&this.flush===exports.Z_FINISH){
-this._error('unexpected end of file');
-return false;
-}
-break;
-case exports.Z_STREAM_END:
-
-break;
-case exports.Z_NEED_DICT:
-if(this.dictionary==null){
-this._error('Missing dictionary');
-}else{
-this._error('Bad dictionary');
-}
-return false;
-default:
-
-this._error('Zlib error');
-return false;}
-
-
-return true;
-};
-
-Zlib.prototype._after=function(){
-if(!this._checkError()){
-return;
-}
-
-var avail_out=this.strm.avail_out;
-var avail_in=this.strm.avail_in;
-
-this.write_in_progress=false;
-
-
-this.callback(avail_in,avail_out);
-
-if(this.pending_close){
-this.close();
-}
-};
-
-Zlib.prototype._error=function(message){
-if(this.strm.msg){
-message=this.strm.msg;
-}
-this.onerror(message,this.err);
-
-
-this.write_in_progress=false;
-if(this.pending_close){
-this.close();
-}
-};
-
-Zlib.prototype.init=function(windowBits,level,memLevel,strategy,dictionary){
-assert(arguments.length===4||arguments.length===5,'init(windowBits, level, memLevel, strategy, [dictionary])');
-
-assert(windowBits>=8&&windowBits<=15,'invalid windowBits');
-assert(level>=-1&&level<=9,'invalid compression level');
-
-assert(memLevel>=1&&memLevel<=9,'invalid memlevel');
-
-assert(strategy===exports.Z_FILTERED||strategy===exports.Z_HUFFMAN_ONLY||strategy===exports.Z_RLE||strategy===exports.Z_FIXED||strategy===exports.Z_DEFAULT_STRATEGY,'invalid strategy');
-
-this._init(level,windowBits,memLevel,strategy,dictionary);
-this._setDictionary();
-};
-
-Zlib.prototype.params=function(){
-throw new Error('deflateParams Not supported');
-};
-
-Zlib.prototype.reset=function(){
-this._reset();
-this._setDictionary();
-};
-
-Zlib.prototype._init=function(level,windowBits,memLevel,strategy,dictionary){
-this.level=level;
-this.windowBits=windowBits;
-this.memLevel=memLevel;
-this.strategy=strategy;
-
-this.flush=exports.Z_NO_FLUSH;
-
-this.err=exports.Z_OK;
-
-if(this.mode===exports.GZIP||this.mode===exports.GUNZIP){
-this.windowBits+=16;
-}
-
-if(this.mode===exports.UNZIP){
-this.windowBits+=32;
-}
-
-if(this.mode===exports.DEFLATERAW||this.mode===exports.INFLATERAW){
-this.windowBits=-1*this.windowBits;
-}
-
-this.strm=new Zstream();
-
-switch(this.mode){
-case exports.DEFLATE:
-case exports.GZIP:
-case exports.DEFLATERAW:
-this.err=zlib_deflate.deflateInit2(this.strm,this.level,exports.Z_DEFLATED,this.windowBits,this.memLevel,this.strategy);
-break;
-case exports.INFLATE:
-case exports.GUNZIP:
-case exports.INFLATERAW:
-case exports.UNZIP:
-this.err=zlib_inflate.inflateInit2(this.strm,this.windowBits);
-break;
-default:
-throw new Error('Unknown mode '+this.mode);}
-
-
-if(this.err!==exports.Z_OK){
-this._error('Init error');
-}
-
-this.dictionary=dictionary;
-
-this.write_in_progress=false;
-this.init_done=true;
-};
-
-Zlib.prototype._setDictionary=function(){
-if(this.dictionary==null){
-return;
-}
-
-this.err=exports.Z_OK;
-
-switch(this.mode){
-case exports.DEFLATE:
-case exports.DEFLATERAW:
-this.err=zlib_deflate.deflateSetDictionary(this.strm,this.dictionary);
-break;
-default:
-break;}
-
-
-if(this.err!==exports.Z_OK){
-this._error('Failed to set dictionary');
-}
-};
-
-Zlib.prototype._reset=function(){
-this.err=exports.Z_OK;
-
-switch(this.mode){
-case exports.DEFLATE:
-case exports.DEFLATERAW:
-case exports.GZIP:
-this.err=zlib_deflate.deflateReset(this.strm);
-break;
-case exports.INFLATE:
-case exports.INFLATERAW:
-case exports.GUNZIP:
-this.err=zlib_inflate.inflateReset(this.strm);
-break;
-default:
-break;}
-
-
-if(this.err!==exports.Z_OK){
-this._error('Failed to reset stream');
-}
-};
-
-exports.Zlib=Zlib;
-}).call(this,require('_process'),require("buffer").Buffer);
-},{"_process":126,"assert":102,"buffer":109,"pako/lib/zlib/constants":118,"pako/lib/zlib/deflate.js":120,"pako/lib/zlib/inflate.js":107,"pako/lib/zlib/zstream":123}],106:[function(require,module,exports){
-(function(process){
-'use strict';
-
-var Buffer=require('buffer').Buffer;
-var Transform=require('stream').Transform;
-var binding=require('./binding');
-var util=require('util');
-var assert=require('assert').ok;
-var kMaxLength=require('buffer').kMaxLength;
-var kRangeErrorMessage='Cannot create final Buffer. It would be larger '+'than 0x'+kMaxLength.toString(16)+' bytes';
-
-
-
-binding.Z_MIN_WINDOWBITS=8;
-binding.Z_MAX_WINDOWBITS=15;
-binding.Z_DEFAULT_WINDOWBITS=15;
-
-
-
-
-binding.Z_MIN_CHUNK=64;
-binding.Z_MAX_CHUNK=Infinity;
-binding.Z_DEFAULT_CHUNK=16*1024;
-
-binding.Z_MIN_MEMLEVEL=1;
-binding.Z_MAX_MEMLEVEL=9;
-binding.Z_DEFAULT_MEMLEVEL=8;
-
-binding.Z_MIN_LEVEL=-1;
-binding.Z_MAX_LEVEL=9;
-binding.Z_DEFAULT_LEVEL=binding.Z_DEFAULT_COMPRESSION;
-
-
-var bkeys=Object.keys(binding);
-for(var bk=0;bk<bkeys.length;bk++){
-var bkey=bkeys[bk];
-if(bkey.match(/^Z/)){
-Object.defineProperty(exports,bkey,{
-enumerable:true,value:binding[bkey],writable:false});
-
-}
-}
-
-
-var codes={
-Z_OK:binding.Z_OK,
-Z_STREAM_END:binding.Z_STREAM_END,
-Z_NEED_DICT:binding.Z_NEED_DICT,
-Z_ERRNO:binding.Z_ERRNO,
-Z_STREAM_ERROR:binding.Z_STREAM_ERROR,
-Z_DATA_ERROR:binding.Z_DATA_ERROR,
-Z_MEM_ERROR:binding.Z_MEM_ERROR,
-Z_BUF_ERROR:binding.Z_BUF_ERROR,
-Z_VERSION_ERROR:binding.Z_VERSION_ERROR};
-
-
-var ckeys=Object.keys(codes);
-for(var ck=0;ck<ckeys.length;ck++){
-var ckey=ckeys[ck];
-codes[codes[ckey]]=ckey;
-}
-
-Object.defineProperty(exports,'codes',{
-enumerable:true,value:Object.freeze(codes),writable:false});
-
-
-exports.Deflate=Deflate;
-exports.Inflate=Inflate;
-exports.Gzip=Gzip;
-exports.Gunzip=Gunzip;
-exports.DeflateRaw=DeflateRaw;
-exports.InflateRaw=InflateRaw;
-exports.Unzip=Unzip;
-
-exports.createDeflate=function(o){
-return new Deflate(o);
-};
-
-exports.createInflate=function(o){
-return new Inflate(o);
-};
-
-exports.createDeflateRaw=function(o){
-return new DeflateRaw(o);
-};
-
-exports.createInflateRaw=function(o){
-return new InflateRaw(o);
-};
-
-exports.createGzip=function(o){
-return new Gzip(o);
-};
-
-exports.createGunzip=function(o){
-return new Gunzip(o);
-};
-
-exports.createUnzip=function(o){
-return new Unzip(o);
-};
-
-
-
-exports.deflate=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new Deflate(opts),buffer,callback);
-};
-
-exports.deflateSync=function(buffer,opts){
-return zlibBufferSync(new Deflate(opts),buffer);
-};
-
-exports.gzip=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new Gzip(opts),buffer,callback);
-};
-
-exports.gzipSync=function(buffer,opts){
-return zlibBufferSync(new Gzip(opts),buffer);
-};
-
-exports.deflateRaw=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new DeflateRaw(opts),buffer,callback);
-};
-
-exports.deflateRawSync=function(buffer,opts){
-return zlibBufferSync(new DeflateRaw(opts),buffer);
-};
-
-exports.unzip=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new Unzip(opts),buffer,callback);
-};
-
-exports.unzipSync=function(buffer,opts){
-return zlibBufferSync(new Unzip(opts),buffer);
-};
-
-exports.inflate=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new Inflate(opts),buffer,callback);
-};
-
-exports.inflateSync=function(buffer,opts){
-return zlibBufferSync(new Inflate(opts),buffer);
-};
-
-exports.gunzip=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new Gunzip(opts),buffer,callback);
-};
-
-exports.gunzipSync=function(buffer,opts){
-return zlibBufferSync(new Gunzip(opts),buffer);
-};
-
-exports.inflateRaw=function(buffer,opts,callback){
-if(typeof opts==='function'){
-callback=opts;
-opts={};
-}
-return zlibBuffer(new InflateRaw(opts),buffer,callback);
-};
-
-exports.inflateRawSync=function(buffer,opts){
-return zlibBufferSync(new InflateRaw(opts),buffer);
-};
-
-function zlibBuffer(engine,buffer,callback){
-var buffers=[];
-var nread=0;
-
-engine.on('error',onError);
-engine.on('end',onEnd);
-
-engine.end(buffer);
-flow();
-
-function flow(){
-var chunk;
-while(null!==(chunk=engine.read())){
-buffers.push(chunk);
-nread+=chunk.length;
-}
-engine.once('readable',flow);
-}
-
-function onError(err){
-engine.removeListener('end',onEnd);
-engine.removeListener('readable',flow);
-callback(err);
-}
-
-function onEnd(){
-var buf;
-var err=null;
-
-if(nread>=kMaxLength){
-err=new RangeError(kRangeErrorMessage);
-}else{
-buf=Buffer.concat(buffers,nread);
-}
-
-buffers=[];
-engine.close();
-callback(err,buf);
-}
-}
-
-function zlibBufferSync(engine,buffer){
-if(typeof buffer==='string')buffer=Buffer.from(buffer);
-
-if(!Buffer.isBuffer(buffer))throw new TypeError('Not a string or buffer');
-
-var flushFlag=engine._finishFlushFlag;
-
-return engine._processChunk(buffer,flushFlag);
-}
-
-
-
-function Deflate(opts){
-if(!(this instanceof Deflate))return new Deflate(opts);
-Zlib.call(this,opts,binding.DEFLATE);
-}
-
-function Inflate(opts){
-if(!(this instanceof Inflate))return new Inflate(opts);
-Zlib.call(this,opts,binding.INFLATE);
-}
-
-
-function Gzip(opts){
-if(!(this instanceof Gzip))return new Gzip(opts);
-Zlib.call(this,opts,binding.GZIP);
-}
-
-function Gunzip(opts){
-if(!(this instanceof Gunzip))return new Gunzip(opts);
-Zlib.call(this,opts,binding.GUNZIP);
-}
-
-
-function DeflateRaw(opts){
-if(!(this instanceof DeflateRaw))return new DeflateRaw(opts);
-Zlib.call(this,opts,binding.DEFLATERAW);
-}
-
-function InflateRaw(opts){
-if(!(this instanceof InflateRaw))return new InflateRaw(opts);
-Zlib.call(this,opts,binding.INFLATERAW);
-}
-
-
-function Unzip(opts){
-if(!(this instanceof Unzip))return new Unzip(opts);
-Zlib.call(this,opts,binding.UNZIP);
-}
-
-function isValidFlushFlag(flag){
-return flag===binding.Z_NO_FLUSH||flag===binding.Z_PARTIAL_FLUSH||flag===binding.Z_SYNC_FLUSH||flag===binding.Z_FULL_FLUSH||flag===binding.Z_FINISH||flag===binding.Z_BLOCK;
-}
-
-
-
-
-
-
-function Zlib(opts,mode){
-var _this=this;
-
-this._opts=opts=opts||{};
-this._chunkSize=opts.chunkSize||exports.Z_DEFAULT_CHUNK;
-
-Transform.call(this,opts);
-
-if(opts.flush&&!isValidFlushFlag(opts.flush)){
-throw new Error('Invalid flush flag: '+opts.flush);
-}
-if(opts.finishFlush&&!isValidFlushFlag(opts.finishFlush)){
-throw new Error('Invalid flush flag: '+opts.finishFlush);
-}
-
-this._flushFlag=opts.flush||binding.Z_NO_FLUSH;
-this._finishFlushFlag=typeof opts.finishFlush!=='undefined'?opts.finishFlush:binding.Z_FINISH;
-
-if(opts.chunkSize){
-if(opts.chunkSize<exports.Z_MIN_CHUNK||opts.chunkSize>exports.Z_MAX_CHUNK){
-throw new Error('Invalid chunk size: '+opts.chunkSize);
-}
-}
-
-if(opts.windowBits){
-if(opts.windowBits<exports.Z_MIN_WINDOWBITS||opts.windowBits>exports.Z_MAX_WINDOWBITS){
-throw new Error('Invalid windowBits: '+opts.windowBits);
-}
-}
-
-if(opts.level){
-if(opts.level<exports.Z_MIN_LEVEL||opts.level>exports.Z_MAX_LEVEL){
-throw new Error('Invalid compression level: '+opts.level);
-}
-}
-
-if(opts.memLevel){
-if(opts.memLevel<exports.Z_MIN_MEMLEVEL||opts.memLevel>exports.Z_MAX_MEMLEVEL){
-throw new Error('Invalid memLevel: '+opts.memLevel);
-}
-}
-
-if(opts.strategy){
-if(opts.strategy!=exports.Z_FILTERED&&opts.strategy!=exports.Z_HUFFMAN_ONLY&&opts.strategy!=exports.Z_RLE&&opts.strategy!=exports.Z_FIXED&&opts.strategy!=exports.Z_DEFAULT_STRATEGY){
-throw new Error('Invalid strategy: '+opts.strategy);
-}
-}
-
-if(opts.dictionary){
-if(!Buffer.isBuffer(opts.dictionary)){
-throw new Error('Invalid dictionary: it should be a Buffer instance');
-}
-}
-
-this._handle=new binding.Zlib(mode);
-
-var self=this;
-this._hadError=false;
-this._handle.onerror=function(message,errno){
-
-
-_close(self);
-self._hadError=true;
-
-var error=new Error(message);
-error.errno=errno;
-error.code=exports.codes[errno];
-self.emit('error',error);
-};
-
-var level=exports.Z_DEFAULT_COMPRESSION;
-if(typeof opts.level==='number')level=opts.level;
-
-var strategy=exports.Z_DEFAULT_STRATEGY;
-if(typeof opts.strategy==='number')strategy=opts.strategy;
-
-this._handle.init(opts.windowBits||exports.Z_DEFAULT_WINDOWBITS,level,opts.memLevel||exports.Z_DEFAULT_MEMLEVEL,strategy,opts.dictionary);
-
-this._buffer=Buffer.allocUnsafe(this._chunkSize);
-this._offset=0;
-this._level=level;
-this._strategy=strategy;
-
-this.once('end',this.close);
-
-Object.defineProperty(this,'_closed',{
-get:function(){
-return!_this._handle;
-},
-configurable:true,
-enumerable:true});
-
-}
-
-util.inherits(Zlib,Transform);
-
-Zlib.prototype.params=function(level,strategy,callback){
-if(level<exports.Z_MIN_LEVEL||level>exports.Z_MAX_LEVEL){
-throw new RangeError('Invalid compression level: '+level);
-}
-if(strategy!=exports.Z_FILTERED&&strategy!=exports.Z_HUFFMAN_ONLY&&strategy!=exports.Z_RLE&&strategy!=exports.Z_FIXED&&strategy!=exports.Z_DEFAULT_STRATEGY){
-throw new TypeError('Invalid strategy: '+strategy);
-}
-
-if(this._level!==level||this._strategy!==strategy){
-var self=this;
-this.flush(binding.Z_SYNC_FLUSH,function(){
-assert(self._handle,'zlib binding closed');
-self._handle.params(level,strategy);
-if(!self._hadError){
-self._level=level;
-self._strategy=strategy;
-if(callback)callback();
-}
-});
-}else{
-process.nextTick(callback);
-}
-};
-
-Zlib.prototype.reset=function(){
-assert(this._handle,'zlib binding closed');
-return this._handle.reset();
-};
-
-
-
-Zlib.prototype._flush=function(callback){
-this._transform(Buffer.alloc(0),'',callback);
-};
-
-Zlib.prototype.flush=function(kind,callback){
-var _this2=this;
-
-var ws=this._writableState;
-
-if(typeof kind==='function'||kind===undefined&&!callback){
-callback=kind;
-kind=binding.Z_FULL_FLUSH;
-}
-
-if(ws.ended){
-if(callback)process.nextTick(callback);
-}else if(ws.ending){
-if(callback)this.once('end',callback);
-}else if(ws.needDrain){
-if(callback){
-this.once('drain',function(){
-return _this2.flush(kind,callback);
-});
-}
-}else{
-this._flushFlag=kind;
-this.write(Buffer.alloc(0),'',callback);
-}
-};
-
-Zlib.prototype.close=function(callback){
-_close(this,callback);
-process.nextTick(emitCloseNT,this);
-};
-
-function _close(engine,callback){
-if(callback)process.nextTick(callback);
-
-
-if(!engine._handle)return;
-
-engine._handle.close();
-engine._handle=null;
-}
-
-function emitCloseNT(self){
-self.emit('close');
-}
-
-Zlib.prototype._transform=function(chunk,encoding,cb){
-var flushFlag;
-var ws=this._writableState;
-var ending=ws.ending||ws.ended;
-var last=ending&&(!chunk||ws.length===chunk.length);
-
-if(chunk!==null&&!Buffer.isBuffer(chunk))return cb(new Error('invalid input'));
-
-if(!this._handle)return cb(new Error('zlib binding closed'));
-
-
-
-
-
-
-if(last)flushFlag=this._finishFlushFlag;else{
-flushFlag=this._flushFlag;
-
-
-if(chunk.length>=ws.length){
-this._flushFlag=this._opts.flush||binding.Z_NO_FLUSH;
-}
-}
-
-this._processChunk(chunk,flushFlag,cb);
-};
-
-Zlib.prototype._processChunk=function(chunk,flushFlag,cb){
-var availInBefore=chunk&&chunk.length;
-var availOutBefore=this._chunkSize-this._offset;
-var inOff=0;
-
-var self=this;
-
-var async=typeof cb==='function';
-
-if(!async){
-var buffers=[];
-var nread=0;
-
-var error;
-this.on('error',function(er){
-error=er;
-});
-
-assert(this._handle,'zlib binding closed');
-do{
-var res=this._handle.writeSync(flushFlag,chunk,
-inOff,
-availInBefore,
-this._buffer,
-this._offset,
-availOutBefore);
-}while(!this._hadError&&callback(res[0],res[1]));
-
-if(this._hadError){
-throw error;
-}
-
-if(nread>=kMaxLength){
-_close(this);
-throw new RangeError(kRangeErrorMessage);
-}
-
-var buf=Buffer.concat(buffers,nread);
-_close(this);
-
-return buf;
-}
-
-assert(this._handle,'zlib binding closed');
-var req=this._handle.write(flushFlag,chunk,
-inOff,
-availInBefore,
-this._buffer,
-this._offset,
-availOutBefore);
-
-req.buffer=chunk;
-req.callback=callback;
-
-function callback(availInAfter,availOutAfter){
-
-
-
-
-
-if(this){
-this.buffer=null;
-this.callback=null;
-}
-
-if(self._hadError)return;
-
-var have=availOutBefore-availOutAfter;
-assert(have>=0,'have should not go down');
-
-if(have>0){
-var out=self._buffer.slice(self._offset,self._offset+have);
-self._offset+=have;
-
-if(async){
-self.push(out);
-}else{
-buffers.push(out);
-nread+=out.length;
-}
-}
-
-
-if(availOutAfter===0||self._offset>=self._chunkSize){
-availOutBefore=self._chunkSize;
-self._offset=0;
-self._buffer=Buffer.allocUnsafe(self._chunkSize);
-}
-
-if(availOutAfter===0){
-
-
-
-
-inOff+=availInBefore-availInAfter;
-availInBefore=availInAfter;
-
-if(!async)return true;
-
-var newReq=self._handle.write(flushFlag,chunk,inOff,availInBefore,self._buffer,self._offset,self._chunkSize);
-newReq.callback=callback;
-newReq.buffer=chunk;
-return;
-}
-
-if(!async)return false;
-
-
-cb();
-}
-};
-
-util.inherits(Deflate,Zlib);
-util.inherits(Inflate,Zlib);
-util.inherits(Gzip,Zlib);
-util.inherits(Gunzip,Zlib);
-util.inherits(DeflateRaw,Zlib);
-util.inherits(InflateRaw,Zlib);
-util.inherits(Unzip,Zlib);
-}).call(this,require('_process'));
-},{"./binding":105,"_process":126,"assert":102,"buffer":109,"stream":141,"util":146}],107:[function(require,module,exports){
-arguments[4][104][0].apply(exports,arguments);
-},{"dup":104}],108:[function(require,module,exports){
-(function(global){
-'use strict';
-
-var buffer=require('buffer');
-var Buffer=buffer.Buffer;
-var SlowBuffer=buffer.SlowBuffer;
-var MAX_LEN=buffer.kMaxLength||2147483647;
-exports.alloc=function alloc(size,fill,encoding){
-if(typeof Buffer.alloc==='function'){
-return Buffer.alloc(size,fill,encoding);
-}
-if(typeof encoding==='number'){
-throw new TypeError('encoding must not be number');
-}
-if(typeof size!=='number'){
-throw new TypeError('size must be a number');
-}
-if(size>MAX_LEN){
-throw new RangeError('size is too large');
-}
-var enc=encoding;
-var _fill=fill;
-if(_fill===undefined){
-enc=undefined;
-_fill=0;
-}
-var buf=new Buffer(size);
-if(typeof _fill==='string'){
-var fillBuf=new Buffer(_fill,enc);
-var flen=fillBuf.length;
-var i=-1;
-while(++i<size){
-buf[i]=fillBuf[i%flen];
-}
-}else{
-buf.fill(_fill);
-}
-return buf;
-};
-exports.allocUnsafe=function allocUnsafe(size){
-if(typeof Buffer.allocUnsafe==='function'){
-return Buffer.allocUnsafe(size);
-}
-if(typeof size!=='number'){
-throw new TypeError('size must be a number');
-}
-if(size>MAX_LEN){
-throw new RangeError('size is too large');
-}
-return new Buffer(size);
-};
-exports.from=function from(value,encodingOrOffset,length){
-if(typeof Buffer.from==='function'&&(!global.Uint8Array||Uint8Array.from!==Buffer.from)){
-return Buffer.from(value,encodingOrOffset,length);
-}
-if(typeof value==='number'){
-throw new TypeError('"value" argument must not be a number');
-}
-if(typeof value==='string'){
-return new Buffer(value,encodingOrOffset);
-}
-if(typeof ArrayBuffer!=='undefined'&&value instanceof ArrayBuffer){
-var offset=encodingOrOffset;
-if(arguments.length===1){
-return new Buffer(value);
-}
-if(typeof offset==='undefined'){
-offset=0;
-}
-var len=length;
-if(typeof len==='undefined'){
-len=value.byteLength-offset;
-}
-if(offset>=value.byteLength){
-throw new RangeError('\'offset\' is out of bounds');
-}
-if(len>value.byteLength-offset){
-throw new RangeError('\'length\' is out of bounds');
-}
-return new Buffer(value.slice(offset,offset+len));
-}
-if(Buffer.isBuffer(value)){
-var out=new Buffer(value.length);
-value.copy(out,0,0,value.length);
-return out;
-}
-if(value){
-if(Array.isArray(value)||typeof ArrayBuffer!=='undefined'&&value.buffer instanceof ArrayBuffer||'length'in value){
-return new Buffer(value);
-}
-if(value.type==='Buffer'&&Array.isArray(value.data)){
-return new Buffer(value.data);
-}
-}
-
-throw new TypeError('First argument must be a string, Buffer, '+'ArrayBuffer, Array, or array-like object.');
-};
-exports.allocUnsafeSlow=function allocUnsafeSlow(size){
-if(typeof Buffer.allocUnsafeSlow==='function'){
-return Buffer.allocUnsafeSlow(size);
-}
-if(typeof size!=='number'){
-throw new TypeError('size must be a number');
-}
-if(size>=MAX_LEN){
-throw new RangeError('size is too large');
-}
-return new SlowBuffer(size);
-};
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"buffer":109}],109:[function(require,module,exports){
-
-
-
-
-
-
-
-
-'use strict';
-
-var base64=require('base64-js');
-var ieee754=require('ieee754');
-
-exports.Buffer=Buffer;
-exports.SlowBuffer=SlowBuffer;
-exports.INSPECT_MAX_BYTES=50;
-
-var K_MAX_LENGTH=0x7fffffff;
-exports.kMaxLength=K_MAX_LENGTH;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Buffer.TYPED_ARRAY_SUPPORT=typedArraySupport();
-
-if(!Buffer.TYPED_ARRAY_SUPPORT&&typeof console!=='undefined'&&
-typeof console.error==='function'){
-console.error(
-'This browser lacks typed array (Uint8Array) support which is required by '+
-'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.');
-
-}
-
-function typedArraySupport(){
-
-try{
-var arr=new Uint8Array(1);
-arr.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42;}};
-return arr.foo()===42;
-}catch(e){
-return false;
-}
-}
-
-Object.defineProperty(Buffer.prototype,'parent',{
-get:function(){
-if(!(this instanceof Buffer)){
-return undefined;
-}
-return this.buffer;
-}});
-
-
-Object.defineProperty(Buffer.prototype,'offset',{
-get:function(){
-if(!(this instanceof Buffer)){
-return undefined;
-}
-return this.byteOffset;
-}});
-
-
-function createBuffer(length){
-if(length>K_MAX_LENGTH){
-throw new RangeError('Invalid typed array length');
-}
-
-var buf=new Uint8Array(length);
-buf.__proto__=Buffer.prototype;
-return buf;
-}
-
-
-
-
-
-
-
-
-
-
-
-function Buffer(arg,encodingOrOffset,length){
-
-if(typeof arg==='number'){
-if(typeof encodingOrOffset==='string'){
-throw new Error(
-'If encoding is specified then the first argument must be a string');
-
-}
-return allocUnsafe(arg);
-}
-return from(arg,encodingOrOffset,length);
-}
-
-
-if(typeof Symbol!=='undefined'&&Symbol.species&&
-Buffer[Symbol.species]===Buffer){
-Object.defineProperty(Buffer,Symbol.species,{
-value:null,
-configurable:true,
-enumerable:false,
-writable:false});
-
-}
-
-Buffer.poolSize=8192;
-
-function from(value,encodingOrOffset,length){
-if(typeof value==='number'){
-throw new TypeError('"value" argument must not be a number');
-}
-
-if(isArrayBuffer(value)||value&&isArrayBuffer(value.buffer)){
-return fromArrayBuffer(value,encodingOrOffset,length);
-}
-
-if(typeof value==='string'){
-return fromString(value,encodingOrOffset);
-}
-
-return fromObject(value);
-}
-
-
-
-
-
-
-
-
-
-Buffer.from=function(value,encodingOrOffset,length){
-return from(value,encodingOrOffset,length);
-};
-
-
-
-Buffer.prototype.__proto__=Uint8Array.prototype;
-Buffer.__proto__=Uint8Array;
-
-function assertSize(size){
-if(typeof size!=='number'){
-throw new TypeError('"size" argument must be of type number');
-}else if(size<0){
-throw new RangeError('"size" argument must not be negative');
-}
-}
-
-function alloc(size,fill,encoding){
-assertSize(size);
-if(size<=0){
-return createBuffer(size);
-}
-if(fill!==undefined){
-
-
-
-return typeof encoding==='string'?
-createBuffer(size).fill(fill,encoding):
-createBuffer(size).fill(fill);
-}
-return createBuffer(size);
-}
-
-
-
-
-
-Buffer.alloc=function(size,fill,encoding){
-return alloc(size,fill,encoding);
-};
-
-function allocUnsafe(size){
-assertSize(size);
-return createBuffer(size<0?0:checked(size)|0);
-}
-
-
-
-
-Buffer.allocUnsafe=function(size){
-return allocUnsafe(size);
-};
-
-
-
-Buffer.allocUnsafeSlow=function(size){
-return allocUnsafe(size);
-};
-
-function fromString(string,encoding){
-if(typeof encoding!=='string'||encoding===''){
-encoding='utf8';
-}
-
-if(!Buffer.isEncoding(encoding)){
-throw new TypeError('Unknown encoding: '+encoding);
-}
-
-var length=byteLength(string,encoding)|0;
-var buf=createBuffer(length);
-
-var actual=buf.write(string,encoding);
-
-if(actual!==length){
-
-
-
-buf=buf.slice(0,actual);
-}
-
-return buf;
-}
-
-function fromArrayLike(array){
-var length=array.length<0?0:checked(array.length)|0;
-var buf=createBuffer(length);
-for(var i=0;i<length;i+=1){
-buf[i]=array[i]&255;
-}
-return buf;
-}
-
-function fromArrayBuffer(array,byteOffset,length){
-if(byteOffset<0||array.byteLength<byteOffset){
-throw new RangeError('"offset" is outside of buffer bounds');
-}
-
-if(array.byteLength<byteOffset+(length||0)){
-throw new RangeError('"length" is outside of buffer bounds');
-}
-
-var buf;
-if(byteOffset===undefined&&length===undefined){
-buf=new Uint8Array(array);
-}else if(length===undefined){
-buf=new Uint8Array(array,byteOffset);
-}else{
-buf=new Uint8Array(array,byteOffset,length);
-}
-
-
-buf.__proto__=Buffer.prototype;
-return buf;
-}
-
-function fromObject(obj){
-if(Buffer.isBuffer(obj)){
-var len=checked(obj.length)|0;
-var buf=createBuffer(len);
-
-if(buf.length===0){
-return buf;
-}
-
-obj.copy(buf,0,0,len);
-return buf;
-}
-
-if(obj){
-if(ArrayBuffer.isView(obj)||'length'in obj){
-if(typeof obj.length!=='number'||numberIsNaN(obj.length)){
-return createBuffer(0);
-}
-return fromArrayLike(obj);
-}
-
-if(obj.type==='Buffer'&&Array.isArray(obj.data)){
-return fromArrayLike(obj.data);
-}
-}
-
-throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object.');
-}
-
-function checked(length){
-
-
-if(length>=K_MAX_LENGTH){
-throw new RangeError('Attempt to allocate Buffer larger than maximum '+
-'size: 0x'+K_MAX_LENGTH.toString(16)+' bytes');
-}
-return length|0;
-}
-
-function SlowBuffer(length){
-if(+length!=length){
-length=0;
-}
-return Buffer.alloc(+length);
-}
-
-Buffer.isBuffer=function isBuffer(b){
-return b!=null&&b._isBuffer===true;
-};
-
-Buffer.compare=function compare(a,b){
-if(!Buffer.isBuffer(a)||!Buffer.isBuffer(b)){
-throw new TypeError('Arguments must be Buffers');
-}
-
-if(a===b)return 0;
-
-var x=a.length;
-var y=b.length;
-
-for(var i=0,len=Math.min(x,y);i<len;++i){
-if(a[i]!==b[i]){
-x=a[i];
-y=b[i];
-break;
-}
-}
-
-if(x<y)return-1;
-if(y<x)return 1;
-return 0;
-};
-
-Buffer.isEncoding=function isEncoding(encoding){
-switch(String(encoding).toLowerCase()){
-case'hex':
-case'utf8':
-case'utf-8':
-case'ascii':
-case'latin1':
-case'binary':
-case'base64':
-case'ucs2':
-case'ucs-2':
-case'utf16le':
-case'utf-16le':
-return true;
-default:
-return false;}
-
-};
-
-Buffer.concat=function concat(list,length){
-if(!Array.isArray(list)){
-throw new TypeError('"list" argument must be an Array of Buffers');
-}
-
-if(list.length===0){
-return Buffer.alloc(0);
-}
-
-var i;
-if(length===undefined){
-length=0;
-for(i=0;i<list.length;++i){
-length+=list[i].length;
-}
-}
-
-var buffer=Buffer.allocUnsafe(length);
-var pos=0;
-for(i=0;i<list.length;++i){
-var buf=list[i];
-if(ArrayBuffer.isView(buf)){
-buf=Buffer.from(buf);
-}
-if(!Buffer.isBuffer(buf)){
-throw new TypeError('"list" argument must be an Array of Buffers');
-}
-buf.copy(buffer,pos);
-pos+=buf.length;
-}
-return buffer;
-};
-
-function byteLength(string,encoding){
-if(Buffer.isBuffer(string)){
-return string.length;
-}
-if(ArrayBuffer.isView(string)||isArrayBuffer(string)){
-return string.byteLength;
-}
-if(typeof string!=='string'){
-string=''+string;
-}
-
-var len=string.length;
-if(len===0)return 0;
-
-
-var loweredCase=false;
-for(;;){
-switch(encoding){
-case'ascii':
-case'latin1':
-case'binary':
-return len;
-case'utf8':
-case'utf-8':
-case undefined:
-return utf8ToBytes(string).length;
-case'ucs2':
-case'ucs-2':
-case'utf16le':
-case'utf-16le':
-return len*2;
-case'hex':
-return len>>>1;
-case'base64':
-return base64ToBytes(string).length;
-default:
-if(loweredCase)return utf8ToBytes(string).length;
-encoding=(''+encoding).toLowerCase();
-loweredCase=true;}
-
-}
-}
-Buffer.byteLength=byteLength;
-
-function slowToString(encoding,start,end){
-var loweredCase=false;
-
-
-
-
-
-
-
-
-if(start===undefined||start<0){
-start=0;
-}
-
-
-if(start>this.length){
-return'';
-}
-
-if(end===undefined||end>this.length){
-end=this.length;
-}
-
-if(end<=0){
-return'';
-}
-
-
-end>>>=0;
-start>>>=0;
-
-if(end<=start){
-return'';
-}
-
-if(!encoding)encoding='utf8';
-
-while(true){
-switch(encoding){
-case'hex':
-return hexSlice(this,start,end);
-
-case'utf8':
-case'utf-8':
-return utf8Slice(this,start,end);
-
-case'ascii':
-return asciiSlice(this,start,end);
-
-case'latin1':
-case'binary':
-return latin1Slice(this,start,end);
-
-case'base64':
-return base64Slice(this,start,end);
-
-case'ucs2':
-case'ucs-2':
-case'utf16le':
-case'utf-16le':
-return utf16leSlice(this,start,end);
-
-default:
-if(loweredCase)throw new TypeError('Unknown encoding: '+encoding);
-encoding=(encoding+'').toLowerCase();
-loweredCase=true;}
-
-}
-}
-
-
-
-
-
-
-
-Buffer.prototype._isBuffer=true;
-
-function swap(b,n,m){
-var i=b[n];
-b[n]=b[m];
-b[m]=i;
-}
-
-Buffer.prototype.swap16=function swap16(){
-var len=this.length;
-if(len%2!==0){
-throw new RangeError('Buffer size must be a multiple of 16-bits');
-}
-for(var i=0;i<len;i+=2){
-swap(this,i,i+1);
-}
-return this;
-};
-
-Buffer.prototype.swap32=function swap32(){
-var len=this.length;
-if(len%4!==0){
-throw new RangeError('Buffer size must be a multiple of 32-bits');
-}
-for(var i=0;i<len;i+=4){
-swap(this,i,i+3);
-swap(this,i+1,i+2);
-}
-return this;
-};
-
-Buffer.prototype.swap64=function swap64(){
-var len=this.length;
-if(len%8!==0){
-throw new RangeError('Buffer size must be a multiple of 64-bits');
-}
-for(var i=0;i<len;i+=8){
-swap(this,i,i+7);
-swap(this,i+1,i+6);
-swap(this,i+2,i+5);
-swap(this,i+3,i+4);
-}
-return this;
-};
-
-Buffer.prototype.toString=function toString(){
-var length=this.length;
-if(length===0)return'';
-if(arguments.length===0)return utf8Slice(this,0,length);
-return slowToString.apply(this,arguments);
-};
-
-Buffer.prototype.toLocaleString=Buffer.prototype.toString;
-
-Buffer.prototype.equals=function equals(b){
-if(!Buffer.isBuffer(b))throw new TypeError('Argument must be a Buffer');
-if(this===b)return true;
-return Buffer.compare(this,b)===0;
-};
-
-Buffer.prototype.inspect=function inspect(){
-var str='';
-var max=exports.INSPECT_MAX_BYTES;
-if(this.length>0){
-str=this.toString('hex',0,max).match(/.{2}/g).join(' ');
-if(this.length>max)str+=' ... ';
-}
-return'<Buffer '+str+'>';
-};
-
-Buffer.prototype.compare=function compare(target,start,end,thisStart,thisEnd){
-if(!Buffer.isBuffer(target)){
-throw new TypeError('Argument must be a Buffer');
-}
-
-if(start===undefined){
-start=0;
-}
-if(end===undefined){
-end=target?target.length:0;
-}
-if(thisStart===undefined){
-thisStart=0;
-}
-if(thisEnd===undefined){
-thisEnd=this.length;
-}
-
-if(start<0||end>target.length||thisStart<0||thisEnd>this.length){
-throw new RangeError('out of range index');
-}
-
-if(thisStart>=thisEnd&&start>=end){
-return 0;
-}
-if(thisStart>=thisEnd){
-return-1;
-}
-if(start>=end){
-return 1;
-}
-
-start>>>=0;
-end>>>=0;
-thisStart>>>=0;
-thisEnd>>>=0;
-
-if(this===target)return 0;
-
-var x=thisEnd-thisStart;
-var y=end-start;
-var len=Math.min(x,y);
-
-var thisCopy=this.slice(thisStart,thisEnd);
-var targetCopy=target.slice(start,end);
-
-for(var i=0;i<len;++i){
-if(thisCopy[i]!==targetCopy[i]){
-x=thisCopy[i];
-y=targetCopy[i];
-break;
-}
-}
-
-if(x<y)return-1;
-if(y<x)return 1;
-return 0;
-};
-
-
-
-
-
-
-
-
-
-
-function bidirectionalIndexOf(buffer,val,byteOffset,encoding,dir){
-
-if(buffer.length===0)return-1;
-
-
-if(typeof byteOffset==='string'){
-encoding=byteOffset;
-byteOffset=0;
-}else if(byteOffset>0x7fffffff){
-byteOffset=0x7fffffff;
-}else if(byteOffset<-0x80000000){
-byteOffset=-0x80000000;
-}
-byteOffset=+byteOffset;
-if(numberIsNaN(byteOffset)){
-
-byteOffset=dir?0:buffer.length-1;
-}
-
-
-if(byteOffset<0)byteOffset=buffer.length+byteOffset;
-if(byteOffset>=buffer.length){
-if(dir)return-1;else
-byteOffset=buffer.length-1;
-}else if(byteOffset<0){
-if(dir)byteOffset=0;else
-return-1;
-}
-
-
-if(typeof val==='string'){
-val=Buffer.from(val,encoding);
-}
-
-
-if(Buffer.isBuffer(val)){
-
-if(val.length===0){
-return-1;
-}
-return arrayIndexOf(buffer,val,byteOffset,encoding,dir);
-}else if(typeof val==='number'){
-val=val&0xFF;
-if(typeof Uint8Array.prototype.indexOf==='function'){
-if(dir){
-return Uint8Array.prototype.indexOf.call(buffer,val,byteOffset);
-}else{
-return Uint8Array.prototype.lastIndexOf.call(buffer,val,byteOffset);
-}
-}
-return arrayIndexOf(buffer,[val],byteOffset,encoding,dir);
-}
-
-throw new TypeError('val must be string, number or Buffer');
-}
-
-function arrayIndexOf(arr,val,byteOffset,encoding,dir){
-var indexSize=1;
-var arrLength=arr.length;
-var valLength=val.length;
-
-if(encoding!==undefined){
-encoding=String(encoding).toLowerCase();
-if(encoding==='ucs2'||encoding==='ucs-2'||
-encoding==='utf16le'||encoding==='utf-16le'){
-if(arr.length<2||val.length<2){
-return-1;
-}
-indexSize=2;
-arrLength/=2;
-valLength/=2;
-byteOffset/=2;
-}
-}
-
-function read(buf,i){
-if(indexSize===1){
-return buf[i];
-}else{
-return buf.readUInt16BE(i*indexSize);
-}
-}
-
-var i;
-if(dir){
-var foundIndex=-1;
-for(i=byteOffset;i<arrLength;i++){
-if(read(arr,i)===read(val,foundIndex===-1?0:i-foundIndex)){
-if(foundIndex===-1)foundIndex=i;
-if(i-foundIndex+1===valLength)return foundIndex*indexSize;
-}else{
-if(foundIndex!==-1)i-=i-foundIndex;
-foundIndex=-1;
-}
-}
-}else{
-if(byteOffset+valLength>arrLength)byteOffset=arrLength-valLength;
-for(i=byteOffset;i>=0;i--){
-var found=true;
-for(var j=0;j<valLength;j++){
-if(read(arr,i+j)!==read(val,j)){
-found=false;
-break;
-}
-}
-if(found)return i;
-}
-}
-
-return-1;
-}
-
-Buffer.prototype.includes=function includes(val,byteOffset,encoding){
-return this.indexOf(val,byteOffset,encoding)!==-1;
-};
-
-Buffer.prototype.indexOf=function indexOf(val,byteOffset,encoding){
-return bidirectionalIndexOf(this,val,byteOffset,encoding,true);
-};
-
-Buffer.prototype.lastIndexOf=function lastIndexOf(val,byteOffset,encoding){
-return bidirectionalIndexOf(this,val,byteOffset,encoding,false);
-};
-
-function hexWrite(buf,string,offset,length){
-offset=Number(offset)||0;
-var remaining=buf.length-offset;
-if(!length){
-length=remaining;
-}else{
-length=Number(length);
-if(length>remaining){
-length=remaining;
-}
-}
-
-var strLen=string.length;
-
-if(length>strLen/2){
-length=strLen/2;
-}
-for(var i=0;i<length;++i){
-var parsed=parseInt(string.substr(i*2,2),16);
-if(numberIsNaN(parsed))return i;
-buf[offset+i]=parsed;
-}
-return i;
-}
-
-function utf8Write(buf,string,offset,length){
-return blitBuffer(utf8ToBytes(string,buf.length-offset),buf,offset,length);
-}
-
-function asciiWrite(buf,string,offset,length){
-return blitBuffer(asciiToBytes(string),buf,offset,length);
-}
-
-function latin1Write(buf,string,offset,length){
-return asciiWrite(buf,string,offset,length);
-}
-
-function base64Write(buf,string,offset,length){
-return blitBuffer(base64ToBytes(string),buf,offset,length);
-}
-
-function ucs2Write(buf,string,offset,length){
-return blitBuffer(utf16leToBytes(string,buf.length-offset),buf,offset,length);
-}
-
-Buffer.prototype.write=function write(string,offset,length,encoding){
-
-if(offset===undefined){
-encoding='utf8';
-length=this.length;
-offset=0;
-
-}else if(length===undefined&&typeof offset==='string'){
-encoding=offset;
-length=this.length;
-offset=0;
-
-}else if(isFinite(offset)){
-offset=offset>>>0;
-if(isFinite(length)){
-length=length>>>0;
-if(encoding===undefined)encoding='utf8';
-}else{
-encoding=length;
-length=undefined;
-}
-}else{
-throw new Error(
-'Buffer.write(string, encoding, offset[, length]) is no longer supported');
-
-}
-
-var remaining=this.length-offset;
-if(length===undefined||length>remaining)length=remaining;
-
-if(string.length>0&&(length<0||offset<0)||offset>this.length){
-throw new RangeError('Attempt to write outside buffer bounds');
-}
-
-if(!encoding)encoding='utf8';
-
-var loweredCase=false;
-for(;;){
-switch(encoding){
-case'hex':
-return hexWrite(this,string,offset,length);
-
-case'utf8':
-case'utf-8':
-return utf8Write(this,string,offset,length);
-
-case'ascii':
-return asciiWrite(this,string,offset,length);
-
-case'latin1':
-case'binary':
-return latin1Write(this,string,offset,length);
-
-case'base64':
-
-return base64Write(this,string,offset,length);
-
-case'ucs2':
-case'ucs-2':
-case'utf16le':
-case'utf-16le':
-return ucs2Write(this,string,offset,length);
-
-default:
-if(loweredCase)throw new TypeError('Unknown encoding: '+encoding);
-encoding=(''+encoding).toLowerCase();
-loweredCase=true;}
-
-}
-};
-
-Buffer.prototype.toJSON=function toJSON(){
-return{
-type:'Buffer',
-data:Array.prototype.slice.call(this._arr||this,0)};
-
-};
-
-function base64Slice(buf,start,end){
-if(start===0&&end===buf.length){
-return base64.fromByteArray(buf);
-}else{
-return base64.fromByteArray(buf.slice(start,end));
-}
-}
-
-function utf8Slice(buf,start,end){
-end=Math.min(buf.length,end);
-var res=[];
-
-var i=start;
-while(i<end){
-var firstByte=buf[i];
-var codePoint=null;
-var bytesPerSequence=firstByte>0xEF?4:
-firstByte>0xDF?3:
-firstByte>0xBF?2:
-1;
-
-if(i+bytesPerSequence<=end){
-var secondByte,thirdByte,fourthByte,tempCodePoint;
-
-switch(bytesPerSequence){
-case 1:
-if(firstByte<0x80){
-codePoint=firstByte;
-}
-break;
-case 2:
-secondByte=buf[i+1];
-if((secondByte&0xC0)===0x80){
-tempCodePoint=(firstByte&0x1F)<<0x6|secondByte&0x3F;
-if(tempCodePoint>0x7F){
-codePoint=tempCodePoint;
-}
-}
-break;
-case 3:
-secondByte=buf[i+1];
-thirdByte=buf[i+2];
-if((secondByte&0xC0)===0x80&&(thirdByte&0xC0)===0x80){
-tempCodePoint=(firstByte&0xF)<<0xC|(secondByte&0x3F)<<0x6|thirdByte&0x3F;
-if(tempCodePoint>0x7FF&&(tempCodePoint<0xD800||tempCodePoint>0xDFFF)){
-codePoint=tempCodePoint;
-}
-}
-break;
-case 4:
-secondByte=buf[i+1];
-thirdByte=buf[i+2];
-fourthByte=buf[i+3];
-if((secondByte&0xC0)===0x80&&(thirdByte&0xC0)===0x80&&(fourthByte&0xC0)===0x80){
-tempCodePoint=(firstByte&0xF)<<0x12|(secondByte&0x3F)<<0xC|(thirdByte&0x3F)<<0x6|fourthByte&0x3F;
-if(tempCodePoint>0xFFFF&&tempCodePoint<0x110000){
-codePoint=tempCodePoint;
-}
-}}
-
-}
-
-if(codePoint===null){
-
-
-codePoint=0xFFFD;
-bytesPerSequence=1;
-}else if(codePoint>0xFFFF){
-
-codePoint-=0x10000;
-res.push(codePoint>>>10&0x3FF|0xD800);
-codePoint=0xDC00|codePoint&0x3FF;
-}
-
-res.push(codePoint);
-i+=bytesPerSequence;
-}
-
-return decodeCodePointsArray(res);
-}
-
-
-
-
-var MAX_ARGUMENTS_LENGTH=0x1000;
-
-function decodeCodePointsArray(codePoints){
-var len=codePoints.length;
-if(len<=MAX_ARGUMENTS_LENGTH){
-return String.fromCharCode.apply(String,codePoints);
-}
-
-
-var res='';
-var i=0;
-while(i<len){
-res+=String.fromCharCode.apply(
-String,
-codePoints.slice(i,i+=MAX_ARGUMENTS_LENGTH));
-
-}
-return res;
-}
-
-function asciiSlice(buf,start,end){
-var ret='';
-end=Math.min(buf.length,end);
-
-for(var i=start;i<end;++i){
-ret+=String.fromCharCode(buf[i]&0x7F);
-}
-return ret;
-}
-
-function latin1Slice(buf,start,end){
-var ret='';
-end=Math.min(buf.length,end);
-
-for(var i=start;i<end;++i){
-ret+=String.fromCharCode(buf[i]);
-}
-return ret;
-}
-
-function hexSlice(buf,start,end){
-var len=buf.length;
-
-if(!start||start<0)start=0;
-if(!end||end<0||end>len)end=len;
-
-var out='';
-for(var i=start;i<end;++i){
-out+=toHex(buf[i]);
-}
-return out;
-}
-
-function utf16leSlice(buf,start,end){
-var bytes=buf.slice(start,end);
-var res='';
-for(var i=0;i<bytes.length;i+=2){
-res+=String.fromCharCode(bytes[i]+bytes[i+1]*256);
-}
-return res;
-}
-
-Buffer.prototype.slice=function slice(start,end){
-var len=this.length;
-start=~~start;
-end=end===undefined?len:~~end;
-
-if(start<0){
-start+=len;
-if(start<0)start=0;
-}else if(start>len){
-start=len;
-}
-
-if(end<0){
-end+=len;
-if(end<0)end=0;
-}else if(end>len){
-end=len;
-}
-
-if(end<start)end=start;
-
-var newBuf=this.subarray(start,end);
-
-newBuf.__proto__=Buffer.prototype;
-return newBuf;
-};
-
-
-
-
-function checkOffset(offset,ext,length){
-if(offset%1!==0||offset<0)throw new RangeError('offset is not uint');
-if(offset+ext>length)throw new RangeError('Trying to access beyond buffer length');
-}
-
-Buffer.prototype.readUIntLE=function readUIntLE(offset,byteLength,noAssert){
-offset=offset>>>0;
-byteLength=byteLength>>>0;
-if(!noAssert)checkOffset(offset,byteLength,this.length);
-
-var val=this[offset];
-var mul=1;
-var i=0;
-while(++i<byteLength&&(mul*=0x100)){
-val+=this[offset+i]*mul;
-}
-
-return val;
-};
-
-Buffer.prototype.readUIntBE=function readUIntBE(offset,byteLength,noAssert){
-offset=offset>>>0;
-byteLength=byteLength>>>0;
-if(!noAssert){
-checkOffset(offset,byteLength,this.length);
-}
-
-var val=this[offset+--byteLength];
-var mul=1;
-while(byteLength>0&&(mul*=0x100)){
-val+=this[offset+--byteLength]*mul;
-}
-
-return val;
-};
-
-Buffer.prototype.readUInt8=function readUInt8(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,1,this.length);
-return this[offset];
-};
-
-Buffer.prototype.readUInt16LE=function readUInt16LE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,2,this.length);
-return this[offset]|this[offset+1]<<8;
-};
-
-Buffer.prototype.readUInt16BE=function readUInt16BE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,2,this.length);
-return this[offset]<<8|this[offset+1];
-};
-
-Buffer.prototype.readUInt32LE=function readUInt32LE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,4,this.length);
-
-return(this[offset]|
-this[offset+1]<<8|
-this[offset+2]<<16)+
-this[offset+3]*0x1000000;
-};
-
-Buffer.prototype.readUInt32BE=function readUInt32BE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,4,this.length);
-
-return this[offset]*0x1000000+(
-this[offset+1]<<16|
-this[offset+2]<<8|
-this[offset+3]);
-};
-
-Buffer.prototype.readIntLE=function readIntLE(offset,byteLength,noAssert){
-offset=offset>>>0;
-byteLength=byteLength>>>0;
-if(!noAssert)checkOffset(offset,byteLength,this.length);
-
-var val=this[offset];
-var mul=1;
-var i=0;
-while(++i<byteLength&&(mul*=0x100)){
-val+=this[offset+i]*mul;
-}
-mul*=0x80;
-
-if(val>=mul)val-=Math.pow(2,8*byteLength);
-
-return val;
-};
-
-Buffer.prototype.readIntBE=function readIntBE(offset,byteLength,noAssert){
-offset=offset>>>0;
-byteLength=byteLength>>>0;
-if(!noAssert)checkOffset(offset,byteLength,this.length);
-
-var i=byteLength;
-var mul=1;
-var val=this[offset+--i];
-while(i>0&&(mul*=0x100)){
-val+=this[offset+--i]*mul;
-}
-mul*=0x80;
-
-if(val>=mul)val-=Math.pow(2,8*byteLength);
-
-return val;
-};
-
-Buffer.prototype.readInt8=function readInt8(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,1,this.length);
-if(!(this[offset]&0x80))return this[offset];
-return(0xff-this[offset]+1)*-1;
-};
-
-Buffer.prototype.readInt16LE=function readInt16LE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,2,this.length);
-var val=this[offset]|this[offset+1]<<8;
-return val&0x8000?val|0xFFFF0000:val;
-};
-
-Buffer.prototype.readInt16BE=function readInt16BE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,2,this.length);
-var val=this[offset+1]|this[offset]<<8;
-return val&0x8000?val|0xFFFF0000:val;
-};
-
-Buffer.prototype.readInt32LE=function readInt32LE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,4,this.length);
-
-return this[offset]|
-this[offset+1]<<8|
-this[offset+2]<<16|
-this[offset+3]<<24;
-};
-
-Buffer.prototype.readInt32BE=function readInt32BE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,4,this.length);
-
-return this[offset]<<24|
-this[offset+1]<<16|
-this[offset+2]<<8|
-this[offset+3];
-};
-
-Buffer.prototype.readFloatLE=function readFloatLE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,4,this.length);
-return ieee754.read(this,offset,true,23,4);
-};
-
-Buffer.prototype.readFloatBE=function readFloatBE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,4,this.length);
-return ieee754.read(this,offset,false,23,4);
-};
-
-Buffer.prototype.readDoubleLE=function readDoubleLE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,8,this.length);
-return ieee754.read(this,offset,true,52,8);
-};
-
-Buffer.prototype.readDoubleBE=function readDoubleBE(offset,noAssert){
-offset=offset>>>0;
-if(!noAssert)checkOffset(offset,8,this.length);
-return ieee754.read(this,offset,false,52,8);
-};
-
-function checkInt(buf,value,offset,ext,max,min){
-if(!Buffer.isBuffer(buf))throw new TypeError('"buffer" argument must be a Buffer instance');
-if(value>max||value<min)throw new RangeError('"value" argument is out of bounds');
-if(offset+ext>buf.length)throw new RangeError('Index out of range');
-}
-
-Buffer.prototype.writeUIntLE=function writeUIntLE(value,offset,byteLength,noAssert){
-value=+value;
-offset=offset>>>0;
-byteLength=byteLength>>>0;
-if(!noAssert){
-var maxBytes=Math.pow(2,8*byteLength)-1;
-checkInt(this,value,offset,byteLength,maxBytes,0);
-}
-
-var mul=1;
-var i=0;
-this[offset]=value&0xFF;
-while(++i<byteLength&&(mul*=0x100)){
-this[offset+i]=value/mul&0xFF;
-}
-
-return offset+byteLength;
-};
-
-Buffer.prototype.writeUIntBE=function writeUIntBE(value,offset,byteLength,noAssert){
-value=+value;
-offset=offset>>>0;
-byteLength=byteLength>>>0;
-if(!noAssert){
-var maxBytes=Math.pow(2,8*byteLength)-1;
-checkInt(this,value,offset,byteLength,maxBytes,0);
-}
-
-var i=byteLength-1;
-var mul=1;
-this[offset+i]=value&0xFF;
-while(--i>=0&&(mul*=0x100)){
-this[offset+i]=value/mul&0xFF;
-}
-
-return offset+byteLength;
-};
-
-Buffer.prototype.writeUInt8=function writeUInt8(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,1,0xff,0);
-this[offset]=value&0xff;
-return offset+1;
-};
-
-Buffer.prototype.writeUInt16LE=function writeUInt16LE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,2,0xffff,0);
-this[offset]=value&0xff;
-this[offset+1]=value>>>8;
-return offset+2;
-};
-
-Buffer.prototype.writeUInt16BE=function writeUInt16BE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,2,0xffff,0);
-this[offset]=value>>>8;
-this[offset+1]=value&0xff;
-return offset+2;
-};
-
-Buffer.prototype.writeUInt32LE=function writeUInt32LE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);
-this[offset+3]=value>>>24;
-this[offset+2]=value>>>16;
-this[offset+1]=value>>>8;
-this[offset]=value&0xff;
-return offset+4;
-};
-
-Buffer.prototype.writeUInt32BE=function writeUInt32BE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);
-this[offset]=value>>>24;
-this[offset+1]=value>>>16;
-this[offset+2]=value>>>8;
-this[offset+3]=value&0xff;
-return offset+4;
-};
-
-Buffer.prototype.writeIntLE=function writeIntLE(value,offset,byteLength,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert){
-var limit=Math.pow(2,8*byteLength-1);
-
-checkInt(this,value,offset,byteLength,limit-1,-limit);
-}
-
-var i=0;
-var mul=1;
-var sub=0;
-this[offset]=value&0xFF;
-while(++i<byteLength&&(mul*=0x100)){
-if(value<0&&sub===0&&this[offset+i-1]!==0){
-sub=1;
-}
-this[offset+i]=(value/mul>>0)-sub&0xFF;
-}
-
-return offset+byteLength;
-};
-
-Buffer.prototype.writeIntBE=function writeIntBE(value,offset,byteLength,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert){
-var limit=Math.pow(2,8*byteLength-1);
-
-checkInt(this,value,offset,byteLength,limit-1,-limit);
-}
-
-var i=byteLength-1;
-var mul=1;
-var sub=0;
-this[offset+i]=value&0xFF;
-while(--i>=0&&(mul*=0x100)){
-if(value<0&&sub===0&&this[offset+i+1]!==0){
-sub=1;
-}
-this[offset+i]=(value/mul>>0)-sub&0xFF;
-}
-
-return offset+byteLength;
-};
-
-Buffer.prototype.writeInt8=function writeInt8(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,1,0x7f,-0x80);
-if(value<0)value=0xff+value+1;
-this[offset]=value&0xff;
-return offset+1;
-};
-
-Buffer.prototype.writeInt16LE=function writeInt16LE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);
-this[offset]=value&0xff;
-this[offset+1]=value>>>8;
-return offset+2;
-};
-
-Buffer.prototype.writeInt16BE=function writeInt16BE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);
-this[offset]=value>>>8;
-this[offset+1]=value&0xff;
-return offset+2;
-};
-
-Buffer.prototype.writeInt32LE=function writeInt32LE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);
-this[offset]=value&0xff;
-this[offset+1]=value>>>8;
-this[offset+2]=value>>>16;
-this[offset+3]=value>>>24;
-return offset+4;
-};
-
-Buffer.prototype.writeInt32BE=function writeInt32BE(value,offset,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);
-if(value<0)value=0xffffffff+value+1;
-this[offset]=value>>>24;
-this[offset+1]=value>>>16;
-this[offset+2]=value>>>8;
-this[offset+3]=value&0xff;
-return offset+4;
-};
-
-function checkIEEE754(buf,value,offset,ext,max,min){
-if(offset+ext>buf.length)throw new RangeError('Index out of range');
-if(offset<0)throw new RangeError('Index out of range');
-}
-
-function writeFloat(buf,value,offset,littleEndian,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert){
-checkIEEE754(buf,value,offset,4,3.4028234663852886e+38,-3.4028234663852886e+38);
-}
-ieee754.write(buf,value,offset,littleEndian,23,4);
-return offset+4;
-}
-
-Buffer.prototype.writeFloatLE=function writeFloatLE(value,offset,noAssert){
-return writeFloat(this,value,offset,true,noAssert);
-};
-
-Buffer.prototype.writeFloatBE=function writeFloatBE(value,offset,noAssert){
-return writeFloat(this,value,offset,false,noAssert);
-};
-
-function writeDouble(buf,value,offset,littleEndian,noAssert){
-value=+value;
-offset=offset>>>0;
-if(!noAssert){
-checkIEEE754(buf,value,offset,8,1.7976931348623157E+308,-1.7976931348623157E+308);
-}
-ieee754.write(buf,value,offset,littleEndian,52,8);
-return offset+8;
-}
-
-Buffer.prototype.writeDoubleLE=function writeDoubleLE(value,offset,noAssert){
-return writeDouble(this,value,offset,true,noAssert);
-};
-
-Buffer.prototype.writeDoubleBE=function writeDoubleBE(value,offset,noAssert){
-return writeDouble(this,value,offset,false,noAssert);
-};
-
-
-Buffer.prototype.copy=function copy(target,targetStart,start,end){
-if(!Buffer.isBuffer(target))throw new TypeError('argument should be a Buffer');
-if(!start)start=0;
-if(!end&&end!==0)end=this.length;
-if(targetStart>=target.length)targetStart=target.length;
-if(!targetStart)targetStart=0;
-if(end>0&&end<start)end=start;
-
-
-if(end===start)return 0;
-if(target.length===0||this.length===0)return 0;
-
-
-if(targetStart<0){
-throw new RangeError('targetStart out of bounds');
-}
-if(start<0||start>=this.length)throw new RangeError('Index out of range');
-if(end<0)throw new RangeError('sourceEnd out of bounds');
-
-
-if(end>this.length)end=this.length;
-if(target.length-targetStart<end-start){
-end=target.length-targetStart+start;
-}
-
-var len=end-start;
-
-if(this===target&&typeof Uint8Array.prototype.copyWithin==='function'){
-
-this.copyWithin(targetStart,start,end);
-}else if(this===target&&start<targetStart&&targetStart<end){
-
-for(var i=len-1;i>=0;--i){
-target[i+targetStart]=this[i+start];
-}
-}else{
-Uint8Array.prototype.set.call(
-target,
-this.subarray(start,end),
-targetStart);
-
-}
-
-return len;
-};
-
-
-
-
-
-Buffer.prototype.fill=function fill(val,start,end,encoding){
-
-if(typeof val==='string'){
-if(typeof start==='string'){
-encoding=start;
-start=0;
-end=this.length;
-}else if(typeof end==='string'){
-encoding=end;
-end=this.length;
-}
-if(encoding!==undefined&&typeof encoding!=='string'){
-throw new TypeError('encoding must be a string');
-}
-if(typeof encoding==='string'&&!Buffer.isEncoding(encoding)){
-throw new TypeError('Unknown encoding: '+encoding);
-}
-if(val.length===1){
-var code=val.charCodeAt(0);
-if(encoding==='utf8'&&code<128||
-encoding==='latin1'){
-
-val=code;
-}
-}
-}else if(typeof val==='number'){
-val=val&255;
-}
-
-
-if(start<0||this.length<start||this.length<end){
-throw new RangeError('Out of range index');
-}
-
-if(end<=start){
-return this;
-}
-
-start=start>>>0;
-end=end===undefined?this.length:end>>>0;
-
-if(!val)val=0;
-
-var i;
-if(typeof val==='number'){
-for(i=start;i<end;++i){
-this[i]=val;
-}
-}else{
-var bytes=Buffer.isBuffer(val)?
-val:
-new Buffer(val,encoding);
-var len=bytes.length;
-if(len===0){
-throw new TypeError('The value "'+val+
-'" is invalid for argument "value"');
-}
-for(i=0;i<end-start;++i){
-this[i+start]=bytes[i%len];
-}
-}
-
-return this;
-};
-
-
-
-
-var INVALID_BASE64_RE=/[^+/0-9A-Za-z-_]/g;
-
-function base64clean(str){
-
-str=str.split('=')[0];
-
-str=str.trim().replace(INVALID_BASE64_RE,'');
-
-if(str.length<2)return'';
-
-while(str.length%4!==0){
-str=str+'=';
-}
-return str;
-}
-
-function toHex(n){
-if(n<16)return'0'+n.toString(16);
-return n.toString(16);
-}
-
-function utf8ToBytes(string,units){
-units=units||Infinity;
-var codePoint;
-var length=string.length;
-var leadSurrogate=null;
-var bytes=[];
-
-for(var i=0;i<length;++i){
-codePoint=string.charCodeAt(i);
-
-
-if(codePoint>0xD7FF&&codePoint<0xE000){
-
-if(!leadSurrogate){
-
-if(codePoint>0xDBFF){
-
-if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
-continue;
-}else if(i+1===length){
-
-if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
-continue;
-}
-
-
-leadSurrogate=codePoint;
-
-continue;
-}
-
-
-if(codePoint<0xDC00){
-if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
-leadSurrogate=codePoint;
-continue;
-}
-
-
-codePoint=(leadSurrogate-0xD800<<10|codePoint-0xDC00)+0x10000;
-}else if(leadSurrogate){
-
-if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
-}
-
-leadSurrogate=null;
-
-
-if(codePoint<0x80){
-if((units-=1)<0)break;
-bytes.push(codePoint);
-}else if(codePoint<0x800){
-if((units-=2)<0)break;
-bytes.push(
-codePoint>>0x6|0xC0,
-codePoint&0x3F|0x80);
-
-}else if(codePoint<0x10000){
-if((units-=3)<0)break;
-bytes.push(
-codePoint>>0xC|0xE0,
-codePoint>>0x6&0x3F|0x80,
-codePoint&0x3F|0x80);
-
-}else if(codePoint<0x110000){
-if((units-=4)<0)break;
-bytes.push(
-codePoint>>0x12|0xF0,
-codePoint>>0xC&0x3F|0x80,
-codePoint>>0x6&0x3F|0x80,
-codePoint&0x3F|0x80);
-
-}else{
-throw new Error('Invalid code point');
-}
-}
-
-return bytes;
-}
-
-function asciiToBytes(str){
-var byteArray=[];
-for(var i=0;i<str.length;++i){
-
-byteArray.push(str.charCodeAt(i)&0xFF);
-}
-return byteArray;
-}
-
-function utf16leToBytes(str,units){
-var c,hi,lo;
-var byteArray=[];
-for(var i=0;i<str.length;++i){
-if((units-=2)<0)break;
-
-c=str.charCodeAt(i);
-hi=c>>8;
-lo=c%256;
-byteArray.push(lo);
-byteArray.push(hi);
-}
-
-return byteArray;
-}
-
-function base64ToBytes(str){
-return base64.toByteArray(base64clean(str));
-}
-
-function blitBuffer(src,dst,offset,length){
-for(var i=0;i<length;++i){
-if(i+offset>=dst.length||i>=src.length)break;
-dst[i+offset]=src[i];
-}
-return i;
-}
-
-
-
-function isArrayBuffer(obj){
-return obj instanceof ArrayBuffer||
-obj!=null&&obj.constructor!=null&&obj.constructor.name==='ArrayBuffer'&&
-typeof obj.byteLength==='number';
-}
-
-function numberIsNaN(obj){
-return obj!==obj;
-}
-
-},{"base64-js":103,"ieee754":112}],110:[function(require,module,exports){
-(function(Buffer){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isArray(arg){
-if(Array.isArray){
-return Array.isArray(arg);
-}
-return objectToString(arg)==='[object Array]';
-}
-exports.isArray=isArray;
-
-function isBoolean(arg){
-return typeof arg==='boolean';
-}
-exports.isBoolean=isBoolean;
-
-function isNull(arg){
-return arg===null;
-}
-exports.isNull=isNull;
-
-function isNullOrUndefined(arg){
-return arg==null;
-}
-exports.isNullOrUndefined=isNullOrUndefined;
-
-function isNumber(arg){
-return typeof arg==='number';
-}
-exports.isNumber=isNumber;
-
-function isString(arg){
-return typeof arg==='string';
-}
-exports.isString=isString;
-
-function isSymbol(arg){
-return typeof arg==='symbol';
-}
-exports.isSymbol=isSymbol;
-
-function isUndefined(arg){
-return arg===void 0;
-}
-exports.isUndefined=isUndefined;
-
-function isRegExp(re){
-return objectToString(re)==='[object RegExp]';
-}
-exports.isRegExp=isRegExp;
-
-function isObject(arg){
-return typeof arg==='object'&&arg!==null;
-}
-exports.isObject=isObject;
-
-function isDate(d){
-return objectToString(d)==='[object Date]';
-}
-exports.isDate=isDate;
-
-function isError(e){
-return objectToString(e)==='[object Error]'||e instanceof Error;
-}
-exports.isError=isError;
-
-function isFunction(arg){
-return typeof arg==='function';
-}
-exports.isFunction=isFunction;
-
-function isPrimitive(arg){
-return arg===null||
-typeof arg==='boolean'||
-typeof arg==='number'||
-typeof arg==='string'||
-typeof arg==='symbol'||
-typeof arg==='undefined';
-}
-exports.isPrimitive=isPrimitive;
-
-exports.isBuffer=Buffer.isBuffer;
-
-function objectToString(o){
-return Object.prototype.toString.call(o);
-}
-
-}).call(this,{"isBuffer":require("../../is-buffer/index.js")});
-},{"../../is-buffer/index.js":114}],111:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var objectCreate=Object.create||objectCreatePolyfill;
-var objectKeys=Object.keys||objectKeysPolyfill;
-var bind=Function.prototype.bind||functionBindPolyfill;
-
-function EventEmitter(){
-if(!this._events||!Object.prototype.hasOwnProperty.call(this,'_events')){
-this._events=objectCreate(null);
-this._eventsCount=0;
-}
-
-this._maxListeners=this._maxListeners||undefined;
-}
-module.exports=EventEmitter;
-
-
-EventEmitter.EventEmitter=EventEmitter;
-
-EventEmitter.prototype._events=undefined;
-EventEmitter.prototype._maxListeners=undefined;
-
-
-
-var defaultMaxListeners=10;
-
-var hasDefineProperty;
-try{
-var o={};
-if(Object.defineProperty)Object.defineProperty(o,'x',{value:0});
-hasDefineProperty=o.x===0;
-}catch(err){hasDefineProperty=false;}
-if(hasDefineProperty){
-Object.defineProperty(EventEmitter,'defaultMaxListeners',{
-enumerable:true,
-get:function(){
-return defaultMaxListeners;
-},
-set:function(arg){
-
-
-if(typeof arg!=='number'||arg<0||arg!==arg)
-throw new TypeError('"defaultMaxListeners" must be a positive number');
-defaultMaxListeners=arg;
-}});
-
-}else{
-EventEmitter.defaultMaxListeners=defaultMaxListeners;
-}
-
-
-
-EventEmitter.prototype.setMaxListeners=function setMaxListeners(n){
-if(typeof n!=='number'||n<0||isNaN(n))
-throw new TypeError('"n" argument must be a positive number');
-this._maxListeners=n;
-return this;
-};
-
-function $getMaxListeners(that){
-if(that._maxListeners===undefined)
-return EventEmitter.defaultMaxListeners;
-return that._maxListeners;
-}
-
-EventEmitter.prototype.getMaxListeners=function getMaxListeners(){
-return $getMaxListeners(this);
-};
-
-
-
-
-
-
-function emitNone(handler,isFn,self){
-if(isFn)
-handler.call(self);else
-{
-var len=handler.length;
-var listeners=arrayClone(handler,len);
-for(var i=0;i<len;++i)
-listeners[i].call(self);
-}
-}
-function emitOne(handler,isFn,self,arg1){
-if(isFn)
-handler.call(self,arg1);else
-{
-var len=handler.length;
-var listeners=arrayClone(handler,len);
-for(var i=0;i<len;++i)
-listeners[i].call(self,arg1);
-}
-}
-function emitTwo(handler,isFn,self,arg1,arg2){
-if(isFn)
-handler.call(self,arg1,arg2);else
-{
-var len=handler.length;
-var listeners=arrayClone(handler,len);
-for(var i=0;i<len;++i)
-listeners[i].call(self,arg1,arg2);
-}
-}
-function emitThree(handler,isFn,self,arg1,arg2,arg3){
-if(isFn)
-handler.call(self,arg1,arg2,arg3);else
-{
-var len=handler.length;
-var listeners=arrayClone(handler,len);
-for(var i=0;i<len;++i)
-listeners[i].call(self,arg1,arg2,arg3);
-}
-}
-
-function emitMany(handler,isFn,self,args){
-if(isFn)
-handler.apply(self,args);else
-{
-var len=handler.length;
-var listeners=arrayClone(handler,len);
-for(var i=0;i<len;++i)
-listeners[i].apply(self,args);
-}
-}
-
-EventEmitter.prototype.emit=function emit(type){
-var er,handler,len,args,i,events;
-var doError=type==='error';
-
-events=this._events;
-if(events)
-doError=doError&&events.error==null;else
-if(!doError)
-return false;
-
-
-if(doError){
-if(arguments.length>1)
-er=arguments[1];
-if(er instanceof Error){
-throw er;
-}else{
-
-var err=new Error('Unhandled "error" event. ('+er+')');
-err.context=er;
-throw err;
-}
-return false;
-}
-
-handler=events[type];
-
-if(!handler)
-return false;
-
-var isFn=typeof handler==='function';
-len=arguments.length;
-switch(len){
-
-case 1:
-emitNone(handler,isFn,this);
-break;
-case 2:
-emitOne(handler,isFn,this,arguments[1]);
-break;
-case 3:
-emitTwo(handler,isFn,this,arguments[1],arguments[2]);
-break;
-case 4:
-emitThree(handler,isFn,this,arguments[1],arguments[2],arguments[3]);
-break;
-
-default:
-args=new Array(len-1);
-for(i=1;i<len;i++)
-args[i-1]=arguments[i];
-emitMany(handler,isFn,this,args);}
-
-
-return true;
-};
-
-function _addListener(target,type,listener,prepend){
-var m;
-var events;
-var existing;
-
-if(typeof listener!=='function')
-throw new TypeError('"listener" argument must be a function');
-
-events=target._events;
-if(!events){
-events=target._events=objectCreate(null);
-target._eventsCount=0;
-}else{
-
-
-if(events.newListener){
-target.emit('newListener',type,
-listener.listener?listener.listener:listener);
-
-
-
-events=target._events;
-}
-existing=events[type];
-}
-
-if(!existing){
-
-existing=events[type]=listener;
-++target._eventsCount;
-}else{
-if(typeof existing==='function'){
-
-existing=events[type]=
-prepend?[listener,existing]:[existing,listener];
-}else{
-
-if(prepend){
-existing.unshift(listener);
-}else{
-existing.push(listener);
-}
-}
-
-
-if(!existing.warned){
-m=$getMaxListeners(target);
-if(m&&m>0&&existing.length>m){
-existing.warned=true;
-var w=new Error('Possible EventEmitter memory leak detected. '+
-existing.length+' "'+String(type)+'" listeners '+
-'added. Use emitter.setMaxListeners() to '+
-'increase limit.');
-w.name='MaxListenersExceededWarning';
-w.emitter=target;
-w.type=type;
-w.count=existing.length;
-if(typeof console==='object'&&console.warn){
-console.warn('%s: %s',w.name,w.message);
-}
-}
-}
-}
-
-return target;
-}
-
-EventEmitter.prototype.addListener=function addListener(type,listener){
-return _addListener(this,type,listener,false);
-};
-
-EventEmitter.prototype.on=EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.prependListener=
-function prependListener(type,listener){
-return _addListener(this,type,listener,true);
-};
-
-function onceWrapper(){
-if(!this.fired){
-this.target.removeListener(this.type,this.wrapFn);
-this.fired=true;
-switch(arguments.length){
-case 0:
-return this.listener.call(this.target);
-case 1:
-return this.listener.call(this.target,arguments[0]);
-case 2:
-return this.listener.call(this.target,arguments[0],arguments[1]);
-case 3:
-return this.listener.call(this.target,arguments[0],arguments[1],
-arguments[2]);
-default:
-var args=new Array(arguments.length);
-for(var i=0;i<args.length;++i)
-args[i]=arguments[i];
-this.listener.apply(this.target,args);}
-
-}
-}
-
-function _onceWrap(target,type,listener){
-var state={fired:false,wrapFn:undefined,target:target,type:type,listener:listener};
-var wrapped=bind.call(onceWrapper,state);
-wrapped.listener=listener;
-state.wrapFn=wrapped;
-return wrapped;
-}
-
-EventEmitter.prototype.once=function once(type,listener){
-if(typeof listener!=='function')
-throw new TypeError('"listener" argument must be a function');
-this.on(type,_onceWrap(this,type,listener));
-return this;
-};
-
-EventEmitter.prototype.prependOnceListener=
-function prependOnceListener(type,listener){
-if(typeof listener!=='function')
-throw new TypeError('"listener" argument must be a function');
-this.prependListener(type,_onceWrap(this,type,listener));
-return this;
-};
-
-
-EventEmitter.prototype.removeListener=
-function removeListener(type,listener){
-var list,events,position,i,originalListener;
-
-if(typeof listener!=='function')
-throw new TypeError('"listener" argument must be a function');
-
-events=this._events;
-if(!events)
-return this;
-
-list=events[type];
-if(!list)
-return this;
-
-if(list===listener||list.listener===listener){
-if(--this._eventsCount===0)
-this._events=objectCreate(null);else
-{
-delete events[type];
-if(events.removeListener)
-this.emit('removeListener',type,list.listener||listener);
-}
-}else if(typeof list!=='function'){
-position=-1;
-
-for(i=list.length-1;i>=0;i--){
-if(list[i]===listener||list[i].listener===listener){
-originalListener=list[i].listener;
-position=i;
-break;
-}
-}
-
-if(position<0)
-return this;
-
-if(position===0)
-list.shift();else
-
-spliceOne(list,position);
-
-if(list.length===1)
-events[type]=list[0];
-
-if(events.removeListener)
-this.emit('removeListener',type,originalListener||listener);
-}
-
-return this;
-};
-
-EventEmitter.prototype.removeAllListeners=
-function removeAllListeners(type){
-var listeners,events,i;
-
-events=this._events;
-if(!events)
-return this;
-
-
-if(!events.removeListener){
-if(arguments.length===0){
-this._events=objectCreate(null);
-this._eventsCount=0;
-}else if(events[type]){
-if(--this._eventsCount===0)
-this._events=objectCreate(null);else
-
-delete events[type];
-}
-return this;
-}
-
-
-if(arguments.length===0){
-var keys=objectKeys(events);
-var key;
-for(i=0;i<keys.length;++i){
-key=keys[i];
-if(key==='removeListener')continue;
-this.removeAllListeners(key);
-}
-this.removeAllListeners('removeListener');
-this._events=objectCreate(null);
-this._eventsCount=0;
-return this;
-}
-
-listeners=events[type];
-
-if(typeof listeners==='function'){
-this.removeListener(type,listeners);
-}else if(listeners){
-
-for(i=listeners.length-1;i>=0;i--){
-this.removeListener(type,listeners[i]);
-}
-}
-
-return this;
-};
-
-EventEmitter.prototype.listeners=function listeners(type){
-var evlistener;
-var ret;
-var events=this._events;
-
-if(!events)
-ret=[];else
-{
-evlistener=events[type];
-if(!evlistener)
-ret=[];else
-if(typeof evlistener==='function')
-ret=[evlistener.listener||evlistener];else
-
-ret=unwrapListeners(evlistener);
-}
-
-return ret;
-};
-
-EventEmitter.listenerCount=function(emitter,type){
-if(typeof emitter.listenerCount==='function'){
-return emitter.listenerCount(type);
-}else{
-return listenerCount.call(emitter,type);
-}
-};
-
-EventEmitter.prototype.listenerCount=listenerCount;
-function listenerCount(type){
-var events=this._events;
-
-if(events){
-var evlistener=events[type];
-
-if(typeof evlistener==='function'){
-return 1;
-}else if(evlistener){
-return evlistener.length;
-}
-}
-
-return 0;
-}
-
-EventEmitter.prototype.eventNames=function eventNames(){
-return this._eventsCount>0?Reflect.ownKeys(this._events):[];
-};
-
-
-function spliceOne(list,index){
-for(var i=index,k=i+1,n=list.length;k<n;i+=1,k+=1)
-list[i]=list[k];
-list.pop();
-}
-
-function arrayClone(arr,n){
-var copy=new Array(n);
-for(var i=0;i<n;++i)
-copy[i]=arr[i];
-return copy;
-}
-
-function unwrapListeners(arr){
-var ret=new Array(arr.length);
-for(var i=0;i<ret.length;++i){
-ret[i]=arr[i].listener||arr[i];
-}
-return ret;
-}
-
-function objectCreatePolyfill(proto){
-var F=function(){};
-F.prototype=proto;
-return new F();
-}
-function objectKeysPolyfill(obj){
-var keys=[];
-for(var k in obj)if(Object.prototype.hasOwnProperty.call(obj,k)){
-keys.push(k);
-}
-return k;
-}
-function functionBindPolyfill(context){
-var fn=this;
-return function(){
-return fn.apply(context,arguments);
-};
-}
-
-},{}],112:[function(require,module,exports){
-exports.read=function(buffer,offset,isLE,mLen,nBytes){
-var e,m;
-var eLen=nBytes*8-mLen-1;
-var eMax=(1<<eLen)-1;
-var eBias=eMax>>1;
-var nBits=-7;
-var i=isLE?nBytes-1:0;
-var d=isLE?-1:1;
-var s=buffer[offset+i];
-
-i+=d;
-
-e=s&(1<<-nBits)-1;
-s>>=-nBits;
-nBits+=eLen;
-for(;nBits>0;e=e*256+buffer[offset+i],i+=d,nBits-=8){}
-
-m=e&(1<<-nBits)-1;
-e>>=-nBits;
-nBits+=mLen;
-for(;nBits>0;m=m*256+buffer[offset+i],i+=d,nBits-=8){}
-
-if(e===0){
-e=1-eBias;
-}else if(e===eMax){
-return m?NaN:(s?-1:1)*Infinity;
-}else{
-m=m+Math.pow(2,mLen);
-e=e-eBias;
-}
-return(s?-1:1)*m*Math.pow(2,e-mLen);
-};
-
-exports.write=function(buffer,value,offset,isLE,mLen,nBytes){
-var e,m,c;
-var eLen=nBytes*8-mLen-1;
-var eMax=(1<<eLen)-1;
-var eBias=eMax>>1;
-var rt=mLen===23?Math.pow(2,-24)-Math.pow(2,-77):0;
-var i=isLE?0:nBytes-1;
-var d=isLE?1:-1;
-var s=value<0||value===0&&1/value<0?1:0;
-
-value=Math.abs(value);
-
-if(isNaN(value)||value===Infinity){
-m=isNaN(value)?1:0;
-e=eMax;
-}else{
-e=Math.floor(Math.log(value)/Math.LN2);
-if(value*(c=Math.pow(2,-e))<1){
-e--;
-c*=2;
-}
-if(e+eBias>=1){
-value+=rt/c;
-}else{
-value+=rt*Math.pow(2,1-eBias);
-}
-if(value*c>=2){
-e++;
-c/=2;
-}
-
-if(e+eBias>=eMax){
-m=0;
-e=eMax;
-}else if(e+eBias>=1){
-m=(value*c-1)*Math.pow(2,mLen);
-e=e+eBias;
-}else{
-m=value*Math.pow(2,eBias-1)*Math.pow(2,mLen);
-e=0;
-}
-}
-
-for(;mLen>=8;buffer[offset+i]=m&0xff,i+=d,m/=256,mLen-=8){}
-
-e=e<<mLen|m;
-eLen+=mLen;
-for(;eLen>0;buffer[offset+i]=e&0xff,i+=d,e/=256,eLen-=8){}
-
-buffer[offset+i-d]|=s*128;
-};
-
-},{}],113:[function(require,module,exports){
-if(typeof Object.create==='function'){
-
-module.exports=function inherits(ctor,superCtor){
-ctor.super_=superCtor;
-ctor.prototype=Object.create(superCtor.prototype,{
-constructor:{
-value:ctor,
-enumerable:false,
-writable:true,
-configurable:true}});
-
-
-};
-}else{
-
-module.exports=function inherits(ctor,superCtor){
-ctor.super_=superCtor;
-var TempCtor=function(){};
-TempCtor.prototype=superCtor.prototype;
-ctor.prototype=new TempCtor();
-ctor.prototype.constructor=ctor;
-};
-}
-
-},{}],114:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-module.exports=function(obj){
-return obj!=null&&(isBuffer(obj)||isSlowBuffer(obj)||!!obj._isBuffer);
-};
-
-function isBuffer(obj){
-return!!obj.constructor&&typeof obj.constructor.isBuffer==='function'&&obj.constructor.isBuffer(obj);
-}
-
-
-function isSlowBuffer(obj){
-return typeof obj.readFloatLE==='function'&&typeof obj.slice==='function'&&isBuffer(obj.slice(0,0));
-}
-
-},{}],115:[function(require,module,exports){
-var toString={}.toString;
-
-module.exports=Array.isArray||function(arr){
-return toString.call(arr)=='[object Array]';
-};
-
-},{}],116:[function(require,module,exports){
-'use strict';
-
-
-var TYPED_OK=typeof Uint8Array!=='undefined'&&
-typeof Uint16Array!=='undefined'&&
-typeof Int32Array!=='undefined';
-
-function _has(obj,key){
-return Object.prototype.hasOwnProperty.call(obj,key);
-}
-
-exports.assign=function(obj){
-var sources=Array.prototype.slice.call(arguments,1);
-while(sources.length){
-var source=sources.shift();
-if(!source){continue;}
-
-if(typeof source!=='object'){
-throw new TypeError(source+'must be non-object');
-}
-
-for(var p in source){
-if(_has(source,p)){
-obj[p]=source[p];
-}
-}
-}
-
-return obj;
-};
-
-
-
-exports.shrinkBuf=function(buf,size){
-if(buf.length===size){return buf;}
-if(buf.subarray){return buf.subarray(0,size);}
-buf.length=size;
-return buf;
-};
-
-
-var fnTyped={
-arraySet:function(dest,src,src_offs,len,dest_offs){
-if(src.subarray&&dest.subarray){
-dest.set(src.subarray(src_offs,src_offs+len),dest_offs);
-return;
-}
-
-for(var i=0;i<len;i++){
-dest[dest_offs+i]=src[src_offs+i];
-}
-},
-
-flattenChunks:function(chunks){
-var i,l,len,pos,chunk,result;
-
-
-len=0;
-for(i=0,l=chunks.length;i<l;i++){
-len+=chunks[i].length;
-}
-
-
-result=new Uint8Array(len);
-pos=0;
-for(i=0,l=chunks.length;i<l;i++){
-chunk=chunks[i];
-result.set(chunk,pos);
-pos+=chunk.length;
-}
-
-return result;
-}};
-
-
-var fnUntyped={
-arraySet:function(dest,src,src_offs,len,dest_offs){
-for(var i=0;i<len;i++){
-dest[dest_offs+i]=src[src_offs+i];
-}
-},
-
-flattenChunks:function(chunks){
-return[].concat.apply([],chunks);
-}};
-
-
-
-
-
-exports.setTyped=function(on){
-if(on){
-exports.Buf8=Uint8Array;
-exports.Buf16=Uint16Array;
-exports.Buf32=Int32Array;
-exports.assign(exports,fnTyped);
-}else{
-exports.Buf8=Array;
-exports.Buf16=Array;
-exports.Buf32=Array;
-exports.assign(exports,fnUntyped);
-}
-};
-
-exports.setTyped(TYPED_OK);
-
-},{}],117:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function adler32(adler,buf,len,pos){
-var s1=adler&0xffff|0,
-s2=adler>>>16&0xffff|0,
-n=0;
-
-while(len!==0){
-
-
-
-n=len>2000?2000:len;
-len-=n;
-
-do{
-s1=s1+buf[pos++]|0;
-s2=s2+s1|0;
-}while(--n);
-
-s1%=65521;
-s2%=65521;
-}
-
-return s1|s2<<16|0;
-}
-
-
-module.exports=adler32;
-
-},{}],118:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-module.exports={
-
-
-Z_NO_FLUSH:0,
-Z_PARTIAL_FLUSH:1,
-Z_SYNC_FLUSH:2,
-Z_FULL_FLUSH:3,
-Z_FINISH:4,
-Z_BLOCK:5,
-Z_TREES:6,
-
-
-
-
-Z_OK:0,
-Z_STREAM_END:1,
-Z_NEED_DICT:2,
-Z_ERRNO:-1,
-Z_STREAM_ERROR:-2,
-Z_DATA_ERROR:-3,
-
-Z_BUF_ERROR:-5,
-
-
-
-Z_NO_COMPRESSION:0,
-Z_BEST_SPEED:1,
-Z_BEST_COMPRESSION:9,
-Z_DEFAULT_COMPRESSION:-1,
-
-
-Z_FILTERED:1,
-Z_HUFFMAN_ONLY:2,
-Z_RLE:3,
-Z_FIXED:4,
-Z_DEFAULT_STRATEGY:0,
-
-
-Z_BINARY:0,
-Z_TEXT:1,
-
-Z_UNKNOWN:2,
-
-
-Z_DEFLATED:8};
-
-
-
-},{}],119:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function makeTable(){
-var c,table=[];
-
-for(var n=0;n<256;n++){
-c=n;
-for(var k=0;k<8;k++){
-c=c&1?0xEDB88320^c>>>1:c>>>1;
-}
-table[n]=c;
-}
-
-return table;
-}
-
-
-var crcTable=makeTable();
-
-
-function crc32(crc,buf,len,pos){
-var t=crcTable,
-end=pos+len;
-
-crc^=-1;
-
-for(var i=pos;i<end;i++){
-crc=crc>>>8^t[(crc^buf[i])&0xFF];
-}
-
-return crc^-1;
-}
-
-
-module.exports=crc32;
-
-},{}],120:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var utils=require('../utils/common');
-var trees=require('./trees');
-var adler32=require('./adler32');
-var crc32=require('./crc32');
-var msg=require('./messages');
-
-
-
-
-
-
-var Z_NO_FLUSH=0;
-var Z_PARTIAL_FLUSH=1;
-
-var Z_FULL_FLUSH=3;
-var Z_FINISH=4;
-var Z_BLOCK=5;
-
-
-
-
-
-
-var Z_OK=0;
-var Z_STREAM_END=1;
-
-
-var Z_STREAM_ERROR=-2;
-var Z_DATA_ERROR=-3;
-
-var Z_BUF_ERROR=-5;
-
-
-
-
-
-
-
-var Z_DEFAULT_COMPRESSION=-1;
-
-
-var Z_FILTERED=1;
-var Z_HUFFMAN_ONLY=2;
-var Z_RLE=3;
-var Z_FIXED=4;
-var Z_DEFAULT_STRATEGY=0;
-
-
-
-
-
-var Z_UNKNOWN=2;
-
-
-
-var Z_DEFLATED=8;
-
-
-
-
-var MAX_MEM_LEVEL=9;
-
-var MAX_WBITS=15;
-
-var DEF_MEM_LEVEL=8;
-
-
-var LENGTH_CODES=29;
-
-var LITERALS=256;
-
-var L_CODES=LITERALS+1+LENGTH_CODES;
-
-var D_CODES=30;
-
-var BL_CODES=19;
-
-var HEAP_SIZE=2*L_CODES+1;
-
-var MAX_BITS=15;
-
-
-var MIN_MATCH=3;
-var MAX_MATCH=258;
-var MIN_LOOKAHEAD=MAX_MATCH+MIN_MATCH+1;
-
-var PRESET_DICT=0x20;
-
-var INIT_STATE=42;
-var EXTRA_STATE=69;
-var NAME_STATE=73;
-var COMMENT_STATE=91;
-var HCRC_STATE=103;
-var BUSY_STATE=113;
-var FINISH_STATE=666;
-
-var BS_NEED_MORE=1;
-var BS_BLOCK_DONE=2;
-var BS_FINISH_STARTED=3;
-var BS_FINISH_DONE=4;
-
-var OS_CODE=0x03;
-
-function err(strm,errorCode){
-strm.msg=msg[errorCode];
-return errorCode;
-}
-
-function rank(f){
-return(f<<1)-(f>4?9:0);
-}
-
-function zero(buf){var len=buf.length;while(--len>=0){buf[len]=0;}}
-
-
-
-
-
-
-
-
-function flush_pending(strm){
-var s=strm.state;
-
-
-var len=s.pending;
-if(len>strm.avail_out){
-len=strm.avail_out;
-}
-if(len===0){return;}
-
-utils.arraySet(strm.output,s.pending_buf,s.pending_out,len,strm.next_out);
-strm.next_out+=len;
-s.pending_out+=len;
-strm.total_out+=len;
-strm.avail_out-=len;
-s.pending-=len;
-if(s.pending===0){
-s.pending_out=0;
-}
-}
-
-
-function flush_block_only(s,last){
-trees._tr_flush_block(s,s.block_start>=0?s.block_start:-1,s.strstart-s.block_start,last);
-s.block_start=s.strstart;
-flush_pending(s.strm);
-}
-
-
-function put_byte(s,b){
-s.pending_buf[s.pending++]=b;
-}
-
-
-
-
-
-
-
-function putShortMSB(s,b){
-
-
-s.pending_buf[s.pending++]=b>>>8&0xff;
-s.pending_buf[s.pending++]=b&0xff;
-}
-
-
-
-
-
-
-
-
-
-function read_buf(strm,buf,start,size){
-var len=strm.avail_in;
-
-if(len>size){len=size;}
-if(len===0){return 0;}
-
-strm.avail_in-=len;
-
-
-utils.arraySet(buf,strm.input,strm.next_in,len,start);
-if(strm.state.wrap===1){
-strm.adler=adler32(strm.adler,buf,len,start);
-}else
-
-if(strm.state.wrap===2){
-strm.adler=crc32(strm.adler,buf,len,start);
-}
-
-strm.next_in+=len;
-strm.total_in+=len;
-
-return len;
-}
-
-
-
-
-
-
-
-
-
-
-
-function longest_match(s,cur_match){
-var chain_length=s.max_chain_length;
-var scan=s.strstart;
-var match;
-var len;
-var best_len=s.prev_length;
-var nice_match=s.nice_match;
-var limit=s.strstart>s.w_size-MIN_LOOKAHEAD?
-s.strstart-(s.w_size-MIN_LOOKAHEAD):0;
-
-var _win=s.window;
-
-var wmask=s.w_mask;
-var prev=s.prev;
-
-
-
-
-
-var strend=s.strstart+MAX_MATCH;
-var scan_end1=_win[scan+best_len-1];
-var scan_end=_win[scan+best_len];
-
-
-
-
-
-
-
-if(s.prev_length>=s.good_match){
-chain_length>>=2;
-}
-
-
-
-if(nice_match>s.lookahead){nice_match=s.lookahead;}
-
-
-
-do{
-
-match=cur_match;
-
-
-
-
-
-
-
-
-
-
-if(_win[match+best_len]!==scan_end||
-_win[match+best_len-1]!==scan_end1||
-_win[match]!==_win[scan]||
-_win[++match]!==_win[scan+1]){
-continue;
-}
-
-
-
-
-
-
-
-scan+=2;
-match++;
-
-
-
-
-
-do{
-
-}while(_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
-_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
-_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
-_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
-scan<strend);
-
-
-
-len=MAX_MATCH-(strend-scan);
-scan=strend-MAX_MATCH;
-
-if(len>best_len){
-s.match_start=cur_match;
-best_len=len;
-if(len>=nice_match){
-break;
-}
-scan_end1=_win[scan+best_len-1];
-scan_end=_win[scan+best_len];
-}
-}while((cur_match=prev[cur_match&wmask])>limit&&--chain_length!==0);
-
-if(best_len<=s.lookahead){
-return best_len;
-}
-return s.lookahead;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-function fill_window(s){
-var _w_size=s.w_size;
-var p,n,m,more,str;
-
-
-
-do{
-more=s.window_size-s.lookahead-s.strstart;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-if(s.strstart>=_w_size+(_w_size-MIN_LOOKAHEAD)){
-
-utils.arraySet(s.window,s.window,_w_size,_w_size,0);
-s.match_start-=_w_size;
-s.strstart-=_w_size;
-
-s.block_start-=_w_size;
-
-
-
-
-
-
-
-
-n=s.hash_size;
-p=n;
-do{
-m=s.head[--p];
-s.head[p]=m>=_w_size?m-_w_size:0;
-}while(--n);
-
-n=_w_size;
-p=n;
-do{
-m=s.prev[--p];
-s.prev[p]=m>=_w_size?m-_w_size:0;
-
-
-
-}while(--n);
-
-more+=_w_size;
-}
-if(s.strm.avail_in===0){
-break;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-n=read_buf(s.strm,s.window,s.strstart+s.lookahead,more);
-s.lookahead+=n;
-
-
-if(s.lookahead+s.insert>=MIN_MATCH){
-str=s.strstart-s.insert;
-s.ins_h=s.window[str];
-
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[str+1])&s.hash_mask;
-
-
-
-while(s.insert){
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[str+MIN_MATCH-1])&s.hash_mask;
-
-s.prev[str&s.w_mask]=s.head[s.ins_h];
-s.head[s.ins_h]=str;
-str++;
-s.insert--;
-if(s.lookahead+s.insert<MIN_MATCH){
-break;
-}
-}
-}
-
-
-
-
-}while(s.lookahead<MIN_LOOKAHEAD&&s.strm.avail_in!==0);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-
-
-
-
-
-
-
-
-
-function deflate_stored(s,flush){
-
-
-
-var max_block_size=0xffff;
-
-if(max_block_size>s.pending_buf_size-5){
-max_block_size=s.pending_buf_size-5;
-}
-
-
-for(;;){
-
-if(s.lookahead<=1){
-
-
-
-
-
-
-
-
-fill_window(s);
-if(s.lookahead===0&&flush===Z_NO_FLUSH){
-return BS_NEED_MORE;
-}
-
-if(s.lookahead===0){
-break;
-}
-
-}
-
-
-
-s.strstart+=s.lookahead;
-s.lookahead=0;
-
-
-var max_start=s.block_start+max_block_size;
-
-if(s.strstart===0||s.strstart>=max_start){
-
-s.lookahead=s.strstart-max_start;
-s.strstart=max_start;
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-
-
-}
-
-
-
-if(s.strstart-s.block_start>=s.w_size-MIN_LOOKAHEAD){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-}
-
-s.insert=0;
-
-if(flush===Z_FINISH){
-
-flush_block_only(s,true);
-if(s.strm.avail_out===0){
-return BS_FINISH_STARTED;
-}
-
-return BS_FINISH_DONE;
-}
-
-if(s.strstart>s.block_start){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-
-return BS_NEED_MORE;
-}
-
-
-
-
-
-
-
-
-function deflate_fast(s,flush){
-var hash_head;
-var bflush;
-
-for(;;){
-
-
-
-
-
-if(s.lookahead<MIN_LOOKAHEAD){
-fill_window(s);
-if(s.lookahead<MIN_LOOKAHEAD&&flush===Z_NO_FLUSH){
-return BS_NEED_MORE;
-}
-if(s.lookahead===0){
-break;
-}
-}
-
-
-
-
-hash_head=0;
-if(s.lookahead>=MIN_MATCH){
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
-hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
-s.head[s.ins_h]=s.strstart;
-
-}
-
-
-
-
-if(hash_head!==0&&s.strstart-hash_head<=s.w_size-MIN_LOOKAHEAD){
-
-
-
-
-s.match_length=longest_match(s,hash_head);
-
-}
-if(s.match_length>=MIN_MATCH){
-
-
-
-
-bflush=trees._tr_tally(s,s.strstart-s.match_start,s.match_length-MIN_MATCH);
-
-s.lookahead-=s.match_length;
-
-
-
-
-if(s.match_length<=s.max_lazy_match&&s.lookahead>=MIN_MATCH){
-s.match_length--;
-do{
-s.strstart++;
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
-hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
-s.head[s.ins_h]=s.strstart;
-
-
-
-
-}while(--s.match_length!==0);
-s.strstart++;
-}else
-{
-s.strstart+=s.match_length;
-s.match_length=0;
-s.ins_h=s.window[s.strstart];
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+1])&s.hash_mask;
-
-
-
-
-
-
-
-}
-}else{
-
-
-
-bflush=trees._tr_tally(s,0,s.window[s.strstart]);
-
-s.lookahead--;
-s.strstart++;
-}
-if(bflush){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-}
-s.insert=s.strstart<MIN_MATCH-1?s.strstart:MIN_MATCH-1;
-if(flush===Z_FINISH){
-
-flush_block_only(s,true);
-if(s.strm.avail_out===0){
-return BS_FINISH_STARTED;
-}
-
-return BS_FINISH_DONE;
-}
-if(s.last_lit){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-return BS_BLOCK_DONE;
-}
-
-
-
-
-
-
-function deflate_slow(s,flush){
-var hash_head;
-var bflush;
-
-var max_insert;
-
-
-for(;;){
-
-
-
-
-
-if(s.lookahead<MIN_LOOKAHEAD){
-fill_window(s);
-if(s.lookahead<MIN_LOOKAHEAD&&flush===Z_NO_FLUSH){
-return BS_NEED_MORE;
-}
-if(s.lookahead===0){break;}
-}
-
-
-
-
-hash_head=0;
-if(s.lookahead>=MIN_MATCH){
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
-hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
-s.head[s.ins_h]=s.strstart;
-
-}
-
-
-
-s.prev_length=s.match_length;
-s.prev_match=s.match_start;
-s.match_length=MIN_MATCH-1;
-
-if(hash_head!==0&&s.prev_length<s.max_lazy_match&&
-s.strstart-hash_head<=s.w_size-MIN_LOOKAHEAD){
-
-
-
-
-s.match_length=longest_match(s,hash_head);
-
-
-if(s.match_length<=5&&(
-s.strategy===Z_FILTERED||s.match_length===MIN_MATCH&&s.strstart-s.match_start>4096)){
-
-
-
-
-s.match_length=MIN_MATCH-1;
-}
-}
-
-
-
-if(s.prev_length>=MIN_MATCH&&s.match_length<=s.prev_length){
-max_insert=s.strstart+s.lookahead-MIN_MATCH;
-
-
-
-
-
-
-bflush=trees._tr_tally(s,s.strstart-1-s.prev_match,s.prev_length-MIN_MATCH);
-
-
-
-
-
-s.lookahead-=s.prev_length-1;
-s.prev_length-=2;
-do{
-if(++s.strstart<=max_insert){
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
-hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
-s.head[s.ins_h]=s.strstart;
-
-}
-}while(--s.prev_length!==0);
-s.match_available=0;
-s.match_length=MIN_MATCH-1;
-s.strstart++;
-
-if(bflush){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-
-}else if(s.match_available){
-
-
-
-
-
-
-bflush=trees._tr_tally(s,0,s.window[s.strstart-1]);
-
-if(bflush){
-
-flush_block_only(s,false);
-
-}
-s.strstart++;
-s.lookahead--;
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-}else{
-
-
-
-s.match_available=1;
-s.strstart++;
-s.lookahead--;
-}
-}
-
-if(s.match_available){
-
-
-bflush=trees._tr_tally(s,0,s.window[s.strstart-1]);
-
-s.match_available=0;
-}
-s.insert=s.strstart<MIN_MATCH-1?s.strstart:MIN_MATCH-1;
-if(flush===Z_FINISH){
-
-flush_block_only(s,true);
-if(s.strm.avail_out===0){
-return BS_FINISH_STARTED;
-}
-
-return BS_FINISH_DONE;
-}
-if(s.last_lit){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-
-return BS_BLOCK_DONE;
-}
-
-
-
-
-
-
-
-function deflate_rle(s,flush){
-var bflush;
-var prev;
-var scan,strend;
-
-var _win=s.window;
-
-for(;;){
-
-
-
-
-if(s.lookahead<=MAX_MATCH){
-fill_window(s);
-if(s.lookahead<=MAX_MATCH&&flush===Z_NO_FLUSH){
-return BS_NEED_MORE;
-}
-if(s.lookahead===0){break;}
-}
-
-
-s.match_length=0;
-if(s.lookahead>=MIN_MATCH&&s.strstart>0){
-scan=s.strstart-1;
-prev=_win[scan];
-if(prev===_win[++scan]&&prev===_win[++scan]&&prev===_win[++scan]){
-strend=s.strstart+MAX_MATCH;
-do{
-
-}while(prev===_win[++scan]&&prev===_win[++scan]&&
-prev===_win[++scan]&&prev===_win[++scan]&&
-prev===_win[++scan]&&prev===_win[++scan]&&
-prev===_win[++scan]&&prev===_win[++scan]&&
-scan<strend);
-s.match_length=MAX_MATCH-(strend-scan);
-if(s.match_length>s.lookahead){
-s.match_length=s.lookahead;
-}
-}
-
-}
-
-
-if(s.match_length>=MIN_MATCH){
-
-
-
-bflush=trees._tr_tally(s,1,s.match_length-MIN_MATCH);
-
-s.lookahead-=s.match_length;
-s.strstart+=s.match_length;
-s.match_length=0;
-}else{
-
-
-
-bflush=trees._tr_tally(s,0,s.window[s.strstart]);
-
-s.lookahead--;
-s.strstart++;
-}
-if(bflush){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-}
-s.insert=0;
-if(flush===Z_FINISH){
-
-flush_block_only(s,true);
-if(s.strm.avail_out===0){
-return BS_FINISH_STARTED;
-}
-
-return BS_FINISH_DONE;
-}
-if(s.last_lit){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-return BS_BLOCK_DONE;
-}
-
-
-
-
-
-function deflate_huff(s,flush){
-var bflush;
-
-for(;;){
-
-if(s.lookahead===0){
-fill_window(s);
-if(s.lookahead===0){
-if(flush===Z_NO_FLUSH){
-return BS_NEED_MORE;
-}
-break;
-}
-}
-
-
-s.match_length=0;
-
-
-bflush=trees._tr_tally(s,0,s.window[s.strstart]);
-s.lookahead--;
-s.strstart++;
-if(bflush){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-}
-s.insert=0;
-if(flush===Z_FINISH){
-
-flush_block_only(s,true);
-if(s.strm.avail_out===0){
-return BS_FINISH_STARTED;
-}
-
-return BS_FINISH_DONE;
-}
-if(s.last_lit){
-
-flush_block_only(s,false);
-if(s.strm.avail_out===0){
-return BS_NEED_MORE;
-}
-
-}
-return BS_BLOCK_DONE;
-}
-
-
-
-
-
-
-function Config(good_length,max_lazy,nice_length,max_chain,func){
-this.good_length=good_length;
-this.max_lazy=max_lazy;
-this.nice_length=nice_length;
-this.max_chain=max_chain;
-this.func=func;
-}
-
-var configuration_table;
-
-configuration_table=[
-
-new Config(0,0,0,0,deflate_stored),
-new Config(4,4,8,4,deflate_fast),
-new Config(4,5,16,8,deflate_fast),
-new Config(4,6,32,32,deflate_fast),
-
-new Config(4,4,16,16,deflate_slow),
-new Config(8,16,32,32,deflate_slow),
-new Config(8,16,128,128,deflate_slow),
-new Config(8,32,128,256,deflate_slow),
-new Config(32,128,258,1024,deflate_slow),
-new Config(32,258,258,4096,deflate_slow)];
-
-
-
-
-
-
-function lm_init(s){
-s.window_size=2*s.w_size;
-
-
-zero(s.head);
-
-
-
-s.max_lazy_match=configuration_table[s.level].max_lazy;
-s.good_match=configuration_table[s.level].good_length;
-s.nice_match=configuration_table[s.level].nice_length;
-s.max_chain_length=configuration_table[s.level].max_chain;
-
-s.strstart=0;
-s.block_start=0;
-s.lookahead=0;
-s.insert=0;
-s.match_length=s.prev_length=MIN_MATCH-1;
-s.match_available=0;
-s.ins_h=0;
-}
-
-
-function DeflateState(){
-this.strm=null;
-this.status=0;
-this.pending_buf=null;
-this.pending_buf_size=0;
-this.pending_out=0;
-this.pending=0;
-this.wrap=0;
-this.gzhead=null;
-this.gzindex=0;
-this.method=Z_DEFLATED;
-this.last_flush=-1;
-
-this.w_size=0;
-this.w_bits=0;
-this.w_mask=0;
-
-this.window=null;
-
-
-
-
-
-
-
-this.window_size=0;
-
-
-
-
-this.prev=null;
-
-
-
-
-
-this.head=null;
-
-this.ins_h=0;
-this.hash_size=0;
-this.hash_bits=0;
-this.hash_mask=0;
-
-this.hash_shift=0;
-
-
-
-
-
-
-this.block_start=0;
-
-
-
-
-this.match_length=0;
-this.prev_match=0;
-this.match_available=0;
-this.strstart=0;
-this.match_start=0;
-this.lookahead=0;
-
-this.prev_length=0;
-
-
-
-
-this.max_chain_length=0;
-
-
-
-
-
-this.max_lazy_match=0;
-
-
-
-
-
-
-
-
-
-
-
-this.level=0;
-this.strategy=0;
-
-this.good_match=0;
-
-
-this.nice_match=0;
-
-
-
-
-
-
-
-
-
-
-
-this.dyn_ltree=new utils.Buf16(HEAP_SIZE*2);
-this.dyn_dtree=new utils.Buf16((2*D_CODES+1)*2);
-this.bl_tree=new utils.Buf16((2*BL_CODES+1)*2);
-zero(this.dyn_ltree);
-zero(this.dyn_dtree);
-zero(this.bl_tree);
-
-this.l_desc=null;
-this.d_desc=null;
-this.bl_desc=null;
-
-
-this.bl_count=new utils.Buf16(MAX_BITS+1);
-
-
-
-this.heap=new utils.Buf16(2*L_CODES+1);
-zero(this.heap);
-
-this.heap_len=0;
-this.heap_max=0;
-
-
-
-
-this.depth=new utils.Buf16(2*L_CODES+1);
-zero(this.depth);
-
-
-
-this.l_buf=0;
-
-this.lit_bufsize=0;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-this.last_lit=0;
-
-this.d_buf=0;
-
-
-
-
-
-this.opt_len=0;
-this.static_len=0;
-this.matches=0;
-this.insert=0;
-
-
-this.bi_buf=0;
-
-
-
-this.bi_valid=0;
-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-
-function deflateResetKeep(strm){
-var s;
-
-if(!strm||!strm.state){
-return err(strm,Z_STREAM_ERROR);
-}
-
-strm.total_in=strm.total_out=0;
-strm.data_type=Z_UNKNOWN;
-
-s=strm.state;
-s.pending=0;
-s.pending_out=0;
-
-if(s.wrap<0){
-s.wrap=-s.wrap;
-
-}
-s.status=s.wrap?INIT_STATE:BUSY_STATE;
-strm.adler=s.wrap===2?
-0:
-
-1;
-s.last_flush=Z_NO_FLUSH;
-trees._tr_init(s);
-return Z_OK;
-}
-
-
-function deflateReset(strm){
-var ret=deflateResetKeep(strm);
-if(ret===Z_OK){
-lm_init(strm.state);
-}
-return ret;
-}
-
-
-function deflateSetHeader(strm,head){
-if(!strm||!strm.state){return Z_STREAM_ERROR;}
-if(strm.state.wrap!==2){return Z_STREAM_ERROR;}
-strm.state.gzhead=head;
-return Z_OK;
-}
-
-
-function deflateInit2(strm,level,method,windowBits,memLevel,strategy){
-if(!strm){
-return Z_STREAM_ERROR;
-}
-var wrap=1;
-
-if(level===Z_DEFAULT_COMPRESSION){
-level=6;
-}
-
-if(windowBits<0){
-wrap=0;
-windowBits=-windowBits;
-}else
-
-if(windowBits>15){
-wrap=2;
-windowBits-=16;
-}
-
-
-if(memLevel<1||memLevel>MAX_MEM_LEVEL||method!==Z_DEFLATED||
-windowBits<8||windowBits>15||level<0||level>9||
-strategy<0||strategy>Z_FIXED){
-return err(strm,Z_STREAM_ERROR);
-}
-
-
-if(windowBits===8){
-windowBits=9;
-}
-
-
-var s=new DeflateState();
-
-strm.state=s;
-s.strm=strm;
-
-s.wrap=wrap;
-s.gzhead=null;
-s.w_bits=windowBits;
-s.w_size=1<<s.w_bits;
-s.w_mask=s.w_size-1;
-
-s.hash_bits=memLevel+7;
-s.hash_size=1<<s.hash_bits;
-s.hash_mask=s.hash_size-1;
-s.hash_shift=~~((s.hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-s.window=new utils.Buf8(s.w_size*2);
-s.head=new utils.Buf16(s.hash_size);
-s.prev=new utils.Buf16(s.w_size);
-
-
-
-
-s.lit_bufsize=1<<memLevel+6;
-
-s.pending_buf_size=s.lit_bufsize*4;
-
-
-
-s.pending_buf=new utils.Buf8(s.pending_buf_size);
-
-
-
-s.d_buf=1*s.lit_bufsize;
-
-
-s.l_buf=(1+2)*s.lit_bufsize;
-
-s.level=level;
-s.strategy=strategy;
-s.method=method;
-
-return deflateReset(strm);
-}
-
-function deflateInit(strm,level){
-return deflateInit2(strm,level,Z_DEFLATED,MAX_WBITS,DEF_MEM_LEVEL,Z_DEFAULT_STRATEGY);
-}
-
-
-function deflate(strm,flush){
-var old_flush,s;
-var beg,val;
-
-if(!strm||!strm.state||
-flush>Z_BLOCK||flush<0){
-return strm?err(strm,Z_STREAM_ERROR):Z_STREAM_ERROR;
-}
-
-s=strm.state;
-
-if(!strm.output||
-!strm.input&&strm.avail_in!==0||
-s.status===FINISH_STATE&&flush!==Z_FINISH){
-return err(strm,strm.avail_out===0?Z_BUF_ERROR:Z_STREAM_ERROR);
-}
-
-s.strm=strm;
-old_flush=s.last_flush;
-s.last_flush=flush;
-
-
-if(s.status===INIT_STATE){
-
-if(s.wrap===2){
-strm.adler=0;
-put_byte(s,31);
-put_byte(s,139);
-put_byte(s,8);
-if(!s.gzhead){
-put_byte(s,0);
-put_byte(s,0);
-put_byte(s,0);
-put_byte(s,0);
-put_byte(s,0);
-put_byte(s,s.level===9?2:
-s.strategy>=Z_HUFFMAN_ONLY||s.level<2?
-4:0);
-put_byte(s,OS_CODE);
-s.status=BUSY_STATE;
-}else
-{
-put_byte(s,(s.gzhead.text?1:0)+(
-s.gzhead.hcrc?2:0)+(
-!s.gzhead.extra?0:4)+(
-!s.gzhead.name?0:8)+(
-!s.gzhead.comment?0:16));
-
-put_byte(s,s.gzhead.time&0xff);
-put_byte(s,s.gzhead.time>>8&0xff);
-put_byte(s,s.gzhead.time>>16&0xff);
-put_byte(s,s.gzhead.time>>24&0xff);
-put_byte(s,s.level===9?2:
-s.strategy>=Z_HUFFMAN_ONLY||s.level<2?
-4:0);
-put_byte(s,s.gzhead.os&0xff);
-if(s.gzhead.extra&&s.gzhead.extra.length){
-put_byte(s,s.gzhead.extra.length&0xff);
-put_byte(s,s.gzhead.extra.length>>8&0xff);
-}
-if(s.gzhead.hcrc){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending,0);
-}
-s.gzindex=0;
-s.status=EXTRA_STATE;
-}
-}else
-
-{
-var header=Z_DEFLATED+(s.w_bits-8<<4)<<8;
-var level_flags=-1;
-
-if(s.strategy>=Z_HUFFMAN_ONLY||s.level<2){
-level_flags=0;
-}else if(s.level<6){
-level_flags=1;
-}else if(s.level===6){
-level_flags=2;
-}else{
-level_flags=3;
-}
-header|=level_flags<<6;
-if(s.strstart!==0){header|=PRESET_DICT;}
-header+=31-header%31;
-
-s.status=BUSY_STATE;
-putShortMSB(s,header);
-
-
-if(s.strstart!==0){
-putShortMSB(s,strm.adler>>>16);
-putShortMSB(s,strm.adler&0xffff);
-}
-strm.adler=1;
-}
-}
-
-
-if(s.status===EXTRA_STATE){
-if(s.gzhead.extra){
-beg=s.pending;
-
-while(s.gzindex<(s.gzhead.extra.length&0xffff)){
-if(s.pending===s.pending_buf_size){
-if(s.gzhead.hcrc&&s.pending>beg){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
-}
-flush_pending(strm);
-beg=s.pending;
-if(s.pending===s.pending_buf_size){
-break;
-}
-}
-put_byte(s,s.gzhead.extra[s.gzindex]&0xff);
-s.gzindex++;
-}
-if(s.gzhead.hcrc&&s.pending>beg){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
-}
-if(s.gzindex===s.gzhead.extra.length){
-s.gzindex=0;
-s.status=NAME_STATE;
-}
-}else
-{
-s.status=NAME_STATE;
-}
-}
-if(s.status===NAME_STATE){
-if(s.gzhead.name){
-beg=s.pending;
-
-
-do{
-if(s.pending===s.pending_buf_size){
-if(s.gzhead.hcrc&&s.pending>beg){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
-}
-flush_pending(strm);
-beg=s.pending;
-if(s.pending===s.pending_buf_size){
-val=1;
-break;
-}
-}
-
-if(s.gzindex<s.gzhead.name.length){
-val=s.gzhead.name.charCodeAt(s.gzindex++)&0xff;
-}else{
-val=0;
-}
-put_byte(s,val);
-}while(val!==0);
-
-if(s.gzhead.hcrc&&s.pending>beg){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
-}
-if(val===0){
-s.gzindex=0;
-s.status=COMMENT_STATE;
-}
-}else
-{
-s.status=COMMENT_STATE;
-}
-}
-if(s.status===COMMENT_STATE){
-if(s.gzhead.comment){
-beg=s.pending;
-
-
-do{
-if(s.pending===s.pending_buf_size){
-if(s.gzhead.hcrc&&s.pending>beg){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
-}
-flush_pending(strm);
-beg=s.pending;
-if(s.pending===s.pending_buf_size){
-val=1;
-break;
-}
-}
-
-if(s.gzindex<s.gzhead.comment.length){
-val=s.gzhead.comment.charCodeAt(s.gzindex++)&0xff;
-}else{
-val=0;
-}
-put_byte(s,val);
-}while(val!==0);
-
-if(s.gzhead.hcrc&&s.pending>beg){
-strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
-}
-if(val===0){
-s.status=HCRC_STATE;
-}
-}else
-{
-s.status=HCRC_STATE;
-}
-}
-if(s.status===HCRC_STATE){
-if(s.gzhead.hcrc){
-if(s.pending+2>s.pending_buf_size){
-flush_pending(strm);
-}
-if(s.pending+2<=s.pending_buf_size){
-put_byte(s,strm.adler&0xff);
-put_byte(s,strm.adler>>8&0xff);
-strm.adler=0;
-s.status=BUSY_STATE;
-}
-}else
-{
-s.status=BUSY_STATE;
-}
-}
-
-
-
-if(s.pending!==0){
-flush_pending(strm);
-if(strm.avail_out===0){
-
-
-
-
-
-
-s.last_flush=-1;
-return Z_OK;
-}
-
-
-
-
-
-}else if(strm.avail_in===0&&rank(flush)<=rank(old_flush)&&
-flush!==Z_FINISH){
-return err(strm,Z_BUF_ERROR);
-}
-
-
-if(s.status===FINISH_STATE&&strm.avail_in!==0){
-return err(strm,Z_BUF_ERROR);
-}
-
-
-
-if(strm.avail_in!==0||s.lookahead!==0||
-flush!==Z_NO_FLUSH&&s.status!==FINISH_STATE){
-var bstate=s.strategy===Z_HUFFMAN_ONLY?deflate_huff(s,flush):
-s.strategy===Z_RLE?deflate_rle(s,flush):
-configuration_table[s.level].func(s,flush);
-
-if(bstate===BS_FINISH_STARTED||bstate===BS_FINISH_DONE){
-s.status=FINISH_STATE;
-}
-if(bstate===BS_NEED_MORE||bstate===BS_FINISH_STARTED){
-if(strm.avail_out===0){
-s.last_flush=-1;
-
-}
-return Z_OK;
-
-
-
-
-
-
-
-}
-if(bstate===BS_BLOCK_DONE){
-if(flush===Z_PARTIAL_FLUSH){
-trees._tr_align(s);
-}else
-if(flush!==Z_BLOCK){
-
-trees._tr_stored_block(s,0,0,false);
-
-
-
-if(flush===Z_FULL_FLUSH){
-
-zero(s.head);
-
-if(s.lookahead===0){
-s.strstart=0;
-s.block_start=0;
-s.insert=0;
-}
-}
-}
-flush_pending(strm);
-if(strm.avail_out===0){
-s.last_flush=-1;
-return Z_OK;
-}
-}
-}
-
-
-
-if(flush!==Z_FINISH){return Z_OK;}
-if(s.wrap<=0){return Z_STREAM_END;}
-
-
-if(s.wrap===2){
-put_byte(s,strm.adler&0xff);
-put_byte(s,strm.adler>>8&0xff);
-put_byte(s,strm.adler>>16&0xff);
-put_byte(s,strm.adler>>24&0xff);
-put_byte(s,strm.total_in&0xff);
-put_byte(s,strm.total_in>>8&0xff);
-put_byte(s,strm.total_in>>16&0xff);
-put_byte(s,strm.total_in>>24&0xff);
-}else
-
-{
-putShortMSB(s,strm.adler>>>16);
-putShortMSB(s,strm.adler&0xffff);
-}
-
-flush_pending(strm);
-
-
-
-if(s.wrap>0){s.wrap=-s.wrap;}
-
-return s.pending!==0?Z_OK:Z_STREAM_END;
-}
-
-function deflateEnd(strm){
-var status;
-
-if(!strm||!strm.state){
-return Z_STREAM_ERROR;
-}
-
-status=strm.state.status;
-if(status!==INIT_STATE&&
-status!==EXTRA_STATE&&
-status!==NAME_STATE&&
-status!==COMMENT_STATE&&
-status!==HCRC_STATE&&
-status!==BUSY_STATE&&
-status!==FINISH_STATE)
-{
-return err(strm,Z_STREAM_ERROR);
-}
-
-strm.state=null;
-
-return status===BUSY_STATE?err(strm,Z_DATA_ERROR):Z_OK;
-}
-
-
-
-
-
-
-function deflateSetDictionary(strm,dictionary){
-var dictLength=dictionary.length;
-
-var s;
-var str,n;
-var wrap;
-var avail;
-var next;
-var input;
-var tmpDict;
-
-if(!strm||!strm.state){
-return Z_STREAM_ERROR;
-}
-
-s=strm.state;
-wrap=s.wrap;
-
-if(wrap===2||wrap===1&&s.status!==INIT_STATE||s.lookahead){
-return Z_STREAM_ERROR;
-}
-
-
-if(wrap===1){
-
-strm.adler=adler32(strm.adler,dictionary,dictLength,0);
-}
-
-s.wrap=0;
-
-
-if(dictLength>=s.w_size){
-if(wrap===0){
-
-zero(s.head);
-s.strstart=0;
-s.block_start=0;
-s.insert=0;
-}
-
-
-tmpDict=new utils.Buf8(s.w_size);
-utils.arraySet(tmpDict,dictionary,dictLength-s.w_size,s.w_size,0);
-dictionary=tmpDict;
-dictLength=s.w_size;
-}
-
-avail=strm.avail_in;
-next=strm.next_in;
-input=strm.input;
-strm.avail_in=dictLength;
-strm.next_in=0;
-strm.input=dictionary;
-fill_window(s);
-while(s.lookahead>=MIN_MATCH){
-str=s.strstart;
-n=s.lookahead-(MIN_MATCH-1);
-do{
-
-s.ins_h=(s.ins_h<<s.hash_shift^s.window[str+MIN_MATCH-1])&s.hash_mask;
-
-s.prev[str&s.w_mask]=s.head[s.ins_h];
-
-s.head[s.ins_h]=str;
-str++;
-}while(--n);
-s.strstart=str;
-s.lookahead=MIN_MATCH-1;
-fill_window(s);
-}
-s.strstart+=s.lookahead;
-s.block_start=s.strstart;
-s.insert=s.lookahead;
-s.lookahead=0;
-s.match_length=s.prev_length=MIN_MATCH-1;
-s.match_available=0;
-strm.next_in=next;
-strm.input=input;
-strm.avail_in=avail;
-s.wrap=wrap;
-return Z_OK;
-}
-
-
-exports.deflateInit=deflateInit;
-exports.deflateInit2=deflateInit2;
-exports.deflateReset=deflateReset;
-exports.deflateResetKeep=deflateResetKeep;
-exports.deflateSetHeader=deflateSetHeader;
-exports.deflate=deflate;
-exports.deflateEnd=deflateEnd;
-exports.deflateSetDictionary=deflateSetDictionary;
-exports.deflateInfo='pako deflate (from Nodeca project)';
-
-
-
-
-
-
-
-
-
-
-},{"../utils/common":116,"./adler32":117,"./crc32":119,"./messages":121,"./trees":122}],121:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-module.exports={
-2:'need dictionary',
-1:'stream end',
-0:'',
-'-1':'file error',
-'-2':'stream error',
-'-3':'data error',
-'-4':'insufficient memory',
-'-5':'buffer error',
-'-6':'incompatible version'};
-
-
-},{}],122:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var utils=require('../utils/common');
-
-
-
-
-
-
-
-
-var Z_FIXED=4;
-
-
-
-var Z_BINARY=0;
-var Z_TEXT=1;
-
-var Z_UNKNOWN=2;
-
-
-
-
-function zero(buf){var len=buf.length;while(--len>=0){buf[len]=0;}}
-
-
-
-var STORED_BLOCK=0;
-var STATIC_TREES=1;
-var DYN_TREES=2;
-
-
-var MIN_MATCH=3;
-var MAX_MATCH=258;
-
-
-
-
-
-
-
-var LENGTH_CODES=29;
-
-
-var LITERALS=256;
-
-
-var L_CODES=LITERALS+1+LENGTH_CODES;
-
-
-var D_CODES=30;
-
-
-var BL_CODES=19;
-
-
-var HEAP_SIZE=2*L_CODES+1;
-
-
-var MAX_BITS=15;
-
-
-var Buf_size=16;
-
-
-
-
-
-
-
-var MAX_BL_BITS=7;
-
-
-var END_BLOCK=256;
-
-
-var REP_3_6=16;
-
-
-var REPZ_3_10=17;
-
-
-var REPZ_11_138=18;
-
-
-
-var extra_lbits=
-[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
-
-var extra_dbits=
-[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
-
-var extra_blbits=
-[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
-
-var bl_order=
-[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
-
-
-
-
-
-
-
-
-
-
-
-
-var DIST_CODE_LEN=512;
-
-
-var static_ltree=new Array((L_CODES+2)*2);
-zero(static_ltree);
-
-
-
-
-
-
-var static_dtree=new Array(D_CODES*2);
-zero(static_dtree);
-
-
-
-
-var _dist_code=new Array(DIST_CODE_LEN);
-zero(_dist_code);
-
-
-
-
-
-var _length_code=new Array(MAX_MATCH-MIN_MATCH+1);
-zero(_length_code);
-
-
-var base_length=new Array(LENGTH_CODES);
-zero(base_length);
-
-
-var base_dist=new Array(D_CODES);
-zero(base_dist);
-
-
-
-function StaticTreeDesc(static_tree,extra_bits,extra_base,elems,max_length){
-
-this.static_tree=static_tree;
-this.extra_bits=extra_bits;
-this.extra_base=extra_base;
-this.elems=elems;
-this.max_length=max_length;
-
-
-this.has_stree=static_tree&&static_tree.length;
-}
-
-
-var static_l_desc;
-var static_d_desc;
-var static_bl_desc;
-
-
-function TreeDesc(dyn_tree,stat_desc){
-this.dyn_tree=dyn_tree;
-this.max_code=0;
-this.stat_desc=stat_desc;
-}
-
-
-
-function d_code(dist){
-return dist<256?_dist_code[dist]:_dist_code[256+(dist>>>7)];
-}
-
-
-
-
-
-
-function put_short(s,w){
-
-
-s.pending_buf[s.pending++]=w&0xff;
-s.pending_buf[s.pending++]=w>>>8&0xff;
-}
-
-
-
-
-
-
-function send_bits(s,value,length){
-if(s.bi_valid>Buf_size-length){
-s.bi_buf|=value<<s.bi_valid&0xffff;
-put_short(s,s.bi_buf);
-s.bi_buf=value>>Buf_size-s.bi_valid;
-s.bi_valid+=length-Buf_size;
-}else{
-s.bi_buf|=value<<s.bi_valid&0xffff;
-s.bi_valid+=length;
-}
-}
-
-
-function send_code(s,c,tree){
-send_bits(s,tree[c*2],tree[c*2+1]);
-}
-
-
-
-
-
-
-
-function bi_reverse(code,len){
-var res=0;
-do{
-res|=code&1;
-code>>>=1;
-res<<=1;
-}while(--len>0);
-return res>>>1;
-}
-
-
-
-
-
-function bi_flush(s){
-if(s.bi_valid===16){
-put_short(s,s.bi_buf);
-s.bi_buf=0;
-s.bi_valid=0;
-
-}else if(s.bi_valid>=8){
-s.pending_buf[s.pending++]=s.bi_buf&0xff;
-s.bi_buf>>=8;
-s.bi_valid-=8;
-}
-}
-
-
-
-
-
-
-
-
-
-
-
-
-function gen_bitlen(s,desc)
-
-
-{
-var tree=desc.dyn_tree;
-var max_code=desc.max_code;
-var stree=desc.stat_desc.static_tree;
-var has_stree=desc.stat_desc.has_stree;
-var extra=desc.stat_desc.extra_bits;
-var base=desc.stat_desc.extra_base;
-var max_length=desc.stat_desc.max_length;
-var h;
-var n,m;
-var bits;
-var xbits;
-var f;
-var overflow=0;
-
-for(bits=0;bits<=MAX_BITS;bits++){
-s.bl_count[bits]=0;
-}
-
-
-
-
-tree[s.heap[s.heap_max]*2+1]=0;
-
-for(h=s.heap_max+1;h<HEAP_SIZE;h++){
-n=s.heap[h];
-bits=tree[tree[n*2+1]*2+1]+1;
-if(bits>max_length){
-bits=max_length;
-overflow++;
-}
-tree[n*2+1]=bits;
-
-
-if(n>max_code){continue;}
-
-s.bl_count[bits]++;
-xbits=0;
-if(n>=base){
-xbits=extra[n-base];
-}
-f=tree[n*2];
-s.opt_len+=f*(bits+xbits);
-if(has_stree){
-s.static_len+=f*(stree[n*2+1]+xbits);
-}
-}
-if(overflow===0){return;}
-
-
-
-
-
-do{
-bits=max_length-1;
-while(s.bl_count[bits]===0){bits--;}
-s.bl_count[bits]--;
-s.bl_count[bits+1]+=2;
-s.bl_count[max_length]--;
-
-
-
-overflow-=2;
-}while(overflow>0);
-
-
-
-
-
-
-for(bits=max_length;bits!==0;bits--){
-n=s.bl_count[bits];
-while(n!==0){
-m=s.heap[--h];
-if(m>max_code){continue;}
-if(tree[m*2+1]!==bits){
-
-s.opt_len+=(bits-tree[m*2+1])*tree[m*2];
-tree[m*2+1]=bits;
-}
-n--;
-}
-}
-}
-
-
-
-
-
-
-
-
-
-
-function gen_codes(tree,max_code,bl_count)
-
-
-
-{
-var next_code=new Array(MAX_BITS+1);
-var code=0;
-var bits;
-var n;
-
-
-
-
-for(bits=1;bits<=MAX_BITS;bits++){
-next_code[bits]=code=code+bl_count[bits-1]<<1;
-}
-
-
-
-
-
-
-
-for(n=0;n<=max_code;n++){
-var len=tree[n*2+1];
-if(len===0){continue;}
-
-tree[n*2]=bi_reverse(next_code[len]++,len);
-
-
-
-}
-}
-
-
-
-
-
-function tr_static_init(){
-var n;
-var bits;
-var length;
-var code;
-var dist;
-var bl_count=new Array(MAX_BITS+1);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-length=0;
-for(code=0;code<LENGTH_CODES-1;code++){
-base_length[code]=length;
-for(n=0;n<1<<extra_lbits[code];n++){
-_length_code[length++]=code;
-}
-}
-
-
-
-
-
-_length_code[length-1]=code;
-
-
-dist=0;
-for(code=0;code<16;code++){
-base_dist[code]=dist;
-for(n=0;n<1<<extra_dbits[code];n++){
-_dist_code[dist++]=code;
-}
-}
-
-dist>>=7;
-for(;code<D_CODES;code++){
-base_dist[code]=dist<<7;
-for(n=0;n<1<<extra_dbits[code]-7;n++){
-_dist_code[256+dist++]=code;
-}
-}
-
-
-
-for(bits=0;bits<=MAX_BITS;bits++){
-bl_count[bits]=0;
-}
-
-n=0;
-while(n<=143){
-static_ltree[n*2+1]=8;
-n++;
-bl_count[8]++;
-}
-while(n<=255){
-static_ltree[n*2+1]=9;
-n++;
-bl_count[9]++;
-}
-while(n<=279){
-static_ltree[n*2+1]=7;
-n++;
-bl_count[7]++;
-}
-while(n<=287){
-static_ltree[n*2+1]=8;
-n++;
-bl_count[8]++;
-}
-
-
-
-
-gen_codes(static_ltree,L_CODES+1,bl_count);
-
-
-for(n=0;n<D_CODES;n++){
-static_dtree[n*2+1]=5;
-static_dtree[n*2]=bi_reverse(n,5);
-}
-
-
-static_l_desc=new StaticTreeDesc(static_ltree,extra_lbits,LITERALS+1,L_CODES,MAX_BITS);
-static_d_desc=new StaticTreeDesc(static_dtree,extra_dbits,0,D_CODES,MAX_BITS);
-static_bl_desc=new StaticTreeDesc(new Array(0),extra_blbits,0,BL_CODES,MAX_BL_BITS);
-
-
-}
-
-
-
-
-
-function init_block(s){
-var n;
-
-
-for(n=0;n<L_CODES;n++){s.dyn_ltree[n*2]=0;}
-for(n=0;n<D_CODES;n++){s.dyn_dtree[n*2]=0;}
-for(n=0;n<BL_CODES;n++){s.bl_tree[n*2]=0;}
-
-s.dyn_ltree[END_BLOCK*2]=1;
-s.opt_len=s.static_len=0;
-s.last_lit=s.matches=0;
-}
-
-
-
-
-
-function bi_windup(s)
-{
-if(s.bi_valid>8){
-put_short(s,s.bi_buf);
-}else if(s.bi_valid>0){
-
-s.pending_buf[s.pending++]=s.bi_buf;
-}
-s.bi_buf=0;
-s.bi_valid=0;
-}
-
-
-
-
-
-function copy_block(s,buf,len,header)
-
-
-
-
-{
-bi_windup(s);
-
-if(header){
-put_short(s,len);
-put_short(s,~len);
-}
-
-
-
-utils.arraySet(s.pending_buf,s.window,buf,len,s.pending);
-s.pending+=len;
-}
-
-
-
-
-
-function smaller(tree,n,m,depth){
-var _n2=n*2;
-var _m2=m*2;
-return tree[_n2]<tree[_m2]||
-tree[_n2]===tree[_m2]&&depth[n]<=depth[m];
-}
-
-
-
-
-
-
-
-function pqdownheap(s,tree,k)
-
-
-
-{
-var v=s.heap[k];
-var j=k<<1;
-while(j<=s.heap_len){
-
-if(j<s.heap_len&&
-smaller(tree,s.heap[j+1],s.heap[j],s.depth)){
-j++;
-}
-
-if(smaller(tree,v,s.heap[j],s.depth)){break;}
-
-
-s.heap[k]=s.heap[j];
-k=j;
-
-
-j<<=1;
-}
-s.heap[k]=v;
-}
-
-
-
-
-
-
-
-
-function compress_block(s,ltree,dtree)
-
-
-
-{
-var dist;
-var lc;
-var lx=0;
-var code;
-var extra;
-
-if(s.last_lit!==0){
-do{
-dist=s.pending_buf[s.d_buf+lx*2]<<8|s.pending_buf[s.d_buf+lx*2+1];
-lc=s.pending_buf[s.l_buf+lx];
-lx++;
-
-if(dist===0){
-send_code(s,lc,ltree);
-
-}else{
-
-code=_length_code[lc];
-send_code(s,code+LITERALS+1,ltree);
-extra=extra_lbits[code];
-if(extra!==0){
-lc-=base_length[code];
-send_bits(s,lc,extra);
-}
-dist--;
-code=d_code(dist);
-
-
-send_code(s,code,dtree);
-extra=extra_dbits[code];
-if(extra!==0){
-dist-=base_dist[code];
-send_bits(s,dist,extra);
-}
-}
-
-
-
-
-
-}while(lx<s.last_lit);
-}
-
-send_code(s,END_BLOCK,ltree);
-}
-
-
-
-
-
-
-
-
-
-
-function build_tree(s,desc)
-
-
-{
-var tree=desc.dyn_tree;
-var stree=desc.stat_desc.static_tree;
-var has_stree=desc.stat_desc.has_stree;
-var elems=desc.stat_desc.elems;
-var n,m;
-var max_code=-1;
-var node;
-
-
-
-
-
-s.heap_len=0;
-s.heap_max=HEAP_SIZE;
-
-for(n=0;n<elems;n++){
-if(tree[n*2]!==0){
-s.heap[++s.heap_len]=max_code=n;
-s.depth[n]=0;
-
-}else{
-tree[n*2+1]=0;
-}
-}
-
-
-
-
-
-
-while(s.heap_len<2){
-node=s.heap[++s.heap_len]=max_code<2?++max_code:0;
-tree[node*2]=1;
-s.depth[node]=0;
-s.opt_len--;
-
-if(has_stree){
-s.static_len-=stree[node*2+1];
-}
-
-}
-desc.max_code=max_code;
-
-
-
-
-for(n=s.heap_len>>1;n>=1;n--){pqdownheap(s,tree,n);}
-
-
-
-
-node=elems;
-do{
-
-
-n=s.heap[1];
-s.heap[1]=s.heap[s.heap_len--];
-pqdownheap(s,tree,1);
-
-
-m=s.heap[1];
-
-s.heap[--s.heap_max]=n;
-s.heap[--s.heap_max]=m;
-
-
-tree[node*2]=tree[n*2]+tree[m*2];
-s.depth[node]=(s.depth[n]>=s.depth[m]?s.depth[n]:s.depth[m])+1;
-tree[n*2+1]=tree[m*2+1]=node;
-
-
-s.heap[1]=node++;
-pqdownheap(s,tree,1);
-
-}while(s.heap_len>=2);
-
-s.heap[--s.heap_max]=s.heap[1];
-
-
-
-
-gen_bitlen(s,desc);
-
-
-gen_codes(tree,max_code,s.bl_count);
-}
-
-
-
-
-
-
-function scan_tree(s,tree,max_code)
-
-
-
-{
-var n;
-var prevlen=-1;
-var curlen;
-
-var nextlen=tree[0*2+1];
-
-var count=0;
-var max_count=7;
-var min_count=4;
-
-if(nextlen===0){
-max_count=138;
-min_count=3;
-}
-tree[(max_code+1)*2+1]=0xffff;
-
-for(n=0;n<=max_code;n++){
-curlen=nextlen;
-nextlen=tree[(n+1)*2+1];
-
-if(++count<max_count&&curlen===nextlen){
-continue;
-
-}else if(count<min_count){
-s.bl_tree[curlen*2]+=count;
-
-}else if(curlen!==0){
-
-if(curlen!==prevlen){s.bl_tree[curlen*2]++;}
-s.bl_tree[REP_3_6*2]++;
-
-}else if(count<=10){
-s.bl_tree[REPZ_3_10*2]++;
-
-}else{
-s.bl_tree[REPZ_11_138*2]++;
-}
-
-count=0;
-prevlen=curlen;
-
-if(nextlen===0){
-max_count=138;
-min_count=3;
-
-}else if(curlen===nextlen){
-max_count=6;
-min_count=3;
-
-}else{
-max_count=7;
-min_count=4;
-}
-}
-}
-
-
-
-
-
-
-function send_tree(s,tree,max_code)
-
-
-
-{
-var n;
-var prevlen=-1;
-var curlen;
-
-var nextlen=tree[0*2+1];
-
-var count=0;
-var max_count=7;
-var min_count=4;
-
-
-if(nextlen===0){
-max_count=138;
-min_count=3;
-}
-
-for(n=0;n<=max_code;n++){
-curlen=nextlen;
-nextlen=tree[(n+1)*2+1];
-
-if(++count<max_count&&curlen===nextlen){
-continue;
-
-}else if(count<min_count){
-do{send_code(s,curlen,s.bl_tree);}while(--count!==0);
-
-}else if(curlen!==0){
-if(curlen!==prevlen){
-send_code(s,curlen,s.bl_tree);
-count--;
-}
-
-send_code(s,REP_3_6,s.bl_tree);
-send_bits(s,count-3,2);
-
-}else if(count<=10){
-send_code(s,REPZ_3_10,s.bl_tree);
-send_bits(s,count-3,3);
-
-}else{
-send_code(s,REPZ_11_138,s.bl_tree);
-send_bits(s,count-11,7);
-}
-
-count=0;
-prevlen=curlen;
-if(nextlen===0){
-max_count=138;
-min_count=3;
-
-}else if(curlen===nextlen){
-max_count=6;
-min_count=3;
-
-}else{
-max_count=7;
-min_count=4;
-}
-}
-}
-
-
-
-
-
-
-function build_bl_tree(s){
-var max_blindex;
-
-
-scan_tree(s,s.dyn_ltree,s.l_desc.max_code);
-scan_tree(s,s.dyn_dtree,s.d_desc.max_code);
-
-
-build_tree(s,s.bl_desc);
-
-
-
-
-
-
-
-
-for(max_blindex=BL_CODES-1;max_blindex>=3;max_blindex--){
-if(s.bl_tree[bl_order[max_blindex]*2+1]!==0){
-break;
-}
-}
-
-s.opt_len+=3*(max_blindex+1)+5+5+4;
-
-
-
-return max_blindex;
-}
-
-
-
-
-
-
-
-function send_all_trees(s,lcodes,dcodes,blcodes)
-
-
-{
-var rank;
-
-
-
-
-
-send_bits(s,lcodes-257,5);
-send_bits(s,dcodes-1,5);
-send_bits(s,blcodes-4,4);
-for(rank=0;rank<blcodes;rank++){
-
-send_bits(s,s.bl_tree[bl_order[rank]*2+1],3);
-}
-
-
-send_tree(s,s.dyn_ltree,lcodes-1);
-
-
-send_tree(s,s.dyn_dtree,dcodes-1);
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function detect_data_type(s){
-
-
-
-
-var black_mask=0xf3ffc07f;
-var n;
-
-
-for(n=0;n<=31;n++,black_mask>>>=1){
-if(black_mask&1&&s.dyn_ltree[n*2]!==0){
-return Z_BINARY;
-}
-}
-
-
-if(s.dyn_ltree[9*2]!==0||s.dyn_ltree[10*2]!==0||
-s.dyn_ltree[13*2]!==0){
-return Z_TEXT;
-}
-for(n=32;n<LITERALS;n++){
-if(s.dyn_ltree[n*2]!==0){
-return Z_TEXT;
-}
-}
-
-
-
-
-return Z_BINARY;
-}
-
-
-var static_init_done=false;
-
-
-
-
-function _tr_init(s)
-{
-
-if(!static_init_done){
-tr_static_init();
-static_init_done=true;
-}
-
-s.l_desc=new TreeDesc(s.dyn_ltree,static_l_desc);
-s.d_desc=new TreeDesc(s.dyn_dtree,static_d_desc);
-s.bl_desc=new TreeDesc(s.bl_tree,static_bl_desc);
-
-s.bi_buf=0;
-s.bi_valid=0;
-
-
-init_block(s);
-}
-
-
-
-
-
-function _tr_stored_block(s,buf,stored_len,last)
-
-
-
-
-{
-send_bits(s,(STORED_BLOCK<<1)+(last?1:0),3);
-copy_block(s,buf,stored_len,true);
-}
-
-
-
-
-
-
-function _tr_align(s){
-send_bits(s,STATIC_TREES<<1,3);
-send_code(s,END_BLOCK,static_ltree);
-bi_flush(s);
-}
-
-
-
-
-
-
-function _tr_flush_block(s,buf,stored_len,last)
-
-
-
-
-{
-var opt_lenb,static_lenb;
-var max_blindex=0;
-
-
-if(s.level>0){
-
-
-if(s.strm.data_type===Z_UNKNOWN){
-s.strm.data_type=detect_data_type(s);
-}
-
-
-build_tree(s,s.l_desc);
-
-
-
-build_tree(s,s.d_desc);
-
-
-
-
-
-
-
-
-
-max_blindex=build_bl_tree(s);
-
-
-opt_lenb=s.opt_len+3+7>>>3;
-static_lenb=s.static_len+3+7>>>3;
-
-
-
-
-
-if(static_lenb<=opt_lenb){opt_lenb=static_lenb;}
-
-}else{
-
-opt_lenb=static_lenb=stored_len+5;
-}
-
-if(stored_len+4<=opt_lenb&&buf!==-1){
-
-
-
-
-
-
-
-
-_tr_stored_block(s,buf,stored_len,last);
-
-}else if(s.strategy===Z_FIXED||static_lenb===opt_lenb){
-
-send_bits(s,(STATIC_TREES<<1)+(last?1:0),3);
-compress_block(s,static_ltree,static_dtree);
-
-}else{
-send_bits(s,(DYN_TREES<<1)+(last?1:0),3);
-send_all_trees(s,s.l_desc.max_code+1,s.d_desc.max_code+1,max_blindex+1);
-compress_block(s,s.dyn_ltree,s.dyn_dtree);
-}
-
-
-
-
-init_block(s);
-
-if(last){
-bi_windup(s);
-}
-
-
-}
-
-
-
-
-
-function _tr_tally(s,dist,lc)
-
-
-
-{
-
-
-s.pending_buf[s.d_buf+s.last_lit*2]=dist>>>8&0xff;
-s.pending_buf[s.d_buf+s.last_lit*2+1]=dist&0xff;
-
-s.pending_buf[s.l_buf+s.last_lit]=lc&0xff;
-s.last_lit++;
-
-if(dist===0){
-
-s.dyn_ltree[lc*2]++;
-}else{
-s.matches++;
-
-dist--;
-
-
-
-
-s.dyn_ltree[(_length_code[lc]+LITERALS+1)*2]++;
-s.dyn_dtree[d_code(dist)*2]++;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-return s.last_lit===s.lit_bufsize-1;
-
-
-
-
-}
-
-exports._tr_init=_tr_init;
-exports._tr_stored_block=_tr_stored_block;
-exports._tr_flush_block=_tr_flush_block;
-exports._tr_tally=_tr_tally;
-exports._tr_align=_tr_align;
-
-},{"../utils/common":116}],123:[function(require,module,exports){
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function ZStream(){
-
-this.input=null;
-this.next_in=0;
-
-this.avail_in=0;
-
-this.total_in=0;
-
-this.output=null;
-this.next_out=0;
-
-this.avail_out=0;
-
-this.total_out=0;
-
-this.msg='';
-
-this.state=null;
-
-this.data_type=2;
-
-this.adler=0;
-}
-
-module.exports=ZStream;
-
-},{}],124:[function(require,module,exports){
-(function(process){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function normalizeArray(parts,allowAboveRoot){
-
-var up=0;
-for(var i=parts.length-1;i>=0;i--){
-var last=parts[i];
-if(last==='.'){
-parts.splice(i,1);
-}else if(last==='..'){
-parts.splice(i,1);
-up++;
-}else if(up){
-parts.splice(i,1);
-up--;
-}
-}
-
-
-if(allowAboveRoot){
-for(;up--;up){
-parts.unshift('..');
-}
-}
-
-return parts;
-}
-
-
-
-var splitPathRe=
-/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
-var splitPath=function(filename){
-return splitPathRe.exec(filename).slice(1);
-};
-
-
-
-exports.resolve=function(){
-var resolvedPath='',
-resolvedAbsolute=false;
-
-for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){
-var path=i>=0?arguments[i]:process.cwd();
-
-
-if(typeof path!=='string'){
-throw new TypeError('Arguments to path.resolve must be strings');
-}else if(!path){
-continue;
-}
-
-resolvedPath=path+'/'+resolvedPath;
-resolvedAbsolute=path.charAt(0)==='/';
-}
-
-
-
-
-
-resolvedPath=normalizeArray(filter(resolvedPath.split('/'),function(p){
-return!!p;
-}),!resolvedAbsolute).join('/');
-
-return(resolvedAbsolute?'/':'')+resolvedPath||'.';
-};
-
-
-
-exports.normalize=function(path){
-var isAbsolute=exports.isAbsolute(path),
-trailingSlash=substr(path,-1)==='/';
-
-
-path=normalizeArray(filter(path.split('/'),function(p){
-return!!p;
-}),!isAbsolute).join('/');
-
-if(!path&&!isAbsolute){
-path='.';
-}
-if(path&&trailingSlash){
-path+='/';
-}
-
-return(isAbsolute?'/':'')+path;
-};
-
-
-exports.isAbsolute=function(path){
-return path.charAt(0)==='/';
-};
-
-
-exports.join=function(){
-var paths=Array.prototype.slice.call(arguments,0);
-return exports.normalize(filter(paths,function(p,index){
-if(typeof p!=='string'){
-throw new TypeError('Arguments to path.join must be strings');
-}
-return p;
-}).join('/'));
-};
-
-
-
-
-exports.relative=function(from,to){
-from=exports.resolve(from).substr(1);
-to=exports.resolve(to).substr(1);
-
-function trim(arr){
-var start=0;
-for(;start<arr.length;start++){
-if(arr[start]!=='')break;
-}
-
-var end=arr.length-1;
-for(;end>=0;end--){
-if(arr[end]!=='')break;
-}
-
-if(start>end)return[];
-return arr.slice(start,end-start+1);
-}
-
-var fromParts=trim(from.split('/'));
-var toParts=trim(to.split('/'));
-
-var length=Math.min(fromParts.length,toParts.length);
-var samePartsLength=length;
-for(var i=0;i<length;i++){
-if(fromParts[i]!==toParts[i]){
-samePartsLength=i;
-break;
-}
-}
-
-var outputParts=[];
-for(var i=samePartsLength;i<fromParts.length;i++){
-outputParts.push('..');
-}
-
-outputParts=outputParts.concat(toParts.slice(samePartsLength));
-
-return outputParts.join('/');
-};
-
-exports.sep='/';
-exports.delimiter=':';
-
-exports.dirname=function(path){
-var result=splitPath(path),
-root=result[0],
-dir=result[1];
-
-if(!root&&!dir){
-
-return'.';
-}
-
-if(dir){
-
-dir=dir.substr(0,dir.length-1);
-}
-
-return root+dir;
-};
-
-
-exports.basename=function(path,ext){
-var f=splitPath(path)[2];
-
-if(ext&&f.substr(-1*ext.length)===ext){
-f=f.substr(0,f.length-ext.length);
-}
-return f;
-};
-
-
-exports.extname=function(path){
-return splitPath(path)[3];
-};
-
-function filter(xs,f){
-if(xs.filter)return xs.filter(f);
-var res=[];
-for(var i=0;i<xs.length;i++){
-if(f(xs[i],i,xs))res.push(xs[i]);
-}
-return res;
-}
-
-
-var substr='ab'.substr(-1)==='b'?
-function(str,start,len){return str.substr(start,len);}:
-function(str,start,len){
-if(start<0)start=str.length+start;
-return str.substr(start,len);
-};
-
-
-}).call(this,require('_process'));
-},{"_process":126}],125:[function(require,module,exports){
-(function(process){
-'use strict';
-
-if(!process.version||
-process.version.indexOf('v0.')===0||
-process.version.indexOf('v1.')===0&&process.version.indexOf('v1.8.')!==0){
-module.exports=nextTick;
-}else{
-module.exports=process.nextTick;
-}
-
-function nextTick(fn,arg1,arg2,arg3){
-if(typeof fn!=='function'){
-throw new TypeError('"callback" argument must be a function');
-}
-var len=arguments.length;
-var args,i;
-switch(len){
-case 0:
-case 1:
-return process.nextTick(fn);
-case 2:
-return process.nextTick(function afterTickOne(){
-fn.call(null,arg1);
-});
-case 3:
-return process.nextTick(function afterTickTwo(){
-fn.call(null,arg1,arg2);
-});
-case 4:
-return process.nextTick(function afterTickThree(){
-fn.call(null,arg1,arg2,arg3);
-});
-default:
-args=new Array(len-1);
-i=0;
-while(i<args.length){
-args[i++]=arguments[i];
-}
-return process.nextTick(function afterTick(){
-fn.apply(null,args);
-});}
-
-}
-
-}).call(this,require('_process'));
-},{"_process":126}],126:[function(require,module,exports){
-
-var process=module.exports={};
-
-
-
-
-
-
-var cachedSetTimeout;
-var cachedClearTimeout;
-
-function defaultSetTimout(){
-throw new Error('setTimeout has not been defined');
-}
-function defaultClearTimeout(){
-throw new Error('clearTimeout has not been defined');
-}
-(function(){
-try{
-if(typeof setTimeout==='function'){
-cachedSetTimeout=setTimeout;
-}else{
-cachedSetTimeout=defaultSetTimout;
-}
-}catch(e){
-cachedSetTimeout=defaultSetTimout;
-}
-try{
-if(typeof clearTimeout==='function'){
-cachedClearTimeout=clearTimeout;
-}else{
-cachedClearTimeout=defaultClearTimeout;
-}
-}catch(e){
-cachedClearTimeout=defaultClearTimeout;
-}
-})();
-function runTimeout(fun){
-if(cachedSetTimeout===setTimeout){
-
-return setTimeout(fun,0);
-}
-
-if((cachedSetTimeout===defaultSetTimout||!cachedSetTimeout)&&setTimeout){
-cachedSetTimeout=setTimeout;
-return setTimeout(fun,0);
-}
-try{
-
-return cachedSetTimeout(fun,0);
-}catch(e){
-try{
-
-return cachedSetTimeout.call(null,fun,0);
-}catch(e){
-
-return cachedSetTimeout.call(this,fun,0);
-}
-}
-
-
-}
-function runClearTimeout(marker){
-if(cachedClearTimeout===clearTimeout){
-
-return clearTimeout(marker);
-}
-
-if((cachedClearTimeout===defaultClearTimeout||!cachedClearTimeout)&&clearTimeout){
-cachedClearTimeout=clearTimeout;
-return clearTimeout(marker);
-}
-try{
-
-return cachedClearTimeout(marker);
-}catch(e){
-try{
-
-return cachedClearTimeout.call(null,marker);
-}catch(e){
-
-
-return cachedClearTimeout.call(this,marker);
-}
-}
-
-
-
-}
-var queue=[];
-var draining=false;
-var currentQueue;
-var queueIndex=-1;
-
-function cleanUpNextTick(){
-if(!draining||!currentQueue){
-return;
-}
-draining=false;
-if(currentQueue.length){
-queue=currentQueue.concat(queue);
-}else{
-queueIndex=-1;
-}
-if(queue.length){
-drainQueue();
-}
-}
-
-function drainQueue(){
-if(draining){
-return;
-}
-var timeout=runTimeout(cleanUpNextTick);
-draining=true;
-
-var len=queue.length;
-while(len){
-currentQueue=queue;
-queue=[];
-while(++queueIndex<len){
-if(currentQueue){
-currentQueue[queueIndex].run();
-}
-}
-queueIndex=-1;
-len=queue.length;
-}
-currentQueue=null;
-draining=false;
-runClearTimeout(timeout);
-}
-
-process.nextTick=function(fun){
-var args=new Array(arguments.length-1);
-if(arguments.length>1){
-for(var i=1;i<arguments.length;i++){
-args[i-1]=arguments[i];
-}
-}
-queue.push(new Item(fun,args));
-if(queue.length===1&&!draining){
-runTimeout(drainQueue);
-}
-};
-
-
-function Item(fun,array){
-this.fun=fun;
-this.array=array;
-}
-Item.prototype.run=function(){
-this.fun.apply(null,this.array);
-};
-process.title='browser';
-process.browser=true;
-process.env={};
-process.argv=[];
-process.version='';
-process.versions={};
-
-function noop(){}
-
-process.on=noop;
-process.addListener=noop;
-process.once=noop;
-process.off=noop;
-process.removeListener=noop;
-process.removeAllListeners=noop;
-process.emit=noop;
-process.prependListener=noop;
-process.prependOnceListener=noop;
-
-process.listeners=function(name){return[];};
-
-process.binding=function(name){
-throw new Error('process.binding is not supported');
-};
-
-process.cwd=function(){return'/';};
-process.chdir=function(dir){
-throw new Error('process.chdir is not supported');
-};
-process.umask=function(){return 0;};
-
-},{}],127:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-
-
-
-function hasOwnProperty(obj,prop){
-return Object.prototype.hasOwnProperty.call(obj,prop);
-}
-
-module.exports=function(qs,sep,eq,options){
-sep=sep||'&';
-eq=eq||'=';
-var obj={};
-
-if(typeof qs!=='string'||qs.length===0){
-return obj;
-}
-
-var regexp=/\+/g;
-qs=qs.split(sep);
-
-var maxKeys=1000;
-if(options&&typeof options.maxKeys==='number'){
-maxKeys=options.maxKeys;
-}
-
-var len=qs.length;
-
-if(maxKeys>0&&len>maxKeys){
-len=maxKeys;
-}
-
-for(var i=0;i<len;++i){
-var x=qs[i].replace(regexp,'%20'),
-idx=x.indexOf(eq),
-kstr,vstr,k,v;
-
-if(idx>=0){
-kstr=x.substr(0,idx);
-vstr=x.substr(idx+1);
-}else{
-kstr=x;
-vstr='';
-}
-
-k=decodeURIComponent(kstr);
-v=decodeURIComponent(vstr);
-
-if(!hasOwnProperty(obj,k)){
-obj[k]=v;
-}else if(isArray(obj[k])){
-obj[k].push(v);
-}else{
-obj[k]=[obj[k],v];
-}
-}
-
-return obj;
-};
-
-var isArray=Array.isArray||function(xs){
-return Object.prototype.toString.call(xs)==='[object Array]';
-};
-
-},{}],128:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-var stringifyPrimitive=function(v){
-switch(typeof v){
-case'string':
-return v;
-
-case'boolean':
-return v?'true':'false';
-
-case'number':
-return isFinite(v)?v:'';
-
-default:
-return'';}
-
-};
-
-module.exports=function(obj,sep,eq,name){
-sep=sep||'&';
-eq=eq||'=';
-if(obj===null){
-obj=undefined;
-}
-
-if(typeof obj==='object'){
-return map(objectKeys(obj),function(k){
-var ks=encodeURIComponent(stringifyPrimitive(k))+eq;
-if(isArray(obj[k])){
-return map(obj[k],function(v){
-return ks+encodeURIComponent(stringifyPrimitive(v));
-}).join(sep);
-}else{
-return ks+encodeURIComponent(stringifyPrimitive(obj[k]));
-}
-}).join(sep);
-
-}
-
-if(!name)return'';
-return encodeURIComponent(stringifyPrimitive(name))+eq+
-encodeURIComponent(stringifyPrimitive(obj));
-};
-
-var isArray=Array.isArray||function(xs){
-return Object.prototype.toString.call(xs)==='[object Array]';
-};
-
-function map(xs,f){
-if(xs.map)return xs.map(f);
-var res=[];
-for(var i=0;i<xs.length;i++){
-res.push(f(xs[i],i));
-}
-return res;
-}
-
-var objectKeys=Object.keys||function(obj){
-var res=[];
-for(var key in obj){
-if(Object.prototype.hasOwnProperty.call(obj,key))res.push(key);
-}
-return res;
-};
-
-},{}],129:[function(require,module,exports){
-'use strict';
-
-exports.decode=exports.parse=require('./decode');
-exports.encode=exports.stringify=require('./encode');
-
-},{"./decode":127,"./encode":128}],130:[function(require,module,exports){
-module.exports=require("./lib/_stream_duplex.js");
-
-},{"./lib/_stream_duplex.js":131}],131:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-var objectKeys=Object.keys||function(obj){
-var keys=[];
-for(var key in obj){
-keys.push(key);
-}return keys;
-};
-
-
-module.exports=Duplex;
-
-
-var processNextTick=require('process-nextick-args');
-
-
-
-var util=require('core-util-is');
-util.inherits=require('inherits');
-
-
-var Readable=require('./_stream_readable');
-var Writable=require('./_stream_writable');
-
-util.inherits(Duplex,Readable);
-
-var keys=objectKeys(Writable.prototype);
-for(var v=0;v<keys.length;v++){
-var method=keys[v];
-if(!Duplex.prototype[method])Duplex.prototype[method]=Writable.prototype[method];
-}
-
-function Duplex(options){
-if(!(this instanceof Duplex))return new Duplex(options);
-
-Readable.call(this,options);
-Writable.call(this,options);
-
-if(options&&options.readable===false)this.readable=false;
-
-if(options&&options.writable===false)this.writable=false;
-
-this.allowHalfOpen=true;
-if(options&&options.allowHalfOpen===false)this.allowHalfOpen=false;
-
-this.once('end',onend);
-}
-
-
-function onend(){
-
-
-if(this.allowHalfOpen||this._writableState.ended)return;
-
-
-
-processNextTick(onEndNT,this);
-}
-
-function onEndNT(self){
-self.end();
-}
-
-function forEach(xs,f){
-for(var i=0,l=xs.length;i<l;i++){
-f(xs[i],i);
-}
-}
-},{"./_stream_readable":133,"./_stream_writable":135,"core-util-is":110,"inherits":113,"process-nextick-args":125}],132:[function(require,module,exports){
-
-
-
-
-'use strict';
-
-module.exports=PassThrough;
-
-var Transform=require('./_stream_transform');
-
-
-var util=require('core-util-is');
-util.inherits=require('inherits');
-
-
-util.inherits(PassThrough,Transform);
-
-function PassThrough(options){
-if(!(this instanceof PassThrough))return new PassThrough(options);
-
-Transform.call(this,options);
-}
-
-PassThrough.prototype._transform=function(chunk,encoding,cb){
-cb(null,chunk);
-};
-},{"./_stream_transform":134,"core-util-is":110,"inherits":113}],133:[function(require,module,exports){
-(function(process){
-'use strict';
-
-module.exports=Readable;
-
-
-var processNextTick=require('process-nextick-args');
-
-
-
-var isArray=require('isarray');
-
-
-
-var Duplex;
-
-
-Readable.ReadableState=ReadableState;
-
-
-var EE=require('events').EventEmitter;
-
-var EElistenerCount=function(emitter,type){
-return emitter.listeners(type).length;
-};
-
-
-
-var Stream;
-(function(){
-try{
-Stream=require('st'+'ream');
-}catch(_){}finally{
-if(!Stream)Stream=require('events').EventEmitter;
-}
-})();
-
-
-var Buffer=require('buffer').Buffer;
-
-var bufferShim=require('buffer-shims');
-
-
-
-var util=require('core-util-is');
-util.inherits=require('inherits');
-
-
-
-var debugUtil=require('util');
-var debug=void 0;
-if(debugUtil&&debugUtil.debuglog){
-debug=debugUtil.debuglog('stream');
-}else{
-debug=function(){};
-}
-
-
-var BufferList=require('./internal/streams/BufferList');
-var StringDecoder;
-
-util.inherits(Readable,Stream);
-
-function prependListener(emitter,event,fn){
-
-
-if(typeof emitter.prependListener==='function'){
-return emitter.prependListener(event,fn);
-}else{
-
-
-
-
-if(!emitter._events||!emitter._events[event])emitter.on(event,fn);else if(isArray(emitter._events[event]))emitter._events[event].unshift(fn);else emitter._events[event]=[fn,emitter._events[event]];
-}
-}
-
-function ReadableState(options,stream){
-Duplex=Duplex||require('./_stream_duplex');
-
-options=options||{};
-
-
-
-this.objectMode=!!options.objectMode;
-
-if(stream instanceof Duplex)this.objectMode=this.objectMode||!!options.readableObjectMode;
-
-
-
-var hwm=options.highWaterMark;
-var defaultHwm=this.objectMode?16:16*1024;
-this.highWaterMark=hwm||hwm===0?hwm:defaultHwm;
-
-
-this.highWaterMark=~~this.highWaterMark;
-
-
-
-
-this.buffer=new BufferList();
-this.length=0;
-this.pipes=null;
-this.pipesCount=0;
-this.flowing=null;
-this.ended=false;
-this.endEmitted=false;
-this.reading=false;
-
-
-
-
-
-this.sync=true;
-
-
-
-this.needReadable=false;
-this.emittedReadable=false;
-this.readableListening=false;
-this.resumeScheduled=false;
-
-
-
-
-this.defaultEncoding=options.defaultEncoding||'utf8';
-
-
-
-this.ranOut=false;
-
-
-this.awaitDrain=0;
-
-
-this.readingMore=false;
-
-this.decoder=null;
-this.encoding=null;
-if(options.encoding){
-if(!StringDecoder)StringDecoder=require('string_decoder/').StringDecoder;
-this.decoder=new StringDecoder(options.encoding);
-this.encoding=options.encoding;
-}
-}
-
-function Readable(options){
-Duplex=Duplex||require('./_stream_duplex');
-
-if(!(this instanceof Readable))return new Readable(options);
-
-this._readableState=new ReadableState(options,this);
-
-
-this.readable=true;
-
-if(options&&typeof options.read==='function')this._read=options.read;
-
-Stream.call(this);
-}
-
-
-
-
-
-Readable.prototype.push=function(chunk,encoding){
-var state=this._readableState;
-
-if(!state.objectMode&&typeof chunk==='string'){
-encoding=encoding||state.defaultEncoding;
-if(encoding!==state.encoding){
-chunk=bufferShim.from(chunk,encoding);
-encoding='';
-}
-}
-
-return readableAddChunk(this,state,chunk,encoding,false);
-};
-
-
-Readable.prototype.unshift=function(chunk){
-var state=this._readableState;
-return readableAddChunk(this,state,chunk,'',true);
-};
-
-Readable.prototype.isPaused=function(){
-return this._readableState.flowing===false;
-};
-
-function readableAddChunk(stream,state,chunk,encoding,addToFront){
-var er=chunkInvalid(state,chunk);
-if(er){
-stream.emit('error',er);
-}else if(chunk===null){
-state.reading=false;
-onEofChunk(stream,state);
-}else if(state.objectMode||chunk&&chunk.length>0){
-if(state.ended&&!addToFront){
-var e=new Error('stream.push() after EOF');
-stream.emit('error',e);
-}else if(state.endEmitted&&addToFront){
-var _e=new Error('stream.unshift() after end event');
-stream.emit('error',_e);
-}else{
-var skipAdd;
-if(state.decoder&&!addToFront&&!encoding){
-chunk=state.decoder.write(chunk);
-skipAdd=!state.objectMode&&chunk.length===0;
-}
-
-if(!addToFront)state.reading=false;
-
-
-
-if(!skipAdd){
-
-if(state.flowing&&state.length===0&&!state.sync){
-stream.emit('data',chunk);
-stream.read(0);
-}else{
-
-state.length+=state.objectMode?1:chunk.length;
-if(addToFront)state.buffer.unshift(chunk);else state.buffer.push(chunk);
-
-if(state.needReadable)emitReadable(stream);
-}
-}
-
-maybeReadMore(stream,state);
-}
-}else if(!addToFront){
-state.reading=false;
-}
-
-return needMoreData(state);
-}
-
-
-
-
-
-
-
-
-function needMoreData(state){
-return!state.ended&&(state.needReadable||state.length<state.highWaterMark||state.length===0);
-}
-
-
-Readable.prototype.setEncoding=function(enc){
-if(!StringDecoder)StringDecoder=require('string_decoder/').StringDecoder;
-this._readableState.decoder=new StringDecoder(enc);
-this._readableState.encoding=enc;
-return this;
-};
-
-
-var MAX_HWM=0x800000;
-function computeNewHighWaterMark(n){
-if(n>=MAX_HWM){
-n=MAX_HWM;
-}else{
-
-
-n--;
-n|=n>>>1;
-n|=n>>>2;
-n|=n>>>4;
-n|=n>>>8;
-n|=n>>>16;
-n++;
-}
-return n;
-}
-
-
-
-function howMuchToRead(n,state){
-if(n<=0||state.length===0&&state.ended)return 0;
-if(state.objectMode)return 1;
-if(n!==n){
-
-if(state.flowing&&state.length)return state.buffer.head.data.length;else return state.length;
-}
-
-if(n>state.highWaterMark)state.highWaterMark=computeNewHighWaterMark(n);
-if(n<=state.length)return n;
-
-if(!state.ended){
-state.needReadable=true;
-return 0;
-}
-return state.length;
-}
-
-
-Readable.prototype.read=function(n){
-debug('read',n);
-n=parseInt(n,10);
-var state=this._readableState;
-var nOrig=n;
-
-if(n!==0)state.emittedReadable=false;
-
-
-
-
-if(n===0&&state.needReadable&&(state.length>=state.highWaterMark||state.ended)){
-debug('read: emitReadable',state.length,state.ended);
-if(state.length===0&&state.ended)endReadable(this);else emitReadable(this);
-return null;
-}
-
-n=howMuchToRead(n,state);
-
-
-if(n===0&&state.ended){
-if(state.length===0)endReadable(this);
-return null;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var doRead=state.needReadable;
-debug('need readable',doRead);
-
-
-if(state.length===0||state.length-n<state.highWaterMark){
-doRead=true;
-debug('length less than watermark',doRead);
-}
-
-
-
-if(state.ended||state.reading){
-doRead=false;
-debug('reading or ended',doRead);
-}else if(doRead){
-debug('do read');
-state.reading=true;
-state.sync=true;
-
-if(state.length===0)state.needReadable=true;
-
-this._read(state.highWaterMark);
-state.sync=false;
-
-
-if(!state.reading)n=howMuchToRead(nOrig,state);
-}
-
-var ret;
-if(n>0)ret=fromList(n,state);else ret=null;
-
-if(ret===null){
-state.needReadable=true;
-n=0;
-}else{
-state.length-=n;
-}
-
-if(state.length===0){
-
-
-if(!state.ended)state.needReadable=true;
-
-
-if(nOrig!==n&&state.ended)endReadable(this);
-}
-
-if(ret!==null)this.emit('data',ret);
-
-return ret;
-};
-
-function chunkInvalid(state,chunk){
-var er=null;
-if(!Buffer.isBuffer(chunk)&&typeof chunk!=='string'&&chunk!==null&&chunk!==undefined&&!state.objectMode){
-er=new TypeError('Invalid non-string/buffer chunk');
-}
-return er;
-}
-
-function onEofChunk(stream,state){
-if(state.ended)return;
-if(state.decoder){
-var chunk=state.decoder.end();
-if(chunk&&chunk.length){
-state.buffer.push(chunk);
-state.length+=state.objectMode?1:chunk.length;
-}
-}
-state.ended=true;
-
-
-emitReadable(stream);
-}
-
-
-
-
-function emitReadable(stream){
-var state=stream._readableState;
-state.needReadable=false;
-if(!state.emittedReadable){
-debug('emitReadable',state.flowing);
-state.emittedReadable=true;
-if(state.sync)processNextTick(emitReadable_,stream);else emitReadable_(stream);
-}
-}
-
-function emitReadable_(stream){
-debug('emit readable');
-stream.emit('readable');
-flow(stream);
-}
-
-
-
-
-
-
-
-function maybeReadMore(stream,state){
-if(!state.readingMore){
-state.readingMore=true;
-processNextTick(maybeReadMore_,stream,state);
-}
-}
-
-function maybeReadMore_(stream,state){
-var len=state.length;
-while(!state.reading&&!state.flowing&&!state.ended&&state.length<state.highWaterMark){
-debug('maybeReadMore read 0');
-stream.read(0);
-if(len===state.length)
-
-break;else len=state.length;
-}
-state.readingMore=false;
-}
-
-
-
-
-
-Readable.prototype._read=function(n){
-this.emit('error',new Error('_read() is not implemented'));
-};
-
-Readable.prototype.pipe=function(dest,pipeOpts){
-var src=this;
-var state=this._readableState;
-
-switch(state.pipesCount){
-case 0:
-state.pipes=dest;
-break;
-case 1:
-state.pipes=[state.pipes,dest];
-break;
-default:
-state.pipes.push(dest);
-break;}
-
-state.pipesCount+=1;
-debug('pipe count=%d opts=%j',state.pipesCount,pipeOpts);
-
-var doEnd=(!pipeOpts||pipeOpts.end!==false)&&dest!==process.stdout&&dest!==process.stderr;
-
-var endFn=doEnd?onend:cleanup;
-if(state.endEmitted)processNextTick(endFn);else src.once('end',endFn);
-
-dest.on('unpipe',onunpipe);
-function onunpipe(readable){
-debug('onunpipe');
-if(readable===src){
-cleanup();
-}
-}
-
-function onend(){
-debug('onend');
-dest.end();
-}
-
-
-
-
-
-var ondrain=pipeOnDrain(src);
-dest.on('drain',ondrain);
-
-var cleanedUp=false;
-function cleanup(){
-debug('cleanup');
-
-dest.removeListener('close',onclose);
-dest.removeListener('finish',onfinish);
-dest.removeListener('drain',ondrain);
-dest.removeListener('error',onerror);
-dest.removeListener('unpipe',onunpipe);
-src.removeListener('end',onend);
-src.removeListener('end',cleanup);
-src.removeListener('data',ondata);
-
-cleanedUp=true;
-
-
-
-
-
-
-if(state.awaitDrain&&(!dest._writableState||dest._writableState.needDrain))ondrain();
-}
-
-
-
-
-
-var increasedAwaitDrain=false;
-src.on('data',ondata);
-function ondata(chunk){
-debug('ondata');
-increasedAwaitDrain=false;
-var ret=dest.write(chunk);
-if(false===ret&&!increasedAwaitDrain){
-
-
-
-
-if((state.pipesCount===1&&state.pipes===dest||state.pipesCount>1&&indexOf(state.pipes,dest)!==-1)&&!cleanedUp){
-debug('false write response, pause',src._readableState.awaitDrain);
-src._readableState.awaitDrain++;
-increasedAwaitDrain=true;
-}
-src.pause();
-}
-}
-
-
-
-function onerror(er){
-debug('onerror',er);
-unpipe();
-dest.removeListener('error',onerror);
-if(EElistenerCount(dest,'error')===0)dest.emit('error',er);
-}
-
-
-prependListener(dest,'error',onerror);
-
-
-function onclose(){
-dest.removeListener('finish',onfinish);
-unpipe();
-}
-dest.once('close',onclose);
-function onfinish(){
-debug('onfinish');
-dest.removeListener('close',onclose);
-unpipe();
-}
-dest.once('finish',onfinish);
-
-function unpipe(){
-debug('unpipe');
-src.unpipe(dest);
-}
-
-
-dest.emit('pipe',src);
-
-
-if(!state.flowing){
-debug('pipe resume');
-src.resume();
-}
-
-return dest;
-};
-
-function pipeOnDrain(src){
-return function(){
-var state=src._readableState;
-debug('pipeOnDrain',state.awaitDrain);
-if(state.awaitDrain)state.awaitDrain--;
-if(state.awaitDrain===0&&EElistenerCount(src,'data')){
-state.flowing=true;
-flow(src);
-}
-};
-}
-
-Readable.prototype.unpipe=function(dest){
-var state=this._readableState;
-
-
-if(state.pipesCount===0)return this;
-
-
-if(state.pipesCount===1){
-
-if(dest&&dest!==state.pipes)return this;
-
-if(!dest)dest=state.pipes;
-
-
-state.pipes=null;
-state.pipesCount=0;
-state.flowing=false;
-if(dest)dest.emit('unpipe',this);
-return this;
-}
-
-
-
-if(!dest){
-
-var dests=state.pipes;
-var len=state.pipesCount;
-state.pipes=null;
-state.pipesCount=0;
-state.flowing=false;
-
-for(var i=0;i<len;i++){
-dests[i].emit('unpipe',this);
-}return this;
-}
-
-
-var index=indexOf(state.pipes,dest);
-if(index===-1)return this;
-
-state.pipes.splice(index,1);
-state.pipesCount-=1;
-if(state.pipesCount===1)state.pipes=state.pipes[0];
-
-dest.emit('unpipe',this);
-
-return this;
-};
-
-
-
-Readable.prototype.on=function(ev,fn){
-var res=Stream.prototype.on.call(this,ev,fn);
-
-if(ev==='data'){
-
-if(this._readableState.flowing!==false)this.resume();
-}else if(ev==='readable'){
-var state=this._readableState;
-if(!state.endEmitted&&!state.readableListening){
-state.readableListening=state.needReadable=true;
-state.emittedReadable=false;
-if(!state.reading){
-processNextTick(nReadingNextTick,this);
-}else if(state.length){
-emitReadable(this,state);
-}
-}
-}
-
-return res;
-};
-Readable.prototype.addListener=Readable.prototype.on;
-
-function nReadingNextTick(self){
-debug('readable nexttick read 0');
-self.read(0);
-}
-
-
-
-Readable.prototype.resume=function(){
-var state=this._readableState;
-if(!state.flowing){
-debug('resume');
-state.flowing=true;
-resume(this,state);
-}
-return this;
-};
-
-function resume(stream,state){
-if(!state.resumeScheduled){
-state.resumeScheduled=true;
-processNextTick(resume_,stream,state);
-}
-}
-
-function resume_(stream,state){
-if(!state.reading){
-debug('resume read 0');
-stream.read(0);
-}
-
-state.resumeScheduled=false;
-state.awaitDrain=0;
-stream.emit('resume');
-flow(stream);
-if(state.flowing&&!state.reading)stream.read(0);
-}
-
-Readable.prototype.pause=function(){
-debug('call pause flowing=%j',this._readableState.flowing);
-if(false!==this._readableState.flowing){
-debug('pause');
-this._readableState.flowing=false;
-this.emit('pause');
-}
-return this;
-};
-
-function flow(stream){
-var state=stream._readableState;
-debug('flow',state.flowing);
-while(state.flowing&&stream.read()!==null){}
-}
-
-
-
-
-Readable.prototype.wrap=function(stream){
-var state=this._readableState;
-var paused=false;
-
-var self=this;
-stream.on('end',function(){
-debug('wrapped end');
-if(state.decoder&&!state.ended){
-var chunk=state.decoder.end();
-if(chunk&&chunk.length)self.push(chunk);
-}
-
-self.push(null);
-});
-
-stream.on('data',function(chunk){
-debug('wrapped data');
-if(state.decoder)chunk=state.decoder.write(chunk);
-
-
-if(state.objectMode&&(chunk===null||chunk===undefined))return;else if(!state.objectMode&&(!chunk||!chunk.length))return;
-
-var ret=self.push(chunk);
-if(!ret){
-paused=true;
-stream.pause();
-}
-});
-
-
-
-for(var i in stream){
-if(this[i]===undefined&&typeof stream[i]==='function'){
-this[i]=function(method){
-return function(){
-return stream[method].apply(stream,arguments);
-};
-}(i);
-}
-}
-
-
-var events=['error','close','destroy','pause','resume'];
-forEach(events,function(ev){
-stream.on(ev,self.emit.bind(self,ev));
-});
-
-
-
-self._read=function(n){
-debug('wrapped _read',n);
-if(paused){
-paused=false;
-stream.resume();
-}
-};
-
-return self;
-};
-
-
-Readable._fromList=fromList;
-
-
-
-
-
-function fromList(n,state){
-
-if(state.length===0)return null;
-
-var ret;
-if(state.objectMode)ret=state.buffer.shift();else if(!n||n>=state.length){
-
-if(state.decoder)ret=state.buffer.join('');else if(state.buffer.length===1)ret=state.buffer.head.data;else ret=state.buffer.concat(state.length);
-state.buffer.clear();
-}else{
-
-ret=fromListPartial(n,state.buffer,state.decoder);
-}
-
-return ret;
-}
-
-
-
-
-function fromListPartial(n,list,hasStrings){
-var ret;
-if(n<list.head.data.length){
-
-ret=list.head.data.slice(0,n);
-list.head.data=list.head.data.slice(n);
-}else if(n===list.head.data.length){
-
-ret=list.shift();
-}else{
-
-ret=hasStrings?copyFromBufferString(n,list):copyFromBuffer(n,list);
-}
-return ret;
-}
-
-
-
-
-
-function copyFromBufferString(n,list){
-var p=list.head;
-var c=1;
-var ret=p.data;
-n-=ret.length;
-while(p=p.next){
-var str=p.data;
-var nb=n>str.length?str.length:n;
-if(nb===str.length)ret+=str;else ret+=str.slice(0,n);
-n-=nb;
-if(n===0){
-if(nb===str.length){
-++c;
-if(p.next)list.head=p.next;else list.head=list.tail=null;
-}else{
-list.head=p;
-p.data=str.slice(nb);
-}
-break;
-}
-++c;
-}
-list.length-=c;
-return ret;
-}
-
-
-
-
-function copyFromBuffer(n,list){
-var ret=bufferShim.allocUnsafe(n);
-var p=list.head;
-var c=1;
-p.data.copy(ret);
-n-=p.data.length;
-while(p=p.next){
-var buf=p.data;
-var nb=n>buf.length?buf.length:n;
-buf.copy(ret,ret.length-n,0,nb);
-n-=nb;
-if(n===0){
-if(nb===buf.length){
-++c;
-if(p.next)list.head=p.next;else list.head=list.tail=null;
-}else{
-list.head=p;
-p.data=buf.slice(nb);
-}
-break;
-}
-++c;
-}
-list.length-=c;
-return ret;
-}
-
-function endReadable(stream){
-var state=stream._readableState;
-
-
-
-if(state.length>0)throw new Error('"endReadable()" called on non-empty stream');
-
-if(!state.endEmitted){
-state.ended=true;
-processNextTick(endReadableNT,state,stream);
-}
-}
-
-function endReadableNT(state,stream){
-
-if(!state.endEmitted&&state.length===0){
-state.endEmitted=true;
-stream.readable=false;
-stream.emit('end');
-}
-}
-
-function forEach(xs,f){
-for(var i=0,l=xs.length;i<l;i++){
-f(xs[i],i);
-}
-}
-
-function indexOf(xs,x){
-for(var i=0,l=xs.length;i<l;i++){
-if(xs[i]===x)return i;
-}
-return-1;
-}
-}).call(this,require('_process'));
-},{"./_stream_duplex":131,"./internal/streams/BufferList":136,"_process":126,"buffer":109,"buffer-shims":108,"core-util-is":110,"events":111,"inherits":113,"isarray":115,"process-nextick-args":125,"string_decoder/":142,"util":104}],134:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-module.exports=Transform;
-
-var Duplex=require('./_stream_duplex');
-
-
-var util=require('core-util-is');
-util.inherits=require('inherits');
-
-
-util.inherits(Transform,Duplex);
-
-function TransformState(stream){
-this.afterTransform=function(er,data){
-return afterTransform(stream,er,data);
-};
-
-this.needTransform=false;
-this.transforming=false;
-this.writecb=null;
-this.writechunk=null;
-this.writeencoding=null;
-}
-
-function afterTransform(stream,er,data){
-var ts=stream._transformState;
-ts.transforming=false;
-
-var cb=ts.writecb;
-
-if(!cb)return stream.emit('error',new Error('no writecb in Transform class'));
-
-ts.writechunk=null;
-ts.writecb=null;
-
-if(data!==null&&data!==undefined)stream.push(data);
-
-cb(er);
-
-var rs=stream._readableState;
-rs.reading=false;
-if(rs.needReadable||rs.length<rs.highWaterMark){
-stream._read(rs.highWaterMark);
-}
-}
-
-function Transform(options){
-if(!(this instanceof Transform))return new Transform(options);
-
-Duplex.call(this,options);
-
-this._transformState=new TransformState(this);
-
-var stream=this;
-
-
-this._readableState.needReadable=true;
-
-
-
-
-this._readableState.sync=false;
-
-if(options){
-if(typeof options.transform==='function')this._transform=options.transform;
-
-if(typeof options.flush==='function')this._flush=options.flush;
-}
-
-
-this.once('prefinish',function(){
-if(typeof this._flush==='function')this._flush(function(er,data){
-done(stream,er,data);
-});else done(stream);
-});
-}
-
-Transform.prototype.push=function(chunk,encoding){
-this._transformState.needTransform=false;
-return Duplex.prototype.push.call(this,chunk,encoding);
-};
-
-
-
-
-
-
-
-
-
-
-
-Transform.prototype._transform=function(chunk,encoding,cb){
-throw new Error('_transform() is not implemented');
-};
-
-Transform.prototype._write=function(chunk,encoding,cb){
-var ts=this._transformState;
-ts.writecb=cb;
-ts.writechunk=chunk;
-ts.writeencoding=encoding;
-if(!ts.transforming){
-var rs=this._readableState;
-if(ts.needTransform||rs.needReadable||rs.length<rs.highWaterMark)this._read(rs.highWaterMark);
-}
-};
-
-
-
-
-Transform.prototype._read=function(n){
-var ts=this._transformState;
-
-if(ts.writechunk!==null&&ts.writecb&&!ts.transforming){
-ts.transforming=true;
-this._transform(ts.writechunk,ts.writeencoding,ts.afterTransform);
-}else{
-
-
-ts.needTransform=true;
-}
-};
-
-function done(stream,er,data){
-if(er)return stream.emit('error',er);
-
-if(data!==null&&data!==undefined)stream.push(data);
-
-
-
-var ws=stream._writableState;
-var ts=stream._transformState;
-
-if(ws.length)throw new Error('Calling transform done when ws.length != 0');
-
-if(ts.transforming)throw new Error('Calling transform done when still transforming');
-
-return stream.push(null);
-}
-},{"./_stream_duplex":131,"core-util-is":110,"inherits":113}],135:[function(require,module,exports){
-(function(process){
-
-
-
-
-'use strict';
-
-module.exports=Writable;
-
-
-var processNextTick=require('process-nextick-args');
-
-
-
-var asyncWrite=!process.browser&&['v0.10','v0.9.'].indexOf(process.version.slice(0,5))>-1?setImmediate:processNextTick;
-
-
-
-var Duplex;
-
-
-Writable.WritableState=WritableState;
-
-
-var util=require('core-util-is');
-util.inherits=require('inherits');
-
-
-
-var internalUtil={
-deprecate:require('util-deprecate')};
-
-
-
-
-var Stream;
-(function(){
-try{
-Stream=require('st'+'ream');
-}catch(_){}finally{
-if(!Stream)Stream=require('events').EventEmitter;
-}
-})();
-
-
-var Buffer=require('buffer').Buffer;
-
-var bufferShim=require('buffer-shims');
-
-
-util.inherits(Writable,Stream);
-
-function nop(){}
-
-function WriteReq(chunk,encoding,cb){
-this.chunk=chunk;
-this.encoding=encoding;
-this.callback=cb;
-this.next=null;
-}
-
-function WritableState(options,stream){
-Duplex=Duplex||require('./_stream_duplex');
-
-options=options||{};
-
-
-
-this.objectMode=!!options.objectMode;
-
-if(stream instanceof Duplex)this.objectMode=this.objectMode||!!options.writableObjectMode;
-
-
-
-
-var hwm=options.highWaterMark;
-var defaultHwm=this.objectMode?16:16*1024;
-this.highWaterMark=hwm||hwm===0?hwm:defaultHwm;
-
-
-this.highWaterMark=~~this.highWaterMark;
-
-
-this.needDrain=false;
-
-this.ending=false;
-
-this.ended=false;
-
-this.finished=false;
-
-
-
-
-var noDecode=options.decodeStrings===false;
-this.decodeStrings=!noDecode;
-
-
-
-
-this.defaultEncoding=options.defaultEncoding||'utf8';
-
-
-
-
-this.length=0;
-
-
-this.writing=false;
-
-
-this.corked=0;
-
-
-
-
-
-this.sync=true;
-
-
-
-
-this.bufferProcessing=false;
-
-
-this.onwrite=function(er){
-onwrite(stream,er);
-};
-
-
-this.writecb=null;
-
-
-this.writelen=0;
-
-this.bufferedRequest=null;
-this.lastBufferedRequest=null;
-
-
-
-this.pendingcb=0;
-
-
-
-this.prefinished=false;
-
-
-this.errorEmitted=false;
-
-
-this.bufferedRequestCount=0;
-
-
-
-this.corkedRequestsFree=new CorkedRequest(this);
-}
-
-WritableState.prototype.getBuffer=function getBuffer(){
-var current=this.bufferedRequest;
-var out=[];
-while(current){
-out.push(current);
-current=current.next;
-}
-return out;
-};
-
-(function(){
-try{
-Object.defineProperty(WritableState.prototype,'buffer',{
-get:internalUtil.deprecate(function(){
-return this.getBuffer();
-},'_writableState.buffer is deprecated. Use _writableState.getBuffer '+'instead.')});
-
-}catch(_){}
-})();
-
-
-
-var realHasInstance;
-if(typeof Symbol==='function'&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==='function'){
-realHasInstance=Function.prototype[Symbol.hasInstance];
-Object.defineProperty(Writable,Symbol.hasInstance,{
-value:function(object){
-if(realHasInstance.call(this,object))return true;
-
-return object&&object._writableState instanceof WritableState;
-}});
-
-}else{
-realHasInstance=function(object){
-return object instanceof this;
-};
-}
-
-function Writable(options){
-Duplex=Duplex||require('./_stream_duplex');
-
-
-
-
-
-
-
-
-if(!realHasInstance.call(Writable,this)&&!(this instanceof Duplex)){
-return new Writable(options);
-}
-
-this._writableState=new WritableState(options,this);
-
-
-this.writable=true;
-
-if(options){
-if(typeof options.write==='function')this._write=options.write;
-
-if(typeof options.writev==='function')this._writev=options.writev;
-}
-
-Stream.call(this);
-}
-
-
-Writable.prototype.pipe=function(){
-this.emit('error',new Error('Cannot pipe, not readable'));
-};
-
-function writeAfterEnd(stream,cb){
-var er=new Error('write after end');
-
-stream.emit('error',er);
-processNextTick(cb,er);
-}
-
-
-
-
-
-
-function validChunk(stream,state,chunk,cb){
-var valid=true;
-var er=false;
-
-
-
-if(chunk===null){
-er=new TypeError('May not write null values to stream');
-}else if(!Buffer.isBuffer(chunk)&&typeof chunk!=='string'&&chunk!==undefined&&!state.objectMode){
-er=new TypeError('Invalid non-string/buffer chunk');
-}
-if(er){
-stream.emit('error',er);
-processNextTick(cb,er);
-valid=false;
-}
-return valid;
-}
-
-Writable.prototype.write=function(chunk,encoding,cb){
-var state=this._writableState;
-var ret=false;
-
-if(typeof encoding==='function'){
-cb=encoding;
-encoding=null;
-}
-
-if(Buffer.isBuffer(chunk))encoding='buffer';else if(!encoding)encoding=state.defaultEncoding;
-
-if(typeof cb!=='function')cb=nop;
-
-if(state.ended)writeAfterEnd(this,cb);else if(validChunk(this,state,chunk,cb)){
-state.pendingcb++;
-ret=writeOrBuffer(this,state,chunk,encoding,cb);
-}
-
-return ret;
-};
-
-Writable.prototype.cork=function(){
-var state=this._writableState;
-
-state.corked++;
-};
-
-Writable.prototype.uncork=function(){
-var state=this._writableState;
-
-if(state.corked){
-state.corked--;
-
-if(!state.writing&&!state.corked&&!state.finished&&!state.bufferProcessing&&state.bufferedRequest)clearBuffer(this,state);
-}
-};
-
-Writable.prototype.setDefaultEncoding=function setDefaultEncoding(encoding){
-
-if(typeof encoding==='string')encoding=encoding.toLowerCase();
-if(!(['hex','utf8','utf-8','ascii','binary','base64','ucs2','ucs-2','utf16le','utf-16le','raw'].indexOf((encoding+'').toLowerCase())>-1))throw new TypeError('Unknown encoding: '+encoding);
-this._writableState.defaultEncoding=encoding;
-return this;
-};
-
-function decodeChunk(state,chunk,encoding){
-if(!state.objectMode&&state.decodeStrings!==false&&typeof chunk==='string'){
-chunk=bufferShim.from(chunk,encoding);
-}
-return chunk;
-}
-
-
-
-
-function writeOrBuffer(stream,state,chunk,encoding,cb){
-chunk=decodeChunk(state,chunk,encoding);
-
-if(Buffer.isBuffer(chunk))encoding='buffer';
-var len=state.objectMode?1:chunk.length;
-
-state.length+=len;
-
-var ret=state.length<state.highWaterMark;
-
-if(!ret)state.needDrain=true;
-
-if(state.writing||state.corked){
-var last=state.lastBufferedRequest;
-state.lastBufferedRequest=new WriteReq(chunk,encoding,cb);
-if(last){
-last.next=state.lastBufferedRequest;
-}else{
-state.bufferedRequest=state.lastBufferedRequest;
-}
-state.bufferedRequestCount+=1;
-}else{
-doWrite(stream,state,false,len,chunk,encoding,cb);
-}
-
-return ret;
-}
-
-function doWrite(stream,state,writev,len,chunk,encoding,cb){
-state.writelen=len;
-state.writecb=cb;
-state.writing=true;
-state.sync=true;
-if(writev)stream._writev(chunk,state.onwrite);else stream._write(chunk,encoding,state.onwrite);
-state.sync=false;
-}
-
-function onwriteError(stream,state,sync,er,cb){
---state.pendingcb;
-if(sync)processNextTick(cb,er);else cb(er);
-
-stream._writableState.errorEmitted=true;
-stream.emit('error',er);
-}
-
-function onwriteStateUpdate(state){
-state.writing=false;
-state.writecb=null;
-state.length-=state.writelen;
-state.writelen=0;
-}
-
-function onwrite(stream,er){
-var state=stream._writableState;
-var sync=state.sync;
-var cb=state.writecb;
-
-onwriteStateUpdate(state);
-
-if(er)onwriteError(stream,state,sync,er,cb);else{
-
-var finished=needFinish(state);
-
-if(!finished&&!state.corked&&!state.bufferProcessing&&state.bufferedRequest){
-clearBuffer(stream,state);
-}
-
-if(sync){
-
-asyncWrite(afterWrite,stream,state,finished,cb);
-
-}else{
-afterWrite(stream,state,finished,cb);
-}
-}
-}
-
-function afterWrite(stream,state,finished,cb){
-if(!finished)onwriteDrain(stream,state);
-state.pendingcb--;
-cb();
-finishMaybe(stream,state);
-}
-
-
-
-
-function onwriteDrain(stream,state){
-if(state.length===0&&state.needDrain){
-state.needDrain=false;
-stream.emit('drain');
-}
-}
-
-
-function clearBuffer(stream,state){
-state.bufferProcessing=true;
-var entry=state.bufferedRequest;
-
-if(stream._writev&&entry&&entry.next){
-
-var l=state.bufferedRequestCount;
-var buffer=new Array(l);
-var holder=state.corkedRequestsFree;
-holder.entry=entry;
-
-var count=0;
-while(entry){
-buffer[count]=entry;
-entry=entry.next;
-count+=1;
-}
-
-doWrite(stream,state,true,state.length,buffer,'',holder.finish);
-
-
-
-state.pendingcb++;
-state.lastBufferedRequest=null;
-if(holder.next){
-state.corkedRequestsFree=holder.next;
-holder.next=null;
-}else{
-state.corkedRequestsFree=new CorkedRequest(state);
-}
-}else{
-
-while(entry){
-var chunk=entry.chunk;
-var encoding=entry.encoding;
-var cb=entry.callback;
-var len=state.objectMode?1:chunk.length;
-
-doWrite(stream,state,false,len,chunk,encoding,cb);
-entry=entry.next;
-
-
-
-
-if(state.writing){
-break;
-}
-}
-
-if(entry===null)state.lastBufferedRequest=null;
-}
-
-state.bufferedRequestCount=0;
-state.bufferedRequest=entry;
-state.bufferProcessing=false;
-}
-
-Writable.prototype._write=function(chunk,encoding,cb){
-cb(new Error('_write() is not implemented'));
-};
-
-Writable.prototype._writev=null;
-
-Writable.prototype.end=function(chunk,encoding,cb){
-var state=this._writableState;
-
-if(typeof chunk==='function'){
-cb=chunk;
-chunk=null;
-encoding=null;
-}else if(typeof encoding==='function'){
-cb=encoding;
-encoding=null;
-}
-
-if(chunk!==null&&chunk!==undefined)this.write(chunk,encoding);
-
-
-if(state.corked){
-state.corked=1;
-this.uncork();
-}
-
-
-if(!state.ending&&!state.finished)endWritable(this,state,cb);
-};
-
-function needFinish(state){
-return state.ending&&state.length===0&&state.bufferedRequest===null&&!state.finished&&!state.writing;
-}
-
-function prefinish(stream,state){
-if(!state.prefinished){
-state.prefinished=true;
-stream.emit('prefinish');
-}
-}
-
-function finishMaybe(stream,state){
-var need=needFinish(state);
-if(need){
-if(state.pendingcb===0){
-prefinish(stream,state);
-state.finished=true;
-stream.emit('finish');
-}else{
-prefinish(stream,state);
-}
-}
-return need;
-}
-
-function endWritable(stream,state,cb){
-state.ending=true;
-finishMaybe(stream,state);
-if(cb){
-if(state.finished)processNextTick(cb);else stream.once('finish',cb);
-}
-state.ended=true;
-stream.writable=false;
-}
-
-
-
-function CorkedRequest(state){
-var _this=this;
-
-this.next=null;
-this.entry=null;
-
-this.finish=function(err){
-var entry=_this.entry;
-_this.entry=null;
-while(entry){
-var cb=entry.callback;
-state.pendingcb--;
-cb(err);
-entry=entry.next;
-}
-if(state.corkedRequestsFree){
-state.corkedRequestsFree.next=_this;
-}else{
-state.corkedRequestsFree=_this;
-}
-};
-}
-}).call(this,require('_process'));
-},{"./_stream_duplex":131,"_process":126,"buffer":109,"buffer-shims":108,"core-util-is":110,"events":111,"inherits":113,"process-nextick-args":125,"util-deprecate":143}],136:[function(require,module,exports){
-'use strict';
-
-var Buffer=require('buffer').Buffer;
-
-var bufferShim=require('buffer-shims');
-
-
-module.exports=BufferList;
-
-function BufferList(){
-this.head=null;
-this.tail=null;
-this.length=0;
-}
-
-BufferList.prototype.push=function(v){
-var entry={data:v,next:null};
-if(this.length>0)this.tail.next=entry;else this.head=entry;
-this.tail=entry;
-++this.length;
-};
-
-BufferList.prototype.unshift=function(v){
-var entry={data:v,next:this.head};
-if(this.length===0)this.tail=entry;
-this.head=entry;
-++this.length;
-};
-
-BufferList.prototype.shift=function(){
-if(this.length===0)return;
-var ret=this.head.data;
-if(this.length===1)this.head=this.tail=null;else this.head=this.head.next;
---this.length;
-return ret;
-};
-
-BufferList.prototype.clear=function(){
-this.head=this.tail=null;
-this.length=0;
-};
-
-BufferList.prototype.join=function(s){
-if(this.length===0)return'';
-var p=this.head;
-var ret=''+p.data;
-while(p=p.next){
-ret+=s+p.data;
-}return ret;
-};
-
-BufferList.prototype.concat=function(n){
-if(this.length===0)return bufferShim.alloc(0);
-if(this.length===1)return this.head.data;
-var ret=bufferShim.allocUnsafe(n>>>0);
-var p=this.head;
-var i=0;
-while(p){
-p.data.copy(ret,i);
-i+=p.data.length;
-p=p.next;
-}
-return ret;
-};
-},{"buffer":109,"buffer-shims":108}],137:[function(require,module,exports){
-module.exports=require("./lib/_stream_passthrough.js");
-
-},{"./lib/_stream_passthrough.js":132}],138:[function(require,module,exports){
-(function(process){
-var Stream=function(){
-try{
-return require('st'+'ream');
-}catch(_){}
-}();
-exports=module.exports=require('./lib/_stream_readable.js');
-exports.Stream=Stream||exports;
-exports.Readable=exports;
-exports.Writable=require('./lib/_stream_writable.js');
-exports.Duplex=require('./lib/_stream_duplex.js');
-exports.Transform=require('./lib/_stream_transform.js');
-exports.PassThrough=require('./lib/_stream_passthrough.js');
-
-if(!process.browser&&process.env.READABLE_STREAM==='disable'&&Stream){
-module.exports=Stream;
-}
-
-}).call(this,require('_process'));
-},{"./lib/_stream_duplex.js":131,"./lib/_stream_passthrough.js":132,"./lib/_stream_readable.js":133,"./lib/_stream_transform.js":134,"./lib/_stream_writable.js":135,"_process":126}],139:[function(require,module,exports){
-module.exports=require("./lib/_stream_transform.js");
-
-},{"./lib/_stream_transform.js":134}],140:[function(require,module,exports){
-module.exports=require("./lib/_stream_writable.js");
-
-},{"./lib/_stream_writable.js":135}],141:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-module.exports=Stream;
-
-var EE=require('events').EventEmitter;
-var inherits=require('inherits');
-
-inherits(Stream,EE);
-Stream.Readable=require('readable-stream/readable.js');
-Stream.Writable=require('readable-stream/writable.js');
-Stream.Duplex=require('readable-stream/duplex.js');
-Stream.Transform=require('readable-stream/transform.js');
-Stream.PassThrough=require('readable-stream/passthrough.js');
-
-
-Stream.Stream=Stream;
-
-
-
-
-
-
-function Stream(){
-EE.call(this);
-}
-
-Stream.prototype.pipe=function(dest,options){
-var source=this;
-
-function ondata(chunk){
-if(dest.writable){
-if(false===dest.write(chunk)&&source.pause){
-source.pause();
-}
-}
-}
-
-source.on('data',ondata);
-
-function ondrain(){
-if(source.readable&&source.resume){
-source.resume();
-}
-}
-
-dest.on('drain',ondrain);
-
-
-
-if(!dest._isStdio&&(!options||options.end!==false)){
-source.on('end',onend);
-source.on('close',onclose);
-}
-
-var didOnEnd=false;
-function onend(){
-if(didOnEnd)return;
-didOnEnd=true;
-
-dest.end();
-}
-
-
-function onclose(){
-if(didOnEnd)return;
-didOnEnd=true;
-
-if(typeof dest.destroy==='function')dest.destroy();
-}
-
-
-function onerror(er){
-cleanup();
-if(EE.listenerCount(this,'error')===0){
-throw er;
-}
-}
-
-source.on('error',onerror);
-dest.on('error',onerror);
-
-
-function cleanup(){
-source.removeListener('data',ondata);
-dest.removeListener('drain',ondrain);
-
-source.removeListener('end',onend);
-source.removeListener('close',onclose);
-
-source.removeListener('error',onerror);
-dest.removeListener('error',onerror);
-
-source.removeListener('end',cleanup);
-source.removeListener('close',cleanup);
-
-dest.removeListener('close',cleanup);
-}
-
-source.on('end',cleanup);
-source.on('close',cleanup);
-
-dest.on('close',cleanup);
-
-dest.emit('pipe',source);
-
-
-return dest;
-};
-
-},{"events":111,"inherits":113,"readable-stream/duplex.js":130,"readable-stream/passthrough.js":137,"readable-stream/readable.js":138,"readable-stream/transform.js":139,"readable-stream/writable.js":140}],142:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var Buffer=require('buffer').Buffer;
-
-var isBufferEncoding=Buffer.isEncoding||
-function(encoding){
-switch(encoding&&encoding.toLowerCase()){
-case'hex':case'utf8':case'utf-8':case'ascii':case'binary':case'base64':case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':case'raw':return true;
-default:return false;}
-
-};
-
-
-function assertEncoding(encoding){
-if(encoding&&!isBufferEncoding(encoding)){
-throw new Error('Unknown encoding: '+encoding);
-}
-}
-
-
-
-
-
-
-
-
-
-var StringDecoder=exports.StringDecoder=function(encoding){
-this.encoding=(encoding||'utf8').toLowerCase().replace(/[-_]/,'');
-assertEncoding(encoding);
-switch(this.encoding){
-case'utf8':
-
-this.surrogateSize=3;
-break;
-case'ucs2':
-case'utf16le':
-
-this.surrogateSize=2;
-this.detectIncompleteChar=utf16DetectIncompleteChar;
-break;
-case'base64':
-
-this.surrogateSize=3;
-this.detectIncompleteChar=base64DetectIncompleteChar;
-break;
-default:
-this.write=passThroughWrite;
-return;}
-
-
-
-
-this.charBuffer=new Buffer(6);
-
-this.charReceived=0;
-
-this.charLength=0;
-};
-
-
-
-
-
-
-
-
-
-
-
-StringDecoder.prototype.write=function(buffer){
-var charStr='';
-
-while(this.charLength){
-
-var available=buffer.length>=this.charLength-this.charReceived?
-this.charLength-this.charReceived:
-buffer.length;
-
-
-buffer.copy(this.charBuffer,this.charReceived,0,available);
-this.charReceived+=available;
-
-if(this.charReceived<this.charLength){
-
-return'';
-}
-
-
-buffer=buffer.slice(available,buffer.length);
-
-
-charStr=this.charBuffer.slice(0,this.charLength).toString(this.encoding);
-
-
-var charCode=charStr.charCodeAt(charStr.length-1);
-if(charCode>=0xD800&&charCode<=0xDBFF){
-this.charLength+=this.surrogateSize;
-charStr='';
-continue;
-}
-this.charReceived=this.charLength=0;
-
-
-if(buffer.length===0){
-return charStr;
-}
-break;
-}
-
-
-this.detectIncompleteChar(buffer);
-
-var end=buffer.length;
-if(this.charLength){
-
-buffer.copy(this.charBuffer,0,buffer.length-this.charReceived,end);
-end-=this.charReceived;
-}
-
-charStr+=buffer.toString(this.encoding,0,end);
-
-var end=charStr.length-1;
-var charCode=charStr.charCodeAt(end);
-
-if(charCode>=0xD800&&charCode<=0xDBFF){
-var size=this.surrogateSize;
-this.charLength+=size;
-this.charReceived+=size;
-this.charBuffer.copy(this.charBuffer,size,0,size);
-buffer.copy(this.charBuffer,0,0,size);
-return charStr.substring(0,end);
-}
-
-
-return charStr;
-};
-
-
-
-
-
-StringDecoder.prototype.detectIncompleteChar=function(buffer){
-
-var i=buffer.length>=3?3:buffer.length;
-
-
-
-for(;i>0;i--){
-var c=buffer[buffer.length-i];
-
-
-
-
-if(i==1&&c>>5==0x06){
-this.charLength=2;
-break;
-}
-
-
-if(i<=2&&c>>4==0x0E){
-this.charLength=3;
-break;
-}
-
-
-if(i<=3&&c>>3==0x1E){
-this.charLength=4;
-break;
-}
-}
-this.charReceived=i;
-};
-
-StringDecoder.prototype.end=function(buffer){
-var res='';
-if(buffer&&buffer.length)
-res=this.write(buffer);
-
-if(this.charReceived){
-var cr=this.charReceived;
-var buf=this.charBuffer;
-var enc=this.encoding;
-res+=buf.slice(0,cr).toString(enc);
-}
-
-return res;
-};
-
-function passThroughWrite(buffer){
-return buffer.toString(this.encoding);
-}
-
-function utf16DetectIncompleteChar(buffer){
-this.charReceived=buffer.length%2;
-this.charLength=this.charReceived?2:0;
-}
-
-function base64DetectIncompleteChar(buffer){
-this.charReceived=buffer.length%3;
-this.charLength=this.charReceived?3:0;
-}
-
-},{"buffer":109}],143:[function(require,module,exports){
-(function(global){
-
-
-
-
-
-module.exports=deprecate;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function deprecate(fn,msg){
-if(config('noDeprecation')){
-return fn;
-}
-
-var warned=false;
-function deprecated(){
-if(!warned){
-if(config('throwDeprecation')){
-throw new Error(msg);
-}else if(config('traceDeprecation')){
-console.trace(msg);
-}else{
-console.warn(msg);
-}
-warned=true;
-}
-return fn.apply(this,arguments);
-}
-
-return deprecated;
-}
-
-
-
-
-
-
-
-
-
-function config(name){
-
-try{
-if(!global.localStorage)return false;
-}catch(_){
-return false;
-}
-var val=global.localStorage[name];
-if(null==val)return false;
-return String(val).toLowerCase()==='true';
-}
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{}],144:[function(require,module,exports){
-arguments[4][113][0].apply(exports,arguments);
-},{"dup":113}],145:[function(require,module,exports){
-module.exports=function isBuffer(arg){
-return arg&&typeof arg==='object'&&
-typeof arg.copy==='function'&&
-typeof arg.fill==='function'&&
-typeof arg.readUInt8==='function';
-};
-},{}],146:[function(require,module,exports){
-(function(process,global){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var formatRegExp=/%[sdj%]/g;
-exports.format=function(f){
-if(!isString(f)){
-var objects=[];
-for(var i=0;i<arguments.length;i++){
-objects.push(inspect(arguments[i]));
-}
-return objects.join(' ');
-}
-
-var i=1;
-var args=arguments;
-var len=args.length;
-var str=String(f).replace(formatRegExp,function(x){
-if(x==='%%')return'%';
-if(i>=len)return x;
-switch(x){
-case'%s':return String(args[i++]);
-case'%d':return Number(args[i++]);
-case'%j':
-try{
-return JSON.stringify(args[i++]);
-}catch(_){
-return'[Circular]';
-}
-default:
-return x;}
-
-});
-for(var x=args[i];i<len;x=args[++i]){
-if(isNull(x)||!isObject(x)){
-str+=' '+x;
-}else{
-str+=' '+inspect(x);
-}
-}
-return str;
-};
-
-
-
-
-
-exports.deprecate=function(fn,msg){
-
-if(isUndefined(global.process)){
-return function(){
-return exports.deprecate(fn,msg).apply(this,arguments);
-};
-}
-
-if(process.noDeprecation===true){
-return fn;
-}
-
-var warned=false;
-function deprecated(){
-if(!warned){
-if(process.throwDeprecation){
-throw new Error(msg);
-}else if(process.traceDeprecation){
-console.trace(msg);
-}else{
-console.error(msg);
-}
-warned=true;
-}
-return fn.apply(this,arguments);
-}
-
-return deprecated;
-};
-
-
-var debugs={};
-var debugEnviron;
-exports.debuglog=function(set){
-if(isUndefined(debugEnviron))
-debugEnviron=process.env.NODE_DEBUG||'';
-set=set.toUpperCase();
-if(!debugs[set]){
-if(new RegExp('\\b'+set+'\\b','i').test(debugEnviron)){
-var pid=process.pid;
-debugs[set]=function(){
-var msg=exports.format.apply(exports,arguments);
-console.error('%s %d: %s',set,pid,msg);
-};
-}else{
-debugs[set]=function(){};
-}
-}
-return debugs[set];
-};
-
-
-
-
-
-
-
-
-
-
-function inspect(obj,opts){
-
-var ctx={
-seen:[],
-stylize:stylizeNoColor};
-
-
-if(arguments.length>=3)ctx.depth=arguments[2];
-if(arguments.length>=4)ctx.colors=arguments[3];
-if(isBoolean(opts)){
-
-ctx.showHidden=opts;
-}else if(opts){
-
-exports._extend(ctx,opts);
-}
-
-if(isUndefined(ctx.showHidden))ctx.showHidden=false;
-if(isUndefined(ctx.depth))ctx.depth=2;
-if(isUndefined(ctx.colors))ctx.colors=false;
-if(isUndefined(ctx.customInspect))ctx.customInspect=true;
-if(ctx.colors)ctx.stylize=stylizeWithColor;
-return formatValue(ctx,obj,ctx.depth);
-}
-exports.inspect=inspect;
-
-
-
-inspect.colors={
-'bold':[1,22],
-'italic':[3,23],
-'underline':[4,24],
-'inverse':[7,27],
-'white':[37,39],
-'grey':[90,39],
-'black':[30,39],
-'blue':[34,39],
-'cyan':[36,39],
-'green':[32,39],
-'magenta':[35,39],
-'red':[31,39],
-'yellow':[33,39]};
-
-
-
-inspect.styles={
-'special':'cyan',
-'number':'yellow',
-'boolean':'yellow',
-'undefined':'grey',
-'null':'bold',
-'string':'green',
-'date':'magenta',
-
-'regexp':'red'};
-
-
-
-function stylizeWithColor(str,styleType){
-var style=inspect.styles[styleType];
-
-if(style){
-return'\u001b['+inspect.colors[style][0]+'m'+str+
-'\u001b['+inspect.colors[style][1]+'m';
-}else{
-return str;
-}
-}
-
-
-function stylizeNoColor(str,styleType){
-return str;
-}
-
-
-function arrayToHash(array){
-var hash={};
-
-array.forEach(function(val,idx){
-hash[val]=true;
-});
-
-return hash;
-}
-
-
-function formatValue(ctx,value,recurseTimes){
-
-
-if(ctx.customInspect&&
-value&&
-isFunction(value.inspect)&&
-
-value.inspect!==exports.inspect&&
-
-!(value.constructor&&value.constructor.prototype===value)){
-var ret=value.inspect(recurseTimes,ctx);
-if(!isString(ret)){
-ret=formatValue(ctx,ret,recurseTimes);
-}
-return ret;
-}
-
-
-var primitive=formatPrimitive(ctx,value);
-if(primitive){
-return primitive;
-}
-
-
-var keys=Object.keys(value);
-var visibleKeys=arrayToHash(keys);
-
-if(ctx.showHidden){
-keys=Object.getOwnPropertyNames(value);
-}
-
-
-
-if(isError(value)&&(
-keys.indexOf('message')>=0||keys.indexOf('description')>=0)){
-return formatError(value);
-}
-
-
-if(keys.length===0){
-if(isFunction(value)){
-var name=value.name?': '+value.name:'';
-return ctx.stylize('[Function'+name+']','special');
-}
-if(isRegExp(value)){
-return ctx.stylize(RegExp.prototype.toString.call(value),'regexp');
-}
-if(isDate(value)){
-return ctx.stylize(Date.prototype.toString.call(value),'date');
-}
-if(isError(value)){
-return formatError(value);
-}
-}
-
-var base='',array=false,braces=['{','}'];
-
-
-if(isArray(value)){
-array=true;
-braces=['[',']'];
-}
-
-
-if(isFunction(value)){
-var n=value.name?': '+value.name:'';
-base=' [Function'+n+']';
-}
-
-
-if(isRegExp(value)){
-base=' '+RegExp.prototype.toString.call(value);
-}
-
-
-if(isDate(value)){
-base=' '+Date.prototype.toUTCString.call(value);
-}
-
-
-if(isError(value)){
-base=' '+formatError(value);
-}
-
-if(keys.length===0&&(!array||value.length==0)){
-return braces[0]+base+braces[1];
-}
-
-if(recurseTimes<0){
-if(isRegExp(value)){
-return ctx.stylize(RegExp.prototype.toString.call(value),'regexp');
-}else{
-return ctx.stylize('[Object]','special');
-}
-}
-
-ctx.seen.push(value);
-
-var output;
-if(array){
-output=formatArray(ctx,value,recurseTimes,visibleKeys,keys);
-}else{
-output=keys.map(function(key){
-return formatProperty(ctx,value,recurseTimes,visibleKeys,key,array);
-});
-}
-
-ctx.seen.pop();
-
-return reduceToSingleString(output,base,braces);
-}
-
-
-function formatPrimitive(ctx,value){
-if(isUndefined(value))
-return ctx.stylize('undefined','undefined');
-if(isString(value)){
-var simple='\''+JSON.stringify(value).replace(/^"|"$/g,'').
-replace(/'/g,"\\'").
-replace(/\\"/g,'"')+'\'';
-return ctx.stylize(simple,'string');
-}
-if(isNumber(value))
-return ctx.stylize(''+value,'number');
-if(isBoolean(value))
-return ctx.stylize(''+value,'boolean');
-
-if(isNull(value))
-return ctx.stylize('null','null');
-}
-
-
-function formatError(value){
-return'['+Error.prototype.toString.call(value)+']';
-}
-
-
-function formatArray(ctx,value,recurseTimes,visibleKeys,keys){
-var output=[];
-for(var i=0,l=value.length;i<l;++i){
-if(hasOwnProperty(value,String(i))){
-output.push(formatProperty(ctx,value,recurseTimes,visibleKeys,
-String(i),true));
-}else{
-output.push('');
-}
-}
-keys.forEach(function(key){
-if(!key.match(/^\d+$/)){
-output.push(formatProperty(ctx,value,recurseTimes,visibleKeys,
-key,true));
-}
-});
-return output;
-}
-
-
-function formatProperty(ctx,value,recurseTimes,visibleKeys,key,array){
-var name,str,desc;
-desc=Object.getOwnPropertyDescriptor(value,key)||{value:value[key]};
-if(desc.get){
-if(desc.set){
-str=ctx.stylize('[Getter/Setter]','special');
-}else{
-str=ctx.stylize('[Getter]','special');
-}
-}else{
-if(desc.set){
-str=ctx.stylize('[Setter]','special');
-}
-}
-if(!hasOwnProperty(visibleKeys,key)){
-name='['+key+']';
-}
-if(!str){
-if(ctx.seen.indexOf(desc.value)<0){
-if(isNull(recurseTimes)){
-str=formatValue(ctx,desc.value,null);
-}else{
-str=formatValue(ctx,desc.value,recurseTimes-1);
-}
-if(str.indexOf('\n')>-1){
-if(array){
-str=str.split('\n').map(function(line){
-return' '+line;
-}).join('\n').substr(2);
-}else{
-str='\n'+str.split('\n').map(function(line){
-return' '+line;
-}).join('\n');
-}
-}
-}else{
-str=ctx.stylize('[Circular]','special');
-}
-}
-if(isUndefined(name)){
-if(array&&key.match(/^\d+$/)){
-return str;
-}
-name=JSON.stringify(''+key);
-if(name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)){
-name=name.substr(1,name.length-2);
-name=ctx.stylize(name,'name');
-}else{
-name=name.replace(/'/g,"\\'").
-replace(/\\"/g,'"').
-replace(/(^"|"$)/g,"'");
-name=ctx.stylize(name,'string');
-}
-}
-
-return name+': '+str;
-}
-
-
-function reduceToSingleString(output,base,braces){
-var numLinesEst=0;
-var length=output.reduce(function(prev,cur){
-numLinesEst++;
-if(cur.indexOf('\n')>=0)numLinesEst++;
-return prev+cur.replace(/\u001b\[\d\d?m/g,'').length+1;
-},0);
-
-if(length>60){
-return braces[0]+(
-base===''?'':base+'\n ')+
-' '+
-output.join(',\n ')+
-' '+
-braces[1];
-}
-
-return braces[0]+base+' '+output.join(', ')+' '+braces[1];
-}
-
-
-
-
-function isArray(ar){
-return Array.isArray(ar);
-}
-exports.isArray=isArray;
-
-function isBoolean(arg){
-return typeof arg==='boolean';
-}
-exports.isBoolean=isBoolean;
-
-function isNull(arg){
-return arg===null;
-}
-exports.isNull=isNull;
-
-function isNullOrUndefined(arg){
-return arg==null;
-}
-exports.isNullOrUndefined=isNullOrUndefined;
-
-function isNumber(arg){
-return typeof arg==='number';
-}
-exports.isNumber=isNumber;
-
-function isString(arg){
-return typeof arg==='string';
-}
-exports.isString=isString;
-
-function isSymbol(arg){
-return typeof arg==='symbol';
-}
-exports.isSymbol=isSymbol;
-
-function isUndefined(arg){
-return arg===void 0;
-}
-exports.isUndefined=isUndefined;
-
-function isRegExp(re){
-return isObject(re)&&objectToString(re)==='[object RegExp]';
-}
-exports.isRegExp=isRegExp;
-
-function isObject(arg){
-return typeof arg==='object'&&arg!==null;
-}
-exports.isObject=isObject;
-
-function isDate(d){
-return isObject(d)&&objectToString(d)==='[object Date]';
-}
-exports.isDate=isDate;
-
-function isError(e){
-return isObject(e)&&(
-objectToString(e)==='[object Error]'||e instanceof Error);
-}
-exports.isError=isError;
-
-function isFunction(arg){
-return typeof arg==='function';
-}
-exports.isFunction=isFunction;
-
-function isPrimitive(arg){
-return arg===null||
-typeof arg==='boolean'||
-typeof arg==='number'||
-typeof arg==='string'||
-typeof arg==='symbol'||
-typeof arg==='undefined';
-}
-exports.isPrimitive=isPrimitive;
-
-exports.isBuffer=require('./support/isBuffer');
-
-function objectToString(o){
-return Object.prototype.toString.call(o);
-}
-
-
-function pad(n){
-return n<10?'0'+n.toString(10):n.toString(10);
-}
-
-
-var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep',
-'Oct','Nov','Dec'];
-
-
-function timestamp(){
-var d=new Date();
-var time=[pad(d.getHours()),
-pad(d.getMinutes()),
-pad(d.getSeconds())].join(':');
-return[d.getDate(),months[d.getMonth()],time].join(' ');
-}
-
-
-
-exports.log=function(){
-console.log('%s - %s',timestamp(),exports.format.apply(exports,arguments));
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-exports.inherits=require('inherits');
-
-exports._extend=function(origin,add){
-
-if(!add||!isObject(add))return origin;
-
-var keys=Object.keys(add);
-var i=keys.length;
-while(i--){
-origin[keys[i]]=add[keys[i]];
-}
-return origin;
-};
-
-function hasOwnProperty(obj,prop){
-return Object.prototype.hasOwnProperty.call(obj,prop);
-}
-
-}).call(this,require('_process'),typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"./support/isBuffer":145,"_process":126,"inherits":144}],147:[function(require,module,exports){
-(function(process){
-
-
-
-
-
-'use strict';
-
-const debug=require('debug');
-const marky=require('marky');
-
-const EventEmitter=require('events').EventEmitter;
-const isWindows=process.platform==='win32';
-
-
-const isBrowser=process.browser;
-
-const colors={
-red:isBrowser?'crimson':1,
-yellow:isBrowser?'gold':3,
-cyan:isBrowser?'darkturquoise':6,
-green:isBrowser?'forestgreen':2,
-blue:isBrowser?'steelblue':4,
-magenta:isBrowser?'palevioletred':5};
-
-
-
-debug.colors=[colors.cyan,colors.green,colors.blue,colors.magenta];
-
-class Emitter extends EventEmitter{
-
-
-
-
-
-
-issueStatus(title,argsArray){
-if(title==='status'||title==='statusEnd'){
-this.emit(title,[title,...argsArray]);
-}
-}
-
-
-
-
-
-
-
-issueWarning(title,argsArray){
-this.emit('warning',[title,...argsArray]);
-}}
-
-
-const loggersByTitle={};
-const loggingBufferColumns=25;
-
-class Log{
-static _logToStdErr(title,argsArray){
-const log=Log.loggerfn(title);
-log(...argsArray);
-}
-
-static loggerfn(title){
-let log=loggersByTitle[title];
-if(!log){
-log=debug(title);
-loggersByTitle[title]=log;
-
-if(title.endsWith('error')){
-log.color=colors.red;
-}else if(title.endsWith('warn')){
-log.color=colors.yellow;
-}
-}
-return log;
-}
-
-static setLevel(level){
-switch(level){
-case'silent':
-debug.enable('-*');
-break;
-case'verbose':
-debug.enable('*');
-break;
-case'error':
-debug.enable('-*, *:error');
-break;
-default:
-debug.enable('*, -*:verbose');}
-
-}
-
-
-
-
-
-
-
-static formatProtocol(prefix,data,level){
-const columns=!process||process.browser?Infinity:process.stdout.columns;
-const method=data.method||'?????';
-const maxLength=columns-method.length-prefix.length-loggingBufferColumns;
-
-const snippet=data.params&&method!=='IO.read'?
-JSON.stringify(data.params).substr(0,maxLength):'';
-Log._logToStdErr(`${prefix}:${level||''}`,[method,snippet]);
-}
-
-static time({msg,id,args=[]},level='log'){
-marky.mark(id);
-Log[level]('status',msg,...args);
-}
-
-static timeEnd({msg,id,args=[]},level='verbose'){
-Log[level]('statusEnd',msg,...args);
-marky.stop(id);
-}
-
-static log(title,...args){
-Log.events.issueStatus(title,args);
-return Log._logToStdErr(title,args);
-}
-
-static warn(title,...args){
-Log.events.issueWarning(title,args);
-return Log._logToStdErr(`${title}:warn`,args);
-}
-
-static error(title,...args){
-return Log._logToStdErr(`${title}:error`,args);
-}
-
-static verbose(title,...args){
-Log.events.issueStatus(title,args);
-return Log._logToStdErr(`${title}:verbose`,args);
-}
-
-
-
-
-
-
-static greenify(str){
-return`${Log.green}${str}${Log.reset}`;
-}
-
-
-
-
-
-
-static redify(str){
-return`${Log.red}${str}${Log.reset}`;
-}
-
-static get green(){
-return'\x1B[32m';
-}
-
-static get red(){
-return'\x1B[31m';
-}
-
-static get yellow(){
-return'\x1b[33m';
-}
-
-static get purple(){
-return'\x1b[95m';
-}
-
-static get reset(){
-return'\x1B[0m';
-}
-
-static get bold(){
-return'\x1b[1m';
-}
-
-static get dim(){
-return'\x1b[2m';
-}
-
-static get tick(){
-return isWindows?'\u221A':'✓';
-}
-
-static get cross(){
-return isWindows?'\u00D7':'✘';
-}
-
-static get whiteSmallSquare(){
-return isWindows?'\u0387':'▫';
-}
-
-static get heavyHorizontal(){
-return isWindows?'\u2500':'━';
-}
-
-static get heavyVertical(){
-return isWindows?'\u2502 ':'┃ ';
-}
-
-static get heavyUpAndRight(){
-return isWindows?'\u2514':'┗';
-}
-
-static get heavyVerticalAndRight(){
-return isWindows?'\u251C':'┣';
-}
-
-static get heavyDownAndHorizontal(){
-return isWindows?'\u252C':'┳';
-}
-
-static get doubleLightHorizontal(){
-return'──';
-}}
-
-
-Log.events=new Emitter();
-Log.takeTimeEntries=_=>{
-const entries=marky.getEntries();
-marky.clear();
-return entries;
-};
-
-module.exports=Log;
-
-}).call(this,require('_process'));
-},{"_process":126,"debug":148,"events":111,"marky":150}],148:[function(require,module,exports){
-(function(process){
-
-
-
-
-
-
-exports=module.exports=require('./debug');
-exports.log=log;
-exports.formatArgs=formatArgs;
-exports.save=save;
-exports.load=load;
-exports.useColors=useColors;
-exports.storage='undefined'!=typeof chrome&&
-'undefined'!=typeof chrome.storage?
-chrome.storage.local:
-localstorage();
-
-
-
-
-
-exports.colors=[
-'lightseagreen',
-'forestgreen',
-'goldenrod',
-'dodgerblue',
-'darkorchid',
-'crimson'];
-
-
-
-
-
-
-
-
-
-
-function useColors(){
-
-
-
-if(typeof window!=='undefined'&&window.process&&window.process.type==='renderer'){
-return true;
-}
-
-
-
-return typeof document!=='undefined'&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||
-
-typeof window!=='undefined'&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||
-
-
-typeof navigator!=='undefined'&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||
-
-typeof navigator!=='undefined'&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
-}
-
-
-
-
-
-exports.formatters.j=function(v){
-try{
-return JSON.stringify(v);
-}catch(err){
-return'[UnexpectedJSONParseError]: '+err.message;
-}
-};
-
-
-
-
-
-
-
-
-function formatArgs(args){
-var useColors=this.useColors;
-
-args[0]=(useColors?'%c':'')+
-this.namespace+(
-useColors?' %c':' ')+
-args[0]+(
-useColors?'%c ':' ')+
-'+'+exports.humanize(this.diff);
-
-if(!useColors)return;
-
-var c='color: '+this.color;
-args.splice(1,0,c,'color: inherit');
-
-
-
-
-var index=0;
-var lastC=0;
-args[0].replace(/%[a-zA-Z%]/g,function(match){
-if('%%'===match)return;
-index++;
-if('%c'===match){
-
-
-lastC=index;
-}
-});
-
-args.splice(lastC,0,c);
-}
-
-
-
-
-
-
-
-
-function log(){
-
-
-return'object'===typeof console&&
-console.log&&
-Function.prototype.apply.call(console.log,console,arguments);
-}
-
-
-
-
-
-
-
-
-function save(namespaces){
-try{
-if(null==namespaces){
-exports.storage.removeItem('debug');
-}else{
-exports.storage.debug=namespaces;
-}
-}catch(e){}
-}
-
-
-
-
-
-
-
-
-function load(){
-var r;
-try{
-r=exports.storage.debug;
-}catch(e){}
-
-
-if(!r&&typeof process!=='undefined'&&'env'in process){
-r=process.env.DEBUG;
-}
-
-return r;
-}
-
-
-
-
-
-exports.enable(load());
-
-
-
-
-
-
-
-
-
-
-
-
-function localstorage(){
-try{
-return window.localStorage;
-}catch(e){}
-}
-
-}).call(this,require('_process'));
-},{"./debug":149,"_process":126}],149:[function(require,module,exports){
-
-
-
-
-
-
-
-
-exports=module.exports=createDebug.debug=createDebug['default']=createDebug;
-exports.coerce=coerce;
-exports.disable=disable;
-exports.enable=enable;
-exports.enabled=enabled;
-exports.humanize=require('ms');
-
-
-
-
-
-exports.names=[];
-exports.skips=[];
-
-
-
-
-
-
-
-exports.formatters={};
-
-
-
-
-
-var prevTime;
-
-
-
-
-
-
-
-
-function selectColor(namespace){
-var hash=0,i;
-
-for(i in namespace){
-hash=(hash<<5)-hash+namespace.charCodeAt(i);
-hash|=0;
-}
-
-return exports.colors[Math.abs(hash)%exports.colors.length];
-}
-
-
-
-
-
-
-
-
-
-function createDebug(namespace){
-
-function debug(){
-
-if(!debug.enabled)return;
-
-var self=debug;
-
-
-var curr=+new Date();
-var ms=curr-(prevTime||curr);
-self.diff=ms;
-self.prev=prevTime;
-self.curr=curr;
-prevTime=curr;
-
-
-var args=new Array(arguments.length);
-for(var i=0;i<args.length;i++){
-args[i]=arguments[i];
-}
-
-args[0]=exports.coerce(args[0]);
-
-if('string'!==typeof args[0]){
-
-args.unshift('%O');
-}
-
-
-var index=0;
-args[0]=args[0].replace(/%([a-zA-Z%])/g,function(match,format){
-
-if(match==='%%')return match;
-index++;
-var formatter=exports.formatters[format];
-if('function'===typeof formatter){
-var val=args[index];
-match=formatter.call(self,val);
-
-
-args.splice(index,1);
-index--;
-}
-return match;
-});
-
-
-exports.formatArgs.call(self,args);
-
-var logFn=debug.log||exports.log||console.log.bind(console);
-logFn.apply(self,args);
-}
-
-debug.namespace=namespace;
-debug.enabled=exports.enabled(namespace);
-debug.useColors=exports.useColors();
-debug.color=selectColor(namespace);
-
-
-if('function'===typeof exports.init){
-exports.init(debug);
-}
-
-return debug;
-}
-
-
-
-
-
-
-
-
-
-function enable(namespaces){
-exports.save(namespaces);
-
-exports.names=[];
-exports.skips=[];
-
-var split=(typeof namespaces==='string'?namespaces:'').split(/[\s,]+/);
-var len=split.length;
-
-for(var i=0;i<len;i++){
-if(!split[i])continue;
-namespaces=split[i].replace(/\*/g,'.*?');
-if(namespaces[0]==='-'){
-exports.skips.push(new RegExp('^'+namespaces.substr(1)+'$'));
-}else{
-exports.names.push(new RegExp('^'+namespaces+'$'));
-}
-}
-}
-
-
-
-
-
-
-
-function disable(){
-exports.enable('');
-}
-
-
-
-
-
-
-
-
-
-function enabled(name){
-var i,len;
-for(i=0,len=exports.skips.length;i<len;i++){
-if(exports.skips[i].test(name)){
-return false;
-}
-}
-for(i=0,len=exports.names.length;i<len;i++){
-if(exports.names[i].test(name)){
-return true;
-}
-}
-return false;
-}
-
-
-
-
-
-
-
-
-
-function coerce(val){
-if(val instanceof Error)return val.stack||val.message;
-return val;
-}
-
-},{"ms":151}],150:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports,'__esModule',{value:true});
-
-
-var perf=typeof performance!=='undefined'&&performance;
-
-var now=perf&&perf.now?function(){return perf.now();}:function(){return Date.now();};
-
-function throwIfEmpty(name){
-if(!name){
-throw new Error('name must be non-empty');
-}
-}
-
-
-function insertSorted(arr,item){
-var low=0;
-var high=arr.length;
-var mid;
-while(low<high){
-mid=low+high>>>1;
-if(arr[mid].startTime<item.startTime){
-low=mid+1;
-}else{
-high=mid;
-}
-}
-arr.splice(low,0,item);
-}
-
-if(perf&&perf.mark){
-exports.mark=function(name){
-throwIfEmpty(name);
-perf.mark("start "+name);
-};
-exports.stop=function(name){
-throwIfEmpty(name);
-perf.mark("end "+name);
-perf.measure(name,"start "+name,"end "+name);
-var entries=perf.getEntriesByName(name);
-return entries[entries.length-1];
-};
-exports.getEntries=function(){return perf.getEntriesByType('measure');};
-exports.clear=function(){
-perf.clearMarks();
-perf.clearMeasures();
-};
-}else{
-var marks={};
-var entries=[];
-exports.mark=function(name){
-throwIfEmpty(name);
-var startTime=now();
-marks['$'+name]=startTime;
-};
-exports.stop=function(name){
-throwIfEmpty(name);
-var endTime=now();
-var startTime=marks['$'+name];
-if(!startTime){
-throw new Error("no known mark: "+name);
-}
-var entry={
-startTime:startTime,
-name:name,
-duration:endTime-startTime,
-entryType:'measure'};
-
-
-
-
-insertSorted(entries,entry);
-return entry;
-};
-exports.getEntries=function(){return entries;};
-exports.clear=function(){entries=[];};
-}
-
-},{}],151:[function(require,module,exports){
-
-
-
-
-var s=1000;
-var m=s*60;
-var h=m*60;
-var d=h*24;
-var y=d*365.25;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-module.exports=function(val,options){
-options=options||{};
-var type=typeof val;
-if(type==='string'&&val.length>0){
-return parse(val);
-}else if(type==='number'&&isNaN(val)===false){
-return options.long?fmtLong(val):fmtShort(val);
-}
-throw new Error(
-'val is not a non-empty string or a valid number. val='+
-JSON.stringify(val));
-
-};
-
-
-
-
-
-
-
-
-
-function parse(str){
-str=String(str);
-if(str.length>100){
-return;
-}
-var match=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
-str);
-
-if(!match){
-return;
-}
-var n=parseFloat(match[1]);
-var type=(match[2]||'ms').toLowerCase();
-switch(type){
-case'years':
-case'year':
-case'yrs':
-case'yr':
-case'y':
-return n*y;
-case'days':
-case'day':
-case'd':
-return n*d;
-case'hours':
-case'hour':
-case'hrs':
-case'hr':
-case'h':
-return n*h;
-case'minutes':
-case'minute':
-case'mins':
-case'min':
-case'm':
-return n*m;
-case'seconds':
-case'second':
-case'secs':
-case'sec':
-case's':
-return n*s;
-case'milliseconds':
-case'millisecond':
-case'msecs':
-case'msec':
-case'ms':
-return n;
-default:
-return undefined;}
-
-}
-
-
-
-
-
-
-
-
-
-function fmtShort(ms){
-if(ms>=d){
-return Math.round(ms/d)+'d';
-}
-if(ms>=h){
-return Math.round(ms/h)+'h';
-}
-if(ms>=m){
-return Math.round(ms/m)+'m';
-}
-if(ms>=s){
-return Math.round(ms/s)+'s';
-}
-return ms+'ms';
-}
-
-
-
-
-
-
-
-
-
-function fmtLong(ms){
-return plural(ms,d,'day')||
-plural(ms,h,'hour')||
-plural(ms,m,'minute')||
-plural(ms,s,'second')||
-ms+' ms';
-}
-
-
-
-
-
-function plural(ms,n,name){
-if(ms<n){
-return;
-}
-if(ms<n*1.5){
-return Math.floor(ms/n)+' '+name;
-}
-return Math.ceil(ms/n)+' '+name+'s';
-}
-
-},{}],152:[function(require,module,exports){
-
-
-var langs=[
-"aa",
-"ab",
-"ae",
-"af",
-"ak",
-"am",
-"an",
-"ar",
-"as",
-"av",
-"ay",
-"az",
-"ba",
-"be",
-"bg",
-"bh",
-"bi",
-"bm",
-"bn",
-"bo",
-"br",
-"bs",
-"ca",
-"ce",
-"ch",
-"co",
-"cr",
-"cs",
-"cu",
-"cv",
-"cy",
-"da",
-"de",
-"dv",
-"dz",
-"ee",
-"el",
-"en",
-"eo",
-"es",
-"et",
-"eu",
-"fa",
-"ff",
-"fi",
-"fj",
-"fo",
-"fr",
-"fy",
-"ga",
-"gd",
-"gl",
-"gn",
-"gu",
-"gv",
-"ha",
-"he",
-"hi",
-"ho",
-"hr",
-"ht",
-"hu",
-"hy",
-"hz",
-"ia",
-"id",
-"ie",
-"ig",
-"ii",
-"ik",
-"in",
-"io",
-"is",
-"it",
-"iu",
-"iw",
-"ja",
-"ji",
-"jv",
-"jw",
-"ka",
-"kg",
-"ki",
-"kj",
-"kk",
-"kl",
-"km",
-"kn",
-"ko",
-"kr",
-"ks",
-"ku",
-"kv",
-"kw",
-"ky",
-"la",
-"lb",
-"lg",
-"li",
-"ln",
-"lo",
-"lt",
-"lu",
-"lv",
-"mg",
-"mh",
-"mi",
-"mk",
-"ml",
-"mn",
-"mo",
-"mr",
-"ms",
-"mt",
-"my",
-"na",
-"nb",
-"nd",
-"ne",
-"ng",
-"nl",
-"nn",
-"no",
-"nr",
-"nv",
-"ny",
-"oc",
-"oj",
-"om",
-"or",
-"os",
-"pa",
-"pi",
-"pl",
-"ps",
-"pt",
-"qu",
-"rm",
-"rn",
-"ro",
-"ru",
-"rw",
-"sa",
-"sc",
-"sd",
-"se",
-"sg",
-"sh",
-"si",
-"sk",
-"sl",
-"sm",
-"sn",
-"so",
-"sq",
-"sr",
-"ss",
-"st",
-"su",
-"sv",
-"sw",
-"ta",
-"te",
-"tg",
-"th",
-"ti",
-"tk",
-"tl",
-"tn",
-"to",
-"tr",
-"ts",
-"tt",
-"tw",
-"ty",
-"ug",
-"uk",
-"ur",
-"uz",
-"ve",
-"vi",
-"vo",
-"wa",
-"wo",
-"xh",
-"yi",
-"yo",
-"za",
-"zh",
-"zu",
-"aaa",
-"aab",
-"aac",
-"aad",
-"aae",
-"aaf",
-"aag",
-"aah",
-"aai",
-"aak",
-"aal",
-"aam",
-"aan",
-"aao",
-"aap",
-"aaq",
-"aas",
-"aat",
-"aau",
-"aav",
-"aaw",
-"aax",
-"aaz",
-"aba",
-"abb",
-"abc",
-"abd",
-"abe",
-"abf",
-"abg",
-"abh",
-"abi",
-"abj",
-"abl",
-"abm",
-"abn",
-"abo",
-"abp",
-"abq",
-"abr",
-"abs",
-"abt",
-"abu",
-"abv",
-"abw",
-"abx",
-"aby",
-"abz",
-"aca",
-"acb",
-"acd",
-"ace",
-"acf",
-"ach",
-"aci",
-"ack",
-"acl",
-"acm",
-"acn",
-"acp",
-"acq",
-"acr",
-"acs",
-"act",
-"acu",
-"acv",
-"acw",
-"acx",
-"acy",
-"acz",
-"ada",
-"adb",
-"add",
-"ade",
-"adf",
-"adg",
-"adh",
-"adi",
-"adj",
-"adl",
-"adn",
-"ado",
-"adp",
-"adq",
-"adr",
-"ads",
-"adt",
-"adu",
-"adw",
-"adx",
-"ady",
-"adz",
-"aea",
-"aeb",
-"aec",
-"aed",
-"aee",
-"aek",
-"ael",
-"aem",
-"aen",
-"aeq",
-"aer",
-"aes",
-"aeu",
-"aew",
-"aey",
-"aez",
-"afa",
-"afb",
-"afd",
-"afe",
-"afg",
-"afh",
-"afi",
-"afk",
-"afn",
-"afo",
-"afp",
-"afs",
-"aft",
-"afu",
-"afz",
-"aga",
-"agb",
-"agc",
-"agd",
-"age",
-"agf",
-"agg",
-"agh",
-"agi",
-"agj",
-"agk",
-"agl",
-"agm",
-"agn",
-"ago",
-"agp",
-"agq",
-"agr",
-"ags",
-"agt",
-"agu",
-"agv",
-"agw",
-"agx",
-"agy",
-"agz",
-"aha",
-"ahb",
-"ahg",
-"ahh",
-"ahi",
-"ahk",
-"ahl",
-"ahm",
-"ahn",
-"aho",
-"ahp",
-"ahr",
-"ahs",
-"aht",
-"aia",
-"aib",
-"aic",
-"aid",
-"aie",
-"aif",
-"aig",
-"aih",
-"aii",
-"aij",
-"aik",
-"ail",
-"aim",
-"ain",
-"aio",
-"aip",
-"aiq",
-"air",
-"ais",
-"ait",
-"aiw",
-"aix",
-"aiy",
-"aja",
-"ajg",
-"aji",
-"ajn",
-"ajp",
-"ajt",
-"aju",
-"ajw",
-"ajz",
-"akb",
-"akc",
-"akd",
-"ake",
-"akf",
-"akg",
-"akh",
-"aki",
-"akj",
-"akk",
-"akl",
-"akm",
-"ako",
-"akp",
-"akq",
-"akr",
-"aks",
-"akt",
-"aku",
-"akv",
-"akw",
-"akx",
-"aky",
-"akz",
-"ala",
-"alc",
-"ald",
-"ale",
-"alf",
-"alg",
-"alh",
-"ali",
-"alj",
-"alk",
-"all",
-"alm",
-"aln",
-"alo",
-"alp",
-"alq",
-"alr",
-"als",
-"alt",
-"alu",
-"alv",
-"alw",
-"alx",
-"aly",
-"alz",
-"ama",
-"amb",
-"amc",
-"ame",
-"amf",
-"amg",
-"ami",
-"amj",
-"amk",
-"aml",
-"amm",
-"amn",
-"amo",
-"amp",
-"amq",
-"amr",
-"ams",
-"amt",
-"amu",
-"amv",
-"amw",
-"amx",
-"amy",
-"amz",
-"ana",
-"anb",
-"anc",
-"and",
-"ane",
-"anf",
-"ang",
-"anh",
-"ani",
-"anj",
-"ank",
-"anl",
-"anm",
-"ann",
-"ano",
-"anp",
-"anq",
-"anr",
-"ans",
-"ant",
-"anu",
-"anv",
-"anw",
-"anx",
-"any",
-"anz",
-"aoa",
-"aob",
-"aoc",
-"aod",
-"aoe",
-"aof",
-"aog",
-"aoh",
-"aoi",
-"aoj",
-"aok",
-"aol",
-"aom",
-"aon",
-"aor",
-"aos",
-"aot",
-"aou",
-"aox",
-"aoz",
-"apa",
-"apb",
-"apc",
-"apd",
-"ape",
-"apf",
-"apg",
-"aph",
-"api",
-"apj",
-"apk",
-"apl",
-"apm",
-"apn",
-"apo",
-"app",
-"apq",
-"apr",
-"aps",
-"apt",
-"apu",
-"apv",
-"apw",
-"apx",
-"apy",
-"apz",
-"aqa",
-"aqc",
-"aqd",
-"aqg",
-"aql",
-"aqm",
-"aqn",
-"aqp",
-"aqr",
-"aqt",
-"aqz",
-"arb",
-"arc",
-"ard",
-"are",
-"arh",
-"ari",
-"arj",
-"ark",
-"arl",
-"arn",
-"aro",
-"arp",
-"arq",
-"arr",
-"ars",
-"art",
-"aru",
-"arv",
-"arw",
-"arx",
-"ary",
-"arz",
-"asa",
-"asb",
-"asc",
-"asd",
-"ase",
-"asf",
-"asg",
-"ash",
-"asi",
-"asj",
-"ask",
-"asl",
-"asn",
-"aso",
-"asp",
-"asq",
-"asr",
-"ass",
-"ast",
-"asu",
-"asv",
-"asw",
-"asx",
-"asy",
-"asz",
-"ata",
-"atb",
-"atc",
-"atd",
-"ate",
-"atg",
-"ath",
-"ati",
-"atj",
-"atk",
-"atl",
-"atm",
-"atn",
-"ato",
-"atp",
-"atq",
-"atr",
-"ats",
-"att",
-"atu",
-"atv",
-"atw",
-"atx",
-"aty",
-"atz",
-"aua",
-"aub",
-"auc",
-"aud",
-"aue",
-"auf",
-"aug",
-"auh",
-"aui",
-"auj",
-"auk",
-"aul",
-"aum",
-"aun",
-"auo",
-"aup",
-"auq",
-"aur",
-"aus",
-"aut",
-"auu",
-"auw",
-"aux",
-"auy",
-"auz",
-"avb",
-"avd",
-"avi",
-"avk",
-"avl",
-"avm",
-"avn",
-"avo",
-"avs",
-"avt",
-"avu",
-"avv",
-"awa",
-"awb",
-"awc",
-"awd",
-"awe",
-"awg",
-"awh",
-"awi",
-"awk",
-"awm",
-"awn",
-"awo",
-"awr",
-"aws",
-"awt",
-"awu",
-"awv",
-"aww",
-"awx",
-"awy",
-"axb",
-"axe",
-"axg",
-"axk",
-"axl",
-"axm",
-"axx",
-"aya",
-"ayb",
-"ayc",
-"ayd",
-"aye",
-"ayg",
-"ayh",
-"ayi",
-"ayk",
-"ayl",
-"ayn",
-"ayo",
-"ayp",
-"ayq",
-"ayr",
-"ays",
-"ayt",
-"ayu",
-"ayx",
-"ayy",
-"ayz",
-"aza",
-"azb",
-"azc",
-"azd",
-"azg",
-"azj",
-"azm",
-"azn",
-"azo",
-"azt",
-"azz",
-"baa",
-"bab",
-"bac",
-"bad",
-"bae",
-"baf",
-"bag",
-"bah",
-"bai",
-"baj",
-"bal",
-"ban",
-"bao",
-"bap",
-"bar",
-"bas",
-"bat",
-"bau",
-"bav",
-"baw",
-"bax",
-"bay",
-"baz",
-"bba",
-"bbb",
-"bbc",
-"bbd",
-"bbe",
-"bbf",
-"bbg",
-"bbh",
-"bbi",
-"bbj",
-"bbk",
-"bbl",
-"bbm",
-"bbn",
-"bbo",
-"bbp",
-"bbq",
-"bbr",
-"bbs",
-"bbt",
-"bbu",
-"bbv",
-"bbw",
-"bbx",
-"bby",
-"bbz",
-"bca",
-"bcb",
-"bcc",
-"bcd",
-"bce",
-"bcf",
-"bcg",
-"bch",
-"bci",
-"bcj",
-"bck",
-"bcl",
-"bcm",
-"bcn",
-"bco",
-"bcp",
-"bcq",
-"bcr",
-"bcs",
-"bct",
-"bcu",
-"bcv",
-"bcw",
-"bcy",
-"bcz",
-"bda",
-"bdb",
-"bdc",
-"bdd",
-"bde",
-"bdf",
-"bdg",
-"bdh",
-"bdi",
-"bdj",
-"bdk",
-"bdl",
-"bdm",
-"bdn",
-"bdo",
-"bdp",
-"bdq",
-"bdr",
-"bds",
-"bdt",
-"bdu",
-"bdv",
-"bdw",
-"bdx",
-"bdy",
-"bdz",
-"bea",
-"beb",
-"bec",
-"bed",
-"bee",
-"bef",
-"beg",
-"beh",
-"bei",
-"bej",
-"bek",
-"bem",
-"beo",
-"bep",
-"beq",
-"ber",
-"bes",
-"bet",
-"beu",
-"bev",
-"bew",
-"bex",
-"bey",
-"bez",
-"bfa",
-"bfb",
-"bfc",
-"bfd",
-"bfe",
-"bff",
-"bfg",
-"bfh",
-"bfi",
-"bfj",
-"bfk",
-"bfl",
-"bfm",
-"bfn",
-"bfo",
-"bfp",
-"bfq",
-"bfr",
-"bfs",
-"bft",
-"bfu",
-"bfw",
-"bfx",
-"bfy",
-"bfz",
-"bga",
-"bgb",
-"bgc",
-"bgd",
-"bge",
-"bgf",
-"bgg",
-"bgi",
-"bgj",
-"bgk",
-"bgl",
-"bgm",
-"bgn",
-"bgo",
-"bgp",
-"bgq",
-"bgr",
-"bgs",
-"bgt",
-"bgu",
-"bgv",
-"bgw",
-"bgx",
-"bgy",
-"bgz",
-"bha",
-"bhb",
-"bhc",
-"bhd",
-"bhe",
-"bhf",
-"bhg",
-"bhh",
-"bhi",
-"bhj",
-"bhk",
-"bhl",
-"bhm",
-"bhn",
-"bho",
-"bhp",
-"bhq",
-"bhr",
-"bhs",
-"bht",
-"bhu",
-"bhv",
-"bhw",
-"bhx",
-"bhy",
-"bhz",
-"bia",
-"bib",
-"bic",
-"bid",
-"bie",
-"bif",
-"big",
-"bij",
-"bik",
-"bil",
-"bim",
-"bin",
-"bio",
-"bip",
-"biq",
-"bir",
-"bit",
-"biu",
-"biv",
-"biw",
-"bix",
-"biy",
-"biz",
-"bja",
-"bjb",
-"bjc",
-"bjd",
-"bje",
-"bjf",
-"bjg",
-"bjh",
-"bji",
-"bjj",
-"bjk",
-"bjl",
-"bjm",
-"bjn",
-"bjo",
-"bjp",
-"bjq",
-"bjr",
-"bjs",
-"bjt",
-"bju",
-"bjv",
-"bjw",
-"bjx",
-"bjy",
-"bjz",
-"bka",
-"bkb",
-"bkc",
-"bkd",
-"bkf",
-"bkg",
-"bkh",
-"bki",
-"bkj",
-"bkk",
-"bkl",
-"bkm",
-"bkn",
-"bko",
-"bkp",
-"bkq",
-"bkr",
-"bks",
-"bkt",
-"bku",
-"bkv",
-"bkw",
-"bkx",
-"bky",
-"bkz",
-"bla",
-"blb",
-"blc",
-"bld",
-"ble",
-"blf",
-"blg",
-"blh",
-"bli",
-"blj",
-"blk",
-"bll",
-"blm",
-"bln",
-"blo",
-"blp",
-"blq",
-"blr",
-"bls",
-"blt",
-"blv",
-"blw",
-"blx",
-"bly",
-"blz",
-"bma",
-"bmb",
-"bmc",
-"bmd",
-"bme",
-"bmf",
-"bmg",
-"bmh",
-"bmi",
-"bmj",
-"bmk",
-"bml",
-"bmm",
-"bmn",
-"bmo",
-"bmp",
-"bmq",
-"bmr",
-"bms",
-"bmt",
-"bmu",
-"bmv",
-"bmw",
-"bmx",
-"bmy",
-"bmz",
-"bna",
-"bnb",
-"bnc",
-"bnd",
-"bne",
-"bnf",
-"bng",
-"bni",
-"bnj",
-"bnk",
-"bnl",
-"bnm",
-"bnn",
-"bno",
-"bnp",
-"bnq",
-"bnr",
-"bns",
-"bnt",
-"bnu",
-"bnv",
-"bnw",
-"bnx",
-"bny",
-"bnz",
-"boa",
-"bob",
-"boe",
-"bof",
-"bog",
-"boh",
-"boi",
-"boj",
-"bok",
-"bol",
-"bom",
-"bon",
-"boo",
-"bop",
-"boq",
-"bor",
-"bot",
-"bou",
-"bov",
-"bow",
-"box",
-"boy",
-"boz",
-"bpa",
-"bpb",
-"bpd",
-"bpg",
-"bph",
-"bpi",
-"bpj",
-"bpk",
-"bpl",
-"bpm",
-"bpn",
-"bpo",
-"bpp",
-"bpq",
-"bpr",
-"bps",
-"bpt",
-"bpu",
-"bpv",
-"bpw",
-"bpx",
-"bpy",
-"bpz",
-"bqa",
-"bqb",
-"bqc",
-"bqd",
-"bqf",
-"bqg",
-"bqh",
-"bqi",
-"bqj",
-"bqk",
-"bql",
-"bqm",
-"bqn",
-"bqo",
-"bqp",
-"bqq",
-"bqr",
-"bqs",
-"bqt",
-"bqu",
-"bqv",
-"bqw",
-"bqx",
-"bqy",
-"bqz",
-"bra",
-"brb",
-"brc",
-"brd",
-"brf",
-"brg",
-"brh",
-"bri",
-"brj",
-"brk",
-"brl",
-"brm",
-"brn",
-"bro",
-"brp",
-"brq",
-"brr",
-"brs",
-"brt",
-"bru",
-"brv",
-"brw",
-"brx",
-"bry",
-"brz",
-"bsa",
-"bsb",
-"bsc",
-"bse",
-"bsf",
-"bsg",
-"bsh",
-"bsi",
-"bsj",
-"bsk",
-"bsl",
-"bsm",
-"bsn",
-"bso",
-"bsp",
-"bsq",
-"bsr",
-"bss",
-"bst",
-"bsu",
-"bsv",
-"bsw",
-"bsx",
-"bsy",
-"bta",
-"btb",
-"btc",
-"btd",
-"bte",
-"btf",
-"btg",
-"bth",
-"bti",
-"btj",
-"btk",
-"btl",
-"btm",
-"btn",
-"bto",
-"btp",
-"btq",
-"btr",
-"bts",
-"btt",
-"btu",
-"btv",
-"btw",
-"btx",
-"bty",
-"btz",
-"bua",
-"bub",
-"buc",
-"bud",
-"bue",
-"buf",
-"bug",
-"buh",
-"bui",
-"buj",
-"buk",
-"bum",
-"bun",
-"buo",
-"bup",
-"buq",
-"bus",
-"but",
-"buu",
-"buv",
-"buw",
-"bux",
-"buy",
-"buz",
-"bva",
-"bvb",
-"bvc",
-"bvd",
-"bve",
-"bvf",
-"bvg",
-"bvh",
-"bvi",
-"bvj",
-"bvk",
-"bvl",
-"bvm",
-"bvn",
-"bvo",
-"bvp",
-"bvq",
-"bvr",
-"bvt",
-"bvu",
-"bvv",
-"bvw",
-"bvx",
-"bvy",
-"bvz",
-"bwa",
-"bwb",
-"bwc",
-"bwd",
-"bwe",
-"bwf",
-"bwg",
-"bwh",
-"bwi",
-"bwj",
-"bwk",
-"bwl",
-"bwm",
-"bwn",
-"bwo",
-"bwp",
-"bwq",
-"bwr",
-"bws",
-"bwt",
-"bwu",
-"bww",
-"bwx",
-"bwy",
-"bwz",
-"bxa",
-"bxb",
-"bxc",
-"bxd",
-"bxe",
-"bxf",
-"bxg",
-"bxh",
-"bxi",
-"bxj",
-"bxk",
-"bxl",
-"bxm",
-"bxn",
-"bxo",
-"bxp",
-"bxq",
-"bxr",
-"bxs",
-"bxu",
-"bxv",
-"bxw",
-"bxx",
-"bxz",
-"bya",
-"byb",
-"byc",
-"byd",
-"bye",
-"byf",
-"byg",
-"byh",
-"byi",
-"byj",
-"byk",
-"byl",
-"bym",
-"byn",
-"byo",
-"byp",
-"byq",
-"byr",
-"bys",
-"byt",
-"byv",
-"byw",
-"byx",
-"byy",
-"byz",
-"bza",
-"bzb",
-"bzc",
-"bzd",
-"bze",
-"bzf",
-"bzg",
-"bzh",
-"bzi",
-"bzj",
-"bzk",
-"bzl",
-"bzm",
-"bzn",
-"bzo",
-"bzp",
-"bzq",
-"bzr",
-"bzs",
-"bzt",
-"bzu",
-"bzv",
-"bzw",
-"bzx",
-"bzy",
-"bzz",
-"caa",
-"cab",
-"cac",
-"cad",
-"cae",
-"caf",
-"cag",
-"cah",
-"cai",
-"caj",
-"cak",
-"cal",
-"cam",
-"can",
-"cao",
-"cap",
-"caq",
-"car",
-"cas",
-"cau",
-"cav",
-"caw",
-"cax",
-"cay",
-"caz",
-"cba",
-"cbb",
-"cbc",
-"cbd",
-"cbe",
-"cbg",
-"cbh",
-"cbi",
-"cbj",
-"cbk",
-"cbl",
-"cbn",
-"cbo",
-"cbq",
-"cbr",
-"cbs",
-"cbt",
-"cbu",
-"cbv",
-"cbw",
-"cby",
-"cca",
-"ccc",
-"ccd",
-"cce",
-"ccg",
-"cch",
-"ccj",
-"ccl",
-"ccm",
-"ccn",
-"cco",
-"ccp",
-"ccq",
-"ccr",
-"ccs",
-"cda",
-"cdc",
-"cdd",
-"cde",
-"cdf",
-"cdg",
-"cdh",
-"cdi",
-"cdj",
-"cdm",
-"cdn",
-"cdo",
-"cdr",
-"cds",
-"cdy",
-"cdz",
-"cea",
-"ceb",
-"ceg",
-"cek",
-"cel",
-"cen",
-"cet",
-"cfa",
-"cfd",
-"cfg",
-"cfm",
-"cga",
-"cgc",
-"cgg",
-"cgk",
-"chb",
-"chc",
-"chd",
-"chf",
-"chg",
-"chh",
-"chj",
-"chk",
-"chl",
-"chm",
-"chn",
-"cho",
-"chp",
-"chq",
-"chr",
-"cht",
-"chw",
-"chx",
-"chy",
-"chz",
-"cia",
-"cib",
-"cic",
-"cid",
-"cie",
-"cih",
-"cik",
-"cim",
-"cin",
-"cip",
-"cir",
-"ciw",
-"ciy",
-"cja",
-"cje",
-"cjh",
-"cji",
-"cjk",
-"cjm",
-"cjn",
-"cjo",
-"cjp",
-"cjr",
-"cjs",
-"cjv",
-"cjy",
-"cka",
-"ckb",
-"ckh",
-"ckl",
-"ckn",
-"cko",
-"ckq",
-"ckr",
-"cks",
-"ckt",
-"cku",
-"ckv",
-"ckx",
-"cky",
-"ckz",
-"cla",
-"clc",
-"cld",
-"cle",
-"clh",
-"cli",
-"clj",
-"clk",
-"cll",
-"clm",
-"clo",
-"clt",
-"clu",
-"clw",
-"cly",
-"cma",
-"cmc",
-"cme",
-"cmg",
-"cmi",
-"cmk",
-"cml",
-"cmm",
-"cmn",
-"cmo",
-"cmr",
-"cms",
-"cmt",
-"cna",
-"cnb",
-"cnc",
-"cng",
-"cnh",
-"cni",
-"cnk",
-"cnl",
-"cno",
-"cns",
-"cnt",
-"cnu",
-"cnw",
-"cnx",
-"coa",
-"cob",
-"coc",
-"cod",
-"coe",
-"cof",
-"cog",
-"coh",
-"coj",
-"cok",
-"col",
-"com",
-"con",
-"coo",
-"cop",
-"coq",
-"cot",
-"cou",
-"cov",
-"cow",
-"cox",
-"coy",
-"coz",
-"cpa",
-"cpb",
-"cpc",
-"cpe",
-"cpf",
-"cpg",
-"cpi",
-"cpn",
-"cpo",
-"cpp",
-"cps",
-"cpu",
-"cpx",
-"cpy",
-"cqd",
-"cqu",
-"cra",
-"crb",
-"crc",
-"crd",
-"crf",
-"crg",
-"crh",
-"cri",
-"crj",
-"crk",
-"crl",
-"crm",
-"crn",
-"cro",
-"crp",
-"crq",
-"crr",
-"crs",
-"crt",
-"crv",
-"crw",
-"crx",
-"cry",
-"crz",
-"csa",
-"csb",
-"csc",
-"csd",
-"cse",
-"csf",
-"csg",
-"csh",
-"csi",
-"csj",
-"csk",
-"csl",
-"csm",
-"csn",
-"cso",
-"csq",
-"csr",
-"css",
-"cst",
-"csu",
-"csv",
-"csw",
-"csy",
-"csz",
-"cta",
-"ctc",
-"ctd",
-"cte",
-"ctg",
-"cth",
-"ctl",
-"ctm",
-"ctn",
-"cto",
-"ctp",
-"cts",
-"ctt",
-"ctu",
-"ctz",
-"cua",
-"cub",
-"cuc",
-"cug",
-"cuh",
-"cui",
-"cuj",
-"cuk",
-"cul",
-"cum",
-"cuo",
-"cup",
-"cuq",
-"cur",
-"cus",
-"cut",
-"cuu",
-"cuv",
-"cuw",
-"cux",
-"cvg",
-"cvn",
-"cwa",
-"cwb",
-"cwd",
-"cwe",
-"cwg",
-"cwt",
-"cya",
-"cyb",
-"cyo",
-"czh",
-"czk",
-"czn",
-"czo",
-"czt",
-"daa",
-"dac",
-"dad",
-"dae",
-"daf",
-"dag",
-"dah",
-"dai",
-"daj",
-"dak",
-"dal",
-"dam",
-"dao",
-"dap",
-"daq",
-"dar",
-"das",
-"dau",
-"dav",
-"daw",
-"dax",
-"day",
-"daz",
-"dba",
-"dbb",
-"dbd",
-"dbe",
-"dbf",
-"dbg",
-"dbi",
-"dbj",
-"dbl",
-"dbm",
-"dbn",
-"dbo",
-"dbp",
-"dbq",
-"dbr",
-"dbt",
-"dbu",
-"dbv",
-"dbw",
-"dby",
-"dcc",
-"dcr",
-"dda",
-"ddd",
-"dde",
-"ddg",
-"ddi",
-"ddj",
-"ddn",
-"ddo",
-"ddr",
-"dds",
-"ddw",
-"dec",
-"ded",
-"dee",
-"def",
-"deg",
-"deh",
-"dei",
-"dek",
-"del",
-"dem",
-"den",
-"dep",
-"deq",
-"der",
-"des",
-"dev",
-"dez",
-"dga",
-"dgb",
-"dgc",
-"dgd",
-"dge",
-"dgg",
-"dgh",
-"dgi",
-"dgk",
-"dgl",
-"dgn",
-"dgo",
-"dgr",
-"dgs",
-"dgt",
-"dgu",
-"dgw",
-"dgx",
-"dgz",
-"dha",
-"dhd",
-"dhg",
-"dhi",
-"dhl",
-"dhm",
-"dhn",
-"dho",
-"dhr",
-"dhs",
-"dhu",
-"dhv",
-"dhw",
-"dhx",
-"dia",
-"dib",
-"dic",
-"did",
-"dif",
-"dig",
-"dih",
-"dii",
-"dij",
-"dik",
-"dil",
-"dim",
-"din",
-"dio",
-"dip",
-"diq",
-"dir",
-"dis",
-"dit",
-"diu",
-"diw",
-"dix",
-"diy",
-"diz",
-"dja",
-"djb",
-"djc",
-"djd",
-"dje",
-"djf",
-"dji",
-"djj",
-"djk",
-"djl",
-"djm",
-"djn",
-"djo",
-"djr",
-"dju",
-"djw",
-"dka",
-"dkk",
-"dkl",
-"dkr",
-"dks",
-"dkx",
-"dlg",
-"dlk",
-"dlm",
-"dln",
-"dma",
-"dmb",
-"dmc",
-"dmd",
-"dme",
-"dmg",
-"dmk",
-"dml",
-"dmm",
-"dmn",
-"dmo",
-"dmr",
-"dms",
-"dmu",
-"dmv",
-"dmw",
-"dmx",
-"dmy",
-"dna",
-"dnd",
-"dne",
-"dng",
-"dni",
-"dnj",
-"dnk",
-"dnn",
-"dnr",
-"dnt",
-"dnu",
-"dnv",
-"dnw",
-"dny",
-"doa",
-"dob",
-"doc",
-"doe",
-"dof",
-"doh",
-"doi",
-"dok",
-"dol",
-"don",
-"doo",
-"dop",
-"doq",
-"dor",
-"dos",
-"dot",
-"dov",
-"dow",
-"dox",
-"doy",
-"doz",
-"dpp",
-"dra",
-"drb",
-"drc",
-"drd",
-"dre",
-"drg",
-"drh",
-"dri",
-"drl",
-"drn",
-"dro",
-"drq",
-"drr",
-"drs",
-"drt",
-"dru",
-"drw",
-"dry",
-"dsb",
-"dse",
-"dsh",
-"dsi",
-"dsl",
-"dsn",
-"dso",
-"dsq",
-"dta",
-"dtb",
-"dtd",
-"dth",
-"dti",
-"dtk",
-"dtm",
-"dtn",
-"dto",
-"dtp",
-"dtr",
-"dts",
-"dtt",
-"dtu",
-"dty",
-"dua",
-"dub",
-"duc",
-"dud",
-"due",
-"duf",
-"dug",
-"duh",
-"dui",
-"duj",
-"duk",
-"dul",
-"dum",
-"dun",
-"duo",
-"dup",
-"duq",
-"dur",
-"dus",
-"duu",
-"duv",
-"duw",
-"dux",
-"duy",
-"duz",
-"dva",
-"dwa",
-"dwl",
-"dwr",
-"dws",
-"dwu",
-"dww",
-"dwy",
-"dya",
-"dyb",
-"dyd",
-"dyg",
-"dyi",
-"dym",
-"dyn",
-"dyo",
-"dyu",
-"dyy",
-"dza",
-"dzd",
-"dze",
-"dzg",
-"dzl",
-"dzn",
-"eaa",
-"ebg",
-"ebk",
-"ebo",
-"ebr",
-"ebu",
-"ecr",
-"ecs",
-"ecy",
-"eee",
-"efa",
-"efe",
-"efi",
-"ega",
-"egl",
-"ego",
-"egx",
-"egy",
-"ehu",
-"eip",
-"eit",
-"eiv",
-"eja",
-"eka",
-"ekc",
-"eke",
-"ekg",
-"eki",
-"ekk",
-"ekl",
-"ekm",
-"eko",
-"ekp",
-"ekr",
-"eky",
-"ele",
-"elh",
-"eli",
-"elk",
-"elm",
-"elo",
-"elp",
-"elu",
-"elx",
-"ema",
-"emb",
-"eme",
-"emg",
-"emi",
-"emk",
-"emm",
-"emn",
-"emo",
-"emp",
-"ems",
-"emu",
-"emw",
-"emx",
-"emy",
-"ena",
-"enb",
-"enc",
-"end",
-"enf",
-"enh",
-"enl",
-"enm",
-"enn",
-"eno",
-"enq",
-"enr",
-"enu",
-"env",
-"enw",
-"enx",
-"eot",
-"epi",
-"era",
-"erg",
-"erh",
-"eri",
-"erk",
-"ero",
-"err",
-"ers",
-"ert",
-"erw",
-"ese",
-"esg",
-"esh",
-"esi",
-"esk",
-"esl",
-"esm",
-"esn",
-"eso",
-"esq",
-"ess",
-"esu",
-"esx",
-"esy",
-"etb",
-"etc",
-"eth",
-"etn",
-"eto",
-"etr",
-"ets",
-"ett",
-"etu",
-"etx",
-"etz",
-"euq",
-"eve",
-"evh",
-"evn",
-"ewo",
-"ext",
-"eya",
-"eyo",
-"eza",
-"eze",
-"faa",
-"fab",
-"fad",
-"faf",
-"fag",
-"fah",
-"fai",
-"faj",
-"fak",
-"fal",
-"fam",
-"fan",
-"fap",
-"far",
-"fat",
-"fau",
-"fax",
-"fay",
-"faz",
-"fbl",
-"fcs",
-"fer",
-"ffi",
-"ffm",
-"fgr",
-"fia",
-"fie",
-"fil",
-"fip",
-"fir",
-"fit",
-"fiu",
-"fiw",
-"fkk",
-"fkv",
-"fla",
-"flh",
-"fli",
-"fll",
-"fln",
-"flr",
-"fly",
-"fmp",
-"fmu",
-"fnb",
-"fng",
-"fni",
-"fod",
-"foi",
-"fom",
-"fon",
-"for",
-"fos",
-"fox",
-"fpe",
-"fqs",
-"frc",
-"frd",
-"frk",
-"frm",
-"fro",
-"frp",
-"frq",
-"frr",
-"frs",
-"frt",
-"fse",
-"fsl",
-"fss",
-"fub",
-"fuc",
-"fud",
-"fue",
-"fuf",
-"fuh",
-"fui",
-"fuj",
-"fum",
-"fun",
-"fuq",
-"fur",
-"fut",
-"fuu",
-"fuv",
-"fuy",
-"fvr",
-"fwa",
-"fwe",
-"gaa",
-"gab",
-"gac",
-"gad",
-"gae",
-"gaf",
-"gag",
-"gah",
-"gai",
-"gaj",
-"gak",
-"gal",
-"gam",
-"gan",
-"gao",
-"gap",
-"gaq",
-"gar",
-"gas",
-"gat",
-"gau",
-"gav",
-"gaw",
-"gax",
-"gay",
-"gaz",
-"gba",
-"gbb",
-"gbc",
-"gbd",
-"gbe",
-"gbf",
-"gbg",
-"gbh",
-"gbi",
-"gbj",
-"gbk",
-"gbl",
-"gbm",
-"gbn",
-"gbo",
-"gbp",
-"gbq",
-"gbr",
-"gbs",
-"gbu",
-"gbv",
-"gbw",
-"gbx",
-"gby",
-"gbz",
-"gcc",
-"gcd",
-"gce",
-"gcf",
-"gcl",
-"gcn",
-"gcr",
-"gct",
-"gda",
-"gdb",
-"gdc",
-"gdd",
-"gde",
-"gdf",
-"gdg",
-"gdh",
-"gdi",
-"gdj",
-"gdk",
-"gdl",
-"gdm",
-"gdn",
-"gdo",
-"gdq",
-"gdr",
-"gds",
-"gdt",
-"gdu",
-"gdx",
-"gea",
-"geb",
-"gec",
-"ged",
-"geg",
-"geh",
-"gei",
-"gej",
-"gek",
-"gel",
-"gem",
-"geq",
-"ges",
-"gev",
-"gew",
-"gex",
-"gey",
-"gez",
-"gfk",
-"gft",
-"gfx",
-"gga",
-"ggb",
-"ggd",
-"gge",
-"ggg",
-"ggk",
-"ggl",
-"ggn",
-"ggo",
-"ggr",
-"ggt",
-"ggu",
-"ggw",
-"gha",
-"ghc",
-"ghe",
-"ghh",
-"ghk",
-"ghl",
-"ghn",
-"gho",
-"ghr",
-"ghs",
-"ght",
-"gia",
-"gib",
-"gic",
-"gid",
-"gie",
-"gig",
-"gih",
-"gil",
-"gim",
-"gin",
-"gio",
-"gip",
-"giq",
-"gir",
-"gis",
-"git",
-"giu",
-"giw",
-"gix",
-"giy",
-"giz",
-"gji",
-"gjk",
-"gjm",
-"gjn",
-"gjr",
-"gju",
-"gka",
-"gke",
-"gkn",
-"gko",
-"gkp",
-"gku",
-"glc",
-"gld",
-"glh",
-"gli",
-"glj",
-"glk",
-"gll",
-"glo",
-"glr",
-"glu",
-"glw",
-"gly",
-"gma",
-"gmb",
-"gmd",
-"gme",
-"gmg",
-"gmh",
-"gml",
-"gmm",
-"gmn",
-"gmq",
-"gmu",
-"gmv",
-"gmw",
-"gmx",
-"gmy",
-"gmz",
-"gna",
-"gnb",
-"gnc",
-"gnd",
-"gne",
-"gng",
-"gnh",
-"gni",
-"gnk",
-"gnl",
-"gnm",
-"gnn",
-"gno",
-"gnq",
-"gnr",
-"gnt",
-"gnu",
-"gnw",
-"gnz",
-"goa",
-"gob",
-"goc",
-"god",
-"goe",
-"gof",
-"gog",
-"goh",
-"goi",
-"goj",
-"gok",
-"gol",
-"gom",
-"gon",
-"goo",
-"gop",
-"goq",
-"gor",
-"gos",
-"got",
-"gou",
-"gow",
-"gox",
-"goy",
-"goz",
-"gpa",
-"gpe",
-"gpn",
-"gqa",
-"gqi",
-"gqn",
-"gqr",
-"gqu",
-"gra",
-"grb",
-"grc",
-"grd",
-"grg",
-"grh",
-"gri",
-"grj",
-"grk",
-"grm",
-"gro",
-"grq",
-"grr",
-"grs",
-"grt",
-"gru",
-"grv",
-"grw",
-"grx",
-"gry",
-"grz",
-"gse",
-"gsg",
-"gsl",
-"gsm",
-"gsn",
-"gso",
-"gsp",
-"gss",
-"gsw",
-"gta",
-"gti",
-"gtu",
-"gua",
-"gub",
-"guc",
-"gud",
-"gue",
-"guf",
-"gug",
-"guh",
-"gui",
-"guk",
-"gul",
-"gum",
-"gun",
-"guo",
-"gup",
-"guq",
-"gur",
-"gus",
-"gut",
-"guu",
-"guv",
-"guw",
-"gux",
-"guz",
-"gva",
-"gvc",
-"gve",
-"gvf",
-"gvj",
-"gvl",
-"gvm",
-"gvn",
-"gvo",
-"gvp",
-"gvr",
-"gvs",
-"gvy",
-"gwa",
-"gwb",
-"gwc",
-"gwd",
-"gwe",
-"gwf",
-"gwg",
-"gwi",
-"gwj",
-"gwm",
-"gwn",
-"gwr",
-"gwt",
-"gwu",
-"gww",
-"gwx",
-"gxx",
-"gya",
-"gyb",
-"gyd",
-"gye",
-"gyf",
-"gyg",
-"gyi",
-"gyl",
-"gym",
-"gyn",
-"gyr",
-"gyy",
-"gza",
-"gzi",
-"gzn",
-"haa",
-"hab",
-"hac",
-"had",
-"hae",
-"haf",
-"hag",
-"hah",
-"hai",
-"haj",
-"hak",
-"hal",
-"ham",
-"han",
-"hao",
-"hap",
-"haq",
-"har",
-"has",
-"hav",
-"haw",
-"hax",
-"hay",
-"haz",
-"hba",
-"hbb",
-"hbn",
-"hbo",
-"hbu",
-"hca",
-"hch",
-"hdn",
-"hds",
-"hdy",
-"hea",
-"hed",
-"heg",
-"heh",
-"hei",
-"hem",
-"hgm",
-"hgw",
-"hhi",
-"hhr",
-"hhy",
-"hia",
-"hib",
-"hid",
-"hif",
-"hig",
-"hih",
-"hii",
-"hij",
-"hik",
-"hil",
-"him",
-"hio",
-"hir",
-"hit",
-"hiw",
-"hix",
-"hji",
-"hka",
-"hke",
-"hkk",
-"hks",
-"hla",
-"hlb",
-"hld",
-"hle",
-"hlt",
-"hlu",
-"hma",
-"hmb",
-"hmc",
-"hmd",
-"hme",
-"hmf",
-"hmg",
-"hmh",
-"hmi",
-"hmj",
-"hmk",
-"hml",
-"hmm",
-"hmn",
-"hmp",
-"hmq",
-"hmr",
-"hms",
-"hmt",
-"hmu",
-"hmv",
-"hmw",
-"hmx",
-"hmy",
-"hmz",
-"hna",
-"hnd",
-"hne",
-"hnh",
-"hni",
-"hnj",
-"hnn",
-"hno",
-"hns",
-"hnu",
-"hoa",
-"hob",
-"hoc",
-"hod",
-"hoe",
-"hoh",
-"hoi",
-"hoj",
-"hok",
-"hol",
-"hom",
-"hoo",
-"hop",
-"hor",
-"hos",
-"hot",
-"hov",
-"how",
-"hoy",
-"hoz",
-"hpo",
-"hps",
-"hra",
-"hrc",
-"hre",
-"hrk",
-"hrm",
-"hro",
-"hrp",
-"hrr",
-"hrt",
-"hru",
-"hrw",
-"hrx",
-"hrz",
-"hsb",
-"hsh",
-"hsl",
-"hsn",
-"hss",
-"hti",
-"hto",
-"hts",
-"htu",
-"htx",
-"hub",
-"huc",
-"hud",
-"hue",
-"huf",
-"hug",
-"huh",
-"hui",
-"huj",
-"huk",
-"hul",
-"hum",
-"huo",
-"hup",
-"huq",
-"hur",
-"hus",
-"hut",
-"huu",
-"huv",
-"huw",
-"hux",
-"huy",
-"huz",
-"hvc",
-"hve",
-"hvk",
-"hvn",
-"hvv",
-"hwa",
-"hwc",
-"hwo",
-"hya",
-"hyx",
-"iai",
-"ian",
-"iap",
-"iar",
-"iba",
-"ibb",
-"ibd",
-"ibe",
-"ibg",
-"ibh",
-"ibi",
-"ibl",
-"ibm",
-"ibn",
-"ibr",
-"ibu",
-"iby",
-"ica",
-"ich",
-"icl",
-"icr",
-"ida",
-"idb",
-"idc",
-"idd",
-"ide",
-"idi",
-"idr",
-"ids",
-"idt",
-"idu",
-"ifa",
-"ifb",
-"ife",
-"iff",
-"ifk",
-"ifm",
-"ifu",
-"ify",
-"igb",
-"ige",
-"igg",
-"igl",
-"igm",
-"ign",
-"igo",
-"igs",
-"igw",
-"ihb",
-"ihi",
-"ihp",
-"ihw",
-"iin",
-"iir",
-"ijc",
-"ije",
-"ijj",
-"ijn",
-"ijo",
-"ijs",
-"ike",
-"iki",
-"ikk",
-"ikl",
-"iko",
-"ikp",
-"ikr",
-"iks",
-"ikt",
-"ikv",
-"ikw",
-"ikx",
-"ikz",
-"ila",
-"ilb",
-"ilg",
-"ili",
-"ilk",
-"ill",
-"ilm",
-"ilo",
-"ilp",
-"ils",
-"ilu",
-"ilv",
-"ilw",
-"ima",
-"ime",
-"imi",
-"iml",
-"imn",
-"imo",
-"imr",
-"ims",
-"imy",
-"inb",
-"inc",
-"ine",
-"ing",
-"inh",
-"inj",
-"inl",
-"inm",
-"inn",
-"ino",
-"inp",
-"ins",
-"int",
-"inz",
-"ior",
-"iou",
-"iow",
-"ipi",
-"ipo",
-"iqu",
-"iqw",
-"ira",
-"ire",
-"irh",
-"iri",
-"irk",
-"irn",
-"iro",
-"irr",
-"iru",
-"irx",
-"iry",
-"isa",
-"isc",
-"isd",
-"ise",
-"isg",
-"ish",
-"isi",
-"isk",
-"ism",
-"isn",
-"iso",
-"isr",
-"ist",
-"isu",
-"itb",
-"itc",
-"itd",
-"ite",
-"iti",
-"itk",
-"itl",
-"itm",
-"ito",
-"itr",
-"its",
-"itt",
-"itv",
-"itw",
-"itx",
-"ity",
-"itz",
-"ium",
-"ivb",
-"ivv",
-"iwk",
-"iwm",
-"iwo",
-"iws",
-"ixc",
-"ixl",
-"iya",
-"iyo",
-"iyx",
-"izh",
-"izi",
-"izr",
-"izz",
-"jaa",
-"jab",
-"jac",
-"jad",
-"jae",
-"jaf",
-"jah",
-"jaj",
-"jak",
-"jal",
-"jam",
-"jan",
-"jao",
-"jaq",
-"jar",
-"jas",
-"jat",
-"jau",
-"jax",
-"jay",
-"jaz",
-"jbe",
-"jbi",
-"jbj",
-"jbk",
-"jbn",
-"jbo",
-"jbr",
-"jbt",
-"jbu",
-"jbw",
-"jcs",
-"jct",
-"jda",
-"jdg",
-"jdt",
-"jeb",
-"jee",
-"jeg",
-"jeh",
-"jei",
-"jek",
-"jel",
-"jen",
-"jer",
-"jet",
-"jeu",
-"jgb",
-"jge",
-"jgk",
-"jgo",
-"jhi",
-"jhs",
-"jia",
-"jib",
-"jic",
-"jid",
-"jie",
-"jig",
-"jih",
-"jii",
-"jil",
-"jim",
-"jio",
-"jiq",
-"jit",
-"jiu",
-"jiv",
-"jiy",
-"jje",
-"jjr",
-"jka",
-"jkm",
-"jko",
-"jkp",
-"jkr",
-"jku",
-"jle",
-"jls",
-"jma",
-"jmb",
-"jmc",
-"jmd",
-"jmi",
-"jml",
-"jmn",
-"jmr",
-"jms",
-"jmw",
-"jmx",
-"jna",
-"jnd",
-"jng",
-"jni",
-"jnj",
-"jnl",
-"jns",
-"job",
-"jod",
-"jog",
-"jor",
-"jos",
-"jow",
-"jpa",
-"jpr",
-"jpx",
-"jqr",
-"jra",
-"jrb",
-"jrr",
-"jrt",
-"jru",
-"jsl",
-"jua",
-"jub",
-"juc",
-"jud",
-"juh",
-"jui",
-"juk",
-"jul",
-"jum",
-"jun",
-"juo",
-"jup",
-"jur",
-"jus",
-"jut",
-"juu",
-"juw",
-"juy",
-"jvd",
-"jvn",
-"jwi",
-"jya",
-"jye",
-"jyy",
-"kaa",
-"kab",
-"kac",
-"kad",
-"kae",
-"kaf",
-"kag",
-"kah",
-"kai",
-"kaj",
-"kak",
-"kam",
-"kao",
-"kap",
-"kaq",
-"kar",
-"kav",
-"kaw",
-"kax",
-"kay",
-"kba",
-"kbb",
-"kbc",
-"kbd",
-"kbe",
-"kbf",
-"kbg",
-"kbh",
-"kbi",
-"kbj",
-"kbk",
-"kbl",
-"kbm",
-"kbn",
-"kbo",
-"kbp",
-"kbq",
-"kbr",
-"kbs",
-"kbt",
-"kbu",
-"kbv",
-"kbw",
-"kbx",
-"kby",
-"kbz",
-"kca",
-"kcb",
-"kcc",
-"kcd",
-"kce",
-"kcf",
-"kcg",
-"kch",
-"kci",
-"kcj",
-"kck",
-"kcl",
-"kcm",
-"kcn",
-"kco",
-"kcp",
-"kcq",
-"kcr",
-"kcs",
-"kct",
-"kcu",
-"kcv",
-"kcw",
-"kcx",
-"kcy",
-"kcz",
-"kda",
-"kdc",
-"kdd",
-"kde",
-"kdf",
-"kdg",
-"kdh",
-"kdi",
-"kdj",
-"kdk",
-"kdl",
-"kdm",
-"kdn",
-"kdo",
-"kdp",
-"kdq",
-"kdr",
-"kdt",
-"kdu",
-"kdv",
-"kdw",
-"kdx",
-"kdy",
-"kdz",
-"kea",
-"keb",
-"kec",
-"ked",
-"kee",
-"kef",
-"keg",
-"keh",
-"kei",
-"kej",
-"kek",
-"kel",
-"kem",
-"ken",
-"keo",
-"kep",
-"keq",
-"ker",
-"kes",
-"ket",
-"keu",
-"kev",
-"kew",
-"kex",
-"key",
-"kez",
-"kfa",
-"kfb",
-"kfc",
-"kfd",
-"kfe",
-"kff",
-"kfg",
-"kfh",
-"kfi",
-"kfj",
-"kfk",
-"kfl",
-"kfm",
-"kfn",
-"kfo",
-"kfp",
-"kfq",
-"kfr",
-"kfs",
-"kft",
-"kfu",
-"kfv",
-"kfw",
-"kfx",
-"kfy",
-"kfz",
-"kga",
-"kgb",
-"kgc",
-"kgd",
-"kge",
-"kgf",
-"kgg",
-"kgh",
-"kgi",
-"kgj",
-"kgk",
-"kgl",
-"kgm",
-"kgn",
-"kgo",
-"kgp",
-"kgq",
-"kgr",
-"kgs",
-"kgt",
-"kgu",
-"kgv",
-"kgw",
-"kgx",
-"kgy",
-"kha",
-"khb",
-"khc",
-"khd",
-"khe",
-"khf",
-"khg",
-"khh",
-"khi",
-"khj",
-"khk",
-"khl",
-"khn",
-"kho",
-"khp",
-"khq",
-"khr",
-"khs",
-"kht",
-"khu",
-"khv",
-"khw",
-"khx",
-"khy",
-"khz",
-"kia",
-"kib",
-"kic",
-"kid",
-"kie",
-"kif",
-"kig",
-"kih",
-"kii",
-"kij",
-"kil",
-"kim",
-"kio",
-"kip",
-"kiq",
-"kis",
-"kit",
-"kiu",
-"kiv",
-"kiw",
-"kix",
-"kiy",
-"kiz",
-"kja",
-"kjb",
-"kjc",
-"kjd",
-"kje",
-"kjf",
-"kjg",
-"kjh",
-"kji",
-"kjj",
-"kjk",
-"kjl",
-"kjm",
-"kjn",
-"kjo",
-"kjp",
-"kjq",
-"kjr",
-"kjs",
-"kjt",
-"kju",
-"kjv",
-"kjx",
-"kjy",
-"kjz",
-"kka",
-"kkb",
-"kkc",
-"kkd",
-"kke",
-"kkf",
-"kkg",
-"kkh",
-"kki",
-"kkj",
-"kkk",
-"kkl",
-"kkm",
-"kkn",
-"kko",
-"kkp",
-"kkq",
-"kkr",
-"kks",
-"kkt",
-"kku",
-"kkv",
-"kkw",
-"kkx",
-"kky",
-"kkz",
-"kla",
-"klb",
-"klc",
-"kld",
-"kle",
-"klf",
-"klg",
-"klh",
-"kli",
-"klj",
-"klk",
-"kll",
-"klm",
-"kln",
-"klo",
-"klp",
-"klq",
-"klr",
-"kls",
-"klt",
-"klu",
-"klv",
-"klw",
-"klx",
-"kly",
-"klz",
-"kma",
-"kmb",
-"kmc",
-"kmd",
-"kme",
-"kmf",
-"kmg",
-"kmh",
-"kmi",
-"kmj",
-"kmk",
-"kml",
-"kmm",
-"kmn",
-"kmo",
-"kmp",
-"kmq",
-"kmr",
-"kms",
-"kmt",
-"kmu",
-"kmv",
-"kmw",
-"kmx",
-"kmy",
-"kmz",
-"kna",
-"knb",
-"knc",
-"knd",
-"kne",
-"knf",
-"kng",
-"kni",
-"knj",
-"knk",
-"knl",
-"knm",
-"knn",
-"kno",
-"knp",
-"knq",
-"knr",
-"kns",
-"knt",
-"knu",
-"knv",
-"knw",
-"knx",
-"kny",
-"knz",
-"koa",
-"koc",
-"kod",
-"koe",
-"kof",
-"kog",
-"koh",
-"koi",
-"koj",
-"kok",
-"kol",
-"koo",
-"kop",
-"koq",
-"kos",
-"kot",
-"kou",
-"kov",
-"kow",
-"kox",
-"koy",
-"koz",
-"kpa",
-"kpb",
-"kpc",
-"kpd",
-"kpe",
-"kpf",
-"kpg",
-"kph",
-"kpi",
-"kpj",
-"kpk",
-"kpl",
-"kpm",
-"kpn",
-"kpo",
-"kpp",
-"kpq",
-"kpr",
-"kps",
-"kpt",
-"kpu",
-"kpv",
-"kpw",
-"kpx",
-"kpy",
-"kpz",
-"kqa",
-"kqb",
-"kqc",
-"kqd",
-"kqe",
-"kqf",
-"kqg",
-"kqh",
-"kqi",
-"kqj",
-"kqk",
-"kql",
-"kqm",
-"kqn",
-"kqo",
-"kqp",
-"kqq",
-"kqr",
-"kqs",
-"kqt",
-"kqu",
-"kqv",
-"kqw",
-"kqx",
-"kqy",
-"kqz",
-"kra",
-"krb",
-"krc",
-"krd",
-"kre",
-"krf",
-"krh",
-"kri",
-"krj",
-"krk",
-"krl",
-"krm",
-"krn",
-"kro",
-"krp",
-"krr",
-"krs",
-"krt",
-"kru",
-"krv",
-"krw",
-"krx",
-"kry",
-"krz",
-"ksa",
-"ksb",
-"ksc",
-"ksd",
-"kse",
-"ksf",
-"ksg",
-"ksh",
-"ksi",
-"ksj",
-"ksk",
-"ksl",
-"ksm",
-"ksn",
-"kso",
-"ksp",
-"ksq",
-"ksr",
-"kss",
-"kst",
-"ksu",
-"ksv",
-"ksw",
-"ksx",
-"ksy",
-"ksz",
-"kta",
-"ktb",
-"ktc",
-"ktd",
-"kte",
-"ktf",
-"ktg",
-"kth",
-"kti",
-"ktj",
-"ktk",
-"ktl",
-"ktm",
-"ktn",
-"kto",
-"ktp",
-"ktq",
-"ktr",
-"kts",
-"ktt",
-"ktu",
-"ktv",
-"ktw",
-"ktx",
-"kty",
-"ktz",
-"kub",
-"kuc",
-"kud",
-"kue",
-"kuf",
-"kug",
-"kuh",
-"kui",
-"kuj",
-"kuk",
-"kul",
-"kum",
-"kun",
-"kuo",
-"kup",
-"kuq",
-"kus",
-"kut",
-"kuu",
-"kuv",
-"kuw",
-"kux",
-"kuy",
-"kuz",
-"kva",
-"kvb",
-"kvc",
-"kvd",
-"kve",
-"kvf",
-"kvg",
-"kvh",
-"kvi",
-"kvj",
-"kvk",
-"kvl",
-"kvm",
-"kvn",
-"kvo",
-"kvp",
-"kvq",
-"kvr",
-"kvs",
-"kvt",
-"kvu",
-"kvv",
-"kvw",
-"kvx",
-"kvy",
-"kvz",
-"kwa",
-"kwb",
-"kwc",
-"kwd",
-"kwe",
-"kwf",
-"kwg",
-"kwh",
-"kwi",
-"kwj",
-"kwk",
-"kwl",
-"kwm",
-"kwn",
-"kwo",
-"kwp",
-"kwq",
-"kwr",
-"kws",
-"kwt",
-"kwu",
-"kwv",
-"kww",
-"kwx",
-"kwy",
-"kwz",
-"kxa",
-"kxb",
-"kxc",
-"kxd",
-"kxe",
-"kxf",
-"kxh",
-"kxi",
-"kxj",
-"kxk",
-"kxl",
-"kxm",
-"kxn",
-"kxo",
-"kxp",
-"kxq",
-"kxr",
-"kxs",
-"kxt",
-"kxu",
-"kxv",
-"kxw",
-"kxx",
-"kxy",
-"kxz",
-"kya",
-"kyb",
-"kyc",
-"kyd",
-"kye",
-"kyf",
-"kyg",
-"kyh",
-"kyi",
-"kyj",
-"kyk",
-"kyl",
-"kym",
-"kyn",
-"kyo",
-"kyp",
-"kyq",
-"kyr",
-"kys",
-"kyt",
-"kyu",
-"kyv",
-"kyw",
-"kyx",
-"kyy",
-"kyz",
-"kza",
-"kzb",
-"kzc",
-"kzd",
-"kze",
-"kzf",
-"kzg",
-"kzh",
-"kzi",
-"kzj",
-"kzk",
-"kzl",
-"kzm",
-"kzn",
-"kzo",
-"kzp",
-"kzq",
-"kzr",
-"kzs",
-"kzt",
-"kzu",
-"kzv",
-"kzw",
-"kzx",
-"kzy",
-"kzz",
-"laa",
-"lab",
-"lac",
-"lad",
-"lae",
-"laf",
-"lag",
-"lah",
-"lai",
-"laj",
-"lak",
-"lal",
-"lam",
-"lan",
-"lap",
-"laq",
-"lar",
-"las",
-"lau",
-"law",
-"lax",
-"lay",
-"laz",
-"lba",
-"lbb",
-"lbc",
-"lbe",
-"lbf",
-"lbg",
-"lbi",
-"lbj",
-"lbk",
-"lbl",
-"lbm",
-"lbn",
-"lbo",
-"lbq",
-"lbr",
-"lbs",
-"lbt",
-"lbu",
-"lbv",
-"lbw",
-"lbx",
-"lby",
-"lbz",
-"lcc",
-"lcd",
-"lce",
-"lcf",
-"lch",
-"lcl",
-"lcm",
-"lcp",
-"lcq",
-"lcs",
-"lda",
-"ldb",
-"ldd",
-"ldg",
-"ldh",
-"ldi",
-"ldj",
-"ldk",
-"ldl",
-"ldm",
-"ldn",
-"ldo",
-"ldp",
-"ldq",
-"lea",
-"leb",
-"lec",
-"led",
-"lee",
-"lef",
-"leg",
-"leh",
-"lei",
-"lej",
-"lek",
-"lel",
-"lem",
-"len",
-"leo",
-"lep",
-"leq",
-"ler",
-"les",
-"let",
-"leu",
-"lev",
-"lew",
-"lex",
-"ley",
-"lez",
-"lfa",
-"lfn",
-"lga",
-"lgb",
-"lgg",
-"lgh",
-"lgi",
-"lgk",
-"lgl",
-"lgm",
-"lgn",
-"lgq",
-"lgr",
-"lgt",
-"lgu",
-"lgz",
-"lha",
-"lhh",
-"lhi",
-"lhl",
-"lhm",
-"lhn",
-"lhp",
-"lhs",
-"lht",
-"lhu",
-"lia",
-"lib",
-"lic",
-"lid",
-"lie",
-"lif",
-"lig",
-"lih",
-"lii",
-"lij",
-"lik",
-"lil",
-"lio",
-"lip",
-"liq",
-"lir",
-"lis",
-"liu",
-"liv",
-"liw",
-"lix",
-"liy",
-"liz",
-"lja",
-"lje",
-"lji",
-"ljl",
-"ljp",
-"ljw",
-"ljx",
-"lka",
-"lkb",
-"lkc",
-"lkd",
-"lke",
-"lkh",
-"lki",
-"lkj",
-"lkl",
-"lkm",
-"lkn",
-"lko",
-"lkr",
-"lks",
-"lkt",
-"lku",
-"lky",
-"lla",
-"llb",
-"llc",
-"lld",
-"lle",
-"llf",
-"llg",
-"llh",
-"lli",
-"llj",
-"llk",
-"lll",
-"llm",
-"lln",
-"llo",
-"llp",
-"llq",
-"lls",
-"llu",
-"llx",
-"lma",
-"lmb",
-"lmc",
-"lmd",
-"lme",
-"lmf",
-"lmg",
-"lmh",
-"lmi",
-"lmj",
-"lmk",
-"lml",
-"lmm",
-"lmn",
-"lmo",
-"lmp",
-"lmq",
-"lmr",
-"lmu",
-"lmv",
-"lmw",
-"lmx",
-"lmy",
-"lmz",
-"lna",
-"lnb",
-"lnd",
-"lng",
-"lnh",
-"lni",
-"lnj",
-"lnl",
-"lnm",
-"lnn",
-"lno",
-"lns",
-"lnu",
-"lnw",
-"lnz",
-"loa",
-"lob",
-"loc",
-"loe",
-"lof",
-"log",
-"loh",
-"loi",
-"loj",
-"lok",
-"lol",
-"lom",
-"lon",
-"loo",
-"lop",
-"loq",
-"lor",
-"los",
-"lot",
-"lou",
-"lov",
-"low",
-"lox",
-"loy",
-"loz",
-"lpa",
-"lpe",
-"lpn",
-"lpo",
-"lpx",
-"lra",
-"lrc",
-"lre",
-"lrg",
-"lri",
-"lrk",
-"lrl",
-"lrm",
-"lrn",
-"lro",
-"lrr",
-"lrt",
-"lrv",
-"lrz",
-"lsa",
-"lsd",
-"lse",
-"lsg",
-"lsh",
-"lsi",
-"lsl",
-"lsm",
-"lso",
-"lsp",
-"lsr",
-"lss",
-"lst",
-"lsy",
-"ltc",
-"ltg",
-"lth",
-"lti",
-"ltn",
-"lto",
-"lts",
-"ltu",
-"lua",
-"luc",
-"lud",
-"lue",
-"luf",
-"lui",
-"luj",
-"luk",
-"lul",
-"lum",
-"lun",
-"luo",
-"lup",
-"luq",
-"lur",
-"lus",
-"lut",
-"luu",
-"luv",
-"luw",
-"luy",
-"luz",
-"lva",
-"lvk",
-"lvs",
-"lvu",
-"lwa",
-"lwe",
-"lwg",
-"lwh",
-"lwl",
-"lwm",
-"lwo",
-"lwt",
-"lwu",
-"lww",
-"lya",
-"lyg",
-"lyn",
-"lzh",
-"lzl",
-"lzn",
-"lzz",
-"maa",
-"mab",
-"mad",
-"mae",
-"maf",
-"mag",
-"mai",
-"maj",
-"mak",
-"mam",
-"man",
-"map",
-"maq",
-"mas",
-"mat",
-"mau",
-"mav",
-"maw",
-"max",
-"maz",
-"mba",
-"mbb",
-"mbc",
-"mbd",
-"mbe",
-"mbf",
-"mbh",
-"mbi",
-"mbj",
-"mbk",
-"mbl",
-"mbm",
-"mbn",
-"mbo",
-"mbp",
-"mbq",
-"mbr",
-"mbs",
-"mbt",
-"mbu",
-"mbv",
-"mbw",
-"mbx",
-"mby",
-"mbz",
-"mca",
-"mcb",
-"mcc",
-"mcd",
-"mce",
-"mcf",
-"mcg",
-"mch",
-"mci",
-"mcj",
-"mck",
-"mcl",
-"mcm",
-"mcn",
-"mco",
-"mcp",
-"mcq",
-"mcr",
-"mcs",
-"mct",
-"mcu",
-"mcv",
-"mcw",
-"mcx",
-"mcy",
-"mcz",
-"mda",
-"mdb",
-"mdc",
-"mdd",
-"mde",
-"mdf",
-"mdg",
-"mdh",
-"mdi",
-"mdj",
-"mdk",
-"mdl",
-"mdm",
-"mdn",
-"mdp",
-"mdq",
-"mdr",
-"mds",
-"mdt",
-"mdu",
-"mdv",
-"mdw",
-"mdx",
-"mdy",
-"mdz",
-"mea",
-"meb",
-"mec",
-"med",
-"mee",
-"mef",
-"meg",
-"meh",
-"mei",
-"mej",
-"mek",
-"mel",
-"mem",
-"men",
-"meo",
-"mep",
-"meq",
-"mer",
-"mes",
-"met",
-"meu",
-"mev",
-"mew",
-"mey",
-"mez",
-"mfa",
-"mfb",
-"mfc",
-"mfd",
-"mfe",
-"mff",
-"mfg",
-"mfh",
-"mfi",
-"mfj",
-"mfk",
-"mfl",
-"mfm",
-"mfn",
-"mfo",
-"mfp",
-"mfq",
-"mfr",
-"mfs",
-"mft",
-"mfu",
-"mfv",
-"mfw",
-"mfx",
-"mfy",
-"mfz",
-"mga",
-"mgb",
-"mgc",
-"mgd",
-"mge",
-"mgf",
-"mgg",
-"mgh",
-"mgi",
-"mgj",
-"mgk",
-"mgl",
-"mgm",
-"mgn",
-"mgo",
-"mgp",
-"mgq",
-"mgr",
-"mgs",
-"mgt",
-"mgu",
-"mgv",
-"mgw",
-"mgx",
-"mgy",
-"mgz",
-"mha",
-"mhb",
-"mhc",
-"mhd",
-"mhe",
-"mhf",
-"mhg",
-"mhh",
-"mhi",
-"mhj",
-"mhk",
-"mhl",
-"mhm",
-"mhn",
-"mho",
-"mhp",
-"mhq",
-"mhr",
-"mhs",
-"mht",
-"mhu",
-"mhw",
-"mhx",
-"mhy",
-"mhz",
-"mia",
-"mib",
-"mic",
-"mid",
-"mie",
-"mif",
-"mig",
-"mih",
-"mii",
-"mij",
-"mik",
-"mil",
-"mim",
-"min",
-"mio",
-"mip",
-"miq",
-"mir",
-"mis",
-"mit",
-"miu",
-"miw",
-"mix",
-"miy",
-"miz",
-"mja",
-"mjb",
-"mjc",
-"mjd",
-"mje",
-"mjg",
-"mjh",
-"mji",
-"mjj",
-"mjk",
-"mjl",
-"mjm",
-"mjn",
-"mjo",
-"mjp",
-"mjq",
-"mjr",
-"mjs",
-"mjt",
-"mju",
-"mjv",
-"mjw",
-"mjx",
-"mjy",
-"mjz",
-"mka",
-"mkb",
-"mkc",
-"mke",
-"mkf",
-"mkg",
-"mkh",
-"mki",
-"mkj",
-"mkk",
-"mkl",
-"mkm",
-"mkn",
-"mko",
-"mkp",
-"mkq",
-"mkr",
-"mks",
-"mkt",
-"mku",
-"mkv",
-"mkw",
-"mkx",
-"mky",
-"mkz",
-"mla",
-"mlb",
-"mlc",
-"mld",
-"mle",
-"mlf",
-"mlh",
-"mli",
-"mlj",
-"mlk",
-"mll",
-"mlm",
-"mln",
-"mlo",
-"mlp",
-"mlq",
-"mlr",
-"mls",
-"mlu",
-"mlv",
-"mlw",
-"mlx",
-"mlz",
-"mma",
-"mmb",
-"mmc",
-"mmd",
-"mme",
-"mmf",
-"mmg",
-"mmh",
-"mmi",
-"mmj",
-"mmk",
-"mml",
-"mmm",
-"mmn",
-"mmo",
-"mmp",
-"mmq",
-"mmr",
-"mmt",
-"mmu",
-"mmv",
-"mmw",
-"mmx",
-"mmy",
-"mmz",
-"mna",
-"mnb",
-"mnc",
-"mnd",
-"mne",
-"mnf",
-"mng",
-"mnh",
-"mni",
-"mnj",
-"mnk",
-"mnl",
-"mnm",
-"mnn",
-"mno",
-"mnp",
-"mnq",
-"mnr",
-"mns",
-"mnt",
-"mnu",
-"mnv",
-"mnw",
-"mnx",
-"mny",
-"mnz",
-"moa",
-"moc",
-"mod",
-"moe",
-"mof",
-"mog",
-"moh",
-"moi",
-"moj",
-"mok",
-"mom",
-"moo",
-"mop",
-"moq",
-"mor",
-"mos",
-"mot",
-"mou",
-"mov",
-"mow",
-"mox",
-"moy",
-"moz",
-"mpa",
-"mpb",
-"mpc",
-"mpd",
-"mpe",
-"mpg",
-"mph",
-"mpi",
-"mpj",
-"mpk",
-"mpl",
-"mpm",
-"mpn",
-"mpo",
-"mpp",
-"mpq",
-"mpr",
-"mps",
-"mpt",
-"mpu",
-"mpv",
-"mpw",
-"mpx",
-"mpy",
-"mpz",
-"mqa",
-"mqb",
-"mqc",
-"mqe",
-"mqf",
-"mqg",
-"mqh",
-"mqi",
-"mqj",
-"mqk",
-"mql",
-"mqm",
-"mqn",
-"mqo",
-"mqp",
-"mqq",
-"mqr",
-"mqs",
-"mqt",
-"mqu",
-"mqv",
-"mqw",
-"mqx",
-"mqy",
-"mqz",
-"mra",
-"mrb",
-"mrc",
-"mrd",
-"mre",
-"mrf",
-"mrg",
-"mrh",
-"mrj",
-"mrk",
-"mrl",
-"mrm",
-"mrn",
-"mro",
-"mrp",
-"mrq",
-"mrr",
-"mrs",
-"mrt",
-"mru",
-"mrv",
-"mrw",
-"mrx",
-"mry",
-"mrz",
-"msb",
-"msc",
-"msd",
-"mse",
-"msf",
-"msg",
-"msh",
-"msi",
-"msj",
-"msk",
-"msl",
-"msm",
-"msn",
-"mso",
-"msp",
-"msq",
-"msr",
-"mss",
-"mst",
-"msu",
-"msv",
-"msw",
-"msx",
-"msy",
-"msz",
-"mta",
-"mtb",
-"mtc",
-"mtd",
-"mte",
-"mtf",
-"mtg",
-"mth",
-"mti",
-"mtj",
-"mtk",
-"mtl",
-"mtm",
-"mtn",
-"mto",
-"mtp",
-"mtq",
-"mtr",
-"mts",
-"mtt",
-"mtu",
-"mtv",
-"mtw",
-"mtx",
-"mty",
-"mua",
-"mub",
-"muc",
-"mud",
-"mue",
-"mug",
-"muh",
-"mui",
-"muj",
-"muk",
-"mul",
-"mum",
-"mun",
-"muo",
-"mup",
-"muq",
-"mur",
-"mus",
-"mut",
-"muu",
-"muv",
-"mux",
-"muy",
-"muz",
-"mva",
-"mvb",
-"mvd",
-"mve",
-"mvf",
-"mvg",
-"mvh",
-"mvi",
-"mvk",
-"mvl",
-"mvm",
-"mvn",
-"mvo",
-"mvp",
-"mvq",
-"mvr",
-"mvs",
-"mvt",
-"mvu",
-"mvv",
-"mvw",
-"mvx",
-"mvy",
-"mvz",
-"mwa",
-"mwb",
-"mwc",
-"mwd",
-"mwe",
-"mwf",
-"mwg",
-"mwh",
-"mwi",
-"mwj",
-"mwk",
-"mwl",
-"mwm",
-"mwn",
-"mwo",
-"mwp",
-"mwq",
-"mwr",
-"mws",
-"mwt",
-"mwu",
-"mwv",
-"mww",
-"mwx",
-"mwy",
-"mwz",
-"mxa",
-"mxb",
-"mxc",
-"mxd",
-"mxe",
-"mxf",
-"mxg",
-"mxh",
-"mxi",
-"mxj",
-"mxk",
-"mxl",
-"mxm",
-"mxn",
-"mxo",
-"mxp",
-"mxq",
-"mxr",
-"mxs",
-"mxt",
-"mxu",
-"mxv",
-"mxw",
-"mxx",
-"mxy",
-"mxz",
-"myb",
-"myc",
-"myd",
-"mye",
-"myf",
-"myg",
-"myh",
-"myi",
-"myj",
-"myk",
-"myl",
-"mym",
-"myn",
-"myo",
-"myp",
-"myq",
-"myr",
-"mys",
-"myt",
-"myu",
-"myv",
-"myw",
-"myx",
-"myy",
-"myz",
-"mza",
-"mzb",
-"mzc",
-"mzd",
-"mze",
-"mzg",
-"mzh",
-"mzi",
-"mzj",
-"mzk",
-"mzl",
-"mzm",
-"mzn",
-"mzo",
-"mzp",
-"mzq",
-"mzr",
-"mzs",
-"mzt",
-"mzu",
-"mzv",
-"mzw",
-"mzx",
-"mzy",
-"mzz",
-"naa",
-"nab",
-"nac",
-"nad",
-"nae",
-"naf",
-"nag",
-"nah",
-"nai",
-"naj",
-"nak",
-"nal",
-"nam",
-"nan",
-"nao",
-"nap",
-"naq",
-"nar",
-"nas",
-"nat",
-"naw",
-"nax",
-"nay",
-"naz",
-"nba",
-"nbb",
-"nbc",
-"nbd",
-"nbe",
-"nbf",
-"nbg",
-"nbh",
-"nbi",
-"nbj",
-"nbk",
-"nbm",
-"nbn",
-"nbo",
-"nbp",
-"nbq",
-"nbr",
-"nbs",
-"nbt",
-"nbu",
-"nbv",
-"nbw",
-"nbx",
-"nby",
-"nca",
-"ncb",
-"ncc",
-"ncd",
-"nce",
-"ncf",
-"ncg",
-"nch",
-"nci",
-"ncj",
-"nck",
-"ncl",
-"ncm",
-"ncn",
-"nco",
-"ncp",
-"ncq",
-"ncr",
-"ncs",
-"nct",
-"ncu",
-"ncx",
-"ncz",
-"nda",
-"ndb",
-"ndc",
-"ndd",
-"ndf",
-"ndg",
-"ndh",
-"ndi",
-"ndj",
-"ndk",
-"ndl",
-"ndm",
-"ndn",
-"ndp",
-"ndq",
-"ndr",
-"nds",
-"ndt",
-"ndu",
-"ndv",
-"ndw",
-"ndx",
-"ndy",
-"ndz",
-"nea",
-"neb",
-"nec",
-"ned",
-"nee",
-"nef",
-"neg",
-"neh",
-"nei",
-"nej",
-"nek",
-"nem",
-"nen",
-"neo",
-"neq",
-"ner",
-"nes",
-"net",
-"neu",
-"nev",
-"new",
-"nex",
-"ney",
-"nez",
-"nfa",
-"nfd",
-"nfl",
-"nfr",
-"nfu",
-"nga",
-"ngb",
-"ngc",
-"ngd",
-"nge",
-"ngf",
-"ngg",
-"ngh",
-"ngi",
-"ngj",
-"ngk",
-"ngl",
-"ngm",
-"ngn",
-"ngo",
-"ngp",
-"ngq",
-"ngr",
-"ngs",
-"ngt",
-"ngu",
-"ngv",
-"ngw",
-"ngx",
-"ngy",
-"ngz",
-"nha",
-"nhb",
-"nhc",
-"nhd",
-"nhe",
-"nhf",
-"nhg",
-"nhh",
-"nhi",
-"nhk",
-"nhm",
-"nhn",
-"nho",
-"nhp",
-"nhq",
-"nhr",
-"nht",
-"nhu",
-"nhv",
-"nhw",
-"nhx",
-"nhy",
-"nhz",
-"nia",
-"nib",
-"nic",
-"nid",
-"nie",
-"nif",
-"nig",
-"nih",
-"nii",
-"nij",
-"nik",
-"nil",
-"nim",
-"nin",
-"nio",
-"niq",
-"nir",
-"nis",
-"nit",
-"niu",
-"niv",
-"niw",
-"nix",
-"niy",
-"niz",
-"nja",
-"njb",
-"njd",
-"njh",
-"nji",
-"njj",
-"njl",
-"njm",
-"njn",
-"njo",
-"njr",
-"njs",
-"njt",
-"nju",
-"njx",
-"njy",
-"njz",
-"nka",
-"nkb",
-"nkc",
-"nkd",
-"nke",
-"nkf",
-"nkg",
-"nkh",
-"nki",
-"nkj",
-"nkk",
-"nkm",
-"nkn",
-"nko",
-"nkp",
-"nkq",
-"nkr",
-"nks",
-"nkt",
-"nku",
-"nkv",
-"nkw",
-"nkx",
-"nkz",
-"nla",
-"nlc",
-"nle",
-"nlg",
-"nli",
-"nlj",
-"nlk",
-"nll",
-"nln",
-"nlo",
-"nlq",
-"nlr",
-"nlu",
-"nlv",
-"nlw",
-"nlx",
-"nly",
-"nlz",
-"nma",
-"nmb",
-"nmc",
-"nmd",
-"nme",
-"nmf",
-"nmg",
-"nmh",
-"nmi",
-"nmj",
-"nmk",
-"nml",
-"nmm",
-"nmn",
-"nmo",
-"nmp",
-"nmq",
-"nmr",
-"nms",
-"nmt",
-"nmu",
-"nmv",
-"nmw",
-"nmx",
-"nmy",
-"nmz",
-"nna",
-"nnb",
-"nnc",
-"nnd",
-"nne",
-"nnf",
-"nng",
-"nnh",
-"nni",
-"nnj",
-"nnk",
-"nnl",
-"nnm",
-"nnn",
-"nnp",
-"nnq",
-"nnr",
-"nns",
-"nnt",
-"nnu",
-"nnv",
-"nnw",
-"nnx",
-"nny",
-"nnz",
-"noa",
-"noc",
-"nod",
-"noe",
-"nof",
-"nog",
-"noh",
-"noi",
-"noj",
-"nok",
-"nol",
-"nom",
-"non",
-"noo",
-"nop",
-"noq",
-"nos",
-"not",
-"nou",
-"nov",
-"now",
-"noy",
-"noz",
-"npa",
-"npb",
-"npg",
-"nph",
-"npi",
-"npl",
-"npn",
-"npo",
-"nps",
-"npu",
-"npx",
-"npy",
-"nqg",
-"nqk",
-"nql",
-"nqm",
-"nqn",
-"nqo",
-"nqq",
-"nqy",
-"nra",
-"nrb",
-"nrc",
-"nre",
-"nrf",
-"nrg",
-"nri",
-"nrk",
-"nrl",
-"nrm",
-"nrn",
-"nrp",
-"nrr",
-"nrt",
-"nru",
-"nrx",
-"nrz",
-"nsa",
-"nsc",
-"nsd",
-"nse",
-"nsf",
-"nsg",
-"nsh",
-"nsi",
-"nsk",
-"nsl",
-"nsm",
-"nsn",
-"nso",
-"nsp",
-"nsq",
-"nsr",
-"nss",
-"nst",
-"nsu",
-"nsv",
-"nsw",
-"nsx",
-"nsy",
-"nsz",
-"ntd",
-"nte",
-"ntg",
-"nti",
-"ntj",
-"ntk",
-"ntm",
-"nto",
-"ntp",
-"ntr",
-"nts",
-"ntu",
-"ntw",
-"ntx",
-"nty",
-"ntz",
-"nua",
-"nub",
-"nuc",
-"nud",
-"nue",
-"nuf",
-"nug",
-"nuh",
-"nui",
-"nuj",
-"nuk",
-"nul",
-"num",
-"nun",
-"nuo",
-"nup",
-"nuq",
-"nur",
-"nus",
-"nut",
-"nuu",
-"nuv",
-"nuw",
-"nux",
-"nuy",
-"nuz",
-"nvh",
-"nvm",
-"nvo",
-"nwa",
-"nwb",
-"nwc",
-"nwe",
-"nwg",
-"nwi",
-"nwm",
-"nwo",
-"nwr",
-"nwx",
-"nwy",
-"nxa",
-"nxd",
-"nxe",
-"nxg",
-"nxi",
-"nxk",
-"nxl",
-"nxm",
-"nxn",
-"nxo",
-"nxq",
-"nxr",
-"nxu",
-"nxx",
-"nyb",
-"nyc",
-"nyd",
-"nye",
-"nyf",
-"nyg",
-"nyh",
-"nyi",
-"nyj",
-"nyk",
-"nyl",
-"nym",
-"nyn",
-"nyo",
-"nyp",
-"nyq",
-"nyr",
-"nys",
-"nyt",
-"nyu",
-"nyv",
-"nyw",
-"nyx",
-"nyy",
-"nza",
-"nzb",
-"nzi",
-"nzk",
-"nzm",
-"nzs",
-"nzu",
-"nzy",
-"nzz",
-"oaa",
-"oac",
-"oar",
-"oav",
-"obi",
-"obk",
-"obl",
-"obm",
-"obo",
-"obr",
-"obt",
-"obu",
-"oca",
-"och",
-"oco",
-"ocu",
-"oda",
-"odk",
-"odt",
-"odu",
-"ofo",
-"ofs",
-"ofu",
-"ogb",
-"ogc",
-"oge",
-"ogg",
-"ogo",
-"ogu",
-"oht",
-"ohu",
-"oia",
-"oin",
-"ojb",
-"ojc",
-"ojg",
-"ojp",
-"ojs",
-"ojv",
-"ojw",
-"oka",
-"okb",
-"okd",
-"oke",
-"okg",
-"okh",
-"oki",
-"okj",
-"okk",
-"okl",
-"okm",
-"okn",
-"oko",
-"okr",
-"oks",
-"oku",
-"okv",
-"okx",
-"ola",
-"old",
-"ole",
-"olk",
-"olm",
-"olo",
-"olr",
-"olt",
-"olu",
-"oma",
-"omb",
-"omc",
-"ome",
-"omg",
-"omi",
-"omk",
-"oml",
-"omn",
-"omo",
-"omp",
-"omq",
-"omr",
-"omt",
-"omu",
-"omv",
-"omw",
-"omx",
-"ona",
-"onb",
-"one",
-"ong",
-"oni",
-"onj",
-"onk",
-"onn",
-"ono",
-"onp",
-"onr",
-"ons",
-"ont",
-"onu",
-"onw",
-"onx",
-"ood",
-"oog",
-"oon",
-"oor",
-"oos",
-"opa",
-"opk",
-"opm",
-"opo",
-"opt",
-"opy",
-"ora",
-"orc",
-"ore",
-"org",
-"orh",
-"orn",
-"oro",
-"orr",
-"ors",
-"ort",
-"oru",
-"orv",
-"orw",
-"orx",
-"ory",
-"orz",
-"osa",
-"osc",
-"osi",
-"oso",
-"osp",
-"ost",
-"osu",
-"osx",
-"ota",
-"otb",
-"otd",
-"ote",
-"oti",
-"otk",
-"otl",
-"otm",
-"otn",
-"oto",
-"otq",
-"otr",
-"ots",
-"ott",
-"otu",
-"otw",
-"otx",
-"oty",
-"otz",
-"oua",
-"oub",
-"oue",
-"oui",
-"oum",
-"oun",
-"ovd",
-"owi",
-"owl",
-"oyb",
-"oyd",
-"oym",
-"oyy",
-"ozm",
-"paa",
-"pab",
-"pac",
-"pad",
-"pae",
-"paf",
-"pag",
-"pah",
-"pai",
-"pak",
-"pal",
-"pam",
-"pao",
-"pap",
-"paq",
-"par",
-"pas",
-"pat",
-"pau",
-"pav",
-"paw",
-"pax",
-"pay",
-"paz",
-"pbb",
-"pbc",
-"pbe",
-"pbf",
-"pbg",
-"pbh",
-"pbi",
-"pbl",
-"pbn",
-"pbo",
-"pbp",
-"pbr",
-"pbs",
-"pbt",
-"pbu",
-"pbv",
-"pby",
-"pbz",
-"pca",
-"pcb",
-"pcc",
-"pcd",
-"pce",
-"pcf",
-"pcg",
-"pch",
-"pci",
-"pcj",
-"pck",
-"pcl",
-"pcm",
-"pcn",
-"pcp",
-"pcr",
-"pcw",
-"pda",
-"pdc",
-"pdi",
-"pdn",
-"pdo",
-"pdt",
-"pdu",
-"pea",
-"peb",
-"ped",
-"pee",
-"pef",
-"peg",
-"peh",
-"pei",
-"pej",
-"pek",
-"pel",
-"pem",
-"peo",
-"pep",
-"peq",
-"pes",
-"pev",
-"pex",
-"pey",
-"pez",
-"pfa",
-"pfe",
-"pfl",
-"pga",
-"pgd",
-"pgg",
-"pgi",
-"pgk",
-"pgl",
-"pgn",
-"pgs",
-"pgu",
-"pgy",
-"pgz",
-"pha",
-"phd",
-"phg",
-"phh",
-"phi",
-"phk",
-"phl",
-"phm",
-"phn",
-"pho",
-"phq",
-"phr",
-"pht",
-"phu",
-"phv",
-"phw",
-"pia",
-"pib",
-"pic",
-"pid",
-"pie",
-"pif",
-"pig",
-"pih",
-"pii",
-"pij",
-"pil",
-"pim",
-"pin",
-"pio",
-"pip",
-"pir",
-"pis",
-"pit",
-"piu",
-"piv",
-"piw",
-"pix",
-"piy",
-"piz",
-"pjt",
-"pka",
-"pkb",
-"pkc",
-"pkg",
-"pkh",
-"pkn",
-"pko",
-"pkp",
-"pkr",
-"pks",
-"pkt",
-"pku",
-"pla",
-"plb",
-"plc",
-"pld",
-"ple",
-"plf",
-"plg",
-"plh",
-"plj",
-"plk",
-"pll",
-"pln",
-"plo",
-"plp",
-"plq",
-"plr",
-"pls",
-"plt",
-"plu",
-"plv",
-"plw",
-"ply",
-"plz",
-"pma",
-"pmb",
-"pmc",
-"pmd",
-"pme",
-"pmf",
-"pmh",
-"pmi",
-"pmj",
-"pmk",
-"pml",
-"pmm",
-"pmn",
-"pmo",
-"pmq",
-"pmr",
-"pms",
-"pmt",
-"pmu",
-"pmw",
-"pmx",
-"pmy",
-"pmz",
-"pna",
-"pnb",
-"pnc",
-"pne",
-"png",
-"pnh",
-"pni",
-"pnj",
-"pnk",
-"pnl",
-"pnm",
-"pnn",
-"pno",
-"pnp",
-"pnq",
-"pnr",
-"pns",
-"pnt",
-"pnu",
-"pnv",
-"pnw",
-"pnx",
-"pny",
-"pnz",
-"poc",
-"pod",
-"poe",
-"pof",
-"pog",
-"poh",
-"poi",
-"pok",
-"pom",
-"pon",
-"poo",
-"pop",
-"poq",
-"pos",
-"pot",
-"pov",
-"pow",
-"pox",
-"poy",
-"poz",
-"ppa",
-"ppe",
-"ppi",
-"ppk",
-"ppl",
-"ppm",
-"ppn",
-"ppo",
-"ppp",
-"ppq",
-"ppr",
-"pps",
-"ppt",
-"ppu",
-"pqa",
-"pqe",
-"pqm",
-"pqw",
-"pra",
-"prb",
-"prc",
-"prd",
-"pre",
-"prf",
-"prg",
-"prh",
-"pri",
-"prk",
-"prl",
-"prm",
-"prn",
-"pro",
-"prp",
-"prq",
-"prr",
-"prs",
-"prt",
-"pru",
-"prw",
-"prx",
-"pry",
-"prz",
-"psa",
-"psc",
-"psd",
-"pse",
-"psg",
-"psh",
-"psi",
-"psl",
-"psm",
-"psn",
-"pso",
-"psp",
-"psq",
-"psr",
-"pss",
-"pst",
-"psu",
-"psw",
-"psy",
-"pta",
-"pth",
-"pti",
-"ptn",
-"pto",
-"ptp",
-"ptq",
-"ptr",
-"ptt",
-"ptu",
-"ptv",
-"ptw",
-"pty",
-"pua",
-"pub",
-"puc",
-"pud",
-"pue",
-"puf",
-"pug",
-"pui",
-"puj",
-"puk",
-"pum",
-"puo",
-"pup",
-"puq",
-"pur",
-"put",
-"puu",
-"puw",
-"pux",
-"puy",
-"puz",
-"pwa",
-"pwb",
-"pwg",
-"pwi",
-"pwm",
-"pwn",
-"pwo",
-"pwr",
-"pww",
-"pxm",
-"pye",
-"pym",
-"pyn",
-"pys",
-"pyu",
-"pyx",
-"pyy",
-"pzn",
-"qaa..qtz",
-"qua",
-"qub",
-"quc",
-"qud",
-"quf",
-"qug",
-"quh",
-"qui",
-"quk",
-"qul",
-"qum",
-"qun",
-"qup",
-"quq",
-"qur",
-"qus",
-"quv",
-"quw",
-"qux",
-"quy",
-"quz",
-"qva",
-"qvc",
-"qve",
-"qvh",
-"qvi",
-"qvj",
-"qvl",
-"qvm",
-"qvn",
-"qvo",
-"qvp",
-"qvs",
-"qvw",
-"qvy",
-"qvz",
-"qwa",
-"qwc",
-"qwe",
-"qwh",
-"qwm",
-"qws",
-"qwt",
-"qxa",
-"qxc",
-"qxh",
-"qxl",
-"qxn",
-"qxo",
-"qxp",
-"qxq",
-"qxr",
-"qxs",
-"qxt",
-"qxu",
-"qxw",
-"qya",
-"qyp",
-"raa",
-"rab",
-"rac",
-"rad",
-"raf",
-"rag",
-"rah",
-"rai",
-"raj",
-"rak",
-"ral",
-"ram",
-"ran",
-"rao",
-"rap",
-"raq",
-"rar",
-"ras",
-"rat",
-"rau",
-"rav",
-"raw",
-"rax",
-"ray",
-"raz",
-"rbb",
-"rbk",
-"rbl",
-"rbp",
-"rcf",
-"rdb",
-"rea",
-"reb",
-"ree",
-"reg",
-"rei",
-"rej",
-"rel",
-"rem",
-"ren",
-"rer",
-"res",
-"ret",
-"rey",
-"rga",
-"rge",
-"rgk",
-"rgn",
-"rgr",
-"rgs",
-"rgu",
-"rhg",
-"rhp",
-"ria",
-"rie",
-"rif",
-"ril",
-"rim",
-"rin",
-"rir",
-"rit",
-"riu",
-"rjg",
-"rji",
-"rjs",
-"rka",
-"rkb",
-"rkh",
-"rki",
-"rkm",
-"rkt",
-"rkw",
-"rma",
-"rmb",
-"rmc",
-"rmd",
-"rme",
-"rmf",
-"rmg",
-"rmh",
-"rmi",
-"rmk",
-"rml",
-"rmm",
-"rmn",
-"rmo",
-"rmp",
-"rmq",
-"rmr",
-"rms",
-"rmt",
-"rmu",
-"rmv",
-"rmw",
-"rmx",
-"rmy",
-"rmz",
-"rna",
-"rnd",
-"rng",
-"rnl",
-"rnn",
-"rnp",
-"rnr",
-"rnw",
-"roa",
-"rob",
-"roc",
-"rod",
-"roe",
-"rof",
-"rog",
-"rol",
-"rom",
-"roo",
-"rop",
-"ror",
-"rou",
-"row",
-"rpn",
-"rpt",
-"rri",
-"rro",
-"rrt",
-"rsb",
-"rsi",
-"rsl",
-"rsm",
-"rtc",
-"rth",
-"rtm",
-"rts",
-"rtw",
-"rub",
-"ruc",
-"rue",
-"ruf",
-"rug",
-"ruh",
-"rui",
-"ruk",
-"ruo",
-"rup",
-"ruq",
-"rut",
-"ruu",
-"ruy",
-"ruz",
-"rwa",
-"rwk",
-"rwm",
-"rwo",
-"rwr",
-"rxd",
-"rxw",
-"ryn",
-"rys",
-"ryu",
-"rzh",
-"saa",
-"sab",
-"sac",
-"sad",
-"sae",
-"saf",
-"sah",
-"sai",
-"saj",
-"sak",
-"sal",
-"sam",
-"sao",
-"sap",
-"saq",
-"sar",
-"sas",
-"sat",
-"sau",
-"sav",
-"saw",
-"sax",
-"say",
-"saz",
-"sba",
-"sbb",
-"sbc",
-"sbd",
-"sbe",
-"sbf",
-"sbg",
-"sbh",
-"sbi",
-"sbj",
-"sbk",
-"sbl",
-"sbm",
-"sbn",
-"sbo",
-"sbp",
-"sbq",
-"sbr",
-"sbs",
-"sbt",
-"sbu",
-"sbv",
-"sbw",
-"sbx",
-"sby",
-"sbz",
-"sca",
-"scb",
-"sce",
-"scf",
-"scg",
-"sch",
-"sci",
-"sck",
-"scl",
-"scn",
-"sco",
-"scp",
-"scq",
-"scs",
-"sct",
-"scu",
-"scv",
-"scw",
-"scx",
-"sda",
-"sdb",
-"sdc",
-"sde",
-"sdf",
-"sdg",
-"sdh",
-"sdj",
-"sdk",
-"sdl",
-"sdm",
-"sdn",
-"sdo",
-"sdp",
-"sdr",
-"sds",
-"sdt",
-"sdu",
-"sdv",
-"sdx",
-"sdz",
-"sea",
-"seb",
-"sec",
-"sed",
-"see",
-"sef",
-"seg",
-"seh",
-"sei",
-"sej",
-"sek",
-"sel",
-"sem",
-"sen",
-"seo",
-"sep",
-"seq",
-"ser",
-"ses",
-"set",
-"seu",
-"sev",
-"sew",
-"sey",
-"sez",
-"sfb",
-"sfe",
-"sfm",
-"sfs",
-"sfw",
-"sga",
-"sgb",
-"sgc",
-"sgd",
-"sge",
-"sgg",
-"sgh",
-"sgi",
-"sgj",
-"sgk",
-"sgl",
-"sgm",
-"sgn",
-"sgo",
-"sgp",
-"sgr",
-"sgs",
-"sgt",
-"sgu",
-"sgw",
-"sgx",
-"sgy",
-"sgz",
-"sha",
-"shb",
-"shc",
-"shd",
-"she",
-"shg",
-"shh",
-"shi",
-"shj",
-"shk",
-"shl",
-"shm",
-"shn",
-"sho",
-"shp",
-"shq",
-"shr",
-"shs",
-"sht",
-"shu",
-"shv",
-"shw",
-"shx",
-"shy",
-"shz",
-"sia",
-"sib",
-"sid",
-"sie",
-"sif",
-"sig",
-"sih",
-"sii",
-"sij",
-"sik",
-"sil",
-"sim",
-"sio",
-"sip",
-"siq",
-"sir",
-"sis",
-"sit",
-"siu",
-"siv",
-"siw",
-"six",
-"siy",
-"siz",
-"sja",
-"sjb",
-"sjd",
-"sje",
-"sjg",
-"sjk",
-"sjl",
-"sjm",
-"sjn",
-"sjo",
-"sjp",
-"sjr",
-"sjs",
-"sjt",
-"sju",
-"sjw",
-"ska",
-"skb",
-"skc",
-"skd",
-"ske",
-"skf",
-"skg",
-"skh",
-"ski",
-"skj",
-"skk",
-"skm",
-"skn",
-"sko",
-"skp",
-"skq",
-"skr",
-"sks",
-"skt",
-"sku",
-"skv",
-"skw",
-"skx",
-"sky",
-"skz",
-"sla",
-"slc",
-"sld",
-"sle",
-"slf",
-"slg",
-"slh",
-"sli",
-"slj",
-"sll",
-"slm",
-"sln",
-"slp",
-"slq",
-"slr",
-"sls",
-"slt",
-"slu",
-"slw",
-"slx",
-"sly",
-"slz",
-"sma",
-"smb",
-"smc",
-"smd",
-"smf",
-"smg",
-"smh",
-"smi",
-"smj",
-"smk",
-"sml",
-"smm",
-"smn",
-"smp",
-"smq",
-"smr",
-"sms",
-"smt",
-"smu",
-"smv",
-"smw",
-"smx",
-"smy",
-"smz",
-"snb",
-"snc",
-"sne",
-"snf",
-"sng",
-"snh",
-"sni",
-"snj",
-"snk",
-"snl",
-"snm",
-"snn",
-"sno",
-"snp",
-"snq",
-"snr",
-"sns",
-"snu",
-"snv",
-"snw",
-"snx",
-"sny",
-"snz",
-"soa",
-"sob",
-"soc",
-"sod",
-"soe",
-"sog",
-"soh",
-"soi",
-"soj",
-"sok",
-"sol",
-"son",
-"soo",
-"sop",
-"soq",
-"sor",
-"sos",
-"sou",
-"sov",
-"sow",
-"sox",
-"soy",
-"soz",
-"spb",
-"spc",
-"spd",
-"spe",
-"spg",
-"spi",
-"spk",
-"spl",
-"spm",
-"spn",
-"spo",
-"spp",
-"spq",
-"spr",
-"sps",
-"spt",
-"spu",
-"spv",
-"spx",
-"spy",
-"sqa",
-"sqh",
-"sqj",
-"sqk",
-"sqm",
-"sqn",
-"sqo",
-"sqq",
-"sqr",
-"sqs",
-"sqt",
-"squ",
-"sra",
-"srb",
-"src",
-"sre",
-"srf",
-"srg",
-"srh",
-"sri",
-"srk",
-"srl",
-"srm",
-"srn",
-"sro",
-"srq",
-"srr",
-"srs",
-"srt",
-"sru",
-"srv",
-"srw",
-"srx",
-"sry",
-"srz",
-"ssa",
-"ssb",
-"ssc",
-"ssd",
-"sse",
-"ssf",
-"ssg",
-"ssh",
-"ssi",
-"ssj",
-"ssk",
-"ssl",
-"ssm",
-"ssn",
-"sso",
-"ssp",
-"ssq",
-"ssr",
-"sss",
-"sst",
-"ssu",
-"ssv",
-"ssx",
-"ssy",
-"ssz",
-"sta",
-"stb",
-"std",
-"ste",
-"stf",
-"stg",
-"sth",
-"sti",
-"stj",
-"stk",
-"stl",
-"stm",
-"stn",
-"sto",
-"stp",
-"stq",
-"str",
-"sts",
-"stt",
-"stu",
-"stv",
-"stw",
-"sty",
-"sua",
-"sub",
-"suc",
-"sue",
-"sug",
-"sui",
-"suj",
-"suk",
-"sul",
-"sum",
-"suq",
-"sur",
-"sus",
-"sut",
-"suv",
-"suw",
-"sux",
-"suy",
-"suz",
-"sva",
-"svb",
-"svc",
-"sve",
-"svk",
-"svm",
-"svr",
-"svs",
-"svx",
-"swb",
-"swc",
-"swf",
-"swg",
-"swh",
-"swi",
-"swj",
-"swk",
-"swl",
-"swm",
-"swn",
-"swo",
-"swp",
-"swq",
-"swr",
-"sws",
-"swt",
-"swu",
-"swv",
-"sww",
-"swx",
-"swy",
-"sxb",
-"sxc",
-"sxe",
-"sxg",
-"sxk",
-"sxl",
-"sxm",
-"sxn",
-"sxo",
-"sxr",
-"sxs",
-"sxu",
-"sxw",
-"sya",
-"syb",
-"syc",
-"syd",
-"syi",
-"syk",
-"syl",
-"sym",
-"syn",
-"syo",
-"syr",
-"sys",
-"syw",
-"syx",
-"syy",
-"sza",
-"szb",
-"szc",
-"szd",
-"sze",
-"szg",
-"szl",
-"szn",
-"szp",
-"szs",
-"szv",
-"szw",
-"taa",
-"tab",
-"tac",
-"tad",
-"tae",
-"taf",
-"tag",
-"tai",
-"taj",
-"tak",
-"tal",
-"tan",
-"tao",
-"tap",
-"taq",
-"tar",
-"tas",
-"tau",
-"tav",
-"taw",
-"tax",
-"tay",
-"taz",
-"tba",
-"tbb",
-"tbc",
-"tbd",
-"tbe",
-"tbf",
-"tbg",
-"tbh",
-"tbi",
-"tbj",
-"tbk",
-"tbl",
-"tbm",
-"tbn",
-"tbo",
-"tbp",
-"tbq",
-"tbr",
-"tbs",
-"tbt",
-"tbu",
-"tbv",
-"tbw",
-"tbx",
-"tby",
-"tbz",
-"tca",
-"tcb",
-"tcc",
-"tcd",
-"tce",
-"tcf",
-"tcg",
-"tch",
-"tci",
-"tck",
-"tcl",
-"tcm",
-"tcn",
-"tco",
-"tcp",
-"tcq",
-"tcs",
-"tct",
-"tcu",
-"tcw",
-"tcx",
-"tcy",
-"tcz",
-"tda",
-"tdb",
-"tdc",
-"tdd",
-"tde",
-"tdf",
-"tdg",
-"tdh",
-"tdi",
-"tdj",
-"tdk",
-"tdl",
-"tdm",
-"tdn",
-"tdo",
-"tdq",
-"tdr",
-"tds",
-"tdt",
-"tdu",
-"tdv",
-"tdx",
-"tdy",
-"tea",
-"teb",
-"tec",
-"ted",
-"tee",
-"tef",
-"teg",
-"teh",
-"tei",
-"tek",
-"tem",
-"ten",
-"teo",
-"tep",
-"teq",
-"ter",
-"tes",
-"tet",
-"teu",
-"tev",
-"tew",
-"tex",
-"tey",
-"tfi",
-"tfn",
-"tfo",
-"tfr",
-"tft",
-"tga",
-"tgb",
-"tgc",
-"tgd",
-"tge",
-"tgf",
-"tgg",
-"tgh",
-"tgi",
-"tgj",
-"tgn",
-"tgo",
-"tgp",
-"tgq",
-"tgr",
-"tgs",
-"tgt",
-"tgu",
-"tgv",
-"tgw",
-"tgx",
-"tgy",
-"tgz",
-"thc",
-"thd",
-"the",
-"thf",
-"thh",
-"thi",
-"thk",
-"thl",
-"thm",
-"thn",
-"thp",
-"thq",
-"thr",
-"ths",
-"tht",
-"thu",
-"thv",
-"thw",
-"thx",
-"thy",
-"thz",
-"tia",
-"tic",
-"tid",
-"tie",
-"tif",
-"tig",
-"tih",
-"tii",
-"tij",
-"tik",
-"til",
-"tim",
-"tin",
-"tio",
-"tip",
-"tiq",
-"tis",
-"tit",
-"tiu",
-"tiv",
-"tiw",
-"tix",
-"tiy",
-"tiz",
-"tja",
-"tjg",
-"tji",
-"tjl",
-"tjm",
-"tjn",
-"tjo",
-"tjs",
-"tju",
-"tjw",
-"tka",
-"tkb",
-"tkd",
-"tke",
-"tkf",
-"tkg",
-"tkk",
-"tkl",
-"tkm",
-"tkn",
-"tkp",
-"tkq",
-"tkr",
-"tks",
-"tkt",
-"tku",
-"tkv",
-"tkw",
-"tkx",
-"tkz",
-"tla",
-"tlb",
-"tlc",
-"tld",
-"tlf",
-"tlg",
-"tlh",
-"tli",
-"tlj",
-"tlk",
-"tll",
-"tlm",
-"tln",
-"tlo",
-"tlp",
-"tlq",
-"tlr",
-"tls",
-"tlt",
-"tlu",
-"tlv",
-"tlw",
-"tlx",
-"tly",
-"tma",
-"tmb",
-"tmc",
-"tmd",
-"tme",
-"tmf",
-"tmg",
-"tmh",
-"tmi",
-"tmj",
-"tmk",
-"tml",
-"tmm",
-"tmn",
-"tmo",
-"tmp",
-"tmq",
-"tmr",
-"tms",
-"tmt",
-"tmu",
-"tmv",
-"tmw",
-"tmy",
-"tmz",
-"tna",
-"tnb",
-"tnc",
-"tnd",
-"tne",
-"tnf",
-"tng",
-"tnh",
-"tni",
-"tnk",
-"tnl",
-"tnm",
-"tnn",
-"tno",
-"tnp",
-"tnq",
-"tnr",
-"tns",
-"tnt",
-"tnu",
-"tnv",
-"tnw",
-"tnx",
-"tny",
-"tnz",
-"tob",
-"toc",
-"tod",
-"toe",
-"tof",
-"tog",
-"toh",
-"toi",
-"toj",
-"tol",
-"tom",
-"too",
-"top",
-"toq",
-"tor",
-"tos",
-"tou",
-"tov",
-"tow",
-"tox",
-"toy",
-"toz",
-"tpa",
-"tpc",
-"tpe",
-"tpf",
-"tpg",
-"tpi",
-"tpj",
-"tpk",
-"tpl",
-"tpm",
-"tpn",
-"tpo",
-"tpp",
-"tpq",
-"tpr",
-"tpt",
-"tpu",
-"tpv",
-"tpw",
-"tpx",
-"tpy",
-"tpz",
-"tqb",
-"tql",
-"tqm",
-"tqn",
-"tqo",
-"tqp",
-"tqq",
-"tqr",
-"tqt",
-"tqu",
-"tqw",
-"tra",
-"trb",
-"trc",
-"trd",
-"tre",
-"trf",
-"trg",
-"trh",
-"tri",
-"trj",
-"trk",
-"trl",
-"trm",
-"trn",
-"tro",
-"trp",
-"trq",
-"trr",
-"trs",
-"trt",
-"tru",
-"trv",
-"trw",
-"trx",
-"try",
-"trz",
-"tsa",
-"tsb",
-"tsc",
-"tsd",
-"tse",
-"tsf",
-"tsg",
-"tsh",
-"tsi",
-"tsj",
-"tsk",
-"tsl",
-"tsm",
-"tsp",
-"tsq",
-"tsr",
-"tss",
-"tst",
-"tsu",
-"tsv",
-"tsw",
-"tsx",
-"tsy",
-"tsz",
-"tta",
-"ttb",
-"ttc",
-"ttd",
-"tte",
-"ttf",
-"ttg",
-"tth",
-"tti",
-"ttj",
-"ttk",
-"ttl",
-"ttm",
-"ttn",
-"tto",
-"ttp",
-"ttq",
-"ttr",
-"tts",
-"ttt",
-"ttu",
-"ttv",
-"ttw",
-"tty",
-"ttz",
-"tua",
-"tub",
-"tuc",
-"tud",
-"tue",
-"tuf",
-"tug",
-"tuh",
-"tui",
-"tuj",
-"tul",
-"tum",
-"tun",
-"tuo",
-"tup",
-"tuq",
-"tus",
-"tut",
-"tuu",
-"tuv",
-"tuw",
-"tux",
-"tuy",
-"tuz",
-"tva",
-"tvd",
-"tve",
-"tvk",
-"tvl",
-"tvm",
-"tvn",
-"tvo",
-"tvs",
-"tvt",
-"tvu",
-"tvw",
-"tvy",
-"twa",
-"twb",
-"twc",
-"twd",
-"twe",
-"twf",
-"twg",
-"twh",
-"twl",
-"twm",
-"twn",
-"two",
-"twp",
-"twq",
-"twr",
-"twt",
-"twu",
-"tww",
-"twx",
-"twy",
-"txa",
-"txb",
-"txc",
-"txe",
-"txg",
-"txh",
-"txi",
-"txj",
-"txm",
-"txn",
-"txo",
-"txq",
-"txr",
-"txs",
-"txt",
-"txu",
-"txx",
-"txy",
-"tya",
-"tye",
-"tyh",
-"tyi",
-"tyj",
-"tyl",
-"tyn",
-"typ",
-"tyr",
-"tys",
-"tyt",
-"tyu",
-"tyv",
-"tyx",
-"tyz",
-"tza",
-"tzh",
-"tzj",
-"tzl",
-"tzm",
-"tzn",
-"tzo",
-"tzx",
-"uam",
-"uan",
-"uar",
-"uba",
-"ubi",
-"ubl",
-"ubr",
-"ubu",
-"uby",
-"uda",
-"ude",
-"udg",
-"udi",
-"udj",
-"udl",
-"udm",
-"udu",
-"ues",
-"ufi",
-"uga",
-"ugb",
-"uge",
-"ugn",
-"ugo",
-"ugy",
-"uha",
-"uhn",
-"uis",
-"uiv",
-"uji",
-"uka",
-"ukg",
-"ukh",
-"ukk",
-"ukl",
-"ukp",
-"ukq",
-"uks",
-"uku",
-"ukw",
-"uky",
-"ula",
-"ulb",
-"ulc",
-"ule",
-"ulf",
-"uli",
-"ulk",
-"ull",
-"ulm",
-"uln",
-"ulu",
-"ulw",
-"uma",
-"umb",
-"umc",
-"umd",
-"umg",
-"umi",
-"umm",
-"umn",
-"umo",
-"ump",
-"umr",
-"ums",
-"umu",
-"una",
-"und",
-"une",
-"ung",
-"unk",
-"unm",
-"unn",
-"unp",
-"unr",
-"unu",
-"unx",
-"unz",
-"uok",
-"upi",
-"upv",
-"ura",
-"urb",
-"urc",
-"ure",
-"urf",
-"urg",
-"urh",
-"uri",
-"urj",
-"urk",
-"url",
-"urm",
-"urn",
-"uro",
-"urp",
-"urr",
-"urt",
-"uru",
-"urv",
-"urw",
-"urx",
-"ury",
-"urz",
-"usa",
-"ush",
-"usi",
-"usk",
-"usp",
-"usu",
-"uta",
-"ute",
-"utp",
-"utr",
-"utu",
-"uum",
-"uun",
-"uur",
-"uuu",
-"uve",
-"uvh",
-"uvl",
-"uwa",
-"uya",
-"uzn",
-"uzs",
-"vaa",
-"vae",
-"vaf",
-"vag",
-"vah",
-"vai",
-"vaj",
-"val",
-"vam",
-"van",
-"vao",
-"vap",
-"var",
-"vas",
-"vau",
-"vav",
-"vay",
-"vbb",
-"vbk",
-"vec",
-"ved",
-"vel",
-"vem",
-"veo",
-"vep",
-"ver",
-"vgr",
-"vgt",
-"vic",
-"vid",
-"vif",
-"vig",
-"vil",
-"vin",
-"vis",
-"vit",
-"viv",
-"vka",
-"vki",
-"vkj",
-"vkk",
-"vkl",
-"vkm",
-"vko",
-"vkp",
-"vkt",
-"vku",
-"vlp",
-"vls",
-"vma",
-"vmb",
-"vmc",
-"vmd",
-"vme",
-"vmf",
-"vmg",
-"vmh",
-"vmi",
-"vmj",
-"vmk",
-"vml",
-"vmm",
-"vmp",
-"vmq",
-"vmr",
-"vms",
-"vmu",
-"vmv",
-"vmw",
-"vmx",
-"vmy",
-"vmz",
-"vnk",
-"vnm",
-"vnp",
-"vor",
-"vot",
-"vra",
-"vro",
-"vrs",
-"vrt",
-"vsi",
-"vsl",
-"vsv",
-"vto",
-"vum",
-"vun",
-"vut",
-"vwa",
-"waa",
-"wab",
-"wac",
-"wad",
-"wae",
-"waf",
-"wag",
-"wah",
-"wai",
-"waj",
-"wak",
-"wal",
-"wam",
-"wan",
-"wao",
-"wap",
-"waq",
-"war",
-"was",
-"wat",
-"wau",
-"wav",
-"waw",
-"wax",
-"way",
-"waz",
-"wba",
-"wbb",
-"wbe",
-"wbf",
-"wbh",
-"wbi",
-"wbj",
-"wbk",
-"wbl",
-"wbm",
-"wbp",
-"wbq",
-"wbr",
-"wbs",
-"wbt",
-"wbv",
-"wbw",
-"wca",
-"wci",
-"wdd",
-"wdg",
-"wdj",
-"wdk",
-"wdu",
-"wdy",
-"wea",
-"wec",
-"wed",
-"weg",
-"weh",
-"wei",
-"wem",
-"wen",
-"weo",
-"wep",
-"wer",
-"wes",
-"wet",
-"weu",
-"wew",
-"wfg",
-"wga",
-"wgb",
-"wgg",
-"wgi",
-"wgo",
-"wgu",
-"wgw",
-"wgy",
-"wha",
-"whg",
-"whk",
-"whu",
-"wib",
-"wic",
-"wie",
-"wif",
-"wig",
-"wih",
-"wii",
-"wij",
-"wik",
-"wil",
-"wim",
-"win",
-"wir",
-"wit",
-"wiu",
-"wiv",
-"wiw",
-"wiy",
-"wja",
-"wji",
-"wka",
-"wkb",
-"wkd",
-"wkl",
-"wku",
-"wkw",
-"wky",
-"wla",
-"wlc",
-"wle",
-"wlg",
-"wli",
-"wlk",
-"wll",
-"wlm",
-"wlo",
-"wlr",
-"wls",
-"wlu",
-"wlv",
-"wlw",
-"wlx",
-"wly",
-"wma",
-"wmb",
-"wmc",
-"wmd",
-"wme",
-"wmh",
-"wmi",
-"wmm",
-"wmn",
-"wmo",
-"wms",
-"wmt",
-"wmw",
-"wmx",
-"wnb",
-"wnc",
-"wnd",
-"wne",
-"wng",
-"wni",
-"wnk",
-"wnm",
-"wnn",
-"wno",
-"wnp",
-"wnu",
-"wnw",
-"wny",
-"woa",
-"wob",
-"woc",
-"wod",
-"woe",
-"wof",
-"wog",
-"woi",
-"wok",
-"wom",
-"won",
-"woo",
-"wor",
-"wos",
-"wow",
-"woy",
-"wpc",
-"wra",
-"wrb",
-"wrd",
-"wrg",
-"wrh",
-"wri",
-"wrk",
-"wrl",
-"wrm",
-"wrn",
-"wro",
-"wrp",
-"wrr",
-"wrs",
-"wru",
-"wrv",
-"wrw",
-"wrx",
-"wry",
-"wrz",
-"wsa",
-"wsg",
-"wsi",
-"wsk",
-"wsr",
-"wss",
-"wsu",
-"wsv",
-"wtf",
-"wth",
-"wti",
-"wtk",
-"wtm",
-"wtw",
-"wua",
-"wub",
-"wud",
-"wuh",
-"wul",
-"wum",
-"wun",
-"wur",
-"wut",
-"wuu",
-"wuv",
-"wux",
-"wuy",
-"wwa",
-"wwb",
-"wwo",
-"wwr",
-"www",
-"wxa",
-"wxw",
-"wya",
-"wyb",
-"wyi",
-"wym",
-"wyr",
-"wyy",
-"xaa",
-"xab",
-"xac",
-"xad",
-"xae",
-"xag",
-"xai",
-"xaj",
-"xak",
-"xal",
-"xam",
-"xan",
-"xao",
-"xap",
-"xaq",
-"xar",
-"xas",
-"xat",
-"xau",
-"xav",
-"xaw",
-"xay",
-"xba",
-"xbb",
-"xbc",
-"xbd",
-"xbe",
-"xbg",
-"xbi",
-"xbj",
-"xbm",
-"xbn",
-"xbo",
-"xbp",
-"xbr",
-"xbw",
-"xbx",
-"xby",
-"xcb",
-"xcc",
-"xce",
-"xcg",
-"xch",
-"xcl",
-"xcm",
-"xcn",
-"xco",
-"xcr",
-"xct",
-"xcu",
-"xcv",
-"xcw",
-"xcy",
-"xda",
-"xdc",
-"xdk",
-"xdm",
-"xdo",
-"xdy",
-"xeb",
-"xed",
-"xeg",
-"xel",
-"xem",
-"xep",
-"xer",
-"xes",
-"xet",
-"xeu",
-"xfa",
-"xga",
-"xgb",
-"xgd",
-"xgf",
-"xgg",
-"xgi",
-"xgl",
-"xgm",
-"xgn",
-"xgr",
-"xgu",
-"xgw",
-"xha",
-"xhc",
-"xhd",
-"xhe",
-"xhr",
-"xht",
-"xhu",
-"xhv",
-"xia",
-"xib",
-"xii",
-"xil",
-"xin",
-"xip",
-"xir",
-"xis",
-"xiv",
-"xiy",
-"xjb",
-"xjt",
-"xka",
-"xkb",
-"xkc",
-"xkd",
-"xke",
-"xkf",
-"xkg",
-"xkh",
-"xki",
-"xkj",
-"xkk",
-"xkl",
-"xkn",
-"xko",
-"xkp",
-"xkq",
-"xkr",
-"xks",
-"xkt",
-"xku",
-"xkv",
-"xkw",
-"xkx",
-"xky",
-"xkz",
-"xla",
-"xlb",
-"xlc",
-"xld",
-"xle",
-"xlg",
-"xli",
-"xln",
-"xlo",
-"xlp",
-"xls",
-"xlu",
-"xly",
-"xma",
-"xmb",
-"xmc",
-"xmd",
-"xme",
-"xmf",
-"xmg",
-"xmh",
-"xmj",
-"xmk",
-"xml",
-"xmm",
-"xmn",
-"xmo",
-"xmp",
-"xmq",
-"xmr",
-"xms",
-"xmt",
-"xmu",
-"xmv",
-"xmw",
-"xmx",
-"xmy",
-"xmz",
-"xna",
-"xnb",
-"xnd",
-"xng",
-"xnh",
-"xni",
-"xnk",
-"xnn",
-"xno",
-"xnr",
-"xns",
-"xnt",
-"xnu",
-"xny",
-"xnz",
-"xoc",
-"xod",
-"xog",
-"xoi",
-"xok",
-"xom",
-"xon",
-"xoo",
-"xop",
-"xor",
-"xow",
-"xpa",
-"xpc",
-"xpe",
-"xpg",
-"xpi",
-"xpj",
-"xpk",
-"xpm",
-"xpn",
-"xpo",
-"xpp",
-"xpq",
-"xpr",
-"xps",
-"xpt",
-"xpu",
-"xpy",
-"xqa",
-"xqt",
-"xra",
-"xrb",
-"xrd",
-"xre",
-"xrg",
-"xri",
-"xrm",
-"xrn",
-"xrq",
-"xrr",
-"xrt",
-"xru",
-"xrw",
-"xsa",
-"xsb",
-"xsc",
-"xsd",
-"xse",
-"xsh",
-"xsi",
-"xsj",
-"xsl",
-"xsm",
-"xsn",
-"xso",
-"xsp",
-"xsq",
-"xsr",
-"xss",
-"xsu",
-"xsv",
-"xsy",
-"xta",
-"xtb",
-"xtc",
-"xtd",
-"xte",
-"xtg",
-"xth",
-"xti",
-"xtj",
-"xtl",
-"xtm",
-"xtn",
-"xto",
-"xtp",
-"xtq",
-"xtr",
-"xts",
-"xtt",
-"xtu",
-"xtv",
-"xtw",
-"xty",
-"xtz",
-"xua",
-"xub",
-"xud",
-"xug",
-"xuj",
-"xul",
-"xum",
-"xun",
-"xuo",
-"xup",
-"xur",
-"xut",
-"xuu",
-"xve",
-"xvi",
-"xvn",
-"xvo",
-"xvs",
-"xwa",
-"xwc",
-"xwd",
-"xwe",
-"xwg",
-"xwj",
-"xwk",
-"xwl",
-"xwo",
-"xwr",
-"xwt",
-"xww",
-"xxb",
-"xxk",
-"xxm",
-"xxr",
-"xxt",
-"xya",
-"xyb",
-"xyj",
-"xyk",
-"xyl",
-"xyt",
-"xyy",
-"xzh",
-"xzm",
-"xzp",
-"yaa",
-"yab",
-"yac",
-"yad",
-"yae",
-"yaf",
-"yag",
-"yah",
-"yai",
-"yaj",
-"yak",
-"yal",
-"yam",
-"yan",
-"yao",
-"yap",
-"yaq",
-"yar",
-"yas",
-"yat",
-"yau",
-"yav",
-"yaw",
-"yax",
-"yay",
-"yaz",
-"yba",
-"ybb",
-"ybd",
-"ybe",
-"ybh",
-"ybi",
-"ybj",
-"ybk",
-"ybl",
-"ybm",
-"ybn",
-"ybo",
-"ybx",
-"yby",
-"ych",
-"ycl",
-"ycn",
-"ycp",
-"yda",
-"ydd",
-"yde",
-"ydg",
-"ydk",
-"yds",
-"yea",
-"yec",
-"yee",
-"yei",
-"yej",
-"yel",
-"yen",
-"yer",
-"yes",
-"yet",
-"yeu",
-"yev",
-"yey",
-"yga",
-"ygi",
-"ygl",
-"ygm",
-"ygp",
-"ygr",
-"ygs",
-"ygu",
-"ygw",
-"yha",
-"yhd",
-"yhl",
-"yhs",
-"yia",
-"yif",
-"yig",
-"yih",
-"yii",
-"yij",
-"yik",
-"yil",
-"yim",
-"yin",
-"yip",
-"yiq",
-"yir",
-"yis",
-"yit",
-"yiu",
-"yiv",
-"yix",
-"yiy",
-"yiz",
-"yka",
-"ykg",
-"yki",
-"ykk",
-"ykl",
-"ykm",
-"ykn",
-"yko",
-"ykr",
-"ykt",
-"yku",
-"yky",
-"yla",
-"ylb",
-"yle",
-"ylg",
-"yli",
-"yll",
-"ylm",
-"yln",
-"ylo",
-"ylr",
-"ylu",
-"yly",
-"yma",
-"ymb",
-"ymc",
-"ymd",
-"yme",
-"ymg",
-"ymh",
-"ymi",
-"ymk",
-"yml",
-"ymm",
-"ymn",
-"ymo",
-"ymp",
-"ymq",
-"ymr",
-"yms",
-"ymt",
-"ymx",
-"ymz",
-"yna",
-"ynd",
-"yne",
-"yng",
-"ynh",
-"ynk",
-"ynl",
-"ynn",
-"yno",
-"ynq",
-"yns",
-"ynu",
-"yob",
-"yog",
-"yoi",
-"yok",
-"yol",
-"yom",
-"yon",
-"yos",
-"yot",
-"yox",
-"yoy",
-"ypa",
-"ypb",
-"ypg",
-"yph",
-"ypk",
-"ypm",
-"ypn",
-"ypo",
-"ypp",
-"ypz",
-"yra",
-"yrb",
-"yre",
-"yri",
-"yrk",
-"yrl",
-"yrm",
-"yrn",
-"yro",
-"yrs",
-"yrw",
-"yry",
-"ysc",
-"ysd",
-"ysg",
-"ysl",
-"ysn",
-"yso",
-"ysp",
-"ysr",
-"yss",
-"ysy",
-"yta",
-"ytl",
-"ytp",
-"ytw",
-"yty",
-"yua",
-"yub",
-"yuc",
-"yud",
-"yue",
-"yuf",
-"yug",
-"yui",
-"yuj",
-"yuk",
-"yul",
-"yum",
-"yun",
-"yup",
-"yuq",
-"yur",
-"yut",
-"yuu",
-"yuw",
-"yux",
-"yuy",
-"yuz",
-"yva",
-"yvt",
-"ywa",
-"ywg",
-"ywl",
-"ywn",
-"ywq",
-"ywr",
-"ywt",
-"ywu",
-"yww",
-"yxa",
-"yxg",
-"yxl",
-"yxm",
-"yxu",
-"yxy",
-"yyr",
-"yyu",
-"yyz",
-"yzg",
-"yzk",
-"zaa",
-"zab",
-"zac",
-"zad",
-"zae",
-"zaf",
-"zag",
-"zah",
-"zai",
-"zaj",
-"zak",
-"zal",
-"zam",
-"zao",
-"zap",
-"zaq",
-"zar",
-"zas",
-"zat",
-"zau",
-"zav",
-"zaw",
-"zax",
-"zay",
-"zaz",
-"zbc",
-"zbe",
-"zbl",
-"zbt",
-"zbw",
-"zca",
-"zch",
-"zdj",
-"zea",
-"zeg",
-"zeh",
-"zen",
-"zga",
-"zgb",
-"zgh",
-"zgm",
-"zgn",
-"zgr",
-"zhb",
-"zhd",
-"zhi",
-"zhn",
-"zhw",
-"zhx",
-"zia",
-"zib",
-"zik",
-"zil",
-"zim",
-"zin",
-"zir",
-"ziw",
-"ziz",
-"zka",
-"zkb",
-"zkd",
-"zkg",
-"zkh",
-"zkk",
-"zkn",
-"zko",
-"zkp",
-"zkr",
-"zkt",
-"zku",
-"zkv",
-"zkz",
-"zle",
-"zlj",
-"zlm",
-"zln",
-"zlq",
-"zls",
-"zlw",
-"zma",
-"zmb",
-"zmc",
-"zmd",
-"zme",
-"zmf",
-"zmg",
-"zmh",
-"zmi",
-"zmj",
-"zmk",
-"zml",
-"zmm",
-"zmn",
-"zmo",
-"zmp",
-"zmq",
-"zmr",
-"zms",
-"zmt",
-"zmu",
-"zmv",
-"zmw",
-"zmx",
-"zmy",
-"zmz",
-"zna",
-"znd",
-"zne",
-"zng",
-"znk",
-"zns",
-"zoc",
-"zoh",
-"zom",
-"zoo",
-"zoq",
-"zor",
-"zos",
-"zpa",
-"zpb",
-"zpc",
-"zpd",
-"zpe",
-"zpf",
-"zpg",
-"zph",
-"zpi",
-"zpj",
-"zpk",
-"zpl",
-"zpm",
-"zpn",
-"zpo",
-"zpp",
-"zpq",
-"zpr",
-"zps",
-"zpt",
-"zpu",
-"zpv",
-"zpw",
-"zpx",
-"zpy",
-"zpz",
-"zqe",
-"zra",
-"zrg",
-"zrn",
-"zro",
-"zrp",
-"zrs",
-"zsa",
-"zsk",
-"zsl",
-"zsm",
-"zsr",
-"zsu",
-"zte",
-"ztg",
-"ztl",
-"ztm",
-"ztn",
-"ztp",
-"ztq",
-"zts",
-"ztt",
-"ztu",
-"ztx",
-"zty",
-"zua",
-"zuh",
-"zum",
-"zun",
-"zuy",
-"zwa",
-"zxx",
-"zyb",
-"zyg",
-"zyj",
-"zyn",
-"zyp",
-"zza",
-"zzj"];
-
-
-
-
-
-
-
-
-
-axe.utils.validLangs=function(){
-'use strict';
-return langs;
-};
-
-},{}],153:[function(require,module,exports){
-
-
-
-
-
-
-SDK.CSSMatchedStyles=class{
-
-
-
-
-
-
-
-
-
-
-constructor(
-cssModel,
-node,
-inlinePayload,
-attributesPayload,
-matchedPayload,
-pseudoPayload,
-inheritedPayload,
-animationsPayload){
-this._cssModel=cssModel;
-this._node=node;
-
-this._addedStyles=new Map();
-
-this._matchingSelectors=new Map();
-this._keyframes=[];
-if(animationsPayload)
-this._keyframes=animationsPayload.map(rule=>new SDK.CSSKeyframesRule(cssModel,rule));
-
-
-this._nodeForStyle=new Map();
-
-this._inheritedStyles=new Set();
-this._mainDOMCascade=this._buildMainCascade(inlinePayload,attributesPayload,matchedPayload,inheritedPayload);
-this._pseudoDOMCascades=this._buildPseudoCascades(pseudoPayload);
-
-
-this._styleToDOMCascade=new Map();
-for(const domCascade of Array.from(this._pseudoDOMCascades.values()).concat(this._mainDOMCascade)){
-for(const style of domCascade.styles())
-this._styleToDOMCascade.set(style,domCascade);
-}
-}
-
-
-
-
-
-
-
-
-_buildMainCascade(inlinePayload,attributesPayload,matchedPayload,inheritedPayload){
-
-const nodeCascades=[];
-
-
-const nodeStyles=[];
-
-
-
-
-function addAttributesStyle(){
-if(!attributesPayload)
-return;
-const style=
-new SDK.CSSStyleDeclaration(this._cssModel,null,attributesPayload,SDK.CSSStyleDeclaration.Type.Attributes);
-this._nodeForStyle.set(style,this._node);
-nodeStyles.push(style);
-}
-
-
-if(inlinePayload&&this._node.nodeType()===Node.ELEMENT_NODE){
-const style=
-new SDK.CSSStyleDeclaration(this._cssModel,null,inlinePayload,SDK.CSSStyleDeclaration.Type.Inline);
-this._nodeForStyle.set(style,this._node);
-nodeStyles.push(style);
-}
-
-
-let addedAttributesStyle;
-for(let i=matchedPayload.length-1;i>=0;--i){
-const rule=new SDK.CSSStyleRule(this._cssModel,matchedPayload[i].rule);
-if((rule.isInjected()||rule.isUserAgent())&&!addedAttributesStyle){
-
-addedAttributesStyle=true;
-addAttributesStyle.call(this);
-}
-this._nodeForStyle.set(rule.style,this._node);
-nodeStyles.push(rule.style);
-this._addMatchingSelectors(this._node,rule,matchedPayload[i].matchingSelectors);
-}
-
-if(!addedAttributesStyle)
-addAttributesStyle.call(this);
-nodeCascades.push(new SDK.CSSMatchedStyles.NodeCascade(this,nodeStyles,false));
-
-
-let parentNode=this._node.parentNode;
-for(let i=0;parentNode&&inheritedPayload&&i<inheritedPayload.length;++i){
-const inheritedStyles=[];
-const entryPayload=inheritedPayload[i];
-const inheritedInlineStyle=entryPayload.inlineStyle?
-new SDK.CSSStyleDeclaration(
-this._cssModel,null,entryPayload.inlineStyle,SDK.CSSStyleDeclaration.Type.Inline):
-null;
-if(inheritedInlineStyle&&this._containsInherited(inheritedInlineStyle)){
-this._nodeForStyle.set(inheritedInlineStyle,parentNode);
-inheritedStyles.push(inheritedInlineStyle);
-this._inheritedStyles.add(inheritedInlineStyle);
-}
-
-const inheritedMatchedCSSRules=entryPayload.matchedCSSRules||[];
-for(let j=inheritedMatchedCSSRules.length-1;j>=0;--j){
-const inheritedRule=new SDK.CSSStyleRule(this._cssModel,inheritedMatchedCSSRules[j].rule);
-this._addMatchingSelectors(parentNode,inheritedRule,inheritedMatchedCSSRules[j].matchingSelectors);
-if(!this._containsInherited(inheritedRule.style))
-continue;
-this._nodeForStyle.set(inheritedRule.style,parentNode);
-inheritedStyles.push(inheritedRule.style);
-this._inheritedStyles.add(inheritedRule.style);
-}
-parentNode=parentNode.parentNode;
-nodeCascades.push(new SDK.CSSMatchedStyles.NodeCascade(this,inheritedStyles,true));
-}
-
-return new SDK.CSSMatchedStyles.DOMInheritanceCascade(nodeCascades);
-}
-
-
-
-
-
-_buildPseudoCascades(pseudoPayload){
-
-const pseudoCascades=new Map();
-if(!pseudoPayload)
-return pseudoCascades;
-for(let i=0;i<pseudoPayload.length;++i){
-const entryPayload=pseudoPayload[i];
-
-const pseudoElement=this._node.pseudoElements().get(entryPayload.pseudoType)||null;
-const pseudoStyles=[];
-const rules=entryPayload.matches||[];
-for(let j=rules.length-1;j>=0;--j){
-const pseudoRule=new SDK.CSSStyleRule(this._cssModel,rules[j].rule);
-pseudoStyles.push(pseudoRule.style);
-this._nodeForStyle.set(pseudoRule.style,pseudoElement);
-if(pseudoElement)
-this._addMatchingSelectors(pseudoElement,pseudoRule,rules[j].matchingSelectors);
-}
-const nodeCascade=new SDK.CSSMatchedStyles.NodeCascade(this,pseudoStyles,false);
-pseudoCascades.set(entryPayload.pseudoType,new SDK.CSSMatchedStyles.DOMInheritanceCascade([nodeCascade]));
-}
-return pseudoCascades;
-}
-
-
-
-
-
-
-
-_addMatchingSelectors(node,rule,matchingSelectorIndices){
-for(const matchingSelectorIndex of matchingSelectorIndices){
-const selector=rule.selectors[matchingSelectorIndex];
-this._setSelectorMatches(node,selector.text,true);
-}
-}
-
-
-
-
-node(){
-return this._node;
-}
-
-
-
-
-cssModel(){
-return this._cssModel;
-}
-
-
-
-
-
-hasMatchingSelectors(rule){
-const matchingSelectors=this.matchingSelectors(rule);
-return matchingSelectors.length>0&&this.mediaMatches(rule.style);
-}
-
-
-
-
-
-matchingSelectors(rule){
-const node=this.nodeForStyle(rule.style);
-if(!node)
-return[];
-const map=this._matchingSelectors.get(node.id);
-if(!map)
-return[];
-const result=[];
-for(let i=0;i<rule.selectors.length;++i){
-if(map.get(rule.selectors[i].text))
-result.push(i);
-}
-return result;
-}
-
-
-
-
-
-recomputeMatchingSelectors(rule){
-const node=this.nodeForStyle(rule.style);
-if(!node)
-return Promise.resolve();
-const promises=[];
-for(const selector of rule.selectors)
-promises.push(querySelector.call(this,node,selector.text));
-return Promise.all(promises);
-
-
-
-
-
-
-async function querySelector(node,selectorText){
-const ownerDocument=node.ownerDocument||null;
-
-
-const map=this._matchingSelectors.get(node.id);
-if(map&&map.has(selectorText)||!ownerDocument)
-return;
-
-const matchingNodeIds=await this._node.domModel().querySelectorAll(ownerDocument.id,selectorText);
-
-if(matchingNodeIds)
-this._setSelectorMatches(node,selectorText,matchingNodeIds.indexOf(node.id)!==-1);
-}
-}
-
-
-
-
-
-
-addNewRule(rule,node){
-this._addedStyles.set(rule.style,node);
-return this.recomputeMatchingSelectors(rule);
-}
-
-
-
-
-
-
-_setSelectorMatches(node,selectorText,value){
-let map=this._matchingSelectors.get(node.id);
-if(!map){
-map=new Map();
-this._matchingSelectors.set(node.id,map);
-}
-map.set(selectorText,value);
-}
-
-
-
-
-
-mediaMatches(style){
-const media=style.parentRule?style.parentRule.media:[];
-for(let i=0;media&&i<media.length;++i){
-if(!media[i].active())
-return false;
-}
-return true;
-}
-
-
-
-
-nodeStyles(){
-return this._mainDOMCascade.styles();
-}
-
-
-
-
-keyframes(){
-return this._keyframes;
-}
-
-
-
-
-
-pseudoStyles(pseudoType){
-const domCascade=this._pseudoDOMCascades.get(pseudoType);
-return domCascade?domCascade.styles():[];
-}
-
-
-
-
-pseudoTypes(){
-return new Set(this._pseudoDOMCascades.keys());
-}
-
-
-
-
-
-_containsInherited(style){
-const properties=style.allProperties();
-for(let i=0;i<properties.length;++i){
-const property=properties[i];
-
-if(property.activeInStyle()&&SDK.cssMetadata().isPropertyInherited(property.name))
-return true;
-}
-return false;
-}
-
-
-
-
-
-nodeForStyle(style){
-return this._addedStyles.get(style)||this._nodeForStyle.get(style)||null;
-}
-
-
-
-
-
-availableCSSVariables(style){
-const domCascade=this._styleToDOMCascade.get(style)||null;
-return domCascade?domCascade.availableCSSVariables(style):[];
-}
-
-
-
-
-
-
-computeCSSVariable(style,variableName){
-const domCascade=this._styleToDOMCascade.get(style)||null;
-return domCascade?domCascade.computeCSSVariable(style,variableName):null;
-}
-
-
-
-
-
-
-computeValue(style,value){
-const domCascade=this._styleToDOMCascade.get(style)||null;
-return domCascade?domCascade.computeValue(style,value):null;
-}
-
-
-
-
-
-isInherited(style){
-return this._inheritedStyles.has(style);
-}
-
-
-
-
-
-propertyState(property){
-const domCascade=this._styleToDOMCascade.get(property.ownerStyle);
-return domCascade?domCascade.propertyState(property):null;
-}
-
-resetActiveProperties(){
-this._mainDOMCascade.reset();
-for(const domCascade of this._pseudoDOMCascades.values())
-domCascade.reset();
-}};
-
-
-SDK.CSSMatchedStyles.NodeCascade=class{
-
-
-
-
-
-constructor(matchedStyles,styles,isInherited){
-this._matchedStyles=matchedStyles;
-this._styles=styles;
-this._isInherited=isInherited;
-
-this._propertiesState=new Map();
-
-this._activeProperties=new Map();
-}
-
-_computeActiveProperties(){
-this._propertiesState.clear();
-this._activeProperties.clear();
-
-for(const style of this._styles){
-const rule=style.parentRule;
-
-if(rule&&!(rule instanceof SDK.CSSStyleRule))
-continue;
-if(rule&&!this._matchedStyles.hasMatchingSelectors(rule))
-continue;
-
-for(const property of style.allProperties()){
-
-if(this._isInherited&&!SDK.cssMetadata().isPropertyInherited(property.name))
-continue;
-
-if(!property.activeInStyle()){
-this._propertiesState.set(property,SDK.CSSMatchedStyles.PropertyState.Overloaded);
-continue;
-}
-
-const canonicalName=SDK.cssMetadata().canonicalPropertyName(property.name);
-const activeProperty=this._activeProperties.get(canonicalName);
-if(activeProperty&&(activeProperty.important||!property.important)){
-this._propertiesState.set(property,SDK.CSSMatchedStyles.PropertyState.Overloaded);
-continue;
-}
-
-if(activeProperty)
-this._propertiesState.set(activeProperty,SDK.CSSMatchedStyles.PropertyState.Overloaded);
-this._propertiesState.set(property,SDK.CSSMatchedStyles.PropertyState.Active);
-this._activeProperties.set(canonicalName,property);
-}
-}
-}};
-
-
-SDK.CSSMatchedStyles.DOMInheritanceCascade=class{
-
-
-
-constructor(nodeCascades){
-this._nodeCascades=nodeCascades;
-
-this._propertiesState=new Map();
-
-this._availableCSSVariables=new Map();
-
-this._computedCSSVariables=new Map();
-this._initialized=false;
-
-
-this._styleToNodeCascade=new Map();
-for(const nodeCascade of nodeCascades){
-for(const style of nodeCascade._styles)
-this._styleToNodeCascade.set(style,nodeCascade);
-}
-}
-
-
-
-
-
-availableCSSVariables(style){
-const nodeCascade=this._styleToNodeCascade.get(style);
-if(!nodeCascade)
-return[];
-this._ensureInitialized();
-return Array.from(this._availableCSSVariables.get(nodeCascade).keys());
-}
-
-
-
-
-
-
-computeCSSVariable(style,variableName){
-const nodeCascade=this._styleToNodeCascade.get(style);
-if(!nodeCascade)
-return null;
-this._ensureInitialized();
-const availableCSSVariables=this._availableCSSVariables.get(nodeCascade);
-const computedCSSVariables=this._computedCSSVariables.get(nodeCascade);
-return this._innerComputeCSSVariable(availableCSSVariables,computedCSSVariables,variableName);
-}
-
-
-
-
-
-
-computeValue(style,value){
-const nodeCascade=this._styleToNodeCascade.get(style);
-if(!nodeCascade)
-return null;
-this._ensureInitialized();
-const availableCSSVariables=this._availableCSSVariables.get(nodeCascade);
-const computedCSSVariables=this._computedCSSVariables.get(nodeCascade);
-return this._innerComputeValue(availableCSSVariables,computedCSSVariables,value);
-}
-
-
-
-
-
-
-
-_innerComputeCSSVariable(availableCSSVariables,computedCSSVariables,variableName){
-if(!availableCSSVariables.has(variableName))
-return null;
-if(computedCSSVariables.has(variableName))
-return computedCSSVariables.get(variableName);
-
-computedCSSVariables.set(variableName,null);
-const definedValue=availableCSSVariables.get(variableName);
-const computedValue=this._innerComputeValue(availableCSSVariables,computedCSSVariables,definedValue);
-computedCSSVariables.set(variableName,computedValue);
-return computedValue;
-}
-
-
-
-
-
-
-
-_innerComputeValue(availableCSSVariables,computedCSSVariables,value){
-const results=TextUtils.TextUtils.splitStringByRegexes(value,[SDK.CSSMetadata.VariableRegex]);
-const tokens=[];
-for(const result of results){
-if(result.regexIndex===-1){
-tokens.push(result.value);
-continue;
-}
-
-const regexMatch=result.value.match(/^var\((--[a-zA-Z0-9-_]+)[,]?\s*(.*)\)$/);
-if(!regexMatch)
-return null;
-const cssVariable=regexMatch[1];
-const computedValue=this._innerComputeCSSVariable(availableCSSVariables,computedCSSVariables,cssVariable);
-if(computedValue===null&&!regexMatch[2])
-return null;
-if(computedValue===null)
-tokens.push(regexMatch[2]);else
-
-tokens.push(computedValue);
-}
-return tokens.map(token=>token.trim()).join(' ');
-}
-
-
-
-
-styles(){
-return Array.from(this._styleToNodeCascade.keys());
-}
-
-
-
-
-
-propertyState(property){
-this._ensureInitialized();
-return this._propertiesState.get(property)||null;
-}
-
-reset(){
-this._initialized=false;
-this._propertiesState.clear();
-this._availableCSSVariables.clear();
-this._computedCSSVariables.clear();
-}
-
-_ensureInitialized(){
-if(this._initialized)
-return;
-this._initialized=true;
-
-const activeProperties=new Map();
-for(const nodeCascade of this._nodeCascades){
-nodeCascade._computeActiveProperties();
-for(const entry of nodeCascade._propertiesState.entries()){
-const property=entry[0];
-const state=entry[1];
-if(state===SDK.CSSMatchedStyles.PropertyState.Overloaded){
-this._propertiesState.set(property,SDK.CSSMatchedStyles.PropertyState.Overloaded);
-continue;
-}
-const canonicalName=SDK.cssMetadata().canonicalPropertyName(property.name);
-if(activeProperties.has(canonicalName)){
-this._propertiesState.set(property,SDK.CSSMatchedStyles.PropertyState.Overloaded);
-continue;
-}
-activeProperties.set(canonicalName,property);
-this._propertiesState.set(property,SDK.CSSMatchedStyles.PropertyState.Active);
-}
-}
-
-for(const entry of activeProperties.entries()){
-const canonicalName=entry[0];
-const shorthandProperty=entry[1];
-const shorthandStyle=shorthandProperty.ownerStyle;
-const longhands=shorthandStyle.longhandProperties(shorthandProperty.name);
-if(!longhands.length)
-continue;
-let hasActiveLonghands=false;
-for(const longhand of longhands){
-const longhandCanonicalName=SDK.cssMetadata().canonicalPropertyName(longhand.name);
-const longhandActiveProperty=activeProperties.get(longhandCanonicalName);
-if(!longhandActiveProperty)
-continue;
-if(longhandActiveProperty.ownerStyle===shorthandStyle){
-hasActiveLonghands=true;
-break;
-}
-}
-if(hasActiveLonghands)
-continue;
-activeProperties.delete(canonicalName);
-this._propertiesState.set(shorthandProperty,SDK.CSSMatchedStyles.PropertyState.Overloaded);
-}
-
-
-const accumulatedCSSVariables=new Map();
-for(let i=this._nodeCascades.length-1;i>=0;--i){
-const nodeCascade=this._nodeCascades[i];
-for(const entry of nodeCascade._activeProperties.entries()){
-const propertyName=entry[0];
-const property=entry[1];
-if(propertyName.startsWith('--'))
-accumulatedCSSVariables.set(propertyName,property.value);
-}
-this._availableCSSVariables.set(nodeCascade,new Map(accumulatedCSSVariables));
-this._computedCSSVariables.set(nodeCascade,new Map());
-}
-}};
-
-
-
-SDK.CSSMatchedStyles.PropertyState={
-Active:'Active',
-Overloaded:'Overloaded'};
-
-
-},{}],154:[function(require,module,exports){
-
-
-
-
-
-
-SDK.CSSMediaQuery=class{
-
-
-
-constructor(payload){
-this._active=payload.active;
-this._expressions=[];
-for(let j=0;j<payload.expressions.length;++j)
-this._expressions.push(SDK.CSSMediaQueryExpression.parsePayload(payload.expressions[j]));
-}
-
-
-
-
-
-static parsePayload(payload){
-return new SDK.CSSMediaQuery(payload);
-}
-
-
-
-
-active(){
-return this._active;
-}
-
-
-
-
-expressions(){
-return this._expressions;
-}};
-
-
-
-
-
-
-SDK.CSSMediaQueryExpression=class{
-
-
-
-constructor(payload){
-this._value=payload.value;
-this._unit=payload.unit;
-this._feature=payload.feature;
-this._valueRange=payload.valueRange?TextUtils.TextRange.fromObject(payload.valueRange):null;
-this._computedLength=payload.computedLength||null;
-}
-
-
-
-
-
-static parsePayload(payload){
-return new SDK.CSSMediaQueryExpression(payload);
-}
-
-
-
-
-value(){
-return this._value;
-}
-
-
-
-
-unit(){
-return this._unit;
-}
-
-
-
-
-feature(){
-return this._feature;
-}
-
-
-
-
-valueRange(){
-return this._valueRange;
-}
-
-
-
-
-computedLength(){
-return this._computedLength;
-}};
-
-
-
-
-
-
-SDK.CSSMedia=class{
-
-
-
-
-constructor(cssModel,payload){
-this._cssModel=cssModel;
-this._reinitialize(payload);
-}
-
-
-
-
-
-
-static parsePayload(cssModel,payload){
-return new SDK.CSSMedia(cssModel,payload);
-}
-
-
-
-
-
-
-static parseMediaArrayPayload(cssModel,payload){
-const result=[];
-for(let i=0;i<payload.length;++i)
-result.push(SDK.CSSMedia.parsePayload(cssModel,payload[i]));
-return result;
-}
-
-
-
-
-_reinitialize(payload){
-this.text=payload.text;
-this.source=payload.source;
-this.sourceURL=payload.sourceURL||'';
-this.range=payload.range?TextUtils.TextRange.fromObject(payload.range):null;
-this.styleSheetId=payload.styleSheetId;
-this.mediaList=null;
-if(payload.mediaList){
-this.mediaList=[];
-for(let i=0;i<payload.mediaList.length;++i)
-this.mediaList.push(SDK.CSSMediaQuery.parsePayload(payload.mediaList[i]));
-}
-}
-
-
-
-
-rebase(edit){
-if(this.styleSheetId!==edit.styleSheetId||!this.range)
-return;
-if(edit.oldRange.equal(this.range))
-this._reinitialize(edit.payload);else
-
-this.range=this.range.rebaseAfterTextEdit(edit.oldRange,edit.newRange);
-}
-
-
-
-
-
-equal(other){
-if(!this.styleSheetId||!this.range||!other.range)
-return false;
-return this.styleSheetId===other.styleSheetId&&this.range.equal(other.range);
-}
-
-
-
-
-active(){
-if(!this.mediaList)
-return true;
-for(let i=0;i<this.mediaList.length;++i){
-if(this.mediaList[i].active())
-return true;
-}
-return false;
-}
-
-
-
-
-lineNumberInSource(){
-if(!this.range)
-return undefined;
-const header=this.header();
-if(!header)
-return undefined;
-return header.lineNumberInSource(this.range.startLine);
-}
-
-
-
-
-columnNumberInSource(){
-if(!this.range)
-return undefined;
-const header=this.header();
-if(!header)
-return undefined;
-return header.columnNumberInSource(this.range.startLine,this.range.startColumn);
-}
-
-
-
-
-header(){
-return this.styleSheetId?this._cssModel.styleSheetHeaderForId(this.styleSheetId):null;
-}
-
-
-
-
-rawLocation(){
-const header=this.header();
-if(!header||this.lineNumberInSource()===undefined)
-return null;
-const lineNumber=Number(this.lineNumberInSource());
-return new SDK.CSSLocation(header,lineNumber,this.columnNumberInSource());
-}};
-
-
-SDK.CSSMedia.Source={
-LINKED_SHEET:'linkedSheet',
-INLINE_SHEET:'inlineSheet',
-MEDIA_RULE:'mediaRule',
-IMPORT_RULE:'importRule'};
-
-
-},{}],155:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-SDK.CSSMetadata=class{
-
-
-
-constructor(properties){
-this._values=[];
-
-this._longhands=new Map();
-
-this._shorthands=new Map();
-
-this._inherited=new Set();
-
-this._svgProperties=new Set();
-for(let i=0;i<properties.length;++i){
-const property=properties[i];
-const propertyName=property.name;
-if(!CSS.supports(propertyName,'initial'))
-continue;
-this._values.push(propertyName);
-
-if(property.inherited)
-this._inherited.add(propertyName);
-if(property.svg)
-this._svgProperties.add(propertyName);
-
-const longhands=properties[i].longhands;
-if(longhands){
-this._longhands.set(propertyName,longhands);
-for(let j=0;j<longhands.length;++j){
-const longhandName=longhands[j];
-let shorthands=this._shorthands.get(longhandName);
-if(!shorthands){
-shorthands=[];
-this._shorthands.set(longhandName,shorthands);
-}
-shorthands.push(propertyName);
-}
-}
-}
-this._values.sort();
-this._valuesSet=new Set(this._values);
-}
-
-
-
-
-allProperties(){
-return this._values;
-}
-
-
-
-
-
-isSVGProperty(name){
-name=name.toLowerCase();
-return this._svgProperties.has(name);
-}
-
-
-
-
-
-longhands(shorthand){
-return this._longhands.get(shorthand)||null;
-}
-
-
-
-
-
-shorthands(longhand){
-return this._shorthands.get(longhand)||null;
-}
-
-
-
-
-
-isColorAwareProperty(propertyName){
-return!!SDK.CSSMetadata._colorAwareProperties.has(propertyName.toLowerCase())||
-this.isCustomProperty(propertyName.toLowerCase());
-}
-
-
-
-
-
-isLengthProperty(propertyName){
-propertyName=propertyName.toLowerCase();
-if(propertyName==='line-height')
-return false;
-return SDK.CSSMetadata._distanceProperties.has(propertyName)||propertyName.startsWith('margin')||
-propertyName.startsWith('padding')||propertyName.indexOf('width')!==-1||
-propertyName.indexOf('height')!==-1;
-}
-
-
-
-
-
-isBezierAwareProperty(propertyName){
-propertyName=propertyName.toLowerCase();
-return!!SDK.CSSMetadata._bezierAwareProperties.has(propertyName)||this.isCustomProperty(propertyName);
-}
-
-
-
-
-
-isCustomProperty(propertyName){
-return propertyName.startsWith('--');
-}
-
-
-
-
-
-canonicalPropertyName(name){
-name=name.toLowerCase();
-if(!name||name.length<9||name.charAt(0)!=='-')
-return name;
-const match=name.match(/(?:-webkit-)(.+)/);
-if(!match||!this._valuesSet.has(match[1]))
-return name;
-return match[1];
-}
-
-
-
-
-
-isCSSPropertyName(propertyName){
-propertyName=propertyName.toLowerCase();
-if(propertyName.startsWith('-moz-')||propertyName.startsWith('-o-')||propertyName.startsWith('-webkit-')||
-propertyName.startsWith('-ms-'))
-return true;
-return this._valuesSet.has(propertyName);
-}
-
-
-
-
-
-isPropertyInherited(propertyName){
-propertyName=propertyName.toLowerCase();
-return propertyName.startsWith('--')||this._inherited.has(this.canonicalPropertyName(propertyName))||
-this._inherited.has(propertyName);
-}
-
-
-
-
-
-propertyValues(propertyName){
-const acceptedKeywords=['inherit','initial','unset'];
-propertyName=propertyName.toLowerCase();
-const unprefixedName=propertyName.replace(/^-webkit-/,'');
-const entry=SDK.CSSMetadata._propertyDataMap[propertyName]||SDK.CSSMetadata._propertyDataMap[unprefixedName];
-if(entry&&entry.values)
-acceptedKeywords.pushAll(entry.values);
-const commonKeywords=['auto','none'];
-for(const commonKeyword of commonKeywords){
-if(CSS.supports(propertyName,commonKeyword))
-acceptedKeywords.push(commonKeyword);
-}
-if(this.isColorAwareProperty(propertyName)){
-acceptedKeywords.push('currentColor');
-for(const color in Common.Color.Nicknames)
-acceptedKeywords.push(color);
-}
-return acceptedKeywords.sort();
-}
-
-
-
-
-
-propertyUsageWeight(property){
-return SDK.CSSMetadata.Weight[property]||SDK.CSSMetadata.Weight[this.canonicalPropertyName(property)]||0;
-}};
-
-
-SDK.CSSMetadata.VariableRegex=/(var\(--.*?\))/g;
-SDK.CSSMetadata.URLRegex=/url\(\s*('.+?'|".+?"|[^)]+)\s*\)/g;
-
-
-
-
-SDK.cssMetadata=function(){
-if(!SDK.CSSMetadata._instance)
-SDK.CSSMetadata._instance=new SDK.CSSMetadata(SDK.CSSMetadata._generatedProperties||[]);
-return SDK.CSSMetadata._instance;
-};
-
-SDK.CSSMetadata._distanceProperties=new Set([
-'background-position','border-spacing','bottom','font-size','height','left','letter-spacing','max-height',
-'max-width','min-height','min-width','right','text-indent','top','width','word-spacing','grid-row-gap',
-'grid-column-gap','row-gap']);
-
-
-SDK.CSSMetadata._bezierAwareProperties=new Set([
-'animation','animation-timing-function','transition','transition-timing-function','-webkit-animation',
-'-webkit-animation-timing-function','-webkit-transition','-webkit-transition-timing-function']);
-
-
-SDK.CSSMetadata._colorAwareProperties=new Set([
-'backdrop-filter',
-'background',
-'background-color',
-'background-image',
-'border',
-'border-color',
-'border-image',
-'border-image-source',
-'border-bottom',
-'border-bottom-color',
-'border-left',
-'border-left-color',
-'border-right',
-'border-right-color',
-'border-top',
-'border-top-color',
-'box-shadow',
-'caret-color',
-'color',
-'column-rule',
-'column-rule-color',
-'fill',
-'list-style',
-'list-style-image',
-'outline',
-'outline-color',
-'stroke',
-'text-decoration-color',
-'text-shadow',
-'-webkit-border-after',
-'-webkit-border-after-color',
-'-webkit-border-before',
-'-webkit-border-before-color',
-'-webkit-border-end',
-'-webkit-border-end-color',
-'-webkit-border-start',
-'-webkit-border-start-color',
-'-webkit-box-reflect',
-'-webkit-box-shadow',
-'-webkit-column-rule-color',
-'-webkit-filter',
-'-webkit-mask',
-'-webkit-mask-box-image',
-'-webkit-mask-box-image-source',
-'-webkit-mask-image',
-'-webkit-tap-highlight-color',
-'-webkit-text-decoration-color',
-'-webkit-text-emphasis',
-'-webkit-text-emphasis-color',
-'-webkit-text-fill-color',
-'-webkit-text-stroke',
-'-webkit-text-stroke-color']);
-
-
-SDK.CSSMetadata._propertyDataMap={
-'table-layout':{values:['fixed']},
-'visibility':{values:['hidden','visible','collapse']},
-'background-repeat':{values:['repeat','repeat-x','repeat-y','no-repeat','space','round']},
-'content':{values:['normal','close-quote','no-close-quote','no-open-quote','open-quote']},
-'clear':{values:['left','right','both']},
-'overflow-x':{values:['hidden','visible','overlay','scroll','-webkit-paged-x','-webkit-paged-y']},
-'stroke-linejoin':{values:['round','miter','bevel']},
-'baseline-shift':{values:['baseline','sub','super']},
-'border-bottom-width':{values:['medium','thick','thin']},
-'margin-top-collapse':{values:['collapse','separate','discard']},
-'max-height':{values:['min-content','max-content','-webkit-fill-available','fit-content']},
-'box-orient':{
-values:['horizontal','vertical','inline-axis','block-axis']},
-
-'font-stretch':{
-values:[
-'normal','ultra-condensed','extra-condensed','condensed','semi-condensed','semi-expanded','expanded',
-'extra-expanded','ultra-expanded']},
-
-
-'border-left-width':{values:['medium','thick','thin']},
-'box-shadow':{values:['inset']},
-'-webkit-writing-mode':{values:['horizontal-tb','vertical-rl','vertical-lr']},
-'writing-mode':
-{values:['lr','rl','tb','lr-tb','rl-tb','tb-rl','horizontal-tb','vertical-rl','vertical-lr']},
-'border-collapse':{values:['collapse','separate']},
-'page-break-inside':{values:['avoid']},
-'border-top-width':{values:['medium','thick','thin']},
-'outline-style':{values:['inset','groove','ridge','outset','dotted','dashed','solid','double','hidden']},
-'cursor':{
-values:[
-'copy',
-'crosshair',
-'default',
-'grab',
-'grabbing',
-'pointer',
-'move',
-'vertical-text',
-'cell',
-'context-menu',
-'alias',
-'progress',
-'no-drop',
-'not-allowed',
-'-webkit-zoom-in',
-'-webkit-zoom-out',
-'e-resize',
-'ne-resize',
-'nw-resize',
-'n-resize',
-'se-resize',
-'sw-resize',
-'s-resize',
-'w-resize',
-'ew-resize',
-'ns-resize',
-'nesw-resize',
-'nwse-resize',
-'col-resize',
-'row-resize',
-'text',
-'wait',
-'help',
-'all-scroll',
-'zoom-in',
-'zoom-out',
-'-webkit-grab',
-'-webkit-grabbing']},
-
-
-'border-width':{values:['medium','thick','thin']},
-'border-style':{values:['hidden','inset','groove','ridge','outset','dotted','dashed','solid','double']},
-'size':{values:['a3','a4','a5','b4','b5','landscape','ledger','legal','letter','portrait']},
-'background-size':{values:['contain','cover']},
-'direction':{values:['ltr','rtl']},
-'enable-background':{values:['accumulate','new']},
-'float':{values:['left','right']},
-'overflow-y':{values:['hidden','visible','overlay','scroll','-webkit-paged-x','-webkit-paged-y']},
-'margin-bottom-collapse':{values:['collapse','separate','discard']},
-'box-reflect':{values:['left','right','above','below']},
-'overflow':{values:['hidden','visible','overlay','scroll','-webkit-paged-x','-webkit-paged-y']},
-'overscroll-behavior':{values:['contain']},
-'overscroll-behavior-x':{values:['contain']},
-'overscroll-behavior-y':{values:['contain']},
-'contain':{values:['strict','content','size','layout','style','paint']},
-'text-rendering':{values:['optimizeSpeed','optimizeLegibility','geometricPrecision']},
-'text-align':{
-values:[
-'-webkit-auto','start','end','left','right','center','justify','-webkit-left','-webkit-right',
-'-webkit-center','-webkit-match-parent']},
-
-
-'list-style-position':{values:['outside','inside']},
-'color-interpolation':{values:['sRGB','linearRGB']},
-'background-origin':{values:['border-box','content-box','padding-box']},
-'word-wrap':{values:['normal','break-word']},
-'font-weight':
-{values:['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900']},
-'margin-before-collapse':{values:['collapse','separate','discard']},
-'text-transform':{values:['capitalize','uppercase','lowercase']},
-'border-right-style':
-{values:['hidden','inset','groove','ridge','outset','dotted','dashed','solid','double']},
-'border-left-style':
-{values:['hidden','inset','groove','ridge','outset','dotted','dashed','solid','double']},
-'-webkit-text-emphasis':{values:['circle','filled','open','dot','double-circle','triangle','sesame']},
-'font-style':{values:['italic','oblique','normal']},
-'speak':{values:['normal','spell-out','digits','literal-punctuation','no-punctuation']},
-'color-rendering':{values:['optimizeSpeed','optimizeQuality']},
-'list-style-type':{
-values:[
-'disc',
-'circle',
-'square',
-'decimal',
-'decimal-leading-zero',
-'arabic-indic',
-'bengali',
-'cambodian',
-'khmer',
-'devanagari',
-'gujarati',
-'gurmukhi',
-'kannada',
-'lao',
-'malayalam',
-'mongolian',
-'myanmar',
-'oriya',
-'persian',
-'urdu',
-'telugu',
-'tibetan',
-'thai',
-'lower-roman',
-'upper-roman',
-'lower-greek',
-'lower-alpha',
-'lower-latin',
-'upper-alpha',
-'upper-latin',
-'ethiopic-halehame',
-'ethiopic-halehame-am',
-'ethiopic-halehame-ti-er',
-'ethiopic-halehame-ti-et',
-'cjk-earthly-branch',
-'cjk-heavenly-stem',
-'hangul-consonant',
-'hangul',
-'korean-hangul-formal',
-'korean-hanja-formal',
-'korean-hanja-informal',
-'simp-chinese-formal',
-'simp-chinese-informal',
-'trad-chinese-formal',
-'trad-chinese-informal',
-'hebrew',
-'armenian',
-'lower-armenian',
-'upper-armenian',
-'georgian',
-'cjk-ideographic',
-'hiragana',
-'katakana',
-'hiragana-iroha',
-'katakana-iroha']},
-
-
-'text-combine-upright':{values:['all']},
-'-webkit-text-combine':{values:['horizontal']},
-'text-orientation':{values:['mixed','upright','sideways','sideways-right']},
-'outline':{
-values:['inset','groove','ridge','outset','dotted','dashed','solid','double','medium','thick','thin']},
-
-'font':{
-values:[
-'caption',
-'icon',
-'menu',
-'message-box',
-'small-caption',
-'-webkit-mini-control',
-'-webkit-small-control',
-'-webkit-control',
-'status-bar',
-'italic',
-'oblique',
-'small-caps',
-'normal',
-'bold',
-'bolder',
-'lighter',
-'100',
-'200',
-'300',
-'400',
-'500',
-'600',
-'700',
-'800',
-'900',
-'xx-small',
-'x-small',
-'small',
-'medium',
-'large',
-'x-large',
-'xx-large',
-'-webkit-xxx-large',
-'smaller',
-'larger',
-'serif',
-'sans-serif',
-'cursive',
-'fantasy',
-'monospace',
-'-webkit-body',
-'-webkit-pictograph']},
-
-
-'dominant-baseline':{
-values:[
-'middle','central','text-before-edge','text-after-edge','ideographic','alphabetic','hanging',
-'mathematical','use-script','no-change','reset-size']},
-
-
-'display':{
-values:[
-'inline',
-'block',
-'flow-root',
-'list-item',
-'inline-block',
-'table',
-'inline-table',
-'table-row-group',
-'table-header-group',
-'table-footer-group',
-'table-row',
-'table-column-group',
-'table-column',
-'table-cell',
-'table-caption',
-'-webkit-box',
-'-webkit-inline-box',
-'flex',
-'inline-flex',
-'grid',
-'inline-grid',
-'contents']},
-
-
-'-webkit-text-emphasis-position':{values:['over','under']},
-'image-rendering':{values:['pixelated','-webkit-optimize-contrast','optimizeSpeed','optimizeQuality']},
-'alignment-baseline':{
-values:[
-'baseline','middle','before-edge','after-edge','central','text-before-edge','text-after-edge',
-'ideographic','alphabetic','hanging','mathematical']},
-
-
-'outline-width':{values:['medium','thick','thin']},
-'box-align':{values:['baseline','center','stretch','start','end']},
-'border-right-width':{values:['medium','thick','thin']},
-'border-top-style':{values:['hidden','inset','groove','ridge','outset','dotted','dashed','solid','double']},
-'line-height':{values:['normal']},
-'text-overflow':{values:['clip','ellipsis']},
-'overflow-wrap':{values:['normal','break-word']},
-'box-direction':{values:['normal','reverse']},
-'margin-after-collapse':{values:['collapse','separate','discard']},
-'page-break-before':{values:['left','right','always','avoid']},
-'border-image':{values:['repeat','stretch','space','round']},
-'text-decoration':
-{values:['blink','line-through','overline','underline','wavy','double','solid','dashed','dotted']},
-'position':{values:['absolute','fixed','relative','static','sticky']},
-'font-family':
-{values:['serif','sans-serif','cursive','fantasy','monospace','-webkit-body','-webkit-pictograph']},
-'border-bottom-style':
-{values:['hidden','inset','groove','ridge','outset','dotted','dashed','solid','double']},
-'unicode-bidi':{values:['normal','bidi-override','embed','isolate','isolate-override','plaintext']},
-'clip-rule':{values:['nonzero','evenodd']},
-'zoom':{values:['normal']},
-'max-width':{values:['min-content','max-content','-webkit-fill-available','fit-content']},
-'caption-side':{values:['top','bottom']},
-'empty-cells':{values:['hide','show']},
-'pointer-events':{
-values:[
-'all','visible','visiblepainted','visiblefill','visiblestroke','painted','fill','stroke','bounding-box']},
-
-
-'letter-spacing':{values:['normal']},
-'background-clip':{values:['border-box','content-box','padding-box']},
-'-webkit-font-smoothing':{values:['antialiased','subpixel-antialiased']},
-'border':{
-values:[
-'hidden','inset','groove','ridge','outset','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'font-size':{
-values:[
-'xx-small','x-small','small','medium','large','x-large','xx-large','-webkit-xxx-large','smaller','larger']},
-
-
-'font-variant':{
-values:[
-'small-caps',
-'normal',
-'common-ligatures',
-'no-common-ligatures',
-'discretionary-ligatures',
-'no-discretionary-ligatures',
-'historical-ligatures',
-'no-historical-ligatures',
-'contextual',
-'no-contextual',
-'all-small-caps',
-'petite-caps',
-'all-petite-caps',
-'unicase',
-'titling-caps',
-'lining-nums',
-'oldstyle-nums',
-'proportional-nums',
-'tabular-nums',
-'diagonal-fractions',
-'stacked-fractions',
-'ordinal',
-'slashed-zero',
-'jis78',
-'jis83',
-'jis90',
-'jis04',
-'simplified',
-'traditional',
-'full-width',
-'proportional-width',
-'ruby']},
-
-
-'vertical-align':{
-values:
-['baseline','middle','sub','super','text-top','text-bottom','top','bottom','-webkit-baseline-middle']},
-
-'white-space':{values:['normal','nowrap','pre','pre-line','pre-wrap']},
-'page-break-after':{values:['left','right','always','avoid']},
-'word-break':{values:['normal','break-all','break-word','keep-all']},
-'word-spacing':{values:['normal']},
-'-webkit-text-emphasis-style':{values:['circle','filled','open','dot','double-circle','triangle','sesame']},
-'transform':{
-values:[
-'scale','scaleX','scaleY','scale3d','rotate','rotateX','rotateY',
-'rotateZ','rotate3d','skew','skewX','skewY','translate','translateX',
-'translateY','translateZ','translate3d','matrix','matrix3d','perspective']},
-
-
-'box-sizing':{values:['content-box','border-box']},
-'resize':{values:['both','horizontal','vertical']},
-'align-content':{
-values:[
-'normal','baseline','space-between','space-around','space-evenly','stretch','unsafe','safe','center',
-'start','end','flex-start','flex-end','left','right']},
-
-
-'justify-content':{
-values:[
-'normal','space-between','space-around','space-evenly','stretch','unsafe','safe','center','start','end',
-'flex-start','flex-end','left','right','baseline']},
-
-
-'place-content':{
-values:[
-'normal','space-between','space-around','space-evenly','stretch','unsafe','safe','center','start','end',
-'flex-start','flex-end','left','right','baseline']},
-
-
-'align-items':{
-values:[
-'normal','stretch','baseline','unsafe','safe','center','start','end','self-start','self-end',
-'flex-start','flex-end','left','right']},
-
-
-'justify-items':{
-values:[
-'normal','stretch','baseline','unsafe','safe','center','start','end','self-start','self-end',
-'flex-start','flex-end','left','right','legacy']},
-
-
-'place-items':{
-values:[
-'normal','stretch','baseline','unsafe','safe','center','start','end','self-start','self-end',
-'flex-start','flex-end','left','right']},
-
-
-'align-self':{
-values:[
-'normal','stretch','baseline','unsafe','safe','center','start','end','self-start','self-end',
-'flex-start','flex-end','left','right']},
-
-
-'justify-self':{
-values:[
-'normal','stretch','baseline','unsafe','safe','center','start','end','self-start','self-end',
-'flex-start','flex-end','left','right']},
-
-
-'place-self':{
-values:[
-'normal','stretch','baseline','unsafe','safe','center','start','end','self-start','self-end',
-'flex-start','flex-end','left','right']},
-
-
-'flex-direction':{values:['row','row-reverse','column','column-reverse']},
-'flex-wrap':{values:['nowrap','wrap','wrap-reverse']},
-'perspective-origin':{values:['left','center','right','top','bottom']},
-'transform-origin':{values:['left','center','right','top','bottom']},
-'transform-style':{values:['flat','preserve-3d']},
-'transition-timing-function':{
-values:[
-'ease','linear','ease-in','ease-out','ease-in-out','step-start','step-end','steps','frames',
-'cubic-bezier','step-middle']},
-
-
-'animation-timing-function':{
-values:[
-'ease','linear','ease-in','ease-out','ease-in-out','step-start','step-end','steps','frames',
-'cubic-bezier','step-middle']},
-
-
-'animation-direction':{values:['normal','reverse','alternate','alternate-reverse']},
-'animation-play-state':{values:['running','paused']},
-'animation-fill-mode':{values:['forwards','backwards','both']},
-'-webkit-backface-visibility':{values:['visible','hidden']},
-'-webkit-box-decoration-break':{values:['slice','clone']},
-'-webkit-column-break-after':
-{values:['always','avoid','left','right','page','column','avoid-page','avoid-column']},
-'-webkit-column-break-before':
-{values:['always','avoid','left','right','page','column','avoid-page','avoid-column']},
-'-webkit-column-break-inside':{values:['avoid','avoid-page','avoid-column']},
-'-webkit-column-span':{values:['all']},
-'-webkit-column-gap':{values:['normal']},
-'filter':{
-values:[
-'url','blur','brightness','contrast','drop-shadow','grayscale','hue-rotate','invert','opacity',
-'saturate','sepia']},
-
-
-'line-break':{values:['loose','normal','strict','after-white-space']},
-'user-select':{values:['text','all']},
-'-webkit-user-modify':{values:['read-only','read-write','read-write-plaintext-only']},
-'text-align-last':{values:['start','end','left','right','center','justify']},
-'-webkit-text-decoration-line':{values:['underline','overline','line-through','blink']},
-'-webkit-text-decoration-style':{values:['solid','double','dotted','dashed','wavy']},
-'mix-blend-mode':{
-values:[
-'normal','multiply','screen','overlay','darken','lighten','color-dodge','color-burn','hard-light',
-'soft-light','difference','exclusion','hue','saturation','color','luminosity','unset']},
-
-
-'background-blend-mode':{
-values:[
-'normal','multiply','screen','overlay','darken','lighten','color-dodge','color-burn','hard-light',
-'soft-light','difference','exclusion','hue','saturation','color','luminosity','unset']},
-
-
-'grid-template-columns':{values:['min-content','max-content']},
-'grid-template-rows':{values:['min-content','max-content']},
-'grid-auto-columns':{values:['min-content','max-content']},
-'grid-auto-rows':{values:['min-content','max-content']},
-'grid-auto-flow':{values:['row','column','dense']},
-'row-gap':{values:['normal']},
-'animation-iteration-count':{values:['infinite']},
-'font-feature-settings':{values:['normal']},
-'font-kerning':{values:['normal']},
-'font-variant-caps':
-{values:['small-caps','all-small-caps','petite-caps','all-petite-caps','unicase','titling-caps','normal']},
-'font-variant-east-asian':{
-values:[
-'jis78','jis83','jis90','jis04','simplified','traditional','full-width','proportional-width','ruby',
-'normal']},
-
-
-'font-variant-ligatures':{
-values:[
-'common-ligatures','no-common-ligatures','discretionary-ligatures','no-discretionary-ligatures',
-'historical-ligatures','no-historical-ligatures','contextual','no-contextual','normal']},
-
-
-'font-variant-numeric':{
-values:[
-'lining-nums','oldstyle-nums','proportional-nums','tabular-nums','diagonal-fractions','stacked-fractions',
-'ordinal','slashed-zero','normal']},
-
-
-'font-variation-settings':{values:['normal']},
-'backface-visibility':{values:['hidden','visible']},
-'background':{
-values:[
-'repeat','repeat-x','repeat-y','no-repeat','top','bottom','left','right','center','fixed','local',
-'scroll','space','round','border-box','content-box','padding-box']},
-
-
-'background-attachment':{values:['fixed','local','scroll']},
-'background-position':{values:['top','bottom','left','right','center']},
-'background-position-x':{values:['left','right','center']},
-'background-position-y':{values:['top','bottom','center']},
-'background-repeat-x':{values:['repeat','no-repeat']},
-'background-repeat-y':{values:['repeat','no-repeat']},
-'border-bottom':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'border-image-repeat':{values:['repeat','stretch','space','round']},
-'border-left':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'border-right':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'border-top':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'break-after':{values:['left','right','avoid','column','avoid-page','page','recto','verso','avoid-column']},
-'break-before':
-{values:['left','right','avoid','column','avoid-page','page','recto','verso','avoid-column']},
-'break-inside':{values:['avoid','avoid-page','avoid-column']},
-'buffered-rendering':{values:['static','dynamic']},
-'color-interpolation-filters':{values:['srgb','linearrgb']},
-'column-fill':{values:['balance']},
-'column-gap':{values:['normal']},
-'column-rule':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'column-rule-style':
-{values:['hidden','inset','groove','outset','ridge','dotted','dashed','solid','double']},
-'column-rule-width':{values:['medium','thick','thin']},
-'column-span':{values:['all']},
-'fill-rule':{values:['nonzero','evenodd']},
-'flex-flow':{values:['nowrap','row','row-reverse','column','column-reverse','wrap','wrap-reverse']},
-'height':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'hyphens':{values:['manual']},
-'inline-size':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'isolation':{values:['isolate']},
-'list-style':{
-values:[
-'outside',
-'inside',
-'disc',
-'circle',
-'square',
-'decimal',
-'decimal-leading-zero',
-'arabic-indic',
-'bengali',
-'cambodian',
-'khmer',
-'devanagari',
-'gujarati',
-'gurmukhi',
-'kannada',
-'lao',
-'malayalam',
-'mongolian',
-'myanmar',
-'oriya',
-'persian',
-'urdu',
-'telugu',
-'tibetan',
-'thai',
-'lower-roman',
-'upper-roman',
-'lower-greek',
-'lower-alpha',
-'lower-latin',
-'upper-alpha',
-'upper-latin',
-'cjk-earthly-branch',
-'cjk-heavenly-stem',
-'ethiopic-halehame',
-'ethiopic-halehame-am',
-'ethiopic-halehame-ti-er',
-'ethiopic-halehame-ti-et',
-'hangul',
-'hangul-consonant',
-'korean-hangul-formal',
-'korean-hanja-formal',
-'korean-hanja-informal',
-'hebrew',
-'armenian',
-'lower-armenian',
-'upper-armenian',
-'georgian',
-'cjk-ideographic',
-'simp-chinese-formal',
-'simp-chinese-informal',
-'trad-chinese-formal',
-'trad-chinese-informal',
-'hiragana',
-'katakana',
-'hiragana-iroha',
-'katakana-iroha']},
-
-
-'mask-source-type':{values:['alpha','luminance']},
-'mask-type':{values:['alpha','luminance']},
-'max-block-size':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'max-inline-size':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'min-block-size':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'min-height':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'min-inline-size':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'min-width':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'object-fit':{values:['contain','cover','fill','scale-down']},
-'object-position':{values:['top','bottom','left','right','center']},
-'offset-anchor':{values:['top','bottom','left','right','center']},
-'offset-position':{values:['top','bottom','left','right','center']},
-'offset-rotate':{values:['reverse']},
-'overflow-anchor':{values:['visible']},
-'paint-order':{values:['normal','fill','stroke','markers']},
-'scroll-behavior':{values:['smooth']},
-'scroll-customization':{
-values:[
-'pan-x',
-'pan-y',
-'pan-left',
-'pan-right',
-'pan-up',
-'pan-down']},
-
-
-'scroll-snap-align':{values:['start','end','center']},
-'scroll-snap-stop':{values:['normal','always']},
-'scroll-snap-type':{values:['x','y','block','inline','both','mandatory','proximity']},
-'shape-outside':{values:['border-box','content-box','padding-box','margin-box']},
-'shape-rendering':{values:['optimizespeed','geometricprecision','crispedges']},
-'stroke-linecap':{values:['square','round','butt']},
-'text-anchor':{values:['middle','start','end']},
-'text-decoration-line':{values:['blink','line-through','overline','underline']},
-'text-decoration-style':{values:['dotted','dashed','solid','double','wavy']},
-'text-justify':{values:['inter-word','distribute']},
-'text-underline-position':{values:['under']},
-'touch-action':
-{values:['pan-x','pan-y','pan-left','pan-right','pan-up','pan-down','manipulation','pinch-zoom']},
-'transform-box':{values:['border-box','fill-box','view-box']},
-'vector-effect':{values:['non-scaling-stroke']},
-'-webkit-app-region':{values:['drag','no-drag']},
-'-webkit-appearance':{
-values:[
-'checkbox',
-'radio',
-'push-button',
-'square-button',
-'button',
-'button-bevel',
-'inner-spin-button',
-'listbox',
-'listitem',
-'media-enter-fullscreen-button',
-'media-exit-fullscreen-button',
-'media-mute-button',
-'media-play-button',
-'media-overlay-play-button',
-'media-toggle-closed-captions-button',
-'media-slider',
-'media-sliderthumb',
-'media-volume-slider-container',
-'media-volume-slider',
-'media-volume-sliderthumb',
-'media-controls-background',
-'media-controls-fullscreen-background',
-'media-current-time-display',
-'media-time-remaining-display',
-'menulist',
-'menulist-button',
-'menulist-text',
-'menulist-textfield',
-'meter',
-'progress-bar',
-'progress-bar-value',
-'slider-horizontal',
-'slider-vertical',
-'sliderthumb-horizontal',
-'sliderthumb-vertical',
-'caret',
-'searchfield',
-'searchfield-cancel-button',
-'textfield',
-'textarea']},
-
-
-'-webkit-border-after':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'-webkit-border-after-style':
-{values:['hidden','inset','groove','outset','ridge','dotted','dashed','solid','double']},
-'-webkit-border-after-width':{values:['medium','thick','thin']},
-'-webkit-border-before':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'-webkit-border-before-style':
-{values:['hidden','inset','groove','outset','ridge','dotted','dashed','solid','double']},
-'-webkit-border-before-width':{values:['medium','thick','thin']},
-'-webkit-border-end':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'-webkit-border-end-style':
-{values:['hidden','inset','groove','outset','ridge','dotted','dashed','solid','double']},
-'-webkit-border-end-width':{values:['medium','thick','thin']},
-'-webkit-border-start':{
-values:[
-'hidden','inset','groove','outset','ridge','dotted','dashed','solid','double','medium','thick','thin']},
-
-
-'-webkit-border-start-style':
-{values:['hidden','inset','groove','outset','ridge','dotted','dashed','solid','double']},
-'-webkit-border-start-width':{values:['medium','thick','thin']},
-'-webkit-box-pack':{values:['center','justify','start','end']},
-'-webkit-logical-height':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'-webkit-logical-width':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'-webkit-margin-collapse':{values:['collapse','separate','discard']},
-'-webkit-mask-box-image':{values:['repeat','stretch','space','round']},
-'-webkit-mask-box-image-repeat':{values:['repeat','stretch','space','round']},
-'-webkit-mask-clip':{values:['text','border','border-box','content','content-box','padding','padding-box']},
-'-webkit-mask-composite':{
-values:[
-'clear','copy','source-over','source-in','source-out','source-atop','destination-over','destination-in',
-'destination-out','destination-atop','xor','plus-lighter']},
-
-
-'-webkit-mask-origin':{values:['border','border-box','content','content-box','padding','padding-box']},
-'-webkit-mask-position':{values:['top','bottom','left','right','center']},
-'-webkit-mask-position-x':{values:['left','right','center']},
-'-webkit-mask-position-y':{values:['top','bottom','center']},
-'-webkit-mask-repeat':{values:['repeat','repeat-x','repeat-y','no-repeat','space','round']},
-'-webkit-mask-size':{values:['contain','cover']},
-'-webkit-max-logical-height':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'-webkit-max-logical-width':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'-webkit-min-logical-height':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'-webkit-min-logical-width':{values:['-webkit-fill-available','min-content','max-content','fit-content']},
-'-webkit-perspective-origin-x':{values:['left','right','center']},
-'-webkit-perspective-origin-y':{values:['top','bottom','center']},
-'-webkit-print-color-adjust':{values:['economy','exact']},
-'-webkit-rtl-ordering':{values:['logical','visual']},
-'-webkit-ruby-position':{values:['after','before']},
-'-webkit-text-decorations-in-effect':{values:['blink','line-through','overline','underline']},
-'-webkit-text-security':{values:['disc','circle','square']},
-'-webkit-text-stroke':{values:['medium','thick','thin']},
-'-webkit-text-stroke-width':{values:['medium','thick','thin']},
-'-webkit-transform-origin-x':{values:['left','right','center']},
-'-webkit-transform-origin-y':{values:['top','bottom','center']},
-'-webkit-user-drag':{values:['element']},
-'width':{values:['-webkit-fill-available','min-content','max-content','fit-content']}};
-
-
-
-SDK.CSSMetadata.Weight={
-'align-content':57,
-'align-items':129,
-'align-self':55,
-'animation':175,
-'animation-delay':114,
-'animation-direction':113,
-'animation-duration':137,
-'animation-fill-mode':132,
-'animation-iteration-count':124,
-'animation-name':139,
-'animation-play-state':104,
-'animation-timing-function':141,
-'backface-visibility':123,
-'background':260,
-'background-attachment':119,
-'background-clip':165,
-'background-color':259,
-'background-image':246,
-'background-origin':107,
-'background-position':237,
-'background-position-x':108,
-'background-position-y':93,
-'background-repeat':234,
-'background-size':203,
-'border':263,
-'border-bottom':233,
-'border-bottom-color':190,
-'border-bottom-left-radius':186,
-'border-bottom-right-radius':185,
-'border-bottom-style':150,
-'border-bottom-width':179,
-'border-collapse':209,
-'border-color':226,
-'border-image':89,
-'border-image-outset':50,
-'border-image-repeat':49,
-'border-image-slice':58,
-'border-image-source':32,
-'border-image-width':52,
-'border-left':221,
-'border-left-color':174,
-'border-left-style':142,
-'border-left-width':172,
-'border-radius':224,
-'border-right':223,
-'border-right-color':182,
-'border-right-style':130,
-'border-right-width':178,
-'border-spacing':198,
-'border-style':206,
-'border-top':231,
-'border-top-color':192,
-'border-top-left-radius':187,
-'border-top-right-radius':189,
-'border-top-style':152,
-'border-top-width':180,
-'border-width':214,
-'bottom':227,
-'box-shadow':213,
-'box-sizing':216,
-'caption-side':96,
-'clear':229,
-'clip':173,
-'clip-rule':5,
-'color':256,
-'content':219,
-'counter-increment':111,
-'counter-reset':110,
-'cursor':250,
-'direction':176,
-'display':262,
-'empty-cells':99,
-'fill':140,
-'fill-opacity':82,
-'fill-rule':22,
-'filter':160,
-'flex':133,
-'flex-basis':66,
-'flex-direction':85,
-'flex-flow':94,
-'flex-grow':112,
-'flex-shrink':61,
-'flex-wrap':68,
-'float':252,
-'font':211,
-'font-family':254,
-'font-kerning':18,
-'font-size':264,
-'font-stretch':77,
-'font-style':220,
-'font-variant':161,
-'font-weight':257,
-'height':266,
-'image-rendering':90,
-'justify-content':127,
-'left':248,
-'letter-spacing':188,
-'line-height':244,
-'list-style':215,
-'list-style-image':145,
-'list-style-position':149,
-'list-style-type':199,
-'margin':267,
-'margin-bottom':241,
-'margin-left':243,
-'margin-right':238,
-'margin-top':253,
-'mask':20,
-'max-height':205,
-'max-width':225,
-'min-height':217,
-'min-width':218,
-'object-fit':33,
-'opacity':251,
-'order':117,
-'orphans':146,
-'outline':222,
-'outline-color':153,
-'outline-offset':147,
-'outline-style':151,
-'outline-width':148,
-'overflow':255,
-'overflow-wrap':105,
-'overflow-x':184,
-'overflow-y':196,
-'padding':265,
-'padding-bottom':230,
-'padding-left':235,
-'padding-right':232,
-'padding-top':240,
-'page':8,
-'page-break-after':120,
-'page-break-before':69,
-'page-break-inside':121,
-'perspective':92,
-'perspective-origin':103,
-'pointer-events':183,
-'position':261,
-'quotes':158,
-'resize':168,
-'right':245,
-'shape-rendering':38,
-'size':64,
-'speak':118,
-'src':170,
-'stop-color':42,
-'stop-opacity':31,
-'stroke':98,
-'stroke-dasharray':36,
-'stroke-dashoffset':3,
-'stroke-linecap':30,
-'stroke-linejoin':21,
-'stroke-miterlimit':12,
-'stroke-opacity':34,
-'stroke-width':87,
-'table-layout':171,
-'tab-size':46,
-'text-align':260,
-'text-anchor':35,
-'text-decoration':247,
-'text-indent':207,
-'text-overflow':204,
-'text-rendering':155,
-'text-shadow':208,
-'text-transform':202,
-'top':258,
-'touch-action':80,
-'transform':181,
-'transform-origin':162,
-'transform-style':86,
-'transition':193,
-'transition-delay':134,
-'transition-duration':135,
-'transition-property':131,
-'transition-timing-function':122,
-'unicode-bidi':156,
-'unicode-range':136,
-'vertical-align':236,
-'visibility':242,
-'-webkit-appearance':191,
-'-webkit-backface-visibility':154,
-'-webkit-background-clip':164,
-'-webkit-background-origin':40,
-'-webkit-background-size':163,
-'-webkit-border-end':9,
-'-webkit-border-horizontal-spacing':81,
-'-webkit-border-image':75,
-'-webkit-border-radius':212,
-'-webkit-border-start':10,
-'-webkit-border-start-color':16,
-'-webkit-border-start-width':13,
-'-webkit-border-vertical-spacing':43,
-'-webkit-box-align':101,
-'-webkit-box-direction':51,
-'-webkit-box-flex':128,
-'-webkit-box-ordinal-group':91,
-'-webkit-box-orient':144,
-'-webkit-box-pack':106,
-'-webkit-box-reflect':39,
-'-webkit-box-shadow':210,
-'-webkit-column-break-inside':60,
-'-webkit-column-count':84,
-'-webkit-column-gap':76,
-'-webkit-column-rule':25,
-'-webkit-column-rule-color':23,
-'-webkit-columns':44,
-'-webkit-column-span':29,
-'-webkit-column-width':47,
-'-webkit-filter':159,
-'-webkit-font-feature-settings':59,
-'-webkit-font-smoothing':177,
-'-webkit-highlight':1,
-'-webkit-line-break':45,
-'-webkit-line-clamp':126,
-'-webkit-margin-after':67,
-'-webkit-margin-before':70,
-'-webkit-margin-collapse':14,
-'-webkit-margin-end':65,
-'-webkit-margin-start':100,
-'-webkit-margin-top-collapse':78,
-'-webkit-mask':19,
-'-webkit-mask-box-image':72,
-'-webkit-mask-image':88,
-'-webkit-mask-position':54,
-'-webkit-mask-repeat':63,
-'-webkit-mask-size':79,
-'-webkit-padding-after':15,
-'-webkit-padding-before':28,
-'-webkit-padding-end':48,
-'-webkit-padding-start':73,
-'-webkit-print-color-adjust':83,
-'-webkit-rtl-ordering':7,
-'-webkit-tap-highlight-color':169,
-'-webkit-text-emphasis-color':11,
-'-webkit-text-fill-color':71,
-'-webkit-text-security':17,
-'-webkit-text-stroke':56,
-'-webkit-text-stroke-color':37,
-'-webkit-text-stroke-width':53,
-'-webkit-user-drag':95,
-'-webkit-user-modify':62,
-'-webkit-user-select':194,
-'-webkit-writing-mode':4,
-'white-space':228,
-'widows':115,
-'width':268,
-'will-change':74,
-'word-break':166,
-'word-spacing':157,
-'word-wrap':197,
-'writing-mode':41,
-'z-index':239,
-'zoom':200};
-
-
-},{}],156:[function(require,module,exports){
-
-
-
-
-
-
-SDK.CSSProperty=class{
-
-
-
-
-
-
-
-
-
-
-
-
-constructor(ownerStyle,index,name,value,important,disabled,parsedOk,implicit,text,range){
-this.ownerStyle=ownerStyle;
-this.index=index;
-this.name=name;
-this.value=value;
-this.important=important;
-this.disabled=disabled;
-this.parsedOk=parsedOk;
-this.implicit=implicit;
-this.text=text;
-this.range=range?TextUtils.TextRange.fromObject(range):null;
-this._active=true;
-this._nameRange=null;
-this._valueRange=null;
-}
-
-
-
-
-
-
-
-static parsePayload(ownerStyle,index,payload){
-
-
-
-
-
-const result=new SDK.CSSProperty(
-ownerStyle,index,payload.name,payload.value,payload.important||false,payload.disabled||false,
-'parsedOk'in payload?!!payload.parsedOk:true,!!payload.implicit,payload.text,payload.range);
-return result;
-}
-
-_ensureRanges(){
-if(this._nameRange&&this._valueRange)
-return;
-const range=this.range;
-const text=this.text?new TextUtils.Text(this.text):null;
-if(!range||!text)
-return;
-
-const nameIndex=text.value().indexOf(this.name);
-const valueIndex=text.value().lastIndexOf(this.value);
-if(nameIndex===-1||valueIndex===-1||nameIndex>valueIndex)
-return;
-
-const nameSourceRange=new TextUtils.SourceRange(nameIndex,this.name.length);
-const valueSourceRange=new TextUtils.SourceRange(valueIndex,this.value.length);
-
-this._nameRange=rebase(text.toTextRange(nameSourceRange),range.startLine,range.startColumn);
-this._valueRange=rebase(text.toTextRange(valueSourceRange),range.startLine,range.startColumn);
-
-
-
-
-
-
-
-function rebase(oneLineRange,lineOffset,columnOffset){
-if(oneLineRange.startLine===0){
-oneLineRange.startColumn+=columnOffset;
-oneLineRange.endColumn+=columnOffset;
-}
-oneLineRange.startLine+=lineOffset;
-oneLineRange.endLine+=lineOffset;
-return oneLineRange;
-}
-}
-
-
-
-
-nameRange(){
-this._ensureRanges();
-return this._nameRange;
-}
-
-
-
-
-valueRange(){
-this._ensureRanges();
-return this._valueRange;
-}
-
-
-
-
-rebase(edit){
-if(this.ownerStyle.styleSheetId!==edit.styleSheetId)
-return;
-if(this.range)
-this.range=this.range.rebaseAfterTextEdit(edit.oldRange,edit.newRange);
-}
-
-
-
-
-setActive(active){
-this._active=active;
-}
-
-get propertyText(){
-if(this.text!==undefined)
-return this.text;
-
-if(this.name==='')
-return'';
-return this.name+': '+this.value+(this.important?' !important':'')+';';
-}
-
-
-
-
-activeInStyle(){
-return this._active;
-}
-
-
-
-
-
-
-
-setText(propertyText,majorChange,overwrite){
-if(!this.ownerStyle)
-return Promise.reject(new Error('No ownerStyle for property'));
-
-if(!this.ownerStyle.styleSheetId)
-return Promise.reject(new Error('No owner style id'));
-
-if(!this.range||!this.ownerStyle.range)
-return Promise.reject(new Error('Style not editable'));
-
-if(majorChange)
-Host.userMetrics.actionTaken(Host.UserMetrics.Action.StyleRuleEdited);
-
-if(overwrite&&propertyText===this.propertyText){
-this.ownerStyle.cssModel().domModel().markUndoableState(!majorChange);
-return Promise.resolve(true);
-}
-
-const range=this.range.relativeTo(this.ownerStyle.range.startLine,this.ownerStyle.range.startColumn);
-const indentation=this.ownerStyle.cssText?this._detectIndentation(this.ownerStyle.cssText):
-Common.moduleSetting('textEditorIndent').get();
-const endIndentation=this.ownerStyle.cssText?indentation.substring(0,this.ownerStyle.range.endColumn):'';
-const text=new TextUtils.Text(this.ownerStyle.cssText||'');
-const newStyleText=text.replaceRange(range,String.sprintf(';%s;',propertyText));
-
-return self.runtime.extension(TextUtils.TokenizerFactory).
-instance().
-then(this._formatStyle.bind(this,newStyleText,indentation,endIndentation)).
-then(setStyleText.bind(this));
-
-
-
-
-
-
-function setStyleText(styleText){
-return this.ownerStyle.setText(styleText,majorChange);
-}
-}
-
-
-
-
-
-
-
-
-_formatStyle(styleText,indentation,endIndentation,tokenizerFactory){
-if(indentation)
-indentation='\n'+indentation;
-let result='';
-let propertyText;
-let insideProperty=false;
-const tokenize=tokenizerFactory.createTokenizer('text/css');
-
-tokenize('*{'+styleText+'}',processToken);
-if(insideProperty)
-result+=propertyText;
-result=result.substring(2,result.length-1).trimRight();
-return result+(indentation?'\n'+endIndentation:'');
-
-
-
-
-
-
-
-function processToken(token,tokenType,column,newColumn){
-if(!insideProperty){
-const disabledProperty=tokenType&&tokenType.includes('css-comment')&&isDisabledProperty(token);
-const isPropertyStart=tokenType&&(
-tokenType.includes('css-string')||tokenType.includes('css-meta')||tokenType.includes('css-property')||
-tokenType.includes('css-variable-2'));
-if(disabledProperty){
-result=result.trimRight()+indentation+token;
-}else if(isPropertyStart){
-insideProperty=true;
-propertyText=token;
-}else if(token!==';'){
-result+=token;
-}
-return;
-}
-
-if(token==='}'||token===';'){
-result=result.trimRight()+indentation+propertyText.trim()+';';
-insideProperty=false;
-if(token==='}')
-result+='}';
-}else{
-propertyText+=token;
-}
-}
-
-
-
-
-
-function isDisabledProperty(text){
-const colon=text.indexOf(':');
-if(colon===-1)
-return false;
-const propertyName=text.substring(2,colon).trim();
-return SDK.cssMetadata().isCSSPropertyName(propertyName);
-}
-}
-
-
-
-
-
-_detectIndentation(text){
-const lines=text.split('\n');
-if(lines.length<2)
-return'';
-return TextUtils.TextUtils.lineIndent(lines[1]);
-}
-
-
-
-
-
-
-
-setValue(newValue,majorChange,overwrite,userCallback){
-const text=this.name+': '+newValue+(this.important?' !important':'')+';';
-this.setText(text,majorChange,overwrite).then(userCallback);
-}
-
-
-
-
-
-setDisabled(disabled){
-if(!this.ownerStyle)
-return Promise.resolve(false);
-if(disabled===this.disabled)
-return Promise.resolve(true);
-const propertyText=this.text.trim();
-const text=disabled?'/* '+propertyText+' */':this.text.substring(2,propertyText.length-2).trim();
-return this.setText(text,true,true);
-}};
-
-
-},{}],157:[function(require,module,exports){
-
-
-
-
-
-
-SDK.CSSValue=class{
-
-
-
-constructor(payload){
-this.text=payload.text;
-if(payload.range)
-this.range=TextUtils.TextRange.fromObject(payload.range);
-}
-
-
-
-
-rebase(edit){
-if(!this.range)
-return;
-this.range=this.range.rebaseAfterTextEdit(edit.oldRange,edit.newRange);
-}};
-
-
-
-
-
-SDK.CSSRule=class{
-
-
-
-
-constructor(cssModel,payload){
-this._cssModel=cssModel;
-this.styleSheetId=payload.styleSheetId;
-
-if(this.styleSheetId){
-const styleSheetHeader=cssModel.styleSheetHeaderForId(this.styleSheetId);
-this.sourceURL=styleSheetHeader.sourceURL;
-}
-this.origin=payload.origin;
-this.style=new SDK.CSSStyleDeclaration(this._cssModel,this,payload.style,SDK.CSSStyleDeclaration.Type.Regular);
-}
-
-
-
-
-rebase(edit){
-if(this.styleSheetId!==edit.styleSheetId)
-return;
-this.style.rebase(edit);
-}
-
-
-
-
-resourceURL(){
-if(!this.styleSheetId)
-return'';
-const styleSheetHeader=this._cssModel.styleSheetHeaderForId(this.styleSheetId);
-return styleSheetHeader.resourceURL();
-}
-
-
-
-
-isUserAgent(){
-return this.origin===Protocol.CSS.StyleSheetOrigin.UserAgent;
-}
-
-
-
-
-isInjected(){
-return this.origin===Protocol.CSS.StyleSheetOrigin.Injected;
-}
-
-
-
-
-isViaInspector(){
-return this.origin===Protocol.CSS.StyleSheetOrigin.Inspector;
-}
-
-
-
-
-isRegular(){
-return this.origin===Protocol.CSS.StyleSheetOrigin.Regular;
-}
-
-
-
-
-cssModel(){
-return this._cssModel;
-}};
-
-
-
-
-
-SDK.CSSStyleRule=class extends SDK.CSSRule{
-
-
-
-
-
-constructor(cssModel,payload,wasUsed){
-super(cssModel,payload);
-
-this._reinitializeSelectors(payload.selectorList);
-this.media=payload.media?SDK.CSSMedia.parseMediaArrayPayload(cssModel,payload.media):[];
-this.wasUsed=wasUsed||false;
-}
-
-
-
-
-
-
-static createDummyRule(cssModel,selectorText){
-const dummyPayload={
-selectorList:{
-selectors:[{text:selectorText}]},
-
-style:{styleSheetId:'0',range:new TextUtils.TextRange(0,0,0,0),shorthandEntries:[],cssProperties:[]}};
-
-return new SDK.CSSStyleRule(cssModel,dummyPayload);
-}
-
-
-
-
-_reinitializeSelectors(selectorList){
-
-this.selectors=[];
-for(let i=0;i<selectorList.selectors.length;++i)
-this.selectors.push(new SDK.CSSValue(selectorList.selectors[i]));
-}
-
-
-
-
-
-setSelectorText(newSelector){
-const styleSheetId=this.styleSheetId;
-if(!styleSheetId)
-throw'No rule stylesheet id';
-const range=this.selectorRange();
-if(!range)
-throw'Rule selector is not editable';
-return this._cssModel.setSelectorText(styleSheetId,range,newSelector);
-}
-
-
-
-
-selectorText(){
-return this.selectors.select('text').join(', ');
-}
-
-
-
-
-selectorRange(){
-const firstRange=this.selectors[0].range;
-if(!firstRange)
-return null;
-const lastRange=this.selectors.peekLast().range;
-return new TextUtils.TextRange(
-firstRange.startLine,firstRange.startColumn,lastRange.endLine,lastRange.endColumn);
-}
-
-
-
-
-
-lineNumberInSource(selectorIndex){
-const selector=this.selectors[selectorIndex];
-if(!selector||!selector.range||!this.styleSheetId)
-return 0;
-const styleSheetHeader=this._cssModel.styleSheetHeaderForId(this.styleSheetId);
-return styleSheetHeader.lineNumberInSource(selector.range.startLine);
-}
-
-
-
-
-
-columnNumberInSource(selectorIndex){
-const selector=this.selectors[selectorIndex];
-if(!selector||!selector.range||!this.styleSheetId)
-return undefined;
-const styleSheetHeader=this._cssModel.styleSheetHeaderForId(this.styleSheetId);
-console.assert(styleSheetHeader);
-return styleSheetHeader.columnNumberInSource(selector.range.startLine,selector.range.startColumn);
-}
-
-
-
-
-
-rebase(edit){
-if(this.styleSheetId!==edit.styleSheetId)
-return;
-if(this.selectorRange().equal(edit.oldRange)){
-this._reinitializeSelectors(edit.payload);
-}else{
-for(let i=0;i<this.selectors.length;++i)
-this.selectors[i].rebase(edit);
-}
-for(const media of this.media)
-media.rebase(edit);
-
-super.rebase(edit);
-}};
-
-
-
-
-
-
-SDK.CSSKeyframesRule=class{
-
-
-
-
-constructor(cssModel,payload){
-this._cssModel=cssModel;
-this._animationName=new SDK.CSSValue(payload.animationName);
-this._keyframes=payload.keyframes.map(keyframeRule=>new SDK.CSSKeyframeRule(cssModel,keyframeRule));
-}
-
-
-
-
-name(){
-return this._animationName;
-}
-
-
-
-
-keyframes(){
-return this._keyframes;
-}};
-
-
-
-
-
-SDK.CSSKeyframeRule=class extends SDK.CSSRule{
-
-
-
-
-constructor(cssModel,payload){
-super(cssModel,payload);
-this._reinitializeKey(payload.keyText);
-}
-
-
-
-
-key(){
-return this._keyText;
-}
-
-
-
-
-_reinitializeKey(payload){
-this._keyText=new SDK.CSSValue(payload);
-}
-
-
-
-
-
-rebase(edit){
-if(this.styleSheetId!==edit.styleSheetId||!this._keyText.range)
-return;
-if(edit.oldRange.equal(this._keyText.range))
-this._reinitializeKey(edit.payload);else
-
-this._keyText.rebase(edit);
-
-super.rebase(edit);
-}
-
-
-
-
-
-setKeyText(newKeyText){
-const styleSheetId=this.styleSheetId;
-if(!styleSheetId)
-throw'No rule stylesheet id';
-const range=this._keyText.range;
-if(!range)
-throw'Keyframe key is not editable';
-return this._cssModel.setKeyframeKey(styleSheetId,range,newKeyText);
-}};
-
-
-},{}],158:[function(require,module,exports){
-
-
-
-SDK.CSSStyleDeclaration=class{
-
-
-
-
-
-
-constructor(cssModel,parentRule,payload,type){
-this._cssModel=cssModel;
-this.parentRule=parentRule;
-
-this._allProperties;
-
-this.styleSheetId;
-
-this.range;
-
-this.cssText;
-
-this._shorthandValues;
-
-this._shorthandIsImportant;
-
-this._activePropertyMap;
-
-this._leadingProperties;
-this._reinitialize(payload);
-this.type=type;
-}
-
-
-
-
-rebase(edit){
-if(this.styleSheetId!==edit.styleSheetId||!this.range)
-return;
-if(edit.oldRange.equal(this.range)){
-this._reinitialize(edit.payload);
-}else{
-this.range=this.range.rebaseAfterTextEdit(edit.oldRange,edit.newRange);
-for(let i=0;i<this._allProperties.length;++i)
-this._allProperties[i].rebase(edit);
-}
-}
-
-
-
-
-_reinitialize(payload){
-this.styleSheetId=payload.styleSheetId;
-this.range=payload.range?TextUtils.TextRange.fromObject(payload.range):null;
-
-const shorthandEntries=payload.shorthandEntries;
-this._shorthandValues=new Map();
-this._shorthandIsImportant=new Set();
-for(let i=0;i<shorthandEntries.length;++i){
-this._shorthandValues.set(shorthandEntries[i].name,shorthandEntries[i].value);
-if(shorthandEntries[i].important)
-this._shorthandIsImportant.add(shorthandEntries[i].name);
-}
-
-this._allProperties=[];
-
-if(payload.cssText&&this.range){
-const cssText=new TextUtils.Text(payload.cssText);
-let start={line:this.range.startLine,column:this.range.startColumn};
-for(const cssProperty of payload.cssProperties){
-const range=cssProperty.range;
-if(range){
-parseUnusedText.call(this,cssText,start.line,start.column,range.startLine,range.startColumn);
-start={line:range.endLine,column:range.endColumn};
-}
-this._allProperties.push(SDK.CSSProperty.parsePayload(this,this._allProperties.length,cssProperty));
-}
-parseUnusedText.call(this,cssText,start.line,start.column,this.range.endLine,this.range.endColumn);
-}else{
-for(const cssProperty of payload.cssProperties)
-this._allProperties.push(SDK.CSSProperty.parsePayload(this,this._allProperties.length,cssProperty));
-}
-
-this._generateSyntheticPropertiesIfNeeded();
-this._computeInactiveProperties();
-
-this._activePropertyMap=new Map();
-for(const property of this._allProperties){
-if(!property.activeInStyle())
-continue;
-this._activePropertyMap.set(property.name,property);
-}
-
-this.cssText=payload.cssText;
-this._leadingProperties=null;
-
-
-
-
-
-
-
-
-
-function parseUnusedText(cssText,startLine,startColumn,endLine,endColumn){
-const tr=new TextUtils.TextRange(startLine,startColumn,endLine,endColumn);
-const missingText=cssText.extract(tr.relativeTo(this.range.startLine,this.range.startColumn));
-
-
-const lines=missingText.split('\n');
-let lineNumber=0;
-let inComment=false;
-for(const line of lines){
-let column=0;
-for(const property of line.split(';')){
-const strippedProperty=stripComments(property,inComment);
-const trimmedProperty=strippedProperty.text.trim();
-inComment=strippedProperty.inComment;
-
-if(trimmedProperty){
-let name;
-let value;
-const colonIndex=trimmedProperty.indexOf(':');
-if(colonIndex===-1){
-name=trimmedProperty;
-value='';
-}else{
-name=trimmedProperty.substring(0,colonIndex).trim();
-value=trimmedProperty.substring(colonIndex+1).trim();
-}
-const range=new TextUtils.TextRange(lineNumber,column,lineNumber,column+property.length);
-this._allProperties.push(new SDK.CSSProperty(
-this,this._allProperties.length,name,value,false,false,false,false,property,
-range.relativeFrom(startLine,startColumn)));
-}
-column+=property.length+1;
-}
-lineNumber++;
-}
-}
-
-
-
-
-
-
-function stripComments(text,inComment){
-let output='';
-for(let i=0;i<text.length;i++){
-if(!inComment&&text.substring(i,i+2)==='/*'){
-inComment=true;
-i++;
-}else if(inComment&&text.substring(i,i+2)==='*/'){
-inComment=false;
-i++;
-}else if(!inComment){
-output+=text[i];
-}
-}
-return{text:output,inComment};
-}
-}
-
-_generateSyntheticPropertiesIfNeeded(){
-if(this.range)
-return;
-
-if(!this._shorthandValues.size)
-return;
-
-const propertiesSet=new Set();
-for(const property of this._allProperties)
-propertiesSet.add(property.name);
-
-const generatedProperties=[];
-
-for(const property of this._allProperties){
-
-const shorthands=SDK.cssMetadata().shorthands(property.name)||[];
-for(const shorthand of shorthands){
-if(propertiesSet.has(shorthand))
-continue;
-const shorthandValue=this._shorthandValues.get(shorthand);
-if(!shorthandValue)
-continue;
-
-
-const shorthandImportance=!!this._shorthandIsImportant.has(shorthand);
-const shorthandProperty=new SDK.CSSProperty(
-this,this.allProperties().length,shorthand,shorthandValue,shorthandImportance,false,true,false);
-generatedProperties.push(shorthandProperty);
-propertiesSet.add(shorthand);
-}
-}
-this._allProperties=this._allProperties.concat(generatedProperties);
-}
-
-
-
-
-_computeLeadingProperties(){
-
-
-
-
-function propertyHasRange(property){
-return!!property.range;
-}
-
-if(this.range)
-return this._allProperties.filter(propertyHasRange);
-
-const leadingProperties=[];
-for(const property of this._allProperties){
-const shorthands=SDK.cssMetadata().shorthands(property.name)||[];
-let belongToAnyShorthand=false;
-for(const shorthand of shorthands){
-if(this._shorthandValues.get(shorthand)){
-belongToAnyShorthand=true;
-break;
-}
-}
-if(!belongToAnyShorthand)
-leadingProperties.push(property);
-}
-
-return leadingProperties;
-}
-
-
-
-
-leadingProperties(){
-if(!this._leadingProperties)
-this._leadingProperties=this._computeLeadingProperties();
-return this._leadingProperties;
-}
-
-
-
-
-target(){
-return this._cssModel.target();
-}
-
-
-
-
-cssModel(){
-return this._cssModel;
-}
-
-_computeInactiveProperties(){
-const activeProperties={};
-for(let i=0;i<this._allProperties.length;++i){
-const property=this._allProperties[i];
-if(property.disabled||!property.parsedOk){
-property.setActive(false);
-continue;
-}
-const canonicalName=SDK.cssMetadata().canonicalPropertyName(property.name);
-const activeProperty=activeProperties[canonicalName];
-if(!activeProperty){
-activeProperties[canonicalName]=property;
-}else if(!activeProperty.important||property.important){
-activeProperty.setActive(false);
-activeProperties[canonicalName]=property;
-}else{
-property.setActive(false);
-}
-}
-}
-
-
-
-
-allProperties(){
-return this._allProperties;
-}
-
-
-
-
-
-getPropertyValue(name){
-const property=this._activePropertyMap.get(name);
-return property?property.value:'';
-}
-
-
-
-
-
-isPropertyImplicit(name){
-const property=this._activePropertyMap.get(name);
-return property?property.implicit:false;
-}
-
-
-
-
-
-longhandProperties(name){
-const longhands=SDK.cssMetadata().longhands(name);
-const result=[];
-for(let i=0;longhands&&i<longhands.length;++i){
-const property=this._activePropertyMap.get(longhands[i]);
-if(property)
-result.push(property);
-}
-return result;
-}
-
-
-
-
-
-propertyAt(index){
-return index<this.allProperties().length?this.allProperties()[index]:null;
-}
-
-
-
-
-pastLastSourcePropertyIndex(){
-for(let i=this.allProperties().length-1;i>=0;--i){
-if(this.allProperties()[i].range)
-return i+1;
-}
-return 0;
-}
-
-
-
-
-
-_insertionRange(index){
-const property=this.propertyAt(index);
-return property&&property.range?property.range.collapseToStart():this.range.collapseToEnd();
-}
-
-
-
-
-
-newBlankProperty(index){
-index=typeof index==='undefined'?this.pastLastSourcePropertyIndex():index;
-const property=
-new SDK.CSSProperty(this,index,'','',false,false,true,false,'',this._insertionRange(index));
-return property;
-}
-
-
-
-
-
-
-setText(text,majorChange){
-if(!this.range||!this.styleSheetId)
-return Promise.resolve(false);
-return this._cssModel.setStyleText(this.styleSheetId,this.range,text,majorChange);
-}
-
-
-
-
-
-
-
-insertPropertyAt(index,name,value,userCallback){
-this.newBlankProperty(index).setText(name+': '+value+';',false,true).then(userCallback);
-}
-
-
-
-
-
-
-appendProperty(name,value,userCallback){
-this.insertPropertyAt(this.allProperties().length,name,value,userCallback);
-}};
-
-
-
-SDK.CSSStyleDeclaration.Type={
-Regular:'Regular',
-Inline:'Inline',
-Attributes:'Attributes'};
-
-
-},{}],159:[function(require,module,exports){
-
-
-
-
-
-
-
-TextUtils.Text=class{
-
-
-
-constructor(value){
-this._value=value;
-}
-
-
-
-
-lineEndings(){
-if(!this._lineEndings)
-this._lineEndings=this._value.computeLineEndings();
-return this._lineEndings;
-}
-
-
-
-
-value(){
-return this._value;
-}
-
-
-
-
-lineCount(){
-const lineEndings=this.lineEndings();
-return lineEndings.length;
-}
-
-
-
-
-
-
-offsetFromPosition(lineNumber,columnNumber){
-return(lineNumber?this.lineEndings()[lineNumber-1]+1:0)+columnNumber;
-}
-
-
-
-
-
-positionFromOffset(offset){
-const lineEndings=this.lineEndings();
-const lineNumber=lineEndings.lowerBound(offset);
-return{lineNumber:lineNumber,columnNumber:offset-(lineNumber&&lineEndings[lineNumber-1]+1)};
-}
-
-
-
-
-lineAt(lineNumber){
-const lineEndings=this.lineEndings();
-const lineStart=lineNumber>0?lineEndings[lineNumber-1]+1:0;
-const lineEnd=lineEndings[lineNumber];
-let lineContent=this._value.substring(lineStart,lineEnd);
-if(lineContent.length>0&&lineContent.charAt(lineContent.length-1)==='\r')
-lineContent=lineContent.substring(0,lineContent.length-1);
-return lineContent;
-}
-
-
-
-
-
-toSourceRange(range){
-const start=this.offsetFromPosition(range.startLine,range.startColumn);
-const end=this.offsetFromPosition(range.endLine,range.endColumn);
-return new TextUtils.SourceRange(start,end-start);
-}
-
-
-
-
-
-toTextRange(sourceRange){
-const cursor=new TextUtils.TextCursor(this.lineEndings());
-const result=TextUtils.TextRange.createFromLocation(0,0);
-
-cursor.resetTo(sourceRange.offset);
-result.startLine=cursor.lineNumber();
-result.startColumn=cursor.columnNumber();
-
-cursor.advance(sourceRange.offset+sourceRange.length);
-result.endLine=cursor.lineNumber();
-result.endColumn=cursor.columnNumber();
-return result;
-}
-
-
-
-
-
-
-replaceRange(range,replacement){
-const sourceRange=this.toSourceRange(range);
-return this._value.substring(0,sourceRange.offset)+replacement+
-this._value.substring(sourceRange.offset+sourceRange.length);
-}
-
-
-
-
-
-extract(range){
-const sourceRange=this.toSourceRange(range);
-return this._value.substr(sourceRange.offset,sourceRange.length);
-}};
-
-
-
-TextUtils.Text.Position;
-
-
-
-
-TextUtils.TextCursor=class{
-
-
-
-constructor(lineEndings){
-this._lineEndings=lineEndings;
-this._offset=0;
-this._lineNumber=0;
-this._columnNumber=0;
-}
-
-
-
-
-advance(offset){
-this._offset=offset;
-while(this._lineNumber<this._lineEndings.length&&this._lineEndings[this._lineNumber]<this._offset)
-++this._lineNumber;
-this._columnNumber=this._lineNumber?this._offset-this._lineEndings[this._lineNumber-1]-1:this._offset;
-}
-
-
-
-
-offset(){
-return this._offset;
-}
-
-
-
-
-resetTo(offset){
-this._offset=offset;
-this._lineNumber=this._lineEndings.lowerBound(offset);
-this._columnNumber=this._lineNumber?this._offset-this._lineEndings[this._lineNumber-1]-1:this._offset;
-}
-
-
-
-
-lineNumber(){
-return this._lineNumber;
-}
-
-
-
-
-columnNumber(){
-return this._columnNumber;
-}};
-
-
-},{}],160:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-TextUtils.TextRange=class{
-
-
-
-
-
-
-constructor(startLine,startColumn,endLine,endColumn){
-this.startLine=startLine;
-this.startColumn=startColumn;
-this.endLine=endLine;
-this.endColumn=endColumn;
-}
-
-
-
-
-
-
-static createFromLocation(line,column){
-return new TextUtils.TextRange(line,column,line,column);
-}
-
-
-
-
-
-static fromObject(serializedTextRange){
-return new TextUtils.TextRange(
-serializedTextRange.startLine,serializedTextRange.startColumn,serializedTextRange.endLine,
-serializedTextRange.endColumn);
-}
-
-
-
-
-
-
-static comparator(range1,range2){
-return range1.compareTo(range2);
-}
-
-
-
-
-
-
-static fromEdit(oldRange,newText){
-let endLine=oldRange.startLine;
-let endColumn=oldRange.startColumn+newText.length;
-const lineEndings=newText.computeLineEndings();
-if(lineEndings.length>1){
-endLine=oldRange.startLine+lineEndings.length-1;
-const len=lineEndings.length;
-endColumn=lineEndings[len-1]-lineEndings[len-2]-1;
-}
-return new TextUtils.TextRange(oldRange.startLine,oldRange.startColumn,endLine,endColumn);
-}
-
-
-
-
-isEmpty(){
-return this.startLine===this.endLine&&this.startColumn===this.endColumn;
-}
-
-
-
-
-
-immediatelyPrecedes(range){
-if(!range)
-return false;
-return this.endLine===range.startLine&&this.endColumn===range.startColumn;
-}
-
-
-
-
-
-immediatelyFollows(range){
-if(!range)
-return false;
-return range.immediatelyPrecedes(this);
-}
-
-
-
-
-
-follows(range){
-return range.endLine===this.startLine&&range.endColumn<=this.startColumn||range.endLine<this.startLine;
-}
-
-
-
-
-get linesCount(){
-return this.endLine-this.startLine;
-}
-
-
-
-
-collapseToEnd(){
-return new TextUtils.TextRange(this.endLine,this.endColumn,this.endLine,this.endColumn);
-}
-
-
-
-
-collapseToStart(){
-return new TextUtils.TextRange(this.startLine,this.startColumn,this.startLine,this.startColumn);
-}
-
-
-
-
-normalize(){
-if(this.startLine>this.endLine||this.startLine===this.endLine&&this.startColumn>this.endColumn)
-return new TextUtils.TextRange(this.endLine,this.endColumn,this.startLine,this.startColumn);else
-
-return this.clone();
-}
-
-
-
-
-clone(){
-return new TextUtils.TextRange(this.startLine,this.startColumn,this.endLine,this.endColumn);
-}
-
-
-
-
-serializeToObject(){
-const serializedTextRange={};
-serializedTextRange.startLine=this.startLine;
-serializedTextRange.startColumn=this.startColumn;
-serializedTextRange.endLine=this.endLine;
-serializedTextRange.endColumn=this.endColumn;
-return serializedTextRange;
-}
-
-
-
-
-
-compareTo(other){
-if(this.startLine>other.startLine)
-return 1;
-if(this.startLine<other.startLine)
-return-1;
-if(this.startColumn>other.startColumn)
-return 1;
-if(this.startColumn<other.startColumn)
-return-1;
-return 0;
-}
-
-
-
-
-
-
-compareToPosition(lineNumber,columnNumber){
-if(lineNumber<this.startLine||lineNumber===this.startLine&&columnNumber<this.startColumn)
-return-1;
-if(lineNumber>this.endLine||lineNumber===this.endLine&&columnNumber>this.endColumn)
-return 1;
-return 0;
-}
-
-
-
-
-
-equal(other){
-return this.startLine===other.startLine&&this.endLine===other.endLine&&
-this.startColumn===other.startColumn&&this.endColumn===other.endColumn;
-}
-
-
-
-
-
-
-relativeTo(line,column){
-const relative=this.clone();
-
-if(this.startLine===line)
-relative.startColumn-=column;
-if(this.endLine===line)
-relative.endColumn-=column;
-
-relative.startLine-=line;
-relative.endLine-=line;
-return relative;
-}
-
-
-
-
-
-
-relativeFrom(line,column){
-const relative=this.clone();
-
-if(this.startLine===0)
-relative.startColumn+=column;
-if(this.endLine===0)
-relative.endColumn+=column;
-
-relative.startLine+=line;
-relative.endLine+=line;
-return relative;
-}
-
-
-
-
-
-
-rebaseAfterTextEdit(originalRange,editedRange){
-console.assert(originalRange.startLine===editedRange.startLine);
-console.assert(originalRange.startColumn===editedRange.startColumn);
-const rebase=this.clone();
-if(!this.follows(originalRange))
-return rebase;
-const lineDelta=editedRange.endLine-originalRange.endLine;
-const columnDelta=editedRange.endColumn-originalRange.endColumn;
-rebase.startLine+=lineDelta;
-rebase.endLine+=lineDelta;
-if(rebase.startLine===editedRange.endLine)
-rebase.startColumn+=columnDelta;
-if(rebase.endLine===editedRange.endLine)
-rebase.endColumn+=columnDelta;
-return rebase;
-}
-
-
-
-
-
-toString(){
-return JSON.stringify(this);
-}
-
-
-
-
-
-
-containsLocation(lineNumber,columnNumber){
-if(this.startLine===this.endLine)
-return this.startLine===lineNumber&&this.startColumn<=columnNumber&&columnNumber<=this.endColumn;
-if(this.startLine===lineNumber)
-return this.startColumn<=columnNumber;
-if(this.endLine===lineNumber)
-return columnNumber<=this.endColumn;
-return this.startLine<lineNumber&&lineNumber<this.endLine;
-}};
-
-
-
-
-
-
-TextUtils.SourceRange=class{
-
-
-
-
-constructor(offset,length){
-this.offset=offset;
-this.length=length;
-}};
-
-
-
-
-
-TextUtils.SourceEdit=class{
-
-
-
-
-
-constructor(sourceURL,oldRange,newText){
-this.sourceURL=sourceURL;
-this.oldRange=oldRange;
-this.newText=newText;
-}
-
-
-
-
-
-
-static comparator(edit1,edit2){
-return TextUtils.TextRange.comparator(edit1.oldRange,edit2.oldRange);
-}
-
-
-
-
-newRange(){
-return TextUtils.TextRange.fromEdit(this.oldRange,this.newText);
-}};
-
-
-},{}],161:[function(require,module,exports){
-
-
-
-
-'use strict';
-
-exports.TYPES={
-INTEGER:1,
-NUMBER:2,
-LENGTH:3,
-PERCENT:4,
-URL:5,
-COLOR:6,
-STRING:7,
-ANGLE:8,
-KEYWORD:9,
-NULL_OR_EMPTY_STR:10};
-
-
-
-
-var integerRegEx=/^[\-+]?[0-9]+$/;
-var numberRegEx=/^[\-+]?[0-9]*\.[0-9]+$/;
-var lengthRegEx=/^(0|[\-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw))$/;
-var percentRegEx=/^[\-+]?[0-9]*\.?[0-9]+%$/;
-var urlRegEx=/^url\(\s*([^\)]*)\s*\)$/;
-var stringRegEx=/^(\"[^\"]*\"|\'[^\']*\')$/;
-var colorRegEx1=/^#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])?$/;
-var colorRegEx2=/^rgb\(([^\)]*)\)$/;
-var colorRegEx3=/^rgba\(([^\)]*)\)$/;
-var angleRegEx=/^([\-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/;
-
-
-
-exports.valueType=function valueType(val){
-if(val===''||val===null){
-return exports.TYPES.NULL_OR_EMPTY_STR;
-}
-if(typeof val==='number'){
-val=val.toString();
-}
-
-if(typeof val!=='string'){
-return undefined;
-}
-
-if(integerRegEx.test(val)){
-return exports.TYPES.INTEGER;
-}
-if(numberRegEx.test(val)){
-return exports.TYPES.NUMBER;
-}
-if(lengthRegEx.test(val)){
-return exports.TYPES.LENGTH;
-}
-if(percentRegEx.test(val)){
-return exports.TYPES.PERCENT;
-}
-if(urlRegEx.test(val)){
-return exports.TYPES.URL;
-}
-if(stringRegEx.test(val)){
-return exports.TYPES.STRING;
-}
-if(angleRegEx.test(val)){
-return exports.TYPES.ANGLE;
-}
-if(colorRegEx1.test(val)){
-return exports.TYPES.COLOR;
-}
-var res=colorRegEx2.exec(val);
-var parts;
-if(res!==null){
-parts=res[1].split(/\s*,\s*/);
-if(parts.length!==3){
-return undefined;
-}
-if(parts.every(percentRegEx.test.bind(percentRegEx))||parts.every(integerRegEx.test.bind(integerRegEx))){
-return exports.TYPES.COLOR;
-}
-return undefined;
-}
-res=colorRegEx3.exec(val);
-if(res!==null){
-parts=res[1].split(/\s*,\s*/);
-if(parts.length!==4){
-return undefined;
-}
-if(parts.slice(0,3).every(percentRegEx.test.bind(percentRegEx))||parts.every(integerRegEx.test.bind(integerRegEx))){
-if(numberRegEx.test(parts[3])){
-return exports.TYPES.COLOR;
-}
-}
-return undefined;
-}
-
-
-val=val.toLowerCase();
-switch(val){
-case'maroon':
-case'red':
-case'orange':
-case'yellow':
-case'olive':
-case'purple':
-case'fuchsia':
-case'white':
-case'lime':
-case'green':
-case'navy':
-case'blue':
-case'aqua':
-case'teal':
-case'black':
-case'silver':
-case'gray':
-
-case'activeborder':
-case'activecaption':
-case'appworkspace':
-case'background':
-case'buttonface':
-case'buttonhighlight':
-case'buttonshadow':
-case'buttontext':
-case'captiontext':
-case'graytext':
-case'highlight':
-case'highlighttext':
-case'inactiveborder':
-case'inactivecaption':
-case'inactivecaptiontext':
-case'infobackground':
-case'infotext':
-case'menu':
-case'menutext':
-case'scrollbar':
-case'threeddarkshadow':
-case'threedface':
-case'threedhighlight':
-case'threedlightshadow':
-case'threedshadow':
-case'window':
-case'windowframe':
-case'windowtext':
-return exports.TYPES.COLOR;
-default:
-return exports.TYPES.KEYWORD;}
-
-};
-
-exports.parseInteger=function parseInteger(val){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.INTEGER){
-return undefined;
-}
-return String(parseInt(val,10));
-};
-
-exports.parseNumber=function parseNumber(val){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.NUMBER&&type!==exports.TYPES.INTEGER){
-return undefined;
-}
-return String(parseFloat(val));
-};
-
-exports.parseLength=function parseLength(val){
-if(val===0||val==='0'){
-return'0px';
-}
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.LENGTH){
-return undefined;
-}
-return val;
-};
-
-exports.parsePercent=function parsePercent(val){
-if(val===0||val==='0'){
-return'0%';
-}
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.PERCENT){
-return undefined;
-}
-return val;
-};
-
-
-exports.parseMeasurement=function parseMeasurement(val){
-var length=exports.parseLength(val);
-if(length!==undefined){
-return length;
-}
-return exports.parsePercent(val);
-};
-
-exports.parseUrl=function parseUrl(val){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-var res=urlRegEx.exec(val);
-
-if(!res){
-return undefined;
-}
-var str=res[1];
-
-if((str[0]==='"'||str[0]==="'")&&str[0]!==str[str.length-1]){
-return undefined;
-}
-if(str[0]==='"'||str[0]==="'"){
-str=str.substr(1,str.length-2);
-}
-
-var i;
-for(i=0;i<str.length;i++){
-switch(str[i]){
-case'(':
-case')':
-case' ':
-case'\t':
-case'\n':
-case"'":
-case'"':
-return undefined;
-case'\\':
-i++;
-break;}
-
-}
-
-return'url('+str+')';
-};
-
-exports.parseString=function parseString(val){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.STRING){
-return undefined;
-}
-var i;
-for(i=1;i<val.length-1;i++){
-switch(val[i]){
-case val[0]:
-return undefined;
-case'\\':
-i++;
-while(i<val.length-1&&/[0-9A-Fa-f]/.test(val[i])){
-i++;
-}
-break;}
-
-}
-if(i>=val.length){
-return undefined;
-}
-return val;
-};
-
-exports.parseColor=function parseColor(val){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-var red,green,blue,alpha=1;
-var parts;
-var res=colorRegEx1.exec(val);
-
-if(res){
-var hex=val.substr(1);
-if(hex.length===3){
-hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
-}
-red=parseInt(hex.substr(0,2),16);
-green=parseInt(hex.substr(2,2),16);
-blue=parseInt(hex.substr(4,2),16);
-return'rgb('+red+', '+green+', '+blue+')';
-}
-
-res=colorRegEx2.exec(val);
-if(res){
-parts=res[1].split(/\s*,\s*/);
-if(parts.length!==3){
-return undefined;
-}
-if(parts.every(percentRegEx.test.bind(percentRegEx))){
-red=Math.floor(parseFloat(parts[0].slice(0,-1))*255/100);
-green=Math.floor(parseFloat(parts[1].slice(0,-1))*255/100);
-blue=Math.floor(parseFloat(parts[2].slice(0,-1))*255/100);
-}else if(parts.every(integerRegEx.test.bind(integerRegEx))){
-red=parseInt(parts[0],10);
-green=parseInt(parts[1],10);
-blue=parseInt(parts[2],10);
-}else{
-return undefined;
-}
-red=Math.min(255,Math.max(0,red));
-green=Math.min(255,Math.max(0,green));
-blue=Math.min(255,Math.max(0,blue));
-return'rgb('+red+', '+green+', '+blue+')';
-}
-
-res=colorRegEx3.exec(val);
-if(res){
-parts=res[1].split(/\s*,\s*/);
-if(parts.length!==4){
-return undefined;
-}
-if(parts.slice(0,3).every(percentRegEx.test.bind(percentRegEx))){
-red=Math.floor(parseFloat(parts[0].slice(0,-1))*255/100);
-green=Math.floor(parseFloat(parts[1].slice(0,-1))*255/100);
-blue=Math.floor(parseFloat(parts[2].slice(0,-1))*255/100);
-alpha=parseFloat(parts[3]);
-}else if(parts.slice(0,3).every(integerRegEx.test.bind(integerRegEx))){
-red=parseInt(parts[0],10);
-green=parseInt(parts[1],10);
-blue=parseInt(parts[2],10);
-alpha=parseFloat(parts[3]);
-}else{
-return undefined;
-}
-if(isNaN(alpha)){
-alpha=1;
-}
-red=Math.min(255,Math.max(0,red));
-green=Math.min(255,Math.max(0,green));
-blue=Math.min(255,Math.max(0,blue));
-alpha=Math.min(1,Math.max(0,alpha));
-if(alpha===1){
-return'rgb('+red+', '+green+', '+blue+')';
-}
-return'rgba('+red+', '+green+', '+blue+', '+alpha+')';
-}
-
-if(type===exports.TYPES.COLOR){
-return val;
-}
-return undefined;
-};
-
-exports.parseAngle=function parseAngle(val){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.ANGLE){
-return undefined;
-}
-var res=angleRegEx.exec(val);
-var flt=parseFloat(res[1]);
-if(res[2]==='rad'){
-flt*=180/Math.PI;
-}else if(res[2]==='grad'){
-flt*=360/400;
-}
-
-while(flt<0){
-flt+=360;
-}
-while(flt>360){
-flt-=360;
-}
-return flt+'deg';
-};
-
-exports.parseKeyword=function parseKeyword(val,valid_keywords){
-var type=exports.valueType(val);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-return val;
-}
-if(type!==exports.TYPES.KEYWORD){
-return undefined;
-}
-val=val.toString().toLowerCase();
-var i;
-for(i=0;i<valid_keywords.length;i++){
-if(valid_keywords[i].toLowerCase()===val){
-return valid_keywords[i];
-}
-}
-return undefined;
-};
-
-
-var dashedToCamelCase=function(dashed){
-var i;
-var camel='';
-var nextCap=false;
-for(i=0;i<dashed.length;i++){
-if(dashed[i]!=='-'){
-camel+=nextCap?dashed[i].toUpperCase():dashed[i];
-nextCap=false;
-}else{
-nextCap=true;
-}
-}
-return camel;
-};
-exports.dashedToCamelCase=dashedToCamelCase;
-
-var is_space=/\s/;
-var opening_deliminators=['"','\'','('];
-var closing_deliminators=['"','\'',')'];
-
-var getParts=function(str){
-var deliminator_stack=[];
-var length=str.length;
-var i;
-var parts=[];
-var current_part='';
-var opening_index;
-var closing_index;
-for(i=0;i<length;i++){
-opening_index=opening_deliminators.indexOf(str[i]);
-closing_index=closing_deliminators.indexOf(str[i]);
-if(is_space.test(str[i])){
-if(deliminator_stack.length===0){
-if(current_part!==''){
-parts.push(current_part);
-}
-current_part='';
-}else{
-current_part+=str[i];
-}
-}else{
-if(str[i]==='\\'){
-i++;
-current_part+=str[i];
-}else{
-current_part+=str[i];
-if(closing_index!==-1&&closing_index===deliminator_stack[deliminator_stack.length-1]){
-deliminator_stack.pop();
-}else if(opening_index!==-1){
-deliminator_stack.push(opening_index);
-}
-}
-}
-}
-if(current_part!==''){
-parts.push(current_part);
-}
-return parts;
-};
-
-
-
-
-
-
-
-exports.shorthandParser=function parse(v,shorthand_for){
-var obj={};
-var type=exports.valueType(v);
-if(type===exports.TYPES.NULL_OR_EMPTY_STR){
-Object.keys(shorthand_for).forEach(function(property){
-obj[property]='';
-});
-return obj;
-}
-
-if(typeof v==='number'){
-v=v.toString();
-}
-
-if(typeof v!=='string'){
-return undefined;
-}
-
-if(v.toLowerCase()==='inherit'){
-return{};
-}
-var parts=getParts(v);
-var valid=true;
-parts.forEach(function(part){
-var part_valid=false;
-Object.keys(shorthand_for).forEach(function(property){
-if(shorthand_for[property].isValid(part)){
-part_valid=true;
-obj[property]=part;
-}
-});
-valid=valid&&part_valid;
-});
-if(!valid){
-return undefined;
-}
-return obj;
-};
-
-exports.shorthandSetter=function(property,shorthand_for){
-return function(v){
-var obj=exports.shorthandParser(v,shorthand_for);
-if(obj===undefined){
-return;
-}
-
-Object.keys(obj).forEach(function(subprop){
-
-
-var camel=dashedToCamelCase(subprop);
-this[camel]=obj[subprop];
-
-obj[subprop]=this[camel];
-this.removeProperty(subprop);
-
-if(obj[subprop]!==''){
-this._values[subprop]=obj[subprop];
-}
-},this);
-Object.keys(shorthand_for).forEach(function(subprop){
-if(!obj.hasOwnProperty(subprop)){
-this.removeProperty(subprop);
-delete this._values[subprop];
-}
-},this);
-
-
-
-
-this.removeProperty(property);
-var calculated=exports.shorthandGetter(property,shorthand_for).call(this);
-if(calculated!==''){
-this._setProperty(property,calculated);
-}
-};
-};
-
-exports.shorthandGetter=function(property,shorthand_for){
-return function(){
-if(this._values[property]!==undefined){
-return this.getPropertyValue(property);
-}
-return Object.keys(shorthand_for).map(function(subprop){
-return this.getPropertyValue(subprop);
-},this).filter(function(value){
-return value!=='';
-}).join(' ');
-};
-};
-
-
-
-
-
-
-exports.implicitSetter=function(property_before,property_after,isValid,parser){
-property_after=property_after||'';
-if(property_after!==''){
-property_after='-'+property_after;
-}
-var part_names=["top","right","bottom","left"];
-
-return function(v){
-if(typeof v==='number'){
-v=v.toString();
-}
-if(typeof v!=='string'){
-return undefined;
-}
-var parts;
-if(v.toLowerCase()==='inherit'||v===''){
-parts=[v];
-}else{
-parts=getParts(v);
-}
-if(parts.length<1||parts.length>4){
-return undefined;
-}
-
-if(!parts.every(isValid)){
-return undefined;
-}
-
-parts=parts.map(function(part){
-return parser(part);
-});
-this._setProperty(property_before+property_after,parts.join(' '));
-if(parts.length===1){
-parts[1]=parts[0];
-}
-if(parts.length===2){
-parts[2]=parts[0];
-}
-if(parts.length===3){
-parts[3]=parts[1];
-}
-
-for(var i=0;i<4;i++){
-var property=property_before+"-"+part_names[i]+property_after;
-this.removeProperty(property);
-if(parts[i]!==''){
-this._values[property]=parts[i];
-}
-}
-return v;
-};
-};
-
-
-
-
-
-
-
-exports.subImplicitSetter=function(prefix,part,isValid,parser){
-var property=prefix+'-'+part;
-var subparts=[prefix+"-top",prefix+"-right",prefix+"-bottom",prefix+"-left"];
-
-return function(v){
-if(typeof v==='number'){
-v=v.toString();
-}
-if(typeof v!=='string'){
-return undefined;
-}
-if(!isValid(v)){
-return undefined;
-}
-v=parser(v);
-this._setProperty(property,v);
-var parts=[];
-for(var i=0;i<4;i++){
-if(this._values[subparts[i]]==null||this._values[subparts[i]]===''){
-break;
-}
-parts.push(this._values[subparts[i]]);
-}
-if(parts.length===4){
-for(i=0;i<4;i++){
-this.removeProperty(subparts[i]);
-this._values[subparts[i]]=parts[i];
-}
-this._setProperty(prefix,parts.join(" "));
-}
-return v;
-};
-};
-
-
-var camel_to_dashed=/[A-Z]/g;
-
-var first_segment=/^\([^\-]\)-/;
-
-var vendor_prefixes=['o','moz','ms','webkit'];
-exports.camelToDashed=function(camel_case){
-var match;
-var dashed=camel_case.replace(camel_to_dashed,'-$&').toLowerCase();
-match=dashed.match(first_segment);
-if(match&&vendor_prefixes.indexOf(match[1])!==-1){
-dashed='-'+dashed;
-}
-return dashed;
-};
-
-},{}],162:[function(require,module,exports){
-(function webpackUniversalModuleDefinition(root,factory){
-
-if(typeof exports==='object'&&typeof module==='object')
-module.exports=factory();else
-if(typeof define==='function'&&define.amd)
-define([],factory);else
-
-if(typeof exports==='object')
-exports["esprima"]=factory();else
-
-root["esprima"]=factory();
-})(this,function(){
-return function(modules){
-
-var installedModules={};
-
-
-function __webpack_require__(moduleId){
-
-
-
-if(installedModules[moduleId])
-return installedModules[moduleId].exports;
-
-
-var module=installedModules[moduleId]={
-exports:{},
-id:moduleId,
-loaded:false};
-
-
-
-modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);
-
-
-module.loaded=true;
-
-
-return module.exports;
-}
-
-
-
-__webpack_require__.m=modules;
-
-
-__webpack_require__.c=installedModules;
-
-
-__webpack_require__.p="";
-
-
-return __webpack_require__(0);
-}(
-
-[
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Object.defineProperty(exports,"__esModule",{value:true});
-var comment_handler_1=__webpack_require__(1);
-var jsx_parser_1=__webpack_require__(3);
-var parser_1=__webpack_require__(8);
-var tokenizer_1=__webpack_require__(15);
-function parse(code,options,delegate){
-var commentHandler=null;
-var proxyDelegate=function(node,metadata){
-if(delegate){
-delegate(node,metadata);
-}
-if(commentHandler){
-commentHandler.visit(node,metadata);
-}
-};
-var parserDelegate=typeof delegate==='function'?proxyDelegate:null;
-var collectComment=false;
-if(options){
-collectComment=typeof options.comment==='boolean'&&options.comment;
-var attachComment=typeof options.attachComment==='boolean'&&options.attachComment;
-if(collectComment||attachComment){
-commentHandler=new comment_handler_1.CommentHandler();
-commentHandler.attach=attachComment;
-options.comment=true;
-parserDelegate=proxyDelegate;
-}
-}
-var isModule=false;
-if(options&&typeof options.sourceType==='string'){
-isModule=options.sourceType==='module';
-}
-var parser;
-if(options&&typeof options.jsx==='boolean'&&options.jsx){
-parser=new jsx_parser_1.JSXParser(code,options,parserDelegate);
-}else
-{
-parser=new parser_1.Parser(code,options,parserDelegate);
-}
-var program=isModule?parser.parseModule():parser.parseScript();
-var ast=program;
-if(collectComment&&commentHandler){
-ast.comments=commentHandler.comments;
-}
-if(parser.config.tokens){
-ast.tokens=parser.tokens;
-}
-if(parser.config.tolerant){
-ast.errors=parser.errorHandler.errors;
-}
-return ast;
-}
-exports.parse=parse;
-function parseModule(code,options,delegate){
-var parsingOptions=options||{};
-parsingOptions.sourceType='module';
-return parse(code,parsingOptions,delegate);
-}
-exports.parseModule=parseModule;
-function parseScript(code,options,delegate){
-var parsingOptions=options||{};
-parsingOptions.sourceType='script';
-return parse(code,parsingOptions,delegate);
-}
-exports.parseScript=parseScript;
-function tokenize(code,options,delegate){
-var tokenizer=new tokenizer_1.Tokenizer(code,options);
-var tokens;
-tokens=[];
-try{
-while(true){
-var token=tokenizer.getNextToken();
-if(!token){
-break;
-}
-if(delegate){
-token=delegate(token);
-}
-tokens.push(token);
-}
-}
-catch(e){
-tokenizer.errorHandler.tolerate(e);
-}
-if(tokenizer.errorHandler.tolerant){
-tokens.errors=tokenizer.errors();
-}
-return tokens;
-}
-exports.tokenize=tokenize;
-var syntax_1=__webpack_require__(2);
-exports.Syntax=syntax_1.Syntax;
-
-exports.version='4.0.1';
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-var syntax_1=__webpack_require__(2);
-var CommentHandler=function(){
-function CommentHandler(){
-this.attach=false;
-this.comments=[];
-this.stack=[];
-this.leading=[];
-this.trailing=[];
-}
-CommentHandler.prototype.insertInnerComments=function(node,metadata){
-
-
-if(node.type===syntax_1.Syntax.BlockStatement&&node.body.length===0){
-var innerComments=[];
-for(var i=this.leading.length-1;i>=0;--i){
-var entry=this.leading[i];
-if(metadata.end.offset>=entry.start){
-innerComments.unshift(entry.comment);
-this.leading.splice(i,1);
-this.trailing.splice(i,1);
-}
-}
-if(innerComments.length){
-node.innerComments=innerComments;
-}
-}
-};
-CommentHandler.prototype.findTrailingComments=function(metadata){
-var trailingComments=[];
-if(this.trailing.length>0){
-for(var i=this.trailing.length-1;i>=0;--i){
-var entry_1=this.trailing[i];
-if(entry_1.start>=metadata.end.offset){
-trailingComments.unshift(entry_1.comment);
-}
-}
-this.trailing.length=0;
-return trailingComments;
-}
-var entry=this.stack[this.stack.length-1];
-if(entry&&entry.node.trailingComments){
-var firstComment=entry.node.trailingComments[0];
-if(firstComment&&firstComment.range[0]>=metadata.end.offset){
-trailingComments=entry.node.trailingComments;
-delete entry.node.trailingComments;
-}
-}
-return trailingComments;
-};
-CommentHandler.prototype.findLeadingComments=function(metadata){
-var leadingComments=[];
-var target;
-while(this.stack.length>0){
-var entry=this.stack[this.stack.length-1];
-if(entry&&entry.start>=metadata.start.offset){
-target=entry.node;
-this.stack.pop();
-}else
-{
-break;
-}
-}
-if(target){
-var count=target.leadingComments?target.leadingComments.length:0;
-for(var i=count-1;i>=0;--i){
-var comment=target.leadingComments[i];
-if(comment.range[1]<=metadata.start.offset){
-leadingComments.unshift(comment);
-target.leadingComments.splice(i,1);
-}
-}
-if(target.leadingComments&&target.leadingComments.length===0){
-delete target.leadingComments;
-}
-return leadingComments;
-}
-for(var i=this.leading.length-1;i>=0;--i){
-var entry=this.leading[i];
-if(entry.start<=metadata.start.offset){
-leadingComments.unshift(entry.comment);
-this.leading.splice(i,1);
-}
-}
-return leadingComments;
-};
-CommentHandler.prototype.visitNode=function(node,metadata){
-if(node.type===syntax_1.Syntax.Program&&node.body.length>0){
-return;
-}
-this.insertInnerComments(node,metadata);
-var trailingComments=this.findTrailingComments(metadata);
-var leadingComments=this.findLeadingComments(metadata);
-if(leadingComments.length>0){
-node.leadingComments=leadingComments;
-}
-if(trailingComments.length>0){
-node.trailingComments=trailingComments;
-}
-this.stack.push({
-node:node,
-start:metadata.start.offset});
-
-};
-CommentHandler.prototype.visitComment=function(node,metadata){
-var type=node.type[0]==='L'?'Line':'Block';
-var comment={
-type:type,
-value:node.value};
-
-if(node.range){
-comment.range=node.range;
-}
-if(node.loc){
-comment.loc=node.loc;
-}
-this.comments.push(comment);
-if(this.attach){
-var entry={
-comment:{
-type:type,
-value:node.value,
-range:[metadata.start.offset,metadata.end.offset]},
-
-start:metadata.start.offset};
-
-if(node.loc){
-entry.comment.loc=node.loc;
-}
-node.type=type;
-this.leading.push(entry);
-this.trailing.push(entry);
-}
-};
-CommentHandler.prototype.visit=function(node,metadata){
-if(node.type==='LineComment'){
-this.visitComment(node,metadata);
-}else
-if(node.type==='BlockComment'){
-this.visitComment(node,metadata);
-}else
-if(this.attach){
-this.visitNode(node,metadata);
-}
-};
-return CommentHandler;
-}();
-exports.CommentHandler=CommentHandler;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-exports.Syntax={
-AssignmentExpression:'AssignmentExpression',
-AssignmentPattern:'AssignmentPattern',
-ArrayExpression:'ArrayExpression',
-ArrayPattern:'ArrayPattern',
-ArrowFunctionExpression:'ArrowFunctionExpression',
-AwaitExpression:'AwaitExpression',
-BlockStatement:'BlockStatement',
-BinaryExpression:'BinaryExpression',
-BreakStatement:'BreakStatement',
-CallExpression:'CallExpression',
-CatchClause:'CatchClause',
-ClassBody:'ClassBody',
-ClassDeclaration:'ClassDeclaration',
-ClassExpression:'ClassExpression',
-ConditionalExpression:'ConditionalExpression',
-ContinueStatement:'ContinueStatement',
-DoWhileStatement:'DoWhileStatement',
-DebuggerStatement:'DebuggerStatement',
-EmptyStatement:'EmptyStatement',
-ExportAllDeclaration:'ExportAllDeclaration',
-ExportDefaultDeclaration:'ExportDefaultDeclaration',
-ExportNamedDeclaration:'ExportNamedDeclaration',
-ExportSpecifier:'ExportSpecifier',
-ExpressionStatement:'ExpressionStatement',
-ForStatement:'ForStatement',
-ForOfStatement:'ForOfStatement',
-ForInStatement:'ForInStatement',
-FunctionDeclaration:'FunctionDeclaration',
-FunctionExpression:'FunctionExpression',
-Identifier:'Identifier',
-IfStatement:'IfStatement',
-ImportDeclaration:'ImportDeclaration',
-ImportDefaultSpecifier:'ImportDefaultSpecifier',
-ImportNamespaceSpecifier:'ImportNamespaceSpecifier',
-ImportSpecifier:'ImportSpecifier',
-Literal:'Literal',
-LabeledStatement:'LabeledStatement',
-LogicalExpression:'LogicalExpression',
-MemberExpression:'MemberExpression',
-MetaProperty:'MetaProperty',
-MethodDefinition:'MethodDefinition',
-NewExpression:'NewExpression',
-ObjectExpression:'ObjectExpression',
-ObjectPattern:'ObjectPattern',
-Program:'Program',
-Property:'Property',
-RestElement:'RestElement',
-ReturnStatement:'ReturnStatement',
-SequenceExpression:'SequenceExpression',
-SpreadElement:'SpreadElement',
-Super:'Super',
-SwitchCase:'SwitchCase',
-SwitchStatement:'SwitchStatement',
-TaggedTemplateExpression:'TaggedTemplateExpression',
-TemplateElement:'TemplateElement',
-TemplateLiteral:'TemplateLiteral',
-ThisExpression:'ThisExpression',
-ThrowStatement:'ThrowStatement',
-TryStatement:'TryStatement',
-UnaryExpression:'UnaryExpression',
-UpdateExpression:'UpdateExpression',
-VariableDeclaration:'VariableDeclaration',
-VariableDeclarator:'VariableDeclarator',
-WhileStatement:'WhileStatement',
-WithStatement:'WithStatement',
-YieldExpression:'YieldExpression'};
-
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-
-var __extends=this&&this.__extends||function(){
-var extendStatics=Object.setPrototypeOf||
-{__proto__:[]}instanceof Array&&function(d,b){d.__proto__=b;}||
-function(d,b){for(var p in b)if(b.hasOwnProperty(p))d[p]=b[p];};
-return function(d,b){
-extendStatics(d,b);
-function __(){this.constructor=d;}
-d.prototype=b===null?Object.create(b):(__.prototype=b.prototype,new __());
-};
-}();
-Object.defineProperty(exports,"__esModule",{value:true});
-var character_1=__webpack_require__(4);
-var JSXNode=__webpack_require__(5);
-var jsx_syntax_1=__webpack_require__(6);
-var Node=__webpack_require__(7);
-var parser_1=__webpack_require__(8);
-var token_1=__webpack_require__(13);
-var xhtml_entities_1=__webpack_require__(14);
-token_1.TokenName[100]='JSXIdentifier';
-token_1.TokenName[101]='JSXText';
-
-function getQualifiedElementName(elementName){
-var qualifiedName;
-switch(elementName.type){
-case jsx_syntax_1.JSXSyntax.JSXIdentifier:
-var id=elementName;
-qualifiedName=id.name;
-break;
-case jsx_syntax_1.JSXSyntax.JSXNamespacedName:
-var ns=elementName;
-qualifiedName=getQualifiedElementName(ns.namespace)+':'+
-getQualifiedElementName(ns.name);
-break;
-case jsx_syntax_1.JSXSyntax.JSXMemberExpression:
-var expr=elementName;
-qualifiedName=getQualifiedElementName(expr.object)+'.'+
-getQualifiedElementName(expr.property);
-break;
-
-default:
-break;}
-
-return qualifiedName;
-}
-var JSXParser=function(_super){
-__extends(JSXParser,_super);
-function JSXParser(code,options,delegate){
-return _super.call(this,code,options,delegate)||this;
-}
-JSXParser.prototype.parsePrimaryExpression=function(){
-return this.match('<')?this.parseJSXRoot():_super.prototype.parsePrimaryExpression.call(this);
-};
-JSXParser.prototype.startJSX=function(){
-
-this.scanner.index=this.startMarker.index;
-this.scanner.lineNumber=this.startMarker.line;
-this.scanner.lineStart=this.startMarker.index-this.startMarker.column;
-};
-JSXParser.prototype.finishJSX=function(){
-
-this.nextToken();
-};
-JSXParser.prototype.reenterJSX=function(){
-this.startJSX();
-this.expectJSX('}');
-
-if(this.config.tokens){
-this.tokens.pop();
-}
-};
-JSXParser.prototype.createJSXNode=function(){
-this.collectComments();
-return{
-index:this.scanner.index,
-line:this.scanner.lineNumber,
-column:this.scanner.index-this.scanner.lineStart};
-
-};
-JSXParser.prototype.createJSXChildNode=function(){
-return{
-index:this.scanner.index,
-line:this.scanner.lineNumber,
-column:this.scanner.index-this.scanner.lineStart};
-
-};
-JSXParser.prototype.scanXHTMLEntity=function(quote){
-var result='&';
-var valid=true;
-var terminated=false;
-var numeric=false;
-var hex=false;
-while(!this.scanner.eof()&&valid&&!terminated){
-var ch=this.scanner.source[this.scanner.index];
-if(ch===quote){
-break;
-}
-terminated=ch===';';
-result+=ch;
-++this.scanner.index;
-if(!terminated){
-switch(result.length){
-case 2:
-
-numeric=ch==='#';
-break;
-case 3:
-if(numeric){
-
-hex=ch==='x';
-valid=hex||character_1.Character.isDecimalDigit(ch.charCodeAt(0));
-numeric=numeric&&!hex;
-}
-break;
-default:
-valid=valid&&!(numeric&&!character_1.Character.isDecimalDigit(ch.charCodeAt(0)));
-valid=valid&&!(hex&&!character_1.Character.isHexDigit(ch.charCodeAt(0)));
-break;}
-
-}
-}
-if(valid&&terminated&&result.length>2){
-
-var str=result.substr(1,result.length-2);
-if(numeric&&str.length>1){
-result=String.fromCharCode(parseInt(str.substr(1),10));
-}else
-if(hex&&str.length>2){
-result=String.fromCharCode(parseInt('0'+str.substr(1),16));
-}else
-if(!numeric&&!hex&&xhtml_entities_1.XHTMLEntities[str]){
-result=xhtml_entities_1.XHTMLEntities[str];
-}
-}
-return result;
-};
-
-JSXParser.prototype.lexJSX=function(){
-var cp=this.scanner.source.charCodeAt(this.scanner.index);
-
-if(cp===60||cp===62||cp===47||cp===58||cp===61||cp===123||cp===125){
-var value=this.scanner.source[this.scanner.index++];
-return{
-type:7,
-value:value,
-lineNumber:this.scanner.lineNumber,
-lineStart:this.scanner.lineStart,
-start:this.scanner.index-1,
-end:this.scanner.index};
-
-}
-
-if(cp===34||cp===39){
-var start=this.scanner.index;
-var quote=this.scanner.source[this.scanner.index++];
-var str='';
-while(!this.scanner.eof()){
-var ch=this.scanner.source[this.scanner.index++];
-if(ch===quote){
-break;
-}else
-if(ch==='&'){
-str+=this.scanXHTMLEntity(quote);
-}else
-{
-str+=ch;
-}
-}
-return{
-type:8,
-value:str,
-lineNumber:this.scanner.lineNumber,
-lineStart:this.scanner.lineStart,
-start:start,
-end:this.scanner.index};
-
-}
-
-if(cp===46){
-var n1=this.scanner.source.charCodeAt(this.scanner.index+1);
-var n2=this.scanner.source.charCodeAt(this.scanner.index+2);
-var value=n1===46&&n2===46?'...':'.';
-var start=this.scanner.index;
-this.scanner.index+=value.length;
-return{
-type:7,
-value:value,
-lineNumber:this.scanner.lineNumber,
-lineStart:this.scanner.lineStart,
-start:start,
-end:this.scanner.index};
-
-}
-
-if(cp===96){
-
-return{
-type:10,
-value:'',
-lineNumber:this.scanner.lineNumber,
-lineStart:this.scanner.lineStart,
-start:this.scanner.index,
-end:this.scanner.index};
-
-}
-
-if(character_1.Character.isIdentifierStart(cp)&&cp!==92){
-var start=this.scanner.index;
-++this.scanner.index;
-while(!this.scanner.eof()){
-var ch=this.scanner.source.charCodeAt(this.scanner.index);
-if(character_1.Character.isIdentifierPart(ch)&&ch!==92){
-++this.scanner.index;
-}else
-if(ch===45){
-
-++this.scanner.index;
-}else
-{
-break;
-}
-}
-var id=this.scanner.source.slice(start,this.scanner.index);
-return{
-type:100,
-value:id,
-lineNumber:this.scanner.lineNumber,
-lineStart:this.scanner.lineStart,
-start:start,
-end:this.scanner.index};
-
-}
-return this.scanner.lex();
-};
-JSXParser.prototype.nextJSXToken=function(){
-this.collectComments();
-this.startMarker.index=this.scanner.index;
-this.startMarker.line=this.scanner.lineNumber;
-this.startMarker.column=this.scanner.index-this.scanner.lineStart;
-var token=this.lexJSX();
-this.lastMarker.index=this.scanner.index;
-this.lastMarker.line=this.scanner.lineNumber;
-this.lastMarker.column=this.scanner.index-this.scanner.lineStart;
-if(this.config.tokens){
-this.tokens.push(this.convertToken(token));
-}
-return token;
-};
-JSXParser.prototype.nextJSXText=function(){
-this.startMarker.index=this.scanner.index;
-this.startMarker.line=this.scanner.lineNumber;
-this.startMarker.column=this.scanner.index-this.scanner.lineStart;
-var start=this.scanner.index;
-var text='';
-while(!this.scanner.eof()){
-var ch=this.scanner.source[this.scanner.index];
-if(ch==='{'||ch==='<'){
-break;
-}
-++this.scanner.index;
-text+=ch;
-if(character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-++this.scanner.lineNumber;
-if(ch==='\r'&&this.scanner.source[this.scanner.index]==='\n'){
-++this.scanner.index;
-}
-this.scanner.lineStart=this.scanner.index;
-}
-}
-this.lastMarker.index=this.scanner.index;
-this.lastMarker.line=this.scanner.lineNumber;
-this.lastMarker.column=this.scanner.index-this.scanner.lineStart;
-var token={
-type:101,
-value:text,
-lineNumber:this.scanner.lineNumber,
-lineStart:this.scanner.lineStart,
-start:start,
-end:this.scanner.index};
-
-if(text.length>0&&this.config.tokens){
-this.tokens.push(this.convertToken(token));
-}
-return token;
-};
-JSXParser.prototype.peekJSXToken=function(){
-var state=this.scanner.saveState();
-this.scanner.scanComments();
-var next=this.lexJSX();
-this.scanner.restoreState(state);
-return next;
-};
-
-
-JSXParser.prototype.expectJSX=function(value){
-var token=this.nextJSXToken();
-if(token.type!==7||token.value!==value){
-this.throwUnexpectedToken(token);
-}
-};
-
-JSXParser.prototype.matchJSX=function(value){
-var next=this.peekJSXToken();
-return next.type===7&&next.value===value;
-};
-JSXParser.prototype.parseJSXIdentifier=function(){
-var node=this.createJSXNode();
-var token=this.nextJSXToken();
-if(token.type!==100){
-this.throwUnexpectedToken(token);
-}
-return this.finalize(node,new JSXNode.JSXIdentifier(token.value));
-};
-JSXParser.prototype.parseJSXElementName=function(){
-var node=this.createJSXNode();
-var elementName=this.parseJSXIdentifier();
-if(this.matchJSX(':')){
-var namespace=elementName;
-this.expectJSX(':');
-var name_1=this.parseJSXIdentifier();
-elementName=this.finalize(node,new JSXNode.JSXNamespacedName(namespace,name_1));
-}else
-if(this.matchJSX('.')){
-while(this.matchJSX('.')){
-var object=elementName;
-this.expectJSX('.');
-var property=this.parseJSXIdentifier();
-elementName=this.finalize(node,new JSXNode.JSXMemberExpression(object,property));
-}
-}
-return elementName;
-};
-JSXParser.prototype.parseJSXAttributeName=function(){
-var node=this.createJSXNode();
-var attributeName;
-var identifier=this.parseJSXIdentifier();
-if(this.matchJSX(':')){
-var namespace=identifier;
-this.expectJSX(':');
-var name_2=this.parseJSXIdentifier();
-attributeName=this.finalize(node,new JSXNode.JSXNamespacedName(namespace,name_2));
-}else
-{
-attributeName=identifier;
-}
-return attributeName;
-};
-JSXParser.prototype.parseJSXStringLiteralAttribute=function(){
-var node=this.createJSXNode();
-var token=this.nextJSXToken();
-if(token.type!==8){
-this.throwUnexpectedToken(token);
-}
-var raw=this.getTokenRaw(token);
-return this.finalize(node,new Node.Literal(token.value,raw));
-};
-JSXParser.prototype.parseJSXExpressionAttribute=function(){
-var node=this.createJSXNode();
-this.expectJSX('{');
-this.finishJSX();
-if(this.match('}')){
-this.tolerateError('JSX attributes must only be assigned a non-empty expression');
-}
-var expression=this.parseAssignmentExpression();
-this.reenterJSX();
-return this.finalize(node,new JSXNode.JSXExpressionContainer(expression));
-};
-JSXParser.prototype.parseJSXAttributeValue=function(){
-return this.matchJSX('{')?this.parseJSXExpressionAttribute():
-this.matchJSX('<')?this.parseJSXElement():this.parseJSXStringLiteralAttribute();
-};
-JSXParser.prototype.parseJSXNameValueAttribute=function(){
-var node=this.createJSXNode();
-var name=this.parseJSXAttributeName();
-var value=null;
-if(this.matchJSX('=')){
-this.expectJSX('=');
-value=this.parseJSXAttributeValue();
-}
-return this.finalize(node,new JSXNode.JSXAttribute(name,value));
-};
-JSXParser.prototype.parseJSXSpreadAttribute=function(){
-var node=this.createJSXNode();
-this.expectJSX('{');
-this.expectJSX('...');
-this.finishJSX();
-var argument=this.parseAssignmentExpression();
-this.reenterJSX();
-return this.finalize(node,new JSXNode.JSXSpreadAttribute(argument));
-};
-JSXParser.prototype.parseJSXAttributes=function(){
-var attributes=[];
-while(!this.matchJSX('/')&&!this.matchJSX('>')){
-var attribute=this.matchJSX('{')?this.parseJSXSpreadAttribute():
-this.parseJSXNameValueAttribute();
-attributes.push(attribute);
-}
-return attributes;
-};
-JSXParser.prototype.parseJSXOpeningElement=function(){
-var node=this.createJSXNode();
-this.expectJSX('<');
-var name=this.parseJSXElementName();
-var attributes=this.parseJSXAttributes();
-var selfClosing=this.matchJSX('/');
-if(selfClosing){
-this.expectJSX('/');
-}
-this.expectJSX('>');
-return this.finalize(node,new JSXNode.JSXOpeningElement(name,selfClosing,attributes));
-};
-JSXParser.prototype.parseJSXBoundaryElement=function(){
-var node=this.createJSXNode();
-this.expectJSX('<');
-if(this.matchJSX('/')){
-this.expectJSX('/');
-var name_3=this.parseJSXElementName();
-this.expectJSX('>');
-return this.finalize(node,new JSXNode.JSXClosingElement(name_3));
-}
-var name=this.parseJSXElementName();
-var attributes=this.parseJSXAttributes();
-var selfClosing=this.matchJSX('/');
-if(selfClosing){
-this.expectJSX('/');
-}
-this.expectJSX('>');
-return this.finalize(node,new JSXNode.JSXOpeningElement(name,selfClosing,attributes));
-};
-JSXParser.prototype.parseJSXEmptyExpression=function(){
-var node=this.createJSXChildNode();
-this.collectComments();
-this.lastMarker.index=this.scanner.index;
-this.lastMarker.line=this.scanner.lineNumber;
-this.lastMarker.column=this.scanner.index-this.scanner.lineStart;
-return this.finalize(node,new JSXNode.JSXEmptyExpression());
-};
-JSXParser.prototype.parseJSXExpressionContainer=function(){
-var node=this.createJSXNode();
-this.expectJSX('{');
-var expression;
-if(this.matchJSX('}')){
-expression=this.parseJSXEmptyExpression();
-this.expectJSX('}');
-}else
-{
-this.finishJSX();
-expression=this.parseAssignmentExpression();
-this.reenterJSX();
-}
-return this.finalize(node,new JSXNode.JSXExpressionContainer(expression));
-};
-JSXParser.prototype.parseJSXChildren=function(){
-var children=[];
-while(!this.scanner.eof()){
-var node=this.createJSXChildNode();
-var token=this.nextJSXText();
-if(token.start<token.end){
-var raw=this.getTokenRaw(token);
-var child=this.finalize(node,new JSXNode.JSXText(token.value,raw));
-children.push(child);
-}
-if(this.scanner.source[this.scanner.index]==='{'){
-var container=this.parseJSXExpressionContainer();
-children.push(container);
-}else
-{
-break;
-}
-}
-return children;
-};
-JSXParser.prototype.parseComplexJSXElement=function(el){
-var stack=[];
-while(!this.scanner.eof()){
-el.children=el.children.concat(this.parseJSXChildren());
-var node=this.createJSXChildNode();
-var element=this.parseJSXBoundaryElement();
-if(element.type===jsx_syntax_1.JSXSyntax.JSXOpeningElement){
-var opening=element;
-if(opening.selfClosing){
-var child=this.finalize(node,new JSXNode.JSXElement(opening,[],null));
-el.children.push(child);
-}else
-{
-stack.push(el);
-el={node:node,opening:opening,closing:null,children:[]};
-}
-}
-if(element.type===jsx_syntax_1.JSXSyntax.JSXClosingElement){
-el.closing=element;
-var open_1=getQualifiedElementName(el.opening.name);
-var close_1=getQualifiedElementName(el.closing.name);
-if(open_1!==close_1){
-this.tolerateError('Expected corresponding JSX closing tag for %0',open_1);
-}
-if(stack.length>0){
-var child=this.finalize(el.node,new JSXNode.JSXElement(el.opening,el.children,el.closing));
-el=stack[stack.length-1];
-el.children.push(child);
-stack.pop();
-}else
-{
-break;
-}
-}
-}
-return el;
-};
-JSXParser.prototype.parseJSXElement=function(){
-var node=this.createJSXNode();
-var opening=this.parseJSXOpeningElement();
-var children=[];
-var closing=null;
-if(!opening.selfClosing){
-var el=this.parseComplexJSXElement({node:node,opening:opening,closing:closing,children:children});
-children=el.children;
-closing=el.closing;
-}
-return this.finalize(node,new JSXNode.JSXElement(opening,children,closing));
-};
-JSXParser.prototype.parseJSXRoot=function(){
-
-if(this.config.tokens){
-this.tokens.pop();
-}
-this.startJSX();
-var element=this.parseJSXElement();
-this.finishJSX();
-return element;
-};
-JSXParser.prototype.isStartOfExpression=function(){
-return _super.prototype.isStartOfExpression.call(this)||this.match('<');
-};
-return JSXParser;
-}(parser_1.Parser);
-exports.JSXParser=JSXParser;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-
-var Regex={
-
-NonAsciiIdentifierStart:/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,
-
-NonAsciiIdentifierPart:/[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/};
-
-exports.Character={
-
-fromCodePoint:function(cp){
-return cp<0x10000?String.fromCharCode(cp):
-String.fromCharCode(0xD800+(cp-0x10000>>10))+
-String.fromCharCode(0xDC00+(cp-0x10000&1023));
-},
-
-isWhiteSpace:function(cp){
-return cp===0x20||cp===0x09||cp===0x0B||cp===0x0C||cp===0xA0||
-cp>=0x1680&&[0x1680,0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,0x2008,0x2009,0x200A,0x202F,0x205F,0x3000,0xFEFF].indexOf(cp)>=0;
-},
-
-isLineTerminator:function(cp){
-return cp===0x0A||cp===0x0D||cp===0x2028||cp===0x2029;
-},
-
-isIdentifierStart:function(cp){
-return cp===0x24||cp===0x5F||
-cp>=0x41&&cp<=0x5A||
-cp>=0x61&&cp<=0x7A||
-cp===0x5C||
-cp>=0x80&&Regex.NonAsciiIdentifierStart.test(exports.Character.fromCodePoint(cp));
-},
-isIdentifierPart:function(cp){
-return cp===0x24||cp===0x5F||
-cp>=0x41&&cp<=0x5A||
-cp>=0x61&&cp<=0x7A||
-cp>=0x30&&cp<=0x39||
-cp===0x5C||
-cp>=0x80&&Regex.NonAsciiIdentifierPart.test(exports.Character.fromCodePoint(cp));
-},
-
-isDecimalDigit:function(cp){
-return cp>=0x30&&cp<=0x39;
-},
-isHexDigit:function(cp){
-return cp>=0x30&&cp<=0x39||
-cp>=0x41&&cp<=0x46||
-cp>=0x61&&cp<=0x66;
-},
-isOctalDigit:function(cp){
-return cp>=0x30&&cp<=0x37;
-}};
-
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-var jsx_syntax_1=__webpack_require__(6);
-
-var JSXClosingElement=function(){
-function JSXClosingElement(name){
-this.type=jsx_syntax_1.JSXSyntax.JSXClosingElement;
-this.name=name;
-}
-return JSXClosingElement;
-}();
-exports.JSXClosingElement=JSXClosingElement;
-var JSXElement=function(){
-function JSXElement(openingElement,children,closingElement){
-this.type=jsx_syntax_1.JSXSyntax.JSXElement;
-this.openingElement=openingElement;
-this.children=children;
-this.closingElement=closingElement;
-}
-return JSXElement;
-}();
-exports.JSXElement=JSXElement;
-var JSXEmptyExpression=function(){
-function JSXEmptyExpression(){
-this.type=jsx_syntax_1.JSXSyntax.JSXEmptyExpression;
-}
-return JSXEmptyExpression;
-}();
-exports.JSXEmptyExpression=JSXEmptyExpression;
-var JSXExpressionContainer=function(){
-function JSXExpressionContainer(expression){
-this.type=jsx_syntax_1.JSXSyntax.JSXExpressionContainer;
-this.expression=expression;
-}
-return JSXExpressionContainer;
-}();
-exports.JSXExpressionContainer=JSXExpressionContainer;
-var JSXIdentifier=function(){
-function JSXIdentifier(name){
-this.type=jsx_syntax_1.JSXSyntax.JSXIdentifier;
-this.name=name;
-}
-return JSXIdentifier;
-}();
-exports.JSXIdentifier=JSXIdentifier;
-var JSXMemberExpression=function(){
-function JSXMemberExpression(object,property){
-this.type=jsx_syntax_1.JSXSyntax.JSXMemberExpression;
-this.object=object;
-this.property=property;
-}
-return JSXMemberExpression;
-}();
-exports.JSXMemberExpression=JSXMemberExpression;
-var JSXAttribute=function(){
-function JSXAttribute(name,value){
-this.type=jsx_syntax_1.JSXSyntax.JSXAttribute;
-this.name=name;
-this.value=value;
-}
-return JSXAttribute;
-}();
-exports.JSXAttribute=JSXAttribute;
-var JSXNamespacedName=function(){
-function JSXNamespacedName(namespace,name){
-this.type=jsx_syntax_1.JSXSyntax.JSXNamespacedName;
-this.namespace=namespace;
-this.name=name;
-}
-return JSXNamespacedName;
-}();
-exports.JSXNamespacedName=JSXNamespacedName;
-var JSXOpeningElement=function(){
-function JSXOpeningElement(name,selfClosing,attributes){
-this.type=jsx_syntax_1.JSXSyntax.JSXOpeningElement;
-this.name=name;
-this.selfClosing=selfClosing;
-this.attributes=attributes;
-}
-return JSXOpeningElement;
-}();
-exports.JSXOpeningElement=JSXOpeningElement;
-var JSXSpreadAttribute=function(){
-function JSXSpreadAttribute(argument){
-this.type=jsx_syntax_1.JSXSyntax.JSXSpreadAttribute;
-this.argument=argument;
-}
-return JSXSpreadAttribute;
-}();
-exports.JSXSpreadAttribute=JSXSpreadAttribute;
-var JSXText=function(){
-function JSXText(value,raw){
-this.type=jsx_syntax_1.JSXSyntax.JSXText;
-this.value=value;
-this.raw=raw;
-}
-return JSXText;
-}();
-exports.JSXText=JSXText;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-exports.JSXSyntax={
-JSXAttribute:'JSXAttribute',
-JSXClosingElement:'JSXClosingElement',
-JSXElement:'JSXElement',
-JSXEmptyExpression:'JSXEmptyExpression',
-JSXExpressionContainer:'JSXExpressionContainer',
-JSXIdentifier:'JSXIdentifier',
-JSXMemberExpression:'JSXMemberExpression',
-JSXNamespacedName:'JSXNamespacedName',
-JSXOpeningElement:'JSXOpeningElement',
-JSXSpreadAttribute:'JSXSpreadAttribute',
-JSXText:'JSXText'};
-
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-var syntax_1=__webpack_require__(2);
-
-var ArrayExpression=function(){
-function ArrayExpression(elements){
-this.type=syntax_1.Syntax.ArrayExpression;
-this.elements=elements;
-}
-return ArrayExpression;
-}();
-exports.ArrayExpression=ArrayExpression;
-var ArrayPattern=function(){
-function ArrayPattern(elements){
-this.type=syntax_1.Syntax.ArrayPattern;
-this.elements=elements;
-}
-return ArrayPattern;
-}();
-exports.ArrayPattern=ArrayPattern;
-var ArrowFunctionExpression=function(){
-function ArrowFunctionExpression(params,body,expression){
-this.type=syntax_1.Syntax.ArrowFunctionExpression;
-this.id=null;
-this.params=params;
-this.body=body;
-this.generator=false;
-this.expression=expression;
-this.async=false;
-}
-return ArrowFunctionExpression;
-}();
-exports.ArrowFunctionExpression=ArrowFunctionExpression;
-var AssignmentExpression=function(){
-function AssignmentExpression(operator,left,right){
-this.type=syntax_1.Syntax.AssignmentExpression;
-this.operator=operator;
-this.left=left;
-this.right=right;
-}
-return AssignmentExpression;
-}();
-exports.AssignmentExpression=AssignmentExpression;
-var AssignmentPattern=function(){
-function AssignmentPattern(left,right){
-this.type=syntax_1.Syntax.AssignmentPattern;
-this.left=left;
-this.right=right;
-}
-return AssignmentPattern;
-}();
-exports.AssignmentPattern=AssignmentPattern;
-var AsyncArrowFunctionExpression=function(){
-function AsyncArrowFunctionExpression(params,body,expression){
-this.type=syntax_1.Syntax.ArrowFunctionExpression;
-this.id=null;
-this.params=params;
-this.body=body;
-this.generator=false;
-this.expression=expression;
-this.async=true;
-}
-return AsyncArrowFunctionExpression;
-}();
-exports.AsyncArrowFunctionExpression=AsyncArrowFunctionExpression;
-var AsyncFunctionDeclaration=function(){
-function AsyncFunctionDeclaration(id,params,body){
-this.type=syntax_1.Syntax.FunctionDeclaration;
-this.id=id;
-this.params=params;
-this.body=body;
-this.generator=false;
-this.expression=false;
-this.async=true;
-}
-return AsyncFunctionDeclaration;
-}();
-exports.AsyncFunctionDeclaration=AsyncFunctionDeclaration;
-var AsyncFunctionExpression=function(){
-function AsyncFunctionExpression(id,params,body){
-this.type=syntax_1.Syntax.FunctionExpression;
-this.id=id;
-this.params=params;
-this.body=body;
-this.generator=false;
-this.expression=false;
-this.async=true;
-}
-return AsyncFunctionExpression;
-}();
-exports.AsyncFunctionExpression=AsyncFunctionExpression;
-var AwaitExpression=function(){
-function AwaitExpression(argument){
-this.type=syntax_1.Syntax.AwaitExpression;
-this.argument=argument;
-}
-return AwaitExpression;
-}();
-exports.AwaitExpression=AwaitExpression;
-var BinaryExpression=function(){
-function BinaryExpression(operator,left,right){
-var logical=operator==='||'||operator==='&&';
-this.type=logical?syntax_1.Syntax.LogicalExpression:syntax_1.Syntax.BinaryExpression;
-this.operator=operator;
-this.left=left;
-this.right=right;
-}
-return BinaryExpression;
-}();
-exports.BinaryExpression=BinaryExpression;
-var BlockStatement=function(){
-function BlockStatement(body){
-this.type=syntax_1.Syntax.BlockStatement;
-this.body=body;
-}
-return BlockStatement;
-}();
-exports.BlockStatement=BlockStatement;
-var BreakStatement=function(){
-function BreakStatement(label){
-this.type=syntax_1.Syntax.BreakStatement;
-this.label=label;
-}
-return BreakStatement;
-}();
-exports.BreakStatement=BreakStatement;
-var CallExpression=function(){
-function CallExpression(callee,args){
-this.type=syntax_1.Syntax.CallExpression;
-this.callee=callee;
-this.arguments=args;
-}
-return CallExpression;
-}();
-exports.CallExpression=CallExpression;
-var CatchClause=function(){
-function CatchClause(param,body){
-this.type=syntax_1.Syntax.CatchClause;
-this.param=param;
-this.body=body;
-}
-return CatchClause;
-}();
-exports.CatchClause=CatchClause;
-var ClassBody=function(){
-function ClassBody(body){
-this.type=syntax_1.Syntax.ClassBody;
-this.body=body;
-}
-return ClassBody;
-}();
-exports.ClassBody=ClassBody;
-var ClassDeclaration=function(){
-function ClassDeclaration(id,superClass,body){
-this.type=syntax_1.Syntax.ClassDeclaration;
-this.id=id;
-this.superClass=superClass;
-this.body=body;
-}
-return ClassDeclaration;
-}();
-exports.ClassDeclaration=ClassDeclaration;
-var ClassExpression=function(){
-function ClassExpression(id,superClass,body){
-this.type=syntax_1.Syntax.ClassExpression;
-this.id=id;
-this.superClass=superClass;
-this.body=body;
-}
-return ClassExpression;
-}();
-exports.ClassExpression=ClassExpression;
-var ComputedMemberExpression=function(){
-function ComputedMemberExpression(object,property){
-this.type=syntax_1.Syntax.MemberExpression;
-this.computed=true;
-this.object=object;
-this.property=property;
-}
-return ComputedMemberExpression;
-}();
-exports.ComputedMemberExpression=ComputedMemberExpression;
-var ConditionalExpression=function(){
-function ConditionalExpression(test,consequent,alternate){
-this.type=syntax_1.Syntax.ConditionalExpression;
-this.test=test;
-this.consequent=consequent;
-this.alternate=alternate;
-}
-return ConditionalExpression;
-}();
-exports.ConditionalExpression=ConditionalExpression;
-var ContinueStatement=function(){
-function ContinueStatement(label){
-this.type=syntax_1.Syntax.ContinueStatement;
-this.label=label;
-}
-return ContinueStatement;
-}();
-exports.ContinueStatement=ContinueStatement;
-var DebuggerStatement=function(){
-function DebuggerStatement(){
-this.type=syntax_1.Syntax.DebuggerStatement;
-}
-return DebuggerStatement;
-}();
-exports.DebuggerStatement=DebuggerStatement;
-var Directive=function(){
-function Directive(expression,directive){
-this.type=syntax_1.Syntax.ExpressionStatement;
-this.expression=expression;
-this.directive=directive;
-}
-return Directive;
-}();
-exports.Directive=Directive;
-var DoWhileStatement=function(){
-function DoWhileStatement(body,test){
-this.type=syntax_1.Syntax.DoWhileStatement;
-this.body=body;
-this.test=test;
-}
-return DoWhileStatement;
-}();
-exports.DoWhileStatement=DoWhileStatement;
-var EmptyStatement=function(){
-function EmptyStatement(){
-this.type=syntax_1.Syntax.EmptyStatement;
-}
-return EmptyStatement;
-}();
-exports.EmptyStatement=EmptyStatement;
-var ExportAllDeclaration=function(){
-function ExportAllDeclaration(source){
-this.type=syntax_1.Syntax.ExportAllDeclaration;
-this.source=source;
-}
-return ExportAllDeclaration;
-}();
-exports.ExportAllDeclaration=ExportAllDeclaration;
-var ExportDefaultDeclaration=function(){
-function ExportDefaultDeclaration(declaration){
-this.type=syntax_1.Syntax.ExportDefaultDeclaration;
-this.declaration=declaration;
-}
-return ExportDefaultDeclaration;
-}();
-exports.ExportDefaultDeclaration=ExportDefaultDeclaration;
-var ExportNamedDeclaration=function(){
-function ExportNamedDeclaration(declaration,specifiers,source){
-this.type=syntax_1.Syntax.ExportNamedDeclaration;
-this.declaration=declaration;
-this.specifiers=specifiers;
-this.source=source;
-}
-return ExportNamedDeclaration;
-}();
-exports.ExportNamedDeclaration=ExportNamedDeclaration;
-var ExportSpecifier=function(){
-function ExportSpecifier(local,exported){
-this.type=syntax_1.Syntax.ExportSpecifier;
-this.exported=exported;
-this.local=local;
-}
-return ExportSpecifier;
-}();
-exports.ExportSpecifier=ExportSpecifier;
-var ExpressionStatement=function(){
-function ExpressionStatement(expression){
-this.type=syntax_1.Syntax.ExpressionStatement;
-this.expression=expression;
-}
-return ExpressionStatement;
-}();
-exports.ExpressionStatement=ExpressionStatement;
-var ForInStatement=function(){
-function ForInStatement(left,right,body){
-this.type=syntax_1.Syntax.ForInStatement;
-this.left=left;
-this.right=right;
-this.body=body;
-this.each=false;
-}
-return ForInStatement;
-}();
-exports.ForInStatement=ForInStatement;
-var ForOfStatement=function(){
-function ForOfStatement(left,right,body){
-this.type=syntax_1.Syntax.ForOfStatement;
-this.left=left;
-this.right=right;
-this.body=body;
-}
-return ForOfStatement;
-}();
-exports.ForOfStatement=ForOfStatement;
-var ForStatement=function(){
-function ForStatement(init,test,update,body){
-this.type=syntax_1.Syntax.ForStatement;
-this.init=init;
-this.test=test;
-this.update=update;
-this.body=body;
-}
-return ForStatement;
-}();
-exports.ForStatement=ForStatement;
-var FunctionDeclaration=function(){
-function FunctionDeclaration(id,params,body,generator){
-this.type=syntax_1.Syntax.FunctionDeclaration;
-this.id=id;
-this.params=params;
-this.body=body;
-this.generator=generator;
-this.expression=false;
-this.async=false;
-}
-return FunctionDeclaration;
-}();
-exports.FunctionDeclaration=FunctionDeclaration;
-var FunctionExpression=function(){
-function FunctionExpression(id,params,body,generator){
-this.type=syntax_1.Syntax.FunctionExpression;
-this.id=id;
-this.params=params;
-this.body=body;
-this.generator=generator;
-this.expression=false;
-this.async=false;
-}
-return FunctionExpression;
-}();
-exports.FunctionExpression=FunctionExpression;
-var Identifier=function(){
-function Identifier(name){
-this.type=syntax_1.Syntax.Identifier;
-this.name=name;
-}
-return Identifier;
-}();
-exports.Identifier=Identifier;
-var IfStatement=function(){
-function IfStatement(test,consequent,alternate){
-this.type=syntax_1.Syntax.IfStatement;
-this.test=test;
-this.consequent=consequent;
-this.alternate=alternate;
-}
-return IfStatement;
-}();
-exports.IfStatement=IfStatement;
-var ImportDeclaration=function(){
-function ImportDeclaration(specifiers,source){
-this.type=syntax_1.Syntax.ImportDeclaration;
-this.specifiers=specifiers;
-this.source=source;
-}
-return ImportDeclaration;
-}();
-exports.ImportDeclaration=ImportDeclaration;
-var ImportDefaultSpecifier=function(){
-function ImportDefaultSpecifier(local){
-this.type=syntax_1.Syntax.ImportDefaultSpecifier;
-this.local=local;
-}
-return ImportDefaultSpecifier;
-}();
-exports.ImportDefaultSpecifier=ImportDefaultSpecifier;
-var ImportNamespaceSpecifier=function(){
-function ImportNamespaceSpecifier(local){
-this.type=syntax_1.Syntax.ImportNamespaceSpecifier;
-this.local=local;
-}
-return ImportNamespaceSpecifier;
-}();
-exports.ImportNamespaceSpecifier=ImportNamespaceSpecifier;
-var ImportSpecifier=function(){
-function ImportSpecifier(local,imported){
-this.type=syntax_1.Syntax.ImportSpecifier;
-this.local=local;
-this.imported=imported;
-}
-return ImportSpecifier;
-}();
-exports.ImportSpecifier=ImportSpecifier;
-var LabeledStatement=function(){
-function LabeledStatement(label,body){
-this.type=syntax_1.Syntax.LabeledStatement;
-this.label=label;
-this.body=body;
-}
-return LabeledStatement;
-}();
-exports.LabeledStatement=LabeledStatement;
-var Literal=function(){
-function Literal(value,raw){
-this.type=syntax_1.Syntax.Literal;
-this.value=value;
-this.raw=raw;
-}
-return Literal;
-}();
-exports.Literal=Literal;
-var MetaProperty=function(){
-function MetaProperty(meta,property){
-this.type=syntax_1.Syntax.MetaProperty;
-this.meta=meta;
-this.property=property;
-}
-return MetaProperty;
-}();
-exports.MetaProperty=MetaProperty;
-var MethodDefinition=function(){
-function MethodDefinition(key,computed,value,kind,isStatic){
-this.type=syntax_1.Syntax.MethodDefinition;
-this.key=key;
-this.computed=computed;
-this.value=value;
-this.kind=kind;
-this.static=isStatic;
-}
-return MethodDefinition;
-}();
-exports.MethodDefinition=MethodDefinition;
-var Module=function(){
-function Module(body){
-this.type=syntax_1.Syntax.Program;
-this.body=body;
-this.sourceType='module';
-}
-return Module;
-}();
-exports.Module=Module;
-var NewExpression=function(){
-function NewExpression(callee,args){
-this.type=syntax_1.Syntax.NewExpression;
-this.callee=callee;
-this.arguments=args;
-}
-return NewExpression;
-}();
-exports.NewExpression=NewExpression;
-var ObjectExpression=function(){
-function ObjectExpression(properties){
-this.type=syntax_1.Syntax.ObjectExpression;
-this.properties=properties;
-}
-return ObjectExpression;
-}();
-exports.ObjectExpression=ObjectExpression;
-var ObjectPattern=function(){
-function ObjectPattern(properties){
-this.type=syntax_1.Syntax.ObjectPattern;
-this.properties=properties;
-}
-return ObjectPattern;
-}();
-exports.ObjectPattern=ObjectPattern;
-var Property=function(){
-function Property(kind,key,computed,value,method,shorthand){
-this.type=syntax_1.Syntax.Property;
-this.key=key;
-this.computed=computed;
-this.value=value;
-this.kind=kind;
-this.method=method;
-this.shorthand=shorthand;
-}
-return Property;
-}();
-exports.Property=Property;
-var RegexLiteral=function(){
-function RegexLiteral(value,raw,pattern,flags){
-this.type=syntax_1.Syntax.Literal;
-this.value=value;
-this.raw=raw;
-this.regex={pattern:pattern,flags:flags};
-}
-return RegexLiteral;
-}();
-exports.RegexLiteral=RegexLiteral;
-var RestElement=function(){
-function RestElement(argument){
-this.type=syntax_1.Syntax.RestElement;
-this.argument=argument;
-}
-return RestElement;
-}();
-exports.RestElement=RestElement;
-var ReturnStatement=function(){
-function ReturnStatement(argument){
-this.type=syntax_1.Syntax.ReturnStatement;
-this.argument=argument;
-}
-return ReturnStatement;
-}();
-exports.ReturnStatement=ReturnStatement;
-var Script=function(){
-function Script(body){
-this.type=syntax_1.Syntax.Program;
-this.body=body;
-this.sourceType='script';
-}
-return Script;
-}();
-exports.Script=Script;
-var SequenceExpression=function(){
-function SequenceExpression(expressions){
-this.type=syntax_1.Syntax.SequenceExpression;
-this.expressions=expressions;
-}
-return SequenceExpression;
-}();
-exports.SequenceExpression=SequenceExpression;
-var SpreadElement=function(){
-function SpreadElement(argument){
-this.type=syntax_1.Syntax.SpreadElement;
-this.argument=argument;
-}
-return SpreadElement;
-}();
-exports.SpreadElement=SpreadElement;
-var StaticMemberExpression=function(){
-function StaticMemberExpression(object,property){
-this.type=syntax_1.Syntax.MemberExpression;
-this.computed=false;
-this.object=object;
-this.property=property;
-}
-return StaticMemberExpression;
-}();
-exports.StaticMemberExpression=StaticMemberExpression;
-var Super=function(){
-function Super(){
-this.type=syntax_1.Syntax.Super;
-}
-return Super;
-}();
-exports.Super=Super;
-var SwitchCase=function(){
-function SwitchCase(test,consequent){
-this.type=syntax_1.Syntax.SwitchCase;
-this.test=test;
-this.consequent=consequent;
-}
-return SwitchCase;
-}();
-exports.SwitchCase=SwitchCase;
-var SwitchStatement=function(){
-function SwitchStatement(discriminant,cases){
-this.type=syntax_1.Syntax.SwitchStatement;
-this.discriminant=discriminant;
-this.cases=cases;
-}
-return SwitchStatement;
-}();
-exports.SwitchStatement=SwitchStatement;
-var TaggedTemplateExpression=function(){
-function TaggedTemplateExpression(tag,quasi){
-this.type=syntax_1.Syntax.TaggedTemplateExpression;
-this.tag=tag;
-this.quasi=quasi;
-}
-return TaggedTemplateExpression;
-}();
-exports.TaggedTemplateExpression=TaggedTemplateExpression;
-var TemplateElement=function(){
-function TemplateElement(value,tail){
-this.type=syntax_1.Syntax.TemplateElement;
-this.value=value;
-this.tail=tail;
-}
-return TemplateElement;
-}();
-exports.TemplateElement=TemplateElement;
-var TemplateLiteral=function(){
-function TemplateLiteral(quasis,expressions){
-this.type=syntax_1.Syntax.TemplateLiteral;
-this.quasis=quasis;
-this.expressions=expressions;
-}
-return TemplateLiteral;
-}();
-exports.TemplateLiteral=TemplateLiteral;
-var ThisExpression=function(){
-function ThisExpression(){
-this.type=syntax_1.Syntax.ThisExpression;
-}
-return ThisExpression;
-}();
-exports.ThisExpression=ThisExpression;
-var ThrowStatement=function(){
-function ThrowStatement(argument){
-this.type=syntax_1.Syntax.ThrowStatement;
-this.argument=argument;
-}
-return ThrowStatement;
-}();
-exports.ThrowStatement=ThrowStatement;
-var TryStatement=function(){
-function TryStatement(block,handler,finalizer){
-this.type=syntax_1.Syntax.TryStatement;
-this.block=block;
-this.handler=handler;
-this.finalizer=finalizer;
-}
-return TryStatement;
-}();
-exports.TryStatement=TryStatement;
-var UnaryExpression=function(){
-function UnaryExpression(operator,argument){
-this.type=syntax_1.Syntax.UnaryExpression;
-this.operator=operator;
-this.argument=argument;
-this.prefix=true;
-}
-return UnaryExpression;
-}();
-exports.UnaryExpression=UnaryExpression;
-var UpdateExpression=function(){
-function UpdateExpression(operator,argument,prefix){
-this.type=syntax_1.Syntax.UpdateExpression;
-this.operator=operator;
-this.argument=argument;
-this.prefix=prefix;
-}
-return UpdateExpression;
-}();
-exports.UpdateExpression=UpdateExpression;
-var VariableDeclaration=function(){
-function VariableDeclaration(declarations,kind){
-this.type=syntax_1.Syntax.VariableDeclaration;
-this.declarations=declarations;
-this.kind=kind;
-}
-return VariableDeclaration;
-}();
-exports.VariableDeclaration=VariableDeclaration;
-var VariableDeclarator=function(){
-function VariableDeclarator(id,init){
-this.type=syntax_1.Syntax.VariableDeclarator;
-this.id=id;
-this.init=init;
-}
-return VariableDeclarator;
-}();
-exports.VariableDeclarator=VariableDeclarator;
-var WhileStatement=function(){
-function WhileStatement(test,body){
-this.type=syntax_1.Syntax.WhileStatement;
-this.test=test;
-this.body=body;
-}
-return WhileStatement;
-}();
-exports.WhileStatement=WhileStatement;
-var WithStatement=function(){
-function WithStatement(object,body){
-this.type=syntax_1.Syntax.WithStatement;
-this.object=object;
-this.body=body;
-}
-return WithStatement;
-}();
-exports.WithStatement=WithStatement;
-var YieldExpression=function(){
-function YieldExpression(argument,delegate){
-this.type=syntax_1.Syntax.YieldExpression;
-this.argument=argument;
-this.delegate=delegate;
-}
-return YieldExpression;
-}();
-exports.YieldExpression=YieldExpression;
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-var assert_1=__webpack_require__(9);
-var error_handler_1=__webpack_require__(10);
-var messages_1=__webpack_require__(11);
-var Node=__webpack_require__(7);
-var scanner_1=__webpack_require__(12);
-var syntax_1=__webpack_require__(2);
-var token_1=__webpack_require__(13);
-var ArrowParameterPlaceHolder='ArrowParameterPlaceHolder';
-var Parser=function(){
-function Parser(code,options,delegate){
-if(options===void 0){options={};}
-this.config={
-range:typeof options.range==='boolean'&&options.range,
-loc:typeof options.loc==='boolean'&&options.loc,
-source:null,
-tokens:typeof options.tokens==='boolean'&&options.tokens,
-comment:typeof options.comment==='boolean'&&options.comment,
-tolerant:typeof options.tolerant==='boolean'&&options.tolerant};
-
-if(this.config.loc&&options.source&&options.source!==null){
-this.config.source=String(options.source);
-}
-this.delegate=delegate;
-this.errorHandler=new error_handler_1.ErrorHandler();
-this.errorHandler.tolerant=this.config.tolerant;
-this.scanner=new scanner_1.Scanner(code,this.errorHandler);
-this.scanner.trackComment=this.config.comment;
-this.operatorPrecedence={
-')':0,
-';':0,
-',':0,
-'=':0,
-']':0,
-'||':1,
-'&&':2,
-'|':3,
-'^':4,
-'&':5,
-'==':6,
-'!=':6,
-'===':6,
-'!==':6,
-'<':7,
-'>':7,
-'<=':7,
-'>=':7,
-'<<':8,
-'>>':8,
-'>>>':8,
-'+':9,
-'-':9,
-'*':11,
-'/':11,
-'%':11};
-
-this.lookahead={
-type:2,
-value:'',
-lineNumber:this.scanner.lineNumber,
-lineStart:0,
-start:0,
-end:0};
-
-this.hasLineTerminator=false;
-this.context={
-isModule:false,
-await:false,
-allowIn:true,
-allowStrictDirective:true,
-allowYield:true,
-firstCoverInitializedNameError:null,
-isAssignmentTarget:false,
-isBindingElement:false,
-inFunctionBody:false,
-inIteration:false,
-inSwitch:false,
-labelSet:{},
-strict:false};
-
-this.tokens=[];
-this.startMarker={
-index:0,
-line:this.scanner.lineNumber,
-column:0};
-
-this.lastMarker={
-index:0,
-line:this.scanner.lineNumber,
-column:0};
-
-this.nextToken();
-this.lastMarker={
-index:this.scanner.index,
-line:this.scanner.lineNumber,
-column:this.scanner.index-this.scanner.lineStart};
-
-}
-Parser.prototype.throwError=function(messageFormat){
-var values=[];
-for(var _i=1;_i<arguments.length;_i++){
-values[_i-1]=arguments[_i];
-}
-var args=Array.prototype.slice.call(arguments,1);
-var msg=messageFormat.replace(/%(\d)/g,function(whole,idx){
-assert_1.assert(idx<args.length,'Message reference must be in range');
-return args[idx];
-});
-var index=this.lastMarker.index;
-var line=this.lastMarker.line;
-var column=this.lastMarker.column+1;
-throw this.errorHandler.createError(index,line,column,msg);
-};
-Parser.prototype.tolerateError=function(messageFormat){
-var values=[];
-for(var _i=1;_i<arguments.length;_i++){
-values[_i-1]=arguments[_i];
-}
-var args=Array.prototype.slice.call(arguments,1);
-var msg=messageFormat.replace(/%(\d)/g,function(whole,idx){
-assert_1.assert(idx<args.length,'Message reference must be in range');
-return args[idx];
-});
-var index=this.lastMarker.index;
-var line=this.scanner.lineNumber;
-var column=this.lastMarker.column+1;
-this.errorHandler.tolerateError(index,line,column,msg);
-};
-
-Parser.prototype.unexpectedTokenError=function(token,message){
-var msg=message||messages_1.Messages.UnexpectedToken;
-var value;
-if(token){
-if(!message){
-msg=token.type===2?messages_1.Messages.UnexpectedEOS:
-token.type===3?messages_1.Messages.UnexpectedIdentifier:
-token.type===6?messages_1.Messages.UnexpectedNumber:
-token.type===8?messages_1.Messages.UnexpectedString:
-token.type===10?messages_1.Messages.UnexpectedTemplate:
-messages_1.Messages.UnexpectedToken;
-if(token.type===4){
-if(this.scanner.isFutureReservedWord(token.value)){
-msg=messages_1.Messages.UnexpectedReserved;
-}else
-if(this.context.strict&&this.scanner.isStrictModeReservedWord(token.value)){
-msg=messages_1.Messages.StrictReservedWord;
-}
-}
-}
-value=token.value;
-}else
-{
-value='ILLEGAL';
-}
-msg=msg.replace('%0',value);
-if(token&&typeof token.lineNumber==='number'){
-var index=token.start;
-var line=token.lineNumber;
-var lastMarkerLineStart=this.lastMarker.index-this.lastMarker.column;
-var column=token.start-lastMarkerLineStart+1;
-return this.errorHandler.createError(index,line,column,msg);
-}else
-{
-var index=this.lastMarker.index;
-var line=this.lastMarker.line;
-var column=this.lastMarker.column+1;
-return this.errorHandler.createError(index,line,column,msg);
-}
-};
-Parser.prototype.throwUnexpectedToken=function(token,message){
-throw this.unexpectedTokenError(token,message);
-};
-Parser.prototype.tolerateUnexpectedToken=function(token,message){
-this.errorHandler.tolerate(this.unexpectedTokenError(token,message));
-};
-Parser.prototype.collectComments=function(){
-if(!this.config.comment){
-this.scanner.scanComments();
-}else
-{
-var comments=this.scanner.scanComments();
-if(comments.length>0&&this.delegate){
-for(var i=0;i<comments.length;++i){
-var e=comments[i];
-var node=void 0;
-node={
-type:e.multiLine?'BlockComment':'LineComment',
-value:this.scanner.source.slice(e.slice[0],e.slice[1])};
-
-if(this.config.range){
-node.range=e.range;
-}
-if(this.config.loc){
-node.loc=e.loc;
-}
-var metadata={
-start:{
-line:e.loc.start.line,
-column:e.loc.start.column,
-offset:e.range[0]},
-
-end:{
-line:e.loc.end.line,
-column:e.loc.end.column,
-offset:e.range[1]}};
-
-
-this.delegate(node,metadata);
-}
-}
-}
-};
-
-Parser.prototype.getTokenRaw=function(token){
-return this.scanner.source.slice(token.start,token.end);
-};
-Parser.prototype.convertToken=function(token){
-var t={
-type:token_1.TokenName[token.type],
-value:this.getTokenRaw(token)};
-
-if(this.config.range){
-t.range=[token.start,token.end];
-}
-if(this.config.loc){
-t.loc={
-start:{
-line:this.startMarker.line,
-column:this.startMarker.column},
-
-end:{
-line:this.scanner.lineNumber,
-column:this.scanner.index-this.scanner.lineStart}};
-
-
-}
-if(token.type===9){
-var pattern=token.pattern;
-var flags=token.flags;
-t.regex={pattern:pattern,flags:flags};
-}
-return t;
-};
-Parser.prototype.nextToken=function(){
-var token=this.lookahead;
-this.lastMarker.index=this.scanner.index;
-this.lastMarker.line=this.scanner.lineNumber;
-this.lastMarker.column=this.scanner.index-this.scanner.lineStart;
-this.collectComments();
-if(this.scanner.index!==this.startMarker.index){
-this.startMarker.index=this.scanner.index;
-this.startMarker.line=this.scanner.lineNumber;
-this.startMarker.column=this.scanner.index-this.scanner.lineStart;
-}
-var next=this.scanner.lex();
-this.hasLineTerminator=token.lineNumber!==next.lineNumber;
-if(next&&this.context.strict&&next.type===3){
-if(this.scanner.isStrictModeReservedWord(next.value)){
-next.type=4;
-}
-}
-this.lookahead=next;
-if(this.config.tokens&&next.type!==2){
-this.tokens.push(this.convertToken(next));
-}
-return token;
-};
-Parser.prototype.nextRegexToken=function(){
-this.collectComments();
-var token=this.scanner.scanRegExp();
-if(this.config.tokens){
-
-
-this.tokens.pop();
-this.tokens.push(this.convertToken(token));
-}
-
-this.lookahead=token;
-this.nextToken();
-return token;
-};
-Parser.prototype.createNode=function(){
-return{
-index:this.startMarker.index,
-line:this.startMarker.line,
-column:this.startMarker.column};
-
-};
-Parser.prototype.startNode=function(token,lastLineStart){
-if(lastLineStart===void 0){lastLineStart=0;}
-var column=token.start-token.lineStart;
-var line=token.lineNumber;
-if(column<0){
-column+=lastLineStart;
-line--;
-}
-return{
-index:token.start,
-line:line,
-column:column};
-
-};
-Parser.prototype.finalize=function(marker,node){
-if(this.config.range){
-node.range=[marker.index,this.lastMarker.index];
-}
-if(this.config.loc){
-node.loc={
-start:{
-line:marker.line,
-column:marker.column},
-
-end:{
-line:this.lastMarker.line,
-column:this.lastMarker.column}};
-
-
-if(this.config.source){
-node.loc.source=this.config.source;
-}
-}
-if(this.delegate){
-var metadata={
-start:{
-line:marker.line,
-column:marker.column,
-offset:marker.index},
-
-end:{
-line:this.lastMarker.line,
-column:this.lastMarker.column,
-offset:this.lastMarker.index}};
-
-
-this.delegate(node,metadata);
-}
-return node;
-};
-
-
-Parser.prototype.expect=function(value){
-var token=this.nextToken();
-if(token.type!==7||token.value!==value){
-this.throwUnexpectedToken(token);
-}
-};
-
-Parser.prototype.expectCommaSeparator=function(){
-if(this.config.tolerant){
-var token=this.lookahead;
-if(token.type===7&&token.value===','){
-this.nextToken();
-}else
-if(token.type===7&&token.value===';'){
-this.nextToken();
-this.tolerateUnexpectedToken(token);
-}else
-{
-this.tolerateUnexpectedToken(token,messages_1.Messages.UnexpectedToken);
-}
-}else
-{
-this.expect(',');
-}
-};
-
-
-Parser.prototype.expectKeyword=function(keyword){
-var token=this.nextToken();
-if(token.type!==4||token.value!==keyword){
-this.throwUnexpectedToken(token);
-}
-};
-
-Parser.prototype.match=function(value){
-return this.lookahead.type===7&&this.lookahead.value===value;
-};
-
-Parser.prototype.matchKeyword=function(keyword){
-return this.lookahead.type===4&&this.lookahead.value===keyword;
-};
-
-
-Parser.prototype.matchContextualKeyword=function(keyword){
-return this.lookahead.type===3&&this.lookahead.value===keyword;
-};
-
-Parser.prototype.matchAssign=function(){
-if(this.lookahead.type!==7){
-return false;
-}
-var op=this.lookahead.value;
-return op==='='||
-op==='*='||
-op==='**='||
-op==='/='||
-op==='%='||
-op==='+='||
-op==='-='||
-op==='<<='||
-op==='>>='||
-op==='>>>='||
-op==='&='||
-op==='^='||
-op==='|=';
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Parser.prototype.isolateCoverGrammar=function(parseFunction){
-var previousIsBindingElement=this.context.isBindingElement;
-var previousIsAssignmentTarget=this.context.isAssignmentTarget;
-var previousFirstCoverInitializedNameError=this.context.firstCoverInitializedNameError;
-this.context.isBindingElement=true;
-this.context.isAssignmentTarget=true;
-this.context.firstCoverInitializedNameError=null;
-var result=parseFunction.call(this);
-if(this.context.firstCoverInitializedNameError!==null){
-this.throwUnexpectedToken(this.context.firstCoverInitializedNameError);
-}
-this.context.isBindingElement=previousIsBindingElement;
-this.context.isAssignmentTarget=previousIsAssignmentTarget;
-this.context.firstCoverInitializedNameError=previousFirstCoverInitializedNameError;
-return result;
-};
-Parser.prototype.inheritCoverGrammar=function(parseFunction){
-var previousIsBindingElement=this.context.isBindingElement;
-var previousIsAssignmentTarget=this.context.isAssignmentTarget;
-var previousFirstCoverInitializedNameError=this.context.firstCoverInitializedNameError;
-this.context.isBindingElement=true;
-this.context.isAssignmentTarget=true;
-this.context.firstCoverInitializedNameError=null;
-var result=parseFunction.call(this);
-this.context.isBindingElement=this.context.isBindingElement&&previousIsBindingElement;
-this.context.isAssignmentTarget=this.context.isAssignmentTarget&&previousIsAssignmentTarget;
-this.context.firstCoverInitializedNameError=previousFirstCoverInitializedNameError||this.context.firstCoverInitializedNameError;
-return result;
-};
-Parser.prototype.consumeSemicolon=function(){
-if(this.match(';')){
-this.nextToken();
-}else
-if(!this.hasLineTerminator){
-if(this.lookahead.type!==2&&!this.match('}')){
-this.throwUnexpectedToken(this.lookahead);
-}
-this.lastMarker.index=this.startMarker.index;
-this.lastMarker.line=this.startMarker.line;
-this.lastMarker.column=this.startMarker.column;
-}
-};
-
-Parser.prototype.parsePrimaryExpression=function(){
-var node=this.createNode();
-var expr;
-var token,raw;
-switch(this.lookahead.type){
-case 3:
-if((this.context.isModule||this.context.await)&&this.lookahead.value==='await'){
-this.tolerateUnexpectedToken(this.lookahead);
-}
-expr=this.matchAsyncFunction()?this.parseFunctionExpression():this.finalize(node,new Node.Identifier(this.nextToken().value));
-break;
-case 6:
-case 8:
-if(this.context.strict&&this.lookahead.octal){
-this.tolerateUnexpectedToken(this.lookahead,messages_1.Messages.StrictOctalLiteral);
-}
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-token=this.nextToken();
-raw=this.getTokenRaw(token);
-expr=this.finalize(node,new Node.Literal(token.value,raw));
-break;
-case 1:
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-token=this.nextToken();
-raw=this.getTokenRaw(token);
-expr=this.finalize(node,new Node.Literal(token.value==='true',raw));
-break;
-case 5:
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-token=this.nextToken();
-raw=this.getTokenRaw(token);
-expr=this.finalize(node,new Node.Literal(null,raw));
-break;
-case 10:
-expr=this.parseTemplateLiteral();
-break;
-case 7:
-switch(this.lookahead.value){
-case'(':
-this.context.isBindingElement=false;
-expr=this.inheritCoverGrammar(this.parseGroupExpression);
-break;
-case'[':
-expr=this.inheritCoverGrammar(this.parseArrayInitializer);
-break;
-case'{':
-expr=this.inheritCoverGrammar(this.parseObjectInitializer);
-break;
-case'/':
-case'/=':
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-this.scanner.index=this.startMarker.index;
-token=this.nextRegexToken();
-raw=this.getTokenRaw(token);
-expr=this.finalize(node,new Node.RegexLiteral(token.regex,raw,token.pattern,token.flags));
-break;
-default:
-expr=this.throwUnexpectedToken(this.nextToken());}
-
-break;
-case 4:
-if(!this.context.strict&&this.context.allowYield&&this.matchKeyword('yield')){
-expr=this.parseIdentifierName();
-}else
-if(!this.context.strict&&this.matchKeyword('let')){
-expr=this.finalize(node,new Node.Identifier(this.nextToken().value));
-}else
-{
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-if(this.matchKeyword('function')){
-expr=this.parseFunctionExpression();
-}else
-if(this.matchKeyword('this')){
-this.nextToken();
-expr=this.finalize(node,new Node.ThisExpression());
-}else
-if(this.matchKeyword('class')){
-expr=this.parseClassExpression();
-}else
-{
-expr=this.throwUnexpectedToken(this.nextToken());
-}
-}
-break;
-default:
-expr=this.throwUnexpectedToken(this.nextToken());}
-
-return expr;
-};
-
-Parser.prototype.parseSpreadElement=function(){
-var node=this.createNode();
-this.expect('...');
-var arg=this.inheritCoverGrammar(this.parseAssignmentExpression);
-return this.finalize(node,new Node.SpreadElement(arg));
-};
-Parser.prototype.parseArrayInitializer=function(){
-var node=this.createNode();
-var elements=[];
-this.expect('[');
-while(!this.match(']')){
-if(this.match(',')){
-this.nextToken();
-elements.push(null);
-}else
-if(this.match('...')){
-var element=this.parseSpreadElement();
-if(!this.match(']')){
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-this.expect(',');
-}
-elements.push(element);
-}else
-{
-elements.push(this.inheritCoverGrammar(this.parseAssignmentExpression));
-if(!this.match(']')){
-this.expect(',');
-}
-}
-}
-this.expect(']');
-return this.finalize(node,new Node.ArrayExpression(elements));
-};
-
-Parser.prototype.parsePropertyMethod=function(params){
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-var previousStrict=this.context.strict;
-var previousAllowStrictDirective=this.context.allowStrictDirective;
-this.context.allowStrictDirective=params.simple;
-var body=this.isolateCoverGrammar(this.parseFunctionSourceElements);
-if(this.context.strict&&params.firstRestricted){
-this.tolerateUnexpectedToken(params.firstRestricted,params.message);
-}
-if(this.context.strict&&params.stricted){
-this.tolerateUnexpectedToken(params.stricted,params.message);
-}
-this.context.strict=previousStrict;
-this.context.allowStrictDirective=previousAllowStrictDirective;
-return body;
-};
-Parser.prototype.parsePropertyMethodFunction=function(){
-var isGenerator=false;
-var node=this.createNode();
-var previousAllowYield=this.context.allowYield;
-this.context.allowYield=true;
-var params=this.parseFormalParameters();
-var method=this.parsePropertyMethod(params);
-this.context.allowYield=previousAllowYield;
-return this.finalize(node,new Node.FunctionExpression(null,params.params,method,isGenerator));
-};
-Parser.prototype.parsePropertyMethodAsyncFunction=function(){
-var node=this.createNode();
-var previousAllowYield=this.context.allowYield;
-var previousAwait=this.context.await;
-this.context.allowYield=false;
-this.context.await=true;
-var params=this.parseFormalParameters();
-var method=this.parsePropertyMethod(params);
-this.context.allowYield=previousAllowYield;
-this.context.await=previousAwait;
-return this.finalize(node,new Node.AsyncFunctionExpression(null,params.params,method));
-};
-Parser.prototype.parseObjectPropertyKey=function(){
-var node=this.createNode();
-var token=this.nextToken();
-var key;
-switch(token.type){
-case 8:
-case 6:
-if(this.context.strict&&token.octal){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictOctalLiteral);
-}
-var raw=this.getTokenRaw(token);
-key=this.finalize(node,new Node.Literal(token.value,raw));
-break;
-case 3:
-case 1:
-case 5:
-case 4:
-key=this.finalize(node,new Node.Identifier(token.value));
-break;
-case 7:
-if(token.value==='['){
-key=this.isolateCoverGrammar(this.parseAssignmentExpression);
-this.expect(']');
-}else
-{
-key=this.throwUnexpectedToken(token);
-}
-break;
-default:
-key=this.throwUnexpectedToken(token);}
-
-return key;
-};
-Parser.prototype.isPropertyKey=function(key,value){
-return key.type===syntax_1.Syntax.Identifier&&key.name===value||
-key.type===syntax_1.Syntax.Literal&&key.value===value;
-};
-Parser.prototype.parseObjectProperty=function(hasProto){
-var node=this.createNode();
-var token=this.lookahead;
-var kind;
-var key=null;
-var value=null;
-var computed=false;
-var method=false;
-var shorthand=false;
-var isAsync=false;
-if(token.type===3){
-var id=token.value;
-this.nextToken();
-computed=this.match('[');
-isAsync=!this.hasLineTerminator&&id==='async'&&
-!this.match(':')&&!this.match('(')&&!this.match('*')&&!this.match(',');
-key=isAsync?this.parseObjectPropertyKey():this.finalize(node,new Node.Identifier(id));
-}else
-if(this.match('*')){
-this.nextToken();
-}else
-{
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-}
-var lookaheadPropertyKey=this.qualifiedPropertyName(this.lookahead);
-if(token.type===3&&!isAsync&&token.value==='get'&&lookaheadPropertyKey){
-kind='get';
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-this.context.allowYield=false;
-value=this.parseGetterMethod();
-}else
-if(token.type===3&&!isAsync&&token.value==='set'&&lookaheadPropertyKey){
-kind='set';
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-value=this.parseSetterMethod();
-}else
-if(token.type===7&&token.value==='*'&&lookaheadPropertyKey){
-kind='init';
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-value=this.parseGeneratorMethod();
-method=true;
-}else
-{
-if(!key){
-this.throwUnexpectedToken(this.lookahead);
-}
-kind='init';
-if(this.match(':')&&!isAsync){
-if(!computed&&this.isPropertyKey(key,'__proto__')){
-if(hasProto.value){
-this.tolerateError(messages_1.Messages.DuplicateProtoProperty);
-}
-hasProto.value=true;
-}
-this.nextToken();
-value=this.inheritCoverGrammar(this.parseAssignmentExpression);
-}else
-if(this.match('(')){
-value=isAsync?this.parsePropertyMethodAsyncFunction():this.parsePropertyMethodFunction();
-method=true;
-}else
-if(token.type===3){
-var id=this.finalize(node,new Node.Identifier(token.value));
-if(this.match('=')){
-this.context.firstCoverInitializedNameError=this.lookahead;
-this.nextToken();
-shorthand=true;
-var init=this.isolateCoverGrammar(this.parseAssignmentExpression);
-value=this.finalize(node,new Node.AssignmentPattern(id,init));
-}else
-{
-shorthand=true;
-value=id;
-}
-}else
-{
-this.throwUnexpectedToken(this.nextToken());
-}
-}
-return this.finalize(node,new Node.Property(kind,key,computed,value,method,shorthand));
-};
-Parser.prototype.parseObjectInitializer=function(){
-var node=this.createNode();
-this.expect('{');
-var properties=[];
-var hasProto={value:false};
-while(!this.match('}')){
-properties.push(this.parseObjectProperty(hasProto));
-if(!this.match('}')){
-this.expectCommaSeparator();
-}
-}
-this.expect('}');
-return this.finalize(node,new Node.ObjectExpression(properties));
-};
-
-Parser.prototype.parseTemplateHead=function(){
-assert_1.assert(this.lookahead.head,'Template literal must start with a template head');
-var node=this.createNode();
-var token=this.nextToken();
-var raw=token.value;
-var cooked=token.cooked;
-return this.finalize(node,new Node.TemplateElement({raw:raw,cooked:cooked},token.tail));
-};
-Parser.prototype.parseTemplateElement=function(){
-if(this.lookahead.type!==10){
-this.throwUnexpectedToken();
-}
-var node=this.createNode();
-var token=this.nextToken();
-var raw=token.value;
-var cooked=token.cooked;
-return this.finalize(node,new Node.TemplateElement({raw:raw,cooked:cooked},token.tail));
-};
-Parser.prototype.parseTemplateLiteral=function(){
-var node=this.createNode();
-var expressions=[];
-var quasis=[];
-var quasi=this.parseTemplateHead();
-quasis.push(quasi);
-while(!quasi.tail){
-expressions.push(this.parseExpression());
-quasi=this.parseTemplateElement();
-quasis.push(quasi);
-}
-return this.finalize(node,new Node.TemplateLiteral(quasis,expressions));
-};
-
-Parser.prototype.reinterpretExpressionAsPattern=function(expr){
-switch(expr.type){
-case syntax_1.Syntax.Identifier:
-case syntax_1.Syntax.MemberExpression:
-case syntax_1.Syntax.RestElement:
-case syntax_1.Syntax.AssignmentPattern:
-break;
-case syntax_1.Syntax.SpreadElement:
-expr.type=syntax_1.Syntax.RestElement;
-this.reinterpretExpressionAsPattern(expr.argument);
-break;
-case syntax_1.Syntax.ArrayExpression:
-expr.type=syntax_1.Syntax.ArrayPattern;
-for(var i=0;i<expr.elements.length;i++){
-if(expr.elements[i]!==null){
-this.reinterpretExpressionAsPattern(expr.elements[i]);
-}
-}
-break;
-case syntax_1.Syntax.ObjectExpression:
-expr.type=syntax_1.Syntax.ObjectPattern;
-for(var i=0;i<expr.properties.length;i++){
-this.reinterpretExpressionAsPattern(expr.properties[i].value);
-}
-break;
-case syntax_1.Syntax.AssignmentExpression:
-expr.type=syntax_1.Syntax.AssignmentPattern;
-delete expr.operator;
-this.reinterpretExpressionAsPattern(expr.left);
-break;
-default:
-
-break;}
-
-};
-Parser.prototype.parseGroupExpression=function(){
-var expr;
-this.expect('(');
-if(this.match(')')){
-this.nextToken();
-if(!this.match('=>')){
-this.expect('=>');
-}
-expr={
-type:ArrowParameterPlaceHolder,
-params:[],
-async:false};
-
-}else
-{
-var startToken=this.lookahead;
-var params=[];
-if(this.match('...')){
-expr=this.parseRestElement(params);
-this.expect(')');
-if(!this.match('=>')){
-this.expect('=>');
-}
-expr={
-type:ArrowParameterPlaceHolder,
-params:[expr],
-async:false};
-
-}else
-{
-var arrow=false;
-this.context.isBindingElement=true;
-expr=this.inheritCoverGrammar(this.parseAssignmentExpression);
-if(this.match(',')){
-var expressions=[];
-this.context.isAssignmentTarget=false;
-expressions.push(expr);
-while(this.lookahead.type!==2){
-if(!this.match(',')){
-break;
-}
-this.nextToken();
-if(this.match(')')){
-this.nextToken();
-for(var i=0;i<expressions.length;i++){
-this.reinterpretExpressionAsPattern(expressions[i]);
-}
-arrow=true;
-expr={
-type:ArrowParameterPlaceHolder,
-params:expressions,
-async:false};
-
-}else
-if(this.match('...')){
-if(!this.context.isBindingElement){
-this.throwUnexpectedToken(this.lookahead);
-}
-expressions.push(this.parseRestElement(params));
-this.expect(')');
-if(!this.match('=>')){
-this.expect('=>');
-}
-this.context.isBindingElement=false;
-for(var i=0;i<expressions.length;i++){
-this.reinterpretExpressionAsPattern(expressions[i]);
-}
-arrow=true;
-expr={
-type:ArrowParameterPlaceHolder,
-params:expressions,
-async:false};
-
-}else
-{
-expressions.push(this.inheritCoverGrammar(this.parseAssignmentExpression));
-}
-if(arrow){
-break;
-}
-}
-if(!arrow){
-expr=this.finalize(this.startNode(startToken),new Node.SequenceExpression(expressions));
-}
-}
-if(!arrow){
-this.expect(')');
-if(this.match('=>')){
-if(expr.type===syntax_1.Syntax.Identifier&&expr.name==='yield'){
-arrow=true;
-expr={
-type:ArrowParameterPlaceHolder,
-params:[expr],
-async:false};
-
-}
-if(!arrow){
-if(!this.context.isBindingElement){
-this.throwUnexpectedToken(this.lookahead);
-}
-if(expr.type===syntax_1.Syntax.SequenceExpression){
-for(var i=0;i<expr.expressions.length;i++){
-this.reinterpretExpressionAsPattern(expr.expressions[i]);
-}
-}else
-{
-this.reinterpretExpressionAsPattern(expr);
-}
-var parameters=expr.type===syntax_1.Syntax.SequenceExpression?expr.expressions:[expr];
-expr={
-type:ArrowParameterPlaceHolder,
-params:parameters,
-async:false};
-
-}
-}
-this.context.isBindingElement=false;
-}
-}
-}
-return expr;
-};
-
-Parser.prototype.parseArguments=function(){
-this.expect('(');
-var args=[];
-if(!this.match(')')){
-while(true){
-var expr=this.match('...')?this.parseSpreadElement():
-this.isolateCoverGrammar(this.parseAssignmentExpression);
-args.push(expr);
-if(this.match(')')){
-break;
-}
-this.expectCommaSeparator();
-if(this.match(')')){
-break;
-}
-}
-}
-this.expect(')');
-return args;
-};
-Parser.prototype.isIdentifierName=function(token){
-return token.type===3||
-token.type===4||
-token.type===1||
-token.type===5;
-};
-Parser.prototype.parseIdentifierName=function(){
-var node=this.createNode();
-var token=this.nextToken();
-if(!this.isIdentifierName(token)){
-this.throwUnexpectedToken(token);
-}
-return this.finalize(node,new Node.Identifier(token.value));
-};
-Parser.prototype.parseNewExpression=function(){
-var node=this.createNode();
-var id=this.parseIdentifierName();
-assert_1.assert(id.name==='new','New expression must start with `new`');
-var expr;
-if(this.match('.')){
-this.nextToken();
-if(this.lookahead.type===3&&this.context.inFunctionBody&&this.lookahead.value==='target'){
-var property=this.parseIdentifierName();
-expr=new Node.MetaProperty(id,property);
-}else
-{
-this.throwUnexpectedToken(this.lookahead);
-}
-}else
-{
-var callee=this.isolateCoverGrammar(this.parseLeftHandSideExpression);
-var args=this.match('(')?this.parseArguments():[];
-expr=new Node.NewExpression(callee,args);
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-}
-return this.finalize(node,expr);
-};
-Parser.prototype.parseAsyncArgument=function(){
-var arg=this.parseAssignmentExpression();
-this.context.firstCoverInitializedNameError=null;
-return arg;
-};
-Parser.prototype.parseAsyncArguments=function(){
-this.expect('(');
-var args=[];
-if(!this.match(')')){
-while(true){
-var expr=this.match('...')?this.parseSpreadElement():
-this.isolateCoverGrammar(this.parseAsyncArgument);
-args.push(expr);
-if(this.match(')')){
-break;
-}
-this.expectCommaSeparator();
-if(this.match(')')){
-break;
-}
-}
-}
-this.expect(')');
-return args;
-};
-Parser.prototype.parseLeftHandSideExpressionAllowCall=function(){
-var startToken=this.lookahead;
-var maybeAsync=this.matchContextualKeyword('async');
-var previousAllowIn=this.context.allowIn;
-this.context.allowIn=true;
-var expr;
-if(this.matchKeyword('super')&&this.context.inFunctionBody){
-expr=this.createNode();
-this.nextToken();
-expr=this.finalize(expr,new Node.Super());
-if(!this.match('(')&&!this.match('.')&&!this.match('[')){
-this.throwUnexpectedToken(this.lookahead);
-}
-}else
-{
-expr=this.inheritCoverGrammar(this.matchKeyword('new')?this.parseNewExpression:this.parsePrimaryExpression);
-}
-while(true){
-if(this.match('.')){
-this.context.isBindingElement=false;
-this.context.isAssignmentTarget=true;
-this.expect('.');
-var property=this.parseIdentifierName();
-expr=this.finalize(this.startNode(startToken),new Node.StaticMemberExpression(expr,property));
-}else
-if(this.match('(')){
-var asyncArrow=maybeAsync&&startToken.lineNumber===this.lookahead.lineNumber;
-this.context.isBindingElement=false;
-this.context.isAssignmentTarget=false;
-var args=asyncArrow?this.parseAsyncArguments():this.parseArguments();
-expr=this.finalize(this.startNode(startToken),new Node.CallExpression(expr,args));
-if(asyncArrow&&this.match('=>')){
-for(var i=0;i<args.length;++i){
-this.reinterpretExpressionAsPattern(args[i]);
-}
-expr={
-type:ArrowParameterPlaceHolder,
-params:args,
-async:true};
-
-}
-}else
-if(this.match('[')){
-this.context.isBindingElement=false;
-this.context.isAssignmentTarget=true;
-this.expect('[');
-var property=this.isolateCoverGrammar(this.parseExpression);
-this.expect(']');
-expr=this.finalize(this.startNode(startToken),new Node.ComputedMemberExpression(expr,property));
-}else
-if(this.lookahead.type===10&&this.lookahead.head){
-var quasi=this.parseTemplateLiteral();
-expr=this.finalize(this.startNode(startToken),new Node.TaggedTemplateExpression(expr,quasi));
-}else
-{
-break;
-}
-}
-this.context.allowIn=previousAllowIn;
-return expr;
-};
-Parser.prototype.parseSuper=function(){
-var node=this.createNode();
-this.expectKeyword('super');
-if(!this.match('[')&&!this.match('.')){
-this.throwUnexpectedToken(this.lookahead);
-}
-return this.finalize(node,new Node.Super());
-};
-Parser.prototype.parseLeftHandSideExpression=function(){
-assert_1.assert(this.context.allowIn,'callee of new expression always allow in keyword.');
-var node=this.startNode(this.lookahead);
-var expr=this.matchKeyword('super')&&this.context.inFunctionBody?this.parseSuper():
-this.inheritCoverGrammar(this.matchKeyword('new')?this.parseNewExpression:this.parsePrimaryExpression);
-while(true){
-if(this.match('[')){
-this.context.isBindingElement=false;
-this.context.isAssignmentTarget=true;
-this.expect('[');
-var property=this.isolateCoverGrammar(this.parseExpression);
-this.expect(']');
-expr=this.finalize(node,new Node.ComputedMemberExpression(expr,property));
-}else
-if(this.match('.')){
-this.context.isBindingElement=false;
-this.context.isAssignmentTarget=true;
-this.expect('.');
-var property=this.parseIdentifierName();
-expr=this.finalize(node,new Node.StaticMemberExpression(expr,property));
-}else
-if(this.lookahead.type===10&&this.lookahead.head){
-var quasi=this.parseTemplateLiteral();
-expr=this.finalize(node,new Node.TaggedTemplateExpression(expr,quasi));
-}else
-{
-break;
-}
-}
-return expr;
-};
-
-Parser.prototype.parseUpdateExpression=function(){
-var expr;
-var startToken=this.lookahead;
-if(this.match('++')||this.match('--')){
-var node=this.startNode(startToken);
-var token=this.nextToken();
-expr=this.inheritCoverGrammar(this.parseUnaryExpression);
-if(this.context.strict&&expr.type===syntax_1.Syntax.Identifier&&this.scanner.isRestrictedWord(expr.name)){
-this.tolerateError(messages_1.Messages.StrictLHSPrefix);
-}
-if(!this.context.isAssignmentTarget){
-this.tolerateError(messages_1.Messages.InvalidLHSInAssignment);
-}
-var prefix=true;
-expr=this.finalize(node,new Node.UpdateExpression(token.value,expr,prefix));
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-}else
-{
-expr=this.inheritCoverGrammar(this.parseLeftHandSideExpressionAllowCall);
-if(!this.hasLineTerminator&&this.lookahead.type===7){
-if(this.match('++')||this.match('--')){
-if(this.context.strict&&expr.type===syntax_1.Syntax.Identifier&&this.scanner.isRestrictedWord(expr.name)){
-this.tolerateError(messages_1.Messages.StrictLHSPostfix);
-}
-if(!this.context.isAssignmentTarget){
-this.tolerateError(messages_1.Messages.InvalidLHSInAssignment);
-}
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-var operator=this.nextToken().value;
-var prefix=false;
-expr=this.finalize(this.startNode(startToken),new Node.UpdateExpression(operator,expr,prefix));
-}
-}
-}
-return expr;
-};
-
-Parser.prototype.parseAwaitExpression=function(){
-var node=this.createNode();
-this.nextToken();
-var argument=this.parseUnaryExpression();
-return this.finalize(node,new Node.AwaitExpression(argument));
-};
-Parser.prototype.parseUnaryExpression=function(){
-var expr;
-if(this.match('+')||this.match('-')||this.match('~')||this.match('!')||
-this.matchKeyword('delete')||this.matchKeyword('void')||this.matchKeyword('typeof')){
-var node=this.startNode(this.lookahead);
-var token=this.nextToken();
-expr=this.inheritCoverGrammar(this.parseUnaryExpression);
-expr=this.finalize(node,new Node.UnaryExpression(token.value,expr));
-if(this.context.strict&&expr.operator==='delete'&&expr.argument.type===syntax_1.Syntax.Identifier){
-this.tolerateError(messages_1.Messages.StrictDelete);
-}
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-}else
-if(this.context.await&&this.matchContextualKeyword('await')){
-expr=this.parseAwaitExpression();
-}else
-{
-expr=this.parseUpdateExpression();
-}
-return expr;
-};
-Parser.prototype.parseExponentiationExpression=function(){
-var startToken=this.lookahead;
-var expr=this.inheritCoverGrammar(this.parseUnaryExpression);
-if(expr.type!==syntax_1.Syntax.UnaryExpression&&this.match('**')){
-this.nextToken();
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-var left=expr;
-var right=this.isolateCoverGrammar(this.parseExponentiationExpression);
-expr=this.finalize(this.startNode(startToken),new Node.BinaryExpression('**',left,right));
-}
-return expr;
-};
-
-
-
-
-
-
-
-
-Parser.prototype.binaryPrecedence=function(token){
-var op=token.value;
-var precedence;
-if(token.type===7){
-precedence=this.operatorPrecedence[op]||0;
-}else
-if(token.type===4){
-precedence=op==='instanceof'||this.context.allowIn&&op==='in'?7:0;
-}else
-{
-precedence=0;
-}
-return precedence;
-};
-Parser.prototype.parseBinaryExpression=function(){
-var startToken=this.lookahead;
-var expr=this.inheritCoverGrammar(this.parseExponentiationExpression);
-var token=this.lookahead;
-var prec=this.binaryPrecedence(token);
-if(prec>0){
-this.nextToken();
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-var markers=[startToken,this.lookahead];
-var left=expr;
-var right=this.isolateCoverGrammar(this.parseExponentiationExpression);
-var stack=[left,token.value,right];
-var precedences=[prec];
-while(true){
-prec=this.binaryPrecedence(this.lookahead);
-if(prec<=0){
-break;
-}
-
-while(stack.length>2&&prec<=precedences[precedences.length-1]){
-right=stack.pop();
-var operator=stack.pop();
-precedences.pop();
-left=stack.pop();
-markers.pop();
-var node=this.startNode(markers[markers.length-1]);
-stack.push(this.finalize(node,new Node.BinaryExpression(operator,left,right)));
-}
-
-stack.push(this.nextToken().value);
-precedences.push(prec);
-markers.push(this.lookahead);
-stack.push(this.isolateCoverGrammar(this.parseExponentiationExpression));
-}
-
-var i=stack.length-1;
-expr=stack[i];
-var lastMarker=markers.pop();
-while(i>1){
-var marker=markers.pop();
-var lastLineStart=lastMarker&&lastMarker.lineStart;
-var node=this.startNode(marker,lastLineStart);
-var operator=stack[i-1];
-expr=this.finalize(node,new Node.BinaryExpression(operator,stack[i-2],expr));
-i-=2;
-lastMarker=marker;
-}
-}
-return expr;
-};
-
-Parser.prototype.parseConditionalExpression=function(){
-var startToken=this.lookahead;
-var expr=this.inheritCoverGrammar(this.parseBinaryExpression);
-if(this.match('?')){
-this.nextToken();
-var previousAllowIn=this.context.allowIn;
-this.context.allowIn=true;
-var consequent=this.isolateCoverGrammar(this.parseAssignmentExpression);
-this.context.allowIn=previousAllowIn;
-this.expect(':');
-var alternate=this.isolateCoverGrammar(this.parseAssignmentExpression);
-expr=this.finalize(this.startNode(startToken),new Node.ConditionalExpression(expr,consequent,alternate));
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-}
-return expr;
-};
-
-Parser.prototype.checkPatternParam=function(options,param){
-switch(param.type){
-case syntax_1.Syntax.Identifier:
-this.validateParam(options,param,param.name);
-break;
-case syntax_1.Syntax.RestElement:
-this.checkPatternParam(options,param.argument);
-break;
-case syntax_1.Syntax.AssignmentPattern:
-this.checkPatternParam(options,param.left);
-break;
-case syntax_1.Syntax.ArrayPattern:
-for(var i=0;i<param.elements.length;i++){
-if(param.elements[i]!==null){
-this.checkPatternParam(options,param.elements[i]);
-}
-}
-break;
-case syntax_1.Syntax.ObjectPattern:
-for(var i=0;i<param.properties.length;i++){
-this.checkPatternParam(options,param.properties[i].value);
-}
-break;
-default:
-break;}
-
-options.simple=options.simple&&param instanceof Node.Identifier;
-};
-Parser.prototype.reinterpretAsCoverFormalsList=function(expr){
-var params=[expr];
-var options;
-var asyncArrow=false;
-switch(expr.type){
-case syntax_1.Syntax.Identifier:
-break;
-case ArrowParameterPlaceHolder:
-params=expr.params;
-asyncArrow=expr.async;
-break;
-default:
-return null;}
-
-options={
-simple:true,
-paramSet:{}};
-
-for(var i=0;i<params.length;++i){
-var param=params[i];
-if(param.type===syntax_1.Syntax.AssignmentPattern){
-if(param.right.type===syntax_1.Syntax.YieldExpression){
-if(param.right.argument){
-this.throwUnexpectedToken(this.lookahead);
-}
-param.right.type=syntax_1.Syntax.Identifier;
-param.right.name='yield';
-delete param.right.argument;
-delete param.right.delegate;
-}
-}else
-if(asyncArrow&&param.type===syntax_1.Syntax.Identifier&&param.name==='await'){
-this.throwUnexpectedToken(this.lookahead);
-}
-this.checkPatternParam(options,param);
-params[i]=param;
-}
-if(this.context.strict||!this.context.allowYield){
-for(var i=0;i<params.length;++i){
-var param=params[i];
-if(param.type===syntax_1.Syntax.YieldExpression){
-this.throwUnexpectedToken(this.lookahead);
-}
-}
-}
-if(options.message===messages_1.Messages.StrictParamDupe){
-var token=this.context.strict?options.stricted:options.firstRestricted;
-this.throwUnexpectedToken(token,options.message);
-}
-return{
-simple:options.simple,
-params:params,
-stricted:options.stricted,
-firstRestricted:options.firstRestricted,
-message:options.message};
-
-};
-Parser.prototype.parseAssignmentExpression=function(){
-var expr;
-if(!this.context.allowYield&&this.matchKeyword('yield')){
-expr=this.parseYieldExpression();
-}else
-{
-var startToken=this.lookahead;
-var token=startToken;
-expr=this.parseConditionalExpression();
-if(token.type===3&&token.lineNumber===this.lookahead.lineNumber&&token.value==='async'){
-if(this.lookahead.type===3||this.matchKeyword('yield')){
-var arg=this.parsePrimaryExpression();
-this.reinterpretExpressionAsPattern(arg);
-expr={
-type:ArrowParameterPlaceHolder,
-params:[arg],
-async:true};
-
-}
-}
-if(expr.type===ArrowParameterPlaceHolder||this.match('=>')){
-
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-var isAsync=expr.async;
-var list=this.reinterpretAsCoverFormalsList(expr);
-if(list){
-if(this.hasLineTerminator){
-this.tolerateUnexpectedToken(this.lookahead);
-}
-this.context.firstCoverInitializedNameError=null;
-var previousStrict=this.context.strict;
-var previousAllowStrictDirective=this.context.allowStrictDirective;
-this.context.allowStrictDirective=list.simple;
-var previousAllowYield=this.context.allowYield;
-var previousAwait=this.context.await;
-this.context.allowYield=true;
-this.context.await=isAsync;
-var node=this.startNode(startToken);
-this.expect('=>');
-var body=void 0;
-if(this.match('{')){
-var previousAllowIn=this.context.allowIn;
-this.context.allowIn=true;
-body=this.parseFunctionSourceElements();
-this.context.allowIn=previousAllowIn;
-}else
-{
-body=this.isolateCoverGrammar(this.parseAssignmentExpression);
-}
-var expression=body.type!==syntax_1.Syntax.BlockStatement;
-if(this.context.strict&&list.firstRestricted){
-this.throwUnexpectedToken(list.firstRestricted,list.message);
-}
-if(this.context.strict&&list.stricted){
-this.tolerateUnexpectedToken(list.stricted,list.message);
-}
-expr=isAsync?this.finalize(node,new Node.AsyncArrowFunctionExpression(list.params,body,expression)):
-this.finalize(node,new Node.ArrowFunctionExpression(list.params,body,expression));
-this.context.strict=previousStrict;
-this.context.allowStrictDirective=previousAllowStrictDirective;
-this.context.allowYield=previousAllowYield;
-this.context.await=previousAwait;
-}
-}else
-{
-if(this.matchAssign()){
-if(!this.context.isAssignmentTarget){
-this.tolerateError(messages_1.Messages.InvalidLHSInAssignment);
-}
-if(this.context.strict&&expr.type===syntax_1.Syntax.Identifier){
-var id=expr;
-if(this.scanner.isRestrictedWord(id.name)){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictLHSAssignment);
-}
-if(this.scanner.isStrictModeReservedWord(id.name)){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictReservedWord);
-}
-}
-if(!this.match('=')){
-this.context.isAssignmentTarget=false;
-this.context.isBindingElement=false;
-}else
-{
-this.reinterpretExpressionAsPattern(expr);
-}
-token=this.nextToken();
-var operator=token.value;
-var right=this.isolateCoverGrammar(this.parseAssignmentExpression);
-expr=this.finalize(this.startNode(startToken),new Node.AssignmentExpression(operator,expr,right));
-this.context.firstCoverInitializedNameError=null;
-}
-}
-}
-return expr;
-};
-
-Parser.prototype.parseExpression=function(){
-var startToken=this.lookahead;
-var expr=this.isolateCoverGrammar(this.parseAssignmentExpression);
-if(this.match(',')){
-var expressions=[];
-expressions.push(expr);
-while(this.lookahead.type!==2){
-if(!this.match(',')){
-break;
-}
-this.nextToken();
-expressions.push(this.isolateCoverGrammar(this.parseAssignmentExpression));
-}
-expr=this.finalize(this.startNode(startToken),new Node.SequenceExpression(expressions));
-}
-return expr;
-};
-
-Parser.prototype.parseStatementListItem=function(){
-var statement;
-this.context.isAssignmentTarget=true;
-this.context.isBindingElement=true;
-if(this.lookahead.type===4){
-switch(this.lookahead.value){
-case'export':
-if(!this.context.isModule){
-this.tolerateUnexpectedToken(this.lookahead,messages_1.Messages.IllegalExportDeclaration);
-}
-statement=this.parseExportDeclaration();
-break;
-case'import':
-if(!this.context.isModule){
-this.tolerateUnexpectedToken(this.lookahead,messages_1.Messages.IllegalImportDeclaration);
-}
-statement=this.parseImportDeclaration();
-break;
-case'const':
-statement=this.parseLexicalDeclaration({inFor:false});
-break;
-case'function':
-statement=this.parseFunctionDeclaration();
-break;
-case'class':
-statement=this.parseClassDeclaration();
-break;
-case'let':
-statement=this.isLexicalDeclaration()?this.parseLexicalDeclaration({inFor:false}):this.parseStatement();
-break;
-default:
-statement=this.parseStatement();
-break;}
-
-}else
-{
-statement=this.parseStatement();
-}
-return statement;
-};
-Parser.prototype.parseBlock=function(){
-var node=this.createNode();
-this.expect('{');
-var block=[];
-while(true){
-if(this.match('}')){
-break;
-}
-block.push(this.parseStatementListItem());
-}
-this.expect('}');
-return this.finalize(node,new Node.BlockStatement(block));
-};
-
-Parser.prototype.parseLexicalBinding=function(kind,options){
-var node=this.createNode();
-var params=[];
-var id=this.parsePattern(params,kind);
-if(this.context.strict&&id.type===syntax_1.Syntax.Identifier){
-if(this.scanner.isRestrictedWord(id.name)){
-this.tolerateError(messages_1.Messages.StrictVarName);
-}
-}
-var init=null;
-if(kind==='const'){
-if(!this.matchKeyword('in')&&!this.matchContextualKeyword('of')){
-if(this.match('=')){
-this.nextToken();
-init=this.isolateCoverGrammar(this.parseAssignmentExpression);
-}else
-{
-this.throwError(messages_1.Messages.DeclarationMissingInitializer,'const');
-}
-}
-}else
-if(!options.inFor&&id.type!==syntax_1.Syntax.Identifier||this.match('=')){
-this.expect('=');
-init=this.isolateCoverGrammar(this.parseAssignmentExpression);
-}
-return this.finalize(node,new Node.VariableDeclarator(id,init));
-};
-Parser.prototype.parseBindingList=function(kind,options){
-var list=[this.parseLexicalBinding(kind,options)];
-while(this.match(',')){
-this.nextToken();
-list.push(this.parseLexicalBinding(kind,options));
-}
-return list;
-};
-Parser.prototype.isLexicalDeclaration=function(){
-var state=this.scanner.saveState();
-this.scanner.scanComments();
-var next=this.scanner.lex();
-this.scanner.restoreState(state);
-return next.type===3||
-next.type===7&&next.value==='['||
-next.type===7&&next.value==='{'||
-next.type===4&&next.value==='let'||
-next.type===4&&next.value==='yield';
-};
-Parser.prototype.parseLexicalDeclaration=function(options){
-var node=this.createNode();
-var kind=this.nextToken().value;
-assert_1.assert(kind==='let'||kind==='const','Lexical declaration must be either let or const');
-var declarations=this.parseBindingList(kind,options);
-this.consumeSemicolon();
-return this.finalize(node,new Node.VariableDeclaration(declarations,kind));
-};
-
-Parser.prototype.parseBindingRestElement=function(params,kind){
-var node=this.createNode();
-this.expect('...');
-var arg=this.parsePattern(params,kind);
-return this.finalize(node,new Node.RestElement(arg));
-};
-Parser.prototype.parseArrayPattern=function(params,kind){
-var node=this.createNode();
-this.expect('[');
-var elements=[];
-while(!this.match(']')){
-if(this.match(',')){
-this.nextToken();
-elements.push(null);
-}else
-{
-if(this.match('...')){
-elements.push(this.parseBindingRestElement(params,kind));
-break;
-}else
-{
-elements.push(this.parsePatternWithDefault(params,kind));
-}
-if(!this.match(']')){
-this.expect(',');
-}
-}
-}
-this.expect(']');
-return this.finalize(node,new Node.ArrayPattern(elements));
-};
-Parser.prototype.parsePropertyPattern=function(params,kind){
-var node=this.createNode();
-var computed=false;
-var shorthand=false;
-var method=false;
-var key;
-var value;
-if(this.lookahead.type===3){
-var keyToken=this.lookahead;
-key=this.parseVariableIdentifier();
-var init=this.finalize(node,new Node.Identifier(keyToken.value));
-if(this.match('=')){
-params.push(keyToken);
-shorthand=true;
-this.nextToken();
-var expr=this.parseAssignmentExpression();
-value=this.finalize(this.startNode(keyToken),new Node.AssignmentPattern(init,expr));
-}else
-if(!this.match(':')){
-params.push(keyToken);
-shorthand=true;
-value=init;
-}else
-{
-this.expect(':');
-value=this.parsePatternWithDefault(params,kind);
-}
-}else
-{
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-this.expect(':');
-value=this.parsePatternWithDefault(params,kind);
-}
-return this.finalize(node,new Node.Property('init',key,computed,value,method,shorthand));
-};
-Parser.prototype.parseObjectPattern=function(params,kind){
-var node=this.createNode();
-var properties=[];
-this.expect('{');
-while(!this.match('}')){
-properties.push(this.parsePropertyPattern(params,kind));
-if(!this.match('}')){
-this.expect(',');
-}
-}
-this.expect('}');
-return this.finalize(node,new Node.ObjectPattern(properties));
-};
-Parser.prototype.parsePattern=function(params,kind){
-var pattern;
-if(this.match('[')){
-pattern=this.parseArrayPattern(params,kind);
-}else
-if(this.match('{')){
-pattern=this.parseObjectPattern(params,kind);
-}else
-{
-if(this.matchKeyword('let')&&(kind==='const'||kind==='let')){
-this.tolerateUnexpectedToken(this.lookahead,messages_1.Messages.LetInLexicalBinding);
-}
-params.push(this.lookahead);
-pattern=this.parseVariableIdentifier(kind);
-}
-return pattern;
-};
-Parser.prototype.parsePatternWithDefault=function(params,kind){
-var startToken=this.lookahead;
-var pattern=this.parsePattern(params,kind);
-if(this.match('=')){
-this.nextToken();
-var previousAllowYield=this.context.allowYield;
-this.context.allowYield=true;
-var right=this.isolateCoverGrammar(this.parseAssignmentExpression);
-this.context.allowYield=previousAllowYield;
-pattern=this.finalize(this.startNode(startToken),new Node.AssignmentPattern(pattern,right));
-}
-return pattern;
-};
-
-Parser.prototype.parseVariableIdentifier=function(kind){
-var node=this.createNode();
-var token=this.nextToken();
-if(token.type===4&&token.value==='yield'){
-if(this.context.strict){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictReservedWord);
-}else
-if(!this.context.allowYield){
-this.throwUnexpectedToken(token);
-}
-}else
-if(token.type!==3){
-if(this.context.strict&&token.type===4&&this.scanner.isStrictModeReservedWord(token.value)){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictReservedWord);
-}else
-{
-if(this.context.strict||token.value!=='let'||kind!=='var'){
-this.throwUnexpectedToken(token);
-}
-}
-}else
-if((this.context.isModule||this.context.await)&&token.type===3&&token.value==='await'){
-this.tolerateUnexpectedToken(token);
-}
-return this.finalize(node,new Node.Identifier(token.value));
-};
-Parser.prototype.parseVariableDeclaration=function(options){
-var node=this.createNode();
-var params=[];
-var id=this.parsePattern(params,'var');
-if(this.context.strict&&id.type===syntax_1.Syntax.Identifier){
-if(this.scanner.isRestrictedWord(id.name)){
-this.tolerateError(messages_1.Messages.StrictVarName);
-}
-}
-var init=null;
-if(this.match('=')){
-this.nextToken();
-init=this.isolateCoverGrammar(this.parseAssignmentExpression);
-}else
-if(id.type!==syntax_1.Syntax.Identifier&&!options.inFor){
-this.expect('=');
-}
-return this.finalize(node,new Node.VariableDeclarator(id,init));
-};
-Parser.prototype.parseVariableDeclarationList=function(options){
-var opt={inFor:options.inFor};
-var list=[];
-list.push(this.parseVariableDeclaration(opt));
-while(this.match(',')){
-this.nextToken();
-list.push(this.parseVariableDeclaration(opt));
-}
-return list;
-};
-Parser.prototype.parseVariableStatement=function(){
-var node=this.createNode();
-this.expectKeyword('var');
-var declarations=this.parseVariableDeclarationList({inFor:false});
-this.consumeSemicolon();
-return this.finalize(node,new Node.VariableDeclaration(declarations,'var'));
-};
-
-Parser.prototype.parseEmptyStatement=function(){
-var node=this.createNode();
-this.expect(';');
-return this.finalize(node,new Node.EmptyStatement());
-};
-
-Parser.prototype.parseExpressionStatement=function(){
-var node=this.createNode();
-var expr=this.parseExpression();
-this.consumeSemicolon();
-return this.finalize(node,new Node.ExpressionStatement(expr));
-};
-
-Parser.prototype.parseIfClause=function(){
-if(this.context.strict&&this.matchKeyword('function')){
-this.tolerateError(messages_1.Messages.StrictFunction);
-}
-return this.parseStatement();
-};
-Parser.prototype.parseIfStatement=function(){
-var node=this.createNode();
-var consequent;
-var alternate=null;
-this.expectKeyword('if');
-this.expect('(');
-var test=this.parseExpression();
-if(!this.match(')')&&this.config.tolerant){
-this.tolerateUnexpectedToken(this.nextToken());
-consequent=this.finalize(this.createNode(),new Node.EmptyStatement());
-}else
-{
-this.expect(')');
-consequent=this.parseIfClause();
-if(this.matchKeyword('else')){
-this.nextToken();
-alternate=this.parseIfClause();
-}
-}
-return this.finalize(node,new Node.IfStatement(test,consequent,alternate));
-};
-
-Parser.prototype.parseDoWhileStatement=function(){
-var node=this.createNode();
-this.expectKeyword('do');
-var previousInIteration=this.context.inIteration;
-this.context.inIteration=true;
-var body=this.parseStatement();
-this.context.inIteration=previousInIteration;
-this.expectKeyword('while');
-this.expect('(');
-var test=this.parseExpression();
-if(!this.match(')')&&this.config.tolerant){
-this.tolerateUnexpectedToken(this.nextToken());
-}else
-{
-this.expect(')');
-if(this.match(';')){
-this.nextToken();
-}
-}
-return this.finalize(node,new Node.DoWhileStatement(body,test));
-};
-
-Parser.prototype.parseWhileStatement=function(){
-var node=this.createNode();
-var body;
-this.expectKeyword('while');
-this.expect('(');
-var test=this.parseExpression();
-if(!this.match(')')&&this.config.tolerant){
-this.tolerateUnexpectedToken(this.nextToken());
-body=this.finalize(this.createNode(),new Node.EmptyStatement());
-}else
-{
-this.expect(')');
-var previousInIteration=this.context.inIteration;
-this.context.inIteration=true;
-body=this.parseStatement();
-this.context.inIteration=previousInIteration;
-}
-return this.finalize(node,new Node.WhileStatement(test,body));
-};
-
-
-Parser.prototype.parseForStatement=function(){
-var init=null;
-var test=null;
-var update=null;
-var forIn=true;
-var left,right;
-var node=this.createNode();
-this.expectKeyword('for');
-this.expect('(');
-if(this.match(';')){
-this.nextToken();
-}else
-{
-if(this.matchKeyword('var')){
-init=this.createNode();
-this.nextToken();
-var previousAllowIn=this.context.allowIn;
-this.context.allowIn=false;
-var declarations=this.parseVariableDeclarationList({inFor:true});
-this.context.allowIn=previousAllowIn;
-if(declarations.length===1&&this.matchKeyword('in')){
-var decl=declarations[0];
-if(decl.init&&(decl.id.type===syntax_1.Syntax.ArrayPattern||decl.id.type===syntax_1.Syntax.ObjectPattern||this.context.strict)){
-this.tolerateError(messages_1.Messages.ForInOfLoopInitializer,'for-in');
-}
-init=this.finalize(init,new Node.VariableDeclaration(declarations,'var'));
-this.nextToken();
-left=init;
-right=this.parseExpression();
-init=null;
-}else
-if(declarations.length===1&&declarations[0].init===null&&this.matchContextualKeyword('of')){
-init=this.finalize(init,new Node.VariableDeclaration(declarations,'var'));
-this.nextToken();
-left=init;
-right=this.parseAssignmentExpression();
-init=null;
-forIn=false;
-}else
-{
-init=this.finalize(init,new Node.VariableDeclaration(declarations,'var'));
-this.expect(';');
-}
-}else
-if(this.matchKeyword('const')||this.matchKeyword('let')){
-init=this.createNode();
-var kind=this.nextToken().value;
-if(!this.context.strict&&this.lookahead.value==='in'){
-init=this.finalize(init,new Node.Identifier(kind));
-this.nextToken();
-left=init;
-right=this.parseExpression();
-init=null;
-}else
-{
-var previousAllowIn=this.context.allowIn;
-this.context.allowIn=false;
-var declarations=this.parseBindingList(kind,{inFor:true});
-this.context.allowIn=previousAllowIn;
-if(declarations.length===1&&declarations[0].init===null&&this.matchKeyword('in')){
-init=this.finalize(init,new Node.VariableDeclaration(declarations,kind));
-this.nextToken();
-left=init;
-right=this.parseExpression();
-init=null;
-}else
-if(declarations.length===1&&declarations[0].init===null&&this.matchContextualKeyword('of')){
-init=this.finalize(init,new Node.VariableDeclaration(declarations,kind));
-this.nextToken();
-left=init;
-right=this.parseAssignmentExpression();
-init=null;
-forIn=false;
-}else
-{
-this.consumeSemicolon();
-init=this.finalize(init,new Node.VariableDeclaration(declarations,kind));
-}
-}
-}else
-{
-var initStartToken=this.lookahead;
-var previousAllowIn=this.context.allowIn;
-this.context.allowIn=false;
-init=this.inheritCoverGrammar(this.parseAssignmentExpression);
-this.context.allowIn=previousAllowIn;
-if(this.matchKeyword('in')){
-if(!this.context.isAssignmentTarget||init.type===syntax_1.Syntax.AssignmentExpression){
-this.tolerateError(messages_1.Messages.InvalidLHSInForIn);
-}
-this.nextToken();
-this.reinterpretExpressionAsPattern(init);
-left=init;
-right=this.parseExpression();
-init=null;
-}else
-if(this.matchContextualKeyword('of')){
-if(!this.context.isAssignmentTarget||init.type===syntax_1.Syntax.AssignmentExpression){
-this.tolerateError(messages_1.Messages.InvalidLHSInForLoop);
-}
-this.nextToken();
-this.reinterpretExpressionAsPattern(init);
-left=init;
-right=this.parseAssignmentExpression();
-init=null;
-forIn=false;
-}else
-{
-if(this.match(',')){
-var initSeq=[init];
-while(this.match(',')){
-this.nextToken();
-initSeq.push(this.isolateCoverGrammar(this.parseAssignmentExpression));
-}
-init=this.finalize(this.startNode(initStartToken),new Node.SequenceExpression(initSeq));
-}
-this.expect(';');
-}
-}
-}
-if(typeof left==='undefined'){
-if(!this.match(';')){
-test=this.parseExpression();
-}
-this.expect(';');
-if(!this.match(')')){
-update=this.parseExpression();
-}
-}
-var body;
-if(!this.match(')')&&this.config.tolerant){
-this.tolerateUnexpectedToken(this.nextToken());
-body=this.finalize(this.createNode(),new Node.EmptyStatement());
-}else
-{
-this.expect(')');
-var previousInIteration=this.context.inIteration;
-this.context.inIteration=true;
-body=this.isolateCoverGrammar(this.parseStatement);
-this.context.inIteration=previousInIteration;
-}
-return typeof left==='undefined'?
-this.finalize(node,new Node.ForStatement(init,test,update,body)):
-forIn?this.finalize(node,new Node.ForInStatement(left,right,body)):
-this.finalize(node,new Node.ForOfStatement(left,right,body));
-};
-
-Parser.prototype.parseContinueStatement=function(){
-var node=this.createNode();
-this.expectKeyword('continue');
-var label=null;
-if(this.lookahead.type===3&&!this.hasLineTerminator){
-var id=this.parseVariableIdentifier();
-label=id;
-var key='$'+id.name;
-if(!Object.prototype.hasOwnProperty.call(this.context.labelSet,key)){
-this.throwError(messages_1.Messages.UnknownLabel,id.name);
-}
-}
-this.consumeSemicolon();
-if(label===null&&!this.context.inIteration){
-this.throwError(messages_1.Messages.IllegalContinue);
-}
-return this.finalize(node,new Node.ContinueStatement(label));
-};
-
-Parser.prototype.parseBreakStatement=function(){
-var node=this.createNode();
-this.expectKeyword('break');
-var label=null;
-if(this.lookahead.type===3&&!this.hasLineTerminator){
-var id=this.parseVariableIdentifier();
-var key='$'+id.name;
-if(!Object.prototype.hasOwnProperty.call(this.context.labelSet,key)){
-this.throwError(messages_1.Messages.UnknownLabel,id.name);
-}
-label=id;
-}
-this.consumeSemicolon();
-if(label===null&&!this.context.inIteration&&!this.context.inSwitch){
-this.throwError(messages_1.Messages.IllegalBreak);
-}
-return this.finalize(node,new Node.BreakStatement(label));
-};
-
-Parser.prototype.parseReturnStatement=function(){
-if(!this.context.inFunctionBody){
-this.tolerateError(messages_1.Messages.IllegalReturn);
-}
-var node=this.createNode();
-this.expectKeyword('return');
-var hasArgument=!this.match(';')&&!this.match('}')&&
-!this.hasLineTerminator&&this.lookahead.type!==2||
-this.lookahead.type===8||
-this.lookahead.type===10;
-var argument=hasArgument?this.parseExpression():null;
-this.consumeSemicolon();
-return this.finalize(node,new Node.ReturnStatement(argument));
-};
-
-Parser.prototype.parseWithStatement=function(){
-if(this.context.strict){
-this.tolerateError(messages_1.Messages.StrictModeWith);
-}
-var node=this.createNode();
-var body;
-this.expectKeyword('with');
-this.expect('(');
-var object=this.parseExpression();
-if(!this.match(')')&&this.config.tolerant){
-this.tolerateUnexpectedToken(this.nextToken());
-body=this.finalize(this.createNode(),new Node.EmptyStatement());
-}else
-{
-this.expect(')');
-body=this.parseStatement();
-}
-return this.finalize(node,new Node.WithStatement(object,body));
-};
-
-Parser.prototype.parseSwitchCase=function(){
-var node=this.createNode();
-var test;
-if(this.matchKeyword('default')){
-this.nextToken();
-test=null;
-}else
-{
-this.expectKeyword('case');
-test=this.parseExpression();
-}
-this.expect(':');
-var consequent=[];
-while(true){
-if(this.match('}')||this.matchKeyword('default')||this.matchKeyword('case')){
-break;
-}
-consequent.push(this.parseStatementListItem());
-}
-return this.finalize(node,new Node.SwitchCase(test,consequent));
-};
-Parser.prototype.parseSwitchStatement=function(){
-var node=this.createNode();
-this.expectKeyword('switch');
-this.expect('(');
-var discriminant=this.parseExpression();
-this.expect(')');
-var previousInSwitch=this.context.inSwitch;
-this.context.inSwitch=true;
-var cases=[];
-var defaultFound=false;
-this.expect('{');
-while(true){
-if(this.match('}')){
-break;
-}
-var clause=this.parseSwitchCase();
-if(clause.test===null){
-if(defaultFound){
-this.throwError(messages_1.Messages.MultipleDefaultsInSwitch);
-}
-defaultFound=true;
-}
-cases.push(clause);
-}
-this.expect('}');
-this.context.inSwitch=previousInSwitch;
-return this.finalize(node,new Node.SwitchStatement(discriminant,cases));
-};
-
-Parser.prototype.parseLabelledStatement=function(){
-var node=this.createNode();
-var expr=this.parseExpression();
-var statement;
-if(expr.type===syntax_1.Syntax.Identifier&&this.match(':')){
-this.nextToken();
-var id=expr;
-var key='$'+id.name;
-if(Object.prototype.hasOwnProperty.call(this.context.labelSet,key)){
-this.throwError(messages_1.Messages.Redeclaration,'Label',id.name);
-}
-this.context.labelSet[key]=true;
-var body=void 0;
-if(this.matchKeyword('class')){
-this.tolerateUnexpectedToken(this.lookahead);
-body=this.parseClassDeclaration();
-}else
-if(this.matchKeyword('function')){
-var token=this.lookahead;
-var declaration=this.parseFunctionDeclaration();
-if(this.context.strict){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictFunction);
-}else
-if(declaration.generator){
-this.tolerateUnexpectedToken(token,messages_1.Messages.GeneratorInLegacyContext);
-}
-body=declaration;
-}else
-{
-body=this.parseStatement();
-}
-delete this.context.labelSet[key];
-statement=new Node.LabeledStatement(id,body);
-}else
-{
-this.consumeSemicolon();
-statement=new Node.ExpressionStatement(expr);
-}
-return this.finalize(node,statement);
-};
-
-Parser.prototype.parseThrowStatement=function(){
-var node=this.createNode();
-this.expectKeyword('throw');
-if(this.hasLineTerminator){
-this.throwError(messages_1.Messages.NewlineAfterThrow);
-}
-var argument=this.parseExpression();
-this.consumeSemicolon();
-return this.finalize(node,new Node.ThrowStatement(argument));
-};
-
-Parser.prototype.parseCatchClause=function(){
-var node=this.createNode();
-this.expectKeyword('catch');
-this.expect('(');
-if(this.match(')')){
-this.throwUnexpectedToken(this.lookahead);
-}
-var params=[];
-var param=this.parsePattern(params);
-var paramMap={};
-for(var i=0;i<params.length;i++){
-var key='$'+params[i].value;
-if(Object.prototype.hasOwnProperty.call(paramMap,key)){
-this.tolerateError(messages_1.Messages.DuplicateBinding,params[i].value);
-}
-paramMap[key]=true;
-}
-if(this.context.strict&&param.type===syntax_1.Syntax.Identifier){
-if(this.scanner.isRestrictedWord(param.name)){
-this.tolerateError(messages_1.Messages.StrictCatchVariable);
-}
-}
-this.expect(')');
-var body=this.parseBlock();
-return this.finalize(node,new Node.CatchClause(param,body));
-};
-Parser.prototype.parseFinallyClause=function(){
-this.expectKeyword('finally');
-return this.parseBlock();
-};
-Parser.prototype.parseTryStatement=function(){
-var node=this.createNode();
-this.expectKeyword('try');
-var block=this.parseBlock();
-var handler=this.matchKeyword('catch')?this.parseCatchClause():null;
-var finalizer=this.matchKeyword('finally')?this.parseFinallyClause():null;
-if(!handler&&!finalizer){
-this.throwError(messages_1.Messages.NoCatchOrFinally);
-}
-return this.finalize(node,new Node.TryStatement(block,handler,finalizer));
-};
-
-Parser.prototype.parseDebuggerStatement=function(){
-var node=this.createNode();
-this.expectKeyword('debugger');
-this.consumeSemicolon();
-return this.finalize(node,new Node.DebuggerStatement());
-};
-
-Parser.prototype.parseStatement=function(){
-var statement;
-switch(this.lookahead.type){
-case 1:
-case 5:
-case 6:
-case 8:
-case 10:
-case 9:
-statement=this.parseExpressionStatement();
-break;
-case 7:
-var value=this.lookahead.value;
-if(value==='{'){
-statement=this.parseBlock();
-}else
-if(value==='('){
-statement=this.parseExpressionStatement();
-}else
-if(value===';'){
-statement=this.parseEmptyStatement();
-}else
-{
-statement=this.parseExpressionStatement();
-}
-break;
-case 3:
-statement=this.matchAsyncFunction()?this.parseFunctionDeclaration():this.parseLabelledStatement();
-break;
-case 4:
-switch(this.lookahead.value){
-case'break':
-statement=this.parseBreakStatement();
-break;
-case'continue':
-statement=this.parseContinueStatement();
-break;
-case'debugger':
-statement=this.parseDebuggerStatement();
-break;
-case'do':
-statement=this.parseDoWhileStatement();
-break;
-case'for':
-statement=this.parseForStatement();
-break;
-case'function':
-statement=this.parseFunctionDeclaration();
-break;
-case'if':
-statement=this.parseIfStatement();
-break;
-case'return':
-statement=this.parseReturnStatement();
-break;
-case'switch':
-statement=this.parseSwitchStatement();
-break;
-case'throw':
-statement=this.parseThrowStatement();
-break;
-case'try':
-statement=this.parseTryStatement();
-break;
-case'var':
-statement=this.parseVariableStatement();
-break;
-case'while':
-statement=this.parseWhileStatement();
-break;
-case'with':
-statement=this.parseWithStatement();
-break;
-default:
-statement=this.parseExpressionStatement();
-break;}
-
-break;
-default:
-statement=this.throwUnexpectedToken(this.lookahead);}
-
-return statement;
-};
-
-Parser.prototype.parseFunctionSourceElements=function(){
-var node=this.createNode();
-this.expect('{');
-var body=this.parseDirectivePrologues();
-var previousLabelSet=this.context.labelSet;
-var previousInIteration=this.context.inIteration;
-var previousInSwitch=this.context.inSwitch;
-var previousInFunctionBody=this.context.inFunctionBody;
-this.context.labelSet={};
-this.context.inIteration=false;
-this.context.inSwitch=false;
-this.context.inFunctionBody=true;
-while(this.lookahead.type!==2){
-if(this.match('}')){
-break;
-}
-body.push(this.parseStatementListItem());
-}
-this.expect('}');
-this.context.labelSet=previousLabelSet;
-this.context.inIteration=previousInIteration;
-this.context.inSwitch=previousInSwitch;
-this.context.inFunctionBody=previousInFunctionBody;
-return this.finalize(node,new Node.BlockStatement(body));
-};
-Parser.prototype.validateParam=function(options,param,name){
-var key='$'+name;
-if(this.context.strict){
-if(this.scanner.isRestrictedWord(name)){
-options.stricted=param;
-options.message=messages_1.Messages.StrictParamName;
-}
-if(Object.prototype.hasOwnProperty.call(options.paramSet,key)){
-options.stricted=param;
-options.message=messages_1.Messages.StrictParamDupe;
-}
-}else
-if(!options.firstRestricted){
-if(this.scanner.isRestrictedWord(name)){
-options.firstRestricted=param;
-options.message=messages_1.Messages.StrictParamName;
-}else
-if(this.scanner.isStrictModeReservedWord(name)){
-options.firstRestricted=param;
-options.message=messages_1.Messages.StrictReservedWord;
-}else
-if(Object.prototype.hasOwnProperty.call(options.paramSet,key)){
-options.stricted=param;
-options.message=messages_1.Messages.StrictParamDupe;
-}
-}
-
-if(typeof Object.defineProperty==='function'){
-Object.defineProperty(options.paramSet,key,{value:true,enumerable:true,writable:true,configurable:true});
-}else
-{
-options.paramSet[key]=true;
-}
-};
-Parser.prototype.parseRestElement=function(params){
-var node=this.createNode();
-this.expect('...');
-var arg=this.parsePattern(params);
-if(this.match('=')){
-this.throwError(messages_1.Messages.DefaultRestParameter);
-}
-if(!this.match(')')){
-this.throwError(messages_1.Messages.ParameterAfterRestParameter);
-}
-return this.finalize(node,new Node.RestElement(arg));
-};
-Parser.prototype.parseFormalParameter=function(options){
-var params=[];
-var param=this.match('...')?this.parseRestElement(params):this.parsePatternWithDefault(params);
-for(var i=0;i<params.length;i++){
-this.validateParam(options,params[i],params[i].value);
-}
-options.simple=options.simple&&param instanceof Node.Identifier;
-options.params.push(param);
-};
-Parser.prototype.parseFormalParameters=function(firstRestricted){
-var options;
-options={
-simple:true,
-params:[],
-firstRestricted:firstRestricted};
-
-this.expect('(');
-if(!this.match(')')){
-options.paramSet={};
-while(this.lookahead.type!==2){
-this.parseFormalParameter(options);
-if(this.match(')')){
-break;
-}
-this.expect(',');
-if(this.match(')')){
-break;
-}
-}
-}
-this.expect(')');
-return{
-simple:options.simple,
-params:options.params,
-stricted:options.stricted,
-firstRestricted:options.firstRestricted,
-message:options.message};
-
-};
-Parser.prototype.matchAsyncFunction=function(){
-var match=this.matchContextualKeyword('async');
-if(match){
-var state=this.scanner.saveState();
-this.scanner.scanComments();
-var next=this.scanner.lex();
-this.scanner.restoreState(state);
-match=state.lineNumber===next.lineNumber&&next.type===4&&next.value==='function';
-}
-return match;
-};
-Parser.prototype.parseFunctionDeclaration=function(identifierIsOptional){
-var node=this.createNode();
-var isAsync=this.matchContextualKeyword('async');
-if(isAsync){
-this.nextToken();
-}
-this.expectKeyword('function');
-var isGenerator=isAsync?false:this.match('*');
-if(isGenerator){
-this.nextToken();
-}
-var message;
-var id=null;
-var firstRestricted=null;
-if(!identifierIsOptional||!this.match('(')){
-var token=this.lookahead;
-id=this.parseVariableIdentifier();
-if(this.context.strict){
-if(this.scanner.isRestrictedWord(token.value)){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictFunctionName);
-}
-}else
-{
-if(this.scanner.isRestrictedWord(token.value)){
-firstRestricted=token;
-message=messages_1.Messages.StrictFunctionName;
-}else
-if(this.scanner.isStrictModeReservedWord(token.value)){
-firstRestricted=token;
-message=messages_1.Messages.StrictReservedWord;
-}
-}
-}
-var previousAllowAwait=this.context.await;
-var previousAllowYield=this.context.allowYield;
-this.context.await=isAsync;
-this.context.allowYield=!isGenerator;
-var formalParameters=this.parseFormalParameters(firstRestricted);
-var params=formalParameters.params;
-var stricted=formalParameters.stricted;
-firstRestricted=formalParameters.firstRestricted;
-if(formalParameters.message){
-message=formalParameters.message;
-}
-var previousStrict=this.context.strict;
-var previousAllowStrictDirective=this.context.allowStrictDirective;
-this.context.allowStrictDirective=formalParameters.simple;
-var body=this.parseFunctionSourceElements();
-if(this.context.strict&&firstRestricted){
-this.throwUnexpectedToken(firstRestricted,message);
-}
-if(this.context.strict&&stricted){
-this.tolerateUnexpectedToken(stricted,message);
-}
-this.context.strict=previousStrict;
-this.context.allowStrictDirective=previousAllowStrictDirective;
-this.context.await=previousAllowAwait;
-this.context.allowYield=previousAllowYield;
-return isAsync?this.finalize(node,new Node.AsyncFunctionDeclaration(id,params,body)):
-this.finalize(node,new Node.FunctionDeclaration(id,params,body,isGenerator));
-};
-Parser.prototype.parseFunctionExpression=function(){
-var node=this.createNode();
-var isAsync=this.matchContextualKeyword('async');
-if(isAsync){
-this.nextToken();
-}
-this.expectKeyword('function');
-var isGenerator=isAsync?false:this.match('*');
-if(isGenerator){
-this.nextToken();
-}
-var message;
-var id=null;
-var firstRestricted;
-var previousAllowAwait=this.context.await;
-var previousAllowYield=this.context.allowYield;
-this.context.await=isAsync;
-this.context.allowYield=!isGenerator;
-if(!this.match('(')){
-var token=this.lookahead;
-id=!this.context.strict&&!isGenerator&&this.matchKeyword('yield')?this.parseIdentifierName():this.parseVariableIdentifier();
-if(this.context.strict){
-if(this.scanner.isRestrictedWord(token.value)){
-this.tolerateUnexpectedToken(token,messages_1.Messages.StrictFunctionName);
-}
-}else
-{
-if(this.scanner.isRestrictedWord(token.value)){
-firstRestricted=token;
-message=messages_1.Messages.StrictFunctionName;
-}else
-if(this.scanner.isStrictModeReservedWord(token.value)){
-firstRestricted=token;
-message=messages_1.Messages.StrictReservedWord;
-}
-}
-}
-var formalParameters=this.parseFormalParameters(firstRestricted);
-var params=formalParameters.params;
-var stricted=formalParameters.stricted;
-firstRestricted=formalParameters.firstRestricted;
-if(formalParameters.message){
-message=formalParameters.message;
-}
-var previousStrict=this.context.strict;
-var previousAllowStrictDirective=this.context.allowStrictDirective;
-this.context.allowStrictDirective=formalParameters.simple;
-var body=this.parseFunctionSourceElements();
-if(this.context.strict&&firstRestricted){
-this.throwUnexpectedToken(firstRestricted,message);
-}
-if(this.context.strict&&stricted){
-this.tolerateUnexpectedToken(stricted,message);
-}
-this.context.strict=previousStrict;
-this.context.allowStrictDirective=previousAllowStrictDirective;
-this.context.await=previousAllowAwait;
-this.context.allowYield=previousAllowYield;
-return isAsync?this.finalize(node,new Node.AsyncFunctionExpression(id,params,body)):
-this.finalize(node,new Node.FunctionExpression(id,params,body,isGenerator));
-};
-
-Parser.prototype.parseDirective=function(){
-var token=this.lookahead;
-var node=this.createNode();
-var expr=this.parseExpression();
-var directive=expr.type===syntax_1.Syntax.Literal?this.getTokenRaw(token).slice(1,-1):null;
-this.consumeSemicolon();
-return this.finalize(node,directive?new Node.Directive(expr,directive):new Node.ExpressionStatement(expr));
-};
-Parser.prototype.parseDirectivePrologues=function(){
-var firstRestricted=null;
-var body=[];
-while(true){
-var token=this.lookahead;
-if(token.type!==8){
-break;
-}
-var statement=this.parseDirective();
-body.push(statement);
-var directive=statement.directive;
-if(typeof directive!=='string'){
-break;
-}
-if(directive==='use strict'){
-this.context.strict=true;
-if(firstRestricted){
-this.tolerateUnexpectedToken(firstRestricted,messages_1.Messages.StrictOctalLiteral);
-}
-if(!this.context.allowStrictDirective){
-this.tolerateUnexpectedToken(token,messages_1.Messages.IllegalLanguageModeDirective);
-}
-}else
-{
-if(!firstRestricted&&token.octal){
-firstRestricted=token;
-}
-}
-}
-return body;
-};
-
-Parser.prototype.qualifiedPropertyName=function(token){
-switch(token.type){
-case 3:
-case 8:
-case 1:
-case 5:
-case 6:
-case 4:
-return true;
-case 7:
-return token.value==='[';
-default:
-break;}
-
-return false;
-};
-Parser.prototype.parseGetterMethod=function(){
-var node=this.createNode();
-var isGenerator=false;
-var previousAllowYield=this.context.allowYield;
-this.context.allowYield=!isGenerator;
-var formalParameters=this.parseFormalParameters();
-if(formalParameters.params.length>0){
-this.tolerateError(messages_1.Messages.BadGetterArity);
-}
-var method=this.parsePropertyMethod(formalParameters);
-this.context.allowYield=previousAllowYield;
-return this.finalize(node,new Node.FunctionExpression(null,formalParameters.params,method,isGenerator));
-};
-Parser.prototype.parseSetterMethod=function(){
-var node=this.createNode();
-var isGenerator=false;
-var previousAllowYield=this.context.allowYield;
-this.context.allowYield=!isGenerator;
-var formalParameters=this.parseFormalParameters();
-if(formalParameters.params.length!==1){
-this.tolerateError(messages_1.Messages.BadSetterArity);
-}else
-if(formalParameters.params[0]instanceof Node.RestElement){
-this.tolerateError(messages_1.Messages.BadSetterRestParameter);
-}
-var method=this.parsePropertyMethod(formalParameters);
-this.context.allowYield=previousAllowYield;
-return this.finalize(node,new Node.FunctionExpression(null,formalParameters.params,method,isGenerator));
-};
-Parser.prototype.parseGeneratorMethod=function(){
-var node=this.createNode();
-var isGenerator=true;
-var previousAllowYield=this.context.allowYield;
-this.context.allowYield=true;
-var params=this.parseFormalParameters();
-this.context.allowYield=false;
-var method=this.parsePropertyMethod(params);
-this.context.allowYield=previousAllowYield;
-return this.finalize(node,new Node.FunctionExpression(null,params.params,method,isGenerator));
-};
-
-Parser.prototype.isStartOfExpression=function(){
-var start=true;
-var value=this.lookahead.value;
-switch(this.lookahead.type){
-case 7:
-start=value==='['||value==='('||value==='{'||
-value==='+'||value==='-'||
-value==='!'||value==='~'||
-value==='++'||value==='--'||
-value==='/'||value==='/=';
-break;
-case 4:
-start=value==='class'||value==='delete'||
-value==='function'||value==='let'||value==='new'||
-value==='super'||value==='this'||value==='typeof'||
-value==='void'||value==='yield';
-break;
-default:
-break;}
-
-return start;
-};
-Parser.prototype.parseYieldExpression=function(){
-var node=this.createNode();
-this.expectKeyword('yield');
-var argument=null;
-var delegate=false;
-if(!this.hasLineTerminator){
-var previousAllowYield=this.context.allowYield;
-this.context.allowYield=false;
-delegate=this.match('*');
-if(delegate){
-this.nextToken();
-argument=this.parseAssignmentExpression();
-}else
-if(this.isStartOfExpression()){
-argument=this.parseAssignmentExpression();
-}
-this.context.allowYield=previousAllowYield;
-}
-return this.finalize(node,new Node.YieldExpression(argument,delegate));
-};
-
-Parser.prototype.parseClassElement=function(hasConstructor){
-var token=this.lookahead;
-var node=this.createNode();
-var kind='';
-var key=null;
-var value=null;
-var computed=false;
-var method=false;
-var isStatic=false;
-var isAsync=false;
-if(this.match('*')){
-this.nextToken();
-}else
-{
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-var id=key;
-if(id.name==='static'&&(this.qualifiedPropertyName(this.lookahead)||this.match('*'))){
-token=this.lookahead;
-isStatic=true;
-computed=this.match('[');
-if(this.match('*')){
-this.nextToken();
-}else
-{
-key=this.parseObjectPropertyKey();
-}
-}
-if(token.type===3&&!this.hasLineTerminator&&token.value==='async'){
-var punctuator=this.lookahead.value;
-if(punctuator!==':'&&punctuator!=='('&&punctuator!=='*'){
-isAsync=true;
-token=this.lookahead;
-key=this.parseObjectPropertyKey();
-if(token.type===3&&token.value==='constructor'){
-this.tolerateUnexpectedToken(token,messages_1.Messages.ConstructorIsAsync);
-}
-}
-}
-}
-var lookaheadPropertyKey=this.qualifiedPropertyName(this.lookahead);
-if(token.type===3){
-if(token.value==='get'&&lookaheadPropertyKey){
-kind='get';
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-this.context.allowYield=false;
-value=this.parseGetterMethod();
-}else
-if(token.value==='set'&&lookaheadPropertyKey){
-kind='set';
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-value=this.parseSetterMethod();
-}
-}else
-if(token.type===7&&token.value==='*'&&lookaheadPropertyKey){
-kind='init';
-computed=this.match('[');
-key=this.parseObjectPropertyKey();
-value=this.parseGeneratorMethod();
-method=true;
-}
-if(!kind&&key&&this.match('(')){
-kind='init';
-value=isAsync?this.parsePropertyMethodAsyncFunction():this.parsePropertyMethodFunction();
-method=true;
-}
-if(!kind){
-this.throwUnexpectedToken(this.lookahead);
-}
-if(kind==='init'){
-kind='method';
-}
-if(!computed){
-if(isStatic&&this.isPropertyKey(key,'prototype')){
-this.throwUnexpectedToken(token,messages_1.Messages.StaticPrototype);
-}
-if(!isStatic&&this.isPropertyKey(key,'constructor')){
-if(kind!=='method'||!method||value&&value.generator){
-this.throwUnexpectedToken(token,messages_1.Messages.ConstructorSpecialMethod);
-}
-if(hasConstructor.value){
-this.throwUnexpectedToken(token,messages_1.Messages.DuplicateConstructor);
-}else
-{
-hasConstructor.value=true;
-}
-kind='constructor';
-}
-}
-return this.finalize(node,new Node.MethodDefinition(key,computed,value,kind,isStatic));
-};
-Parser.prototype.parseClassElementList=function(){
-var body=[];
-var hasConstructor={value:false};
-this.expect('{');
-while(!this.match('}')){
-if(this.match(';')){
-this.nextToken();
-}else
-{
-body.push(this.parseClassElement(hasConstructor));
-}
-}
-this.expect('}');
-return body;
-};
-Parser.prototype.parseClassBody=function(){
-var node=this.createNode();
-var elementList=this.parseClassElementList();
-return this.finalize(node,new Node.ClassBody(elementList));
-};
-Parser.prototype.parseClassDeclaration=function(identifierIsOptional){
-var node=this.createNode();
-var previousStrict=this.context.strict;
-this.context.strict=true;
-this.expectKeyword('class');
-var id=identifierIsOptional&&this.lookahead.type!==3?null:this.parseVariableIdentifier();
-var superClass=null;
-if(this.matchKeyword('extends')){
-this.nextToken();
-superClass=this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall);
-}
-var classBody=this.parseClassBody();
-this.context.strict=previousStrict;
-return this.finalize(node,new Node.ClassDeclaration(id,superClass,classBody));
-};
-Parser.prototype.parseClassExpression=function(){
-var node=this.createNode();
-var previousStrict=this.context.strict;
-this.context.strict=true;
-this.expectKeyword('class');
-var id=this.lookahead.type===3?this.parseVariableIdentifier():null;
-var superClass=null;
-if(this.matchKeyword('extends')){
-this.nextToken();
-superClass=this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall);
-}
-var classBody=this.parseClassBody();
-this.context.strict=previousStrict;
-return this.finalize(node,new Node.ClassExpression(id,superClass,classBody));
-};
-
-
-Parser.prototype.parseModule=function(){
-this.context.strict=true;
-this.context.isModule=true;
-this.scanner.isModule=true;
-var node=this.createNode();
-var body=this.parseDirectivePrologues();
-while(this.lookahead.type!==2){
-body.push(this.parseStatementListItem());
-}
-return this.finalize(node,new Node.Module(body));
-};
-Parser.prototype.parseScript=function(){
-var node=this.createNode();
-var body=this.parseDirectivePrologues();
-while(this.lookahead.type!==2){
-body.push(this.parseStatementListItem());
-}
-return this.finalize(node,new Node.Script(body));
-};
-
-Parser.prototype.parseModuleSpecifier=function(){
-var node=this.createNode();
-if(this.lookahead.type!==8){
-this.throwError(messages_1.Messages.InvalidModuleSpecifier);
-}
-var token=this.nextToken();
-var raw=this.getTokenRaw(token);
-return this.finalize(node,new Node.Literal(token.value,raw));
-};
-
-Parser.prototype.parseImportSpecifier=function(){
-var node=this.createNode();
-var imported;
-var local;
-if(this.lookahead.type===3){
-imported=this.parseVariableIdentifier();
-local=imported;
-if(this.matchContextualKeyword('as')){
-this.nextToken();
-local=this.parseVariableIdentifier();
-}
-}else
-{
-imported=this.parseIdentifierName();
-local=imported;
-if(this.matchContextualKeyword('as')){
-this.nextToken();
-local=this.parseVariableIdentifier();
-}else
-{
-this.throwUnexpectedToken(this.nextToken());
-}
-}
-return this.finalize(node,new Node.ImportSpecifier(local,imported));
-};
-
-Parser.prototype.parseNamedImports=function(){
-this.expect('{');
-var specifiers=[];
-while(!this.match('}')){
-specifiers.push(this.parseImportSpecifier());
-if(!this.match('}')){
-this.expect(',');
-}
-}
-this.expect('}');
-return specifiers;
-};
-
-Parser.prototype.parseImportDefaultSpecifier=function(){
-var node=this.createNode();
-var local=this.parseIdentifierName();
-return this.finalize(node,new Node.ImportDefaultSpecifier(local));
-};
-
-Parser.prototype.parseImportNamespaceSpecifier=function(){
-var node=this.createNode();
-this.expect('*');
-if(!this.matchContextualKeyword('as')){
-this.throwError(messages_1.Messages.NoAsAfterImportNamespace);
-}
-this.nextToken();
-var local=this.parseIdentifierName();
-return this.finalize(node,new Node.ImportNamespaceSpecifier(local));
-};
-Parser.prototype.parseImportDeclaration=function(){
-if(this.context.inFunctionBody){
-this.throwError(messages_1.Messages.IllegalImportDeclaration);
-}
-var node=this.createNode();
-this.expectKeyword('import');
-var src;
-var specifiers=[];
-if(this.lookahead.type===8){
-
-src=this.parseModuleSpecifier();
-}else
-{
-if(this.match('{')){
-
-specifiers=specifiers.concat(this.parseNamedImports());
-}else
-if(this.match('*')){
-
-specifiers.push(this.parseImportNamespaceSpecifier());
-}else
-if(this.isIdentifierName(this.lookahead)&&!this.matchKeyword('default')){
-
-specifiers.push(this.parseImportDefaultSpecifier());
-if(this.match(',')){
-this.nextToken();
-if(this.match('*')){
-
-specifiers.push(this.parseImportNamespaceSpecifier());
-}else
-if(this.match('{')){
-
-specifiers=specifiers.concat(this.parseNamedImports());
-}else
-{
-this.throwUnexpectedToken(this.lookahead);
-}
-}
-}else
-{
-this.throwUnexpectedToken(this.nextToken());
-}
-if(!this.matchContextualKeyword('from')){
-var message=this.lookahead.value?messages_1.Messages.UnexpectedToken:messages_1.Messages.MissingFromClause;
-this.throwError(message,this.lookahead.value);
-}
-this.nextToken();
-src=this.parseModuleSpecifier();
-}
-this.consumeSemicolon();
-return this.finalize(node,new Node.ImportDeclaration(specifiers,src));
-};
-
-Parser.prototype.parseExportSpecifier=function(){
-var node=this.createNode();
-var local=this.parseIdentifierName();
-var exported=local;
-if(this.matchContextualKeyword('as')){
-this.nextToken();
-exported=this.parseIdentifierName();
-}
-return this.finalize(node,new Node.ExportSpecifier(local,exported));
-};
-Parser.prototype.parseExportDeclaration=function(){
-if(this.context.inFunctionBody){
-this.throwError(messages_1.Messages.IllegalExportDeclaration);
-}
-var node=this.createNode();
-this.expectKeyword('export');
-var exportDeclaration;
-if(this.matchKeyword('default')){
-
-this.nextToken();
-if(this.matchKeyword('function')){
-
-
-var declaration=this.parseFunctionDeclaration(true);
-exportDeclaration=this.finalize(node,new Node.ExportDefaultDeclaration(declaration));
-}else
-if(this.matchKeyword('class')){
-
-var declaration=this.parseClassDeclaration(true);
-exportDeclaration=this.finalize(node,new Node.ExportDefaultDeclaration(declaration));
-}else
-if(this.matchContextualKeyword('async')){
-
-
-
-var declaration=this.matchAsyncFunction()?this.parseFunctionDeclaration(true):this.parseAssignmentExpression();
-exportDeclaration=this.finalize(node,new Node.ExportDefaultDeclaration(declaration));
-}else
-{
-if(this.matchContextualKeyword('from')){
-this.throwError(messages_1.Messages.UnexpectedToken,this.lookahead.value);
-}
-
-
-
-var declaration=this.match('{')?this.parseObjectInitializer():
-this.match('[')?this.parseArrayInitializer():this.parseAssignmentExpression();
-this.consumeSemicolon();
-exportDeclaration=this.finalize(node,new Node.ExportDefaultDeclaration(declaration));
-}
-}else
-if(this.match('*')){
-
-this.nextToken();
-if(!this.matchContextualKeyword('from')){
-var message=this.lookahead.value?messages_1.Messages.UnexpectedToken:messages_1.Messages.MissingFromClause;
-this.throwError(message,this.lookahead.value);
-}
-this.nextToken();
-var src=this.parseModuleSpecifier();
-this.consumeSemicolon();
-exportDeclaration=this.finalize(node,new Node.ExportAllDeclaration(src));
-}else
-if(this.lookahead.type===4){
-
-var declaration=void 0;
-switch(this.lookahead.value){
-case'let':
-case'const':
-declaration=this.parseLexicalDeclaration({inFor:false});
-break;
-case'var':
-case'class':
-case'function':
-declaration=this.parseStatementListItem();
-break;
-default:
-this.throwUnexpectedToken(this.lookahead);}
-
-exportDeclaration=this.finalize(node,new Node.ExportNamedDeclaration(declaration,[],null));
-}else
-if(this.matchAsyncFunction()){
-var declaration=this.parseFunctionDeclaration();
-exportDeclaration=this.finalize(node,new Node.ExportNamedDeclaration(declaration,[],null));
-}else
-{
-var specifiers=[];
-var source=null;
-var isExportFromIdentifier=false;
-this.expect('{');
-while(!this.match('}')){
-isExportFromIdentifier=isExportFromIdentifier||this.matchKeyword('default');
-specifiers.push(this.parseExportSpecifier());
-if(!this.match('}')){
-this.expect(',');
-}
-}
-this.expect('}');
-if(this.matchContextualKeyword('from')){
-
-
-this.nextToken();
-source=this.parseModuleSpecifier();
-this.consumeSemicolon();
-}else
-if(isExportFromIdentifier){
-
-var message=this.lookahead.value?messages_1.Messages.UnexpectedToken:messages_1.Messages.MissingFromClause;
-this.throwError(message,this.lookahead.value);
-}else
-{
-
-this.consumeSemicolon();
-}
-exportDeclaration=this.finalize(node,new Node.ExportNamedDeclaration(null,specifiers,source));
-}
-return exportDeclaration;
-};
-return Parser;
-}();
-exports.Parser=Parser;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-
-
-
-
-Object.defineProperty(exports,"__esModule",{value:true});
-function assert(condition,message){
-
-if(!condition){
-throw new Error('ASSERT: '+message);
-}
-}
-exports.assert=assert;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-
-Object.defineProperty(exports,"__esModule",{value:true});
-var ErrorHandler=function(){
-function ErrorHandler(){
-this.errors=[];
-this.tolerant=false;
-}
-ErrorHandler.prototype.recordError=function(error){
-this.errors.push(error);
-};
-ErrorHandler.prototype.tolerate=function(error){
-if(this.tolerant){
-this.recordError(error);
-}else
-{
-throw error;
-}
-};
-ErrorHandler.prototype.constructError=function(msg,column){
-var error=new Error(msg);
-try{
-throw error;
-}
-catch(base){
-
-if(Object.create&&Object.defineProperty){
-error=Object.create(base);
-Object.defineProperty(error,'column',{value:column});
-}
-}
-
-return error;
-};
-ErrorHandler.prototype.createError=function(index,line,col,description){
-var msg='Line '+line+': '+description;
-var error=this.constructError(msg,col);
-error.index=index;
-error.lineNumber=line;
-error.description=description;
-return error;
-};
-ErrorHandler.prototype.throwError=function(index,line,col,description){
-throw this.createError(index,line,col,description);
-};
-ErrorHandler.prototype.tolerateError=function(index,line,col,description){
-var error=this.createError(index,line,col,description);
-if(this.tolerant){
-this.recordError(error);
-}else
-{
-throw error;
-}
-};
-return ErrorHandler;
-}();
-exports.ErrorHandler=ErrorHandler;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-
-exports.Messages={
-BadGetterArity:'Getter must not have any formal parameters',
-BadSetterArity:'Setter must have exactly one formal parameter',
-BadSetterRestParameter:'Setter function argument must not be a rest parameter',
-ConstructorIsAsync:'Class constructor may not be an async method',
-ConstructorSpecialMethod:'Class constructor may not be an accessor',
-DeclarationMissingInitializer:'Missing initializer in %0 declaration',
-DefaultRestParameter:'Unexpected token =',
-DuplicateBinding:'Duplicate binding %0',
-DuplicateConstructor:'A class may only have one constructor',
-DuplicateProtoProperty:'Duplicate __proto__ fields are not allowed in object literals',
-ForInOfLoopInitializer:'%0 loop variable declaration may not have an initializer',
-GeneratorInLegacyContext:'Generator declarations are not allowed in legacy contexts',
-IllegalBreak:'Illegal break statement',
-IllegalContinue:'Illegal continue statement',
-IllegalExportDeclaration:'Unexpected token',
-IllegalImportDeclaration:'Unexpected token',
-IllegalLanguageModeDirective:'Illegal \'use strict\' directive in function with non-simple parameter list',
-IllegalReturn:'Illegal return statement',
-InvalidEscapedReservedWord:'Keyword must not contain escaped characters',
-InvalidHexEscapeSequence:'Invalid hexadecimal escape sequence',
-InvalidLHSInAssignment:'Invalid left-hand side in assignment',
-InvalidLHSInForIn:'Invalid left-hand side in for-in',
-InvalidLHSInForLoop:'Invalid left-hand side in for-loop',
-InvalidModuleSpecifier:'Unexpected token',
-InvalidRegExp:'Invalid regular expression',
-LetInLexicalBinding:'let is disallowed as a lexically bound name',
-MissingFromClause:'Unexpected token',
-MultipleDefaultsInSwitch:'More than one default clause in switch statement',
-NewlineAfterThrow:'Illegal newline after throw',
-NoAsAfterImportNamespace:'Unexpected token',
-NoCatchOrFinally:'Missing catch or finally after try',
-ParameterAfterRestParameter:'Rest parameter must be last formal parameter',
-Redeclaration:'%0 \'%1\' has already been declared',
-StaticPrototype:'Classes may not have static property named prototype',
-StrictCatchVariable:'Catch variable may not be eval or arguments in strict mode',
-StrictDelete:'Delete of an unqualified identifier in strict mode.',
-StrictFunction:'In strict mode code, functions can only be declared at top level or inside a block',
-StrictFunctionName:'Function name may not be eval or arguments in strict mode',
-StrictLHSAssignment:'Assignment to eval or arguments is not allowed in strict mode',
-StrictLHSPostfix:'Postfix increment/decrement may not have eval or arguments operand in strict mode',
-StrictLHSPrefix:'Prefix increment/decrement may not have eval or arguments operand in strict mode',
-StrictModeWith:'Strict mode code may not include a with statement',
-StrictOctalLiteral:'Octal literals are not allowed in strict mode.',
-StrictParamDupe:'Strict mode function may not have duplicate parameter names',
-StrictParamName:'Parameter name eval or arguments is not allowed in strict mode',
-StrictReservedWord:'Use of future reserved word in strict mode',
-StrictVarName:'Variable name may not be eval or arguments in strict mode',
-TemplateOctalLiteral:'Octal literals are not allowed in template strings.',
-UnexpectedEOS:'Unexpected end of input',
-UnexpectedIdentifier:'Unexpected identifier',
-UnexpectedNumber:'Unexpected number',
-UnexpectedReserved:'Unexpected reserved word',
-UnexpectedString:'Unexpected string',
-UnexpectedTemplate:'Unexpected quasi %0',
-UnexpectedToken:'Unexpected token %0',
-UnexpectedTokenIllegal:'Unexpected token ILLEGAL',
-UnknownLabel:'Undefined label \'%0\'',
-UnterminatedRegExp:'Invalid regular expression: missing /'};
-
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-var assert_1=__webpack_require__(9);
-var character_1=__webpack_require__(4);
-var messages_1=__webpack_require__(11);
-function hexValue(ch){
-return'0123456789abcdef'.indexOf(ch.toLowerCase());
-}
-function octalValue(ch){
-return'01234567'.indexOf(ch);
-}
-var Scanner=function(){
-function Scanner(code,handler){
-this.source=code;
-this.errorHandler=handler;
-this.trackComment=false;
-this.isModule=false;
-this.length=code.length;
-this.index=0;
-this.lineNumber=code.length>0?1:0;
-this.lineStart=0;
-this.curlyStack=[];
-}
-Scanner.prototype.saveState=function(){
-return{
-index:this.index,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart};
-
-};
-Scanner.prototype.restoreState=function(state){
-this.index=state.index;
-this.lineNumber=state.lineNumber;
-this.lineStart=state.lineStart;
-};
-Scanner.prototype.eof=function(){
-return this.index>=this.length;
-};
-Scanner.prototype.throwUnexpectedToken=function(message){
-if(message===void 0){message=messages_1.Messages.UnexpectedTokenIllegal;}
-return this.errorHandler.throwError(this.index,this.lineNumber,this.index-this.lineStart+1,message);
-};
-Scanner.prototype.tolerateUnexpectedToken=function(message){
-if(message===void 0){message=messages_1.Messages.UnexpectedTokenIllegal;}
-this.errorHandler.tolerateError(this.index,this.lineNumber,this.index-this.lineStart+1,message);
-};
-
-Scanner.prototype.skipSingleLineComment=function(offset){
-var comments=[];
-var start,loc;
-if(this.trackComment){
-comments=[];
-start=this.index-offset;
-loc={
-start:{
-line:this.lineNumber,
-column:this.index-this.lineStart-offset},
-
-end:{}};
-
-}
-while(!this.eof()){
-var ch=this.source.charCodeAt(this.index);
-++this.index;
-if(character_1.Character.isLineTerminator(ch)){
-if(this.trackComment){
-loc.end={
-line:this.lineNumber,
-column:this.index-this.lineStart-1};
-
-var entry={
-multiLine:false,
-slice:[start+offset,this.index-1],
-range:[start,this.index-1],
-loc:loc};
-
-comments.push(entry);
-}
-if(ch===13&&this.source.charCodeAt(this.index)===10){
-++this.index;
-}
-++this.lineNumber;
-this.lineStart=this.index;
-return comments;
-}
-}
-if(this.trackComment){
-loc.end={
-line:this.lineNumber,
-column:this.index-this.lineStart};
-
-var entry={
-multiLine:false,
-slice:[start+offset,this.index],
-range:[start,this.index],
-loc:loc};
-
-comments.push(entry);
-}
-return comments;
-};
-Scanner.prototype.skipMultiLineComment=function(){
-var comments=[];
-var start,loc;
-if(this.trackComment){
-comments=[];
-start=this.index-2;
-loc={
-start:{
-line:this.lineNumber,
-column:this.index-this.lineStart-2},
-
-end:{}};
-
-}
-while(!this.eof()){
-var ch=this.source.charCodeAt(this.index);
-if(character_1.Character.isLineTerminator(ch)){
-if(ch===0x0D&&this.source.charCodeAt(this.index+1)===0x0A){
-++this.index;
-}
-++this.lineNumber;
-++this.index;
-this.lineStart=this.index;
-}else
-if(ch===0x2A){
-
-if(this.source.charCodeAt(this.index+1)===0x2F){
-this.index+=2;
-if(this.trackComment){
-loc.end={
-line:this.lineNumber,
-column:this.index-this.lineStart};
-
-var entry={
-multiLine:true,
-slice:[start+2,this.index-2],
-range:[start,this.index],
-loc:loc};
-
-comments.push(entry);
-}
-return comments;
-}
-++this.index;
-}else
-{
-++this.index;
-}
-}
-
-if(this.trackComment){
-loc.end={
-line:this.lineNumber,
-column:this.index-this.lineStart};
-
-var entry={
-multiLine:true,
-slice:[start+2,this.index],
-range:[start,this.index],
-loc:loc};
-
-comments.push(entry);
-}
-this.tolerateUnexpectedToken();
-return comments;
-};
-Scanner.prototype.scanComments=function(){
-var comments;
-if(this.trackComment){
-comments=[];
-}
-var start=this.index===0;
-while(!this.eof()){
-var ch=this.source.charCodeAt(this.index);
-if(character_1.Character.isWhiteSpace(ch)){
-++this.index;
-}else
-if(character_1.Character.isLineTerminator(ch)){
-++this.index;
-if(ch===0x0D&&this.source.charCodeAt(this.index)===0x0A){
-++this.index;
-}
-++this.lineNumber;
-this.lineStart=this.index;
-start=true;
-}else
-if(ch===0x2F){
-ch=this.source.charCodeAt(this.index+1);
-if(ch===0x2F){
-this.index+=2;
-var comment=this.skipSingleLineComment(2);
-if(this.trackComment){
-comments=comments.concat(comment);
-}
-start=true;
-}else
-if(ch===0x2A){
-this.index+=2;
-var comment=this.skipMultiLineComment();
-if(this.trackComment){
-comments=comments.concat(comment);
-}
-}else
-{
-break;
-}
-}else
-if(start&&ch===0x2D){
-
-if(this.source.charCodeAt(this.index+1)===0x2D&&this.source.charCodeAt(this.index+2)===0x3E){
-
-this.index+=3;
-var comment=this.skipSingleLineComment(3);
-if(this.trackComment){
-comments=comments.concat(comment);
-}
-}else
-{
-break;
-}
-}else
-if(ch===0x3C&&!this.isModule){
-if(this.source.slice(this.index+1,this.index+4)==='!--'){
-this.index+=4;
-var comment=this.skipSingleLineComment(4);
-if(this.trackComment){
-comments=comments.concat(comment);
-}
-}else
-{
-break;
-}
-}else
-{
-break;
-}
-}
-return comments;
-};
-
-Scanner.prototype.isFutureReservedWord=function(id){
-switch(id){
-case'enum':
-case'export':
-case'import':
-case'super':
-return true;
-default:
-return false;}
-
-};
-Scanner.prototype.isStrictModeReservedWord=function(id){
-switch(id){
-case'implements':
-case'interface':
-case'package':
-case'private':
-case'protected':
-case'public':
-case'static':
-case'yield':
-case'let':
-return true;
-default:
-return false;}
-
-};
-Scanner.prototype.isRestrictedWord=function(id){
-return id==='eval'||id==='arguments';
-};
-
-Scanner.prototype.isKeyword=function(id){
-switch(id.length){
-case 2:
-return id==='if'||id==='in'||id==='do';
-case 3:
-return id==='var'||id==='for'||id==='new'||
-id==='try'||id==='let';
-case 4:
-return id==='this'||id==='else'||id==='case'||
-id==='void'||id==='with'||id==='enum';
-case 5:
-return id==='while'||id==='break'||id==='catch'||
-id==='throw'||id==='const'||id==='yield'||
-id==='class'||id==='super';
-case 6:
-return id==='return'||id==='typeof'||id==='delete'||
-id==='switch'||id==='export'||id==='import';
-case 7:
-return id==='default'||id==='finally'||id==='extends';
-case 8:
-return id==='function'||id==='continue'||id==='debugger';
-case 10:
-return id==='instanceof';
-default:
-return false;}
-
-};
-Scanner.prototype.codePointAt=function(i){
-var cp=this.source.charCodeAt(i);
-if(cp>=0xD800&&cp<=0xDBFF){
-var second=this.source.charCodeAt(i+1);
-if(second>=0xDC00&&second<=0xDFFF){
-var first=cp;
-cp=(first-0xD800)*0x400+second-0xDC00+0x10000;
-}
-}
-return cp;
-};
-Scanner.prototype.scanHexEscape=function(prefix){
-var len=prefix==='u'?4:2;
-var code=0;
-for(var i=0;i<len;++i){
-if(!this.eof()&&character_1.Character.isHexDigit(this.source.charCodeAt(this.index))){
-code=code*16+hexValue(this.source[this.index++]);
-}else
-{
-return null;
-}
-}
-return String.fromCharCode(code);
-};
-Scanner.prototype.scanUnicodeCodePointEscape=function(){
-var ch=this.source[this.index];
-var code=0;
-
-if(ch==='}'){
-this.throwUnexpectedToken();
-}
-while(!this.eof()){
-ch=this.source[this.index++];
-if(!character_1.Character.isHexDigit(ch.charCodeAt(0))){
-break;
-}
-code=code*16+hexValue(ch);
-}
-if(code>0x10FFFF||ch!=='}'){
-this.throwUnexpectedToken();
-}
-return character_1.Character.fromCodePoint(code);
-};
-Scanner.prototype.getIdentifier=function(){
-var start=this.index++;
-while(!this.eof()){
-var ch=this.source.charCodeAt(this.index);
-if(ch===0x5C){
-
-this.index=start;
-return this.getComplexIdentifier();
-}else
-if(ch>=0xD800&&ch<0xDFFF){
-
-this.index=start;
-return this.getComplexIdentifier();
-}
-if(character_1.Character.isIdentifierPart(ch)){
-++this.index;
-}else
-{
-break;
-}
-}
-return this.source.slice(start,this.index);
-};
-Scanner.prototype.getComplexIdentifier=function(){
-var cp=this.codePointAt(this.index);
-var id=character_1.Character.fromCodePoint(cp);
-this.index+=id.length;
-
-var ch;
-if(cp===0x5C){
-if(this.source.charCodeAt(this.index)!==0x75){
-this.throwUnexpectedToken();
-}
-++this.index;
-if(this.source[this.index]==='{'){
-++this.index;
-ch=this.scanUnicodeCodePointEscape();
-}else
-{
-ch=this.scanHexEscape('u');
-if(ch===null||ch==='\\'||!character_1.Character.isIdentifierStart(ch.charCodeAt(0))){
-this.throwUnexpectedToken();
-}
-}
-id=ch;
-}
-while(!this.eof()){
-cp=this.codePointAt(this.index);
-if(!character_1.Character.isIdentifierPart(cp)){
-break;
-}
-ch=character_1.Character.fromCodePoint(cp);
-id+=ch;
-this.index+=ch.length;
-
-if(cp===0x5C){
-id=id.substr(0,id.length-1);
-if(this.source.charCodeAt(this.index)!==0x75){
-this.throwUnexpectedToken();
-}
-++this.index;
-if(this.source[this.index]==='{'){
-++this.index;
-ch=this.scanUnicodeCodePointEscape();
-}else
-{
-ch=this.scanHexEscape('u');
-if(ch===null||ch==='\\'||!character_1.Character.isIdentifierPart(ch.charCodeAt(0))){
-this.throwUnexpectedToken();
-}
-}
-id+=ch;
-}
-}
-return id;
-};
-Scanner.prototype.octalToDecimal=function(ch){
-
-var octal=ch!=='0';
-var code=octalValue(ch);
-if(!this.eof()&&character_1.Character.isOctalDigit(this.source.charCodeAt(this.index))){
-octal=true;
-code=code*8+octalValue(this.source[this.index++]);
-
-
-if('0123'.indexOf(ch)>=0&&!this.eof()&&character_1.Character.isOctalDigit(this.source.charCodeAt(this.index))){
-code=code*8+octalValue(this.source[this.index++]);
-}
-}
-return{
-code:code,
-octal:octal};
-
-};
-
-Scanner.prototype.scanIdentifier=function(){
-var type;
-var start=this.index;
-
-var id=this.source.charCodeAt(start)===0x5C?this.getComplexIdentifier():this.getIdentifier();
-
-
-if(id.length===1){
-type=3;
-}else
-if(this.isKeyword(id)){
-type=4;
-}else
-if(id==='null'){
-type=5;
-}else
-if(id==='true'||id==='false'){
-type=1;
-}else
-{
-type=3;
-}
-if(type!==3&&start+id.length!==this.index){
-var restore=this.index;
-this.index=start;
-this.tolerateUnexpectedToken(messages_1.Messages.InvalidEscapedReservedWord);
-this.index=restore;
-}
-return{
-type:type,
-value:id,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-
-Scanner.prototype.scanPunctuator=function(){
-var start=this.index;
-
-var str=this.source[this.index];
-switch(str){
-case'(':
-case'{':
-if(str==='{'){
-this.curlyStack.push('{');
-}
-++this.index;
-break;
-case'.':
-++this.index;
-if(this.source[this.index]==='.'&&this.source[this.index+1]==='.'){
-
-this.index+=2;
-str='...';
-}
-break;
-case'}':
-++this.index;
-this.curlyStack.pop();
-break;
-case')':
-case';':
-case',':
-case'[':
-case']':
-case':':
-case'?':
-case'~':
-++this.index;
-break;
-default:
-
-str=this.source.substr(this.index,4);
-if(str==='>>>='){
-this.index+=4;
-}else
-{
-
-str=str.substr(0,3);
-if(str==='==='||str==='!=='||str==='>>>'||
-str==='<<='||str==='>>='||str==='**='){
-this.index+=3;
-}else
-{
-
-str=str.substr(0,2);
-if(str==='&&'||str==='||'||str==='=='||str==='!='||
-str==='+='||str==='-='||str==='*='||str==='/='||
-str==='++'||str==='--'||str==='<<'||str==='>>'||
-str==='&='||str==='|='||str==='^='||str==='%='||
-str==='<='||str==='>='||str==='=>'||str==='**'){
-this.index+=2;
-}else
-{
-
-str=this.source[this.index];
-if('<>=!+-*%&|^/'.indexOf(str)>=0){
-++this.index;
-}
-}
-}
-}}
-
-if(this.index===start){
-this.throwUnexpectedToken();
-}
-return{
-type:7,
-value:str,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-
-Scanner.prototype.scanHexLiteral=function(start){
-var num='';
-while(!this.eof()){
-if(!character_1.Character.isHexDigit(this.source.charCodeAt(this.index))){
-break;
-}
-num+=this.source[this.index++];
-}
-if(num.length===0){
-this.throwUnexpectedToken();
-}
-if(character_1.Character.isIdentifierStart(this.source.charCodeAt(this.index))){
-this.throwUnexpectedToken();
-}
-return{
-type:6,
-value:parseInt('0x'+num,16),
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-Scanner.prototype.scanBinaryLiteral=function(start){
-var num='';
-var ch;
-while(!this.eof()){
-ch=this.source[this.index];
-if(ch!=='0'&&ch!=='1'){
-break;
-}
-num+=this.source[this.index++];
-}
-if(num.length===0){
-
-this.throwUnexpectedToken();
-}
-if(!this.eof()){
-ch=this.source.charCodeAt(this.index);
-
-if(character_1.Character.isIdentifierStart(ch)||character_1.Character.isDecimalDigit(ch)){
-this.throwUnexpectedToken();
-}
-}
-return{
-type:6,
-value:parseInt(num,2),
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-Scanner.prototype.scanOctalLiteral=function(prefix,start){
-var num='';
-var octal=false;
-if(character_1.Character.isOctalDigit(prefix.charCodeAt(0))){
-octal=true;
-num='0'+this.source[this.index++];
-}else
-{
-++this.index;
-}
-while(!this.eof()){
-if(!character_1.Character.isOctalDigit(this.source.charCodeAt(this.index))){
-break;
-}
-num+=this.source[this.index++];
-}
-if(!octal&&num.length===0){
-
-this.throwUnexpectedToken();
-}
-if(character_1.Character.isIdentifierStart(this.source.charCodeAt(this.index))||character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index))){
-this.throwUnexpectedToken();
-}
-return{
-type:6,
-value:parseInt(num,8),
-octal:octal,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-Scanner.prototype.isImplicitOctalLiteral=function(){
-
-
-for(var i=this.index+1;i<this.length;++i){
-var ch=this.source[i];
-if(ch==='8'||ch==='9'){
-return false;
-}
-if(!character_1.Character.isOctalDigit(ch.charCodeAt(0))){
-return true;
-}
-}
-return true;
-};
-Scanner.prototype.scanNumericLiteral=function(){
-var start=this.index;
-var ch=this.source[start];
-assert_1.assert(character_1.Character.isDecimalDigit(ch.charCodeAt(0))||ch==='.','Numeric literal must start with a decimal digit or a decimal point');
-var num='';
-if(ch!=='.'){
-num=this.source[this.index++];
-ch=this.source[this.index];
-
-
-
-
-if(num==='0'){
-if(ch==='x'||ch==='X'){
-++this.index;
-return this.scanHexLiteral(start);
-}
-if(ch==='b'||ch==='B'){
-++this.index;
-return this.scanBinaryLiteral(start);
-}
-if(ch==='o'||ch==='O'){
-return this.scanOctalLiteral(ch,start);
-}
-if(ch&&character_1.Character.isOctalDigit(ch.charCodeAt(0))){
-if(this.isImplicitOctalLiteral()){
-return this.scanOctalLiteral(ch,start);
-}
-}
-}
-while(character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index))){
-num+=this.source[this.index++];
-}
-ch=this.source[this.index];
-}
-if(ch==='.'){
-num+=this.source[this.index++];
-while(character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index))){
-num+=this.source[this.index++];
-}
-ch=this.source[this.index];
-}
-if(ch==='e'||ch==='E'){
-num+=this.source[this.index++];
-ch=this.source[this.index];
-if(ch==='+'||ch==='-'){
-num+=this.source[this.index++];
-}
-if(character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index))){
-while(character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index))){
-num+=this.source[this.index++];
-}
-}else
-{
-this.throwUnexpectedToken();
-}
-}
-if(character_1.Character.isIdentifierStart(this.source.charCodeAt(this.index))){
-this.throwUnexpectedToken();
-}
-return{
-type:6,
-value:parseFloat(num),
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-
-Scanner.prototype.scanStringLiteral=function(){
-var start=this.index;
-var quote=this.source[start];
-assert_1.assert(quote==='\''||quote==='"','String literal must starts with a quote');
-++this.index;
-var octal=false;
-var str='';
-while(!this.eof()){
-var ch=this.source[this.index++];
-if(ch===quote){
-quote='';
-break;
-}else
-if(ch==='\\'){
-ch=this.source[this.index++];
-if(!ch||!character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-switch(ch){
-case'u':
-if(this.source[this.index]==='{'){
-++this.index;
-str+=this.scanUnicodeCodePointEscape();
-}else
-{
-var unescaped_1=this.scanHexEscape(ch);
-if(unescaped_1===null){
-this.throwUnexpectedToken();
-}
-str+=unescaped_1;
-}
-break;
-case'x':
-var unescaped=this.scanHexEscape(ch);
-if(unescaped===null){
-this.throwUnexpectedToken(messages_1.Messages.InvalidHexEscapeSequence);
-}
-str+=unescaped;
-break;
-case'n':
-str+='\n';
-break;
-case'r':
-str+='\r';
-break;
-case't':
-str+='\t';
-break;
-case'b':
-str+='\b';
-break;
-case'f':
-str+='\f';
-break;
-case'v':
-str+='\x0B';
-break;
-case'8':
-case'9':
-str+=ch;
-this.tolerateUnexpectedToken();
-break;
-default:
-if(ch&&character_1.Character.isOctalDigit(ch.charCodeAt(0))){
-var octToDec=this.octalToDecimal(ch);
-octal=octToDec.octal||octal;
-str+=String.fromCharCode(octToDec.code);
-}else
-{
-str+=ch;
-}
-break;}
-
-}else
-{
-++this.lineNumber;
-if(ch==='\r'&&this.source[this.index]==='\n'){
-++this.index;
-}
-this.lineStart=this.index;
-}
-}else
-if(character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-break;
-}else
-{
-str+=ch;
-}
-}
-if(quote!==''){
-this.index=start;
-this.throwUnexpectedToken();
-}
-return{
-type:8,
-value:str,
-octal:octal,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-
-Scanner.prototype.scanTemplate=function(){
-var cooked='';
-var terminated=false;
-var start=this.index;
-var head=this.source[start]==='`';
-var tail=false;
-var rawOffset=2;
-++this.index;
-while(!this.eof()){
-var ch=this.source[this.index++];
-if(ch==='`'){
-rawOffset=1;
-tail=true;
-terminated=true;
-break;
-}else
-if(ch==='$'){
-if(this.source[this.index]==='{'){
-this.curlyStack.push('${');
-++this.index;
-terminated=true;
-break;
-}
-cooked+=ch;
-}else
-if(ch==='\\'){
-ch=this.source[this.index++];
-if(!character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-switch(ch){
-case'n':
-cooked+='\n';
-break;
-case'r':
-cooked+='\r';
-break;
-case't':
-cooked+='\t';
-break;
-case'u':
-if(this.source[this.index]==='{'){
-++this.index;
-cooked+=this.scanUnicodeCodePointEscape();
-}else
-{
-var restore=this.index;
-var unescaped_2=this.scanHexEscape(ch);
-if(unescaped_2!==null){
-cooked+=unescaped_2;
-}else
-{
-this.index=restore;
-cooked+=ch;
-}
-}
-break;
-case'x':
-var unescaped=this.scanHexEscape(ch);
-if(unescaped===null){
-this.throwUnexpectedToken(messages_1.Messages.InvalidHexEscapeSequence);
-}
-cooked+=unescaped;
-break;
-case'b':
-cooked+='\b';
-break;
-case'f':
-cooked+='\f';
-break;
-case'v':
-cooked+='\v';
-break;
-default:
-if(ch==='0'){
-if(character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index))){
-
-this.throwUnexpectedToken(messages_1.Messages.TemplateOctalLiteral);
-}
-cooked+='\0';
-}else
-if(character_1.Character.isOctalDigit(ch.charCodeAt(0))){
-
-this.throwUnexpectedToken(messages_1.Messages.TemplateOctalLiteral);
-}else
-{
-cooked+=ch;
-}
-break;}
-
-}else
-{
-++this.lineNumber;
-if(ch==='\r'&&this.source[this.index]==='\n'){
-++this.index;
-}
-this.lineStart=this.index;
-}
-}else
-if(character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-++this.lineNumber;
-if(ch==='\r'&&this.source[this.index]==='\n'){
-++this.index;
-}
-this.lineStart=this.index;
-cooked+='\n';
-}else
-{
-cooked+=ch;
-}
-}
-if(!terminated){
-this.throwUnexpectedToken();
-}
-if(!head){
-this.curlyStack.pop();
-}
-return{
-type:10,
-value:this.source.slice(start+1,this.index-rawOffset),
-cooked:cooked,
-head:head,
-tail:tail,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-
-Scanner.prototype.testRegExp=function(pattern,flags){
-
-
-
-
-
-
-var astralSubstitute='\uFFFF';
-var tmp=pattern;
-var self=this;
-if(flags.indexOf('u')>=0){
-tmp=tmp.
-replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g,function($0,$1,$2){
-var codePoint=parseInt($1||$2,16);
-if(codePoint>0x10FFFF){
-self.throwUnexpectedToken(messages_1.Messages.InvalidRegExp);
-}
-if(codePoint<=0xFFFF){
-return String.fromCharCode(codePoint);
-}
-return astralSubstitute;
-}).
-replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,astralSubstitute);
-}
-
-try{
-RegExp(tmp);
-}
-catch(e){
-this.throwUnexpectedToken(messages_1.Messages.InvalidRegExp);
-}
-
-
-
-try{
-return new RegExp(pattern,flags);
-}
-catch(exception){
-
-return null;
-}
-};
-Scanner.prototype.scanRegExpBody=function(){
-var ch=this.source[this.index];
-assert_1.assert(ch==='/','Regular expression literal must start with a slash');
-var str=this.source[this.index++];
-var classMarker=false;
-var terminated=false;
-while(!this.eof()){
-ch=this.source[this.index++];
-str+=ch;
-if(ch==='\\'){
-ch=this.source[this.index++];
-
-if(character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-this.throwUnexpectedToken(messages_1.Messages.UnterminatedRegExp);
-}
-str+=ch;
-}else
-if(character_1.Character.isLineTerminator(ch.charCodeAt(0))){
-this.throwUnexpectedToken(messages_1.Messages.UnterminatedRegExp);
-}else
-if(classMarker){
-if(ch===']'){
-classMarker=false;
-}
-}else
-{
-if(ch==='/'){
-terminated=true;
-break;
-}else
-if(ch==='['){
-classMarker=true;
-}
-}
-}
-if(!terminated){
-this.throwUnexpectedToken(messages_1.Messages.UnterminatedRegExp);
-}
-
-return str.substr(1,str.length-2);
-};
-Scanner.prototype.scanRegExpFlags=function(){
-var str='';
-var flags='';
-while(!this.eof()){
-var ch=this.source[this.index];
-if(!character_1.Character.isIdentifierPart(ch.charCodeAt(0))){
-break;
-}
-++this.index;
-if(ch==='\\'&&!this.eof()){
-ch=this.source[this.index];
-if(ch==='u'){
-++this.index;
-var restore=this.index;
-var char=this.scanHexEscape('u');
-if(char!==null){
-flags+=char;
-for(str+='\\u';restore<this.index;++restore){
-str+=this.source[restore];
-}
-}else
-{
-this.index=restore;
-flags+='u';
-str+='\\u';
-}
-this.tolerateUnexpectedToken();
-}else
-{
-str+='\\';
-this.tolerateUnexpectedToken();
-}
-}else
-{
-flags+=ch;
-str+=ch;
-}
-}
-return flags;
-};
-Scanner.prototype.scanRegExp=function(){
-var start=this.index;
-var pattern=this.scanRegExpBody();
-var flags=this.scanRegExpFlags();
-var value=this.testRegExp(pattern,flags);
-return{
-type:9,
-value:'',
-pattern:pattern,
-flags:flags,
-regex:value,
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:start,
-end:this.index};
-
-};
-Scanner.prototype.lex=function(){
-if(this.eof()){
-return{
-type:2,
-value:'',
-lineNumber:this.lineNumber,
-lineStart:this.lineStart,
-start:this.index,
-end:this.index};
-
-}
-var cp=this.source.charCodeAt(this.index);
-if(character_1.Character.isIdentifierStart(cp)){
-return this.scanIdentifier();
-}
-
-if(cp===0x28||cp===0x29||cp===0x3B){
-return this.scanPunctuator();
-}
-
-if(cp===0x27||cp===0x22){
-return this.scanStringLiteral();
-}
-
-
-if(cp===0x2E){
-if(character_1.Character.isDecimalDigit(this.source.charCodeAt(this.index+1))){
-return this.scanNumericLiteral();
-}
-return this.scanPunctuator();
-}
-if(character_1.Character.isDecimalDigit(cp)){
-return this.scanNumericLiteral();
-}
-
-
-if(cp===0x60||cp===0x7D&&this.curlyStack[this.curlyStack.length-1]==='${'){
-return this.scanTemplate();
-}
-
-if(cp>=0xD800&&cp<0xDFFF){
-if(character_1.Character.isIdentifierStart(this.codePointAt(this.index))){
-return this.scanIdentifier();
-}
-}
-return this.scanPunctuator();
-};
-return Scanner;
-}();
-exports.Scanner=Scanner;
-
-
-},
-
-function(module,exports){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-exports.TokenName={};
-exports.TokenName[1]='Boolean';
-exports.TokenName[2]='<end>';
-exports.TokenName[3]='Identifier';
-exports.TokenName[4]='Keyword';
-exports.TokenName[5]='Null';
-exports.TokenName[6]='Numeric';
-exports.TokenName[7]='Punctuator';
-exports.TokenName[8]='String';
-exports.TokenName[9]='RegularExpression';
-exports.TokenName[10]='Template';
-
-
-},
-
-function(module,exports){
-
-"use strict";
-
-Object.defineProperty(exports,"__esModule",{value:true});
-exports.XHTMLEntities={
-quot:'\u0022',
-amp:'\u0026',
-apos:'\u0027',
-gt:'\u003E',
-nbsp:'\u00A0',
-iexcl:'\u00A1',
-cent:'\u00A2',
-pound:'\u00A3',
-curren:'\u00A4',
-yen:'\u00A5',
-brvbar:'\u00A6',
-sect:'\u00A7',
-uml:'\u00A8',
-copy:'\u00A9',
-ordf:'\u00AA',
-laquo:'\u00AB',
-not:'\u00AC',
-shy:'\u00AD',
-reg:'\u00AE',
-macr:'\u00AF',
-deg:'\u00B0',
-plusmn:'\u00B1',
-sup2:'\u00B2',
-sup3:'\u00B3',
-acute:'\u00B4',
-micro:'\u00B5',
-para:'\u00B6',
-middot:'\u00B7',
-cedil:'\u00B8',
-sup1:'\u00B9',
-ordm:'\u00BA',
-raquo:'\u00BB',
-frac14:'\u00BC',
-frac12:'\u00BD',
-frac34:'\u00BE',
-iquest:'\u00BF',
-Agrave:'\u00C0',
-Aacute:'\u00C1',
-Acirc:'\u00C2',
-Atilde:'\u00C3',
-Auml:'\u00C4',
-Aring:'\u00C5',
-AElig:'\u00C6',
-Ccedil:'\u00C7',
-Egrave:'\u00C8',
-Eacute:'\u00C9',
-Ecirc:'\u00CA',
-Euml:'\u00CB',
-Igrave:'\u00CC',
-Iacute:'\u00CD',
-Icirc:'\u00CE',
-Iuml:'\u00CF',
-ETH:'\u00D0',
-Ntilde:'\u00D1',
-Ograve:'\u00D2',
-Oacute:'\u00D3',
-Ocirc:'\u00D4',
-Otilde:'\u00D5',
-Ouml:'\u00D6',
-times:'\u00D7',
-Oslash:'\u00D8',
-Ugrave:'\u00D9',
-Uacute:'\u00DA',
-Ucirc:'\u00DB',
-Uuml:'\u00DC',
-Yacute:'\u00DD',
-THORN:'\u00DE',
-szlig:'\u00DF',
-agrave:'\u00E0',
-aacute:'\u00E1',
-acirc:'\u00E2',
-atilde:'\u00E3',
-auml:'\u00E4',
-aring:'\u00E5',
-aelig:'\u00E6',
-ccedil:'\u00E7',
-egrave:'\u00E8',
-eacute:'\u00E9',
-ecirc:'\u00EA',
-euml:'\u00EB',
-igrave:'\u00EC',
-iacute:'\u00ED',
-icirc:'\u00EE',
-iuml:'\u00EF',
-eth:'\u00F0',
-ntilde:'\u00F1',
-ograve:'\u00F2',
-oacute:'\u00F3',
-ocirc:'\u00F4',
-otilde:'\u00F5',
-ouml:'\u00F6',
-divide:'\u00F7',
-oslash:'\u00F8',
-ugrave:'\u00F9',
-uacute:'\u00FA',
-ucirc:'\u00FB',
-uuml:'\u00FC',
-yacute:'\u00FD',
-thorn:'\u00FE',
-yuml:'\u00FF',
-OElig:'\u0152',
-oelig:'\u0153',
-Scaron:'\u0160',
-scaron:'\u0161',
-Yuml:'\u0178',
-fnof:'\u0192',
-circ:'\u02C6',
-tilde:'\u02DC',
-Alpha:'\u0391',
-Beta:'\u0392',
-Gamma:'\u0393',
-Delta:'\u0394',
-Epsilon:'\u0395',
-Zeta:'\u0396',
-Eta:'\u0397',
-Theta:'\u0398',
-Iota:'\u0399',
-Kappa:'\u039A',
-Lambda:'\u039B',
-Mu:'\u039C',
-Nu:'\u039D',
-Xi:'\u039E',
-Omicron:'\u039F',
-Pi:'\u03A0',
-Rho:'\u03A1',
-Sigma:'\u03A3',
-Tau:'\u03A4',
-Upsilon:'\u03A5',
-Phi:'\u03A6',
-Chi:'\u03A7',
-Psi:'\u03A8',
-Omega:'\u03A9',
-alpha:'\u03B1',
-beta:'\u03B2',
-gamma:'\u03B3',
-delta:'\u03B4',
-epsilon:'\u03B5',
-zeta:'\u03B6',
-eta:'\u03B7',
-theta:'\u03B8',
-iota:'\u03B9',
-kappa:'\u03BA',
-lambda:'\u03BB',
-mu:'\u03BC',
-nu:'\u03BD',
-xi:'\u03BE',
-omicron:'\u03BF',
-pi:'\u03C0',
-rho:'\u03C1',
-sigmaf:'\u03C2',
-sigma:'\u03C3',
-tau:'\u03C4',
-upsilon:'\u03C5',
-phi:'\u03C6',
-chi:'\u03C7',
-psi:'\u03C8',
-omega:'\u03C9',
-thetasym:'\u03D1',
-upsih:'\u03D2',
-piv:'\u03D6',
-ensp:'\u2002',
-emsp:'\u2003',
-thinsp:'\u2009',
-zwnj:'\u200C',
-zwj:'\u200D',
-lrm:'\u200E',
-rlm:'\u200F',
-ndash:'\u2013',
-mdash:'\u2014',
-lsquo:'\u2018',
-rsquo:'\u2019',
-sbquo:'\u201A',
-ldquo:'\u201C',
-rdquo:'\u201D',
-bdquo:'\u201E',
-dagger:'\u2020',
-Dagger:'\u2021',
-bull:'\u2022',
-hellip:'\u2026',
-permil:'\u2030',
-prime:'\u2032',
-Prime:'\u2033',
-lsaquo:'\u2039',
-rsaquo:'\u203A',
-oline:'\u203E',
-frasl:'\u2044',
-euro:'\u20AC',
-image:'\u2111',
-weierp:'\u2118',
-real:'\u211C',
-trade:'\u2122',
-alefsym:'\u2135',
-larr:'\u2190',
-uarr:'\u2191',
-rarr:'\u2192',
-darr:'\u2193',
-harr:'\u2194',
-crarr:'\u21B5',
-lArr:'\u21D0',
-uArr:'\u21D1',
-rArr:'\u21D2',
-dArr:'\u21D3',
-hArr:'\u21D4',
-forall:'\u2200',
-part:'\u2202',
-exist:'\u2203',
-empty:'\u2205',
-nabla:'\u2207',
-isin:'\u2208',
-notin:'\u2209',
-ni:'\u220B',
-prod:'\u220F',
-sum:'\u2211',
-minus:'\u2212',
-lowast:'\u2217',
-radic:'\u221A',
-prop:'\u221D',
-infin:'\u221E',
-ang:'\u2220',
-and:'\u2227',
-or:'\u2228',
-cap:'\u2229',
-cup:'\u222A',
-int:'\u222B',
-there4:'\u2234',
-sim:'\u223C',
-cong:'\u2245',
-asymp:'\u2248',
-ne:'\u2260',
-equiv:'\u2261',
-le:'\u2264',
-ge:'\u2265',
-sub:'\u2282',
-sup:'\u2283',
-nsub:'\u2284',
-sube:'\u2286',
-supe:'\u2287',
-oplus:'\u2295',
-otimes:'\u2297',
-perp:'\u22A5',
-sdot:'\u22C5',
-lceil:'\u2308',
-rceil:'\u2309',
-lfloor:'\u230A',
-rfloor:'\u230B',
-loz:'\u25CA',
-spades:'\u2660',
-clubs:'\u2663',
-hearts:'\u2665',
-diams:'\u2666',
-lang:'\u27E8',
-rang:'\u27E9'};
-
-
-
-},
-
-function(module,exports,__webpack_require__){
-
-"use strict";
-Object.defineProperty(exports,"__esModule",{value:true});
-var error_handler_1=__webpack_require__(10);
-var scanner_1=__webpack_require__(12);
-var token_1=__webpack_require__(13);
-var Reader=function(){
-function Reader(){
-this.values=[];
-this.curly=this.paren=-1;
-}
-
-Reader.prototype.beforeFunctionExpression=function(t){
-return['(','{','[','in','typeof','instanceof','new',
-'return','case','delete','throw','void',
-
-'=','+=','-=','*=','**=','/=','%=','<<=','>>=','>>>=',
-'&=','|=','^=',',',
-
-'+','-','*','**','/','%','++','--','<<','>>','>>>','&',
-'|','^','!','~','&&','||','?',':','===','==','>=',
-'<=','<','>','!=','!=='].indexOf(t)>=0;
-};
-
-
-Reader.prototype.isRegexStart=function(){
-var previous=this.values[this.values.length-1];
-var regex=previous!==null;
-switch(previous){
-case'this':
-case']':
-regex=false;
-break;
-case')':
-var keyword=this.values[this.paren-1];
-regex=keyword==='if'||keyword==='while'||keyword==='for'||keyword==='with';
-break;
-case'}':
-
-
-regex=false;
-if(this.values[this.curly-3]==='function'){
-
-var check=this.values[this.curly-4];
-regex=check?!this.beforeFunctionExpression(check):false;
-}else
-if(this.values[this.curly-4]==='function'){
-
-var check=this.values[this.curly-5];
-regex=check?!this.beforeFunctionExpression(check):true;
-}
-break;
-default:
-break;}
-
-return regex;
-};
-Reader.prototype.push=function(token){
-if(token.type===7||token.type===4){
-if(token.value==='{'){
-this.curly=this.values.length;
-}else
-if(token.value==='('){
-this.paren=this.values.length;
-}
-this.values.push(token.value);
-}else
-{
-this.values.push(null);
-}
-};
-return Reader;
-}();
-var Tokenizer=function(){
-function Tokenizer(code,config){
-this.errorHandler=new error_handler_1.ErrorHandler();
-this.errorHandler.tolerant=config?typeof config.tolerant==='boolean'&&config.tolerant:false;
-this.scanner=new scanner_1.Scanner(code,this.errorHandler);
-this.scanner.trackComment=config?typeof config.comment==='boolean'&&config.comment:false;
-this.trackRange=config?typeof config.range==='boolean'&&config.range:false;
-this.trackLoc=config?typeof config.loc==='boolean'&&config.loc:false;
-this.buffer=[];
-this.reader=new Reader();
-}
-Tokenizer.prototype.errors=function(){
-return this.errorHandler.errors;
-};
-Tokenizer.prototype.getNextToken=function(){
-if(this.buffer.length===0){
-var comments=this.scanner.scanComments();
-if(this.scanner.trackComment){
-for(var i=0;i<comments.length;++i){
-var e=comments[i];
-var value=this.scanner.source.slice(e.slice[0],e.slice[1]);
-var comment={
-type:e.multiLine?'BlockComment':'LineComment',
-value:value};
-
-if(this.trackRange){
-comment.range=e.range;
-}
-if(this.trackLoc){
-comment.loc=e.loc;
-}
-this.buffer.push(comment);
-}
-}
-if(!this.scanner.eof()){
-var loc=void 0;
-if(this.trackLoc){
-loc={
-start:{
-line:this.scanner.lineNumber,
-column:this.scanner.index-this.scanner.lineStart},
-
-end:{}};
-
-}
-var startRegex=this.scanner.source[this.scanner.index]==='/'&&this.reader.isRegexStart();
-var token=startRegex?this.scanner.scanRegExp():this.scanner.lex();
-this.reader.push(token);
-var entry={
-type:token_1.TokenName[token.type],
-value:this.scanner.source.slice(token.start,token.end)};
-
-if(this.trackRange){
-entry.range=[token.start,token.end];
-}
-if(this.trackLoc){
-loc.end={
-line:this.scanner.lineNumber,
-column:this.scanner.index-this.scanner.lineStart};
-
-entry.loc=loc;
-}
-if(token.type===9){
-var pattern=token.pattern;
-var flags=token.flags;
-entry.regex={pattern:pattern,flags:flags};
-}
-this.buffer.push(entry);
-}
-}
-return this.buffer.shift();
-};
-return Tokenizer;
-}();
-exports.Tokenizer=Tokenizer;
-
-
-}]);
-
-});
-;
-},{}],163:[function(require,module,exports){
-(function(Buffer){
-var querystring=require('querystring');
-var trim=require('./trim');
-
-
-
-
-
-
-function Link(value){
-
-if(!(this instanceof Link)){
-return new Link(value);
-}
-
-
-this.refs=[];
-
-}
-
-
-
-
-
-Link.pattern=/(?:\<([^\>]+)\>)((\s*;\s*([a-z\*]+)=(("[^"]+")|('[^']+')|([^\,\;]+)))*)(\s*,\s*|$)/gi;
-
-
-
-
-
-Link.attrPattern=/([a-z\*]+)=(?:(?:"([^"]+)")|(?:'([^']+)')|([^\,\;]+))/gi;
-
-
-
-
-
-
-
-Link.isCompatibleEncoding=function(value){
-return /^utf-?8|ascii|utf-?16-?le|ucs-?2|base-?64|latin-?1$/i.test(value);
-};
-
-
-
-
-
-
-
-Link.formatExtendedAttribute=function(attr,data){
-
-var encoding=(data.encoding||'utf-8').toUpperCase();
-var language=data.language||'en';
-
-var encodedValue='';
-
-if(Buffer.isBuffer(data.value)&&Link.isCompatibleEncoding(encoding)){
-encodedValue=data.value.toString(encoding);
-}else if(Buffer.isBuffer(data.value)){
-encodedValue=data.value.toString('hex').
-replace(/[0-9a-f]{2}/gi,'%$1');
-}else{
-encodedValue=querystring.escape(data.value);
-}
-
-return attr+'='+encoding+'\''+
-language+'\''+encodedValue;
-
-};
-
-
-
-
-
-
-
-Link.formatAttribute=function(attr,value){
-
-
-if(/\*$/.test(attr)||typeof value!=='string')
-return Link.formatExtendedAttribute(attr,value);
-
-
-
-var needsQuotes=/[^a-z]/i.test(value);
-
-if(needsQuotes){
-
-value=querystring.escape(value).
-replace(/%20/g,' ').
-replace(/%2C/g,',').
-replace(/%3B/g,';');
-
-value='"'+value+'"';
-}
-
-return attr+'='+value;
-
-};
-
-
-
-
-
-
-
-Link.parseExtendedValue=function(value){
-var parts=/([^']+)?(?:'([^']+)')?(.+)/.exec(value);
-return{
-language:parts[2].toLowerCase(),
-encoding:Link.isCompatibleEncoding(parts[1])?
-null:parts[1].toLowerCase(),
-value:Link.isCompatibleEncoding(parts[1])?
-querystring.unescape(parts[3]):parts[3]};
-
-};
-
-
-
-
-
-
-
-Link.setAttr=function(link,attr,value){
-
-
-
-if(attr==='rel'&&link[attr]!=null)
-return link;
-
-if(Array.isArray(link[attr])){
-link[attr].push(value);
-}else if(link[attr]!=null){
-link[attr]=[link[attr],value];
-}else{
-link[attr]=value;
-}
-
-return link;
-
-};
-
-
-
-
-Link.parseParams=function(link,uri){
-
-var kvs={};
-var params=/(.+)\?(.+)/gi.exec(uri);
-
-if(!params){
-return link;
-}
-
-params=params[2].split('&');
-
-for(var i=0;i<params.length;i++){
-var param=params[i].split('=');
-kvs[param[0]]=param[1];
-}
-
-Link.setAttr(link,'params',kvs);
-
-return link;
-
-};
-
-
-
-
-
-
-
-
-Link.parseAttrs=function(link,parts){
-
-var match=null;
-var attr='';
-var value='';
-var attrs='';
-
-var uriAttrs=/<(.*)>;\s*(.*)/gi.exec(parts);
-if(uriAttrs){
-attrs=uriAttrs[2];
-link=Link.parseParams(link,uriAttrs[1]);
-}
-
-while(match=Link.attrPattern.exec(attrs)){
-attr=match[1].toLowerCase();
-value=match[4]||match[3]||match[2];
-if(/\*$/.test(attr)){
-Link.setAttr(link,attr,Link.parseExtendedValue(value));
-}else if(/%/.test(value)){
-Link.setAttr(link,attr,querystring.unescape(value));
-}else{
-Link.setAttr(link,attr,value);
-}
-}
-
-return link;
-
-};
-
-Link.parse=function(value){
-return new Link().parse(value);
-};
-
-
-
-
-
-Link.prototype={
-
-constructor:Link,
-
-
-
-
-
-
-rel:function(value){
-
-var links=[];
-
-for(var i=0;i<this.refs.length;i++){
-if(this.refs[i].rel===value){
-links.push(this.refs[i]);
-}
-}
-
-return links;
-
-},
-
-
-
-
-
-
-
-get:function(attr,value){
-
-attr=attr.toLowerCase();
-
-var links=[];
-
-for(var i=0;i<this.refs.length;i++){
-if(this.refs[i][attr]===value){
-links.push(this.refs[i]);
-}
-}
-
-return links;
-
-},
-
-set:function(link){
-this.refs.push(link);
-return this;
-},
-
-has:function(attr,value){
-return this.get(attr,value)!=null;
-},
-
-parse:function(value){
-
-
-value=trim(value).
-replace(/\r?\n[\x20\x09]+/g,'');
-
-var match=null;
-
-while(match=Link.pattern.exec(value)){
-var link=Link.parseAttrs({uri:match[1]},match[0]);
-this.refs.push(link);
-}
-
-return this;
-
-},
-
-toString:function(){
-
-var refs=[];
-var link='';
-var ref=null;
-
-for(var i=0;i<this.refs.length;i++){
-ref=this.refs[i];
-link=Object.keys(this.refs[i]).reduce(function(link,attr){
-if(attr==='uri')return link;
-return link+'; '+Link.formatAttribute(attr,ref[attr]);
-},'<'+ref.uri+'>');
-refs.push(link);
-}
-
-return refs.join(', ');
-
-}};
-
-
-
-
-module.exports=Link;
-
-}).call(this,{"isBuffer":require("../../../lighthouse-extension/node_modules/is-buffer/index.js")});
-},{"../../../lighthouse-extension/node_modules/is-buffer/index.js":114,"./trim":164,"querystring":129}],164:[function(require,module,exports){
-module.exports=function trim(value){
-return value.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,'');
-};
-
-},{}],165:[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-var ImageSSIM;
-(function(ImageSSIM){
-'use strict';
-
-
-
-(function(Channels){
-Channels[Channels["Grey"]=1]="Grey";
-Channels[Channels["GreyAlpha"]=2]="GreyAlpha";
-Channels[Channels["RGB"]=3]="RGB";
-Channels[Channels["RGBAlpha"]=4]="RGBAlpha";
-})(ImageSSIM.Channels||(ImageSSIM.Channels={}));
-var Channels=ImageSSIM.Channels;
-
-
-
-
-function compare(image1,image2,windowSize,K1,K2,luminance,bitsPerComponent){
-if(windowSize===void 0){windowSize=8;}
-if(K1===void 0){K1=0.01;}
-if(K2===void 0){K2=0.03;}
-if(luminance===void 0){luminance=true;}
-if(bitsPerComponent===void 0){bitsPerComponent=8;}
-if(image1.width!==image2.width||image1.height!==image2.height){
-throw new Error('Images have different sizes!');
-}
-
-var L=(1<<bitsPerComponent)-1;
-
-var c1=Math.pow(K1*L,2),c2=Math.pow(K2*L,2),numWindows=0,mssim=0.0;
-var mcs=0.0;
-function iteration(lumaValues1,lumaValues2,averageLumaValue1,averageLumaValue2){
-
-var sigxy,sigsqx,sigsqy;
-sigxy=sigsqx=sigsqy=0.0;
-for(var i=0;i<lumaValues1.length;i++){
-sigsqx+=Math.pow(lumaValues1[i]-averageLumaValue1,2);
-sigsqy+=Math.pow(lumaValues2[i]-averageLumaValue2,2);
-sigxy+=(lumaValues1[i]-averageLumaValue1)*(lumaValues2[i]-averageLumaValue2);
-}
-var numPixelsInWin=lumaValues1.length-1;
-sigsqx/=numPixelsInWin;
-sigsqy/=numPixelsInWin;
-sigxy/=numPixelsInWin;
-
-var numerator=(2*averageLumaValue1*averageLumaValue2+c1)*(2*sigxy+c2);
-var denominator=(Math.pow(averageLumaValue1,2)+Math.pow(averageLumaValue2,2)+c1)*(sigsqx+sigsqy+c2);
-mssim+=numerator/denominator;
-mcs+=(2*sigxy+c2)/(sigsqx+sigsqy+c2);
-numWindows++;
-}
-
-Internals._iterate(image1,image2,windowSize,luminance,iteration);
-return{ssim:mssim/numWindows,mcs:mcs/numWindows};
-}
-ImageSSIM.compare=compare;
-
-
-
-var Internals;
-(function(Internals){
-function _iterate(image1,image2,windowSize,luminance,callback){
-var width=image1.width,height=image1.height;
-for(var y=0;y<height;y+=windowSize){
-for(var x=0;x<width;x+=windowSize){
-
-var windowWidth=Math.min(windowSize,width-x),windowHeight=Math.min(windowSize,height-y);
-var lumaValues1=_lumaValuesForWindow(image1,x,y,windowWidth,windowHeight,luminance),lumaValues2=_lumaValuesForWindow(image2,x,y,windowWidth,windowHeight,luminance),averageLuma1=_averageLuma(lumaValues1),averageLuma2=_averageLuma(lumaValues2);
-callback(lumaValues1,lumaValues2,averageLuma1,averageLuma2);
-}
-}
-}
-Internals._iterate=_iterate;
-function _lumaValuesForWindow(image,x,y,width,height,luminance){
-var array=image.data,lumaValues=new Float32Array(new ArrayBuffer(width*height*4)),counter=0;
-var maxj=y+height;
-for(var j=y;j<maxj;j++){
-var offset=j*image.width;
-var i=(offset+x)*image.channels;
-var maxi=(offset+x+width)*image.channels;
-switch(image.channels){
-case 1:
-while(i<maxi){
-
-lumaValues[counter++]=array[i++];
-}
-break;
-case 2:
-while(i<maxi){
-lumaValues[counter++]=array[i++]*(array[i++]/255);
-}
-break;
-case 3:
-if(luminance){
-while(i<maxi){
-lumaValues[counter++]=array[i++]*0.212655+array[i++]*0.715158+array[i++]*0.072187;
-}
-}else
-{
-while(i<maxi){
-lumaValues[counter++]=array[i++]+array[i++]+array[i++];
-}
-}
-break;
-case 4:
-if(luminance){
-while(i<maxi){
-lumaValues[counter++]=(array[i++]*0.212655+array[i++]*0.715158+array[i++]*0.072187)*(array[i++]/255);
-}
-}else
-{
-while(i<maxi){
-lumaValues[counter++]=(array[i++]+array[i++]+array[i++])*(array[i++]/255);
-}
-}
-break;}
-
-}
-return lumaValues;
-}
-function _averageLuma(lumaValues){
-var sumLuma=0.0;
-for(var i=0;i<lumaValues.length;i++){
-sumLuma+=lumaValues[i];
-}
-return sumLuma/lumaValues.length;
-}
-})(Internals||(Internals={}));
-})(ImageSSIM||(ImageSSIM={}));
-module.exports=ImageSSIM;
-
-},{}],166:[function(require,module,exports){
-'use strict';
-
-exports=module.exports=require('./lib/parser')['default'];
-exports['default']=exports;
-
-},{"./lib/parser":167}],167:[function(require,module,exports){
-"use strict";
-
-exports["default"]=function(){
-"use strict";
-
-
-
-
-
-
-
-function peg$subclass(child,parent){
-function ctor(){this.constructor=child;}
-ctor.prototype=parent.prototype;
-child.prototype=new ctor();
-}
-
-function peg$SyntaxError(message,expected,found,location){
-this.message=message;
-this.expected=expected;
-this.found=found;
-this.location=location;
-this.name="SyntaxError";
-
-if(typeof Error.captureStackTrace==="function"){
-Error.captureStackTrace(this,peg$SyntaxError);
-}
-}
-
-peg$subclass(peg$SyntaxError,Error);
-
-function peg$parse(input){
-var options=arguments.length>1?arguments[1]:{},
-parser=this,
-
-peg$FAILED={},
-
-peg$startRuleFunctions={start:peg$parsestart},
-peg$startRuleFunction=peg$parsestart,
-
-peg$c0=function(elements){
-return{
-type:'messageFormatPattern',
-elements:elements,
-location:location()};
-
-},
-peg$c1=function(text){
-var string='',
-i,j,outerLen,inner,innerLen;
-
-for(i=0,outerLen=text.length;i<outerLen;i+=1){
-inner=text[i];
-
-for(j=0,innerLen=inner.length;j<innerLen;j+=1){
-string+=inner[j];
-}
-}
-
-return string;
-},
-peg$c2=function(messageText){
-return{
-type:'messageTextElement',
-value:messageText,
-location:location()};
-
-},
-peg$c3=/^[^ \t\n\r,.+={}#]/,
-peg$c4={type:"class",value:"[^ \\t\\n\\r,.+={}#]",description:"[^ \\t\\n\\r,.+={}#]"},
-peg$c5="{",
-peg$c6={type:"literal",value:"{",description:"\"{\""},
-peg$c7=",",
-peg$c8={type:"literal",value:",",description:"\",\""},
-peg$c9="}",
-peg$c10={type:"literal",value:"}",description:"\"}\""},
-peg$c11=function(id,format){
-return{
-type:'argumentElement',
-id:id,
-format:format&&format[2],
-location:location()};
-
-},
-peg$c12="number",
-peg$c13={type:"literal",value:"number",description:"\"number\""},
-peg$c14="date",
-peg$c15={type:"literal",value:"date",description:"\"date\""},
-peg$c16="time",
-peg$c17={type:"literal",value:"time",description:"\"time\""},
-peg$c18=function(type,style){
-return{
-type:type+'Format',
-style:style&&style[2],
-location:location()};
-
-},
-peg$c19="plural",
-peg$c20={type:"literal",value:"plural",description:"\"plural\""},
-peg$c21=function(pluralStyle){
-return{
-type:pluralStyle.type,
-ordinal:false,
-offset:pluralStyle.offset||0,
-options:pluralStyle.options,
-location:location()};
-
-},
-peg$c22="selectordinal",
-peg$c23={type:"literal",value:"selectordinal",description:"\"selectordinal\""},
-peg$c24=function(pluralStyle){
-return{
-type:pluralStyle.type,
-ordinal:true,
-offset:pluralStyle.offset||0,
-options:pluralStyle.options,
-location:location()};
-
-},
-peg$c25="select",
-peg$c26={type:"literal",value:"select",description:"\"select\""},
-peg$c27=function(options){
-return{
-type:'selectFormat',
-options:options,
-location:location()};
-
-},
-peg$c28="=",
-peg$c29={type:"literal",value:"=",description:"\"=\""},
-peg$c30=function(selector,pattern){
-return{
-type:'optionalFormatPattern',
-selector:selector,
-value:pattern,
-location:location()};
-
-},
-peg$c31="offset:",
-peg$c32={type:"literal",value:"offset:",description:"\"offset:\""},
-peg$c33=function(number){
-return number;
-},
-peg$c34=function(offset,options){
-return{
-type:'pluralFormat',
-offset:offset,
-options:options,
-location:location()};
-
-},
-peg$c35={type:"other",description:"whitespace"},
-peg$c36=/^[ \t\n\r]/,
-peg$c37={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},
-peg$c38={type:"other",description:"optionalWhitespace"},
-peg$c39=/^[0-9]/,
-peg$c40={type:"class",value:"[0-9]",description:"[0-9]"},
-peg$c41=/^[0-9a-f]/i,
-peg$c42={type:"class",value:"[0-9a-f]i",description:"[0-9a-f]i"},
-peg$c43="0",
-peg$c44={type:"literal",value:"0",description:"\"0\""},
-peg$c45=/^[1-9]/,
-peg$c46={type:"class",value:"[1-9]",description:"[1-9]"},
-peg$c47=function(digits){
-return parseInt(digits,10);
-},
-peg$c48=/^[^{}\\\0-\x1F \t\n\r]/,
-peg$c49={type:"class",value:"[^{}\\\\\\0-\\x1F\\x7f \\t\\n\\r]",description:"[^{}\\\\\\0-\\x1F\\x7f \\t\\n\\r]"},
-peg$c50="\\\\",
-peg$c51={type:"literal",value:"\\\\",description:"\"\\\\\\\\\""},
-peg$c52=function(){return'\\';},
-peg$c53="\\#",
-peg$c54={type:"literal",value:"\\#",description:"\"\\\\#\""},
-peg$c55=function(){return'\\#';},
-peg$c56="\\{",
-peg$c57={type:"literal",value:"\\{",description:"\"\\\\{\""},
-peg$c58=function(){return'\u007B';},
-peg$c59="\\}",
-peg$c60={type:"literal",value:"\\}",description:"\"\\\\}\""},
-peg$c61=function(){return'\u007D';},
-peg$c62="\\u",
-peg$c63={type:"literal",value:"\\u",description:"\"\\\\u\""},
-peg$c64=function(digits){
-return String.fromCharCode(parseInt(digits,16));
-},
-peg$c65=function(chars){return chars.join('');},
-
-peg$currPos=0,
-peg$savedPos=0,
-peg$posDetailsCache=[{line:1,column:1,seenCR:false}],
-peg$maxFailPos=0,
-peg$maxFailExpected=[],
-peg$silentFails=0,
-
-peg$result;
-
-if("startRule"in options){
-if(!(options.startRule in peg$startRuleFunctions)){
-throw new Error("Can't start parsing from rule \""+options.startRule+"\".");
-}
-
-peg$startRuleFunction=peg$startRuleFunctions[options.startRule];
-}
-
-function text(){
-return input.substring(peg$savedPos,peg$currPos);
-}
-
-function location(){
-return peg$computeLocation(peg$savedPos,peg$currPos);
-}
-
-function expected(description){
-throw peg$buildException(
-null,
-[{type:"other",description:description}],
-input.substring(peg$savedPos,peg$currPos),
-peg$computeLocation(peg$savedPos,peg$currPos));
-
-}
-
-function error(message){
-throw peg$buildException(
-message,
-null,
-input.substring(peg$savedPos,peg$currPos),
-peg$computeLocation(peg$savedPos,peg$currPos));
-
-}
-
-function peg$computePosDetails(pos){
-var details=peg$posDetailsCache[pos],
-p,ch;
-
-if(details){
-return details;
-}else{
-p=pos-1;
-while(!peg$posDetailsCache[p]){
-p--;
-}
-
-details=peg$posDetailsCache[p];
-details={
-line:details.line,
-column:details.column,
-seenCR:details.seenCR};
-
-
-while(p<pos){
-ch=input.charAt(p);
-if(ch==="\n"){
-if(!details.seenCR){details.line++;}
-details.column=1;
-details.seenCR=false;
-}else if(ch==="\r"||ch==="\u2028"||ch==="\u2029"){
-details.line++;
-details.column=1;
-details.seenCR=true;
-}else{
-details.column++;
-details.seenCR=false;
-}
-
-p++;
-}
-
-peg$posDetailsCache[pos]=details;
-return details;
-}
-}
-
-function peg$computeLocation(startPos,endPos){
-var startPosDetails=peg$computePosDetails(startPos),
-endPosDetails=peg$computePosDetails(endPos);
-
-return{
-start:{
-offset:startPos,
-line:startPosDetails.line,
-column:startPosDetails.column},
-
-end:{
-offset:endPos,
-line:endPosDetails.line,
-column:endPosDetails.column}};
-
-
-}
-
-function peg$fail(expected){
-if(peg$currPos<peg$maxFailPos){return;}
-
-if(peg$currPos>peg$maxFailPos){
-peg$maxFailPos=peg$currPos;
-peg$maxFailExpected=[];
-}
-
-peg$maxFailExpected.push(expected);
-}
-
-function peg$buildException(message,expected,found,location){
-function cleanupExpected(expected){
-var i=1;
-
-expected.sort(function(a,b){
-if(a.description<b.description){
-return-1;
-}else if(a.description>b.description){
-return 1;
-}else{
-return 0;
-}
-});
-
-while(i<expected.length){
-if(expected[i-1]===expected[i]){
-expected.splice(i,1);
-}else{
-i++;
-}
-}
-}
-
-function buildMessage(expected,found){
-function stringEscape(s){
-function hex(ch){return ch.charCodeAt(0).toString(16).toUpperCase();}
-
-return s.
-replace(/\\/g,'\\\\').
-replace(/"/g,'\\"').
-replace(/\x08/g,'\\b').
-replace(/\t/g,'\\t').
-replace(/\n/g,'\\n').
-replace(/\f/g,'\\f').
-replace(/\r/g,'\\r').
-replace(/[\x00-\x07\x0B\x0E\x0F]/g,function(ch){return'\\x0'+hex(ch);}).
-replace(/[\x10-\x1F\x80-\xFF]/g,function(ch){return'\\x'+hex(ch);}).
-replace(/[\u0100-\u0FFF]/g,function(ch){return'\\u0'+hex(ch);}).
-replace(/[\u1000-\uFFFF]/g,function(ch){return'\\u'+hex(ch);});
-}
-
-var expectedDescs=new Array(expected.length),
-expectedDesc,foundDesc,i;
-
-for(i=0;i<expected.length;i++){
-expectedDescs[i]=expected[i].description;
-}
-
-expectedDesc=expected.length>1?
-expectedDescs.slice(0,-1).join(", ")+
-" or "+
-expectedDescs[expected.length-1]:
-expectedDescs[0];
-
-foundDesc=found?"\""+stringEscape(found)+"\"":"end of input";
-
-return"Expected "+expectedDesc+" but "+foundDesc+" found.";
-}
-
-if(expected!==null){
-cleanupExpected(expected);
-}
-
-return new peg$SyntaxError(
-message!==null?message:buildMessage(expected,found),
-expected,
-found,
-location);
-
-}
-
-function peg$parsestart(){
-var s0;
-
-s0=peg$parsemessageFormatPattern();
-
-return s0;
-}
-
-function peg$parsemessageFormatPattern(){
-var s0,s1,s2;
-
-s0=peg$currPos;
-s1=[];
-s2=peg$parsemessageFormatElement();
-while(s2!==peg$FAILED){
-s1.push(s2);
-s2=peg$parsemessageFormatElement();
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c0(s1);
-}
-s0=s1;
-
-return s0;
-}
-
-function peg$parsemessageFormatElement(){
-var s0;
-
-s0=peg$parsemessageTextElement();
-if(s0===peg$FAILED){
-s0=peg$parseargumentElement();
-}
-
-return s0;
-}
-
-function peg$parsemessageText(){
-var s0,s1,s2,s3,s4,s5;
-
-s0=peg$currPos;
-s1=[];
-s2=peg$currPos;
-s3=peg$parse_();
-if(s3!==peg$FAILED){
-s4=peg$parsechars();
-if(s4!==peg$FAILED){
-s5=peg$parse_();
-if(s5!==peg$FAILED){
-s3=[s3,s4,s5];
-s2=s3;
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-if(s2!==peg$FAILED){
-while(s2!==peg$FAILED){
-s1.push(s2);
-s2=peg$currPos;
-s3=peg$parse_();
-if(s3!==peg$FAILED){
-s4=peg$parsechars();
-if(s4!==peg$FAILED){
-s5=peg$parse_();
-if(s5!==peg$FAILED){
-s3=[s3,s4,s5];
-s2=s3;
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-}
-}else{
-s1=peg$FAILED;
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c1(s1);
-}
-s0=s1;
-if(s0===peg$FAILED){
-s0=peg$currPos;
-s1=peg$parsews();
-if(s1!==peg$FAILED){
-s0=input.substring(s0,peg$currPos);
-}else{
-s0=s1;
-}
-}
-
-return s0;
-}
-
-function peg$parsemessageTextElement(){
-var s0,s1;
-
-s0=peg$currPos;
-s1=peg$parsemessageText();
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c2(s1);
-}
-s0=s1;
-
-return s0;
-}
-
-function peg$parseargument(){
-var s0,s1,s2;
-
-s0=peg$parsenumber();
-if(s0===peg$FAILED){
-s0=peg$currPos;
-s1=[];
-if(peg$c3.test(input.charAt(peg$currPos))){
-s2=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s2=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c4);}
-}
-if(s2!==peg$FAILED){
-while(s2!==peg$FAILED){
-s1.push(s2);
-if(peg$c3.test(input.charAt(peg$currPos))){
-s2=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s2=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c4);}
-}
-}
-}else{
-s1=peg$FAILED;
-}
-if(s1!==peg$FAILED){
-s0=input.substring(s0,peg$currPos);
-}else{
-s0=s1;
-}
-}
-
-return s0;
-}
-
-function peg$parseargumentElement(){
-var s0,s1,s2,s3,s4,s5,s6,s7,s8;
-
-s0=peg$currPos;
-if(input.charCodeAt(peg$currPos)===123){
-s1=peg$c5;
-peg$currPos++;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c6);}
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-s3=peg$parseargument();
-if(s3!==peg$FAILED){
-s4=peg$parse_();
-if(s4!==peg$FAILED){
-s5=peg$currPos;
-if(input.charCodeAt(peg$currPos)===44){
-s6=peg$c7;
-peg$currPos++;
-}else{
-s6=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c8);}
-}
-if(s6!==peg$FAILED){
-s7=peg$parse_();
-if(s7!==peg$FAILED){
-s8=peg$parseelementFormat();
-if(s8!==peg$FAILED){
-s6=[s6,s7,s8];
-s5=s6;
-}else{
-peg$currPos=s5;
-s5=peg$FAILED;
-}
-}else{
-peg$currPos=s5;
-s5=peg$FAILED;
-}
-}else{
-peg$currPos=s5;
-s5=peg$FAILED;
-}
-if(s5===peg$FAILED){
-s5=null;
-}
-if(s5!==peg$FAILED){
-s6=peg$parse_();
-if(s6!==peg$FAILED){
-if(input.charCodeAt(peg$currPos)===125){
-s7=peg$c9;
-peg$currPos++;
-}else{
-s7=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c10);}
-}
-if(s7!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c11(s3,s5);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parseelementFormat(){
-var s0;
-
-s0=peg$parsesimpleFormat();
-if(s0===peg$FAILED){
-s0=peg$parsepluralFormat();
-if(s0===peg$FAILED){
-s0=peg$parseselectOrdinalFormat();
-if(s0===peg$FAILED){
-s0=peg$parseselectFormat();
-}
-}
-}
-
-return s0;
-}
-
-function peg$parsesimpleFormat(){
-var s0,s1,s2,s3,s4,s5,s6;
-
-s0=peg$currPos;
-if(input.substr(peg$currPos,6)===peg$c12){
-s1=peg$c12;
-peg$currPos+=6;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c13);}
-}
-if(s1===peg$FAILED){
-if(input.substr(peg$currPos,4)===peg$c14){
-s1=peg$c14;
-peg$currPos+=4;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c15);}
-}
-if(s1===peg$FAILED){
-if(input.substr(peg$currPos,4)===peg$c16){
-s1=peg$c16;
-peg$currPos+=4;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c17);}
-}
-}
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-s3=peg$currPos;
-if(input.charCodeAt(peg$currPos)===44){
-s4=peg$c7;
-peg$currPos++;
-}else{
-s4=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c8);}
-}
-if(s4!==peg$FAILED){
-s5=peg$parse_();
-if(s5!==peg$FAILED){
-s6=peg$parsechars();
-if(s6!==peg$FAILED){
-s4=[s4,s5,s6];
-s3=s4;
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-if(s3===peg$FAILED){
-s3=null;
-}
-if(s3!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c18(s1,s3);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parsepluralFormat(){
-var s0,s1,s2,s3,s4,s5;
-
-s0=peg$currPos;
-if(input.substr(peg$currPos,6)===peg$c19){
-s1=peg$c19;
-peg$currPos+=6;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c20);}
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-if(input.charCodeAt(peg$currPos)===44){
-s3=peg$c7;
-peg$currPos++;
-}else{
-s3=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c8);}
-}
-if(s3!==peg$FAILED){
-s4=peg$parse_();
-if(s4!==peg$FAILED){
-s5=peg$parsepluralStyle();
-if(s5!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c21(s5);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parseselectOrdinalFormat(){
-var s0,s1,s2,s3,s4,s5;
-
-s0=peg$currPos;
-if(input.substr(peg$currPos,13)===peg$c22){
-s1=peg$c22;
-peg$currPos+=13;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c23);}
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-if(input.charCodeAt(peg$currPos)===44){
-s3=peg$c7;
-peg$currPos++;
-}else{
-s3=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c8);}
-}
-if(s3!==peg$FAILED){
-s4=peg$parse_();
-if(s4!==peg$FAILED){
-s5=peg$parsepluralStyle();
-if(s5!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c24(s5);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parseselectFormat(){
-var s0,s1,s2,s3,s4,s5,s6;
-
-s0=peg$currPos;
-if(input.substr(peg$currPos,6)===peg$c25){
-s1=peg$c25;
-peg$currPos+=6;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c26);}
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-if(input.charCodeAt(peg$currPos)===44){
-s3=peg$c7;
-peg$currPos++;
-}else{
-s3=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c8);}
-}
-if(s3!==peg$FAILED){
-s4=peg$parse_();
-if(s4!==peg$FAILED){
-s5=[];
-s6=peg$parseoptionalFormatPattern();
-if(s6!==peg$FAILED){
-while(s6!==peg$FAILED){
-s5.push(s6);
-s6=peg$parseoptionalFormatPattern();
-}
-}else{
-s5=peg$FAILED;
-}
-if(s5!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c27(s5);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parseselector(){
-var s0,s1,s2,s3;
-
-s0=peg$currPos;
-s1=peg$currPos;
-if(input.charCodeAt(peg$currPos)===61){
-s2=peg$c28;
-peg$currPos++;
-}else{
-s2=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c29);}
-}
-if(s2!==peg$FAILED){
-s3=peg$parsenumber();
-if(s3!==peg$FAILED){
-s2=[s2,s3];
-s1=s2;
-}else{
-peg$currPos=s1;
-s1=peg$FAILED;
-}
-}else{
-peg$currPos=s1;
-s1=peg$FAILED;
-}
-if(s1!==peg$FAILED){
-s0=input.substring(s0,peg$currPos);
-}else{
-s0=s1;
-}
-if(s0===peg$FAILED){
-s0=peg$parsechars();
-}
-
-return s0;
-}
-
-function peg$parseoptionalFormatPattern(){
-var s0,s1,s2,s3,s4,s5,s6,s7,s8;
-
-s0=peg$currPos;
-s1=peg$parse_();
-if(s1!==peg$FAILED){
-s2=peg$parseselector();
-if(s2!==peg$FAILED){
-s3=peg$parse_();
-if(s3!==peg$FAILED){
-if(input.charCodeAt(peg$currPos)===123){
-s4=peg$c5;
-peg$currPos++;
-}else{
-s4=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c6);}
-}
-if(s4!==peg$FAILED){
-s5=peg$parse_();
-if(s5!==peg$FAILED){
-s6=peg$parsemessageFormatPattern();
-if(s6!==peg$FAILED){
-s7=peg$parse_();
-if(s7!==peg$FAILED){
-if(input.charCodeAt(peg$currPos)===125){
-s8=peg$c9;
-peg$currPos++;
-}else{
-s8=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c10);}
-}
-if(s8!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c30(s2,s6);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parseoffset(){
-var s0,s1,s2,s3;
-
-s0=peg$currPos;
-if(input.substr(peg$currPos,7)===peg$c31){
-s1=peg$c31;
-peg$currPos+=7;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c32);}
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-s3=peg$parsenumber();
-if(s3!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c33(s3);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parsepluralStyle(){
-var s0,s1,s2,s3,s4;
-
-s0=peg$currPos;
-s1=peg$parseoffset();
-if(s1===peg$FAILED){
-s1=null;
-}
-if(s1!==peg$FAILED){
-s2=peg$parse_();
-if(s2!==peg$FAILED){
-s3=[];
-s4=peg$parseoptionalFormatPattern();
-if(s4!==peg$FAILED){
-while(s4!==peg$FAILED){
-s3.push(s4);
-s4=peg$parseoptionalFormatPattern();
-}
-}else{
-s3=peg$FAILED;
-}
-if(s3!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c34(s1,s3);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-
-return s0;
-}
-
-function peg$parsews(){
-var s0,s1;
-
-peg$silentFails++;
-s0=[];
-if(peg$c36.test(input.charAt(peg$currPos))){
-s1=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c37);}
-}
-if(s1!==peg$FAILED){
-while(s1!==peg$FAILED){
-s0.push(s1);
-if(peg$c36.test(input.charAt(peg$currPos))){
-s1=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c37);}
-}
-}
-}else{
-s0=peg$FAILED;
-}
-peg$silentFails--;
-if(s0===peg$FAILED){
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c35);}
-}
-
-return s0;
-}
-
-function peg$parse_(){
-var s0,s1,s2;
-
-peg$silentFails++;
-s0=peg$currPos;
-s1=[];
-s2=peg$parsews();
-while(s2!==peg$FAILED){
-s1.push(s2);
-s2=peg$parsews();
-}
-if(s1!==peg$FAILED){
-s0=input.substring(s0,peg$currPos);
-}else{
-s0=s1;
-}
-peg$silentFails--;
-if(s0===peg$FAILED){
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c38);}
-}
-
-return s0;
-}
-
-function peg$parsedigit(){
-var s0;
-
-if(peg$c39.test(input.charAt(peg$currPos))){
-s0=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s0=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c40);}
-}
-
-return s0;
-}
-
-function peg$parsehexDigit(){
-var s0;
-
-if(peg$c41.test(input.charAt(peg$currPos))){
-s0=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s0=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c42);}
-}
-
-return s0;
-}
-
-function peg$parsenumber(){
-var s0,s1,s2,s3,s4,s5;
-
-s0=peg$currPos;
-if(input.charCodeAt(peg$currPos)===48){
-s1=peg$c43;
-peg$currPos++;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c44);}
-}
-if(s1===peg$FAILED){
-s1=peg$currPos;
-s2=peg$currPos;
-if(peg$c45.test(input.charAt(peg$currPos))){
-s3=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s3=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c46);}
-}
-if(s3!==peg$FAILED){
-s4=[];
-s5=peg$parsedigit();
-while(s5!==peg$FAILED){
-s4.push(s5);
-s5=peg$parsedigit();
-}
-if(s4!==peg$FAILED){
-s3=[s3,s4];
-s2=s3;
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-}else{
-peg$currPos=s2;
-s2=peg$FAILED;
-}
-if(s2!==peg$FAILED){
-s1=input.substring(s1,peg$currPos);
-}else{
-s1=s2;
-}
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c47(s1);
-}
-s0=s1;
-
-return s0;
-}
-
-function peg$parsechar(){
-var s0,s1,s2,s3,s4,s5,s6,s7;
-
-if(peg$c48.test(input.charAt(peg$currPos))){
-s0=input.charAt(peg$currPos);
-peg$currPos++;
-}else{
-s0=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c49);}
-}
-if(s0===peg$FAILED){
-s0=peg$currPos;
-if(input.substr(peg$currPos,2)===peg$c50){
-s1=peg$c50;
-peg$currPos+=2;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c51);}
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c52();
-}
-s0=s1;
-if(s0===peg$FAILED){
-s0=peg$currPos;
-if(input.substr(peg$currPos,2)===peg$c53){
-s1=peg$c53;
-peg$currPos+=2;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c54);}
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c55();
-}
-s0=s1;
-if(s0===peg$FAILED){
-s0=peg$currPos;
-if(input.substr(peg$currPos,2)===peg$c56){
-s1=peg$c56;
-peg$currPos+=2;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c57);}
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c58();
-}
-s0=s1;
-if(s0===peg$FAILED){
-s0=peg$currPos;
-if(input.substr(peg$currPos,2)===peg$c59){
-s1=peg$c59;
-peg$currPos+=2;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c60);}
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c61();
-}
-s0=s1;
-if(s0===peg$FAILED){
-s0=peg$currPos;
-if(input.substr(peg$currPos,2)===peg$c62){
-s1=peg$c62;
-peg$currPos+=2;
-}else{
-s1=peg$FAILED;
-if(peg$silentFails===0){peg$fail(peg$c63);}
-}
-if(s1!==peg$FAILED){
-s2=peg$currPos;
-s3=peg$currPos;
-s4=peg$parsehexDigit();
-if(s4!==peg$FAILED){
-s5=peg$parsehexDigit();
-if(s5!==peg$FAILED){
-s6=peg$parsehexDigit();
-if(s6!==peg$FAILED){
-s7=peg$parsehexDigit();
-if(s7!==peg$FAILED){
-s4=[s4,s5,s6,s7];
-s3=s4;
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-}else{
-peg$currPos=s3;
-s3=peg$FAILED;
-}
-if(s3!==peg$FAILED){
-s2=input.substring(s2,peg$currPos);
-}else{
-s2=s3;
-}
-if(s2!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c64(s2);
-s0=s1;
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}else{
-peg$currPos=s0;
-s0=peg$FAILED;
-}
-}
-}
-}
-}
-}
-
-return s0;
-}
-
-function peg$parsechars(){
-var s0,s1,s2;
-
-s0=peg$currPos;
-s1=[];
-s2=peg$parsechar();
-if(s2!==peg$FAILED){
-while(s2!==peg$FAILED){
-s1.push(s2);
-s2=peg$parsechar();
-}
-}else{
-s1=peg$FAILED;
-}
-if(s1!==peg$FAILED){
-peg$savedPos=s0;
-s1=peg$c65(s1);
-}
-s0=s1;
-
-return s0;
-}
-
-peg$result=peg$startRuleFunction();
-
-if(peg$result!==peg$FAILED&&peg$currPos===input.length){
-return peg$result;
-}else{
-if(peg$result!==peg$FAILED&&peg$currPos<input.length){
-peg$fail({type:"end",description:"end of input"});
-}
-
-throw peg$buildException(
-null,
-peg$maxFailExpected,
-peg$maxFailPos<input.length?input.charAt(peg$maxFailPos):null,
-peg$maxFailPos<input.length?
-peg$computeLocation(peg$maxFailPos,peg$maxFailPos+1):
-peg$computeLocation(peg$maxFailPos,peg$maxFailPos));
-
-}
-}
-
-return{
-SyntaxError:peg$SyntaxError,
-parse:peg$parse};
-
-}();
-
-
-},{}],168:[function(require,module,exports){
-
-
-'use strict';
-
-var IntlMessageFormat=require('./lib/main')['default'];
-
-
-
-require('./lib/locales');
-
-
-
-
-exports=module.exports=IntlMessageFormat;
-exports['default']=exports;
-
-},{"./lib/locales":104,"./lib/main":173}],169:[function(require,module,exports){
-
-
-
-
-
-
-
-
-"use strict";
-exports["default"]=Compiler;
-
-function Compiler(locales,formats,pluralFn){
-this.locales=locales;
-this.formats=formats;
-this.pluralFn=pluralFn;
-}
-
-Compiler.prototype.compile=function(ast){
-this.pluralStack=[];
-this.currentPlural=null;
-this.pluralNumberFormat=null;
-
-return this.compileMessage(ast);
-};
-
-Compiler.prototype.compileMessage=function(ast){
-if(!(ast&&ast.type==='messageFormatPattern')){
-throw new Error('Message AST is not of type: "messageFormatPattern"');
-}
-
-var elements=ast.elements,
-pattern=[];
-
-var i,len,element;
-
-for(i=0,len=elements.length;i<len;i+=1){
-element=elements[i];
-
-switch(element.type){
-case'messageTextElement':
-pattern.push(this.compileMessageText(element));
-break;
-
-case'argumentElement':
-pattern.push(this.compileArgument(element));
-break;
-
-default:
-throw new Error('Message element does not have a valid type');}
-
-}
-
-return pattern;
-};
-
-Compiler.prototype.compileMessageText=function(element){
-
-
-
-if(this.currentPlural&&/(^|[^\\])#/g.test(element.value)){
-
-
-if(!this.pluralNumberFormat){
-this.pluralNumberFormat=new Intl.NumberFormat(this.locales);
-}
-
-return new PluralOffsetString(
-this.currentPlural.id,
-this.currentPlural.format.offset,
-this.pluralNumberFormat,
-element.value);
-}
-
-
-return element.value.replace(/\\#/g,'#');
-};
-
-Compiler.prototype.compileArgument=function(element){
-var format=element.format;
-
-if(!format){
-return new StringFormat(element.id);
-}
-
-var formats=this.formats,
-locales=this.locales,
-pluralFn=this.pluralFn,
-options;
-
-switch(format.type){
-case'numberFormat':
-options=formats.number[format.style];
-return{
-id:element.id,
-format:new Intl.NumberFormat(locales,options).format};
-
-
-case'dateFormat':
-options=formats.date[format.style];
-return{
-id:element.id,
-format:new Intl.DateTimeFormat(locales,options).format};
-
-
-case'timeFormat':
-options=formats.time[format.style];
-return{
-id:element.id,
-format:new Intl.DateTimeFormat(locales,options).format};
-
-
-case'pluralFormat':
-options=this.compileOptions(element);
-return new PluralFormat(
-element.id,format.ordinal,format.offset,options,pluralFn);
-
-
-case'selectFormat':
-options=this.compileOptions(element);
-return new SelectFormat(element.id,options);
-
-default:
-throw new Error('Message element does not have a valid format type');}
-
-};
-
-Compiler.prototype.compileOptions=function(element){
-var format=element.format,
-options=format.options,
-optionsHash={};
-
-
-
-
-this.pluralStack.push(this.currentPlural);
-this.currentPlural=format.type==='pluralFormat'?element:null;
-
-var i,len,option;
-
-for(i=0,len=options.length;i<len;i+=1){
-option=options[i];
-
-
-optionsHash[option.selector]=this.compileMessage(option.value);
-}
-
-
-this.currentPlural=this.pluralStack.pop();
-
-return optionsHash;
-};
-
-
-
-function StringFormat(id){
-this.id=id;
-}
-
-StringFormat.prototype.format=function(value){
-if(!value&&typeof value!=='number'){
-return'';
-}
-
-return typeof value==='string'?value:String(value);
-};
-
-function PluralFormat(id,useOrdinal,offset,options,pluralFn){
-this.id=id;
-this.useOrdinal=useOrdinal;
-this.offset=offset;
-this.options=options;
-this.pluralFn=pluralFn;
-}
-
-PluralFormat.prototype.getOption=function(value){
-var options=this.options;
-
-var option=options['='+value]||
-options[this.pluralFn(value-this.offset,this.useOrdinal)];
-
-return option||options.other;
-};
-
-function PluralOffsetString(id,offset,numberFormat,string){
-this.id=id;
-this.offset=offset;
-this.numberFormat=numberFormat;
-this.string=string;
-}
-
-PluralOffsetString.prototype.format=function(value){
-var number=this.numberFormat.format(value-this.offset);
-
-return this.string.
-replace(/(^|[^\\])#/g,'$1'+number).
-replace(/\\#/g,'#');
-};
-
-function SelectFormat(id,options){
-this.id=id;
-this.options=options;
-}
-
-SelectFormat.prototype.getOption=function(value){
-var options=this.options;
-return options[value]||options.other;
-};
-
-
-},{}],170:[function(require,module,exports){
-
-
-
-
-
-
-
-
-"use strict";
-var src$utils$$=require("./utils"),src$es5$$=require("./es5"),src$compiler$$=require("./compiler"),intl$messageformat$parser$$=require("intl-messageformat-parser");
-exports["default"]=MessageFormat;
-
-
-
-function MessageFormat(message,locales,formats){
-
-var ast=typeof message==='string'?
-MessageFormat.__parse(message):message;
-
-if(!(ast&&ast.type==='messageFormatPattern')){
-throw new TypeError('A message must be provided as a String or AST.');
-}
-
-
-
-formats=this._mergeFormats(MessageFormat.formats,formats);
-
-
-src$es5$$.defineProperty(this,'_locale',{value:this._resolveLocale(locales)});
-
-
-
-
-var pluralFn=this._findPluralRuleFunction(this._locale);
-var pattern=this._compilePattern(ast,locales,formats,pluralFn);
-
-
-
-var messageFormat=this;
-this.format=function(values){
-try{
-return messageFormat._format(pattern,values);
-}catch(e){
-if(e.variableId){
-throw new Error(
-'The intl string context variable \''+e.variableId+'\''+
-' was not provided to the string \''+message+'\'');
-
-}else{
-throw e;
-}
-}
-};
-}
-
-
-
-
-src$es5$$.defineProperty(MessageFormat,'formats',{
-enumerable:true,
-
-value:{
-number:{
-'currency':{
-style:'currency'},
-
-
-'percent':{
-style:'percent'}},
-
-
-
-date:{
-'short':{
-month:'numeric',
-day:'numeric',
-year:'2-digit'},
-
-
-'medium':{
-month:'short',
-day:'numeric',
-year:'numeric'},
-
-
-'long':{
-month:'long',
-day:'numeric',
-year:'numeric'},
-
-
-'full':{
-weekday:'long',
-month:'long',
-day:'numeric',
-year:'numeric'}},
-
-
-
-time:{
-'short':{
-hour:'numeric',
-minute:'numeric'},
-
-
-'medium':{
-hour:'numeric',
-minute:'numeric',
-second:'numeric'},
-
-
-'long':{
-hour:'numeric',
-minute:'numeric',
-second:'numeric',
-timeZoneName:'short'},
-
-
-'full':{
-hour:'numeric',
-minute:'numeric',
-second:'numeric',
-timeZoneName:'short'}}}});
-
-
-
-
-
-
-src$es5$$.defineProperty(MessageFormat,'__localeData__',{value:src$es5$$.objCreate(null)});
-src$es5$$.defineProperty(MessageFormat,'__addLocaleData',{value:function(data){
-if(!(data&&data.locale)){
-throw new Error(
-'Locale data provided to IntlMessageFormat is missing a '+
-'`locale` property');
-
-}
-
-MessageFormat.__localeData__[data.locale.toLowerCase()]=data;
-}});
-
-
-src$es5$$.defineProperty(MessageFormat,'__parse',{value:intl$messageformat$parser$$["default"].parse});
-
-
-
-src$es5$$.defineProperty(MessageFormat,'defaultLocale',{
-enumerable:true,
-writable:true,
-value:undefined});
-
-
-MessageFormat.prototype.resolvedOptions=function(){
-
-return{
-locale:this._locale};
-
-};
-
-MessageFormat.prototype._compilePattern=function(ast,locales,formats,pluralFn){
-var compiler=new src$compiler$$["default"](locales,formats,pluralFn);
-return compiler.compile(ast);
-};
-
-MessageFormat.prototype._findPluralRuleFunction=function(locale){
-var localeData=MessageFormat.__localeData__;
-var data=localeData[locale.toLowerCase()];
-
-
-
-while(data){
-if(data.pluralRuleFunction){
-return data.pluralRuleFunction;
-}
-
-data=data.parentLocale&&localeData[data.parentLocale.toLowerCase()];
-}
-
-throw new Error(
-'Locale data added to IntlMessageFormat is missing a '+
-'`pluralRuleFunction` for :'+locale);
-
-};
-
-MessageFormat.prototype._format=function(pattern,values){
-var result='',
-i,len,part,id,value,err;
-
-for(i=0,len=pattern.length;i<len;i+=1){
-part=pattern[i];
-
-
-if(typeof part==='string'){
-result+=part;
-continue;
-}
-
-id=part.id;
-
-
-if(!(values&&src$utils$$.hop.call(values,id))){
-err=new Error('A value must be provided for: '+id);
-err.variableId=id;
-throw err;
-}
-
-value=values[id];
-
-
-
-
-if(part.options){
-result+=this._format(part.getOption(value),values);
-}else{
-result+=part.format(value);
-}
-}
-
-return result;
-};
-
-MessageFormat.prototype._mergeFormats=function(defaults,formats){
-var mergedFormats={},
-type,mergedType;
-
-for(type in defaults){
-if(!src$utils$$.hop.call(defaults,type)){continue;}
-
-mergedFormats[type]=mergedType=src$es5$$.objCreate(defaults[type]);
-
-if(formats&&src$utils$$.hop.call(formats,type)){
-src$utils$$.extend(mergedType,formats[type]);
-}
-}
-
-return mergedFormats;
-};
-
-MessageFormat.prototype._resolveLocale=function(locales){
-if(typeof locales==='string'){
-locales=[locales];
-}
-
-
-locales=(locales||[]).concat(MessageFormat.defaultLocale);
-
-var localeData=MessageFormat.__localeData__;
-var i,len,localeParts,data;
-
-
-
-
-
-
-for(i=0,len=locales.length;i<len;i+=1){
-localeParts=locales[i].toLowerCase().split('-');
-
-while(localeParts.length){
-data=localeData[localeParts.join('-')];
-if(data){
-
-
-return data.locale;
-}
-
-localeParts.pop();
-}
-}
-
-var defaultLocale=locales.pop();
-throw new Error(
-'No locale data has been added to IntlMessageFormat for: '+
-locales.join(', ')+', or the default locale: '+defaultLocale);
-
-};
-
-
-},{"./compiler":169,"./es5":172,"./utils":174,"intl-messageformat-parser":166}],171:[function(require,module,exports){
-
-"use strict";
-exports["default"]={"locale":"en","pluralRuleFunction":function(n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return n10==1&&n100!=11?"one":n10==2&&n100!=12?"two":n10==3&&n100!=13?"few":"other";return n==1&&v0?"one":"other";}};
-
-
-},{}],172:[function(require,module,exports){
-
-
-
-
-
-
-
-
-"use strict";
-var src$utils$$=require("./utils");
-
-
-
-
-var realDefineProp=function(){
-try{return!!Object.defineProperty({},'a',{});}
-catch(e){return false;}
-}();
-
-var es3=!realDefineProp&&!Object.prototype.__defineGetter__;
-
-var defineProperty=realDefineProp?Object.defineProperty:
-function(obj,name,desc){
-
-if('get'in desc&&obj.__defineGetter__){
-obj.__defineGetter__(name,desc.get);
-}else if(!src$utils$$.hop.call(obj,name)||'value'in desc){
-obj[name]=desc.value;
-}
-};
-
-var objCreate=Object.create||function(proto,props){
-var obj,k;
-
-function F(){}
-F.prototype=proto;
-obj=new F();
-
-for(k in props){
-if(src$utils$$.hop.call(props,k)){
-defineProperty(obj,k,props[k]);
-}
-}
-
-return obj;
-};
-
-exports.defineProperty=defineProperty,exports.objCreate=objCreate;
-
-
-},{"./utils":174}],173:[function(require,module,exports){
-
-
-"use strict";
-var src$core$$=require("./core"),src$en$$=require("./en");
-
-src$core$$["default"].__addLocaleData(src$en$$["default"]);
-src$core$$["default"].defaultLocale='en';
-
-exports["default"]=src$core$$["default"];
-
-
-},{"./core":170,"./en":171}],174:[function(require,module,exports){
-
-
-
-
-
-
-
-
-"use strict";
-exports.extend=extend;
-var hop=Object.prototype.hasOwnProperty;
-
-function extend(obj){
-var sources=Array.prototype.slice.call(arguments,1),
-i,len,source,key;
-
-for(i=0,len=sources.length;i<len;i+=1){
-source=sources[i];
-if(!source){continue;}
-
-for(key in source){
-if(hop.call(source,key)){
-obj[key]=source[key];
-}
-}
-}
-
-return obj;
-}
-exports.hop=hop;
-
-
-},{}],175:[function(require,module,exports){
-var encode=require('./lib/encoder'),
-decode=require('./lib/decoder');
-
-module.exports={
-encode:encode,
-decode:decode};
-
-
-},{"./lib/decoder":176,"./lib/encoder":177}],176:[function(require,module,exports){
-(function(Buffer){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var JpegImage=function jpegImage(){
-"use strict";
-var dctZigZag=new Int32Array([
-0,
-1,8,
-16,9,2,
-3,10,17,24,
-32,25,18,11,4,
-5,12,19,26,33,40,
-48,41,34,27,20,13,6,
-7,14,21,28,35,42,49,56,
-57,50,43,36,29,22,15,
-23,30,37,44,51,58,
-59,52,45,38,31,
-39,46,53,60,
-61,54,47,
-55,62,
-63]);
-
-
-var dctCos1=4017;
-var dctSin1=799;
-var dctCos3=3406;
-var dctSin3=2276;
-var dctCos6=1567;
-var dctSin6=3784;
-var dctSqrt2=5793;
-var dctSqrt1d2=2896;
-
-function constructor(){
-}
-
-function buildHuffmanTable(codeLengths,values){
-var k=0,code=[],i,j,length=16;
-while(length>0&&!codeLengths[length-1])
-length--;
-code.push({children:[],index:0});
-var p=code[0],q;
-for(i=0;i<length;i++){
-for(j=0;j<codeLengths[i];j++){
-p=code.pop();
-p.children[p.index]=values[k];
-while(p.index>0){
-p=code.pop();
-}
-p.index++;
-code.push(p);
-while(code.length<=i){
-code.push(q={children:[],index:0});
-p.children[p.index]=q.children;
-p=q;
-}
-k++;
-}
-if(i+1<length){
-
-code.push(q={children:[],index:0});
-p.children[p.index]=q.children;
-p=q;
-}
-}
-return code[0].children;
-}
-
-function decodeScan(data,offset,
-frame,components,resetInterval,
-spectralStart,spectralEnd,
-successivePrev,successive){
-var precision=frame.precision;
-var samplesPerLine=frame.samplesPerLine;
-var scanLines=frame.scanLines;
-var mcusPerLine=frame.mcusPerLine;
-var progressive=frame.progressive;
-var maxH=frame.maxH,maxV=frame.maxV;
-
-var startOffset=offset,bitsData=0,bitsCount=0;
-function readBit(){
-if(bitsCount>0){
-bitsCount--;
-return bitsData>>bitsCount&1;
-}
-bitsData=data[offset++];
-if(bitsData==0xFF){
-var nextByte=data[offset++];
-if(nextByte){
-throw"unexpected marker: "+(bitsData<<8|nextByte).toString(16);
-}
-
-}
-bitsCount=7;
-return bitsData>>>7;
-}
-function decodeHuffman(tree){
-var node=tree,bit;
-while((bit=readBit())!==null){
-node=node[bit];
-if(typeof node==='number')
-return node;
-if(typeof node!=='object')
-throw"invalid huffman sequence";
-}
-return null;
-}
-function receive(length){
-var n=0;
-while(length>0){
-var bit=readBit();
-if(bit===null)return;
-n=n<<1|bit;
-length--;
-}
-return n;
-}
-function receiveAndExtend(length){
-var n=receive(length);
-if(n>=1<<length-1)
-return n;
-return n+(-1<<length)+1;
-}
-function decodeBaseline(component,zz){
-var t=decodeHuffman(component.huffmanTableDC);
-var diff=t===0?0:receiveAndExtend(t);
-zz[0]=component.pred+=diff;
-var k=1;
-while(k<64){
-var rs=decodeHuffman(component.huffmanTableAC);
-var s=rs&15,r=rs>>4;
-if(s===0){
-if(r<15)
-break;
-k+=16;
-continue;
-}
-k+=r;
-var z=dctZigZag[k];
-zz[z]=receiveAndExtend(s);
-k++;
-}
-}
-function decodeDCFirst(component,zz){
-var t=decodeHuffman(component.huffmanTableDC);
-var diff=t===0?0:receiveAndExtend(t)<<successive;
-zz[0]=component.pred+=diff;
-}
-function decodeDCSuccessive(component,zz){
-zz[0]|=readBit()<<successive;
-}
-var eobrun=0;
-function decodeACFirst(component,zz){
-if(eobrun>0){
-eobrun--;
-return;
-}
-var k=spectralStart,e=spectralEnd;
-while(k<=e){
-var rs=decodeHuffman(component.huffmanTableAC);
-var s=rs&15,r=rs>>4;
-if(s===0){
-if(r<15){
-eobrun=receive(r)+(1<<r)-1;
-break;
-}
-k+=16;
-continue;
-}
-k+=r;
-var z=dctZigZag[k];
-zz[z]=receiveAndExtend(s)*(1<<successive);
-k++;
-}
-}
-var successiveACState=0,successiveACNextValue;
-function decodeACSuccessive(component,zz){
-var k=spectralStart,e=spectralEnd,r=0;
-while(k<=e){
-var z=dctZigZag[k];
-switch(successiveACState){
-case 0:
-var rs=decodeHuffman(component.huffmanTableAC);
-var s=rs&15,r=rs>>4;
-if(s===0){
-if(r<15){
-eobrun=receive(r)+(1<<r);
-successiveACState=4;
-}else{
-r=16;
-successiveACState=1;
-}
-}else{
-if(s!==1)
-throw"invalid ACn encoding";
-successiveACNextValue=receiveAndExtend(s);
-successiveACState=r?2:3;
-}
-continue;
-case 1:
-case 2:
-if(zz[z])
-zz[z]+=readBit()<<successive;else
-{
-r--;
-if(r===0)
-successiveACState=successiveACState==2?3:0;
-}
-break;
-case 3:
-if(zz[z])
-zz[z]+=readBit()<<successive;else
-{
-zz[z]=successiveACNextValue<<successive;
-successiveACState=0;
-}
-break;
-case 4:
-if(zz[z])
-zz[z]+=readBit()<<successive;
-break;}
-
-k++;
-}
-if(successiveACState===4){
-eobrun--;
-if(eobrun===0)
-successiveACState=0;
-}
-}
-function decodeMcu(component,decode,mcu,row,col){
-var mcuRow=mcu/mcusPerLine|0;
-var mcuCol=mcu%mcusPerLine;
-var blockRow=mcuRow*component.v+row;
-var blockCol=mcuCol*component.h+col;
-decode(component,component.blocks[blockRow][blockCol]);
-}
-function decodeBlock(component,decode,mcu){
-var blockRow=mcu/component.blocksPerLine|0;
-var blockCol=mcu%component.blocksPerLine;
-decode(component,component.blocks[blockRow][blockCol]);
-}
-
-var componentsLength=components.length;
-var component,i,j,k,n;
-var decodeFn;
-if(progressive){
-if(spectralStart===0)
-decodeFn=successivePrev===0?decodeDCFirst:decodeDCSuccessive;else
-
-decodeFn=successivePrev===0?decodeACFirst:decodeACSuccessive;
-}else{
-decodeFn=decodeBaseline;
-}
-
-var mcu=0,marker;
-var mcuExpected;
-if(componentsLength==1){
-mcuExpected=components[0].blocksPerLine*components[0].blocksPerColumn;
-}else{
-mcuExpected=mcusPerLine*frame.mcusPerColumn;
-}
-if(!resetInterval)resetInterval=mcuExpected;
-
-var h,v;
-while(mcu<mcuExpected){
-
-for(i=0;i<componentsLength;i++)
-components[i].pred=0;
-eobrun=0;
-
-if(componentsLength==1){
-component=components[0];
-for(n=0;n<resetInterval;n++){
-decodeBlock(component,decodeFn,mcu);
-mcu++;
-}
-}else{
-for(n=0;n<resetInterval;n++){
-for(i=0;i<componentsLength;i++){
-component=components[i];
-h=component.h;
-v=component.v;
-for(j=0;j<v;j++){
-for(k=0;k<h;k++){
-decodeMcu(component,decodeFn,mcu,j,k);
-}
-}
-}
-mcu++;
-
-
-if(mcu===mcuExpected)break;
-}
-}
-
-
-bitsCount=0;
-marker=data[offset]<<8|data[offset+1];
-if(marker<0xFF00){
-throw"marker was not found";
-}
-
-if(marker>=0xFFD0&&marker<=0xFFD7){
-offset+=2;
-}else
-
-break;
-}
-
-return offset-startOffset;
-}
-
-function buildComponentData(frame,component){
-var lines=[];
-var blocksPerLine=component.blocksPerLine;
-var blocksPerColumn=component.blocksPerColumn;
-var samplesPerLine=blocksPerLine<<3;
-var R=new Int32Array(64),r=new Uint8Array(64);
-
-
-
-
-
-
-function quantizeAndInverse(zz,dataOut,dataIn){
-var qt=component.quantizationTable;
-var v0,v1,v2,v3,v4,v5,v6,v7,t;
-var p=dataIn;
-var i;
-
-
-for(i=0;i<64;i++)
-p[i]=zz[i]*qt[i];
-
-
-for(i=0;i<8;++i){
-var row=8*i;
-
-
-if(p[1+row]==0&&p[2+row]==0&&p[3+row]==0&&
-p[4+row]==0&&p[5+row]==0&&p[6+row]==0&&
-p[7+row]==0){
-t=dctSqrt2*p[0+row]+512>>10;
-p[0+row]=t;
-p[1+row]=t;
-p[2+row]=t;
-p[3+row]=t;
-p[4+row]=t;
-p[5+row]=t;
-p[6+row]=t;
-p[7+row]=t;
-continue;
-}
-
-
-v0=dctSqrt2*p[0+row]+128>>8;
-v1=dctSqrt2*p[4+row]+128>>8;
-v2=p[2+row];
-v3=p[6+row];
-v4=dctSqrt1d2*(p[1+row]-p[7+row])+128>>8;
-v7=dctSqrt1d2*(p[1+row]+p[7+row])+128>>8;
-v5=p[3+row]<<4;
-v6=p[5+row]<<4;
-
-
-t=v0-v1+1>>1;
-v0=v0+v1+1>>1;
-v1=t;
-t=v2*dctSin6+v3*dctCos6+128>>8;
-v2=v2*dctCos6-v3*dctSin6+128>>8;
-v3=t;
-t=v4-v6+1>>1;
-v4=v4+v6+1>>1;
-v6=t;
-t=v7+v5+1>>1;
-v5=v7-v5+1>>1;
-v7=t;
-
-
-t=v0-v3+1>>1;
-v0=v0+v3+1>>1;
-v3=t;
-t=v1-v2+1>>1;
-v1=v1+v2+1>>1;
-v2=t;
-t=v4*dctSin3+v7*dctCos3+2048>>12;
-v4=v4*dctCos3-v7*dctSin3+2048>>12;
-v7=t;
-t=v5*dctSin1+v6*dctCos1+2048>>12;
-v5=v5*dctCos1-v6*dctSin1+2048>>12;
-v6=t;
-
-
-p[0+row]=v0+v7;
-p[7+row]=v0-v7;
-p[1+row]=v1+v6;
-p[6+row]=v1-v6;
-p[2+row]=v2+v5;
-p[5+row]=v2-v5;
-p[3+row]=v3+v4;
-p[4+row]=v3-v4;
-}
-
-
-for(i=0;i<8;++i){
-var col=i;
-
-
-if(p[1*8+col]==0&&p[2*8+col]==0&&p[3*8+col]==0&&
-p[4*8+col]==0&&p[5*8+col]==0&&p[6*8+col]==0&&
-p[7*8+col]==0){
-t=dctSqrt2*dataIn[i+0]+8192>>14;
-p[0*8+col]=t;
-p[1*8+col]=t;
-p[2*8+col]=t;
-p[3*8+col]=t;
-p[4*8+col]=t;
-p[5*8+col]=t;
-p[6*8+col]=t;
-p[7*8+col]=t;
-continue;
-}
-
-
-v0=dctSqrt2*p[0*8+col]+2048>>12;
-v1=dctSqrt2*p[4*8+col]+2048>>12;
-v2=p[2*8+col];
-v3=p[6*8+col];
-v4=dctSqrt1d2*(p[1*8+col]-p[7*8+col])+2048>>12;
-v7=dctSqrt1d2*(p[1*8+col]+p[7*8+col])+2048>>12;
-v5=p[3*8+col];
-v6=p[5*8+col];
-
-
-t=v0-v1+1>>1;
-v0=v0+v1+1>>1;
-v1=t;
-t=v2*dctSin6+v3*dctCos6+2048>>12;
-v2=v2*dctCos6-v3*dctSin6+2048>>12;
-v3=t;
-t=v4-v6+1>>1;
-v4=v4+v6+1>>1;
-v6=t;
-t=v7+v5+1>>1;
-v5=v7-v5+1>>1;
-v7=t;
-
-
-t=v0-v3+1>>1;
-v0=v0+v3+1>>1;
-v3=t;
-t=v1-v2+1>>1;
-v1=v1+v2+1>>1;
-v2=t;
-t=v4*dctSin3+v7*dctCos3+2048>>12;
-v4=v4*dctCos3-v7*dctSin3+2048>>12;
-v7=t;
-t=v5*dctSin1+v6*dctCos1+2048>>12;
-v5=v5*dctCos1-v6*dctSin1+2048>>12;
-v6=t;
-
-
-p[0*8+col]=v0+v7;
-p[7*8+col]=v0-v7;
-p[1*8+col]=v1+v6;
-p[6*8+col]=v1-v6;
-p[2*8+col]=v2+v5;
-p[5*8+col]=v2-v5;
-p[3*8+col]=v3+v4;
-p[4*8+col]=v3-v4;
-}
-
-
-for(i=0;i<64;++i){
-var sample=128+(p[i]+8>>4);
-dataOut[i]=sample<0?0:sample>0xFF?0xFF:sample;
-}
-}
-
-var i,j;
-for(var blockRow=0;blockRow<blocksPerColumn;blockRow++){
-var scanLine=blockRow<<3;
-for(i=0;i<8;i++)
-lines.push(new Uint8Array(samplesPerLine));
-for(var blockCol=0;blockCol<blocksPerLine;blockCol++){
-quantizeAndInverse(component.blocks[blockRow][blockCol],r,R);
-
-var offset=0,sample=blockCol<<3;
-for(j=0;j<8;j++){
-var line=lines[scanLine+j];
-for(i=0;i<8;i++)
-line[sample+i]=r[offset++];
-}
-}
-}
-return lines;
-}
-
-function clampTo8bit(a){
-return a<0?0:a>255?255:a;
-}
-
-constructor.prototype={
-load:function load(path){
-var xhr=new XMLHttpRequest();
-xhr.open("GET",path,true);
-xhr.responseType="arraybuffer";
-xhr.onload=function(){
-
-var data=new Uint8Array(xhr.response||xhr.mozResponseArrayBuffer);
-this.parse(data);
-if(this.onload)
-this.onload();
-}.bind(this);
-xhr.send(null);
-},
-parse:function parse(data){
-var offset=0,length=data.length;
-function readUint16(){
-var value=data[offset]<<8|data[offset+1];
-offset+=2;
-return value;
-}
-function readDataBlock(){
-var length=readUint16();
-var array=data.subarray(offset,offset+length-2);
-offset+=array.length;
-return array;
-}
-function prepareComponents(frame){
-var maxH=0,maxV=0;
-var component,componentId;
-for(componentId in frame.components){
-if(frame.components.hasOwnProperty(componentId)){
-component=frame.components[componentId];
-if(maxH<component.h)maxH=component.h;
-if(maxV<component.v)maxV=component.v;
-}
-}
-var mcusPerLine=Math.ceil(frame.samplesPerLine/8/maxH);
-var mcusPerColumn=Math.ceil(frame.scanLines/8/maxV);
-for(componentId in frame.components){
-if(frame.components.hasOwnProperty(componentId)){
-component=frame.components[componentId];
-var blocksPerLine=Math.ceil(Math.ceil(frame.samplesPerLine/8)*component.h/maxH);
-var blocksPerColumn=Math.ceil(Math.ceil(frame.scanLines/8)*component.v/maxV);
-var blocksPerLineForMcu=mcusPerLine*component.h;
-var blocksPerColumnForMcu=mcusPerColumn*component.v;
-var blocks=[];
-for(var i=0;i<blocksPerColumnForMcu;i++){
-var row=[];
-for(var j=0;j<blocksPerLineForMcu;j++)
-row.push(new Int32Array(64));
-blocks.push(row);
-}
-component.blocksPerLine=blocksPerLine;
-component.blocksPerColumn=blocksPerColumn;
-component.blocks=blocks;
-}
-}
-frame.maxH=maxH;
-frame.maxV=maxV;
-frame.mcusPerLine=mcusPerLine;
-frame.mcusPerColumn=mcusPerColumn;
-}
-var jfif=null;
-var adobe=null;
-var pixels=null;
-var frame,resetInterval;
-var quantizationTables=[],frames=[];
-var huffmanTablesAC=[],huffmanTablesDC=[];
-var fileMarker=readUint16();
-if(fileMarker!=0xFFD8){
-throw"SOI not found";
-}
-
-fileMarker=readUint16();
-while(fileMarker!=0xFFD9){
-var i,j,l;
-switch(fileMarker){
-case 0xFF00:break;
-case 0xFFE0:
-case 0xFFE1:
-case 0xFFE2:
-case 0xFFE3:
-case 0xFFE4:
-case 0xFFE5:
-case 0xFFE6:
-case 0xFFE7:
-case 0xFFE8:
-case 0xFFE9:
-case 0xFFEA:
-case 0xFFEB:
-case 0xFFEC:
-case 0xFFED:
-case 0xFFEE:
-case 0xFFEF:
-case 0xFFFE:
-var appData=readDataBlock();
-
-if(fileMarker===0xFFE0){
-if(appData[0]===0x4A&&appData[1]===0x46&&appData[2]===0x49&&
-appData[3]===0x46&&appData[4]===0){
-jfif={
-version:{major:appData[5],minor:appData[6]},
-densityUnits:appData[7],
-xDensity:appData[8]<<8|appData[9],
-yDensity:appData[10]<<8|appData[11],
-thumbWidth:appData[12],
-thumbHeight:appData[13],
-thumbData:appData.subarray(14,14+3*appData[12]*appData[13])};
-
-}
-}
-
-if(fileMarker===0xFFEE){
-if(appData[0]===0x41&&appData[1]===0x64&&appData[2]===0x6F&&
-appData[3]===0x62&&appData[4]===0x65&&appData[5]===0){
-adobe={
-version:appData[6],
-flags0:appData[7]<<8|appData[8],
-flags1:appData[9]<<8|appData[10],
-transformCode:appData[11]};
-
-}
-}
-break;
-
-case 0xFFDB:
-var quantizationTablesLength=readUint16();
-var quantizationTablesEnd=quantizationTablesLength+offset-2;
-while(offset<quantizationTablesEnd){
-var quantizationTableSpec=data[offset++];
-var tableData=new Int32Array(64);
-if(quantizationTableSpec>>4===0){
-for(j=0;j<64;j++){
-var z=dctZigZag[j];
-tableData[z]=data[offset++];
-}
-}else if(quantizationTableSpec>>4===1){
-for(j=0;j<64;j++){
-var z=dctZigZag[j];
-tableData[z]=readUint16();
-}
-}else
-throw"DQT: invalid table spec";
-quantizationTables[quantizationTableSpec&15]=tableData;
-}
-break;
-
-case 0xFFC0:
-case 0xFFC1:
-case 0xFFC2:
-readUint16();
-frame={};
-frame.extended=fileMarker===0xFFC1;
-frame.progressive=fileMarker===0xFFC2;
-frame.precision=data[offset++];
-frame.scanLines=readUint16();
-frame.samplesPerLine=readUint16();
-frame.components={};
-frame.componentsOrder=[];
-var componentsCount=data[offset++],componentId;
-var maxH=0,maxV=0;
-for(i=0;i<componentsCount;i++){
-componentId=data[offset];
-var h=data[offset+1]>>4;
-var v=data[offset+1]&15;
-var qId=data[offset+2];
-frame.componentsOrder.push(componentId);
-frame.components[componentId]={
-h:h,
-v:v,
-quantizationIdx:qId};
-
-offset+=3;
-}
-prepareComponents(frame);
-frames.push(frame);
-break;
-
-case 0xFFC4:
-var huffmanLength=readUint16();
-for(i=2;i<huffmanLength;){
-var huffmanTableSpec=data[offset++];
-var codeLengths=new Uint8Array(16);
-var codeLengthSum=0;
-for(j=0;j<16;j++,offset++)
-codeLengthSum+=codeLengths[j]=data[offset];
-var huffmanValues=new Uint8Array(codeLengthSum);
-for(j=0;j<codeLengthSum;j++,offset++)
-huffmanValues[j]=data[offset];
-i+=17+codeLengthSum;
-
-(huffmanTableSpec>>4===0?
-huffmanTablesDC:huffmanTablesAC)[huffmanTableSpec&15]=
-buildHuffmanTable(codeLengths,huffmanValues);
-}
-break;
-
-case 0xFFDD:
-readUint16();
-resetInterval=readUint16();
-break;
-
-case 0xFFDA:
-var scanLength=readUint16();
-var selectorsCount=data[offset++];
-var components=[],component;
-for(i=0;i<selectorsCount;i++){
-component=frame.components[data[offset++]];
-var tableSpec=data[offset++];
-component.huffmanTableDC=huffmanTablesDC[tableSpec>>4];
-component.huffmanTableAC=huffmanTablesAC[tableSpec&15];
-components.push(component);
-}
-var spectralStart=data[offset++];
-var spectralEnd=data[offset++];
-var successiveApproximation=data[offset++];
-var processed=decodeScan(data,offset,
-frame,components,resetInterval,
-spectralStart,spectralEnd,
-successiveApproximation>>4,successiveApproximation&15);
-offset+=processed;
-break;
-default:
-if(data[offset-3]==0xFF&&
-data[offset-2]>=0xC0&&data[offset-2]<=0xFE){
-
-
-offset-=3;
-break;
-}
-throw"unknown JPEG marker "+fileMarker.toString(16);}
-
-fileMarker=readUint16();
-}
-if(frames.length!=1)
-throw"only single frame JPEGs supported";
-
-
-for(var i=0;i<frames.length;i++){
-var cp=frames[i].components;
-for(var j in cp){
-cp[j].quantizationTable=quantizationTables[cp[j].quantizationIdx];
-delete cp[j].quantizationIdx;
-}
-}
-
-this.width=frame.samplesPerLine;
-this.height=frame.scanLines;
-this.jfif=jfif;
-this.adobe=adobe;
-this.components=[];
-for(var i=0;i<frame.componentsOrder.length;i++){
-var component=frame.components[frame.componentsOrder[i]];
-this.components.push({
-lines:buildComponentData(frame,component),
-scaleX:component.h/frame.maxH,
-scaleY:component.v/frame.maxV});
-
-}
-},
-getData:function getData(width,height){
-var scaleX=this.width/width,scaleY=this.height/height;
-
-var component1,component2,component3,component4;
-var component1Line,component2Line,component3Line,component4Line;
-var x,y;
-var offset=0;
-var Y,Cb,Cr,K,C,M,Ye,R,G,B;
-var colorTransform;
-var dataLength=width*height*this.components.length;
-var data=new Uint8Array(dataLength);
-switch(this.components.length){
-case 1:
-component1=this.components[0];
-for(y=0;y<height;y++){
-component1Line=component1.lines[0|y*component1.scaleY*scaleY];
-for(x=0;x<width;x++){
-Y=component1Line[0|x*component1.scaleX*scaleX];
-
-data[offset++]=Y;
-}
-}
-break;
-case 2:
-
-component1=this.components[0];
-component2=this.components[1];
-for(y=0;y<height;y++){
-component1Line=component1.lines[0|y*component1.scaleY*scaleY];
-component2Line=component2.lines[0|y*component2.scaleY*scaleY];
-for(x=0;x<width;x++){
-Y=component1Line[0|x*component1.scaleX*scaleX];
-data[offset++]=Y;
-Y=component2Line[0|x*component2.scaleX*scaleX];
-data[offset++]=Y;
-}
-}
-break;
-case 3:
-
-colorTransform=true;
-
-if(this.adobe&&this.adobe.transformCode)
-colorTransform=true;else
-if(typeof this.colorTransform!=='undefined')
-colorTransform=!!this.colorTransform;
-
-component1=this.components[0];
-component2=this.components[1];
-component3=this.components[2];
-for(y=0;y<height;y++){
-component1Line=component1.lines[0|y*component1.scaleY*scaleY];
-component2Line=component2.lines[0|y*component2.scaleY*scaleY];
-component3Line=component3.lines[0|y*component3.scaleY*scaleY];
-for(x=0;x<width;x++){
-if(!colorTransform){
-R=component1Line[0|x*component1.scaleX*scaleX];
-G=component2Line[0|x*component2.scaleX*scaleX];
-B=component3Line[0|x*component3.scaleX*scaleX];
-}else{
-Y=component1Line[0|x*component1.scaleX*scaleX];
-Cb=component2Line[0|x*component2.scaleX*scaleX];
-Cr=component3Line[0|x*component3.scaleX*scaleX];
-
-R=clampTo8bit(Y+1.402*(Cr-128));
-G=clampTo8bit(Y-0.3441363*(Cb-128)-0.71413636*(Cr-128));
-B=clampTo8bit(Y+1.772*(Cb-128));
-}
-
-data[offset++]=R;
-data[offset++]=G;
-data[offset++]=B;
-}
-}
-break;
-case 4:
-if(!this.adobe)
-throw'Unsupported color mode (4 components)';
-
-colorTransform=false;
-
-if(this.adobe&&this.adobe.transformCode)
-colorTransform=true;else
-if(typeof this.colorTransform!=='undefined')
-colorTransform=!!this.colorTransform;
-
-component1=this.components[0];
-component2=this.components[1];
-component3=this.components[2];
-component4=this.components[3];
-for(y=0;y<height;y++){
-component1Line=component1.lines[0|y*component1.scaleY*scaleY];
-component2Line=component2.lines[0|y*component2.scaleY*scaleY];
-component3Line=component3.lines[0|y*component3.scaleY*scaleY];
-component4Line=component4.lines[0|y*component4.scaleY*scaleY];
-for(x=0;x<width;x++){
-if(!colorTransform){
-C=component1Line[0|x*component1.scaleX*scaleX];
-M=component2Line[0|x*component2.scaleX*scaleX];
-Ye=component3Line[0|x*component3.scaleX*scaleX];
-K=component4Line[0|x*component4.scaleX*scaleX];
-}else{
-Y=component1Line[0|x*component1.scaleX*scaleX];
-Cb=component2Line[0|x*component2.scaleX*scaleX];
-Cr=component3Line[0|x*component3.scaleX*scaleX];
-K=component4Line[0|x*component4.scaleX*scaleX];
-
-C=255-clampTo8bit(Y+1.402*(Cr-128));
-M=255-clampTo8bit(Y-0.3441363*(Cb-128)-0.71413636*(Cr-128));
-Ye=255-clampTo8bit(Y+1.772*(Cb-128));
-}
-data[offset++]=255-C;
-data[offset++]=255-M;
-data[offset++]=255-Ye;
-data[offset++]=255-K;
-}
-}
-break;
-default:
-throw'Unsupported color mode';}
-
-return data;
-},
-copyToImageData:function copyToImageData(imageData){
-var width=imageData.width,height=imageData.height;
-var imageDataArray=imageData.data;
-var data=this.getData(width,height);
-var i=0,j=0,x,y;
-var Y,K,C,M,R,G,B;
-switch(this.components.length){
-case 1:
-for(y=0;y<height;y++){
-for(x=0;x<width;x++){
-Y=data[i++];
-
-imageDataArray[j++]=Y;
-imageDataArray[j++]=Y;
-imageDataArray[j++]=Y;
-imageDataArray[j++]=255;
-}
-}
-break;
-case 3:
-for(y=0;y<height;y++){
-for(x=0;x<width;x++){
-R=data[i++];
-G=data[i++];
-B=data[i++];
-
-imageDataArray[j++]=R;
-imageDataArray[j++]=G;
-imageDataArray[j++]=B;
-imageDataArray[j++]=255;
-}
-}
-break;
-case 4:
-for(y=0;y<height;y++){
-for(x=0;x<width;x++){
-C=data[i++];
-M=data[i++];
-Y=data[i++];
-K=data[i++];
-
-R=255-clampTo8bit(C*(1-K/255)+K);
-G=255-clampTo8bit(M*(1-K/255)+K);
-B=255-clampTo8bit(Y*(1-K/255)+K);
-
-imageDataArray[j++]=R;
-imageDataArray[j++]=G;
-imageDataArray[j++]=B;
-imageDataArray[j++]=255;
-}
-}
-break;
-default:
-throw'Unsupported color mode';}
-
-}};
-
-
-return constructor;
-}();
-module.exports=decode;
-
-function decode(jpegData){
-var arr=new Uint8Array(jpegData);
-var decoder=new JpegImage();
-decoder.parse(arr);
-
-var image={
-width:decoder.width,
-height:decoder.height,
-data:new Buffer(decoder.width*decoder.height*4)};
-
-
-decoder.copyToImageData(image);
-
-return image;
-}
-
-}).call(this,require("buffer").Buffer);
-},{"buffer":109}],177:[function(require,module,exports){
-(function(Buffer){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var btoa=btoa||function(buf){
-return new Buffer(buf).toString('base64');
-};
-
-function JPEGEncoder(quality){
-var self=this;
-var fround=Math.round;
-var ffloor=Math.floor;
-var YTable=new Array(64);
-var UVTable=new Array(64);
-var fdtbl_Y=new Array(64);
-var fdtbl_UV=new Array(64);
-var YDC_HT;
-var UVDC_HT;
-var YAC_HT;
-var UVAC_HT;
-
-var bitcode=new Array(65535);
-var category=new Array(65535);
-var outputfDCTQuant=new Array(64);
-var DU=new Array(64);
-var byteout=[];
-var bytenew=0;
-var bytepos=7;
-
-var YDU=new Array(64);
-var UDU=new Array(64);
-var VDU=new Array(64);
-var clt=new Array(256);
-var RGB_YUV_TABLE=new Array(2048);
-var currentQuality;
-
-var ZigZag=[
-0,1,5,6,14,15,27,28,
-2,4,7,13,16,26,29,42,
-3,8,12,17,25,30,41,43,
-9,11,18,24,31,40,44,53,
-10,19,23,32,39,45,52,54,
-20,22,33,38,46,51,55,60,
-21,34,37,47,50,56,59,61,
-35,36,48,49,57,58,62,63];
-
-
-var std_dc_luminance_nrcodes=[0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];
-var std_dc_luminance_values=[0,1,2,3,4,5,6,7,8,9,10,11];
-var std_ac_luminance_nrcodes=[0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];
-var std_ac_luminance_values=[
-0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
-0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
-0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
-0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
-0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
-0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
-0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
-0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
-0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
-0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
-0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
-0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
-0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
-0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
-0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
-0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
-0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
-0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
-0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
-0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
-0xf9,0xfa];
-
-
-var std_dc_chrominance_nrcodes=[0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];
-var std_dc_chrominance_values=[0,1,2,3,4,5,6,7,8,9,10,11];
-var std_ac_chrominance_nrcodes=[0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];
-var std_ac_chrominance_values=[
-0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
-0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
-0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
-0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
-0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
-0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
-0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
-0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
-0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
-0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
-0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
-0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
-0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
-0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
-0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
-0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
-0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
-0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
-0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
-0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
-0xf9,0xfa];
-
-
-function initQuantTables(sf){
-var YQT=[
-16,11,10,16,24,40,51,61,
-12,12,14,19,26,58,60,55,
-14,13,16,24,40,57,69,56,
-14,17,22,29,51,87,80,62,
-18,22,37,56,68,109,103,77,
-24,35,55,64,81,104,113,92,
-49,64,78,87,103,121,120,101,
-72,92,95,98,112,100,103,99];
-
-
-for(var i=0;i<64;i++){
-var t=ffloor((YQT[i]*sf+50)/100);
-if(t<1){
-t=1;
-}else if(t>255){
-t=255;
-}
-YTable[ZigZag[i]]=t;
-}
-var UVQT=[
-17,18,24,47,99,99,99,99,
-18,21,26,66,99,99,99,99,
-24,26,56,99,99,99,99,99,
-47,66,99,99,99,99,99,99,
-99,99,99,99,99,99,99,99,
-99,99,99,99,99,99,99,99,
-99,99,99,99,99,99,99,99,
-99,99,99,99,99,99,99,99];
-
-for(var j=0;j<64;j++){
-var u=ffloor((UVQT[j]*sf+50)/100);
-if(u<1){
-u=1;
-}else if(u>255){
-u=255;
-}
-UVTable[ZigZag[j]]=u;
-}
-var aasf=[
-1.0,1.387039845,1.306562965,1.175875602,
-1.0,0.785694958,0.541196100,0.275899379];
-
-var k=0;
-for(var row=0;row<8;row++)
-{
-for(var col=0;col<8;col++)
-{
-fdtbl_Y[k]=1.0/(YTable[ZigZag[k]]*aasf[row]*aasf[col]*8.0);
-fdtbl_UV[k]=1.0/(UVTable[ZigZag[k]]*aasf[row]*aasf[col]*8.0);
-k++;
-}
-}
-}
-
-function computeHuffmanTbl(nrcodes,std_table){
-var codevalue=0;
-var pos_in_table=0;
-var HT=new Array();
-for(var k=1;k<=16;k++){
-for(var j=1;j<=nrcodes[k];j++){
-HT[std_table[pos_in_table]]=[];
-HT[std_table[pos_in_table]][0]=codevalue;
-HT[std_table[pos_in_table]][1]=k;
-pos_in_table++;
-codevalue++;
-}
-codevalue*=2;
-}
-return HT;
-}
-
-function initHuffmanTbl()
-{
-YDC_HT=computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);
-UVDC_HT=computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);
-YAC_HT=computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);
-UVAC_HT=computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);
-}
-
-function initCategoryNumber()
-{
-var nrlower=1;
-var nrupper=2;
-for(var cat=1;cat<=15;cat++){
-
-for(var nr=nrlower;nr<nrupper;nr++){
-category[32767+nr]=cat;
-bitcode[32767+nr]=[];
-bitcode[32767+nr][1]=cat;
-bitcode[32767+nr][0]=nr;
-}
-
-for(var nrneg=-(nrupper-1);nrneg<=-nrlower;nrneg++){
-category[32767+nrneg]=cat;
-bitcode[32767+nrneg]=[];
-bitcode[32767+nrneg][1]=cat;
-bitcode[32767+nrneg][0]=nrupper-1+nrneg;
-}
-nrlower<<=1;
-nrupper<<=1;
-}
-}
-
-function initRGBYUVTable(){
-for(var i=0;i<256;i++){
-RGB_YUV_TABLE[i]=19595*i;
-RGB_YUV_TABLE[i+256>>0]=38470*i;
-RGB_YUV_TABLE[i+512>>0]=7471*i+0x8000;
-RGB_YUV_TABLE[i+768>>0]=-11059*i;
-RGB_YUV_TABLE[i+1024>>0]=-21709*i;
-RGB_YUV_TABLE[i+1280>>0]=32768*i+0x807FFF;
-RGB_YUV_TABLE[i+1536>>0]=-27439*i;
-RGB_YUV_TABLE[i+1792>>0]=-5329*i;
-}
-}
-
-
-function writeBits(bs)
-{
-var value=bs[0];
-var posval=bs[1]-1;
-while(posval>=0){
-if(value&1<<posval){
-bytenew|=1<<bytepos;
-}
-posval--;
-bytepos--;
-if(bytepos<0){
-if(bytenew==0xFF){
-writeByte(0xFF);
-writeByte(0);
-}else
-{
-writeByte(bytenew);
-}
-bytepos=7;
-bytenew=0;
-}
-}
-}
-
-function writeByte(value)
-{
-
-byteout.push(value);
-}
-
-function writeWord(value)
-{
-writeByte(value>>8&0xFF);
-writeByte(value&0xFF);
-}
-
-
-function fDCTQuant(data,fdtbl)
-{
-var d0,d1,d2,d3,d4,d5,d6,d7;
-
-var dataOff=0;
-var i;
-const I8=8;
-const I64=64;
-for(i=0;i<I8;++i)
-{
-d0=data[dataOff];
-d1=data[dataOff+1];
-d2=data[dataOff+2];
-d3=data[dataOff+3];
-d4=data[dataOff+4];
-d5=data[dataOff+5];
-d6=data[dataOff+6];
-d7=data[dataOff+7];
-
-var tmp0=d0+d7;
-var tmp7=d0-d7;
-var tmp1=d1+d6;
-var tmp6=d1-d6;
-var tmp2=d2+d5;
-var tmp5=d2-d5;
-var tmp3=d3+d4;
-var tmp4=d3-d4;
-
-
-var tmp10=tmp0+tmp3;
-var tmp13=tmp0-tmp3;
-var tmp11=tmp1+tmp2;
-var tmp12=tmp1-tmp2;
-
-data[dataOff]=tmp10+tmp11;
-data[dataOff+4]=tmp10-tmp11;
-
-var z1=(tmp12+tmp13)*0.707106781;
-data[dataOff+2]=tmp13+z1;
-data[dataOff+6]=tmp13-z1;
-
-
-tmp10=tmp4+tmp5;
-tmp11=tmp5+tmp6;
-tmp12=tmp6+tmp7;
-
-
-var z5=(tmp10-tmp12)*0.382683433;
-var z2=0.541196100*tmp10+z5;
-var z4=1.306562965*tmp12+z5;
-var z3=tmp11*0.707106781;
-
-var z11=tmp7+z3;
-var z13=tmp7-z3;
-
-data[dataOff+5]=z13+z2;
-data[dataOff+3]=z13-z2;
-data[dataOff+1]=z11+z4;
-data[dataOff+7]=z11-z4;
-
-dataOff+=8;
-}
-
-
-dataOff=0;
-for(i=0;i<I8;++i)
-{
-d0=data[dataOff];
-d1=data[dataOff+8];
-d2=data[dataOff+16];
-d3=data[dataOff+24];
-d4=data[dataOff+32];
-d5=data[dataOff+40];
-d6=data[dataOff+48];
-d7=data[dataOff+56];
-
-var tmp0p2=d0+d7;
-var tmp7p2=d0-d7;
-var tmp1p2=d1+d6;
-var tmp6p2=d1-d6;
-var tmp2p2=d2+d5;
-var tmp5p2=d2-d5;
-var tmp3p2=d3+d4;
-var tmp4p2=d3-d4;
-
-
-var tmp10p2=tmp0p2+tmp3p2;
-var tmp13p2=tmp0p2-tmp3p2;
-var tmp11p2=tmp1p2+tmp2p2;
-var tmp12p2=tmp1p2-tmp2p2;
-
-data[dataOff]=tmp10p2+tmp11p2;
-data[dataOff+32]=tmp10p2-tmp11p2;
-
-var z1p2=(tmp12p2+tmp13p2)*0.707106781;
-data[dataOff+16]=tmp13p2+z1p2;
-data[dataOff+48]=tmp13p2-z1p2;
-
-
-tmp10p2=tmp4p2+tmp5p2;
-tmp11p2=tmp5p2+tmp6p2;
-tmp12p2=tmp6p2+tmp7p2;
-
-
-var z5p2=(tmp10p2-tmp12p2)*0.382683433;
-var z2p2=0.541196100*tmp10p2+z5p2;
-var z4p2=1.306562965*tmp12p2+z5p2;
-var z3p2=tmp11p2*0.707106781;
-
-var z11p2=tmp7p2+z3p2;
-var z13p2=tmp7p2-z3p2;
-
-data[dataOff+40]=z13p2+z2p2;
-data[dataOff+24]=z13p2-z2p2;
-data[dataOff+8]=z11p2+z4p2;
-data[dataOff+56]=z11p2-z4p2;
-
-dataOff++;
-}
-
-
-var fDCTQuant;
-for(i=0;i<I64;++i)
-{
-
-fDCTQuant=data[i]*fdtbl[i];
-outputfDCTQuant[i]=fDCTQuant>0.0?fDCTQuant+0.5|0:fDCTQuant-0.5|0;
-
-
-}
-return outputfDCTQuant;
-}
-
-function writeAPP0()
-{
-writeWord(0xFFE0);
-writeWord(16);
-writeByte(0x4A);
-writeByte(0x46);
-writeByte(0x49);
-writeByte(0x46);
-writeByte(0);
-writeByte(1);
-writeByte(1);
-writeByte(0);
-writeWord(1);
-writeWord(1);
-writeByte(0);
-writeByte(0);
-}
-
-function writeSOF0(width,height)
-{
-writeWord(0xFFC0);
-writeWord(17);
-writeByte(8);
-writeWord(height);
-writeWord(width);
-writeByte(3);
-writeByte(1);
-writeByte(0x11);
-writeByte(0);
-writeByte(2);
-writeByte(0x11);
-writeByte(1);
-writeByte(3);
-writeByte(0x11);
-writeByte(1);
-}
-
-function writeDQT()
-{
-writeWord(0xFFDB);
-writeWord(132);
-writeByte(0);
-for(var i=0;i<64;i++){
-writeByte(YTable[i]);
-}
-writeByte(1);
-for(var j=0;j<64;j++){
-writeByte(UVTable[j]);
-}
-}
-
-function writeDHT()
-{
-writeWord(0xFFC4);
-writeWord(0x01A2);
-
-writeByte(0);
-for(var i=0;i<16;i++){
-writeByte(std_dc_luminance_nrcodes[i+1]);
-}
-for(var j=0;j<=11;j++){
-writeByte(std_dc_luminance_values[j]);
-}
-
-writeByte(0x10);
-for(var k=0;k<16;k++){
-writeByte(std_ac_luminance_nrcodes[k+1]);
-}
-for(var l=0;l<=161;l++){
-writeByte(std_ac_luminance_values[l]);
-}
-
-writeByte(1);
-for(var m=0;m<16;m++){
-writeByte(std_dc_chrominance_nrcodes[m+1]);
-}
-for(var n=0;n<=11;n++){
-writeByte(std_dc_chrominance_values[n]);
-}
-
-writeByte(0x11);
-for(var o=0;o<16;o++){
-writeByte(std_ac_chrominance_nrcodes[o+1]);
-}
-for(var p=0;p<=161;p++){
-writeByte(std_ac_chrominance_values[p]);
-}
-}
-
-function writeSOS()
-{
-writeWord(0xFFDA);
-writeWord(12);
-writeByte(3);
-writeByte(1);
-writeByte(0);
-writeByte(2);
-writeByte(0x11);
-writeByte(3);
-writeByte(0x11);
-writeByte(0);
-writeByte(0x3f);
-writeByte(0);
-}
-
-function processDU(CDU,fdtbl,DC,HTDC,HTAC){
-var EOB=HTAC[0x00];
-var M16zeroes=HTAC[0xF0];
-var pos;
-const I16=16;
-const I63=63;
-const I64=64;
-var DU_DCT=fDCTQuant(CDU,fdtbl);
-
-for(var j=0;j<I64;++j){
-DU[ZigZag[j]]=DU_DCT[j];
-}
-var Diff=DU[0]-DC;DC=DU[0];
-
-if(Diff==0){
-writeBits(HTDC[0]);
-}else{
-pos=32767+Diff;
-writeBits(HTDC[category[pos]]);
-writeBits(bitcode[pos]);
-}
-
-var end0pos=63;
-for(;end0pos>0&&DU[end0pos]==0;end0pos--){};
-
-if(end0pos==0){
-writeBits(EOB);
-return DC;
-}
-var i=1;
-var lng;
-while(i<=end0pos){
-var startpos=i;
-for(;DU[i]==0&&i<=end0pos;++i){}
-var nrzeroes=i-startpos;
-if(nrzeroes>=I16){
-lng=nrzeroes>>4;
-for(var nrmarker=1;nrmarker<=lng;++nrmarker)
-writeBits(M16zeroes);
-nrzeroes=nrzeroes&0xF;
-}
-pos=32767+DU[i];
-writeBits(HTAC[(nrzeroes<<4)+category[pos]]);
-writeBits(bitcode[pos]);
-i++;
-}
-if(end0pos!=I63){
-writeBits(EOB);
-}
-return DC;
-}
-
-function initCharLookupTable(){
-var sfcc=String.fromCharCode;
-for(var i=0;i<256;i++){
-clt[i]=sfcc(i);
-}
-}
-
-this.encode=function(image,quality)
-{
-var time_start=new Date().getTime();
-
-if(quality)setQuality(quality);
-
-
-byteout=new Array();
-bytenew=0;
-bytepos=7;
-
-
-writeWord(0xFFD8);
-writeAPP0();
-writeDQT();
-writeSOF0(image.width,image.height);
-writeDHT();
-writeSOS();
-
-
-
-var DCY=0;
-var DCU=0;
-var DCV=0;
-
-bytenew=0;
-bytepos=7;
-
-
-this.encode.displayName="_encode_";
-
-var imageData=image.data;
-var width=image.width;
-var height=image.height;
-
-var quadWidth=width*4;
-var tripleWidth=width*3;
-
-var x,y=0;
-var r,g,b;
-var start,p,col,row,pos;
-while(y<height){
-x=0;
-while(x<quadWidth){
-start=quadWidth*y+x;
-p=start;
-col=-1;
-row=0;
-
-for(pos=0;pos<64;pos++){
-row=pos>>3;
-col=(pos&7)*4;
-p=start+row*quadWidth+col;
-
-if(y+row>=height){
-p-=quadWidth*(y+1+row-height);
-}
-
-if(x+col>=quadWidth){
-p-=x+col-quadWidth+4;
-}
-
-r=imageData[p++];
-g=imageData[p++];
-b=imageData[p++];
-
-
-
-
-
-
-
-
-
-YDU[pos]=(RGB_YUV_TABLE[r]+RGB_YUV_TABLE[g+256>>0]+RGB_YUV_TABLE[b+512>>0]>>16)-128;
-UDU[pos]=(RGB_YUV_TABLE[r+768>>0]+RGB_YUV_TABLE[g+1024>>0]+RGB_YUV_TABLE[b+1280>>0]>>16)-128;
-VDU[pos]=(RGB_YUV_TABLE[r+1280>>0]+RGB_YUV_TABLE[g+1536>>0]+RGB_YUV_TABLE[b+1792>>0]>>16)-128;
-
-}
-
-DCY=processDU(YDU,fdtbl_Y,DCY,YDC_HT,YAC_HT);
-DCU=processDU(UDU,fdtbl_UV,DCU,UVDC_HT,UVAC_HT);
-DCV=processDU(VDU,fdtbl_UV,DCV,UVDC_HT,UVAC_HT);
-x+=32;
-}
-y+=8;
-}
-
-
-
-
-
-if(bytepos>=0){
-var fillbits=[];
-fillbits[1]=bytepos+1;
-fillbits[0]=(1<<bytepos+1)-1;
-writeBits(fillbits);
-}
-
-writeWord(0xFFD9);
-
-
-return new Buffer(byteout);
-
-var jpegDataUri='data:image/jpeg;base64,'+btoa(byteout.join(''));
-
-byteout=[];
-
-
-var duration=new Date().getTime()-time_start;
-
-
-
-return jpegDataUri;
-};
-
-function setQuality(quality){
-if(quality<=0){
-quality=1;
-}
-if(quality>100){
-quality=100;
-}
-
-if(currentQuality==quality)return;
-
-var sf=0;
-if(quality<50){
-sf=Math.floor(5000/quality);
-}else{
-sf=Math.floor(200-quality*2);
-}
-
-initQuantTables(sf);
-currentQuality=quality;
-
-}
-
-function init(){
-var time_start=new Date().getTime();
-if(!quality)quality=50;
-
-initCharLookupTable();
-initHuffmanTbl();
-initCategoryNumber();
-initRGBYUVTable();
-
-setQuality(quality);
-var duration=new Date().getTime()-time_start;
-
-}
-
-init();
-
-};
-module.exports=encode;
-
-function encode(imgData,qu){
-if(typeof qu==='undefined')qu=50;
-var encoder=new JPEGEncoder(qu);
-var data=encoder.encode(imgData,qu);
-return{
-data:data,
-width:imgData.width,
-height:imgData.height};
-
-}
-
-
-function getImageDataFromImage(idOrElement){
-var theImg=typeof idOrElement=='string'?document.getElementById(idOrElement):idOrElement;
-var cvs=document.createElement('canvas');
-cvs.width=theImg.width;
-cvs.height=theImg.height;
-var ctx=cvs.getContext("2d");
-ctx.drawImage(theImg,0,0);
-
-return ctx.getImageData(0,0,cvs.width,cvs.height);
-}
-
-}).call(this,require("buffer").Buffer);
-},{"buffer":109}],178:[function(require,module,exports){
-(function(global){
-
-
-
-
-
-
-
-
-
-
-var LARGE_ARRAY_SIZE=200;
-
-
-var HASH_UNDEFINED='__lodash_hash_undefined__';
-
-
-var COMPARE_PARTIAL_FLAG=1,
-COMPARE_UNORDERED_FLAG=2;
-
-
-var MAX_SAFE_INTEGER=9007199254740991;
-
-
-var argsTag='[object Arguments]',
-arrayTag='[object Array]',
-asyncTag='[object AsyncFunction]',
-boolTag='[object Boolean]',
-dateTag='[object Date]',
-errorTag='[object Error]',
-funcTag='[object Function]',
-genTag='[object GeneratorFunction]',
-mapTag='[object Map]',
-numberTag='[object Number]',
-nullTag='[object Null]',
-objectTag='[object Object]',
-promiseTag='[object Promise]',
-proxyTag='[object Proxy]',
-regexpTag='[object RegExp]',
-setTag='[object Set]',
-stringTag='[object String]',
-symbolTag='[object Symbol]',
-undefinedTag='[object Undefined]',
-weakMapTag='[object WeakMap]';
-
-var arrayBufferTag='[object ArrayBuffer]',
-dataViewTag='[object DataView]',
-float32Tag='[object Float32Array]',
-float64Tag='[object Float64Array]',
-int8Tag='[object Int8Array]',
-int16Tag='[object Int16Array]',
-int32Tag='[object Int32Array]',
-uint8Tag='[object Uint8Array]',
-uint8ClampedTag='[object Uint8ClampedArray]',
-uint16Tag='[object Uint16Array]',
-uint32Tag='[object Uint32Array]';
-
-
-
-
-
-var reRegExpChar=/[\\^$.*+?()[\]{}|]/g;
-
-
-var reIsHostCtor=/^\[object .+?Constructor\]$/;
-
-
-var reIsUint=/^(?:0|[1-9]\d*)$/;
-
-
-var typedArrayTags={};
-typedArrayTags[float32Tag]=typedArrayTags[float64Tag]=
-typedArrayTags[int8Tag]=typedArrayTags[int16Tag]=
-typedArrayTags[int32Tag]=typedArrayTags[uint8Tag]=
-typedArrayTags[uint8ClampedTag]=typedArrayTags[uint16Tag]=
-typedArrayTags[uint32Tag]=true;
-typedArrayTags[argsTag]=typedArrayTags[arrayTag]=
-typedArrayTags[arrayBufferTag]=typedArrayTags[boolTag]=
-typedArrayTags[dataViewTag]=typedArrayTags[dateTag]=
-typedArrayTags[errorTag]=typedArrayTags[funcTag]=
-typedArrayTags[mapTag]=typedArrayTags[numberTag]=
-typedArrayTags[objectTag]=typedArrayTags[regexpTag]=
-typedArrayTags[setTag]=typedArrayTags[stringTag]=
-typedArrayTags[weakMapTag]=false;
-
-
-var freeGlobal=typeof global=='object'&&global&&global.Object===Object&&global;
-
-
-var freeSelf=typeof self=='object'&&self&&self.Object===Object&&self;
-
-
-var root=freeGlobal||freeSelf||Function('return this')();
-
-
-var freeExports=typeof exports=='object'&&exports&&!exports.nodeType&&exports;
-
-
-var freeModule=freeExports&&typeof module=='object'&&module&&!module.nodeType&&module;
-
-
-var moduleExports=freeModule&&freeModule.exports===freeExports;
-
-
-var freeProcess=moduleExports&&freeGlobal.process;
-
-
-var nodeUtil=function(){
-try{
-return freeProcess&&freeProcess.binding&&freeProcess.binding('util');
-}catch(e){}
-}();
-
-
-var nodeIsTypedArray=nodeUtil&&nodeUtil.isTypedArray;
-
-
-
-
-
-
-
-
-
-
-function arrayFilter(array,predicate){
-var index=-1,
-length=array==null?0:array.length,
-resIndex=0,
-result=[];
-
-while(++index<length){
-var value=array[index];
-if(predicate(value,index,array)){
-result[resIndex++]=value;
-}
-}
-return result;
-}
-
-
-
-
-
-
-
-
-
-function arrayPush(array,values){
-var index=-1,
-length=values.length,
-offset=array.length;
-
-while(++index<length){
-array[offset+index]=values[index];
-}
-return array;
-}
-
-
-
-
-
-
-
-
-
-
-
-function arraySome(array,predicate){
-var index=-1,
-length=array==null?0:array.length;
-
-while(++index<length){
-if(predicate(array[index],index,array)){
-return true;
-}
-}
-return false;
-}
-
-
-
-
-
-
-
-
-
-
-function baseTimes(n,iteratee){
-var index=-1,
-result=Array(n);
-
-while(++index<n){
-result[index]=iteratee(index);
-}
-return result;
-}
-
-
-
-
-
-
-
-
-function baseUnary(func){
-return function(value){
-return func(value);
-};
-}
-
-
-
-
-
-
-
-
-
-function cacheHas(cache,key){
-return cache.has(key);
-}
-
-
-
-
-
-
-
-
-
-function getValue(object,key){
-return object==null?undefined:object[key];
-}
-
-
-
-
-
-
-
-
-function mapToArray(map){
-var index=-1,
-result=Array(map.size);
-
-map.forEach(function(value,key){
-result[++index]=[key,value];
-});
-return result;
-}
-
-
-
-
-
-
-
-
-
-function overArg(func,transform){
-return function(arg){
-return func(transform(arg));
-};
-}
-
-
-
-
-
-
-
-
-function setToArray(set){
-var index=-1,
-result=Array(set.size);
-
-set.forEach(function(value){
-result[++index]=value;
-});
-return result;
-}
-
-
-var arrayProto=Array.prototype,
-funcProto=Function.prototype,
-objectProto=Object.prototype;
-
-
-var coreJsData=root['__core-js_shared__'];
-
-
-var funcToString=funcProto.toString;
-
-
-var hasOwnProperty=objectProto.hasOwnProperty;
-
-
-var maskSrcKey=function(){
-var uid=/[^.]+$/.exec(coreJsData&&coreJsData.keys&&coreJsData.keys.IE_PROTO||'');
-return uid?'Symbol(src)_1.'+uid:'';
-}();
-
-
-
-
-
-
-var nativeObjectToString=objectProto.toString;
-
-
-var reIsNative=RegExp('^'+
-funcToString.call(hasOwnProperty).replace(reRegExpChar,'\\$&').
-replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,'$1.*?')+'$');
-
-
-
-var Buffer=moduleExports?root.Buffer:undefined,
-Symbol=root.Symbol,
-Uint8Array=root.Uint8Array,
-propertyIsEnumerable=objectProto.propertyIsEnumerable,
-splice=arrayProto.splice,
-symToStringTag=Symbol?Symbol.toStringTag:undefined;
-
-
-var nativeGetSymbols=Object.getOwnPropertySymbols,
-nativeIsBuffer=Buffer?Buffer.isBuffer:undefined,
-nativeKeys=overArg(Object.keys,Object);
-
-
-var DataView=getNative(root,'DataView'),
-Map=getNative(root,'Map'),
-Promise=getNative(root,'Promise'),
-Set=getNative(root,'Set'),
-WeakMap=getNative(root,'WeakMap'),
-nativeCreate=getNative(Object,'create');
-
-
-var dataViewCtorString=toSource(DataView),
-mapCtorString=toSource(Map),
-promiseCtorString=toSource(Promise),
-setCtorString=toSource(Set),
-weakMapCtorString=toSource(WeakMap);
-
-
-var symbolProto=Symbol?Symbol.prototype:undefined,
-symbolValueOf=symbolProto?symbolProto.valueOf:undefined;
-
-
-
-
-
-
-
-
-function Hash(entries){
-var index=-1,
-length=entries==null?0:entries.length;
-
-this.clear();
-while(++index<length){
-var entry=entries[index];
-this.set(entry[0],entry[1]);
-}
-}
-
-
-
-
-
-
-
-
-function hashClear(){
-this.__data__=nativeCreate?nativeCreate(null):{};
-this.size=0;
-}
-
-
-
-
-
-
-
-
-
-
-
-function hashDelete(key){
-var result=this.has(key)&&delete this.__data__[key];
-this.size-=result?1:0;
-return result;
-}
-
-
-
-
-
-
-
-
-
-
-function hashGet(key){
-var data=this.__data__;
-if(nativeCreate){
-var result=data[key];
-return result===HASH_UNDEFINED?undefined:result;
-}
-return hasOwnProperty.call(data,key)?data[key]:undefined;
-}
-
-
-
-
-
-
-
-
-
-
-function hashHas(key){
-var data=this.__data__;
-return nativeCreate?data[key]!==undefined:hasOwnProperty.call(data,key);
-}
-
-
-
-
-
-
-
-
-
-
-
-function hashSet(key,value){
-var data=this.__data__;
-this.size+=this.has(key)?0:1;
-data[key]=nativeCreate&&value===undefined?HASH_UNDEFINED:value;
-return this;
-}
-
-
-Hash.prototype.clear=hashClear;
-Hash.prototype['delete']=hashDelete;
-Hash.prototype.get=hashGet;
-Hash.prototype.has=hashHas;
-Hash.prototype.set=hashSet;
-
-
-
-
-
-
-
-
-function ListCache(entries){
-var index=-1,
-length=entries==null?0:entries.length;
-
-this.clear();
-while(++index<length){
-var entry=entries[index];
-this.set(entry[0],entry[1]);
-}
-}
-
-
-
-
-
-
-
-
-function listCacheClear(){
-this.__data__=[];
-this.size=0;
-}
-
-
-
-
-
-
-
-
-
-
-function listCacheDelete(key){
-var data=this.__data__,
-index=assocIndexOf(data,key);
-
-if(index<0){
-return false;
-}
-var lastIndex=data.length-1;
-if(index==lastIndex){
-data.pop();
-}else{
-splice.call(data,index,1);
-}
---this.size;
-return true;
-}
-
-
-
-
-
-
-
-
-
-
-function listCacheGet(key){
-var data=this.__data__,
-index=assocIndexOf(data,key);
-
-return index<0?undefined:data[index][1];
-}
-
-
-
-
-
-
-
-
-
-
-function listCacheHas(key){
-return assocIndexOf(this.__data__,key)>-1;
-}
-
-
-
-
-
-
-
-
-
-
-
-function listCacheSet(key,value){
-var data=this.__data__,
-index=assocIndexOf(data,key);
-
-if(index<0){
-++this.size;
-data.push([key,value]);
-}else{
-data[index][1]=value;
-}
-return this;
-}
-
-
-ListCache.prototype.clear=listCacheClear;
-ListCache.prototype['delete']=listCacheDelete;
-ListCache.prototype.get=listCacheGet;
-ListCache.prototype.has=listCacheHas;
-ListCache.prototype.set=listCacheSet;
-
-
-
-
-
-
-
-
-function MapCache(entries){
-var index=-1,
-length=entries==null?0:entries.length;
-
-this.clear();
-while(++index<length){
-var entry=entries[index];
-this.set(entry[0],entry[1]);
-}
-}
-
-
-
-
-
-
-
-
-function mapCacheClear(){
-this.size=0;
-this.__data__={
-'hash':new Hash(),
-'map':new(Map||ListCache)(),
-'string':new Hash()};
-
-}
-
-
-
-
-
-
-
-
-
-
-function mapCacheDelete(key){
-var result=getMapData(this,key)['delete'](key);
-this.size-=result?1:0;
-return result;
-}
-
-
-
-
-
-
-
-
-
-
-function mapCacheGet(key){
-return getMapData(this,key).get(key);
-}
-
-
-
-
-
-
-
-
-
-
-function mapCacheHas(key){
-return getMapData(this,key).has(key);
-}
-
-
-
-
-
-
-
-
-
-
-
-function mapCacheSet(key,value){
-var data=getMapData(this,key),
-size=data.size;
-
-data.set(key,value);
-this.size+=data.size==size?0:1;
-return this;
-}
-
-
-MapCache.prototype.clear=mapCacheClear;
-MapCache.prototype['delete']=mapCacheDelete;
-MapCache.prototype.get=mapCacheGet;
-MapCache.prototype.has=mapCacheHas;
-MapCache.prototype.set=mapCacheSet;
-
-
-
-
-
-
-
-
-
-function SetCache(values){
-var index=-1,
-length=values==null?0:values.length;
-
-this.__data__=new MapCache();
-while(++index<length){
-this.add(values[index]);
-}
-}
-
-
-
-
-
-
-
-
-
-
-
-function setCacheAdd(value){
-this.__data__.set(value,HASH_UNDEFINED);
-return this;
-}
-
-
-
-
-
-
-
-
-
-
-function setCacheHas(value){
-return this.__data__.has(value);
-}
-
-
-SetCache.prototype.add=SetCache.prototype.push=setCacheAdd;
-SetCache.prototype.has=setCacheHas;
-
-
-
-
-
-
-
-
-function Stack(entries){
-var data=this.__data__=new ListCache(entries);
-this.size=data.size;
-}
-
-
-
-
-
-
-
-
-function stackClear(){
-this.__data__=new ListCache();
-this.size=0;
-}
-
-
-
-
-
-
-
-
-
-
-function stackDelete(key){
-var data=this.__data__,
-result=data['delete'](key);
-
-this.size=data.size;
-return result;
-}
-
-
-
-
-
-
-
-
-
-
-function stackGet(key){
-return this.__data__.get(key);
-}
-
-
-
-
-
-
-
-
-
-
-function stackHas(key){
-return this.__data__.has(key);
-}
-
-
-
-
-
-
-
-
-
-
-
-function stackSet(key,value){
-var data=this.__data__;
-if(data instanceof ListCache){
-var pairs=data.__data__;
-if(!Map||pairs.length<LARGE_ARRAY_SIZE-1){
-pairs.push([key,value]);
-this.size=++data.size;
-return this;
-}
-data=this.__data__=new MapCache(pairs);
-}
-data.set(key,value);
-this.size=data.size;
-return this;
-}
-
-
-Stack.prototype.clear=stackClear;
-Stack.prototype['delete']=stackDelete;
-Stack.prototype.get=stackGet;
-Stack.prototype.has=stackHas;
-Stack.prototype.set=stackSet;
-
-
-
-
-
-
-
-
-
-function arrayLikeKeys(value,inherited){
-var isArr=isArray(value),
-isArg=!isArr&&isArguments(value),
-isBuff=!isArr&&!isArg&&isBuffer(value),
-isType=!isArr&&!isArg&&!isBuff&&isTypedArray(value),
-skipIndexes=isArr||isArg||isBuff||isType,
-result=skipIndexes?baseTimes(value.length,String):[],
-length=result.length;
-
-for(var key in value){
-if((inherited||hasOwnProperty.call(value,key))&&
-!(skipIndexes&&(
-
-key=='length'||
-
-isBuff&&(key=='offset'||key=='parent')||
-
-isType&&(key=='buffer'||key=='byteLength'||key=='byteOffset')||
-
-isIndex(key,length))))
-{
-result.push(key);
-}
-}
-return result;
-}
-
-
-
-
-
-
-
-
-
-function assocIndexOf(array,key){
-var length=array.length;
-while(length--){
-if(eq(array[length][0],key)){
-return length;
-}
-}
-return-1;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-function baseGetAllKeys(object,keysFunc,symbolsFunc){
-var result=keysFunc(object);
-return isArray(object)?result:arrayPush(result,symbolsFunc(object));
-}
-
-
-
-
-
-
-
-
-function baseGetTag(value){
-if(value==null){
-return value===undefined?undefinedTag:nullTag;
-}
-return symToStringTag&&symToStringTag in Object(value)?
-getRawTag(value):
-objectToString(value);
-}
-
-
-
-
-
-
-
-
-function baseIsArguments(value){
-return isObjectLike(value)&&baseGetTag(value)==argsTag;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function baseIsEqual(value,other,bitmask,customizer,stack){
-if(value===other){
-return true;
-}
-if(value==null||other==null||!isObjectLike(value)&&!isObjectLike(other)){
-return value!==value&&other!==other;
-}
-return baseIsEqualDeep(value,other,bitmask,customizer,baseIsEqual,stack);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function baseIsEqualDeep(object,other,bitmask,customizer,equalFunc,stack){
-var objIsArr=isArray(object),
-othIsArr=isArray(other),
-objTag=objIsArr?arrayTag:getTag(object),
-othTag=othIsArr?arrayTag:getTag(other);
-
-objTag=objTag==argsTag?objectTag:objTag;
-othTag=othTag==argsTag?objectTag:othTag;
-
-var objIsObj=objTag==objectTag,
-othIsObj=othTag==objectTag,
-isSameTag=objTag==othTag;
-
-if(isSameTag&&isBuffer(object)){
-if(!isBuffer(other)){
-return false;
-}
-objIsArr=true;
-objIsObj=false;
-}
-if(isSameTag&&!objIsObj){
-stack||(stack=new Stack());
-return objIsArr||isTypedArray(object)?
-equalArrays(object,other,bitmask,customizer,equalFunc,stack):
-equalByTag(object,other,objTag,bitmask,customizer,equalFunc,stack);
-}
-if(!(bitmask&COMPARE_PARTIAL_FLAG)){
-var objIsWrapped=objIsObj&&hasOwnProperty.call(object,'__wrapped__'),
-othIsWrapped=othIsObj&&hasOwnProperty.call(other,'__wrapped__');
-
-if(objIsWrapped||othIsWrapped){
-var objUnwrapped=objIsWrapped?object.value():object,
-othUnwrapped=othIsWrapped?other.value():other;
-
-stack||(stack=new Stack());
-return equalFunc(objUnwrapped,othUnwrapped,bitmask,customizer,stack);
-}
-}
-if(!isSameTag){
-return false;
-}
-stack||(stack=new Stack());
-return equalObjects(object,other,bitmask,customizer,equalFunc,stack);
-}
-
-
-
-
-
-
-
-
-
-function baseIsNative(value){
-if(!isObject(value)||isMasked(value)){
-return false;
-}
-var pattern=isFunction(value)?reIsNative:reIsHostCtor;
-return pattern.test(toSource(value));
-}
-
-
-
-
-
-
-
-
-function baseIsTypedArray(value){
-return isObjectLike(value)&&
-isLength(value.length)&&!!typedArrayTags[baseGetTag(value)];
-}
-
-
-
-
-
-
-
-
-function baseKeys(object){
-if(!isPrototype(object)){
-return nativeKeys(object);
-}
-var result=[];
-for(var key in Object(object)){
-if(hasOwnProperty.call(object,key)&&key!='constructor'){
-result.push(key);
-}
-}
-return result;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function equalArrays(array,other,bitmask,customizer,equalFunc,stack){
-var isPartial=bitmask&COMPARE_PARTIAL_FLAG,
-arrLength=array.length,
-othLength=other.length;
-
-if(arrLength!=othLength&&!(isPartial&&othLength>arrLength)){
-return false;
-}
-
-var stacked=stack.get(array);
-if(stacked&&stack.get(other)){
-return stacked==other;
-}
-var index=-1,
-result=true,
-seen=bitmask&COMPARE_UNORDERED_FLAG?new SetCache():undefined;
-
-stack.set(array,other);
-stack.set(other,array);
-
-
-while(++index<arrLength){
-var arrValue=array[index],
-othValue=other[index];
-
-if(customizer){
-var compared=isPartial?
-customizer(othValue,arrValue,index,other,array,stack):
-customizer(arrValue,othValue,index,array,other,stack);
-}
-if(compared!==undefined){
-if(compared){
-continue;
-}
-result=false;
-break;
-}
-
-if(seen){
-if(!arraySome(other,function(othValue,othIndex){
-if(!cacheHas(seen,othIndex)&&(
-arrValue===othValue||equalFunc(arrValue,othValue,bitmask,customizer,stack))){
-return seen.push(othIndex);
-}
-})){
-result=false;
-break;
-}
-}else if(!(
-arrValue===othValue||
-equalFunc(arrValue,othValue,bitmask,customizer,stack)))
-{
-result=false;
-break;
-}
-}
-stack['delete'](array);
-stack['delete'](other);
-return result;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function equalByTag(object,other,tag,bitmask,customizer,equalFunc,stack){
-switch(tag){
-case dataViewTag:
-if(object.byteLength!=other.byteLength||
-object.byteOffset!=other.byteOffset){
-return false;
-}
-object=object.buffer;
-other=other.buffer;
-
-case arrayBufferTag:
-if(object.byteLength!=other.byteLength||
-!equalFunc(new Uint8Array(object),new Uint8Array(other))){
-return false;
-}
-return true;
-
-case boolTag:
-case dateTag:
-case numberTag:
-
-
-return eq(+object,+other);
-
-case errorTag:
-return object.name==other.name&&object.message==other.message;
-
-case regexpTag:
-case stringTag:
-
-
-
-return object==other+'';
-
-case mapTag:
-var convert=mapToArray;
-
-case setTag:
-var isPartial=bitmask&COMPARE_PARTIAL_FLAG;
-convert||(convert=setToArray);
-
-if(object.size!=other.size&&!isPartial){
-return false;
-}
-
-var stacked=stack.get(object);
-if(stacked){
-return stacked==other;
-}
-bitmask|=COMPARE_UNORDERED_FLAG;
-
-
-stack.set(object,other);
-var result=equalArrays(convert(object),convert(other),bitmask,customizer,equalFunc,stack);
-stack['delete'](object);
-return result;
-
-case symbolTag:
-if(symbolValueOf){
-return symbolValueOf.call(object)==symbolValueOf.call(other);
-}}
-
-return false;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function equalObjects(object,other,bitmask,customizer,equalFunc,stack){
-var isPartial=bitmask&COMPARE_PARTIAL_FLAG,
-objProps=getAllKeys(object),
-objLength=objProps.length,
-othProps=getAllKeys(other),
-othLength=othProps.length;
-
-if(objLength!=othLength&&!isPartial){
-return false;
-}
-var index=objLength;
-while(index--){
-var key=objProps[index];
-if(!(isPartial?key in other:hasOwnProperty.call(other,key))){
-return false;
-}
-}
-
-var stacked=stack.get(object);
-if(stacked&&stack.get(other)){
-return stacked==other;
-}
-var result=true;
-stack.set(object,other);
-stack.set(other,object);
-
-var skipCtor=isPartial;
-while(++index<objLength){
-key=objProps[index];
-var objValue=object[key],
-othValue=other[key];
-
-if(customizer){
-var compared=isPartial?
-customizer(othValue,objValue,key,other,object,stack):
-customizer(objValue,othValue,key,object,other,stack);
-}
-
-if(!(compared===undefined?
-objValue===othValue||equalFunc(objValue,othValue,bitmask,customizer,stack):
-compared))
-{
-result=false;
-break;
-}
-skipCtor||(skipCtor=key=='constructor');
-}
-if(result&&!skipCtor){
-var objCtor=object.constructor,
-othCtor=other.constructor;
-
-
-if(objCtor!=othCtor&&
-'constructor'in object&&'constructor'in other&&
-!(typeof objCtor=='function'&&objCtor instanceof objCtor&&
-typeof othCtor=='function'&&othCtor instanceof othCtor)){
-result=false;
-}
-}
-stack['delete'](object);
-stack['delete'](other);
-return result;
-}
-
-
-
-
-
-
-
-
-function getAllKeys(object){
-return baseGetAllKeys(object,keys,getSymbols);
-}
-
-
-
-
-
-
-
-
-
-function getMapData(map,key){
-var data=map.__data__;
-return isKeyable(key)?
-data[typeof key=='string'?'string':'hash']:
-data.map;
-}
-
-
-
-
-
-
-
-
-
-function getNative(object,key){
-var value=getValue(object,key);
-return baseIsNative(value)?value:undefined;
-}
-
-
-
-
-
-
-
-
-function getRawTag(value){
-var isOwn=hasOwnProperty.call(value,symToStringTag),
-tag=value[symToStringTag];
-
-try{
-value[symToStringTag]=undefined;
-var unmasked=true;
-}catch(e){}
-
-var result=nativeObjectToString.call(value);
-if(unmasked){
-if(isOwn){
-value[symToStringTag]=tag;
-}else{
-delete value[symToStringTag];
-}
-}
-return result;
-}
-
-
-
-
-
-
-
-
-var getSymbols=!nativeGetSymbols?stubArray:function(object){
-if(object==null){
-return[];
-}
-object=Object(object);
-return arrayFilter(nativeGetSymbols(object),function(symbol){
-return propertyIsEnumerable.call(object,symbol);
-});
-};
-
-
-
-
-
-
-
-
-var getTag=baseGetTag;
-
-
-if(DataView&&getTag(new DataView(new ArrayBuffer(1)))!=dataViewTag||
-Map&&getTag(new Map())!=mapTag||
-Promise&&getTag(Promise.resolve())!=promiseTag||
-Set&&getTag(new Set())!=setTag||
-WeakMap&&getTag(new WeakMap())!=weakMapTag){
-getTag=function(value){
-var result=baseGetTag(value),
-Ctor=result==objectTag?value.constructor:undefined,
-ctorString=Ctor?toSource(Ctor):'';
-
-if(ctorString){
-switch(ctorString){
-case dataViewCtorString:return dataViewTag;
-case mapCtorString:return mapTag;
-case promiseCtorString:return promiseTag;
-case setCtorString:return setTag;
-case weakMapCtorString:return weakMapTag;}
-
-}
-return result;
-};
-}
-
-
-
-
-
-
-
-
-
-function isIndex(value,length){
-length=length==null?MAX_SAFE_INTEGER:length;
-return!!length&&(
-typeof value=='number'||reIsUint.test(value))&&
-value>-1&&value%1==0&&value<length;
-}
-
-
-
-
-
-
-
-
-function isKeyable(value){
-var type=typeof value;
-return type=='string'||type=='number'||type=='symbol'||type=='boolean'?
-value!=='__proto__':
-value===null;
-}
-
-
-
-
-
-
-
-
-function isMasked(func){
-return!!maskSrcKey&&maskSrcKey in func;
-}
-
-
-
-
-
-
-
-
-function isPrototype(value){
-var Ctor=value&&value.constructor,
-proto=typeof Ctor=='function'&&Ctor.prototype||objectProto;
-
-return value===proto;
-}
-
-
-
-
-
-
-
-
-function objectToString(value){
-return nativeObjectToString.call(value);
-}
-
-
-
-
-
-
-
-
-function toSource(func){
-if(func!=null){
-try{
-return funcToString.call(func);
-}catch(e){}
-try{
-return func+'';
-}catch(e){}
-}
-return'';
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function eq(value,other){
-return value===other||value!==value&&other!==other;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var isArguments=baseIsArguments(function(){return arguments;}())?baseIsArguments:function(value){
-return isObjectLike(value)&&hasOwnProperty.call(value,'callee')&&
-!propertyIsEnumerable.call(value,'callee');
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var isArray=Array.isArray;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isArrayLike(value){
-return value!=null&&isLength(value.length)&&!isFunction(value);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var isBuffer=nativeIsBuffer||stubFalse;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isEqual(value,other){
-return baseIsEqual(value,other);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isFunction(value){
-if(!isObject(value)){
-return false;
-}
-
-
-var tag=baseGetTag(value);
-return tag==funcTag||tag==genTag||tag==asyncTag||tag==proxyTag;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isLength(value){
-return typeof value=='number'&&
-value>-1&&value%1==0&&value<=MAX_SAFE_INTEGER;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isObject(value){
-var type=typeof value;
-return value!=null&&(type=='object'||type=='function');
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function isObjectLike(value){
-return value!=null&&typeof value=='object';
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var isTypedArray=nodeIsTypedArray?baseUnary(nodeIsTypedArray):baseIsTypedArray;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function keys(object){
-return isArrayLike(object)?arrayLikeKeys(object):baseKeys(object);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function stubArray(){
-return[];
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function stubFalse(){
-return false;
-}
-
-module.exports=isEqual;
-
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{}],179:[function(require,module,exports){
-
-
-
-module.exports=function lookupClosestLocale(locale,available){
-if(typeof locale==='string'&&available[locale])return locale;
-var locales=[].concat(locale||[]);
-for(var l=0,ll=locales.length;l<ll;++l){
-var current=locales[l].split('-');
-while(current.length){
-var candidate=current.join('-');
-if(available[candidate])return candidate;
-current.pop();
-}
-}
-};
-
-},{}],180:[function(require,module,exports){
-exports.getRenderingDataFromViewport=function(viewportProperties,uaDeviceWidth,uaDeviceHeight,uaMaxZoom,uaMinZoom){
-
-var vw=uaDeviceWidth/100;
-var vh=uaDeviceHeight/100;
-
-
-
-var maxZoom=null;
-var minZoom=null;
-var zoom=null;
-var minWidth=null;
-var minHeight=null;
-var maxWidth=null;
-var maxHeight=null;
-var width=null,height=null;
-var initialWidth=uaDeviceWidth;
-var initialHeight=uaDeviceHeight;
-var userZoom="zoom";
-
-if(viewportProperties["maximum-scale"]!==undefined){
-maxZoom=translateZoomProperty(viewportProperties["maximum-scale"]);
-}
-if(viewportProperties["minimum-scale"]!==undefined){
-minZoom=translateZoomProperty(viewportProperties["minimum-scale"]);
-}
-if(viewportProperties["initial-scale"]!==undefined){
-zoom=translateZoomProperty(viewportProperties["initial-scale"]);
-}
-
-
-
-
-
-
-
-if(minZoom!==null&&maxZoom===null){
-minZoom=min(uaMaxZoom,translateZoomProperty(viewportProperties["minimum-scale"]));
-}
-
-if(viewportProperties["width"]!==undefined){
-minWidth="extend-to-zoom";
-maxWidth=translateLengthProperty(viewportProperties["width"],vw,vh);
-}
-
-if(viewportProperties["height"]!==undefined){
-minHeight="extend-to-zoom";
-maxHeight=translateLengthProperty(viewportProperties["height"],vw,vh);
-}
-
-
-if(viewportProperties["user-scalable"]!==undefined){
-userZoom=viewportProperties["user-scalable"];
-if(typeof userZoom==="number"){
-if(userZoom>=1||userZoom<=-1){
-userZoom="zoom";
-}else{
-userZoom="fixed";
-}
-}else{
-switch(userZoom){
-case"yes":
-case"device-width":
-case"device-height":
-userZoom="zoom";
-break;
-case"no":
-default:
-userZoom="fixed";
-break;}
-
-}
-}
-
-
-
-if(zoom!==null&&(
-viewportProperties["width"]===undefined||width===undefined)){
-if(viewportProperties["height"]!==undefined){
-
-minWidth=null;
-maxWidth=null;
-}else{
-
-minWidth="extend-to-zoom";
-maxWidth="extend-to-zoom";
-}
-}
-
-
-
-
-
-
-if(minZoom!==null&&maxZoom!==null){
-maxZoom=max(minZoom,maxZoom);
-}
-
-
-if(zoom!==null){
-zoom=clamp(zoom,minZoom,maxZoom);
-}
-
-
-var extendZoom=zoom===null&&maxZoom===null?null:min(zoom,maxZoom);
-var extendWidth,extendHeight;
-if(extendZoom===null){
-if(maxWidth==="extend-to-zoom"){
-maxWidth=null;
-}
-if(maxHeight==="extend-to-zoom"){
-maxHeight=null;
-}
-if(minWidth==="extend-to-zoom"){
-minWidth=maxWidth;
-}
-if(minHeight==="extend-to-zoom"){
-minHeight=maxHeight;
-}
-}else{
-extendWidth=initialWidth/extendZoom;
-extendHeight=initialHeight/extendZoom;
-
-if(maxWidth==="extend-to-zoom"){
-maxWidth=extendWidth;
-}
-if(maxHeight==="extend-to-zoom"){
-maxHeight=extendHeight;
-}
-if(minWidth==="extend-to-zoom"){
-minWidth=max(extendWidth,maxWidth);
-}
-if(minHeight==="extend-to-zoom"){
-minHeight=max(extendHeight,maxHeight);
-}
-}
-
-
-if(minWidth!==null||maxWidth!==null){
-width=max(minWidth,min(maxWidth,initialWidth));
-}
-if(minHeight!==null||maxHeight!==null){
-height=max(minHeight,min(maxHeight,initialHeight));
-}
-
-
-if(width===null){
-if(height===null){
-width=initialWidth;
-}else{
-if(initialHeight!==0){
-width=Math.round(height*(initialWidth/initialHeight));
-}else{
-width=initialWidth;
-}
-}
-}
-if(height===null){
-if(initialWidth!==0){
-height=Math.round(width*(initialHeight/initialWidth));
-}else{
-height=initialHeight;
-}
-}
-
-return{zoom:zoom,width:width,height:height,userZoom:userZoom};
-};
-
-function min(a,b){
-if(a===null)return b;
-if(b===null)return a;
-return Math.min(a,b);
-}
-
-function max(a,b){
-if(a===null)return b;
-if(b===null)return a;
-return Math.max(a,b);
-}
-
-
-function translateLengthProperty(prop,vw,vh){
-
-if(typeof prop==="number"){
-if(prop>=0){
-
-return clamp(prop,1,10000);
-}else{
-return undefined;
-}
-}
-if(prop==="device-width"){
-return 100*vw;
-}
-if(prop==="device-height"){
-return 100*vh;
-}
-return 1;
-}
-
-function translateZoomProperty(prop){
-
-if(typeof prop==="number"){
-if(prop>=0){
-
-return clamp(prop,0.1,10);
-}else{
-return undefined;
-}
-}
-if(prop==="yes"){
-return 1;
-}
-if(prop==="device-width"||prop==="device-height"){
-return 10;
-}
-if(prop==="no"||prop===null){
-return 0.1;
-}
-}
-
-
-function clamp(value,minv,maxv){
-return max(min(value,maxv),minv);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-exports.parseMetaViewPortContent=function(S){
-var parsedContent={
-validProperties:{},
-unknownProperties:{},
-invalidValues:{}};
-
-var i=1;
-while(i<=S.length){
-while(i<=S.length&&RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])){
-i++;
-}
-if(i<=S.length){
-i=parseProperty(parsedContent,S,i);
-}
-}
-return parsedContent;
-};
-
-var propertyNames=["width","height","initial-scale","minimum-scale","maximum-scale","user-scalable","shrink-to-fit","viewport-fit"];
-
-function parseProperty(parsedContent,S,i){
-var start=i;
-while(i<=S.length&&!RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])){
-i++;
-}
-if(i>S.length||RegExp(',|;').test(S[i-1])){
-return i;
-}
-var propertyName=S.slice(start-1,i-1);
-while(i<=S.length&&!RegExp(',|;|=').test(S[i-1])){
-i++;
-}
-if(i>S.length||RegExp(',|;').test(S[i-1])){
-return i;
-}
-while(i<=S.length&&RegExp(' |\x0A|\x09|\0d|=').test(S[i-1])){
-i++;
-}
-if(i>S.length||RegExp(',|;').test(S[i-1])){
-return i;
-}
-start=i;
-while(i<=S.length&&!RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])){
-i++;
-}
-var propertyValue=S.slice(start-1,i-1);
-setProperty(parsedContent,propertyName,propertyValue);
-return i;
-}
-
-function setProperty(parsedContent,name,value){
-if(propertyNames.indexOf(name)>=0){
-var number=parseFloat(value);
-if(!isNaN(number)){
-parsedContent.validProperties[name]=number;
-return;
-}
-var string=value.toLowerCase();
-
-if(string==="yes"||string==="no"||string==="device-width"||string==="device-height"||
-
-
-name.toLowerCase()==='viewport-fit'&&(string==='auto'||string==='cover')){
-
-parsedContent.validProperties[name]=string;
-return;
-}
-
-parsedContent.validProperties[name]=null;
-parsedContent.invalidValues[name]=value;
-}else{
-parsedContent.unknownProperties[name]=value;
-}
-}
-
-exports.expectedValues={
-"width":["device-width","device-height","a positive number"],
-"height":["device-width","device-height","a positive number"],
-"initial-scale":["a positive number"],
-"minimum-scale":["a positive number"],
-"maximum-scale":["a positive number"],
-"user-scalable":["yes","no","0","1"],
-"shrink-to-fit":["yes","no"],
-"viewport-fit":["auto","cover"]};
-
-
-},{}],181:[function(require,module,exports){
-module.exports=function parseCacheControl(field){
-
-if(typeof field!=='string'){
-return null;
-}
-
-
-
-
-
-
-
-
-
-var regex=/(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;
-
-var header={};
-var err=field.replace(regex,function($0,$1,$2,$3){
-var value=$2||$3;
-header[$1]=value?value.toLowerCase():true;
-return'';
-});
-
-if(header['max-age']){
-try{
-var maxAge=parseInt(header['max-age'],10);
-if(isNaN(maxAge)){
-return null;
-}
-
-header['max-age']=maxAge;
-}
-catch(err){}
-}
-
-return err?null:header;
-};
-
-},{}],182:[function(require,module,exports){
-var URL=require('url').URL;
-
-
-
-
-
-
-
-
-
-
-
-function trimLine(line){
-if(!line){
-return null;
-}
-
-if(Array.isArray(line)){
-return line.map(trimLine);
-}
-
-return String(line).trim();
-}
-
-
-
-
-
-
-
-
-function removeComments(line){
-var commentStartIndex=line.indexOf('#');
-if(commentStartIndex>-1){
-return line.substr(0,commentStartIndex);
-}
-
-return line;
-}
-
-
-
-
-
-
-
-
-function splitLine(line){
-var idx=String(line).indexOf(':');
-
-if(!line||idx<0){
-return null;
-}
-
-return[line.slice(0,idx),line.slice(idx+1)];
-}
-
-
-
-
-
-
-
-
-
-function formatUserAgent(userAgent){
-var formattedUserAgent=userAgent.toLowerCase();
-
-
-var idx=formattedUserAgent.indexOf('/');
-if(idx>-1){
-formattedUserAgent=formattedUserAgent.substr(0,idx);
-}
-
-return formattedUserAgent.trim();
-}
-
-
-
-
-
-
-
-
-
-function normaliseEncoding(path){
-try{
-return urlEncodeToUpper(encodeURI(path).replace(/%25/g,'%'));
-}catch(e){
-return path;
-}
-}
-
-
-
-
-
-
-
-
-
-
-function urlEncodeToUpper(path){
-return path.replace(/%[0-9a-fA-F]{2}/g,function(match){
-return match.toUpperCase();
-});
-}
-
-
-
-
-
-
-
-
-
-
-
-function parsePattern(pattern){
-var regexSpecialChars=/[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g;
-var wildCardPattern=/\*/g;
-var endOfLinePattern=/\\\$$/;
-
-pattern=normaliseEncoding(pattern);
-
-if(pattern.indexOf('*')<0&&pattern.indexOf('$')<0){
-return pattern;
-}
-
-pattern=pattern.
-replace(regexSpecialChars,'\\$&').
-replace(wildCardPattern,'(?:.*)').
-replace(endOfLinePattern,'$');
-
-return new RegExp(pattern);
-}
-
-function parseRobots(contents,robots){
-var newlineRegex=/\r\n|\r|\n/;
-var lines=contents.
-split(newlineRegex).
-map(removeComments).
-map(splitLine).
-map(trimLine);
-
-var currentUserAgents=[];
-var isNoneUserAgentState=true;
-for(var i=0;i<lines.length;i++){
-var line=lines[i];
-
-if(!line||!line[0]){
-continue;
-}
-
-switch(line[0].toLowerCase()){
-case'user-agent':
-if(isNoneUserAgentState){
-currentUserAgents.length=0;
-}
-
-if(line[1]){
-currentUserAgents.push(formatUserAgent(line[1]));
-}
-break;
-case'disallow':
-robots.addRule(currentUserAgents,line[1],false,i+1);
-break;
-case'allow':
-robots.addRule(currentUserAgents,line[1],true,i+1);
-break;
-case'crawl-delay':
-robots.setCrawlDelay(currentUserAgents,line[1]);
-break;
-case'sitemap':
-if(line[1]){
-robots.addSitemap(line[1]);
-}
-break;
-case'host':
-if(line[1]){
-robots.setPreferredHost(line[1].toLowerCase());
-}
-break;}
-
-
-isNoneUserAgentState=line[0].toLowerCase()!=='user-agent';
-}
-}
-
-
-
-
-
-
-
-
-
-function findRule(path,rules){
-var matchingRule=null;
-
-for(var i=0;i<rules.length;i++){
-var rule=rules[i];
-
-if(typeof rule.pattern==='string'){
-if(path.indexOf(rule.pattern)!==0){
-continue;
-}
-
-
-if(!matchingRule||rule.pattern.length>matchingRule.pattern.length){
-matchingRule=rule;
-}
-
-
-}else if(rule.pattern.test(path)){
-return rule;
-}
-}
-
-return matchingRule;
-}
-
-
-
-
-
-
-
-
-
-
-function parseUrl(url){
-try{
-return new URL(url);
-}catch(e){
-return null;
-}
-}
-
-
-function Robots(url,contents){
-this._url=parseUrl(url)||{};
-this._url.port=this._url.port||80;
-
-this._rules={};
-this._sitemaps=[];
-this._preferedHost=null;
-
-parseRobots(contents||'',this);
-}
-
-
-
-
-
-
-
-
-
-
-Robots.prototype.addRule=function(userAgents,pattern,allow,lineNumber){
-var rules=this._rules;
-
-userAgents.forEach(function(userAgent){
-rules[userAgent]=rules[userAgent]||[];
-
-if(!pattern){
-return;
-}
-
-rules[userAgent].push({
-pattern:parsePattern(pattern),
-allow:allow,
-lineNumber:lineNumber});
-
-});
-};
-
-
-
-
-
-
-
-Robots.prototype.setCrawlDelay=function(userAgents,delayStr){
-var rules=this._rules;
-var delay=Number(delayStr);
-
-userAgents.forEach(function(userAgent){
-rules[userAgent]=rules[userAgent]||[];
-
-if(isNaN(delay)){
-return;
-}
-
-rules[userAgent].crawlDelay=delay;
-});
-};
-
-
-
-
-
-
-Robots.prototype.addSitemap=function(url){
-this._sitemaps.push(url);
-};
-
-
-
-
-
-
-Robots.prototype.setPreferredHost=function(url){
-this._preferedHost=url;
-};
-
-Robots.prototype._getRule=function(url,ua){
-var parsedUrl=parseUrl(url)||{};
-var userAgent=formatUserAgent(ua||'*');
-
-parsedUrl.port=parsedUrl.port||'80';
-
-
-if(parsedUrl.protocol!==this._url.protocol||
-parsedUrl.hostname!==this._url.hostname||
-parsedUrl.port!==this._url.port){
-return;
-}
-
-var rules=this._rules[userAgent]||this._rules['*']||[];
-var path=urlEncodeToUpper(parsedUrl.pathname+parsedUrl.search);
-var rule=findRule(path,rules);
-
-return rule;
-};
-
-
-
-
-
-
-
-
-
-
-
-Robots.prototype.isAllowed=function(url,ua){
-var rule=this._getRule(url,ua);
-
-if(typeof rule==='undefined'){
-return;
-}
-
-return!rule||rule.allow;
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Robots.prototype.getMatchingLineNumber=function(url,ua){
-var rule=this._getRule(url,ua);
-
-return rule?rule.lineNumber:-1;
-};
-
-
-
-
-
-
-
-
-Robots.prototype.isDisallowed=function(url,ua){
-return!this.isAllowed(url,ua);
-};
-
-
-
-
-
-
-
-
-
-Robots.prototype.getCrawlDelay=function(ua){
-var userAgent=formatUserAgent(ua||'*');
-
-return(this._rules[userAgent]||this._rules['*']||{}).crawlDelay;
-};
-
-
-
-
-
-
-Robots.prototype.getPreferredHost=function(){
-return this._preferedHost;
-};
-
-
-
-
-
-
-Robots.prototype.getSitemaps=function(){
-return this._sitemaps.slice(0);
-};
-
-module.exports=Robots;
-
-},{"url":"url"}],183:[function(require,module,exports){
-var Robots=require('./Robots');
-
-module.exports=function(url,contents){
-return new Robots(url,contents);
-};
-},{"./Robots":182}],184:[function(require,module,exports){
-(function(process){
-exports=module.exports=SemVer;
-
-
-var debug;
-if(typeof process==='object'&&
-process.env&&
-process.env.NODE_DEBUG&&
-/\bsemver\b/i.test(process.env.NODE_DEBUG))
-debug=function(){
-var args=Array.prototype.slice.call(arguments,0);
-args.unshift('SEMVER');
-console.log.apply(console,args);
-};else
-
-debug=function(){};
-
-
-
-exports.SEMVER_SPEC_VERSION='2.0.0';
-
-var MAX_LENGTH=256;
-var MAX_SAFE_INTEGER=Number.MAX_SAFE_INTEGER||9007199254740991;
-
-
-var re=exports.re=[];
-var src=exports.src=[];
-var R=0;
-
-
-
-
-
-
-
-var NUMERICIDENTIFIER=R++;
-src[NUMERICIDENTIFIER]='0|[1-9]\\d*';
-var NUMERICIDENTIFIERLOOSE=R++;
-src[NUMERICIDENTIFIERLOOSE]='[0-9]+';
-
-
-
-
-
-
-var NONNUMERICIDENTIFIER=R++;
-src[NONNUMERICIDENTIFIER]='\\d*[a-zA-Z-][a-zA-Z0-9-]*';
-
-
-
-
-
-var MAINVERSION=R++;
-src[MAINVERSION]='('+src[NUMERICIDENTIFIER]+')\\.'+
-'('+src[NUMERICIDENTIFIER]+')\\.'+
-'('+src[NUMERICIDENTIFIER]+')';
-
-var MAINVERSIONLOOSE=R++;
-src[MAINVERSIONLOOSE]='('+src[NUMERICIDENTIFIERLOOSE]+')\\.'+
-'('+src[NUMERICIDENTIFIERLOOSE]+')\\.'+
-'('+src[NUMERICIDENTIFIERLOOSE]+')';
-
-
-
-
-var PRERELEASEIDENTIFIER=R++;
-src[PRERELEASEIDENTIFIER]='(?:'+src[NUMERICIDENTIFIER]+
-'|'+src[NONNUMERICIDENTIFIER]+')';
-
-var PRERELEASEIDENTIFIERLOOSE=R++;
-src[PRERELEASEIDENTIFIERLOOSE]='(?:'+src[NUMERICIDENTIFIERLOOSE]+
-'|'+src[NONNUMERICIDENTIFIER]+')';
-
-
-
-
-
-
-var PRERELEASE=R++;
-src[PRERELEASE]='(?:-('+src[PRERELEASEIDENTIFIER]+
-'(?:\\.'+src[PRERELEASEIDENTIFIER]+')*))';
-
-var PRERELEASELOOSE=R++;
-src[PRERELEASELOOSE]='(?:-?('+src[PRERELEASEIDENTIFIERLOOSE]+
-'(?:\\.'+src[PRERELEASEIDENTIFIERLOOSE]+')*))';
-
-
-
-
-var BUILDIDENTIFIER=R++;
-src[BUILDIDENTIFIER]='[0-9A-Za-z-]+';
-
-
-
-
-
-var BUILD=R++;
-src[BUILD]='(?:\\+('+src[BUILDIDENTIFIER]+
-'(?:\\.'+src[BUILDIDENTIFIER]+')*))';
-
-
-
-
-
-
-
-
-
-
-
-var FULL=R++;
-var FULLPLAIN='v?'+src[MAINVERSION]+
-src[PRERELEASE]+'?'+
-src[BUILD]+'?';
-
-src[FULL]='^'+FULLPLAIN+'$';
-
-
-
-
-var LOOSEPLAIN='[v=\\s]*'+src[MAINVERSIONLOOSE]+
-src[PRERELEASELOOSE]+'?'+
-src[BUILD]+'?';
-
-var LOOSE=R++;
-src[LOOSE]='^'+LOOSEPLAIN+'$';
-
-var GTLT=R++;
-src[GTLT]='((?:<|>)?=?)';
-
-
-
-
-var XRANGEIDENTIFIERLOOSE=R++;
-src[XRANGEIDENTIFIERLOOSE]=src[NUMERICIDENTIFIERLOOSE]+'|x|X|\\*';
-var XRANGEIDENTIFIER=R++;
-src[XRANGEIDENTIFIER]=src[NUMERICIDENTIFIER]+'|x|X|\\*';
-
-var XRANGEPLAIN=R++;
-src[XRANGEPLAIN]='[v=\\s]*('+src[XRANGEIDENTIFIER]+')'+
-'(?:\\.('+src[XRANGEIDENTIFIER]+')'+
-'(?:\\.('+src[XRANGEIDENTIFIER]+')'+
-'(?:'+src[PRERELEASE]+')?'+
-src[BUILD]+'?'+
-')?)?';
-
-var XRANGEPLAINLOOSE=R++;
-src[XRANGEPLAINLOOSE]='[v=\\s]*('+src[XRANGEIDENTIFIERLOOSE]+')'+
-'(?:\\.('+src[XRANGEIDENTIFIERLOOSE]+')'+
-'(?:\\.('+src[XRANGEIDENTIFIERLOOSE]+')'+
-'(?:'+src[PRERELEASELOOSE]+')?'+
-src[BUILD]+'?'+
-')?)?';
-
-var XRANGE=R++;
-src[XRANGE]='^'+src[GTLT]+'\\s*'+src[XRANGEPLAIN]+'$';
-var XRANGELOOSE=R++;
-src[XRANGELOOSE]='^'+src[GTLT]+'\\s*'+src[XRANGEPLAINLOOSE]+'$';
-
-
-
-var LONETILDE=R++;
-src[LONETILDE]='(?:~>?)';
-
-var TILDETRIM=R++;
-src[TILDETRIM]='(\\s*)'+src[LONETILDE]+'\\s+';
-re[TILDETRIM]=new RegExp(src[TILDETRIM],'g');
-var tildeTrimReplace='$1~';
-
-var TILDE=R++;
-src[TILDE]='^'+src[LONETILDE]+src[XRANGEPLAIN]+'$';
-var TILDELOOSE=R++;
-src[TILDELOOSE]='^'+src[LONETILDE]+src[XRANGEPLAINLOOSE]+'$';
-
-
-
-var LONECARET=R++;
-src[LONECARET]='(?:\\^)';
-
-var CARETTRIM=R++;
-src[CARETTRIM]='(\\s*)'+src[LONECARET]+'\\s+';
-re[CARETTRIM]=new RegExp(src[CARETTRIM],'g');
-var caretTrimReplace='$1^';
-
-var CARET=R++;
-src[CARET]='^'+src[LONECARET]+src[XRANGEPLAIN]+'$';
-var CARETLOOSE=R++;
-src[CARETLOOSE]='^'+src[LONECARET]+src[XRANGEPLAINLOOSE]+'$';
-
-
-var COMPARATORLOOSE=R++;
-src[COMPARATORLOOSE]='^'+src[GTLT]+'\\s*('+LOOSEPLAIN+')$|^$';
-var COMPARATOR=R++;
-src[COMPARATOR]='^'+src[GTLT]+'\\s*('+FULLPLAIN+')$|^$';
-
-
-
-
-var COMPARATORTRIM=R++;
-src[COMPARATORTRIM]='(\\s*)'+src[GTLT]+
-'\\s*('+LOOSEPLAIN+'|'+src[XRANGEPLAIN]+')';
-
-
-re[COMPARATORTRIM]=new RegExp(src[COMPARATORTRIM],'g');
-var comparatorTrimReplace='$1$2$3';
-
-
-
-
-
-
-var HYPHENRANGE=R++;
-src[HYPHENRANGE]='^\\s*('+src[XRANGEPLAIN]+')'+
-'\\s+-\\s+'+
-'('+src[XRANGEPLAIN]+')'+
-'\\s*$';
-
-var HYPHENRANGELOOSE=R++;
-src[HYPHENRANGELOOSE]='^\\s*('+src[XRANGEPLAINLOOSE]+')'+
-'\\s+-\\s+'+
-'('+src[XRANGEPLAINLOOSE]+')'+
-'\\s*$';
-
-
-var STAR=R++;
-src[STAR]='(<|>)?=?\\s*\\*';
-
-
-
-for(var i=0;i<R;i++){
-debug(i,src[i]);
-if(!re[i])
-re[i]=new RegExp(src[i]);
-}
-
-exports.parse=parse;
-function parse(version,loose){
-if(version instanceof SemVer)
-return version;
-
-if(typeof version!=='string')
-return null;
-
-if(version.length>MAX_LENGTH)
-return null;
-
-var r=loose?re[LOOSE]:re[FULL];
-if(!r.test(version))
-return null;
-
-try{
-return new SemVer(version,loose);
-}catch(er){
-return null;
-}
-}
-
-exports.valid=valid;
-function valid(version,loose){
-var v=parse(version,loose);
-return v?v.version:null;
-}
-
-
-exports.clean=clean;
-function clean(version,loose){
-var s=parse(version.trim().replace(/^[=v]+/,''),loose);
-return s?s.version:null;
-}
-
-exports.SemVer=SemVer;
-
-function SemVer(version,loose){
-if(version instanceof SemVer){
-if(version.loose===loose)
-return version;else
-
-version=version.version;
-}else if(typeof version!=='string'){
-throw new TypeError('Invalid Version: '+version);
-}
-
-if(version.length>MAX_LENGTH)
-throw new TypeError('version is longer than '+MAX_LENGTH+' characters');
-
-if(!(this instanceof SemVer))
-return new SemVer(version,loose);
-
-debug('SemVer',version,loose);
-this.loose=loose;
-var m=version.trim().match(loose?re[LOOSE]:re[FULL]);
-
-if(!m)
-throw new TypeError('Invalid Version: '+version);
-
-this.raw=version;
-
-
-this.major=+m[1];
-this.minor=+m[2];
-this.patch=+m[3];
-
-if(this.major>MAX_SAFE_INTEGER||this.major<0)
-throw new TypeError('Invalid major version');
-
-if(this.minor>MAX_SAFE_INTEGER||this.minor<0)
-throw new TypeError('Invalid minor version');
-
-if(this.patch>MAX_SAFE_INTEGER||this.patch<0)
-throw new TypeError('Invalid patch version');
-
-
-if(!m[4])
-this.prerelease=[];else
-
-this.prerelease=m[4].split('.').map(function(id){
-if(/^[0-9]+$/.test(id)){
-var num=+id;
-if(num>=0&&num<MAX_SAFE_INTEGER)
-return num;
-}
-return id;
-});
-
-this.build=m[5]?m[5].split('.'):[];
-this.format();
-}
-
-SemVer.prototype.format=function(){
-this.version=this.major+'.'+this.minor+'.'+this.patch;
-if(this.prerelease.length)
-this.version+='-'+this.prerelease.join('.');
-return this.version;
-};
-
-SemVer.prototype.toString=function(){
-return this.version;
-};
-
-SemVer.prototype.compare=function(other){
-debug('SemVer.compare',this.version,this.loose,other);
-if(!(other instanceof SemVer))
-other=new SemVer(other,this.loose);
-
-return this.compareMain(other)||this.comparePre(other);
-};
-
-SemVer.prototype.compareMain=function(other){
-if(!(other instanceof SemVer))
-other=new SemVer(other,this.loose);
-
-return compareIdentifiers(this.major,other.major)||
-compareIdentifiers(this.minor,other.minor)||
-compareIdentifiers(this.patch,other.patch);
-};
-
-SemVer.prototype.comparePre=function(other){
-if(!(other instanceof SemVer))
-other=new SemVer(other,this.loose);
-
-
-if(this.prerelease.length&&!other.prerelease.length)
-return-1;else
-if(!this.prerelease.length&&other.prerelease.length)
-return 1;else
-if(!this.prerelease.length&&!other.prerelease.length)
-return 0;
-
-var i=0;
-do{
-var a=this.prerelease[i];
-var b=other.prerelease[i];
-debug('prerelease compare',i,a,b);
-if(a===undefined&&b===undefined)
-return 0;else
-if(b===undefined)
-return 1;else
-if(a===undefined)
-return-1;else
-if(a===b)
-continue;else
-
-return compareIdentifiers(a,b);
-}while(++i);
-};
-
-
-
-SemVer.prototype.inc=function(release,identifier){
-switch(release){
-case'premajor':
-this.prerelease.length=0;
-this.patch=0;
-this.minor=0;
-this.major++;
-this.inc('pre',identifier);
-break;
-case'preminor':
-this.prerelease.length=0;
-this.patch=0;
-this.minor++;
-this.inc('pre',identifier);
-break;
-case'prepatch':
-
-
-
-this.prerelease.length=0;
-this.inc('patch',identifier);
-this.inc('pre',identifier);
-break;
-
-
-case'prerelease':
-if(this.prerelease.length===0)
-this.inc('patch',identifier);
-this.inc('pre',identifier);
-break;
-
-case'major':
-
-
-
-
-if(this.minor!==0||this.patch!==0||this.prerelease.length===0)
-this.major++;
-this.minor=0;
-this.patch=0;
-this.prerelease=[];
-break;
-case'minor':
-
-
-
-
-if(this.patch!==0||this.prerelease.length===0)
-this.minor++;
-this.patch=0;
-this.prerelease=[];
-break;
-case'patch':
-
-
-
-
-if(this.prerelease.length===0)
-this.patch++;
-this.prerelease=[];
-break;
-
-
-case'pre':
-if(this.prerelease.length===0)
-this.prerelease=[0];else
-{
-var i=this.prerelease.length;
-while(--i>=0){
-if(typeof this.prerelease[i]==='number'){
-this.prerelease[i]++;
-i=-2;
-}
-}
-if(i===-1)
-this.prerelease.push(0);
-}
-if(identifier){
-
-
-if(this.prerelease[0]===identifier){
-if(isNaN(this.prerelease[1]))
-this.prerelease=[identifier,0];
-}else
-this.prerelease=[identifier,0];
-}
-break;
-
-default:
-throw new Error('invalid increment argument: '+release);}
-
-this.format();
-this.raw=this.version;
-return this;
-};
-
-exports.inc=inc;
-function inc(version,release,loose,identifier){
-if(typeof loose==='string'){
-identifier=loose;
-loose=undefined;
-}
-
-try{
-return new SemVer(version,loose).inc(release,identifier).version;
-}catch(er){
-return null;
-}
-}
-
-exports.diff=diff;
-function diff(version1,version2){
-if(eq(version1,version2)){
-return null;
-}else{
-var v1=parse(version1);
-var v2=parse(version2);
-if(v1.prerelease.length||v2.prerelease.length){
-for(var key in v1){
-if(key==='major'||key==='minor'||key==='patch'){
-if(v1[key]!==v2[key]){
-return'pre'+key;
-}
-}
-}
-return'prerelease';
-}
-for(var key in v1){
-if(key==='major'||key==='minor'||key==='patch'){
-if(v1[key]!==v2[key]){
-return key;
-}
-}
-}
-}
-}
-
-exports.compareIdentifiers=compareIdentifiers;
-
-var numeric=/^[0-9]+$/;
-function compareIdentifiers(a,b){
-var anum=numeric.test(a);
-var bnum=numeric.test(b);
-
-if(anum&&bnum){
-a=+a;
-b=+b;
-}
-
-return anum&&!bnum?-1:
-bnum&&!anum?1:
-a<b?-1:
-a>b?1:
-0;
-}
-
-exports.rcompareIdentifiers=rcompareIdentifiers;
-function rcompareIdentifiers(a,b){
-return compareIdentifiers(b,a);
-}
-
-exports.major=major;
-function major(a,loose){
-return new SemVer(a,loose).major;
-}
-
-exports.minor=minor;
-function minor(a,loose){
-return new SemVer(a,loose).minor;
-}
-
-exports.patch=patch;
-function patch(a,loose){
-return new SemVer(a,loose).patch;
-}
-
-exports.compare=compare;
-function compare(a,b,loose){
-return new SemVer(a,loose).compare(b);
-}
-
-exports.compareLoose=compareLoose;
-function compareLoose(a,b){
-return compare(a,b,true);
-}
-
-exports.rcompare=rcompare;
-function rcompare(a,b,loose){
-return compare(b,a,loose);
-}
-
-exports.sort=sort;
-function sort(list,loose){
-return list.sort(function(a,b){
-return exports.compare(a,b,loose);
-});
-}
-
-exports.rsort=rsort;
-function rsort(list,loose){
-return list.sort(function(a,b){
-return exports.rcompare(a,b,loose);
-});
-}
-
-exports.gt=gt;
-function gt(a,b,loose){
-return compare(a,b,loose)>0;
-}
-
-exports.lt=lt;
-function lt(a,b,loose){
-return compare(a,b,loose)<0;
-}
-
-exports.eq=eq;
-function eq(a,b,loose){
-return compare(a,b,loose)===0;
-}
-
-exports.neq=neq;
-function neq(a,b,loose){
-return compare(a,b,loose)!==0;
-}
-
-exports.gte=gte;
-function gte(a,b,loose){
-return compare(a,b,loose)>=0;
-}
-
-exports.lte=lte;
-function lte(a,b,loose){
-return compare(a,b,loose)<=0;
-}
-
-exports.cmp=cmp;
-function cmp(a,op,b,loose){
-var ret;
-switch(op){
-case'===':
-if(typeof a==='object')a=a.version;
-if(typeof b==='object')b=b.version;
-ret=a===b;
-break;
-case'!==':
-if(typeof a==='object')a=a.version;
-if(typeof b==='object')b=b.version;
-ret=a!==b;
-break;
-case'':case'=':case'==':ret=eq(a,b,loose);break;
-case'!=':ret=neq(a,b,loose);break;
-case'>':ret=gt(a,b,loose);break;
-case'>=':ret=gte(a,b,loose);break;
-case'<':ret=lt(a,b,loose);break;
-case'<=':ret=lte(a,b,loose);break;
-default:throw new TypeError('Invalid operator: '+op);}
-
-return ret;
-}
-
-exports.Comparator=Comparator;
-function Comparator(comp,loose){
-if(comp instanceof Comparator){
-if(comp.loose===loose)
-return comp;else
-
-comp=comp.value;
-}
-
-if(!(this instanceof Comparator))
-return new Comparator(comp,loose);
-
-debug('comparator',comp,loose);
-this.loose=loose;
-this.parse(comp);
-
-if(this.semver===ANY)
-this.value='';else
-
-this.value=this.operator+this.semver.version;
-
-debug('comp',this);
-}
-
-var ANY={};
-Comparator.prototype.parse=function(comp){
-var r=this.loose?re[COMPARATORLOOSE]:re[COMPARATOR];
-var m=comp.match(r);
-
-if(!m)
-throw new TypeError('Invalid comparator: '+comp);
-
-this.operator=m[1];
-if(this.operator==='=')
-this.operator='';
-
-
-if(!m[2])
-this.semver=ANY;else
-
-this.semver=new SemVer(m[2],this.loose);
-};
-
-Comparator.prototype.toString=function(){
-return this.value;
-};
-
-Comparator.prototype.test=function(version){
-debug('Comparator.test',version,this.loose);
-
-if(this.semver===ANY)
-return true;
-
-if(typeof version==='string')
-version=new SemVer(version,this.loose);
-
-return cmp(version,this.operator,this.semver,this.loose);
-};
-
-
-exports.Range=Range;
-function Range(range,loose){
-if(range instanceof Range&&range.loose===loose)
-return range;
-
-if(!(this instanceof Range))
-return new Range(range,loose);
-
-this.loose=loose;
-
-
-this.raw=range;
-this.set=range.split(/\s*\|\|\s*/).map(function(range){
-return this.parseRange(range.trim());
-},this).filter(function(c){
-
-return c.length;
-});
-
-if(!this.set.length){
-throw new TypeError('Invalid SemVer Range: '+range);
-}
-
-this.format();
-}
-
-Range.prototype.format=function(){
-this.range=this.set.map(function(comps){
-return comps.join(' ').trim();
-}).join('||').trim();
-return this.range;
-};
-
-Range.prototype.toString=function(){
-return this.range;
-};
-
-Range.prototype.parseRange=function(range){
-var loose=this.loose;
-range=range.trim();
-debug('range',range,loose);
-
-var hr=loose?re[HYPHENRANGELOOSE]:re[HYPHENRANGE];
-range=range.replace(hr,hyphenReplace);
-debug('hyphen replace',range);
-
-range=range.replace(re[COMPARATORTRIM],comparatorTrimReplace);
-debug('comparator trim',range,re[COMPARATORTRIM]);
-
-
-range=range.replace(re[TILDETRIM],tildeTrimReplace);
-
-
-range=range.replace(re[CARETTRIM],caretTrimReplace);
-
-
-range=range.split(/\s+/).join(' ');
-
-
-
-
-var compRe=loose?re[COMPARATORLOOSE]:re[COMPARATOR];
-var set=range.split(' ').map(function(comp){
-return parseComparator(comp,loose);
-}).join(' ').split(/\s+/);
-if(this.loose){
-
-set=set.filter(function(comp){
-return!!comp.match(compRe);
-});
-}
-set=set.map(function(comp){
-return new Comparator(comp,loose);
-});
-
-return set;
-};
-
-
-exports.toComparators=toComparators;
-function toComparators(range,loose){
-return new Range(range,loose).set.map(function(comp){
-return comp.map(function(c){
-return c.value;
-}).join(' ').trim().split(' ');
-});
-}
-
-
-
-
-function parseComparator(comp,loose){
-debug('comp',comp);
-comp=replaceCarets(comp,loose);
-debug('caret',comp);
-comp=replaceTildes(comp,loose);
-debug('tildes',comp);
-comp=replaceXRanges(comp,loose);
-debug('xrange',comp);
-comp=replaceStars(comp,loose);
-debug('stars',comp);
-return comp;
-}
-
-function isX(id){
-return!id||id.toLowerCase()==='x'||id==='*';
-}
-
-
-
-
-
-
-
-function replaceTildes(comp,loose){
-return comp.trim().split(/\s+/).map(function(comp){
-return replaceTilde(comp,loose);
-}).join(' ');
-}
-
-function replaceTilde(comp,loose){
-var r=loose?re[TILDELOOSE]:re[TILDE];
-return comp.replace(r,function(_,M,m,p,pr){
-debug('tilde',comp,_,M,m,p,pr);
-var ret;
-
-if(isX(M))
-ret='';else
-if(isX(m))
-ret='>='+M+'.0.0 <'+(+M+1)+'.0.0';else
-if(isX(p))
-
-ret='>='+M+'.'+m+'.0 <'+M+'.'+(+m+1)+'.0';else
-if(pr){
-debug('replaceTilde pr',pr);
-if(pr.charAt(0)!=='-')
-pr='-'+pr;
-ret='>='+M+'.'+m+'.'+p+pr+
-' <'+M+'.'+(+m+1)+'.0';
-}else
-
-ret='>='+M+'.'+m+'.'+p+
-' <'+M+'.'+(+m+1)+'.0';
-
-debug('tilde return',ret);
-return ret;
-});
-}
-
-
-
-
-
-
-
-function replaceCarets(comp,loose){
-return comp.trim().split(/\s+/).map(function(comp){
-return replaceCaret(comp,loose);
-}).join(' ');
-}
-
-function replaceCaret(comp,loose){
-debug('caret',comp,loose);
-var r=loose?re[CARETLOOSE]:re[CARET];
-return comp.replace(r,function(_,M,m,p,pr){
-debug('caret',comp,_,M,m,p,pr);
-var ret;
-
-if(isX(M))
-ret='';else
-if(isX(m))
-ret='>='+M+'.0.0 <'+(+M+1)+'.0.0';else
-if(isX(p)){
-if(M==='0')
-ret='>='+M+'.'+m+'.0 <'+M+'.'+(+m+1)+'.0';else
-
-ret='>='+M+'.'+m+'.0 <'+(+M+1)+'.0.0';
-}else if(pr){
-debug('replaceCaret pr',pr);
-if(pr.charAt(0)!=='-')
-pr='-'+pr;
-if(M==='0'){
-if(m==='0')
-ret='>='+M+'.'+m+'.'+p+pr+
-' <'+M+'.'+m+'.'+(+p+1);else
-
-ret='>='+M+'.'+m+'.'+p+pr+
-' <'+M+'.'+(+m+1)+'.0';
-}else
-ret='>='+M+'.'+m+'.'+p+pr+
-' <'+(+M+1)+'.0.0';
-}else{
-debug('no pr');
-if(M==='0'){
-if(m==='0')
-ret='>='+M+'.'+m+'.'+p+
-' <'+M+'.'+m+'.'+(+p+1);else
-
-ret='>='+M+'.'+m+'.'+p+
-' <'+M+'.'+(+m+1)+'.0';
-}else
-ret='>='+M+'.'+m+'.'+p+
-' <'+(+M+1)+'.0.0';
-}
-
-debug('caret return',ret);
-return ret;
-});
-}
-
-function replaceXRanges(comp,loose){
-debug('replaceXRanges',comp,loose);
-return comp.split(/\s+/).map(function(comp){
-return replaceXRange(comp,loose);
-}).join(' ');
-}
-
-function replaceXRange(comp,loose){
-comp=comp.trim();
-var r=loose?re[XRANGELOOSE]:re[XRANGE];
-return comp.replace(r,function(ret,gtlt,M,m,p,pr){
-debug('xRange',comp,ret,gtlt,M,m,p,pr);
-var xM=isX(M);
-var xm=xM||isX(m);
-var xp=xm||isX(p);
-var anyX=xp;
-
-if(gtlt==='='&&anyX)
-gtlt='';
-
-if(xM){
-if(gtlt==='>'||gtlt==='<'){
-
-ret='<0.0.0';
-}else{
-
-ret='*';
-}
-}else if(gtlt&&anyX){
-
-if(xm)
-m=0;
-if(xp)
-p=0;
-
-if(gtlt==='>'){
-
-
-
-gtlt='>=';
-if(xm){
-M=+M+1;
-m=0;
-p=0;
-}else if(xp){
-m=+m+1;
-p=0;
-}
-}else if(gtlt==='<='){
-
-
-gtlt='<';
-if(xm)
-M=+M+1;else
-
-m=+m+1;
-}
-
-ret=gtlt+M+'.'+m+'.'+p;
-}else if(xm){
-ret='>='+M+'.0.0 <'+(+M+1)+'.0.0';
-}else if(xp){
-ret='>='+M+'.'+m+'.0 <'+M+'.'+(+m+1)+'.0';
-}
-
-debug('xRange return',ret);
-
-return ret;
-});
-}
-
-
-
-function replaceStars(comp,loose){
-debug('replaceStars',comp,loose);
-
-return comp.trim().replace(re[STAR],'');
-}
-
-
-
-
-
-
-function hyphenReplace($0,
-from,fM,fm,fp,fpr,fb,
-to,tM,tm,tp,tpr,tb){
-
-if(isX(fM))
-from='';else
-if(isX(fm))
-from='>='+fM+'.0.0';else
-if(isX(fp))
-from='>='+fM+'.'+fm+'.0';else
-
-from='>='+from;
-
-if(isX(tM))
-to='';else
-if(isX(tm))
-to='<'+(+tM+1)+'.0.0';else
-if(isX(tp))
-to='<'+tM+'.'+(+tm+1)+'.0';else
-if(tpr)
-to='<='+tM+'.'+tm+'.'+tp+'-'+tpr;else
-
-to='<='+to;
-
-return(from+' '+to).trim();
-}
-
-
-
-Range.prototype.test=function(version){
-if(!version)
-return false;
-
-if(typeof version==='string')
-version=new SemVer(version,this.loose);
-
-for(var i=0;i<this.set.length;i++){
-if(testSet(this.set[i],version))
-return true;
-}
-return false;
-};
-
-function testSet(set,version){
-for(var i=0;i<set.length;i++){
-if(!set[i].test(version))
-return false;
-}
-
-if(version.prerelease.length){
-
-
-
-
-
-for(var i=0;i<set.length;i++){
-debug(set[i].semver);
-if(set[i].semver===ANY)
-continue;
-
-if(set[i].semver.prerelease.length>0){
-var allowed=set[i].semver;
-if(allowed.major===version.major&&
-allowed.minor===version.minor&&
-allowed.patch===version.patch)
-return true;
-}
-}
-
-
-return false;
-}
-
-return true;
-}
-
-exports.satisfies=satisfies;
-function satisfies(version,range,loose){
-try{
-range=new Range(range,loose);
-}catch(er){
-return false;
-}
-return range.test(version);
-}
-
-exports.maxSatisfying=maxSatisfying;
-function maxSatisfying(versions,range,loose){
-return versions.filter(function(version){
-return satisfies(version,range,loose);
-}).sort(function(a,b){
-return rcompare(a,b,loose);
-})[0]||null;
-}
-
-exports.minSatisfying=minSatisfying;
-function minSatisfying(versions,range,loose){
-return versions.filter(function(version){
-return satisfies(version,range,loose);
-}).sort(function(a,b){
-return compare(a,b,loose);
-})[0]||null;
-}
-
-exports.validRange=validRange;
-function validRange(range,loose){
-try{
-
-
-return new Range(range,loose).range||'*';
-}catch(er){
-return null;
-}
-}
-
-
-exports.ltr=ltr;
-function ltr(version,range,loose){
-return outside(version,range,'<',loose);
-}
-
-
-exports.gtr=gtr;
-function gtr(version,range,loose){
-return outside(version,range,'>',loose);
-}
-
-exports.outside=outside;
-function outside(version,range,hilo,loose){
-version=new SemVer(version,loose);
-range=new Range(range,loose);
-
-var gtfn,ltefn,ltfn,comp,ecomp;
-switch(hilo){
-case'>':
-gtfn=gt;
-ltefn=lte;
-ltfn=lt;
-comp='>';
-ecomp='>=';
-break;
-case'<':
-gtfn=lt;
-ltefn=gte;
-ltfn=gt;
-comp='<';
-ecomp='<=';
-break;
-default:
-throw new TypeError('Must provide a hilo val of "<" or ">"');}
-
-
-
-if(satisfies(version,range,loose)){
-return false;
-}
-
-
-
-
-for(var i=0;i<range.set.length;++i){
-var comparators=range.set[i];
-
-var high=null;
-var low=null;
-
-comparators.forEach(function(comparator){
-if(comparator.semver===ANY){
-comparator=new Comparator('>=0.0.0');
-}
-high=high||comparator;
-low=low||comparator;
-if(gtfn(comparator.semver,high.semver,loose)){
-high=comparator;
-}else if(ltfn(comparator.semver,low.semver,loose)){
-low=comparator;
-}
-});
-
-
-
-if(high.operator===comp||high.operator===ecomp){
-return false;
-}
-
-
-
-if((!low.operator||low.operator===comp)&&
-ltefn(version,low.semver)){
-return false;
-}else if(low.operator===ecomp&&ltfn(version,low.semver)){
-return false;
-}
-}
-return true;
-}
-
-exports.prerelease=prerelease;
-function prerelease(version,loose){
-var parsed=parse(version,loose);
-return parsed&&parsed.prerelease.length?parsed.prerelease:null;
-}
-
-}).call(this,require('_process'));
-},{"_process":126}],185:[function(require,module,exports){
-(function(Buffer){
-'use strict';
-
-
-const jpeg=require('jpeg-js');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function getPixel(x,y,channel,width,buff){
-return buff[(x+y*width)*4+channel];
-}
-
-
-
-
-
-
-function isWhitePixel(i,j,img){
-return getPixel(i,j,0,img.width,img.data)>=249&&
-getPixel(i,j,1,img.width,img.data)>=249&&
-getPixel(i,j,2,img.width,img.data)>=249;
-}
-
-
-function convertPixelsToHistogram(img){
-const createHistogramArray=function(){
-const ret=[];
-for(let i=0;i<256;i++){
-ret[i]=0;
-}
-return ret;
-};
-
-const width=img.width;
-const height=img.height;
-
-const histograms=[
-createHistogramArray(),
-createHistogramArray(),
-createHistogramArray()];
-
-
-for(let j=0;j<height;j++){
-for(let i=0;i<width;i++){
-
-if(isWhitePixel(i,j,img)){
-continue;
-}
-
-for(let channel=0;channel<histograms.length;channel++){
-const pixelValue=getPixel(i,j,channel,width,img.data);
-histograms[channel][pixelValue]++;
-}
-}
-}
-
-return histograms;
-}
-
-
-function synthesizeWhiteFrame(frames){
-const firstImageData=jpeg.decode(frames[0].getImage());
-const width=firstImageData.width;
-const height=firstImageData.height;
-
-const frameData=Buffer.alloc(width*height*4);
-let i=0;
-while(i<frameData.length){
-frameData[i++]=0xFF;
-frameData[i++]=0xFF;
-frameData[i++]=0xFF;
-frameData[i++]=0xFF;
-}
-
-var jpegImageData=jpeg.encode({
-data:frameData,
-width:width,
-height:height});
-
-return jpegImageData.data;
-}
-
-const screenshotTraceCategory='disabled-by-default-devtools.screenshot';
-
-
-
-
-
-function extractFramesFromTimeline(timeline,opts){
-opts=opts||{};
-
-let trace;
-timeline=typeof timeline==='string'?fs.readFileSync(timeline,'utf-8'):timeline;
-try{
-trace=typeof timeline==='string'?JSON.parse(timeline):timeline;
-}catch(e){
-throw new Error('Speedline: Invalid JSON'+e.message);
-}
-
-let events=trace.traceEvents||trace;
-
-let startTs=Number.MAX_VALUE;
-let endTs=-Number.MAX_VALUE;
-events.forEach(e=>{
-if(e.ts===0){
-return;
-}
-
-startTs=Math.min(startTs,e.ts);
-endTs=Math.max(endTs,e.ts);
-});
-
-startTs=(opts.timeOrigin||startTs)/1000;
-endTs/=1000;
-
-
-let lastFrame=null;
-const rawScreenshots=events.filter(e=>e.cat.includes(screenshotTraceCategory)&&e.ts>=startTs*1000);
-rawScreenshots.sort((a,b)=>a.ts-b.ts);
-
-
-const uniqueFrames=rawScreenshots.map(function(evt){
-const base64img=evt.args&&evt.args.snapshot;
-const timestamp=evt.ts/1000;
-
-if(base64img===lastFrame){
-return null;
-}
-
-lastFrame=base64img;
-const imgBuff=Buffer.from(base64img,'base64');
-return frame(imgBuff,timestamp);
-}).filter(Boolean);
-
-if(uniqueFrames.length===0){
-return Promise.reject(new Error('No screenshots found in trace'));
-}
-
-const fakeWhiteFrame=frame(synthesizeWhiteFrame(uniqueFrames),startTs);
-uniqueFrames.unshift(fakeWhiteFrame);
-
-const data={
-startTs,
-endTs,
-frames:uniqueFrames};
-
-return Promise.resolve(data);
-}
-
-
-
-
-
-
-function frame(imgBuff,ts){
-
-let _histogram=null;
-
-let _progress=null;
-
-let _isProgressInterpolated=null;
-
-let _perceptualProgress=null;
-
-let _isPerceptualProgressInterpolated=null;
-
-let _parsedImage=null;
-
-return{
-getHistogram:function(){
-if(_histogram){
-return _histogram;
-}
-
-const pixels=this.getParsedImage();
-_histogram=convertPixelsToHistogram(pixels);
-return _histogram;
-},
-
-getTimeStamp:function(){
-return ts;
-},
-
-setProgress:function(progress,isInterpolated){
-_progress=progress;
-_isProgressInterpolated=Boolean(isInterpolated);
-},
-
-setPerceptualProgress:function(progress,isInterpolated){
-_perceptualProgress=progress;
-_isPerceptualProgressInterpolated=Boolean(isInterpolated);
-},
-
-getImage:function(){
-return imgBuff;
-},
-
-getParsedImage:function(){
-if(!_parsedImage){
-_parsedImage=jpeg.decode(imgBuff);
-}
-return _parsedImage;
-},
-
-getProgress:function(){
-return _progress;
-},
-
-isProgressInterpolated:function(){
-return _isProgressInterpolated;
-},
-
-getPerceptualProgress:function(){
-return _perceptualProgress;
-},
-
-isPerceptualProgressInterpolated:function(){
-return _isPerceptualProgressInterpolated;
-}};
-
-}
-
-module.exports={
-extractFramesFromTimeline,
-create:frame};
-
-
-}).call(this,require("buffer").Buffer);
-},{"buffer":109,"jpeg-js":175}],186:[function(require,module,exports){
-'use strict';
-
-const frame=require('./frame');
-const speedIndex=require('./speed-index');
-
-
-
-
-
-
-
-
-
-
-
-function calculateValues(frames,data){
-const indexes=speedIndex.calculateSpeedIndexes(frames,data);
-const duration=Math.floor(data.endTs-data.startTs);
-const first=Math.floor(indexes.firstPaintTs-data.startTs);
-const complete=Math.floor(indexes.visuallyCompleteTs-data.startTs);
-
-return{
-beginning:data.startTs,
-end:data.endTs,
-frames,
-first,
-complete,
-duration,
-speedIndex:indexes.speedIndex,
-perceptualSpeedIndex:indexes.perceptualSpeedIndex};
-
-}
-
-
-const Include={
-All:'all',
-pSI:'perceptualSpeedIndex',
-SI:'speedIndex'};
-
-
-
-
-
-
-
-
-
-module.exports=function(timeline,opts){
-const include=opts&&opts.include||Include.All;
-
-if(!Object.keys(Include).some(key=>Include[key]===include)){
-throw new Error(`Unrecognized include option: ${include}`);
-}
-
-return frame.extractFramesFromTimeline(timeline,opts).then(function(data){
-const frames=data.frames;
-
-if(include===Include.All||include===Include.SI){
-speedIndex.calculateVisualProgress(frames,opts);
-}
-
-if(include===Include.All||include===Include.pSI){
-speedIndex.calculatePerceptualProgress(frames,opts);
-}
-
-return calculateValues(frames,data);
-});
-};
-
-},{"./frame":185,"./speed-index":187}],187:[function(require,module,exports){
-'use strict';
-
-const imageSSIM=require('image-ssim');
-
-
-const fastModeAllowableChangeMax=5;
-const fastModeAllowableChangeMedian=3;
-const fastModeAllowableChangeMin=-1;
-
-const fastModeConstant=fastModeAllowableChangeMin;
-const fastModeMultiplier=fastModeAllowableChangeMax-fastModeConstant;
-const fastModeExponentiationCoefficient=Math.log((fastModeAllowableChangeMedian-fastModeConstant)/fastModeMultiplier);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function calculateFastModeAllowableChange(elapsedTime){
-const elapsedTimeInSeconds=elapsedTime/1000;
-const allowableChange=fastModeMultiplier*Math.exp(fastModeExponentiationCoefficient*elapsedTimeInSeconds)+fastModeConstant;
-return allowableChange;
-}
-
-
-
-
-
-
-function calculateFrameProgress(current,initial,target){
-let total=0;
-let match=0;
-
-const currentHist=current.getHistogram();
-const initialHist=initial.getHistogram();
-const targetHist=target.getHistogram();
-
-for(let channel=0;channel<3;channel++){
-for(let pixelVal=0;pixelVal<256;pixelVal++){
-const currentCount=currentHist[channel][pixelVal];
-const initialCount=initialHist[channel][pixelVal];
-const targetCount=targetHist[channel][pixelVal];
-
-const currentDiff=Math.abs(currentCount-initialCount);
-const targetDiff=Math.abs(targetCount-initialCount);
-
-match+=Math.min(currentDiff,targetDiff);
-total+=targetDiff;
-}
-}
-
-let progress;
-if(match===0&&total===0){
-progress=100;
-}else{
-progress=Math.floor(match/total*100);
-}
-return progress;
-}
-
-
-
-
-
-
-
-
-
-function calculateProgressBetweenFrames(frames,lowerBound,upperBound,isFastMode,getProgress,setProgress){
-if(!isFastMode){
-frames.forEach(frame=>setProgress(frame,getProgress(frame),false));
-return;
-}
-
-const lowerFrame=frames[lowerBound];
-const upperFrame=frames[upperBound];
-const elapsedTime=upperFrame.getTimeStamp()-lowerFrame.getTimeStamp();
-
-const lowerProgress=getProgress(lowerFrame);
-const upperProgress=getProgress(upperFrame);
-
-setProgress(lowerFrame,lowerProgress,false);
-setProgress(upperFrame,upperProgress,false);
-
-if(Math.abs(lowerProgress-upperProgress)<calculateFastModeAllowableChange(elapsedTime)){
-for(let i=lowerBound+1;i<upperBound;i++){
-setProgress(frames[i],lowerProgress,true);
-}
-}else if(upperBound-lowerBound>1){
-const midpoint=Math.floor((lowerBound+upperBound)/2);
-calculateProgressBetweenFrames(frames,lowerBound,midpoint,isFastMode,getProgress,setProgress);
-calculateProgressBetweenFrames(frames,midpoint,upperBound,isFastMode,getProgress,setProgress);
-}
-}
-
-
-
-
-
-function calculateVisualProgress(frames,opts){
-const initial=frames[0];
-const target=frames[frames.length-1];
-
-
-function getProgress(frame){
-if(typeof frame.getProgress()==='number'){
-return frame.getProgress();
-}
-
-return calculateFrameProgress(frame,initial,target);
-}
-
-
-
-
-
-
-function setProgress(frame,progress,isInterpolated){
-return frame.setProgress(progress,isInterpolated);
-}
-
-calculateProgressBetweenFrames(
-frames,
-0,
-frames.length-1,
-opts&&opts.fastMode,
-getProgress,
-setProgress);
-
-
-return frames;
-}
-
-
-
-
-
-
-function calculateFrameSimilarity(frame,target){
-const defaultImageConfig={
-
-
-channels:4};
-
-
-const frameData=Object.assign(frame.getParsedImage(),defaultImageConfig);
-const targetData=Object.assign(target.getParsedImage(),defaultImageConfig);
-
-const diff=imageSSIM.compare(frameData,targetData);
-return diff.ssim;
-}
-
-
-
-
-
-function calculatePerceptualProgress(frames,opts){
-const initial=frames[0];
-const target=frames[frames.length-1];
-const initialSimilarity=calculateFrameSimilarity(initial,target);
-
-
-function getProgress(frame){
-if(typeof frame.getPerceptualProgress()==='number'){
-return frame.getPerceptualProgress();
-}
-
-const ssim=calculateFrameSimilarity(frame,target);
-return Math.max(100*(ssim-initialSimilarity)/(1-initialSimilarity),0);
-}
-
-
-
-
-
-
-function setProgress(frame,progress,isInterpolated){
-return frame.setPerceptualProgress(progress,isInterpolated);
-}
-
-calculateProgressBetweenFrames(
-frames,
-0,
-frames.length-1,
-opts&&opts.fastMode,
-getProgress,
-setProgress);
-
-
-return frames;
-}
-
-
-
-
-
-
-function calculateSpeedIndexes(frames,data){
-const hasVisualProgress=typeof frames[0].getProgress()==='number';
-const hasPerceptualProgress=typeof frames[0].getPerceptualProgress()==='number';
-const progressToUse=hasVisualProgress?'getProgress':'getPerceptualProgress';
-const startTs=data.startTs;
-let visuallyCompleteTs;
-
-let firstPaintTs;
-
-
-for(let i=0;i<frames.length&&!firstPaintTs;i++){
-if(frames[i][progressToUse]()>0){
-firstPaintTs=frames[i].getTimeStamp();
-}
-}
-
-
-for(let i=0;i<frames.length&&!visuallyCompleteTs;i++){
-if(frames[i][progressToUse]()>=100){
-visuallyCompleteTs=frames[i].getTimeStamp();
-}
-}
-
-let prevFrameTs=frames[0].getTimeStamp();
-let prevProgress=frames[0].getProgress();
-let prevPerceptualProgress=frames[0].getPerceptualProgress();
-
-
-
-
-let speedIndex=firstPaintTs-startTs;
-
-let perceptualSpeedIndex=firstPaintTs-startTs;
-
-frames.forEach(function(frame){
-
-if(frame.getTimeStamp()>firstPaintTs){
-const elapsed=frame.getTimeStamp()-prevFrameTs;
-speedIndex+=elapsed*(1-prevProgress);
-perceptualSpeedIndex+=elapsed*(1-prevPerceptualProgress);
-}
-
-prevFrameTs=frame.getTimeStamp();
-prevProgress=frame.getProgress()/100;
-prevPerceptualProgress=frame.getPerceptualProgress()/100;
-});
-
-speedIndex=hasVisualProgress?speedIndex:undefined;
-perceptualSpeedIndex=hasPerceptualProgress?perceptualSpeedIndex:undefined;
-
-return{
-firstPaintTs,
-visuallyCompleteTs,
-speedIndex,
-perceptualSpeedIndex};
-
-}
-
-module.exports={
-calculateFastModeAllowableChange,
-calculateFrameSimilarity,
-calculateVisualProgress,
-calculatePerceptualProgress,
-calculateSpeedIndexes};
-
-
-},{"image-ssim":165}],188:[function(require,module,exports){
-module.exports={
-"version":"3.2.0"};
-
-},{}],189:[function(require,module,exports){
-module.exports={
-"npm":{
-"angular":[
-{"id":"npm:angular:20180202","severity":"medium","semver":{"vulnerable":["<1.6.9"]}},
-{"id":"npm:angular:20171018","severity":"medium","semver":{"vulnerable":["<1.6.7"]}},
-{"id":"npm:angular:20160527","severity":"medium","semver":{"vulnerable":["<1.2.30 >=1.0.0"]}},
-{"id":"npm:angular:20160122","severity":"medium","semver":{"vulnerable":["<1.5.0-rc.2 >=1.3.0"]}},
-{"id":"npm:angular:20140608","severity":"low","semver":{"vulnerable":["<1.3.0"]}},
-{"id":"npm:angular:20131113","severity":"high","semver":{"vulnerable":["<1.2.2"]}},
-{"id":"npm:angular:20140908","severity":"medium","semver":{"vulnerable":["<1.3.0-rc.4"]}},
-{"id":"npm:angular:20161101","severity":"medium","semver":{"vulnerable":["<1.5.9 >=1.5.0"]}},
-{"id":"npm:angular:20150909","severity":"high","semver":{"vulnerable":["<1.5.0-beta.2"]}},
-{"id":"npm:angular:20151205","severity":"medium","semver":{"vulnerable":["<1.5.0-rc.0"]}},
-{"id":"npm:angular:20151130","severity":"medium","semver":{"vulnerable":["<1.4.10"]}},
-{"id":"npm:angular:20130622","severity":"medium","semver":{"vulnerable":["<1.2.0 >=1.0.0"]}},
-{"id":"npm:angular:20150807-1","severity":"medium","semver":{"vulnerable":["<1.5.0-beta.0 >=1.3.1"]}},
-{"id":"npm:angular:20150807","severity":"high","semver":{"vulnerable":["<1.5.0-beta.0 >=1.0.0"]}},
-{"id":"npm:angular:20150315","severity":"medium","semver":{"vulnerable":["<1.6.1"]}},
-{"id":"npm:angular:20150310","severity":"high","semver":{"vulnerable":["<1.5.0-beta.2"]}},
-{"id":"npm:angular:20141104","severity":"medium","semver":{"vulnerable":["<1.3.2"]}},
-{"id":"npm:angular:20130621","severity":"medium","semver":{"vulnerable":["<=1.1.5"]}},
-{"id":"npm:angular:20140909","severity":"high","semver":{"vulnerable":["<1.2.24 >=1.2.19"]}},
-{"id":"npm:angular:20130625","severity":"high","semver":{"vulnerable":["<1.1.5"]}}],
-
-"backbone":[
-{"id":"npm:backbone:20160523","severity":"medium","semver":{"vulnerable":["<= 0.3.3"]}},
-{"id":"npm:backbone:20110701","severity":"medium","semver":{"vulnerable":["<0.5.0"]}}],
-
-"bootstrap":[
-{"id":"npm:bootstrap:20180529","severity":"medium","semver":{"vulnerable":[">=4.0.0 <4.1.2"]}},
-{"id":"npm:bootstrap:20160627","severity":"medium","semver":{"vulnerable":["<3.4.0 || >=4.0.0-alpha <4.0.0-beta.2"]}},
-{"id":"npm:bootstrap:20120510","severity":"medium","semver":{"vulnerable":["<2.1.0"]}}],
-
-"dojo":[
-{"id":"SNYK-JS-DOJO-72305","severity":"medium","semver":{"vulnerable":["<1.14"]}},
-{"id":"npm:dojo:20180818","severity":"medium","semver":{"vulnerable":["<1.10.10 || >=1.11.0 <1.11.6 || >=1.12.0 <1.12.4 || >=1.13.0 <1.13.1"]}},
-{"id":"npm:dojo:20160523","severity":"medium","semver":{"vulnerable":["<= 1.0.0"]}},
-{"id":"npm:dojo:20100614-6","severity":"medium","semver":{"vulnerable":["<1.4.2"]}},
-{"id":"npm:dojo:20100614-1","severity":"high","semver":{"vulnerable":[">=0.4 <0.4.4 || >=1.0 <1.0.3 || >=1.1 <1.1.2 || >=1.2 <1.2.4 || >=1.3 <1.3.3 || >=1.4 <1.4.2"]}},
-{"id":"npm:dojo:20090409","severity":"medium","semver":{"vulnerable":["<1.1"]}}],
-
-"foundation-sites":[
-{"id":"npm:foundation-sites:20170802","severity":"medium","semver":{"vulnerable":["<6.0.0"]}},
-{"id":"npm:foundation-sites:20150619","severity":"medium","semver":{"vulnerable":["<5.5.3"]}},
-{"id":"npm:foundation-sites:20120717","severity":"medium","semver":{"vulnerable":["<3.0.6 >=3.0.0"]}}],
-
-"handlebars":[
-{"id":"npm:handlebars:20151207","severity":"medium","semver":{"vulnerable":["<4.0.0"]}},
-{"id":"npm:handlebars:20110425","severity":"medium","semver":{"vulnerable":["<=1.0.0-beta.3"]}}],
-
-"highcharts":[
-{"id":"npm:highcharts:20180225","severity":"low","semver":{"vulnerable":["<6.1.0"]}}],
-
-"jquery":[
-{"id":"npm:jquery:20160529","severity":"low","semver":{"vulnerable":["=3.0.0-rc.1"]}},
-{"id":"npm:jquery:20150627","severity":"medium","semver":{"vulnerable":["<3.0.0-beta1 >1.12.3 || <1.12.0 >=1.4.0"]}},
-{"id":"npm:jquery:20140902","severity":"medium","semver":{"vulnerable":[">=1.4.2 <1.6.2"]}},
-{"id":"npm:jquery:20120206","severity":"medium","semver":{"vulnerable":["<1.9.0 >=1.7.1"]}},
-{"id":"npm:jquery:20110606","severity":"medium","semver":{"vulnerable":["<1.6.3"]}}],
-
-"jquery-mobile":[
-{"id":"npm:jquery-mobile:20120802","severity":"medium","semver":{"vulnerable":["<1.2.0"]}}],
-
-"jquery-ui":[
-{"id":"npm:jquery-ui:20121127","severity":"medium","semver":{"vulnerable":["<1.10.0"]}},
-{"id":"npm:jquery-ui:20100903","severity":"medium","semver":{"vulnerable":["<1.10.0"]}},
-{"id":"npm:jquery-ui:20160721","severity":"high","semver":{"vulnerable":["<=1.11.4"]}}],
-
-"knockout":[
-{"id":"npm:knockout:20180213","severity":"medium","semver":{"vulnerable":["<3.5.0-beta"]}},
-{"id":"npm:knockout:20130701","severity":"medium","semver":{"vulnerable":["<3.0.0 >=2.1.0-pre"]}}],
-
-"lodash":[
-{"id":"npm:lodash:20180130","severity":"low","semver":{"vulnerable":["<4.17.5"]}}],
-
-"moment":[
-{"id":"npm:moment:20170905","severity":"low","semver":{"vulnerable":["<2.19.3"]}},
-{"id":"npm:moment:20161019","severity":"medium","semver":{"vulnerable":["<2.15.2"]}},
-{"id":"npm:moment:20160126","severity":"low","semver":{"vulnerable":["<=2.11.1"]}}],
-
-"mustache":[
-{"id":"npm:mustache:20151207","severity":"medium","semver":{"vulnerable":["<2.2.1"]}},
-{"id":"npm:mustache:20110814","severity":"medium","semver":{"vulnerable":["< 0.3.1"]}}],
-
-"preact-render-to-string":[
-{"id":"npm:preact-render-to-string:20180802","severity":"medium","semver":{"vulnerable":["<3.7.2"]}}],
-
-"react":[
-{"id":"npm:react:20150318","severity":"high","semver":{"vulnerable":["<0.14.0"]}},
-{"id":"npm:react:20131217","severity":"medium","semver":{"vulnerable":[">=0.5.0 <0.5.2 || >=0.4.0 <0.4.2"]}}],
-
-"react-dom":[
-{"id":"npm:react-dom:20180802","severity":"medium","semver":{"vulnerable":[">=16.0.0 <16.0.1",">=16.1.0 <16.1.2",">=16.2.0 <16.2.1",">=16.3.0 <16.3.3",">=16.4.0 <16.4.2"]}}],
-
-"riot":[
-{"id":"npm:riot:20131114","severity":"medium","semver":{"vulnerable":["<0.9.6"]}}],
-
-"socket.io":[
-{"id":"npm:socket.io:20120417","severity":"medium","semver":{"vulnerable":["<0.9.6"]}},
-{"id":"npm:socket.io:20120323","severity":"medium","semver":{"vulnerable":["<0.9.7"]}}],
-
-"vue":[
-{"id":"npm:vue:20170829","severity":"medium","semver":{"vulnerable":["<2.4.3"]}},
-{"id":"npm:vue:20170401","severity":"medium","semver":{"vulnerable":["<2.3.0-beta.1"]}},
-{"id":"npm:vue:20180802","severity":"medium","semver":{"vulnerable":["<2.5.17"]}},
-{"id":"npm:vue:20180222","severity":"low","semver":{"vulnerable":["<=2.5.14"]}}],
-
-"yui":[
-{"id":"npm:yui:20130604","severity":"medium","semver":{"vulnerable":[">=3.0.0 <3.10.1 || =3.10.2"]}},
-{"id":"npm:yui:20130515","severity":"medium","semver":{"vulnerable":["<3.10.0 >=3.0.0"]}},
-{"id":"npm:yui:20121030","severity":"medium","semver":{"vulnerable":["<3.0.0 >=2.4.0"]}},
-{"id":"npm:yui:20120428","severity":"medium","semver":{"vulnerable":["<3.5.1 >=3.5.0-PR1"]}},
-{"id":"npm:yui:20101025","severity":"medium","semver":{"vulnerable":["<2.8.2 >=2.4.0"]}}]}};
-
-
-
-},{}],"url":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const Util=require('../report/html/renderer/util.js');
-
-
-const URL=typeof self!=='undefined'&&self.URL||
-require('url').URL;
-
-
-
-const listOfTlds=[
-'com','co','gov','edu','ac','org','go','gob','or','net','in','ne','nic','gouv',
-'web','spb','blog','jus','kiev','mil','wi','qc','ca','bel','on'];
-
-
-const allowedProtocols=[
-'https:','http:','chrome:'];
-
-
-
-
-
-
-
-
-
-function rewriteChromeInternalUrl(url){
-if(!url||!url.startsWith('chrome://'))return url;
-
-
-if(url.endsWith('/'))url=url.replace(/\/$/,'');
-return url.replace(/^chrome:\/\/chrome\//,'chrome://');
-}
-
-class URLShim extends URL{
-
-
-
-
-static isValid(url){
-try{
-new URL(url);
-return true;
-}catch(e){
-return false;
-}
-}
-
-
-
-
-
-
-static hostsMatch(urlA,urlB){
-try{
-return new URL(urlA).host===new URL(urlB).host;
-}catch(e){
-return false;
-}
-}
-
-
-
-
-
-
-static originsMatch(urlA,urlB){
-try{
-return new URL(urlA).origin===new URL(urlB).origin;
-}catch(e){
-return false;
-}
-}
-
-
-
-
-
-static getOrigin(url){
-try{
-const urlInfo=new URL(url);
-
-
-return urlInfo.host&&urlInfo.origin||null;
-}catch(e){
-return null;
-}
-}
-
-
-
-
-
-
-
-static getTld(hostname){
-const tlds=hostname.split('.').slice(-2);
-
-if(!listOfTlds.includes(tlds[0])){
-return`.${tlds[tlds.length-1]}`;
-}
-
-return`.${tlds.join('.')}`;
-}
-
-
-
-
-
-
-
-static rootDomainsMatch(urlA,urlB){
-let urlAInfo;
-let urlBInfo;
-try{
-urlAInfo=new URL(urlA);
-urlBInfo=new URL(urlB);
-}catch(err){
-return false;
-}
-
-if(!urlAInfo.hostname||!urlBInfo.hostname){
-return false;
-}
-
-const tldA=URLShim.getTld(urlAInfo.hostname);
-const tldB=URLShim.getTld(urlBInfo.hostname);
-
-
-const urlARootDomain=urlAInfo.hostname.replace(new RegExp(`${tldA}$`),'').
-split('.').splice(-1)[0];
-const urlBRootDomain=urlBInfo.hostname.replace(new RegExp(`${tldB}$`),'').
-split('.').splice(-1)[0];
-
-return urlARootDomain===urlBRootDomain;
-}
-
-
-
-
-
-
-static getURLDisplayName(url,options){
-return Util.getURLDisplayName(new URL(url),options);
-}
-
-
-
-
-
-
-static elideDataURI(url){
-try{
-const parsed=new URL(url);
-return parsed.protocol==='data:'?url.slice(0,100):url;
-}catch(e){
-return url;
-}
-}
-
-
-
-
-
-
-
-static equalWithExcludedFragments(url1,url2){
-[url1,url2]=[url1,url2].map(rewriteChromeInternalUrl);
-try{
-const urla=new URL(url1);
-urla.hash='';
-
-const urlb=new URL(url2);
-urlb.hash='';
-
-return urla.href===urlb.href;
-}catch(e){
-return false;
-}
-}
-
-
-
-
-
-
-static isProtocolAllowed(url){
-try{
-const parsed=new URL(url);
-return allowedProtocols.includes(parsed.protocol);
-}catch(e){
-return false;
-}
-}}
-
-
-URLShim.URL=URL;
-URLShim.URLSearchParams=typeof self!=='undefined'&&self.URLSearchParams||
-require('url').URLSearchParams;
-
-URLShim.NON_NETWORK_PROTOCOLS=['blob','data'];
-
-URLShim.INVALID_URL_DEBUG_STRING=
-'Lighthouse was unable to determine the URL of some script executions. '+
-'It\'s possible a Chrome extension or other eval\'d code is the source.';
-
-module.exports=URLShim;
-
-},{"../report/html/renderer/util.js":97,"url":"url"}]},{},[101]); \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-dt-bundle.js b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-dt-bundle.js
new file mode 100644
index 00000000000..c7dd6b0df6d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/lighthouse/lighthouse-dt-bundle.js
@@ -0,0 +1,59456 @@
+// lighthouse, browserified. 4.0.0 (bfa10f1ac4ba8cdf95c809858d8bc4c8ac1c1da8)
+require=function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o;}return r;}()({"../audits/accessibility/aria-allowed-attr":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[aria-*]` attributes match their roles',
+
+failureTitle:'`[aria-*]` attributes do not match their roles',
+
+description:'Each ARIA `role` supports a specific subset of `aria-*` attributes. '+
+'Mismatching these invalidates the `aria-*` attributes. [Learn '+
+'more](https://dequeuniversity.com/rules/axe/3.1/aria-allowed-attr?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ARIAAllowedAttr extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-allowed-attr',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ARIAAllowedAttr;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-allowed-attr.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/aria-required-attr":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[role]`s have all required `[aria-*]` attributes',
+
+failureTitle:'`[role]`s do not have all required `[aria-*]` attributes',
+
+description:'Some ARIA roles have required attributes that describe the state '+
+'of the element to screen readers. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-required-attr?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ARIARequiredAttr extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-required-attr',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ARIARequiredAttr;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-required-attr.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/aria-required-children":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Elements with `[role]` that require specific children `[role]`s, are present',
+
+failureTitle:'Elements with `[role]` that require specific children `[role]`s, '+
+'are missing.',
+
+description:'Some ARIA parent roles must contain specific child roles to perform '+
+'their intended accessibility functions. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-required-children?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class AriaRequiredChildren extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-required-children',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=AriaRequiredChildren;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-required-children.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/aria-required-parent":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[role]`s are contained by their required parent element',
+
+failureTitle:'`[role]`s are not contained by their required parent element',
+
+description:'Some ARIA child roles must be contained by specific parent roles to '+
+'properly perform their intended accessibility functions. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-required-parent?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class AriaRequiredParent extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-required-parent',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=AriaRequiredParent;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-required-parent.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/aria-roles":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[role]` values are valid',
+
+failureTitle:'`[role]` values are not valid',
+
+description:'ARIA roles must have valid values in order to perform their '+
+'intended accessibility functions. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-roles?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class AriaRoles extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-roles',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=AriaRoles;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-roles.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/aria-valid-attr-value":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[aria-*]` attributes have valid values',
+
+failureTitle:'`[aria-*]` attributes do not have valid values',
+
+description:'Assistive technologies, like screen readers, can\'t interpret ARIA '+
+'attributes with invalid values. [Learn '+
+'more](https://dequeuniversity.com/rules/axe/3.1/aria-valid-attr-value?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ARIAValidAttr extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-valid-attr-value',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ARIAValidAttr;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-valid-attr-value.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/aria-valid-attr":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[aria-*]` attributes are valid and not misspelled',
+
+failureTitle:'`[aria-*]` attributes are not valid or misspelled',
+
+description:'Assistive technologies, like screen readers, can\'t interpret ARIA '+
+'attributes with invalid names. [Learn '+
+'more](https://dequeuniversity.com/rules/axe/3.1/aria-valid-attr?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ARIAValidAttr extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'aria-valid-attr',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ARIAValidAttr;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/aria-valid-attr.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/audio-caption":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<audio>` elements contain a `<track>` element with `[kind="captions"]`',
+
+failureTitle:'`<audio>` elements are missing a `<track>` element with '+
+'`[kind="captions"]`.',
+
+description:'Captions make audio elements usable for deaf or hearing-impaired users, '+
+'providing critical information such as who is talking, what they\'re saying, '+
+'and other non-speech information. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/audio-caption?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class AudioCaption extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'audio-caption',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=AudioCaption;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/audio-caption.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/button-name":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Buttons have an accessible name',
+
+failureTitle:'Buttons do not have an accessible name',
+
+description:'When a button doesn\'t have an accessible name, screen readers announce it '+
+'as "button", making it unusable for users who rely on screen readers. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/button-name?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ButtonName extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'button-name',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ButtonName;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/button-name.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/bypass":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'The page contains a heading, skip link, or landmark region',
+
+failureTitle:'The page does not contain a heading, skip link, or landmark region',
+
+description:'Adding ways to bypass repetitive content lets keyboard users navigate the '+
+'page more efficiently. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/bypass?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class Bypass extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'bypass',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=Bypass;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/bypass.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/color-contrast":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Background and foreground colors have a sufficient contrast ratio',
+
+failureTitle:'Background and foreground colors do not have a '+
+'sufficient contrast ratio.',
+
+description:'Low-contrast text is difficult or impossible for many users to read. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/color-contrast?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ColorContrast extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'color-contrast',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ColorContrast;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/color-contrast.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/definition-list":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<dl>`\'s contain only properly-ordered `<dt>` and `<dd>` groups, `<script>` '+
+'or `<template>` elements.',
+
+failureTitle:'`<dl>`\'s do not contain only properly-ordered `<dt>` and `<dd>` '+
+'groups, `<script>` or `<template>` elements.',
+
+description:'When definition lists are not properly marked up, screen readers may produce '+
+'confusing or inaccurate output. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/definition-list?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class DefinitionList extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'definition-list',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=DefinitionList;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/definition-list.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/dlitem":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Definition list items are wrapped in `<dl>` elements',
+
+failureTitle:'Definition list items are not wrapped in `<dl>` elements',
+
+description:'Definition list items (`<dt>` and `<dd>`) must be wrapped in a '+
+'parent `<dl>` element to ensure that screen readers can properly announce them. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/dlitem?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class DLItem extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'dlitem',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=DLItem;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/dlitem.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/document-title":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Document has a `<title>` element',
+
+failureTitle:'Document doesn\'t have a `<title>` element',
+
+description:'The title gives screen reader users an overview of the page, and search '+
+'engine users rely on it heavily to determine if a page is relevant to their search. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/title).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class DocumentTitle extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'document-title',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=DocumentTitle;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/document-title.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/duplicate-id":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[id]` attributes on the page are unique',
+
+failureTitle:'`[id]` attributes on the page are not unique',
+
+description:'The value of an id attribute must be unique to prevent '+
+'other instances from being overlooked by assistive technologies. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/duplicate-id?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class DuplicateId extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'duplicate-id',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=DuplicateId;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/duplicate-id.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/frame-title":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<frame>` or `<iframe>` elements have a title',
+
+failureTitle:'`<frame>` or `<iframe>` elements do not have a title',
+
+description:'Screen reader users rely on frame titles to describe the contents of frames. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/frame-title?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class FrameTitle extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'frame-title',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=FrameTitle;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/frame-title.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/html-has-lang":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<html>` element has a `[lang]` attribute',
+
+failureTitle:'`<html>` element does not have a `[lang]` attribute',
+
+description:'If a page doesn\'t specify a lang attribute, a screen reader assumes '+
+'that the page is in the default language that the user chose when setting up the '+
+'screen reader. If the page isn\'t actually in the default language, then the screen '+
+'reader might not announce the page\'s text correctly. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/html-has-lang?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class HTMLHasLang extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'html-has-lang',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=HTMLHasLang;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/html-has-lang.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/html-lang-valid":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<html>` element has a valid value for its `[lang]` attribute',
+
+failureTitle:'`<html>` element does not have a valid value for '+
+'its `[lang]` attribute.',
+
+description:'Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) '+
+'helps screen readers announce text properly. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/valid-lang?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class HTMLLangValid extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'html-lang-valid',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=HTMLLangValid;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/html-lang-valid.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/image-alt":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Image elements have `[alt]` attributes',
+
+failureTitle:'Image elements do not have `[alt]` attributes',
+
+description:'Informative elements should aim for short, descriptive alternate text. '+
+'Decorative elements can be ignored with an empty alt attribute. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/image-alt?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ImageAlt extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'image-alt',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ImageAlt;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/image-alt.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/input-image-alt":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<input type="image">` elements have `[alt]` text',
+
+failureTitle:'`<input type="image">` elements do not have `[alt]` text',
+
+description:'When an image is being used as an `<input>` button, providing alternative '+
+'text can help screen reader users understand the purpose of the button. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/input-image-alt?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class InputImageAlt extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'input-image-alt',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=InputImageAlt;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/input-image-alt.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/label":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Form elements have associated labels',
+
+failureTitle:'Form elements do not have associated labels',
+
+description:'Labels ensure that form controls are announced properly by assistive '+
+'technologies, like screen readers. [Learn '+
+'more](https://dequeuniversity.com/rules/axe/3.1/label?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class Label extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'label',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=Label;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/label.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/layout-table":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Presentational `<table>` elements avoid using `<th>`, `<caption>` or the '+
+'`[summary]` attribute.',
+
+failureTitle:'Presentational `<table>` elements do not avoid using `<th>`, '+
+'`<caption>` or the `[summary]` attribute.',
+
+description:'A table being used for layout purposes should not include data elements, '+
+'such as the th or caption elements or the summary attribute, because this can '+
+'create a confusing experience for screen reader users. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/layout-table?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class LayoutTable extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'layout-table',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=LayoutTable;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/layout-table.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/link-name":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Links have a discernible name',
+
+failureTitle:'Links do not have a discernible name',
+
+description:'Link text (and alternate text for images, when used as links) that is '+
+'discernible, unique, and focusable improves the navigation experience for '+
+'screen reader users. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/link-name?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class LinkName extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'link-name',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=LinkName;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/link-name.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/listitem":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'List items (`<li>`) are contained within `<ul>` or `<ol>` parent elements',
+
+failureTitle:'List items (`<li>`) are not contained within `<ul>` '+
+'or `<ol>` parent elements.',
+
+description:'Screen readers require list items (`<li>`) to be contained within a '+
+'parent `<ul>` or `<ol>` to be announced properly. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/listitem?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ListItem extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'listitem',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ListItem;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/listitem.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/list":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Lists contain only `<li>` elements and script supporting elements '+
+'(`<script>` and `<template>`).',
+
+failureTitle:'Lists do not contain only `<li>` elements and script '+
+'supporting elements (`<script>` and `<template>`).',
+
+description:'Screen readers have a specific way of announcing lists. Ensuring proper list '+
+'structure aids screen reader output. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/list?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class List extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'list',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=List;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/list.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/manual/accesskeys":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+const Audit=require('../../audit.js');
+const i18n=require('../../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[accesskey]` values are unique',
+
+description:'Access keys let users quickly focus a part of the page. For proper '+
+'navigation, each access key must be unique. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/accesskeys?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class Accesskeys extends Audit{
+
+
+
+static get meta(){
+return{
+id:'accesskeys',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.MANUAL,
+requiredArtifacts:[]};
+
+}
+
+
+
+
+static audit(){
+return{rawValue:false};
+}}
+
+
+module.exports=Accesskeys;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/manual/accesskeys.js");
+},{"../../../lib/i18n/i18n.js":59,"../../audit.js":3}],"../audits/accessibility/manual/custom-controls-labels":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class CustomControlsLabels extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'custom-controls-labels',
+description:'Custom interactive controls have associated labels, provided by aria-label or aria-labelledby. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
+title:'Custom controls have associated labels'},
+super.partialMeta);
+}}
+
+
+module.exports=CustomControlsLabels;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/custom-controls-roles":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class CustomControlsRoles extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'custom-controls-roles',
+description:'Custom interactive controls have appropriate ARIA roles. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
+title:'Custom controls have ARIA roles'},
+super.partialMeta);
+}}
+
+
+module.exports=CustomControlsRoles;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/focus-traps":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class FocusTraps extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'focus-traps',
+description:'A user can tab into and out of any control or region without accidentally trapping their focus. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
+title:'User focus is not accidentally trapped in a region'},
+super.partialMeta);
+}}
+
+
+module.exports=FocusTraps;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/focusable-controls":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class FocusableControls extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'focusable-controls',
+description:'Custom interactive controls are keyboard focusable and display a focus indicator. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
+title:'Interactive controls are keyboard focusable'},
+super.partialMeta);
+}}
+
+
+module.exports=FocusableControls;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/heading-levels":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class HeadingLevels extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'heading-levels',
+description:'Headings are used to create an outline for the page and heading levels are not skipped. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#take_advantage_of_headings_and_landmarks).',
+title:'Headings don\'t skip levels'},
+super.partialMeta);
+}}
+
+
+module.exports=HeadingLevels;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/interactive-element-affordance":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class InteractiveElementAffordance extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'interactive-element-affordance',
+description:'Interactive elements, such as links and buttons, should indicate their state and be distinguishable from non-interactive elements. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#interactive_elements_like_links_and_buttons_should_indicate_their_purpose_and_state).',
+title:'Interactive elements indicate their purpose and state'},
+super.partialMeta);
+}}
+
+
+module.exports=InteractiveElementAffordance;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/logical-tab-order":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class LogicalTabOrder extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'logical-tab-order',
+description:'Tabbing through the page follows the visual layout. Users cannot focus elements that are offscreen. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
+title:'The page has a logical tab order'},
+super.partialMeta);
+}}
+
+
+module.exports=LogicalTabOrder;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/managed-focus":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class ManagedFocus extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'managed-focus',
+description:'If new content, such as a dialog, is added to the page, the user\'s focus is directed to it. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
+title:'The user\'s focus is directed to new content added to the page'},
+super.partialMeta);
+}}
+
+
+module.exports=ManagedFocus;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/offscreen-content-hidden":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+
+class OffscreenContentHidden extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'offscreen-content-hidden',
+description:'Offscreen content is hidden with display: none or aria-hidden=true. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
+title:'Offscreen content is hidden from assistive technology'},
+super.partialMeta);
+}}
+
+
+module.exports=OffscreenContentHidden;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/use-landmarks":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class UseLandmarks extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'use-landmarks',
+description:'Landmark elements (<main>, <nav>, etc.) are used to improve the keyboard navigation of the page for assistive technology. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#take_advantage_of_headings_and_landmarks).',
+title:'HTML5 landmark elements are used to improve navigation'},
+super.partialMeta);
+}}
+
+
+module.exports=UseLandmarks;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/manual/visual-order-follows-dom":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class VisualOrderFollowsDOM extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'visual-order-follows-dom',
+description:'DOM order matches the visual order, improving navigation for assistive technology. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
+title:'Visual order on the page follows DOM order'},
+super.partialMeta);
+}}
+
+
+module.exports=VisualOrderFollowsDOM;
+
+},{"../../manual/manual-audit":5}],"../audits/accessibility/meta-refresh":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'The document does not use `<meta http-equiv="refresh">`',
+
+failureTitle:'The document uses `<meta http-equiv="refresh">`',
+
+description:'Users do not expect a page to refresh automatically, and doing so will move '+
+'focus back to the top of the page. This may create a frustrating or '+
+'confusing experience. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/meta-refresh?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class MetaRefresh extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'meta-refresh',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=MetaRefresh;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/meta-refresh.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/meta-viewport":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[user-scalable="no"]` is not used in the `<meta name="viewport">` '+
+'element and the `[maximum-scale]` attribute is not less than 5.',
+
+failureTitle:'`[user-scalable="no"]` is used in the `<meta name="viewport">` '+
+'element or the `[maximum-scale]` attribute is less than 5.',
+
+description:'Disabling zooming is problematic for users with low vision who rely on '+
+'screen magnification to properly see the contents of a web page. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/meta-viewport?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class MetaViewport extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'meta-viewport',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=MetaViewport;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/meta-viewport.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/object-alt":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<object>` elements have `[alt]` text',
+
+failureTitle:'`<object>` elements do not have `[alt]` text',
+
+description:'Screen readers cannot translate non-text content. Adding alt text to '+
+'`<object>` elements helps screen readers convey meaning to users. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/object-alt?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ObjectAlt extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'object-alt',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ObjectAlt;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/object-alt.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/tabindex":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'No element has a `[tabindex]` value greater than 0',
+
+failureTitle:'Some elements have a `[tabindex]` value greater than 0',
+
+description:'A value greater than 0 implies an explicit navigation ordering. '+
+'Although technically valid, this often creates frustrating experiences '+
+'for users who rely on assistive technologies. [Learn more](https://dequeuniversity.com/rules/axe/3.1/tabindex?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class TabIndex extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'tabindex',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=TabIndex;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/tabindex.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/td-headers-attr":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Cells in a `<table>` element that use the `[headers]` attribute only refer '+
+'to other cells of that same table.',
+
+failureTitle:'Cells in a `<table>` element that use the `[headers]` '+
+'attribute refers to other cells of that same table.',
+
+description:'Screen readers have features to make navigating tables easier. Ensuring '+
+'`<td>` cells using the `[headers]` attribute only refer to other cells in the same '+
+'table may improve the experience for screen reader users. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/td-headers-attr?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class TDHeadersAttr extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'td-headers-attr',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=TDHeadersAttr;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/td-headers-attr.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/th-has-data-cells":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<th>` elements and elements with `[role="columnheader"/"rowheader"]` have '+
+'data cells they describe.',
+
+failureTitle:'`<th>` elements and elements with '+
+'`[role="columnheader"/"rowheader"]` do not have data cells they describe.',
+
+description:'Screen readers have features to make navigating tables easier. Ensuring '+
+'table headers always refer to some set of cells may improve the experience for screen '+
+'reader users. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/th-has-data-cells?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class THHasDataCells extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'th-has-data-cells',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=THHasDataCells;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/th-has-data-cells.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/valid-lang":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`[lang]` attributes have a valid value',
+
+failureTitle:'`[lang]` attributes do not have a valid value',
+
+description:'Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) '+
+'on elements helps ensure that text is pronounced correctly by a screen reader. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/valid-lang?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class ValidLang extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'valid-lang',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=ValidLang;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/valid-lang.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/video-caption":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<video>` elements contain a `<track>` element with `[kind="captions"]`',
+
+failureTitle:'`<video>` elements do not contain a `<track>` element '+
+'with `[kind="captions"]`.',
+
+description:'When a video provides a caption it is easier for deaf and hearing impaired '+
+'users to access its information. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/video-caption?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class VideoCaption extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'video-caption',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=VideoCaption;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/video-caption.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/accessibility/video-description":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const AxeAudit=require('./axe-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'`<video>` elements contain a `<track>` element with `[kind="description"]`',
+
+failureTitle:'`<video>` elements do not contain a `<track>` element with '+
+'`[kind="description"]`.',
+
+description:'Audio descriptions provide relevant information for videos that dialogue '+
+'cannot, such as facial expressions and scenes. '+
+'[Learn more](https://dequeuniversity.com/rules/axe/3.1/video-description?application=lighthouse).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class VideoDescription extends AxeAudit{
+
+
+
+static get meta(){
+return{
+id:'video-description',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['Accessibility']};
+
+}}
+
+
+module.exports=VideoDescription;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/video-description.js");
+},{"../../lib/i18n/i18n.js":59,"./axe-audit":2}],"../audits/bootup-time":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const NetworkRequest=require('../lib/network-request');
+const{taskGroups}=require('../lib/task-groups');
+const i18n=require('../lib/i18n/i18n.js');
+const NetworkRecords=require('../computed/network-records.js');
+const MainThreadTasks=require('../computed/main-thread-tasks.js');
+
+const UIStrings={
+
+title:'JavaScript execution time',
+
+failureTitle:'Reduce JavaScript execution time',
+
+description:'Consider reducing the time spent parsing, compiling, and executing JS. '+
+'You may find delivering smaller JS payloads helps with this. [Learn '+
+'more](https://developers.google.com/web/tools/lighthouse/audits/bootup).',
+
+columnTotal:'Total',
+
+columnScriptEval:'Script Evaluation',
+
+columnScriptParse:'Script Parse',
+
+chromeExtensionsWarning:'Chrome extensions negatively affected this page\'s load performance. '+
+'Try auditing the page in incognito mode or from a Chrome profile without extensions.'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class BootupTime extends Audit{
+
+
+
+static get meta(){
+return{
+id:'bootup-time',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+scorePODR:600,
+scoreMedian:3500,
+thresholdInMs:50};
+
+}
+
+
+
+
+static getJavaScriptURLs(records){
+
+const urls=new Set();
+for(const record of records){
+if(record.resourceType===NetworkRequest.TYPES.Script){
+urls.add(record.url);
+}
+}
+
+return urls;
+}
+
+
+
+
+
+
+static getExecutionTimingsByURL(tasks,jsURLs){
+
+const result=new Map();
+
+for(const task of tasks){
+const jsURL=task.attributableURLs.find(url=>jsURLs.has(url));
+const fallbackURL=task.attributableURLs[0];
+const attributableURL=jsURL||fallbackURL;
+if(!attributableURL||attributableURL==='about:blank')continue;
+
+const timingByGroupId=result.get(attributableURL)||{};
+const originalTime=timingByGroupId[task.group.id]||0;
+timingByGroupId[task.group.id]=originalTime+task.selfTime;
+result.set(attributableURL,timingByGroupId);
+}
+
+return result;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const settings=context.settings||{};
+const trace=artifacts.traces[BootupTime.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[BootupTime.DEFAULT_PASS];
+const networkRecords=await NetworkRecords.request(devtoolsLog,context);
+const tasks=await MainThreadTasks.request(trace,context);
+const multiplier=settings.throttlingMethod==='simulate'?
+settings.throttling.cpuSlowdownMultiplier:1;
+
+const jsURLs=BootupTime.getJavaScriptURLs(networkRecords);
+const executionTimings=BootupTime.getExecutionTimingsByURL(tasks,jsURLs);
+
+let hadExcessiveChromeExtension=false;
+let totalBootupTime=0;
+const results=Array.from(executionTimings).
+map(([url,timingByGroupId])=>{
+
+let bootupTimeForURL=0;
+for(const[groupId,timespanMs]of Object.entries(timingByGroupId)){
+timingByGroupId[groupId]=timespanMs*multiplier;
+bootupTimeForURL+=timespanMs*multiplier;
+}
+
+
+if(bootupTimeForURL>=context.options.thresholdInMs){
+totalBootupTime+=bootupTimeForURL;
+}
+
+const scriptingTotal=timingByGroupId[taskGroups.scriptEvaluation.id]||0;
+const parseCompileTotal=timingByGroupId[taskGroups.scriptParseCompile.id]||0;
+
+hadExcessiveChromeExtension=hadExcessiveChromeExtension||
+url.startsWith('chrome-extension:')&&scriptingTotal>100;
+
+return{
+url:url,
+total:bootupTimeForURL,
+
+scripting:scriptingTotal,
+scriptParseCompile:parseCompileTotal};
+
+}).
+filter(result=>result.total>=context.options.thresholdInMs).
+sort((a,b)=>b.total-a.total);
+
+
+
+if(hadExcessiveChromeExtension){
+context.LighthouseRunWarnings.push(str_(UIStrings.chromeExtensionsWarning));
+}
+
+const summary={wastedMs:totalBootupTime};
+
+const headings=[
+{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
+{key:'total',granularity:1,itemType:'ms',text:str_(UIStrings.columnTotal)},
+{key:'scripting',granularity:1,itemType:'ms',text:str_(UIStrings.columnScriptEval)},
+{key:'scriptParseCompile',granularity:1,itemType:'ms',
+text:str_(UIStrings.columnScriptParse)}];
+
+
+const details=BootupTime.makeTableDetails(headings,results,summary);
+
+const score=Audit.computeLogNormalScore(
+totalBootupTime,
+context.options.scorePODR,
+context.options.scoreMedian);
+
+
+return{
+score,
+rawValue:totalBootupTime,
+displayValue:totalBootupTime>0?
+str_(i18n.UIStrings.seconds,{timeInMs:totalBootupTime}):'',
+details};
+
+}}
+
+
+module.exports=BootupTime;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/bootup-time.js");
+},{"../computed/main-thread-tasks.js":12,"../computed/network-records.js":29,"../lib/i18n/i18n.js":59,"../lib/network-request":67,"../lib/task-groups":71,"./audit":3}],"../audits/byte-efficiency/efficient-animated-content":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+'use strict';
+
+const NetworkRequest=require('../../lib/network-request');
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Use video formats for animated content',
+
+description:'Large GIFs are inefficient for delivering animated content. Consider using '+
+'MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save '+
+'network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+const GIF_BYTE_THRESHOLD=100*1024;
+
+class EfficientAnimatedContent extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'efficient-animated-content',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+
+static getPercentSavings(bytes){
+return Math.round(29.1*Math.log10(bytes)-100.7)/100;
+}
+
+
+
+
+
+
+static audit_(artifacts,networkRecords){
+const unoptimizedContent=networkRecords.filter(
+record=>record.mimeType==='image/gif'&&
+record.resourceType===NetworkRequest.TYPES.Image&&
+(record.resourceSize||0)>GIF_BYTE_THRESHOLD);
+
+
+
+const items=unoptimizedContent.map(record=>{
+const resourceSize=record.resourceSize||0;
+return{
+url:record.url,
+totalBytes:resourceSize,
+wastedBytes:Math.round(resourceSize*
+EfficientAnimatedContent.getPercentSavings(resourceSize))};
+
+});
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+items,
+headings};
+
+}}
+
+
+module.exports=EfficientAnimatedContent;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/efficient-animated-content.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/network-request":67,"./byte-efficiency-audit":4}],"../audits/byte-efficiency/offscreen-images":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const Sentry=require('../../lib/sentry');
+const URL=require('../../lib/url-shim');
+const i18n=require('../../lib/i18n/i18n.js');
+const Interactive=require('../../computed/metrics/interactive.js');
+const TraceOfTab=require('../../computed/trace-of-tab.js');
+
+const UIStrings={
+
+title:'Defer offscreen images',
+
+description:
+'Consider lazy-loading offscreen and hidden images after all critical resources have '+
+'finished loading to lower time to interactive. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const ALLOWABLE_OFFSCREEN_X=100;
+const ALLOWABLE_OFFSCREEN_Y=200;
+
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+const IGNORE_THRESHOLD_IN_PERCENT=75;
+const IGNORE_THRESHOLD_IN_MS=50;
+
+
+
+class OffscreenImages extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'offscreen-images',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['ImageUsage','ViewportDimensions','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+static computeVisiblePixels(imageRect,viewportDimensions){
+const innerWidth=viewportDimensions.innerWidth;
+const innerHeight=viewportDimensions.innerHeight;
+
+const top=Math.max(imageRect.top,-1*ALLOWABLE_OFFSCREEN_Y);
+const right=Math.min(imageRect.right,innerWidth+ALLOWABLE_OFFSCREEN_X);
+const bottom=Math.min(imageRect.bottom,innerHeight+ALLOWABLE_OFFSCREEN_Y);
+const left=Math.max(imageRect.left,-1*ALLOWABLE_OFFSCREEN_X);
+
+return Math.max(right-left,0)*Math.max(bottom-top,0);
+}
+
+
+
+
+
+
+static computeWaste(image,viewportDimensions){
+if(!image.networkRecord){
+return null;
+}
+
+const url=URL.elideDataURI(image.src);
+const totalPixels=image.clientWidth*image.clientHeight;
+const visiblePixels=this.computeVisiblePixels(image.clientRect,viewportDimensions);
+
+const wastedRatio=totalPixels===0?1:1-visiblePixels/totalPixels;
+const totalBytes=image.networkRecord.resourceSize;
+const wastedBytes=Math.round(totalBytes*wastedRatio);
+
+if(!Number.isFinite(wastedRatio)){
+return new Error(`Invalid image sizing information ${url}`);
+}
+
+return{
+url,
+requestStartTime:image.networkRecord.startTime,
+totalBytes,
+wastedBytes,
+wastedPercent:100*wastedRatio};
+
+}
+
+
+
+
+
+
+
+static filterLanternResults(images,lanternMetricData){
+const nodeTimings=lanternMetricData.pessimisticEstimate.nodeTimings;
+
+
+let lastLongTaskStartTime=0;
+
+
+const startTimesByURL=new Map();
+for(const[node,timing]of nodeTimings){
+if(node.type==='cpu'&&timing.duration>=50){
+lastLongTaskStartTime=Math.max(lastLongTaskStartTime,timing.startTime);
+}else if(node.type==='network'){
+const networkNode=node;
+startTimesByURL.set(networkNode.record.url,timing.startTime);
+}
+}
+
+return images.filter(image=>{
+
+if(image.wastedBytes<IGNORE_THRESHOLD_IN_BYTES)return false;
+if(image.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT)return false;
+
+const imageRequestStartTime=startTimesByURL.get(image.url)||0;
+return imageRequestStartTime<lastLongTaskStartTime-IGNORE_THRESHOLD_IN_MS;
+});
+}
+
+
+
+
+
+
+
+static filterObservedResults(images,interactiveTimestamp){
+return images.filter(image=>{
+if(image.wastedBytes<IGNORE_THRESHOLD_IN_BYTES)return false;
+if(image.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT)return false;
+return image.requestStartTime<interactiveTimestamp/1e6-IGNORE_THRESHOLD_IN_MS/1000;
+});
+}
+
+
+
+
+
+
+
+
+
+
+
+static computeWasteWithTTIGraph(results,graph,simulator){
+return super.computeWasteWithTTIGraph(results,graph,simulator,
+{includeLoad:false});
+}
+
+
+
+
+
+
+
+static async audit_(artifacts,networkRecords,context){
+const images=artifacts.ImageUsage;
+const viewportDimensions=artifacts.ViewportDimensions;
+const trace=artifacts.traces[ByteEfficiencyAudit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
+
+
+const warnings=[];
+const resultsMap=images.reduce((results,image)=>{
+const processed=OffscreenImages.computeWaste(image,viewportDimensions);
+if(processed===null){
+return results;
+}
+
+if(processed instanceof Error){
+warnings.push(processed.message);
+Sentry.captureException(processed,{tags:{audit:this.meta.id},level:'warning'});
+return results;
+}
+
+
+const existing=results.get(processed.url);
+if(!existing||existing.wastedBytes>processed.wastedBytes){
+results.set(processed.url,processed);
+}
+
+return results;
+},new Map());
+
+const settings=context.settings;
+
+let items;
+const unfilteredResults=Array.from(resultsMap.values());
+
+try{
+const interactive=await Interactive.request({trace,devtoolsLog,settings},context);
+
+
+const lanternInteractive=interactive;
+
+items=context.settings.throttlingMethod==='simulate'?
+OffscreenImages.filterLanternResults(unfilteredResults,lanternInteractive):
+
+OffscreenImages.filterObservedResults(unfilteredResults,interactive.timestamp);
+}catch(err){
+
+if(context.settings.throttlingMethod==='simulate'){
+throw err;
+}
+
+items=OffscreenImages.filterObservedResults(unfilteredResults,(
+await TraceOfTab.request(trace,context).then(tot=>tot.timestamps.traceEnd)));
+}
+
+
+const headings=[
+{key:'url',valueType:'thumbnail',label:''},
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+warnings,
+items,
+headings};
+
+}}
+
+
+module.exports=OffscreenImages;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/offscreen-images.js");
+},{"../../computed/metrics/interactive.js":18,"../../computed/trace-of-tab.js":33,"../../lib/i18n/i18n.js":59,"../../lib/sentry":69,"../../lib/url-shim":"url","./byte-efficiency-audit":4}],"../audits/byte-efficiency/render-blocking-resources":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const BaseNode=require('../../lib/dependency-graph/base-node');
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const UnusedCSS=require('./unused-css-rules');
+const NetworkRequest=require('../../lib/network-request');
+const TraceOfTab=require('../../computed/trace-of-tab.js');
+const LoadSimulator=require('../../computed/load-simulator.js');
+const FirstContentfulPaint=require('../../computed/metrics/first-contentful-paint.js');
+
+
+
+
+
+
+
+
+
+const MINIMUM_WASTED_MS=50;
+
+const UIStrings={
+
+title:'Eliminate render-blocking resources',
+
+description:'Resources are blocking the first paint of your page. Consider '+
+'delivering critical JS/CSS inline and deferring all non-critical '+
+'JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+
+
+
+function getNodesAndTimingByUrl(nodeTimings){
+
+const urlMap={};
+const nodes=Array.from(nodeTimings.keys());
+nodes.forEach(node=>{
+if(node.type!=='network')return;
+const nodeTiming=nodeTimings.get(node);
+if(!nodeTiming)return;
+
+urlMap[node.record.url]={node,nodeTiming};
+});
+
+return urlMap;
+}
+
+class RenderBlockingResources extends Audit{
+
+
+
+static get meta(){
+return{
+id:'render-blocking-resources',
+title:str_(UIStrings.title),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+description:str_(UIStrings.description),
+
+
+
+requiredArtifacts:['URL','TagsBlockingFirstPaint','traces']};
+
+}
+
+
+
+
+
+
+static async computeResults(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const simulatorData={devtoolsLog,settings:context.settings};
+const traceOfTab=await TraceOfTab.request(trace,context);
+const simulator=await LoadSimulator.request(simulatorData,context);
+const wastedCssBytes=await RenderBlockingResources.computeWastedCSSBytes(artifacts,context);
+
+const metricSettings={throttlingMethod:'simulate'};
+const metricComputationData={trace,devtoolsLog,simulator,settings:metricSettings};
+
+const fcpSimulation=await FirstContentfulPaint.request(metricComputationData,context);
+const fcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
+
+const nodesByUrl=getNodesAndTimingByUrl(fcpSimulation.optimisticEstimate.nodeTimings);
+
+const results=[];
+const deferredNodeIds=new Set();
+for(const resource of artifacts.TagsBlockingFirstPaint){
+
+if(resource.endTime*1000>fcpTsInMs)continue;
+
+if(!nodesByUrl[resource.tag.url])continue;
+
+const{node,nodeTiming}=nodesByUrl[resource.tag.url];
+
+
+
+
+node.traverse(node=>deferredNodeIds.add(node.id));
+
+
+const wastedMs=Math.round(nodeTiming.duration);
+if(wastedMs<MINIMUM_WASTED_MS)continue;
+
+results.push({
+url:resource.tag.url,
+totalBytes:resource.transferSize,
+wastedMs});
+
+}
+
+if(!results.length){
+return{results,wastedMs:0};
+}
+
+const wastedMs=RenderBlockingResources.estimateSavingsWithGraphs(
+simulator,
+fcpSimulation.optimisticGraph,
+deferredNodeIds,
+wastedCssBytes);
+
+
+return{results,wastedMs};
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static estimateSavingsWithGraphs(simulator,fcpGraph,deferredIds,wastedCssBytesByUrl){
+const originalEstimate=simulator.simulate(fcpGraph).timeInMs;
+
+let totalChildNetworkBytes=0;
+const minimalFCPGraph=fcpGraph.cloneWithRelationships(node=>{
+
+const canDeferRequest=deferredIds.has(node.id);
+if(node.type!==BaseNode.TYPES.NETWORK)return!canDeferRequest;
+
+const isStylesheet=
+node.record.resourceType===NetworkRequest.TYPES.Stylesheet;
+if(canDeferRequest&&isStylesheet){
+
+const wastedBytes=wastedCssBytesByUrl.get(node.record.url)||0;
+totalChildNetworkBytes+=(node.record.transferSize||0)-wastedBytes;
+}
+return!canDeferRequest;
+});
+
+
+const originalTransferSize=minimalFCPGraph.record.transferSize;
+const safeTransferSize=originalTransferSize||0;
+minimalFCPGraph.record.transferSize=safeTransferSize+totalChildNetworkBytes;
+const estimateAfterInline=simulator.simulate(minimalFCPGraph).timeInMs;
+minimalFCPGraph.record.transferSize=originalTransferSize;
+return Math.round(Math.max(originalEstimate-estimateAfterInline,0));
+}
+
+
+
+
+
+
+static async computeWastedCSSBytes(artifacts,context){
+const wastedBytesByUrl=new Map();
+try{
+
+const results=await UnusedCSS.audit(artifacts,context);
+
+for(const item of results.details.items){
+wastedBytesByUrl.set(item.url,item.wastedBytes);
+}
+}catch(_){}
+
+return wastedBytesByUrl;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const{results,wastedMs}=await RenderBlockingResources.computeResults(artifacts,context);
+
+let displayValue='';
+if(results.length>0){
+displayValue=str_(i18n.UIStrings.displayValueMsSavings,{wastedMs});
+}
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnWastedMs)}];
+
+
+const details=Audit.makeOpportunityDetails(headings,results,wastedMs);
+
+return{
+displayValue,
+score:ByteEfficiencyAudit.scoreForWastedMs(wastedMs),
+rawValue:wastedMs,
+details};
+
+}}
+
+
+module.exports=RenderBlockingResources;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/render-blocking-resources.js");
+},{"../../computed/load-simulator.js":10,"../../computed/metrics/first-contentful-paint.js":15,"../../computed/trace-of-tab.js":33,"../../lib/dependency-graph/base-node":48,"../../lib/i18n/i18n.js":59,"../../lib/network-request":67,"../audit":3,"./byte-efficiency-audit":4,"./unused-css-rules":"../audits/byte-efficiency/unused-css-rules"}],"../audits/byte-efficiency/total-byte-weight":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const NetworkRecords=require('../../computed/network-records.js');
+
+const UIStrings={
+
+title:'Avoids enormous network payloads',
+
+failureTitle:'Avoid enormous network payloads',
+
+description:
+'Large network payloads cost users real money and are highly correlated with '+
+'long load times. [Learn '+
+'more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).',
+
+displayValue:'Total size was {totalBytes, number, bytes}\xa0KB'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class TotalByteWeight extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'total-byte-weight',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['devtoolsLogs','traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+scorePODR:2500*1024,
+scoreMedian:4000*1024};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
+const records=await NetworkRecords.request(devtoolsLog,context);
+
+let totalBytes=0;
+
+let results=[];
+records.forEach(record=>{
+
+
+if(record.parsedURL.scheme==='data'||!record.finished)return;
+
+const result={
+url:record.url,
+totalBytes:record.transferSize};
+
+
+totalBytes+=result.totalBytes;
+results.push(result);
+});
+const totalCompletedRequests=results.length;
+results=results.sort((itemA,itemB)=>itemB.totalBytes-itemA.totalBytes).slice(0,10);
+
+const score=ByteEfficiencyAudit.computeLogNormalScore(
+totalBytes,
+context.options.scorePODR,
+context.options.scoreMedian);
+
+
+const headings=[
+{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',itemType:'bytes',text:str_(i18n.UIStrings.columnSize)}];
+
+
+const tableDetails=ByteEfficiencyAudit.makeTableDetails(headings,results);
+
+return{
+score,
+rawValue:totalBytes,
+displayValue:str_(UIStrings.displayValue,{totalBytes}),
+extendedInfo:{
+value:{
+results,
+totalCompletedRequests}},
+
+
+details:tableDetails};
+
+}}
+
+
+module.exports=TotalByteWeight;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/total-byte-weight.js");
+},{"../../computed/network-records.js":29,"../../lib/i18n/i18n.js":59,"./byte-efficiency-audit":4}],"../audits/byte-efficiency/unminified-css":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const UnusedCSSRules=require('./unused-css-rules');
+const i18n=require('../../lib/i18n/i18n.js');
+const computeTokenLength=require('../../lib/minification-estimator').computeCSSTokenLength;
+
+const UIStrings={
+
+title:'Minify CSS',
+
+description:'Minifying CSS files can reduce network payload sizes. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/minify-css).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_PERCENT=5;
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+
+
+
+
+class UnminifiedCSS extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'unminified-css',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['CSSUsage','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+
+static computeTokenLength(content){
+return computeTokenLength(content);
+}
+
+
+
+
+
+
+
+static computeWaste(stylesheet,networkRecord,pageUrl){
+const content=stylesheet.content;
+const totalTokenLength=UnminifiedCSS.computeTokenLength(content);
+
+let url=stylesheet.header.sourceURL;
+if(!url||url===pageUrl){
+const contentPreview=UnusedCSSRules.determineContentPreview(stylesheet.content);
+url=contentPreview;
+}
+
+const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,content.length,
+'Stylesheet');
+const wastedRatio=1-totalTokenLength/content.length;
+const wastedBytes=Math.round(totalBytes*wastedRatio);
+
+return{
+url,
+totalBytes,
+wastedBytes,
+wastedPercent:100*wastedRatio};
+
+}
+
+
+
+
+
+
+static audit_(artifacts,networkRecords){
+const pageUrl=artifacts.URL.finalUrl;
+const items=[];
+for(const stylesheet of artifacts.CSSUsage.stylesheets){
+const networkRecord=networkRecords.
+find(record=>record.url===stylesheet.header.sourceURL);
+if(!stylesheet.content)continue;
+
+const result=UnminifiedCSS.computeWaste(stylesheet,networkRecord,pageUrl);
+
+
+
+if(result.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT||
+result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES||
+!Number.isFinite(result.wastedBytes))continue;
+items.push(result);
+}
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{items,headings};
+}}
+
+
+module.exports=UnminifiedCSS;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/unminified-css.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/minification-estimator":65,"./byte-efficiency-audit":4,"./unused-css-rules":"../audits/byte-efficiency/unused-css-rules"}],"../audits/byte-efficiency/unminified-javascript":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const computeTokenLength=require('../../lib/minification-estimator').computeJSTokenLength;
+
+const UIStrings={
+
+title:'Minify JavaScript',
+
+description:'Minifying JavaScript files can reduce payload sizes and script parse time. '+
+'[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_PERCENT=10;
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+
+
+
+
+
+
+
+
+
+
+
+class UnminifiedJavaScript extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'unminified-javascript',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['Scripts','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+static computeWaste(scriptContent,networkRecord){
+const contentLength=scriptContent.length;
+const totalTokenLength=computeTokenLength(scriptContent);
+
+const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,contentLength,
+'Script');
+const wastedRatio=1-totalTokenLength/contentLength;
+const wastedBytes=Math.round(totalBytes*wastedRatio);
+
+return{
+url:networkRecord.url,
+totalBytes,
+wastedBytes,
+wastedPercent:100*wastedRatio};
+
+}
+
+
+
+
+
+
+static audit_(artifacts,networkRecords){
+
+const items=[];
+const warnings=[];
+for(const requestId of Object.keys(artifacts.Scripts)){
+const scriptContent=artifacts.Scripts[requestId];
+const networkRecord=networkRecords.find(record=>record.requestId===requestId);
+if(!networkRecord||!scriptContent)continue;
+
+try{
+const result=UnminifiedJavaScript.computeWaste(scriptContent,networkRecord);
+
+
+if(result.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT||
+result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES||
+!Number.isFinite(result.wastedBytes))continue;
+items.push(result);
+}catch(err){
+warnings.push(`Unable to process ${networkRecord.url}: ${err.message}`);
+}
+}
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+items,
+warnings,
+headings};
+
+}}
+
+
+module.exports=UnminifiedJavaScript;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/unminified-javascript.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/minification-estimator":65,"./byte-efficiency-audit":4}],"../audits/byte-efficiency/unused-css-rules":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Defer unused CSS',
+
+description:'Remove unused rules from stylesheets to reduce unnecessary '+
+'bytes consumed by network activity. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+const PREVIEW_LENGTH=100;
+
+
+
+class UnusedCSSRules extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'unused-css-rules',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['CSSUsage','URL','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+static indexStylesheetsById(styles,networkRecords){
+const indexedNetworkRecords=networkRecords.
+reduce((indexed,record)=>{
+indexed[record.url]=record;
+return indexed;
+},{});
+
+return styles.reduce((indexed,stylesheet)=>{
+indexed[stylesheet.header.styleSheetId]=Object.assign({
+usedRules:[],
+networkRecord:indexedNetworkRecords[stylesheet.header.sourceURL]},
+stylesheet);
+return indexed;
+},{});
+}
+
+
+
+
+
+
+static indexUsedRules(rules,indexedStylesheets){
+rules.forEach(rule=>{
+const stylesheetInfo=indexedStylesheets[rule.styleSheetId];
+
+if(!stylesheetInfo){
+return;
+}
+
+if(rule.used){
+stylesheetInfo.usedRules.push(rule);
+}
+});
+}
+
+
+
+
+
+static computeUsage(stylesheetInfo){
+let usedUncompressedBytes=0;
+const totalUncompressedBytes=stylesheetInfo.content.length;
+
+for(const usedRule of stylesheetInfo.usedRules){
+usedUncompressedBytes+=usedRule.endOffset-usedRule.startOffset;
+}
+
+const totalTransferredBytes=ByteEfficiencyAudit.estimateTransferSize(
+stylesheetInfo.networkRecord,totalUncompressedBytes,'Stylesheet');
+const percentUnused=(totalUncompressedBytes-usedUncompressedBytes)/totalUncompressedBytes;
+const wastedBytes=Math.round(percentUnused*totalTransferredBytes);
+
+return{
+wastedBytes,
+wastedPercent:percentUnused*100,
+totalBytes:totalTransferredBytes};
+
+}
+
+
+
+
+
+
+static determineContentPreview(content){
+let preview=(content||'').
+slice(0,PREVIEW_LENGTH*5).
+replace(/( {2,}|\t)+/g,' ').
+replace(/\n\s+}/g,'\n}').
+trim();
+
+if(preview.length>PREVIEW_LENGTH){
+const firstRuleStart=preview.indexOf('{');
+const firstRuleEnd=preview.indexOf('}');
+
+if(firstRuleStart===-1||firstRuleEnd===-1||
+firstRuleStart>firstRuleEnd||
+firstRuleStart>PREVIEW_LENGTH){
+
+preview=preview.slice(0,PREVIEW_LENGTH)+'...';
+}else if(firstRuleEnd<PREVIEW_LENGTH){
+
+preview=preview.slice(0,firstRuleEnd+1)+' ...';
+}else{
+
+const lastSemicolonIndex=preview.slice(0,PREVIEW_LENGTH).lastIndexOf(';');
+preview=lastSemicolonIndex<firstRuleStart?
+preview.slice(0,PREVIEW_LENGTH)+'... } ...':
+preview.slice(0,lastSemicolonIndex+1)+' ... } ...';
+}
+}
+
+return preview;
+}
+
+
+
+
+
+
+static mapSheetToResult(stylesheetInfo,pageUrl){
+let url=stylesheetInfo.header.sourceURL;
+if(!url||url===pageUrl){
+const contentPreview=UnusedCSSRules.determineContentPreview(stylesheetInfo.content);
+url=contentPreview;
+}
+
+const usage=UnusedCSSRules.computeUsage(stylesheetInfo);
+
+return Object.assign({url},usage);
+}
+
+
+
+
+
+
+static audit_(artifacts,networkRecords){
+const styles=artifacts.CSSUsage.stylesheets;
+const usage=artifacts.CSSUsage.rules;
+const pageUrl=artifacts.URL.finalUrl;
+
+return Promise.resolve(networkRecords).then(networkRecords=>{
+const indexedSheets=UnusedCSSRules.indexStylesheetsById(styles,networkRecords);
+UnusedCSSRules.indexUsedRules(usage,indexedSheets);
+
+const items=Object.keys(indexedSheets).
+map(sheetId=>UnusedCSSRules.mapSheetToResult(indexedSheets[sheetId],pageUrl)).
+filter(sheet=>sheet&&sheet.wastedBytes>IGNORE_THRESHOLD_IN_BYTES);
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+items,
+headings};
+
+});
+}}
+
+
+module.exports=UnusedCSSRules;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/unused-css-rules.js");
+},{"../../lib/i18n/i18n.js":59,"./byte-efficiency-audit":4}],"../audits/byte-efficiency/unused-javascript":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Remove unused JavaScript',
+
+description:'Remove unused JavaScript to reduce bytes consumed by network activity.'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+
+class UnusedJavaScript extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'unused-javascript',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['JsUsage','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+static computeWaste(script){
+let maximumEndOffset=0;
+for(const func of script.functions){
+for(const range of func.ranges){
+maximumEndOffset=Math.max(maximumEndOffset,range.endOffset);
+}
+}
+
+
+
+const unusedByIndex=new Uint8Array(maximumEndOffset);
+for(const func of script.functions){
+for(const range of func.ranges){
+if(range.count===0){
+for(let i=range.startOffset;i<range.endOffset;i++){
+unusedByIndex[i]=1;
+}
+}
+}
+}
+
+let unused=0;
+for(const x of unusedByIndex){
+unused+=x;
+}
+
+return{
+unusedLength:unused,
+contentLength:maximumEndOffset};
+
+}
+
+
+
+
+
+
+static mergeWaste(wasteData,networkRecord){
+let unusedLength=0;
+let contentLength=0;
+for(const usage of wasteData){
+unusedLength+=usage.unusedLength;
+contentLength+=usage.contentLength;
+}
+
+const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,contentLength,
+'Script');
+const wastedRatio=unusedLength/contentLength||0;
+const wastedBytes=Math.round(totalBytes*wastedRatio);
+
+return{
+url:networkRecord.url,
+totalBytes,
+wastedBytes,
+wastedPercent:100*wastedRatio};
+
+}
+
+
+
+
+
+
+static audit_(artifacts,networkRecords){
+
+const scriptsByUrl=new Map();
+for(const script of artifacts.JsUsage){
+const scripts=scriptsByUrl.get(script.url)||[];
+scripts.push(script);
+scriptsByUrl.set(script.url,scripts);
+}
+
+const items=[];
+for(const[url,scripts]of scriptsByUrl.entries()){
+const networkRecord=networkRecords.find(record=>record.url===url);
+if(!networkRecord)continue;
+const wasteData=scripts.map(UnusedJavaScript.computeWaste);
+const item=UnusedJavaScript.mergeWaste(wasteData,networkRecord);
+if(item.wastedBytes<=IGNORE_THRESHOLD_IN_BYTES)continue;
+items.push(item);
+}
+
+return{
+items,
+headings:[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}]};
+
+
+}}
+
+
+module.exports=UnusedJavaScript;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/unused-javascript.js");
+},{"../../lib/i18n/i18n.js":59,"./byte-efficiency-audit":4}],"../audits/byte-efficiency/uses-long-cache-ttl":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const assert=require('assert');
+
+const parseCacheControl=require('parse-cache-control');
+const Audit=require('../audit');
+const NetworkRequest=require('../../lib/network-request');
+const URL=require('../../lib/url-shim');
+const linearInterpolation=require('../../lib/statistics').linearInterpolation;
+const i18n=require('../../lib/i18n/i18n.js');
+const NetworkRecords=require('../../computed/network-records.js');
+
+const UIStrings={
+
+title:'Uses efficient cache policy on static assets',
+
+failureTitle:'Serve static assets with an efficient cache policy',
+
+description:
+'A long cache lifetime can speed up repeat visits to your page. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/cache-policy).',
+
+displayValue:`{itemCount, plural,
+ =1 {1 resource found}
+ other {# resources found}
+ }`};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+const IGNORE_THRESHOLD_IN_PERCENT=0.925;
+
+class CacheHeaders extends Audit{
+
+
+
+static get meta(){
+return{
+id:'uses-long-cache-ttl',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['devtoolsLogs','traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:4*1024,
+scoreMedian:128*1024};
+
+}
+
+
+
+
+
+
+
+static getCacheHitProbability(maxAgeInSeconds){
+
+
+
+
+
+const RESOURCE_AGE_IN_HOURS_DECILES=[0,0.2,1,3,8,12,24,48,72,168,8760,Infinity];
+assert.ok(RESOURCE_AGE_IN_HOURS_DECILES.length===12,'deciles 0-10 and 1 for overflow');
+
+const maxAgeInHours=maxAgeInSeconds/3600;
+const upperDecileIndex=RESOURCE_AGE_IN_HOURS_DECILES.findIndex(
+decile=>decile>=maxAgeInHours);
+
+
+
+if(upperDecileIndex===RESOURCE_AGE_IN_HOURS_DECILES.length-1)return 1;
+if(upperDecileIndex===0)return 0;
+
+
+const upperDecileValue=RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex];
+const lowerDecileValue=RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex-1];
+const upperDecile=upperDecileIndex/10;
+const lowerDecile=(upperDecileIndex-1)/10;
+
+
+return linearInterpolation(
+lowerDecileValue,
+lowerDecile,
+upperDecileValue,
+upperDecile,
+maxAgeInHours);
+
+}
+
+
+
+
+
+
+
+
+
+static computeCacheLifetimeInSeconds(headers,cacheControl){
+if(cacheControl){
+
+if(cacheControl['no-cache']||cacheControl['no-store'])return 0;
+const maxAge=cacheControl['max-age'];
+if(maxAge!==undefined&&Number.isFinite(maxAge))return Math.max(maxAge,0);
+}else if((headers.get('pragma')||'').includes('no-cache')){
+
+return 0;
+}
+
+const expiresHeaders=headers.get('expires');
+if(expiresHeaders){
+const expires=new Date(expiresHeaders).getTime();
+
+if(!expires)return 0;
+return Math.max(0,Math.ceil((expires-Date.now())/1000));
+}
+
+return null;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static isCacheableAsset(record){
+const CACHEABLE_STATUS_CODES=new Set([200,203,206]);
+
+
+const STATIC_RESOURCE_TYPES=new Set([
+NetworkRequest.TYPES.Font,
+NetworkRequest.TYPES.Image,
+NetworkRequest.TYPES.Media,
+NetworkRequest.TYPES.Script,
+NetworkRequest.TYPES.Stylesheet]);
+
+
+const resourceUrl=record.url;
+return(
+CACHEABLE_STATUS_CODES.has(record.statusCode)&&
+STATIC_RESOURCE_TYPES.has(record.resourceType||'Other')&&
+!resourceUrl.includes('data:'));
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+return NetworkRecords.request(devtoolsLogs,context).then(records=>{
+const results=[];
+let queryStringCount=0;
+let totalWastedBytes=0;
+
+for(const record of records){
+if(!CacheHeaders.isCacheableAsset(record))continue;
+
+
+const headers=new Map();
+for(const header of record.responseHeaders||[]){
+if(headers.has(header.name.toLowerCase())){
+const previousHeaderValue=headers.get(header.name.toLowerCase());
+headers.set(header.name.toLowerCase(),
+`${previousHeaderValue}, ${header.value}`);
+}else{
+headers.set(header.name.toLowerCase(),header.value);
+}
+}
+
+const cacheControl=parseCacheControl(headers.get('cache-control'));
+let cacheLifetimeInSeconds=CacheHeaders.computeCacheLifetimeInSeconds(
+headers,
+cacheControl);
+
+
+
+if(cacheLifetimeInSeconds===0)continue;
+cacheLifetimeInSeconds=cacheLifetimeInSeconds||0;
+
+const cacheHitProbability=CacheHeaders.getCacheHitProbability(cacheLifetimeInSeconds);
+if(cacheHitProbability>IGNORE_THRESHOLD_IN_PERCENT)continue;
+
+const url=URL.elideDataURI(record.url);
+const totalBytes=record.transferSize||0;
+const wastedBytes=(1-cacheHitProbability)*totalBytes;
+
+totalWastedBytes+=wastedBytes;
+if(url.includes('?'))queryStringCount++;
+
+results.push({
+url,
+cacheControl,
+cacheLifetimeMs:cacheLifetimeInSeconds*1000,
+cacheHitProbability,
+totalBytes,
+wastedBytes});
+
+}
+
+results.sort(
+(a,b)=>a.cacheLifetimeMs-b.cacheLifetimeMs||b.totalBytes-a.totalBytes);
+
+
+const score=Audit.computeLogNormalScore(
+totalWastedBytes,
+context.options.scorePODR,
+context.options.scoreMedian);
+
+
+const headings=[
+{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
+
+{key:'cacheLifetimeMs',itemType:'ms',text:str_(i18n.UIStrings.columnCacheTTL),
+displayUnit:'duration'},
+{key:'totalBytes',itemType:'bytes',text:str_(i18n.UIStrings.columnSize),
+displayUnit:'kb',granularity:1}];
+
+
+const summary={wastedBytes:totalWastedBytes};
+const details=Audit.makeTableDetails(headings,results,summary);
+
+return{
+score,
+rawValue:totalWastedBytes,
+displayValue:str_(UIStrings.displayValue,{itemCount:results.length}),
+extendedInfo:{
+value:{
+results,
+queryStringCount}},
+
+
+details};
+
+});
+}}
+
+
+module.exports=CacheHeaders;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js");
+},{"../../computed/network-records.js":29,"../../lib/i18n/i18n.js":59,"../../lib/network-request":67,"../../lib/statistics":70,"../../lib/url-shim":"url","../audit":3,"assert":78,"parse-cache-control":127}],"../audits/byte-efficiency/uses-optimized-images":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const URL=require('../../lib/url-shim');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Efficiently encode images',
+
+description:'Optimized images load faster and consume less cellular data. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_BYTES=4096;
+
+class UsesOptimizedImages extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'uses-optimized-images',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['OptimizedImages','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+static computeSavings(image){
+const bytes=image.originalSize-image.jpegSize;
+const percent=100*bytes/image.originalSize;
+return{bytes,percent};
+}
+
+
+
+
+
+static audit_(artifacts){
+const images=artifacts.OptimizedImages;
+
+
+const items=[];
+const warnings=[];
+for(const image of images){
+if(image.failed){
+warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
+continue;
+}else if(/(jpeg|bmp)/.test(image.mimeType)===false||
+image.originalSize<image.jpegSize+IGNORE_THRESHOLD_IN_BYTES){
+continue;
+}
+
+const url=URL.elideDataURI(image.url);
+const jpegSavings=UsesOptimizedImages.computeSavings(image);
+
+items.push({
+url,
+fromProtocol:image.fromProtocol,
+isCrossOrigin:!image.isSameOrigin,
+totalBytes:image.originalSize,
+wastedBytes:jpegSavings.bytes});
+
+}
+
+
+const headings=[
+{key:'url',valueType:'thumbnail',label:''},
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+warnings,
+items,
+headings};
+
+}}
+
+
+module.exports=UsesOptimizedImages;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/url-shim":"url","./byte-efficiency-audit":4}],"../audits/byte-efficiency/uses-responsive-images":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const Sentry=require('../../lib/sentry');
+const URL=require('../../lib/url-shim');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Properly size images',
+
+description:
+'Serve images that are appropriately-sized to save cellular data '+
+'and improve load time. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+
+class UsesResponsiveImages extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'uses-responsive-images',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['ImageUsage','ViewportDimensions','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+static computeWaste(image,DPR){
+
+if(!image.networkRecord){
+return null;
+}
+
+const url=URL.elideDataURI(image.src);
+const actualPixels=image.naturalWidth*image.naturalHeight;
+const usedPixels=image.clientWidth*image.clientHeight*Math.pow(DPR,2);
+const wastedRatio=1-usedPixels/actualPixels;
+const totalBytes=image.networkRecord.resourceSize;
+const wastedBytes=Math.round(totalBytes*wastedRatio);
+
+
+
+if(!usedPixels){
+return null;
+}
+
+if(!Number.isFinite(wastedRatio)){
+return new Error(`Invalid image sizing information ${url}`);
+}
+
+return{
+url,
+totalBytes,
+wastedBytes,
+wastedPercent:100*wastedRatio};
+
+}
+
+
+
+
+
+static audit_(artifacts){
+const images=artifacts.ImageUsage;
+const DPR=artifacts.ViewportDimensions.devicePixelRatio;
+
+
+const warnings=[];
+
+const resultsMap=new Map();
+images.forEach(image=>{
+
+if(!image.networkRecord||image.networkRecord.mimeType==='image/svg+xml'){
+return;
+}
+
+const processed=UsesResponsiveImages.computeWaste(image,DPR);
+if(!processed)return;
+
+if(processed instanceof Error){
+warnings.push(processed.message);
+Sentry.captureException(processed,{tags:{audit:this.meta.id},level:'warning'});
+return;
+}
+
+
+const existing=resultsMap.get(processed.url);
+if(!existing||existing.wastedBytes>processed.wastedBytes){
+resultsMap.set(processed.url,processed);
+}
+});
+
+const items=Array.from(resultsMap.values()).
+filter(item=>item.wastedBytes>IGNORE_THRESHOLD_IN_BYTES);
+
+
+const headings=[
+{key:'url',valueType:'thumbnail',label:''},
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+warnings,
+items,
+headings};
+
+}}
+
+
+module.exports=UsesResponsiveImages;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/sentry":69,"../../lib/url-shim":"url","./byte-efficiency-audit":4}],"../audits/byte-efficiency/uses-text-compression":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const URL=require('../../lib/url-shim');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Enable text compression',
+
+description:'Text-based resources should be served with compression (gzip, deflate or'+
+' brotli) to minimize total network bytes.'+
+' [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_BYTES=1400;
+const IGNORE_THRESHOLD_IN_PERCENT=0.1;
+
+class ResponsesAreCompressed extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'uses-text-compression',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['ResponseCompression','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+static audit_(artifacts){
+const uncompressedResponses=artifacts.ResponseCompression;
+
+
+const items=[];
+uncompressedResponses.forEach(record=>{
+
+if(!record.gzipSize||record.gzipSize<0)return;
+
+const originalSize=record.resourceSize;
+const gzipSize=record.gzipSize;
+const gzipSavings=originalSize-gzipSize;
+
+
+
+if(1-gzipSize/originalSize<IGNORE_THRESHOLD_IN_PERCENT||
+gzipSavings<IGNORE_THRESHOLD_IN_BYTES||
+record.transferSize<gzipSize)
+{
+return;
+}
+
+
+const url=URL.elideDataURI(record.url);
+const isDuplicate=items.find(item=>item.url===url&&
+item.totalBytes===record.resourceSize);
+if(isDuplicate){
+return;
+}
+
+items.push({
+url,
+totalBytes:originalSize,
+wastedBytes:gzipSavings});
+
+});
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+items,
+headings};
+
+}}
+
+
+module.exports=ResponsesAreCompressed;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/uses-text-compression.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/url-shim":"url","./byte-efficiency-audit":4}],"../audits/byte-efficiency/uses-webp-images":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const URL=require('../../lib/url-shim');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+title:'Serve images in next-gen formats',
+
+description:'Image formats like JPEG 2000, JPEG XR, and WebP often provide better '+
+'compression than PNG or JPEG, which means faster downloads and less data consumption. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const IGNORE_THRESHOLD_IN_BYTES=8192;
+
+class UsesWebPImages extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+id:'uses-webp-images',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['OptimizedImages','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+static computeSavings(image){
+const bytes=image.originalSize-image.webpSize;
+const percent=100*bytes/image.originalSize;
+return{bytes,percent};
+}
+
+
+
+
+
+static audit_(artifacts){
+const images=artifacts.OptimizedImages;
+
+
+const items=[];
+const warnings=[];
+for(const image of images){
+if(image.failed){
+warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
+continue;
+}else if(image.originalSize<image.webpSize+IGNORE_THRESHOLD_IN_BYTES){
+continue;
+}
+
+const url=URL.elideDataURI(image.url);
+const webpSavings=UsesWebPImages.computeSavings(image);
+
+items.push({
+url,
+fromProtocol:image.fromProtocol,
+isCrossOrigin:!image.isSameOrigin,
+totalBytes:image.originalSize,
+wastedBytes:webpSavings.bytes});
+
+}
+
+
+const headings=[
+{key:'url',valueType:'thumbnail',label:''},
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'totalBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnSize)},
+{key:'wastedBytes',valueType:'bytes',label:str_(i18n.UIStrings.columnWastedBytes)}];
+
+
+return{
+warnings,
+items,
+headings};
+
+}}
+
+
+module.exports=UsesWebPImages;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/uses-webp-images.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/url-shim":"url","./byte-efficiency-audit":4}],"../audits/content-width":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+
+class ContentWidth extends Audit{
+
+
+
+static get meta(){
+return{
+id:'content-width',
+title:'Content is sized correctly for the viewport',
+failureTitle:'Content is not sized correctly for the viewport',
+description:'If the width of your app\'s content doesn\'t match the width '+
+'of the viewport, your app might not be optimized for mobile screens. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/content-sized-correctly-for-viewport).',
+requiredArtifacts:['ViewportDimensions','HostUserAgent']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const userAgent=artifacts.HostUserAgent;
+const viewportWidth=artifacts.ViewportDimensions.innerWidth;
+const windowWidth=artifacts.ViewportDimensions.outerWidth;
+const widthsMatch=viewportWidth===windowWidth;
+
+
+const isMobileHost=userAgent.includes('Android')||userAgent.includes('Mobile');
+const isMobile=context.settings.emulatedFormFactor==='mobile'||
+context.settings.emulatedFormFactor!=='desktop'&&isMobileHost;
+
+if(isMobile){
+return{
+rawValue:widthsMatch,
+explanation:this.createExplanation(widthsMatch,artifacts.ViewportDimensions)};
+
+}else{
+return{
+rawValue:true,
+notApplicable:true};
+
+}
+}
+
+
+
+
+
+
+static createExplanation(match,artifact){
+if(match){
+return'';
+}
+
+return'The viewport size is '+artifact.innerWidth+'px, '+
+'whereas the window size is '+artifact.outerWidth+'px.';
+}}
+
+
+module.exports=ContentWidth;
+
+},{"./audit":3}],"../audits/critical-request-chains":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const i18n=require('../lib/i18n/i18n.js');
+const ComputedChains=require('../computed/critical-request-chains.js');
+
+const UIStrings={
+
+title:'Minimize Critical Requests Depth',
+
+description:'The Critical Request Chains below show you what resources are '+
+'loaded with a high priority. Consider reducing '+
+'the length of chains, reducing the download size of resources, or '+
+'deferring the download of unnecessary resources to improve page load. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).',
+
+displayValue:`{itemCount, plural,
+ =1 {1 chain found}
+ other {# chains found}
+ }`};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class CriticalRequestChains extends Audit{
+
+
+
+static get meta(){
+return{
+id:'critical-request-chains',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+requiredArtifacts:['devtoolsLogs','URL']};
+
+}
+
+
+
+
+
+
+
+static _traverse(tree,cb){
+
+
+
+
+
+
+function walk(node,depth,startTime,transferSize=0){
+const children=Object.keys(node);
+if(children.length===0){
+return;
+}
+children.forEach(id=>{
+const child=node[id];
+if(!startTime){
+startTime=child.request.startTime;
+}
+
+
+cb({
+depth,
+id,
+node:child,
+chainDuration:(child.request.endTime-startTime)*1000,
+chainTransferSize:transferSize+child.request.transferSize});
+
+
+
+if(child.children){
+walk(child.children,depth+1,startTime);
+}
+},'');
+}
+
+walk(tree,0);
+}
+
+
+
+
+
+
+static _getLongestChain(tree){
+const longest={
+duration:0,
+length:0,
+transferSize:0};
+
+CriticalRequestChains._traverse(tree,opts=>{
+const duration=opts.chainDuration;
+if(duration>longest.duration){
+longest.duration=duration;
+longest.transferSize=opts.chainTransferSize;
+longest.length=opts.depth;
+}
+});
+
+longest.length++;
+return longest;
+}
+
+
+
+
+
+static flattenRequests(tree){
+
+const flattendChains={};
+
+const chainMap=new Map();
+
+
+function flatten(opts){
+const request=opts.node.request;
+const simpleRequest={
+url:request.url,
+startTime:request.startTime,
+endTime:request.endTime,
+responseReceivedTime:request.responseReceivedTime,
+transferSize:request.transferSize};
+
+
+let chain=chainMap.get(opts.id);
+if(chain){
+chain.request=simpleRequest;
+}else{
+chain={
+request:simpleRequest};
+
+flattendChains[opts.id]=chain;
+}
+
+if(opts.node.children){
+for(const chainId of Object.keys(opts.node.children)){
+
+const childChain={
+request:{}};
+
+chainMap.set(chainId,childChain);
+if(!chain.children){
+chain.children={};
+}
+chain.children[chainId]=childChain;
+}
+}
+chainMap.set(opts.id,chain);
+}
+
+CriticalRequestChains._traverse(tree,flatten);
+
+return flattendChains;
+}
+
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const URL=artifacts.URL;
+return ComputedChains.request({devtoolsLog,URL},context).then(chains=>{
+let chainCount=0;
+
+
+
+
+function walk(node,depth){
+const childIds=Object.keys(node);
+
+childIds.forEach(id=>{
+const child=node[id];
+if(child.children){
+walk(child.children,depth+1);
+}else{
+
+chainCount++;
+}
+},'');
+}
+
+const flattenedChains=CriticalRequestChains.flattenRequests(chains);
+
+
+const initialNavKey=Object.keys(flattenedChains)[0];
+const initialNavChildren=initialNavKey&&flattenedChains[initialNavKey].children;
+if(initialNavChildren&&Object.keys(initialNavChildren).length>0){
+walk(initialNavChildren,0);
+}
+
+const longestChain=CriticalRequestChains._getLongestChain(flattenedChains);
+
+return{
+rawValue:chainCount===0,
+notApplicable:chainCount===0,
+displayValue:chainCount?str_(UIStrings.displayValue,{itemCount:chainCount}):'',
+extendedInfo:{
+value:{
+chains:flattenedChains,
+longestChain}},
+
+
+details:{
+type:'criticalrequestchain',
+chains:flattenedChains,
+longestChain}};
+
+
+});
+}}
+
+
+module.exports=CriticalRequestChains;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/critical-request-chains.js");
+},{"../computed/critical-request-chains.js":9,"../lib/i18n/i18n.js":59,"./audit":3}],"../audits/deprecations":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const Audit=require('./audit');
+const Util=require('../report/html/renderer/util');
+
+class Deprecations extends Audit{
+
+
+
+static get meta(){
+return{
+id:'deprecations',
+title:'Avoids deprecated APIs',
+failureTitle:'Uses deprecated APIs',
+description:'Deprecated APIs will eventually be removed from the browser. '+
+'[Learn more](https://www.chromestatus.com/features#deprecated).',
+requiredArtifacts:['ChromeConsoleMessages']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const entries=artifacts.ChromeConsoleMessages;
+
+const deprecations=entries.filter(log=>log.entry.source==='deprecation').map(log=>{
+return{
+value:log.entry.text,
+url:log.entry.url||'',
+source:log.entry.source,
+lineNumber:log.entry.lineNumber};
+
+});
+
+const headings=[
+{key:'value',itemType:'code',text:'Deprecation / Warning'},
+{key:'url',itemType:'url',text:'URL'},
+{key:'lineNumber',itemType:'text',text:'Line'}];
+
+const details=Audit.makeTableDetails(headings,deprecations);
+
+let displayValue='';
+if(deprecations.length>1){
+displayValue=`${Util.formatNumber(deprecations.length)} warnings found`;
+}else if(deprecations.length===1){
+displayValue=`${deprecations.length} warning found`;
+}
+
+return{
+rawValue:deprecations.length===0,
+displayValue,
+extendedInfo:{
+value:deprecations},
+
+details};
+
+}}
+
+
+module.exports=Deprecations;
+
+},{"../report/html/renderer/util":74,"./audit":3}],"../audits/dobetterweb/appcache-manifest":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+
+class AppCacheManifestAttr extends Audit{
+
+
+
+static get meta(){
+return{
+id:'appcache-manifest',
+title:'Avoids Application Cache',
+failureTitle:'Uses Application Cache',
+description:'Application Cache is deprecated. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/appcache).',
+requiredArtifacts:['AppCacheManifest']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const usingAppcache=artifacts.AppCacheManifest!==null;
+const displayValue=usingAppcache?`Found "${artifacts.AppCacheManifest}"`:'';
+
+return{
+rawValue:!usingAppcache,
+displayValue};
+
+}}
+
+
+module.exports=AppCacheManifestAttr;
+
+},{"../audit":3}],"../audits/dobetterweb/doctype":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+
+class Doctype extends Audit{
+
+
+
+static get meta(){
+return{
+id:'doctype',
+title:'Page has the HTML doctype',
+failureTitle:'Page is missing the HTML doctype',
+description:'Specifying a doctype prevents the browser from switching to quirks-mode.'+
+'Read more on the '+
+'[MDN Web Docs page](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)',
+requiredArtifacts:['Doctype']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+if(!artifacts.Doctype){
+return{
+rawValue:false,
+explanation:'Document must contain a doctype'};
+
+}
+
+
+const doctypeName=artifacts.Doctype.name.trim();
+const doctypePublicId=artifacts.Doctype.publicId;
+const doctypeSystemId=artifacts.Doctype.systemId;
+
+if(doctypePublicId!==''){
+return{
+rawValue:false,
+explanation:'Expected publicId to be an empty string'};
+
+}
+
+if(doctypeSystemId!==''){
+return{
+rawValue:false,
+explanation:'Expected systemId to be an empty string'};
+
+}
+
+
+
+
+if(doctypeName==='html'){
+return{
+rawValue:true};
+
+}else{
+return{
+rawValue:false,
+explanation:'Doctype name must be the lowercase string `html`'};
+
+}
+}}
+
+
+module.exports=Doctype;
+
+},{"../audit":3}],"../audits/dobetterweb/dom-size":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const Util=require('../../report/html/renderer/util.js');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const MAX_DOM_NODES=1500;
+const MAX_DOM_TREE_WIDTH=60;
+const MAX_DOM_TREE_DEPTH=32;
+
+const UIStrings={
+
+title:'Avoids an excessive DOM size',
+
+failureTitle:'Avoid an excessive DOM size',
+
+description:'Browser engineers recommend pages contain fewer than '+
+`~${MAX_DOM_NODES.toLocaleString()} DOM nodes. The sweet spot is a tree `+
+`depth < ${MAX_DOM_TREE_DEPTH} elements and fewer than ${MAX_DOM_TREE_WIDTH} `+
+'children/parent element. A large DOM can increase memory usage, cause longer '+
+'[style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), '+
+'and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size).',
+
+columnStatistic:'Statistic',
+
+columnElement:'Element',
+
+columnValue:'Value',
+
+displayValue:`{itemCount, plural,
+ =1 {1 node}
+ other {# nodes}
+ }`,
+
+statisticDOMNodes:'Total DOM Nodes',
+
+statisticDOMDepth:'Maximum DOM Depth',
+
+statisticDOMWidth:'Maximum Child Elements'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+class DOMSize extends Audit{
+static get MAX_DOM_NODES(){
+return MAX_DOM_NODES;
+}
+
+
+
+
+static get meta(){
+return{
+id:'dom-size',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['DOMStats']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:700,
+scoreMedian:1400};
+
+}
+
+
+
+
+
+
+
+static audit(artifacts,context){
+const stats=artifacts.DOMStats;
+
+const score=Audit.computeLogNormalScore(
+stats.totalDOMNodes,
+context.options.scorePODR,
+context.options.scoreMedian);
+
+
+const headings=[
+{key:'statistic',itemType:'text',text:str_(UIStrings.columnStatistic)},
+{key:'element',itemType:'code',text:str_(UIStrings.columnElement)},
+{key:'value',itemType:'numeric',text:str_(UIStrings.columnValue)}];
+
+
+
+const items=[
+{
+statistic:str_(UIStrings.statisticDOMNodes),
+element:'',
+value:Util.formatNumber(stats.totalDOMNodes)},
+
+{
+statistic:str_(UIStrings.statisticDOMDepth),
+element:{
+type:'code',
+value:stats.depth.snippet},
+
+value:Util.formatNumber(stats.depth.max)},
+
+{
+statistic:str_(UIStrings.statisticDOMWidth),
+element:{
+type:'code',
+value:stats.width.snippet},
+
+value:Util.formatNumber(stats.width.max)}];
+
+
+
+return{
+score,
+rawValue:stats.totalDOMNodes,
+displayValue:str_(UIStrings.displayValue,{itemCount:stats.totalDOMNodes}),
+extendedInfo:{
+value:items},
+
+details:Audit.makeTableDetails(headings,items)};
+
+}}
+
+
+module.exports=DOMSize;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/dobetterweb/dom-size.js");
+},{"../../lib/i18n/i18n.js":59,"../../report/html/renderer/util.js":74,"../audit":3}],"../audits/dobetterweb/external-anchors-use-rel-noopener":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const URL=require('../../lib/url-shim');
+const Audit=require('../audit');
+
+class ExternalAnchorsUseRelNoopenerAudit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'external-anchors-use-rel-noopener',
+title:'Links to cross-origin destinations are safe',
+failureTitle:'Links to cross-origin destinations are unsafe',
+description:'Add `rel="noopener"` or `rel="noreferrer"` to any external links to improve '+
+'performance and prevent security vulnerabilities. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/noopener).',
+requiredArtifacts:['URL','AnchorsWithNoRelNoopener']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+
+const warnings=[];
+const pageHost=new URL(artifacts.URL.finalUrl).host;
+
+const failingAnchors=artifacts.AnchorsWithNoRelNoopener.
+filter(anchor=>{
+try{
+return new URL(anchor.href).host!==pageHost;
+}catch(err){
+warnings.push(`Unable to determine the destination for anchor (${anchor.outerHTML}). `+
+'If not used as a hyperlink, consider removing target=_blank.');
+return true;
+}
+}).
+filter(anchor=>{
+return!anchor.href||anchor.href.toLowerCase().startsWith('http');
+}).
+map(anchor=>{
+return{
+href:anchor.href||'Unknown',
+target:anchor.target||'',
+rel:anchor.rel||'',
+outerHTML:anchor.outerHTML||''};
+
+});
+
+const headings=[
+{key:'href',itemType:'url',text:'URL'},
+{key:'target',itemType:'text',text:'Target'},
+{key:'rel',itemType:'text',text:'Rel'}];
+
+
+const details=Audit.makeTableDetails(headings,failingAnchors);
+
+return{
+rawValue:failingAnchors.length===0,
+extendedInfo:{
+value:failingAnchors},
+
+details,
+warnings};
+
+}}
+
+
+module.exports=ExternalAnchorsUseRelNoopenerAudit;
+
+},{"../../lib/url-shim":"url","../audit":3}],"../audits/dobetterweb/geolocation-on-start":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ViolationAudit=require('../violation-audit');
+
+class GeolocationOnStart extends ViolationAudit{
+
+
+
+static get meta(){
+return{
+id:'geolocation-on-start',
+title:'Avoids requesting the geolocation permission on page load',
+failureTitle:'Requests the geolocation permission on page load',
+description:'Users are mistrustful of or confused by sites that request their '+
+'location without context. Consider tying the request to user gestures instead. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/geolocation-on-load).',
+requiredArtifacts:['ChromeConsoleMessages']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+
+const results=ViolationAudit.getViolationResults(artifacts,/geolocation/);
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'label',itemType:'text',text:'Location'}];
+
+
+
+const details=ViolationAudit.makeTableDetails(headings,results);
+
+return{
+rawValue:results.length===0,
+extendedInfo:{
+value:results},
+
+details};
+
+}}
+
+
+module.exports=GeolocationOnStart;
+
+},{"../violation-audit":7}],"../audits/dobetterweb/js-libraries":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+
+class JsLibrariesAudit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'js-libraries',
+title:'Detected JavaScript libraries',
+description:'All front-end JavaScript libraries detected on the page.',
+requiredArtifacts:['JSLibraries']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const libDetails=artifacts.JSLibraries.map(lib=>({
+name:lib.name,
+version:lib.version,
+npm:lib.npmPkgName||null}));
+
+
+const headings=[
+{key:'name',itemType:'text',text:'Name'},
+{key:'version',itemType:'text',text:'Version'}];
+
+const details=Audit.makeTableDetails(headings,libDetails,{});
+
+return{
+rawValue:true,
+details};
+
+}}
+
+
+module.exports=JsLibrariesAudit;
+
+},{"../audit":3}],"../audits/dobetterweb/no-document-write":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ViolationAudit=require('../violation-audit');
+
+class NoDocWriteAudit extends ViolationAudit{
+
+
+
+static get meta(){
+return{
+id:'no-document-write',
+title:'Avoids `document.write()`',
+failureTitle:'Uses `document.write()`',
+description:'For users on slow connections, external scripts dynamically injected via '+
+'`document.write()` can delay page load by tens of seconds. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/document-write).',
+requiredArtifacts:['ChromeConsoleMessages']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const results=ViolationAudit.getViolationResults(artifacts,/document\.write/);
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'label',itemType:'text',text:'Location'}];
+
+
+const details=ViolationAudit.makeTableDetails(headings,results);
+
+return{
+rawValue:results.length===0,
+extendedInfo:{
+value:results},
+
+details};
+
+}}
+
+
+module.exports=NoDocWriteAudit;
+
+},{"../violation-audit":7}],"../audits/dobetterweb/no-vulnerable-libraries":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const Sentry=require('../../lib/sentry');
+const semver=require('semver');
+const snykDatabase=require('../../../third-party/snyk/snapshot.json');
+
+const SEMVER_REGEX=/^(\d+\.\d+\.\d+)[^-0-9]+/;
+
+
+
+
+class NoVulnerableLibrariesAudit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'no-vulnerable-libraries',
+title:'Avoids front-end JavaScript libraries'+
+' with known security vulnerabilities',
+failureTitle:'Includes front-end JavaScript libraries'+
+' with known security vulnerabilities',
+description:'Some third-party scripts may contain known security vulnerabilities '+
+'that are easily identified and exploited by attackers. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/vulnerabilities).',
+requiredArtifacts:['JSLibraries']};
+
+}
+
+
+
+
+static get snykDB(){
+return snykDatabase;
+}
+
+
+
+
+static get severityMap(){
+return{
+high:3,
+medium:2,
+low:1};
+
+}
+
+
+
+
+
+
+static normalizeVersion(version){
+if(!version)return version;
+if(semver.valid(version))return version;
+
+
+if(/^\d+\.\d+$/.test(version))return`${version}.0`;
+
+const versionMatch=version.match(SEMVER_REGEX);
+if(versionMatch)return versionMatch[1];
+
+return version;
+}
+
+
+
+
+
+
+static getVulnerabilities(normalizedVersion,lib){
+const snykDB=NoVulnerableLibrariesAudit.snykDB;
+if(!lib.npmPkgName||!snykDB.npm[lib.npmPkgName]){
+return[];
+}
+
+try{
+semver.satisfies(normalizedVersion,'*');
+}catch(err){
+err.pkgName=lib.npmPkgName;
+
+Sentry.captureException(err,{level:'warning'});
+return[];
+}
+
+const snykInfo=snykDB.npm[lib.npmPkgName];
+const vulns=snykInfo.
+filter(vuln=>semver.satisfies(normalizedVersion,vuln.semver.vulnerable[0])).
+
+map(vuln=>{
+return{
+severity:vuln.severity,
+numericSeverity:this.severityMap[vuln.severity],
+library:`${lib.name}@${normalizedVersion}`,
+url:'https://snyk.io/vuln/'+vuln.id};
+
+});
+
+return vulns;
+}
+
+
+
+
+
+static highestSeverity(vulnerabilities){
+const sortedVulns=vulnerabilities.
+sort((a,b)=>b.numericSeverity-a.numericSeverity);
+return sortedVulns[0].severity;
+}
+
+
+
+
+
+static audit(artifacts){
+const foundLibraries=artifacts.JSLibraries;
+if(!foundLibraries.length){
+return{
+rawValue:true};
+
+}
+
+let totalVulns=0;
+
+const vulnerabilityResults=[];
+
+const libraryVulns=foundLibraries.map(lib=>{
+const version=this.normalizeVersion(lib.version)||'';
+const vulns=this.getVulnerabilities(version,lib);
+const vulnCount=vulns.length;
+totalVulns+=vulnCount;
+
+let highestSeverity;
+if(vulns.length>0){
+highestSeverity=this.highestSeverity(vulns).replace(/^\w/,l=>l.toUpperCase());
+
+vulnerabilityResults.push({
+highestSeverity,
+vulnCount,
+detectedLib:{
+text:lib.name+'@'+version,
+url:`https://snyk.io/vuln/npm:${lib.npmPkgName}?lh=${version}&utm_source=lighthouse&utm_medium=ref&utm_campaign=audit`,
+type:'link'}});
+
+
+}
+
+return{
+name:lib.name,
+npmPkgName:lib.npmPkgName,
+version,
+vulns,
+highestSeverity};
+
+});
+
+let displayValue='';
+if(totalVulns>1){
+displayValue=`${totalVulns} vulnerabilities detected`;
+}else if(totalVulns===1){
+displayValue=`${totalVulns} vulnerability detected`;
+}
+
+const headings=[
+{key:'detectedLib',itemType:'link',text:'Library Version'},
+{key:'vulnCount',itemType:'text',text:'Vulnerability Count'},
+{key:'highestSeverity',itemType:'text',text:'Highest Severity'}];
+
+const details=Audit.makeTableDetails(headings,vulnerabilityResults,{});
+
+return{
+rawValue:totalVulns===0,
+displayValue,
+extendedInfo:{
+jsLibs:libraryVulns,
+vulnerabilities:vulnerabilityResults},
+
+details};
+
+}}
+
+
+module.exports=NoVulnerableLibrariesAudit;
+
+},{"../../../third-party/snyk/snapshot.json":161,"../../lib/sentry":69,"../audit":3,"semver":151}],"../audits/dobetterweb/notification-on-start":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ViolationAudit=require('../violation-audit');
+
+class NotificationOnStart extends ViolationAudit{
+
+
+
+static get meta(){
+return{
+id:'notification-on-start',
+title:'Avoids requesting the notification permission on page load',
+failureTitle:'Requests the notification permission on page load',
+description:'Users are mistrustful of or confused by sites that request to send '+
+'notifications without context. Consider tying the request to user gestures '+
+'instead. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/notifications-on-load).',
+requiredArtifacts:['ChromeConsoleMessages']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const results=ViolationAudit.getViolationResults(artifacts,/notification permission/);
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'label',itemType:'text',text:'Location'}];
+
+
+const details=ViolationAudit.makeTableDetails(headings,results);
+
+return{
+rawValue:results.length===0,
+extendedInfo:{
+value:results},
+
+details};
+
+}}
+
+
+module.exports=NotificationOnStart;
+
+},{"../violation-audit":7}],"../audits/dobetterweb/password-inputs-can-be-pasted-into":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+
+class PasswordInputsCanBePastedIntoAudit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'password-inputs-can-be-pasted-into',
+title:'Allows users to paste into password fields',
+failureTitle:'Prevents users to paste into password fields',
+description:'Preventing password pasting undermines good security policy. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/password-pasting).',
+requiredArtifacts:['PasswordInputsWithPreventedPaste']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const passwordInputsWithPreventedPaste=artifacts.PasswordInputsWithPreventedPaste;
+
+
+const items=[];
+passwordInputsWithPreventedPaste.forEach(input=>{
+items.push({
+node:{type:'node',snippet:input.snippet}});
+
+});
+
+const headings=[
+{key:'node',itemType:'node',text:'Failing Elements'}];
+
+
+return{
+rawValue:passwordInputsWithPreventedPaste.length===0,
+extendedInfo:{
+value:passwordInputsWithPreventedPaste},
+
+details:Audit.makeTableDetails(headings,items)};
+
+}}
+
+
+module.exports=PasswordInputsCanBePastedIntoAudit;
+
+},{"../audit":3}],"../audits/dobetterweb/uses-http2":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const URL=require('../../lib/url-shim');
+const Audit=require('../audit');
+const Util=require('../../report/html/renderer/util.js');
+const NetworkRecords=require('../../computed/network-records.js');
+
+class UsesHTTP2Audit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'uses-http2',
+title:'Uses HTTP/2 for its own resources',
+failureTitle:'Does not use HTTP/2 for all of its resources',
+description:'HTTP/2 offers many benefits over HTTP/1.1, including binary headers, '+
+'multiplexing, and server push. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/http2).',
+requiredArtifacts:['URL','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+return NetworkRecords.request(devtoolsLogs,context).then(networkRecords=>{
+const finalHost=new URL(artifacts.URL.finalUrl).host;
+
+const seenURLs=new Set();
+
+const resources=networkRecords.filter(record=>{
+
+const isOldHttp=/HTTP\/[01][.\d]?/i.test(record.protocol);
+if(!isOldHttp)return false;
+const requestHost=new URL(record.url).host;
+return requestHost===finalHost;
+}).map(record=>{
+return{
+protocol:record.protocol,
+url:record.url};
+
+}).filter(record=>{
+if(seenURLs.has(record.url))return false;
+seenURLs.add(record.url);
+return true;
+});
+
+let displayValue='';
+if(resources.length>1){
+displayValue=
+`${Util.formatNumber(resources.length)} requests not served via HTTP/2`;
+}else if(resources.length===1){
+displayValue=`${resources.length} request not served via HTTP/2`;
+}
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'protocol',itemType:'text',text:'Protocol'}];
+
+const details=Audit.makeTableDetails(headings,resources);
+
+return{
+rawValue:resources.length===0,
+displayValue:displayValue,
+extendedInfo:{
+value:{
+results:resources}},
+
+
+details};
+
+});
+}}
+
+
+module.exports=UsesHTTP2Audit;
+
+},{"../../computed/network-records.js":29,"../../lib/url-shim":"url","../../report/html/renderer/util.js":74,"../audit":3}],"../audits/dobetterweb/uses-passive-event-listeners":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ViolationAudit=require('../violation-audit');
+
+class PassiveEventsAudit extends ViolationAudit{
+
+
+
+static get meta(){
+return{
+id:'uses-passive-event-listeners',
+title:'Uses passive listeners to improve scrolling performance',
+failureTitle:'Does not use passive listeners to improve scrolling performance',
+description:'Consider marking your touch and wheel event listeners as `passive` '+
+'to improve your page\'s scroll performance. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners).',
+requiredArtifacts:['ChromeConsoleMessages']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const results=ViolationAudit.getViolationResults(artifacts,/passive event listener/);
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'label',itemType:'text',text:'Location'}];
+
+
+const details=ViolationAudit.makeTableDetails(headings,results);
+
+return{
+rawValue:results.length===0,
+extendedInfo:{
+value:results},
+
+details};
+
+}}
+
+
+module.exports=PassiveEventsAudit;
+
+},{"../violation-audit":7}],"../audits/errors-in-console":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const Audit=require('./audit');
+
+class ErrorLogs extends Audit{
+
+
+
+static get meta(){
+return{
+id:'errors-in-console',
+title:'No browser errors logged to the console',
+description:'Errors logged to the console indicate unresolved problems. '+
+'They can come from network request failures and other browser concerns.',
+failureTitle:'Browser errors were logged to the console',
+requiredArtifacts:['ChromeConsoleMessages','RuntimeExceptions']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const consoleEntries=artifacts.ChromeConsoleMessages;
+const runtimeExceptions=artifacts.RuntimeExceptions;
+
+const consoleRows=
+consoleEntries.filter(log=>log.entry&&log.entry.level==='error').
+map(item=>{
+return{
+source:item.entry.source,
+description:item.entry.text,
+url:item.entry.url};
+
+});
+
+const runtimeExRows=
+runtimeExceptions.filter(entry=>entry.exceptionDetails!==undefined).
+map(entry=>{
+const description=entry.exceptionDetails.exception?
+entry.exceptionDetails.exception.description:entry.exceptionDetails.text;
+
+return{
+source:'Runtime.exception',
+description,
+url:entry.exceptionDetails.url};
+
+});
+
+const tableRows=consoleRows.concat(runtimeExRows);
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'description',itemType:'code',text:'Description'}];
+
+
+const details=Audit.makeTableDetails(headings,tableRows);
+const numErrors=tableRows.length;
+
+return{
+score:Number(numErrors===0),
+rawValue:numErrors,
+details};
+
+}}
+
+
+module.exports=ErrorLogs;
+
+},{"./audit":3}],"../audits/final-screenshot":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const LHError=require('../lib/lh-error');
+const Screenshots=require('../computed/screenshots.js');
+
+class FinalScreenshot extends Audit{
+
+
+
+static get meta(){
+return{
+id:'final-screenshot',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+title:'Final Screenshot',
+description:'The last screenshot captured of the pageload.',
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const screenshots=await Screenshots.request(trace,context);
+const finalScreenshot=screenshots[screenshots.length-1];
+
+if(!finalScreenshot){
+throw new LHError(LHError.errors.NO_SCREENSHOTS);
+}
+
+return{
+rawValue:true,
+details:{
+type:'screenshot',
+timestamp:finalScreenshot.timestamp,
+data:finalScreenshot.datauri}};
+
+
+}}
+
+
+module.exports=FinalScreenshot;
+
+},{"../computed/screenshots.js":31,"../lib/lh-error":63,"./audit":3}],"../audits/font-display":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const URL=require('../lib/url-shim').URL;
+const PASSING_FONT_DISPLAY_REGEX=/block|fallback|optional|swap/;
+const CSS_URL_REGEX=/url\((.*?)\)/;
+const CSS_URL_GLOBAL_REGEX=new RegExp(CSS_URL_REGEX,'g');
+const i18n=require('../lib/i18n/i18n.js');
+const Sentry=require('../lib/sentry.js');
+const NetworkRecords=require('../computed/network-records.js');
+
+const UIStrings={
+
+title:'All text remains visible during webfont loads',
+
+failureTitle:'Ensure text remains visible during webfont load',
+
+description:
+'Leverage the font-display CSS feature to ensure text is user-visible while '+
+'webfonts are loading. '+
+'[Learn more](https://developers.google.com/web/updates/2016/02/font-display).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class FontDisplay extends Audit{
+
+
+
+static get meta(){
+return{
+id:'font-display',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['devtoolsLogs','CSSUsage','URL']};
+
+}
+
+
+
+
+static findPassingFontDisplayDeclarations(artifacts){
+
+const passingURLs=new Set();
+
+
+for(const stylesheet of artifacts.CSSUsage.stylesheets){
+
+const newlinesStripped=stylesheet.content.replace(/\n/g,' ');
+
+const fontFaceDeclarations=newlinesStripped.match(/@font-face\s*{(.*?)}/g)||[];
+
+for(const declaration of fontFaceDeclarations){
+const rawFontDisplay=declaration.match(/font-display:(.*?);/);
+
+if(!rawFontDisplay)continue;
+
+const hasPassingFontDisplay=PASSING_FONT_DISPLAY_REGEX.test(rawFontDisplay[0]);
+if(!hasPassingFontDisplay)continue;
+
+
+const rawFontURLs=declaration.match(CSS_URL_GLOBAL_REGEX);
+
+if(!rawFontURLs)continue;
+
+const relativeURLs=rawFontURLs.
+
+map(s=>s.match(CSS_URL_REGEX)[1].trim()).
+map(s=>{
+
+if(/^('|").*\1$/.test(s)){
+return s.substr(1,s.length-2);
+}
+
+return s;
+});
+
+
+for(const relativeURL of relativeURLs){
+try{
+const relativeRoot=stylesheet.header.sourceURL||artifacts.URL.finalUrl;
+const absoluteURL=new URL(relativeURL,relativeRoot);
+passingURLs.add(absoluteURL.href);
+}catch(err){
+Sentry.captureException(err,{tags:{audit:this.meta.id}});
+}
+}
+}
+}
+
+return passingURLs;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const devtoolsLogs=artifacts.devtoolsLogs[this.DEFAULT_PASS];
+const networkRecords=await NetworkRecords.request(devtoolsLogs,context);
+const passingFontURLs=FontDisplay.findPassingFontDisplayDeclarations(artifacts);
+
+const results=networkRecords.
+
+filter(record=>record.resourceType==='Font').
+
+filter(record=>!passingFontURLs.has(record.url)).
+map(record=>{
+
+
+const wastedMs=Math.min((record.endTime-record.startTime)*1000,3000);
+
+return{
+url:record.url,
+wastedMs};
+
+});
+
+const headings=[
+{key:'url',itemType:'url',text:str_(i18n.UIStrings.columnURL)},
+{key:'wastedMs',itemType:'ms',text:str_(i18n.UIStrings.columnWastedMs)}];
+
+
+const details=Audit.makeTableDetails(headings,results);
+
+return{
+score:Number(results.length===0),
+rawValue:results.length===0,
+details};
+
+}}
+
+
+module.exports=FontDisplay;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/font-display.js");
+},{"../computed/network-records.js":29,"../lib/i18n/i18n.js":59,"../lib/sentry.js":69,"../lib/url-shim":"url","./audit":3}],"../audits/image-aspect-ratio":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+
+const URL=require('../lib/url-shim');
+const THRESHOLD_PX=2;
+
+
+
+class ImageAspectRatio extends Audit{
+
+
+
+static get meta(){
+return{
+id:'image-aspect-ratio',
+title:'Displays images with correct aspect ratio',
+failureTitle:'Displays images with incorrect aspect ratio',
+description:'Image display dimensions should match natural aspect ratio. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/aspect-ratio).',
+requiredArtifacts:['ImageUsage']};
+
+}
+
+
+
+
+
+static computeAspectRatios(image){
+const url=URL.elideDataURI(image.src);
+const actualAspectRatio=image.naturalWidth/image.naturalHeight;
+const displayedAspectRatio=image.width/image.height;
+
+const targetDisplayHeight=image.width/actualAspectRatio;
+const doRatiosMatch=Math.abs(targetDisplayHeight-image.height)<THRESHOLD_PX;
+
+if(!Number.isFinite(actualAspectRatio)||
+!Number.isFinite(displayedAspectRatio)){
+return new Error(`Invalid image sizing information ${url}`);
+}
+
+return{
+url,
+displayedAspectRatio:`${image.width} x ${image.height}
+ (${displayedAspectRatio.toFixed(2)})`,
+actualAspectRatio:`${image.naturalWidth} x ${image.naturalHeight}
+ (${actualAspectRatio.toFixed(2)})`,
+doRatiosMatch};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const images=artifacts.ImageUsage;
+
+
+const warnings=[];
+
+const results=[];
+images.filter(image=>{
+
+
+
+return image.networkRecord&&
+image.networkRecord.mimeType!=='image/svg+xml'&&
+image.naturalHeight>5&&
+image.naturalWidth>5&&
+image.width&&
+image.height&&
+!image.usesObjectFit;
+}).forEach(image=>{
+const wellDefinedImage=image;
+const processed=ImageAspectRatio.computeAspectRatios(wellDefinedImage);
+if(processed instanceof Error){
+warnings.push(processed.message);
+return;
+}
+
+if(!processed.doRatiosMatch)results.push(processed);
+});
+
+const headings=[
+{key:'url',itemType:'thumbnail',text:''},
+{key:'url',itemType:'url',text:'URL'},
+{key:'displayedAspectRatio',itemType:'text',text:'Aspect Ratio (Displayed)'},
+{key:'actualAspectRatio',itemType:'text',text:'Aspect Ratio (Actual)'}];
+
+
+return{
+rawValue:results.length===0,
+warnings,
+details:Audit.makeTableDetails(headings,results)};
+
+}}
+
+
+module.exports=ImageAspectRatio;
+
+},{"../lib/url-shim":"url","./audit":3}],"../audits/installable-manifest":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MultiCheckAudit=require('./multi-check-audit.js');
+const ManifestValues=require('../computed/manifest-values.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class InstallableManifest extends MultiCheckAudit{
+
+
+
+static get meta(){
+return{
+id:'installable-manifest',
+title:'Web app manifest meets the installability requirements',
+failureTitle:'Web app manifest does not meet the installability requirements',
+description:'Browsers can proactively prompt users to add your app to their homescreen, '+
+'which can lead to higher engagement. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/install-prompt).',
+requiredArtifacts:['URL','Manifest']};
+
+}
+
+
+
+
+
+static assessManifest(manifestValues){
+if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
+return[manifestValues.parseFailureReason];
+}
+
+
+const failures=[];
+const bannerCheckIds=[
+'hasName',
+
+
+
+
+
+
+'hasShortName',
+'hasStartUrl',
+'hasPWADisplayValue',
+'hasIconsAtLeast192px'];
+
+manifestValues.allChecks.
+filter(item=>bannerCheckIds.includes(item.id)).
+forEach(item=>{
+if(!item.passing){
+failures.push(item.failureText);
+}
+});
+
+return failures;
+}
+
+
+
+
+
+
+static async audit_(artifacts,context){
+const manifestValues=await ManifestValues.request(artifacts.Manifest,context);
+const manifestFailures=InstallableManifest.assessManifest(manifestValues);
+
+return{
+failures:[
+...manifestFailures],
+
+manifestValues};
+
+}}
+
+
+module.exports=InstallableManifest;
+
+},{"../computed/manifest-values.js":13,"./multi-check-audit.js":6}],"../audits/is-on-https":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const URL=require('../lib/url-shim');
+const Util=require('../report/html/renderer/util');
+const NetworkRecords=require('../computed/network-records.js');
+
+const SECURE_SCHEMES=['data','https','wss','blob','chrome','chrome-extension','about'];
+const SECURE_DOMAINS=['localhost','127.0.0.1'];
+
+class HTTPS extends Audit{
+
+
+
+static get meta(){
+return{
+id:'is-on-https',
+title:'Uses HTTPS',
+failureTitle:'Does not use HTTPS',
+description:'All sites should be protected with HTTPS, even ones that don\'t handle '+
+'sensitive data. HTTPS prevents intruders from tampering with or passively listening '+
+'in on the communications between your app and your users, and is a prerequisite for '+
+'HTTP/2 and many new web platform APIs. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/https).',
+requiredArtifacts:['devtoolsLogs']};
+
+}
+
+
+
+
+
+static isSecureRecord(record){
+return SECURE_SCHEMES.includes(record.parsedURL.scheme)||
+SECURE_SCHEMES.includes(record.protocol)||
+SECURE_DOMAINS.includes(record.parsedURL.host);
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+return NetworkRecords.request(devtoolsLogs,context).then(networkRecords=>{
+const insecureURLs=networkRecords.
+filter(record=>!HTTPS.isSecureRecord(record)).
+map(record=>URL.elideDataURI(record.url));
+
+let displayValue='';
+if(insecureURLs.length>1){
+displayValue=`${Util.formatNumber(insecureURLs.length)} insecure requests found`;
+}else if(insecureURLs.length===1){
+displayValue=`${insecureURLs.length} insecure request found`;
+}
+
+const items=Array.from(new Set(insecureURLs)).map(url=>({url}));
+
+const headings=[
+{key:'url',itemType:'url',text:'Insecure URL'}];
+
+
+return{
+rawValue:items.length===0,
+displayValue,
+extendedInfo:{
+value:items},
+
+details:Audit.makeTableDetails(headings,items)};
+
+});
+}}
+
+
+module.exports=HTTPS;
+
+},{"../computed/network-records.js":29,"../lib/url-shim":"url","../report/html/renderer/util":74,"./audit":3}],"../audits/load-fast-enough-for-pwa":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const isDeepEqual=require('lodash.isequal');
+const Audit=require('./audit');
+const mobileThrottling=require('../config/constants').throttling.mobileSlow4G;
+const Interactive=require('../computed/metrics/interactive.js');
+const i18n=require('../lib/i18n/i18n.js');
+
+
+
+const MAXIMUM_TTI=10*1000;
+
+const UIStrings={
+
+title:'Page load is fast enough on mobile networks',
+
+failureTitle:'Page load is not fast enough on mobile networks',
+
+description:'A fast page load over a cellular network ensures a good mobile user experience. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/fast-3g).',
+
+displayValueText:'Interactive at {timeInMs, number, seconds}\xa0s',
+
+displayValueTextWithOverride:'Interactive on simulated mobile network at '+
+'{timeInMs, number, seconds}\xa0s'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class LoadFastEnough4Pwa extends Audit{
+
+
+
+static get meta(){
+return{
+id:'load-fast-enough-for-pwa',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+
+
+const settingOverrides={throttlingMethod:'simulate',throttling:mobileThrottling};
+
+
+
+const override=context.settings.throttlingMethod==='provided'||
+!isDeepEqual(context.settings.throttling,mobileThrottling);
+
+const displayValueTemplate=override?
+UIStrings.displayValueTextWithOverride:UIStrings.displayValueText;
+
+const settings=override?Object.assign({},context.settings,settingOverrides):
+context.settings;
+
+const metricComputationData={trace,devtoolsLog,settings};
+const tti=await Interactive.request(metricComputationData,context);
+
+const score=Number(tti.timing<MAXIMUM_TTI);
+
+
+let displayValue;
+
+let explanation;
+if(!score){
+displayValue=str_(displayValueTemplate,{timeInMs:tti.timing});
+explanation='Your page loads too slowly and is not interactive within 10 seconds. '+
+'Look at the opportunities and diagnostics in the "Performance" section to learn how to '+
+'improve.';
+}
+
+return{
+score,
+displayValue,
+explanation,
+rawValue:tti.timing};
+
+}}
+
+
+module.exports=LoadFastEnough4Pwa;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/load-fast-enough-for-pwa.js");
+},{"../computed/metrics/interactive.js":18,"../config/constants":36,"../lib/i18n/i18n.js":59,"./audit":3,"lodash.isequal":114}],"../audits/mainthread-work-breakdown":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const{taskGroups}=require('../lib/task-groups');
+const i18n=require('../lib/i18n/i18n.js');
+const MainThreadTasks=require('../computed/main-thread-tasks.js');
+
+const UIStrings={
+
+title:'Minimizes main-thread work',
+
+failureTitle:'Minimize main-thread work',
+
+description:'Consider reducing the time spent parsing, compiling and executing JS. '+
+'You may find delivering smaller JS payloads helps with this.',
+
+columnCategory:'Category'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+class MainThreadWorkBreakdown extends Audit{
+
+
+
+static get meta(){
+return{
+id:'mainthread-work-breakdown',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+scorePODR:1500,
+scoreMedian:4000};
+
+}
+
+
+
+
+
+static getExecutionTimingsByGroup(tasks){
+
+const result=new Map();
+
+for(const task of tasks){
+const originalTime=result.get(task.group.id)||0;
+result.set(task.group.id,originalTime+task.selfTime);
+}
+
+return result;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const settings=context.settings||{};
+const trace=artifacts.traces[MainThreadWorkBreakdown.DEFAULT_PASS];
+
+const tasks=await MainThreadTasks.request(trace,context);
+const multiplier=settings.throttlingMethod==='simulate'?
+settings.throttling.cpuSlowdownMultiplier:1;
+
+const executionTimings=MainThreadWorkBreakdown.getExecutionTimingsByGroup(tasks);
+
+let totalExecutionTime=0;
+
+const categoryTotals={};
+const results=Array.from(executionTimings).map(([groupId,rawDuration])=>{
+const duration=rawDuration*multiplier;
+totalExecutionTime+=duration;
+
+const categoryTotal=categoryTotals[groupId]||0;
+categoryTotals[groupId]=categoryTotal+duration;
+
+return{
+group:groupId,
+groupLabel:taskGroups[groupId].label,
+duration:duration};
+
+});
+
+const headings=[
+{key:'groupLabel',itemType:'text',text:str_(UIStrings.columnCategory)},
+{key:'duration',itemType:'ms',granularity:1,text:str_(i18n.UIStrings.columnTimeSpent)}];
+
+
+results.sort((a,b)=>categoryTotals[b.group]-categoryTotals[a.group]);
+const tableDetails=MainThreadWorkBreakdown.makeTableDetails(headings,results);
+
+const score=Audit.computeLogNormalScore(
+totalExecutionTime,
+context.options.scorePODR,
+context.options.scoreMedian);
+
+
+return{
+score,
+rawValue:totalExecutionTime,
+displayValue:str_(i18n.UIStrings.seconds,{timeInMs:totalExecutionTime}),
+details:tableDetails};
+
+}}
+
+
+module.exports=MainThreadWorkBreakdown;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/mainthread-work-breakdown.js");
+},{"../computed/main-thread-tasks.js":12,"../lib/i18n/i18n.js":59,"../lib/task-groups":71,"./audit":3}],"../audits/manual/pwa-cross-browser":[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('./manual-audit');
+
+
+
+
+
+class PWACrossBrowser extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'pwa-cross-browser',
+description:'To reach the most number of users, sites should work across '+
+'every major browser. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#site-works-cross-browser).',
+title:'Site works cross-browser'},
+super.partialMeta);
+}}
+
+
+module.exports=PWACrossBrowser;
+
+},{"./manual-audit":5}],"../audits/manual/pwa-each-page-has-url":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('./manual-audit');
+
+
+
+
+
+class PWAEachPageHasURL extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'pwa-each-page-has-url',
+description:'Ensure individual pages are deep linkable via the URLs and that URLs are '+
+'unique for the purpose of shareability on social media. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#each-page-has-a-url).',
+title:'Each page has a URL'},
+super.partialMeta);
+}}
+
+
+module.exports=PWAEachPageHasURL;
+
+},{"./manual-audit":5}],"../audits/manual/pwa-page-transitions":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('./manual-audit');
+
+
+
+
+
+class PWAPageTransitions extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'pwa-page-transitions',
+description:'Transitions should feel snappy as you tap around, even on a slow network, a '+
+'key to perceived performance. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#page-transitions-dont-feel-like-they-block-on-the-network).',
+title:'Page transitions don\'t feel like they block on the network'},
+super.partialMeta);
+}}
+
+
+module.exports=PWAPageTransitions;
+
+},{"./manual-audit":5}],"../audits/metrics/estimated-input-latency":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const ComputedEil=require('../../computed/metrics/estimated-input-latency.js');
+
+const UIStrings={
+
+title:'Estimated Input Latency',
+
+description:'Estimated Input Latency is an estimate of how long your app takes to respond to '+
+'user input, in milliseconds, during the busiest 5s window of page load. If your '+
+'latency is higher than 50 ms, users may perceive your app as laggy. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class EstimatedInputLatency extends Audit{
+
+
+
+static get meta(){
+return{
+id:'estimated-input-latency',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+scorePODR:50,
+scoreMedian:100};
+
+}
+
+
+
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await ComputedEil.request(metricComputationData,context);
+
+return{
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:metricResult.timing,
+displayValue:str_(i18n.UIStrings.ms,{timeInMs:metricResult.timing})};
+
+}}
+
+
+module.exports=EstimatedInputLatency;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/metrics/estimated-input-latency.js");
+},{"../../computed/metrics/estimated-input-latency.js":14,"../../lib/i18n/i18n.js":59,"../audit":3}],"../audits/metrics/first-contentful-paint":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const ComputedFcp=require('../../computed/metrics/first-contentful-paint.js');
+
+const UIStrings={
+
+title:'First Contentful Paint',
+
+description:'First Contentful Paint marks the time at which the first text or image is '+
+`painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint).`};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class FirstContentfulPaint extends Audit{
+
+
+
+static get meta(){
+return{
+id:'first-contentful-paint',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2000,
+scoreMedian:4000};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await ComputedFcp.request(metricComputationData,context);
+
+return{
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:metricResult.timing,
+displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
+
+}}
+
+
+module.exports=FirstContentfulPaint;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/metrics/first-contentful-paint.js");
+},{"../../computed/metrics/first-contentful-paint.js":15,"../../lib/i18n/i18n.js":59,"../audit":3}],"../audits/metrics/first-cpu-idle":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const ComputedFci=require('../../computed/metrics/first-cpu-idle.js');
+
+const UIStrings={
+
+title:'First CPU Idle',
+
+description:'First CPU Idle marks the first time at which the page\'s main thread is '+
+'quiet enough to handle input. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class FirstCPUIdle extends Audit{
+
+
+
+static get meta(){
+return{
+id:'first-cpu-idle',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2900,
+scoreMedian:6500};
+
+}
+
+
+
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await ComputedFci.request(metricComputationData,context);
+
+return{
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:metricResult.timing,
+displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
+
+}}
+
+
+module.exports=FirstCPUIdle;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/metrics/first-cpu-idle.js");
+},{"../../computed/metrics/first-cpu-idle.js":16,"../../lib/i18n/i18n.js":59,"../audit":3}],"../audits/metrics/first-meaningful-paint":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const ComputedFmp=require('../../computed/metrics/first-meaningful-paint.js');
+
+const UIStrings={
+
+title:'First Meaningful Paint',
+
+description:'First Meaningful Paint measures when the primary content of a page is '+
+'visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class FirstMeaningfulPaint extends Audit{
+
+
+
+static get meta(){
+return{
+id:'first-meaningful-paint',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2000,
+scoreMedian:4000};
+
+}
+
+
+
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await ComputedFmp.request(metricComputationData,context);
+
+return{
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:metricResult.timing,
+displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
+
+}}
+
+
+module.exports=FirstMeaningfulPaint;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/metrics/first-meaningful-paint.js");
+},{"../../computed/metrics/first-meaningful-paint.js":17,"../../lib/i18n/i18n.js":59,"../audit":3}],"../audits/metrics/interactive":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const Interactive=require('../../computed/metrics/interactive.js');
+
+const UIStrings={
+
+title:'Time to Interactive',
+
+description:'Time to interactive is the amount of time it takes for the page to become fully '+
+'interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+
+
+
+
+class InteractiveMetric extends Audit{
+
+
+
+static get meta(){
+return{
+id:'interactive',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2900,
+scoreMedian:7300};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await Interactive.request(metricComputationData,context);
+const timeInMs=metricResult.timing;
+const extendedInfo={
+timeInMs,
+timestamp:metricResult.timestamp,
+
+optimistic:metricResult.optimisticEstimate&&metricResult.optimisticEstimate.timeInMs,
+
+pessimistic:metricResult.pessimisticEstimate&&metricResult.pessimisticEstimate.timeInMs};
+
+
+return{
+score:Audit.computeLogNormalScore(
+timeInMs,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:timeInMs,
+displayValue:str_(i18n.UIStrings.seconds,{timeInMs}),
+extendedInfo:{
+value:extendedInfo}};
+
+
+}}
+
+
+module.exports=InteractiveMetric;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/metrics/interactive.js");
+},{"../../computed/metrics/interactive.js":18,"../../lib/i18n/i18n.js":59,"../audit":3}],"../audits/metrics/speed-index":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+const ComputedSi=require('../../computed/metrics/speed-index.js');
+
+const UIStrings={
+
+title:'Speed Index',
+
+description:'Speed Index shows how quickly the contents of a page are visibly populated. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class SpeedIndex extends Audit{
+
+
+
+static get meta(){
+return{
+id:'speed-index',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2900,
+scoreMedian:5800};
+
+}
+
+
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await ComputedSi.request(metricComputationData,context);
+
+return{
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:metricResult.timing,
+displayValue:str_(i18n.UIStrings.seconds,{timeInMs:metricResult.timing})};
+
+}}
+
+
+module.exports=SpeedIndex;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/metrics/speed-index.js");
+},{"../../computed/metrics/speed-index.js":27,"../../lib/i18n/i18n.js":59,"../audit":3}],"../audits/metrics":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const TraceOfTab=require('../computed/trace-of-tab.js');
+const Speedline=require('../computed/speedline.js');
+const FirstContentfulPaint=require('../computed/metrics/first-contentful-paint.js');
+const FirstMeaningfulPaint=require('../computed/metrics/first-meaningful-paint.js');
+const FirstCPUIdle=require('../computed/metrics/first-cpu-idle.js');
+const Interactive=require('../computed/metrics/interactive.js');
+const SpeedIndex=require('../computed/metrics/speed-index.js');
+const EstimatedInputLatency=require('../computed/metrics/estimated-input-latency.js');
+
+class Metrics extends Audit{
+
+
+
+static get meta(){
+return{
+id:'metrics',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+title:'Metrics',
+description:'Collects all available metrics.',
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+
+const traceOfTab=await TraceOfTab.request(trace,context);
+const speedline=await Speedline.request(trace,context);
+const firstContentfulPaint=await FirstContentfulPaint.request(metricComputationData,context);
+const firstMeaningfulPaint=await FirstMeaningfulPaint.request(metricComputationData,context);
+const firstCPUIdle=await FirstCPUIdle.request(metricComputationData,context);
+const interactive=await Interactive.request(metricComputationData,context);
+const speedIndex=await SpeedIndex.request(metricComputationData,context);
+const estimatedInputLatency=await EstimatedInputLatency.request(metricComputationData,context);
+
+
+const metrics={
+
+firstContentfulPaint:firstContentfulPaint.timing,
+firstContentfulPaintTs:firstContentfulPaint.timestamp,
+firstMeaningfulPaint:firstMeaningfulPaint.timing,
+firstMeaningfulPaintTs:firstMeaningfulPaint.timestamp,
+firstCPUIdle:firstCPUIdle.timing,
+firstCPUIdleTs:firstCPUIdle.timestamp,
+interactive:interactive.timing,
+interactiveTs:interactive.timestamp,
+speedIndex:speedIndex.timing,
+speedIndexTs:speedIndex.timestamp,
+estimatedInputLatency:estimatedInputLatency.timing,
+estimatedInputLatencyTs:estimatedInputLatency.timestamp,
+
+
+observedNavigationStart:traceOfTab.timings.navigationStart,
+observedNavigationStartTs:traceOfTab.timestamps.navigationStart,
+observedFirstPaint:traceOfTab.timings.firstPaint,
+observedFirstPaintTs:traceOfTab.timestamps.firstPaint,
+observedFirstContentfulPaint:traceOfTab.timings.firstContentfulPaint,
+observedFirstContentfulPaintTs:traceOfTab.timestamps.firstContentfulPaint,
+observedFirstMeaningfulPaint:traceOfTab.timings.firstMeaningfulPaint,
+observedFirstMeaningfulPaintTs:traceOfTab.timestamps.firstMeaningfulPaint,
+observedTraceEnd:traceOfTab.timings.traceEnd,
+observedTraceEndTs:traceOfTab.timestamps.traceEnd,
+observedLoad:traceOfTab.timings.load,
+observedLoadTs:traceOfTab.timestamps.load,
+observedDomContentLoaded:traceOfTab.timings.domContentLoaded,
+observedDomContentLoadedTs:traceOfTab.timestamps.domContentLoaded,
+
+
+observedFirstVisualChange:speedline.first,
+observedFirstVisualChangeTs:(speedline.first+speedline.beginning)*1000,
+observedLastVisualChange:speedline.complete,
+observedLastVisualChangeTs:(speedline.complete+speedline.beginning)*1000,
+observedSpeedIndex:speedline.speedIndex,
+observedSpeedIndexTs:(speedline.speedIndex+speedline.beginning)*1000};
+
+
+for(const[name,value]of Object.entries(metrics)){
+const key=name;
+if(typeof value!=='undefined'){
+metrics[key]=Math.round(value);
+}
+}
+
+
+const details={items:[metrics]};
+
+return{
+score:1,
+rawValue:interactive.timing,
+details};
+
+}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports=Metrics;
+
+},{"../computed/metrics/estimated-input-latency.js":14,"../computed/metrics/first-contentful-paint.js":15,"../computed/metrics/first-cpu-idle.js":16,"../computed/metrics/first-meaningful-paint.js":17,"../computed/metrics/interactive.js":18,"../computed/metrics/speed-index.js":27,"../computed/speedline.js":32,"../computed/trace-of-tab.js":33,"./audit":3}],"../audits/mixed-content":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const URL=require('../lib/url-shim');
+const Util=require('../report/html/renderer/util');
+const NetworkRecords=require('../computed/network-records.js');
+
+
+
+
+
+
+
+class MixedContent extends Audit{
+
+
+
+static get meta(){
+return{
+id:'mixed-content',
+title:'All resources loaded are secure',
+failureTitle:'Some insecure resources can be upgraded to HTTPS',
+description:`Mixed content warnings can prevent you from upgrading to HTTPS.
+ This audit shows which insecure resources this page uses that can be
+ upgraded to HTTPS. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/mixed-content)`,
+requiredArtifacts:['devtoolsLogs','MixedContent']};
+
+}
+
+
+
+
+
+
+
+static upgradeURL(url){
+const parsedURL=new URL(url);
+parsedURL.protocol='https:';
+return parsedURL.href;
+}
+
+
+
+
+
+
+
+static simplifyURL(url){
+const parsedURL=new URL(url);
+parsedURL.hash='';
+parsedURL.search='';
+return parsedURL.href;
+}
+
+
+
+
+
+
+
+static displayURL(url=''){
+const displayOptions={
+numPathParts:4,
+preserveQuery:false,
+preserveHost:true};
+
+return URL.getURLDisplayName(url,displayOptions);
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const defaultLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const upgradeLogs=artifacts.devtoolsLogs['mixedContentPass'];
+const baseHostname=new URL(artifacts.MixedContent.url).host;
+
+const computedArtifacts=[
+NetworkRecords.request(defaultLogs,context),
+NetworkRecords.request(upgradeLogs,context)];
+
+
+return Promise.all(computedArtifacts).then(([defaultRecords,upgradedRecords])=>{
+const insecureRecords=defaultRecords.filter(
+record=>!record.isSecure);
+const secureRecords=defaultRecords.filter(
+record=>record.isSecure);
+
+const upgradePassHosts=new Set();
+const upgradePassSecureHosts=new Set();
+upgradedRecords.forEach(record=>{
+upgradePassHosts.add(new URL(record.url).hostname);
+if(record.isSecure&&record.finished&&!record.failed){
+upgradePassSecureHosts.add(new URL(record.url).hostname);
+}
+});
+
+
+
+
+const seen=new Set();
+const upgradeableResources=[];
+
+for(const record of insecureRecords){
+const simpleUrl=this.simplifyURL(record.url);
+if(seen.has(simpleUrl))continue;
+seen.add(simpleUrl);
+
+const resource={
+host:new URL(record.url).hostname,
+fullUrl:record.url,
+referrerDocUrl:this.displayURL(record.documentURL)};
+
+
+if(!upgradePassSecureHosts.has(resource.host))continue;
+
+if(!resource.referrerDocUrl.includes(baseHostname))continue;
+
+upgradeableResources.push(resource);
+}
+
+const displayValue=`${Util.formatNumber(upgradeableResources.length)}
+ ${upgradeableResources.length===1?'request':'requests'}`;
+
+const headings=[
+{key:'fullUrl',itemType:'url',text:'URL'}];
+
+const details=Audit.makeTableDetails(headings,upgradeableResources);
+
+const totalRecords=defaultRecords.length;
+const score=(secureRecords.length+0.5*upgradeableResources.length)/totalRecords;
+
+return{
+rawValue:upgradeableResources.length===0,
+score,
+displayValue:displayValue,
+details};
+
+});
+}}
+
+
+module.exports=MixedContent;
+
+},{"../computed/network-records.js":29,"../lib/url-shim":"url","../report/html/renderer/util":74,"./audit":3}],"../audits/network-requests":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const URL=require('../lib/url-shim');
+const NetworkRecords=require('../computed/network-records.js');
+
+class NetworkRequests extends Audit{
+
+
+
+static get meta(){
+return{
+id:'network-requests',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+title:'Network Requests',
+description:'Lists the network requests that were made during page load.',
+requiredArtifacts:['devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+return NetworkRecords.request(devtoolsLog,context).then(records=>{
+const earliestStartTime=records.reduce(
+(min,record)=>Math.min(min,record.startTime),
+Infinity);
+
+
+
+const timeToMs=time=>time<earliestStartTime||!Number.isFinite(time)?
+undefined:(time-earliestStartTime)*1000;
+
+const results=records.map(record=>{
+return{
+url:URL.elideDataURI(record.url),
+startTime:timeToMs(record.startTime),
+endTime:timeToMs(record.endTime),
+transferSize:record.transferSize,
+statusCode:record.statusCode,
+mimeType:record.mimeType,
+resourceType:record.resourceType};
+
+});
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'startTime',itemType:'ms',granularity:1,text:'Start Time'},
+{key:'endTime',itemType:'ms',granularity:1,text:'End Time'},
+{
+key:'transferSize',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:1,
+text:'Transfer Size'},
+
+{key:'statusCode',itemType:'text',text:'Status Code'},
+{key:'mimeType',itemType:'text',text:'MIME Type'},
+{key:'resourceType',itemType:'text',text:'Resource Type'}];
+
+
+const tableDetails=Audit.makeTableDetails(headings,results);
+
+return{
+score:1,
+rawValue:results.length,
+details:tableDetails};
+
+});
+}}
+
+
+module.exports=NetworkRequests;
+
+},{"../computed/network-records.js":29,"../lib/url-shim":"url","./audit":3}],"../audits/offline-start-url":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit.js');
+
+class OfflineStartUrl extends Audit{
+
+
+
+static get meta(){
+return{
+id:'offline-start-url',
+title:'start_url responds with a 200 when offline',
+failureTitle:'start_url does not respond with a 200 when offline',
+description:'A service worker enables your web app to be reliable in unpredictable network conditions. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/http-200-when-offline).',
+requiredArtifacts:['Manifest','StartUrl']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+
+
+const warnings=[];
+const manifest=artifacts.Manifest;
+if(manifest&&manifest.value&&manifest.value.start_url.warning){
+const manifestWarning=manifest.value.start_url.warning;
+warnings.push('We couldn\'t read the start_url from the manifest. As a result, the '+
+`start_url was assumed to be the document's URL. Error message: '${manifestWarning}'.`);
+}
+
+const hasOfflineStartUrl=artifacts.StartUrl.statusCode===200;
+
+return{
+rawValue:hasOfflineStartUrl,
+explanation:artifacts.StartUrl.explanation,
+warnings};
+
+}}
+
+
+module.exports=OfflineStartUrl;
+
+},{"./audit.js":3}],"../audits/predictive-perf":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const Util=require('../report/html/renderer/util');
+
+const LanternFcp=require('../computed/metrics/lantern-first-contentful-paint.js');
+const LanternFmp=require('../computed/metrics/lantern-first-meaningful-paint.js');
+const LanternInteractive=require('../computed/metrics/lantern-interactive.js');
+const LanternFirstCPUIdle=require('../computed/metrics/lantern-first-cpu-idle.js');
+const LanternSpeedIndex=require('../computed/metrics/lantern-speed-index.js');
+const LanternEil=require('../computed/metrics/lantern-estimated-input-latency.js');
+
+
+
+const SCORING_POINT_OF_DIMINISHING_RETURNS=1700;
+const SCORING_MEDIAN=10000;
+
+class PredictivePerf extends Audit{
+
+
+
+static get meta(){
+return{
+id:'predictive-perf',
+title:'Predicted Performance (beta)',
+description:
+'Predicted performance evaluates how your site will perform under '+
+'a cellular connection on a mobile device.',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+
+const settings={};
+const fcp=await LanternFcp.request({trace,devtoolsLog,settings},context);
+const fmp=await LanternFmp.request({trace,devtoolsLog,settings},context);
+const tti=await LanternInteractive.request({trace,devtoolsLog,settings},context);
+const ttfcpui=await LanternFirstCPUIdle.request({trace,devtoolsLog,settings},context);
+const si=await LanternSpeedIndex.request({trace,devtoolsLog,settings},context);
+const eil=await LanternEil.request({trace,devtoolsLog,settings},context);
+
+const values={
+roughEstimateOfFCP:fcp.timing,
+optimisticFCP:fcp.optimisticEstimate.timeInMs,
+pessimisticFCP:fcp.pessimisticEstimate.timeInMs,
+
+roughEstimateOfFMP:fmp.timing,
+optimisticFMP:fmp.optimisticEstimate.timeInMs,
+pessimisticFMP:fmp.pessimisticEstimate.timeInMs,
+
+roughEstimateOfTTI:tti.timing,
+optimisticTTI:tti.optimisticEstimate.timeInMs,
+pessimisticTTI:tti.pessimisticEstimate.timeInMs,
+
+roughEstimateOfTTFCPUI:ttfcpui.timing,
+optimisticTTFCPUI:ttfcpui.optimisticEstimate.timeInMs,
+pessimisticTTFCPUI:ttfcpui.pessimisticEstimate.timeInMs,
+
+roughEstimateOfSI:si.timing,
+optimisticSI:si.optimisticEstimate.timeInMs,
+pessimisticSI:si.pessimisticEstimate.timeInMs,
+
+roughEstimateOfEIL:eil.timing,
+optimisticEIL:eil.optimisticEstimate.timeInMs,
+pessimisticEIL:eil.pessimisticEstimate.timeInMs};
+
+
+const score=Audit.computeLogNormalScore(
+values.roughEstimateOfTTI,
+SCORING_POINT_OF_DIMINISHING_RETURNS,
+SCORING_MEDIAN);
+
+
+return{
+score,
+rawValue:values.roughEstimateOfTTI,
+displayValue:Util.formatMilliseconds(values.roughEstimateOfTTI),
+details:{items:[values]}};
+
+}}
+
+
+module.exports=PredictivePerf;
+
+},{"../computed/metrics/lantern-estimated-input-latency.js":19,"../computed/metrics/lantern-first-contentful-paint.js":20,"../computed/metrics/lantern-first-cpu-idle.js":21,"../computed/metrics/lantern-first-meaningful-paint.js":22,"../computed/metrics/lantern-interactive.js":23,"../computed/metrics/lantern-speed-index.js":25,"../report/html/renderer/util":74,"./audit":3}],"../audits/redirects-http":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+
+class RedirectsHTTP extends Audit{
+
+
+
+static get meta(){
+return{
+id:'redirects-http',
+title:'Redirects HTTP traffic to HTTPS',
+failureTitle:'Does not redirect HTTP traffic to HTTPS',
+description:'If you\'ve already set up HTTPS, make sure that you redirect all HTTP '+
+'traffic to HTTPS. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/http-redirects-to-https).',
+requiredArtifacts:['HTTPRedirect']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+return{
+rawValue:artifacts.HTTPRedirect.value};
+
+}}
+
+
+module.exports=RedirectsHTTP;
+
+},{"./audit":3}],"../audits/redirects":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
+const i18n=require('../lib/i18n/i18n.js');
+const TraceOfTab=require('../computed/trace-of-tab.js');
+const NetworkRecords=require('../computed/network-records.js');
+const MainResource=require('../computed/main-resource.js');
+const LanternInteractive=require('../computed/metrics/lantern-interactive.js');
+
+const UIStrings={
+
+title:'Avoid multiple page redirects',
+
+description:'Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects).'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class Redirects extends Audit{
+
+
+
+static get meta(){
+return{
+id:'redirects',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['URL','devtoolsLogs','traces']};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const settings=context.settings;
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+const traceOfTab=await TraceOfTab.request(trace,context);
+const networkRecords=await NetworkRecords.request(devtoolsLog,context);
+const mainResource=await MainResource.request({URL:artifacts.URL,devtoolsLog},context);
+
+const metricComputationData={trace,devtoolsLog,traceOfTab,networkRecords,settings};
+const metricResult=await LanternInteractive.request(metricComputationData,context);
+
+
+const nodeTimingsByUrl=new Map();
+for(const[node,timing]of metricResult.pessimisticEstimate.nodeTimings.entries()){
+if(node.type==='network'){
+const networkNode=node;
+nodeTimingsByUrl.set(networkNode.record.url,timing);
+}
+}
+
+
+const redirectRequests=Array.from(mainResource.redirects||[]);
+
+
+redirectRequests.push(mainResource);
+
+let totalWastedMs=0;
+const pageRedirects=[];
+
+
+if(redirectRequests.length>1){
+pageRedirects.push({
+url:`(Initial: ${redirectRequests[0].url})`,
+wastedMs:0});
+
+}
+
+for(let i=1;i<redirectRequests.length;i++){
+const initialRequest=redirectRequests[i-1];
+const redirectedRequest=redirectRequests[i];
+
+const initialTiming=nodeTimingsByUrl.get(initialRequest.url);
+const redirectedTiming=nodeTimingsByUrl.get(redirectedRequest.url);
+if(!initialTiming||!redirectedTiming){
+throw new Error('Could not find redirects in graph');
+}
+
+const wastedMs=redirectedTiming.startTime-initialTiming.startTime;
+totalWastedMs+=wastedMs;
+
+pageRedirects.push({
+url:redirectedRequest.url,
+wastedMs});
+
+}
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnTimeSpent)}];
+
+const details=Audit.makeOpportunityDetails(headings,pageRedirects,totalWastedMs);
+
+return{
+
+score:redirectRequests.length<=2?1:UnusedBytes.scoreForWastedMs(totalWastedMs),
+rawValue:totalWastedMs,
+displayValue:totalWastedMs?
+str_(i18n.UIStrings.displayValueMsSavings,{wastedMs:totalWastedMs}):
+'',
+extendedInfo:{
+value:{
+wastedMs:totalWastedMs}},
+
+
+details};
+
+}}
+
+
+module.exports=Redirects;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/redirects.js");
+},{"../computed/main-resource.js":11,"../computed/metrics/lantern-interactive.js":23,"../computed/network-records.js":29,"../computed/trace-of-tab.js":33,"../lib/i18n/i18n.js":59,"./audit":3,"./byte-efficiency/byte-efficiency-audit":4}],"../audits/screenshot-thumbnails":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const LHError=require('../lib/lh-error');
+const jpeg=require('jpeg-js');
+const Speedline=require('../computed/speedline.js');
+const Interactive=require('../computed/metrics/interactive.js');
+
+const NUMBER_OF_THUMBNAILS=10;
+const THUMBNAIL_WIDTH=120;
+
+
+
+class ScreenshotThumbnails extends Audit{
+
+
+
+static get meta(){
+return{
+id:'screenshot-thumbnails',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+title:'Screenshot Thumbnails',
+description:'This is what the load of your site looked like.',
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+
+
+static scaleImageToThumbnail(imageData){
+const scaledWidth=THUMBNAIL_WIDTH;
+const scaleFactor=imageData.width/scaledWidth;
+const scaledHeight=Math.floor(imageData.height/scaleFactor);
+
+const outPixels=new Uint8Array(scaledWidth*scaledHeight*4);
+
+for(let i=0;i<scaledWidth;i++){
+for(let j=0;j<scaledHeight;j++){
+const origX=Math.floor(i*scaleFactor);
+const origY=Math.floor(j*scaleFactor);
+
+const origPos=(origY*imageData.width+origX)*4;
+const outPos=(j*scaledWidth+i)*4;
+
+outPixels[outPos]=imageData.data[origPos];
+outPixels[outPos+1]=imageData.data[origPos+1];
+outPixels[outPos+2]=imageData.data[origPos+2];
+outPixels[outPos+3]=imageData.data[origPos+3];
+}
+}
+
+return{
+width:scaledWidth,
+height:scaledHeight,
+data:outPixels};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+
+const cachedThumbnails=new Map();
+
+const speedline=await Speedline.request(trace,context);
+
+
+let minimumTimelineDuration=context.options.minimumTimelineDuration||3000;
+
+if(context.settings.throttlingMethod!=='simulate'){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const tti=Interactive.request(metricComputationData,context);
+try{
+minimumTimelineDuration=Math.max((await tti).timing,minimumTimelineDuration);
+}catch(_){}
+}
+
+const thumbnails=[];
+const analyzedFrames=speedline.frames.filter(frame=>!frame.isProgressInterpolated());
+const maxFrameTime=
+speedline.complete||
+Math.max(...speedline.frames.map(frame=>frame.getTimeStamp()-speedline.beginning));
+const timelineEnd=Math.max(maxFrameTime,minimumTimelineDuration);
+
+if(!analyzedFrames.length||!Number.isFinite(timelineEnd)){
+throw new LHError(LHError.errors.INVALID_SPEEDLINE);
+}
+
+for(let i=1;i<=NUMBER_OF_THUMBNAILS;i++){
+const targetTimestamp=speedline.beginning+timelineEnd*i/NUMBER_OF_THUMBNAILS;
+
+
+
+let frameForTimestamp=null;
+if(i===NUMBER_OF_THUMBNAILS){
+frameForTimestamp=analyzedFrames[analyzedFrames.length-1];
+}else{
+analyzedFrames.forEach(frame=>{
+if(frame.getTimeStamp()<=targetTimestamp){
+frameForTimestamp=frame;
+}
+});
+}
+let base64Data;
+if(cachedThumbnails.has(frameForTimestamp)){
+base64Data=cachedThumbnails.get(frameForTimestamp);
+}else{
+const imageData=frameForTimestamp.getParsedImage();
+const thumbnailImageData=ScreenshotThumbnails.scaleImageToThumbnail(imageData);
+base64Data=jpeg.encode(thumbnailImageData,90).data.toString('base64');
+cachedThumbnails.set(frameForTimestamp,base64Data);
+}
+thumbnails.push({
+timing:Math.round(targetTimestamp-speedline.beginning),
+timestamp:targetTimestamp*1000,
+data:base64Data});
+
+}
+
+return{
+score:1,
+rawValue:thumbnails.length>0,
+details:{
+type:'filmstrip',
+scale:timelineEnd,
+items:thumbnails}};
+
+
+}}
+
+
+module.exports=ScreenshotThumbnails;
+
+},{"../computed/metrics/interactive.js":18,"../computed/speedline.js":32,"../lib/lh-error":63,"./audit":3,"jpeg-js":110}],"../audits/seo/canonical":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const LinkHeader=require('http-link-header');
+const URL=require('../../lib/url-shim');
+const MainResource=require('../../computed/main-resource.js');
+const LINK_HEADER='link';
+
+
+
+
+
+function getCanonicalLinksFromHeader(headerValue){
+const linkHeader=LinkHeader.parse(headerValue);
+
+return linkHeader.get('rel','canonical').map(c=>c.uri);
+}
+
+
+
+
+
+function getHreflangsFromHeader(headerValue){
+const linkHeader=LinkHeader.parse(headerValue);
+
+return linkHeader.get('rel','alternate').map(h=>h.uri);
+}
+
+
+
+
+
+
+function isValidRelativeOrAbsoluteURL(url){
+try{
+new URL(url,'https://example.com/');
+return true;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+
+
+function getPrimaryDomain(url){
+return url.hostname.split('.').slice(-2).join('.');
+}
+
+class Canonical extends Audit{
+
+
+
+static get meta(){
+return{
+id:'canonical',
+title:'Document has a valid `rel=canonical`',
+failureTitle:'Document does not have a valid `rel=canonical`',
+description:'Canonical links suggest which URL to show in search results. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/canonical).',
+requiredArtifacts:['Canonical','Hreflang','URL']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+return MainResource.request({devtoolsLog,URL:artifacts.URL},context).
+then(mainResource=>{
+const baseURL=new URL(mainResource.url);
+
+let canonicals=[];
+
+let hreflangs=[];
+
+mainResource.responseHeaders&&mainResource.responseHeaders.
+filter(h=>h.name.toLowerCase()===LINK_HEADER).
+forEach(h=>{
+canonicals=canonicals.concat(getCanonicalLinksFromHeader(h.value));
+hreflangs=hreflangs.concat(getHreflangsFromHeader(h.value));
+});
+
+for(const canonical of artifacts.Canonical){
+if(canonical!==null){
+canonicals.push(canonical);
+}
+}
+
+
+canonicals=Array.from(new Set(canonicals));
+
+artifacts.Hreflang.forEach(({href})=>hreflangs.push(href));
+
+hreflangs=hreflangs.
+filter(href=>isValidRelativeOrAbsoluteURL(href)).
+map(href=>new URL(href,baseURL).href);
+
+if(canonicals.length===0){
+return{
+rawValue:true,
+notApplicable:true};
+
+}
+
+if(canonicals.length>1){
+return{
+rawValue:false,
+explanation:`Multiple conflicting URLs (${canonicals.join(', ')})`};
+
+}
+
+const canonical=canonicals[0];
+
+if(!isValidRelativeOrAbsoluteURL(canonical)){
+return{
+rawValue:false,
+explanation:`Invalid URL (${canonical})`};
+
+}
+
+if(!URL.isValid(canonical)){
+return{
+rawValue:false,
+explanation:`Relative URL (${canonical})`};
+
+}
+
+const canonicalURL=new URL(canonical);
+
+
+if(hreflangs.includes(baseURL.href)&&hreflangs.includes(canonicalURL.href)&&
+baseURL.href!==canonicalURL.href){
+return{
+rawValue:false,
+explanation:`Points to another hreflang location (${baseURL.href})`};
+
+}
+
+
+
+if(getPrimaryDomain(canonicalURL)!==getPrimaryDomain(baseURL)){
+return{
+rawValue:false,
+explanation:`Points to a different domain (${canonicalURL})`};
+
+}
+
+
+if(canonicalURL.origin===baseURL.origin&&
+canonicalURL.pathname==='/'&&baseURL.pathname!=='/'){
+return{
+rawValue:false,
+explanation:'Points to a root of the same origin'};
+
+}
+
+return{
+rawValue:true};
+
+});
+}}
+
+
+module.exports=Canonical;
+
+},{"../../computed/main-resource.js":11,"../../lib/url-shim":"url","../audit":3,"http-link-header":94}],"../audits/seo/font-size":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+const URL=require('../../lib/url-shim');
+const i18n=require('../../lib/i18n/i18n.js');
+const Audit=require('../audit');
+const ViewportAudit=require('../viewport');
+const MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT=60;
+
+const UIStrings={
+
+title:'Document uses legible font sizes',
+
+failureTitle:'Document doesn\'t use legible font sizes',
+
+description:'Font sizes less than 12px are too small to be legible and require mobile visitors to “pinch to zoom” in order to read. Strive to have >60% of page text ≥12px. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/font-sizes).',
+
+displayValue:'{decimalProportion, number, extendedPercent} legible text'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+
+
+function getUniqueFailingRules(fontSizeArtifact){
+
+const failingRules=new Map();
+
+fontSizeArtifact.forEach(({cssRule,fontSize,textLength,node})=>{
+const artifactId=getFontArtifactId(cssRule,node);
+const failingRule=failingRules.get(artifactId);
+
+if(!failingRule){
+failingRules.set(artifactId,{
+node,
+cssRule,
+fontSize,
+textLength});
+
+}else{
+failingRule.textLength+=textLength;
+}
+});
+
+return[...failingRules.values()];
+}
+
+
+
+
+
+function getAttributeMap(attributes=[]){
+const map=new Map();
+
+for(let i=0;i<attributes.length;i+=2){
+const name=attributes[i].toLowerCase();
+const value=attributes[i+1].trim();
+
+if(value){
+map.set(name,value);
+}
+}
+
+return map;
+}
+
+
+
+
+
+
+function getSelector(node){
+const attributeMap=getAttributeMap(node.attributes);
+
+if(attributeMap.has('id')){
+return'#'+attributeMap.get('id');
+}else{
+const attrClass=attributeMap.get('class');
+if(attrClass){
+return'.'+attrClass.split(/\s+/).join('.');
+}
+}
+
+return node.localName.toLowerCase();
+}
+
+
+
+
+
+function nodeToTableNode(node){
+const attributes=node.attributes||[];
+const attributesString=attributes.map((value,idx)=>
+idx%2===0?` ${value}`:`="${value}"`).
+join('');
+
+return{
+type:'node',
+selector:node.parentNode?getSelector(node.parentNode):'',
+snippet:`<${node.localName}${attributesString}>`};
+
+}
+
+
+
+
+
+
+
+function findStyleRuleSource(baseURL,styleDeclaration,node){
+if(
+!styleDeclaration||
+styleDeclaration.type==='Attributes'||
+styleDeclaration.type==='Inline')
+{
+return{
+selector:nodeToTableNode(node),
+source:baseURL};
+
+}
+
+if(styleDeclaration.parentRule&&
+styleDeclaration.parentRule.origin==='user-agent'){
+return{
+selector:styleDeclaration.parentRule.selectors.map(item=>item.text).join(', '),
+source:'User Agent Stylesheet'};
+
+}
+
+if(styleDeclaration.type==='Regular'&&styleDeclaration.parentRule){
+const rule=styleDeclaration.parentRule;
+const stylesheet=styleDeclaration.stylesheet;
+
+if(stylesheet){
+let source;
+const selector=rule.selectors.map(item=>item.text).join(', ');
+
+if(stylesheet.sourceURL){
+const url=new URL(stylesheet.sourceURL,baseURL);
+const range=styleDeclaration.range;
+source=`${url.href}`;
+
+if(range){
+
+
+const absoluteStartLine=range.startLine+stylesheet.startLine+1;
+const absoluteStartColumn=range.startColumn+stylesheet.startColumn+1;
+
+source+=`:${absoluteStartLine}:${absoluteStartColumn}`;
+}
+}else{
+
+source='dynamic';
+}
+
+return{
+selector,
+source};
+
+}
+}
+
+return{
+selector:'',
+source:'Unknown'};
+
+}
+
+
+
+
+
+
+function getFontArtifactId(styleDeclaration,node){
+if(styleDeclaration&&styleDeclaration.type==='Regular'){
+const startLine=styleDeclaration.range?styleDeclaration.range.startLine:0;
+const startColumn=styleDeclaration.range?styleDeclaration.range.startColumn:0;
+return`${styleDeclaration.styleSheetId}@${startLine}:${startColumn}`;
+}else{
+return`node_${node.nodeId}`;
+}
+}
+
+class FontSize extends Audit{
+
+
+
+static get meta(){
+return{
+id:'font-size',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['FontSize','URL','Viewport']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const hasViewportSet=ViewportAudit.audit(artifacts).rawValue;
+if(!hasViewportSet){
+return{
+rawValue:false,
+explanation:'Text is illegible because of a missing viewport config'};
+
+}
+
+const{
+analyzedFailingNodesData,
+analyzedFailingTextLength,
+failingTextLength,
+visitedTextLength,
+totalTextLength}=
+artifacts.FontSize;
+
+if(totalTextLength===0){
+return{
+rawValue:true};
+
+}
+
+const failingRules=getUniqueFailingRules(analyzedFailingNodesData);
+const percentageOfPassingText=
+(visitedTextLength-failingTextLength)/visitedTextLength*100;
+const pageUrl=artifacts.URL.finalUrl;
+
+const headings=[
+{key:'source',itemType:'url',text:'Source'},
+{key:'selector',itemType:'code',text:'Selector'},
+{key:'coverage',itemType:'text',text:'% of Page Text'},
+{key:'fontSize',itemType:'text',text:'Font Size'}];
+
+
+const tableData=failingRules.sort((a,b)=>b.textLength-a.textLength).
+map(({cssRule,textLength,fontSize,node})=>{
+const percentageOfAffectedText=textLength/visitedTextLength*100;
+const origin=findStyleRuleSource(pageUrl,cssRule,node);
+
+return{
+source:origin.source,
+selector:origin.selector,
+coverage:`${percentageOfAffectedText.toFixed(2)}%`,
+fontSize:`${fontSize}px`};
+
+});
+
+
+if(analyzedFailingTextLength<failingTextLength){
+const percentageOfUnanalyzedFailingText=
+(failingTextLength-analyzedFailingTextLength)/visitedTextLength*100;
+
+tableData.push({
+source:'Add\'l illegible text',
+selector:'',
+coverage:`${percentageOfUnanalyzedFailingText.toFixed(2)}%`,
+fontSize:'< 12px'});
+
+}
+
+if(percentageOfPassingText>0){
+tableData.push({
+source:'Legible text',
+selector:'',
+coverage:`${percentageOfPassingText.toFixed(2)}%`,
+fontSize:'≥ 12px'});
+
+}
+
+const decimalProportion=percentageOfPassingText/100;
+
+const displayValue=str_(UIStrings.displayValue,{decimalProportion});
+const details=Audit.makeTableDetails(headings,tableData);
+const passed=percentageOfPassingText>=MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT;
+
+let explanation;
+if(!passed){
+const percentageOfFailingText=parseFloat((100-percentageOfPassingText).toFixed(2));
+let disclaimer='';
+
+
+if(visitedTextLength<totalTextLength){
+const percentageOfVisitedText=visitedTextLength/totalTextLength*100;
+disclaimer=` (based on ${percentageOfVisitedText.toFixed()}% sample)`;
+}
+
+explanation=`${percentageOfFailingText}% of text is too small${disclaimer}.`;
+}
+
+return{
+rawValue:passed,
+details,
+displayValue,
+explanation};
+
+}}
+
+
+module.exports=FontSize;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/seo/font-size.js");
+},{"../../lib/i18n/i18n.js":59,"../../lib/url-shim":"url","../audit":3,"../viewport":"../audits/viewport"}],"../audits/seo/hreflang":[function(require,module,exports){
+(function(global){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const LinkHeader=require('http-link-header');
+const MainResource=require('../../computed/main-resource.js');
+const VALID_LANGS=importValidLangs();
+const LINK_HEADER='link';
+const NO_LANGUAGE='x-default';
+
+
+
+
+
+
+
+function importValidLangs(){
+
+const axeCache=global.axe;
+
+global.axe={utils:{}};
+
+require('axe-core/lib/commons/utils/valid-langs.js');
+
+const validLangs=global.axe.utils.validLangs();
+
+global.axe=axeCache;
+
+return validLangs;
+}
+
+
+
+
+
+function isValidHreflang(hreflang){
+if(hreflang.toLowerCase()===NO_LANGUAGE){
+return true;
+}
+
+
+const[lang]=hreflang.split('-');
+return VALID_LANGS.includes(lang.toLowerCase());
+}
+
+
+
+
+
+function headerHasValidHreflangs(headerValue){
+const linkHeader=LinkHeader.parse(headerValue);
+
+return linkHeader.get('rel','alternate').
+every(link=>!!link.hreflang&&isValidHreflang(link.hreflang));
+}
+
+class Hreflang extends Audit{
+
+
+
+static get meta(){
+return{
+id:'hreflang',
+title:'Document has a valid `hreflang`',
+failureTitle:'Document doesn\'t have a valid `hreflang`',
+description:'hreflang links tell search engines what version of a page they should '+
+'list in search results for a given language or region. [Learn more]'+
+'(https://developers.google.com/web/tools/lighthouse/audits/hreflang).',
+requiredArtifacts:['Hreflang','URL']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const URL=artifacts.URL;
+
+return MainResource.request({devtoolsLog,URL},context).
+then(mainResource=>{
+
+const invalidHreflangs=[];
+
+if(artifacts.Hreflang){
+artifacts.Hreflang.forEach(({href,hreflang})=>{
+if(!isValidHreflang(hreflang)){
+invalidHreflangs.push({
+source:{
+type:'node',
+snippet:`<link name="alternate" hreflang="${hreflang}" href="${href}" />`}});
+
+
+}
+});
+}
+
+mainResource.responseHeaders&&mainResource.responseHeaders.
+filter(h=>h.name.toLowerCase()===LINK_HEADER&&!headerHasValidHreflangs(h.value)).
+forEach(h=>invalidHreflangs.push({source:`${h.name}: ${h.value}`}));
+
+const headings=[
+{key:'source',itemType:'code',text:'Source'}];
+
+const details=Audit.makeTableDetails(headings,invalidHreflangs);
+
+return{
+rawValue:invalidHreflangs.length===0,
+details};
+
+});
+}}
+
+
+module.exports=Hreflang;
+
+}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{"../../computed/main-resource.js":11,"../audit":3,"axe-core/lib/commons/utils/valid-langs.js":82,"http-link-header":94}],"../audits/seo/http-status-code":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const MainResource=require('../../computed/main-resource.js');
+const HTTP_UNSUCCESSFUL_CODE_LOW=400;
+const HTTP_UNSUCCESSFUL_CODE_HIGH=599;
+
+class HTTPStatusCode extends Audit{
+
+
+
+static get meta(){
+return{
+id:'http-status-code',
+title:'Page has successful HTTP status code',
+failureTitle:'Page has unsuccessful HTTP status code',
+description:'Pages with unsuccessful HTTP status codes may not be indexed properly. '+
+'[Learn more]'+
+'(https://developers.google.com/web/tools/lighthouse/audits/successful-http-code).',
+requiredArtifacts:['devtoolsLogs','URL']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const URL=artifacts.URL;
+
+return MainResource.request({devtoolsLog,URL},context).
+then(mainResource=>{
+const statusCode=mainResource.statusCode;
+
+if(statusCode>=HTTP_UNSUCCESSFUL_CODE_LOW&&
+statusCode<=HTTP_UNSUCCESSFUL_CODE_HIGH){
+return{
+rawValue:false,
+displayValue:`${statusCode}`};
+
+}
+
+return{
+rawValue:true};
+
+});
+}}
+
+
+module.exports=HTTPStatusCode;
+
+},{"../../computed/main-resource.js":11,"../audit":3}],"../audits/seo/is-crawlable":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const robotsParser=require('robots-parser');
+const URL=require('../../lib/url-shim');
+const MainResource=require('../../computed/main-resource.js');
+const BLOCKLIST=new Set([
+'noindex',
+'none']);
+
+const ROBOTS_HEADER='x-robots-tag';
+const UNAVAILABLE_AFTER='unavailable_after';
+
+
+
+
+
+
+function isUnavailable(directive){
+const parts=directive.split(':');
+
+if(parts.length<=1||parts[0]!==UNAVAILABLE_AFTER){
+return false;
+}
+
+const date=Date.parse(parts.slice(1).join(':'));
+
+return!isNaN(date)&&date<Date.now();
+}
+
+
+
+
+
+
+function hasBlockingDirective(directives){
+return directives.split(',').
+map(d=>d.toLowerCase().trim()).
+some(d=>BLOCKLIST.has(d)||isUnavailable(d));
+}
+
+
+
+
+
+
+function hasUserAgent(directives){
+const parts=directives.match(/^([^,:]+):/);
+
+
+
+return!!parts&&parts[1].toLowerCase()!==UNAVAILABLE_AFTER;
+}
+
+class IsCrawlable extends Audit{
+
+
+
+static get meta(){
+return{
+id:'is-crawlable',
+title:'Page isn’t blocked from indexing',
+failureTitle:'Page is blocked from indexing',
+description:'Search engines are unable to include your pages in search results '+
+'if they don\'t have permission to crawl them. [Learn '+
+'more](https://developers.google.com/web/tools/lighthouse/audits/indexing).',
+requiredArtifacts:['MetaRobots','RobotsTxt','URL']};
+
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+return MainResource.request({devtoolsLog,URL:artifacts.URL},context).
+then(mainResource=>{
+
+const blockingDirectives=[];
+
+if(artifacts.MetaRobots){
+const isBlocking=hasBlockingDirective(artifacts.MetaRobots);
+
+if(isBlocking){
+blockingDirectives.push({
+source:{
+type:'node',
+snippet:`<meta name="robots" content="${artifacts.MetaRobots}" />`}});
+
+
+}
+}
+
+mainResource.responseHeaders&&mainResource.responseHeaders.
+filter(h=>h.name.toLowerCase()===ROBOTS_HEADER&&!hasUserAgent(h.value)&&
+hasBlockingDirective(h.value)).
+forEach(h=>blockingDirectives.push({source:`${h.name}: ${h.value}`}));
+
+if(artifacts.RobotsTxt.content){
+const robotsFileUrl=new URL('/robots.txt',mainResource.url);
+const robotsTxt=robotsParser(robotsFileUrl.href,artifacts.RobotsTxt.content);
+
+if(!robotsTxt.isAllowed(mainResource.url)){
+blockingDirectives.push({
+source:{
+type:'url',
+value:robotsFileUrl.href}});
+
+
+}
+}
+
+const headings=[
+{key:'source',itemType:'code',text:'Blocking Directive Source'}];
+
+const details=Audit.makeTableDetails(headings,blockingDirectives);
+
+return{
+rawValue:blockingDirectives.length===0,
+details};
+
+});
+}}
+
+
+module.exports=IsCrawlable;
+
+},{"../../computed/main-resource.js":11,"../../lib/url-shim":"url","../audit":3,"robots-parser":149}],"../audits/seo/link-text":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const URL=require('../../lib/url-shim');
+const BLOCKLIST=new Set([
+'click here',
+'click this',
+'go',
+'here',
+'this',
+'start',
+'right here',
+'more',
+'learn more']);
+
+
+class LinkText extends Audit{
+
+
+
+static get meta(){
+return{
+id:'link-text',
+title:'Links have descriptive text',
+failureTitle:'Links do not have descriptive text',
+description:'Descriptive link text helps search engines understand your content. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/descriptive-link-text).',
+requiredArtifacts:['URL','CrawlableLinks']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const failingLinks=artifacts.CrawlableLinks.
+filter(link=>{
+const href=link.href.toLowerCase();
+if(
+href.startsWith('javascript:')||
+href.startsWith('mailto:')||
+URL.equalWithExcludedFragments(link.href,artifacts.URL.finalUrl))
+{
+return false;
+}
+
+return BLOCKLIST.has(link.text.trim().toLowerCase());
+}).
+map(link=>{
+return{
+href:link.href,
+text:link.text.trim()};
+
+});
+
+const headings=[
+{key:'href',itemType:'url',text:'Link destination'},
+{key:'text',itemType:'text',text:'Link Text'}];
+
+
+const details=Audit.makeTableDetails(headings,failingLinks,{});
+let displayValue;
+
+if(failingLinks.length){
+displayValue=failingLinks.length>1?
+`${failingLinks.length} links found`:'1 link found';
+}
+
+return{
+rawValue:failingLinks.length===0,
+details,
+displayValue};
+
+}}
+
+
+module.exports=LinkText;
+
+},{"../../lib/url-shim":"url","../audit":3}],"../audits/seo/manual/mobile-friendly":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class MobileFriendly extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'mobile-friendly',
+description:'Take the [Mobile-Friendly Test](https://search.google.com/test/mobile-friendly) to check for audits not covered by Lighthouse, like sizing tap targets appropriately. [Learn more](https://developers.google.com/search/mobile-sites/).',
+title:'Page is mobile friendly'},
+super.partialMeta);
+}}
+
+
+module.exports=MobileFriendly;
+
+},{"../../manual/manual-audit":5}],"../audits/seo/manual/structured-data":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ManualAudit=require('../../manual/manual-audit');
+
+
+
+
+
+class StructuredData extends ManualAudit{
+
+
+
+static get meta(){
+return Object.assign({
+id:'structured-data',
+description:'Run the [Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/) and the [Structured Data Linter](http://linter.structured-data.org/) to validate structured data. [Learn more](https://developers.google.com/search/docs/guides/mark-up-content).',
+title:'Structured data is valid'},
+super.partialMeta);
+}}
+
+
+module.exports=StructuredData;
+
+},{"../../manual/manual-audit":5}],"../audits/seo/meta-description":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+
+class Description extends Audit{
+
+
+
+static get meta(){
+return{
+id:'meta-description',
+title:'Document has a meta description',
+failureTitle:'Document does not have a meta description',
+description:'Meta descriptions may be included in search results to concisely summarize '+
+'page content. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/description).',
+requiredArtifacts:['MetaDescription']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+if(artifacts.MetaDescription===null){
+return{
+rawValue:false};
+
+}
+
+if(artifacts.MetaDescription.trim().length===0){
+return{
+rawValue:false,
+explanation:'Description text is empty.'};
+
+}
+
+return{
+rawValue:true};
+
+}}
+
+
+module.exports=Description;
+
+},{"../audit":3}],"../audits/seo/plugins":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const URL=require('../../lib/url-shim');
+
+const JAVA_APPLET_TYPE='application/x-java-applet';
+const JAVA_BEAN_TYPE='application/x-java-bean';
+const TYPE_BLOCKLIST=new Set([
+'application/x-shockwave-flash',
+
+JAVA_APPLET_TYPE,
+JAVA_BEAN_TYPE,
+
+'application/x-silverlight',
+'application/x-silverlight-2']);
+
+const FILE_EXTENSION_BLOCKLIST=new Set([
+'swf',
+'flv',
+'class',
+'xap']);
+
+const SOURCE_PARAMS=new Set([
+'code',
+'movie',
+'source',
+'src']);
+
+
+
+
+
+
+
+function isPluginType(type){
+type=type.trim().toLowerCase();
+
+return TYPE_BLOCKLIST.has(type)||
+type.startsWith(JAVA_APPLET_TYPE)||
+type.startsWith(JAVA_BEAN_TYPE);
+}
+
+
+
+
+
+
+function isPluginURL(url){
+try{
+
+const filePath=new URL(url,'http://example.com').pathname;
+const parts=filePath.split('.');
+
+if(parts.length<2){
+return false;
+}
+const part=parts.pop();
+return FILE_EXTENSION_BLOCKLIST.has(part.trim().toLowerCase());
+}catch(e){
+return false;
+}
+}
+
+class Plugins extends Audit{
+
+
+
+static get meta(){
+return{
+id:'plugins',
+title:'Document avoids plugins',
+failureTitle:'Document uses plugins',
+description:'Search engines can\'t index plugin content, and '+
+'many devices restrict plugins or don\'t support them. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/plugins).',
+requiredArtifacts:['EmbeddedContent']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const plugins=artifacts.EmbeddedContent.
+filter(item=>{
+if(item.tagName==='APPLET'){
+return true;
+}
+
+if(
+(item.tagName==='EMBED'||item.tagName==='OBJECT')&&
+item.type&&
+isPluginType(item.type))
+{
+return true;
+}
+
+const embedSrc=item.src||item.code;
+if(item.tagName==='EMBED'&&embedSrc&&isPluginURL(embedSrc)){
+return true;
+}
+
+if(item.tagName==='OBJECT'&&item.data&&isPluginURL(item.data)){
+return true;
+}
+
+const failingParams=item.params.filter(param=>
+SOURCE_PARAMS.has(param.name.trim().toLowerCase())&&isPluginURL(param.value));
+
+
+return failingParams.length>0;
+}).
+map(plugin=>{
+const tagName=plugin.tagName.toLowerCase();
+
+const attributeKeys=['src','data','code','type'];
+const attributes=attributeKeys.
+reduce((result,attr)=>{
+if(plugin[attr]!==null){
+result+=` ${attr}="${plugin[attr]}"`;
+}
+return result;
+},'');
+const params=plugin.params.
+filter(param=>SOURCE_PARAMS.has(param.name.trim().toLowerCase())).
+map(param=>`<param ${param.name}="${param.value}" />`).
+join('');
+
+return{
+source:{
+type:'node',
+snippet:`<${tagName}${attributes}>${params}</${tagName}>`}};
+
+
+});
+
+const headings=[
+{key:'source',itemType:'code',text:'Element source'}];
+
+
+const details=Audit.makeTableDetails(headings,plugins);
+
+return{
+rawValue:plugins.length===0,
+details};
+
+}}
+
+
+module.exports=Plugins;
+
+},{"../../lib/url-shim":"url","../audit":3}],"../audits/seo/robots-txt":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+const Audit=require('../audit');
+const URL=require('../../lib/url-shim');
+
+const HTTP_CLIENT_ERROR_CODE_LOW=400;
+const HTTP_SERVER_ERROR_CODE_LOW=500;
+
+const DIRECTIVE_SITEMAP='sitemap';
+const DIRECTIVE_USER_AGENT='user-agent';
+const DIRECTIVE_ALLOW='allow';
+const DIRECTIVE_DISALLOW='disallow';
+const DIRECTIVES_GROUP_MEMBERS=new Set([DIRECTIVE_ALLOW,DIRECTIVE_DISALLOW]);
+const DIRECTIVE_SAFELIST=new Set([
+DIRECTIVE_USER_AGENT,DIRECTIVE_DISALLOW,
+DIRECTIVE_ALLOW,DIRECTIVE_SITEMAP,
+'crawl-delay',
+'clean-param','host',
+'request-rate','visit-time','noindex']);
+
+const SITEMAP_VALID_PROTOCOLS=new Set(['https:','http:','ftp:']);
+
+
+
+
+
+
+function verifyDirective(directiveName,directiveValue){
+if(!DIRECTIVE_SAFELIST.has(directiveName)){
+throw new Error('Unknown directive');
+}
+
+if(directiveName===DIRECTIVE_SITEMAP){
+let sitemapUrl;
+
+try{
+sitemapUrl=new URL(directiveValue);
+}catch(e){
+throw new Error('Invalid sitemap URL');
+}
+
+if(!SITEMAP_VALID_PROTOCOLS.has(sitemapUrl.protocol)){
+throw new Error('Invalid sitemap URL protocol');
+}
+}
+
+if(directiveName===DIRECTIVE_USER_AGENT&&!directiveValue){
+throw new Error('No user-agent specified');
+}
+
+if(directiveName===DIRECTIVE_ALLOW||directiveName===DIRECTIVE_DISALLOW){
+if(directiveValue!==''&&directiveValue[0]!=='/'&&directiveValue[0]!=='*'){
+throw new Error('Pattern should either be empty, start with "/" or "*"');
+}
+
+const dollarIndex=directiveValue.indexOf('$');
+
+if(dollarIndex!==-1&&dollarIndex!==directiveValue.length-1){
+throw new Error('"$" should only be used at the end of the pattern');
+}
+}
+}
+
+
+
+
+
+
+function parseLine(line){
+const hashIndex=line.indexOf('#');
+
+if(hashIndex!==-1){
+line=line.substr(0,hashIndex);
+}
+
+line=line.trim();
+
+if(line.length===0){
+return null;
+}
+
+const colonIndex=line.indexOf(':');
+
+if(colonIndex===-1){
+throw new Error('Syntax not understood');
+}
+
+const directiveName=line.slice(0,colonIndex).trim().toLowerCase();
+const directiveValue=line.slice(colonIndex+1).trim();
+
+verifyDirective(directiveName,directiveValue);
+
+return{
+directive:directiveName,
+value:directiveValue};
+
+}
+
+
+
+
+
+function validateRobots(content){
+
+
+
+const errors=[];
+let inGroup=false;
+
+content.
+split(/\r\n|\r|\n/).
+forEach((line,index)=>{
+let parsedLine;
+
+try{
+parsedLine=parseLine(line);
+}catch(e){
+errors.push({
+index:(index+1).toString(),
+line:line,
+message:e.message.toString()});
+
+}
+
+if(!parsedLine){
+return;
+}
+
+
+
+if(parsedLine.directive===DIRECTIVE_USER_AGENT){
+inGroup=true;
+}else if(!inGroup&&DIRECTIVES_GROUP_MEMBERS.has(parsedLine.directive)){
+errors.push({
+index:(index+1).toString(),
+line:line,
+message:'No user-agent specified'});
+
+}
+});
+
+return errors;
+}
+
+class RobotsTxt extends Audit{
+
+
+
+static get meta(){
+return{
+id:'robots-txt',
+title:'robots.txt is valid',
+failureTitle:'robots.txt is not valid',
+description:'If your robots.txt file is malformed, crawlers may not be able to understand '+
+'how you want your website to be crawled or indexed.',
+requiredArtifacts:['RobotsTxt']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const{
+status,
+content}=
+artifacts.RobotsTxt;
+
+if(!status){
+return{
+rawValue:false,
+explanation:'Lighthouse was unable to download your robots.txt file'};
+
+}
+
+if(status>=HTTP_SERVER_ERROR_CODE_LOW){
+return{
+rawValue:false,
+displayValue:`request for robots.txt returned HTTP${status}`};
+
+}else if(status>=HTTP_CLIENT_ERROR_CODE_LOW||content===''){
+return{
+rawValue:true,
+notApplicable:true};
+
+}
+
+
+if(content===null){
+throw new Error(`Status ${status} was valid, but content was null`);
+}
+
+const validationErrors=validateRobots(content);
+
+const headings=[
+{key:'index',itemType:'text',text:'Line #'},
+{key:'line',itemType:'code',text:'Content'},
+{key:'message',itemType:'code',text:'Error'}];
+
+
+const details=Audit.makeTableDetails(headings,validationErrors,{});
+let displayValue;
+
+if(validationErrors.length){
+displayValue=validationErrors.length>1?
+`${validationErrors.length} errors found`:'1 error found';
+}
+
+return{
+rawValue:validationErrors.length===0,
+details,
+displayValue};
+
+}}
+
+
+module.exports=RobotsTxt;
+
+},{"../../lib/url-shim":"url","../audit":3}],"../audits/service-worker":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const URL=require('../lib/url-shim.js');
+const Audit=require('./audit.js');
+
+class ServiceWorker extends Audit{
+
+
+
+static get meta(){
+return{
+id:'service-worker',
+title:'Registers a service worker that controls page and start_url',
+failureTitle:'Does not register a service worker that controls page and start_url',
+description:'The service worker is the technology that enables your app to use many '+
+'Progressive Web App features, such as offline, add to homescreen, and push '+
+'notifications. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/registered-service-worker).',
+requiredArtifacts:['URL','ServiceWorker','Manifest']};
+
+}
+
+
+
+
+
+
+
+static getVersionsForOrigin(versions,pageUrl){
+return versions.
+filter(v=>v.status==='activated').
+filter(v=>new URL(v.scriptURL).origin===pageUrl.origin);
+}
+
+
+
+
+
+
+
+
+
+static getControllingScopeUrl(matchingSWVersions,registrations,pageUrl){
+
+const matchingScopeUrls=matchingSWVersions.
+map(v=>registrations.find(r=>r.registrationId===v.registrationId)).
+filter(r=>!!r).
+map(r=>new URL(r.scopeURL).href);
+
+
+
+const pageControllingScope=matchingScopeUrls.
+filter(scopeUrl=>pageUrl.href.startsWith(scopeUrl)).
+sort((scopeA,scopeB)=>scopeA.length-scopeB.length).
+pop();
+
+return pageControllingScope;
+}
+
+
+
+
+
+
+
+
+static checkStartUrl(manifest,scopeUrl){
+if(!manifest){
+return'no start_url was found because no manifest was fetched';
+}
+if(!manifest.value){
+return'no start_url was found because manifest failed to parse as valid JSON';
+}
+
+const startUrl=manifest.value.start_url.value;
+if(!startUrl.startsWith(scopeUrl)){
+return`the start_url ("${startUrl}") is not in the service worker's scope ("${scopeUrl}")`;
+}
+}
+
+
+
+
+
+static audit(artifacts){
+
+const pageUrl=new URL(artifacts.URL.finalUrl);
+const{versions,registrations}=artifacts.ServiceWorker;
+
+const versionsForOrigin=ServiceWorker.getVersionsForOrigin(versions,pageUrl);
+if(versionsForOrigin.length===0){
+return{
+rawValue:false};
+
+}
+
+const controllingScopeUrl=ServiceWorker.getControllingScopeUrl(versionsForOrigin,
+registrations,pageUrl);
+if(!controllingScopeUrl){
+return{
+rawValue:false,
+explanation:`This origin has one or more service workers, however the page ("${pageUrl.href}") is not in scope.`};
+
+}
+
+const startUrlFailure=ServiceWorker.checkStartUrl(artifacts.Manifest,controllingScopeUrl);
+if(startUrlFailure){
+return{
+rawValue:false,
+explanation:`This page is controlled by a service worker, however ${startUrlFailure}.`};
+
+}
+
+
+return{
+rawValue:true};
+
+}}
+
+
+module.exports=ServiceWorker;
+
+},{"../lib/url-shim.js":"url","./audit.js":3}],"../audits/splash-screen":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MultiCheckAudit=require('./multi-check-audit');
+const ManifestValues=require('../computed/manifest-values.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class SplashScreen extends MultiCheckAudit{
+
+
+
+static get meta(){
+return{
+id:'splash-screen',
+title:'Configured for a custom splash screen',
+failureTitle:'Is not configured for a custom splash screen',
+description:'A themed splash screen ensures a high-quality experience when '+
+'users launch your app from their homescreens. [Learn '+
+'more](https://developers.google.com/web/tools/lighthouse/audits/custom-splash-screen).',
+requiredArtifacts:['Manifest']};
+
+}
+
+
+
+
+
+static assessManifest(manifestValues,failures){
+if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
+failures.push(manifestValues.parseFailureReason);
+return;
+}
+
+const splashScreenCheckIds=[
+'hasName',
+'hasBackgroundColor',
+'hasThemeColor',
+'hasIconsAtLeast512px'];
+
+
+manifestValues.allChecks.
+filter(item=>splashScreenCheckIds.includes(item.id)).
+forEach(item=>{
+if(!item.passing){
+failures.push(item.failureText);
+}
+});
+}
+
+
+
+
+
+
+static async audit_(artifacts,context){
+
+const failures=[];
+
+const manifestValues=await ManifestValues.request(artifacts.Manifest,context);
+SplashScreen.assessManifest(manifestValues,failures);
+
+return{
+failures,
+manifestValues};
+
+}}
+
+
+module.exports=SplashScreen;
+
+},{"../computed/manifest-values.js":13,"./multi-check-audit":6}],"../audits/themed-omnibox":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MultiCheckAudit=require('./multi-check-audit');
+const ManifestValues=require('../computed/manifest-values.js');
+const cssParsers=require('cssstyle/lib/parsers');
+
+
+
+
+
+
+
+
+
+
+
+class ThemedOmnibox extends MultiCheckAudit{
+
+
+
+static get meta(){
+return{
+id:'themed-omnibox',
+title:'Sets an address-bar theme color',
+failureTitle:'Does not set an address-bar theme color',
+description:'The browser address bar can be themed to match your site. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/address-bar).',
+requiredArtifacts:['Manifest','ThemeColor']};
+
+}
+
+
+
+
+
+static isValidColor(color){
+return cssParsers.valueType(color)===cssParsers.TYPES.COLOR;
+}
+
+
+
+
+
+static assessMetaThemecolor(themeColorMeta,failures){
+if(themeColorMeta===null){
+failures.push('No `<meta name="theme-color">` tag found');
+}else if(!ThemedOmnibox.isValidColor(themeColorMeta)){
+failures.push('The theme-color meta tag did not contain a valid CSS color');
+}
+}
+
+
+
+
+
+static assessManifest(manifestValues,failures){
+if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
+failures.push(manifestValues.parseFailureReason);
+return;
+}
+
+const themeColorCheck=manifestValues.allChecks.find(i=>i.id==='hasThemeColor');
+if(themeColorCheck&&!themeColorCheck.passing){
+failures.push(themeColorCheck.failureText);
+}
+}
+
+
+
+
+
+
+static async audit_(artifacts,context){
+
+const failures=[];
+
+const manifestValues=await ManifestValues.request(artifacts.Manifest,context);
+ThemedOmnibox.assessManifest(manifestValues,failures);
+ThemedOmnibox.assessMetaThemecolor(artifacts.ThemeColor,failures);
+
+return{
+failures,
+manifestValues,
+themeColor:artifacts.ThemeColor};
+
+}}
+
+
+module.exports=ThemedOmnibox;
+
+},{"../computed/manifest-values.js":13,"./multi-check-audit":6,"cssstyle/lib/parsers":90}],"../audits/time-to-first-byte":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const i18n=require('../lib/i18n/i18n.js');
+const MainResource=require('../computed/main-resource.js');
+
+const UIStrings={
+
+title:'Server response times are low (TTFB)',
+
+failureTitle:'Reduce server response times (TTFB)',
+
+description:'Time To First Byte identifies the time at which your server sends a response.'+
+' [Learn more](https://developers.google.com/web/tools/lighthouse/audits/ttfb).',
+
+displayValue:`Root document took {timeInMs, number, milliseconds}\xa0ms`};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const TTFB_THRESHOLD=600;
+
+class TTFBMetric extends Audit{
+
+
+
+static get meta(){
+return{
+id:'time-to-first-byte',
+title:str_(UIStrings.title),
+failureTitle:str_(UIStrings.failureTitle),
+description:str_(UIStrings.description),
+requiredArtifacts:['devtoolsLogs','URL']};
+
+}
+
+
+
+
+static caclulateTTFB(record){
+const timing=record.timing;
+return timing?timing.receiveHeadersEnd-timing.sendEnd:0;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const mainResource=await MainResource.request({devtoolsLog,URL:artifacts.URL},context);
+
+const ttfb=TTFBMetric.caclulateTTFB(mainResource);
+const passed=ttfb<TTFB_THRESHOLD;
+const displayValue=str_(UIStrings.displayValue,{timeInMs:ttfb});
+
+
+const details={
+type:'opportunity',
+overallSavingsMs:ttfb-TTFB_THRESHOLD,
+headings:[],
+items:[]};
+
+
+return{
+rawValue:ttfb,
+score:Number(passed),
+displayValue,
+details,
+extendedInfo:{
+value:{
+wastedMs:ttfb-TTFB_THRESHOLD}}};
+
+
+
+}}
+
+
+module.exports=TTFBMetric;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/time-to-first-byte.js");
+},{"../computed/main-resource.js":11,"../lib/i18n/i18n.js":59,"./audit":3}],"../audits/user-timings":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const i18n=require('../lib/i18n/i18n.js');
+const ComputedUserTimings=require('../computed/user-timings.js');
+
+const UIStrings={
+
+title:'User Timing marks and measures',
+
+description:'Consider instrumenting your app with the User Timing API to measure your '+
+'app\'s real-world performance during key user experiences. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/user-timing).',
+
+displayValue:`{itemCount, plural,
+ =1 {1 user timing}
+ other {# user timings}
+ }`,
+
+columnName:'Name',
+
+columnType:'Type',
+
+columnStartTime:'Start Time',
+
+columnDuration:'Duration'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+
+class UserTimings extends Audit{
+
+
+
+static get meta(){
+return{
+id:'user-timings',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+requiredArtifacts:['traces']};
+
+}
+
+
+
+
+static get blacklistedPrefixes(){
+return['goog_'];
+}
+
+
+
+
+
+
+static excludeBlacklisted(evt){
+return UserTimings.blacklistedPrefixes.every(prefix=>!evt.name.startsWith(prefix));
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+return ComputedUserTimings.request(trace,context).then(computedUserTimings=>{
+const userTimings=computedUserTimings.filter(UserTimings.excludeBlacklisted);
+const tableRows=userTimings.map(item=>{
+return{
+name:item.name,
+startTime:item.startTime,
+duration:item.isMark?undefined:item.duration,
+timingType:item.isMark?'Mark':'Measure'};
+
+}).sort((itemA,itemB)=>{
+if(itemA.timingType===itemB.timingType){
+
+return itemA.startTime-itemB.startTime;
+}else if(itemA.timingType==='Measure'){
+
+return-1;
+}else{
+return 1;
+}
+});
+
+const headings=[
+{key:'name',itemType:'text',text:str_(UIStrings.columnName)},
+{key:'timingType',itemType:'text',text:str_(UIStrings.columnType)},
+{key:'startTime',itemType:'ms',granularity:0.01,
+text:str_(UIStrings.columnStartTime)},
+{key:'duration',itemType:'ms',granularity:0.01,text:str_(UIStrings.columnDuration)}];
+
+
+const details=Audit.makeTableDetails(headings,tableRows);
+
+
+let displayValue;
+if(userTimings.length){
+displayValue=str_(UIStrings.displayValue,{itemCount:userTimings.length});
+}
+
+return{
+
+rawValue:userTimings.length===0,
+notApplicable:userTimings.length===0,
+displayValue,
+extendedInfo:{
+value:userTimings},
+
+details};
+
+});
+}}
+
+
+module.exports=UserTimings;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/user-timings.js");
+},{"../computed/user-timings.js":34,"../lib/i18n/i18n.js":59,"./audit":3}],"../audits/uses-rel-preconnect":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
+const URL=require('../lib/url-shim.js');
+const i18n=require('../lib/i18n/i18n.js');
+const NetworkRecords=require('../computed/network-records.js');
+const MainResource=require('../computed/main-resource.js');
+const LoadSimulator=require('../computed/load-simulator.js');
+
+
+
+
+
+const PRECONNECT_SOCKET_MAX_IDLE=15;
+
+const IGNORE_THRESHOLD_IN_MS=50;
+
+const UIStrings={
+
+title:'Preconnect to required origins',
+
+description:
+'Consider adding preconnect or dns-prefetch resource hints to establish early '+
+`connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect).`,
+
+crossoriginWarning:'A preconnect <link> was found for "{securityOrigin}" but was not used '+
+'by the browser. Check that you are using the `crossorigin` attribute properly.'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class UsesRelPreconnectAudit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'uses-rel-preconnect',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+requiredArtifacts:['devtoolsLogs','URL','LinkElements'],
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC};
+
+}
+
+
+
+
+
+
+static hasValidTiming(record){
+return!!record.timing&&record.timing.connectEnd>0&&record.timing.connectStart>0;
+}
+
+
+
+
+
+
+static hasAlreadyConnectedToOrigin(record){
+return(
+!!record.timing&&
+record.timing.dnsEnd-record.timing.dnsStart===0&&
+record.timing.connectEnd-record.timing.connectStart===0);
+
+}
+
+
+
+
+
+
+
+static socketStartTimeIsBelowThreshold(record,mainResource){
+return Math.max(0,record.startTime-mainResource.endTime)<PRECONNECT_SOCKET_MAX_IDLE;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[UsesRelPreconnectAudit.DEFAULT_PASS];
+const settings=context.settings;
+let maxWasted=0;
+
+const warnings=[];
+
+const[networkRecords,mainResource,loadSimulator]=await Promise.all([
+NetworkRecords.request(devtoolsLog,context),
+MainResource.request({devtoolsLog,URL:artifacts.URL},context),
+LoadSimulator.request({devtoolsLog,settings},context)]);
+
+
+const{rtt,additionalRttByOrigin}=loadSimulator.getOptions();
+
+
+const origins=new Map();
+networkRecords.
+forEach(record=>{
+if(
+
+!UsesRelPreconnectAudit.hasValidTiming(record)||
+
+record.initiator.url===mainResource.url||
+
+!record.parsedURL||!record.parsedURL.securityOrigin||
+
+mainResource.parsedURL.securityOrigin===record.parsedURL.securityOrigin||
+
+UsesRelPreconnectAudit.hasAlreadyConnectedToOrigin(record)||
+
+!UsesRelPreconnectAudit.socketStartTimeIsBelowThreshold(record,mainResource))
+{
+return;
+}
+
+const securityOrigin=record.parsedURL.securityOrigin;
+const records=origins.get(securityOrigin)||[];
+records.push(record);
+origins.set(securityOrigin,records);
+});
+
+const preconnectLinks=artifacts.LinkElements.filter(el=>el.rel==='preconnect');
+const preconnectOrigins=new Set(preconnectLinks.map(link=>URL.getOrigin(link.href||'')));
+
+
+let results=[];
+origins.forEach(records=>{
+
+
+const firstRecordOfOrigin=records.reduce((firstRecord,record)=>{
+return record.startTime<firstRecord.startTime?record:firstRecord;
+});
+
+
+if(!firstRecordOfOrigin.timing)return;
+
+const securityOrigin=firstRecordOfOrigin.parsedURL.securityOrigin;
+
+
+
+
+const additionalRtt=additionalRttByOrigin.get(securityOrigin)||0;
+let connectionTime=rtt+additionalRtt;
+
+if(firstRecordOfOrigin.parsedURL.scheme==='https')connectionTime=connectionTime*2;
+
+const timeBetweenMainResourceAndDnsStart=
+firstRecordOfOrigin.startTime*1000-
+mainResource.endTime*1000+
+firstRecordOfOrigin.timing.dnsStart;
+
+const wastedMs=Math.min(connectionTime,timeBetweenMainResourceAndDnsStart);
+if(wastedMs<IGNORE_THRESHOLD_IN_MS)return;
+
+if(preconnectOrigins.has(securityOrigin)){
+
+warnings.push(str_(UIStrings.crossoriginWarning,{securityOrigin}));
+return;
+}
+
+maxWasted=Math.max(wastedMs,maxWasted);
+results.push({
+url:securityOrigin,
+wastedMs:wastedMs});
+
+});
+
+results=results.
+sort((a,b)=>b.wastedMs-a.wastedMs);
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnWastedMs)}];
+
+
+const details=Audit.makeOpportunityDetails(headings,results,maxWasted);
+
+return{
+score:UnusedBytes.scoreForWastedMs(maxWasted),
+rawValue:maxWasted,
+displayValue:maxWasted?
+str_(i18n.UIStrings.displayValueMsSavings,{wastedMs:maxWasted}):
+'',
+extendedInfo:{
+value:results},
+
+warnings,
+details};
+
+}}
+
+
+module.exports=UsesRelPreconnectAudit;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/uses-rel-preconnect.js");
+},{"../computed/load-simulator.js":10,"../computed/main-resource.js":11,"../computed/network-records.js":29,"../lib/i18n/i18n.js":59,"../lib/url-shim.js":"url","./audit":3,"./byte-efficiency/byte-efficiency-audit":4}],"../audits/uses-rel-preload":[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const URL=require('../lib/url-shim');
+const Audit=require('./audit');
+const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
+const CriticalRequestChains=require('../computed/critical-request-chains.js');
+const i18n=require('../lib/i18n/i18n.js');
+const MainResource=require('../computed/main-resource.js');
+const PageDependencyGraph=require('../computed/page-dependency-graph.js');
+const LoadSimulator=require('../computed/load-simulator.js');
+
+const UIStrings={
+
+title:'Preload key requests',
+
+description:'Consider using <link rel=preload> to prioritize fetching resources that are '+
+'currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).',
+
+crossoriginWarning:'A preload <link> was found for "{preloadURL}" but was not used '+
+'by the browser. Check that you are using the `crossorigin` attribute properly.'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+const THRESHOLD_IN_MS=100;
+
+class UsesRelPreloadAudit extends Audit{
+
+
+
+static get meta(){
+return{
+id:'uses-rel-preload',
+title:str_(UIStrings.title),
+description:str_(UIStrings.description),
+requiredArtifacts:['devtoolsLogs','traces','URL'],
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC};
+
+}
+
+
+
+
+
+
+static getURLsToPreload(mainResource,graph){
+
+const urls=new Set();
+
+graph.traverse((node,traversalPath)=>{
+if(node.type!=='network')return;
+
+const path=traversalPath.slice(1).filter(initiator=>initiator.type==='network');
+if(!UsesRelPreloadAudit.shouldPreloadRequest(node.record,mainResource,path))return;
+urls.add(node.record.url);
+});
+
+return urls;
+}
+
+
+
+
+
+
+
+static getURLsFailedToPreload(graph){
+
+const requests=[];
+graph.traverse(node=>node.type==='network'&&requests.push(node.record));
+
+const preloadRequests=requests.filter(req=>req.isLinkPreload);
+const preloadURLs=new Set(preloadRequests.map(req=>req.url));
+
+
+const failedRequests=requests.filter(req=>preloadURLs.has(req.url)&&!req.isLinkPreload);
+return new Set(failedRequests.map(req=>req.url));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+static shouldPreloadRequest(request,mainResource,initiatorPath){
+const mainResourceDepth=mainResource.redirects?mainResource.redirects.length:0;
+
+
+if(request.isLinkPreload)return false;
+
+if(!CriticalRequestChains.isCritical(request,mainResource))return false;
+
+if(URL.NON_NETWORK_PROTOCOLS.includes(request.protocol))return false;
+
+if(initiatorPath.length!==mainResourceDepth+2)return false;
+
+return URL.rootDomainsMatch(request.url,mainResource.url);
+}
+
+
+
+
+
+
+
+
+static computeWasteWithGraph(urls,graph,simulator){
+if(!urls.size){
+return{wastedMs:0,results:[]};
+}
+
+
+
+const simulationBeforeChanges=simulator.simulate(graph,{flexibleOrdering:true});
+const modifiedGraph=graph.cloneWithRelationships();
+
+
+const nodesToPreload=[];
+
+let mainDocumentNode=null;
+modifiedGraph.traverse(node=>{
+if(node.type!=='network')return;
+
+const networkNode=node;
+if(node.isMainDocument()){
+mainDocumentNode=networkNode;
+}else if(networkNode.record&&urls.has(networkNode.record.url)){
+nodesToPreload.push(networkNode);
+}
+});
+
+if(!mainDocumentNode){
+
+throw new Error('Could not find main document node');
+}
+
+
+
+for(const node of nodesToPreload){
+node.removeAllDependencies();
+node.addDependency(mainDocumentNode);
+}
+
+
+const simulationAfterChanges=simulator.simulate(modifiedGraph,{flexibleOrdering:true});
+const originalNodesByRecord=Array.from(simulationBeforeChanges.nodeTimings.keys()).
+
+reduce((map,node)=>map.set(node.record,node),new Map());
+
+const results=[];
+for(const node of nodesToPreload){
+const originalNode=originalNodesByRecord.get(node.record);
+const timingAfter=simulationAfterChanges.nodeTimings.get(node);
+const timingBefore=simulationBeforeChanges.nodeTimings.get(originalNode);
+if(!timingBefore||!timingAfter)throw new Error('Missing preload node');
+
+const wastedMs=Math.round(timingBefore.endTime-timingAfter.endTime);
+if(wastedMs<THRESHOLD_IN_MS)continue;
+results.push({url:node.record.url,wastedMs});
+}
+
+if(!results.length){
+return{wastedMs:0,results};
+}
+
+return{
+
+
+wastedMs:Math.max(...results.map(item=>item.wastedMs)),
+results};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[UsesRelPreloadAudit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS];
+const URL=artifacts.URL;
+const simulatorOptions={trace,devtoolsLog,settings:context.settings};
+
+const[mainResource,graph,simulator]=await Promise.all([
+MainResource.request({devtoolsLog,URL},context),
+PageDependencyGraph.request({trace,devtoolsLog},context),
+LoadSimulator.request(simulatorOptions,context)]);
+
+
+const urls=UsesRelPreloadAudit.getURLsToPreload(mainResource,graph);
+const{results,wastedMs}=UsesRelPreloadAudit.computeWasteWithGraph(urls,graph,simulator);
+
+results.sort((a,b)=>b.wastedMs-a.wastedMs);
+
+
+let warnings;
+const failedURLs=UsesRelPreloadAudit.getURLsFailedToPreload(graph);
+if(failedURLs.size){
+warnings=Array.from(failedURLs).
+map(preloadURL=>str_(UIStrings.crossoriginWarning,{preloadURL}));
+}
+
+
+const headings=[
+{key:'url',valueType:'url',label:str_(i18n.UIStrings.columnURL)},
+{key:'wastedMs',valueType:'timespanMs',label:str_(i18n.UIStrings.columnWastedMs)}];
+
+const details=Audit.makeOpportunityDetails(headings,results,wastedMs);
+
+return{
+score:UnusedBytes.scoreForWastedMs(wastedMs),
+rawValue:wastedMs,
+displayValue:wastedMs?
+str_(i18n.UIStrings.displayValueMsSavings,{wastedMs}):
+'',
+extendedInfo:{
+value:results},
+
+details,
+warnings};
+
+}}
+
+
+module.exports=UsesRelPreloadAudit;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/uses-rel-preload.js");
+},{"../computed/critical-request-chains.js":9,"../computed/load-simulator.js":10,"../computed/main-resource.js":11,"../computed/page-dependency-graph.js":30,"../lib/i18n/i18n.js":59,"../lib/url-shim":"url","./audit":3,"./byte-efficiency/byte-efficiency-audit":4}],"../audits/viewport":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const Parser=require('metaviewport-parser');
+
+class Viewport extends Audit{
+
+
+
+static get meta(){
+return{
+id:'viewport',
+title:'Has a `<meta name="viewport">` tag with `width` or `initial-scale`',
+failureTitle:'Does not have a `<meta name="viewport">` tag with `width` '+
+'or `initial-scale`',
+description:'Add a viewport meta tag to optimize your app for mobile screens. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/has-viewport-meta-tag).',
+requiredArtifacts:['Viewport']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+if(artifacts.Viewport===null){
+return{
+explanation:'No viewport meta tag found',
+rawValue:false};
+
+}
+
+const warnings=[];
+const parsedProps=Parser.parseMetaViewPortContent(artifacts.Viewport);
+
+if(Object.keys(parsedProps.unknownProperties).length){
+warnings.push(`Invalid properties found: ${JSON.stringify(parsedProps.unknownProperties)}`);
+}
+if(Object.keys(parsedProps.invalidValues).length){
+warnings.push(`Invalid values found: ${JSON.stringify(parsedProps.invalidValues)}`);
+}
+
+const viewportProps=parsedProps.validProperties;
+const hasMobileViewport=viewportProps.width||viewportProps['initial-scale'];
+
+return{
+rawValue:!!hasMobileViewport,
+warnings};
+
+}}
+
+
+module.exports=Viewport;
+
+},{"./audit":3,"metaviewport-parser":117}],"../audits/without-javascript":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+
+class WithoutJavaScript extends Audit{
+
+
+
+static get meta(){
+return{
+id:'without-javascript',
+title:'Contains some content when JavaScript is not available',
+failureTitle:'Does not provide fallback content when JavaScript is not available',
+description:'Your app should display some content when JavaScript is disabled, even if '+
+'it\'s just a warning to the user that JavaScript is required to use the app. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/no-js).',
+requiredArtifacts:['HTMLWithoutJavaScript']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const artifact=artifacts.HTMLWithoutJavaScript;
+
+
+if(artifact.bodyText.trim()===''&&!artifact.hasNoScript){
+return{
+rawValue:false,
+explanation:'The page body should render some content if its scripts are not available.'};
+
+}
+
+return{
+rawValue:true};
+
+}}
+
+
+module.exports=WithoutJavaScript;
+
+},{"./audit":3}],"../audits/works-offline":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const URL=require('../lib/url-shim');
+const Audit=require('./audit');
+
+class WorksOffline extends Audit{
+
+
+
+static get meta(){
+return{
+id:'works-offline',
+title:'Current page responds with a 200 when offline',
+failureTitle:'Current page does not respond with a 200 when offline',
+description:'If you\'re building a Progressive Web App, consider using a service worker '+
+'so that your app can work offline. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/http-200-when-offline).',
+requiredArtifacts:['Offline','URL']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const warnings=[];
+const passed=artifacts.Offline===200;
+if(!passed&&
+!URL.equalWithExcludedFragments(artifacts.URL.requestedUrl,artifacts.URL.finalUrl)){
+warnings.push('You may be not loading offline because your test URL '+
+`(${artifacts.URL.requestedUrl}) was redirected to "${artifacts.URL.finalUrl}". `+
+'Try testing the second URL directly.');
+}
+
+return{
+rawValue:passed,
+warnings};
+
+}}
+
+
+module.exports=WorksOffline;
+
+},{"../lib/url-shim":"url","./audit":3}],"../gather/gatherers/accessibility":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+const Gatherer=require('./gatherer');
+
+const axeLibSource="/*! aXe v3.1.2\n * Copyright (c) 2018 Deque Systems, Inc.\n *\n * Your use of this Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This entire copyright notice must appear in every copy of this file you\n * distribute or in any file that contains substantial portions of this source\n * code.\n */\n!function e(window){var document=window.document,T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function c(e){this.name=\"SupportError\",this.cause=e.cause,this.message=\"`\"+e.cause+\"` - feature unsupported in your environment.\",e.ruleId&&(this.ruleId=e.ruleId,this.message+=\" Skipping \"+this.ruleId+\" rule.\"),this.stack=(new Error).stack}(axe=axe||{}).version=\"3.1.2\",\"function\"==typeof define&&define.amd&&define(\"axe-core\",[],function(){\"use strict\";return axe}),\"object\"===(\"undefined\"==typeof module?\"undefined\":T(module))&&module.exports&&\"function\"==typeof e.toString&&(axe.source=\"(\"+e.toString()+')(typeof window === \"object\" ? window : this);',module.exports=axe),\"function\"==typeof window.getComputedStyle&&(window.axe=axe),(c.prototype=Object.create(Error.prototype)).constructor=c,axe.imports={};var utils=axe.utils={},i={},p=(T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e});function t(e,t,r){\"use strict\";var a,n;for(a=0,n=e.length;a<n;a++)t[r](e[a])}function r(e){this.brand=\"axe\",this.application=\"axeAPI\",this.tagExclude=[\"experimental\"],this.defaultConfig=e,this._init(),this._defaultLocale=null}r.prototype._setDefaultLocale=function(){if(!this._defaultLocale){for(var e={checks:{},rules:{}},t=Object.keys(this.data.checks),r=0;r<t.length;r++){var a=t[r],n=this.data.checks[a].messages,o=n.pass,i=n.fail,s=n.incomplete;e.checks[a]={pass:o,fail:i,incomplete:s}}for(var l=Object.keys(this.data.rules),u=0;u<l.length;u++){var c=l[u],d=this.data.rules[c],m=d.description,p=d.help;e.rules[c]={description:m,help:p}}this._defaultLocale=e}},r.prototype._resetLocale=function(){var e=this._defaultLocale;e&&this.applyLocale(e)};function f(n,e,o){var t=void 0,i=void 0;return o.performanceTimer&&(t=\"mark_rule_start_\"+n.id,i=\"mark_rule_end_\"+n.id,axe.utils.performanceTimer.mark(t)),function(r,a){n.run(e,o,function(e){o.performanceTimer&&(axe.utils.performanceTimer.mark(i),axe.utils.performanceTimer.measure(\"rule_\"+n.id,t,i)),r(e)},function(e){if(o.debug)a(e);else{var t=Object.assign(new m(n),{result:axe.constants.CANTTELL,description:\"An error occured while running this rule\",message:e.message,stack:e.stack,error:e});r(t)}})}}function o(e,t,r){var a=e.brand,n=e.application;return axe.constants.helpUrlBase+a+\"/\"+(r||axe.version.substring(0,axe.version.lastIndexOf(\".\")))+\"/\"+t+\"?application=\"+n}function d(e){\"use strict\";this.id=e.id,this.data=null,this.relatedNodes=[],this.result=null}function a(e){\"use strict\";return\"string\"==typeof e?new Function(\"return \"+e+\";\")():e}function n(e){e&&(this.id=e.id,this.configure(e))}r.prototype._applyCheckLocale=function(e){for(var t,r,a,n,o=Object.keys(e),i=0;i<o.length;i++){var s=o[i];if(!this.data.checks[s])throw new Error('Locale provided for unknown check: \"'+s+'\"');this.data.checks[s]=(t=this.data.checks[s],r=e[s],n=a=void 0,a=r.pass,n=r.fail,\"string\"==typeof a&&(a=axe.imports.doT.compile(a)),\"string\"==typeof n&&(n=axe.imports.doT.compile(n)),p({},t,{messages:{pass:a||t.messages.pass,fail:n||t.messages.fail,incomplete:\"object\"===T(t.messages.incomplete)?p({},t.messages.incomplete,r.incomplete):r.incomplete}}))}},r.prototype._applyRuleLocale=function(e){for(var t,r,a,n,o=Object.keys(e),i=0;i<o.length;i++){var s=o[i];if(!this.data.rules[s])throw new Error('Locale provided for unknown rule: \"'+s+'\"');this.data.rules[s]=(t=this.data.rules[s],r=e[s],n=a=void 0,a=r.help,n=r.description,\"string\"==typeof a&&(a=axe.imports.doT.compile(a)),\"string\"==typeof n&&(n=axe.imports.doT.compile(n)),p({},t,{help:a||t.help,description:n||t.description}))}},r.prototype.applyLocale=function(e){this._setDefaultLocale(),e.checks&&this._applyCheckLocale(e.checks),e.rules&&this._applyRuleLocale(e.rules)},r.prototype._init=function(){var e=function(e){\"use strict\";var t;return e?(t=axe.utils.clone(e)).commons=e.commons:t={},t.reporter=t.reporter||null,t.rules=t.rules||[],t.checks=t.checks||[],t.data=p({checks:{},rules:{}},t.data),t}(this.defaultConfig);axe.commons=e.commons,this.reporter=e.reporter,this.commands={},this.rules=[],this.checks={},t(e.rules,this,\"addRule\"),t(e.checks,this,\"addCheck\"),this.data={},this.data.checks=e.data&&e.data.checks||{},this.data.rules=e.data&&e.data.rules||{},this.data.failureSummaries=e.data&&e.data.failureSummaries||{},this.data.incompleteFallbackMessage=e.data&&e.data.incompleteFallbackMessage||\"\",this._constructHelpUrls()},r.prototype.registerCommand=function(e){\"use strict\";this.commands[e.id]=e.callback},r.prototype.addRule=function(e){\"use strict\";e.metadata&&(this.data.rules[e.id]=e.metadata);var t=this.getRule(e.id);t?t.configure(e):this.rules.push(new h(e,this))},r.prototype.addCheck=function(e){\"use strict\";var t=e.metadata;\"object\"===(void 0===t?\"undefined\":T(t))&&(this.data.checks[e.id]=t,\"object\"===T(t.messages)&&Object.keys(t.messages).filter(function(e){return t.messages.hasOwnProperty(e)&&\"string\"==typeof t.messages[e]}).forEach(function(e){0===t.messages[e].indexOf(\"function\")&&(t.messages[e]=new Function(\"return \"+t.messages[e]+\";\")())})),this.checks[e.id]?this.checks[e.id].configure(e):this.checks[e.id]=new n(e)},r.prototype.run=function(o,i,s,l){\"use strict\";this.normalizeOptions(i),axe._selectCache=[];var e,r,a,t=(e=this.rules,r=o,a=i,e.reduce(function(e,t){return axe.utils.ruleShouldRun(t,r,a)&&(t.preload?e.later.push(t):e.now.push(t)),e},{now:[],later:[]})),n=t.now,u=t.later,c=axe.utils.queue();n.forEach(function(e){c.defer(f(e,o,i))});var d=axe.utils.queue();u.length&&d.defer(function(r,e){axe.utils.preload(i).then(function(e){var t=e[0];r(t)}).catch(function(e){console.warn(\"Couldn't load preload assets: \",e);r(void 0)})});var m=axe.utils.queue();m.defer(c),m.defer(d),m.then(function(e){var t=e.pop();if(t&&t.length){var r=t[0];r&&(o=p({},o,r))}var a=e[0];if(!u.length)return axe._selectCache=void 0,void s(a.filter(function(e){return!!e}));var n=axe.utils.queue();u.forEach(function(e){var t=f(e,o,i);n.defer(t)}),n.then(function(e){axe._selectCache=void 0,s(a.concat(e).filter(function(e){return!!e}))}).catch(l)}).catch(l)},r.prototype.after=function(e,r){\"use strict\";var a=this.rules;return e.map(function(e){var t=axe.utils.findBy(a,\"id\",e.id);if(!t)throw new Error(\"Result for unknown rule. You may be running mismatch aXe-core versions\");return t.after(e,r)})},r.prototype.getRule=function(t){return this.rules.find(function(e){return e.id===t})},r.prototype.normalizeOptions=function(e){\"use strict\";var t=this;if(\"object\"===T(e.runOnly)){Array.isArray(e.runOnly)&&(e.runOnly={type:\"tag\",values:e.runOnly});var r=e.runOnly;if(r.value&&!r.values&&(r.values=r.value,delete r.value),!Array.isArray(r.values)||0===r.values.length)throw new Error(\"runOnly.values must be a non-empty array\");if([\"rule\",\"rules\"].includes(r.type))r.type=\"rule\",r.values.forEach(function(e){if(!t.getRule(e))throw new Error(\"unknown rule `\"+e+\"` in options.runOnly\")});else{if(![\"tag\",\"tags\",void 0].includes(r.type))throw new Error(\"Unknown runOnly type '\"+r.type+\"'\");r.type=\"tag\";var a=t.rules.reduce(function(e,t){return e.length?e.filter(function(e){return!t.tags.includes(e)}):e},r.values);if(0!==a.length)throw new Error(\"Could not find tags `\"+a.join(\"`, `\")+\"`\")}}return\"object\"===T(e.rules)&&Object.keys(e.rules).forEach(function(e){if(!t.getRule(e))throw new Error(\"unknown rule `\"+e+\"` in options.rules\")}),e},r.prototype.setBranding=function(e){\"use strict\";var t={brand:this.brand,application:this.application};e&&e.hasOwnProperty(\"brand\")&&e.brand&&\"string\"==typeof e.brand&&(this.brand=e.brand),e&&e.hasOwnProperty(\"application\")&&e.application&&\"string\"==typeof e.application&&(this.application=e.application),this._constructHelpUrls(t)},r.prototype._constructHelpUrls=function(){var r=this,a=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=(axe.version.match(/^[1-9][0-9]*\\.[0-9]+/)||[\"x.y\"])[0];this.rules.forEach(function(e){r.data.rules[e.id]||(r.data.rules[e.id]={});var t=r.data.rules[e.id];(\"string\"!=typeof t.helpUrl||a&&t.helpUrl===o(a,e.id,n))&&(t.helpUrl=o(r,e.id,n))})},r.prototype.resetRulesAndChecks=function(){\"use strict\";this._init(),this._resetLocale()},n.prototype.enabled=!0,n.prototype.run=function(e,t,r,a,n){\"use strict\";var o=(t=t||{}).hasOwnProperty(\"enabled\")?t.enabled:this.enabled,i=t.options||this.options;if(o){var s,l=new d(this),u=axe.utils.checkHelper(l,t,a,n);try{s=this.evaluate.call(u,e.actualNode,i,e,r)}catch(e){return void n(e)}u.isAsync||(l.result=s,setTimeout(function(){a(l)},0))}else a(null)},n.prototype.configure=function(t){var r=this;[\"options\",\"enabled\"].filter(function(e){return t.hasOwnProperty(e)}).forEach(function(e){return r[e]=t[e]}),[\"evaluate\",\"after\"].filter(function(e){return t.hasOwnProperty(e)}).forEach(function(e){return r[e]=a(t[e])})};T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function s(e,t,r){\"use strict\";var a,n;e.frames=e.frames||[];var o=document.querySelectorAll(r.shift());e:for(var i=0,s=o.length;i<s;i++){n=o[i];for(var l=0,u=e.frames.length;l<u;l++)if(e.frames[l].node===n){e.frames[l][t].push(r);break e}a={node:n,include:[],exclude:[]},r&&a[t].push(r),e.frames.push(a)}}function l(t,e){\"use strict\";for(var r,a,n=[],o=0,i=t[e].length;o<i;o++){if(\"string\"==typeof(r=t[e][o])){a=Array.from(document.querySelectorAll(r)),n=n.concat(a.map(function(e){return axe.utils.getNodeFromTree(t.flatTree[0],e)}));break}!r||!r.length||r instanceof Node?r instanceof Node&&(r.documentElement instanceof Node?n.push(t.flatTree[0]):n.push(axe.utils.getNodeFromTree(t.flatTree[0],r))):1<r.length?s(t,e,r):(a=Array.from(document.querySelectorAll(r[0])),n=n.concat(a.map(function(e){return axe.utils.getNodeFromTree(t.flatTree[0],e)})))}return n.filter(function(e){return e})}function u(e){\"use strict\";var t,r,a,n=this;this.frames=[],this.initiator=!e||\"boolean\"!=typeof e.initiator||e.initiator,this.page=!1,e=function(e){if(e&&\"object\"===(void 0===e?\"undefined\":T(e))||e instanceof NodeList){if(e instanceof Node)return{include:[e],exclude:[]};if(e.hasOwnProperty(\"include\")||e.hasOwnProperty(\"exclude\"))return{include:e.include&&+e.include.length?e.include:[document],exclude:e.exclude||[]};if(e.length===+e.length)return{include:e,exclude:[]}}return\"string\"==typeof e?{include:[e],exclude:[]}:{include:[document],exclude:[]}}(e),this.flatTree=axe.utils.getFlattenedTree((r=(t=e).include,a=t.exclude,(Array.from(r).concat(Array.from(a)).reduce(function(e,t){return e||(t instanceof Element?t.ownerDocument:t instanceof Document?t:void 0)},null)||document).documentElement)),this.exclude=e.exclude,this.include=e.include,this.include=l(this,\"include\"),this.exclude=l(this,\"exclude\"),axe.utils.select(\"frame, iframe\",this).forEach(function(e){var t,r;ve(e,n)&&(t=n.frames,r=e.actualNode,axe.utils.isHidden(r)||axe.utils.findBy(t,\"node\",r)||t.push({node:r,include:[],exclude:[]}))}),1===this.include.length&&this.include[0].actualNode===document.documentElement&&(this.page=!0);var o=function(e){if(0===e.include.length){if(0===e.frames.length){var t=axe.utils.respondable.isInFrame()?\"frame\":\"page\";return new Error(\"No elements found for include in \"+t+\" Context\")}e.frames.forEach(function(e,t){if(0===e.include.length)return new Error(\"No elements found for include in Context of frame \"+t)})}}(this);if(o instanceof Error)throw o;Array.isArray(this.include)||(this.include=Array.from(this.include)),this.include.sort(axe.utils.nodeSorter)}function m(e){\"use strict\";this.id=e.id,this.result=axe.constants.NA,this.pageLevel=e.pageLevel,this.impact=null,this.nodes=[]}function h(e,t){\"use strict\";this._audit=t,this.id=e.id,this.selector=e.selector||\"*\",this.excludeHidden=\"boolean\"!=typeof e.excludeHidden||e.excludeHidden,this.enabled=\"boolean\"!=typeof e.enabled||e.enabled,this.pageLevel=\"boolean\"==typeof e.pageLevel&&e.pageLevel,this.any=e.any||[],this.all=e.all||[],this.none=e.none||[],this.tags=e.tags||[],this.preload=!!e.preload,e.matches&&(this.matches=a(e.matches))}h.prototype.matches=function(){\"use strict\";return!0},h.prototype.gather=function(e){\"use strict\";var t=axe.utils.select(this.selector,e);return this.excludeHidden?t.filter(function(e){return!axe.utils.isHidden(e.actualNode)}):t},h.prototype.runChecks=function(t,n,o,i,r,e){\"use strict\";var s=this,l=axe.utils.queue();this[t].forEach(function(e){var r=s._audit.checks[e.id||e],a=axe.utils.getCheckOption(r,s.id,o);l.defer(function(e,t){r.run(n,a,i,e,t)})}),l.then(function(e){e=e.filter(function(e){return e}),r({type:t,results:e})}).catch(e)},h.prototype.run=function(a,o,e,t){var i=this,r=axe.utils.queue(),s=new m(this),n=\"mark_runchecks_start_\"+this.id,l=\"mark_runchecks_end_\"+this.id,u=void 0;try{u=this.gather(a).filter(function(e){return i.matches(e.actualNode,e)})}catch(e){return void t(new c({cause:e,ruleId:this.id}))}o.performanceTimer&&(axe.log(\"gather (\",u.length,\"):\",axe.utils.performanceTimer.timeElapsed()+\"ms\"),axe.utils.performanceTimer.mark(n)),u.forEach(function(n){r.defer(function(t,r){var e=axe.utils.queue();[\"any\",\"all\",\"none\"].forEach(function(r){e.defer(function(e,t){i.runChecks(r,n,o,a,e,t)})}),e.then(function(e){if(e.length){var r=!1,a={};e.forEach(function(e){var t=e.results.filter(function(e){return e});(a[e.type]=t).length&&(r=!0)}),r&&(a.node=new axe.utils.DqElement(n.actualNode,o),s.nodes.push(a))}t()}).catch(function(e){return r(e)})})}),o.performanceTimer&&(axe.utils.performanceTimer.mark(l),axe.utils.performanceTimer.measure(\"runchecks_\"+this.id,n,l)),r.then(function(){return e(s)}).catch(function(e){return t(e)})},h.prototype.after=function(s,l){\"use strict\";var r,e,a,t,n=(r=this,axe.utils.getAllChecks(r).map(function(e){var t=r._audit.checks[e.id||e];return t&&\"function\"==typeof t.after?t:null}).filter(Boolean)),u=this.id;return n.forEach(function(e){var t,r,a,n=(t=s.nodes,r=e.id,a=[],t.forEach(function(e){axe.utils.getAllChecks(e).forEach(function(e){e.id===r&&a.push(e)})}),a),o=axe.utils.getCheckOption(e,u,l),i=e.after(n,o);n.forEach(function(e){-1===i.indexOf(e)&&(e.filtered=!0)})}),s.nodes=(a=[\"any\",\"all\",\"none\"],t=(e=s).nodes.filter(function(t){var r=0;return a.forEach(function(e){t[e]=t[e].filter(function(e){return!0!==e.filtered}),r+=t[e].length}),0<r}),e.pageLevel&&t.length&&(t=[t.reduce(function(t,r){if(t)return a.forEach(function(e){t[e].push.apply(t[e],r[e])}),t})]),t),s},h.prototype.configure=function(e){\"use strict\";e.hasOwnProperty(\"selector\")&&(this.selector=e.selector),e.hasOwnProperty(\"excludeHidden\")&&(this.excludeHidden=\"boolean\"!=typeof e.excludeHidden||e.excludeHidden),e.hasOwnProperty(\"enabled\")&&(this.enabled=\"boolean\"!=typeof e.enabled||e.enabled),e.hasOwnProperty(\"pageLevel\")&&(this.pageLevel=\"boolean\"==typeof e.pageLevel&&e.pageLevel),e.hasOwnProperty(\"any\")&&(this.any=e.any),e.hasOwnProperty(\"all\")&&(this.all=e.all),e.hasOwnProperty(\"none\")&&(this.none=e.none),e.hasOwnProperty(\"tags\")&&(this.tags=e.tags),e.hasOwnProperty(\"matches\")&&(\"string\"==typeof e.matches?this.matches=new Function(\"return \"+e.matches+\";\")():this.matches=e.matches)},function(axe){var o={helpUrlBase:\"https://dequeuniversity.com/rules/\",results:[],resultGroups:[],resultGroupMap:{},impact:Object.freeze([\"minor\",\"moderate\",\"serious\",\"critical\"]),preloadAssets:Object.freeze([\"cssom\"]),preloadAssetsTimeout:1e4};[{name:\"NA\",value:\"inapplicable\",priority:0,group:\"inapplicable\"},{name:\"PASS\",value:\"passed\",priority:1,group:\"passes\"},{name:\"CANTTELL\",value:\"cantTell\",priority:2,group:\"incomplete\"},{name:\"FAIL\",value:\"failed\",priority:3,group:\"violations\"}].forEach(function(e){var t=e.name,r=e.value,a=e.priority,n=e.group;o[t]=r,o[t+\"_PRIO\"]=a,o[t+\"_GROUP\"]=n,o.results[a]=r,o.resultGroups[a]=n,o.resultGroupMap[r]=n}),Object.freeze(o.results),Object.freeze(o.resultGroups),Object.freeze(o.resultGroupMap),Object.freeze(o),Object.defineProperty(axe,\"constants\",{value:o,enumerable:!0,configurable:!1,writable:!1})}(axe);T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};axe.imports.axios=function(r){var a={};function n(e){if(a[e])return a[e].exports;var t=a[e]={exports:{},id:e,loaded:!1};return r[e].call(t.exports,t,t.exports,n),t.loaded=!0,t.exports}return n.m=r,n.c=a,n.p=\"\",n(0)}([function(e,t,r){e.exports=r(1)},function(e,t,r){\"use strict\";var utils=r(2),a=r(3),n=r(5),o=r(6);function i(e){var t=new n(e),r=a(n.prototype.request,t);return utils.extend(r,n.prototype,t),utils.extend(r,t),r}var s=i(o);s.Axios=n,s.create=function(e){return i(utils.merge(o,e))},s.Cancel=r(23),s.CancelToken=r(24),s.isCancel=r(20),s.all=function(e){return Promise.all(e)},s.spread=r(25),e.exports=s,e.exports.default=s},function(e,t,r){\"use strict\";var n=r(3),a=r(4),o=Object.prototype.toString;function i(e){return\"[object Array]\"===o.call(e)}function s(e){return null!==e&&\"object\"===(void 0===e?\"undefined\":T(e))}function l(e){return\"[object Function]\"===o.call(e)}function u(e,t){if(null!=e)if(\"object\"!==(void 0===e?\"undefined\":T(e))&&(e=[e]),i(e))for(var r=0,a=e.length;r<a;r++)t.call(null,e[r],r,e);else for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.call(null,e[n],n,e)}e.exports={isArray:i,isArrayBuffer:function(e){return\"[object ArrayBuffer]\"===o.call(e)},isBuffer:a,isFormData:function(e){return\"undefined\"!=typeof FormData&&e instanceof FormData},isArrayBufferView:function(e){return\"undefined\"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer},isString:function(e){return\"string\"==typeof e},isNumber:function(e){return\"number\"==typeof e},isObject:s,isUndefined:function(e){return void 0===e},isDate:function(e){return\"[object Date]\"===o.call(e)},isFile:function(e){return\"[object File]\"===o.call(e)},isBlob:function(e){return\"[object Blob]\"===o.call(e)},isFunction:l,isStream:function(e){return s(e)&&l(e.pipe)},isURLSearchParams:function(e){return\"undefined\"!=typeof URLSearchParams&&e instanceof URLSearchParams},isStandardBrowserEnv:function(){return(\"undefined\"==typeof navigator||\"ReactNative\"!==navigator.product)&&void 0!==window&&void 0!==document},forEach:u,merge:function r(){var a={};function e(e,t){\"object\"===T(a[t])&&\"object\"===(void 0===e?\"undefined\":T(e))?a[t]=r(a[t],e):a[t]=e}for(var t=0,n=arguments.length;t<n;t++)u(arguments[t],e);return a},extend:function(r,e,a){return u(e,function(e,t){r[t]=a&&\"function\"==typeof e?n(e,a):e}),r},trim:function(e){return e.replace(/^\\s*/,\"\").replace(/\\s*$/,\"\")}}},function(e,t){\"use strict\";e.exports=function(r,a){return function(){for(var e=new Array(arguments.length),t=0;t<e.length;t++)e[t]=arguments[t];return r.apply(a,e)}}},function(e,t){function r(e){return!!e.constructor&&\"function\"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}e.exports=function(e){return null!=e&&(r(e)||\"function\"==typeof(t=e).readFloatLE&&\"function\"==typeof t.slice&&r(t.slice(0,0))||!!e._isBuffer);var t}},function(e,t,r){\"use strict\";var a=r(6),utils=r(2),n=r(17),o=r(18);function i(e){this.defaults=e,this.interceptors={request:new n,response:new n}}i.prototype.request=function(e){\"string\"==typeof e&&(e=utils.merge({url:arguments[0]},arguments[1])),(e=utils.merge(a,{method:\"get\"},this.defaults,e)).method=e.method.toLowerCase();var t=[o,void 0],r=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)r=r.then(t.shift(),t.shift());return r},utils.forEach([\"delete\",\"get\",\"head\",\"options\"],function(r){i.prototype[r]=function(e,t){return this.request(utils.merge(t||{},{method:r,url:e}))}}),utils.forEach([\"post\",\"put\",\"patch\"],function(a){i.prototype[a]=function(e,t,r){return this.request(utils.merge(r||{},{method:a,url:e,data:t}))}}),e.exports=i},function(e,t,r){\"use strict\";var utils=r(2),a=r(7),n={\"Content-Type\":\"application/x-www-form-urlencoded\"};function o(e,t){!utils.isUndefined(e)&&utils.isUndefined(e[\"Content-Type\"])&&(e[\"Content-Type\"]=t)}var i,s={adapter:(\"undefined\"!=typeof XMLHttpRequest?i=r(8):\"undefined\"!=typeof process&&(i=r(8)),i),transformRequest:[function(e,t){return a(t,\"Content-Type\"),utils.isFormData(e)||utils.isArrayBuffer(e)||utils.isBuffer(e)||utils.isStream(e)||utils.isFile(e)||utils.isBlob(e)?e:utils.isArrayBufferView(e)?e.buffer:utils.isURLSearchParams(e)?(o(t,\"application/x-www-form-urlencoded;charset=utf-8\"),e.toString()):utils.isObject(e)?(o(t,\"application/json;charset=utf-8\"),JSON.stringify(e)):e}],transformResponse:[function(e){if(\"string\"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:\"XSRF-TOKEN\",xsrfHeaderName:\"X-XSRF-TOKEN\",maxContentLength:-1,validateStatus:function(e){return 200<=e&&e<300},headers:{common:{Accept:\"application/json, text/plain, */*\"}}};utils.forEach([\"delete\",\"get\",\"head\"],function(e){s.headers[e]={}}),utils.forEach([\"post\",\"put\",\"patch\"],function(e){s.headers[e]=utils.merge(n)}),e.exports=s},function(e,t,r){\"use strict\";var utils=r(2);e.exports=function(r,a){utils.forEach(r,function(e,t){t!==a&&t.toUpperCase()===a.toUpperCase()&&(r[a]=e,delete r[t])})}},function(e,t,m){\"use strict\";var utils=m(2),p=m(9),f=m(12),h=m(13),g=m(14),b=m(10),y=void 0!==window&&window.btoa&&window.btoa.bind(window)||m(15);e.exports=function(d){return new Promise(function(r,a){var n=d.data,o=d.headers;utils.isFormData(n)&&delete o[\"Content-Type\"];var i=new XMLHttpRequest,e=\"onreadystatechange\",s=!1;if(void 0===window||!window.XDomainRequest||\"withCredentials\"in i||g(d.url)||(i=new window.XDomainRequest,e=\"onload\",s=!0,i.onprogress=function(){},i.ontimeout=function(){}),d.auth){var t=d.auth.username||\"\",l=d.auth.password||\"\";o.Authorization=\"Basic \"+y(t+\":\"+l)}if(i.open(d.method.toUpperCase(),f(d.url,d.params,d.paramsSerializer),!0),i.timeout=d.timeout,i[e]=function(){if(i&&(4===i.readyState||s)&&(0!==i.status||i.responseURL&&0===i.responseURL.indexOf(\"file:\"))){var e=\"getAllResponseHeaders\"in i?h(i.getAllResponseHeaders()):null,t={data:d.responseType&&\"text\"!==d.responseType?i.response:i.responseText,status:1223===i.status?204:i.status,statusText:1223===i.status?\"No Content\":i.statusText,headers:e,config:d,request:i};p(r,a,t),i=null}},i.onerror=function(){a(b(\"Network Error\",d,null,i)),i=null},i.ontimeout=function(){a(b(\"timeout of \"+d.timeout+\"ms exceeded\",d,\"ECONNABORTED\",i)),i=null},utils.isStandardBrowserEnv()){var u=m(16),c=(d.withCredentials||g(d.url))&&d.xsrfCookieName?u.read(d.xsrfCookieName):void 0;c&&(o[d.xsrfHeaderName]=c)}if(\"setRequestHeader\"in i&&utils.forEach(o,function(e,t){void 0===n&&\"content-type\"===t.toLowerCase()?delete o[t]:i.setRequestHeader(t,e)}),d.withCredentials&&(i.withCredentials=!0),d.responseType)try{i.responseType=d.responseType}catch(e){if(\"json\"!==d.responseType)throw e}\"function\"==typeof d.onDownloadProgress&&i.addEventListener(\"progress\",d.onDownloadProgress),\"function\"==typeof d.onUploadProgress&&i.upload&&i.upload.addEventListener(\"progress\",d.onUploadProgress),d.cancelToken&&d.cancelToken.promise.then(function(e){i&&(i.abort(),a(e),i=null)}),void 0===n&&(n=null),i.send(n)})}},function(e,t,r){\"use strict\";var n=r(10);e.exports=function(e,t,r){var a=r.config.validateStatus;r.status&&a&&!a(r.status)?t(n(\"Request failed with status code \"+r.status,r.config,null,r.request,r)):e(r)}},function(e,t,r){\"use strict\";var i=r(11);e.exports=function(e,t,r,a,n){var o=new Error(e);return i(o,t,r,a,n)}},function(e,t){\"use strict\";e.exports=function(e,t,r,a,n){return e.config=t,r&&(e.code=r),e.request=a,e.response=n,e}},function(e,t,r){\"use strict\";var utils=r(2);function o(e){return encodeURIComponent(e).replace(/%40/gi,\"@\").replace(/%3A/gi,\":\").replace(/%24/g,\"$\").replace(/%2C/gi,\",\").replace(/%20/g,\"+\").replace(/%5B/gi,\"[\").replace(/%5D/gi,\"]\")}e.exports=function(e,t,r){if(!t)return e;var a;if(r)a=r(t);else if(utils.isURLSearchParams(t))a=t.toString();else{var n=[];utils.forEach(t,function(e,t){null!=e&&(utils.isArray(e)?t+=\"[]\":e=[e],utils.forEach(e,function(e){utils.isDate(e)?e=e.toISOString():utils.isObject(e)&&(e=JSON.stringify(e)),n.push(o(t)+\"=\"+o(e))}))}),a=n.join(\"&\")}return a&&(e+=(-1===e.indexOf(\"?\")?\"?\":\"&\")+a),e}},function(e,t,r){\"use strict\";var utils=r(2),o=[\"age\",\"authorization\",\"content-length\",\"content-type\",\"etag\",\"expires\",\"from\",\"host\",\"if-modified-since\",\"if-unmodified-since\",\"last-modified\",\"location\",\"max-forwards\",\"proxy-authorization\",\"referer\",\"retry-after\",\"user-agent\"];e.exports=function(e){var t,r,a,n={};return e&&utils.forEach(e.split(\"\\n\"),function(e){if(a=e.indexOf(\":\"),t=utils.trim(e.substr(0,a)).toLowerCase(),r=utils.trim(e.substr(a+1)),t){if(n[t]&&0<=o.indexOf(t))return;n[t]=\"set-cookie\"===t?(n[t]?n[t]:[]).concat([r]):n[t]?n[t]+\", \"+r:r}}),n}},function(e,t,r){\"use strict\";var utils=r(2);e.exports=utils.isStandardBrowserEnv()?function(){var r,a=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement(\"a\");function o(e){var t=e;return a&&(n.setAttribute(\"href\",t),t=n.href),n.setAttribute(\"href\",t),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,\"\"):\"\",host:n.host,search:n.search?n.search.replace(/^\\?/,\"\"):\"\",hash:n.hash?n.hash.replace(/^#/,\"\"):\"\",hostname:n.hostname,port:n.port,pathname:\"/\"===n.pathname.charAt(0)?n.pathname:\"/\"+n.pathname}}return r=o(window.location.href),function(e){var t=utils.isString(e)?o(e):e;return t.protocol===r.protocol&&t.host===r.host}}():function(){return!0}},function(e,t){\"use strict\";function s(){this.message=\"String contains an invalid character\"}(s.prototype=new Error).code=5,s.prototype.name=\"InvalidCharacterError\",e.exports=function(e){for(var t,r,a=String(e),n=\"\",o=0,i=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";a.charAt(0|o)||(i=\"=\",o%1);n+=i.charAt(63&t>>8-o%1*8)){if(255<(r=a.charCodeAt(o+=.75)))throw new s;t=t<<8|r}return n}},function(e,t,r){\"use strict\";var utils=r(2);e.exports=utils.isStandardBrowserEnv()?{write:function(e,t,r,a,n,o){var i=[];i.push(e+\"=\"+encodeURIComponent(t)),utils.isNumber(r)&&i.push(\"expires=\"+new Date(r).toGMTString()),utils.isString(a)&&i.push(\"path=\"+a),utils.isString(n)&&i.push(\"domain=\"+n),!0===o&&i.push(\"secure\"),document.cookie=i.join(\"; \")},read:function(e){var t=document.cookie.match(new RegExp(\"(^|;\\\\s*)(\"+e+\")=([^;]*)\"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,\"\",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},function(e,t,r){\"use strict\";var utils=r(2);function a(){this.handlers=[]}a.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},a.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},a.prototype.forEach=function(t){utils.forEach(this.handlers,function(e){null!==e&&t(e)})},e.exports=a},function(e,t,r){\"use strict\";var utils=r(2),a=r(19),n=r(20),o=r(6),i=r(21),s=r(22);function l(e){e.cancelToken&&e.cancelToken.throwIfRequested()}e.exports=function(t){return l(t),t.baseURL&&!i(t.url)&&(t.url=s(t.baseURL,t.url)),t.headers=t.headers||{},t.data=a(t.data,t.headers,t.transformRequest),t.headers=utils.merge(t.headers.common||{},t.headers[t.method]||{},t.headers||{}),utils.forEach([\"delete\",\"get\",\"head\",\"post\",\"put\",\"patch\",\"common\"],function(e){delete t.headers[e]}),(t.adapter||o.adapter)(t).then(function(e){return l(t),e.data=a(e.data,e.headers,t.transformResponse),e},function(e){return n(e)||(l(t),e&&e.response&&(e.response.data=a(e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)})}},function(e,t,r){\"use strict\";var utils=r(2);e.exports=function(t,r,e){return utils.forEach(e,function(e){t=e(t,r)}),t}},function(e,t){\"use strict\";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t){\"use strict\";e.exports=function(e){return/^([a-z][a-z\\d\\+\\-\\.]*:)?\\/\\//i.test(e)}},function(e,t){\"use strict\";e.exports=function(e,t){return t?e.replace(/\\/+$/,\"\")+\"/\"+t.replace(/^\\/+/,\"\"):e}},function(e,t){\"use strict\";function r(e){this.message=e}r.prototype.toString=function(){return\"Cancel\"+(this.message?\": \"+this.message:\"\")},r.prototype.__CANCEL__=!0,e.exports=r},function(e,t,r){\"use strict\";var a=r(23);function n(e){if(\"function\"!=typeof e)throw new TypeError(\"executor must be a function.\");var t;this.promise=new Promise(function(e){t=e});var r=this;e(function(e){r.reason||(r.reason=new a(e),t(r.reason))})}n.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},n.source=function(){var t;return{token:new n(function(e){t=e}),cancel:t}},e.exports=n},function(e,t){\"use strict\";e.exports=function(t){return function(e){return t.apply(null,e)}}}]),axe.imports.doT=function(e,t,r,a,n){var o=Function(\"return this\")(),i=o.doT;!function(){\"use strict\";var l,u={name:\"doT\",version:\"1.1.1\",templateSettings:{evaluate:/\\{\\{([\\s\\S]+?(\\}?)+)\\}\\}/g,interpolate:/\\{\\{=([\\s\\S]+?)\\}\\}/g,encode:/\\{\\{!([\\s\\S]+?)\\}\\}/g,use:/\\{\\{#([\\s\\S]+?)\\}\\}/g,useParams:/(^|[^\\w$])def(?:\\.|\\[[\\'\\\"])([\\w$\\.]+)(?:[\\'\\\"]\\])?\\s*\\:\\s*([\\w$\\.]+|\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|\\{[^\\}]+\\})/g,define:/\\{\\{##\\s*([\\w\\.$]+)\\s*(\\:|=)([\\s\\S]+?)#\\}\\}/g,defineParams:/^\\s*([\\w$]+):([\\s\\S]+)/,conditional:/\\{\\{\\?(\\?)?\\s*([\\s\\S]*?)\\s*\\}\\}/g,iterate:/\\{\\{~\\s*(?:\\}\\}|([\\s\\S]+?)\\s*\\:\\s*([\\w$]+)\\s*(?:\\:\\s*([\\w$]+))?\\s*\\}\\})/g,varname:\"it\",strip:!0,append:!0,selfcontained:!1,doNotSkipEncoded:!1},template:void 0,compile:void 0,log:!0};u.encodeHTMLSource=function(e){var t={\"&\":\"&#38;\",\"<\":\"&#60;\",\">\":\"&#62;\",'\"':\"&#34;\",\"'\":\"&#39;\",\"/\":\"&#47;\"},r=e?/[&<>\"'\\/]/g:/&(?!#?\\w+;)|<|>|\"|'|\\//g;return function(e){return e?e.toString().replace(r,function(e){return t[e]||e}):\"\"}},(l=function(){return this||(0,eval)(\"this\")}()).doT=u;var c={append:{start:\"'+(\",end:\")+'\",startencode:\"'+encodeHTML(\"},split:{start:\"';out+=(\",end:\");out+='\",startencode:\"';out+=encodeHTML(\"}},d=/$^/;function m(e){return e.replace(/\\\\('|\\\\)/g,\"$1\").replace(/[\\r\\t\\n]/g,\" \")}u.template=function(e,t,r){var a,n,o=(t=t||u.templateSettings).append?c.append:c.split,i=0,s=t.use||t.define?function a(n,e,o){return(\"string\"==typeof e?e:e.toString()).replace(n.define||d,function(e,a,t,r){return 0===a.indexOf(\"def.\")&&(a=a.substring(4)),a in o||(\":\"===t?(n.defineParams&&r.replace(n.defineParams,function(e,t,r){o[a]={arg:t,text:r}}),a in o||(o[a]=r)):new Function(\"def\",\"def['\"+a+\"']=\"+r)(o)),\"\"}).replace(n.use||d,function(e,t){n.useParams&&(t=t.replace(n.useParams,function(e,t,r,a){if(o[r]&&o[r].arg&&a){var n=(r+\":\"+a).replace(/'|\\\\/g,\"_\");return o.__exp=o.__exp||{},o.__exp[n]=o[r].text.replace(new RegExp(\"(^|[^\\\\w$])\"+o[r].arg+\"([^\\\\w$])\",\"g\"),\"$1\"+a+\"$2\"),t+\"def.__exp['\"+n+\"']\"}}));var r=new Function(\"def\",\"return \"+t)(o);return r?a(n,r,o):r})}(t,e,r||{}):e;s=(\"var out='\"+(t.strip?s.replace(/(^|\\r|\\n)\\t* +| +\\t*(\\r|\\n|$)/g,\" \").replace(/\\r|\\n|\\t|\\/\\*[\\s\\S]*?\\*\\//g,\"\"):s).replace(/'|\\\\/g,\"\\\\$&\").replace(t.interpolate||d,function(e,t){return o.start+m(t)+o.end}).replace(t.encode||d,function(e,t){return a=!0,o.startencode+m(t)+o.end}).replace(t.conditional||d,function(e,t,r){return t?r?\"';}else if(\"+m(r)+\"){out+='\":\"';}else{out+='\":r?\"';if(\"+m(r)+\"){out+='\":\"';}out+='\"}).replace(t.iterate||d,function(e,t,r,a){return t?(i+=1,n=a||\"i\"+i,t=m(t),\"';var arr\"+i+\"=\"+t+\";if(arr\"+i+\"){var \"+r+\",\"+n+\"=-1,l\"+i+\"=arr\"+i+\".length-1;while(\"+n+\"<l\"+i+\"){\"+r+\"=arr\"+i+\"[\"+n+\"+=1];out+='\"):\"';} } out+='\"}).replace(t.evaluate||d,function(e,t){return\"';\"+m(t)+\"out+='\"})+\"';return out;\").replace(/\\n/g,\"\\\\n\").replace(/\\t/g,\"\\\\t\").replace(/\\r/g,\"\\\\r\").replace(/(\\s|;|\\}|^|\\{)out\\+='';/g,\"$1\").replace(/\\+''/g,\"\"),a&&(t.selfcontained||!l||l._encodeHTML||(l._encodeHTML=u.encodeHTMLSource(t.doNotSkipEncoded)),s=\"var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : (\"+u.encodeHTMLSource.toString()+\"(\"+(t.doNotSkipEncoded||\"\")+\"));\"+s);try{return new Function(t.varname,s)}catch(e){throw\"undefined\"!=typeof console&&console.log(\"Could not create a template function: \"+s),e}},u.compile=function(e,t){return u.template(e,null,t)}}();var s=o.doT;return delete o.doT,i&&(o.doT=i),s}();T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function g(t,r){\"use strict\";if(t=t||function(){},r=r||axe.log,!axe._audit)throw new Error(\"No audit configured\");var a=axe.utils.queue(),n=[];Object.keys(axe.plugins).forEach(function(e){a.defer(function(t){var r=function(e){n.push(e),t()};try{axe.plugins[e].cleanup(t,r)}catch(e){r(e)}})});var e=axe.utils.getFlattenedTree(document.body);axe.utils.querySelectorAll(e,\"iframe, frame\").forEach(function(r){a.defer(function(e,t){return axe.utils.sendCommandToFrame(r.actualNode,{command:\"cleanup-plugin\"},e,t)})}),a.then(function(e){0===n.length?t(e):r(n)}).catch(r)}function b(e,t,r){\"use strict\";var a=r,n=function(e){e instanceof Error==!1&&(e=new Error(e)),r(e)},o=e&&e.context||{};o.hasOwnProperty(\"include\")&&!o.include.length&&(o.include=[document]);var i=e&&e.options||{};switch(e.command){case\"rules\":return x(o,i,function(e,t){a(e),t()},n);case\"cleanup-plugin\":return g(a,n);default:if(axe._audit&&axe._audit.commands&&axe._audit.commands[e.command])return axe._audit.commands[e.command](e,r)}}function y(e){\"use strict\";this._run=e.run,this._collect=e.collect,this._registry={},e.commands.forEach(function(e){axe._audit.registerCommand(e)})}axe.log=function(){\"use strict\";\"object\"===(\"undefined\"==typeof console?\"undefined\":T(console))&&console.log&&Function.prototype.apply.call(console.log,console,arguments)},axe.cleanup=g,axe.configure=function(e){\"use strict\";var t;if(!(t=axe._audit))throw new Error(\"No audit configured\");e.reporter&&(\"function\"==typeof e.reporter||w[e.reporter])&&(t.reporter=e.reporter),e.checks&&e.checks.forEach(function(e){t.addCheck(e)});var r=[];e.rules&&e.rules.forEach(function(e){r.push(e.id),t.addRule(e)}),e.disableOtherRules&&t.rules.forEach(function(e){!1===r.includes(e.id)&&(e.enabled=!1)}),void 0!==e.branding?t.setBranding(e.branding):t._constructHelpUrls(),e.tagExclude&&(t.tagExclude=e.tagExclude),e.locale&&t.applyLocale(e.locale)},axe.getRules=function(e){\"use strict\";var t=(e=e||[]).length?axe._audit.rules.filter(function(t){return!!e.filter(function(e){return-1!==t.tags.indexOf(e)}).length}):axe._audit.rules,r=axe._audit.data.rules||{};return t.map(function(e){var t=r[e.id]||{};return{ruleId:e.id,description:t.description,help:t.help,helpUrl:t.helpUrl,tags:e.tags}})},axe._load=function(e){\"use strict\";axe.utils.respondable.subscribe(\"axe.ping\",function(e,t,r){r({axe:!0})}),axe.utils.respondable.subscribe(\"axe.start\",b),axe._audit=new r(e)},(axe=axe||{}).plugins={},y.prototype.run=function(){\"use strict\";return this._run.apply(this,arguments)},y.prototype.collect=function(){\"use strict\";return this._collect.apply(this,arguments)},y.prototype.cleanup=function(e){\"use strict\";var r=axe.utils.queue(),a=this;Object.keys(this._registry).forEach(function(t){r.defer(function(e){a._registry[t].cleanup(e)})}),r.then(function(){e()})},y.prototype.add=function(e){\"use strict\";this._registry[e.id]=e},axe.registerPlugin=function(e){\"use strict\";axe.plugins[e.id]=new y(e)};var v,w={};function k(){axe._tree=void 0,axe._selectorData=void 0}function x(r,a,n,o){\"use strict\";try{r=new u(r),axe._tree=r.flatTree,axe._selectorData=axe.utils.getSelectorData(r.flatTree)}catch(e){return k(),o(e)}var e=axe.utils.queue(),i=axe._audit;a.performanceTimer&&axe.utils.performanceTimer.auditStart(),r.frames.length&&!1!==a.iframes&&e.defer(function(e,t){axe.utils.collectResultsFromFrames(r,a,\"rules\",null,e,t)});var s=void 0;e.defer(function(e,t){a.restoreScroll&&(s=axe.utils.getScrollState()),i.run(r,a,e,t)}),e.then(function(e){try{s&&axe.utils.setScrollState(s),a.performanceTimer&&axe.utils.performanceTimer.auditEnd();var t=axe.utils.mergeResults(e.map(function(e){return{results:e}}));r.initiator&&((t=i.after(t,a)).forEach(axe.utils.publishMetaData),t=t.map(axe.utils.finalizeRuleResult));try{n(t,k)}catch(e){k(),axe.log(e)}}catch(e){k(),o(e)}}).catch(function(e){k(),o(e)})}axe.getReporter=function(e){\"use strict\";return\"string\"==typeof e&&w[e]?w[e]:\"function\"==typeof e?e:v},axe.addReporter=function(e,t,r){\"use strict\";w[e]=t,r&&(v=t)},axe.reset=function(){\"use strict\";var e=axe._audit;if(!e)throw new Error(\"No audit configured\");e.resetRulesAndChecks()},axe._runRules=x;T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};var E=function(){};function A(e,t,r){\"use strict\";var a=new TypeError(\"axe.run arguments are invalid\");if(!function(e){switch(!0){case\"string\"==typeof e:case Array.isArray(e):case Node&&e instanceof Node:case NodeList&&e instanceof NodeList:return!0;case\"object\"!==(void 0===e?\"undefined\":T(e)):return!1;case void 0!==e.include:case void 0!==e.exclude:case\"number\"==typeof e.length:return!0;default:return!1}}(e)){if(void 0!==r)throw a;r=t,t=e,e=document}if(\"object\"!==(void 0===t?\"undefined\":T(t))){if(void 0!==r)throw a;r=t,t={}}if(\"function\"!=typeof r&&void 0!==r)throw a;return{context:e,options:t,callback:r||E}}axe.run=function(e,n,o){\"use strict\";if(!axe._audit)throw new Error(\"No audit configured\");var t=A(e,n,o);e=t.context,n=t.options,o=t.callback,n.reporter=n.reporter||axe._audit.reporter||\"v1\",n.performanceTimer&&axe.utils.performanceTimer.start();var r=void 0,i=E,s=E;return\"function\"==typeof Promise&&o===E&&(r=new Promise(function(e,t){i=t,s=e})),axe._runRules(e,n,function(e,t){var r=function(e){t();try{o(null,e)}catch(e){axe.log(e)}s(e)};n.performanceTimer&&axe.utils.performanceTimer.end();try{var a=axe.getReporter(n.reporter)(e,n,r);void 0!==a&&r(a)}catch(e){t(),o(e),i(e)}},function(e){o(e),i(e)}),r},i.failureSummary=function(e){\"use strict\";var r={};return r.none=e.none.concat(e.all),r.any=e.any,Object.keys(r).map(function(e){if(r[e].length){var t=axe._audit.data.failureSummaries[e];return t&&\"function\"==typeof t.failureMessage?t.failureMessage(r[e].map(function(e){return e.message||\"\"})):void 0}}).filter(function(e){return void 0!==e}).join(\"\\n\\n\")},i.incompleteFallbackMessage=function(){\"use strict\";return axe._audit.data.incompleteFallbackMessage()};T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};var N=axe.constants.resultGroups;i.processAggregate=function(e,r){var t=axe.utils.aggregateResult(e);return t.timestamp=(new Date).toISOString(),t.url=window.location.href,N.forEach(function(e){r.resultTypes&&!r.resultTypes.includes(e)&&(t[e]||[]).forEach(function(e){Array.isArray(e.nodes)&&0<e.nodes.length&&(e.nodes=[e.nodes[0]])}),t[e]=(t[e]||[]).map(function(t){return t=Object.assign({},t),Array.isArray(t.nodes)&&0<t.nodes.length&&(t.nodes=t.nodes.map(function(e){return\"object\"===T(e.node)&&(e.html=e.node.source,r.elementRef&&!e.node.fromFrame&&(e.element=e.node.element),(!1!==r.selectors||e.node.fromFrame)&&(e.target=e.node.selector),r.xpath&&(e.xpath=e.node.xpath)),delete e.result,delete e.node,function(t,r){\"use strict\";[\"any\",\"all\",\"none\"].forEach(function(e){Array.isArray(t[e])&&t[e].filter(function(e){return Array.isArray(e.relatedNodes)}).forEach(function(e){e.relatedNodes=e.relatedNodes.map(function(e){var t={html:e.source};return r.elementRef&&!e.fromFrame&&(t.element=e.element),(!1!==r.selectors||e.fromFrame)&&(t.target=e.selector),r.xpath&&(t.xpath=e.xpath),t})})})}(e,r),e})),N.forEach(function(e){return delete t[e]}),delete t.pageLevel,delete t.result,t})}),t},axe.addReporter(\"na\",function(e,t,r){\"use strict\";\"function\"==typeof t&&(r=t,t={});var a=i.processAggregate(e,t);r({violations:a.violations,passes:a.passes,incomplete:a.incomplete,inapplicable:a.inapplicable,timestamp:a.timestamp,url:a.url})}),axe.addReporter(\"no-passes\",function(e,t,r){\"use strict\";\"function\"==typeof t&&(r=t,t={}),t.resultTypes=[\"violations\"];var a=i.processAggregate(e,t);r({violations:a.violations,timestamp:a.timestamp,url:a.url})}),axe.addReporter(\"raw\",function(e,t,r){\"use strict\";\"function\"==typeof t&&(r=t,t={}),r(e)}),axe.addReporter(\"v1\",function(e,t,r){\"use strict\";\"function\"==typeof t&&(r=t,t={});var a=i.processAggregate(e,t);a.violations.forEach(function(e){return e.nodes.forEach(function(e){e.failureSummary=i.failureSummary(e)})}),r({violations:a.violations,passes:a.passes,incomplete:a.incomplete,inapplicable:a.inapplicable,timestamp:a.timestamp,url:a.url})}),axe.addReporter(\"v2\",function(e,t,r){\"use strict\";\"function\"==typeof t&&(r=t,t={});var a=i.processAggregate(e,t);r({violations:a.violations,passes:a.passes,incomplete:a.incomplete,inapplicable:a.inapplicable,timestamp:a.timestamp,url:a.url})},!0),axe.utils.aggregate=function(t,e,r){e=e.slice(),r&&e.push(r);var a=e.map(function(e){return t.indexOf(e)}).sort();return t[a.pop()]};var j=axe.constants,z=j.CANTTELL_PRIO,q=j.FAIL_PRIO,S=[];S[axe.constants.PASS_PRIO]=!0,S[axe.constants.CANTTELL_PRIO]=null,S[axe.constants.FAIL_PRIO]=!1;var C=[\"any\",\"all\",\"none\"];function R(r,a){return C.reduce(function(e,t){return e[t]=(r[t]||[]).map(function(e){return a(e,t)}),e},{})}function I(e,t,r){var a=Object.assign({},t);a.nodes=(a[r]||[]).concat(),axe.constants.resultGroups.forEach(function(e){delete a[e]}),e[r].push(a)}axe.utils.aggregateChecks=function(e){var r=Object.assign({},e);R(r,function(e,t){var r=void 0===e.result?-1:S.indexOf(e.result);e.priority=-1!==r?r:axe.constants.CANTTELL_PRIO,\"none\"===t&&(e.priority===axe.constants.PASS_PRIO?e.priority=axe.constants.FAIL_PRIO:e.priority===axe.constants.FAIL_PRIO&&(e.priority=axe.constants.PASS_PRIO))});var a={all:r.all.reduce(function(e,t){return Math.max(e,t.priority)},0),none:r.none.reduce(function(e,t){return Math.max(e,t.priority)},0),any:r.any.reduce(function(e,t){return Math.min(e,t.priority)},4)%4};r.priority=Math.max(a.all,a.none,a.any);var n=[];return C.forEach(function(t){r[t]=r[t].filter(function(e){return e.priority===r.priority&&e.priority===a[t]}),r[t].forEach(function(e){return n.push(e.impact)})}),[z,q].includes(r.priority)?r.impact=axe.utils.aggregate(axe.constants.impact,n):r.impact=null,R(r,function(e){delete e.result,delete e.priority}),r.result=axe.constants.results[r.priority],delete r.priority,r},axe.utils.aggregateNodeResults=function(e){var r={};if((e=e.map(function(e){if(e.any&&e.all&&e.none)return axe.utils.aggregateChecks(e);if(Array.isArray(e.node))return axe.utils.finalizeRuleResult(e);throw new TypeError(\"Invalid Result type\")}))&&e.length){var t=e.map(function(e){return e.result});r.result=axe.utils.aggregate(axe.constants.results,t,r.result)}else r.result=\"inapplicable\";axe.constants.resultGroups.forEach(function(e){return r[e]=[]}),e.forEach(function(e){var t=axe.constants.resultGroupMap[e.result];r[t].push(e)});var a=axe.constants.FAIL_GROUP;if(0===r[a].length&&(a=axe.constants.CANTTELL_GROUP),0<r[a].length){var n=r[a].map(function(e){return e.impact});r.impact=axe.utils.aggregate(axe.constants.impact,n)||null}else r.impact=null;return r},axe.utils.aggregateResult=function(e){var r={};return axe.constants.resultGroups.forEach(function(e){return r[e]=[]}),e.forEach(function(t){t.error?I(r,t,axe.constants.CANTTELL_GROUP):t.result===axe.constants.NA?I(r,t,axe.constants.NA_GROUP):axe.constants.resultGroups.forEach(function(e){Array.isArray(t[e])&&0<t[e].length&&I(r,t,e)})}),r},axe.utils.areStylesSet=function e(t,r,a){\"use strict\";var n=window.getComputedStyle(t,null),o=!1;return!!n&&(r.forEach(function(e){n.getPropertyValue(e.property)===e.value&&(o=!0)}),!!o||!(t.nodeName.toUpperCase()===a.toUpperCase()||!t.parentNode)&&e(t.parentNode,r,a))},axe.utils.checkHelper=function(t,r,a,n){\"use strict\";return{isAsync:!1,async:function(){return this.isAsync=!0,function(e){e instanceof Error==!1?(t.result=e,a(t)):n(e)}},data:function(e){t.data=e},relatedNodes:function(e){e=e instanceof Node?[e]:axe.utils.toArray(e),t.relatedNodes=e.map(function(e){return new axe.utils.DqElement(e,r)})}}};T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function O(e,t){\"use strict\";var r;return axe._tree&&(r=axe.utils.getSelector(t)),new Error(e+\": \"+(r||t))}function L(e,t,r){var a,n;this._fromFrame=!!r,this.spec=r||{},t&&t.absolutePaths&&(this._options={toRoot:!0}),this.source=void 0!==this.spec.source?this.spec.source:((n=(a=e).outerHTML)||\"function\"!=typeof XMLSerializer||(n=(new XMLSerializer).serializeToString(a)),function(e,t){if(t=t||300,e.length>t){var r=e.indexOf(\">\");e=e.substring(0,r+1)}return e}(n||\"\")),this._element=e}axe.utils.clone=function(e){\"use strict\";var t,r,a=e;if(null!==e&&\"object\"===(void 0===e?\"undefined\":T(e)))if(Array.isArray(e))for(a=[],t=0,r=e.length;t<r;t++)a[t]=axe.utils.clone(e[t]);else for(t in a={},e)a[t]=axe.utils.clone(e[t]);return a},axe.utils.sendCommandToFrame=function(t,r,a,n){\"use strict\";var o=t.contentWindow;if(!o)return axe.log(\"Frame does not have a content window\",t),void a(null);var i=setTimeout(function(){i=setTimeout(function(){r.debug?n(O(\"No response from frame\",t)):a(null)},0)},500);axe.utils.respondable(o,\"axe.ping\",null,void 0,function(){clearTimeout(i);var e=r.options&&r.options.frameWaitTime||6e4;i=setTimeout(function(){n(O(\"Axe in frame timed out\",t))},e),axe.utils.respondable(o,\"axe.start\",r,void 0,function(e){clearTimeout(i),e instanceof Error==!1?a(e):n(e)})})},axe.utils.collectResultsFromFrames=function(e,t,r,o,a,n){\"use strict\";var i=axe.utils.queue();e.frames.forEach(function(a){var n={options:t,command:r,parameter:o,context:{initiator:!1,page:e.page,include:a.include||[],exclude:a.exclude||[]}};i.defer(function(t,e){var r=a.node;axe.utils.sendCommandToFrame(r,n,function(e){if(e)return t({results:e,frameElement:r,frame:axe.utils.getSelector(r)});t(null)},e)})}),i.then(function(e){a(axe.utils.mergeResults(e,t))}).catch(n)},axe.utils.contains=function(e,t){\"use strict\";return e.shadowId||t.shadowId?function t(e,r){return e.shadowId===r.shadowId||!!e.children.find(function(e){return t(e,r)})}(e,t):\"function\"==typeof e.actualNode.contains?e.actualNode.contains(t.actualNode):!!(16&e.actualNode.compareDocumentPosition(t.actualNode))},function(axe){function e(){this.pseudos={},this.attrEqualityMods={},this.ruleNestingOperators={},this.substitutesEnabled=!1}function o(e){return\"a\"<=e&&e<=\"f\"||\"A\"<=e&&e<=\"F\"||\"0\"<=e&&e<=\"9\"}e.prototype.registerSelectorPseudos=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],this.pseudos[e]=\"selector\";return this},e.prototype.unregisterSelectorPseudos=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],delete this.pseudos[e];return this},e.prototype.registerNumericPseudos=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],this.pseudos[e]=\"numeric\";return this},e.prototype.unregisterNumericPseudos=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],delete this.pseudos[e];return this},e.prototype.registerNestingOperators=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],this.ruleNestingOperators[e]=!0;return this},e.prototype.unregisterNestingOperators=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],delete this.ruleNestingOperators[e];return this},e.prototype.registerAttrEqualityMods=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],this.attrEqualityMods[e]=!0;return this},e.prototype.unregisterAttrEqualityMods=function(e){for(var t=0,r=arguments.length;t<r;t++)e=arguments[t],delete this.attrEqualityMods[e];return this},e.prototype.enableSubstitutes=function(){return this.substitutesEnabled=!0,this},e.prototype.disableSubstitutes=function(){return this.substitutesEnabled=!1,this};var s={\"!\":!0,'\"':!0,\"#\":!0,$:!0,\"%\":!0,\"&\":!0,\"'\":!0,\"(\":!0,\")\":!0,\"*\":!0,\"+\":!0,\",\":!0,\".\":!0,\"/\":!0,\";\":!0,\"<\":!0,\"=\":!0,\">\":!0,\"?\":!0,\"@\":!0,\"[\":!0,\"\\\\\":!0,\"]\":!0,\"^\":!0,\"`\":!0,\"{\":!0,\"|\":!0,\"}\":!0,\"~\":!0},i={\"\\n\":\"\\\\n\",\"\\r\":\"\\\\r\",\"\\t\":\"\\\\t\",\"\\f\":\"\\\\f\",\"\\v\":\"\\\\v\"},y={n:\"\\n\",r:\"\\r\",t:\"\\t\",f:\"\\f\",\"\\\\\":\"\\\\\",\"'\":\"'\"},v={n:\"\\n\",r:\"\\r\",t:\"\\t\",f:\"\\f\",\"\\\\\":\"\\\\\",'\"':'\"'};function t(l,u,c,d,n,m){var p,f,h,g,b;return g=l.length,p=null,h=function(e,t){var r,a,n;for(n=\"\",u++,p=l.charAt(u);u<g;){if(p===e)return u++,n;if(\"\\\\\"===p)if(u++,(p=l.charAt(u))===e)n+=e;else if(r=t[p])n+=r;else{if(o(p)){for(a=p,u++,p=l.charAt(u);o(p);)a+=p,u++,p=l.charAt(u);\" \"===p&&(u++,p=l.charAt(u)),n+=String.fromCharCode(parseInt(a,16));continue}n+=p}else n+=p;u++,p=l.charAt(u)}return n},f=function(){var e,t=\"\";for(p=l.charAt(u);u<g;){if(\"a\"<=(e=p)&&e<=\"z\"||\"A\"<=e&&e<=\"Z\"||\"0\"<=e&&e<=\"9\"||\"-\"===e||\"_\"===e)t+=p;else{if(\"\\\\\"!==p)return t;if(g<=++u)throw Error(\"Expected symbol but end of file reached.\");if(p=l.charAt(u),s[p])t+=p;else{if(o(p)){var r=p;for(u++,p=l.charAt(u);o(p);)r+=p,u++,p=l.charAt(u);\" \"===p&&(u++,p=l.charAt(u)),t+=String.fromCharCode(parseInt(r,16));continue}t+=p}}u++,p=l.charAt(u)}return t},b=function(){p=l.charAt(u);for(var e=!1;\" \"===p||\"\\t\"===p||\"\\n\"===p||\"\\r\"===p||\"\\f\"===p;)e=!0,u++,p=l.charAt(u);return e},this.parse=function(){var e=this.parseSelector();if(u<g)throw Error('Rule expected but \"'+l.charAt(u)+'\" found.');return e},this.parseSelector=function(){var e,t=e=this.parseSingleSelector();for(p=l.charAt(u);\",\"===p;){if(u++,b(),\"selectors\"!==e.type&&(e={type:\"selectors\",selectors:[t]}),!(t=this.parseSingleSelector()))throw Error('Rule expected after \",\".');e.selectors.push(t)}return e},this.parseSingleSelector=function(){b();var e={type:\"ruleSet\"},t=this.parseRule();if(!t)return null;for(var r=e;t&&(t.type=\"rule\",r.rule=t,r=t,b(),p=l.charAt(u),!(g<=u||\",\"===p||\")\"===p));)if(n[p]){var a=p;if(u++,b(),!(t=this.parseRule()))throw Error('Rule expected after \"'+a+'\".');t.nestingOperator=a}else(t=this.parseRule())&&(t.nestingOperator=null);return e},this.parseRule=function(){for(var e,t=null;u<g;)if(\"*\"===(p=l.charAt(u)))u++,(t=t||{}).tagName=\"*\";else if(\"a\"<=(e=p)&&e<=\"z\"||\"A\"<=e&&e<=\"Z\"||\"-\"===e||\"_\"===e||\"\\\\\"===p)(t=t||{}).tagName=f();else if(\".\"===p)u++,((t=t||{}).classNames=t.classNames||[]).push(f());else if(\"#\"===p)u++,(t=t||{}).id=f();else if(\"[\"===p){u++,b();var r={name:f()};if(b(),\"]\"===p)u++;else{var a=\"\";if(d[p]&&(a=p,u++,p=l.charAt(u)),g<=u)throw Error('Expected \"=\" but end of file reached.');if(\"=\"!==p)throw Error('Expected \"=\" but \"'+p+'\" found.');r.operator=a+\"=\",u++,b();var n=\"\";if(r.valueType=\"string\",'\"'===p)n=h('\"',v);else if(\"'\"===p)n=h(\"'\",y);else if(m&&\"$\"===p)u++,n=f(),r.valueType=\"substitute\";else{for(;u<g&&\"]\"!==p;)n+=p,u++,p=l.charAt(u);n=n.trim()}if(b(),g<=u)throw Error('Expected \"]\" but end of file reached.');if(\"]\"!==p)throw Error('Expected \"]\" but \"'+p+'\" found.');u++,r.value=n}((t=t||{}).attrs=t.attrs||[]).push(r)}else{if(\":\"!==p)break;u++;var o=f(),i={name:o};if(\"(\"===p){u++;var s=\"\";if(b(),\"selector\"===c[o])i.valueType=\"selector\",s=this.parseSelector();else{if(i.valueType=c[o]||\"string\",'\"'===p)s=h('\"',v);else if(\"'\"===p)s=h(\"'\",y);else if(m&&\"$\"===p)u++,s=f(),i.valueType=\"substitute\";else{for(;u<g&&\")\"!==p;)s+=p,u++,p=l.charAt(u);s=s.trim()}b()}if(g<=u)throw Error('Expected \")\" but end of file reached.');if(\")\"!==p)throw Error('Expected \")\" but \"'+p+'\" found.');u++,i.value=s}((t=t||{}).pseudos=t.pseudos||[]).push(i)}return t},this}e.prototype.parse=function(e){return new t(e,0,this.pseudos,this.attrEqualityMods,this.ruleNestingOperators,this.substitutesEnabled).parse()},e.prototype.escapeIdentifier=function(e){for(var t=\"\",r=0,a=e.length;r<a;){var n=e.charAt(r);if(s[n])t+=\"\\\\\"+n;else if(\"_\"===n||\"-\"===n||\"A\"<=n&&n<=\"Z\"||\"a\"<=n&&n<=\"z\"||0!==r&&\"0\"<=n&&n<=\"9\")t+=n;else{var o=n.charCodeAt(0);if(55296==(63488&o)){var i=e.charCodeAt(r++);if(55296!=(64512&o)||56320!=(64512&i))throw Error(\"UCS-2(decode): illegal sequence\");o=((1023&o)<<10)+(1023&i)+65536}t+=\"\\\\\"+o.toString(16)+\" \"}r++}return t},e.prototype.escapeStr=function(e){for(var t,r,a=\"\",n=0,o=e.length;n<o;)'\"'===(t=e.charAt(n))?t='\\\\\"':\"\\\\\"===t?t=\"\\\\\\\\\":(r=i[t])&&(t=r),a+=t,n++;return'\"'+a+'\"'},e.prototype.render=function(e){return this._renderEntity(e).trim()},e.prototype._renderEntity=function(e){var t,r,a;switch(a=\"\",e.type){case\"ruleSet\":for(t=e.rule,r=[];t;)t.nestingOperator&&r.push(t.nestingOperator),r.push(this._renderEntity(t)),t=t.rule;a=r.join(\" \");break;case\"selectors\":a=e.selectors.map(this._renderEntity,this).join(\", \");break;case\"rule\":e.tagName&&(a=\"*\"===e.tagName?\"*\":this.escapeIdentifier(e.tagName)),e.id&&(a+=\"#\"+this.escapeIdentifier(e.id)),e.classNames&&(a+=e.classNames.map(function(e){return\".\"+this.escapeIdentifier(e)},this).join(\"\")),e.attrs&&(a+=e.attrs.map(function(e){return e.operator?\"substitute\"===e.valueType?\"[\"+this.escapeIdentifier(e.name)+e.operator+\"$\"+e.value+\"]\":\"[\"+this.escapeIdentifier(e.name)+e.operator+this.escapeStr(e.value)+\"]\":\"[\"+this.escapeIdentifier(e.name)+\"]\"},this).join(\"\")),e.pseudos&&(a+=e.pseudos.map(function(e){return e.valueType?\"selector\"===e.valueType?\":\"+this.escapeIdentifier(e.name)+\"(\"+this._renderEntity(e.value)+\")\":\"substitute\"===e.valueType?\":\"+this.escapeIdentifier(e.name)+\"($\"+e.value+\")\":\"numeric\"===e.valueType?\":\"+this.escapeIdentifier(e.name)+\"(\"+e.value+\")\":\":\"+this.escapeIdentifier(e.name)+\"(\"+this.escapeIdentifier(e.value)+\")\":\":\"+this.escapeIdentifier(e.name)},this).join(\"\"));break;default:throw Error('Unknown entity type: \"'+e.type(NaN))}return a};var r=new e;r.registerNestingOperators(\">\"),axe.utils.cssParser=r}(axe),L.prototype={get selector(){return this.spec.selector||[axe.utils.getSelector(this.element,this._options)]},get xpath(){return this.spec.xpath||[axe.utils.getXpath(this.element)]},get element(){return this._element},get fromFrame(){return this._fromFrame},toJSON:function(){\"use strict\";return{selector:this.selector,source:this.source,xpath:this.xpath}}},L.fromFrame=function(e,t,r){return e.selector.unshift(r.selector),e.xpath.unshift(r.xpath),new axe.utils.DqElement(r.element,t,e)},axe.utils.DqElement=L,axe.utils.matchesSelector=function(){\"use strict\";var r;return function(e,t){return r&&e[r]||(r=function(e){var t,r,a=[\"matches\",\"matchesSelector\",\"mozMatchesSelector\",\"webkitMatchesSelector\",\"msMatchesSelector\"],n=a.length;for(t=0;t<n;t++)if(e[r=a[t]])return r}(e)),e[r](t)}}(),axe.utils.escapeSelector=function(e){\"use strict\";for(var t,r=String(e),a=r.length,n=-1,o=\"\",i=r.charCodeAt(0);++n<a;)0!=(t=r.charCodeAt(n))?o+=1<=t&&t<=31||127==t||0==n&&48<=t&&t<=57||1==n&&48<=t&&t<=57&&45==i?\"\\\\\"+t.toString(16)+\" \":(0!=n||1!=a||45!=t)&&(128<=t||45==t||95==t||48<=t&&t<=57||65<=t&&t<=90||97<=t&&t<=122)?r.charAt(n):\"\\\\\"+r.charAt(n):o+=\"�\";return o},axe.utils.extendMetaData=function(t,r){Object.assign(t,r),Object.keys(r).filter(function(e){return\"function\"==typeof r[e]}).forEach(function(e){t[e]=null;try{t[e]=r[e](t)}catch(e){}})},axe.utils.finalizeRuleResult=function(e){return Object.assign(e,axe.utils.aggregateNodeResults(e.nodes)),delete e.nodes,e};var axe;T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function P(e,t){return{shadowId:t,children:[],actualNode:e}}axe.utils.findBy=function(e,t,r){if(Array.isArray(e))return e.find(function(e){return\"object\"===(void 0===e?\"undefined\":T(e))&&e[t]===r})},(axe=axe||{utils:{}}).utils.getFlattenedTree=function(e,a){var t,r,n;function o(e,t){var r=axe.utils.getFlattenedTree(t,a);return r&&(e=e.concat(r)),e}if(e.documentElement&&(e=e.documentElement),n=e.nodeName.toLowerCase(),axe.utils.isShadowRoot(e))return t=P(e,a),a=\"a\"+Math.random().toString().substring(2),r=Array.from(e.shadowRoot.childNodes),t.children=r.reduce(o,[]),[t];if(\"content\"===n)return(r=Array.from(e.getDistributedNodes())).reduce(o,[]);if(\"slot\"!==n||\"function\"!=typeof e.assignedNodes)return 1===e.nodeType?(t=P(e,a),r=Array.from(e.childNodes),t.children=r.reduce(o,[]),[t]):3===e.nodeType?[P(e)]:void 0;(r=Array.from(e.assignedNodes())).length||(r=function(e){var t=[];for(e=e.firstChild;e;)t.push(e),e=e.nextSibling;return t}(e));window.getComputedStyle(e);return r.reduce(o,[])},axe.utils.getNodeFromTree=function(e,r){var a;return e.actualNode===r?e:(e.children.forEach(function(e){var t;e.actualNode===r?a=e:(t=axe.utils.getNodeFromTree(e,r))&&(a=t)}),a)},axe.utils.getAllChecks=function(e){\"use strict\";return[].concat(e.any||[]).concat(e.all||[]).concat(e.none||[])},axe.utils.getCheckOption=function(e,t,r){var a=((r.rules&&r.rules[t]||{}).checks||{})[e.id],n=(r.checks||{})[e.id],o=e.enabled,i=e.options;return n&&(n.hasOwnProperty(\"enabled\")&&(o=n.enabled),n.hasOwnProperty(\"options\")&&(i=n.options)),a&&(a.hasOwnProperty(\"enabled\")&&(o=a.enabled),a.hasOwnProperty(\"options\")&&(i=a.options)),{enabled:o,options:i,absolutePaths:r.absolutePaths}};var U=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var r=[],a=!0,n=!1,o=void 0;try{for(var i,s=e[Symbol.iterator]();!(a=(i=s.next()).done)&&(r.push(i.value),!t||r.length!==t);a=!0);}catch(e){n=!0,o=e}finally{try{!a&&s.return&&s.return()}finally{if(n)throw o}}return r}(e,t);throw new TypeError(\"Invalid attempt to destructure non-iterable instance\")};function F(e,t){return[e.substring(0,t),e.substring(t)]}function _(e){return e.replace(/\\s+$/,\"\")}axe.utils.getFriendlyUriEnd=function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:\"\",t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!(e.length<=1||\"data:\"===e.substr(0,5)||\"javascript:\"===e.substr(0,11)||e.includes(\"?\"))){var r=t.currentDomain,a=t.maxLength,n=void 0===a?25:a,o=function(e){var t=e,r=\"\",a=\"\",n=\"\",o=\"\",i=\"\";if(e.includes(\"#\")){var s=F(e,e.indexOf(\"#\")),l=U(s,2);e=l[0],i=l[1]}if(e.includes(\"?\")){var u=F(e,e.indexOf(\"?\")),c=U(u,2);e=c[0],o=c[1]}if(e.includes(\"://\")){var d=e.split(\"://\"),m=U(d,2);r=m[0];var p=F(e=m[1],e.indexOf(\"/\")),f=U(p,2);a=f[0],e=f[1]}else if(\"//\"===e.substr(0,2)){var h=F(e=e.substr(2),e.indexOf(\"/\")),g=U(h,2);a=g[0],e=g[1]}if(\"www.\"===a.substr(0,4)&&(a=a.substr(4)),a&&a.includes(\":\")){var b=F(a,a.indexOf(\":\")),y=U(b,2);a=y[0],n=y[1]}return{original:t,protocol:r,domain:a,port:n,path:e,query:o,hash:i}}(e),i=o.path,s=o.domain,l=o.hash,u=i.substr(i.substr(0,i.length-2).lastIndexOf(\"/\")+1);if(l)return u&&(u+l).length<=n?_(u+l):u.length<2&&2<l.length&&l.length<=n?_(l):void 0;if(s&&s.length<n&&i.length<=1)return _(s+i);if(i===\"/\"+u&&s&&r&&s!==r&&(s+i).length<=n)return _(s+i);var c=u.lastIndexOf(\".\");return(-1===c||1<c)&&(-1!==c||2<u.length)&&u.length<=n&&!u.match(/index(\\.[a-zA-Z]{2-4})?/)&&!function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:\"\";return 0!==e.length&&(e.match(/[0-9]/g)||\"\").length>=e.length/2}(u)?_(u):void 0}},axe.utils.getRootNode=function(e){var t=e.getRootNode&&e.getRootNode()||document;return t===e&&(t=document),t};var H,D=axe.utils.escapeSelector,M=void 0,V=[\"class\",\"style\",\"id\",\"selected\",\"checked\",\"disabled\",\"tabindex\",\"aria-checked\",\"aria-selected\",\"aria-invalid\",\"aria-activedescendant\",\"aria-busy\",\"aria-disabled\",\"aria-expanded\",\"aria-grabbed\",\"aria-pressed\",\"aria-valuenow\"],B=31;function G(e,t){var r=t.name,a=void 0;if(-1!==r.indexOf(\"href\")||-1!==r.indexOf(\"src\")){var n=axe.utils.getFriendlyUriEnd(e.getAttribute(r));if(n){var o=encodeURI(n);if(!o)return;a=D(t.name)+'$=\"'+o+'\"'}else a=D(t.name)+'=\"'+e.getAttribute(r)+'\"'}else a=D(r)+'=\"'+D(t.value)+'\"';return a}function Y(e,t){return e.count<t.count?-1:e.count===t.count?0:1}function W(e){return!V.includes(e.name)&&-1===e.name.indexOf(\":\")&&(!e.value||e.value.length<B)}function $(t,r){var e=t.parentNode&&Array.from(t.parentNode.children||\"\")||[];return e.find(function(e){return e!==t&&axe.utils.matchesSelector(e,r)})?\":nth-child(\"+(1+e.indexOf(t))+\")\":\"\"}function X(e){if(e.getAttribute(\"id\")){var t=e.getRootNode&&e.getRootNode()||document,r=\"#\"+D(e.getAttribute(\"id\")||\"\");return r.match(/player_uid_/)||1!==t.querySelectorAll(r).length?void 0:r}}function K(e){return void 0===M&&(M=axe.utils.isXHTML(document)),D(M?e.localName:e.nodeName.toLowerCase())}function J(e,t){var r,a,n,o,i,s,l,u,c,d,m=\"\",p=void 0,f=(r=e,n=[],o=(a=t).classes,i=a.tags,r.classList&&Array.from(r.classList).forEach(function(e){var t=D(e);o[t]<i[r.nodeName]&&n.push({name:t,count:o[t],species:\"class\"})}),n.sort(Y)),h=(s=e,u=[],c=(l=t).attributes,d=l.tags,s.attributes&&Array.from(s.attributes).filter(W).forEach(function(e){var t=G(s,e);t&&c[t]<d[s.nodeName]&&u.push({name:t,count:c[t],species:\"attribute\"})}),u.sort(Y));return f.length&&1===f[0].count?p=[f[0]]:h.length&&1===h[0].count?(p=[h[0]],m=K(e)):((p=f.concat(h)).sort(Y),(p=p.slice(0,3)).some(function(e){return\"class\"===e.species})?p.sort(function(e,t){return e.species!==t.species&&\"class\"===e.species?-1:e.species===t.species?0:1}):m=K(e)),m+p.reduce(function(e,t){switch(t.species){case\"class\":return e+\".\"+t.name;case\"attribute\":return e+\"[\"+t.name+\"]\"}return e},\"\")}function Z(e,t,r){if(!axe._selectorData)throw new Error(\"Expect axe._selectorData to be set up\");var a=t.toRoot,n=void 0!==a&&a,o=void 0,i=void 0;do{var s=X(e);s||(s=J(e,axe._selectorData),s+=$(e,s)),o=o?s+\" > \"+o:s,i=i?i.filter(function(e){return axe.utils.matchesSelector(e,o)}):Array.from(r.querySelectorAll(o)),e=e.parentElement}while((1<i.length||n)&&e&&11!==e.nodeType);return 1===i.length?o:-1!==o.indexOf(\" > \")?\":root\"+o.substring(o.indexOf(\" > \")):\":root\"}axe.utils.getSelectorData=function(e){for(var a={classes:{},tags:{},attributes:{}},n=(e=Array.isArray(e)?e:[e]).slice(),o=[],t=function(){var e=n.pop(),r=e.actualNode;if(r.querySelectorAll){var t=r.nodeName;a.tags[t]?a.tags[t]++:a.tags[t]=1,r.classList&&Array.from(r.classList).forEach(function(e){var t=D(e);a.classes[t]?a.classes[t]++:a.classes[t]=1}),r.attributes&&Array.from(r.attributes).filter(W).forEach(function(e){var t=G(r,e);t&&(a.attributes[t]?a.attributes[t]++:a.attributes[t]=1)})}for(e.children.length&&(o.push(n),n=e.children.slice());!n.length&&o.length;)n=o.pop()};n.length;)t();return a},axe.utils.getSelector=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!e)return\"\";var r=e.getRootNode&&e.getRootNode()||document;if(11!==r.nodeType)return Z(e,t,r);for(var a=[];11===r.nodeType;)a.push({elm:e,doc:r}),r=(e=r.host).getRootNode();return a.push({elm:e,doc:r}),a.reverse().map(function(e){return Z(e.elm,t,e.doc)})},axe.utils.getXpath=function(e){var t=function e(t,r){var a,n;if(!t)return[];if(!r&&9===t.nodeType)return r=[{str:\"html\"}];if(r=r||[],t.parentNode&&t.parentNode!==t&&(r=e(t.parentNode,r)),t.previousSibling){for(n=1,a=t.previousSibling;1===a.nodeType&&a.nodeName===t.nodeName&&n++,a=a.previousSibling;);1===n&&(n=null)}else if(t.nextSibling)for(a=t.nextSibling;a=1===a.nodeType&&a.nodeName===t.nodeName?(n=1,null):(n=null,a.previousSibling););if(1===t.nodeType){var o={};o.str=t.nodeName.toLowerCase();var i=t.getAttribute&&axe.utils.escapeSelector(t.getAttribute(\"id\"));i&&1===t.ownerDocument.querySelectorAll(\"#\"+i).length&&(o.id=t.getAttribute(\"id\")),1<n&&(o.count=n),r.push(o)}return r}(e);return t.reduce(function(e,t){return t.id?\"/\"+t.str+\"[@id='\"+t.id+\"']\":e+\"/\"+t.str+(0<t.count?\"[\"+t.count+\"]\":\"\")},\"\")},axe.utils.injectStyle=function(e){\"use strict\";if(H&&H.parentNode)return void 0===H.styleSheet?H.appendChild(document.createTextNode(e)):H.styleSheet.cssText+=e,H;if(e){var t=document.head||document.getElementsByTagName(\"head\")[0];return(H=document.createElement(\"style\")).type=\"text/css\",void 0===H.styleSheet?H.appendChild(document.createTextNode(e)):H.styleSheet.cssText=e,t.appendChild(H),H}},axe.utils.isHidden=function(e,t){\"use strict\";var r;if(9===e.nodeType)return!1;11===e.nodeType&&(e=e.host);var a=window.getComputedStyle(e,null);return!a||!e.parentNode||\"none\"===a.getPropertyValue(\"display\")||!t&&\"hidden\"===a.getPropertyValue(\"visibility\")||\"true\"===e.getAttribute(\"aria-hidden\")||(r=e.assignedSlot?e.assignedSlot:e.parentNode,axe.utils.isHidden(r,!0))};var Q,ee,te,re,ae=[\"article\",\"aside\",\"blockquote\",\"body\",\"div\",\"footer\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"main\",\"nav\",\"p\",\"section\",\"span\"];axe.utils.isShadowRoot=function(e){var t=e.nodeName.toLowerCase();return!(!e.shadowRoot||!/^[a-z][a-z0-9_.-]*-[a-z0-9_.-]*$/.test(t)&&!ae.includes(t))},axe.utils.isXHTML=function(e){\"use strict\";return!!e.createElement&&\"A\"===e.createElement(\"A\").localName},axe.utils.mergeResults=function(e,l){\"use strict\";var u=[];return e.forEach(function(s){var e,t=(e=s)&&e.results?Array.isArray(e.results)?e.results.length?e.results:null:[e.results]:null;t&&t.length&&t.forEach(function(e){var t,r,a,n,o;e.nodes&&s.frame&&(t=e.nodes,r=l,a=s.frameElement,n=s.frame,o={element:a,selector:n,xpath:axe.utils.getXpath(a)},t.forEach(function(e){e.node=axe.utils.DqElement.fromFrame(e.node,r,o);var t=axe.utils.getAllChecks(e);t.length&&t.forEach(function(e){e.relatedNodes=e.relatedNodes.map(function(e){return axe.utils.DqElement.fromFrame(e,r,o)})})}));var i=axe.utils.findBy(u,\"id\",e.id);i?e.nodes.length&&function(e,t){for(var r,a,n=t[0].node,o=0,i=e.length;o<i;o++)if(a=e[o].node,0<(r=axe.utils.nodeSorter({actualNode:a.element},{actualNode:n.element}))||0===r&&n.selector.length<a.selector.length)return e.splice.apply(e,[o,0].concat(t));e.push.apply(e,t)}(i.nodes,e.nodes):u.push(e)})}),u},axe.utils.nodeSorter=function(e,t){\"use strict\";return e.actualNode===t.actualNode?0:4&e.actualNode.compareDocumentPosition(t.actualNode)?-1:1},utils.performanceTimer=function(){\"use strict\";function e(){if(window.performance&&window.performance)return window.performance.now()}var t=null,r=e();return{start:function(){this.mark(\"mark_axe_start\")},end:function(){this.mark(\"mark_axe_end\"),this.measure(\"axe\",\"mark_axe_start\",\"mark_axe_end\"),this.logMeasures(\"axe\")},auditStart:function(){this.mark(\"mark_audit_start\")},auditEnd:function(){this.mark(\"mark_audit_end\"),this.measure(\"audit_start_to_end\",\"mark_audit_start\",\"mark_audit_end\"),this.logMeasures()},mark:function(e){window.performance&&void 0!==window.performance.mark&&window.performance.mark(e)},measure:function(e,t,r){window.performance&&void 0!==window.performance.measure&&window.performance.measure(e,t,r)},logMeasures:function(e){function t(e){axe.log(\"Measure \"+e.name+\" took \"+e.duration+\"ms\")}if(window.performance&&void 0!==window.performance.getEntriesByType)for(var r=window.performance.getEntriesByType(\"measure\"),a=0;a<r.length;++a){var n=r[a];if(n.name===e)return void t(n);t(n)}},timeElapsed:function(){return e()-r},reset:function(){t||(t=e()),r=e()}}}(),\"function\"!=typeof Object.assign&&(Object.assign=function(e){\"use strict\";if(null==e)throw new TypeError(\"Cannot convert undefined or null to object\");for(var t=Object(e),r=1;r<arguments.length;r++){var a=arguments[r];if(null!=a)for(var n in a)a.hasOwnProperty(n)&&(t[n]=a[n])}return t}),Array.prototype.find||Object.defineProperty(Array.prototype,\"find\",{value:function(e){if(null===this)throw new TypeError(\"Array.prototype.find called on null or undefined\");if(\"function\"!=typeof e)throw new TypeError(\"predicate must be a function\");for(var t,r=Object(this),a=r.length>>>0,n=arguments[1],o=0;o<a;o++)if(t=r[o],e.call(n,t,o,r))return t}}),axe.utils.pollyfillElementsFromPoint=function(){if(document.elementsFromPoint)return document.elementsFromPoint;if(document.msElementsFromPoint)return document.msElementsFromPoint;var e,t=((e=document.createElement(\"x\")).style.cssText=\"pointer-events:auto\",\"auto\"===e.style.pointerEvents),s=t?\"pointer-events\":\"visibility\",l=t?\"none\":\"hidden\",u=document.createElement(\"style\");return u.innerHTML=t?\"* { pointer-events: all }\":\"* { visibility: visible }\",function(e,t){var r,a,n,o=[],i=[];for(document.head.appendChild(u);(r=document.elementFromPoint(e,t))&&-1===o.indexOf(r);)o.push(r),i.push({value:r.style.getPropertyValue(s),priority:r.style.getPropertyPriority(s)}),r.style.setProperty(s,l,\"important\");for(o.indexOf(document.documentElement)<o.length-1&&(o.splice(o.indexOf(document.documentElement),1),o.push(document.documentElement)),a=i.length;n=i[--a];)o[a].style.setProperty(s,n.value?n.value:\"\",n.priority);return document.head.removeChild(u),o}},\"function\"==typeof window.addEventListener&&(document.elementsFromPoint=axe.utils.pollyfillElementsFromPoint()),Array.prototype.includes||Object.defineProperty(Array.prototype,\"includes\",{value:function(e){\"use strict\";var t=Object(this),r=parseInt(t.length,10)||0;if(0===r)return!1;var a,n,o=parseInt(arguments[1],10)||0;for(0<=o?a=o:(a=r+o)<0&&(a=0);a<r;){if(e===(n=t[a])||e!=e&&n!=n)return!0;a++}return!1}}),Array.prototype.some||Object.defineProperty(Array.prototype,\"some\",{value:function(e){\"use strict\";if(null==this)throw new TypeError(\"Array.prototype.some called on null or undefined\");if(\"function\"!=typeof e)throw new TypeError;for(var t=Object(this),r=t.length>>>0,a=2<=arguments.length?arguments[1]:void 0,n=0;n<r;n++)if(n in t&&e.call(a,t[n],n,t))return!0;return!1}}),Array.from||Object.defineProperty(Array,\"from\",{value:(Q=Object.prototype.toString,ee=function(e){return\"function\"==typeof e||\"[object Function]\"===Q.call(e)},te=Math.pow(2,53)-1,re=function(e){var t,r=(t=Number(e),isNaN(t)?0:0!==t&&isFinite(t)?(0<t?1:-1)*Math.floor(Math.abs(t)):t);return Math.min(Math.max(r,0),te)},function(e){var t=Object(e);if(null==e)throw new TypeError(\"Array.from requires an array-like object - not null or undefined\");var r,a=1<arguments.length?arguments[1]:void 0;if(void 0!==a){if(!ee(a))throw new TypeError(\"Array.from: when provided, the second argument must be a function\");2<arguments.length&&(r=arguments[2])}for(var n,o=re(t.length),i=ee(this)?Object(new this(o)):new Array(o),s=0;s<o;)n=t[s],i[s]=a?void 0===r?a(n,s):a.call(r,n,s):n,s+=1;return i.length=o,i})}),String.prototype.includes||(String.prototype.includes=function(e,t){return\"number\"!=typeof t&&(t=0),!(t+e.length>this.length)&&-1!==this.indexOf(e,t)}),axe.utils.preloadCssom=function(e){var t,r,a=e.timeout,n=e.treeRoot,o=void 0===n?axe._tree[0]:n,i=axe.utils.uniqueArray((t=o,r=[],axe.utils.querySelectorAllFilter(t,\"*\",function(e){return!r.includes(e.shadowId)&&(r.push(e.shadowId),!0)}).map(function(e){return{shadowId:e.shadowId,root:axe.utils.getRootNode(e.actualNode)}})),[]),s=axe.utils.queue();if(!i.length)return s;var l=document.implementation.createHTMLDocument();function u(e){var t=e.data,r=e.isExternal,a=e.shadowId,n=e.root,o=l.createElement(\"style\");return o.type=\"text/css\",o.appendChild(l.createTextNode(t)),l.head.appendChild(o),{sheet:o.sheet,isExternal:r,shadowId:a,root:n}}return s.defer(function(t,e){i.reduce(function(e,r){return e.defer(function(e,t){(function(e,n,o){var i=e.root,s=e.shadowId;function l(e){var a=e.resolve,t=e.reject,r=e.url;axe.imports.axios({method:\"get\",url:r,timeout:n}).then(function(e){var t=e.data,r=o({data:t,isExternal:!0,shadowId:s,root:i});a(r)}).catch(t)}var u=axe.utils.queue(),t=i.styleSheets?Array.from(i.styleSheets):null;if(!t)return u;var r=[];return t.filter(function(e){var t=!1;return e.href&&(r.includes(e.href)?t=!0:r.push(e.href)),!Array.from(e.media).includes(\"print\")&&!t}).forEach(function(r){try{var e=r.cssRules,t=Array.from(e),a=t.filter(function(e){return e.href});if(!a.length)return void u.defer(function(e){return e({sheet:r,isExternal:!1,shadowId:s,root:i})});a.forEach(function(r){u.defer(function(e,t){l({resolve:e,reject:t,url:r.href})})});var n=t.filter(function(e){return!e.href}).reduce(function(e,t){return e.push(t.cssText),e},[]).join();u.defer(function(e){return e(o({data:n,shadowId:s,root:i,isExternal:!1}))})}catch(e){u.defer(function(e,t){l({resolve:e,reject:t,url:r.href})})}},[]),u})(r,a,u).then(e).catch(t)}),e},axe.utils.queue()).then(function(e){t(e.reduce(function(e,t){return e.concat(t)},[]))}).catch(e)}),s};T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};axe.utils.shouldPreload=function(e){return!(!e||!e.preload)&&(\"boolean\"==typeof e.preload?e.preload:\"object\"===(void 0===(t=e.preload)?\"undefined\":T(t))&&Array.isArray(t.assets));var t},axe.utils.getPreloadConfig=function(e){var t={assets:axe.constants.preloadAssets,timeout:axe.constants.preloadAssetsTimeout};if(\"boolean\"==typeof e.preload)return t;if(!e.preload.assets.every(function(e){return axe.constants.preloadAssets.includes(e.toLowerCase())}))throw new Error(\"Requested assets, not supported. Supported assets are: \"+axe.constants.preloadAssets.join(\", \")+\".\");return t.assets=axe.utils.uniqueArray(e.preload.assets.map(function(e){return e.toLowerCase()}),[]),e.preload.timeout&&\"number\"==typeof e.preload.timeout&&!Number.isNaN(e.preload.timeout)&&(t.timeout=e.preload.timeout),t},axe.utils.preload=function(e){var t={cssom:axe.utils.preloadCssom},r=axe.utils.queue();if(!axe.utils.shouldPreload(e))return r;var a=axe.utils.getPreloadConfig(e);return a.assets.forEach(function(o){r.defer(function(n,e){t[o](a).then(function(e){var t,r,a;n((t={},r=o,a=e[0],r in t?Object.defineProperty(t,r,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[r]=a,t))}).catch(e)})}),r};T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function ne(n,o){\"use strict\";return function(e){var t=n[e.id]||{},r=t.messages||{},a=Object.assign({},t);delete a.messages,void 0===e.result?\"object\"===T(r.incomplete)?a.message=function(){return function(t,r){function a(e){return e.incomplete&&e.incomplete.default?e.incomplete.default:i.incompleteFallbackMessage()}if(!t||!t.missingData)return a(r);try{var e=r.incomplete[t.missingData[0].reason];if(!e)throw new Error;return e}catch(e){return\"string\"==typeof t.missingData?r.incomplete[t.missingData]:a(r)}}(e.data,r)}:a.message=r.incomplete:a.message=e.result===o?r.pass:r.fail,axe.utils.extendMetaData(e,a)}}axe.utils.publishMetaData=function(e){\"use strict\";var t=axe._audit.data.checks||{},r=axe._audit.data.rules||{},a=axe.utils.findBy(axe._audit.rules,\"id\",e.id)||{};e.tags=axe.utils.clone(a.tags||[]);var n=ne(t,!0),o=ne(t,!1);e.nodes.forEach(function(e){e.any.forEach(n),e.all.forEach(n),e.none.forEach(o)}),axe.utils.extendMetaData(e,axe.utils.clone(r[e.id]||{}))};var oe=function(){},ie=function(){};var se,le=(se=/(?=[\\-\\[\\]{}()*+?.\\\\\\^$|,#\\s])/g,function(e){return e.replace(se,\"\\\\\")}),ue=/\\\\/g;function ce(e){if(e)return e.map(function(e){var t,r,a=e.name.replace(ue,\"\"),n=(e.value||\"\").replace(ue,\"\");switch(e.operator){case\"^=\":r=new RegExp(\"^\"+le(n));break;case\"$=\":r=new RegExp(le(n)+\"$\");break;case\"~=\":r=new RegExp(\"(^|\\\\s)\"+le(n)+\"(\\\\s|$)\");break;case\"|=\":r=new RegExp(\"^\"+le(n)+\"(-|$)\");break;case\"=\":t=function(e){return n===e};break;case\"*=\":t=function(e){return e&&e.includes(n)};break;case\"!=\":t=function(e){return n!==e};break;default:t=function(e){return!!e}}return\"\"===n&&/^[*$^]=$/.test(e.operator)&&(t=function(){return!1}),t||(t=function(e){return e&&r.test(e)}),{key:a,value:n,test:t}})}function de(e){if(e)return e.map(function(e){return{value:e=e.replace(ue,\"\"),regexp:new RegExp(\"(^|\\\\s)\"+le(e)+\"(\\\\s|$)\")}})}function me(e){if(e)return e.map(function(e){var t;return\"not\"===e.name&&(t=(t=axe.utils.cssParser.parse(e.value)).selectors?t.selectors:[t],t=oe(t)),{name:e.name,expressions:t,value:e.value}})}function pe(e,t,r,a){var n={nodes:e.slice(),anyLevel:t,thisLevel:r,parentShadowId:a};return n.nodes.reverse(),n}function fe(e,t){return c=e.actualNode,d=t[0],1===c.nodeType&&(\"*\"===d.tag||c.nodeName.toLowerCase()===d.tag)&&(l=e.actualNode,!(u=t[0]).classes||u.classes.reduce(function(e,t){return e&&l.className&&l.className.match(t.regexp)},!0))&&(i=e.actualNode,!(s=t[0]).attributes||s.attributes.reduce(function(e,t){var r=i.getAttribute(t.key);return e&&null!==r&&(!t.value||t.test(r))},!0))&&(n=e.actualNode,!(o=t[0]).id||n.id===o.id)&&(r=e,!((a=t[0]).pseudos&&!a.pseudos.reduce(function(e,t){if(\"not\"===t.name)return e&&!ie([r],t.expressions,!1).length;throw new Error(\"the pseudo selector \"+t.name+\" has not yet been implemented\")},!0)));var r,a,n,o,i,s,l,u,c,d}oe=function(e){return e.map(function(e){for(var t=[],r=e.rule;r;)t.push({tag:r.tagName?r.tagName.toLowerCase():\"*\",combinator:r.nestingOperator?r.nestingOperator:\" \",id:r.id,attributes:ce(r.attrs),classes:de(r.classNames),pseudos:me(r.pseudos)}),r=r.rule;return t})},ie=function(e,t,r,a){for(var n=[],o=pe(Array.isArray(e)?e:[e],t,[],e[0].shadowId),i=[];o.nodes.length;){for(var s=o.nodes.pop(),l=[],u=[],c=o.anyLevel.slice().concat(o.thisLevel),d=!1,m=0;m<c.length;m++){var p=c[m];if(fe(s,p)&&(!p[0].id||s.shadowId===o.parentShadowId))if(1===p.length)d||a&&!a(s)||(i.push(s),d=!0);else{var f=p.slice(1);if(!1===[\" \",\">\"].includes(f[0].combinator))throw new Error(\"axe.utils.querySelectorAll does not support the combinator: \"+p[1].combinator);\">\"===f[0].combinator?l.push(f):u.push(f)}!o.anyLevel.includes(p)||p[0].id&&s.shadowId!==o.parentShadowId||u.push(p)}for(s.children&&s.children.length&&r&&(n.push(o),o=pe(s.children,u,l,s.shadowId));!o.nodes.length&&n.length;)o=n.pop()}return i},axe.utils.querySelectorAll=function(e,t){return axe.utils.querySelectorAllFilter(e,t)},axe.utils.querySelectorAllFilter=function(e,t,r){e=Array.isArray(e)?e:[e];var a=axe.utils.cssParser.parse(t);return a=a.selectors?a.selectors:[a],a=oe(a),ie(e,a,!0,r)};T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};!function(){\"use strict\";function m(){}function p(e){if(\"function\"!=typeof e)throw new TypeError(\"Queue methods require functions as arguments\")}axe.utils.queue=function(){var t,a=[],n=0,o=0,r=m,i=!1,s=function(e){t=e,setTimeout(function(){null!=t&&axe.log(\"Uncaught error (of queue)\",t)},1)},l=s;function u(t){return function(e){a[t]=e,(o-=1)||r===m||(i=!0,r(a))}}function c(e){return r=m,l(e),a}var d={defer:function(e){if(\"object\"===(void 0===e?\"undefined\":T(e))&&e.then&&e.catch){var r=e;e=function(e,t){r.then(e).catch(t)}}if(p(e),void 0===t){if(i)throw new Error(\"Queue already completed\");return a.push(e),++o,function(){for(var e=a.length;n<e;n++){var t=a[n];try{t.call(null,u(n),c)}catch(e){c(e)}}}(),d}},then:function(e){if(p(e),r!==m)throw new Error(\"queue `then` already set\");return t||(r=e,o||(i=!0,r(a))),d},catch:function(e){if(p(e),l!==s)throw new Error(\"queue `catch` already set\");return t?(e(t),t=null):l=e,d},abort:c};return d}}();var he;T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function ge(t,e){\"use strict\";var r,a,n=axe._audit&&axe._audit.tagExclude?axe._audit.tagExclude:[];return a=e.hasOwnProperty(\"include\")||e.hasOwnProperty(\"exclude\")?(r=e.include||[],r=Array.isArray(r)?r:[r],a=e.exclude||[],(a=Array.isArray(a)?a:[a]).concat(n.filter(function(e){return-1===r.indexOf(e)}))):(r=Array.isArray(e)?e:[e],n.filter(function(e){return-1===r.indexOf(e)})),!!(r.some(function(e){return-1!==t.tags.indexOf(e)})||0===r.length&&!1!==t.enabled)&&a.every(function(e){return-1===t.tags.indexOf(e)})}function be(e){return Array.from(e.children).reduce(function(e,t){var r=function(e){var t=window.getComputedStyle(e),r=\"visible\"===t.getPropertyValue(\"overflow-y\"),a=\"visible\"===t.getPropertyValue(\"overflow-x\");if(!r&&e.scrollHeight>e.clientHeight||!a&&e.scrollWidth>e.clientWidth)return{elm:e,top:e.scrollTop,left:e.scrollLeft}}(t);return r&&e.push(r),e.concat(be(t))},[])}function ye(e){\"use strict\";return e.sort(function(e,t){return axe.utils.contains(e,t)?1:-1})[0]}function ve(t,e){\"use strict\";var r=e.include&&ye(e.include.filter(function(e){return axe.utils.contains(e,t)})),a=e.exclude&&ye(e.exclude.filter(function(e){return axe.utils.contains(e,t)}));return!!(!a&&r||a&&axe.utils.contains(a,r))}function we(e,t){\"use strict\";var r;if(0===e.length)return t;e.length<t.length&&(r=e,e=t,t=r);for(var a=0,n=t.length;a<n;a++)e.includes(t[a])||e.push(t[a]);return e}!function(e){\"use strict\";var l={},i={},s=Object.freeze([\"EvalError\",\"RangeError\",\"ReferenceError\",\"SyntaxError\",\"TypeError\",\"URIError\"]);function u(){var e=\"axeAPI\",t=\"\";return void 0!==axe&&axe._audit&&axe._audit.application&&(e=axe._audit.application),void 0!==axe&&(t=axe.version),e+\".\"+t}function c(e,t,r,a,n,o){var i;r instanceof Error&&(i={name:r.name,message:r.message,stack:r.stack},r=void 0);var s={uuid:a,topic:t,message:r,error:i,_respondable:!0,_source:u(),_keepalive:n};\"function\"==typeof o&&(l[a]=o),e.postMessage(JSON.stringify(s),\"*\")}function t(e,t,r,a,n){c(e,t,r,he.v1(),a,n)}function d(a,n,o){return function(e,t,r){c(a,n,e,o,t,r)}}function o(e){var t;if(\"string\"==typeof e){try{t=JSON.parse(e)}catch(e){}var r,a,n,o;if(function(e){if(\"object\"!==(void 0===e?\"undefined\":T(e))||\"string\"!=typeof e.uuid||!0!==e._respondable)return!1;var t=u();return e._source===t||\"axeAPI.x.y.z\"===e._source||\"axeAPI.x.y.z\"===t}(t))return\"object\"===T(t.error)?t.error=(r=t.error,a=r.message||\"Unknown error occurred\",n=s.includes(r.name)?r.name:\"Error\",o=window[n]||Error,r.stack&&(a+=\"\\n\"+r.stack.replace(r.message,\"\")),new o(a)):t.error=void 0,t}}t.subscribe=function(e,t){i[e]=t},t.isInFrame=function(e){return!!(e=e||window).frameElement},\"function\"==typeof window.addEventListener&&window.addEventListener(\"message\",function(t){var r=o(t.data);if(r){var a=r.uuid,e=r._keepalive,n=l[a];if(n)n(r.error||r.message,e,d(t.source,r.topic,a)),e||delete l[a];if(!r.error)try{!function(e,t,r){var a=t.topic,n=i[a];if(n){var o=d(e,null,t.uuid);n(t.message,r,o)}}(t.source,r,e)}catch(e){c(t.source,r.topic,e,a,!1)}}},!1),e.respondable=t}(utils),axe.utils.ruleShouldRun=function(e,t,r){\"use strict\";var a=r.runOnly||{},n=(r.rules||{})[e.id];return!(e.pageLevel&&!t.page)&&(\"rule\"===a.type?-1!==a.values.indexOf(e.id):n&&\"boolean\"==typeof n.enabled?n.enabled:\"tag\"===a.type&&a.values?ge(e,a.values):ge(e,[]))},axe.utils.getScrollState=function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:window,t=e.document.documentElement;return[void 0!==e.pageXOffset?{elm:e,top:e.pageYOffset,left:e.pageXOffset}:{elm:t,top:t.scrollTop,left:t.scrollLeft}].concat(be(document.body))},axe.utils.setScrollState=function(e){e.forEach(function(e){return function(e,t,r){if(e===window)return e.scroll(t,r);e.scrollTop=t,e.scrollLeft=r}(e.elm,e.top,e.left)})},axe.utils.select=function(e,t){\"use strict\";var r,a=[];if(axe._selectCache)for(var n=0,o=axe._selectCache.length;n<o;n++){var i=axe._selectCache[n];if(i.selector===e)return i.result}for(var s,l=(s=t,function(e){return ve(e,s)}),u=t.include.reduce(function(e,t){return e.length&&e[e.length-1].actualNode.contains(t.actualNode)||e.push(t),e},[]),c=0;c<u.length;c++)(r=u[c]).actualNode.nodeType===r.actualNode.ELEMENT_NODE&&axe.utils.matchesSelector(r.actualNode,e)&&l(r)&&(a=we(a,[r])),a=we(a,axe.utils.querySelectorAllFilter(r,e,l));return axe._selectCache&&axe._selectCache.push({selector:e,result:a}),a},axe.utils.toArray=function(e){\"use strict\";return Array.prototype.slice.call(e)},axe.utils.uniqueArray=function(e,t){return e.concat(t).filter(function(e,t,r){return r.indexOf(e)===t})},function(e){var i,t=e.crypto||e.msCrypto;if(!i&&t&&t.getRandomValues){var r=new Uint8Array(16);i=function(){return t.getRandomValues(r),r}}if(!i){var a=new Array(16);i=function(){for(var e,t=0;t<16;t++)0==(3&t)&&(e=4294967296*Math.random()),a[t]=e>>>((3&t)<<3)&255;return a}}for(var s=\"function\"==typeof e.Buffer?e.Buffer:Array,n=[],o={},l=0;l<256;l++)n[l]=(l+256).toString(16).substr(1),o[n[l]]=l;function p(e,t){var r=t||0,a=n;return a[e[r++]]+a[e[r++]]+a[e[r++]]+a[e[r++]]+\"-\"+a[e[r++]]+a[e[r++]]+\"-\"+a[e[r++]]+a[e[r++]]+\"-\"+a[e[r++]]+a[e[r++]]+\"-\"+a[e[r++]]+a[e[r++]]+a[e[r++]]+a[e[r++]]+a[e[r++]]+a[e[r++]]}var u=i(),f=[1|u[0],u[1],u[2],u[3],u[4],u[5]],h=16383&(u[6]<<8|u[7]),g=0,b=0;function c(e,t,r){var a=t&&r||0;\"string\"==typeof e&&(t=\"binary\"==e?new s(16):null,e=null);var n=(e=e||{}).random||(e.rng||i)();if(n[6]=15&n[6]|64,n[8]=63&n[8]|128,t)for(var o=0;o<16;o++)t[a+o]=n[o];return t||p(n)}(he=c).v1=function(e,t,r){var a=t&&r||0,n=t||[],o=null!=(e=e||{}).clockseq?e.clockseq:h,i=null!=e.msecs?e.msecs:(new Date).getTime(),s=null!=e.nsecs?e.nsecs:b+1,l=i-g+(s-b)/1e4;if(l<0&&null==e.clockseq&&(o=o+1&16383),(l<0||g<i)&&null==e.nsecs&&(s=0),1e4<=s)throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");g=i,h=o;var u=(1e4*(268435455&(i+=122192928e5))+(b=s))%4294967296;n[a++]=u>>>24&255,n[a++]=u>>>16&255,n[a++]=u>>>8&255,n[a++]=255&u;var c=i/4294967296*1e4&268435455;n[a++]=c>>>8&255,n[a++]=255&c,n[a++]=c>>>24&15|16,n[a++]=c>>>16&255,n[a++]=o>>>8|128,n[a++]=255&o;for(var d=e.node||f,m=0;m<6;m++)n[a+m]=d[m];return t||p(n)},he.v4=c,he.parse=function(e,t,r){var a=t&&r||0,n=0;for(t=t||[],e.toLowerCase().replace(/[0-9a-f]{2}/g,function(e){n<16&&(t[a+n++]=o[e])});n<16;)t[a+n++]=0;return t},he.unparse=p,he.BufferClass=s}(window);T=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};axe._load({data:{rules:{accesskeys:{description:\"Ensures every accesskey attribute value is unique\",help:\"accesskey attribute value must be unique\"},\"area-alt\":{description:\"Ensures <area> elements of image maps have alternate text\",help:\"Active <area> elements must have alternate text\"},\"aria-allowed-attr\":{description:\"Ensures ARIA attributes are allowed for an element's role\",help:\"Elements must only use allowed ARIA attributes\"},\"aria-allowed-role\":{description:\"Ensures role attribute has an appropriate value for the element\",help:\"ARIA role must be appropriate for the element\"},\"aria-dpub-role-fallback\":{description:\"Ensures unsupported DPUB roles are only used on elements with implicit fallback roles\",help:\"Unsupported DPUB ARIA roles should be used on elements with implicit fallback roles\"},\"aria-hidden-body\":{description:\"Ensures aria-hidden='true' is not present on the document body.\",help:\"aria-hidden='true' must not be present on the document body\"},\"aria-required-attr\":{description:\"Ensures elements with ARIA roles have all required ARIA attributes\",help:\"Required ARIA attributes must be provided\"},\"aria-required-children\":{description:\"Ensures elements with an ARIA role that require child roles contain them\",help:\"Certain ARIA roles must contain particular children\"},\"aria-required-parent\":{description:\"Ensures elements with an ARIA role that require parent roles are contained by them\",help:\"Certain ARIA roles must be contained by particular parents\"},\"aria-roles\":{description:\"Ensures all elements with a role attribute use a valid value\",help:\"ARIA roles used must conform to valid values\"},\"aria-valid-attr-value\":{description:\"Ensures all ARIA attributes have valid values\",help:\"ARIA attributes must conform to valid values\"},\"aria-valid-attr\":{description:\"Ensures attributes that begin with aria- are valid ARIA attributes\",help:\"ARIA attributes must conform to valid names\"},\"audio-caption\":{description:\"Ensures <audio> elements have captions\",help:\"<audio> elements must have a captions track\"},\"autocomplete-valid\":{description:\"Ensure the autocomplete attribute is correct and suitable for the form field\",help:\"autocomplete attribute must be used correctly\"},blink:{description:\"Ensures <blink> elements are not used\",help:\"<blink> elements are deprecated and must not be used\"},\"button-name\":{description:\"Ensures buttons have discernible text\",help:\"Buttons must have discernible text\"},bypass:{description:\"Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content\",help:\"Page must have means to bypass repeated blocks\"},checkboxgroup:{description:'Ensures related <input type=\"checkbox\"> elements have a group and that the group designation is consistent',help:\"Checkbox inputs with the same name attribute value must be part of a group\"},\"color-contrast\":{description:\"Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds\",help:\"Elements must have sufficient color contrast\"},\"css-orientation-lock\":{description:\"Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations\",help:\"CSS Media queries are not used to lock display orientation\"},\"definition-list\":{description:\"Ensures <dl> elements are structured correctly\",help:\"<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script> or <template> elements\"},dlitem:{description:\"Ensures <dt> and <dd> elements are contained by a <dl>\",help:\"<dt> and <dd> elements must be contained by a <dl>\"},\"document-title\":{description:\"Ensures each HTML document contains a non-empty <title> element\",help:\"Documents must have <title> element to aid in navigation\"},\"duplicate-id-active\":{description:\"Ensures every id attribute value of active elements is unique\",help:\"IDs of active elements must be unique\"},\"duplicate-id-aria\":{description:\"Ensures every id attribute value used in ARIA and in labels is unique\",help:\"IDs used in ARIA and labels must be unique\"},\"duplicate-id\":{description:\"Ensures every id attribute value is unique\",help:\"id attribute value must be unique\"},\"empty-heading\":{description:\"Ensures headings have discernible text\",help:\"Headings must not be empty\"},\"focus-order-semantics\":{description:\"Ensures elements in the focus order have an appropriate role\",help:\"Elements in the focus order need a role appropriate for interactive content\"},\"frame-tested\":{description:\"Ensures <iframe> and <frame> elements contain the axe-core script\",help:\"Frames must be tested with axe-core\"},\"frame-title-unique\":{description:\"Ensures <iframe> and <frame> elements contain a unique title attribute\",help:\"Frames must have a unique title attribute\"},\"frame-title\":{description:\"Ensures <iframe> and <frame> elements contain a non-empty title attribute\",help:\"Frames must have title attribute\"},\"heading-order\":{description:\"Ensures the order of headings is semantically correct\",help:\"Heading levels should only increase by one\"},\"hidden-content\":{description:\"Informs users about hidden content.\",help:\"Hidden content on the page cannot be analyzed\"},\"html-has-lang\":{description:\"Ensures every HTML document has a lang attribute\",help:\"<html> element must have a lang attribute\"},\"html-lang-valid\":{description:\"Ensures the lang attribute of the <html> element has a valid value\",help:\"<html> element must have a valid value for the lang attribute\"},\"html-xml-lang-mismatch\":{description:\"Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page\",help:\"HTML elements with lang and xml:lang must have the same base language\"},\"image-alt\":{description:\"Ensures <img> elements have alternate text or a role of none or presentation\",help:\"Images must have alternate text\"},\"image-redundant-alt\":{description:\"Ensure button and link text is not repeated as image alternative\",help:\"Text of buttons and links should not be repeated in the image alternative\"},\"input-image-alt\":{description:'Ensures <input type=\"image\"> elements have alternate text',help:\"Image buttons must have alternate text\"},\"label-title-only\":{description:\"Ensures that every form element is not solely labeled using the title or aria-describedby attributes\",help:\"Form elements should have a visible label\"},label:{description:\"Ensures every form element has a label\",help:\"Form elements must have labels\"},\"landmark-banner-is-top-level\":{description:\"Ensures the banner landmark is at top level\",help:\"Banner landmark must not be contained in another landmark\"},\"landmark-contentinfo-is-top-level\":{description:\"Ensures the contentinfo landmark is at top level\",help:\"Contentinfo landmark must not be contained in another landmark\"},\"landmark-main-is-top-level\":{description:\"Ensures the main landmark is at top level\",help:\"Main landmark must not be contained in another landmark\"},\"landmark-no-duplicate-banner\":{description:\"Ensures the page has at most one banner landmark\",help:\"Page must not have more than one banner landmark\"},\"landmark-no-duplicate-contentinfo\":{description:\"Ensures the page has at most one contentinfo landmark\",help:\"Page must not have more than one contentinfo landmark\"},\"landmark-one-main\":{description:\"Ensures the page has only one main landmark and each iframe in the page has at most one main landmark\",help:\"Page must have one main landmark\"},\"layout-table\":{description:\"Ensures presentational <table> elements do not use <th>, <caption> elements or the summary attribute\",help:\"Layout tables must not use data table elements\"},\"link-in-text-block\":{description:\"Links can be distinguished without relying on color\",help:\"Links must be distinguished from surrounding text in a way that does not rely on color\"},\"link-name\":{description:\"Ensures links have discernible text\",help:\"Links must have discernible text\"},list:{description:\"Ensures that lists are structured correctly\",help:\"<ul> and <ol> must only directly contain <li>, <script> or <template> elements\"},listitem:{description:\"Ensures <li> elements are used semantically\",help:\"<li> elements must be contained in a <ul> or <ol>\"},marquee:{description:\"Ensures <marquee> elements are not used\",help:\"<marquee> elements are deprecated and must not be used\"},\"meta-refresh\":{description:'Ensures <meta http-equiv=\"refresh\"> is not used',help:\"Timed refresh must not exist\"},\"meta-viewport-large\":{description:'Ensures <meta name=\"viewport\"> can scale a significant amount',help:\"Users should be able to zoom and scale the text up to 500%\"},\"meta-viewport\":{description:'Ensures <meta name=\"viewport\"> does not disable text scaling and zooming',help:\"Zooming and scaling must not be disabled\"},\"object-alt\":{description:\"Ensures <object> elements have alternate text\",help:\"<object> elements must have alternate text\"},\"p-as-heading\":{description:\"Ensure p elements are not used to style headings\",help:\"Bold, italic text and font-size are not used to style p elements as a heading\"},\"page-has-heading-one\":{description:\"Ensure that the page, or at least one of its frames contains a level-one heading\",help:\"Page must contain a level-one heading\"},radiogroup:{description:'Ensures related <input type=\"radio\"> elements have a group and that the group designation is consistent',help:\"Radio inputs with the same name attribute value must be part of a group\"},region:{description:\"Ensures all page content is contained by landmarks\",help:\"All page content must be contained by landmarks\"},\"scope-attr-valid\":{description:\"Ensures the scope attribute is used correctly on tables\",help:\"scope attribute should be used correctly\"},\"server-side-image-map\":{description:\"Ensures that server-side image maps are not used\",help:\"Server-side image maps must not be used\"},\"skip-link\":{description:\"Ensure all skip links have a focusable target\",help:\"The skip-link target should exist and be focusable\"},tabindex:{description:\"Ensures tabindex attribute values are not greater than 0\",help:\"Elements should not have tabindex greater than zero\"},\"table-duplicate-name\":{description:\"Ensure that tables do not have the same summary and caption\",help:\"The <caption> element should not contain the same text as the summary attribute\"},\"table-fake-caption\":{description:\"Ensure that tables with a caption use the <caption> element.\",help:\"Data or header cells should not be used to give caption to a data table.\"},\"td-has-header\":{description:\"Ensure that each non-empty data cell in a large table has one or more table headers\",help:\"All non-empty td element in table larger than 3 by 3 must have an associated table header\"},\"td-headers-attr\":{description:\"Ensure that each cell in a table using the headers refers to another cell in that table\",help:\"All cells in a table element that use the headers attribute must only refer to other cells of that same table\"},\"th-has-data-cells\":{description:\"Ensure that each table header in a data table refers to data cells\",help:\"All th elements and elements with role=columnheader/rowheader must have data cells they describe\"},\"valid-lang\":{description:\"Ensures lang attributes have valid values\",help:\"lang attribute must have a valid value\"},\"video-caption\":{description:\"Ensures <video> elements have captions\",help:\"<video> elements must have captions\"},\"video-description\":{description:\"Ensures <video> elements have audio descriptions\",help:\"<video> elements must have an audio description track\"}},checks:{accesskeys:{impact:\"serious\",messages:{pass:function(e){return\"Accesskey attribute value is unique\"},fail:function(e){return\"Document has multiple elements with the same accesskey\"}}},\"non-empty-alt\":{impact:\"critical\",messages:{pass:function(e){return\"Element has a non-empty alt attribute\"},fail:function(e){return\"Element has no alt attribute or the alt attribute is empty\"}}},\"non-empty-title\":{impact:\"serious\",messages:{pass:function(e){return\"Element has a title attribute\"},fail:function(e){return\"Element has no title attribute or the title attribute is empty\"}}},\"aria-label\":{impact:\"serious\",messages:{pass:function(e){return\"aria-label attribute exists and is not empty\"},fail:function(e){return\"aria-label attribute does not exist or is empty\"}}},\"aria-labelledby\":{impact:\"serious\",messages:{pass:function(e){return\"aria-labelledby attribute exists and references elements that are visible to screen readers\"},fail:function(e){return\"aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty\"}}},\"aria-allowed-attr\":{impact:\"critical\",messages:{pass:function(e){return\"ARIA attributes are used correctly for the defined role\"},fail:function(e){var t=\"ARIA attribute\"+(e.data&&1<e.data.length?\"s are\":\" is\")+\" not allowed:\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t}}},\"aria-allowed-role\":{impact:\"minor\",messages:{pass:function(e){return\"ARIA role is allowed for given element\"},fail:function(e){return\"role\"+(e.data&&1<e.data.length?\"s\":\"\")+\" \"+e.data.join(\", \")+\" \"+(e.data&&1<e.data.length?\"are\":\" is\")+\" not allowed for given element\"}}},\"implicit-role-fallback\":{impact:\"moderate\",messages:{pass:function(e){return\"Element’s implicit ARIA role is an appropriate fallback\"},fail:function(e){return\"Element’s implicit ARIA role is not a good fallback for the (unsupported) role\"}}},\"aria-hidden-body\":{impact:\"critical\",messages:{pass:function(e){return\"No aria-hidden attribute is present on document body\"},fail:function(e){return\"aria-hidden=true should not be present on the document body\"}}},\"aria-required-attr\":{impact:\"critical\",messages:{pass:function(e){return\"All required ARIA attributes are present\"},fail:function(e){var t=\"Required ARIA attribute\"+(e.data&&1<e.data.length?\"s\":\"\")+\" not present:\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t}}},\"aria-required-children\":{impact:\"critical\",messages:{pass:function(e){return\"Required ARIA children are present\"},fail:function(e){var t=\"Required ARIA \"+(e.data&&1<e.data.length?\"children\":\"child\")+\" role not present:\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t},incomplete:function(e){var t=\"Expecting ARIA \"+(e.data&&1<e.data.length?\"children\":\"child\")+\" role to be added:\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t}}},\"aria-required-parent\":{impact:\"critical\",messages:{pass:function(e){return\"Required ARIA parent role present\"},fail:function(e){var t=\"Required ARIA parent\"+(e.data&&1<e.data.length?\"s\":\"\")+\" role not present:\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t}}},invalidrole:{impact:\"critical\",messages:{pass:function(e){return\"ARIA role is valid\"},fail:function(e){return\"Role must be one of the valid ARIA roles\"}}},abstractrole:{impact:\"serious\",messages:{pass:function(e){return\"Abstract roles are not used\"},fail:function(e){return\"Abstract roles cannot be directly used\"}}},unsupportedrole:{impact:\"critical\",messages:{pass:function(e){return\"ARIA role is supported\"},fail:function(e){return\"The role used is not widely supported in assistive technologies\"}}},\"aria-valid-attr-value\":{impact:\"critical\",messages:{pass:function(e){return\"ARIA attribute values are valid\"},fail:function(e){var t=\"Invalid ARIA attribute value\"+(e.data&&1<e.data.length?\"s\":\"\")+\":\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t}}},\"aria-errormessage\":{impact:\"critical\",messages:{pass:function(e){return\"Uses a supported aria-errormessage technique\"},fail:function(e){var t=\"aria-errormessage value\"+(e.data&&1<e.data.length?\"s\":\"\")+\" \",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" `\"+r[a+=1];return t+=\"` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)\"}}},\"aria-valid-attr\":{impact:\"critical\",messages:{pass:function(e){return\"ARIA attribute name\"+(e.data&&1<e.data.length?\"s\":\"\")+\" are valid\"},fail:function(e){var t=\"Invalid ARIA attribute name\"+(e.data&&1<e.data.length?\"s\":\"\")+\":\",r=e.data;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\" \"+r[a+=1];return t}}},caption:{impact:\"critical\",messages:{pass:function(e){return\"The multimedia element has a captions track\"},incomplete:function(e){return\"Check that captions is available for the element\"}}},\"autocomplete-valid\":{impact:\"serious\",messages:{pass:function(e){return\"the autocomplete attribute is correctly formatted\"},fail:function(e){return\"the autocomplete attribute is incorrectly formatted\"}}},\"autocomplete-appropriate\":{impact:\"serious\",messages:{pass:function(e){return\"the autocomplete value is on an appropriate element\"},fail:function(e){return\"the autocomplete value is inappropriate for this type of input\"}}},\"is-on-screen\":{impact:\"serious\",messages:{pass:function(e){return\"Element is not visible\"},fail:function(e){return\"Element is visible\"}}},\"non-empty-if-present\":{impact:\"critical\",messages:{pass:function(e){var t=\"Element \";return e.data?t+=\"has a non-empty value attribute\":t+=\"does not have a value attribute\",t},fail:function(e){return\"Element has a value attribute and the value attribute is empty\"}}},\"non-empty-value\":{impact:\"critical\",messages:{pass:function(e){return\"Element has a non-empty value attribute\"},fail:function(e){return\"Element has no value attribute or the value attribute is empty\"}}},\"button-has-visible-text\":{impact:\"critical\",messages:{pass:function(e){return\"Element has inner text that is visible to screen readers\"},fail:function(e){return\"Element does not have inner text that is visible to screen readers\"}}},\"role-presentation\":{impact:\"minor\",messages:{pass:function(e){return'Element\\'s default semantics were overriden with role=\"presentation\"'},fail:function(e){return'Element\\'s default semantics were not overridden with role=\"presentation\"'}}},\"role-none\":{impact:\"minor\",messages:{pass:function(e){return'Element\\'s default semantics were overriden with role=\"none\"'},fail:function(e){return'Element\\'s default semantics were not overridden with role=\"none\"'}}},\"focusable-no-name\":{impact:\"serious\",messages:{pass:function(e){return\"Element is not in tab order or has accessible text\"},fail:function(e){return\"Element is in tab order and does not have accessible text\"}}},\"internal-link-present\":{impact:\"serious\",messages:{pass:function(e){return\"Valid skip link found\"},fail:function(e){return\"No valid skip link found\"}}},\"header-present\":{impact:\"serious\",messages:{pass:function(e){return\"Page has a header\"},fail:function(e){return\"Page does not have a header\"}}},landmark:{impact:\"serious\",messages:{pass:function(e){return\"Page has a landmark region\"},fail:function(e){return\"Page does not have a landmark region\"}}},\"group-labelledby\":{impact:\"critical\",messages:{pass:function(e){return'All elements with the name \"'+e.data.name+'\" reference the same element with aria-labelledby'},fail:function(e){return'All elements with the name \"'+e.data.name+'\" do not reference the same element with aria-labelledby'}}},fieldset:{impact:\"critical\",messages:{pass:function(e){return\"Element is contained in a fieldset\"},fail:function(e){var t=\"\",r=e.data&&e.data.failureCode;return t+=\"no-legend\"===r?\"Fieldset does not have a legend as its first child\":\"empty-legend\"===r?\"Legend does not have text that is visible to screen readers\":\"mixed-inputs\"===r?\"Fieldset contains unrelated inputs\":\"no-group-label\"===r?\"ARIA group does not have aria-label or aria-labelledby\":\"group-mixed-inputs\"===r?\"ARIA group contains unrelated inputs\":\"Element does not have a containing fieldset or ARIA group\"}}},\"color-contrast\":{impact:\"serious\",messages:{pass:function(e){return\"Element has sufficient color contrast of \"+e.data.contrastRatio},fail:function(e){return\"Element has insufficient color contrast of \"+e.data.contrastRatio+\" (foreground color: \"+e.data.fgColor+\", background color: \"+e.data.bgColor+\", font size: \"+e.data.fontSize+\", font weight: \"+e.data.fontWeight+\"). Expected contrast ratio of \"+e.data.expectedContrastRatio},incomplete:{bgImage:\"Element's background color could not be determined due to a background image\",bgGradient:\"Element's background color could not be determined due to a background gradient\",imgNode:\"Element's background color could not be determined because element contains an image node\",bgOverlap:\"Element's background color could not be determined because it is overlapped by another element\",fgAlpha:\"Element's foreground color could not be determined because of alpha transparency\",elmPartiallyObscured:\"Element's background color could not be determined because it's partially obscured by another element\",elmPartiallyObscuring:\"Element's background color could not be determined because it partially overlaps other elements\",outsideViewport:\"Element's background color could not be determined because it's outside the viewport\",equalRatio:\"Element has a 1:1 contrast ratio with the background\",shortTextContent:\"Element content is too short to determine if it is actual text content\",default:\"Unable to determine contrast ratio\"}}},\"css-orientation-lock\":{impact:\"serious\",messages:{pass:function(e){return\"Display is operable, and orientation lock does not exist\"},fail:function(e){return\"CSS Orientation lock is applied, and makes display inoperable\"}}},\"structured-dlitems\":{impact:\"serious\",messages:{pass:function(e){return\"When not empty, element has both <dt> and <dd> elements\"},fail:function(e){return\"When not empty, element does not have at least one <dt> element followed by at least one <dd> element\"}}},\"only-dlitems\":{impact:\"serious\",messages:{pass:function(e){return\"List element only has direct children that are allowed inside <dt> or <dd> elements\"},fail:function(e){return\"List element has direct children that are not allowed inside <dt> or <dd> elements\"}}},dlitem:{impact:\"serious\",messages:{pass:function(e){return\"Description list item has a <dl> parent element\"},fail:function(e){return\"Description list item does not have a <dl> parent element\"}}},\"doc-has-title\":{impact:\"serious\",messages:{pass:function(e){return\"Document has a non-empty <title> element\"},fail:function(e){return\"Document does not have a non-empty <title> element\"}}},\"duplicate-id-active\":{impact:\"serious\",messages:{pass:function(e){return\"Document has no active elements that share the same id attribute\"},fail:function(e){return\"Document has active elements with the same id attribute: \"+e.data}}},\"duplicate-id-aria\":{impact:\"critical\",messages:{pass:function(e){return\"Document has no elements referenced with ARIA or labels that share the same id attribute\"},fail:function(e){return\"Document has multiple elements referenced with ARIA with the same id attribute: \"+e.data}}},\"duplicate-id\":{impact:\"minor\",messages:{pass:function(e){return\"Document has no static elements that share the same id attribute\"},fail:function(e){return\"Document has multiple static elements with the same id attribute\"}}},\"has-visible-text\":{impact:\"minor\",messages:{pass:function(e){return\"Element has text that is visible to screen readers\"},fail:function(e){return\"Element does not have text that is visible to screen readers\"}}},\"has-widget-role\":{impact:\"minor\",messages:{pass:function(e){return\"Element has a widget role.\"},fail:function(e){return\"Element does not have a widget role.\"}}},\"valid-scrollable-semantics\":{impact:\"minor\",messages:{pass:function(e){return\"Element has valid semantics for an element in the focus order.\"},fail:function(e){return\"Element has invalid semantics for an element in the focus order.\"}}},\"frame-tested\":{impact:\"critical\",messages:{pass:function(e){return\"The iframe was tested with axe-core\"},fail:function(e){return\"The iframe could not be tested with axe-core\"},incomplete:function(e){return\"The iframe still has to be tested with axe-core\"}}},\"unique-frame-title\":{impact:\"serious\",messages:{pass:function(e){return\"Element's title attribute is unique\"},fail:function(e){return\"Element's title attribute is not unique\"}}},\"heading-order\":{impact:\"moderate\",messages:{pass:function(e){return\"Heading order valid\"},fail:function(e){return\"Heading order invalid\"}}},\"hidden-content\":{impact:\"minor\",messages:{pass:function(e){return\"All content on the page has been analyzed.\"},fail:function(e){return\"There were problems analyzing the content on this page.\"},incomplete:function(e){return\"There is hidden content on the page that was not analyzed. You will need to trigger the display of this content in order to analyze it.\"}}},\"has-lang\":{impact:\"serious\",messages:{pass:function(e){return\"The <html> element has a lang attribute\"},fail:function(e){return\"The <html> element does not have a lang attribute\"}}},\"valid-lang\":{impact:\"serious\",messages:{pass:function(e){return\"Value of lang attribute is included in the list of valid languages\"},fail:function(e){return\"Value of lang attribute not included in the list of valid languages\"}}},\"xml-lang-mismatch\":{impact:\"moderate\",messages:{pass:function(e){return\"Lang and xml:lang attributes have the same base language\"},fail:function(e){return\"Lang and xml:lang attributes do not have the same base language\"}}},\"has-alt\":{impact:\"critical\",messages:{pass:function(e){return\"Element has an alt attribute\"},fail:function(e){return\"Element does not have an alt attribute\"}}},\"duplicate-img-label\":{impact:\"minor\",messages:{pass:function(e){return\"Element does not duplicate existing text in <img> alt text\"},fail:function(e){return\"Element contains <img> element with alt text that duplicates existing text\"}}},\"title-only\":{impact:\"serious\",messages:{pass:function(e){return\"Form element does not solely use title attribute for its label\"},fail:function(e){return\"Only title used to generate label for form element\"}}},\"implicit-label\":{impact:\"critical\",messages:{pass:function(e){return\"Form element has an implicit (wrapped) <label>\"},fail:function(e){return\"Form element does not have an implicit (wrapped) <label>\"}}},\"explicit-label\":{impact:\"critical\",messages:{pass:function(e){return\"Form element has an explicit <label>\"},fail:function(e){return\"Form element does not have an explicit <label>\"}}},\"help-same-as-label\":{impact:\"minor\",messages:{pass:function(e){return\"Help text (title or aria-describedby) does not duplicate label text\"},fail:function(e){return\"Help text (title or aria-describedby) text is the same as the label text\"}}},\"multiple-label\":{impact:\"serious\",messages:{pass:function(e){return\"Form element does not have multiple <label> elements\"},fail:function(e){return\"Form element has multiple <label> elements\"}}},\"hidden-explicit-label\":{impact:\"critical\",messages:{pass:function(e){return\"Form element has a visible explicit <label>\"},fail:function(e){return\"Form element has explicit <label> that is hidden\"}}},\"landmark-is-top-level\":{impact:\"moderate\",messages:{pass:function(e){return\"The \"+e.data.role+\" landmark is at the top level.\"},fail:function(e){return\"The \"+e.data.role+\" landmark is contained in another landmark.\"}}},\"page-no-duplicate-banner\":{impact:\"moderate\",messages:{pass:function(e){return\"Document has no more than one banner landmark\"},fail:function(e){return\"Document has more than one banner landmark\"}}},\"page-no-duplicate-contentinfo\":{impact:\"moderate\",messages:{pass:function(e){return\"Page does not have more than one contentinfo landmark\"},fail:function(e){return\"Page has more than one contentinfo landmark\"}}},\"page-has-main\":{impact:\"moderate\",messages:{pass:function(e){return\"Page has at least one main landmark\"},fail:function(e){return\"Page does not have a main landmark\"}}},\"page-no-duplicate-main\":{impact:\"moderate\",messages:{pass:function(e){return\"Page does not have more than one main landmark\"},fail:function(e){return\"Page has more than one main landmark\"}}},\"has-th\":{impact:\"serious\",messages:{pass:function(e){return\"Layout table does not use <th> elements\"},fail:function(e){return\"Layout table uses <th> elements\"}}},\"has-caption\":{impact:\"serious\",messages:{pass:function(e){return\"Layout table does not use <caption> element\"},fail:function(e){return\"Layout table uses <caption> element\"}}},\"has-summary\":{impact:\"serious\",messages:{pass:function(e){return\"Layout table does not use summary attribute\"},fail:function(e){return\"Layout table uses summary attribute\"}}},\"link-in-text-block\":{impact:\"serious\",messages:{pass:function(e){return\"Links can be distinguished from surrounding text in some way other than by color\"},fail:function(e){return\"Links need to be distinguished from surrounding text in some way other than by color\"},incomplete:{bgContrast:\"Element's contrast ratio could not be determined. Check for a distinct hover/focus style\",bgImage:\"Element's contrast ratio could not be determined due to a background image\",bgGradient:\"Element's contrast ratio could not be determined due to a background gradient\",imgNode:\"Element's contrast ratio could not be determined because element contains an image node\",bgOverlap:\"Element's contrast ratio could not be determined because of element overlap\",default:\"Unable to determine contrast ratio\"}}},\"only-listitems\":{impact:\"serious\",messages:{pass:function(e){return\"List element only has direct children that are allowed inside <li> elements\"},fail:function(e){return\"List element has direct children that are not allowed inside <li> elements\"}}},listitem:{impact:\"serious\",messages:{pass:function(e){return'List item has a <ul>, <ol> or role=\"list\" parent element'},fail:function(e){return'List item does not have a <ul>, <ol> or role=\"list\" parent element'}}},\"meta-refresh\":{impact:\"critical\",messages:{pass:function(e){return\"<meta> tag does not immediately refresh the page\"},fail:function(e){return\"<meta> tag forces timed refresh of page\"}}},\"meta-viewport-large\":{impact:\"minor\",messages:{pass:function(e){return\"<meta> tag does not prevent significant zooming on mobile devices\"},fail:function(e){return\"<meta> tag limits zooming on mobile devices\"}}},\"meta-viewport\":{impact:\"critical\",messages:{pass:function(e){return\"<meta> tag does not disable zooming on mobile devices\"},fail:function(e){return e.data+\" on <meta> tag disables zooming on mobile devices\"}}},\"p-as-heading\":{impact:\"serious\",messages:{pass:function(e){return\"<p> elements are not styled as headings\"},fail:function(e){return\"Heading elements should be used instead of styled p elements\"}}},\"page-has-heading-one\":{impact:\"moderate\",messages:{pass:function(e){return\"Page has at least one level-one heading\"},fail:function(e){return\"Page must have a level-one heading\"}}},region:{impact:\"moderate\",messages:{pass:function(e){return\"All page content is contained by landmarks\"},fail:function(e){return\"Some page content is not contained by landmarks\"}}},\"html5-scope\":{impact:\"moderate\",messages:{pass:function(e){return\"Scope attribute is only used on table header elements (<th>)\"},fail:function(e){return\"In HTML 5, scope attributes may only be used on table header elements (<th>)\"}}},\"scope-value\":{impact:\"critical\",messages:{pass:function(e){return\"Scope attribute is used correctly\"},fail:function(e){return\"The value of the scope attribute may only be 'row' or 'col'\"}}},exists:{impact:\"minor\",messages:{pass:function(e){return\"Element does not exist\"},fail:function(e){return\"Element exists\"}}},\"skip-link\":{impact:\"moderate\",messages:{pass:function(e){return\"Skip link target exists\"},incomplete:function(e){return\"Skip link target should become visible on activation\"},fail:function(e){return\"No skip link target\"}}},tabindex:{impact:\"serious\",messages:{pass:function(e){return\"Element does not have a tabindex greater than 0\"},fail:function(e){return\"Element has a tabindex greater than 0\"}}},\"same-caption-summary\":{impact:\"minor\",messages:{pass:function(e){return\"Content of summary attribute and <caption> are not duplicated\"},fail:function(e){return\"Content of summary attribute and <caption> element are identical\"}}},\"caption-faked\":{impact:\"serious\",messages:{pass:function(e){return\"The first row of a table is not used as a caption\"},fail:function(e){return\"The first row of the table should be a caption instead of a table cell\"}}},\"td-has-header\":{impact:\"critical\",messages:{pass:function(e){return\"All non-empty data cells have table headers\"},fail:function(e){return\"Some non-empty data cells do not have table headers\"}}},\"td-headers-attr\":{impact:\"serious\",messages:{pass:function(e){return\"The headers attribute is exclusively used to refer to other cells in the table\"},fail:function(e){return\"The headers attribute is not exclusively used to refer to other cells in the table\"}}},\"th-has-data-cells\":{impact:\"serious\",messages:{pass:function(e){return\"All table header cells refer to data cells\"},fail:function(e){return\"Not all table header cells refer to data cells\"},incomplete:function(e){return\"Table data cells are missing or empty\"}}},description:{impact:\"critical\",messages:{pass:function(e){return\"The multimedia element has an audio description track\"},incomplete:function(e){return\"Check that audio description is available for the element\"}}}},failureSummaries:{any:{failureMessage:function(e){var t=\"Fix any of the following:\",r=e;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\"\\n \"+r[a+=1].split(\"\\n\").join(\"\\n \");return t}},none:{failureMessage:function(e){var t=\"Fix all of the following:\",r=e;if(r)for(var a=-1,n=r.length-1;a<n;)t+=\"\\n \"+r[a+=1].split(\"\\n\").join(\"\\n \");return t}}},incompleteFallbackMessage:function(e){return\"aXe couldn't tell the reason. Time to break out the element inspector!\"}},rules:[{id:\"accesskeys\",selector:\"[accesskey]\",excludeHidden:!1,tags:[\"best-practice\",\"cat.keyboard\"],all:[],any:[],none:[\"accesskeys\"]},{id:\"area-alt\",selector:\"map area[href]\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"non-empty-title\",\"aria-label\",\"aria-labelledby\"],none:[]},{id:\"aria-allowed-attr\",matches:function(e,t){var r=e.getAttribute(\"role\");r||(r=axe.commons.aria.implicitRole(e));var a=axe.commons.aria.allowedAttr(r);if(r&&a){var n=/^aria-/;if(e.hasAttributes())for(var o=e.attributes,i=0,s=o.length;i<s;i++)if(n.test(o[i].name))return!0}return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[\"aria-allowed-attr\"],none:[]},{id:\"aria-allowed-role\",excludeHidden:!1,selector:\"[role]\",matches:function(e,t){return null!==axe.commons.aria.getRole(e,{noImplicit:!0,dpub:!0,fallback:!0})},tags:[\"cat.aria\",\"best-practice\"],all:[],any:[{options:{allowImplicit:!0,ignoredTags:[]},id:\"aria-allowed-role\"}],none:[]},{id:\"aria-dpub-role-fallback\",selector:\"[role]\",matches:function(e,t){var r=e.getAttribute(\"role\");return[\"doc-backlink\",\"doc-biblioentry\",\"doc-biblioref\",\"doc-cover\",\"doc-endnote\",\"doc-glossref\",\"doc-noteref\"].includes(r)},tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[\"implicit-role-fallback\"],any:[],none:[]},{id:\"aria-hidden-body\",selector:\"body\",excludeHidden:!1,tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[\"aria-hidden-body\"],none:[]},{id:\"aria-required-attr\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[\"aria-required-attr\"],none:[]},{id:\"aria-required-children\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[{options:{reviewEmpty:[\"listbox\"]},id:\"aria-required-children\"}],none:[]},{id:\"aria-required-parent\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-parent\"],none:[]},{id:\"aria-roles\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[],none:[\"invalidrole\",\"abstractrole\",\"unsupportedrole\"]},{id:\"aria-valid-attr-value\",matches:function(e,t){var r=/^aria-/;if(e.hasAttributes())for(var a=e.attributes,n=0,o=a.length;n<o;n++)if(r.test(a[n].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[{options:[],id:\"aria-valid-attr-value\"},\"aria-errormessage\"],any:[],none:[]},{id:\"aria-valid-attr\",matches:function(e,t){var r=/^aria-/;if(e.hasAttributes())for(var a=e.attributes,n=0,o=a.length;n<o;n++)if(r.test(a[n].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[{options:[],id:\"aria-valid-attr\"}],none:[]},{id:\"audio-caption\",selector:\"audio\",enabled:!1,excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag121\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"autocomplete-valid\",matches:function(e,t){var r=axe.commons,a=r.text,n=r.aria,o=r.dom,i=e.getAttribute(\"autocomplete\");if(!i||\"\"===a.sanitize(i))return!1;var s=e.nodeName.toUpperCase();if(!1===[\"TEXTAREA\",\"INPUT\",\"SELECT\"].includes(s))return!1;if(\"INPUT\"===s&&[\"submit\",\"reset\",\"button\",\"hidden\"].includes(e.type))return!1;var l=e.getAttribute(\"aria-disabled\")||\"false\";if(e.disabled||\"true\"===l.toLowerCase())return!1;var u=e.getAttribute(\"role\"),c=e.getAttribute(\"tabindex\");if(\"-1\"===c&&u){var d=n.lookupTable.role[u];if(void 0===d||\"widget\"!==d.type)return!1}return!(\"-1\"===c&&!o.isVisible(e,!1)&&!o.isVisible(e,!0))},tags:[\"cat.forms\",\"wcag21aa\",\"wcag135\"],all:[\"autocomplete-valid\",\"autocomplete-appropriate\"],any:[],none:[]},{id:\"blink\",selector:\"blink\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag222\",\"section508\",\"section508.22.j\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"button-name\",selector:'button, [role=\"button\"], input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"]',tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-if-present\",\"non-empty-value\",\"button-has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\",\"non-empty-title\"],none:[\"focusable-no-name\"]},{id:\"bypass\",selector:\"html\",pageLevel:!0,matches:function(e,t){return!!e.querySelector(\"a[href]\")},tags:[\"cat.keyboard\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.o\"],all:[],any:[\"internal-link-present\",\"header-present\",\"landmark\"],none:[]},{id:\"checkboxgroup\",selector:\"input[type=checkbox][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"color-contrast\",matches:function(e,t){var r=e.nodeName.toUpperCase(),a=e.type;if(\"true\"===e.getAttribute(\"aria-disabled\")||axe.commons.dom.findUpVirtual(t,'[aria-disabled=\"true\"]'))return!1;if(\"INPUT\"===r)return-1===[\"hidden\",\"range\",\"color\",\"checkbox\",\"radio\",\"image\"].indexOf(a)&&!e.disabled;if(\"SELECT\"===r)return!!e.options.length&&!e.disabled;if(\"TEXTAREA\"===r)return!e.disabled;if(\"OPTION\"===r)return!1;if(\"BUTTON\"===r&&e.disabled||axe.commons.dom.findUpVirtual(t,\"button[disabled]\"))return!1;if(\"FIELDSET\"===r&&e.disabled||axe.commons.dom.findUpVirtual(t,\"fieldset[disabled]\"))return!1;var n=axe.commons.dom.findUpVirtual(t,\"label\");if(\"LABEL\"===r||n){var o=e,i=t;n&&(o=n,i=axe.utils.getNodeFromTree(axe._tree[0],n));var s=axe.commons.dom.getRootNode(o);if((l=o.htmlFor&&s.getElementById(o.htmlFor))&&l.disabled)return!1;if((l=axe.utils.querySelectorAll(i,'input:not([type=\"hidden\"]):not([type=\"image\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]), select, textarea')).length&&l[0].actualNode.disabled)return!1}if(e.getAttribute(\"id\")){var l,u=axe.commons.utils.escapeSelector(e.getAttribute(\"id\"));if((l=axe.commons.dom.getRootNode(e).querySelector(\"[aria-labelledby~=\"+u+\"]\"))&&l.disabled)return!1}if(\"\"===axe.commons.text.visibleVirtual(t,!1,!0))return!1;var c,d,m=document.createRange(),p=t.children,f=p.length;for(d=0;d<f;d++)3===(c=p[d]).actualNode.nodeType&&\"\"!==axe.commons.text.sanitize(c.actualNode.nodeValue)&&m.selectNodeContents(c.actualNode);var h=m.getClientRects();for(f=h.length,d=0;d<f;d++)if(axe.commons.dom.visuallyOverlaps(h[d],e))return!0;return!1},excludeHidden:!1,options:{noScroll:!1},tags:[\"cat.color\",\"wcag2aa\",\"wcag143\"],all:[],any:[\"color-contrast\"],none:[]},{id:\"css-orientation-lock\",selector:\"html\",tags:[\"cat.structure\",\"wcag262\",\"wcag21aa\",\"experimental\"],all:[\"css-orientation-lock\"],any:[],none:[],preload:!0},{id:\"definition-list\",selector:\"dl\",matches:function(e,t){return!e.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"structured-dlitems\",\"only-dlitems\"]},{id:\"dlitem\",selector:\"dd, dt\",matches:function(e,t){return!e.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"dlitem\"],none:[]},{id:\"document-title\",selector:\"html\",matches:function(e,t){return e.ownerDocument.defaultView.self===e.ownerDocument.defaultView.top},tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag242\"],all:[],any:[\"doc-has-title\"],none:[]},{id:\"duplicate-id-active\",selector:\"[id]\",matches:function(e,t){var r=axe.commons,a=r.dom,n=r.aria,o=e.getAttribute(\"id\").trim(),i='*[id=\"'+axe.utils.escapeSelector(o)+'\"]';return Array.from(a.getRootNode(e).querySelectorAll(i)).some(a.isFocusable)&&!n.isAccessibleRef(e)},excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag411\"],all:[],any:[\"duplicate-id-active\"],none:[]},{id:\"duplicate-id-aria\",selector:\"[id]\",matches:function(e,t){return axe.commons.aria.isAccessibleRef(e)},excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag411\"],all:[],any:[\"duplicate-id-aria\"],none:[]},{id:\"duplicate-id\",selector:\"[id]\",matches:function(e,t){var r=axe.commons,a=r.dom,n=r.aria,o=e.getAttribute(\"id\").trim(),i='*[id=\"'+axe.utils.escapeSelector(o)+'\"]';return Array.from(a.getRootNode(e).querySelectorAll(i)).every(function(e){return!a.isFocusable(e)})&&!n.isAccessibleRef(e)},excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag411\"],all:[],any:[\"duplicate-id\"],none:[]},{id:\"empty-heading\",selector:'h1, h2, h3, h4, h5, h6, [role=\"heading\"]',matches:function(e,t){var r=void 0;return e.hasAttribute(\"role\")&&(r=e.getAttribute(\"role\").split(/\\s+/i).filter(axe.commons.aria.isValidRole)),r&&0<r.length?r.includes(\"heading\"):\"heading\"===axe.commons.aria.implicitRole(e)},tags:[\"cat.name-role-value\",\"best-practice\"],all:[],any:[\"has-visible-text\"],none:[]},{id:\"focus-order-semantics\",selector:\"div, h1, h2, h3, h4, h5, h6, [role=heading], p, span\",matches:function(e,t){return axe.commons.dom.insertedIntoFocusOrder(e)},tags:[\"cat.keyboard\",\"best-practice\",\"experimental\"],all:[],any:[{options:[],id:\"has-widget-role\"},{options:[],id:\"valid-scrollable-semantics\"}],none:[]},{id:\"frame-tested\",selector:\"frame, iframe\",tags:[\"cat.structure\",\"review-item\"],all:[{options:{isViolation:!1},id:\"frame-tested\"}],any:[],none:[]},{id:\"frame-title-unique\",selector:\"frame[title], iframe[title]\",matches:function(e,t){var r=e.getAttribute(\"title\");return!(!r||!axe.commons.text.sanitize(r).trim())},tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"unique-frame-title\"]},{id:\"frame-title\",selector:\"frame, iframe\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag241\",\"wcag412\",\"section508\",\"section508.22.i\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"heading-order\",selector:\"h1, h2, h3, h4, h5, h6, [role=heading]\",matches:function(e,t){var r=void 0;return e.hasAttribute(\"role\")&&(r=e.getAttribute(\"role\").split(/\\s+/i).filter(axe.commons.aria.isValidRole)),r&&0<r.length?r.includes(\"heading\"):\"heading\"===axe.commons.aria.implicitRole(e)},tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"heading-order\"],none:[]},{id:\"hidden-content\",selector:\"*\",excludeHidden:!1,tags:[\"cat.structure\",\"experimental\",\"review-item\"],all:[],any:[\"hidden-content\"],none:[]},{id:\"html-has-lang\",selector:\"html\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[\"has-lang\"],none:[]},{id:\"html-lang-valid\",selector:\"html[lang]\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"html-xml-lang-mismatch\",selector:\"html[lang][xml\\\\:lang]\",matches:function(e,t){var r=axe.commons.utils.getBaseLang,a=r(e.getAttribute(\"lang\")),n=r(e.getAttribute(\"xml:lang\"));return axe.utils.validLangs().includes(a)&&axe.utils.validLangs().includes(n)},tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[\"xml-lang-mismatch\"],any:[],none:[]},{id:\"image-alt\",selector:\"img, [role='img']:not(svg)\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"image-redundant-alt\",selector:'button, [role=\"button\"], a[href], p, li, td, th',tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"duplicate-img-label\"]},{id:\"input-image-alt\",selector:'input[type=\"image\"]',tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"label-title-only\",selector:\"input, select, textarea\",matches:function(e,t){if(\"input\"!==e.nodeName.toLowerCase()||!1===e.hasAttribute(\"type\"))return!0;var r=e.getAttribute(\"type\").toLowerCase();return!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(r)},tags:[\"cat.forms\",\"best-practice\"],all:[],any:[],none:[\"title-only\"]},{id:\"label\",selector:\"input, select, textarea\",matches:function(e,t){if(\"input\"!==e.nodeName.toLowerCase()||!1===e.hasAttribute(\"type\"))return!0;var r=e.getAttribute(\"type\").toLowerCase();return!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(r)},tags:[\"cat.forms\",\"wcag2a\",\"wcag332\",\"wcag131\",\"section508\",\"section508.22.n\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"implicit-label\",\"explicit-label\",\"non-empty-title\"],none:[\"help-same-as-label\",\"multiple-label\",\"hidden-explicit-label\"]},{id:\"landmark-banner-is-top-level\",selector:\"header:not([role]), [role=banner]\",matches:function(e,t){return e.hasAttribute(\"role\")||!axe.commons.dom.findUpVirtual(t,\"article, aside, main, nav, section\")},tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-contentinfo-is-top-level\",selector:\"footer:not([role]), [role=contentinfo]\",matches:function(e,t){return e.hasAttribute(\"role\")||!axe.commons.dom.findUpVirtual(t,\"article, aside, main, nav, section\")},tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-main-is-top-level\",selector:\"main:not([role]), [role=main]\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-no-duplicate-banner\",selector:\"html\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[{options:{selector:\"header:not([role]), [role=banner]\",nativeScopeFilter:\"article, aside, main, nav, section\"},id:\"page-no-duplicate-banner\"}],none:[]},{id:\"landmark-no-duplicate-contentinfo\",selector:\"html\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[{options:{selector:\"footer:not([role]), [role=contentinfo]\",nativeScopeFilter:\"article, aside, main, nav, section\"},id:\"page-no-duplicate-contentinfo\"}],none:[]},{id:\"landmark-one-main\",selector:\"html\",tags:[\"cat.semantics\",\"best-practice\"],all:[{options:{selector:\"main:not([role]), [role='main']\"},id:\"page-has-main\"},{options:{selector:\"main:not([role]), [role='main']\"},id:\"page-no-duplicate-main\"}],any:[],none:[]},{id:\"layout-table\",selector:\"table\",matches:function(e,t){var r=(e.getAttribute(\"role\")||\"\").toLowerCase();return!((\"presentation\"===r||\"none\"===r)&&!axe.commons.dom.isFocusable(e)||axe.commons.table.isDataTable(e))},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"has-th\",\"has-caption\",\"has-summary\"]},{id:\"link-in-text-block\",selector:\"a[href], [role=link]\",matches:function(e,t){var r=axe.commons.text.sanitize(e.textContent),a=e.getAttribute(\"role\");return(!a||\"link\"===a)&&(!!r&&(!!axe.commons.dom.isVisible(e,!1)&&axe.commons.dom.isInTextBlock(e)))},excludeHidden:!1,tags:[\"cat.color\",\"experimental\",\"wcag2a\",\"wcag141\"],all:[\"link-in-text-block\"],any:[],none:[]},{id:\"link-name\",selector:\"a[href], [role=link][href]\",matches:function(e,t){return\"button\"!==e.getAttribute(\"role\")},tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"wcag244\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"list\",selector:\"ul, ol\",matches:function(e,t){return!e.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"only-listitems\"]},{id:\"listitem\",selector:\"li\",matches:function(e,t){return!e.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"listitem\"],none:[]},{id:\"marquee\",selector:\"marquee\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag222\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"meta-refresh\",selector:'meta[http-equiv=\"refresh\"]',excludeHidden:!1,tags:[\"cat.time\",\"wcag2a\",\"wcag2aaa\",\"wcag221\",\"wcag224\",\"wcag325\"],all:[],any:[\"meta-refresh\"],none:[]},{id:\"meta-viewport-large\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"best-practice\"],all:[],any:[{options:{scaleMinimum:5,lowerBound:2},id:\"meta-viewport-large\"}],none:[]},{id:\"meta-viewport\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"wcag2aa\",\"wcag144\"],all:[],any:[{options:{scaleMinimum:2},id:\"meta-viewport\"}],none:[]},{id:\"object-alt\",selector:\"object\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"p-as-heading\",selector:\"p\",matches:function(e,t){var r=Array.from(e.parentNode.childNodes),a=e.textContent.trim();return!(0===a.length||2<=(a.match(/[.!?:;](?![.!?:;])/g)||[]).length)&&0!==r.slice(r.indexOf(e)+1).filter(function(e){return\"P\"===e.nodeName.toUpperCase()&&\"\"!==e.textContent.trim()}).length},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\",\"experimental\"],all:[{options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]},id:\"p-as-heading\"}],any:[],none:[]},{id:\"page-has-heading-one\",selector:\"html\",tags:[\"cat.semantics\",\"best-practice\"],all:[{options:{selector:'h1:not([role]), [role=\"heading\"][aria-level=\"1\"]'},id:\"page-has-heading-one\"}],any:[],none:[]},{id:\"radiogroup\",selector:\"input[type=radio][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"region\",selector:\"html\",pageLevel:!0,tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"region\"],none:[]},{id:\"scope-attr-valid\",selector:\"td[scope], th[scope]\",tags:[\"cat.tables\",\"best-practice\"],all:[\"html5-scope\",\"scope-value\"],any:[],none:[]},{id:\"server-side-image-map\",selector:\"img[ismap]\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag211\",\"section508\",\"section508.22.f\"],all:[],any:[],none:[\"exists\"]},{id:\"skip-link\",selector:\"a[href]\",matches:function(e,t){return/^#[^/!]/.test(e.getAttribute(\"href\"))},tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"skip-link\"],none:[]},{id:\"tabindex\",selector:\"[tabindex]\",tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"tabindex\"],none:[]},{id:\"table-duplicate-name\",selector:\"table\",tags:[\"cat.tables\",\"best-practice\"],all:[],any:[],none:[\"same-caption-summary\"]},{id:\"table-fake-caption\",selector:\"table\",matches:function(e,t){return axe.commons.table.isDataTable(e)},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"caption-faked\"],any:[],none:[]},{id:\"td-has-header\",selector:\"table\",matches:function(e,t){if(axe.commons.table.isDataTable(e)){var r=axe.commons.table.toArray(e);return 3<=r.length&&3<=r[0].length&&3<=r[1].length&&3<=r[2].length}return!1},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-has-header\"],any:[],none:[]},{id:\"td-headers-attr\",selector:\"table\",tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-headers-attr\"],any:[],none:[]},{id:\"th-has-data-cells\",selector:\"table\",matches:function(e,t){return axe.commons.table.isDataTable(e)},tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"th-has-data-cells\"],any:[],none:[]},{id:\"valid-lang\",selector:\"[lang], [xml\\\\:lang]\",matches:function(e,t){return\"html\"!==e.nodeName.toLowerCase()},tags:[\"cat.language\",\"wcag2aa\",\"wcag312\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"video-caption\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag122\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"video-description\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2aa\",\"wcag125\",\"section508\",\"section508.22.b\"],all:[],any:[],none:[\"description\"]}],checks:[{id:\"abstractrole\",evaluate:function(e,t,r,a){return\"abstract\"===axe.commons.aria.getRoleType(e.getAttribute(\"role\"))}},{id:\"aria-allowed-attr\",evaluate:function(e,t,r,a){t=t||{};var n,o,i,s=[],l=e.getAttribute(\"role\"),u=e.attributes;if(l||(l=axe.commons.aria.implicitRole(e)),i=axe.commons.aria.allowedAttr(l),Array.isArray(t[l])&&(i=axe.utils.uniqueArray(t[l].concat(i))),l&&i)for(var c=0,d=u.length;c<d;c++)o=(n=u[c]).name,axe.commons.aria.validateAttr(o)&&!i.includes(o)&&s.push(o+'=\"'+n.nodeValue+'\"');return!s.length||(this.data(s),!1)}},{id:\"aria-allowed-role\",evaluate:function(e,t,r,a){var n=t||{},o=n.allowImplicit,i=void 0===o||o,s=n.ignoredTags,l=void 0===s?[]:s,u=e.nodeName.toUpperCase();if(l.map(function(e){return e.toUpperCase()}).includes(u))return!0;var c=axe.commons.aria.getElementUnallowedRoles(e,i);return!c.length||(this.data(c),!1)},options:{allowImplicit:!0,ignoredTags:[]}},{id:\"aria-hidden-body\",evaluate:function(e,t,r,a){return\"true\"!==e.getAttribute(\"aria-hidden\")}},{id:\"aria-errormessage\",evaluate:function(t,e,r,a){e=Array.isArray(e)?e:[];var n=t.getAttribute(\"aria-errormessage\"),o=t.hasAttribute(\"aria-errormessage\"),i=axe.commons.dom.getRootNode(t);return!(-1===e.indexOf(n)&&o&&!function(){var e=n&&i.getElementById(n);if(e)return\"alert\"===e.getAttribute(\"role\")||\"assertive\"===e.getAttribute(\"aria-live\")||-1<axe.utils.tokenList(t.getAttribute(\"aria-describedby\")||\"\").indexOf(n)}())||(this.data(axe.utils.tokenList(n)),!1)}},{id:\"has-widget-role\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"role\");if(null===n)return!1;var o=axe.commons.aria.getRoleType(n);return\"widget\"===o||\"composite\"===o},options:[]},{id:\"implicit-role-fallback\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"role\");if(null===n||!axe.commons.aria.isValidRole(n))return!0;var o=axe.commons.aria.getRoleType(n);return axe.commons.aria.implicitRole(e)===o}},{id:\"invalidrole\",evaluate:function(e,t,r,a){return!axe.commons.aria.isValidRole(e.getAttribute(\"role\"),{allowAbstract:!0})}},{id:\"aria-required-attr\",evaluate:function(e,t,r,a){t=t||{};var n=[];if(e.hasAttributes()){var o,i=e.getAttribute(\"role\"),s=axe.commons.aria.requiredAttr(i);if(Array.isArray(t[i])&&(s=axe.utils.uniqueArray(t[i],s)),i&&s)for(var l=0,u=s.length;l<u;l++)o=s[l],e.getAttribute(o)||n.push(o)}return!n.length||(this.data(n),!1)}},{id:\"aria-required-children\",evaluate:function(e,t,m,r){var a=axe.commons.aria.requiredOwned,i=axe.commons.aria.implicitNodes,s=axe.commons.utils.matchesSelector,p=axe.commons.dom.idrefs,n=t&&Array.isArray(t.reviewEmpty)?t.reviewEmpty:[];function f(e,t,r,a){if(null===e)return!1;var n=i(r),o=['[role=\"'+r+'\"]'];return n&&(o=o.concat(n)),o=o.join(\",\"),a&&s(e,o)||!!axe.utils.querySelectorAll(t,o)[0]}function h(e,t){var r,a;for(r=0,a=e.length;r<a;r++)if(null!==e[r]){var n=axe.utils.getNodeFromTree(axe._tree[0],e[r]);if(f(e[r],n,t,!0))return!0}return!1}var o=e.getAttribute(\"role\"),l=a(o);if(!l)return!0;var u=!1,c=l.one;if(!c){u=!0;c=l.all}var d=function(e,t,r,a){var n,o=t.length,i=[],s=p(e,\"aria-owns\");for(n=0;n<o;n++){var l=t[n];if(f(e,m,l)||h(s,l)){if(!r)return null}else r&&i.push(l)}if(\"combobox\"===a){var u=i.indexOf(\"textbox\");0<=u&&\"INPUT\"===e.tagName&&[\"text\",\"search\",\"email\",\"url\",\"tel\"].includes(e.type)&&i.splice(u,1);var c=i.indexOf(\"listbox\"),d=e.getAttribute(\"aria-expanded\");0<=c&&(!d||\"false\"===d)&&i.splice(c,1)}return i.length?i:!r&&t.length?t:null}(e,c,u,o);return!d||(this.data(d),!!n.includes(o)&&void 0)},options:{reviewEmpty:[\"listbox\"]}},{id:\"aria-required-parent\",evaluate:function(e,t,r,a){function s(e){return(axe.commons.aria.implicitNodes(e)||[]).concat('[role=\"'+e+'\"]').join(\",\")}function n(e,t,r){var a,n,o=e.actualNode.getAttribute(\"role\"),i=[];if(t||(t=axe.commons.aria.requiredContext(o)),!t)return null;for(a=0,n=t.length;a<n;a++){if(r&&axe.utils.matchesSelector(e.actualNode,s(t[a])))return null;if(axe.commons.dom.findUpVirtual(e,s(t[a])))return null;i.push(t[a])}return i}var o=n(r);if(!o)return!0;var i=function(e){for(var t=[],r=null;e;){if(e.getAttribute(\"id\")){var a=axe.commons.utils.escapeSelector(e.getAttribute(\"id\"));(r=axe.commons.dom.getRootNode(e).querySelector(\"[aria-owns~=\"+a+\"]\"))&&t.push(r)}e=e.parentElement}return t.length?t:null}(e);if(i)for(var l=0,u=i.length;l<u;l++)if(!(o=n(axe.utils.getNodeFromTree(axe._tree[0],i[l]),o,!0)))return!0;return this.data(o),!1}},{id:\"unsupportedrole\",evaluate:function(e,t,r,a){return!axe.commons.aria.isValidRole(e.getAttribute(\"role\"),{flagUnsupported:!0})}},{id:\"aria-valid-attr-value\",evaluate:function(e,t,r,a){t=Array.isArray(t)?t:[];for(var n,o,i=[],s=/^aria-/,l=e.attributes,u=[\"aria-errormessage\"],c=0,d=l.length;c<d;c++)o=(n=l[c]).name,u.includes(o)||-1===t.indexOf(o)&&s.test(o)&&!axe.commons.aria.validateAttrValue(e,o)&&i.push(o+'=\"'+n.nodeValue+'\"');return!i.length||(this.data(i),!1)},options:[]},{id:\"aria-valid-attr\",evaluate:function(e,t,r,a){t=Array.isArray(t)?t:[];for(var n,o=[],i=/^aria-/,s=e.attributes,l=0,u=s.length;l<u;l++)n=s[l].name,-1===t.indexOf(n)&&i.test(n)&&!axe.commons.aria.validateAttr(n)&&o.push(n);return!o.length||(this.data(o),!1)},options:[]},{id:\"valid-scrollable-semantics\",evaluate:function(e,t,r,a){var n,o,i,s={ARTICLE:!0,ASIDE:!0,NAV:!0,SECTION:!0},l={application:!0,banner:!1,complementary:!0,contentinfo:!0,form:!0,main:!0,navigation:!0,region:!0,search:!1};return(i=(n=e).getAttribute(\"role\"))&&l[i.toLowerCase()]||(o=n.tagName.toUpperCase(),s[o]||!1)},options:[]},{id:\"color-contrast\",evaluate:function(e,t,r,a){var n=axe.commons,o=n.dom,i=n.color,s=n.text;if(!o.isVisible(e,!1))return!0;var l=!!(t||{}).noScroll,u=[],c=i.getBackgroundColor(e,u,l),d=i.getForegroundColor(e,l),m=window.getComputedStyle(e),p=parseFloat(m.getPropertyValue(\"font-size\")),f=m.getPropertyValue(\"font-weight\"),h=-1!==[\"bold\",\"bolder\",\"600\",\"700\",\"800\",\"900\"].indexOf(f),g=i.hasValidContrastRatio(c,d,p,h),b=Math.floor(100*g.contrastRatio)/100,y=void 0;null===c&&(y=i.incompleteData.get(\"bgColor\"));var v=1===b,w=1===s.visibleVirtual(r,!1,!0).length;v?y=i.incompleteData.set(\"bgColor\",\"equalRatio\"):w&&(y=\"shortTextContent\");var k={fgColor:d?d.toHexString():void 0,bgColor:c?c.toHexString():void 0,contrastRatio:g?b:void 0,fontSize:(72*p/96).toFixed(1)+\"pt\",fontWeight:h?\"bold\":\"normal\",missingData:y,expectedContrastRatio:g.expectedContrastRatio+\":1\"};return this.data(k),null===d||null===c||v||w&&!g.isValid?(y=null,i.incompleteData.clear(),void this.relatedNodes(u)):(g.isValid||this.relatedNodes(u),g.isValid)}},{id:\"link-in-text-block\",evaluate:function(e,t,r,a){var n=axe.commons,o=n.color,i=n.dom;function s(e,t){var r=e.getRelativeLuminance(),a=t.getRelativeLuminance();return(Math.max(r,a)+.05)/(Math.min(r,a)+.05)}var l=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];function u(e){var t=window.getComputedStyle(e).getPropertyValue(\"display\");return-1!==l.indexOf(t)||\"table-\"===t.substr(0,6)}if(u(e))return!1;for(var c,d,m=i.getComposedParent(e);1===m.nodeType&&!u(m);)m=i.getComposedParent(m);if(this.relatedNodes([m]),o.elementIsDistinct(e,m))return!0;if(c=o.getForegroundColor(e),d=o.getForegroundColor(m),c&&d){var p=s(c,d);if(1===p)return!0;if(3<=p)return axe.commons.color.incompleteData.set(\"fgColor\",\"bgContrast\"),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear();if(c=o.getBackgroundColor(e),d=o.getBackgroundColor(m),!c||!d||3<=s(c,d)){var f=void 0;return f=c&&d?\"bgContrast\":axe.commons.color.incompleteData.get(\"bgColor\"),axe.commons.color.incompleteData.set(\"fgColor\",f),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear()}return!1}}},{id:\"autocomplete-appropriate\",evaluate:function(e,t,r,a){if(\"INPUT\"!==e.nodeName.toUpperCase())return!0;var n=[\"text\",\"search\",\"number\"],o=[\"text\",\"search\",\"url\"],i={bday:[\"text\",\"search\",\"date\"],email:[\"text\",\"search\",\"email\"],\"cc-exp\":[\"text\",\"search\",\"month\"],\"street-address\":[],tel:[\"text\",\"search\",\"tel\"],\"cc-exp-month\":n,\"cc-exp-year\":n,\"transaction-amount\":n,\"bday-day\":n,\"bday-month\":n,\"bday-year\":n,\"new-password\":[\"text\",\"search\",\"password\"],\"current-password\":[\"text\",\"search\",\"password\"],url:o,photo:o,impp:o};\"object\"===(void 0===t?\"undefined\":T(t))&&Object.keys(t).forEach(function(e){i[e]||(i[e]=[]),i[e]=i[e].concat(t[e])});var s=e.getAttribute(\"autocomplete\").split(/\\s+/g).map(function(e){return e.toLowerCase()}),l=s[s.length-1];if(axe.commons.text.autocomplete.stateTerms.includes(l))return!0;var u=i[l];return void 0===u?\"text\"===e.type:u.includes(e.type)}},{id:\"autocomplete-valid\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"autocomplete\")||\"\";return axe.commons.text.isValidAutocomplete(n,t)}},{id:\"fieldset\",evaluate:function(e,t,r,a){var s,l=this;function u(e,t){return axe.commons.utils.toArray(e.querySelectorAll('select,textarea,button,input:not([name=\"'+t+'\"]):not([type=\"hidden\"])'))}var n={name:e.getAttribute(\"name\"),type:e.getAttribute(\"type\")},o=function(e){var t=axe.commons.utils.escapeSelector(e.actualNode.name),r=axe.commons.dom.getRootNode(e.actualNode).querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(e.actualNode.type)+'\"][name=\"'+t+'\"]');if(r.length<2)return!0;var a,n,o=axe.commons.dom.findUpVirtual(e,\"fieldset\"),i=axe.commons.dom.findUpVirtual(e,'[role=\"group\"]'+(\"radio\"===e.actualNode.type?',[role=\"radiogroup\"]':\"\"));return i||o?o?function(e,t){var r=e.firstElementChild;if(!r||\"LEGEND\"!==r.nodeName.toUpperCase())return l.relatedNodes([e]),!(s=\"no-legend\");if(!axe.commons.text.accessibleText(r))return l.relatedNodes([r]),!(s=\"empty-legend\");var a=u(e,t);return!(a.length&&(l.relatedNodes(a),s=\"mixed-inputs\"))}(o,t):function(e,t){var r=axe.commons.dom.idrefs(e,\"aria-labelledby\").some(function(e){return e&&axe.commons.text.accessibleText(e)}),a=e.getAttribute(\"aria-label\");if(!(r||a&&axe.commons.text.sanitize(a)))return l.relatedNodes(e),!(s=\"no-group-label\");var n=u(e,t);return!(n.length&&(l.relatedNodes(n),s=\"group-mixed-inputs\"))}(i,t):(s=\"no-group\",l.relatedNodes((a=r,n=e.actualNode,axe.commons.utils.toArray(a).filter(function(e){return e!==n}))),!1)}(r);return o||(n.failureCode=s),this.data(n),o},after:function(e,t){var a={};return e.filter(function(e){if(e.result)return!0;var t=e.data;if(t){if(a[t.type]=a[t.type]||{},!a[t.type][t.name])return a[t.type][t.name]=[t],!0;var r=a[t.type][t.name].some(function(e){return e.failureCode===t.failureCode});return r||a[t.type][t.name].push(t),!r}return!1})}},{id:\"group-labelledby\",evaluate:function(e,t,r,a){this.data({name:e.getAttribute(\"name\"),type:e.getAttribute(\"type\")});var n=axe.commons.dom.getRootNode(e),o=n.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(e.type)+'\"][name=\"'+axe.commons.utils.escapeSelector(e.name)+'\"]');return o.length<=1||0!==[].map.call(o,function(e){var t=e.getAttribute(\"aria-labelledby\");return t?t.split(/\\s+/):[]}).reduce(function(e,t){return e.filter(function(e){return t.includes(e)})}).filter(function(e){var t=n.getElementById(e);return t&&axe.commons.text.accessibleText(t,!0)}).length},after:function(e,t){var r={};return e.filter(function(e){var t=e.data;return!(!t||(r[t.type]=r[t.type]||{},r[t.type][t.name]))&&(r[t.type][t.name]=!0)})}},{id:\"accesskeys\",evaluate:function(e,t,r,a){return axe.commons.dom.isVisible(e,!1)&&(this.data(e.getAttribute(\"accesskey\")),this.relatedNodes([e])),!0},after:function(e,t){var r={};return e.filter(function(e){if(!e.data)return!1;var t=e.data.toUpperCase();return r[t]?(r[t].relatedNodes.push(e.relatedNodes[0]),!1):((r[t]=e).relatedNodes=[],!0)}).map(function(e){return e.result=!!e.relatedNodes.length,e})}},{id:\"focusable-no-name\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"tabindex\");return!!(axe.commons.dom.isFocusable(e)&&-1<n)&&!axe.commons.text.accessibleTextVirtual(r)}},{id:\"landmark-is-top-level\",evaluate:function(e,t,r,a){var n=axe.commons.aria.getRolesByType(\"landmark\"),o=axe.commons.dom.getComposedParent(e);for(this.data({role:e.getAttribute(\"role\")||axe.commons.aria.implicitRole(e)});o;){var i=o.getAttribute(\"role\");if(i||\"form\"===o.tagName.toLowerCase()||(i=axe.commons.aria.implicitRole(o)),i&&n.includes(i))return!1;o=axe.commons.dom.getComposedParent(o)}return!0}},{id:\"page-has-heading-one\",evaluate:function(e,t,r,a){if(!t||!t.selector||\"string\"!=typeof t.selector)throw new TypeError(\"visible-in-page requires options.selector to be a string\");var n=axe.utils.querySelectorAll(r,t.selector);return this.relatedNodes(n.map(function(e){return e.actualNode})),0<n.length},after:function(e,t){return e.some(function(e){return!0===e.result})&&e.forEach(function(e){e.result=!0}),e},options:{selector:'h1:not([role]), [role=\"heading\"][aria-level=\"1\"]'}},{id:\"page-has-main\",evaluate:function(e,t,r,a){if(!t||!t.selector||\"string\"!=typeof t.selector)throw new TypeError(\"visible-in-page requires options.selector to be a string\");var n=axe.utils.querySelectorAll(r,t.selector);return this.relatedNodes(n.map(function(e){return e.actualNode})),0<n.length},after:function(e,t){return e.some(function(e){return!0===e.result})&&e.forEach(function(e){e.result=!0}),e},options:{selector:\"main:not([role]), [role='main']\"}},{id:\"page-no-duplicate-banner\",evaluate:function(e,t,r,a){if(!t||!t.selector||\"string\"!=typeof t.selector)throw new TypeError(\"visible-in-page requires options.selector to be a string\");var n=axe.utils.querySelectorAll(r,t.selector);return\"string\"==typeof t.nativeScopeFilter&&(n=n.filter(function(e){return e.actualNode.hasAttribute(\"role\")||!axe.commons.dom.findUpVirtual(e,t.nativeScopeFilter)})),this.relatedNodes(n.map(function(e){return e.actualNode})),n.length<=1},options:{selector:\"header:not([role]), [role=banner]\",nativeScopeFilter:\"article, aside, main, nav, section\"}},{id:\"page-no-duplicate-contentinfo\",evaluate:function(e,t,r,a){if(!t||!t.selector||\"string\"!=typeof t.selector)throw new TypeError(\"visible-in-page requires options.selector to be a string\");var n=axe.utils.querySelectorAll(r,t.selector);return\"string\"==typeof t.nativeScopeFilter&&(n=n.filter(function(e){return e.actualNode.hasAttribute(\"role\")||!axe.commons.dom.findUpVirtual(e,t.nativeScopeFilter)})),this.relatedNodes(n.map(function(e){return e.actualNode})),n.length<=1},options:{selector:\"footer:not([role]), [role=contentinfo]\",nativeScopeFilter:\"article, aside, main, nav, section\"}},{id:\"page-no-duplicate-main\",evaluate:function(e,t,r,a){if(!t||!t.selector||\"string\"!=typeof t.selector)throw new TypeError(\"visible-in-page requires options.selector to be a string\");var n=axe.utils.querySelectorAll(r,t.selector);return\"string\"==typeof t.nativeScopeFilter&&(n=n.filter(function(e){return e.actualNode.hasAttribute(\"role\")||!axe.commons.dom.findUpVirtual(e,t.nativeScopeFilter)})),this.relatedNodes(n.map(function(e){return e.actualNode})),n.length<=1},options:{selector:\"main:not([role]), [role='main']\"}},{id:\"tabindex\",evaluate:function(e,t,r,a){return e.tabIndex<=0}},{id:\"duplicate-img-label\",evaluate:function(e,t,r,a){var n=axe.commons.text.visibleVirtual(r,!0).toLowerCase();return\"\"!==n&&axe.utils.querySelectorAll(r,\"img\").filter(function(e){var t=e.actualNode;return axe.commons.dom.isVisible(t)&&![\"none\",\"presentation\"].includes(t.getAttribute(\"role\"))}).some(function(e){return n===axe.commons.text.accessibleTextVirtual(e).toLowerCase()})}},{id:\"explicit-label\",evaluate:function(e,t,r,a){if(e.getAttribute(\"id\")){var n=axe.commons.dom.getRootNode(e),o=axe.commons.utils.escapeSelector(e.getAttribute(\"id\")),i=n.querySelector('label[for=\"'+o+'\"]');if(i)return!axe.commons.dom.isVisible(i)||!!axe.commons.text.accessibleText(i)}return!1}},{id:\"help-same-as-label\",evaluate:function(e,t,r,a){var n=axe.commons.text.labelVirtual(r),o=e.getAttribute(\"title\");if(!n)return!1;o||(o=\"\",e.getAttribute(\"aria-describedby\")&&(o=axe.commons.dom.idrefs(e,\"aria-describedby\").map(function(e){return e?axe.commons.text.accessibleText(e):\"\"}).join(\"\")));return axe.commons.text.sanitize(o)===axe.commons.text.sanitize(n)},enabled:!1},{id:\"hidden-explicit-label\",evaluate:function(e,t,r,a){if(e.getAttribute(\"id\")){var n=axe.commons.dom.getRootNode(e),o=axe.commons.utils.escapeSelector(e.getAttribute(\"id\")),i=n.querySelector('label[for=\"'+o+'\"]');if(i&&!axe.commons.dom.isVisible(i))return!0}return!1}},{id:\"implicit-label\",evaluate:function(e,t,r,a){var n=axe.commons.dom.findUpVirtual(r,\"label\");return!!n&&!!axe.commons.text.accessibleTextVirtual(n)}},{id:\"multiple-label\",evaluate:function(e,t,r,a){var n=axe.commons.utils.escapeSelector(e.getAttribute(\"id\")),o=Array.from(document.querySelectorAll('label[for=\"'+n+'\"]')),i=e.parentNode;for(o.length&&(o=o.filter(function(e,t){if(0===t&&!axe.commons.dom.isVisible(e,!0)||axe.commons.dom.isVisible(e,!0))return e}));i;)\"LABEL\"===i.tagName&&-1===o.indexOf(i)&&o.push(i),i=i.parentNode;return this.relatedNodes(o),1<o.length}},{id:\"title-only\",evaluate:function(e,t,r,a){return!(axe.commons.text.labelVirtual(r)||!e.getAttribute(\"title\")&&!e.getAttribute(\"aria-describedby\"))}},{id:\"has-lang\",evaluate:function(e,t,r,a){return!!(e.getAttribute(\"lang\")||e.getAttribute(\"xml:lang\")||\"\").trim()}},{id:\"valid-lang\",evaluate:function(n,e,t,r){var o,a;return o=(e||axe.commons.utils.validLangs()).map(axe.commons.utils.getBaseLang),!!(a=[\"lang\",\"xml:lang\"].reduce(function(e,t){var r=n.getAttribute(t);if(\"string\"!=typeof r)return e;var a=axe.commons.utils.getBaseLang(r);return\"\"!==a&&-1===o.indexOf(a)&&e.push(t+'=\"'+n.getAttribute(t)+'\"'),e},[])).length&&(this.data(a),!0)}},{id:\"xml-lang-mismatch\",evaluate:function(e,t,r,a){var n=axe.commons.utils.getBaseLang;return n(e.getAttribute(\"lang\"))===n(e.getAttribute(\"xml:lang\"))}},{id:\"dlitem\",evaluate:function(e,t,r,a){var n=axe.commons.dom.getComposedParent(e);if(\"DL\"!==n.nodeName.toUpperCase())return!1;var o=(n.getAttribute(\"role\")||\"\").toLowerCase();return!o||!axe.commons.aria.isValidRole(o)||\"list\"===o}},{id:\"has-listitem\",evaluate:function(e,t,r,a){return r.children.every(function(e){return\"LI\"!==e.actualNode.nodeName.toUpperCase()})}},{id:\"listitem\",evaluate:function(e,t,r,a){var n=axe.commons.dom.getComposedParent(e);if(n){var o=n.nodeName.toUpperCase(),i=(n.getAttribute(\"role\")||\"\").toLowerCase();return\"list\"===i||(!i||!axe.commons.aria.isValidRole(i))&&[\"UL\",\"OL\"].includes(o)}}},{id:\"only-dlitems\",evaluate:function(e,t,r,a){var n=axe.commons,o=n.dom,i=n.aria,s=[\"definition\",\"term\",\"list\"],l=r.children.reduce(function(e,t){var r=t.actualNode;return\"DIV\"===r.nodeName.toUpperCase()&&null===i.getRole(r)?e.concat(t.children):e.concat(t)},[]).reduce(function(e,t){var r=t.actualNode,a=r.nodeName.toUpperCase();if(1===r.nodeType&&o.isVisible(r,!0,!1)){var n=i.getRole(r,{noImplicit:!0});(\"DT\"!==a&&\"DD\"!==a||n)&&(s.includes(n)||e.badNodes.push(r))}else 3===r.nodeType&&\"\"!==r.nodeValue.trim()&&(e.hasNonEmptyTextNode=!0);return e},{badNodes:[],hasNonEmptyTextNode:!1});return l.badNodes.length&&this.relatedNodes(l.badNodes),!!l.badNodes.length||l.hasNonEmptyTextNode}},{id:\"only-listitems\",evaluate:function(e,t,r,a){var d=axe.commons.dom,n=r.children.reduce(function(e,t){var r,a,n,o,i,s=t.actualNode,l=s.nodeName.toUpperCase();if(1===s.nodeType&&d.isVisible(s,!0,!1)){var u=(s.getAttribute(\"role\")||\"\").toLowerCase(),c=(i=l,\"listitem\"===(o=u)||\"LI\"===i&&!o);e.hasListItem=(r=e.hasListItem,a=l,n=c,r||\"LI\"===a&&n||n),c&&(e.isEmpty=!1),\"LI\"!==l||c||e.liItemsWithRole++,\"LI\"===l||c||e.badNodes.push(s)}return 3===s.nodeType&&\"\"!==s.nodeValue.trim()&&(e.hasNonEmptyTextNode=!0),e},{badNodes:[],isEmpty:!0,hasNonEmptyTextNode:!1,hasListItem:!1,liItemsWithRole:0}),o=r.children.filter(function(e){return\"LI\"===e.actualNode.nodeName.toUpperCase()}),i=0<n.liItemsWithRole&&o.length===n.liItemsWithRole;return n.badNodes.length&&this.relatedNodes(n.badNodes),!(n.hasListItem||n.isEmpty&&!i)||!!n.badNodes.length||n.hasNonEmptyTextNode}},{id:\"structured-dlitems\",evaluate:function(e,t,r,a){var n=r.children;if(!n||!n.length)return!1;for(var o,i=!1,s=!1,l=0;l<n.length;l++){if(\"DT\"===(o=n[l].actualNode.nodeName.toUpperCase())&&(i=!0),i&&\"DD\"===o)return!1;\"DD\"===o&&(s=!0)}return i||s}},{id:\"caption\",evaluate:function(e,t,r,a){return!axe.utils.querySelectorAll(r,\"track\").some(function(e){return\"captions\"===(e.actualNode.getAttribute(\"kind\")||\"\").toLowerCase()})&&void 0}},{id:\"description\",evaluate:function(e,t,r,a){return!axe.utils.querySelectorAll(r,\"track\").some(function(e){return\"descriptions\"===(e.actualNode.getAttribute(\"kind\")||\"\").toLowerCase()})&&void 0}},{id:\"frame-tested\",evaluate:function(e,t,r,a){var n=this.async(),o=Object.assign({isViolation:!1,timeout:500},t),i=o.isViolation,s=o.timeout,l=setTimeout(function(){l=setTimeout(function(){l=null,n(!i&&void 0)},0)},s);axe.utils.respondable(e.contentWindow,\"axe.ping\",null,void 0,function(){null!==l&&(clearTimeout(l),n(!0))})},options:{isViolation:!1}},{id:\"css-orientation-lock\",evaluate:function(e,t,r,a){var n=(a||{}).cssom,o=void 0===n?void 0:n;if(o&&o.length){var i=o.reduce(function(e,t){var r=t.sheet,a=t.root,n=t.shadowId,o=n||\"topDocument\";if(e[o]||(e[o]={root:a,rules:[]}),!r||!r.cssRules)return e;var i=Array.from(r.cssRules);return e[o].rules=e[o].rules.concat(i),e},{}),l=!1,u=[];return Object.keys(i).forEach(function(e){var t=i[e],s=t.root,r=t.rules.filter(function(e){return 4===e.type});if(r&&r.length){var a=r.filter(function(e){var t=e.cssText;return/orientation:\\s+landscape/i.test(t)||/orientation:\\s+portrait/i.test(t)});a&&a.length&&a.forEach(function(e){e.cssRules.length&&Array.from(e.cssRules).forEach(function(e){if(e.selectorText&&!(e.style.length<=0)){var t=e.style.transform||!1;if(t){var r=t.match(/rotate\\(([^)]+)deg\\)/),a=parseInt(r&&r[1]||0),n=a%90==0&&a%180!=0;if(n&&\"HTML\"!==e.selectorText.toUpperCase()){var o=e.selectorText,i=Array.from(s.querySelectorAll(o));i&&i.length&&(u=u.concat(i))}l=n}}})})}}),l?(u.length&&this.relatedNodes(u),!1):!0}}},{id:\"meta-viewport-large\",evaluate:function(e,t,r,a){t=t||{};for(var n,o=(e.getAttribute(\"content\")||\"\").split(/[;,]/),i={},s=t.scaleMinimum||2,l=t.lowerBound||!1,u=0,c=o.length;u<c;u++){var d=(n=o[u].split(\"=\")).shift().toLowerCase();d&&n.length&&(i[d.trim()]=n.shift().trim().toLowerCase())}return!!(l&&i[\"maximum-scale\"]&&parseFloat(i[\"maximum-scale\"])<l)||(l||\"no\"!==i[\"user-scalable\"]?!(i[\"maximum-scale\"]&&parseFloat(i[\"maximum-scale\"])<s)||(this.data(\"maximum-scale\"),!1):(this.data(\"user-scalable=no\"),!1))},options:{scaleMinimum:5,lowerBound:2}},{id:\"meta-viewport\",evaluate:function(e,t,r,a){t=t||{};for(var n,o=(e.getAttribute(\"content\")||\"\").split(/[;,]/),i={},s=t.scaleMinimum||2,l=t.lowerBound||!1,u=0,c=o.length;u<c;u++){var d=(n=o[u].split(\"=\")).shift().toLowerCase();d&&n.length&&(i[d.trim()]=n.shift().trim().toLowerCase())}return!!(l&&i[\"maximum-scale\"]&&parseFloat(i[\"maximum-scale\"])<l)||(l||\"no\"!==i[\"user-scalable\"]?!(i[\"maximum-scale\"]&&parseFloat(i[\"maximum-scale\"])<s)||(this.data(\"maximum-scale\"),!1):(this.data(\"user-scalable=no\"),!1))},options:{scaleMinimum:2}},{id:\"header-present\",evaluate:function(e,t,r,a){return!!axe.utils.querySelectorAll(r,'h1, h2, h3, h4, h5, h6, [role=\"heading\"]')[0]}},{id:\"heading-order\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"aria-level\");if(null!==n)return this.data(parseInt(n,10)),!0;var o=e.tagName.match(/H(\\d)/);return o&&this.data(parseInt(o[1],10)),!0},after:function(e,t){if(e.length<2)return e;for(var r=e[0].data,a=1;a<e.length;a++)e[a].result&&e[a].data>r+1&&(e[a].result=!1),r=e[a].data;return e}},{id:\"internal-link-present\",evaluate:function(e,t,r,a){return axe.utils.querySelectorAll(r,\"a[href]\").some(function(e){return/^#[^/!]/.test(e.actualNode.getAttribute(\"href\"))})}},{id:\"landmark\",evaluate:function(e,t,r,a){return 0<axe.utils.querySelectorAll(r,'main, [role=\"main\"]').length}},{id:\"meta-refresh\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"content\")||\"\",o=n.split(/[;,]/);return\"\"===n||\"0\"===o[0]}},{id:\"p-as-heading\",evaluate:function(e,t,r,a){var n=Array.from(e.parentNode.children),o=n.indexOf(e),i=(t=t||{}).margins||[],s=n.slice(o+1).find(function(e){return\"P\"===e.nodeName.toUpperCase()}),l=n.slice(0,o).reverse().find(function(e){return\"P\"===e.nodeName.toUpperCase()});function u(e){var t=window.getComputedStyle(function(e){for(var t=e,r=e.textContent.trim(),a=r;a===r&&void 0!==t;){var n=-1;if(0===(e=t).children.length)return e;for(;n++,\"\"===(a=e.children[n].textContent.trim())&&n+1<e.children.length;);t=e.children[n]}return e}(e));return{fontWeight:function(e){switch(e){case\"lighter\":return 100;case\"normal\":return 400;case\"bold\":return 700;case\"bolder\":return 900}return e=parseInt(e),isNaN(e)?400:e}(t.getPropertyValue(\"font-weight\")),fontSize:parseInt(t.getPropertyValue(\"font-size\")),isItalic:\"italic\"===t.getPropertyValue(\"font-style\")}}function c(r,a,e){return e.reduce(function(e,t){return e||(!t.size||r.fontSize/t.size>a.fontSize)&&(!t.weight||r.fontWeight-t.weight>a.fontWeight)&&(!t.italic||r.isItalic&&!a.isItalic)},!1)}var d=u(e),m=s?u(s):null,p=l?u(l):null;if(!m||!c(d,m,i))return!0;var f=axe.commons.dom.findUpVirtual(r,\"blockquote\");return!!(f&&\"BLOCKQUOTE\"===f.nodeName.toUpperCase()||p&&!c(d,p,i))&&void 0},options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]}},{id:\"region\",evaluate:function(e,t,r,a){var n=axe.commons,l=n.dom,u=n.aria;var c=function(e){var t=axe.utils.querySelectorAll(e,\"a[href]\")[0];if(t&&axe.commons.dom.getElementByReference(t.actualNode,\"href\"))return t.actualNode}(r),d=u.getRolesByType(\"landmark\"),m=d.reduce(function(e,t){return e.concat(u.implicitNodes(t))},[]).filter(function(e){return null!==e});var o=function e(t){var r,n,o,a,i,s=t.actualNode;return o=(n=t).actualNode,a=axe.commons.aria.getRole(o,{noImplicit:!0}),i=(o.getAttribute(\"aria-live\")||\"\").toLowerCase().trim(),(a?\"dialog\"===a||d.includes(a):[\"assertive\",\"polite\"].includes(i)||m.some(function(e){var t=axe.utils.matchesSelector(o,e);if(\"form\"!==o.tagName.toLowerCase())return t;var r=o.getAttribute(\"title\"),a=r&&\"\"!==r.trim()?axe.commons.text.sanitize(r):null;return t&&(!!u.labelVirtual(n)||!!a)}))||(r=t,c&&c===r.actualNode)||!l.isVisible(s,!0)?[]:l.hasContent(s,!0)?[s]:t.children.filter(function(e){return 1===e.actualNode.nodeType}).map(e).reduce(function(e,t){return e.concat(t)},[])}(r);return this.relatedNodes(o),0===o.length},after:function(e,t){return[e[0]]}},{id:\"skip-link\",evaluate:function(e,t,r,a){var n=axe.commons.dom.getElementByReference(e,\"href\");return!!n&&(axe.commons.dom.isVisible(n,!0)||void 0)}},{id:\"unique-frame-title\",evaluate:function(e,t,r,a){var n=axe.commons.text.sanitize(e.title).trim().toLowerCase();return this.data(n),!0},after:function(e,t){var r={};return e.forEach(function(e){r[e.data]=void 0!==r[e.data]?++r[e.data]:0}),e.forEach(function(e){e.result=!!r[e.data]}),e}},{id:\"duplicate-id-active\",evaluate:function(t,e,r,a){var n=t.getAttribute(\"id\").trim();if(!n)return!0;var o=axe.commons.dom.getRootNode(t),i=Array.from(o.querySelectorAll('[id=\"'+axe.commons.utils.escapeSelector(n)+'\"]')).filter(function(e){return e!==t});return i.length&&this.relatedNodes(i),this.data(n),0===i.length},after:function(e,t){var r=[];return e.filter(function(e){return-1===r.indexOf(e.data)&&(r.push(e.data),!0)})}},{id:\"duplicate-id-aria\",evaluate:function(t,e,r,a){var n=t.getAttribute(\"id\").trim();if(!n)return!0;var o=axe.commons.dom.getRootNode(t),i=Array.from(o.querySelectorAll('[id=\"'+axe.commons.utils.escapeSelector(n)+'\"]')).filter(function(e){return e!==t});return i.length&&this.relatedNodes(i),this.data(n),0===i.length},after:function(e,t){var r=[];return e.filter(function(e){return-1===r.indexOf(e.data)&&(r.push(e.data),!0)})}},{id:\"duplicate-id\",evaluate:function(t,e,r,a){var n=t.getAttribute(\"id\").trim();if(!n)return!0;var o=axe.commons.dom.getRootNode(t),i=Array.from(o.querySelectorAll('[id=\"'+axe.commons.utils.escapeSelector(n)+'\"]')).filter(function(e){return e!==t});return i.length&&this.relatedNodes(i),this.data(n),0===i.length},after:function(e,t){var r=[];return e.filter(function(e){return-1===r.indexOf(e.data)&&(r.push(e.data),!0)})}},{id:\"aria-label\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"aria-label\");return!(!n||!axe.commons.text.sanitize(n).trim())}},{id:\"aria-labelledby\",evaluate:function(e,t,r,a){return(0,axe.commons.dom.idrefs)(e,\"aria-labelledby\").some(function(e){return e&&axe.commons.text.accessibleText(e,!0)})}},{id:\"button-has-visible-text\",evaluate:function(e,t,r,a){var n=e.nodeName.toUpperCase(),o=e.getAttribute(\"role\"),i=void 0;return(\"BUTTON\"===n||\"button\"===o&&\"INPUT\"!==n)&&(i=axe.commons.text.accessibleTextVirtual(r),this.data(i),!!i)}},{id:\"doc-has-title\",evaluate:function(e,t,r,a){var n=document.title;return!(!n||!axe.commons.text.sanitize(n).trim())}},{id:\"exists\",evaluate:function(e,t,r,a){return!0}},{id:\"has-alt\",evaluate:function(e,t,r,a){var n=e.nodeName.toLowerCase();return e.hasAttribute(\"alt\")&&(\"img\"===n||\"input\"===n||\"area\"===n)}},{id:\"has-visible-text\",evaluate:function(e,t,r,a){return 0<axe.commons.text.accessibleTextVirtual(r).length}},{id:\"is-on-screen\",evaluate:function(e,t,r,a){return axe.commons.dom.isVisible(e,!1)&&!axe.commons.dom.isOffscreen(e)}},{id:\"non-empty-alt\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"alt\");return!(!n||!axe.commons.text.sanitize(n).trim())}},{id:\"non-empty-if-present\",evaluate:function(e,t,r,a){var n=e.nodeName.toUpperCase(),o=(e.getAttribute(\"type\")||\"\").toLowerCase(),i=e.getAttribute(\"value\");return this.data(i),!(\"INPUT\"!==n||![\"submit\",\"reset\"].includes(o))&&null===i}},{id:\"non-empty-title\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"title\");return!(!n||!axe.commons.text.sanitize(n).trim())}},{id:\"non-empty-value\",evaluate:function(e,t,r,a){var n=e.getAttribute(\"value\");return!(!n||!axe.commons.text.sanitize(n).trim())}},{id:\"role-none\",evaluate:function(e,t,r,a){return\"none\"===e.getAttribute(\"role\")}},{id:\"role-presentation\",evaluate:function(e,t,r,a){return\"presentation\"===e.getAttribute(\"role\")}},{id:\"caption-faked\",evaluate:function(e,t,r,a){var n=axe.commons.table.toGrid(e),o=n[0];return n.length<=1||o.length<=1||e.rows.length<=1||o.reduce(function(e,t,r){return e||t!==o[r+1]&&void 0!==o[r+1]},!1)}},{id:\"has-caption\",evaluate:function(e,t,r,a){return!!e.caption}},{id:\"has-summary\",evaluate:function(e,t,r,a){return!!e.summary}},{id:\"has-th\",evaluate:function(e,t,r,a){for(var n,o,i=[],s=0,l=e.rows.length;s<l;s++)for(var u=0,c=(n=e.rows[s]).cells.length;u<c;u++)\"TH\"!==(o=n.cells[u]).nodeName.toUpperCase()&&-1===[\"rowheader\",\"columnheader\"].indexOf(o.getAttribute(\"role\"))||i.push(o);return!!i.length&&(this.relatedNodes(i),!0)}},{id:\"html5-scope\",evaluate:function(e,t,r,a){return!axe.commons.dom.isHTML5(document)||\"TH\"===e.nodeName.toUpperCase()}},{id:\"same-caption-summary\",evaluate:function(e,t,r,a){return!(!e.summary||!e.caption)&&e.summary.toLowerCase()===axe.commons.text.accessibleText(e.caption).toLowerCase()}},{id:\"scope-value\",evaluate:function(e,t,r,a){t=t||{};var n=e.getAttribute(\"scope\").toLowerCase();return-1!==[\"row\",\"col\",\"rowgroup\",\"colgroup\"].indexOf(n)}},{id:\"td-has-header\",evaluate:function(e,t,r,a){var n=axe.commons.table,o=[];return n.getAllCells(e).forEach(function(e){axe.commons.dom.hasContent(e)&&n.isDataCell(e)&&!axe.commons.aria.label(e)&&(n.getHeaders(e).some(function(e){return null!==e&&!!axe.commons.dom.hasContent(e)})||o.push(e))}),!o.length||(this.relatedNodes(o),!1)}},{id:\"td-headers-attr\",evaluate:function(e,t,r,a){for(var n=[],o=0,i=e.rows.length;o<i;o++)for(var s=e.rows[o],l=0,u=s.cells.length;l<u;l++)n.push(s.cells[l]);var c=n.reduce(function(e,t){return t.getAttribute(\"id\")&&e.push(t.getAttribute(\"id\")),e},[]),d=n.reduce(function(e,t){var r,a,n=(t.getAttribute(\"headers\")||\"\").split(/\\s/).reduce(function(e,t){return(t=t.trim())&&e.push(t),e},[]);return 0!==n.length&&(t.getAttribute(\"id\")&&(r=-1!==n.indexOf(t.getAttribute(\"id\").trim())),a=n.reduce(function(e,t){return e||-1===c.indexOf(t)},!1),(r||a)&&e.push(t)),e},[]);return!(0<d.length)||(this.relatedNodes(d),!1)}},{id:\"th-has-data-cells\",evaluate:function(e,t,r,a){var n=axe.commons.table,o=n.getAllCells(e),i=this,s=[];o.forEach(function(e){var t=e.getAttribute(\"headers\");t&&(s=s.concat(t.split(/\\s+/)));var r=e.getAttribute(\"aria-labelledby\");r&&(s=s.concat(r.split(/\\s+/)))});var l=o.filter(function(e){return\"\"!==axe.commons.text.sanitize(e.textContent)&&(\"TH\"===e.nodeName.toUpperCase()||-1!==[\"rowheader\",\"columnheader\"].indexOf(e.getAttribute(\"role\")))}),u=n.toGrid(e);return!!l.reduce(function(e,t){if(t.getAttribute(\"id\")&&s.includes(t.getAttribute(\"id\")))return!!e||e;var r=!1,a=n.getCellPosition(t,u);return n.isColumnHeader(t)&&(r=n.traverse(\"down\",a,u).reduce(function(e,t){return e||axe.commons.dom.hasContent(t)&&!n.isColumnHeader(t)},!1)),!r&&n.isRowHeader(t)&&(r=n.traverse(\"right\",a,u).reduce(function(e,t){return e||axe.commons.dom.hasContent(t)&&!n.isRowHeader(t)},!1)),r||i.relatedNodes(t),e&&r},!0)||void 0}},{id:\"hidden-content\",evaluate:function(e,t,r,a){if(![\"SCRIPT\",\"HEAD\",\"TITLE\",\"NOSCRIPT\",\"STYLE\",\"TEMPLATE\"].includes(e.tagName.toUpperCase())&&axe.commons.dom.hasContentVirtual(r)){var n=window.getComputedStyle(e);if(\"none\"===n.getPropertyValue(\"display\"))return;if(\"hidden\"===n.getPropertyValue(\"visibility\")){var o=axe.commons.dom.getComposedParent(e),i=o&&window.getComputedStyle(o);if(!i||\"hidden\"!==i.getPropertyValue(\"visibility\"))return}}return!0}}],commons:function(){var commons={},u=commons.aria={},e=u.lookupTable={};e.attributes={\"aria-activedescendant\":{type:\"idref\"},\"aria-atomic\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-autocomplete\":{type:\"nmtoken\",values:[\"inline\",\"list\",\"both\",\"none\"]},\"aria-busy\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-checked\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-colcount\":{type:\"int\"},\"aria-colindex\":{type:\"int\"},\"aria-colspan\":{type:\"int\"},\"aria-controls\":{type:\"idrefs\"},\"aria-current\":{type:\"nmtoken\",values:[\"page\",\"step\",\"location\",\"date\",\"time\",\"true\",\"false\"]},\"aria-describedby\":{type:\"idrefs\"},\"aria-disabled\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-dropeffect\":{type:\"nmtokens\",values:[\"copy\",\"move\",\"reference\",\"execute\",\"popup\",\"none\"]},\"aria-errormessage\":{type:\"idref\"},\"aria-expanded\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-flowto\":{type:\"idrefs\"},\"aria-grabbed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-haspopup\":{type:\"nmtoken\",values:[\"true\",\"false\",\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"]},\"aria-hidden\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-invalid\":{type:\"nmtoken\",values:[\"true\",\"false\",\"spelling\",\"grammar\"]},\"aria-keyshortcuts\":{type:\"string\"},\"aria-label\":{type:\"string\"},\"aria-labelledby\":{type:\"idrefs\"},\"aria-level\":{type:\"int\"},\"aria-live\":{type:\"nmtoken\",values:[\"off\",\"polite\",\"assertive\"]},\"aria-modal\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiline\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiselectable\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-orientation\":{type:\"nmtoken\",values:[\"horizontal\",\"vertical\"]},\"aria-owns\":{type:\"idrefs\"},\"aria-placeholder\":{type:\"string\"},\"aria-posinset\":{type:\"int\"},\"aria-pressed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-readonly\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-relevant\":{type:\"nmtokens\",values:[\"additions\",\"removals\",\"text\",\"all\"]},\"aria-required\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-rowcount\":{type:\"int\"},\"aria-rowindex\":{type:\"int\"},\"aria-rowspan\":{type:\"int\"},\"aria-selected\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-setsize\":{type:\"int\"},\"aria-sort\":{type:\"nmtoken\",values:[\"ascending\",\"descending\",\"other\",\"none\"]},\"aria-valuemax\":{type:\"decimal\"},\"aria-valuemin\":{type:\"decimal\"},\"aria-valuenow\":{type:\"decimal\"},\"aria-valuetext\":{type:\"string\"}},e.globalAttributes=[\"aria-atomic\",\"aria-busy\",\"aria-controls\",\"aria-current\",\"aria-describedby\",\"aria-disabled\",\"aria-dropeffect\",\"aria-flowto\",\"aria-grabbed\",\"aria-haspopup\",\"aria-hidden\",\"aria-invalid\",\"aria-keyshortcuts\",\"aria-label\",\"aria-labelledby\",\"aria-live\",\"aria-owns\",\"aria-relevant\"];var t={CANNOT_HAVE_LIST_ATTRIBUTE:function(e){return!Array.from(e.attributes).map(function(e){return e.name.toUpperCase()}).includes(\"LIST\")},CANNOT_HAVE_HREF_ATTRIBUTE:function(e){return!Array.from(e.attributes).map(function(e){return e.name.toUpperCase()}).includes(\"HREF\")},MUST_HAVE_HREF_ATTRIBUTE:function(e){return!!e.href},MUST_HAVE_SIZE_ATTRIBUTE_WITH_VALUE_GREATER_THAN_1:function(e){return!!Array.from(e.attributes).map(function(e){return e.name.toUpperCase()}).includes(\"SIZE\")&&1<Number(e.getAttribute(\"SIZE\"))},MUST_HAVE_ALT_ATTRIBUTE:function(e){return!!Array.from(e.attributes).map(function(e){return e.name.toUpperCase()}).includes(\"ALT\")},MUST_HAVE_ALT_ATTRIBUTE_WITH_VALUE:function(e){if(!Array.from(e.attributes).map(function(e){return e.name.toUpperCase()}).includes(\"ALT\"))return!1;var t=e.getAttribute(\"ALT\");return t&&0<t.length}};e.role={alert:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},alertdialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"DIALOG\",\"SECTION\"]},application:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ARTICLE\",\"AUDIO\",\"EMBED\",\"IFRAME\",\"OBJECT\",\"SECTION\",\"SVG\",\"VIDEO\"]},article:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"article\"],unsupported:!1},banner:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"header\"],unsupported:!1,allowedElements:[\"SECTION\"]},button:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-pressed\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"button\",'input[type=\"button\"]','input[type=\"image\"]','input[type=\"reset\"]','input[type=\"submit\"]',\"summary\"],unsupported:!1,allowedElements:[{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},cell:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-rowindex\",\"aria-rowspan\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"],unsupported:!1},checkbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-required\",\"aria-readonly\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"checkbox\"]'],unsupported:!1,allowedElements:[\"BUTTON\"]},columnheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"],unsupported:!1},combobox:{type:\"composite\",attributes:{allowed:[\"aria-autocomplete\",\"aria-required\",\"aria-activedescendant\",\"aria-orientation\",\"aria-errormessage\"],required:[\"aria-expanded\"]},owned:{all:[\"listbox\",\"textbox\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[{tagName:\"INPUT\",attributes:{TYPE:\"TEXT\"}}]},command:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},complementary:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"aside\"],unsupported:!1,allowedElements:[\"SECTION\"]},composite:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},contentinfo:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"footer\"],unsupported:!1,allowedElements:[\"SECTION\"]},definition:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dd\",\"dfn\"],unsupported:!1},dialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dialog\"],unsupported:!1,allowedElements:[\"SECTION\"]},directory:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[\"OL\",\"UL\"]},document:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"body\"],unsupported:!1,allowedElements:[\"ARTICLE\",\"EMBED\",\"IFRAME\",\"SECTION\",\"SVG\",\"OBJECT\"]},\"doc-abstract\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-acknowledgments\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-afterword\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-appendix\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-backlink\":{type:\"link\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},\"doc-biblioentry\":{type:\"listitem\",attributes:{allowed:[\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:[\"doc-bibliography\"],unsupported:!1,allowedElements:[\"LI\"]},\"doc-bibliography\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-biblioref\":{type:\"link\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},\"doc-chapter\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-colophon\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-conclusion\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-cover\":{type:\"img\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1},\"doc-credit\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-credits\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-dedication\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-endnote\":{type:\"listitem\",attributes:{allowed:[\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:[\"doc-endnotes\"],unsupported:!1,allowedElements:[\"LI\"]},\"doc-endnotes\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:[\"doc-endnote\"],namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-epigraph\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1},\"doc-epilogue\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-errata\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-example\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ASIDE\",\"SECTION\"]},\"doc-footnote\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ASIDE\",\"FOOTER\",\"HEADER\"]},\"doc-foreword\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-glossary\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:[\"term\",\"definition\"],namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"DL\"]},\"doc-glossref\":{type:\"link\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},\"doc-index\":{type:\"navigation\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"NAV\",\"SECTION\"]},\"doc-introduction\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-noteref\":{type:\"link\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},\"doc-notice\":{type:\"note\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-pagebreak\":{type:\"separator\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"HR\"]},\"doc-pagelist\":{type:\"navigation\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"NAV\",\"SECTION\"]},\"doc-part\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-preface\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-prologue\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-pullquote\":{type:\"none\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ASIDE\",\"SECTION\"]},\"doc-qna\":{type:\"section\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},\"doc-subtitle\":{type:\"sectionhead\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"H1\",\"H2\",\"H3\",\"H4\",\"H5\",\"H6\"]},\"doc-tip\":{type:\"note\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ASIDE\"]},\"doc-toc\":{type:\"navigation\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"NAV\",\"SECTION\"]},feed:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:{one:[\"article\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ARTICLE\",\"ASIDE\",\"SECTION\"]},figure:{type:\"structure\",unsupported:!0},form:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"form\"],unsupported:!1},grid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-colcount\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-rowcount\",\"aria-errormessage\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"],unsupported:!1},gridcell:{type:\"widget\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\",\"aria-readonly\",\"aria-required\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"],unsupported:!1},group:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"details\",\"optgroup\"],unsupported:!1,allowedElements:[\"DL\",\"FIGCAPTION\",\"FIELDSET\",\"FIGURE\",\"FOOTER\",\"HEADER\",\"OL\",\"UL\"]},heading:{type:\"structure\",attributes:{required:[\"aria-level\"],allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"],unsupported:!1},img:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"img\"],unsupported:!1,allowedElements:[\"EMBED\",\"IFRAME\",\"OBJECT\",\"SVG\"]},input:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},landmark:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},link:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"a[href]\"],unsupported:!1,allowedElements:[\"BUTTON\",{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}}]},list:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:{all:[\"listitem\"]},nameFrom:[\"author\"],context:null,implicit:[\"ol\",\"ul\",\"dl\"],unsupported:!1},listbox:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{all:[\"option\"]},nameFrom:[\"author\"],context:null,implicit:[\"select\"],unsupported:!1,allowedElements:[\"OL\",\"UL\"]},listitem:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"list\"],implicit:[\"li\",\"dt\"],unsupported:!1},log:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},main:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"main\"],unsupported:!1,allowedElements:[\"ARTICLE\",\"SECTION\"]},marquee:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},math:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"math\"],unsupported:!1},menu:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{one:[\"menuitem\",\"menuitemradio\",\"menuitemcheckbox\"]},nameFrom:[\"author\"],context:null,implicit:['menu[type=\"context\"]'],unsupported:!1,allowedElements:[\"OL\",\"UL\"]},menubar:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"OL\",\"UL\"]},menuitem:{type:\"widget\",attributes:{allowed:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"command\"]'],unsupported:!1,allowedElements:[\"BUTTON\",\"LI\",{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}},{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},menuitemcheckbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"checkbox\"]'],unsupported:!1,allowedElements:[\"BUTTON\",\"LI\",{tagName:\"INPUT\",attributes:{TYPE:\"CHECKBOX\"}},{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}},{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},menuitemradio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"radio\"]'],unsupported:!1,allowedElements:[\"BUTTON\",\"LI\",{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}},{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},navigation:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"nav\"],unsupported:!1,allowedElements:[\"SECTION\"]},none:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ARTICLE\",\"ASIDE\",\"DL\",\"EMBED\",\"FIGCAPTION\",\"FIELDSET\",\"FIGURE\",\"FOOTER\",\"FORM\",\"H1\",\"H2\",\"H3\",\"H4\",\"H5\",\"H6\",\"HEADER\",\"LI\",\"SECTION\",\"OL\",{tagName:\"IMG\",condition:t.MUST_HAVE_ALT_ATTRIBUTE}]},note:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ASIDE\"]},option:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-checked\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"listbox\"],implicit:[\"option\"],unsupported:!1,allowedElements:[\"BUTTON\",\"LI\",{tagName:\"INPUT\",attributes:{TYPE:\"CHECKBOX\"}},{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}},{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},presentation:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ARTICLE\",\"ASIDE\",\"DL\",\"EMBED\",\"FIGCAPTION\",\"FIELDSET\",\"FIGURE\",\"FOOTER\",\"FORM\",\"H1\",\"H2\",\"H3\",\"H4\",\"H5\",\"H6\",\"HEADER\",\"HR\",\"LI\",\"OL\",\"SECTION\",\"UL\",{tagName:\"IMG\",condition:t.MUST_HAVE_ALT_ATTRIBUTE}]},progressbar:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"progress\"],unsupported:!1},radio:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-required\",\"aria-errormessage\"],required:[\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"radio\"]'],unsupported:!1,allowedElements:[\"BUTTON\",\"LI\",{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}}]},radiogroup:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-required\",\"aria-expanded\",\"aria-readonly\",\"aria-errormessage\"]},owned:{all:[\"radio\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"OL\",\"UL\"]},range:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},region:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"section[aria-label]\",\"section[aria-labelledby]\",\"section[title]\"],unsupported:!1,allowedElements:[\"ARTICLE\",\"ASIDE\"]},roletype:{type:\"abstract\",unsupported:!1},row:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colindex\",\"aria-expanded\",\"aria-level\",\"aria-selected\",\"aria-rowindex\",\"aria-errormessage\"]},owned:{one:[\"cell\",\"columnheader\",\"rowheader\",\"gridcell\"]},nameFrom:[\"author\",\"contents\"],context:[\"rowgroup\",\"grid\",\"treegrid\",\"table\"],implicit:[\"tr\"],unsupported:!1},rowgroup:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-errormessage\"]},owned:{all:[\"row\"]},nameFrom:[\"author\",\"contents\"],context:[\"grid\",\"table\"],implicit:[\"tbody\",\"thead\",\"tfoot\"],unsupported:!1},rowheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"],unsupported:!1},scrollbar:{type:\"widget\",attributes:{required:[\"aria-controls\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"],allowed:[\"aria-valuetext\",\"aria-orientation\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1},search:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ASIDE\",\"FORM\",\"SECTION\"]},searchbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"search\"]'],unsupported:!1,allowedElements:[{tagName:\"INPUT\",attributes:{TYPE:\"TEXT\"}}]},section:{nameFrom:[\"author\",\"contents\"],type:\"abstract\",unsupported:!1},sectionhead:{nameFrom:[\"author\",\"contents\"],type:\"abstract\",unsupported:!1},select:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},separator:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-orientation\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\",\"aria-valuetext\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"hr\"],unsupported:!1,allowedElements:[\"LI\"]},slider:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-orientation\",\"aria-readonly\",\"aria-errormessage\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"range\"]'],unsupported:!1},spinbutton:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-required\",\"aria-readonly\",\"aria-errormessage\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"number\"]'],unsupported:!1,allowedElements:[{tagName:\"INPUT\",attributes:{TYPE:\"TEXT\"}}]},status:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"output\"],unsupported:!1,allowedElements:[\"SECTION\"]},structure:{type:\"abstract\",unsupported:!1},switch:{type:\"widget\",attributes:{allowed:[\"aria-errormessage\"],required:[\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[\"BUTTON\",{tagName:\"INPUT\",attributes:{TYPE:\"CHECKBOX\"}},{tagName:\"INPUT\",attributes:{TYPE:\"IMAGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}},{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},tab:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-expanded\",\"aria-setsize\",\"aria-posinset\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"tablist\"],unsupported:!1,allowedElements:[\"BUTTON\",\"H1\",\"H2\",\"H3\",\"H4\",\"H5\",\"H6\",\"LI\",{tagName:\"INPUT\",attributes:{TYPE:\"BUTTON\"}},{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},table:{type:\"structure\",attributes:{allowed:[\"aria-colcount\",\"aria-rowcount\",\"aria-errormessage\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"],unsupported:!1},tablist:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-orientation\",\"aria-errormessage\"]},owned:{all:[\"tab\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"OL\",\"UL\"]},tabpanel:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"SECTION\"]},term:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"dt\"],unsupported:!1},textbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"text\"]','input[type=\"email\"]','input[type=\"password\"]','input[type=\"tel\"]','input[type=\"url\"]',\"input:not([type])\",\"textarea\"],unsupported:!1},timer:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1},toolbar:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['menu[type=\"toolbar\"]'],unsupported:!1,allowedElements:[\"OL\",\"UL\"]},tooltip:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1},tree:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{all:[\"treeitem\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"OL\",\"UL\"]},treegrid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-required\",\"aria-rowcount\",\"aria-orientation\",\"aria-errormessage\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,unsupported:!1},treeitem:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"group\",\"tree\"],unsupported:!1,allowedElements:[\"LI\",{tagName:\"A\",condition:t.MUST_HAVE_HREF_ATTRIBUTE}]},widget:{type:\"abstract\",unsupported:!1},window:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1}},e.elementsAllowedNoRole=[{tagName:\"AREA\",condition:t.MUST_HAVE_HREF_ATTRIBUTE},\"BASE\",\"BODY\",\"CAPTION\",\"COL\",\"COLGROUP\",\"DATALIST\",\"DD\",\"DETAILS\",\"DT\",\"HEAD\",\"HTML\",{tagName:\"INPUT\",attributes:{TYPE:\"COLOR\"}},{tagName:\"INPUT\",attributes:{TYPE:\"DATE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"DATETIME\"}},{tagName:\"INPUT\",condition:t.CANNOT_HAVE_LIST_ATTRIBUTE,attributes:{TYPE:\"EMAIL\"}},{tagName:\"INPUT\",attributes:{TYPE:\"FILE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"HIDDEN\"}},{tagName:\"INPUT\",attributes:{TYPE:\"MONTH\"}},{tagName:\"INPUT\",attributes:{TYPE:\"NUMBER\"}},{tagName:\"INPUT\",attributes:{TYPE:\"PASSWORD\"}},{tagName:\"INPUT\",attributes:{TYPE:\"RANGE\"}},{tagName:\"INPUT\",attributes:{TYPE:\"RESET\"}},{tagName:\"INPUT\",condition:t.CANNOT_HAVE_LIST_ATTRIBUTE,attributes:{TYPE:\"SEARCH\"}},{tagName:\"INPUT\",attributes:{TYPE:\"SUBMIT\"}},{tagName:\"INPUT\",condition:t.CANNOT_HAVE_LIST_ATTRIBUTE,attributes:{TYPE:\"TEL\"}},{tagName:\"INPUT\",attributes:{TYPE:\"TIME\"}},{tagName:\"INPUT\",condition:t.CANNOT_HAVE_LIST_ATTRIBUTE,attributes:{TYPE:\"URL\"}},{tagName:\"INPUT\",attributes:{TYPE:\"WEEK\"}},\"KEYGEN\",\"LABEL\",\"LEGEND\",{tagName:\"LINK\",attributes:{TYPE:\"HREF\"}},\"MAIN\",\"MAP\",\"MATH\",{tagName:\"MENU\",attributes:{TYPE:\"CONTEXT\"}},{tagName:\"MENUITEM\",attributes:{TYPE:\"COMMAND\"}},{tagName:\"MENUITEM\",attributes:{TYPE:\"CHECKBOX\"}},{tagName:\"MENUITEM\",attributes:{TYPE:\"RADIO\"}},\"META\",\"METER\",\"NOSCRIPT\",\"OPTGROUP\",\"PARAM\",\"PICTURE\",\"PROGRESS\",\"SCRIPT\",{tagName:\"SELECT\",condition:t.MUST_HAVE_SIZE_ATTRIBUTE_WITH_VALUE_GREATER_THAN_1,attributes:{TYPE:\"MULTIPLE\"}},\"SOURCE\",\"STYLE\",\"TEMPLATE\",\"TEXTAREA\",\"TITLE\",\"TRACK\",\"CLIPPATH\",\"CURSOR\",\"DEFS\",\"DESC\",\"FEBLEND\",\"FECOLORMATRIX\",\"FECOMPONENTTRANSFER\",\"FECOMPOSITE\",\"FECONVOLVEMATRIX\",\"FEDIFFUSELIGHTING\",\"FEDISPLACEMENTMAP\",\"FEDISTANTLIGHT\",\"FEDROPSHADOW\",\"FEFLOOD\",\"FEFUNCA\",\"FEFUNCB\",\"FEFUNCG\",\"FEFUNCR\",\"FEGAUSSIANBLUR\",\"FEIMAGE\",\"FEMERGE\",\"FEMERGENODE\",\"FEMORPHOLOGY\",\"FEOFFSET\",\"FEPOINTLIGHT\",\"FESPECULARLIGHTING\",\"FESPOTLIGHT\",\"FETILE\",\"FETURBULENCE\",\"FILTER\",\"HATCH\",\"HATCHPATH\",\"LINEARGRADIENT\",\"MARKER\",\"MASK\",\"MESHGRADIENT\",\"MESHPATCH\",\"MESHROW\",\"METADATA\",\"MPATH\",\"PATTERN\",\"RADIALGRADIENT\",\"SOLIDCOLOR\",\"STOP\",\"SWITCH\",\"VIEW\"],e.elementsAllowedAnyRole=[{tagName:\"A\",condition:t.CANNOT_HAVE_HREF_ATTRIBUTE},\"ABBR\",\"ADDRESS\",\"CANVAS\",\"DIV\",\"P\",\"PRE\",\"BLOCKQUOTE\",\"INS\",\"DEL\",\"OUTPUT\",\"SPAN\",\"TABLE\",\"TBODY\",\"THEAD\",\"TFOOT\",\"TD\",\"EM\",\"STRONG\",\"SMALL\",\"S\",\"CITE\",\"Q\",\"DFN\",\"ABBR\",\"TIME\",\"CODE\",\"VAR\",\"SAMP\",\"KBD\",\"SUB\",\"SUP\",\"I\",\"B\",\"U\",\"MARK\",\"RUBY\",\"RT\",\"RP\",\"BDI\",\"BDO\",\"BR\",\"WBR\",\"TH\",\"TR\"],e.evaluateRoleForElement={A:function(e){var t=e.node,r=e.out;return\"http://www.w3.org/2000/svg\"===t.namespaceURI||(!t.href.length||r)},AREA:function(e){return!e.node.href},BUTTON:function(e){var t=e.node,r=e.role,a=e.out;return\"menu\"===t.getAttribute(\"type\")?\"menuitem\"===r:a},IMG:function(e){var t=e.node,r=e.out;return t.alt?!r:r},INPUT:function(e){var t=e.node,r=e.role,a=e.out;switch(t.type){case\"button\":case\"image\":return a;case\"checkbox\":return!(\"button\"!==r||!t.hasAttribute(\"aria-pressed\"))||a;case\"radio\":return\"menuitemradio\"===r;case\"text\":return\"combobox\"===r||\"searchbox\"===r||\"spinbutton\"===r;default:return!1}},LI:function(e){var t=e.node,r=e.out;return!axe.utils.matchesSelector(t,\"ol li, ul li\")||r},LINK:function(e){return!e.node.href},MENU:function(e){return\"context\"!==e.node.getAttribute(\"type\")},OPTION:function(e){var t=e.node;return!axe.utils.matchesSelector(t,\"select > option, datalist > option, optgroup > option\")},SELECT:function(e){var t=e.node,r=e.role;return!t.multiple&&t.size<=1&&\"menu\"===r},SVG:function(e){var t=e.node,r=e.out;return!(!t.parentNode||\"http://www.w3.org/2000/svg\"!==t.parentNode.namespaceURI)||r}};var c={};commons.color=c;var y=commons.dom={},o=commons.table={},v=commons.text={EdgeFormDefaults:{}};commons.utils=axe.utils;function i(e){return e.getPropertyValue(\"font-family\").split(/[,;]/g).map(function(e){return e.trim().toLowerCase()})}u.requiredAttr=function(e){\"use strict\";var t=u.lookupTable.role[e];return t&&t.attributes&&t.attributes.required||[]},u.allowedAttr=function(e){\"use strict\";var t=u.lookupTable.role[e],r=t&&t.attributes&&t.attributes.allowed||[],a=t&&t.attributes&&t.attributes.required||[];return r.concat(u.lookupTable.globalAttributes).concat(a)},u.validateAttr=function(e){\"use strict\";return!!u.lookupTable.attributes[e]},u.validateAttrValue=function(e,t){\"use strict\";var r,a,n=e.getAttribute(t),o=u.lookupTable.attributes[t],i=y.getRootNode(e);if(!o)return!0;switch(o.type){case\"boolean\":case\"nmtoken\":return\"string\"==typeof n&&o.values.includes(n.toLowerCase());case\"nmtokens\":return(a=axe.utils.tokenList(n)).reduce(function(e,t){return e&&o.values.includes(t)},0!==a.length);case\"idref\":return 0===n.trim().length||!(!n||!i.getElementById(n));case\"idrefs\":return 0===n.trim().length||(a=axe.utils.tokenList(n)).some(function(e){return i.getElementById(e)});case\"string\":return!0;case\"decimal\":return!(!(r=n.match(/^[-+]?([0-9]*)\\.?([0-9]*)$/))||!r[1]&&!r[2]);case\"int\":return/^[-+]?[0-9]+$/.test(n)}},u.getElementUnallowedRoles=function(t){var r=!(1<arguments.length&&void 0!==arguments[1])||arguments[1],a=t.nodeName.toUpperCase();if(!axe.utils.isHtmlElement(t))return[];var e=function(e){var t=[];if(!e)return t;if(e.hasAttribute(\"role\")){var r=axe.utils.tokenList(e.getAttribute(\"role\").toLowerCase());t=t.concat(r)}if(e.hasAttributeNS(\"http://www.idpf.org/2007/ops\",\"type\")){var a=axe.utils.tokenList(e.getAttributeNS(\"http://www.idpf.org/2007/ops\",\"type\").toLowerCase()).map(function(e){return\"doc-\"+e});t=t.concat(a)}return t=t.filter(function(e){return axe.commons.aria.isValidRole(e)})}(t),n=axe.commons.aria.implicitRole(t);return e.filter(function(e){return(!r||e!==n)&&(!(r||\"row\"===e&&\"TR\"===a&&axe.utils.matchesSelector(t,'table[role=\"grid\"] > tr'))||(!u.isAriaRoleAllowedOnElement(t,e)||void 0))})},u.getRole=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},r=t.noImplicit,a=t.fallback,n=t.abstracts,o=t.dpub,i=(e.getAttribute(\"role\")||\"\").trim().toLowerCase(),s=(a?axe.utils.tokenList(i):[i]).filter(function(e){return!(!o&&\"doc-\"===e.substr(0,4))&&u.isValidRole(e,{allowAbstract:n})})[0];return s||r?s||null:u.implicitRole(e)},u.isAccessibleRef=function(e){e=e.actualNode||e;var t=y.getRootNode(e);t=t.documentElement||t;var a=e.id,n=Object.keys(u.lookupTable.attributes).filter(function(e){var t=u.lookupTable.attributes[e].type;return/^idrefs?$/.test(t)});return void 0!==function e(t,r){if(r(t))return t;for(var a=0;a<t.children.length;a++){var n=e(t.children[a],r);if(n)return n}}(t,function(r){if(1===r.nodeType)return\"LABEL\"===r.nodeName.toUpperCase()&&r.getAttribute(\"for\")===a||n.filter(function(e){return r.hasAttribute(e)}).some(function(e){var t=r.getAttribute(e);return\"idref\"===u.lookupTable.attributes[e].type?t===a:axe.utils.tokenList(t).includes(a)})})},u.isAriaRoleAllowedOnElement=function(e,t){var r=e.nodeName.toUpperCase(),a=axe.commons.aria.lookupTable;if(u.validateNodeAndAttributes(e,a.elementsAllowedNoRole))return!1;if(u.validateNodeAndAttributes(e,a.elementsAllowedAnyRole))return!0;var n=a.role[t];if(!n)return!1;if(!(n.allowedElements&&Array.isArray(n.allowedElements)&&n.allowedElements.length))return!1;var o=!1;return o=u.validateNodeAndAttributes(e,n.allowedElements),Object.keys(a.evaluateRoleForElement).includes(r)&&(o=a.evaluateRoleForElement[r]({node:e,role:t,out:o})),o},u.labelVirtual=function(e){var t=e.actualNode,r=void 0;return t.getAttribute(\"aria-labelledby\")&&(r=y.idrefs(t,\"aria-labelledby\").map(function(e){var t=axe.utils.getNodeFromTree(axe._tree[0],e);return t?v.visibleVirtual(t,!0):\"\"}).join(\" \").trim())?r:(r=t.getAttribute(\"aria-label\"))&&(r=v.sanitize(r).trim())?r:null},u.label=function(e){return e=axe.utils.getNodeFromTree(axe._tree[0],e),u.labelVirtual(e)},u.isValidRole=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},r=t.allowAbstract,a=t.flagUnsupported,n=void 0!==a&&a,o=u.lookupTable.role[e],i=!!o&&o.unsupported;return!(!o||n&&i)&&(!!r||\"abstract\"!==o.type)},u.getRolesWithNameFromContents=function(){return Object.keys(u.lookupTable.role).filter(function(e){return u.lookupTable.role[e].nameFrom&&-1!==u.lookupTable.role[e].nameFrom.indexOf(\"contents\")})},u.getRolesByType=function(t){return Object.keys(u.lookupTable.role).filter(function(e){return u.lookupTable.role[e].type===t})},u.getRoleType=function(e){var t=u.lookupTable.role[e];return t&&t.type||null},u.requiredOwned=function(e){\"use strict\";var t=null,r=u.lookupTable.role[e];return r&&(t=axe.utils.clone(r.owned)),t},u.requiredContext=function(e){\"use strict\";var t=null,r=u.lookupTable.role[e];return r&&(t=axe.utils.clone(r.context)),t},u.implicitNodes=function(e){\"use strict\";var t=null,r=u.lookupTable.role[e];return r&&r.implicit&&(t=axe.utils.clone(r.implicit)),t},u.implicitRole=function(r){\"use strict\";var e=Object.keys(u.lookupTable.role).map(function(e){var t=u.lookupTable.role[e];return{name:e,implicit:t&&t.implicit}}).reduce(function(e,t){return t.implicit&&t.implicit.some(function(e){return axe.utils.matchesSelector(r,e)})&&e.push(t.name),e},[]);if(!e.length)return null;for(var t,a,n=r.attributes,o=[],i=0,s=n.length;i<s;i++){var l=n[i];l.name.match(/^aria-/)&&o.push(l.name)}return(t=e,a=o,t.map(function(e){return{score:(t=e,u.allowedAttr(t).reduce(function(e,t){return e+(-1<a.indexOf(t)?1:0)},0)),name:e};var t}).sort(function(e,t){return t.score-e.score}).map(function(e){return e.name})).shift()},u.validateNodeAndAttributes=function(a,e){var t=a.nodeName.toUpperCase();if(e.filter(function(e){return\"string\"==typeof e}).includes(t))return!0;var r=e.filter(function(e){return\"object\"===(void 0===e?\"undefined\":T(e))}).filter(function(e){return e.tagName===t}),n=Array.from(a.attributes).map(function(e){return e.name.toUpperCase()}),o=r.filter(function(t){if(!t.attributes)return!!t.condition;var e=Object.keys(t.attributes);if(!e.length)return!1;var r=!1;return e.forEach(function(e){n.includes(e)&&(a.getAttribute(e).trim().toUpperCase()===t.attributes[e]&&(r=!0))}),r});if(!o.length)return!1;var i=!0;return o.forEach(function(e){e.condition&&\"function\"==typeof e.condition&&(i=e.condition(a))}),i},c.Color=function(e,t,r,a){this.red=e,this.green=t,this.blue=r,this.alpha=a,this.toHexString=function(){var e=Math.round(this.red).toString(16),t=Math.round(this.green).toString(16),r=Math.round(this.blue).toString(16);return\"#\"+(15.5<this.red?e:\"0\"+e)+(15.5<this.green?t:\"0\"+t)+(15.5<this.blue?r:\"0\"+r)};var n=/^rgb\\((\\d+), (\\d+), (\\d+)\\)$/,o=/^rgba\\((\\d+), (\\d+), (\\d+), (\\d*(\\.\\d+)?)\\)/;this.parseRgbString=function(e){if(\"transparent\"===e)return this.red=0,this.green=0,this.blue=0,void(this.alpha=0);var t=e.match(n);return t?(this.red=parseInt(t[1],10),this.green=parseInt(t[2],10),this.blue=parseInt(t[3],10),void(this.alpha=1)):(t=e.match(o))?(this.red=parseInt(t[1],10),this.green=parseInt(t[2],10),this.blue=parseInt(t[3],10),void(this.alpha=parseFloat(t[4]))):void 0},this.getRelativeLuminance=function(){var e=this.red/255,t=this.green/255,r=this.blue/255;return.2126*(e<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4))+.7152*(t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4))+.0722*(r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4))}},c.flattenColors=function(e,t){var r=e.alpha,a=(1-r)*t.red+r*e.red,n=(1-r)*t.green+r*e.green,o=(1-r)*t.blue+r*e.blue,i=e.alpha+t.alpha*(1-e.alpha);return new c.Color(a,n,o,i)},c.getContrast=function(e,t){if(!t||!e)return null;t.alpha<1&&(t=c.flattenColors(t,e));var r=e.getRelativeLuminance(),a=t.getRelativeLuminance();return(Math.max(a,r)+.05)/(Math.min(a,r)+.05)},c.hasValidContrastRatio=function(e,t,r,a){var n=c.getContrast(e,t),o=a&&Math.ceil(72*r)/96<14||!a&&Math.ceil(72*r)/96<18?4.5:3;return{isValid:o<n,contrastRatio:n,expectedContrastRatio:o}},c.elementIsDistinct=function(e,t){var a=window.getComputedStyle(e);if(\"none\"!==a.getPropertyValue(\"background-image\"))return!0;if([\"border-bottom\",\"border-top\",\"outline\"].reduce(function(e,t){var r=new c.Color;return r.parseRgbString(a.getPropertyValue(t+\"-color\")),e||\"none\"!==a.getPropertyValue(t+\"-style\")&&0<parseFloat(a.getPropertyValue(t+\"-width\"))&&0!==r.alpha},!1))return!0;var r=window.getComputedStyle(t);if(i(a)[0]!==i(r)[0])return!0;var n=[\"text-decoration-line\",\"text-decoration-style\",\"font-weight\",\"font-style\",\"font-size\"].reduce(function(e,t){return e||a.getPropertyValue(t)!==r.getPropertyValue(t)},!1),o=a.getPropertyValue(\"text-decoration\");return o.split(\" \").length<3&&(n=n||o!==r.getPropertyValue(\"text-decoration\")),n};var r,s=[\"IMG\",\"CANVAS\",\"OBJECT\",\"IFRAME\",\"VIDEO\",\"SVG\"];function d(e,t){var r=e.nodeName.toUpperCase();if(s.includes(r))return axe.commons.color.incompleteData.set(\"bgColor\",\"imgNode\"),!0;var a=(t=t||window.getComputedStyle(e)).getPropertyValue(\"background-image\"),n=\"none\"!==a;if(n){var o=/gradient/.test(a);axe.commons.color.incompleteData.set(\"bgColor\",o?\"bgGradient\":\"bgImage\")}return n}function m(e,t){t=t||window.getComputedStyle(e);var r=new c.Color;if(r.parseRgbString(t.getPropertyValue(\"background-color\")),0!==r.alpha){var a=t.getPropertyValue(\"opacity\");r.alpha=r.alpha*a}return r}function l(e,t){var r=e.getClientRects()[0],a=y.shadowElementsFromPoint(r.left,r.top);if(a)for(var n=0;n<a.length;n++)if(a[n]!==e&&a[n]===t)return!0;return!1}c.getCoords=function(e){if(!(e.left>window.innerWidth||e.top>window.innerHeight))return{x:Math.min(Math.ceil(e.left+e.width/2),window.innerWidth-1),y:Math.min(Math.ceil(e.top+e.height/2),window.innerHeight-1)}},c.getRectStack=function(e){var t=c.getCoords(e.getBoundingClientRect());if(t){var r=y.shadowElementsFromPoint(t.x,t.y),a=Array.from(e.getClientRects());if(a&&1<a.length){var n=a.filter(function(e){return e.width&&0<e.width}).map(function(e){var t=c.getCoords(e);if(t)return y.shadowElementsFromPoint(t.x,t.y)});return n.splice(0,0,r),n}return[r]}return null},c.filteredRectStack=function(n){var o=c.getRectStack(n);if(o&&1===o.length)return o[0];if(o&&1<o.length){var i=o.shift(),s=void 0;return o.forEach(function(e,t){if(0!==t){var r=o[t-1],a=o[t];s=r.every(function(e,t){return e===a[t]})||i.includes(n)}}),s?o[0]:(axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscuring\"),null)}return axe.commons.color.incompleteData.set(\"bgColor\",\"outsideViewport\"),null},c.getBackgroundStack=function(e){var t,r,a,n=c.filteredRectStack(e);if(null===n)return null;n=function(e,t){var r={TD:[\"TR\",\"TBODY\"],TH:[\"TR\",\"THEAD\"],INPUT:[\"LABEL\"]},a=e.map(function(e){return e.tagName}),n=e;for(var o in r)if(a.includes(o))for(var i in r[o])if(o.hasOwnProperty(i)){var s=axe.commons.dom.findUp(t,r[o][i]);s&&-1===e.indexOf(s)&&axe.commons.dom.visuallyOverlaps(t.getBoundingClientRect(),s)&&n.splice(a.indexOf(o)+1,0,s),t.tagName===r[o][i]&&-1===a.indexOf(t.tagName)&&n.splice(a.indexOf(o)+1,0,t)}return n}(n,e),n=y.reduceToElementsBelowFloating(n,e),r=(t=n).indexOf(document.body),a=t,1<r&&!d(document.documentElement)&&0===m(document.documentElement).alpha&&(a.splice(r,1),a.splice(t.indexOf(document.documentElement),1),a.push(document.body));var o=(n=a).indexOf(e);return.99<=function(e,t,r){var a=0;if(0<e)for(var n=e-1;0<=n;n--){var o=t[n],i=m(o,window.getComputedStyle(o));i.alpha&&l(r,o)?a+=i.alpha:t.splice(n,1)}return a}(o,n,e)?(axe.commons.color.incompleteData.set(\"bgColor\",\"bgOverlap\"),null):-1!==o?n:null},c.getBackgroundColor=function(s){var l=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[];if(!0!==(2<arguments.length&&void 0!==arguments[2]&&arguments[2])){var e=s.clientHeight-2>=2*window.innerHeight;s.scrollIntoView(e)}var u=[],t=c.getBackgroundStack(s);return(t||[]).some(function(e){var t,r,a,n,o=window.getComputedStyle(e),i=m(e,o);return a=i,(n=(t=s)!==(r=e)&&!y.visuallyContains(t,r)&&0!==a.alpha)&&axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscured\"),n||d(e,o)?(u=null,l.push(e),!0):0!==i.alpha&&(l.push(e),u.push(i),1===i.alpha)}),null===u||null===t?null:(u.push(new c.Color(255,255,255,1)),u.reduce(c.flattenColors))},y.isOpaque=function(e){var t=window.getComputedStyle(e);return d(e,t)||1===m(e,t).alpha},c.getForegroundColor=function(e,t){var r=window.getComputedStyle(e),a=new c.Color;a.parseRgbString(r.getPropertyValue(\"color\"));var n=r.getPropertyValue(\"opacity\");if(a.alpha=a.alpha*n,1===a.alpha)return a;var o=c.getBackgroundColor(e,[],t);if(null!==o)return c.flattenColors(a,o);var i=axe.commons.color.incompleteData.get(\"bgColor\");return axe.commons.color.incompleteData.set(\"fgColor\",i),null},c.incompleteData=(r={},{set:function(e,t){if(\"string\"!=typeof e)throw new Error(\"Incomplete data: key must be a string\");return t&&(r[e]=t),r[e]},get:function(e){return r[e]},clear:function(){r={}}}),y.reduceToElementsBelowFloating=function(e,t){var r,a,n,o=[\"fixed\",\"sticky\"],i=[],s=!1;for(r=0;r<e.length;++r)(a=e[r])===t&&(s=!0),n=window.getComputedStyle(a),s||-1===o.indexOf(n.position)?i.push(a):i=[];return i},y.findElmsInContext=function(e){var t=e.context,r=e.value,a=e.attr,n=e.elm,o=void 0===n?\"\":n,i=void 0,s=axe.utils.escapeSelector(r);return i=9===t.nodeType||11===t.nodeType?t:y.getRootNode(t),Array.from(i.querySelectorAll(o+\"[\"+a+\"=\"+s+\"]\"))},y.findUp=function(e,t){return y.findUpVirtual(axe.utils.getNodeFromTree(axe._tree[0],e),t)},y.findUpVirtual=function(e,t){var r=void 0;if(r=e.actualNode,!e.shadowId&&\"function\"==typeof e.actualNode.closest){var a=e.actualNode.closest(t);return a||null}for(;(r=r.assignedSlot?r.assignedSlot:r.parentNode)&&11===r.nodeType&&(r=r.host),r&&!axe.utils.matchesSelector(r,t)&&r!==document.documentElement;);return axe.utils.matchesSelector(r,t)?r:null},y.getComposedParent=function e(t){if(t.assignedSlot)return e(t.assignedSlot);if(t.parentNode){var r=t.parentNode;if(1===r.nodeType)return r;if(r.host)return r.host}return null},y.getElementByReference=function(e,t){var r=e.getAttribute(t);if(r&&\"#\"===r.charAt(0)){r=decodeURIComponent(r.substring(1));var a=document.getElementById(r);if(a)return a;if((a=document.getElementsByName(r)).length)return a[0]}return null},y.getElementCoordinates=function(e){\"use strict\";var t=y.getScrollOffset(document),r=t.left,a=t.top,n=e.getBoundingClientRect();return{top:n.top+a,right:n.right+r,bottom:n.bottom+a,left:n.left+r,width:n.right-n.left,height:n.bottom-n.top}},y.getRootNode=axe.utils.getRootNode,y.getScrollOffset=function(e){\"use strict\";if(!e.nodeType&&e.document&&(e=e.document),9!==e.nodeType)return{left:e.scrollLeft,top:e.scrollTop};var t=e.documentElement,r=e.body;return{left:t&&t.scrollLeft||r&&r.scrollLeft||0,top:t&&t.scrollTop||r&&r.scrollTop||0}},y.getViewportSize=function(e){\"use strict\";var t,r=e.document,a=r.documentElement;return e.innerWidth?{width:e.innerWidth,height:e.innerHeight}:a?{width:a.clientWidth,height:a.clientHeight}:{width:(t=r.body).clientWidth,height:t.clientHeight}};var a=[\"HEAD\",\"TITLE\",\"TEMPLATE\",\"SCRIPT\",\"STYLE\",\"IFRAME\",\"OBJECT\",\"VIDEO\",\"AUDIO\",\"NOSCRIPT\"];function n(e){return e.disabled||!y.isVisible(e,!0)&&\"AREA\"!==e.nodeName.toUpperCase()}y.hasContentVirtual=function(e,t){return function(e){if(!a.includes(e.actualNode.nodeName.toUpperCase()))return e.children.some(function(e){var t=e.actualNode;return 3===t.nodeType&&t.nodeValue.trim()})}(e)||y.isVisualContent(e.actualNode)||!!u.labelVirtual(e)||!t&&e.children.some(function(e){return 1===e.actualNode.nodeType&&y.hasContentVirtual(e)})},y.hasContent=function(e,t){return e=axe.utils.getNodeFromTree(axe._tree[0],e),y.hasContentVirtual(e,t)},y.idrefs=function(e,t){\"use strict\";var r,a,n=y.getRootNode(e),o=[],i=e.getAttribute(t);if(i)for(r=0,a=(i=axe.utils.tokenList(i)).length;r<a;r++)o.push(n.getElementById(i[r]));return o},y.isFocusable=function(e){\"use strict\";if(n(e))return!1;if(y.isNativelyFocusable(e))return!0;var t=e.getAttribute(\"tabindex\");return!(!t||isNaN(parseInt(t,10)))},y.isNativelyFocusable=function(e){\"use strict\";if(!e||n(e))return!1;switch(e.nodeName.toUpperCase()){case\"A\":case\"AREA\":if(e.href)return!0;break;case\"INPUT\":return\"hidden\"!==e.type;case\"TEXTAREA\":case\"SELECT\":case\"DETAILS\":case\"BUTTON\":return!0}return!1},y.insertedIntoFocusOrder=function(e){return-1<e.tabIndex&&y.isFocusable(e)&&!y.isNativelyFocusable(e)},y.isHTML5=function(e){var t=e.doctype;return null!==t&&(\"html\"===t.name&&!t.publicId&&!t.systemId)};var p=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];function f(e){var t=window.getComputedStyle(e).getPropertyValue(\"display\");return p.includes(t)||\"table-\"===t.substr(0,6)}y.isInTextBlock=function(r){if(f(r))return!1;var e=function(e){for(var t=y.getComposedParent(e);t&&!f(t);)t=y.getComposedParent(t);return axe.utils.getNodeFromTree(axe._tree[0],t)}(r),a=\"\",n=\"\",o=0;return function t(e,r){!1!==r(e.actualNode)&&e.children.forEach(function(e){return t(e,r)})}(e,function(e){if(2===o)return!1;if(3===e.nodeType&&(a+=e.nodeValue),1===e.nodeType){var t=(e.nodeName||\"\").toUpperCase();if([\"BR\",\"HR\"].includes(t))0===o?n=a=\"\":o=2;else{if(\"none\"===e.style.display||\"hidden\"===e.style.overflow||![\"\",null,\"none\"].includes(e.style.float)||![\"\",null,\"relative\"].includes(e.style.position))return!1;if(\"A\"===t&&e.href||\"link\"===(e.getAttribute(\"role\")||\"\").toLowerCase())return e===r&&(o=1),n+=e.textContent,!1}}}),a=axe.commons.text.sanitize(a),n=axe.commons.text.sanitize(n),a.length>n.length},y.isNode=function(e){\"use strict\";return e instanceof Node},y.isOffscreen=function(e){var t=void 0,r=document.documentElement,a=window.getComputedStyle(e),n=window.getComputedStyle(document.body||r).getPropertyValue(\"direction\"),o=y.getElementCoordinates(e);if(o.bottom<0&&(function(e,t){for(e=y.getComposedParent(e);e&&\"html\"!==e.nodeName.toLowerCase();){if(e.scrollTop&&0<=(t+=e.scrollTop))return!1;e=y.getComposedParent(e)}return!0}(e,o.bottom)||\"absolute\"===a.position))return!0;if(0===o.left&&0===o.right)return!1;if(\"ltr\"===n){if(o.right<=0)return!0}else if(t=Math.max(r.scrollWidth,y.getViewportSize(window).width),o.left>=t)return!0;return!1},y.isVisible=function(e,t,r){\"use strict\";var a,n,o,i,s;return 9===e.nodeType||(11===e.nodeType&&(e=e.host),null!==(a=window.getComputedStyle(e,null))&&(n=e.nodeName.toUpperCase(),!(\"none\"===a.getPropertyValue(\"display\")||\"STYLE\"===n.toUpperCase()||\"SCRIPT\"===n.toUpperCase()||!t&&(i=a.getPropertyValue(\"clip\"),(s=i.match(/rect\\s*\\(([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px\\s*\\)/))&&5===s.length&&s[3]-s[1]<=0&&s[2]-s[4]<=0)||!r&&(\"hidden\"===a.getPropertyValue(\"visibility\")||!t&&y.isOffscreen(e))||t&&\"true\"===e.getAttribute(\"aria-hidden\"))&&(!!(o=e.assignedSlot?e.assignedSlot:e.parentNode)&&y.isVisible(o,t,!0))))};var h=[\"checkbox\",\"img\",\"radio\",\"range\",\"slider\",\"spinbutton\",\"textbox\"];y.isVisualContent=function(e){var t=e.getAttribute(\"role\");if(t)return-1!==h.indexOf(t);switch(e.tagName.toUpperCase()){case\"IMG\":case\"IFRAME\":case\"OBJECT\":case\"VIDEO\":case\"AUDIO\":case\"CANVAS\":case\"SVG\":case\"MATH\":case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":case\"KEYGEN\":case\"PROGRESS\":case\"METER\":return!0;case\"INPUT\":return\"hidden\"!==e.type;default:return!1}},y.shadowElementsFromPoint=function(a,n){var t=2<arguments.length&&void 0!==arguments[2]?arguments[2]:document,o=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;if(999<o)throw new Error(\"Infinite loop detected\");return Array.from(t.elementsFromPoint(a,n)).filter(function(e){return y.getRootNode(e)===t}).reduce(function(e,t){if(axe.utils.isShadowRoot(t)){var r=y.shadowElementsFromPoint(a,n,t.shadowRoot,o+1);(e=e.concat(r)).length&&axe.commons.dom.visuallyContains(e[0],t)&&e.push(t)}else e.push(t);return e},[])},y.visuallyContains=function(e,t){var r=e.getBoundingClientRect(),a=r.top+.01,n=r.bottom-.01,o=r.left+.01,i=r.right-.01,s=t.getBoundingClientRect(),l=s.top,u=s.left,c=l-t.scrollTop,d=l-t.scrollTop+t.scrollHeight,m=u-t.scrollLeft,p=u-t.scrollLeft+t.scrollWidth,f=window.getComputedStyle(t);return\"inline\"===f.getPropertyValue(\"display\")||!(o<m&&o<s.left||a<c&&a<s.top||p<i&&i>s.right||d<n&&n>s.bottom)&&(!(i>s.right||n>s.bottom)||(\"scroll\"===f.overflow||\"auto\"===f.overflow||\"hidden\"===f.overflow||t instanceof HTMLBodyElement||t instanceof HTMLHtmlElement))},y.visuallyOverlaps=function(e,t){var r=t.getBoundingClientRect(),a=r.top,n=r.left,o=a-t.scrollTop,i=a-t.scrollTop+t.scrollHeight,s=n-t.scrollLeft,l=n-t.scrollLeft+t.scrollWidth;if(e.left>l&&e.left>r.right||e.top>i&&e.top>r.bottom||e.right<s&&e.right<r.left||e.bottom<o&&e.bottom<r.top)return!1;var u=window.getComputedStyle(t);return!(e.left>r.right||e.top>r.bottom)||(\"scroll\"===u.overflow||\"auto\"===u.overflow||t instanceof HTMLBodyElement||t instanceof HTMLHtmlElement)},o.getAllCells=function(e){var t,r,a,n,o=[];for(t=0,a=e.rows.length;t<a;t++)for(r=0,n=e.rows[t].cells.length;r<n;r++)o.push(e.rows[t].cells[r]);return o},o.getCellPosition=function(e,t){var r,a;for(t||(t=o.toGrid(y.findUp(e,\"table\"))),r=0;r<t.length;r++)if(t[r]&&-1!==(a=t[r].indexOf(e)))return{x:a,y:r}},o.getHeaders=function(e){if(e.hasAttribute(\"headers\"))return commons.dom.idrefs(e,\"headers\");var t=commons.table.toGrid(commons.dom.findUp(e,\"table\")),r=commons.table.getCellPosition(e,t),a=o.traverse(\"left\",r,t).filter(function(e){return o.isRowHeader(e)}),n=o.traverse(\"up\",r,t).filter(function(e){return o.isColumnHeader(e)});return[].concat(a,n).reverse()},o.getScope=function(e){var t=e.getAttribute(\"scope\"),r=e.getAttribute(\"role\");if(e instanceof Element==!1||-1===[\"TD\",\"TH\"].indexOf(e.nodeName.toUpperCase()))throw new TypeError(\"Expected TD or TH element\");if(\"columnheader\"===r)return\"col\";if(\"rowheader\"===r)return\"row\";if(\"col\"===t||\"row\"===t)return t;if(\"TH\"!==e.nodeName.toUpperCase())return!1;var a=o.toGrid(y.findUp(e,\"table\")),n=o.getCellPosition(e);return a[n.y].reduce(function(e,t){return e&&\"TH\"===t.nodeName.toUpperCase()},!0)?\"col\":a.map(function(e){return e[n.x]}).reduce(function(e,t){return e&&\"TH\"===t.nodeName.toUpperCase()},!0)?\"row\":\"auto\"},o.isColumnHeader=function(e){return-1!==[\"col\",\"auto\"].indexOf(o.getScope(e))},o.isDataCell=function(e){if(!e.children.length&&!e.textContent.trim())return!1;var t=e.getAttribute(\"role\");return axe.commons.aria.isValidRole(t)?[\"cell\",\"gridcell\"].includes(t):\"TD\"===e.nodeName.toUpperCase()},o.isDataTable=function(e){var t=(e.getAttribute(\"role\")||\"\").toLowerCase();if((\"presentation\"===t||\"none\"===t)&&!y.isFocusable(e))return!1;if(\"true\"===e.getAttribute(\"contenteditable\")||y.findUp(e,'[contenteditable=\"true\"]'))return!0;if(\"grid\"===t||\"treegrid\"===t||\"table\"===t)return!0;if(\"landmark\"===commons.aria.getRoleType(t))return!0;if(\"0\"===e.getAttribute(\"datatable\"))return!1;if(e.getAttribute(\"summary\"))return!0;if(e.tHead||e.tFoot||e.caption)return!0;for(var r=0,a=e.children.length;r<a;r++)if(\"COLGROUP\"===e.children[r].nodeName.toUpperCase())return!0;for(var n,o,i=0,s=e.rows.length,l=!1,u=0;u<s;u++)for(var c=0,d=(n=e.rows[u]).cells.length;c<d;c++){if(\"TH\"===(o=n.cells[c]).nodeName.toUpperCase())return!0;if(l||o.offsetWidth===o.clientWidth&&o.offsetHeight===o.clientHeight||(l=!0),o.getAttribute(\"scope\")||o.getAttribute(\"headers\")||o.getAttribute(\"abbr\"))return!0;if([\"columnheader\",\"rowheader\"].includes((o.getAttribute(\"role\")||\"\").toLowerCase()))return!0;if(1===o.children.length&&\"ABBR\"===o.children[0].nodeName.toUpperCase())return!0;i++}if(e.getElementsByTagName(\"table\").length)return!1;if(s<2)return!1;var m,p,f=e.rows[Math.ceil(s/2)];if(1===f.cells.length&&1===f.cells[0].colSpan)return!1;if(5<=f.cells.length)return!0;if(l)return!0;for(u=0;u<s;u++){if(n=e.rows[u],m&&m!==window.getComputedStyle(n).getPropertyValue(\"background-color\"))return!0;if(m=window.getComputedStyle(n).getPropertyValue(\"background-color\"),p&&p!==window.getComputedStyle(n).getPropertyValue(\"background-image\"))return!0;p=window.getComputedStyle(n).getPropertyValue(\"background-image\")}return 20<=s||!(y.getElementCoordinates(e).width>.95*y.getViewportSize(window).width)&&(!(i<10)&&!e.querySelector(\"object, embed, iframe, applet\"))},o.isHeader=function(e){if(o.isColumnHeader(e)||o.isRowHeader(e))return!0;if(e.getAttribute(\"id\")){var t=axe.utils.escapeSelector(e.getAttribute(\"id\"));return!!document.querySelector('[headers~=\"'+t+'\"]')}return!1},o.isRowHeader=function(e){return[\"row\",\"auto\"].includes(o.getScope(e))},o.toGrid=function(e){for(var t=[],r=e.rows,a=0,n=r.length;a<n;a++){var o=r[a].cells;t[a]=t[a]||[];for(var i=0,s=0,l=o.length;s<l;s++)for(var u=0;u<o[s].colSpan;u++){for(var c=0;c<o[s].rowSpan;c++){for(t[a+c]=t[a+c]||[];t[a+c][i];)i++;t[a+c][i]=o[s]}i++}}return t},o.toArray=o.toGrid,o.traverse=function(e,t,r,a){if(Array.isArray(t)&&(a=r,r=t,t={x:0,y:0}),\"string\"==typeof e)switch(e){case\"left\":e={x:-1,y:0};break;case\"up\":e={x:0,y:-1};break;case\"right\":e={x:1,y:0};break;case\"down\":e={x:0,y:1}}return function e(t,r,a,n){var o,i=a[r.y]?a[r.y][r.x]:void 0;return i?\"function\"==typeof n&&!0===(o=n(i,r,a))?[i]:((o=e(t,{x:r.x+t.x,y:r.y+t.y},a,n)).unshift(i),o):[]}(e,{x:t.x+e.x,y:t.y+e.y},r,a)};var w={submit:\"Submit\",reset:\"Reset\"},k=[\"text\",\"search\",\"tel\",\"url\",\"email\",\"date\",\"time\",\"number\",\"range\",\"color\"],x=[\"A\",\"EM\",\"STRONG\",\"SMALL\",\"MARK\",\"ABBR\",\"DFN\",\"I\",\"B\",\"S\",\"U\",\"CODE\",\"VAR\",\"SAMP\",\"KBD\",\"SUP\",\"SUB\",\"Q\",\"CITE\",\"SPAN\",\"BDO\",\"BDI\",\"BR\",\"WBR\",\"INS\",\"DEL\",\"IMG\",\"EMBED\",\"OBJECT\",\"IFRAME\",\"MAP\",\"AREA\",\"SCRIPT\",\"NOSCRIPT\",\"RUBY\",\"VIDEO\",\"AUDIO\",\"INPUT\",\"TEXTAREA\",\"SELECT\",\"BUTTON\",\"LABEL\",\"OUTPUT\",\"DATALIST\",\"KEYGEN\",\"PROGRESS\",\"COMMAND\",\"CANVAS\",\"TIME\",\"METER\"];function E(e,t){var r=e.actualNode.querySelector(t.toLowerCase());return r?v.accessibleText(r):\"\"}function A(e){return!!v.sanitize(e)}v.accessibleText=function(e,t){var r=axe.utils.getNodeFromTree(axe._tree[0],e);return axe.commons.text.accessibleTextVirtual(r,t)},v.accessibleTextVirtual=function(e,t){var g=void 0,i=[];function b(e,a,n){return e.children.reduce(function(e,t){var r=t.actualNode;return 3===r.nodeType?e+=r.nodeValue:1===r.nodeType&&(x.includes(r.nodeName.toUpperCase())||(e+=\" \"),e+=g(t,a,n)),e},\"\")}function s(e,t,r){var a,n,o,i,s,l,u,c,d,m=\"\",p=e.actualNode,f=p.nodeName.toUpperCase();if(a=e.actualNode,[\"BUTTON\",\"SUMMARY\",\"A\"].includes(a.nodeName.toUpperCase())&&A(m=b(e,!1,!1)||\"\"))return m;if(\"FIGURE\"===f&&A(m=E(e,\"figcaption\")))return m;if(\"TABLE\"===f){if(A(m=E(e,\"caption\")))return m;if(A(m=p.getAttribute(\"title\")||p.getAttribute(\"summary\")||(n=e,axe.commons.table.isDataTable(n.actualNode)||1!==axe.commons.table.getAllCells(n.actualNode).length?\"\":b(n,!1,!1).trim())||\"\"))return m}if(o=e.actualNode,i=o.nodeName.toUpperCase(),[\"IMG\",\"APPLET\",\"AREA\"].includes(i)||\"INPUT\"===i&&\"image\"===o.type.toLowerCase())return p.getAttribute(\"alt\")||\"\";if(c=e.actualNode,(\"TEXTAREA\"===(d=c.nodeName.toUpperCase())||\"SELECT\"===d||\"INPUT\"===d&&\"hidden\"!==c.type.toLowerCase())&&!r){if(u=e.actualNode,[\"button\",\"reset\",\"submit\"].includes(u.type.toLowerCase()))return p.value||p.title||w[p.type]||\"\";var h=(l=void 0,(s=e).actualNode.id&&(l=y.findElmsInContext({elm:\"label\",attr:\"for\",value:s.actualNode.id,context:s.actualNode})[0]),l||(l=y.findUpVirtual(s,\"label\")),axe.utils.getNodeFromTree(axe._tree[0],l));if(h)return g(h,t,!0)}return\"\"}function l(e,t,r){var a=\"\",n=e.actualNode;return!t&&n.hasAttribute(\"aria-labelledby\")&&(a=v.sanitize(y.idrefs(n,\"aria-labelledby\").map(function(e){if(null===e)return\"\";n===e&&i.pop();var t=axe.utils.getNodeFromTree(axe._tree[0],e);return g(t,!0,n!==e)}).join(\" \"))),a||r&&function(e){if(!e)return!1;var t=e.actualNode;switch(t.nodeName.toUpperCase()){case\"SELECT\":case\"TEXTAREA\":return!0;case\"INPUT\":return!t.hasAttribute(\"type\")||k.includes(t.getAttribute(\"type\").toLowerCase());default:return!1}}(e)||!n.hasAttribute(\"aria-label\")?a:v.sanitize(n.getAttribute(\"aria-label\"))}return e instanceof Node&&(e=axe.utils.getNodeFromTree(axe._tree[0],e)),g=function(e,t,r){var a=void 0;if(!e||i.includes(e))return\"\";if(null!==e&&e.actualNode instanceof Node!=!0)throw new Error(\"Invalid argument. Virtual Node must be provided\");if(!t&&!y.isVisible(e.actualNode,!0))return\"\";i.push(e);var n,o=e.actualNode.getAttribute(\"role\");return A(a=l(e,t,r))?a:A(a=s(e,t,r))?a:r&&A(a=function(e,t){var r=e.actualNode,a=r.nodeName.toUpperCase();if(\"INPUT\"===a)return!r.hasAttribute(\"type\")||k.includes(r.type.toLowerCase())?r.value:\"\";if(\"SELECT\"===a&&t){var n=r.options;if(n&&n.length){for(var o=\"\",i=0;i<n.length;i++)n[i].selected&&(o+=\" \"+n[i].text);return v.sanitize(o)}return\"\"}return\"TEXTAREA\"===a&&r.value?r.value:\"\"}(e,t))?a:!t&&(n=e.actualNode,[\"TABLE\",\"FIGURE\",\"SELECT\"].includes(n.nodeName.toUpperCase()))||o&&-1===u.getRolesWithNameFromContents().indexOf(o)||!A(a=b(e,t,r))?e.actualNode.hasAttribute(\"title\")?e.actualNode.getAttribute(\"title\"):\"\":a},v.sanitize(g(e,t))};v.autocomplete={stateTerms:[\"on\",\"off\"],standaloneTerms:[\"name\",\"honorific-prefix\",\"given-name\",\"additional-name\",\"family-name\",\"honorific-suffix\",\"nickname\",\"username\",\"new-password\",\"current-password\",\"organization-title\",\"organization\",\"street-address\",\"address-line1\",\"address-line2\",\"address-line3\",\"address-level4\",\"address-level3\",\"address-level2\",\"address-level1\",\"country\",\"country-name\",\"postal-code\",\"cc-name\",\"cc-given-name\",\"cc-additional-name\",\"cc-family-name\",\"cc-number\",\"cc-exp\",\"cc-exp-month\",\"cc-exp-year\",\"cc-csc\",\"cc-type\",\"transaction-currency\",\"transaction-amount\",\"language\",\"bday\",\"bday-day\",\"bday-month\",\"bday-year\",\"sex\",\"url\",\"photo\"],qualifiers:[\"home\",\"work\",\"mobile\",\"fax\",\"pager\"],qualifiedTerms:[\"tel\",\"tel-country-code\",\"tel-national\",\"tel-area-code\",\"tel-local\",\"tel-local-prefix\",\"tel-local-suffix\",\"tel-extension\",\"email\",\"impp\"],locations:[\"billing\",\"shipping\"]},v.isValidAutocomplete=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},r=t.looseTyped,a=void 0!==r&&r,n=t.stateTerms,o=void 0===n?[]:n,i=t.locations,s=void 0===i?[]:i,l=t.qualifiers,u=void 0===l?[]:l,c=t.standaloneTerms,d=void 0===c?[]:c,m=t.qualifiedTerms,p=void 0===m?[]:m;if(e=e.toLowerCase().trim(),(o=o.concat(v.autocomplete.stateTerms)).includes(e)||\"\"===e)return!0;u=u.concat(v.autocomplete.qualifiers),s=s.concat(v.autocomplete.locations),d=d.concat(v.autocomplete.standaloneTerms),p=p.concat(v.autocomplete.qualifiedTerms);var f=e.split(/\\s+/g);if(!a&&(8<f[0].length&&\"section-\"===f[0].substr(0,8)&&f.shift(),s.includes(f[0])&&f.shift(),u.includes(f[0])&&(f.shift(),d=[]),1!==f.length))return!1;var h=f[f.length-1];return d.includes(h)||p.includes(h)},v.labelVirtual=function(e){var t,r;if(r=u.labelVirtual(e))return r;if(e.actualNode.id){var a=axe.commons.utils.escapeSelector(e.actualNode.getAttribute(\"id\"));if(r=(t=axe.commons.dom.getRootNode(e.actualNode).querySelector('label[for=\"'+a+'\"]'))&&v.visible(t,!0))return r}return(r=(t=y.findUpVirtual(e,\"label\"))&&v.visible(t,!0))||null},v.label=function(e){return e=axe.utils.getNodeFromTree(axe._tree[0],e),v.labelVirtual(e)},v.sanitize=function(e){\"use strict\";return e.replace(/\\r\\n/g,\"\\n\").replace(/\\u00A0/g,\" \").replace(/[\\s]{2,}/g,\" \").trim()},v.visibleVirtual=function(r,a,n){var e=r.children.map(function(e){if(3===e.actualNode.nodeType){var t=e.actualNode.nodeValue;if(t&&y.isVisible(r.actualNode,a))return t}else if(!n)return v.visibleVirtual(e,a)}).join(\"\");return v.sanitize(e)},v.visible=function(e,t,r){return e=axe.utils.getNodeFromTree(axe._tree[0],e),v.visibleVirtual(e,t,r)},axe.utils.getBaseLang=function(e){return e?e.trim().split(\"-\")[0].toLowerCase():\"\"};var g=[\"a\",\"abbr\",\"address\",\"area\",\"article\",\"aside\",\"audio\",\"b\",\"base\",\"bdi\",\"bdo\",\"blockquote\",\"body\",\"br\",\"button\",\"canvas\",\"caption\",\"cite\",\"code\",\"col\",\"colgroup\",\"data\",\"datalist\",\"dd\",\"del\",\"details\",\"dfn\",\"dialog\",\"div\",\"dl\",\"dt\",\"em\",\"embed\",\"fieldset\",\"figcaption\",\"figure\",\"footer\",\"form\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"head\",\"header\",\"hgroup\",\"hr\",\"html\",\"i\",\"iframe\",\"img\",\"input\",\"ins\",\"kbd\",\"keygen\",\"label\",\"legend\",\"li\",\"link\",\"main\",\"map\",\"mark\",\"math\",\"menu\",\"menuitem\",\"meta\",\"meter\",\"nav\",\"noscript\",\"object\",\"ol\",\"optgroup\",\"option\",\"output\",\"p\",\"param\",\"picture\",\"pre\",\"progress\",\"q\",\"rb\",\"rp\",\"rt\",\"rtc\",\"ruby\",\"s\",\"samp\",\"script\",\"section\",\"select\",\"slot\",\"small\",\"source\",\"span\",\"strong\",\"style\",\"sub\",\"summary\",\"sup\",\"svg\",\"table\",\"tbody\",\"td\",\"template\",\"textarea\",\"tfoot\",\"th\",\"thead\",\"time\",\"title\",\"tr\",\"track\",\"u\",\"ul\",\"var\",\"video\",\"wbr\"];axe.utils.isHtmlElement=function(e){var t=e.nodeName.toLowerCase();return g.includes(t)&&\"http://www.w3.org/2000/svg\"!==e.namespaceURI},axe.utils.tokenList=function(e){\"use strict\";return e.trim().replace(/\\s{2,}/g,\" \").split(\" \")};var b=[\"aa\",\"ab\",\"ae\",\"af\",\"ak\",\"am\",\"an\",\"ar\",\"as\",\"av\",\"ay\",\"az\",\"ba\",\"be\",\"bg\",\"bh\",\"bi\",\"bm\",\"bn\",\"bo\",\"br\",\"bs\",\"ca\",\"ce\",\"ch\",\"co\",\"cr\",\"cs\",\"cu\",\"cv\",\"cy\",\"da\",\"de\",\"dv\",\"dz\",\"ee\",\"el\",\"en\",\"eo\",\"es\",\"et\",\"eu\",\"fa\",\"ff\",\"fi\",\"fj\",\"fo\",\"fr\",\"fy\",\"ga\",\"gd\",\"gl\",\"gn\",\"gu\",\"gv\",\"ha\",\"he\",\"hi\",\"ho\",\"hr\",\"ht\",\"hu\",\"hy\",\"hz\",\"ia\",\"id\",\"ie\",\"ig\",\"ii\",\"ik\",\"in\",\"io\",\"is\",\"it\",\"iu\",\"iw\",\"ja\",\"ji\",\"jv\",\"jw\",\"ka\",\"kg\",\"ki\",\"kj\",\"kk\",\"kl\",\"km\",\"kn\",\"ko\",\"kr\",\"ks\",\"ku\",\"kv\",\"kw\",\"ky\",\"la\",\"lb\",\"lg\",\"li\",\"ln\",\"lo\",\"lt\",\"lu\",\"lv\",\"mg\",\"mh\",\"mi\",\"mk\",\"ml\",\"mn\",\"mo\",\"mr\",\"ms\",\"mt\",\"my\",\"na\",\"nb\",\"nd\",\"ne\",\"ng\",\"nl\",\"nn\",\"no\",\"nr\",\"nv\",\"ny\",\"oc\",\"oj\",\"om\",\"or\",\"os\",\"pa\",\"pi\",\"pl\",\"ps\",\"pt\",\"qu\",\"rm\",\"rn\",\"ro\",\"ru\",\"rw\",\"sa\",\"sc\",\"sd\",\"se\",\"sg\",\"sh\",\"si\",\"sk\",\"sl\",\"sm\",\"sn\",\"so\",\"sq\",\"sr\",\"ss\",\"st\",\"su\",\"sv\",\"sw\",\"ta\",\"te\",\"tg\",\"th\",\"ti\",\"tk\",\"tl\",\"tn\",\"to\",\"tr\",\"ts\",\"tt\",\"tw\",\"ty\",\"ug\",\"uk\",\"ur\",\"uz\",\"ve\",\"vi\",\"vo\",\"wa\",\"wo\",\"xh\",\"yi\",\"yo\",\"za\",\"zh\",\"zu\",\"aaa\",\"aab\",\"aac\",\"aad\",\"aae\",\"aaf\",\"aag\",\"aah\",\"aai\",\"aak\",\"aal\",\"aam\",\"aan\",\"aao\",\"aap\",\"aaq\",\"aas\",\"aat\",\"aau\",\"aav\",\"aaw\",\"aax\",\"aaz\",\"aba\",\"abb\",\"abc\",\"abd\",\"abe\",\"abf\",\"abg\",\"abh\",\"abi\",\"abj\",\"abl\",\"abm\",\"abn\",\"abo\",\"abp\",\"abq\",\"abr\",\"abs\",\"abt\",\"abu\",\"abv\",\"abw\",\"abx\",\"aby\",\"abz\",\"aca\",\"acb\",\"acd\",\"ace\",\"acf\",\"ach\",\"aci\",\"ack\",\"acl\",\"acm\",\"acn\",\"acp\",\"acq\",\"acr\",\"acs\",\"act\",\"acu\",\"acv\",\"acw\",\"acx\",\"acy\",\"acz\",\"ada\",\"adb\",\"add\",\"ade\",\"adf\",\"adg\",\"adh\",\"adi\",\"adj\",\"adl\",\"adn\",\"ado\",\"adp\",\"adq\",\"adr\",\"ads\",\"adt\",\"adu\",\"adw\",\"adx\",\"ady\",\"adz\",\"aea\",\"aeb\",\"aec\",\"aed\",\"aee\",\"aek\",\"ael\",\"aem\",\"aen\",\"aeq\",\"aer\",\"aes\",\"aeu\",\"aew\",\"aey\",\"aez\",\"afa\",\"afb\",\"afd\",\"afe\",\"afg\",\"afh\",\"afi\",\"afk\",\"afn\",\"afo\",\"afp\",\"afs\",\"aft\",\"afu\",\"afz\",\"aga\",\"agb\",\"agc\",\"agd\",\"age\",\"agf\",\"agg\",\"agh\",\"agi\",\"agj\",\"agk\",\"agl\",\"agm\",\"agn\",\"ago\",\"agp\",\"agq\",\"agr\",\"ags\",\"agt\",\"agu\",\"agv\",\"agw\",\"agx\",\"agy\",\"agz\",\"aha\",\"ahb\",\"ahg\",\"ahh\",\"ahi\",\"ahk\",\"ahl\",\"ahm\",\"ahn\",\"aho\",\"ahp\",\"ahr\",\"ahs\",\"aht\",\"aia\",\"aib\",\"aic\",\"aid\",\"aie\",\"aif\",\"aig\",\"aih\",\"aii\",\"aij\",\"aik\",\"ail\",\"aim\",\"ain\",\"aio\",\"aip\",\"aiq\",\"air\",\"ais\",\"ait\",\"aiw\",\"aix\",\"aiy\",\"aja\",\"ajg\",\"aji\",\"ajn\",\"ajp\",\"ajt\",\"aju\",\"ajw\",\"ajz\",\"akb\",\"akc\",\"akd\",\"ake\",\"akf\",\"akg\",\"akh\",\"aki\",\"akj\",\"akk\",\"akl\",\"akm\",\"ako\",\"akp\",\"akq\",\"akr\",\"aks\",\"akt\",\"aku\",\"akv\",\"akw\",\"akx\",\"aky\",\"akz\",\"ala\",\"alc\",\"ald\",\"ale\",\"alf\",\"alg\",\"alh\",\"ali\",\"alj\",\"alk\",\"all\",\"alm\",\"aln\",\"alo\",\"alp\",\"alq\",\"alr\",\"als\",\"alt\",\"alu\",\"alv\",\"alw\",\"alx\",\"aly\",\"alz\",\"ama\",\"amb\",\"amc\",\"ame\",\"amf\",\"amg\",\"ami\",\"amj\",\"amk\",\"aml\",\"amm\",\"amn\",\"amo\",\"amp\",\"amq\",\"amr\",\"ams\",\"amt\",\"amu\",\"amv\",\"amw\",\"amx\",\"amy\",\"amz\",\"ana\",\"anb\",\"anc\",\"and\",\"ane\",\"anf\",\"ang\",\"anh\",\"ani\",\"anj\",\"ank\",\"anl\",\"anm\",\"ann\",\"ano\",\"anp\",\"anq\",\"anr\",\"ans\",\"ant\",\"anu\",\"anv\",\"anw\",\"anx\",\"any\",\"anz\",\"aoa\",\"aob\",\"aoc\",\"aod\",\"aoe\",\"aof\",\"aog\",\"aoh\",\"aoi\",\"aoj\",\"aok\",\"aol\",\"aom\",\"aon\",\"aor\",\"aos\",\"aot\",\"aou\",\"aox\",\"aoz\",\"apa\",\"apb\",\"apc\",\"apd\",\"ape\",\"apf\",\"apg\",\"aph\",\"api\",\"apj\",\"apk\",\"apl\",\"apm\",\"apn\",\"apo\",\"app\",\"apq\",\"apr\",\"aps\",\"apt\",\"apu\",\"apv\",\"apw\",\"apx\",\"apy\",\"apz\",\"aqa\",\"aqc\",\"aqd\",\"aqg\",\"aql\",\"aqm\",\"aqn\",\"aqp\",\"aqr\",\"aqt\",\"aqz\",\"arb\",\"arc\",\"ard\",\"are\",\"arh\",\"ari\",\"arj\",\"ark\",\"arl\",\"arn\",\"aro\",\"arp\",\"arq\",\"arr\",\"ars\",\"art\",\"aru\",\"arv\",\"arw\",\"arx\",\"ary\",\"arz\",\"asa\",\"asb\",\"asc\",\"asd\",\"ase\",\"asf\",\"asg\",\"ash\",\"asi\",\"asj\",\"ask\",\"asl\",\"asn\",\"aso\",\"asp\",\"asq\",\"asr\",\"ass\",\"ast\",\"asu\",\"asv\",\"asw\",\"asx\",\"asy\",\"asz\",\"ata\",\"atb\",\"atc\",\"atd\",\"ate\",\"atg\",\"ath\",\"ati\",\"atj\",\"atk\",\"atl\",\"atm\",\"atn\",\"ato\",\"atp\",\"atq\",\"atr\",\"ats\",\"att\",\"atu\",\"atv\",\"atw\",\"atx\",\"aty\",\"atz\",\"aua\",\"aub\",\"auc\",\"aud\",\"aue\",\"auf\",\"aug\",\"auh\",\"aui\",\"auj\",\"auk\",\"aul\",\"aum\",\"aun\",\"auo\",\"aup\",\"auq\",\"aur\",\"aus\",\"aut\",\"auu\",\"auw\",\"aux\",\"auy\",\"auz\",\"avb\",\"avd\",\"avi\",\"avk\",\"avl\",\"avm\",\"avn\",\"avo\",\"avs\",\"avt\",\"avu\",\"avv\",\"awa\",\"awb\",\"awc\",\"awd\",\"awe\",\"awg\",\"awh\",\"awi\",\"awk\",\"awm\",\"awn\",\"awo\",\"awr\",\"aws\",\"awt\",\"awu\",\"awv\",\"aww\",\"awx\",\"awy\",\"axb\",\"axe\",\"axg\",\"axk\",\"axl\",\"axm\",\"axx\",\"aya\",\"ayb\",\"ayc\",\"ayd\",\"aye\",\"ayg\",\"ayh\",\"ayi\",\"ayk\",\"ayl\",\"ayn\",\"ayo\",\"ayp\",\"ayq\",\"ayr\",\"ays\",\"ayt\",\"ayu\",\"ayx\",\"ayy\",\"ayz\",\"aza\",\"azb\",\"azc\",\"azd\",\"azg\",\"azj\",\"azm\",\"azn\",\"azo\",\"azt\",\"azz\",\"baa\",\"bab\",\"bac\",\"bad\",\"bae\",\"baf\",\"bag\",\"bah\",\"bai\",\"baj\",\"bal\",\"ban\",\"bao\",\"bap\",\"bar\",\"bas\",\"bat\",\"bau\",\"bav\",\"baw\",\"bax\",\"bay\",\"baz\",\"bba\",\"bbb\",\"bbc\",\"bbd\",\"bbe\",\"bbf\",\"bbg\",\"bbh\",\"bbi\",\"bbj\",\"bbk\",\"bbl\",\"bbm\",\"bbn\",\"bbo\",\"bbp\",\"bbq\",\"bbr\",\"bbs\",\"bbt\",\"bbu\",\"bbv\",\"bbw\",\"bbx\",\"bby\",\"bbz\",\"bca\",\"bcb\",\"bcc\",\"bcd\",\"bce\",\"bcf\",\"bcg\",\"bch\",\"bci\",\"bcj\",\"bck\",\"bcl\",\"bcm\",\"bcn\",\"bco\",\"bcp\",\"bcq\",\"bcr\",\"bcs\",\"bct\",\"bcu\",\"bcv\",\"bcw\",\"bcy\",\"bcz\",\"bda\",\"bdb\",\"bdc\",\"bdd\",\"bde\",\"bdf\",\"bdg\",\"bdh\",\"bdi\",\"bdj\",\"bdk\",\"bdl\",\"bdm\",\"bdn\",\"bdo\",\"bdp\",\"bdq\",\"bdr\",\"bds\",\"bdt\",\"bdu\",\"bdv\",\"bdw\",\"bdx\",\"bdy\",\"bdz\",\"bea\",\"beb\",\"bec\",\"bed\",\"bee\",\"bef\",\"beg\",\"beh\",\"bei\",\"bej\",\"bek\",\"bem\",\"beo\",\"bep\",\"beq\",\"ber\",\"bes\",\"bet\",\"beu\",\"bev\",\"bew\",\"bex\",\"bey\",\"bez\",\"bfa\",\"bfb\",\"bfc\",\"bfd\",\"bfe\",\"bff\",\"bfg\",\"bfh\",\"bfi\",\"bfj\",\"bfk\",\"bfl\",\"bfm\",\"bfn\",\"bfo\",\"bfp\",\"bfq\",\"bfr\",\"bfs\",\"bft\",\"bfu\",\"bfw\",\"bfx\",\"bfy\",\"bfz\",\"bga\",\"bgb\",\"bgc\",\"bgd\",\"bge\",\"bgf\",\"bgg\",\"bgi\",\"bgj\",\"bgk\",\"bgl\",\"bgm\",\"bgn\",\"bgo\",\"bgp\",\"bgq\",\"bgr\",\"bgs\",\"bgt\",\"bgu\",\"bgv\",\"bgw\",\"bgx\",\"bgy\",\"bgz\",\"bha\",\"bhb\",\"bhc\",\"bhd\",\"bhe\",\"bhf\",\"bhg\",\"bhh\",\"bhi\",\"bhj\",\"bhk\",\"bhl\",\"bhm\",\"bhn\",\"bho\",\"bhp\",\"bhq\",\"bhr\",\"bhs\",\"bht\",\"bhu\",\"bhv\",\"bhw\",\"bhx\",\"bhy\",\"bhz\",\"bia\",\"bib\",\"bic\",\"bid\",\"bie\",\"bif\",\"big\",\"bij\",\"bik\",\"bil\",\"bim\",\"bin\",\"bio\",\"bip\",\"biq\",\"bir\",\"bit\",\"biu\",\"biv\",\"biw\",\"bix\",\"biy\",\"biz\",\"bja\",\"bjb\",\"bjc\",\"bjd\",\"bje\",\"bjf\",\"bjg\",\"bjh\",\"bji\",\"bjj\",\"bjk\",\"bjl\",\"bjm\",\"bjn\",\"bjo\",\"bjp\",\"bjq\",\"bjr\",\"bjs\",\"bjt\",\"bju\",\"bjv\",\"bjw\",\"bjx\",\"bjy\",\"bjz\",\"bka\",\"bkb\",\"bkc\",\"bkd\",\"bkf\",\"bkg\",\"bkh\",\"bki\",\"bkj\",\"bkk\",\"bkl\",\"bkm\",\"bkn\",\"bko\",\"bkp\",\"bkq\",\"bkr\",\"bks\",\"bkt\",\"bku\",\"bkv\",\"bkw\",\"bkx\",\"bky\",\"bkz\",\"bla\",\"blb\",\"blc\",\"bld\",\"ble\",\"blf\",\"blg\",\"blh\",\"bli\",\"blj\",\"blk\",\"bll\",\"blm\",\"bln\",\"blo\",\"blp\",\"blq\",\"blr\",\"bls\",\"blt\",\"blv\",\"blw\",\"blx\",\"bly\",\"blz\",\"bma\",\"bmb\",\"bmc\",\"bmd\",\"bme\",\"bmf\",\"bmg\",\"bmh\",\"bmi\",\"bmj\",\"bmk\",\"bml\",\"bmm\",\"bmn\",\"bmo\",\"bmp\",\"bmq\",\"bmr\",\"bms\",\"bmt\",\"bmu\",\"bmv\",\"bmw\",\"bmx\",\"bmy\",\"bmz\",\"bna\",\"bnb\",\"bnc\",\"bnd\",\"bne\",\"bnf\",\"bng\",\"bni\",\"bnj\",\"bnk\",\"bnl\",\"bnm\",\"bnn\",\"bno\",\"bnp\",\"bnq\",\"bnr\",\"bns\",\"bnt\",\"bnu\",\"bnv\",\"bnw\",\"bnx\",\"bny\",\"bnz\",\"boa\",\"bob\",\"boe\",\"bof\",\"bog\",\"boh\",\"boi\",\"boj\",\"bok\",\"bol\",\"bom\",\"bon\",\"boo\",\"bop\",\"boq\",\"bor\",\"bot\",\"bou\",\"bov\",\"bow\",\"box\",\"boy\",\"boz\",\"bpa\",\"bpb\",\"bpd\",\"bpg\",\"bph\",\"bpi\",\"bpj\",\"bpk\",\"bpl\",\"bpm\",\"bpn\",\"bpo\",\"bpp\",\"bpq\",\"bpr\",\"bps\",\"bpt\",\"bpu\",\"bpv\",\"bpw\",\"bpx\",\"bpy\",\"bpz\",\"bqa\",\"bqb\",\"bqc\",\"bqd\",\"bqf\",\"bqg\",\"bqh\",\"bqi\",\"bqj\",\"bqk\",\"bql\",\"bqm\",\"bqn\",\"bqo\",\"bqp\",\"bqq\",\"bqr\",\"bqs\",\"bqt\",\"bqu\",\"bqv\",\"bqw\",\"bqx\",\"bqy\",\"bqz\",\"bra\",\"brb\",\"brc\",\"brd\",\"brf\",\"brg\",\"brh\",\"bri\",\"brj\",\"brk\",\"brl\",\"brm\",\"brn\",\"bro\",\"brp\",\"brq\",\"brr\",\"brs\",\"brt\",\"bru\",\"brv\",\"brw\",\"brx\",\"bry\",\"brz\",\"bsa\",\"bsb\",\"bsc\",\"bse\",\"bsf\",\"bsg\",\"bsh\",\"bsi\",\"bsj\",\"bsk\",\"bsl\",\"bsm\",\"bsn\",\"bso\",\"bsp\",\"bsq\",\"bsr\",\"bss\",\"bst\",\"bsu\",\"bsv\",\"bsw\",\"bsx\",\"bsy\",\"bta\",\"btb\",\"btc\",\"btd\",\"bte\",\"btf\",\"btg\",\"bth\",\"bti\",\"btj\",\"btk\",\"btl\",\"btm\",\"btn\",\"bto\",\"btp\",\"btq\",\"btr\",\"bts\",\"btt\",\"btu\",\"btv\",\"btw\",\"btx\",\"bty\",\"btz\",\"bua\",\"bub\",\"buc\",\"bud\",\"bue\",\"buf\",\"bug\",\"buh\",\"bui\",\"buj\",\"buk\",\"bum\",\"bun\",\"buo\",\"bup\",\"buq\",\"bus\",\"but\",\"buu\",\"buv\",\"buw\",\"bux\",\"buy\",\"buz\",\"bva\",\"bvb\",\"bvc\",\"bvd\",\"bve\",\"bvf\",\"bvg\",\"bvh\",\"bvi\",\"bvj\",\"bvk\",\"bvl\",\"bvm\",\"bvn\",\"bvo\",\"bvp\",\"bvq\",\"bvr\",\"bvt\",\"bvu\",\"bvv\",\"bvw\",\"bvx\",\"bvy\",\"bvz\",\"bwa\",\"bwb\",\"bwc\",\"bwd\",\"bwe\",\"bwf\",\"bwg\",\"bwh\",\"bwi\",\"bwj\",\"bwk\",\"bwl\",\"bwm\",\"bwn\",\"bwo\",\"bwp\",\"bwq\",\"bwr\",\"bws\",\"bwt\",\"bwu\",\"bww\",\"bwx\",\"bwy\",\"bwz\",\"bxa\",\"bxb\",\"bxc\",\"bxd\",\"bxe\",\"bxf\",\"bxg\",\"bxh\",\"bxi\",\"bxj\",\"bxk\",\"bxl\",\"bxm\",\"bxn\",\"bxo\",\"bxp\",\"bxq\",\"bxr\",\"bxs\",\"bxu\",\"bxv\",\"bxw\",\"bxx\",\"bxz\",\"bya\",\"byb\",\"byc\",\"byd\",\"bye\",\"byf\",\"byg\",\"byh\",\"byi\",\"byj\",\"byk\",\"byl\",\"bym\",\"byn\",\"byo\",\"byp\",\"byq\",\"byr\",\"bys\",\"byt\",\"byv\",\"byw\",\"byx\",\"byy\",\"byz\",\"bza\",\"bzb\",\"bzc\",\"bzd\",\"bze\",\"bzf\",\"bzg\",\"bzh\",\"bzi\",\"bzj\",\"bzk\",\"bzl\",\"bzm\",\"bzn\",\"bzo\",\"bzp\",\"bzq\",\"bzr\",\"bzs\",\"bzt\",\"bzu\",\"bzv\",\"bzw\",\"bzx\",\"bzy\",\"bzz\",\"caa\",\"cab\",\"cac\",\"cad\",\"cae\",\"caf\",\"cag\",\"cah\",\"cai\",\"caj\",\"cak\",\"cal\",\"cam\",\"can\",\"cao\",\"cap\",\"caq\",\"car\",\"cas\",\"cau\",\"cav\",\"caw\",\"cax\",\"cay\",\"caz\",\"cba\",\"cbb\",\"cbc\",\"cbd\",\"cbe\",\"cbg\",\"cbh\",\"cbi\",\"cbj\",\"cbk\",\"cbl\",\"cbn\",\"cbo\",\"cbq\",\"cbr\",\"cbs\",\"cbt\",\"cbu\",\"cbv\",\"cbw\",\"cby\",\"cca\",\"ccc\",\"ccd\",\"cce\",\"ccg\",\"cch\",\"ccj\",\"ccl\",\"ccm\",\"ccn\",\"cco\",\"ccp\",\"ccq\",\"ccr\",\"ccs\",\"cda\",\"cdc\",\"cdd\",\"cde\",\"cdf\",\"cdg\",\"cdh\",\"cdi\",\"cdj\",\"cdm\",\"cdn\",\"cdo\",\"cdr\",\"cds\",\"cdy\",\"cdz\",\"cea\",\"ceb\",\"ceg\",\"cek\",\"cel\",\"cen\",\"cet\",\"cfa\",\"cfd\",\"cfg\",\"cfm\",\"cga\",\"cgc\",\"cgg\",\"cgk\",\"chb\",\"chc\",\"chd\",\"chf\",\"chg\",\"chh\",\"chj\",\"chk\",\"chl\",\"chm\",\"chn\",\"cho\",\"chp\",\"chq\",\"chr\",\"cht\",\"chw\",\"chx\",\"chy\",\"chz\",\"cia\",\"cib\",\"cic\",\"cid\",\"cie\",\"cih\",\"cik\",\"cim\",\"cin\",\"cip\",\"cir\",\"ciw\",\"ciy\",\"cja\",\"cje\",\"cjh\",\"cji\",\"cjk\",\"cjm\",\"cjn\",\"cjo\",\"cjp\",\"cjr\",\"cjs\",\"cjv\",\"cjy\",\"cka\",\"ckb\",\"ckh\",\"ckl\",\"ckn\",\"cko\",\"ckq\",\"ckr\",\"cks\",\"ckt\",\"cku\",\"ckv\",\"ckx\",\"cky\",\"ckz\",\"cla\",\"clc\",\"cld\",\"cle\",\"clh\",\"cli\",\"clj\",\"clk\",\"cll\",\"clm\",\"clo\",\"clt\",\"clu\",\"clw\",\"cly\",\"cma\",\"cmc\",\"cme\",\"cmg\",\"cmi\",\"cmk\",\"cml\",\"cmm\",\"cmn\",\"cmo\",\"cmr\",\"cms\",\"cmt\",\"cna\",\"cnb\",\"cnc\",\"cng\",\"cnh\",\"cni\",\"cnk\",\"cnl\",\"cno\",\"cnr\",\"cns\",\"cnt\",\"cnu\",\"cnw\",\"cnx\",\"coa\",\"cob\",\"coc\",\"cod\",\"coe\",\"cof\",\"cog\",\"coh\",\"coj\",\"cok\",\"col\",\"com\",\"con\",\"coo\",\"cop\",\"coq\",\"cot\",\"cou\",\"cov\",\"cow\",\"cox\",\"coy\",\"coz\",\"cpa\",\"cpb\",\"cpc\",\"cpe\",\"cpf\",\"cpg\",\"cpi\",\"cpn\",\"cpo\",\"cpp\",\"cps\",\"cpu\",\"cpx\",\"cpy\",\"cqd\",\"cqu\",\"cra\",\"crb\",\"crc\",\"crd\",\"crf\",\"crg\",\"crh\",\"cri\",\"crj\",\"crk\",\"crl\",\"crm\",\"crn\",\"cro\",\"crp\",\"crq\",\"crr\",\"crs\",\"crt\",\"crv\",\"crw\",\"crx\",\"cry\",\"crz\",\"csa\",\"csb\",\"csc\",\"csd\",\"cse\",\"csf\",\"csg\",\"csh\",\"csi\",\"csj\",\"csk\",\"csl\",\"csm\",\"csn\",\"cso\",\"csq\",\"csr\",\"css\",\"cst\",\"csu\",\"csv\",\"csw\",\"csy\",\"csz\",\"cta\",\"ctc\",\"ctd\",\"cte\",\"ctg\",\"cth\",\"ctl\",\"ctm\",\"ctn\",\"cto\",\"ctp\",\"cts\",\"ctt\",\"ctu\",\"ctz\",\"cua\",\"cub\",\"cuc\",\"cug\",\"cuh\",\"cui\",\"cuj\",\"cuk\",\"cul\",\"cum\",\"cuo\",\"cup\",\"cuq\",\"cur\",\"cus\",\"cut\",\"cuu\",\"cuv\",\"cuw\",\"cux\",\"cuy\",\"cvg\",\"cvn\",\"cwa\",\"cwb\",\"cwd\",\"cwe\",\"cwg\",\"cwt\",\"cya\",\"cyb\",\"cyo\",\"czh\",\"czk\",\"czn\",\"czo\",\"czt\",\"daa\",\"dac\",\"dad\",\"dae\",\"daf\",\"dag\",\"dah\",\"dai\",\"daj\",\"dak\",\"dal\",\"dam\",\"dao\",\"dap\",\"daq\",\"dar\",\"das\",\"dau\",\"dav\",\"daw\",\"dax\",\"day\",\"daz\",\"dba\",\"dbb\",\"dbd\",\"dbe\",\"dbf\",\"dbg\",\"dbi\",\"dbj\",\"dbl\",\"dbm\",\"dbn\",\"dbo\",\"dbp\",\"dbq\",\"dbr\",\"dbt\",\"dbu\",\"dbv\",\"dbw\",\"dby\",\"dcc\",\"dcr\",\"dda\",\"ddd\",\"dde\",\"ddg\",\"ddi\",\"ddj\",\"ddn\",\"ddo\",\"ddr\",\"dds\",\"ddw\",\"dec\",\"ded\",\"dee\",\"def\",\"deg\",\"deh\",\"dei\",\"dek\",\"del\",\"dem\",\"den\",\"dep\",\"deq\",\"der\",\"des\",\"dev\",\"dez\",\"dga\",\"dgb\",\"dgc\",\"dgd\",\"dge\",\"dgg\",\"dgh\",\"dgi\",\"dgk\",\"dgl\",\"dgn\",\"dgo\",\"dgr\",\"dgs\",\"dgt\",\"dgu\",\"dgw\",\"dgx\",\"dgz\",\"dha\",\"dhd\",\"dhg\",\"dhi\",\"dhl\",\"dhm\",\"dhn\",\"dho\",\"dhr\",\"dhs\",\"dhu\",\"dhv\",\"dhw\",\"dhx\",\"dia\",\"dib\",\"dic\",\"did\",\"dif\",\"dig\",\"dih\",\"dii\",\"dij\",\"dik\",\"dil\",\"dim\",\"din\",\"dio\",\"dip\",\"diq\",\"dir\",\"dis\",\"dit\",\"diu\",\"diw\",\"dix\",\"diy\",\"diz\",\"dja\",\"djb\",\"djc\",\"djd\",\"dje\",\"djf\",\"dji\",\"djj\",\"djk\",\"djl\",\"djm\",\"djn\",\"djo\",\"djr\",\"dju\",\"djw\",\"dka\",\"dkk\",\"dkl\",\"dkr\",\"dks\",\"dkx\",\"dlg\",\"dlk\",\"dlm\",\"dln\",\"dma\",\"dmb\",\"dmc\",\"dmd\",\"dme\",\"dmg\",\"dmk\",\"dml\",\"dmm\",\"dmn\",\"dmo\",\"dmr\",\"dms\",\"dmu\",\"dmv\",\"dmw\",\"dmx\",\"dmy\",\"dna\",\"dnd\",\"dne\",\"dng\",\"dni\",\"dnj\",\"dnk\",\"dnn\",\"dnr\",\"dnt\",\"dnu\",\"dnv\",\"dnw\",\"dny\",\"doa\",\"dob\",\"doc\",\"doe\",\"dof\",\"doh\",\"doi\",\"dok\",\"dol\",\"don\",\"doo\",\"dop\",\"doq\",\"dor\",\"dos\",\"dot\",\"dov\",\"dow\",\"dox\",\"doy\",\"doz\",\"dpp\",\"dra\",\"drb\",\"drc\",\"drd\",\"dre\",\"drg\",\"drh\",\"dri\",\"drl\",\"drn\",\"dro\",\"drq\",\"drr\",\"drs\",\"drt\",\"dru\",\"drw\",\"dry\",\"dsb\",\"dse\",\"dsh\",\"dsi\",\"dsl\",\"dsn\",\"dso\",\"dsq\",\"dta\",\"dtb\",\"dtd\",\"dth\",\"dti\",\"dtk\",\"dtm\",\"dtn\",\"dto\",\"dtp\",\"dtr\",\"dts\",\"dtt\",\"dtu\",\"dty\",\"dua\",\"dub\",\"duc\",\"dud\",\"due\",\"duf\",\"dug\",\"duh\",\"dui\",\"duj\",\"duk\",\"dul\",\"dum\",\"dun\",\"duo\",\"dup\",\"duq\",\"dur\",\"dus\",\"duu\",\"duv\",\"duw\",\"dux\",\"duy\",\"duz\",\"dva\",\"dwa\",\"dwl\",\"dwr\",\"dws\",\"dwu\",\"dww\",\"dwy\",\"dya\",\"dyb\",\"dyd\",\"dyg\",\"dyi\",\"dym\",\"dyn\",\"dyo\",\"dyu\",\"dyy\",\"dza\",\"dzd\",\"dze\",\"dzg\",\"dzl\",\"dzn\",\"eaa\",\"ebg\",\"ebk\",\"ebo\",\"ebr\",\"ebu\",\"ecr\",\"ecs\",\"ecy\",\"eee\",\"efa\",\"efe\",\"efi\",\"ega\",\"egl\",\"ego\",\"egx\",\"egy\",\"ehu\",\"eip\",\"eit\",\"eiv\",\"eja\",\"eka\",\"ekc\",\"eke\",\"ekg\",\"eki\",\"ekk\",\"ekl\",\"ekm\",\"eko\",\"ekp\",\"ekr\",\"eky\",\"ele\",\"elh\",\"eli\",\"elk\",\"elm\",\"elo\",\"elp\",\"elu\",\"elx\",\"ema\",\"emb\",\"eme\",\"emg\",\"emi\",\"emk\",\"emm\",\"emn\",\"emo\",\"emp\",\"ems\",\"emu\",\"emw\",\"emx\",\"emy\",\"ena\",\"enb\",\"enc\",\"end\",\"enf\",\"enh\",\"enl\",\"enm\",\"enn\",\"eno\",\"enq\",\"enr\",\"enu\",\"env\",\"enw\",\"enx\",\"eot\",\"epi\",\"era\",\"erg\",\"erh\",\"eri\",\"erk\",\"ero\",\"err\",\"ers\",\"ert\",\"erw\",\"ese\",\"esg\",\"esh\",\"esi\",\"esk\",\"esl\",\"esm\",\"esn\",\"eso\",\"esq\",\"ess\",\"esu\",\"esx\",\"esy\",\"etb\",\"etc\",\"eth\",\"etn\",\"eto\",\"etr\",\"ets\",\"ett\",\"etu\",\"etx\",\"etz\",\"euq\",\"eve\",\"evh\",\"evn\",\"ewo\",\"ext\",\"eya\",\"eyo\",\"eza\",\"eze\",\"faa\",\"fab\",\"fad\",\"faf\",\"fag\",\"fah\",\"fai\",\"faj\",\"fak\",\"fal\",\"fam\",\"fan\",\"fap\",\"far\",\"fat\",\"fau\",\"fax\",\"fay\",\"faz\",\"fbl\",\"fcs\",\"fer\",\"ffi\",\"ffm\",\"fgr\",\"fia\",\"fie\",\"fil\",\"fip\",\"fir\",\"fit\",\"fiu\",\"fiw\",\"fkk\",\"fkv\",\"fla\",\"flh\",\"fli\",\"fll\",\"fln\",\"flr\",\"fly\",\"fmp\",\"fmu\",\"fnb\",\"fng\",\"fni\",\"fod\",\"foi\",\"fom\",\"fon\",\"for\",\"fos\",\"fox\",\"fpe\",\"fqs\",\"frc\",\"frd\",\"frk\",\"frm\",\"fro\",\"frp\",\"frq\",\"frr\",\"frs\",\"frt\",\"fse\",\"fsl\",\"fss\",\"fub\",\"fuc\",\"fud\",\"fue\",\"fuf\",\"fuh\",\"fui\",\"fuj\",\"fum\",\"fun\",\"fuq\",\"fur\",\"fut\",\"fuu\",\"fuv\",\"fuy\",\"fvr\",\"fwa\",\"fwe\",\"gaa\",\"gab\",\"gac\",\"gad\",\"gae\",\"gaf\",\"gag\",\"gah\",\"gai\",\"gaj\",\"gak\",\"gal\",\"gam\",\"gan\",\"gao\",\"gap\",\"gaq\",\"gar\",\"gas\",\"gat\",\"gau\",\"gav\",\"gaw\",\"gax\",\"gay\",\"gaz\",\"gba\",\"gbb\",\"gbc\",\"gbd\",\"gbe\",\"gbf\",\"gbg\",\"gbh\",\"gbi\",\"gbj\",\"gbk\",\"gbl\",\"gbm\",\"gbn\",\"gbo\",\"gbp\",\"gbq\",\"gbr\",\"gbs\",\"gbu\",\"gbv\",\"gbw\",\"gbx\",\"gby\",\"gbz\",\"gcc\",\"gcd\",\"gce\",\"gcf\",\"gcl\",\"gcn\",\"gcr\",\"gct\",\"gda\",\"gdb\",\"gdc\",\"gdd\",\"gde\",\"gdf\",\"gdg\",\"gdh\",\"gdi\",\"gdj\",\"gdk\",\"gdl\",\"gdm\",\"gdn\",\"gdo\",\"gdq\",\"gdr\",\"gds\",\"gdt\",\"gdu\",\"gdx\",\"gea\",\"geb\",\"gec\",\"ged\",\"geg\",\"geh\",\"gei\",\"gej\",\"gek\",\"gel\",\"gem\",\"geq\",\"ges\",\"gev\",\"gew\",\"gex\",\"gey\",\"gez\",\"gfk\",\"gft\",\"gfx\",\"gga\",\"ggb\",\"ggd\",\"gge\",\"ggg\",\"ggk\",\"ggl\",\"ggn\",\"ggo\",\"ggr\",\"ggt\",\"ggu\",\"ggw\",\"gha\",\"ghc\",\"ghe\",\"ghh\",\"ghk\",\"ghl\",\"ghn\",\"gho\",\"ghr\",\"ghs\",\"ght\",\"gia\",\"gib\",\"gic\",\"gid\",\"gie\",\"gig\",\"gih\",\"gil\",\"gim\",\"gin\",\"gio\",\"gip\",\"giq\",\"gir\",\"gis\",\"git\",\"giu\",\"giw\",\"gix\",\"giy\",\"giz\",\"gji\",\"gjk\",\"gjm\",\"gjn\",\"gjr\",\"gju\",\"gka\",\"gkd\",\"gke\",\"gkn\",\"gko\",\"gkp\",\"gku\",\"glc\",\"gld\",\"glh\",\"gli\",\"glj\",\"glk\",\"gll\",\"glo\",\"glr\",\"glu\",\"glw\",\"gly\",\"gma\",\"gmb\",\"gmd\",\"gme\",\"gmg\",\"gmh\",\"gml\",\"gmm\",\"gmn\",\"gmq\",\"gmu\",\"gmv\",\"gmw\",\"gmx\",\"gmy\",\"gmz\",\"gna\",\"gnb\",\"gnc\",\"gnd\",\"gne\",\"gng\",\"gnh\",\"gni\",\"gnj\",\"gnk\",\"gnl\",\"gnm\",\"gnn\",\"gno\",\"gnq\",\"gnr\",\"gnt\",\"gnu\",\"gnw\",\"gnz\",\"goa\",\"gob\",\"goc\",\"god\",\"goe\",\"gof\",\"gog\",\"goh\",\"goi\",\"goj\",\"gok\",\"gol\",\"gom\",\"gon\",\"goo\",\"gop\",\"goq\",\"gor\",\"gos\",\"got\",\"gou\",\"gow\",\"gox\",\"goy\",\"goz\",\"gpa\",\"gpe\",\"gpn\",\"gqa\",\"gqi\",\"gqn\",\"gqr\",\"gqu\",\"gra\",\"grb\",\"grc\",\"grd\",\"grg\",\"grh\",\"gri\",\"grj\",\"grk\",\"grm\",\"gro\",\"grq\",\"grr\",\"grs\",\"grt\",\"gru\",\"grv\",\"grw\",\"grx\",\"gry\",\"grz\",\"gse\",\"gsg\",\"gsl\",\"gsm\",\"gsn\",\"gso\",\"gsp\",\"gss\",\"gsw\",\"gta\",\"gti\",\"gtu\",\"gua\",\"gub\",\"guc\",\"gud\",\"gue\",\"guf\",\"gug\",\"guh\",\"gui\",\"guk\",\"gul\",\"gum\",\"gun\",\"guo\",\"gup\",\"guq\",\"gur\",\"gus\",\"gut\",\"guu\",\"guv\",\"guw\",\"gux\",\"guz\",\"gva\",\"gvc\",\"gve\",\"gvf\",\"gvj\",\"gvl\",\"gvm\",\"gvn\",\"gvo\",\"gvp\",\"gvr\",\"gvs\",\"gvy\",\"gwa\",\"gwb\",\"gwc\",\"gwd\",\"gwe\",\"gwf\",\"gwg\",\"gwi\",\"gwj\",\"gwm\",\"gwn\",\"gwr\",\"gwt\",\"gwu\",\"gww\",\"gwx\",\"gxx\",\"gya\",\"gyb\",\"gyd\",\"gye\",\"gyf\",\"gyg\",\"gyi\",\"gyl\",\"gym\",\"gyn\",\"gyo\",\"gyr\",\"gyy\",\"gza\",\"gzi\",\"gzn\",\"haa\",\"hab\",\"hac\",\"had\",\"hae\",\"haf\",\"hag\",\"hah\",\"hai\",\"haj\",\"hak\",\"hal\",\"ham\",\"han\",\"hao\",\"hap\",\"haq\",\"har\",\"has\",\"hav\",\"haw\",\"hax\",\"hay\",\"haz\",\"hba\",\"hbb\",\"hbn\",\"hbo\",\"hbu\",\"hca\",\"hch\",\"hdn\",\"hds\",\"hdy\",\"hea\",\"hed\",\"heg\",\"heh\",\"hei\",\"hem\",\"hgm\",\"hgw\",\"hhi\",\"hhr\",\"hhy\",\"hia\",\"hib\",\"hid\",\"hif\",\"hig\",\"hih\",\"hii\",\"hij\",\"hik\",\"hil\",\"him\",\"hio\",\"hir\",\"hit\",\"hiw\",\"hix\",\"hji\",\"hka\",\"hke\",\"hkk\",\"hkn\",\"hks\",\"hla\",\"hlb\",\"hld\",\"hle\",\"hlt\",\"hlu\",\"hma\",\"hmb\",\"hmc\",\"hmd\",\"hme\",\"hmf\",\"hmg\",\"hmh\",\"hmi\",\"hmj\",\"hmk\",\"hml\",\"hmm\",\"hmn\",\"hmp\",\"hmq\",\"hmr\",\"hms\",\"hmt\",\"hmu\",\"hmv\",\"hmw\",\"hmx\",\"hmy\",\"hmz\",\"hna\",\"hnd\",\"hne\",\"hnh\",\"hni\",\"hnj\",\"hnn\",\"hno\",\"hns\",\"hnu\",\"hoa\",\"hob\",\"hoc\",\"hod\",\"hoe\",\"hoh\",\"hoi\",\"hoj\",\"hok\",\"hol\",\"hom\",\"hoo\",\"hop\",\"hor\",\"hos\",\"hot\",\"hov\",\"how\",\"hoy\",\"hoz\",\"hpo\",\"hps\",\"hra\",\"hrc\",\"hre\",\"hrk\",\"hrm\",\"hro\",\"hrp\",\"hrr\",\"hrt\",\"hru\",\"hrw\",\"hrx\",\"hrz\",\"hsb\",\"hsh\",\"hsl\",\"hsn\",\"hss\",\"hti\",\"hto\",\"hts\",\"htu\",\"htx\",\"hub\",\"huc\",\"hud\",\"hue\",\"huf\",\"hug\",\"huh\",\"hui\",\"huj\",\"huk\",\"hul\",\"hum\",\"huo\",\"hup\",\"huq\",\"hur\",\"hus\",\"hut\",\"huu\",\"huv\",\"huw\",\"hux\",\"huy\",\"huz\",\"hvc\",\"hve\",\"hvk\",\"hvn\",\"hvv\",\"hwa\",\"hwc\",\"hwo\",\"hya\",\"hyw\",\"hyx\",\"iai\",\"ian\",\"iap\",\"iar\",\"iba\",\"ibb\",\"ibd\",\"ibe\",\"ibg\",\"ibh\",\"ibi\",\"ibl\",\"ibm\",\"ibn\",\"ibr\",\"ibu\",\"iby\",\"ica\",\"ich\",\"icl\",\"icr\",\"ida\",\"idb\",\"idc\",\"idd\",\"ide\",\"idi\",\"idr\",\"ids\",\"idt\",\"idu\",\"ifa\",\"ifb\",\"ife\",\"iff\",\"ifk\",\"ifm\",\"ifu\",\"ify\",\"igb\",\"ige\",\"igg\",\"igl\",\"igm\",\"ign\",\"igo\",\"igs\",\"igw\",\"ihb\",\"ihi\",\"ihp\",\"ihw\",\"iin\",\"iir\",\"ijc\",\"ije\",\"ijj\",\"ijn\",\"ijo\",\"ijs\",\"ike\",\"iki\",\"ikk\",\"ikl\",\"iko\",\"ikp\",\"ikr\",\"iks\",\"ikt\",\"ikv\",\"ikw\",\"ikx\",\"ikz\",\"ila\",\"ilb\",\"ilg\",\"ili\",\"ilk\",\"ill\",\"ilm\",\"ilo\",\"ilp\",\"ils\",\"ilu\",\"ilv\",\"ilw\",\"ima\",\"ime\",\"imi\",\"iml\",\"imn\",\"imo\",\"imr\",\"ims\",\"imy\",\"inb\",\"inc\",\"ine\",\"ing\",\"inh\",\"inj\",\"inl\",\"inm\",\"inn\",\"ino\",\"inp\",\"ins\",\"int\",\"inz\",\"ior\",\"iou\",\"iow\",\"ipi\",\"ipo\",\"iqu\",\"iqw\",\"ira\",\"ire\",\"irh\",\"iri\",\"irk\",\"irn\",\"iro\",\"irr\",\"iru\",\"irx\",\"iry\",\"isa\",\"isc\",\"isd\",\"ise\",\"isg\",\"ish\",\"isi\",\"isk\",\"ism\",\"isn\",\"iso\",\"isr\",\"ist\",\"isu\",\"itb\",\"itc\",\"itd\",\"ite\",\"iti\",\"itk\",\"itl\",\"itm\",\"ito\",\"itr\",\"its\",\"itt\",\"itv\",\"itw\",\"itx\",\"ity\",\"itz\",\"ium\",\"ivb\",\"ivv\",\"iwk\",\"iwm\",\"iwo\",\"iws\",\"ixc\",\"ixl\",\"iya\",\"iyo\",\"iyx\",\"izh\",\"izi\",\"izr\",\"izz\",\"jaa\",\"jab\",\"jac\",\"jad\",\"jae\",\"jaf\",\"jah\",\"jaj\",\"jak\",\"jal\",\"jam\",\"jan\",\"jao\",\"jaq\",\"jar\",\"jas\",\"jat\",\"jau\",\"jax\",\"jay\",\"jaz\",\"jbe\",\"jbi\",\"jbj\",\"jbk\",\"jbn\",\"jbo\",\"jbr\",\"jbt\",\"jbu\",\"jbw\",\"jcs\",\"jct\",\"jda\",\"jdg\",\"jdt\",\"jeb\",\"jee\",\"jeg\",\"jeh\",\"jei\",\"jek\",\"jel\",\"jen\",\"jer\",\"jet\",\"jeu\",\"jgb\",\"jge\",\"jgk\",\"jgo\",\"jhi\",\"jhs\",\"jia\",\"jib\",\"jic\",\"jid\",\"jie\",\"jig\",\"jih\",\"jii\",\"jil\",\"jim\",\"jio\",\"jiq\",\"jit\",\"jiu\",\"jiv\",\"jiy\",\"jje\",\"jjr\",\"jka\",\"jkm\",\"jko\",\"jkp\",\"jkr\",\"jku\",\"jle\",\"jls\",\"jma\",\"jmb\",\"jmc\",\"jmd\",\"jmi\",\"jml\",\"jmn\",\"jmr\",\"jms\",\"jmw\",\"jmx\",\"jna\",\"jnd\",\"jng\",\"jni\",\"jnj\",\"jnl\",\"jns\",\"job\",\"jod\",\"jog\",\"jor\",\"jos\",\"jow\",\"jpa\",\"jpr\",\"jpx\",\"jqr\",\"jra\",\"jrb\",\"jrr\",\"jrt\",\"jru\",\"jsl\",\"jua\",\"jub\",\"juc\",\"jud\",\"juh\",\"jui\",\"juk\",\"jul\",\"jum\",\"jun\",\"juo\",\"jup\",\"jur\",\"jus\",\"jut\",\"juu\",\"juw\",\"juy\",\"jvd\",\"jvn\",\"jwi\",\"jya\",\"jye\",\"jyy\",\"kaa\",\"kab\",\"kac\",\"kad\",\"kae\",\"kaf\",\"kag\",\"kah\",\"kai\",\"kaj\",\"kak\",\"kam\",\"kao\",\"kap\",\"kaq\",\"kar\",\"kav\",\"kaw\",\"kax\",\"kay\",\"kba\",\"kbb\",\"kbc\",\"kbd\",\"kbe\",\"kbf\",\"kbg\",\"kbh\",\"kbi\",\"kbj\",\"kbk\",\"kbl\",\"kbm\",\"kbn\",\"kbo\",\"kbp\",\"kbq\",\"kbr\",\"kbs\",\"kbt\",\"kbu\",\"kbv\",\"kbw\",\"kbx\",\"kby\",\"kbz\",\"kca\",\"kcb\",\"kcc\",\"kcd\",\"kce\",\"kcf\",\"kcg\",\"kch\",\"kci\",\"kcj\",\"kck\",\"kcl\",\"kcm\",\"kcn\",\"kco\",\"kcp\",\"kcq\",\"kcr\",\"kcs\",\"kct\",\"kcu\",\"kcv\",\"kcw\",\"kcx\",\"kcy\",\"kcz\",\"kda\",\"kdc\",\"kdd\",\"kde\",\"kdf\",\"kdg\",\"kdh\",\"kdi\",\"kdj\",\"kdk\",\"kdl\",\"kdm\",\"kdn\",\"kdo\",\"kdp\",\"kdq\",\"kdr\",\"kdt\",\"kdu\",\"kdv\",\"kdw\",\"kdx\",\"kdy\",\"kdz\",\"kea\",\"keb\",\"kec\",\"ked\",\"kee\",\"kef\",\"keg\",\"keh\",\"kei\",\"kej\",\"kek\",\"kel\",\"kem\",\"ken\",\"keo\",\"kep\",\"keq\",\"ker\",\"kes\",\"ket\",\"keu\",\"kev\",\"kew\",\"kex\",\"key\",\"kez\",\"kfa\",\"kfb\",\"kfc\",\"kfd\",\"kfe\",\"kff\",\"kfg\",\"kfh\",\"kfi\",\"kfj\",\"kfk\",\"kfl\",\"kfm\",\"kfn\",\"kfo\",\"kfp\",\"kfq\",\"kfr\",\"kfs\",\"kft\",\"kfu\",\"kfv\",\"kfw\",\"kfx\",\"kfy\",\"kfz\",\"kga\",\"kgb\",\"kgc\",\"kgd\",\"kge\",\"kgf\",\"kgg\",\"kgh\",\"kgi\",\"kgj\",\"kgk\",\"kgl\",\"kgm\",\"kgn\",\"kgo\",\"kgp\",\"kgq\",\"kgr\",\"kgs\",\"kgt\",\"kgu\",\"kgv\",\"kgw\",\"kgx\",\"kgy\",\"kha\",\"khb\",\"khc\",\"khd\",\"khe\",\"khf\",\"khg\",\"khh\",\"khi\",\"khj\",\"khk\",\"khl\",\"khn\",\"kho\",\"khp\",\"khq\",\"khr\",\"khs\",\"kht\",\"khu\",\"khv\",\"khw\",\"khx\",\"khy\",\"khz\",\"kia\",\"kib\",\"kic\",\"kid\",\"kie\",\"kif\",\"kig\",\"kih\",\"kii\",\"kij\",\"kil\",\"kim\",\"kio\",\"kip\",\"kiq\",\"kis\",\"kit\",\"kiu\",\"kiv\",\"kiw\",\"kix\",\"kiy\",\"kiz\",\"kja\",\"kjb\",\"kjc\",\"kjd\",\"kje\",\"kjf\",\"kjg\",\"kjh\",\"kji\",\"kjj\",\"kjk\",\"kjl\",\"kjm\",\"kjn\",\"kjo\",\"kjp\",\"kjq\",\"kjr\",\"kjs\",\"kjt\",\"kju\",\"kjv\",\"kjx\",\"kjy\",\"kjz\",\"kka\",\"kkb\",\"kkc\",\"kkd\",\"kke\",\"kkf\",\"kkg\",\"kkh\",\"kki\",\"kkj\",\"kkk\",\"kkl\",\"kkm\",\"kkn\",\"kko\",\"kkp\",\"kkq\",\"kkr\",\"kks\",\"kkt\",\"kku\",\"kkv\",\"kkw\",\"kkx\",\"kky\",\"kkz\",\"kla\",\"klb\",\"klc\",\"kld\",\"kle\",\"klf\",\"klg\",\"klh\",\"kli\",\"klj\",\"klk\",\"kll\",\"klm\",\"kln\",\"klo\",\"klp\",\"klq\",\"klr\",\"kls\",\"klt\",\"klu\",\"klv\",\"klw\",\"klx\",\"kly\",\"klz\",\"kma\",\"kmb\",\"kmc\",\"kmd\",\"kme\",\"kmf\",\"kmg\",\"kmh\",\"kmi\",\"kmj\",\"kmk\",\"kml\",\"kmm\",\"kmn\",\"kmo\",\"kmp\",\"kmq\",\"kmr\",\"kms\",\"kmt\",\"kmu\",\"kmv\",\"kmw\",\"kmx\",\"kmy\",\"kmz\",\"kna\",\"knb\",\"knc\",\"knd\",\"kne\",\"knf\",\"kng\",\"kni\",\"knj\",\"knk\",\"knl\",\"knm\",\"knn\",\"kno\",\"knp\",\"knq\",\"knr\",\"kns\",\"knt\",\"knu\",\"knv\",\"knw\",\"knx\",\"kny\",\"knz\",\"koa\",\"koc\",\"kod\",\"koe\",\"kof\",\"kog\",\"koh\",\"koi\",\"koj\",\"kok\",\"kol\",\"koo\",\"kop\",\"koq\",\"kos\",\"kot\",\"kou\",\"kov\",\"kow\",\"kox\",\"koy\",\"koz\",\"kpa\",\"kpb\",\"kpc\",\"kpd\",\"kpe\",\"kpf\",\"kpg\",\"kph\",\"kpi\",\"kpj\",\"kpk\",\"kpl\",\"kpm\",\"kpn\",\"kpo\",\"kpp\",\"kpq\",\"kpr\",\"kps\",\"kpt\",\"kpu\",\"kpv\",\"kpw\",\"kpx\",\"kpy\",\"kpz\",\"kqa\",\"kqb\",\"kqc\",\"kqd\",\"kqe\",\"kqf\",\"kqg\",\"kqh\",\"kqi\",\"kqj\",\"kqk\",\"kql\",\"kqm\",\"kqn\",\"kqo\",\"kqp\",\"kqq\",\"kqr\",\"kqs\",\"kqt\",\"kqu\",\"kqv\",\"kqw\",\"kqx\",\"kqy\",\"kqz\",\"kra\",\"krb\",\"krc\",\"krd\",\"kre\",\"krf\",\"krh\",\"kri\",\"krj\",\"krk\",\"krl\",\"krm\",\"krn\",\"kro\",\"krp\",\"krr\",\"krs\",\"krt\",\"kru\",\"krv\",\"krw\",\"krx\",\"kry\",\"krz\",\"ksa\",\"ksb\",\"ksc\",\"ksd\",\"kse\",\"ksf\",\"ksg\",\"ksh\",\"ksi\",\"ksj\",\"ksk\",\"ksl\",\"ksm\",\"ksn\",\"kso\",\"ksp\",\"ksq\",\"ksr\",\"kss\",\"kst\",\"ksu\",\"ksv\",\"ksw\",\"ksx\",\"ksy\",\"ksz\",\"kta\",\"ktb\",\"ktc\",\"ktd\",\"kte\",\"ktf\",\"ktg\",\"kth\",\"kti\",\"ktj\",\"ktk\",\"ktl\",\"ktm\",\"ktn\",\"kto\",\"ktp\",\"ktq\",\"ktr\",\"kts\",\"ktt\",\"ktu\",\"ktv\",\"ktw\",\"ktx\",\"kty\",\"ktz\",\"kub\",\"kuc\",\"kud\",\"kue\",\"kuf\",\"kug\",\"kuh\",\"kui\",\"kuj\",\"kuk\",\"kul\",\"kum\",\"kun\",\"kuo\",\"kup\",\"kuq\",\"kus\",\"kut\",\"kuu\",\"kuv\",\"kuw\",\"kux\",\"kuy\",\"kuz\",\"kva\",\"kvb\",\"kvc\",\"kvd\",\"kve\",\"kvf\",\"kvg\",\"kvh\",\"kvi\",\"kvj\",\"kvk\",\"kvl\",\"kvm\",\"kvn\",\"kvo\",\"kvp\",\"kvq\",\"kvr\",\"kvs\",\"kvt\",\"kvu\",\"kvv\",\"kvw\",\"kvx\",\"kvy\",\"kvz\",\"kwa\",\"kwb\",\"kwc\",\"kwd\",\"kwe\",\"kwf\",\"kwg\",\"kwh\",\"kwi\",\"kwj\",\"kwk\",\"kwl\",\"kwm\",\"kwn\",\"kwo\",\"kwp\",\"kwq\",\"kwr\",\"kws\",\"kwt\",\"kwu\",\"kwv\",\"kww\",\"kwx\",\"kwy\",\"kwz\",\"kxa\",\"kxb\",\"kxc\",\"kxd\",\"kxe\",\"kxf\",\"kxh\",\"kxi\",\"kxj\",\"kxk\",\"kxl\",\"kxm\",\"kxn\",\"kxo\",\"kxp\",\"kxq\",\"kxr\",\"kxs\",\"kxt\",\"kxu\",\"kxv\",\"kxw\",\"kxx\",\"kxy\",\"kxz\",\"kya\",\"kyb\",\"kyc\",\"kyd\",\"kye\",\"kyf\",\"kyg\",\"kyh\",\"kyi\",\"kyj\",\"kyk\",\"kyl\",\"kym\",\"kyn\",\"kyo\",\"kyp\",\"kyq\",\"kyr\",\"kys\",\"kyt\",\"kyu\",\"kyv\",\"kyw\",\"kyx\",\"kyy\",\"kyz\",\"kza\",\"kzb\",\"kzc\",\"kzd\",\"kze\",\"kzf\",\"kzg\",\"kzh\",\"kzi\",\"kzj\",\"kzk\",\"kzl\",\"kzm\",\"kzn\",\"kzo\",\"kzp\",\"kzq\",\"kzr\",\"kzs\",\"kzt\",\"kzu\",\"kzv\",\"kzw\",\"kzx\",\"kzy\",\"kzz\",\"laa\",\"lab\",\"lac\",\"lad\",\"lae\",\"laf\",\"lag\",\"lah\",\"lai\",\"laj\",\"lak\",\"lal\",\"lam\",\"lan\",\"lap\",\"laq\",\"lar\",\"las\",\"lau\",\"law\",\"lax\",\"lay\",\"laz\",\"lba\",\"lbb\",\"lbc\",\"lbe\",\"lbf\",\"lbg\",\"lbi\",\"lbj\",\"lbk\",\"lbl\",\"lbm\",\"lbn\",\"lbo\",\"lbq\",\"lbr\",\"lbs\",\"lbt\",\"lbu\",\"lbv\",\"lbw\",\"lbx\",\"lby\",\"lbz\",\"lcc\",\"lcd\",\"lce\",\"lcf\",\"lch\",\"lcl\",\"lcm\",\"lcp\",\"lcq\",\"lcs\",\"lda\",\"ldb\",\"ldd\",\"ldg\",\"ldh\",\"ldi\",\"ldj\",\"ldk\",\"ldl\",\"ldm\",\"ldn\",\"ldo\",\"ldp\",\"ldq\",\"lea\",\"leb\",\"lec\",\"led\",\"lee\",\"lef\",\"leg\",\"leh\",\"lei\",\"lej\",\"lek\",\"lel\",\"lem\",\"len\",\"leo\",\"lep\",\"leq\",\"ler\",\"les\",\"let\",\"leu\",\"lev\",\"lew\",\"lex\",\"ley\",\"lez\",\"lfa\",\"lfn\",\"lga\",\"lgb\",\"lgg\",\"lgh\",\"lgi\",\"lgk\",\"lgl\",\"lgm\",\"lgn\",\"lgq\",\"lgr\",\"lgt\",\"lgu\",\"lgz\",\"lha\",\"lhh\",\"lhi\",\"lhl\",\"lhm\",\"lhn\",\"lhp\",\"lhs\",\"lht\",\"lhu\",\"lia\",\"lib\",\"lic\",\"lid\",\"lie\",\"lif\",\"lig\",\"lih\",\"lii\",\"lij\",\"lik\",\"lil\",\"lio\",\"lip\",\"liq\",\"lir\",\"lis\",\"liu\",\"liv\",\"liw\",\"lix\",\"liy\",\"liz\",\"lja\",\"lje\",\"lji\",\"ljl\",\"ljp\",\"ljw\",\"ljx\",\"lka\",\"lkb\",\"lkc\",\"lkd\",\"lke\",\"lkh\",\"lki\",\"lkj\",\"lkl\",\"lkm\",\"lkn\",\"lko\",\"lkr\",\"lks\",\"lkt\",\"lku\",\"lky\",\"lla\",\"llb\",\"llc\",\"lld\",\"lle\",\"llf\",\"llg\",\"llh\",\"lli\",\"llj\",\"llk\",\"lll\",\"llm\",\"lln\",\"llo\",\"llp\",\"llq\",\"lls\",\"llu\",\"llx\",\"lma\",\"lmb\",\"lmc\",\"lmd\",\"lme\",\"lmf\",\"lmg\",\"lmh\",\"lmi\",\"lmj\",\"lmk\",\"lml\",\"lmm\",\"lmn\",\"lmo\",\"lmp\",\"lmq\",\"lmr\",\"lmu\",\"lmv\",\"lmw\",\"lmx\",\"lmy\",\"lmz\",\"lna\",\"lnb\",\"lnd\",\"lng\",\"lnh\",\"lni\",\"lnj\",\"lnl\",\"lnm\",\"lnn\",\"lno\",\"lns\",\"lnu\",\"lnw\",\"lnz\",\"loa\",\"lob\",\"loc\",\"loe\",\"lof\",\"log\",\"loh\",\"loi\",\"loj\",\"lok\",\"lol\",\"lom\",\"lon\",\"loo\",\"lop\",\"loq\",\"lor\",\"los\",\"lot\",\"lou\",\"lov\",\"low\",\"lox\",\"loy\",\"loz\",\"lpa\",\"lpe\",\"lpn\",\"lpo\",\"lpx\",\"lra\",\"lrc\",\"lre\",\"lrg\",\"lri\",\"lrk\",\"lrl\",\"lrm\",\"lrn\",\"lro\",\"lrr\",\"lrt\",\"lrv\",\"lrz\",\"lsa\",\"lsd\",\"lse\",\"lsg\",\"lsh\",\"lsi\",\"lsl\",\"lsm\",\"lso\",\"lsp\",\"lsr\",\"lss\",\"lst\",\"lsy\",\"ltc\",\"ltg\",\"lth\",\"lti\",\"ltn\",\"lto\",\"lts\",\"ltu\",\"lua\",\"luc\",\"lud\",\"lue\",\"luf\",\"lui\",\"luj\",\"luk\",\"lul\",\"lum\",\"lun\",\"luo\",\"lup\",\"luq\",\"lur\",\"lus\",\"lut\",\"luu\",\"luv\",\"luw\",\"luy\",\"luz\",\"lva\",\"lvk\",\"lvs\",\"lvu\",\"lwa\",\"lwe\",\"lwg\",\"lwh\",\"lwl\",\"lwm\",\"lwo\",\"lws\",\"lwt\",\"lwu\",\"lww\",\"lya\",\"lyg\",\"lyn\",\"lzh\",\"lzl\",\"lzn\",\"lzz\",\"maa\",\"mab\",\"mad\",\"mae\",\"maf\",\"mag\",\"mai\",\"maj\",\"mak\",\"mam\",\"man\",\"map\",\"maq\",\"mas\",\"mat\",\"mau\",\"mav\",\"maw\",\"max\",\"maz\",\"mba\",\"mbb\",\"mbc\",\"mbd\",\"mbe\",\"mbf\",\"mbh\",\"mbi\",\"mbj\",\"mbk\",\"mbl\",\"mbm\",\"mbn\",\"mbo\",\"mbp\",\"mbq\",\"mbr\",\"mbs\",\"mbt\",\"mbu\",\"mbv\",\"mbw\",\"mbx\",\"mby\",\"mbz\",\"mca\",\"mcb\",\"mcc\",\"mcd\",\"mce\",\"mcf\",\"mcg\",\"mch\",\"mci\",\"mcj\",\"mck\",\"mcl\",\"mcm\",\"mcn\",\"mco\",\"mcp\",\"mcq\",\"mcr\",\"mcs\",\"mct\",\"mcu\",\"mcv\",\"mcw\",\"mcx\",\"mcy\",\"mcz\",\"mda\",\"mdb\",\"mdc\",\"mdd\",\"mde\",\"mdf\",\"mdg\",\"mdh\",\"mdi\",\"mdj\",\"mdk\",\"mdl\",\"mdm\",\"mdn\",\"mdp\",\"mdq\",\"mdr\",\"mds\",\"mdt\",\"mdu\",\"mdv\",\"mdw\",\"mdx\",\"mdy\",\"mdz\",\"mea\",\"meb\",\"mec\",\"med\",\"mee\",\"mef\",\"meg\",\"meh\",\"mei\",\"mej\",\"mek\",\"mel\",\"mem\",\"men\",\"meo\",\"mep\",\"meq\",\"mer\",\"mes\",\"met\",\"meu\",\"mev\",\"mew\",\"mey\",\"mez\",\"mfa\",\"mfb\",\"mfc\",\"mfd\",\"mfe\",\"mff\",\"mfg\",\"mfh\",\"mfi\",\"mfj\",\"mfk\",\"mfl\",\"mfm\",\"mfn\",\"mfo\",\"mfp\",\"mfq\",\"mfr\",\"mfs\",\"mft\",\"mfu\",\"mfv\",\"mfw\",\"mfx\",\"mfy\",\"mfz\",\"mga\",\"mgb\",\"mgc\",\"mgd\",\"mge\",\"mgf\",\"mgg\",\"mgh\",\"mgi\",\"mgj\",\"mgk\",\"mgl\",\"mgm\",\"mgn\",\"mgo\",\"mgp\",\"mgq\",\"mgr\",\"mgs\",\"mgt\",\"mgu\",\"mgv\",\"mgw\",\"mgx\",\"mgy\",\"mgz\",\"mha\",\"mhb\",\"mhc\",\"mhd\",\"mhe\",\"mhf\",\"mhg\",\"mhh\",\"mhi\",\"mhj\",\"mhk\",\"mhl\",\"mhm\",\"mhn\",\"mho\",\"mhp\",\"mhq\",\"mhr\",\"mhs\",\"mht\",\"mhu\",\"mhw\",\"mhx\",\"mhy\",\"mhz\",\"mia\",\"mib\",\"mic\",\"mid\",\"mie\",\"mif\",\"mig\",\"mih\",\"mii\",\"mij\",\"mik\",\"mil\",\"mim\",\"min\",\"mio\",\"mip\",\"miq\",\"mir\",\"mis\",\"mit\",\"miu\",\"miw\",\"mix\",\"miy\",\"miz\",\"mja\",\"mjb\",\"mjc\",\"mjd\",\"mje\",\"mjg\",\"mjh\",\"mji\",\"mjj\",\"mjk\",\"mjl\",\"mjm\",\"mjn\",\"mjo\",\"mjp\",\"mjq\",\"mjr\",\"mjs\",\"mjt\",\"mju\",\"mjv\",\"mjw\",\"mjx\",\"mjy\",\"mjz\",\"mka\",\"mkb\",\"mkc\",\"mke\",\"mkf\",\"mkg\",\"mkh\",\"mki\",\"mkj\",\"mkk\",\"mkl\",\"mkm\",\"mkn\",\"mko\",\"mkp\",\"mkq\",\"mkr\",\"mks\",\"mkt\",\"mku\",\"mkv\",\"mkw\",\"mkx\",\"mky\",\"mkz\",\"mla\",\"mlb\",\"mlc\",\"mld\",\"mle\",\"mlf\",\"mlh\",\"mli\",\"mlj\",\"mlk\",\"mll\",\"mlm\",\"mln\",\"mlo\",\"mlp\",\"mlq\",\"mlr\",\"mls\",\"mlu\",\"mlv\",\"mlw\",\"mlx\",\"mlz\",\"mma\",\"mmb\",\"mmc\",\"mmd\",\"mme\",\"mmf\",\"mmg\",\"mmh\",\"mmi\",\"mmj\",\"mmk\",\"mml\",\"mmm\",\"mmn\",\"mmo\",\"mmp\",\"mmq\",\"mmr\",\"mmt\",\"mmu\",\"mmv\",\"mmw\",\"mmx\",\"mmy\",\"mmz\",\"mna\",\"mnb\",\"mnc\",\"mnd\",\"mne\",\"mnf\",\"mng\",\"mnh\",\"mni\",\"mnj\",\"mnk\",\"mnl\",\"mnm\",\"mnn\",\"mno\",\"mnp\",\"mnq\",\"mnr\",\"mns\",\"mnt\",\"mnu\",\"mnv\",\"mnw\",\"mnx\",\"mny\",\"mnz\",\"moa\",\"moc\",\"mod\",\"moe\",\"mof\",\"mog\",\"moh\",\"moi\",\"moj\",\"mok\",\"mom\",\"moo\",\"mop\",\"moq\",\"mor\",\"mos\",\"mot\",\"mou\",\"mov\",\"mow\",\"mox\",\"moy\",\"moz\",\"mpa\",\"mpb\",\"mpc\",\"mpd\",\"mpe\",\"mpg\",\"mph\",\"mpi\",\"mpj\",\"mpk\",\"mpl\",\"mpm\",\"mpn\",\"mpo\",\"mpp\",\"mpq\",\"mpr\",\"mps\",\"mpt\",\"mpu\",\"mpv\",\"mpw\",\"mpx\",\"mpy\",\"mpz\",\"mqa\",\"mqb\",\"mqc\",\"mqe\",\"mqf\",\"mqg\",\"mqh\",\"mqi\",\"mqj\",\"mqk\",\"mql\",\"mqm\",\"mqn\",\"mqo\",\"mqp\",\"mqq\",\"mqr\",\"mqs\",\"mqt\",\"mqu\",\"mqv\",\"mqw\",\"mqx\",\"mqy\",\"mqz\",\"mra\",\"mrb\",\"mrc\",\"mrd\",\"mre\",\"mrf\",\"mrg\",\"mrh\",\"mrj\",\"mrk\",\"mrl\",\"mrm\",\"mrn\",\"mro\",\"mrp\",\"mrq\",\"mrr\",\"mrs\",\"mrt\",\"mru\",\"mrv\",\"mrw\",\"mrx\",\"mry\",\"mrz\",\"msb\",\"msc\",\"msd\",\"mse\",\"msf\",\"msg\",\"msh\",\"msi\",\"msj\",\"msk\",\"msl\",\"msm\",\"msn\",\"mso\",\"msp\",\"msq\",\"msr\",\"mss\",\"mst\",\"msu\",\"msv\",\"msw\",\"msx\",\"msy\",\"msz\",\"mta\",\"mtb\",\"mtc\",\"mtd\",\"mte\",\"mtf\",\"mtg\",\"mth\",\"mti\",\"mtj\",\"mtk\",\"mtl\",\"mtm\",\"mtn\",\"mto\",\"mtp\",\"mtq\",\"mtr\",\"mts\",\"mtt\",\"mtu\",\"mtv\",\"mtw\",\"mtx\",\"mty\",\"mua\",\"mub\",\"muc\",\"mud\",\"mue\",\"mug\",\"muh\",\"mui\",\"muj\",\"muk\",\"mul\",\"mum\",\"mun\",\"muo\",\"mup\",\"muq\",\"mur\",\"mus\",\"mut\",\"muu\",\"muv\",\"mux\",\"muy\",\"muz\",\"mva\",\"mvb\",\"mvd\",\"mve\",\"mvf\",\"mvg\",\"mvh\",\"mvi\",\"mvk\",\"mvl\",\"mvm\",\"mvn\",\"mvo\",\"mvp\",\"mvq\",\"mvr\",\"mvs\",\"mvt\",\"mvu\",\"mvv\",\"mvw\",\"mvx\",\"mvy\",\"mvz\",\"mwa\",\"mwb\",\"mwc\",\"mwd\",\"mwe\",\"mwf\",\"mwg\",\"mwh\",\"mwi\",\"mwj\",\"mwk\",\"mwl\",\"mwm\",\"mwn\",\"mwo\",\"mwp\",\"mwq\",\"mwr\",\"mws\",\"mwt\",\"mwu\",\"mwv\",\"mww\",\"mwx\",\"mwy\",\"mwz\",\"mxa\",\"mxb\",\"mxc\",\"mxd\",\"mxe\",\"mxf\",\"mxg\",\"mxh\",\"mxi\",\"mxj\",\"mxk\",\"mxl\",\"mxm\",\"mxn\",\"mxo\",\"mxp\",\"mxq\",\"mxr\",\"mxs\",\"mxt\",\"mxu\",\"mxv\",\"mxw\",\"mxx\",\"mxy\",\"mxz\",\"myb\",\"myc\",\"myd\",\"mye\",\"myf\",\"myg\",\"myh\",\"myi\",\"myj\",\"myk\",\"myl\",\"mym\",\"myn\",\"myo\",\"myp\",\"myq\",\"myr\",\"mys\",\"myt\",\"myu\",\"myv\",\"myw\",\"myx\",\"myy\",\"myz\",\"mza\",\"mzb\",\"mzc\",\"mzd\",\"mze\",\"mzg\",\"mzh\",\"mzi\",\"mzj\",\"mzk\",\"mzl\",\"mzm\",\"mzn\",\"mzo\",\"mzp\",\"mzq\",\"mzr\",\"mzs\",\"mzt\",\"mzu\",\"mzv\",\"mzw\",\"mzx\",\"mzy\",\"mzz\",\"naa\",\"nab\",\"nac\",\"nad\",\"nae\",\"naf\",\"nag\",\"nah\",\"nai\",\"naj\",\"nak\",\"nal\",\"nam\",\"nan\",\"nao\",\"nap\",\"naq\",\"nar\",\"nas\",\"nat\",\"naw\",\"nax\",\"nay\",\"naz\",\"nba\",\"nbb\",\"nbc\",\"nbd\",\"nbe\",\"nbf\",\"nbg\",\"nbh\",\"nbi\",\"nbj\",\"nbk\",\"nbm\",\"nbn\",\"nbo\",\"nbp\",\"nbq\",\"nbr\",\"nbs\",\"nbt\",\"nbu\",\"nbv\",\"nbw\",\"nbx\",\"nby\",\"nca\",\"ncb\",\"ncc\",\"ncd\",\"nce\",\"ncf\",\"ncg\",\"nch\",\"nci\",\"ncj\",\"nck\",\"ncl\",\"ncm\",\"ncn\",\"nco\",\"ncp\",\"ncq\",\"ncr\",\"ncs\",\"nct\",\"ncu\",\"ncx\",\"ncz\",\"nda\",\"ndb\",\"ndc\",\"ndd\",\"ndf\",\"ndg\",\"ndh\",\"ndi\",\"ndj\",\"ndk\",\"ndl\",\"ndm\",\"ndn\",\"ndp\",\"ndq\",\"ndr\",\"nds\",\"ndt\",\"ndu\",\"ndv\",\"ndw\",\"ndx\",\"ndy\",\"ndz\",\"nea\",\"neb\",\"nec\",\"ned\",\"nee\",\"nef\",\"neg\",\"neh\",\"nei\",\"nej\",\"nek\",\"nem\",\"nen\",\"neo\",\"neq\",\"ner\",\"nes\",\"net\",\"neu\",\"nev\",\"new\",\"nex\",\"ney\",\"nez\",\"nfa\",\"nfd\",\"nfl\",\"nfr\",\"nfu\",\"nga\",\"ngb\",\"ngc\",\"ngd\",\"nge\",\"ngf\",\"ngg\",\"ngh\",\"ngi\",\"ngj\",\"ngk\",\"ngl\",\"ngm\",\"ngn\",\"ngo\",\"ngp\",\"ngq\",\"ngr\",\"ngs\",\"ngt\",\"ngu\",\"ngv\",\"ngw\",\"ngx\",\"ngy\",\"ngz\",\"nha\",\"nhb\",\"nhc\",\"nhd\",\"nhe\",\"nhf\",\"nhg\",\"nhh\",\"nhi\",\"nhk\",\"nhm\",\"nhn\",\"nho\",\"nhp\",\"nhq\",\"nhr\",\"nht\",\"nhu\",\"nhv\",\"nhw\",\"nhx\",\"nhy\",\"nhz\",\"nia\",\"nib\",\"nic\",\"nid\",\"nie\",\"nif\",\"nig\",\"nih\",\"nii\",\"nij\",\"nik\",\"nil\",\"nim\",\"nin\",\"nio\",\"niq\",\"nir\",\"nis\",\"nit\",\"niu\",\"niv\",\"niw\",\"nix\",\"niy\",\"niz\",\"nja\",\"njb\",\"njd\",\"njh\",\"nji\",\"njj\",\"njl\",\"njm\",\"njn\",\"njo\",\"njr\",\"njs\",\"njt\",\"nju\",\"njx\",\"njy\",\"njz\",\"nka\",\"nkb\",\"nkc\",\"nkd\",\"nke\",\"nkf\",\"nkg\",\"nkh\",\"nki\",\"nkj\",\"nkk\",\"nkm\",\"nkn\",\"nko\",\"nkp\",\"nkq\",\"nkr\",\"nks\",\"nkt\",\"nku\",\"nkv\",\"nkw\",\"nkx\",\"nkz\",\"nla\",\"nlc\",\"nle\",\"nlg\",\"nli\",\"nlj\",\"nlk\",\"nll\",\"nlm\",\"nln\",\"nlo\",\"nlq\",\"nlr\",\"nlu\",\"nlv\",\"nlw\",\"nlx\",\"nly\",\"nlz\",\"nma\",\"nmb\",\"nmc\",\"nmd\",\"nme\",\"nmf\",\"nmg\",\"nmh\",\"nmi\",\"nmj\",\"nmk\",\"nml\",\"nmm\",\"nmn\",\"nmo\",\"nmp\",\"nmq\",\"nmr\",\"nms\",\"nmt\",\"nmu\",\"nmv\",\"nmw\",\"nmx\",\"nmy\",\"nmz\",\"nna\",\"nnb\",\"nnc\",\"nnd\",\"nne\",\"nnf\",\"nng\",\"nnh\",\"nni\",\"nnj\",\"nnk\",\"nnl\",\"nnm\",\"nnn\",\"nnp\",\"nnq\",\"nnr\",\"nns\",\"nnt\",\"nnu\",\"nnv\",\"nnw\",\"nnx\",\"nny\",\"nnz\",\"noa\",\"noc\",\"nod\",\"noe\",\"nof\",\"nog\",\"noh\",\"noi\",\"noj\",\"nok\",\"nol\",\"nom\",\"non\",\"noo\",\"nop\",\"noq\",\"nos\",\"not\",\"nou\",\"nov\",\"now\",\"noy\",\"noz\",\"npa\",\"npb\",\"npg\",\"nph\",\"npi\",\"npl\",\"npn\",\"npo\",\"nps\",\"npu\",\"npx\",\"npy\",\"nqg\",\"nqk\",\"nql\",\"nqm\",\"nqn\",\"nqo\",\"nqq\",\"nqy\",\"nra\",\"nrb\",\"nrc\",\"nre\",\"nrf\",\"nrg\",\"nri\",\"nrk\",\"nrl\",\"nrm\",\"nrn\",\"nrp\",\"nrr\",\"nrt\",\"nru\",\"nrx\",\"nrz\",\"nsa\",\"nsc\",\"nsd\",\"nse\",\"nsf\",\"nsg\",\"nsh\",\"nsi\",\"nsk\",\"nsl\",\"nsm\",\"nsn\",\"nso\",\"nsp\",\"nsq\",\"nsr\",\"nss\",\"nst\",\"nsu\",\"nsv\",\"nsw\",\"nsx\",\"nsy\",\"nsz\",\"ntd\",\"nte\",\"ntg\",\"nti\",\"ntj\",\"ntk\",\"ntm\",\"nto\",\"ntp\",\"ntr\",\"nts\",\"ntu\",\"ntw\",\"ntx\",\"nty\",\"ntz\",\"nua\",\"nub\",\"nuc\",\"nud\",\"nue\",\"nuf\",\"nug\",\"nuh\",\"nui\",\"nuj\",\"nuk\",\"nul\",\"num\",\"nun\",\"nuo\",\"nup\",\"nuq\",\"nur\",\"nus\",\"nut\",\"nuu\",\"nuv\",\"nuw\",\"nux\",\"nuy\",\"nuz\",\"nvh\",\"nvm\",\"nvo\",\"nwa\",\"nwb\",\"nwc\",\"nwe\",\"nwg\",\"nwi\",\"nwm\",\"nwo\",\"nwr\",\"nwx\",\"nwy\",\"nxa\",\"nxd\",\"nxe\",\"nxg\",\"nxi\",\"nxk\",\"nxl\",\"nxm\",\"nxn\",\"nxo\",\"nxq\",\"nxr\",\"nxu\",\"nxx\",\"nyb\",\"nyc\",\"nyd\",\"nye\",\"nyf\",\"nyg\",\"nyh\",\"nyi\",\"nyj\",\"nyk\",\"nyl\",\"nym\",\"nyn\",\"nyo\",\"nyp\",\"nyq\",\"nyr\",\"nys\",\"nyt\",\"nyu\",\"nyv\",\"nyw\",\"nyx\",\"nyy\",\"nza\",\"nzb\",\"nzd\",\"nzi\",\"nzk\",\"nzm\",\"nzs\",\"nzu\",\"nzy\",\"nzz\",\"oaa\",\"oac\",\"oar\",\"oav\",\"obi\",\"obk\",\"obl\",\"obm\",\"obo\",\"obr\",\"obt\",\"obu\",\"oca\",\"och\",\"oco\",\"ocu\",\"oda\",\"odk\",\"odt\",\"odu\",\"ofo\",\"ofs\",\"ofu\",\"ogb\",\"ogc\",\"oge\",\"ogg\",\"ogo\",\"ogu\",\"oht\",\"ohu\",\"oia\",\"oin\",\"ojb\",\"ojc\",\"ojg\",\"ojp\",\"ojs\",\"ojv\",\"ojw\",\"oka\",\"okb\",\"okd\",\"oke\",\"okg\",\"okh\",\"oki\",\"okj\",\"okk\",\"okl\",\"okm\",\"okn\",\"oko\",\"okr\",\"oks\",\"oku\",\"okv\",\"okx\",\"ola\",\"old\",\"ole\",\"olk\",\"olm\",\"olo\",\"olr\",\"olt\",\"olu\",\"oma\",\"omb\",\"omc\",\"ome\",\"omg\",\"omi\",\"omk\",\"oml\",\"omn\",\"omo\",\"omp\",\"omq\",\"omr\",\"omt\",\"omu\",\"omv\",\"omw\",\"omx\",\"ona\",\"onb\",\"one\",\"ong\",\"oni\",\"onj\",\"onk\",\"onn\",\"ono\",\"onp\",\"onr\",\"ons\",\"ont\",\"onu\",\"onw\",\"onx\",\"ood\",\"oog\",\"oon\",\"oor\",\"oos\",\"opa\",\"opk\",\"opm\",\"opo\",\"opt\",\"opy\",\"ora\",\"orc\",\"ore\",\"org\",\"orh\",\"orn\",\"oro\",\"orr\",\"ors\",\"ort\",\"oru\",\"orv\",\"orw\",\"orx\",\"ory\",\"orz\",\"osa\",\"osc\",\"osi\",\"oso\",\"osp\",\"ost\",\"osu\",\"osx\",\"ota\",\"otb\",\"otd\",\"ote\",\"oti\",\"otk\",\"otl\",\"otm\",\"otn\",\"oto\",\"otq\",\"otr\",\"ots\",\"ott\",\"otu\",\"otw\",\"otx\",\"oty\",\"otz\",\"oua\",\"oub\",\"oue\",\"oui\",\"oum\",\"oun\",\"ovd\",\"owi\",\"owl\",\"oyb\",\"oyd\",\"oym\",\"oyy\",\"ozm\",\"paa\",\"pab\",\"pac\",\"pad\",\"pae\",\"paf\",\"pag\",\"pah\",\"pai\",\"pak\",\"pal\",\"pam\",\"pao\",\"pap\",\"paq\",\"par\",\"pas\",\"pat\",\"pau\",\"pav\",\"paw\",\"pax\",\"pay\",\"paz\",\"pbb\",\"pbc\",\"pbe\",\"pbf\",\"pbg\",\"pbh\",\"pbi\",\"pbl\",\"pbm\",\"pbn\",\"pbo\",\"pbp\",\"pbr\",\"pbs\",\"pbt\",\"pbu\",\"pbv\",\"pby\",\"pbz\",\"pca\",\"pcb\",\"pcc\",\"pcd\",\"pce\",\"pcf\",\"pcg\",\"pch\",\"pci\",\"pcj\",\"pck\",\"pcl\",\"pcm\",\"pcn\",\"pcp\",\"pcr\",\"pcw\",\"pda\",\"pdc\",\"pdi\",\"pdn\",\"pdo\",\"pdt\",\"pdu\",\"pea\",\"peb\",\"ped\",\"pee\",\"pef\",\"peg\",\"peh\",\"pei\",\"pej\",\"pek\",\"pel\",\"pem\",\"peo\",\"pep\",\"peq\",\"pes\",\"pev\",\"pex\",\"pey\",\"pez\",\"pfa\",\"pfe\",\"pfl\",\"pga\",\"pgd\",\"pgg\",\"pgi\",\"pgk\",\"pgl\",\"pgn\",\"pgs\",\"pgu\",\"pgy\",\"pgz\",\"pha\",\"phd\",\"phg\",\"phh\",\"phi\",\"phk\",\"phl\",\"phm\",\"phn\",\"pho\",\"phq\",\"phr\",\"pht\",\"phu\",\"phv\",\"phw\",\"pia\",\"pib\",\"pic\",\"pid\",\"pie\",\"pif\",\"pig\",\"pih\",\"pii\",\"pij\",\"pil\",\"pim\",\"pin\",\"pio\",\"pip\",\"pir\",\"pis\",\"pit\",\"piu\",\"piv\",\"piw\",\"pix\",\"piy\",\"piz\",\"pjt\",\"pka\",\"pkb\",\"pkc\",\"pkg\",\"pkh\",\"pkn\",\"pko\",\"pkp\",\"pkr\",\"pks\",\"pkt\",\"pku\",\"pla\",\"plb\",\"plc\",\"pld\",\"ple\",\"plf\",\"plg\",\"plh\",\"plj\",\"plk\",\"pll\",\"pln\",\"plo\",\"plp\",\"plq\",\"plr\",\"pls\",\"plt\",\"plu\",\"plv\",\"plw\",\"ply\",\"plz\",\"pma\",\"pmb\",\"pmc\",\"pmd\",\"pme\",\"pmf\",\"pmh\",\"pmi\",\"pmj\",\"pmk\",\"pml\",\"pmm\",\"pmn\",\"pmo\",\"pmq\",\"pmr\",\"pms\",\"pmt\",\"pmu\",\"pmw\",\"pmx\",\"pmy\",\"pmz\",\"pna\",\"pnb\",\"pnc\",\"pne\",\"png\",\"pnh\",\"pni\",\"pnj\",\"pnk\",\"pnl\",\"pnm\",\"pnn\",\"pno\",\"pnp\",\"pnq\",\"pnr\",\"pns\",\"pnt\",\"pnu\",\"pnv\",\"pnw\",\"pnx\",\"pny\",\"pnz\",\"poc\",\"pod\",\"poe\",\"pof\",\"pog\",\"poh\",\"poi\",\"pok\",\"pom\",\"pon\",\"poo\",\"pop\",\"poq\",\"pos\",\"pot\",\"pov\",\"pow\",\"pox\",\"poy\",\"poz\",\"ppa\",\"ppe\",\"ppi\",\"ppk\",\"ppl\",\"ppm\",\"ppn\",\"ppo\",\"ppp\",\"ppq\",\"ppr\",\"pps\",\"ppt\",\"ppu\",\"pqa\",\"pqe\",\"pqm\",\"pqw\",\"pra\",\"prb\",\"prc\",\"prd\",\"pre\",\"prf\",\"prg\",\"prh\",\"pri\",\"prk\",\"prl\",\"prm\",\"prn\",\"pro\",\"prp\",\"prq\",\"prr\",\"prs\",\"prt\",\"pru\",\"prw\",\"prx\",\"pry\",\"prz\",\"psa\",\"psc\",\"psd\",\"pse\",\"psg\",\"psh\",\"psi\",\"psl\",\"psm\",\"psn\",\"pso\",\"psp\",\"psq\",\"psr\",\"pss\",\"pst\",\"psu\",\"psw\",\"psy\",\"pta\",\"pth\",\"pti\",\"ptn\",\"pto\",\"ptp\",\"ptq\",\"ptr\",\"ptt\",\"ptu\",\"ptv\",\"ptw\",\"pty\",\"pua\",\"pub\",\"puc\",\"pud\",\"pue\",\"puf\",\"pug\",\"pui\",\"puj\",\"puk\",\"pum\",\"puo\",\"pup\",\"puq\",\"pur\",\"put\",\"puu\",\"puw\",\"pux\",\"puy\",\"puz\",\"pwa\",\"pwb\",\"pwg\",\"pwi\",\"pwm\",\"pwn\",\"pwo\",\"pwr\",\"pww\",\"pxm\",\"pye\",\"pym\",\"pyn\",\"pys\",\"pyu\",\"pyx\",\"pyy\",\"pzn\",\"qaa..qtz\",\"qua\",\"qub\",\"quc\",\"qud\",\"quf\",\"qug\",\"quh\",\"qui\",\"quk\",\"qul\",\"qum\",\"qun\",\"qup\",\"quq\",\"qur\",\"qus\",\"quv\",\"quw\",\"qux\",\"quy\",\"quz\",\"qva\",\"qvc\",\"qve\",\"qvh\",\"qvi\",\"qvj\",\"qvl\",\"qvm\",\"qvn\",\"qvo\",\"qvp\",\"qvs\",\"qvw\",\"qvy\",\"qvz\",\"qwa\",\"qwc\",\"qwe\",\"qwh\",\"qwm\",\"qws\",\"qwt\",\"qxa\",\"qxc\",\"qxh\",\"qxl\",\"qxn\",\"qxo\",\"qxp\",\"qxq\",\"qxr\",\"qxs\",\"qxt\",\"qxu\",\"qxw\",\"qya\",\"qyp\",\"raa\",\"rab\",\"rac\",\"rad\",\"raf\",\"rag\",\"rah\",\"rai\",\"raj\",\"rak\",\"ral\",\"ram\",\"ran\",\"rao\",\"rap\",\"raq\",\"rar\",\"ras\",\"rat\",\"rau\",\"rav\",\"raw\",\"rax\",\"ray\",\"raz\",\"rbb\",\"rbk\",\"rbl\",\"rbp\",\"rcf\",\"rdb\",\"rea\",\"reb\",\"ree\",\"reg\",\"rei\",\"rej\",\"rel\",\"rem\",\"ren\",\"rer\",\"res\",\"ret\",\"rey\",\"rga\",\"rge\",\"rgk\",\"rgn\",\"rgr\",\"rgs\",\"rgu\",\"rhg\",\"rhp\",\"ria\",\"rie\",\"rif\",\"ril\",\"rim\",\"rin\",\"rir\",\"rit\",\"riu\",\"rjg\",\"rji\",\"rjs\",\"rka\",\"rkb\",\"rkh\",\"rki\",\"rkm\",\"rkt\",\"rkw\",\"rma\",\"rmb\",\"rmc\",\"rmd\",\"rme\",\"rmf\",\"rmg\",\"rmh\",\"rmi\",\"rmk\",\"rml\",\"rmm\",\"rmn\",\"rmo\",\"rmp\",\"rmq\",\"rmr\",\"rms\",\"rmt\",\"rmu\",\"rmv\",\"rmw\",\"rmx\",\"rmy\",\"rmz\",\"rna\",\"rnd\",\"rng\",\"rnl\",\"rnn\",\"rnp\",\"rnr\",\"rnw\",\"roa\",\"rob\",\"roc\",\"rod\",\"roe\",\"rof\",\"rog\",\"rol\",\"rom\",\"roo\",\"rop\",\"ror\",\"rou\",\"row\",\"rpn\",\"rpt\",\"rri\",\"rro\",\"rrt\",\"rsb\",\"rsi\",\"rsl\",\"rsm\",\"rtc\",\"rth\",\"rtm\",\"rts\",\"rtw\",\"rub\",\"ruc\",\"rue\",\"ruf\",\"rug\",\"ruh\",\"rui\",\"ruk\",\"ruo\",\"rup\",\"ruq\",\"rut\",\"ruu\",\"ruy\",\"ruz\",\"rwa\",\"rwk\",\"rwm\",\"rwo\",\"rwr\",\"rxd\",\"rxw\",\"ryn\",\"rys\",\"ryu\",\"rzh\",\"saa\",\"sab\",\"sac\",\"sad\",\"sae\",\"saf\",\"sah\",\"sai\",\"saj\",\"sak\",\"sal\",\"sam\",\"sao\",\"sap\",\"saq\",\"sar\",\"sas\",\"sat\",\"sau\",\"sav\",\"saw\",\"sax\",\"say\",\"saz\",\"sba\",\"sbb\",\"sbc\",\"sbd\",\"sbe\",\"sbf\",\"sbg\",\"sbh\",\"sbi\",\"sbj\",\"sbk\",\"sbl\",\"sbm\",\"sbn\",\"sbo\",\"sbp\",\"sbq\",\"sbr\",\"sbs\",\"sbt\",\"sbu\",\"sbv\",\"sbw\",\"sbx\",\"sby\",\"sbz\",\"sca\",\"scb\",\"sce\",\"scf\",\"scg\",\"sch\",\"sci\",\"sck\",\"scl\",\"scn\",\"sco\",\"scp\",\"scq\",\"scs\",\"sct\",\"scu\",\"scv\",\"scw\",\"scx\",\"sda\",\"sdb\",\"sdc\",\"sde\",\"sdf\",\"sdg\",\"sdh\",\"sdj\",\"sdk\",\"sdl\",\"sdm\",\"sdn\",\"sdo\",\"sdp\",\"sdr\",\"sds\",\"sdt\",\"sdu\",\"sdv\",\"sdx\",\"sdz\",\"sea\",\"seb\",\"sec\",\"sed\",\"see\",\"sef\",\"seg\",\"seh\",\"sei\",\"sej\",\"sek\",\"sel\",\"sem\",\"sen\",\"seo\",\"sep\",\"seq\",\"ser\",\"ses\",\"set\",\"seu\",\"sev\",\"sew\",\"sey\",\"sez\",\"sfb\",\"sfe\",\"sfm\",\"sfs\",\"sfw\",\"sga\",\"sgb\",\"sgc\",\"sgd\",\"sge\",\"sgg\",\"sgh\",\"sgi\",\"sgj\",\"sgk\",\"sgl\",\"sgm\",\"sgn\",\"sgo\",\"sgp\",\"sgr\",\"sgs\",\"sgt\",\"sgu\",\"sgw\",\"sgx\",\"sgy\",\"sgz\",\"sha\",\"shb\",\"shc\",\"shd\",\"she\",\"shg\",\"shh\",\"shi\",\"shj\",\"shk\",\"shl\",\"shm\",\"shn\",\"sho\",\"shp\",\"shq\",\"shr\",\"shs\",\"sht\",\"shu\",\"shv\",\"shw\",\"shx\",\"shy\",\"shz\",\"sia\",\"sib\",\"sid\",\"sie\",\"sif\",\"sig\",\"sih\",\"sii\",\"sij\",\"sik\",\"sil\",\"sim\",\"sio\",\"sip\",\"siq\",\"sir\",\"sis\",\"sit\",\"siu\",\"siv\",\"siw\",\"six\",\"siy\",\"siz\",\"sja\",\"sjb\",\"sjd\",\"sje\",\"sjg\",\"sjk\",\"sjl\",\"sjm\",\"sjn\",\"sjo\",\"sjp\",\"sjr\",\"sjs\",\"sjt\",\"sju\",\"sjw\",\"ska\",\"skb\",\"skc\",\"skd\",\"ske\",\"skf\",\"skg\",\"skh\",\"ski\",\"skj\",\"skk\",\"skm\",\"skn\",\"sko\",\"skp\",\"skq\",\"skr\",\"sks\",\"skt\",\"sku\",\"skv\",\"skw\",\"skx\",\"sky\",\"skz\",\"sla\",\"slc\",\"sld\",\"sle\",\"slf\",\"slg\",\"slh\",\"sli\",\"slj\",\"sll\",\"slm\",\"sln\",\"slp\",\"slq\",\"slr\",\"sls\",\"slt\",\"slu\",\"slw\",\"slx\",\"sly\",\"slz\",\"sma\",\"smb\",\"smc\",\"smd\",\"smf\",\"smg\",\"smh\",\"smi\",\"smj\",\"smk\",\"sml\",\"smm\",\"smn\",\"smp\",\"smq\",\"smr\",\"sms\",\"smt\",\"smu\",\"smv\",\"smw\",\"smx\",\"smy\",\"smz\",\"snb\",\"snc\",\"sne\",\"snf\",\"sng\",\"snh\",\"sni\",\"snj\",\"snk\",\"snl\",\"snm\",\"snn\",\"sno\",\"snp\",\"snq\",\"snr\",\"sns\",\"snu\",\"snv\",\"snw\",\"snx\",\"sny\",\"snz\",\"soa\",\"sob\",\"soc\",\"sod\",\"soe\",\"sog\",\"soh\",\"soi\",\"soj\",\"sok\",\"sol\",\"son\",\"soo\",\"sop\",\"soq\",\"sor\",\"sos\",\"sou\",\"sov\",\"sow\",\"sox\",\"soy\",\"soz\",\"spb\",\"spc\",\"spd\",\"spe\",\"spg\",\"spi\",\"spk\",\"spl\",\"spm\",\"spn\",\"spo\",\"spp\",\"spq\",\"spr\",\"sps\",\"spt\",\"spu\",\"spv\",\"spx\",\"spy\",\"sqa\",\"sqh\",\"sqj\",\"sqk\",\"sqm\",\"sqn\",\"sqo\",\"sqq\",\"sqr\",\"sqs\",\"sqt\",\"squ\",\"sra\",\"srb\",\"src\",\"sre\",\"srf\",\"srg\",\"srh\",\"sri\",\"srk\",\"srl\",\"srm\",\"srn\",\"sro\",\"srq\",\"srr\",\"srs\",\"srt\",\"sru\",\"srv\",\"srw\",\"srx\",\"sry\",\"srz\",\"ssa\",\"ssb\",\"ssc\",\"ssd\",\"sse\",\"ssf\",\"ssg\",\"ssh\",\"ssi\",\"ssj\",\"ssk\",\"ssl\",\"ssm\",\"ssn\",\"sso\",\"ssp\",\"ssq\",\"ssr\",\"sss\",\"sst\",\"ssu\",\"ssv\",\"ssx\",\"ssy\",\"ssz\",\"sta\",\"stb\",\"std\",\"ste\",\"stf\",\"stg\",\"sth\",\"sti\",\"stj\",\"stk\",\"stl\",\"stm\",\"stn\",\"sto\",\"stp\",\"stq\",\"str\",\"sts\",\"stt\",\"stu\",\"stv\",\"stw\",\"sty\",\"sua\",\"sub\",\"suc\",\"sue\",\"sug\",\"sui\",\"suj\",\"suk\",\"sul\",\"sum\",\"suq\",\"sur\",\"sus\",\"sut\",\"suv\",\"suw\",\"sux\",\"suy\",\"suz\",\"sva\",\"svb\",\"svc\",\"sve\",\"svk\",\"svm\",\"svr\",\"svs\",\"svx\",\"swb\",\"swc\",\"swf\",\"swg\",\"swh\",\"swi\",\"swj\",\"swk\",\"swl\",\"swm\",\"swn\",\"swo\",\"swp\",\"swq\",\"swr\",\"sws\",\"swt\",\"swu\",\"swv\",\"sww\",\"swx\",\"swy\",\"sxb\",\"sxc\",\"sxe\",\"sxg\",\"sxk\",\"sxl\",\"sxm\",\"sxn\",\"sxo\",\"sxr\",\"sxs\",\"sxu\",\"sxw\",\"sya\",\"syb\",\"syc\",\"syd\",\"syi\",\"syk\",\"syl\",\"sym\",\"syn\",\"syo\",\"syr\",\"sys\",\"syw\",\"syx\",\"syy\",\"sza\",\"szb\",\"szc\",\"szd\",\"sze\",\"szg\",\"szl\",\"szn\",\"szp\",\"szs\",\"szv\",\"szw\",\"taa\",\"tab\",\"tac\",\"tad\",\"tae\",\"taf\",\"tag\",\"tai\",\"taj\",\"tak\",\"tal\",\"tan\",\"tao\",\"tap\",\"taq\",\"tar\",\"tas\",\"tau\",\"tav\",\"taw\",\"tax\",\"tay\",\"taz\",\"tba\",\"tbb\",\"tbc\",\"tbd\",\"tbe\",\"tbf\",\"tbg\",\"tbh\",\"tbi\",\"tbj\",\"tbk\",\"tbl\",\"tbm\",\"tbn\",\"tbo\",\"tbp\",\"tbq\",\"tbr\",\"tbs\",\"tbt\",\"tbu\",\"tbv\",\"tbw\",\"tbx\",\"tby\",\"tbz\",\"tca\",\"tcb\",\"tcc\",\"tcd\",\"tce\",\"tcf\",\"tcg\",\"tch\",\"tci\",\"tck\",\"tcl\",\"tcm\",\"tcn\",\"tco\",\"tcp\",\"tcq\",\"tcs\",\"tct\",\"tcu\",\"tcw\",\"tcx\",\"tcy\",\"tcz\",\"tda\",\"tdb\",\"tdc\",\"tdd\",\"tde\",\"tdf\",\"tdg\",\"tdh\",\"tdi\",\"tdj\",\"tdk\",\"tdl\",\"tdm\",\"tdn\",\"tdo\",\"tdq\",\"tdr\",\"tds\",\"tdt\",\"tdu\",\"tdv\",\"tdx\",\"tdy\",\"tea\",\"teb\",\"tec\",\"ted\",\"tee\",\"tef\",\"teg\",\"teh\",\"tei\",\"tek\",\"tem\",\"ten\",\"teo\",\"tep\",\"teq\",\"ter\",\"tes\",\"tet\",\"teu\",\"tev\",\"tew\",\"tex\",\"tey\",\"tez\",\"tfi\",\"tfn\",\"tfo\",\"tfr\",\"tft\",\"tga\",\"tgb\",\"tgc\",\"tgd\",\"tge\",\"tgf\",\"tgg\",\"tgh\",\"tgi\",\"tgj\",\"tgn\",\"tgo\",\"tgp\",\"tgq\",\"tgr\",\"tgs\",\"tgt\",\"tgu\",\"tgv\",\"tgw\",\"tgx\",\"tgy\",\"tgz\",\"thc\",\"thd\",\"the\",\"thf\",\"thh\",\"thi\",\"thk\",\"thl\",\"thm\",\"thn\",\"thp\",\"thq\",\"thr\",\"ths\",\"tht\",\"thu\",\"thv\",\"thw\",\"thx\",\"thy\",\"thz\",\"tia\",\"tic\",\"tid\",\"tie\",\"tif\",\"tig\",\"tih\",\"tii\",\"tij\",\"tik\",\"til\",\"tim\",\"tin\",\"tio\",\"tip\",\"tiq\",\"tis\",\"tit\",\"tiu\",\"tiv\",\"tiw\",\"tix\",\"tiy\",\"tiz\",\"tja\",\"tjg\",\"tji\",\"tjl\",\"tjm\",\"tjn\",\"tjo\",\"tjs\",\"tju\",\"tjw\",\"tka\",\"tkb\",\"tkd\",\"tke\",\"tkf\",\"tkg\",\"tkk\",\"tkl\",\"tkm\",\"tkn\",\"tkp\",\"tkq\",\"tkr\",\"tks\",\"tkt\",\"tku\",\"tkv\",\"tkw\",\"tkx\",\"tkz\",\"tla\",\"tlb\",\"tlc\",\"tld\",\"tlf\",\"tlg\",\"tlh\",\"tli\",\"tlj\",\"tlk\",\"tll\",\"tlm\",\"tln\",\"tlo\",\"tlp\",\"tlq\",\"tlr\",\"tls\",\"tlt\",\"tlu\",\"tlv\",\"tlw\",\"tlx\",\"tly\",\"tma\",\"tmb\",\"tmc\",\"tmd\",\"tme\",\"tmf\",\"tmg\",\"tmh\",\"tmi\",\"tmj\",\"tmk\",\"tml\",\"tmm\",\"tmn\",\"tmo\",\"tmp\",\"tmq\",\"tmr\",\"tms\",\"tmt\",\"tmu\",\"tmv\",\"tmw\",\"tmy\",\"tmz\",\"tna\",\"tnb\",\"tnc\",\"tnd\",\"tne\",\"tnf\",\"tng\",\"tnh\",\"tni\",\"tnk\",\"tnl\",\"tnm\",\"tnn\",\"tno\",\"tnp\",\"tnq\",\"tnr\",\"tns\",\"tnt\",\"tnu\",\"tnv\",\"tnw\",\"tnx\",\"tny\",\"tnz\",\"tob\",\"toc\",\"tod\",\"toe\",\"tof\",\"tog\",\"toh\",\"toi\",\"toj\",\"tol\",\"tom\",\"too\",\"top\",\"toq\",\"tor\",\"tos\",\"tou\",\"tov\",\"tow\",\"tox\",\"toy\",\"toz\",\"tpa\",\"tpc\",\"tpe\",\"tpf\",\"tpg\",\"tpi\",\"tpj\",\"tpk\",\"tpl\",\"tpm\",\"tpn\",\"tpo\",\"tpp\",\"tpq\",\"tpr\",\"tpt\",\"tpu\",\"tpv\",\"tpw\",\"tpx\",\"tpy\",\"tpz\",\"tqb\",\"tql\",\"tqm\",\"tqn\",\"tqo\",\"tqp\",\"tqq\",\"tqr\",\"tqt\",\"tqu\",\"tqw\",\"tra\",\"trb\",\"trc\",\"trd\",\"tre\",\"trf\",\"trg\",\"trh\",\"tri\",\"trj\",\"trk\",\"trl\",\"trm\",\"trn\",\"tro\",\"trp\",\"trq\",\"trr\",\"trs\",\"trt\",\"tru\",\"trv\",\"trw\",\"trx\",\"try\",\"trz\",\"tsa\",\"tsb\",\"tsc\",\"tsd\",\"tse\",\"tsf\",\"tsg\",\"tsh\",\"tsi\",\"tsj\",\"tsk\",\"tsl\",\"tsm\",\"tsp\",\"tsq\",\"tsr\",\"tss\",\"tst\",\"tsu\",\"tsv\",\"tsw\",\"tsx\",\"tsy\",\"tsz\",\"tta\",\"ttb\",\"ttc\",\"ttd\",\"tte\",\"ttf\",\"ttg\",\"tth\",\"tti\",\"ttj\",\"ttk\",\"ttl\",\"ttm\",\"ttn\",\"tto\",\"ttp\",\"ttq\",\"ttr\",\"tts\",\"ttt\",\"ttu\",\"ttv\",\"ttw\",\"tty\",\"ttz\",\"tua\",\"tub\",\"tuc\",\"tud\",\"tue\",\"tuf\",\"tug\",\"tuh\",\"tui\",\"tuj\",\"tul\",\"tum\",\"tun\",\"tuo\",\"tup\",\"tuq\",\"tus\",\"tut\",\"tuu\",\"tuv\",\"tuw\",\"tux\",\"tuy\",\"tuz\",\"tva\",\"tvd\",\"tve\",\"tvk\",\"tvl\",\"tvm\",\"tvn\",\"tvo\",\"tvs\",\"tvt\",\"tvu\",\"tvw\",\"tvy\",\"twa\",\"twb\",\"twc\",\"twd\",\"twe\",\"twf\",\"twg\",\"twh\",\"twl\",\"twm\",\"twn\",\"two\",\"twp\",\"twq\",\"twr\",\"twt\",\"twu\",\"tww\",\"twx\",\"twy\",\"txa\",\"txb\",\"txc\",\"txe\",\"txg\",\"txh\",\"txi\",\"txj\",\"txm\",\"txn\",\"txo\",\"txq\",\"txr\",\"txs\",\"txt\",\"txu\",\"txx\",\"txy\",\"tya\",\"tye\",\"tyh\",\"tyi\",\"tyj\",\"tyl\",\"tyn\",\"typ\",\"tyr\",\"tys\",\"tyt\",\"tyu\",\"tyv\",\"tyx\",\"tyz\",\"tza\",\"tzh\",\"tzj\",\"tzl\",\"tzm\",\"tzn\",\"tzo\",\"tzx\",\"uam\",\"uan\",\"uar\",\"uba\",\"ubi\",\"ubl\",\"ubr\",\"ubu\",\"uby\",\"uda\",\"ude\",\"udg\",\"udi\",\"udj\",\"udl\",\"udm\",\"udu\",\"ues\",\"ufi\",\"uga\",\"ugb\",\"uge\",\"ugn\",\"ugo\",\"ugy\",\"uha\",\"uhn\",\"uis\",\"uiv\",\"uji\",\"uka\",\"ukg\",\"ukh\",\"ukk\",\"ukl\",\"ukp\",\"ukq\",\"uks\",\"uku\",\"ukw\",\"uky\",\"ula\",\"ulb\",\"ulc\",\"ule\",\"ulf\",\"uli\",\"ulk\",\"ull\",\"ulm\",\"uln\",\"ulu\",\"ulw\",\"uma\",\"umb\",\"umc\",\"umd\",\"umg\",\"umi\",\"umm\",\"umn\",\"umo\",\"ump\",\"umr\",\"ums\",\"umu\",\"una\",\"und\",\"une\",\"ung\",\"unk\",\"unm\",\"unn\",\"unp\",\"unr\",\"unu\",\"unx\",\"unz\",\"uok\",\"upi\",\"upv\",\"ura\",\"urb\",\"urc\",\"ure\",\"urf\",\"urg\",\"urh\",\"uri\",\"urj\",\"urk\",\"url\",\"urm\",\"urn\",\"uro\",\"urp\",\"urr\",\"urt\",\"uru\",\"urv\",\"urw\",\"urx\",\"ury\",\"urz\",\"usa\",\"ush\",\"usi\",\"usk\",\"usp\",\"usu\",\"uta\",\"ute\",\"utp\",\"utr\",\"utu\",\"uum\",\"uun\",\"uur\",\"uuu\",\"uve\",\"uvh\",\"uvl\",\"uwa\",\"uya\",\"uzn\",\"uzs\",\"vaa\",\"vae\",\"vaf\",\"vag\",\"vah\",\"vai\",\"vaj\",\"val\",\"vam\",\"van\",\"vao\",\"vap\",\"var\",\"vas\",\"vau\",\"vav\",\"vay\",\"vbb\",\"vbk\",\"vec\",\"ved\",\"vel\",\"vem\",\"veo\",\"vep\",\"ver\",\"vgr\",\"vgt\",\"vic\",\"vid\",\"vif\",\"vig\",\"vil\",\"vin\",\"vis\",\"vit\",\"viv\",\"vka\",\"vki\",\"vkj\",\"vkk\",\"vkl\",\"vkm\",\"vko\",\"vkp\",\"vkt\",\"vku\",\"vlp\",\"vls\",\"vma\",\"vmb\",\"vmc\",\"vmd\",\"vme\",\"vmf\",\"vmg\",\"vmh\",\"vmi\",\"vmj\",\"vmk\",\"vml\",\"vmm\",\"vmp\",\"vmq\",\"vmr\",\"vms\",\"vmu\",\"vmv\",\"vmw\",\"vmx\",\"vmy\",\"vmz\",\"vnk\",\"vnm\",\"vnp\",\"vor\",\"vot\",\"vra\",\"vro\",\"vrs\",\"vrt\",\"vsi\",\"vsl\",\"vsv\",\"vto\",\"vum\",\"vun\",\"vut\",\"vwa\",\"waa\",\"wab\",\"wac\",\"wad\",\"wae\",\"waf\",\"wag\",\"wah\",\"wai\",\"waj\",\"wak\",\"wal\",\"wam\",\"wan\",\"wao\",\"wap\",\"waq\",\"war\",\"was\",\"wat\",\"wau\",\"wav\",\"waw\",\"wax\",\"way\",\"waz\",\"wba\",\"wbb\",\"wbe\",\"wbf\",\"wbh\",\"wbi\",\"wbj\",\"wbk\",\"wbl\",\"wbm\",\"wbp\",\"wbq\",\"wbr\",\"wbs\",\"wbt\",\"wbv\",\"wbw\",\"wca\",\"wci\",\"wdd\",\"wdg\",\"wdj\",\"wdk\",\"wdu\",\"wdy\",\"wea\",\"wec\",\"wed\",\"weg\",\"weh\",\"wei\",\"wem\",\"wen\",\"weo\",\"wep\",\"wer\",\"wes\",\"wet\",\"weu\",\"wew\",\"wfg\",\"wga\",\"wgb\",\"wgg\",\"wgi\",\"wgo\",\"wgu\",\"wgw\",\"wgy\",\"wha\",\"whg\",\"whk\",\"whu\",\"wib\",\"wic\",\"wie\",\"wif\",\"wig\",\"wih\",\"wii\",\"wij\",\"wik\",\"wil\",\"wim\",\"win\",\"wir\",\"wit\",\"wiu\",\"wiv\",\"wiw\",\"wiy\",\"wja\",\"wji\",\"wka\",\"wkb\",\"wkd\",\"wkl\",\"wku\",\"wkw\",\"wky\",\"wla\",\"wlc\",\"wle\",\"wlg\",\"wli\",\"wlk\",\"wll\",\"wlm\",\"wlo\",\"wlr\",\"wls\",\"wlu\",\"wlv\",\"wlw\",\"wlx\",\"wly\",\"wma\",\"wmb\",\"wmc\",\"wmd\",\"wme\",\"wmh\",\"wmi\",\"wmm\",\"wmn\",\"wmo\",\"wms\",\"wmt\",\"wmw\",\"wmx\",\"wnb\",\"wnc\",\"wnd\",\"wne\",\"wng\",\"wni\",\"wnk\",\"wnm\",\"wnn\",\"wno\",\"wnp\",\"wnu\",\"wnw\",\"wny\",\"woa\",\"wob\",\"woc\",\"wod\",\"woe\",\"wof\",\"wog\",\"woi\",\"wok\",\"wom\",\"won\",\"woo\",\"wor\",\"wos\",\"wow\",\"woy\",\"wpc\",\"wra\",\"wrb\",\"wrd\",\"wrg\",\"wrh\",\"wri\",\"wrk\",\"wrl\",\"wrm\",\"wrn\",\"wro\",\"wrp\",\"wrr\",\"wrs\",\"wru\",\"wrv\",\"wrw\",\"wrx\",\"wry\",\"wrz\",\"wsa\",\"wsg\",\"wsi\",\"wsk\",\"wsr\",\"wss\",\"wsu\",\"wsv\",\"wtf\",\"wth\",\"wti\",\"wtk\",\"wtm\",\"wtw\",\"wua\",\"wub\",\"wud\",\"wuh\",\"wul\",\"wum\",\"wun\",\"wur\",\"wut\",\"wuu\",\"wuv\",\"wux\",\"wuy\",\"wwa\",\"wwb\",\"wwo\",\"wwr\",\"www\",\"wxa\",\"wxw\",\"wya\",\"wyb\",\"wyi\",\"wym\",\"wyr\",\"wyy\",\"xaa\",\"xab\",\"xac\",\"xad\",\"xae\",\"xag\",\"xai\",\"xaj\",\"xak\",\"xal\",\"xam\",\"xan\",\"xao\",\"xap\",\"xaq\",\"xar\",\"xas\",\"xat\",\"xau\",\"xav\",\"xaw\",\"xay\",\"xba\",\"xbb\",\"xbc\",\"xbd\",\"xbe\",\"xbg\",\"xbi\",\"xbj\",\"xbm\",\"xbn\",\"xbo\",\"xbp\",\"xbr\",\"xbw\",\"xbx\",\"xby\",\"xcb\",\"xcc\",\"xce\",\"xcg\",\"xch\",\"xcl\",\"xcm\",\"xcn\",\"xco\",\"xcr\",\"xct\",\"xcu\",\"xcv\",\"xcw\",\"xcy\",\"xda\",\"xdc\",\"xdk\",\"xdm\",\"xdo\",\"xdy\",\"xeb\",\"xed\",\"xeg\",\"xel\",\"xem\",\"xep\",\"xer\",\"xes\",\"xet\",\"xeu\",\"xfa\",\"xga\",\"xgb\",\"xgd\",\"xgf\",\"xgg\",\"xgi\",\"xgl\",\"xgm\",\"xgn\",\"xgr\",\"xgu\",\"xgw\",\"xha\",\"xhc\",\"xhd\",\"xhe\",\"xhr\",\"xht\",\"xhu\",\"xhv\",\"xia\",\"xib\",\"xii\",\"xil\",\"xin\",\"xip\",\"xir\",\"xis\",\"xiv\",\"xiy\",\"xjb\",\"xjt\",\"xka\",\"xkb\",\"xkc\",\"xkd\",\"xke\",\"xkf\",\"xkg\",\"xkh\",\"xki\",\"xkj\",\"xkk\",\"xkl\",\"xkn\",\"xko\",\"xkp\",\"xkq\",\"xkr\",\"xks\",\"xkt\",\"xku\",\"xkv\",\"xkw\",\"xkx\",\"xky\",\"xkz\",\"xla\",\"xlb\",\"xlc\",\"xld\",\"xle\",\"xlg\",\"xli\",\"xln\",\"xlo\",\"xlp\",\"xls\",\"xlu\",\"xly\",\"xma\",\"xmb\",\"xmc\",\"xmd\",\"xme\",\"xmf\",\"xmg\",\"xmh\",\"xmj\",\"xmk\",\"xml\",\"xmm\",\"xmn\",\"xmo\",\"xmp\",\"xmq\",\"xmr\",\"xms\",\"xmt\",\"xmu\",\"xmv\",\"xmw\",\"xmx\",\"xmy\",\"xmz\",\"xna\",\"xnb\",\"xnd\",\"xng\",\"xnh\",\"xni\",\"xnk\",\"xnn\",\"xno\",\"xnr\",\"xns\",\"xnt\",\"xnu\",\"xny\",\"xnz\",\"xoc\",\"xod\",\"xog\",\"xoi\",\"xok\",\"xom\",\"xon\",\"xoo\",\"xop\",\"xor\",\"xow\",\"xpa\",\"xpc\",\"xpe\",\"xpg\",\"xpi\",\"xpj\",\"xpk\",\"xpm\",\"xpn\",\"xpo\",\"xpp\",\"xpq\",\"xpr\",\"xps\",\"xpt\",\"xpu\",\"xpy\",\"xqa\",\"xqt\",\"xra\",\"xrb\",\"xrd\",\"xre\",\"xrg\",\"xri\",\"xrm\",\"xrn\",\"xrq\",\"xrr\",\"xrt\",\"xru\",\"xrw\",\"xsa\",\"xsb\",\"xsc\",\"xsd\",\"xse\",\"xsh\",\"xsi\",\"xsj\",\"xsl\",\"xsm\",\"xsn\",\"xso\",\"xsp\",\"xsq\",\"xsr\",\"xss\",\"xsu\",\"xsv\",\"xsy\",\"xta\",\"xtb\",\"xtc\",\"xtd\",\"xte\",\"xtg\",\"xth\",\"xti\",\"xtj\",\"xtl\",\"xtm\",\"xtn\",\"xto\",\"xtp\",\"xtq\",\"xtr\",\"xts\",\"xtt\",\"xtu\",\"xtv\",\"xtw\",\"xty\",\"xtz\",\"xua\",\"xub\",\"xud\",\"xug\",\"xuj\",\"xul\",\"xum\",\"xun\",\"xuo\",\"xup\",\"xur\",\"xut\",\"xuu\",\"xve\",\"xvi\",\"xvn\",\"xvo\",\"xvs\",\"xwa\",\"xwc\",\"xwd\",\"xwe\",\"xwg\",\"xwj\",\"xwk\",\"xwl\",\"xwo\",\"xwr\",\"xwt\",\"xww\",\"xxb\",\"xxk\",\"xxm\",\"xxr\",\"xxt\",\"xya\",\"xyb\",\"xyj\",\"xyk\",\"xyl\",\"xyt\",\"xyy\",\"xzh\",\"xzm\",\"xzp\",\"yaa\",\"yab\",\"yac\",\"yad\",\"yae\",\"yaf\",\"yag\",\"yah\",\"yai\",\"yaj\",\"yak\",\"yal\",\"yam\",\"yan\",\"yao\",\"yap\",\"yaq\",\"yar\",\"yas\",\"yat\",\"yau\",\"yav\",\"yaw\",\"yax\",\"yay\",\"yaz\",\"yba\",\"ybb\",\"ybd\",\"ybe\",\"ybh\",\"ybi\",\"ybj\",\"ybk\",\"ybl\",\"ybm\",\"ybn\",\"ybo\",\"ybx\",\"yby\",\"ych\",\"ycl\",\"ycn\",\"ycp\",\"yda\",\"ydd\",\"yde\",\"ydg\",\"ydk\",\"yds\",\"yea\",\"yec\",\"yee\",\"yei\",\"yej\",\"yel\",\"yen\",\"yer\",\"yes\",\"yet\",\"yeu\",\"yev\",\"yey\",\"yga\",\"ygi\",\"ygl\",\"ygm\",\"ygp\",\"ygr\",\"ygs\",\"ygu\",\"ygw\",\"yha\",\"yhd\",\"yhl\",\"yhs\",\"yia\",\"yif\",\"yig\",\"yih\",\"yii\",\"yij\",\"yik\",\"yil\",\"yim\",\"yin\",\"yip\",\"yiq\",\"yir\",\"yis\",\"yit\",\"yiu\",\"yiv\",\"yix\",\"yiy\",\"yiz\",\"yka\",\"ykg\",\"yki\",\"ykk\",\"ykl\",\"ykm\",\"ykn\",\"yko\",\"ykr\",\"ykt\",\"yku\",\"yky\",\"yla\",\"ylb\",\"yle\",\"ylg\",\"yli\",\"yll\",\"ylm\",\"yln\",\"ylo\",\"ylr\",\"ylu\",\"yly\",\"yma\",\"ymb\",\"ymc\",\"ymd\",\"yme\",\"ymg\",\"ymh\",\"ymi\",\"ymk\",\"yml\",\"ymm\",\"ymn\",\"ymo\",\"ymp\",\"ymq\",\"ymr\",\"yms\",\"ymt\",\"ymx\",\"ymz\",\"yna\",\"ynd\",\"yne\",\"yng\",\"ynh\",\"ynk\",\"ynl\",\"ynn\",\"yno\",\"ynq\",\"yns\",\"ynu\",\"yob\",\"yog\",\"yoi\",\"yok\",\"yol\",\"yom\",\"yon\",\"yos\",\"yot\",\"yox\",\"yoy\",\"ypa\",\"ypb\",\"ypg\",\"yph\",\"ypk\",\"ypm\",\"ypn\",\"ypo\",\"ypp\",\"ypz\",\"yra\",\"yrb\",\"yre\",\"yri\",\"yrk\",\"yrl\",\"yrm\",\"yrn\",\"yro\",\"yrs\",\"yrw\",\"yry\",\"ysc\",\"ysd\",\"ysg\",\"ysl\",\"ysn\",\"yso\",\"ysp\",\"ysr\",\"yss\",\"ysy\",\"yta\",\"ytl\",\"ytp\",\"ytw\",\"yty\",\"yua\",\"yub\",\"yuc\",\"yud\",\"yue\",\"yuf\",\"yug\",\"yui\",\"yuj\",\"yuk\",\"yul\",\"yum\",\"yun\",\"yup\",\"yuq\",\"yur\",\"yut\",\"yuu\",\"yuw\",\"yux\",\"yuy\",\"yuz\",\"yva\",\"yvt\",\"ywa\",\"ywg\",\"ywl\",\"ywn\",\"ywq\",\"ywr\",\"ywt\",\"ywu\",\"yww\",\"yxa\",\"yxg\",\"yxl\",\"yxm\",\"yxu\",\"yxy\",\"yyr\",\"yyu\",\"yyz\",\"yzg\",\"yzk\",\"zaa\",\"zab\",\"zac\",\"zad\",\"zae\",\"zaf\",\"zag\",\"zah\",\"zai\",\"zaj\",\"zak\",\"zal\",\"zam\",\"zao\",\"zap\",\"zaq\",\"zar\",\"zas\",\"zat\",\"zau\",\"zav\",\"zaw\",\"zax\",\"zay\",\"zaz\",\"zbc\",\"zbe\",\"zbl\",\"zbt\",\"zbw\",\"zca\",\"zch\",\"zdj\",\"zea\",\"zeg\",\"zeh\",\"zen\",\"zga\",\"zgb\",\"zgh\",\"zgm\",\"zgn\",\"zgr\",\"zhb\",\"zhd\",\"zhi\",\"zhn\",\"zhw\",\"zhx\",\"zia\",\"zib\",\"zik\",\"zil\",\"zim\",\"zin\",\"zir\",\"ziw\",\"ziz\",\"zka\",\"zkb\",\"zkd\",\"zkg\",\"zkh\",\"zkk\",\"zkn\",\"zko\",\"zkp\",\"zkr\",\"zkt\",\"zku\",\"zkv\",\"zkz\",\"zle\",\"zlj\",\"zlm\",\"zln\",\"zlq\",\"zls\",\"zlw\",\"zma\",\"zmb\",\"zmc\",\"zmd\",\"zme\",\"zmf\",\"zmg\",\"zmh\",\"zmi\",\"zmj\",\"zmk\",\"zml\",\"zmm\",\"zmn\",\"zmo\",\"zmp\",\"zmq\",\"zmr\",\"zms\",\"zmt\",\"zmu\",\"zmv\",\"zmw\",\"zmx\",\"zmy\",\"zmz\",\"zna\",\"znd\",\"zne\",\"zng\",\"znk\",\"zns\",\"zoc\",\"zoh\",\"zom\",\"zoo\",\"zoq\",\"zor\",\"zos\",\"zpa\",\"zpb\",\"zpc\",\"zpd\",\"zpe\",\"zpf\",\"zpg\",\"zph\",\"zpi\",\"zpj\",\"zpk\",\"zpl\",\"zpm\",\"zpn\",\"zpo\",\"zpp\",\"zpq\",\"zpr\",\"zps\",\"zpt\",\"zpu\",\"zpv\",\"zpw\",\"zpx\",\"zpy\",\"zpz\",\"zqe\",\"zra\",\"zrg\",\"zrn\",\"zro\",\"zrp\",\"zrs\",\"zsa\",\"zsk\",\"zsl\",\"zsm\",\"zsr\",\"zsu\",\"zte\",\"ztg\",\"ztl\",\"ztm\",\"ztn\",\"ztp\",\"ztq\",\"zts\",\"ztt\",\"ztu\",\"ztx\",\"zty\",\"zua\",\"zuh\",\"zum\",\"zun\",\"zuy\",\"zwa\",\"zxx\",\"zyb\",\"zyg\",\"zyj\",\"zyn\",\"zyp\",\"zza\",\"zzj\"];return axe.utils.validLangs=function(){\"use strict\";return b},commons}()})}(\"object\"==typeof window?window:this);";
+const pageFunctions=require('../../lib/page-functions');
+
+
+
+
+
+
+
+
+function runA11yChecks(){
+
+return window.axe.run(document,{
+elementRef:true,
+runOnly:{
+type:'tag',
+values:[
+'wcag2a',
+'wcag2aa']},
+
+
+resultTypes:['violations','inapplicable'],
+rules:{
+'tabindex':{enabled:true},
+'table-fake-caption':{enabled:false},
+'td-has-header':{enabled:false},
+'marquee':{enabled:false},
+'area-alt':{enabled:false},
+'blink':{enabled:false},
+'server-side-image-map':{enabled:false}}}).
+
+
+then(axeResult=>{
+
+
+axeResult.violations.forEach(v=>v.nodes.forEach(node=>{
+
+node.path=getNodePath(node.element);
+
+node.snippet=getOuterHTMLSnippet(node.element);
+
+node.element=node.any=node.all=node.none=undefined;
+}));
+
+
+axeResult={violations:axeResult.violations,notApplicable:axeResult.inapplicable};
+return axeResult;
+});
+}
+
+class Accessibility extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+const expression=`(function () {
+ ${pageFunctions.getOuterHTMLSnippetString};
+ ${pageFunctions.getNodePathString};
+ ${axeLibSource};
+ return (${runA11yChecks.toString()}());
+ })()`;
+
+return driver.evaluateAsync(expression,{useIsolation:true}).then(returnedValue=>{
+if(!returnedValue){
+throw new Error('No axe-core results returned');
+}
+if(!Array.isArray(returnedValue.violations)){
+throw new Error('Unable to parse axe results'+returnedValue);
+}
+return returnedValue;
+});
+}}
+
+
+module.exports=Accessibility;
+
+},{"../../lib/page-functions":68,"./gatherer":44}],"../gather/gatherers/cache-contents":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+const Gatherer=require('./gatherer');
+
+
+
+
+
+
+function getCacheContents(){
+
+return caches.keys().
+
+
+then(cacheNames=>Promise.all(cacheNames.map(cacheName=>caches.open(cacheName)))).
+
+then(caches=>{
+
+const requests=[];
+
+
+return Promise.all(caches.map(cache=>{
+return cache.keys().
+then(reqs=>{
+requests.push(...reqs.map(r=>r.url));
+});
+})).then(_=>{
+return requests;
+});
+});
+}
+
+class CacheContents extends Gatherer{
+
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+
+const cacheUrls=await driver.evaluateAsync(`(${getCacheContents.toString()}())`);
+if(!cacheUrls||!Array.isArray(cacheUrls)){
+throw new Error('Unable to retrieve cache contents');
+}
+
+return cacheUrls;
+}}
+
+
+module.exports=CacheContents;
+
+},{"./gatherer":44}],"../gather/gatherers/chrome-console-messages":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+class ChromeConsoleMessages extends Gatherer{
+constructor(){
+super();
+
+this._logEntries=[];
+this._onConsoleEntryAdded=this.onConsoleEntry.bind(this);
+}
+
+
+
+
+onConsoleEntry(entry){
+this._logEntries.push(entry);
+}
+
+
+
+
+async beforePass(passContext){
+const driver=passContext.driver;
+driver.on('Log.entryAdded',this._onConsoleEntryAdded);
+await driver.sendCommand('Log.enable');
+await driver.sendCommand('Log.startViolationsReport',{
+config:[{name:'discouragedAPIUse',threshold:-1}]});
+
+}
+
+
+
+
+
+async afterPass(passContext){
+await passContext.driver.sendCommand('Log.stopViolationsReport');
+await passContext.driver.off('Log.entryAdded',this._onConsoleEntryAdded);
+await passContext.driver.sendCommand('Log.disable');
+return this._logEntries;
+}}
+
+
+module.exports=ChromeConsoleMessages;
+
+},{"./gatherer":44}],"../gather/gatherers/css-usage":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+
+
+
+class CSSUsage extends Gatherer{
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+
+const stylesheets=[];
+
+const onStylesheetAdded=sheet=>stylesheets.push(sheet);
+driver.on('CSS.styleSheetAdded',onStylesheetAdded);
+
+await driver.sendCommand('DOM.enable');
+await driver.sendCommand('CSS.enable');
+await driver.sendCommand('CSS.startRuleUsageTracking');
+await driver.evaluateAsync('getComputedStyle(document.body)');
+driver.off('CSS.styleSheetAdded',onStylesheetAdded);
+
+
+const promises=stylesheets.map(sheet=>{
+const styleSheetId=sheet.header.styleSheetId;
+return driver.sendCommand('CSS.getStyleSheetText',{styleSheetId}).then(content=>{
+return{
+header:sheet.header,
+content:content.text};
+
+});
+});
+const styleSheetInfo=await Promise.all(promises);
+
+const ruleUsageResponse=await driver.sendCommand('CSS.stopRuleUsageTracking');
+await driver.sendCommand('CSS.disable');
+await driver.sendCommand('DOM.disable');
+
+const dedupedStylesheets=new Map(styleSheetInfo.map(sheet=>{
+return[sheet.content,sheet];
+}));
+return{
+rules:ruleUsageResponse.ruleUsage,
+stylesheets:Array.from(dedupedStylesheets.values())};
+
+}}
+
+
+module.exports=CSSUsage;
+
+},{"./gatherer":44}],"../gather/gatherers/dobetterweb/anchors-with-no-rel-noopener":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const pageFunctions=require('../../../lib/page-functions.js');
+
+class AnchorsWithNoRelNoopener extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const expression=`(function() {
+ ${pageFunctions.getOuterHTMLSnippetString};
+ ${pageFunctions.getElementsInDocumentString}; // define function on page
+ const selector = 'a[target="_blank"]:not([rel~="noopener"]):not([rel~="noreferrer"])';
+ const elements = getElementsInDocument(selector);
+ return elements.map(node => ({
+ href: node.href,
+ rel: node.getAttribute('rel'),
+ target: node.getAttribute('target'),
+ outerHTML: getOuterHTMLSnippet(node),
+ }));
+ })()`;
+
+return passContext.driver.evaluateAsync(expression);
+}}
+
+
+module.exports=AnchorsWithNoRelNoopener;
+
+},{"../../../lib/page-functions.js":68,"../gatherer":44}],"../gather/gatherers/dobetterweb/appcache":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+class AppCacheManifest extends Gatherer{
+
+
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+
+return driver.querySelector('html').
+then(node=>node&&node.getAttribute('manifest'));
+}}
+
+
+module.exports=AppCacheManifest;
+
+},{"../gatherer":44}],"../gather/gatherers/dobetterweb/doctype":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+
+
+
+
+
+function getDoctype(){
+
+if(!document.doctype){
+return null;
+}
+
+const{name,publicId,systemId}=document.doctype;
+return{name,publicId,systemId};
+}
+
+class Doctype extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+return driver.evaluateAsync(`(${getDoctype.toString()}())`);
+}}
+
+
+module.exports=Doctype;
+
+},{"../gatherer":44}],"../gather/gatherers/dobetterweb/domstats":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const pageFunctions=require('../../../lib/page-functions');
+
+
+
+
+
+
+
+
+function createSelectorsLabel(element){
+let name=element.localName||'';
+const idAttr=element.getAttribute&&element.getAttribute('id');
+if(idAttr){
+name+=`#${idAttr}`;
+}
+
+
+if(element.classList){
+const className=element.classList.toString();
+if(className){
+name+=`.${className.trim().replace(/\s+/g,'.')}`;
+}
+}else if(ShadowRoot.prototype.isPrototypeOf(element)){
+name+='#shadow-root';
+}
+
+return name;
+}
+
+
+
+
+
+
+function elementPathInDOM(element){
+const visited=new Set();
+const path=[createSelectorsLabel(element)];
+let node=element;
+while(node){
+visited.add(node);
+
+
+
+if(ShadowRoot.prototype.isPrototypeOf(node)){
+const isShadowHost=node.host&&node.localName!=='a';
+node=isShadowHost?node.host:node.parentElement;
+}else{
+const isShadowHost=node.parentNode&&node.parentNode.host&&
+node.parentNode.localName!=='a';
+node=isShadowHost?node.parentNode.host:node.parentElement;
+}
+
+if(visited.has(node)){
+node=null;
+}
+
+if(node){
+path.unshift(createSelectorsLabel(node));
+}
+}
+return path;
+}
+
+
+
+
+
+
+
+
+function getDOMStats(element,deep=true){
+let deepestNode=null;
+let maxDepth=0;
+let maxWidth=0;
+let parentWithMostChildren=null;
+
+
+
+
+
+const _calcDOMWidthAndHeight=function(element,depth=1){
+if(depth>maxDepth){
+deepestNode=element;
+maxDepth=depth;
+}
+if(element.children.length>maxWidth){
+parentWithMostChildren=element;
+maxWidth=element.children.length;
+}
+
+let child=element.firstElementChild;
+while(child){
+_calcDOMWidthAndHeight(child,depth+1);
+
+if(deep&&child.shadowRoot){
+_calcDOMWidthAndHeight(child.shadowRoot,depth+1);
+}
+child=child.nextElementSibling;
+}
+
+return{maxDepth,maxWidth};
+};
+
+const result=_calcDOMWidthAndHeight(element);
+
+return{
+depth:{
+max:result.maxDepth,
+pathToElement:elementPathInDOM(deepestNode),
+
+snippet:getOuterHTMLSnippet(deepestNode,['style'])},
+
+width:{
+max:result.maxWidth,
+pathToElement:elementPathInDOM(parentWithMostChildren),
+snippet:getOuterHTMLSnippet(parentWithMostChildren,['style'])}};
+
+
+}
+
+class DOMStats extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const expression=`(function() {
+ ${pageFunctions.getOuterHTMLSnippetString};
+ ${createSelectorsLabel.toString()};
+ ${elementPathInDOM.toString()};
+ return (${getDOMStats.toString()}(document.documentElement));
+ })()`;
+return passContext.driver.sendCommand('DOM.enable').
+then(()=>passContext.driver.evaluateAsync(expression,{useIsolation:true})).
+then(results=>passContext.driver.getElementsInDocument().then(allNodes=>{
+results.totalDOMNodes=allNodes.length;
+return passContext.driver.sendCommand('DOM.disable').then(()=>results);
+}));
+}}
+
+
+module.exports=DOMStats;
+
+},{"../../../lib/page-functions":68,"../gatherer":44}],"../gather/gatherers/dobetterweb/js-libraries":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+const libDetectorSource="var UNKNOWN_VERSION = null;\nvar d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests = {\n\n 'GWT': {\n icon: 'gwt',\n url: 'http://www.gwtproject.org/',\n test: function(win) {\n // pretty complicated, many possible tell tales\n var doc = win.document,\n hasHistFrame = doc.getElementById('__gwt_historyFrame'),\n hasGwtUid = doc.gwt_uid,\n hasBodyListener = doc.body.__listener,\n hasBodyEventBits = doc.body.__eventBits,\n hasModules = win.__gwt_activeModules,\n hasJsonP = win.__gwt_jsonp__,\n hasRootWinApp = win.__gwt_scriptsLoaded || win.__gwt_stylesLoaded || win.__gwt_activeModules;\n\n // use the many possible indicators\n if(hasHistFrame || hasGwtUid || hasBodyListener || hasBodyEventBits || hasModules || hasJsonP || hasRootWinApp) {\n\n // carefully look at frames, but only if certain is GWT frame\n var frames = doc.getElementsByTagName('iframe'),\n gwtVersion = UNKNOWN_VERSION;\n for(var n=0; n<frames.length; n++) {\n // catch security access errors\n try {\n var hasNegativeTabIndex = frames[n].tabIndex < 0; // on for GWT\n if(hasNegativeTabIndex && frames[n].contentWindow && frames[n].contentWindow.$gwt_version) {\n gwtVersion = frames[n].contentWindow.$gwt_version;\n break;\n }\n }\n catch(e) {}\n }\n\n if(gwtVersion=='0.0.999') {\n gwtVersion = 'Google Internal';\n }\n\n return { version: gwtVersion };\n }\n return false;\n }\n },\n\n 'Ink': {\n icon: 'ink',\n url: 'http://ink.sapo.pt/',\n test: function(win) {\n if (win.Ink && win.Ink.createModule) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Vaadin': {\n icon: 'vaadin',\n url: 'https://vaadin.com/',\n test: function(win) {\n if (win.vaadin && win.vaadin.registerWidgetset) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Bootstrap': {\n icon: 'bootstrap',\n url: 'http://getbootstrap.com/',\n npm: 'bootstrap',\n // look for a function Boostrap has added to jQuery - regex for BS 2 & 3\n test: function(win) {\n var jQueryAvailable = win.$ && win.$.fn,\n RE_PREFIX_V2 = '\\\\$this\\\\.data\\\\((?:\\'|\")',\n RE_PREFIX_V3 = '\\\\$this\\\\.data\\\\((?:\\'|\")(?:bs\\\\.){1}',\n bootstrapComponents = [\n 'affix', 'alert', 'button', 'carousel', 'collapse', 'dropdown',\n 'modal', 'popover', 'scrollspy', 'tab', 'tooltip'\n ];\n\n if(jQueryAvailable) {\n var bootstrapVersion;\n\n bootstrapComponents.some(function(component) {\n if(win.$.fn[component]) {\n // Bootstrap >= 3.2.0 detection\n if(win.$.fn[component].Constructor && win.$.fn[component].Constructor.VERSION) {\n bootstrapVersion = win.$.fn[component].Constructor.VERSION;\n return true;\n // Bootstrap >= 2.0.0 and <= 3.1.0 detection\n } else if(new RegExp(RE_PREFIX_V3 + component).test(win.$.fn[component].toString())) {\n bootstrapVersion = '>= 3.0.0 & <= 3.1.1';\n return true;\n // Bootstrap < 3.1.0 detection\n } else if(new RegExp(RE_PREFIX_V2 + component).test(win.$.fn[component].toString())) {\n bootstrapVersion = '>= 2.0.0 & <= 2.3.2';\n return true;\n }\n }\n\n return false;\n });\n\n if (bootstrapVersion) {\n return { version: bootstrapVersion };\n }\n }\n\n return false;\n }\n },\n\n 'Zurb': {\n icon: 'zurb',\n url: 'https://foundation.zurb.com/',\n npm: 'foundation-sites',\n test: function(win) {\n if(win.Foundation && win.Foundation.Toggler) {\n return { version: win.Foundation.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Polymer': {\n icon: 'polymer',\n url: 'https://www.polymer-project.org/',\n npm: '@polymer/polymer',\n test: function(win) {\n if(win.Polymer && win.Polymer.dom) {\n return { version: win.Polymer.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Highcharts': {\n icon: 'highcharts',\n url: 'http://www.highcharts.com',\n npm: 'highcharts',\n test: function(win) {\n if(win.Highcharts && win.Highcharts.Point) {\n return { version: win.Highcharts.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'InfoVis': {\n icon: 'jit',\n url: 'http://philogb.github.com/jit/',\n test: function test(win) {\n if(win.$jit && win.$jit.PieChart) {\n return { version: win.$jit.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'FlotCharts': {\n icon: 'flotcharts',\n url: 'http://www.flotcharts.org/',\n npm: 'flot',\n test: function(win) {\n if(win.$ && win.$.plot) {\n return { version: win.$.plot.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'CreateJS': {\n icon: 'createjs',\n url: 'https://createjs.com/',\n npm: 'createjs',\n test: function(win) {\n if(win.createjs && win.createjs.promote) {\n return { version: UNKNOWN_VERSION}; // no version info available\n }\n return false;\n }\n },\n\n 'Google Maps': {\n icon: 'gmaps',\n url: 'https://developers.google.com/maps/',\n test: function(win) {\n if (win.google && win.google.maps) {\n return { version: win.google.maps.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'jQuery': {\n icon: 'jquery',\n url: 'http://jquery.com',\n npm: 'jquery',\n test: function(win) {\n var jq = win.jQuery || win.$;\n if (jq && jq.fn) {\n return { version: jq.fn.jquery.replace(/[^\\d+\\.+]/g, '') || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'jQuery UI': {\n icon: 'jquery_ui',\n url: 'http://jqueryui.com',\n npm: 'jquery-ui',\n test: function(win) {\n var jq = win.jQuery || win.$ || win.$jq || win.$j;\n if(jq && jq.fn && jq.fn.jquery && jq.ui) {\n var plugins = 'accordion,datepicker,dialog,draggable,droppable,progressbar,resizable,selectable,slider,menu,grid,tabs'.split(','), concat = [];\n for (var i=0; i < plugins.length; i++) { if(jq.ui[plugins[i]]) concat.push(plugins[i].substr(0,1).toUpperCase() + plugins[i].substr(1)); }\n return { version: jq.ui.version || UNKNOWN_VERSION, details: concat.length ? 'Plugins used: '+concat.join(',') : '' };\n }\n return false;\n }\n },\n\n 'Dojo': {\n icon: 'dojo',\n url: 'http://dojotoolkit.org',\n npm: 'dojo',\n test: function(win) {\n if(win.dojo && win.dojo.delegate) {\n var version = win.dojo.version ? win.dojo.version.toString() : UNKNOWN_VERSION;\n return { version: version, details: 'Details: '+(win.dijit ? 'Uses Dijit' : 'none') };\n }\n return false;\n }\n },\n\n 'Prototype': {\n icon: 'prototype',\n url: 'http://prototypejs.org',\n test: function(win) {\n if(win.Prototype && win.Prototype.BrowserFeatures) {\n return { version: win.Prototype.Version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Scriptaculous': {\n icon: 'scriptaculous',\n url: 'http://script.aculo.us',\n test: function(win) {\n if(win.Scriptaculous && win.Scriptaculous.load) {\n return { version: win.Scriptaculous.Version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'MooTools': {\n icon: 'mootools',\n url: 'https://mootools.net/',\n test: function(win) {\n if(win.MooTools && win.MooTools.build) {\n return { version: win.MooTools.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Spry': {\n icon: 'spry',\n url: 'http://labs.adobe.com/technologies/spry',\n test: function(win) {\n if (win.Spry && win.Spry.Data) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'YUI 2': {\n icon: 'yui',\n url: 'http://developer.yahoo.com/yui/2/',\n test: function(win) {\n if (win.YAHOO && win.YAHOO.util) {\n return { version: win.YAHOO.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'YUI 3': {\n icon: 'yui3',\n url: 'https://yuilibrary.com/',\n npm: 'yui',\n test: function(win) {\n if (win.YUI && win.YUI.Env) {\n return { version: win.YUI.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Qooxdoo': {\n icon: 'qooxdoo',\n url: 'http://www.qooxdoo.org/',\n npm: 'qooxdoo',\n test: function(win) {\n if(win.qx && win.qx.Bootstrap) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Ext JS': {\n icon: 'extjs',\n url: 'https://www.sencha.com/products/extjs/',\n test: function(win) {\n if (win.Ext && win.Ext.versions) {\n return { version: win.Ext.versions.core.version };\n }\n else if(win.Ext) {\n return { version: win.Ext.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'base2': {\n icon: 'base2',\n url: 'http://code.google.com/p/base2',\n test: function(win) {\n if(win.base2 && win.base2.dom) {\n return { version: win.base2.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Closure Library': {\n icon: 'closure',\n url: 'https://developers.google.com/closure/library/',\n npm: 'google-closure-library',\n test: function(win) {\n if(win.goog && win.goog.provide) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Rapha&euml;l': {\n icon: 'raphael',\n url: 'http://dmitrybaranovskiy.github.io/raphael/',\n test: function(win) {\n if (win.Raphael && win.Raphael.circle) {\n return { version: win.Raphael.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'React': {\n icon: 'react',\n url: 'https://reactjs.org/',\n npm: 'react',\n test: function(win) {\n function isReactNode(node) {\n return node._reactRootContainer!=null;\n }\n var reactRoot = document.getElementById('react-root');\n var altHasReact = document.querySelector('*[data-reactroot]');\n var bodyReactRoot = isReactNode(document.body) || isReactNode(document.body.firstElementChild || {});\n var hasReactRoot = bodyReactRoot|| document.createTreeWalker(document.body, 3, isReactNode).nextNode() != null;\n if (hasReactRoot || reactRoot && reactRoot.innerText.length > 0 || altHasReact || win.React && win.React.Component) {\n return { version: win.React && win.React.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Preact': {\n icon: 'preact',\n url: 'https://preactjs.com/',\n npm: 'preact',\n test: function(win) {\n var expando = typeof Symbol!='undefined' && Symbol.for && Symbol.for('preactattr');\n function isPreactNode(node) {\n if (node._component!=null || node.__preactattr_!=null || expando && node[expando]!=null) {\n return node;\n }\n return null;\n }\n var preactRoot = isPreactNode(document.body) || isPreactNode(document.body.firstElementChild || {});\n if (!preactRoot) {\n preactRoot = document.createTreeWalker(document.body, 3, isPreactNode).nextNode();\n }\n if (preactRoot || win.preact) {\n var version = UNKNOWN_VERSION;\n if (expando && preactRoot && preactRoot[expando]!=null) {\n version = '7';\n }\n return { version: version };\n }\n return false;\n }\n },\n\n 'Modernizr': {\n icon: 'modernizr',\n url: 'https://modernizr.com/',\n npm: 'modernizr',\n test: function(win) {\n if (win.Modernizr && win.Modernizr.addTest) {\n return { version: win.Modernizr._version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Processing.js': {\n icon: 'processingjs',\n url: 'http://processingjs.org',\n npm: 'processing-js',\n test: function(win) {\n if(win.Processing && win.Processing.box) {\n return { version: Processing.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Backbone': {\n icon: 'backbone',\n url: 'http://backbonejs.org/',\n npm: 'backbone',\n test: function(win) {\n if (win.Backbone && win.Backbone.Model.extend) {\n return {version: win.Backbone.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Leaflet': {\n icon: 'leaflet',\n url: 'http://leafletjs.com',\n npm: 'leaflet',\n test: function(win) {\n // Leaflet 3.1 uses L.Marker and L.VERSION; later versions use L.marker and L.version\n if (win.L && win.L.GeoJSON && (win.L.marker || win.L.Marker)) {\n return { version: win.L.version || win.L.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Mapbox': {\n icon: 'mapbox',\n url: 'https://www.mapbox.com/',\n npm: 'mapbox-gl',\n test: function(win) {\n if (win.L && win.L.mapbox && win.L.mapbox.geocoder) {\n return { version: win.L.mapbox.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Lo-Dash': {\n icon: 'lodash',\n url: 'https://lodash.com/',\n npm: 'lodash',\n test: function(win) {\n var _ = typeof (_ = win._) == 'function' && _,\n chain = typeof (chain = _ && _.chain) == 'function' && chain,\n wrapper = (chain || _ || function() { return {}; })(1);\n\n if (_ && wrapper.__wrapped__) {\n return { version: _.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Underscore': {\n icon: 'underscore',\n url: 'http://underscorejs.org/',\n npm: 'underscore',\n test: function(win) {\n if (win._ && typeof win._.tap === 'function' &&\n !d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests['Lo-Dash'].test(win)) {\n return {version: win._.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Sammy': {\n icon: 'sammy',\n url: 'http://sammyjs.org',\n test: function(win) {\n if (win.Sammy && win.Sammy.Application.curry) {\n return {version: win.Sammy.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Rico': {\n icon: 'rico',\n url: 'http://openrico.sourceforge.net/examples/index.html',\n test: function(win) {\n if (win.Rico && window.Rico.checkIfComplete) {\n return {version: win.Rico.Version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'MochiKit': {\n icon: 'mochikit',\n url: 'https://mochi.github.io/mochikit/',\n test: function(win) {\n if (win.MochiKit && win.MochiKit.Base.module) {\n return {version: MochiKit.VERSION || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'gRapha&euml;l': {\n icon: 'graphael',\n url: 'https://github.com/DmitryBaranovskiy/g.raphael',\n test: function(win) {\n if (win.Raphael && win.Raphael.fn.g) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Glow': {\n icon: 'glow',\n url: 'http://www.bbc.co.uk/glow/',\n test: function(win) {\n if (win.gloader && win.gloader.getRequests) {\n return {version: UNKNOWN_VERSION};\n }\n else if (win.glow && win.glow.dom) {\n return {version: win.glow.VERSION || UNKNOWN_VERSION};\n }\n else if (win.Glow) {\n return {version: win.Glow.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Socket.IO': {\n icon: 'socketio', // currently has no icon\n url: 'https://socket.io/',\n npm: 'socket.io',\n test: function(win) {\n // version 0.6.2 uses only io.Socket; more recent versions also have io.sockets\n if (win.io && (win.io.sockets || win.io.Socket)) {\n return {version: win.io.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Mustache': {\n icon: 'mustache',\n url: 'http://mustache.github.io/',\n npm: 'mustache',\n test: function(win) {\n if (win.Mustache && win.Mustache.to_html) {\n return {version: win.Mustache.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Fabric.js': {\n icon: 'icon38', // currently has no icon\n url: 'http://fabricjs.com/',\n npm: 'fabric',\n test: function(win) {\n if (win.fabric && win.fabric.util) {\n return {version: win.fabric.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'FuseJS': {\n icon: 'fusejs',\n url: 'http://fusejs.io/',\n npm: 'fuse.js',\n test: function(win) {\n if (win.Fuse) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Tween.js': {\n icon: 'icon38', // currently has no icon\n url: 'https://github.com/tweenjs/tween.js',\n npm: 'tween.js',\n test: function(win) {\n if (win.TWEEN && win.TWEEN.Easing) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'SproutCore': {\n icon: 'sproutcore',\n url: 'http://sproutcore.com/',\n test: function(win) {\n if (win.SC && win.SC.Application) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Zepto.js': {\n icon: 'zepto',\n url: 'http://zeptojs.com',\n npm: 'zepto',\n test: function(win) {\n if (win.Zepto && win.Zepto.fn) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'three.js': {\n icon: 'icon38', // currently has no icon\n url: 'https://threejs.org/',\n npm: 'three',\n test: function(win) {\n if (win.THREE && win.THREE.REVISION) {\n return {version: 'r' + win.THREE.REVISION};\n }\n else if (win.THREE) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'PhiloGL': {\n icon: 'philogl',\n url: 'http://www.senchalabs.org/philogl/',\n npm: 'philogl',\n test: function(win) {\n if (win.PhiloGL && win.PhiloGL.Camera) {\n return {version: win.PhiloGL.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'CamanJS': {\n icon: 'camanjs',\n url: 'http://camanjs.com/',\n npm: 'caman',\n test: function(win) {\n if (win.Caman && win.Caman.version) {\n return {version: win.Caman.version.release};\n }\n else if (win.Caman) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'yepnope': {\n icon: 'yepnope',\n url: 'http://yepnopejs.com/',\n test: function(win) {\n if (win.yepnope && win.yepnope.injectJs) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'LABjs': {\n icon: 'icon38',\n url: 'https://github.com/getify/LABjs',\n test: function(win) {\n if (win.$LAB && win.$LAB.setOptions) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'Head JS': {\n icon: 'headjs',\n url: 'http://headjs.com/',\n npm: 'headjs',\n test: function(win) {\n if (win.head && win.head.js) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'ControlJS': {\n icon: 'icon38',\n url: 'http://stevesouders.com/controljs/',\n test: function(win) {\n if (win.CJS && win.CJS.start) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'RequireJS': {\n icon: 'requirejs',\n url: 'http://requirejs.org/',\n npm: 'requirejs',\n test: function(win) {\n var req = win.require || win.requirejs;\n if (req && (req.load || (req.s && req.s.contexts && req.s.contexts._ && (req.s.contexts._.loaded || req.s.contexts._.load)))) {\n return { version: req.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'RightJS': {\n icon: 'rightjs',\n url: 'http://rightjs.org/',\n test: function(win) {\n if (win.RightJS && win.RightJS.isNode) {\n return { version: win.RightJS.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'jQuery Tools': {\n icon: 'jquerytools',\n url: 'http://jquerytools.github.io/',\n test: function(win) {\n var jq = win.jQuery || win.$;\n if(jq && jq.tools) {\n return { version: jq.tools.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Pusher': {\n icon: 'pusher',\n url: 'https://pusher.com/docs/',\n npm: 'pusher-js',\n test: function(win) {\n if(win.Pusher && win.Pusher.Channel) {\n return { version: win.Pusher.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Paper.js': {\n icon: 'paperjs',\n url: 'http://paperjs.org/',\n npm: 'paper',\n test: function(win) {\n if(win.paper && win.paper.Point) {\n return { version: win.paper.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Swiffy': {\n icon: 'icon38',\n url: 'https://developers.google.com/swiffy/',\n test: function(win) {\n if(win.swiffy && win.swiffy.Stage) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Move': {\n icon: 'move',\n url: 'https://github.com/rsms/move',\n npm: 'move',\n test: function(win) {\n if(win.move && win.move.compile) {\n return { version: win.move.version() || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'AmplifyJS': {\n icon: 'amplifyjs',\n url: 'http://amplifyjs.com/',\n npm: 'amplifyjs',\n test: function(win) {\n if(win.amplify && win.amplify.publish) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Popcorn.js': {\n icon: 'popcornjs',\n url: 'https://github.com/mozilla/popcorn-js/',\n test: function(win) {\n if (win.Popcorn && win.Popcorn.Events) {\n return { version: win.Popcorn.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'D3': {\n icon: 'd3',\n url: 'https://d3js.org/',\n npm: 'd3',\n test: function(win) {\n if (win.d3 && win.d3.select) {\n return { version: win.d3.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Handlebars': {\n icon: 'handlebars',\n url: 'http://handlebarsjs.com/',\n npm: 'handlebars',\n test: function(win) {\n if(win.Handlebars && win.Handlebars.compile) {\n return { version: win.Handlebars.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Knockout': {\n icon: 'knockout',\n url: 'http://knockoutjs.com/',\n npm: 'knockout',\n test: function(win) {\n if (win.ko && win.ko.applyBindings) {\n return { version: win.ko.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Spine': {\n icon: 'icon38',\n url: 'http://spine.github.io/',\n test: function(win) {\n if (win.Spine && win.Spine.Controller) {\n return {version: win.Spine.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n\n 'jQuery Mobile': {\n icon: 'jquery_mobile',\n url: 'http://jquerymobile.com/',\n npm: 'jquery-mobile',\n test: function(win) {\n var jq = win.jQuery || win.$ || win.$jq || win.$j;\n if(jq && jq.fn && jq.fn.jquery && jq.mobile) {\n return { version: jq.mobile.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'WebFont Loader': {\n icon: 'icon38',\n url: 'https://github.com/typekit/webfontloader',\n npm: 'webfontloader',\n test: function(win) {\n if(win.WebFont && win.WebFont.load) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Angular': {\n icon: 'angular',\n url: 'https://angular.io/',\n npm: '@angular/core',\n test: function(win) {\n var ng = win.document.querySelector('[ng-version]');\n if (ng) {\n return { version: ng.getAttribute('ng-version') || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'AngularJS': {\n icon: 'angularjs',\n url: 'https://angularjs.org/',\n npm: 'angular',\n test: function(win) {\n var ng = win.angular;\n if(ng && ng.version && ng.version.full) {\n return { version: ng.version.full };\n }\n else if (ng) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Ember.js': {\n icon: 'emberjs',\n url: 'https://emberjs.com/',\n npm: 'ember-source',\n test: function(win) {\n var ember = win.Ember || win.Em;\n if (ember && ember.propertyDidChange) {\n return { version: ember.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Hammer.js': {\n icon: 'hammerjs',\n url: 'http://eightmedia.github.io/hammer.js/',\n npm: 'hammerjs',\n test: function(win) {\n if(win.Hammer && win.Hammer.Pinch) {\n // Hammer.VERSION available in 1.0.10+\n return { version: win.Hammer.VERSION || \"&lt; 1.0.10\" };\n }\n return false;\n }\n },\n\n 'Visibility.js': {\n icon: 'icon38',\n url: 'https://github.com/ai/visibilityjs',\n npm: 'visibilityjs',\n test: function(win) {\n if(win.Visibility && win.Visibility.every) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'Velocity.js': {\n icon: 'icon38',\n url: 'http://velocityjs.org/',\n npm: 'velocity-animate',\n test: function(win) {\n var jq = win.jQuery || win.$,\n velocity = jq ? jq.Velocity : win.Velocity;\n\n if(velocity && velocity.RegisterEffect && velocity.version) {\n return {\n version:\n velocity.version.major + \".\" +\n velocity.version.minor + \".\" +\n velocity.version.patch\n };\n }\n else if (velocity && velocity.RegisterEffect) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n\n 'IfVisible.js': {\n icon: 'icon38',\n url: 'http://serkanyersen.github.io/ifvisible.js/',\n npm: 'ifvisible.js',\n test: function(win) {\n var iv = win.ifvisible;\n if(iv && iv.__ceGUID === \"ifvisible.object.event.identifier\") {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Pixi.js': {\n icon: 'pixi',\n url: 'http://www.pixijs.com/',\n npm: 'pixi.js',\n test: function(win) {\n var px = win.PIXI;\n if(px && px.WebGLRenderer && px.VERSION) {\n // version 4.4.3 returns simply \"4.4.3\"; version 1.5.2 returns \"v1.5.2\"\n return { version: px.VERSION.replace('v', '') || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'DC.js': {\n icon: 'dcjs',\n url: 'http://dc-js.github.io/dc.js/',\n npm: 'dc',\n test: function(win) {\n var dc = win.dc;\n if(dc && dc.registerChart) {\n return { version: dc.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'GreenSock JS': {\n icon: 'greensock',\n url: 'https://greensock.com/gsap',\n npm: 'gsap',\n test: function(win) {\n if (win.TweenMax && win.TweenMax.pauseAll) {\n return { version: win.TweenMax.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'FastClick': {\n icon: 'fastclick',\n url: 'https://github.com/ftlabs/fastclick',\n npm: 'fastclick',\n test: function(win) {\n if(win.FastClick && win.FastClick.notNeeded) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Isotope': {\n icon: 'isotope',\n url: 'https://isotope.metafizzy.co/',\n npm: 'isotope-layout',\n test: function(win) {\n if(win.Isotope || (win.$ != null && win.$.Isotope)) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Marionette': {\n icon: 'marionette',\n url: 'https://marionettejs.com/',\n npm: 'backbone.marionette',\n test: function(win) {\n if(win.Marionette && win.Marionette.Application) {\n return { version: win.Marionette.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Can': {\n icon: 'canjs',\n url: 'https://canjs.com/',\n npm: 'can',\n test: function (win) {\n if (win.can && win.can.Construct) {\n return { version: win.can.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Vue': {\n icon: 'vue',\n url: 'https://vuejs.org/',\n npm: 'vue',\n test: function(win) {\n if (win.Vue && win.Vue.nextTick) {\n return { version: win.Vue.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Two': {\n icon: 'two',\n url: 'https://two.js.org/',\n npm: 'two.js',\n test: function(win) {\n if (win.Two && win.Two.Utils) {\n return { version: win.Two.Version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Brewser': {\n icon: 'brewser',\n url: 'https://robertpataki.github.io/brewser/',\n npm: 'brewser',\n test: function(win) {\n if(win.BREWSER && win.BREWSER.ua) {\n return { version: BREWSER.VERSION || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Material Design Lite': {\n icon: 'mdl',\n url: 'https://getmdl.io/',\n npm: 'material-design-lite',\n test: function(win) {\n if(win.componentHandler && win.componentHandler.upgradeElement) {\n return { version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'Kendo UI': {\n icon: 'kendoui',\n url: 'https://github.com/telerik/kendo-ui-core',\n npm: 'kendo-ui-core',\n test: function(win) {\n if (win.kendo && win.kendo.View && win.kendo.View.extend) {\n return {version: win.kendo.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'Matter.js': {\n icon: 'matter-js',\n url: 'http://brm.io/matter-js/',\n npm: 'matter-js',\n test: function(win) {\n if (win.Matter && win.Matter.Engine) {\n return {version: UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'Riot': {\n icon: 'riot',\n url: 'http://riotjs.com/',\n npm: 'riot',\n test: function(win) {\n if (win.riot && win.riot.mixin) {\n return { version: win.riot.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Sea.js': {\n icon: 'icon38',\n url: 'https://seajs.github.io/seajs/docs/',\n npm: 'seajs',\n test: function(win) {\n if(win.seajs && win.seajs.use) {\n return { version: win.seajs.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Moment.js': {\n icon: 'momentjs',\n url: 'http://momentjs.com/',\n npm: 'moment',\n test: function(win) {\n if(win.moment && (win.moment.isMoment || win.moment.lang)) {\n // version 1.0.0 has neither \"isMoment\" nor \"version\"\n return { version: win.moment.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Moment Timezone': {\n icon: 'momentjs',\n url: 'http://momentjs.com/timezone/',\n npm: 'moment-timezone',\n test: function(win) {\n if (win.moment && win.moment.tz) {\n return { version: win.moment.tz.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'ScrollMagic': {\n icon: 'scrollmagic',\n url: 'http://scrollmagic.io/',\n npm: 'scrollmagic',\n test: function(win) {\n if (win.ScrollMagic && win.ScrollMagic.Controller) {\n return {version: ScrollMagic.version || UNKNOWN_VERSION};\n }\n return false;\n }\n },\n 'SWFObject': {\n icon: 'icon38', // currently has no icon\n url: 'https://github.com/swfobject/swfobject',\n test: function(win) {\n if (win.swfobject && win.swfobject.embedSWF) {\n // 2.x - exact version only for 2.3\n return { version: win.swfobject.version || UNKNOWN_VERSION };\n } else if(win.deconcept && win.deconcept.SWFObject) {\n // 1.x\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'FlexSlider': {\n icon: 'icon38', // currently has no icon\n url: 'https://woocommerce.com/flexslider/',\n npm: 'flexslider',\n test: function(win) {\n var jq = win.jQuery || win.$ || win.$jq || win.$j;\n if (jq && jq.fn && jq.fn.jquery && jq.flexslider){\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'SPF': {\n icon: 'icon38', // currently has no icon\n url: 'https://youtube.github.io/spfjs/',\n npm: 'spf',\n test: function(win) {\n if (win.spf && win.spf.init) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Numeral.js': {\n icon: 'icon38', // currently has no icon\n url: 'http://numeraljs.com/',\n npm: 'numeraljs',\n test: function(win) {\n if (win.numeral && win.isNumeral) {\n return { version: win.numeral.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'boomerang.js': {\n icon: 'icon38', // currently has no icon\n url: 'https://soasta.github.io/boomerang/',\n npm: 'boomerangjs',\n test: function(win) {\n if (win.BOOMR && win.BOOMR.utils && win.BOOMR.init) {\n return { version: win.BOOMR.version || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Framer': {\n icon: 'framer',\n url: 'https://framer.com/',\n npm: 'framerjs',\n test: function(win) {\n if (win.Framer && win.Framer.Layer) {\n return { version: win.Framer.Version.build || UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'Marko': {\n icon: 'marko',\n url: 'https://markojs.com/',\n npm: 'marko',\n test: function (win) {\n var selector = '[data-marko-key], [data-marko]';\n var markoElement = document.querySelector(selector);\n if (markoElement) {\n return { version: UNKNOWN_VERSION };\n }\n return false;\n }\n },\n 'AMP': {\n icon: 'amp',\n url: 'https://ampproject.org/',\n npm: null,\n test: function (win) {\n var version = win.document.documentElement.getAttribute(\"amp-version\");\n return version ? { version: version } : false;\n }\n },\n 'Workbox': {\n icon: 'workbox',\n url: 'https://developers.google.com/web/tools/workbox/',\n npm: 'workbox-sw',\n test: async function (win) {\n var nav = win.navigator;\n // Service Workers not supported\n if (!('serviceWorker' in nav)) {\n return false;\n }\n return nav.serviceWorker.getRegistration()\n .then(function(registration) {\n var scriptURL = nav.serviceWorker.controller.scriptURL;\n return fetch(scriptURL, { credentials: 'include',\n headers: { 'service-worker': 'script' }\n })\n .then(function(response) {\n return response.text();\n })\n .then(function(scriptContent) {\n var workboxRegExp = /new Workbox|new workbox|workbox\\.precaching\\.|workbox\\.strategies/gm;\n if (workboxRegExp.test(scriptContent)) {\n // Adapted from\n // https://github.com/semver/semver/issues/232#issue-48635632\n var semVerRegExp = /workbox.*?\\b((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?)\\b/gim;\n var matches = semVerRegExp.exec(scriptContent);\n var version = UNKNOWN_VERSION;\n if (Array.isArray(matches) && matches.length > 1 && matches[1]) {\n version = matches[1];\n }\n return { version: version };\n }\n return false;\n });\n }).catch(function(exception) {\n return false;\n });\n }\n }\n};\n";
+
+
+
+
+
+function detectLibraries(){
+
+const libraries=[];
+
+
+
+
+Object.entries(d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests).forEach(async([name,lib])=>{
+try{
+const result=await lib.test(window);
+if(result){
+libraries.push({
+name:name,
+version:result.version,
+npmPkgName:lib.npm});
+
+}
+}catch(e){}
+});
+
+return libraries;
+}
+
+class JSLibraries extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const expression=`(function () {
+ ${libDetectorSource};
+ return (${detectLibraries.toString()}());
+ })()`;
+
+return passContext.driver.evaluateAsync(expression);
+}}
+
+
+module.exports=JSLibraries;
+
+},{"../gatherer":44}],"../gather/gatherers/dobetterweb/optimized-images":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const URL=require('../../../lib/url-shim');
+const NetworkRequest=require('../../../lib/network-request');
+const Sentry=require('../../../lib/sentry');
+const Driver=require('../../driver.js');
+
+const JPEG_QUALITY=0.92;
+const WEBP_QUALITY=0.85;
+
+const MINIMUM_IMAGE_SIZE=4096;
+
+const IMAGE_REGEX=/^image\/((x|ms|x-ms)-)?(png|bmp|jpeg)$/;
+
+
+
+
+
+
+
+
+
+
+
+function getOptimizedNumBytes(url){
+return new Promise(function(resolve,reject){
+const img=new Image();
+const canvas=document.createElement('canvas');
+const context=canvas.getContext('2d');
+if(!context){
+return reject(new Error('unable to create canvas context'));
+}
+
+
+
+
+
+
+function getTypeStats(type,quality){
+const dataURI=canvas.toDataURL(type,quality);
+const base64=dataURI.slice(dataURI.indexOf(',')+1);
+return{base64:base64.length,binary:atob(base64).length};
+}
+
+img.addEventListener('error',reject);
+img.addEventListener('load',()=>{
+try{
+canvas.height=img.height;
+canvas.width=img.width;
+context.drawImage(img,0,0);
+
+const jpeg=getTypeStats('image/jpeg',0.92);
+const webp=getTypeStats('image/webp',0.85);
+
+resolve({jpeg,webp});
+}catch(err){
+reject(err);
+}
+},false);
+
+img.src=url;
+});
+}
+
+class OptimizedImages extends Gatherer{
+
+
+
+
+
+static filterImageRequests(pageUrl,networkRecords){
+
+const seenUrls=new Set();
+return networkRecords.reduce((prev,record)=>{
+if(seenUrls.has(record.url)||!record.finished){
+return prev;
+}
+
+seenUrls.add(record.url);
+const isOptimizableImage=record.resourceType===NetworkRequest.TYPES.Image&&
+IMAGE_REGEX.test(record.mimeType);
+const isSameOrigin=URL.originsMatch(pageUrl,record.url);
+const isBase64DataUri=/^data:.{2,40}base64\s*,/.test(record.url);
+
+const actualResourceSize=Math.min(record.resourceSize||0,record.transferSize||0);
+if(isOptimizableImage&&actualResourceSize>MINIMUM_IMAGE_SIZE){
+prev.push({
+isSameOrigin,
+isBase64DataUri,
+requestId:record.requestId,
+url:record.url,
+mimeType:record.mimeType,
+resourceSize:actualResourceSize});
+
+}
+
+return prev;
+},[]);
+}
+
+
+
+
+
+
+
+_getEncodedResponse(driver,requestId,encoding){
+requestId=NetworkRequest.getRequestIdForBackend(requestId);
+
+const quality=encoding==='jpeg'?JPEG_QUALITY:WEBP_QUALITY;
+const params={requestId,encoding,quality,sizeOnly:true};
+return driver.sendCommand('Audits.getEncodedResponse',params);
+}
+
+
+
+
+
+
+calculateImageStats(driver,networkRecord){
+
+
+return Promise.resolve(networkRecord.requestId).then(requestId=>{
+if(this._getEncodedResponseUnsupported)return;
+return this._getEncodedResponse(driver,requestId,'jpeg').then(jpegData=>{
+return this._getEncodedResponse(driver,requestId,'webp').then(webpData=>{
+return{
+fromProtocol:true,
+originalSize:networkRecord.resourceSize,
+jpegSize:jpegData.encodedSize,
+webpSize:webpData.encodedSize};
+
+});
+}).catch(err=>{
+if(/wasn't found/.test(err.message)){
+
+this._getEncodedResponseUnsupported=true;
+}else{
+throw err;
+}
+});
+}).then(result=>{
+if(result)return result;
+
+
+
+if(!networkRecord.isSameOrigin&&!networkRecord.isBase64DataUri)return null;
+
+const script=`(${getOptimizedNumBytes.toString()})(${JSON.stringify(networkRecord.url)})`;
+return driver.evaluateAsync(script).then(stats=>{
+if(!stats)return null;
+const isBase64DataUri=networkRecord.isBase64DataUri;
+const base64Length=networkRecord.url.length-networkRecord.url.indexOf(',')-1;
+return{
+fromProtocol:false,
+originalSize:isBase64DataUri?base64Length:networkRecord.resourceSize,
+jpegSize:isBase64DataUri?stats.jpeg.base64:stats.jpeg.binary,
+webpSize:isBase64DataUri?stats.webp.base64:stats.webp.binary};
+
+});
+});
+}
+
+
+
+
+
+
+async computeOptimizedImages(driver,imageRecords){
+
+const results=[];
+
+for(const record of imageRecords){
+try{
+const stats=await this.calculateImageStats(driver,record);
+if(stats===null){
+continue;
+}
+
+
+const image={failed:false,...stats,...record};
+results.push(image);
+}catch(err){
+
+
+Sentry.captureException(err,{
+tags:{gatherer:'OptimizedImages'},
+extra:{imageUrl:URL.elideDataURI(record.url)},
+level:'warning'});
+
+
+
+const imageError={failed:true,errMsg:err.message,...record};
+results.push(imageError);
+}
+}
+
+return results;
+}
+
+
+
+
+
+
+afterPass(passContext,loadData){
+const networkRecords=loadData.networkRecords;
+const imageRecords=OptimizedImages.filterImageRequests(passContext.url,networkRecords);
+
+return Promise.resolve().
+then(_=>this.computeOptimizedImages(passContext.driver,imageRecords)).
+then(results=>{
+const successfulResults=results.filter(result=>!result.failed);
+if(results.length&&!successfulResults.length){
+throw new Error('All image optimizations failed');
+}
+
+return results;
+});
+}}
+
+
+module.exports=OptimizedImages;
+
+},{"../../../lib/network-request":67,"../../../lib/sentry":69,"../../../lib/url-shim":"url","../../driver.js":42,"../gatherer":44}],"../gather/gatherers/dobetterweb/password-inputs-with-prevented-paste":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+const Gatherer=require('../gatherer');
+const pageFunctions=require('../../../lib/page-functions');
+
+
+
+
+
+
+function findPasswordInputsWithPreventedPaste(){
+return Array.from(document.querySelectorAll('input[type="password"]')).
+filter(passwordInput=>
+!passwordInput.dispatchEvent(
+new ClipboardEvent('paste',{cancelable:true}))).
+
+
+map(passwordInput=>({
+
+snippet:getOuterHTMLSnippet(passwordInput)}));
+
+}
+
+class PasswordInputsWithPreventedPaste extends Gatherer{
+
+
+
+
+afterPass(passContext){
+return passContext.driver.evaluateAsync(`(() => {
+ ${pageFunctions.getOuterHTMLSnippetString};
+ return (${findPasswordInputsWithPreventedPaste.toString()}());
+ })()`);
+}}
+
+
+
+module.exports=PasswordInputsWithPreventedPaste;
+
+},{"../../../lib/page-functions":68,"../gatherer":44}],"../gather/gatherers/dobetterweb/response-compression":[function(require,module,exports){
+(function(Buffer){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const URL=require('../../../lib/url-shim');
+const Sentry=require('../../../lib/sentry');
+const NetworkRequest=require('../../../lib/network-request');
+const gzip=require('zlib').gzip;
+
+const CHROME_EXTENSION_PROTOCOL='chrome-extension:';
+const compressionHeaders=['content-encoding','x-original-content-encoding'];
+const compressionTypes=['gzip','br','deflate'];
+const binaryMimeTypes=['image','audio','video'];
+
+const textResourceTypes=[
+NetworkRequest.TYPES.Document,
+NetworkRequest.TYPES.Script,
+NetworkRequest.TYPES.Stylesheet,
+NetworkRequest.TYPES.XHR,
+NetworkRequest.TYPES.Fetch,
+NetworkRequest.TYPES.EventSource];
+
+
+class ResponseCompression extends Gatherer{
+
+
+
+
+static filterUnoptimizedResponses(networkRecords){
+
+const unoptimizedResponses=[];
+
+networkRecords.forEach(record=>{
+const mimeType=record.mimeType;
+const resourceType=record.resourceType||NetworkRequest.TYPES.Other;
+const resourceSize=record.resourceSize;
+
+const isBinaryResource=mimeType&&binaryMimeTypes.some(type=>mimeType.startsWith(type));
+const isTextResource=!isBinaryResource&&textResourceTypes.includes(resourceType);
+const isChromeExtensionResource=record.url.startsWith(CHROME_EXTENSION_PROTOCOL);
+
+if(!isTextResource||!resourceSize||!record.finished||
+isChromeExtensionResource||!record.transferSize||record.statusCode===304){
+return;
+}
+
+const isContentEncoded=(record.responseHeaders||[]).find(header=>
+compressionHeaders.includes(header.name.toLowerCase())&&
+compressionTypes.includes(header.value));
+
+
+if(!isContentEncoded){
+unoptimizedResponses.push({
+requestId:record.requestId,
+url:record.url,
+mimeType:mimeType,
+transferSize:record.transferSize,
+resourceSize:resourceSize,
+gzipSize:0});
+
+}
+});
+
+return unoptimizedResponses;
+}
+
+
+
+
+
+
+afterPass(passContext,loadData){
+const networkRecords=loadData.networkRecords;
+const textRecords=ResponseCompression.filterUnoptimizedResponses(networkRecords);
+
+const driver=passContext.driver;
+return Promise.all(textRecords.map(record=>{
+return driver.getRequestContent(record.requestId).then(content=>{
+
+if(!content){
+return record;
+}
+
+return new Promise((resolve,reject)=>{
+return gzip(content,(err,res)=>{
+if(err){
+return reject(err);
+}
+
+
+record.gzipSize=Buffer.byteLength(res,'utf8');
+
+resolve(record);
+});
+});
+}).catch(err=>{
+Sentry.captureException(err,{
+tags:{gatherer:'ResponseCompression'},
+extra:{url:URL.elideDataURI(record.url)},
+level:'warning'});
+
+
+record.gzipSize=undefined;
+return record;
+});
+}));
+}}
+
+
+module.exports=ResponseCompression;
+
+}).call(this,require("buffer").Buffer);
+},{"../../../lib/network-request":67,"../../../lib/sentry":69,"../../../lib/url-shim":"url","../gatherer":44,"buffer":88,"zlib":86}],"../gather/gatherers/dobetterweb/tags-blocking-first-paint":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const Driver=require('../../driver.js');
+
+
+
+
+function installMediaListener(){
+window.___linkMediaChanges=[];
+Object.defineProperty(HTMLLinkElement.prototype,'media',{
+set:function(val){
+window.___linkMediaChanges.push({
+href:this.href,
+media:val,
+msSinceHTMLEnd:Date.now()-window.performance.timing.responseEnd,
+matches:window.matchMedia(val).matches});
+
+
+return this.setAttribute('media',val);
+}});
+
+}
+
+
+
+
+
+function collectTagsThatBlockFirstPaint(){
+return new Promise((resolve,reject)=>{
+try{
+const tagList=[...document.querySelectorAll('link, head script[src]')].
+filter(tag=>{
+if(tag.tagName==='SCRIPT'){
+const scriptTag=tag;
+return(
+!scriptTag.hasAttribute('async')&&
+!scriptTag.hasAttribute('defer')&&
+!/^data:/.test(scriptTag.src)&&
+scriptTag.getAttribute('type')!=='module');
+
+}else if(tag.tagName==='LINK'){
+
+
+
+const linkTag=tag;
+const blockingStylesheet=linkTag.rel==='stylesheet'&&
+window.matchMedia(linkTag.media).matches&&!linkTag.disabled;
+const blockingImport=linkTag.rel==='import'&&!linkTag.hasAttribute('async');
+return blockingStylesheet||blockingImport;
+}
+
+return false;
+}).
+map(tag=>{
+return{
+tagName:tag.tagName,
+url:tag.tagName==='LINK'?tag.href:tag.src,
+src:tag.src,
+href:tag.href,
+rel:tag.rel,
+media:tag.media,
+disabled:tag.disabled,
+mediaChanges:window.___linkMediaChanges.filter(item=>item.href===tag.href)};
+
+});
+resolve(tagList);
+}catch(e){
+const friendly='Unable to gather Scripts/Stylesheets/HTML Imports on the page';
+reject(new Error(`${friendly}: ${e.message}`));
+}
+});
+}
+
+class TagsBlockingFirstPaint extends Gatherer{
+
+
+
+static _filteredAndIndexedByUrl(networkRecords){
+
+const result={};
+
+return networkRecords.reduce((prev,record)=>{
+if(!record.finished){
+return prev;
+}
+
+const isParserGenerated=record.initiator.type==='parser';
+
+
+const isParserScriptOrStyle=/(css|script)/.test(record.mimeType)&&isParserGenerated;
+const isFailedRequest=record._failed;
+const isHtml=record.mimeType&&record.mimeType.includes('html');
+
+
+
+if(isHtml||isParserScriptOrStyle||isFailedRequest&&isParserGenerated){
+prev[record.url]={
+isLinkPreload:!!record.isLinkPreload,
+transferSize:record.transferSize,
+startTime:record.startTime,
+endTime:record.endTime};
+
+}
+
+return prev;
+},result);
+}
+
+
+
+
+
+static findBlockingTags(driver,networkRecords){
+const scriptSrc=`(${collectTagsThatBlockFirstPaint.toString()}())`;
+const firstRequestEndTime=networkRecords.reduce(
+(min,record)=>Math.min(min,record.endTime),
+Infinity);
+
+return driver.evaluateAsync(scriptSrc).then(tags=>{
+const requests=TagsBlockingFirstPaint._filteredAndIndexedByUrl(networkRecords);
+
+return tags.reduce((prev,tag)=>{
+const request=requests[tag.url];
+if(request&&!request.isLinkPreload){
+
+
+
+const timesResourceBecameNonBlocking=(tag.mediaChanges||[]).
+filter(change=>!change.matches).
+map(change=>change.msSinceHTMLEnd);
+const earliestNonBlockingTime=Math.min(...timesResourceBecameNonBlocking);
+const lastTimeResourceWasBlocking=Math.max(
+request.startTime,
+firstRequestEndTime+earliestNonBlockingTime/1000);
+
+
+prev.push({
+tag,
+transferSize:request.transferSize||0,
+startTime:request.startTime,
+endTime:Math.min(request.endTime,lastTimeResourceWasBlocking)});
+
+
+
+requests[tag.url]=null;
+}
+
+return prev;
+},[]);
+});
+}
+
+
+
+
+beforePass(passContext){
+return passContext.driver.evaluateScriptOnNewDocument(`(${installMediaListener.toString()})()`);
+}
+
+
+
+
+
+
+afterPass(passContext,loadData){
+return TagsBlockingFirstPaint.findBlockingTags(passContext.driver,loadData.networkRecords);
+}}
+
+
+module.exports=TagsBlockingFirstPaint;
+
+},{"../../driver.js":42,"../gatherer":44}],"../gather/gatherers/html-without-javascript":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+
+
+
+
+
+
+
+
+function getBodyText(){
+
+const body=document.querySelector('body');
+return Promise.resolve({
+bodyText:body?body.innerText:'',
+hasNoScript:!!document.querySelector('noscript')});
+
+}
+
+class HTMLWithoutJavaScript extends Gatherer{
+
+
+
+beforePass(passContext){
+passContext.disableJavaScript=true;
+}
+
+
+
+
+
+async afterPass(passContext){
+
+passContext.disableJavaScript=false;
+
+const expression=`(${getBodyText.toString()}())`;
+const{bodyText,hasNoScript}=await passContext.driver.evaluateAsync(expression);
+if(typeof bodyText!=='string'){
+throw new Error('document body innerText returned by protocol was not a string');
+}
+
+return{
+bodyText,
+hasNoScript};
+
+}}
+
+
+module.exports=HTMLWithoutJavaScript;
+
+},{"./gatherer":44}],"../gather/gatherers/http-redirect":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+
+
+
+
+
+class HTTPRedirect extends Gatherer{
+constructor(){
+super();
+this._preRedirectURL='';
+}
+
+
+
+
+beforePass(passContext){
+this._preRedirectURL=passContext.url;
+passContext.url=this._preRedirectURL.replace(/^https/,'http');
+}
+
+
+
+
+
+async afterPass(passContext){
+
+passContext.url=this._preRedirectURL;
+
+const expression=`new URL(window.location).protocol === 'https:'`;
+const isHttps=await passContext.driver.evaluateAsync(expression,{useIsolation:true});
+return{
+value:isHttps};
+
+}}
+
+
+module.exports=HTTPRedirect;
+
+},{"./gatherer":44}],"../gather/gatherers/image-usage":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+const pageFunctions=require('../../lib/page-functions.js');
+const Driver=require('../driver.js');
+
+
+
+
+
+function collectImageElementInfo(){
+
+function getClientRect(element){
+const clientRect=element.getBoundingClientRect();
+return{
+
+top:clientRect.top,
+bottom:clientRect.bottom,
+left:clientRect.left,
+right:clientRect.right};
+
+}
+
+
+
+const allElements=getElementsInDocument();
+const allImageElements=allElements.filter(element=>{
+return element.localName==='img';
+});
+
+
+const htmlImages=allImageElements.map(element=>{
+const computedStyle=window.getComputedStyle(element);
+return{
+
+
+src:element.currentSrc,
+width:element.width,
+height:element.height,
+clientWidth:element.clientWidth,
+clientHeight:element.clientHeight,
+clientRect:getClientRect(element),
+naturalWidth:element.naturalWidth,
+naturalHeight:element.naturalHeight,
+isCss:false,
+isPicture:!!element.parentElement&&element.parentElement.tagName==='PICTURE',
+usesObjectFit:['cover','contain','scale-down','none'].includes(
+computedStyle.getPropertyValue('object-fit'))};
+
+
+});
+
+
+
+const CSS_URL_REGEX=/^url\("([^"]+)"\)$/;
+
+const CSS_SIZE_REGEX=/(auto|contain|cover)/;
+
+const cssImages=allElements.reduce((images,element)=>{
+const style=window.getComputedStyle(element);
+if(!style.backgroundImage||!CSS_URL_REGEX.test(style.backgroundImage)||
+!style.backgroundSize||!CSS_SIZE_REGEX.test(style.backgroundSize)){
+return images;
+}
+
+const imageMatch=style.backgroundImage.match(CSS_URL_REGEX);
+
+const url=imageMatch[1];
+
+
+const differentImages=images.filter(image=>image.src!==url);
+if(images.length-differentImages.length>2){
+return differentImages;
+}
+
+images.push({
+src:url,
+clientWidth:element.clientWidth,
+clientHeight:element.clientHeight,
+clientRect:getClientRect(element),
+
+naturalWidth:Number.MAX_VALUE,
+naturalHeight:Number.MAX_VALUE,
+isCss:true,
+isPicture:false,
+usesObjectFit:false});
+
+
+return images;
+},[]);
+
+return htmlImages.concat(cssImages);
+}
+
+
+
+
+
+
+function determineNaturalSize(url){
+return new Promise((resolve,reject)=>{
+const img=new Image();
+img.addEventListener('error',_=>reject(new Error('determineNaturalSize failed img load')));
+img.addEventListener('load',()=>{
+resolve({
+naturalWidth:img.naturalWidth,
+naturalHeight:img.naturalHeight});
+
+});
+
+img.src=url;
+});
+}
+
+class ImageUsage extends Gatherer{
+
+
+
+
+
+async fetchElementWithSizeInformation(driver,element){
+const url=JSON.stringify(element.src);
+try{
+
+const size=await driver.evaluateAsync(`(${determineNaturalSize.toString()})(${url})`);
+return Object.assign(element,size);
+}catch(_){
+
+return Object.assign(element,{naturalWidth:0,naturalHeight:0});
+}
+}
+
+
+
+
+
+
+async afterPass(passContext,loadData){
+const driver=passContext.driver;
+const indexedNetworkRecords=loadData.networkRecords.reduce((map,record)=>{
+if(/^image/.test(record.mimeType)&&record.finished){
+map[record.url]={
+url:record.url,
+resourceSize:Math.min(record.resourceSize||0,record.transferSize),
+startTime:record.startTime,
+endTime:record.endTime,
+responseReceivedTime:record.responseReceivedTime,
+mimeType:record.mimeType};
+
+}
+
+return map;
+},{});
+
+const expression=`(function() {
+ ${pageFunctions.getElementsInDocumentString}; // define function on page
+ return (${collectImageElementInfo.toString()})();
+ })()`;
+
+
+const elements=await driver.evaluateAsync(expression);
+
+const imageUsage=[];
+for(let element of elements){
+
+element.networkRecord=indexedNetworkRecords[element.src];
+
+
+
+
+if((element.isPicture||element.isCss)&&element.networkRecord){
+element=await this.fetchElementWithSizeInformation(driver,element);
+}
+
+imageUsage.push(element);
+}
+
+return imageUsage;
+}}
+
+
+module.exports=ImageUsage;
+
+},{"../../lib/page-functions.js":68,"../driver.js":42,"./gatherer":44}],"../gather/gatherers/js-usage":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+
+
+
+class JsUsage extends Gatherer{
+
+
+
+async beforePass(passContext){
+await passContext.driver.sendCommand('Profiler.enable');
+await passContext.driver.sendCommand('Profiler.startPreciseCoverage');
+}
+
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+const coverageResponse=await driver.sendCommand('Profiler.takePreciseCoverage');
+await driver.sendCommand('Profiler.stopPreciseCoverage');
+await driver.sendCommand('Profiler.disable');
+return coverageResponse.result;
+}}
+
+
+module.exports=JsUsage;
+
+},{"./gatherer":44}],"../gather/gatherers/link-elements":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer.js');
+const getElementsInDocumentString=require('../../lib/page-functions.js').getElementsInDocumentString;
+
+class LinkElements extends Gatherer{
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+
+
+
+return driver.evaluateAsync(`(() => {
+ ${getElementsInDocumentString};
+
+ return getElementsInDocument('link').map(link => {
+ return {
+ rel: link.rel,
+ href: link.href,
+ as: link.as,
+ crossOrigin: link.crossOrigin,
+ };
+ });
+ })()`,{useIsolation:true});
+}}
+
+
+module.exports=LinkElements;
+
+},{"../../lib/page-functions.js":68,"./gatherer.js":44}],"../gather/gatherers/manifest":[function(require,module,exports){
+(function(Buffer){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+const manifestParser=require('../../lib/manifest-parser');
+const BOM_LENGTH=3;
+const BOM_FIRSTCHAR=65279;
+
+
+
+
+
+
+
+class Manifest extends Gatherer{
+
+
+
+
+
+
+
+async afterPass(passContext){
+const manifestPromise=passContext.driver.getAppManifest();
+
+const timeoutPromise=new Promise(resolve=>setTimeout(resolve,3000));
+
+const response=await Promise.race([manifestPromise,timeoutPromise]);
+if(!response){
+return null;
+}
+
+const isBomEncoded=response.data.charCodeAt(0)===BOM_FIRSTCHAR;
+if(isBomEncoded){
+response.data=Buffer.from(response.data).slice(BOM_LENGTH).toString();
+}
+
+return manifestParser(response.data,response.url,passContext.url);
+}}
+
+
+module.exports=Manifest;
+
+}).call(this,require("buffer").Buffer);
+},{"../../lib/manifest-parser":64,"./gatherer":44,"buffer":88}],"../gather/gatherers/mixed-content":[function(require,module,exports){
+(function(Buffer){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+const URL=require('../../lib/url-shim');
+
+const Driver=require('../driver.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+class MixedContent extends Gatherer{
+constructor(){
+super();
+this.ids=new Set();
+this.url=undefined;
+this._onRequestIntercepted=undefined;
+}
+
+
+
+
+
+upgradeURL(url){
+const parsedURL=new URL(url);
+parsedURL.protocol='https:';
+return parsedURL.href;
+}
+
+
+
+
+
+downgradeURL(url){
+const parsedURL=new URL(url);
+parsedURL.protocol='http:';
+return parsedURL.href;
+}
+
+
+
+
+
+_getRequestInterceptor(pageUrl,driver){
+
+const onRequestIntercepted=event=>{
+
+
+
+if(new URL(event.request.url).protocol==='http:'&&
+!URL.equalWithExcludedFragments(event.request.url,pageUrl)&&
+!this.ids.has(event.interceptionId)){
+this.ids.add(event.interceptionId);
+event.request.url=this.upgradeURL(event.request.url);
+driver.sendCommand('Network.continueInterceptedRequest',{
+interceptionId:event.interceptionId,
+rawResponse:Buffer.from(
+`HTTP/1.1 302 Found\r\nLocation: ${event.request.url}\r\n\r\n`,
+'utf8').toString('base64')});
+
+}else{
+driver.sendCommand('Network.continueInterceptedRequest',{
+interceptionId:event.interceptionId});
+
+}
+};
+
+return onRequestIntercepted;
+}
+
+
+
+
+async beforePass(passContext){
+const driver=passContext.driver;
+
+
+
+
+
+passContext.url=this.downgradeURL(passContext.url);
+this.url=passContext.url;
+this._onRequestIntercepted=this._getRequestInterceptor(this.url,driver);
+
+await driver.sendCommand('Network.enable');
+driver.on('Network.requestIntercepted',this._onRequestIntercepted);
+await driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:true});
+await driver.sendCommand('Network.setRequestInterception',{patterns:[{urlPattern:'*'}]});
+}
+
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+await driver.sendCommand('Network.setRequestInterception',{patterns:[]});
+if(this._onRequestIntercepted){
+driver.off('Network.requestIntercepted',this._onRequestIntercepted);
+}
+await driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:false});
+
+return{url:passContext.url};
+}}
+
+
+module.exports=MixedContent;
+
+}).call(this,require("buffer").Buffer);
+},{"../../lib/url-shim":"url","../driver.js":42,"./gatherer":44,"buffer":88}],"../gather/gatherers/offline":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+const URL=require('../../lib/url-shim');
+
+class Offline extends Gatherer{
+
+
+
+beforePass(passContext){
+return passContext.driver.goOffline();
+}
+
+
+
+
+
+
+afterPass(passContext,loadData){
+const navigationRecord=loadData.networkRecords.filter(record=>{
+return URL.equalWithExcludedFragments(record.url,passContext.url)&&
+record.fetchedViaServiceWorker;
+}).pop();
+
+return passContext.driver.goOnline(passContext).
+then(_=>navigationRecord?navigationRecord.statusCode:-1);
+}}
+
+
+module.exports=Offline;
+
+},{"../../lib/url-shim":"url","./gatherer":44}],"../gather/gatherers/runtime-exceptions":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+class RuntimeExceptions extends Gatherer{
+constructor(){
+super();
+
+this._exceptions=[];
+this._onRuntimeExceptionThrown=this.onRuntimeExceptionThrown.bind(this);
+}
+
+
+
+
+onRuntimeExceptionThrown(entry){
+this._exceptions.push(entry);
+}
+
+
+
+
+beforePass(passContext){
+const driver=passContext.driver;
+driver.on('Runtime.exceptionThrown',this._onRuntimeExceptionThrown);
+}
+
+
+
+
+
+async afterPass(passContext){
+await passContext.driver.off('Runtime.exceptionThrown',this._onRuntimeExceptionThrown);
+return this._exceptions;
+}}
+
+
+module.exports=RuntimeExceptions;
+
+},{"./gatherer":44}],"../gather/gatherers/scripts":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+const NetworkRequest=require('../../lib/network-request');
+
+
+
+
+class Scripts extends Gatherer{
+
+
+
+
+
+async afterPass(passContext,loadData){
+const driver=passContext.driver;
+
+
+const scriptContentMap={};
+const scriptRecords=loadData.networkRecords.
+filter(record=>record.resourceType===NetworkRequest.TYPES.Script);
+
+for(const record of scriptRecords){
+try{
+const content=await driver.getRequestContent(record.requestId);
+if(content){
+scriptContentMap[record.requestId]=content;
+}
+}catch(e){}
+}
+
+return scriptContentMap;
+}}
+
+
+module.exports=Scripts;
+
+},{"../../lib/network-request":67,"./gatherer":44}],"../gather/gatherers/seo/canonical":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+class Canonical extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+
+return driver.querySelectorAll('head link[rel="canonical" i]').
+then(nodes=>Promise.all(nodes.map(node=>node.getAttribute('href'))));
+}}
+
+
+module.exports=Canonical;
+
+
+},{"../gatherer":44}],"../gather/gatherers/seo/crawlable-links":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const pageFunctions=require('../../../lib/page-functions.js');
+
+class CrawlableLinks extends Gatherer{
+
+
+
+
+async afterPass(passContext){
+const expression=`(function() {
+ ${pageFunctions.getElementsInDocumentString}; // define function on page
+ const resolveURLOrNull = url => {
+ try { return new URL(url, window.location.href).href; }
+ catch (_) { return null; }
+ };
+
+ const selector = 'a[href]:not([rel~="nofollow"])';
+ const elements = getElementsInDocument(selector);
+ return elements
+ .map(node => ({
+ href: node.href instanceof SVGAnimatedString ?
+ resolveURLOrNull(node.href.baseVal) :
+ node.href,
+ text: node.href instanceof SVGAnimatedString ?
+ node.textContent :
+ node.innerText,
+ }));
+ })()`;
+
+
+const links=await passContext.driver.evaluateAsync(expression,{useIsolation:true});
+return links.filter(link=>typeof link.href==='string'&&link.href);
+}}
+
+
+module.exports=CrawlableLinks;
+
+
+},{"../../../lib/page-functions.js":68,"../gatherer":44}],"../gather/gatherers/seo/embedded-content":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+const pageFunctions=require('../../../lib/page-functions.js');
+
+class EmbeddedContent extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const expression=`(function() {
+ ${pageFunctions.getElementsInDocumentString}; // define function on page
+ const selector = 'object, embed, applet';
+ const elements = getElementsInDocument(selector);
+ return elements
+ .map(node => ({
+ tagName: node.tagName,
+ type: node.getAttribute('type'),
+ src: node.getAttribute('src'),
+ data: node.getAttribute('data'),
+ code: node.getAttribute('code'),
+ params: Array.from(node.children)
+ .filter(el => el.tagName === 'PARAM')
+ .map(el => ({
+ name: el.getAttribute('name') || '',
+ value: el.getAttribute('value') || '',
+ })),
+ }));
+ })()`;
+
+return passContext.driver.evaluateAsync(expression);
+}}
+
+
+module.exports=EmbeddedContent;
+
+},{"../../../lib/page-functions.js":68,"../gatherer":44}],"../gather/gatherers/seo/font-size":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+const Gatherer=require('../gatherer');
+const Sentry=require('../../../lib/sentry.js');
+const FONT_SIZE_PROPERTY_NAME='font-size';
+const TEXT_NODE_BLOCK_LIST=new Set(['SCRIPT','STYLE','NOSCRIPT']);
+const MINIMAL_LEGIBLE_FONT_SIZE_PX=12;
+
+const MAX_NODES_VISITED=500;
+const MAX_NODES_SOURCE_RULE_FETCHED=50;
+
+
+const TEXT_NODE_TYPE=3;
+
+
+
+
+
+
+
+
+
+function nodeInBody(node){
+if(!node){
+return false;
+}
+if(node.nodeName==='BODY'){
+return true;
+}
+return nodeInBody(node.parentNode);
+}
+
+
+
+
+
+
+
+async function getAllNodesFromBody(driver){
+const nodes=await driver.getNodesInDocument();
+
+const nodeMap=new Map();
+nodes.forEach(node=>nodeMap.set(node.nodeId,node));
+nodes.forEach(node=>node.parentNode=nodeMap.get(node.parentId));
+return nodes.filter(nodeInBody);
+}
+
+
+
+
+
+function hasFontSizeDeclaration(style){
+return!!style&&!!style.cssProperties.find(({name})=>name===FONT_SIZE_PROPERTY_NAME);
+}
+
+
+
+
+
+
+
+
+
+
+
+function computeSelectorSpecificity(selector){
+const tokens=selector.split(' ');
+
+let numIDs=0;
+let numClasses=0;
+let numTypes=0;
+
+for(const token of tokens){
+const ids=token.match(/\b#[a-z0-9]+/g)||[];
+const classes=token.match(/\b\.[a-z0-9]+/g)||[];
+const types=token.match(/^[a-z]+/)?[1]:[];
+numIDs+=ids.length;
+numClasses+=classes.length;
+numTypes+=types.length;
+}
+
+return Math.min(9,numIDs)*100+Math.min(9,numClasses)*10+Math.min(9,numTypes);
+}
+
+
+
+
+
+
+
+function findMostSpecificMatchedCSSRule(matchedCSSRules=[]){
+let maxSpecificity=-Infinity;
+
+let maxSpecificityRule;
+
+for(const{rule,matchingSelectors}of matchedCSSRules){
+if(hasFontSizeDeclaration(rule.style)){
+const specificities=matchingSelectors.map(idx=>
+computeSelectorSpecificity(rule.selectorList.selectors[idx].text));
+
+const specificity=Math.max(...specificities);
+
+if(specificity>=maxSpecificity){
+maxSpecificity=specificity;
+maxSpecificityRule=rule;
+}
+}
+}
+
+if(maxSpecificityRule){
+return{
+type:'Regular',
+...maxSpecificityRule.style,
+parentRule:{
+origin:maxSpecificityRule.origin,
+selectors:maxSpecificityRule.selectorList.selectors}};
+
+
+}
+}
+
+
+
+
+
+
+
+function findInheritedCSSRule(inheritedEntries=[]){
+
+
+
+
+for(const{inlineStyle,matchedCSSRules}of inheritedEntries){
+if(hasFontSizeDeclaration(inlineStyle))return{type:'Inline',...inlineStyle};
+
+const directRule=findMostSpecificMatchedCSSRule(matchedCSSRules);
+if(directRule)return directRule;
+}
+}
+
+
+
+
+
+
+
+
+
+function getEffectiveFontRule({inlineStyle,matchedCSSRules,inherited}){
+
+if(hasFontSizeDeclaration(inlineStyle))return{type:'Inline',...inlineStyle};
+
+
+const matchedRule=findMostSpecificMatchedCSSRule(matchedCSSRules);
+if(matchedRule)return matchedRule;
+
+
+const inheritedRule=findInheritedCSSRule(inherited);
+if(inheritedRule)return inheritedRule;
+
+return undefined;
+}
+
+
+
+
+
+function getNodeTextLength(node){
+return!node.nodeValue?0:node.nodeValue.trim().length;
+}
+
+
+
+
+
+
+async function fetchSourceRule(driver,node){
+const matchedRules=await driver.sendCommand('CSS.getMatchedStylesForNode',{
+nodeId:node.nodeId});
+
+const sourceRule=getEffectiveFontRule(matchedRules);
+if(!sourceRule)return undefined;
+
+return{
+type:sourceRule.type,
+range:sourceRule.range,
+styleSheetId:sourceRule.styleSheetId,
+parentRule:sourceRule.parentRule&&{
+origin:sourceRule.parentRule.origin,
+selectors:sourceRule.parentRule.selectors}};
+
+
+}
+
+
+
+
+
+
+async function fetchComputedFontSize(driver,textNode){
+try{
+const{computedStyle}=await driver.sendCommand('CSS.getComputedStyleForNode',{
+nodeId:textNode.parentId});
+
+
+const fontSizeProperty=computedStyle.find(({name})=>name===FONT_SIZE_PROPERTY_NAME);
+
+return{
+
+fontSize:parseInt(fontSizeProperty.value,10),
+textLength:getNodeTextLength(textNode),
+node:textNode.parentNode};
+
+}catch(err){
+Sentry.captureException(err,{tags:{gatherer:'FontSize'}});
+return null;
+}
+}
+
+
+
+
+
+function isNonEmptyTextNode(node){
+return(
+node.nodeType===TEXT_NODE_TYPE&&
+!TEXT_NODE_BLOCK_LIST.has(node.parentNode.nodeName)&&
+getNodeTextLength(node)>0);
+
+}
+
+class FontSize extends Gatherer{
+
+
+
+static async fetchNodesToAnalyze(driver){
+let failingTextLength=0;
+let visitedTextLength=0;
+let totalTextLength=0;
+
+const nodes=await getAllNodesFromBody(driver);
+
+const textNodes=nodes.filter(isNonEmptyTextNode);
+totalTextLength=textNodes.reduce((sum,node)=>sum+=getNodeTextLength(node),0);
+
+const nodesToVisit=textNodes.
+sort((a,b)=>getNodeTextLength(b)-getNodeTextLength(a)).
+slice(0,MAX_NODES_VISITED);
+
+const nodePromises=nodesToVisit.map(node=>fetchComputedFontSize(driver,node));
+const visitedNodes=await Promise.all(nodePromises);
+
+
+const failingNodes=[];
+for(const visitedNode of visitedNodes){
+if(!visitedNode)continue;
+visitedTextLength+=visitedNode.textLength;
+
+if(visitedNode.fontSize<MINIMAL_LEGIBLE_FONT_SIZE_PX){
+failingNodes.push(visitedNode);
+failingTextLength+=visitedNode.textLength;
+}
+}
+
+return{totalTextLength,visitedTextLength,failingTextLength,failingNodes};
+}
+
+
+
+
+
+static async fetchFailingNodeSourceRules(driver,failingNodes){
+const analysisPromises=failingNodes.
+sort((a,b)=>b.textLength-a.textLength).
+slice(0,MAX_NODES_SOURCE_RULE_FETCHED).
+map(async failingNode=>{
+failingNode.cssRule=await fetchSourceRule(driver,failingNode.node);
+return failingNode;
+});
+
+const analyzedFailingNodesData=await Promise.all(analysisPromises);
+
+const analyzedFailingTextLength=analyzedFailingNodesData.reduce(
+(sum,{textLength})=>sum+=textLength,
+0);
+
+
+return{analyzedFailingNodesData,analyzedFailingTextLength};
+}
+
+
+
+
+
+async afterPass(passContext){
+
+const stylesheets=new Map();
+
+const onStylesheetAdd=sheet=>stylesheets.set(sheet.header.styleSheetId,sheet.header);
+passContext.driver.on('CSS.styleSheetAdded',onStylesheetAdd);
+
+await Promise.all([
+passContext.driver.sendCommand('DOM.enable'),
+passContext.driver.sendCommand('CSS.enable')]);
+
+
+const{
+totalTextLength,
+visitedTextLength,
+failingTextLength,
+failingNodes}=
+await FontSize.fetchNodesToAnalyze(passContext.driver);
+
+const{
+analyzedFailingNodesData,
+analyzedFailingTextLength}=
+await FontSize.fetchFailingNodeSourceRules(passContext.driver,failingNodes);
+
+passContext.driver.off('CSS.styleSheetAdded',onStylesheetAdd);
+
+analyzedFailingNodesData.
+filter(data=>data.cssRule&&data.cssRule.styleSheetId).
+
+forEach(data=>data.cssRule.stylesheet=stylesheets.get(data.cssRule.styleSheetId));
+
+await Promise.all([
+passContext.driver.sendCommand('DOM.disable'),
+passContext.driver.sendCommand('CSS.disable')]);
+
+
+return{
+analyzedFailingNodesData,
+analyzedFailingTextLength,
+failingTextLength,
+visitedTextLength,
+totalTextLength};
+
+}}
+
+
+module.exports=FontSize;
+module.exports.TEXT_NODE_TYPE=TEXT_NODE_TYPE;
+module.exports.computeSelectorSpecificity=computeSelectorSpecificity;
+module.exports.getEffectiveFontRule=getEffectiveFontRule;
+
+},{"../../../lib/sentry.js":69,"../gatherer":44}],"../gather/gatherers/seo/hreflang":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+class Hreflang extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+
+return driver.querySelectorAll('head link[rel="alternate" i][hreflang]').
+then(nodes=>Promise.all(nodes.map(node=>
+Promise.all([node.getAttribute('href'),node.getAttribute('hreflang')])))).
+
+then(attributeValues=>attributeValues&&
+attributeValues.map(values=>{
+const[href,hreflang]=values;
+return{
+href:href||'',
+hreflang:hreflang||''};
+
+}));
+
+}}
+
+
+module.exports=Hreflang;
+
+
+},{"../gatherer":44}],"../gather/gatherers/seo/meta-description":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+class MetaDescription extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+
+return driver.querySelector('head meta[name="description" i]').
+then(node=>node&&node.getAttribute('content'));
+}}
+
+
+module.exports=MetaDescription;
+
+
+},{"../gatherer":44}],"../gather/gatherers/seo/meta-robots":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+class MetaRobots extends Gatherer{
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+
+return driver.querySelector('head meta[name="robots" i]').
+then(node=>node&&node.getAttribute('content'));
+}}
+
+
+module.exports=MetaRobots;
+
+},{"../gatherer":44}],"../gather/gatherers/seo/robots-txt":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+
+
+
+
+async function getRobotsTxtContent(){
+try{
+const response=await fetch(new URL('/robots.txt',location.href).href);
+if(!response.ok){
+return{status:response.status,content:null};
+}
+
+const content=await response.text();
+return{status:response.status,content};
+}catch(_){
+return{status:null,content:null};
+}
+}
+
+
+class RobotsTxt extends Gatherer{
+
+
+
+
+afterPass(passContext){
+return passContext.driver.evaluateAsync(`(${getRobotsTxtContent.toString()}())`);
+}}
+
+
+module.exports=RobotsTxt;
+
+},{"../gatherer":44}],"../gather/gatherers/service-worker":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+class ServiceWorker extends Gatherer{
+
+
+
+
+async beforePass(passContext){
+const{versions}=await passContext.driver.getServiceWorkerVersions();
+const{registrations}=await passContext.driver.getServiceWorkerRegistrations();
+
+return{
+versions,
+registrations};
+
+}}
+
+
+module.exports=ServiceWorker;
+
+},{"./gatherer":44}],"../gather/gatherers/start-url":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+const manifestParser=require('../../lib/manifest-parser');
+
+
+
+class StartUrl extends Gatherer{
+
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
+return driver.goOnline(passContext).
+then(()=>driver.getAppManifest()).
+then(response=>driver.goOffline().then(()=>response)).
+then(response=>response&&manifestParser(response.data,response.url,passContext.url)).
+then(manifest=>{
+const startUrlInfo=this._readManifestStartUrl(manifest);
+if(startUrlInfo.isReadFailure){
+return{statusCode:-1,explanation:startUrlInfo.reason};
+}
+
+return this._attemptManifestFetch(passContext.driver,startUrlInfo.startUrl);
+}).catch(()=>{
+return{statusCode:-1,explanation:'Unable to fetch start URL via service worker.'};
+});
+}
+
+
+
+
+
+
+_readManifestStartUrl(manifest){
+if(!manifest||!manifest.value){
+const detailedMsg=manifest&&manifest.warning;
+
+if(detailedMsg){
+return{isReadFailure:true,reason:`Error fetching web app manifest: ${detailedMsg}.`};
+}else{
+return{isReadFailure:true,reason:`No usable web app manifest found on page.`};
+}
+}
+
+
+return{isReadFailure:false,startUrl:manifest.value.start_url.value};
+}
+
+
+
+
+
+
+
+
+_attemptManifestFetch(driver,startUrl){
+
+const timeoutPromise=new Promise(resolve=>
+setTimeout(
+()=>resolve({statusCode:-1,explanation:'Timed out waiting for fetched start_url.'}),
+3000));
+
+
+
+const fetchPromise=new Promise(resolve=>{
+driver.on('Network.responseReceived',onResponseReceived);
+
+
+function onResponseReceived(responseEvent){
+const{response}=responseEvent;
+
+if(response.url!==startUrl)return;
+driver.off('Network.responseReceived',onResponseReceived);
+
+if(!response.fromServiceWorker){
+return resolve({
+statusCode:-1,
+explanation:'Unable to fetch start URL via service worker.'});
+
+}
+
+return resolve({statusCode:response.status});
+}
+});
+
+return driver.
+evaluateAsync(`window.location = '${startUrl}'`).
+then(()=>Promise.race([fetchPromise,timeoutPromise]));
+}}
+
+
+module.exports=StartUrl;
+
+},{"../../lib/manifest-parser":64,"./gatherer":44}],"../gather/gatherers/theme-color":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+class ThemeColor extends Gatherer{
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+const metaEl=await driver.querySelector('head meta[name="theme-color" i]');
+return metaEl&&metaEl.getAttribute('content');
+}}
+
+
+module.exports=ThemeColor;
+
+},{"./gatherer":44}],"../gather/gatherers/viewport-dimensions":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+
+
+
+
+
+
+function getViewportDimensions(){
+
+
+
+return Promise.resolve({
+innerWidth:window.innerWidth,
+innerHeight:window.innerHeight,
+outerWidth:window.outerWidth,
+outerHeight:window.outerHeight,
+devicePixelRatio:window.devicePixelRatio});
+
+}
+
+class ViewportDimensions extends Gatherer{
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+
+const dimensions=await driver.evaluateAsync(`(${getViewportDimensions.toString()}())`,
+{useIsolation:true});
+
+const allNumeric=Object.values(dimensions).every(Number.isFinite);
+if(!allNumeric){
+const results=JSON.stringify(dimensions);
+throw new Error(`ViewportDimensions results were not numeric: ${results}`);
+}
+
+return dimensions;
+}}
+
+
+module.exports=ViewportDimensions;
+
+},{"./gatherer":44}],"../gather/gatherers/viewport":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('./gatherer');
+
+class Viewport extends Gatherer{
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
+const metaEl=await driver.querySelector('head meta[name="viewport" i]');
+return metaEl&&metaEl.getAttribute('content');
+}}
+
+
+module.exports=Viewport;
+
+},{"./gatherer":44}],1:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const lighthouse=require('../lighthouse-core/index.js');
+const RawProtocol=require('../lighthouse-core/gather/connections/raw.js');
+const log=require('lighthouse-logger');
+
+
+
+
+
+
+
+
+
+function getDefaultConfigForCategories(categoryIDs){
+return{
+extends:'lighthouse:default',
+settings:{
+onlyCategories:categoryIDs}};
+
+
+}
+
+
+
+
+
+
+
+
+function runLighthouseInWorker(port,url,flags,categoryIDs){
+
+flags.logLevel=flags.logLevel||'info';
+const config=getDefaultConfigForCategories(categoryIDs);
+const connection=new RawProtocol(port);
+
+return lighthouse(url,flags,config,connection);
+}
+
+
+function listenForStatus(listenCallback){
+log.events.addListener('status',listenCallback);
+}
+
+if(typeof module!=='undefined'&&module.exports){
+
+module.exports={
+runLighthouseInWorker,
+listenForStatus};
+
+}
+
+
+
+if(typeof self!=='undefined'){
+
+self.runLighthouseInWorker=runLighthouseInWorker;
+
+self.listenForStatus=listenForStatus;
+}
+
+},{"../lighthouse-core/gather/connections/raw.js":40,"../lighthouse-core/index.js":45,"lighthouse-logger":113}],2:[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const Audit=require('../audit');
+const i18n=require('../../lib/i18n/i18n.js');
+
+const UIStrings={
+
+failingElementsHeader:'Failing Elements'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+class AxeAudit extends Audit{
+
+
+
+
+
+static audit(artifacts){
+
+
+
+const notApplicables=artifacts.Accessibility.notApplicable||[];
+const isNotApplicable=notApplicables.find(result=>result.id===this.meta.id);
+if(isNotApplicable){
+return{
+rawValue:true,
+notApplicable:true};
+
+}
+
+const violations=artifacts.Accessibility.violations||[];
+const rule=violations.find(result=>result.id===this.meta.id);
+const impact=rule&&rule.impact;
+const tags=rule&&rule.tags;
+
+
+let items=[];
+if(rule&&rule.nodes){
+items=rule.nodes.map(node=>({
+node:{
+type:'node',
+selector:Array.isArray(node.target)?node.target.join(' '):'',
+path:node.path,
+snippet:node.html||node.snippet,
+explanation:node.failureSummary}}));
+
+
+}
+
+const headings=[
+{key:'node',itemType:'node',text:str_(UIStrings.failingElementsHeader)}];
+
+
+return{
+rawValue:typeof rule==='undefined',
+extendedInfo:{
+value:rule},
+
+details:{...Audit.makeTableDetails(headings,items),impact,tags}};
+
+}}
+
+
+module.exports=AxeAudit;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/audits/accessibility/axe-audit.js");
+},{"../../lib/i18n/i18n.js":59,"../audit":3}],3:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const statistics=require('../lib/statistics');
+const Util=require('../report/html/renderer/util');
+
+const DEFAULT_PASS='defaultPass';
+
+
+
+
+
+
+const clampTo2Decimals=val=>Math.round(val*100)/100;
+
+class Audit{
+
+
+
+static get DEFAULT_PASS(){
+return DEFAULT_PASS;
+}
+
+
+
+
+static get SCORING_MODES(){
+return{
+NUMERIC:'numeric',
+BINARY:'binary',
+MANUAL:'manual',
+INFORMATIVE:'informative',
+NOT_APPLICABLE:'notApplicable',
+ERROR:'error'};
+
+}
+
+
+
+
+static get meta(){
+throw new Error('Audit meta information must be overridden.');
+}
+
+
+
+
+static get defaultOptions(){
+return{};
+}
+
+
+
+
+
+
+
+
+
+static audit(artifacts,context){
+throw new Error('audit() method must be overriden');
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+static computeLogNormalScore(measuredValue,diminishingReturnsValue,medianValue){
+const distribution=statistics.getLogNormalDistribution(
+medianValue,
+diminishingReturnsValue);
+
+
+let score=distribution.computeComplementaryPercentile(measuredValue);
+score=Math.min(1,score);
+score=Math.max(0,score);
+return clampTo2Decimals(score);
+}
+
+
+
+
+
+
+static generateErrorAuditResult(audit,errorMessage){
+return Audit.generateAuditResult(audit,{
+rawValue:null,
+errorMessage});
+
+}
+
+
+
+
+
+
+
+static makeTableDetails(headings,results,summary){
+if(results.length===0){
+return{
+type:'table',
+headings:[],
+items:[],
+summary};
+
+}
+
+return{
+type:'table',
+headings:headings,
+items:results,
+summary};
+
+}
+
+
+
+
+
+
+
+
+static makeOpportunityDetails(headings,items,overallSavingsMs,overallSavingsBytes){
+return{
+type:'opportunity',
+headings:items.length===0?[]:headings,
+items,
+overallSavingsMs,
+overallSavingsBytes};
+
+}
+
+
+
+
+
+
+static _normalizeAuditScore(audit,result){
+
+let score=result.score===undefined?Number(result.rawValue):result.score;
+
+if(!Number.isFinite(score))throw new Error(`Invalid score: ${score}`);
+if(score>1)throw new Error(`Audit score for ${audit.meta.id} is > 1`);
+if(score<0)throw new Error(`Audit score for ${audit.meta.id} is < 0`);
+
+score=clampTo2Decimals(score);
+
+const scoreDisplayMode=audit.meta.scoreDisplayMode||Audit.SCORING_MODES.BINARY;
+
+return{
+score,
+scoreDisplayMode};
+
+}
+
+
+
+
+
+
+static generateAuditResult(audit,result){
+if(typeof result.rawValue==='undefined'){
+throw new Error('generateAuditResult requires a rawValue');
+}
+
+
+let{score,scoreDisplayMode}=Audit._normalizeAuditScore(audit,result);
+
+
+if(result.notApplicable){
+scoreDisplayMode=Audit.SCORING_MODES.NOT_APPLICABLE;
+result.rawValue=true;
+}
+
+if(result.errorMessage){
+scoreDisplayMode=Audit.SCORING_MODES.ERROR;
+}
+
+let auditTitle=audit.meta.title;
+if(audit.meta.failureTitle){
+if(Number(score)<Util.PASS_THRESHOLD){
+auditTitle=audit.meta.failureTitle;
+}
+}
+
+if(scoreDisplayMode!==Audit.SCORING_MODES.BINARY&&
+scoreDisplayMode!==Audit.SCORING_MODES.NUMERIC){
+score=null;
+}
+
+return{
+id:audit.meta.id,
+title:auditTitle,
+description:audit.meta.description,
+
+score,
+scoreDisplayMode,
+rawValue:result.rawValue,
+
+displayValue:result.displayValue,
+explanation:result.explanation,
+errorMessage:result.errorMessage,
+warnings:result.warnings,
+
+details:result.details};
+
+}}
+
+
+module.exports=Audit;
+
+},{"../lib/statistics":70,"../report/html/renderer/util":74}],4:[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const linearInterpolation=require('../../lib/statistics').linearInterpolation;
+const Interactive=require('../../computed/metrics/lantern-interactive.js');
+const i18n=require('../../lib/i18n/i18n.js');
+const NetworkRecords=require('../../computed/network-records.js');
+const LoadSimulator=require('../../computed/load-simulator.js');
+const PageDependencyGraph=require('../../computed/page-dependency-graph.js');
+
+const str_=i18n.createMessageInstanceIdFn(__filename,{});
+
+
+
+
+const KB_IN_BYTES=1024;
+
+const WASTED_MS_FOR_AVERAGE=300;
+const WASTED_MS_FOR_POOR=750;
+const WASTED_MS_FOR_SCORE_OF_ZERO=5000;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class UnusedBytes extends Audit{
+
+
+
+
+
+
+static scoreForWastedMs(wastedMs){
+if(wastedMs===0){
+return 1;
+}else if(wastedMs<WASTED_MS_FOR_AVERAGE){
+return linearInterpolation(0,1,WASTED_MS_FOR_AVERAGE,0.75,wastedMs);
+}else if(wastedMs<WASTED_MS_FOR_POOR){
+return linearInterpolation(WASTED_MS_FOR_AVERAGE,0.75,WASTED_MS_FOR_POOR,0.5,wastedMs);
+}else{
+return Math.max(
+0,
+linearInterpolation(WASTED_MS_FOR_POOR,0.5,WASTED_MS_FOR_SCORE_OF_ZERO,0,wastedMs));
+
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+static estimateTransferSize(networkRecord,totalBytes,resourceType,compressionRatio=0.5){
+if(!networkRecord){
+
+
+
+return Math.round(totalBytes*compressionRatio);
+}else if(networkRecord.resourceType===resourceType){
+
+return networkRecord.transferSize||0;
+}else{
+
+
+const transferSize=networkRecord.transferSize||0;
+const resourceSize=networkRecord.resourceSize;
+const compressionRatio=resourceSize!==undefined?transferSize/resourceSize:1;
+return Math.round(totalBytes*compressionRatio);
+}
+}
+
+
+
+
+
+
+static audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const settings=context&&context.settings||{};
+const simulatorOptions={
+devtoolsLog,
+settings};
+
+
+return NetworkRecords.request(devtoolsLog,context).
+then(networkRecords=>
+Promise.all([
+this.audit_(artifacts,networkRecords,context),
+PageDependencyGraph.request({trace,devtoolsLog},context),
+LoadSimulator.request(simulatorOptions,context)])).
+
+
+then(([result,graph,simulator])=>this.createAuditProduct(result,graph,simulator));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+static computeWasteWithTTIGraph(results,graph,simulator,options){
+options=Object.assign({includeLoad:true,label:this.meta.id},options);
+const beforeLabel=`${options.label}-before`;
+const afterLabel=`${options.label}-after`;
+
+const simulationBeforeChanges=simulator.simulate(graph,{label:beforeLabel});
+
+const resultsByUrl=new Map();
+for(const result of results){
+resultsByUrl.set(result.url,result);
+}
+
+
+
+const originalTransferSizes=new Map();
+graph.traverse(node=>{
+if(node.type!=='network')return;
+const result=resultsByUrl.get(node.record.url);
+if(!result)return;
+
+const original=node.record.transferSize;
+originalTransferSizes.set(node.record.requestId,original);
+
+const wastedBytes=result.wastedBytes;
+node.record.transferSize=Math.max(original-wastedBytes,0);
+});
+
+const simulationAfterChanges=simulator.simulate(graph,{label:afterLabel});
+
+
+graph.traverse(node=>{
+if(node.type!=='network')return;
+const originalTransferSize=originalTransferSizes.get(node.record.requestId);
+if(originalTransferSize===undefined)return;
+node.record.transferSize=originalTransferSize;
+});
+
+const savingsOnOverallLoad=simulationBeforeChanges.timeInMs-simulationAfterChanges.timeInMs;
+const savingsOnTTI=Interactive.getLastLongTaskEndTime(simulationBeforeChanges.nodeTimings)-
+Interactive.getLastLongTaskEndTime(simulationAfterChanges.nodeTimings);
+
+let savings=savingsOnTTI;
+if(options.includeLoad)savings=Math.max(savings,savingsOnOverallLoad);
+
+
+return Math.round(Math.max(savings,0)/10)*10;
+}
+
+
+
+
+
+
+
+static createAuditProduct(result,graph,simulator){
+const results=result.items.sort((itemA,itemB)=>itemB.wastedBytes-itemA.wastedBytes);
+
+const wastedBytes=results.reduce((sum,item)=>sum+item.wastedBytes,0);
+const wastedKb=Math.round(wastedBytes/KB_IN_BYTES);
+const wastedMs=this.computeWasteWithTTIGraph(results,graph,simulator);
+
+
+let displayValue=result.displayValue||'';
+if(typeof result.displayValue==='undefined'&&wastedBytes){
+displayValue=str_(i18n.UIStrings.displayValueByteSavings,{wastedBytes});
+}
+
+const details=Audit.makeOpportunityDetails(result.headings,results,wastedMs,wastedBytes);
+
+return{
+explanation:result.explanation,
+warnings:result.warnings,
+displayValue,
+rawValue:wastedMs,
+score:UnusedBytes.scoreForWastedMs(wastedMs),
+extendedInfo:{
+value:{
+wastedMs,
+wastedKb,
+results}},
+
+
+details};
+
+}
+
+
+
+
+
+
+
+
+
+static audit_(artifacts,networkRecords,context){
+throw new Error('audit_ unimplemented');
+}}
+
+
+
+
+module.exports=UnusedBytes;
+
+}).call(this,"/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js");
+},{"../../computed/load-simulator.js":10,"../../computed/metrics/lantern-interactive.js":23,"../../computed/network-records.js":29,"../../computed/page-dependency-graph.js":30,"../../lib/i18n/i18n.js":59,"../../lib/statistics":70,"../audit":3}],5:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const Audit=require('../audit');
+
+class ManualAudit extends Audit{
+
+
+
+static get partialMeta(){
+return{
+scoreDisplayMode:Audit.SCORING_MODES.MANUAL,
+requiredArtifacts:[]};
+
+}
+
+
+
+
+static audit(){
+return{
+rawValue:false};
+
+
+}}
+
+
+module.exports=ManualAudit;
+
+},{"../audit":3}],6:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+const Audit=require('./audit');
+
+class MultiCheckAudit extends Audit{
+
+
+
+
+
+static async audit(artifacts,context){
+const multiProduct=await this.audit_(artifacts,context);
+return this.createAuditProduct(multiProduct);
+}
+
+
+
+
+
+static createAuditProduct(result){
+
+const detailsItem={
+...result,
+...result.manifestValues,
+manifestValues:undefined,
+allChecks:undefined};
+
+
+if(result.manifestValues&&result.manifestValues.allChecks){
+result.manifestValues.allChecks.forEach(check=>{
+detailsItem[check.id]=check.passing;
+});
+}
+
+const details={items:[detailsItem]};
+
+
+if(result.failures.length>0){
+return{
+rawValue:false,
+explanation:`Failures: ${result.failures.join(',\n')}.`,
+details};
+
+}
+
+
+return{
+rawValue:true,
+details};
+
+}
+
+
+
+
+
+
+
+
+static audit_(artifacts,context){
+throw new Error('audit_ unimplemented');
+}}
+
+
+
+
+module.exports=MultiCheckAudit;
+
+},{"./audit":3}],7:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+
+class ViolationAudit extends Audit{
+
+
+
+
+
+static getViolationResults(artifacts,pattern){
+const seen=new Set();
+return artifacts.ChromeConsoleMessages.
+map(message=>message.entry).
+filter(entry=>entry.url&&entry.source==='violation'&&pattern.test(entry.text)).
+map(entry=>({label:`line: ${entry.lineNumber}`,url:entry.url})).
+filter(entry=>{
+
+
+const key=`${entry.url}!${entry.label}`;
+if(seen.has(key))return false;
+seen.add(key);
+return true;
+});
+}}
+
+
+module.exports=ViolationAudit;
+
+},{"./audit":3}],8:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ArbitraryEqualityMap=require('../lib/arbitrary-equality-map.js');
+const log=require('lighthouse-logger');
+
+
+
+
+
+
+
+function makeComputedArtifact(computableArtifact){
+
+
+
+
+
+
+
+
+
+const request=(artifacts,context)=>{
+const computedCache=context.computedCache;
+const computedName=computableArtifact.name;
+
+const cache=computedCache.get(computedName)||new ArbitraryEqualityMap();
+computedCache.set(computedName,cache);
+
+const computed=cache.get(artifacts);
+if(computed){
+return computed;
+}
+
+const status={msg:`Computing artifact: ${computedName}`,id:`lh:computed:${computedName}`};
+log.time(status,'verbose');
+
+const artifactPromise=
+computableArtifact.compute_(artifacts,context);
+cache.set(artifacts,artifactPromise);
+
+artifactPromise.then(()=>log.timeEnd(status)).catch(()=>log.timeEnd(status));
+
+return artifactPromise;
+};
+
+return Object.assign(computableArtifact,{request});
+}
+
+module.exports=makeComputedArtifact;
+
+},{"../lib/arbitrary-equality-map.js":46,"lighthouse-logger":113}],9:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const NetworkRequest=require('../lib/network-request.js');
+const assert=require('assert');
+const NetworkRecords=require('./network-records.js');
+const MainResource=require('./main-resource.js');
+
+class CriticalRequestChains{
+
+
+
+
+
+
+
+
+static isCritical(request,mainResource){
+assert.ok(mainResource,'mainResource not provided');
+
+
+if(request.isLinkPreload){
+return false;
+}
+
+
+const isIframe=request.resourceType===NetworkRequest.TYPES.Document&&
+request.frameId!==mainResource.frameId;
+
+
+
+
+const nonCriticalResourceTypes=[
+NetworkRequest.TYPES.Image,
+NetworkRequest.TYPES.XHR,
+NetworkRequest.TYPES.Fetch,
+NetworkRequest.TYPES.EventSource];
+
+if(nonCriticalResourceTypes.includes(request.resourceType||'Other')||
+isIframe||
+request.mimeType&&request.mimeType.startsWith('image/')){
+return false;
+}
+
+return['VeryHigh','High','Medium'].includes(request.priority);
+}
+
+
+
+
+
+
+static extractChain(networkRecords,mainResource){
+networkRecords=networkRecords.filter(req=>req.finished);
+
+
+
+const requestIdToRequests=new Map();
+for(const request of networkRecords){
+requestIdToRequests.set(request.requestId,request);
+}
+
+
+
+const criticalRequests=networkRecords.filter(request=>
+CriticalRequestChains.isCritical(request,mainResource));
+
+
+
+const criticalRequestChains={};
+for(const request of criticalRequests){
+
+
+
+
+const ancestors=[];
+let ancestorRequest=request.initiatorRequest;
+
+let node=criticalRequestChains;
+while(ancestorRequest){
+const ancestorIsCritical=CriticalRequestChains.isCritical(ancestorRequest,mainResource);
+
+
+
+
+
+if(!ancestorIsCritical||ancestors.includes(ancestorRequest.requestId)){
+
+
+ancestors.length=0;
+node=undefined;
+break;
+}
+ancestors.push(ancestorRequest.requestId);
+ancestorRequest=ancestorRequest.initiatorRequest;
+}
+
+
+
+let ancestor=ancestors.pop();
+while(ancestor&&node){
+const parentRequest=requestIdToRequests.get(ancestor);
+if(!parentRequest){
+throw new Error(`request with id ${ancestor} not found.`);
+}
+
+const parentRequestId=parentRequest.requestId;
+if(!node[parentRequestId]){
+node[parentRequestId]={
+request:parentRequest,
+children:{}};
+
+}
+
+
+ancestor=ancestors.pop();
+node=node[parentRequestId].children;
+}
+
+if(!node){
+continue;
+}
+
+
+if(node[request.requestId]){
+continue;
+}
+
+
+node[request.requestId]={
+request,
+children:{}};
+
+}
+
+return criticalRequestChains;
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const[networkRecords,mainResource]=await Promise.all([
+NetworkRecords.request(data.devtoolsLog,context),
+MainResource.request(data,context)]);
+
+
+return CriticalRequestChains.extractChain(networkRecords,mainResource);
+}}
+
+
+module.exports=makeComputedArtifact(CriticalRequestChains);
+
+},{"../lib/network-request.js":67,"./computed-artifact.js":8,"./main-resource.js":11,"./network-records.js":29,"assert":78}],10:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const constants=require('../config/constants.js');
+const Simulator=require('../lib/dependency-graph/simulator/simulator.js');
+const NetworkAnalysis=require('./network-analysis.js');
+
+class LoadSimulator{
+
+
+
+
+
+static async compute_(data,context){
+const{throttlingMethod,throttling}=data.settings;
+const networkAnalysis=await NetworkAnalysis.request(data.devtoolsLog,context);
+
+
+const options={
+additionalRttByOrigin:networkAnalysis.additionalRttByOrigin,
+serverResponseTimeByOrigin:networkAnalysis.serverResponseTimeByOrigin};
+
+
+switch(throttlingMethod){
+case'provided':
+options.rtt=networkAnalysis.rtt;
+options.throughput=networkAnalysis.throughput;
+options.cpuSlowdownMultiplier=1;
+options.layoutTaskMultiplier=1;
+break;
+case'devtools':
+if(throttling){
+options.rtt=
+throttling.requestLatencyMs/constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR;
+options.throughput=
+throttling.downloadThroughputKbps*1024/
+constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR;
+}
+
+options.cpuSlowdownMultiplier=1;
+options.layoutTaskMultiplier=1;
+break;
+case'simulate':
+if(throttling){
+options.rtt=throttling.rttMs;
+options.throughput=throttling.throughputKbps*1024;
+options.cpuSlowdownMultiplier=throttling.cpuSlowdownMultiplier;
+}
+break;
+default:
+
+break;}
+
+
+return new Simulator(options);
+}}
+
+
+module.exports=makeComputedArtifact(LoadSimulator);
+
+},{"../config/constants.js":36,"../lib/dependency-graph/simulator/simulator.js":54,"./computed-artifact.js":8,"./network-analysis.js":28}],11:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const URL=require('../lib/url-shim.js');
+const NetworkRecords=require('./network-records.js');
+
+
+
+
+
+class MainResource{
+
+
+
+
+
+static async compute_(data,context){
+const finalUrl=data.URL.finalUrl;
+const requests=await NetworkRecords.request(data.devtoolsLog,context);
+
+const mainResource=requests.find(request=>finalUrl.startsWith(request.url)&&
+URL.equalWithExcludedFragments(request.url,finalUrl));
+
+if(!mainResource){
+throw new Error('Unable to identify the main resource');
+}
+
+return mainResource;
+}}
+
+
+module.exports=makeComputedArtifact(MainResource);
+
+},{"../lib/url-shim.js":"url","./computed-artifact.js":8,"./network-records.js":29}],12:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const{taskGroups,taskNameToGroup}=require('../lib/task-groups.js');
+const TraceOfTab=require('./trace-of-tab.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class MainThreadTasks{
+
+
+
+
+
+static _createNewTaskNode(event,parent){
+const newTask={
+event,
+startTime:event.ts,
+endTime:event.ph==='X'?event.ts+Number(event.dur||0):NaN,
+parent:parent,
+children:[],
+
+
+attributableURLs:[],
+group:taskGroups.other,
+duration:NaN,
+selfTime:NaN};
+
+
+if(parent){
+parent.children.push(newTask);
+}
+
+return newTask;
+}
+
+
+
+
+
+static _createTasksFromEvents(mainThreadEvents){
+
+const tasks=[];
+
+let currentTask;
+
+for(const event of mainThreadEvents){
+
+if(event.ph!=='X'&&event.ph!=='B'&&event.ph!=='E')continue;
+
+
+
+while(
+currentTask&&
+Number.isFinite(currentTask.endTime)&&
+currentTask.endTime<=event.ts)
+{
+currentTask=currentTask.parent;
+}
+
+
+if(!currentTask){
+
+if(event.ph==='E'){
+throw new Error('Fatal trace logic error');
+}
+
+currentTask=MainThreadTasks._createNewTaskNode(event);
+tasks.push(currentTask);
+
+continue;
+}
+
+if(event.ph==='X'||event.ph==='B'){
+
+const newTask=MainThreadTasks._createNewTaskNode(event,currentTask);
+tasks.push(newTask);
+currentTask=newTask;
+}else{
+if(currentTask.event.ph!=='B'){
+throw new Error('Fatal trace logic error');
+}
+
+
+currentTask.endTime=event.ts;
+currentTask=currentTask.parent;
+}
+}
+
+return tasks;
+}
+
+
+
+
+
+static _computeRecursiveSelfTime(task){
+const childTime=task.children.
+map(MainThreadTasks._computeRecursiveSelfTime).
+reduce((sum,child)=>sum+child,0);
+task.duration=task.endTime-task.startTime;
+task.selfTime=task.duration-childTime;
+return task.duration;
+}
+
+
+
+
+
+static _computeRecursiveAttributableURLs(task,parentURLs){
+const argsData=task.event.args.data||{};
+const stackFrameURLs=(argsData.stackTrace||[]).map(entry=>entry.url);
+
+let taskURLs=[];
+switch(task.event.name){
+
+
+
+
+
+case'v8.compile':
+case'EvaluateScript':
+case'FunctionCall':
+taskURLs=[argsData.url].concat(stackFrameURLs);
+break;
+case'v8.compileModule':
+taskURLs=[task.event.args.fileName].concat(stackFrameURLs);
+break;
+default:
+taskURLs=stackFrameURLs;
+break;}
+
+
+
+const attributableURLs=Array.from(parentURLs);
+for(const url of taskURLs){
+
+if(!url)continue;
+
+if(attributableURLs[attributableURLs.length-1]===url)continue;
+attributableURLs.push(url);
+}
+
+task.attributableURLs=attributableURLs;
+task.children.forEach(child=>
+MainThreadTasks._computeRecursiveAttributableURLs(child,attributableURLs));
+}
+
+
+
+
+
+static _computeRecursiveTaskGroup(task,parentGroup){
+const group=taskNameToGroup[task.event.name];
+task.group=group||parentGroup||taskGroups.other;
+task.children.forEach(child=>MainThreadTasks._computeRecursiveTaskGroup(child,task.group));
+}
+
+
+
+
+
+static getMainThreadTasks(traceEvents){
+const tasks=MainThreadTasks._createTasksFromEvents(traceEvents);
+
+
+for(const task of tasks){
+if(task.parent)continue;
+
+MainThreadTasks._computeRecursiveSelfTime(task);
+MainThreadTasks._computeRecursiveAttributableURLs(task,[]);
+MainThreadTasks._computeRecursiveTaskGroup(task);
+}
+
+
+const firstTs=(tasks[0]||{startTime:0}).startTime;
+for(const task of tasks){
+task.startTime=(task.startTime-firstTs)/1000;
+task.endTime=(task.endTime-firstTs)/1000;
+task.duration/=1000;
+task.selfTime/=1000;
+
+
+if(!Number.isFinite(task.selfTime)){
+throw new Error('Invalid task timing data');
+}
+}
+
+return tasks;
+}
+
+
+
+
+
+
+static async compute_(trace,context){
+const{mainThreadEvents}=await TraceOfTab.request(trace,context);
+return MainThreadTasks.getMainThreadTasks(mainThreadEvents);
+}}
+
+
+module.exports=makeComputedArtifact(MainThreadTasks);
+
+},{"../lib/task-groups.js":71,"./computed-artifact.js":8,"./trace-of-tab.js":33}],13:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const icons=require('../lib/icons.js');
+
+const PWA_DISPLAY_VALUES=['minimal-ui','fullscreen','standalone'];
+
+
+
+const SUGGESTED_SHORTNAME_LENGTH=12;
+
+class ManifestValues{
+
+
+
+
+
+static get manifestChecks(){
+return[
+{
+id:'hasStartUrl',
+failureText:'Manifest does not contain a `start_url`',
+validate:manifestValue=>!!manifestValue.start_url.value},
+
+{
+id:'hasIconsAtLeast192px',
+failureText:'Manifest does not have a PNG icon of at least 192px',
+validate:manifestValue=>icons.doExist(manifestValue)&&
+icons.pngSizedAtLeast(192,manifestValue).length>0},
+
+{
+id:'hasIconsAtLeast512px',
+failureText:'Manifest does not have a PNG icon of at least 512px',
+validate:manifestValue=>icons.doExist(manifestValue)&&
+icons.pngSizedAtLeast(512,manifestValue).length>0},
+
+{
+id:'hasPWADisplayValue',
+failureText:'Manifest\'s `display` value is not one of: '+PWA_DISPLAY_VALUES.join(' | '),
+validate:manifestValue=>PWA_DISPLAY_VALUES.includes(manifestValue.display.value)},
+
+{
+id:'hasBackgroundColor',
+failureText:'Manifest does not have `background_color`',
+validate:manifestValue=>!!manifestValue.background_color.value},
+
+{
+id:'hasThemeColor',
+failureText:'Manifest does not have `theme_color`',
+validate:manifestValue=>!!manifestValue.theme_color.value},
+
+{
+id:'hasShortName',
+failureText:'Manifest does not have `short_name`',
+validate:manifestValue=>!!manifestValue.short_name.value},
+
+{
+id:'shortNameLength',
+failureText:`Manifest's \`short_name\` is too long (>${SUGGESTED_SHORTNAME_LENGTH} `+
+`characters) to be displayed on a homescreen without truncation`,
+
+validate:manifestValue=>!!manifestValue.short_name.value&&
+manifestValue.short_name.value.length<=SUGGESTED_SHORTNAME_LENGTH},
+
+{
+id:'hasName',
+failureText:'Manifest does not have `name`',
+validate:manifestValue=>!!manifestValue.name.value}];
+
+
+}
+
+
+
+
+
+
+static async compute_(manifest){
+
+if(manifest===null){
+return{
+isParseFailure:true,
+parseFailureReason:'No manifest was fetched',
+allChecks:[]};
+
+}
+const manifestValue=manifest.value;
+if(manifestValue===undefined){
+return{
+isParseFailure:true,
+parseFailureReason:'Manifest failed to parse as valid JSON',
+allChecks:[]};
+
+}
+
+
+const remainingChecks=ManifestValues.manifestChecks.map(item=>{
+return{
+id:item.id,
+failureText:item.failureText,
+passing:item.validate(manifestValue)};
+
+});
+
+return{
+isParseFailure:false,
+allChecks:remainingChecks};
+
+}}
+
+
+module.exports=makeComputedArtifact(ManifestValues);
+
+},{"../lib/icons.js":61,"./computed-artifact.js":8}],14:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const ComputedMetric=require('./metric.js');
+const LHError=require('../../lib/lh-error.js');
+const TracingProcessor=require('../../lib/traces/tracing-processor.js');
+const LanternEstimatedInputLatency=require('./lantern-estimated-input-latency.js');
+
+const ROLLING_WINDOW_SIZE=5000;
+
+
+
+
+
+
+class EstimatedInputLatency extends ComputedMetric{
+
+
+
+
+static calculateRollingWindowEIL(events){
+const candidateStartEvts=events.filter(evt=>evt.duration>=10);
+
+let worst90thPercentileLatency=16;
+for(const startEvt of candidateStartEvts){
+const latencyPercentiles=TracingProcessor.getRiskToResponsiveness(
+events,
+startEvt.start,
+startEvt.start+ROLLING_WINDOW_SIZE,
+[0.9]);
+
+
+worst90thPercentileLatency=Math.max(latencyPercentiles[0].time,worst90thPercentileLatency);
+}
+
+return worst90thPercentileLatency;
+}
+
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+return LanternEstimatedInputLatency.request(data,context);
+}
+
+
+
+
+
+static computeObservedMetric(data){
+const{firstMeaningfulPaint}=data.traceOfTab.timings;
+if(!firstMeaningfulPaint){
+throw new LHError(LHError.errors.NO_FMP);
+}
+
+const events=TracingProcessor.getMainThreadTopLevelEvents(
+data.traceOfTab,
+firstMeaningfulPaint).
+filter(evt=>evt.duration>=1);
+
+return Promise.resolve({
+timing:EstimatedInputLatency.calculateRollingWindowEIL(events)});
+
+}}
+
+
+module.exports=makeComputedArtifact(EstimatedInputLatency);
+
+},{"../../lib/lh-error.js":63,"../../lib/traces/tracing-processor.js":73,"../computed-artifact.js":8,"./lantern-estimated-input-latency.js":19,"./metric.js":26}],15:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const ComputedMetric=require('./metric.js');
+const LanternFirstContentfulPaint=require('./lantern-first-contentful-paint.js');
+
+class FirstContentfulPaint extends ComputedMetric{
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+return LanternFirstContentfulPaint.request(data,context);
+}
+
+
+
+
+
+static async computeObservedMetric(data){
+const{traceOfTab}=data;
+
+return{
+timing:traceOfTab.timings.firstContentfulPaint,
+timestamp:traceOfTab.timestamps.firstContentfulPaint};
+
+}}
+
+
+module.exports=makeComputedArtifact(FirstContentfulPaint);
+
+},{"../computed-artifact.js":8,"./lantern-first-contentful-paint.js":20,"./metric.js":26}],16:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const ComputedMetric=require('./metric.js');
+const TracingProcessor=require('../../lib/traces/tracing-processor.js');
+const LHError=require('../../lib/lh-error.js');
+const LanternFirstCPUIdle=require('./lantern-first-cpu-idle.js');
+
+const LONG_TASK_THRESHOLD=50;
+
+const MAX_TASK_CLUSTER_DURATION=250;
+const MIN_TASK_CLUSTER_PADDING=1000;
+const MIN_TASK_CLUSTER_FMP_DISTANCE=5000;
+
+const MAX_QUIET_WINDOW_SIZE=5000;
+
+
+const EXPONENTIATION_COEFFICIENT=-Math.log(3-1)/15;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class FirstCPUIdle extends ComputedMetric{
+
+
+
+
+static getRequiredWindowSizeInMs(t){
+const tInSeconds=t/1000;
+const exponentiationComponent=Math.exp(EXPONENTIATION_COEFFICIENT*tInSeconds);
+return(4*exponentiationComponent+1)*1000;
+}
+
+
+
+
+
+
+
+
+
+
+static getTaskClustersInWindow(tasks,startIndex,windowEnd){
+const clusters=[];
+
+let previousTaskEndTime=-Infinity;
+
+let currentCluster=[];
+
+
+
+
+
+const clusteringWindowEnd=windowEnd+MIN_TASK_CLUSTER_PADDING;
+
+const isInClusteringWindow=task=>task.start<clusteringWindowEnd;
+for(let i=startIndex;i<tasks.length;i++){
+if(!isInClusteringWindow(tasks[i])){
+break;
+}
+
+const task=tasks[i];
+
+
+if(task.start-previousTaskEndTime>MIN_TASK_CLUSTER_PADDING){
+currentCluster=[];
+clusters.push(currentCluster);
+}
+
+currentCluster.push(task);
+previousTaskEndTime=task.end;
+}
+
+return clusters.
+
+map(tasks=>{
+const start=tasks[0].start;
+const end=tasks[tasks.length-1].end;
+const duration=end-start;
+return{start,end,duration};
+}).
+
+filter(cluster=>cluster.start<windowEnd);
+}
+
+
+
+
+
+
+
+
+
+
+static findQuietWindow(FMP,traceEnd,longTasks){
+
+if(longTasks.length===0||
+longTasks[0].start>FMP+FirstCPUIdle.getRequiredWindowSizeInMs(0)){
+return FMP;
+}
+
+
+const isTooCloseToFMP=cluster=>cluster.start<FMP+MIN_TASK_CLUSTER_FMP_DISTANCE;
+
+const isTooLong=cluster=>cluster.duration>MAX_TASK_CLUSTER_DURATION;
+
+const isBadCluster=cluster=>isTooCloseToFMP(cluster)||isTooLong(cluster);
+
+
+
+for(let i=0;i<longTasks.length;i++){
+const windowStart=longTasks[i].end;
+const windowSize=FirstCPUIdle.getRequiredWindowSizeInMs(windowStart-FMP);
+const windowEnd=windowStart+windowSize;
+
+
+if(windowEnd>traceEnd){
+throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
+}
+
+
+if(i+1<longTasks.length&&
+longTasks[i+1].start-windowStart<=MIN_TASK_CLUSTER_PADDING){
+continue;
+}
+
+const taskClusters=FirstCPUIdle.getTaskClustersInWindow(longTasks,i+1,windowEnd);
+const hasBadTaskClusters=taskClusters.some(isBadCluster);
+
+if(!hasBadTaskClusters){
+return windowStart;
+}
+}
+
+throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
+}
+
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+return LanternFirstCPUIdle.request(data,context);
+}
+
+
+
+
+
+static async computeObservedMetric(data){
+const{traceOfTab}=data;
+const navStart=traceOfTab.timestamps.navigationStart;
+const FMP=traceOfTab.timings.firstMeaningfulPaint;
+const DCL=traceOfTab.timings.domContentLoaded;
+const traceEnd=traceOfTab.timings.traceEnd;
+
+if(!FMP||!DCL){
+throw new LHError(FMP?LHError.errors.NO_DCL:LHError.errors.NO_FMP);
+}
+
+if(traceEnd-FMP<MAX_QUIET_WINDOW_SIZE){
+throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
+}
+
+const longTasksAfterFMP=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab,FMP).
+filter(evt=>evt.duration>=LONG_TASK_THRESHOLD);
+const firstInteractive=FirstCPUIdle.findQuietWindow(FMP,traceEnd,longTasksAfterFMP);
+
+const valueInMs=Math.max(firstInteractive,DCL);
+
+return Promise.resolve({
+timing:valueInMs,
+timestamp:valueInMs*1000+navStart});
+
+}}
+
+
+
+
+
+
+
+module.exports=makeComputedArtifact(FirstCPUIdle);
+
+},{"../../lib/lh-error.js":63,"../../lib/traces/tracing-processor.js":73,"../computed-artifact.js":8,"./lantern-first-cpu-idle.js":21,"./metric.js":26}],17:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const ComputedMetric=require('./metric.js');
+const LHError=require('../../lib/lh-error.js');
+const LanternFirstMeaningfulPaint=require('./lantern-first-meaningful-paint.js');
+
+class FirstMeaningfulPaint extends ComputedMetric{
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+return LanternFirstMeaningfulPaint.request(data,context);
+}
+
+
+
+
+
+static async computeObservedMetric(data){
+const{traceOfTab}=data;
+if(!traceOfTab.timestamps.firstMeaningfulPaint){
+throw new LHError(LHError.errors.NO_FMP);
+}
+
+return{
+
+timing:traceOfTab.timings.firstMeaningfulPaint,
+timestamp:traceOfTab.timestamps.firstMeaningfulPaint};
+
+}}
+
+
+module.exports=makeComputedArtifact(FirstMeaningfulPaint);
+
+},{"../../lib/lh-error.js":63,"../computed-artifact.js":8,"./lantern-first-meaningful-paint.js":22,"./metric.js":26}],18:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const ComputedMetric=require('./metric.js');
+const LanternInteractive=require('./lantern-interactive.js');
+
+const NetworkRecorder=require('../../lib/network-recorder.js');
+const TracingProcessor=require('../../lib/traces/tracing-processor.js');
+const LHError=require('../../lib/lh-error.js');
+
+const REQUIRED_QUIET_WINDOW=5000;
+const ALLOWED_CONCURRENT_REQUESTS=2;
+
+
+
+
+
+
+class Interactive extends ComputedMetric{
+
+
+
+
+
+
+
+static _findNetworkQuietPeriods(networkRecords,traceOfTab){
+const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
+
+const filteredNetworkRecords=networkRecords.filter(record=>{
+return record.finished&&record.requestMethod==='GET'&&!record.failed&&
+
+record.statusCode<400;
+});
+return NetworkRecorder.findNetworkQuietPeriods(filteredNetworkRecords,
+ALLOWED_CONCURRENT_REQUESTS,traceEndTsInMs);
+}
+
+
+
+
+
+
+
+static _findCPUQuietPeriods(longTasks,traceOfTab){
+const navStartTsInMs=traceOfTab.timestamps.navigationStart/1000;
+const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
+if(longTasks.length===0){
+return[{start:0,end:traceEndTsInMs}];
+}
+
+
+const quietPeriods=[];
+longTasks.forEach((task,index)=>{
+if(index===0){
+quietPeriods.push({
+start:0,
+end:task.start+navStartTsInMs});
+
+}
+
+if(index===longTasks.length-1){
+quietPeriods.push({
+start:task.end+navStartTsInMs,
+end:traceEndTsInMs});
+
+}else{
+quietPeriods.push({
+start:task.end+navStartTsInMs,
+end:longTasks[index+1].start+navStartTsInMs});
+
+}
+});
+
+return quietPeriods;
+}
+
+
+
+
+
+
+
+
+static findOverlappingQuietPeriods(longTasks,networkRecords,traceOfTab){
+const FcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
+
+
+const isLongEnoughQuietPeriod=period=>
+period.end>FcpTsInMs+REQUIRED_QUIET_WINDOW&&
+period.end-period.start>=REQUIRED_QUIET_WINDOW;
+const networkQuietPeriods=this._findNetworkQuietPeriods(networkRecords,traceOfTab).
+filter(isLongEnoughQuietPeriod);
+const cpuQuietPeriods=this._findCPUQuietPeriods(longTasks,traceOfTab).
+filter(isLongEnoughQuietPeriod);
+
+const cpuQueue=cpuQuietPeriods.slice();
+const networkQueue=networkQuietPeriods.slice();
+
+
+let cpuCandidate=cpuQueue.shift();
+let networkCandidate=networkQueue.shift();
+while(cpuCandidate&&networkCandidate){
+if(cpuCandidate.start>=networkCandidate.start){
+
+if(networkCandidate.end>=cpuCandidate.start+REQUIRED_QUIET_WINDOW){
+return{
+cpuQuietPeriod:cpuCandidate,
+networkQuietPeriod:networkCandidate,
+cpuQuietPeriods,
+networkQuietPeriods};
+
+}else{
+networkCandidate=networkQueue.shift();
+}
+}else{
+
+if(cpuCandidate.end>=networkCandidate.start+REQUIRED_QUIET_WINDOW){
+return{
+cpuQuietPeriod:cpuCandidate,
+networkQuietPeriod:networkCandidate,
+cpuQuietPeriods,
+networkQuietPeriods};
+
+}else{
+cpuCandidate=cpuQueue.shift();
+}
+}
+}
+
+throw new LHError(
+cpuCandidate?
+LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD:
+LHError.errors.NO_TTI_CPU_IDLE_PERIOD);
+
+}
+
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+return LanternInteractive.request(data,context);
+}
+
+
+
+
+
+static computeObservedMetric(data){
+const{traceOfTab,networkRecords}=data;
+
+if(!traceOfTab.timestamps.domContentLoaded){
+throw new LHError(LHError.errors.NO_DCL);
+}
+
+const longTasks=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab).
+filter(event=>event.duration>=50);
+const quietPeriodInfo=Interactive.findOverlappingQuietPeriods(
+longTasks,
+networkRecords,
+traceOfTab);
+
+
+const cpuQuietPeriod=quietPeriodInfo.cpuQuietPeriod;
+
+const timestamp=Math.max(
+cpuQuietPeriod.start,
+traceOfTab.timestamps.firstContentfulPaint/1000,
+traceOfTab.timestamps.domContentLoaded/1000)*
+1000;
+const timing=(timestamp-traceOfTab.timestamps.navigationStart)/1000;
+return Promise.resolve({timing,timestamp});
+}}
+
+
+module.exports=makeComputedArtifact(Interactive);
+
+
+
+
+
+
+
+},{"../../lib/lh-error.js":63,"../../lib/network-recorder.js":66,"../../lib/traces/tracing-processor.js":73,"../computed-artifact.js":8,"./lantern-interactive.js":23,"./metric.js":26}],19:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const LanternMetric=require('./lantern-metric.js');
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+const LanternFirstMeaningfulPaint=require('./lantern-first-meaningful-paint.js');
+
+
+
+class LanternEstimatedInputLatency extends LanternMetric{
+
+
+
+static get COEFFICIENTS(){
+return{
+intercept:0,
+optimistic:0.4,
+pessimistic:0.4};
+
+}
+
+
+
+
+
+static getOptimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+static getPessimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+
+static getEstimateFromSimulation(simulation,extras){
+
+
+const fmpTimeInMs=extras.optimistic?
+extras.fmpResult.pessimisticEstimate.timeInMs:
+extras.fmpResult.optimisticEstimate.timeInMs;
+
+const events=LanternEstimatedInputLatency.getEventsAfterFMP(
+simulation.nodeTimings,
+fmpTimeInMs);
+
+
+
+const EstimatedInputLatency=require('./estimated-input-latency.js');
+
+return{
+timeInMs:EstimatedInputLatency.calculateRollingWindowEIL(events),
+nodeTimings:simulation.nodeTimings};
+
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const fmpResult=await LanternFirstMeaningfulPaint.request(data,context);
+return this.computeMetricWithGraphs(data,context,{fmpResult});
+}
+
+
+
+
+
+static getEventsAfterFMP(nodeTimings,fmpTimeInMs){
+
+const events=[];
+for(const[node,timing]of nodeTimings.entries()){
+if(node.type!==BaseNode.TYPES.CPU)continue;
+if(timing.endTime<fmpTimeInMs)continue;
+
+events.push({
+start:timing.startTime,
+end:timing.endTime,
+duration:timing.duration});
+
+}
+
+return events.sort((a,b)=>a.start-b.start);
+}}
+
+
+module.exports=makeComputedArtifact(LanternEstimatedInputLatency);
+
+},{"../../lib/dependency-graph/base-node.js":48,"../computed-artifact.js":8,"./estimated-input-latency.js":14,"./lantern-first-meaningful-paint.js":22,"./lantern-metric.js":24}],20:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const LanternMetric=require('./lantern-metric.js');
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+
+
+
+class LanternFirstContentfulPaint extends LanternMetric{
+
+
+
+static get COEFFICIENTS(){
+return{
+intercept:0,
+optimistic:0.5,
+pessimistic:0.5};
+
+}
+
+
+
+
+
+
+static getOptimisticGraph(dependencyGraph,traceOfTab){
+const fcp=traceOfTab.timestamps.firstContentfulPaint;
+const blockingScriptUrls=LanternMetric.getScriptUrls(dependencyGraph,node=>{
+return(
+node.endTime<=fcp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
+
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fcp&&!node.isMainDocument())return false;
+
+if(node.type===BaseNode.TYPES.CPU){
+return node.isEvaluateScriptFor(blockingScriptUrls);
+}
+
+
+return node.hasRenderBlockingPriority()&&node.initiatorType!=='script';
+});
+}
+
+
+
+
+
+
+static getPessimisticGraph(dependencyGraph,traceOfTab){
+const fcp=traceOfTab.timestamps.firstContentfulPaint;
+const blockingScriptUrls=LanternMetric.getScriptUrls(dependencyGraph,node=>{
+return node.endTime<=fcp&&node.hasRenderBlockingPriority();
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fcp&&!node.isMainDocument())return false;
+
+if(node.type===BaseNode.TYPES.CPU){
+return node.isEvaluateScriptFor(blockingScriptUrls);
+}
+
+
+return node.hasRenderBlockingPriority();
+});
+}}
+
+
+module.exports=makeComputedArtifact(LanternFirstContentfulPaint);
+
+},{"../../lib/dependency-graph/base-node.js":48,"../computed-artifact.js":8,"./lantern-metric.js":24}],21:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+const LanternInteractive=require('./lantern-interactive.js');
+
+class LanternFirstCPUIdle extends LanternInteractive{
+
+
+
+static get COEFFICIENTS(){
+return{
+intercept:0,
+optimistic:1,
+pessimistic:0};
+
+}
+
+
+
+
+
+
+
+static getEstimateFromSimulation(simulation,extras){
+const fmpTimeInMs=extras.optimistic?
+extras.fmpResult.optimisticEstimate.timeInMs:
+extras.fmpResult.pessimisticEstimate.timeInMs;
+
+return{
+timeInMs:LanternFirstCPUIdle.getFirstCPUIdleWindowStart(simulation.nodeTimings,fmpTimeInMs),
+nodeTimings:simulation.nodeTimings};
+
+}
+
+
+
+
+
+
+static getFirstCPUIdleWindowStart(nodeTimings,fmpTimeInMs,longTaskLength=50){
+
+const longTasks=[];
+for(const[node,timing]of nodeTimings.entries()){
+if(node.type!==BaseNode.TYPES.CPU)continue;
+if(timing.duration<longTaskLength)continue;
+longTasks.push({start:timing.startTime,end:timing.endTime});
+}
+
+longTasks.sort((a,b)=>a.start-b.start);
+
+const FirstCPUIdle=require('./first-cpu-idle');
+return FirstCPUIdle.findQuietWindow(fmpTimeInMs,Infinity,longTasks);
+}
+
+
+
+
+
+
+static async compute_(data,context){
+return super.compute_(data,context);
+}}
+
+
+module.exports=makeComputedArtifact(LanternFirstCPUIdle);
+
+},{"../../lib/dependency-graph/base-node.js":48,"../computed-artifact.js":8,"./first-cpu-idle":16,"./lantern-interactive.js":23}],22:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const LanternMetric=require('./lantern-metric.js');
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+const LHError=require('../../lib/lh-error.js');
+const LanternFirstContentfulPaint=require('./lantern-first-contentful-paint.js');
+
+
+
+class LanternFirstMeaningfulPaint extends LanternMetric{
+
+
+
+static get COEFFICIENTS(){
+return{
+intercept:0,
+optimistic:0.5,
+pessimistic:0.5};
+
+}
+
+
+
+
+
+
+static getOptimisticGraph(dependencyGraph,traceOfTab){
+const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
+if(!fmp){
+throw new LHError(LHError.errors.NO_FMP);
+}
+
+const blockingScriptUrls=LanternMetric.getScriptUrls(dependencyGraph,node=>{
+return(
+node.endTime<=fmp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
+
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fmp&&!node.isMainDocument())return false;
+
+if(node.type===BaseNode.TYPES.CPU){
+return node.isEvaluateScriptFor(blockingScriptUrls);
+}
+
+
+return node.hasRenderBlockingPriority()&&node.initiatorType!=='script';
+});
+}
+
+
+
+
+
+
+static getPessimisticGraph(dependencyGraph,traceOfTab){
+const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
+if(!fmp){
+throw new LHError(LHError.errors.NO_FMP);
+}
+
+const requiredScriptUrls=LanternMetric.getScriptUrls(dependencyGraph,node=>{
+return node.endTime<=fmp&&node.hasRenderBlockingPriority();
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fmp&&!node.isMainDocument())return false;
+
+
+if(node.type===BaseNode.TYPES.CPU){
+return node.didPerformLayout()||node.isEvaluateScriptFor(requiredScriptUrls);
+}
+
+
+return node.hasRenderBlockingPriority();
+});
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const fcpResult=await LanternFirstContentfulPaint.request(data,context);
+const metricResult=await this.computeMetricWithGraphs(data,context);
+metricResult.timing=Math.max(metricResult.timing,fcpResult.timing);
+return metricResult;
+}}
+
+
+module.exports=makeComputedArtifact(LanternFirstMeaningfulPaint);
+
+},{"../../lib/dependency-graph/base-node.js":48,"../../lib/lh-error.js":63,"../computed-artifact.js":8,"./lantern-first-contentful-paint.js":20,"./lantern-metric.js":24}],23:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const LanternMetric=require('./lantern-metric.js');
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+const NetworkRequest=require('../../lib/network-request.js');
+const LanternFirstMeaningfulPaint=require('./lantern-first-meaningful-paint.js');
+
+
+
+
+const CRITICAL_LONG_TASK_THRESHOLD=20;
+
+class LanternInteractive extends LanternMetric{
+
+
+
+static get COEFFICIENTS(){
+return{
+intercept:0,
+optimistic:0.5,
+pessimistic:0.5};
+
+}
+
+
+
+
+
+static getOptimisticGraph(dependencyGraph){
+
+const minimumCpuTaskDuration=CRITICAL_LONG_TASK_THRESHOLD*1000;
+
+return dependencyGraph.cloneWithRelationships(node=>{
+
+if(node.type===BaseNode.TYPES.CPU){
+return node.event.dur>minimumCpuTaskDuration;
+}
+
+
+const isImage=node.record.resourceType===NetworkRequest.TYPES.Image;
+const isScript=node.record.resourceType===NetworkRequest.TYPES.Script;
+return(
+!isImage&&(
+isScript||
+node.record.priority==='High'||
+node.record.priority==='VeryHigh'));
+
+});
+}
+
+
+
+
+
+static getPessimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+
+static getEstimateFromSimulation(simulationResult,extras){
+const lastTaskAt=LanternInteractive.getLastLongTaskEndTime(simulationResult.nodeTimings);
+const minimumTime=extras.optimistic?
+extras.fmpResult.optimisticEstimate.timeInMs:
+extras.fmpResult.pessimisticEstimate.timeInMs;
+return{
+timeInMs:Math.max(minimumTime,lastTaskAt),
+nodeTimings:simulationResult.nodeTimings};
+
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const fmpResult=await LanternFirstMeaningfulPaint.request(data,context);
+const metricResult=await this.computeMetricWithGraphs(data,context,{fmpResult});
+metricResult.timing=Math.max(metricResult.timing,fmpResult.timing);
+return metricResult;
+}
+
+
+
+
+
+static getLastLongTaskEndTime(nodeTimings,duration=50){
+return Array.from(nodeTimings.entries()).
+filter(([node,timing])=>{
+if(node.type!==BaseNode.TYPES.CPU)return false;
+return timing.duration>duration;
+}).
+map(([_,timing])=>timing.endTime).
+reduce((max,x)=>Math.max(max||0,x||0),0);
+}}
+
+
+module.exports=makeComputedArtifact(LanternInteractive);
+
+},{"../../lib/dependency-graph/base-node.js":48,"../../lib/network-request.js":67,"../computed-artifact.js":8,"./lantern-first-meaningful-paint.js":22,"./lantern-metric.js":24}],24:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+const NetworkRequest=require('../../lib/network-request.js');
+const TraceOfTab=require('../trace-of-tab.js');
+const PageDependencyGraph=require('../page-dependency-graph.js');
+const LoadSimulator=require('../load-simulator.js');
+
+
+
+
+
+class LanternMetricArtifact{
+
+
+
+
+
+static getScriptUrls(dependencyGraph,condition){
+
+const scriptUrls=new Set();
+
+dependencyGraph.traverse(node=>{
+if(node.type===BaseNode.TYPES.CPU)return;
+if(node.record.resourceType!==NetworkRequest.TYPES.Script)return;
+if(condition&&!condition(node))return;
+scriptUrls.add(node.record.url);
+});
+
+return scriptUrls;
+}
+
+
+
+
+static get COEFFICIENTS(){
+throw new Error('COEFFICIENTS unimplemented!');
+}
+
+
+
+
+
+
+
+
+
+
+static getScaledCoefficients(rttMs){
+return this.COEFFICIENTS;
+}
+
+
+
+
+
+
+static getOptimisticGraph(dependencyGraph,traceOfTab){
+throw new Error('Optimistic graph unimplemented!');
+}
+
+
+
+
+
+
+static getPessimisticGraph(dependencyGraph,traceOfTab){
+throw new Error('Pessmistic graph unimplemented!');
+}
+
+
+
+
+
+
+static getEstimateFromSimulation(simulationResult,extras){
+return simulationResult;
+}
+
+
+
+
+
+
+
+static async computeMetricWithGraphs(data,context,extras){
+const{trace,devtoolsLog,settings}=data;
+const metricName=this.name.replace('Lantern','');
+const graph=await PageDependencyGraph.request({trace,devtoolsLog},context);
+const traceOfTab=await TraceOfTab.request(trace,context);
+const simulator=data.simulator||(
+await LoadSimulator.request({devtoolsLog,settings},context));
+
+const optimisticGraph=this.getOptimisticGraph(graph,traceOfTab);
+const pessimisticGraph=this.getPessimisticGraph(graph,traceOfTab);
+
+
+let simulateOptions={label:`optimistic${metricName}`};
+const optimisticSimulation=simulator.simulate(optimisticGraph,simulateOptions);
+
+simulateOptions={label:`optimisticFlex${metricName}`,flexibleOrdering:true};
+const optimisticFlexSimulation=simulator.simulate(optimisticGraph,simulateOptions);
+
+simulateOptions={label:`pessimistic${metricName}`};
+const pessimisticSimulation=simulator.simulate(pessimisticGraph,simulateOptions);
+
+const optimisticEstimate=this.getEstimateFromSimulation(
+optimisticSimulation.timeInMs<optimisticFlexSimulation.timeInMs?
+optimisticSimulation:optimisticFlexSimulation,
+Object.assign({},extras,{optimistic:true}));
+
+
+const pessimisticEstimate=this.getEstimateFromSimulation(
+pessimisticSimulation,
+Object.assign({},extras,{optimistic:false}));
+
+
+const coefficients=this.getScaledCoefficients(simulator.rtt);
+
+const interceptMultiplier=coefficients.intercept>0?
+Math.min(1,optimisticEstimate.timeInMs/1000):1;
+const timing=
+coefficients.intercept*interceptMultiplier+
+coefficients.optimistic*optimisticEstimate.timeInMs+
+coefficients.pessimistic*pessimisticEstimate.timeInMs;
+
+return{
+timing,
+optimisticEstimate,
+pessimisticEstimate,
+optimisticGraph,
+pessimisticGraph};
+
+}
+
+
+
+
+
+
+static async compute_(data,context){
+return this.computeMetricWithGraphs(data,context);
+}}
+
+
+module.exports=LanternMetricArtifact;
+
+},{"../../lib/dependency-graph/base-node.js":48,"../../lib/network-request.js":67,"../load-simulator.js":10,"../page-dependency-graph.js":30,"../trace-of-tab.js":33}],25:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const LanternMetric=require('./lantern-metric.js');
+const BaseNode=require('../../lib/dependency-graph/base-node.js');
+const Speedline=require('../speedline.js');
+const LanternFirstContentfulPaint=require('./lantern-first-contentful-paint.js');
+const defaultThrottling=require('../../config/constants.js').throttling;
+
+
+
+class LanternSpeedIndex extends LanternMetric{
+
+
+
+static get COEFFICIENTS(){
+return{
+
+
+
+intercept:-250,
+optimistic:1.4,
+pessimistic:0.65};
+
+}
+
+
+
+
+
+static getScaledCoefficients(rttMs){
+
+
+
+
+
+
+
+
+
+
+
+const defaultCoefficients=this.COEFFICIENTS;
+const defaultRttExcess=defaultThrottling.mobileSlow4G.rttMs-30;
+const multiplier=Math.max((rttMs-30)/defaultRttExcess,0);
+
+return{
+intercept:defaultCoefficients.intercept*multiplier,
+optimistic:0.5+(defaultCoefficients.optimistic-0.5)*multiplier,
+pessimistic:0.5+(defaultCoefficients.pessimistic-0.5)*multiplier};
+
+}
+
+
+
+
+
+static getOptimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+static getPessimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+
+static getEstimateFromSimulation(simulationResult,extras){
+const fcpTimeInMs=extras.fcpResult.pessimisticEstimate.timeInMs;
+const estimate=extras.optimistic?
+extras.speedline.speedIndex:
+LanternSpeedIndex.computeLayoutBasedSpeedIndex(simulationResult.nodeTimings,fcpTimeInMs);
+return{
+timeInMs:estimate,
+nodeTimings:simulationResult.nodeTimings};
+
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const speedline=await Speedline.request(data.trace,context);
+const fcpResult=await LanternFirstContentfulPaint.request(data,context);
+const metricResult=await this.computeMetricWithGraphs(data,context,{
+speedline,
+fcpResult});
+
+metricResult.timing=Math.max(metricResult.timing,fcpResult.timing);
+return metricResult;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static computeLayoutBasedSpeedIndex(nodeTimings,fcpTimeInMs){
+
+const layoutWeights=[];
+for(const[node,timing]of nodeTimings.entries()){
+if(node.type!==BaseNode.TYPES.CPU)continue;
+
+if(node.childEvents.some(x=>x.name==='Layout')){
+const timingWeight=Math.max(Math.log2(timing.endTime-timing.startTime),0);
+layoutWeights.push({time:timing.endTime,weight:timingWeight});
+}
+}
+
+if(!layoutWeights.length){
+return fcpTimeInMs;
+}
+
+const totalWeightedTime=layoutWeights.
+map(evt=>evt.weight*Math.max(evt.time,fcpTimeInMs)).
+reduce((a,b)=>a+b,0);
+const totalWeight=layoutWeights.map(evt=>evt.weight).reduce((a,b)=>a+b,0);
+return totalWeightedTime/totalWeight;
+}}
+
+
+module.exports=makeComputedArtifact(LanternSpeedIndex);
+
+},{"../../config/constants.js":36,"../../lib/dependency-graph/base-node.js":48,"../computed-artifact.js":8,"../speedline.js":32,"./lantern-first-contentful-paint.js":20,"./lantern-metric.js":24}],26:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const TracingProcessor=require('../../lib/traces/tracing-processor.js');
+const TraceOfTab=require('../trace-of-tab.js');
+const NetworkRecords=require('../network-records.js');
+
+
+
+
+
+
+
+
+
+
+class ComputedMetric{
+constructor(){}
+
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+throw new Error('Unimplemented');
+}
+
+
+
+
+
+
+static computeObservedMetric(data,context){
+throw new Error('Unimplemented');
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const{trace,devtoolsLog,settings}=data;
+if(!trace||!devtoolsLog||!settings){
+throw new Error('Did not provide necessary metric computation data');
+}
+
+const augmentedData=Object.assign({
+networkRecords:await NetworkRecords.request(devtoolsLog,context),
+traceOfTab:await TraceOfTab.request(trace,context)},
+data);
+
+TracingProcessor.assertHasToplevelEvents(augmentedData.traceOfTab.mainThreadEvents);
+
+switch(settings.throttlingMethod){
+case'simulate':
+return this.computeSimulatedMetric(augmentedData,context);
+case'provided':
+case'devtools':
+return this.computeObservedMetric(augmentedData,context);
+default:
+throw new TypeError(`Unrecognized throttling method: ${settings.throttlingMethod}`);}
+
+}}
+
+
+module.exports=ComputedMetric;
+
+},{"../../lib/traces/tracing-processor.js":73,"../network-records.js":29,"../trace-of-tab.js":33}],27:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('../computed-artifact.js');
+const ComputedMetric=require('./metric.js');
+const LanternSpeedIndex=require('./lantern-speed-index.js');
+const Speedline=require('../speedline.js');
+
+class SpeedIndex extends ComputedMetric{
+
+
+
+
+
+static computeSimulatedMetric(data,context){
+return LanternSpeedIndex.request(data,context);
+}
+
+
+
+
+
+
+static async computeObservedMetric(data,context){
+const speedline=await Speedline.request(data.trace,context);
+const timing=Math.round(speedline.speedIndex);
+const timestamp=(timing+speedline.beginning)*1000;
+return Promise.resolve({timing,timestamp});
+}}
+
+
+module.exports=makeComputedArtifact(SpeedIndex);
+
+},{"../computed-artifact.js":8,"../speedline.js":32,"./lantern-speed-index.js":25,"./metric.js":26}],28:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const NetworkAnalyzer=require('../lib/dependency-graph/simulator/network-analyzer.js');
+const NetworkRecords=require('./network-records.js');
+
+class NetworkAnalysis{
+
+
+
+
+static computeRTTAndServerResponseTime(records){
+
+
+const rttByOrigin=new Map();
+for(const[origin,summary]of NetworkAnalyzer.estimateRTTByOrigin(records).entries()){
+rttByOrigin.set(origin,summary.min);
+}
+
+
+
+const minimumRtt=Math.min(...Array.from(rttByOrigin.values()));
+
+const responseTimeSummaries=NetworkAnalyzer.estimateServerResponseTimeByOrigin(records,{
+rttByOrigin});
+
+
+
+const additionalRttByOrigin=new Map();
+
+const serverResponseTimeByOrigin=new Map();
+for(const[origin,summary]of responseTimeSummaries.entries()){
+
+
+const rttForOrigin=rttByOrigin.get(origin);
+additionalRttByOrigin.set(origin,rttForOrigin-minimumRtt);
+serverResponseTimeByOrigin.set(origin,summary.median);
+}
+
+return{
+rtt:minimumRtt,
+additionalRttByOrigin,
+serverResponseTimeByOrigin};
+
+}
+
+
+
+
+
+
+static async compute_(devtoolsLog,context){
+const records=await NetworkRecords.request(devtoolsLog,context);
+const throughput=NetworkAnalyzer.estimateThroughput(records);
+const rttAndServerResponseTime=NetworkAnalysis.computeRTTAndServerResponseTime(records);
+return{records,throughput,...rttAndServerResponseTime};
+}}
+
+
+module.exports=makeComputedArtifact(NetworkAnalysis);
+
+},{"../lib/dependency-graph/simulator/network-analyzer.js":53,"./computed-artifact.js":8,"./network-records.js":29}],29:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const NetworkRecorder=require('../lib/network-recorder.js');
+
+class NetworkRecords{
+
+
+
+
+static async compute_(devtoolsLog){
+return NetworkRecorder.recordsFromLogs(devtoolsLog);
+}}
+
+
+module.exports=makeComputedArtifact(NetworkRecords);
+
+},{"../lib/network-recorder.js":66,"./computed-artifact.js":8}],30:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const NetworkNode=require('../lib/dependency-graph/network-node.js');
+const CPUNode=require('../lib/dependency-graph/cpu-node.js');
+const NetworkAnalyzer=require('../lib/dependency-graph/simulator/network-analyzer.js');
+const TracingProcessor=require('../lib/traces/tracing-processor.js');
+const NetworkRequest=require('../lib/network-request.js');
+const TraceOfTab=require('./trace-of-tab.js');
+const NetworkRecords=require('./network-records.js');
+
+
+
+
+const MINIMUM_TASK_DURATION_OF_INTEREST=10;
+
+
+const IGNORED_MIME_TYPES_REGEX=/^video/;
+
+class PageDependencyGraph{
+
+
+
+
+static getNetworkInitiators(record){
+if(!record.initiator)return[];
+if(record.initiator.url)return[record.initiator.url];
+if(record.initiator.type==='script'&&record.initiator.stack){
+const frames=record.initiator.stack.callFrames;
+return Array.from(new Set(frames.map(frame=>frame.url))).filter(Boolean);
+}
+
+return[];
+}
+
+
+
+
+
+static getNetworkNodeOutput(networkRecords){
+
+const nodes=[];
+const idToNodeMap=new Map();
+const urlToNodeMap=new Map();
+
+networkRecords.forEach(record=>{
+if(IGNORED_MIME_TYPES_REGEX.test(record.mimeType))return;
+
+
+
+
+
+while(idToNodeMap.has(record.requestId)){
+record.requestId+=':duplicate';
+}
+
+const node=new NetworkNode(record);
+nodes.push(node);
+
+const list=urlToNodeMap.get(record.url)||[];
+list.push(node);
+
+idToNodeMap.set(record.requestId,node);
+urlToNodeMap.set(record.url,list);
+});
+
+return{nodes,idToNodeMap,urlToNodeMap};
+}
+
+
+
+
+
+static getCPUNodes(traceOfTab){
+
+const nodes=[];
+let i=0;
+
+TracingProcessor.assertHasToplevelEvents(traceOfTab.mainThreadEvents);
+
+const minimumEvtDur=MINIMUM_TASK_DURATION_OF_INTEREST*1000;
+while(i<traceOfTab.mainThreadEvents.length){
+const evt=traceOfTab.mainThreadEvents[i];
+
+
+if(
+!TracingProcessor.isScheduleableTask(evt)||
+!evt.dur||
+evt.dur<minimumEvtDur)
+{
+i++;
+continue;
+}
+
+
+
+const children=[];
+i++;
+for(
+const endTime=evt.ts+evt.dur;
+i<traceOfTab.mainThreadEvents.length&&traceOfTab.mainThreadEvents[i].ts<endTime;
+i++)
+{
+children.push(traceOfTab.mainThreadEvents[i]);
+}
+
+nodes.push(new CPUNode(evt,children));
+}
+
+return nodes;
+}
+
+
+
+
+
+static linkNetworkNodes(rootNode,networkNodeOutput){
+networkNodeOutput.nodes.forEach(node=>{
+const initiators=PageDependencyGraph.getNetworkInitiators(node.record);
+if(initiators.length){
+initiators.forEach(initiator=>{
+const parentCandidates=networkNodeOutput.urlToNodeMap.get(initiator)||[rootNode];
+
+const parent=parentCandidates.length===1?parentCandidates[0]:rootNode;
+node.addDependency(parent);
+});
+}else if(node!==rootNode){
+rootNode.addDependent(node);
+}
+
+const redirects=Array.from(node.record.redirects||[]);
+redirects.push(node.record);
+
+for(let i=1;i<redirects.length;i++){
+const redirectNode=networkNodeOutput.idToNodeMap.get(redirects[i-1].requestId);
+const actualNode=networkNodeOutput.idToNodeMap.get(redirects[i].requestId);
+if(actualNode&&redirectNode){
+actualNode.addDependency(redirectNode);
+}
+}
+});
+}
+
+
+
+
+
+
+static linkCPUNodes(rootNode,networkNodeOutput,cpuNodes){
+
+function addDependentNetworkRequest(cpuNode,reqId){
+const networkNode=networkNodeOutput.idToNodeMap.get(reqId);
+if(!networkNode||
+
+networkNode.record.resourceType!==NetworkRequest.TYPES.XHR||
+
+
+networkNode.startTime<=cpuNode.startTime)return;
+cpuNode.addDependent(networkNode);
+}
+
+
+function addDependencyOnUrl(cpuNode,url){
+if(!url)return;
+
+
+const minimumAllowableTimeSinceNetworkNodeEnd=-100*1000;
+const candidates=networkNodeOutput.urlToNodeMap.get(url)||[];
+
+let minCandidate=null;
+let minDistance=Infinity;
+
+for(const candidate of candidates){
+
+
+if(cpuNode.startTime<=candidate.startTime)return;
+
+const distance=cpuNode.startTime-candidate.endTime;
+if(distance>=minimumAllowableTimeSinceNetworkNodeEnd&&distance<minDistance){
+minCandidate=candidate;
+minDistance=distance;
+}
+}
+
+if(!minCandidate)return;
+cpuNode.addDependency(minCandidate);
+}
+
+
+const timers=new Map();
+for(const node of cpuNodes){
+for(const evt of node.childEvents){
+if(!evt.args.data)continue;
+
+const argsUrl=evt.args.data.url;
+const stackTraceUrls=(evt.args.data.stackTrace||[]).map(l=>l.url).filter(Boolean);
+
+switch(evt.name){
+case'TimerInstall':
+
+timers.set(evt.args.data.timerId,node);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+case'TimerFire':{
+
+const installer=timers.get(evt.args.data.timerId);
+if(!installer)break;
+installer.addDependent(node);
+break;
+}
+
+case'InvalidateLayout':
+case'ScheduleStyleRecalculation':
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+
+case'EvaluateScript':
+
+addDependencyOnUrl(node,argsUrl);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+
+case'XHRReadyStateChange':
+
+
+if(evt.args.data.readyState!==4)break;
+
+
+addDependencyOnUrl(node,argsUrl);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+
+case'FunctionCall':
+case'v8.compile':
+
+addDependencyOnUrl(node,argsUrl);
+break;
+
+case'ParseAuthorStyleSheet':
+
+addDependencyOnUrl(node,evt.args.data.styleSheetUrl);
+break;
+
+case'ResourceSendRequest':
+
+addDependentNetworkRequest(node,evt.args.data.requestId);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;}
+
+}
+
+if(node.getNumberOfDependencies()===0){
+node.addDependency(rootNode);
+}
+}
+}
+
+
+
+
+
+
+static createGraph(traceOfTab,networkRecords){
+const networkNodeOutput=PageDependencyGraph.getNetworkNodeOutput(networkRecords);
+const cpuNodes=PageDependencyGraph.getCPUNodes(traceOfTab);
+
+
+const rootRequest=networkRecords.reduce((min,r)=>r.startTime<min.startTime?r:min);
+const rootNode=networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
+
+
+const mainDocumentRequest=NetworkAnalyzer.findMainDocument(networkRecords);
+const mainDocumentNode=networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
+
+if(!rootNode||!mainDocumentNode){
+
+throw new Error(`${rootNode?'mainDocument':'root'}Node not found.`);
+}
+
+if(mainDocumentNode!==rootNode&&(
+!mainDocumentNode.record.redirects||
+!mainDocumentNode.record.redirects.includes(rootNode.record))){
+throw new Error('Root node was not in redirect chain of mainDocument');
+}
+
+PageDependencyGraph.linkNetworkNodes(rootNode,networkNodeOutput);
+PageDependencyGraph.linkCPUNodes(rootNode,networkNodeOutput,cpuNodes);
+mainDocumentNode.setIsMainDocument(true);
+
+if(NetworkNode.hasCycle(rootNode)){
+throw new Error('Invalid dependency graph created, cycle detected');
+}
+
+return rootNode;
+}
+
+
+
+
+
+static printGraph(rootNode,widthInCharacters=100){
+
+function padRight(str,target,padChar=' '){
+return str+padChar.repeat(Math.max(target-str.length,0));
+}
+
+
+const nodes=[];
+rootNode.traverse(node=>nodes.push(node));
+nodes.sort((a,b)=>a.startTime-b.startTime);
+
+const min=nodes[0].startTime;
+const max=nodes.reduce((max,node)=>Math.max(max,node.endTime),0);
+
+const totalTime=max-min;
+const timePerCharacter=totalTime/widthInCharacters;
+nodes.forEach(node=>{
+const offset=Math.round((node.startTime-min)/timePerCharacter);
+const length=Math.ceil((node.endTime-node.startTime)/timePerCharacter);
+const bar=padRight('',offset)+padRight('',length,'=');
+
+
+const displayName=node.record?node.record.url:node.type;
+
+console.log(padRight(bar,widthInCharacters),`| ${displayName.slice(0,30)}`);
+});
+}
+
+
+
+
+
+
+static async compute_(data,context){
+const trace=data.trace;
+const devtoolsLog=data.devtoolsLog;
+const[traceOfTab,networkRecords]=await Promise.all([
+TraceOfTab.request(trace,context),
+NetworkRecords.request(devtoolsLog,context)]);
+
+
+return PageDependencyGraph.createGraph(traceOfTab,networkRecords);
+}}
+
+
+module.exports=makeComputedArtifact(PageDependencyGraph);
+
+
+
+
+
+
+
+
+},{"../lib/dependency-graph/cpu-node.js":49,"../lib/dependency-graph/network-node.js":50,"../lib/dependency-graph/simulator/network-analyzer.js":53,"../lib/network-request.js":67,"../lib/traces/tracing-processor.js":73,"./computed-artifact.js":8,"./network-records.js":29,"./trace-of-tab.js":33}],31:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+
+const SCREENSHOT_TRACE_NAME='Screenshot';
+
+class Screenshots{
+
+
+
+
+static async compute_(trace){
+return trace.traceEvents.
+filter(evt=>evt.name===SCREENSHOT_TRACE_NAME).
+map(evt=>{
+return{
+timestamp:evt.ts/1000,
+datauri:`data:image/jpeg;base64,${evt.args.snapshot}`};
+
+});
+}}
+
+
+module.exports=makeComputedArtifact(Screenshots);
+
+},{"./computed-artifact.js":8}],32:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const speedline=require('speedline-core');
+const LHError=require('../lib/lh-error.js');
+const TraceOfTab=require('./trace-of-tab.js');
+
+class Speedline{
+
+
+
+
+
+static async compute_(trace,context){
+
+
+return TraceOfTab.request(trace,context).then(traceOfTab=>{
+
+
+const traceEvents=trace.traceEvents.slice();
+
+
+const navStart=traceOfTab.timestamps.navigationStart;
+return speedline(traceEvents,{
+timeOrigin:navStart,
+fastMode:true,
+include:'speedIndex'});
+
+}).catch(err=>{
+if(/No screenshots found in trace/.test(err.message)){
+throw new LHError(LHError.errors.NO_SCREENSHOTS);
+}
+
+throw err;
+}).then(speedline=>{
+if(speedline.frames.length===0){
+throw new LHError(LHError.errors.NO_SPEEDLINE_FRAMES);
+}
+
+if(speedline.speedIndex===0){
+throw new LHError(LHError.errors.SPEEDINDEX_OF_ZERO);
+}
+
+return speedline;
+});
+}}
+
+
+module.exports=makeComputedArtifact(Speedline);
+
+},{"../lib/lh-error.js":63,"./computed-artifact.js":8,"./trace-of-tab.js":33,"speedline-core":153}],33:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const log=require('lighthouse-logger');
+const TracingProcessor=require('../lib/traces/tracing-processor.js');
+const LHError=require('../lib/lh-error.js');
+const Sentry=require('../lib/sentry.js');
+
+const ACCEPTABLE_NAVIGATION_URL_REGEX=/^(chrome|https?):/;
+
+class TraceOfTab{
+
+
+
+
+
+static isNavigationStartOfInterest(event){
+return event.name==='navigationStart'&&(
+!event.args.data||!event.args.data.documentLoaderURL||
+ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL));
+}
+
+
+
+
+
+static filteredStableSort(traceEvents,filter){
+
+const indices=[];
+for(let srcIndex=0;srcIndex<traceEvents.length;srcIndex++){
+if(filter(traceEvents[srcIndex])){
+indices.push(srcIndex);
+}
+}
+
+
+indices.sort((indexA,indexB)=>{
+const result=traceEvents[indexA].ts-traceEvents[indexB].ts;
+return result?result:indexA-indexB;
+});
+
+
+const sorted=[];
+for(let i=0;i<indices.length;i++){
+sorted.push(traceEvents[indices[i]]);
+}
+
+return sorted;
+}
+
+
+
+
+
+
+
+
+static async compute_(trace){
+
+
+const keyEvents=TraceOfTab.filteredStableSort(trace.traceEvents,e=>{
+return e.cat.includes('blink.user_timing')||
+e.cat.includes('loading')||
+e.cat.includes('devtools.timeline')||
+e.cat==='__metadata';
+});
+
+
+const mainFrameIds=TracingProcessor.findMainFrameIds(keyEvents);
+
+
+const frameEvents=keyEvents.filter(e=>e.args.frame===mainFrameIds.frameId);
+
+
+const navigationStart=frameEvents.filter(TraceOfTab.isNavigationStartOfInterest).pop();
+if(!navigationStart)throw new LHError(LHError.errors.NO_NAVSTART);
+
+
+const firstPaint=frameEvents.find(e=>e.name==='firstPaint'&&e.ts>navigationStart.ts);
+
+
+const firstContentfulPaint=frameEvents.find(
+e=>e.name==='firstContentfulPaint'&&e.ts>navigationStart.ts);
+
+if(!firstContentfulPaint)throw new LHError(LHError.errors.NO_FCP);
+
+
+let firstMeaningfulPaint=frameEvents.find(
+e=>e.name==='firstMeaningfulPaint'&&e.ts>navigationStart.ts);
+
+let fmpFellBack=false;
+
+
+
+
+
+if(!firstMeaningfulPaint){
+
+Sentry.captureMessage('No firstMeaningfulPaint found, using fallback',{level:'warning'});
+
+const fmpCand='firstMeaningfulPaintCandidate';
+fmpFellBack=true;
+log.verbose('trace-of-tab',`No firstMeaningfulPaint found, falling back to last ${fmpCand}`);
+const lastCandidate=frameEvents.filter(e=>e.name===fmpCand).pop();
+if(!lastCandidate){
+log.verbose('trace-of-tab','No `firstMeaningfulPaintCandidate` events found in trace');
+}
+firstMeaningfulPaint=lastCandidate;
+}
+
+const load=frameEvents.find(e=>e.name==='loadEventEnd'&&e.ts>navigationStart.ts);
+const domContentLoaded=frameEvents.find(
+e=>e.name==='domContentLoadedEventEnd'&&e.ts>navigationStart.ts);
+
+
+
+
+const processEvents=TraceOfTab.
+filteredStableSort(trace.traceEvents,e=>e.pid===mainFrameIds.pid);
+
+const mainThreadEvents=processEvents.
+filter(e=>e.tid===mainFrameIds.tid);
+
+
+const traceEnd=trace.traceEvents.reduce((max,evt)=>{
+return max.ts>evt.ts?max:evt;
+});
+const fakeEndOfTraceEvt={ts:traceEnd.ts+(traceEnd.dur||0)};
+
+
+const getTimestamp=event=>event&&event.ts;
+
+const timestamps={
+navigationStart:navigationStart.ts,
+firstPaint:getTimestamp(firstPaint),
+firstContentfulPaint:firstContentfulPaint.ts,
+firstMeaningfulPaint:getTimestamp(firstMeaningfulPaint),
+traceEnd:fakeEndOfTraceEvt.ts,
+load:getTimestamp(load),
+domContentLoaded:getTimestamp(domContentLoaded)};
+
+
+
+
+const getTiming=ts=>(ts-navigationStart.ts)/1000;
+
+const maybeGetTiming=ts=>ts===undefined?undefined:getTiming(ts);
+
+const timings={
+navigationStart:0,
+firstPaint:maybeGetTiming(timestamps.firstPaint),
+firstContentfulPaint:getTiming(timestamps.firstContentfulPaint),
+firstMeaningfulPaint:maybeGetTiming(timestamps.firstMeaningfulPaint),
+traceEnd:getTiming(timestamps.traceEnd),
+load:maybeGetTiming(timestamps.load),
+domContentLoaded:maybeGetTiming(timestamps.domContentLoaded)};
+
+
+return{
+timings,
+timestamps,
+processEvents,
+mainThreadEvents,
+mainFrameIds,
+navigationStartEvt:navigationStart,
+firstPaintEvt:firstPaint,
+firstContentfulPaintEvt:firstContentfulPaint,
+firstMeaningfulPaintEvt:firstMeaningfulPaint,
+loadEvt:load,
+domContentLoadedEvt:domContentLoaded,
+fmpFellBack};
+
+}}
+
+
+module.exports=makeComputedArtifact(TraceOfTab);
+
+},{"../lib/lh-error.js":63,"../lib/sentry.js":69,"../lib/traces/tracing-processor.js":73,"./computed-artifact.js":8,"lighthouse-logger":113}],34:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const makeComputedArtifact=require('./computed-artifact.js');
+const TraceOfTab=require('./trace-of-tab.js');
+
+
+
+
+class UserTimings{
+
+
+
+
+
+static async compute_(trace,context){
+const traceOfTab=await TraceOfTab.request(trace,context);
+
+const userTimings=[];
+
+const measuresStartTimes={};
+
+
+
+
+
+traceOfTab.processEvents.filter(evt=>{
+if(!evt.cat.includes('blink.user_timing')){
+return false;
+}
+
+
+
+return evt.name!=='requestStart'&&
+evt.name!=='navigationStart'&&
+evt.name!=='paintNonDefaultBackgroundColor'&&
+evt.args.frame===undefined;
+}).
+forEach(ut=>{
+
+if(ut.ph==='R'||ut.ph.toUpperCase()==='I'){
+userTimings.push({
+name:ut.name,
+isMark:true,
+args:ut.args,
+startTime:ut.ts});
+
+
+
+}else if(ut.ph.toLowerCase()==='b'){
+measuresStartTimes[ut.name]=ut.ts;
+
+
+}else if(ut.ph.toLowerCase()==='e'){
+userTimings.push({
+name:ut.name,
+isMark:false,
+args:ut.args,
+startTime:measuresStartTimes[ut.name],
+endTime:ut.ts,
+duration:ut.ts-measuresStartTimes[ut.name]});
+
+}
+});
+
+
+userTimings.forEach(ut=>{
+ut.startTime=(ut.startTime-traceOfTab.navigationStartEvt.ts)/1000;
+if(!ut.isMark){
+ut.endTime=(ut.endTime-traceOfTab.navigationStartEvt.ts)/1000;
+ut.duration=ut.duration/1000;
+}
+});
+
+return userTimings;
+}}
+
+
+module.exports=makeComputedArtifact(UserTimings);
+
+},{"./computed-artifact.js":8,"./trace-of-tab.js":33}],35:[function(require,module,exports){
+(function(process,__dirname){
+
+
+
+
+
+'use strict';
+
+const defaultConfigPath='./default-config.js';
+const defaultConfig=require('./default-config.js');
+const fullConfig=require('./full-config.js');
+const constants=require('./constants.js');
+const i18n=require('./../lib/i18n/i18n.js');
+
+const isDeepEqual=require('lodash.isequal');
+const log=require('lighthouse-logger');
+const path=require('path');
+const Audit=require('../audits/audit.js');
+const Runner=require('../runner.js');
+
+
+
+
+
+
+
+
+function validatePasses(passes,audits){
+if(!Array.isArray(passes)){
+return;
+}
+
+const requiredGatherers=Config.getGatherersNeededByAudits(audits);
+
+
+passes.forEach(pass=>{
+pass.gatherers.forEach(gathererDefn=>{
+const gatherer=gathererDefn.instance;
+const isGatherRequiredByAudits=requiredGatherers.has(gatherer.name);
+if(!isGatherRequiredByAudits){
+const msg=`${gatherer.name} gatherer requested, however no audit requires it.`;
+log.warn('config',msg);
+}
+});
+});
+
+
+const usedNames=new Set();
+passes.forEach(pass=>{
+const passName=pass.passName;
+if(usedNames.has(passName)){
+throw new Error(`Passes must have unique names (repeated passName: ${passName}.`);
+}
+usedNames.add(passName);
+});
+}
+
+
+
+
+
+
+function validateCategories(categories,audits,groups){
+if(!categories){
+return;
+}
+
+const auditsKeyedById=new Map((audits||[]).map(audit=>
+
+[audit.implementation.meta.id,audit]));
+
+
+Object.keys(categories).forEach(categoryId=>{
+categories[categoryId].auditRefs.forEach((auditRef,index)=>{
+if(!auditRef.id){
+throw new Error(`missing an audit id at ${categoryId}[${index}]`);
+}
+
+const audit=auditsKeyedById.get(auditRef.id);
+if(!audit){
+throw new Error(`could not find ${auditRef.id} audit for category ${categoryId}`);
+}
+
+const auditImpl=audit.implementation;
+const isManual=auditImpl.meta.scoreDisplayMode==='manual';
+if(categoryId==='accessibility'&&!auditRef.group&&!isManual){
+throw new Error(`${auditRef.id} accessibility audit does not have a group`);
+}
+
+if(auditRef.weight>0&&isManual){
+throw new Error(`${auditRef.id} is manual but has a positive weight`);
+}
+
+if(auditRef.group&&(!groups||!groups[auditRef.group])){
+throw new Error(`${auditRef.id} references unknown group ${auditRef.group}`);
+}
+});
+});
+}
+
+
+
+
+
+function assertValidAudit(auditDefinition,auditPath){
+const auditName=auditPath||
+auditDefinition&&auditDefinition.meta&&auditDefinition.meta.id;
+
+if(typeof auditDefinition.audit!=='function'||auditDefinition.audit===Audit.audit){
+throw new Error(`${auditName} has no audit() method.`);
+}
+
+if(typeof auditDefinition.meta.id!=='string'){
+throw new Error(`${auditName} has no meta.id property, or the property is not a string.`);
+}
+
+if(typeof auditDefinition.meta.title!=='string'){
+throw new Error(
+`${auditName} has no meta.title property, or the property is not a string.`);
+
+}
+
+
+if(typeof auditDefinition.meta.failureTitle!=='string'&&
+auditDefinition.meta.scoreDisplayMode===Audit.SCORING_MODES.BINARY){
+throw new Error(`${auditName} has no failureTitle and should.`);
+}
+
+if(typeof auditDefinition.meta.description!=='string'){
+throw new Error(
+`${auditName} has no meta.description property, or the property is not a string.`);
+
+}else if(auditDefinition.meta.description===''){
+throw new Error(
+`${auditName} has an empty meta.description string. Please add a description for the UI.`);
+
+}
+
+if(!Array.isArray(auditDefinition.meta.requiredArtifacts)){
+throw new Error(
+`${auditName} has no meta.requiredArtifacts property, or the property is not an array.`);
+
+}
+}
+
+
+
+
+
+function assertValidGatherer(gathererInstance,gathererName){
+gathererName=gathererName||gathererInstance.name||'gatherer';
+
+if(typeof gathererInstance.beforePass!=='function'){
+throw new Error(`${gathererName} has no beforePass() method.`);
+}
+
+if(typeof gathererInstance.pass!=='function'){
+throw new Error(`${gathererName} has no pass() method.`);
+}
+
+if(typeof gathererInstance.afterPass!=='function'){
+throw new Error(`${gathererName} has no afterPass() method.`);
+}
+}
+
+
+
+
+
+
+
+function cleanFlagsForSettings(flags={}){
+
+const settings={};
+
+for(const key of Object.keys(flags)){
+
+if(typeof constants.defaultSettings[key]!=='undefined'){
+
+const safekey=key;
+settings[safekey]=flags[safekey];
+}
+}
+
+return settings;
+}
+
+
+
+
+
+
+
+
+function _merge(base,extension,overwriteArrays=false){
+
+if(typeof base==='undefined'||base===null){
+return extension;
+}else if(typeof extension==='undefined'){
+return base;
+}else if(Array.isArray(extension)){
+if(overwriteArrays)return extension;
+if(!Array.isArray(base))throw new TypeError(`Expected array but got ${typeof base}`);
+const merged=base.slice();
+extension.forEach(item=>{
+if(!merged.some(candidate=>isDeepEqual(candidate,item)))merged.push(item);
+});
+
+return merged;
+}else if(typeof extension==='object'){
+if(typeof base!=='object')throw new TypeError(`Expected object but got ${typeof base}`);
+if(Array.isArray(base))throw new TypeError('Expected object but got Array');
+Object.keys(extension).forEach(key=>{
+const localOverwriteArrays=overwriteArrays||
+key==='settings'&&typeof base[key]==='object';
+base[key]=_merge(base[key],extension[key],localOverwriteArrays);
+});
+return base;
+}
+
+return extension;
+}
+
+
+
+
+
+
+const merge=_merge;
+
+
+
+
+
+
+function cloneArrayWithPluginSafety(array){
+return array.map(item=>{
+if(typeof item==='object'){
+
+return Object.assign(
+Object.create(
+Object.getPrototypeOf(item)),
+
+item);
+
+}
+
+return item;
+});
+}
+
+
+
+
+
+
+
+
+function deepClone(json){
+return JSON.parse(JSON.stringify(json));
+}
+
+
+
+
+
+
+
+function deepCloneConfigJson(json){
+const cloned=deepClone(json);
+
+
+
+if(Array.isArray(cloned.passes)&&Array.isArray(json.passes)){
+for(let i=0;i<cloned.passes.length;i++){
+const pass=cloned.passes[i];
+pass.gatherers=cloneArrayWithPluginSafety(json.passes[i].gatherers||[]);
+}
+}
+
+if(Array.isArray(json.audits)){
+cloned.audits=cloneArrayWithPluginSafety(json.audits);
+}
+
+return cloned;
+}
+
+
+
+
+
+
+
+
+
+const mergeOptionsOfItems=function(items){
+
+const mergedItems=[];
+
+for(const item of items){
+const existingItem=item.path&&mergedItems.find(candidate=>candidate.path===item.path);
+if(!existingItem){
+mergedItems.push(item);
+continue;
+}
+
+existingItem.options=Object.assign({},existingItem.options,item.options);
+}
+
+return mergedItems;
+};
+
+class Config{
+
+
+
+
+
+
+constructor(configJSON,flags){
+const status={msg:'Create config',id:'lh:init:config'};
+log.time(status,'verbose');
+let configPath=flags&&flags.configPath;
+
+if(!configJSON){
+configJSON=defaultConfig;
+configPath=path.resolve(__dirname,defaultConfigPath);
+}
+
+if(configPath&&!path.isAbsolute(configPath)){
+throw new Error('configPath must be an absolute path.');
+}
+
+
+configJSON=deepCloneConfigJson(configJSON);
+
+
+if(configJSON.extends==='lighthouse:full'){
+const explodedFullConfig=Config.extendConfigJSON(deepCloneConfigJson(defaultConfig),
+deepCloneConfigJson(fullConfig));
+configJSON=Config.extendConfigJSON(explodedFullConfig,configJSON);
+}else if(configJSON.extends){
+configJSON=Config.extendConfigJSON(deepCloneConfigJson(defaultConfig),configJSON);
+}
+
+
+const configDir=configPath?path.dirname(configPath):undefined;
+
+const settings=Config.initSettings(configJSON.settings,flags);
+
+
+const passesWithDefaults=Config.augmentPassesWithDefaults(configJSON.passes);
+Config.adjustDefaultPassForThrottling(settings,passesWithDefaults);
+const passes=Config.requireGatherers(passesWithDefaults,configDir);
+
+
+this.settings=settings;
+
+this.passes=passes;
+
+this.audits=Config.requireAudits(configJSON.audits,configDir);
+
+this.categories=configJSON.categories||null;
+
+this.groups=configJSON.groups||null;
+
+Config.filterConfigIfNeeded(this);
+
+validatePasses(this.passes,this.audits);
+validateCategories(this.categories,this.audits,this.groups);
+
+
+
+const configJson=this;
+log.timeEnd(status);
+}
+
+
+
+
+
+
+getPrintString(){
+const jsonConfig=deepClone(this);
+
+if(jsonConfig.passes){
+for(const pass of jsonConfig.passes){
+for(const gathererDefn of pass.gatherers){
+gathererDefn.implementation=undefined;
+
+gathererDefn.instance=undefined;
+if(Object.keys(gathererDefn.options).length===0){
+
+gathererDefn.options=undefined;
+}
+}
+}
+}
+
+if(jsonConfig.audits){
+for(const auditDefn of jsonConfig.audits){
+
+auditDefn.implementation=undefined;
+if(Object.keys(auditDefn.options).length===0){
+
+auditDefn.options=undefined;
+}
+}
+}
+
+
+i18n.replaceIcuMessageInstanceIds(jsonConfig,jsonConfig.settings.locale);
+
+return JSON.stringify(jsonConfig,null,2);
+}
+
+
+
+
+
+
+static extendConfigJSON(baseJSON,extendJSON){
+if(extendJSON.passes&&baseJSON.passes){
+for(const pass of extendJSON.passes){
+
+const passName=pass.passName||constants.defaultPassConfig.passName;
+const basePass=baseJSON.passes.find(candidate=>candidate.passName===passName);
+
+if(!basePass){
+baseJSON.passes.push(pass);
+}else{
+merge(basePass,pass);
+}
+}
+
+delete extendJSON.passes;
+}
+
+return merge(baseJSON,extendJSON);
+}
+
+
+
+
+
+static augmentPassesWithDefaults(passes){
+if(!passes){
+return null;
+}
+
+const{defaultPassConfig}=constants;
+return passes.map(pass=>merge(deepClone(defaultPassConfig),pass));
+}
+
+
+
+
+
+
+static initSettings(settingsJson={},flags){
+
+
+
+const locale=i18n.lookupLocale(flags&&flags.locale||settingsJson.locale);
+
+
+const{defaultSettings}=constants;
+const settingWithDefaults=merge(deepClone(defaultSettings),settingsJson,true);
+
+
+const settingsWithFlags=merge(settingWithDefaults||{},cleanFlagsForSettings(flags),true);
+
+
+settingsWithFlags.locale=locale;
+
+return settingsWithFlags;
+}
+
+
+
+
+
+
+static expandAuditShorthand(audits){
+if(!audits){
+return null;
+}
+
+const newAudits=audits.map(audit=>{
+if(typeof audit==='string'){
+
+return{path:audit,options:{}};
+}else if('implementation'in audit&&typeof audit.implementation.audit==='function'){
+
+return audit;
+}else if('path'in audit&&typeof audit.path==='string'){
+
+return audit;
+}else if('audit'in audit&&typeof audit.audit==='function'){
+
+return{implementation:audit,options:{}};
+}else{
+throw new Error('Invalid Audit type '+JSON.stringify(audit));
+}
+});
+
+return newAudits;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+static expandGathererShorthand(gatherers){
+const expanded=gatherers.map(gatherer=>{
+if(typeof gatherer==='string'){
+
+return{path:gatherer,options:{}};
+}else if('implementation'in gatherer||'instance'in gatherer){
+
+return gatherer;
+}else if('path'in gatherer){
+
+if(typeof gatherer.path!=='string'){
+throw new Error('Invalid Gatherer type '+JSON.stringify(gatherer));
+}
+return gatherer;
+}else if(typeof gatherer==='function'){
+
+return{implementation:gatherer,options:{}};
+}else if(gatherer&&typeof gatherer.beforePass==='function'){
+
+return{instance:gatherer,options:{}};
+}else{
+throw new Error('Invalid Gatherer type '+JSON.stringify(gatherer));
+}
+});
+
+return expanded;
+}
+
+
+
+
+
+
+
+static adjustDefaultPassForThrottling(settings,passes){
+if(!passes||
+settings.throttlingMethod!=='devtools'&&settings.throttlingMethod!=='provided'){
+return;
+}
+
+const defaultPass=passes.find(pass=>pass.passName==='defaultPass');
+if(!defaultPass)return;
+const overrides=constants.nonSimulatedPassConfigOverrides;
+defaultPass.pauseAfterLoadMs=
+Math.max(overrides.pauseAfterLoadMs,defaultPass.pauseAfterLoadMs);
+defaultPass.cpuQuietThresholdMs=
+Math.max(overrides.cpuQuietThresholdMs,defaultPass.cpuQuietThresholdMs);
+defaultPass.networkQuietThresholdMs=
+Math.max(overrides.networkQuietThresholdMs,defaultPass.networkQuietThresholdMs);
+}
+
+
+
+
+
+static filterConfigIfNeeded(config){
+const settings=config.settings;
+if(!settings.onlyCategories&&!settings.onlyAudits&&!settings.skipAudits){
+return;
+}
+
+
+const{categories,requestedAuditNames}=Config.filterCategoriesAndAudits(config.categories,
+settings);
+
+
+const audits=config.audits&&config.audits.filter(auditDefn=>
+requestedAuditNames.has(auditDefn.implementation.meta.id));
+
+
+const requiredGathererIds=Config.getGatherersNeededByAudits(audits);
+
+
+const passes=Config.generatePassesNeededByGatherers(config.passes,requiredGathererIds);
+
+config.categories=categories;
+config.audits=audits;
+config.passes=passes;
+}
+
+
+
+
+
+
+
+static filterCategoriesAndAudits(oldCategories,settings){
+if(!oldCategories){
+return{categories:null,requestedAuditNames:new Set()};
+}
+
+if(settings.onlyAudits&&settings.skipAudits){
+throw new Error('Cannot set both skipAudits and onlyAudits');
+}
+
+
+const categories={};
+const filterByIncludedCategory=!!settings.onlyCategories;
+const filterByIncludedAudit=!!settings.onlyAudits;
+const categoryIds=settings.onlyCategories||[];
+const auditIds=settings.onlyAudits||[];
+const skipAuditIds=settings.skipAudits||[];
+
+
+categoryIds.forEach(categoryId=>{
+if(!oldCategories[categoryId]){
+log.warn('config',`unrecognized category in 'onlyCategories': ${categoryId}`);
+}
+});
+
+
+const auditsToValidate=new Set(auditIds.concat(skipAuditIds));
+for(const auditId of auditsToValidate){
+const foundCategory=Object.keys(oldCategories).find(categoryId=>{
+const auditRefs=oldCategories[categoryId].auditRefs;
+return!!auditRefs.find(candidate=>candidate.id===auditId);
+});
+
+if(!foundCategory){
+const parentKeyName=skipAuditIds.includes(auditId)?'skipAudits':'onlyAudits';
+log.warn('config',`unrecognized audit in '${parentKeyName}': ${auditId}`);
+}else if(auditIds.includes(auditId)&&categoryIds.includes(foundCategory)){
+log.warn('config',`${auditId} in 'onlyAudits' is already included by `+
+`${foundCategory} in 'onlyCategories'`);
+}
+}
+
+const includedAudits=new Set(auditIds);
+skipAuditIds.forEach(id=>includedAudits.delete(id));
+
+Object.keys(oldCategories).forEach(categoryId=>{
+const category=deepClone(oldCategories[categoryId]);
+
+if(filterByIncludedCategory&&filterByIncludedAudit){
+
+if(!categoryIds.includes(categoryId)){
+category.auditRefs=category.auditRefs.filter(audit=>auditIds.includes(audit.id));
+}
+}else if(filterByIncludedCategory){
+
+if(!categoryIds.includes(categoryId)){
+return;
+}
+}else if(filterByIncludedAudit){
+category.auditRefs=category.auditRefs.filter(audit=>auditIds.includes(audit.id));
+}
+
+
+category.auditRefs=category.auditRefs.filter(audit=>!skipAuditIds.includes(audit.id));
+
+if(category.auditRefs.length){
+categories[categoryId]=category;
+category.auditRefs.forEach(audit=>includedAudits.add(audit.id));
+}
+});
+
+return{categories,requestedAuditNames:includedAudits};
+}
+
+
+
+
+
+static getCategories(config){
+const categories=config.categories;
+if(!categories){
+return[];
+}
+
+return Object.keys(categories).map(id=>{
+const title=categories[id].title;
+return{id,title};
+});
+}
+
+
+
+
+
+
+static getGatherersNeededByAudits(audits){
+
+
+if(!audits){
+return new Set();
+}
+
+return audits.reduce((list,auditDefn)=>{
+auditDefn.implementation.meta.requiredArtifacts.forEach(artifact=>list.add(artifact));
+return list;
+},new Set());
+}
+
+
+
+
+
+
+
+static generatePassesNeededByGatherers(passes,requiredGatherers){
+if(!passes){
+return null;
+}
+
+const auditsNeedTrace=requiredGatherers.has('traces');
+const filteredPasses=passes.map(pass=>{
+
+pass.gatherers=pass.gatherers.filter(gathererDefn=>{
+const gatherer=gathererDefn.instance;
+return requiredGatherers.has(gatherer.name);
+});
+
+
+if(pass.recordTrace&&!auditsNeedTrace){
+const passName=pass.passName||'unknown pass';
+log.warn('config',`Trace not requested by an audit, dropping trace in ${passName}`);
+pass.recordTrace=false;
+}
+
+return pass;
+}).filter(pass=>{
+
+if(pass.recordTrace)return true;
+
+if(pass.passName==='defaultPass')return true;
+return pass.gatherers.length>0;
+});
+return filteredPasses;
+}
+
+
+
+
+
+
+
+
+
+static requireAudits(audits,configDir){
+const status={msg:'Requiring audits',id:'lh:config:requireAudits'};
+log.time(status,'verbose');
+const expandedAudits=Config.expandAuditShorthand(audits);
+if(!expandedAudits){
+return null;
+}
+
+const coreList=Runner.getAuditList();
+const auditDefns=expandedAudits.map(audit=>{
+let implementation;
+if('implementation'in audit){
+implementation=audit.implementation;
+}else{
+
+const auditPathJs=`${audit.path}.js`;
+const coreAudit=coreList.find(a=>a===auditPathJs);
+let requirePath=`../audits/${audit.path}`;
+if(!coreAudit){
+
+requirePath=Config.resolveModule(audit.path,configDir,'audit');
+}
+implementation=require(requirePath);
+}
+
+return{
+implementation,
+path:audit.path,
+options:audit.options||{}};
+
+});
+
+const mergedAuditDefns=mergeOptionsOfItems(auditDefns);
+mergedAuditDefns.forEach(audit=>assertValidAudit(audit.implementation,audit.path));
+log.timeEnd(status);
+return mergedAuditDefns;
+}
+
+
+
+
+
+
+
+
+static requireGathererFromPath(path,options,coreAuditList,configDir){
+const coreGatherer=coreAuditList.find(a=>a===`${path}.js`);
+
+let requirePath=`../gather/gatherers/${path}`;
+if(!coreGatherer){
+
+requirePath=Config.resolveModule(path,configDir,'gatherer');
+}
+
+const GathererClass=require(requirePath);
+
+return{
+instance:new GathererClass(),
+implementation:GathererClass,
+path,
+options:options||{}};
+
+}
+
+
+
+
+
+
+
+
+
+static requireGatherers(passes,configDir){
+if(!passes){
+return null;
+}
+const status={msg:'Requiring gatherers',id:'lh:config:requireGatherers'};
+log.time(status,'verbose');
+
+const coreList=Runner.getGathererList();
+const fullPasses=passes.map(pass=>{
+const gathererDefns=Config.expandGathererShorthand(pass.gatherers).map(gathererDefn=>{
+if(gathererDefn.instance){
+return{
+instance:gathererDefn.instance,
+implementation:gathererDefn.implementation,
+path:gathererDefn.path,
+options:gathererDefn.options||{}};
+
+}else if(gathererDefn.implementation){
+const GathererClass=gathererDefn.implementation;
+return{
+instance:new GathererClass(),
+implementation:gathererDefn.implementation,
+path:gathererDefn.path,
+options:gathererDefn.options||{}};
+
+}else if(gathererDefn.path){
+const path=gathererDefn.path;
+const options=gathererDefn.options;
+return Config.requireGathererFromPath(path,options,coreList,configDir);
+}else{
+throw new Error('Invalid expanded Gatherer: '+JSON.stringify(gathererDefn));
+}
+});
+
+const mergedDefns=mergeOptionsOfItems(gathererDefns);
+mergedDefns.forEach(gatherer=>assertValidGatherer(gatherer.instance,gatherer.path));
+
+return Object.assign(pass,{gatherers:mergedDefns});
+});
+log.timeEnd(status);
+return fullPasses;
+}
+
+
+
+
+
+
+
+
+
+
+
+static resolveModule(moduleIdentifier,configDir,category){
+
+
+
+
+try{
+return require.resolve(moduleIdentifier);
+}catch(e){}
+
+
+
+
+const cwdPath=path.resolve(process.cwd(),moduleIdentifier);
+try{
+return require.resolve(cwdPath);
+}catch(e){}
+
+const errorString='Unable to locate '+(
+category?`${category}: `:'')+
+`${moduleIdentifier} (tried to require() from '${__dirname}' and load from '${cwdPath}'`;
+
+if(!configDir){
+throw new Error(errorString+')');
+}
+
+
+
+
+const relativePath=path.resolve(configDir,moduleIdentifier);
+try{
+return require.resolve(relativePath);
+}catch(requireError){}
+
+throw new Error(errorString+` and '${relativePath}')`);
+}}
+
+
+module.exports=Config;
+
+}).call(this,require('_process'),"/lighthouse-core/config");
+},{"../audits/audit.js":3,"../runner.js":76,"./../lib/i18n/i18n.js":59,"./constants.js":36,"./default-config.js":37,"./full-config.js":38,"_process":130,"lighthouse-logger":113,"lodash.isequal":114,"path":128}],36:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const DEVTOOLS_RTT_ADJUSTMENT_FACTOR=3.75;
+const DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR=0.9;
+
+const throttling={
+DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
+DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
+mobileSlow4G:{
+rttMs:150,
+throughputKbps:1.6*1024,
+requestLatencyMs:150*DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
+downloadThroughputKbps:1.6*1024*DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
+uploadThroughputKbps:750*DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
+cpuSlowdownMultiplier:4}};
+
+
+
+
+const defaultSettings={
+output:'json',
+maxWaitForLoad:45*1000,
+throttlingMethod:'simulate',
+throttling:throttling.mobileSlow4G,
+auditMode:false,
+gatherMode:false,
+disableStorageReset:false,
+disableDeviceEmulation:false,
+emulatedFormFactor:'mobile',
+
+
+
+locale:'en-US',
+blockedUrlPatterns:null,
+additionalTraceCategories:null,
+extraHeaders:null,
+onlyAudits:null,
+onlyCategories:null,
+skipAudits:null};
+
+
+
+const defaultPassConfig={
+passName:'defaultPass',
+recordTrace:false,
+useThrottling:false,
+pauseAfterLoadMs:0,
+networkQuietThresholdMs:0,
+cpuQuietThresholdMs:0,
+blockedUrlPatterns:[],
+blankPage:'about:blank',
+gatherers:[]};
+
+
+const nonSimulatedPassConfigOverrides={
+pauseAfterLoadMs:5250,
+networkQuietThresholdMs:5250,
+cpuQuietThresholdMs:5250};
+
+
+module.exports={
+throttling,
+defaultSettings,
+defaultPassConfig,
+nonSimulatedPassConfigOverrides};
+
+
+},{}],37:[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+
+
+const constants=require('./constants');
+const i18n=require('../lib/i18n/i18n.js');
+
+const UIStrings={
+
+performanceCategoryTitle:'Performance',
+
+metricGroupTitle:'Metrics',
+
+loadOpportunitiesGroupTitle:'Opportunities',
+
+loadOpportunitiesGroupDescription:'These optimizations can speed up your page load.',
+
+firstPaintImprovementsGroupTitle:'First Paint Improvements',
+
+firstPaintImprovementsGroupDescription:'The most critical aspect of performance is how quickly pixels are rendered onscreen. Key metrics: First Contentful Paint, First Meaningful Paint',
+
+overallImprovementsGroupTitle:'Overall Improvements',
+
+overallImprovementsGroupDescription:'Enhance the overall loading experience, so the page is responsive and ready to use as soon as possible. Key metrics: Time to Interactive, Speed Index',
+
+diagnosticsGroupTitle:'Diagnostics',
+
+diagnosticsGroupDescription:'More information about the performance of your application.',
+
+a11yColorContrastGroupTitle:'Color Contrast Is Satisfactory',
+
+a11yColorContrastGroupDescription:'These are opportunities to improve the legibility of your content.',
+
+a11yDescribeContentsGroupTitle:'Elements Describe Contents Well',
+
+a11yDescribeContentsGroupDescription:'These are opportunities to make your content easier to understand for a user of assistive technology, like a screen reader.',
+
+a11yWellStructuredGroupTitle:'Elements Are Well Structured',
+
+a11yWellStructuredGroupDescription:'These are opportunities to make sure your HTML is appropriately structured.',
+
+a11yAriaGroupTitle:'ARIA Attributes Follow Best Practices',
+
+a11yAriaGroupDescription:'These are opportunities to improve the usage of ARIA in your application which may enhance the experience for users of assistive technology, like a screen reader.',
+
+a11yCorrectAttributesGroupTitle:'Elements Use Attributes Correctly',
+
+a11yCorrectAttributesGroupDescription:'These are opportunities to improve the configuration of your HTML elements.',
+
+a11yElementNamesGroupTitle:'Elements Have Discernible Names',
+
+a11yElementNamesGroupDescription:'These are opportunities to improve the semantics of the controls in your application. This may enhance the experience for users of assistive technology, like a screen reader.',
+
+a11yLanguageGroupTitle:'Page Specifies Valid Language',
+
+a11yLanguageGroupDescription:'These are opportunities to improve the interpretation of your content by users in different locales.',
+
+a11yMetaGroupTitle:'Meta Tags Used Properly',
+
+a11yMetaGroupDescription:'These are opportunities to improve the user experience of your site.',
+
+pwaFastReliableGroupTitle:'Fast and reliable',
+
+pwaInstallableGroupTitle:'Installable',
+
+pwaOptimizedGroupTitle:'PWA Optimized'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+const defaultConfig={
+settings:constants.defaultSettings,
+passes:[{
+passName:'defaultPass',
+recordTrace:true,
+useThrottling:true,
+pauseAfterLoadMs:1000,
+networkQuietThresholdMs:1000,
+cpuQuietThresholdMs:1000,
+gatherers:[
+'scripts',
+'css-usage',
+'viewport',
+'viewport-dimensions',
+'theme-color',
+'manifest',
+'runtime-exceptions',
+'chrome-console-messages',
+'image-usage',
+'accessibility',
+'link-elements',
+'dobetterweb/anchors-with-no-rel-noopener',
+'dobetterweb/appcache',
+'dobetterweb/doctype',
+'dobetterweb/domstats',
+'dobetterweb/js-libraries',
+'dobetterweb/optimized-images',
+'dobetterweb/password-inputs-with-prevented-paste',
+'dobetterweb/response-compression',
+'dobetterweb/tags-blocking-first-paint',
+'seo/meta-description',
+'seo/font-size',
+'seo/crawlable-links',
+'seo/meta-robots',
+'seo/hreflang',
+'seo/embedded-content',
+'seo/canonical',
+'seo/robots-txt']},
+
+
+{
+passName:'offlinePass',
+gatherers:[
+'service-worker',
+'offline',
+'start-url']},
+
+
+{
+passName:'redirectPass',
+
+blockedUrlPatterns:['*.css','*.jpg','*.jpeg','*.png','*.gif','*.svg','*.ttf','*.woff','*.woff2'],
+gatherers:[
+'http-redirect',
+'html-without-javascript']}],
+
+
+audits:[
+'is-on-https',
+'redirects-http',
+'service-worker',
+'works-offline',
+'viewport',
+'without-javascript',
+'metrics/first-contentful-paint',
+'metrics/first-meaningful-paint',
+'load-fast-enough-for-pwa',
+'metrics/speed-index',
+'screenshot-thumbnails',
+'final-screenshot',
+'metrics/estimated-input-latency',
+'errors-in-console',
+'time-to-first-byte',
+'metrics/first-cpu-idle',
+'metrics/interactive',
+'user-timings',
+'critical-request-chains',
+'redirects',
+'installable-manifest',
+'splash-screen',
+'themed-omnibox',
+'content-width',
+'image-aspect-ratio',
+'deprecations',
+'mainthread-work-breakdown',
+'bootup-time',
+'uses-rel-preload',
+'uses-rel-preconnect',
+'font-display',
+'network-requests',
+'metrics',
+'offline-start-url',
+'manual/pwa-cross-browser',
+'manual/pwa-page-transitions',
+'manual/pwa-each-page-has-url',
+'accessibility/aria-allowed-attr',
+'accessibility/aria-required-attr',
+'accessibility/aria-required-children',
+'accessibility/aria-required-parent',
+'accessibility/aria-roles',
+'accessibility/aria-valid-attr-value',
+'accessibility/aria-valid-attr',
+'accessibility/audio-caption',
+'accessibility/button-name',
+'accessibility/bypass',
+'accessibility/color-contrast',
+'accessibility/definition-list',
+'accessibility/dlitem',
+'accessibility/document-title',
+'accessibility/duplicate-id',
+'accessibility/frame-title',
+'accessibility/html-has-lang',
+'accessibility/html-lang-valid',
+'accessibility/image-alt',
+'accessibility/input-image-alt',
+'accessibility/label',
+'accessibility/layout-table',
+'accessibility/link-name',
+'accessibility/list',
+'accessibility/listitem',
+'accessibility/meta-refresh',
+'accessibility/meta-viewport',
+'accessibility/object-alt',
+'accessibility/tabindex',
+'accessibility/td-headers-attr',
+'accessibility/th-has-data-cells',
+'accessibility/valid-lang',
+'accessibility/video-caption',
+'accessibility/video-description',
+'accessibility/manual/accesskeys',
+'accessibility/manual/custom-controls-labels',
+'accessibility/manual/custom-controls-roles',
+'accessibility/manual/focus-traps',
+'accessibility/manual/focusable-controls',
+'accessibility/manual/heading-levels',
+'accessibility/manual/interactive-element-affordance',
+'accessibility/manual/logical-tab-order',
+'accessibility/manual/managed-focus',
+'accessibility/manual/offscreen-content-hidden',
+'accessibility/manual/use-landmarks',
+'accessibility/manual/visual-order-follows-dom',
+'byte-efficiency/uses-long-cache-ttl',
+'byte-efficiency/total-byte-weight',
+'byte-efficiency/offscreen-images',
+'byte-efficiency/render-blocking-resources',
+'byte-efficiency/unminified-css',
+'byte-efficiency/unminified-javascript',
+'byte-efficiency/unused-css-rules',
+'byte-efficiency/uses-webp-images',
+'byte-efficiency/uses-optimized-images',
+'byte-efficiency/uses-text-compression',
+'byte-efficiency/uses-responsive-images',
+'byte-efficiency/efficient-animated-content',
+'dobetterweb/appcache-manifest',
+'dobetterweb/doctype',
+'dobetterweb/dom-size',
+'dobetterweb/external-anchors-use-rel-noopener',
+'dobetterweb/geolocation-on-start',
+'dobetterweb/no-document-write',
+'dobetterweb/no-vulnerable-libraries',
+'dobetterweb/js-libraries',
+'dobetterweb/notification-on-start',
+'dobetterweb/password-inputs-can-be-pasted-into',
+'dobetterweb/uses-http2',
+'dobetterweb/uses-passive-event-listeners',
+'seo/meta-description',
+'seo/http-status-code',
+'seo/font-size',
+'seo/link-text',
+'seo/is-crawlable',
+'seo/robots-txt',
+'seo/hreflang',
+'seo/plugins',
+'seo/canonical',
+'seo/manual/mobile-friendly',
+'seo/manual/structured-data'],
+
+
+groups:{
+'metrics':{
+title:str_(UIStrings.metricGroupTitle)},
+
+'load-opportunities':{
+title:str_(UIStrings.loadOpportunitiesGroupTitle),
+description:str_(UIStrings.loadOpportunitiesGroupDescription)},
+
+'diagnostics':{
+title:str_(UIStrings.diagnosticsGroupTitle),
+description:str_(UIStrings.diagnosticsGroupDescription)},
+
+'pwa-fast-reliable':{
+title:str_(UIStrings.pwaFastReliableGroupTitle)},
+
+'pwa-installable':{
+title:str_(UIStrings.pwaInstallableGroupTitle)},
+
+'pwa-optimized':{
+title:str_(UIStrings.pwaOptimizedGroupTitle)},
+
+'a11y-color-contrast':{
+title:str_(UIStrings.a11yColorContrastGroupTitle),
+description:str_(UIStrings.a11yColorContrastGroupDescription)},
+
+'a11y-describe-contents':{
+title:str_(UIStrings.a11yDescribeContentsGroupTitle),
+description:str_(UIStrings.a11yDescribeContentsGroupDescription)},
+
+'a11y-well-structured':{
+title:str_(UIStrings.a11yWellStructuredGroupTitle),
+description:str_(UIStrings.a11yWellStructuredGroupDescription)},
+
+'a11y-aria':{
+title:str_(UIStrings.a11yAriaGroupTitle),
+description:str_(UIStrings.a11yAriaGroupDescription)},
+
+'a11y-correct-attributes':{
+title:str_(UIStrings.a11yCorrectAttributesGroupTitle),
+description:str_(UIStrings.a11yCorrectAttributesGroupDescription)},
+
+'a11y-element-names':{
+title:str_(UIStrings.a11yElementNamesGroupTitle),
+description:str_(UIStrings.a11yElementNamesGroupDescription)},
+
+'a11y-language':{
+title:str_(UIStrings.a11yLanguageGroupTitle),
+description:str_(UIStrings.a11yLanguageGroupDescription)},
+
+'a11y-meta':{
+title:str_(UIStrings.a11yMetaGroupTitle),
+description:str_(UIStrings.a11yMetaGroupDescription)},
+
+'seo-mobile':{
+title:'Mobile Friendly',
+description:'Make sure your pages are mobile friendly so users don’t have to pinch or zoom '+
+'in order to read the content pages. [Learn more](https://developers.google.com/search/mobile-sites/).'},
+
+'seo-content':{
+title:'Content Best Practices',
+description:'Format your HTML in a way that enables crawlers to better understand your app’s content.'},
+
+'seo-crawl':{
+title:'Crawling and Indexing',
+description:'To appear in search results, crawlers need access to your app.'}},
+
+
+categories:{
+'performance':{
+title:str_(UIStrings.performanceCategoryTitle),
+auditRefs:[
+{id:'first-contentful-paint',weight:3,group:'metrics'},
+{id:'first-meaningful-paint',weight:1,group:'metrics'},
+{id:'speed-index',weight:4,group:'metrics'},
+{id:'interactive',weight:5,group:'metrics'},
+{id:'first-cpu-idle',weight:2,group:'metrics'},
+{id:'estimated-input-latency',weight:0,group:'metrics'},
+
+{id:'render-blocking-resources',weight:0,group:'load-opportunities'},
+{id:'uses-responsive-images',weight:0,group:'load-opportunities'},
+{id:'offscreen-images',weight:0,group:'load-opportunities'},
+{id:'unminified-css',weight:0,group:'load-opportunities'},
+{id:'unminified-javascript',weight:0,group:'load-opportunities'},
+{id:'unused-css-rules',weight:0,group:'load-opportunities'},
+{id:'uses-optimized-images',weight:0,group:'load-opportunities'},
+{id:'uses-webp-images',weight:0,group:'load-opportunities'},
+{id:'uses-text-compression',weight:0,group:'load-opportunities'},
+{id:'uses-rel-preconnect',weight:0,group:'load-opportunities'},
+{id:'time-to-first-byte',weight:0,group:'load-opportunities'},
+{id:'redirects',weight:0,group:'load-opportunities'},
+{id:'uses-rel-preload',weight:0,group:'load-opportunities'},
+{id:'efficient-animated-content',weight:0,group:'load-opportunities'},
+{id:'total-byte-weight',weight:0,group:'diagnostics'},
+{id:'uses-long-cache-ttl',weight:0,group:'diagnostics'},
+{id:'dom-size',weight:0,group:'diagnostics'},
+{id:'critical-request-chains',weight:0,group:'diagnostics'},
+{id:'network-requests',weight:0},
+{id:'metrics',weight:0},
+{id:'user-timings',weight:0,group:'diagnostics'},
+{id:'bootup-time',weight:0,group:'diagnostics'},
+{id:'screenshot-thumbnails',weight:0},
+{id:'final-screenshot',weight:0},
+{id:'mainthread-work-breakdown',weight:0,group:'diagnostics'},
+{id:'font-display',weight:0,group:'diagnostics'}]},
+
+
+'accessibility':{
+title:'Accessibility',
+description:'These checks highlight opportunities to [improve the accessibility of your web app](https://developers.google.com/web/fundamentals/accessibility). Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.',
+manualDescription:'These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://developers.google.com/web/fundamentals/accessibility/how-to-review).',
+auditRefs:[
+{id:'aria-allowed-attr',weight:3,group:'a11y-aria'},
+{id:'aria-required-attr',weight:2,group:'a11y-aria'},
+{id:'aria-required-children',weight:5,group:'a11y-aria'},
+{id:'aria-required-parent',weight:2,group:'a11y-aria'},
+{id:'aria-roles',weight:3,group:'a11y-aria'},
+{id:'aria-valid-attr-value',weight:2,group:'a11y-aria'},
+{id:'aria-valid-attr',weight:5,group:'a11y-aria'},
+{id:'audio-caption',weight:4,group:'a11y-correct-attributes'},
+{id:'button-name',weight:10,group:'a11y-element-names'},
+{id:'bypass',weight:10,group:'a11y-describe-contents'},
+{id:'color-contrast',weight:6,group:'a11y-color-contrast'},
+{id:'definition-list',weight:1,group:'a11y-well-structured'},
+{id:'dlitem',weight:1,group:'a11y-well-structured'},
+{id:'document-title',weight:2,group:'a11y-describe-contents'},
+{id:'duplicate-id',weight:5,group:'a11y-well-structured'},
+{id:'frame-title',weight:5,group:'a11y-describe-contents'},
+{id:'html-has-lang',weight:4,group:'a11y-language'},
+{id:'html-lang-valid',weight:1,group:'a11y-language'},
+{id:'image-alt',weight:8,group:'a11y-correct-attributes'},
+{id:'input-image-alt',weight:1,group:'a11y-correct-attributes'},
+{id:'label',weight:10,group:'a11y-describe-contents'},
+{id:'layout-table',weight:1,group:'a11y-describe-contents'},
+{id:'link-name',weight:9,group:'a11y-element-names'},
+{id:'list',weight:5,group:'a11y-well-structured'},
+{id:'listitem',weight:4,group:'a11y-well-structured'},
+{id:'meta-refresh',weight:1,group:'a11y-meta'},
+{id:'meta-viewport',weight:3,group:'a11y-meta'},
+{id:'object-alt',weight:4,group:'a11y-describe-contents'},
+{id:'tabindex',weight:4,group:'a11y-correct-attributes'},
+{id:'td-headers-attr',weight:1,group:'a11y-correct-attributes'},
+{id:'th-has-data-cells',weight:1,group:'a11y-correct-attributes'},
+{id:'valid-lang',weight:1,group:'a11y-language'},
+{id:'video-caption',weight:4,group:'a11y-describe-contents'},
+{id:'video-description',weight:3,group:'a11y-describe-contents'},
+
+{id:'accesskeys',weight:0},
+{id:'logical-tab-order',weight:0},
+{id:'focusable-controls',weight:0},
+{id:'interactive-element-affordance',weight:0},
+{id:'managed-focus',weight:0},
+{id:'focus-traps',weight:0},
+{id:'custom-controls-labels',weight:0},
+{id:'custom-controls-roles',weight:0},
+{id:'visual-order-follows-dom',weight:0},
+{id:'offscreen-content-hidden',weight:0},
+{id:'heading-levels',weight:0},
+{id:'use-landmarks',weight:0}]},
+
+
+'best-practices':{
+title:'Best Practices',
+auditRefs:[
+{id:'appcache-manifest',weight:1},
+{id:'is-on-https',weight:1},
+{id:'uses-http2',weight:1},
+{id:'uses-passive-event-listeners',weight:1},
+{id:'no-document-write',weight:1},
+{id:'external-anchors-use-rel-noopener',weight:1},
+{id:'geolocation-on-start',weight:1},
+{id:'doctype',weight:1},
+{id:'no-vulnerable-libraries',weight:1},
+{id:'js-libraries',weight:0},
+{id:'notification-on-start',weight:1},
+{id:'deprecations',weight:1},
+{id:'password-inputs-can-be-pasted-into',weight:1},
+{id:'errors-in-console',weight:1},
+{id:'image-aspect-ratio',weight:1}]},
+
+
+'seo':{
+title:'SEO',
+description:'These checks ensure that your page is optimized for search engine results ranking. '+
+'There are additional factors Lighthouse does not check that may affect your search ranking. '+
+'[Learn more](https://support.google.com/webmasters/answer/35769).',
+manualDescription:'Run these additional validators on your site to check additional SEO best practices.',
+auditRefs:[
+{id:'viewport',weight:1,group:'seo-mobile'},
+{id:'document-title',weight:1,group:'seo-content'},
+{id:'meta-description',weight:1,group:'seo-content'},
+{id:'http-status-code',weight:1,group:'seo-crawl'},
+{id:'link-text',weight:1,group:'seo-content'},
+{id:'is-crawlable',weight:1,group:'seo-crawl'},
+{id:'robots-txt',weight:1,group:'seo-crawl'},
+{id:'hreflang',weight:1,group:'seo-content'},
+{id:'canonical',weight:1,group:'seo-content'},
+{id:'font-size',weight:1,group:'seo-mobile'},
+{id:'plugins',weight:1,group:'seo-content'},
+
+{id:'mobile-friendly',weight:0},
+{id:'structured-data',weight:0}]},
+
+
+'pwa':{
+title:'Progressive Web App',
+description:'These checks validate the aspects of a Progressive Web App. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist).',
+manualDescription:'These checks are required by the baseline '+
+'[PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are '+
+'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
+auditRefs:[
+
+{id:'load-fast-enough-for-pwa',weight:7,group:'pwa-fast-reliable'},
+{id:'works-offline',weight:5,group:'pwa-fast-reliable'},
+{id:'offline-start-url',weight:1,group:'pwa-fast-reliable'},
+
+{id:'is-on-https',weight:2,group:'pwa-installable'},
+{id:'service-worker',weight:1,group:'pwa-installable'},
+{id:'installable-manifest',weight:2,group:'pwa-installable'},
+
+{id:'redirects-http',weight:2,group:'pwa-optimized'},
+{id:'splash-screen',weight:1,group:'pwa-optimized'},
+{id:'themed-omnibox',weight:1,group:'pwa-optimized'},
+{id:'content-width',weight:1,group:'pwa-optimized'},
+{id:'viewport',weight:2,group:'pwa-optimized'},
+{id:'without-javascript',weight:1,group:'pwa-optimized'},
+
+{id:'pwa-cross-browser',weight:0},
+{id:'pwa-page-transitions',weight:0},
+{id:'pwa-each-page-has-url',weight:0}]}}};
+
+
+
+
+
+module.exports=defaultConfig;
+
+
+Object.defineProperty(module.exports,'UIStrings',{
+enumerable:false,
+get:()=>UIStrings});
+
+
+}).call(this,"/lighthouse-core/config/default-config.js");
+},{"../lib/i18n/i18n.js":59,"./constants":36}],38:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+const fullConfig={
+extends:'lighthouse:default',
+settings:{},
+passes:[
+{
+passName:'extraPass',
+gatherers:[
+'js-usage']}],
+
+
+
+audits:[
+'byte-efficiency/unused-javascript'],
+
+
+categories:{
+'performance':{
+auditRefs:[
+{id:'unused-javascript',weight:0,group:'load-opportunities'}]}}};
+
+
+
+
+
+module.exports=fullConfig;
+
+},{}],39:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const EventEmitter=require('events').EventEmitter;
+const log=require('lighthouse-logger');
+const LHError=require('../../lib/lh-error');
+
+
+
+
+
+
+
+
+
+
+class Connection{
+constructor(){
+this._lastCommandId=0;
+
+this._callbacks=new Map();
+
+this._eventEmitter=new EventEmitter();
+}
+
+
+
+
+connect(){
+return Promise.reject(new Error('Not implemented'));
+}
+
+
+
+
+disconnect(){
+return Promise.reject(new Error('Not implemented'));
+}
+
+
+
+
+wsEndpoint(){
+return Promise.reject(new Error('Not implemented'));
+}
+
+
+
+
+
+
+
+
+sendCommand(method,...paramArgs){
+
+const params=paramArgs.length?paramArgs[0]:undefined;
+
+log.formatProtocol('method => browser',{method,params},'verbose');
+const id=++this._lastCommandId;
+const message=JSON.stringify({id,method,params});
+this.sendRawMessage(message);
+
+return new Promise(resolve=>{
+this._callbacks.set(id,{method,resolve});
+});
+}
+
+
+
+
+
+
+on(eventName,cb){
+if(eventName!=='protocolevent'){
+throw new Error('Only supports "protocolevent" events');
+}
+
+if(!this._eventEmitter){
+throw new Error('Attempted to add event listener after connection disposed.');
+}
+this._eventEmitter.on(eventName,cb);
+}
+
+
+
+
+
+
+
+sendRawMessage(message){
+throw new Error('Not implemented');
+}
+
+
+
+
+
+
+
+
+handleRawMessage(message){
+const object=JSON.parse(message);
+
+
+if(!('id'in object)){
+log.formatProtocol('<= event',
+{method:object.method,params:object.params},'verbose');
+this.emitProtocolEvent(object);
+return;
+}
+
+const callback=this._callbacks.get(object.id);
+if(callback){
+this._callbacks.delete(object.id);
+
+return callback.resolve(Promise.resolve().then(_=>{
+if(object.error){
+log.formatProtocol('method <= browser ERR',{method:callback.method},'error');
+throw LHError.fromProtocolMessage(callback.method,object.error);
+}
+
+log.formatProtocol('method <= browser OK',
+{method:callback.method,params:object.result},'verbose');
+return object.result;
+}));
+}else{
+
+
+const error=object.error&&object.error.message;
+log.formatProtocol(`disowned method <= browser ${error?'ERR':'OK'}`,
+{method:'UNKNOWN',params:error||object.result},'verbose');
+}
+}
+
+
+
+
+emitProtocolEvent(eventMessage){
+if(!this._eventEmitter){
+throw new Error('Attempted to emit event after connection disposed.');
+}
+
+this._eventEmitter.emit('protocolevent',eventMessage);
+}
+
+
+
+
+dispose(){
+if(this._eventEmitter){
+this._eventEmitter.removeAllListeners();
+this._eventEmitter=null;
+}
+}}
+
+
+module.exports=Connection;
+
+},{"../../lib/lh-error":63,"events":93,"lighthouse-logger":113}],40:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Connection=require('./connection.js');
+
+
+
+
+
+
+
+
+
+
+
+
+class RawConnection extends Connection{
+
+
+
+constructor(port){
+super();
+this._port=port;
+this._port.on('message',this.handleRawMessage.bind(this));
+this._port.on('close',this.dispose.bind(this));
+}
+
+
+
+
+
+connect(){
+return Promise.resolve();
+}
+
+
+
+
+disconnect(){
+this._port.close();
+return Promise.resolve();
+}
+
+
+
+
+
+
+sendRawMessage(message){
+this._port.send(message);
+}}
+
+
+module.exports=RawConnection;
+
+},{"./connection.js":39}],41:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+class DevtoolsLog{
+
+
+
+constructor(regexFilter){
+this._filter=regexFilter;
+
+
+this._messages=[];
+this._isRecording=false;
+}
+
+
+
+
+get messages(){
+return this._messages;
+}
+
+reset(){
+this._messages=[];
+}
+
+beginRecording(){
+this._isRecording=true;
+}
+
+endRecording(){
+this._isRecording=false;
+}
+
+
+
+
+
+record(message){
+if(this._isRecording&&(!this._filter||this._filter.test(message.method))){
+this._messages.push(message);
+}
+}}
+
+
+module.exports=DevtoolsLog;
+
+},{}],42:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const NetworkRecorder=require('../lib/network-recorder');
+const emulation=require('../lib/emulation');
+const Element=require('../lib/element');
+const LHError=require('../lib/lh-error');
+const NetworkRequest=require('../lib/network-request');
+const EventEmitter=require('events').EventEmitter;
+const URL=require('../lib/url-shim');
+const constants=require('../config/constants');
+
+const log=require('lighthouse-logger');
+const DevtoolsLog=require('./devtools-log');
+
+const pageFunctions=require('../lib/page-functions.js');
+
+
+
+const Connection=require('./connections/connection.js');
+
+
+const DEFAULT_PAUSE_AFTER_LOAD=0;
+
+const DEFAULT_NETWORK_QUIET_THRESHOLD=5000;
+
+const DEFAULT_CPU_QUIET_THRESHOLD=0;
+
+const DEFAULT_PROTOCOL_TIMEOUT=30000;
+
+
+
+
+
+class Driver{
+
+
+
+constructor(connection){
+this._traceCategories=Driver.traceCategories;
+
+
+
+this._eventEmitter=new EventEmitter();
+this._connection=connection;
+
+this._devtoolsLog=new DevtoolsLog(/^(Page|Network)\./);
+this.online=true;
+
+this._domainEnabledCounts=new Map();
+
+this._isolatedExecutionContextId=undefined;
+
+
+
+
+
+
+this._networkStatusMonitor=null;
+
+
+
+
+
+
+this._monitoredUrl=null;
+
+connection.on('protocolevent',event=>{
+this._devtoolsLog.record(event);
+if(this._networkStatusMonitor){
+this._networkStatusMonitor.dispatch(event);
+}
+
+
+
+
+this._eventEmitter.emit(event.method,event.params);
+});
+
+
+
+
+
+this._nextProtocolTimeout=DEFAULT_PROTOCOL_TIMEOUT;
+}
+
+static get traceCategories(){
+return[
+
+'-*',
+
+
+'disabled-by-default-lighthouse',
+
+
+
+'v8',
+
+
+'v8.execute',
+
+
+'blink.user_timing',
+
+
+'blink.console',
+
+
+'devtools.timeline',
+'disabled-by-default-devtools.timeline',
+
+
+'disabled-by-default-devtools.screenshot',
+
+
+'disabled-by-default-devtools.timeline.stack'];
+
+
+
+
+
+}
+
+
+
+
+async getBrowserVersion(){
+const status={msg:'Getting browser version',id:'lh:gather:getVersion'};
+log.time(status,'verbose');
+const version=await this.sendCommand('Browser.getVersion');
+const match=version.product.match(/\/(\d+)/);
+const milestone=match?parseInt(match[1]):0;
+log.timeEnd(status);
+return Object.assign(version,{milestone});
+}
+
+
+
+
+
+async getBenchmarkIndex(){
+const status={msg:'Benchmarking machine',id:'lh:gather:getBenchmarkIndex'};
+log.time(status);
+const indexVal=await this.evaluateAsync(`(${pageFunctions.ultradumbBenchmarkString})()`);
+log.timeEnd(status);
+return indexVal;
+}
+
+
+
+
+async connect(){
+const status={msg:'Connecting to browser',id:'lh:init:connect'};
+log.time(status);
+await this._connection.connect();
+log.timeEnd(status);
+}
+
+
+
+
+disconnect(){
+return this._connection.disconnect();
+}
+
+
+
+
+
+
+wsEndpoint(){
+return this._connection.wsEndpoint();
+}
+
+
+
+
+
+
+
+on(eventName,cb){
+if(this._eventEmitter===null){
+throw new Error('connect() must be called before attempting to listen to events.');
+}
+
+
+log.formatProtocol('listen for event =>',{method:eventName},'verbose');
+this._eventEmitter.on(eventName,cb);
+}
+
+
+
+
+
+
+
+
+once(eventName,cb){
+if(this._eventEmitter===null){
+throw new Error('connect() must be called before attempting to listen to events.');
+}
+
+log.formatProtocol('listen once for event =>',{method:eventName},'verbose');
+this._eventEmitter.once(eventName,cb);
+}
+
+
+
+
+
+
+
+off(eventName,cb){
+if(this._eventEmitter===null){
+throw new Error('connect() must be called before attempting to remove an event listener.');
+}
+
+this._eventEmitter.removeListener(eventName,cb);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+_shouldToggleDomain(domain,enable){
+const enabledCount=this._domainEnabledCounts.get(domain)||0;
+const newCount=enabledCount+(enable?1:-1);
+this._domainEnabledCounts.set(domain,Math.max(0,newCount));
+
+
+if(enable&&newCount===1||!enable&&newCount===0){
+log.verbose('Driver',`${domain}.${enable?'enable':'disable'}`);
+return true;
+}else{
+if(newCount<0){
+log.error('Driver',`Attempted to disable domain '${domain}' when already disabled.`);
+}
+return false;
+}
+}
+
+
+
+
+
+
+
+setNextProtocolTimeout(timeout){
+this._nextProtocolTimeout=timeout;
+}
+
+
+
+
+
+
+
+
+
+sendCommand(method,...params){
+const timeout=this._nextProtocolTimeout;
+this._nextProtocolTimeout=DEFAULT_PROTOCOL_TIMEOUT;
+return new Promise(async(resolve,reject)=>{
+const asyncTimeout=setTimeout(()=>{
+const err=new LHError(
+LHError.errors.PROTOCOL_TIMEOUT,
+{protocolMethod:method});
+
+reject(err);
+},timeout);
+try{
+const result=await this._innerSendCommand(method,...params);
+resolve(result);
+}catch(err){
+reject(err);
+}finally{
+clearTimeout(asyncTimeout);
+}
+});
+}
+
+
+
+
+
+
+
+
+
+_innerSendCommand(method,...params){
+const domainCommand=/^(\w+)\.(enable|disable)$/.exec(method);
+if(domainCommand){
+const enable=domainCommand[2]==='enable';
+if(!this._shouldToggleDomain(domainCommand[1],enable)){
+return Promise.resolve();
+}
+}
+return this._connection.sendCommand(method,...params);
+}
+
+
+
+
+
+
+isDomainEnabled(domain){
+
+return!!this._domainEnabledCounts.get(domain);
+}
+
+
+
+
+
+
+evaluateScriptOnNewDocument(scriptSource){
+return this.sendCommand('Page.addScriptToEvaluateOnLoad',{
+scriptSource});
+
+}
+
+
+
+
+
+
+
+
+
+
+evaluateAsync(expression,options={}){
+
+
+
+const contextIdPromise=options.useIsolation?
+this._getOrCreateIsolatedContextId():
+Promise.resolve(undefined);
+return contextIdPromise.then(contextId=>this._evaluateInContext(expression,contextId));
+}
+
+
+
+
+
+
+
+
+async _evaluateInContext(expression,contextId){
+const evaluationParams={
+
+
+
+
+
+expression:`(function wrapInNativePromise() {
+ const __nativePromise = window.__nativePromise || Promise;
+ const URL = window.__nativeURL || window.URL;
+ return new __nativePromise(function (resolve) {
+ return __nativePromise.resolve()
+ .then(_ => ${expression})
+ .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString})
+ .then(resolve);
+ });
+ }())`,
+includeCommandLineAPI:true,
+awaitPromise:true,
+returnByValue:true,
+timeout:60000,
+contextId};
+
+
+this.setNextProtocolTimeout(60000);
+const response=await this.sendCommand('Runtime.evaluate',evaluationParams);
+if(response.exceptionDetails){
+
+return Promise.reject(new Error(`Evaluation exception: ${response.exceptionDetails.text}`));
+}
+
+if(response.result===undefined){
+return Promise.reject(
+new Error('Runtime.evaluate response did not contain a "result" object'));
+}
+const value=response.result.value;
+if(value&&value.__failedInBrowser){
+return Promise.reject(Object.assign(new Error(),value));
+}else{
+return value;
+}
+}
+
+
+
+
+getAppManifest(){
+return this.sendCommand('Page.getAppManifest').
+then(response=>{
+
+
+
+if(!response.data){
+
+return null;
+}
+
+return response;
+});
+}
+
+
+
+
+getServiceWorkerVersions(){
+return new Promise((resolve,reject)=>{
+
+
+
+const versionUpdatedListener=data=>{
+
+
+const activateCandidates=data.versions.filter(sw=>{
+return sw.status!=='redundant';
+});
+const hasActiveServiceWorker=activateCandidates.find(sw=>{
+return sw.status==='activated';
+});
+
+if(!activateCandidates.length||hasActiveServiceWorker){
+this.off('ServiceWorker.workerVersionUpdated',versionUpdatedListener);
+this.sendCommand('ServiceWorker.disable').
+then(_=>resolve(data),reject);
+}
+};
+
+this.on('ServiceWorker.workerVersionUpdated',versionUpdatedListener);
+
+this.sendCommand('ServiceWorker.enable').catch(reject);
+});
+}
+
+
+
+
+getServiceWorkerRegistrations(){
+return new Promise((resolve,reject)=>{
+this.once('ServiceWorker.workerRegistrationUpdated',data=>{
+this.sendCommand('ServiceWorker.disable').
+then(_=>resolve(data),reject);
+});
+
+this.sendCommand('ServiceWorker.enable').catch(reject);
+});
+}
+
+
+
+
+
+
+
+
+assertNoSameOriginServiceWorkerClients(pageUrl){
+
+let registrations;
+
+let versions;
+
+return this.getServiceWorkerRegistrations().then(data=>{
+registrations=data.registrations;
+}).then(_=>this.getServiceWorkerVersions()).then(data=>{
+versions=data.versions;
+}).then(_=>{
+const origin=new URL(pageUrl).origin;
+
+registrations.
+filter(reg=>{
+const swOrigin=new URL(reg.scopeURL).origin;
+
+return origin===swOrigin;
+}).
+forEach(reg=>{
+versions.forEach(ver=>{
+
+if(ver.registrationId!==reg.registrationId){
+return;
+}
+
+
+if(ver.controlledClients&&ver.controlledClients.length>0){
+throw new Error('You probably have multiple tabs open to the same origin.');
+}
+});
+});
+});
+}
+
+
+
+
+
+
+
+_waitForNothing(){
+return{promise:Promise.resolve(),cancel(){}};
+}
+
+
+
+
+
+_waitForFrameNavigated(){
+return new Promise(resolve=>{
+this.once('Page.frameNavigated',resolve);
+});
+}
+
+
+
+
+
+_waitForFCP(){
+
+let cancel=()=>{
+throw new Error('_waitForFCP.cancel() called before it was defined');
+};
+
+const promise=new Promise(resolve=>{
+
+const lifecycleListener=e=>{
+if(e.name==='firstContentfulPaint'){
+cancel();
+resolve();
+}
+};
+
+this.on('Page.lifecycleEvent',lifecycleListener);
+
+let canceled=false;
+cancel=()=>{
+if(canceled)return;
+canceled=true;
+this.off('Page.lifecycleEvent',lifecycleListener);
+};
+});
+
+return{
+promise,
+cancel};
+
+}
+
+
+
+
+
+
+
+
+_waitForNetworkIdle(networkQuietThresholdMs){
+let hasDCLFired=false;
+
+let idleTimeout;
+
+let cancel=()=>{
+throw new Error('_waitForNetworkIdle.cancel() called before it was defined');
+};
+
+
+
+if(!this._networkStatusMonitor){
+throw new Error('Driver._waitForNetworkIdle called with no networkStatusMonitor');
+}
+const networkStatusMonitor=this._networkStatusMonitor;
+
+const promise=new Promise((resolve,reject)=>{
+const onIdle=()=>{
+
+networkStatusMonitor.once('network-2-busy',onBusy);
+idleTimeout=setTimeout(_=>{
+cancel();
+resolve();
+},networkQuietThresholdMs);
+};
+
+const onBusy=()=>{
+networkStatusMonitor.once('network-2-idle',onIdle);
+idleTimeout&&clearTimeout(idleTimeout);
+};
+
+const domContentLoadedListener=()=>{
+hasDCLFired=true;
+if(networkStatusMonitor.is2Idle()){
+onIdle();
+}else{
+onBusy();
+}
+};
+
+
+
+const logStatus=()=>{
+if(!hasDCLFired){
+log.verbose('Driver','Waiting on DomContentLoaded');
+return;
+}
+
+const inflightRecords=networkStatusMonitor.getInflightRecords();
+
+
+if(inflightRecords.length<20){
+for(const record of inflightRecords){
+log.verbose('Driver',`Waiting on ${record.url.slice(0,120)} to finish`);
+}
+}
+};
+
+networkStatusMonitor.on('requeststarted',logStatus);
+networkStatusMonitor.on('requestloaded',logStatus);
+networkStatusMonitor.on('network-2-busy',logStatus);
+
+this.once('Page.domContentEventFired',domContentLoadedListener);
+let canceled=false;
+cancel=()=>{
+if(canceled)return;
+canceled=true;
+idleTimeout&&clearTimeout(idleTimeout);
+this.off('Page.domContentEventFired',domContentLoadedListener);
+networkStatusMonitor.removeListener('network-2-busy',onBusy);
+networkStatusMonitor.removeListener('network-2-idle',onIdle);
+networkStatusMonitor.removeListener('requeststarted',logStatus);
+networkStatusMonitor.removeListener('requestloaded',logStatus);
+networkStatusMonitor.removeListener('network-2-busy',logStatus);
+};
+});
+
+return{
+promise,
+cancel};
+
+}
+
+
+
+
+
+
+_waitForCPUIdle(waitForCPUQuiet){
+if(!waitForCPUQuiet){
+return{
+promise:Promise.resolve(),
+cancel:()=>undefined};
+
+}
+
+
+let lastTimeout;
+let canceled=false;
+
+const checkForQuietExpression=`(${pageFunctions.checkTimeSinceLastLongTaskString})()`;
+
+
+
+
+
+async function checkForQuiet(driver,resolve){
+if(canceled)return;
+const timeSinceLongTask=await driver.evaluateAsync(checkForQuietExpression);
+if(canceled)return;
+
+if(typeof timeSinceLongTask==='number'){
+if(timeSinceLongTask>=waitForCPUQuiet){
+log.verbose('Driver',`CPU has been idle for ${timeSinceLongTask} ms`);
+resolve();
+}else{
+log.verbose('Driver',`CPU has been idle for ${timeSinceLongTask} ms`);
+const timeToWait=waitForCPUQuiet-timeSinceLongTask;
+lastTimeout=setTimeout(()=>checkForQuiet(driver,resolve),timeToWait);
+}
+}
+}
+
+
+let cancel=()=>{
+throw new Error('_waitForCPUIdle.cancel() called before it was defined');
+};
+const promise=new Promise((resolve,reject)=>{
+checkForQuiet(this,resolve).catch(reject);
+cancel=()=>{
+if(canceled)return;
+canceled=true;
+if(lastTimeout)clearTimeout(lastTimeout);
+reject(new Error('Wait for CPU idle canceled'));
+};
+});
+
+return{
+promise,
+cancel};
+
+}
+
+
+
+
+
+
+
+
+_waitForLoadEvent(pauseAfterLoadMs){
+
+let cancel=()=>{
+throw new Error('_waitForLoadEvent.cancel() called before it was defined');
+};
+
+const promise=new Promise((resolve,reject)=>{
+
+let loadTimeout;
+const loadListener=function(){
+loadTimeout=setTimeout(resolve,pauseAfterLoadMs);
+};
+this.once('Page.loadEventFired',loadListener);
+
+let canceled=false;
+cancel=()=>{
+if(canceled)return;
+canceled=true;
+this.off('Page.loadEventFired',loadListener);
+loadTimeout&&clearTimeout(loadTimeout);
+};
+});
+
+return{
+promise,
+cancel};
+
+}
+
+
+
+
+
+
+
+_monitorForInsecureState(){
+
+let cancel=()=>{
+throw new Error('_monitorForInsecureState.cancel() called before it was defined');
+};
+
+const promise=new Promise((resolve,reject)=>{
+
+
+
+const securityStateChangedListener=({securityState,explanations})=>{
+if(securityState==='insecure'){
+cancel();
+const insecureDescriptions=explanations.
+filter(exp=>exp.securityState==='insecure').
+map(exp=>exp.description);
+resolve(insecureDescriptions.join(' '));
+}
+};
+let canceled=false;
+cancel=()=>{
+if(canceled)return;
+canceled=true;
+this.off('Security.securityStateChanged',securityStateChangedListener);
+
+this.sendCommand('Security.disable').catch(()=>{});
+};
+this.on('Security.securityStateChanged',securityStateChangedListener);
+this.sendCommand('Security.enable').catch(()=>{});
+});
+
+return{
+promise,
+cancel};
+
+}
+
+
+
+
+
+async isPageHung(){
+try{
+this.setNextProtocolTimeout(1000);
+await this.sendCommand('Runtime.evaluate',{
+expression:'"ping"',
+returnByValue:true,
+timeout:1000});
+
+
+return false;
+}catch(err){
+return true;
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+async _waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
+maxWaitForLoadedMs,shouldWaitForFCP){
+
+let maxTimeoutHandle;
+
+
+const waitForFCP=shouldWaitForFCP?this._waitForFCP():this._waitForNothing();
+
+const waitForLoadEvent=this._waitForLoadEvent(pauseAfterLoadMs);
+
+const waitForNetworkIdle=this._waitForNetworkIdle(networkQuietThresholdMs);
+
+let waitForCPUIdle=this._waitForNothing();
+
+const monitorForInsecureState=this._monitorForInsecureState();
+const securityCheckPromise=monitorForInsecureState.promise.then(securityMessages=>{
+return function(){
+throw new LHError(LHError.errors.INSECURE_DOCUMENT_REQUEST,{securityMessages});
+};
+});
+
+
+
+const loadPromise=Promise.all([
+waitForFCP.promise,
+waitForLoadEvent.promise,
+waitForNetworkIdle.promise]).
+then(()=>{
+waitForCPUIdle=this._waitForCPUIdle(cpuQuietThresholdMs);
+return waitForCPUIdle.promise;
+}).then(()=>{
+return function(){
+log.verbose('Driver','loadEventFired and network considered idle');
+};
+});
+
+
+
+const maxTimeoutPromise=new Promise((resolve,reject)=>{
+maxTimeoutHandle=setTimeout(resolve,maxWaitForLoadedMs);
+}).then(_=>{
+return async()=>{
+log.warn('Driver','Timed out waiting for page load. Checking if page is hung...');
+if(await this.isPageHung()){
+log.warn('Driver','Page appears to be hung, killing JavaScript...');
+await this.sendCommand('Emulation.setScriptExecutionDisabled',{value:true});
+await this.sendCommand('Runtime.terminateExecution');
+throw new LHError(LHError.errors.PAGE_HUNG);
+}
+};
+});
+
+
+const cleanupFn=await Promise.race([
+securityCheckPromise,
+loadPromise,
+maxTimeoutPromise]);
+
+
+maxTimeoutHandle&&clearTimeout(maxTimeoutHandle);
+waitForFCP.cancel();
+waitForLoadEvent.cancel();
+waitForNetworkIdle.cancel();
+waitForCPUIdle.cancel();
+monitorForInsecureState.cancel();
+
+await cleanupFn();
+}
+
+
+
+
+
+
+
+
+
+_beginNetworkStatusMonitoring(startingUrl){
+this._networkStatusMonitor=new NetworkRecorder();
+
+
+this._monitoredUrl=startingUrl;
+
+const requestLoadedListener=redirectRequest=>{
+
+if(!redirectRequest.redirectSource){
+return;
+}
+const earlierRequest=redirectRequest.redirectSource;
+if(earlierRequest.url===this._monitoredUrl){
+this._monitoredUrl=redirectRequest.url;
+}
+};
+this._networkStatusMonitor.on('requestloaded',requestLoadedListener);
+
+return this.sendCommand('Network.enable');
+}
+
+
+
+
+
+
+
+_endNetworkStatusMonitoring(){
+this._networkStatusMonitor=null;
+const finalUrl=this._monitoredUrl;
+this._monitoredUrl=null;
+
+if(!finalUrl){
+throw new Error('Network Status Monitoring ended with an undefined finalUrl');
+}
+
+return finalUrl;
+}
+
+
+
+
+
+
+
+async _getOrCreateIsolatedContextId(){
+if(typeof this._isolatedExecutionContextId==='number'){
+return this._isolatedExecutionContextId;
+}
+
+const resourceTreeResponse=await this.sendCommand('Page.getResourceTree');
+const mainFrameId=resourceTreeResponse.frameTree.frame.id;
+
+const isolatedWorldResponse=await this.sendCommand('Page.createIsolatedWorld',{
+frameId:mainFrameId,
+worldName:'lighthouse_isolated_context'});
+
+
+this._isolatedExecutionContextId=isolatedWorldResponse.executionContextId;
+return isolatedWorldResponse.executionContextId;
+}
+
+_clearIsolatedContextId(){
+this._isolatedExecutionContextId=undefined;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+async gotoURL(url,options={}){
+const waitForFCP=options.waitForFCP||false;
+const waitForNavigated=options.waitForNavigated||false;
+const waitForLoad=options.waitForLoad||false;
+const passContext=options.passContext||{};
+const disableJS=passContext.disableJavaScript||false;
+
+if(waitForNavigated&&(waitForFCP||waitForLoad)){
+throw new Error('Cannot use both waitForNavigated and another event, pick just one');
+}
+
+await this._beginNetworkStatusMonitoring(url);
+await this._clearIsolatedContextId();
+
+await this.sendCommand('Page.enable');
+await this.sendCommand('Page.setLifecycleEventsEnabled',{enabled:true});
+await this.sendCommand('Emulation.setScriptExecutionDisabled',{value:disableJS});
+
+const waitforPageNavigateCmd=this._innerSendCommand('Page.navigate',{url});
+
+if(waitForNavigated){
+await this._waitForFrameNavigated();
+}else if(waitForLoad){
+const passConfig=passContext.passConfig||{};
+let{pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs}=passConfig;
+let maxWaitMs=passContext.settings&&passContext.settings.maxWaitForLoad;
+
+
+if(typeof pauseAfterLoadMs!=='number')pauseAfterLoadMs=DEFAULT_PAUSE_AFTER_LOAD;
+if(typeof networkQuietThresholdMs!=='number')networkQuietThresholdMs=DEFAULT_NETWORK_QUIET_THRESHOLD;
+if(typeof cpuQuietThresholdMs!=='number')cpuQuietThresholdMs=DEFAULT_CPU_QUIET_THRESHOLD;
+if(typeof maxWaitMs!=='number')maxWaitMs=constants.defaultSettings.maxWaitForLoad;
+
+
+await this._waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
+maxWaitMs,waitForFCP);
+}
+
+
+await waitforPageNavigateCmd;
+
+return this._endNetworkStatusMonitoring();
+}
+
+
+
+
+
+
+async getObjectProperty(objectId,propName){
+const propertiesResponse=await this.sendCommand('Runtime.getProperties',{
+objectId,
+accessorPropertiesOnly:true,
+generatePreview:false,
+ownProperties:false});
+
+
+const propertyForName=propertiesResponse.result.
+find(property=>property.name===propName);
+
+if(propertyForName&&propertyForName.value){
+return propertyForName.value.value;
+}else{
+return null;
+}
+}
+
+
+
+
+
+
+
+
+async getRequestContent(requestId,timeout=1000){
+requestId=NetworkRequest.getRequestIdForBackend(requestId);
+
+
+
+this.setNextProtocolTimeout(timeout);
+const result=await this.sendCommand('Network.getResponseBody',{requestId});
+return result.body;
+}
+
+
+
+
+
+
+queryPermissionState(name){
+const expressionToEval=`
+ navigator.permissions.query({name: '${name}'}).then(result => {
+ return result.state;
+ })
+ `;
+
+return this.evaluateAsync(expressionToEval);
+}
+
+
+
+
+
+async querySelector(selector){
+const documentResponse=await this.sendCommand('DOM.getDocument');
+const rootNodeId=documentResponse.root.nodeId;
+
+const targetNode=await this.sendCommand('DOM.querySelector',{
+nodeId:rootNodeId,
+selector});
+
+
+if(targetNode.nodeId===0){
+return null;
+}
+return new Element(targetNode,this);
+}
+
+
+
+
+
+async querySelectorAll(selector){
+const documentResponse=await this.sendCommand('DOM.getDocument');
+const rootNodeId=documentResponse.root.nodeId;
+
+const targetNodeList=await this.sendCommand('DOM.querySelectorAll',{
+nodeId:rootNodeId,
+selector});
+
+
+
+const elementList=[];
+targetNodeList.nodeIds.forEach(nodeId=>{
+if(nodeId!==0){
+elementList.push(new Element({nodeId},this));
+}
+});
+return elementList;
+}
+
+
+
+
+
+
+
+getElementsInDocument(pierce=true){
+return this.getNodesInDocument(pierce).
+then(nodes=>nodes.
+filter(node=>node.nodeType===1).
+map(node=>new Element({nodeId:node.nodeId},this)));
+
+}
+
+
+
+
+
+
+
+async getNodesInDocument(pierce=true){
+const flattenedDocument=await this.sendCommand('DOM.getFlattenedDocument',
+{depth:-1,pierce});
+
+return flattenedDocument.nodes?flattenedDocument.nodes:[];
+}
+
+
+
+
+
+async beginTrace(settings){
+const additionalCategories=settings&&settings.additionalTraceCategories&&
+settings.additionalTraceCategories.split(',')||[];
+const traceCategories=this._traceCategories.concat(additionalCategories);
+
+
+
+const milestone=(await this.getBrowserVersion()).milestone;
+if(milestone<71){
+const toplevelIndex=traceCategories.indexOf('disabled-by-default-lighthouse');
+traceCategories[toplevelIndex]='toplevel';
+}
+
+const uniqueCategories=Array.from(new Set(traceCategories));
+
+
+if(this.isDomainEnabled('Debugger')){
+throw new Error('Debugger domain enabled when starting trace');
+}
+if(this.isDomainEnabled('CSS')){
+throw new Error('CSS domain enabled when starting trace');
+}
+if(this.isDomainEnabled('DOM')){
+throw new Error('DOM domain enabled when starting trace');
+}
+
+
+return this.sendCommand('Page.enable').
+then(_=>this.sendCommand('Tracing.start',{
+categories:uniqueCategories.join(','),
+options:'sampling-frequency=10000'}));
+
+}
+
+
+
+
+endTrace(){
+
+const traceEvents=[];
+
+
+
+
+
+const dataListener=function(data){
+traceEvents.push(...data.value);
+};
+this.on('Tracing.dataCollected',dataListener);
+
+return new Promise((resolve,reject)=>{
+this.once('Tracing.tracingComplete',_=>{
+this.off('Tracing.dataCollected',dataListener);
+resolve({traceEvents});
+});
+
+return this.sendCommand('Tracing.end').catch(reject);
+});
+}
+
+
+
+
+beginDevtoolsLog(){
+this._devtoolsLog.reset();
+this._devtoolsLog.beginRecording();
+}
+
+
+
+
+
+endDevtoolsLog(){
+this._devtoolsLog.endRecording();
+return this._devtoolsLog.messages;
+}
+
+
+
+
+enableRuntimeEvents(){
+return this.sendCommand('Runtime.enable');
+}
+
+
+
+
+
+async beginEmulation(settings){
+
+if(!settings.disableDeviceEmulation){
+if(settings.emulatedFormFactor==='mobile'){
+await emulation.enableNexus5X(this);
+}else if(settings.emulatedFormFactor==='desktop'){
+await emulation.enableDesktop(this);
+}
+}
+
+await this.setThrottling(settings,{useThrottling:true});
+}
+
+
+
+
+
+
+async setThrottling(settings,passConfig){
+if(settings.throttlingMethod!=='devtools'){
+return emulation.clearAllNetworkEmulation(this);
+}
+
+const cpuPromise=passConfig.useThrottling?
+emulation.enableCPUThrottling(this,settings.throttling):
+emulation.disableCPUThrottling(this);
+const networkPromise=passConfig.useThrottling?
+emulation.enableNetworkThrottling(this,settings.throttling):
+emulation.clearAllNetworkEmulation(this);
+
+await Promise.all([cpuPromise,networkPromise]);
+}
+
+
+
+
+
+async goOffline(){
+await this.sendCommand('Network.enable');
+await emulation.goOffline(this);
+this.online=false;
+}
+
+
+
+
+
+
+async goOnline(options){
+await this.setThrottling(options.settings,options.passConfig);
+this.online=true;
+}
+
+
+
+
+
+cleanBrowserCaches(){
+
+return this.sendCommand('Network.clearBrowserCache').
+
+then(_=>this.sendCommand('Network.setCacheDisabled',{cacheDisabled:true})).
+then(_=>this.sendCommand('Network.setCacheDisabled',{cacheDisabled:false}));
+}
+
+
+
+
+
+async setExtraHTTPHeaders(headers){
+if(!headers){
+return;
+}
+
+return this.sendCommand('Network.setExtraHTTPHeaders',{headers});
+}
+
+
+
+
+
+clearDataForOrigin(url){
+const origin=new URL(url).origin;
+
+
+
+const typesToClear=[
+'appcache',
+
+'file_systems',
+'indexeddb',
+'local_storage',
+'shader_cache',
+'websql',
+'service_workers',
+'cache_storage'].
+join(',');
+
+return this.sendCommand('Storage.clearDataForOrigin',{
+origin:origin,
+storageTypes:typesToClear});
+
+}
+
+
+
+
+
+
+async cacheNatives(){
+await this.evaluateScriptOnNewDocument(`
+ window.__nativePromise = Promise;
+ window.__nativeError = Error;
+ window.__nativeURL = URL;
+ window.__ElementMatches = Element.prototype.matches;
+ window.__perfNow = performance.now.bind(performance);
+ `);
+}
+
+
+
+
+
+async registerPerformanceObserver(){
+const scriptStr=`(${pageFunctions.registerPerformanceObserverInPageString})()`;
+await this.evaluateScriptOnNewDocument(scriptStr);
+}
+
+
+
+
+
+blockUrlPatterns(urls){
+return this.sendCommand('Network.setBlockedURLs',{urls}).
+catch(err=>{
+
+if(!/wasn't found/.test(err.message)){
+throw err;
+}
+});
+}
+
+
+
+
+
+
+async dismissJavaScriptDialogs(){
+this.on('Page.javascriptDialogOpening',data=>{
+log.warn('Driver',`${data.type} dialog opened by the page automatically suppressed.`);
+
+this.sendCommand('Page.handleJavaScriptDialog',{
+accept:true,
+promptText:'Lighthouse prompt response'}).
+catch(err=>log.warn('Driver',err));
+});
+
+await this.sendCommand('Page.enable');
+}}
+
+
+module.exports=Driver;
+
+},{"../config/constants":36,"../lib/element":56,"../lib/emulation":57,"../lib/lh-error":63,"../lib/network-recorder":66,"../lib/network-request":67,"../lib/page-functions.js":68,"../lib/url-shim":"url","./connections/connection.js":39,"./devtools-log":41,"events":93,"lighthouse-logger":113}],43:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const log=require('lighthouse-logger');
+const LHError=require('../lib/lh-error');
+const URL=require('../lib/url-shim');
+const NetworkRecorder=require('../lib/network-recorder.js');
+const constants=require('../config/constants');
+
+const Driver=require('../gather/driver.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class GatherRunner{
+
+
+
+
+
+
+
+
+
+static async loadBlank(driver,url=constants.defaultPassConfig.blankPage){
+const status={msg:'Resetting state with about:blank',id:'lh:gather:loadBlank'};
+log.time(status);
+await driver.gotoURL(url,{waitForNavigated:true});
+log.timeEnd(status);
+}
+
+
+
+
+
+
+
+
+
+
+static async loadPage(driver,passContext){
+const finalUrl=await driver.gotoURL(passContext.url,{
+waitForFCP:passContext.passConfig.recordTrace,
+waitForLoad:true,
+passContext});
+
+passContext.url=finalUrl;
+}
+
+
+
+
+
+
+static async setupDriver(driver,options){
+const status={msg:'Initializing…',id:'lh:gather:setupDriver'};
+log.time(status);
+const resetStorage=!options.settings.disableStorageReset;
+await driver.assertNoSameOriginServiceWorkerClients(options.requestedUrl);
+await driver.beginEmulation(options.settings);
+await driver.enableRuntimeEvents();
+await driver.cacheNatives();
+await driver.registerPerformanceObserver();
+await driver.dismissJavaScriptDialogs();
+if(resetStorage)await driver.clearDataForOrigin(options.requestedUrl);
+log.timeEnd(status);
+}
+
+
+
+
+
+static async disposeDriver(driver){
+const status={msg:'Disconnecting from browser...',id:'lh:gather:disconnect'};
+
+log.time(status);
+try{
+await driver.disconnect();
+}catch(err){
+
+
+if(!/close\/.*status: 500$/.test(err.message)){
+log.error('GatherRunner disconnect',err.message);
+}
+}
+log.timeEnd(status);
+}
+
+
+
+
+
+
+
+static getPageLoadError(url,networkRecords){
+const mainRecord=networkRecords.find(record=>{
+
+return URL.equalWithExcludedFragments(record.url,url);
+});
+
+if(!mainRecord){
+return new LHError(LHError.errors.NO_DOCUMENT_REQUEST);
+}else if(mainRecord.failed){
+const netErr=mainRecord.localizedFailDescription;
+
+
+if(
+netErr==='net::ERR_NAME_NOT_RESOLVED'||
+netErr==='net::ERR_NAME_RESOLUTION_FAILED'||
+netErr.startsWith('net::ERR_DNS_'))
+{
+return new LHError(LHError.errors.DNS_FAILURE);
+}else{
+return new LHError(
+LHError.errors.FAILED_DOCUMENT_REQUEST,
+{errorDetails:netErr});
+
+}
+}else if(mainRecord.hasErrorStatusCode()){
+return new LHError(
+LHError.errors.ERRORED_DOCUMENT_REQUEST,
+{statusCode:`${mainRecord.statusCode}`});
+
+}
+}
+
+
+
+
+
+
+
+
+static async beforePass(passContext,gathererResults){
+const bpStatus={msg:`Running beforePass methods`,id:`lh:gather:beforePass`};
+log.time(bpStatus,'verbose');
+const blockedUrls=(passContext.passConfig.blockedUrlPatterns||[]).
+concat(passContext.settings.blockedUrlPatterns||[]);
+
+
+
+
+await passContext.driver.blockUrlPatterns(blockedUrls);
+await passContext.driver.setExtraHTTPHeaders(passContext.settings.extraHeaders);
+
+for(const gathererDefn of passContext.passConfig.gatherers){
+const gatherer=gathererDefn.instance;
+
+passContext.options=gathererDefn.options||{};
+const status={
+msg:`Retrieving setup: ${gatherer.name}`,
+id:`lh:gather:beforePass:${gatherer.name}`};
+
+log.time(status,'verbose');
+const artifactPromise=Promise.resolve().then(_=>gatherer.beforePass(passContext));
+gathererResults[gatherer.name]=[artifactPromise];
+await artifactPromise.catch(()=>{});
+log.timeEnd(status);
+}
+log.timeEnd(bpStatus);
+}
+
+
+
+
+
+
+
+
+static async pass(passContext,gathererResults){
+const driver=passContext.driver;
+const config=passContext.passConfig;
+const settings=passContext.settings;
+const gatherers=config.gatherers;
+
+const recordTrace=config.recordTrace;
+const isPerfRun=!settings.disableStorageReset&&recordTrace&&config.useThrottling;
+
+const status={
+msg:'Loading page & waiting for onload',
+id:`lh:gather:loadPage-${passContext.passConfig.passName}`,
+args:[gatherers.map(g=>g.instance.name).join(', ')]};
+
+log.time(status);
+
+
+if(isPerfRun)await driver.cleanBrowserCaches();
+
+await driver.beginDevtoolsLog();
+
+if(recordTrace)await driver.beginTrace(settings);
+
+
+await GatherRunner.loadPage(driver,passContext);
+log.timeEnd(status);
+
+const pStatus={msg:`Running pass methods`,id:`lh:gather:pass`};
+log.time(pStatus,'verbose');
+for(const gathererDefn of gatherers){
+const gatherer=gathererDefn.instance;
+
+passContext.options=gathererDefn.options||{};
+const status={
+msg:`Retrieving in-page: ${gatherer.name}`,
+id:`lh:gather:pass:${gatherer.name}`};
+
+log.time(status);
+const artifactPromise=Promise.resolve().then(_=>gatherer.pass(passContext));
+
+const gathererResult=gathererResults[gatherer.name]||[];
+gathererResult.push(artifactPromise);
+gathererResults[gatherer.name]=gathererResult;
+await artifactPromise.catch(()=>{});
+}
+log.timeEnd(status);
+log.timeEnd(pStatus);
+}
+
+
+
+
+
+
+
+
+
+static async afterPass(passContext,gathererResults){
+const driver=passContext.driver;
+const config=passContext.passConfig;
+const gatherers=config.gatherers;
+
+let trace;
+if(config.recordTrace){
+const status={msg:'Retrieving trace',id:`lh:gather:getTrace`};
+log.time(status);
+trace=await driver.endTrace();
+log.timeEnd(status);
+}
+
+const status={
+msg:'Retrieving devtoolsLog & network records',
+id:`lh:gather:getDevtoolsLog`};
+
+log.time(status);
+const devtoolsLog=driver.endDevtoolsLog();
+const networkRecords=NetworkRecorder.recordsFromLogs(devtoolsLog);
+log.timeEnd(status);
+
+let pageLoadError=GatherRunner.getPageLoadError(passContext.url,networkRecords);
+
+if(!driver.online)pageLoadError=undefined;
+
+if(pageLoadError){
+log.error('GatherRunner',pageLoadError.message,passContext.url);
+passContext.LighthouseRunWarnings.push(pageLoadError.friendlyMessage);
+}
+
+
+
+const passData={
+networkRecords,
+devtoolsLog,
+trace};
+
+
+const apStatus={msg:`Running afterPass methods`,id:`lh:gather:afterPass`};
+
+await driver.setThrottling(passContext.settings,{useThrottling:false});
+log.time(apStatus,'verbose');
+
+for(const gathererDefn of gatherers){
+const gatherer=gathererDefn.instance;
+const status={
+msg:`Retrieving: ${gatherer.name}`,
+id:`lh:gather:afterPass:${gatherer.name}`};
+
+log.time(status);
+
+
+passContext.options=gathererDefn.options||{};
+
+
+const artifactPromise=pageLoadError?
+Promise.reject(pageLoadError):
+
+Promise.resolve().then(_=>gatherer.afterPass(passContext,passData));
+
+const gathererResult=gathererResults[gatherer.name]||[];
+gathererResult.push(artifactPromise);
+gathererResults[gatherer.name]=gathererResult;
+await artifactPromise.catch(()=>{});
+log.timeEnd(status);
+}
+log.timeEnd(apStatus);
+
+
+return passData;
+}
+
+
+
+
+
+
+
+
+
+
+static async collectArtifacts(gathererResults,baseArtifacts){
+
+const gathererArtifacts={};
+
+const resultsEntries=Object.entries(gathererResults);
+for(const[gathererName,phaseResultsPromises]of resultsEntries){
+if(gathererArtifacts[gathererName]!==undefined)continue;
+
+try{
+const phaseResults=await Promise.all(phaseResultsPromises);
+
+const definedResults=phaseResults.filter(element=>element!==undefined);
+const artifact=definedResults[definedResults.length-1];
+
+gathererArtifacts[gathererName]=artifact;
+}catch(err){
+
+gathererArtifacts[gathererName]=err;
+}
+
+if(gathererArtifacts[gathererName]===undefined){
+throw new Error(`${gathererName} failed to provide an artifact.`);
+}
+}
+
+
+baseArtifacts.LighthouseRunWarnings=Array.from(new Set(baseArtifacts.LighthouseRunWarnings));
+
+
+baseArtifacts.Timing=log.getTimeEntries();
+
+
+return{...baseArtifacts,...gathererArtifacts};
+}
+
+
+
+
+
+static async getBaseArtifacts(options){
+return{
+fetchTime:new Date().toJSON(),
+LighthouseRunWarnings:[],
+HostUserAgent:(await options.driver.getBrowserVersion()).userAgent,
+NetworkUserAgent:'',
+BenchmarkIndex:0,
+traces:{},
+devtoolsLogs:{},
+settings:options.settings,
+URL:{requestedUrl:options.requestedUrl,finalUrl:''},
+Timing:[]};
+
+}
+
+
+
+
+
+
+static async run(passes,options){
+const driver=options.driver;
+
+
+const gathererResults={};
+
+try{
+await driver.connect();
+const baseArtifacts=await GatherRunner.getBaseArtifacts(options);
+
+
+await GatherRunner.loadBlank(driver);
+baseArtifacts.BenchmarkIndex=await options.driver.getBenchmarkIndex();
+await GatherRunner.setupDriver(driver,options);
+
+
+let isFirstPass=true;
+for(const passConfig of passes){
+const passContext={
+driver:options.driver,
+
+url:options.requestedUrl,
+settings:options.settings,
+passConfig,
+
+LighthouseRunWarnings:baseArtifacts.LighthouseRunWarnings};
+
+
+await driver.setThrottling(options.settings,passConfig);
+if(!isFirstPass){
+
+await GatherRunner.loadBlank(driver,passConfig.blankPage);
+}
+await GatherRunner.beforePass(passContext,gathererResults);
+await GatherRunner.pass(passContext,gathererResults);
+const passData=await GatherRunner.afterPass(passContext,gathererResults);
+
+
+baseArtifacts.devtoolsLogs[passConfig.passName]=passData.devtoolsLog;
+
+const userAgentEntry=passData.devtoolsLog.find(entry=>
+entry.method==='Network.requestWillBeSent'&&
+!!entry.params.request.headers['User-Agent']);
+
+
+if(userAgentEntry&&!baseArtifacts.NetworkUserAgent){
+
+baseArtifacts.NetworkUserAgent=userAgentEntry.params.request.headers['User-Agent'];
+}
+
+
+if(passData.trace){
+baseArtifacts.traces[passConfig.passName]=passData.trace;
+}
+
+if(isFirstPass){
+
+baseArtifacts.URL.finalUrl=passContext.url;
+isFirstPass=false;
+}
+}
+const resetStorage=!options.settings.disableStorageReset;
+if(resetStorage)await driver.clearDataForOrigin(options.requestedUrl);
+await GatherRunner.disposeDriver(driver);
+return GatherRunner.collectArtifacts(gathererResults,baseArtifacts);
+}catch(err){
+
+GatherRunner.disposeDriver(driver);
+throw err;
+}
+}}
+
+
+module.exports=GatherRunner;
+
+},{"../config/constants":36,"../gather/driver.js":42,"../lib/lh-error":63,"../lib/network-recorder.js":66,"../lib/url-shim":"url","lighthouse-logger":113}],44:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+class Gatherer{
+
+
+
+get name(){
+
+return this.constructor.name;
+}
+
+
+
+
+
+
+
+
+beforePass(passContext){}
+
+
+
+
+
+
+
+pass(passContext){}
+
+
+
+
+
+
+
+
+
+afterPass(passContext,loadData){}}
+
+
+
+
+module.exports=Gatherer;
+
+},{}],45:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Runner=require('./runner');
+const log=require('lighthouse-logger');
+const ChromeProtocol=require('./gather/connections/cri.js');
+const Config=require('./config/config');
+
+const URL=require('./lib/url-shim.js');
+const LHError=require('./lib/lh-error.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+async function lighthouse(url,flags={},configJSON,connection){
+
+if(url&&(!URL.isValid(url)||!URL.isProtocolAllowed(url))){
+throw new LHError(LHError.errors.INVALID_URL);
+}
+
+
+flags.logLevel=flags.logLevel||'error';
+log.setLevel(flags.logLevel);
+
+const config=generateConfig(configJSON,flags);
+
+connection=connection||new ChromeProtocol(flags.port,flags.hostname);
+
+
+return Runner.run(connection,{url,config});
+}
+
+
+
+
+
+
+
+
+
+function generateConfig(configJson,flags){
+return new Config(configJson,flags);
+}
+
+lighthouse.generateConfig=generateConfig;
+lighthouse.getAuditList=Runner.getAuditList;
+lighthouse.traceCategories=require('./gather/driver').traceCategories;
+lighthouse.Audit=require('./audits/audit');
+lighthouse.Gatherer=require('./gather/gatherers/gatherer');
+
+module.exports=lighthouse;
+
+},{"./audits/audit":3,"./config/config":35,"./gather/connections/cri.js":87,"./gather/driver":42,"./gather/gatherers/gatherer":44,"./lib/lh-error.js":63,"./lib/url-shim.js":"url","./runner":76,"lighthouse-logger":113}],46:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const isEqual=require('lodash.isequal');
+
+
+
+
+
+
+class ArbitraryEqualityMap{
+constructor(){
+this._equalsFn=ArbitraryEqualityMap.deepEquals;
+
+this._entries=[];
+}
+
+
+
+
+setEqualityFn(equalsFn){
+this._equalsFn=equalsFn;
+}
+
+
+
+
+
+has(key){
+return this._findIndexOf(key)!==-1;
+}
+
+
+
+
+
+get(key){
+const entry=this._entries[this._findIndexOf(key)];
+return entry&&entry.value;
+}
+
+
+
+
+
+set(key,value){
+let index=this._findIndexOf(key);
+if(index===-1)index=this._entries.length;
+this._entries[index]={key,value};
+}
+
+
+
+
+
+_findIndexOf(key){
+for(let i=0;i<this._entries.length;i++){
+if(this._equalsFn(key,this._entries[i].key))return i;
+}
+
+return-1;
+}
+
+
+
+
+
+
+
+
+
+static deepEquals(objA,objB){
+return isEqual(objA,objB);
+}}
+
+
+module.exports=ArbitraryEqualityMap;
+
+},{"lodash.isequal":114}],47:[function(require,module,exports){
+(function(process){
+
+
+
+
+
+'use strict';
+
+
+const path=require('path');
+const log=require('lighthouse-logger');
+const stream=require('stream');
+const Simulator=require('./dependency-graph/simulator/simulator');
+const lanternTraceSaver=require('./lantern-trace-saver');
+const Metrics=require('./traces/pwmetrics-events');
+const rimraf=require('rimraf');
+const mkdirp=require('mkdirp');
+
+const artifactsFilename='artifacts.json';
+const traceSuffix='.trace.json';
+const devtoolsLogSuffix='.devtoolslog.json';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+async function loadArtifacts(basePath){
+log.log('Reading artifacts from disk:',basePath);
+
+if(!fs.existsSync(basePath)){
+throw new Error('No saved artifacts found at '+basePath);
+}
+
+
+
+const artifacts=JSON.parse(fs.readFileSync(path.join(basePath,artifactsFilename),'utf8'));
+
+const filenames=fs.readdirSync(basePath);
+
+
+artifacts.devtoolsLogs={};
+filenames.filter(f=>f.endsWith(devtoolsLogSuffix)).forEach(filename=>{
+const passName=filename.replace(devtoolsLogSuffix,'');
+const devtoolsLog=JSON.parse(fs.readFileSync(path.join(basePath,filename),'utf8'));
+artifacts.devtoolsLogs[passName]=devtoolsLog;
+});
+
+
+artifacts.traces={};
+filenames.filter(f=>f.endsWith(traceSuffix)).forEach(filename=>{
+const file=fs.readFileSync(path.join(basePath,filename),{encoding:'utf-8'});
+const trace=JSON.parse(file);
+const passName=filename.replace(traceSuffix,'');
+artifacts.traces[passName]=Array.isArray(trace)?{traceEvents:trace}:trace;
+});
+
+if(Array.isArray(artifacts.Timing)){
+
+
+artifacts.Timing.forEach(entry=>entry.gather=true);
+}
+return artifacts;
+}
+
+
+
+
+
+
+
+
+async function saveArtifacts(artifacts,basePath){
+const status={msg:'Saving artifacts',id:'lh:assetSaver:saveArtifacts'};
+log.time(status);
+mkdirp.sync(basePath);
+rimraf.sync(`${basePath}/*${traceSuffix}`);
+rimraf.sync(`${basePath}/${artifactsFilename}`);
+
+const{traces,devtoolsLogs,...restArtifacts}=artifacts;
+
+
+for(const[passName,trace]of Object.entries(traces)){
+await saveTrace(trace,`${basePath}/${passName}${traceSuffix}`);
+}
+
+
+for(const[passName,devtoolsLog]of Object.entries(devtoolsLogs)){
+const log=JSON.stringify(devtoolsLog);
+fs.writeFileSync(`${basePath}/${passName}${devtoolsLogSuffix}`,log,'utf8');
+}
+
+
+const restArtifactsString=JSON.stringify(restArtifacts,null,2);
+fs.writeFileSync(`${basePath}/${artifactsFilename}`,restArtifactsString,'utf8');
+log.log('Artifacts saved to disk in folder:',basePath);
+log.timeEnd(status);
+}
+
+
+
+
+
+
+
+async function prepareAssets(artifacts,audits){
+const passNames=Object.keys(artifacts.traces);
+
+const assets=[];
+
+for(const passName of passNames){
+const trace=artifacts.traces[passName];
+const devtoolsLog=artifacts.devtoolsLogs[passName];
+
+const traceData=Object.assign({},trace);
+if(audits){
+const evts=new Metrics(traceData.traceEvents,audits).generateFakeEvents();
+traceData.traceEvents=traceData.traceEvents.concat(evts);
+}
+
+assets.push({
+passName,
+traceData,
+devtoolsLog});
+
+}
+
+return assets;
+}
+
+
+
+
+
+
+
+
+function*traceJsonGenerator(traceData){
+const EVENTS_PER_ITERATION=500;
+const keys=Object.keys(traceData);
+
+yield'{\n';
+
+
+yield'"traceEvents": [\n';
+if(traceData.traceEvents.length>0){
+const eventsIterator=traceData.traceEvents[Symbol.iterator]();
+
+const firstEvent=eventsIterator.next().value;
+yield` ${JSON.stringify(firstEvent)}`;
+
+let eventsRemaining=EVENTS_PER_ITERATION;
+let eventsJSON='';
+for(const event of eventsIterator){
+eventsJSON+=`,\n ${JSON.stringify(event)}`;
+eventsRemaining--;
+if(eventsRemaining===0){
+yield eventsJSON;
+eventsRemaining=EVENTS_PER_ITERATION;
+eventsJSON='';
+}
+}
+yield eventsJSON;
+}
+yield'\n]';
+
+
+if(keys.length>1){
+for(const key of keys){
+if(key==='traceEvents')continue;
+
+yield`,\n"${key}": ${JSON.stringify(traceData[key],null,2)}`;
+}
+}
+
+yield'}\n';
+}
+
+
+
+
+
+
+
+function saveTrace(traceData,traceFilename){
+return new Promise((resolve,reject)=>{
+const traceIter=traceJsonGenerator(traceData);
+
+
+const traceStream=new stream.Readable({
+read(){
+const next=traceIter.next();
+this.push(next.done?null:next.value);
+}});
+
+
+const writeStream=fs.createWriteStream(traceFilename);
+writeStream.on('finish',resolve);
+writeStream.on('error',reject);
+
+traceStream.pipe(writeStream);
+});
+}
+
+
+
+
+
+async function saveLanternDebugTraces(pathWithBasename){
+if(!process.env.LANTERN_DEBUG)return;
+
+for(const[label,nodeTimings]of Simulator.ALL_NODE_TIMINGS){
+if(lanternTraceSaver.simulationNamesToIgnore.includes(label))continue;
+
+const traceFilename=`${pathWithBasename}-${label}${traceSuffix}`;
+await saveTrace(lanternTraceSaver.convertNodeTimingsToTrace(nodeTimings),traceFilename);
+log.log('saveAssets',`${label} lantern trace file streamed to disk: ${traceFilename}`);
+}
+}
+
+
+
+
+
+
+
+
+async function saveAssets(artifacts,audits,pathWithBasename){
+const allAssets=await prepareAssets(artifacts,audits);
+const saveAll=allAssets.map(async(passAssets,index)=>{
+const devtoolsLogFilename=`${pathWithBasename}-${index}${devtoolsLogSuffix}`;
+fs.writeFileSync(devtoolsLogFilename,JSON.stringify(passAssets.devtoolsLog,null,2));
+log.log('saveAssets','devtools log saved to disk: '+devtoolsLogFilename);
+
+const streamTraceFilename=`${pathWithBasename}-${index}${traceSuffix}`;
+log.log('saveAssets','streaming trace file to disk: '+streamTraceFilename);
+await saveTrace(passAssets.traceData,streamTraceFilename);
+log.log('saveAssets','trace file streamed to disk: '+streamTraceFilename);
+});
+
+await Promise.all(saveAll);
+await saveLanternDebugTraces(pathWithBasename);
+}
+
+
+
+
+
+
+
+async function logAssets(artifacts,audits){
+const allAssets=await prepareAssets(artifacts,audits);
+allAssets.map(passAssets=>{
+const dtlogdata=JSON.stringify(passAssets.devtoolsLog);
+
+console.log(`loggedAsset %%% devtoolslog-${passAssets.passName}.json %%% ${dtlogdata}`);
+const traceIter=traceJsonGenerator(passAssets.traceData);
+let traceJson='';
+for(const trace of traceIter){
+traceJson+=trace;
+}
+
+console.log(`loggedAsset %%% trace-${passAssets.passName}.json %%% ${traceJson}`);
+});
+}
+
+module.exports={
+saveArtifacts,
+loadArtifacts,
+saveAssets,
+prepareAssets,
+saveTrace,
+logAssets};
+
+
+}).call(this,require('_process'));
+},{"./dependency-graph/simulator/simulator":54,"./lantern-trace-saver":62,"./traces/pwmetrics-events":72,"_process":130,"lighthouse-logger":113,"mkdirp":87,"path":128,"rimraf":87,"stream":155}],48:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class BaseNode{
+
+
+
+constructor(id){
+this._id=id;
+this._isMainDocument=false;
+
+this._dependents=[];
+
+this._dependencies=[];
+}
+
+
+
+
+get id(){
+return this._id;
+}
+
+
+
+
+get type(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+get startTime(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+get endTime(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+setIsMainDocument(value){
+this._isMainDocument=value;
+}
+
+
+
+
+isMainDocument(){
+return this._isMainDocument;
+}
+
+
+
+
+getDependents(){
+return this._dependents.slice();
+}
+
+
+
+
+getDependencies(){
+return this._dependencies.slice();
+}
+
+
+
+
+getNumberOfDependencies(){
+return this._dependencies.length;
+}
+
+
+
+
+getRootNode(){
+let rootNode=this;
+while(rootNode._dependencies.length){
+rootNode=rootNode._dependencies[0];
+}
+
+return rootNode;
+}
+
+
+
+
+addDependent(node){
+node.addDependency(this);
+}
+
+
+
+
+addDependency(node){
+if(this._dependencies.includes(node)){
+return;
+}
+
+node._dependents.push(this);
+this._dependencies.push(node);
+}
+
+
+
+
+removeDependent(node){
+node.removeDependency(this);
+}
+
+
+
+
+removeDependency(node){
+if(!this._dependencies.includes(node)){
+return;
+}
+
+const thisIndex=node._dependents.indexOf(this);
+node._dependents.splice(thisIndex,1);
+this._dependencies.splice(this._dependencies.indexOf(node),1);
+}
+
+removeAllDependencies(){
+for(const node of this._dependencies.slice()){
+this.removeDependency(node);
+}
+}
+
+
+
+
+
+cloneWithoutRelationships(){
+const node=new BaseNode(this.id);
+node.setIsMainDocument(this._isMainDocument);
+return node;
+}
+
+
+
+
+
+
+
+
+cloneWithRelationships(predicate){
+const rootNode=this.getRootNode();
+
+
+let shouldIncludeNode=()=>true;
+if(predicate){
+const idsToInclude=new Set();
+rootNode.traverse(node=>{
+if(predicate(node)){
+node.traverse(
+node=>idsToInclude.add(node.id),
+node=>node._dependencies.filter(parent=>!idsToInclude.has(parent)));
+
+}
+});
+
+shouldIncludeNode=node=>idsToInclude.has(node.id);
+}
+
+const idToNodeMap=new Map();
+rootNode.traverse(originalNode=>{
+if(!shouldIncludeNode(originalNode))return;
+const clonedNode=originalNode.cloneWithoutRelationships();
+idToNodeMap.set(clonedNode.id,clonedNode);
+});
+
+rootNode.traverse(originalNode=>{
+if(!shouldIncludeNode(originalNode))return;
+const clonedNode=idToNodeMap.get(originalNode.id);
+
+for(const dependency of originalNode._dependencies){
+const clonedDependency=idToNodeMap.get(dependency.id);
+clonedNode.addDependency(clonedDependency);
+}
+});
+
+if(!idToNodeMap.has(this.id))throw new Error('Cloned graph missing node');
+return idToNodeMap.get(this.id);
+}
+
+
+
+
+
+
+
+_traversePaths(iterator,getNext){
+const stack=[[this]];
+while(stack.length){
+
+
+const path=stack.shift();
+const node=path[0];
+iterator(node,path);
+
+const nodesToAdd=getNext(node);
+for(const nextNode of nodesToAdd){
+stack.push([nextNode].concat(path));
+}
+}
+}
+
+
+
+
+
+
+
+traverse(iterator,getNext){
+if(!getNext){
+getNext=node=>node.getDependents();
+}
+
+const visited=new Set();
+const originalGetNext=getNext;
+
+getNext=node=>{
+visited.add(node.id);
+const allNodesToVisit=originalGetNext(node);
+const nodesToVisit=allNodesToVisit.filter(nextNode=>!visited.has(nextNode.id));
+nodesToVisit.forEach(nextNode=>visited.add(nextNode.id));
+return nodesToVisit;
+};
+
+this._traversePaths(iterator,getNext);
+}
+
+
+
+
+
+
+
+static hasCycle(node,direction='both'){
+
+if(direction==='both'){
+return BaseNode.hasCycle(node,'dependents')||BaseNode.hasCycle(node,'dependencies');
+}
+
+const visited=new Set();
+
+const currentPath=[];
+const toVisit=[node];
+const depthAdded=new Map([[node,0]]);
+
+
+while(toVisit.length){
+
+
+
+const currentNode=toVisit.pop();
+
+
+if(currentPath.includes(currentNode))return true;
+
+if(visited.has(currentNode))continue;
+
+
+
+while(currentPath.length>depthAdded.get(currentNode))currentPath.pop();
+
+
+visited.add(currentNode);
+currentPath.push(currentNode);
+
+
+const nodesToExplore=direction==='dependents'?
+currentNode._dependents:
+currentNode._dependencies;
+for(const nextNode of nodesToExplore){
+if(toVisit.includes(nextNode))continue;
+toVisit.push(nextNode);
+depthAdded.set(nextNode,currentPath.length);
+}
+}
+
+return false;
+}}
+
+
+BaseNode.TYPES={
+NETWORK:'network',
+CPU:'cpu'};
+
+
+module.exports=BaseNode;
+
+},{}],49:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const BaseNode=require('./base-node');
+
+class CPUNode extends BaseNode{
+
+
+
+
+constructor(parentEvent,childEvents=[]){
+const nodeId=`${parentEvent.tid}.${parentEvent.ts}`;
+super(nodeId);
+
+this._event=parentEvent;
+this._childEvents=childEvents;
+}
+
+get type(){
+return BaseNode.TYPES.CPU;
+}
+
+
+
+
+get startTime(){
+return this._event.ts;
+}
+
+
+
+
+get endTime(){
+return this._event.ts+this._event.dur;
+}
+
+
+
+
+get event(){
+return this._event;
+}
+
+
+
+
+get childEvents(){
+return this._childEvents;
+}
+
+
+
+
+
+didPerformLayout(){
+return this._childEvents.some(evt=>evt.name==='Layout');
+}
+
+
+
+
+
+
+isEvaluateScriptFor(urls){
+return this._childEvents.some(evt=>{
+return evt.name==='EvaluateScript'&&
+!!evt.args.data&&!!evt.args.data.url&&
+urls.has(evt.args.data.url);
+});
+}
+
+
+
+
+cloneWithoutRelationships(){
+return new CPUNode(this._event,this._childEvents);
+}}
+
+
+module.exports=CPUNode;
+
+},{"./base-node":48}],50:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const BaseNode=require('./base-node');
+const NetworkRequest=require('../network-request');
+
+class NetworkNode extends BaseNode{
+
+
+
+constructor(networkRecord){
+super(networkRecord.requestId);
+
+this._record=networkRecord;
+}
+
+get type(){
+return BaseNode.TYPES.NETWORK;
+}
+
+
+
+
+get startTime(){
+return this._record.startTime*1000*1000;
+}
+
+
+
+
+get endTime(){
+return this._record.endTime*1000*1000;
+}
+
+
+
+
+get record(){
+return this._record;
+}
+
+
+
+
+get initiatorType(){
+return this._record.initiator&&this._record.initiator.type;
+}
+
+
+
+
+get fromDiskCache(){
+return!!this._record.fromDiskCache;
+}
+
+
+
+
+hasRenderBlockingPriority(){
+const priority=this._record.priority;
+const isScript=this._record.resourceType===NetworkRequest.TYPES.Script;
+const isDocument=this._record.resourceType===NetworkRequest.TYPES.Document;
+const isBlockingScript=priority==='High'&&isScript;
+const isBlockingHtmlImport=priority==='High'&&isDocument;
+return priority==='VeryHigh'||isBlockingScript||isBlockingHtmlImport;
+}
+
+
+
+
+cloneWithoutRelationships(){
+const node=new NetworkNode(this._record);
+node.setIsMainDocument(this._isMainDocument);
+return node;
+}}
+
+
+module.exports=NetworkNode;
+
+},{"../network-request":67,"./base-node":48}],51:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const NetworkAnalyzer=require('./network-analyzer');
+const TcpConnection=require('./tcp-connection');
+
+const DEFAULT_SERVER_RESPONSE_TIME=30;
+const TLS_SCHEMES=['https','wss'];
+
+
+
+const CONNECTIONS_PER_ORIGIN=6;
+
+module.exports=class ConnectionPool{
+
+
+
+
+constructor(records,options){
+this._options=Object.assign(
+{
+rtt:undefined,
+throughput:undefined,
+additionalRttByOrigin:new Map(),
+serverResponseTimeByOrigin:new Map()},
+
+options);
+
+
+if(!this._options.rtt||!this._options.throughput){
+throw new Error('Cannot create pool with no rtt or throughput');
+}
+
+this._records=records;
+
+this._connectionsByOrigin=new Map();
+
+this._connectionsByRecord=new Map();
+this._connectionsInUse=new Set();
+this._connectionReusedByRequestId=NetworkAnalyzer.estimateIfConnectionWasReused(records,{
+forceCoarseEstimates:true});
+
+
+this._initializeConnections();
+}
+
+
+
+
+connectionsInUse(){
+return Array.from(this._connectionsInUse);
+}
+
+_initializeConnections(){
+const connectionReused=this._connectionReusedByRequestId;
+const additionalRttByOrigin=this._options.additionalRttByOrigin;
+const serverResponseTimeByOrigin=this._options.serverResponseTimeByOrigin;
+
+const recordsByOrigin=NetworkAnalyzer.groupByOrigin(this._records);
+for(const[origin,records]of recordsByOrigin.entries()){
+const connections=[];
+const additionalRtt=additionalRttByOrigin.get(origin)||0;
+const responseTime=serverResponseTimeByOrigin.get(origin)||DEFAULT_SERVER_RESPONSE_TIME;
+
+for(const record of records){
+if(connectionReused.get(record.requestId))continue;
+
+const isTLS=TLS_SCHEMES.includes(record.parsedURL.scheme);
+const isH2=record.protocol==='h2';
+const connection=new TcpConnection(
+this._options.rtt+additionalRtt,
+this._options.throughput,
+responseTime,
+isTLS,
+isH2);
+
+
+connections.push(connection);
+}
+
+if(!connections.length){
+throw new Error(`Could not find a connection for origin: ${origin}`);
+}
+
+
+while(connections.length<CONNECTIONS_PER_ORIGIN)connections.push(connections[0].clone());
+
+this._connectionsByOrigin.set(origin,connections);
+}
+}
+
+
+
+
+
+_findAvailableConnectionWithLargestCongestionWindow(connections,options){
+const{ignoreConnectionReused,observedConnectionWasReused}=options;
+
+
+let maxConnection=null;
+for(let i=0;i<connections.length;i++){
+const connection=connections[i];
+
+
+
+
+
+if(!ignoreConnectionReused&&connection._warmed!==observedConnectionWasReused){
+continue;
+}
+
+
+if(this._connectionsInUse.has(connection)){
+continue;
+}
+
+
+const currentMax=maxConnection&&maxConnection.congestionWindow||-Infinity;
+if(connection.congestionWindow>currentMax)maxConnection=connection;
+}
+
+return maxConnection;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+acquire(record,options={}){
+if(this._connectionsByRecord.has(record)){
+
+return this._connectionsByRecord.get(record);
+}
+
+const origin=String(record.parsedURL.securityOrigin);
+const observedConnectionWasReused=!!this._connectionReusedByRequestId.get(record.requestId);
+
+const connections=this._connectionsByOrigin.get(origin)||[];
+const connectionToUse=this._findAvailableConnectionWithLargestCongestionWindow(connections,{
+ignoreConnectionReused:options.ignoreConnectionReused,
+observedConnectionWasReused});
+
+
+if(!connectionToUse)return null;
+
+this._connectionsInUse.add(connectionToUse);
+this._connectionsByRecord.set(record,connectionToUse);
+return connectionToUse;
+}
+
+
+
+
+release(record){
+const connection=this._connectionsByRecord.get(record);
+this._connectionsByRecord.delete(record);
+this._connectionsInUse.delete(connection);
+}};
+
+
+},{"./network-analyzer":53,"./tcp-connection":55}],52:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+const DNS_RESOLUTION_RTT_MULTIPLIER=2;
+
+class DNSCache{
+
+
+
+constructor(options){
+this._options=Object.assign(
+{
+rtt:undefined},
+
+options);
+
+
+if(!this._options.rtt){
+throw new Error('Cannot create DNS cache with no rtt');
+}
+
+this._rtt=this._options.rtt;
+
+this._resolvedDomainNames=new Map();
+}
+
+
+
+
+
+
+getTimeUntilResolution(request,options){
+const{requestedAt=0,shouldUpdateCache=false}=options||{};
+
+const domain=request.parsedURL.host;
+const cacheEntry=this._resolvedDomainNames.get(domain);
+let timeUntilResolved=this._rtt*DNSCache.RTT_MULTIPLIER;
+if(cacheEntry){
+const timeUntilCachedIsResolved=Math.max(cacheEntry.resolvedAt-requestedAt,0);
+timeUntilResolved=Math.min(timeUntilCachedIsResolved,timeUntilResolved);
+}
+
+const resolvedAt=requestedAt+timeUntilResolved;
+if(shouldUpdateCache)this._updateCacheResolvedAtIfNeeded(request,resolvedAt);
+
+return timeUntilResolved;
+}
+
+
+
+
+
+_updateCacheResolvedAtIfNeeded(request,resolvedAt){
+const domain=request.parsedURL.host;
+const cacheEntry=this._resolvedDomainNames.get(domain)||{resolvedAt};
+cacheEntry.resolvedAt=Math.min(cacheEntry.resolvedAt,resolvedAt);
+this._resolvedDomainNames.set(domain,cacheEntry);
+}
+
+
+
+
+
+
+
+
+setResolvedAt(domain,resolvedAt){
+this._resolvedDomainNames.set(domain,{resolvedAt});
+}}
+
+
+DNSCache.RTT_MULTIPLIER=DNS_RESOLUTION_RTT_MULTIPLIER;
+
+module.exports=DNSCache;
+
+},{}],53:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const INITIAL_CWD=14*1024;
+const NetworkRequest=require('../../network-request');
+
+
+const DEFAULT_SERVER_RESPONSE_PERCENTAGE=0.4;
+
+
+
+
+
+
+const SERVER_RESPONSE_PERCENTAGE_OF_TTFB={
+Document:0.9,
+XHR:0.9,
+Fetch:0.9};
+
+
+class NetworkAnalyzer{
+
+
+
+static get SUMMARY(){
+return'__SUMMARY__';
+}
+
+
+
+
+
+static groupByOrigin(records){
+const grouped=new Map();
+records.forEach(item=>{
+const key=item.parsedURL.securityOrigin;
+const group=grouped.get(key)||[];
+group.push(item);
+grouped.set(key,group);
+});
+return grouped;
+}
+
+
+
+
+
+static getSummary(values){
+values.sort((a,b)=>a-b);
+
+return{
+min:values[0],
+max:values[values.length-1],
+avg:values.reduce((a,b)=>a+b,0)/values.length,
+median:values[Math.floor((values.length-1)/2)]};
+
+}
+
+
+
+
+
+static summarize(values){
+const summaryByKey=new Map();
+const allEstimates=[];
+for(const[key,estimates]of values){
+summaryByKey.set(key,NetworkAnalyzer.getSummary(estimates));
+allEstimates.push(...estimates);
+}
+
+summaryByKey.set(NetworkAnalyzer.SUMMARY,NetworkAnalyzer.getSummary(allEstimates));
+return summaryByKey;
+}
+
+
+
+
+
+
+
+
+static _estimateValueByOrigin(records,iteratee){
+const connectionWasReused=NetworkAnalyzer.estimateIfConnectionWasReused(records);
+const groupedByOrigin=NetworkAnalyzer.groupByOrigin(records);
+
+const estimates=new Map();
+for(const[origin,originRecords]of groupedByOrigin.entries()){
+
+let originEstimates=[];
+
+for(const record of originRecords){
+const timing=record.timing;
+if(!timing)continue;
+
+const value=iteratee({
+record,
+timing,
+connectionReused:connectionWasReused.get(record.requestId)});
+
+if(typeof value!=='undefined'){
+originEstimates=originEstimates.concat(value);
+}
+}
+
+if(!originEstimates.length)continue;
+estimates.set(origin,originEstimates);
+}
+
+return estimates;
+}
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaTCPTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({timing,connectionReused})=>{
+if(connectionReused)return;
+
+
+
+if(timing.sslStart>0&&timing.sslEnd>0){
+return[timing.connectEnd-timing.sslStart,timing.sslStart-timing.connectStart];
+}else if(timing.connectStart>0&&timing.connectEnd>0){
+return timing.connectEnd-timing.connectStart;
+}
+});
+}
+
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaDownloadTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
+if(connectionReused)return;
+
+if(record.transferSize<=INITIAL_CWD)return;
+if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
+
+
+const totalTime=(record.endTime-record.startTime)*1000;
+const downloadTimeAfterFirstByte=totalTime-timing.receiveHeadersEnd;
+const numberOfRoundTrips=Math.log2(record.transferSize/INITIAL_CWD);
+
+
+
+if(numberOfRoundTrips>5)return;
+return downloadTimeAfterFirstByte/numberOfRoundTrips;
+});
+}
+
+
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaSendStartTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
+if(connectionReused)return;
+if(!Number.isFinite(timing.sendStart)||timing.sendStart<0)return;
+
+
+
+let roundTrips=2;
+if(record.parsedURL.scheme==='https')roundTrips+=1;
+return timing.sendStart/roundTrips;
+});
+}
+
+
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaHeadersEndTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
+if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
+if(!record.resourceType)return;
+
+const serverResponseTimePercentage=SERVER_RESPONSE_PERCENTAGE_OF_TTFB[record.resourceType]||
+DEFAULT_SERVER_RESPONSE_PERCENTAGE;
+const estimatedServerResponseTime=timing.receiveHeadersEnd*serverResponseTimePercentage;
+
+
+
+let roundTrips=1;
+
+
+
+if(!connectionReused){
+roundTrips+=1;
+if(record.parsedURL.scheme==='https')roundTrips+=1;
+roundTrips+=1;
+}
+
+
+return Math.max((timing.receiveHeadersEnd-estimatedServerResponseTime)/roundTrips,3);
+});
+}
+
+
+
+
+
+
+
+
+static _estimateResponseTimeByOrigin(records,rttByOrigin){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing})=>{
+if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
+if(!Number.isFinite(timing.sendEnd)||timing.sendEnd<0)return;
+
+const ttfb=timing.receiveHeadersEnd-timing.sendEnd;
+const origin=record.parsedURL.securityOrigin;
+const rtt=rttByOrigin.get(origin)||rttByOrigin.get(NetworkAnalyzer.SUMMARY)||0;
+return Math.max(ttfb-rtt,0);
+});
+}
+
+
+
+
+
+static canTrustConnectionInformation(records){
+const connectionIdWasStarted=new Map();
+for(const record of records){
+const started=connectionIdWasStarted.get(record.connectionId)||!record.connectionReused;
+connectionIdWasStarted.set(record.connectionId,started);
+}
+
+
+if(connectionIdWasStarted.size<=1)return false;
+
+return Array.from(connectionIdWasStarted.values()).every(started=>started);
+}
+
+
+
+
+
+
+
+
+
+static estimateIfConnectionWasReused(records,options){
+options=Object.assign({forceCoarseEstimates:false},options);
+
+
+if(!options.forceCoarseEstimates&&NetworkAnalyzer.canTrustConnectionInformation(records)){
+
+return new Map(records.map(record=>[record.requestId,!!record.connectionReused]));
+}
+
+
+
+
+
+const connectionWasReused=new Map();
+const groupedByOrigin=NetworkAnalyzer.groupByOrigin(records);
+for(const[_,originRecords]of groupedByOrigin.entries()){
+const earliestReusePossible=originRecords.
+map(record=>record.endTime).
+reduce((a,b)=>Math.min(a,b),Infinity);
+
+for(const record of originRecords){
+connectionWasReused.set(
+record.requestId,
+record.startTime>=earliestReusePossible||record.protocol==='h2');
+
+}
+
+
+
+const firstRecord=originRecords.reduce((a,b)=>a.startTime>b.startTime?b:a);
+connectionWasReused.set(firstRecord.requestId,false);
+}
+
+return connectionWasReused;
+}
+
+
+
+
+
+
+
+
+
+
+static estimateRTTByOrigin(records,options){
+options=Object.assign(
+{
+
+
+forceCoarseEstimates:false,
+
+
+coarseEstimateMultiplier:0.3,
+
+useDownloadEstimates:true,
+useSendStartEstimates:true,
+useHeadersEndEstimates:true},
+
+options);
+
+
+let estimatesByOrigin=NetworkAnalyzer._estimateRTTByOriginViaTCPTiming(records);
+if(!estimatesByOrigin.size||options.forceCoarseEstimates){
+estimatesByOrigin=new Map();
+const estimatesViaDownload=NetworkAnalyzer._estimateRTTByOriginViaDownloadTiming(records);
+const estimatesViaSendStart=NetworkAnalyzer._estimateRTTByOriginViaSendStartTiming(records);
+const estimatesViaTTFB=NetworkAnalyzer._estimateRTTByOriginViaHeadersEndTiming(records);
+
+for(const[origin,estimates]of estimatesViaDownload.entries()){
+if(!options.useDownloadEstimates)continue;
+estimatesByOrigin.set(origin,estimates);
+}
+
+for(const[origin,estimates]of estimatesViaSendStart.entries()){
+if(!options.useSendStartEstimates)continue;
+const existing=estimatesByOrigin.get(origin)||[];
+estimatesByOrigin.set(origin,existing.concat(estimates));
+}
+
+for(const[origin,estimates]of estimatesViaTTFB.entries()){
+if(!options.useHeadersEndEstimates)continue;
+const existing=estimatesByOrigin.get(origin)||[];
+estimatesByOrigin.set(origin,existing.concat(estimates));
+}
+
+for(const estimates of estimatesByOrigin.values()){
+estimates.forEach((x,i)=>estimates[i]=x*options.coarseEstimateMultiplier);
+}
+}
+
+if(!estimatesByOrigin.size)throw new Error('No timing information available');
+return NetworkAnalyzer.summarize(estimatesByOrigin);
+}
+
+
+
+
+
+
+
+
+
+static estimateServerResponseTimeByOrigin(records,options){
+options=Object.assign(
+{
+rttByOrigin:null},
+
+options);
+
+
+let rttByOrigin=options.rttByOrigin;
+if(!rttByOrigin){
+rttByOrigin=NetworkAnalyzer.estimateRTTByOrigin(records,options);
+for(const[origin,summary]of rttByOrigin.entries()){
+rttByOrigin.set(origin,summary.min);
+}
+}
+
+const estimatesByOrigin=NetworkAnalyzer._estimateResponseTimeByOrigin(records,rttByOrigin);
+return NetworkAnalyzer.summarize(estimatesByOrigin);
+}
+
+
+
+
+
+
+
+
+
+
+static estimateThroughput(networkRecords){
+let totalBytes=0;
+
+
+
+
+const timeBoundaries=networkRecords.reduce((boundaries,record)=>{
+const scheme=record.parsedURL&&record.parsedURL.scheme;
+
+
+if(scheme==='data'||record.failed||!record.finished||
+record.statusCode>300||!record.transferSize){
+return boundaries;
+}
+
+
+totalBytes+=record.transferSize;
+boundaries.push({time:record.responseReceivedTime,isStart:true});
+boundaries.push({time:record.endTime,isStart:false});
+return boundaries;
+},[]).sort((a,b)=>a.time-b.time);
+
+if(!timeBoundaries.length){
+return Infinity;
+}
+
+let inflight=0;
+let currentStart=0;
+let totalDuration=0;
+
+timeBoundaries.forEach(boundary=>{
+if(boundary.isStart){
+if(inflight===0){
+
+currentStart=boundary.time;
+}
+inflight++;
+}else{
+inflight--;
+if(inflight===0){
+
+totalDuration+=boundary.time-currentStart;
+}
+}
+});
+
+return totalBytes*8/totalDuration;
+}
+
+
+
+
+
+static findMainDocument(records){
+
+const documentRequests=records.filter(record=>record.resourceType===
+NetworkRequest.TYPES.Document);
+
+return documentRequests.reduce((min,r)=>r.startTime<min.startTime?r:min);
+}}
+
+
+module.exports=NetworkAnalyzer;
+
+
+
+
+
+
+
+
+
+},{"../../network-request":67}],54:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const BaseNode=require('../base-node');
+const TcpConnection=require('./tcp-connection');
+const ConnectionPool=require('./connection-pool');
+const DNSCache=require('./dns-cache');
+const mobileSlow4G=require('../../../config/constants').throttling.mobileSlow4G;
+
+
+
+
+
+
+const DEFAULT_MAXIMUM_CONCURRENT_REQUESTS=10;
+
+const DEFAULT_LAYOUT_TASK_MULTIPLIER=0.5;
+
+const DEFAULT_MAXIMUM_CPU_TASK_DURATION=10000;
+
+const NodeState={
+NotReadyToStart:0,
+ReadyToStart:1,
+InProgress:2,
+Complete:3};
+
+
+
+const ALL_SIMULATION_NODE_TIMINGS=new Map();
+
+class Simulator{
+
+
+
+constructor(options){
+
+this._options=Object.assign(
+{
+rtt:mobileSlow4G.rttMs,
+throughput:mobileSlow4G.throughputKbps*1024,
+maximumConcurrentRequests:DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,
+cpuSlowdownMultiplier:mobileSlow4G.cpuSlowdownMultiplier,
+layoutTaskMultiplier:DEFAULT_LAYOUT_TASK_MULTIPLIER,
+additionalRttByOrigin:new Map(),
+serverResponseTimeByOrigin:new Map()},
+
+options);
+
+
+this._rtt=this._options.rtt;
+this._throughput=this._options.throughput;
+this._maximumConcurrentRequests=Math.max(Math.min(
+TcpConnection.maximumSaturatedConnections(this._rtt,this._throughput),
+this._options.maximumConcurrentRequests),
+1);
+this._cpuSlowdownMultiplier=this._options.cpuSlowdownMultiplier;
+this._layoutTaskMultiplier=this._cpuSlowdownMultiplier*this._options.layoutTaskMultiplier;
+
+this._cachedNodeListByStartTime=[];
+
+
+this._flexibleOrdering=false;
+
+this._nodeTimings=new Map();
+
+this._numberInProgressByType=new Map();
+
+this._nodes={};
+this._dns=new DNSCache({rtt:this._rtt});
+
+this._connectionPool=null;
+}
+
+
+get rtt(){
+return this._rtt;
+}
+
+
+
+
+_initializeConnectionPool(graph){
+
+const records=[];
+graph.getRootNode().traverse(node=>{
+if(node.type===BaseNode.TYPES.NETWORK){
+records.push(node.record);
+}
+});
+
+this._connectionPool=new ConnectionPool(records,this._options);
+}
+
+
+
+
+_initializeAuxiliaryData(){
+this._nodeTimings=new Map();
+this._numberInProgressByType=new Map();
+
+this._nodes={};
+this._cachedNodeListByStartTime=[];
+
+
+
+for(const state of Object.values(NodeState)){
+this._nodes[state]=new Set();
+}
+}
+
+
+
+
+
+_numberInProgress(type){
+return this._numberInProgressByType.get(type)||0;
+}
+
+
+
+
+
+_setTimingData(node,values){
+const timingData=this._nodeTimings.get(node)||{};
+Object.assign(timingData,values);
+this._nodeTimings.set(node,timingData);
+}
+
+
+
+
+
+_getTimingData(node){
+const timingData=this._nodeTimings.get(node);
+if(!timingData)throw new Error(`Unable to get timing data for node ${node.id}`);
+return timingData;
+}
+
+
+
+
+
+_markNodeAsReadyToStart(node,queuedTime){
+const firstNodeIndexWithGreaterStartTime=this._cachedNodeListByStartTime.
+findIndex(candidate=>candidate.startTime>node.startTime);
+const insertionIndex=firstNodeIndexWithGreaterStartTime===-1?
+this._cachedNodeListByStartTime.length:firstNodeIndexWithGreaterStartTime;
+this._cachedNodeListByStartTime.splice(insertionIndex,0,node);
+
+this._nodes[NodeState.ReadyToStart].add(node);
+this._nodes[NodeState.NotReadyToStart].delete(node);
+this._setTimingData(node,{queuedTime});
+}
+
+
+
+
+
+_markNodeAsInProgress(node,startTime){
+const indexOfNodeToStart=this._cachedNodeListByStartTime.indexOf(node);
+this._cachedNodeListByStartTime.splice(indexOfNodeToStart,1);
+
+this._nodes[NodeState.InProgress].add(node);
+this._nodes[NodeState.ReadyToStart].delete(node);
+this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)+1);
+this._setTimingData(node,{startTime});
+}
+
+
+
+
+
+_markNodeAsComplete(node,endTime){
+this._nodes[NodeState.Complete].add(node);
+this._nodes[NodeState.InProgress].delete(node);
+this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)-1);
+this._setTimingData(node,{endTime});
+
+
+for(const dependent of node.getDependents()){
+
+const dependencies=dependent.getDependencies();
+if(dependencies.some(dep=>!this._nodes[NodeState.Complete].has(dep)))continue;
+
+
+this._markNodeAsReadyToStart(dependent,endTime);
+}
+}
+
+
+
+
+
+_acquireConnection(record){
+return this._connectionPool.acquire(record,{
+ignoreConnectionReused:this._flexibleOrdering});
+
+}
+
+
+
+
+_getNodesSortedByStartTime(){
+
+return Array.from(this._cachedNodeListByStartTime);
+}
+
+
+
+
+
+_startNodeIfPossible(node,totalElapsedTime){
+if(node.type===BaseNode.TYPES.CPU){
+
+if(this._numberInProgress(node.type)===0){
+this._markNodeAsInProgress(node,totalElapsedTime);
+this._setTimingData(node,{timeElapsed:0});
+}
+
+return;
+}
+
+if(node.type!==BaseNode.TYPES.NETWORK)throw new Error('Unsupported');
+
+
+if(!node.fromDiskCache){
+
+const numberOfActiveRequests=this._numberInProgress(node.type);
+if(numberOfActiveRequests>=this._maximumConcurrentRequests)return;
+const connection=this._acquireConnection(node.record);
+if(!connection)return;
+}
+
+this._markNodeAsInProgress(node,totalElapsedTime);
+this._setTimingData(node,{
+timeElapsed:0,
+timeElapsedOvershoot:0,
+bytesDownloaded:0});
+
+}
+
+
+
+
+
+_updateNetworkCapacity(){
+for(const connection of this._connectionPool.connectionsInUse()){
+connection.setThroughput(this._throughput/this._nodes[NodeState.InProgress].size);
+}
+}
+
+
+
+
+
+
+_estimateTimeRemaining(node){
+if(node.type===BaseNode.TYPES.CPU){
+return this._estimateCPUTimeRemaining(node);
+}else if(node.type===BaseNode.TYPES.NETWORK){
+return this._estimateNetworkTimeRemaining(node);
+}else{
+throw new Error('Unsupported');
+}
+}
+
+
+
+
+
+_estimateCPUTimeRemaining(cpuNode){
+const timingData=this._getTimingData(cpuNode);
+const multiplier=cpuNode.didPerformLayout()?
+this._layoutTaskMultiplier:
+this._cpuSlowdownMultiplier;
+const totalDuration=Math.min(
+Math.round(cpuNode.event.dur/1000*multiplier),
+DEFAULT_MAXIMUM_CPU_TASK_DURATION);
+
+const estimatedTimeElapsed=totalDuration-timingData.timeElapsed;
+this._setTimingData(cpuNode,{estimatedTimeElapsed});
+return estimatedTimeElapsed;
+}
+
+
+
+
+
+_estimateNetworkTimeRemaining(networkNode){
+const record=networkNode.record;
+const timingData=this._getTimingData(networkNode);
+
+let timeElapsed=0;
+if(networkNode.fromDiskCache){
+
+
+const sizeInMb=(record.resourceSize||0)/1024/1024;
+timeElapsed=8+20*sizeInMb-timingData.timeElapsed;
+}else{
+
+const connection=this._acquireConnection(record);
+const dnsResolutionTime=this._dns.getTimeUntilResolution(record,{
+requestedAt:timingData.startTime,
+shouldUpdateCache:true});
+
+const timeAlreadyElapsed=timingData.timeElapsed;
+const calculation=connection.simulateDownloadUntil(
+record.transferSize-timingData.bytesDownloaded,
+{timeAlreadyElapsed,dnsResolutionTime,maximumTimeToElapse:Infinity});
+
+
+timeElapsed=calculation.timeElapsed;
+}
+
+const estimatedTimeElapsed=timeElapsed+timingData.timeElapsedOvershoot;
+this._setTimingData(networkNode,{estimatedTimeElapsed});
+return estimatedTimeElapsed;
+}
+
+
+
+
+
+_findNextNodeCompletionTime(){
+let minimumTime=Infinity;
+for(const node of this._nodes[NodeState.InProgress]){
+minimumTime=Math.min(minimumTime,this._estimateTimeRemaining(node));
+}
+
+return minimumTime;
+}
+
+
+
+
+
+
+
+_updateProgressMadeInTimePeriod(node,timePeriodLength,totalElapsedTime){
+const timingData=this._getTimingData(node);
+const isFinished=timingData.estimatedTimeElapsed===timePeriodLength;
+
+if(node.type===BaseNode.TYPES.CPU||node.fromDiskCache){
+return isFinished?
+this._markNodeAsComplete(node,totalElapsedTime):
+timingData.timeElapsed+=timePeriodLength;
+}
+
+if(node.type!==BaseNode.TYPES.NETWORK)throw new Error('Unsupported');
+
+const record=node.record;
+
+const connection=this._acquireConnection(record);
+const dnsResolutionTime=this._dns.getTimeUntilResolution(record,{
+requestedAt:timingData.startTime,
+shouldUpdateCache:true});
+
+const calculation=connection.simulateDownloadUntil(
+record.transferSize-timingData.bytesDownloaded,
+{
+dnsResolutionTime,
+timeAlreadyElapsed:timingData.timeElapsed,
+maximumTimeToElapse:timePeriodLength-timingData.timeElapsedOvershoot});
+
+
+
+connection.setCongestionWindow(calculation.congestionWindow);
+connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);
+
+if(isFinished){
+connection.setWarmed(true);
+this._connectionPool.release(record);
+this._markNodeAsComplete(node,totalElapsedTime);
+}else{
+timingData.timeElapsed+=calculation.timeElapsed;
+timingData.timeElapsedOvershoot+=calculation.timeElapsed-timePeriodLength;
+timingData.bytesDownloaded+=calculation.bytesDownloaded;
+}
+}
+
+
+
+
+_computeFinalNodeTimings(){
+
+const nodeTimingEntries=[];
+for(const[node,timing]of this._nodeTimings){
+nodeTimingEntries.push([node,{
+startTime:timing.startTime,
+endTime:timing.endTime,
+duration:timing.endTime-timing.startTime}]);
+
+}
+
+
+nodeTimingEntries.sort((a,b)=>a[1].startTime-b[1].startTime);
+return new Map(nodeTimingEntries);
+}
+
+
+
+
+getOptions(){
+return this._options;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+simulate(graph,options){
+if(BaseNode.hasCycle(graph)){
+throw new Error('Cannot simulate graph with cycle');
+}
+
+options=Object.assign({
+label:undefined,
+flexibleOrdering:false},
+options);
+
+
+this._flexibleOrdering=!!options.flexibleOrdering;
+this._dns=new DNSCache({rtt:this._rtt});
+this._initializeConnectionPool(graph);
+this._initializeAuxiliaryData();
+
+const nodesNotReadyToStart=this._nodes[NodeState.NotReadyToStart];
+const nodesReadyToStart=this._nodes[NodeState.ReadyToStart];
+const nodesInProgress=this._nodes[NodeState.InProgress];
+
+const rootNode=graph.getRootNode();
+rootNode.traverse(node=>nodesNotReadyToStart.add(node));
+let totalElapsedTime=0;
+let iteration=0;
+
+
+this._markNodeAsReadyToStart(rootNode,totalElapsedTime);
+
+
+while(nodesReadyToStart.size||nodesInProgress.size){
+
+for(const node of this._getNodesSortedByStartTime()){
+this._startNodeIfPossible(node,totalElapsedTime);
+}
+
+if(!nodesInProgress.size){
+
+
+if(this._flexibleOrdering)throw new Error('Failed to start a node');
+this._flexibleOrdering=true;
+continue;
+}
+
+
+this._updateNetworkCapacity();
+
+
+const minimumTime=this._findNextNodeCompletionTime();
+totalElapsedTime+=minimumTime;
+
+
+if(!Number.isFinite(minimumTime)||iteration>100000){
+throw new Error('Graph creation failed, depth exceeded');
+}
+
+iteration++;
+
+for(const node of nodesInProgress){
+this._updateProgressMadeInTimePeriod(node,minimumTime,totalElapsedTime);
+}
+}
+
+const nodeTimings=this._computeFinalNodeTimings();
+ALL_SIMULATION_NODE_TIMINGS.set(options.label||'unlabeled',nodeTimings);
+
+return{
+timeInMs:totalElapsedTime,
+nodeTimings};
+
+}
+
+
+static get ALL_NODE_TIMINGS(){
+return ALL_SIMULATION_NODE_TIMINGS;
+}}
+
+
+module.exports=Simulator;
+
+
+
+
+
+
+
+
+
+
+
+
+},{"../../../config/constants":36,"../base-node":48,"./connection-pool":51,"./dns-cache":52,"./tcp-connection":55}],55:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const INITIAL_CONGESTION_WINDOW=10;
+const TCP_SEGMENT_SIZE=1460;
+
+class TcpConnection{
+
+
+
+
+
+
+
+constructor(rtt,throughput,serverLatency=0,ssl=true,h2=false){
+this._warmed=false;
+this._ssl=ssl;
+this._h2=h2;
+this._rtt=rtt;
+this._throughput=throughput;
+this._serverLatency=serverLatency;
+this._congestionWindow=INITIAL_CONGESTION_WINDOW;
+this._h2OverflowBytesDownloaded=0;
+}
+
+
+
+
+
+
+static maximumSaturatedConnections(rtt,availableThroughput){
+const roundTripsPerSecond=1000/rtt;
+const bytesPerRoundTrip=TCP_SEGMENT_SIZE;
+const bytesPerSecond=roundTripsPerSecond*bytesPerRoundTrip;
+const minimumThroughputRequiredPerRequest=bytesPerSecond*8;
+return Math.floor(availableThroughput/minimumThroughputRequiredPerRequest);
+}
+
+
+
+
+_computeMaximumCongestionWindowInSegments(){
+const bytesPerSecond=this._throughput/8;
+const secondsPerRoundTrip=this._rtt/1000;
+const bytesPerRoundTrip=bytesPerSecond*secondsPerRoundTrip;
+return Math.floor(bytesPerRoundTrip/TCP_SEGMENT_SIZE);
+}
+
+
+
+
+setThroughput(throughput){
+this._throughput=throughput;
+}
+
+
+
+
+setCongestionWindow(congestion){
+this._congestionWindow=congestion;
+}
+
+
+
+
+setWarmed(warmed){
+this._warmed=warmed;
+}
+
+
+
+
+isWarm(){
+return this._warmed;
+}
+
+
+
+
+isH2(){
+return this._h2;
+}
+
+
+
+
+get congestionWindow(){
+return this._congestionWindow;
+}
+
+
+
+
+
+
+setH2OverflowBytesDownloaded(bytes){
+if(!this._h2)return;
+this._h2OverflowBytesDownloaded=bytes;
+}
+
+
+
+
+clone(){
+return Object.assign(new TcpConnection(this._rtt,this._throughput),this);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+simulateDownloadUntil(bytesToDownload,options){
+const{timeAlreadyElapsed=0,maximumTimeToElapse=Infinity,dnsResolutionTime=0}=
+options||{};
+
+if(this._warmed&&this._h2){
+bytesToDownload-=this._h2OverflowBytesDownloaded;
+}
+const twoWayLatency=this._rtt;
+const oneWayLatency=twoWayLatency/2;
+const maximumCongestionWindow=this._computeMaximumCongestionWindowInSegments();
+
+let handshakeAndRequest=oneWayLatency;
+if(!this._warmed){
+handshakeAndRequest=
+
+dnsResolutionTime+
+
+oneWayLatency+
+
+oneWayLatency+
+
+oneWayLatency+(
+
+this._ssl?twoWayLatency:0);
+}
+
+let roundTrips=Math.ceil(handshakeAndRequest/twoWayLatency);
+let timeToFirstByte=handshakeAndRequest+this._serverLatency+oneWayLatency;
+if(this._warmed&&this._h2)timeToFirstByte=0;
+
+const timeElapsedForTTFB=Math.max(timeToFirstByte-timeAlreadyElapsed,0);
+const maximumDownloadTimeToElapse=maximumTimeToElapse-timeElapsedForTTFB;
+
+let congestionWindow=Math.min(this._congestionWindow,maximumCongestionWindow);
+let totalBytesDownloaded=0;
+if(timeElapsedForTTFB>0){
+totalBytesDownloaded=congestionWindow*TCP_SEGMENT_SIZE;
+}else{
+roundTrips=0;
+}
+
+let downloadTimeElapsed=0;
+let bytesRemaining=bytesToDownload-totalBytesDownloaded;
+while(bytesRemaining>0&&downloadTimeElapsed<=maximumDownloadTimeToElapse){
+roundTrips++;
+downloadTimeElapsed+=twoWayLatency;
+congestionWindow=Math.max(Math.min(maximumCongestionWindow,congestionWindow*2),1);
+
+const bytesDownloadedInWindow=congestionWindow*TCP_SEGMENT_SIZE;
+totalBytesDownloaded+=bytesDownloadedInWindow;
+bytesRemaining-=bytesDownloadedInWindow;
+}
+
+const timeElapsed=timeElapsedForTTFB+downloadTimeElapsed;
+const extraBytesDownloaded=this._h2?Math.max(totalBytesDownloaded-bytesToDownload,0):0;
+const bytesDownloaded=Math.max(Math.min(totalBytesDownloaded,bytesToDownload),0);
+
+return{
+roundTrips,
+timeElapsed,
+bytesDownloaded,
+extraBytesDownloaded,
+congestionWindow};
+
+}}
+
+
+module.exports=TcpConnection;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+},{}],56:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Driver=require('../gather/driver.js');
+
+class Element{
+
+
+
+
+constructor(element,driver){
+if(!element||!driver){
+throw Error('Driver and element required to create Element');
+}
+this.driver=driver;
+this.element=element;
+}
+
+
+
+
+
+getAttribute(name){
+return this.driver.
+sendCommand('DOM.getAttributes',{
+nodeId:this.element.nodeId}).
+
+
+
+
+then(resp=>{
+const attrIndex=resp.attributes.indexOf(name);
+if(attrIndex===-1){
+return null;
+}
+
+return resp.attributes[attrIndex+1];
+});
+}
+
+
+
+
+getNodeId(){
+return this.element.nodeId;
+}
+
+
+
+
+
+getProperty(propName){
+return this.driver.
+sendCommand('DOM.resolveNode',{
+nodeId:this.element.nodeId}).
+
+then(resp=>{
+if(!resp.object.objectId){
+return null;
+}
+return this.driver.getObjectProperty(resp.object.objectId,propName);
+}).
+catch(()=>null);
+}}
+
+
+module.exports=Element;
+
+},{"../gather/driver.js":42}],57:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const NEXUS5X_EMULATION_METRICS={
+mobile:true,
+screenWidth:412,
+screenHeight:660,
+width:412,
+height:660,
+positionX:0,
+positionY:0,
+scale:1,
+deviceScaleFactor:2.625,
+screenOrientation:{
+angle:0,
+type:'portraitPrimary'}};
+
+
+
+
+
+
+
+const DESKTOP_EMULATION_METRICS={
+mobile:false,
+width:1350,
+height:940,
+deviceScaleFactor:1};
+
+
+const NEXUS5X_USERAGENT={
+
+userAgent:'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3559.0 Mobile Safari/537.36'};
+
+
+const DESKTOP_USERAGENT={
+
+userAgent:'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3559.0 Safari/537.36'};
+
+
+const OFFLINE_METRICS={
+offline:true,
+
+latency:0,
+downloadThroughput:0,
+uploadThroughput:0};
+
+
+const NO_THROTTLING_METRICS={
+latency:0,
+downloadThroughput:0,
+uploadThroughput:0,
+offline:false};
+
+
+const NO_CPU_THROTTLE_METRICS={
+rate:1};
+
+
+
+
+
+
+async function enableNexus5X(driver){
+await Promise.all([
+driver.sendCommand('Emulation.setDeviceMetricsOverride',NEXUS5X_EMULATION_METRICS),
+
+driver.sendCommand('Network.enable'),
+driver.sendCommand('Network.setUserAgentOverride',NEXUS5X_USERAGENT),
+driver.sendCommand('Emulation.setTouchEmulationEnabled',{enabled:true})]);
+
+}
+
+
+
+
+
+async function enableDesktop(driver){
+await Promise.all([
+driver.sendCommand('Emulation.setDeviceMetricsOverride',DESKTOP_EMULATION_METRICS),
+
+driver.sendCommand('Network.enable'),
+driver.sendCommand('Network.setUserAgentOverride',DESKTOP_USERAGENT),
+driver.sendCommand('Emulation.setTouchEmulationEnabled',{enabled:false})]);
+
+}
+
+
+
+
+
+
+function enableNetworkThrottling(driver,throttlingSettings){
+
+const conditions={
+offline:false,
+latency:throttlingSettings.requestLatencyMs||0,
+downloadThroughput:throttlingSettings.downloadThroughputKbps||0,
+uploadThroughput:throttlingSettings.uploadThroughputKbps||0};
+
+
+
+conditions.downloadThroughput=Math.floor(conditions.downloadThroughput*1024/8);
+conditions.uploadThroughput=Math.floor(conditions.uploadThroughput*1024/8);
+return driver.sendCommand('Network.emulateNetworkConditions',conditions);
+}
+
+
+
+
+
+function clearAllNetworkEmulation(driver){
+return driver.sendCommand('Network.emulateNetworkConditions',NO_THROTTLING_METRICS);
+}
+
+
+
+
+
+function goOffline(driver){
+return driver.sendCommand('Network.emulateNetworkConditions',OFFLINE_METRICS);
+}
+
+
+
+
+
+
+function enableCPUThrottling(driver,throttlingSettings){
+const rate=throttlingSettings.cpuSlowdownMultiplier;
+return driver.sendCommand('Emulation.setCPUThrottlingRate',{rate});
+}
+
+
+
+
+
+function disableCPUThrottling(driver){
+return driver.sendCommand('Emulation.setCPUThrottlingRate',NO_CPU_THROTTLE_METRICS);
+}
+
+module.exports={
+enableNexus5X,
+enableDesktop,
+enableNetworkThrottling,
+clearAllNetworkEmulation,
+enableCPUThrottling,
+disableCPUThrottling,
+goOffline};
+
+
+},{}],58:[function(require,module,exports){
+module.exports={
+"lighthouse-core/audits/accessibility/aria-allowed-attr.js | description":{
+"message":"Each ARIA `role` supports a specific subset of `aria-*` attributes. Mismatching these invalidates the `aria-*` attributes. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-allowed-attr?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-allowed-attr.js | failureTitle":{
+"message":"`[aria-*]` attributes do not match their roles",
+"description":"Title of an accesibility audit that evaluates if the ARIA HTML attributes are misaligned with the aria-role HTML attribute specificed on the element, such mismatches are invalid. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-allowed-attr.js | title":{
+"message":"`[aria-*]` attributes match their roles",
+"description":"Title of an accesibility audit that evaluates if the ARIA HTML attributes are misaligned with the aria-role HTML attribute specificed on the element, such mismatches are invalid. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/aria-required-attr.js | description":{
+"message":"Some ARIA roles have required attributes that describe the state of the element to screen readers. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-required-attr?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-required-attr.js | failureTitle":{
+"message":"`[role]`s do not have all required `[aria-*]` attributes",
+"description":"Title of an accesibility audit that evaluates if all elements with the aria-role attribute have the other corresponding ARIA attributes set as well. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-required-attr.js | title":{
+"message":"`[role]`s have all required `[aria-*]` attributes",
+"description":"Title of an accesibility audit that evaluates if all elements with the aria-role attribute have the other corresponding ARIA attributes set as well. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/aria-required-children.js | description":{
+"message":"Some ARIA parent roles must contain specific child roles to perform their intended accessibility functions. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-required-children?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-required-children.js | failureTitle":{
+"message":"Elements with `[role]` that require specific children `[role]`s, are missing.",
+"description":"Title of an accesibility audit that evaluates if the elements with an aria-role that require child elements have the required children. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-required-children.js | title":{
+"message":"Elements with `[role]` that require specific children `[role]`s, are present",
+"description":"Title of an accesibility audit that evaluates if the elements with an aria-role that require child elements have the required children. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/aria-required-parent.js | description":{
+"message":"Some ARIA child roles must be contained by specific parent roles to properly perform their intended accessibility functions. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-required-parent?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-required-parent.js | failureTitle":{
+"message":"`[role]`s are not contained by their required parent element",
+"description":"Title of an accesibility audit that evaluates valid aria-role usage. Some ARIA roles require that elements must be a child of specific parent element. This audit checks that when those roles are used, the element with the role is in fact a child of the required parent. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-required-parent.js | title":{
+"message":"`[role]`s are contained by their required parent element",
+"description":"Title of an accesibility audit that evaluates valid aria-role usage. Some ARIA roles require that elements must be a child of specific parent element. This audit checks that when those roles are used, the element with the role is in fact a child of the required parent. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/aria-roles.js | description":{
+"message":"ARIA roles must have valid values in order to perform their intended accessibility functions. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-roles?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-roles.js | failureTitle":{
+"message":"`[role]` values are not valid",
+"description":"Title of an accesibility audit that evaluates if all elements have valid aria-role HTML attributes. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-roles.js | title":{
+"message":"`[role]` values are valid",
+"description":"Title of an accesibility audit that evaluates if all elements have valid aria-role HTML attributes. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/aria-valid-attr-value.js | description":{
+"message":"Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid values. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-valid-attr-value?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-valid-attr-value.js | failureTitle":{
+"message":"`[aria-*]` attributes do not have valid values",
+"description":"Title of an accesibility audit that evaluates if all elements that have an ARIA HTML attribute have a valid value for that attribute. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-valid-attr-value.js | title":{
+"message":"`[aria-*]` attributes have valid values",
+"description":"Title of an accesibility audit that evaluates if all elements that have an ARIA HTML attribute have a valid value for that attribute. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/aria-valid-attr.js | description":{
+"message":"Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid names. [Learn more](https://dequeuniversity.com/rules/axe/3.1/aria-valid-attr?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/aria-valid-attr.js | failureTitle":{
+"message":"`[aria-*]` attributes are not valid or misspelled",
+"description":"Title of an accesibility audit that evaluates if all elements with ARIA HTML attributes have spelled the name of attribute correctly. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/aria-valid-attr.js | title":{
+"message":"`[aria-*]` attributes are valid and not misspelled",
+"description":"Title of an accesibility audit that evaluates if all elements with ARIA HTML attributes have spelled the name of attribute correctly. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/audio-caption.js | description":{
+"message":"Captions make audio elements usable for deaf or hearing-impaired users, providing critical information such as who is talking, what they're saying, and other non-speech information. [Learn more](https://dequeuniversity.com/rules/axe/3.1/audio-caption?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/audio-caption.js | failureTitle":{
+"message":"`<audio>` elements are missing a `<track>` element with `[kind=\"captions\"]`.",
+"description":"Title of an accesibility audit that evaluates if all audio elements have a track element that has captions for screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/audio-caption.js | title":{
+"message":"`<audio>` elements contain a `<track>` element with `[kind=\"captions\"]`",
+"description":"Title of an accesibility audit that evaluates if all audio elements have a track element that has captions for screen readers. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/axe-audit.js | failingElementsHeader":{
+"message":"Failing Elements",
+"description":"Label of a table column that identifies HTML elements that have failed an audit."},
+
+"lighthouse-core/audits/accessibility/button-name.js | description":{
+"message":"When a button doesn't have an accessible name, screen readers announce it as \"button\", making it unusable for users who rely on screen readers. [Learn more](https://dequeuniversity.com/rules/axe/3.1/button-name?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/button-name.js | failureTitle":{
+"message":"Buttons do not have an accessible name",
+"description":"Title of an accesibility audit that evaluates if all button elements have names accessible to screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/button-name.js | title":{
+"message":"Buttons have an accessible name",
+"description":"Title of an accesibility audit that evaluates if all button elements have names accessible to screen readers. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/bypass.js | description":{
+"message":"Adding ways to bypass repetitive content lets keyboard users navigate the page more efficiently. [Learn more](https://dequeuniversity.com/rules/axe/3.1/bypass?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/bypass.js | failureTitle":{
+"message":"The page does not contain a heading, skip link, or landmark region",
+"description":"Title of an accesibility audit that evaluates if the page has elements that let screen reader users skip over repetitive content. `heading`, `skip link`, and `landmark region` are technical terms for the elements that enable quick page navigation. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/bypass.js | title":{
+"message":"The page contains a heading, skip link, or landmark region",
+"description":"Title of an accesibility audit that evaluates if the page has elements that let screen reader users skip over repetitive content. `heading`, `skip link`, and `landmark region` are technical terms for the elements that enable quick page navigation. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/color-contrast.js | description":{
+"message":"Low-contrast text is difficult or impossible for many users to read. [Learn more](https://dequeuniversity.com/rules/axe/3.1/color-contrast?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/color-contrast.js | failureTitle":{
+"message":"Background and foreground colors do not have a sufficient contrast ratio.",
+"description":"Title of an accesibility audit that evaluates if all foreground colors are distinct enough from their background colors to be legible for users. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/color-contrast.js | title":{
+"message":"Background and foreground colors have a sufficient contrast ratio",
+"description":"Title of an accesibility audit that evaluates if all foreground colors are distinct enough from their background colors to be legible for users. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/definition-list.js | description":{
+"message":"When definition lists are not properly marked up, screen readers may produce confusing or inaccurate output. [Learn more](https://dequeuniversity.com/rules/axe/3.1/definition-list?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/definition-list.js | failureTitle":{
+"message":"`<dl>`'s do not contain only properly-ordered `<dt>` and `<dd>` groups, `<script>` or `<template>` elements.",
+"description":"Title of an accesibility audit that evaluates if all the definition list elements have valid markup for screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/definition-list.js | title":{
+"message":"`<dl>`'s contain only properly-ordered `<dt>` and `<dd>` groups, `<script>` or `<template>` elements.",
+"description":"Title of an accesibility audit that evaluates if all the definition list elements have valid markup for screen readers. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/dlitem.js | description":{
+"message":"Definition list items (`<dt>` and `<dd>`) must be wrapped in a parent `<dl>` element to ensure that screen readers can properly announce them. [Learn more](https://dequeuniversity.com/rules/axe/3.1/dlitem?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/dlitem.js | failureTitle":{
+"message":"Definition list items are not wrapped in `<dl>` elements",
+"description":"Title of an accesibility audit that evaluates if all definition list item elements (`<dt>`/`<dd>`) have a definition list parent element (`<dl>`). This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/dlitem.js | title":{
+"message":"Definition list items are wrapped in `<dl>` elements",
+"description":"Title of an accesibility audit that evaluates if all definition list item elements (`<dt>`/`<dd>`) have a definition list parent element (`<dl>`). This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/document-title.js | description":{
+"message":"The title gives screen reader users an overview of the page, and search engine users rely on it heavily to determine if a page is relevant to their search. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/title).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/document-title.js | failureTitle":{
+"message":"Document doesn't have a `<title>` element",
+"description":"Title of an accesibility audit that evaluates if the page has a <title> element that describes the page. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/document-title.js | title":{
+"message":"Document has a `<title>` element",
+"description":"Title of an accesibility audit that evaluates if the page has a <title> element that describes the page. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/duplicate-id.js | description":{
+"message":"The value of an id attribute must be unique to prevent other instances from being overlooked by assistive technologies. [Learn more](https://dequeuniversity.com/rules/axe/3.1/duplicate-id?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/duplicate-id.js | failureTitle":{
+"message":"`[id]` attributes on the page are not unique",
+"description":"Title of an accesibility audit that evaluates if there are any duplicate id HTML attributes on the page. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/duplicate-id.js | title":{
+"message":"`[id]` attributes on the page are unique",
+"description":"Title of an accesibility audit that evaluates if there are any duplicate id HTML attributes on the page. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/frame-title.js | description":{
+"message":"Screen reader users rely on frame titles to describe the contents of frames. [Learn more](https://dequeuniversity.com/rules/axe/3.1/frame-title?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/frame-title.js | failureTitle":{
+"message":"`<frame>` or `<iframe>` elements do not have a title",
+"description":"Title of an accesibility audit that evaluates if all `<frame>` and `<iframe>` elements on the page have a title HTML attribute to describe their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/frame-title.js | title":{
+"message":"`<frame>` or `<iframe>` elements have a title",
+"description":"Title of an accesibility audit that evaluates if all `<frame>` and `<iframe>` elements on the page have a title HTML attribute to describe their contents. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/html-has-lang.js | description":{
+"message":"If a page doesn't specify a lang attribute, a screen reader assumes that the page is in the default language that the user chose when setting up the screen reader. If the page isn't actually in the default language, then the screen reader might not announce the page's text correctly. [Learn more](https://dequeuniversity.com/rules/axe/3.1/html-has-lang?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/html-has-lang.js | failureTitle":{
+"message":"`<html>` element does not have a `[lang]` attribute",
+"description":"Title of an accesibility audit that evaluates if the root HTML tag has a lang attribute identifying the page's language. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/html-has-lang.js | title":{
+"message":"`<html>` element has a `[lang]` attribute",
+"description":"Title of an accesibility audit that evaluates if the root HTML tag has a lang attribute identifying the page's language. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/html-lang-valid.js | description":{
+"message":"Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) helps screen readers announce text properly. [Learn more](https://dequeuniversity.com/rules/axe/3.1/valid-lang?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/html-lang-valid.js | failureTitle":{
+"message":"`<html>` element does not have a valid value for its `[lang]` attribute.",
+"description":"Title of an accesibility audit that evaluates if the value for root HTML tag's lang attribute is a valid BCP 47 language. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/html-lang-valid.js | title":{
+"message":"`<html>` element has a valid value for its `[lang]` attribute",
+"description":"Title of an accesibility audit that evaluates if the value for root HTML tag's lang attribute is a valid BCP 47 language. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/image-alt.js | description":{
+"message":"Informative elements should aim for short, descriptive alternate text. Decorative elements can be ignored with an empty alt attribute. [Learn more](https://dequeuniversity.com/rules/axe/3.1/image-alt?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/image-alt.js | failureTitle":{
+"message":"Image elements do not have `[alt]` attributes",
+"description":"Title of an accesibility audit that evaluates if all image elements have the alt HTML attribute to describe their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/image-alt.js | title":{
+"message":"Image elements have `[alt]` attributes",
+"description":"Title of an accesibility audit that evaluates if all image elements have the alt HTML attribute to describe their contents. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/input-image-alt.js | description":{
+"message":"When an image is being used as an `<input>` button, providing alternative text can help screen reader users understand the purpose of the button. [Learn more](https://dequeuniversity.com/rules/axe/3.1/input-image-alt?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/input-image-alt.js | failureTitle":{
+"message":"`<input type=\"image\">` elements do not have `[alt]` text",
+"description":"Title of an accesibility audit that evaluates if all input elements of type image have an alt HTML attribute to describe their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/input-image-alt.js | title":{
+"message":"`<input type=\"image\">` elements have `[alt]` text",
+"description":"Title of an accesibility audit that evaluates if all input elements of type image have an alt HTML attribute to describe their contents. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/label.js | description":{
+"message":"Labels ensure that form controls are announced properly by assistive technologies, like screen readers. [Learn more](https://dequeuniversity.com/rules/axe/3.1/label?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/label.js | failureTitle":{
+"message":"Form elements do not have associated labels",
+"description":"Title of an accesibility audit that evaluates if all form elements have corresponding label elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/label.js | title":{
+"message":"Form elements have associated labels",
+"description":"Title of an accesibility audit that evaluates if all form elements have corresponding label elements. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/layout-table.js | description":{
+"message":"A table being used for layout purposes should not include data elements, such as the th or caption elements or the summary attribute, because this can create a confusing experience for screen reader users. [Learn more](https://dequeuniversity.com/rules/axe/3.1/layout-table?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/layout-table.js | failureTitle":{
+"message":"Presentational `<table>` elements do not avoid using `<th>`, `<caption>` or the `[summary]` attribute.",
+"description":"Title of an accesibility audit that evaluates if a table intended for layout contains data annotations as it can be confusing for screen readers. This is evaluated by checking if tables with the ARIA role of `presentation` or `none` contain any data elements such as table headers (`<th>`). This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/layout-table.js | title":{
+"message":"Presentational `<table>` elements avoid using `<th>`, `<caption>` or the `[summary]` attribute.",
+"description":"Title of an accesibility audit that evaluates if a table intended for layout contains data annotations as it can be confusing for screen readers. This is evaluated by checking if tables with the ARIA role of `presentation` or `none` contain any data elements such as table headers (`<th>`). This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/link-name.js | description":{
+"message":"Link text (and alternate text for images, when used as links) that is discernible, unique, and focusable improves the navigation experience for screen reader users. [Learn more](https://dequeuniversity.com/rules/axe/3.1/link-name?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/link-name.js | failureTitle":{
+"message":"Links do not have a discernible name",
+"description":"Title of an accesibility audit that evaluates if all link elements have a non-generic name to screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/link-name.js | title":{
+"message":"Links have a discernible name",
+"description":"Title of an accesibility audit that evaluates if all link elements have a non-generic name to screen readers. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/list.js | description":{
+"message":"Screen readers have a specific way of announcing lists. Ensuring proper list structure aids screen reader output. [Learn more](https://dequeuniversity.com/rules/axe/3.1/list?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/list.js | failureTitle":{
+"message":"Lists do not contain only `<li>` elements and script supporting elements (`<script>` and `<template>`).",
+"description":"Title of an accesibility audit that evaluates if all list elements have a valid structure containing only list items. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/list.js | title":{
+"message":"Lists contain only `<li>` elements and script supporting elements (`<script>` and `<template>`).",
+"description":"Title of an accesibility audit that evaluates if all list elements have a valid structure containing only list items. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/listitem.js | description":{
+"message":"Screen readers require list items (`<li>`) to be contained within a parent `<ul>` or `<ol>` to be announced properly. [Learn more](https://dequeuniversity.com/rules/axe/3.1/listitem?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/listitem.js | failureTitle":{
+"message":"List items (`<li>`) are not contained within `<ul>` or `<ol>` parent elements.",
+"description":"Title of an accesibility audit that evaluates if any list item elements do not have list parent elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/listitem.js | title":{
+"message":"List items (`<li>`) are contained within `<ul>` or `<ol>` parent elements",
+"description":"Title of an accesibility audit that evaluates if any list item elements do not have list parent elements. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/manual/accesskeys.js | description":{
+"message":"Access keys let users quickly focus a part of the page. For proper navigation, each access key must be unique. [Learn more](https://dequeuniversity.com/rules/axe/3.1/accesskeys?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/manual/accesskeys.js | title":{
+"message":"`[accesskey]` values are unique",
+"description":"Title of an accesibility audit that evaluates if the accesskey HTML attribute values are unique across all elements. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/meta-refresh.js | description":{
+"message":"Users do not expect a page to refresh automatically, and doing so will move focus back to the top of the page. This may create a frustrating or confusing experience. [Learn more](https://dequeuniversity.com/rules/axe/3.1/meta-refresh?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/meta-refresh.js | failureTitle":{
+"message":"The document uses `<meta http-equiv=\"refresh\">`",
+"description":"Title of an accesibility audit that evaluates if the page uses a meta tag that refreshes the page automatically. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/meta-refresh.js | title":{
+"message":"The document does not use `<meta http-equiv=\"refresh\">`",
+"description":"Title of an accesibility audit that evaluates if the page uses a meta tag that refreshes the page automatically. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/meta-viewport.js | description":{
+"message":"Disabling zooming is problematic for users with low vision who rely on screen magnification to properly see the contents of a web page. [Learn more](https://dequeuniversity.com/rules/axe/3.1/meta-viewport?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/meta-viewport.js | failureTitle":{
+"message":"`[user-scalable=\"no\"]` is used in the `<meta name=\"viewport\">` element or the `[maximum-scale]` attribute is less than 5.",
+"description":"Title of an accesibility audit that evaluates if the page has limited the scaling properties of the page in a way that harms users with low vision. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/meta-viewport.js | title":{
+"message":"`[user-scalable=\"no\"]` is not used in the `<meta name=\"viewport\">` element and the `[maximum-scale]` attribute is not less than 5.",
+"description":"Title of an accesibility audit that evaluates if the page has limited the scaling properties of the page in a way that harms users with low vision. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/object-alt.js | description":{
+"message":"Screen readers cannot translate non-text content. Adding alt text to `<object>` elements helps screen readers convey meaning to users. [Learn more](https://dequeuniversity.com/rules/axe/3.1/object-alt?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/object-alt.js | failureTitle":{
+"message":"`<object>` elements do not have `[alt]` text",
+"description":"Title of an accesibility audit that evaluates if all object elements have an alt HTML attribute that describes their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/object-alt.js | title":{
+"message":"`<object>` elements have `[alt]` text",
+"description":"Title of an accesibility audit that evaluates if all object elements have an alt HTML attribute that describes their contents. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/tabindex.js | description":{
+"message":"A value greater than 0 implies an explicit navigation ordering. Although technically valid, this often creates frustrating experiences for users who rely on assistive technologies. [Learn more](https://dequeuniversity.com/rules/axe/3.1/tabindex?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/tabindex.js | failureTitle":{
+"message":"Some elements have a `[tabindex]` value greater than 0",
+"description":"Title of an accesibility audit that evaluates if any elements have custom tabindex HTML attributes that might frustrate users of assitive technology. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/tabindex.js | title":{
+"message":"No element has a `[tabindex]` value greater than 0",
+"description":"Title of an accesibility audit that evaluates if any elements have custom tabindex HTML attributes that might frustrate users of assitive technology. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/td-headers-attr.js | description":{
+"message":"Screen readers have features to make navigating tables easier. Ensuring `<td>` cells using the `[headers]` attribute only refer to other cells in the same table may improve the experience for screen reader users. [Learn more](https://dequeuniversity.com/rules/axe/3.1/td-headers-attr?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/td-headers-attr.js | failureTitle":{
+"message":"Cells in a `<table>` element that use the `[headers]` attribute refers to other cells of that same table.",
+"description":"Title of an accesibility audit that evaluates if all table cell elements in a table that use the headers HTML attribute use it correctly to refer to cells within the same table. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/td-headers-attr.js | title":{
+"message":"Cells in a `<table>` element that use the `[headers]` attribute only refer to other cells of that same table.",
+"description":"Title of an accesibility audit that evaluates if all table cell elements in a table that use the headers HTML attribute use it correctly to refer to cells within the same table. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/th-has-data-cells.js | description":{
+"message":"Screen readers have features to make navigating tables easier. Ensuring table headers always refer to some set of cells may improve the experience for screen reader users. [Learn more](https://dequeuniversity.com/rules/axe/3.1/th-has-data-cells?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/th-has-data-cells.js | failureTitle":{
+"message":"`<th>` elements and elements with `[role=\"columnheader\"/\"rowheader\"]` do not have data cells they describe.",
+"description":"Title of an accesibility audit that evaluates if all table header elements have children. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/th-has-data-cells.js | title":{
+"message":"`<th>` elements and elements with `[role=\"columnheader\"/\"rowheader\"]` have data cells they describe.",
+"description":"Title of an accesibility audit that evaluates if all table header elements have children. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/valid-lang.js | description":{
+"message":"Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) on elements helps ensure that text is pronounced correctly by a screen reader. [Learn more](https://dequeuniversity.com/rules/axe/3.1/valid-lang?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/valid-lang.js | failureTitle":{
+"message":"`[lang]` attributes do not have a valid value",
+"description":"Title of an accesibility audit that evaluates if all lang HTML attributes are valid BCP 47 languages. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/valid-lang.js | title":{
+"message":"`[lang]` attributes have a valid value",
+"description":"Title of an accesibility audit that evaluates if all lang HTML attributes are valid BCP 47 languages. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/video-caption.js | description":{
+"message":"When a video provides a caption it is easier for deaf and hearing impaired users to access its information. [Learn more](https://dequeuniversity.com/rules/axe/3.1/video-caption?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/video-caption.js | failureTitle":{
+"message":"`<video>` elements do not contain a `<track>` element with `[kind=\"captions\"]`.",
+"description":"Title of an accesibility audit that evaluates if all video elements contain a child track element that has captions describing their audio. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/video-caption.js | title":{
+"message":"`<video>` elements contain a `<track>` element with `[kind=\"captions\"]`",
+"description":"Title of an accesibility audit that evaluates if all video elements contain a child track element that has captions describing their audio. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/accessibility/video-description.js | description":{
+"message":"Audio descriptions provide relevant information for videos that dialogue cannot, such as facial expressions and scenes. [Learn more](https://dequeuniversity.com/rules/axe/3.1/video-description?application=lighthouse).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/accessibility/video-description.js | failureTitle":{
+"message":"`<video>` elements do not contain a `<track>` element with `[kind=\"description\"]`.",
+"description":"Title of an accesibility audit that evaluates if all video elements have child track elements that contain a description of the video content. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed."},
+
+"lighthouse-core/audits/accessibility/video-description.js | title":{
+"message":"`<video>` elements contain a `<track>` element with `[kind=\"description\"]`",
+"description":"Title of an accesibility audit that evaluates if all video elements have child track elements that contain a description of the video content. This title is descriptive of the successful state and is shown to users when no user action is required."},
+
+"lighthouse-core/audits/bootup-time.js | chromeExtensionsWarning":{
+"message":"Chrome extensions negatively affected this page's load performance. Try auditing the page in incognito mode or from a Chrome profile without extensions.",
+"description":"A message displayed in a Lighthouse audit result warning that Chrome extensions on the user's system substantially affected Lighthouse's measurements and instructs the user on how to run again without those extensions."},
+
+"lighthouse-core/audits/bootup-time.js | columnScriptEval":{
+"message":"Script Evaluation",
+"description":"Label for a time column in a data table; entries will be the number of milliseconds spent evaluating script for every script loaded by the page."},
+
+"lighthouse-core/audits/bootup-time.js | columnScriptParse":{
+"message":"Script Parse",
+"description":"Label for a time column in a data table; entries will be the number of milliseconds spent parsing script files for every script loaded by the page."},
+
+"lighthouse-core/audits/bootup-time.js | columnTotal":{
+"message":"Total",
+"description":"Label for the total time column in a data table; entries will be the number of milliseconds spent executing per resource loaded by the page."},
+
+"lighthouse-core/audits/bootup-time.js | description":{
+"message":"Consider reducing the time spent parsing, compiling, and executing JS. You may find delivering smaller JS payloads helps with this. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/bootup).",
+"description":"Description of a Lighthouse audit that tells the user that they should reduce the amount of time spent executing javascript and one method of doing so. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/bootup-time.js | failureTitle":{
+"message":"Reduce JavaScript execution time",
+"description":"Title of a diagnostic audit that provides detail on the time spent executing javascript files during the load. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
+
+"lighthouse-core/audits/bootup-time.js | title":{
+"message":"JavaScript execution time",
+"description":"Title of a diagnostic audit that provides detail on the time spent executing javascript files during the load. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
+
+"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | description":{
+"message":"Large GIFs are inefficient for delivering animated content. Consider using MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)",
+"description":"Description of a Lighthouse audit that tells the user *why* they should use video instead of GIF format for delivering animated content. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/efficient-animated-content.js | title":{
+"message":"Use video formats for animated content",
+"description":"Imperative title of a Lighthouse audit that tells the user to use video formats rather than animated GIFs, which are wasteful. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/offscreen-images.js | description":{
+"message":"Consider lazy-loading offscreen and hidden images after all critical resources have finished loading to lower time to interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should defer loading offscreen images. Offscreen images are images located outside of the visible browser viewport. As they are unseen by the user and slow down page load, they should be loaded later, closer to when the user is going to see them. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/offscreen-images.js | title":{
+"message":"Defer offscreen images",
+"description":"Imperative title of a Lighthouse audit that tells the user to defer loading offscreen images. Offscreen images are images located outside of the visible browser viewport. As they are unseen by the user and slow down page load, they should be loaded later, closer to when the user is going to see them. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | description":{
+"message":"Resources are blocking the first paint of your page. Consider delivering critical JS/CSS inline and deferring all non-critical JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should reduce or remove network resources that block the initial render of the page. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/render-blocking-resources.js | title":{
+"message":"Eliminate render-blocking resources",
+"description":"Imperative title of a Lighthouse audit that tells the user to reduce or remove network resources that block the initial render of the page. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | description":{
+"message":"Large network payloads cost users real money and are highly correlated with long load times. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the size of the network resources required by the page. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | displayValue":{
+"message":"Total size was {totalBytes, number, bytes} KB",
+"description":"Used to summarize the total byte size of the page and all its network requests. The `{totalBytes}` placeholder will be replaced with the total byte sizes, shown in kilobytes (e.g. 142 KB)"},
+
+"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | failureTitle":{
+"message":"Avoid enormous network payloads",
+"description":"Title of a diagnostic audit that provides detail on large network resources required during page load. 'Payloads' is roughly equivalent to 'resources'. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
+
+"lighthouse-core/audits/byte-efficiency/total-byte-weight.js | title":{
+"message":"Avoids enormous network payloads",
+"description":"Title of a diagnostic audit that provides detail on large network resources required during page load. 'Payloads' is roughly equivalent to 'resources'. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
+
+"lighthouse-core/audits/byte-efficiency/unminified-css.js | description":{
+"message":"Minifying CSS files can reduce network payload sizes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/minify-css).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should minify (remove whitespace) the page's CSS code. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/unminified-css.js | title":{
+"message":"Minify CSS",
+"description":"Imperative title of a Lighthouse audit that tells the user to minify (remove whitespace) the page's CSS code. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | description":{
+"message":"Minifying JavaScript files can reduce payload sizes and script parse time. [Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should minify the page’s JS code to reduce file size. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/unminified-javascript.js | title":{
+"message":"Minify JavaScript",
+"description":"Imperative title of a Lighthouse audit that tells the user to minify the page’s JS code to reduce file size. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | description":{
+"message":"Remove unused rules from stylesheets to reduce unnecessary bytes consumed by network activity. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should defer loading any content in CSS that isn’t needed at page load. This is displayed after a user expands the section to see more. No word length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/unused-css-rules.js | title":{
+"message":"Defer unused CSS",
+"description":"Imperative title of a Lighthouse audit that tells the user to remove content from their CSS that isn’t needed immediately and instead load that content at a later time. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/unused-javascript.js | description":{
+"message":"Remove unused JavaScript to reduce bytes consumed by network activity.",
+"description":"Description of a Lighthouse audit that tells the user *why* they should remove JavaScript that is never needed/evaluated by the browser. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/unused-javascript.js | title":{
+"message":"Remove unused JavaScript",
+"description":"Imperative title of a Lighthouse audit that tells the user to remove JavaScript that is never evaluated during page load. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | description":{
+"message":"A long cache lifetime can speed up repeat visits to your page. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/cache-policy).",
+"description":"Description of a Lighthouse audit that tells the user *why* they need to adopt a long cache lifetime policy. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | displayValue":{
+"message":"{itemCount, plural,\n =1 {1 resource found}\n other {# resources found}\n }",
+"description":"[ICU Syntax] Label for the audit identifying network resources with inefficient cache values. Clicking this will expand the audit to show the resources."},
+
+"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | failureTitle":{
+"message":"Serve static assets with an efficient cache policy",
+"description":"Title of a diagnostic audit that provides details on the any page resources that could have been served with more efficient cache policies. Cache refers to browser disk cache, which keeps old versions of network resources around for future use. This imperative title is shown to users when there is a significant amount of assets served with poor cache policies."},
+
+"lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js | title":{
+"message":"Uses efficient cache policy on static assets",
+"description":"Title of a diagnostic audit that provides detail on the cache policy applies to the page's static assets. Cache refers to browser disk cache, which keeps old versions of network resources around for future use. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | description":{
+"message":"Optimized images load faster and consume less cellular data. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).",
+"description":"Description of a Lighthouse audit that tells the user *why* they need to efficiently encode images. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/uses-optimized-images.js | title":{
+"message":"Efficiently encode images",
+"description":"Imperative title of a Lighthouse audit that tells the user to encode images with optimization (better compression). This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | description":{
+"message":"Serve images that are appropriately-sized to save cellular data and improve load time. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images).",
+"description":"Description of a Lighthouse audit that tells the user *why* they need to serve appropriately sized images. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/uses-responsive-images.js | title":{
+"message":"Properly size images",
+"description":"Imperative title of a Lighthouse audit that tells the user to resize images to match the display dimensions. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | description":{
+"message":"Text-based resources should be served with compression (gzip, deflate or brotli) to minimize total network bytes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression).",
+"description":"Description of a Lighthouse audit that tells the user *why* their text-based resources should be served with compression (like gzip). This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/uses-text-compression.js | title":{
+"message":"Enable text compression",
+"description":"Imperative title of a Lighthouse audit that tells the user to enable text compression (like gzip) in order to enhance the performance of a page. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | description":{
+"message":"Image formats like JPEG 2000, JPEG XR, and WebP often provide better compression than PNG or JPEG, which means faster downloads and less data consumption. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should use newer and more efficient image formats. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/byte-efficiency/uses-webp-images.js | title":{
+"message":"Serve images in next-gen formats",
+"description":"Imperative title of a Lighthouse audit that tells the user to serve images in newer and more efficient image formats in order to enhance the performance of a page. A non-modern image format was designed 20+ years ago. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/critical-request-chains.js | description":{
+"message":"The Critical Request Chains below show you what resources are loaded with a high priority. Consider reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the depth of critical network requests to enhance initial load of a page . This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/critical-request-chains.js | displayValue":{
+"message":"{itemCount, plural,\n =1 {1 chain found}\n other {# chains found}\n }",
+"description":"[ICU Syntax] Label for an audit identifying the number of sequences of dependent network requests used to load the page."},
+
+"lighthouse-core/audits/critical-request-chains.js | title":{
+"message":"Minimize Critical Requests Depth",
+"description":"Imperative title of a Lighthouse audit that tells the user to reduce the depth of critical network requests to enhance initial load of a page. Critical request chains are series of dependent network requests that are important for page rendering. For example, here's a 4-request-deep chain: The biglogo.jpg image is required, but is requested via the styles.css style code, which is requested by the initialize.js javascript, which is requested by the page's HTML. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | columnElement":{
+"message":"Element",
+"description":"Table column header for the DOM element. Each DOM element is described with its HTML representation."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | columnStatistic":{
+"message":"Statistic",
+"description":"Table column header for the type of statistic. These statistics describe how big the DOM is (count of DOM nodes, children, depth)."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | columnValue":{
+"message":"Value",
+"description":"Table column header for the observed value of the DOM statistic."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | description":{
+"message":"Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer [style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM nodes and greatest DOM depth. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | displayValue":{
+"message":"{itemCount, plural,\n =1 {1 node}\n other {# nodes}\n }",
+"description":"[ICU Syntax] Label for an audit identifying the number of DOM nodes found in the page."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | failureTitle":{
+"message":"Avoid an excessive DOM size",
+"description":"Title of a diagnostic audit that provides detail on the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM nodes and greatest DOM depth. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMDepth":{
+"message":"Maximum DOM Depth",
+"description":"Label for the numeric value of the maximum depth in the page's DOM tree."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMNodes":{
+"message":"Total DOM Nodes",
+"description":"Label for the total number of DOM nodes found in the page."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | statisticDOMWidth":{
+"message":"Maximum Child Elements",
+"description":"Label for the numeric value of the maximum number of children any DOM element in the page has. The element described will have the most children in the page."},
+
+"lighthouse-core/audits/dobetterweb/dom-size.js | title":{
+"message":"Avoids an excessive DOM size",
+"description":"Title of a diagnostic audit that provides detail on the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM nodes and greatest DOM depth. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
+
+"lighthouse-core/audits/font-display.js | description":{
+"message":"Leverage the font-display CSS feature to ensure text is user-visible while webfonts are loading. [Learn more](https://developers.google.com/web/updates/2016/02/font-display).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should use the font-display CSS feature. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/font-display.js | failureTitle":{
+"message":"Ensure text remains visible during webfont load",
+"description":"Title of a diagnostic audit that provides detail on the load of the page's webfonts. Often the text is invisible for seconds before the webfont resource is loaded. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
+
+"lighthouse-core/audits/font-display.js | title":{
+"message":"All text remains visible during webfont loads",
+"description":"Title of a diagnostic audit that provides detail on if all the text on a webpage was visible while the page was loading its webfonts. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
+
+"lighthouse-core/audits/load-fast-enough-for-pwa.js | description":{
+"message":"A fast page load over a cellular network ensures a good mobile user experience. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/fast-3g).",
+"description":"Description of a Lighthouse audit that tells the user *why* they need to load fast enough on mobile networks. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/load-fast-enough-for-pwa.js | displayValueText":{
+"message":"Interactive at {timeInMs, number, seconds} s",
+"description":"[ICU Syntax] Label for the audit identifying the time it took for the page to become interactive."},
+
+"lighthouse-core/audits/load-fast-enough-for-pwa.js | displayValueTextWithOverride":{
+"message":"Interactive on simulated mobile network at {timeInMs, number, seconds} s",
+"description":"[ICU Syntax] Label for the audit identifying the time it took for the page to become interactive on a mobile network."},
+
+"lighthouse-core/audits/load-fast-enough-for-pwa.js | failureTitle":{
+"message":"Page load is not fast enough on mobile networks",
+"description":"Imperative title of a Lighthouse audit that tells the user that their page has loaded fast enough to be considered a Progressive Web App. This imperative title is shown to users when the web page has loaded too slowly to be considered a Progressive Web App."},
+
+"lighthouse-core/audits/load-fast-enough-for-pwa.js | title":{
+"message":"Page load is fast enough on mobile networks",
+"description":"Imperative title of a Lighthouse audit that tells the user that their page has loaded fast enough to be considered a Progressive Web App. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/mainthread-work-breakdown.js | columnCategory":{
+"message":"Category",
+"description":"Label for the Main Thread Category column in data tables, rows will have a main thread Category and main thread Task Name."},
+
+"lighthouse-core/audits/mainthread-work-breakdown.js | description":{
+"message":"Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this.",
+"description":"Description of a Lighthouse audit that tells the user *why* they should reduce JS execution times. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/mainthread-work-breakdown.js | failureTitle":{
+"message":"Minimize main-thread work",
+"description":"Title of a diagnostic audit that provides detail on the main thread work the browser did to load the page. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
+
+"lighthouse-core/audits/mainthread-work-breakdown.js | title":{
+"message":"Minimizes main-thread work",
+"description":"Title of a diagnostic audit that provides detail on the main thread work the browser did to load the page. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
+
+"lighthouse-core/audits/metrics/estimated-input-latency.js | description":{
+"message":"Estimated Input Latency is an estimate of how long your app takes to respond to user input, in milliseconds, during the busiest 5s window of page load. If your latency is higher than 50 ms, users may perceive your app as laggy. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).",
+"description":"Description of the Estimated Input Latency metric that estimates the amount of time, in milliseconds, that the app takes to respond to user input. This description is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/metrics/estimated-input-latency.js | title":{
+"message":"Estimated Input Latency",
+"description":"The name of the metric that marks the estimated time between the page receiving input (a user clicking, tapping, or typing) and the page responding. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
+
+"lighthouse-core/audits/metrics/first-contentful-paint.js | description":{
+"message":"First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint).",
+"description":"Description of the First Contentful Paint (FCP) metric, which marks the time at which the first text or image is painted by the browser. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/metrics/first-contentful-paint.js | title":{
+"message":"First Contentful Paint",
+"description":"The name of the metric that marks the time at which the first text or image is painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
+
+"lighthouse-core/audits/metrics/first-cpu-idle.js | description":{
+"message":"First CPU Idle marks the first time at which the page's main thread is quiet enough to handle input. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).",
+"description":"Description of the First CPU Idle metric, which marks the time at which the page has displayed content and the CPU is not busy executing the page's scripts. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/metrics/first-cpu-idle.js | title":{
+"message":"First CPU Idle",
+"description":"The name of the metric that marks when the page has displayed content and the CPU is not busy executing the page's scripts. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
+
+"lighthouse-core/audits/metrics/first-meaningful-paint.js | description":{
+"message":"First Meaningful Paint measures when the primary content of a page is visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).",
+"description":"Description of the First Meaningful Paint (FMP) metric, which marks the time at which a majority of the content has been painted by the browser. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/metrics/first-meaningful-paint.js | title":{
+"message":"First Meaningful Paint",
+"description":"The name of the metric that marks the time at which a majority of the content has been painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
+
+"lighthouse-core/audits/metrics/interactive.js | description":{
+"message":"Time to interactive is the amount of time it takes for the page to become fully interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).",
+"description":"Description of the Time to Interactive (TTI) metric, which evaluates when a page has completed its primary network activity and main thread work. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/metrics/interactive.js | title":{
+"message":"Time to Interactive",
+"description":"The name of the metric that marks the time at which the page is fully loaded and is able to quickly respond to user input (clicks, taps, and keypresses feel responsive). Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
+
+"lighthouse-core/audits/metrics/speed-index.js | description":{
+"message":"Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index).",
+"description":"Description of the Speed Index metric, which summarizes how quickly the page looked visually complete. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/metrics/speed-index.js | title":{
+"message":"Speed Index",
+"description":"The name of the metric that summarizes how quickly the page looked visually complete. The name of this metric is largely abstract and can be loosely translated. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit."},
+
+"lighthouse-core/audits/redirects.js | description":{
+"message":"Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects).",
+"description":"Description of a Lighthouse audit that tells users why they should reduce the number of server-side redirects on their page. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/redirects.js | title":{
+"message":"Avoid multiple page redirects",
+"description":"Imperative title of a Lighthouse audit that tells the user to eliminate the redirects taken through multiple URLs to load the page. This is shown in a list of audits that Lighthouse generates."},
+
+"lighthouse-core/audits/seo/font-size.js | description":{
+"message":"Font sizes less than 12px are too small to be legible and require mobile visitors to “pinch to zoom” in order to read. Strive to have >60% of page text ≥12px. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/font-sizes).",
+"description":"Description of a Lighthouse audit that tells the user *why* they need to use a larger font size. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/seo/font-size.js | displayValue":{
+"message":"{decimalProportion, number, extendedPercent} legible text",
+"description":"[ICU Syntax] Label for the audit identifying font sizes that are too small."},
+
+"lighthouse-core/audits/seo/font-size.js | failureTitle":{
+"message":"Document doesn't use legible font sizes",
+"description":"Imperative title of a Lighthouse audit that tells the user that they should use font sizes that are easily read by the user. This imperative title is shown to users when there is a font that is too small to be read by the user."},
+
+"lighthouse-core/audits/seo/font-size.js | title":{
+"message":"Document uses legible font sizes",
+"description":"Imperative title of a Lighthouse audit that tells the user that they should use font sizes that are easily read by the user. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/time-to-first-byte.js | description":{
+"message":"Time To First Byte identifies the time at which your server sends a response. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/ttfb).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should reduce the amount of time it takes their server to start responding to requests. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/time-to-first-byte.js | displayValue":{
+"message":"Root document took {timeInMs, number, milliseconds} ms",
+"description":"Used to summarize the total Time to First Byte duration for the primary HTML response. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 210 ms)"},
+
+"lighthouse-core/audits/time-to-first-byte.js | failureTitle":{
+"message":"Reduce server response times (TTFB)",
+"description":"Title of a diagnostic audit that provides detail on how long it took from starting a request to when the server started responding. This imperative title is shown to users when there is a significant amount of execution time that could be reduced."},
+
+"lighthouse-core/audits/time-to-first-byte.js | title":{
+"message":"Server response times are low (TTFB)",
+"description":"Title of a diagnostic audit that provides detail on how long it took from starting a request to when the server started responding. This descriptive title is shown to users when the amount is acceptable and no user action is required."},
+
+"lighthouse-core/audits/user-timings.js | columnDuration":{
+"message":"Duration",
+"description":"Label for the Duration column in the User Timing event data table. User Timing API entries are added by the developer of the web page. Durations are only provided for 'Measure' entries. Durations are the number of total number milliseconds from Start Time to their ending point. e.g. '2,020.64 ms'"},
+
+"lighthouse-core/audits/user-timings.js | columnName":{
+"message":"Name",
+"description":"Label for the Name column in the User Timing event data table. User Timing API entries are added by the developer of the web page. An example user timing event name: 'pageload_logoimage_done'"},
+
+"lighthouse-core/audits/user-timings.js | columnStartTime":{
+"message":"Start Time",
+"description":"Label for the Start Time column in the User Timing event data table. User Timing API entries are added by the developer of the web page. Start Times are the number of milliseconds since the page started loading, e.g. '380.26 ms'"},
+
+"lighthouse-core/audits/user-timings.js | columnType":{
+"message":"Type",
+"description":"Label for the Type column in the User Timing event data table. User Timing API entries are added by the developer of the web page. The only possible types are 'Mark' and Measure'."},
+
+"lighthouse-core/audits/user-timings.js | description":{
+"message":"Consider instrumenting your app with the User Timing API to measure your app's real-world performance during key user experiences. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/user-timing).",
+"description":"Description of a Lighthouse audit that tells the user they may want to use the User Timing API to help measure the performance of aspects of their page load and interaction. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/user-timings.js | displayValue":{
+"message":"{itemCount, plural,\n =1 {1 user timing}\n other {# user timings}\n }",
+"description":"[ICU Syntax] Label for an audit identifying the number of User Timing timestamps present in the page."},
+
+"lighthouse-core/audits/user-timings.js | title":{
+"message":"User Timing marks and measures",
+"description":"Descriptive title of a diagnostic audit that provides details on any timestamps generated by the page. User Timing refers to the 'User Timing API', which enables a website to record specific times as 'marks', or spans of time as 'measures'."},
+
+"lighthouse-core/audits/uses-rel-preconnect.js | crossoriginWarning":{
+"message":"A preconnect <link> was found for \"{securityOrigin}\" but was not used by the browser. Check that you are using the `crossorigin` attribute properly.",
+"description":"A warning message that is shown when the user tried to follow the advice of the audit, but it's not working as expected. Forgetting to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links."},
+
+"lighthouse-core/audits/uses-rel-preconnect.js | description":{
+"message":"Consider adding preconnect or dns-prefetch resource hints to establish early connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect).",
+"description":"Description of a Lighthouse audit that tells the user how to connect early to third-party domains that will be used to load page resources. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/uses-rel-preconnect.js | title":{
+"message":"Preconnect to required origins",
+"description":"Imperative title of a Lighthouse audit that tells the user to connect early to internet domains that will be used to load page resources. Origin is the correct term, however 'domain name' could be used if neccsesary. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/audits/uses-rel-preload.js | crossoriginWarning":{
+"message":"A preload <link> was found for \"{preloadURL}\" but was not used by the browser. Check that you are using the `crossorigin` attribute properly.",
+"description":"A warning message that is shown when the user tried to follow the advice of the audit, but it's not working as expected. Forgetting to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preload links."},
+
+"lighthouse-core/audits/uses-rel-preload.js | description":{
+"message":"Consider using <link rel=preload> to prioritize fetching resources that are currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).",
+"description":"Description of a Lighthouse audit that tells the user *why* they should preload important network requests. The associated network requests are started halfway through pageload (or later) but should be started at the beginning. This is displayed after a user expands the section to see more. No character length limits. '<link rel=preload>' is the html code the user would include in their page and shouldn't be translated. 'Learn More' becomes link text to additional documentation."},
+
+"lighthouse-core/audits/uses-rel-preload.js | title":{
+"message":"Preload key requests",
+"description":"Imperative title of a Lighthouse audit that tells the user to use <link rel=preload> to initiate important network requests earlier during page load. This is displayed in a list of audit titles that Lighthouse generates."},
+
+"lighthouse-core/config/default-config.js | a11yAriaGroupDescription":{
+"message":"These are opportunities to improve the usage of ARIA in your application which may enhance the experience for users of assistive technology, like a screen reader.",
+"description":"Description of the ARIA validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight if whether all the aria- HTML attributes have been used properly."},
+
+"lighthouse-core/config/default-config.js | a11yAriaGroupTitle":{
+"message":"ARIA Attributes Follow Best Practices",
+"description":"Title of the ARIA validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight if whether all the aria- HTML attributes have been used properly."},
+
+"lighthouse-core/config/default-config.js | a11yColorContrastGroupDescription":{
+"message":"These are opportunities to improve the legibility of your content.",
+"description":"Description of the color contrast section within the Accessibility category. Within this section are audits with descriptive titles that highlight the color and vision aspects of the page's accessibility that are passing or failing."},
+
+"lighthouse-core/config/default-config.js | a11yColorContrastGroupTitle":{
+"message":"Color Contrast Is Satisfactory",
+"description":"Title of the color contrast section within the Accessibility category. Within this section are audits with descriptive titles that highlight the color and vision aspects of the page's accessibility that are passing or failing."},
+
+"lighthouse-core/config/default-config.js | a11yCorrectAttributesGroupDescription":{
+"message":"These are opportunities to improve the configuration of your HTML elements.",
+"description":"Description of the HTML attribute validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the HTML attribute values on the page are used correctly."},
+
+"lighthouse-core/config/default-config.js | a11yCorrectAttributesGroupTitle":{
+"message":"Elements Use Attributes Correctly",
+"description":"Title of the HTML attribute validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the HTML attribute values on the page are used correctly. 'Elements' refers to HTML elements."},
+
+"lighthouse-core/config/default-config.js | a11yDescribeContentsGroupDescription":{
+"message":"These are opportunities to make your content easier to understand for a user of assistive technology, like a screen reader.",
+"description":"Description of the screen reader annotation section within the Accessibility category. Within this section are audits with descriptive titles that highlight the screen reader readability aspects of the page's accessibility that are passing or failing."},
+
+"lighthouse-core/config/default-config.js | a11yDescribeContentsGroupTitle":{
+"message":"Elements Describe Contents Well",
+"description":"Title of the screen reader annotation section within the Accessibility category. Within this section are audits with descriptive titles that highlight the screen reader readability aspects of the page's accessibility that are passing or failing. 'Elements' refers to HTML elements."},
+
+"lighthouse-core/config/default-config.js | a11yElementNamesGroupDescription":{
+"message":"These are opportunities to improve the semantics of the controls in your application. This may enhance the experience for users of assistive technology, like a screen reader.",
+"description":"Description of the HTML element naming section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the non-textual HTML elements on the page have names discernible by a screen reader."},
+
+"lighthouse-core/config/default-config.js | a11yElementNamesGroupTitle":{
+"message":"Elements Have Discernible Names",
+"description":"Title of the HTML element naming section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the non-textual HTML elements on the page have names discernible by a screen reader."},
+
+"lighthouse-core/config/default-config.js | a11yLanguageGroupDescription":{
+"message":"These are opportunities to improve the interpretation of your content by users in different locales.",
+"description":"Description of the language section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the language has been annotated in the correct HTML attributes on the page."},
+
+"lighthouse-core/config/default-config.js | a11yLanguageGroupTitle":{
+"message":"Page Specifies Valid Language",
+"description":"Title of the language section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the language has been annotated in the correct HTML attributes on the page."},
+
+"lighthouse-core/config/default-config.js | a11yMetaGroupDescription":{
+"message":"These are opportunities to improve the user experience of your site.",
+"description":"Description of the meta tag section within the Accessibility category. Within this section are audits with descriptive titles that highlight if meta tags on the page have been used properly and if any important ones are missing."},
+
+"lighthouse-core/config/default-config.js | a11yMetaGroupTitle":{
+"message":"Meta Tags Used Properly",
+"description":"Title of the meta tag section within the Accessibility category. Within this section are audits with descriptive titles that highlight if meta tags on the page have been used properly and if any important ones are missing."},
+
+"lighthouse-core/config/default-config.js | a11yWellStructuredGroupDescription":{
+"message":"These are opportunities to make sure your HTML is appropriately structured.",
+"description":"Description of the HTML validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight structural HTML aspects of the page's accessibility that are passing or failing."},
+
+"lighthouse-core/config/default-config.js | a11yWellStructuredGroupTitle":{
+"message":"Elements Are Well Structured",
+"description":"Title of the HTML validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight structural HTML aspects of the page's accessibility that are passing or failing (i.e. that list items are contained within list parents, etc). 'Elements' refers to HTML elements."},
+
+"lighthouse-core/config/default-config.js | diagnosticsGroupDescription":{
+"message":"More information about the performance of your application.",
+"description":"Description of the diagnostics section of the Performance category. Within this section are audits with non-imperative titles that provide more detail on the page's page load performance characteristics. Whereas the 'Opportunities' suggest an action along with expected time savings, diagnostics do not. Within this section, the user may read the details and deduce additional actions they could take."},
+
+"lighthouse-core/config/default-config.js | diagnosticsGroupTitle":{
+"message":"Diagnostics",
+"description":"Title of the diagnostics section of the Performance category. Within this section are audits with non-imperative titles that provide more detail on the page's page load performance characteristics. Whereas the 'Opportunities' suggest an action along with expected time savings, diagnostics do not. Within this section, the user may read the details and deduce additional actions they could take."},
+
+"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupDescription":{
+"message":"The most critical aspect of performance is how quickly pixels are rendered onscreen. Key metrics: First Contentful Paint, First Meaningful Paint",
+"description":"Description of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage."},
+
+"lighthouse-core/config/default-config.js | firstPaintImprovementsGroupTitle":{
+"message":"First Paint Improvements",
+"description":"Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage."},
+
+"lighthouse-core/config/default-config.js | loadOpportunitiesGroupDescription":{
+"message":"These optimizations can speed up your page load.",
+"description":"Description of the opportunity section of the Performance category. 'Optimizations' could also be 'recommendations' or 'suggestions'. Within this section are audits with imperative titles that suggest actions the user can take to improve the loading performance of their web page."},
+
+"lighthouse-core/config/default-config.js | loadOpportunitiesGroupTitle":{
+"message":"Opportunities",
+"description":"Title of the opportunity section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the loading performance of their web page. 'Suggestion'/'Optimization'/'Recommendation' are reasonable synonyms for 'opportunity' in this case."},
+
+"lighthouse-core/config/default-config.js | metricGroupTitle":{
+"message":"Metrics",
+"description":"Title of the speed metrics section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds."},
+
+"lighthouse-core/config/default-config.js | overallImprovementsGroupDescription":{
+"message":"Enhance the overall loading experience, so the page is responsive and ready to use as soon as possible. Key metrics: Time to Interactive, Speed Index",
+"description":"Description of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the overall loading performance of their web page."},
+
+"lighthouse-core/config/default-config.js | overallImprovementsGroupTitle":{
+"message":"Overall Improvements",
+"description":"Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the overall loading performance of their web page."},
+
+"lighthouse-core/config/default-config.js | performanceCategoryTitle":{
+"message":"Performance",
+"description":"Title of the Performance category of audits. Equivalent to 'Web performance', this term is inclusive of all web page speed and loading optimization topics. Also used as a label of a score gauge; try to limit to 20 characters."},
+
+"lighthouse-core/config/default-config.js | pwaFastReliableGroupTitle":{
+"message":"Fast and reliable",
+"description":"Title of the Fast and Reliable section of the web app category. Within this section are audits that check if the web site loaded quickly and can reliably load even if the internet connection is very slow or goes offline."},
+
+"lighthouse-core/config/default-config.js | pwaInstallableGroupTitle":{
+"message":"Installable",
+"description":"Title of the Installable section of the web app category. Within this section are audits that check if Chrome supports installing the web site as an app on their device."},
+
+"lighthouse-core/config/default-config.js | pwaOptimizedGroupTitle":{
+"message":"PWA Optimized",
+"description":"Title of the \"PWA Optimized\" section of the web app category. Within this section are audits that check if the developer has taken advantage of features to make their web page more enjoyable and engaging for the user."},
+
+"lighthouse-core/lib/i18n/i18n.js | columnCacheTTL":{
+"message":"Cache TTL",
+"description":"Label for the TTL column in data tables, entries will be the time to live value of the cache header on a web resource"},
+
+"lighthouse-core/lib/i18n/i18n.js | columnSize":{
+"message":"Size (KB)",
+"description":"Label for the size column in data tables, entries will be the size of a web resource in kilobytes"},
+
+"lighthouse-core/lib/i18n/i18n.js | columnTimeSpent":{
+"message":"Time Spent",
+"description":"Label for the time spent column in data tables, entries will be the number of milliseconds spent during a particular activity"},
+
+"lighthouse-core/lib/i18n/i18n.js | columnURL":{
+"message":"URL",
+"description":"Label for the URL column in data tables, entries will be the URL of a web resource"},
+
+"lighthouse-core/lib/i18n/i18n.js | columnWastedBytes":{
+"message":"Potential Savings (KB)",
+"description":"Label for the wasted bytes column in data tables, entries will be the number of kilobytes the user could reduce their page by if they implemented the suggestions"},
+
+"lighthouse-core/lib/i18n/i18n.js | columnWastedMs":{
+"message":"Potential Savings (ms)",
+"description":"Label for the wasted bytes column in data tables, entries will be the number of milliseconds the user could reduce page load by if they implemented the suggestions"},
+
+"lighthouse-core/lib/i18n/i18n.js | displayValueByteSavings":{
+"message":"Potential savings of {wastedBytes, number, bytes} KB",
+"description":"Label shown per-audit to show how many bytes smaller the page could be if the user implemented the suggestions. The `{wastedBytes}` placeholder will be replaced with the number of bytes, shown in kilobytes (e.g. 148 KB)"},
+
+"lighthouse-core/lib/i18n/i18n.js | displayValueMsSavings":{
+"message":"Potential savings of {wastedMs, number, milliseconds} ms",
+"description":"Label shown per-audit to show how many milliseconds faster the page load could be if the user implemented the suggestions. The `{wastedMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 140 ms)"},
+
+"lighthouse-core/lib/i18n/i18n.js | ms":{
+"message":"{timeInMs, number, milliseconds} ms",
+"description":"Used to show the duration in milliseconds that something lasted. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 63 ms)"},
+
+"lighthouse-core/lib/i18n/i18n.js | seconds":{
+"message":"{timeInMs, number, seconds} s",
+"description":"Used to show the duration in seconds that something lasted. The {timeInMs} placeholder will be replaced with the time duration, shown in seconds (e.g. 5.2 s)"},
+
+"lighthouse-core/lib/lh-error.js | badTraceRecording":{
+"message":"Something went wrong with recording the trace over your page load. Please run Lighthouse again. ({errorCode})",
+"description":"Error message explaining that the network trace was not able to be recorded for the Lighthouse run."},
+
+"lighthouse-core/lib/lh-error.js | didntCollectScreenshots":{
+"message":"Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse. ({errorCode})",
+"description":"Error message explaining that the Lighthouse run was not able to collect screenshots through Chrome."},
+
+"lighthouse-core/lib/lh-error.js | dnsFailure":{
+"message":"DNS servers could not resolve the provided domain.",
+"description":"Error message explaining that the requested page could not be resolved by the DNS server."},
+
+"lighthouse-core/lib/lh-error.js | internalChromeError":{
+"message":"An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.",
+"description":"Error message explaining that Chrome has encountered an error during the Lighthouse run, and that Chrome should be restarted."},
+
+"lighthouse-core/lib/lh-error.js | pageLoadFailed":{
+"message":"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.",
+"description":"Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability."},
+
+"lighthouse-core/lib/lh-error.js | pageLoadFailedHung":{
+"message":"Lighthouse was unable to reliably load the URL you requested because the page stopped responding.",
+"description":"Error message explaining that Lighthouse couldn't complete because the page has stopped responding to its instructions."},
+
+"lighthouse-core/lib/lh-error.js | pageLoadFailedInsecure":{
+"message":"The URL you have provided does not have valid security credentials. {securityMessages}",
+"description":"Error message explaining that the credentials included in the Lighthouse run were invalid, so the URL cannot be accessed. securityMessages will be replaced with one or more strings from the browser explaining what was insecure about the page load."},
+
+"lighthouse-core/lib/lh-error.js | pageLoadFailedWithDetails":{
+"message":"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Details: {errorDetails})",
+"description":"Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability."},
+
+"lighthouse-core/lib/lh-error.js | pageLoadFailedWithStatusCode":{
+"message":"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Status code: {statusCode})",
+"description":"Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability."},
+
+"lighthouse-core/lib/lh-error.js | pageLoadTookTooLong":{
+"message":"Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse. ({errorCode})",
+"description":"Error message explaining that the page loaded too slowly to perform a Lighthouse run."},
+
+"lighthouse-core/lib/lh-error.js | protocolTimeout":{
+"message":"Waiting for DevTools protocol response has exceeded the allotted time. (Method: {protocolMethod})",
+"description":"Error message explaining that the Chrome Devtools protocol has exceeded the maximum timeout allowed."},
+
+"lighthouse-core/lib/lh-error.js | requestContentTimeout":{
+"message":"Fetching resource content has exceeded the allotted time",
+"description":"Error message explaining that fetching the resources of the webpage has taken longer than the maximum time."},
+
+"lighthouse-core/lib/lh-error.js | urlInvalid":{
+"message":"The URL you have provided appears to be invalid.",
+"description":"Error message explaining that the provided URL Lighthouse points to is not valid, and cannot be loaded."},
+
+"lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip":{
+"message":"Show audits",
+"description":"The tooltip text on an expandable chevron icon. Clicking the icon expands a section to reveal a list of audit results that was hidden by default."},
+
+"lighthouse-core/report/html/renderer/util.js | crcInitialNavigation":{
+"message":"Initial Navigation",
+"description":"String of text shown in a graphical representation of the flow of network requests for the web page. This label represents the initial network request that fetches an HTML page. This navigation may be redirected (eg. Initial navigation to http://example.com redirects to https://www.example.com)."},
+
+"lighthouse-core/report/html/renderer/util.js | crcLongestDurationLabel":{
+"message":"Maximum critical path latency:",
+"description":"Label of value shown in the summary of critical request chains. Refers to the total amount of time (milliseconds) of the longest critical path chain/sequence of network requests. Example value: 2310 ms"},
+
+"lighthouse-core/report/html/renderer/util.js | errorLabel":{
+"message":"Error!",
+"description":"A label, shown next to an audit title or metric title, indicating that there was an error computing it. The user can hover on the label to reveal a tooltip with the extended error message. Translation should be short (< 20 characters)."},
+
+"lighthouse-core/report/html/renderer/util.js | errorMissingAuditInfo":{
+"message":"Report error: no audit information",
+"description":"An error string displayed next to a particular audit when it has errored, but not provided any specific error message."},
+
+"lighthouse-core/report/html/renderer/util.js | labDataTitle":{
+"message":"Lab Data",
+"description":"Title of the lab data section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. \"Lab\" is an abbreviated form of \"laboratory\", and refers to the fact that the data is from a controlled test of a website, not measurements from real users visiting that site."},
+
+"lighthouse-core/report/html/renderer/util.js | lsPerformanceCategoryDescription":{
+"message":"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.",
+"description":"Explanation shown to users below performance results to inform them that the test was done with a 4G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation."},
+
+"lighthouse-core/report/html/renderer/util.js | manualAuditsGroupTitle":{
+"message":"Additional items to manually check",
+"description":"Section heading shown above a list of audits that were not computed by Lighthouse. They serve as a list of suggestions for the user to go and manually check. For example, Lighthouse can't automate testing cross-browser compatibility, so that is listed within this section, so the user is reminded to test it themselves. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list."},
+
+"lighthouse-core/report/html/renderer/util.js | notApplicableAuditsGroupTitle":{
+"message":"Not applicable",
+"description":"Section heading shown above a list of audits that do not apply to the page. For example, if an audit is 'Are images optimized?', but the page has no images on it, the audit will be marked as not applicable. This is neither passing or failing. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list."},
+
+"lighthouse-core/report/html/renderer/util.js | opportunityResourceColumnLabel":{
+"message":"Opportunity",
+"description":"Column heading label for the listing of opportunity audits. Each audit title represents an opportunity. There are only 2 columns, so no strict character limit."},
+
+"lighthouse-core/report/html/renderer/util.js | opportunitySavingsColumnLabel":{
+"message":"Estimated Savings",
+"description":"Column heading label for the estimated page load savings of opportunity audits. Estimated Savings is the total amount of time (in seconds) that Lighthouse computed could be reduced from the total page load time, if the suggested action is taken. There are only 2 columns, so no strict character limit."},
+
+"lighthouse-core/report/html/renderer/util.js | passedAuditsGroupTitle":{
+"message":"Passed audits",
+"description":"Section heading shown above a list of audits that are passing. 'Passed' here refers to a passing grade. This section is collapsed by default, as the user should be focusing on the failed audits instead. Users can click this heading to reveal the list."},
+
+"lighthouse-core/report/html/renderer/util.js | scorescaleLabel":{
+"message":"Score scale:",
+"description":"Label preceding a pictorial explanation of the scoring scale: 0-50 is red (bad), 50-90 is orange (ok), 90-100 is green (good). These colors are used throughout the report to provide context for how good/bad a particular result is."},
+
+"lighthouse-core/report/html/renderer/util.js | toplevelWarningsMessage":{
+"message":"There were issues affecting this run of Lighthouse:",
+"description":"Label shown preceding any important warnings that may have invalidated the entire report. For example, if the user has Chrome extensions installed, they may add enough performance overhead that Lighthouse's performance metrics are unreliable. If shown, this will be displayed at the top of the report UI."},
+
+"lighthouse-core/report/html/renderer/util.js | varianceDisclaimer":{
+"message":"Values are estimated and may vary.",
+"description":"Disclaimer shown to users below the metric values (First Contentful Paint, Time to Interactive, etc) to warn them that the numbers they see will likely change slightly the next time they run Lighthouse."},
+
+"lighthouse-core/report/html/renderer/util.js | warningAuditsGroupTitle":{
+"message":"Passed audits but with warnings",
+"description":"Section heading shown above a list of passed audits that contain warnings. Audits under this section do not negatively impact the score, but Lighthouse has generated some potentially actionable suggestions that should be reviewed. This section is expanded by default and displays after the failing audits."},
+
+"lighthouse-core/report/html/renderer/util.js | warningHeader":{
+"message":"Warnings: ",
+"description":"This label is shown above a bulleted list of warnings. It is shown directly below an audit that produced warnings. Warnings describe situations the user should be aware of, as Lighthouse was unable to complete all the work required on this audit. For example, The 'Unable to decode image (biglogo.jpg)' warning may show up below an image encoding audit."}};
+
+
+
+},{}],59:[function(require,module,exports){
+(function(__filename,__dirname){
+
+
+
+
+
+'use strict';
+
+const path=require('path');
+const isDeepEqual=require('lodash.isequal');
+const log=require('lighthouse-logger');
+const MessageFormat=require('intl-messageformat').default;
+const MessageParser=require('intl-messageformat-parser');
+const lookupClosestLocale=require('lookup-closest-locale');
+const LOCALES=require('./locales.js');
+
+const LH_ROOT=path.join(__dirname,'../../../');
+const MESSAGE_INSTANCE_ID_REGEX=/(.* \| .*) # (\d+)$/;
+
+const MESSAGE_INSTANCE_ID_QUICK_REGEX=/ # \d+$/;
+
+(()=>{
+
+
+try{
+
+const IntlPolyfill=require('intl');
+
+if(!IntlPolyfill.NumberFormat)return;
+
+Intl.NumberFormat=IntlPolyfill.NumberFormat;
+Intl.DateTimeFormat=IntlPolyfill.DateTimeFormat;
+}catch(_){
+log.warn('i18n','Failed to install `intl` polyfill');
+}
+})();
+
+
+const UIStrings={
+
+ms:'{timeInMs, number, milliseconds}\xa0ms',
+
+seconds:'{timeInMs, number, seconds}\xa0s',
+
+displayValueByteSavings:'Potential savings of {wastedBytes, number, bytes}\xa0KB',
+
+displayValueMsSavings:'Potential savings of {wastedMs, number, milliseconds}\xa0ms',
+
+columnURL:'URL',
+
+columnSize:'Size (KB)',
+
+columnCacheTTL:'Cache TTL',
+
+columnWastedBytes:'Potential Savings (KB)',
+
+columnWastedMs:'Potential Savings (ms)',
+
+columnTimeSpent:'Time Spent'};
+
+
+const formats={
+number:{
+bytes:{
+maximumFractionDigits:0},
+
+milliseconds:{
+maximumFractionDigits:0},
+
+seconds:{
+
+minimumFractionDigits:1,
+maximumFractionDigits:1},
+
+extendedPercent:{
+
+maximumFractionDigits:2,
+style:'percent'}}};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function lookupLocale(locale){
+
+const canonicalLocale=Intl.getCanonicalLocales(locale)[0];
+
+const closestLocale=lookupClosestLocale(canonicalLocale,LOCALES);
+return closestLocale||'en';
+}
+
+
+
+
+
+function _preprocessMessageValues(icuMessage,values){
+if(!values)return;
+
+const clonedValues=JSON.parse(JSON.stringify(values));
+const parsed=MessageParser.parse(icuMessage);
+
+parsed.elements.
+filter(el=>el.type==='argumentElement').
+forEach(el=>{
+if(el.id&&el.id in values===false){
+throw new Error('ICU Message contains a value reference that wasn\'t provided');
+}
+});
+
+
+parsed.elements.
+filter(el=>el.format&&el.format.style==='milliseconds').
+
+forEach(el=>clonedValues[el.id]=Math.round(clonedValues[el.id]/10)*10);
+
+
+parsed.elements.
+filter(el=>el.format&&el.format.style==='seconds'&&el.id==='timeInMs').
+
+forEach(el=>clonedValues[el.id]=Math.round(clonedValues[el.id]/100)/10);
+
+
+parsed.elements.
+filter(el=>el.format&&el.format.style==='bytes').
+
+forEach(el=>clonedValues[el.id]=clonedValues[el.id]/1024);
+
+return clonedValues;
+}
+
+
+
+
+
+
+
+
+
+const _icuMessageInstanceMap=new Map();
+
+
+
+
+
+
+
+
+
+function _formatIcuMessage(locale,icuMessageId,icuMessage,values){
+const localeMessages=LOCALES[locale];
+const localeMessage=localeMessages[icuMessageId]&&localeMessages[icuMessageId].message;
+
+
+const messageForMessageFormat=localeMessage||icuMessage;
+
+const localeForMessageFormat=locale==='en-XA'?'de-DE':locale;
+
+const valuesForMessageFormat=_preprocessMessageValues(icuMessage,values);
+
+const formatter=new MessageFormat(messageForMessageFormat,localeForMessageFormat,formats);
+const formattedString=formatter.format(valuesForMessageFormat);
+
+return{formattedString,icuMessage:messageForMessageFormat};
+}
+
+
+function _formatPathAsString(pathInLHR){
+let pathAsString='';
+for(const property of pathInLHR){
+if(/^[a-z]+$/i.test(property)){
+if(pathAsString.length)pathAsString+='.';
+pathAsString+=property;
+}else{
+if(/]|"|'|\s/.test(property))throw new Error(`Cannot handle "${property}" in i18n`);
+pathAsString+=`[${property}]`;
+}
+}
+
+return pathAsString;
+}
+
+
+
+
+
+function getRendererFormattedStrings(locale){
+const icuMessageIds=Object.keys(LOCALES[locale]).filter(f=>f.includes('core/report/html/'));
+
+const strings={};
+for(const icuMessageId of icuMessageIds){
+const[filename,varName]=icuMessageId.split(' | ');
+if(!filename.endsWith('util.js'))throw new Error(`Unexpected message: ${icuMessageId}`);
+strings[varName]=LOCALES[locale][icuMessageId].message;
+}
+
+return strings;
+}
+
+
+
+
+
+function createMessageInstanceIdFn(filename,fileStrings){
+
+const mergedStrings={...UIStrings,...fileStrings};
+
+
+const getMessageInstanceIdFn=(icuMessage,values)=>{
+const keyname=Object.keys(mergedStrings).find(key=>mergedStrings[key]===icuMessage);
+if(!keyname)throw new Error(`Could not locate: ${icuMessage}`);
+
+const filenameToLookup=keyname in fileStrings?filename:__filename;
+const unixStyleFilename=path.relative(LH_ROOT,filenameToLookup).replace(/\\/g,'/');
+const icuMessageId=`${unixStyleFilename} | ${keyname}`;
+const icuMessageInstances=_icuMessageInstanceMap.get(icuMessageId)||[];
+
+let indexOfInstance=icuMessageInstances.findIndex(inst=>isDeepEqual(inst.values,values));
+if(indexOfInstance===-1){
+icuMessageInstances.push({icuMessageId,icuMessage,values});
+indexOfInstance=icuMessageInstances.length-1;
+}
+
+_icuMessageInstanceMap.set(icuMessageId,icuMessageInstances);
+
+return`${icuMessageId} # ${indexOfInstance}`;
+};
+
+return getMessageInstanceIdFn;
+}
+
+
+
+
+
+
+function isIcuMessage(icuMessageIdOrRawString){
+return MESSAGE_INSTANCE_ID_QUICK_REGEX.test(icuMessageIdOrRawString)&&
+MESSAGE_INSTANCE_ID_REGEX.test(icuMessageIdOrRawString);
+}
+
+
+
+
+
+
+function getFormatted(icuMessageIdOrRawString,locale){
+if(isIcuMessage(icuMessageIdOrRawString)){
+return _resolveIcuMessageInstanceId(icuMessageIdOrRawString,locale).formattedString;
+}
+
+return icuMessageIdOrRawString;
+}
+
+
+
+
+
+
+function _resolveIcuMessageInstanceId(icuMessageInstanceId,locale){
+const matches=icuMessageInstanceId.match(MESSAGE_INSTANCE_ID_REGEX);
+if(!matches)throw new Error(`${icuMessageInstanceId} is not a valid message instance ID`);
+
+const[_,icuMessageId,icuMessageInstanceIndex]=matches;
+const icuMessageInstances=_icuMessageInstanceMap.get(icuMessageId)||[];
+const icuMessageInstance=icuMessageInstances[Number(icuMessageInstanceIndex)];
+
+const{formattedString}=_formatIcuMessage(locale,icuMessageId,
+icuMessageInstance.icuMessage,icuMessageInstance.values);
+
+return{icuMessageInstance,formattedString};
+}
+
+
+
+
+
+
+
+
+
+function replaceIcuMessageInstanceIds(inputObject,locale){
+
+
+
+
+
+function replaceInObject(subObject,icuMessagePaths,pathInLHR=[]){
+if(typeof subObject!=='object'||!subObject)return;
+
+for(const[property,value]of Object.entries(subObject)){
+const currentPathInLHR=pathInLHR.concat([property]);
+
+
+if(typeof value==='string'&&isIcuMessage(value)){
+const{icuMessageInstance,formattedString}=_resolveIcuMessageInstanceId(value,locale);
+const messageInstancesInLHR=icuMessagePaths[icuMessageInstance.icuMessageId]||[];
+const currentPathAsString=_formatPathAsString(currentPathInLHR);
+
+messageInstancesInLHR.push(
+icuMessageInstance.values?
+{values:icuMessageInstance.values,path:currentPathAsString}:
+currentPathAsString);
+
+
+subObject[property]=formattedString;
+icuMessagePaths[icuMessageInstance.icuMessageId]=messageInstancesInLHR;
+}else{
+replaceInObject(value,icuMessagePaths,currentPathInLHR);
+}
+}
+}
+
+
+const icuMessagePaths={};
+replaceInObject(inputObject,icuMessagePaths);
+return icuMessagePaths;
+}
+
+module.exports={
+_formatPathAsString,
+UIStrings,
+lookupLocale,
+getRendererFormattedStrings,
+createMessageInstanceIdFn,
+getFormatted,
+replaceIcuMessageInstanceIds,
+isIcuMessage};
+
+
+}).call(this,"/lighthouse-core/lib/i18n/i18n.js","/lighthouse-core/lib/i18n");
+},{"./locales.js":60,"intl":87,"intl-messageformat":102,"intl-messageformat-parser":100,"lighthouse-logger":113,"lodash.isequal":114,"lookup-closest-locale":115,"path":128}],60:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+const locales={
+'en-US':require('./en-US.json'),
+'en':require('./en-US.json'),
+
+
+'en-AU':require('./locales/en-GB.json'),
+'en-GB':require('./locales/en-GB.json'),
+'en-IE':require('./locales/en-GB.json'),
+'en-SG':require('./locales/en-GB.json'),
+'en-ZA':require('./locales/en-GB.json'),
+'en-IN':require('./locales/en-GB.json'),
+
+
+'ar-XB':require('./locales/ar-XB.json'),
+'ar':require('./locales/ar.json'),
+'bg':require('./locales/bg.json'),
+'bs':require('./locales/hr.json'),
+'ca':require('./locales/ca.json'),
+'cs':require('./locales/cs.json'),
+'da':require('./locales/da.json'),
+'de':require('./locales/de.json'),
+'el':require('./locales/el.json'),
+'en-XA':require('./locales/en-XA.json'),
+'es':require('./locales/es.json'),
+'fi':require('./locales/fi.json'),
+'fil':require('./locales/fil.json'),
+'fr':require('./locales/fr.json'),
+'he':require('./locales/he.json'),
+'hi':require('./locales/hi.json'),
+'hr':require('./locales/hr.json'),
+'hu':require('./locales/hu.json'),
+'gsw':require('./locales/de.json'),
+'id':require('./locales/id.json'),
+'in':require('./locales/id.json'),
+'it':require('./locales/it.json'),
+'iw':require('./locales/he.json'),
+'ja':require('./locales/ja.json'),
+'ko':require('./locales/ko.json'),
+'ln':require('./locales/fr.json'),
+'lt':require('./locales/lt.json'),
+'lv':require('./locales/lv.json'),
+'mo':require('./locales/ro.json'),
+'nl':require('./locales/nl.json'),
+'nb':require('./locales/no.json'),
+'no':require('./locales/no.json'),
+'pl':require('./locales/pl.json'),
+'pt':require('./locales/pt.json'),
+'pt-PT':require('./locales/pt-PT.json'),
+'ro':require('./locales/ro.json'),
+'ru':require('./locales/ru.json'),
+'sk':require('./locales/sk.json'),
+'sl':require('./locales/sl.json'),
+'sr':require('./locales/sr.json'),
+'sr-Latn':require('./locales/sr-Latn.json'),
+'sv':require('./locales/sv.json'),
+'ta':require('./locales/ta.json'),
+'te':require('./locales/te.json'),
+'th':require('./locales/th.json'),
+'tl':require('./locales/fil.json'),
+'tr':require('./locales/tr.json'),
+'uk':require('./locales/uk.json'),
+'vi':require('./locales/vi.json'),
+'zh':require('./locales/zh.json'),
+'zh-HK':require('./locales/zh-HK.json'),
+'zh-TW':require('./locales/zh-TW.json')};
+
+
+module.exports=locales;
+
+},{"./en-US.json":58,"./locales/ar-XB.json":87,"./locales/ar.json":87,"./locales/bg.json":87,"./locales/ca.json":87,"./locales/cs.json":87,"./locales/da.json":87,"./locales/de.json":87,"./locales/el.json":87,"./locales/en-GB.json":87,"./locales/en-XA.json":87,"./locales/es.json":87,"./locales/fi.json":87,"./locales/fil.json":87,"./locales/fr.json":87,"./locales/he.json":87,"./locales/hi.json":87,"./locales/hr.json":87,"./locales/hu.json":87,"./locales/id.json":87,"./locales/it.json":87,"./locales/ja.json":87,"./locales/ko.json":87,"./locales/lt.json":87,"./locales/lv.json":87,"./locales/nl.json":87,"./locales/no.json":87,"./locales/pl.json":87,"./locales/pt-PT.json":87,"./locales/pt.json":87,"./locales/ro.json":87,"./locales/ru.json":87,"./locales/sk.json":87,"./locales/sl.json":87,"./locales/sr-Latn.json":87,"./locales/sr.json":87,"./locales/sv.json":87,"./locales/ta.json":87,"./locales/te.json":87,"./locales/th.json":87,"./locales/tr.json":87,"./locales/uk.json":87,"./locales/vi.json":87,"./locales/zh-HK.json":87,"./locales/zh-TW.json":87,"./locales/zh.json":87}],61:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const URL=require('./url-shim.js');
+
+
+
+
+
+function doExist(manifest){
+if(!manifest||!manifest.icons){
+return false;
+}
+if(manifest.icons.value.length===0){
+return false;
+}
+return true;
+}
+
+
+
+
+
+
+function pngSizedAtLeast(sizeRequirement,manifest){
+
+
+const iconValues=manifest.icons.value;
+
+const flattenedSizes=[];
+iconValues.
+filter(icon=>{
+const typeHint=icon.value.type.value;
+if(typeHint){
+
+return typeHint==='image/png';
+}
+
+const src=icon.value.src.value;
+return src&&new URL(src).pathname.endsWith('.png');
+}).
+forEach(icon=>{
+
+if(icon.value.sizes.value){
+flattenedSizes.push(...icon.value.sizes.value);
+}
+});
+
+return flattenedSizes.
+
+filter(size=>/\d+x\d+/.test(size)).
+filter(size=>{
+
+const sizeStrs=size.split(/x/i);
+
+const sizeNums=[parseFloat(sizeStrs[0]),parseFloat(sizeStrs[1])];
+
+const areIconsBigEnough=sizeNums[0]>=sizeRequirement&&sizeNums[1]>=sizeRequirement;
+
+const areIconsSquare=sizeNums[0]===sizeNums[1];
+return areIconsBigEnough&&areIconsSquare;
+});
+}
+
+module.exports={
+doExist,
+pngSizedAtLeast};
+
+
+},{"./url-shim.js":"url"}],62:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+function convertNodeTimingsToTrace(nodeTimings){
+
+const traceEvents=[];
+const baseTs=1e9;
+const baseEvent={pid:1,tid:1,cat:'devtools.timeline'};
+const frame='A00001';
+
+const toMicroseconds=ms=>baseTs+ms*1000;
+
+traceEvents.push(createFakeTracingStartedEvent());
+traceEvents.push({...createFakeTracingStartedEvent(),name:'TracingStartedInBrowser'});
+
+
+let requestId=1;
+let lastEventEndTime=0;
+for(const[node,timing]of nodeTimings.entries()){
+lastEventEndTime=Math.max(lastEventEndTime,timing.endTime);
+if(node.type==='cpu'){
+
+const cpuNode=node;
+traceEvents.push(...createFakeTaskEvents(cpuNode,timing));
+}else{
+const networkNode=node;
+
+if(/^data/.test(networkNode.record.url))continue;
+traceEvents.push(...createFakeNetworkEvents(networkNode.record,timing));
+}
+}
+
+
+traceEvents.push(
+...createFakeTaskEvents(
+
+{childEvents:[],event:{}},
+{
+startTime:lastEventEndTime+1000,
+endTime:lastEventEndTime+1001}));
+
+
+
+
+return{traceEvents};
+
+
+
+
+function createFakeTracingStartedEvent(){
+const argsData={
+frameTreeNodeId:1,
+sessionId:'1.1',
+page:frame,
+persistentIds:true,
+frames:[{frame,url:'about:blank',name:'',processId:1}]};
+
+
+return{
+...baseEvent,
+ts:baseTs-1e5,
+ph:'I',
+s:'t',
+cat:'disabled-by-default-devtools.timeline',
+name:'TracingStartedInPage',
+args:{data:argsData},
+dur:0};
+
+}
+
+
+
+
+
+
+function createFakeTaskEvents(cpuNode,timing){
+const argsData={
+url:'',
+frame,
+lineNumber:0,
+columnNumber:0};
+
+
+const eventTs=toMicroseconds(timing.startTime);
+
+
+const events=[
+{
+...baseEvent,
+ph:'X',
+name:'Task',
+ts:eventTs,
+dur:(timing.endTime-timing.startTime)*1000,
+args:{data:argsData}}];
+
+
+
+const nestedBaseTs=cpuNode.event.ts||0;
+const multiplier=(timing.endTime-timing.startTime)*1000/cpuNode.event.dur;
+
+const netReqEvents=new Set(['ResourceSendRequest','ResourceFinish',
+'ResourceReceiveResponse','ResourceReceivedData']);
+for(const event of cpuNode.childEvents){
+if(netReqEvents.has(event.name))continue;
+const ts=eventTs+(event.ts-nestedBaseTs)*multiplier;
+const newEvent={...event,...{pid:baseEvent.pid,tid:baseEvent.tid},ts};
+if(event.dur)newEvent.dur=event.dur*multiplier;
+events.push(newEvent);
+}
+
+return events;
+}
+
+
+
+
+
+
+function createFakeNetworkEvents(record,timing){
+requestId++;
+
+
+
+let{startTime,endTime}=timing;
+if(startTime===endTime)endTime+=0.3;
+
+const requestData={requestId:requestId.toString(),frame};
+
+const baseRequestEvent={...baseEvent,ph:'I',s:'t',dur:0};
+
+const sendRequestData={
+...requestData,
+requestMethod:record.requestMethod,
+url:record.url,
+priority:record.priority};
+
+
+const receiveResponseData={
+...requestData,
+statusCode:record.statusCode,
+mimeType:record.mimeType,
+encodedDataLength:record.transferSize,
+fromCache:record.fromDiskCache,
+fromServiceWorker:record.fetchedViaServiceWorker};
+
+
+const resourceFinishData={
+...requestData,
+decodedBodyLength:record.resourceSize,
+didFail:!!record.failed,
+finishTime:endTime};
+
+
+
+const events=[
+{
+...baseRequestEvent,
+name:'ResourceSendRequest',
+ts:toMicroseconds(startTime),
+args:{data:sendRequestData}},
+
+{
+...baseRequestEvent,
+name:'ResourceFinish',
+ts:toMicroseconds(endTime),
+args:{data:resourceFinishData}}];
+
+
+
+if(!record.failed){
+events.push({
+...baseRequestEvent,
+name:'ResourceReceiveResponse',
+ts:toMicroseconds((startTime+endTime)/2),
+args:{data:receiveResponseData}});
+
+}
+
+return events;
+}
+}
+
+module.exports={
+simulationNamesToIgnore:[
+'unlabeled',
+
+'optimisticFirstCPUIdle',
+'optimisticFlexFirstCPUIdle',
+'pessimisticFirstCPUIdle',
+'optimisticSpeedIndex',
+'optimisticFlexSpeedIndex',
+'pessimisticSpeedIndex',
+'optimisticEstimatedInputLatency',
+'optimisticFlexEstimatedInputLatency',
+'pessimisticEstimatedInputLatency'],
+
+convertNodeTimingsToTrace};
+
+
+},{}],63:[function(require,module,exports){
+(function(__filename){
+
+
+
+
+
+'use strict';
+
+const i18n=require('./i18n/i18n.js');
+
+
+const UIStrings={
+
+didntCollectScreenshots:`Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse. ({errorCode})`,
+
+badTraceRecording:'Something went wrong with recording the trace over your page load. Please run Lighthouse again. ({errorCode})',
+
+pageLoadTookTooLong:'Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse. ({errorCode})',
+
+pageLoadFailed:'Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.',
+
+pageLoadFailedWithStatusCode:'Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Status code: {statusCode})',
+
+pageLoadFailedWithDetails:'Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Details: {errorDetails})',
+
+pageLoadFailedInsecure:'The URL you have provided does not have valid security credentials. {securityMessages}',
+
+internalChromeError:'An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.',
+
+requestContentTimeout:'Fetching resource content has exceeded the allotted time',
+
+urlInvalid:'The URL you have provided appears to be invalid.',
+
+protocolTimeout:'Waiting for DevTools protocol response has exceeded the allotted time. (Method: {protocolMethod})',
+
+dnsFailure:'DNS servers could not resolve the provided domain.',
+
+pageLoadFailedHung:'Lighthouse was unable to reliably load the URL you requested because the page stopped responding.'};
+
+
+const str_=i18n.createMessageInstanceIdFn(__filename,UIStrings);
+
+
+
+
+
+
+
+
+
+
+class LighthouseError extends Error{
+
+
+
+
+constructor(errorDefinition,properties){
+super(errorDefinition.code);
+this.name='LHError';
+this.code=errorDefinition.code;
+
+this.friendlyMessage=str_(errorDefinition.message,{errorCode:this.code,...properties});
+this.lhrRuntimeError=!!errorDefinition.lhrRuntimeError;
+if(properties)Object.assign(this,properties);
+
+Error.captureStackTrace(this,LighthouseError);
+}
+
+
+
+
+
+
+static fromProtocolMessage(method,protocolError){
+
+const protocolErrors=Object.values(LighthouseError.errors).filter(e=>e.pattern);
+
+const matchedErrorDefinition=protocolErrors.find(e=>e.pattern.test(protocolError.message));
+if(matchedErrorDefinition){
+return new LighthouseError(matchedErrorDefinition,{
+protocolMethod:method,
+protocolError:protocolError.message});
+
+}
+
+
+let errMsg=`(${method}): ${protocolError.message}`;
+if(protocolError.data)errMsg+=` (${protocolError.data})`;
+const error=new Error(`Protocol error ${errMsg}`);
+return Object.assign(error,{protocolMethod:method,protocolError:protocolError.message});
+}}
+
+
+const ERRORS={
+
+NO_SPEEDLINE_FRAMES:{
+code:'NO_SPEEDLINE_FRAMES',
+message:UIStrings.didntCollectScreenshots,
+lhrRuntimeError:true},
+
+SPEEDINDEX_OF_ZERO:{
+code:'SPEEDINDEX_OF_ZERO',
+message:UIStrings.didntCollectScreenshots,
+lhrRuntimeError:true},
+
+NO_SCREENSHOTS:{
+code:'NO_SCREENSHOTS',
+message:UIStrings.didntCollectScreenshots,
+lhrRuntimeError:true},
+
+INVALID_SPEEDLINE:{
+code:'INVALID_SPEEDLINE',
+message:UIStrings.didntCollectScreenshots,
+lhrRuntimeError:true},
+
+
+
+NO_TRACING_STARTED:{
+code:'NO_TRACING_STARTED',
+message:UIStrings.badTraceRecording,
+lhrRuntimeError:true},
+
+NO_NAVSTART:{
+code:'NO_NAVSTART',
+message:UIStrings.badTraceRecording,
+lhrRuntimeError:true},
+
+NO_FCP:{
+code:'NO_FCP',
+message:UIStrings.badTraceRecording,
+lhrRuntimeError:true},
+
+NO_DCL:{
+code:'NO_DCL',
+message:UIStrings.badTraceRecording,
+lhrRuntimeError:true},
+
+NO_FMP:{
+code:'NO_FMP',
+message:UIStrings.badTraceRecording},
+
+
+
+FMP_TOO_LATE_FOR_FCPUI:{code:'FMP_TOO_LATE_FOR_FCPUI',message:UIStrings.pageLoadTookTooLong},
+NO_FCPUI_IDLE_PERIOD:{code:'NO_FCPUI_IDLE_PERIOD',message:UIStrings.pageLoadTookTooLong},
+NO_TTI_CPU_IDLE_PERIOD:{code:'NO_TTI_CPU_IDLE_PERIOD',message:UIStrings.pageLoadTookTooLong},
+NO_TTI_NETWORK_IDLE_PERIOD:{
+code:'NO_TTI_NETWORK_IDLE_PERIOD',
+message:UIStrings.pageLoadTookTooLong},
+
+
+
+NO_DOCUMENT_REQUEST:{
+code:'NO_DOCUMENT_REQUEST',
+message:UIStrings.pageLoadFailed,
+lhrRuntimeError:true},
+
+
+
+
+FAILED_DOCUMENT_REQUEST:{
+code:'FAILED_DOCUMENT_REQUEST',
+message:UIStrings.pageLoadFailedWithDetails,
+lhrRuntimeError:true},
+
+
+
+
+ERRORED_DOCUMENT_REQUEST:{
+code:'ERRORED_DOCUMENT_REQUEST',
+message:UIStrings.pageLoadFailedWithStatusCode,
+lhrRuntimeError:true},
+
+
+
+
+INSECURE_DOCUMENT_REQUEST:{
+code:'INSECURE_DOCUMENT_REQUEST',
+message:UIStrings.pageLoadFailedInsecure,
+lhrRuntimeError:true},
+
+
+PAGE_HUNG:{
+code:'PAGE_HUNG',
+message:UIStrings.pageLoadFailedHung,
+lhrRuntimeError:true},
+
+
+
+TRACING_ALREADY_STARTED:{
+code:'TRACING_ALREADY_STARTED',
+message:UIStrings.internalChromeError,
+pattern:/Tracing.*started/,
+lhrRuntimeError:true},
+
+PARSING_PROBLEM:{
+code:'PARSING_PROBLEM',
+message:UIStrings.internalChromeError,
+pattern:/Parsing problem/,
+lhrRuntimeError:true},
+
+READ_FAILED:{
+code:'READ_FAILED',
+message:UIStrings.internalChromeError,
+pattern:/Read failed/,
+lhrRuntimeError:true},
+
+
+
+INVALID_URL:{
+code:'INVALID_URL',
+message:UIStrings.urlInvalid},
+
+
+
+
+
+PROTOCOL_TIMEOUT:{
+code:'PROTOCOL_TIMEOUT',
+message:UIStrings.protocolTimeout,
+lhrRuntimeError:true},
+
+
+
+DNS_FAILURE:{
+code:'DNS_FAILURE',
+message:UIStrings.dnsFailure,
+lhrRuntimeError:true}};
+
+
+
+
+
+
+LighthouseError.errors=ERRORS;
+LighthouseError.NO_ERROR='NO_ERROR';
+LighthouseError.UNKNOWN_ERROR='UNKNOWN_ERROR';
+module.exports=LighthouseError;
+module.exports.UIStrings=UIStrings;
+
+}).call(this,"/lighthouse-core/lib/lh-error.js");
+},{"./i18n/i18n.js":59}],64:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const URL=require('./url-shim');
+const cssParsers=require('cssstyle/lib/parsers');
+
+const ALLOWED_DISPLAY_VALUES=[
+'fullscreen',
+'standalone',
+'minimal-ui',
+'browser'];
+
+
+
+
+
+const DEFAULT_DISPLAY_MODE='browser';
+
+const ALLOWED_ORIENTATION_VALUES=[
+'any',
+'natural',
+'landscape',
+'portrait',
+'portrait-primary',
+'portrait-secondary',
+'landscape-primary',
+'landscape-secondary'];
+
+
+
+
+
+
+function isValidColor(color){
+return cssParsers.valueType(color)===cssParsers.TYPES.COLOR;
+}
+
+
+
+
+
+function parseString(raw,trim){
+let value;
+let warning;
+
+if(typeof raw==='string'){
+value=trim?raw.trim():raw;
+}else{
+if(raw!==undefined){
+warning='ERROR: expected a string.';
+}
+value=undefined;
+}
+
+return{
+raw,
+value,
+warning};
+
+}
+
+
+
+
+function parseColor(raw){
+const color=parseString(raw);
+
+
+if(color.value===undefined){
+return color;
+}
+
+
+if(!isValidColor(color.raw)){
+color.value=undefined;
+color.warning='ERROR: color parsing failed.';
+}
+
+return color;
+}
+
+
+
+
+function parseName(jsonInput){
+return parseString(jsonInput.name,true);
+}
+
+
+
+
+function parseShortName(jsonInput){
+return parseString(jsonInput.short_name,true);
+}
+
+
+
+
+
+
+
+function checkSameOrigin(url1,url2){
+const parsed1=new URL(url1);
+const parsed2=new URL(url2);
+
+return parsed1.origin===parsed2.origin;
+}
+
+
+
+
+
+
+
+
+function parseStartUrl(jsonInput,manifestUrl,documentUrl){
+const raw=jsonInput.start_url;
+
+
+if(raw===''){
+return{
+raw,
+value:documentUrl,
+warning:'ERROR: start_url string empty'};
+
+}
+if(raw===undefined){
+return{
+raw,
+value:documentUrl};
+
+}
+if(typeof raw!=='string'){
+return{
+raw,
+value:documentUrl,
+warning:'ERROR: expected a string.'};
+
+}
+
+
+let startUrl;
+try{
+startUrl=new URL(raw,manifestUrl).href;
+}catch(e){
+
+return{
+raw,
+value:documentUrl,
+warning:'ERROR: invalid start_url relative to ${manifestUrl}'};
+
+}
+
+
+if(!checkSameOrigin(startUrl,documentUrl)){
+return{
+raw,
+value:documentUrl,
+warning:'ERROR: start_url must be same-origin as document'};
+
+}
+
+return{
+raw,
+value:startUrl};
+
+}
+
+
+
+
+function parseDisplay(jsonInput){
+const parsedString=parseString(jsonInput.display,true);
+const stringValue=parsedString.value;
+
+if(!stringValue){
+return{
+raw:jsonInput,
+value:DEFAULT_DISPLAY_MODE,
+warning:parsedString.warning};
+
+}
+
+const displayValue=stringValue.toLowerCase();
+if(!ALLOWED_DISPLAY_VALUES.includes(displayValue)){
+return{
+raw:jsonInput,
+value:DEFAULT_DISPLAY_MODE,
+warning:'ERROR: \'display\' has invalid value '+displayValue+
+`. will fall back to ${DEFAULT_DISPLAY_MODE}.`};
+
+}
+
+return{
+raw:jsonInput,
+value:displayValue,
+warning:undefined};
+
+}
+
+
+
+
+function parseOrientation(jsonInput){
+const orientation=parseString(jsonInput.orientation,true);
+
+if(orientation.value&&
+!ALLOWED_ORIENTATION_VALUES.includes(orientation.value.toLowerCase())){
+orientation.value=undefined;
+orientation.warning='ERROR: \'orientation\' has an invalid value, will be ignored.';
+}
+
+return orientation;
+}
+
+
+
+
+
+function parseIcon(raw,manifestUrl){
+
+const src=parseString(raw.src,true);
+
+if(src.value===''){
+src.value=undefined;
+}
+if(src.value){
+
+src.value=new URL(src.value,manifestUrl).href;
+}
+
+const type=parseString(raw.type,true);
+
+const density={
+raw:raw.density,
+value:1,
+
+warning:undefined};
+
+if(density.raw!==undefined){
+density.value=parseFloat(density.raw);
+if(isNaN(density.value)||!isFinite(density.value)||density.value<=0){
+density.value=1;
+density.warning='ERROR: icon density cannot be NaN, +∞, or less than or equal to +0.';
+}
+}
+
+let sizes;
+const parsedSizes=parseString(raw.sizes);
+if(parsedSizes.value!==undefined){
+
+const set=new Set();
+parsedSizes.value.trim().split(/\s+/).forEach(size=>set.add(size.toLowerCase()));
+sizes={
+raw:raw.sizes,
+value:set.size>0?Array.from(set):undefined,
+warning:undefined};
+
+}else{
+sizes={...parsedSizes,value:undefined};
+}
+
+return{
+raw,
+value:{
+src,
+type,
+density,
+sizes},
+
+warning:undefined};
+
+}
+
+
+
+
+
+function parseIcons(jsonInput,manifestUrl){
+const raw=jsonInput.icons;
+
+if(raw===undefined){
+return{
+raw,
+
+value:[],
+warning:undefined};
+
+}
+
+if(!Array.isArray(raw)){
+return{
+raw,
+
+value:[],
+warning:'ERROR: \'icons\' expected to be an array but is not.'};
+
+}
+
+
+
+const value=raw.
+
+filter(icon=>icon.src!==undefined).
+
+map(icon=>parseIcon(icon,manifestUrl)).
+
+filter(parsedIcon=>parsedIcon.value.src.value!==undefined);
+
+return{
+raw,
+value,
+warning:undefined};
+
+}
+
+
+
+
+function parseApplication(raw){
+const platform=parseString(raw.platform,true);
+const id=parseString(raw.id,true);
+
+
+const appUrl=parseString(raw.url,true);
+if(appUrl.value){
+try{
+
+appUrl.value=new URL(appUrl.value).href;
+}catch(e){
+appUrl.value=undefined;
+appUrl.warning='ERROR: invalid application URL ${raw.url}';
+}
+}
+
+return{
+raw,
+value:{
+platform,
+id,
+url:appUrl},
+
+warning:undefined};
+
+}
+
+
+
+
+function parseRelatedApplications(jsonInput){
+const raw=jsonInput.related_applications;
+
+if(raw===undefined){
+return{
+raw,
+value:undefined,
+warning:undefined};
+
+}
+
+if(!Array.isArray(raw)){
+return{
+raw,
+value:undefined,
+warning:'ERROR: \'related_applications\' expected to be an array but is not.'};
+
+}
+
+
+
+const value=raw.
+filter(application=>!!application.platform).
+map(parseApplication).
+filter(parsedApp=>!!parsedApp.value.id.value||!!parsedApp.value.url.value);
+
+return{
+raw,
+value,
+warning:undefined};
+
+}
+
+
+
+
+function parsePreferRelatedApplications(jsonInput){
+const raw=jsonInput.prefer_related_applications;
+let value;
+let warning;
+
+if(typeof raw==='boolean'){
+value=raw;
+}else{
+if(raw!==undefined){
+warning='ERROR: \'prefer_related_applications\' expected to be a boolean.';
+}
+value=undefined;
+}
+
+return{
+raw,
+value,
+warning};
+
+}
+
+
+
+
+function parseThemeColor(jsonInput){
+return parseColor(jsonInput.theme_color);
+}
+
+
+
+
+function parseBackgroundColor(jsonInput){
+return parseColor(jsonInput.background_color);
+}
+
+
+
+
+
+
+
+function parse(string,manifestUrl,documentUrl){
+if(manifestUrl===undefined||documentUrl===undefined){
+throw new Error('Manifest and document URLs required for manifest parsing.');
+}
+
+let jsonInput;
+
+try{
+jsonInput=JSON.parse(string);
+}catch(e){
+return{
+raw:string,
+value:undefined,
+warning:'ERROR: file isn\'t valid JSON: '+e};
+
+}
+
+
+const manifest={
+name:parseName(jsonInput),
+short_name:parseShortName(jsonInput),
+start_url:parseStartUrl(jsonInput,manifestUrl,documentUrl),
+display:parseDisplay(jsonInput),
+orientation:parseOrientation(jsonInput),
+icons:parseIcons(jsonInput,manifestUrl),
+related_applications:parseRelatedApplications(jsonInput),
+prefer_related_applications:parsePreferRelatedApplications(jsonInput),
+theme_color:parseThemeColor(jsonInput),
+background_color:parseBackgroundColor(jsonInput)};
+
+
+
+return{
+raw:string,
+value:manifest,
+warning:undefined};
+
+}
+
+module.exports=parse;
+
+},{"./url-shim":"url","cssstyle/lib/parsers":90}],65:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+const PUNCTUATOR_REGEX=/(return|{|\(|\[|\.\.\.|;|,|<|>|<=|>=|==|!=|===|!==|\+|-|\*|%|\*\*|\+\+|--|<<|>>|>>>|&|\||\^|!|~|&&|\|\||\?|:|=|\+=|-=|\*=|%=|\*\*=|<<=|>>=|>>>=|&=|\|=|\^=|=>|\/|\/=|\})$/;
+const WHITESPACE_REGEX=/( |\n|\t)+$/;
+
+
+
+
+
+
+
+
+
+function hasPunctuatorBefore(content,startPosition){
+for(let i=startPosition;i>0;i--){
+
+const sliceStart=Math.max(0,i-6);
+const precedingCharacters=content.slice(sliceStart,i);
+
+if(WHITESPACE_REGEX.test(precedingCharacters))continue;
+
+return PUNCTUATOR_REGEX.test(precedingCharacters);
+}
+
+
+
+return true;
+}
+
+
+
+
+
+
+
+function computeTokenLength(content,features){
+let totalTokenLength=0;
+let isInSinglelineComment=false;
+let isInMultilineComment=false;
+let isInLicenseComment=false;
+let isInString=false;
+let isInRegex=false;
+let isInRegexCharacterClass=false;
+let stringOpenChar=null;
+
+for(let i=0;i<content.length;i++){
+const twoChars=content.substr(i,2);
+const char=twoChars.charAt(0);
+
+const isWhitespace=char===' '||char==='\n'||char==='\t';
+const isAStringOpenChar=char===`'`||char==='"'||char==='`';
+
+if(isInSinglelineComment){
+if(char==='\n'){
+
+isInSinglelineComment=false;
+}
+}else if(isInMultilineComment){
+
+if(isInLicenseComment)totalTokenLength++;
+
+if(twoChars==='*/'){
+
+if(isInLicenseComment)totalTokenLength++;
+
+isInMultilineComment=false;
+
+i++;
+}
+}else if(isInString){
+
+totalTokenLength++;
+
+if(char==='\\'){
+
+totalTokenLength++;
+i++;
+}else if(char===stringOpenChar){
+
+isInString=false;
+
+}
+}else if(isInRegex){
+
+totalTokenLength++;
+
+if(char==='\\'){
+
+totalTokenLength++;
+i++;
+}else if(char==='['){
+
+isInRegexCharacterClass=true;
+}else if(char===']'&&isInRegexCharacterClass){
+
+isInRegexCharacterClass=false;
+}else if(char==='/'&&!isInRegexCharacterClass){
+
+isInRegex=false;
+
+}
+}else{
+
+if(twoChars==='/*'){
+
+isInMultilineComment=true;
+
+isInLicenseComment=content.charAt(i+2)==='!';
+
+if(isInLicenseComment)totalTokenLength+=2;
+
+i++;
+}else if(twoChars==='//'&&features.singlelineComments){
+
+isInSinglelineComment=true;
+isInMultilineComment=false;
+isInLicenseComment=false;
+
+i++;
+}else if(char==='/'&&features.regex&&hasPunctuatorBefore(content,i)){
+
+isInRegex=true;
+
+totalTokenLength++;
+}else if(isAStringOpenChar){
+
+isInString=true;
+
+stringOpenChar=char;
+
+totalTokenLength++;
+}else if(!isWhitespace){
+
+totalTokenLength++;
+}
+}
+}
+
+
+
+if(isInMultilineComment||isInString){
+return content.length;
+}
+
+return totalTokenLength;
+}
+
+
+
+
+function computeJSTokenLength(content){
+return computeTokenLength(content,{singlelineComments:true,regex:true});
+}
+
+
+
+
+function computeCSSTokenLength(content){
+return computeTokenLength(content,{singlelineComments:false,regex:false});
+}
+
+module.exports={computeJSTokenLength,computeCSSTokenLength};
+
+},{}],66:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const NetworkRequest=require('./network-request');
+const EventEmitter=require('events').EventEmitter;
+const log=require('lighthouse-logger');
+
+const IGNORED_NETWORK_SCHEMES=['data','ws'];
+
+
+
+class NetworkRecorder extends EventEmitter{
+
+
+
+constructor(){
+super();
+
+
+this._records=[];
+
+this._recordsById=new Map();
+}
+
+
+
+
+getInflightRecords(){
+return this._records.filter(record=>!NetworkRecorder.isNetworkRecordFinished(record));
+}
+
+getRecords(){
+return Array.from(this._records);
+}
+
+
+
+
+
+on(event,listener){
+return super.on(event,listener);
+}
+
+
+
+
+
+once(event,listener){
+return super.once(event,listener);
+}
+
+isIdle(){
+return!!this._getActiveIdlePeriod(0);
+}
+
+is2Idle(){
+return!!this._getActiveIdlePeriod(2);
+}
+
+
+
+
+_getActiveIdlePeriod(allowedRequests){
+const quietPeriods=NetworkRecorder.findNetworkQuietPeriods(this._records,allowedRequests);
+return quietPeriods.find(period=>!Number.isFinite(period.end));
+}
+
+_emitNetworkStatus(){
+const zeroQuiet=this._getActiveIdlePeriod(0);
+const twoQuiet=this._getActiveIdlePeriod(2);
+
+if(twoQuiet&&zeroQuiet){
+log.verbose('NetworkRecorder','network fully-quiet');
+this.emit('network-2-idle');
+this.emit('networkidle');
+}else if(twoQuiet&&!zeroQuiet){
+log.verbose('NetworkRecorder','network semi-quiet');
+this.emit('network-2-idle');
+this.emit('networkbusy');
+}else{
+log.verbose('NetworkRecorder','network busy');
+this.emit('network-2-busy');
+this.emit('networkbusy');
+}
+}
+
+
+
+
+
+
+
+static _isQUICAndFinished(record){
+const isQUIC=record.responseHeaders&&record.responseHeaders.
+some(header=>header.name.toLowerCase()==='alt-svc'&&/quic/.test(header.value));
+const receivedHeaders=record.timing&&record.timing.receiveHeadersEnd>0;
+return!!(isQUIC&&receivedHeaders&&record.endTime);
+}
+
+
+
+
+
+
+
+static _isFrameRootRequestAndFinished(record){
+const isFrameRootRequest=record.url===record.documentURL;
+const responseReceived=record.responseReceivedTime>0;
+return!!(isFrameRootRequest&&responseReceived&&record.endTime);
+}
+
+
+
+
+
+static isNetworkRecordFinished(record){
+return record.finished||
+NetworkRecorder._isQUICAndFinished(record)||
+NetworkRecorder._isFrameRootRequestAndFinished(record);
+}
+
+
+
+
+
+
+
+
+
+static findNetworkQuietPeriods(networkRecords,allowedConcurrentRequests,endTime=Infinity){
+
+
+let timeBoundaries=[];
+networkRecords.forEach(record=>{
+const scheme=record.parsedURL&&record.parsedURL.scheme;
+if(IGNORED_NETWORK_SCHEMES.includes(scheme)){
+return;
+}
+
+
+timeBoundaries.push({time:record.startTime*1000,isStart:true});
+if(NetworkRecorder.isNetworkRecordFinished(record)){
+timeBoundaries.push({time:record.endTime*1000,isStart:false});
+}
+});
+
+timeBoundaries=timeBoundaries.
+filter(boundary=>boundary.time<=endTime).
+sort((a,b)=>a.time-b.time);
+
+let numInflightRequests=0;
+let quietPeriodStart=0;
+
+const quietPeriods=[];
+timeBoundaries.forEach(boundary=>{
+if(boundary.isStart){
+
+if(numInflightRequests===allowedConcurrentRequests){
+quietPeriods.push({start:quietPeriodStart,end:boundary.time});
+}
+numInflightRequests++;
+}else{
+numInflightRequests--;
+
+if(numInflightRequests===allowedConcurrentRequests){
+quietPeriodStart=boundary.time;
+}
+}
+});
+
+
+if(numInflightRequests<=allowedConcurrentRequests){
+quietPeriods.push({start:quietPeriodStart,end:endTime});
+}
+
+return quietPeriods.filter(period=>period.start!==period.end);
+}
+
+
+
+
+
+
+
+onRequestStarted(request){
+this._records.push(request);
+this._recordsById.set(request.requestId,request);
+
+this.emit('requeststarted',request);
+this._emitNetworkStatus();
+}
+
+
+
+
+
+
+
+onRequestFinished(request){
+this.emit('requestloaded',request);
+this._emitNetworkStatus();
+}
+
+
+
+
+
+
+
+onRequestWillBeSent(data){
+const originalRequest=this._findRealRequest(data.requestId);
+
+if(!originalRequest){
+const request=new NetworkRequest();
+request.onRequestWillBeSent(data);
+this.onRequestStarted(request);
+return;
+}
+
+
+if(!data.redirectResponse){
+return;
+}
+
+
+
+const modifiedData={
+...data,
+
+
+initiator:originalRequest.initiator,
+requestId:`${originalRequest.requestId}:redirect`};
+
+const redirectedRequest=new NetworkRequest();
+
+redirectedRequest.onRequestWillBeSent(modifiedData);
+originalRequest.onRedirectResponse(data);
+
+originalRequest.redirectDestination=redirectedRequest;
+redirectedRequest.redirectSource=originalRequest;
+
+
+this.onRequestStarted(redirectedRequest);
+this.onRequestFinished(originalRequest);
+}
+
+
+
+
+onRequestServedFromCache(data){
+const request=this._findRealRequest(data.requestId);
+if(!request)return;
+request.onRequestServedFromCache();
+}
+
+
+
+
+onResponseReceived(data){
+const request=this._findRealRequest(data.requestId);
+if(!request)return;
+request.onResponseReceived(data);
+}
+
+
+
+
+onDataReceived(data){
+const request=this._findRealRequest(data.requestId);
+if(!request)return;
+request.onDataReceived(data);
+}
+
+
+
+
+onLoadingFinished(data){
+const request=this._findRealRequest(data.requestId);
+if(!request)return;
+request.onLoadingFinished(data);
+this.onRequestFinished(request);
+}
+
+
+
+
+onLoadingFailed(data){
+const request=this._findRealRequest(data.requestId);
+if(!request)return;
+request.onLoadingFailed(data);
+this.onRequestFinished(request);
+}
+
+
+
+
+onResourceChangedPriority(data){
+const request=this._findRealRequest(data.requestId);
+if(!request)return;
+request.onResourceChangedPriority(data);
+}
+
+
+
+
+
+dispatch(event){
+if(!event.method.startsWith('Network.')){
+return;
+}
+
+switch(event.method){
+case'Network.requestWillBeSent':return this.onRequestWillBeSent(event.params);
+case'Network.requestServedFromCache':return this.onRequestServedFromCache(event.params);
+case'Network.responseReceived':return this.onResponseReceived(event.params);
+case'Network.dataReceived':return this.onDataReceived(event.params);
+case'Network.loadingFinished':return this.onLoadingFinished(event.params);
+case'Network.loadingFailed':return this.onLoadingFailed(event.params);
+case'Network.resourceChangedPriority':return this.onResourceChangedPriority(event.params);
+default:return;}
+
+}
+
+
+
+
+
+
+
+
+
+
+_findRealRequest(requestId){
+let request=this._recordsById.get(requestId);
+if(!request||!request.isValid)return undefined;
+
+while(request.redirectDestination){
+request=request.redirectDestination;
+}
+
+return request;
+}
+
+
+
+
+
+
+static recordsFromLogs(devtoolsLog){
+const networkRecorder=new NetworkRecorder();
+
+devtoolsLog.forEach(message=>networkRecorder.dispatch(message));
+
+
+const records=networkRecorder.getRecords().filter(record=>record.isValid);
+
+
+const recordsByURL=new Map();
+for(const record of records){
+if(recordsByURL.has(record.url))continue;
+recordsByURL.set(record.url,record);
+}
+
+
+for(const record of records){
+const stackFrames=record.initiator.stack&&record.initiator.stack.callFrames||[];
+const initiatorURL=record.initiator.url||stackFrames[0]&&stackFrames[0].url;
+const initiator=recordsByURL.get(initiatorURL)||record.redirectSource;
+if(initiator){
+record.setInitiatorRequest(initiator);
+}
+
+let finalRecord=record;
+while(finalRecord.redirectDestination)finalRecord=finalRecord.redirectDestination;
+if(finalRecord===record||finalRecord.redirects)continue;
+
+const redirects=[];
+for(
+let redirect=finalRecord.redirectSource;
+redirect;
+redirect=redirect.redirectSource)
+{
+redirects.unshift(redirect);
+}
+
+finalRecord.redirects=redirects;
+}
+
+return records;
+}}
+
+
+module.exports=NetworkRecorder;
+
+},{"./network-request":67,"events":93,"lighthouse-logger":113}],67:[function(require,module,exports){
+(function(global){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const URL=require('./url-shim');
+
+const SECURE_SCHEMES=['data','https','wss','blob','chrome','chrome-extension','about'];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const RESOURCE_TYPES={
+XHR:'XHR',
+Fetch:'Fetch',
+EventSource:'EventSource',
+Script:'Script',
+Stylesheet:'Stylesheet',
+Image:'Image',
+Media:'Media',
+Font:'Font',
+Document:'Document',
+TextTrack:'TextTrack',
+WebSocket:'WebSocket',
+Other:'Other',
+Manifest:'Manifest',
+SignedExchange:'SignedExchange',
+Ping:'Ping',
+CSPViolationReport:'CSPViolationReport'};
+
+
+module.exports=class NetworkRequest{
+constructor(){
+this.requestId='';
+
+this.connectionId='0';
+this.connectionReused=false;
+
+this.url='';
+this.protocol='';
+this.isSecure=false;
+this.isValid=false;
+this.parsedURL={scheme:''};
+this.documentURL='';
+
+this.startTime=-1;
+
+this.endTime=-1;
+
+this.responseReceivedTime=-1;
+
+this.transferSize=0;
+this.resourceSize=0;
+this.fromDiskCache=false;
+this.fromMemoryCache=false;
+
+this.finished=false;
+this.requestMethod='';
+this.statusCode=-1;
+
+this.redirectSource=undefined;
+
+this.redirectDestination=undefined;
+
+this.redirects=undefined;
+this.failed=false;
+this.localizedFailDescription='';
+
+this.initiator={type:'other'};
+
+this.timing=undefined;
+
+this.resourceType=undefined;
+this.mimeType='';
+
+this.priority='Low';
+
+this.initiatorRequest=undefined;
+
+this.responseHeaders=[];
+
+this.responseHeadersText='';
+
+this.fetchedViaServiceWorker=false;
+
+this.frameId='';
+this.isLinkPreload=false;
+}
+
+
+
+
+hasErrorStatusCode(){
+return this.statusCode>=400;
+}
+
+
+
+
+setInitiatorRequest(initiator){
+this.initiatorRequest=initiator;
+}
+
+
+
+
+onRequestWillBeSent(data){
+this.requestId=data.requestId;
+let url;
+try{
+
+url=new URL(data.request.url);
+}catch(e){
+
+return;
+}
+this.url=data.request.url;
+this.documentURL=data.documentURL;
+this.parsedURL={
+scheme:url.protocol.split(':')[0],
+
+host:url.hostname,
+securityOrigin:url.origin};
+
+this.isSecure=SECURE_SCHEMES.includes(this.parsedURL.scheme);
+
+this.startTime=data.timestamp;
+
+this.requestMethod=data.request.method;
+
+this.initiator=data.initiator;
+this.resourceType=data.type&&RESOURCE_TYPES[data.type];
+this.priority=data.request.initialPriority;
+
+this.frameId=data.frameId;
+this.isLinkPreload=data.initiator.type==='preload'||!!data.request.isLinkPreload;
+this.isValid=true;
+}
+
+onRequestServedFromCache(){
+this.fromMemoryCache=true;
+}
+
+
+
+
+onResponseReceived(data){
+this._onResponse(data.response,data.timestamp,data.type);
+this.frameId=data.frameId;
+}
+
+
+
+
+onDataReceived(data){
+this.resourceSize+=data.dataLength;
+if(data.encodedDataLength!==-1){
+this.transferSize+=data.encodedDataLength;
+}
+}
+
+
+
+
+onLoadingFinished(data){
+
+if(this.finished)return;
+
+this.finished=true;
+this.endTime=data.timestamp;
+if(data.encodedDataLength>=0){
+this.transferSize=data.encodedDataLength;
+}
+
+this._updateResponseReceivedTimeIfNecessary();
+this._updateTransferSizeForLightRiderIfNecessary();
+}
+
+
+
+
+onLoadingFailed(data){
+
+if(this.finished)return;
+
+this.finished=true;
+this.endTime=data.timestamp;
+
+this.failed=true;
+this.resourceType=data.type&&RESOURCE_TYPES[data.type];
+this.localizedFailDescription=data.errorText;
+
+this._updateResponseReceivedTimeIfNecessary();
+}
+
+
+
+
+onResourceChangedPriority(data){
+this.priority=data.newPriority;
+}
+
+
+
+
+onRedirectResponse(data){
+if(!data.redirectResponse)throw new Error('Missing redirectResponse data');
+this._onResponse(data.redirectResponse,data.timestamp,data.type);
+this.resourceType=undefined;
+this.finished=true;
+this.endTime=data.timestamp;
+
+this._updateResponseReceivedTimeIfNecessary();
+}
+
+
+
+
+
+
+_onResponse(response,timestamp,resourceType){
+this.url=response.url;
+
+this.connectionId=String(response.connectionId);
+this.connectionReused=response.connectionReused;
+
+if(response.protocol)this.protocol=response.protocol;
+
+this.responseReceivedTime=timestamp;
+
+this.transferSize=response.encodedDataLength;
+if(typeof response.fromDiskCache==='boolean')this.fromDiskCache=response.fromDiskCache;
+
+this.statusCode=response.status;
+
+this.timing=response.timing;
+if(resourceType)this.resourceType=RESOURCE_TYPES[resourceType];
+this.mimeType=response.mimeType;
+this.responseHeadersText=response.headersText||'';
+this.responseHeaders=NetworkRequest._headersDictToHeadersArray(response.headers);
+
+this.fetchedViaServiceWorker=!!response.fromServiceWorker;
+
+if(this.fromMemoryCache)this.timing=undefined;
+if(this.timing)this._recomputeTimesWithResourceTiming(this.timing);
+
+this._updateTransferSizeForLightRiderIfNecessary();
+}
+
+
+
+
+
+
+_recomputeTimesWithResourceTiming(timing){
+
+
+if(timing.requestTime===0||timing.receiveHeadersEnd===-1)return;
+
+
+this.startTime=timing.requestTime;
+const headersReceivedTime=timing.requestTime+timing.receiveHeadersEnd/1000;
+if(!this.responseReceivedTime||this.responseReceivedTime<0){
+this.responseReceivedTime=headersReceivedTime;
+}
+
+this.responseReceivedTime=Math.min(this.responseReceivedTime,headersReceivedTime);
+this.responseReceivedTime=Math.max(this.responseReceivedTime,this.startTime);
+this.endTime=Math.max(this.endTime,this.responseReceivedTime);
+}
+
+
+
+
+
+_updateResponseReceivedTimeIfNecessary(){
+this.responseReceivedTime=Math.min(this.endTime,this.responseReceivedTime);
+}
+
+
+
+
+_updateTransferSizeForLightRiderIfNecessary(){
+
+if(!global.isLightRider)return;
+
+if(this.transferSize)return;
+
+const totalFetchedSize=this.responseHeaders.find(item=>item.name==='X-TotalFetchedSize');
+
+if(!totalFetchedSize)return;
+this.transferSize=parseFloat(totalFetchedSize.value);
+}
+
+
+
+
+
+
+
+static getRequestIdForBackend(requestId){
+return requestId.replace(/(:redirect)+$/,'');
+}
+
+
+
+
+
+
+
+static _headersDictToHeadersArray(headersDict){
+const result=[];
+for(const name of Object.keys(headersDict)){
+const values=headersDict[name].split('\n');
+for(let i=0;i<values.length;++i){
+result.push({name:name,value:values[i]});
+}
+}
+return result;
+}
+
+static get TYPES(){
+return RESOURCE_TYPES;
+}};
+
+
+}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{"./url-shim":"url"}],68:[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function wrapRuntimeEvalErrorInBrowser(err){
+err=err||new Error();
+const fallbackMessage=typeof err==='string'?err:'unknown error';
+
+return{
+__failedInBrowser:true,
+name:err.name||'Error',
+message:err.message||fallbackMessage,
+stack:err.stack||new Error().stack};
+
+}
+
+
+
+
+
+
+function registerPerformanceObserverInPage(){
+window.____lastLongTask=window.__perfNow();
+const observer=new window.PerformanceObserver(entryList=>{
+const entries=entryList.getEntries();
+for(const entry of entries){
+if(entry.entryType==='longtask'){
+const taskEnd=entry.startTime+entry.duration;
+window.____lastLongTask=Math.max(window.____lastLongTask,taskEnd);
+}
+}
+});
+
+observer.observe({entryTypes:['longtask']});
+
+
+
+
+
+window.____lhPerformanceObserver=observer;
+}
+
+
+
+
+
+function checkTimeSinceLastLongTask(){
+
+
+return new window.__nativePromise(resolve=>{
+const timeoutRequested=window.__perfNow()+50;
+
+setTimeout(()=>{
+
+const timeoutFired=window.__perfNow();
+const timeSinceLongTask=timeoutFired-timeoutRequested<50?
+timeoutFired-window.____lastLongTask:0;
+resolve(timeSinceLongTask);
+},50);
+});
+}
+
+
+
+
+
+
+
+function getElementsInDocument(selector){
+const realMatchesFn=window.__ElementMatches||window.Element.prototype.matches;
+
+const results=[];
+
+
+const _findAllElements=nodes=>{
+for(let i=0,el;el=nodes[i];++i){
+if(!selector||realMatchesFn.call(el,selector)){
+results.push(el);
+}
+
+if(el.shadowRoot){
+_findAllElements(el.shadowRoot.querySelectorAll('*'));
+}
+}
+};
+_findAllElements(document.querySelectorAll('*'));
+
+return results;
+}
+
+
+
+
+
+
+
+
+function getOuterHTMLSnippet(element,ignoreAttrs=[]){
+const clone=element.cloneNode();
+
+ignoreAttrs.forEach(attribute=>{
+clone.removeAttribute(attribute);
+});
+
+const reOpeningTag=/^[\s\S]*?>/;
+const match=clone.outerHTML.match(reOpeningTag);
+
+return match&&match[0]||'';
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function ultradumbBenchmark(){
+const start=Date.now();
+let iterations=0;
+
+while(Date.now()-start<500){
+let s='';
+for(let j=0;j<100000;j++)s+='a';
+
+iterations++;
+}
+
+const durationInSeconds=(Date.now()-start)/1000;
+return Math.round(iterations/durationInSeconds);
+}
+
+
+
+
+
+
+
+
+function getNodePath(node){
+
+function getNodeIndex(node){
+let index=0;
+let prevNode;
+while(prevNode=node.previousSibling){
+node=prevNode;
+
+if(node.nodeType===Node.TEXT_NODE&&node.textContent&&
+node.textContent.trim().length===0)continue;
+index++;
+}
+return index;
+}
+
+const path=[];
+while(node&&node.parentNode){
+const index=getNodeIndex(node);
+path.push([index,node.nodeName]);
+node=node.parentNode;
+}
+path.reverse();
+return path.join(',');
+}
+
+
+
+
+
+
+function getNodeSelector(node){
+
+
+
+function getSelectorPart(node){
+let part=node.tagName.toLowerCase();
+if(node.id){
+part+='#'+node.id;
+}else if(node.classList.length>0){
+part+='.'+node.classList[0];
+}
+return part;
+}
+
+const parts=[];
+while(parts.length<4){
+parts.unshift(getSelectorPart(node));
+if(!node.parentElement){
+break;
+}
+node=node.parentElement;
+if(node.tagName==='HTML'){
+break;
+}
+}
+return parts.join(' > ');
+}
+
+module.exports={
+wrapRuntimeEvalErrorInBrowserString:wrapRuntimeEvalErrorInBrowser.toString(),
+registerPerformanceObserverInPageString:registerPerformanceObserverInPage.toString(),
+checkTimeSinceLastLongTaskString:checkTimeSinceLastLongTask.toString(),
+getElementsInDocumentString:getElementsInDocument.toString(),
+getOuterHTMLSnippetString:getOuterHTMLSnippet.toString(),
+getOuterHTMLSnippet:getOuterHTMLSnippet,
+ultradumbBenchmark:ultradumbBenchmark,
+ultradumbBenchmarkString:ultradumbBenchmark.toString(),
+getNodePathString:getNodePath.toString(),
+getNodeSelectorString:getNodeSelector.toString(),
+getNodeSelector:getNodeSelector};
+
+
+},{}],69:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const log=require('lighthouse-logger');
+
+
+
+
+const SENTRY_URL='https://a6bb0da87ee048cc9ae2a345fc09ab2e:63a7029f46f74265981b7e005e0f69f8@sentry.io/174697';
+
+
+const SAMPLE_RATE=0.01;
+
+
+const SAMPLED_ERRORS=[];
+
+
+
+
+const noop=()=>{};
+
+
+
+
+
+const sentryDelegate={
+init,
+
+captureMessage:noop,
+
+captureBreadcrumb:noop,
+
+getContext:noop,
+
+captureException:async()=>{},
+_shouldSample(){
+return SAMPLE_RATE>=Math.random();
+}};
+
+
+
+
+
+
+function init(opts){
+
+if(!opts.flags.enableErrorReporting){
+return;
+}
+
+
+if(!sentryDelegate._shouldSample()){
+return;
+}
+
+try{
+const Sentry=require('raven');
+const sentryConfig=Object.assign({},opts.environmentData,
+{captureUnhandledRejections:true});
+Sentry.config(SENTRY_URL,sentryConfig).install();
+
+
+sentryDelegate.captureMessage=(...args)=>Sentry.captureMessage(...args);
+sentryDelegate.captureBreadcrumb=(...args)=>Sentry.captureBreadcrumb(...args);
+sentryDelegate.getContext=()=>Sentry.getContext();
+
+
+const sentryExceptionCache=new Map();
+
+sentryDelegate.captureException=async(err,opts={})=>{
+
+if(!err)return;
+
+
+
+if(err.expected)return;
+
+const tags=opts.tags||{};
+if(tags.audit){
+const key=`audit-${tags.audit}-${err.message}`;
+if(sentryExceptionCache.has(key))return;
+sentryExceptionCache.set(key,true);
+}
+
+if(tags.gatherer){
+const key=`gatherer-${tags.gatherer}-${err.message}`;
+if(sentryExceptionCache.has(key))return;
+sentryExceptionCache.set(key,true);
+}
+
+
+const sampledErrorMatch=SAMPLED_ERRORS.find(sample=>sample.pattern.test(err.message));
+if(sampledErrorMatch&&sampledErrorMatch.rate<=Math.random())return;
+
+
+
+if(err.protocolMethod){
+
+opts.fingerprint=['{{ default }}',err.protocolMethod,err.protocolError];
+}
+
+return new Promise(resolve=>{
+Sentry.captureException(err,opts,()=>resolve());
+});
+};
+
+const context=Object.assign({
+url:opts.url,
+deviceEmulation:!opts.flags.disableDeviceEmulation,
+emulatedFormFactor:opts.flags.emulatedFormFactor,
+throttlingMethod:opts.flags.throttlingMethod},
+opts.flags.throttling);
+Sentry.mergeContext({extra:Object.assign({},opts.environmentData.extra,context)});
+}catch(e){
+log.warn(
+'sentry',
+'Could not load raven library, errors will not be reported.');
+
+}
+}
+
+module.exports=sentryDelegate;
+
+},{"lighthouse-logger":113,"raven":87}],70:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+function erf(x){
+
+const sign=Math.sign(x);
+x=Math.abs(x);
+
+const a1=0.254829592;
+const a2=-0.284496736;
+const a3=1.421413741;
+const a4=-1.453152027;
+const a5=1.061405429;
+const p=0.3275911;
+const t=1/(1+p*x);
+const y=t*(a1+t*(a2+t*(a3+t*(a4+t*a5))));
+return sign*(1-y*Math.exp(-x*x));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function getLogNormalDistribution(median,falloff){
+const location=Math.log(median);
+
+
+
+
+const logRatio=Math.log(falloff/median);
+const shape=Math.sqrt(1-3*logRatio-Math.sqrt((logRatio-3)*(logRatio-3)-8))/2;
+
+return{
+computeComplementaryPercentile(x){
+const standardizedX=(Math.log(x)-location)/(Math.SQRT2*shape);
+return(1-erf(standardizedX))/2;
+}};
+
+}
+
+
+
+
+
+
+
+
+
+
+function linearInterpolation(x0,y0,x1,y1,x){
+const slope=(y1-y0)/(x1-x0);
+return y0+(x-x0)*slope;
+}
+
+module.exports={
+linearInterpolation,
+getLogNormalDistribution};
+
+
+},{}],71:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const taskGroups={
+parseHTML:{
+id:'parseHTML',
+label:'Parse HTML & CSS',
+traceEventNames:['ParseHTML','ParseAuthorStyleSheet']},
+
+styleLayout:{
+id:'styleLayout',
+label:'Style & Layout',
+traceEventNames:[
+'ScheduleStyleRecalculation',
+'UpdateLayoutTree',
+'InvalidateLayout',
+'Layout']},
+
+
+paintCompositeRender:{
+id:'paintCompositeRender',
+label:'Rendering',
+traceEventNames:[
+'Animation',
+'HitTest',
+'PaintSetup',
+'Paint',
+'PaintImage',
+'RasterTask',
+'ScrollLayer',
+'UpdateLayer',
+'UpdateLayerTree',
+'CompositeLayers']},
+
+
+scriptParseCompile:{
+id:'scriptParseCompile',
+label:'Script Parsing & Compilation',
+traceEventNames:['v8.compile','v8.compileModule','v8.parseOnBackground']},
+
+scriptEvaluation:{
+id:'scriptEvaluation',
+label:'Script Evaluation',
+traceEventNames:[
+'EventDispatch',
+'EvaluateScript',
+'v8.evaluateModule',
+'FunctionCall',
+'TimerFire',
+'FireIdleCallback',
+'FireAnimationFrame',
+'RunMicrotasks',
+'V8.Execute']},
+
+
+garbageCollection:{
+id:'garbageCollection',
+label:'Garbage Collection',
+traceEventNames:[
+'MinorGC',
+'MajorGC',
+'BlinkGC.AtomicPhase',
+
+
+'ThreadState::performIdleLazySweep',
+'ThreadState::completeSweep',
+'BlinkGCMarking']},
+
+
+other:{
+id:'other',
+label:'Other',
+traceEventNames:[
+'MessageLoop::RunTask',
+'TaskQueueManager::ProcessTaskFromWorkQueue',
+'ThreadControllerImpl::DoWork']}};
+
+
+
+
+
+const taskNameToGroup={};
+for(const group of Object.values(taskGroups)){
+for(const traceEventName of group.traceEventNames){
+taskNameToGroup[traceEventName]=group;
+}
+}
+
+module.exports={
+taskGroups,
+taskNameToGroup};
+
+
+},{}],72:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const log=require('lighthouse-logger');
+
+
+
+
+
+
+
+function getUberMetrics(auditResults){
+const metricsAudit=auditResults.metrics;
+if(!metricsAudit||!metricsAudit.details||!metricsAudit.details.items)return;
+
+return metricsAudit.details.items[0];
+}
+
+class Metrics{
+
+
+
+
+constructor(traceEvents,auditResults){
+this._traceEvents=traceEvents;
+this._auditResults=auditResults;
+}
+
+
+
+
+
+static get metricsDefinitions(){
+return[
+{
+name:'Navigation Start',
+id:'navstart',
+tsKey:'observedNavigationStartTs'},
+
+{
+name:'First Contentful Paint',
+id:'ttfcp',
+tsKey:'observedFirstContentfulPaintTs'},
+
+{
+name:'First Meaningful Paint',
+id:'ttfmp',
+tsKey:'observedFirstMeaningfulPaintTs'},
+
+{
+name:'Speed Index',
+id:'si',
+tsKey:'observedSpeedIndexTs'},
+
+{
+name:'First Visual Change',
+id:'fv',
+tsKey:'observedFirstVisualChangeTs'},
+
+{
+name:'Visually Complete 100%',
+id:'vc100',
+tsKey:'observedLastVisualChangeTs'},
+
+{
+name:'First CPU Idle',
+id:'ttfi',
+tsKey:'firstCPUIdleTs'},
+
+{
+name:'Interactive',
+id:'tti',
+tsKey:'interactiveTs'},
+
+{
+name:'End of Trace',
+id:'eot',
+tsKey:'observedTraceEndTs'},
+
+{
+name:'On Load',
+id:'onload',
+tsKey:'observedLoadTs'},
+
+{
+name:'DOM Content Loaded',
+id:'dcl',
+tsKey:'observedDomContentLoadedTs'}];
+
+
+}
+
+
+
+
+
+gatherMetrics(){
+const uberMetrics=getUberMetrics(this._auditResults);
+if(!uberMetrics){
+return[];
+}
+
+
+const resolvedMetrics=[];
+Metrics.metricsDefinitions.forEach(metric=>{
+
+const ts=uberMetrics[metric.tsKey];
+if(ts===undefined){
+log.error('pwmetrics-events',`${metric.name} timestamp not found`);
+return;
+}
+
+resolvedMetrics.push({
+id:metric.id,
+name:metric.name,
+ts});
+
+});
+
+return resolvedMetrics;
+}
+
+
+
+
+
+
+getNavigationStartEvt(metrics){
+const navStartMetric=metrics.find(e=>e.id==='navstart');
+if(!navStartMetric)return;
+return this._traceEvents.find(
+e=>e.name==='navigationStart'&&e.ts===navStartMetric.ts);
+
+}
+
+
+
+
+
+
+
+
+
+synthesizeEventPair(metric,navigationStartEvt){
+
+const eventBase={
+pid:navigationStartEvt.pid,
+tid:navigationStartEvt.tid,
+cat:'blink.user_timing',
+name:metric.name,
+args:{},
+
+id:`0x${(Math.random()*1000000|0).toString(16)}`};
+
+const fakeMeasureStartEvent=Object.assign({},eventBase,{
+ts:navigationStartEvt.ts,
+ph:'b'});
+
+const fakeMeasureEndEvent=Object.assign({},eventBase,{
+ts:metric.ts,
+ph:'e'});
+
+return[fakeMeasureStartEvent,fakeMeasureEndEvent];
+}
+
+
+
+
+generateFakeEvents(){
+const metrics=this.gatherMetrics();
+if(metrics.length===0){
+log.error('metrics-events','Metrics collection had errors, not synthetizing trace events');
+return[];
+}
+
+const navigationStartEvt=this.getNavigationStartEvt(metrics);
+if(!navigationStartEvt){
+log.error('pwmetrics-events','Reference navigationStart not found');
+return[];
+}
+
+
+const fakeEvents=[];
+metrics.forEach(metric=>{
+if(metric.id==='navstart'){
+return;
+}
+if(!metric.ts){
+log.error('pwmetrics-events',`(${metric.name}) missing timestamp. Skipping…`);
+return;
+}
+log.verbose('pwmetrics-events',`Sythesizing trace events for ${metric.name}`);
+fakeEvents.push(...this.synthesizeEventPair(metric,navigationStartEvt));
+});
+return fakeEvents;
+}}
+
+
+module.exports=Metrics;
+
+},{"lighthouse-logger":113}],73:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+const BASE_RESPONSE_LATENCY=16;
+
+const SCHEDULABLE_TASK_TITLE_LH='RunTask';
+
+const SCHEDULABLE_TASK_TITLE_ALT1='ThreadControllerImpl::RunTask';
+
+const SCHEDULABLE_TASK_TITLE_ALT2='ThreadControllerImpl::DoWork';
+
+const SCHEDULABLE_TASK_TITLE_ALT3='TaskQueueManager::ProcessTaskFromWorkQueue';
+
+
+const LHError=require('../lh-error');
+
+class TraceProcessor{
+
+
+
+
+
+
+static assertHasToplevelEvents(events){
+const hasToplevelTask=events.some(TraceProcessor.isScheduleableTask);
+if(!hasToplevelTask){
+throw new Error('Could not find any top level events');
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static _riskPercentiles(durations,totalTime,percentiles,clippedLength=0){
+let busyTime=0;
+for(let i=0;i<durations.length;i++){
+busyTime+=durations[i];
+}
+busyTime-=clippedLength;
+
+
+let completedTime=totalTime-busyTime;
+let duration=0;
+let cdfTime=completedTime;
+const results=[];
+
+let durationIndex=-1;
+let remainingCount=durations.length+1;
+if(clippedLength>0){
+
+remainingCount--;
+}
+
+
+for(const percentile of percentiles){
+
+
+const percentileTime=percentile*totalTime;
+while(cdfTime<percentileTime&&durationIndex<durations.length-1){
+completedTime+=duration;
+remainingCount-=duration<0?-1:1;
+
+if(clippedLength>0&&clippedLength<durations[durationIndex+1]){
+duration=-clippedLength;
+clippedLength=0;
+}else{
+durationIndex++;
+duration=durations[durationIndex];
+}
+
+
+cdfTime=completedTime+Math.abs(duration)*remainingCount;
+}
+
+
+results.push({
+percentile,
+time:Math.max(0,(percentileTime-completedTime)/remainingCount)+
+BASE_RESPONSE_LATENCY});
+
+}
+
+return results;
+}
+
+
+
+
+
+
+
+
+
+
+
+static getRiskToResponsiveness(
+events,
+startTime,
+endTime,
+percentiles=[0.5,0.75,0.9,0.99,1])
+{
+const totalTime=endTime-startTime;
+percentiles.sort((a,b)=>a-b);
+
+const ret=TraceProcessor.getMainThreadTopLevelEventDurations(events,startTime,endTime);
+return TraceProcessor._riskPercentiles(ret.durations,totalTime,percentiles,
+ret.clippedLength);
+}
+
+
+
+
+
+
+
+
+static getMainThreadTopLevelEventDurations(topLevelEvents,startTime=0,endTime=Infinity){
+
+
+const durations=[];
+let clippedLength=0;
+
+for(const event of topLevelEvents){
+if(event.end<startTime||event.start>endTime){
+continue;
+}
+
+let duration=event.duration;
+let eventStart=event.start;
+if(eventStart<startTime){
+
+eventStart=startTime;
+duration=event.end-startTime;
+}
+
+if(event.end>endTime){
+
+clippedLength=duration-(endTime-eventStart);
+}
+
+durations.push(duration);
+}
+durations.sort((a,b)=>a-b);
+
+return{
+durations,
+clippedLength};
+
+}
+
+
+
+
+
+
+
+
+
+static getMainThreadTopLevelEvents(tabTrace,startTime=0,endTime=Infinity){
+const topLevelEvents=[];
+
+for(const event of tabTrace.mainThreadEvents){
+if(!TraceProcessor.isScheduleableTask(event)||!event.dur)continue;
+
+const start=(event.ts-tabTrace.navigationStartEvt.ts)/1000;
+const end=(event.ts+event.dur-tabTrace.navigationStartEvt.ts)/1000;
+if(start>endTime||end<startTime)continue;
+
+topLevelEvents.push({
+start,
+end,
+duration:event.dur/1000});
+
+}
+
+return topLevelEvents;
+}
+
+
+
+
+
+static findMainFrameIds(events){
+
+const startedInBrowserEvt=events.find(e=>e.name==='TracingStartedInBrowser');
+if(startedInBrowserEvt&&startedInBrowserEvt.args.data&&
+startedInBrowserEvt.args.data.frames){
+const mainFrame=startedInBrowserEvt.args.data.frames.find(frame=>!frame.parent);
+const frameId=mainFrame&&mainFrame.frame;
+const pid=mainFrame&&mainFrame.processId;
+
+const threadNameEvt=events.find(e=>e.pid===pid&&e.ph==='M'&&
+e.cat==='__metadata'&&e.name==='thread_name'&&e.args.name==='CrRendererMain');
+const tid=threadNameEvt&&threadNameEvt.tid;
+
+if(pid&&tid&&frameId){
+return{
+pid,
+tid,
+frameId};
+
+}
+}
+
+
+
+
+const startedInPageEvt=events.find(e=>e.name==='TracingStartedInPage');
+if(startedInPageEvt&&startedInPageEvt.args&&startedInPageEvt.args.data){
+const frameId=startedInPageEvt.args.data.page;
+if(frameId){
+return{
+pid:startedInPageEvt.pid,
+tid:startedInPageEvt.tid,
+frameId};
+
+}
+}
+
+throw new LHError(LHError.errors.NO_TRACING_STARTED);
+}
+
+
+
+
+
+static isScheduleableTask(evt){
+return evt.name===SCHEDULABLE_TASK_TITLE_LH||
+evt.name===SCHEDULABLE_TASK_TITLE_ALT1||
+evt.name===SCHEDULABLE_TASK_TITLE_ALT2||
+evt.name===SCHEDULABLE_TASK_TITLE_ALT3;
+}}
+
+
+
+
+
+
+
+
+
+module.exports=TraceProcessor;
+
+},{"../lh-error":63}],74:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+
+
+const ELLIPSIS='\u2026';
+const NBSP='\xa0';
+const PASS_THRESHOLD=0.9;
+
+const RATINGS={
+PASS:{label:'pass',minScore:PASS_THRESHOLD},
+AVERAGE:{label:'average',minScore:0.5},
+FAIL:{label:'fail'},
+ERROR:{label:'error'}};
+
+
+class Util{
+static get PASS_THRESHOLD(){
+return PASS_THRESHOLD;
+}
+
+static get MS_DISPLAY_VALUE(){
+return`%10d${NBSP}ms`;
+}
+
+
+
+
+
+
+
+
+
+static prepareReportResult(result){
+
+const clone=JSON.parse(JSON.stringify(result));
+
+
+if(!clone.configSettings.locale){
+clone.configSettings.locale='en';
+}
+Util.setNumberDateLocale(clone.configSettings.locale);
+if(clone.i18n&&clone.i18n.rendererFormattedStrings){
+Util.updateAllUIStrings(clone.i18n.rendererFormattedStrings);
+}
+
+if(typeof clone.categories!=='object')throw new Error('No categories provided.');
+clone.reportCategories=Object.values(clone.categories);
+
+
+
+for(const audit of Object.values(clone.audits)){
+
+
+if(audit.scoreDisplayMode==='not_applicable'||audit.scoreDisplayMode==='not-applicable'){
+audit.scoreDisplayMode='notApplicable';
+}
+}
+
+
+for(const category of clone.reportCategories){
+category.auditRefs.forEach(auditMeta=>{
+const result=clone.audits[auditMeta.id];
+auditMeta.result=result;
+});
+}
+
+return clone;
+}
+
+
+
+
+
+static updateAllUIStrings(rendererFormattedStrings){
+
+for(const[key,value]of Object.entries(rendererFormattedStrings)){
+Util.UIStrings[key]=value;
+}
+}
+
+
+
+
+
+static formatDisplayValue(displayValue){
+if(typeof displayValue==='string')return displayValue;
+if(!displayValue)return'';
+
+const replacementRegex=/%([0-9]*(\.[0-9]+)?d|s)/;
+const template=displayValue[0];
+if(typeof template!=='string'){
+
+
+return'UNKNOWN';
+}
+
+let output=template;
+for(const replacement of displayValue.slice(1)){
+if(!replacementRegex.test(output)){
+
+console.warn('Too many replacements given');
+break;
+}
+
+output=output.replace(replacementRegex,match=>{
+const granularity=Number(match.match(/[0-9.]+/))||1;
+return match==='%s'?
+replacement.toLocaleString():
+(Math.round(Number(replacement)/granularity)*granularity).toLocaleString();
+});
+}
+
+if(replacementRegex.test(output)){
+
+console.warn('Not enough replacements given');
+}
+
+return output;
+}
+
+
+
+
+
+
+
+
+static showAsPassed(audit){
+switch(audit.scoreDisplayMode){
+case'manual':
+case'notApplicable':
+return true;
+case'error':
+case'informative':
+return false;
+case'numeric':
+case'binary':
+default:
+return Number(audit.score)>=RATINGS.PASS.minScore;}
+
+}
+
+
+
+
+
+
+
+static calculateRating(score,scoreDisplayMode){
+
+if(scoreDisplayMode==='manual'||scoreDisplayMode==='notApplicable'){
+return RATINGS.PASS.label;
+}else if(scoreDisplayMode==='error'){
+return RATINGS.ERROR.label;
+}else if(score===null){
+return RATINGS.FAIL.label;
+}
+
+
+let rating=RATINGS.FAIL.label;
+if(score>=RATINGS.PASS.minScore){
+rating=RATINGS.PASS.label;
+}else if(score>=RATINGS.AVERAGE.minScore){
+rating=RATINGS.AVERAGE.label;
+}
+return rating;
+}
+
+
+
+
+
+
+
+static formatNumber(number,granularity=0.1){
+const coarseValue=Math.round(number/granularity)*granularity;
+return coarseValue.toLocaleString(Util.numberDateLocale);
+}
+
+
+
+
+
+
+static formatBytesToKB(size,granularity=0.1){
+const kbs=(Math.round(size/1024/granularity)*granularity).
+toLocaleString(Util.numberDateLocale);
+return`${kbs}${NBSP}KB`;
+}
+
+
+
+
+
+
+static formatMilliseconds(ms,granularity=10){
+const coarseTime=Math.round(ms/granularity)*granularity;
+return`${coarseTime.toLocaleString(Util.numberDateLocale)}${NBSP}ms`;
+}
+
+
+
+
+
+
+static formatSeconds(ms,granularity=0.1){
+const coarseTime=Math.round(ms/1000/granularity)*granularity;
+return`${coarseTime.toLocaleString(Util.numberDateLocale)}${NBSP}s`;
+}
+
+
+
+
+
+
+static formatDateTime(date){
+
+const options={
+month:'short',day:'numeric',year:'numeric',
+hour:'numeric',minute:'numeric',timeZoneName:'short'};
+
+let formatter=new Intl.DateTimeFormat(Util.numberDateLocale,options);
+
+
+
+const tz=formatter.resolvedOptions().timeZone;
+if(!tz||tz.toLowerCase()==='etc/unknown'){
+options.timeZone='UTC';
+formatter=new Intl.DateTimeFormat(Util.numberDateLocale,options);
+}
+return formatter.format(new Date(date));
+}
+
+
+
+
+
+static formatDuration(timeInMilliseconds){
+let timeInSeconds=timeInMilliseconds/1000;
+if(Math.round(timeInSeconds)===0){
+return'None';
+}
+
+
+const parts=[];
+const unitLabels={
+d:60*60*24,
+h:60*60,
+m:60,
+s:1};
+
+
+Object.keys(unitLabels).forEach(label=>{
+const unit=unitLabels[label];
+const numberOfUnits=Math.floor(timeInSeconds/unit);
+if(numberOfUnits>0){
+timeInSeconds-=numberOfUnits*unit;
+parts.push(`${numberOfUnits}\xa0${label}`);
+}
+});
+
+return parts.join(' ');
+}
+
+
+
+
+
+
+static getURLDisplayName(parsedUrl,options){
+
+options=options||{numPathParts:undefined,preserveQuery:undefined,
+preserveHost:undefined};
+const numPathParts=options.numPathParts!==undefined?options.numPathParts:2;
+const preserveQuery=options.preserveQuery!==undefined?options.preserveQuery:true;
+const preserveHost=options.preserveHost||false;
+
+let name;
+
+if(parsedUrl.protocol==='about:'||parsedUrl.protocol==='data:'){
+
+name=parsedUrl.href;
+}else{
+name=parsedUrl.pathname;
+const parts=name.split('/').filter(part=>part.length);
+if(numPathParts&&parts.length>numPathParts){
+name=ELLIPSIS+parts.slice(-1*numPathParts).join('/');
+}
+
+if(preserveHost){
+name=`${parsedUrl.host}/${name.replace(/^\//,'')}`;
+}
+if(preserveQuery){
+name=`${name}${parsedUrl.search}`;
+}
+}
+
+const MAX_LENGTH=64;
+
+name=name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,`$1${ELLIPSIS}`);
+
+name=name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,
+`$1${ELLIPSIS}`);
+
+name=name.replace(/(\d{3})\d{6,}/g,`$1${ELLIPSIS}`);
+
+name=name.replace(/\u2026+/g,ELLIPSIS);
+
+
+if(name.length>MAX_LENGTH&&name.includes('?')){
+
+name=name.replace(/\?([^=]*)(=)?.*/,`?$1$2${ELLIPSIS}`);
+
+
+if(name.length>MAX_LENGTH){
+name=name.replace(/\?.*/,`?${ELLIPSIS}`);
+}
+}
+
+
+if(name.length>MAX_LENGTH){
+const dotIndex=name.lastIndexOf('.');
+if(dotIndex>=0){
+name=name.slice(0,MAX_LENGTH-1-(name.length-dotIndex))+
+
+`${ELLIPSIS}${name.slice(dotIndex)}`;
+}else{
+name=name.slice(0,MAX_LENGTH-1)+ELLIPSIS;
+}
+}
+
+return name;
+}
+
+
+
+
+
+
+static parseURL(url){
+const parsedUrl=new URL(url);
+return{
+file:Util.getURLDisplayName(parsedUrl),
+hostname:parsedUrl.hostname,
+origin:parsedUrl.origin};
+
+}
+
+
+
+
+
+static getEnvironmentDisplayValues(settings){
+const emulationDesc=Util.getEmulationDescriptions(settings);
+
+return[
+{
+name:'Device',
+description:emulationDesc.deviceEmulation},
+
+{
+name:'Network throttling',
+description:emulationDesc.networkThrottling},
+
+{
+name:'CPU throttling',
+description:emulationDesc.cpuThrottling}];
+
+
+}
+
+
+
+
+
+static getEmulationDescriptions(settings){
+let cpuThrottling;
+let networkThrottling;
+let summary;
+
+const throttling=settings.throttling;
+
+switch(settings.throttlingMethod){
+case'provided':
+cpuThrottling='Provided by environment';
+networkThrottling='Provided by environment';
+summary='No throttling applied';
+break;
+case'devtools':{
+const{cpuSlowdownMultiplier,requestLatencyMs}=throttling;
+cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;
+networkThrottling=`${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, `+
+`${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, `+
+`${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
+summary='Throttled Slow 4G network';
+break;
+}
+case'simulate':{
+const{cpuSlowdownMultiplier,rttMs,throughputKbps}=throttling;
+cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
+networkThrottling=`${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, `+
+`${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
+summary='Simulated Slow 4G network';
+break;
+}
+default:
+cpuThrottling='Unknown';
+networkThrottling='Unknown';
+summary='Unknown';}
+
+
+let deviceEmulation='No emulation';
+if(!settings.disableDeviceEmulation){
+if(settings.emulatedFormFactor==='mobile')deviceEmulation='Emulated Nexus 5X';
+if(settings.emulatedFormFactor==='desktop')deviceEmulation='Emulated Desktop';
+}
+
+return{
+deviceEmulation,
+cpuThrottling,
+networkThrottling,
+summary:`${deviceEmulation}, ${summary}`};
+
+}
+
+
+
+
+
+static setNumberDateLocale(locale){
+Util.numberDateLocale=locale;
+
+
+if(Util.numberDateLocale==='en-XA')Util.numberDateLocale='de';
+}}
+
+
+
+
+
+
+Util.numberDateLocale='en';
+
+
+
+
+
+Util.UIStrings={
+
+varianceDisclaimer:'Values are estimated and may vary.',
+
+opportunityResourceColumnLabel:'Opportunity',
+
+opportunitySavingsColumnLabel:'Estimated Savings',
+
+
+errorMissingAuditInfo:'Report error: no audit information',
+
+errorLabel:'Error!',
+
+warningHeader:'Warnings: ',
+
+auditGroupExpandTooltip:'Show audits',
+
+warningAuditsGroupTitle:'Passed audits but with warnings',
+
+passedAuditsGroupTitle:'Passed audits',
+
+notApplicableAuditsGroupTitle:'Not applicable',
+
+manualAuditsGroupTitle:'Additional items to manually check',
+
+
+toplevelWarningsMessage:'There were issues affecting this run of Lighthouse:',
+
+scorescaleLabel:'Score scale:',
+
+
+crcInitialNavigation:'Initial Navigation',
+
+crcLongestDurationLabel:'Maximum critical path latency:',
+
+
+lsPerformanceCategoryDescription:'[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.',
+
+labDataTitle:'Lab Data'};
+
+
+if(typeof module!=='undefined'&&module.exports){
+module.exports=Util;
+}else{
+self.Util=Util;
+}
+
+},{}],75:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const htmlReportAssets=require('./html/html-report-assets');
+
+class ReportGenerator{
+
+
+
+
+
+
+static replaceStrings(source,replacements){
+if(replacements.length===0){
+return source;
+}
+
+const firstReplacement=replacements[0];
+const nextReplacements=replacements.slice(1);
+return source.
+split(firstReplacement.search).
+map(part=>ReportGenerator.replaceStrings(part,nextReplacements)).
+join(firstReplacement.replacement);
+}
+
+
+
+
+
+
+static generateReportHtml(lhr){
+const sanitizedJson=JSON.stringify(lhr).
+replace(/</g,'\\u003c').
+replace(/\u2028/g,'\\u2028').
+replace(/\u2029/g,'\\u2029');
+const sanitizedJavascript=htmlReportAssets.REPORT_JAVASCRIPT.replace(/<\//g,'\\u003c/');
+
+return ReportGenerator.replaceStrings(htmlReportAssets.REPORT_TEMPLATE,[
+{search:'%%LIGHTHOUSE_JSON%%',replacement:sanitizedJson},
+{search:'%%LIGHTHOUSE_JAVASCRIPT%%',replacement:sanitizedJavascript},
+{search:'/*%%LIGHTHOUSE_CSS%%*/',replacement:htmlReportAssets.REPORT_CSS},
+{search:'%%LIGHTHOUSE_TEMPLATES%%',replacement:htmlReportAssets.REPORT_TEMPLATES}]);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+static generateReportCSV(lhr){
+
+
+const CRLF='\r\n';
+const separator=',';
+
+const escape=value=>`"${value.replace(/"/g,'""')}"`;
+
+
+const header=['category','name','title','type','score'];
+const table=Object.values(lhr.categories).map(category=>{
+return category.auditRefs.map(auditRef=>{
+const audit=lhr.audits[auditRef.id];
+
+const numericScore=audit.score===null?-1:audit.score;
+return[category.title,audit.id,audit.title,audit.scoreDisplayMode,numericScore].
+map(value=>value.toString()).
+map(escape);
+});
+});
+
+return[header].concat(...table).
+map(row=>row.join(separator)).join(CRLF);
+}
+
+
+
+
+
+
+
+static generateReport(lhr,outputModes){
+const outputAsArray=Array.isArray(outputModes);
+if(typeof outputModes==='string')outputModes=[outputModes];
+
+const output=outputModes.map(outputMode=>{
+
+if(outputMode==='html'){
+return ReportGenerator.generateReportHtml(lhr);
+}
+
+if(outputMode==='csv'){
+return ReportGenerator.generateReportCSV(lhr);
+}
+
+if(outputMode==='json'){
+return JSON.stringify(lhr,null,2);
+}
+
+throw new Error('Invalid output mode: '+outputMode);
+});
+
+return outputAsArray?output:output[0];
+}}
+
+
+module.exports=ReportGenerator;
+
+},{"./html/html-report-assets":87}],76:[function(require,module,exports){
+(function(process){
+
+
+
+
+
+'use strict';
+
+const isDeepEqual=require('lodash.isequal');
+const Driver=require('./gather/driver.js');
+const GatherRunner=require('./gather/gather-runner');
+const ReportScoring=require('./scoring');
+const Audit=require('./audits/audit');
+const log=require('lighthouse-logger');
+const i18n=require('./lib/i18n/i18n.js');
+const assetSaver=require('./lib/asset-saver');
+
+const path=require('path');
+const URL=require('./lib/url-shim');
+const Sentry=require('./lib/sentry');
+const generateReport=require('./report/report-generator').generateReport;
+const LHError=require('./lib/lh-error.js');
+
+
+
+
+class Runner{
+
+
+
+
+
+static async run(connection,runOpts){
+const settings=runOpts.config.settings;
+try{
+const runnerStatus={msg:'Runner setup',id:'lh:runner:run'};
+log.time(runnerStatus,'verbose');
+
+
+
+
+
+const lighthouseRunWarnings=[];
+
+const sentryContext=Sentry.getContext();
+Sentry.captureBreadcrumb({
+message:'Run started',
+category:'lifecycle',
+data:sentryContext&&sentryContext.extra});
+
+
+
+
+
+
+
+
+let artifacts;
+let requestedUrl;
+if(settings.auditMode&&!settings.gatherMode){
+
+const path=Runner._getArtifactsPath(settings);
+artifacts=await assetSaver.loadArtifacts(path);
+requestedUrl=artifacts.URL.requestedUrl;
+
+if(!requestedUrl){
+throw new Error('Cannot run audit mode on empty URL');
+}
+if(runOpts.url&&!URL.equalWithExcludedFragments(runOpts.url,requestedUrl)){
+throw new Error('Cannot run audit mode on different URL');
+}
+}else{
+if(typeof runOpts.url!=='string'||runOpts.url.length===0){
+throw new Error(`You must provide a url to the runner. '${runOpts.url}' provided.`);
+}
+
+try{
+
+requestedUrl=new URL(runOpts.url).href;
+}catch(e){
+throw new Error('The url provided should have a proper protocol and hostname.');
+}
+
+artifacts=await Runner._gatherArtifactsFromBrowser(requestedUrl,runOpts,connection);
+
+if(settings.gatherMode){
+const path=Runner._getArtifactsPath(settings);
+await assetSaver.saveArtifacts(artifacts,path);
+}
+}
+
+
+if(settings.gatherMode&&!settings.auditMode)return;
+
+
+if(!runOpts.config.audits){
+throw new Error('No audits to evaluate.');
+}
+const auditResults=await Runner._runAudits(settings,runOpts.config.audits,artifacts,
+lighthouseRunWarnings);
+
+
+const resultsStatus={msg:'Generating results...',id:'lh:runner:generate'};
+log.time(resultsStatus);
+
+if(artifacts.LighthouseRunWarnings){
+lighthouseRunWarnings.push(...artifacts.LighthouseRunWarnings);
+}
+
+
+const lighthouseVersion=require('../package.json').version;
+
+
+const resultsById={};
+for(const audit of auditResults){
+resultsById[audit.id]=audit;
+}
+
+
+let categories={};
+if(runOpts.config.categories){
+categories=ReportScoring.scoreAllCategories(runOpts.config.categories,resultsById);
+}
+
+log.timeEnd(resultsStatus);
+log.timeEnd(runnerStatus);
+
+
+const lhr={
+userAgent:artifacts.HostUserAgent,
+environment:{
+networkUserAgent:artifacts.NetworkUserAgent,
+hostUserAgent:artifacts.HostUserAgent,
+benchmarkIndex:artifacts.BenchmarkIndex},
+
+lighthouseVersion,
+fetchTime:artifacts.fetchTime,
+requestedUrl:requestedUrl,
+finalUrl:artifacts.URL.finalUrl,
+runWarnings:lighthouseRunWarnings,
+runtimeError:Runner.getArtifactRuntimeError(artifacts),
+audits:resultsById,
+configSettings:settings,
+categories,
+categoryGroups:runOpts.config.groups||undefined,
+timing:this._getTiming(artifacts),
+i18n:{
+rendererFormattedStrings:i18n.getRendererFormattedStrings(settings.locale),
+icuMessagePaths:{}}};
+
+
+
+
+lhr.i18n.icuMessagePaths=i18n.replaceIcuMessageInstanceIds(lhr,settings.locale);
+
+
+const report=generateReport(lhr,settings.output);
+
+return{lhr,artifacts,report};
+}catch(err){
+
+err.friendlyMessage=i18n.getFormatted(err.friendlyMessage,settings.locale);
+await Sentry.captureException(err,{level:'fatal'});
+throw err;
+}
+}
+
+
+
+
+
+
+
+
+static _getTiming(artifacts){
+const timingEntriesFromArtifacts=artifacts.Timing||[];
+const timingEntriesFromRunner=log.takeTimeEntries();
+const timingEntriesKeyValues=[
+...timingEntriesFromArtifacts,
+...timingEntriesFromRunner].
+
+map(entry=>[entry.startTime,entry]);
+const timingEntries=Array.from(new Map(timingEntriesKeyValues).values());
+const runnerEntry=timingEntries.find(e=>e.name==='lh:runner:run');
+return{entries:timingEntries,total:runnerEntry&&runnerEntry.duration||0};
+}
+
+
+
+
+
+
+
+
+static async _gatherArtifactsFromBrowser(requestedUrl,runnerOpts,connection){
+if(!runnerOpts.config.passes){
+throw new Error('No browser artifacts are either provided or requested.');
+}
+const driver=runnerOpts.driverMock||new Driver(connection);
+const gatherOpts={
+driver,
+requestedUrl,
+settings:runnerOpts.config.settings};
+
+const artifacts=await GatherRunner.run(runnerOpts.config.passes,gatherOpts);
+return artifacts;
+}
+
+
+
+
+
+
+
+
+
+static async _runAudits(settings,audits,artifacts,runWarnings){
+const status={msg:'Analyzing and running audits...',id:'lh:runner:auditing'};
+log.time(status);
+
+if(artifacts.settings){
+const overrides={
+locale:undefined,
+gatherMode:undefined,
+auditMode:undefined,
+output:undefined};
+
+const normalizedGatherSettings=Object.assign({},artifacts.settings,overrides);
+const normalizedAuditSettings=Object.assign({},settings,overrides);
+
+
+if(!isDeepEqual(normalizedGatherSettings,normalizedAuditSettings)){
+throw new Error('Cannot change settings between gathering and auditing');
+}
+}
+
+
+const sharedAuditContext={
+settings,
+LighthouseRunWarnings:runWarnings,
+computedCache:new Map()};
+
+
+
+const auditResults=[];
+for(const auditDefn of audits){
+const auditResult=await Runner._runAudit(auditDefn,artifacts,sharedAuditContext);
+auditResults.push(auditResult);
+}
+
+log.timeEnd(status);
+return auditResults;
+}
+
+
+
+
+
+
+
+
+
+
+static async _runAudit(auditDefn,artifacts,sharedAuditContext){
+const audit=auditDefn.implementation;
+const status={
+msg:`Evaluating: ${i18n.getFormatted(audit.meta.title,'en-US')}`,
+id:`lh:audit:${audit.meta.id}`};
+
+log.time(status);
+
+let auditResult;
+try{
+
+for(const artifactName of audit.meta.requiredArtifacts){
+const noArtifact=artifacts[artifactName]===undefined;
+
+
+
+const noTrace=artifactName==='traces'&&!artifacts.traces[Audit.DEFAULT_PASS];
+
+if(noArtifact||noTrace){
+log.warn('Runner',
+`${artifactName} gatherer, required by audit ${audit.meta.id}, did not run.`);
+throw new Error(`Required ${artifactName} gatherer did not run.`);
+}
+
+
+if(artifacts[artifactName]instanceof Error){
+
+
+const artifactError=artifacts[artifactName];
+
+Sentry.captureException(artifactError,{
+tags:{gatherer:artifactName},
+level:'error'});
+
+
+log.warn('Runner',`${artifactName} gatherer, required by audit ${audit.meta.id},`+
+` encountered an error: ${artifactError.message}`);
+
+
+const error=new Error(
+`Required ${artifactName} gatherer encountered an error: ${artifactError.message}`);
+
+error.expected=true;
+throw error;
+}
+}
+
+
+const auditOptions=Object.assign({},audit.defaultOptions,auditDefn.options);
+const auditContext={
+options:auditOptions,
+...sharedAuditContext};
+
+
+const product=await audit.audit(artifacts,auditContext);
+auditResult=Audit.generateAuditResult(audit,product);
+}catch(err){
+log.warn(audit.meta.id,`Caught exception: ${err.message}`);
+
+Sentry.captureException(err,{tags:{audit:audit.meta.id},level:'error'});
+
+const errorMessage=err.friendlyMessage?err.friendlyMessage:err.message;
+auditResult=Audit.generateErrorAuditResult(audit,errorMessage);
+}
+
+log.timeEnd(status);
+return auditResult;
+}
+
+
+
+
+
+
+static getArtifactRuntimeError(artifacts){
+for(const possibleErrorArtifact of Object.values(artifacts)){
+if(possibleErrorArtifact instanceof LHError&&possibleErrorArtifact.lhrRuntimeError){
+const errorMessage=possibleErrorArtifact.friendlyMessage||possibleErrorArtifact.message;
+
+return{
+code:possibleErrorArtifact.code,
+message:errorMessage};
+
+}
+}
+
+return{
+code:LHError.NO_ERROR,
+message:''};
+
+}
+
+
+
+
+
+static getAuditList(){
+const ignoredFiles=[
+'audit.js',
+'violation-audit.js',
+'accessibility/axe-audit.js',
+'multi-check-audit.js',
+'byte-efficiency/byte-efficiency-audit.js',
+'manual/manual-audit.js'];
+
+
+const fileList=[
+...["accessibility","audit.js","bootup-time.js","byte-efficiency","content-width.js","critical-request-chains.js","deprecations.js","dobetterweb","errors-in-console.js","final-screenshot.js","font-display.js","image-aspect-ratio.js","installable-manifest.js","is-on-https.js","load-fast-enough-for-pwa.js","mainthread-work-breakdown.js","manual","metrics","metrics.js","mixed-content.js","multi-check-audit.js","network-requests.js","offline-start-url.js","predictive-perf.js","redirects-http.js","redirects.js","screenshot-thumbnails.js","seo","service-worker.js","splash-screen.js","themed-omnibox.js","time-to-first-byte.js","user-timings.js","uses-rel-preconnect.js","uses-rel-preload.js","viewport.js","violation-audit.js","without-javascript.js","works-offline.js"],
+...["appcache-manifest.js","doctype.js","dom-size.js","external-anchors-use-rel-noopener.js","geolocation-on-start.js","js-libraries.js","no-document-write.js","no-vulnerable-libraries.js","notification-on-start.js","password-inputs-can-be-pasted-into.js","uses-http2.js","uses-passive-event-listeners.js"].map(f=>`dobetterweb/${f}`),
+...["estimated-input-latency.js","first-contentful-paint.js","first-cpu-idle.js","first-meaningful-paint.js","interactive.js","speed-index.js"].map(f=>`metrics/${f}`),
+...["canonical.js","font-size.js","hreflang.js","http-status-code.js","is-crawlable.js","link-text.js","manual","meta-description.js","plugins.js","robots-txt.js"].map(f=>`seo/${f}`),
+...["mobile-friendly.js","structured-data.js"].map(f=>`seo/manual/${f}`),
+...["aria-allowed-attr.js","aria-required-attr.js","aria-required-children.js","aria-required-parent.js","aria-roles.js","aria-valid-attr-value.js","aria-valid-attr.js","audio-caption.js","axe-audit.js","button-name.js","bypass.js","color-contrast.js","definition-list.js","dlitem.js","document-title.js","duplicate-id.js","frame-title.js","html-has-lang.js","html-lang-valid.js","image-alt.js","input-image-alt.js","label.js","layout-table.js","link-name.js","list.js","listitem.js","manual","meta-refresh.js","meta-viewport.js","object-alt.js","tabindex.js","td-headers-attr.js","th-has-data-cells.js","valid-lang.js","video-caption.js","video-description.js"].
+map(f=>`accessibility/${f}`),
+...["accesskeys.js","custom-controls-labels.js","custom-controls-roles.js","focus-traps.js","focusable-controls.js","heading-levels.js","interactive-element-affordance.js","logical-tab-order.js","managed-focus.js","offscreen-content-hidden.js","use-landmarks.js","visual-order-follows-dom.js"].
+map(f=>`accessibility/manual/${f}`),
+...["byte-efficiency-audit.js","efficient-animated-content.js","offscreen-images.js","render-blocking-resources.js","total-byte-weight.js","unminified-css.js","unminified-javascript.js","unused-css-rules.js","unused-javascript.js","uses-long-cache-ttl.js","uses-optimized-images.js","uses-responsive-images.js","uses-text-compression.js","uses-webp-images.js"].
+map(f=>`byte-efficiency/${f}`),
+...["manual-audit.js","pwa-cross-browser.js","pwa-each-page-has-url.js","pwa-page-transitions.js"].map(f=>`manual/${f}`)];
+
+return fileList.filter(f=>{
+return /\.js$/.test(f)&&!ignoredFiles.includes(f);
+}).sort();
+}
+
+
+
+
+
+static getGathererList(){
+const fileList=[
+...["accessibility.js","cache-contents.js","chrome-console-messages.js","css-usage.js","dobetterweb","gatherer.js","html-without-javascript.js","http-redirect.js","image-usage.js","js-usage.js","link-elements.js","manifest.js","mixed-content.js","offline.js","runtime-exceptions.js","scripts.js","seo","service-worker.js","start-url.js","theme-color.js","viewport-dimensions.js","viewport.js"],
+...["canonical.js","crawlable-links.js","embedded-content.js","font-size.js","hreflang.js","meta-description.js","meta-robots.js","robots-txt.js"].map(f=>`seo/${f}`),
+...["anchors-with-no-rel-noopener.js","appcache.js","doctype.js","domstats.js","js-libraries.js","optimized-images.js","password-inputs-with-prevented-paste.js","response-compression.js","tags-blocking-first-paint.js"].
+map(f=>`dobetterweb/${f}`)];
+
+return fileList.filter(f=>/\.js$/.test(f)&&f!=='gatherer.js').sort();
+}
+
+
+
+
+
+
+static _getArtifactsPath(settings){
+const{auditMode,gatherMode}=settings;
+
+
+if(typeof auditMode==='string')return path.resolve(process.cwd(),auditMode);
+if(typeof gatherMode==='string')return path.resolve(process.cwd(),gatherMode);
+
+return path.join(process.cwd(),'latest-run');
+}}
+
+
+module.exports=Runner;
+
+}).call(this,require('_process'));
+},{"../package.json":160,"./audits/audit":3,"./gather/driver.js":42,"./gather/gather-runner":43,"./lib/asset-saver":47,"./lib/i18n/i18n.js":59,"./lib/lh-error.js":63,"./lib/sentry":69,"./lib/url-shim":"url","./report/report-generator":75,"./scoring":77,"_process":130,"lighthouse-logger":113,"lodash.isequal":114,"path":128}],77:[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audits/audit');
+
+
+
+
+
+
+const clampTo2Decimals=val=>Math.round(val*100)/100;
+
+class ReportScoring{
+
+
+
+
+
+static arithmeticMean(items){
+
+items=items.filter(item=>item.weight>0);
+
+if(items.some(item=>item.score===null))return null;
+
+const results=items.reduce(
+(result,item)=>{
+const score=item.score;
+const weight=item.weight;
+
+return{
+weight:result.weight+weight,
+sum:result.sum+score*weight};
+
+},
+{weight:0,sum:0});
+
+
+return clampTo2Decimals(results.sum/results.weight||0);
+}
+
+
+
+
+
+
+
+static scoreAllCategories(configCategories,resultsByAuditId){
+
+const scoredCategories={};
+
+for(const[categoryId,configCategory]of Object.entries(configCategories)){
+
+const auditRefs=configCategory.auditRefs.map(configMember=>{
+const member={...configMember};
+
+
+
+
+
+const result=resultsByAuditId[member.id];
+if(result.scoreDisplayMode===Audit.SCORING_MODES.NOT_APPLICABLE||
+result.scoreDisplayMode===Audit.SCORING_MODES.INFORMATIVE||
+result.scoreDisplayMode===Audit.SCORING_MODES.MANUAL){
+member.weight=0;
+}
+
+return member;
+});
+
+const scores=auditRefs.map(auditRef=>({
+score:resultsByAuditId[auditRef.id].score,
+weight:auditRef.weight}));
+
+const score=ReportScoring.arithmeticMean(scores);
+
+scoredCategories[categoryId]={
+...configCategory,
+auditRefs,
+id:categoryId,
+score};
+
+}
+
+return scoredCategories;
+}}
+
+
+module.exports=ReportScoring;
+
+},{"./audits/audit":3}],78:[function(require,module,exports){
+(function(global){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+function compare(a,b){
+if(a===b){
+return 0;
+}
+
+var x=a.length;
+var y=b.length;
+
+for(var i=0,len=Math.min(x,y);i<len;++i){
+if(a[i]!==b[i]){
+x=a[i];
+y=b[i];
+break;
+}
+}
+
+if(x<y){
+return-1;
+}
+if(y<x){
+return 1;
+}
+return 0;
+}
+function isBuffer(b){
+if(global.Buffer&&typeof global.Buffer.isBuffer==='function'){
+return global.Buffer.isBuffer(b);
+}
+return!!(b!=null&&b._isBuffer);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var util=require('util/');
+var hasOwn=Object.prototype.hasOwnProperty;
+var pSlice=Array.prototype.slice;
+var functionsHaveNames=function(){
+return function foo(){}.name==='foo';
+}();
+function pToString(obj){
+return Object.prototype.toString.call(obj);
+}
+function isView(arrbuf){
+if(isBuffer(arrbuf)){
+return false;
+}
+if(typeof global.ArrayBuffer!=='function'){
+return false;
+}
+if(typeof ArrayBuffer.isView==='function'){
+return ArrayBuffer.isView(arrbuf);
+}
+if(!arrbuf){
+return false;
+}
+if(arrbuf instanceof DataView){
+return true;
+}
+if(arrbuf.buffer&&arrbuf.buffer instanceof ArrayBuffer){
+return true;
+}
+return false;
+}
+
+
+
+
+var assert=module.exports=ok;
+
+
+
+
+
+
+var regex=/\s*function\s+([^\(\s]*)\s*/;
+
+function getName(func){
+if(!util.isFunction(func)){
+return;
+}
+if(functionsHaveNames){
+return func.name;
+}
+var str=func.toString();
+var match=str.match(regex);
+return match&&match[1];
+}
+assert.AssertionError=function AssertionError(options){
+this.name='AssertionError';
+this.actual=options.actual;
+this.expected=options.expected;
+this.operator=options.operator;
+if(options.message){
+this.message=options.message;
+this.generatedMessage=false;
+}else{
+this.message=getMessage(this);
+this.generatedMessage=true;
+}
+var stackStartFunction=options.stackStartFunction||fail;
+if(Error.captureStackTrace){
+Error.captureStackTrace(this,stackStartFunction);
+}else{
+
+var err=new Error();
+if(err.stack){
+var out=err.stack;
+
+
+var fn_name=getName(stackStartFunction);
+var idx=out.indexOf('\n'+fn_name);
+if(idx>=0){
+
+
+var next_line=out.indexOf('\n',idx+1);
+out=out.substring(next_line+1);
+}
+
+this.stack=out;
+}
+}
+};
+
+
+util.inherits(assert.AssertionError,Error);
+
+function truncate(s,n){
+if(typeof s==='string'){
+return s.length<n?s:s.slice(0,n);
+}else{
+return s;
+}
+}
+function inspect(something){
+if(functionsHaveNames||!util.isFunction(something)){
+return util.inspect(something);
+}
+var rawname=getName(something);
+var name=rawname?': '+rawname:'';
+return'[Function'+name+']';
+}
+function getMessage(self){
+return truncate(inspect(self.actual),128)+' '+
+self.operator+' '+
+truncate(inspect(self.expected),128);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+function fail(actual,expected,message,operator,stackStartFunction){
+throw new assert.AssertionError({
+message:message,
+actual:actual,
+expected:expected,
+operator:operator,
+stackStartFunction:stackStartFunction});
+
+}
+
+
+assert.fail=fail;
+
+
+
+
+
+
+
+
+function ok(value,message){
+if(!value)fail(value,true,message,'==',assert.ok);
+}
+assert.ok=ok;
+
+
+
+
+
+assert.equal=function equal(actual,expected,message){
+if(actual!=expected)fail(actual,expected,message,'==',assert.equal);
+};
+
+
+
+
+assert.notEqual=function notEqual(actual,expected,message){
+if(actual==expected){
+fail(actual,expected,message,'!=',assert.notEqual);
+}
+};
+
+
+
+
+assert.deepEqual=function deepEqual(actual,expected,message){
+if(!_deepEqual(actual,expected,false)){
+fail(actual,expected,message,'deepEqual',assert.deepEqual);
+}
+};
+
+assert.deepStrictEqual=function deepStrictEqual(actual,expected,message){
+if(!_deepEqual(actual,expected,true)){
+fail(actual,expected,message,'deepStrictEqual',assert.deepStrictEqual);
+}
+};
+
+function _deepEqual(actual,expected,strict,memos){
+
+if(actual===expected){
+return true;
+}else if(isBuffer(actual)&&isBuffer(expected)){
+return compare(actual,expected)===0;
+
+
+
+}else if(util.isDate(actual)&&util.isDate(expected)){
+return actual.getTime()===expected.getTime();
+
+
+
+
+}else if(util.isRegExp(actual)&&util.isRegExp(expected)){
+return actual.source===expected.source&&
+actual.global===expected.global&&
+actual.multiline===expected.multiline&&
+actual.lastIndex===expected.lastIndex&&
+actual.ignoreCase===expected.ignoreCase;
+
+
+
+}else if((actual===null||typeof actual!=='object')&&(
+expected===null||typeof expected!=='object')){
+return strict?actual===expected:actual==expected;
+
+
+
+
+
+
+
+}else if(isView(actual)&&isView(expected)&&
+pToString(actual)===pToString(expected)&&
+!(actual instanceof Float32Array||
+actual instanceof Float64Array)){
+return compare(new Uint8Array(actual.buffer),
+new Uint8Array(expected.buffer))===0;
+
+
+
+
+
+
+
+}else if(isBuffer(actual)!==isBuffer(expected)){
+return false;
+}else{
+memos=memos||{actual:[],expected:[]};
+
+var actualIndex=memos.actual.indexOf(actual);
+if(actualIndex!==-1){
+if(actualIndex===memos.expected.indexOf(expected)){
+return true;
+}
+}
+
+memos.actual.push(actual);
+memos.expected.push(expected);
+
+return objEquiv(actual,expected,strict,memos);
+}
+}
+
+function isArguments(object){
+return Object.prototype.toString.call(object)=='[object Arguments]';
+}
+
+function objEquiv(a,b,strict,actualVisitedObjects){
+if(a===null||a===undefined||b===null||b===undefined)
+return false;
+
+if(util.isPrimitive(a)||util.isPrimitive(b))
+return a===b;
+if(strict&&Object.getPrototypeOf(a)!==Object.getPrototypeOf(b))
+return false;
+var aIsArgs=isArguments(a);
+var bIsArgs=isArguments(b);
+if(aIsArgs&&!bIsArgs||!aIsArgs&&bIsArgs)
+return false;
+if(aIsArgs){
+a=pSlice.call(a);
+b=pSlice.call(b);
+return _deepEqual(a,b,strict);
+}
+var ka=objectKeys(a);
+var kb=objectKeys(b);
+var key,i;
+
+
+if(ka.length!==kb.length)
+return false;
+
+ka.sort();
+kb.sort();
+
+for(i=ka.length-1;i>=0;i--){
+if(ka[i]!==kb[i])
+return false;
+}
+
+
+for(i=ka.length-1;i>=0;i--){
+key=ka[i];
+if(!_deepEqual(a[key],b[key],strict,actualVisitedObjects))
+return false;
+}
+return true;
+}
+
+
+
+
+assert.notDeepEqual=function notDeepEqual(actual,expected,message){
+if(_deepEqual(actual,expected,false)){
+fail(actual,expected,message,'notDeepEqual',assert.notDeepEqual);
+}
+};
+
+assert.notDeepStrictEqual=notDeepStrictEqual;
+function notDeepStrictEqual(actual,expected,message){
+if(_deepEqual(actual,expected,true)){
+fail(actual,expected,message,'notDeepStrictEqual',notDeepStrictEqual);
+}
+}
+
+
+
+
+
+assert.strictEqual=function strictEqual(actual,expected,message){
+if(actual!==expected){
+fail(actual,expected,message,'===',assert.strictEqual);
+}
+};
+
+
+
+
+assert.notStrictEqual=function notStrictEqual(actual,expected,message){
+if(actual===expected){
+fail(actual,expected,message,'!==',assert.notStrictEqual);
+}
+};
+
+function expectedException(actual,expected){
+if(!actual||!expected){
+return false;
+}
+
+if(Object.prototype.toString.call(expected)=='[object RegExp]'){
+return expected.test(actual);
+}
+
+try{
+if(actual instanceof expected){
+return true;
+}
+}catch(e){
+
+}
+
+if(Error.isPrototypeOf(expected)){
+return false;
+}
+
+return expected.call({},actual)===true;
+}
+
+function _tryBlock(block){
+var error;
+try{
+block();
+}catch(e){
+error=e;
+}
+return error;
+}
+
+function _throws(shouldThrow,block,expected,message){
+var actual;
+
+if(typeof block!=='function'){
+throw new TypeError('"block" argument must be a function');
+}
+
+if(typeof expected==='string'){
+message=expected;
+expected=null;
+}
+
+actual=_tryBlock(block);
+
+message=(expected&&expected.name?' ('+expected.name+').':'.')+(
+message?' '+message:'.');
+
+if(shouldThrow&&!actual){
+fail(actual,expected,'Missing expected exception'+message);
+}
+
+var userProvidedMessage=typeof message==='string';
+var isUnwantedException=!shouldThrow&&util.isError(actual);
+var isUnexpectedException=!shouldThrow&&actual&&!expected;
+
+if(isUnwantedException&&
+userProvidedMessage&&
+expectedException(actual,expected)||
+isUnexpectedException){
+fail(actual,expected,'Got unwanted exception'+message);
+}
+
+if(shouldThrow&&actual&&expected&&
+!expectedException(actual,expected)||!shouldThrow&&actual){
+throw actual;
+}
+}
+
+
+
+
+assert.throws=function(block,error,message){
+_throws(true,block,error,message);
+};
+
+
+assert.doesNotThrow=function(block,error,message){
+_throws(false,block,error,message);
+};
+
+assert.ifError=function(err){if(err)throw err;};
+
+var objectKeys=Object.keys||function(obj){
+var keys=[];
+for(var key in obj){
+if(hasOwn.call(obj,key))keys.push(key);
+}
+return keys;
+};
+
+}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{"util/":81}],79:[function(require,module,exports){
+if(typeof Object.create==='function'){
+
+module.exports=function inherits(ctor,superCtor){
+ctor.super_=superCtor;
+ctor.prototype=Object.create(superCtor.prototype,{
+constructor:{
+value:ctor,
+enumerable:false,
+writable:true,
+configurable:true}});
+
+
+};
+}else{
+
+module.exports=function inherits(ctor,superCtor){
+ctor.super_=superCtor;
+var TempCtor=function(){};
+TempCtor.prototype=superCtor.prototype;
+ctor.prototype=new TempCtor();
+ctor.prototype.constructor=ctor;
+};
+}
+
+},{}],80:[function(require,module,exports){
+module.exports=function isBuffer(arg){
+return arg&&typeof arg==='object'&&
+typeof arg.copy==='function'&&
+typeof arg.fill==='function'&&
+typeof arg.readUInt8==='function';
+};
+},{}],81:[function(require,module,exports){
+(function(process,global){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var formatRegExp=/%[sdj%]/g;
+exports.format=function(f){
+if(!isString(f)){
+var objects=[];
+for(var i=0;i<arguments.length;i++){
+objects.push(inspect(arguments[i]));
+}
+return objects.join(' ');
+}
+
+var i=1;
+var args=arguments;
+var len=args.length;
+var str=String(f).replace(formatRegExp,function(x){
+if(x==='%%')return'%';
+if(i>=len)return x;
+switch(x){
+case'%s':return String(args[i++]);
+case'%d':return Number(args[i++]);
+case'%j':
+try{
+return JSON.stringify(args[i++]);
+}catch(_){
+return'[Circular]';
+}
+default:
+return x;}
+
+});
+for(var x=args[i];i<len;x=args[++i]){
+if(isNull(x)||!isObject(x)){
+str+=' '+x;
+}else{
+str+=' '+inspect(x);
+}
+}
+return str;
+};
+
+
+
+
+
+exports.deprecate=function(fn,msg){
+
+if(isUndefined(global.process)){
+return function(){
+return exports.deprecate(fn,msg).apply(this,arguments);
+};
+}
+
+if(process.noDeprecation===true){
+return fn;
+}
+
+var warned=false;
+function deprecated(){
+if(!warned){
+if(process.throwDeprecation){
+throw new Error(msg);
+}else if(process.traceDeprecation){
+console.trace(msg);
+}else{
+console.error(msg);
+}
+warned=true;
+}
+return fn.apply(this,arguments);
+}
+
+return deprecated;
+};
+
+
+var debugs={};
+var debugEnviron;
+exports.debuglog=function(set){
+if(isUndefined(debugEnviron))
+debugEnviron=process.env.NODE_DEBUG||'';
+set=set.toUpperCase();
+if(!debugs[set]){
+if(new RegExp('\\b'+set+'\\b','i').test(debugEnviron)){
+var pid=process.pid;
+debugs[set]=function(){
+var msg=exports.format.apply(exports,arguments);
+console.error('%s %d: %s',set,pid,msg);
+};
+}else{
+debugs[set]=function(){};
+}
+}
+return debugs[set];
+};
+
+
+
+
+
+
+
+
+
+
+function inspect(obj,opts){
+
+var ctx={
+seen:[],
+stylize:stylizeNoColor};
+
+
+if(arguments.length>=3)ctx.depth=arguments[2];
+if(arguments.length>=4)ctx.colors=arguments[3];
+if(isBoolean(opts)){
+
+ctx.showHidden=opts;
+}else if(opts){
+
+exports._extend(ctx,opts);
+}
+
+if(isUndefined(ctx.showHidden))ctx.showHidden=false;
+if(isUndefined(ctx.depth))ctx.depth=2;
+if(isUndefined(ctx.colors))ctx.colors=false;
+if(isUndefined(ctx.customInspect))ctx.customInspect=true;
+if(ctx.colors)ctx.stylize=stylizeWithColor;
+return formatValue(ctx,obj,ctx.depth);
+}
+exports.inspect=inspect;
+
+
+
+inspect.colors={
+'bold':[1,22],
+'italic':[3,23],
+'underline':[4,24],
+'inverse':[7,27],
+'white':[37,39],
+'grey':[90,39],
+'black':[30,39],
+'blue':[34,39],
+'cyan':[36,39],
+'green':[32,39],
+'magenta':[35,39],
+'red':[31,39],
+'yellow':[33,39]};
+
+
+
+inspect.styles={
+'special':'cyan',
+'number':'yellow',
+'boolean':'yellow',
+'undefined':'grey',
+'null':'bold',
+'string':'green',
+'date':'magenta',
+
+'regexp':'red'};
+
+
+
+function stylizeWithColor(str,styleType){
+var style=inspect.styles[styleType];
+
+if(style){
+return'\u001b['+inspect.colors[style][0]+'m'+str+
+'\u001b['+inspect.colors[style][1]+'m';
+}else{
+return str;
+}
+}
+
+
+function stylizeNoColor(str,styleType){
+return str;
+}
+
+
+function arrayToHash(array){
+var hash={};
+
+array.forEach(function(val,idx){
+hash[val]=true;
+});
+
+return hash;
+}
+
+
+function formatValue(ctx,value,recurseTimes){
+
+
+if(ctx.customInspect&&
+value&&
+isFunction(value.inspect)&&
+
+value.inspect!==exports.inspect&&
+
+!(value.constructor&&value.constructor.prototype===value)){
+var ret=value.inspect(recurseTimes,ctx);
+if(!isString(ret)){
+ret=formatValue(ctx,ret,recurseTimes);
+}
+return ret;
+}
+
+
+var primitive=formatPrimitive(ctx,value);
+if(primitive){
+return primitive;
+}
+
+
+var keys=Object.keys(value);
+var visibleKeys=arrayToHash(keys);
+
+if(ctx.showHidden){
+keys=Object.getOwnPropertyNames(value);
+}
+
+
+
+if(isError(value)&&(
+keys.indexOf('message')>=0||keys.indexOf('description')>=0)){
+return formatError(value);
+}
+
+
+if(keys.length===0){
+if(isFunction(value)){
+var name=value.name?': '+value.name:'';
+return ctx.stylize('[Function'+name+']','special');
+}
+if(isRegExp(value)){
+return ctx.stylize(RegExp.prototype.toString.call(value),'regexp');
+}
+if(isDate(value)){
+return ctx.stylize(Date.prototype.toString.call(value),'date');
+}
+if(isError(value)){
+return formatError(value);
+}
+}
+
+var base='',array=false,braces=['{','}'];
+
+
+if(isArray(value)){
+array=true;
+braces=['[',']'];
+}
+
+
+if(isFunction(value)){
+var n=value.name?': '+value.name:'';
+base=' [Function'+n+']';
+}
+
+
+if(isRegExp(value)){
+base=' '+RegExp.prototype.toString.call(value);
+}
+
+
+if(isDate(value)){
+base=' '+Date.prototype.toUTCString.call(value);
+}
+
+
+if(isError(value)){
+base=' '+formatError(value);
+}
+
+if(keys.length===0&&(!array||value.length==0)){
+return braces[0]+base+braces[1];
+}
+
+if(recurseTimes<0){
+if(isRegExp(value)){
+return ctx.stylize(RegExp.prototype.toString.call(value),'regexp');
+}else{
+return ctx.stylize('[Object]','special');
+}
+}
+
+ctx.seen.push(value);
+
+var output;
+if(array){
+output=formatArray(ctx,value,recurseTimes,visibleKeys,keys);
+}else{
+output=keys.map(function(key){
+return formatProperty(ctx,value,recurseTimes,visibleKeys,key,array);
+});
+}
+
+ctx.seen.pop();
+
+return reduceToSingleString(output,base,braces);
+}
+
+
+function formatPrimitive(ctx,value){
+if(isUndefined(value))
+return ctx.stylize('undefined','undefined');
+if(isString(value)){
+var simple='\''+JSON.stringify(value).replace(/^"|"$/g,'').
+replace(/'/g,"\\'").
+replace(/\\"/g,'"')+'\'';
+return ctx.stylize(simple,'string');
+}
+if(isNumber(value))
+return ctx.stylize(''+value,'number');
+if(isBoolean(value))
+return ctx.stylize(''+value,'boolean');
+
+if(isNull(value))
+return ctx.stylize('null','null');
+}
+
+
+function formatError(value){
+return'['+Error.prototype.toString.call(value)+']';
+}
+
+
+function formatArray(ctx,value,recurseTimes,visibleKeys,keys){
+var output=[];
+for(var i=0,l=value.length;i<l;++i){
+if(hasOwnProperty(value,String(i))){
+output.push(formatProperty(ctx,value,recurseTimes,visibleKeys,
+String(i),true));
+}else{
+output.push('');
+}
+}
+keys.forEach(function(key){
+if(!key.match(/^\d+$/)){
+output.push(formatProperty(ctx,value,recurseTimes,visibleKeys,
+key,true));
+}
+});
+return output;
+}
+
+
+function formatProperty(ctx,value,recurseTimes,visibleKeys,key,array){
+var name,str,desc;
+desc=Object.getOwnPropertyDescriptor(value,key)||{value:value[key]};
+if(desc.get){
+if(desc.set){
+str=ctx.stylize('[Getter/Setter]','special');
+}else{
+str=ctx.stylize('[Getter]','special');
+}
+}else{
+if(desc.set){
+str=ctx.stylize('[Setter]','special');
+}
+}
+if(!hasOwnProperty(visibleKeys,key)){
+name='['+key+']';
+}
+if(!str){
+if(ctx.seen.indexOf(desc.value)<0){
+if(isNull(recurseTimes)){
+str=formatValue(ctx,desc.value,null);
+}else{
+str=formatValue(ctx,desc.value,recurseTimes-1);
+}
+if(str.indexOf('\n')>-1){
+if(array){
+str=str.split('\n').map(function(line){
+return' '+line;
+}).join('\n').substr(2);
+}else{
+str='\n'+str.split('\n').map(function(line){
+return' '+line;
+}).join('\n');
+}
+}
+}else{
+str=ctx.stylize('[Circular]','special');
+}
+}
+if(isUndefined(name)){
+if(array&&key.match(/^\d+$/)){
+return str;
+}
+name=JSON.stringify(''+key);
+if(name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)){
+name=name.substr(1,name.length-2);
+name=ctx.stylize(name,'name');
+}else{
+name=name.replace(/'/g,"\\'").
+replace(/\\"/g,'"').
+replace(/(^"|"$)/g,"'");
+name=ctx.stylize(name,'string');
+}
+}
+
+return name+': '+str;
+}
+
+
+function reduceToSingleString(output,base,braces){
+var numLinesEst=0;
+var length=output.reduce(function(prev,cur){
+numLinesEst++;
+if(cur.indexOf('\n')>=0)numLinesEst++;
+return prev+cur.replace(/\u001b\[\d\d?m/g,'').length+1;
+},0);
+
+if(length>60){
+return braces[0]+(
+base===''?'':base+'\n ')+
+' '+
+output.join(',\n ')+
+' '+
+braces[1];
+}
+
+return braces[0]+base+' '+output.join(', ')+' '+braces[1];
+}
+
+
+
+
+function isArray(ar){
+return Array.isArray(ar);
+}
+exports.isArray=isArray;
+
+function isBoolean(arg){
+return typeof arg==='boolean';
+}
+exports.isBoolean=isBoolean;
+
+function isNull(arg){
+return arg===null;
+}
+exports.isNull=isNull;
+
+function isNullOrUndefined(arg){
+return arg==null;
+}
+exports.isNullOrUndefined=isNullOrUndefined;
+
+function isNumber(arg){
+return typeof arg==='number';
+}
+exports.isNumber=isNumber;
+
+function isString(arg){
+return typeof arg==='string';
+}
+exports.isString=isString;
+
+function isSymbol(arg){
+return typeof arg==='symbol';
+}
+exports.isSymbol=isSymbol;
+
+function isUndefined(arg){
+return arg===void 0;
+}
+exports.isUndefined=isUndefined;
+
+function isRegExp(re){
+return isObject(re)&&objectToString(re)==='[object RegExp]';
+}
+exports.isRegExp=isRegExp;
+
+function isObject(arg){
+return typeof arg==='object'&&arg!==null;
+}
+exports.isObject=isObject;
+
+function isDate(d){
+return isObject(d)&&objectToString(d)==='[object Date]';
+}
+exports.isDate=isDate;
+
+function isError(e){
+return isObject(e)&&(
+objectToString(e)==='[object Error]'||e instanceof Error);
+}
+exports.isError=isError;
+
+function isFunction(arg){
+return typeof arg==='function';
+}
+exports.isFunction=isFunction;
+
+function isPrimitive(arg){
+return arg===null||
+typeof arg==='boolean'||
+typeof arg==='number'||
+typeof arg==='string'||
+typeof arg==='symbol'||
+typeof arg==='undefined';
+}
+exports.isPrimitive=isPrimitive;
+
+exports.isBuffer=require('./support/isBuffer');
+
+function objectToString(o){
+return Object.prototype.toString.call(o);
+}
+
+
+function pad(n){
+return n<10?'0'+n.toString(10):n.toString(10);
+}
+
+
+var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep',
+'Oct','Nov','Dec'];
+
+
+function timestamp(){
+var d=new Date();
+var time=[pad(d.getHours()),
+pad(d.getMinutes()),
+pad(d.getSeconds())].join(':');
+return[d.getDate(),months[d.getMonth()],time].join(' ');
+}
+
+
+
+exports.log=function(){
+console.log('%s - %s',timestamp(),exports.format.apply(exports,arguments));
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+exports.inherits=require('inherits');
+
+exports._extend=function(origin,add){
+
+if(!add||!isObject(add))return origin;
+
+var keys=Object.keys(add);
+var i=keys.length;
+while(i--){
+origin[keys[i]]=add[keys[i]];
+}
+return origin;
+};
+
+function hasOwnProperty(obj,prop){
+return Object.prototype.hasOwnProperty.call(obj,prop);
+}
+
+}).call(this,require('_process'),typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{"./support/isBuffer":80,"_process":130,"inherits":79}],82:[function(require,module,exports){
+
+
+var langs=[
+'aa',
+'ab',
+'ae',
+'af',
+'ak',
+'am',
+'an',
+'ar',
+'as',
+'av',
+'ay',
+'az',
+'ba',
+'be',
+'bg',
+'bh',
+'bi',
+'bm',
+'bn',
+'bo',
+'br',
+'bs',
+'ca',
+'ce',
+'ch',
+'co',
+'cr',
+'cs',
+'cu',
+'cv',
+'cy',
+'da',
+'de',
+'dv',
+'dz',
+'ee',
+'el',
+'en',
+'eo',
+'es',
+'et',
+'eu',
+'fa',
+'ff',
+'fi',
+'fj',
+'fo',
+'fr',
+'fy',
+'ga',
+'gd',
+'gl',
+'gn',
+'gu',
+'gv',
+'ha',
+'he',
+'hi',
+'ho',
+'hr',
+'ht',
+'hu',
+'hy',
+'hz',
+'ia',
+'id',
+'ie',
+'ig',
+'ii',
+'ik',
+'in',
+'io',
+'is',
+'it',
+'iu',
+'iw',
+'ja',
+'ji',
+'jv',
+'jw',
+'ka',
+'kg',
+'ki',
+'kj',
+'kk',
+'kl',
+'km',
+'kn',
+'ko',
+'kr',
+'ks',
+'ku',
+'kv',
+'kw',
+'ky',
+'la',
+'lb',
+'lg',
+'li',
+'ln',
+'lo',
+'lt',
+'lu',
+'lv',
+'mg',
+'mh',
+'mi',
+'mk',
+'ml',
+'mn',
+'mo',
+'mr',
+'ms',
+'mt',
+'my',
+'na',
+'nb',
+'nd',
+'ne',
+'ng',
+'nl',
+'nn',
+'no',
+'nr',
+'nv',
+'ny',
+'oc',
+'oj',
+'om',
+'or',
+'os',
+'pa',
+'pi',
+'pl',
+'ps',
+'pt',
+'qu',
+'rm',
+'rn',
+'ro',
+'ru',
+'rw',
+'sa',
+'sc',
+'sd',
+'se',
+'sg',
+'sh',
+'si',
+'sk',
+'sl',
+'sm',
+'sn',
+'so',
+'sq',
+'sr',
+'ss',
+'st',
+'su',
+'sv',
+'sw',
+'ta',
+'te',
+'tg',
+'th',
+'ti',
+'tk',
+'tl',
+'tn',
+'to',
+'tr',
+'ts',
+'tt',
+'tw',
+'ty',
+'ug',
+'uk',
+'ur',
+'uz',
+'ve',
+'vi',
+'vo',
+'wa',
+'wo',
+'xh',
+'yi',
+'yo',
+'za',
+'zh',
+'zu',
+'aaa',
+'aab',
+'aac',
+'aad',
+'aae',
+'aaf',
+'aag',
+'aah',
+'aai',
+'aak',
+'aal',
+'aam',
+'aan',
+'aao',
+'aap',
+'aaq',
+'aas',
+'aat',
+'aau',
+'aav',
+'aaw',
+'aax',
+'aaz',
+'aba',
+'abb',
+'abc',
+'abd',
+'abe',
+'abf',
+'abg',
+'abh',
+'abi',
+'abj',
+'abl',
+'abm',
+'abn',
+'abo',
+'abp',
+'abq',
+'abr',
+'abs',
+'abt',
+'abu',
+'abv',
+'abw',
+'abx',
+'aby',
+'abz',
+'aca',
+'acb',
+'acd',
+'ace',
+'acf',
+'ach',
+'aci',
+'ack',
+'acl',
+'acm',
+'acn',
+'acp',
+'acq',
+'acr',
+'acs',
+'act',
+'acu',
+'acv',
+'acw',
+'acx',
+'acy',
+'acz',
+'ada',
+'adb',
+'add',
+'ade',
+'adf',
+'adg',
+'adh',
+'adi',
+'adj',
+'adl',
+'adn',
+'ado',
+'adp',
+'adq',
+'adr',
+'ads',
+'adt',
+'adu',
+'adw',
+'adx',
+'ady',
+'adz',
+'aea',
+'aeb',
+'aec',
+'aed',
+'aee',
+'aek',
+'ael',
+'aem',
+'aen',
+'aeq',
+'aer',
+'aes',
+'aeu',
+'aew',
+'aey',
+'aez',
+'afa',
+'afb',
+'afd',
+'afe',
+'afg',
+'afh',
+'afi',
+'afk',
+'afn',
+'afo',
+'afp',
+'afs',
+'aft',
+'afu',
+'afz',
+'aga',
+'agb',
+'agc',
+'agd',
+'age',
+'agf',
+'agg',
+'agh',
+'agi',
+'agj',
+'agk',
+'agl',
+'agm',
+'agn',
+'ago',
+'agp',
+'agq',
+'agr',
+'ags',
+'agt',
+'agu',
+'agv',
+'agw',
+'agx',
+'agy',
+'agz',
+'aha',
+'ahb',
+'ahg',
+'ahh',
+'ahi',
+'ahk',
+'ahl',
+'ahm',
+'ahn',
+'aho',
+'ahp',
+'ahr',
+'ahs',
+'aht',
+'aia',
+'aib',
+'aic',
+'aid',
+'aie',
+'aif',
+'aig',
+'aih',
+'aii',
+'aij',
+'aik',
+'ail',
+'aim',
+'ain',
+'aio',
+'aip',
+'aiq',
+'air',
+'ais',
+'ait',
+'aiw',
+'aix',
+'aiy',
+'aja',
+'ajg',
+'aji',
+'ajn',
+'ajp',
+'ajt',
+'aju',
+'ajw',
+'ajz',
+'akb',
+'akc',
+'akd',
+'ake',
+'akf',
+'akg',
+'akh',
+'aki',
+'akj',
+'akk',
+'akl',
+'akm',
+'ako',
+'akp',
+'akq',
+'akr',
+'aks',
+'akt',
+'aku',
+'akv',
+'akw',
+'akx',
+'aky',
+'akz',
+'ala',
+'alc',
+'ald',
+'ale',
+'alf',
+'alg',
+'alh',
+'ali',
+'alj',
+'alk',
+'all',
+'alm',
+'aln',
+'alo',
+'alp',
+'alq',
+'alr',
+'als',
+'alt',
+'alu',
+'alv',
+'alw',
+'alx',
+'aly',
+'alz',
+'ama',
+'amb',
+'amc',
+'ame',
+'amf',
+'amg',
+'ami',
+'amj',
+'amk',
+'aml',
+'amm',
+'amn',
+'amo',
+'amp',
+'amq',
+'amr',
+'ams',
+'amt',
+'amu',
+'amv',
+'amw',
+'amx',
+'amy',
+'amz',
+'ana',
+'anb',
+'anc',
+'and',
+'ane',
+'anf',
+'ang',
+'anh',
+'ani',
+'anj',
+'ank',
+'anl',
+'anm',
+'ann',
+'ano',
+'anp',
+'anq',
+'anr',
+'ans',
+'ant',
+'anu',
+'anv',
+'anw',
+'anx',
+'any',
+'anz',
+'aoa',
+'aob',
+'aoc',
+'aod',
+'aoe',
+'aof',
+'aog',
+'aoh',
+'aoi',
+'aoj',
+'aok',
+'aol',
+'aom',
+'aon',
+'aor',
+'aos',
+'aot',
+'aou',
+'aox',
+'aoz',
+'apa',
+'apb',
+'apc',
+'apd',
+'ape',
+'apf',
+'apg',
+'aph',
+'api',
+'apj',
+'apk',
+'apl',
+'apm',
+'apn',
+'apo',
+'app',
+'apq',
+'apr',
+'aps',
+'apt',
+'apu',
+'apv',
+'apw',
+'apx',
+'apy',
+'apz',
+'aqa',
+'aqc',
+'aqd',
+'aqg',
+'aql',
+'aqm',
+'aqn',
+'aqp',
+'aqr',
+'aqt',
+'aqz',
+'arb',
+'arc',
+'ard',
+'are',
+'arh',
+'ari',
+'arj',
+'ark',
+'arl',
+'arn',
+'aro',
+'arp',
+'arq',
+'arr',
+'ars',
+'art',
+'aru',
+'arv',
+'arw',
+'arx',
+'ary',
+'arz',
+'asa',
+'asb',
+'asc',
+'asd',
+'ase',
+'asf',
+'asg',
+'ash',
+'asi',
+'asj',
+'ask',
+'asl',
+'asn',
+'aso',
+'asp',
+'asq',
+'asr',
+'ass',
+'ast',
+'asu',
+'asv',
+'asw',
+'asx',
+'asy',
+'asz',
+'ata',
+'atb',
+'atc',
+'atd',
+'ate',
+'atg',
+'ath',
+'ati',
+'atj',
+'atk',
+'atl',
+'atm',
+'atn',
+'ato',
+'atp',
+'atq',
+'atr',
+'ats',
+'att',
+'atu',
+'atv',
+'atw',
+'atx',
+'aty',
+'atz',
+'aua',
+'aub',
+'auc',
+'aud',
+'aue',
+'auf',
+'aug',
+'auh',
+'aui',
+'auj',
+'auk',
+'aul',
+'aum',
+'aun',
+'auo',
+'aup',
+'auq',
+'aur',
+'aus',
+'aut',
+'auu',
+'auw',
+'aux',
+'auy',
+'auz',
+'avb',
+'avd',
+'avi',
+'avk',
+'avl',
+'avm',
+'avn',
+'avo',
+'avs',
+'avt',
+'avu',
+'avv',
+'awa',
+'awb',
+'awc',
+'awd',
+'awe',
+'awg',
+'awh',
+'awi',
+'awk',
+'awm',
+'awn',
+'awo',
+'awr',
+'aws',
+'awt',
+'awu',
+'awv',
+'aww',
+'awx',
+'awy',
+'axb',
+'axe',
+'axg',
+'axk',
+'axl',
+'axm',
+'axx',
+'aya',
+'ayb',
+'ayc',
+'ayd',
+'aye',
+'ayg',
+'ayh',
+'ayi',
+'ayk',
+'ayl',
+'ayn',
+'ayo',
+'ayp',
+'ayq',
+'ayr',
+'ays',
+'ayt',
+'ayu',
+'ayx',
+'ayy',
+'ayz',
+'aza',
+'azb',
+'azc',
+'azd',
+'azg',
+'azj',
+'azm',
+'azn',
+'azo',
+'azt',
+'azz',
+'baa',
+'bab',
+'bac',
+'bad',
+'bae',
+'baf',
+'bag',
+'bah',
+'bai',
+'baj',
+'bal',
+'ban',
+'bao',
+'bap',
+'bar',
+'bas',
+'bat',
+'bau',
+'bav',
+'baw',
+'bax',
+'bay',
+'baz',
+'bba',
+'bbb',
+'bbc',
+'bbd',
+'bbe',
+'bbf',
+'bbg',
+'bbh',
+'bbi',
+'bbj',
+'bbk',
+'bbl',
+'bbm',
+'bbn',
+'bbo',
+'bbp',
+'bbq',
+'bbr',
+'bbs',
+'bbt',
+'bbu',
+'bbv',
+'bbw',
+'bbx',
+'bby',
+'bbz',
+'bca',
+'bcb',
+'bcc',
+'bcd',
+'bce',
+'bcf',
+'bcg',
+'bch',
+'bci',
+'bcj',
+'bck',
+'bcl',
+'bcm',
+'bcn',
+'bco',
+'bcp',
+'bcq',
+'bcr',
+'bcs',
+'bct',
+'bcu',
+'bcv',
+'bcw',
+'bcy',
+'bcz',
+'bda',
+'bdb',
+'bdc',
+'bdd',
+'bde',
+'bdf',
+'bdg',
+'bdh',
+'bdi',
+'bdj',
+'bdk',
+'bdl',
+'bdm',
+'bdn',
+'bdo',
+'bdp',
+'bdq',
+'bdr',
+'bds',
+'bdt',
+'bdu',
+'bdv',
+'bdw',
+'bdx',
+'bdy',
+'bdz',
+'bea',
+'beb',
+'bec',
+'bed',
+'bee',
+'bef',
+'beg',
+'beh',
+'bei',
+'bej',
+'bek',
+'bem',
+'beo',
+'bep',
+'beq',
+'ber',
+'bes',
+'bet',
+'beu',
+'bev',
+'bew',
+'bex',
+'bey',
+'bez',
+'bfa',
+'bfb',
+'bfc',
+'bfd',
+'bfe',
+'bff',
+'bfg',
+'bfh',
+'bfi',
+'bfj',
+'bfk',
+'bfl',
+'bfm',
+'bfn',
+'bfo',
+'bfp',
+'bfq',
+'bfr',
+'bfs',
+'bft',
+'bfu',
+'bfw',
+'bfx',
+'bfy',
+'bfz',
+'bga',
+'bgb',
+'bgc',
+'bgd',
+'bge',
+'bgf',
+'bgg',
+'bgi',
+'bgj',
+'bgk',
+'bgl',
+'bgm',
+'bgn',
+'bgo',
+'bgp',
+'bgq',
+'bgr',
+'bgs',
+'bgt',
+'bgu',
+'bgv',
+'bgw',
+'bgx',
+'bgy',
+'bgz',
+'bha',
+'bhb',
+'bhc',
+'bhd',
+'bhe',
+'bhf',
+'bhg',
+'bhh',
+'bhi',
+'bhj',
+'bhk',
+'bhl',
+'bhm',
+'bhn',
+'bho',
+'bhp',
+'bhq',
+'bhr',
+'bhs',
+'bht',
+'bhu',
+'bhv',
+'bhw',
+'bhx',
+'bhy',
+'bhz',
+'bia',
+'bib',
+'bic',
+'bid',
+'bie',
+'bif',
+'big',
+'bij',
+'bik',
+'bil',
+'bim',
+'bin',
+'bio',
+'bip',
+'biq',
+'bir',
+'bit',
+'biu',
+'biv',
+'biw',
+'bix',
+'biy',
+'biz',
+'bja',
+'bjb',
+'bjc',
+'bjd',
+'bje',
+'bjf',
+'bjg',
+'bjh',
+'bji',
+'bjj',
+'bjk',
+'bjl',
+'bjm',
+'bjn',
+'bjo',
+'bjp',
+'bjq',
+'bjr',
+'bjs',
+'bjt',
+'bju',
+'bjv',
+'bjw',
+'bjx',
+'bjy',
+'bjz',
+'bka',
+'bkb',
+'bkc',
+'bkd',
+'bkf',
+'bkg',
+'bkh',
+'bki',
+'bkj',
+'bkk',
+'bkl',
+'bkm',
+'bkn',
+'bko',
+'bkp',
+'bkq',
+'bkr',
+'bks',
+'bkt',
+'bku',
+'bkv',
+'bkw',
+'bkx',
+'bky',
+'bkz',
+'bla',
+'blb',
+'blc',
+'bld',
+'ble',
+'blf',
+'blg',
+'blh',
+'bli',
+'blj',
+'blk',
+'bll',
+'blm',
+'bln',
+'blo',
+'blp',
+'blq',
+'blr',
+'bls',
+'blt',
+'blv',
+'blw',
+'blx',
+'bly',
+'blz',
+'bma',
+'bmb',
+'bmc',
+'bmd',
+'bme',
+'bmf',
+'bmg',
+'bmh',
+'bmi',
+'bmj',
+'bmk',
+'bml',
+'bmm',
+'bmn',
+'bmo',
+'bmp',
+'bmq',
+'bmr',
+'bms',
+'bmt',
+'bmu',
+'bmv',
+'bmw',
+'bmx',
+'bmy',
+'bmz',
+'bna',
+'bnb',
+'bnc',
+'bnd',
+'bne',
+'bnf',
+'bng',
+'bni',
+'bnj',
+'bnk',
+'bnl',
+'bnm',
+'bnn',
+'bno',
+'bnp',
+'bnq',
+'bnr',
+'bns',
+'bnt',
+'bnu',
+'bnv',
+'bnw',
+'bnx',
+'bny',
+'bnz',
+'boa',
+'bob',
+'boe',
+'bof',
+'bog',
+'boh',
+'boi',
+'boj',
+'bok',
+'bol',
+'bom',
+'bon',
+'boo',
+'bop',
+'boq',
+'bor',
+'bot',
+'bou',
+'bov',
+'bow',
+'box',
+'boy',
+'boz',
+'bpa',
+'bpb',
+'bpd',
+'bpg',
+'bph',
+'bpi',
+'bpj',
+'bpk',
+'bpl',
+'bpm',
+'bpn',
+'bpo',
+'bpp',
+'bpq',
+'bpr',
+'bps',
+'bpt',
+'bpu',
+'bpv',
+'bpw',
+'bpx',
+'bpy',
+'bpz',
+'bqa',
+'bqb',
+'bqc',
+'bqd',
+'bqf',
+'bqg',
+'bqh',
+'bqi',
+'bqj',
+'bqk',
+'bql',
+'bqm',
+'bqn',
+'bqo',
+'bqp',
+'bqq',
+'bqr',
+'bqs',
+'bqt',
+'bqu',
+'bqv',
+'bqw',
+'bqx',
+'bqy',
+'bqz',
+'bra',
+'brb',
+'brc',
+'brd',
+'brf',
+'brg',
+'brh',
+'bri',
+'brj',
+'brk',
+'brl',
+'brm',
+'brn',
+'bro',
+'brp',
+'brq',
+'brr',
+'brs',
+'brt',
+'bru',
+'brv',
+'brw',
+'brx',
+'bry',
+'brz',
+'bsa',
+'bsb',
+'bsc',
+'bse',
+'bsf',
+'bsg',
+'bsh',
+'bsi',
+'bsj',
+'bsk',
+'bsl',
+'bsm',
+'bsn',
+'bso',
+'bsp',
+'bsq',
+'bsr',
+'bss',
+'bst',
+'bsu',
+'bsv',
+'bsw',
+'bsx',
+'bsy',
+'bta',
+'btb',
+'btc',
+'btd',
+'bte',
+'btf',
+'btg',
+'bth',
+'bti',
+'btj',
+'btk',
+'btl',
+'btm',
+'btn',
+'bto',
+'btp',
+'btq',
+'btr',
+'bts',
+'btt',
+'btu',
+'btv',
+'btw',
+'btx',
+'bty',
+'btz',
+'bua',
+'bub',
+'buc',
+'bud',
+'bue',
+'buf',
+'bug',
+'buh',
+'bui',
+'buj',
+'buk',
+'bum',
+'bun',
+'buo',
+'bup',
+'buq',
+'bus',
+'but',
+'buu',
+'buv',
+'buw',
+'bux',
+'buy',
+'buz',
+'bva',
+'bvb',
+'bvc',
+'bvd',
+'bve',
+'bvf',
+'bvg',
+'bvh',
+'bvi',
+'bvj',
+'bvk',
+'bvl',
+'bvm',
+'bvn',
+'bvo',
+'bvp',
+'bvq',
+'bvr',
+'bvt',
+'bvu',
+'bvv',
+'bvw',
+'bvx',
+'bvy',
+'bvz',
+'bwa',
+'bwb',
+'bwc',
+'bwd',
+'bwe',
+'bwf',
+'bwg',
+'bwh',
+'bwi',
+'bwj',
+'bwk',
+'bwl',
+'bwm',
+'bwn',
+'bwo',
+'bwp',
+'bwq',
+'bwr',
+'bws',
+'bwt',
+'bwu',
+'bww',
+'bwx',
+'bwy',
+'bwz',
+'bxa',
+'bxb',
+'bxc',
+'bxd',
+'bxe',
+'bxf',
+'bxg',
+'bxh',
+'bxi',
+'bxj',
+'bxk',
+'bxl',
+'bxm',
+'bxn',
+'bxo',
+'bxp',
+'bxq',
+'bxr',
+'bxs',
+'bxu',
+'bxv',
+'bxw',
+'bxx',
+'bxz',
+'bya',
+'byb',
+'byc',
+'byd',
+'bye',
+'byf',
+'byg',
+'byh',
+'byi',
+'byj',
+'byk',
+'byl',
+'bym',
+'byn',
+'byo',
+'byp',
+'byq',
+'byr',
+'bys',
+'byt',
+'byv',
+'byw',
+'byx',
+'byy',
+'byz',
+'bza',
+'bzb',
+'bzc',
+'bzd',
+'bze',
+'bzf',
+'bzg',
+'bzh',
+'bzi',
+'bzj',
+'bzk',
+'bzl',
+'bzm',
+'bzn',
+'bzo',
+'bzp',
+'bzq',
+'bzr',
+'bzs',
+'bzt',
+'bzu',
+'bzv',
+'bzw',
+'bzx',
+'bzy',
+'bzz',
+'caa',
+'cab',
+'cac',
+'cad',
+'cae',
+'caf',
+'cag',
+'cah',
+'cai',
+'caj',
+'cak',
+'cal',
+'cam',
+'can',
+'cao',
+'cap',
+'caq',
+'car',
+'cas',
+'cau',
+'cav',
+'caw',
+'cax',
+'cay',
+'caz',
+'cba',
+'cbb',
+'cbc',
+'cbd',
+'cbe',
+'cbg',
+'cbh',
+'cbi',
+'cbj',
+'cbk',
+'cbl',
+'cbn',
+'cbo',
+'cbq',
+'cbr',
+'cbs',
+'cbt',
+'cbu',
+'cbv',
+'cbw',
+'cby',
+'cca',
+'ccc',
+'ccd',
+'cce',
+'ccg',
+'cch',
+'ccj',
+'ccl',
+'ccm',
+'ccn',
+'cco',
+'ccp',
+'ccq',
+'ccr',
+'ccs',
+'cda',
+'cdc',
+'cdd',
+'cde',
+'cdf',
+'cdg',
+'cdh',
+'cdi',
+'cdj',
+'cdm',
+'cdn',
+'cdo',
+'cdr',
+'cds',
+'cdy',
+'cdz',
+'cea',
+'ceb',
+'ceg',
+'cek',
+'cel',
+'cen',
+'cet',
+'cfa',
+'cfd',
+'cfg',
+'cfm',
+'cga',
+'cgc',
+'cgg',
+'cgk',
+'chb',
+'chc',
+'chd',
+'chf',
+'chg',
+'chh',
+'chj',
+'chk',
+'chl',
+'chm',
+'chn',
+'cho',
+'chp',
+'chq',
+'chr',
+'cht',
+'chw',
+'chx',
+'chy',
+'chz',
+'cia',
+'cib',
+'cic',
+'cid',
+'cie',
+'cih',
+'cik',
+'cim',
+'cin',
+'cip',
+'cir',
+'ciw',
+'ciy',
+'cja',
+'cje',
+'cjh',
+'cji',
+'cjk',
+'cjm',
+'cjn',
+'cjo',
+'cjp',
+'cjr',
+'cjs',
+'cjv',
+'cjy',
+'cka',
+'ckb',
+'ckh',
+'ckl',
+'ckn',
+'cko',
+'ckq',
+'ckr',
+'cks',
+'ckt',
+'cku',
+'ckv',
+'ckx',
+'cky',
+'ckz',
+'cla',
+'clc',
+'cld',
+'cle',
+'clh',
+'cli',
+'clj',
+'clk',
+'cll',
+'clm',
+'clo',
+'clt',
+'clu',
+'clw',
+'cly',
+'cma',
+'cmc',
+'cme',
+'cmg',
+'cmi',
+'cmk',
+'cml',
+'cmm',
+'cmn',
+'cmo',
+'cmr',
+'cms',
+'cmt',
+'cna',
+'cnb',
+'cnc',
+'cng',
+'cnh',
+'cni',
+'cnk',
+'cnl',
+'cno',
+'cnr',
+'cns',
+'cnt',
+'cnu',
+'cnw',
+'cnx',
+'coa',
+'cob',
+'coc',
+'cod',
+'coe',
+'cof',
+'cog',
+'coh',
+'coj',
+'cok',
+'col',
+'com',
+'con',
+'coo',
+'cop',
+'coq',
+'cot',
+'cou',
+'cov',
+'cow',
+'cox',
+'coy',
+'coz',
+'cpa',
+'cpb',
+'cpc',
+'cpe',
+'cpf',
+'cpg',
+'cpi',
+'cpn',
+'cpo',
+'cpp',
+'cps',
+'cpu',
+'cpx',
+'cpy',
+'cqd',
+'cqu',
+'cra',
+'crb',
+'crc',
+'crd',
+'crf',
+'crg',
+'crh',
+'cri',
+'crj',
+'crk',
+'crl',
+'crm',
+'crn',
+'cro',
+'crp',
+'crq',
+'crr',
+'crs',
+'crt',
+'crv',
+'crw',
+'crx',
+'cry',
+'crz',
+'csa',
+'csb',
+'csc',
+'csd',
+'cse',
+'csf',
+'csg',
+'csh',
+'csi',
+'csj',
+'csk',
+'csl',
+'csm',
+'csn',
+'cso',
+'csq',
+'csr',
+'css',
+'cst',
+'csu',
+'csv',
+'csw',
+'csy',
+'csz',
+'cta',
+'ctc',
+'ctd',
+'cte',
+'ctg',
+'cth',
+'ctl',
+'ctm',
+'ctn',
+'cto',
+'ctp',
+'cts',
+'ctt',
+'ctu',
+'ctz',
+'cua',
+'cub',
+'cuc',
+'cug',
+'cuh',
+'cui',
+'cuj',
+'cuk',
+'cul',
+'cum',
+'cuo',
+'cup',
+'cuq',
+'cur',
+'cus',
+'cut',
+'cuu',
+'cuv',
+'cuw',
+'cux',
+'cuy',
+'cvg',
+'cvn',
+'cwa',
+'cwb',
+'cwd',
+'cwe',
+'cwg',
+'cwt',
+'cya',
+'cyb',
+'cyo',
+'czh',
+'czk',
+'czn',
+'czo',
+'czt',
+'daa',
+'dac',
+'dad',
+'dae',
+'daf',
+'dag',
+'dah',
+'dai',
+'daj',
+'dak',
+'dal',
+'dam',
+'dao',
+'dap',
+'daq',
+'dar',
+'das',
+'dau',
+'dav',
+'daw',
+'dax',
+'day',
+'daz',
+'dba',
+'dbb',
+'dbd',
+'dbe',
+'dbf',
+'dbg',
+'dbi',
+'dbj',
+'dbl',
+'dbm',
+'dbn',
+'dbo',
+'dbp',
+'dbq',
+'dbr',
+'dbt',
+'dbu',
+'dbv',
+'dbw',
+'dby',
+'dcc',
+'dcr',
+'dda',
+'ddd',
+'dde',
+'ddg',
+'ddi',
+'ddj',
+'ddn',
+'ddo',
+'ddr',
+'dds',
+'ddw',
+'dec',
+'ded',
+'dee',
+'def',
+'deg',
+'deh',
+'dei',
+'dek',
+'del',
+'dem',
+'den',
+'dep',
+'deq',
+'der',
+'des',
+'dev',
+'dez',
+'dga',
+'dgb',
+'dgc',
+'dgd',
+'dge',
+'dgg',
+'dgh',
+'dgi',
+'dgk',
+'dgl',
+'dgn',
+'dgo',
+'dgr',
+'dgs',
+'dgt',
+'dgu',
+'dgw',
+'dgx',
+'dgz',
+'dha',
+'dhd',
+'dhg',
+'dhi',
+'dhl',
+'dhm',
+'dhn',
+'dho',
+'dhr',
+'dhs',
+'dhu',
+'dhv',
+'dhw',
+'dhx',
+'dia',
+'dib',
+'dic',
+'did',
+'dif',
+'dig',
+'dih',
+'dii',
+'dij',
+'dik',
+'dil',
+'dim',
+'din',
+'dio',
+'dip',
+'diq',
+'dir',
+'dis',
+'dit',
+'diu',
+'diw',
+'dix',
+'diy',
+'diz',
+'dja',
+'djb',
+'djc',
+'djd',
+'dje',
+'djf',
+'dji',
+'djj',
+'djk',
+'djl',
+'djm',
+'djn',
+'djo',
+'djr',
+'dju',
+'djw',
+'dka',
+'dkk',
+'dkl',
+'dkr',
+'dks',
+'dkx',
+'dlg',
+'dlk',
+'dlm',
+'dln',
+'dma',
+'dmb',
+'dmc',
+'dmd',
+'dme',
+'dmg',
+'dmk',
+'dml',
+'dmm',
+'dmn',
+'dmo',
+'dmr',
+'dms',
+'dmu',
+'dmv',
+'dmw',
+'dmx',
+'dmy',
+'dna',
+'dnd',
+'dne',
+'dng',
+'dni',
+'dnj',
+'dnk',
+'dnn',
+'dnr',
+'dnt',
+'dnu',
+'dnv',
+'dnw',
+'dny',
+'doa',
+'dob',
+'doc',
+'doe',
+'dof',
+'doh',
+'doi',
+'dok',
+'dol',
+'don',
+'doo',
+'dop',
+'doq',
+'dor',
+'dos',
+'dot',
+'dov',
+'dow',
+'dox',
+'doy',
+'doz',
+'dpp',
+'dra',
+'drb',
+'drc',
+'drd',
+'dre',
+'drg',
+'drh',
+'dri',
+'drl',
+'drn',
+'dro',
+'drq',
+'drr',
+'drs',
+'drt',
+'dru',
+'drw',
+'dry',
+'dsb',
+'dse',
+'dsh',
+'dsi',
+'dsl',
+'dsn',
+'dso',
+'dsq',
+'dta',
+'dtb',
+'dtd',
+'dth',
+'dti',
+'dtk',
+'dtm',
+'dtn',
+'dto',
+'dtp',
+'dtr',
+'dts',
+'dtt',
+'dtu',
+'dty',
+'dua',
+'dub',
+'duc',
+'dud',
+'due',
+'duf',
+'dug',
+'duh',
+'dui',
+'duj',
+'duk',
+'dul',
+'dum',
+'dun',
+'duo',
+'dup',
+'duq',
+'dur',
+'dus',
+'duu',
+'duv',
+'duw',
+'dux',
+'duy',
+'duz',
+'dva',
+'dwa',
+'dwl',
+'dwr',
+'dws',
+'dwu',
+'dww',
+'dwy',
+'dya',
+'dyb',
+'dyd',
+'dyg',
+'dyi',
+'dym',
+'dyn',
+'dyo',
+'dyu',
+'dyy',
+'dza',
+'dzd',
+'dze',
+'dzg',
+'dzl',
+'dzn',
+'eaa',
+'ebg',
+'ebk',
+'ebo',
+'ebr',
+'ebu',
+'ecr',
+'ecs',
+'ecy',
+'eee',
+'efa',
+'efe',
+'efi',
+'ega',
+'egl',
+'ego',
+'egx',
+'egy',
+'ehu',
+'eip',
+'eit',
+'eiv',
+'eja',
+'eka',
+'ekc',
+'eke',
+'ekg',
+'eki',
+'ekk',
+'ekl',
+'ekm',
+'eko',
+'ekp',
+'ekr',
+'eky',
+'ele',
+'elh',
+'eli',
+'elk',
+'elm',
+'elo',
+'elp',
+'elu',
+'elx',
+'ema',
+'emb',
+'eme',
+'emg',
+'emi',
+'emk',
+'emm',
+'emn',
+'emo',
+'emp',
+'ems',
+'emu',
+'emw',
+'emx',
+'emy',
+'ena',
+'enb',
+'enc',
+'end',
+'enf',
+'enh',
+'enl',
+'enm',
+'enn',
+'eno',
+'enq',
+'enr',
+'enu',
+'env',
+'enw',
+'enx',
+'eot',
+'epi',
+'era',
+'erg',
+'erh',
+'eri',
+'erk',
+'ero',
+'err',
+'ers',
+'ert',
+'erw',
+'ese',
+'esg',
+'esh',
+'esi',
+'esk',
+'esl',
+'esm',
+'esn',
+'eso',
+'esq',
+'ess',
+'esu',
+'esx',
+'esy',
+'etb',
+'etc',
+'eth',
+'etn',
+'eto',
+'etr',
+'ets',
+'ett',
+'etu',
+'etx',
+'etz',
+'euq',
+'eve',
+'evh',
+'evn',
+'ewo',
+'ext',
+'eya',
+'eyo',
+'eza',
+'eze',
+'faa',
+'fab',
+'fad',
+'faf',
+'fag',
+'fah',
+'fai',
+'faj',
+'fak',
+'fal',
+'fam',
+'fan',
+'fap',
+'far',
+'fat',
+'fau',
+'fax',
+'fay',
+'faz',
+'fbl',
+'fcs',
+'fer',
+'ffi',
+'ffm',
+'fgr',
+'fia',
+'fie',
+'fil',
+'fip',
+'fir',
+'fit',
+'fiu',
+'fiw',
+'fkk',
+'fkv',
+'fla',
+'flh',
+'fli',
+'fll',
+'fln',
+'flr',
+'fly',
+'fmp',
+'fmu',
+'fnb',
+'fng',
+'fni',
+'fod',
+'foi',
+'fom',
+'fon',
+'for',
+'fos',
+'fox',
+'fpe',
+'fqs',
+'frc',
+'frd',
+'frk',
+'frm',
+'fro',
+'frp',
+'frq',
+'frr',
+'frs',
+'frt',
+'fse',
+'fsl',
+'fss',
+'fub',
+'fuc',
+'fud',
+'fue',
+'fuf',
+'fuh',
+'fui',
+'fuj',
+'fum',
+'fun',
+'fuq',
+'fur',
+'fut',
+'fuu',
+'fuv',
+'fuy',
+'fvr',
+'fwa',
+'fwe',
+'gaa',
+'gab',
+'gac',
+'gad',
+'gae',
+'gaf',
+'gag',
+'gah',
+'gai',
+'gaj',
+'gak',
+'gal',
+'gam',
+'gan',
+'gao',
+'gap',
+'gaq',
+'gar',
+'gas',
+'gat',
+'gau',
+'gav',
+'gaw',
+'gax',
+'gay',
+'gaz',
+'gba',
+'gbb',
+'gbc',
+'gbd',
+'gbe',
+'gbf',
+'gbg',
+'gbh',
+'gbi',
+'gbj',
+'gbk',
+'gbl',
+'gbm',
+'gbn',
+'gbo',
+'gbp',
+'gbq',
+'gbr',
+'gbs',
+'gbu',
+'gbv',
+'gbw',
+'gbx',
+'gby',
+'gbz',
+'gcc',
+'gcd',
+'gce',
+'gcf',
+'gcl',
+'gcn',
+'gcr',
+'gct',
+'gda',
+'gdb',
+'gdc',
+'gdd',
+'gde',
+'gdf',
+'gdg',
+'gdh',
+'gdi',
+'gdj',
+'gdk',
+'gdl',
+'gdm',
+'gdn',
+'gdo',
+'gdq',
+'gdr',
+'gds',
+'gdt',
+'gdu',
+'gdx',
+'gea',
+'geb',
+'gec',
+'ged',
+'geg',
+'geh',
+'gei',
+'gej',
+'gek',
+'gel',
+'gem',
+'geq',
+'ges',
+'gev',
+'gew',
+'gex',
+'gey',
+'gez',
+'gfk',
+'gft',
+'gfx',
+'gga',
+'ggb',
+'ggd',
+'gge',
+'ggg',
+'ggk',
+'ggl',
+'ggn',
+'ggo',
+'ggr',
+'ggt',
+'ggu',
+'ggw',
+'gha',
+'ghc',
+'ghe',
+'ghh',
+'ghk',
+'ghl',
+'ghn',
+'gho',
+'ghr',
+'ghs',
+'ght',
+'gia',
+'gib',
+'gic',
+'gid',
+'gie',
+'gig',
+'gih',
+'gil',
+'gim',
+'gin',
+'gio',
+'gip',
+'giq',
+'gir',
+'gis',
+'git',
+'giu',
+'giw',
+'gix',
+'giy',
+'giz',
+'gji',
+'gjk',
+'gjm',
+'gjn',
+'gjr',
+'gju',
+'gka',
+'gkd',
+'gke',
+'gkn',
+'gko',
+'gkp',
+'gku',
+'glc',
+'gld',
+'glh',
+'gli',
+'glj',
+'glk',
+'gll',
+'glo',
+'glr',
+'glu',
+'glw',
+'gly',
+'gma',
+'gmb',
+'gmd',
+'gme',
+'gmg',
+'gmh',
+'gml',
+'gmm',
+'gmn',
+'gmq',
+'gmu',
+'gmv',
+'gmw',
+'gmx',
+'gmy',
+'gmz',
+'gna',
+'gnb',
+'gnc',
+'gnd',
+'gne',
+'gng',
+'gnh',
+'gni',
+'gnj',
+'gnk',
+'gnl',
+'gnm',
+'gnn',
+'gno',
+'gnq',
+'gnr',
+'gnt',
+'gnu',
+'gnw',
+'gnz',
+'goa',
+'gob',
+'goc',
+'god',
+'goe',
+'gof',
+'gog',
+'goh',
+'goi',
+'goj',
+'gok',
+'gol',
+'gom',
+'gon',
+'goo',
+'gop',
+'goq',
+'gor',
+'gos',
+'got',
+'gou',
+'gow',
+'gox',
+'goy',
+'goz',
+'gpa',
+'gpe',
+'gpn',
+'gqa',
+'gqi',
+'gqn',
+'gqr',
+'gqu',
+'gra',
+'grb',
+'grc',
+'grd',
+'grg',
+'grh',
+'gri',
+'grj',
+'grk',
+'grm',
+'gro',
+'grq',
+'grr',
+'grs',
+'grt',
+'gru',
+'grv',
+'grw',
+'grx',
+'gry',
+'grz',
+'gse',
+'gsg',
+'gsl',
+'gsm',
+'gsn',
+'gso',
+'gsp',
+'gss',
+'gsw',
+'gta',
+'gti',
+'gtu',
+'gua',
+'gub',
+'guc',
+'gud',
+'gue',
+'guf',
+'gug',
+'guh',
+'gui',
+'guk',
+'gul',
+'gum',
+'gun',
+'guo',
+'gup',
+'guq',
+'gur',
+'gus',
+'gut',
+'guu',
+'guv',
+'guw',
+'gux',
+'guz',
+'gva',
+'gvc',
+'gve',
+'gvf',
+'gvj',
+'gvl',
+'gvm',
+'gvn',
+'gvo',
+'gvp',
+'gvr',
+'gvs',
+'gvy',
+'gwa',
+'gwb',
+'gwc',
+'gwd',
+'gwe',
+'gwf',
+'gwg',
+'gwi',
+'gwj',
+'gwm',
+'gwn',
+'gwr',
+'gwt',
+'gwu',
+'gww',
+'gwx',
+'gxx',
+'gya',
+'gyb',
+'gyd',
+'gye',
+'gyf',
+'gyg',
+'gyi',
+'gyl',
+'gym',
+'gyn',
+'gyo',
+'gyr',
+'gyy',
+'gza',
+'gzi',
+'gzn',
+'haa',
+'hab',
+'hac',
+'had',
+'hae',
+'haf',
+'hag',
+'hah',
+'hai',
+'haj',
+'hak',
+'hal',
+'ham',
+'han',
+'hao',
+'hap',
+'haq',
+'har',
+'has',
+'hav',
+'haw',
+'hax',
+'hay',
+'haz',
+'hba',
+'hbb',
+'hbn',
+'hbo',
+'hbu',
+'hca',
+'hch',
+'hdn',
+'hds',
+'hdy',
+'hea',
+'hed',
+'heg',
+'heh',
+'hei',
+'hem',
+'hgm',
+'hgw',
+'hhi',
+'hhr',
+'hhy',
+'hia',
+'hib',
+'hid',
+'hif',
+'hig',
+'hih',
+'hii',
+'hij',
+'hik',
+'hil',
+'him',
+'hio',
+'hir',
+'hit',
+'hiw',
+'hix',
+'hji',
+'hka',
+'hke',
+'hkk',
+'hkn',
+'hks',
+'hla',
+'hlb',
+'hld',
+'hle',
+'hlt',
+'hlu',
+'hma',
+'hmb',
+'hmc',
+'hmd',
+'hme',
+'hmf',
+'hmg',
+'hmh',
+'hmi',
+'hmj',
+'hmk',
+'hml',
+'hmm',
+'hmn',
+'hmp',
+'hmq',
+'hmr',
+'hms',
+'hmt',
+'hmu',
+'hmv',
+'hmw',
+'hmx',
+'hmy',
+'hmz',
+'hna',
+'hnd',
+'hne',
+'hnh',
+'hni',
+'hnj',
+'hnn',
+'hno',
+'hns',
+'hnu',
+'hoa',
+'hob',
+'hoc',
+'hod',
+'hoe',
+'hoh',
+'hoi',
+'hoj',
+'hok',
+'hol',
+'hom',
+'hoo',
+'hop',
+'hor',
+'hos',
+'hot',
+'hov',
+'how',
+'hoy',
+'hoz',
+'hpo',
+'hps',
+'hra',
+'hrc',
+'hre',
+'hrk',
+'hrm',
+'hro',
+'hrp',
+'hrr',
+'hrt',
+'hru',
+'hrw',
+'hrx',
+'hrz',
+'hsb',
+'hsh',
+'hsl',
+'hsn',
+'hss',
+'hti',
+'hto',
+'hts',
+'htu',
+'htx',
+'hub',
+'huc',
+'hud',
+'hue',
+'huf',
+'hug',
+'huh',
+'hui',
+'huj',
+'huk',
+'hul',
+'hum',
+'huo',
+'hup',
+'huq',
+'hur',
+'hus',
+'hut',
+'huu',
+'huv',
+'huw',
+'hux',
+'huy',
+'huz',
+'hvc',
+'hve',
+'hvk',
+'hvn',
+'hvv',
+'hwa',
+'hwc',
+'hwo',
+'hya',
+'hyw',
+'hyx',
+'iai',
+'ian',
+'iap',
+'iar',
+'iba',
+'ibb',
+'ibd',
+'ibe',
+'ibg',
+'ibh',
+'ibi',
+'ibl',
+'ibm',
+'ibn',
+'ibr',
+'ibu',
+'iby',
+'ica',
+'ich',
+'icl',
+'icr',
+'ida',
+'idb',
+'idc',
+'idd',
+'ide',
+'idi',
+'idr',
+'ids',
+'idt',
+'idu',
+'ifa',
+'ifb',
+'ife',
+'iff',
+'ifk',
+'ifm',
+'ifu',
+'ify',
+'igb',
+'ige',
+'igg',
+'igl',
+'igm',
+'ign',
+'igo',
+'igs',
+'igw',
+'ihb',
+'ihi',
+'ihp',
+'ihw',
+'iin',
+'iir',
+'ijc',
+'ije',
+'ijj',
+'ijn',
+'ijo',
+'ijs',
+'ike',
+'iki',
+'ikk',
+'ikl',
+'iko',
+'ikp',
+'ikr',
+'iks',
+'ikt',
+'ikv',
+'ikw',
+'ikx',
+'ikz',
+'ila',
+'ilb',
+'ilg',
+'ili',
+'ilk',
+'ill',
+'ilm',
+'ilo',
+'ilp',
+'ils',
+'ilu',
+'ilv',
+'ilw',
+'ima',
+'ime',
+'imi',
+'iml',
+'imn',
+'imo',
+'imr',
+'ims',
+'imy',
+'inb',
+'inc',
+'ine',
+'ing',
+'inh',
+'inj',
+'inl',
+'inm',
+'inn',
+'ino',
+'inp',
+'ins',
+'int',
+'inz',
+'ior',
+'iou',
+'iow',
+'ipi',
+'ipo',
+'iqu',
+'iqw',
+'ira',
+'ire',
+'irh',
+'iri',
+'irk',
+'irn',
+'iro',
+'irr',
+'iru',
+'irx',
+'iry',
+'isa',
+'isc',
+'isd',
+'ise',
+'isg',
+'ish',
+'isi',
+'isk',
+'ism',
+'isn',
+'iso',
+'isr',
+'ist',
+'isu',
+'itb',
+'itc',
+'itd',
+'ite',
+'iti',
+'itk',
+'itl',
+'itm',
+'ito',
+'itr',
+'its',
+'itt',
+'itv',
+'itw',
+'itx',
+'ity',
+'itz',
+'ium',
+'ivb',
+'ivv',
+'iwk',
+'iwm',
+'iwo',
+'iws',
+'ixc',
+'ixl',
+'iya',
+'iyo',
+'iyx',
+'izh',
+'izi',
+'izr',
+'izz',
+'jaa',
+'jab',
+'jac',
+'jad',
+'jae',
+'jaf',
+'jah',
+'jaj',
+'jak',
+'jal',
+'jam',
+'jan',
+'jao',
+'jaq',
+'jar',
+'jas',
+'jat',
+'jau',
+'jax',
+'jay',
+'jaz',
+'jbe',
+'jbi',
+'jbj',
+'jbk',
+'jbn',
+'jbo',
+'jbr',
+'jbt',
+'jbu',
+'jbw',
+'jcs',
+'jct',
+'jda',
+'jdg',
+'jdt',
+'jeb',
+'jee',
+'jeg',
+'jeh',
+'jei',
+'jek',
+'jel',
+'jen',
+'jer',
+'jet',
+'jeu',
+'jgb',
+'jge',
+'jgk',
+'jgo',
+'jhi',
+'jhs',
+'jia',
+'jib',
+'jic',
+'jid',
+'jie',
+'jig',
+'jih',
+'jii',
+'jil',
+'jim',
+'jio',
+'jiq',
+'jit',
+'jiu',
+'jiv',
+'jiy',
+'jje',
+'jjr',
+'jka',
+'jkm',
+'jko',
+'jkp',
+'jkr',
+'jku',
+'jle',
+'jls',
+'jma',
+'jmb',
+'jmc',
+'jmd',
+'jmi',
+'jml',
+'jmn',
+'jmr',
+'jms',
+'jmw',
+'jmx',
+'jna',
+'jnd',
+'jng',
+'jni',
+'jnj',
+'jnl',
+'jns',
+'job',
+'jod',
+'jog',
+'jor',
+'jos',
+'jow',
+'jpa',
+'jpr',
+'jpx',
+'jqr',
+'jra',
+'jrb',
+'jrr',
+'jrt',
+'jru',
+'jsl',
+'jua',
+'jub',
+'juc',
+'jud',
+'juh',
+'jui',
+'juk',
+'jul',
+'jum',
+'jun',
+'juo',
+'jup',
+'jur',
+'jus',
+'jut',
+'juu',
+'juw',
+'juy',
+'jvd',
+'jvn',
+'jwi',
+'jya',
+'jye',
+'jyy',
+'kaa',
+'kab',
+'kac',
+'kad',
+'kae',
+'kaf',
+'kag',
+'kah',
+'kai',
+'kaj',
+'kak',
+'kam',
+'kao',
+'kap',
+'kaq',
+'kar',
+'kav',
+'kaw',
+'kax',
+'kay',
+'kba',
+'kbb',
+'kbc',
+'kbd',
+'kbe',
+'kbf',
+'kbg',
+'kbh',
+'kbi',
+'kbj',
+'kbk',
+'kbl',
+'kbm',
+'kbn',
+'kbo',
+'kbp',
+'kbq',
+'kbr',
+'kbs',
+'kbt',
+'kbu',
+'kbv',
+'kbw',
+'kbx',
+'kby',
+'kbz',
+'kca',
+'kcb',
+'kcc',
+'kcd',
+'kce',
+'kcf',
+'kcg',
+'kch',
+'kci',
+'kcj',
+'kck',
+'kcl',
+'kcm',
+'kcn',
+'kco',
+'kcp',
+'kcq',
+'kcr',
+'kcs',
+'kct',
+'kcu',
+'kcv',
+'kcw',
+'kcx',
+'kcy',
+'kcz',
+'kda',
+'kdc',
+'kdd',
+'kde',
+'kdf',
+'kdg',
+'kdh',
+'kdi',
+'kdj',
+'kdk',
+'kdl',
+'kdm',
+'kdn',
+'kdo',
+'kdp',
+'kdq',
+'kdr',
+'kdt',
+'kdu',
+'kdv',
+'kdw',
+'kdx',
+'kdy',
+'kdz',
+'kea',
+'keb',
+'kec',
+'ked',
+'kee',
+'kef',
+'keg',
+'keh',
+'kei',
+'kej',
+'kek',
+'kel',
+'kem',
+'ken',
+'keo',
+'kep',
+'keq',
+'ker',
+'kes',
+'ket',
+'keu',
+'kev',
+'kew',
+'kex',
+'key',
+'kez',
+'kfa',
+'kfb',
+'kfc',
+'kfd',
+'kfe',
+'kff',
+'kfg',
+'kfh',
+'kfi',
+'kfj',
+'kfk',
+'kfl',
+'kfm',
+'kfn',
+'kfo',
+'kfp',
+'kfq',
+'kfr',
+'kfs',
+'kft',
+'kfu',
+'kfv',
+'kfw',
+'kfx',
+'kfy',
+'kfz',
+'kga',
+'kgb',
+'kgc',
+'kgd',
+'kge',
+'kgf',
+'kgg',
+'kgh',
+'kgi',
+'kgj',
+'kgk',
+'kgl',
+'kgm',
+'kgn',
+'kgo',
+'kgp',
+'kgq',
+'kgr',
+'kgs',
+'kgt',
+'kgu',
+'kgv',
+'kgw',
+'kgx',
+'kgy',
+'kha',
+'khb',
+'khc',
+'khd',
+'khe',
+'khf',
+'khg',
+'khh',
+'khi',
+'khj',
+'khk',
+'khl',
+'khn',
+'kho',
+'khp',
+'khq',
+'khr',
+'khs',
+'kht',
+'khu',
+'khv',
+'khw',
+'khx',
+'khy',
+'khz',
+'kia',
+'kib',
+'kic',
+'kid',
+'kie',
+'kif',
+'kig',
+'kih',
+'kii',
+'kij',
+'kil',
+'kim',
+'kio',
+'kip',
+'kiq',
+'kis',
+'kit',
+'kiu',
+'kiv',
+'kiw',
+'kix',
+'kiy',
+'kiz',
+'kja',
+'kjb',
+'kjc',
+'kjd',
+'kje',
+'kjf',
+'kjg',
+'kjh',
+'kji',
+'kjj',
+'kjk',
+'kjl',
+'kjm',
+'kjn',
+'kjo',
+'kjp',
+'kjq',
+'kjr',
+'kjs',
+'kjt',
+'kju',
+'kjv',
+'kjx',
+'kjy',
+'kjz',
+'kka',
+'kkb',
+'kkc',
+'kkd',
+'kke',
+'kkf',
+'kkg',
+'kkh',
+'kki',
+'kkj',
+'kkk',
+'kkl',
+'kkm',
+'kkn',
+'kko',
+'kkp',
+'kkq',
+'kkr',
+'kks',
+'kkt',
+'kku',
+'kkv',
+'kkw',
+'kkx',
+'kky',
+'kkz',
+'kla',
+'klb',
+'klc',
+'kld',
+'kle',
+'klf',
+'klg',
+'klh',
+'kli',
+'klj',
+'klk',
+'kll',
+'klm',
+'kln',
+'klo',
+'klp',
+'klq',
+'klr',
+'kls',
+'klt',
+'klu',
+'klv',
+'klw',
+'klx',
+'kly',
+'klz',
+'kma',
+'kmb',
+'kmc',
+'kmd',
+'kme',
+'kmf',
+'kmg',
+'kmh',
+'kmi',
+'kmj',
+'kmk',
+'kml',
+'kmm',
+'kmn',
+'kmo',
+'kmp',
+'kmq',
+'kmr',
+'kms',
+'kmt',
+'kmu',
+'kmv',
+'kmw',
+'kmx',
+'kmy',
+'kmz',
+'kna',
+'knb',
+'knc',
+'knd',
+'kne',
+'knf',
+'kng',
+'kni',
+'knj',
+'knk',
+'knl',
+'knm',
+'knn',
+'kno',
+'knp',
+'knq',
+'knr',
+'kns',
+'knt',
+'knu',
+'knv',
+'knw',
+'knx',
+'kny',
+'knz',
+'koa',
+'koc',
+'kod',
+'koe',
+'kof',
+'kog',
+'koh',
+'koi',
+'koj',
+'kok',
+'kol',
+'koo',
+'kop',
+'koq',
+'kos',
+'kot',
+'kou',
+'kov',
+'kow',
+'kox',
+'koy',
+'koz',
+'kpa',
+'kpb',
+'kpc',
+'kpd',
+'kpe',
+'kpf',
+'kpg',
+'kph',
+'kpi',
+'kpj',
+'kpk',
+'kpl',
+'kpm',
+'kpn',
+'kpo',
+'kpp',
+'kpq',
+'kpr',
+'kps',
+'kpt',
+'kpu',
+'kpv',
+'kpw',
+'kpx',
+'kpy',
+'kpz',
+'kqa',
+'kqb',
+'kqc',
+'kqd',
+'kqe',
+'kqf',
+'kqg',
+'kqh',
+'kqi',
+'kqj',
+'kqk',
+'kql',
+'kqm',
+'kqn',
+'kqo',
+'kqp',
+'kqq',
+'kqr',
+'kqs',
+'kqt',
+'kqu',
+'kqv',
+'kqw',
+'kqx',
+'kqy',
+'kqz',
+'kra',
+'krb',
+'krc',
+'krd',
+'kre',
+'krf',
+'krh',
+'kri',
+'krj',
+'krk',
+'krl',
+'krm',
+'krn',
+'kro',
+'krp',
+'krr',
+'krs',
+'krt',
+'kru',
+'krv',
+'krw',
+'krx',
+'kry',
+'krz',
+'ksa',
+'ksb',
+'ksc',
+'ksd',
+'kse',
+'ksf',
+'ksg',
+'ksh',
+'ksi',
+'ksj',
+'ksk',
+'ksl',
+'ksm',
+'ksn',
+'kso',
+'ksp',
+'ksq',
+'ksr',
+'kss',
+'kst',
+'ksu',
+'ksv',
+'ksw',
+'ksx',
+'ksy',
+'ksz',
+'kta',
+'ktb',
+'ktc',
+'ktd',
+'kte',
+'ktf',
+'ktg',
+'kth',
+'kti',
+'ktj',
+'ktk',
+'ktl',
+'ktm',
+'ktn',
+'kto',
+'ktp',
+'ktq',
+'ktr',
+'kts',
+'ktt',
+'ktu',
+'ktv',
+'ktw',
+'ktx',
+'kty',
+'ktz',
+'kub',
+'kuc',
+'kud',
+'kue',
+'kuf',
+'kug',
+'kuh',
+'kui',
+'kuj',
+'kuk',
+'kul',
+'kum',
+'kun',
+'kuo',
+'kup',
+'kuq',
+'kus',
+'kut',
+'kuu',
+'kuv',
+'kuw',
+'kux',
+'kuy',
+'kuz',
+'kva',
+'kvb',
+'kvc',
+'kvd',
+'kve',
+'kvf',
+'kvg',
+'kvh',
+'kvi',
+'kvj',
+'kvk',
+'kvl',
+'kvm',
+'kvn',
+'kvo',
+'kvp',
+'kvq',
+'kvr',
+'kvs',
+'kvt',
+'kvu',
+'kvv',
+'kvw',
+'kvx',
+'kvy',
+'kvz',
+'kwa',
+'kwb',
+'kwc',
+'kwd',
+'kwe',
+'kwf',
+'kwg',
+'kwh',
+'kwi',
+'kwj',
+'kwk',
+'kwl',
+'kwm',
+'kwn',
+'kwo',
+'kwp',
+'kwq',
+'kwr',
+'kws',
+'kwt',
+'kwu',
+'kwv',
+'kww',
+'kwx',
+'kwy',
+'kwz',
+'kxa',
+'kxb',
+'kxc',
+'kxd',
+'kxe',
+'kxf',
+'kxh',
+'kxi',
+'kxj',
+'kxk',
+'kxl',
+'kxm',
+'kxn',
+'kxo',
+'kxp',
+'kxq',
+'kxr',
+'kxs',
+'kxt',
+'kxu',
+'kxv',
+'kxw',
+'kxx',
+'kxy',
+'kxz',
+'kya',
+'kyb',
+'kyc',
+'kyd',
+'kye',
+'kyf',
+'kyg',
+'kyh',
+'kyi',
+'kyj',
+'kyk',
+'kyl',
+'kym',
+'kyn',
+'kyo',
+'kyp',
+'kyq',
+'kyr',
+'kys',
+'kyt',
+'kyu',
+'kyv',
+'kyw',
+'kyx',
+'kyy',
+'kyz',
+'kza',
+'kzb',
+'kzc',
+'kzd',
+'kze',
+'kzf',
+'kzg',
+'kzh',
+'kzi',
+'kzj',
+'kzk',
+'kzl',
+'kzm',
+'kzn',
+'kzo',
+'kzp',
+'kzq',
+'kzr',
+'kzs',
+'kzt',
+'kzu',
+'kzv',
+'kzw',
+'kzx',
+'kzy',
+'kzz',
+'laa',
+'lab',
+'lac',
+'lad',
+'lae',
+'laf',
+'lag',
+'lah',
+'lai',
+'laj',
+'lak',
+'lal',
+'lam',
+'lan',
+'lap',
+'laq',
+'lar',
+'las',
+'lau',
+'law',
+'lax',
+'lay',
+'laz',
+'lba',
+'lbb',
+'lbc',
+'lbe',
+'lbf',
+'lbg',
+'lbi',
+'lbj',
+'lbk',
+'lbl',
+'lbm',
+'lbn',
+'lbo',
+'lbq',
+'lbr',
+'lbs',
+'lbt',
+'lbu',
+'lbv',
+'lbw',
+'lbx',
+'lby',
+'lbz',
+'lcc',
+'lcd',
+'lce',
+'lcf',
+'lch',
+'lcl',
+'lcm',
+'lcp',
+'lcq',
+'lcs',
+'lda',
+'ldb',
+'ldd',
+'ldg',
+'ldh',
+'ldi',
+'ldj',
+'ldk',
+'ldl',
+'ldm',
+'ldn',
+'ldo',
+'ldp',
+'ldq',
+'lea',
+'leb',
+'lec',
+'led',
+'lee',
+'lef',
+'leg',
+'leh',
+'lei',
+'lej',
+'lek',
+'lel',
+'lem',
+'len',
+'leo',
+'lep',
+'leq',
+'ler',
+'les',
+'let',
+'leu',
+'lev',
+'lew',
+'lex',
+'ley',
+'lez',
+'lfa',
+'lfn',
+'lga',
+'lgb',
+'lgg',
+'lgh',
+'lgi',
+'lgk',
+'lgl',
+'lgm',
+'lgn',
+'lgq',
+'lgr',
+'lgt',
+'lgu',
+'lgz',
+'lha',
+'lhh',
+'lhi',
+'lhl',
+'lhm',
+'lhn',
+'lhp',
+'lhs',
+'lht',
+'lhu',
+'lia',
+'lib',
+'lic',
+'lid',
+'lie',
+'lif',
+'lig',
+'lih',
+'lii',
+'lij',
+'lik',
+'lil',
+'lio',
+'lip',
+'liq',
+'lir',
+'lis',
+'liu',
+'liv',
+'liw',
+'lix',
+'liy',
+'liz',
+'lja',
+'lje',
+'lji',
+'ljl',
+'ljp',
+'ljw',
+'ljx',
+'lka',
+'lkb',
+'lkc',
+'lkd',
+'lke',
+'lkh',
+'lki',
+'lkj',
+'lkl',
+'lkm',
+'lkn',
+'lko',
+'lkr',
+'lks',
+'lkt',
+'lku',
+'lky',
+'lla',
+'llb',
+'llc',
+'lld',
+'lle',
+'llf',
+'llg',
+'llh',
+'lli',
+'llj',
+'llk',
+'lll',
+'llm',
+'lln',
+'llo',
+'llp',
+'llq',
+'lls',
+'llu',
+'llx',
+'lma',
+'lmb',
+'lmc',
+'lmd',
+'lme',
+'lmf',
+'lmg',
+'lmh',
+'lmi',
+'lmj',
+'lmk',
+'lml',
+'lmm',
+'lmn',
+'lmo',
+'lmp',
+'lmq',
+'lmr',
+'lmu',
+'lmv',
+'lmw',
+'lmx',
+'lmy',
+'lmz',
+'lna',
+'lnb',
+'lnd',
+'lng',
+'lnh',
+'lni',
+'lnj',
+'lnl',
+'lnm',
+'lnn',
+'lno',
+'lns',
+'lnu',
+'lnw',
+'lnz',
+'loa',
+'lob',
+'loc',
+'loe',
+'lof',
+'log',
+'loh',
+'loi',
+'loj',
+'lok',
+'lol',
+'lom',
+'lon',
+'loo',
+'lop',
+'loq',
+'lor',
+'los',
+'lot',
+'lou',
+'lov',
+'low',
+'lox',
+'loy',
+'loz',
+'lpa',
+'lpe',
+'lpn',
+'lpo',
+'lpx',
+'lra',
+'lrc',
+'lre',
+'lrg',
+'lri',
+'lrk',
+'lrl',
+'lrm',
+'lrn',
+'lro',
+'lrr',
+'lrt',
+'lrv',
+'lrz',
+'lsa',
+'lsd',
+'lse',
+'lsg',
+'lsh',
+'lsi',
+'lsl',
+'lsm',
+'lso',
+'lsp',
+'lsr',
+'lss',
+'lst',
+'lsy',
+'ltc',
+'ltg',
+'lth',
+'lti',
+'ltn',
+'lto',
+'lts',
+'ltu',
+'lua',
+'luc',
+'lud',
+'lue',
+'luf',
+'lui',
+'luj',
+'luk',
+'lul',
+'lum',
+'lun',
+'luo',
+'lup',
+'luq',
+'lur',
+'lus',
+'lut',
+'luu',
+'luv',
+'luw',
+'luy',
+'luz',
+'lva',
+'lvk',
+'lvs',
+'lvu',
+'lwa',
+'lwe',
+'lwg',
+'lwh',
+'lwl',
+'lwm',
+'lwo',
+'lws',
+'lwt',
+'lwu',
+'lww',
+'lya',
+'lyg',
+'lyn',
+'lzh',
+'lzl',
+'lzn',
+'lzz',
+'maa',
+'mab',
+'mad',
+'mae',
+'maf',
+'mag',
+'mai',
+'maj',
+'mak',
+'mam',
+'man',
+'map',
+'maq',
+'mas',
+'mat',
+'mau',
+'mav',
+'maw',
+'max',
+'maz',
+'mba',
+'mbb',
+'mbc',
+'mbd',
+'mbe',
+'mbf',
+'mbh',
+'mbi',
+'mbj',
+'mbk',
+'mbl',
+'mbm',
+'mbn',
+'mbo',
+'mbp',
+'mbq',
+'mbr',
+'mbs',
+'mbt',
+'mbu',
+'mbv',
+'mbw',
+'mbx',
+'mby',
+'mbz',
+'mca',
+'mcb',
+'mcc',
+'mcd',
+'mce',
+'mcf',
+'mcg',
+'mch',
+'mci',
+'mcj',
+'mck',
+'mcl',
+'mcm',
+'mcn',
+'mco',
+'mcp',
+'mcq',
+'mcr',
+'mcs',
+'mct',
+'mcu',
+'mcv',
+'mcw',
+'mcx',
+'mcy',
+'mcz',
+'mda',
+'mdb',
+'mdc',
+'mdd',
+'mde',
+'mdf',
+'mdg',
+'mdh',
+'mdi',
+'mdj',
+'mdk',
+'mdl',
+'mdm',
+'mdn',
+'mdp',
+'mdq',
+'mdr',
+'mds',
+'mdt',
+'mdu',
+'mdv',
+'mdw',
+'mdx',
+'mdy',
+'mdz',
+'mea',
+'meb',
+'mec',
+'med',
+'mee',
+'mef',
+'meg',
+'meh',
+'mei',
+'mej',
+'mek',
+'mel',
+'mem',
+'men',
+'meo',
+'mep',
+'meq',
+'mer',
+'mes',
+'met',
+'meu',
+'mev',
+'mew',
+'mey',
+'mez',
+'mfa',
+'mfb',
+'mfc',
+'mfd',
+'mfe',
+'mff',
+'mfg',
+'mfh',
+'mfi',
+'mfj',
+'mfk',
+'mfl',
+'mfm',
+'mfn',
+'mfo',
+'mfp',
+'mfq',
+'mfr',
+'mfs',
+'mft',
+'mfu',
+'mfv',
+'mfw',
+'mfx',
+'mfy',
+'mfz',
+'mga',
+'mgb',
+'mgc',
+'mgd',
+'mge',
+'mgf',
+'mgg',
+'mgh',
+'mgi',
+'mgj',
+'mgk',
+'mgl',
+'mgm',
+'mgn',
+'mgo',
+'mgp',
+'mgq',
+'mgr',
+'mgs',
+'mgt',
+'mgu',
+'mgv',
+'mgw',
+'mgx',
+'mgy',
+'mgz',
+'mha',
+'mhb',
+'mhc',
+'mhd',
+'mhe',
+'mhf',
+'mhg',
+'mhh',
+'mhi',
+'mhj',
+'mhk',
+'mhl',
+'mhm',
+'mhn',
+'mho',
+'mhp',
+'mhq',
+'mhr',
+'mhs',
+'mht',
+'mhu',
+'mhw',
+'mhx',
+'mhy',
+'mhz',
+'mia',
+'mib',
+'mic',
+'mid',
+'mie',
+'mif',
+'mig',
+'mih',
+'mii',
+'mij',
+'mik',
+'mil',
+'mim',
+'min',
+'mio',
+'mip',
+'miq',
+'mir',
+'mis',
+'mit',
+'miu',
+'miw',
+'mix',
+'miy',
+'miz',
+'mja',
+'mjb',
+'mjc',
+'mjd',
+'mje',
+'mjg',
+'mjh',
+'mji',
+'mjj',
+'mjk',
+'mjl',
+'mjm',
+'mjn',
+'mjo',
+'mjp',
+'mjq',
+'mjr',
+'mjs',
+'mjt',
+'mju',
+'mjv',
+'mjw',
+'mjx',
+'mjy',
+'mjz',
+'mka',
+'mkb',
+'mkc',
+'mke',
+'mkf',
+'mkg',
+'mkh',
+'mki',
+'mkj',
+'mkk',
+'mkl',
+'mkm',
+'mkn',
+'mko',
+'mkp',
+'mkq',
+'mkr',
+'mks',
+'mkt',
+'mku',
+'mkv',
+'mkw',
+'mkx',
+'mky',
+'mkz',
+'mla',
+'mlb',
+'mlc',
+'mld',
+'mle',
+'mlf',
+'mlh',
+'mli',
+'mlj',
+'mlk',
+'mll',
+'mlm',
+'mln',
+'mlo',
+'mlp',
+'mlq',
+'mlr',
+'mls',
+'mlu',
+'mlv',
+'mlw',
+'mlx',
+'mlz',
+'mma',
+'mmb',
+'mmc',
+'mmd',
+'mme',
+'mmf',
+'mmg',
+'mmh',
+'mmi',
+'mmj',
+'mmk',
+'mml',
+'mmm',
+'mmn',
+'mmo',
+'mmp',
+'mmq',
+'mmr',
+'mmt',
+'mmu',
+'mmv',
+'mmw',
+'mmx',
+'mmy',
+'mmz',
+'mna',
+'mnb',
+'mnc',
+'mnd',
+'mne',
+'mnf',
+'mng',
+'mnh',
+'mni',
+'mnj',
+'mnk',
+'mnl',
+'mnm',
+'mnn',
+'mno',
+'mnp',
+'mnq',
+'mnr',
+'mns',
+'mnt',
+'mnu',
+'mnv',
+'mnw',
+'mnx',
+'mny',
+'mnz',
+'moa',
+'moc',
+'mod',
+'moe',
+'mof',
+'mog',
+'moh',
+'moi',
+'moj',
+'mok',
+'mom',
+'moo',
+'mop',
+'moq',
+'mor',
+'mos',
+'mot',
+'mou',
+'mov',
+'mow',
+'mox',
+'moy',
+'moz',
+'mpa',
+'mpb',
+'mpc',
+'mpd',
+'mpe',
+'mpg',
+'mph',
+'mpi',
+'mpj',
+'mpk',
+'mpl',
+'mpm',
+'mpn',
+'mpo',
+'mpp',
+'mpq',
+'mpr',
+'mps',
+'mpt',
+'mpu',
+'mpv',
+'mpw',
+'mpx',
+'mpy',
+'mpz',
+'mqa',
+'mqb',
+'mqc',
+'mqe',
+'mqf',
+'mqg',
+'mqh',
+'mqi',
+'mqj',
+'mqk',
+'mql',
+'mqm',
+'mqn',
+'mqo',
+'mqp',
+'mqq',
+'mqr',
+'mqs',
+'mqt',
+'mqu',
+'mqv',
+'mqw',
+'mqx',
+'mqy',
+'mqz',
+'mra',
+'mrb',
+'mrc',
+'mrd',
+'mre',
+'mrf',
+'mrg',
+'mrh',
+'mrj',
+'mrk',
+'mrl',
+'mrm',
+'mrn',
+'mro',
+'mrp',
+'mrq',
+'mrr',
+'mrs',
+'mrt',
+'mru',
+'mrv',
+'mrw',
+'mrx',
+'mry',
+'mrz',
+'msb',
+'msc',
+'msd',
+'mse',
+'msf',
+'msg',
+'msh',
+'msi',
+'msj',
+'msk',
+'msl',
+'msm',
+'msn',
+'mso',
+'msp',
+'msq',
+'msr',
+'mss',
+'mst',
+'msu',
+'msv',
+'msw',
+'msx',
+'msy',
+'msz',
+'mta',
+'mtb',
+'mtc',
+'mtd',
+'mte',
+'mtf',
+'mtg',
+'mth',
+'mti',
+'mtj',
+'mtk',
+'mtl',
+'mtm',
+'mtn',
+'mto',
+'mtp',
+'mtq',
+'mtr',
+'mts',
+'mtt',
+'mtu',
+'mtv',
+'mtw',
+'mtx',
+'mty',
+'mua',
+'mub',
+'muc',
+'mud',
+'mue',
+'mug',
+'muh',
+'mui',
+'muj',
+'muk',
+'mul',
+'mum',
+'mun',
+'muo',
+'mup',
+'muq',
+'mur',
+'mus',
+'mut',
+'muu',
+'muv',
+'mux',
+'muy',
+'muz',
+'mva',
+'mvb',
+'mvd',
+'mve',
+'mvf',
+'mvg',
+'mvh',
+'mvi',
+'mvk',
+'mvl',
+'mvm',
+'mvn',
+'mvo',
+'mvp',
+'mvq',
+'mvr',
+'mvs',
+'mvt',
+'mvu',
+'mvv',
+'mvw',
+'mvx',
+'mvy',
+'mvz',
+'mwa',
+'mwb',
+'mwc',
+'mwd',
+'mwe',
+'mwf',
+'mwg',
+'mwh',
+'mwi',
+'mwj',
+'mwk',
+'mwl',
+'mwm',
+'mwn',
+'mwo',
+'mwp',
+'mwq',
+'mwr',
+'mws',
+'mwt',
+'mwu',
+'mwv',
+'mww',
+'mwx',
+'mwy',
+'mwz',
+'mxa',
+'mxb',
+'mxc',
+'mxd',
+'mxe',
+'mxf',
+'mxg',
+'mxh',
+'mxi',
+'mxj',
+'mxk',
+'mxl',
+'mxm',
+'mxn',
+'mxo',
+'mxp',
+'mxq',
+'mxr',
+'mxs',
+'mxt',
+'mxu',
+'mxv',
+'mxw',
+'mxx',
+'mxy',
+'mxz',
+'myb',
+'myc',
+'myd',
+'mye',
+'myf',
+'myg',
+'myh',
+'myi',
+'myj',
+'myk',
+'myl',
+'mym',
+'myn',
+'myo',
+'myp',
+'myq',
+'myr',
+'mys',
+'myt',
+'myu',
+'myv',
+'myw',
+'myx',
+'myy',
+'myz',
+'mza',
+'mzb',
+'mzc',
+'mzd',
+'mze',
+'mzg',
+'mzh',
+'mzi',
+'mzj',
+'mzk',
+'mzl',
+'mzm',
+'mzn',
+'mzo',
+'mzp',
+'mzq',
+'mzr',
+'mzs',
+'mzt',
+'mzu',
+'mzv',
+'mzw',
+'mzx',
+'mzy',
+'mzz',
+'naa',
+'nab',
+'nac',
+'nad',
+'nae',
+'naf',
+'nag',
+'nah',
+'nai',
+'naj',
+'nak',
+'nal',
+'nam',
+'nan',
+'nao',
+'nap',
+'naq',
+'nar',
+'nas',
+'nat',
+'naw',
+'nax',
+'nay',
+'naz',
+'nba',
+'nbb',
+'nbc',
+'nbd',
+'nbe',
+'nbf',
+'nbg',
+'nbh',
+'nbi',
+'nbj',
+'nbk',
+'nbm',
+'nbn',
+'nbo',
+'nbp',
+'nbq',
+'nbr',
+'nbs',
+'nbt',
+'nbu',
+'nbv',
+'nbw',
+'nbx',
+'nby',
+'nca',
+'ncb',
+'ncc',
+'ncd',
+'nce',
+'ncf',
+'ncg',
+'nch',
+'nci',
+'ncj',
+'nck',
+'ncl',
+'ncm',
+'ncn',
+'nco',
+'ncp',
+'ncq',
+'ncr',
+'ncs',
+'nct',
+'ncu',
+'ncx',
+'ncz',
+'nda',
+'ndb',
+'ndc',
+'ndd',
+'ndf',
+'ndg',
+'ndh',
+'ndi',
+'ndj',
+'ndk',
+'ndl',
+'ndm',
+'ndn',
+'ndp',
+'ndq',
+'ndr',
+'nds',
+'ndt',
+'ndu',
+'ndv',
+'ndw',
+'ndx',
+'ndy',
+'ndz',
+'nea',
+'neb',
+'nec',
+'ned',
+'nee',
+'nef',
+'neg',
+'neh',
+'nei',
+'nej',
+'nek',
+'nem',
+'nen',
+'neo',
+'neq',
+'ner',
+'nes',
+'net',
+'neu',
+'nev',
+'new',
+'nex',
+'ney',
+'nez',
+'nfa',
+'nfd',
+'nfl',
+'nfr',
+'nfu',
+'nga',
+'ngb',
+'ngc',
+'ngd',
+'nge',
+'ngf',
+'ngg',
+'ngh',
+'ngi',
+'ngj',
+'ngk',
+'ngl',
+'ngm',
+'ngn',
+'ngo',
+'ngp',
+'ngq',
+'ngr',
+'ngs',
+'ngt',
+'ngu',
+'ngv',
+'ngw',
+'ngx',
+'ngy',
+'ngz',
+'nha',
+'nhb',
+'nhc',
+'nhd',
+'nhe',
+'nhf',
+'nhg',
+'nhh',
+'nhi',
+'nhk',
+'nhm',
+'nhn',
+'nho',
+'nhp',
+'nhq',
+'nhr',
+'nht',
+'nhu',
+'nhv',
+'nhw',
+'nhx',
+'nhy',
+'nhz',
+'nia',
+'nib',
+'nic',
+'nid',
+'nie',
+'nif',
+'nig',
+'nih',
+'nii',
+'nij',
+'nik',
+'nil',
+'nim',
+'nin',
+'nio',
+'niq',
+'nir',
+'nis',
+'nit',
+'niu',
+'niv',
+'niw',
+'nix',
+'niy',
+'niz',
+'nja',
+'njb',
+'njd',
+'njh',
+'nji',
+'njj',
+'njl',
+'njm',
+'njn',
+'njo',
+'njr',
+'njs',
+'njt',
+'nju',
+'njx',
+'njy',
+'njz',
+'nka',
+'nkb',
+'nkc',
+'nkd',
+'nke',
+'nkf',
+'nkg',
+'nkh',
+'nki',
+'nkj',
+'nkk',
+'nkm',
+'nkn',
+'nko',
+'nkp',
+'nkq',
+'nkr',
+'nks',
+'nkt',
+'nku',
+'nkv',
+'nkw',
+'nkx',
+'nkz',
+'nla',
+'nlc',
+'nle',
+'nlg',
+'nli',
+'nlj',
+'nlk',
+'nll',
+'nlm',
+'nln',
+'nlo',
+'nlq',
+'nlr',
+'nlu',
+'nlv',
+'nlw',
+'nlx',
+'nly',
+'nlz',
+'nma',
+'nmb',
+'nmc',
+'nmd',
+'nme',
+'nmf',
+'nmg',
+'nmh',
+'nmi',
+'nmj',
+'nmk',
+'nml',
+'nmm',
+'nmn',
+'nmo',
+'nmp',
+'nmq',
+'nmr',
+'nms',
+'nmt',
+'nmu',
+'nmv',
+'nmw',
+'nmx',
+'nmy',
+'nmz',
+'nna',
+'nnb',
+'nnc',
+'nnd',
+'nne',
+'nnf',
+'nng',
+'nnh',
+'nni',
+'nnj',
+'nnk',
+'nnl',
+'nnm',
+'nnn',
+'nnp',
+'nnq',
+'nnr',
+'nns',
+'nnt',
+'nnu',
+'nnv',
+'nnw',
+'nnx',
+'nny',
+'nnz',
+'noa',
+'noc',
+'nod',
+'noe',
+'nof',
+'nog',
+'noh',
+'noi',
+'noj',
+'nok',
+'nol',
+'nom',
+'non',
+'noo',
+'nop',
+'noq',
+'nos',
+'not',
+'nou',
+'nov',
+'now',
+'noy',
+'noz',
+'npa',
+'npb',
+'npg',
+'nph',
+'npi',
+'npl',
+'npn',
+'npo',
+'nps',
+'npu',
+'npx',
+'npy',
+'nqg',
+'nqk',
+'nql',
+'nqm',
+'nqn',
+'nqo',
+'nqq',
+'nqy',
+'nra',
+'nrb',
+'nrc',
+'nre',
+'nrf',
+'nrg',
+'nri',
+'nrk',
+'nrl',
+'nrm',
+'nrn',
+'nrp',
+'nrr',
+'nrt',
+'nru',
+'nrx',
+'nrz',
+'nsa',
+'nsc',
+'nsd',
+'nse',
+'nsf',
+'nsg',
+'nsh',
+'nsi',
+'nsk',
+'nsl',
+'nsm',
+'nsn',
+'nso',
+'nsp',
+'nsq',
+'nsr',
+'nss',
+'nst',
+'nsu',
+'nsv',
+'nsw',
+'nsx',
+'nsy',
+'nsz',
+'ntd',
+'nte',
+'ntg',
+'nti',
+'ntj',
+'ntk',
+'ntm',
+'nto',
+'ntp',
+'ntr',
+'nts',
+'ntu',
+'ntw',
+'ntx',
+'nty',
+'ntz',
+'nua',
+'nub',
+'nuc',
+'nud',
+'nue',
+'nuf',
+'nug',
+'nuh',
+'nui',
+'nuj',
+'nuk',
+'nul',
+'num',
+'nun',
+'nuo',
+'nup',
+'nuq',
+'nur',
+'nus',
+'nut',
+'nuu',
+'nuv',
+'nuw',
+'nux',
+'nuy',
+'nuz',
+'nvh',
+'nvm',
+'nvo',
+'nwa',
+'nwb',
+'nwc',
+'nwe',
+'nwg',
+'nwi',
+'nwm',
+'nwo',
+'nwr',
+'nwx',
+'nwy',
+'nxa',
+'nxd',
+'nxe',
+'nxg',
+'nxi',
+'nxk',
+'nxl',
+'nxm',
+'nxn',
+'nxo',
+'nxq',
+'nxr',
+'nxu',
+'nxx',
+'nyb',
+'nyc',
+'nyd',
+'nye',
+'nyf',
+'nyg',
+'nyh',
+'nyi',
+'nyj',
+'nyk',
+'nyl',
+'nym',
+'nyn',
+'nyo',
+'nyp',
+'nyq',
+'nyr',
+'nys',
+'nyt',
+'nyu',
+'nyv',
+'nyw',
+'nyx',
+'nyy',
+'nza',
+'nzb',
+'nzd',
+'nzi',
+'nzk',
+'nzm',
+'nzs',
+'nzu',
+'nzy',
+'nzz',
+'oaa',
+'oac',
+'oar',
+'oav',
+'obi',
+'obk',
+'obl',
+'obm',
+'obo',
+'obr',
+'obt',
+'obu',
+'oca',
+'och',
+'oco',
+'ocu',
+'oda',
+'odk',
+'odt',
+'odu',
+'ofo',
+'ofs',
+'ofu',
+'ogb',
+'ogc',
+'oge',
+'ogg',
+'ogo',
+'ogu',
+'oht',
+'ohu',
+'oia',
+'oin',
+'ojb',
+'ojc',
+'ojg',
+'ojp',
+'ojs',
+'ojv',
+'ojw',
+'oka',
+'okb',
+'okd',
+'oke',
+'okg',
+'okh',
+'oki',
+'okj',
+'okk',
+'okl',
+'okm',
+'okn',
+'oko',
+'okr',
+'oks',
+'oku',
+'okv',
+'okx',
+'ola',
+'old',
+'ole',
+'olk',
+'olm',
+'olo',
+'olr',
+'olt',
+'olu',
+'oma',
+'omb',
+'omc',
+'ome',
+'omg',
+'omi',
+'omk',
+'oml',
+'omn',
+'omo',
+'omp',
+'omq',
+'omr',
+'omt',
+'omu',
+'omv',
+'omw',
+'omx',
+'ona',
+'onb',
+'one',
+'ong',
+'oni',
+'onj',
+'onk',
+'onn',
+'ono',
+'onp',
+'onr',
+'ons',
+'ont',
+'onu',
+'onw',
+'onx',
+'ood',
+'oog',
+'oon',
+'oor',
+'oos',
+'opa',
+'opk',
+'opm',
+'opo',
+'opt',
+'opy',
+'ora',
+'orc',
+'ore',
+'org',
+'orh',
+'orn',
+'oro',
+'orr',
+'ors',
+'ort',
+'oru',
+'orv',
+'orw',
+'orx',
+'ory',
+'orz',
+'osa',
+'osc',
+'osi',
+'oso',
+'osp',
+'ost',
+'osu',
+'osx',
+'ota',
+'otb',
+'otd',
+'ote',
+'oti',
+'otk',
+'otl',
+'otm',
+'otn',
+'oto',
+'otq',
+'otr',
+'ots',
+'ott',
+'otu',
+'otw',
+'otx',
+'oty',
+'otz',
+'oua',
+'oub',
+'oue',
+'oui',
+'oum',
+'oun',
+'ovd',
+'owi',
+'owl',
+'oyb',
+'oyd',
+'oym',
+'oyy',
+'ozm',
+'paa',
+'pab',
+'pac',
+'pad',
+'pae',
+'paf',
+'pag',
+'pah',
+'pai',
+'pak',
+'pal',
+'pam',
+'pao',
+'pap',
+'paq',
+'par',
+'pas',
+'pat',
+'pau',
+'pav',
+'paw',
+'pax',
+'pay',
+'paz',
+'pbb',
+'pbc',
+'pbe',
+'pbf',
+'pbg',
+'pbh',
+'pbi',
+'pbl',
+'pbm',
+'pbn',
+'pbo',
+'pbp',
+'pbr',
+'pbs',
+'pbt',
+'pbu',
+'pbv',
+'pby',
+'pbz',
+'pca',
+'pcb',
+'pcc',
+'pcd',
+'pce',
+'pcf',
+'pcg',
+'pch',
+'pci',
+'pcj',
+'pck',
+'pcl',
+'pcm',
+'pcn',
+'pcp',
+'pcr',
+'pcw',
+'pda',
+'pdc',
+'pdi',
+'pdn',
+'pdo',
+'pdt',
+'pdu',
+'pea',
+'peb',
+'ped',
+'pee',
+'pef',
+'peg',
+'peh',
+'pei',
+'pej',
+'pek',
+'pel',
+'pem',
+'peo',
+'pep',
+'peq',
+'pes',
+'pev',
+'pex',
+'pey',
+'pez',
+'pfa',
+'pfe',
+'pfl',
+'pga',
+'pgd',
+'pgg',
+'pgi',
+'pgk',
+'pgl',
+'pgn',
+'pgs',
+'pgu',
+'pgy',
+'pgz',
+'pha',
+'phd',
+'phg',
+'phh',
+'phi',
+'phk',
+'phl',
+'phm',
+'phn',
+'pho',
+'phq',
+'phr',
+'pht',
+'phu',
+'phv',
+'phw',
+'pia',
+'pib',
+'pic',
+'pid',
+'pie',
+'pif',
+'pig',
+'pih',
+'pii',
+'pij',
+'pil',
+'pim',
+'pin',
+'pio',
+'pip',
+'pir',
+'pis',
+'pit',
+'piu',
+'piv',
+'piw',
+'pix',
+'piy',
+'piz',
+'pjt',
+'pka',
+'pkb',
+'pkc',
+'pkg',
+'pkh',
+'pkn',
+'pko',
+'pkp',
+'pkr',
+'pks',
+'pkt',
+'pku',
+'pla',
+'plb',
+'plc',
+'pld',
+'ple',
+'plf',
+'plg',
+'plh',
+'plj',
+'plk',
+'pll',
+'pln',
+'plo',
+'plp',
+'plq',
+'plr',
+'pls',
+'plt',
+'plu',
+'plv',
+'plw',
+'ply',
+'plz',
+'pma',
+'pmb',
+'pmc',
+'pmd',
+'pme',
+'pmf',
+'pmh',
+'pmi',
+'pmj',
+'pmk',
+'pml',
+'pmm',
+'pmn',
+'pmo',
+'pmq',
+'pmr',
+'pms',
+'pmt',
+'pmu',
+'pmw',
+'pmx',
+'pmy',
+'pmz',
+'pna',
+'pnb',
+'pnc',
+'pne',
+'png',
+'pnh',
+'pni',
+'pnj',
+'pnk',
+'pnl',
+'pnm',
+'pnn',
+'pno',
+'pnp',
+'pnq',
+'pnr',
+'pns',
+'pnt',
+'pnu',
+'pnv',
+'pnw',
+'pnx',
+'pny',
+'pnz',
+'poc',
+'pod',
+'poe',
+'pof',
+'pog',
+'poh',
+'poi',
+'pok',
+'pom',
+'pon',
+'poo',
+'pop',
+'poq',
+'pos',
+'pot',
+'pov',
+'pow',
+'pox',
+'poy',
+'poz',
+'ppa',
+'ppe',
+'ppi',
+'ppk',
+'ppl',
+'ppm',
+'ppn',
+'ppo',
+'ppp',
+'ppq',
+'ppr',
+'pps',
+'ppt',
+'ppu',
+'pqa',
+'pqe',
+'pqm',
+'pqw',
+'pra',
+'prb',
+'prc',
+'prd',
+'pre',
+'prf',
+'prg',
+'prh',
+'pri',
+'prk',
+'prl',
+'prm',
+'prn',
+'pro',
+'prp',
+'prq',
+'prr',
+'prs',
+'prt',
+'pru',
+'prw',
+'prx',
+'pry',
+'prz',
+'psa',
+'psc',
+'psd',
+'pse',
+'psg',
+'psh',
+'psi',
+'psl',
+'psm',
+'psn',
+'pso',
+'psp',
+'psq',
+'psr',
+'pss',
+'pst',
+'psu',
+'psw',
+'psy',
+'pta',
+'pth',
+'pti',
+'ptn',
+'pto',
+'ptp',
+'ptq',
+'ptr',
+'ptt',
+'ptu',
+'ptv',
+'ptw',
+'pty',
+'pua',
+'pub',
+'puc',
+'pud',
+'pue',
+'puf',
+'pug',
+'pui',
+'puj',
+'puk',
+'pum',
+'puo',
+'pup',
+'puq',
+'pur',
+'put',
+'puu',
+'puw',
+'pux',
+'puy',
+'puz',
+'pwa',
+'pwb',
+'pwg',
+'pwi',
+'pwm',
+'pwn',
+'pwo',
+'pwr',
+'pww',
+'pxm',
+'pye',
+'pym',
+'pyn',
+'pys',
+'pyu',
+'pyx',
+'pyy',
+'pzn',
+'qaa..qtz',
+'qua',
+'qub',
+'quc',
+'qud',
+'quf',
+'qug',
+'quh',
+'qui',
+'quk',
+'qul',
+'qum',
+'qun',
+'qup',
+'quq',
+'qur',
+'qus',
+'quv',
+'quw',
+'qux',
+'quy',
+'quz',
+'qva',
+'qvc',
+'qve',
+'qvh',
+'qvi',
+'qvj',
+'qvl',
+'qvm',
+'qvn',
+'qvo',
+'qvp',
+'qvs',
+'qvw',
+'qvy',
+'qvz',
+'qwa',
+'qwc',
+'qwe',
+'qwh',
+'qwm',
+'qws',
+'qwt',
+'qxa',
+'qxc',
+'qxh',
+'qxl',
+'qxn',
+'qxo',
+'qxp',
+'qxq',
+'qxr',
+'qxs',
+'qxt',
+'qxu',
+'qxw',
+'qya',
+'qyp',
+'raa',
+'rab',
+'rac',
+'rad',
+'raf',
+'rag',
+'rah',
+'rai',
+'raj',
+'rak',
+'ral',
+'ram',
+'ran',
+'rao',
+'rap',
+'raq',
+'rar',
+'ras',
+'rat',
+'rau',
+'rav',
+'raw',
+'rax',
+'ray',
+'raz',
+'rbb',
+'rbk',
+'rbl',
+'rbp',
+'rcf',
+'rdb',
+'rea',
+'reb',
+'ree',
+'reg',
+'rei',
+'rej',
+'rel',
+'rem',
+'ren',
+'rer',
+'res',
+'ret',
+'rey',
+'rga',
+'rge',
+'rgk',
+'rgn',
+'rgr',
+'rgs',
+'rgu',
+'rhg',
+'rhp',
+'ria',
+'rie',
+'rif',
+'ril',
+'rim',
+'rin',
+'rir',
+'rit',
+'riu',
+'rjg',
+'rji',
+'rjs',
+'rka',
+'rkb',
+'rkh',
+'rki',
+'rkm',
+'rkt',
+'rkw',
+'rma',
+'rmb',
+'rmc',
+'rmd',
+'rme',
+'rmf',
+'rmg',
+'rmh',
+'rmi',
+'rmk',
+'rml',
+'rmm',
+'rmn',
+'rmo',
+'rmp',
+'rmq',
+'rmr',
+'rms',
+'rmt',
+'rmu',
+'rmv',
+'rmw',
+'rmx',
+'rmy',
+'rmz',
+'rna',
+'rnd',
+'rng',
+'rnl',
+'rnn',
+'rnp',
+'rnr',
+'rnw',
+'roa',
+'rob',
+'roc',
+'rod',
+'roe',
+'rof',
+'rog',
+'rol',
+'rom',
+'roo',
+'rop',
+'ror',
+'rou',
+'row',
+'rpn',
+'rpt',
+'rri',
+'rro',
+'rrt',
+'rsb',
+'rsi',
+'rsl',
+'rsm',
+'rtc',
+'rth',
+'rtm',
+'rts',
+'rtw',
+'rub',
+'ruc',
+'rue',
+'ruf',
+'rug',
+'ruh',
+'rui',
+'ruk',
+'ruo',
+'rup',
+'ruq',
+'rut',
+'ruu',
+'ruy',
+'ruz',
+'rwa',
+'rwk',
+'rwm',
+'rwo',
+'rwr',
+'rxd',
+'rxw',
+'ryn',
+'rys',
+'ryu',
+'rzh',
+'saa',
+'sab',
+'sac',
+'sad',
+'sae',
+'saf',
+'sah',
+'sai',
+'saj',
+'sak',
+'sal',
+'sam',
+'sao',
+'sap',
+'saq',
+'sar',
+'sas',
+'sat',
+'sau',
+'sav',
+'saw',
+'sax',
+'say',
+'saz',
+'sba',
+'sbb',
+'sbc',
+'sbd',
+'sbe',
+'sbf',
+'sbg',
+'sbh',
+'sbi',
+'sbj',
+'sbk',
+'sbl',
+'sbm',
+'sbn',
+'sbo',
+'sbp',
+'sbq',
+'sbr',
+'sbs',
+'sbt',
+'sbu',
+'sbv',
+'sbw',
+'sbx',
+'sby',
+'sbz',
+'sca',
+'scb',
+'sce',
+'scf',
+'scg',
+'sch',
+'sci',
+'sck',
+'scl',
+'scn',
+'sco',
+'scp',
+'scq',
+'scs',
+'sct',
+'scu',
+'scv',
+'scw',
+'scx',
+'sda',
+'sdb',
+'sdc',
+'sde',
+'sdf',
+'sdg',
+'sdh',
+'sdj',
+'sdk',
+'sdl',
+'sdm',
+'sdn',
+'sdo',
+'sdp',
+'sdr',
+'sds',
+'sdt',
+'sdu',
+'sdv',
+'sdx',
+'sdz',
+'sea',
+'seb',
+'sec',
+'sed',
+'see',
+'sef',
+'seg',
+'seh',
+'sei',
+'sej',
+'sek',
+'sel',
+'sem',
+'sen',
+'seo',
+'sep',
+'seq',
+'ser',
+'ses',
+'set',
+'seu',
+'sev',
+'sew',
+'sey',
+'sez',
+'sfb',
+'sfe',
+'sfm',
+'sfs',
+'sfw',
+'sga',
+'sgb',
+'sgc',
+'sgd',
+'sge',
+'sgg',
+'sgh',
+'sgi',
+'sgj',
+'sgk',
+'sgl',
+'sgm',
+'sgn',
+'sgo',
+'sgp',
+'sgr',
+'sgs',
+'sgt',
+'sgu',
+'sgw',
+'sgx',
+'sgy',
+'sgz',
+'sha',
+'shb',
+'shc',
+'shd',
+'she',
+'shg',
+'shh',
+'shi',
+'shj',
+'shk',
+'shl',
+'shm',
+'shn',
+'sho',
+'shp',
+'shq',
+'shr',
+'shs',
+'sht',
+'shu',
+'shv',
+'shw',
+'shx',
+'shy',
+'shz',
+'sia',
+'sib',
+'sid',
+'sie',
+'sif',
+'sig',
+'sih',
+'sii',
+'sij',
+'sik',
+'sil',
+'sim',
+'sio',
+'sip',
+'siq',
+'sir',
+'sis',
+'sit',
+'siu',
+'siv',
+'siw',
+'six',
+'siy',
+'siz',
+'sja',
+'sjb',
+'sjd',
+'sje',
+'sjg',
+'sjk',
+'sjl',
+'sjm',
+'sjn',
+'sjo',
+'sjp',
+'sjr',
+'sjs',
+'sjt',
+'sju',
+'sjw',
+'ska',
+'skb',
+'skc',
+'skd',
+'ske',
+'skf',
+'skg',
+'skh',
+'ski',
+'skj',
+'skk',
+'skm',
+'skn',
+'sko',
+'skp',
+'skq',
+'skr',
+'sks',
+'skt',
+'sku',
+'skv',
+'skw',
+'skx',
+'sky',
+'skz',
+'sla',
+'slc',
+'sld',
+'sle',
+'slf',
+'slg',
+'slh',
+'sli',
+'slj',
+'sll',
+'slm',
+'sln',
+'slp',
+'slq',
+'slr',
+'sls',
+'slt',
+'slu',
+'slw',
+'slx',
+'sly',
+'slz',
+'sma',
+'smb',
+'smc',
+'smd',
+'smf',
+'smg',
+'smh',
+'smi',
+'smj',
+'smk',
+'sml',
+'smm',
+'smn',
+'smp',
+'smq',
+'smr',
+'sms',
+'smt',
+'smu',
+'smv',
+'smw',
+'smx',
+'smy',
+'smz',
+'snb',
+'snc',
+'sne',
+'snf',
+'sng',
+'snh',
+'sni',
+'snj',
+'snk',
+'snl',
+'snm',
+'snn',
+'sno',
+'snp',
+'snq',
+'snr',
+'sns',
+'snu',
+'snv',
+'snw',
+'snx',
+'sny',
+'snz',
+'soa',
+'sob',
+'soc',
+'sod',
+'soe',
+'sog',
+'soh',
+'soi',
+'soj',
+'sok',
+'sol',
+'son',
+'soo',
+'sop',
+'soq',
+'sor',
+'sos',
+'sou',
+'sov',
+'sow',
+'sox',
+'soy',
+'soz',
+'spb',
+'spc',
+'spd',
+'spe',
+'spg',
+'spi',
+'spk',
+'spl',
+'spm',
+'spn',
+'spo',
+'spp',
+'spq',
+'spr',
+'sps',
+'spt',
+'spu',
+'spv',
+'spx',
+'spy',
+'sqa',
+'sqh',
+'sqj',
+'sqk',
+'sqm',
+'sqn',
+'sqo',
+'sqq',
+'sqr',
+'sqs',
+'sqt',
+'squ',
+'sra',
+'srb',
+'src',
+'sre',
+'srf',
+'srg',
+'srh',
+'sri',
+'srk',
+'srl',
+'srm',
+'srn',
+'sro',
+'srq',
+'srr',
+'srs',
+'srt',
+'sru',
+'srv',
+'srw',
+'srx',
+'sry',
+'srz',
+'ssa',
+'ssb',
+'ssc',
+'ssd',
+'sse',
+'ssf',
+'ssg',
+'ssh',
+'ssi',
+'ssj',
+'ssk',
+'ssl',
+'ssm',
+'ssn',
+'sso',
+'ssp',
+'ssq',
+'ssr',
+'sss',
+'sst',
+'ssu',
+'ssv',
+'ssx',
+'ssy',
+'ssz',
+'sta',
+'stb',
+'std',
+'ste',
+'stf',
+'stg',
+'sth',
+'sti',
+'stj',
+'stk',
+'stl',
+'stm',
+'stn',
+'sto',
+'stp',
+'stq',
+'str',
+'sts',
+'stt',
+'stu',
+'stv',
+'stw',
+'sty',
+'sua',
+'sub',
+'suc',
+'sue',
+'sug',
+'sui',
+'suj',
+'suk',
+'sul',
+'sum',
+'suq',
+'sur',
+'sus',
+'sut',
+'suv',
+'suw',
+'sux',
+'suy',
+'suz',
+'sva',
+'svb',
+'svc',
+'sve',
+'svk',
+'svm',
+'svr',
+'svs',
+'svx',
+'swb',
+'swc',
+'swf',
+'swg',
+'swh',
+'swi',
+'swj',
+'swk',
+'swl',
+'swm',
+'swn',
+'swo',
+'swp',
+'swq',
+'swr',
+'sws',
+'swt',
+'swu',
+'swv',
+'sww',
+'swx',
+'swy',
+'sxb',
+'sxc',
+'sxe',
+'sxg',
+'sxk',
+'sxl',
+'sxm',
+'sxn',
+'sxo',
+'sxr',
+'sxs',
+'sxu',
+'sxw',
+'sya',
+'syb',
+'syc',
+'syd',
+'syi',
+'syk',
+'syl',
+'sym',
+'syn',
+'syo',
+'syr',
+'sys',
+'syw',
+'syx',
+'syy',
+'sza',
+'szb',
+'szc',
+'szd',
+'sze',
+'szg',
+'szl',
+'szn',
+'szp',
+'szs',
+'szv',
+'szw',
+'taa',
+'tab',
+'tac',
+'tad',
+'tae',
+'taf',
+'tag',
+'tai',
+'taj',
+'tak',
+'tal',
+'tan',
+'tao',
+'tap',
+'taq',
+'tar',
+'tas',
+'tau',
+'tav',
+'taw',
+'tax',
+'tay',
+'taz',
+'tba',
+'tbb',
+'tbc',
+'tbd',
+'tbe',
+'tbf',
+'tbg',
+'tbh',
+'tbi',
+'tbj',
+'tbk',
+'tbl',
+'tbm',
+'tbn',
+'tbo',
+'tbp',
+'tbq',
+'tbr',
+'tbs',
+'tbt',
+'tbu',
+'tbv',
+'tbw',
+'tbx',
+'tby',
+'tbz',
+'tca',
+'tcb',
+'tcc',
+'tcd',
+'tce',
+'tcf',
+'tcg',
+'tch',
+'tci',
+'tck',
+'tcl',
+'tcm',
+'tcn',
+'tco',
+'tcp',
+'tcq',
+'tcs',
+'tct',
+'tcu',
+'tcw',
+'tcx',
+'tcy',
+'tcz',
+'tda',
+'tdb',
+'tdc',
+'tdd',
+'tde',
+'tdf',
+'tdg',
+'tdh',
+'tdi',
+'tdj',
+'tdk',
+'tdl',
+'tdm',
+'tdn',
+'tdo',
+'tdq',
+'tdr',
+'tds',
+'tdt',
+'tdu',
+'tdv',
+'tdx',
+'tdy',
+'tea',
+'teb',
+'tec',
+'ted',
+'tee',
+'tef',
+'teg',
+'teh',
+'tei',
+'tek',
+'tem',
+'ten',
+'teo',
+'tep',
+'teq',
+'ter',
+'tes',
+'tet',
+'teu',
+'tev',
+'tew',
+'tex',
+'tey',
+'tez',
+'tfi',
+'tfn',
+'tfo',
+'tfr',
+'tft',
+'tga',
+'tgb',
+'tgc',
+'tgd',
+'tge',
+'tgf',
+'tgg',
+'tgh',
+'tgi',
+'tgj',
+'tgn',
+'tgo',
+'tgp',
+'tgq',
+'tgr',
+'tgs',
+'tgt',
+'tgu',
+'tgv',
+'tgw',
+'tgx',
+'tgy',
+'tgz',
+'thc',
+'thd',
+'the',
+'thf',
+'thh',
+'thi',
+'thk',
+'thl',
+'thm',
+'thn',
+'thp',
+'thq',
+'thr',
+'ths',
+'tht',
+'thu',
+'thv',
+'thw',
+'thx',
+'thy',
+'thz',
+'tia',
+'tic',
+'tid',
+'tie',
+'tif',
+'tig',
+'tih',
+'tii',
+'tij',
+'tik',
+'til',
+'tim',
+'tin',
+'tio',
+'tip',
+'tiq',
+'tis',
+'tit',
+'tiu',
+'tiv',
+'tiw',
+'tix',
+'tiy',
+'tiz',
+'tja',
+'tjg',
+'tji',
+'tjl',
+'tjm',
+'tjn',
+'tjo',
+'tjs',
+'tju',
+'tjw',
+'tka',
+'tkb',
+'tkd',
+'tke',
+'tkf',
+'tkg',
+'tkk',
+'tkl',
+'tkm',
+'tkn',
+'tkp',
+'tkq',
+'tkr',
+'tks',
+'tkt',
+'tku',
+'tkv',
+'tkw',
+'tkx',
+'tkz',
+'tla',
+'tlb',
+'tlc',
+'tld',
+'tlf',
+'tlg',
+'tlh',
+'tli',
+'tlj',
+'tlk',
+'tll',
+'tlm',
+'tln',
+'tlo',
+'tlp',
+'tlq',
+'tlr',
+'tls',
+'tlt',
+'tlu',
+'tlv',
+'tlw',
+'tlx',
+'tly',
+'tma',
+'tmb',
+'tmc',
+'tmd',
+'tme',
+'tmf',
+'tmg',
+'tmh',
+'tmi',
+'tmj',
+'tmk',
+'tml',
+'tmm',
+'tmn',
+'tmo',
+'tmp',
+'tmq',
+'tmr',
+'tms',
+'tmt',
+'tmu',
+'tmv',
+'tmw',
+'tmy',
+'tmz',
+'tna',
+'tnb',
+'tnc',
+'tnd',
+'tne',
+'tnf',
+'tng',
+'tnh',
+'tni',
+'tnk',
+'tnl',
+'tnm',
+'tnn',
+'tno',
+'tnp',
+'tnq',
+'tnr',
+'tns',
+'tnt',
+'tnu',
+'tnv',
+'tnw',
+'tnx',
+'tny',
+'tnz',
+'tob',
+'toc',
+'tod',
+'toe',
+'tof',
+'tog',
+'toh',
+'toi',
+'toj',
+'tol',
+'tom',
+'too',
+'top',
+'toq',
+'tor',
+'tos',
+'tou',
+'tov',
+'tow',
+'tox',
+'toy',
+'toz',
+'tpa',
+'tpc',
+'tpe',
+'tpf',
+'tpg',
+'tpi',
+'tpj',
+'tpk',
+'tpl',
+'tpm',
+'tpn',
+'tpo',
+'tpp',
+'tpq',
+'tpr',
+'tpt',
+'tpu',
+'tpv',
+'tpw',
+'tpx',
+'tpy',
+'tpz',
+'tqb',
+'tql',
+'tqm',
+'tqn',
+'tqo',
+'tqp',
+'tqq',
+'tqr',
+'tqt',
+'tqu',
+'tqw',
+'tra',
+'trb',
+'trc',
+'trd',
+'tre',
+'trf',
+'trg',
+'trh',
+'tri',
+'trj',
+'trk',
+'trl',
+'trm',
+'trn',
+'tro',
+'trp',
+'trq',
+'trr',
+'trs',
+'trt',
+'tru',
+'trv',
+'trw',
+'trx',
+'try',
+'trz',
+'tsa',
+'tsb',
+'tsc',
+'tsd',
+'tse',
+'tsf',
+'tsg',
+'tsh',
+'tsi',
+'tsj',
+'tsk',
+'tsl',
+'tsm',
+'tsp',
+'tsq',
+'tsr',
+'tss',
+'tst',
+'tsu',
+'tsv',
+'tsw',
+'tsx',
+'tsy',
+'tsz',
+'tta',
+'ttb',
+'ttc',
+'ttd',
+'tte',
+'ttf',
+'ttg',
+'tth',
+'tti',
+'ttj',
+'ttk',
+'ttl',
+'ttm',
+'ttn',
+'tto',
+'ttp',
+'ttq',
+'ttr',
+'tts',
+'ttt',
+'ttu',
+'ttv',
+'ttw',
+'tty',
+'ttz',
+'tua',
+'tub',
+'tuc',
+'tud',
+'tue',
+'tuf',
+'tug',
+'tuh',
+'tui',
+'tuj',
+'tul',
+'tum',
+'tun',
+'tuo',
+'tup',
+'tuq',
+'tus',
+'tut',
+'tuu',
+'tuv',
+'tuw',
+'tux',
+'tuy',
+'tuz',
+'tva',
+'tvd',
+'tve',
+'tvk',
+'tvl',
+'tvm',
+'tvn',
+'tvo',
+'tvs',
+'tvt',
+'tvu',
+'tvw',
+'tvy',
+'twa',
+'twb',
+'twc',
+'twd',
+'twe',
+'twf',
+'twg',
+'twh',
+'twl',
+'twm',
+'twn',
+'two',
+'twp',
+'twq',
+'twr',
+'twt',
+'twu',
+'tww',
+'twx',
+'twy',
+'txa',
+'txb',
+'txc',
+'txe',
+'txg',
+'txh',
+'txi',
+'txj',
+'txm',
+'txn',
+'txo',
+'txq',
+'txr',
+'txs',
+'txt',
+'txu',
+'txx',
+'txy',
+'tya',
+'tye',
+'tyh',
+'tyi',
+'tyj',
+'tyl',
+'tyn',
+'typ',
+'tyr',
+'tys',
+'tyt',
+'tyu',
+'tyv',
+'tyx',
+'tyz',
+'tza',
+'tzh',
+'tzj',
+'tzl',
+'tzm',
+'tzn',
+'tzo',
+'tzx',
+'uam',
+'uan',
+'uar',
+'uba',
+'ubi',
+'ubl',
+'ubr',
+'ubu',
+'uby',
+'uda',
+'ude',
+'udg',
+'udi',
+'udj',
+'udl',
+'udm',
+'udu',
+'ues',
+'ufi',
+'uga',
+'ugb',
+'uge',
+'ugn',
+'ugo',
+'ugy',
+'uha',
+'uhn',
+'uis',
+'uiv',
+'uji',
+'uka',
+'ukg',
+'ukh',
+'ukk',
+'ukl',
+'ukp',
+'ukq',
+'uks',
+'uku',
+'ukw',
+'uky',
+'ula',
+'ulb',
+'ulc',
+'ule',
+'ulf',
+'uli',
+'ulk',
+'ull',
+'ulm',
+'uln',
+'ulu',
+'ulw',
+'uma',
+'umb',
+'umc',
+'umd',
+'umg',
+'umi',
+'umm',
+'umn',
+'umo',
+'ump',
+'umr',
+'ums',
+'umu',
+'una',
+'und',
+'une',
+'ung',
+'unk',
+'unm',
+'unn',
+'unp',
+'unr',
+'unu',
+'unx',
+'unz',
+'uok',
+'upi',
+'upv',
+'ura',
+'urb',
+'urc',
+'ure',
+'urf',
+'urg',
+'urh',
+'uri',
+'urj',
+'urk',
+'url',
+'urm',
+'urn',
+'uro',
+'urp',
+'urr',
+'urt',
+'uru',
+'urv',
+'urw',
+'urx',
+'ury',
+'urz',
+'usa',
+'ush',
+'usi',
+'usk',
+'usp',
+'usu',
+'uta',
+'ute',
+'utp',
+'utr',
+'utu',
+'uum',
+'uun',
+'uur',
+'uuu',
+'uve',
+'uvh',
+'uvl',
+'uwa',
+'uya',
+'uzn',
+'uzs',
+'vaa',
+'vae',
+'vaf',
+'vag',
+'vah',
+'vai',
+'vaj',
+'val',
+'vam',
+'van',
+'vao',
+'vap',
+'var',
+'vas',
+'vau',
+'vav',
+'vay',
+'vbb',
+'vbk',
+'vec',
+'ved',
+'vel',
+'vem',
+'veo',
+'vep',
+'ver',
+'vgr',
+'vgt',
+'vic',
+'vid',
+'vif',
+'vig',
+'vil',
+'vin',
+'vis',
+'vit',
+'viv',
+'vka',
+'vki',
+'vkj',
+'vkk',
+'vkl',
+'vkm',
+'vko',
+'vkp',
+'vkt',
+'vku',
+'vlp',
+'vls',
+'vma',
+'vmb',
+'vmc',
+'vmd',
+'vme',
+'vmf',
+'vmg',
+'vmh',
+'vmi',
+'vmj',
+'vmk',
+'vml',
+'vmm',
+'vmp',
+'vmq',
+'vmr',
+'vms',
+'vmu',
+'vmv',
+'vmw',
+'vmx',
+'vmy',
+'vmz',
+'vnk',
+'vnm',
+'vnp',
+'vor',
+'vot',
+'vra',
+'vro',
+'vrs',
+'vrt',
+'vsi',
+'vsl',
+'vsv',
+'vto',
+'vum',
+'vun',
+'vut',
+'vwa',
+'waa',
+'wab',
+'wac',
+'wad',
+'wae',
+'waf',
+'wag',
+'wah',
+'wai',
+'waj',
+'wak',
+'wal',
+'wam',
+'wan',
+'wao',
+'wap',
+'waq',
+'war',
+'was',
+'wat',
+'wau',
+'wav',
+'waw',
+'wax',
+'way',
+'waz',
+'wba',
+'wbb',
+'wbe',
+'wbf',
+'wbh',
+'wbi',
+'wbj',
+'wbk',
+'wbl',
+'wbm',
+'wbp',
+'wbq',
+'wbr',
+'wbs',
+'wbt',
+'wbv',
+'wbw',
+'wca',
+'wci',
+'wdd',
+'wdg',
+'wdj',
+'wdk',
+'wdu',
+'wdy',
+'wea',
+'wec',
+'wed',
+'weg',
+'weh',
+'wei',
+'wem',
+'wen',
+'weo',
+'wep',
+'wer',
+'wes',
+'wet',
+'weu',
+'wew',
+'wfg',
+'wga',
+'wgb',
+'wgg',
+'wgi',
+'wgo',
+'wgu',
+'wgw',
+'wgy',
+'wha',
+'whg',
+'whk',
+'whu',
+'wib',
+'wic',
+'wie',
+'wif',
+'wig',
+'wih',
+'wii',
+'wij',
+'wik',
+'wil',
+'wim',
+'win',
+'wir',
+'wit',
+'wiu',
+'wiv',
+'wiw',
+'wiy',
+'wja',
+'wji',
+'wka',
+'wkb',
+'wkd',
+'wkl',
+'wku',
+'wkw',
+'wky',
+'wla',
+'wlc',
+'wle',
+'wlg',
+'wli',
+'wlk',
+'wll',
+'wlm',
+'wlo',
+'wlr',
+'wls',
+'wlu',
+'wlv',
+'wlw',
+'wlx',
+'wly',
+'wma',
+'wmb',
+'wmc',
+'wmd',
+'wme',
+'wmh',
+'wmi',
+'wmm',
+'wmn',
+'wmo',
+'wms',
+'wmt',
+'wmw',
+'wmx',
+'wnb',
+'wnc',
+'wnd',
+'wne',
+'wng',
+'wni',
+'wnk',
+'wnm',
+'wnn',
+'wno',
+'wnp',
+'wnu',
+'wnw',
+'wny',
+'woa',
+'wob',
+'woc',
+'wod',
+'woe',
+'wof',
+'wog',
+'woi',
+'wok',
+'wom',
+'won',
+'woo',
+'wor',
+'wos',
+'wow',
+'woy',
+'wpc',
+'wra',
+'wrb',
+'wrd',
+'wrg',
+'wrh',
+'wri',
+'wrk',
+'wrl',
+'wrm',
+'wrn',
+'wro',
+'wrp',
+'wrr',
+'wrs',
+'wru',
+'wrv',
+'wrw',
+'wrx',
+'wry',
+'wrz',
+'wsa',
+'wsg',
+'wsi',
+'wsk',
+'wsr',
+'wss',
+'wsu',
+'wsv',
+'wtf',
+'wth',
+'wti',
+'wtk',
+'wtm',
+'wtw',
+'wua',
+'wub',
+'wud',
+'wuh',
+'wul',
+'wum',
+'wun',
+'wur',
+'wut',
+'wuu',
+'wuv',
+'wux',
+'wuy',
+'wwa',
+'wwb',
+'wwo',
+'wwr',
+'www',
+'wxa',
+'wxw',
+'wya',
+'wyb',
+'wyi',
+'wym',
+'wyr',
+'wyy',
+'xaa',
+'xab',
+'xac',
+'xad',
+'xae',
+'xag',
+'xai',
+'xaj',
+'xak',
+'xal',
+'xam',
+'xan',
+'xao',
+'xap',
+'xaq',
+'xar',
+'xas',
+'xat',
+'xau',
+'xav',
+'xaw',
+'xay',
+'xba',
+'xbb',
+'xbc',
+'xbd',
+'xbe',
+'xbg',
+'xbi',
+'xbj',
+'xbm',
+'xbn',
+'xbo',
+'xbp',
+'xbr',
+'xbw',
+'xbx',
+'xby',
+'xcb',
+'xcc',
+'xce',
+'xcg',
+'xch',
+'xcl',
+'xcm',
+'xcn',
+'xco',
+'xcr',
+'xct',
+'xcu',
+'xcv',
+'xcw',
+'xcy',
+'xda',
+'xdc',
+'xdk',
+'xdm',
+'xdo',
+'xdy',
+'xeb',
+'xed',
+'xeg',
+'xel',
+'xem',
+'xep',
+'xer',
+'xes',
+'xet',
+'xeu',
+'xfa',
+'xga',
+'xgb',
+'xgd',
+'xgf',
+'xgg',
+'xgi',
+'xgl',
+'xgm',
+'xgn',
+'xgr',
+'xgu',
+'xgw',
+'xha',
+'xhc',
+'xhd',
+'xhe',
+'xhr',
+'xht',
+'xhu',
+'xhv',
+'xia',
+'xib',
+'xii',
+'xil',
+'xin',
+'xip',
+'xir',
+'xis',
+'xiv',
+'xiy',
+'xjb',
+'xjt',
+'xka',
+'xkb',
+'xkc',
+'xkd',
+'xke',
+'xkf',
+'xkg',
+'xkh',
+'xki',
+'xkj',
+'xkk',
+'xkl',
+'xkn',
+'xko',
+'xkp',
+'xkq',
+'xkr',
+'xks',
+'xkt',
+'xku',
+'xkv',
+'xkw',
+'xkx',
+'xky',
+'xkz',
+'xla',
+'xlb',
+'xlc',
+'xld',
+'xle',
+'xlg',
+'xli',
+'xln',
+'xlo',
+'xlp',
+'xls',
+'xlu',
+'xly',
+'xma',
+'xmb',
+'xmc',
+'xmd',
+'xme',
+'xmf',
+'xmg',
+'xmh',
+'xmj',
+'xmk',
+'xml',
+'xmm',
+'xmn',
+'xmo',
+'xmp',
+'xmq',
+'xmr',
+'xms',
+'xmt',
+'xmu',
+'xmv',
+'xmw',
+'xmx',
+'xmy',
+'xmz',
+'xna',
+'xnb',
+'xnd',
+'xng',
+'xnh',
+'xni',
+'xnk',
+'xnn',
+'xno',
+'xnr',
+'xns',
+'xnt',
+'xnu',
+'xny',
+'xnz',
+'xoc',
+'xod',
+'xog',
+'xoi',
+'xok',
+'xom',
+'xon',
+'xoo',
+'xop',
+'xor',
+'xow',
+'xpa',
+'xpc',
+'xpe',
+'xpg',
+'xpi',
+'xpj',
+'xpk',
+'xpm',
+'xpn',
+'xpo',
+'xpp',
+'xpq',
+'xpr',
+'xps',
+'xpt',
+'xpu',
+'xpy',
+'xqa',
+'xqt',
+'xra',
+'xrb',
+'xrd',
+'xre',
+'xrg',
+'xri',
+'xrm',
+'xrn',
+'xrq',
+'xrr',
+'xrt',
+'xru',
+'xrw',
+'xsa',
+'xsb',
+'xsc',
+'xsd',
+'xse',
+'xsh',
+'xsi',
+'xsj',
+'xsl',
+'xsm',
+'xsn',
+'xso',
+'xsp',
+'xsq',
+'xsr',
+'xss',
+'xsu',
+'xsv',
+'xsy',
+'xta',
+'xtb',
+'xtc',
+'xtd',
+'xte',
+'xtg',
+'xth',
+'xti',
+'xtj',
+'xtl',
+'xtm',
+'xtn',
+'xto',
+'xtp',
+'xtq',
+'xtr',
+'xts',
+'xtt',
+'xtu',
+'xtv',
+'xtw',
+'xty',
+'xtz',
+'xua',
+'xub',
+'xud',
+'xug',
+'xuj',
+'xul',
+'xum',
+'xun',
+'xuo',
+'xup',
+'xur',
+'xut',
+'xuu',
+'xve',
+'xvi',
+'xvn',
+'xvo',
+'xvs',
+'xwa',
+'xwc',
+'xwd',
+'xwe',
+'xwg',
+'xwj',
+'xwk',
+'xwl',
+'xwo',
+'xwr',
+'xwt',
+'xww',
+'xxb',
+'xxk',
+'xxm',
+'xxr',
+'xxt',
+'xya',
+'xyb',
+'xyj',
+'xyk',
+'xyl',
+'xyt',
+'xyy',
+'xzh',
+'xzm',
+'xzp',
+'yaa',
+'yab',
+'yac',
+'yad',
+'yae',
+'yaf',
+'yag',
+'yah',
+'yai',
+'yaj',
+'yak',
+'yal',
+'yam',
+'yan',
+'yao',
+'yap',
+'yaq',
+'yar',
+'yas',
+'yat',
+'yau',
+'yav',
+'yaw',
+'yax',
+'yay',
+'yaz',
+'yba',
+'ybb',
+'ybd',
+'ybe',
+'ybh',
+'ybi',
+'ybj',
+'ybk',
+'ybl',
+'ybm',
+'ybn',
+'ybo',
+'ybx',
+'yby',
+'ych',
+'ycl',
+'ycn',
+'ycp',
+'yda',
+'ydd',
+'yde',
+'ydg',
+'ydk',
+'yds',
+'yea',
+'yec',
+'yee',
+'yei',
+'yej',
+'yel',
+'yen',
+'yer',
+'yes',
+'yet',
+'yeu',
+'yev',
+'yey',
+'yga',
+'ygi',
+'ygl',
+'ygm',
+'ygp',
+'ygr',
+'ygs',
+'ygu',
+'ygw',
+'yha',
+'yhd',
+'yhl',
+'yhs',
+'yia',
+'yif',
+'yig',
+'yih',
+'yii',
+'yij',
+'yik',
+'yil',
+'yim',
+'yin',
+'yip',
+'yiq',
+'yir',
+'yis',
+'yit',
+'yiu',
+'yiv',
+'yix',
+'yiy',
+'yiz',
+'yka',
+'ykg',
+'yki',
+'ykk',
+'ykl',
+'ykm',
+'ykn',
+'yko',
+'ykr',
+'ykt',
+'yku',
+'yky',
+'yla',
+'ylb',
+'yle',
+'ylg',
+'yli',
+'yll',
+'ylm',
+'yln',
+'ylo',
+'ylr',
+'ylu',
+'yly',
+'yma',
+'ymb',
+'ymc',
+'ymd',
+'yme',
+'ymg',
+'ymh',
+'ymi',
+'ymk',
+'yml',
+'ymm',
+'ymn',
+'ymo',
+'ymp',
+'ymq',
+'ymr',
+'yms',
+'ymt',
+'ymx',
+'ymz',
+'yna',
+'ynd',
+'yne',
+'yng',
+'ynh',
+'ynk',
+'ynl',
+'ynn',
+'yno',
+'ynq',
+'yns',
+'ynu',
+'yob',
+'yog',
+'yoi',
+'yok',
+'yol',
+'yom',
+'yon',
+'yos',
+'yot',
+'yox',
+'yoy',
+'ypa',
+'ypb',
+'ypg',
+'yph',
+'ypk',
+'ypm',
+'ypn',
+'ypo',
+'ypp',
+'ypz',
+'yra',
+'yrb',
+'yre',
+'yri',
+'yrk',
+'yrl',
+'yrm',
+'yrn',
+'yro',
+'yrs',
+'yrw',
+'yry',
+'ysc',
+'ysd',
+'ysg',
+'ysl',
+'ysn',
+'yso',
+'ysp',
+'ysr',
+'yss',
+'ysy',
+'yta',
+'ytl',
+'ytp',
+'ytw',
+'yty',
+'yua',
+'yub',
+'yuc',
+'yud',
+'yue',
+'yuf',
+'yug',
+'yui',
+'yuj',
+'yuk',
+'yul',
+'yum',
+'yun',
+'yup',
+'yuq',
+'yur',
+'yut',
+'yuu',
+'yuw',
+'yux',
+'yuy',
+'yuz',
+'yva',
+'yvt',
+'ywa',
+'ywg',
+'ywl',
+'ywn',
+'ywq',
+'ywr',
+'ywt',
+'ywu',
+'yww',
+'yxa',
+'yxg',
+'yxl',
+'yxm',
+'yxu',
+'yxy',
+'yyr',
+'yyu',
+'yyz',
+'yzg',
+'yzk',
+'zaa',
+'zab',
+'zac',
+'zad',
+'zae',
+'zaf',
+'zag',
+'zah',
+'zai',
+'zaj',
+'zak',
+'zal',
+'zam',
+'zao',
+'zap',
+'zaq',
+'zar',
+'zas',
+'zat',
+'zau',
+'zav',
+'zaw',
+'zax',
+'zay',
+'zaz',
+'zbc',
+'zbe',
+'zbl',
+'zbt',
+'zbw',
+'zca',
+'zch',
+'zdj',
+'zea',
+'zeg',
+'zeh',
+'zen',
+'zga',
+'zgb',
+'zgh',
+'zgm',
+'zgn',
+'zgr',
+'zhb',
+'zhd',
+'zhi',
+'zhn',
+'zhw',
+'zhx',
+'zia',
+'zib',
+'zik',
+'zil',
+'zim',
+'zin',
+'zir',
+'ziw',
+'ziz',
+'zka',
+'zkb',
+'zkd',
+'zkg',
+'zkh',
+'zkk',
+'zkn',
+'zko',
+'zkp',
+'zkr',
+'zkt',
+'zku',
+'zkv',
+'zkz',
+'zle',
+'zlj',
+'zlm',
+'zln',
+'zlq',
+'zls',
+'zlw',
+'zma',
+'zmb',
+'zmc',
+'zmd',
+'zme',
+'zmf',
+'zmg',
+'zmh',
+'zmi',
+'zmj',
+'zmk',
+'zml',
+'zmm',
+'zmn',
+'zmo',
+'zmp',
+'zmq',
+'zmr',
+'zms',
+'zmt',
+'zmu',
+'zmv',
+'zmw',
+'zmx',
+'zmy',
+'zmz',
+'zna',
+'znd',
+'zne',
+'zng',
+'znk',
+'zns',
+'zoc',
+'zoh',
+'zom',
+'zoo',
+'zoq',
+'zor',
+'zos',
+'zpa',
+'zpb',
+'zpc',
+'zpd',
+'zpe',
+'zpf',
+'zpg',
+'zph',
+'zpi',
+'zpj',
+'zpk',
+'zpl',
+'zpm',
+'zpn',
+'zpo',
+'zpp',
+'zpq',
+'zpr',
+'zps',
+'zpt',
+'zpu',
+'zpv',
+'zpw',
+'zpx',
+'zpy',
+'zpz',
+'zqe',
+'zra',
+'zrg',
+'zrn',
+'zro',
+'zrp',
+'zrs',
+'zsa',
+'zsk',
+'zsl',
+'zsm',
+'zsr',
+'zsu',
+'zte',
+'ztg',
+'ztl',
+'ztm',
+'ztn',
+'ztp',
+'ztq',
+'zts',
+'ztt',
+'ztu',
+'ztx',
+'zty',
+'zua',
+'zuh',
+'zum',
+'zun',
+'zuy',
+'zwa',
+'zxx',
+'zyb',
+'zyg',
+'zyj',
+'zyn',
+'zyp',
+'zza',
+'zzj'];
+
+
+
+
+
+
+
+
+
+axe.utils.validLangs=function(){
+'use strict';
+return langs;
+};
+
+},{}],83:[function(require,module,exports){
+'use strict';
+
+exports.byteLength=byteLength;
+exports.toByteArray=toByteArray;
+exports.fromByteArray=fromByteArray;
+
+var lookup=[];
+var revLookup=[];
+var Arr=typeof Uint8Array!=='undefined'?Uint8Array:Array;
+
+var code='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+for(var i=0,len=code.length;i<len;++i){
+lookup[i]=code[i];
+revLookup[code.charCodeAt(i)]=i;
+}
+
+
+
+revLookup['-'.charCodeAt(0)]=62;
+revLookup['_'.charCodeAt(0)]=63;
+
+function getLens(b64){
+var len=b64.length;
+
+if(len%4>0){
+throw new Error('Invalid string. Length must be a multiple of 4');
+}
+
+
+
+var validLen=b64.indexOf('=');
+if(validLen===-1)validLen=len;
+
+var placeHoldersLen=validLen===len?
+0:
+4-validLen%4;
+
+return[validLen,placeHoldersLen];
+}
+
+
+function byteLength(b64){
+var lens=getLens(b64);
+var validLen=lens[0];
+var placeHoldersLen=lens[1];
+return(validLen+placeHoldersLen)*3/4-placeHoldersLen;
+}
+
+function _byteLength(b64,validLen,placeHoldersLen){
+return(validLen+placeHoldersLen)*3/4-placeHoldersLen;
+}
+
+function toByteArray(b64){
+var tmp;
+var lens=getLens(b64);
+var validLen=lens[0];
+var placeHoldersLen=lens[1];
+
+var arr=new Arr(_byteLength(b64,validLen,placeHoldersLen));
+
+var curByte=0;
+
+
+var len=placeHoldersLen>0?
+validLen-4:
+validLen;
+
+for(var i=0;i<len;i+=4){
+tmp=
+revLookup[b64.charCodeAt(i)]<<18|
+revLookup[b64.charCodeAt(i+1)]<<12|
+revLookup[b64.charCodeAt(i+2)]<<6|
+revLookup[b64.charCodeAt(i+3)];
+arr[curByte++]=tmp>>16&0xFF;
+arr[curByte++]=tmp>>8&0xFF;
+arr[curByte++]=tmp&0xFF;
+}
+
+if(placeHoldersLen===2){
+tmp=
+revLookup[b64.charCodeAt(i)]<<2|
+revLookup[b64.charCodeAt(i+1)]>>4;
+arr[curByte++]=tmp&0xFF;
+}
+
+if(placeHoldersLen===1){
+tmp=
+revLookup[b64.charCodeAt(i)]<<10|
+revLookup[b64.charCodeAt(i+1)]<<4|
+revLookup[b64.charCodeAt(i+2)]>>2;
+arr[curByte++]=tmp>>8&0xFF;
+arr[curByte++]=tmp&0xFF;
+}
+
+return arr;
+}
+
+function tripletToBase64(num){
+return lookup[num>>18&0x3F]+
+lookup[num>>12&0x3F]+
+lookup[num>>6&0x3F]+
+lookup[num&0x3F];
+}
+
+function encodeChunk(uint8,start,end){
+var tmp;
+var output=[];
+for(var i=start;i<end;i+=3){
+tmp=
+(uint8[i]<<16&0xFF0000)+(
+uint8[i+1]<<8&0xFF00)+(
+uint8[i+2]&0xFF);
+output.push(tripletToBase64(tmp));
+}
+return output.join('');
+}
+
+function fromByteArray(uint8){
+var tmp;
+var len=uint8.length;
+var extraBytes=len%3;
+var parts=[];
+var maxChunkLength=16383;
+
+
+for(var i=0,len2=len-extraBytes;i<len2;i+=maxChunkLength){
+parts.push(encodeChunk(
+uint8,i,i+maxChunkLength>len2?len2:i+maxChunkLength));
+
+}
+
+
+if(extraBytes===1){
+tmp=uint8[len-1];
+parts.push(
+lookup[tmp>>2]+
+lookup[tmp<<4&0x3F]+
+'==');
+
+}else if(extraBytes===2){
+tmp=(uint8[len-2]<<8)+uint8[len-1];
+parts.push(
+lookup[tmp>>10]+
+lookup[tmp>>4&0x3F]+
+lookup[tmp<<2&0x3F]+
+'=');
+
+}
+
+return parts.join('');
+}
+
+},{}],84:[function(require,module,exports){
+
+},{}],85:[function(require,module,exports){
+(function(process,Buffer){
+'use strict';
+
+
+var assert=require('assert');
+
+var Zstream=require('pako/lib/zlib/zstream');
+var zlib_deflate=require('pako/lib/zlib/deflate.js');
+var zlib_inflate=require('pako/lib/zlib/inflate.js');
+var constants=require('pako/lib/zlib/constants');
+
+for(var key in constants){
+exports[key]=constants[key];
+}
+
+
+exports.NONE=0;
+exports.DEFLATE=1;
+exports.INFLATE=2;
+exports.GZIP=3;
+exports.GUNZIP=4;
+exports.DEFLATERAW=5;
+exports.INFLATERAW=6;
+exports.UNZIP=7;
+
+var GZIP_HEADER_ID1=0x1f;
+var GZIP_HEADER_ID2=0x8b;
+
+
+
+
+function Zlib(mode){
+if(typeof mode!=='number'||mode<exports.DEFLATE||mode>exports.UNZIP){
+throw new TypeError('Bad argument');
+}
+
+this.dictionary=null;
+this.err=0;
+this.flush=0;
+this.init_done=false;
+this.level=0;
+this.memLevel=0;
+this.mode=mode;
+this.strategy=0;
+this.windowBits=0;
+this.write_in_progress=false;
+this.pending_close=false;
+this.gzip_id_bytes_read=0;
+}
+
+Zlib.prototype.close=function(){
+if(this.write_in_progress){
+this.pending_close=true;
+return;
+}
+
+this.pending_close=false;
+
+assert(this.init_done,'close before init');
+assert(this.mode<=exports.UNZIP);
+
+if(this.mode===exports.DEFLATE||this.mode===exports.GZIP||this.mode===exports.DEFLATERAW){
+zlib_deflate.deflateEnd(this.strm);
+}else if(this.mode===exports.INFLATE||this.mode===exports.GUNZIP||this.mode===exports.INFLATERAW||this.mode===exports.UNZIP){
+zlib_inflate.inflateEnd(this.strm);
+}
+
+this.mode=exports.NONE;
+
+this.dictionary=null;
+};
+
+Zlib.prototype.write=function(flush,input,in_off,in_len,out,out_off,out_len){
+return this._write(true,flush,input,in_off,in_len,out,out_off,out_len);
+};
+
+Zlib.prototype.writeSync=function(flush,input,in_off,in_len,out,out_off,out_len){
+return this._write(false,flush,input,in_off,in_len,out,out_off,out_len);
+};
+
+Zlib.prototype._write=function(async,flush,input,in_off,in_len,out,out_off,out_len){
+assert.equal(arguments.length,8);
+
+assert(this.init_done,'write before init');
+assert(this.mode!==exports.NONE,'already finalized');
+assert.equal(false,this.write_in_progress,'write already in progress');
+assert.equal(false,this.pending_close,'close is pending');
+
+this.write_in_progress=true;
+
+assert.equal(false,flush===undefined,'must provide flush value');
+
+this.write_in_progress=true;
+
+if(flush!==exports.Z_NO_FLUSH&&flush!==exports.Z_PARTIAL_FLUSH&&flush!==exports.Z_SYNC_FLUSH&&flush!==exports.Z_FULL_FLUSH&&flush!==exports.Z_FINISH&&flush!==exports.Z_BLOCK){
+throw new Error('Invalid flush value');
+}
+
+if(input==null){
+input=Buffer.alloc(0);
+in_len=0;
+in_off=0;
+}
+
+this.strm.avail_in=in_len;
+this.strm.input=input;
+this.strm.next_in=in_off;
+this.strm.avail_out=out_len;
+this.strm.output=out;
+this.strm.next_out=out_off;
+this.flush=flush;
+
+if(!async){
+
+this._process();
+
+if(this._checkError()){
+return this._afterSync();
+}
+return;
+}
+
+
+var self=this;
+process.nextTick(function(){
+self._process();
+self._after();
+});
+
+return this;
+};
+
+Zlib.prototype._afterSync=function(){
+var avail_out=this.strm.avail_out;
+var avail_in=this.strm.avail_in;
+
+this.write_in_progress=false;
+
+return[avail_in,avail_out];
+};
+
+Zlib.prototype._process=function(){
+var next_expected_header_byte=null;
+
+
+
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.GZIP:
+case exports.DEFLATERAW:
+this.err=zlib_deflate.deflate(this.strm,this.flush);
+break;
+case exports.UNZIP:
+if(this.strm.avail_in>0){
+next_expected_header_byte=this.strm.next_in;
+}
+
+switch(this.gzip_id_bytes_read){
+case 0:
+if(next_expected_header_byte===null){
+break;
+}
+
+if(this.strm.input[next_expected_header_byte]===GZIP_HEADER_ID1){
+this.gzip_id_bytes_read=1;
+next_expected_header_byte++;
+
+if(this.strm.avail_in===1){
+
+break;
+}
+}else{
+this.mode=exports.INFLATE;
+break;
+}
+
+
+case 1:
+if(next_expected_header_byte===null){
+break;
+}
+
+if(this.strm.input[next_expected_header_byte]===GZIP_HEADER_ID2){
+this.gzip_id_bytes_read=2;
+this.mode=exports.GUNZIP;
+}else{
+
+
+this.mode=exports.INFLATE;
+}
+
+break;
+default:
+throw new Error('invalid number of gzip magic number bytes read');}
+
+
+
+case exports.INFLATE:
+case exports.GUNZIP:
+case exports.INFLATERAW:
+this.err=zlib_inflate.inflate(this.strm,this.flush);
+
+
+if(this.err===exports.Z_NEED_DICT&&this.dictionary){
+
+this.err=zlib_inflate.inflateSetDictionary(this.strm,this.dictionary);
+if(this.err===exports.Z_OK){
+
+this.err=zlib_inflate.inflate(this.strm,this.flush);
+}else if(this.err===exports.Z_DATA_ERROR){
+
+
+
+this.err=exports.Z_NEED_DICT;
+}
+}
+while(this.strm.avail_in>0&&this.mode===exports.GUNZIP&&this.err===exports.Z_STREAM_END&&this.strm.next_in[0]!==0x00){
+
+
+
+
+
+this.reset();
+this.err=zlib_inflate.inflate(this.strm,this.flush);
+}
+break;
+default:
+throw new Error('Unknown mode '+this.mode);}
+
+};
+
+Zlib.prototype._checkError=function(){
+
+switch(this.err){
+case exports.Z_OK:
+case exports.Z_BUF_ERROR:
+if(this.strm.avail_out!==0&&this.flush===exports.Z_FINISH){
+this._error('unexpected end of file');
+return false;
+}
+break;
+case exports.Z_STREAM_END:
+
+break;
+case exports.Z_NEED_DICT:
+if(this.dictionary==null){
+this._error('Missing dictionary');
+}else{
+this._error('Bad dictionary');
+}
+return false;
+default:
+
+this._error('Zlib error');
+return false;}
+
+
+return true;
+};
+
+Zlib.prototype._after=function(){
+if(!this._checkError()){
+return;
+}
+
+var avail_out=this.strm.avail_out;
+var avail_in=this.strm.avail_in;
+
+this.write_in_progress=false;
+
+
+this.callback(avail_in,avail_out);
+
+if(this.pending_close){
+this.close();
+}
+};
+
+Zlib.prototype._error=function(message){
+if(this.strm.msg){
+message=this.strm.msg;
+}
+this.onerror(message,this.err);
+
+
+this.write_in_progress=false;
+if(this.pending_close){
+this.close();
+}
+};
+
+Zlib.prototype.init=function(windowBits,level,memLevel,strategy,dictionary){
+assert(arguments.length===4||arguments.length===5,'init(windowBits, level, memLevel, strategy, [dictionary])');
+
+assert(windowBits>=8&&windowBits<=15,'invalid windowBits');
+assert(level>=-1&&level<=9,'invalid compression level');
+
+assert(memLevel>=1&&memLevel<=9,'invalid memlevel');
+
+assert(strategy===exports.Z_FILTERED||strategy===exports.Z_HUFFMAN_ONLY||strategy===exports.Z_RLE||strategy===exports.Z_FIXED||strategy===exports.Z_DEFAULT_STRATEGY,'invalid strategy');
+
+this._init(level,windowBits,memLevel,strategy,dictionary);
+this._setDictionary();
+};
+
+Zlib.prototype.params=function(){
+throw new Error('deflateParams Not supported');
+};
+
+Zlib.prototype.reset=function(){
+this._reset();
+this._setDictionary();
+};
+
+Zlib.prototype._init=function(level,windowBits,memLevel,strategy,dictionary){
+this.level=level;
+this.windowBits=windowBits;
+this.memLevel=memLevel;
+this.strategy=strategy;
+
+this.flush=exports.Z_NO_FLUSH;
+
+this.err=exports.Z_OK;
+
+if(this.mode===exports.GZIP||this.mode===exports.GUNZIP){
+this.windowBits+=16;
+}
+
+if(this.mode===exports.UNZIP){
+this.windowBits+=32;
+}
+
+if(this.mode===exports.DEFLATERAW||this.mode===exports.INFLATERAW){
+this.windowBits=-1*this.windowBits;
+}
+
+this.strm=new Zstream();
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.GZIP:
+case exports.DEFLATERAW:
+this.err=zlib_deflate.deflateInit2(this.strm,this.level,exports.Z_DEFLATED,this.windowBits,this.memLevel,this.strategy);
+break;
+case exports.INFLATE:
+case exports.GUNZIP:
+case exports.INFLATERAW:
+case exports.UNZIP:
+this.err=zlib_inflate.inflateInit2(this.strm,this.windowBits);
+break;
+default:
+throw new Error('Unknown mode '+this.mode);}
+
+
+if(this.err!==exports.Z_OK){
+this._error('Init error');
+}
+
+this.dictionary=dictionary;
+
+this.write_in_progress=false;
+this.init_done=true;
+};
+
+Zlib.prototype._setDictionary=function(){
+if(this.dictionary==null){
+return;
+}
+
+this.err=exports.Z_OK;
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.DEFLATERAW:
+this.err=zlib_deflate.deflateSetDictionary(this.strm,this.dictionary);
+break;
+default:
+break;}
+
+
+if(this.err!==exports.Z_OK){
+this._error('Failed to set dictionary');
+}
+};
+
+Zlib.prototype._reset=function(){
+this.err=exports.Z_OK;
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.DEFLATERAW:
+case exports.GZIP:
+this.err=zlib_deflate.deflateReset(this.strm);
+break;
+case exports.INFLATE:
+case exports.INFLATERAW:
+case exports.GUNZIP:
+this.err=zlib_inflate.inflateReset(this.strm);
+break;
+default:
+break;}
+
+
+if(this.err!==exports.Z_OK){
+this._error('Failed to reset stream');
+}
+};
+
+exports.Zlib=Zlib;
+}).call(this,require('_process'),require("buffer").Buffer);
+},{"_process":130,"assert":78,"buffer":88,"pako/lib/zlib/constants":121,"pako/lib/zlib/deflate.js":123,"pako/lib/zlib/inflate.js":87,"pako/lib/zlib/zstream":126}],86:[function(require,module,exports){
+(function(process){
+'use strict';
+
+var Buffer=require('buffer').Buffer;
+var Transform=require('stream').Transform;
+var binding=require('./binding');
+var util=require('util');
+var assert=require('assert').ok;
+var kMaxLength=require('buffer').kMaxLength;
+var kRangeErrorMessage='Cannot create final Buffer. It would be larger '+'than 0x'+kMaxLength.toString(16)+' bytes';
+
+
+
+binding.Z_MIN_WINDOWBITS=8;
+binding.Z_MAX_WINDOWBITS=15;
+binding.Z_DEFAULT_WINDOWBITS=15;
+
+
+
+
+binding.Z_MIN_CHUNK=64;
+binding.Z_MAX_CHUNK=Infinity;
+binding.Z_DEFAULT_CHUNK=16*1024;
+
+binding.Z_MIN_MEMLEVEL=1;
+binding.Z_MAX_MEMLEVEL=9;
+binding.Z_DEFAULT_MEMLEVEL=8;
+
+binding.Z_MIN_LEVEL=-1;
+binding.Z_MAX_LEVEL=9;
+binding.Z_DEFAULT_LEVEL=binding.Z_DEFAULT_COMPRESSION;
+
+
+var bkeys=Object.keys(binding);
+for(var bk=0;bk<bkeys.length;bk++){
+var bkey=bkeys[bk];
+if(bkey.match(/^Z/)){
+Object.defineProperty(exports,bkey,{
+enumerable:true,value:binding[bkey],writable:false});
+
+}
+}
+
+
+var codes={
+Z_OK:binding.Z_OK,
+Z_STREAM_END:binding.Z_STREAM_END,
+Z_NEED_DICT:binding.Z_NEED_DICT,
+Z_ERRNO:binding.Z_ERRNO,
+Z_STREAM_ERROR:binding.Z_STREAM_ERROR,
+Z_DATA_ERROR:binding.Z_DATA_ERROR,
+Z_MEM_ERROR:binding.Z_MEM_ERROR,
+Z_BUF_ERROR:binding.Z_BUF_ERROR,
+Z_VERSION_ERROR:binding.Z_VERSION_ERROR};
+
+
+var ckeys=Object.keys(codes);
+for(var ck=0;ck<ckeys.length;ck++){
+var ckey=ckeys[ck];
+codes[codes[ckey]]=ckey;
+}
+
+Object.defineProperty(exports,'codes',{
+enumerable:true,value:Object.freeze(codes),writable:false});
+
+
+exports.Deflate=Deflate;
+exports.Inflate=Inflate;
+exports.Gzip=Gzip;
+exports.Gunzip=Gunzip;
+exports.DeflateRaw=DeflateRaw;
+exports.InflateRaw=InflateRaw;
+exports.Unzip=Unzip;
+
+exports.createDeflate=function(o){
+return new Deflate(o);
+};
+
+exports.createInflate=function(o){
+return new Inflate(o);
+};
+
+exports.createDeflateRaw=function(o){
+return new DeflateRaw(o);
+};
+
+exports.createInflateRaw=function(o){
+return new InflateRaw(o);
+};
+
+exports.createGzip=function(o){
+return new Gzip(o);
+};
+
+exports.createGunzip=function(o){
+return new Gunzip(o);
+};
+
+exports.createUnzip=function(o){
+return new Unzip(o);
+};
+
+
+
+exports.deflate=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new Deflate(opts),buffer,callback);
+};
+
+exports.deflateSync=function(buffer,opts){
+return zlibBufferSync(new Deflate(opts),buffer);
+};
+
+exports.gzip=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new Gzip(opts),buffer,callback);
+};
+
+exports.gzipSync=function(buffer,opts){
+return zlibBufferSync(new Gzip(opts),buffer);
+};
+
+exports.deflateRaw=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new DeflateRaw(opts),buffer,callback);
+};
+
+exports.deflateRawSync=function(buffer,opts){
+return zlibBufferSync(new DeflateRaw(opts),buffer);
+};
+
+exports.unzip=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new Unzip(opts),buffer,callback);
+};
+
+exports.unzipSync=function(buffer,opts){
+return zlibBufferSync(new Unzip(opts),buffer);
+};
+
+exports.inflate=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new Inflate(opts),buffer,callback);
+};
+
+exports.inflateSync=function(buffer,opts){
+return zlibBufferSync(new Inflate(opts),buffer);
+};
+
+exports.gunzip=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new Gunzip(opts),buffer,callback);
+};
+
+exports.gunzipSync=function(buffer,opts){
+return zlibBufferSync(new Gunzip(opts),buffer);
+};
+
+exports.inflateRaw=function(buffer,opts,callback){
+if(typeof opts==='function'){
+callback=opts;
+opts={};
+}
+return zlibBuffer(new InflateRaw(opts),buffer,callback);
+};
+
+exports.inflateRawSync=function(buffer,opts){
+return zlibBufferSync(new InflateRaw(opts),buffer);
+};
+
+function zlibBuffer(engine,buffer,callback){
+var buffers=[];
+var nread=0;
+
+engine.on('error',onError);
+engine.on('end',onEnd);
+
+engine.end(buffer);
+flow();
+
+function flow(){
+var chunk;
+while(null!==(chunk=engine.read())){
+buffers.push(chunk);
+nread+=chunk.length;
+}
+engine.once('readable',flow);
+}
+
+function onError(err){
+engine.removeListener('end',onEnd);
+engine.removeListener('readable',flow);
+callback(err);
+}
+
+function onEnd(){
+var buf;
+var err=null;
+
+if(nread>=kMaxLength){
+err=new RangeError(kRangeErrorMessage);
+}else{
+buf=Buffer.concat(buffers,nread);
+}
+
+buffers=[];
+engine.close();
+callback(err,buf);
+}
+}
+
+function zlibBufferSync(engine,buffer){
+if(typeof buffer==='string')buffer=Buffer.from(buffer);
+
+if(!Buffer.isBuffer(buffer))throw new TypeError('Not a string or buffer');
+
+var flushFlag=engine._finishFlushFlag;
+
+return engine._processChunk(buffer,flushFlag);
+}
+
+
+
+function Deflate(opts){
+if(!(this instanceof Deflate))return new Deflate(opts);
+Zlib.call(this,opts,binding.DEFLATE);
+}
+
+function Inflate(opts){
+if(!(this instanceof Inflate))return new Inflate(opts);
+Zlib.call(this,opts,binding.INFLATE);
+}
+
+
+function Gzip(opts){
+if(!(this instanceof Gzip))return new Gzip(opts);
+Zlib.call(this,opts,binding.GZIP);
+}
+
+function Gunzip(opts){
+if(!(this instanceof Gunzip))return new Gunzip(opts);
+Zlib.call(this,opts,binding.GUNZIP);
+}
+
+
+function DeflateRaw(opts){
+if(!(this instanceof DeflateRaw))return new DeflateRaw(opts);
+Zlib.call(this,opts,binding.DEFLATERAW);
+}
+
+function InflateRaw(opts){
+if(!(this instanceof InflateRaw))return new InflateRaw(opts);
+Zlib.call(this,opts,binding.INFLATERAW);
+}
+
+
+function Unzip(opts){
+if(!(this instanceof Unzip))return new Unzip(opts);
+Zlib.call(this,opts,binding.UNZIP);
+}
+
+function isValidFlushFlag(flag){
+return flag===binding.Z_NO_FLUSH||flag===binding.Z_PARTIAL_FLUSH||flag===binding.Z_SYNC_FLUSH||flag===binding.Z_FULL_FLUSH||flag===binding.Z_FINISH||flag===binding.Z_BLOCK;
+}
+
+
+
+
+
+
+function Zlib(opts,mode){
+var _this=this;
+
+this._opts=opts=opts||{};
+this._chunkSize=opts.chunkSize||exports.Z_DEFAULT_CHUNK;
+
+Transform.call(this,opts);
+
+if(opts.flush&&!isValidFlushFlag(opts.flush)){
+throw new Error('Invalid flush flag: '+opts.flush);
+}
+if(opts.finishFlush&&!isValidFlushFlag(opts.finishFlush)){
+throw new Error('Invalid flush flag: '+opts.finishFlush);
+}
+
+this._flushFlag=opts.flush||binding.Z_NO_FLUSH;
+this._finishFlushFlag=typeof opts.finishFlush!=='undefined'?opts.finishFlush:binding.Z_FINISH;
+
+if(opts.chunkSize){
+if(opts.chunkSize<exports.Z_MIN_CHUNK||opts.chunkSize>exports.Z_MAX_CHUNK){
+throw new Error('Invalid chunk size: '+opts.chunkSize);
+}
+}
+
+if(opts.windowBits){
+if(opts.windowBits<exports.Z_MIN_WINDOWBITS||opts.windowBits>exports.Z_MAX_WINDOWBITS){
+throw new Error('Invalid windowBits: '+opts.windowBits);
+}
+}
+
+if(opts.level){
+if(opts.level<exports.Z_MIN_LEVEL||opts.level>exports.Z_MAX_LEVEL){
+throw new Error('Invalid compression level: '+opts.level);
+}
+}
+
+if(opts.memLevel){
+if(opts.memLevel<exports.Z_MIN_MEMLEVEL||opts.memLevel>exports.Z_MAX_MEMLEVEL){
+throw new Error('Invalid memLevel: '+opts.memLevel);
+}
+}
+
+if(opts.strategy){
+if(opts.strategy!=exports.Z_FILTERED&&opts.strategy!=exports.Z_HUFFMAN_ONLY&&opts.strategy!=exports.Z_RLE&&opts.strategy!=exports.Z_FIXED&&opts.strategy!=exports.Z_DEFAULT_STRATEGY){
+throw new Error('Invalid strategy: '+opts.strategy);
+}
+}
+
+if(opts.dictionary){
+if(!Buffer.isBuffer(opts.dictionary)){
+throw new Error('Invalid dictionary: it should be a Buffer instance');
+}
+}
+
+this._handle=new binding.Zlib(mode);
+
+var self=this;
+this._hadError=false;
+this._handle.onerror=function(message,errno){
+
+
+_close(self);
+self._hadError=true;
+
+var error=new Error(message);
+error.errno=errno;
+error.code=exports.codes[errno];
+self.emit('error',error);
+};
+
+var level=exports.Z_DEFAULT_COMPRESSION;
+if(typeof opts.level==='number')level=opts.level;
+
+var strategy=exports.Z_DEFAULT_STRATEGY;
+if(typeof opts.strategy==='number')strategy=opts.strategy;
+
+this._handle.init(opts.windowBits||exports.Z_DEFAULT_WINDOWBITS,level,opts.memLevel||exports.Z_DEFAULT_MEMLEVEL,strategy,opts.dictionary);
+
+this._buffer=Buffer.allocUnsafe(this._chunkSize);
+this._offset=0;
+this._level=level;
+this._strategy=strategy;
+
+this.once('end',this.close);
+
+Object.defineProperty(this,'_closed',{
+get:function(){
+return!_this._handle;
+},
+configurable:true,
+enumerable:true});
+
+}
+
+util.inherits(Zlib,Transform);
+
+Zlib.prototype.params=function(level,strategy,callback){
+if(level<exports.Z_MIN_LEVEL||level>exports.Z_MAX_LEVEL){
+throw new RangeError('Invalid compression level: '+level);
+}
+if(strategy!=exports.Z_FILTERED&&strategy!=exports.Z_HUFFMAN_ONLY&&strategy!=exports.Z_RLE&&strategy!=exports.Z_FIXED&&strategy!=exports.Z_DEFAULT_STRATEGY){
+throw new TypeError('Invalid strategy: '+strategy);
+}
+
+if(this._level!==level||this._strategy!==strategy){
+var self=this;
+this.flush(binding.Z_SYNC_FLUSH,function(){
+assert(self._handle,'zlib binding closed');
+self._handle.params(level,strategy);
+if(!self._hadError){
+self._level=level;
+self._strategy=strategy;
+if(callback)callback();
+}
+});
+}else{
+process.nextTick(callback);
+}
+};
+
+Zlib.prototype.reset=function(){
+assert(this._handle,'zlib binding closed');
+return this._handle.reset();
+};
+
+
+
+Zlib.prototype._flush=function(callback){
+this._transform(Buffer.alloc(0),'',callback);
+};
+
+Zlib.prototype.flush=function(kind,callback){
+var _this2=this;
+
+var ws=this._writableState;
+
+if(typeof kind==='function'||kind===undefined&&!callback){
+callback=kind;
+kind=binding.Z_FULL_FLUSH;
+}
+
+if(ws.ended){
+if(callback)process.nextTick(callback);
+}else if(ws.ending){
+if(callback)this.once('end',callback);
+}else if(ws.needDrain){
+if(callback){
+this.once('drain',function(){
+return _this2.flush(kind,callback);
+});
+}
+}else{
+this._flushFlag=kind;
+this.write(Buffer.alloc(0),'',callback);
+}
+};
+
+Zlib.prototype.close=function(callback){
+_close(this,callback);
+process.nextTick(emitCloseNT,this);
+};
+
+function _close(engine,callback){
+if(callback)process.nextTick(callback);
+
+
+if(!engine._handle)return;
+
+engine._handle.close();
+engine._handle=null;
+}
+
+function emitCloseNT(self){
+self.emit('close');
+}
+
+Zlib.prototype._transform=function(chunk,encoding,cb){
+var flushFlag;
+var ws=this._writableState;
+var ending=ws.ending||ws.ended;
+var last=ending&&(!chunk||ws.length===chunk.length);
+
+if(chunk!==null&&!Buffer.isBuffer(chunk))return cb(new Error('invalid input'));
+
+if(!this._handle)return cb(new Error('zlib binding closed'));
+
+
+
+
+
+
+if(last)flushFlag=this._finishFlushFlag;else{
+flushFlag=this._flushFlag;
+
+
+if(chunk.length>=ws.length){
+this._flushFlag=this._opts.flush||binding.Z_NO_FLUSH;
+}
+}
+
+this._processChunk(chunk,flushFlag,cb);
+};
+
+Zlib.prototype._processChunk=function(chunk,flushFlag,cb){
+var availInBefore=chunk&&chunk.length;
+var availOutBefore=this._chunkSize-this._offset;
+var inOff=0;
+
+var self=this;
+
+var async=typeof cb==='function';
+
+if(!async){
+var buffers=[];
+var nread=0;
+
+var error;
+this.on('error',function(er){
+error=er;
+});
+
+assert(this._handle,'zlib binding closed');
+do{
+var res=this._handle.writeSync(flushFlag,chunk,
+inOff,
+availInBefore,
+this._buffer,
+this._offset,
+availOutBefore);
+}while(!this._hadError&&callback(res[0],res[1]));
+
+if(this._hadError){
+throw error;
+}
+
+if(nread>=kMaxLength){
+_close(this);
+throw new RangeError(kRangeErrorMessage);
+}
+
+var buf=Buffer.concat(buffers,nread);
+_close(this);
+
+return buf;
+}
+
+assert(this._handle,'zlib binding closed');
+var req=this._handle.write(flushFlag,chunk,
+inOff,
+availInBefore,
+this._buffer,
+this._offset,
+availOutBefore);
+
+req.buffer=chunk;
+req.callback=callback;
+
+function callback(availInAfter,availOutAfter){
+
+
+
+
+
+if(this){
+this.buffer=null;
+this.callback=null;
+}
+
+if(self._hadError)return;
+
+var have=availOutBefore-availOutAfter;
+assert(have>=0,'have should not go down');
+
+if(have>0){
+var out=self._buffer.slice(self._offset,self._offset+have);
+self._offset+=have;
+
+if(async){
+self.push(out);
+}else{
+buffers.push(out);
+nread+=out.length;
+}
+}
+
+
+if(availOutAfter===0||self._offset>=self._chunkSize){
+availOutBefore=self._chunkSize;
+self._offset=0;
+self._buffer=Buffer.allocUnsafe(self._chunkSize);
+}
+
+if(availOutAfter===0){
+
+
+
+
+inOff+=availInBefore-availInAfter;
+availInBefore=availInAfter;
+
+if(!async)return true;
+
+var newReq=self._handle.write(flushFlag,chunk,inOff,availInBefore,self._buffer,self._offset,self._chunkSize);
+newReq.callback=callback;
+newReq.buffer=chunk;
+return;
+}
+
+if(!async)return false;
+
+
+cb();
+}
+};
+
+util.inherits(Deflate,Zlib);
+util.inherits(Inflate,Zlib);
+util.inherits(Gzip,Zlib);
+util.inherits(Gunzip,Zlib);
+util.inherits(DeflateRaw,Zlib);
+util.inherits(InflateRaw,Zlib);
+util.inherits(Unzip,Zlib);
+}).call(this,require('_process'));
+},{"./binding":85,"_process":130,"assert":78,"buffer":88,"stream":155,"util":159}],87:[function(require,module,exports){
+arguments[4][84][0].apply(exports,arguments);
+},{"dup":84}],88:[function(require,module,exports){
+
+
+
+
+
+
+
+
+'use strict';
+
+var base64=require('base64-js');
+var ieee754=require('ieee754');
+
+exports.Buffer=Buffer;
+exports.SlowBuffer=SlowBuffer;
+exports.INSPECT_MAX_BYTES=50;
+
+var K_MAX_LENGTH=0x7fffffff;
+exports.kMaxLength=K_MAX_LENGTH;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Buffer.TYPED_ARRAY_SUPPORT=typedArraySupport();
+
+if(!Buffer.TYPED_ARRAY_SUPPORT&&typeof console!=='undefined'&&
+typeof console.error==='function'){
+console.error(
+'This browser lacks typed array (Uint8Array) support which is required by '+
+'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.');
+
+}
+
+function typedArraySupport(){
+
+try{
+var arr=new Uint8Array(1);
+arr.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42;}};
+return arr.foo()===42;
+}catch(e){
+return false;
+}
+}
+
+Object.defineProperty(Buffer.prototype,'parent',{
+enumerable:true,
+get:function(){
+if(!Buffer.isBuffer(this))return undefined;
+return this.buffer;
+}});
+
+
+Object.defineProperty(Buffer.prototype,'offset',{
+enumerable:true,
+get:function(){
+if(!Buffer.isBuffer(this))return undefined;
+return this.byteOffset;
+}});
+
+
+function createBuffer(length){
+if(length>K_MAX_LENGTH){
+throw new RangeError('The value "'+length+'" is invalid for option "size"');
+}
+
+var buf=new Uint8Array(length);
+buf.__proto__=Buffer.prototype;
+return buf;
+}
+
+
+
+
+
+
+
+
+
+
+
+function Buffer(arg,encodingOrOffset,length){
+
+if(typeof arg==='number'){
+if(typeof encodingOrOffset==='string'){
+throw new TypeError(
+'The "string" argument must be of type string. Received type number');
+
+}
+return allocUnsafe(arg);
+}
+return from(arg,encodingOrOffset,length);
+}
+
+
+if(typeof Symbol!=='undefined'&&Symbol.species!=null&&
+Buffer[Symbol.species]===Buffer){
+Object.defineProperty(Buffer,Symbol.species,{
+value:null,
+configurable:true,
+enumerable:false,
+writable:false});
+
+}
+
+Buffer.poolSize=8192;
+
+function from(value,encodingOrOffset,length){
+if(typeof value==='string'){
+return fromString(value,encodingOrOffset);
+}
+
+if(ArrayBuffer.isView(value)){
+return fromArrayLike(value);
+}
+
+if(value==null){
+throw TypeError(
+'The first argument must be one of type string, Buffer, ArrayBuffer, Array, '+
+'or Array-like Object. Received type '+typeof value);
+
+}
+
+if(isInstance(value,ArrayBuffer)||
+value&&isInstance(value.buffer,ArrayBuffer)){
+return fromArrayBuffer(value,encodingOrOffset,length);
+}
+
+if(typeof value==='number'){
+throw new TypeError(
+'The "value" argument must not be of type number. Received type number');
+
+}
+
+var valueOf=value.valueOf&&value.valueOf();
+if(valueOf!=null&&valueOf!==value){
+return Buffer.from(valueOf,encodingOrOffset,length);
+}
+
+var b=fromObject(value);
+if(b)return b;
+
+if(typeof Symbol!=='undefined'&&Symbol.toPrimitive!=null&&
+typeof value[Symbol.toPrimitive]==='function'){
+return Buffer.from(
+value[Symbol.toPrimitive]('string'),encodingOrOffset,length);
+
+}
+
+throw new TypeError(
+'The first argument must be one of type string, Buffer, ArrayBuffer, Array, '+
+'or Array-like Object. Received type '+typeof value);
+
+}
+
+
+
+
+
+
+
+
+
+Buffer.from=function(value,encodingOrOffset,length){
+return from(value,encodingOrOffset,length);
+};
+
+
+
+Buffer.prototype.__proto__=Uint8Array.prototype;
+Buffer.__proto__=Uint8Array;
+
+function assertSize(size){
+if(typeof size!=='number'){
+throw new TypeError('"size" argument must be of type number');
+}else if(size<0){
+throw new RangeError('The value "'+size+'" is invalid for option "size"');
+}
+}
+
+function alloc(size,fill,encoding){
+assertSize(size);
+if(size<=0){
+return createBuffer(size);
+}
+if(fill!==undefined){
+
+
+
+return typeof encoding==='string'?
+createBuffer(size).fill(fill,encoding):
+createBuffer(size).fill(fill);
+}
+return createBuffer(size);
+}
+
+
+
+
+
+Buffer.alloc=function(size,fill,encoding){
+return alloc(size,fill,encoding);
+};
+
+function allocUnsafe(size){
+assertSize(size);
+return createBuffer(size<0?0:checked(size)|0);
+}
+
+
+
+
+Buffer.allocUnsafe=function(size){
+return allocUnsafe(size);
+};
+
+
+
+Buffer.allocUnsafeSlow=function(size){
+return allocUnsafe(size);
+};
+
+function fromString(string,encoding){
+if(typeof encoding!=='string'||encoding===''){
+encoding='utf8';
+}
+
+if(!Buffer.isEncoding(encoding)){
+throw new TypeError('Unknown encoding: '+encoding);
+}
+
+var length=byteLength(string,encoding)|0;
+var buf=createBuffer(length);
+
+var actual=buf.write(string,encoding);
+
+if(actual!==length){
+
+
+
+buf=buf.slice(0,actual);
+}
+
+return buf;
+}
+
+function fromArrayLike(array){
+var length=array.length<0?0:checked(array.length)|0;
+var buf=createBuffer(length);
+for(var i=0;i<length;i+=1){
+buf[i]=array[i]&255;
+}
+return buf;
+}
+
+function fromArrayBuffer(array,byteOffset,length){
+if(byteOffset<0||array.byteLength<byteOffset){
+throw new RangeError('"offset" is outside of buffer bounds');
+}
+
+if(array.byteLength<byteOffset+(length||0)){
+throw new RangeError('"length" is outside of buffer bounds');
+}
+
+var buf;
+if(byteOffset===undefined&&length===undefined){
+buf=new Uint8Array(array);
+}else if(length===undefined){
+buf=new Uint8Array(array,byteOffset);
+}else{
+buf=new Uint8Array(array,byteOffset,length);
+}
+
+
+buf.__proto__=Buffer.prototype;
+return buf;
+}
+
+function fromObject(obj){
+if(Buffer.isBuffer(obj)){
+var len=checked(obj.length)|0;
+var buf=createBuffer(len);
+
+if(buf.length===0){
+return buf;
+}
+
+obj.copy(buf,0,0,len);
+return buf;
+}
+
+if(obj.length!==undefined){
+if(typeof obj.length!=='number'||numberIsNaN(obj.length)){
+return createBuffer(0);
+}
+return fromArrayLike(obj);
+}
+
+if(obj.type==='Buffer'&&Array.isArray(obj.data)){
+return fromArrayLike(obj.data);
+}
+}
+
+function checked(length){
+
+
+if(length>=K_MAX_LENGTH){
+throw new RangeError('Attempt to allocate Buffer larger than maximum '+
+'size: 0x'+K_MAX_LENGTH.toString(16)+' bytes');
+}
+return length|0;
+}
+
+function SlowBuffer(length){
+if(+length!=length){
+length=0;
+}
+return Buffer.alloc(+length);
+}
+
+Buffer.isBuffer=function isBuffer(b){
+return b!=null&&b._isBuffer===true&&
+b!==Buffer.prototype;
+};
+
+Buffer.compare=function compare(a,b){
+if(isInstance(a,Uint8Array))a=Buffer.from(a,a.offset,a.byteLength);
+if(isInstance(b,Uint8Array))b=Buffer.from(b,b.offset,b.byteLength);
+if(!Buffer.isBuffer(a)||!Buffer.isBuffer(b)){
+throw new TypeError(
+'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');
+
+}
+
+if(a===b)return 0;
+
+var x=a.length;
+var y=b.length;
+
+for(var i=0,len=Math.min(x,y);i<len;++i){
+if(a[i]!==b[i]){
+x=a[i];
+y=b[i];
+break;
+}
+}
+
+if(x<y)return-1;
+if(y<x)return 1;
+return 0;
+};
+
+Buffer.isEncoding=function isEncoding(encoding){
+switch(String(encoding).toLowerCase()){
+case'hex':
+case'utf8':
+case'utf-8':
+case'ascii':
+case'latin1':
+case'binary':
+case'base64':
+case'ucs2':
+case'ucs-2':
+case'utf16le':
+case'utf-16le':
+return true;
+default:
+return false;}
+
+};
+
+Buffer.concat=function concat(list,length){
+if(!Array.isArray(list)){
+throw new TypeError('"list" argument must be an Array of Buffers');
+}
+
+if(list.length===0){
+return Buffer.alloc(0);
+}
+
+var i;
+if(length===undefined){
+length=0;
+for(i=0;i<list.length;++i){
+length+=list[i].length;
+}
+}
+
+var buffer=Buffer.allocUnsafe(length);
+var pos=0;
+for(i=0;i<list.length;++i){
+var buf=list[i];
+if(isInstance(buf,Uint8Array)){
+buf=Buffer.from(buf);
+}
+if(!Buffer.isBuffer(buf)){
+throw new TypeError('"list" argument must be an Array of Buffers');
+}
+buf.copy(buffer,pos);
+pos+=buf.length;
+}
+return buffer;
+};
+
+function byteLength(string,encoding){
+if(Buffer.isBuffer(string)){
+return string.length;
+}
+if(ArrayBuffer.isView(string)||isInstance(string,ArrayBuffer)){
+return string.byteLength;
+}
+if(typeof string!=='string'){
+throw new TypeError(
+'The "string" argument must be one of type string, Buffer, or ArrayBuffer. '+
+'Received type '+typeof string);
+
+}
+
+var len=string.length;
+var mustMatch=arguments.length>2&&arguments[2]===true;
+if(!mustMatch&&len===0)return 0;
+
+
+var loweredCase=false;
+for(;;){
+switch(encoding){
+case'ascii':
+case'latin1':
+case'binary':
+return len;
+case'utf8':
+case'utf-8':
+return utf8ToBytes(string).length;
+case'ucs2':
+case'ucs-2':
+case'utf16le':
+case'utf-16le':
+return len*2;
+case'hex':
+return len>>>1;
+case'base64':
+return base64ToBytes(string).length;
+default:
+if(loweredCase){
+return mustMatch?-1:utf8ToBytes(string).length;
+}
+encoding=(''+encoding).toLowerCase();
+loweredCase=true;}
+
+}
+}
+Buffer.byteLength=byteLength;
+
+function slowToString(encoding,start,end){
+var loweredCase=false;
+
+
+
+
+
+
+
+
+if(start===undefined||start<0){
+start=0;
+}
+
+
+if(start>this.length){
+return'';
+}
+
+if(end===undefined||end>this.length){
+end=this.length;
+}
+
+if(end<=0){
+return'';
+}
+
+
+end>>>=0;
+start>>>=0;
+
+if(end<=start){
+return'';
+}
+
+if(!encoding)encoding='utf8';
+
+while(true){
+switch(encoding){
+case'hex':
+return hexSlice(this,start,end);
+
+case'utf8':
+case'utf-8':
+return utf8Slice(this,start,end);
+
+case'ascii':
+return asciiSlice(this,start,end);
+
+case'latin1':
+case'binary':
+return latin1Slice(this,start,end);
+
+case'base64':
+return base64Slice(this,start,end);
+
+case'ucs2':
+case'ucs-2':
+case'utf16le':
+case'utf-16le':
+return utf16leSlice(this,start,end);
+
+default:
+if(loweredCase)throw new TypeError('Unknown encoding: '+encoding);
+encoding=(encoding+'').toLowerCase();
+loweredCase=true;}
+
+}
+}
+
+
+
+
+
+
+
+Buffer.prototype._isBuffer=true;
+
+function swap(b,n,m){
+var i=b[n];
+b[n]=b[m];
+b[m]=i;
+}
+
+Buffer.prototype.swap16=function swap16(){
+var len=this.length;
+if(len%2!==0){
+throw new RangeError('Buffer size must be a multiple of 16-bits');
+}
+for(var i=0;i<len;i+=2){
+swap(this,i,i+1);
+}
+return this;
+};
+
+Buffer.prototype.swap32=function swap32(){
+var len=this.length;
+if(len%4!==0){
+throw new RangeError('Buffer size must be a multiple of 32-bits');
+}
+for(var i=0;i<len;i+=4){
+swap(this,i,i+3);
+swap(this,i+1,i+2);
+}
+return this;
+};
+
+Buffer.prototype.swap64=function swap64(){
+var len=this.length;
+if(len%8!==0){
+throw new RangeError('Buffer size must be a multiple of 64-bits');
+}
+for(var i=0;i<len;i+=8){
+swap(this,i,i+7);
+swap(this,i+1,i+6);
+swap(this,i+2,i+5);
+swap(this,i+3,i+4);
+}
+return this;
+};
+
+Buffer.prototype.toString=function toString(){
+var length=this.length;
+if(length===0)return'';
+if(arguments.length===0)return utf8Slice(this,0,length);
+return slowToString.apply(this,arguments);
+};
+
+Buffer.prototype.toLocaleString=Buffer.prototype.toString;
+
+Buffer.prototype.equals=function equals(b){
+if(!Buffer.isBuffer(b))throw new TypeError('Argument must be a Buffer');
+if(this===b)return true;
+return Buffer.compare(this,b)===0;
+};
+
+Buffer.prototype.inspect=function inspect(){
+var str='';
+var max=exports.INSPECT_MAX_BYTES;
+str=this.toString('hex',0,max).replace(/(.{2})/g,'$1 ').trim();
+if(this.length>max)str+=' ... ';
+return'<Buffer '+str+'>';
+};
+
+Buffer.prototype.compare=function compare(target,start,end,thisStart,thisEnd){
+if(isInstance(target,Uint8Array)){
+target=Buffer.from(target,target.offset,target.byteLength);
+}
+if(!Buffer.isBuffer(target)){
+throw new TypeError(
+'The "target" argument must be one of type Buffer or Uint8Array. '+
+'Received type '+typeof target);
+
+}
+
+if(start===undefined){
+start=0;
+}
+if(end===undefined){
+end=target?target.length:0;
+}
+if(thisStart===undefined){
+thisStart=0;
+}
+if(thisEnd===undefined){
+thisEnd=this.length;
+}
+
+if(start<0||end>target.length||thisStart<0||thisEnd>this.length){
+throw new RangeError('out of range index');
+}
+
+if(thisStart>=thisEnd&&start>=end){
+return 0;
+}
+if(thisStart>=thisEnd){
+return-1;
+}
+if(start>=end){
+return 1;
+}
+
+start>>>=0;
+end>>>=0;
+thisStart>>>=0;
+thisEnd>>>=0;
+
+if(this===target)return 0;
+
+var x=thisEnd-thisStart;
+var y=end-start;
+var len=Math.min(x,y);
+
+var thisCopy=this.slice(thisStart,thisEnd);
+var targetCopy=target.slice(start,end);
+
+for(var i=0;i<len;++i){
+if(thisCopy[i]!==targetCopy[i]){
+x=thisCopy[i];
+y=targetCopy[i];
+break;
+}
+}
+
+if(x<y)return-1;
+if(y<x)return 1;
+return 0;
+};
+
+
+
+
+
+
+
+
+
+
+function bidirectionalIndexOf(buffer,val,byteOffset,encoding,dir){
+
+if(buffer.length===0)return-1;
+
+
+if(typeof byteOffset==='string'){
+encoding=byteOffset;
+byteOffset=0;
+}else if(byteOffset>0x7fffffff){
+byteOffset=0x7fffffff;
+}else if(byteOffset<-0x80000000){
+byteOffset=-0x80000000;
+}
+byteOffset=+byteOffset;
+if(numberIsNaN(byteOffset)){
+
+byteOffset=dir?0:buffer.length-1;
+}
+
+
+if(byteOffset<0)byteOffset=buffer.length+byteOffset;
+if(byteOffset>=buffer.length){
+if(dir)return-1;else
+byteOffset=buffer.length-1;
+}else if(byteOffset<0){
+if(dir)byteOffset=0;else
+return-1;
+}
+
+
+if(typeof val==='string'){
+val=Buffer.from(val,encoding);
+}
+
+
+if(Buffer.isBuffer(val)){
+
+if(val.length===0){
+return-1;
+}
+return arrayIndexOf(buffer,val,byteOffset,encoding,dir);
+}else if(typeof val==='number'){
+val=val&0xFF;
+if(typeof Uint8Array.prototype.indexOf==='function'){
+if(dir){
+return Uint8Array.prototype.indexOf.call(buffer,val,byteOffset);
+}else{
+return Uint8Array.prototype.lastIndexOf.call(buffer,val,byteOffset);
+}
+}
+return arrayIndexOf(buffer,[val],byteOffset,encoding,dir);
+}
+
+throw new TypeError('val must be string, number or Buffer');
+}
+
+function arrayIndexOf(arr,val,byteOffset,encoding,dir){
+var indexSize=1;
+var arrLength=arr.length;
+var valLength=val.length;
+
+if(encoding!==undefined){
+encoding=String(encoding).toLowerCase();
+if(encoding==='ucs2'||encoding==='ucs-2'||
+encoding==='utf16le'||encoding==='utf-16le'){
+if(arr.length<2||val.length<2){
+return-1;
+}
+indexSize=2;
+arrLength/=2;
+valLength/=2;
+byteOffset/=2;
+}
+}
+
+function read(buf,i){
+if(indexSize===1){
+return buf[i];
+}else{
+return buf.readUInt16BE(i*indexSize);
+}
+}
+
+var i;
+if(dir){
+var foundIndex=-1;
+for(i=byteOffset;i<arrLength;i++){
+if(read(arr,i)===read(val,foundIndex===-1?0:i-foundIndex)){
+if(foundIndex===-1)foundIndex=i;
+if(i-foundIndex+1===valLength)return foundIndex*indexSize;
+}else{
+if(foundIndex!==-1)i-=i-foundIndex;
+foundIndex=-1;
+}
+}
+}else{
+if(byteOffset+valLength>arrLength)byteOffset=arrLength-valLength;
+for(i=byteOffset;i>=0;i--){
+var found=true;
+for(var j=0;j<valLength;j++){
+if(read(arr,i+j)!==read(val,j)){
+found=false;
+break;
+}
+}
+if(found)return i;
+}
+}
+
+return-1;
+}
+
+Buffer.prototype.includes=function includes(val,byteOffset,encoding){
+return this.indexOf(val,byteOffset,encoding)!==-1;
+};
+
+Buffer.prototype.indexOf=function indexOf(val,byteOffset,encoding){
+return bidirectionalIndexOf(this,val,byteOffset,encoding,true);
+};
+
+Buffer.prototype.lastIndexOf=function lastIndexOf(val,byteOffset,encoding){
+return bidirectionalIndexOf(this,val,byteOffset,encoding,false);
+};
+
+function hexWrite(buf,string,offset,length){
+offset=Number(offset)||0;
+var remaining=buf.length-offset;
+if(!length){
+length=remaining;
+}else{
+length=Number(length);
+if(length>remaining){
+length=remaining;
+}
+}
+
+var strLen=string.length;
+
+if(length>strLen/2){
+length=strLen/2;
+}
+for(var i=0;i<length;++i){
+var parsed=parseInt(string.substr(i*2,2),16);
+if(numberIsNaN(parsed))return i;
+buf[offset+i]=parsed;
+}
+return i;
+}
+
+function utf8Write(buf,string,offset,length){
+return blitBuffer(utf8ToBytes(string,buf.length-offset),buf,offset,length);
+}
+
+function asciiWrite(buf,string,offset,length){
+return blitBuffer(asciiToBytes(string),buf,offset,length);
+}
+
+function latin1Write(buf,string,offset,length){
+return asciiWrite(buf,string,offset,length);
+}
+
+function base64Write(buf,string,offset,length){
+return blitBuffer(base64ToBytes(string),buf,offset,length);
+}
+
+function ucs2Write(buf,string,offset,length){
+return blitBuffer(utf16leToBytes(string,buf.length-offset),buf,offset,length);
+}
+
+Buffer.prototype.write=function write(string,offset,length,encoding){
+
+if(offset===undefined){
+encoding='utf8';
+length=this.length;
+offset=0;
+
+}else if(length===undefined&&typeof offset==='string'){
+encoding=offset;
+length=this.length;
+offset=0;
+
+}else if(isFinite(offset)){
+offset=offset>>>0;
+if(isFinite(length)){
+length=length>>>0;
+if(encoding===undefined)encoding='utf8';
+}else{
+encoding=length;
+length=undefined;
+}
+}else{
+throw new Error(
+'Buffer.write(string, encoding, offset[, length]) is no longer supported');
+
+}
+
+var remaining=this.length-offset;
+if(length===undefined||length>remaining)length=remaining;
+
+if(string.length>0&&(length<0||offset<0)||offset>this.length){
+throw new RangeError('Attempt to write outside buffer bounds');
+}
+
+if(!encoding)encoding='utf8';
+
+var loweredCase=false;
+for(;;){
+switch(encoding){
+case'hex':
+return hexWrite(this,string,offset,length);
+
+case'utf8':
+case'utf-8':
+return utf8Write(this,string,offset,length);
+
+case'ascii':
+return asciiWrite(this,string,offset,length);
+
+case'latin1':
+case'binary':
+return latin1Write(this,string,offset,length);
+
+case'base64':
+
+return base64Write(this,string,offset,length);
+
+case'ucs2':
+case'ucs-2':
+case'utf16le':
+case'utf-16le':
+return ucs2Write(this,string,offset,length);
+
+default:
+if(loweredCase)throw new TypeError('Unknown encoding: '+encoding);
+encoding=(''+encoding).toLowerCase();
+loweredCase=true;}
+
+}
+};
+
+Buffer.prototype.toJSON=function toJSON(){
+return{
+type:'Buffer',
+data:Array.prototype.slice.call(this._arr||this,0)};
+
+};
+
+function base64Slice(buf,start,end){
+if(start===0&&end===buf.length){
+return base64.fromByteArray(buf);
+}else{
+return base64.fromByteArray(buf.slice(start,end));
+}
+}
+
+function utf8Slice(buf,start,end){
+end=Math.min(buf.length,end);
+var res=[];
+
+var i=start;
+while(i<end){
+var firstByte=buf[i];
+var codePoint=null;
+var bytesPerSequence=firstByte>0xEF?4:
+firstByte>0xDF?3:
+firstByte>0xBF?2:
+1;
+
+if(i+bytesPerSequence<=end){
+var secondByte,thirdByte,fourthByte,tempCodePoint;
+
+switch(bytesPerSequence){
+case 1:
+if(firstByte<0x80){
+codePoint=firstByte;
+}
+break;
+case 2:
+secondByte=buf[i+1];
+if((secondByte&0xC0)===0x80){
+tempCodePoint=(firstByte&0x1F)<<0x6|secondByte&0x3F;
+if(tempCodePoint>0x7F){
+codePoint=tempCodePoint;
+}
+}
+break;
+case 3:
+secondByte=buf[i+1];
+thirdByte=buf[i+2];
+if((secondByte&0xC0)===0x80&&(thirdByte&0xC0)===0x80){
+tempCodePoint=(firstByte&0xF)<<0xC|(secondByte&0x3F)<<0x6|thirdByte&0x3F;
+if(tempCodePoint>0x7FF&&(tempCodePoint<0xD800||tempCodePoint>0xDFFF)){
+codePoint=tempCodePoint;
+}
+}
+break;
+case 4:
+secondByte=buf[i+1];
+thirdByte=buf[i+2];
+fourthByte=buf[i+3];
+if((secondByte&0xC0)===0x80&&(thirdByte&0xC0)===0x80&&(fourthByte&0xC0)===0x80){
+tempCodePoint=(firstByte&0xF)<<0x12|(secondByte&0x3F)<<0xC|(thirdByte&0x3F)<<0x6|fourthByte&0x3F;
+if(tempCodePoint>0xFFFF&&tempCodePoint<0x110000){
+codePoint=tempCodePoint;
+}
+}}
+
+}
+
+if(codePoint===null){
+
+
+codePoint=0xFFFD;
+bytesPerSequence=1;
+}else if(codePoint>0xFFFF){
+
+codePoint-=0x10000;
+res.push(codePoint>>>10&0x3FF|0xD800);
+codePoint=0xDC00|codePoint&0x3FF;
+}
+
+res.push(codePoint);
+i+=bytesPerSequence;
+}
+
+return decodeCodePointsArray(res);
+}
+
+
+
+
+var MAX_ARGUMENTS_LENGTH=0x1000;
+
+function decodeCodePointsArray(codePoints){
+var len=codePoints.length;
+if(len<=MAX_ARGUMENTS_LENGTH){
+return String.fromCharCode.apply(String,codePoints);
+}
+
+
+var res='';
+var i=0;
+while(i<len){
+res+=String.fromCharCode.apply(
+String,
+codePoints.slice(i,i+=MAX_ARGUMENTS_LENGTH));
+
+}
+return res;
+}
+
+function asciiSlice(buf,start,end){
+var ret='';
+end=Math.min(buf.length,end);
+
+for(var i=start;i<end;++i){
+ret+=String.fromCharCode(buf[i]&0x7F);
+}
+return ret;
+}
+
+function latin1Slice(buf,start,end){
+var ret='';
+end=Math.min(buf.length,end);
+
+for(var i=start;i<end;++i){
+ret+=String.fromCharCode(buf[i]);
+}
+return ret;
+}
+
+function hexSlice(buf,start,end){
+var len=buf.length;
+
+if(!start||start<0)start=0;
+if(!end||end<0||end>len)end=len;
+
+var out='';
+for(var i=start;i<end;++i){
+out+=toHex(buf[i]);
+}
+return out;
+}
+
+function utf16leSlice(buf,start,end){
+var bytes=buf.slice(start,end);
+var res='';
+for(var i=0;i<bytes.length;i+=2){
+res+=String.fromCharCode(bytes[i]+bytes[i+1]*256);
+}
+return res;
+}
+
+Buffer.prototype.slice=function slice(start,end){
+var len=this.length;
+start=~~start;
+end=end===undefined?len:~~end;
+
+if(start<0){
+start+=len;
+if(start<0)start=0;
+}else if(start>len){
+start=len;
+}
+
+if(end<0){
+end+=len;
+if(end<0)end=0;
+}else if(end>len){
+end=len;
+}
+
+if(end<start)end=start;
+
+var newBuf=this.subarray(start,end);
+
+newBuf.__proto__=Buffer.prototype;
+return newBuf;
+};
+
+
+
+
+function checkOffset(offset,ext,length){
+if(offset%1!==0||offset<0)throw new RangeError('offset is not uint');
+if(offset+ext>length)throw new RangeError('Trying to access beyond buffer length');
+}
+
+Buffer.prototype.readUIntLE=function readUIntLE(offset,byteLength,noAssert){
+offset=offset>>>0;
+byteLength=byteLength>>>0;
+if(!noAssert)checkOffset(offset,byteLength,this.length);
+
+var val=this[offset];
+var mul=1;
+var i=0;
+while(++i<byteLength&&(mul*=0x100)){
+val+=this[offset+i]*mul;
+}
+
+return val;
+};
+
+Buffer.prototype.readUIntBE=function readUIntBE(offset,byteLength,noAssert){
+offset=offset>>>0;
+byteLength=byteLength>>>0;
+if(!noAssert){
+checkOffset(offset,byteLength,this.length);
+}
+
+var val=this[offset+--byteLength];
+var mul=1;
+while(byteLength>0&&(mul*=0x100)){
+val+=this[offset+--byteLength]*mul;
+}
+
+return val;
+};
+
+Buffer.prototype.readUInt8=function readUInt8(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,1,this.length);
+return this[offset];
+};
+
+Buffer.prototype.readUInt16LE=function readUInt16LE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,2,this.length);
+return this[offset]|this[offset+1]<<8;
+};
+
+Buffer.prototype.readUInt16BE=function readUInt16BE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,2,this.length);
+return this[offset]<<8|this[offset+1];
+};
+
+Buffer.prototype.readUInt32LE=function readUInt32LE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,4,this.length);
+
+return(this[offset]|
+this[offset+1]<<8|
+this[offset+2]<<16)+
+this[offset+3]*0x1000000;
+};
+
+Buffer.prototype.readUInt32BE=function readUInt32BE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,4,this.length);
+
+return this[offset]*0x1000000+(
+this[offset+1]<<16|
+this[offset+2]<<8|
+this[offset+3]);
+};
+
+Buffer.prototype.readIntLE=function readIntLE(offset,byteLength,noAssert){
+offset=offset>>>0;
+byteLength=byteLength>>>0;
+if(!noAssert)checkOffset(offset,byteLength,this.length);
+
+var val=this[offset];
+var mul=1;
+var i=0;
+while(++i<byteLength&&(mul*=0x100)){
+val+=this[offset+i]*mul;
+}
+mul*=0x80;
+
+if(val>=mul)val-=Math.pow(2,8*byteLength);
+
+return val;
+};
+
+Buffer.prototype.readIntBE=function readIntBE(offset,byteLength,noAssert){
+offset=offset>>>0;
+byteLength=byteLength>>>0;
+if(!noAssert)checkOffset(offset,byteLength,this.length);
+
+var i=byteLength;
+var mul=1;
+var val=this[offset+--i];
+while(i>0&&(mul*=0x100)){
+val+=this[offset+--i]*mul;
+}
+mul*=0x80;
+
+if(val>=mul)val-=Math.pow(2,8*byteLength);
+
+return val;
+};
+
+Buffer.prototype.readInt8=function readInt8(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,1,this.length);
+if(!(this[offset]&0x80))return this[offset];
+return(0xff-this[offset]+1)*-1;
+};
+
+Buffer.prototype.readInt16LE=function readInt16LE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,2,this.length);
+var val=this[offset]|this[offset+1]<<8;
+return val&0x8000?val|0xFFFF0000:val;
+};
+
+Buffer.prototype.readInt16BE=function readInt16BE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,2,this.length);
+var val=this[offset+1]|this[offset]<<8;
+return val&0x8000?val|0xFFFF0000:val;
+};
+
+Buffer.prototype.readInt32LE=function readInt32LE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,4,this.length);
+
+return this[offset]|
+this[offset+1]<<8|
+this[offset+2]<<16|
+this[offset+3]<<24;
+};
+
+Buffer.prototype.readInt32BE=function readInt32BE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,4,this.length);
+
+return this[offset]<<24|
+this[offset+1]<<16|
+this[offset+2]<<8|
+this[offset+3];
+};
+
+Buffer.prototype.readFloatLE=function readFloatLE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,4,this.length);
+return ieee754.read(this,offset,true,23,4);
+};
+
+Buffer.prototype.readFloatBE=function readFloatBE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,4,this.length);
+return ieee754.read(this,offset,false,23,4);
+};
+
+Buffer.prototype.readDoubleLE=function readDoubleLE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,8,this.length);
+return ieee754.read(this,offset,true,52,8);
+};
+
+Buffer.prototype.readDoubleBE=function readDoubleBE(offset,noAssert){
+offset=offset>>>0;
+if(!noAssert)checkOffset(offset,8,this.length);
+return ieee754.read(this,offset,false,52,8);
+};
+
+function checkInt(buf,value,offset,ext,max,min){
+if(!Buffer.isBuffer(buf))throw new TypeError('"buffer" argument must be a Buffer instance');
+if(value>max||value<min)throw new RangeError('"value" argument is out of bounds');
+if(offset+ext>buf.length)throw new RangeError('Index out of range');
+}
+
+Buffer.prototype.writeUIntLE=function writeUIntLE(value,offset,byteLength,noAssert){
+value=+value;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
+if(!noAssert){
+var maxBytes=Math.pow(2,8*byteLength)-1;
+checkInt(this,value,offset,byteLength,maxBytes,0);
+}
+
+var mul=1;
+var i=0;
+this[offset]=value&0xFF;
+while(++i<byteLength&&(mul*=0x100)){
+this[offset+i]=value/mul&0xFF;
+}
+
+return offset+byteLength;
+};
+
+Buffer.prototype.writeUIntBE=function writeUIntBE(value,offset,byteLength,noAssert){
+value=+value;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
+if(!noAssert){
+var maxBytes=Math.pow(2,8*byteLength)-1;
+checkInt(this,value,offset,byteLength,maxBytes,0);
+}
+
+var i=byteLength-1;
+var mul=1;
+this[offset+i]=value&0xFF;
+while(--i>=0&&(mul*=0x100)){
+this[offset+i]=value/mul&0xFF;
+}
+
+return offset+byteLength;
+};
+
+Buffer.prototype.writeUInt8=function writeUInt8(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,1,0xff,0);
+this[offset]=value&0xff;
+return offset+1;
+};
+
+Buffer.prototype.writeUInt16LE=function writeUInt16LE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,2,0xffff,0);
+this[offset]=value&0xff;
+this[offset+1]=value>>>8;
+return offset+2;
+};
+
+Buffer.prototype.writeUInt16BE=function writeUInt16BE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,2,0xffff,0);
+this[offset]=value>>>8;
+this[offset+1]=value&0xff;
+return offset+2;
+};
+
+Buffer.prototype.writeUInt32LE=function writeUInt32LE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);
+this[offset+3]=value>>>24;
+this[offset+2]=value>>>16;
+this[offset+1]=value>>>8;
+this[offset]=value&0xff;
+return offset+4;
+};
+
+Buffer.prototype.writeUInt32BE=function writeUInt32BE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);
+this[offset]=value>>>24;
+this[offset+1]=value>>>16;
+this[offset+2]=value>>>8;
+this[offset+3]=value&0xff;
+return offset+4;
+};
+
+Buffer.prototype.writeIntLE=function writeIntLE(value,offset,byteLength,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert){
+var limit=Math.pow(2,8*byteLength-1);
+
+checkInt(this,value,offset,byteLength,limit-1,-limit);
+}
+
+var i=0;
+var mul=1;
+var sub=0;
+this[offset]=value&0xFF;
+while(++i<byteLength&&(mul*=0x100)){
+if(value<0&&sub===0&&this[offset+i-1]!==0){
+sub=1;
+}
+this[offset+i]=(value/mul>>0)-sub&0xFF;
+}
+
+return offset+byteLength;
+};
+
+Buffer.prototype.writeIntBE=function writeIntBE(value,offset,byteLength,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert){
+var limit=Math.pow(2,8*byteLength-1);
+
+checkInt(this,value,offset,byteLength,limit-1,-limit);
+}
+
+var i=byteLength-1;
+var mul=1;
+var sub=0;
+this[offset+i]=value&0xFF;
+while(--i>=0&&(mul*=0x100)){
+if(value<0&&sub===0&&this[offset+i+1]!==0){
+sub=1;
+}
+this[offset+i]=(value/mul>>0)-sub&0xFF;
+}
+
+return offset+byteLength;
+};
+
+Buffer.prototype.writeInt8=function writeInt8(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,1,0x7f,-0x80);
+if(value<0)value=0xff+value+1;
+this[offset]=value&0xff;
+return offset+1;
+};
+
+Buffer.prototype.writeInt16LE=function writeInt16LE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);
+this[offset]=value&0xff;
+this[offset+1]=value>>>8;
+return offset+2;
+};
+
+Buffer.prototype.writeInt16BE=function writeInt16BE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);
+this[offset]=value>>>8;
+this[offset+1]=value&0xff;
+return offset+2;
+};
+
+Buffer.prototype.writeInt32LE=function writeInt32LE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);
+this[offset]=value&0xff;
+this[offset+1]=value>>>8;
+this[offset+2]=value>>>16;
+this[offset+3]=value>>>24;
+return offset+4;
+};
+
+Buffer.prototype.writeInt32BE=function writeInt32BE(value,offset,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);
+if(value<0)value=0xffffffff+value+1;
+this[offset]=value>>>24;
+this[offset+1]=value>>>16;
+this[offset+2]=value>>>8;
+this[offset+3]=value&0xff;
+return offset+4;
+};
+
+function checkIEEE754(buf,value,offset,ext,max,min){
+if(offset+ext>buf.length)throw new RangeError('Index out of range');
+if(offset<0)throw new RangeError('Index out of range');
+}
+
+function writeFloat(buf,value,offset,littleEndian,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert){
+checkIEEE754(buf,value,offset,4,3.4028234663852886e+38,-3.4028234663852886e+38);
+}
+ieee754.write(buf,value,offset,littleEndian,23,4);
+return offset+4;
+}
+
+Buffer.prototype.writeFloatLE=function writeFloatLE(value,offset,noAssert){
+return writeFloat(this,value,offset,true,noAssert);
+};
+
+Buffer.prototype.writeFloatBE=function writeFloatBE(value,offset,noAssert){
+return writeFloat(this,value,offset,false,noAssert);
+};
+
+function writeDouble(buf,value,offset,littleEndian,noAssert){
+value=+value;
+offset=offset>>>0;
+if(!noAssert){
+checkIEEE754(buf,value,offset,8,1.7976931348623157E+308,-1.7976931348623157E+308);
+}
+ieee754.write(buf,value,offset,littleEndian,52,8);
+return offset+8;
+}
+
+Buffer.prototype.writeDoubleLE=function writeDoubleLE(value,offset,noAssert){
+return writeDouble(this,value,offset,true,noAssert);
+};
+
+Buffer.prototype.writeDoubleBE=function writeDoubleBE(value,offset,noAssert){
+return writeDouble(this,value,offset,false,noAssert);
+};
+
+
+Buffer.prototype.copy=function copy(target,targetStart,start,end){
+if(!Buffer.isBuffer(target))throw new TypeError('argument should be a Buffer');
+if(!start)start=0;
+if(!end&&end!==0)end=this.length;
+if(targetStart>=target.length)targetStart=target.length;
+if(!targetStart)targetStart=0;
+if(end>0&&end<start)end=start;
+
+
+if(end===start)return 0;
+if(target.length===0||this.length===0)return 0;
+
+
+if(targetStart<0){
+throw new RangeError('targetStart out of bounds');
+}
+if(start<0||start>=this.length)throw new RangeError('Index out of range');
+if(end<0)throw new RangeError('sourceEnd out of bounds');
+
+
+if(end>this.length)end=this.length;
+if(target.length-targetStart<end-start){
+end=target.length-targetStart+start;
+}
+
+var len=end-start;
+
+if(this===target&&typeof Uint8Array.prototype.copyWithin==='function'){
+
+this.copyWithin(targetStart,start,end);
+}else if(this===target&&start<targetStart&&targetStart<end){
+
+for(var i=len-1;i>=0;--i){
+target[i+targetStart]=this[i+start];
+}
+}else{
+Uint8Array.prototype.set.call(
+target,
+this.subarray(start,end),
+targetStart);
+
+}
+
+return len;
+};
+
+
+
+
+
+Buffer.prototype.fill=function fill(val,start,end,encoding){
+
+if(typeof val==='string'){
+if(typeof start==='string'){
+encoding=start;
+start=0;
+end=this.length;
+}else if(typeof end==='string'){
+encoding=end;
+end=this.length;
+}
+if(encoding!==undefined&&typeof encoding!=='string'){
+throw new TypeError('encoding must be a string');
+}
+if(typeof encoding==='string'&&!Buffer.isEncoding(encoding)){
+throw new TypeError('Unknown encoding: '+encoding);
+}
+if(val.length===1){
+var code=val.charCodeAt(0);
+if(encoding==='utf8'&&code<128||
+encoding==='latin1'){
+
+val=code;
+}
+}
+}else if(typeof val==='number'){
+val=val&255;
+}
+
+
+if(start<0||this.length<start||this.length<end){
+throw new RangeError('Out of range index');
+}
+
+if(end<=start){
+return this;
+}
+
+start=start>>>0;
+end=end===undefined?this.length:end>>>0;
+
+if(!val)val=0;
+
+var i;
+if(typeof val==='number'){
+for(i=start;i<end;++i){
+this[i]=val;
+}
+}else{
+var bytes=Buffer.isBuffer(val)?
+val:
+Buffer.from(val,encoding);
+var len=bytes.length;
+if(len===0){
+throw new TypeError('The value "'+val+
+'" is invalid for argument "value"');
+}
+for(i=0;i<end-start;++i){
+this[i+start]=bytes[i%len];
+}
+}
+
+return this;
+};
+
+
+
+
+var INVALID_BASE64_RE=/[^+/0-9A-Za-z-_]/g;
+
+function base64clean(str){
+
+str=str.split('=')[0];
+
+str=str.trim().replace(INVALID_BASE64_RE,'');
+
+if(str.length<2)return'';
+
+while(str.length%4!==0){
+str=str+'=';
+}
+return str;
+}
+
+function toHex(n){
+if(n<16)return'0'+n.toString(16);
+return n.toString(16);
+}
+
+function utf8ToBytes(string,units){
+units=units||Infinity;
+var codePoint;
+var length=string.length;
+var leadSurrogate=null;
+var bytes=[];
+
+for(var i=0;i<length;++i){
+codePoint=string.charCodeAt(i);
+
+
+if(codePoint>0xD7FF&&codePoint<0xE000){
+
+if(!leadSurrogate){
+
+if(codePoint>0xDBFF){
+
+if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
+continue;
+}else if(i+1===length){
+
+if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
+continue;
+}
+
+
+leadSurrogate=codePoint;
+
+continue;
+}
+
+
+if(codePoint<0xDC00){
+if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
+leadSurrogate=codePoint;
+continue;
+}
+
+
+codePoint=(leadSurrogate-0xD800<<10|codePoint-0xDC00)+0x10000;
+}else if(leadSurrogate){
+
+if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);
+}
+
+leadSurrogate=null;
+
+
+if(codePoint<0x80){
+if((units-=1)<0)break;
+bytes.push(codePoint);
+}else if(codePoint<0x800){
+if((units-=2)<0)break;
+bytes.push(
+codePoint>>0x6|0xC0,
+codePoint&0x3F|0x80);
+
+}else if(codePoint<0x10000){
+if((units-=3)<0)break;
+bytes.push(
+codePoint>>0xC|0xE0,
+codePoint>>0x6&0x3F|0x80,
+codePoint&0x3F|0x80);
+
+}else if(codePoint<0x110000){
+if((units-=4)<0)break;
+bytes.push(
+codePoint>>0x12|0xF0,
+codePoint>>0xC&0x3F|0x80,
+codePoint>>0x6&0x3F|0x80,
+codePoint&0x3F|0x80);
+
+}else{
+throw new Error('Invalid code point');
+}
+}
+
+return bytes;
+}
+
+function asciiToBytes(str){
+var byteArray=[];
+for(var i=0;i<str.length;++i){
+
+byteArray.push(str.charCodeAt(i)&0xFF);
+}
+return byteArray;
+}
+
+function utf16leToBytes(str,units){
+var c,hi,lo;
+var byteArray=[];
+for(var i=0;i<str.length;++i){
+if((units-=2)<0)break;
+
+c=str.charCodeAt(i);
+hi=c>>8;
+lo=c%256;
+byteArray.push(lo);
+byteArray.push(hi);
+}
+
+return byteArray;
+}
+
+function base64ToBytes(str){
+return base64.toByteArray(base64clean(str));
+}
+
+function blitBuffer(src,dst,offset,length){
+for(var i=0;i<length;++i){
+if(i+offset>=dst.length||i>=src.length)break;
+dst[i+offset]=src[i];
+}
+return i;
+}
+
+
+
+
+function isInstance(obj,type){
+return obj instanceof type||
+obj!=null&&obj.constructor!=null&&obj.constructor.name!=null&&
+obj.constructor.name===type.name;
+}
+function numberIsNaN(obj){
+
+return obj!==obj;
+}
+
+},{"base64-js":83,"ieee754":96}],89:[function(require,module,exports){
+(function(Buffer){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isArray(arg){
+if(Array.isArray){
+return Array.isArray(arg);
+}
+return objectToString(arg)==='[object Array]';
+}
+exports.isArray=isArray;
+
+function isBoolean(arg){
+return typeof arg==='boolean';
+}
+exports.isBoolean=isBoolean;
+
+function isNull(arg){
+return arg===null;
+}
+exports.isNull=isNull;
+
+function isNullOrUndefined(arg){
+return arg==null;
+}
+exports.isNullOrUndefined=isNullOrUndefined;
+
+function isNumber(arg){
+return typeof arg==='number';
+}
+exports.isNumber=isNumber;
+
+function isString(arg){
+return typeof arg==='string';
+}
+exports.isString=isString;
+
+function isSymbol(arg){
+return typeof arg==='symbol';
+}
+exports.isSymbol=isSymbol;
+
+function isUndefined(arg){
+return arg===void 0;
+}
+exports.isUndefined=isUndefined;
+
+function isRegExp(re){
+return objectToString(re)==='[object RegExp]';
+}
+exports.isRegExp=isRegExp;
+
+function isObject(arg){
+return typeof arg==='object'&&arg!==null;
+}
+exports.isObject=isObject;
+
+function isDate(d){
+return objectToString(d)==='[object Date]';
+}
+exports.isDate=isDate;
+
+function isError(e){
+return objectToString(e)==='[object Error]'||e instanceof Error;
+}
+exports.isError=isError;
+
+function isFunction(arg){
+return typeof arg==='function';
+}
+exports.isFunction=isFunction;
+
+function isPrimitive(arg){
+return arg===null||
+typeof arg==='boolean'||
+typeof arg==='number'||
+typeof arg==='string'||
+typeof arg==='symbol'||
+typeof arg==='undefined';
+}
+exports.isPrimitive=isPrimitive;
+
+exports.isBuffer=Buffer.isBuffer;
+
+function objectToString(o){
+return Object.prototype.toString.call(o);
+}
+
+}).call(this,{"isBuffer":require("../../insert-module-globals/node_modules/is-buffer/index.js")});
+},{"../../insert-module-globals/node_modules/is-buffer/index.js":99}],90:[function(require,module,exports){
+
+
+
+
+'use strict';
+
+exports.TYPES={
+INTEGER:1,
+NUMBER:2,
+LENGTH:3,
+PERCENT:4,
+URL:5,
+COLOR:6,
+STRING:7,
+ANGLE:8,
+KEYWORD:9,
+NULL_OR_EMPTY_STR:10};
+
+
+
+
+var integerRegEx=/^[\-+]?[0-9]+$/;
+var numberRegEx=/^[\-+]?[0-9]*\.[0-9]+$/;
+var lengthRegEx=/^(0|[\-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw))$/;
+var percentRegEx=/^[\-+]?[0-9]*\.?[0-9]+%$/;
+var urlRegEx=/^url\(\s*([^\)]*)\s*\)$/;
+var stringRegEx=/^(\"[^\"]*\"|\'[^\']*\')$/;
+var colorRegEx1=/^#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])?$/;
+var colorRegEx2=/^rgb\(([^\)]*)\)$/;
+var colorRegEx3=/^rgba\(([^\)]*)\)$/;
+var angleRegEx=/^([\-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/;
+
+
+
+exports.valueType=function valueType(val){
+if(val===''||val===null){
+return exports.TYPES.NULL_OR_EMPTY_STR;
+}
+if(typeof val==='number'){
+val=val.toString();
+}
+
+if(typeof val!=='string'){
+return undefined;
+}
+
+if(integerRegEx.test(val)){
+return exports.TYPES.INTEGER;
+}
+if(numberRegEx.test(val)){
+return exports.TYPES.NUMBER;
+}
+if(lengthRegEx.test(val)){
+return exports.TYPES.LENGTH;
+}
+if(percentRegEx.test(val)){
+return exports.TYPES.PERCENT;
+}
+if(urlRegEx.test(val)){
+return exports.TYPES.URL;
+}
+if(stringRegEx.test(val)){
+return exports.TYPES.STRING;
+}
+if(angleRegEx.test(val)){
+return exports.TYPES.ANGLE;
+}
+if(colorRegEx1.test(val)){
+return exports.TYPES.COLOR;
+}
+var res=colorRegEx2.exec(val);
+var parts;
+if(res!==null){
+parts=res[1].split(/\s*,\s*/);
+if(parts.length!==3){
+return undefined;
+}
+if(parts.every(percentRegEx.test.bind(percentRegEx))||parts.every(integerRegEx.test.bind(integerRegEx))){
+return exports.TYPES.COLOR;
+}
+return undefined;
+}
+res=colorRegEx3.exec(val);
+if(res!==null){
+parts=res[1].split(/\s*,\s*/);
+if(parts.length!==4){
+return undefined;
+}
+if(parts.slice(0,3).every(percentRegEx.test.bind(percentRegEx))||parts.every(integerRegEx.test.bind(integerRegEx))){
+if(numberRegEx.test(parts[3])){
+return exports.TYPES.COLOR;
+}
+}
+return undefined;
+}
+
+
+val=val.toLowerCase();
+switch(val){
+case'maroon':
+case'red':
+case'orange':
+case'yellow':
+case'olive':
+case'purple':
+case'fuchsia':
+case'white':
+case'lime':
+case'green':
+case'navy':
+case'blue':
+case'aqua':
+case'teal':
+case'black':
+case'silver':
+case'gray':
+
+case'activeborder':
+case'activecaption':
+case'appworkspace':
+case'background':
+case'buttonface':
+case'buttonhighlight':
+case'buttonshadow':
+case'buttontext':
+case'captiontext':
+case'graytext':
+case'highlight':
+case'highlighttext':
+case'inactiveborder':
+case'inactivecaption':
+case'inactivecaptiontext':
+case'infobackground':
+case'infotext':
+case'menu':
+case'menutext':
+case'scrollbar':
+case'threeddarkshadow':
+case'threedface':
+case'threedhighlight':
+case'threedlightshadow':
+case'threedshadow':
+case'window':
+case'windowframe':
+case'windowtext':
+return exports.TYPES.COLOR;
+default:
+return exports.TYPES.KEYWORD;}
+
+};
+
+exports.parseInteger=function parseInteger(val){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.INTEGER){
+return undefined;
+}
+return String(parseInt(val,10));
+};
+
+exports.parseNumber=function parseNumber(val){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.NUMBER&&type!==exports.TYPES.INTEGER){
+return undefined;
+}
+return String(parseFloat(val));
+};
+
+exports.parseLength=function parseLength(val){
+if(val===0||val==='0'){
+return'0px';
+}
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.LENGTH){
+return undefined;
+}
+return val;
+};
+
+exports.parsePercent=function parsePercent(val){
+if(val===0||val==='0'){
+return'0%';
+}
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.PERCENT){
+return undefined;
+}
+return val;
+};
+
+
+exports.parseMeasurement=function parseMeasurement(val){
+var length=exports.parseLength(val);
+if(length!==undefined){
+return length;
+}
+return exports.parsePercent(val);
+};
+
+exports.parseUrl=function parseUrl(val){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+var res=urlRegEx.exec(val);
+
+if(!res){
+return undefined;
+}
+var str=res[1];
+
+if((str[0]==='"'||str[0]==="'")&&str[0]!==str[str.length-1]){
+return undefined;
+}
+if(str[0]==='"'||str[0]==="'"){
+str=str.substr(1,str.length-2);
+}
+
+var i;
+for(i=0;i<str.length;i++){
+switch(str[i]){
+case'(':
+case')':
+case' ':
+case'\t':
+case'\n':
+case"'":
+case'"':
+return undefined;
+case'\\':
+i++;
+break;}
+
+}
+
+return'url('+str+')';
+};
+
+exports.parseString=function parseString(val){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.STRING){
+return undefined;
+}
+var i;
+for(i=1;i<val.length-1;i++){
+switch(val[i]){
+case val[0]:
+return undefined;
+case'\\':
+i++;
+while(i<val.length-1&&/[0-9A-Fa-f]/.test(val[i])){
+i++;
+}
+break;}
+
+}
+if(i>=val.length){
+return undefined;
+}
+return val;
+};
+
+exports.parseColor=function parseColor(val){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+var red,green,blue,alpha=1;
+var parts;
+var res=colorRegEx1.exec(val);
+
+if(res){
+var hex=val.substr(1);
+if(hex.length===3){
+hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
+}
+red=parseInt(hex.substr(0,2),16);
+green=parseInt(hex.substr(2,2),16);
+blue=parseInt(hex.substr(4,2),16);
+return'rgb('+red+', '+green+', '+blue+')';
+}
+
+res=colorRegEx2.exec(val);
+if(res){
+parts=res[1].split(/\s*,\s*/);
+if(parts.length!==3){
+return undefined;
+}
+if(parts.every(percentRegEx.test.bind(percentRegEx))){
+red=Math.floor(parseFloat(parts[0].slice(0,-1))*255/100);
+green=Math.floor(parseFloat(parts[1].slice(0,-1))*255/100);
+blue=Math.floor(parseFloat(parts[2].slice(0,-1))*255/100);
+}else if(parts.every(integerRegEx.test.bind(integerRegEx))){
+red=parseInt(parts[0],10);
+green=parseInt(parts[1],10);
+blue=parseInt(parts[2],10);
+}else{
+return undefined;
+}
+red=Math.min(255,Math.max(0,red));
+green=Math.min(255,Math.max(0,green));
+blue=Math.min(255,Math.max(0,blue));
+return'rgb('+red+', '+green+', '+blue+')';
+}
+
+res=colorRegEx3.exec(val);
+if(res){
+parts=res[1].split(/\s*,\s*/);
+if(parts.length!==4){
+return undefined;
+}
+if(parts.slice(0,3).every(percentRegEx.test.bind(percentRegEx))){
+red=Math.floor(parseFloat(parts[0].slice(0,-1))*255/100);
+green=Math.floor(parseFloat(parts[1].slice(0,-1))*255/100);
+blue=Math.floor(parseFloat(parts[2].slice(0,-1))*255/100);
+alpha=parseFloat(parts[3]);
+}else if(parts.slice(0,3).every(integerRegEx.test.bind(integerRegEx))){
+red=parseInt(parts[0],10);
+green=parseInt(parts[1],10);
+blue=parseInt(parts[2],10);
+alpha=parseFloat(parts[3]);
+}else{
+return undefined;
+}
+if(isNaN(alpha)){
+alpha=1;
+}
+red=Math.min(255,Math.max(0,red));
+green=Math.min(255,Math.max(0,green));
+blue=Math.min(255,Math.max(0,blue));
+alpha=Math.min(1,Math.max(0,alpha));
+if(alpha===1){
+return'rgb('+red+', '+green+', '+blue+')';
+}
+return'rgba('+red+', '+green+', '+blue+', '+alpha+')';
+}
+
+if(type===exports.TYPES.COLOR){
+return val;
+}
+return undefined;
+};
+
+exports.parseAngle=function parseAngle(val){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.ANGLE){
+return undefined;
+}
+var res=angleRegEx.exec(val);
+var flt=parseFloat(res[1]);
+if(res[2]==='rad'){
+flt*=180/Math.PI;
+}else if(res[2]==='grad'){
+flt*=360/400;
+}
+
+while(flt<0){
+flt+=360;
+}
+while(flt>360){
+flt-=360;
+}
+return flt+'deg';
+};
+
+exports.parseKeyword=function parseKeyword(val,valid_keywords){
+var type=exports.valueType(val);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+return val;
+}
+if(type!==exports.TYPES.KEYWORD){
+return undefined;
+}
+val=val.toString().toLowerCase();
+var i;
+for(i=0;i<valid_keywords.length;i++){
+if(valid_keywords[i].toLowerCase()===val){
+return valid_keywords[i];
+}
+}
+return undefined;
+};
+
+
+var dashedToCamelCase=function(dashed){
+var i;
+var camel='';
+var nextCap=false;
+for(i=0;i<dashed.length;i++){
+if(dashed[i]!=='-'){
+camel+=nextCap?dashed[i].toUpperCase():dashed[i];
+nextCap=false;
+}else{
+nextCap=true;
+}
+}
+return camel;
+};
+exports.dashedToCamelCase=dashedToCamelCase;
+
+var is_space=/\s/;
+var opening_deliminators=['"','\'','('];
+var closing_deliminators=['"','\'',')'];
+
+var getParts=function(str){
+var deliminator_stack=[];
+var length=str.length;
+var i;
+var parts=[];
+var current_part='';
+var opening_index;
+var closing_index;
+for(i=0;i<length;i++){
+opening_index=opening_deliminators.indexOf(str[i]);
+closing_index=closing_deliminators.indexOf(str[i]);
+if(is_space.test(str[i])){
+if(deliminator_stack.length===0){
+if(current_part!==''){
+parts.push(current_part);
+}
+current_part='';
+}else{
+current_part+=str[i];
+}
+}else{
+if(str[i]==='\\'){
+i++;
+current_part+=str[i];
+}else{
+current_part+=str[i];
+if(closing_index!==-1&&closing_index===deliminator_stack[deliminator_stack.length-1]){
+deliminator_stack.pop();
+}else if(opening_index!==-1){
+deliminator_stack.push(opening_index);
+}
+}
+}
+}
+if(current_part!==''){
+parts.push(current_part);
+}
+return parts;
+};
+
+
+
+
+
+
+
+exports.shorthandParser=function parse(v,shorthand_for){
+var obj={};
+var type=exports.valueType(v);
+if(type===exports.TYPES.NULL_OR_EMPTY_STR){
+Object.keys(shorthand_for).forEach(function(property){
+obj[property]='';
+});
+return obj;
+}
+
+if(typeof v==='number'){
+v=v.toString();
+}
+
+if(typeof v!=='string'){
+return undefined;
+}
+
+if(v.toLowerCase()==='inherit'){
+return{};
+}
+var parts=getParts(v);
+var valid=true;
+parts.forEach(function(part){
+var part_valid=false;
+Object.keys(shorthand_for).forEach(function(property){
+if(shorthand_for[property].isValid(part)){
+part_valid=true;
+obj[property]=part;
+}
+});
+valid=valid&&part_valid;
+});
+if(!valid){
+return undefined;
+}
+return obj;
+};
+
+exports.shorthandSetter=function(property,shorthand_for){
+return function(v){
+var obj=exports.shorthandParser(v,shorthand_for);
+if(obj===undefined){
+return;
+}
+
+Object.keys(obj).forEach(function(subprop){
+
+
+var camel=dashedToCamelCase(subprop);
+this[camel]=obj[subprop];
+
+obj[subprop]=this[camel];
+this.removeProperty(subprop);
+
+if(obj[subprop]!==''){
+this._values[subprop]=obj[subprop];
+}
+},this);
+Object.keys(shorthand_for).forEach(function(subprop){
+if(!obj.hasOwnProperty(subprop)){
+this.removeProperty(subprop);
+delete this._values[subprop];
+}
+},this);
+
+
+
+
+this.removeProperty(property);
+var calculated=exports.shorthandGetter(property,shorthand_for).call(this);
+if(calculated!==''){
+this._setProperty(property,calculated);
+}
+};
+};
+
+exports.shorthandGetter=function(property,shorthand_for){
+return function(){
+if(this._values[property]!==undefined){
+return this.getPropertyValue(property);
+}
+return Object.keys(shorthand_for).map(function(subprop){
+return this.getPropertyValue(subprop);
+},this).filter(function(value){
+return value!=='';
+}).join(' ');
+};
+};
+
+
+
+
+
+
+exports.implicitSetter=function(property_before,property_after,isValid,parser){
+property_after=property_after||'';
+if(property_after!==''){
+property_after='-'+property_after;
+}
+var part_names=["top","right","bottom","left"];
+
+return function(v){
+if(typeof v==='number'){
+v=v.toString();
+}
+if(typeof v!=='string'){
+return undefined;
+}
+var parts;
+if(v.toLowerCase()==='inherit'||v===''){
+parts=[v];
+}else{
+parts=getParts(v);
+}
+if(parts.length<1||parts.length>4){
+return undefined;
+}
+
+if(!parts.every(isValid)){
+return undefined;
+}
+
+parts=parts.map(function(part){
+return parser(part);
+});
+this._setProperty(property_before+property_after,parts.join(' '));
+if(parts.length===1){
+parts[1]=parts[0];
+}
+if(parts.length===2){
+parts[2]=parts[0];
+}
+if(parts.length===3){
+parts[3]=parts[1];
+}
+
+for(var i=0;i<4;i++){
+var property=property_before+"-"+part_names[i]+property_after;
+this.removeProperty(property);
+if(parts[i]!==''){
+this._values[property]=parts[i];
+}
+}
+return v;
+};
+};
+
+
+
+
+
+
+
+exports.subImplicitSetter=function(prefix,part,isValid,parser){
+var property=prefix+'-'+part;
+var subparts=[prefix+"-top",prefix+"-right",prefix+"-bottom",prefix+"-left"];
+
+return function(v){
+if(typeof v==='number'){
+v=v.toString();
+}
+if(typeof v!=='string'){
+return undefined;
+}
+if(!isValid(v)){
+return undefined;
+}
+v=parser(v);
+this._setProperty(property,v);
+var parts=[];
+for(var i=0;i<4;i++){
+if(this._values[subparts[i]]==null||this._values[subparts[i]]===''){
+break;
+}
+parts.push(this._values[subparts[i]]);
+}
+if(parts.length===4){
+for(i=0;i<4;i++){
+this.removeProperty(subparts[i]);
+this._values[subparts[i]]=parts[i];
+}
+this._setProperty(prefix,parts.join(" "));
+}
+return v;
+};
+};
+
+
+var camel_to_dashed=/[A-Z]/g;
+
+var first_segment=/^\([^\-]\)-/;
+
+var vendor_prefixes=['o','moz','ms','webkit'];
+exports.camelToDashed=function(camel_case){
+var match;
+var dashed=camel_case.replace(camel_to_dashed,'-$&').toLowerCase();
+match=dashed.match(first_segment);
+if(match&&vendor_prefixes.indexOf(match[1])!==-1){
+dashed='-'+dashed;
+}
+return dashed;
+};
+
+},{}],91:[function(require,module,exports){
+(function(process){
+
+
+
+
+
+
+exports=module.exports=require('./debug');
+exports.log=log;
+exports.formatArgs=formatArgs;
+exports.save=save;
+exports.load=load;
+exports.useColors=useColors;
+exports.storage='undefined'!=typeof chrome&&
+'undefined'!=typeof chrome.storage?
+chrome.storage.local:
+localstorage();
+
+
+
+
+
+exports.colors=[
+'lightseagreen',
+'forestgreen',
+'goldenrod',
+'dodgerblue',
+'darkorchid',
+'crimson'];
+
+
+
+
+
+
+
+
+
+
+function useColors(){
+
+
+
+if(typeof window!=='undefined'&&window.process&&window.process.type==='renderer'){
+return true;
+}
+
+
+
+return typeof document!=='undefined'&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||
+
+typeof window!=='undefined'&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||
+
+
+typeof navigator!=='undefined'&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||
+
+typeof navigator!=='undefined'&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
+}
+
+
+
+
+
+exports.formatters.j=function(v){
+try{
+return JSON.stringify(v);
+}catch(err){
+return'[UnexpectedJSONParseError]: '+err.message;
+}
+};
+
+
+
+
+
+
+
+
+function formatArgs(args){
+var useColors=this.useColors;
+
+args[0]=(useColors?'%c':'')+
+this.namespace+(
+useColors?' %c':' ')+
+args[0]+(
+useColors?'%c ':' ')+
+'+'+exports.humanize(this.diff);
+
+if(!useColors)return;
+
+var c='color: '+this.color;
+args.splice(1,0,c,'color: inherit');
+
+
+
+
+var index=0;
+var lastC=0;
+args[0].replace(/%[a-zA-Z%]/g,function(match){
+if('%%'===match)return;
+index++;
+if('%c'===match){
+
+
+lastC=index;
+}
+});
+
+args.splice(lastC,0,c);
+}
+
+
+
+
+
+
+
+
+function log(){
+
+
+return'object'===typeof console&&
+console.log&&
+Function.prototype.apply.call(console.log,console,arguments);
+}
+
+
+
+
+
+
+
+
+function save(namespaces){
+try{
+if(null==namespaces){
+exports.storage.removeItem('debug');
+}else{
+exports.storage.debug=namespaces;
+}
+}catch(e){}
+}
+
+
+
+
+
+
+
+
+function load(){
+var r;
+try{
+r=exports.storage.debug;
+}catch(e){}
+
+
+if(!r&&typeof process!=='undefined'&&'env'in process){
+r=process.env.DEBUG;
+}
+
+return r;
+}
+
+
+
+
+
+exports.enable(load());
+
+
+
+
+
+
+
+
+
+
+
+
+function localstorage(){
+try{
+return window.localStorage;
+}catch(e){}
+}
+
+}).call(this,require('_process'));
+},{"./debug":92,"_process":130}],92:[function(require,module,exports){
+
+
+
+
+
+
+
+
+exports=module.exports=createDebug.debug=createDebug['default']=createDebug;
+exports.coerce=coerce;
+exports.disable=disable;
+exports.enable=enable;
+exports.enabled=enabled;
+exports.humanize=require('ms');
+
+
+
+
+
+exports.names=[];
+exports.skips=[];
+
+
+
+
+
+
+
+exports.formatters={};
+
+
+
+
+
+var prevTime;
+
+
+
+
+
+
+
+
+function selectColor(namespace){
+var hash=0,i;
+
+for(i in namespace){
+hash=(hash<<5)-hash+namespace.charCodeAt(i);
+hash|=0;
+}
+
+return exports.colors[Math.abs(hash)%exports.colors.length];
+}
+
+
+
+
+
+
+
+
+
+function createDebug(namespace){
+
+function debug(){
+
+if(!debug.enabled)return;
+
+var self=debug;
+
+
+var curr=+new Date();
+var ms=curr-(prevTime||curr);
+self.diff=ms;
+self.prev=prevTime;
+self.curr=curr;
+prevTime=curr;
+
+
+var args=new Array(arguments.length);
+for(var i=0;i<args.length;i++){
+args[i]=arguments[i];
+}
+
+args[0]=exports.coerce(args[0]);
+
+if('string'!==typeof args[0]){
+
+args.unshift('%O');
+}
+
+
+var index=0;
+args[0]=args[0].replace(/%([a-zA-Z%])/g,function(match,format){
+
+if(match==='%%')return match;
+index++;
+var formatter=exports.formatters[format];
+if('function'===typeof formatter){
+var val=args[index];
+match=formatter.call(self,val);
+
+
+args.splice(index,1);
+index--;
+}
+return match;
+});
+
+
+exports.formatArgs.call(self,args);
+
+var logFn=debug.log||exports.log||console.log.bind(console);
+logFn.apply(self,args);
+}
+
+debug.namespace=namespace;
+debug.enabled=exports.enabled(namespace);
+debug.useColors=exports.useColors();
+debug.color=selectColor(namespace);
+
+
+if('function'===typeof exports.init){
+exports.init(debug);
+}
+
+return debug;
+}
+
+
+
+
+
+
+
+
+
+function enable(namespaces){
+exports.save(namespaces);
+
+exports.names=[];
+exports.skips=[];
+
+var split=(typeof namespaces==='string'?namespaces:'').split(/[\s,]+/);
+var len=split.length;
+
+for(var i=0;i<len;i++){
+if(!split[i])continue;
+namespaces=split[i].replace(/\*/g,'.*?');
+if(namespaces[0]==='-'){
+exports.skips.push(new RegExp('^'+namespaces.substr(1)+'$'));
+}else{
+exports.names.push(new RegExp('^'+namespaces+'$'));
+}
+}
+}
+
+
+
+
+
+
+
+function disable(){
+exports.enable('');
+}
+
+
+
+
+
+
+
+
+
+function enabled(name){
+var i,len;
+for(i=0,len=exports.skips.length;i<len;i++){
+if(exports.skips[i].test(name)){
+return false;
+}
+}
+for(i=0,len=exports.names.length;i<len;i++){
+if(exports.names[i].test(name)){
+return true;
+}
+}
+return false;
+}
+
+
+
+
+
+
+
+
+
+function coerce(val){
+if(val instanceof Error)return val.stack||val.message;
+return val;
+}
+
+},{"ms":118}],93:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var objectCreate=Object.create||objectCreatePolyfill;
+var objectKeys=Object.keys||objectKeysPolyfill;
+var bind=Function.prototype.bind||functionBindPolyfill;
+
+function EventEmitter(){
+if(!this._events||!Object.prototype.hasOwnProperty.call(this,'_events')){
+this._events=objectCreate(null);
+this._eventsCount=0;
+}
+
+this._maxListeners=this._maxListeners||undefined;
+}
+module.exports=EventEmitter;
+
+
+EventEmitter.EventEmitter=EventEmitter;
+
+EventEmitter.prototype._events=undefined;
+EventEmitter.prototype._maxListeners=undefined;
+
+
+
+var defaultMaxListeners=10;
+
+var hasDefineProperty;
+try{
+var o={};
+if(Object.defineProperty)Object.defineProperty(o,'x',{value:0});
+hasDefineProperty=o.x===0;
+}catch(err){hasDefineProperty=false;}
+if(hasDefineProperty){
+Object.defineProperty(EventEmitter,'defaultMaxListeners',{
+enumerable:true,
+get:function(){
+return defaultMaxListeners;
+},
+set:function(arg){
+
+
+if(typeof arg!=='number'||arg<0||arg!==arg)
+throw new TypeError('"defaultMaxListeners" must be a positive number');
+defaultMaxListeners=arg;
+}});
+
+}else{
+EventEmitter.defaultMaxListeners=defaultMaxListeners;
+}
+
+
+
+EventEmitter.prototype.setMaxListeners=function setMaxListeners(n){
+if(typeof n!=='number'||n<0||isNaN(n))
+throw new TypeError('"n" argument must be a positive number');
+this._maxListeners=n;
+return this;
+};
+
+function $getMaxListeners(that){
+if(that._maxListeners===undefined)
+return EventEmitter.defaultMaxListeners;
+return that._maxListeners;
+}
+
+EventEmitter.prototype.getMaxListeners=function getMaxListeners(){
+return $getMaxListeners(this);
+};
+
+
+
+
+
+
+function emitNone(handler,isFn,self){
+if(isFn)
+handler.call(self);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self);
+}
+}
+function emitOne(handler,isFn,self,arg1){
+if(isFn)
+handler.call(self,arg1);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self,arg1);
+}
+}
+function emitTwo(handler,isFn,self,arg1,arg2){
+if(isFn)
+handler.call(self,arg1,arg2);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self,arg1,arg2);
+}
+}
+function emitThree(handler,isFn,self,arg1,arg2,arg3){
+if(isFn)
+handler.call(self,arg1,arg2,arg3);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self,arg1,arg2,arg3);
+}
+}
+
+function emitMany(handler,isFn,self,args){
+if(isFn)
+handler.apply(self,args);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].apply(self,args);
+}
+}
+
+EventEmitter.prototype.emit=function emit(type){
+var er,handler,len,args,i,events;
+var doError=type==='error';
+
+events=this._events;
+if(events)
+doError=doError&&events.error==null;else
+if(!doError)
+return false;
+
+
+if(doError){
+if(arguments.length>1)
+er=arguments[1];
+if(er instanceof Error){
+throw er;
+}else{
+
+var err=new Error('Unhandled "error" event. ('+er+')');
+err.context=er;
+throw err;
+}
+return false;
+}
+
+handler=events[type];
+
+if(!handler)
+return false;
+
+var isFn=typeof handler==='function';
+len=arguments.length;
+switch(len){
+
+case 1:
+emitNone(handler,isFn,this);
+break;
+case 2:
+emitOne(handler,isFn,this,arguments[1]);
+break;
+case 3:
+emitTwo(handler,isFn,this,arguments[1],arguments[2]);
+break;
+case 4:
+emitThree(handler,isFn,this,arguments[1],arguments[2],arguments[3]);
+break;
+
+default:
+args=new Array(len-1);
+for(i=1;i<len;i++)
+args[i-1]=arguments[i];
+emitMany(handler,isFn,this,args);}
+
+
+return true;
+};
+
+function _addListener(target,type,listener,prepend){
+var m;
+var events;
+var existing;
+
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
+
+events=target._events;
+if(!events){
+events=target._events=objectCreate(null);
+target._eventsCount=0;
+}else{
+
+
+if(events.newListener){
+target.emit('newListener',type,
+listener.listener?listener.listener:listener);
+
+
+
+events=target._events;
+}
+existing=events[type];
+}
+
+if(!existing){
+
+existing=events[type]=listener;
+++target._eventsCount;
+}else{
+if(typeof existing==='function'){
+
+existing=events[type]=
+prepend?[listener,existing]:[existing,listener];
+}else{
+
+if(prepend){
+existing.unshift(listener);
+}else{
+existing.push(listener);
+}
+}
+
+
+if(!existing.warned){
+m=$getMaxListeners(target);
+if(m&&m>0&&existing.length>m){
+existing.warned=true;
+var w=new Error('Possible EventEmitter memory leak detected. '+
+existing.length+' "'+String(type)+'" listeners '+
+'added. Use emitter.setMaxListeners() to '+
+'increase limit.');
+w.name='MaxListenersExceededWarning';
+w.emitter=target;
+w.type=type;
+w.count=existing.length;
+if(typeof console==='object'&&console.warn){
+console.warn('%s: %s',w.name,w.message);
+}
+}
+}
+}
+
+return target;
+}
+
+EventEmitter.prototype.addListener=function addListener(type,listener){
+return _addListener(this,type,listener,false);
+};
+
+EventEmitter.prototype.on=EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.prependListener=
+function prependListener(type,listener){
+return _addListener(this,type,listener,true);
+};
+
+function onceWrapper(){
+if(!this.fired){
+this.target.removeListener(this.type,this.wrapFn);
+this.fired=true;
+switch(arguments.length){
+case 0:
+return this.listener.call(this.target);
+case 1:
+return this.listener.call(this.target,arguments[0]);
+case 2:
+return this.listener.call(this.target,arguments[0],arguments[1]);
+case 3:
+return this.listener.call(this.target,arguments[0],arguments[1],
+arguments[2]);
+default:
+var args=new Array(arguments.length);
+for(var i=0;i<args.length;++i)
+args[i]=arguments[i];
+this.listener.apply(this.target,args);}
+
+}
+}
+
+function _onceWrap(target,type,listener){
+var state={fired:false,wrapFn:undefined,target:target,type:type,listener:listener};
+var wrapped=bind.call(onceWrapper,state);
+wrapped.listener=listener;
+state.wrapFn=wrapped;
+return wrapped;
+}
+
+EventEmitter.prototype.once=function once(type,listener){
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
+this.on(type,_onceWrap(this,type,listener));
+return this;
+};
+
+EventEmitter.prototype.prependOnceListener=
+function prependOnceListener(type,listener){
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
+this.prependListener(type,_onceWrap(this,type,listener));
+return this;
+};
+
+
+EventEmitter.prototype.removeListener=
+function removeListener(type,listener){
+var list,events,position,i,originalListener;
+
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
+
+events=this._events;
+if(!events)
+return this;
+
+list=events[type];
+if(!list)
+return this;
+
+if(list===listener||list.listener===listener){
+if(--this._eventsCount===0)
+this._events=objectCreate(null);else
+{
+delete events[type];
+if(events.removeListener)
+this.emit('removeListener',type,list.listener||listener);
+}
+}else if(typeof list!=='function'){
+position=-1;
+
+for(i=list.length-1;i>=0;i--){
+if(list[i]===listener||list[i].listener===listener){
+originalListener=list[i].listener;
+position=i;
+break;
+}
+}
+
+if(position<0)
+return this;
+
+if(position===0)
+list.shift();else
+
+spliceOne(list,position);
+
+if(list.length===1)
+events[type]=list[0];
+
+if(events.removeListener)
+this.emit('removeListener',type,originalListener||listener);
+}
+
+return this;
+};
+
+EventEmitter.prototype.removeAllListeners=
+function removeAllListeners(type){
+var listeners,events,i;
+
+events=this._events;
+if(!events)
+return this;
+
+
+if(!events.removeListener){
+if(arguments.length===0){
+this._events=objectCreate(null);
+this._eventsCount=0;
+}else if(events[type]){
+if(--this._eventsCount===0)
+this._events=objectCreate(null);else
+
+delete events[type];
+}
+return this;
+}
+
+
+if(arguments.length===0){
+var keys=objectKeys(events);
+var key;
+for(i=0;i<keys.length;++i){
+key=keys[i];
+if(key==='removeListener')continue;
+this.removeAllListeners(key);
+}
+this.removeAllListeners('removeListener');
+this._events=objectCreate(null);
+this._eventsCount=0;
+return this;
+}
+
+listeners=events[type];
+
+if(typeof listeners==='function'){
+this.removeListener(type,listeners);
+}else if(listeners){
+
+for(i=listeners.length-1;i>=0;i--){
+this.removeListener(type,listeners[i]);
+}
+}
+
+return this;
+};
+
+function _listeners(target,type,unwrap){
+var events=target._events;
+
+if(!events)
+return[];
+
+var evlistener=events[type];
+if(!evlistener)
+return[];
+
+if(typeof evlistener==='function')
+return unwrap?[evlistener.listener||evlistener]:[evlistener];
+
+return unwrap?unwrapListeners(evlistener):arrayClone(evlistener,evlistener.length);
+}
+
+EventEmitter.prototype.listeners=function listeners(type){
+return _listeners(this,type,true);
+};
+
+EventEmitter.prototype.rawListeners=function rawListeners(type){
+return _listeners(this,type,false);
+};
+
+EventEmitter.listenerCount=function(emitter,type){
+if(typeof emitter.listenerCount==='function'){
+return emitter.listenerCount(type);
+}else{
+return listenerCount.call(emitter,type);
+}
+};
+
+EventEmitter.prototype.listenerCount=listenerCount;
+function listenerCount(type){
+var events=this._events;
+
+if(events){
+var evlistener=events[type];
+
+if(typeof evlistener==='function'){
+return 1;
+}else if(evlistener){
+return evlistener.length;
+}
+}
+
+return 0;
+}
+
+EventEmitter.prototype.eventNames=function eventNames(){
+return this._eventsCount>0?Reflect.ownKeys(this._events):[];
+};
+
+
+function spliceOne(list,index){
+for(var i=index,k=i+1,n=list.length;k<n;i+=1,k+=1)
+list[i]=list[k];
+list.pop();
+}
+
+function arrayClone(arr,n){
+var copy=new Array(n);
+for(var i=0;i<n;++i)
+copy[i]=arr[i];
+return copy;
+}
+
+function unwrapListeners(arr){
+var ret=new Array(arr.length);
+for(var i=0;i<ret.length;++i){
+ret[i]=arr[i].listener||arr[i];
+}
+return ret;
+}
+
+function objectCreatePolyfill(proto){
+var F=function(){};
+F.prototype=proto;
+return new F();
+}
+function objectKeysPolyfill(obj){
+var keys=[];
+for(var k in obj)if(Object.prototype.hasOwnProperty.call(obj,k)){
+keys.push(k);
+}
+return k;
+}
+function functionBindPolyfill(context){
+var fn=this;
+return function(){
+return fn.apply(context,arguments);
+};
+}
+
+},{}],94:[function(require,module,exports){
+(function(Buffer){
+var querystring=require('querystring');
+var trim=require('./trim');
+
+
+
+
+
+
+function Link(value){
+
+if(!(this instanceof Link)){
+return new Link(value);
+}
+
+
+this.refs=[];
+
+}
+
+
+
+
+
+Link.pattern=/(?:\<([^\>]+)\>)((\s*;\s*([a-z\*]+)=(("[^"]+")|('[^']+')|([^\,\;]+)))*)(\s*,\s*|$)/gi;
+
+
+
+
+
+Link.attrPattern=/([a-z\*]+)=(?:(?:"([^"]+)")|(?:'([^']+)')|([^\,\;]+))/gi;
+
+
+
+
+
+
+
+Link.isCompatibleEncoding=function(value){
+return /^utf-?8|ascii|utf-?16-?le|ucs-?2|base-?64|latin-?1$/i.test(value);
+};
+
+
+
+
+
+
+
+Link.formatExtendedAttribute=function(attr,data){
+
+var encoding=(data.encoding||'utf-8').toUpperCase();
+var language=data.language||'en';
+
+var encodedValue='';
+
+if(Buffer.isBuffer(data.value)&&Link.isCompatibleEncoding(encoding)){
+encodedValue=data.value.toString(encoding);
+}else if(Buffer.isBuffer(data.value)){
+encodedValue=data.value.toString('hex').
+replace(/[0-9a-f]{2}/gi,'%$1');
+}else{
+encodedValue=querystring.escape(data.value);
+}
+
+return attr+'='+encoding+'\''+
+language+'\''+encodedValue;
+
+};
+
+
+
+
+
+
+
+Link.formatAttribute=function(attr,value){
+
+
+if(/\*$/.test(attr)||typeof value!=='string')
+return Link.formatExtendedAttribute(attr,value);
+
+
+
+var needsQuotes=/[^a-z]/i.test(value);
+
+if(needsQuotes){
+
+value=querystring.escape(value).
+replace(/%20/g,' ').
+replace(/%2C/g,',').
+replace(/%3B/g,';');
+
+value='"'+value+'"';
+}
+
+return attr+'='+value;
+
+};
+
+
+
+
+
+
+
+Link.parseExtendedValue=function(value){
+var parts=/([^']+)?(?:'([^']+)')?(.+)/.exec(value);
+return{
+language:parts[2].toLowerCase(),
+encoding:Link.isCompatibleEncoding(parts[1])?
+null:parts[1].toLowerCase(),
+value:Link.isCompatibleEncoding(parts[1])?
+querystring.unescape(parts[3]):parts[3]};
+
+};
+
+
+
+
+
+
+
+Link.setAttr=function(link,attr,value){
+
+
+
+if(attr==='rel'&&link[attr]!=null)
+return link;
+
+if(Array.isArray(link[attr])){
+link[attr].push(value);
+}else if(link[attr]!=null){
+link[attr]=[link[attr],value];
+}else{
+link[attr]=value;
+}
+
+return link;
+
+};
+
+
+
+
+Link.parseParams=function(link,uri){
+
+var kvs={};
+var params=/(.+)\?(.+)/gi.exec(uri);
+
+if(!params){
+return link;
+}
+
+params=params[2].split('&');
+
+for(var i=0;i<params.length;i++){
+var param=params[i].split('=');
+kvs[param[0]]=param[1];
+}
+
+Link.setAttr(link,'params',kvs);
+
+return link;
+
+};
+
+
+
+
+
+
+
+
+Link.parseAttrs=function(link,parts){
+
+var match=null;
+var attr='';
+var value='';
+var attrs='';
+
+var uriAttrs=/<(.*)>;\s*(.*)/gi.exec(parts);
+if(uriAttrs){
+attrs=uriAttrs[2];
+link=Link.parseParams(link,uriAttrs[1]);
+}
+
+while(match=Link.attrPattern.exec(attrs)){
+attr=match[1].toLowerCase();
+value=match[4]||match[3]||match[2];
+if(/\*$/.test(attr)){
+Link.setAttr(link,attr,Link.parseExtendedValue(value));
+}else if(/%/.test(value)){
+Link.setAttr(link,attr,querystring.unescape(value));
+}else{
+Link.setAttr(link,attr,value);
+}
+}
+
+return link;
+
+};
+
+Link.parse=function(value){
+return new Link().parse(value);
+};
+
+
+
+
+
+Link.prototype={
+
+constructor:Link,
+
+
+
+
+
+
+rel:function(value){
+
+var links=[];
+
+for(var i=0;i<this.refs.length;i++){
+if(this.refs[i].rel===value){
+links.push(this.refs[i]);
+}
+}
+
+return links;
+
+},
+
+
+
+
+
+
+
+get:function(attr,value){
+
+attr=attr.toLowerCase();
+
+var links=[];
+
+for(var i=0;i<this.refs.length;i++){
+if(this.refs[i][attr]===value){
+links.push(this.refs[i]);
+}
+}
+
+return links;
+
+},
+
+set:function(link){
+this.refs.push(link);
+return this;
+},
+
+has:function(attr,value){
+return this.get(attr,value)!=null;
+},
+
+parse:function(value){
+
+
+value=trim(value).
+replace(/\r?\n[\x20\x09]+/g,'');
+
+var match=null;
+
+while(match=Link.pattern.exec(value)){
+var link=Link.parseAttrs({uri:match[1]},match[0]);
+this.refs.push(link);
+}
+
+return this;
+
+},
+
+toString:function(){
+
+var refs=[];
+var link='';
+var ref=null;
+
+for(var i=0;i<this.refs.length;i++){
+ref=this.refs[i];
+link=Object.keys(this.refs[i]).reduce(function(link,attr){
+if(attr==='uri')return link;
+return link+'; '+Link.formatAttribute(attr,ref[attr]);
+},'<'+ref.uri+'>');
+refs.push(link);
+}
+
+return refs.join(', ');
+
+}};
+
+
+
+
+module.exports=Link;
+
+}).call(this,{"isBuffer":require("../../insert-module-globals/node_modules/is-buffer/index.js")});
+},{"../../insert-module-globals/node_modules/is-buffer/index.js":99,"./trim":95,"querystring":133}],95:[function(require,module,exports){
+module.exports=function trim(value){
+return value.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,'');
+};
+
+},{}],96:[function(require,module,exports){
+exports.read=function(buffer,offset,isLE,mLen,nBytes){
+var e,m;
+var eLen=nBytes*8-mLen-1;
+var eMax=(1<<eLen)-1;
+var eBias=eMax>>1;
+var nBits=-7;
+var i=isLE?nBytes-1:0;
+var d=isLE?-1:1;
+var s=buffer[offset+i];
+
+i+=d;
+
+e=s&(1<<-nBits)-1;
+s>>=-nBits;
+nBits+=eLen;
+for(;nBits>0;e=e*256+buffer[offset+i],i+=d,nBits-=8){}
+
+m=e&(1<<-nBits)-1;
+e>>=-nBits;
+nBits+=mLen;
+for(;nBits>0;m=m*256+buffer[offset+i],i+=d,nBits-=8){}
+
+if(e===0){
+e=1-eBias;
+}else if(e===eMax){
+return m?NaN:(s?-1:1)*Infinity;
+}else{
+m=m+Math.pow(2,mLen);
+e=e-eBias;
+}
+return(s?-1:1)*m*Math.pow(2,e-mLen);
+};
+
+exports.write=function(buffer,value,offset,isLE,mLen,nBytes){
+var e,m,c;
+var eLen=nBytes*8-mLen-1;
+var eMax=(1<<eLen)-1;
+var eBias=eMax>>1;
+var rt=mLen===23?Math.pow(2,-24)-Math.pow(2,-77):0;
+var i=isLE?0:nBytes-1;
+var d=isLE?1:-1;
+var s=value<0||value===0&&1/value<0?1:0;
+
+value=Math.abs(value);
+
+if(isNaN(value)||value===Infinity){
+m=isNaN(value)?1:0;
+e=eMax;
+}else{
+e=Math.floor(Math.log(value)/Math.LN2);
+if(value*(c=Math.pow(2,-e))<1){
+e--;
+c*=2;
+}
+if(e+eBias>=1){
+value+=rt/c;
+}else{
+value+=rt*Math.pow(2,1-eBias);
+}
+if(value*c>=2){
+e++;
+c/=2;
+}
+
+if(e+eBias>=eMax){
+m=0;
+e=eMax;
+}else if(e+eBias>=1){
+m=(value*c-1)*Math.pow(2,mLen);
+e=e+eBias;
+}else{
+m=value*Math.pow(2,eBias-1)*Math.pow(2,mLen);
+e=0;
+}
+}
+
+for(;mLen>=8;buffer[offset+i]=m&0xff,i+=d,m/=256,mLen-=8){}
+
+e=e<<mLen|m;
+eLen+=mLen;
+for(;eLen>0;buffer[offset+i]=e&0xff,i+=d,e/=256,eLen-=8){}
+
+buffer[offset+i-d]|=s*128;
+};
+
+},{}],97:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+var ImageSSIM;
+(function(ImageSSIM){
+'use strict';
+
+
+
+(function(Channels){
+Channels[Channels["Grey"]=1]="Grey";
+Channels[Channels["GreyAlpha"]=2]="GreyAlpha";
+Channels[Channels["RGB"]=3]="RGB";
+Channels[Channels["RGBAlpha"]=4]="RGBAlpha";
+})(ImageSSIM.Channels||(ImageSSIM.Channels={}));
+var Channels=ImageSSIM.Channels;
+
+
+
+
+function compare(image1,image2,windowSize,K1,K2,luminance,bitsPerComponent){
+if(windowSize===void 0){windowSize=8;}
+if(K1===void 0){K1=0.01;}
+if(K2===void 0){K2=0.03;}
+if(luminance===void 0){luminance=true;}
+if(bitsPerComponent===void 0){bitsPerComponent=8;}
+if(image1.width!==image2.width||image1.height!==image2.height){
+throw new Error('Images have different sizes!');
+}
+
+var L=(1<<bitsPerComponent)-1;
+
+var c1=Math.pow(K1*L,2),c2=Math.pow(K2*L,2),numWindows=0,mssim=0.0;
+var mcs=0.0;
+function iteration(lumaValues1,lumaValues2,averageLumaValue1,averageLumaValue2){
+
+var sigxy,sigsqx,sigsqy;
+sigxy=sigsqx=sigsqy=0.0;
+for(var i=0;i<lumaValues1.length;i++){
+sigsqx+=Math.pow(lumaValues1[i]-averageLumaValue1,2);
+sigsqy+=Math.pow(lumaValues2[i]-averageLumaValue2,2);
+sigxy+=(lumaValues1[i]-averageLumaValue1)*(lumaValues2[i]-averageLumaValue2);
+}
+var numPixelsInWin=lumaValues1.length-1;
+sigsqx/=numPixelsInWin;
+sigsqy/=numPixelsInWin;
+sigxy/=numPixelsInWin;
+
+var numerator=(2*averageLumaValue1*averageLumaValue2+c1)*(2*sigxy+c2);
+var denominator=(Math.pow(averageLumaValue1,2)+Math.pow(averageLumaValue2,2)+c1)*(sigsqx+sigsqy+c2);
+mssim+=numerator/denominator;
+mcs+=(2*sigxy+c2)/(sigsqx+sigsqy+c2);
+numWindows++;
+}
+
+Internals._iterate(image1,image2,windowSize,luminance,iteration);
+return{ssim:mssim/numWindows,mcs:mcs/numWindows};
+}
+ImageSSIM.compare=compare;
+
+
+
+var Internals;
+(function(Internals){
+function _iterate(image1,image2,windowSize,luminance,callback){
+var width=image1.width,height=image1.height;
+for(var y=0;y<height;y+=windowSize){
+for(var x=0;x<width;x+=windowSize){
+
+var windowWidth=Math.min(windowSize,width-x),windowHeight=Math.min(windowSize,height-y);
+var lumaValues1=_lumaValuesForWindow(image1,x,y,windowWidth,windowHeight,luminance),lumaValues2=_lumaValuesForWindow(image2,x,y,windowWidth,windowHeight,luminance),averageLuma1=_averageLuma(lumaValues1),averageLuma2=_averageLuma(lumaValues2);
+callback(lumaValues1,lumaValues2,averageLuma1,averageLuma2);
+}
+}
+}
+Internals._iterate=_iterate;
+function _lumaValuesForWindow(image,x,y,width,height,luminance){
+var array=image.data,lumaValues=new Float32Array(new ArrayBuffer(width*height*4)),counter=0;
+var maxj=y+height;
+for(var j=y;j<maxj;j++){
+var offset=j*image.width;
+var i=(offset+x)*image.channels;
+var maxi=(offset+x+width)*image.channels;
+switch(image.channels){
+case 1:
+while(i<maxi){
+
+lumaValues[counter++]=array[i++];
+}
+break;
+case 2:
+while(i<maxi){
+lumaValues[counter++]=array[i++]*(array[i++]/255);
+}
+break;
+case 3:
+if(luminance){
+while(i<maxi){
+lumaValues[counter++]=array[i++]*0.212655+array[i++]*0.715158+array[i++]*0.072187;
+}
+}else
+{
+while(i<maxi){
+lumaValues[counter++]=array[i++]+array[i++]+array[i++];
+}
+}
+break;
+case 4:
+if(luminance){
+while(i<maxi){
+lumaValues[counter++]=(array[i++]*0.212655+array[i++]*0.715158+array[i++]*0.072187)*(array[i++]/255);
+}
+}else
+{
+while(i<maxi){
+lumaValues[counter++]=(array[i++]+array[i++]+array[i++])*(array[i++]/255);
+}
+}
+break;}
+
+}
+return lumaValues;
+}
+function _averageLuma(lumaValues){
+var sumLuma=0.0;
+for(var i=0;i<lumaValues.length;i++){
+sumLuma+=lumaValues[i];
+}
+return sumLuma/lumaValues.length;
+}
+})(Internals||(Internals={}));
+})(ImageSSIM||(ImageSSIM={}));
+module.exports=ImageSSIM;
+
+},{}],98:[function(require,module,exports){
+arguments[4][79][0].apply(exports,arguments);
+},{"dup":79}],99:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+module.exports=function(obj){
+return obj!=null&&(isBuffer(obj)||isSlowBuffer(obj)||!!obj._isBuffer);
+};
+
+function isBuffer(obj){
+return!!obj.constructor&&typeof obj.constructor.isBuffer==='function'&&obj.constructor.isBuffer(obj);
+}
+
+
+function isSlowBuffer(obj){
+return typeof obj.readFloatLE==='function'&&typeof obj.slice==='function'&&isBuffer(obj.slice(0,0));
+}
+
+},{}],100:[function(require,module,exports){
+'use strict';
+
+exports=module.exports=require('./lib/parser')['default'];
+exports['default']=exports;
+
+},{"./lib/parser":101}],101:[function(require,module,exports){
+"use strict";
+
+exports["default"]=function(){
+"use strict";
+
+
+
+
+
+
+
+function peg$subclass(child,parent){
+function ctor(){this.constructor=child;}
+ctor.prototype=parent.prototype;
+child.prototype=new ctor();
+}
+
+function peg$SyntaxError(message,expected,found,location){
+this.message=message;
+this.expected=expected;
+this.found=found;
+this.location=location;
+this.name="SyntaxError";
+
+if(typeof Error.captureStackTrace==="function"){
+Error.captureStackTrace(this,peg$SyntaxError);
+}
+}
+
+peg$subclass(peg$SyntaxError,Error);
+
+function peg$parse(input){
+var options=arguments.length>1?arguments[1]:{},
+parser=this,
+
+peg$FAILED={},
+
+peg$startRuleFunctions={start:peg$parsestart},
+peg$startRuleFunction=peg$parsestart,
+
+peg$c0=function(elements){
+return{
+type:'messageFormatPattern',
+elements:elements,
+location:location()};
+
+},
+peg$c1=function(text){
+var string='',
+i,j,outerLen,inner,innerLen;
+
+for(i=0,outerLen=text.length;i<outerLen;i+=1){
+inner=text[i];
+
+for(j=0,innerLen=inner.length;j<innerLen;j+=1){
+string+=inner[j];
+}
+}
+
+return string;
+},
+peg$c2=function(messageText){
+return{
+type:'messageTextElement',
+value:messageText,
+location:location()};
+
+},
+peg$c3=/^[^ \t\n\r,.+={}#]/,
+peg$c4={type:"class",value:"[^ \\t\\n\\r,.+={}#]",description:"[^ \\t\\n\\r,.+={}#]"},
+peg$c5="{",
+peg$c6={type:"literal",value:"{",description:"\"{\""},
+peg$c7=",",
+peg$c8={type:"literal",value:",",description:"\",\""},
+peg$c9="}",
+peg$c10={type:"literal",value:"}",description:"\"}\""},
+peg$c11=function(id,format){
+return{
+type:'argumentElement',
+id:id,
+format:format&&format[2],
+location:location()};
+
+},
+peg$c12="number",
+peg$c13={type:"literal",value:"number",description:"\"number\""},
+peg$c14="date",
+peg$c15={type:"literal",value:"date",description:"\"date\""},
+peg$c16="time",
+peg$c17={type:"literal",value:"time",description:"\"time\""},
+peg$c18=function(type,style){
+return{
+type:type+'Format',
+style:style&&style[2],
+location:location()};
+
+},
+peg$c19="plural",
+peg$c20={type:"literal",value:"plural",description:"\"plural\""},
+peg$c21=function(pluralStyle){
+return{
+type:pluralStyle.type,
+ordinal:false,
+offset:pluralStyle.offset||0,
+options:pluralStyle.options,
+location:location()};
+
+},
+peg$c22="selectordinal",
+peg$c23={type:"literal",value:"selectordinal",description:"\"selectordinal\""},
+peg$c24=function(pluralStyle){
+return{
+type:pluralStyle.type,
+ordinal:true,
+offset:pluralStyle.offset||0,
+options:pluralStyle.options,
+location:location()};
+
+},
+peg$c25="select",
+peg$c26={type:"literal",value:"select",description:"\"select\""},
+peg$c27=function(options){
+return{
+type:'selectFormat',
+options:options,
+location:location()};
+
+},
+peg$c28="=",
+peg$c29={type:"literal",value:"=",description:"\"=\""},
+peg$c30=function(selector,pattern){
+return{
+type:'optionalFormatPattern',
+selector:selector,
+value:pattern,
+location:location()};
+
+},
+peg$c31="offset:",
+peg$c32={type:"literal",value:"offset:",description:"\"offset:\""},
+peg$c33=function(number){
+return number;
+},
+peg$c34=function(offset,options){
+return{
+type:'pluralFormat',
+offset:offset,
+options:options,
+location:location()};
+
+},
+peg$c35={type:"other",description:"whitespace"},
+peg$c36=/^[ \t\n\r]/,
+peg$c37={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},
+peg$c38={type:"other",description:"optionalWhitespace"},
+peg$c39=/^[0-9]/,
+peg$c40={type:"class",value:"[0-9]",description:"[0-9]"},
+peg$c41=/^[0-9a-f]/i,
+peg$c42={type:"class",value:"[0-9a-f]i",description:"[0-9a-f]i"},
+peg$c43="0",
+peg$c44={type:"literal",value:"0",description:"\"0\""},
+peg$c45=/^[1-9]/,
+peg$c46={type:"class",value:"[1-9]",description:"[1-9]"},
+peg$c47=function(digits){
+return parseInt(digits,10);
+},
+peg$c48=/^[^{}\\\0-\x1F \t\n\r]/,
+peg$c49={type:"class",value:"[^{}\\\\\\0-\\x1F\\x7f \\t\\n\\r]",description:"[^{}\\\\\\0-\\x1F\\x7f \\t\\n\\r]"},
+peg$c50="\\\\",
+peg$c51={type:"literal",value:"\\\\",description:"\"\\\\\\\\\""},
+peg$c52=function(){return'\\';},
+peg$c53="\\#",
+peg$c54={type:"literal",value:"\\#",description:"\"\\\\#\""},
+peg$c55=function(){return'\\#';},
+peg$c56="\\{",
+peg$c57={type:"literal",value:"\\{",description:"\"\\\\{\""},
+peg$c58=function(){return'\u007B';},
+peg$c59="\\}",
+peg$c60={type:"literal",value:"\\}",description:"\"\\\\}\""},
+peg$c61=function(){return'\u007D';},
+peg$c62="\\u",
+peg$c63={type:"literal",value:"\\u",description:"\"\\\\u\""},
+peg$c64=function(digits){
+return String.fromCharCode(parseInt(digits,16));
+},
+peg$c65=function(chars){return chars.join('');},
+
+peg$currPos=0,
+peg$savedPos=0,
+peg$posDetailsCache=[{line:1,column:1,seenCR:false}],
+peg$maxFailPos=0,
+peg$maxFailExpected=[],
+peg$silentFails=0,
+
+peg$result;
+
+if("startRule"in options){
+if(!(options.startRule in peg$startRuleFunctions)){
+throw new Error("Can't start parsing from rule \""+options.startRule+"\".");
+}
+
+peg$startRuleFunction=peg$startRuleFunctions[options.startRule];
+}
+
+function text(){
+return input.substring(peg$savedPos,peg$currPos);
+}
+
+function location(){
+return peg$computeLocation(peg$savedPos,peg$currPos);
+}
+
+function expected(description){
+throw peg$buildException(
+null,
+[{type:"other",description:description}],
+input.substring(peg$savedPos,peg$currPos),
+peg$computeLocation(peg$savedPos,peg$currPos));
+
+}
+
+function error(message){
+throw peg$buildException(
+message,
+null,
+input.substring(peg$savedPos,peg$currPos),
+peg$computeLocation(peg$savedPos,peg$currPos));
+
+}
+
+function peg$computePosDetails(pos){
+var details=peg$posDetailsCache[pos],
+p,ch;
+
+if(details){
+return details;
+}else{
+p=pos-1;
+while(!peg$posDetailsCache[p]){
+p--;
+}
+
+details=peg$posDetailsCache[p];
+details={
+line:details.line,
+column:details.column,
+seenCR:details.seenCR};
+
+
+while(p<pos){
+ch=input.charAt(p);
+if(ch==="\n"){
+if(!details.seenCR){details.line++;}
+details.column=1;
+details.seenCR=false;
+}else if(ch==="\r"||ch==="\u2028"||ch==="\u2029"){
+details.line++;
+details.column=1;
+details.seenCR=true;
+}else{
+details.column++;
+details.seenCR=false;
+}
+
+p++;
+}
+
+peg$posDetailsCache[pos]=details;
+return details;
+}
+}
+
+function peg$computeLocation(startPos,endPos){
+var startPosDetails=peg$computePosDetails(startPos),
+endPosDetails=peg$computePosDetails(endPos);
+
+return{
+start:{
+offset:startPos,
+line:startPosDetails.line,
+column:startPosDetails.column},
+
+end:{
+offset:endPos,
+line:endPosDetails.line,
+column:endPosDetails.column}};
+
+
+}
+
+function peg$fail(expected){
+if(peg$currPos<peg$maxFailPos){return;}
+
+if(peg$currPos>peg$maxFailPos){
+peg$maxFailPos=peg$currPos;
+peg$maxFailExpected=[];
+}
+
+peg$maxFailExpected.push(expected);
+}
+
+function peg$buildException(message,expected,found,location){
+function cleanupExpected(expected){
+var i=1;
+
+expected.sort(function(a,b){
+if(a.description<b.description){
+return-1;
+}else if(a.description>b.description){
+return 1;
+}else{
+return 0;
+}
+});
+
+while(i<expected.length){
+if(expected[i-1]===expected[i]){
+expected.splice(i,1);
+}else{
+i++;
+}
+}
+}
+
+function buildMessage(expected,found){
+function stringEscape(s){
+function hex(ch){return ch.charCodeAt(0).toString(16).toUpperCase();}
+
+return s.
+replace(/\\/g,'\\\\').
+replace(/"/g,'\\"').
+replace(/\x08/g,'\\b').
+replace(/\t/g,'\\t').
+replace(/\n/g,'\\n').
+replace(/\f/g,'\\f').
+replace(/\r/g,'\\r').
+replace(/[\x00-\x07\x0B\x0E\x0F]/g,function(ch){return'\\x0'+hex(ch);}).
+replace(/[\x10-\x1F\x80-\xFF]/g,function(ch){return'\\x'+hex(ch);}).
+replace(/[\u0100-\u0FFF]/g,function(ch){return'\\u0'+hex(ch);}).
+replace(/[\u1000-\uFFFF]/g,function(ch){return'\\u'+hex(ch);});
+}
+
+var expectedDescs=new Array(expected.length),
+expectedDesc,foundDesc,i;
+
+for(i=0;i<expected.length;i++){
+expectedDescs[i]=expected[i].description;
+}
+
+expectedDesc=expected.length>1?
+expectedDescs.slice(0,-1).join(", ")+
+" or "+
+expectedDescs[expected.length-1]:
+expectedDescs[0];
+
+foundDesc=found?"\""+stringEscape(found)+"\"":"end of input";
+
+return"Expected "+expectedDesc+" but "+foundDesc+" found.";
+}
+
+if(expected!==null){
+cleanupExpected(expected);
+}
+
+return new peg$SyntaxError(
+message!==null?message:buildMessage(expected,found),
+expected,
+found,
+location);
+
+}
+
+function peg$parsestart(){
+var s0;
+
+s0=peg$parsemessageFormatPattern();
+
+return s0;
+}
+
+function peg$parsemessageFormatPattern(){
+var s0,s1,s2;
+
+s0=peg$currPos;
+s1=[];
+s2=peg$parsemessageFormatElement();
+while(s2!==peg$FAILED){
+s1.push(s2);
+s2=peg$parsemessageFormatElement();
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c0(s1);
+}
+s0=s1;
+
+return s0;
+}
+
+function peg$parsemessageFormatElement(){
+var s0;
+
+s0=peg$parsemessageTextElement();
+if(s0===peg$FAILED){
+s0=peg$parseargumentElement();
+}
+
+return s0;
+}
+
+function peg$parsemessageText(){
+var s0,s1,s2,s3,s4,s5;
+
+s0=peg$currPos;
+s1=[];
+s2=peg$currPos;
+s3=peg$parse_();
+if(s3!==peg$FAILED){
+s4=peg$parsechars();
+if(s4!==peg$FAILED){
+s5=peg$parse_();
+if(s5!==peg$FAILED){
+s3=[s3,s4,s5];
+s2=s3;
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+if(s2!==peg$FAILED){
+while(s2!==peg$FAILED){
+s1.push(s2);
+s2=peg$currPos;
+s3=peg$parse_();
+if(s3!==peg$FAILED){
+s4=peg$parsechars();
+if(s4!==peg$FAILED){
+s5=peg$parse_();
+if(s5!==peg$FAILED){
+s3=[s3,s4,s5];
+s2=s3;
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+}
+}else{
+s1=peg$FAILED;
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c1(s1);
+}
+s0=s1;
+if(s0===peg$FAILED){
+s0=peg$currPos;
+s1=peg$parsews();
+if(s1!==peg$FAILED){
+s0=input.substring(s0,peg$currPos);
+}else{
+s0=s1;
+}
+}
+
+return s0;
+}
+
+function peg$parsemessageTextElement(){
+var s0,s1;
+
+s0=peg$currPos;
+s1=peg$parsemessageText();
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c2(s1);
+}
+s0=s1;
+
+return s0;
+}
+
+function peg$parseargument(){
+var s0,s1,s2;
+
+s0=peg$parsenumber();
+if(s0===peg$FAILED){
+s0=peg$currPos;
+s1=[];
+if(peg$c3.test(input.charAt(peg$currPos))){
+s2=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s2=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c4);}
+}
+if(s2!==peg$FAILED){
+while(s2!==peg$FAILED){
+s1.push(s2);
+if(peg$c3.test(input.charAt(peg$currPos))){
+s2=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s2=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c4);}
+}
+}
+}else{
+s1=peg$FAILED;
+}
+if(s1!==peg$FAILED){
+s0=input.substring(s0,peg$currPos);
+}else{
+s0=s1;
+}
+}
+
+return s0;
+}
+
+function peg$parseargumentElement(){
+var s0,s1,s2,s3,s4,s5,s6,s7,s8;
+
+s0=peg$currPos;
+if(input.charCodeAt(peg$currPos)===123){
+s1=peg$c5;
+peg$currPos++;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c6);}
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+s3=peg$parseargument();
+if(s3!==peg$FAILED){
+s4=peg$parse_();
+if(s4!==peg$FAILED){
+s5=peg$currPos;
+if(input.charCodeAt(peg$currPos)===44){
+s6=peg$c7;
+peg$currPos++;
+}else{
+s6=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c8);}
+}
+if(s6!==peg$FAILED){
+s7=peg$parse_();
+if(s7!==peg$FAILED){
+s8=peg$parseelementFormat();
+if(s8!==peg$FAILED){
+s6=[s6,s7,s8];
+s5=s6;
+}else{
+peg$currPos=s5;
+s5=peg$FAILED;
+}
+}else{
+peg$currPos=s5;
+s5=peg$FAILED;
+}
+}else{
+peg$currPos=s5;
+s5=peg$FAILED;
+}
+if(s5===peg$FAILED){
+s5=null;
+}
+if(s5!==peg$FAILED){
+s6=peg$parse_();
+if(s6!==peg$FAILED){
+if(input.charCodeAt(peg$currPos)===125){
+s7=peg$c9;
+peg$currPos++;
+}else{
+s7=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c10);}
+}
+if(s7!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c11(s3,s5);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parseelementFormat(){
+var s0;
+
+s0=peg$parsesimpleFormat();
+if(s0===peg$FAILED){
+s0=peg$parsepluralFormat();
+if(s0===peg$FAILED){
+s0=peg$parseselectOrdinalFormat();
+if(s0===peg$FAILED){
+s0=peg$parseselectFormat();
+}
+}
+}
+
+return s0;
+}
+
+function peg$parsesimpleFormat(){
+var s0,s1,s2,s3,s4,s5,s6;
+
+s0=peg$currPos;
+if(input.substr(peg$currPos,6)===peg$c12){
+s1=peg$c12;
+peg$currPos+=6;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c13);}
+}
+if(s1===peg$FAILED){
+if(input.substr(peg$currPos,4)===peg$c14){
+s1=peg$c14;
+peg$currPos+=4;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c15);}
+}
+if(s1===peg$FAILED){
+if(input.substr(peg$currPos,4)===peg$c16){
+s1=peg$c16;
+peg$currPos+=4;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c17);}
+}
+}
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+s3=peg$currPos;
+if(input.charCodeAt(peg$currPos)===44){
+s4=peg$c7;
+peg$currPos++;
+}else{
+s4=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c8);}
+}
+if(s4!==peg$FAILED){
+s5=peg$parse_();
+if(s5!==peg$FAILED){
+s6=peg$parsechars();
+if(s6!==peg$FAILED){
+s4=[s4,s5,s6];
+s3=s4;
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+if(s3===peg$FAILED){
+s3=null;
+}
+if(s3!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c18(s1,s3);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parsepluralFormat(){
+var s0,s1,s2,s3,s4,s5;
+
+s0=peg$currPos;
+if(input.substr(peg$currPos,6)===peg$c19){
+s1=peg$c19;
+peg$currPos+=6;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c20);}
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+if(input.charCodeAt(peg$currPos)===44){
+s3=peg$c7;
+peg$currPos++;
+}else{
+s3=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c8);}
+}
+if(s3!==peg$FAILED){
+s4=peg$parse_();
+if(s4!==peg$FAILED){
+s5=peg$parsepluralStyle();
+if(s5!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c21(s5);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parseselectOrdinalFormat(){
+var s0,s1,s2,s3,s4,s5;
+
+s0=peg$currPos;
+if(input.substr(peg$currPos,13)===peg$c22){
+s1=peg$c22;
+peg$currPos+=13;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c23);}
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+if(input.charCodeAt(peg$currPos)===44){
+s3=peg$c7;
+peg$currPos++;
+}else{
+s3=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c8);}
+}
+if(s3!==peg$FAILED){
+s4=peg$parse_();
+if(s4!==peg$FAILED){
+s5=peg$parsepluralStyle();
+if(s5!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c24(s5);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parseselectFormat(){
+var s0,s1,s2,s3,s4,s5,s6;
+
+s0=peg$currPos;
+if(input.substr(peg$currPos,6)===peg$c25){
+s1=peg$c25;
+peg$currPos+=6;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c26);}
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+if(input.charCodeAt(peg$currPos)===44){
+s3=peg$c7;
+peg$currPos++;
+}else{
+s3=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c8);}
+}
+if(s3!==peg$FAILED){
+s4=peg$parse_();
+if(s4!==peg$FAILED){
+s5=[];
+s6=peg$parseoptionalFormatPattern();
+if(s6!==peg$FAILED){
+while(s6!==peg$FAILED){
+s5.push(s6);
+s6=peg$parseoptionalFormatPattern();
+}
+}else{
+s5=peg$FAILED;
+}
+if(s5!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c27(s5);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parseselector(){
+var s0,s1,s2,s3;
+
+s0=peg$currPos;
+s1=peg$currPos;
+if(input.charCodeAt(peg$currPos)===61){
+s2=peg$c28;
+peg$currPos++;
+}else{
+s2=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c29);}
+}
+if(s2!==peg$FAILED){
+s3=peg$parsenumber();
+if(s3!==peg$FAILED){
+s2=[s2,s3];
+s1=s2;
+}else{
+peg$currPos=s1;
+s1=peg$FAILED;
+}
+}else{
+peg$currPos=s1;
+s1=peg$FAILED;
+}
+if(s1!==peg$FAILED){
+s0=input.substring(s0,peg$currPos);
+}else{
+s0=s1;
+}
+if(s0===peg$FAILED){
+s0=peg$parsechars();
+}
+
+return s0;
+}
+
+function peg$parseoptionalFormatPattern(){
+var s0,s1,s2,s3,s4,s5,s6,s7,s8;
+
+s0=peg$currPos;
+s1=peg$parse_();
+if(s1!==peg$FAILED){
+s2=peg$parseselector();
+if(s2!==peg$FAILED){
+s3=peg$parse_();
+if(s3!==peg$FAILED){
+if(input.charCodeAt(peg$currPos)===123){
+s4=peg$c5;
+peg$currPos++;
+}else{
+s4=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c6);}
+}
+if(s4!==peg$FAILED){
+s5=peg$parse_();
+if(s5!==peg$FAILED){
+s6=peg$parsemessageFormatPattern();
+if(s6!==peg$FAILED){
+s7=peg$parse_();
+if(s7!==peg$FAILED){
+if(input.charCodeAt(peg$currPos)===125){
+s8=peg$c9;
+peg$currPos++;
+}else{
+s8=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c10);}
+}
+if(s8!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c30(s2,s6);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parseoffset(){
+var s0,s1,s2,s3;
+
+s0=peg$currPos;
+if(input.substr(peg$currPos,7)===peg$c31){
+s1=peg$c31;
+peg$currPos+=7;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c32);}
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+s3=peg$parsenumber();
+if(s3!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c33(s3);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parsepluralStyle(){
+var s0,s1,s2,s3,s4;
+
+s0=peg$currPos;
+s1=peg$parseoffset();
+if(s1===peg$FAILED){
+s1=null;
+}
+if(s1!==peg$FAILED){
+s2=peg$parse_();
+if(s2!==peg$FAILED){
+s3=[];
+s4=peg$parseoptionalFormatPattern();
+if(s4!==peg$FAILED){
+while(s4!==peg$FAILED){
+s3.push(s4);
+s4=peg$parseoptionalFormatPattern();
+}
+}else{
+s3=peg$FAILED;
+}
+if(s3!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c34(s1,s3);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+
+return s0;
+}
+
+function peg$parsews(){
+var s0,s1;
+
+peg$silentFails++;
+s0=[];
+if(peg$c36.test(input.charAt(peg$currPos))){
+s1=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c37);}
+}
+if(s1!==peg$FAILED){
+while(s1!==peg$FAILED){
+s0.push(s1);
+if(peg$c36.test(input.charAt(peg$currPos))){
+s1=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c37);}
+}
+}
+}else{
+s0=peg$FAILED;
+}
+peg$silentFails--;
+if(s0===peg$FAILED){
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c35);}
+}
+
+return s0;
+}
+
+function peg$parse_(){
+var s0,s1,s2;
+
+peg$silentFails++;
+s0=peg$currPos;
+s1=[];
+s2=peg$parsews();
+while(s2!==peg$FAILED){
+s1.push(s2);
+s2=peg$parsews();
+}
+if(s1!==peg$FAILED){
+s0=input.substring(s0,peg$currPos);
+}else{
+s0=s1;
+}
+peg$silentFails--;
+if(s0===peg$FAILED){
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c38);}
+}
+
+return s0;
+}
+
+function peg$parsedigit(){
+var s0;
+
+if(peg$c39.test(input.charAt(peg$currPos))){
+s0=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s0=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c40);}
+}
+
+return s0;
+}
+
+function peg$parsehexDigit(){
+var s0;
+
+if(peg$c41.test(input.charAt(peg$currPos))){
+s0=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s0=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c42);}
+}
+
+return s0;
+}
+
+function peg$parsenumber(){
+var s0,s1,s2,s3,s4,s5;
+
+s0=peg$currPos;
+if(input.charCodeAt(peg$currPos)===48){
+s1=peg$c43;
+peg$currPos++;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c44);}
+}
+if(s1===peg$FAILED){
+s1=peg$currPos;
+s2=peg$currPos;
+if(peg$c45.test(input.charAt(peg$currPos))){
+s3=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s3=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c46);}
+}
+if(s3!==peg$FAILED){
+s4=[];
+s5=peg$parsedigit();
+while(s5!==peg$FAILED){
+s4.push(s5);
+s5=peg$parsedigit();
+}
+if(s4!==peg$FAILED){
+s3=[s3,s4];
+s2=s3;
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+}else{
+peg$currPos=s2;
+s2=peg$FAILED;
+}
+if(s2!==peg$FAILED){
+s1=input.substring(s1,peg$currPos);
+}else{
+s1=s2;
+}
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c47(s1);
+}
+s0=s1;
+
+return s0;
+}
+
+function peg$parsechar(){
+var s0,s1,s2,s3,s4,s5,s6,s7;
+
+if(peg$c48.test(input.charAt(peg$currPos))){
+s0=input.charAt(peg$currPos);
+peg$currPos++;
+}else{
+s0=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c49);}
+}
+if(s0===peg$FAILED){
+s0=peg$currPos;
+if(input.substr(peg$currPos,2)===peg$c50){
+s1=peg$c50;
+peg$currPos+=2;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c51);}
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c52();
+}
+s0=s1;
+if(s0===peg$FAILED){
+s0=peg$currPos;
+if(input.substr(peg$currPos,2)===peg$c53){
+s1=peg$c53;
+peg$currPos+=2;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c54);}
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c55();
+}
+s0=s1;
+if(s0===peg$FAILED){
+s0=peg$currPos;
+if(input.substr(peg$currPos,2)===peg$c56){
+s1=peg$c56;
+peg$currPos+=2;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c57);}
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c58();
+}
+s0=s1;
+if(s0===peg$FAILED){
+s0=peg$currPos;
+if(input.substr(peg$currPos,2)===peg$c59){
+s1=peg$c59;
+peg$currPos+=2;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c60);}
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c61();
+}
+s0=s1;
+if(s0===peg$FAILED){
+s0=peg$currPos;
+if(input.substr(peg$currPos,2)===peg$c62){
+s1=peg$c62;
+peg$currPos+=2;
+}else{
+s1=peg$FAILED;
+if(peg$silentFails===0){peg$fail(peg$c63);}
+}
+if(s1!==peg$FAILED){
+s2=peg$currPos;
+s3=peg$currPos;
+s4=peg$parsehexDigit();
+if(s4!==peg$FAILED){
+s5=peg$parsehexDigit();
+if(s5!==peg$FAILED){
+s6=peg$parsehexDigit();
+if(s6!==peg$FAILED){
+s7=peg$parsehexDigit();
+if(s7!==peg$FAILED){
+s4=[s4,s5,s6,s7];
+s3=s4;
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+}else{
+peg$currPos=s3;
+s3=peg$FAILED;
+}
+if(s3!==peg$FAILED){
+s2=input.substring(s2,peg$currPos);
+}else{
+s2=s3;
+}
+if(s2!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c64(s2);
+s0=s1;
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}else{
+peg$currPos=s0;
+s0=peg$FAILED;
+}
+}
+}
+}
+}
+}
+
+return s0;
+}
+
+function peg$parsechars(){
+var s0,s1,s2;
+
+s0=peg$currPos;
+s1=[];
+s2=peg$parsechar();
+if(s2!==peg$FAILED){
+while(s2!==peg$FAILED){
+s1.push(s2);
+s2=peg$parsechar();
+}
+}else{
+s1=peg$FAILED;
+}
+if(s1!==peg$FAILED){
+peg$savedPos=s0;
+s1=peg$c65(s1);
+}
+s0=s1;
+
+return s0;
+}
+
+peg$result=peg$startRuleFunction();
+
+if(peg$result!==peg$FAILED&&peg$currPos===input.length){
+return peg$result;
+}else{
+if(peg$result!==peg$FAILED&&peg$currPos<input.length){
+peg$fail({type:"end",description:"end of input"});
+}
+
+throw peg$buildException(
+null,
+peg$maxFailExpected,
+peg$maxFailPos<input.length?input.charAt(peg$maxFailPos):null,
+peg$maxFailPos<input.length?
+peg$computeLocation(peg$maxFailPos,peg$maxFailPos+1):
+peg$computeLocation(peg$maxFailPos,peg$maxFailPos));
+
+}
+}
+
+return{
+SyntaxError:peg$SyntaxError,
+parse:peg$parse};
+
+}();
+
+
+},{}],102:[function(require,module,exports){
+
+
+'use strict';
+
+var IntlMessageFormat=require('./lib/main')['default'];
+
+
+
+require('./lib/locales');
+
+
+
+
+exports=module.exports=IntlMessageFormat;
+exports['default']=exports;
+
+},{"./lib/locales":84,"./lib/main":107}],103:[function(require,module,exports){
+
+
+
+
+
+
+
+
+"use strict";
+exports["default"]=Compiler;
+
+function Compiler(locales,formats,pluralFn){
+this.locales=locales;
+this.formats=formats;
+this.pluralFn=pluralFn;
+}
+
+Compiler.prototype.compile=function(ast){
+this.pluralStack=[];
+this.currentPlural=null;
+this.pluralNumberFormat=null;
+
+return this.compileMessage(ast);
+};
+
+Compiler.prototype.compileMessage=function(ast){
+if(!(ast&&ast.type==='messageFormatPattern')){
+throw new Error('Message AST is not of type: "messageFormatPattern"');
+}
+
+var elements=ast.elements,
+pattern=[];
+
+var i,len,element;
+
+for(i=0,len=elements.length;i<len;i+=1){
+element=elements[i];
+
+switch(element.type){
+case'messageTextElement':
+pattern.push(this.compileMessageText(element));
+break;
+
+case'argumentElement':
+pattern.push(this.compileArgument(element));
+break;
+
+default:
+throw new Error('Message element does not have a valid type');}
+
+}
+
+return pattern;
+};
+
+Compiler.prototype.compileMessageText=function(element){
+
+
+
+if(this.currentPlural&&/(^|[^\\])#/g.test(element.value)){
+
+
+if(!this.pluralNumberFormat){
+this.pluralNumberFormat=new Intl.NumberFormat(this.locales);
+}
+
+return new PluralOffsetString(
+this.currentPlural.id,
+this.currentPlural.format.offset,
+this.pluralNumberFormat,
+element.value);
+}
+
+
+return element.value.replace(/\\#/g,'#');
+};
+
+Compiler.prototype.compileArgument=function(element){
+var format=element.format;
+
+if(!format){
+return new StringFormat(element.id);
+}
+
+var formats=this.formats,
+locales=this.locales,
+pluralFn=this.pluralFn,
+options;
+
+switch(format.type){
+case'numberFormat':
+options=formats.number[format.style];
+return{
+id:element.id,
+format:new Intl.NumberFormat(locales,options).format};
+
+
+case'dateFormat':
+options=formats.date[format.style];
+return{
+id:element.id,
+format:new Intl.DateTimeFormat(locales,options).format};
+
+
+case'timeFormat':
+options=formats.time[format.style];
+return{
+id:element.id,
+format:new Intl.DateTimeFormat(locales,options).format};
+
+
+case'pluralFormat':
+options=this.compileOptions(element);
+return new PluralFormat(
+element.id,format.ordinal,format.offset,options,pluralFn);
+
+
+case'selectFormat':
+options=this.compileOptions(element);
+return new SelectFormat(element.id,options);
+
+default:
+throw new Error('Message element does not have a valid format type');}
+
+};
+
+Compiler.prototype.compileOptions=function(element){
+var format=element.format,
+options=format.options,
+optionsHash={};
+
+
+
+
+this.pluralStack.push(this.currentPlural);
+this.currentPlural=format.type==='pluralFormat'?element:null;
+
+var i,len,option;
+
+for(i=0,len=options.length;i<len;i+=1){
+option=options[i];
+
+
+optionsHash[option.selector]=this.compileMessage(option.value);
+}
+
+
+this.currentPlural=this.pluralStack.pop();
+
+return optionsHash;
+};
+
+
+
+function StringFormat(id){
+this.id=id;
+}
+
+StringFormat.prototype.format=function(value){
+if(!value&&typeof value!=='number'){
+return'';
+}
+
+return typeof value==='string'?value:String(value);
+};
+
+function PluralFormat(id,useOrdinal,offset,options,pluralFn){
+this.id=id;
+this.useOrdinal=useOrdinal;
+this.offset=offset;
+this.options=options;
+this.pluralFn=pluralFn;
+}
+
+PluralFormat.prototype.getOption=function(value){
+var options=this.options;
+
+var option=options['='+value]||
+options[this.pluralFn(value-this.offset,this.useOrdinal)];
+
+return option||options.other;
+};
+
+function PluralOffsetString(id,offset,numberFormat,string){
+this.id=id;
+this.offset=offset;
+this.numberFormat=numberFormat;
+this.string=string;
+}
+
+PluralOffsetString.prototype.format=function(value){
+var number=this.numberFormat.format(value-this.offset);
+
+return this.string.
+replace(/(^|[^\\])#/g,'$1'+number).
+replace(/\\#/g,'#');
+};
+
+function SelectFormat(id,options){
+this.id=id;
+this.options=options;
+}
+
+SelectFormat.prototype.getOption=function(value){
+var options=this.options;
+return options[value]||options.other;
+};
+
+
+},{}],104:[function(require,module,exports){
+
+
+
+
+
+
+
+
+"use strict";
+var src$utils$$=require("./utils"),src$es5$$=require("./es5"),src$compiler$$=require("./compiler"),intl$messageformat$parser$$=require("intl-messageformat-parser");
+exports["default"]=MessageFormat;
+
+
+
+function MessageFormat(message,locales,formats){
+
+var ast=typeof message==='string'?
+MessageFormat.__parse(message):message;
+
+if(!(ast&&ast.type==='messageFormatPattern')){
+throw new TypeError('A message must be provided as a String or AST.');
+}
+
+
+
+formats=this._mergeFormats(MessageFormat.formats,formats);
+
+
+src$es5$$.defineProperty(this,'_locale',{value:this._resolveLocale(locales)});
+
+
+
+
+var pluralFn=this._findPluralRuleFunction(this._locale);
+var pattern=this._compilePattern(ast,locales,formats,pluralFn);
+
+
+
+var messageFormat=this;
+this.format=function(values){
+try{
+return messageFormat._format(pattern,values);
+}catch(e){
+if(e.variableId){
+throw new Error(
+'The intl string context variable \''+e.variableId+'\''+
+' was not provided to the string \''+message+'\'');
+
+}else{
+throw e;
+}
+}
+};
+}
+
+
+
+
+src$es5$$.defineProperty(MessageFormat,'formats',{
+enumerable:true,
+
+value:{
+number:{
+'currency':{
+style:'currency'},
+
+
+'percent':{
+style:'percent'}},
+
+
+
+date:{
+'short':{
+month:'numeric',
+day:'numeric',
+year:'2-digit'},
+
+
+'medium':{
+month:'short',
+day:'numeric',
+year:'numeric'},
+
+
+'long':{
+month:'long',
+day:'numeric',
+year:'numeric'},
+
+
+'full':{
+weekday:'long',
+month:'long',
+day:'numeric',
+year:'numeric'}},
+
+
+
+time:{
+'short':{
+hour:'numeric',
+minute:'numeric'},
+
+
+'medium':{
+hour:'numeric',
+minute:'numeric',
+second:'numeric'},
+
+
+'long':{
+hour:'numeric',
+minute:'numeric',
+second:'numeric',
+timeZoneName:'short'},
+
+
+'full':{
+hour:'numeric',
+minute:'numeric',
+second:'numeric',
+timeZoneName:'short'}}}});
+
+
+
+
+
+
+src$es5$$.defineProperty(MessageFormat,'__localeData__',{value:src$es5$$.objCreate(null)});
+src$es5$$.defineProperty(MessageFormat,'__addLocaleData',{value:function(data){
+if(!(data&&data.locale)){
+throw new Error(
+'Locale data provided to IntlMessageFormat is missing a '+
+'`locale` property');
+
+}
+
+MessageFormat.__localeData__[data.locale.toLowerCase()]=data;
+}});
+
+
+src$es5$$.defineProperty(MessageFormat,'__parse',{value:intl$messageformat$parser$$["default"].parse});
+
+
+
+src$es5$$.defineProperty(MessageFormat,'defaultLocale',{
+enumerable:true,
+writable:true,
+value:undefined});
+
+
+MessageFormat.prototype.resolvedOptions=function(){
+
+return{
+locale:this._locale};
+
+};
+
+MessageFormat.prototype._compilePattern=function(ast,locales,formats,pluralFn){
+var compiler=new src$compiler$$["default"](locales,formats,pluralFn);
+return compiler.compile(ast);
+};
+
+MessageFormat.prototype._findPluralRuleFunction=function(locale){
+var localeData=MessageFormat.__localeData__;
+var data=localeData[locale.toLowerCase()];
+
+
+
+while(data){
+if(data.pluralRuleFunction){
+return data.pluralRuleFunction;
+}
+
+data=data.parentLocale&&localeData[data.parentLocale.toLowerCase()];
+}
+
+throw new Error(
+'Locale data added to IntlMessageFormat is missing a '+
+'`pluralRuleFunction` for :'+locale);
+
+};
+
+MessageFormat.prototype._format=function(pattern,values){
+var result='',
+i,len,part,id,value,err;
+
+for(i=0,len=pattern.length;i<len;i+=1){
+part=pattern[i];
+
+
+if(typeof part==='string'){
+result+=part;
+continue;
+}
+
+id=part.id;
+
+
+if(!(values&&src$utils$$.hop.call(values,id))){
+err=new Error('A value must be provided for: '+id);
+err.variableId=id;
+throw err;
+}
+
+value=values[id];
+
+
+
+
+if(part.options){
+result+=this._format(part.getOption(value),values);
+}else{
+result+=part.format(value);
+}
+}
+
+return result;
+};
+
+MessageFormat.prototype._mergeFormats=function(defaults,formats){
+var mergedFormats={},
+type,mergedType;
+
+for(type in defaults){
+if(!src$utils$$.hop.call(defaults,type)){continue;}
+
+mergedFormats[type]=mergedType=src$es5$$.objCreate(defaults[type]);
+
+if(formats&&src$utils$$.hop.call(formats,type)){
+src$utils$$.extend(mergedType,formats[type]);
+}
+}
+
+return mergedFormats;
+};
+
+MessageFormat.prototype._resolveLocale=function(locales){
+if(typeof locales==='string'){
+locales=[locales];
+}
+
+
+locales=(locales||[]).concat(MessageFormat.defaultLocale);
+
+var localeData=MessageFormat.__localeData__;
+var i,len,localeParts,data;
+
+
+
+
+
+
+for(i=0,len=locales.length;i<len;i+=1){
+localeParts=locales[i].toLowerCase().split('-');
+
+while(localeParts.length){
+data=localeData[localeParts.join('-')];
+if(data){
+
+
+return data.locale;
+}
+
+localeParts.pop();
+}
+}
+
+var defaultLocale=locales.pop();
+throw new Error(
+'No locale data has been added to IntlMessageFormat for: '+
+locales.join(', ')+', or the default locale: '+defaultLocale);
+
+};
+
+
+},{"./compiler":103,"./es5":106,"./utils":108,"intl-messageformat-parser":100}],105:[function(require,module,exports){
+
+"use strict";
+exports["default"]={"locale":"en","pluralRuleFunction":function(n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return n10==1&&n100!=11?"one":n10==2&&n100!=12?"two":n10==3&&n100!=13?"few":"other";return n==1&&v0?"one":"other";}};
+
+
+},{}],106:[function(require,module,exports){
+
+
+
+
+
+
+
+
+"use strict";
+var src$utils$$=require("./utils");
+
+
+
+
+var realDefineProp=function(){
+try{return!!Object.defineProperty({},'a',{});}
+catch(e){return false;}
+}();
+
+var es3=!realDefineProp&&!Object.prototype.__defineGetter__;
+
+var defineProperty=realDefineProp?Object.defineProperty:
+function(obj,name,desc){
+
+if('get'in desc&&obj.__defineGetter__){
+obj.__defineGetter__(name,desc.get);
+}else if(!src$utils$$.hop.call(obj,name)||'value'in desc){
+obj[name]=desc.value;
+}
+};
+
+var objCreate=Object.create||function(proto,props){
+var obj,k;
+
+function F(){}
+F.prototype=proto;
+obj=new F();
+
+for(k in props){
+if(src$utils$$.hop.call(props,k)){
+defineProperty(obj,k,props[k]);
+}
+}
+
+return obj;
+};
+
+exports.defineProperty=defineProperty,exports.objCreate=objCreate;
+
+
+},{"./utils":108}],107:[function(require,module,exports){
+
+
+"use strict";
+var src$core$$=require("./core"),src$en$$=require("./en");
+
+src$core$$["default"].__addLocaleData(src$en$$["default"]);
+src$core$$["default"].defaultLocale='en';
+
+exports["default"]=src$core$$["default"];
+
+
+},{"./core":104,"./en":105}],108:[function(require,module,exports){
+
+
+
+
+
+
+
+
+"use strict";
+exports.extend=extend;
+var hop=Object.prototype.hasOwnProperty;
+
+function extend(obj){
+var sources=Array.prototype.slice.call(arguments,1),
+i,len,source,key;
+
+for(i=0,len=sources.length;i<len;i+=1){
+source=sources[i];
+if(!source){continue;}
+
+for(key in source){
+if(hop.call(source,key)){
+obj[key]=source[key];
+}
+}
+}
+
+return obj;
+}
+exports.hop=hop;
+
+
+},{}],109:[function(require,module,exports){
+var toString={}.toString;
+
+module.exports=Array.isArray||function(arr){
+return toString.call(arr)=='[object Array]';
+};
+
+},{}],110:[function(require,module,exports){
+var encode=require('./lib/encoder'),
+decode=require('./lib/decoder');
+
+module.exports={
+encode:encode,
+decode:decode};
+
+
+},{"./lib/decoder":111,"./lib/encoder":112}],111:[function(require,module,exports){
+(function(Buffer){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var JpegImage=function jpegImage(){
+"use strict";
+var dctZigZag=new Int32Array([
+0,
+1,8,
+16,9,2,
+3,10,17,24,
+32,25,18,11,4,
+5,12,19,26,33,40,
+48,41,34,27,20,13,6,
+7,14,21,28,35,42,49,56,
+57,50,43,36,29,22,15,
+23,30,37,44,51,58,
+59,52,45,38,31,
+39,46,53,60,
+61,54,47,
+55,62,
+63]);
+
+
+var dctCos1=4017;
+var dctSin1=799;
+var dctCos3=3406;
+var dctSin3=2276;
+var dctCos6=1567;
+var dctSin6=3784;
+var dctSqrt2=5793;
+var dctSqrt1d2=2896;
+
+function constructor(){
+}
+
+function buildHuffmanTable(codeLengths,values){
+var k=0,code=[],i,j,length=16;
+while(length>0&&!codeLengths[length-1])
+length--;
+code.push({children:[],index:0});
+var p=code[0],q;
+for(i=0;i<length;i++){
+for(j=0;j<codeLengths[i];j++){
+p=code.pop();
+p.children[p.index]=values[k];
+while(p.index>0){
+p=code.pop();
+}
+p.index++;
+code.push(p);
+while(code.length<=i){
+code.push(q={children:[],index:0});
+p.children[p.index]=q.children;
+p=q;
+}
+k++;
+}
+if(i+1<length){
+
+code.push(q={children:[],index:0});
+p.children[p.index]=q.children;
+p=q;
+}
+}
+return code[0].children;
+}
+
+function decodeScan(data,offset,
+frame,components,resetInterval,
+spectralStart,spectralEnd,
+successivePrev,successive){
+var precision=frame.precision;
+var samplesPerLine=frame.samplesPerLine;
+var scanLines=frame.scanLines;
+var mcusPerLine=frame.mcusPerLine;
+var progressive=frame.progressive;
+var maxH=frame.maxH,maxV=frame.maxV;
+
+var startOffset=offset,bitsData=0,bitsCount=0;
+function readBit(){
+if(bitsCount>0){
+bitsCount--;
+return bitsData>>bitsCount&1;
+}
+bitsData=data[offset++];
+if(bitsData==0xFF){
+var nextByte=data[offset++];
+if(nextByte){
+throw"unexpected marker: "+(bitsData<<8|nextByte).toString(16);
+}
+
+}
+bitsCount=7;
+return bitsData>>>7;
+}
+function decodeHuffman(tree){
+var node=tree,bit;
+while((bit=readBit())!==null){
+node=node[bit];
+if(typeof node==='number')
+return node;
+if(typeof node!=='object')
+throw"invalid huffman sequence";
+}
+return null;
+}
+function receive(length){
+var n=0;
+while(length>0){
+var bit=readBit();
+if(bit===null)return;
+n=n<<1|bit;
+length--;
+}
+return n;
+}
+function receiveAndExtend(length){
+var n=receive(length);
+if(n>=1<<length-1)
+return n;
+return n+(-1<<length)+1;
+}
+function decodeBaseline(component,zz){
+var t=decodeHuffman(component.huffmanTableDC);
+var diff=t===0?0:receiveAndExtend(t);
+zz[0]=component.pred+=diff;
+var k=1;
+while(k<64){
+var rs=decodeHuffman(component.huffmanTableAC);
+var s=rs&15,r=rs>>4;
+if(s===0){
+if(r<15)
+break;
+k+=16;
+continue;
+}
+k+=r;
+var z=dctZigZag[k];
+zz[z]=receiveAndExtend(s);
+k++;
+}
+}
+function decodeDCFirst(component,zz){
+var t=decodeHuffman(component.huffmanTableDC);
+var diff=t===0?0:receiveAndExtend(t)<<successive;
+zz[0]=component.pred+=diff;
+}
+function decodeDCSuccessive(component,zz){
+zz[0]|=readBit()<<successive;
+}
+var eobrun=0;
+function decodeACFirst(component,zz){
+if(eobrun>0){
+eobrun--;
+return;
+}
+var k=spectralStart,e=spectralEnd;
+while(k<=e){
+var rs=decodeHuffman(component.huffmanTableAC);
+var s=rs&15,r=rs>>4;
+if(s===0){
+if(r<15){
+eobrun=receive(r)+(1<<r)-1;
+break;
+}
+k+=16;
+continue;
+}
+k+=r;
+var z=dctZigZag[k];
+zz[z]=receiveAndExtend(s)*(1<<successive);
+k++;
+}
+}
+var successiveACState=0,successiveACNextValue;
+function decodeACSuccessive(component,zz){
+var k=spectralStart,e=spectralEnd,r=0;
+while(k<=e){
+var z=dctZigZag[k];
+switch(successiveACState){
+case 0:
+var rs=decodeHuffman(component.huffmanTableAC);
+var s=rs&15,r=rs>>4;
+if(s===0){
+if(r<15){
+eobrun=receive(r)+(1<<r);
+successiveACState=4;
+}else{
+r=16;
+successiveACState=1;
+}
+}else{
+if(s!==1)
+throw"invalid ACn encoding";
+successiveACNextValue=receiveAndExtend(s);
+successiveACState=r?2:3;
+}
+continue;
+case 1:
+case 2:
+if(zz[z])
+zz[z]+=readBit()<<successive;else
+{
+r--;
+if(r===0)
+successiveACState=successiveACState==2?3:0;
+}
+break;
+case 3:
+if(zz[z])
+zz[z]+=readBit()<<successive;else
+{
+zz[z]=successiveACNextValue<<successive;
+successiveACState=0;
+}
+break;
+case 4:
+if(zz[z])
+zz[z]+=readBit()<<successive;
+break;}
+
+k++;
+}
+if(successiveACState===4){
+eobrun--;
+if(eobrun===0)
+successiveACState=0;
+}
+}
+function decodeMcu(component,decode,mcu,row,col){
+var mcuRow=mcu/mcusPerLine|0;
+var mcuCol=mcu%mcusPerLine;
+var blockRow=mcuRow*component.v+row;
+var blockCol=mcuCol*component.h+col;
+decode(component,component.blocks[blockRow][blockCol]);
+}
+function decodeBlock(component,decode,mcu){
+var blockRow=mcu/component.blocksPerLine|0;
+var blockCol=mcu%component.blocksPerLine;
+decode(component,component.blocks[blockRow][blockCol]);
+}
+
+var componentsLength=components.length;
+var component,i,j,k,n;
+var decodeFn;
+if(progressive){
+if(spectralStart===0)
+decodeFn=successivePrev===0?decodeDCFirst:decodeDCSuccessive;else
+
+decodeFn=successivePrev===0?decodeACFirst:decodeACSuccessive;
+}else{
+decodeFn=decodeBaseline;
+}
+
+var mcu=0,marker;
+var mcuExpected;
+if(componentsLength==1){
+mcuExpected=components[0].blocksPerLine*components[0].blocksPerColumn;
+}else{
+mcuExpected=mcusPerLine*frame.mcusPerColumn;
+}
+if(!resetInterval)resetInterval=mcuExpected;
+
+var h,v;
+while(mcu<mcuExpected){
+
+for(i=0;i<componentsLength;i++)
+components[i].pred=0;
+eobrun=0;
+
+if(componentsLength==1){
+component=components[0];
+for(n=0;n<resetInterval;n++){
+decodeBlock(component,decodeFn,mcu);
+mcu++;
+}
+}else{
+for(n=0;n<resetInterval;n++){
+for(i=0;i<componentsLength;i++){
+component=components[i];
+h=component.h;
+v=component.v;
+for(j=0;j<v;j++){
+for(k=0;k<h;k++){
+decodeMcu(component,decodeFn,mcu,j,k);
+}
+}
+}
+mcu++;
+
+
+if(mcu===mcuExpected)break;
+}
+}
+
+
+bitsCount=0;
+marker=data[offset]<<8|data[offset+1];
+if(marker<0xFF00){
+throw"marker was not found";
+}
+
+if(marker>=0xFFD0&&marker<=0xFFD7){
+offset+=2;
+}else
+
+break;
+}
+
+return offset-startOffset;
+}
+
+function buildComponentData(frame,component){
+var lines=[];
+var blocksPerLine=component.blocksPerLine;
+var blocksPerColumn=component.blocksPerColumn;
+var samplesPerLine=blocksPerLine<<3;
+var R=new Int32Array(64),r=new Uint8Array(64);
+
+
+
+
+
+
+function quantizeAndInverse(zz,dataOut,dataIn){
+var qt=component.quantizationTable;
+var v0,v1,v2,v3,v4,v5,v6,v7,t;
+var p=dataIn;
+var i;
+
+
+for(i=0;i<64;i++)
+p[i]=zz[i]*qt[i];
+
+
+for(i=0;i<8;++i){
+var row=8*i;
+
+
+if(p[1+row]==0&&p[2+row]==0&&p[3+row]==0&&
+p[4+row]==0&&p[5+row]==0&&p[6+row]==0&&
+p[7+row]==0){
+t=dctSqrt2*p[0+row]+512>>10;
+p[0+row]=t;
+p[1+row]=t;
+p[2+row]=t;
+p[3+row]=t;
+p[4+row]=t;
+p[5+row]=t;
+p[6+row]=t;
+p[7+row]=t;
+continue;
+}
+
+
+v0=dctSqrt2*p[0+row]+128>>8;
+v1=dctSqrt2*p[4+row]+128>>8;
+v2=p[2+row];
+v3=p[6+row];
+v4=dctSqrt1d2*(p[1+row]-p[7+row])+128>>8;
+v7=dctSqrt1d2*(p[1+row]+p[7+row])+128>>8;
+v5=p[3+row]<<4;
+v6=p[5+row]<<4;
+
+
+t=v0-v1+1>>1;
+v0=v0+v1+1>>1;
+v1=t;
+t=v2*dctSin6+v3*dctCos6+128>>8;
+v2=v2*dctCos6-v3*dctSin6+128>>8;
+v3=t;
+t=v4-v6+1>>1;
+v4=v4+v6+1>>1;
+v6=t;
+t=v7+v5+1>>1;
+v5=v7-v5+1>>1;
+v7=t;
+
+
+t=v0-v3+1>>1;
+v0=v0+v3+1>>1;
+v3=t;
+t=v1-v2+1>>1;
+v1=v1+v2+1>>1;
+v2=t;
+t=v4*dctSin3+v7*dctCos3+2048>>12;
+v4=v4*dctCos3-v7*dctSin3+2048>>12;
+v7=t;
+t=v5*dctSin1+v6*dctCos1+2048>>12;
+v5=v5*dctCos1-v6*dctSin1+2048>>12;
+v6=t;
+
+
+p[0+row]=v0+v7;
+p[7+row]=v0-v7;
+p[1+row]=v1+v6;
+p[6+row]=v1-v6;
+p[2+row]=v2+v5;
+p[5+row]=v2-v5;
+p[3+row]=v3+v4;
+p[4+row]=v3-v4;
+}
+
+
+for(i=0;i<8;++i){
+var col=i;
+
+
+if(p[1*8+col]==0&&p[2*8+col]==0&&p[3*8+col]==0&&
+p[4*8+col]==0&&p[5*8+col]==0&&p[6*8+col]==0&&
+p[7*8+col]==0){
+t=dctSqrt2*dataIn[i+0]+8192>>14;
+p[0*8+col]=t;
+p[1*8+col]=t;
+p[2*8+col]=t;
+p[3*8+col]=t;
+p[4*8+col]=t;
+p[5*8+col]=t;
+p[6*8+col]=t;
+p[7*8+col]=t;
+continue;
+}
+
+
+v0=dctSqrt2*p[0*8+col]+2048>>12;
+v1=dctSqrt2*p[4*8+col]+2048>>12;
+v2=p[2*8+col];
+v3=p[6*8+col];
+v4=dctSqrt1d2*(p[1*8+col]-p[7*8+col])+2048>>12;
+v7=dctSqrt1d2*(p[1*8+col]+p[7*8+col])+2048>>12;
+v5=p[3*8+col];
+v6=p[5*8+col];
+
+
+t=v0-v1+1>>1;
+v0=v0+v1+1>>1;
+v1=t;
+t=v2*dctSin6+v3*dctCos6+2048>>12;
+v2=v2*dctCos6-v3*dctSin6+2048>>12;
+v3=t;
+t=v4-v6+1>>1;
+v4=v4+v6+1>>1;
+v6=t;
+t=v7+v5+1>>1;
+v5=v7-v5+1>>1;
+v7=t;
+
+
+t=v0-v3+1>>1;
+v0=v0+v3+1>>1;
+v3=t;
+t=v1-v2+1>>1;
+v1=v1+v2+1>>1;
+v2=t;
+t=v4*dctSin3+v7*dctCos3+2048>>12;
+v4=v4*dctCos3-v7*dctSin3+2048>>12;
+v7=t;
+t=v5*dctSin1+v6*dctCos1+2048>>12;
+v5=v5*dctCos1-v6*dctSin1+2048>>12;
+v6=t;
+
+
+p[0*8+col]=v0+v7;
+p[7*8+col]=v0-v7;
+p[1*8+col]=v1+v6;
+p[6*8+col]=v1-v6;
+p[2*8+col]=v2+v5;
+p[5*8+col]=v2-v5;
+p[3*8+col]=v3+v4;
+p[4*8+col]=v3-v4;
+}
+
+
+for(i=0;i<64;++i){
+var sample=128+(p[i]+8>>4);
+dataOut[i]=sample<0?0:sample>0xFF?0xFF:sample;
+}
+}
+
+var i,j;
+for(var blockRow=0;blockRow<blocksPerColumn;blockRow++){
+var scanLine=blockRow<<3;
+for(i=0;i<8;i++)
+lines.push(new Uint8Array(samplesPerLine));
+for(var blockCol=0;blockCol<blocksPerLine;blockCol++){
+quantizeAndInverse(component.blocks[blockRow][blockCol],r,R);
+
+var offset=0,sample=blockCol<<3;
+for(j=0;j<8;j++){
+var line=lines[scanLine+j];
+for(i=0;i<8;i++)
+line[sample+i]=r[offset++];
+}
+}
+}
+return lines;
+}
+
+function clampTo8bit(a){
+return a<0?0:a>255?255:a;
+}
+
+constructor.prototype={
+load:function load(path){
+var xhr=new XMLHttpRequest();
+xhr.open("GET",path,true);
+xhr.responseType="arraybuffer";
+xhr.onload=function(){
+
+var data=new Uint8Array(xhr.response||xhr.mozResponseArrayBuffer);
+this.parse(data);
+if(this.onload)
+this.onload();
+}.bind(this);
+xhr.send(null);
+},
+parse:function parse(data){
+var offset=0,length=data.length;
+function readUint16(){
+var value=data[offset]<<8|data[offset+1];
+offset+=2;
+return value;
+}
+function readDataBlock(){
+var length=readUint16();
+var array=data.subarray(offset,offset+length-2);
+offset+=array.length;
+return array;
+}
+function prepareComponents(frame){
+var maxH=0,maxV=0;
+var component,componentId;
+for(componentId in frame.components){
+if(frame.components.hasOwnProperty(componentId)){
+component=frame.components[componentId];
+if(maxH<component.h)maxH=component.h;
+if(maxV<component.v)maxV=component.v;
+}
+}
+var mcusPerLine=Math.ceil(frame.samplesPerLine/8/maxH);
+var mcusPerColumn=Math.ceil(frame.scanLines/8/maxV);
+for(componentId in frame.components){
+if(frame.components.hasOwnProperty(componentId)){
+component=frame.components[componentId];
+var blocksPerLine=Math.ceil(Math.ceil(frame.samplesPerLine/8)*component.h/maxH);
+var blocksPerColumn=Math.ceil(Math.ceil(frame.scanLines/8)*component.v/maxV);
+var blocksPerLineForMcu=mcusPerLine*component.h;
+var blocksPerColumnForMcu=mcusPerColumn*component.v;
+var blocks=[];
+for(var i=0;i<blocksPerColumnForMcu;i++){
+var row=[];
+for(var j=0;j<blocksPerLineForMcu;j++)
+row.push(new Int32Array(64));
+blocks.push(row);
+}
+component.blocksPerLine=blocksPerLine;
+component.blocksPerColumn=blocksPerColumn;
+component.blocks=blocks;
+}
+}
+frame.maxH=maxH;
+frame.maxV=maxV;
+frame.mcusPerLine=mcusPerLine;
+frame.mcusPerColumn=mcusPerColumn;
+}
+var jfif=null;
+var adobe=null;
+var pixels=null;
+var frame,resetInterval;
+var quantizationTables=[],frames=[];
+var huffmanTablesAC=[],huffmanTablesDC=[];
+var fileMarker=readUint16();
+if(fileMarker!=0xFFD8){
+throw"SOI not found";
+}
+
+fileMarker=readUint16();
+while(fileMarker!=0xFFD9){
+var i,j,l;
+switch(fileMarker){
+case 0xFF00:break;
+case 0xFFE0:
+case 0xFFE1:
+case 0xFFE2:
+case 0xFFE3:
+case 0xFFE4:
+case 0xFFE5:
+case 0xFFE6:
+case 0xFFE7:
+case 0xFFE8:
+case 0xFFE9:
+case 0xFFEA:
+case 0xFFEB:
+case 0xFFEC:
+case 0xFFED:
+case 0xFFEE:
+case 0xFFEF:
+case 0xFFFE:
+var appData=readDataBlock();
+
+if(fileMarker===0xFFE0){
+if(appData[0]===0x4A&&appData[1]===0x46&&appData[2]===0x49&&
+appData[3]===0x46&&appData[4]===0){
+jfif={
+version:{major:appData[5],minor:appData[6]},
+densityUnits:appData[7],
+xDensity:appData[8]<<8|appData[9],
+yDensity:appData[10]<<8|appData[11],
+thumbWidth:appData[12],
+thumbHeight:appData[13],
+thumbData:appData.subarray(14,14+3*appData[12]*appData[13])};
+
+}
+}
+
+if(fileMarker===0xFFEE){
+if(appData[0]===0x41&&appData[1]===0x64&&appData[2]===0x6F&&
+appData[3]===0x62&&appData[4]===0x65&&appData[5]===0){
+adobe={
+version:appData[6],
+flags0:appData[7]<<8|appData[8],
+flags1:appData[9]<<8|appData[10],
+transformCode:appData[11]};
+
+}
+}
+break;
+
+case 0xFFDB:
+var quantizationTablesLength=readUint16();
+var quantizationTablesEnd=quantizationTablesLength+offset-2;
+while(offset<quantizationTablesEnd){
+var quantizationTableSpec=data[offset++];
+var tableData=new Int32Array(64);
+if(quantizationTableSpec>>4===0){
+for(j=0;j<64;j++){
+var z=dctZigZag[j];
+tableData[z]=data[offset++];
+}
+}else if(quantizationTableSpec>>4===1){
+for(j=0;j<64;j++){
+var z=dctZigZag[j];
+tableData[z]=readUint16();
+}
+}else
+throw"DQT: invalid table spec";
+quantizationTables[quantizationTableSpec&15]=tableData;
+}
+break;
+
+case 0xFFC0:
+case 0xFFC1:
+case 0xFFC2:
+readUint16();
+frame={};
+frame.extended=fileMarker===0xFFC1;
+frame.progressive=fileMarker===0xFFC2;
+frame.precision=data[offset++];
+frame.scanLines=readUint16();
+frame.samplesPerLine=readUint16();
+frame.components={};
+frame.componentsOrder=[];
+var componentsCount=data[offset++],componentId;
+var maxH=0,maxV=0;
+for(i=0;i<componentsCount;i++){
+componentId=data[offset];
+var h=data[offset+1]>>4;
+var v=data[offset+1]&15;
+var qId=data[offset+2];
+frame.componentsOrder.push(componentId);
+frame.components[componentId]={
+h:h,
+v:v,
+quantizationIdx:qId};
+
+offset+=3;
+}
+prepareComponents(frame);
+frames.push(frame);
+break;
+
+case 0xFFC4:
+var huffmanLength=readUint16();
+for(i=2;i<huffmanLength;){
+var huffmanTableSpec=data[offset++];
+var codeLengths=new Uint8Array(16);
+var codeLengthSum=0;
+for(j=0;j<16;j++,offset++)
+codeLengthSum+=codeLengths[j]=data[offset];
+var huffmanValues=new Uint8Array(codeLengthSum);
+for(j=0;j<codeLengthSum;j++,offset++)
+huffmanValues[j]=data[offset];
+i+=17+codeLengthSum;
+
+(huffmanTableSpec>>4===0?
+huffmanTablesDC:huffmanTablesAC)[huffmanTableSpec&15]=
+buildHuffmanTable(codeLengths,huffmanValues);
+}
+break;
+
+case 0xFFDD:
+readUint16();
+resetInterval=readUint16();
+break;
+
+case 0xFFDA:
+var scanLength=readUint16();
+var selectorsCount=data[offset++];
+var components=[],component;
+for(i=0;i<selectorsCount;i++){
+component=frame.components[data[offset++]];
+var tableSpec=data[offset++];
+component.huffmanTableDC=huffmanTablesDC[tableSpec>>4];
+component.huffmanTableAC=huffmanTablesAC[tableSpec&15];
+components.push(component);
+}
+var spectralStart=data[offset++];
+var spectralEnd=data[offset++];
+var successiveApproximation=data[offset++];
+var processed=decodeScan(data,offset,
+frame,components,resetInterval,
+spectralStart,spectralEnd,
+successiveApproximation>>4,successiveApproximation&15);
+offset+=processed;
+break;
+default:
+if(data[offset-3]==0xFF&&
+data[offset-2]>=0xC0&&data[offset-2]<=0xFE){
+
+
+offset-=3;
+break;
+}
+throw"unknown JPEG marker "+fileMarker.toString(16);}
+
+fileMarker=readUint16();
+}
+if(frames.length!=1)
+throw"only single frame JPEGs supported";
+
+
+for(var i=0;i<frames.length;i++){
+var cp=frames[i].components;
+for(var j in cp){
+cp[j].quantizationTable=quantizationTables[cp[j].quantizationIdx];
+delete cp[j].quantizationIdx;
+}
+}
+
+this.width=frame.samplesPerLine;
+this.height=frame.scanLines;
+this.jfif=jfif;
+this.adobe=adobe;
+this.components=[];
+for(var i=0;i<frame.componentsOrder.length;i++){
+var component=frame.components[frame.componentsOrder[i]];
+this.components.push({
+lines:buildComponentData(frame,component),
+scaleX:component.h/frame.maxH,
+scaleY:component.v/frame.maxV});
+
+}
+},
+getData:function getData(width,height){
+var scaleX=this.width/width,scaleY=this.height/height;
+
+var component1,component2,component3,component4;
+var component1Line,component2Line,component3Line,component4Line;
+var x,y;
+var offset=0;
+var Y,Cb,Cr,K,C,M,Ye,R,G,B;
+var colorTransform;
+var dataLength=width*height*this.components.length;
+var data=new Uint8Array(dataLength);
+switch(this.components.length){
+case 1:
+component1=this.components[0];
+for(y=0;y<height;y++){
+component1Line=component1.lines[0|y*component1.scaleY*scaleY];
+for(x=0;x<width;x++){
+Y=component1Line[0|x*component1.scaleX*scaleX];
+
+data[offset++]=Y;
+}
+}
+break;
+case 2:
+
+component1=this.components[0];
+component2=this.components[1];
+for(y=0;y<height;y++){
+component1Line=component1.lines[0|y*component1.scaleY*scaleY];
+component2Line=component2.lines[0|y*component2.scaleY*scaleY];
+for(x=0;x<width;x++){
+Y=component1Line[0|x*component1.scaleX*scaleX];
+data[offset++]=Y;
+Y=component2Line[0|x*component2.scaleX*scaleX];
+data[offset++]=Y;
+}
+}
+break;
+case 3:
+
+colorTransform=true;
+
+if(this.adobe&&this.adobe.transformCode)
+colorTransform=true;else
+if(typeof this.colorTransform!=='undefined')
+colorTransform=!!this.colorTransform;
+
+component1=this.components[0];
+component2=this.components[1];
+component3=this.components[2];
+for(y=0;y<height;y++){
+component1Line=component1.lines[0|y*component1.scaleY*scaleY];
+component2Line=component2.lines[0|y*component2.scaleY*scaleY];
+component3Line=component3.lines[0|y*component3.scaleY*scaleY];
+for(x=0;x<width;x++){
+if(!colorTransform){
+R=component1Line[0|x*component1.scaleX*scaleX];
+G=component2Line[0|x*component2.scaleX*scaleX];
+B=component3Line[0|x*component3.scaleX*scaleX];
+}else{
+Y=component1Line[0|x*component1.scaleX*scaleX];
+Cb=component2Line[0|x*component2.scaleX*scaleX];
+Cr=component3Line[0|x*component3.scaleX*scaleX];
+
+R=clampTo8bit(Y+1.402*(Cr-128));
+G=clampTo8bit(Y-0.3441363*(Cb-128)-0.71413636*(Cr-128));
+B=clampTo8bit(Y+1.772*(Cb-128));
+}
+
+data[offset++]=R;
+data[offset++]=G;
+data[offset++]=B;
+}
+}
+break;
+case 4:
+if(!this.adobe)
+throw'Unsupported color mode (4 components)';
+
+colorTransform=false;
+
+if(this.adobe&&this.adobe.transformCode)
+colorTransform=true;else
+if(typeof this.colorTransform!=='undefined')
+colorTransform=!!this.colorTransform;
+
+component1=this.components[0];
+component2=this.components[1];
+component3=this.components[2];
+component4=this.components[3];
+for(y=0;y<height;y++){
+component1Line=component1.lines[0|y*component1.scaleY*scaleY];
+component2Line=component2.lines[0|y*component2.scaleY*scaleY];
+component3Line=component3.lines[0|y*component3.scaleY*scaleY];
+component4Line=component4.lines[0|y*component4.scaleY*scaleY];
+for(x=0;x<width;x++){
+if(!colorTransform){
+C=component1Line[0|x*component1.scaleX*scaleX];
+M=component2Line[0|x*component2.scaleX*scaleX];
+Ye=component3Line[0|x*component3.scaleX*scaleX];
+K=component4Line[0|x*component4.scaleX*scaleX];
+}else{
+Y=component1Line[0|x*component1.scaleX*scaleX];
+Cb=component2Line[0|x*component2.scaleX*scaleX];
+Cr=component3Line[0|x*component3.scaleX*scaleX];
+K=component4Line[0|x*component4.scaleX*scaleX];
+
+C=255-clampTo8bit(Y+1.402*(Cr-128));
+M=255-clampTo8bit(Y-0.3441363*(Cb-128)-0.71413636*(Cr-128));
+Ye=255-clampTo8bit(Y+1.772*(Cb-128));
+}
+data[offset++]=255-C;
+data[offset++]=255-M;
+data[offset++]=255-Ye;
+data[offset++]=255-K;
+}
+}
+break;
+default:
+throw'Unsupported color mode';}
+
+return data;
+},
+copyToImageData:function copyToImageData(imageData){
+var width=imageData.width,height=imageData.height;
+var imageDataArray=imageData.data;
+var data=this.getData(width,height);
+var i=0,j=0,x,y;
+var Y,K,C,M,R,G,B;
+switch(this.components.length){
+case 1:
+for(y=0;y<height;y++){
+for(x=0;x<width;x++){
+Y=data[i++];
+
+imageDataArray[j++]=Y;
+imageDataArray[j++]=Y;
+imageDataArray[j++]=Y;
+imageDataArray[j++]=255;
+}
+}
+break;
+case 3:
+for(y=0;y<height;y++){
+for(x=0;x<width;x++){
+R=data[i++];
+G=data[i++];
+B=data[i++];
+
+imageDataArray[j++]=R;
+imageDataArray[j++]=G;
+imageDataArray[j++]=B;
+imageDataArray[j++]=255;
+}
+}
+break;
+case 4:
+for(y=0;y<height;y++){
+for(x=0;x<width;x++){
+C=data[i++];
+M=data[i++];
+Y=data[i++];
+K=data[i++];
+
+R=255-clampTo8bit(C*(1-K/255)+K);
+G=255-clampTo8bit(M*(1-K/255)+K);
+B=255-clampTo8bit(Y*(1-K/255)+K);
+
+imageDataArray[j++]=R;
+imageDataArray[j++]=G;
+imageDataArray[j++]=B;
+imageDataArray[j++]=255;
+}
+}
+break;
+default:
+throw'Unsupported color mode';}
+
+}};
+
+
+return constructor;
+}();
+module.exports=decode;
+
+function decode(jpegData){
+var arr=new Uint8Array(jpegData);
+var decoder=new JpegImage();
+decoder.parse(arr);
+
+var image={
+width:decoder.width,
+height:decoder.height,
+data:new Buffer(decoder.width*decoder.height*4)};
+
+
+decoder.copyToImageData(image);
+
+return image;
+}
+
+}).call(this,require("buffer").Buffer);
+},{"buffer":88}],112:[function(require,module,exports){
+(function(Buffer){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var btoa=btoa||function(buf){
+return new Buffer(buf).toString('base64');
+};
+
+function JPEGEncoder(quality){
+var self=this;
+var fround=Math.round;
+var ffloor=Math.floor;
+var YTable=new Array(64);
+var UVTable=new Array(64);
+var fdtbl_Y=new Array(64);
+var fdtbl_UV=new Array(64);
+var YDC_HT;
+var UVDC_HT;
+var YAC_HT;
+var UVAC_HT;
+
+var bitcode=new Array(65535);
+var category=new Array(65535);
+var outputfDCTQuant=new Array(64);
+var DU=new Array(64);
+var byteout=[];
+var bytenew=0;
+var bytepos=7;
+
+var YDU=new Array(64);
+var UDU=new Array(64);
+var VDU=new Array(64);
+var clt=new Array(256);
+var RGB_YUV_TABLE=new Array(2048);
+var currentQuality;
+
+var ZigZag=[
+0,1,5,6,14,15,27,28,
+2,4,7,13,16,26,29,42,
+3,8,12,17,25,30,41,43,
+9,11,18,24,31,40,44,53,
+10,19,23,32,39,45,52,54,
+20,22,33,38,46,51,55,60,
+21,34,37,47,50,56,59,61,
+35,36,48,49,57,58,62,63];
+
+
+var std_dc_luminance_nrcodes=[0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];
+var std_dc_luminance_values=[0,1,2,3,4,5,6,7,8,9,10,11];
+var std_ac_luminance_nrcodes=[0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];
+var std_ac_luminance_values=[
+0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
+0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
+0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
+0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
+0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
+0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
+0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
+0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
+0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
+0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
+0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
+0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
+0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
+0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
+0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
+0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
+0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
+0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
+0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
+0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
+0xf9,0xfa];
+
+
+var std_dc_chrominance_nrcodes=[0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];
+var std_dc_chrominance_values=[0,1,2,3,4,5,6,7,8,9,10,11];
+var std_ac_chrominance_nrcodes=[0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];
+var std_ac_chrominance_values=[
+0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
+0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
+0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
+0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
+0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
+0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
+0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
+0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
+0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
+0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
+0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
+0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
+0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
+0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
+0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
+0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
+0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
+0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
+0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
+0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
+0xf9,0xfa];
+
+
+function initQuantTables(sf){
+var YQT=[
+16,11,10,16,24,40,51,61,
+12,12,14,19,26,58,60,55,
+14,13,16,24,40,57,69,56,
+14,17,22,29,51,87,80,62,
+18,22,37,56,68,109,103,77,
+24,35,55,64,81,104,113,92,
+49,64,78,87,103,121,120,101,
+72,92,95,98,112,100,103,99];
+
+
+for(var i=0;i<64;i++){
+var t=ffloor((YQT[i]*sf+50)/100);
+if(t<1){
+t=1;
+}else if(t>255){
+t=255;
+}
+YTable[ZigZag[i]]=t;
+}
+var UVQT=[
+17,18,24,47,99,99,99,99,
+18,21,26,66,99,99,99,99,
+24,26,56,99,99,99,99,99,
+47,66,99,99,99,99,99,99,
+99,99,99,99,99,99,99,99,
+99,99,99,99,99,99,99,99,
+99,99,99,99,99,99,99,99,
+99,99,99,99,99,99,99,99];
+
+for(var j=0;j<64;j++){
+var u=ffloor((UVQT[j]*sf+50)/100);
+if(u<1){
+u=1;
+}else if(u>255){
+u=255;
+}
+UVTable[ZigZag[j]]=u;
+}
+var aasf=[
+1.0,1.387039845,1.306562965,1.175875602,
+1.0,0.785694958,0.541196100,0.275899379];
+
+var k=0;
+for(var row=0;row<8;row++)
+{
+for(var col=0;col<8;col++)
+{
+fdtbl_Y[k]=1.0/(YTable[ZigZag[k]]*aasf[row]*aasf[col]*8.0);
+fdtbl_UV[k]=1.0/(UVTable[ZigZag[k]]*aasf[row]*aasf[col]*8.0);
+k++;
+}
+}
+}
+
+function computeHuffmanTbl(nrcodes,std_table){
+var codevalue=0;
+var pos_in_table=0;
+var HT=new Array();
+for(var k=1;k<=16;k++){
+for(var j=1;j<=nrcodes[k];j++){
+HT[std_table[pos_in_table]]=[];
+HT[std_table[pos_in_table]][0]=codevalue;
+HT[std_table[pos_in_table]][1]=k;
+pos_in_table++;
+codevalue++;
+}
+codevalue*=2;
+}
+return HT;
+}
+
+function initHuffmanTbl()
+{
+YDC_HT=computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);
+UVDC_HT=computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);
+YAC_HT=computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);
+UVAC_HT=computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);
+}
+
+function initCategoryNumber()
+{
+var nrlower=1;
+var nrupper=2;
+for(var cat=1;cat<=15;cat++){
+
+for(var nr=nrlower;nr<nrupper;nr++){
+category[32767+nr]=cat;
+bitcode[32767+nr]=[];
+bitcode[32767+nr][1]=cat;
+bitcode[32767+nr][0]=nr;
+}
+
+for(var nrneg=-(nrupper-1);nrneg<=-nrlower;nrneg++){
+category[32767+nrneg]=cat;
+bitcode[32767+nrneg]=[];
+bitcode[32767+nrneg][1]=cat;
+bitcode[32767+nrneg][0]=nrupper-1+nrneg;
+}
+nrlower<<=1;
+nrupper<<=1;
+}
+}
+
+function initRGBYUVTable(){
+for(var i=0;i<256;i++){
+RGB_YUV_TABLE[i]=19595*i;
+RGB_YUV_TABLE[i+256>>0]=38470*i;
+RGB_YUV_TABLE[i+512>>0]=7471*i+0x8000;
+RGB_YUV_TABLE[i+768>>0]=-11059*i;
+RGB_YUV_TABLE[i+1024>>0]=-21709*i;
+RGB_YUV_TABLE[i+1280>>0]=32768*i+0x807FFF;
+RGB_YUV_TABLE[i+1536>>0]=-27439*i;
+RGB_YUV_TABLE[i+1792>>0]=-5329*i;
+}
+}
+
+
+function writeBits(bs)
+{
+var value=bs[0];
+var posval=bs[1]-1;
+while(posval>=0){
+if(value&1<<posval){
+bytenew|=1<<bytepos;
+}
+posval--;
+bytepos--;
+if(bytepos<0){
+if(bytenew==0xFF){
+writeByte(0xFF);
+writeByte(0);
+}else
+{
+writeByte(bytenew);
+}
+bytepos=7;
+bytenew=0;
+}
+}
+}
+
+function writeByte(value)
+{
+
+byteout.push(value);
+}
+
+function writeWord(value)
+{
+writeByte(value>>8&0xFF);
+writeByte(value&0xFF);
+}
+
+
+function fDCTQuant(data,fdtbl)
+{
+var d0,d1,d2,d3,d4,d5,d6,d7;
+
+var dataOff=0;
+var i;
+const I8=8;
+const I64=64;
+for(i=0;i<I8;++i)
+{
+d0=data[dataOff];
+d1=data[dataOff+1];
+d2=data[dataOff+2];
+d3=data[dataOff+3];
+d4=data[dataOff+4];
+d5=data[dataOff+5];
+d6=data[dataOff+6];
+d7=data[dataOff+7];
+
+var tmp0=d0+d7;
+var tmp7=d0-d7;
+var tmp1=d1+d6;
+var tmp6=d1-d6;
+var tmp2=d2+d5;
+var tmp5=d2-d5;
+var tmp3=d3+d4;
+var tmp4=d3-d4;
+
+
+var tmp10=tmp0+tmp3;
+var tmp13=tmp0-tmp3;
+var tmp11=tmp1+tmp2;
+var tmp12=tmp1-tmp2;
+
+data[dataOff]=tmp10+tmp11;
+data[dataOff+4]=tmp10-tmp11;
+
+var z1=(tmp12+tmp13)*0.707106781;
+data[dataOff+2]=tmp13+z1;
+data[dataOff+6]=tmp13-z1;
+
+
+tmp10=tmp4+tmp5;
+tmp11=tmp5+tmp6;
+tmp12=tmp6+tmp7;
+
+
+var z5=(tmp10-tmp12)*0.382683433;
+var z2=0.541196100*tmp10+z5;
+var z4=1.306562965*tmp12+z5;
+var z3=tmp11*0.707106781;
+
+var z11=tmp7+z3;
+var z13=tmp7-z3;
+
+data[dataOff+5]=z13+z2;
+data[dataOff+3]=z13-z2;
+data[dataOff+1]=z11+z4;
+data[dataOff+7]=z11-z4;
+
+dataOff+=8;
+}
+
+
+dataOff=0;
+for(i=0;i<I8;++i)
+{
+d0=data[dataOff];
+d1=data[dataOff+8];
+d2=data[dataOff+16];
+d3=data[dataOff+24];
+d4=data[dataOff+32];
+d5=data[dataOff+40];
+d6=data[dataOff+48];
+d7=data[dataOff+56];
+
+var tmp0p2=d0+d7;
+var tmp7p2=d0-d7;
+var tmp1p2=d1+d6;
+var tmp6p2=d1-d6;
+var tmp2p2=d2+d5;
+var tmp5p2=d2-d5;
+var tmp3p2=d3+d4;
+var tmp4p2=d3-d4;
+
+
+var tmp10p2=tmp0p2+tmp3p2;
+var tmp13p2=tmp0p2-tmp3p2;
+var tmp11p2=tmp1p2+tmp2p2;
+var tmp12p2=tmp1p2-tmp2p2;
+
+data[dataOff]=tmp10p2+tmp11p2;
+data[dataOff+32]=tmp10p2-tmp11p2;
+
+var z1p2=(tmp12p2+tmp13p2)*0.707106781;
+data[dataOff+16]=tmp13p2+z1p2;
+data[dataOff+48]=tmp13p2-z1p2;
+
+
+tmp10p2=tmp4p2+tmp5p2;
+tmp11p2=tmp5p2+tmp6p2;
+tmp12p2=tmp6p2+tmp7p2;
+
+
+var z5p2=(tmp10p2-tmp12p2)*0.382683433;
+var z2p2=0.541196100*tmp10p2+z5p2;
+var z4p2=1.306562965*tmp12p2+z5p2;
+var z3p2=tmp11p2*0.707106781;
+
+var z11p2=tmp7p2+z3p2;
+var z13p2=tmp7p2-z3p2;
+
+data[dataOff+40]=z13p2+z2p2;
+data[dataOff+24]=z13p2-z2p2;
+data[dataOff+8]=z11p2+z4p2;
+data[dataOff+56]=z11p2-z4p2;
+
+dataOff++;
+}
+
+
+var fDCTQuant;
+for(i=0;i<I64;++i)
+{
+
+fDCTQuant=data[i]*fdtbl[i];
+outputfDCTQuant[i]=fDCTQuant>0.0?fDCTQuant+0.5|0:fDCTQuant-0.5|0;
+
+
+}
+return outputfDCTQuant;
+}
+
+function writeAPP0()
+{
+writeWord(0xFFE0);
+writeWord(16);
+writeByte(0x4A);
+writeByte(0x46);
+writeByte(0x49);
+writeByte(0x46);
+writeByte(0);
+writeByte(1);
+writeByte(1);
+writeByte(0);
+writeWord(1);
+writeWord(1);
+writeByte(0);
+writeByte(0);
+}
+
+function writeSOF0(width,height)
+{
+writeWord(0xFFC0);
+writeWord(17);
+writeByte(8);
+writeWord(height);
+writeWord(width);
+writeByte(3);
+writeByte(1);
+writeByte(0x11);
+writeByte(0);
+writeByte(2);
+writeByte(0x11);
+writeByte(1);
+writeByte(3);
+writeByte(0x11);
+writeByte(1);
+}
+
+function writeDQT()
+{
+writeWord(0xFFDB);
+writeWord(132);
+writeByte(0);
+for(var i=0;i<64;i++){
+writeByte(YTable[i]);
+}
+writeByte(1);
+for(var j=0;j<64;j++){
+writeByte(UVTable[j]);
+}
+}
+
+function writeDHT()
+{
+writeWord(0xFFC4);
+writeWord(0x01A2);
+
+writeByte(0);
+for(var i=0;i<16;i++){
+writeByte(std_dc_luminance_nrcodes[i+1]);
+}
+for(var j=0;j<=11;j++){
+writeByte(std_dc_luminance_values[j]);
+}
+
+writeByte(0x10);
+for(var k=0;k<16;k++){
+writeByte(std_ac_luminance_nrcodes[k+1]);
+}
+for(var l=0;l<=161;l++){
+writeByte(std_ac_luminance_values[l]);
+}
+
+writeByte(1);
+for(var m=0;m<16;m++){
+writeByte(std_dc_chrominance_nrcodes[m+1]);
+}
+for(var n=0;n<=11;n++){
+writeByte(std_dc_chrominance_values[n]);
+}
+
+writeByte(0x11);
+for(var o=0;o<16;o++){
+writeByte(std_ac_chrominance_nrcodes[o+1]);
+}
+for(var p=0;p<=161;p++){
+writeByte(std_ac_chrominance_values[p]);
+}
+}
+
+function writeSOS()
+{
+writeWord(0xFFDA);
+writeWord(12);
+writeByte(3);
+writeByte(1);
+writeByte(0);
+writeByte(2);
+writeByte(0x11);
+writeByte(3);
+writeByte(0x11);
+writeByte(0);
+writeByte(0x3f);
+writeByte(0);
+}
+
+function processDU(CDU,fdtbl,DC,HTDC,HTAC){
+var EOB=HTAC[0x00];
+var M16zeroes=HTAC[0xF0];
+var pos;
+const I16=16;
+const I63=63;
+const I64=64;
+var DU_DCT=fDCTQuant(CDU,fdtbl);
+
+for(var j=0;j<I64;++j){
+DU[ZigZag[j]]=DU_DCT[j];
+}
+var Diff=DU[0]-DC;DC=DU[0];
+
+if(Diff==0){
+writeBits(HTDC[0]);
+}else{
+pos=32767+Diff;
+writeBits(HTDC[category[pos]]);
+writeBits(bitcode[pos]);
+}
+
+var end0pos=63;
+for(;end0pos>0&&DU[end0pos]==0;end0pos--){};
+
+if(end0pos==0){
+writeBits(EOB);
+return DC;
+}
+var i=1;
+var lng;
+while(i<=end0pos){
+var startpos=i;
+for(;DU[i]==0&&i<=end0pos;++i){}
+var nrzeroes=i-startpos;
+if(nrzeroes>=I16){
+lng=nrzeroes>>4;
+for(var nrmarker=1;nrmarker<=lng;++nrmarker)
+writeBits(M16zeroes);
+nrzeroes=nrzeroes&0xF;
+}
+pos=32767+DU[i];
+writeBits(HTAC[(nrzeroes<<4)+category[pos]]);
+writeBits(bitcode[pos]);
+i++;
+}
+if(end0pos!=I63){
+writeBits(EOB);
+}
+return DC;
+}
+
+function initCharLookupTable(){
+var sfcc=String.fromCharCode;
+for(var i=0;i<256;i++){
+clt[i]=sfcc(i);
+}
+}
+
+this.encode=function(image,quality)
+{
+var time_start=new Date().getTime();
+
+if(quality)setQuality(quality);
+
+
+byteout=new Array();
+bytenew=0;
+bytepos=7;
+
+
+writeWord(0xFFD8);
+writeAPP0();
+writeDQT();
+writeSOF0(image.width,image.height);
+writeDHT();
+writeSOS();
+
+
+
+var DCY=0;
+var DCU=0;
+var DCV=0;
+
+bytenew=0;
+bytepos=7;
+
+
+this.encode.displayName="_encode_";
+
+var imageData=image.data;
+var width=image.width;
+var height=image.height;
+
+var quadWidth=width*4;
+var tripleWidth=width*3;
+
+var x,y=0;
+var r,g,b;
+var start,p,col,row,pos;
+while(y<height){
+x=0;
+while(x<quadWidth){
+start=quadWidth*y+x;
+p=start;
+col=-1;
+row=0;
+
+for(pos=0;pos<64;pos++){
+row=pos>>3;
+col=(pos&7)*4;
+p=start+row*quadWidth+col;
+
+if(y+row>=height){
+p-=quadWidth*(y+1+row-height);
+}
+
+if(x+col>=quadWidth){
+p-=x+col-quadWidth+4;
+}
+
+r=imageData[p++];
+g=imageData[p++];
+b=imageData[p++];
+
+
+
+
+
+
+
+
+
+YDU[pos]=(RGB_YUV_TABLE[r]+RGB_YUV_TABLE[g+256>>0]+RGB_YUV_TABLE[b+512>>0]>>16)-128;
+UDU[pos]=(RGB_YUV_TABLE[r+768>>0]+RGB_YUV_TABLE[g+1024>>0]+RGB_YUV_TABLE[b+1280>>0]>>16)-128;
+VDU[pos]=(RGB_YUV_TABLE[r+1280>>0]+RGB_YUV_TABLE[g+1536>>0]+RGB_YUV_TABLE[b+1792>>0]>>16)-128;
+
+}
+
+DCY=processDU(YDU,fdtbl_Y,DCY,YDC_HT,YAC_HT);
+DCU=processDU(UDU,fdtbl_UV,DCU,UVDC_HT,UVAC_HT);
+DCV=processDU(VDU,fdtbl_UV,DCV,UVDC_HT,UVAC_HT);
+x+=32;
+}
+y+=8;
+}
+
+
+
+
+
+if(bytepos>=0){
+var fillbits=[];
+fillbits[1]=bytepos+1;
+fillbits[0]=(1<<bytepos+1)-1;
+writeBits(fillbits);
+}
+
+writeWord(0xFFD9);
+
+
+return new Buffer(byteout);
+
+var jpegDataUri='data:image/jpeg;base64,'+btoa(byteout.join(''));
+
+byteout=[];
+
+
+var duration=new Date().getTime()-time_start;
+
+
+
+return jpegDataUri;
+};
+
+function setQuality(quality){
+if(quality<=0){
+quality=1;
+}
+if(quality>100){
+quality=100;
+}
+
+if(currentQuality==quality)return;
+
+var sf=0;
+if(quality<50){
+sf=Math.floor(5000/quality);
+}else{
+sf=Math.floor(200-quality*2);
+}
+
+initQuantTables(sf);
+currentQuality=quality;
+
+}
+
+function init(){
+var time_start=new Date().getTime();
+if(!quality)quality=50;
+
+initCharLookupTable();
+initHuffmanTbl();
+initCategoryNumber();
+initRGBYUVTable();
+
+setQuality(quality);
+var duration=new Date().getTime()-time_start;
+
+}
+
+init();
+
+};
+module.exports=encode;
+
+function encode(imgData,qu){
+if(typeof qu==='undefined')qu=50;
+var encoder=new JPEGEncoder(qu);
+var data=encoder.encode(imgData,qu);
+return{
+data:data,
+width:imgData.width,
+height:imgData.height};
+
+}
+
+
+function getImageDataFromImage(idOrElement){
+var theImg=typeof idOrElement=='string'?document.getElementById(idOrElement):idOrElement;
+var cvs=document.createElement('canvas');
+cvs.width=theImg.width;
+cvs.height=theImg.height;
+var ctx=cvs.getContext("2d");
+ctx.drawImage(theImg,0,0);
+
+return ctx.getImageData(0,0,cvs.width,cvs.height);
+}
+
+}).call(this,require("buffer").Buffer);
+},{"buffer":88}],113:[function(require,module,exports){
+(function(process){
+
+
+
+
+
+'use strict';
+
+const debug=require('debug');
+const marky=require('marky');
+
+const EventEmitter=require('events').EventEmitter;
+const isWindows=process.platform==='win32';
+
+
+const isBrowser=process.browser;
+
+const colors={
+red:isBrowser?'crimson':1,
+yellow:isBrowser?'gold':3,
+cyan:isBrowser?'darkturquoise':6,
+green:isBrowser?'forestgreen':2,
+blue:isBrowser?'steelblue':4,
+magenta:isBrowser?'palevioletred':5};
+
+
+
+debug.colors=[colors.cyan,colors.green,colors.blue,colors.magenta];
+
+class Emitter extends EventEmitter{
+
+
+
+
+
+
+issueStatus(title,argsArray){
+if(title==='status'||title==='statusEnd'){
+this.emit(title,[title,...argsArray]);
+}
+}
+
+
+
+
+
+
+
+issueWarning(title,argsArray){
+this.emit('warning',[title,...argsArray]);
+}}
+
+
+const loggersByTitle={};
+const loggingBufferColumns=25;
+let level_;
+
+class Log{
+static _logToStdErr(title,argsArray){
+const log=Log.loggerfn(title);
+log(...argsArray);
+}
+
+static loggerfn(title){
+let log=loggersByTitle[title];
+if(!log){
+log=debug(title);
+loggersByTitle[title]=log;
+
+if(title.endsWith('error')){
+log.color=colors.red;
+}else if(title.endsWith('warn')){
+log.color=colors.yellow;
+}
+}
+return log;
+}
+
+
+
+
+static setLevel(level){
+level_=level;
+switch(level){
+case'silent':
+debug.enable('-*');
+break;
+case'verbose':
+debug.enable('*');
+break;
+case'error':
+debug.enable('-*, *:error');
+break;
+default:
+debug.enable('*, -*:verbose');}
+
+}
+
+
+
+
+
+
+
+static formatProtocol(prefix,data,level){
+const columns=!process||process.browser?Infinity:process.stdout.columns;
+const method=data.method||'?????';
+const maxLength=columns-method.length-prefix.length-loggingBufferColumns;
+
+const snippet=data.params&&method!=='IO.read'?
+JSON.stringify(data.params).substr(0,maxLength):'';
+Log._logToStdErr(`${prefix}:${level||''}`,[method,snippet]);
+}
+
+
+
+
+static isVerbose(){
+return level_==='verbose';
+}
+
+static time({msg,id,args=[]},level='log'){
+marky.mark(id);
+Log[level]('status',msg,...args);
+}
+
+static timeEnd({msg,id,args=[]},level='verbose'){
+Log[level]('statusEnd',msg,...args);
+marky.stop(id);
+}
+
+static log(title,...args){
+Log.events.issueStatus(title,args);
+return Log._logToStdErr(title,args);
+}
+
+static warn(title,...args){
+Log.events.issueWarning(title,args);
+return Log._logToStdErr(`${title}:warn`,args);
+}
+
+static error(title,...args){
+return Log._logToStdErr(`${title}:error`,args);
+}
+
+static verbose(title,...args){
+Log.events.issueStatus(title,args);
+return Log._logToStdErr(`${title}:verbose`,args);
+}
+
+
+
+
+
+
+static greenify(str){
+return`${Log.green}${str}${Log.reset}`;
+}
+
+
+
+
+
+
+static redify(str){
+return`${Log.red}${str}${Log.reset}`;
+}
+
+static get green(){
+return'\x1B[32m';
+}
+
+static get red(){
+return'\x1B[31m';
+}
+
+static get yellow(){
+return'\x1b[33m';
+}
+
+static get purple(){
+return'\x1b[95m';
+}
+
+static get reset(){
+return'\x1B[0m';
+}
+
+static get bold(){
+return'\x1b[1m';
+}
+
+static get dim(){
+return'\x1b[2m';
+}
+
+static get tick(){
+return isWindows?'\u221A':'✓';
+}
+
+static get cross(){
+return isWindows?'\u00D7':'✘';
+}
+
+static get whiteSmallSquare(){
+return isWindows?'\u0387':'▫';
+}
+
+static get heavyHorizontal(){
+return isWindows?'\u2500':'━';
+}
+
+static get heavyVertical(){
+return isWindows?'\u2502 ':'┃ ';
+}
+
+static get heavyUpAndRight(){
+return isWindows?'\u2514':'┗';
+}
+
+static get heavyVerticalAndRight(){
+return isWindows?'\u251C':'┣';
+}
+
+static get heavyDownAndHorizontal(){
+return isWindows?'\u252C':'┳';
+}
+
+static get doubleLightHorizontal(){
+return'──';
+}}
+
+
+Log.events=new Emitter();
+Log.takeTimeEntries=()=>{
+const entries=marky.getEntries();
+marky.clear();
+return entries;
+};
+Log.getTimeEntries=()=>marky.getEntries();
+
+module.exports=Log;
+
+}).call(this,require('_process'));
+},{"_process":130,"debug":91,"events":93,"marky":116}],114:[function(require,module,exports){
+(function(global){
+
+
+
+
+
+
+
+
+
+
+var LARGE_ARRAY_SIZE=200;
+
+
+var HASH_UNDEFINED='__lodash_hash_undefined__';
+
+
+var COMPARE_PARTIAL_FLAG=1,
+COMPARE_UNORDERED_FLAG=2;
+
+
+var MAX_SAFE_INTEGER=9007199254740991;
+
+
+var argsTag='[object Arguments]',
+arrayTag='[object Array]',
+asyncTag='[object AsyncFunction]',
+boolTag='[object Boolean]',
+dateTag='[object Date]',
+errorTag='[object Error]',
+funcTag='[object Function]',
+genTag='[object GeneratorFunction]',
+mapTag='[object Map]',
+numberTag='[object Number]',
+nullTag='[object Null]',
+objectTag='[object Object]',
+promiseTag='[object Promise]',
+proxyTag='[object Proxy]',
+regexpTag='[object RegExp]',
+setTag='[object Set]',
+stringTag='[object String]',
+symbolTag='[object Symbol]',
+undefinedTag='[object Undefined]',
+weakMapTag='[object WeakMap]';
+
+var arrayBufferTag='[object ArrayBuffer]',
+dataViewTag='[object DataView]',
+float32Tag='[object Float32Array]',
+float64Tag='[object Float64Array]',
+int8Tag='[object Int8Array]',
+int16Tag='[object Int16Array]',
+int32Tag='[object Int32Array]',
+uint8Tag='[object Uint8Array]',
+uint8ClampedTag='[object Uint8ClampedArray]',
+uint16Tag='[object Uint16Array]',
+uint32Tag='[object Uint32Array]';
+
+
+
+
+
+var reRegExpChar=/[\\^$.*+?()[\]{}|]/g;
+
+
+var reIsHostCtor=/^\[object .+?Constructor\]$/;
+
+
+var reIsUint=/^(?:0|[1-9]\d*)$/;
+
+
+var typedArrayTags={};
+typedArrayTags[float32Tag]=typedArrayTags[float64Tag]=
+typedArrayTags[int8Tag]=typedArrayTags[int16Tag]=
+typedArrayTags[int32Tag]=typedArrayTags[uint8Tag]=
+typedArrayTags[uint8ClampedTag]=typedArrayTags[uint16Tag]=
+typedArrayTags[uint32Tag]=true;
+typedArrayTags[argsTag]=typedArrayTags[arrayTag]=
+typedArrayTags[arrayBufferTag]=typedArrayTags[boolTag]=
+typedArrayTags[dataViewTag]=typedArrayTags[dateTag]=
+typedArrayTags[errorTag]=typedArrayTags[funcTag]=
+typedArrayTags[mapTag]=typedArrayTags[numberTag]=
+typedArrayTags[objectTag]=typedArrayTags[regexpTag]=
+typedArrayTags[setTag]=typedArrayTags[stringTag]=
+typedArrayTags[weakMapTag]=false;
+
+
+var freeGlobal=typeof global=='object'&&global&&global.Object===Object&&global;
+
+
+var freeSelf=typeof self=='object'&&self&&self.Object===Object&&self;
+
+
+var root=freeGlobal||freeSelf||Function('return this')();
+
+
+var freeExports=typeof exports=='object'&&exports&&!exports.nodeType&&exports;
+
+
+var freeModule=freeExports&&typeof module=='object'&&module&&!module.nodeType&&module;
+
+
+var moduleExports=freeModule&&freeModule.exports===freeExports;
+
+
+var freeProcess=moduleExports&&freeGlobal.process;
+
+
+var nodeUtil=function(){
+try{
+return freeProcess&&freeProcess.binding&&freeProcess.binding('util');
+}catch(e){}
+}();
+
+
+var nodeIsTypedArray=nodeUtil&&nodeUtil.isTypedArray;
+
+
+
+
+
+
+
+
+
+
+function arrayFilter(array,predicate){
+var index=-1,
+length=array==null?0:array.length,
+resIndex=0,
+result=[];
+
+while(++index<length){
+var value=array[index];
+if(predicate(value,index,array)){
+result[resIndex++]=value;
+}
+}
+return result;
+}
+
+
+
+
+
+
+
+
+
+function arrayPush(array,values){
+var index=-1,
+length=values.length,
+offset=array.length;
+
+while(++index<length){
+array[offset+index]=values[index];
+}
+return array;
+}
+
+
+
+
+
+
+
+
+
+
+
+function arraySome(array,predicate){
+var index=-1,
+length=array==null?0:array.length;
+
+while(++index<length){
+if(predicate(array[index],index,array)){
+return true;
+}
+}
+return false;
+}
+
+
+
+
+
+
+
+
+
+
+function baseTimes(n,iteratee){
+var index=-1,
+result=Array(n);
+
+while(++index<n){
+result[index]=iteratee(index);
+}
+return result;
+}
+
+
+
+
+
+
+
+
+function baseUnary(func){
+return function(value){
+return func(value);
+};
+}
+
+
+
+
+
+
+
+
+
+function cacheHas(cache,key){
+return cache.has(key);
+}
+
+
+
+
+
+
+
+
+
+function getValue(object,key){
+return object==null?undefined:object[key];
+}
+
+
+
+
+
+
+
+
+function mapToArray(map){
+var index=-1,
+result=Array(map.size);
+
+map.forEach(function(value,key){
+result[++index]=[key,value];
+});
+return result;
+}
+
+
+
+
+
+
+
+
+
+function overArg(func,transform){
+return function(arg){
+return func(transform(arg));
+};
+}
+
+
+
+
+
+
+
+
+function setToArray(set){
+var index=-1,
+result=Array(set.size);
+
+set.forEach(function(value){
+result[++index]=value;
+});
+return result;
+}
+
+
+var arrayProto=Array.prototype,
+funcProto=Function.prototype,
+objectProto=Object.prototype;
+
+
+var coreJsData=root['__core-js_shared__'];
+
+
+var funcToString=funcProto.toString;
+
+
+var hasOwnProperty=objectProto.hasOwnProperty;
+
+
+var maskSrcKey=function(){
+var uid=/[^.]+$/.exec(coreJsData&&coreJsData.keys&&coreJsData.keys.IE_PROTO||'');
+return uid?'Symbol(src)_1.'+uid:'';
+}();
+
+
+
+
+
+
+var nativeObjectToString=objectProto.toString;
+
+
+var reIsNative=RegExp('^'+
+funcToString.call(hasOwnProperty).replace(reRegExpChar,'\\$&').
+replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,'$1.*?')+'$');
+
+
+
+var Buffer=moduleExports?root.Buffer:undefined,
+Symbol=root.Symbol,
+Uint8Array=root.Uint8Array,
+propertyIsEnumerable=objectProto.propertyIsEnumerable,
+splice=arrayProto.splice,
+symToStringTag=Symbol?Symbol.toStringTag:undefined;
+
+
+var nativeGetSymbols=Object.getOwnPropertySymbols,
+nativeIsBuffer=Buffer?Buffer.isBuffer:undefined,
+nativeKeys=overArg(Object.keys,Object);
+
+
+var DataView=getNative(root,'DataView'),
+Map=getNative(root,'Map'),
+Promise=getNative(root,'Promise'),
+Set=getNative(root,'Set'),
+WeakMap=getNative(root,'WeakMap'),
+nativeCreate=getNative(Object,'create');
+
+
+var dataViewCtorString=toSource(DataView),
+mapCtorString=toSource(Map),
+promiseCtorString=toSource(Promise),
+setCtorString=toSource(Set),
+weakMapCtorString=toSource(WeakMap);
+
+
+var symbolProto=Symbol?Symbol.prototype:undefined,
+symbolValueOf=symbolProto?symbolProto.valueOf:undefined;
+
+
+
+
+
+
+
+
+function Hash(entries){
+var index=-1,
+length=entries==null?0:entries.length;
+
+this.clear();
+while(++index<length){
+var entry=entries[index];
+this.set(entry[0],entry[1]);
+}
+}
+
+
+
+
+
+
+
+
+function hashClear(){
+this.__data__=nativeCreate?nativeCreate(null):{};
+this.size=0;
+}
+
+
+
+
+
+
+
+
+
+
+
+function hashDelete(key){
+var result=this.has(key)&&delete this.__data__[key];
+this.size-=result?1:0;
+return result;
+}
+
+
+
+
+
+
+
+
+
+
+function hashGet(key){
+var data=this.__data__;
+if(nativeCreate){
+var result=data[key];
+return result===HASH_UNDEFINED?undefined:result;
+}
+return hasOwnProperty.call(data,key)?data[key]:undefined;
+}
+
+
+
+
+
+
+
+
+
+
+function hashHas(key){
+var data=this.__data__;
+return nativeCreate?data[key]!==undefined:hasOwnProperty.call(data,key);
+}
+
+
+
+
+
+
+
+
+
+
+
+function hashSet(key,value){
+var data=this.__data__;
+this.size+=this.has(key)?0:1;
+data[key]=nativeCreate&&value===undefined?HASH_UNDEFINED:value;
+return this;
+}
+
+
+Hash.prototype.clear=hashClear;
+Hash.prototype['delete']=hashDelete;
+Hash.prototype.get=hashGet;
+Hash.prototype.has=hashHas;
+Hash.prototype.set=hashSet;
+
+
+
+
+
+
+
+
+function ListCache(entries){
+var index=-1,
+length=entries==null?0:entries.length;
+
+this.clear();
+while(++index<length){
+var entry=entries[index];
+this.set(entry[0],entry[1]);
+}
+}
+
+
+
+
+
+
+
+
+function listCacheClear(){
+this.__data__=[];
+this.size=0;
+}
+
+
+
+
+
+
+
+
+
+
+function listCacheDelete(key){
+var data=this.__data__,
+index=assocIndexOf(data,key);
+
+if(index<0){
+return false;
+}
+var lastIndex=data.length-1;
+if(index==lastIndex){
+data.pop();
+}else{
+splice.call(data,index,1);
+}
+--this.size;
+return true;
+}
+
+
+
+
+
+
+
+
+
+
+function listCacheGet(key){
+var data=this.__data__,
+index=assocIndexOf(data,key);
+
+return index<0?undefined:data[index][1];
+}
+
+
+
+
+
+
+
+
+
+
+function listCacheHas(key){
+return assocIndexOf(this.__data__,key)>-1;
+}
+
+
+
+
+
+
+
+
+
+
+
+function listCacheSet(key,value){
+var data=this.__data__,
+index=assocIndexOf(data,key);
+
+if(index<0){
+++this.size;
+data.push([key,value]);
+}else{
+data[index][1]=value;
+}
+return this;
+}
+
+
+ListCache.prototype.clear=listCacheClear;
+ListCache.prototype['delete']=listCacheDelete;
+ListCache.prototype.get=listCacheGet;
+ListCache.prototype.has=listCacheHas;
+ListCache.prototype.set=listCacheSet;
+
+
+
+
+
+
+
+
+function MapCache(entries){
+var index=-1,
+length=entries==null?0:entries.length;
+
+this.clear();
+while(++index<length){
+var entry=entries[index];
+this.set(entry[0],entry[1]);
+}
+}
+
+
+
+
+
+
+
+
+function mapCacheClear(){
+this.size=0;
+this.__data__={
+'hash':new Hash(),
+'map':new(Map||ListCache)(),
+'string':new Hash()};
+
+}
+
+
+
+
+
+
+
+
+
+
+function mapCacheDelete(key){
+var result=getMapData(this,key)['delete'](key);
+this.size-=result?1:0;
+return result;
+}
+
+
+
+
+
+
+
+
+
+
+function mapCacheGet(key){
+return getMapData(this,key).get(key);
+}
+
+
+
+
+
+
+
+
+
+
+function mapCacheHas(key){
+return getMapData(this,key).has(key);
+}
+
+
+
+
+
+
+
+
+
+
+
+function mapCacheSet(key,value){
+var data=getMapData(this,key),
+size=data.size;
+
+data.set(key,value);
+this.size+=data.size==size?0:1;
+return this;
+}
+
+
+MapCache.prototype.clear=mapCacheClear;
+MapCache.prototype['delete']=mapCacheDelete;
+MapCache.prototype.get=mapCacheGet;
+MapCache.prototype.has=mapCacheHas;
+MapCache.prototype.set=mapCacheSet;
+
+
+
+
+
+
+
+
+
+function SetCache(values){
+var index=-1,
+length=values==null?0:values.length;
+
+this.__data__=new MapCache();
+while(++index<length){
+this.add(values[index]);
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+function setCacheAdd(value){
+this.__data__.set(value,HASH_UNDEFINED);
+return this;
+}
+
+
+
+
+
+
+
+
+
+
+function setCacheHas(value){
+return this.__data__.has(value);
+}
+
+
+SetCache.prototype.add=SetCache.prototype.push=setCacheAdd;
+SetCache.prototype.has=setCacheHas;
+
+
+
+
+
+
+
+
+function Stack(entries){
+var data=this.__data__=new ListCache(entries);
+this.size=data.size;
+}
+
+
+
+
+
+
+
+
+function stackClear(){
+this.__data__=new ListCache();
+this.size=0;
+}
+
+
+
+
+
+
+
+
+
+
+function stackDelete(key){
+var data=this.__data__,
+result=data['delete'](key);
+
+this.size=data.size;
+return result;
+}
+
+
+
+
+
+
+
+
+
+
+function stackGet(key){
+return this.__data__.get(key);
+}
+
+
+
+
+
+
+
+
+
+
+function stackHas(key){
+return this.__data__.has(key);
+}
+
+
+
+
+
+
+
+
+
+
+
+function stackSet(key,value){
+var data=this.__data__;
+if(data instanceof ListCache){
+var pairs=data.__data__;
+if(!Map||pairs.length<LARGE_ARRAY_SIZE-1){
+pairs.push([key,value]);
+this.size=++data.size;
+return this;
+}
+data=this.__data__=new MapCache(pairs);
+}
+data.set(key,value);
+this.size=data.size;
+return this;
+}
+
+
+Stack.prototype.clear=stackClear;
+Stack.prototype['delete']=stackDelete;
+Stack.prototype.get=stackGet;
+Stack.prototype.has=stackHas;
+Stack.prototype.set=stackSet;
+
+
+
+
+
+
+
+
+
+function arrayLikeKeys(value,inherited){
+var isArr=isArray(value),
+isArg=!isArr&&isArguments(value),
+isBuff=!isArr&&!isArg&&isBuffer(value),
+isType=!isArr&&!isArg&&!isBuff&&isTypedArray(value),
+skipIndexes=isArr||isArg||isBuff||isType,
+result=skipIndexes?baseTimes(value.length,String):[],
+length=result.length;
+
+for(var key in value){
+if((inherited||hasOwnProperty.call(value,key))&&
+!(skipIndexes&&(
+
+key=='length'||
+
+isBuff&&(key=='offset'||key=='parent')||
+
+isType&&(key=='buffer'||key=='byteLength'||key=='byteOffset')||
+
+isIndex(key,length))))
+{
+result.push(key);
+}
+}
+return result;
+}
+
+
+
+
+
+
+
+
+
+function assocIndexOf(array,key){
+var length=array.length;
+while(length--){
+if(eq(array[length][0],key)){
+return length;
+}
+}
+return-1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+function baseGetAllKeys(object,keysFunc,symbolsFunc){
+var result=keysFunc(object);
+return isArray(object)?result:arrayPush(result,symbolsFunc(object));
+}
+
+
+
+
+
+
+
+
+function baseGetTag(value){
+if(value==null){
+return value===undefined?undefinedTag:nullTag;
+}
+return symToStringTag&&symToStringTag in Object(value)?
+getRawTag(value):
+objectToString(value);
+}
+
+
+
+
+
+
+
+
+function baseIsArguments(value){
+return isObjectLike(value)&&baseGetTag(value)==argsTag;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function baseIsEqual(value,other,bitmask,customizer,stack){
+if(value===other){
+return true;
+}
+if(value==null||other==null||!isObjectLike(value)&&!isObjectLike(other)){
+return value!==value&&other!==other;
+}
+return baseIsEqualDeep(value,other,bitmask,customizer,baseIsEqual,stack);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function baseIsEqualDeep(object,other,bitmask,customizer,equalFunc,stack){
+var objIsArr=isArray(object),
+othIsArr=isArray(other),
+objTag=objIsArr?arrayTag:getTag(object),
+othTag=othIsArr?arrayTag:getTag(other);
+
+objTag=objTag==argsTag?objectTag:objTag;
+othTag=othTag==argsTag?objectTag:othTag;
+
+var objIsObj=objTag==objectTag,
+othIsObj=othTag==objectTag,
+isSameTag=objTag==othTag;
+
+if(isSameTag&&isBuffer(object)){
+if(!isBuffer(other)){
+return false;
+}
+objIsArr=true;
+objIsObj=false;
+}
+if(isSameTag&&!objIsObj){
+stack||(stack=new Stack());
+return objIsArr||isTypedArray(object)?
+equalArrays(object,other,bitmask,customizer,equalFunc,stack):
+equalByTag(object,other,objTag,bitmask,customizer,equalFunc,stack);
+}
+if(!(bitmask&COMPARE_PARTIAL_FLAG)){
+var objIsWrapped=objIsObj&&hasOwnProperty.call(object,'__wrapped__'),
+othIsWrapped=othIsObj&&hasOwnProperty.call(other,'__wrapped__');
+
+if(objIsWrapped||othIsWrapped){
+var objUnwrapped=objIsWrapped?object.value():object,
+othUnwrapped=othIsWrapped?other.value():other;
+
+stack||(stack=new Stack());
+return equalFunc(objUnwrapped,othUnwrapped,bitmask,customizer,stack);
+}
+}
+if(!isSameTag){
+return false;
+}
+stack||(stack=new Stack());
+return equalObjects(object,other,bitmask,customizer,equalFunc,stack);
+}
+
+
+
+
+
+
+
+
+
+function baseIsNative(value){
+if(!isObject(value)||isMasked(value)){
+return false;
+}
+var pattern=isFunction(value)?reIsNative:reIsHostCtor;
+return pattern.test(toSource(value));
+}
+
+
+
+
+
+
+
+
+function baseIsTypedArray(value){
+return isObjectLike(value)&&
+isLength(value.length)&&!!typedArrayTags[baseGetTag(value)];
+}
+
+
+
+
+
+
+
+
+function baseKeys(object){
+if(!isPrototype(object)){
+return nativeKeys(object);
+}
+var result=[];
+for(var key in Object(object)){
+if(hasOwnProperty.call(object,key)&&key!='constructor'){
+result.push(key);
+}
+}
+return result;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function equalArrays(array,other,bitmask,customizer,equalFunc,stack){
+var isPartial=bitmask&COMPARE_PARTIAL_FLAG,
+arrLength=array.length,
+othLength=other.length;
+
+if(arrLength!=othLength&&!(isPartial&&othLength>arrLength)){
+return false;
+}
+
+var stacked=stack.get(array);
+if(stacked&&stack.get(other)){
+return stacked==other;
+}
+var index=-1,
+result=true,
+seen=bitmask&COMPARE_UNORDERED_FLAG?new SetCache():undefined;
+
+stack.set(array,other);
+stack.set(other,array);
+
+
+while(++index<arrLength){
+var arrValue=array[index],
+othValue=other[index];
+
+if(customizer){
+var compared=isPartial?
+customizer(othValue,arrValue,index,other,array,stack):
+customizer(arrValue,othValue,index,array,other,stack);
+}
+if(compared!==undefined){
+if(compared){
+continue;
+}
+result=false;
+break;
+}
+
+if(seen){
+if(!arraySome(other,function(othValue,othIndex){
+if(!cacheHas(seen,othIndex)&&(
+arrValue===othValue||equalFunc(arrValue,othValue,bitmask,customizer,stack))){
+return seen.push(othIndex);
+}
+})){
+result=false;
+break;
+}
+}else if(!(
+arrValue===othValue||
+equalFunc(arrValue,othValue,bitmask,customizer,stack)))
+{
+result=false;
+break;
+}
+}
+stack['delete'](array);
+stack['delete'](other);
+return result;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function equalByTag(object,other,tag,bitmask,customizer,equalFunc,stack){
+switch(tag){
+case dataViewTag:
+if(object.byteLength!=other.byteLength||
+object.byteOffset!=other.byteOffset){
+return false;
+}
+object=object.buffer;
+other=other.buffer;
+
+case arrayBufferTag:
+if(object.byteLength!=other.byteLength||
+!equalFunc(new Uint8Array(object),new Uint8Array(other))){
+return false;
+}
+return true;
+
+case boolTag:
+case dateTag:
+case numberTag:
+
+
+return eq(+object,+other);
+
+case errorTag:
+return object.name==other.name&&object.message==other.message;
+
+case regexpTag:
+case stringTag:
+
+
+
+return object==other+'';
+
+case mapTag:
+var convert=mapToArray;
+
+case setTag:
+var isPartial=bitmask&COMPARE_PARTIAL_FLAG;
+convert||(convert=setToArray);
+
+if(object.size!=other.size&&!isPartial){
+return false;
+}
+
+var stacked=stack.get(object);
+if(stacked){
+return stacked==other;
+}
+bitmask|=COMPARE_UNORDERED_FLAG;
+
+
+stack.set(object,other);
+var result=equalArrays(convert(object),convert(other),bitmask,customizer,equalFunc,stack);
+stack['delete'](object);
+return result;
+
+case symbolTag:
+if(symbolValueOf){
+return symbolValueOf.call(object)==symbolValueOf.call(other);
+}}
+
+return false;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function equalObjects(object,other,bitmask,customizer,equalFunc,stack){
+var isPartial=bitmask&COMPARE_PARTIAL_FLAG,
+objProps=getAllKeys(object),
+objLength=objProps.length,
+othProps=getAllKeys(other),
+othLength=othProps.length;
+
+if(objLength!=othLength&&!isPartial){
+return false;
+}
+var index=objLength;
+while(index--){
+var key=objProps[index];
+if(!(isPartial?key in other:hasOwnProperty.call(other,key))){
+return false;
+}
+}
+
+var stacked=stack.get(object);
+if(stacked&&stack.get(other)){
+return stacked==other;
+}
+var result=true;
+stack.set(object,other);
+stack.set(other,object);
+
+var skipCtor=isPartial;
+while(++index<objLength){
+key=objProps[index];
+var objValue=object[key],
+othValue=other[key];
+
+if(customizer){
+var compared=isPartial?
+customizer(othValue,objValue,key,other,object,stack):
+customizer(objValue,othValue,key,object,other,stack);
+}
+
+if(!(compared===undefined?
+objValue===othValue||equalFunc(objValue,othValue,bitmask,customizer,stack):
+compared))
+{
+result=false;
+break;
+}
+skipCtor||(skipCtor=key=='constructor');
+}
+if(result&&!skipCtor){
+var objCtor=object.constructor,
+othCtor=other.constructor;
+
+
+if(objCtor!=othCtor&&
+'constructor'in object&&'constructor'in other&&
+!(typeof objCtor=='function'&&objCtor instanceof objCtor&&
+typeof othCtor=='function'&&othCtor instanceof othCtor)){
+result=false;
+}
+}
+stack['delete'](object);
+stack['delete'](other);
+return result;
+}
+
+
+
+
+
+
+
+
+function getAllKeys(object){
+return baseGetAllKeys(object,keys,getSymbols);
+}
+
+
+
+
+
+
+
+
+
+function getMapData(map,key){
+var data=map.__data__;
+return isKeyable(key)?
+data[typeof key=='string'?'string':'hash']:
+data.map;
+}
+
+
+
+
+
+
+
+
+
+function getNative(object,key){
+var value=getValue(object,key);
+return baseIsNative(value)?value:undefined;
+}
+
+
+
+
+
+
+
+
+function getRawTag(value){
+var isOwn=hasOwnProperty.call(value,symToStringTag),
+tag=value[symToStringTag];
+
+try{
+value[symToStringTag]=undefined;
+var unmasked=true;
+}catch(e){}
+
+var result=nativeObjectToString.call(value);
+if(unmasked){
+if(isOwn){
+value[symToStringTag]=tag;
+}else{
+delete value[symToStringTag];
+}
+}
+return result;
+}
+
+
+
+
+
+
+
+
+var getSymbols=!nativeGetSymbols?stubArray:function(object){
+if(object==null){
+return[];
+}
+object=Object(object);
+return arrayFilter(nativeGetSymbols(object),function(symbol){
+return propertyIsEnumerable.call(object,symbol);
+});
+};
+
+
+
+
+
+
+
+
+var getTag=baseGetTag;
+
+
+if(DataView&&getTag(new DataView(new ArrayBuffer(1)))!=dataViewTag||
+Map&&getTag(new Map())!=mapTag||
+Promise&&getTag(Promise.resolve())!=promiseTag||
+Set&&getTag(new Set())!=setTag||
+WeakMap&&getTag(new WeakMap())!=weakMapTag){
+getTag=function(value){
+var result=baseGetTag(value),
+Ctor=result==objectTag?value.constructor:undefined,
+ctorString=Ctor?toSource(Ctor):'';
+
+if(ctorString){
+switch(ctorString){
+case dataViewCtorString:return dataViewTag;
+case mapCtorString:return mapTag;
+case promiseCtorString:return promiseTag;
+case setCtorString:return setTag;
+case weakMapCtorString:return weakMapTag;}
+
+}
+return result;
+};
+}
+
+
+
+
+
+
+
+
+
+function isIndex(value,length){
+length=length==null?MAX_SAFE_INTEGER:length;
+return!!length&&(
+typeof value=='number'||reIsUint.test(value))&&
+value>-1&&value%1==0&&value<length;
+}
+
+
+
+
+
+
+
+
+function isKeyable(value){
+var type=typeof value;
+return type=='string'||type=='number'||type=='symbol'||type=='boolean'?
+value!=='__proto__':
+value===null;
+}
+
+
+
+
+
+
+
+
+function isMasked(func){
+return!!maskSrcKey&&maskSrcKey in func;
+}
+
+
+
+
+
+
+
+
+function isPrototype(value){
+var Ctor=value&&value.constructor,
+proto=typeof Ctor=='function'&&Ctor.prototype||objectProto;
+
+return value===proto;
+}
+
+
+
+
+
+
+
+
+function objectToString(value){
+return nativeObjectToString.call(value);
+}
+
+
+
+
+
+
+
+
+function toSource(func){
+if(func!=null){
+try{
+return funcToString.call(func);
+}catch(e){}
+try{
+return func+'';
+}catch(e){}
+}
+return'';
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function eq(value,other){
+return value===other||value!==value&&other!==other;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var isArguments=baseIsArguments(function(){return arguments;}())?baseIsArguments:function(value){
+return isObjectLike(value)&&hasOwnProperty.call(value,'callee')&&
+!propertyIsEnumerable.call(value,'callee');
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var isArray=Array.isArray;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isArrayLike(value){
+return value!=null&&isLength(value.length)&&!isFunction(value);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var isBuffer=nativeIsBuffer||stubFalse;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isEqual(value,other){
+return baseIsEqual(value,other);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isFunction(value){
+if(!isObject(value)){
+return false;
+}
+
+
+var tag=baseGetTag(value);
+return tag==funcTag||tag==genTag||tag==asyncTag||tag==proxyTag;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isLength(value){
+return typeof value=='number'&&
+value>-1&&value%1==0&&value<=MAX_SAFE_INTEGER;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isObject(value){
+var type=typeof value;
+return value!=null&&(type=='object'||type=='function');
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function isObjectLike(value){
+return value!=null&&typeof value=='object';
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var isTypedArray=nodeIsTypedArray?baseUnary(nodeIsTypedArray):baseIsTypedArray;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function keys(object){
+return isArrayLike(object)?arrayLikeKeys(object):baseKeys(object);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function stubArray(){
+return[];
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function stubFalse(){
+return false;
+}
+
+module.exports=isEqual;
+
+}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{}],115:[function(require,module,exports){
+
+
+
+module.exports=function lookupClosestLocale(locale,available){
+if(typeof locale==='string'&&available[locale])return locale;
+var locales=[].concat(locale||[]);
+for(var l=0,ll=locales.length;l<ll;++l){
+var current=locales[l].split('-');
+while(current.length){
+var candidate=current.join('-');
+if(available[candidate])return candidate;
+current.pop();
+}
+}
+};
+
+},{}],116:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports,'__esModule',{value:true});
+
+
+var perf=typeof performance!=='undefined'&&performance;
+
+var now=perf&&perf.now?function(){return perf.now();}:function(){return Date.now();};
+
+function throwIfEmpty(name){
+if(!name){
+throw new Error('name must be non-empty');
+}
+}
+
+
+function insertSorted(arr,item){
+var low=0;
+var high=arr.length;
+var mid;
+while(low<high){
+mid=low+high>>>1;
+if(arr[mid].startTime<item.startTime){
+low=mid+1;
+}else{
+high=mid;
+}
+}
+arr.splice(low,0,item);
+}
+
+if(perf&&perf.mark){
+exports.mark=function(name){
+throwIfEmpty(name);
+perf.mark("start "+name);
+};
+exports.stop=function(name){
+throwIfEmpty(name);
+perf.mark("end "+name);
+perf.measure(name,"start "+name,"end "+name);
+var entries=perf.getEntriesByName(name);
+return entries[entries.length-1];
+};
+exports.getEntries=function(){return perf.getEntriesByType('measure');};
+exports.clear=function(){
+perf.clearMarks();
+perf.clearMeasures();
+};
+}else{
+var marks={};
+var entries=[];
+exports.mark=function(name){
+throwIfEmpty(name);
+var startTime=now();
+marks['$'+name]=startTime;
+};
+exports.stop=function(name){
+throwIfEmpty(name);
+var endTime=now();
+var startTime=marks['$'+name];
+if(!startTime){
+throw new Error("no known mark: "+name);
+}
+var entry={
+startTime:startTime,
+name:name,
+duration:endTime-startTime,
+entryType:'measure'};
+
+
+
+
+insertSorted(entries,entry);
+return entry;
+};
+exports.getEntries=function(){return entries;};
+exports.clear=function(){entries=[];};
+}
+
+},{}],117:[function(require,module,exports){
+exports.getRenderingDataFromViewport=function(viewportProperties,uaDeviceWidth,uaDeviceHeight,uaMaxZoom,uaMinZoom){
+
+var vw=uaDeviceWidth/100;
+var vh=uaDeviceHeight/100;
+
+
+
+var maxZoom=null;
+var minZoom=null;
+var zoom=null;
+var minWidth=null;
+var minHeight=null;
+var maxWidth=null;
+var maxHeight=null;
+var width=null,height=null;
+var initialWidth=uaDeviceWidth;
+var initialHeight=uaDeviceHeight;
+var userZoom="zoom";
+
+if(viewportProperties["maximum-scale"]!==undefined){
+maxZoom=translateZoomProperty(viewportProperties["maximum-scale"]);
+}
+if(viewportProperties["minimum-scale"]!==undefined){
+minZoom=translateZoomProperty(viewportProperties["minimum-scale"]);
+}
+if(viewportProperties["initial-scale"]!==undefined){
+zoom=translateZoomProperty(viewportProperties["initial-scale"]);
+}
+
+
+
+
+
+
+
+if(minZoom!==null&&maxZoom===null){
+minZoom=min(uaMaxZoom,translateZoomProperty(viewportProperties["minimum-scale"]));
+}
+
+if(viewportProperties["width"]!==undefined){
+minWidth="extend-to-zoom";
+maxWidth=translateLengthProperty(viewportProperties["width"],vw,vh);
+}
+
+if(viewportProperties["height"]!==undefined){
+minHeight="extend-to-zoom";
+maxHeight=translateLengthProperty(viewportProperties["height"],vw,vh);
+}
+
+
+if(viewportProperties["user-scalable"]!==undefined){
+userZoom=viewportProperties["user-scalable"];
+if(typeof userZoom==="number"){
+if(userZoom>=1||userZoom<=-1){
+userZoom="zoom";
+}else{
+userZoom="fixed";
+}
+}else{
+switch(userZoom){
+case"yes":
+case"device-width":
+case"device-height":
+userZoom="zoom";
+break;
+case"no":
+default:
+userZoom="fixed";
+break;}
+
+}
+}
+
+
+
+if(zoom!==null&&(
+viewportProperties["width"]===undefined||width===undefined)){
+if(viewportProperties["height"]!==undefined){
+
+minWidth=null;
+maxWidth=null;
+}else{
+
+minWidth="extend-to-zoom";
+maxWidth="extend-to-zoom";
+}
+}
+
+
+
+
+
+
+if(minZoom!==null&&maxZoom!==null){
+maxZoom=max(minZoom,maxZoom);
+}
+
+
+if(zoom!==null){
+zoom=clamp(zoom,minZoom,maxZoom);
+}
+
+
+var extendZoom=zoom===null&&maxZoom===null?null:min(zoom,maxZoom);
+var extendWidth,extendHeight;
+if(extendZoom===null){
+if(maxWidth==="extend-to-zoom"){
+maxWidth=null;
+}
+if(maxHeight==="extend-to-zoom"){
+maxHeight=null;
+}
+if(minWidth==="extend-to-zoom"){
+minWidth=maxWidth;
+}
+if(minHeight==="extend-to-zoom"){
+minHeight=maxHeight;
+}
+}else{
+extendWidth=initialWidth/extendZoom;
+extendHeight=initialHeight/extendZoom;
+
+if(maxWidth==="extend-to-zoom"){
+maxWidth=extendWidth;
+}
+if(maxHeight==="extend-to-zoom"){
+maxHeight=extendHeight;
+}
+if(minWidth==="extend-to-zoom"){
+minWidth=max(extendWidth,maxWidth);
+}
+if(minHeight==="extend-to-zoom"){
+minHeight=max(extendHeight,maxHeight);
+}
+}
+
+
+if(minWidth!==null||maxWidth!==null){
+width=max(minWidth,min(maxWidth,initialWidth));
+}
+if(minHeight!==null||maxHeight!==null){
+height=max(minHeight,min(maxHeight,initialHeight));
+}
+
+
+if(width===null){
+if(height===null){
+width=initialWidth;
+}else{
+if(initialHeight!==0){
+width=Math.round(height*(initialWidth/initialHeight));
+}else{
+width=initialWidth;
+}
+}
+}
+if(height===null){
+if(initialWidth!==0){
+height=Math.round(width*(initialHeight/initialWidth));
+}else{
+height=initialHeight;
+}
+}
+
+return{zoom:zoom,width:width,height:height,userZoom:userZoom};
+};
+
+function min(a,b){
+if(a===null)return b;
+if(b===null)return a;
+return Math.min(a,b);
+}
+
+function max(a,b){
+if(a===null)return b;
+if(b===null)return a;
+return Math.max(a,b);
+}
+
+
+function translateLengthProperty(prop,vw,vh){
+
+if(typeof prop==="number"){
+if(prop>=0){
+
+return clamp(prop,1,10000);
+}else{
+return undefined;
+}
+}
+if(prop==="device-width"){
+return 100*vw;
+}
+if(prop==="device-height"){
+return 100*vh;
+}
+return 1;
+}
+
+function translateZoomProperty(prop){
+
+if(typeof prop==="number"){
+if(prop>=0){
+
+return clamp(prop,0.1,10);
+}else{
+return undefined;
+}
+}
+if(prop==="yes"){
+return 1;
+}
+if(prop==="device-width"||prop==="device-height"){
+return 10;
+}
+if(prop==="no"||prop===null){
+return 0.1;
+}
+}
+
+
+function clamp(value,minv,maxv){
+return max(min(value,maxv),minv);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+exports.parseMetaViewPortContent=function(S){
+var parsedContent={
+validProperties:{},
+unknownProperties:{},
+invalidValues:{}};
+
+var i=1;
+while(i<=S.length){
+while(i<=S.length&&RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])){
+i++;
+}
+if(i<=S.length){
+i=parseProperty(parsedContent,S,i);
+}
+}
+return parsedContent;
+};
+
+var propertyNames=["width","height","initial-scale","minimum-scale","maximum-scale","user-scalable","shrink-to-fit","viewport-fit"];
+
+function parseProperty(parsedContent,S,i){
+var start=i;
+while(i<=S.length&&!RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])){
+i++;
+}
+if(i>S.length||RegExp(',|;').test(S[i-1])){
+return i;
+}
+var propertyName=S.slice(start-1,i-1);
+while(i<=S.length&&!RegExp(',|;|=').test(S[i-1])){
+i++;
+}
+if(i>S.length||RegExp(',|;').test(S[i-1])){
+return i;
+}
+while(i<=S.length&&RegExp(' |\x0A|\x09|\0d|=').test(S[i-1])){
+i++;
+}
+if(i>S.length||RegExp(',|;').test(S[i-1])){
+return i;
+}
+start=i;
+while(i<=S.length&&!RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])){
+i++;
+}
+var propertyValue=S.slice(start-1,i-1);
+setProperty(parsedContent,propertyName,propertyValue);
+return i;
+}
+
+function setProperty(parsedContent,name,value){
+if(propertyNames.indexOf(name)>=0){
+var number=parseFloat(value);
+if(!isNaN(number)){
+parsedContent.validProperties[name]=number;
+return;
+}
+var string=value.toLowerCase();
+
+if(string==="yes"||string==="no"||string==="device-width"||string==="device-height"||
+
+
+name.toLowerCase()==='viewport-fit'&&(string==='auto'||string==='cover')){
+
+parsedContent.validProperties[name]=string;
+return;
+}
+
+parsedContent.validProperties[name]=null;
+parsedContent.invalidValues[name]=value;
+}else{
+parsedContent.unknownProperties[name]=value;
+}
+}
+
+exports.expectedValues={
+"width":["device-width","device-height","a positive number"],
+"height":["device-width","device-height","a positive number"],
+"initial-scale":["a positive number"],
+"minimum-scale":["a positive number"],
+"maximum-scale":["a positive number"],
+"user-scalable":["yes","no","0","1"],
+"shrink-to-fit":["yes","no"],
+"viewport-fit":["auto","cover"]};
+
+
+},{}],118:[function(require,module,exports){
+
+
+
+
+var s=1000;
+var m=s*60;
+var h=m*60;
+var d=h*24;
+var y=d*365.25;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports=function(val,options){
+options=options||{};
+var type=typeof val;
+if(type==='string'&&val.length>0){
+return parse(val);
+}else if(type==='number'&&isNaN(val)===false){
+return options.long?fmtLong(val):fmtShort(val);
+}
+throw new Error(
+'val is not a non-empty string or a valid number. val='+
+JSON.stringify(val));
+
+};
+
+
+
+
+
+
+
+
+
+function parse(str){
+str=String(str);
+if(str.length>100){
+return;
+}
+var match=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
+str);
+
+if(!match){
+return;
+}
+var n=parseFloat(match[1]);
+var type=(match[2]||'ms').toLowerCase();
+switch(type){
+case'years':
+case'year':
+case'yrs':
+case'yr':
+case'y':
+return n*y;
+case'days':
+case'day':
+case'd':
+return n*d;
+case'hours':
+case'hour':
+case'hrs':
+case'hr':
+case'h':
+return n*h;
+case'minutes':
+case'minute':
+case'mins':
+case'min':
+case'm':
+return n*m;
+case'seconds':
+case'second':
+case'secs':
+case'sec':
+case's':
+return n*s;
+case'milliseconds':
+case'millisecond':
+case'msecs':
+case'msec':
+case'ms':
+return n;
+default:
+return undefined;}
+
+}
+
+
+
+
+
+
+
+
+
+function fmtShort(ms){
+if(ms>=d){
+return Math.round(ms/d)+'d';
+}
+if(ms>=h){
+return Math.round(ms/h)+'h';
+}
+if(ms>=m){
+return Math.round(ms/m)+'m';
+}
+if(ms>=s){
+return Math.round(ms/s)+'s';
+}
+return ms+'ms';
+}
+
+
+
+
+
+
+
+
+
+function fmtLong(ms){
+return plural(ms,d,'day')||
+plural(ms,h,'hour')||
+plural(ms,m,'minute')||
+plural(ms,s,'second')||
+ms+' ms';
+}
+
+
+
+
+
+function plural(ms,n,name){
+if(ms<n){
+return;
+}
+if(ms<n*1.5){
+return Math.floor(ms/n)+' '+name;
+}
+return Math.ceil(ms/n)+' '+name+'s';
+}
+
+},{}],119:[function(require,module,exports){
+'use strict';
+
+
+var TYPED_OK=typeof Uint8Array!=='undefined'&&
+typeof Uint16Array!=='undefined'&&
+typeof Int32Array!=='undefined';
+
+function _has(obj,key){
+return Object.prototype.hasOwnProperty.call(obj,key);
+}
+
+exports.assign=function(obj){
+var sources=Array.prototype.slice.call(arguments,1);
+while(sources.length){
+var source=sources.shift();
+if(!source){continue;}
+
+if(typeof source!=='object'){
+throw new TypeError(source+'must be non-object');
+}
+
+for(var p in source){
+if(_has(source,p)){
+obj[p]=source[p];
+}
+}
+}
+
+return obj;
+};
+
+
+
+exports.shrinkBuf=function(buf,size){
+if(buf.length===size){return buf;}
+if(buf.subarray){return buf.subarray(0,size);}
+buf.length=size;
+return buf;
+};
+
+
+var fnTyped={
+arraySet:function(dest,src,src_offs,len,dest_offs){
+if(src.subarray&&dest.subarray){
+dest.set(src.subarray(src_offs,src_offs+len),dest_offs);
+return;
+}
+
+for(var i=0;i<len;i++){
+dest[dest_offs+i]=src[src_offs+i];
+}
+},
+
+flattenChunks:function(chunks){
+var i,l,len,pos,chunk,result;
+
+
+len=0;
+for(i=0,l=chunks.length;i<l;i++){
+len+=chunks[i].length;
+}
+
+
+result=new Uint8Array(len);
+pos=0;
+for(i=0,l=chunks.length;i<l;i++){
+chunk=chunks[i];
+result.set(chunk,pos);
+pos+=chunk.length;
+}
+
+return result;
+}};
+
+
+var fnUntyped={
+arraySet:function(dest,src,src_offs,len,dest_offs){
+for(var i=0;i<len;i++){
+dest[dest_offs+i]=src[src_offs+i];
+}
+},
+
+flattenChunks:function(chunks){
+return[].concat.apply([],chunks);
+}};
+
+
+
+
+
+exports.setTyped=function(on){
+if(on){
+exports.Buf8=Uint8Array;
+exports.Buf16=Uint16Array;
+exports.Buf32=Int32Array;
+exports.assign(exports,fnTyped);
+}else{
+exports.Buf8=Array;
+exports.Buf16=Array;
+exports.Buf32=Array;
+exports.assign(exports,fnUntyped);
+}
+};
+
+exports.setTyped(TYPED_OK);
+
+},{}],120:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function adler32(adler,buf,len,pos){
+var s1=adler&0xffff|0,
+s2=adler>>>16&0xffff|0,
+n=0;
+
+while(len!==0){
+
+
+
+n=len>2000?2000:len;
+len-=n;
+
+do{
+s1=s1+buf[pos++]|0;
+s2=s2+s1|0;
+}while(--n);
+
+s1%=65521;
+s2%=65521;
+}
+
+return s1|s2<<16|0;
+}
+
+
+module.exports=adler32;
+
+},{}],121:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports={
+
+
+Z_NO_FLUSH:0,
+Z_PARTIAL_FLUSH:1,
+Z_SYNC_FLUSH:2,
+Z_FULL_FLUSH:3,
+Z_FINISH:4,
+Z_BLOCK:5,
+Z_TREES:6,
+
+
+
+
+Z_OK:0,
+Z_STREAM_END:1,
+Z_NEED_DICT:2,
+Z_ERRNO:-1,
+Z_STREAM_ERROR:-2,
+Z_DATA_ERROR:-3,
+
+Z_BUF_ERROR:-5,
+
+
+
+Z_NO_COMPRESSION:0,
+Z_BEST_SPEED:1,
+Z_BEST_COMPRESSION:9,
+Z_DEFAULT_COMPRESSION:-1,
+
+
+Z_FILTERED:1,
+Z_HUFFMAN_ONLY:2,
+Z_RLE:3,
+Z_FIXED:4,
+Z_DEFAULT_STRATEGY:0,
+
+
+Z_BINARY:0,
+Z_TEXT:1,
+
+Z_UNKNOWN:2,
+
+
+Z_DEFLATED:8};
+
+
+
+},{}],122:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function makeTable(){
+var c,table=[];
+
+for(var n=0;n<256;n++){
+c=n;
+for(var k=0;k<8;k++){
+c=c&1?0xEDB88320^c>>>1:c>>>1;
+}
+table[n]=c;
+}
+
+return table;
+}
+
+
+var crcTable=makeTable();
+
+
+function crc32(crc,buf,len,pos){
+var t=crcTable,
+end=pos+len;
+
+crc^=-1;
+
+for(var i=pos;i<end;i++){
+crc=crc>>>8^t[(crc^buf[i])&0xFF];
+}
+
+return crc^-1;
+}
+
+
+module.exports=crc32;
+
+},{}],123:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var utils=require('../utils/common');
+var trees=require('./trees');
+var adler32=require('./adler32');
+var crc32=require('./crc32');
+var msg=require('./messages');
+
+
+
+
+
+
+var Z_NO_FLUSH=0;
+var Z_PARTIAL_FLUSH=1;
+
+var Z_FULL_FLUSH=3;
+var Z_FINISH=4;
+var Z_BLOCK=5;
+
+
+
+
+
+
+var Z_OK=0;
+var Z_STREAM_END=1;
+
+
+var Z_STREAM_ERROR=-2;
+var Z_DATA_ERROR=-3;
+
+var Z_BUF_ERROR=-5;
+
+
+
+
+
+
+
+var Z_DEFAULT_COMPRESSION=-1;
+
+
+var Z_FILTERED=1;
+var Z_HUFFMAN_ONLY=2;
+var Z_RLE=3;
+var Z_FIXED=4;
+var Z_DEFAULT_STRATEGY=0;
+
+
+
+
+
+var Z_UNKNOWN=2;
+
+
+
+var Z_DEFLATED=8;
+
+
+
+
+var MAX_MEM_LEVEL=9;
+
+var MAX_WBITS=15;
+
+var DEF_MEM_LEVEL=8;
+
+
+var LENGTH_CODES=29;
+
+var LITERALS=256;
+
+var L_CODES=LITERALS+1+LENGTH_CODES;
+
+var D_CODES=30;
+
+var BL_CODES=19;
+
+var HEAP_SIZE=2*L_CODES+1;
+
+var MAX_BITS=15;
+
+
+var MIN_MATCH=3;
+var MAX_MATCH=258;
+var MIN_LOOKAHEAD=MAX_MATCH+MIN_MATCH+1;
+
+var PRESET_DICT=0x20;
+
+var INIT_STATE=42;
+var EXTRA_STATE=69;
+var NAME_STATE=73;
+var COMMENT_STATE=91;
+var HCRC_STATE=103;
+var BUSY_STATE=113;
+var FINISH_STATE=666;
+
+var BS_NEED_MORE=1;
+var BS_BLOCK_DONE=2;
+var BS_FINISH_STARTED=3;
+var BS_FINISH_DONE=4;
+
+var OS_CODE=0x03;
+
+function err(strm,errorCode){
+strm.msg=msg[errorCode];
+return errorCode;
+}
+
+function rank(f){
+return(f<<1)-(f>4?9:0);
+}
+
+function zero(buf){var len=buf.length;while(--len>=0){buf[len]=0;}}
+
+
+
+
+
+
+
+
+function flush_pending(strm){
+var s=strm.state;
+
+
+var len=s.pending;
+if(len>strm.avail_out){
+len=strm.avail_out;
+}
+if(len===0){return;}
+
+utils.arraySet(strm.output,s.pending_buf,s.pending_out,len,strm.next_out);
+strm.next_out+=len;
+s.pending_out+=len;
+strm.total_out+=len;
+strm.avail_out-=len;
+s.pending-=len;
+if(s.pending===0){
+s.pending_out=0;
+}
+}
+
+
+function flush_block_only(s,last){
+trees._tr_flush_block(s,s.block_start>=0?s.block_start:-1,s.strstart-s.block_start,last);
+s.block_start=s.strstart;
+flush_pending(s.strm);
+}
+
+
+function put_byte(s,b){
+s.pending_buf[s.pending++]=b;
+}
+
+
+
+
+
+
+
+function putShortMSB(s,b){
+
+
+s.pending_buf[s.pending++]=b>>>8&0xff;
+s.pending_buf[s.pending++]=b&0xff;
+}
+
+
+
+
+
+
+
+
+
+function read_buf(strm,buf,start,size){
+var len=strm.avail_in;
+
+if(len>size){len=size;}
+if(len===0){return 0;}
+
+strm.avail_in-=len;
+
+
+utils.arraySet(buf,strm.input,strm.next_in,len,start);
+if(strm.state.wrap===1){
+strm.adler=adler32(strm.adler,buf,len,start);
+}else
+
+if(strm.state.wrap===2){
+strm.adler=crc32(strm.adler,buf,len,start);
+}
+
+strm.next_in+=len;
+strm.total_in+=len;
+
+return len;
+}
+
+
+
+
+
+
+
+
+
+
+
+function longest_match(s,cur_match){
+var chain_length=s.max_chain_length;
+var scan=s.strstart;
+var match;
+var len;
+var best_len=s.prev_length;
+var nice_match=s.nice_match;
+var limit=s.strstart>s.w_size-MIN_LOOKAHEAD?
+s.strstart-(s.w_size-MIN_LOOKAHEAD):0;
+
+var _win=s.window;
+
+var wmask=s.w_mask;
+var prev=s.prev;
+
+
+
+
+
+var strend=s.strstart+MAX_MATCH;
+var scan_end1=_win[scan+best_len-1];
+var scan_end=_win[scan+best_len];
+
+
+
+
+
+
+
+if(s.prev_length>=s.good_match){
+chain_length>>=2;
+}
+
+
+
+if(nice_match>s.lookahead){nice_match=s.lookahead;}
+
+
+
+do{
+
+match=cur_match;
+
+
+
+
+
+
+
+
+
+
+if(_win[match+best_len]!==scan_end||
+_win[match+best_len-1]!==scan_end1||
+_win[match]!==_win[scan]||
+_win[++match]!==_win[scan+1]){
+continue;
+}
+
+
+
+
+
+
+
+scan+=2;
+match++;
+
+
+
+
+
+do{
+
+}while(_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
+_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
+_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
+_win[++scan]===_win[++match]&&_win[++scan]===_win[++match]&&
+scan<strend);
+
+
+
+len=MAX_MATCH-(strend-scan);
+scan=strend-MAX_MATCH;
+
+if(len>best_len){
+s.match_start=cur_match;
+best_len=len;
+if(len>=nice_match){
+break;
+}
+scan_end1=_win[scan+best_len-1];
+scan_end=_win[scan+best_len];
+}
+}while((cur_match=prev[cur_match&wmask])>limit&&--chain_length!==0);
+
+if(best_len<=s.lookahead){
+return best_len;
+}
+return s.lookahead;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+function fill_window(s){
+var _w_size=s.w_size;
+var p,n,m,more,str;
+
+
+
+do{
+more=s.window_size-s.lookahead-s.strstart;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if(s.strstart>=_w_size+(_w_size-MIN_LOOKAHEAD)){
+
+utils.arraySet(s.window,s.window,_w_size,_w_size,0);
+s.match_start-=_w_size;
+s.strstart-=_w_size;
+
+s.block_start-=_w_size;
+
+
+
+
+
+
+
+
+n=s.hash_size;
+p=n;
+do{
+m=s.head[--p];
+s.head[p]=m>=_w_size?m-_w_size:0;
+}while(--n);
+
+n=_w_size;
+p=n;
+do{
+m=s.prev[--p];
+s.prev[p]=m>=_w_size?m-_w_size:0;
+
+
+
+}while(--n);
+
+more+=_w_size;
+}
+if(s.strm.avail_in===0){
+break;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+n=read_buf(s.strm,s.window,s.strstart+s.lookahead,more);
+s.lookahead+=n;
+
+
+if(s.lookahead+s.insert>=MIN_MATCH){
+str=s.strstart-s.insert;
+s.ins_h=s.window[str];
+
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[str+1])&s.hash_mask;
+
+
+
+while(s.insert){
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[str+MIN_MATCH-1])&s.hash_mask;
+
+s.prev[str&s.w_mask]=s.head[s.ins_h];
+s.head[s.ins_h]=str;
+str++;
+s.insert--;
+if(s.lookahead+s.insert<MIN_MATCH){
+break;
+}
+}
+}
+
+
+
+
+}while(s.lookahead<MIN_LOOKAHEAD&&s.strm.avail_in!==0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+
+
+
+
+
+
+
+
+
+function deflate_stored(s,flush){
+
+
+
+var max_block_size=0xffff;
+
+if(max_block_size>s.pending_buf_size-5){
+max_block_size=s.pending_buf_size-5;
+}
+
+
+for(;;){
+
+if(s.lookahead<=1){
+
+
+
+
+
+
+
+
+fill_window(s);
+if(s.lookahead===0&&flush===Z_NO_FLUSH){
+return BS_NEED_MORE;
+}
+
+if(s.lookahead===0){
+break;
+}
+
+}
+
+
+
+s.strstart+=s.lookahead;
+s.lookahead=0;
+
+
+var max_start=s.block_start+max_block_size;
+
+if(s.strstart===0||s.strstart>=max_start){
+
+s.lookahead=s.strstart-max_start;
+s.strstart=max_start;
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+
+
+}
+
+
+
+if(s.strstart-s.block_start>=s.w_size-MIN_LOOKAHEAD){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+}
+
+s.insert=0;
+
+if(flush===Z_FINISH){
+
+flush_block_only(s,true);
+if(s.strm.avail_out===0){
+return BS_FINISH_STARTED;
+}
+
+return BS_FINISH_DONE;
+}
+
+if(s.strstart>s.block_start){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+
+return BS_NEED_MORE;
+}
+
+
+
+
+
+
+
+
+function deflate_fast(s,flush){
+var hash_head;
+var bflush;
+
+for(;;){
+
+
+
+
+
+if(s.lookahead<MIN_LOOKAHEAD){
+fill_window(s);
+if(s.lookahead<MIN_LOOKAHEAD&&flush===Z_NO_FLUSH){
+return BS_NEED_MORE;
+}
+if(s.lookahead===0){
+break;
+}
+}
+
+
+
+
+hash_head=0;
+if(s.lookahead>=MIN_MATCH){
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
+hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
+s.head[s.ins_h]=s.strstart;
+
+}
+
+
+
+
+if(hash_head!==0&&s.strstart-hash_head<=s.w_size-MIN_LOOKAHEAD){
+
+
+
+
+s.match_length=longest_match(s,hash_head);
+
+}
+if(s.match_length>=MIN_MATCH){
+
+
+
+
+bflush=trees._tr_tally(s,s.strstart-s.match_start,s.match_length-MIN_MATCH);
+
+s.lookahead-=s.match_length;
+
+
+
+
+if(s.match_length<=s.max_lazy_match&&s.lookahead>=MIN_MATCH){
+s.match_length--;
+do{
+s.strstart++;
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
+hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
+s.head[s.ins_h]=s.strstart;
+
+
+
+
+}while(--s.match_length!==0);
+s.strstart++;
+}else
+{
+s.strstart+=s.match_length;
+s.match_length=0;
+s.ins_h=s.window[s.strstart];
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+1])&s.hash_mask;
+
+
+
+
+
+
+
+}
+}else{
+
+
+
+bflush=trees._tr_tally(s,0,s.window[s.strstart]);
+
+s.lookahead--;
+s.strstart++;
+}
+if(bflush){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+}
+s.insert=s.strstart<MIN_MATCH-1?s.strstart:MIN_MATCH-1;
+if(flush===Z_FINISH){
+
+flush_block_only(s,true);
+if(s.strm.avail_out===0){
+return BS_FINISH_STARTED;
+}
+
+return BS_FINISH_DONE;
+}
+if(s.last_lit){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+return BS_BLOCK_DONE;
+}
+
+
+
+
+
+
+function deflate_slow(s,flush){
+var hash_head;
+var bflush;
+
+var max_insert;
+
+
+for(;;){
+
+
+
+
+
+if(s.lookahead<MIN_LOOKAHEAD){
+fill_window(s);
+if(s.lookahead<MIN_LOOKAHEAD&&flush===Z_NO_FLUSH){
+return BS_NEED_MORE;
+}
+if(s.lookahead===0){break;}
+}
+
+
+
+
+hash_head=0;
+if(s.lookahead>=MIN_MATCH){
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
+hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
+s.head[s.ins_h]=s.strstart;
+
+}
+
+
+
+s.prev_length=s.match_length;
+s.prev_match=s.match_start;
+s.match_length=MIN_MATCH-1;
+
+if(hash_head!==0&&s.prev_length<s.max_lazy_match&&
+s.strstart-hash_head<=s.w_size-MIN_LOOKAHEAD){
+
+
+
+
+s.match_length=longest_match(s,hash_head);
+
+
+if(s.match_length<=5&&(
+s.strategy===Z_FILTERED||s.match_length===MIN_MATCH&&s.strstart-s.match_start>4096)){
+
+
+
+
+s.match_length=MIN_MATCH-1;
+}
+}
+
+
+
+if(s.prev_length>=MIN_MATCH&&s.match_length<=s.prev_length){
+max_insert=s.strstart+s.lookahead-MIN_MATCH;
+
+
+
+
+
+
+bflush=trees._tr_tally(s,s.strstart-1-s.prev_match,s.prev_length-MIN_MATCH);
+
+
+
+
+
+s.lookahead-=s.prev_length-1;
+s.prev_length-=2;
+do{
+if(++s.strstart<=max_insert){
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[s.strstart+MIN_MATCH-1])&s.hash_mask;
+hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h];
+s.head[s.ins_h]=s.strstart;
+
+}
+}while(--s.prev_length!==0);
+s.match_available=0;
+s.match_length=MIN_MATCH-1;
+s.strstart++;
+
+if(bflush){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+
+}else if(s.match_available){
+
+
+
+
+
+
+bflush=trees._tr_tally(s,0,s.window[s.strstart-1]);
+
+if(bflush){
+
+flush_block_only(s,false);
+
+}
+s.strstart++;
+s.lookahead--;
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+}else{
+
+
+
+s.match_available=1;
+s.strstart++;
+s.lookahead--;
+}
+}
+
+if(s.match_available){
+
+
+bflush=trees._tr_tally(s,0,s.window[s.strstart-1]);
+
+s.match_available=0;
+}
+s.insert=s.strstart<MIN_MATCH-1?s.strstart:MIN_MATCH-1;
+if(flush===Z_FINISH){
+
+flush_block_only(s,true);
+if(s.strm.avail_out===0){
+return BS_FINISH_STARTED;
+}
+
+return BS_FINISH_DONE;
+}
+if(s.last_lit){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+
+return BS_BLOCK_DONE;
+}
+
+
+
+
+
+
+
+function deflate_rle(s,flush){
+var bflush;
+var prev;
+var scan,strend;
+
+var _win=s.window;
+
+for(;;){
+
+
+
+
+if(s.lookahead<=MAX_MATCH){
+fill_window(s);
+if(s.lookahead<=MAX_MATCH&&flush===Z_NO_FLUSH){
+return BS_NEED_MORE;
+}
+if(s.lookahead===0){break;}
+}
+
+
+s.match_length=0;
+if(s.lookahead>=MIN_MATCH&&s.strstart>0){
+scan=s.strstart-1;
+prev=_win[scan];
+if(prev===_win[++scan]&&prev===_win[++scan]&&prev===_win[++scan]){
+strend=s.strstart+MAX_MATCH;
+do{
+
+}while(prev===_win[++scan]&&prev===_win[++scan]&&
+prev===_win[++scan]&&prev===_win[++scan]&&
+prev===_win[++scan]&&prev===_win[++scan]&&
+prev===_win[++scan]&&prev===_win[++scan]&&
+scan<strend);
+s.match_length=MAX_MATCH-(strend-scan);
+if(s.match_length>s.lookahead){
+s.match_length=s.lookahead;
+}
+}
+
+}
+
+
+if(s.match_length>=MIN_MATCH){
+
+
+
+bflush=trees._tr_tally(s,1,s.match_length-MIN_MATCH);
+
+s.lookahead-=s.match_length;
+s.strstart+=s.match_length;
+s.match_length=0;
+}else{
+
+
+
+bflush=trees._tr_tally(s,0,s.window[s.strstart]);
+
+s.lookahead--;
+s.strstart++;
+}
+if(bflush){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+}
+s.insert=0;
+if(flush===Z_FINISH){
+
+flush_block_only(s,true);
+if(s.strm.avail_out===0){
+return BS_FINISH_STARTED;
+}
+
+return BS_FINISH_DONE;
+}
+if(s.last_lit){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+return BS_BLOCK_DONE;
+}
+
+
+
+
+
+function deflate_huff(s,flush){
+var bflush;
+
+for(;;){
+
+if(s.lookahead===0){
+fill_window(s);
+if(s.lookahead===0){
+if(flush===Z_NO_FLUSH){
+return BS_NEED_MORE;
+}
+break;
+}
+}
+
+
+s.match_length=0;
+
+
+bflush=trees._tr_tally(s,0,s.window[s.strstart]);
+s.lookahead--;
+s.strstart++;
+if(bflush){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+}
+s.insert=0;
+if(flush===Z_FINISH){
+
+flush_block_only(s,true);
+if(s.strm.avail_out===0){
+return BS_FINISH_STARTED;
+}
+
+return BS_FINISH_DONE;
+}
+if(s.last_lit){
+
+flush_block_only(s,false);
+if(s.strm.avail_out===0){
+return BS_NEED_MORE;
+}
+
+}
+return BS_BLOCK_DONE;
+}
+
+
+
+
+
+
+function Config(good_length,max_lazy,nice_length,max_chain,func){
+this.good_length=good_length;
+this.max_lazy=max_lazy;
+this.nice_length=nice_length;
+this.max_chain=max_chain;
+this.func=func;
+}
+
+var configuration_table;
+
+configuration_table=[
+
+new Config(0,0,0,0,deflate_stored),
+new Config(4,4,8,4,deflate_fast),
+new Config(4,5,16,8,deflate_fast),
+new Config(4,6,32,32,deflate_fast),
+
+new Config(4,4,16,16,deflate_slow),
+new Config(8,16,32,32,deflate_slow),
+new Config(8,16,128,128,deflate_slow),
+new Config(8,32,128,256,deflate_slow),
+new Config(32,128,258,1024,deflate_slow),
+new Config(32,258,258,4096,deflate_slow)];
+
+
+
+
+
+
+function lm_init(s){
+s.window_size=2*s.w_size;
+
+
+zero(s.head);
+
+
+
+s.max_lazy_match=configuration_table[s.level].max_lazy;
+s.good_match=configuration_table[s.level].good_length;
+s.nice_match=configuration_table[s.level].nice_length;
+s.max_chain_length=configuration_table[s.level].max_chain;
+
+s.strstart=0;
+s.block_start=0;
+s.lookahead=0;
+s.insert=0;
+s.match_length=s.prev_length=MIN_MATCH-1;
+s.match_available=0;
+s.ins_h=0;
+}
+
+
+function DeflateState(){
+this.strm=null;
+this.status=0;
+this.pending_buf=null;
+this.pending_buf_size=0;
+this.pending_out=0;
+this.pending=0;
+this.wrap=0;
+this.gzhead=null;
+this.gzindex=0;
+this.method=Z_DEFLATED;
+this.last_flush=-1;
+
+this.w_size=0;
+this.w_bits=0;
+this.w_mask=0;
+
+this.window=null;
+
+
+
+
+
+
+
+this.window_size=0;
+
+
+
+
+this.prev=null;
+
+
+
+
+
+this.head=null;
+
+this.ins_h=0;
+this.hash_size=0;
+this.hash_bits=0;
+this.hash_mask=0;
+
+this.hash_shift=0;
+
+
+
+
+
+
+this.block_start=0;
+
+
+
+
+this.match_length=0;
+this.prev_match=0;
+this.match_available=0;
+this.strstart=0;
+this.match_start=0;
+this.lookahead=0;
+
+this.prev_length=0;
+
+
+
+
+this.max_chain_length=0;
+
+
+
+
+
+this.max_lazy_match=0;
+
+
+
+
+
+
+
+
+
+
+
+this.level=0;
+this.strategy=0;
+
+this.good_match=0;
+
+
+this.nice_match=0;
+
+
+
+
+
+
+
+
+
+
+
+this.dyn_ltree=new utils.Buf16(HEAP_SIZE*2);
+this.dyn_dtree=new utils.Buf16((2*D_CODES+1)*2);
+this.bl_tree=new utils.Buf16((2*BL_CODES+1)*2);
+zero(this.dyn_ltree);
+zero(this.dyn_dtree);
+zero(this.bl_tree);
+
+this.l_desc=null;
+this.d_desc=null;
+this.bl_desc=null;
+
+
+this.bl_count=new utils.Buf16(MAX_BITS+1);
+
+
+
+this.heap=new utils.Buf16(2*L_CODES+1);
+zero(this.heap);
+
+this.heap_len=0;
+this.heap_max=0;
+
+
+
+
+this.depth=new utils.Buf16(2*L_CODES+1);
+zero(this.depth);
+
+
+
+this.l_buf=0;
+
+this.lit_bufsize=0;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+this.last_lit=0;
+
+this.d_buf=0;
+
+
+
+
+
+this.opt_len=0;
+this.static_len=0;
+this.matches=0;
+this.insert=0;
+
+
+this.bi_buf=0;
+
+
+
+this.bi_valid=0;
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+
+function deflateResetKeep(strm){
+var s;
+
+if(!strm||!strm.state){
+return err(strm,Z_STREAM_ERROR);
+}
+
+strm.total_in=strm.total_out=0;
+strm.data_type=Z_UNKNOWN;
+
+s=strm.state;
+s.pending=0;
+s.pending_out=0;
+
+if(s.wrap<0){
+s.wrap=-s.wrap;
+
+}
+s.status=s.wrap?INIT_STATE:BUSY_STATE;
+strm.adler=s.wrap===2?
+0:
+
+1;
+s.last_flush=Z_NO_FLUSH;
+trees._tr_init(s);
+return Z_OK;
+}
+
+
+function deflateReset(strm){
+var ret=deflateResetKeep(strm);
+if(ret===Z_OK){
+lm_init(strm.state);
+}
+return ret;
+}
+
+
+function deflateSetHeader(strm,head){
+if(!strm||!strm.state){return Z_STREAM_ERROR;}
+if(strm.state.wrap!==2){return Z_STREAM_ERROR;}
+strm.state.gzhead=head;
+return Z_OK;
+}
+
+
+function deflateInit2(strm,level,method,windowBits,memLevel,strategy){
+if(!strm){
+return Z_STREAM_ERROR;
+}
+var wrap=1;
+
+if(level===Z_DEFAULT_COMPRESSION){
+level=6;
+}
+
+if(windowBits<0){
+wrap=0;
+windowBits=-windowBits;
+}else
+
+if(windowBits>15){
+wrap=2;
+windowBits-=16;
+}
+
+
+if(memLevel<1||memLevel>MAX_MEM_LEVEL||method!==Z_DEFLATED||
+windowBits<8||windowBits>15||level<0||level>9||
+strategy<0||strategy>Z_FIXED){
+return err(strm,Z_STREAM_ERROR);
+}
+
+
+if(windowBits===8){
+windowBits=9;
+}
+
+
+var s=new DeflateState();
+
+strm.state=s;
+s.strm=strm;
+
+s.wrap=wrap;
+s.gzhead=null;
+s.w_bits=windowBits;
+s.w_size=1<<s.w_bits;
+s.w_mask=s.w_size-1;
+
+s.hash_bits=memLevel+7;
+s.hash_size=1<<s.hash_bits;
+s.hash_mask=s.hash_size-1;
+s.hash_shift=~~((s.hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+s.window=new utils.Buf8(s.w_size*2);
+s.head=new utils.Buf16(s.hash_size);
+s.prev=new utils.Buf16(s.w_size);
+
+
+
+
+s.lit_bufsize=1<<memLevel+6;
+
+s.pending_buf_size=s.lit_bufsize*4;
+
+
+
+s.pending_buf=new utils.Buf8(s.pending_buf_size);
+
+
+
+s.d_buf=1*s.lit_bufsize;
+
+
+s.l_buf=(1+2)*s.lit_bufsize;
+
+s.level=level;
+s.strategy=strategy;
+s.method=method;
+
+return deflateReset(strm);
+}
+
+function deflateInit(strm,level){
+return deflateInit2(strm,level,Z_DEFLATED,MAX_WBITS,DEF_MEM_LEVEL,Z_DEFAULT_STRATEGY);
+}
+
+
+function deflate(strm,flush){
+var old_flush,s;
+var beg,val;
+
+if(!strm||!strm.state||
+flush>Z_BLOCK||flush<0){
+return strm?err(strm,Z_STREAM_ERROR):Z_STREAM_ERROR;
+}
+
+s=strm.state;
+
+if(!strm.output||
+!strm.input&&strm.avail_in!==0||
+s.status===FINISH_STATE&&flush!==Z_FINISH){
+return err(strm,strm.avail_out===0?Z_BUF_ERROR:Z_STREAM_ERROR);
+}
+
+s.strm=strm;
+old_flush=s.last_flush;
+s.last_flush=flush;
+
+
+if(s.status===INIT_STATE){
+
+if(s.wrap===2){
+strm.adler=0;
+put_byte(s,31);
+put_byte(s,139);
+put_byte(s,8);
+if(!s.gzhead){
+put_byte(s,0);
+put_byte(s,0);
+put_byte(s,0);
+put_byte(s,0);
+put_byte(s,0);
+put_byte(s,s.level===9?2:
+s.strategy>=Z_HUFFMAN_ONLY||s.level<2?
+4:0);
+put_byte(s,OS_CODE);
+s.status=BUSY_STATE;
+}else
+{
+put_byte(s,(s.gzhead.text?1:0)+(
+s.gzhead.hcrc?2:0)+(
+!s.gzhead.extra?0:4)+(
+!s.gzhead.name?0:8)+(
+!s.gzhead.comment?0:16));
+
+put_byte(s,s.gzhead.time&0xff);
+put_byte(s,s.gzhead.time>>8&0xff);
+put_byte(s,s.gzhead.time>>16&0xff);
+put_byte(s,s.gzhead.time>>24&0xff);
+put_byte(s,s.level===9?2:
+s.strategy>=Z_HUFFMAN_ONLY||s.level<2?
+4:0);
+put_byte(s,s.gzhead.os&0xff);
+if(s.gzhead.extra&&s.gzhead.extra.length){
+put_byte(s,s.gzhead.extra.length&0xff);
+put_byte(s,s.gzhead.extra.length>>8&0xff);
+}
+if(s.gzhead.hcrc){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending,0);
+}
+s.gzindex=0;
+s.status=EXTRA_STATE;
+}
+}else
+
+{
+var header=Z_DEFLATED+(s.w_bits-8<<4)<<8;
+var level_flags=-1;
+
+if(s.strategy>=Z_HUFFMAN_ONLY||s.level<2){
+level_flags=0;
+}else if(s.level<6){
+level_flags=1;
+}else if(s.level===6){
+level_flags=2;
+}else{
+level_flags=3;
+}
+header|=level_flags<<6;
+if(s.strstart!==0){header|=PRESET_DICT;}
+header+=31-header%31;
+
+s.status=BUSY_STATE;
+putShortMSB(s,header);
+
+
+if(s.strstart!==0){
+putShortMSB(s,strm.adler>>>16);
+putShortMSB(s,strm.adler&0xffff);
+}
+strm.adler=1;
+}
+}
+
+
+if(s.status===EXTRA_STATE){
+if(s.gzhead.extra){
+beg=s.pending;
+
+while(s.gzindex<(s.gzhead.extra.length&0xffff)){
+if(s.pending===s.pending_buf_size){
+if(s.gzhead.hcrc&&s.pending>beg){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
+}
+flush_pending(strm);
+beg=s.pending;
+if(s.pending===s.pending_buf_size){
+break;
+}
+}
+put_byte(s,s.gzhead.extra[s.gzindex]&0xff);
+s.gzindex++;
+}
+if(s.gzhead.hcrc&&s.pending>beg){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
+}
+if(s.gzindex===s.gzhead.extra.length){
+s.gzindex=0;
+s.status=NAME_STATE;
+}
+}else
+{
+s.status=NAME_STATE;
+}
+}
+if(s.status===NAME_STATE){
+if(s.gzhead.name){
+beg=s.pending;
+
+
+do{
+if(s.pending===s.pending_buf_size){
+if(s.gzhead.hcrc&&s.pending>beg){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
+}
+flush_pending(strm);
+beg=s.pending;
+if(s.pending===s.pending_buf_size){
+val=1;
+break;
+}
+}
+
+if(s.gzindex<s.gzhead.name.length){
+val=s.gzhead.name.charCodeAt(s.gzindex++)&0xff;
+}else{
+val=0;
+}
+put_byte(s,val);
+}while(val!==0);
+
+if(s.gzhead.hcrc&&s.pending>beg){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
+}
+if(val===0){
+s.gzindex=0;
+s.status=COMMENT_STATE;
+}
+}else
+{
+s.status=COMMENT_STATE;
+}
+}
+if(s.status===COMMENT_STATE){
+if(s.gzhead.comment){
+beg=s.pending;
+
+
+do{
+if(s.pending===s.pending_buf_size){
+if(s.gzhead.hcrc&&s.pending>beg){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
+}
+flush_pending(strm);
+beg=s.pending;
+if(s.pending===s.pending_buf_size){
+val=1;
+break;
+}
+}
+
+if(s.gzindex<s.gzhead.comment.length){
+val=s.gzhead.comment.charCodeAt(s.gzindex++)&0xff;
+}else{
+val=0;
+}
+put_byte(s,val);
+}while(val!==0);
+
+if(s.gzhead.hcrc&&s.pending>beg){
+strm.adler=crc32(strm.adler,s.pending_buf,s.pending-beg,beg);
+}
+if(val===0){
+s.status=HCRC_STATE;
+}
+}else
+{
+s.status=HCRC_STATE;
+}
+}
+if(s.status===HCRC_STATE){
+if(s.gzhead.hcrc){
+if(s.pending+2>s.pending_buf_size){
+flush_pending(strm);
+}
+if(s.pending+2<=s.pending_buf_size){
+put_byte(s,strm.adler&0xff);
+put_byte(s,strm.adler>>8&0xff);
+strm.adler=0;
+s.status=BUSY_STATE;
+}
+}else
+{
+s.status=BUSY_STATE;
+}
+}
+
+
+
+if(s.pending!==0){
+flush_pending(strm);
+if(strm.avail_out===0){
+
+
+
+
+
+
+s.last_flush=-1;
+return Z_OK;
+}
+
+
+
+
+
+}else if(strm.avail_in===0&&rank(flush)<=rank(old_flush)&&
+flush!==Z_FINISH){
+return err(strm,Z_BUF_ERROR);
+}
+
+
+if(s.status===FINISH_STATE&&strm.avail_in!==0){
+return err(strm,Z_BUF_ERROR);
+}
+
+
+
+if(strm.avail_in!==0||s.lookahead!==0||
+flush!==Z_NO_FLUSH&&s.status!==FINISH_STATE){
+var bstate=s.strategy===Z_HUFFMAN_ONLY?deflate_huff(s,flush):
+s.strategy===Z_RLE?deflate_rle(s,flush):
+configuration_table[s.level].func(s,flush);
+
+if(bstate===BS_FINISH_STARTED||bstate===BS_FINISH_DONE){
+s.status=FINISH_STATE;
+}
+if(bstate===BS_NEED_MORE||bstate===BS_FINISH_STARTED){
+if(strm.avail_out===0){
+s.last_flush=-1;
+
+}
+return Z_OK;
+
+
+
+
+
+
+
+}
+if(bstate===BS_BLOCK_DONE){
+if(flush===Z_PARTIAL_FLUSH){
+trees._tr_align(s);
+}else
+if(flush!==Z_BLOCK){
+
+trees._tr_stored_block(s,0,0,false);
+
+
+
+if(flush===Z_FULL_FLUSH){
+
+zero(s.head);
+
+if(s.lookahead===0){
+s.strstart=0;
+s.block_start=0;
+s.insert=0;
+}
+}
+}
+flush_pending(strm);
+if(strm.avail_out===0){
+s.last_flush=-1;
+return Z_OK;
+}
+}
+}
+
+
+
+if(flush!==Z_FINISH){return Z_OK;}
+if(s.wrap<=0){return Z_STREAM_END;}
+
+
+if(s.wrap===2){
+put_byte(s,strm.adler&0xff);
+put_byte(s,strm.adler>>8&0xff);
+put_byte(s,strm.adler>>16&0xff);
+put_byte(s,strm.adler>>24&0xff);
+put_byte(s,strm.total_in&0xff);
+put_byte(s,strm.total_in>>8&0xff);
+put_byte(s,strm.total_in>>16&0xff);
+put_byte(s,strm.total_in>>24&0xff);
+}else
+
+{
+putShortMSB(s,strm.adler>>>16);
+putShortMSB(s,strm.adler&0xffff);
+}
+
+flush_pending(strm);
+
+
+
+if(s.wrap>0){s.wrap=-s.wrap;}
+
+return s.pending!==0?Z_OK:Z_STREAM_END;
+}
+
+function deflateEnd(strm){
+var status;
+
+if(!strm||!strm.state){
+return Z_STREAM_ERROR;
+}
+
+status=strm.state.status;
+if(status!==INIT_STATE&&
+status!==EXTRA_STATE&&
+status!==NAME_STATE&&
+status!==COMMENT_STATE&&
+status!==HCRC_STATE&&
+status!==BUSY_STATE&&
+status!==FINISH_STATE)
+{
+return err(strm,Z_STREAM_ERROR);
+}
+
+strm.state=null;
+
+return status===BUSY_STATE?err(strm,Z_DATA_ERROR):Z_OK;
+}
+
+
+
+
+
+
+function deflateSetDictionary(strm,dictionary){
+var dictLength=dictionary.length;
+
+var s;
+var str,n;
+var wrap;
+var avail;
+var next;
+var input;
+var tmpDict;
+
+if(!strm||!strm.state){
+return Z_STREAM_ERROR;
+}
+
+s=strm.state;
+wrap=s.wrap;
+
+if(wrap===2||wrap===1&&s.status!==INIT_STATE||s.lookahead){
+return Z_STREAM_ERROR;
+}
+
+
+if(wrap===1){
+
+strm.adler=adler32(strm.adler,dictionary,dictLength,0);
+}
+
+s.wrap=0;
+
+
+if(dictLength>=s.w_size){
+if(wrap===0){
+
+zero(s.head);
+s.strstart=0;
+s.block_start=0;
+s.insert=0;
+}
+
+
+tmpDict=new utils.Buf8(s.w_size);
+utils.arraySet(tmpDict,dictionary,dictLength-s.w_size,s.w_size,0);
+dictionary=tmpDict;
+dictLength=s.w_size;
+}
+
+avail=strm.avail_in;
+next=strm.next_in;
+input=strm.input;
+strm.avail_in=dictLength;
+strm.next_in=0;
+strm.input=dictionary;
+fill_window(s);
+while(s.lookahead>=MIN_MATCH){
+str=s.strstart;
+n=s.lookahead-(MIN_MATCH-1);
+do{
+
+s.ins_h=(s.ins_h<<s.hash_shift^s.window[str+MIN_MATCH-1])&s.hash_mask;
+
+s.prev[str&s.w_mask]=s.head[s.ins_h];
+
+s.head[s.ins_h]=str;
+str++;
+}while(--n);
+s.strstart=str;
+s.lookahead=MIN_MATCH-1;
+fill_window(s);
+}
+s.strstart+=s.lookahead;
+s.block_start=s.strstart;
+s.insert=s.lookahead;
+s.lookahead=0;
+s.match_length=s.prev_length=MIN_MATCH-1;
+s.match_available=0;
+strm.next_in=next;
+strm.input=input;
+strm.avail_in=avail;
+s.wrap=wrap;
+return Z_OK;
+}
+
+
+exports.deflateInit=deflateInit;
+exports.deflateInit2=deflateInit2;
+exports.deflateReset=deflateReset;
+exports.deflateResetKeep=deflateResetKeep;
+exports.deflateSetHeader=deflateSetHeader;
+exports.deflate=deflate;
+exports.deflateEnd=deflateEnd;
+exports.deflateSetDictionary=deflateSetDictionary;
+exports.deflateInfo='pako deflate (from Nodeca project)';
+
+
+
+
+
+
+
+
+
+
+},{"../utils/common":119,"./adler32":120,"./crc32":122,"./messages":124,"./trees":125}],124:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports={
+2:'need dictionary',
+1:'stream end',
+0:'',
+'-1':'file error',
+'-2':'stream error',
+'-3':'data error',
+'-4':'insufficient memory',
+'-5':'buffer error',
+'-6':'incompatible version'};
+
+
+},{}],125:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var utils=require('../utils/common');
+
+
+
+
+
+
+
+
+var Z_FIXED=4;
+
+
+
+var Z_BINARY=0;
+var Z_TEXT=1;
+
+var Z_UNKNOWN=2;
+
+
+
+
+function zero(buf){var len=buf.length;while(--len>=0){buf[len]=0;}}
+
+
+
+var STORED_BLOCK=0;
+var STATIC_TREES=1;
+var DYN_TREES=2;
+
+
+var MIN_MATCH=3;
+var MAX_MATCH=258;
+
+
+
+
+
+
+
+var LENGTH_CODES=29;
+
+
+var LITERALS=256;
+
+
+var L_CODES=LITERALS+1+LENGTH_CODES;
+
+
+var D_CODES=30;
+
+
+var BL_CODES=19;
+
+
+var HEAP_SIZE=2*L_CODES+1;
+
+
+var MAX_BITS=15;
+
+
+var Buf_size=16;
+
+
+
+
+
+
+
+var MAX_BL_BITS=7;
+
+
+var END_BLOCK=256;
+
+
+var REP_3_6=16;
+
+
+var REPZ_3_10=17;
+
+
+var REPZ_11_138=18;
+
+
+
+var extra_lbits=
+[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
+
+var extra_dbits=
+[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
+
+var extra_blbits=
+[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
+
+var bl_order=
+[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
+
+
+
+
+
+
+
+
+
+
+
+
+var DIST_CODE_LEN=512;
+
+
+var static_ltree=new Array((L_CODES+2)*2);
+zero(static_ltree);
+
+
+
+
+
+
+var static_dtree=new Array(D_CODES*2);
+zero(static_dtree);
+
+
+
+
+var _dist_code=new Array(DIST_CODE_LEN);
+zero(_dist_code);
+
+
+
+
+
+var _length_code=new Array(MAX_MATCH-MIN_MATCH+1);
+zero(_length_code);
+
+
+var base_length=new Array(LENGTH_CODES);
+zero(base_length);
+
+
+var base_dist=new Array(D_CODES);
+zero(base_dist);
+
+
+
+function StaticTreeDesc(static_tree,extra_bits,extra_base,elems,max_length){
+
+this.static_tree=static_tree;
+this.extra_bits=extra_bits;
+this.extra_base=extra_base;
+this.elems=elems;
+this.max_length=max_length;
+
+
+this.has_stree=static_tree&&static_tree.length;
+}
+
+
+var static_l_desc;
+var static_d_desc;
+var static_bl_desc;
+
+
+function TreeDesc(dyn_tree,stat_desc){
+this.dyn_tree=dyn_tree;
+this.max_code=0;
+this.stat_desc=stat_desc;
+}
+
+
+
+function d_code(dist){
+return dist<256?_dist_code[dist]:_dist_code[256+(dist>>>7)];
+}
+
+
+
+
+
+
+function put_short(s,w){
+
+
+s.pending_buf[s.pending++]=w&0xff;
+s.pending_buf[s.pending++]=w>>>8&0xff;
+}
+
+
+
+
+
+
+function send_bits(s,value,length){
+if(s.bi_valid>Buf_size-length){
+s.bi_buf|=value<<s.bi_valid&0xffff;
+put_short(s,s.bi_buf);
+s.bi_buf=value>>Buf_size-s.bi_valid;
+s.bi_valid+=length-Buf_size;
+}else{
+s.bi_buf|=value<<s.bi_valid&0xffff;
+s.bi_valid+=length;
+}
+}
+
+
+function send_code(s,c,tree){
+send_bits(s,tree[c*2],tree[c*2+1]);
+}
+
+
+
+
+
+
+
+function bi_reverse(code,len){
+var res=0;
+do{
+res|=code&1;
+code>>>=1;
+res<<=1;
+}while(--len>0);
+return res>>>1;
+}
+
+
+
+
+
+function bi_flush(s){
+if(s.bi_valid===16){
+put_short(s,s.bi_buf);
+s.bi_buf=0;
+s.bi_valid=0;
+
+}else if(s.bi_valid>=8){
+s.pending_buf[s.pending++]=s.bi_buf&0xff;
+s.bi_buf>>=8;
+s.bi_valid-=8;
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+function gen_bitlen(s,desc)
+
+
+{
+var tree=desc.dyn_tree;
+var max_code=desc.max_code;
+var stree=desc.stat_desc.static_tree;
+var has_stree=desc.stat_desc.has_stree;
+var extra=desc.stat_desc.extra_bits;
+var base=desc.stat_desc.extra_base;
+var max_length=desc.stat_desc.max_length;
+var h;
+var n,m;
+var bits;
+var xbits;
+var f;
+var overflow=0;
+
+for(bits=0;bits<=MAX_BITS;bits++){
+s.bl_count[bits]=0;
+}
+
+
+
+
+tree[s.heap[s.heap_max]*2+1]=0;
+
+for(h=s.heap_max+1;h<HEAP_SIZE;h++){
+n=s.heap[h];
+bits=tree[tree[n*2+1]*2+1]+1;
+if(bits>max_length){
+bits=max_length;
+overflow++;
+}
+tree[n*2+1]=bits;
+
+
+if(n>max_code){continue;}
+
+s.bl_count[bits]++;
+xbits=0;
+if(n>=base){
+xbits=extra[n-base];
+}
+f=tree[n*2];
+s.opt_len+=f*(bits+xbits);
+if(has_stree){
+s.static_len+=f*(stree[n*2+1]+xbits);
+}
+}
+if(overflow===0){return;}
+
+
+
+
+
+do{
+bits=max_length-1;
+while(s.bl_count[bits]===0){bits--;}
+s.bl_count[bits]--;
+s.bl_count[bits+1]+=2;
+s.bl_count[max_length]--;
+
+
+
+overflow-=2;
+}while(overflow>0);
+
+
+
+
+
+
+for(bits=max_length;bits!==0;bits--){
+n=s.bl_count[bits];
+while(n!==0){
+m=s.heap[--h];
+if(m>max_code){continue;}
+if(tree[m*2+1]!==bits){
+
+s.opt_len+=(bits-tree[m*2+1])*tree[m*2];
+tree[m*2+1]=bits;
+}
+n--;
+}
+}
+}
+
+
+
+
+
+
+
+
+
+
+function gen_codes(tree,max_code,bl_count)
+
+
+
+{
+var next_code=new Array(MAX_BITS+1);
+var code=0;
+var bits;
+var n;
+
+
+
+
+for(bits=1;bits<=MAX_BITS;bits++){
+next_code[bits]=code=code+bl_count[bits-1]<<1;
+}
+
+
+
+
+
+
+
+for(n=0;n<=max_code;n++){
+var len=tree[n*2+1];
+if(len===0){continue;}
+
+tree[n*2]=bi_reverse(next_code[len]++,len);
+
+
+
+}
+}
+
+
+
+
+
+function tr_static_init(){
+var n;
+var bits;
+var length;
+var code;
+var dist;
+var bl_count=new Array(MAX_BITS+1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+length=0;
+for(code=0;code<LENGTH_CODES-1;code++){
+base_length[code]=length;
+for(n=0;n<1<<extra_lbits[code];n++){
+_length_code[length++]=code;
+}
+}
+
+
+
+
+
+_length_code[length-1]=code;
+
+
+dist=0;
+for(code=0;code<16;code++){
+base_dist[code]=dist;
+for(n=0;n<1<<extra_dbits[code];n++){
+_dist_code[dist++]=code;
+}
+}
+
+dist>>=7;
+for(;code<D_CODES;code++){
+base_dist[code]=dist<<7;
+for(n=0;n<1<<extra_dbits[code]-7;n++){
+_dist_code[256+dist++]=code;
+}
+}
+
+
+
+for(bits=0;bits<=MAX_BITS;bits++){
+bl_count[bits]=0;
+}
+
+n=0;
+while(n<=143){
+static_ltree[n*2+1]=8;
+n++;
+bl_count[8]++;
+}
+while(n<=255){
+static_ltree[n*2+1]=9;
+n++;
+bl_count[9]++;
+}
+while(n<=279){
+static_ltree[n*2+1]=7;
+n++;
+bl_count[7]++;
+}
+while(n<=287){
+static_ltree[n*2+1]=8;
+n++;
+bl_count[8]++;
+}
+
+
+
+
+gen_codes(static_ltree,L_CODES+1,bl_count);
+
+
+for(n=0;n<D_CODES;n++){
+static_dtree[n*2+1]=5;
+static_dtree[n*2]=bi_reverse(n,5);
+}
+
+
+static_l_desc=new StaticTreeDesc(static_ltree,extra_lbits,LITERALS+1,L_CODES,MAX_BITS);
+static_d_desc=new StaticTreeDesc(static_dtree,extra_dbits,0,D_CODES,MAX_BITS);
+static_bl_desc=new StaticTreeDesc(new Array(0),extra_blbits,0,BL_CODES,MAX_BL_BITS);
+
+
+}
+
+
+
+
+
+function init_block(s){
+var n;
+
+
+for(n=0;n<L_CODES;n++){s.dyn_ltree[n*2]=0;}
+for(n=0;n<D_CODES;n++){s.dyn_dtree[n*2]=0;}
+for(n=0;n<BL_CODES;n++){s.bl_tree[n*2]=0;}
+
+s.dyn_ltree[END_BLOCK*2]=1;
+s.opt_len=s.static_len=0;
+s.last_lit=s.matches=0;
+}
+
+
+
+
+
+function bi_windup(s)
+{
+if(s.bi_valid>8){
+put_short(s,s.bi_buf);
+}else if(s.bi_valid>0){
+
+s.pending_buf[s.pending++]=s.bi_buf;
+}
+s.bi_buf=0;
+s.bi_valid=0;
+}
+
+
+
+
+
+function copy_block(s,buf,len,header)
+
+
+
+
+{
+bi_windup(s);
+
+if(header){
+put_short(s,len);
+put_short(s,~len);
+}
+
+
+
+utils.arraySet(s.pending_buf,s.window,buf,len,s.pending);
+s.pending+=len;
+}
+
+
+
+
+
+function smaller(tree,n,m,depth){
+var _n2=n*2;
+var _m2=m*2;
+return tree[_n2]<tree[_m2]||
+tree[_n2]===tree[_m2]&&depth[n]<=depth[m];
+}
+
+
+
+
+
+
+
+function pqdownheap(s,tree,k)
+
+
+
+{
+var v=s.heap[k];
+var j=k<<1;
+while(j<=s.heap_len){
+
+if(j<s.heap_len&&
+smaller(tree,s.heap[j+1],s.heap[j],s.depth)){
+j++;
+}
+
+if(smaller(tree,v,s.heap[j],s.depth)){break;}
+
+
+s.heap[k]=s.heap[j];
+k=j;
+
+
+j<<=1;
+}
+s.heap[k]=v;
+}
+
+
+
+
+
+
+
+
+function compress_block(s,ltree,dtree)
+
+
+
+{
+var dist;
+var lc;
+var lx=0;
+var code;
+var extra;
+
+if(s.last_lit!==0){
+do{
+dist=s.pending_buf[s.d_buf+lx*2]<<8|s.pending_buf[s.d_buf+lx*2+1];
+lc=s.pending_buf[s.l_buf+lx];
+lx++;
+
+if(dist===0){
+send_code(s,lc,ltree);
+
+}else{
+
+code=_length_code[lc];
+send_code(s,code+LITERALS+1,ltree);
+extra=extra_lbits[code];
+if(extra!==0){
+lc-=base_length[code];
+send_bits(s,lc,extra);
+}
+dist--;
+code=d_code(dist);
+
+
+send_code(s,code,dtree);
+extra=extra_dbits[code];
+if(extra!==0){
+dist-=base_dist[code];
+send_bits(s,dist,extra);
+}
+}
+
+
+
+
+
+}while(lx<s.last_lit);
+}
+
+send_code(s,END_BLOCK,ltree);
+}
+
+
+
+
+
+
+
+
+
+
+function build_tree(s,desc)
+
+
+{
+var tree=desc.dyn_tree;
+var stree=desc.stat_desc.static_tree;
+var has_stree=desc.stat_desc.has_stree;
+var elems=desc.stat_desc.elems;
+var n,m;
+var max_code=-1;
+var node;
+
+
+
+
+
+s.heap_len=0;
+s.heap_max=HEAP_SIZE;
+
+for(n=0;n<elems;n++){
+if(tree[n*2]!==0){
+s.heap[++s.heap_len]=max_code=n;
+s.depth[n]=0;
+
+}else{
+tree[n*2+1]=0;
+}
+}
+
+
+
+
+
+
+while(s.heap_len<2){
+node=s.heap[++s.heap_len]=max_code<2?++max_code:0;
+tree[node*2]=1;
+s.depth[node]=0;
+s.opt_len--;
+
+if(has_stree){
+s.static_len-=stree[node*2+1];
+}
+
+}
+desc.max_code=max_code;
+
+
+
+
+for(n=s.heap_len>>1;n>=1;n--){pqdownheap(s,tree,n);}
+
+
+
+
+node=elems;
+do{
+
+
+n=s.heap[1];
+s.heap[1]=s.heap[s.heap_len--];
+pqdownheap(s,tree,1);
+
+
+m=s.heap[1];
+
+s.heap[--s.heap_max]=n;
+s.heap[--s.heap_max]=m;
+
+
+tree[node*2]=tree[n*2]+tree[m*2];
+s.depth[node]=(s.depth[n]>=s.depth[m]?s.depth[n]:s.depth[m])+1;
+tree[n*2+1]=tree[m*2+1]=node;
+
+
+s.heap[1]=node++;
+pqdownheap(s,tree,1);
+
+}while(s.heap_len>=2);
+
+s.heap[--s.heap_max]=s.heap[1];
+
+
+
+
+gen_bitlen(s,desc);
+
+
+gen_codes(tree,max_code,s.bl_count);
+}
+
+
+
+
+
+
+function scan_tree(s,tree,max_code)
+
+
+
+{
+var n;
+var prevlen=-1;
+var curlen;
+
+var nextlen=tree[0*2+1];
+
+var count=0;
+var max_count=7;
+var min_count=4;
+
+if(nextlen===0){
+max_count=138;
+min_count=3;
+}
+tree[(max_code+1)*2+1]=0xffff;
+
+for(n=0;n<=max_code;n++){
+curlen=nextlen;
+nextlen=tree[(n+1)*2+1];
+
+if(++count<max_count&&curlen===nextlen){
+continue;
+
+}else if(count<min_count){
+s.bl_tree[curlen*2]+=count;
+
+}else if(curlen!==0){
+
+if(curlen!==prevlen){s.bl_tree[curlen*2]++;}
+s.bl_tree[REP_3_6*2]++;
+
+}else if(count<=10){
+s.bl_tree[REPZ_3_10*2]++;
+
+}else{
+s.bl_tree[REPZ_11_138*2]++;
+}
+
+count=0;
+prevlen=curlen;
+
+if(nextlen===0){
+max_count=138;
+min_count=3;
+
+}else if(curlen===nextlen){
+max_count=6;
+min_count=3;
+
+}else{
+max_count=7;
+min_count=4;
+}
+}
+}
+
+
+
+
+
+
+function send_tree(s,tree,max_code)
+
+
+
+{
+var n;
+var prevlen=-1;
+var curlen;
+
+var nextlen=tree[0*2+1];
+
+var count=0;
+var max_count=7;
+var min_count=4;
+
+
+if(nextlen===0){
+max_count=138;
+min_count=3;
+}
+
+for(n=0;n<=max_code;n++){
+curlen=nextlen;
+nextlen=tree[(n+1)*2+1];
+
+if(++count<max_count&&curlen===nextlen){
+continue;
+
+}else if(count<min_count){
+do{send_code(s,curlen,s.bl_tree);}while(--count!==0);
+
+}else if(curlen!==0){
+if(curlen!==prevlen){
+send_code(s,curlen,s.bl_tree);
+count--;
+}
+
+send_code(s,REP_3_6,s.bl_tree);
+send_bits(s,count-3,2);
+
+}else if(count<=10){
+send_code(s,REPZ_3_10,s.bl_tree);
+send_bits(s,count-3,3);
+
+}else{
+send_code(s,REPZ_11_138,s.bl_tree);
+send_bits(s,count-11,7);
+}
+
+count=0;
+prevlen=curlen;
+if(nextlen===0){
+max_count=138;
+min_count=3;
+
+}else if(curlen===nextlen){
+max_count=6;
+min_count=3;
+
+}else{
+max_count=7;
+min_count=4;
+}
+}
+}
+
+
+
+
+
+
+function build_bl_tree(s){
+var max_blindex;
+
+
+scan_tree(s,s.dyn_ltree,s.l_desc.max_code);
+scan_tree(s,s.dyn_dtree,s.d_desc.max_code);
+
+
+build_tree(s,s.bl_desc);
+
+
+
+
+
+
+
+
+for(max_blindex=BL_CODES-1;max_blindex>=3;max_blindex--){
+if(s.bl_tree[bl_order[max_blindex]*2+1]!==0){
+break;
+}
+}
+
+s.opt_len+=3*(max_blindex+1)+5+5+4;
+
+
+
+return max_blindex;
+}
+
+
+
+
+
+
+
+function send_all_trees(s,lcodes,dcodes,blcodes)
+
+
+{
+var rank;
+
+
+
+
+
+send_bits(s,lcodes-257,5);
+send_bits(s,dcodes-1,5);
+send_bits(s,blcodes-4,4);
+for(rank=0;rank<blcodes;rank++){
+
+send_bits(s,s.bl_tree[bl_order[rank]*2+1],3);
+}
+
+
+send_tree(s,s.dyn_ltree,lcodes-1);
+
+
+send_tree(s,s.dyn_dtree,dcodes-1);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function detect_data_type(s){
+
+
+
+
+var black_mask=0xf3ffc07f;
+var n;
+
+
+for(n=0;n<=31;n++,black_mask>>>=1){
+if(black_mask&1&&s.dyn_ltree[n*2]!==0){
+return Z_BINARY;
+}
+}
+
+
+if(s.dyn_ltree[9*2]!==0||s.dyn_ltree[10*2]!==0||
+s.dyn_ltree[13*2]!==0){
+return Z_TEXT;
+}
+for(n=32;n<LITERALS;n++){
+if(s.dyn_ltree[n*2]!==0){
+return Z_TEXT;
+}
+}
+
+
+
+
+return Z_BINARY;
+}
+
+
+var static_init_done=false;
+
+
+
+
+function _tr_init(s)
+{
+
+if(!static_init_done){
+tr_static_init();
+static_init_done=true;
+}
+
+s.l_desc=new TreeDesc(s.dyn_ltree,static_l_desc);
+s.d_desc=new TreeDesc(s.dyn_dtree,static_d_desc);
+s.bl_desc=new TreeDesc(s.bl_tree,static_bl_desc);
+
+s.bi_buf=0;
+s.bi_valid=0;
+
+
+init_block(s);
+}
+
+
+
+
+
+function _tr_stored_block(s,buf,stored_len,last)
+
+
+
+
+{
+send_bits(s,(STORED_BLOCK<<1)+(last?1:0),3);
+copy_block(s,buf,stored_len,true);
+}
+
+
+
+
+
+
+function _tr_align(s){
+send_bits(s,STATIC_TREES<<1,3);
+send_code(s,END_BLOCK,static_ltree);
+bi_flush(s);
+}
+
+
+
+
+
+
+function _tr_flush_block(s,buf,stored_len,last)
+
+
+
+
+{
+var opt_lenb,static_lenb;
+var max_blindex=0;
+
+
+if(s.level>0){
+
+
+if(s.strm.data_type===Z_UNKNOWN){
+s.strm.data_type=detect_data_type(s);
+}
+
+
+build_tree(s,s.l_desc);
+
+
+
+build_tree(s,s.d_desc);
+
+
+
+
+
+
+
+
+
+max_blindex=build_bl_tree(s);
+
+
+opt_lenb=s.opt_len+3+7>>>3;
+static_lenb=s.static_len+3+7>>>3;
+
+
+
+
+
+if(static_lenb<=opt_lenb){opt_lenb=static_lenb;}
+
+}else{
+
+opt_lenb=static_lenb=stored_len+5;
+}
+
+if(stored_len+4<=opt_lenb&&buf!==-1){
+
+
+
+
+
+
+
+
+_tr_stored_block(s,buf,stored_len,last);
+
+}else if(s.strategy===Z_FIXED||static_lenb===opt_lenb){
+
+send_bits(s,(STATIC_TREES<<1)+(last?1:0),3);
+compress_block(s,static_ltree,static_dtree);
+
+}else{
+send_bits(s,(DYN_TREES<<1)+(last?1:0),3);
+send_all_trees(s,s.l_desc.max_code+1,s.d_desc.max_code+1,max_blindex+1);
+compress_block(s,s.dyn_ltree,s.dyn_dtree);
+}
+
+
+
+
+init_block(s);
+
+if(last){
+bi_windup(s);
+}
+
+
+}
+
+
+
+
+
+function _tr_tally(s,dist,lc)
+
+
+
+{
+
+
+s.pending_buf[s.d_buf+s.last_lit*2]=dist>>>8&0xff;
+s.pending_buf[s.d_buf+s.last_lit*2+1]=dist&0xff;
+
+s.pending_buf[s.l_buf+s.last_lit]=lc&0xff;
+s.last_lit++;
+
+if(dist===0){
+
+s.dyn_ltree[lc*2]++;
+}else{
+s.matches++;
+
+dist--;
+
+
+
+
+s.dyn_ltree[(_length_code[lc]+LITERALS+1)*2]++;
+s.dyn_dtree[d_code(dist)*2]++;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+return s.last_lit===s.lit_bufsize-1;
+
+
+
+
+}
+
+exports._tr_init=_tr_init;
+exports._tr_stored_block=_tr_stored_block;
+exports._tr_flush_block=_tr_flush_block;
+exports._tr_tally=_tr_tally;
+exports._tr_align=_tr_align;
+
+},{"../utils/common":119}],126:[function(require,module,exports){
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function ZStream(){
+
+this.input=null;
+this.next_in=0;
+
+this.avail_in=0;
+
+this.total_in=0;
+
+this.output=null;
+this.next_out=0;
+
+this.avail_out=0;
+
+this.total_out=0;
+
+this.msg='';
+
+this.state=null;
+
+this.data_type=2;
+
+this.adler=0;
+}
+
+module.exports=ZStream;
+
+},{}],127:[function(require,module,exports){
+module.exports=function parseCacheControl(field){
+
+if(typeof field!=='string'){
+return null;
+}
+
+
+
+
+
+
+
+
+
+var regex=/(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;
+
+var header={};
+var err=field.replace(regex,function($0,$1,$2,$3){
+var value=$2||$3;
+header[$1]=value?value.toLowerCase():true;
+return'';
+});
+
+if(header['max-age']){
+try{
+var maxAge=parseInt(header['max-age'],10);
+if(isNaN(maxAge)){
+return null;
+}
+
+header['max-age']=maxAge;
+}
+catch(err){}
+}
+
+return err?null:header;
+};
+
+},{}],128:[function(require,module,exports){
+(function(process){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function normalizeArray(parts,allowAboveRoot){
+
+var up=0;
+for(var i=parts.length-1;i>=0;i--){
+var last=parts[i];
+if(last==='.'){
+parts.splice(i,1);
+}else if(last==='..'){
+parts.splice(i,1);
+up++;
+}else if(up){
+parts.splice(i,1);
+up--;
+}
+}
+
+
+if(allowAboveRoot){
+for(;up--;up){
+parts.unshift('..');
+}
+}
+
+return parts;
+}
+
+
+
+exports.resolve=function(){
+var resolvedPath='',
+resolvedAbsolute=false;
+
+for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){
+var path=i>=0?arguments[i]:process.cwd();
+
+
+if(typeof path!=='string'){
+throw new TypeError('Arguments to path.resolve must be strings');
+}else if(!path){
+continue;
+}
+
+resolvedPath=path+'/'+resolvedPath;
+resolvedAbsolute=path.charAt(0)==='/';
+}
+
+
+
+
+
+resolvedPath=normalizeArray(filter(resolvedPath.split('/'),function(p){
+return!!p;
+}),!resolvedAbsolute).join('/');
+
+return(resolvedAbsolute?'/':'')+resolvedPath||'.';
+};
+
+
+
+exports.normalize=function(path){
+var isAbsolute=exports.isAbsolute(path),
+trailingSlash=substr(path,-1)==='/';
+
+
+path=normalizeArray(filter(path.split('/'),function(p){
+return!!p;
+}),!isAbsolute).join('/');
+
+if(!path&&!isAbsolute){
+path='.';
+}
+if(path&&trailingSlash){
+path+='/';
+}
+
+return(isAbsolute?'/':'')+path;
+};
+
+
+exports.isAbsolute=function(path){
+return path.charAt(0)==='/';
+};
+
+
+exports.join=function(){
+var paths=Array.prototype.slice.call(arguments,0);
+return exports.normalize(filter(paths,function(p,index){
+if(typeof p!=='string'){
+throw new TypeError('Arguments to path.join must be strings');
+}
+return p;
+}).join('/'));
+};
+
+
+
+
+exports.relative=function(from,to){
+from=exports.resolve(from).substr(1);
+to=exports.resolve(to).substr(1);
+
+function trim(arr){
+var start=0;
+for(;start<arr.length;start++){
+if(arr[start]!=='')break;
+}
+
+var end=arr.length-1;
+for(;end>=0;end--){
+if(arr[end]!=='')break;
+}
+
+if(start>end)return[];
+return arr.slice(start,end-start+1);
+}
+
+var fromParts=trim(from.split('/'));
+var toParts=trim(to.split('/'));
+
+var length=Math.min(fromParts.length,toParts.length);
+var samePartsLength=length;
+for(var i=0;i<length;i++){
+if(fromParts[i]!==toParts[i]){
+samePartsLength=i;
+break;
+}
+}
+
+var outputParts=[];
+for(var i=samePartsLength;i<fromParts.length;i++){
+outputParts.push('..');
+}
+
+outputParts=outputParts.concat(toParts.slice(samePartsLength));
+
+return outputParts.join('/');
+};
+
+exports.sep='/';
+exports.delimiter=':';
+
+exports.dirname=function(path){
+if(typeof path!=='string')path=path+'';
+if(path.length===0)return'.';
+var code=path.charCodeAt(0);
+var hasRoot=code===47;
+var end=-1;
+var matchedSlash=true;
+for(var i=path.length-1;i>=1;--i){
+code=path.charCodeAt(i);
+if(code===47){
+if(!matchedSlash){
+end=i;
+break;
+}
+}else{
+
+matchedSlash=false;
+}
+}
+
+if(end===-1)return hasRoot?'/':'.';
+if(hasRoot&&end===1){
+
+
+return'/';
+}
+return path.slice(0,end);
+};
+
+function basename(path){
+if(typeof path!=='string')path=path+'';
+
+var start=0;
+var end=-1;
+var matchedSlash=true;
+var i;
+
+for(i=path.length-1;i>=0;--i){
+if(path.charCodeAt(i)===47){
+
+
+if(!matchedSlash){
+start=i+1;
+break;
+}
+}else if(end===-1){
+
+
+matchedSlash=false;
+end=i+1;
+}
+}
+
+if(end===-1)return'';
+return path.slice(start,end);
+}
+
+
+
+exports.basename=function(path,ext){
+var f=basename(path);
+if(ext&&f.substr(-1*ext.length)===ext){
+f=f.substr(0,f.length-ext.length);
+}
+return f;
+};
+
+exports.extname=function(path){
+if(typeof path!=='string')path=path+'';
+var startDot=-1;
+var startPart=0;
+var end=-1;
+var matchedSlash=true;
+
+
+var preDotState=0;
+for(var i=path.length-1;i>=0;--i){
+var code=path.charCodeAt(i);
+if(code===47){
+
+
+if(!matchedSlash){
+startPart=i+1;
+break;
+}
+continue;
+}
+if(end===-1){
+
+
+matchedSlash=false;
+end=i+1;
+}
+if(code===46){
+
+if(startDot===-1)
+startDot=i;else
+if(preDotState!==1)
+preDotState=1;
+}else if(startDot!==-1){
+
+
+preDotState=-1;
+}
+}
+
+if(startDot===-1||end===-1||
+
+preDotState===0||
+
+preDotState===1&&startDot===end-1&&startDot===startPart+1){
+return'';
+}
+return path.slice(startDot,end);
+};
+
+function filter(xs,f){
+if(xs.filter)return xs.filter(f);
+var res=[];
+for(var i=0;i<xs.length;i++){
+if(f(xs[i],i,xs))res.push(xs[i]);
+}
+return res;
+}
+
+
+var substr='ab'.substr(-1)==='b'?
+function(str,start,len){return str.substr(start,len);}:
+function(str,start,len){
+if(start<0)start=str.length+start;
+return str.substr(start,len);
+};
+
+
+}).call(this,require('_process'));
+},{"_process":130}],129:[function(require,module,exports){
+(function(process){
+'use strict';
+
+if(!process.version||
+process.version.indexOf('v0.')===0||
+process.version.indexOf('v1.')===0&&process.version.indexOf('v1.8.')!==0){
+module.exports=nextTick;
+}else{
+module.exports=process.nextTick;
+}
+
+function nextTick(fn,arg1,arg2,arg3){
+if(typeof fn!=='function'){
+throw new TypeError('"callback" argument must be a function');
+}
+var len=arguments.length;
+var args,i;
+switch(len){
+case 0:
+case 1:
+return process.nextTick(fn);
+case 2:
+return process.nextTick(function afterTickOne(){
+fn.call(null,arg1);
+});
+case 3:
+return process.nextTick(function afterTickTwo(){
+fn.call(null,arg1,arg2);
+});
+case 4:
+return process.nextTick(function afterTickThree(){
+fn.call(null,arg1,arg2,arg3);
+});
+default:
+args=new Array(len-1);
+i=0;
+while(i<args.length){
+args[i++]=arguments[i];
+}
+return process.nextTick(function afterTick(){
+fn.apply(null,args);
+});}
+
+}
+
+}).call(this,require('_process'));
+},{"_process":130}],130:[function(require,module,exports){
+
+var process=module.exports={};
+
+
+
+
+
+
+var cachedSetTimeout;
+var cachedClearTimeout;
+
+function defaultSetTimout(){
+throw new Error('setTimeout has not been defined');
+}
+function defaultClearTimeout(){
+throw new Error('clearTimeout has not been defined');
+}
+(function(){
+try{
+if(typeof setTimeout==='function'){
+cachedSetTimeout=setTimeout;
+}else{
+cachedSetTimeout=defaultSetTimout;
+}
+}catch(e){
+cachedSetTimeout=defaultSetTimout;
+}
+try{
+if(typeof clearTimeout==='function'){
+cachedClearTimeout=clearTimeout;
+}else{
+cachedClearTimeout=defaultClearTimeout;
+}
+}catch(e){
+cachedClearTimeout=defaultClearTimeout;
+}
+})();
+function runTimeout(fun){
+if(cachedSetTimeout===setTimeout){
+
+return setTimeout(fun,0);
+}
+
+if((cachedSetTimeout===defaultSetTimout||!cachedSetTimeout)&&setTimeout){
+cachedSetTimeout=setTimeout;
+return setTimeout(fun,0);
+}
+try{
+
+return cachedSetTimeout(fun,0);
+}catch(e){
+try{
+
+return cachedSetTimeout.call(null,fun,0);
+}catch(e){
+
+return cachedSetTimeout.call(this,fun,0);
+}
+}
+
+
+}
+function runClearTimeout(marker){
+if(cachedClearTimeout===clearTimeout){
+
+return clearTimeout(marker);
+}
+
+if((cachedClearTimeout===defaultClearTimeout||!cachedClearTimeout)&&clearTimeout){
+cachedClearTimeout=clearTimeout;
+return clearTimeout(marker);
+}
+try{
+
+return cachedClearTimeout(marker);
+}catch(e){
+try{
+
+return cachedClearTimeout.call(null,marker);
+}catch(e){
+
+
+return cachedClearTimeout.call(this,marker);
+}
+}
+
+
+
+}
+var queue=[];
+var draining=false;
+var currentQueue;
+var queueIndex=-1;
+
+function cleanUpNextTick(){
+if(!draining||!currentQueue){
+return;
+}
+draining=false;
+if(currentQueue.length){
+queue=currentQueue.concat(queue);
+}else{
+queueIndex=-1;
+}
+if(queue.length){
+drainQueue();
+}
+}
+
+function drainQueue(){
+if(draining){
+return;
+}
+var timeout=runTimeout(cleanUpNextTick);
+draining=true;
+
+var len=queue.length;
+while(len){
+currentQueue=queue;
+queue=[];
+while(++queueIndex<len){
+if(currentQueue){
+currentQueue[queueIndex].run();
+}
+}
+queueIndex=-1;
+len=queue.length;
+}
+currentQueue=null;
+draining=false;
+runClearTimeout(timeout);
+}
+
+process.nextTick=function(fun){
+var args=new Array(arguments.length-1);
+if(arguments.length>1){
+for(var i=1;i<arguments.length;i++){
+args[i-1]=arguments[i];
+}
+}
+queue.push(new Item(fun,args));
+if(queue.length===1&&!draining){
+runTimeout(drainQueue);
+}
+};
+
+
+function Item(fun,array){
+this.fun=fun;
+this.array=array;
+}
+Item.prototype.run=function(){
+this.fun.apply(null,this.array);
+};
+process.title='browser';
+process.browser=true;
+process.env={};
+process.argv=[];
+process.version='';
+process.versions={};
+
+function noop(){}
+
+process.on=noop;
+process.addListener=noop;
+process.once=noop;
+process.off=noop;
+process.removeListener=noop;
+process.removeAllListeners=noop;
+process.emit=noop;
+process.prependListener=noop;
+process.prependOnceListener=noop;
+
+process.listeners=function(name){return[];};
+
+process.binding=function(name){
+throw new Error('process.binding is not supported');
+};
+
+process.cwd=function(){return'/';};
+process.chdir=function(dir){
+throw new Error('process.chdir is not supported');
+};
+process.umask=function(){return 0;};
+
+},{}],131:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+
+
+
+function hasOwnProperty(obj,prop){
+return Object.prototype.hasOwnProperty.call(obj,prop);
+}
+
+module.exports=function(qs,sep,eq,options){
+sep=sep||'&';
+eq=eq||'=';
+var obj={};
+
+if(typeof qs!=='string'||qs.length===0){
+return obj;
+}
+
+var regexp=/\+/g;
+qs=qs.split(sep);
+
+var maxKeys=1000;
+if(options&&typeof options.maxKeys==='number'){
+maxKeys=options.maxKeys;
+}
+
+var len=qs.length;
+
+if(maxKeys>0&&len>maxKeys){
+len=maxKeys;
+}
+
+for(var i=0;i<len;++i){
+var x=qs[i].replace(regexp,'%20'),
+idx=x.indexOf(eq),
+kstr,vstr,k,v;
+
+if(idx>=0){
+kstr=x.substr(0,idx);
+vstr=x.substr(idx+1);
+}else{
+kstr=x;
+vstr='';
+}
+
+k=decodeURIComponent(kstr);
+v=decodeURIComponent(vstr);
+
+if(!hasOwnProperty(obj,k)){
+obj[k]=v;
+}else if(isArray(obj[k])){
+obj[k].push(v);
+}else{
+obj[k]=[obj[k],v];
+}
+}
+
+return obj;
+};
+
+var isArray=Array.isArray||function(xs){
+return Object.prototype.toString.call(xs)==='[object Array]';
+};
+
+},{}],132:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+var stringifyPrimitive=function(v){
+switch(typeof v){
+case'string':
+return v;
+
+case'boolean':
+return v?'true':'false';
+
+case'number':
+return isFinite(v)?v:'';
+
+default:
+return'';}
+
+};
+
+module.exports=function(obj,sep,eq,name){
+sep=sep||'&';
+eq=eq||'=';
+if(obj===null){
+obj=undefined;
+}
+
+if(typeof obj==='object'){
+return map(objectKeys(obj),function(k){
+var ks=encodeURIComponent(stringifyPrimitive(k))+eq;
+if(isArray(obj[k])){
+return map(obj[k],function(v){
+return ks+encodeURIComponent(stringifyPrimitive(v));
+}).join(sep);
+}else{
+return ks+encodeURIComponent(stringifyPrimitive(obj[k]));
+}
+}).join(sep);
+
+}
+
+if(!name)return'';
+return encodeURIComponent(stringifyPrimitive(name))+eq+
+encodeURIComponent(stringifyPrimitive(obj));
+};
+
+var isArray=Array.isArray||function(xs){
+return Object.prototype.toString.call(xs)==='[object Array]';
+};
+
+function map(xs,f){
+if(xs.map)return xs.map(f);
+var res=[];
+for(var i=0;i<xs.length;i++){
+res.push(f(xs[i],i));
+}
+return res;
+}
+
+var objectKeys=Object.keys||function(obj){
+var res=[];
+for(var key in obj){
+if(Object.prototype.hasOwnProperty.call(obj,key))res.push(key);
+}
+return res;
+};
+
+},{}],133:[function(require,module,exports){
+'use strict';
+
+exports.decode=exports.parse=require('./decode');
+exports.encode=exports.stringify=require('./encode');
+
+},{"./decode":131,"./encode":132}],134:[function(require,module,exports){
+module.exports=require('./lib/_stream_duplex.js');
+
+},{"./lib/_stream_duplex.js":135}],135:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+
+
+var processNextTick=require('process-nextick-args');
+
+
+
+var objectKeys=Object.keys||function(obj){
+var keys=[];
+for(var key in obj){
+keys.push(key);
+}return keys;
+};
+
+
+module.exports=Duplex;
+
+
+var util=require('core-util-is');
+util.inherits=require('inherits');
+
+
+var Readable=require('./_stream_readable');
+var Writable=require('./_stream_writable');
+
+util.inherits(Duplex,Readable);
+
+var keys=objectKeys(Writable.prototype);
+for(var v=0;v<keys.length;v++){
+var method=keys[v];
+if(!Duplex.prototype[method])Duplex.prototype[method]=Writable.prototype[method];
+}
+
+function Duplex(options){
+if(!(this instanceof Duplex))return new Duplex(options);
+
+Readable.call(this,options);
+Writable.call(this,options);
+
+if(options&&options.readable===false)this.readable=false;
+
+if(options&&options.writable===false)this.writable=false;
+
+this.allowHalfOpen=true;
+if(options&&options.allowHalfOpen===false)this.allowHalfOpen=false;
+
+this.once('end',onend);
+}
+
+
+function onend(){
+
+
+if(this.allowHalfOpen||this._writableState.ended)return;
+
+
+
+processNextTick(onEndNT,this);
+}
+
+function onEndNT(self){
+self.end();
+}
+
+Object.defineProperty(Duplex.prototype,'destroyed',{
+get:function(){
+if(this._readableState===undefined||this._writableState===undefined){
+return false;
+}
+return this._readableState.destroyed&&this._writableState.destroyed;
+},
+set:function(value){
+
+
+if(this._readableState===undefined||this._writableState===undefined){
+return;
+}
+
+
+
+this._readableState.destroyed=value;
+this._writableState.destroyed=value;
+}});
+
+
+Duplex.prototype._destroy=function(err,cb){
+this.push(null);
+this.end();
+
+processNextTick(cb,err);
+};
+
+function forEach(xs,f){
+for(var i=0,l=xs.length;i<l;i++){
+f(xs[i],i);
+}
+}
+},{"./_stream_readable":137,"./_stream_writable":139,"core-util-is":89,"inherits":98,"process-nextick-args":129}],136:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+module.exports=PassThrough;
+
+var Transform=require('./_stream_transform');
+
+
+var util=require('core-util-is');
+util.inherits=require('inherits');
+
+
+util.inherits(PassThrough,Transform);
+
+function PassThrough(options){
+if(!(this instanceof PassThrough))return new PassThrough(options);
+
+Transform.call(this,options);
+}
+
+PassThrough.prototype._transform=function(chunk,encoding,cb){
+cb(null,chunk);
+};
+},{"./_stream_transform":138,"core-util-is":89,"inherits":98}],137:[function(require,module,exports){
+(function(process,global){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+
+
+var processNextTick=require('process-nextick-args');
+
+
+module.exports=Readable;
+
+
+var isArray=require('isarray');
+
+
+
+var Duplex;
+
+
+Readable.ReadableState=ReadableState;
+
+
+var EE=require('events').EventEmitter;
+
+var EElistenerCount=function(emitter,type){
+return emitter.listeners(type).length;
+};
+
+
+
+var Stream=require('./internal/streams/stream');
+
+
+
+
+
+var Buffer=require('safe-buffer').Buffer;
+var OurUint8Array=global.Uint8Array||function(){};
+function _uint8ArrayToBuffer(chunk){
+return Buffer.from(chunk);
+}
+function _isUint8Array(obj){
+return Buffer.isBuffer(obj)||obj instanceof OurUint8Array;
+}
+
+
+
+var util=require('core-util-is');
+util.inherits=require('inherits');
+
+
+
+var debugUtil=require('util');
+var debug=void 0;
+if(debugUtil&&debugUtil.debuglog){
+debug=debugUtil.debuglog('stream');
+}else{
+debug=function(){};
+}
+
+
+var BufferList=require('./internal/streams/BufferList');
+var destroyImpl=require('./internal/streams/destroy');
+var StringDecoder;
+
+util.inherits(Readable,Stream);
+
+var kProxyEvents=['error','close','destroy','pause','resume'];
+
+function prependListener(emitter,event,fn){
+
+
+if(typeof emitter.prependListener==='function'){
+return emitter.prependListener(event,fn);
+}else{
+
+
+
+
+if(!emitter._events||!emitter._events[event])emitter.on(event,fn);else if(isArray(emitter._events[event]))emitter._events[event].unshift(fn);else emitter._events[event]=[fn,emitter._events[event]];
+}
+}
+
+function ReadableState(options,stream){
+Duplex=Duplex||require('./_stream_duplex');
+
+options=options||{};
+
+
+
+this.objectMode=!!options.objectMode;
+
+if(stream instanceof Duplex)this.objectMode=this.objectMode||!!options.readableObjectMode;
+
+
+
+var hwm=options.highWaterMark;
+var defaultHwm=this.objectMode?16:16*1024;
+this.highWaterMark=hwm||hwm===0?hwm:defaultHwm;
+
+
+this.highWaterMark=Math.floor(this.highWaterMark);
+
+
+
+
+this.buffer=new BufferList();
+this.length=0;
+this.pipes=null;
+this.pipesCount=0;
+this.flowing=null;
+this.ended=false;
+this.endEmitted=false;
+this.reading=false;
+
+
+
+
+
+this.sync=true;
+
+
+
+this.needReadable=false;
+this.emittedReadable=false;
+this.readableListening=false;
+this.resumeScheduled=false;
+
+
+this.destroyed=false;
+
+
+
+
+this.defaultEncoding=options.defaultEncoding||'utf8';
+
+
+this.awaitDrain=0;
+
+
+this.readingMore=false;
+
+this.decoder=null;
+this.encoding=null;
+if(options.encoding){
+if(!StringDecoder)StringDecoder=require('string_decoder/').StringDecoder;
+this.decoder=new StringDecoder(options.encoding);
+this.encoding=options.encoding;
+}
+}
+
+function Readable(options){
+Duplex=Duplex||require('./_stream_duplex');
+
+if(!(this instanceof Readable))return new Readable(options);
+
+this._readableState=new ReadableState(options,this);
+
+
+this.readable=true;
+
+if(options){
+if(typeof options.read==='function')this._read=options.read;
+
+if(typeof options.destroy==='function')this._destroy=options.destroy;
+}
+
+Stream.call(this);
+}
+
+Object.defineProperty(Readable.prototype,'destroyed',{
+get:function(){
+if(this._readableState===undefined){
+return false;
+}
+return this._readableState.destroyed;
+},
+set:function(value){
+
+
+if(!this._readableState){
+return;
+}
+
+
+
+this._readableState.destroyed=value;
+}});
+
+
+Readable.prototype.destroy=destroyImpl.destroy;
+Readable.prototype._undestroy=destroyImpl.undestroy;
+Readable.prototype._destroy=function(err,cb){
+this.push(null);
+cb(err);
+};
+
+
+
+
+
+Readable.prototype.push=function(chunk,encoding){
+var state=this._readableState;
+var skipChunkCheck;
+
+if(!state.objectMode){
+if(typeof chunk==='string'){
+encoding=encoding||state.defaultEncoding;
+if(encoding!==state.encoding){
+chunk=Buffer.from(chunk,encoding);
+encoding='';
+}
+skipChunkCheck=true;
+}
+}else{
+skipChunkCheck=true;
+}
+
+return readableAddChunk(this,chunk,encoding,false,skipChunkCheck);
+};
+
+
+Readable.prototype.unshift=function(chunk){
+return readableAddChunk(this,chunk,null,true,false);
+};
+
+function readableAddChunk(stream,chunk,encoding,addToFront,skipChunkCheck){
+var state=stream._readableState;
+if(chunk===null){
+state.reading=false;
+onEofChunk(stream,state);
+}else{
+var er;
+if(!skipChunkCheck)er=chunkInvalid(state,chunk);
+if(er){
+stream.emit('error',er);
+}else if(state.objectMode||chunk&&chunk.length>0){
+if(typeof chunk!=='string'&&!state.objectMode&&Object.getPrototypeOf(chunk)!==Buffer.prototype){
+chunk=_uint8ArrayToBuffer(chunk);
+}
+
+if(addToFront){
+if(state.endEmitted)stream.emit('error',new Error('stream.unshift() after end event'));else addChunk(stream,state,chunk,true);
+}else if(state.ended){
+stream.emit('error',new Error('stream.push() after EOF'));
+}else{
+state.reading=false;
+if(state.decoder&&!encoding){
+chunk=state.decoder.write(chunk);
+if(state.objectMode||chunk.length!==0)addChunk(stream,state,chunk,false);else maybeReadMore(stream,state);
+}else{
+addChunk(stream,state,chunk,false);
+}
+}
+}else if(!addToFront){
+state.reading=false;
+}
+}
+
+return needMoreData(state);
+}
+
+function addChunk(stream,state,chunk,addToFront){
+if(state.flowing&&state.length===0&&!state.sync){
+stream.emit('data',chunk);
+stream.read(0);
+}else{
+
+state.length+=state.objectMode?1:chunk.length;
+if(addToFront)state.buffer.unshift(chunk);else state.buffer.push(chunk);
+
+if(state.needReadable)emitReadable(stream);
+}
+maybeReadMore(stream,state);
+}
+
+function chunkInvalid(state,chunk){
+var er;
+if(!_isUint8Array(chunk)&&typeof chunk!=='string'&&chunk!==undefined&&!state.objectMode){
+er=new TypeError('Invalid non-string/buffer chunk');
+}
+return er;
+}
+
+
+
+
+
+
+
+
+function needMoreData(state){
+return!state.ended&&(state.needReadable||state.length<state.highWaterMark||state.length===0);
+}
+
+Readable.prototype.isPaused=function(){
+return this._readableState.flowing===false;
+};
+
+
+Readable.prototype.setEncoding=function(enc){
+if(!StringDecoder)StringDecoder=require('string_decoder/').StringDecoder;
+this._readableState.decoder=new StringDecoder(enc);
+this._readableState.encoding=enc;
+return this;
+};
+
+
+var MAX_HWM=0x800000;
+function computeNewHighWaterMark(n){
+if(n>=MAX_HWM){
+n=MAX_HWM;
+}else{
+
+
+n--;
+n|=n>>>1;
+n|=n>>>2;
+n|=n>>>4;
+n|=n>>>8;
+n|=n>>>16;
+n++;
+}
+return n;
+}
+
+
+
+function howMuchToRead(n,state){
+if(n<=0||state.length===0&&state.ended)return 0;
+if(state.objectMode)return 1;
+if(n!==n){
+
+if(state.flowing&&state.length)return state.buffer.head.data.length;else return state.length;
+}
+
+if(n>state.highWaterMark)state.highWaterMark=computeNewHighWaterMark(n);
+if(n<=state.length)return n;
+
+if(!state.ended){
+state.needReadable=true;
+return 0;
+}
+return state.length;
+}
+
+
+Readable.prototype.read=function(n){
+debug('read',n);
+n=parseInt(n,10);
+var state=this._readableState;
+var nOrig=n;
+
+if(n!==0)state.emittedReadable=false;
+
+
+
+
+if(n===0&&state.needReadable&&(state.length>=state.highWaterMark||state.ended)){
+debug('read: emitReadable',state.length,state.ended);
+if(state.length===0&&state.ended)endReadable(this);else emitReadable(this);
+return null;
+}
+
+n=howMuchToRead(n,state);
+
+
+if(n===0&&state.ended){
+if(state.length===0)endReadable(this);
+return null;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var doRead=state.needReadable;
+debug('need readable',doRead);
+
+
+if(state.length===0||state.length-n<state.highWaterMark){
+doRead=true;
+debug('length less than watermark',doRead);
+}
+
+
+
+if(state.ended||state.reading){
+doRead=false;
+debug('reading or ended',doRead);
+}else if(doRead){
+debug('do read');
+state.reading=true;
+state.sync=true;
+
+if(state.length===0)state.needReadable=true;
+
+this._read(state.highWaterMark);
+state.sync=false;
+
+
+if(!state.reading)n=howMuchToRead(nOrig,state);
+}
+
+var ret;
+if(n>0)ret=fromList(n,state);else ret=null;
+
+if(ret===null){
+state.needReadable=true;
+n=0;
+}else{
+state.length-=n;
+}
+
+if(state.length===0){
+
+
+if(!state.ended)state.needReadable=true;
+
+
+if(nOrig!==n&&state.ended)endReadable(this);
+}
+
+if(ret!==null)this.emit('data',ret);
+
+return ret;
+};
+
+function onEofChunk(stream,state){
+if(state.ended)return;
+if(state.decoder){
+var chunk=state.decoder.end();
+if(chunk&&chunk.length){
+state.buffer.push(chunk);
+state.length+=state.objectMode?1:chunk.length;
+}
+}
+state.ended=true;
+
+
+emitReadable(stream);
+}
+
+
+
+
+function emitReadable(stream){
+var state=stream._readableState;
+state.needReadable=false;
+if(!state.emittedReadable){
+debug('emitReadable',state.flowing);
+state.emittedReadable=true;
+if(state.sync)processNextTick(emitReadable_,stream);else emitReadable_(stream);
+}
+}
+
+function emitReadable_(stream){
+debug('emit readable');
+stream.emit('readable');
+flow(stream);
+}
+
+
+
+
+
+
+
+function maybeReadMore(stream,state){
+if(!state.readingMore){
+state.readingMore=true;
+processNextTick(maybeReadMore_,stream,state);
+}
+}
+
+function maybeReadMore_(stream,state){
+var len=state.length;
+while(!state.reading&&!state.flowing&&!state.ended&&state.length<state.highWaterMark){
+debug('maybeReadMore read 0');
+stream.read(0);
+if(len===state.length)
+
+break;else len=state.length;
+}
+state.readingMore=false;
+}
+
+
+
+
+
+Readable.prototype._read=function(n){
+this.emit('error',new Error('_read() is not implemented'));
+};
+
+Readable.prototype.pipe=function(dest,pipeOpts){
+var src=this;
+var state=this._readableState;
+
+switch(state.pipesCount){
+case 0:
+state.pipes=dest;
+break;
+case 1:
+state.pipes=[state.pipes,dest];
+break;
+default:
+state.pipes.push(dest);
+break;}
+
+state.pipesCount+=1;
+debug('pipe count=%d opts=%j',state.pipesCount,pipeOpts);
+
+var doEnd=(!pipeOpts||pipeOpts.end!==false)&&dest!==process.stdout&&dest!==process.stderr;
+
+var endFn=doEnd?onend:unpipe;
+if(state.endEmitted)processNextTick(endFn);else src.once('end',endFn);
+
+dest.on('unpipe',onunpipe);
+function onunpipe(readable,unpipeInfo){
+debug('onunpipe');
+if(readable===src){
+if(unpipeInfo&&unpipeInfo.hasUnpiped===false){
+unpipeInfo.hasUnpiped=true;
+cleanup();
+}
+}
+}
+
+function onend(){
+debug('onend');
+dest.end();
+}
+
+
+
+
+
+var ondrain=pipeOnDrain(src);
+dest.on('drain',ondrain);
+
+var cleanedUp=false;
+function cleanup(){
+debug('cleanup');
+
+dest.removeListener('close',onclose);
+dest.removeListener('finish',onfinish);
+dest.removeListener('drain',ondrain);
+dest.removeListener('error',onerror);
+dest.removeListener('unpipe',onunpipe);
+src.removeListener('end',onend);
+src.removeListener('end',unpipe);
+src.removeListener('data',ondata);
+
+cleanedUp=true;
+
+
+
+
+
+
+if(state.awaitDrain&&(!dest._writableState||dest._writableState.needDrain))ondrain();
+}
+
+
+
+
+
+var increasedAwaitDrain=false;
+src.on('data',ondata);
+function ondata(chunk){
+debug('ondata');
+increasedAwaitDrain=false;
+var ret=dest.write(chunk);
+if(false===ret&&!increasedAwaitDrain){
+
+
+
+
+if((state.pipesCount===1&&state.pipes===dest||state.pipesCount>1&&indexOf(state.pipes,dest)!==-1)&&!cleanedUp){
+debug('false write response, pause',src._readableState.awaitDrain);
+src._readableState.awaitDrain++;
+increasedAwaitDrain=true;
+}
+src.pause();
+}
+}
+
+
+
+function onerror(er){
+debug('onerror',er);
+unpipe();
+dest.removeListener('error',onerror);
+if(EElistenerCount(dest,'error')===0)dest.emit('error',er);
+}
+
+
+prependListener(dest,'error',onerror);
+
+
+function onclose(){
+dest.removeListener('finish',onfinish);
+unpipe();
+}
+dest.once('close',onclose);
+function onfinish(){
+debug('onfinish');
+dest.removeListener('close',onclose);
+unpipe();
+}
+dest.once('finish',onfinish);
+
+function unpipe(){
+debug('unpipe');
+src.unpipe(dest);
+}
+
+
+dest.emit('pipe',src);
+
+
+if(!state.flowing){
+debug('pipe resume');
+src.resume();
+}
+
+return dest;
+};
+
+function pipeOnDrain(src){
+return function(){
+var state=src._readableState;
+debug('pipeOnDrain',state.awaitDrain);
+if(state.awaitDrain)state.awaitDrain--;
+if(state.awaitDrain===0&&EElistenerCount(src,'data')){
+state.flowing=true;
+flow(src);
+}
+};
+}
+
+Readable.prototype.unpipe=function(dest){
+var state=this._readableState;
+var unpipeInfo={hasUnpiped:false};
+
+
+if(state.pipesCount===0)return this;
+
+
+if(state.pipesCount===1){
+
+if(dest&&dest!==state.pipes)return this;
+
+if(!dest)dest=state.pipes;
+
+
+state.pipes=null;
+state.pipesCount=0;
+state.flowing=false;
+if(dest)dest.emit('unpipe',this,unpipeInfo);
+return this;
+}
+
+
+
+if(!dest){
+
+var dests=state.pipes;
+var len=state.pipesCount;
+state.pipes=null;
+state.pipesCount=0;
+state.flowing=false;
+
+for(var i=0;i<len;i++){
+dests[i].emit('unpipe',this,unpipeInfo);
+}return this;
+}
+
+
+var index=indexOf(state.pipes,dest);
+if(index===-1)return this;
+
+state.pipes.splice(index,1);
+state.pipesCount-=1;
+if(state.pipesCount===1)state.pipes=state.pipes[0];
+
+dest.emit('unpipe',this,unpipeInfo);
+
+return this;
+};
+
+
+
+Readable.prototype.on=function(ev,fn){
+var res=Stream.prototype.on.call(this,ev,fn);
+
+if(ev==='data'){
+
+if(this._readableState.flowing!==false)this.resume();
+}else if(ev==='readable'){
+var state=this._readableState;
+if(!state.endEmitted&&!state.readableListening){
+state.readableListening=state.needReadable=true;
+state.emittedReadable=false;
+if(!state.reading){
+processNextTick(nReadingNextTick,this);
+}else if(state.length){
+emitReadable(this);
+}
+}
+}
+
+return res;
+};
+Readable.prototype.addListener=Readable.prototype.on;
+
+function nReadingNextTick(self){
+debug('readable nexttick read 0');
+self.read(0);
+}
+
+
+
+Readable.prototype.resume=function(){
+var state=this._readableState;
+if(!state.flowing){
+debug('resume');
+state.flowing=true;
+resume(this,state);
+}
+return this;
+};
+
+function resume(stream,state){
+if(!state.resumeScheduled){
+state.resumeScheduled=true;
+processNextTick(resume_,stream,state);
+}
+}
+
+function resume_(stream,state){
+if(!state.reading){
+debug('resume read 0');
+stream.read(0);
+}
+
+state.resumeScheduled=false;
+state.awaitDrain=0;
+stream.emit('resume');
+flow(stream);
+if(state.flowing&&!state.reading)stream.read(0);
+}
+
+Readable.prototype.pause=function(){
+debug('call pause flowing=%j',this._readableState.flowing);
+if(false!==this._readableState.flowing){
+debug('pause');
+this._readableState.flowing=false;
+this.emit('pause');
+}
+return this;
+};
+
+function flow(stream){
+var state=stream._readableState;
+debug('flow',state.flowing);
+while(state.flowing&&stream.read()!==null){}
+}
+
+
+
+
+Readable.prototype.wrap=function(stream){
+var state=this._readableState;
+var paused=false;
+
+var self=this;
+stream.on('end',function(){
+debug('wrapped end');
+if(state.decoder&&!state.ended){
+var chunk=state.decoder.end();
+if(chunk&&chunk.length)self.push(chunk);
+}
+
+self.push(null);
+});
+
+stream.on('data',function(chunk){
+debug('wrapped data');
+if(state.decoder)chunk=state.decoder.write(chunk);
+
+
+if(state.objectMode&&(chunk===null||chunk===undefined))return;else if(!state.objectMode&&(!chunk||!chunk.length))return;
+
+var ret=self.push(chunk);
+if(!ret){
+paused=true;
+stream.pause();
+}
+});
+
+
+
+for(var i in stream){
+if(this[i]===undefined&&typeof stream[i]==='function'){
+this[i]=function(method){
+return function(){
+return stream[method].apply(stream,arguments);
+};
+}(i);
+}
+}
+
+
+for(var n=0;n<kProxyEvents.length;n++){
+stream.on(kProxyEvents[n],self.emit.bind(self,kProxyEvents[n]));
+}
+
+
+
+self._read=function(n){
+debug('wrapped _read',n);
+if(paused){
+paused=false;
+stream.resume();
+}
+};
+
+return self;
+};
+
+
+Readable._fromList=fromList;
+
+
+
+
+
+function fromList(n,state){
+
+if(state.length===0)return null;
+
+var ret;
+if(state.objectMode)ret=state.buffer.shift();else if(!n||n>=state.length){
+
+if(state.decoder)ret=state.buffer.join('');else if(state.buffer.length===1)ret=state.buffer.head.data;else ret=state.buffer.concat(state.length);
+state.buffer.clear();
+}else{
+
+ret=fromListPartial(n,state.buffer,state.decoder);
+}
+
+return ret;
+}
+
+
+
+
+function fromListPartial(n,list,hasStrings){
+var ret;
+if(n<list.head.data.length){
+
+ret=list.head.data.slice(0,n);
+list.head.data=list.head.data.slice(n);
+}else if(n===list.head.data.length){
+
+ret=list.shift();
+}else{
+
+ret=hasStrings?copyFromBufferString(n,list):copyFromBuffer(n,list);
+}
+return ret;
+}
+
+
+
+
+
+function copyFromBufferString(n,list){
+var p=list.head;
+var c=1;
+var ret=p.data;
+n-=ret.length;
+while(p=p.next){
+var str=p.data;
+var nb=n>str.length?str.length:n;
+if(nb===str.length)ret+=str;else ret+=str.slice(0,n);
+n-=nb;
+if(n===0){
+if(nb===str.length){
+++c;
+if(p.next)list.head=p.next;else list.head=list.tail=null;
+}else{
+list.head=p;
+p.data=str.slice(nb);
+}
+break;
+}
+++c;
+}
+list.length-=c;
+return ret;
+}
+
+
+
+
+function copyFromBuffer(n,list){
+var ret=Buffer.allocUnsafe(n);
+var p=list.head;
+var c=1;
+p.data.copy(ret);
+n-=p.data.length;
+while(p=p.next){
+var buf=p.data;
+var nb=n>buf.length?buf.length:n;
+buf.copy(ret,ret.length-n,0,nb);
+n-=nb;
+if(n===0){
+if(nb===buf.length){
+++c;
+if(p.next)list.head=p.next;else list.head=list.tail=null;
+}else{
+list.head=p;
+p.data=buf.slice(nb);
+}
+break;
+}
+++c;
+}
+list.length-=c;
+return ret;
+}
+
+function endReadable(stream){
+var state=stream._readableState;
+
+
+
+if(state.length>0)throw new Error('"endReadable()" called on non-empty stream');
+
+if(!state.endEmitted){
+state.ended=true;
+processNextTick(endReadableNT,state,stream);
+}
+}
+
+function endReadableNT(state,stream){
+
+if(!state.endEmitted&&state.length===0){
+state.endEmitted=true;
+stream.readable=false;
+stream.emit('end');
+}
+}
+
+function forEach(xs,f){
+for(var i=0,l=xs.length;i<l;i++){
+f(xs[i],i);
+}
+}
+
+function indexOf(xs,x){
+for(var i=0,l=xs.length;i<l;i++){
+if(xs[i]===x)return i;
+}
+return-1;
+}
+}).call(this,require('_process'),typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{"./_stream_duplex":135,"./internal/streams/BufferList":140,"./internal/streams/destroy":141,"./internal/streams/stream":142,"_process":130,"core-util-is":89,"events":93,"inherits":98,"isarray":109,"process-nextick-args":129,"safe-buffer":150,"string_decoder/":143,"util":84}],138:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+module.exports=Transform;
+
+var Duplex=require('./_stream_duplex');
+
+
+var util=require('core-util-is');
+util.inherits=require('inherits');
+
+
+util.inherits(Transform,Duplex);
+
+function TransformState(stream){
+this.afterTransform=function(er,data){
+return afterTransform(stream,er,data);
+};
+
+this.needTransform=false;
+this.transforming=false;
+this.writecb=null;
+this.writechunk=null;
+this.writeencoding=null;
+}
+
+function afterTransform(stream,er,data){
+var ts=stream._transformState;
+ts.transforming=false;
+
+var cb=ts.writecb;
+
+if(!cb){
+return stream.emit('error',new Error('write callback called multiple times'));
+}
+
+ts.writechunk=null;
+ts.writecb=null;
+
+if(data!==null&&data!==undefined)stream.push(data);
+
+cb(er);
+
+var rs=stream._readableState;
+rs.reading=false;
+if(rs.needReadable||rs.length<rs.highWaterMark){
+stream._read(rs.highWaterMark);
+}
+}
+
+function Transform(options){
+if(!(this instanceof Transform))return new Transform(options);
+
+Duplex.call(this,options);
+
+this._transformState=new TransformState(this);
+
+var stream=this;
+
+
+this._readableState.needReadable=true;
+
+
+
+
+this._readableState.sync=false;
+
+if(options){
+if(typeof options.transform==='function')this._transform=options.transform;
+
+if(typeof options.flush==='function')this._flush=options.flush;
+}
+
+
+this.once('prefinish',function(){
+if(typeof this._flush==='function')this._flush(function(er,data){
+done(stream,er,data);
+});else done(stream);
+});
+}
+
+Transform.prototype.push=function(chunk,encoding){
+this._transformState.needTransform=false;
+return Duplex.prototype.push.call(this,chunk,encoding);
+};
+
+
+
+
+
+
+
+
+
+
+
+Transform.prototype._transform=function(chunk,encoding,cb){
+throw new Error('_transform() is not implemented');
+};
+
+Transform.prototype._write=function(chunk,encoding,cb){
+var ts=this._transformState;
+ts.writecb=cb;
+ts.writechunk=chunk;
+ts.writeencoding=encoding;
+if(!ts.transforming){
+var rs=this._readableState;
+if(ts.needTransform||rs.needReadable||rs.length<rs.highWaterMark)this._read(rs.highWaterMark);
+}
+};
+
+
+
+
+Transform.prototype._read=function(n){
+var ts=this._transformState;
+
+if(ts.writechunk!==null&&ts.writecb&&!ts.transforming){
+ts.transforming=true;
+this._transform(ts.writechunk,ts.writeencoding,ts.afterTransform);
+}else{
+
+
+ts.needTransform=true;
+}
+};
+
+Transform.prototype._destroy=function(err,cb){
+var _this=this;
+
+Duplex.prototype._destroy.call(this,err,function(err2){
+cb(err2);
+_this.emit('close');
+});
+};
+
+function done(stream,er,data){
+if(er)return stream.emit('error',er);
+
+if(data!==null&&data!==undefined)stream.push(data);
+
+
+
+var ws=stream._writableState;
+var ts=stream._transformState;
+
+if(ws.length)throw new Error('Calling transform done when ws.length != 0');
+
+if(ts.transforming)throw new Error('Calling transform done when still transforming');
+
+return stream.push(null);
+}
+},{"./_stream_duplex":135,"core-util-is":89,"inherits":98}],139:[function(require,module,exports){
+(function(process,global,setImmediate){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+
+
+var processNextTick=require('process-nextick-args');
+
+
+module.exports=Writable;
+
+
+function WriteReq(chunk,encoding,cb){
+this.chunk=chunk;
+this.encoding=encoding;
+this.callback=cb;
+this.next=null;
+}
+
+
+
+function CorkedRequest(state){
+var _this=this;
+
+this.next=null;
+this.entry=null;
+this.finish=function(){
+onCorkedFinish(_this,state);
+};
+}
+
+
+
+var asyncWrite=!process.browser&&['v0.10','v0.9.'].indexOf(process.version.slice(0,5))>-1?setImmediate:processNextTick;
+
+
+
+var Duplex;
+
+
+Writable.WritableState=WritableState;
+
+
+var util=require('core-util-is');
+util.inherits=require('inherits');
+
+
+
+var internalUtil={
+deprecate:require('util-deprecate')};
+
+
+
+
+var Stream=require('./internal/streams/stream');
+
+
+
+var Buffer=require('safe-buffer').Buffer;
+var OurUint8Array=global.Uint8Array||function(){};
+function _uint8ArrayToBuffer(chunk){
+return Buffer.from(chunk);
+}
+function _isUint8Array(obj){
+return Buffer.isBuffer(obj)||obj instanceof OurUint8Array;
+}
+
+
+var destroyImpl=require('./internal/streams/destroy');
+
+util.inherits(Writable,Stream);
+
+function nop(){}
+
+function WritableState(options,stream){
+Duplex=Duplex||require('./_stream_duplex');
+
+options=options||{};
+
+
+
+this.objectMode=!!options.objectMode;
+
+if(stream instanceof Duplex)this.objectMode=this.objectMode||!!options.writableObjectMode;
+
+
+
+
+var hwm=options.highWaterMark;
+var defaultHwm=this.objectMode?16:16*1024;
+this.highWaterMark=hwm||hwm===0?hwm:defaultHwm;
+
+
+this.highWaterMark=Math.floor(this.highWaterMark);
+
+
+this.finalCalled=false;
+
+
+this.needDrain=false;
+
+this.ending=false;
+
+this.ended=false;
+
+this.finished=false;
+
+
+this.destroyed=false;
+
+
+
+
+var noDecode=options.decodeStrings===false;
+this.decodeStrings=!noDecode;
+
+
+
+
+this.defaultEncoding=options.defaultEncoding||'utf8';
+
+
+
+
+this.length=0;
+
+
+this.writing=false;
+
+
+this.corked=0;
+
+
+
+
+
+this.sync=true;
+
+
+
+
+this.bufferProcessing=false;
+
+
+this.onwrite=function(er){
+onwrite(stream,er);
+};
+
+
+this.writecb=null;
+
+
+this.writelen=0;
+
+this.bufferedRequest=null;
+this.lastBufferedRequest=null;
+
+
+
+this.pendingcb=0;
+
+
+
+this.prefinished=false;
+
+
+this.errorEmitted=false;
+
+
+this.bufferedRequestCount=0;
+
+
+
+this.corkedRequestsFree=new CorkedRequest(this);
+}
+
+WritableState.prototype.getBuffer=function getBuffer(){
+var current=this.bufferedRequest;
+var out=[];
+while(current){
+out.push(current);
+current=current.next;
+}
+return out;
+};
+
+(function(){
+try{
+Object.defineProperty(WritableState.prototype,'buffer',{
+get:internalUtil.deprecate(function(){
+return this.getBuffer();
+},'_writableState.buffer is deprecated. Use _writableState.getBuffer '+'instead.','DEP0003')});
+
+}catch(_){}
+})();
+
+
+
+var realHasInstance;
+if(typeof Symbol==='function'&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==='function'){
+realHasInstance=Function.prototype[Symbol.hasInstance];
+Object.defineProperty(Writable,Symbol.hasInstance,{
+value:function(object){
+if(realHasInstance.call(this,object))return true;
+
+return object&&object._writableState instanceof WritableState;
+}});
+
+}else{
+realHasInstance=function(object){
+return object instanceof this;
+};
+}
+
+function Writable(options){
+Duplex=Duplex||require('./_stream_duplex');
+
+
+
+
+
+
+
+
+if(!realHasInstance.call(Writable,this)&&!(this instanceof Duplex)){
+return new Writable(options);
+}
+
+this._writableState=new WritableState(options,this);
+
+
+this.writable=true;
+
+if(options){
+if(typeof options.write==='function')this._write=options.write;
+
+if(typeof options.writev==='function')this._writev=options.writev;
+
+if(typeof options.destroy==='function')this._destroy=options.destroy;
+
+if(typeof options.final==='function')this._final=options.final;
+}
+
+Stream.call(this);
+}
+
+
+Writable.prototype.pipe=function(){
+this.emit('error',new Error('Cannot pipe, not readable'));
+};
+
+function writeAfterEnd(stream,cb){
+var er=new Error('write after end');
+
+stream.emit('error',er);
+processNextTick(cb,er);
+}
+
+
+
+
+function validChunk(stream,state,chunk,cb){
+var valid=true;
+var er=false;
+
+if(chunk===null){
+er=new TypeError('May not write null values to stream');
+}else if(typeof chunk!=='string'&&chunk!==undefined&&!state.objectMode){
+er=new TypeError('Invalid non-string/buffer chunk');
+}
+if(er){
+stream.emit('error',er);
+processNextTick(cb,er);
+valid=false;
+}
+return valid;
+}
+
+Writable.prototype.write=function(chunk,encoding,cb){
+var state=this._writableState;
+var ret=false;
+var isBuf=_isUint8Array(chunk)&&!state.objectMode;
+
+if(isBuf&&!Buffer.isBuffer(chunk)){
+chunk=_uint8ArrayToBuffer(chunk);
+}
+
+if(typeof encoding==='function'){
+cb=encoding;
+encoding=null;
+}
+
+if(isBuf)encoding='buffer';else if(!encoding)encoding=state.defaultEncoding;
+
+if(typeof cb!=='function')cb=nop;
+
+if(state.ended)writeAfterEnd(this,cb);else if(isBuf||validChunk(this,state,chunk,cb)){
+state.pendingcb++;
+ret=writeOrBuffer(this,state,isBuf,chunk,encoding,cb);
+}
+
+return ret;
+};
+
+Writable.prototype.cork=function(){
+var state=this._writableState;
+
+state.corked++;
+};
+
+Writable.prototype.uncork=function(){
+var state=this._writableState;
+
+if(state.corked){
+state.corked--;
+
+if(!state.writing&&!state.corked&&!state.finished&&!state.bufferProcessing&&state.bufferedRequest)clearBuffer(this,state);
+}
+};
+
+Writable.prototype.setDefaultEncoding=function setDefaultEncoding(encoding){
+
+if(typeof encoding==='string')encoding=encoding.toLowerCase();
+if(!(['hex','utf8','utf-8','ascii','binary','base64','ucs2','ucs-2','utf16le','utf-16le','raw'].indexOf((encoding+'').toLowerCase())>-1))throw new TypeError('Unknown encoding: '+encoding);
+this._writableState.defaultEncoding=encoding;
+return this;
+};
+
+function decodeChunk(state,chunk,encoding){
+if(!state.objectMode&&state.decodeStrings!==false&&typeof chunk==='string'){
+chunk=Buffer.from(chunk,encoding);
+}
+return chunk;
+}
+
+
+
+
+function writeOrBuffer(stream,state,isBuf,chunk,encoding,cb){
+if(!isBuf){
+var newChunk=decodeChunk(state,chunk,encoding);
+if(chunk!==newChunk){
+isBuf=true;
+encoding='buffer';
+chunk=newChunk;
+}
+}
+var len=state.objectMode?1:chunk.length;
+
+state.length+=len;
+
+var ret=state.length<state.highWaterMark;
+
+if(!ret)state.needDrain=true;
+
+if(state.writing||state.corked){
+var last=state.lastBufferedRequest;
+state.lastBufferedRequest={
+chunk:chunk,
+encoding:encoding,
+isBuf:isBuf,
+callback:cb,
+next:null};
+
+if(last){
+last.next=state.lastBufferedRequest;
+}else{
+state.bufferedRequest=state.lastBufferedRequest;
+}
+state.bufferedRequestCount+=1;
+}else{
+doWrite(stream,state,false,len,chunk,encoding,cb);
+}
+
+return ret;
+}
+
+function doWrite(stream,state,writev,len,chunk,encoding,cb){
+state.writelen=len;
+state.writecb=cb;
+state.writing=true;
+state.sync=true;
+if(writev)stream._writev(chunk,state.onwrite);else stream._write(chunk,encoding,state.onwrite);
+state.sync=false;
+}
+
+function onwriteError(stream,state,sync,er,cb){
+--state.pendingcb;
+
+if(sync){
+
+
+processNextTick(cb,er);
+
+
+processNextTick(finishMaybe,stream,state);
+stream._writableState.errorEmitted=true;
+stream.emit('error',er);
+}else{
+
+
+cb(er);
+stream._writableState.errorEmitted=true;
+stream.emit('error',er);
+
+
+finishMaybe(stream,state);
+}
+}
+
+function onwriteStateUpdate(state){
+state.writing=false;
+state.writecb=null;
+state.length-=state.writelen;
+state.writelen=0;
+}
+
+function onwrite(stream,er){
+var state=stream._writableState;
+var sync=state.sync;
+var cb=state.writecb;
+
+onwriteStateUpdate(state);
+
+if(er)onwriteError(stream,state,sync,er,cb);else{
+
+var finished=needFinish(state);
+
+if(!finished&&!state.corked&&!state.bufferProcessing&&state.bufferedRequest){
+clearBuffer(stream,state);
+}
+
+if(sync){
+
+asyncWrite(afterWrite,stream,state,finished,cb);
+
+}else{
+afterWrite(stream,state,finished,cb);
+}
+}
+}
+
+function afterWrite(stream,state,finished,cb){
+if(!finished)onwriteDrain(stream,state);
+state.pendingcb--;
+cb();
+finishMaybe(stream,state);
+}
+
+
+
+
+function onwriteDrain(stream,state){
+if(state.length===0&&state.needDrain){
+state.needDrain=false;
+stream.emit('drain');
+}
+}
+
+
+function clearBuffer(stream,state){
+state.bufferProcessing=true;
+var entry=state.bufferedRequest;
+
+if(stream._writev&&entry&&entry.next){
+
+var l=state.bufferedRequestCount;
+var buffer=new Array(l);
+var holder=state.corkedRequestsFree;
+holder.entry=entry;
+
+var count=0;
+var allBuffers=true;
+while(entry){
+buffer[count]=entry;
+if(!entry.isBuf)allBuffers=false;
+entry=entry.next;
+count+=1;
+}
+buffer.allBuffers=allBuffers;
+
+doWrite(stream,state,true,state.length,buffer,'',holder.finish);
+
+
+
+state.pendingcb++;
+state.lastBufferedRequest=null;
+if(holder.next){
+state.corkedRequestsFree=holder.next;
+holder.next=null;
+}else{
+state.corkedRequestsFree=new CorkedRequest(state);
+}
+}else{
+
+while(entry){
+var chunk=entry.chunk;
+var encoding=entry.encoding;
+var cb=entry.callback;
+var len=state.objectMode?1:chunk.length;
+
+doWrite(stream,state,false,len,chunk,encoding,cb);
+entry=entry.next;
+
+
+
+
+if(state.writing){
+break;
+}
+}
+
+if(entry===null)state.lastBufferedRequest=null;
+}
+
+state.bufferedRequestCount=0;
+state.bufferedRequest=entry;
+state.bufferProcessing=false;
+}
+
+Writable.prototype._write=function(chunk,encoding,cb){
+cb(new Error('_write() is not implemented'));
+};
+
+Writable.prototype._writev=null;
+
+Writable.prototype.end=function(chunk,encoding,cb){
+var state=this._writableState;
+
+if(typeof chunk==='function'){
+cb=chunk;
+chunk=null;
+encoding=null;
+}else if(typeof encoding==='function'){
+cb=encoding;
+encoding=null;
+}
+
+if(chunk!==null&&chunk!==undefined)this.write(chunk,encoding);
+
+
+if(state.corked){
+state.corked=1;
+this.uncork();
+}
+
+
+if(!state.ending&&!state.finished)endWritable(this,state,cb);
+};
+
+function needFinish(state){
+return state.ending&&state.length===0&&state.bufferedRequest===null&&!state.finished&&!state.writing;
+}
+function callFinal(stream,state){
+stream._final(function(err){
+state.pendingcb--;
+if(err){
+stream.emit('error',err);
+}
+state.prefinished=true;
+stream.emit('prefinish');
+finishMaybe(stream,state);
+});
+}
+function prefinish(stream,state){
+if(!state.prefinished&&!state.finalCalled){
+if(typeof stream._final==='function'){
+state.pendingcb++;
+state.finalCalled=true;
+processNextTick(callFinal,stream,state);
+}else{
+state.prefinished=true;
+stream.emit('prefinish');
+}
+}
+}
+
+function finishMaybe(stream,state){
+var need=needFinish(state);
+if(need){
+prefinish(stream,state);
+if(state.pendingcb===0){
+state.finished=true;
+stream.emit('finish');
+}
+}
+return need;
+}
+
+function endWritable(stream,state,cb){
+state.ending=true;
+finishMaybe(stream,state);
+if(cb){
+if(state.finished)processNextTick(cb);else stream.once('finish',cb);
+}
+state.ended=true;
+stream.writable=false;
+}
+
+function onCorkedFinish(corkReq,state,err){
+var entry=corkReq.entry;
+corkReq.entry=null;
+while(entry){
+var cb=entry.callback;
+state.pendingcb--;
+cb(err);
+entry=entry.next;
+}
+if(state.corkedRequestsFree){
+state.corkedRequestsFree.next=corkReq;
+}else{
+state.corkedRequestsFree=corkReq;
+}
+}
+
+Object.defineProperty(Writable.prototype,'destroyed',{
+get:function(){
+if(this._writableState===undefined){
+return false;
+}
+return this._writableState.destroyed;
+},
+set:function(value){
+
+
+if(!this._writableState){
+return;
+}
+
+
+
+this._writableState.destroyed=value;
+}});
+
+
+Writable.prototype.destroy=destroyImpl.destroy;
+Writable.prototype._undestroy=destroyImpl.undestroy;
+Writable.prototype._destroy=function(err,cb){
+this.end();
+cb(err);
+};
+}).call(this,require('_process'),typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{},require("timers").setImmediate);
+},{"./_stream_duplex":135,"./internal/streams/destroy":141,"./internal/streams/stream":142,"_process":130,"core-util-is":89,"inherits":98,"process-nextick-args":129,"safe-buffer":150,"timers":156,"util-deprecate":157}],140:[function(require,module,exports){
+'use strict';
+
+
+
+function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}
+
+var Buffer=require('safe-buffer').Buffer;
+
+
+function copyBuffer(src,target,offset){
+src.copy(target,offset);
+}
+
+module.exports=function(){
+function BufferList(){
+_classCallCheck(this,BufferList);
+
+this.head=null;
+this.tail=null;
+this.length=0;
+}
+
+BufferList.prototype.push=function push(v){
+var entry={data:v,next:null};
+if(this.length>0)this.tail.next=entry;else this.head=entry;
+this.tail=entry;
+++this.length;
+};
+
+BufferList.prototype.unshift=function unshift(v){
+var entry={data:v,next:this.head};
+if(this.length===0)this.tail=entry;
+this.head=entry;
+++this.length;
+};
+
+BufferList.prototype.shift=function shift(){
+if(this.length===0)return;
+var ret=this.head.data;
+if(this.length===1)this.head=this.tail=null;else this.head=this.head.next;
+--this.length;
+return ret;
+};
+
+BufferList.prototype.clear=function clear(){
+this.head=this.tail=null;
+this.length=0;
+};
+
+BufferList.prototype.join=function join(s){
+if(this.length===0)return'';
+var p=this.head;
+var ret=''+p.data;
+while(p=p.next){
+ret+=s+p.data;
+}return ret;
+};
+
+BufferList.prototype.concat=function concat(n){
+if(this.length===0)return Buffer.alloc(0);
+if(this.length===1)return this.head.data;
+var ret=Buffer.allocUnsafe(n>>>0);
+var p=this.head;
+var i=0;
+while(p){
+copyBuffer(p.data,ret,i);
+i+=p.data.length;
+p=p.next;
+}
+return ret;
+};
+
+return BufferList;
+}();
+},{"safe-buffer":150}],141:[function(require,module,exports){
+'use strict';
+
+
+
+var processNextTick=require('process-nextick-args');
+
+
+
+function destroy(err,cb){
+var _this=this;
+
+var readableDestroyed=this._readableState&&this._readableState.destroyed;
+var writableDestroyed=this._writableState&&this._writableState.destroyed;
+
+if(readableDestroyed||writableDestroyed){
+if(cb){
+cb(err);
+}else if(err&&(!this._writableState||!this._writableState.errorEmitted)){
+processNextTick(emitErrorNT,this,err);
+}
+return;
+}
+
+
+
+
+if(this._readableState){
+this._readableState.destroyed=true;
+}
+
+
+if(this._writableState){
+this._writableState.destroyed=true;
+}
+
+this._destroy(err||null,function(err){
+if(!cb&&err){
+processNextTick(emitErrorNT,_this,err);
+if(_this._writableState){
+_this._writableState.errorEmitted=true;
+}
+}else if(cb){
+cb(err);
+}
+});
+}
+
+function undestroy(){
+if(this._readableState){
+this._readableState.destroyed=false;
+this._readableState.reading=false;
+this._readableState.ended=false;
+this._readableState.endEmitted=false;
+}
+
+if(this._writableState){
+this._writableState.destroyed=false;
+this._writableState.ended=false;
+this._writableState.ending=false;
+this._writableState.finished=false;
+this._writableState.errorEmitted=false;
+}
+}
+
+function emitErrorNT(self,err){
+self.emit('error',err);
+}
+
+module.exports={
+destroy:destroy,
+undestroy:undestroy};
+
+},{"process-nextick-args":129}],142:[function(require,module,exports){
+module.exports=require('events').EventEmitter;
+
+},{"events":93}],143:[function(require,module,exports){
+'use strict';
+
+var Buffer=require('safe-buffer').Buffer;
+
+var isEncoding=Buffer.isEncoding||function(encoding){
+encoding=''+encoding;
+switch(encoding&&encoding.toLowerCase()){
+case'hex':case'utf8':case'utf-8':case'ascii':case'binary':case'base64':case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':case'raw':
+return true;
+default:
+return false;}
+
+};
+
+function _normalizeEncoding(enc){
+if(!enc)return'utf8';
+var retried;
+while(true){
+switch(enc){
+case'utf8':
+case'utf-8':
+return'utf8';
+case'ucs2':
+case'ucs-2':
+case'utf16le':
+case'utf-16le':
+return'utf16le';
+case'latin1':
+case'binary':
+return'latin1';
+case'base64':
+case'ascii':
+case'hex':
+return enc;
+default:
+if(retried)return;
+enc=(''+enc).toLowerCase();
+retried=true;}
+
+}
+};
+
+
+
+function normalizeEncoding(enc){
+var nenc=_normalizeEncoding(enc);
+if(typeof nenc!=='string'&&(Buffer.isEncoding===isEncoding||!isEncoding(enc)))throw new Error('Unknown encoding: '+enc);
+return nenc||enc;
+}
+
+
+
+
+exports.StringDecoder=StringDecoder;
+function StringDecoder(encoding){
+this.encoding=normalizeEncoding(encoding);
+var nb;
+switch(this.encoding){
+case'utf16le':
+this.text=utf16Text;
+this.end=utf16End;
+nb=4;
+break;
+case'utf8':
+this.fillLast=utf8FillLast;
+nb=4;
+break;
+case'base64':
+this.text=base64Text;
+this.end=base64End;
+nb=3;
+break;
+default:
+this.write=simpleWrite;
+this.end=simpleEnd;
+return;}
+
+this.lastNeed=0;
+this.lastTotal=0;
+this.lastChar=Buffer.allocUnsafe(nb);
+}
+
+StringDecoder.prototype.write=function(buf){
+if(buf.length===0)return'';
+var r;
+var i;
+if(this.lastNeed){
+r=this.fillLast(buf);
+if(r===undefined)return'';
+i=this.lastNeed;
+this.lastNeed=0;
+}else{
+i=0;
+}
+if(i<buf.length)return r?r+this.text(buf,i):this.text(buf,i);
+return r||'';
+};
+
+StringDecoder.prototype.end=utf8End;
+
+
+StringDecoder.prototype.text=utf8Text;
+
+
+StringDecoder.prototype.fillLast=function(buf){
+if(this.lastNeed<=buf.length){
+buf.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed);
+return this.lastChar.toString(this.encoding,0,this.lastTotal);
+}
+buf.copy(this.lastChar,this.lastTotal-this.lastNeed,0,buf.length);
+this.lastNeed-=buf.length;
+};
+
+
+
+function utf8CheckByte(byte){
+if(byte<=0x7F)return 0;else if(byte>>5===0x06)return 2;else if(byte>>4===0x0E)return 3;else if(byte>>3===0x1E)return 4;
+return-1;
+}
+
+
+
+
+function utf8CheckIncomplete(self,buf,i){
+var j=buf.length-1;
+if(j<i)return 0;
+var nb=utf8CheckByte(buf[j]);
+if(nb>=0){
+if(nb>0)self.lastNeed=nb-1;
+return nb;
+}
+if(--j<i)return 0;
+nb=utf8CheckByte(buf[j]);
+if(nb>=0){
+if(nb>0)self.lastNeed=nb-2;
+return nb;
+}
+if(--j<i)return 0;
+nb=utf8CheckByte(buf[j]);
+if(nb>=0){
+if(nb>0){
+if(nb===2)nb=0;else self.lastNeed=nb-3;
+}
+return nb;
+}
+return 0;
+}
+
+
+
+
+
+
+
+
+
+function utf8CheckExtraBytes(self,buf,p){
+if((buf[0]&0xC0)!==0x80){
+self.lastNeed=0;
+return'\ufffd'.repeat(p);
+}
+if(self.lastNeed>1&&buf.length>1){
+if((buf[1]&0xC0)!==0x80){
+self.lastNeed=1;
+return'\ufffd'.repeat(p+1);
+}
+if(self.lastNeed>2&&buf.length>2){
+if((buf[2]&0xC0)!==0x80){
+self.lastNeed=2;
+return'\ufffd'.repeat(p+2);
+}
+}
+}
+}
+
+
+function utf8FillLast(buf){
+var p=this.lastTotal-this.lastNeed;
+var r=utf8CheckExtraBytes(this,buf,p);
+if(r!==undefined)return r;
+if(this.lastNeed<=buf.length){
+buf.copy(this.lastChar,p,0,this.lastNeed);
+return this.lastChar.toString(this.encoding,0,this.lastTotal);
+}
+buf.copy(this.lastChar,p,0,buf.length);
+this.lastNeed-=buf.length;
+}
+
+
+
+
+function utf8Text(buf,i){
+var total=utf8CheckIncomplete(this,buf,i);
+if(!this.lastNeed)return buf.toString('utf8',i);
+this.lastTotal=total;
+var end=buf.length-(total-this.lastNeed);
+buf.copy(this.lastChar,0,end);
+return buf.toString('utf8',i,end);
+}
+
+
+
+function utf8End(buf){
+var r=buf&&buf.length?this.write(buf):'';
+if(this.lastNeed)return r+'\ufffd'.repeat(this.lastTotal-this.lastNeed);
+return r;
+}
+
+
+
+
+
+function utf16Text(buf,i){
+if((buf.length-i)%2===0){
+var r=buf.toString('utf16le',i);
+if(r){
+var c=r.charCodeAt(r.length-1);
+if(c>=0xD800&&c<=0xDBFF){
+this.lastNeed=2;
+this.lastTotal=4;
+this.lastChar[0]=buf[buf.length-2];
+this.lastChar[1]=buf[buf.length-1];
+return r.slice(0,-1);
+}
+}
+return r;
+}
+this.lastNeed=1;
+this.lastTotal=2;
+this.lastChar[0]=buf[buf.length-1];
+return buf.toString('utf16le',i,buf.length-1);
+}
+
+
+
+function utf16End(buf){
+var r=buf&&buf.length?this.write(buf):'';
+if(this.lastNeed){
+var end=this.lastTotal-this.lastNeed;
+return r+this.lastChar.toString('utf16le',0,end);
+}
+return r;
+}
+
+function base64Text(buf,i){
+var n=(buf.length-i)%3;
+if(n===0)return buf.toString('base64',i);
+this.lastNeed=3-n;
+this.lastTotal=3;
+if(n===1){
+this.lastChar[0]=buf[buf.length-1];
+}else{
+this.lastChar[0]=buf[buf.length-2];
+this.lastChar[1]=buf[buf.length-1];
+}
+return buf.toString('base64',i,buf.length-n);
+}
+
+function base64End(buf){
+var r=buf&&buf.length?this.write(buf):'';
+if(this.lastNeed)return r+this.lastChar.toString('base64',0,3-this.lastNeed);
+return r;
+}
+
+
+function simpleWrite(buf){
+return buf.toString(this.encoding);
+}
+
+function simpleEnd(buf){
+return buf&&buf.length?this.write(buf):'';
+}
+},{"safe-buffer":150}],144:[function(require,module,exports){
+module.exports=require('./readable').PassThrough;
+
+},{"./readable":145}],145:[function(require,module,exports){
+exports=module.exports=require('./lib/_stream_readable.js');
+exports.Stream=exports;
+exports.Readable=exports;
+exports.Writable=require('./lib/_stream_writable.js');
+exports.Duplex=require('./lib/_stream_duplex.js');
+exports.Transform=require('./lib/_stream_transform.js');
+exports.PassThrough=require('./lib/_stream_passthrough.js');
+
+},{"./lib/_stream_duplex.js":135,"./lib/_stream_passthrough.js":136,"./lib/_stream_readable.js":137,"./lib/_stream_transform.js":138,"./lib/_stream_writable.js":139}],146:[function(require,module,exports){
+module.exports=require('./readable').Transform;
+
+},{"./readable":145}],147:[function(require,module,exports){
+module.exports=require('./lib/_stream_writable.js');
+
+},{"./lib/_stream_writable.js":139}],148:[function(require,module,exports){
+var URL=require('url').URL;
+
+
+
+
+
+
+
+
+
+
+
+function trimLine(line){
+if(!line){
+return null;
+}
+
+if(Array.isArray(line)){
+return line.map(trimLine);
+}
+
+return String(line).trim();
+}
+
+
+
+
+
+
+
+
+function removeComments(line){
+var commentStartIndex=line.indexOf('#');
+if(commentStartIndex>-1){
+return line.substr(0,commentStartIndex);
+}
+
+return line;
+}
+
+
+
+
+
+
+
+
+function splitLine(line){
+var idx=String(line).indexOf(':');
+
+if(!line||idx<0){
+return null;
+}
+
+return[line.slice(0,idx),line.slice(idx+1)];
+}
+
+
+
+
+
+
+
+
+
+function formatUserAgent(userAgent){
+var formattedUserAgent=userAgent.toLowerCase();
+
+
+var idx=formattedUserAgent.indexOf('/');
+if(idx>-1){
+formattedUserAgent=formattedUserAgent.substr(0,idx);
+}
+
+return formattedUserAgent.trim();
+}
+
+
+
+
+
+
+
+
+
+function normaliseEncoding(path){
+try{
+return urlEncodeToUpper(encodeURI(path).replace(/%25/g,'%'));
+}catch(e){
+return path;
+}
+}
+
+
+
+
+
+
+
+
+
+
+function urlEncodeToUpper(path){
+return path.replace(/%[0-9a-fA-F]{2}/g,function(match){
+return match.toUpperCase();
+});
+}
+
+
+
+
+
+
+
+
+
+
+
+function parsePattern(pattern){
+var regexSpecialChars=/[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g;
+var wildCardPattern=/\*/g;
+var endOfLinePattern=/\\\$$/;
+
+pattern=normaliseEncoding(pattern);
+
+if(pattern.indexOf('*')<0&&pattern.indexOf('$')<0){
+return pattern;
+}
+
+pattern=pattern.
+replace(regexSpecialChars,'\\$&').
+replace(wildCardPattern,'(?:.*)').
+replace(endOfLinePattern,'$');
+
+return new RegExp(pattern);
+}
+
+function parseRobots(contents,robots){
+var newlineRegex=/\r\n|\r|\n/;
+var lines=contents.
+split(newlineRegex).
+map(removeComments).
+map(splitLine).
+map(trimLine);
+
+var currentUserAgents=[];
+var isNoneUserAgentState=true;
+for(var i=0;i<lines.length;i++){
+var line=lines[i];
+
+if(!line||!line[0]){
+continue;
+}
+
+switch(line[0].toLowerCase()){
+case'user-agent':
+if(isNoneUserAgentState){
+currentUserAgents.length=0;
+}
+
+if(line[1]){
+currentUserAgents.push(formatUserAgent(line[1]));
+}
+break;
+case'disallow':
+robots.addRule(currentUserAgents,line[1],false,i+1);
+break;
+case'allow':
+robots.addRule(currentUserAgents,line[1],true,i+1);
+break;
+case'crawl-delay':
+robots.setCrawlDelay(currentUserAgents,line[1]);
+break;
+case'sitemap':
+if(line[1]){
+robots.addSitemap(line[1]);
+}
+break;
+case'host':
+if(line[1]){
+robots.setPreferredHost(line[1].toLowerCase());
+}
+break;}
+
+
+isNoneUserAgentState=line[0].toLowerCase()!=='user-agent';
+}
+}
+
+
+
+
+
+
+
+
+
+function findRule(path,rules){
+var matchingRule=null;
+
+for(var i=0;i<rules.length;i++){
+var rule=rules[i];
+
+if(typeof rule.pattern==='string'){
+if(path.indexOf(rule.pattern)!==0){
+continue;
+}
+
+
+if(!matchingRule||rule.pattern.length>matchingRule.pattern.length){
+matchingRule=rule;
+}
+
+
+}else if(rule.pattern.test(path)){
+return rule;
+}
+}
+
+return matchingRule;
+}
+
+
+
+
+
+
+
+
+
+
+function parseUrl(url){
+try{
+return new URL(url);
+}catch(e){
+return null;
+}
+}
+
+
+function Robots(url,contents){
+this._url=parseUrl(url)||{};
+this._url.port=this._url.port||80;
+
+this._rules={};
+this._sitemaps=[];
+this._preferedHost=null;
+
+parseRobots(contents||'',this);
+}
+
+
+
+
+
+
+
+
+
+
+Robots.prototype.addRule=function(userAgents,pattern,allow,lineNumber){
+var rules=this._rules;
+
+userAgents.forEach(function(userAgent){
+rules[userAgent]=rules[userAgent]||[];
+
+if(!pattern){
+return;
+}
+
+rules[userAgent].push({
+pattern:parsePattern(pattern),
+allow:allow,
+lineNumber:lineNumber});
+
+});
+};
+
+
+
+
+
+
+
+Robots.prototype.setCrawlDelay=function(userAgents,delayStr){
+var rules=this._rules;
+var delay=Number(delayStr);
+
+userAgents.forEach(function(userAgent){
+rules[userAgent]=rules[userAgent]||[];
+
+if(isNaN(delay)){
+return;
+}
+
+rules[userAgent].crawlDelay=delay;
+});
+};
+
+
+
+
+
+
+Robots.prototype.addSitemap=function(url){
+this._sitemaps.push(url);
+};
+
+
+
+
+
+
+Robots.prototype.setPreferredHost=function(url){
+this._preferedHost=url;
+};
+
+Robots.prototype._getRule=function(url,ua){
+var parsedUrl=parseUrl(url)||{};
+var userAgent=formatUserAgent(ua||'*');
+
+parsedUrl.port=parsedUrl.port||'80';
+
+
+if(parsedUrl.protocol!==this._url.protocol||
+parsedUrl.hostname!==this._url.hostname||
+parsedUrl.port!==this._url.port){
+return;
+}
+
+var rules=this._rules[userAgent]||this._rules['*']||[];
+var path=urlEncodeToUpper(parsedUrl.pathname+parsedUrl.search);
+var rule=findRule(path,rules);
+
+return rule;
+};
+
+
+
+
+
+
+
+
+
+
+
+Robots.prototype.isAllowed=function(url,ua){
+var rule=this._getRule(url,ua);
+
+if(typeof rule==='undefined'){
+return;
+}
+
+return!rule||rule.allow;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Robots.prototype.getMatchingLineNumber=function(url,ua){
+var rule=this._getRule(url,ua);
+
+return rule?rule.lineNumber:-1;
+};
+
+
+
+
+
+
+
+
+Robots.prototype.isDisallowed=function(url,ua){
+return!this.isAllowed(url,ua);
+};
+
+
+
+
+
+
+
+
+
+Robots.prototype.getCrawlDelay=function(ua){
+var userAgent=formatUserAgent(ua||'*');
+
+return(this._rules[userAgent]||this._rules['*']||{}).crawlDelay;
+};
+
+
+
+
+
+
+Robots.prototype.getPreferredHost=function(){
+return this._preferedHost;
+};
+
+
+
+
+
+
+Robots.prototype.getSitemaps=function(){
+return this._sitemaps.slice(0);
+};
+
+module.exports=Robots;
+
+},{"url":"url"}],149:[function(require,module,exports){
+var Robots=require('./Robots');
+
+module.exports=function(url,contents){
+return new Robots(url,contents);
+};
+},{"./Robots":148}],150:[function(require,module,exports){
+
+var buffer=require('buffer');
+var Buffer=buffer.Buffer;
+
+
+function copyProps(src,dst){
+for(var key in src){
+dst[key]=src[key];
+}
+}
+if(Buffer.from&&Buffer.alloc&&Buffer.allocUnsafe&&Buffer.allocUnsafeSlow){
+module.exports=buffer;
+}else{
+
+copyProps(buffer,exports);
+exports.Buffer=SafeBuffer;
+}
+
+function SafeBuffer(arg,encodingOrOffset,length){
+return Buffer(arg,encodingOrOffset,length);
+}
+
+
+copyProps(Buffer,SafeBuffer);
+
+SafeBuffer.from=function(arg,encodingOrOffset,length){
+if(typeof arg==='number'){
+throw new TypeError('Argument must not be a number');
+}
+return Buffer(arg,encodingOrOffset,length);
+};
+
+SafeBuffer.alloc=function(size,fill,encoding){
+if(typeof size!=='number'){
+throw new TypeError('Argument must be a number');
+}
+var buf=Buffer(size);
+if(fill!==undefined){
+if(typeof encoding==='string'){
+buf.fill(fill,encoding);
+}else{
+buf.fill(fill);
+}
+}else{
+buf.fill(0);
+}
+return buf;
+};
+
+SafeBuffer.allocUnsafe=function(size){
+if(typeof size!=='number'){
+throw new TypeError('Argument must be a number');
+}
+return Buffer(size);
+};
+
+SafeBuffer.allocUnsafeSlow=function(size){
+if(typeof size!=='number'){
+throw new TypeError('Argument must be a number');
+}
+return buffer.SlowBuffer(size);
+};
+
+},{"buffer":88}],151:[function(require,module,exports){
+(function(process){
+exports=module.exports=SemVer;
+
+
+var debug;
+if(typeof process==='object'&&
+process.env&&
+process.env.NODE_DEBUG&&
+/\bsemver\b/i.test(process.env.NODE_DEBUG))
+debug=function(){
+var args=Array.prototype.slice.call(arguments,0);
+args.unshift('SEMVER');
+console.log.apply(console,args);
+};else
+
+debug=function(){};
+
+
+
+exports.SEMVER_SPEC_VERSION='2.0.0';
+
+var MAX_LENGTH=256;
+var MAX_SAFE_INTEGER=Number.MAX_SAFE_INTEGER||9007199254740991;
+
+
+var re=exports.re=[];
+var src=exports.src=[];
+var R=0;
+
+
+
+
+
+
+
+var NUMERICIDENTIFIER=R++;
+src[NUMERICIDENTIFIER]='0|[1-9]\\d*';
+var NUMERICIDENTIFIERLOOSE=R++;
+src[NUMERICIDENTIFIERLOOSE]='[0-9]+';
+
+
+
+
+
+
+var NONNUMERICIDENTIFIER=R++;
+src[NONNUMERICIDENTIFIER]='\\d*[a-zA-Z-][a-zA-Z0-9-]*';
+
+
+
+
+
+var MAINVERSION=R++;
+src[MAINVERSION]='('+src[NUMERICIDENTIFIER]+')\\.'+
+'('+src[NUMERICIDENTIFIER]+')\\.'+
+'('+src[NUMERICIDENTIFIER]+')';
+
+var MAINVERSIONLOOSE=R++;
+src[MAINVERSIONLOOSE]='('+src[NUMERICIDENTIFIERLOOSE]+')\\.'+
+'('+src[NUMERICIDENTIFIERLOOSE]+')\\.'+
+'('+src[NUMERICIDENTIFIERLOOSE]+')';
+
+
+
+
+var PRERELEASEIDENTIFIER=R++;
+src[PRERELEASEIDENTIFIER]='(?:'+src[NUMERICIDENTIFIER]+
+'|'+src[NONNUMERICIDENTIFIER]+')';
+
+var PRERELEASEIDENTIFIERLOOSE=R++;
+src[PRERELEASEIDENTIFIERLOOSE]='(?:'+src[NUMERICIDENTIFIERLOOSE]+
+'|'+src[NONNUMERICIDENTIFIER]+')';
+
+
+
+
+
+
+var PRERELEASE=R++;
+src[PRERELEASE]='(?:-('+src[PRERELEASEIDENTIFIER]+
+'(?:\\.'+src[PRERELEASEIDENTIFIER]+')*))';
+
+var PRERELEASELOOSE=R++;
+src[PRERELEASELOOSE]='(?:-?('+src[PRERELEASEIDENTIFIERLOOSE]+
+'(?:\\.'+src[PRERELEASEIDENTIFIERLOOSE]+')*))';
+
+
+
+
+var BUILDIDENTIFIER=R++;
+src[BUILDIDENTIFIER]='[0-9A-Za-z-]+';
+
+
+
+
+
+var BUILD=R++;
+src[BUILD]='(?:\\+('+src[BUILDIDENTIFIER]+
+'(?:\\.'+src[BUILDIDENTIFIER]+')*))';
+
+
+
+
+
+
+
+
+
+
+
+var FULL=R++;
+var FULLPLAIN='v?'+src[MAINVERSION]+
+src[PRERELEASE]+'?'+
+src[BUILD]+'?';
+
+src[FULL]='^'+FULLPLAIN+'$';
+
+
+
+
+var LOOSEPLAIN='[v=\\s]*'+src[MAINVERSIONLOOSE]+
+src[PRERELEASELOOSE]+'?'+
+src[BUILD]+'?';
+
+var LOOSE=R++;
+src[LOOSE]='^'+LOOSEPLAIN+'$';
+
+var GTLT=R++;
+src[GTLT]='((?:<|>)?=?)';
+
+
+
+
+var XRANGEIDENTIFIERLOOSE=R++;
+src[XRANGEIDENTIFIERLOOSE]=src[NUMERICIDENTIFIERLOOSE]+'|x|X|\\*';
+var XRANGEIDENTIFIER=R++;
+src[XRANGEIDENTIFIER]=src[NUMERICIDENTIFIER]+'|x|X|\\*';
+
+var XRANGEPLAIN=R++;
+src[XRANGEPLAIN]='[v=\\s]*('+src[XRANGEIDENTIFIER]+')'+
+'(?:\\.('+src[XRANGEIDENTIFIER]+')'+
+'(?:\\.('+src[XRANGEIDENTIFIER]+')'+
+'(?:'+src[PRERELEASE]+')?'+
+src[BUILD]+'?'+
+')?)?';
+
+var XRANGEPLAINLOOSE=R++;
+src[XRANGEPLAINLOOSE]='[v=\\s]*('+src[XRANGEIDENTIFIERLOOSE]+')'+
+'(?:\\.('+src[XRANGEIDENTIFIERLOOSE]+')'+
+'(?:\\.('+src[XRANGEIDENTIFIERLOOSE]+')'+
+'(?:'+src[PRERELEASELOOSE]+')?'+
+src[BUILD]+'?'+
+')?)?';
+
+var XRANGE=R++;
+src[XRANGE]='^'+src[GTLT]+'\\s*'+src[XRANGEPLAIN]+'$';
+var XRANGELOOSE=R++;
+src[XRANGELOOSE]='^'+src[GTLT]+'\\s*'+src[XRANGEPLAINLOOSE]+'$';
+
+
+
+var LONETILDE=R++;
+src[LONETILDE]='(?:~>?)';
+
+var TILDETRIM=R++;
+src[TILDETRIM]='(\\s*)'+src[LONETILDE]+'\\s+';
+re[TILDETRIM]=new RegExp(src[TILDETRIM],'g');
+var tildeTrimReplace='$1~';
+
+var TILDE=R++;
+src[TILDE]='^'+src[LONETILDE]+src[XRANGEPLAIN]+'$';
+var TILDELOOSE=R++;
+src[TILDELOOSE]='^'+src[LONETILDE]+src[XRANGEPLAINLOOSE]+'$';
+
+
+
+var LONECARET=R++;
+src[LONECARET]='(?:\\^)';
+
+var CARETTRIM=R++;
+src[CARETTRIM]='(\\s*)'+src[LONECARET]+'\\s+';
+re[CARETTRIM]=new RegExp(src[CARETTRIM],'g');
+var caretTrimReplace='$1^';
+
+var CARET=R++;
+src[CARET]='^'+src[LONECARET]+src[XRANGEPLAIN]+'$';
+var CARETLOOSE=R++;
+src[CARETLOOSE]='^'+src[LONECARET]+src[XRANGEPLAINLOOSE]+'$';
+
+
+var COMPARATORLOOSE=R++;
+src[COMPARATORLOOSE]='^'+src[GTLT]+'\\s*('+LOOSEPLAIN+')$|^$';
+var COMPARATOR=R++;
+src[COMPARATOR]='^'+src[GTLT]+'\\s*('+FULLPLAIN+')$|^$';
+
+
+
+
+var COMPARATORTRIM=R++;
+src[COMPARATORTRIM]='(\\s*)'+src[GTLT]+
+'\\s*('+LOOSEPLAIN+'|'+src[XRANGEPLAIN]+')';
+
+
+re[COMPARATORTRIM]=new RegExp(src[COMPARATORTRIM],'g');
+var comparatorTrimReplace='$1$2$3';
+
+
+
+
+
+
+var HYPHENRANGE=R++;
+src[HYPHENRANGE]='^\\s*('+src[XRANGEPLAIN]+')'+
+'\\s+-\\s+'+
+'('+src[XRANGEPLAIN]+')'+
+'\\s*$';
+
+var HYPHENRANGELOOSE=R++;
+src[HYPHENRANGELOOSE]='^\\s*('+src[XRANGEPLAINLOOSE]+')'+
+'\\s+-\\s+'+
+'('+src[XRANGEPLAINLOOSE]+')'+
+'\\s*$';
+
+
+var STAR=R++;
+src[STAR]='(<|>)?=?\\s*\\*';
+
+
+
+for(var i=0;i<R;i++){
+debug(i,src[i]);
+if(!re[i])
+re[i]=new RegExp(src[i]);
+}
+
+exports.parse=parse;
+function parse(version,loose){
+if(version instanceof SemVer)
+return version;
+
+if(typeof version!=='string')
+return null;
+
+if(version.length>MAX_LENGTH)
+return null;
+
+var r=loose?re[LOOSE]:re[FULL];
+if(!r.test(version))
+return null;
+
+try{
+return new SemVer(version,loose);
+}catch(er){
+return null;
+}
+}
+
+exports.valid=valid;
+function valid(version,loose){
+var v=parse(version,loose);
+return v?v.version:null;
+}
+
+
+exports.clean=clean;
+function clean(version,loose){
+var s=parse(version.trim().replace(/^[=v]+/,''),loose);
+return s?s.version:null;
+}
+
+exports.SemVer=SemVer;
+
+function SemVer(version,loose){
+if(version instanceof SemVer){
+if(version.loose===loose)
+return version;else
+
+version=version.version;
+}else if(typeof version!=='string'){
+throw new TypeError('Invalid Version: '+version);
+}
+
+if(version.length>MAX_LENGTH)
+throw new TypeError('version is longer than '+MAX_LENGTH+' characters');
+
+if(!(this instanceof SemVer))
+return new SemVer(version,loose);
+
+debug('SemVer',version,loose);
+this.loose=loose;
+var m=version.trim().match(loose?re[LOOSE]:re[FULL]);
+
+if(!m)
+throw new TypeError('Invalid Version: '+version);
+
+this.raw=version;
+
+
+this.major=+m[1];
+this.minor=+m[2];
+this.patch=+m[3];
+
+if(this.major>MAX_SAFE_INTEGER||this.major<0)
+throw new TypeError('Invalid major version');
+
+if(this.minor>MAX_SAFE_INTEGER||this.minor<0)
+throw new TypeError('Invalid minor version');
+
+if(this.patch>MAX_SAFE_INTEGER||this.patch<0)
+throw new TypeError('Invalid patch version');
+
+
+if(!m[4])
+this.prerelease=[];else
+
+this.prerelease=m[4].split('.').map(function(id){
+if(/^[0-9]+$/.test(id)){
+var num=+id;
+if(num>=0&&num<MAX_SAFE_INTEGER)
+return num;
+}
+return id;
+});
+
+this.build=m[5]?m[5].split('.'):[];
+this.format();
+}
+
+SemVer.prototype.format=function(){
+this.version=this.major+'.'+this.minor+'.'+this.patch;
+if(this.prerelease.length)
+this.version+='-'+this.prerelease.join('.');
+return this.version;
+};
+
+SemVer.prototype.toString=function(){
+return this.version;
+};
+
+SemVer.prototype.compare=function(other){
+debug('SemVer.compare',this.version,this.loose,other);
+if(!(other instanceof SemVer))
+other=new SemVer(other,this.loose);
+
+return this.compareMain(other)||this.comparePre(other);
+};
+
+SemVer.prototype.compareMain=function(other){
+if(!(other instanceof SemVer))
+other=new SemVer(other,this.loose);
+
+return compareIdentifiers(this.major,other.major)||
+compareIdentifiers(this.minor,other.minor)||
+compareIdentifiers(this.patch,other.patch);
+};
+
+SemVer.prototype.comparePre=function(other){
+if(!(other instanceof SemVer))
+other=new SemVer(other,this.loose);
+
+
+if(this.prerelease.length&&!other.prerelease.length)
+return-1;else
+if(!this.prerelease.length&&other.prerelease.length)
+return 1;else
+if(!this.prerelease.length&&!other.prerelease.length)
+return 0;
+
+var i=0;
+do{
+var a=this.prerelease[i];
+var b=other.prerelease[i];
+debug('prerelease compare',i,a,b);
+if(a===undefined&&b===undefined)
+return 0;else
+if(b===undefined)
+return 1;else
+if(a===undefined)
+return-1;else
+if(a===b)
+continue;else
+
+return compareIdentifiers(a,b);
+}while(++i);
+};
+
+
+
+SemVer.prototype.inc=function(release,identifier){
+switch(release){
+case'premajor':
+this.prerelease.length=0;
+this.patch=0;
+this.minor=0;
+this.major++;
+this.inc('pre',identifier);
+break;
+case'preminor':
+this.prerelease.length=0;
+this.patch=0;
+this.minor++;
+this.inc('pre',identifier);
+break;
+case'prepatch':
+
+
+
+this.prerelease.length=0;
+this.inc('patch',identifier);
+this.inc('pre',identifier);
+break;
+
+
+case'prerelease':
+if(this.prerelease.length===0)
+this.inc('patch',identifier);
+this.inc('pre',identifier);
+break;
+
+case'major':
+
+
+
+
+if(this.minor!==0||this.patch!==0||this.prerelease.length===0)
+this.major++;
+this.minor=0;
+this.patch=0;
+this.prerelease=[];
+break;
+case'minor':
+
+
+
+
+if(this.patch!==0||this.prerelease.length===0)
+this.minor++;
+this.patch=0;
+this.prerelease=[];
+break;
+case'patch':
+
+
+
+
+if(this.prerelease.length===0)
+this.patch++;
+this.prerelease=[];
+break;
+
+
+case'pre':
+if(this.prerelease.length===0)
+this.prerelease=[0];else
+{
+var i=this.prerelease.length;
+while(--i>=0){
+if(typeof this.prerelease[i]==='number'){
+this.prerelease[i]++;
+i=-2;
+}
+}
+if(i===-1)
+this.prerelease.push(0);
+}
+if(identifier){
+
+
+if(this.prerelease[0]===identifier){
+if(isNaN(this.prerelease[1]))
+this.prerelease=[identifier,0];
+}else
+this.prerelease=[identifier,0];
+}
+break;
+
+default:
+throw new Error('invalid increment argument: '+release);}
+
+this.format();
+this.raw=this.version;
+return this;
+};
+
+exports.inc=inc;
+function inc(version,release,loose,identifier){
+if(typeof loose==='string'){
+identifier=loose;
+loose=undefined;
+}
+
+try{
+return new SemVer(version,loose).inc(release,identifier).version;
+}catch(er){
+return null;
+}
+}
+
+exports.diff=diff;
+function diff(version1,version2){
+if(eq(version1,version2)){
+return null;
+}else{
+var v1=parse(version1);
+var v2=parse(version2);
+if(v1.prerelease.length||v2.prerelease.length){
+for(var key in v1){
+if(key==='major'||key==='minor'||key==='patch'){
+if(v1[key]!==v2[key]){
+return'pre'+key;
+}
+}
+}
+return'prerelease';
+}
+for(var key in v1){
+if(key==='major'||key==='minor'||key==='patch'){
+if(v1[key]!==v2[key]){
+return key;
+}
+}
+}
+}
+}
+
+exports.compareIdentifiers=compareIdentifiers;
+
+var numeric=/^[0-9]+$/;
+function compareIdentifiers(a,b){
+var anum=numeric.test(a);
+var bnum=numeric.test(b);
+
+if(anum&&bnum){
+a=+a;
+b=+b;
+}
+
+return anum&&!bnum?-1:
+bnum&&!anum?1:
+a<b?-1:
+a>b?1:
+0;
+}
+
+exports.rcompareIdentifiers=rcompareIdentifiers;
+function rcompareIdentifiers(a,b){
+return compareIdentifiers(b,a);
+}
+
+exports.major=major;
+function major(a,loose){
+return new SemVer(a,loose).major;
+}
+
+exports.minor=minor;
+function minor(a,loose){
+return new SemVer(a,loose).minor;
+}
+
+exports.patch=patch;
+function patch(a,loose){
+return new SemVer(a,loose).patch;
+}
+
+exports.compare=compare;
+function compare(a,b,loose){
+return new SemVer(a,loose).compare(b);
+}
+
+exports.compareLoose=compareLoose;
+function compareLoose(a,b){
+return compare(a,b,true);
+}
+
+exports.rcompare=rcompare;
+function rcompare(a,b,loose){
+return compare(b,a,loose);
+}
+
+exports.sort=sort;
+function sort(list,loose){
+return list.sort(function(a,b){
+return exports.compare(a,b,loose);
+});
+}
+
+exports.rsort=rsort;
+function rsort(list,loose){
+return list.sort(function(a,b){
+return exports.rcompare(a,b,loose);
+});
+}
+
+exports.gt=gt;
+function gt(a,b,loose){
+return compare(a,b,loose)>0;
+}
+
+exports.lt=lt;
+function lt(a,b,loose){
+return compare(a,b,loose)<0;
+}
+
+exports.eq=eq;
+function eq(a,b,loose){
+return compare(a,b,loose)===0;
+}
+
+exports.neq=neq;
+function neq(a,b,loose){
+return compare(a,b,loose)!==0;
+}
+
+exports.gte=gte;
+function gte(a,b,loose){
+return compare(a,b,loose)>=0;
+}
+
+exports.lte=lte;
+function lte(a,b,loose){
+return compare(a,b,loose)<=0;
+}
+
+exports.cmp=cmp;
+function cmp(a,op,b,loose){
+var ret;
+switch(op){
+case'===':
+if(typeof a==='object')a=a.version;
+if(typeof b==='object')b=b.version;
+ret=a===b;
+break;
+case'!==':
+if(typeof a==='object')a=a.version;
+if(typeof b==='object')b=b.version;
+ret=a!==b;
+break;
+case'':case'=':case'==':ret=eq(a,b,loose);break;
+case'!=':ret=neq(a,b,loose);break;
+case'>':ret=gt(a,b,loose);break;
+case'>=':ret=gte(a,b,loose);break;
+case'<':ret=lt(a,b,loose);break;
+case'<=':ret=lte(a,b,loose);break;
+default:throw new TypeError('Invalid operator: '+op);}
+
+return ret;
+}
+
+exports.Comparator=Comparator;
+function Comparator(comp,loose){
+if(comp instanceof Comparator){
+if(comp.loose===loose)
+return comp;else
+
+comp=comp.value;
+}
+
+if(!(this instanceof Comparator))
+return new Comparator(comp,loose);
+
+debug('comparator',comp,loose);
+this.loose=loose;
+this.parse(comp);
+
+if(this.semver===ANY)
+this.value='';else
+
+this.value=this.operator+this.semver.version;
+
+debug('comp',this);
+}
+
+var ANY={};
+Comparator.prototype.parse=function(comp){
+var r=this.loose?re[COMPARATORLOOSE]:re[COMPARATOR];
+var m=comp.match(r);
+
+if(!m)
+throw new TypeError('Invalid comparator: '+comp);
+
+this.operator=m[1];
+if(this.operator==='=')
+this.operator='';
+
+
+if(!m[2])
+this.semver=ANY;else
+
+this.semver=new SemVer(m[2],this.loose);
+};
+
+Comparator.prototype.toString=function(){
+return this.value;
+};
+
+Comparator.prototype.test=function(version){
+debug('Comparator.test',version,this.loose);
+
+if(this.semver===ANY)
+return true;
+
+if(typeof version==='string')
+version=new SemVer(version,this.loose);
+
+return cmp(version,this.operator,this.semver,this.loose);
+};
+
+
+exports.Range=Range;
+function Range(range,loose){
+if(range instanceof Range&&range.loose===loose)
+return range;
+
+if(!(this instanceof Range))
+return new Range(range,loose);
+
+this.loose=loose;
+
+
+this.raw=range;
+this.set=range.split(/\s*\|\|\s*/).map(function(range){
+return this.parseRange(range.trim());
+},this).filter(function(c){
+
+return c.length;
+});
+
+if(!this.set.length){
+throw new TypeError('Invalid SemVer Range: '+range);
+}
+
+this.format();
+}
+
+Range.prototype.format=function(){
+this.range=this.set.map(function(comps){
+return comps.join(' ').trim();
+}).join('||').trim();
+return this.range;
+};
+
+Range.prototype.toString=function(){
+return this.range;
+};
+
+Range.prototype.parseRange=function(range){
+var loose=this.loose;
+range=range.trim();
+debug('range',range,loose);
+
+var hr=loose?re[HYPHENRANGELOOSE]:re[HYPHENRANGE];
+range=range.replace(hr,hyphenReplace);
+debug('hyphen replace',range);
+
+range=range.replace(re[COMPARATORTRIM],comparatorTrimReplace);
+debug('comparator trim',range,re[COMPARATORTRIM]);
+
+
+range=range.replace(re[TILDETRIM],tildeTrimReplace);
+
+
+range=range.replace(re[CARETTRIM],caretTrimReplace);
+
+
+range=range.split(/\s+/).join(' ');
+
+
+
+
+var compRe=loose?re[COMPARATORLOOSE]:re[COMPARATOR];
+var set=range.split(' ').map(function(comp){
+return parseComparator(comp,loose);
+}).join(' ').split(/\s+/);
+if(this.loose){
+
+set=set.filter(function(comp){
+return!!comp.match(compRe);
+});
+}
+set=set.map(function(comp){
+return new Comparator(comp,loose);
+});
+
+return set;
+};
+
+
+exports.toComparators=toComparators;
+function toComparators(range,loose){
+return new Range(range,loose).set.map(function(comp){
+return comp.map(function(c){
+return c.value;
+}).join(' ').trim().split(' ');
+});
+}
+
+
+
+
+function parseComparator(comp,loose){
+debug('comp',comp);
+comp=replaceCarets(comp,loose);
+debug('caret',comp);
+comp=replaceTildes(comp,loose);
+debug('tildes',comp);
+comp=replaceXRanges(comp,loose);
+debug('xrange',comp);
+comp=replaceStars(comp,loose);
+debug('stars',comp);
+return comp;
+}
+
+function isX(id){
+return!id||id.toLowerCase()==='x'||id==='*';
+}
+
+
+
+
+
+
+
+function replaceTildes(comp,loose){
+return comp.trim().split(/\s+/).map(function(comp){
+return replaceTilde(comp,loose);
+}).join(' ');
+}
+
+function replaceTilde(comp,loose){
+var r=loose?re[TILDELOOSE]:re[TILDE];
+return comp.replace(r,function(_,M,m,p,pr){
+debug('tilde',comp,_,M,m,p,pr);
+var ret;
+
+if(isX(M))
+ret='';else
+if(isX(m))
+ret='>='+M+'.0.0 <'+(+M+1)+'.0.0';else
+if(isX(p))
+
+ret='>='+M+'.'+m+'.0 <'+M+'.'+(+m+1)+'.0';else
+if(pr){
+debug('replaceTilde pr',pr);
+if(pr.charAt(0)!=='-')
+pr='-'+pr;
+ret='>='+M+'.'+m+'.'+p+pr+
+' <'+M+'.'+(+m+1)+'.0';
+}else
+
+ret='>='+M+'.'+m+'.'+p+
+' <'+M+'.'+(+m+1)+'.0';
+
+debug('tilde return',ret);
+return ret;
+});
+}
+
+
+
+
+
+
+
+function replaceCarets(comp,loose){
+return comp.trim().split(/\s+/).map(function(comp){
+return replaceCaret(comp,loose);
+}).join(' ');
+}
+
+function replaceCaret(comp,loose){
+debug('caret',comp,loose);
+var r=loose?re[CARETLOOSE]:re[CARET];
+return comp.replace(r,function(_,M,m,p,pr){
+debug('caret',comp,_,M,m,p,pr);
+var ret;
+
+if(isX(M))
+ret='';else
+if(isX(m))
+ret='>='+M+'.0.0 <'+(+M+1)+'.0.0';else
+if(isX(p)){
+if(M==='0')
+ret='>='+M+'.'+m+'.0 <'+M+'.'+(+m+1)+'.0';else
+
+ret='>='+M+'.'+m+'.0 <'+(+M+1)+'.0.0';
+}else if(pr){
+debug('replaceCaret pr',pr);
+if(pr.charAt(0)!=='-')
+pr='-'+pr;
+if(M==='0'){
+if(m==='0')
+ret='>='+M+'.'+m+'.'+p+pr+
+' <'+M+'.'+m+'.'+(+p+1);else
+
+ret='>='+M+'.'+m+'.'+p+pr+
+' <'+M+'.'+(+m+1)+'.0';
+}else
+ret='>='+M+'.'+m+'.'+p+pr+
+' <'+(+M+1)+'.0.0';
+}else{
+debug('no pr');
+if(M==='0'){
+if(m==='0')
+ret='>='+M+'.'+m+'.'+p+
+' <'+M+'.'+m+'.'+(+p+1);else
+
+ret='>='+M+'.'+m+'.'+p+
+' <'+M+'.'+(+m+1)+'.0';
+}else
+ret='>='+M+'.'+m+'.'+p+
+' <'+(+M+1)+'.0.0';
+}
+
+debug('caret return',ret);
+return ret;
+});
+}
+
+function replaceXRanges(comp,loose){
+debug('replaceXRanges',comp,loose);
+return comp.split(/\s+/).map(function(comp){
+return replaceXRange(comp,loose);
+}).join(' ');
+}
+
+function replaceXRange(comp,loose){
+comp=comp.trim();
+var r=loose?re[XRANGELOOSE]:re[XRANGE];
+return comp.replace(r,function(ret,gtlt,M,m,p,pr){
+debug('xRange',comp,ret,gtlt,M,m,p,pr);
+var xM=isX(M);
+var xm=xM||isX(m);
+var xp=xm||isX(p);
+var anyX=xp;
+
+if(gtlt==='='&&anyX)
+gtlt='';
+
+if(xM){
+if(gtlt==='>'||gtlt==='<'){
+
+ret='<0.0.0';
+}else{
+
+ret='*';
+}
+}else if(gtlt&&anyX){
+
+if(xm)
+m=0;
+if(xp)
+p=0;
+
+if(gtlt==='>'){
+
+
+
+gtlt='>=';
+if(xm){
+M=+M+1;
+m=0;
+p=0;
+}else if(xp){
+m=+m+1;
+p=0;
+}
+}else if(gtlt==='<='){
+
+
+gtlt='<';
+if(xm)
+M=+M+1;else
+
+m=+m+1;
+}
+
+ret=gtlt+M+'.'+m+'.'+p;
+}else if(xm){
+ret='>='+M+'.0.0 <'+(+M+1)+'.0.0';
+}else if(xp){
+ret='>='+M+'.'+m+'.0 <'+M+'.'+(+m+1)+'.0';
+}
+
+debug('xRange return',ret);
+
+return ret;
+});
+}
+
+
+
+function replaceStars(comp,loose){
+debug('replaceStars',comp,loose);
+
+return comp.trim().replace(re[STAR],'');
+}
+
+
+
+
+
+
+function hyphenReplace($0,
+from,fM,fm,fp,fpr,fb,
+to,tM,tm,tp,tpr,tb){
+
+if(isX(fM))
+from='';else
+if(isX(fm))
+from='>='+fM+'.0.0';else
+if(isX(fp))
+from='>='+fM+'.'+fm+'.0';else
+
+from='>='+from;
+
+if(isX(tM))
+to='';else
+if(isX(tm))
+to='<'+(+tM+1)+'.0.0';else
+if(isX(tp))
+to='<'+tM+'.'+(+tm+1)+'.0';else
+if(tpr)
+to='<='+tM+'.'+tm+'.'+tp+'-'+tpr;else
+
+to='<='+to;
+
+return(from+' '+to).trim();
+}
+
+
+
+Range.prototype.test=function(version){
+if(!version)
+return false;
+
+if(typeof version==='string')
+version=new SemVer(version,this.loose);
+
+for(var i=0;i<this.set.length;i++){
+if(testSet(this.set[i],version))
+return true;
+}
+return false;
+};
+
+function testSet(set,version){
+for(var i=0;i<set.length;i++){
+if(!set[i].test(version))
+return false;
+}
+
+if(version.prerelease.length){
+
+
+
+
+
+for(var i=0;i<set.length;i++){
+debug(set[i].semver);
+if(set[i].semver===ANY)
+continue;
+
+if(set[i].semver.prerelease.length>0){
+var allowed=set[i].semver;
+if(allowed.major===version.major&&
+allowed.minor===version.minor&&
+allowed.patch===version.patch)
+return true;
+}
+}
+
+
+return false;
+}
+
+return true;
+}
+
+exports.satisfies=satisfies;
+function satisfies(version,range,loose){
+try{
+range=new Range(range,loose);
+}catch(er){
+return false;
+}
+return range.test(version);
+}
+
+exports.maxSatisfying=maxSatisfying;
+function maxSatisfying(versions,range,loose){
+return versions.filter(function(version){
+return satisfies(version,range,loose);
+}).sort(function(a,b){
+return rcompare(a,b,loose);
+})[0]||null;
+}
+
+exports.minSatisfying=minSatisfying;
+function minSatisfying(versions,range,loose){
+return versions.filter(function(version){
+return satisfies(version,range,loose);
+}).sort(function(a,b){
+return compare(a,b,loose);
+})[0]||null;
+}
+
+exports.validRange=validRange;
+function validRange(range,loose){
+try{
+
+
+return new Range(range,loose).range||'*';
+}catch(er){
+return null;
+}
+}
+
+
+exports.ltr=ltr;
+function ltr(version,range,loose){
+return outside(version,range,'<',loose);
+}
+
+
+exports.gtr=gtr;
+function gtr(version,range,loose){
+return outside(version,range,'>',loose);
+}
+
+exports.outside=outside;
+function outside(version,range,hilo,loose){
+version=new SemVer(version,loose);
+range=new Range(range,loose);
+
+var gtfn,ltefn,ltfn,comp,ecomp;
+switch(hilo){
+case'>':
+gtfn=gt;
+ltefn=lte;
+ltfn=lt;
+comp='>';
+ecomp='>=';
+break;
+case'<':
+gtfn=lt;
+ltefn=gte;
+ltfn=gt;
+comp='<';
+ecomp='<=';
+break;
+default:
+throw new TypeError('Must provide a hilo val of "<" or ">"');}
+
+
+
+if(satisfies(version,range,loose)){
+return false;
+}
+
+
+
+
+for(var i=0;i<range.set.length;++i){
+var comparators=range.set[i];
+
+var high=null;
+var low=null;
+
+comparators.forEach(function(comparator){
+if(comparator.semver===ANY){
+comparator=new Comparator('>=0.0.0');
+}
+high=high||comparator;
+low=low||comparator;
+if(gtfn(comparator.semver,high.semver,loose)){
+high=comparator;
+}else if(ltfn(comparator.semver,low.semver,loose)){
+low=comparator;
+}
+});
+
+
+
+if(high.operator===comp||high.operator===ecomp){
+return false;
+}
+
+
+
+if((!low.operator||low.operator===comp)&&
+ltefn(version,low.semver)){
+return false;
+}else if(low.operator===ecomp&&ltfn(version,low.semver)){
+return false;
+}
+}
+return true;
+}
+
+exports.prerelease=prerelease;
+function prerelease(version,loose){
+var parsed=parse(version,loose);
+return parsed&&parsed.prerelease.length?parsed.prerelease:null;
+}
+
+}).call(this,require('_process'));
+},{"_process":130}],152:[function(require,module,exports){
+(function(Buffer){
+'use strict';
+
+
+const jpeg=require('jpeg-js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function getPixel(x,y,channel,width,buff){
+return buff[(x+y*width)*4+channel];
+}
+
+
+
+
+
+
+function isWhitePixel(i,j,img){
+return getPixel(i,j,0,img.width,img.data)>=249&&
+getPixel(i,j,1,img.width,img.data)>=249&&
+getPixel(i,j,2,img.width,img.data)>=249;
+}
+
+
+function convertPixelsToHistogram(img){
+const createHistogramArray=function(){
+const ret=[];
+for(let i=0;i<256;i++){
+ret[i]=0;
+}
+return ret;
+};
+
+const width=img.width;
+const height=img.height;
+
+const histograms=[
+createHistogramArray(),
+createHistogramArray(),
+createHistogramArray()];
+
+
+for(let j=0;j<height;j++){
+for(let i=0;i<width;i++){
+
+if(isWhitePixel(i,j,img)){
+continue;
+}
+
+for(let channel=0;channel<histograms.length;channel++){
+const pixelValue=getPixel(i,j,channel,width,img.data);
+histograms[channel][pixelValue]++;
+}
+}
+}
+
+return histograms;
+}
+
+
+function synthesizeWhiteFrame(frames){
+const firstImageData=jpeg.decode(frames[0].getImage());
+const width=firstImageData.width;
+const height=firstImageData.height;
+
+const frameData=Buffer.alloc(width*height*4);
+let i=0;
+while(i<frameData.length){
+frameData[i++]=0xFF;
+frameData[i++]=0xFF;
+frameData[i++]=0xFF;
+frameData[i++]=0xFF;
+}
+
+var jpegImageData=jpeg.encode({
+data:frameData,
+width:width,
+height:height});
+
+return jpegImageData.data;
+}
+
+const screenshotTraceCategory='disabled-by-default-devtools.screenshot';
+
+
+
+
+
+function extractFramesFromTimeline(timeline,opts){
+opts=opts||{};
+
+let trace;
+timeline=typeof timeline==='string'?fs.readFileSync(timeline,'utf-8'):timeline;
+try{
+trace=typeof timeline==='string'?JSON.parse(timeline):timeline;
+}catch(e){
+throw new Error('Speedline: Invalid JSON'+e.message);
+}
+
+let events=trace.traceEvents||trace;
+
+let startTs=Number.MAX_VALUE;
+let endTs=-Number.MAX_VALUE;
+events.forEach(e=>{
+if(e.ts===0){
+return;
+}
+
+startTs=Math.min(startTs,e.ts);
+endTs=Math.max(endTs,e.ts);
+});
+
+startTs=(opts.timeOrigin||startTs)/1000;
+endTs/=1000;
+
+
+let lastFrame=null;
+const rawScreenshots=events.filter(e=>e.cat.includes(screenshotTraceCategory)&&e.ts>=startTs*1000);
+rawScreenshots.sort((a,b)=>a.ts-b.ts);
+
+
+const uniqueFrames=rawScreenshots.map(function(evt){
+const base64img=evt.args&&evt.args.snapshot;
+const timestamp=evt.ts/1000;
+
+if(base64img===lastFrame){
+return null;
+}
+
+lastFrame=base64img;
+const imgBuff=Buffer.from(base64img,'base64');
+return frame(imgBuff,timestamp);
+}).filter(Boolean);
+
+if(uniqueFrames.length===0){
+return Promise.reject(new Error('No screenshots found in trace'));
+}
+
+const fakeWhiteFrame=frame(synthesizeWhiteFrame(uniqueFrames),startTs);
+uniqueFrames.unshift(fakeWhiteFrame);
+
+const data={
+startTs,
+endTs,
+frames:uniqueFrames};
+
+return Promise.resolve(data);
+}
+
+
+
+
+
+
+function frame(imgBuff,ts){
+
+let _histogram=null;
+
+let _progress=null;
+
+let _isProgressInterpolated=null;
+
+let _perceptualProgress=null;
+
+let _isPerceptualProgressInterpolated=null;
+
+let _parsedImage=null;
+
+return{
+getHistogram:function(){
+if(_histogram){
+return _histogram;
+}
+
+const pixels=this.getParsedImage();
+_histogram=convertPixelsToHistogram(pixels);
+return _histogram;
+},
+
+getTimeStamp:function(){
+return ts;
+},
+
+setProgress:function(progress,isInterpolated){
+_progress=progress;
+_isProgressInterpolated=Boolean(isInterpolated);
+},
+
+setPerceptualProgress:function(progress,isInterpolated){
+_perceptualProgress=progress;
+_isPerceptualProgressInterpolated=Boolean(isInterpolated);
+},
+
+getImage:function(){
+return imgBuff;
+},
+
+getParsedImage:function(){
+if(!_parsedImage){
+_parsedImage=jpeg.decode(imgBuff);
+}
+return _parsedImage;
+},
+
+getProgress:function(){
+return _progress;
+},
+
+isProgressInterpolated:function(){
+return _isProgressInterpolated;
+},
+
+getPerceptualProgress:function(){
+return _perceptualProgress;
+},
+
+isPerceptualProgressInterpolated:function(){
+return _isPerceptualProgressInterpolated;
+}};
+
+}
+
+module.exports={
+extractFramesFromTimeline,
+create:frame};
+
+
+}).call(this,require("buffer").Buffer);
+},{"buffer":88,"jpeg-js":110}],153:[function(require,module,exports){
+'use strict';
+
+const frame=require('./frame');
+const speedIndex=require('./speed-index');
+
+
+
+
+
+
+
+
+
+
+
+function calculateValues(frames,data){
+const indexes=speedIndex.calculateSpeedIndexes(frames,data);
+const duration=Math.floor(data.endTs-data.startTs);
+const first=Math.floor(indexes.firstPaintTs-data.startTs);
+const complete=Math.floor(indexes.visuallyCompleteTs-data.startTs);
+
+return{
+beginning:data.startTs,
+end:data.endTs,
+frames,
+first,
+complete,
+duration,
+speedIndex:indexes.speedIndex,
+perceptualSpeedIndex:indexes.perceptualSpeedIndex};
+
+}
+
+
+const Include={
+All:'all',
+pSI:'perceptualSpeedIndex',
+SI:'speedIndex'};
+
+
+
+
+
+
+
+
+
+module.exports=function(timeline,opts){
+const include=opts&&opts.include||Include.All;
+
+if(!Object.keys(Include).some(key=>Include[key]===include)){
+throw new Error(`Unrecognized include option: ${include}`);
+}
+
+return frame.extractFramesFromTimeline(timeline,opts).then(function(data){
+const frames=data.frames;
+
+if(include===Include.All||include===Include.SI){
+speedIndex.calculateVisualProgress(frames,opts);
+}
+
+if(include===Include.All||include===Include.pSI){
+speedIndex.calculatePerceptualProgress(frames,opts);
+}
+
+return calculateValues(frames,data);
+});
+};
+
+},{"./frame":152,"./speed-index":154}],154:[function(require,module,exports){
+'use strict';
+
+const imageSSIM=require('image-ssim');
+
+
+const fastModeAllowableChangeMax=5;
+const fastModeAllowableChangeMedian=3;
+const fastModeAllowableChangeMin=-1;
+
+const fastModeConstant=fastModeAllowableChangeMin;
+const fastModeMultiplier=fastModeAllowableChangeMax-fastModeConstant;
+const fastModeExponentiationCoefficient=Math.log((fastModeAllowableChangeMedian-fastModeConstant)/fastModeMultiplier);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function calculateFastModeAllowableChange(elapsedTime){
+const elapsedTimeInSeconds=elapsedTime/1000;
+const allowableChange=fastModeMultiplier*Math.exp(fastModeExponentiationCoefficient*elapsedTimeInSeconds)+fastModeConstant;
+return allowableChange;
+}
+
+
+
+
+
+
+function calculateFrameProgress(current,initial,target){
+let total=0;
+let match=0;
+
+const currentHist=current.getHistogram();
+const initialHist=initial.getHistogram();
+const targetHist=target.getHistogram();
+
+for(let channel=0;channel<3;channel++){
+for(let pixelVal=0;pixelVal<256;pixelVal++){
+const currentCount=currentHist[channel][pixelVal];
+const initialCount=initialHist[channel][pixelVal];
+const targetCount=targetHist[channel][pixelVal];
+
+const currentDiff=Math.abs(currentCount-initialCount);
+const targetDiff=Math.abs(targetCount-initialCount);
+
+match+=Math.min(currentDiff,targetDiff);
+total+=targetDiff;
+}
+}
+
+let progress;
+if(match===0&&total===0){
+progress=100;
+}else{
+progress=Math.floor(match/total*100);
+}
+return progress;
+}
+
+
+
+
+
+
+
+
+
+function calculateProgressBetweenFrames(frames,lowerBound,upperBound,isFastMode,getProgress,setProgress){
+if(!isFastMode){
+frames.forEach(frame=>setProgress(frame,getProgress(frame),false));
+return;
+}
+
+const lowerFrame=frames[lowerBound];
+const upperFrame=frames[upperBound];
+const elapsedTime=upperFrame.getTimeStamp()-lowerFrame.getTimeStamp();
+
+const lowerProgress=getProgress(lowerFrame);
+const upperProgress=getProgress(upperFrame);
+
+setProgress(lowerFrame,lowerProgress,false);
+setProgress(upperFrame,upperProgress,false);
+
+if(Math.abs(lowerProgress-upperProgress)<calculateFastModeAllowableChange(elapsedTime)){
+for(let i=lowerBound+1;i<upperBound;i++){
+setProgress(frames[i],lowerProgress,true);
+}
+}else if(upperBound-lowerBound>1){
+const midpoint=Math.floor((lowerBound+upperBound)/2);
+calculateProgressBetweenFrames(frames,lowerBound,midpoint,isFastMode,getProgress,setProgress);
+calculateProgressBetweenFrames(frames,midpoint,upperBound,isFastMode,getProgress,setProgress);
+}
+}
+
+
+
+
+
+function calculateVisualProgress(frames,opts){
+const initial=frames[0];
+const target=frames[frames.length-1];
+
+
+function getProgress(frame){
+if(typeof frame.getProgress()==='number'){
+return frame.getProgress();
+}
+
+return calculateFrameProgress(frame,initial,target);
+}
+
+
+
+
+
+
+function setProgress(frame,progress,isInterpolated){
+return frame.setProgress(progress,isInterpolated);
+}
+
+calculateProgressBetweenFrames(
+frames,
+0,
+frames.length-1,
+opts&&opts.fastMode,
+getProgress,
+setProgress);
+
+
+return frames;
+}
+
+
+
+
+
+
+function calculateFrameSimilarity(frame,target){
+const defaultImageConfig={
+
+
+channels:4};
+
+
+const frameData=Object.assign(frame.getParsedImage(),defaultImageConfig);
+const targetData=Object.assign(target.getParsedImage(),defaultImageConfig);
+
+const diff=imageSSIM.compare(frameData,targetData);
+return diff.ssim;
+}
+
+
+
+
+
+function calculatePerceptualProgress(frames,opts){
+const initial=frames[0];
+const target=frames[frames.length-1];
+const initialSimilarity=calculateFrameSimilarity(initial,target);
+
+
+function getProgress(frame){
+if(typeof frame.getPerceptualProgress()==='number'){
+return frame.getPerceptualProgress();
+}
+
+const ssim=calculateFrameSimilarity(frame,target);
+return Math.max(100*(ssim-initialSimilarity)/(1-initialSimilarity),0);
+}
+
+
+
+
+
+
+function setProgress(frame,progress,isInterpolated){
+return frame.setPerceptualProgress(progress,isInterpolated);
+}
+
+calculateProgressBetweenFrames(
+frames,
+0,
+frames.length-1,
+opts&&opts.fastMode,
+getProgress,
+setProgress);
+
+
+return frames;
+}
+
+
+
+
+
+
+function calculateSpeedIndexes(frames,data){
+const hasVisualProgress=typeof frames[0].getProgress()==='number';
+const hasPerceptualProgress=typeof frames[0].getPerceptualProgress()==='number';
+const progressToUse=hasVisualProgress?'getProgress':'getPerceptualProgress';
+const startTs=data.startTs;
+let visuallyCompleteTs;
+
+let firstPaintTs;
+
+
+for(let i=0;i<frames.length&&!firstPaintTs;i++){
+if(frames[i][progressToUse]()>0){
+firstPaintTs=frames[i].getTimeStamp();
+}
+}
+
+
+for(let i=0;i<frames.length&&!visuallyCompleteTs;i++){
+if(frames[i][progressToUse]()>=100){
+visuallyCompleteTs=frames[i].getTimeStamp();
+}
+}
+
+let prevFrameTs=frames[0].getTimeStamp();
+let prevProgress=frames[0].getProgress();
+let prevPerceptualProgress=frames[0].getPerceptualProgress();
+
+
+
+
+let speedIndex=firstPaintTs-startTs;
+
+let perceptualSpeedIndex=firstPaintTs-startTs;
+
+frames.forEach(function(frame){
+
+if(frame.getTimeStamp()>firstPaintTs){
+const elapsed=frame.getTimeStamp()-prevFrameTs;
+speedIndex+=elapsed*(1-prevProgress);
+perceptualSpeedIndex+=elapsed*(1-prevPerceptualProgress);
+}
+
+prevFrameTs=frame.getTimeStamp();
+prevProgress=frame.getProgress()/100;
+prevPerceptualProgress=frame.getPerceptualProgress()/100;
+});
+
+speedIndex=hasVisualProgress?speedIndex:undefined;
+perceptualSpeedIndex=hasPerceptualProgress?perceptualSpeedIndex:undefined;
+
+return{
+firstPaintTs,
+visuallyCompleteTs,
+speedIndex,
+perceptualSpeedIndex};
+
+}
+
+module.exports={
+calculateFastModeAllowableChange,
+calculateFrameSimilarity,
+calculateVisualProgress,
+calculatePerceptualProgress,
+calculateSpeedIndexes};
+
+
+},{"image-ssim":97}],155:[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports=Stream;
+
+var EE=require('events').EventEmitter;
+var inherits=require('inherits');
+
+inherits(Stream,EE);
+Stream.Readable=require('readable-stream/readable.js');
+Stream.Writable=require('readable-stream/writable.js');
+Stream.Duplex=require('readable-stream/duplex.js');
+Stream.Transform=require('readable-stream/transform.js');
+Stream.PassThrough=require('readable-stream/passthrough.js');
+
+
+Stream.Stream=Stream;
+
+
+
+
+
+
+function Stream(){
+EE.call(this);
+}
+
+Stream.prototype.pipe=function(dest,options){
+var source=this;
+
+function ondata(chunk){
+if(dest.writable){
+if(false===dest.write(chunk)&&source.pause){
+source.pause();
+}
+}
+}
+
+source.on('data',ondata);
+
+function ondrain(){
+if(source.readable&&source.resume){
+source.resume();
+}
+}
+
+dest.on('drain',ondrain);
+
+
+
+if(!dest._isStdio&&(!options||options.end!==false)){
+source.on('end',onend);
+source.on('close',onclose);
+}
+
+var didOnEnd=false;
+function onend(){
+if(didOnEnd)return;
+didOnEnd=true;
+
+dest.end();
+}
+
+
+function onclose(){
+if(didOnEnd)return;
+didOnEnd=true;
+
+if(typeof dest.destroy==='function')dest.destroy();
+}
+
+
+function onerror(er){
+cleanup();
+if(EE.listenerCount(this,'error')===0){
+throw er;
+}
+}
+
+source.on('error',onerror);
+dest.on('error',onerror);
+
+
+function cleanup(){
+source.removeListener('data',ondata);
+dest.removeListener('drain',ondrain);
+
+source.removeListener('end',onend);
+source.removeListener('close',onclose);
+
+source.removeListener('error',onerror);
+dest.removeListener('error',onerror);
+
+source.removeListener('end',cleanup);
+source.removeListener('close',cleanup);
+
+dest.removeListener('close',cleanup);
+}
+
+source.on('end',cleanup);
+source.on('close',cleanup);
+
+dest.on('close',cleanup);
+
+dest.emit('pipe',source);
+
+
+return dest;
+};
+
+},{"events":93,"inherits":98,"readable-stream/duplex.js":134,"readable-stream/passthrough.js":144,"readable-stream/readable.js":145,"readable-stream/transform.js":146,"readable-stream/writable.js":147}],156:[function(require,module,exports){
+(function(setImmediate,clearImmediate){
+var nextTick=require('process/browser.js').nextTick;
+var apply=Function.prototype.apply;
+var slice=Array.prototype.slice;
+var immediateIds={};
+var nextImmediateId=0;
+
+
+
+exports.setTimeout=function(){
+return new Timeout(apply.call(setTimeout,window,arguments),clearTimeout);
+};
+exports.setInterval=function(){
+return new Timeout(apply.call(setInterval,window,arguments),clearInterval);
+};
+exports.clearTimeout=
+exports.clearInterval=function(timeout){timeout.close();};
+
+function Timeout(id,clearFn){
+this._id=id;
+this._clearFn=clearFn;
+}
+Timeout.prototype.unref=Timeout.prototype.ref=function(){};
+Timeout.prototype.close=function(){
+this._clearFn.call(window,this._id);
+};
+
+
+exports.enroll=function(item,msecs){
+clearTimeout(item._idleTimeoutId);
+item._idleTimeout=msecs;
+};
+
+exports.unenroll=function(item){
+clearTimeout(item._idleTimeoutId);
+item._idleTimeout=-1;
+};
+
+exports._unrefActive=exports.active=function(item){
+clearTimeout(item._idleTimeoutId);
+
+var msecs=item._idleTimeout;
+if(msecs>=0){
+item._idleTimeoutId=setTimeout(function onTimeout(){
+if(item._onTimeout)
+item._onTimeout();
+},msecs);
+}
+};
+
+
+exports.setImmediate=typeof setImmediate==="function"?setImmediate:function(fn){
+var id=nextImmediateId++;
+var args=arguments.length<2?false:slice.call(arguments,1);
+
+immediateIds[id]=true;
+
+nextTick(function onNextTick(){
+if(immediateIds[id]){
+
+
+if(args){
+fn.apply(null,args);
+}else{
+fn.call(null);
+}
+
+exports.clearImmediate(id);
+}
+});
+
+return id;
+};
+
+exports.clearImmediate=typeof clearImmediate==="function"?clearImmediate:function(id){
+delete immediateIds[id];
+};
+}).call(this,require("timers").setImmediate,require("timers").clearImmediate);
+},{"process/browser.js":130,"timers":156}],157:[function(require,module,exports){
+(function(global){
+
+
+
+
+
+module.exports=deprecate;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function deprecate(fn,msg){
+if(config('noDeprecation')){
+return fn;
+}
+
+var warned=false;
+function deprecated(){
+if(!warned){
+if(config('throwDeprecation')){
+throw new Error(msg);
+}else if(config('traceDeprecation')){
+console.trace(msg);
+}else{
+console.warn(msg);
+}
+warned=true;
+}
+return fn.apply(this,arguments);
+}
+
+return deprecated;
+}
+
+
+
+
+
+
+
+
+
+function config(name){
+
+try{
+if(!global.localStorage)return false;
+}catch(_){
+return false;
+}
+var val=global.localStorage[name];
+if(null==val)return false;
+return String(val).toLowerCase()==='true';
+}
+
+}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
+},{}],158:[function(require,module,exports){
+arguments[4][80][0].apply(exports,arguments);
+},{"dup":80}],159:[function(require,module,exports){
+arguments[4][81][0].apply(exports,arguments);
+},{"./support/isBuffer":158,"_process":130,"dup":81,"inherits":98}],160:[function(require,module,exports){
+module.exports={
+"version":"4.0.0"};
+
+},{}],161:[function(require,module,exports){
+module.exports={
+"npm":{
+"angular":[
+{"id":"npm:angular:20180202","severity":"medium","semver":{"vulnerable":["<1.6.9"]}},
+{"id":"npm:angular:20171018","severity":"medium","semver":{"vulnerable":["<1.6.7"]}},
+{"id":"npm:angular:20160527","severity":"medium","semver":{"vulnerable":["<1.2.30 >=1.0.0"]}},
+{"id":"npm:angular:20160122","severity":"medium","semver":{"vulnerable":["<1.5.0-rc.2 >=1.3.0"]}},
+{"id":"npm:angular:20140608","severity":"low","semver":{"vulnerable":["<1.3.0"]}},
+{"id":"npm:angular:20131113","severity":"high","semver":{"vulnerable":["<1.2.2"]}},
+{"id":"npm:angular:20140908","severity":"medium","semver":{"vulnerable":["<1.3.0-rc.4"]}},
+{"id":"npm:angular:20161101","severity":"medium","semver":{"vulnerable":["<1.5.9 >=1.5.0"]}},
+{"id":"npm:angular:20150909","severity":"high","semver":{"vulnerable":["<1.5.0-beta.2"]}},
+{"id":"npm:angular:20151205","severity":"medium","semver":{"vulnerable":["<1.5.0-rc.0"]}},
+{"id":"npm:angular:20151130","severity":"medium","semver":{"vulnerable":["<1.4.10"]}},
+{"id":"npm:angular:20130622","severity":"medium","semver":{"vulnerable":["<1.2.0 >=1.0.0"]}},
+{"id":"npm:angular:20150807-1","severity":"medium","semver":{"vulnerable":["<1.5.0-beta.0 >=1.3.1"]}},
+{"id":"npm:angular:20150807","severity":"high","semver":{"vulnerable":["<1.5.0-beta.0 >=1.0.0"]}},
+{"id":"npm:angular:20150315","severity":"medium","semver":{"vulnerable":["<1.6.1"]}},
+{"id":"npm:angular:20150310","severity":"high","semver":{"vulnerable":["<1.5.0-beta.2"]}},
+{"id":"npm:angular:20141104","severity":"medium","semver":{"vulnerable":["<1.3.2"]}},
+{"id":"npm:angular:20130621","severity":"medium","semver":{"vulnerable":["<=1.1.5"]}},
+{"id":"npm:angular:20140909","severity":"high","semver":{"vulnerable":["<1.2.24 >=1.2.19"]}},
+{"id":"npm:angular:20130625","severity":"high","semver":{"vulnerable":["<1.1.5"]}}],
+
+"backbone":[
+{"id":"npm:backbone:20160523","severity":"medium","semver":{"vulnerable":["<= 0.3.3"]}},
+{"id":"npm:backbone:20110701","severity":"medium","semver":{"vulnerable":["<0.5.0"]}}],
+
+"bootstrap":[
+{"id":"npm:bootstrap:20180529","severity":"medium","semver":{"vulnerable":[">=4.0.0 <4.1.2"]}},
+{"id":"npm:bootstrap:20160627","severity":"medium","semver":{"vulnerable":["<3.4.0 || >=4.0.0-alpha <4.0.0-beta.2"]}},
+{"id":"npm:bootstrap:20120510","severity":"medium","semver":{"vulnerable":["<2.1.0"]}}],
+
+"dojo":[
+{"id":"SNYK-JS-DOJO-72305","severity":"medium","semver":{"vulnerable":["<1.14"]}},
+{"id":"npm:dojo:20180818","severity":"medium","semver":{"vulnerable":["<1.10.10 || >=1.11.0 <1.11.6 || >=1.12.0 <1.12.4 || >=1.13.0 <1.13.1"]}},
+{"id":"npm:dojo:20160523","severity":"medium","semver":{"vulnerable":["<= 1.0.0"]}},
+{"id":"npm:dojo:20100614-6","severity":"medium","semver":{"vulnerable":["<1.4.2"]}},
+{"id":"npm:dojo:20100614-1","severity":"high","semver":{"vulnerable":[">=0.4 <0.4.4 || >=1.0 <1.0.3 || >=1.1 <1.1.2 || >=1.2 <1.2.4 || >=1.3 <1.3.3 || >=1.4 <1.4.2"]}},
+{"id":"npm:dojo:20090409","severity":"medium","semver":{"vulnerable":["<1.1"]}}],
+
+"foundation-sites":[
+{"id":"npm:foundation-sites:20170802","severity":"medium","semver":{"vulnerable":["<6.0.0"]}},
+{"id":"npm:foundation-sites:20150619","severity":"medium","semver":{"vulnerable":["<5.5.3"]}},
+{"id":"npm:foundation-sites:20120717","severity":"medium","semver":{"vulnerable":["<3.0.6 >=3.0.0"]}}],
+
+"handlebars":[
+{"id":"npm:handlebars:20151207","severity":"medium","semver":{"vulnerable":["<4.0.0"]}},
+{"id":"npm:handlebars:20110425","severity":"medium","semver":{"vulnerable":["<=1.0.0-beta.3"]}}],
+
+"highcharts":[
+{"id":"npm:highcharts:20180225","severity":"low","semver":{"vulnerable":["<6.1.0"]}}],
+
+"jquery":[
+{"id":"npm:jquery:20160529","severity":"low","semver":{"vulnerable":["=3.0.0-rc.1"]}},
+{"id":"npm:jquery:20150627","severity":"medium","semver":{"vulnerable":["<3.0.0-beta1 >1.12.3 || <1.12.0 >=1.4.0"]}},
+{"id":"npm:jquery:20140902","severity":"medium","semver":{"vulnerable":[">=1.4.2 <1.6.2"]}},
+{"id":"npm:jquery:20120206","severity":"medium","semver":{"vulnerable":["<1.9.0 >=1.7.1"]}},
+{"id":"npm:jquery:20110606","severity":"medium","semver":{"vulnerable":["<1.6.3"]}}],
+
+"jquery-mobile":[
+{"id":"npm:jquery-mobile:20120802","severity":"medium","semver":{"vulnerable":["<1.2.0"]}}],
+
+"jquery-ui":[
+{"id":"npm:jquery-ui:20121127","severity":"medium","semver":{"vulnerable":["<1.10.0"]}},
+{"id":"npm:jquery-ui:20100903","severity":"medium","semver":{"vulnerable":["<1.10.0"]}},
+{"id":"npm:jquery-ui:20160721","severity":"high","semver":{"vulnerable":["<=1.11.4"]}}],
+
+"knockout":[
+{"id":"npm:knockout:20180213","severity":"medium","semver":{"vulnerable":["<3.5.0-beta"]}},
+{"id":"npm:knockout:20130701","severity":"medium","semver":{"vulnerable":["<3.0.0 >=2.1.0-pre"]}}],
+
+"lodash":[
+{"id":"npm:lodash:20180130","severity":"low","semver":{"vulnerable":["<4.17.5"]}}],
+
+"moment":[
+{"id":"npm:moment:20170905","severity":"low","semver":{"vulnerable":["<2.19.3"]}},
+{"id":"npm:moment:20161019","severity":"medium","semver":{"vulnerable":["<2.15.2"]}},
+{"id":"npm:moment:20160126","severity":"low","semver":{"vulnerable":["<=2.11.1"]}}],
+
+"mustache":[
+{"id":"npm:mustache:20151207","severity":"medium","semver":{"vulnerable":["<2.2.1"]}},
+{"id":"npm:mustache:20110814","severity":"medium","semver":{"vulnerable":["< 0.3.1"]}}],
+
+"react":[
+{"id":"npm:react:20150318","severity":"high","semver":{"vulnerable":["<0.14.0"]}},
+{"id":"npm:react:20131217","severity":"medium","semver":{"vulnerable":[">=0.5.0 <0.5.2 || >=0.4.0 <0.4.2"]}}],
+
+"riot":[
+{"id":"npm:riot:20131114","severity":"medium","semver":{"vulnerable":["<0.9.6"]}}],
+
+"socket.io":[
+{"id":"npm:socket.io:20120417","severity":"medium","semver":{"vulnerable":["<0.9.6"]}},
+{"id":"npm:socket.io:20120323","severity":"medium","semver":{"vulnerable":["<0.9.7"]}}],
+
+"vue":[
+{"id":"npm:vue:20170829","severity":"medium","semver":{"vulnerable":["<2.4.3"]}},
+{"id":"npm:vue:20170401","severity":"medium","semver":{"vulnerable":["<2.3.0-beta.1"]}},
+{"id":"npm:vue:20180802","severity":"medium","semver":{"vulnerable":["<2.5.17"]}},
+{"id":"npm:vue:20180222","severity":"low","semver":{"vulnerable":["<=2.5.14"]}}],
+
+"yui":[
+{"id":"npm:yui:20130604","severity":"medium","semver":{"vulnerable":[">=3.0.0 <3.10.1 || =3.10.2"]}},
+{"id":"npm:yui:20130515","severity":"medium","semver":{"vulnerable":["<3.10.0 >=3.0.0"]}},
+{"id":"npm:yui:20121030","severity":"medium","semver":{"vulnerable":["<3.0.0 >=2.4.0"]}},
+{"id":"npm:yui:20120428","severity":"medium","semver":{"vulnerable":["<3.5.1 >=3.5.0-PR1"]}},
+{"id":"npm:yui:20101025","severity":"medium","semver":{"vulnerable":["<2.8.2 >=2.4.0"]}}]}};
+
+
+
+},{}],"url":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const Util=require('../report/html/renderer/util.js');
+
+
+const URL=typeof self!=='undefined'&&self.URL||
+require('url').URL;
+
+
+
+const listOfTlds=[
+'com','co','gov','edu','ac','org','go','gob','or','net','in','ne','nic','gouv',
+'web','spb','blog','jus','kiev','mil','wi','qc','ca','bel','on'];
+
+
+const allowedProtocols=[
+'https:','http:','chrome:','chrome-extension:'];
+
+
+
+
+
+
+
+
+
+function rewriteChromeInternalUrl(url){
+if(!url||!url.startsWith('chrome://'))return url;
+
+
+if(url.endsWith('/'))url=url.replace(/\/$/,'');
+return url.replace(/^chrome:\/\/chrome\//,'chrome://');
+}
+
+class URLShim extends URL{
+
+
+
+
+static isValid(url){
+try{
+new URL(url);
+return true;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+
+static hostsMatch(urlA,urlB){
+try{
+return new URL(urlA).host===new URL(urlB).host;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+
+static originsMatch(urlA,urlB){
+try{
+return new URL(urlA).origin===new URL(urlB).origin;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+static getOrigin(url){
+try{
+const urlInfo=new URL(url);
+
+
+return urlInfo.host&&urlInfo.origin||null;
+}catch(e){
+return null;
+}
+}
+
+
+
+
+
+
+
+static getTld(hostname){
+const tlds=hostname.split('.').slice(-2);
+
+if(!listOfTlds.includes(tlds[0])){
+return`.${tlds[tlds.length-1]}`;
+}
+
+return`.${tlds.join('.')}`;
+}
+
+
+
+
+
+
+
+static rootDomainsMatch(urlA,urlB){
+let urlAInfo;
+let urlBInfo;
+try{
+urlAInfo=new URL(urlA);
+urlBInfo=new URL(urlB);
+}catch(err){
+return false;
+}
+
+if(!urlAInfo.hostname||!urlBInfo.hostname){
+return false;
+}
+
+const tldA=URLShim.getTld(urlAInfo.hostname);
+const tldB=URLShim.getTld(urlBInfo.hostname);
+
+
+const urlARootDomain=urlAInfo.hostname.replace(new RegExp(`${tldA}$`),'').
+split('.').splice(-1)[0];
+const urlBRootDomain=urlBInfo.hostname.replace(new RegExp(`${tldB}$`),'').
+split('.').splice(-1)[0];
+
+return urlARootDomain===urlBRootDomain;
+}
+
+
+
+
+
+
+static getURLDisplayName(url,options){
+return Util.getURLDisplayName(new URL(url),options);
+}
+
+
+
+
+
+
+static elideDataURI(url){
+try{
+const parsed=new URL(url);
+return parsed.protocol==='data:'?url.slice(0,100):url;
+}catch(e){
+return url;
+}
+}
+
+
+
+
+
+
+
+static equalWithExcludedFragments(url1,url2){
+[url1,url2]=[url1,url2].map(rewriteChromeInternalUrl);
+try{
+const urla=new URL(url1);
+urla.hash='';
+
+const urlb=new URL(url2);
+urlb.hash='';
+
+return urla.href===urlb.href;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+
+static isProtocolAllowed(url){
+try{
+const parsed=new URL(url);
+return allowedProtocols.includes(parsed.protocol);
+}catch(e){
+return false;
+}
+}}
+
+
+URLShim.URL=URL;
+
+URLShim.NON_NETWORK_PROTOCOLS=['blob','data','intent'];
+
+URLShim.INVALID_URL_DEBUG_STRING=
+'Lighthouse was unable to determine the URL of some script executions. '+
+'It\'s possible a Chrome extension or other eval\'d code is the source.';
+
+module.exports=URLShim;
+
+},{"../report/html/renderer/util.js":74,"url":"url"}]},{},[1]); \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/module.json b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/module.json
index 22c9ed80a5b..407717ae8a3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits2_worker/module.json
@@ -10,10 +10,10 @@
}
],
"scripts": [
- "lighthouse/lighthouse-background.js",
+ "lighthouse/lighthouse-dt-bundle.js",
"Audits2Service.js"
],
"skip_compilation": [
- "lighthouse/lighthouse-background.js"
+ "lighthouse/lighthouse-dt-bundle.js"
]
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/XHRBreakpointsSidebarPane.js b/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/XHRBreakpointsSidebarPane.js
index 2de8ea2b503..2fd60a923f2 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/XHRBreakpointsSidebarPane.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/XHRBreakpointsSidebarPane.js
@@ -40,8 +40,8 @@ BrowserDebugger.XHRBreakpointsSidebarPane = class extends UI.VBox {
contextMenu.show();
}
- _addButtonClicked() {
- UI.viewManager.showView('sources.xhrBreakpoints');
+ async _addButtonClicked() {
+ await UI.viewManager.showView('sources.xhrBreakpoints');
const inputElementContainer = createElementWithClass('p', 'breakpoint-condition');
inputElementContainer.textContent = Common.UIString('Break when URL contains:');
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/module.json b/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/module.json
index 5593cb1d73d..ca831aaf1d3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/browser_debugger/module.json
@@ -2,7 +2,7 @@
"extensions": [
{
"type": "view",
- "location": "sources-sidebar",
+ "location": "sources.sidebar-bottom",
"id": "sources.eventListenerBreakpoints",
"title": "Event Listener Breakpoints",
"order": 9,
@@ -18,7 +18,7 @@
},
{
"type": "view",
- "location": "sources-sidebar",
+ "location": "sources.sidebar-bottom",
"id": "sources.xhrBreakpoints",
"title": "XHR/fetch Breakpoints",
"order": 5,
@@ -28,7 +28,7 @@
},
{
"type": "view",
- "location": "sources-sidebar",
+ "location": "sources.sidebar-bottom",
"id": "sources.domBreakpoints",
"title": "DOM Breakpoints",
"order": 7,
@@ -67,7 +67,7 @@
},
{
"type": "view",
- "location": "sources-sidebar",
+ "location": "sources.sidebar-bottom",
"id": "sources.globalListeners",
"title": "Global Listeners",
"order": 8,
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/LogManager.js b/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/LogManager.js
index 8fa6c8b0913..faf4032e660 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/LogManager.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/LogManager.js
@@ -42,7 +42,22 @@ BrowserSDK.LogManager = class {
if (data.entry.networkRequestId)
SDK.networkLog.associateConsoleMessageWithRequest(consoleMessage, data.entry.networkRequestId);
- SDK.consoleModel.addMessage(consoleMessage);
+
+ if (consoleMessage.source === SDK.ConsoleMessage.MessageSource.Worker) {
+ const workerId = consoleMessage.workerId || '';
+ // We have a copy of worker messages reported through the page, so that
+ // user can see messages from the worker which has been already destroyed.
+ // When opening DevTools, give us some time to connect to the worker and
+ // not report the message twice if the worker is still alive.
+ if (SDK.targetManager.targetById(workerId))
+ return;
+ setTimeout(() => {
+ if (!SDK.targetManager.targetById(workerId))
+ SDK.consoleModel.addMessage(consoleMessage);
+ }, 1000);
+ } else {
+ SDK.consoleModel.addMessage(consoleMessage);
+ }
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/module.json b/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/module.json
index 1c276e0fa19..7cca023c87a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/browser_sdk/module.json
@@ -3,7 +3,6 @@
{
"type": "setting",
"category": "Network",
- "storageType": "session",
"title": "Preserve log",
"settingName": "network_log.preserve-log",
"settingType": "boolean",
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/changes/changesView.css b/chromium/third_party/blink/renderer/devtools/front_end/changes/changesView.css
index 8d3ad90584e..552e9ec2d0f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/changes/changesView.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/changes/changesView.css
@@ -3,14 +3,15 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-.insertion-point-main{
+[slot=insertion-point-main]{
flex-direction: column;
display: flex;
}
-.insertion-point-sidebar {
+[slot=insertion-point-sidebar] {
overflow: auto;
}
+
.editor-container{
flex: 1;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/brace-fold.js b/chromium/third_party/blink/renderer/devtools/front_end/cm/brace-fold.js
new file mode 100644
index 00000000000..2fee403822c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/brace-fold.js
@@ -0,0 +1,125 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+if (typeof exports == 'object' && typeof module == 'object') // CommonJS
+ mod(require('../../lib/codemirror'));
+else if (typeof define == 'function' && define.amd) // AMD
+ define(['../../lib/codemirror'], mod);
+else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+'use strict';
+
+CodeMirror.registerHelper('fold', 'brace', function(cm, start) {
+ var line = start.line, lineText = cm.getLine(line);
+ var tokenType;
+
+ function findOpening(openCh) {
+ for (var at = start.ch, pass = 0;;) {
+ var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
+ if (found == -1) {
+ if (pass == 1)
+ break;
+ pass = 1;
+ at = lineText.length;
+ continue;
+ }
+ if (pass == 1 && found < start.ch)
+ break;
+ tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
+ if (!/^(comment|string)/.test(tokenType))
+ return found + 1;
+ at = found - 1;
+ }
+ }
+
+ var startToken = '{', endToken = '}', startCh = findOpening('{');
+ if (startCh == null) {
+ startToken = '[', endToken = ']';
+ startCh = findOpening('[');
+ }
+
+ if (startCh == null)
+ return;
+ var count = 1, lastLine = cm.lastLine(), end, endCh;
+ outer: for (var i = line; i <= lastLine; ++i) {
+ var text = cm.getLine(i), pos = i == line ? startCh : 0;
+ for (;;) {
+ var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
+ if (nextOpen < 0)
+ nextOpen = text.length;
+ if (nextClose < 0)
+ nextClose = text.length;
+ pos = Math.min(nextOpen, nextClose);
+ if (pos == text.length)
+ break;
+ if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
+ if (pos == nextOpen)
+ ++count;
+ else if (!--count) {
+ end = i;
+ endCh = pos;
+ break outer;
+ }
+ }
+ ++pos;
+ }
+ }
+ if (end == null || line == end && endCh == startCh)
+ return;
+ return {from: CodeMirror.Pos(line, startCh), to: CodeMirror.Pos(end, endCh)};
+});
+
+CodeMirror.registerHelper('fold', 'import', function(cm, start) {
+ function hasImport(line) {
+ if (line < cm.firstLine() || line > cm.lastLine())
+ return null;
+ var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+ if (!/\S/.test(start.string))
+ start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+ if (start.type != 'keyword' || start.string != 'import')
+ return null;
+ // Now find closing semicolon, return its position
+ for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
+ var text = cm.getLine(i), semi = text.indexOf(';');
+ if (semi != -1)
+ return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
+ }
+ }
+
+ var startLine = start.line, has = hasImport(startLine), prev;
+ if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
+ return null;
+ for (var end = has.end;;) {
+ var next = hasImport(end.line + 1);
+ if (next == null)
+ break;
+ end = next.end;
+ }
+ return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
+});
+
+CodeMirror.registerHelper('fold', 'include', function(cm, start) {
+ function hasInclude(line) {
+ if (line < cm.firstLine() || line > cm.lastLine())
+ return null;
+ var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+ if (!/\S/.test(start.string))
+ start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+ if (start.type == 'meta' && start.string.slice(0, 8) == '#include')
+ return start.start + 8;
+ }
+
+ var startLine = start.line, has = hasInclude(startLine);
+ if (has == null || hasInclude(startLine - 1) != null)
+ return null;
+ for (var end = startLine;;) {
+ var next = hasInclude(end + 1);
+ if (next == null)
+ break;
+ ++end;
+ }
+ return {from: CodeMirror.Pos(startLine, has + 1), to: cm.clipPos(CodeMirror.Pos(end))};
+});
+}); \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.css b/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.css
index fdbf48c3994..66567f0f0d6 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.css
@@ -3,192 +3,192 @@
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
- .CodeMirror {
- position: relative;
- overflow: hidden;
- background: white;
- }
-
- .CodeMirror-scroll {
- overflow: scroll !important; /* Things will break if this is overridden */
- /* 30px is the magic margin used to hide the element's real scrollbars */
- /* See overflow: hidden in .CodeMirror */
- margin-bottom: -30px; margin-right: -30px;
- padding-bottom: 30px;
- height: 100%;
- outline: none; /* Prevent dragging from highlighting the element */
- position: relative;
- }
- .CodeMirror-sizer {
- position: relative;
- border-right: 30px solid transparent;
- }
-
- /* The fake, visible scrollbars. Used to force redraw during scrolling
- before actual scrolling happens, thus preventing shaking and
- flickering artifacts. */
- .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
- position: absolute;
- z-index: 6;
- display: none;
- }
- .CodeMirror-vscrollbar {
- right: 0; top: 0;
- overflow-x: hidden;
- overflow-y: scroll;
- }
- .CodeMirror-hscrollbar {
- bottom: 0; left: 0;
- overflow-y: hidden;
- overflow-x: scroll;
- }
- .CodeMirror-scrollbar-filler {
- right: 0; bottom: 0;
- }
- .CodeMirror-gutter-filler {
- left: 0; bottom: 0;
- }
-
- .CodeMirror-gutters {
- position: absolute; left: 0; top: 0;
- min-height: 100%;
- z-index: 3;
- }
- .CodeMirror-gutter {
- white-space: normal;
- height: 100%;
- display: inline-block;
- vertical-align: top;
- margin-bottom: -30px;
- }
- .CodeMirror-gutter-wrapper {
- position: absolute;
- z-index: 4;
- background: none !important;
- border: none !important;
- }
- .CodeMirror-gutter-background {
- position: absolute;
- top: 0; bottom: 0;
- z-index: 4;
- }
- .CodeMirror-gutter-elt {
- position: absolute;
- cursor: default;
- z-index: 4;
- }
- .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
- .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
-
- .CodeMirror-lines {
- cursor: text;
- min-height: 1px; /* prevents collapsing before first draw */
- }
- .CodeMirror pre {
- /* Reset some styles that the rest of the page might have set */
- -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
- border-width: 0;
- background: transparent;
- font-family: inherit;
- font-size: inherit;
- margin: 0;
- white-space: pre;
- word-wrap: normal;
- line-height: inherit;
- color: inherit;
- z-index: 2;
- position: relative;
- overflow: visible;
- -webkit-tap-highlight-color: transparent;
- -webkit-font-variant-ligatures: contextual;
- font-variant-ligatures: contextual;
- }
- .CodeMirror-wrap pre {
- word-wrap: break-word;
- white-space: pre-wrap;
- word-break: normal;
- }
-
- .CodeMirror-linebackground {
- position: absolute;
- left: 0; right: 0; top: 0; bottom: 0;
- z-index: 0;
- }
-
- .CodeMirror-linewidget {
- position: relative;
- z-index: 2;
- padding: 0.1px; /* Force widget margins to stay inside of the container */
- }
-
- .CodeMirror-widget {}
-
- .CodeMirror-rtl pre { direction: rtl; }
-
- .CodeMirror-code {
- outline: none;
- }
-
- /* Force content-box sizing for the elements where we expect it */
- .CodeMirror-scroll,
- .CodeMirror-sizer,
- .CodeMirror-gutter,
- .CodeMirror-gutters,
- .CodeMirror-linenumber {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- }
-
- .CodeMirror-measure {
- position: absolute;
- width: 100%;
- height: 0;
- overflow: hidden;
- visibility: hidden;
- }
-
- .CodeMirror-cursor {
- position: absolute;
- pointer-events: none;
- }
- .CodeMirror-measure pre { position: static; }
-
- div.CodeMirror-cursors {
+.CodeMirror {
+ position: relative;
+ overflow: hidden;
+ background: white;
+}
+
+.CodeMirror-scroll {
+ overflow: scroll !important; /* Things will break if this is overridden */
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-right: -30px;
+ padding-bottom: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+}
+.CodeMirror-sizer {
+ position: relative;
+ border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actual scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ right: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; left: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; left: 0; top: 0;
+ min-height: 100%;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ display: inline-block;
+ vertical-align: top;
+ margin-bottom: -30px;
+}
+.CodeMirror-gutter-wrapper {
+ position: absolute;
+ z-index: 4;
+ background: none !important;
+ border: none !important;
+}
+.CodeMirror-gutter-background {
+ position: absolute;
+ top: 0; bottom: 0;
+ z-index: 4;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+}
+.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
+.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
+
+.CodeMirror-lines {
+ cursor: text;
+ min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-font-variant-ligatures: contextual;
+ font-variant-ligatures: contextual;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+
+.CodeMirror-linebackground {
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ padding: 0.1px; /* Force widget margins to stay inside of the container */
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-rtl pre { direction: rtl; }
+
+.CodeMirror-code {
+ outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%;
+ height: 0;
+ overflow: hidden;
+ visibility: hidden;
+}
+
+.CodeMirror-cursor {
+ position: absolute;
+ pointer-events: none;
+}
+.CodeMirror-measure pre { position: static; }
+
+div.CodeMirror-cursors {
+ visibility: hidden;
+ position: relative;
+ z-index: 3;
+}
+div.CodeMirror-dragcursors {
+ visibility: visible;
+}
+
+.CodeMirror-focused div.CodeMirror-cursors {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
+
+.cm-searching {
+ background-color: #ffa;
+ background-color: rgba(255, 255, 0, .4);
+}
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursors {
visibility: hidden;
- position: relative;
- z-index: 3;
- }
- div.CodeMirror-dragcursors {
- visibility: visible;
- }
-
- .CodeMirror-focused div.CodeMirror-cursors {
- visibility: visible;
- }
-
- .CodeMirror-selected { background: #d9d9d9; }
- .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
- .CodeMirror-crosshair { cursor: crosshair; }
- .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
- .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
-
- .cm-searching {
- background-color: #ffa;
- background-color: rgba(255, 255, 0, .4);
- }
-
- /* Used to force a border model for a node */
- .cm-force-border { padding-right: .1px; }
-
- @media print {
- /* Hide the cursor when printing */
- .CodeMirror div.CodeMirror-cursors {
- visibility: hidden;
- }
}
+}
- /* See issue #2901 */
- .cm-tab-wrap-hack:after { content: ''; }
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
- /* Help users use markselection to safely style text background */
- span.CodeMirror-selectedtext { background: none; }
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.js b/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.js
index eaea2faa043..fabfe4cd210 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/codemirror.js
@@ -8,9695 +8,9655 @@
// at http://marijnhaverbeke.nl/blog/#cm-internals .
(function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global.CodeMirror = factory());
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global.CodeMirror = factory());
}(this, (function () { 'use strict';
-// Kludges for bugs and behavior differences that can't be feature
-// detected are enabled based on userAgent etc sniffing.
-var userAgent = navigator.userAgent;
-var platform = navigator.platform;
-
-var gecko = /gecko\/\d/i.test(userAgent);
-var ie_upto10 = /MSIE \d/.test(userAgent);
-var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
-var edge = /Edge\/(\d+)/.exec(userAgent);
-var ie = ie_upto10 || ie_11up || edge;
-var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
-var webkit = !edge && /WebKit\//.test(userAgent);
-var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
-var chrome = !edge && /Chrome\//.test(userAgent);
-var presto = /Opera\//.test(userAgent);
-var safari = /Apple Computer/.test(navigator.vendor);
-var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
-var phantom = /PhantomJS/.test(userAgent);
-
-var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
-var android = /Android/.test(userAgent);
-// This is woefully incomplete. Suggestions for alternative methods welcome.
-var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
-var mac = ios || /Mac/.test(platform);
-var chromeOS = /\bCrOS\b/.test(userAgent);
-var windows = /win/i.test(platform);
-
-var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
-if (presto_version) { presto_version = Number(presto_version[1]); }
-if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
-// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
-var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
-var captureRightClick = gecko || (ie && ie_version >= 9);
-
-function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
-
-var rmClass = function(node, cls) {
- var current = node.className;
- var match = classTest(cls).exec(current);
- if (match) {
- var after = current.slice(match.index + match[0].length);
- node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
- }
-};
-
-function removeChildren(e) {
- for (var count = e.childNodes.length; count > 0; --count)
- { e.removeChild(e.firstChild); }
- return e
-}
-
-function removeChildrenAndAdd(parent, e) {
- return removeChildren(parent).appendChild(e)
-}
-
-function elt(tag, content, className, style) {
- var e = document.createElement(tag);
- if (className) { e.className = className; }
- if (style) { e.style.cssText = style; }
- if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
- else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
- return e
-}
-// wrapper for elt, which removes the elt from the accessibility tree
-function eltP(tag, content, className, style) {
- var e = elt(tag, content, className, style);
- e.setAttribute("role", "presentation");
- return e
-}
-
-var range;
-if (document.createRange) { range = function(node, start, end, endNode) {
- var r = document.createRange();
- r.setEnd(endNode || node, end);
- r.setStart(node, start);
- return r
-}; }
-else { range = function(node, start, end) {
- var r = document.body.createTextRange();
- try { r.moveToElementText(node.parentNode); }
- catch(e) { return r }
- r.collapse(true);
- r.moveEnd("character", end);
- r.moveStart("character", start);
- return r
-}; }
-
-function contains(parent, child) {
- if (child.nodeType == 3) // Android browser always returns false when child is a textnode
- { child = child.parentNode; }
- if (parent.contains)
- { return parent.contains(child) }
- do {
- if (child.nodeType == 11) { child = child.host; }
- if (child == parent) { return true }
- } while (child = child.parentNode)
-}
-
-function activeElt() {
- // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
- // IE < 10 will throw when accessed while the page is loading or in an iframe.
- // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
- var activeElement;
- try {
- activeElement = document.activeElement;
- } catch(e) {
- activeElement = document.body || null;
- }
- while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
- { activeElement = activeElement.shadowRoot.activeElement; }
- return activeElement
-}
-
-function addClass(node, cls) {
- var current = node.className;
- if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
-}
-function joinClasses(a, b) {
- var as = a.split(" ");
- for (var i = 0; i < as.length; i++)
- { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
- return b
-}
-
-var selectInput = function(node) { node.select(); };
-if (ios) // Mobile Safari apparently has a bug where select() is broken.
- { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
-else if (ie) // Suppress mysterious IE10 errors
- { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
-
-function bind(f) {
- var args = Array.prototype.slice.call(arguments, 1);
- return function(){return f.apply(null, args)}
-}
-
-function copyObj(obj, target, overwrite) {
- if (!target) { target = {}; }
- for (var prop in obj)
- { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
- { target[prop] = obj[prop]; } }
- return target
-}
-
-// Counts the column offset in a string, taking tabs into account.
-// Used mostly to find indentation.
-function countColumn(string, end, tabSize, startIndex, startValue) {
- if (end == null) {
- end = string.search(/[^\s\u00a0]/);
- if (end == -1) { end = string.length; }
- }
- for (var i = startIndex || 0, n = startValue || 0;;) {
- var nextTab = string.indexOf("\t", i);
- if (nextTab < 0 || nextTab >= end)
- { return n + (end - i) }
- n += nextTab - i;
- n += tabSize - (n % tabSize);
- i = nextTab + 1;
- }
-}
-
-var Delayed = function() {this.id = null;};
-Delayed.prototype.set = function (ms, f) {
- clearTimeout(this.id);
- this.id = setTimeout(f, ms);
-};
-
-function indexOf(array, elt) {
- for (var i = 0; i < array.length; ++i)
- { if (array[i] == elt) { return i } }
- return -1
-}
-
-// Number of pixels added to scroller and sizer to hide scrollbar
-var scrollerGap = 30;
-
-// Returned or thrown by various protocols to signal 'I'm not
-// handling this'.
-var Pass = {toString: function(){return "CodeMirror.Pass"}};
-
-// Reused option objects for setSelection & friends
-var sel_dontScroll = {scroll: false};
-var sel_mouse = {origin: "*mouse"};
-var sel_move = {origin: "+move"};
-
-// The inverse of countColumn -- find the offset that corresponds to
-// a particular column.
-function findColumn(string, goal, tabSize) {
- for (var pos = 0, col = 0;;) {
- var nextTab = string.indexOf("\t", pos);
- if (nextTab == -1) { nextTab = string.length; }
- var skipped = nextTab - pos;
- if (nextTab == string.length || col + skipped >= goal)
- { return pos + Math.min(skipped, goal - col) }
- col += nextTab - pos;
- col += tabSize - (col % tabSize);
- pos = nextTab + 1;
- if (col >= goal) { return pos }
- }
-}
-
-var spaceStrs = [""];
-function spaceStr(n) {
- while (spaceStrs.length <= n)
- { spaceStrs.push(lst(spaceStrs) + " "); }
- return spaceStrs[n]
-}
-
-function lst(arr) { return arr[arr.length-1] }
-
-function map(array, f) {
- var out = [];
- for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
- return out
-}
-
-function insertSorted(array, value, score) {
- var pos = 0, priority = score(value);
- while (pos < array.length && score(array[pos]) <= priority) { pos++; }
- array.splice(pos, 0, value);
-}
-
-function nothing() {}
-
-function createObj(base, props) {
- var inst;
- if (Object.create) {
- inst = Object.create(base);
- } else {
- nothing.prototype = base;
- inst = new nothing();
- }
- if (props) { copyObj(props, inst); }
- return inst
-}
-
-var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
-function isWordCharBasic(ch) {
- return /\w/.test(ch) || ch > "\x80" &&
- (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
-}
-function isWordChar(ch, helper) {
- if (!helper) { return isWordCharBasic(ch) }
- if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
- return helper.test(ch)
-}
-
-function isEmpty(obj) {
- for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
- return true
-}
-
-// Extending unicode characters. A series of a non-extending char +
-// any number of extending chars is treated as a single unit as far
-// as editing and measuring is concerned. This is not fully correct,
-// since some scripts/fonts/browsers also treat other configurations
-// of code points as a group.
-var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
-function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
-
-// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
-function skipExtendingChars(str, pos, dir) {
- while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
- return pos
-}
-
-// Returns the value from the range [`from`; `to`] that satisfies
-// `pred` and is closest to `from`. Assumes that at least `to`
-// satisfies `pred`. Supports `from` being greater than `to`.
-function findFirst(pred, from, to) {
- // At any point we are certain `to` satisfies `pred`, don't know
- // whether `from` does.
- var dir = from > to ? -1 : 1;
- for (;;) {
- if (from == to) { return from }
- var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
- if (mid == from) { return pred(mid) ? from : to }
- if (pred(mid)) { to = mid; }
- else { from = mid + dir; }
- }
-}
-
-// The display handles the DOM integration, both for input reading
-// and content drawing. It holds references to DOM nodes and
-// display-related state.
-
-function Display(place, doc, input) {
- var d = this;
- this.input = input;
-
- // Covers bottom-right square when both scrollbars are present.
- d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
- d.scrollbarFiller.setAttribute("cm-not-content", "true");
- // Covers bottom of gutter when coverGutterNextToScrollbar is on
- // and h scrollbar is present.
- d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
- d.gutterFiller.setAttribute("cm-not-content", "true");
- // Will contain the actual code, positioned to cover the viewport.
- d.lineDiv = eltP("div", null, "CodeMirror-code");
- // Elements are added to these to represent selection and cursors.
- d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
- d.cursorDiv = elt("div", null, "CodeMirror-cursors");
- // A visibility: hidden element used to find the size of things.
- d.measure = elt("div", null, "CodeMirror-measure");
- // When lines outside of the viewport are measured, they are drawn in this.
- d.lineMeasure = elt("div", null, "CodeMirror-measure");
- // Wraps everything that needs to exist inside the vertically-padded coordinate system
- d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
- null, "position: relative; outline: none");
- var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
- // Moved around its parent to cover visible view.
- d.mover = elt("div", [lines], null, "position: relative");
- // Set to the height of the document, allowing scrolling.
- d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
- d.sizerWidth = null;
- // Behavior of elts with overflow: auto and padding is
- // inconsistent across browsers. This is used to ensure the
- // scrollable area is big enough.
- d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
- // Will contain the gutters, if any.
- d.gutters = elt("div", null, "CodeMirror-gutters");
- d.lineGutter = null;
- // Actual scrollable element.
- d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
- d.scroller.setAttribute("tabIndex", "-1");
- // The element in which the editor lives.
- d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
-
- // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
- if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
- if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
-
- if (place) {
- if (place.appendChild) { place.appendChild(d.wrapper); }
- else { place(d.wrapper); }
- }
-
- // Current rendered range (may be bigger than the view window).
- d.viewFrom = d.viewTo = doc.first;
- d.reportedViewFrom = d.reportedViewTo = doc.first;
- // Information about the rendered lines.
- d.view = [];
- d.renderedView = null;
- // Holds info about a single rendered line when it was rendered
- // for measurement, while not in view.
- d.externalMeasured = null;
- // Empty space (in pixels) above the view
- d.viewOffset = 0;
- d.lastWrapHeight = d.lastWrapWidth = 0;
- d.updateLineNumbers = null;
-
- d.nativeBarWidth = d.barHeight = d.barWidth = 0;
- d.scrollbarsClipped = false;
-
- // Used to only resize the line number gutter when necessary (when
- // the amount of lines crosses a boundary that makes its width change)
- d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
- // Set to true when a non-horizontal-scrolling line widget is
- // added. As an optimization, line widget aligning is skipped when
- // this is false.
- d.alignWidgets = false;
-
- d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
-
- // Tracks the maximum line length so that the horizontal scrollbar
- // can be kept static when scrolling.
- d.maxLine = null;
- d.maxLineLength = 0;
- d.maxLineChanged = false;
-
- // Used for measuring wheel scrolling granularity
- d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
-
- // True when shift is held down.
- d.shift = false;
-
- // Used to track whether anything happened since the context menu
- // was opened.
- d.selForContextMenu = null;
-
- d.activeTouch = null;
-
- input.init(d);
-}
-
-// Find the line object corresponding to the given line number.
-function getLine(doc, n) {
- n -= doc.first;
- if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
- var chunk = doc;
- while (!chunk.lines) {
- for (var i = 0;; ++i) {
- var child = chunk.children[i], sz = child.chunkSize();
- if (n < sz) { chunk = child; break }
- n -= sz;
- }
- }
- return chunk.lines[n]
-}
-
-// Get the part of a document between two positions, as an array of
-// strings.
-function getBetween(doc, start, end) {
- var out = [], n = start.line;
- doc.iter(start.line, end.line + 1, function (line) {
- var text = line.text;
- if (n == end.line) { text = text.slice(0, end.ch); }
- if (n == start.line) { text = text.slice(start.ch); }
- out.push(text);
- ++n;
- });
- return out
-}
-// Get the lines between from and to, as array of strings.
-function getLines(doc, from, to) {
- var out = [];
- doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
- return out
-}
-
-// Update the height of a line, propagating the height change
-// upwards to parent nodes.
-function updateLineHeight(line, height) {
- var diff = height - line.height;
- if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
-}
-
-// Given a line object, find its line number by walking up through
-// its parent links.
-function lineNo(line) {
- if (line.parent == null) { return null }
- var cur = line.parent, no = indexOf(cur.lines, line);
- for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
- for (var i = 0;; ++i) {
- if (chunk.children[i] == cur) { break }
- no += chunk.children[i].chunkSize();
- }
- }
- return no + cur.first
-}
-
-// Find the line at the given vertical position, using the height
-// information in the document tree.
-function lineAtHeight(chunk, h) {
- var n = chunk.first;
- outer: do {
- for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
- var child = chunk.children[i$1], ch = child.height;
- if (h < ch) { chunk = child; continue outer }
- h -= ch;
- n += child.chunkSize();
- }
- return n
- } while (!chunk.lines)
- var i = 0;
- for (; i < chunk.lines.length; ++i) {
- var line = chunk.lines[i], lh = line.height;
- if (h < lh) { break }
- h -= lh;
- }
- return n + i
-}
-
-function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
-
-function lineNumberFor(options, i) {
- return String(options.lineNumberFormatter(i + options.firstLineNumber))
-}
-
-// A Pos instance represents a position within the text.
-function Pos(line, ch, sticky) {
- if ( sticky === void 0 ) sticky = null;
-
- if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
- this.line = line;
- this.ch = ch;
- this.sticky = sticky;
-}
-
-// Compare two positions, return 0 if they are the same, a negative
-// number when a is less, and a positive number otherwise.
-function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
-
-function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
-
-function copyPos(x) {return Pos(x.line, x.ch)}
-function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
-function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
-
-// Most of the external API clips given positions to make sure they
-// actually exist within the document.
-function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
-function clipPos(doc, pos) {
- if (pos.line < doc.first) { return Pos(doc.first, 0) }
- var last = doc.first + doc.size - 1;
- if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
- return clipToLen(pos, getLine(doc, pos.line).text.length)
-}
-function clipToLen(pos, linelen) {
- var ch = pos.ch;
- if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
- else if (ch < 0) { return Pos(pos.line, 0) }
- else { return pos }
-}
-function clipPosArray(doc, array) {
- var out = [];
- for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
- return out
-}
-
-// Optimize some code when these features are not used.
-var sawReadOnlySpans = false;
-var sawCollapsedSpans = false;
-
-function seeReadOnlySpans() {
- sawReadOnlySpans = true;
-}
-
-function seeCollapsedSpans() {
- sawCollapsedSpans = true;
-}
-
-// TEXTMARKER SPANS
-
-function MarkedSpan(marker, from, to) {
- this.marker = marker;
- this.from = from; this.to = to;
-}
-
-// Search an array of spans for a span matching the given marker.
-function getMarkedSpanFor(spans, marker) {
- if (spans) { for (var i = 0; i < spans.length; ++i) {
- var span = spans[i];
- if (span.marker == marker) { return span }
- } }
-}
-// Remove a span from an array, returning undefined if no spans are
-// left (we don't store arrays for lines without spans).
-function removeMarkedSpan(spans, span) {
- var r;
- for (var i = 0; i < spans.length; ++i)
- { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
- return r
-}
-// Add a span to a line.
-function addMarkedSpan(line, span) {
- line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
- span.marker.attachLine(line);
-}
-
-// Used for the algorithm that adjusts markers for a change in the
-// document. These functions cut an array of spans at a given
-// character position, returning an array of remaining chunks (or
-// undefined if nothing remains).
-function markedSpansBefore(old, startCh, isInsert) {
- var nw;
- if (old) { for (var i = 0; i < old.length; ++i) {
- var span = old[i], marker = span.marker;
- var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
- if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
- var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
- }
- } }
- return nw
-}
-function markedSpansAfter(old, endCh, isInsert) {
- var nw;
- if (old) { for (var i = 0; i < old.length; ++i) {
- var span = old[i], marker = span.marker;
- var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
- if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
- var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
- span.to == null ? null : span.to - endCh));
- }
- } }
- return nw
-}
-
-// Given a change object, compute the new set of marker spans that
-// cover the line in which the change took place. Removes spans
-// entirely within the change, reconnects spans belonging to the
-// same marker that appear on both sides of the change, and cuts off
-// spans partially within the change. Returns an array of span
-// arrays with one element for each line in (after) the change.
-function stretchSpansOverChange(doc, change) {
- if (change.full) { return null }
- var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
- var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
- if (!oldFirst && !oldLast) { return null }
-
- var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
- // Get the spans that 'stick out' on both sides
- var first = markedSpansBefore(oldFirst, startCh, isInsert);
- var last = markedSpansAfter(oldLast, endCh, isInsert);
-
- // Next, merge those two ends
- var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
- if (first) {
- // Fix up .to properties of first
- for (var i = 0; i < first.length; ++i) {
- var span = first[i];
- if (span.to == null) {
- var found = getMarkedSpanFor(last, span.marker);
- if (!found) { span.to = startCh; }
- else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
- }
- }
- }
- if (last) {
- // Fix up .from in last (or move them into first in case of sameLine)
- for (var i$1 = 0; i$1 < last.length; ++i$1) {
- var span$1 = last[i$1];
- if (span$1.to != null) { span$1.to += offset; }
- if (span$1.from == null) {
- var found$1 = getMarkedSpanFor(first, span$1.marker);
- if (!found$1) {
- span$1.from = offset;
- if (sameLine) { (first || (first = [])).push(span$1); }
- }
- } else {
- span$1.from += offset;
- if (sameLine) { (first || (first = [])).push(span$1); }
- }
- }
- }
- // Make sure we didn't create any zero-length spans
- if (first) { first = clearEmptySpans(first); }
- if (last && last != first) { last = clearEmptySpans(last); }
-
- var newMarkers = [first];
- if (!sameLine) {
- // Fill gap with whole-line-spans
- var gap = change.text.length - 2, gapMarkers;
- if (gap > 0 && first)
- { for (var i$2 = 0; i$2 < first.length; ++i$2)
- { if (first[i$2].to == null)
- { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
- for (var i$3 = 0; i$3 < gap; ++i$3)
- { newMarkers.push(gapMarkers); }
- newMarkers.push(last);
- }
- return newMarkers
-}
-
-// Remove spans that are empty and don't have a clearWhenEmpty
-// option of false.
-function clearEmptySpans(spans) {
- for (var i = 0; i < spans.length; ++i) {
- var span = spans[i];
- if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
- { spans.splice(i--, 1); }
- }
- if (!spans.length) { return null }
- return spans
-}
-
-// Used to 'clip' out readOnly ranges when making a change.
-function removeReadOnlyRanges(doc, from, to) {
- var markers = null;
- doc.iter(from.line, to.line + 1, function (line) {
- if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
- var mark = line.markedSpans[i].marker;
- if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
- { (markers || (markers = [])).push(mark); }
- } }
- });
- if (!markers) { return null }
- var parts = [{from: from, to: to}];
- for (var i = 0; i < markers.length; ++i) {
- var mk = markers[i], m = mk.find(0);
- for (var j = 0; j < parts.length; ++j) {
- var p = parts[j];
- if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
- var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
- if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
- { newParts.push({from: p.from, to: m.from}); }
- if (dto > 0 || !mk.inclusiveRight && !dto)
- { newParts.push({from: m.to, to: p.to}); }
- parts.splice.apply(parts, newParts);
- j += newParts.length - 3;
- }
- }
- return parts
-}
-
-// Connect or disconnect spans from a line.
-function detachMarkedSpans(line) {
- var spans = line.markedSpans;
- if (!spans) { return }
- for (var i = 0; i < spans.length; ++i)
- { spans[i].marker.detachLine(line); }
- line.markedSpans = null;
-}
-function attachMarkedSpans(line, spans) {
- if (!spans) { return }
- for (var i = 0; i < spans.length; ++i)
- { spans[i].marker.attachLine(line); }
- line.markedSpans = spans;
-}
-
-// Helpers used when computing which overlapping collapsed span
-// counts as the larger one.
-function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
-function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
-
-// Returns a number indicating which of two overlapping collapsed
-// spans is larger (and thus includes the other). Falls back to
-// comparing ids when the spans cover exactly the same range.
-function compareCollapsedMarkers(a, b) {
- var lenDiff = a.lines.length - b.lines.length;
- if (lenDiff != 0) { return lenDiff }
- var aPos = a.find(), bPos = b.find();
- var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
- if (fromCmp) { return -fromCmp }
- var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
- if (toCmp) { return toCmp }
- return b.id - a.id
-}
-
-// Find out whether a line ends or starts in a collapsed span. If
-// so, return the marker for that span.
-function collapsedSpanAtSide(line, start) {
- var sps = sawCollapsedSpans && line.markedSpans, found;
- if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
- sp = sps[i];
- if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
- (!found || compareCollapsedMarkers(found, sp.marker) < 0))
- { found = sp.marker; }
- } }
- return found
-}
-function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
-function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
-
-function collapsedSpanAround(line, ch) {
- var sps = sawCollapsedSpans && line.markedSpans, found;
- if (sps) { for (var i = 0; i < sps.length; ++i) {
- var sp = sps[i];
- if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
- (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
- } }
- return found
-}
-
-// Test whether there exists a collapsed span that partially
-// overlaps (covers the start or end, but not both) of a new span.
-// Such overlap is not allowed.
-function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
- var line = getLine(doc, lineNo$$1);
- var sps = sawCollapsedSpans && line.markedSpans;
- if (sps) { for (var i = 0; i < sps.length; ++i) {
- var sp = sps[i];
- if (!sp.marker.collapsed) { continue }
- var found = sp.marker.find(0);
- var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
- var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
- if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
- if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
- fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
- { return true }
- } }
-}
-
-// A visual line is a line as drawn on the screen. Folding, for
-// example, can cause multiple logical lines to appear on the same
-// visual line. This finds the start of the visual line that the
-// given line is part of (usually that is the line itself).
-function visualLine(line) {
- var merged;
- while (merged = collapsedSpanAtStart(line))
- { line = merged.find(-1, true).line; }
- return line
-}
-
-function visualLineEnd(line) {
- var merged;
- while (merged = collapsedSpanAtEnd(line))
- { line = merged.find(1, true).line; }
- return line
-}
-
-// Returns an array of logical lines that continue the visual line
-// started by the argument, or undefined if there are no such lines.
-function visualLineContinued(line) {
- var merged, lines;
- while (merged = collapsedSpanAtEnd(line)) {
- line = merged.find(1, true).line
- ;(lines || (lines = [])).push(line);
- }
- return lines
-}
-
-// Get the line number of the start of the visual line that the
-// given line number is part of.
-function visualLineNo(doc, lineN) {
- var line = getLine(doc, lineN), vis = visualLine(line);
- if (line == vis) { return lineN }
- return lineNo(vis)
-}
-
-// Get the line number of the start of the next visual line after
-// the given line.
-function visualLineEndNo(doc, lineN) {
- if (lineN > doc.lastLine()) { return lineN }
- var line = getLine(doc, lineN), merged;
- if (!lineIsHidden(doc, line)) { return lineN }
- while (merged = collapsedSpanAtEnd(line))
- { line = merged.find(1, true).line; }
- return lineNo(line) + 1
-}
-
-// Compute whether a line is hidden. Lines count as hidden when they
-// are part of a visual line that starts with another line, or when
-// they are entirely covered by collapsed, non-widget span.
-function lineIsHidden(doc, line) {
- var sps = sawCollapsedSpans && line.markedSpans;
- if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
- sp = sps[i];
- if (!sp.marker.collapsed) { continue }
- if (sp.from == null) { return true }
- if (sp.marker.widgetNode) { continue }
- if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
- { return true }
- } }
-}
-function lineIsHiddenInner(doc, line, span) {
- if (span.to == null) {
- var end = span.marker.find(1, true);
- return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
- }
- if (span.marker.inclusiveRight && span.to == line.text.length)
- { return true }
- for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
- sp = line.markedSpans[i];
- if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
- (sp.to == null || sp.to != span.from) &&
- (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
- lineIsHiddenInner(doc, line, sp)) { return true }
- }
-}
-
-// Find the height above the given line.
-function heightAtLine(lineObj) {
- lineObj = visualLine(lineObj);
-
- var h = 0, chunk = lineObj.parent;
- for (var i = 0; i < chunk.lines.length; ++i) {
- var line = chunk.lines[i];
- if (line == lineObj) { break }
- else { h += line.height; }
- }
- for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
- for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
- var cur = p.children[i$1];
- if (cur == chunk) { break }
- else { h += cur.height; }
- }
- }
- return h
-}
-
-// Compute the character length of a line, taking into account
-// collapsed ranges (see markText) that might hide parts, and join
-// other lines onto it.
-function lineLength(line) {
- if (line.height == 0) { return 0 }
- var len = line.text.length, merged, cur = line;
- while (merged = collapsedSpanAtStart(cur)) {
- var found = merged.find(0, true);
- cur = found.from.line;
- len += found.from.ch - found.to.ch;
- }
- cur = line;
- while (merged = collapsedSpanAtEnd(cur)) {
- var found$1 = merged.find(0, true);
- len -= cur.text.length - found$1.from.ch;
- cur = found$1.to.line;
- len += cur.text.length - found$1.to.ch;
- }
- return len
-}
-
-// Find the longest line in the document.
-function findMaxLine(cm) {
- var d = cm.display, doc = cm.doc;
- d.maxLine = getLine(doc, doc.first);
- d.maxLineLength = lineLength(d.maxLine);
- d.maxLineChanged = true;
- doc.iter(function (line) {
- var len = lineLength(line);
- if (len > d.maxLineLength) {
- d.maxLineLength = len;
- d.maxLine = line;
+ // Kludges for bugs and behavior differences that can't be feature
+ // detected are enabled based on userAgent etc sniffing.
+ var userAgent = navigator.userAgent;
+ var platform = navigator.platform;
+
+ var gecko = /gecko\/\d/i.test(userAgent);
+ var ie_upto10 = /MSIE \d/.test(userAgent);
+ var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
+ var edge = /Edge\/(\d+)/.exec(userAgent);
+ var ie = ie_upto10 || ie_11up || edge;
+ var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
+ var webkit = !edge && /WebKit\//.test(userAgent);
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
+ var chrome = !edge && /Chrome\//.test(userAgent);
+ var presto = /Opera\//.test(userAgent);
+ var safari = /Apple Computer/.test(navigator.vendor);
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
+ var phantom = /PhantomJS/.test(userAgent);
+
+ var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
+ var android = /Android/.test(userAgent);
+ // This is woefully incomplete. Suggestions for alternative methods welcome.
+ var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
+ var mac = ios || /Mac/.test(platform);
+ var chromeOS = /\bCrOS\b/.test(userAgent);
+ var windows = /win/i.test(platform);
+
+ var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
+ if (presto_version) { presto_version = Number(presto_version[1]); }
+ if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
+ // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
+ var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
+ var captureRightClick = gecko || (ie && ie_version >= 9);
+
+ function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
+
+ var rmClass = function(node, cls) {
+ var current = node.className;
+ var match = classTest(cls).exec(current);
+ if (match) {
+ var after = current.slice(match.index + match[0].length);
+ node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
}
- });
-}
-
-// BIDI HELPERS
-
-function iterateBidiSections(order, from, to, f) {
- if (!order) { return f(from, to, "ltr", 0) }
- var found = false;
- for (var i = 0; i < order.length; ++i) {
- var part = order[i];
- if (part.from < to && part.to > from || from == to && part.to == from) {
- f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
- found = true;
- }
- }
- if (!found) { f(from, to, "ltr"); }
-}
-
-var bidiOther = null;
-function getBidiPartAt(order, ch, sticky) {
- var found;
- bidiOther = null;
- for (var i = 0; i < order.length; ++i) {
- var cur = order[i];
- if (cur.from < ch && cur.to > ch) { return i }
- if (cur.to == ch) {
- if (cur.from != cur.to && sticky == "before") { found = i; }
- else { bidiOther = i; }
- }
- if (cur.from == ch) {
- if (cur.from != cur.to && sticky != "before") { found = i; }
- else { bidiOther = i; }
- }
- }
- return found != null ? found : bidiOther
-}
-
-// Bidirectional ordering algorithm
-// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
-// that this (partially) implements.
-
-// One-char codes used for character types:
-// L (L): Left-to-Right
-// R (R): Right-to-Left
-// r (AL): Right-to-Left Arabic
-// 1 (EN): European Number
-// + (ES): European Number Separator
-// % (ET): European Number Terminator
-// n (AN): Arabic Number
-// , (CS): Common Number Separator
-// m (NSM): Non-Spacing Mark
-// b (BN): Boundary Neutral
-// s (B): Paragraph Separator
-// t (S): Segment Separator
-// w (WS): Whitespace
-// N (ON): Other Neutrals
-
-// Returns null if characters are ordered as they appear
-// (left-to-right), or an array of sections ({from, to, level}
-// objects) in the order in which they occur visually.
-var bidiOrdering = (function() {
- // Character types for codepoints 0 to 0xff
- var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
- // Character types for codepoints 0x600 to 0x6f9
- var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
- function charType(code) {
- if (code <= 0xf7) { return lowTypes.charAt(code) }
- else if (0x590 <= code && code <= 0x5f4) { return "R" }
- else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
- else if (0x6ee <= code && code <= 0x8ac) { return "r" }
- else if (0x2000 <= code && code <= 0x200b) { return "w" }
- else if (code == 0x200c) { return "b" }
- else { return "L" }
- }
-
- var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
- var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
-
- function BidiSpan(level, from, to) {
- this.level = level;
- this.from = from; this.to = to;
+ };
+
+ function removeChildren(e) {
+ for (var count = e.childNodes.length; count > 0; --count)
+ { e.removeChild(e.firstChild); }
+ return e
}
- return function(str, direction) {
- var outerType = direction == "ltr" ? "L" : "R";
-
- if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
- var len = str.length, types = [];
- for (var i = 0; i < len; ++i)
- { types.push(charType(str.charCodeAt(i))); }
-
- // W1. Examine each non-spacing mark (NSM) in the level run, and
- // change the type of the NSM to the type of the previous
- // character. If the NSM is at the start of the level run, it will
- // get the type of sor.
- for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
- var type = types[i$1];
- if (type == "m") { types[i$1] = prev; }
- else { prev = type; }
- }
-
- // W2. Search backwards from each instance of a European number
- // until the first strong type (R, L, AL, or sor) is found. If an
- // AL is found, change the type of the European number to Arabic
- // number.
- // W3. Change all ALs to R.
- for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
- var type$1 = types[i$2];
- if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
- else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
- }
-
- // W4. A single European separator between two European numbers
- // changes to a European number. A single common separator between
- // two numbers of the same type changes to that type.
- for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
- var type$2 = types[i$3];
- if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
- else if (type$2 == "," && prev$1 == types[i$3+1] &&
- (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
- prev$1 = type$2;
- }
-
- // W5. A sequence of European terminators adjacent to European
- // numbers changes to all European numbers.
- // W6. Otherwise, separators and terminators change to Other
- // Neutral.
- for (var i$4 = 0; i$4 < len; ++i$4) {
- var type$3 = types[i$4];
- if (type$3 == ",") { types[i$4] = "N"; }
- else if (type$3 == "%") {
- var end = (void 0);
- for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
- var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
- for (var j = i$4; j < end; ++j) { types[j] = replace; }
- i$4 = end - 1;
- }
- }
-
- // W7. Search backwards from each instance of a European number
- // until the first strong type (R, L, or sor) is found. If an L is
- // found, then change the type of the European number to L.
- for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
- var type$4 = types[i$5];
- if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
- else if (isStrong.test(type$4)) { cur$1 = type$4; }
- }
-
- // N1. A sequence of neutrals takes the direction of the
- // surrounding strong text if the text on both sides has the same
- // direction. European and Arabic numbers act as if they were R in
- // terms of their influence on neutrals. Start-of-level-run (sor)
- // and end-of-level-run (eor) are used at level run boundaries.
- // N2. Any remaining neutrals take the embedding direction.
- for (var i$6 = 0; i$6 < len; ++i$6) {
- if (isNeutral.test(types[i$6])) {
- var end$1 = (void 0);
- for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
- var before = (i$6 ? types[i$6-1] : outerType) == "L";
- var after = (end$1 < len ? types[end$1] : outerType) == "L";
- var replace$1 = before == after ? (before ? "L" : "R") : outerType;
- for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
- i$6 = end$1 - 1;
- }
- }
-
- // Here we depart from the documented algorithm, in order to avoid
- // building up an actual levels array. Since there are only three
- // levels (0, 1, 2) in an implementation that doesn't take
- // explicit embedding into account, we can build up the order on
- // the fly, without following the level-based algorithm.
- var order = [], m;
- for (var i$7 = 0; i$7 < len;) {
- if (countsAsLeft.test(types[i$7])) {
- var start = i$7;
- for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
- order.push(new BidiSpan(0, start, i$7));
- } else {
- var pos = i$7, at = order.length;
- for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
- for (var j$2 = pos; j$2 < i$7;) {
- if (countsAsNum.test(types[j$2])) {
- if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
- var nstart = j$2;
- for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
- order.splice(at, 0, new BidiSpan(2, nstart, j$2));
- pos = j$2;
- } else { ++j$2; }
- }
- if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
- }
- }
- if (direction == "ltr") {
- if (order[0].level == 1 && (m = str.match(/^\s+/))) {
- order[0].from = m[0].length;
- order.unshift(new BidiSpan(0, 0, m[0].length));
- }
- if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
- lst(order).to -= m[0].length;
- order.push(new BidiSpan(0, len - m[0].length, len));
- }
- }
-
- return direction == "rtl" ? order.reverse() : order
- }
-})();
-
-// Get the bidi ordering for the given line (and cache it). Returns
-// false for lines that are fully left-to-right, and an array of
-// BidiSpan objects otherwise.
-function getOrder(line, direction) {
- var order = line.order;
- if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
- return order
-}
-
-// EVENT HANDLING
-
-// Lightweight event framework. on/off also work on DOM nodes,
-// registering native DOM handlers.
-
-var noHandlers = [];
-
-var on = function(emitter, type, f) {
- if (emitter.addEventListener) {
- emitter.addEventListener(type, f, false);
- } else if (emitter.attachEvent) {
- emitter.attachEvent("on" + type, f);
- } else {
- var map$$1 = emitter._handlers || (emitter._handlers = {});
- map$$1[type] = (map$$1[type] || noHandlers).concat(f);
- }
-};
-
-function getHandlers(emitter, type) {
- return emitter._handlers && emitter._handlers[type] || noHandlers
-}
-
-function off(emitter, type, f) {
- if (emitter.removeEventListener) {
- emitter.removeEventListener(type, f, false);
- } else if (emitter.detachEvent) {
- emitter.detachEvent("on" + type, f);
- } else {
- var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
- if (arr) {
- var index = indexOf(arr, f);
- if (index > -1)
- { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
- }
- }
-}
-
-function signal(emitter, type /*, values...*/) {
- var handlers = getHandlers(emitter, type);
- if (!handlers.length) { return }
- var args = Array.prototype.slice.call(arguments, 2);
- for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
-}
-
-// The DOM events that CodeMirror handles can be overridden by
-// registering a (non-DOM) handler on the editor for the event name,
-// and preventDefault-ing the event in that handler.
-function signalDOMEvent(cm, e, override) {
- if (typeof e == "string")
- { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
- signal(cm, override || e.type, cm, e);
- return e_defaultPrevented(e) || e.codemirrorIgnore
-}
-
-function signalCursorActivity(cm) {
- var arr = cm._handlers && cm._handlers.cursorActivity;
- if (!arr) { return }
- var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
- for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
- { set.push(arr[i]); } }
-}
-
-function hasHandler(emitter, type) {
- return getHandlers(emitter, type).length > 0
-}
-
-// Add on and off methods to a constructor's prototype, to make
-// registering events on such objects more convenient.
-function eventMixin(ctor) {
- ctor.prototype.on = function(type, f) {on(this, type, f);};
- ctor.prototype.off = function(type, f) {off(this, type, f);};
-}
-
-// Due to the fact that we still support jurassic IE versions, some
-// compatibility wrappers are needed.
-
-function e_preventDefault(e) {
- if (e.preventDefault) { e.preventDefault(); }
- else { e.returnValue = false; }
-}
-function e_stopPropagation(e) {
- if (e.stopPropagation) { e.stopPropagation(); }
- else { e.cancelBubble = true; }
-}
-function e_defaultPrevented(e) {
- return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
-}
-function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
-
-function e_target(e) {return e.target || e.srcElement}
-function e_button(e) {
- var b = e.which;
- if (b == null) {
- if (e.button & 1) { b = 1; }
- else if (e.button & 2) { b = 3; }
- else if (e.button & 4) { b = 2; }
- }
- if (mac && e.ctrlKey && b == 1) { b = 3; }
- return b
-}
-
-// Detect drag-and-drop
-var dragAndDrop = function() {
- // There is *some* kind of drag-and-drop support in IE6-8, but I
- // couldn't get it to work yet.
- if (ie && ie_version < 9) { return false }
- var div = elt('div');
- return "draggable" in div || "dragDrop" in div
-}();
-
-var zwspSupported;
-function zeroWidthElement(measure) {
- if (zwspSupported == null) {
- var test = elt("span", "\u200b");
- removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
- if (measure.firstChild.offsetHeight != 0)
- { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
- }
- var node = zwspSupported ? elt("span", "\u200b") :
- elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
- node.setAttribute("cm-text", "");
- return node
-}
-
-// Feature-detect IE's crummy client rect reporting for bidi text
-var badBidiRects;
-function hasBadBidiRects(measure) {
- if (badBidiRects != null) { return badBidiRects }
- var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
- var r0 = range(txt, 0, 1).getBoundingClientRect();
- var r1 = range(txt, 1, 2).getBoundingClientRect();
- removeChildren(measure);
- if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
- return badBidiRects = (r1.right - r0.right < 3)
-}
-
-// See if "".split is the broken IE version, if so, provide an
-// alternative way to split lines.
-var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
- var pos = 0, result = [], l = string.length;
- while (pos <= l) {
- var nl = string.indexOf("\n", pos);
- if (nl == -1) { nl = string.length; }
- var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
- var rt = line.indexOf("\r");
- if (rt != -1) {
- result.push(line.slice(0, rt));
- pos += rt + 1;
- } else {
- result.push(line);
- pos = nl + 1;
- }
- }
- return result
-} : function (string) { return string.split(/\r\n?|\n/); };
-
-var hasSelection = window.getSelection ? function (te) {
- try { return te.selectionStart != te.selectionEnd }
- catch(e) { return false }
-} : function (te) {
- var range$$1;
- try {range$$1 = te.ownerDocument.selection.createRange();}
- catch(e) {}
- if (!range$$1 || range$$1.parentElement() != te) { return false }
- return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
-};
-
-var hasCopyEvent = (function () {
- var e = elt("div");
- if ("oncopy" in e) { return true }
- e.setAttribute("oncopy", "return;");
- return typeof e.oncopy == "function"
-})();
-
-var badZoomedRects = null;
-function hasBadZoomedRects(measure) {
- if (badZoomedRects != null) { return badZoomedRects }
- var node = removeChildrenAndAdd(measure, elt("span", "x"));
- var normal = node.getBoundingClientRect();
- var fromRange = range(node, 0, 1).getBoundingClientRect();
- return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
-}
-
-// Known modes, by name and by MIME
-var modes = {};
-var mimeModes = {};
-
-// Extra arguments are stored as the mode's dependencies, which is
-// used by (legacy) mechanisms like loadmode.js to automatically
-// load a mode. (Preferred mechanism is the require/define calls.)
-function defineMode(name, mode) {
- if (arguments.length > 2)
- { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
- modes[name] = mode;
-}
-
-function defineMIME(mime, spec) {
- mimeModes[mime] = spec;
-}
-
-// Given a MIME type, a {name, ...options} config object, or a name
-// string, return a mode config object.
-function resolveMode(spec) {
- if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
- spec = mimeModes[spec];
- } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
- var found = mimeModes[spec.name];
- if (typeof found == "string") { found = {name: found}; }
- spec = createObj(found, spec);
- spec.name = found.name;
- } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
- return resolveMode("application/xml")
- } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
- return resolveMode("application/json")
- }
- if (typeof spec == "string") { return {name: spec} }
- else { return spec || {name: "null"} }
-}
-
-// Given a mode spec (anything that resolveMode accepts), find and
-// initialize an actual mode object.
-function getMode(options, spec) {
- spec = resolveMode(spec);
- var mfactory = modes[spec.name];
- if (!mfactory) { return getMode(options, "text/plain") }
- var modeObj = mfactory(options, spec);
- if (modeExtensions.hasOwnProperty(spec.name)) {
- var exts = modeExtensions[spec.name];
- for (var prop in exts) {
- if (!exts.hasOwnProperty(prop)) { continue }
- if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
- modeObj[prop] = exts[prop];
- }
- }
- modeObj.name = spec.name;
- if (spec.helperType) { modeObj.helperType = spec.helperType; }
- if (spec.modeProps) { for (var prop$1 in spec.modeProps)
- { modeObj[prop$1] = spec.modeProps[prop$1]; } }
-
- return modeObj
-}
-
-// This can be used to attach properties to mode objects from
-// outside the actual mode definition.
-var modeExtensions = {};
-function extendMode(mode, properties) {
- var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
- copyObj(properties, exts);
-}
-
-function copyState(mode, state) {
- if (state === true) { return state }
- if (mode.copyState) { return mode.copyState(state) }
- var nstate = {};
- for (var n in state) {
- var val = state[n];
- if (val instanceof Array) { val = val.concat([]); }
- nstate[n] = val;
- }
- return nstate
-}
-
-// Given a mode and a state (for that mode), find the inner mode and
-// state at the position that the state refers to.
-function innerMode(mode, state) {
- var info;
- while (mode.innerMode) {
- info = mode.innerMode(state);
- if (!info || info.mode == mode) { break }
- state = info.state;
- mode = info.mode;
- }
- return info || {mode: mode, state: state}
-}
-
-function startState(mode, a1, a2) {
- return mode.startState ? mode.startState(a1, a2) : true
-}
-
-// STRING STREAM
-
-// Fed to the mode parsers, provides helper functions to make
-// parsers more succinct.
-
-var StringStream = function(string, tabSize, lineOracle) {
- this.pos = this.start = 0;
- this.string = string;
- this.tabSize = tabSize || 8;
- this.lastColumnPos = this.lastColumnValue = 0;
- this.lineStart = 0;
- this.lineOracle = lineOracle;
-};
-
-StringStream.prototype.eol = function () {return this.pos >= this.string.length};
-StringStream.prototype.sol = function () {return this.pos == this.lineStart};
-StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
-StringStream.prototype.next = function () {
- if (this.pos < this.string.length)
- { return this.string.charAt(this.pos++) }
-};
-StringStream.prototype.eat = function (match) {
- var ch = this.string.charAt(this.pos);
- var ok;
- if (typeof match == "string") { ok = ch == match; }
- else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
- if (ok) {++this.pos; return ch}
-};
-StringStream.prototype.eatWhile = function (match) {
- var start = this.pos;
- while (this.eat(match)){}
- return this.pos > start
-};
-StringStream.prototype.eatSpace = function () {
- var this$1 = this;
+ function removeChildrenAndAdd(parent, e) {
+ return removeChildren(parent).appendChild(e)
+ }
- var start = this.pos;
- while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
- return this.pos > start
-};
-StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
-StringStream.prototype.skipTo = function (ch) {
- var found = this.string.indexOf(ch, this.pos);
- if (found > -1) {this.pos = found; return true}
-};
-StringStream.prototype.backUp = function (n) {this.pos -= n;};
-StringStream.prototype.column = function () {
- if (this.lastColumnPos < this.start) {
- this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
- this.lastColumnPos = this.start;
- }
- return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
-};
-StringStream.prototype.indentation = function () {
- return countColumn(this.string, null, this.tabSize) -
- (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
-};
-StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
- if (typeof pattern == "string") {
- var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
- var substr = this.string.substr(this.pos, pattern.length);
- if (cased(substr) == cased(pattern)) {
- if (consume !== false) { this.pos += pattern.length; }
- return true
+ function elt(tag, content, className, style) {
+ var e = document.createElement(tag);
+ if (className) { e.className = className; }
+ if (style) { e.style.cssText = style; }
+ if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
+ else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
+ return e
+ }
+ // wrapper for elt, which removes the elt from the accessibility tree
+ function eltP(tag, content, className, style) {
+ var e = elt(tag, content, className, style);
+ e.setAttribute("role", "presentation");
+ return e
+ }
+
+ var range;
+ if (document.createRange) { range = function(node, start, end, endNode) {
+ var r = document.createRange();
+ r.setEnd(endNode || node, end);
+ r.setStart(node, start);
+ return r
+ }; }
+ else { range = function(node, start, end) {
+ var r = document.body.createTextRange();
+ try { r.moveToElementText(node.parentNode); }
+ catch(e) { return r }
+ r.collapse(true);
+ r.moveEnd("character", end);
+ r.moveStart("character", start);
+ return r
+ }; }
+
+ function contains(parent, child) {
+ if (child.nodeType == 3) // Android browser always returns false when child is a textnode
+ { child = child.parentNode; }
+ if (parent.contains)
+ { return parent.contains(child) }
+ do {
+ if (child.nodeType == 11) { child = child.host; }
+ if (child == parent) { return true }
+ } while (child = child.parentNode)
+ }
+
+ function activeElt() {
+ // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
+ // IE < 10 will throw when accessed while the page is loading or in an iframe.
+ // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
+ var activeElement;
+ try {
+ activeElement = document.activeElement;
+ } catch(e) {
+ activeElement = document.body || null;
}
- } else {
- var match = this.string.slice(this.pos).match(pattern);
- if (match && match.index > 0) { return null }
- if (match && consume !== false) { this.pos += match[0].length; }
- return match
- }
-};
-StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
-StringStream.prototype.hideFirstChars = function (n, inner) {
- this.lineStart += n;
- try { return inner() }
- finally { this.lineStart -= n; }
-};
-StringStream.prototype.lookAhead = function (n) {
- var oracle = this.lineOracle;
- return oracle && oracle.lookAhead(n)
-};
-StringStream.prototype.baseToken = function () {
- var oracle = this.lineOracle;
- return oracle && oracle.baseToken(this.pos)
-};
-
-var SavedContext = function(state, lookAhead) {
- this.state = state;
- this.lookAhead = lookAhead;
-};
-
-var Context = function(doc, state, line, lookAhead) {
- this.state = state;
- this.doc = doc;
- this.line = line;
- this.maxLookAhead = lookAhead || 0;
- this.baseTokens = null;
- this.baseTokenPos = 1;
-};
-
-Context.prototype.lookAhead = function (n) {
- var line = this.doc.getLine(this.line + n);
- if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
- return line
-};
-
-Context.prototype.baseToken = function (n) {
- var this$1 = this;
+ while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
+ { activeElement = activeElement.shadowRoot.activeElement; }
+ return activeElement
+ }
- if (!this.baseTokens) { return null }
- while (this.baseTokens[this.baseTokenPos] <= n)
- { this$1.baseTokenPos += 2; }
- var type = this.baseTokens[this.baseTokenPos + 1];
- return {type: type && type.replace(/( |^)overlay .*/, ""),
- size: this.baseTokens[this.baseTokenPos] - n}
-};
-
-Context.prototype.nextLine = function () {
- this.line++;
- if (this.maxLookAhead > 0) { this.maxLookAhead--; }
-};
-
-Context.fromSaved = function (doc, saved, line) {
- if (saved instanceof SavedContext)
- { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
- else
- { return new Context(doc, copyState(doc.mode, saved), line) }
-};
-
-Context.prototype.save = function (copy) {
- var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
- return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
-};
-
-
-// Compute a style array (an array starting with a mode generation
-// -- for invalidation -- followed by pairs of end positions and
-// style strings), which is used to highlight the tokens on the
-// line.
-function highlightLine(cm, line, context, forceToEnd) {
- // A styles array always starts with a number identifying the
- // mode/overlays that it is based on (for easy invalidation).
- var st = [cm.state.modeGen], lineClasses = {};
- // Compute the base array of styles
- runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
- lineClasses, forceToEnd);
- var state = context.state;
-
- // Run overlays, adjust style array.
- var loop = function ( o ) {
- context.baseTokens = st;
- var overlay = cm.state.overlays[o], i = 1, at = 0;
- context.state = true;
- runMode(cm, line.text, overlay.mode, context, function (end, style) {
- var start = i;
- // Ensure there's a token end at the current position, and that i points at it
- while (at < end) {
- var i_end = st[i];
- if (i_end > end)
- { st.splice(i, 1, end, st[i+1], i_end); }
- i += 2;
- at = Math.min(end, i_end);
- }
- if (!style) { return }
- if (overlay.opaque) {
- st.splice(start, i - start, end, "overlay " + style);
- i = start + 2;
- } else {
- for (; start < i; start += 2) {
- var cur = st[start+1];
- st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
- }
- }
- }, lineClasses);
- context.state = state;
- context.baseTokens = null;
- context.baseTokenPos = 1;
+ function addClass(node, cls) {
+ var current = node.className;
+ if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
+ }
+ function joinClasses(a, b) {
+ var as = a.split(" ");
+ for (var i = 0; i < as.length; i++)
+ { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
+ return b
+ }
+
+ var selectInput = function(node) { node.select(); };
+ if (ios) // Mobile Safari apparently has a bug where select() is broken.
+ { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
+ else if (ie) // Suppress mysterious IE10 errors
+ { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
+
+ function bind(f) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function(){return f.apply(null, args)}
+ }
+
+ function copyObj(obj, target, overwrite) {
+ if (!target) { target = {}; }
+ for (var prop in obj)
+ { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
+ { target[prop] = obj[prop]; } }
+ return target
+ }
+
+ // Counts the column offset in a string, taking tabs into account.
+ // Used mostly to find indentation.
+ function countColumn(string, end, tabSize, startIndex, startValue) {
+ if (end == null) {
+ end = string.search(/[^\s\u00a0]/);
+ if (end == -1) { end = string.length; }
+ }
+ for (var i = startIndex || 0, n = startValue || 0;;) {
+ var nextTab = string.indexOf("\t", i);
+ if (nextTab < 0 || nextTab >= end)
+ { return n + (end - i) }
+ n += nextTab - i;
+ n += tabSize - (n % tabSize);
+ i = nextTab + 1;
+ }
+ }
+
+ var Delayed = function() {this.id = null;};
+ Delayed.prototype.set = function (ms, f) {
+ clearTimeout(this.id);
+ this.id = setTimeout(f, ms);
};
- for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
-
- return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
-}
-
-function getLineStyles(cm, line, updateFrontier) {
- if (!line.styles || line.styles[0] != cm.state.modeGen) {
- var context = getContextBefore(cm, lineNo(line));
- var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
- var result = highlightLine(cm, line, context);
- if (resetState) { context.state = resetState; }
- line.stateAfter = context.save(!resetState);
- line.styles = result.styles;
- if (result.classes) { line.styleClasses = result.classes; }
- else if (line.styleClasses) { line.styleClasses = null; }
- if (updateFrontier === cm.doc.highlightFrontier)
- { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
- }
- return line.styles
-}
-
-function getContextBefore(cm, n, precise) {
- var doc = cm.doc, display = cm.display;
- if (!doc.mode.startState) { return new Context(doc, true, n) }
- var start = findStartLine(cm, n, precise);
- var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
- var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
-
- doc.iter(start, n, function (line) {
- processLine(cm, line.text, context);
- var pos = context.line;
- line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
- context.nextLine();
- });
- if (precise) { doc.modeFrontier = context.line; }
- return context
-}
-
-// Lightweight form of highlight -- proceed over this line and
-// update state, but don't save a style array. Used for lines that
-// aren't currently visible.
-function processLine(cm, text, context, startAt) {
- var mode = cm.doc.mode;
- var stream = new StringStream(text, cm.options.tabSize, context);
- stream.start = stream.pos = startAt || 0;
- if (text == "") { callBlankLine(mode, context.state); }
- while (!stream.eol()) {
- readToken(mode, stream, context.state);
- stream.start = stream.pos;
- }
-}
-
-function callBlankLine(mode, state) {
- if (mode.blankLine) { return mode.blankLine(state) }
- if (!mode.innerMode) { return }
- var inner = innerMode(mode, state);
- if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
-}
-
-function readToken(mode, stream, state, inner) {
- for (var i = 0; i < 10; i++) {
- if (inner) { inner[0] = innerMode(mode, state).mode; }
- var style = mode.token(stream, state);
- if (stream.pos > stream.start) { return style }
- }
- throw new Error("Mode " + mode.name + " failed to advance stream.")
-}
-
-var Token = function(stream, type, state) {
- this.start = stream.start; this.end = stream.pos;
- this.string = stream.current();
- this.type = type || null;
- this.state = state;
-};
-
-// Utility for getTokenAt and getLineTokens
-function takeToken(cm, pos, precise, asArray) {
- var doc = cm.doc, mode = doc.mode, style;
- pos = clipPos(doc, pos);
- var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
- var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
- if (asArray) { tokens = []; }
- while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
- stream.start = stream.pos;
- style = readToken(mode, stream, context.state);
- if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
- }
- return asArray ? tokens : new Token(stream, style, context.state)
-}
-
-function extractLineClasses(type, output) {
- if (type) { for (;;) {
- var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
- if (!lineClass) { break }
- type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
- var prop = lineClass[1] ? "bgClass" : "textClass";
- if (output[prop] == null)
- { output[prop] = lineClass[2]; }
- else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
- { output[prop] += " " + lineClass[2]; }
- } }
- return type
-}
-
-// Run the given mode's parser over a line, calling f for each token.
-function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
- var flattenSpans = mode.flattenSpans;
- if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
- var curStart = 0, curStyle = null;
- var stream = new StringStream(text, cm.options.tabSize, context), style;
- var inner = cm.options.addModeClass && [null];
- if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
- while (!stream.eol()) {
- if (stream.pos > cm.options.maxHighlightLength) {
- flattenSpans = false;
- if (forceToEnd) { processLine(cm, text, context, stream.pos); }
- stream.pos = text.length;
- style = null;
- } else {
- style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
- }
- if (inner) {
- var mName = inner[0].name;
- if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
- }
- if (!flattenSpans || curStyle != style) {
- while (curStart < stream.start) {
- curStart = Math.min(stream.start, curStart + 5000);
- f(curStart, curStyle);
- }
- curStyle = style;
- }
- stream.start = stream.pos;
- }
- while (curStart < stream.pos) {
- // Webkit seems to refuse to render text nodes longer than 57444
- // characters, and returns inaccurate measurements in nodes
- // starting around 5000 chars.
- var pos = Math.min(stream.pos, curStart + 5000);
- f(pos, curStyle);
- curStart = pos;
- }
-}
-
-// Finds the line to start with when starting a parse. Tries to
-// find a line with a stateAfter, so that it can start with a
-// valid state. If that fails, it returns the line with the
-// smallest indentation, which tends to need the least context to
-// parse correctly.
-function findStartLine(cm, n, precise) {
- var minindent, minline, doc = cm.doc;
- var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
- for (var search = n; search > lim; --search) {
- if (search <= doc.first) { return doc.first }
- var line = getLine(doc, search - 1), after = line.stateAfter;
- if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
- { return search }
- var indented = countColumn(line.text, null, cm.options.tabSize);
- if (minline == null || minindent > indented) {
- minline = search - 1;
- minindent = indented;
- }
- }
- return minline
-}
-
-function retreatFrontier(doc, n) {
- doc.modeFrontier = Math.min(doc.modeFrontier, n);
- if (doc.highlightFrontier < n - 10) { return }
- var start = doc.first;
- for (var line = n - 1; line > start; line--) {
- var saved = getLine(doc, line).stateAfter;
- // change is on 3
- // state on line 1 looked ahead 2 -- so saw 3
- // test 1 + 2 < 3 should cover this
- if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
- start = line + 1;
- break
- }
- }
- doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
-}
-
-// LINE DATA STRUCTURE
-
-// Line objects. These hold state related to a line, including
-// highlighting info (the styles array).
-var Line = function(text, markedSpans, estimateHeight) {
- this.text = text;
- attachMarkedSpans(this, markedSpans);
- this.height = estimateHeight ? estimateHeight(this) : 1;
-};
-
-Line.prototype.lineNo = function () { return lineNo(this) };
-eventMixin(Line);
-
-// Change the content (text, markers) of a line. Automatically
-// invalidates cached information and tries to re-estimate the
-// line's height.
-function updateLine(line, text, markedSpans, estimateHeight) {
- line.text = text;
- if (line.stateAfter) { line.stateAfter = null; }
- if (line.styles) { line.styles = null; }
- if (line.order != null) { line.order = null; }
- detachMarkedSpans(line);
- attachMarkedSpans(line, markedSpans);
- var estHeight = estimateHeight ? estimateHeight(line) : 1;
- if (estHeight != line.height) { updateLineHeight(line, estHeight); }
-}
-
-// Detach a line from the document tree and its markers.
-function cleanUpLine(line) {
- line.parent = null;
- detachMarkedSpans(line);
-}
-
-// Convert a style as returned by a mode (either null, or a string
-// containing one or more styles) to a CSS style. This is cached,
-// and also looks for line-wide styles.
-var styleToClassCache = {};
-var styleToClassCacheWithMode = {};
-function interpretTokenStyle(style, options) {
- if (!style || /^\s*$/.test(style)) { return null }
- var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
- return cache[style] ||
- (cache[style] = style.replace(/\S+/g, "cm-$&"))
-}
-
-// Render the DOM representation of the text of a line. Also builds
-// up a 'line map', which points at the DOM nodes that represent
-// specific stretches of text, and is used by the measuring code.
-// The returned object contains the DOM node, this map, and
-// information about line-wide styles that were set by the mode.
-function buildLineContent(cm, lineView) {
- // The padding-right forces the element to have a 'border', which
- // is needed on Webkit to be able to get line-level bounding
- // rectangles for it (in measureChar).
- var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
- var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
- col: 0, pos: 0, cm: cm,
- trailingSpace: false,
- splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
- lineView.measure = {};
-
- // Iterate over the logical lines that make up this visual line.
- for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
- var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
- builder.pos = 0;
- builder.addToken = buildToken;
- // Optionally wire in some hacks into the token-rendering
- // algorithm, to deal with browser quirks.
- if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
- { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
- builder.map = [];
- var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
- insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
- if (line.styleClasses) {
- if (line.styleClasses.bgClass)
- { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
- if (line.styleClasses.textClass)
- { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
- }
-
- // Ensure at least a single node is present, for measuring.
- if (builder.map.length == 0)
- { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
-
- // Store the map and a cache object for the current logical line
- if (i == 0) {
- lineView.measure.map = builder.map;
- lineView.measure.cache = {};
+ function indexOf(array, elt) {
+ for (var i = 0; i < array.length; ++i)
+ { if (array[i] == elt) { return i } }
+ return -1
+ }
+
+ // Number of pixels added to scroller and sizer to hide scrollbar
+ var scrollerGap = 30;
+
+ // Returned or thrown by various protocols to signal 'I'm not
+ // handling this'.
+ var Pass = {toString: function(){return "CodeMirror.Pass"}};
+
+ // Reused option objects for setSelection & friends
+ var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
+
+ // The inverse of countColumn -- find the offset that corresponds to
+ // a particular column.
+ function findColumn(string, goal, tabSize) {
+ for (var pos = 0, col = 0;;) {
+ var nextTab = string.indexOf("\t", pos);
+ if (nextTab == -1) { nextTab = string.length; }
+ var skipped = nextTab - pos;
+ if (nextTab == string.length || col + skipped >= goal)
+ { return pos + Math.min(skipped, goal - col) }
+ col += nextTab - pos;
+ col += tabSize - (col % tabSize);
+ pos = nextTab + 1;
+ if (col >= goal) { return pos }
+ }
+ }
+
+ var spaceStrs = [""];
+ function spaceStr(n) {
+ while (spaceStrs.length <= n)
+ { spaceStrs.push(lst(spaceStrs) + " "); }
+ return spaceStrs[n]
+ }
+
+ function lst(arr) { return arr[arr.length-1] }
+
+ function map(array, f) {
+ var out = [];
+ for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
+ return out
+ }
+
+ function insertSorted(array, value, score) {
+ var pos = 0, priority = score(value);
+ while (pos < array.length && score(array[pos]) <= priority) { pos++; }
+ array.splice(pos, 0, value);
+ }
+
+ function nothing() {}
+
+ function createObj(base, props) {
+ var inst;
+ if (Object.create) {
+ inst = Object.create(base);
} else {
- (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
- ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
- }
- }
-
- // See issue #2901
- if (webkit) {
- var last = builder.content.lastChild;
- if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
- { builder.content.className = "cm-tab-wrap-hack"; }
- }
-
- signal(cm, "renderLine", cm, lineView.line, builder.pre);
- if (builder.pre.className)
- { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
-
- return builder
-}
-
-function defaultSpecialCharPlaceholder(ch) {
- var token = elt("span", "\u2022", "cm-invalidchar");
- token.title = "\\u" + ch.charCodeAt(0).toString(16);
- token.setAttribute("aria-label", token.title);
- return token
-}
-
-// Build up the DOM representation for a single token, and add it to
-// the line map. Takes care to render special characters separately.
-function buildToken(builder, text, style, startStyle, endStyle, title, css) {
- if (!text) { return }
- var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
- var special = builder.cm.state.specialChars, mustWrap = false;
- var content;
- if (!special.test(text)) {
- builder.col += text.length;
- content = document.createTextNode(displayText);
- builder.map.push(builder.pos, builder.pos + text.length, content);
- if (ie && ie_version < 9) { mustWrap = true; }
- builder.pos += text.length;
- } else {
- content = document.createDocumentFragment();
- var pos = 0;
- while (true) {
- special.lastIndex = pos;
- var m = special.exec(text);
- var skipped = m ? m.index - pos : text.length - pos;
- if (skipped) {
- var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
- if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
- else { content.appendChild(txt); }
- builder.map.push(builder.pos, builder.pos + skipped, txt);
- builder.col += skipped;
- builder.pos += skipped;
- }
- if (!m) { break }
- pos += skipped + 1;
- var txt$1 = (void 0);
- if (m[0] == "\t") {
- var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
- txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
- txt$1.setAttribute("role", "presentation");
- txt$1.setAttribute("cm-text", "\t");
- builder.col += tabWidth;
- } else if (m[0] == "\r" || m[0] == "\n") {
- txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
- txt$1.setAttribute("cm-text", m[0]);
- builder.col += 1;
- } else {
- txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
- txt$1.setAttribute("cm-text", m[0]);
- if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
- else { content.appendChild(txt$1); }
- builder.col += 1;
- }
- builder.map.push(builder.pos, builder.pos + 1, txt$1);
- builder.pos++;
- }
- }
- builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
- if (style || startStyle || endStyle || mustWrap || css) {
- var fullStyle = style || "";
- if (startStyle) { fullStyle += startStyle; }
- if (endStyle) { fullStyle += endStyle; }
- var token = elt("span", [content], fullStyle, css);
- if (title) { token.title = title; }
- return builder.content.appendChild(token)
- }
- builder.content.appendChild(content);
-}
-
-function splitSpaces(text, trailingBefore) {
- if (text.length > 1 && !/ /.test(text)) { return text }
- var spaceBefore = trailingBefore, result = "";
- for (var i = 0; i < text.length; i++) {
- var ch = text.charAt(i);
- if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
- { ch = "\u00a0"; }
- result += ch;
- spaceBefore = ch == " ";
- }
- return result
-}
-
-// Work around nonsense dimensions being reported for stretches of
-// right-to-left text.
-function buildTokenBadBidi(inner, order) {
- return function (builder, text, style, startStyle, endStyle, title, css) {
- style = style ? style + " cm-force-border" : "cm-force-border";
- var start = builder.pos, end = start + text.length;
+ nothing.prototype = base;
+ inst = new nothing();
+ }
+ if (props) { copyObj(props, inst); }
+ return inst
+ }
+
+ var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
+ function isWordCharBasic(ch) {
+ return /\w/.test(ch) || ch > "\x80" &&
+ (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
+ }
+ function isWordChar(ch, helper) {
+ if (!helper) { return isWordCharBasic(ch) }
+ if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
+ return helper.test(ch)
+ }
+
+ function isEmpty(obj) {
+ for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
+ return true
+ }
+
+ // Extending unicode characters. A series of a non-extending char +
+ // any number of extending chars is treated as a single unit as far
+ // as editing and measuring is concerned. This is not fully correct,
+ // since some scripts/fonts/browsers also treat other configurations
+ // of code points as a group.
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
+
+ // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
+ function skipExtendingChars(str, pos, dir) {
+ while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
+ return pos
+ }
+
+ // Returns the value from the range [`from`; `to`] that satisfies
+ // `pred` and is closest to `from`. Assumes that at least `to`
+ // satisfies `pred`. Supports `from` being greater than `to`.
+ function findFirst(pred, from, to) {
+ // At any point we are certain `to` satisfies `pred`, don't know
+ // whether `from` does.
+ var dir = from > to ? -1 : 1;
for (;;) {
- // Find the part that overlaps with the start of this text
- var part = (void 0);
- for (var i = 0; i < order.length; i++) {
- part = order[i];
- if (part.to > start && part.from <= start) { break }
- }
- if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
- inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
- startStyle = null;
- text = text.slice(part.to - start);
- start = part.to;
- }
- }
-}
-
-function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
- var widget = !ignoreWidget && marker.widgetNode;
- if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
- if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
- if (!widget)
- { widget = builder.content.appendChild(document.createElement("span")); }
- widget.setAttribute("cm-marker", marker.id);
- }
- if (widget) {
- builder.cm.display.input.setUneditable(widget);
- builder.content.appendChild(widget);
- }
- builder.pos += size;
- builder.trailingSpace = false;
-}
-
-// Outputs a number of spans to make up a line, taking highlighting
-// and marked text into account.
-function insertLineContent(line, builder, styles) {
- var spans = line.markedSpans, allText = line.text, at = 0;
- if (!spans) {
- for (var i$1 = 1; i$1 < styles.length; i$1+=2)
- { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
- return
- }
-
- var len = allText.length, pos = 0, i = 1, text = "", style, css;
- var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
- for (;;) {
- if (nextChange == pos) { // Update current marker set
- spanStyle = spanEndStyle = spanStartStyle = title = css = "";
- collapsed = null; nextChange = Infinity;
- var foundBookmarks = [], endStyles = (void 0);
- for (var j = 0; j < spans.length; ++j) {
- var sp = spans[j], m = sp.marker;
- if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
- foundBookmarks.push(m);
- } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
- if (sp.to != null && sp.to != pos && nextChange > sp.to) {
- nextChange = sp.to;
- spanEndStyle = "";
+ if (from == to) { return from }
+ var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
+ if (mid == from) { return pred(mid) ? from : to }
+ if (pred(mid)) { to = mid; }
+ else { from = mid + dir; }
+ }
+ }
+
+ // The display handles the DOM integration, both for input reading
+ // and content drawing. It holds references to DOM nodes and
+ // display-related state.
+
+ function Display(place, doc, input) {
+ var d = this;
+ this.input = input;
+
+ // Covers bottom-right square when both scrollbars are present.
+ d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
+ d.scrollbarFiller.setAttribute("cm-not-content", "true");
+ // Covers bottom of gutter when coverGutterNextToScrollbar is on
+ // and h scrollbar is present.
+ d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
+ d.gutterFiller.setAttribute("cm-not-content", "true");
+ // Will contain the actual code, positioned to cover the viewport.
+ d.lineDiv = eltP("div", null, "CodeMirror-code");
+ // Elements are added to these to represent selection and cursors.
+ d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
+ d.cursorDiv = elt("div", null, "CodeMirror-cursors");
+ // A visibility: hidden element used to find the size of things.
+ d.measure = elt("div", null, "CodeMirror-measure");
+ // When lines outside of the viewport are measured, they are drawn in this.
+ d.lineMeasure = elt("div", null, "CodeMirror-measure");
+ // Wraps everything that needs to exist inside the vertically-padded coordinate system
+ d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
+ null, "position: relative; outline: none");
+ var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
+ // Moved around its parent to cover visible view.
+ d.mover = elt("div", [lines], null, "position: relative");
+ // Set to the height of the document, allowing scrolling.
+ d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
+ d.sizerWidth = null;
+ // Behavior of elts with overflow: auto and padding is
+ // inconsistent across browsers. This is used to ensure the
+ // scrollable area is big enough.
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
+ // Will contain the gutters, if any.
+ d.gutters = elt("div", null, "CodeMirror-gutters");
+ d.lineGutter = null;
+ // Actual scrollable element.
+ d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
+ d.scroller.setAttribute("tabIndex", "-1");
+ // The element in which the editor lives.
+ d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
+
+ // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
+ if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
+ if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
+
+ if (place) {
+ if (place.appendChild) { place.appendChild(d.wrapper); }
+ else { place(d.wrapper); }
+ }
+
+ // Current rendered range (may be bigger than the view window).
+ d.viewFrom = d.viewTo = doc.first;
+ d.reportedViewFrom = d.reportedViewTo = doc.first;
+ // Information about the rendered lines.
+ d.view = [];
+ d.renderedView = null;
+ // Holds info about a single rendered line when it was rendered
+ // for measurement, while not in view.
+ d.externalMeasured = null;
+ // Empty space (in pixels) above the view
+ d.viewOffset = 0;
+ d.lastWrapHeight = d.lastWrapWidth = 0;
+ d.updateLineNumbers = null;
+
+ d.nativeBarWidth = d.barHeight = d.barWidth = 0;
+ d.scrollbarsClipped = false;
+
+ // Used to only resize the line number gutter when necessary (when
+ // the amount of lines crosses a boundary that makes its width change)
+ d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
+ // Set to true when a non-horizontal-scrolling line widget is
+ // added. As an optimization, line widget aligning is skipped when
+ // this is false.
+ d.alignWidgets = false;
+
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+
+ // Tracks the maximum line length so that the horizontal scrollbar
+ // can be kept static when scrolling.
+ d.maxLine = null;
+ d.maxLineLength = 0;
+ d.maxLineChanged = false;
+
+ // Used for measuring wheel scrolling granularity
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
+
+ // True when shift is held down.
+ d.shift = false;
+
+ // Used to track whether anything happened since the context menu
+ // was opened.
+ d.selForContextMenu = null;
+
+ d.activeTouch = null;
+
+ input.init(d);
+ }
+
+ // Find the line object corresponding to the given line number.
+ function getLine(doc, n) {
+ n -= doc.first;
+ if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
+ var chunk = doc;
+ while (!chunk.lines) {
+ for (var i = 0;; ++i) {
+ var child = chunk.children[i], sz = child.chunkSize();
+ if (n < sz) { chunk = child; break }
+ n -= sz;
+ }
+ }
+ return chunk.lines[n]
+ }
+
+ // Get the part of a document between two positions, as an array of
+ // strings.
+ function getBetween(doc, start, end) {
+ var out = [], n = start.line;
+ doc.iter(start.line, end.line + 1, function (line) {
+ var text = line.text;
+ if (n == end.line) { text = text.slice(0, end.ch); }
+ if (n == start.line) { text = text.slice(start.ch); }
+ out.push(text);
+ ++n;
+ });
+ return out
+ }
+ // Get the lines between from and to, as array of strings.
+ function getLines(doc, from, to) {
+ var out = [];
+ doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
+ return out
+ }
+
+ // Update the height of a line, propagating the height change
+ // upwards to parent nodes.
+ function updateLineHeight(line, height) {
+ var diff = height - line.height;
+ if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
+ }
+
+ // Given a line object, find its line number by walking up through
+ // its parent links.
+ function lineNo(line) {
+ if (line.parent == null) { return null }
+ var cur = line.parent, no = indexOf(cur.lines, line);
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
+ for (var i = 0;; ++i) {
+ if (chunk.children[i] == cur) { break }
+ no += chunk.children[i].chunkSize();
+ }
+ }
+ return no + cur.first
+ }
+
+ // Find the line at the given vertical position, using the height
+ // information in the document tree.
+ function lineAtHeight(chunk, h) {
+ var n = chunk.first;
+ outer: do {
+ for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
+ var child = chunk.children[i$1], ch = child.height;
+ if (h < ch) { chunk = child; continue outer }
+ h -= ch;
+ n += child.chunkSize();
+ }
+ return n
+ } while (!chunk.lines)
+ var i = 0;
+ for (; i < chunk.lines.length; ++i) {
+ var line = chunk.lines[i], lh = line.height;
+ if (h < lh) { break }
+ h -= lh;
+ }
+ return n + i
+ }
+
+ function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
+
+ function lineNumberFor(options, i) {
+ return String(options.lineNumberFormatter(i + options.firstLineNumber))
+ }
+
+ // A Pos instance represents a position within the text.
+ function Pos(line, ch, sticky) {
+ if ( sticky === void 0 ) sticky = null;
+
+ if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
+ this.line = line;
+ this.ch = ch;
+ this.sticky = sticky;
+ }
+
+ // Compare two positions, return 0 if they are the same, a negative
+ // number when a is less, and a positive number otherwise.
+ function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
+
+ function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
+
+ function copyPos(x) {return Pos(x.line, x.ch)}
+ function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
+ function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
+
+ // Most of the external API clips given positions to make sure they
+ // actually exist within the document.
+ function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
+ function clipPos(doc, pos) {
+ if (pos.line < doc.first) { return Pos(doc.first, 0) }
+ var last = doc.first + doc.size - 1;
+ if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
+ return clipToLen(pos, getLine(doc, pos.line).text.length)
+ }
+ function clipToLen(pos, linelen) {
+ var ch = pos.ch;
+ if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
+ else if (ch < 0) { return Pos(pos.line, 0) }
+ else { return pos }
+ }
+ function clipPosArray(doc, array) {
+ var out = [];
+ for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
+ return out
+ }
+
+ // Optimize some code when these features are not used.
+ var sawReadOnlySpans = false, sawCollapsedSpans = false;
+
+ function seeReadOnlySpans() {
+ sawReadOnlySpans = true;
+ }
+
+ function seeCollapsedSpans() {
+ sawCollapsedSpans = true;
+ }
+
+ // TEXTMARKER SPANS
+
+ function MarkedSpan(marker, from, to) {
+ this.marker = marker;
+ this.from = from; this.to = to;
+ }
+
+ // Search an array of spans for a span matching the given marker.
+ function getMarkedSpanFor(spans, marker) {
+ if (spans) { for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.marker == marker) { return span }
+ } }
+ }
+ // Remove a span from an array, returning undefined if no spans are
+ // left (we don't store arrays for lines without spans).
+ function removeMarkedSpan(spans, span) {
+ var r;
+ for (var i = 0; i < spans.length; ++i)
+ { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
+ return r
+ }
+ // Add a span to a line.
+ function addMarkedSpan(line, span) {
+ line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
+ span.marker.attachLine(line);
+ }
+
+ // Used for the algorithm that adjusts markers for a change in the
+ // document. These functions cut an array of spans at a given
+ // character position, returning an array of remaining chunks (or
+ // undefined if nothing remains).
+ function markedSpansBefore(old, startCh, isInsert) {
+ var nw;
+ if (old) { for (var i = 0; i < old.length; ++i) {
+ var span = old[i], marker = span.marker;
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
+ ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
+ }
+ } }
+ return nw
+ }
+ function markedSpansAfter(old, endCh, isInsert) {
+ var nw;
+ if (old) { for (var i = 0; i < old.length; ++i) {
+ var span = old[i], marker = span.marker;
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
+ ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
+ span.to == null ? null : span.to - endCh));
+ }
+ } }
+ return nw
+ }
+
+ // Given a change object, compute the new set of marker spans that
+ // cover the line in which the change took place. Removes spans
+ // entirely within the change, reconnects spans belonging to the
+ // same marker that appear on both sides of the change, and cuts off
+ // spans partially within the change. Returns an array of span
+ // arrays with one element for each line in (after) the change.
+ function stretchSpansOverChange(doc, change) {
+ if (change.full) { return null }
+ var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
+ var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
+ if (!oldFirst && !oldLast) { return null }
+
+ var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
+ // Get the spans that 'stick out' on both sides
+ var first = markedSpansBefore(oldFirst, startCh, isInsert);
+ var last = markedSpansAfter(oldLast, endCh, isInsert);
+
+ // Next, merge those two ends
+ var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
+ if (first) {
+ // Fix up .to properties of first
+ for (var i = 0; i < first.length; ++i) {
+ var span = first[i];
+ if (span.to == null) {
+ var found = getMarkedSpanFor(last, span.marker);
+ if (!found) { span.to = startCh; }
+ else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
+ }
+ }
+ }
+ if (last) {
+ // Fix up .from in last (or move them into first in case of sameLine)
+ for (var i$1 = 0; i$1 < last.length; ++i$1) {
+ var span$1 = last[i$1];
+ if (span$1.to != null) { span$1.to += offset; }
+ if (span$1.from == null) {
+ var found$1 = getMarkedSpanFor(first, span$1.marker);
+ if (!found$1) {
+ span$1.from = offset;
+ if (sameLine) { (first || (first = [])).push(span$1); }
}
- if (m.className) { spanStyle += " " + m.className; }
- if (m.css) { css = (css ? css + ";" : "") + m.css; }
- if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
- if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
- if (m.title && !title) { title = m.title; }
- if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
- { collapsed = sp; }
- } else if (sp.from > pos && nextChange > sp.from) {
- nextChange = sp.from;
+ } else {
+ span$1.from += offset;
+ if (sameLine) { (first || (first = [])).push(span$1); }
}
}
- if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
- { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
+ }
+ // Make sure we didn't create any zero-length spans
+ if (first) { first = clearEmptySpans(first); }
+ if (last && last != first) { last = clearEmptySpans(last); }
+
+ var newMarkers = [first];
+ if (!sameLine) {
+ // Fill gap with whole-line-spans
+ var gap = change.text.length - 2, gapMarkers;
+ if (gap > 0 && first)
+ { for (var i$2 = 0; i$2 < first.length; ++i$2)
+ { if (first[i$2].to == null)
+ { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
+ for (var i$3 = 0; i$3 < gap; ++i$3)
+ { newMarkers.push(gapMarkers); }
+ newMarkers.push(last);
+ }
+ return newMarkers
+ }
+
+ // Remove spans that are empty and don't have a clearWhenEmpty
+ // option of false.
+ function clearEmptySpans(spans) {
+ for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
+ { spans.splice(i--, 1); }
+ }
+ if (!spans.length) { return null }
+ return spans
+ }
- if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
- { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
- if (collapsed && (collapsed.from || 0) == pos) {
- buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
- collapsed.marker, collapsed.from == null);
- if (collapsed.to == null) { return }
- if (collapsed.to == pos) { collapsed = false; }
+ // Used to 'clip' out readOnly ranges when making a change.
+ function removeReadOnlyRanges(doc, from, to) {
+ var markers = null;
+ doc.iter(from.line, to.line + 1, function (line) {
+ if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
+ var mark = line.markedSpans[i].marker;
+ if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
+ { (markers || (markers = [])).push(mark); }
+ } }
+ });
+ if (!markers) { return null }
+ var parts = [{from: from, to: to}];
+ for (var i = 0; i < markers.length; ++i) {
+ var mk = markers[i], m = mk.find(0);
+ for (var j = 0; j < parts.length; ++j) {
+ var p = parts[j];
+ if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
+ var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
+ if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
+ { newParts.push({from: p.from, to: m.from}); }
+ if (dto > 0 || !mk.inclusiveRight && !dto)
+ { newParts.push({from: m.to, to: p.to}); }
+ parts.splice.apply(parts, newParts);
+ j += newParts.length - 3;
}
}
- if (pos >= len) { break }
+ return parts
+ }
- var upto = Math.min(len, nextChange);
- while (true) {
- if (text) {
- var end = pos + text.length;
- if (!collapsed) {
- var tokenText = end > upto ? text.slice(0, upto - pos) : text;
- builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
- spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
- }
- if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
- pos = end;
- spanStartStyle = "";
- }
- text = allText.slice(at, at = styles[i++]);
- style = interpretTokenStyle(styles[i++], builder.cm.options);
- }
- }
-}
-
-
-// These objects are used to represent the visible (currently drawn)
-// part of the document. A LineView may correspond to multiple
-// logical lines, if those are connected by collapsed ranges.
-function LineView(doc, line, lineN) {
- // The starting line
- this.line = line;
- // Continuing lines, if any
- this.rest = visualLineContinued(line);
- // Number of logical lines in this visual line
- this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
- this.node = this.text = null;
- this.hidden = lineIsHidden(doc, line);
-}
-
-// Create a range of LineView objects for the given lines.
-function buildViewArray(cm, from, to) {
- var array = [], nextPos;
- for (var pos = from; pos < to; pos = nextPos) {
- var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
- nextPos = pos + view.size;
- array.push(view);
- }
- return array
-}
-
-var operationGroup = null;
-
-function pushOperation(op) {
- if (operationGroup) {
- operationGroup.ops.push(op);
- } else {
- op.ownsGroup = operationGroup = {
- ops: [op],
- delayedCallbacks: []
- };
+ // Connect or disconnect spans from a line.
+ function detachMarkedSpans(line) {
+ var spans = line.markedSpans;
+ if (!spans) { return }
+ for (var i = 0; i < spans.length; ++i)
+ { spans[i].marker.detachLine(line); }
+ line.markedSpans = null;
+ }
+ function attachMarkedSpans(line, spans) {
+ if (!spans) { return }
+ for (var i = 0; i < spans.length; ++i)
+ { spans[i].marker.attachLine(line); }
+ line.markedSpans = spans;
+ }
+
+ // Helpers used when computing which overlapping collapsed span
+ // counts as the larger one.
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
+
+ // Returns a number indicating which of two overlapping collapsed
+ // spans is larger (and thus includes the other). Falls back to
+ // comparing ids when the spans cover exactly the same range.
+ function compareCollapsedMarkers(a, b) {
+ var lenDiff = a.lines.length - b.lines.length;
+ if (lenDiff != 0) { return lenDiff }
+ var aPos = a.find(), bPos = b.find();
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
+ if (fromCmp) { return -fromCmp }
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
+ if (toCmp) { return toCmp }
+ return b.id - a.id
+ }
+
+ // Find out whether a line ends or starts in a collapsed span. If
+ // so, return the marker for that span.
+ function collapsedSpanAtSide(line, start) {
+ var sps = sawCollapsedSpans && line.markedSpans, found;
+ if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
+ sp = sps[i];
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
+ { found = sp.marker; }
+ } }
+ return found
}
-}
-
-function fireCallbacksForOps(group) {
- // Calls delayed callbacks and cursorActivity handlers until no
- // new ones appear
- var callbacks = group.delayedCallbacks, i = 0;
- do {
- for (; i < callbacks.length; i++)
- { callbacks[i].call(null); }
- for (var j = 0; j < group.ops.length; j++) {
- var op = group.ops[j];
- if (op.cursorActivityHandlers)
- { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
- { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
- }
- } while (i < callbacks.length)
-}
-
-function finishOperation(op, endCb) {
- var group = op.ownsGroup;
- if (!group) { return }
-
- try { fireCallbacksForOps(group); }
- finally {
- operationGroup = null;
- endCb(group);
- }
-}
-
-var orphanDelayedCallbacks = null;
-
-// Often, we want to signal events at a point where we are in the
-// middle of some work, but don't want the handler to start calling
-// other methods on the editor, which might be in an inconsistent
-// state or simply not expect any other events to happen.
-// signalLater looks whether there are any handlers, and schedules
-// them to be executed when the last operation ends, or, if no
-// operation is active, when a timeout fires.
-function signalLater(emitter, type /*, values...*/) {
- var arr = getHandlers(emitter, type);
- if (!arr.length) { return }
- var args = Array.prototype.slice.call(arguments, 2), list;
- if (operationGroup) {
- list = operationGroup.delayedCallbacks;
- } else if (orphanDelayedCallbacks) {
- list = orphanDelayedCallbacks;
- } else {
- list = orphanDelayedCallbacks = [];
- setTimeout(fireOrphanDelayed, 0);
- }
- var loop = function ( i ) {
- list.push(function () { return arr[i].apply(null, args); });
- };
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
- for (var i = 0; i < arr.length; ++i)
- loop( i );
-}
-
-function fireOrphanDelayed() {
- var delayed = orphanDelayedCallbacks;
- orphanDelayedCallbacks = null;
- for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
-}
-
-// When an aspect of a line changes, a string is added to
-// lineView.changes. This updates the relevant part of the line's
-// DOM structure.
-function updateLineForChanges(cm, lineView, lineN, dims) {
- for (var j = 0; j < lineView.changes.length; j++) {
- var type = lineView.changes[j];
- if (type == "text") { updateLineText(cm, lineView); }
- else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
- else if (type == "class") { updateLineClasses(cm, lineView); }
- else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
- }
- lineView.changes = null;
-}
-
-// Lines with gutter elements, widgets or a background class need to
-// be wrapped, and have the extra elements added to the wrapper div
-function ensureLineWrapped(lineView) {
- if (lineView.node == lineView.text) {
- lineView.node = elt("div", null, null, "position: relative");
- if (lineView.text.parentNode)
- { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
- lineView.node.appendChild(lineView.text);
- if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
- }
- return lineView.node
-}
-
-function updateLineBackground(cm, lineView) {
- var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
- if (cls) { cls += " CodeMirror-linebackground"; }
- if (lineView.background) {
- if (cls) { lineView.background.className = cls; }
- else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
- } else if (cls) {
- var wrap = ensureLineWrapped(lineView);
- lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
- cm.display.input.setUneditable(lineView.background);
- }
-}
-
-// Wrapper around buildLineContent which will reuse the structure
-// in display.externalMeasured when possible.
-function getLineContent(cm, lineView) {
- var ext = cm.display.externalMeasured;
- if (ext && ext.line == lineView.line) {
- cm.display.externalMeasured = null;
- lineView.measure = ext.measure;
- return ext.built
- }
- return buildLineContent(cm, lineView)
-}
-
-// Redraw the line's text. Interacts with the background and text
-// classes because the mode may output tokens that influence these
-// classes.
-function updateLineText(cm, lineView) {
- var cls = lineView.text.className;
- var built = getLineContent(cm, lineView);
- if (lineView.text == lineView.node) { lineView.node = built.pre; }
- lineView.text.parentNode.replaceChild(built.pre, lineView.text);
- lineView.text = built.pre;
- if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
- lineView.bgClass = built.bgClass;
- lineView.textClass = built.textClass;
- updateLineClasses(cm, lineView);
- } else if (cls) {
- lineView.text.className = cls;
- }
-}
-
-function updateLineClasses(cm, lineView) {
- updateLineBackground(cm, lineView);
- if (lineView.line.wrapClass)
- { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
- else if (lineView.node != lineView.text)
- { lineView.node.className = ""; }
- var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
- lineView.text.className = textClass || "";
-}
-
-function updateLineGutter(cm, lineView, lineN, dims) {
- if (lineView.gutter) {
- lineView.node.removeChild(lineView.gutter);
- lineView.gutter = null;
- }
- if (lineView.gutterBackground) {
- lineView.node.removeChild(lineView.gutterBackground);
- lineView.gutterBackground = null;
- }
- if (lineView.line.gutterClass) {
- var wrap = ensureLineWrapped(lineView);
- lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
- ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
- cm.display.input.setUneditable(lineView.gutterBackground);
- wrap.insertBefore(lineView.gutterBackground, lineView.text);
- }
- var markers = lineView.line.gutterMarkers;
- if (cm.options.lineNumbers || markers) {
- var wrap$1 = ensureLineWrapped(lineView);
- var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
- cm.display.input.setUneditable(gutterWrap);
- wrap$1.insertBefore(gutterWrap, lineView.text);
- if (lineView.line.gutterClass)
- { gutterWrap.className += " " + lineView.line.gutterClass; }
- if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
- { lineView.lineNumber = gutterWrap.appendChild(
- elt("div", lineNumberFor(cm.options, lineN),
- "CodeMirror-linenumber CodeMirror-gutter-elt",
- ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
- if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
- var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
- if (found)
- { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
- ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
+ function collapsedSpanAround(line, ch) {
+ var sps = sawCollapsedSpans && line.markedSpans, found;
+ if (sps) { for (var i = 0; i < sps.length; ++i) {
+ var sp = sps[i];
+ if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
} }
+ return found
}
-}
-
-function updateLineWidgets(cm, lineView, dims) {
- if (lineView.alignable) { lineView.alignable = null; }
- for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
- next = node.nextSibling;
- if (node.className == "CodeMirror-linewidget")
- { lineView.node.removeChild(node); }
- }
- insertLineWidgets(cm, lineView, dims);
-}
-
-// Build a line's DOM representation from scratch
-function buildLineElement(cm, lineView, lineN, dims) {
- var built = getLineContent(cm, lineView);
- lineView.text = lineView.node = built.pre;
- if (built.bgClass) { lineView.bgClass = built.bgClass; }
- if (built.textClass) { lineView.textClass = built.textClass; }
-
- updateLineClasses(cm, lineView);
- updateLineGutter(cm, lineView, lineN, dims);
- insertLineWidgets(cm, lineView, dims);
- return lineView.node
-}
-
-// A lineView may contain multiple logical lines (when merged by
-// collapsed spans). The widgets for all of them need to be drawn.
-function insertLineWidgets(cm, lineView, dims) {
- insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
- if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
- { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
-}
-
-function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
- if (!line.widgets) { return }
- var wrap = ensureLineWrapped(lineView);
- for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
- var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
- if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
- positionLineWidget(widget, node, lineView, dims);
- cm.display.input.setUneditable(node);
- if (allowAbove && widget.above)
- { wrap.insertBefore(node, lineView.gutter || lineView.text); }
- else
- { wrap.appendChild(node); }
- signalLater(widget, "redraw");
- }
-}
-
-function positionLineWidget(widget, node, lineView, dims) {
- if (widget.noHScroll) {
- (lineView.alignable || (lineView.alignable = [])).push(node);
- var width = dims.wrapperWidth;
- node.style.left = dims.fixedPos + "px";
- if (!widget.coverGutter) {
- width -= dims.gutterTotalWidth;
- node.style.paddingLeft = dims.gutterTotalWidth + "px";
- }
- node.style.width = width + "px";
- }
- if (widget.coverGutter) {
- node.style.zIndex = 5;
- node.style.position = "relative";
- if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
- }
-}
-
-function widgetHeight(widget) {
- if (widget.height != null) { return widget.height }
- var cm = widget.doc.cm;
- if (!cm) { return 0 }
- if (!contains(document.body, widget.node)) {
- var parentStyle = "position: relative;";
- if (widget.coverGutter)
- { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
- if (widget.noHScroll)
- { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
- removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
- }
- return widget.height = widget.node.parentNode.offsetHeight
-}
-
-// Return true when the given mouse event happened in a widget
-function eventInWidget(display, e) {
- for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
- if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
- (n.parentNode == display.sizer && n != display.mover))
- { return true }
+
+ // Test whether there exists a collapsed span that partially
+ // overlaps (covers the start or end, but not both) of a new span.
+ // Such overlap is not allowed.
+ function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
+ var line = getLine(doc, lineNo$$1);
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) { for (var i = 0; i < sps.length; ++i) {
+ var sp = sps[i];
+ if (!sp.marker.collapsed) { continue }
+ var found = sp.marker.find(0);
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
+ if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
+ fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
+ { return true }
+ } }
}
-}
-
-// POSITION MEASUREMENT
-
-function paddingTop(display) {return display.lineSpace.offsetTop}
-function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
-function paddingH(display) {
- if (display.cachedPaddingH) { return display.cachedPaddingH }
- var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
- var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
- var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
- if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
- return data
-}
-
-function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
-function displayWidth(cm) {
- return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
-}
-function displayHeight(cm) {
- return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
-}
-
-// Ensure the lineView.wrapping.heights array is populated. This is
-// an array of bottom offsets for the lines that make up a drawn
-// line. When lineWrapping is on, there might be more than one
-// height.
-function ensureLineHeights(cm, lineView, rect) {
- var wrapping = cm.options.lineWrapping;
- var curWidth = wrapping && displayWidth(cm);
- if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
- var heights = lineView.measure.heights = [];
- if (wrapping) {
- lineView.measure.width = curWidth;
- var rects = lineView.text.firstChild.getClientRects();
- for (var i = 0; i < rects.length - 1; i++) {
- var cur = rects[i], next = rects[i + 1];
- if (Math.abs(cur.bottom - next.bottom) > 2)
- { heights.push((cur.bottom + next.top) / 2 - rect.top); }
- }
- }
- heights.push(rect.bottom - rect.top);
- }
-}
-
-// Find a line map (mapping character offsets to text nodes) and a
-// measurement cache for the given line number. (A line view might
-// contain multiple lines when collapsed ranges are present.)
-function mapFromLineView(lineView, line, lineN) {
- if (lineView.line == line)
- { return {map: lineView.measure.map, cache: lineView.measure.cache} }
- for (var i = 0; i < lineView.rest.length; i++)
- { if (lineView.rest[i] == line)
- { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
- for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
- { if (lineNo(lineView.rest[i$1]) > lineN)
- { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
-}
-
-// Render a line into the hidden node display.externalMeasured. Used
-// when measurement is needed for a line that's not in the viewport.
-function updateExternalMeasurement(cm, line) {
- line = visualLine(line);
- var lineN = lineNo(line);
- var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
- view.lineN = lineN;
- var built = view.built = buildLineContent(cm, view);
- view.text = built.pre;
- removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
- return view
-}
-
-// Get a {top, bottom, left, right} box (in line-local coordinates)
-// for a given character.
-function measureChar(cm, line, ch, bias) {
- return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
-}
-
-// Find a line view that corresponds to the given line number.
-function findViewForLine(cm, lineN) {
- if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
- { return cm.display.view[findViewIndex(cm, lineN)] }
- var ext = cm.display.externalMeasured;
- if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
- { return ext }
-}
-
-// Measurement can be split in two steps, the set-up work that
-// applies to the whole line, and the measurement of the actual
-// character. Functions like coordsChar, that need to do a lot of
-// measurements in a row, can thus ensure that the set-up work is
-// only done once.
-function prepareMeasureForLine(cm, line) {
- var lineN = lineNo(line);
- var view = findViewForLine(cm, lineN);
- if (view && !view.text) {
- view = null;
- } else if (view && view.changes) {
- updateLineForChanges(cm, view, lineN, getDimensions(cm));
- cm.curOp.forceUpdate = true;
- }
- if (!view)
- { view = updateExternalMeasurement(cm, line); }
-
- var info = mapFromLineView(view, line, lineN);
- return {
- line: line, view: view, rect: null,
- map: info.map, cache: info.cache, before: info.before,
- hasHeights: false
- }
-}
-
-// Given a prepared measurement object, measures the position of an
-// actual character (or fetches it from the cache).
-function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
- if (prepared.before) { ch = -1; }
- var key = ch + (bias || ""), found;
- if (prepared.cache.hasOwnProperty(key)) {
- found = prepared.cache[key];
- } else {
- if (!prepared.rect)
- { prepared.rect = prepared.view.text.getBoundingClientRect(); }
- if (!prepared.hasHeights) {
- ensureLineHeights(cm, prepared.view, prepared.rect);
- prepared.hasHeights = true;
- }
- found = measureCharInner(cm, prepared, ch, bias);
- if (!found.bogus) { prepared.cache[key] = found; }
- }
- return {left: found.left, right: found.right,
- top: varHeight ? found.rtop : found.top,
- bottom: varHeight ? found.rbottom : found.bottom}
-}
-
-var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
-
-function nodeAndOffsetInLineMap(map$$1, ch, bias) {
- var node, start, end, collapse, mStart, mEnd;
- // First, search the line map for the text node corresponding to,
- // or closest to, the target character.
- for (var i = 0; i < map$$1.length; i += 3) {
- mStart = map$$1[i];
- mEnd = map$$1[i + 1];
- if (ch < mStart) {
- start = 0; end = 1;
- collapse = "left";
- } else if (ch < mEnd) {
- start = ch - mStart;
- end = start + 1;
- } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
- end = mEnd - mStart;
- start = end - 1;
- if (ch >= mEnd) { collapse = "right"; }
- }
- if (start != null) {
- node = map$$1[i + 2];
- if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
- { collapse = bias; }
- if (bias == "left" && start == 0)
- { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
- node = map$$1[(i -= 3) + 2];
- collapse = "left";
- } }
- if (bias == "right" && start == mEnd - mStart)
- { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
- node = map$$1[(i += 3) + 2];
- collapse = "right";
- } }
- break
- }
- }
- return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
-}
-
-function getUsefulRect(rects, bias) {
- var rect = nullRect;
- if (bias == "left") { for (var i = 0; i < rects.length; i++) {
- if ((rect = rects[i]).left != rect.right) { break }
- } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
- if ((rect = rects[i$1]).left != rect.right) { break }
- } }
- return rect
-}
-
-function measureCharInner(cm, prepared, ch, bias) {
- var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
- var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
-
- var rect;
- if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
- for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
- while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
- while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
- if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
- { rect = node.parentNode.getBoundingClientRect(); }
- else
- { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
- if (rect.left || rect.right || start == 0) { break }
- end = start;
- start = start - 1;
- collapse = "right";
- }
- if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
- } else { // If it is a widget, simply get the box for the whole widget.
- if (start > 0) { collapse = bias = "right"; }
- var rects;
- if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
- { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
- else
- { rect = node.getBoundingClientRect(); }
+
+ // A visual line is a line as drawn on the screen. Folding, for
+ // example, can cause multiple logical lines to appear on the same
+ // visual line. This finds the start of the visual line that the
+ // given line is part of (usually that is the line itself).
+ function visualLine(line) {
+ var merged;
+ while (merged = collapsedSpanAtStart(line))
+ { line = merged.find(-1, true).line; }
+ return line
+ }
+
+ function visualLineEnd(line) {
+ var merged;
+ while (merged = collapsedSpanAtEnd(line))
+ { line = merged.find(1, true).line; }
+ return line
+ }
+
+ // Returns an array of logical lines that continue the visual line
+ // started by the argument, or undefined if there are no such lines.
+ function visualLineContinued(line) {
+ var merged, lines;
+ while (merged = collapsedSpanAtEnd(line)) {
+ line = merged.find(1, true).line
+ ;(lines || (lines = [])).push(line);
+ }
+ return lines
+ }
+
+ // Get the line number of the start of the visual line that the
+ // given line number is part of.
+ function visualLineNo(doc, lineN) {
+ var line = getLine(doc, lineN), vis = visualLine(line);
+ if (line == vis) { return lineN }
+ return lineNo(vis)
+ }
+
+ // Get the line number of the start of the next visual line after
+ // the given line.
+ function visualLineEndNo(doc, lineN) {
+ if (lineN > doc.lastLine()) { return lineN }
+ var line = getLine(doc, lineN), merged;
+ if (!lineIsHidden(doc, line)) { return lineN }
+ while (merged = collapsedSpanAtEnd(line))
+ { line = merged.find(1, true).line; }
+ return lineNo(line) + 1
+ }
+
+ // Compute whether a line is hidden. Lines count as hidden when they
+ // are part of a visual line that starts with another line, or when
+ // they are entirely covered by collapsed, non-widget span.
+ function lineIsHidden(doc, line) {
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
+ sp = sps[i];
+ if (!sp.marker.collapsed) { continue }
+ if (sp.from == null) { return true }
+ if (sp.marker.widgetNode) { continue }
+ if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
+ { return true }
+ } }
}
- if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
- var rSpan = node.parentNode.getClientRects()[0];
- if (rSpan)
- { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
- else
- { rect = nullRect; }
- }
-
- var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
- var mid = (rtop + rbot) / 2;
- var heights = prepared.view.measure.heights;
- var i = 0;
- for (; i < heights.length - 1; i++)
- { if (mid < heights[i]) { break } }
- var top = i ? heights[i - 1] : 0, bot = heights[i];
- var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
- right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
- top: top, bottom: bot};
- if (!rect.left && !rect.right) { result.bogus = true; }
- if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
-
- return result
-}
-
-// Work around problem with bounding client rects on ranges being
-// returned incorrectly when zoomed on IE10 and below.
-function maybeUpdateRectForZooming(measure, rect) {
- if (!window.screen || screen.logicalXDPI == null ||
- screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
- { return rect }
- var scaleX = screen.logicalXDPI / screen.deviceXDPI;
- var scaleY = screen.logicalYDPI / screen.deviceYDPI;
- return {left: rect.left * scaleX, right: rect.right * scaleX,
- top: rect.top * scaleY, bottom: rect.bottom * scaleY}
-}
-
-function clearLineMeasurementCacheFor(lineView) {
- if (lineView.measure) {
- lineView.measure.cache = {};
- lineView.measure.heights = null;
- if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
- { lineView.measure.caches[i] = {}; } }
- }
-}
-
-function clearLineMeasurementCache(cm) {
- cm.display.externalMeasure = null;
- removeChildren(cm.display.lineMeasure);
- for (var i = 0; i < cm.display.view.length; i++)
- { clearLineMeasurementCacheFor(cm.display.view[i]); }
-}
-
-function clearCaches(cm) {
- clearLineMeasurementCache(cm);
- cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
- if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
- cm.display.lineNumChars = null;
-}
-
-function pageScrollX() {
- // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
- // which causes page_Offset and bounding client rects to use
- // different reference viewports and invalidate our calculations.
- if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
- return window.pageXOffset || (document.documentElement || document.body).scrollLeft
-}
-function pageScrollY() {
- if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
- return window.pageYOffset || (document.documentElement || document.body).scrollTop
-}
-
-function widgetTopHeight(lineObj) {
- var height = 0;
- if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
- { height += widgetHeight(lineObj.widgets[i]); } } }
- return height
-}
-
-// Converts a {top, bottom, left, right} box from line-local
-// coordinates into another coordinate system. Context may be one of
-// "line", "div" (display.lineDiv), "local"./null (editor), "window",
-// or "page".
-function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
- if (!includeWidgets) {
- var height = widgetTopHeight(lineObj);
- rect.top += height; rect.bottom += height;
- }
- if (context == "line") { return rect }
- if (!context) { context = "local"; }
- var yOff = heightAtLine(lineObj);
- if (context == "local") { yOff += paddingTop(cm.display); }
- else { yOff -= cm.display.viewOffset; }
- if (context == "page" || context == "window") {
- var lOff = cm.display.lineSpace.getBoundingClientRect();
- yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
- var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
- rect.left += xOff; rect.right += xOff;
- }
- rect.top += yOff; rect.bottom += yOff;
- return rect
-}
-
-// Coverts a box from "div" coords to another coordinate system.
-// Context may be "window", "page", "div", or "local"./null.
-function fromCoordSystem(cm, coords, context) {
- if (context == "div") { return coords }
- var left = coords.left, top = coords.top;
- // First move into "page" coordinate system
- if (context == "page") {
- left -= pageScrollX();
- top -= pageScrollY();
- } else if (context == "local" || !context) {
- var localBox = cm.display.sizer.getBoundingClientRect();
- left += localBox.left;
- top += localBox.top;
- }
-
- var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
- return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
-}
-
-function charCoords(cm, pos, context, lineObj, bias) {
- if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
- return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
-}
-
-// Returns a box for a given cursor position, which may have an
-// 'other' property containing the position of the secondary cursor
-// on a bidi boundary.
-// A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
-// and after `char - 1` in writing order of `char - 1`
-// A cursor Pos(line, char, "after") is on the same visual line as `char`
-// and before `char` in writing order of `char`
-// Examples (upper-case letters are RTL, lower-case are LTR):
-// Pos(0, 1, ...)
-// before after
-// ab a|b a|b
-// aB a|B aB|
-// Ab |Ab A|b
-// AB B|A B|A
-// Every position after the last character on a line is considered to stick
-// to the last character on the line.
-function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
- lineObj = lineObj || getLine(cm.doc, pos.line);
- if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
- function get(ch, right) {
- var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
- if (right) { m.left = m.right; } else { m.right = m.left; }
- return intoCoordSystem(cm, lineObj, m, context)
- }
- var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
- if (ch >= lineObj.text.length) {
- ch = lineObj.text.length;
- sticky = "before";
- } else if (ch <= 0) {
- ch = 0;
- sticky = "after";
- }
- if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
-
- function getBidi(ch, partPos, invert) {
- var part = order[partPos], right = part.level == 1;
- return get(invert ? ch - 1 : ch, right != invert)
- }
- var partPos = getBidiPartAt(order, ch, sticky);
- var other = bidiOther;
- var val = getBidi(ch, partPos, sticky == "before");
- if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
- return val
-}
-
-// Used to cheaply estimate the coordinates for a position. Used for
-// intermediate scroll updates.
-function estimateCoords(cm, pos) {
- var left = 0;
- pos = clipPos(cm.doc, pos);
- if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
- var lineObj = getLine(cm.doc, pos.line);
- var top = heightAtLine(lineObj) + paddingTop(cm.display);
- return {left: left, right: left, top: top, bottom: top + lineObj.height}
-}
-
-// Positions returned by coordsChar contain some extra information.
-// xRel is the relative x position of the input coordinates compared
-// to the found position (so xRel > 0 means the coordinates are to
-// the right of the character position, for example). When outside
-// is true, that means the coordinates lie outside the line's
-// vertical range.
-function PosWithInfo(line, ch, sticky, outside, xRel) {
- var pos = Pos(line, ch, sticky);
- pos.xRel = xRel;
- if (outside) { pos.outside = true; }
- return pos
-}
-
-// Compute the character position closest to the given coordinates.
-// Input must be lineSpace-local ("div" coordinate system).
-function coordsChar(cm, x, y) {
- var doc = cm.doc;
- y += cm.display.viewOffset;
- if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
- var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
- if (lineN > last)
- { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
- if (x < 0) { x = 0; }
-
- var lineObj = getLine(doc, lineN);
- for (;;) {
- var found = coordsCharInner(cm, lineObj, lineN, x, y);
- var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0));
- if (!collapsed) { return found }
- var rangeEnd = collapsed.find(1);
- if (rangeEnd.line == lineN) { return rangeEnd }
- lineObj = getLine(doc, lineN = rangeEnd.line);
- }
-}
-
-function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
- y -= widgetTopHeight(lineObj);
- var end = lineObj.text.length;
- var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
- end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
- return {begin: begin, end: end}
-}
-
-function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
- if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
- var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
- return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
-}
-
-// Returns true if the given side of a box is after the given
-// coordinates, in top-to-bottom, left-to-right order.
-function boxIsAfter(box, x, y, left) {
- return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
-}
-
-function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
- // Move y into line-local coordinate space
- y -= heightAtLine(lineObj);
- var preparedMeasure = prepareMeasureForLine(cm, lineObj);
- // When directly calling `measureCharPrepared`, we have to adjust
- // for the widgets at this line.
- var widgetHeight$$1 = widgetTopHeight(lineObj);
- var begin = 0, end = lineObj.text.length, ltr = true;
-
- var order = getOrder(lineObj, cm.doc.direction);
- // If the line isn't plain left-to-right text, first figure out
- // which bidi section the coordinates fall into.
- if (order) {
- var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
- (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
- ltr = part.level != 1;
- // The awkward -1 offsets are needed because findFirst (called
- // on these below) will treat its first bound as inclusive,
- // second as exclusive, but we want to actually address the
- // characters in the part's range
- begin = ltr ? part.from : part.to - 1;
- end = ltr ? part.to : part.from - 1;
- }
-
- // A binary search to find the first character whose bounding box
- // starts after the coordinates. If we run across any whose box wrap
- // the coordinates, store that.
- var chAround = null, boxAround = null;
- var ch = findFirst(function (ch) {
- var box = measureCharPrepared(cm, preparedMeasure, ch);
- box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
- if (!boxIsAfter(box, x, y, false)) { return false }
- if (box.top <= y && box.left <= x) {
- chAround = ch;
- boxAround = box;
+ function lineIsHiddenInner(doc, line, span) {
+ if (span.to == null) {
+ var end = span.marker.find(1, true);
+ return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
}
- return true
- }, begin, end);
-
- var baseX, sticky, outside = false;
- // If a box around the coordinates was found, use that
- if (boxAround) {
- // Distinguish coordinates nearer to the left or right side of the box
- var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
- ch = chAround + (atStart ? 0 : 1);
- sticky = atStart ? "after" : "before";
- baseX = atLeft ? boxAround.left : boxAround.right;
- } else {
- // (Adjust for extended bound, if necessary.)
- if (!ltr && (ch == end || ch == begin)) { ch++; }
- // To determine which side to associate with, get the box to the
- // left of the character and compare it's vertical position to the
- // coordinates
- sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
- (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
- "after" : "before";
- // Now get accurate coordinates for this place, in order to get a
- // base X position
- var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
- baseX = coords.left;
- outside = y < coords.top || y >= coords.bottom;
- }
-
- ch = skipExtendingChars(lineObj.text, ch, 1);
- return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
-}
-
-function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
- // Bidi parts are sorted left-to-right, and in a non-line-wrapping
- // situation, we can take this ordering to correspond to the visual
- // ordering. This finds the first part whose end is after the given
- // coordinates.
- var index = findFirst(function (i) {
- var part = order[i], ltr = part.level != 1;
- return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
- "line", lineObj, preparedMeasure), x, y, true)
- }, 0, order.length - 1);
- var part = order[index];
- // If this isn't the first part, the part's start is also after
- // the coordinates, and the coordinates aren't on the same line as
- // that start, move one part back.
- if (index > 0) {
- var ltr = part.level != 1;
- var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
- "line", lineObj, preparedMeasure);
- if (boxIsAfter(start, x, y, true) && start.top > y)
- { part = order[index - 1]; }
- }
- return part
-}
-
-function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
- // In a wrapped line, rtl text on wrapping boundaries can do things
- // that don't correspond to the ordering in our `order` array at
- // all, so a binary search doesn't work, and we want to return a
- // part that only spans one line so that the binary search in
- // coordsCharInner is safe. As such, we first find the extent of the
- // wrapped line, and then do a flat search in which we discard any
- // spans that aren't on the line.
- var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
- var begin = ref.begin;
- var end = ref.end;
- if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
- var part = null, closestDist = null;
- for (var i = 0; i < order.length; i++) {
- var p = order[i];
- if (p.from >= end || p.to <= begin) { continue }
- var ltr = p.level != 1;
- var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
- // Weigh against spans ending before this, so that they are only
- // picked if nothing ends after
- var dist = endX < x ? x - endX + 1e9 : endX - x;
- if (!part || closestDist > dist) {
- part = p;
- closestDist = dist;
- }
- }
- if (!part) { part = order[order.length - 1]; }
- // Clip the part to the wrapped line.
- if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
- if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
- return part
-}
-
-var measureText;
-// Compute the default text height.
-function textHeight(display) {
- if (display.cachedTextHeight != null) { return display.cachedTextHeight }
- if (measureText == null) {
- measureText = elt("pre");
- // Measure a bunch of lines, for browsers that compute
- // fractional heights.
- for (var i = 0; i < 49; ++i) {
- measureText.appendChild(document.createTextNode("x"));
- measureText.appendChild(elt("br"));
- }
- measureText.appendChild(document.createTextNode("x"));
- }
- removeChildrenAndAdd(display.measure, measureText);
- var height = measureText.offsetHeight / 50;
- if (height > 3) { display.cachedTextHeight = height; }
- removeChildren(display.measure);
- return height || 1
-}
-
-// Compute the default character width.
-function charWidth(display) {
- if (display.cachedCharWidth != null) { return display.cachedCharWidth }
- var anchor = elt("span", "xxxxxxxxxx");
- var pre = elt("pre", [anchor]);
- removeChildrenAndAdd(display.measure, pre);
- var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
- if (width > 2) { display.cachedCharWidth = width; }
- return width || 10
-}
-
-// Do a bulk-read of the DOM positions and sizes needed to draw the
-// view, so that we don't interleave reading and writing to the DOM.
-function getDimensions(cm) {
- var d = cm.display, left = {}, width = {};
- var gutterLeft = d.gutters.clientLeft;
- for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
- left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
- width[cm.options.gutters[i]] = n.clientWidth;
- }
- return {fixedPos: compensateForHScroll(d),
- gutterTotalWidth: d.gutters.offsetWidth,
- gutterLeft: left,
- gutterWidth: width,
- wrapperWidth: d.wrapper.clientWidth}
-}
-
-// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
-// but using getBoundingClientRect to get a sub-pixel-accurate
-// result.
-function compensateForHScroll(display) {
- return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
-}
-
-// Returns a function that estimates the height of a line, to use as
-// first approximation until the line becomes visible (and is thus
-// properly measurable).
-function estimateHeight(cm) {
- var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
- var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
- return function (line) {
- if (lineIsHidden(cm.doc, line)) { return 0 }
-
- var widgetsHeight = 0;
- if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
- if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
- } }
+ if (span.marker.inclusiveRight && span.to == line.text.length)
+ { return true }
+ for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
+ sp = line.markedSpans[i];
+ if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
+ (sp.to == null || sp.to != span.from) &&
+ (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
+ lineIsHiddenInner(doc, line, sp)) { return true }
+ }
+ }
+
+ // Find the height above the given line.
+ function heightAtLine(lineObj) {
+ lineObj = visualLine(lineObj);
+
+ var h = 0, chunk = lineObj.parent;
+ for (var i = 0; i < chunk.lines.length; ++i) {
+ var line = chunk.lines[i];
+ if (line == lineObj) { break }
+ else { h += line.height; }
+ }
+ for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
+ for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
+ var cur = p.children[i$1];
+ if (cur == chunk) { break }
+ else { h += cur.height; }
+ }
+ }
+ return h
+ }
+
+ // Compute the character length of a line, taking into account
+ // collapsed ranges (see markText) that might hide parts, and join
+ // other lines onto it.
+ function lineLength(line) {
+ if (line.height == 0) { return 0 }
+ var len = line.text.length, merged, cur = line;
+ while (merged = collapsedSpanAtStart(cur)) {
+ var found = merged.find(0, true);
+ cur = found.from.line;
+ len += found.from.ch - found.to.ch;
+ }
+ cur = line;
+ while (merged = collapsedSpanAtEnd(cur)) {
+ var found$1 = merged.find(0, true);
+ len -= cur.text.length - found$1.from.ch;
+ cur = found$1.to.line;
+ len += cur.text.length - found$1.to.ch;
+ }
+ return len
+ }
+
+ // Find the longest line in the document.
+ function findMaxLine(cm) {
+ var d = cm.display, doc = cm.doc;
+ d.maxLine = getLine(doc, doc.first);
+ d.maxLineLength = lineLength(d.maxLine);
+ d.maxLineChanged = true;
+ doc.iter(function (line) {
+ var len = lineLength(line);
+ if (len > d.maxLineLength) {
+ d.maxLineLength = len;
+ d.maxLine = line;
+ }
+ });
+ }
- if (wrapping)
- { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
- else
- { return widgetsHeight + th }
+ // BIDI HELPERS
+
+ function iterateBidiSections(order, from, to, f) {
+ if (!order) { return f(from, to, "ltr", 0) }
+ var found = false;
+ for (var i = 0; i < order.length; ++i) {
+ var part = order[i];
+ if (part.from < to && part.to > from || from == to && part.to == from) {
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
+ found = true;
+ }
+ }
+ if (!found) { f(from, to, "ltr"); }
}
-}
-function estimateLineHeights(cm) {
- var doc = cm.doc, est = estimateHeight(cm);
- doc.iter(function (line) {
- var estHeight = est(line);
- if (estHeight != line.height) { updateLineHeight(line, estHeight); }
- });
-}
-
-// Given a mouse event, find the corresponding position. If liberal
-// is false, it checks whether a gutter or scrollbar was clicked,
-// and returns null if it was. forRect is used by rectangular
-// selections, and tries to estimate a character position even for
-// coordinates beyond the right of the text.
-function posFromMouse(cm, e, liberal, forRect) {
- var display = cm.display;
- if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
-
- var x, y, space = display.lineSpace.getBoundingClientRect();
- // Fails unpredictably on IE[67] when mouse is dragged around quickly.
- try { x = e.clientX - space.left; y = e.clientY - space.top; }
- catch (e) { return null }
- var coords = coordsChar(cm, x, y), line;
- if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
- var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
- coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
- }
- return coords
-}
-
-// Find the view element corresponding to a given line. Return null
-// when the line isn't visible.
-function findViewIndex(cm, n) {
- if (n >= cm.display.viewTo) { return null }
- n -= cm.display.viewFrom;
- if (n < 0) { return null }
- var view = cm.display.view;
- for (var i = 0; i < view.length; i++) {
- n -= view[i].size;
- if (n < 0) { return i }
- }
-}
-
-function updateSelection(cm) {
- cm.display.input.showSelection(cm.display.input.prepareSelection());
-}
-
-function prepareSelection(cm, primary) {
- if ( primary === void 0 ) primary = true;
-
- var doc = cm.doc, result = {};
- var curFragment = result.cursors = document.createDocumentFragment();
- var selFragment = result.selection = document.createDocumentFragment();
-
- for (var i = 0; i < doc.sel.ranges.length; i++) {
- if (!primary && i == doc.sel.primIndex) { continue }
- var range$$1 = doc.sel.ranges[i];
- if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
- var collapsed = range$$1.empty();
- if (collapsed || cm.options.showCursorWhenSelecting)
- { drawSelectionCursor(cm, range$$1.head, curFragment); }
- if (!collapsed)
- { drawSelectionRange(cm, range$$1, selFragment); }
- }
- return result
-}
-
-// Draws a cursor for the given range
-function drawSelectionCursor(cm, head, output) {
- var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
-
- var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
- cursor.style.left = pos.left + "px";
- cursor.style.top = pos.top + "px";
- cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
-
- if (pos.other) {
- // Secondary cursor, shown when on a 'jump' in bi-directional text
- var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
- otherCursor.style.display = "";
- otherCursor.style.left = pos.other.left + "px";
- otherCursor.style.top = pos.other.top + "px";
- otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
- }
-}
-
-function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
-
-// Draws the given range as a highlighted selection
-function drawSelectionRange(cm, range$$1, output) {
- var display = cm.display, doc = cm.doc;
- var fragment = document.createDocumentFragment();
- var padding = paddingH(cm.display), leftSide = padding.left;
- var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
- var docLTR = doc.direction == "ltr";
-
- function add(left, top, width, bottom) {
- if (top < 0) { top = 0; }
- top = Math.round(top);
- bottom = Math.round(bottom);
- fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px")));
- }
-
- function drawForLine(line, fromArg, toArg) {
- var lineObj = getLine(doc, line);
- var lineLen = lineObj.text.length;
- var start, end;
- function coords(ch, bias) {
- return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
- }
-
- function wrapX(pos, dir, side) {
- var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
- var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
- var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
- return coords(ch, prop)[prop]
- }
-
- var order = getOrder(lineObj, doc.direction);
- iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
- var ltr = dir == "ltr";
- var fromPos = coords(from, ltr ? "left" : "right");
- var toPos = coords(to - 1, ltr ? "right" : "left");
-
- var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
- var first = i == 0, last = !order || i == order.length - 1;
- if (toPos.top - fromPos.top <= 3) { // Single line
- var openLeft = (docLTR ? openStart : openEnd) && first;
- var openRight = (docLTR ? openEnd : openStart) && last;
- var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
- var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
- add(left, fromPos.top, right - left, fromPos.bottom);
- } else { // Multiple lines
- var topLeft, topRight, botLeft, botRight;
- if (ltr) {
- topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
- topRight = docLTR ? rightSide : wrapX(from, dir, "before");
- botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
- botRight = docLTR && openEnd && last ? rightSide : toPos.right;
+ var bidiOther = null;
+ function getBidiPartAt(order, ch, sticky) {
+ var found;
+ bidiOther = null;
+ for (var i = 0; i < order.length; ++i) {
+ var cur = order[i];
+ if (cur.from < ch && cur.to > ch) { return i }
+ if (cur.to == ch) {
+ if (cur.from != cur.to && sticky == "before") { found = i; }
+ else { bidiOther = i; }
+ }
+ if (cur.from == ch) {
+ if (cur.from != cur.to && sticky != "before") { found = i; }
+ else { bidiOther = i; }
+ }
+ }
+ return found != null ? found : bidiOther
+ }
+
+ // Bidirectional ordering algorithm
+ // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
+ // that this (partially) implements.
+
+ // One-char codes used for character types:
+ // L (L): Left-to-Right
+ // R (R): Right-to-Left
+ // r (AL): Right-to-Left Arabic
+ // 1 (EN): European Number
+ // + (ES): European Number Separator
+ // % (ET): European Number Terminator
+ // n (AN): Arabic Number
+ // , (CS): Common Number Separator
+ // m (NSM): Non-Spacing Mark
+ // b (BN): Boundary Neutral
+ // s (B): Paragraph Separator
+ // t (S): Segment Separator
+ // w (WS): Whitespace
+ // N (ON): Other Neutrals
+
+ // Returns null if characters are ordered as they appear
+ // (left-to-right), or an array of sections ({from, to, level}
+ // objects) in the order in which they occur visually.
+ var bidiOrdering = (function() {
+ // Character types for codepoints 0 to 0xff
+ var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
+ // Character types for codepoints 0x600 to 0x6f9
+ var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
+ function charType(code) {
+ if (code <= 0xf7) { return lowTypes.charAt(code) }
+ else if (0x590 <= code && code <= 0x5f4) { return "R" }
+ else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
+ else if (0x6ee <= code && code <= 0x8ac) { return "r" }
+ else if (0x2000 <= code && code <= 0x200b) { return "w" }
+ else if (code == 0x200c) { return "b" }
+ else { return "L" }
+ }
+
+ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
+ var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
+
+ function BidiSpan(level, from, to) {
+ this.level = level;
+ this.from = from; this.to = to;
+ }
+
+ return function(str, direction) {
+ var outerType = direction == "ltr" ? "L" : "R";
+
+ if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
+ var len = str.length, types = [];
+ for (var i = 0; i < len; ++i)
+ { types.push(charType(str.charCodeAt(i))); }
+
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
+ // change the type of the NSM to the type of the previous
+ // character. If the NSM is at the start of the level run, it will
+ // get the type of sor.
+ for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
+ var type = types[i$1];
+ if (type == "m") { types[i$1] = prev; }
+ else { prev = type; }
+ }
+
+ // W2. Search backwards from each instance of a European number
+ // until the first strong type (R, L, AL, or sor) is found. If an
+ // AL is found, change the type of the European number to Arabic
+ // number.
+ // W3. Change all ALs to R.
+ for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
+ var type$1 = types[i$2];
+ if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
+ else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
+ }
+
+ // W4. A single European separator between two European numbers
+ // changes to a European number. A single common separator between
+ // two numbers of the same type changes to that type.
+ for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
+ var type$2 = types[i$3];
+ if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
+ else if (type$2 == "," && prev$1 == types[i$3+1] &&
+ (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
+ prev$1 = type$2;
+ }
+
+ // W5. A sequence of European terminators adjacent to European
+ // numbers changes to all European numbers.
+ // W6. Otherwise, separators and terminators change to Other
+ // Neutral.
+ for (var i$4 = 0; i$4 < len; ++i$4) {
+ var type$3 = types[i$4];
+ if (type$3 == ",") { types[i$4] = "N"; }
+ else if (type$3 == "%") {
+ var end = (void 0);
+ for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
+ var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
+ for (var j = i$4; j < end; ++j) { types[j] = replace; }
+ i$4 = end - 1;
+ }
+ }
+
+ // W7. Search backwards from each instance of a European number
+ // until the first strong type (R, L, or sor) is found. If an L is
+ // found, then change the type of the European number to L.
+ for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
+ var type$4 = types[i$5];
+ if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
+ else if (isStrong.test(type$4)) { cur$1 = type$4; }
+ }
+
+ // N1. A sequence of neutrals takes the direction of the
+ // surrounding strong text if the text on both sides has the same
+ // direction. European and Arabic numbers act as if they were R in
+ // terms of their influence on neutrals. Start-of-level-run (sor)
+ // and end-of-level-run (eor) are used at level run boundaries.
+ // N2. Any remaining neutrals take the embedding direction.
+ for (var i$6 = 0; i$6 < len; ++i$6) {
+ if (isNeutral.test(types[i$6])) {
+ var end$1 = (void 0);
+ for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
+ var before = (i$6 ? types[i$6-1] : outerType) == "L";
+ var after = (end$1 < len ? types[end$1] : outerType) == "L";
+ var replace$1 = before == after ? (before ? "L" : "R") : outerType;
+ for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
+ i$6 = end$1 - 1;
+ }
+ }
+
+ // Here we depart from the documented algorithm, in order to avoid
+ // building up an actual levels array. Since there are only three
+ // levels (0, 1, 2) in an implementation that doesn't take
+ // explicit embedding into account, we can build up the order on
+ // the fly, without following the level-based algorithm.
+ var order = [], m;
+ for (var i$7 = 0; i$7 < len;) {
+ if (countsAsLeft.test(types[i$7])) {
+ var start = i$7;
+ for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
+ order.push(new BidiSpan(0, start, i$7));
} else {
- topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
- topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
- botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
- botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
+ var pos = i$7, at = order.length;
+ for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
+ for (var j$2 = pos; j$2 < i$7;) {
+ if (countsAsNum.test(types[j$2])) {
+ if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
+ var nstart = j$2;
+ for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
+ order.splice(at, 0, new BidiSpan(2, nstart, j$2));
+ pos = j$2;
+ } else { ++j$2; }
+ }
+ if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
+ }
+ }
+ if (direction == "ltr") {
+ if (order[0].level == 1 && (m = str.match(/^\s+/))) {
+ order[0].from = m[0].length;
+ order.unshift(new BidiSpan(0, 0, m[0].length));
+ }
+ if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
+ lst(order).to -= m[0].length;
+ order.push(new BidiSpan(0, len - m[0].length, len));
}
- add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
- if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
- add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
}
- if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
- if (cmpCoords(toPos, start) < 0) { start = toPos; }
- if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
- if (cmpCoords(toPos, end) < 0) { end = toPos; }
- });
- return {start: start, end: end}
- }
-
- var sFrom = range$$1.from(), sTo = range$$1.to();
- if (sFrom.line == sTo.line) {
- drawForLine(sFrom.line, sFrom.ch, sTo.ch);
- } else {
- var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
- var singleVLine = visualLine(fromLine) == visualLine(toLine);
- var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
- var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
- if (singleVLine) {
- if (leftEnd.top < rightStart.top - 2) {
- add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
- add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
- } else {
- add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
- }
- }
- if (leftEnd.bottom < rightStart.top)
- { add(leftSide, leftEnd.bottom, null, rightStart.top); }
- }
-
- output.appendChild(fragment);
-}
-
-// Cursor-blinking
-function restartBlink(cm) {
- if (!cm.state.focused) { return }
- var display = cm.display;
- clearInterval(display.blinker);
- var on = true;
- display.cursorDiv.style.visibility = "";
- if (cm.options.cursorBlinkRate > 0)
- { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
- cm.options.cursorBlinkRate); }
- else if (cm.options.cursorBlinkRate < 0)
- { display.cursorDiv.style.visibility = "hidden"; }
-}
-
-function ensureFocus(cm) {
- if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
-}
-
-function delayBlurEvent(cm) {
- cm.state.delayingBlurEvent = true;
- setTimeout(function () { if (cm.state.delayingBlurEvent) {
- cm.state.delayingBlurEvent = false;
- onBlur(cm);
- } }, 100);
-}
-
-function onFocus(cm, e) {
- if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
-
- if (cm.options.readOnly == "nocursor") { return }
- if (!cm.state.focused) {
- signal(cm, "focus", cm, e);
- cm.state.focused = true;
- addClass(cm.display.wrapper, "CodeMirror-focused");
- // This test prevents this from firing when a context
- // menu is closed (since the input reset would kill the
- // select-all detection hack)
- if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
- cm.display.input.reset();
- if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
- }
- cm.display.input.receivedFocus();
- }
- restartBlink(cm);
-}
-function onBlur(cm, e) {
- if (cm.state.delayingBlurEvent) { return }
-
- if (cm.state.focused) {
- signal(cm, "blur", cm, e);
- cm.state.focused = false;
- rmClass(cm.display.wrapper, "CodeMirror-focused");
- }
- clearInterval(cm.display.blinker);
- setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
-}
-
-// Read the actual heights of the rendered lines, and update their
-// stored heights to match.
-function updateHeightsInViewport(cm) {
- var display = cm.display;
- var prevBottom = display.lineDiv.offsetTop;
- for (var i = 0; i < display.view.length; i++) {
- var cur = display.view[i], height = (void 0);
- if (cur.hidden) { continue }
- if (ie && ie_version < 8) {
- var bot = cur.node.offsetTop + cur.node.offsetHeight;
- height = bot - prevBottom;
- prevBottom = bot;
+ return direction == "rtl" ? order.reverse() : order
+ }
+ })();
+
+ // Get the bidi ordering for the given line (and cache it). Returns
+ // false for lines that are fully left-to-right, and an array of
+ // BidiSpan objects otherwise.
+ function getOrder(line, direction) {
+ var order = line.order;
+ if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
+ return order
+ }
+
+ // EVENT HANDLING
+
+ // Lightweight event framework. on/off also work on DOM nodes,
+ // registering native DOM handlers.
+
+ var noHandlers = [];
+
+ var on = function(emitter, type, f) {
+ if (emitter.addEventListener) {
+ emitter.addEventListener(type, f, false);
+ } else if (emitter.attachEvent) {
+ emitter.attachEvent("on" + type, f);
} else {
- var box = cur.node.getBoundingClientRect();
- height = box.bottom - box.top;
- }
- var diff = cur.line.height - height;
- if (height < 2) { height = textHeight(display); }
- if (diff > .005 || diff < -.005) {
- updateLineHeight(cur.line, height);
- updateWidgetHeight(cur.line);
- if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
- { updateWidgetHeight(cur.rest[j]); } }
- }
- }
-}
-
-// Read and store the height of line widgets associated with the
-// given line.
-function updateWidgetHeight(line) {
- if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
- var w = line.widgets[i], parent = w.node.parentNode;
- if (parent) { w.height = parent.offsetHeight; }
- } }
-}
-
-// Compute the lines that are visible in a given viewport (defaults
-// the the current scroll position). viewport may contain top,
-// height, and ensure (see op.scrollToPos) properties.
-function visibleLines(display, doc, viewport) {
- var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
- top = Math.floor(top - paddingTop(display));
- var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
-
- var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
- // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
- // forces those lines into the viewport (if possible).
- if (viewport && viewport.ensure) {
- var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
- if (ensureFrom < from) {
- from = ensureFrom;
- to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
- } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
- from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
- to = ensureTo;
- }
- }
- return {from: from, to: Math.max(to, from + 1)}
-}
-
-// Re-align line numbers and gutter marks to compensate for
-// horizontal scrolling.
-function alignHorizontally(cm) {
- var display = cm.display, view = display.view;
- if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
- var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
- var gutterW = display.gutters.offsetWidth, left = comp + "px";
- for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
- if (cm.options.fixedGutter) {
- if (view[i].gutter)
- { view[i].gutter.style.left = left; }
- if (view[i].gutterBackground)
- { view[i].gutterBackground.style.left = left; }
- }
- var align = view[i].alignable;
- if (align) { for (var j = 0; j < align.length; j++)
- { align[j].style.left = left; } }
- } }
- if (cm.options.fixedGutter)
- { display.gutters.style.left = (comp + gutterW) + "px"; }
-}
-
-// Used to ensure that the line number gutter is still the right
-// size for the current document size. Returns true when an update
-// is needed.
-function maybeUpdateLineNumberWidth(cm) {
- if (!cm.options.lineNumbers) { return false }
- var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
- if (last.length != display.lineNumChars) {
- var test = display.measure.appendChild(elt("div", [elt("div", last)],
- "CodeMirror-linenumber CodeMirror-gutter-elt"));
- var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
- display.lineGutter.style.width = "";
- display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
- display.lineNumWidth = display.lineNumInnerWidth + padding;
- display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
- display.lineGutter.style.width = display.lineNumWidth + "px";
- updateGutterSpace(cm);
- return true
+ var map$$1 = emitter._handlers || (emitter._handlers = {});
+ map$$1[type] = (map$$1[type] || noHandlers).concat(f);
+ }
+ };
+
+ function getHandlers(emitter, type) {
+ return emitter._handlers && emitter._handlers[type] || noHandlers
}
- return false
-}
-
-// SCROLLING THINGS INTO VIEW
-
-// If an editor sits on the top or bottom of the window, partially
-// scrolled out of view, this ensures that the cursor is visible.
-function maybeScrollWindow(cm, rect) {
- if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
-
- var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
- if (rect.top + box.top < 0) { doScroll = true; }
- else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
- if (doScroll != null && !phantom) {
- var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
- cm.display.lineSpace.appendChild(scrollNode);
- scrollNode.scrollIntoView(doScroll);
- cm.display.lineSpace.removeChild(scrollNode);
- }
-}
-
-// Scroll a given position into view (immediately), verifying that
-// it actually became visible (as line heights are accurately
-// measured, the position of something may 'drift' during drawing).
-function scrollPosIntoView(cm, pos, end, margin) {
- if (margin == null) { margin = 0; }
- var rect;
- if (!cm.options.lineWrapping && pos == end) {
- // Set pos and end to the cursor positions around the character pos sticks to
- // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
- // If pos == Pos(_, 0, "before"), pos and end are unchanged
- pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
- end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
- }
- for (var limit = 0; limit < 5; limit++) {
- var changed = false;
- var coords = cursorCoords(cm, pos);
- var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
- rect = {left: Math.min(coords.left, endCoords.left),
- top: Math.min(coords.top, endCoords.top) - margin,
- right: Math.max(coords.left, endCoords.left),
- bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
- var scrollPos = calculateScrollPos(cm, rect);
- var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
- if (scrollPos.scrollTop != null) {
- updateScrollTop(cm, scrollPos.scrollTop);
- if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
- }
- if (scrollPos.scrollLeft != null) {
- setScrollLeft(cm, scrollPos.scrollLeft);
- if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
- }
- if (!changed) { break }
- }
- return rect
-}
-
-// Scroll a given set of coordinates into view (immediately).
-function scrollIntoView(cm, rect) {
- var scrollPos = calculateScrollPos(cm, rect);
- if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
- if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
-}
-
-// Calculate a new scroll position needed to scroll the given
-// rectangle into view. Returns an object with scrollTop and
-// scrollLeft properties. When these are undefined, the
-// vertical/horizontal position does not need to be adjusted.
-function calculateScrollPos(cm, rect) {
- var display = cm.display, snapMargin = textHeight(cm.display);
- if (rect.top < 0) { rect.top = 0; }
- var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
- var screen = displayHeight(cm), result = {};
- if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
- var docBottom = cm.doc.height + paddingVert(display);
- var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
- if (rect.top < screentop) {
- result.scrollTop = atTop ? 0 : rect.top;
- } else if (rect.bottom > screentop + screen) {
- var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
- if (newTop != screentop) { result.scrollTop = newTop; }
- }
-
- var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
- var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
- var tooWide = rect.right - rect.left > screenw;
- if (tooWide) { rect.right = rect.left + screenw; }
- if (rect.left < 10)
- { result.scrollLeft = 0; }
- else if (rect.left < screenleft)
- { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
- else if (rect.right > screenw + screenleft - 3)
- { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
- return result
-}
-
-// Store a relative adjustment to the scroll position in the current
-// operation (to be applied when the operation finishes).
-function addToScrollTop(cm, top) {
- if (top == null) { return }
- resolveScrollToPos(cm);
- cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
-}
-
-// Make sure that at the end of the operation the current cursor is
-// shown.
-function ensureCursorVisible(cm) {
- resolveScrollToPos(cm);
- var cur = cm.getCursor();
- cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
-}
-
-function scrollToCoords(cm, x, y) {
- if (x != null || y != null) { resolveScrollToPos(cm); }
- if (x != null) { cm.curOp.scrollLeft = x; }
- if (y != null) { cm.curOp.scrollTop = y; }
-}
-
-function scrollToRange(cm, range$$1) {
- resolveScrollToPos(cm);
- cm.curOp.scrollToPos = range$$1;
-}
-
-// When an operation has its scrollToPos property set, and another
-// scroll action is applied before the end of the operation, this
-// 'simulates' scrolling that position into view in a cheap way, so
-// that the effect of intermediate scroll commands is not ignored.
-function resolveScrollToPos(cm) {
- var range$$1 = cm.curOp.scrollToPos;
- if (range$$1) {
- cm.curOp.scrollToPos = null;
- var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
- scrollToCoordsRange(cm, from, to, range$$1.margin);
- }
-}
-
-function scrollToCoordsRange(cm, from, to, margin) {
- var sPos = calculateScrollPos(cm, {
- left: Math.min(from.left, to.left),
- top: Math.min(from.top, to.top) - margin,
- right: Math.max(from.right, to.right),
- bottom: Math.max(from.bottom, to.bottom) + margin
- });
- scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
-}
-
-// Sync the scrollable area and scrollbars, ensure the viewport
-// covers the visible area.
-function updateScrollTop(cm, val) {
- if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
- if (!gecko) { updateDisplaySimple(cm, {top: val}); }
- setScrollTop(cm, val, true);
- if (gecko) { updateDisplaySimple(cm); }
- startWorker(cm, 100);
-}
-
-function setScrollTop(cm, val, forceScroll) {
- val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
- if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
- cm.doc.scrollTop = val;
- cm.display.scrollbars.setScrollTop(val);
- if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
-}
-
-// Sync scroller and scrollbar, ensure the gutter elements are
-// aligned.
-function setScrollLeft(cm, val, isScroller, forceScroll) {
- val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
- if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
- cm.doc.scrollLeft = val;
- alignHorizontally(cm);
- if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
- cm.display.scrollbars.setScrollLeft(val);
-}
-
-// SCROLLBARS
-
-// Prepare DOM reads needed to update the scrollbars. Done in one
-// shot to minimize update/measure roundtrips.
-function measureForScrollbars(cm) {
- var d = cm.display, gutterW = d.gutters.offsetWidth;
- var docH = Math.round(cm.doc.height + paddingVert(cm.display));
- return {
- clientHeight: d.scroller.clientHeight,
- viewHeight: d.wrapper.clientHeight,
- scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
- viewWidth: d.wrapper.clientWidth,
- barLeft: cm.options.fixedGutter ? gutterW : 0,
- docHeight: docH,
- scrollHeight: docH + scrollGap(cm) + d.barHeight,
- nativeBarWidth: d.nativeBarWidth,
- gutterWidth: gutterW
- }
-}
-
-var NativeScrollbars = function(place, scroll, cm) {
- this.cm = cm;
- var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
- var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
- vert.tabIndex = horiz.tabIndex = -1;
- place(vert); place(horiz);
-
- on(vert, "scroll", function () {
- if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
- });
- on(horiz, "scroll", function () {
- if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
- });
- this.checkedZeroWidth = false;
- // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
- if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
-};
-
-NativeScrollbars.prototype.update = function (measure) {
- var needsH = measure.scrollWidth > measure.clientWidth + 1;
- var needsV = measure.scrollHeight > measure.clientHeight + 1;
- var sWidth = measure.nativeBarWidth;
-
- if (needsV) {
- this.vert.style.display = "block";
- this.vert.style.bottom = needsH ? sWidth + "px" : "0";
- var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
- // A bug in IE8 can cause this value to be negative, so guard it.
- this.vert.firstChild.style.height =
- Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
- } else {
- this.vert.style.display = "";
- this.vert.firstChild.style.height = "0";
- }
-
- if (needsH) {
- this.horiz.style.display = "block";
- this.horiz.style.right = needsV ? sWidth + "px" : "0";
- this.horiz.style.left = measure.barLeft + "px";
- var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
- this.horiz.firstChild.style.width =
- Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
- } else {
- this.horiz.style.display = "";
- this.horiz.firstChild.style.width = "0";
- }
-
- if (!this.checkedZeroWidth && measure.clientHeight > 0) {
- if (sWidth == 0) { this.zeroWidthHack(); }
- this.checkedZeroWidth = true;
- }
-
- return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
-};
-
-NativeScrollbars.prototype.setScrollLeft = function (pos) {
- if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
- if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
-};
-
-NativeScrollbars.prototype.setScrollTop = function (pos) {
- if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
- if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
-};
-
-NativeScrollbars.prototype.zeroWidthHack = function () {
- var w = mac && !mac_geMountainLion ? "12px" : "18px";
- this.horiz.style.height = this.vert.style.width = w;
- this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
- this.disableHoriz = new Delayed;
- this.disableVert = new Delayed;
-};
-
-NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
- bar.style.pointerEvents = "auto";
- function maybeDisable() {
- // To find out whether the scrollbar is still visible, we
- // check whether the element under the pixel in the bottom
- // right corner of the scrollbar box is the scrollbar box
- // itself (when the bar is still visible) or its filler child
- // (when the bar is hidden). If it is still visible, we keep
- // it enabled, if it's hidden, we disable pointer events.
- var box = bar.getBoundingClientRect();
- var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
- : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
- if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
- else { delay.set(1000, maybeDisable); }
- }
- delay.set(1000, maybeDisable);
-};
-
-NativeScrollbars.prototype.clear = function () {
- var parent = this.horiz.parentNode;
- parent.removeChild(this.horiz);
- parent.removeChild(this.vert);
-};
-
-var NullScrollbars = function () {};
-
-NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
-NullScrollbars.prototype.setScrollLeft = function () {};
-NullScrollbars.prototype.setScrollTop = function () {};
-NullScrollbars.prototype.clear = function () {};
-
-function updateScrollbars(cm, measure) {
- if (!measure) { measure = measureForScrollbars(cm); }
- var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
- updateScrollbarsInner(cm, measure);
- for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
- if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
- { updateHeightsInViewport(cm); }
- updateScrollbarsInner(cm, measureForScrollbars(cm));
- startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
- }
-}
-
-// Re-synchronize the fake scrollbars with the actual size of the
-// content.
-function updateScrollbarsInner(cm, measure) {
- var d = cm.display;
- var sizes = d.scrollbars.update(measure);
-
- d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
- d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
- d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
-
- if (sizes.right && sizes.bottom) {
- d.scrollbarFiller.style.display = "block";
- d.scrollbarFiller.style.height = sizes.bottom + "px";
- d.scrollbarFiller.style.width = sizes.right + "px";
- } else { d.scrollbarFiller.style.display = ""; }
- if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
- d.gutterFiller.style.display = "block";
- d.gutterFiller.style.height = sizes.bottom + "px";
- d.gutterFiller.style.width = measure.gutterWidth + "px";
- } else { d.gutterFiller.style.display = ""; }
-}
-
-var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
-
-function initScrollbars(cm) {
- if (cm.display.scrollbars) {
- cm.display.scrollbars.clear();
- if (cm.display.scrollbars.addClass)
- { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
+ function off(emitter, type, f) {
+ if (emitter.removeEventListener) {
+ emitter.removeEventListener(type, f, false);
+ } else if (emitter.detachEvent) {
+ emitter.detachEvent("on" + type, f);
+ } else {
+ var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
+ if (arr) {
+ var index = indexOf(arr, f);
+ if (index > -1)
+ { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
+ }
+ }
}
- cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
- cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
- // Prevent clicks in the scrollbars from killing focus
- on(node, "mousedown", function () {
- if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
- });
- node.setAttribute("cm-not-content", "true");
- }, function (pos, axis) {
- if (axis == "horizontal") { setScrollLeft(cm, pos); }
- else { updateScrollTop(cm, pos); }
- }, cm);
- if (cm.display.scrollbars.addClass)
- { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
-}
-
-// Operations are used to wrap a series of changes to the editor
-// state in such a way that each change won't have to update the
-// cursor and display (which would be awkward, slow, and
-// error-prone). Instead, display updates are batched and then all
-// combined and executed at once.
-
-var nextOpId = 0;
-// Start a new operation.
-function startOperation(cm) {
- cm.curOp = {
- cm: cm,
- viewChanged: false, // Flag that indicates that lines might need to be redrawn
- startHeight: cm.doc.height, // Used to detect need to update scrollbar
- forceUpdate: false, // Used to force a redraw
- updateInput: null, // Whether to reset the input textarea
- typing: false, // Whether this reset should be careful to leave existing text (for compositing)
- changeObjs: null, // Accumulated changes, for firing change events
- cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
- cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
- selectionChanged: false, // Whether the selection needs to be redrawn
- updateMaxLine: false, // Set when the widest line needs to be determined anew
- scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
- scrollToPos: null, // Used to scroll to a specific position
- focus: false,
- id: ++nextOpId // Unique ID
+ function signal(emitter, type /*, values...*/) {
+ var handlers = getHandlers(emitter, type);
+ if (!handlers.length) { return }
+ var args = Array.prototype.slice.call(arguments, 2);
+ for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
+ }
+
+ // The DOM events that CodeMirror handles can be overridden by
+ // registering a (non-DOM) handler on the editor for the event name,
+ // and preventDefault-ing the event in that handler.
+ function signalDOMEvent(cm, e, override) {
+ if (typeof e == "string")
+ { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
+ signal(cm, override || e.type, cm, e);
+ return e_defaultPrevented(e) || e.codemirrorIgnore
+ }
+
+ function signalCursorActivity(cm) {
+ var arr = cm._handlers && cm._handlers.cursorActivity;
+ if (!arr) { return }
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
+ for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
+ { set.push(arr[i]); } }
+ }
+
+ function hasHandler(emitter, type) {
+ return getHandlers(emitter, type).length > 0
+ }
+
+ // Add on and off methods to a constructor's prototype, to make
+ // registering events on such objects more convenient.
+ function eventMixin(ctor) {
+ ctor.prototype.on = function(type, f) {on(this, type, f);};
+ ctor.prototype.off = function(type, f) {off(this, type, f);};
+ }
+
+ // Due to the fact that we still support jurassic IE versions, some
+ // compatibility wrappers are needed.
+
+ function e_preventDefault(e) {
+ if (e.preventDefault) { e.preventDefault(); }
+ else { e.returnValue = false; }
+ }
+ function e_stopPropagation(e) {
+ if (e.stopPropagation) { e.stopPropagation(); }
+ else { e.cancelBubble = true; }
+ }
+ function e_defaultPrevented(e) {
+ return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
+ }
+ function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
+
+ function e_target(e) {return e.target || e.srcElement}
+ function e_button(e) {
+ var b = e.which;
+ if (b == null) {
+ if (e.button & 1) { b = 1; }
+ else if (e.button & 2) { b = 3; }
+ else if (e.button & 4) { b = 2; }
+ }
+ if (mac && e.ctrlKey && b == 1) { b = 3; }
+ return b
+ }
+
+ // Detect drag-and-drop
+ var dragAndDrop = function() {
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
+ // couldn't get it to work yet.
+ if (ie && ie_version < 9) { return false }
+ var div = elt('div');
+ return "draggable" in div || "dragDrop" in div
+ }();
+
+ var zwspSupported;
+ function zeroWidthElement(measure) {
+ if (zwspSupported == null) {
+ var test = elt("span", "\u200b");
+ removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
+ if (measure.firstChild.offsetHeight != 0)
+ { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
+ }
+ var node = zwspSupported ? elt("span", "\u200b") :
+ elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
+ node.setAttribute("cm-text", "");
+ return node
+ }
+
+ // Feature-detect IE's crummy client rect reporting for bidi text
+ var badBidiRects;
+ function hasBadBidiRects(measure) {
+ if (badBidiRects != null) { return badBidiRects }
+ var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
+ var r0 = range(txt, 0, 1).getBoundingClientRect();
+ var r1 = range(txt, 1, 2).getBoundingClientRect();
+ removeChildren(measure);
+ if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
+ return badBidiRects = (r1.right - r0.right < 3)
+ }
+
+ // See if "".split is the broken IE version, if so, provide an
+ // alternative way to split lines.
+ var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
+ var pos = 0, result = [], l = string.length;
+ while (pos <= l) {
+ var nl = string.indexOf("\n", pos);
+ if (nl == -1) { nl = string.length; }
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
+ var rt = line.indexOf("\r");
+ if (rt != -1) {
+ result.push(line.slice(0, rt));
+ pos += rt + 1;
+ } else {
+ result.push(line);
+ pos = nl + 1;
+ }
+ }
+ return result
+ } : function (string) { return string.split(/\r\n?|\n/); };
+
+ var hasSelection = window.getSelection ? function (te) {
+ try { return te.selectionStart != te.selectionEnd }
+ catch(e) { return false }
+ } : function (te) {
+ var range$$1;
+ try {range$$1 = te.ownerDocument.selection.createRange();}
+ catch(e) {}
+ if (!range$$1 || range$$1.parentElement() != te) { return false }
+ return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
};
- pushOperation(cm.curOp);
-}
-
-// Finish an operation, updating the display and signalling delayed events
-function endOperation(cm) {
- var op = cm.curOp;
- finishOperation(op, function (group) {
- for (var i = 0; i < group.ops.length; i++)
- { group.ops[i].cm.curOp = null; }
- endOperations(group);
- });
-}
-
-// The DOM updates done when an operation finishes are batched so
-// that the minimum number of relayouts are required.
-function endOperations(group) {
- var ops = group.ops;
- for (var i = 0; i < ops.length; i++) // Read DOM
- { endOperation_R1(ops[i]); }
- for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
- { endOperation_W1(ops[i$1]); }
- for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
- { endOperation_R2(ops[i$2]); }
- for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
- { endOperation_W2(ops[i$3]); }
- for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
- { endOperation_finish(ops[i$4]); }
-}
-
-function endOperation_R1(op) {
- var cm = op.cm, display = cm.display;
- maybeClipScrollbars(cm);
- if (op.updateMaxLine) { findMaxLine(cm); }
-
- op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
- op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
- op.scrollToPos.to.line >= display.viewTo) ||
- display.maxLineChanged && cm.options.lineWrapping;
- op.update = op.mustUpdate &&
- new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
-}
-
-function endOperation_W1(op) {
- op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
-}
-
-function endOperation_R2(op) {
- var cm = op.cm, display = cm.display;
- if (op.updatedDisplay) { updateHeightsInViewport(cm); }
-
- op.barMeasure = measureForScrollbars(cm);
-
- // If the max line changed since it was last measured, measure it,
- // and ensure the document's width matches it.
- // updateDisplay_W2 will use these properties to do the actual resizing
- if (display.maxLineChanged && !cm.options.lineWrapping) {
- op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
- cm.display.sizerWidth = op.adjustWidthTo;
- op.barMeasure.scrollWidth =
- Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
- op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
- }
-
- if (op.updatedDisplay || op.selectionChanged)
- { op.preparedSelection = display.input.prepareSelection(); }
-}
-
-function endOperation_W2(op) {
- var cm = op.cm;
-
- if (op.adjustWidthTo != null) {
- cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
- if (op.maxScrollLeft < cm.doc.scrollLeft)
- { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
- cm.display.maxLineChanged = false;
- }
-
- var takeFocus = op.focus && op.focus == activeElt();
- if (op.preparedSelection)
- { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
- if (op.updatedDisplay || op.startHeight != cm.doc.height)
- { updateScrollbars(cm, op.barMeasure); }
- if (op.updatedDisplay)
- { setDocumentHeight(cm, op.barMeasure); }
-
- if (op.selectionChanged) { restartBlink(cm); }
-
- if (cm.state.focused && op.updateInput)
- { cm.display.input.reset(op.typing); }
- if (takeFocus) { ensureFocus(op.cm); }
-}
-
-function endOperation_finish(op) {
- var cm = op.cm, display = cm.display, doc = cm.doc;
-
- if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
-
- // Abort mouse wheel delta measurement, when scrolling explicitly
- if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
- { display.wheelStartX = display.wheelStartY = null; }
-
- // Propagate the scroll position to the actual DOM scroller
- if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
-
- if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
- // If we need to scroll a specific position into view, do so.
- if (op.scrollToPos) {
- var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
- clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
- maybeScrollWindow(cm, rect);
- }
-
- // Fire events for markers that are hidden/unidden by editing or
- // undoing
- var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
- if (hidden) { for (var i = 0; i < hidden.length; ++i)
- { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
- if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
- { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
-
- if (display.wrapper.offsetHeight)
- { doc.scrollTop = cm.display.scroller.scrollTop; }
-
- // Fire change events, and delayed event handlers
- if (op.changeObjs)
- { signal(cm, "changes", cm, op.changeObjs); }
- if (op.update)
- { op.update.finish(); }
-}
-
-// Run the given function in an operation
-function runInOp(cm, f) {
- if (cm.curOp) { return f() }
- startOperation(cm);
- try { return f() }
- finally { endOperation(cm); }
-}
-// Wraps a function in an operation. Returns the wrapped function.
-function operation(cm, f) {
- return function() {
- if (cm.curOp) { return f.apply(cm, arguments) }
- startOperation(cm);
- try { return f.apply(cm, arguments) }
- finally { endOperation(cm); }
+
+ var hasCopyEvent = (function () {
+ var e = elt("div");
+ if ("oncopy" in e) { return true }
+ e.setAttribute("oncopy", "return;");
+ return typeof e.oncopy == "function"
+ })();
+
+ var badZoomedRects = null;
+ function hasBadZoomedRects(measure) {
+ if (badZoomedRects != null) { return badZoomedRects }
+ var node = removeChildrenAndAdd(measure, elt("span", "x"));
+ var normal = node.getBoundingClientRect();
+ var fromRange = range(node, 0, 1).getBoundingClientRect();
+ return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
+ }
+
+ // Known modes, by name and by MIME
+ var modes = {}, mimeModes = {};
+
+ // Extra arguments are stored as the mode's dependencies, which is
+ // used by (legacy) mechanisms like loadmode.js to automatically
+ // load a mode. (Preferred mechanism is the require/define calls.)
+ function defineMode(name, mode) {
+ if (arguments.length > 2)
+ { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
+ modes[name] = mode;
+ }
+
+ function defineMIME(mime, spec) {
+ mimeModes[mime] = spec;
+ }
+
+ // Given a MIME type, a {name, ...options} config object, or a name
+ // string, return a mode config object.
+ function resolveMode(spec) {
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
+ spec = mimeModes[spec];
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+ var found = mimeModes[spec.name];
+ if (typeof found == "string") { found = {name: found}; }
+ spec = createObj(found, spec);
+ spec.name = found.name;
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
+ return resolveMode("application/xml")
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
+ return resolveMode("application/json")
+ }
+ if (typeof spec == "string") { return {name: spec} }
+ else { return spec || {name: "null"} }
+ }
+
+ // Given a mode spec (anything that resolveMode accepts), find and
+ // initialize an actual mode object.
+ function getMode(options, spec) {
+ spec = resolveMode(spec);
+ var mfactory = modes[spec.name];
+ if (!mfactory) { return getMode(options, "text/plain") }
+ var modeObj = mfactory(options, spec);
+ if (modeExtensions.hasOwnProperty(spec.name)) {
+ var exts = modeExtensions[spec.name];
+ for (var prop in exts) {
+ if (!exts.hasOwnProperty(prop)) { continue }
+ if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
+ modeObj[prop] = exts[prop];
+ }
+ }
+ modeObj.name = spec.name;
+ if (spec.helperType) { modeObj.helperType = spec.helperType; }
+ if (spec.modeProps) { for (var prop$1 in spec.modeProps)
+ { modeObj[prop$1] = spec.modeProps[prop$1]; } }
+
+ return modeObj
}
-}
-// Used to add methods to editor and doc instances, wrapping them in
-// operations.
-function methodOp(f) {
- return function() {
- if (this.curOp) { return f.apply(this, arguments) }
- startOperation(this);
- try { return f.apply(this, arguments) }
- finally { endOperation(this); }
+
+ // This can be used to attach properties to mode objects from
+ // outside the actual mode definition.
+ var modeExtensions = {};
+ function extendMode(mode, properties) {
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
+ copyObj(properties, exts);
}
-}
-function docMethodOp(f) {
- return function() {
- var cm = this.cm;
- if (!cm || cm.curOp) { return f.apply(this, arguments) }
- startOperation(cm);
- try { return f.apply(this, arguments) }
- finally { endOperation(cm); }
+
+ function copyState(mode, state) {
+ if (state === true) { return state }
+ if (mode.copyState) { return mode.copyState(state) }
+ var nstate = {};
+ for (var n in state) {
+ var val = state[n];
+ if (val instanceof Array) { val = val.concat([]); }
+ nstate[n] = val;
+ }
+ return nstate
}
-}
-
-// Updates the display.view data structure for a given change to the
-// document. From and to are in pre-change coordinates. Lendiff is
-// the amount of lines added or subtracted by the change. This is
-// used for changes that span multiple lines, or change the way
-// lines are divided into visual lines. regLineChange (below)
-// registers single-line changes.
-function regChange(cm, from, to, lendiff) {
- if (from == null) { from = cm.doc.first; }
- if (to == null) { to = cm.doc.first + cm.doc.size; }
- if (!lendiff) { lendiff = 0; }
-
- var display = cm.display;
- if (lendiff && to < display.viewTo &&
- (display.updateLineNumbers == null || display.updateLineNumbers > from))
- { display.updateLineNumbers = from; }
-
- cm.curOp.viewChanged = true;
-
- if (from >= display.viewTo) { // Change after
- if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
- { resetView(cm); }
- } else if (to <= display.viewFrom) { // Change before
- if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
- resetView(cm);
- } else {
- display.viewFrom += lendiff;
- display.viewTo += lendiff;
- }
- } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
- resetView(cm);
- } else if (from <= display.viewFrom) { // Top overlap
- var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
- if (cut) {
- display.view = display.view.slice(cut.index);
- display.viewFrom = cut.lineN;
- display.viewTo += lendiff;
- } else {
- resetView(cm);
+
+ // Given a mode and a state (for that mode), find the inner mode and
+ // state at the position that the state refers to.
+ function innerMode(mode, state) {
+ var info;
+ while (mode.innerMode) {
+ info = mode.innerMode(state);
+ if (!info || info.mode == mode) { break }
+ state = info.state;
+ mode = info.mode;
}
- } else if (to >= display.viewTo) { // Bottom overlap
- var cut$1 = viewCuttingPoint(cm, from, from, -1);
- if (cut$1) {
- display.view = display.view.slice(0, cut$1.index);
- display.viewTo = cut$1.lineN;
- } else {
- resetView(cm);
+ return info || {mode: mode, state: state}
+ }
+
+ function startState(mode, a1, a2) {
+ return mode.startState ? mode.startState(a1, a2) : true
+ }
+
+ // STRING STREAM
+
+ // Fed to the mode parsers, provides helper functions to make
+ // parsers more succinct.
+
+ var StringStream = function(string, tabSize, lineOracle) {
+ this.pos = this.start = 0;
+ this.string = string;
+ this.tabSize = tabSize || 8;
+ this.lastColumnPos = this.lastColumnValue = 0;
+ this.lineStart = 0;
+ this.lineOracle = lineOracle;
+ };
+
+ StringStream.prototype.eol = function () {return this.pos >= this.string.length};
+ StringStream.prototype.sol = function () {return this.pos == this.lineStart};
+ StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
+ StringStream.prototype.next = function () {
+ if (this.pos < this.string.length)
+ { return this.string.charAt(this.pos++) }
+ };
+ StringStream.prototype.eat = function (match) {
+ var ch = this.string.charAt(this.pos);
+ var ok;
+ if (typeof match == "string") { ok = ch == match; }
+ else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
+ if (ok) {++this.pos; return ch}
+ };
+ StringStream.prototype.eatWhile = function (match) {
+ var start = this.pos;
+ while (this.eat(match)){}
+ return this.pos > start
+ };
+ StringStream.prototype.eatSpace = function () {
+ var start = this.pos;
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }
+ return this.pos > start
+ };
+ StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
+ StringStream.prototype.skipTo = function (ch) {
+ var found = this.string.indexOf(ch, this.pos);
+ if (found > -1) {this.pos = found; return true}
+ };
+ StringStream.prototype.backUp = function (n) {this.pos -= n;};
+ StringStream.prototype.column = function () {
+ if (this.lastColumnPos < this.start) {
+ this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
+ this.lastColumnPos = this.start;
}
- } else { // Gap in the middle
- var cutTop = viewCuttingPoint(cm, from, from, -1);
- var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
- if (cutTop && cutBot) {
- display.view = display.view.slice(0, cutTop.index)
- .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
- .concat(display.view.slice(cutBot.index));
- display.viewTo += lendiff;
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
+ };
+ StringStream.prototype.indentation = function () {
+ return countColumn(this.string, null, this.tabSize) -
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
+ };
+ StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
+ if (typeof pattern == "string") {
+ var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
+ var substr = this.string.substr(this.pos, pattern.length);
+ if (cased(substr) == cased(pattern)) {
+ if (consume !== false) { this.pos += pattern.length; }
+ return true
+ }
} else {
- resetView(cm);
+ var match = this.string.slice(this.pos).match(pattern);
+ if (match && match.index > 0) { return null }
+ if (match && consume !== false) { this.pos += match[0].length; }
+ return match
}
- }
+ };
+ StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
+ StringStream.prototype.hideFirstChars = function (n, inner) {
+ this.lineStart += n;
+ try { return inner() }
+ finally { this.lineStart -= n; }
+ };
+ StringStream.prototype.lookAhead = function (n) {
+ var oracle = this.lineOracle;
+ return oracle && oracle.lookAhead(n)
+ };
+ StringStream.prototype.baseToken = function () {
+ var oracle = this.lineOracle;
+ return oracle && oracle.baseToken(this.pos)
+ };
- var ext = display.externalMeasured;
- if (ext) {
- if (to < ext.lineN)
- { ext.lineN += lendiff; }
- else if (from < ext.lineN + ext.size)
- { display.externalMeasured = null; }
+ var SavedContext = function(state, lookAhead) {
+ this.state = state;
+ this.lookAhead = lookAhead;
+ };
+
+ var Context = function(doc, state, line, lookAhead) {
+ this.state = state;
+ this.doc = doc;
+ this.line = line;
+ this.maxLookAhead = lookAhead || 0;
+ this.baseTokens = null;
+ this.baseTokenPos = 1;
+ };
+
+ Context.prototype.lookAhead = function (n) {
+ var line = this.doc.getLine(this.line + n);
+ if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
+ return line
+ };
+
+ Context.prototype.baseToken = function (n) {
+ if (!this.baseTokens) { return null }
+ while (this.baseTokens[this.baseTokenPos] <= n)
+ { this.baseTokenPos += 2; }
+ var type = this.baseTokens[this.baseTokenPos + 1];
+ return {type: type && type.replace(/( |^)overlay .*/, ""),
+ size: this.baseTokens[this.baseTokenPos] - n}
+ };
+
+ Context.prototype.nextLine = function () {
+ this.line++;
+ if (this.maxLookAhead > 0) { this.maxLookAhead--; }
+ };
+
+ Context.fromSaved = function (doc, saved, line) {
+ if (saved instanceof SavedContext)
+ { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
+ else
+ { return new Context(doc, copyState(doc.mode, saved), line) }
+ };
+
+ Context.prototype.save = function (copy) {
+ var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
+ return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
+ };
+
+
+ // Compute a style array (an array starting with a mode generation
+ // -- for invalidation -- followed by pairs of end positions and
+ // style strings), which is used to highlight the tokens on the
+ // line.
+ function highlightLine(cm, line, context, forceToEnd) {
+ // A styles array always starts with a number identifying the
+ // mode/overlays that it is based on (for easy invalidation).
+ var st = [cm.state.modeGen], lineClasses = {};
+ // Compute the base array of styles
+ runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
+ lineClasses, forceToEnd);
+ var state = context.state;
+
+ // Run overlays, adjust style array.
+ var loop = function ( o ) {
+ context.baseTokens = st;
+ var overlay = cm.state.overlays[o], i = 1, at = 0;
+ context.state = true;
+ runMode(cm, line.text, overlay.mode, context, function (end, style) {
+ var start = i;
+ // Ensure there's a token end at the current position, and that i points at it
+ while (at < end) {
+ var i_end = st[i];
+ if (i_end > end)
+ { st.splice(i, 1, end, st[i+1], i_end); }
+ i += 2;
+ at = Math.min(end, i_end);
+ }
+ if (!style) { return }
+ if (overlay.opaque) {
+ st.splice(start, i - start, end, "overlay " + style);
+ i = start + 2;
+ } else {
+ for (; start < i; start += 2) {
+ var cur = st[start+1];
+ st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
+ }
+ }
+ }, lineClasses);
+ context.state = state;
+ context.baseTokens = null;
+ context.baseTokenPos = 1;
+ };
+
+ for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
+
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
}
-}
-
-// Register a change to a single line. Type must be one of "text",
-// "gutter", "class", "widget"
-function regLineChange(cm, line, type) {
- cm.curOp.viewChanged = true;
- var display = cm.display, ext = cm.display.externalMeasured;
- if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
- { display.externalMeasured = null; }
-
- if (line < display.viewFrom || line >= display.viewTo) { return }
- var lineView = display.view[findViewIndex(cm, line)];
- if (lineView.node == null) { return }
- var arr = lineView.changes || (lineView.changes = []);
- if (indexOf(arr, type) == -1) { arr.push(type); }
-}
-
-// Clear the view.
-function resetView(cm) {
- cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
- cm.display.view = [];
- cm.display.viewOffset = 0;
-}
-
-function viewCuttingPoint(cm, oldN, newN, dir) {
- var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
- if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
- { return {index: index, lineN: newN} }
- var n = cm.display.viewFrom;
- for (var i = 0; i < index; i++)
- { n += view[i].size; }
- if (n != oldN) {
- if (dir > 0) {
- if (index == view.length - 1) { return null }
- diff = (n + view[index].size) - oldN;
- index++;
- } else {
- diff = n - oldN;
- }
- oldN += diff; newN += diff;
- }
- while (visualLineNo(cm.doc, newN) != newN) {
- if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
- newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
- index += dir;
- }
- return {index: index, lineN: newN}
-}
-
-// Force the view to cover a given range, adding empty view element
-// or clipping off existing ones as needed.
-function adjustView(cm, from, to) {
- var display = cm.display, view = display.view;
- if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
- display.view = buildViewArray(cm, from, to);
- display.viewFrom = from;
- } else {
- if (display.viewFrom > from)
- { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
- else if (display.viewFrom < from)
- { display.view = display.view.slice(findViewIndex(cm, from)); }
- display.viewFrom = from;
- if (display.viewTo < to)
- { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
- else if (display.viewTo > to)
- { display.view = display.view.slice(0, findViewIndex(cm, to)); }
- }
- display.viewTo = to;
-}
-
-// Count the number of lines in the view whose DOM representation is
-// out of date (or nonexistent).
-function countDirtyView(cm) {
- var view = cm.display.view, dirty = 0;
- for (var i = 0; i < view.length; i++) {
- var lineView = view[i];
- if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
- }
- return dirty
-}
-
-// HIGHLIGHT WORKER
-
-function startWorker(cm, time) {
- if (cm.doc.highlightFrontier < cm.display.viewTo)
- { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
-}
-
-function highlightWorker(cm) {
- var doc = cm.doc;
- if (doc.highlightFrontier >= cm.display.viewTo) { return }
- var end = +new Date + cm.options.workTime;
- var context = getContextBefore(cm, doc.highlightFrontier);
- var changedLines = [];
-
- doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
- if (context.line >= cm.display.viewFrom) { // Visible
- var oldStyles = line.styles;
- var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
- var highlighted = highlightLine(cm, line, context, true);
+
+ function getLineStyles(cm, line, updateFrontier) {
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
+ var context = getContextBefore(cm, lineNo(line));
+ var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
+ var result = highlightLine(cm, line, context);
if (resetState) { context.state = resetState; }
- line.styles = highlighted.styles;
- var oldCls = line.styleClasses, newCls = highlighted.classes;
- if (newCls) { line.styleClasses = newCls; }
- else if (oldCls) { line.styleClasses = null; }
- var ischange = !oldStyles || oldStyles.length != line.styles.length ||
- oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
- for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
- if (ischange) { changedLines.push(context.line); }
- line.stateAfter = context.save();
- context.nextLine();
- } else {
- if (line.text.length <= cm.options.maxHighlightLength)
- { processLine(cm, line.text, context); }
- line.stateAfter = context.line % 5 == 0 ? context.save() : null;
+ line.stateAfter = context.save(!resetState);
+ line.styles = result.styles;
+ if (result.classes) { line.styleClasses = result.classes; }
+ else if (line.styleClasses) { line.styleClasses = null; }
+ if (updateFrontier === cm.doc.highlightFrontier)
+ { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
+ }
+ return line.styles
+ }
+
+ function getContextBefore(cm, n, precise) {
+ var doc = cm.doc, display = cm.display;
+ if (!doc.mode.startState) { return new Context(doc, true, n) }
+ var start = findStartLine(cm, n, precise);
+ var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
+ var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
+
+ doc.iter(start, n, function (line) {
+ processLine(cm, line.text, context);
+ var pos = context.line;
+ line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
context.nextLine();
+ });
+ if (precise) { doc.modeFrontier = context.line; }
+ return context
+ }
+
+ // Lightweight form of highlight -- proceed over this line and
+ // update state, but don't save a style array. Used for lines that
+ // aren't currently visible.
+ function processLine(cm, text, context, startAt) {
+ var mode = cm.doc.mode;
+ var stream = new StringStream(text, cm.options.tabSize, context);
+ stream.start = stream.pos = startAt || 0;
+ if (text == "") { callBlankLine(mode, context.state); }
+ while (!stream.eol()) {
+ readToken(mode, stream, context.state);
+ stream.start = stream.pos;
}
- if (+new Date > end) {
- startWorker(cm, cm.options.workDelay);
- return true
+ }
+
+ function callBlankLine(mode, state) {
+ if (mode.blankLine) { return mode.blankLine(state) }
+ if (!mode.innerMode) { return }
+ var inner = innerMode(mode, state);
+ if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
+ }
+
+ function readToken(mode, stream, state, inner) {
+ for (var i = 0; i < 10; i++) {
+ if (inner) { inner[0] = innerMode(mode, state).mode; }
+ var style = mode.token(stream, state);
+ if (stream.pos > stream.start) { return style }
}
- });
- doc.highlightFrontier = context.line;
- doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
- if (changedLines.length) { runInOp(cm, function () {
- for (var i = 0; i < changedLines.length; i++)
- { regLineChange(cm, changedLines[i], "text"); }
- }); }
-}
-
-// DISPLAY DRAWING
-
-var DisplayUpdate = function(cm, viewport, force) {
- var display = cm.display;
-
- this.viewport = viewport;
- // Store some values that we'll need later (but don't want to force a relayout for)
- this.visible = visibleLines(display, cm.doc, viewport);
- this.editorIsHidden = !display.wrapper.offsetWidth;
- this.wrapperHeight = display.wrapper.clientHeight;
- this.wrapperWidth = display.wrapper.clientWidth;
- this.oldDisplayWidth = displayWidth(cm);
- this.force = force;
- this.dims = getDimensions(cm);
- this.events = [];
-};
-
-DisplayUpdate.prototype.signal = function (emitter, type) {
- if (hasHandler(emitter, type))
- { this.events.push(arguments); }
-};
-DisplayUpdate.prototype.finish = function () {
- var this$1 = this;
+ throw new Error("Mode " + mode.name + " failed to advance stream.")
+ }
- for (var i = 0; i < this.events.length; i++)
- { signal.apply(null, this$1.events[i]); }
-};
-
-function maybeClipScrollbars(cm) {
- var display = cm.display;
- if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
- display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
- display.heightForcer.style.height = scrollGap(cm) + "px";
- display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
- display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
- display.scrollbarsClipped = true;
- }
-}
-
-function selectionSnapshot(cm) {
- if (cm.hasFocus()) { return null }
- var active = activeElt();
- if (!active || !contains(cm.display.lineDiv, active)) { return null }
- var result = {activeElt: active};
- if (window.getSelection) {
- var sel = window.getSelection();
- if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
- result.anchorNode = sel.anchorNode;
- result.anchorOffset = sel.anchorOffset;
- result.focusNode = sel.focusNode;
- result.focusOffset = sel.focusOffset;
- }
- }
- return result
-}
-
-function restoreSelection(snapshot) {
- if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
- snapshot.activeElt.focus();
- if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
- var sel = window.getSelection(), range$$1 = document.createRange();
- range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
- range$$1.collapse(false);
- sel.removeAllRanges();
- sel.addRange(range$$1);
- sel.extend(snapshot.focusNode, snapshot.focusOffset);
- }
-}
-
-// Does the actual updating of the line display. Bails out
-// (returning false) when there is nothing to be done and forced is
-// false.
-function updateDisplayIfNeeded(cm, update) {
- var display = cm.display, doc = cm.doc;
-
- if (update.editorIsHidden) {
- resetView(cm);
- return false
+ var Token = function(stream, type, state) {
+ this.start = stream.start; this.end = stream.pos;
+ this.string = stream.current();
+ this.type = type || null;
+ this.state = state;
+ };
+
+ // Utility for getTokenAt and getLineTokens
+ function takeToken(cm, pos, precise, asArray) {
+ var doc = cm.doc, mode = doc.mode, style;
+ pos = clipPos(doc, pos);
+ var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
+ var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
+ if (asArray) { tokens = []; }
+ while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
+ stream.start = stream.pos;
+ style = readToken(mode, stream, context.state);
+ if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
+ }
+ return asArray ? tokens : new Token(stream, style, context.state)
+ }
+
+ function extractLineClasses(type, output) {
+ if (type) { for (;;) {
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
+ if (!lineClass) { break }
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
+ var prop = lineClass[1] ? "bgClass" : "textClass";
+ if (output[prop] == null)
+ { output[prop] = lineClass[2]; }
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
+ { output[prop] += " " + lineClass[2]; }
+ } }
+ return type
+ }
+
+ // Run the given mode's parser over a line, calling f for each token.
+ function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
+ var flattenSpans = mode.flattenSpans;
+ if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
+ var curStart = 0, curStyle = null;
+ var stream = new StringStream(text, cm.options.tabSize, context), style;
+ var inner = cm.options.addModeClass && [null];
+ if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
+ while (!stream.eol()) {
+ if (stream.pos > cm.options.maxHighlightLength) {
+ flattenSpans = false;
+ if (forceToEnd) { processLine(cm, text, context, stream.pos); }
+ stream.pos = text.length;
+ style = null;
+ } else {
+ style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
+ }
+ if (inner) {
+ var mName = inner[0].name;
+ if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
+ }
+ if (!flattenSpans || curStyle != style) {
+ while (curStart < stream.start) {
+ curStart = Math.min(stream.start, curStart + 5000);
+ f(curStart, curStyle);
+ }
+ curStyle = style;
+ }
+ stream.start = stream.pos;
+ }
+ while (curStart < stream.pos) {
+ // Webkit seems to refuse to render text nodes longer than 57444
+ // characters, and returns inaccurate measurements in nodes
+ // starting around 5000 chars.
+ var pos = Math.min(stream.pos, curStart + 5000);
+ f(pos, curStyle);
+ curStart = pos;
+ }
+ }
+
+ // Finds the line to start with when starting a parse. Tries to
+ // find a line with a stateAfter, so that it can start with a
+ // valid state. If that fails, it returns the line with the
+ // smallest indentation, which tends to need the least context to
+ // parse correctly.
+ function findStartLine(cm, n, precise) {
+ var minindent, minline, doc = cm.doc;
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
+ for (var search = n; search > lim; --search) {
+ if (search <= doc.first) { return doc.first }
+ var line = getLine(doc, search - 1), after = line.stateAfter;
+ if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
+ { return search }
+ var indented = countColumn(line.text, null, cm.options.tabSize);
+ if (minline == null || minindent > indented) {
+ minline = search - 1;
+ minindent = indented;
+ }
+ }
+ return minline
}
- // Bail out if the visible area is already rendered and nothing changed.
- if (!update.force &&
- update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
- (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
- display.renderedView == display.view && countDirtyView(cm) == 0)
- { return false }
-
- if (maybeUpdateLineNumberWidth(cm)) {
- resetView(cm);
- update.dims = getDimensions(cm);
- }
-
- // Compute a suitable new viewport (from & to)
- var end = doc.first + doc.size;
- var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
- var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
- if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
- if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
- if (sawCollapsedSpans) {
- from = visualLineNo(cm.doc, from);
- to = visualLineEndNo(cm.doc, to);
- }
-
- var different = from != display.viewFrom || to != display.viewTo ||
- display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
- adjustView(cm, from, to);
-
- display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
- // Position the mover div to align with the current scroll position
- cm.display.mover.style.top = display.viewOffset + "px";
-
- var toUpdate = countDirtyView(cm);
- if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
- (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
- { return false }
-
- // For big changes, we hide the enclosing element during the
- // update, since that speeds up the operations on most browsers.
- var selSnapshot = selectionSnapshot(cm);
- if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
- patchDisplay(cm, display.updateLineNumbers, update.dims);
- if (toUpdate > 4) { display.lineDiv.style.display = ""; }
- display.renderedView = display.view;
- // There might have been a widget with a focused element that got
- // hidden or updated, if so re-focus it.
- restoreSelection(selSnapshot);
-
- // Prevent selection and cursors from interfering with the scroll
- // width and height.
- removeChildren(display.cursorDiv);
- removeChildren(display.selectionDiv);
- display.gutters.style.height = display.sizer.style.minHeight = 0;
-
- if (different) {
- display.lastWrapHeight = update.wrapperHeight;
- display.lastWrapWidth = update.wrapperWidth;
- startWorker(cm, 400);
+ function retreatFrontier(doc, n) {
+ doc.modeFrontier = Math.min(doc.modeFrontier, n);
+ if (doc.highlightFrontier < n - 10) { return }
+ var start = doc.first;
+ for (var line = n - 1; line > start; line--) {
+ var saved = getLine(doc, line).stateAfter;
+ // change is on 3
+ // state on line 1 looked ahead 2 -- so saw 3
+ // test 1 + 2 < 3 should cover this
+ if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
+ start = line + 1;
+ break
+ }
+ }
+ doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
}
- display.updateLineNumbers = null;
+ // LINE DATA STRUCTURE
- return true
-}
+ // Line objects. These hold state related to a line, including
+ // highlighting info (the styles array).
+ var Line = function(text, markedSpans, estimateHeight) {
+ this.text = text;
+ attachMarkedSpans(this, markedSpans);
+ this.height = estimateHeight ? estimateHeight(this) : 1;
+ };
-function postUpdateDisplay(cm, update) {
- var viewport = update.viewport;
+ Line.prototype.lineNo = function () { return lineNo(this) };
+ eventMixin(Line);
- for (var first = true;; first = false) {
- if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
- // Clip forced viewport to actual scrollable area.
- if (viewport && viewport.top != null)
- { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
- // Updated line heights might result in the drawn area not
- // actually covering the viewport. Keep looping until it does.
- update.visible = visibleLines(cm.display, cm.doc, viewport);
- if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
- { break }
+ // Change the content (text, markers) of a line. Automatically
+ // invalidates cached information and tries to re-estimate the
+ // line's height.
+ function updateLine(line, text, markedSpans, estimateHeight) {
+ line.text = text;
+ if (line.stateAfter) { line.stateAfter = null; }
+ if (line.styles) { line.styles = null; }
+ if (line.order != null) { line.order = null; }
+ detachMarkedSpans(line);
+ attachMarkedSpans(line, markedSpans);
+ var estHeight = estimateHeight ? estimateHeight(line) : 1;
+ if (estHeight != line.height) { updateLineHeight(line, estHeight); }
+ }
+
+ // Detach a line from the document tree and its markers.
+ function cleanUpLine(line) {
+ line.parent = null;
+ detachMarkedSpans(line);
+ }
+
+ // Convert a style as returned by a mode (either null, or a string
+ // containing one or more styles) to a CSS style. This is cached,
+ // and also looks for line-wide styles.
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
+ function interpretTokenStyle(style, options) {
+ if (!style || /^\s*$/.test(style)) { return null }
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+ return cache[style] ||
+ (cache[style] = style.replace(/\S+/g, "cm-$&"))
+ }
+
+ // Render the DOM representation of the text of a line. Also builds
+ // up a 'line map', which points at the DOM nodes that represent
+ // specific stretches of text, and is used by the measuring code.
+ // The returned object contains the DOM node, this map, and
+ // information about line-wide styles that were set by the mode.
+ function buildLineContent(cm, lineView) {
+ // The padding-right forces the element to have a 'border', which
+ // is needed on Webkit to be able to get line-level bounding
+ // rectangles for it (in measureChar).
+ var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
+ var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
+ col: 0, pos: 0, cm: cm,
+ trailingSpace: false,
+ splitSpaces: cm.getOption("lineWrapping")};
+ lineView.measure = {};
+
+ // Iterate over the logical lines that make up this visual line.
+ for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
+ var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
+ builder.pos = 0;
+ builder.addToken = buildToken;
+ // Optionally wire in some hacks into the token-rendering
+ // algorithm, to deal with browser quirks.
+ if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
+ { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
+ builder.map = [];
+ var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
+ insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
+ if (line.styleClasses) {
+ if (line.styleClasses.bgClass)
+ { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
+ if (line.styleClasses.textClass)
+ { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
+ }
+
+ // Ensure at least a single node is present, for measuring.
+ if (builder.map.length == 0)
+ { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
+
+ // Store the map and a cache object for the current logical line
+ if (i == 0) {
+ lineView.measure.map = builder.map;
+ lineView.measure.cache = {};
+ } else {
+ (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
+ ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
+ }
}
- if (!updateDisplayIfNeeded(cm, update)) { break }
- updateHeightsInViewport(cm);
- var barMeasure = measureForScrollbars(cm);
- updateSelection(cm);
- updateScrollbars(cm, barMeasure);
- setDocumentHeight(cm, barMeasure);
- update.force = false;
- }
-
- update.signal(cm, "update", cm);
- if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
- update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
- cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
- }
-}
-
-function updateDisplaySimple(cm, viewport) {
- var update = new DisplayUpdate(cm, viewport);
- if (updateDisplayIfNeeded(cm, update)) {
- updateHeightsInViewport(cm);
- postUpdateDisplay(cm, update);
- var barMeasure = measureForScrollbars(cm);
- updateSelection(cm);
- updateScrollbars(cm, barMeasure);
- setDocumentHeight(cm, barMeasure);
- update.finish();
- }
-}
-
-// Sync the actual display DOM structure with display.view, removing
-// nodes for lines that are no longer in view, and creating the ones
-// that are not there yet, and updating the ones that are out of
-// date.
-function patchDisplay(cm, updateNumbersFrom, dims) {
- var display = cm.display, lineNumbers = cm.options.lineNumbers;
- var container = display.lineDiv, cur = container.firstChild;
-
- function rm(node) {
- var next = node.nextSibling;
- // Works around a throw-scroll bug in OS X Webkit
- if (webkit && mac && cm.display.currentWheelTarget == node)
- { node.style.display = "none"; }
- else
- { node.parentNode.removeChild(node); }
- return next
- }
-
- var view = display.view, lineN = display.viewFrom;
- // Loop over the elements in the view, syncing cur (the DOM nodes
- // in display.lineDiv) with the view as we go.
- for (var i = 0; i < view.length; i++) {
- var lineView = view[i];
- if (lineView.hidden) {
- } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
- var node = buildLineElement(cm, lineView, lineN, dims);
- container.insertBefore(node, cur);
- } else { // Already drawn
- while (cur != lineView.node) { cur = rm(cur); }
- var updateNumber = lineNumbers && updateNumbersFrom != null &&
- updateNumbersFrom <= lineN && lineView.lineNumber;
- if (lineView.changes) {
- if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
- updateLineForChanges(cm, lineView, lineN, dims);
- }
- if (updateNumber) {
- removeChildren(lineView.lineNumber);
- lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
- }
- cur = lineView.node.nextSibling;
- }
- lineN += lineView.size;
- }
- while (cur) { cur = rm(cur); }
-}
-
-function updateGutterSpace(cm) {
- var width = cm.display.gutters.offsetWidth;
- cm.display.sizer.style.marginLeft = width + "px";
-}
-
-function setDocumentHeight(cm, measure) {
- cm.display.sizer.style.minHeight = measure.docHeight + "px";
- cm.display.heightForcer.style.top = measure.docHeight + "px";
- cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
-}
-
-// Rebuild the gutter elements, ensure the margin to the left of the
-// code matches their width.
-function updateGutters(cm) {
- var gutters = cm.display.gutters, specs = cm.options.gutters;
- removeChildren(gutters);
- var i = 0;
- for (; i < specs.length; ++i) {
- var gutterClass = specs[i];
- var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
- if (gutterClass == "CodeMirror-linenumbers") {
- cm.display.lineGutter = gElt;
- gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
- }
- }
- gutters.style.display = i ? "" : "none";
- updateGutterSpace(cm);
-}
-
-// Make sure the gutters options contains the element
-// "CodeMirror-linenumbers" when the lineNumbers option is true.
-function setGuttersForLineNumbers(options) {
- var found = indexOf(options.gutters, "CodeMirror-linenumbers");
- if (found == -1 && options.lineNumbers) {
- options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
- } else if (found > -1 && !options.lineNumbers) {
- options.gutters = options.gutters.slice(0);
- options.gutters.splice(found, 1);
- }
-}
-
-// Since the delta values reported on mouse wheel events are
-// unstandardized between browsers and even browser versions, and
-// generally horribly unpredictable, this code starts by measuring
-// the scroll effect that the first few mouse wheel events have,
-// and, from that, detects the way it can convert deltas to pixel
-// offsets afterwards.
-//
-// The reason we want to know the amount a wheel event will scroll
-// is that it gives us a chance to update the display before the
-// actual scrolling happens, reducing flickering.
-
-var wheelSamples = 0;
-var wheelPixelsPerUnit = null;
-// Fill in a browser-detected starting value on browsers where we
-// know one. These don't have to be accurate -- the result of them
-// being wrong would just be a slight flicker on the first wheel
-// scroll (if it is large enough).
-if (ie) { wheelPixelsPerUnit = -.53; }
-else if (gecko) { wheelPixelsPerUnit = 15; }
-else if (chrome) { wheelPixelsPerUnit = -.7; }
-else if (safari) { wheelPixelsPerUnit = -1/3; }
-
-function wheelEventDelta(e) {
- var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
- if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
- if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
- else if (dy == null) { dy = e.wheelDelta; }
- return {x: dx, y: dy}
-}
-function wheelEventPixels(e) {
- var delta = wheelEventDelta(e);
- delta.x *= wheelPixelsPerUnit;
- delta.y *= wheelPixelsPerUnit;
- return delta
-}
-
-function onScrollWheel(cm, e) {
- var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
-
- var display = cm.display, scroll = display.scroller;
- // Quit if there's nothing to scroll here
- var canScrollX = scroll.scrollWidth > scroll.clientWidth;
- var canScrollY = scroll.scrollHeight > scroll.clientHeight;
- if (!(dx && canScrollX || dy && canScrollY)) { return }
-
- // Webkit browsers on OS X abort momentum scrolls when the target
- // of the scroll event is removed from the scrollable element.
- // This hack (see related code in patchDisplay) makes sure the
- // element is kept around.
- if (dy && mac && webkit) {
- outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
- for (var i = 0; i < view.length; i++) {
- if (view[i].node == cur) {
- cm.display.currentWheelTarget = cur;
- break outer
+
+ // See issue #2901
+ if (webkit) {
+ var last = builder.content.lastChild;
+ if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
+ { builder.content.className = "cm-tab-wrap-hack"; }
+ }
+
+ signal(cm, "renderLine", cm, lineView.line, builder.pre);
+ if (builder.pre.className)
+ { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
+
+ return builder
+ }
+
+ function defaultSpecialCharPlaceholder(ch) {
+ var token = elt("span", "\u2022", "cm-invalidchar");
+ token.title = "\\u" + ch.charCodeAt(0).toString(16);
+ token.setAttribute("aria-label", token.title);
+ return token
+ }
+
+ // Build up the DOM representation for a single token, and add it to
+ // the line map. Takes care to render special characters separately.
+ function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
+ if (!text) { return }
+ var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
+ var special = builder.cm.state.specialChars, mustWrap = false;
+ var content;
+ if (!special.test(text)) {
+ builder.col += text.length;
+ content = document.createTextNode(displayText);
+ builder.map.push(builder.pos, builder.pos + text.length, content);
+ if (ie && ie_version < 9) { mustWrap = true; }
+ builder.pos += text.length;
+ } else {
+ content = document.createDocumentFragment();
+ var pos = 0;
+ while (true) {
+ special.lastIndex = pos;
+ var m = special.exec(text);
+ var skipped = m ? m.index - pos : text.length - pos;
+ if (skipped) {
+ var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
+ if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
+ else { content.appendChild(txt); }
+ builder.map.push(builder.pos, builder.pos + skipped, txt);
+ builder.col += skipped;
+ builder.pos += skipped;
}
+ if (!m) { break }
+ pos += skipped + 1;
+ var txt$1 = (void 0);
+ if (m[0] == "\t") {
+ var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
+ txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
+ txt$1.setAttribute("role", "presentation");
+ txt$1.setAttribute("cm-text", "\t");
+ builder.col += tabWidth;
+ } else if (m[0] == "\r" || m[0] == "\n") {
+ txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
+ txt$1.setAttribute("cm-text", m[0]);
+ builder.col += 1;
+ } else {
+ txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
+ txt$1.setAttribute("cm-text", m[0]);
+ if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
+ else { content.appendChild(txt$1); }
+ builder.col += 1;
+ }
+ builder.map.push(builder.pos, builder.pos + 1, txt$1);
+ builder.pos++;
+ }
+ }
+ builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
+ if (style || startStyle || endStyle || mustWrap || css) {
+ var fullStyle = style || "";
+ if (startStyle) { fullStyle += startStyle; }
+ if (endStyle) { fullStyle += endStyle; }
+ var token = elt("span", [content], fullStyle, css);
+ if (attributes) {
+ for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
+ { token.setAttribute(attr, attributes[attr]); } }
}
+ return builder.content.appendChild(token)
}
+ builder.content.appendChild(content);
}
- // On some browsers, horizontal scrolling will cause redraws to
- // happen before the gutter has been realigned, causing it to
- // wriggle around in a most unseemly way. When we have an
- // estimated pixels/delta value, we just handle horizontal
- // scrolling entirely here. It'll be slightly off from native, but
- // better than glitching out.
- if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
- if (dy && canScrollY)
- { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
- setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
- // Only prevent default scrolling if vertical scrolling is
- // actually possible. Otherwise, it causes vertical scroll
- // jitter on OSX trackpads when deltaX is small and deltaY
- // is large (issue #3579)
- if (!dy || (dy && canScrollY))
- { e_preventDefault(e); }
- display.wheelStartX = null; // Abort measurement, if in progress
- return
- }
-
- // 'Project' the visible viewport to cover the area that is being
- // scrolled into view (if we know enough to estimate it).
- if (dy && wheelPixelsPerUnit != null) {
- var pixels = dy * wheelPixelsPerUnit;
- var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
- if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
- else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
- updateDisplaySimple(cm, {top: top, bottom: bot});
- }
-
- if (wheelSamples < 20) {
- if (display.wheelStartX == null) {
- display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
- display.wheelDX = dx; display.wheelDY = dy;
- setTimeout(function () {
- if (display.wheelStartX == null) { return }
- var movedX = scroll.scrollLeft - display.wheelStartX;
- var movedY = scroll.scrollTop - display.wheelStartY;
- var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
- (movedX && display.wheelDX && movedX / display.wheelDX);
- display.wheelStartX = display.wheelStartY = null;
- if (!sample) { return }
- wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
- ++wheelSamples;
- }, 200);
- } else {
- display.wheelDX += dx; display.wheelDY += dy;
+ // Change some spaces to NBSP to prevent the browser from collapsing
+ // trailing spaces at the end of a line when rendering text (issue #1362).
+ function splitSpaces(text, trailingBefore) {
+ if (text.length > 1 && !/ /.test(text)) { return text }
+ var spaceBefore = trailingBefore, result = "";
+ for (var i = 0; i < text.length; i++) {
+ var ch = text.charAt(i);
+ if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
+ { ch = "\u00a0"; }
+ result += ch;
+ spaceBefore = ch == " ";
}
+ return result
}
-}
-// Selection objects are immutable. A new one is created every time
-// the selection changes. A selection is one or more non-overlapping
-// (and non-touching) ranges, sorted, and an integer that indicates
-// which one is the primary selection (the one that's scrolled into
-// view, that getCursor returns, etc).
-var Selection = function(ranges, primIndex) {
- this.ranges = ranges;
- this.primIndex = primIndex;
-};
+ // Work around nonsense dimensions being reported for stretches of
+ // right-to-left text.
+ function buildTokenBadBidi(inner, order) {
+ return function (builder, text, style, startStyle, endStyle, css, attributes) {
+ style = style ? style + " cm-force-border" : "cm-force-border";
+ var start = builder.pos, end = start + text.length;
+ for (;;) {
+ // Find the part that overlaps with the start of this text
+ var part = (void 0);
+ for (var i = 0; i < order.length; i++) {
+ part = order[i];
+ if (part.to > start && part.from <= start) { break }
+ }
+ if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) }
+ inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes);
+ startStyle = null;
+ text = text.slice(part.to - start);
+ start = part.to;
+ }
+ }
+ }
-Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
+ function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
+ var widget = !ignoreWidget && marker.widgetNode;
+ if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
+ if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
+ if (!widget)
+ { widget = builder.content.appendChild(document.createElement("span")); }
+ widget.setAttribute("cm-marker", marker.id);
+ }
+ if (widget) {
+ builder.cm.display.input.setUneditable(widget);
+ builder.content.appendChild(widget);
+ }
+ builder.pos += size;
+ builder.trailingSpace = false;
+ }
-Selection.prototype.equals = function (other) {
- var this$1 = this;
+ // Outputs a number of spans to make up a line, taking highlighting
+ // and marked text into account.
+ function insertLineContent(line, builder, styles) {
+ var spans = line.markedSpans, allText = line.text, at = 0;
+ if (!spans) {
+ for (var i$1 = 1; i$1 < styles.length; i$1+=2)
+ { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
+ return
+ }
- if (other == this) { return true }
- if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
- for (var i = 0; i < this.ranges.length; i++) {
- var here = this$1.ranges[i], there = other.ranges[i];
- if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
+ var len = allText.length, pos = 0, i = 1, text = "", style, css;
+ var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes;
+ for (;;) {
+ if (nextChange == pos) { // Update current marker set
+ spanStyle = spanEndStyle = spanStartStyle = css = "";
+ attributes = null;
+ collapsed = null; nextChange = Infinity;
+ var foundBookmarks = [], endStyles = (void 0);
+ for (var j = 0; j < spans.length; ++j) {
+ var sp = spans[j], m = sp.marker;
+ if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
+ foundBookmarks.push(m);
+ } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
+ if (sp.to != null && sp.to != pos && nextChange > sp.to) {
+ nextChange = sp.to;
+ spanEndStyle = "";
+ }
+ if (m.className) { spanStyle += " " + m.className; }
+ if (m.css) { css = (css ? css + ";" : "") + m.css; }
+ if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
+ if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
+ // support for the old title property
+ // https://github.com/codemirror/CodeMirror/pull/5673
+ if (m.title) { (attributes || (attributes = {})).title = m.title; }
+ if (m.attributes) {
+ for (var attr in m.attributes)
+ { (attributes || (attributes = {}))[attr] = m.attributes[attr]; }
+ }
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
+ { collapsed = sp; }
+ } else if (sp.from > pos && nextChange > sp.from) {
+ nextChange = sp.from;
+ }
+ }
+ if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
+ { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
+
+ if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
+ { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
+ if (collapsed && (collapsed.from || 0) == pos) {
+ buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
+ collapsed.marker, collapsed.from == null);
+ if (collapsed.to == null) { return }
+ if (collapsed.to == pos) { collapsed = false; }
+ }
+ }
+ if (pos >= len) { break }
+
+ var upto = Math.min(len, nextChange);
+ while (true) {
+ if (text) {
+ var end = pos + text.length;
+ if (!collapsed) {
+ var tokenText = end > upto ? text.slice(0, upto - pos) : text;
+ builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes);
+ }
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
+ pos = end;
+ spanStartStyle = "";
+ }
+ text = allText.slice(at, at = styles[i++]);
+ style = interpretTokenStyle(styles[i++], builder.cm.options);
+ }
+ }
}
- return true
-};
-Selection.prototype.deepCopy = function () {
- var this$1 = this;
- var out = [];
- for (var i = 0; i < this.ranges.length; i++)
- { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
- return new Selection(out, this.primIndex)
-};
+ // These objects are used to represent the visible (currently drawn)
+ // part of the document. A LineView may correspond to multiple
+ // logical lines, if those are connected by collapsed ranges.
+ function LineView(doc, line, lineN) {
+ // The starting line
+ this.line = line;
+ // Continuing lines, if any
+ this.rest = visualLineContinued(line);
+ // Number of logical lines in this visual line
+ this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
+ this.node = this.text = null;
+ this.hidden = lineIsHidden(doc, line);
+ }
-Selection.prototype.somethingSelected = function () {
- var this$1 = this;
+ // Create a range of LineView objects for the given lines.
+ function buildViewArray(cm, from, to) {
+ var array = [], nextPos;
+ for (var pos = from; pos < to; pos = nextPos) {
+ var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
+ nextPos = pos + view.size;
+ array.push(view);
+ }
+ return array
+ }
- for (var i = 0; i < this.ranges.length; i++)
- { if (!this$1.ranges[i].empty()) { return true } }
- return false
-};
+ var operationGroup = null;
-Selection.prototype.contains = function (pos, end) {
- var this$1 = this;
+ function pushOperation(op) {
+ if (operationGroup) {
+ operationGroup.ops.push(op);
+ } else {
+ op.ownsGroup = operationGroup = {
+ ops: [op],
+ delayedCallbacks: []
+ };
+ }
+ }
- if (!end) { end = pos; }
- for (var i = 0; i < this.ranges.length; i++) {
- var range = this$1.ranges[i];
- if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
- { return i }
- }
- return -1
-};
-
-var Range = function(anchor, head) {
- this.anchor = anchor; this.head = head;
-};
-
-Range.prototype.from = function () { return minPos(this.anchor, this.head) };
-Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
-Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
-
-// Take an unsorted, potentially overlapping set of ranges, and
-// build a selection out of it. 'Consumes' ranges array (modifying
-// it).
-function normalizeSelection(ranges, primIndex) {
- var prim = ranges[primIndex];
- ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
- primIndex = indexOf(ranges, prim);
- for (var i = 1; i < ranges.length; i++) {
- var cur = ranges[i], prev = ranges[i - 1];
- if (cmp(prev.to(), cur.from()) >= 0) {
- var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
- var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
- if (i <= primIndex) { --primIndex; }
- ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
- }
- }
- return new Selection(ranges, primIndex)
-}
-
-function simpleSelection(anchor, head) {
- return new Selection([new Range(anchor, head || anchor)], 0)
-}
-
-// Compute the position of the end of a change (its 'to' property
-// refers to the pre-change end).
-function changeEnd(change) {
- if (!change.text) { return change.to }
- return Pos(change.from.line + change.text.length - 1,
- lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
-}
-
-// Adjust a position to refer to the post-change position of the
-// same text, or the end of the change if the change covers it.
-function adjustForChange(pos, change) {
- if (cmp(pos, change.from) < 0) { return pos }
- if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
-
- var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
- if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
- return Pos(line, ch)
-}
-
-function computeSelAfterChange(doc, change) {
- var out = [];
- for (var i = 0; i < doc.sel.ranges.length; i++) {
- var range = doc.sel.ranges[i];
- out.push(new Range(adjustForChange(range.anchor, change),
- adjustForChange(range.head, change)));
- }
- return normalizeSelection(out, doc.sel.primIndex)
-}
-
-function offsetPos(pos, old, nw) {
- if (pos.line == old.line)
- { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
- else
- { return Pos(nw.line + (pos.line - old.line), pos.ch) }
-}
-
-// Used by replaceSelections to allow moving the selection to the
-// start or around the replaced test. Hint may be "start" or "around".
-function computeReplacedSel(doc, changes, hint) {
- var out = [];
- var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
- for (var i = 0; i < changes.length; i++) {
- var change = changes[i];
- var from = offsetPos(change.from, oldPrev, newPrev);
- var to = offsetPos(changeEnd(change), oldPrev, newPrev);
- oldPrev = change.to;
- newPrev = to;
- if (hint == "around") {
- var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
- out[i] = new Range(inv ? to : from, inv ? from : to);
+ function fireCallbacksForOps(group) {
+ // Calls delayed callbacks and cursorActivity handlers until no
+ // new ones appear
+ var callbacks = group.delayedCallbacks, i = 0;
+ do {
+ for (; i < callbacks.length; i++)
+ { callbacks[i].call(null); }
+ for (var j = 0; j < group.ops.length; j++) {
+ var op = group.ops[j];
+ if (op.cursorActivityHandlers)
+ { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
+ { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
+ }
+ } while (i < callbacks.length)
+ }
+
+ function finishOperation(op, endCb) {
+ var group = op.ownsGroup;
+ if (!group) { return }
+
+ try { fireCallbacksForOps(group); }
+ finally {
+ operationGroup = null;
+ endCb(group);
+ }
+ }
+
+ var orphanDelayedCallbacks = null;
+
+ // Often, we want to signal events at a point where we are in the
+ // middle of some work, but don't want the handler to start calling
+ // other methods on the editor, which might be in an inconsistent
+ // state or simply not expect any other events to happen.
+ // signalLater looks whether there are any handlers, and schedules
+ // them to be executed when the last operation ends, or, if no
+ // operation is active, when a timeout fires.
+ function signalLater(emitter, type /*, values...*/) {
+ var arr = getHandlers(emitter, type);
+ if (!arr.length) { return }
+ var args = Array.prototype.slice.call(arguments, 2), list;
+ if (operationGroup) {
+ list = operationGroup.delayedCallbacks;
+ } else if (orphanDelayedCallbacks) {
+ list = orphanDelayedCallbacks;
} else {
- out[i] = new Range(from, from);
+ list = orphanDelayedCallbacks = [];
+ setTimeout(fireOrphanDelayed, 0);
+ }
+ var loop = function ( i ) {
+ list.push(function () { return arr[i].apply(null, args); });
+ };
+
+ for (var i = 0; i < arr.length; ++i)
+ loop( i );
+ }
+
+ function fireOrphanDelayed() {
+ var delayed = orphanDelayedCallbacks;
+ orphanDelayedCallbacks = null;
+ for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
+ }
+
+ // When an aspect of a line changes, a string is added to
+ // lineView.changes. This updates the relevant part of the line's
+ // DOM structure.
+ function updateLineForChanges(cm, lineView, lineN, dims) {
+ for (var j = 0; j < lineView.changes.length; j++) {
+ var type = lineView.changes[j];
+ if (type == "text") { updateLineText(cm, lineView); }
+ else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
+ else if (type == "class") { updateLineClasses(cm, lineView); }
+ else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
+ }
+ lineView.changes = null;
+ }
+
+ // Lines with gutter elements, widgets or a background class need to
+ // be wrapped, and have the extra elements added to the wrapper div
+ function ensureLineWrapped(lineView) {
+ if (lineView.node == lineView.text) {
+ lineView.node = elt("div", null, null, "position: relative");
+ if (lineView.text.parentNode)
+ { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
+ lineView.node.appendChild(lineView.text);
+ if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
+ }
+ return lineView.node
+ }
+
+ function updateLineBackground(cm, lineView) {
+ var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
+ if (cls) { cls += " CodeMirror-linebackground"; }
+ if (lineView.background) {
+ if (cls) { lineView.background.className = cls; }
+ else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
+ } else if (cls) {
+ var wrap = ensureLineWrapped(lineView);
+ lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
+ cm.display.input.setUneditable(lineView.background);
+ }
+ }
+
+ // Wrapper around buildLineContent which will reuse the structure
+ // in display.externalMeasured when possible.
+ function getLineContent(cm, lineView) {
+ var ext = cm.display.externalMeasured;
+ if (ext && ext.line == lineView.line) {
+ cm.display.externalMeasured = null;
+ lineView.measure = ext.measure;
+ return ext.built
+ }
+ return buildLineContent(cm, lineView)
+ }
+
+ // Redraw the line's text. Interacts with the background and text
+ // classes because the mode may output tokens that influence these
+ // classes.
+ function updateLineText(cm, lineView) {
+ var cls = lineView.text.className;
+ var built = getLineContent(cm, lineView);
+ if (lineView.text == lineView.node) { lineView.node = built.pre; }
+ lineView.text.parentNode.replaceChild(built.pre, lineView.text);
+ lineView.text = built.pre;
+ if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
+ lineView.bgClass = built.bgClass;
+ lineView.textClass = built.textClass;
+ updateLineClasses(cm, lineView);
+ } else if (cls) {
+ lineView.text.className = cls;
+ }
+ }
+
+ function updateLineClasses(cm, lineView) {
+ updateLineBackground(cm, lineView);
+ if (lineView.line.wrapClass)
+ { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
+ else if (lineView.node != lineView.text)
+ { lineView.node.className = ""; }
+ var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
+ lineView.text.className = textClass || "";
+ }
+
+ function updateLineGutter(cm, lineView, lineN, dims) {
+ if (lineView.gutter) {
+ lineView.node.removeChild(lineView.gutter);
+ lineView.gutter = null;
+ }
+ if (lineView.gutterBackground) {
+ lineView.node.removeChild(lineView.gutterBackground);
+ lineView.gutterBackground = null;
+ }
+ if (lineView.line.gutterClass) {
+ var wrap = ensureLineWrapped(lineView);
+ lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
+ ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
+ cm.display.input.setUneditable(lineView.gutterBackground);
+ wrap.insertBefore(lineView.gutterBackground, lineView.text);
+ }
+ var markers = lineView.line.gutterMarkers;
+ if (cm.options.lineNumbers || markers) {
+ var wrap$1 = ensureLineWrapped(lineView);
+ var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
+ cm.display.input.setUneditable(gutterWrap);
+ wrap$1.insertBefore(gutterWrap, lineView.text);
+ if (lineView.line.gutterClass)
+ { gutterWrap.className += " " + lineView.line.gutterClass; }
+ if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
+ { lineView.lineNumber = gutterWrap.appendChild(
+ elt("div", lineNumberFor(cm.options, lineN),
+ "CodeMirror-linenumber CodeMirror-gutter-elt",
+ ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
+ if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
+ var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
+ if (found)
+ { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
+ ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
+ } }
}
}
- return new Selection(out, doc.sel.primIndex)
-}
-// Used to get the editor into a consistent state again when options change.
+ function updateLineWidgets(cm, lineView, dims) {
+ if (lineView.alignable) { lineView.alignable = null; }
+ for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
+ next = node.nextSibling;
+ if (node.className == "CodeMirror-linewidget")
+ { lineView.node.removeChild(node); }
+ }
+ insertLineWidgets(cm, lineView, dims);
+ }
-function loadMode(cm) {
- cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
- resetModeState(cm);
-}
+ // Build a line's DOM representation from scratch
+ function buildLineElement(cm, lineView, lineN, dims) {
+ var built = getLineContent(cm, lineView);
+ lineView.text = lineView.node = built.pre;
+ if (built.bgClass) { lineView.bgClass = built.bgClass; }
+ if (built.textClass) { lineView.textClass = built.textClass; }
-function resetModeState(cm) {
- cm.doc.iter(function (line) {
- if (line.stateAfter) { line.stateAfter = null; }
- if (line.styles) { line.styles = null; }
- });
- cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
- startWorker(cm, 100);
- cm.state.modeGen++;
- if (cm.curOp) { regChange(cm); }
-}
-
-// DOCUMENT DATA STRUCTURE
-
-// By default, updates that start and end at the beginning of a line
-// are treated specially, in order to make the association of line
-// widgets and marker elements with the text behave more intuitive.
-function isWholeLineUpdate(doc, change) {
- return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
- (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
-}
-
-// Perform a change on the document data structure.
-function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
- function spansFor(n) {return markedSpans ? markedSpans[n] : null}
- function update(line, text, spans) {
- updateLine(line, text, spans, estimateHeight$$1);
- signalLater(line, "change", line, change);
- }
- function linesFor(start, end) {
- var result = [];
- for (var i = start; i < end; ++i)
- { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
- return result
+ updateLineClasses(cm, lineView);
+ updateLineGutter(cm, lineView, lineN, dims);
+ insertLineWidgets(cm, lineView, dims);
+ return lineView.node
+ }
+
+ // A lineView may contain multiple logical lines (when merged by
+ // collapsed spans). The widgets for all of them need to be drawn.
+ function insertLineWidgets(cm, lineView, dims) {
+ insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
+ if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
+ { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
+ }
+
+ function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
+ if (!line.widgets) { return }
+ var wrap = ensureLineWrapped(lineView);
+ for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
+ var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
+ if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
+ positionLineWidget(widget, node, lineView, dims);
+ cm.display.input.setUneditable(node);
+ if (allowAbove && widget.above)
+ { wrap.insertBefore(node, lineView.gutter || lineView.text); }
+ else
+ { wrap.appendChild(node); }
+ signalLater(widget, "redraw");
+ }
}
- var from = change.from, to = change.to, text = change.text;
- var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
- var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
-
- // Adjust the line structure
- if (change.full) {
- doc.insert(0, linesFor(0, text.length));
- doc.remove(text.length, doc.size - text.length);
- } else if (isWholeLineUpdate(doc, change)) {
- // This is a whole-line replace. Treated specially to make
- // sure line objects move the way they are supposed to.
- var added = linesFor(0, text.length - 1);
- update(lastLine, lastLine.text, lastSpans);
- if (nlines) { doc.remove(from.line, nlines); }
- if (added.length) { doc.insert(from.line, added); }
- } else if (firstLine == lastLine) {
- if (text.length == 1) {
- update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
+ function positionLineWidget(widget, node, lineView, dims) {
+ if (widget.noHScroll) {
+ (lineView.alignable || (lineView.alignable = [])).push(node);
+ var width = dims.wrapperWidth;
+ node.style.left = dims.fixedPos + "px";
+ if (!widget.coverGutter) {
+ width -= dims.gutterTotalWidth;
+ node.style.paddingLeft = dims.gutterTotalWidth + "px";
+ }
+ node.style.width = width + "px";
+ }
+ if (widget.coverGutter) {
+ node.style.zIndex = 5;
+ node.style.position = "relative";
+ if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
+ }
+ }
+
+ function widgetHeight(widget) {
+ if (widget.height != null) { return widget.height }
+ var cm = widget.doc.cm;
+ if (!cm) { return 0 }
+ if (!contains(document.body, widget.node)) {
+ var parentStyle = "position: relative;";
+ if (widget.coverGutter)
+ { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
+ if (widget.noHScroll)
+ { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
+ removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
+ }
+ return widget.height = widget.node.parentNode.offsetHeight
+ }
+
+ // Return true when the given mouse event happened in a widget
+ function eventInWidget(display, e) {
+ for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
+ if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
+ (n.parentNode == display.sizer && n != display.mover))
+ { return true }
+ }
+ }
+
+ // POSITION MEASUREMENT
+
+ function paddingTop(display) {return display.lineSpace.offsetTop}
+ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
+ function paddingH(display) {
+ if (display.cachedPaddingH) { return display.cachedPaddingH }
+ var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
+ var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
+ if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
+ return data
+ }
+
+ function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
+ function displayWidth(cm) {
+ return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
+ }
+ function displayHeight(cm) {
+ return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
+ }
+
+ // Ensure the lineView.wrapping.heights array is populated. This is
+ // an array of bottom offsets for the lines that make up a drawn
+ // line. When lineWrapping is on, there might be more than one
+ // height.
+ function ensureLineHeights(cm, lineView, rect) {
+ var wrapping = cm.options.lineWrapping;
+ var curWidth = wrapping && displayWidth(cm);
+ if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
+ var heights = lineView.measure.heights = [];
+ if (wrapping) {
+ lineView.measure.width = curWidth;
+ var rects = lineView.text.firstChild.getClientRects();
+ for (var i = 0; i < rects.length - 1; i++) {
+ var cur = rects[i], next = rects[i + 1];
+ if (Math.abs(cur.bottom - next.bottom) > 2)
+ { heights.push((cur.bottom + next.top) / 2 - rect.top); }
+ }
+ }
+ heights.push(rect.bottom - rect.top);
+ }
+ }
+
+ // Find a line map (mapping character offsets to text nodes) and a
+ // measurement cache for the given line number. (A line view might
+ // contain multiple lines when collapsed ranges are present.)
+ function mapFromLineView(lineView, line, lineN) {
+ if (lineView.line == line)
+ { return {map: lineView.measure.map, cache: lineView.measure.cache} }
+ for (var i = 0; i < lineView.rest.length; i++)
+ { if (lineView.rest[i] == line)
+ { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
+ for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
+ { if (lineNo(lineView.rest[i$1]) > lineN)
+ { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
+ }
+
+ // Render a line into the hidden node display.externalMeasured. Used
+ // when measurement is needed for a line that's not in the viewport.
+ function updateExternalMeasurement(cm, line) {
+ line = visualLine(line);
+ var lineN = lineNo(line);
+ var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
+ view.lineN = lineN;
+ var built = view.built = buildLineContent(cm, view);
+ view.text = built.pre;
+ removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
+ return view
+ }
+
+ // Get a {top, bottom, left, right} box (in line-local coordinates)
+ // for a given character.
+ function measureChar(cm, line, ch, bias) {
+ return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
+ }
+
+ // Find a line view that corresponds to the given line number.
+ function findViewForLine(cm, lineN) {
+ if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
+ { return cm.display.view[findViewIndex(cm, lineN)] }
+ var ext = cm.display.externalMeasured;
+ if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
+ { return ext }
+ }
+
+ // Measurement can be split in two steps, the set-up work that
+ // applies to the whole line, and the measurement of the actual
+ // character. Functions like coordsChar, that need to do a lot of
+ // measurements in a row, can thus ensure that the set-up work is
+ // only done once.
+ function prepareMeasureForLine(cm, line) {
+ var lineN = lineNo(line);
+ var view = findViewForLine(cm, lineN);
+ if (view && !view.text) {
+ view = null;
+ } else if (view && view.changes) {
+ updateLineForChanges(cm, view, lineN, getDimensions(cm));
+ cm.curOp.forceUpdate = true;
+ }
+ if (!view)
+ { view = updateExternalMeasurement(cm, line); }
+
+ var info = mapFromLineView(view, line, lineN);
+ return {
+ line: line, view: view, rect: null,
+ map: info.map, cache: info.cache, before: info.before,
+ hasHeights: false
+ }
+ }
+
+ // Given a prepared measurement object, measures the position of an
+ // actual character (or fetches it from the cache).
+ function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
+ if (prepared.before) { ch = -1; }
+ var key = ch + (bias || ""), found;
+ if (prepared.cache.hasOwnProperty(key)) {
+ found = prepared.cache[key];
} else {
- var added$1 = linesFor(1, text.length - 1);
- added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
- update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
- doc.insert(from.line + 1, added$1);
- }
- } else if (text.length == 1) {
- update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
- doc.remove(from.line + 1, nlines);
- } else {
- update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
- update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
- var added$2 = linesFor(1, text.length - 1);
- if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
- doc.insert(from.line + 1, added$2);
- }
-
- signalLater(doc, "change", doc, change);
-}
-
-// Call f for all linked documents.
-function linkedDocs(doc, f, sharedHistOnly) {
- function propagate(doc, skip, sharedHist) {
- if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
- var rel = doc.linked[i];
- if (rel.doc == skip) { continue }
- var shared = sharedHist && rel.sharedHist;
- if (sharedHistOnly && !shared) { continue }
- f(rel.doc, shared);
- propagate(rel.doc, doc, shared);
+ if (!prepared.rect)
+ { prepared.rect = prepared.view.text.getBoundingClientRect(); }
+ if (!prepared.hasHeights) {
+ ensureLineHeights(cm, prepared.view, prepared.rect);
+ prepared.hasHeights = true;
+ }
+ found = measureCharInner(cm, prepared, ch, bias);
+ if (!found.bogus) { prepared.cache[key] = found; }
+ }
+ return {left: found.left, right: found.right,
+ top: varHeight ? found.rtop : found.top,
+ bottom: varHeight ? found.rbottom : found.bottom}
+ }
+
+ var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
+
+ function nodeAndOffsetInLineMap(map$$1, ch, bias) {
+ var node, start, end, collapse, mStart, mEnd;
+ // First, search the line map for the text node corresponding to,
+ // or closest to, the target character.
+ for (var i = 0; i < map$$1.length; i += 3) {
+ mStart = map$$1[i];
+ mEnd = map$$1[i + 1];
+ if (ch < mStart) {
+ start = 0; end = 1;
+ collapse = "left";
+ } else if (ch < mEnd) {
+ start = ch - mStart;
+ end = start + 1;
+ } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
+ end = mEnd - mStart;
+ start = end - 1;
+ if (ch >= mEnd) { collapse = "right"; }
+ }
+ if (start != null) {
+ node = map$$1[i + 2];
+ if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
+ { collapse = bias; }
+ if (bias == "left" && start == 0)
+ { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
+ node = map$$1[(i -= 3) + 2];
+ collapse = "left";
+ } }
+ if (bias == "right" && start == mEnd - mStart)
+ { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
+ node = map$$1[(i += 3) + 2];
+ collapse = "right";
+ } }
+ break
+ }
+ }
+ return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
+ }
+
+ function getUsefulRect(rects, bias) {
+ var rect = nullRect;
+ if (bias == "left") { for (var i = 0; i < rects.length; i++) {
+ if ((rect = rects[i]).left != rect.right) { break }
+ } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
+ if ((rect = rects[i$1]).left != rect.right) { break }
} }
+ return rect
}
- propagate(doc, null, true);
-}
-
-// Attach a document to an editor.
-function attachDoc(cm, doc) {
- if (doc.cm) { throw new Error("This document is already in use.") }
- cm.doc = doc;
- doc.cm = cm;
- estimateLineHeights(cm);
- loadMode(cm);
- setDirectionClass(cm);
- if (!cm.options.lineWrapping) { findMaxLine(cm); }
- cm.options.mode = doc.modeOption;
- regChange(cm);
-}
-
-function setDirectionClass(cm) {
- (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
-}
-function directionChanged(cm) {
- runInOp(cm, function () {
- setDirectionClass(cm);
- regChange(cm);
- });
-}
-
-function History(startGen) {
- // Arrays of change events and selections. Doing something adds an
- // event to done and clears undo. Undoing moves events from done
- // to undone, redoing moves them in the other direction.
- this.done = []; this.undone = [];
- this.undoDepth = Infinity;
- // Used to track when changes can be merged into a single undo
- // event
- this.lastModTime = this.lastSelTime = 0;
- this.lastOp = this.lastSelOp = null;
- this.lastOrigin = this.lastSelOrigin = null;
- // Used by the isClean() method
- this.generation = this.maxGeneration = startGen || 1;
-}
-
-// Create a history change event from an updateDoc-style change
-// object.
-function historyChangeFromChange(doc, change) {
- var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
- attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
- linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
- return histChange
-}
-
-// Pop all selection events off the end of a history array. Stop at
-// a change event.
-function clearSelectionEvents(array) {
- while (array.length) {
- var last = lst(array);
- if (last.ranges) { array.pop(); }
- else { break }
- }
-}
-
-// Find the top change event in the history. Pop off selection
-// events that are in the way.
-function lastChangeEvent(hist, force) {
- if (force) {
- clearSelectionEvents(hist.done);
- return lst(hist.done)
- } else if (hist.done.length && !lst(hist.done).ranges) {
- return lst(hist.done)
- } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
- hist.done.pop();
- return lst(hist.done)
- }
-}
-
-// Register a change in the history. Merges changes that are within
-// a single operation, or are close together with an origin that
-// allows merging (starting with "+") into a single event.
-function addChangeToHistory(doc, change, selAfter, opId) {
- var hist = doc.history;
- hist.undone.length = 0;
- var time = +new Date, cur;
- var last;
-
- if ((hist.lastOp == opId ||
- hist.lastOrigin == change.origin && change.origin &&
- ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
- change.origin.charAt(0) == "*")) &&
- (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
- // Merge this change into the last event
- last = lst(cur.changes);
- if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
- // Optimized case for simple insertion -- don't want to add
- // new changesets for every character typed
- last.to = changeEnd(change);
- } else {
- // Add new sub-event
- cur.changes.push(historyChangeFromChange(doc, change));
- }
- } else {
- // Can not be merged, start a new event.
- var before = lst(hist.done);
- if (!before || !before.ranges)
- { pushSelectionToHistory(doc.sel, hist.done); }
- cur = {changes: [historyChangeFromChange(doc, change)],
- generation: hist.generation};
- hist.done.push(cur);
- while (hist.done.length > hist.undoDepth) {
- hist.done.shift();
- if (!hist.done[0].ranges) { hist.done.shift(); }
- }
- }
- hist.done.push(selAfter);
- hist.generation = ++hist.maxGeneration;
- hist.lastModTime = hist.lastSelTime = time;
- hist.lastOp = hist.lastSelOp = opId;
- hist.lastOrigin = hist.lastSelOrigin = change.origin;
-
- if (!last) { signal(doc, "historyAdded"); }
-}
-
-function selectionEventCanBeMerged(doc, origin, prev, sel) {
- var ch = origin.charAt(0);
- return ch == "*" ||
- ch == "+" &&
- prev.ranges.length == sel.ranges.length &&
- prev.somethingSelected() == sel.somethingSelected() &&
- new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
-}
-
-// Called whenever the selection changes, sets the new selection as
-// the pending selection in the history, and pushes the old pending
-// selection into the 'done' array when it was significantly
-// different (in number of selected ranges, emptiness, or time).
-function addSelectionToHistory(doc, sel, opId, options) {
- var hist = doc.history, origin = options && options.origin;
-
- // A new event is started when the previous origin does not match
- // the current, or the origins don't allow matching. Origins
- // starting with * are always merged, those starting with + are
- // merged when similar and close together in time.
- if (opId == hist.lastSelOp ||
- (origin && hist.lastSelOrigin == origin &&
- (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
- selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
- { hist.done[hist.done.length - 1] = sel; }
- else
- { pushSelectionToHistory(sel, hist.done); }
-
- hist.lastSelTime = +new Date;
- hist.lastSelOrigin = origin;
- hist.lastSelOp = opId;
- if (options && options.clearRedo !== false)
- { clearSelectionEvents(hist.undone); }
-}
-
-function pushSelectionToHistory(sel, dest) {
- var top = lst(dest);
- if (!(top && top.ranges && top.equals(sel)))
- { dest.push(sel); }
-}
-
-// Used to store marked span information in the history.
-function attachLocalSpans(doc, change, from, to) {
- var existing = change["spans_" + doc.id], n = 0;
- doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
- if (line.markedSpans)
- { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
- ++n;
- });
-}
-
-// When un/re-doing restores text containing marked spans, those
-// that have been explicitly cleared should not be restored.
-function removeClearedSpans(spans) {
- if (!spans) { return null }
- var out;
- for (var i = 0; i < spans.length; ++i) {
- if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
- else if (out) { out.push(spans[i]); }
- }
- return !out ? spans : out.length ? out : null
-}
-
-// Retrieve and filter the old marked spans stored in a change event.
-function getOldSpans(doc, change) {
- var found = change["spans_" + doc.id];
- if (!found) { return null }
- var nw = [];
- for (var i = 0; i < change.text.length; ++i)
- { nw.push(removeClearedSpans(found[i])); }
- return nw
-}
-
-// Used for un/re-doing changes from the history. Combines the
-// result of computing the existing spans with the set of spans that
-// existed in the history (so that deleting around a span and then
-// undoing brings back the span).
-function mergeOldSpans(doc, change) {
- var old = getOldSpans(doc, change);
- var stretched = stretchSpansOverChange(doc, change);
- if (!old) { return stretched }
- if (!stretched) { return old }
-
- for (var i = 0; i < old.length; ++i) {
- var oldCur = old[i], stretchCur = stretched[i];
- if (oldCur && stretchCur) {
- spans: for (var j = 0; j < stretchCur.length; ++j) {
- var span = stretchCur[j];
- for (var k = 0; k < oldCur.length; ++k)
- { if (oldCur[k].marker == span.marker) { continue spans } }
- oldCur.push(span);
- }
- } else if (stretchCur) {
- old[i] = stretchCur;
- }
- }
- return old
-}
-
-// Used both to provide a JSON-safe object in .getHistory, and, when
-// detaching a document, to split the history in two
-function copyHistoryArray(events, newGroup, instantiateSel) {
- var copy = [];
- for (var i = 0; i < events.length; ++i) {
- var event = events[i];
- if (event.ranges) {
- copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
- continue
- }
- var changes = event.changes, newChanges = [];
- copy.push({changes: newChanges});
- for (var j = 0; j < changes.length; ++j) {
- var change = changes[j], m = (void 0);
- newChanges.push({from: change.from, to: change.to, text: change.text});
- if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
- if (indexOf(newGroup, Number(m[1])) > -1) {
- lst(newChanges)[prop] = change[prop];
- delete change[prop];
- }
- } } }
- }
- }
- return copy
-}
-
-// The 'scroll' parameter given to many of these indicated whether
-// the new cursor position should be scrolled into view after
-// modifying the selection.
-
-// If shift is held or the extend flag is set, extends a range to
-// include a given position (and optionally a second position).
-// Otherwise, simply returns the range between the given positions.
-// Used for cursor motion and such.
-function extendRange(range, head, other, extend) {
- if (extend) {
- var anchor = range.anchor;
- if (other) {
- var posBefore = cmp(head, anchor) < 0;
- if (posBefore != (cmp(other, anchor) < 0)) {
- anchor = head;
- head = other;
- } else if (posBefore != (cmp(head, other) < 0)) {
- head = other;
- }
- }
- return new Range(anchor, head)
- } else {
- return new Range(other || head, head)
- }
-}
-
-// Extend the primary selection range, discard the rest.
-function extendSelection(doc, head, other, options, extend) {
- if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
- setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
-}
-
-// Extend all selections (pos is an array of selections with length
-// equal the number of selections)
-function extendSelections(doc, heads, options) {
- var out = [];
- var extend = doc.cm && (doc.cm.display.shift || doc.extend);
- for (var i = 0; i < doc.sel.ranges.length; i++)
- { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
- var newSel = normalizeSelection(out, doc.sel.primIndex);
- setSelection(doc, newSel, options);
-}
-
-// Updates a single range in the selection.
-function replaceOneSelection(doc, i, range, options) {
- var ranges = doc.sel.ranges.slice(0);
- ranges[i] = range;
- setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
-}
-
-// Reset the selection to a single range.
-function setSimpleSelection(doc, anchor, head, options) {
- setSelection(doc, simpleSelection(anchor, head), options);
-}
-
-// Give beforeSelectionChange handlers a change to influence a
-// selection update.
-function filterSelectionChange(doc, sel, options) {
- var obj = {
- ranges: sel.ranges,
- update: function(ranges) {
- var this$1 = this;
+ function measureCharInner(cm, prepared, ch, bias) {
+ var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
+ var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
- this.ranges = [];
- for (var i = 0; i < ranges.length; i++)
- { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
- clipPos(doc, ranges[i].head)); }
- },
- origin: options && options.origin
- };
- signal(doc, "beforeSelectionChange", doc, obj);
- if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
- if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }
- else { return sel }
-}
-
-function setSelectionReplaceHistory(doc, sel, options) {
- var done = doc.history.done, last = lst(done);
- if (last && last.ranges) {
- done[done.length - 1] = sel;
- setSelectionNoUndo(doc, sel, options);
- } else {
- setSelection(doc, sel, options);
- }
-}
-
-// Set a new selection.
-function setSelection(doc, sel, options) {
- setSelectionNoUndo(doc, sel, options);
- addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
-}
-
-function setSelectionNoUndo(doc, sel, options) {
- if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
- { sel = filterSelectionChange(doc, sel, options); }
-
- var bias = options && options.bias ||
- (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
- setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
-
- if (!(options && options.scroll === false) && doc.cm)
- { ensureCursorVisible(doc.cm); }
-}
-
-function setSelectionInner(doc, sel) {
- if (sel.equals(doc.sel)) { return }
-
- doc.sel = sel;
-
- if (doc.cm) {
- doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
- signalCursorActivity(doc.cm);
- }
- signalLater(doc, "cursorActivity", doc);
-}
-
-// Verify that the selection does not partially select any atomic
-// marked ranges.
-function reCheckSelection(doc) {
- setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
-}
-
-// Return a selection that does not partially select any atomic
-// ranges.
-function skipAtomicInSelection(doc, sel, bias, mayClear) {
- var out;
- for (var i = 0; i < sel.ranges.length; i++) {
- var range = sel.ranges[i];
- var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
- var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
- var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
- if (out || newAnchor != range.anchor || newHead != range.head) {
- if (!out) { out = sel.ranges.slice(0, i); }
- out[i] = new Range(newAnchor, newHead);
- }
- }
- return out ? normalizeSelection(out, sel.primIndex) : sel
-}
-
-function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
- var line = getLine(doc, pos.line);
- if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
- var sp = line.markedSpans[i], m = sp.marker;
- if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
- (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
- if (mayClear) {
- signal(m, "beforeCursorEnter");
- if (m.explicitlyCleared) {
- if (!line.markedSpans) { break }
- else {--i; continue}
- }
+ var rect;
+ if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
+ for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
+ while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
+ while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
+ if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
+ { rect = node.parentNode.getBoundingClientRect(); }
+ else
+ { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
+ if (rect.left || rect.right || start == 0) { break }
+ end = start;
+ start = start - 1;
+ collapse = "right";
}
- if (!m.atomic) { continue }
-
- if (oldPos) {
- var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
- if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
- { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
- if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
- { return skipAtomicInner(doc, near, pos, dir, mayClear) }
- }
-
- var far = m.find(dir < 0 ? -1 : 1);
- if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
- { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
- return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
- }
- } }
- return pos
-}
-
-// Ensure a given position is not inside an atomic range.
-function skipAtomic(doc, pos, oldPos, bias, mayClear) {
- var dir = bias || 1;
- var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
- (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
- skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
- (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
- if (!found) {
- doc.cantEdit = true;
- return Pos(doc.first, 0)
- }
- return found
-}
-
-function movePos(doc, pos, dir, line) {
- if (dir < 0 && pos.ch == 0) {
- if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
- else { return null }
- } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
- if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
- else { return null }
- } else {
- return new Pos(pos.line, pos.ch + dir)
- }
-}
-
-function selectAll(cm) {
- cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
-}
-
-// UPDATING
-
-// Allow "beforeChange" event handlers to influence a change
-function filterChange(doc, change, update) {
- var obj = {
- canceled: false,
- from: change.from,
- to: change.to,
- text: change.text,
- origin: change.origin,
- cancel: function () { return obj.canceled = true; }
- };
- if (update) { obj.update = function (from, to, text, origin) {
- if (from) { obj.from = clipPos(doc, from); }
- if (to) { obj.to = clipPos(doc, to); }
- if (text) { obj.text = text; }
- if (origin !== undefined) { obj.origin = origin; }
- }; }
- signal(doc, "beforeChange", doc, obj);
- if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
+ if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
+ } else { // If it is a widget, simply get the box for the whole widget.
+ if (start > 0) { collapse = bias = "right"; }
+ var rects;
+ if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
+ { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
+ else
+ { rect = node.getBoundingClientRect(); }
+ }
+ if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
+ var rSpan = node.parentNode.getClientRects()[0];
+ if (rSpan)
+ { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
+ else
+ { rect = nullRect; }
+ }
+
+ var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
+ var mid = (rtop + rbot) / 2;
+ var heights = prepared.view.measure.heights;
+ var i = 0;
+ for (; i < heights.length - 1; i++)
+ { if (mid < heights[i]) { break } }
+ var top = i ? heights[i - 1] : 0, bot = heights[i];
+ var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
+ right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
+ top: top, bottom: bot};
+ if (!rect.left && !rect.right) { result.bogus = true; }
+ if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
- if (obj.canceled) { return null }
- return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
-}
+ return result
+ }
+
+ // Work around problem with bounding client rects on ranges being
+ // returned incorrectly when zoomed on IE10 and below.
+ function maybeUpdateRectForZooming(measure, rect) {
+ if (!window.screen || screen.logicalXDPI == null ||
+ screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
+ { return rect }
+ var scaleX = screen.logicalXDPI / screen.deviceXDPI;
+ var scaleY = screen.logicalYDPI / screen.deviceYDPI;
+ return {left: rect.left * scaleX, right: rect.right * scaleX,
+ top: rect.top * scaleY, bottom: rect.bottom * scaleY}
+ }
+
+ function clearLineMeasurementCacheFor(lineView) {
+ if (lineView.measure) {
+ lineView.measure.cache = {};
+ lineView.measure.heights = null;
+ if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
+ { lineView.measure.caches[i] = {}; } }
+ }
+ }
-// Apply a change to a document, and add it to the document's
-// history, and propagating it to all linked documents.
-function makeChange(doc, change, ignoreReadOnly) {
- if (doc.cm) {
- if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
- if (doc.cm.state.suppressEdits) { return }
+ function clearLineMeasurementCache(cm) {
+ cm.display.externalMeasure = null;
+ removeChildren(cm.display.lineMeasure);
+ for (var i = 0; i < cm.display.view.length; i++)
+ { clearLineMeasurementCacheFor(cm.display.view[i]); }
}
- if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
- change = filterChange(doc, change, true);
- if (!change) { return }
+ function clearCaches(cm) {
+ clearLineMeasurementCache(cm);
+ cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
+ if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
+ cm.display.lineNumChars = null;
}
- // Possibly split or suppress the update based on the presence
- // of read-only spans in its range.
- var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
- if (split) {
- for (var i = split.length - 1; i >= 0; --i)
- { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
- } else {
- makeChangeInner(doc, change);
+ function pageScrollX() {
+ // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
+ // which causes page_Offset and bounding client rects to use
+ // different reference viewports and invalidate our calculations.
+ if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
+ return window.pageXOffset || (document.documentElement || document.body).scrollLeft
+ }
+ function pageScrollY() {
+ if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
+ return window.pageYOffset || (document.documentElement || document.body).scrollTop
}
-}
-function makeChangeInner(doc, change) {
- if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
- var selAfter = computeSelAfterChange(doc, change);
- addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
+ function widgetTopHeight(lineObj) {
+ var height = 0;
+ if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
+ { height += widgetHeight(lineObj.widgets[i]); } } }
+ return height
+ }
+
+ // Converts a {top, bottom, left, right} box from line-local
+ // coordinates into another coordinate system. Context may be one of
+ // "line", "div" (display.lineDiv), "local"./null (editor), "window",
+ // or "page".
+ function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
+ if (!includeWidgets) {
+ var height = widgetTopHeight(lineObj);
+ rect.top += height; rect.bottom += height;
+ }
+ if (context == "line") { return rect }
+ if (!context) { context = "local"; }
+ var yOff = heightAtLine(lineObj);
+ if (context == "local") { yOff += paddingTop(cm.display); }
+ else { yOff -= cm.display.viewOffset; }
+ if (context == "page" || context == "window") {
+ var lOff = cm.display.lineSpace.getBoundingClientRect();
+ yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
+ var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
+ rect.left += xOff; rect.right += xOff;
+ }
+ rect.top += yOff; rect.bottom += yOff;
+ return rect
+ }
+
+ // Coverts a box from "div" coords to another coordinate system.
+ // Context may be "window", "page", "div", or "local"./null.
+ function fromCoordSystem(cm, coords, context) {
+ if (context == "div") { return coords }
+ var left = coords.left, top = coords.top;
+ // First move into "page" coordinate system
+ if (context == "page") {
+ left -= pageScrollX();
+ top -= pageScrollY();
+ } else if (context == "local" || !context) {
+ var localBox = cm.display.sizer.getBoundingClientRect();
+ left += localBox.left;
+ top += localBox.top;
+ }
+
+ var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
+ return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
+ }
+
+ function charCoords(cm, pos, context, lineObj, bias) {
+ if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
+ return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
+ }
+
+ // Returns a box for a given cursor position, which may have an
+ // 'other' property containing the position of the secondary cursor
+ // on a bidi boundary.
+ // A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
+ // and after `char - 1` in writing order of `char - 1`
+ // A cursor Pos(line, char, "after") is on the same visual line as `char`
+ // and before `char` in writing order of `char`
+ // Examples (upper-case letters are RTL, lower-case are LTR):
+ // Pos(0, 1, ...)
+ // before after
+ // ab a|b a|b
+ // aB a|B aB|
+ // Ab |Ab A|b
+ // AB B|A B|A
+ // Every position after the last character on a line is considered to stick
+ // to the last character on the line.
+ function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
+ lineObj = lineObj || getLine(cm.doc, pos.line);
+ if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
+ function get(ch, right) {
+ var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
+ if (right) { m.left = m.right; } else { m.right = m.left; }
+ return intoCoordSystem(cm, lineObj, m, context)
+ }
+ var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
+ if (ch >= lineObj.text.length) {
+ ch = lineObj.text.length;
+ sticky = "before";
+ } else if (ch <= 0) {
+ ch = 0;
+ sticky = "after";
+ }
+ if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
+
+ function getBidi(ch, partPos, invert) {
+ var part = order[partPos], right = part.level == 1;
+ return get(invert ? ch - 1 : ch, right != invert)
+ }
+ var partPos = getBidiPartAt(order, ch, sticky);
+ var other = bidiOther;
+ var val = getBidi(ch, partPos, sticky == "before");
+ if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
+ return val
+ }
+
+ // Used to cheaply estimate the coordinates for a position. Used for
+ // intermediate scroll updates.
+ function estimateCoords(cm, pos) {
+ var left = 0;
+ pos = clipPos(cm.doc, pos);
+ if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
+ var lineObj = getLine(cm.doc, pos.line);
+ var top = heightAtLine(lineObj) + paddingTop(cm.display);
+ return {left: left, right: left, top: top, bottom: top + lineObj.height}
+ }
+
+ // Positions returned by coordsChar contain some extra information.
+ // xRel is the relative x position of the input coordinates compared
+ // to the found position (so xRel > 0 means the coordinates are to
+ // the right of the character position, for example). When outside
+ // is true, that means the coordinates lie outside the line's
+ // vertical range.
+ function PosWithInfo(line, ch, sticky, outside, xRel) {
+ var pos = Pos(line, ch, sticky);
+ pos.xRel = xRel;
+ if (outside) { pos.outside = true; }
+ return pos
+ }
- makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
- var rebased = [];
+ // Compute the character position closest to the given coordinates.
+ // Input must be lineSpace-local ("div" coordinate system).
+ function coordsChar(cm, x, y) {
+ var doc = cm.doc;
+ y += cm.display.viewOffset;
+ if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
+ var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
+ if (lineN > last)
+ { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
+ if (x < 0) { x = 0; }
- linkedDocs(doc, function (doc, sharedHist) {
- if (!sharedHist && indexOf(rebased, doc.history) == -1) {
- rebaseHist(doc.history, change);
- rebased.push(doc.history);
+ var lineObj = getLine(doc, lineN);
+ for (;;) {
+ var found = coordsCharInner(cm, lineObj, lineN, x, y);
+ var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0));
+ if (!collapsed) { return found }
+ var rangeEnd = collapsed.find(1);
+ if (rangeEnd.line == lineN) { return rangeEnd }
+ lineObj = getLine(doc, lineN = rangeEnd.line);
}
- makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
- });
-}
-
-// Revert a change stored in a document's history.
-function makeChangeFromHistory(doc, type, allowSelectionOnly) {
- var suppress = doc.cm && doc.cm.state.suppressEdits;
- if (suppress && !allowSelectionOnly) { return }
-
- var hist = doc.history, event, selAfter = doc.sel;
- var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
-
- // Verify that there is a useable event (so that ctrl-z won't
- // needlessly clear selection events)
- var i = 0;
- for (; i < source.length; i++) {
- event = source[i];
- if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
- { break }
- }
- if (i == source.length) { return }
- hist.lastOrigin = hist.lastSelOrigin = null;
-
- for (;;) {
- event = source.pop();
- if (event.ranges) {
- pushSelectionToHistory(event, dest);
- if (allowSelectionOnly && !event.equals(doc.sel)) {
- setSelection(doc, event, {clearRedo: false});
- return
+ }
+
+ function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
+ y -= widgetTopHeight(lineObj);
+ var end = lineObj.text.length;
+ var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
+ end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
+ return {begin: begin, end: end}
+ }
+
+ function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
+ if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
+ var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
+ return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
+ }
+
+ // Returns true if the given side of a box is after the given
+ // coordinates, in top-to-bottom, left-to-right order.
+ function boxIsAfter(box, x, y, left) {
+ return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
+ }
+
+ function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
+ // Move y into line-local coordinate space
+ y -= heightAtLine(lineObj);
+ var preparedMeasure = prepareMeasureForLine(cm, lineObj);
+ // When directly calling `measureCharPrepared`, we have to adjust
+ // for the widgets at this line.
+ var widgetHeight$$1 = widgetTopHeight(lineObj);
+ var begin = 0, end = lineObj.text.length, ltr = true;
+
+ var order = getOrder(lineObj, cm.doc.direction);
+ // If the line isn't plain left-to-right text, first figure out
+ // which bidi section the coordinates fall into.
+ if (order) {
+ var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
+ (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
+ ltr = part.level != 1;
+ // The awkward -1 offsets are needed because findFirst (called
+ // on these below) will treat its first bound as inclusive,
+ // second as exclusive, but we want to actually address the
+ // characters in the part's range
+ begin = ltr ? part.from : part.to - 1;
+ end = ltr ? part.to : part.from - 1;
+ }
+
+ // A binary search to find the first character whose bounding box
+ // starts after the coordinates. If we run across any whose box wrap
+ // the coordinates, store that.
+ var chAround = null, boxAround = null;
+ var ch = findFirst(function (ch) {
+ var box = measureCharPrepared(cm, preparedMeasure, ch);
+ box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
+ if (!boxIsAfter(box, x, y, false)) { return false }
+ if (box.top <= y && box.left <= x) {
+ chAround = ch;
+ boxAround = box;
}
- selAfter = event;
- } else if (suppress) {
- source.push(event);
- return
- } else { break }
+ return true
+ }, begin, end);
+
+ var baseX, sticky, outside = false;
+ // If a box around the coordinates was found, use that
+ if (boxAround) {
+ // Distinguish coordinates nearer to the left or right side of the box
+ var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
+ ch = chAround + (atStart ? 0 : 1);
+ sticky = atStart ? "after" : "before";
+ baseX = atLeft ? boxAround.left : boxAround.right;
+ } else {
+ // (Adjust for extended bound, if necessary.)
+ if (!ltr && (ch == end || ch == begin)) { ch++; }
+ // To determine which side to associate with, get the box to the
+ // left of the character and compare it's vertical position to the
+ // coordinates
+ sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
+ (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
+ "after" : "before";
+ // Now get accurate coordinates for this place, in order to get a
+ // base X position
+ var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
+ baseX = coords.left;
+ outside = y < coords.top || y >= coords.bottom;
+ }
+
+ ch = skipExtendingChars(lineObj.text, ch, 1);
+ return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
+ }
+
+ function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
+ // Bidi parts are sorted left-to-right, and in a non-line-wrapping
+ // situation, we can take this ordering to correspond to the visual
+ // ordering. This finds the first part whose end is after the given
+ // coordinates.
+ var index = findFirst(function (i) {
+ var part = order[i], ltr = part.level != 1;
+ return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
+ "line", lineObj, preparedMeasure), x, y, true)
+ }, 0, order.length - 1);
+ var part = order[index];
+ // If this isn't the first part, the part's start is also after
+ // the coordinates, and the coordinates aren't on the same line as
+ // that start, move one part back.
+ if (index > 0) {
+ var ltr = part.level != 1;
+ var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
+ "line", lineObj, preparedMeasure);
+ if (boxIsAfter(start, x, y, true) && start.top > y)
+ { part = order[index - 1]; }
+ }
+ return part
+ }
+
+ function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
+ // In a wrapped line, rtl text on wrapping boundaries can do things
+ // that don't correspond to the ordering in our `order` array at
+ // all, so a binary search doesn't work, and we want to return a
+ // part that only spans one line so that the binary search in
+ // coordsCharInner is safe. As such, we first find the extent of the
+ // wrapped line, and then do a flat search in which we discard any
+ // spans that aren't on the line.
+ var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
+ var begin = ref.begin;
+ var end = ref.end;
+ if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
+ var part = null, closestDist = null;
+ for (var i = 0; i < order.length; i++) {
+ var p = order[i];
+ if (p.from >= end || p.to <= begin) { continue }
+ var ltr = p.level != 1;
+ var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
+ // Weigh against spans ending before this, so that they are only
+ // picked if nothing ends after
+ var dist = endX < x ? x - endX + 1e9 : endX - x;
+ if (!part || closestDist > dist) {
+ part = p;
+ closestDist = dist;
+ }
+ }
+ if (!part) { part = order[order.length - 1]; }
+ // Clip the part to the wrapped line.
+ if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
+ if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
+ return part
+ }
+
+ var measureText;
+ // Compute the default text height.
+ function textHeight(display) {
+ if (display.cachedTextHeight != null) { return display.cachedTextHeight }
+ if (measureText == null) {
+ measureText = elt("pre");
+ // Measure a bunch of lines, for browsers that compute
+ // fractional heights.
+ for (var i = 0; i < 49; ++i) {
+ measureText.appendChild(document.createTextNode("x"));
+ measureText.appendChild(elt("br"));
+ }
+ measureText.appendChild(document.createTextNode("x"));
+ }
+ removeChildrenAndAdd(display.measure, measureText);
+ var height = measureText.offsetHeight / 50;
+ if (height > 3) { display.cachedTextHeight = height; }
+ removeChildren(display.measure);
+ return height || 1
+ }
+
+ // Compute the default character width.
+ function charWidth(display) {
+ if (display.cachedCharWidth != null) { return display.cachedCharWidth }
+ var anchor = elt("span", "xxxxxxxxxx");
+ var pre = elt("pre", [anchor]);
+ removeChildrenAndAdd(display.measure, pre);
+ var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
+ if (width > 2) { display.cachedCharWidth = width; }
+ return width || 10
+ }
+
+ // Do a bulk-read of the DOM positions and sizes needed to draw the
+ // view, so that we don't interleave reading and writing to the DOM.
+ function getDimensions(cm) {
+ var d = cm.display, left = {}, width = {};
+ var gutterLeft = d.gutters.clientLeft;
+ for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
+ left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
+ width[cm.options.gutters[i]] = n.clientWidth;
+ }
+ return {fixedPos: compensateForHScroll(d),
+ gutterTotalWidth: d.gutters.offsetWidth,
+ gutterLeft: left,
+ gutterWidth: width,
+ wrapperWidth: d.wrapper.clientWidth}
+ }
+
+ // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
+ // but using getBoundingClientRect to get a sub-pixel-accurate
+ // result.
+ function compensateForHScroll(display) {
+ return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
+ }
+
+ // Returns a function that estimates the height of a line, to use as
+ // first approximation until the line becomes visible (and is thus
+ // properly measurable).
+ function estimateHeight(cm) {
+ var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
+ var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
+ return function (line) {
+ if (lineIsHidden(cm.doc, line)) { return 0 }
+
+ var widgetsHeight = 0;
+ if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
+ if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
+ } }
+
+ if (wrapping)
+ { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
+ else
+ { return widgetsHeight + th }
+ }
}
- // Build up a reverse change object to add to the opposite history
- // stack (redo when undoing, and vice versa).
- var antiChanges = [];
- pushSelectionToHistory(selAfter, dest);
- dest.push({changes: antiChanges, generation: hist.generation});
- hist.generation = event.generation || ++hist.maxGeneration;
+ function estimateLineHeights(cm) {
+ var doc = cm.doc, est = estimateHeight(cm);
+ doc.iter(function (line) {
+ var estHeight = est(line);
+ if (estHeight != line.height) { updateLineHeight(line, estHeight); }
+ });
+ }
- var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
+ // Given a mouse event, find the corresponding position. If liberal
+ // is false, it checks whether a gutter or scrollbar was clicked,
+ // and returns null if it was. forRect is used by rectangular
+ // selections, and tries to estimate a character position even for
+ // coordinates beyond the right of the text.
+ function posFromMouse(cm, e, liberal, forRect) {
+ var display = cm.display;
+ if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
- var loop = function ( i ) {
- var change = event.changes[i];
- change.origin = type;
- if (filter && !filterChange(doc, change, false)) {
- source.length = 0;
- return {}
+ var x, y, space = display.lineSpace.getBoundingClientRect();
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
+ try { x = e.clientX - space.left; y = e.clientY - space.top; }
+ catch (e) { return null }
+ var coords = coordsChar(cm, x, y), line;
+ if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
+ var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
}
+ return coords
+ }
- antiChanges.push(historyChangeFromChange(doc, change));
+ // Find the view element corresponding to a given line. Return null
+ // when the line isn't visible.
+ function findViewIndex(cm, n) {
+ if (n >= cm.display.viewTo) { return null }
+ n -= cm.display.viewFrom;
+ if (n < 0) { return null }
+ var view = cm.display.view;
+ for (var i = 0; i < view.length; i++) {
+ n -= view[i].size;
+ if (n < 0) { return i }
+ }
+ }
- var after = i ? computeSelAfterChange(doc, change) : lst(source);
- makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
- if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
- var rebased = [];
+ function updateSelection(cm) {
+ cm.display.input.showSelection(cm.display.input.prepareSelection());
+ }
- // Propagate to the linked documents
- linkedDocs(doc, function (doc, sharedHist) {
- if (!sharedHist && indexOf(rebased, doc.history) == -1) {
- rebaseHist(doc.history, change);
- rebased.push(doc.history);
+ function prepareSelection(cm, primary) {
+ if ( primary === void 0 ) primary = true;
+
+ var doc = cm.doc, result = {};
+ var curFragment = result.cursors = document.createDocumentFragment();
+ var selFragment = result.selection = document.createDocumentFragment();
+
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ if (!primary && i == doc.sel.primIndex) { continue }
+ var range$$1 = doc.sel.ranges[i];
+ if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
+ var collapsed = range$$1.empty();
+ if (collapsed || cm.options.showCursorWhenSelecting)
+ { drawSelectionCursor(cm, range$$1.head, curFragment); }
+ if (!collapsed)
+ { drawSelectionRange(cm, range$$1, selFragment); }
+ }
+ return result
+ }
+
+ // Draws a cursor for the given range
+ function drawSelectionCursor(cm, head, output) {
+ var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
+
+ var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
+ cursor.style.left = pos.left + "px";
+ cursor.style.top = pos.top + "px";
+ cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
+
+ if (pos.other) {
+ // Secondary cursor, shown when on a 'jump' in bi-directional text
+ var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
+ otherCursor.style.display = "";
+ otherCursor.style.left = pos.other.left + "px";
+ otherCursor.style.top = pos.other.top + "px";
+ otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
+ }
+ }
+
+ function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
+
+ // Draws the given range as a highlighted selection
+ function drawSelectionRange(cm, range$$1, output) {
+ var display = cm.display, doc = cm.doc;
+ var fragment = document.createDocumentFragment();
+ var padding = paddingH(cm.display), leftSide = padding.left;
+ var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
+ var docLTR = doc.direction == "ltr";
+
+ function add(left, top, width, bottom) {
+ if (top < 0) { top = 0; }
+ top = Math.round(top);
+ bottom = Math.round(bottom);
+ fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px")));
+ }
+
+ function drawForLine(line, fromArg, toArg) {
+ var lineObj = getLine(doc, line);
+ var lineLen = lineObj.text.length;
+ var start, end;
+ function coords(ch, bias) {
+ return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
}
- makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
- });
- };
- for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
- var returned = loop( i$1 );
-
- if ( returned ) return returned.v;
- }
-}
-
-// Sub-views need their line numbers shifted when text is added
-// above or below them in the parent document.
-function shiftDoc(doc, distance) {
- if (distance == 0) { return }
- doc.first += distance;
- doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
- Pos(range.anchor.line + distance, range.anchor.ch),
- Pos(range.head.line + distance, range.head.ch)
- ); }), doc.sel.primIndex);
- if (doc.cm) {
- regChange(doc.cm, doc.first, doc.first - distance, distance);
- for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
- { regLineChange(doc.cm, l, "gutter"); }
- }
-}
-
-// More lower-level change function, handling only a single document
-// (not linked ones).
-function makeChangeSingleDoc(doc, change, selAfter, spans) {
- if (doc.cm && !doc.cm.curOp)
- { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
-
- if (change.to.line < doc.first) {
- shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
- return
- }
- if (change.from.line > doc.lastLine()) { return }
-
- // Clip the change to the size of this doc
- if (change.from.line < doc.first) {
- var shift = change.text.length - 1 - (doc.first - change.from.line);
- shiftDoc(doc, shift);
- change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
- text: [lst(change.text)], origin: change.origin};
- }
- var last = doc.lastLine();
- if (change.to.line > last) {
- change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
- text: [change.text[0]], origin: change.origin};
- }
-
- change.removed = getBetween(doc, change.from, change.to);
-
- if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
- if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
- else { updateDoc(doc, change, spans); }
- setSelectionNoUndo(doc, selAfter, sel_dontScroll);
-}
-
-// Handle the interaction of a change to a document with the editor
-// that this document is part of.
-function makeChangeSingleDocInEditor(cm, change, spans) {
- var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
-
- var recomputeMaxLength = false, checkWidthStart = from.line;
- if (!cm.options.lineWrapping) {
- checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
- doc.iter(checkWidthStart, to.line + 1, function (line) {
- if (line == display.maxLine) {
- recomputeMaxLength = true;
- return true
+ function wrapX(pos, dir, side) {
+ var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
+ var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
+ var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
+ return coords(ch, prop)[prop]
}
- });
+
+ var order = getOrder(lineObj, doc.direction);
+ iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
+ var ltr = dir == "ltr";
+ var fromPos = coords(from, ltr ? "left" : "right");
+ var toPos = coords(to - 1, ltr ? "right" : "left");
+
+ var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
+ var first = i == 0, last = !order || i == order.length - 1;
+ if (toPos.top - fromPos.top <= 3) { // Single line
+ var openLeft = (docLTR ? openStart : openEnd) && first;
+ var openRight = (docLTR ? openEnd : openStart) && last;
+ var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
+ var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
+ add(left, fromPos.top, right - left, fromPos.bottom);
+ } else { // Multiple lines
+ var topLeft, topRight, botLeft, botRight;
+ if (ltr) {
+ topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
+ topRight = docLTR ? rightSide : wrapX(from, dir, "before");
+ botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
+ botRight = docLTR && openEnd && last ? rightSide : toPos.right;
+ } else {
+ topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
+ topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
+ botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
+ botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
+ }
+ add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
+ if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
+ add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
+ }
+
+ if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
+ if (cmpCoords(toPos, start) < 0) { start = toPos; }
+ if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
+ if (cmpCoords(toPos, end) < 0) { end = toPos; }
+ });
+ return {start: start, end: end}
+ }
+
+ var sFrom = range$$1.from(), sTo = range$$1.to();
+ if (sFrom.line == sTo.line) {
+ drawForLine(sFrom.line, sFrom.ch, sTo.ch);
+ } else {
+ var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
+ var singleVLine = visualLine(fromLine) == visualLine(toLine);
+ var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
+ var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
+ if (singleVLine) {
+ if (leftEnd.top < rightStart.top - 2) {
+ add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
+ add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
+ } else {
+ add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
+ }
+ }
+ if (leftEnd.bottom < rightStart.top)
+ { add(leftSide, leftEnd.bottom, null, rightStart.top); }
+ }
+
+ output.appendChild(fragment);
}
- if (doc.sel.contains(change.from, change.to) > -1)
- { signalCursorActivity(cm); }
+ // Cursor-blinking
+ function restartBlink(cm) {
+ if (!cm.state.focused) { return }
+ var display = cm.display;
+ clearInterval(display.blinker);
+ var on = true;
+ display.cursorDiv.style.visibility = "";
+ if (cm.options.cursorBlinkRate > 0)
+ { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
+ cm.options.cursorBlinkRate); }
+ else if (cm.options.cursorBlinkRate < 0)
+ { display.cursorDiv.style.visibility = "hidden"; }
+ }
- updateDoc(doc, change, spans, estimateHeight(cm));
+ function ensureFocus(cm) {
+ if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
+ }
- if (!cm.options.lineWrapping) {
- doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
- var len = lineLength(line);
- if (len > display.maxLineLength) {
- display.maxLine = line;
- display.maxLineLength = len;
- display.maxLineChanged = true;
- recomputeMaxLength = false;
+ function delayBlurEvent(cm) {
+ cm.state.delayingBlurEvent = true;
+ setTimeout(function () { if (cm.state.delayingBlurEvent) {
+ cm.state.delayingBlurEvent = false;
+ onBlur(cm);
+ } }, 100);
+ }
+
+ function onFocus(cm, e) {
+ if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
+
+ if (cm.options.readOnly == "nocursor") { return }
+ if (!cm.state.focused) {
+ signal(cm, "focus", cm, e);
+ cm.state.focused = true;
+ addClass(cm.display.wrapper, "CodeMirror-focused");
+ // This test prevents this from firing when a context
+ // menu is closed (since the input reset would kill the
+ // select-all detection hack)
+ if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
+ cm.display.input.reset();
+ if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
}
- });
- if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
+ cm.display.input.receivedFocus();
+ }
+ restartBlink(cm);
+ }
+ function onBlur(cm, e) {
+ if (cm.state.delayingBlurEvent) { return }
+
+ if (cm.state.focused) {
+ signal(cm, "blur", cm, e);
+ cm.state.focused = false;
+ rmClass(cm.display.wrapper, "CodeMirror-focused");
+ }
+ clearInterval(cm.display.blinker);
+ setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
+ }
+
+ // Read the actual heights of the rendered lines, and update their
+ // stored heights to match.
+ function updateHeightsInViewport(cm) {
+ var display = cm.display;
+ var prevBottom = display.lineDiv.offsetTop;
+ for (var i = 0; i < display.view.length; i++) {
+ var cur = display.view[i], wrapping = cm.options.lineWrapping;
+ var height = (void 0), width = 0;
+ if (cur.hidden) { continue }
+ if (ie && ie_version < 8) {
+ var bot = cur.node.offsetTop + cur.node.offsetHeight;
+ height = bot - prevBottom;
+ prevBottom = bot;
+ } else {
+ var box = cur.node.getBoundingClientRect();
+ height = box.bottom - box.top;
+ // Check that lines don't extend past the right of the current
+ // editor width
+ if (!wrapping && cur.text.firstChild)
+ { width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; }
+ }
+ var diff = cur.line.height - height;
+ if (height < 2) { height = textHeight(display); }
+ if (diff > .005 || diff < -.005) {
+ updateLineHeight(cur.line, height);
+ updateWidgetHeight(cur.line);
+ if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
+ { updateWidgetHeight(cur.rest[j]); } }
+ }
+ if (width > cm.display.sizerWidth) {
+ var chWidth = Math.ceil(width / charWidth(cm.display));
+ if (chWidth > cm.display.maxLineLength) {
+ cm.display.maxLineLength = chWidth;
+ cm.display.maxLine = cur.line;
+ cm.display.maxLineChanged = true;
+ }
+ }
+ }
}
- retreatFrontier(doc, from.line);
- startWorker(cm, 400);
+ // Read and store the height of line widgets associated with the
+ // given line.
+ function updateWidgetHeight(line) {
+ if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
+ var w = line.widgets[i], parent = w.node.parentNode;
+ if (parent) { w.height = parent.offsetHeight; }
+ } }
+ }
- var lendiff = change.text.length - (to.line - from.line) - 1;
- // Remember that these lines changed, for updating the display
- if (change.full)
- { regChange(cm); }
- else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
- { regLineChange(cm, from.line, "text"); }
- else
- { regChange(cm, from.line, to.line + 1, lendiff); }
+ // Compute the lines that are visible in a given viewport (defaults
+ // the the current scroll position). viewport may contain top,
+ // height, and ensure (see op.scrollToPos) properties.
+ function visibleLines(display, doc, viewport) {
+ var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
+ top = Math.floor(top - paddingTop(display));
+ var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
+
+ var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
+ // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
+ // forces those lines into the viewport (if possible).
+ if (viewport && viewport.ensure) {
+ var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
+ if (ensureFrom < from) {
+ from = ensureFrom;
+ to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
+ } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
+ from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
+ to = ensureTo;
+ }
+ }
+ return {from: from, to: Math.max(to, from + 1)}
+ }
+
+ // Re-align line numbers and gutter marks to compensate for
+ // horizontal scrolling.
+ function alignHorizontally(cm) {
+ var display = cm.display, view = display.view;
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
+ var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
+ var gutterW = display.gutters.offsetWidth, left = comp + "px";
+ for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
+ if (cm.options.fixedGutter) {
+ if (view[i].gutter)
+ { view[i].gutter.style.left = left; }
+ if (view[i].gutterBackground)
+ { view[i].gutterBackground.style.left = left; }
+ }
+ var align = view[i].alignable;
+ if (align) { for (var j = 0; j < align.length; j++)
+ { align[j].style.left = left; } }
+ } }
+ if (cm.options.fixedGutter)
+ { display.gutters.style.left = (comp + gutterW) + "px"; }
+ }
+
+ // Used to ensure that the line number gutter is still the right
+ // size for the current document size. Returns true when an update
+ // is needed.
+ function maybeUpdateLineNumberWidth(cm) {
+ if (!cm.options.lineNumbers) { return false }
+ var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
+ if (last.length != display.lineNumChars) {
+ var test = display.measure.appendChild(elt("div", [elt("div", last)],
+ "CodeMirror-linenumber CodeMirror-gutter-elt"));
+ var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
+ display.lineGutter.style.width = "";
+ display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
+ display.lineNumWidth = display.lineNumInnerWidth + padding;
+ display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
+ display.lineGutter.style.width = display.lineNumWidth + "px";
+ updateGutterSpace(cm);
+ return true
+ }
+ return false
+ }
- var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
- if (changeHandler || changesHandler) {
- var obj = {
- from: from, to: to,
- text: change.text,
- removed: change.removed,
- origin: change.origin
- };
- if (changeHandler) { signalLater(cm, "change", cm, obj); }
- if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
- }
- cm.display.selForContextMenu = null;
-}
-
-function replaceRange(doc, code, from, to, origin) {
- if (!to) { to = from; }
- if (cmp(to, from) < 0) { var assign;
- (assign = [to, from], from = assign[0], to = assign[1]); }
- if (typeof code == "string") { code = doc.splitLines(code); }
- makeChange(doc, {from: from, to: to, text: code, origin: origin});
-}
-
-// Rebasing/resetting history to deal with externally-sourced changes
-
-function rebaseHistSelSingle(pos, from, to, diff) {
- if (to < pos.line) {
- pos.line += diff;
- } else if (from < pos.line) {
- pos.line = from;
- pos.ch = 0;
- }
-}
-
-// Tries to rebase an array of history events given a change in the
-// document. If the change touches the same lines as the event, the
-// event, and everything 'behind' it, is discarded. If the change is
-// before the event, the event's positions are updated. Uses a
-// copy-on-write scheme for the positions, to avoid having to
-// reallocate them all on every rebase, but also avoid problems with
-// shared position objects being unsafely updated.
-function rebaseHistArray(array, from, to, diff) {
- for (var i = 0; i < array.length; ++i) {
- var sub = array[i], ok = true;
- if (sub.ranges) {
- if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
- for (var j = 0; j < sub.ranges.length; j++) {
- rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
- rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
- }
- continue
- }
- for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
- var cur = sub.changes[j$1];
- if (to < cur.from.line) {
- cur.from = Pos(cur.from.line + diff, cur.from.ch);
- cur.to = Pos(cur.to.line + diff, cur.to.ch);
- } else if (from <= cur.to.line) {
- ok = false;
- break
+ // SCROLLING THINGS INTO VIEW
+
+ // If an editor sits on the top or bottom of the window, partially
+ // scrolled out of view, this ensures that the cursor is visible.
+ function maybeScrollWindow(cm, rect) {
+ if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
+
+ var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
+ if (rect.top + box.top < 0) { doScroll = true; }
+ else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
+ if (doScroll != null && !phantom) {
+ var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
+ cm.display.lineSpace.appendChild(scrollNode);
+ scrollNode.scrollIntoView(doScroll);
+ cm.display.lineSpace.removeChild(scrollNode);
+ }
+ }
+
+ // Scroll a given position into view (immediately), verifying that
+ // it actually became visible (as line heights are accurately
+ // measured, the position of something may 'drift' during drawing).
+ function scrollPosIntoView(cm, pos, end, margin) {
+ if (margin == null) { margin = 0; }
+ var rect;
+ if (!cm.options.lineWrapping && pos == end) {
+ // Set pos and end to the cursor positions around the character pos sticks to
+ // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
+ // If pos == Pos(_, 0, "before"), pos and end are unchanged
+ pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
+ end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
+ }
+ for (var limit = 0; limit < 5; limit++) {
+ var changed = false;
+ var coords = cursorCoords(cm, pos);
+ var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
+ rect = {left: Math.min(coords.left, endCoords.left),
+ top: Math.min(coords.top, endCoords.top) - margin,
+ right: Math.max(coords.left, endCoords.left),
+ bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
+ var scrollPos = calculateScrollPos(cm, rect);
+ var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
+ if (scrollPos.scrollTop != null) {
+ updateScrollTop(cm, scrollPos.scrollTop);
+ if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
+ }
+ if (scrollPos.scrollLeft != null) {
+ setScrollLeft(cm, scrollPos.scrollLeft);
+ if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
}
+ if (!changed) { break }
}
- if (!ok) {
- array.splice(0, i + 1);
- i = 0;
- }
- }
-}
-
-function rebaseHist(hist, change) {
- var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
- rebaseHistArray(hist.done, from, to, diff);
- rebaseHistArray(hist.undone, from, to, diff);
-}
-
-// Utility for applying a change to a line by handle or number,
-// returning the number and optionally registering the line as
-// changed.
-function changeLine(doc, handle, changeType, op) {
- var no = handle, line = handle;
- if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
- else { no = lineNo(handle); }
- if (no == null) { return null }
- if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
- return line
-}
-
-// The document is represented as a BTree consisting of leaves, with
-// chunk of lines in them, and branches, with up to ten leaves or
-// other branch nodes below them. The top node is always a branch
-// node, and is the document object itself (meaning it has
-// additional methods and properties).
-//
-// All nodes have parent links. The tree is used both to go from
-// line numbers to line objects, and to go from objects to numbers.
-// It also indexes by height, and is used to convert between height
-// and line object, and to find the total height of the document.
-//
-// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
+ return rect
+ }
-function LeafChunk(lines) {
- var this$1 = this;
+ // Scroll a given set of coordinates into view (immediately).
+ function scrollIntoView(cm, rect) {
+ var scrollPos = calculateScrollPos(cm, rect);
+ if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
+ if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
+ }
+
+ // Calculate a new scroll position needed to scroll the given
+ // rectangle into view. Returns an object with scrollTop and
+ // scrollLeft properties. When these are undefined, the
+ // vertical/horizontal position does not need to be adjusted.
+ function calculateScrollPos(cm, rect) {
+ var display = cm.display, snapMargin = textHeight(cm.display);
+ if (rect.top < 0) { rect.top = 0; }
+ var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
+ var screen = displayHeight(cm), result = {};
+ if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
+ var docBottom = cm.doc.height + paddingVert(display);
+ var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
+ if (rect.top < screentop) {
+ result.scrollTop = atTop ? 0 : rect.top;
+ } else if (rect.bottom > screentop + screen) {
+ var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
+ if (newTop != screentop) { result.scrollTop = newTop; }
+ }
+
+ var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
+ var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
+ var tooWide = rect.right - rect.left > screenw;
+ if (tooWide) { rect.right = rect.left + screenw; }
+ if (rect.left < 10)
+ { result.scrollLeft = 0; }
+ else if (rect.left < screenleft)
+ { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
+ else if (rect.right > screenw + screenleft - 3)
+ { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
+ return result
+ }
- this.lines = lines;
- this.parent = null;
- var height = 0;
- for (var i = 0; i < lines.length; ++i) {
- lines[i].parent = this$1;
- height += lines[i].height;
+ // Store a relative adjustment to the scroll position in the current
+ // operation (to be applied when the operation finishes).
+ function addToScrollTop(cm, top) {
+ if (top == null) { return }
+ resolveScrollToPos(cm);
+ cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
}
- this.height = height;
-}
-LeafChunk.prototype = {
- chunkSize: function() { return this.lines.length },
+ // Make sure that at the end of the operation the current cursor is
+ // shown.
+ function ensureCursorVisible(cm) {
+ resolveScrollToPos(cm);
+ var cur = cm.getCursor();
+ cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
+ }
- // Remove the n lines at offset 'at'.
- removeInner: function(at, n) {
- var this$1 = this;
+ function scrollToCoords(cm, x, y) {
+ if (x != null || y != null) { resolveScrollToPos(cm); }
+ if (x != null) { cm.curOp.scrollLeft = x; }
+ if (y != null) { cm.curOp.scrollTop = y; }
+ }
+
+ function scrollToRange(cm, range$$1) {
+ resolveScrollToPos(cm);
+ cm.curOp.scrollToPos = range$$1;
+ }
- for (var i = at, e = at + n; i < e; ++i) {
- var line = this$1.lines[i];
- this$1.height -= line.height;
- cleanUpLine(line);
- signalLater(line, "delete");
+ // When an operation has its scrollToPos property set, and another
+ // scroll action is applied before the end of the operation, this
+ // 'simulates' scrolling that position into view in a cheap way, so
+ // that the effect of intermediate scroll commands is not ignored.
+ function resolveScrollToPos(cm) {
+ var range$$1 = cm.curOp.scrollToPos;
+ if (range$$1) {
+ cm.curOp.scrollToPos = null;
+ var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
+ scrollToCoordsRange(cm, from, to, range$$1.margin);
}
- this.lines.splice(at, n);
- },
+ }
- // Helper used to collapse a small branch into a single leaf.
- collapse: function(lines) {
- lines.push.apply(lines, this.lines);
- },
+ function scrollToCoordsRange(cm, from, to, margin) {
+ var sPos = calculateScrollPos(cm, {
+ left: Math.min(from.left, to.left),
+ top: Math.min(from.top, to.top) - margin,
+ right: Math.max(from.right, to.right),
+ bottom: Math.max(from.bottom, to.bottom) + margin
+ });
+ scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
+ }
+
+ // Sync the scrollable area and scrollbars, ensure the viewport
+ // covers the visible area.
+ function updateScrollTop(cm, val) {
+ if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
+ if (!gecko) { updateDisplaySimple(cm, {top: val}); }
+ setScrollTop(cm, val, true);
+ if (gecko) { updateDisplaySimple(cm); }
+ startWorker(cm, 100);
+ }
+
+ function setScrollTop(cm, val, forceScroll) {
+ val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
+ if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
+ cm.doc.scrollTop = val;
+ cm.display.scrollbars.setScrollTop(val);
+ if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
+ }
+
+ // Sync scroller and scrollbar, ensure the gutter elements are
+ // aligned.
+ function setScrollLeft(cm, val, isScroller, forceScroll) {
+ val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
+ if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
+ cm.doc.scrollLeft = val;
+ alignHorizontally(cm);
+ if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
+ cm.display.scrollbars.setScrollLeft(val);
+ }
+
+ // SCROLLBARS
+
+ // Prepare DOM reads needed to update the scrollbars. Done in one
+ // shot to minimize update/measure roundtrips.
+ function measureForScrollbars(cm) {
+ var d = cm.display, gutterW = d.gutters.offsetWidth;
+ var docH = Math.round(cm.doc.height + paddingVert(cm.display));
+ return {
+ clientHeight: d.scroller.clientHeight,
+ viewHeight: d.wrapper.clientHeight,
+ scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
+ viewWidth: d.wrapper.clientWidth,
+ barLeft: cm.options.fixedGutter ? gutterW : 0,
+ docHeight: docH,
+ scrollHeight: docH + scrollGap(cm) + d.barHeight,
+ nativeBarWidth: d.nativeBarWidth,
+ gutterWidth: gutterW
+ }
+ }
+
+ var NativeScrollbars = function(place, scroll, cm) {
+ this.cm = cm;
+ var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
+ var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
+ vert.tabIndex = horiz.tabIndex = -1;
+ place(vert); place(horiz);
+
+ on(vert, "scroll", function () {
+ if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
+ });
+ on(horiz, "scroll", function () {
+ if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
+ });
- // Insert the given array of lines at offset 'at', count them as
- // having the given height.
- insertInner: function(at, lines, height) {
- var this$1 = this;
+ this.checkedZeroWidth = false;
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+ if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
+ };
- this.height += height;
- this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
- for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
- },
+ NativeScrollbars.prototype.update = function (measure) {
+ var needsH = measure.scrollWidth > measure.clientWidth + 1;
+ var needsV = measure.scrollHeight > measure.clientHeight + 1;
+ var sWidth = measure.nativeBarWidth;
+
+ if (needsV) {
+ this.vert.style.display = "block";
+ this.vert.style.bottom = needsH ? sWidth + "px" : "0";
+ var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
+ // A bug in IE8 can cause this value to be negative, so guard it.
+ this.vert.firstChild.style.height =
+ Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
+ } else {
+ this.vert.style.display = "";
+ this.vert.firstChild.style.height = "0";
+ }
- // Used to iterate over a part of the tree.
- iterN: function(at, n, op) {
- var this$1 = this;
+ if (needsH) {
+ this.horiz.style.display = "block";
+ this.horiz.style.right = needsV ? sWidth + "px" : "0";
+ this.horiz.style.left = measure.barLeft + "px";
+ var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
+ this.horiz.firstChild.style.width =
+ Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
+ } else {
+ this.horiz.style.display = "";
+ this.horiz.firstChild.style.width = "0";
+ }
- for (var e = at + n; at < e; ++at)
- { if (op(this$1.lines[at])) { return true } }
+ if (!this.checkedZeroWidth && measure.clientHeight > 0) {
+ if (sWidth == 0) { this.zeroWidthHack(); }
+ this.checkedZeroWidth = true;
+ }
+
+ return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
+ };
+
+ NativeScrollbars.prototype.setScrollLeft = function (pos) {
+ if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
+ if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
+ };
+
+ NativeScrollbars.prototype.setScrollTop = function (pos) {
+ if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
+ if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
+ };
+
+ NativeScrollbars.prototype.zeroWidthHack = function () {
+ var w = mac && !mac_geMountainLion ? "12px" : "18px";
+ this.horiz.style.height = this.vert.style.width = w;
+ this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
+ this.disableHoriz = new Delayed;
+ this.disableVert = new Delayed;
+ };
+
+ NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
+ bar.style.pointerEvents = "auto";
+ function maybeDisable() {
+ // To find out whether the scrollbar is still visible, we
+ // check whether the element under the pixel in the bottom
+ // right corner of the scrollbar box is the scrollbar box
+ // itself (when the bar is still visible) or its filler child
+ // (when the bar is hidden). If it is still visible, we keep
+ // it enabled, if it's hidden, we disable pointer events.
+ var box = bar.getBoundingClientRect();
+ var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
+ : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
+ if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
+ else { delay.set(1000, maybeDisable); }
+ }
+ delay.set(1000, maybeDisable);
+ };
+
+ NativeScrollbars.prototype.clear = function () {
+ var parent = this.horiz.parentNode;
+ parent.removeChild(this.horiz);
+ parent.removeChild(this.vert);
+ };
+
+ var NullScrollbars = function () {};
+
+ NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
+ NullScrollbars.prototype.setScrollLeft = function () {};
+ NullScrollbars.prototype.setScrollTop = function () {};
+ NullScrollbars.prototype.clear = function () {};
+
+ function updateScrollbars(cm, measure) {
+ if (!measure) { measure = measureForScrollbars(cm); }
+ var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
+ updateScrollbarsInner(cm, measure);
+ for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
+ if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
+ { updateHeightsInViewport(cm); }
+ updateScrollbarsInner(cm, measureForScrollbars(cm));
+ startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
+ }
+ }
+
+ // Re-synchronize the fake scrollbars with the actual size of the
+ // content.
+ function updateScrollbarsInner(cm, measure) {
+ var d = cm.display;
+ var sizes = d.scrollbars.update(measure);
+
+ d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
+ d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
+ d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
+
+ if (sizes.right && sizes.bottom) {
+ d.scrollbarFiller.style.display = "block";
+ d.scrollbarFiller.style.height = sizes.bottom + "px";
+ d.scrollbarFiller.style.width = sizes.right + "px";
+ } else { d.scrollbarFiller.style.display = ""; }
+ if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
+ d.gutterFiller.style.display = "block";
+ d.gutterFiller.style.height = sizes.bottom + "px";
+ d.gutterFiller.style.width = measure.gutterWidth + "px";
+ } else { d.gutterFiller.style.display = ""; }
+ }
+
+ var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
+
+ function initScrollbars(cm) {
+ if (cm.display.scrollbars) {
+ cm.display.scrollbars.clear();
+ if (cm.display.scrollbars.addClass)
+ { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
+ }
+
+ cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
+ cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
+ // Prevent clicks in the scrollbars from killing focus
+ on(node, "mousedown", function () {
+ if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
+ });
+ node.setAttribute("cm-not-content", "true");
+ }, function (pos, axis) {
+ if (axis == "horizontal") { setScrollLeft(cm, pos); }
+ else { updateScrollTop(cm, pos); }
+ }, cm);
+ if (cm.display.scrollbars.addClass)
+ { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
+ }
+
+ // Operations are used to wrap a series of changes to the editor
+ // state in such a way that each change won't have to update the
+ // cursor and display (which would be awkward, slow, and
+ // error-prone). Instead, display updates are batched and then all
+ // combined and executed at once.
+
+ var nextOpId = 0;
+ // Start a new operation.
+ function startOperation(cm) {
+ cm.curOp = {
+ cm: cm,
+ viewChanged: false, // Flag that indicates that lines might need to be redrawn
+ startHeight: cm.doc.height, // Used to detect need to update scrollbar
+ forceUpdate: false, // Used to force a redraw
+ updateInput: 0, // Whether to reset the input textarea
+ typing: false, // Whether this reset should be careful to leave existing text (for compositing)
+ changeObjs: null, // Accumulated changes, for firing change events
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
+ cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
+ selectionChanged: false, // Whether the selection needs to be redrawn
+ updateMaxLine: false, // Set when the widest line needs to be determined anew
+ scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
+ scrollToPos: null, // Used to scroll to a specific position
+ focus: false,
+ id: ++nextOpId // Unique ID
+ };
+ pushOperation(cm.curOp);
}
-};
-function BranchChunk(children) {
- var this$1 = this;
+ // Finish an operation, updating the display and signalling delayed events
+ function endOperation(cm) {
+ var op = cm.curOp;
+ if (op) { finishOperation(op, function (group) {
+ for (var i = 0; i < group.ops.length; i++)
+ { group.ops[i].cm.curOp = null; }
+ endOperations(group);
+ }); }
+ }
- this.children = children;
- var size = 0, height = 0;
- for (var i = 0; i < children.length; ++i) {
- var ch = children[i];
- size += ch.chunkSize(); height += ch.height;
- ch.parent = this$1;
+ // The DOM updates done when an operation finishes are batched so
+ // that the minimum number of relayouts are required.
+ function endOperations(group) {
+ var ops = group.ops;
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ { endOperation_R1(ops[i]); }
+ for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
+ { endOperation_W1(ops[i$1]); }
+ for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
+ { endOperation_R2(ops[i$2]); }
+ for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
+ { endOperation_W2(ops[i$3]); }
+ for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
+ { endOperation_finish(ops[i$4]); }
}
- this.size = size;
- this.height = height;
- this.parent = null;
-}
-BranchChunk.prototype = {
- chunkSize: function() { return this.size },
+ function endOperation_R1(op) {
+ var cm = op.cm, display = cm.display;
+ maybeClipScrollbars(cm);
+ if (op.updateMaxLine) { findMaxLine(cm); }
- removeInner: function(at, n) {
- var this$1 = this;
+ op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
+ op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
+ op.scrollToPos.to.line >= display.viewTo) ||
+ display.maxLineChanged && cm.options.lineWrapping;
+ op.update = op.mustUpdate &&
+ new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
+ }
- this.size -= n;
- for (var i = 0; i < this.children.length; ++i) {
- var child = this$1.children[i], sz = child.chunkSize();
- if (at < sz) {
- var rm = Math.min(n, sz - at), oldHeight = child.height;
- child.removeInner(at, rm);
- this$1.height -= oldHeight - child.height;
- if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
- if ((n -= rm) == 0) { break }
- at = 0;
- } else { at -= sz; }
- }
- // If the result is smaller than 25 lines, ensure that it is a
- // single leaf node.
- if (this.size - n < 25 &&
- (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
- var lines = [];
- this.collapse(lines);
- this.children = [new LeafChunk(lines)];
- this.children[0].parent = this;
- }
- },
-
- collapse: function(lines) {
- var this$1 = this;
+ function endOperation_W1(op) {
+ op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
+ }
- for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
- },
+ function endOperation_R2(op) {
+ var cm = op.cm, display = cm.display;
+ if (op.updatedDisplay) { updateHeightsInViewport(cm); }
- insertInner: function(at, lines, height) {
- var this$1 = this;
+ op.barMeasure = measureForScrollbars(cm);
- this.size += lines.length;
- this.height += height;
- for (var i = 0; i < this.children.length; ++i) {
- var child = this$1.children[i], sz = child.chunkSize();
- if (at <= sz) {
- child.insertInner(at, lines, height);
- if (child.lines && child.lines.length > 50) {
- // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
- // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
- var remaining = child.lines.length % 25 + 25;
- for (var pos = remaining; pos < child.lines.length;) {
- var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
- child.height -= leaf.height;
- this$1.children.splice(++i, 0, leaf);
- leaf.parent = this$1;
- }
- child.lines = child.lines.slice(0, remaining);
- this$1.maybeSpill();
- }
- break
- }
- at -= sz;
+ // If the max line changed since it was last measured, measure it,
+ // and ensure the document's width matches it.
+ // updateDisplay_W2 will use these properties to do the actual resizing
+ if (display.maxLineChanged && !cm.options.lineWrapping) {
+ op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
+ cm.display.sizerWidth = op.adjustWidthTo;
+ op.barMeasure.scrollWidth =
+ Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
+ op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
}
- },
- // When a node has grown, check whether it should be split.
- maybeSpill: function() {
- if (this.children.length <= 10) { return }
- var me = this;
- do {
- var spilled = me.children.splice(me.children.length - 5, 5);
- var sibling = new BranchChunk(spilled);
- if (!me.parent) { // Become the parent node
- var copy = new BranchChunk(me.children);
- copy.parent = me;
- me.children = [copy, sibling];
- me = copy;
- } else {
- me.size -= sibling.size;
- me.height -= sibling.height;
- var myIndex = indexOf(me.parent.children, me);
- me.parent.children.splice(myIndex + 1, 0, sibling);
- }
- sibling.parent = me.parent;
- } while (me.children.length > 10)
- me.parent.maybeSpill();
- },
-
- iterN: function(at, n, op) {
- var this$1 = this;
+ if (op.updatedDisplay || op.selectionChanged)
+ { op.preparedSelection = display.input.prepareSelection(); }
+ }
- for (var i = 0; i < this.children.length; ++i) {
- var child = this$1.children[i], sz = child.chunkSize();
- if (at < sz) {
- var used = Math.min(n, sz - at);
- if (child.iterN(at, used, op)) { return true }
- if ((n -= used) == 0) { break }
- at = 0;
- } else { at -= sz; }
+ function endOperation_W2(op) {
+ var cm = op.cm;
+
+ if (op.adjustWidthTo != null) {
+ cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
+ if (op.maxScrollLeft < cm.doc.scrollLeft)
+ { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
+ cm.display.maxLineChanged = false;
}
+
+ var takeFocus = op.focus && op.focus == activeElt();
+ if (op.preparedSelection)
+ { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
+ if (op.updatedDisplay || op.startHeight != cm.doc.height)
+ { updateScrollbars(cm, op.barMeasure); }
+ if (op.updatedDisplay)
+ { setDocumentHeight(cm, op.barMeasure); }
+
+ if (op.selectionChanged) { restartBlink(cm); }
+
+ if (cm.state.focused && op.updateInput)
+ { cm.display.input.reset(op.typing); }
+ if (takeFocus) { ensureFocus(op.cm); }
}
-};
-// Line widgets are block elements displayed above or below a line.
+ function endOperation_finish(op) {
+ var cm = op.cm, display = cm.display, doc = cm.doc;
-var LineWidget = function(doc, node, options) {
- var this$1 = this;
+ if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
- if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
- { this$1[opt] = options[opt]; } } }
- this.doc = doc;
- this.node = node;
-};
+ // Abort mouse wheel delta measurement, when scrolling explicitly
+ if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
+ { display.wheelStartX = display.wheelStartY = null; }
-LineWidget.prototype.clear = function () {
- var this$1 = this;
+ // Propagate the scroll position to the actual DOM scroller
+ if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
- var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
- if (no == null || !ws) { return }
- for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
- if (!ws.length) { line.widgets = null; }
- var height = widgetHeight(this);
- updateLineHeight(line, Math.max(0, line.height - height));
- if (cm) {
- runInOp(cm, function () {
- adjustScrollWhenAboveVisible(cm, line, -height);
- regLineChange(cm, no, "widget");
- });
- signalLater(cm, "lineWidgetCleared", cm, this, no);
+ if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
+ // If we need to scroll a specific position into view, do so.
+ if (op.scrollToPos) {
+ var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
+ clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
+ maybeScrollWindow(cm, rect);
+ }
+
+ // Fire events for markers that are hidden/unidden by editing or
+ // undoing
+ var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
+ if (hidden) { for (var i = 0; i < hidden.length; ++i)
+ { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
+ if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
+ { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
+
+ if (display.wrapper.offsetHeight)
+ { doc.scrollTop = cm.display.scroller.scrollTop; }
+
+ // Fire change events, and delayed event handlers
+ if (op.changeObjs)
+ { signal(cm, "changes", cm, op.changeObjs); }
+ if (op.update)
+ { op.update.finish(); }
}
-};
-LineWidget.prototype.changed = function () {
- var this$1 = this;
+ // Run the given function in an operation
+ function runInOp(cm, f) {
+ if (cm.curOp) { return f() }
+ startOperation(cm);
+ try { return f() }
+ finally { endOperation(cm); }
+ }
+ // Wraps a function in an operation. Returns the wrapped function.
+ function operation(cm, f) {
+ return function() {
+ if (cm.curOp) { return f.apply(cm, arguments) }
+ startOperation(cm);
+ try { return f.apply(cm, arguments) }
+ finally { endOperation(cm); }
+ }
+ }
+ // Used to add methods to editor and doc instances, wrapping them in
+ // operations.
+ function methodOp(f) {
+ return function() {
+ if (this.curOp) { return f.apply(this, arguments) }
+ startOperation(this);
+ try { return f.apply(this, arguments) }
+ finally { endOperation(this); }
+ }
+ }
+ function docMethodOp(f) {
+ return function() {
+ var cm = this.cm;
+ if (!cm || cm.curOp) { return f.apply(this, arguments) }
+ startOperation(cm);
+ try { return f.apply(this, arguments) }
+ finally { endOperation(cm); }
+ }
+ }
+
+ // Updates the display.view data structure for a given change to the
+ // document. From and to are in pre-change coordinates. Lendiff is
+ // the amount of lines added or subtracted by the change. This is
+ // used for changes that span multiple lines, or change the way
+ // lines are divided into visual lines. regLineChange (below)
+ // registers single-line changes.
+ function regChange(cm, from, to, lendiff) {
+ if (from == null) { from = cm.doc.first; }
+ if (to == null) { to = cm.doc.first + cm.doc.size; }
+ if (!lendiff) { lendiff = 0; }
+
+ var display = cm.display;
+ if (lendiff && to < display.viewTo &&
+ (display.updateLineNumbers == null || display.updateLineNumbers > from))
+ { display.updateLineNumbers = from; }
+
+ cm.curOp.viewChanged = true;
+
+ if (from >= display.viewTo) { // Change after
+ if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
+ { resetView(cm); }
+ } else if (to <= display.viewFrom) { // Change before
+ if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
+ resetView(cm);
+ } else {
+ display.viewFrom += lendiff;
+ display.viewTo += lendiff;
+ }
+ } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
+ resetView(cm);
+ } else if (from <= display.viewFrom) { // Top overlap
+ var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
+ if (cut) {
+ display.view = display.view.slice(cut.index);
+ display.viewFrom = cut.lineN;
+ display.viewTo += lendiff;
+ } else {
+ resetView(cm);
+ }
+ } else if (to >= display.viewTo) { // Bottom overlap
+ var cut$1 = viewCuttingPoint(cm, from, from, -1);
+ if (cut$1) {
+ display.view = display.view.slice(0, cut$1.index);
+ display.viewTo = cut$1.lineN;
+ } else {
+ resetView(cm);
+ }
+ } else { // Gap in the middle
+ var cutTop = viewCuttingPoint(cm, from, from, -1);
+ var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
+ if (cutTop && cutBot) {
+ display.view = display.view.slice(0, cutTop.index)
+ .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
+ .concat(display.view.slice(cutBot.index));
+ display.viewTo += lendiff;
+ } else {
+ resetView(cm);
+ }
+ }
- var oldH = this.height, cm = this.doc.cm, line = this.line;
- this.height = null;
- var diff = widgetHeight(this) - oldH;
- if (!diff) { return }
- if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }
- if (cm) {
- runInOp(cm, function () {
- cm.curOp.forceUpdate = true;
- adjustScrollWhenAboveVisible(cm, line, diff);
- signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
- });
+ var ext = display.externalMeasured;
+ if (ext) {
+ if (to < ext.lineN)
+ { ext.lineN += lendiff; }
+ else if (from < ext.lineN + ext.size)
+ { display.externalMeasured = null; }
+ }
}
-};
-eventMixin(LineWidget);
-
-function adjustScrollWhenAboveVisible(cm, line, diff) {
- if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
- { addToScrollTop(cm, diff); }
-}
-
-function addLineWidget(doc, handle, node, options) {
- var widget = new LineWidget(doc, node, options);
- var cm = doc.cm;
- if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
- changeLine(doc, handle, "widget", function (line) {
- var widgets = line.widgets || (line.widgets = []);
- if (widget.insertAt == null) { widgets.push(widget); }
- else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
- widget.line = line;
- if (cm && !lineIsHidden(doc, line)) {
- var aboveVisible = heightAtLine(line) < doc.scrollTop;
- updateLineHeight(line, line.height + widgetHeight(widget));
- if (aboveVisible) { addToScrollTop(cm, widget.height); }
- cm.curOp.forceUpdate = true;
+
+ // Register a change to a single line. Type must be one of "text",
+ // "gutter", "class", "widget"
+ function regLineChange(cm, line, type) {
+ cm.curOp.viewChanged = true;
+ var display = cm.display, ext = cm.display.externalMeasured;
+ if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
+ { display.externalMeasured = null; }
+
+ if (line < display.viewFrom || line >= display.viewTo) { return }
+ var lineView = display.view[findViewIndex(cm, line)];
+ if (lineView.node == null) { return }
+ var arr = lineView.changes || (lineView.changes = []);
+ if (indexOf(arr, type) == -1) { arr.push(type); }
+ }
+
+ // Clear the view.
+ function resetView(cm) {
+ cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
+ cm.display.view = [];
+ cm.display.viewOffset = 0;
+ }
+
+ function viewCuttingPoint(cm, oldN, newN, dir) {
+ var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
+ if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
+ { return {index: index, lineN: newN} }
+ var n = cm.display.viewFrom;
+ for (var i = 0; i < index; i++)
+ { n += view[i].size; }
+ if (n != oldN) {
+ if (dir > 0) {
+ if (index == view.length - 1) { return null }
+ diff = (n + view[index].size) - oldN;
+ index++;
+ } else {
+ diff = n - oldN;
+ }
+ oldN += diff; newN += diff;
}
- return true
- });
- if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); }
- return widget
-}
-
-// TEXTMARKERS
-
-// Created with markText and setBookmark methods. A TextMarker is a
-// handle that can be used to clear or find a marked position in the
-// document. Line objects hold arrays (markedSpans) containing
-// {from, to, marker} object pointing to such marker objects, and
-// indicating that such a marker is present on that line. Multiple
-// lines may point to the same marker when it spans across lines.
-// The spans will have null for their from/to properties when the
-// marker continues beyond the start/end of the line. Markers have
-// links back to the lines they currently touch.
-
-// Collapsed markers have unique ids, in order to be able to order
-// them, which is needed for uniquely determining an outer marker
-// when they overlap (they may nest, but not partially overlap).
-var nextMarkerId = 0;
-
-var TextMarker = function(doc, type) {
- this.lines = [];
- this.type = type;
- this.doc = doc;
- this.id = ++nextMarkerId;
-};
-
-// Clear the marker.
-TextMarker.prototype.clear = function () {
- var this$1 = this;
+ while (visualLineNo(cm.doc, newN) != newN) {
+ if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
+ newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
+ index += dir;
+ }
+ return {index: index, lineN: newN}
+ }
- if (this.explicitlyCleared) { return }
- var cm = this.doc.cm, withOp = cm && !cm.curOp;
- if (withOp) { startOperation(cm); }
- if (hasHandler(this, "clear")) {
- var found = this.find();
- if (found) { signalLater(this, "clear", found.from, found.to); }
- }
- var min = null, max = null;
- for (var i = 0; i < this.lines.length; ++i) {
- var line = this$1.lines[i];
- var span = getMarkedSpanFor(line.markedSpans, this$1);
- if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
- else if (cm) {
- if (span.to != null) { max = lineNo(line); }
- if (span.from != null) { min = lineNo(line); }
- }
- line.markedSpans = removeMarkedSpan(line.markedSpans, span);
- if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
- { updateLineHeight(line, textHeight(cm.display)); }
- }
- if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
- var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
- if (len > cm.display.maxLineLength) {
- cm.display.maxLine = visual;
- cm.display.maxLineLength = len;
- cm.display.maxLineChanged = true;
- }
- } }
-
- if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
- this.lines.length = 0;
- this.explicitlyCleared = true;
- if (this.atomic && this.doc.cantEdit) {
- this.doc.cantEdit = false;
- if (cm) { reCheckSelection(cm.doc); }
- }
- if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
- if (withOp) { endOperation(cm); }
- if (this.parent) { this.parent.clear(); }
-};
-
-// Find the position of the marker in the document. Returns a {from,
-// to} object by default. Side can be passed to get a specific side
-// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
-// Pos objects returned contain a line object, rather than a line
-// number (used to prevent looking up the same line twice).
-TextMarker.prototype.find = function (side, lineObj) {
- var this$1 = this;
+ // Force the view to cover a given range, adding empty view element
+ // or clipping off existing ones as needed.
+ function adjustView(cm, from, to) {
+ var display = cm.display, view = display.view;
+ if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
+ display.view = buildViewArray(cm, from, to);
+ display.viewFrom = from;
+ } else {
+ if (display.viewFrom > from)
+ { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
+ else if (display.viewFrom < from)
+ { display.view = display.view.slice(findViewIndex(cm, from)); }
+ display.viewFrom = from;
+ if (display.viewTo < to)
+ { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
+ else if (display.viewTo > to)
+ { display.view = display.view.slice(0, findViewIndex(cm, to)); }
+ }
+ display.viewTo = to;
+ }
+
+ // Count the number of lines in the view whose DOM representation is
+ // out of date (or nonexistent).
+ function countDirtyView(cm) {
+ var view = cm.display.view, dirty = 0;
+ for (var i = 0; i < view.length; i++) {
+ var lineView = view[i];
+ if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
+ }
+ return dirty
+ }
+
+ // HIGHLIGHT WORKER
+
+ function startWorker(cm, time) {
+ if (cm.doc.highlightFrontier < cm.display.viewTo)
+ { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
+ }
+
+ function highlightWorker(cm) {
+ var doc = cm.doc;
+ if (doc.highlightFrontier >= cm.display.viewTo) { return }
+ var end = +new Date + cm.options.workTime;
+ var context = getContextBefore(cm, doc.highlightFrontier);
+ var changedLines = [];
+
+ doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
+ if (context.line >= cm.display.viewFrom) { // Visible
+ var oldStyles = line.styles;
+ var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
+ var highlighted = highlightLine(cm, line, context, true);
+ if (resetState) { context.state = resetState; }
+ line.styles = highlighted.styles;
+ var oldCls = line.styleClasses, newCls = highlighted.classes;
+ if (newCls) { line.styleClasses = newCls; }
+ else if (oldCls) { line.styleClasses = null; }
+ var ischange = !oldStyles || oldStyles.length != line.styles.length ||
+ oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
+ for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
+ if (ischange) { changedLines.push(context.line); }
+ line.stateAfter = context.save();
+ context.nextLine();
+ } else {
+ if (line.text.length <= cm.options.maxHighlightLength)
+ { processLine(cm, line.text, context); }
+ line.stateAfter = context.line % 5 == 0 ? context.save() : null;
+ context.nextLine();
+ }
+ if (+new Date > end) {
+ startWorker(cm, cm.options.workDelay);
+ return true
+ }
+ });
+ doc.highlightFrontier = context.line;
+ doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
+ if (changedLines.length) { runInOp(cm, function () {
+ for (var i = 0; i < changedLines.length; i++)
+ { regLineChange(cm, changedLines[i], "text"); }
+ }); }
+ }
+
+ // DISPLAY DRAWING
+
+ var DisplayUpdate = function(cm, viewport, force) {
+ var display = cm.display;
+
+ this.viewport = viewport;
+ // Store some values that we'll need later (but don't want to force a relayout for)
+ this.visible = visibleLines(display, cm.doc, viewport);
+ this.editorIsHidden = !display.wrapper.offsetWidth;
+ this.wrapperHeight = display.wrapper.clientHeight;
+ this.wrapperWidth = display.wrapper.clientWidth;
+ this.oldDisplayWidth = displayWidth(cm);
+ this.force = force;
+ this.dims = getDimensions(cm);
+ this.events = [];
+ };
+
+ DisplayUpdate.prototype.signal = function (emitter, type) {
+ if (hasHandler(emitter, type))
+ { this.events.push(arguments); }
+ };
+ DisplayUpdate.prototype.finish = function () {
+ for (var i = 0; i < this.events.length; i++)
+ { signal.apply(null, this.events[i]); }
+ };
+
+ function maybeClipScrollbars(cm) {
+ var display = cm.display;
+ if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
+ display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
+ display.heightForcer.style.height = scrollGap(cm) + "px";
+ display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
+ display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
+ display.scrollbarsClipped = true;
+ }
+ }
+
+ function selectionSnapshot(cm) {
+ if (cm.hasFocus()) { return null }
+ var active = activeElt();
+ if (!active || !contains(cm.display.lineDiv, active)) { return null }
+ var result = {activeElt: active};
+ if (window.getSelection) {
+ var sel = window.getSelection();
+ if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
+ result.anchorNode = sel.anchorNode;
+ result.anchorOffset = sel.anchorOffset;
+ result.focusNode = sel.focusNode;
+ result.focusOffset = sel.focusOffset;
+ }
+ }
+ return result
+ }
- if (side == null && this.type == "bookmark") { side = 1; }
- var from, to;
- for (var i = 0; i < this.lines.length; ++i) {
- var line = this$1.lines[i];
- var span = getMarkedSpanFor(line.markedSpans, this$1);
- if (span.from != null) {
- from = Pos(lineObj ? line : lineNo(line), span.from);
- if (side == -1) { return from }
+ function restoreSelection(snapshot) {
+ if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
+ snapshot.activeElt.focus();
+ if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
+ var sel = window.getSelection(), range$$1 = document.createRange();
+ range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
+ range$$1.collapse(false);
+ sel.removeAllRanges();
+ sel.addRange(range$$1);
+ sel.extend(snapshot.focusNode, snapshot.focusOffset);
}
- if (span.to != null) {
- to = Pos(lineObj ? line : lineNo(line), span.to);
- if (side == 1) { return to }
+ }
+
+ // Does the actual updating of the line display. Bails out
+ // (returning false) when there is nothing to be done and forced is
+ // false.
+ function updateDisplayIfNeeded(cm, update) {
+ var display = cm.display, doc = cm.doc;
+
+ if (update.editorIsHidden) {
+ resetView(cm);
+ return false
}
+
+ // Bail out if the visible area is already rendered and nothing changed.
+ if (!update.force &&
+ update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
+ display.renderedView == display.view && countDirtyView(cm) == 0)
+ { return false }
+
+ if (maybeUpdateLineNumberWidth(cm)) {
+ resetView(cm);
+ update.dims = getDimensions(cm);
+ }
+
+ // Compute a suitable new viewport (from & to)
+ var end = doc.first + doc.size;
+ var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
+ var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
+ if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
+ if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
+ if (sawCollapsedSpans) {
+ from = visualLineNo(cm.doc, from);
+ to = visualLineEndNo(cm.doc, to);
+ }
+
+ var different = from != display.viewFrom || to != display.viewTo ||
+ display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
+ adjustView(cm, from, to);
+
+ display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
+ // Position the mover div to align with the current scroll position
+ cm.display.mover.style.top = display.viewOffset + "px";
+
+ var toUpdate = countDirtyView(cm);
+ if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
+ { return false }
+
+ // For big changes, we hide the enclosing element during the
+ // update, since that speeds up the operations on most browsers.
+ var selSnapshot = selectionSnapshot(cm);
+ if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
+ patchDisplay(cm, display.updateLineNumbers, update.dims);
+ if (toUpdate > 4) { display.lineDiv.style.display = ""; }
+ display.renderedView = display.view;
+ // There might have been a widget with a focused element that got
+ // hidden or updated, if so re-focus it.
+ restoreSelection(selSnapshot);
+
+ // Prevent selection and cursors from interfering with the scroll
+ // width and height.
+ removeChildren(display.cursorDiv);
+ removeChildren(display.selectionDiv);
+ display.gutters.style.height = display.sizer.style.minHeight = 0;
+
+ if (different) {
+ display.lastWrapHeight = update.wrapperHeight;
+ display.lastWrapWidth = update.wrapperWidth;
+ startWorker(cm, 400);
+ }
+
+ display.updateLineNumbers = null;
+
+ return true
}
- return from && {from: from, to: to}
-};
-// Signals that the marker's widget changed, and surrounding layout
-// should be recomputed.
-TextMarker.prototype.changed = function () {
- var this$1 = this;
+ function postUpdateDisplay(cm, update) {
+ var viewport = update.viewport;
- var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
- if (!pos || !cm) { return }
- runInOp(cm, function () {
- var line = pos.line, lineN = lineNo(pos.line);
- var view = findViewForLine(cm, lineN);
- if (view) {
- clearLineMeasurementCacheFor(view);
- cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
- }
- cm.curOp.updateMaxLine = true;
- if (!lineIsHidden(widget.doc, line) && widget.height != null) {
- var oldHeight = widget.height;
- widget.height = null;
- var dHeight = widgetHeight(widget) - oldHeight;
- if (dHeight)
- { updateLineHeight(line, line.height + dHeight); }
- }
- signalLater(cm, "markerChanged", cm, this$1);
- });
-};
-
-TextMarker.prototype.attachLine = function (line) {
- if (!this.lines.length && this.doc.cm) {
- var op = this.doc.cm.curOp;
- if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
- { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
- }
- this.lines.push(line);
-};
-
-TextMarker.prototype.detachLine = function (line) {
- this.lines.splice(indexOf(this.lines, line), 1);
- if (!this.lines.length && this.doc.cm) {
- var op = this.doc.cm.curOp;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
- }
-};
-eventMixin(TextMarker);
-
-// Create a marker, wire it up to the right lines, and
-function markText(doc, from, to, options, type) {
- // Shared markers (across linked documents) are handled separately
- // (markTextShared will call out to this again, once per
- // document).
- if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
- // Ensure we are in an operation.
- if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
-
- var marker = new TextMarker(doc, type), diff = cmp(from, to);
- if (options) { copyObj(options, marker, false); }
- // Don't connect empty markers unless clearWhenEmpty is false
- if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
- { return marker }
- if (marker.replacedWith) {
- // Showing up as a widget implies collapsed (widget replaces text)
- marker.collapsed = true;
- marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
- if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
- if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
- }
- if (marker.collapsed) {
- if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
- from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
- { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
- seeCollapsedSpans();
- }
-
- if (marker.addToHistory)
- { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
-
- var curLine = from.line, cm = doc.cm, updateMaxLine;
- doc.iter(curLine, to.line + 1, function (line) {
- if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
- { updateMaxLine = true; }
- if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
- addMarkedSpan(line, new MarkedSpan(marker,
- curLine == from.line ? from.ch : null,
- curLine == to.line ? to.ch : null));
- ++curLine;
- });
- // lineIsHidden depends on the presence of the spans, so needs a second pass
- if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
- if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
- }); }
-
- if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
-
- if (marker.readOnly) {
- seeReadOnlySpans();
- if (doc.history.done.length || doc.history.undone.length)
- { doc.clearHistory(); }
- }
- if (marker.collapsed) {
- marker.id = ++nextMarkerId;
- marker.atomic = true;
- }
- if (cm) {
- // Sync editor state
- if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
- if (marker.collapsed)
- { regChange(cm, from.line, to.line + 1); }
- else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
- { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
- if (marker.atomic) { reCheckSelection(cm.doc); }
- signalLater(cm, "markerAdded", cm, marker);
- }
- return marker
-}
-
-// SHARED TEXTMARKERS
-
-// A shared marker spans multiple linked documents. It is
-// implemented as a meta-marker-object controlling multiple normal
-// markers.
-var SharedTextMarker = function(markers, primary) {
- var this$1 = this;
-
- this.markers = markers;
- this.primary = primary;
- for (var i = 0; i < markers.length; ++i)
- { markers[i].parent = this$1; }
-};
-
-SharedTextMarker.prototype.clear = function () {
- var this$1 = this;
+ for (var first = true;; first = false) {
+ if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
+ // Clip forced viewport to actual scrollable area.
+ if (viewport && viewport.top != null)
+ { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
+ // Updated line heights might result in the drawn area not
+ // actually covering the viewport. Keep looping until it does.
+ update.visible = visibleLines(cm.display, cm.doc, viewport);
+ if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
+ { break }
+ }
+ if (!updateDisplayIfNeeded(cm, update)) { break }
+ updateHeightsInViewport(cm);
+ var barMeasure = measureForScrollbars(cm);
+ updateSelection(cm);
+ updateScrollbars(cm, barMeasure);
+ setDocumentHeight(cm, barMeasure);
+ update.force = false;
+ }
+
+ update.signal(cm, "update", cm);
+ if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
+ update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
+ cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
+ }
+ }
+
+ function updateDisplaySimple(cm, viewport) {
+ var update = new DisplayUpdate(cm, viewport);
+ if (updateDisplayIfNeeded(cm, update)) {
+ updateHeightsInViewport(cm);
+ postUpdateDisplay(cm, update);
+ var barMeasure = measureForScrollbars(cm);
+ updateSelection(cm);
+ updateScrollbars(cm, barMeasure);
+ setDocumentHeight(cm, barMeasure);
+ update.finish();
+ }
+ }
+
+ // Sync the actual display DOM structure with display.view, removing
+ // nodes for lines that are no longer in view, and creating the ones
+ // that are not there yet, and updating the ones that are out of
+ // date.
+ function patchDisplay(cm, updateNumbersFrom, dims) {
+ var display = cm.display, lineNumbers = cm.options.lineNumbers;
+ var container = display.lineDiv, cur = container.firstChild;
+
+ function rm(node) {
+ var next = node.nextSibling;
+ // Works around a throw-scroll bug in OS X Webkit
+ if (webkit && mac && cm.display.currentWheelTarget == node)
+ { node.style.display = "none"; }
+ else
+ { node.parentNode.removeChild(node); }
+ return next
+ }
+
+ var view = display.view, lineN = display.viewFrom;
+ // Loop over the elements in the view, syncing cur (the DOM nodes
+ // in display.lineDiv) with the view as we go.
+ for (var i = 0; i < view.length; i++) {
+ var lineView = view[i];
+ if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
+ var node = buildLineElement(cm, lineView, lineN, dims);
+ container.insertBefore(node, cur);
+ } else { // Already drawn
+ while (cur != lineView.node) { cur = rm(cur); }
+ var updateNumber = lineNumbers && updateNumbersFrom != null &&
+ updateNumbersFrom <= lineN && lineView.lineNumber;
+ if (lineView.changes) {
+ if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
+ updateLineForChanges(cm, lineView, lineN, dims);
+ }
+ if (updateNumber) {
+ removeChildren(lineView.lineNumber);
+ lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
+ }
+ cur = lineView.node.nextSibling;
+ }
+ lineN += lineView.size;
+ }
+ while (cur) { cur = rm(cur); }
+ }
- if (this.explicitlyCleared) { return }
- this.explicitlyCleared = true;
- for (var i = 0; i < this.markers.length; ++i)
- { this$1.markers[i].clear(); }
- signalLater(this, "clear");
-};
-
-SharedTextMarker.prototype.find = function (side, lineObj) {
- return this.primary.find(side, lineObj)
-};
-eventMixin(SharedTextMarker);
-
-function markTextShared(doc, from, to, options, type) {
- options = copyObj(options);
- options.shared = false;
- var markers = [markText(doc, from, to, options, type)], primary = markers[0];
- var widget = options.widgetNode;
- linkedDocs(doc, function (doc) {
- if (widget) { options.widgetNode = widget.cloneNode(true); }
- markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
- for (var i = 0; i < doc.linked.length; ++i)
- { if (doc.linked[i].isParent) { return } }
- primary = lst(markers);
- });
- return new SharedTextMarker(markers, primary)
-}
+ function updateGutterSpace(cm) {
+ var width = cm.display.gutters.offsetWidth;
+ cm.display.sizer.style.marginLeft = width + "px";
+ }
-function findSharedMarkers(doc) {
- return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
-}
+ function setDocumentHeight(cm, measure) {
+ cm.display.sizer.style.minHeight = measure.docHeight + "px";
+ cm.display.heightForcer.style.top = measure.docHeight + "px";
+ cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
+ }
-function copySharedMarkers(doc, markers) {
- for (var i = 0; i < markers.length; i++) {
- var marker = markers[i], pos = marker.find();
- var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
- if (cmp(mFrom, mTo)) {
- var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
- marker.markers.push(subMark);
- subMark.parent = marker;
+ // Rebuild the gutter elements, ensure the margin to the left of the
+ // code matches their width.
+ function updateGutters(cm) {
+ var gutters = cm.display.gutters, specs = cm.options.gutters;
+ removeChildren(gutters);
+ var i = 0;
+ for (; i < specs.length; ++i) {
+ var gutterClass = specs[i];
+ var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
+ if (gutterClass == "CodeMirror-linenumbers") {
+ cm.display.lineGutter = gElt;
+ gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
+ }
}
+ gutters.style.display = i ? "" : "none";
+ updateGutterSpace(cm);
}
-}
-function detachSharedMarkers(markers) {
- var loop = function ( i ) {
- var marker = markers[i], linked = [marker.primary.doc];
- linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
- for (var j = 0; j < marker.markers.length; j++) {
- var subMarker = marker.markers[j];
- if (indexOf(linked, subMarker.doc) == -1) {
- subMarker.parent = null;
- marker.markers.splice(j--, 1);
+ // Make sure the gutters options contains the element
+ // "CodeMirror-linenumbers" when the lineNumbers option is true.
+ function setGuttersForLineNumbers(options) {
+ var found = indexOf(options.gutters, "CodeMirror-linenumbers");
+ if (found == -1 && options.lineNumbers) {
+ options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
+ } else if (found > -1 && !options.lineNumbers) {
+ options.gutters = options.gutters.slice(0);
+ options.gutters.splice(found, 1);
+ }
+ }
+
+ // Since the delta values reported on mouse wheel events are
+ // unstandardized between browsers and even browser versions, and
+ // generally horribly unpredictable, this code starts by measuring
+ // the scroll effect that the first few mouse wheel events have,
+ // and, from that, detects the way it can convert deltas to pixel
+ // offsets afterwards.
+ //
+ // The reason we want to know the amount a wheel event will scroll
+ // is that it gives us a chance to update the display before the
+ // actual scrolling happens, reducing flickering.
+
+ var wheelSamples = 0, wheelPixelsPerUnit = null;
+ // Fill in a browser-detected starting value on browsers where we
+ // know one. These don't have to be accurate -- the result of them
+ // being wrong would just be a slight flicker on the first wheel
+ // scroll (if it is large enough).
+ if (ie) { wheelPixelsPerUnit = -.53; }
+ else if (gecko) { wheelPixelsPerUnit = 15; }
+ else if (chrome) { wheelPixelsPerUnit = -.7; }
+ else if (safari) { wheelPixelsPerUnit = -1/3; }
+
+ function wheelEventDelta(e) {
+ var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
+ if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
+ if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
+ else if (dy == null) { dy = e.wheelDelta; }
+ return {x: dx, y: dy}
+ }
+ function wheelEventPixels(e) {
+ var delta = wheelEventDelta(e);
+ delta.x *= wheelPixelsPerUnit;
+ delta.y *= wheelPixelsPerUnit;
+ return delta
+ }
+
+ function onScrollWheel(cm, e) {
+ var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
+
+ var display = cm.display, scroll = display.scroller;
+ // Quit if there's nothing to scroll here
+ var canScrollX = scroll.scrollWidth > scroll.clientWidth;
+ var canScrollY = scroll.scrollHeight > scroll.clientHeight;
+ if (!(dx && canScrollX || dy && canScrollY)) { return }
+
+ // Webkit browsers on OS X abort momentum scrolls when the target
+ // of the scroll event is removed from the scrollable element.
+ // This hack (see related code in patchDisplay) makes sure the
+ // element is kept around.
+ if (dy && mac && webkit) {
+ outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
+ for (var i = 0; i < view.length; i++) {
+ if (view[i].node == cur) {
+ cm.display.currentWheelTarget = cur;
+ break outer
+ }
+ }
+ }
+ }
+
+ // On some browsers, horizontal scrolling will cause redraws to
+ // happen before the gutter has been realigned, causing it to
+ // wriggle around in a most unseemly way. When we have an
+ // estimated pixels/delta value, we just handle horizontal
+ // scrolling entirely here. It'll be slightly off from native, but
+ // better than glitching out.
+ if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
+ if (dy && canScrollY)
+ { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
+ setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
+ // Only prevent default scrolling if vertical scrolling is
+ // actually possible. Otherwise, it causes vertical scroll
+ // jitter on OSX trackpads when deltaX is small and deltaY
+ // is large (issue #3579)
+ if (!dy || (dy && canScrollY))
+ { e_preventDefault(e); }
+ display.wheelStartX = null; // Abort measurement, if in progress
+ return
+ }
+
+ // 'Project' the visible viewport to cover the area that is being
+ // scrolled into view (if we know enough to estimate it).
+ if (dy && wheelPixelsPerUnit != null) {
+ var pixels = dy * wheelPixelsPerUnit;
+ var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
+ if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
+ else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
+ updateDisplaySimple(cm, {top: top, bottom: bot});
+ }
+
+ if (wheelSamples < 20) {
+ if (display.wheelStartX == null) {
+ display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
+ display.wheelDX = dx; display.wheelDY = dy;
+ setTimeout(function () {
+ if (display.wheelStartX == null) { return }
+ var movedX = scroll.scrollLeft - display.wheelStartX;
+ var movedY = scroll.scrollTop - display.wheelStartY;
+ var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
+ (movedX && display.wheelDX && movedX / display.wheelDX);
+ display.wheelStartX = display.wheelStartY = null;
+ if (!sample) { return }
+ wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
+ ++wheelSamples;
+ }, 200);
+ } else {
+ display.wheelDX += dx; display.wheelDY += dy;
}
}
+ }
+
+ // Selection objects are immutable. A new one is created every time
+ // the selection changes. A selection is one or more non-overlapping
+ // (and non-touching) ranges, sorted, and an integer that indicates
+ // which one is the primary selection (the one that's scrolled into
+ // view, that getCursor returns, etc).
+ var Selection = function(ranges, primIndex) {
+ this.ranges = ranges;
+ this.primIndex = primIndex;
};
- for (var i = 0; i < markers.length; i++) loop( i );
-}
-
-var nextDocId = 0;
-var Doc = function(text, mode, firstLine, lineSep, direction) {
- if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
- if (firstLine == null) { firstLine = 0; }
-
- BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
- this.first = firstLine;
- this.scrollTop = this.scrollLeft = 0;
- this.cantEdit = false;
- this.cleanGeneration = 1;
- this.modeFrontier = this.highlightFrontier = firstLine;
- var start = Pos(firstLine, 0);
- this.sel = simpleSelection(start);
- this.history = new History(null);
- this.id = ++nextDocId;
- this.modeOption = mode;
- this.lineSep = lineSep;
- this.direction = (direction == "rtl") ? "rtl" : "ltr";
- this.extend = false;
-
- if (typeof text == "string") { text = this.splitLines(text); }
- updateDoc(this, {from: start, to: start, text: text});
- setSelection(this, simpleSelection(start), sel_dontScroll);
-};
-
-Doc.prototype = createObj(BranchChunk.prototype, {
- constructor: Doc,
- // Iterate over the document. Supports two forms -- with only one
- // argument, it calls that for each line in the document. With
- // three, it iterates over the range given by the first two (with
- // the second being non-inclusive).
- iter: function(from, to, op) {
- if (op) { this.iterN(from - this.first, to - from, op); }
- else { this.iterN(this.first, this.first + this.size, from); }
- },
-
- // Non-public interface for adding and removing lines.
- insert: function(at, lines) {
- var height = 0;
- for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
- this.insertInner(at - this.first, lines, height);
- },
- remove: function(at, n) { this.removeInner(at - this.first, n); },
-
- // From here, the methods are part of the public interface. Most
- // are also available from CodeMirror (editor) instances.
-
- getValue: function(lineSep) {
- var lines = getLines(this, this.first, this.first + this.size);
- if (lineSep === false) { return lines }
- return lines.join(lineSep || this.lineSeparator())
- },
- setValue: docMethodOp(function(code) {
- var top = Pos(this.first, 0), last = this.first + this.size - 1;
- makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
- text: this.splitLines(code), origin: "setValue", full: true}, true);
- if (this.cm) { scrollToCoords(this.cm, 0, 0); }
- setSelection(this, simpleSelection(top), sel_dontScroll);
- }),
- replaceRange: function(code, from, to, origin) {
- from = clipPos(this, from);
- to = to ? clipPos(this, to) : from;
- replaceRange(this, code, from, to, origin);
- },
- getRange: function(from, to, lineSep) {
- var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
- if (lineSep === false) { return lines }
- return lines.join(lineSep || this.lineSeparator())
- },
-
- getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
-
- getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
- getLineNumber: function(line) {return lineNo(line)},
-
- getLineHandleVisualStart: function(line) {
- if (typeof line == "number") { line = getLine(this, line); }
- return visualLine(line)
- },
-
- lineCount: function() {return this.size},
- firstLine: function() {return this.first},
- lastLine: function() {return this.first + this.size - 1},
-
- clipPos: function(pos) {return clipPos(this, pos)},
-
- getCursor: function(start) {
- var range$$1 = this.sel.primary(), pos;
- if (start == null || start == "head") { pos = range$$1.head; }
- else if (start == "anchor") { pos = range$$1.anchor; }
- else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
- else { pos = range$$1.from(); }
- return pos
- },
- listSelections: function() { return this.sel.ranges },
- somethingSelected: function() {return this.sel.somethingSelected()},
-
- setCursor: docMethodOp(function(line, ch, options) {
- setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
- }),
- setSelection: docMethodOp(function(anchor, head, options) {
- setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
- }),
- extendSelection: docMethodOp(function(head, other, options) {
- extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
- }),
- extendSelections: docMethodOp(function(heads, options) {
- extendSelections(this, clipPosArray(this, heads), options);
- }),
- extendSelectionsBy: docMethodOp(function(f, options) {
- var heads = map(this.sel.ranges, f);
- extendSelections(this, clipPosArray(this, heads), options);
- }),
- setSelections: docMethodOp(function(ranges, primary, options) {
- var this$1 = this;
+ Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
- if (!ranges.length) { return }
+ Selection.prototype.equals = function (other) {
+ if (other == this) { return true }
+ if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
+ for (var i = 0; i < this.ranges.length; i++) {
+ var here = this.ranges[i], there = other.ranges[i];
+ if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
+ }
+ return true
+ };
+
+ Selection.prototype.deepCopy = function () {
var out = [];
- for (var i = 0; i < ranges.length; i++)
- { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
- clipPos(this$1, ranges[i].head)); }
- if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
- setSelection(this, normalizeSelection(out, primary), options);
- }),
- addSelection: docMethodOp(function(anchor, head, options) {
- var ranges = this.sel.ranges.slice(0);
- ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
- setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
- }),
-
- getSelection: function(lineSep) {
- var this$1 = this;
+ for (var i = 0; i < this.ranges.length; i++)
+ { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); }
+ return new Selection(out, this.primIndex)
+ };
- var ranges = this.sel.ranges, lines;
- for (var i = 0; i < ranges.length; i++) {
- var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
- lines = lines ? lines.concat(sel) : sel;
+ Selection.prototype.somethingSelected = function () {
+ for (var i = 0; i < this.ranges.length; i++)
+ { if (!this.ranges[i].empty()) { return true } }
+ return false
+ };
+
+ Selection.prototype.contains = function (pos, end) {
+ if (!end) { end = pos; }
+ for (var i = 0; i < this.ranges.length; i++) {
+ var range = this.ranges[i];
+ if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
+ { return i }
}
- if (lineSep === false) { return lines }
- else { return lines.join(lineSep || this.lineSeparator()) }
- },
- getSelections: function(lineSep) {
- var this$1 = this;
+ return -1
+ };
- var parts = [], ranges = this.sel.ranges;
- for (var i = 0; i < ranges.length; i++) {
- var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
- if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
- parts[i] = sel;
+ var Range = function(anchor, head) {
+ this.anchor = anchor; this.head = head;
+ };
+
+ Range.prototype.from = function () { return minPos(this.anchor, this.head) };
+ Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
+ Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
+
+ // Take an unsorted, potentially overlapping set of ranges, and
+ // build a selection out of it. 'Consumes' ranges array (modifying
+ // it).
+ function normalizeSelection(cm, ranges, primIndex) {
+ var mayTouch = cm && cm.options.selectionsMayTouch;
+ var prim = ranges[primIndex];
+ ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
+ primIndex = indexOf(ranges, prim);
+ for (var i = 1; i < ranges.length; i++) {
+ var cur = ranges[i], prev = ranges[i - 1];
+ var diff = cmp(prev.to(), cur.from());
+ if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {
+ var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
+ var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
+ if (i <= primIndex) { --primIndex; }
+ ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
+ }
}
- return parts
- },
- replaceSelection: function(code, collapse, origin) {
- var dup = [];
- for (var i = 0; i < this.sel.ranges.length; i++)
- { dup[i] = code; }
- this.replaceSelections(dup, collapse, origin || "+input");
- },
- replaceSelections: docMethodOp(function(code, collapse, origin) {
- var this$1 = this;
+ return new Selection(ranges, primIndex)
+ }
- var changes = [], sel = this.sel;
- for (var i = 0; i < sel.ranges.length; i++) {
- var range$$1 = sel.ranges[i];
- changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
- }
- var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
- for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
- { makeChange(this$1, changes[i$1]); }
- if (newSel) { setSelectionReplaceHistory(this, newSel); }
- else if (this.cm) { ensureCursorVisible(this.cm); }
- }),
- undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
- redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
- undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
- redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
-
- setExtending: function(val) {this.extend = val;},
- getExtending: function() {return this.extend},
-
- historySize: function() {
- var hist = this.history, done = 0, undone = 0;
- for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
- for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
- return {undo: done, redo: undone}
- },
- clearHistory: function() {this.history = new History(this.history.maxGeneration);},
-
- markClean: function() {
- this.cleanGeneration = this.changeGeneration(true);
- },
- changeGeneration: function(forceSplit) {
- if (forceSplit)
- { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
- return this.history.generation
- },
- isClean: function (gen) {
- return this.history.generation == (gen || this.cleanGeneration)
- },
-
- getHistory: function() {
- return {done: copyHistoryArray(this.history.done),
- undone: copyHistoryArray(this.history.undone)}
- },
- setHistory: function(histData) {
- var hist = this.history = new History(this.history.maxGeneration);
- hist.done = copyHistoryArray(histData.done.slice(0), null, true);
- hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
- },
-
- setGutterMarker: docMethodOp(function(line, gutterID, value) {
- return changeLine(this, line, "gutter", function (line) {
- var markers = line.gutterMarkers || (line.gutterMarkers = {});
- markers[gutterID] = value;
- if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
- return true
- })
- }),
+ function simpleSelection(anchor, head) {
+ return new Selection([new Range(anchor, head || anchor)], 0)
+ }
- clearGutter: docMethodOp(function(gutterID) {
- var this$1 = this;
+ // Compute the position of the end of a change (its 'to' property
+ // refers to the pre-change end).
+ function changeEnd(change) {
+ if (!change.text) { return change.to }
+ return Pos(change.from.line + change.text.length - 1,
+ lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
+ }
- this.iter(function (line) {
- if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
- changeLine(this$1, line, "gutter", function () {
- line.gutterMarkers[gutterID] = null;
- if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
- return true
- });
+ // Adjust a position to refer to the post-change position of the
+ // same text, or the end of the change if the change covers it.
+ function adjustForChange(pos, change) {
+ if (cmp(pos, change.from) < 0) { return pos }
+ if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
+
+ var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
+ if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
+ return Pos(line, ch)
+ }
+
+ function computeSelAfterChange(doc, change) {
+ var out = [];
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ var range = doc.sel.ranges[i];
+ out.push(new Range(adjustForChange(range.anchor, change),
+ adjustForChange(range.head, change)));
+ }
+ return normalizeSelection(doc.cm, out, doc.sel.primIndex)
+ }
+
+ function offsetPos(pos, old, nw) {
+ if (pos.line == old.line)
+ { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
+ else
+ { return Pos(nw.line + (pos.line - old.line), pos.ch) }
+ }
+
+ // Used by replaceSelections to allow moving the selection to the
+ // start or around the replaced test. Hint may be "start" or "around".
+ function computeReplacedSel(doc, changes, hint) {
+ var out = [];
+ var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
+ for (var i = 0; i < changes.length; i++) {
+ var change = changes[i];
+ var from = offsetPos(change.from, oldPrev, newPrev);
+ var to = offsetPos(changeEnd(change), oldPrev, newPrev);
+ oldPrev = change.to;
+ newPrev = to;
+ if (hint == "around") {
+ var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
+ out[i] = new Range(inv ? to : from, inv ? from : to);
+ } else {
+ out[i] = new Range(from, from);
}
+ }
+ return new Selection(out, doc.sel.primIndex)
+ }
+
+ // Used to get the editor into a consistent state again when options change.
+
+ function loadMode(cm) {
+ cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
+ resetModeState(cm);
+ }
+
+ function resetModeState(cm) {
+ cm.doc.iter(function (line) {
+ if (line.stateAfter) { line.stateAfter = null; }
+ if (line.styles) { line.styles = null; }
});
- }),
-
- lineInfo: function(line) {
- var n;
- if (typeof line == "number") {
- if (!isLine(this, line)) { return null }
- n = line;
- line = getLine(this, line);
- if (!line) { return null }
- } else {
- n = lineNo(line);
- if (n == null) { return null }
- }
- return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
- textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
- widgets: line.widgets}
- },
-
- addLineClass: docMethodOp(function(handle, where, cls) {
- return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
- var prop = where == "text" ? "textClass"
- : where == "background" ? "bgClass"
- : where == "gutter" ? "gutterClass" : "wrapClass";
- if (!line[prop]) { line[prop] = cls; }
- else if (classTest(cls).test(line[prop])) { return false }
- else { line[prop] += " " + cls; }
- return true
- })
- }),
- removeLineClass: docMethodOp(function(handle, where, cls) {
- return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
- var prop = where == "text" ? "textClass"
- : where == "background" ? "bgClass"
- : where == "gutter" ? "gutterClass" : "wrapClass";
- var cur = line[prop];
- if (!cur) { return false }
- else if (cls == null) { line[prop] = null; }
- else {
- var found = cur.match(classTest(cls));
- if (!found) { return false }
- var end = found.index + found[0].length;
- line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
+ cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
+ startWorker(cm, 100);
+ cm.state.modeGen++;
+ if (cm.curOp) { regChange(cm); }
+ }
+
+ // DOCUMENT DATA STRUCTURE
+
+ // By default, updates that start and end at the beginning of a line
+ // are treated specially, in order to make the association of line
+ // widgets and marker elements with the text behave more intuitive.
+ function isWholeLineUpdate(doc, change) {
+ return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
+ }
+
+ // Perform a change on the document data structure.
+ function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
+ function spansFor(n) {return markedSpans ? markedSpans[n] : null}
+ function update(line, text, spans) {
+ updateLine(line, text, spans, estimateHeight$$1);
+ signalLater(line, "change", line, change);
+ }
+ function linesFor(start, end) {
+ var result = [];
+ for (var i = start; i < end; ++i)
+ { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
+ return result
+ }
+
+ var from = change.from, to = change.to, text = change.text;
+ var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
+ var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
+
+ // Adjust the line structure
+ if (change.full) {
+ doc.insert(0, linesFor(0, text.length));
+ doc.remove(text.length, doc.size - text.length);
+ } else if (isWholeLineUpdate(doc, change)) {
+ // This is a whole-line replace. Treated specially to make
+ // sure line objects move the way they are supposed to.
+ var added = linesFor(0, text.length - 1);
+ update(lastLine, lastLine.text, lastSpans);
+ if (nlines) { doc.remove(from.line, nlines); }
+ if (added.length) { doc.insert(from.line, added); }
+ } else if (firstLine == lastLine) {
+ if (text.length == 1) {
+ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
+ } else {
+ var added$1 = linesFor(1, text.length - 1);
+ added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+ doc.insert(from.line + 1, added$1);
}
- return true
- })
- }),
-
- addLineWidget: docMethodOp(function(handle, node, options) {
- return addLineWidget(this, handle, node, options)
- }),
- removeLineWidget: function(widget) { widget.clear(); },
-
- markText: function(from, to, options) {
- return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
- },
- setBookmark: function(pos, options) {
- var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
- insertLeft: options && options.insertLeft,
- clearWhenEmpty: false, shared: options && options.shared,
- handleMouseEvents: options && options.handleMouseEvents};
- pos = clipPos(this, pos);
- return markText(this, pos, pos, realOpts, "bookmark")
- },
- findMarksAt: function(pos) {
- pos = clipPos(this, pos);
- var markers = [], spans = getLine(this, pos.line).markedSpans;
- if (spans) { for (var i = 0; i < spans.length; ++i) {
- var span = spans[i];
- if ((span.from == null || span.from <= pos.ch) &&
- (span.to == null || span.to >= pos.ch))
- { markers.push(span.marker.parent || span.marker); }
- } }
- return markers
- },
- findMarks: function(from, to, filter) {
- from = clipPos(this, from); to = clipPos(this, to);
- var found = [], lineNo$$1 = from.line;
- this.iter(from.line, to.line + 1, function (line) {
- var spans = line.markedSpans;
- if (spans) { for (var i = 0; i < spans.length; i++) {
- var span = spans[i];
- if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
- span.from == null && lineNo$$1 != from.line ||
- span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
- (!filter || filter(span.marker)))
- { found.push(span.marker.parent || span.marker); }
+ } else if (text.length == 1) {
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
+ doc.remove(from.line + 1, nlines);
+ } else {
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+ update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
+ var added$2 = linesFor(1, text.length - 1);
+ if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
+ doc.insert(from.line + 1, added$2);
+ }
+
+ signalLater(doc, "change", doc, change);
+ }
+
+ // Call f for all linked documents.
+ function linkedDocs(doc, f, sharedHistOnly) {
+ function propagate(doc, skip, sharedHist) {
+ if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
+ var rel = doc.linked[i];
+ if (rel.doc == skip) { continue }
+ var shared = sharedHist && rel.sharedHist;
+ if (sharedHistOnly && !shared) { continue }
+ f(rel.doc, shared);
+ propagate(rel.doc, doc, shared);
} }
- ++lineNo$$1;
- });
- return found
- },
- getAllMarks: function() {
- var markers = [];
- this.iter(function (line) {
- var sps = line.markedSpans;
- if (sps) { for (var i = 0; i < sps.length; ++i)
- { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
- });
- return markers
- },
-
- posFromIndex: function(off) {
- var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
- this.iter(function (line) {
- var sz = line.text.length + sepSize;
- if (sz > off) { ch = off; return true }
- off -= sz;
- ++lineNo$$1;
+ }
+ propagate(doc, null, true);
+ }
+
+ // Attach a document to an editor.
+ function attachDoc(cm, doc) {
+ if (doc.cm) { throw new Error("This document is already in use.") }
+ cm.doc = doc;
+ doc.cm = cm;
+ estimateLineHeights(cm);
+ loadMode(cm);
+ setDirectionClass(cm);
+ if (!cm.options.lineWrapping) { findMaxLine(cm); }
+ cm.options.mode = doc.modeOption;
+ regChange(cm);
+ }
+
+ function setDirectionClass(cm) {
+ (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
+ }
+
+ function directionChanged(cm) {
+ runInOp(cm, function () {
+ setDirectionClass(cm);
+ regChange(cm);
});
- return clipPos(this, Pos(lineNo$$1, ch))
- },
- indexFromPos: function (coords) {
- coords = clipPos(this, coords);
- var index = coords.ch;
- if (coords.line < this.first || coords.ch < 0) { return 0 }
- var sepSize = this.lineSeparator().length;
- this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
- index += line.text.length + sepSize;
+ }
+
+ function History(startGen) {
+ // Arrays of change events and selections. Doing something adds an
+ // event to done and clears undo. Undoing moves events from done
+ // to undone, redoing moves them in the other direction.
+ this.done = []; this.undone = [];
+ this.undoDepth = Infinity;
+ // Used to track when changes can be merged into a single undo
+ // event
+ this.lastModTime = this.lastSelTime = 0;
+ this.lastOp = this.lastSelOp = null;
+ this.lastOrigin = this.lastSelOrigin = null;
+ // Used by the isClean() method
+ this.generation = this.maxGeneration = startGen || 1;
+ }
+
+ // Create a history change event from an updateDoc-style change
+ // object.
+ function historyChangeFromChange(doc, change) {
+ var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
+ attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
+ linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
+ return histChange
+ }
+
+ // Pop all selection events off the end of a history array. Stop at
+ // a change event.
+ function clearSelectionEvents(array) {
+ while (array.length) {
+ var last = lst(array);
+ if (last.ranges) { array.pop(); }
+ else { break }
+ }
+ }
+
+ // Find the top change event in the history. Pop off selection
+ // events that are in the way.
+ function lastChangeEvent(hist, force) {
+ if (force) {
+ clearSelectionEvents(hist.done);
+ return lst(hist.done)
+ } else if (hist.done.length && !lst(hist.done).ranges) {
+ return lst(hist.done)
+ } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
+ hist.done.pop();
+ return lst(hist.done)
+ }
+ }
+
+ // Register a change in the history. Merges changes that are within
+ // a single operation, or are close together with an origin that
+ // allows merging (starting with "+") into a single event.
+ function addChangeToHistory(doc, change, selAfter, opId) {
+ var hist = doc.history;
+ hist.undone.length = 0;
+ var time = +new Date, cur;
+ var last;
+
+ if ((hist.lastOp == opId ||
+ hist.lastOrigin == change.origin && change.origin &&
+ ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
+ change.origin.charAt(0) == "*")) &&
+ (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
+ // Merge this change into the last event
+ last = lst(cur.changes);
+ if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
+ // Optimized case for simple insertion -- don't want to add
+ // new changesets for every character typed
+ last.to = changeEnd(change);
+ } else {
+ // Add new sub-event
+ cur.changes.push(historyChangeFromChange(doc, change));
+ }
+ } else {
+ // Can not be merged, start a new event.
+ var before = lst(hist.done);
+ if (!before || !before.ranges)
+ { pushSelectionToHistory(doc.sel, hist.done); }
+ cur = {changes: [historyChangeFromChange(doc, change)],
+ generation: hist.generation};
+ hist.done.push(cur);
+ while (hist.done.length > hist.undoDepth) {
+ hist.done.shift();
+ if (!hist.done[0].ranges) { hist.done.shift(); }
+ }
+ }
+ hist.done.push(selAfter);
+ hist.generation = ++hist.maxGeneration;
+ hist.lastModTime = hist.lastSelTime = time;
+ hist.lastOp = hist.lastSelOp = opId;
+ hist.lastOrigin = hist.lastSelOrigin = change.origin;
+
+ if (!last) { signal(doc, "historyAdded"); }
+ }
+
+ function selectionEventCanBeMerged(doc, origin, prev, sel) {
+ var ch = origin.charAt(0);
+ return ch == "*" ||
+ ch == "+" &&
+ prev.ranges.length == sel.ranges.length &&
+ prev.somethingSelected() == sel.somethingSelected() &&
+ new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
+ }
+
+ // Called whenever the selection changes, sets the new selection as
+ // the pending selection in the history, and pushes the old pending
+ // selection into the 'done' array when it was significantly
+ // different (in number of selected ranges, emptiness, or time).
+ function addSelectionToHistory(doc, sel, opId, options) {
+ var hist = doc.history, origin = options && options.origin;
+
+ // A new event is started when the previous origin does not match
+ // the current, or the origins don't allow matching. Origins
+ // starting with * are always merged, those starting with + are
+ // merged when similar and close together in time.
+ if (opId == hist.lastSelOp ||
+ (origin && hist.lastSelOrigin == origin &&
+ (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
+ selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
+ { hist.done[hist.done.length - 1] = sel; }
+ else
+ { pushSelectionToHistory(sel, hist.done); }
+
+ hist.lastSelTime = +new Date;
+ hist.lastSelOrigin = origin;
+ hist.lastSelOp = opId;
+ if (options && options.clearRedo !== false)
+ { clearSelectionEvents(hist.undone); }
+ }
+
+ function pushSelectionToHistory(sel, dest) {
+ var top = lst(dest);
+ if (!(top && top.ranges && top.equals(sel)))
+ { dest.push(sel); }
+ }
+
+ // Used to store marked span information in the history.
+ function attachLocalSpans(doc, change, from, to) {
+ var existing = change["spans_" + doc.id], n = 0;
+ doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
+ if (line.markedSpans)
+ { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
+ ++n;
});
- return index
- },
-
- copy: function(copyHistory) {
- var doc = new Doc(getLines(this, this.first, this.first + this.size),
- this.modeOption, this.first, this.lineSep, this.direction);
- doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
- doc.sel = this.sel;
- doc.extend = false;
- if (copyHistory) {
- doc.history.undoDepth = this.history.undoDepth;
- doc.setHistory(this.getHistory());
- }
- return doc
- },
-
- linkedDoc: function(options) {
- if (!options) { options = {}; }
- var from = this.first, to = this.first + this.size;
- if (options.from != null && options.from > from) { from = options.from; }
- if (options.to != null && options.to < to) { to = options.to; }
- var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
- if (options.sharedHist) { copy.history = this.history
- ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
- copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
- copySharedMarkers(copy, findSharedMarkers(this));
- return copy
- },
- unlinkDoc: function(other) {
- var this$1 = this;
+ }
- if (other instanceof CodeMirror$1) { other = other.doc; }
- if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
- var link = this$1.linked[i];
- if (link.doc != other) { continue }
- this$1.linked.splice(i, 1);
- other.unlinkDoc(this$1);
- detachSharedMarkers(findSharedMarkers(this$1));
- break
- } }
- // If the histories were shared, split them again
- if (other.history == this.history) {
- var splitIds = [other.id];
- linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
- other.history = new History(null);
- other.history.done = copyHistoryArray(this.history.done, splitIds);
- other.history.undone = copyHistoryArray(this.history.undone, splitIds);
- }
- },
- iterLinkedDocs: function(f) {linkedDocs(this, f);},
-
- getMode: function() {return this.mode},
- getEditor: function() {return this.cm},
-
- splitLines: function(str) {
- if (this.lineSep) { return str.split(this.lineSep) }
- return splitLinesAuto(str)
- },
- lineSeparator: function() { return this.lineSep || "\n" },
-
- setDirection: docMethodOp(function (dir) {
- if (dir != "rtl") { dir = "ltr"; }
- if (dir == this.direction) { return }
- this.direction = dir;
- this.iter(function (line) { return line.order = null; });
- if (this.cm) { directionChanged(this.cm); }
- })
-});
-
-// Public alias.
-Doc.prototype.eachLine = Doc.prototype.iter;
-
-// Kludge to work around strange IE behavior where it'll sometimes
-// re-fire a series of drag-related events right after the drop (#1551)
-var lastDrop = 0;
-
-function onDrop(e) {
- var cm = this;
- clearDragCursor(cm);
- if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
- { return }
- e_preventDefault(e);
- if (ie) { lastDrop = +new Date; }
- var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
- if (!pos || cm.isReadOnly()) { return }
- // Might be a file drop, in which case we simply extract the text
- // and insert it.
- if (files && files.length && window.FileReader && window.File) {
- var n = files.length, text = Array(n), read = 0;
- var loadFile = function (file, i) {
- if (cm.options.allowDropFileTypes &&
- indexOf(cm.options.allowDropFileTypes, file.type) == -1)
- { return }
-
- var reader = new FileReader;
- reader.onload = operation(cm, function () {
- var content = reader.result;
- if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
- text[i] = content;
- if (++read == n) {
- pos = clipPos(cm.doc, pos);
- var change = {from: pos, to: pos,
- text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
- origin: "paste"};
- makeChange(cm.doc, change);
- setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
+ // When un/re-doing restores text containing marked spans, those
+ // that have been explicitly cleared should not be restored.
+ function removeClearedSpans(spans) {
+ if (!spans) { return null }
+ var out;
+ for (var i = 0; i < spans.length; ++i) {
+ if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
+ else if (out) { out.push(spans[i]); }
+ }
+ return !out ? spans : out.length ? out : null
+ }
+
+ // Retrieve and filter the old marked spans stored in a change event.
+ function getOldSpans(doc, change) {
+ var found = change["spans_" + doc.id];
+ if (!found) { return null }
+ var nw = [];
+ for (var i = 0; i < change.text.length; ++i)
+ { nw.push(removeClearedSpans(found[i])); }
+ return nw
+ }
+
+ // Used for un/re-doing changes from the history. Combines the
+ // result of computing the existing spans with the set of spans that
+ // existed in the history (so that deleting around a span and then
+ // undoing brings back the span).
+ function mergeOldSpans(doc, change) {
+ var old = getOldSpans(doc, change);
+ var stretched = stretchSpansOverChange(doc, change);
+ if (!old) { return stretched }
+ if (!stretched) { return old }
+
+ for (var i = 0; i < old.length; ++i) {
+ var oldCur = old[i], stretchCur = stretched[i];
+ if (oldCur && stretchCur) {
+ spans: for (var j = 0; j < stretchCur.length; ++j) {
+ var span = stretchCur[j];
+ for (var k = 0; k < oldCur.length; ++k)
+ { if (oldCur[k].marker == span.marker) { continue spans } }
+ oldCur.push(span);
}
- });
- reader.readAsText(file);
- };
- for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
- } else { // Normal drop
- // Don't do a replace if the drop happened inside of the selected text.
- if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
- cm.state.draggingText(e);
- // Ensure the editor is re-focused
- setTimeout(function () { return cm.display.input.focus(); }, 20);
- return
+ } else if (stretchCur) {
+ old[i] = stretchCur;
+ }
}
- try {
- var text$1 = e.dataTransfer.getData("Text");
- if (text$1) {
- var selected;
- if (cm.state.draggingText && !cm.state.draggingText.copy)
- { selected = cm.listSelections(); }
- setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
- if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
- { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
- cm.replaceSelection(text$1, "around", "paste");
- cm.display.input.focus();
- }
- }
- catch(e){}
- }
-}
-
-function onDragStart(cm, e) {
- if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
- if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
-
- e.dataTransfer.setData("Text", cm.getSelection());
- e.dataTransfer.effectAllowed = "copyMove";
-
- // Use dummy image instead of default browsers image.
- // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
- if (e.dataTransfer.setDragImage && !safari) {
- var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
- img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
- if (presto) {
- img.width = img.height = 1;
- cm.display.wrapper.appendChild(img);
- // Force a relayout, or Opera won't use our image for some obscure reason
- img._top = img.offsetTop;
- }
- e.dataTransfer.setDragImage(img, 0, 0);
- if (presto) { img.parentNode.removeChild(img); }
- }
-}
-
-function onDragOver(cm, e) {
- var pos = posFromMouse(cm, e);
- if (!pos) { return }
- var frag = document.createDocumentFragment();
- drawSelectionCursor(cm, pos, frag);
- if (!cm.display.dragCursor) {
- cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
- cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
- }
- removeChildrenAndAdd(cm.display.dragCursor, frag);
-}
-
-function clearDragCursor(cm) {
- if (cm.display.dragCursor) {
- cm.display.lineSpace.removeChild(cm.display.dragCursor);
- cm.display.dragCursor = null;
- }
-}
-
-// These must be handled carefully, because naively registering a
-// handler for each editor will cause the editors to never be
-// garbage collected.
-
-function forEachCodeMirror(f) {
- if (!document.getElementsByClassName) { return }
- var byClass = document.getElementsByClassName("CodeMirror");
- for (var i = 0; i < byClass.length; i++) {
- var cm = byClass[i].CodeMirror;
- if (cm) { f(cm); }
- }
-}
-
-var globalsRegistered = false;
-function ensureGlobalHandlers() {
- if (globalsRegistered) { return }
- registerGlobalHandlers();
- globalsRegistered = true;
-}
-function registerGlobalHandlers() {
- // When the window resizes, we need to refresh active editors.
- var resizeTimer;
- on(window, "resize", function () {
- if (resizeTimer == null) { resizeTimer = setTimeout(function () {
- resizeTimer = null;
- forEachCodeMirror(onResize);
- }, 100); }
- });
- // When the window loses focus, we want to show the editor as blurred
- on(window, "blur", function () { return forEachCodeMirror(onBlur); });
-}
-// Called when the window resizes
-function onResize(cm) {
- var d = cm.display;
- // Might be a text scaling operation, clear size caches.
- d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
- d.scrollbarsClipped = false;
- cm.setSize();
-}
-
-var keyNames = {
- 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
- 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
- 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
- 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
- 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
- 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
- 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
- 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
-};
-
-// Number keys
-for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
-// Alphabetic keys
-for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
-// Function keys
-for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
-
-var keyMap = {};
-
-keyMap.basic = {
- "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
- "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
- "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
- "Tab": "defaultTab", "Shift-Tab": "indentAuto",
- "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
- "Esc": "singleSelection"
-};
-// Note that the save and find-related commands aren't defined by
-// default. User code or addons can define them. Unknown commands
-// are simply ignored.
-keyMap.pcDefault = {
- "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
- "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
- "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
- "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
- "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
- "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
- "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
- "fallthrough": "basic"
-};
-// Very basic readline/emacs-style bindings, which are standard on Mac.
-keyMap.emacsy = {
- "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
- "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
- "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
- "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
- "Ctrl-O": "openLine"
-};
-keyMap.macDefault = {
- "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
- "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
- "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
- "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
- "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
- "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
- "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
- "fallthrough": ["basic", "emacsy"]
-};
-keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
-
-// KEYMAP DISPATCH
-
-function normalizeKeyName(name) {
- var parts = name.split(/-(?!$)/);
- name = parts[parts.length - 1];
- var alt, ctrl, shift, cmd;
- for (var i = 0; i < parts.length - 1; i++) {
- var mod = parts[i];
- if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
- else if (/^a(lt)?$/i.test(mod)) { alt = true; }
- else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
- else if (/^s(hift)?$/i.test(mod)) { shift = true; }
- else { throw new Error("Unrecognized modifier name: " + mod) }
- }
- if (alt) { name = "Alt-" + name; }
- if (ctrl) { name = "Ctrl-" + name; }
- if (cmd) { name = "Cmd-" + name; }
- if (shift) { name = "Shift-" + name; }
- return name
-}
-
-// This is a kludge to keep keymaps mostly working as raw objects
-// (backwards compatibility) while at the same time support features
-// like normalization and multi-stroke key bindings. It compiles a
-// new normalized keymap, and then updates the old object to reflect
-// this.
-function normalizeKeyMap(keymap) {
- var copy = {};
- for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
- var value = keymap[keyname];
- if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
- if (value == "...") { delete keymap[keyname]; continue }
-
- var keys = map(keyname.split(" "), normalizeKeyName);
- for (var i = 0; i < keys.length; i++) {
- var val = (void 0), name = (void 0);
- if (i == keys.length - 1) {
- name = keys.join(" ");
- val = value;
- } else {
- name = keys.slice(0, i + 1).join(" ");
- val = "...";
- }
- var prev = copy[name];
- if (!prev) { copy[name] = val; }
- else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
- }
- delete keymap[keyname];
- } }
- for (var prop in copy) { keymap[prop] = copy[prop]; }
- return keymap
-}
-
-function lookupKey(key, map$$1, handle, context) {
- map$$1 = getKeyMap(map$$1);
- var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
- if (found === false) { return "nothing" }
- if (found === "...") { return "multi" }
- if (found != null && handle(found)) { return "handled" }
-
- if (map$$1.fallthrough) {
- if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
- { return lookupKey(key, map$$1.fallthrough, handle, context) }
- for (var i = 0; i < map$$1.fallthrough.length; i++) {
- var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
- if (result) { return result }
+ return old
+ }
+
+ // Used both to provide a JSON-safe object in .getHistory, and, when
+ // detaching a document, to split the history in two
+ function copyHistoryArray(events, newGroup, instantiateSel) {
+ var copy = [];
+ for (var i = 0; i < events.length; ++i) {
+ var event = events[i];
+ if (event.ranges) {
+ copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
+ continue
+ }
+ var changes = event.changes, newChanges = [];
+ copy.push({changes: newChanges});
+ for (var j = 0; j < changes.length; ++j) {
+ var change = changes[j], m = (void 0);
+ newChanges.push({from: change.from, to: change.to, text: change.text});
+ if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
+ if (indexOf(newGroup, Number(m[1])) > -1) {
+ lst(newChanges)[prop] = change[prop];
+ delete change[prop];
+ }
+ } } }
+ }
}
+ return copy
}
-}
-
-// Modifier key presses don't count as 'real' key presses for the
-// purpose of keymap fallthrough.
-function isModifierKey(value) {
- var name = typeof value == "string" ? value : keyNames[value.keyCode];
- return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
-}
-
-function addModifierNames(name, event, noShift) {
- var base = name;
- if (event.altKey && base != "Alt") { name = "Alt-" + name; }
- if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
- if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
- if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
- return name
-}
-
-// Look up the name of a key as indicated by an event object.
-function keyName(event, noShift) {
- if (presto && event.keyCode == 34 && event["char"]) { return false }
- var name = keyNames[event.keyCode];
- if (name == null || event.altGraphKey) { return false }
- // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
- // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
- if (event.keyCode == 3 && event.code) { name = event.code; }
- return addModifierNames(name, event, noShift)
-}
-
-function getKeyMap(val) {
- return typeof val == "string" ? keyMap[val] : val
-}
-
-// Helper for deleting text near the selection(s), used to implement
-// backspace, delete, and similar functionality.
-function deleteNearSelection(cm, compute) {
- var ranges = cm.doc.sel.ranges, kill = [];
- // Build up a set of ranges to kill first, merging overlapping
- // ranges.
- for (var i = 0; i < ranges.length; i++) {
- var toKill = compute(ranges[i]);
- while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
- var replaced = kill.pop();
- if (cmp(replaced.from, toKill.from) < 0) {
- toKill.from = replaced.from;
- break
+
+ // The 'scroll' parameter given to many of these indicated whether
+ // the new cursor position should be scrolled into view after
+ // modifying the selection.
+
+ // If shift is held or the extend flag is set, extends a range to
+ // include a given position (and optionally a second position).
+ // Otherwise, simply returns the range between the given positions.
+ // Used for cursor motion and such.
+ function extendRange(range, head, other, extend) {
+ if (extend) {
+ var anchor = range.anchor;
+ if (other) {
+ var posBefore = cmp(head, anchor) < 0;
+ if (posBefore != (cmp(other, anchor) < 0)) {
+ anchor = head;
+ head = other;
+ } else if (posBefore != (cmp(head, other) < 0)) {
+ head = other;
+ }
}
+ return new Range(anchor, head)
+ } else {
+ return new Range(other || head, head)
}
- kill.push(toKill);
}
- // Next, remove those actual ranges.
- runInOp(cm, function () {
- for (var i = kill.length - 1; i >= 0; i--)
- { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
- ensureCursorVisible(cm);
- });
-}
-function moveCharLogically(line, ch, dir) {
- var target = skipExtendingChars(line.text, ch + dir, dir);
- return target < 0 || target > line.text.length ? null : target
-}
+ // Extend the primary selection range, discard the rest.
+ function extendSelection(doc, head, other, options, extend) {
+ if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
+ setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
+ }
-function moveLogically(line, start, dir) {
- var ch = moveCharLogically(line, start.ch, dir);
- return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
-}
+ // Extend all selections (pos is an array of selections with length
+ // equal the number of selections)
+ function extendSelections(doc, heads, options) {
+ var out = [];
+ var extend = doc.cm && (doc.cm.display.shift || doc.extend);
+ for (var i = 0; i < doc.sel.ranges.length; i++)
+ { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
+ var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex);
+ setSelection(doc, newSel, options);
+ }
-function endOfLine(visually, cm, lineObj, lineNo, dir) {
- if (visually) {
- var order = getOrder(lineObj, cm.doc.direction);
- if (order) {
- var part = dir < 0 ? lst(order) : order[0];
- var moveInStorageOrder = (dir < 0) == (part.level == 1);
- var sticky = moveInStorageOrder ? "after" : "before";
- var ch;
- // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
- // it could be that the last bidi part is not on the last visual line,
- // since visual lines contain content order-consecutive chunks.
- // Thus, in rtl, we are looking for the first (content-order) character
- // in the rtl chunk that is on the last line (that is, the same line
- // as the last (content-order) character).
- if (part.level > 0 || cm.doc.direction == "rtl") {
- var prep = prepareMeasureForLine(cm, lineObj);
- ch = dir < 0 ? lineObj.text.length - 1 : 0;
- var targetTop = measureCharPrepared(cm, prep, ch).top;
- ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
- if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
- } else { ch = dir < 0 ? part.to : part.from; }
- return new Pos(lineNo, ch, sticky)
- }
- }
- return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
-}
-
-function moveVisually(cm, line, start, dir) {
- var bidi = getOrder(line, cm.doc.direction);
- if (!bidi) { return moveLogically(line, start, dir) }
- if (start.ch >= line.text.length) {
- start.ch = line.text.length;
- start.sticky = "before";
- } else if (start.ch <= 0) {
- start.ch = 0;
- start.sticky = "after";
- }
- var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
- if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
- // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
- // nothing interesting happens.
- return moveLogically(line, start, dir)
- }
-
- var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
- var prep;
- var getWrappedLineExtent = function (ch) {
- if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
- prep = prep || prepareMeasureForLine(cm, line);
- return wrappedLineExtentChar(cm, line, prep, ch)
- };
- var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
+ // Updates a single range in the selection.
+ function replaceOneSelection(doc, i, range, options) {
+ var ranges = doc.sel.ranges.slice(0);
+ ranges[i] = range;
+ setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options);
+ }
- if (cm.doc.direction == "rtl" || part.level == 1) {
- var moveInStorageOrder = (part.level == 1) == (dir < 0);
- var ch = mv(start, moveInStorageOrder ? 1 : -1);
- if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
- // Case 2: We move within an rtl part or in an rtl editor on the same visual line
- var sticky = moveInStorageOrder ? "before" : "after";
- return new Pos(start.line, ch, sticky)
+ // Reset the selection to a single range.
+ function setSimpleSelection(doc, anchor, head, options) {
+ setSelection(doc, simpleSelection(anchor, head), options);
+ }
+
+ // Give beforeSelectionChange handlers a change to influence a
+ // selection update.
+ function filterSelectionChange(doc, sel, options) {
+ var obj = {
+ ranges: sel.ranges,
+ update: function(ranges) {
+ this.ranges = [];
+ for (var i = 0; i < ranges.length; i++)
+ { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
+ clipPos(doc, ranges[i].head)); }
+ },
+ origin: options && options.origin
+ };
+ signal(doc, "beforeSelectionChange", doc, obj);
+ if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
+ if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) }
+ else { return sel }
+ }
+
+ function setSelectionReplaceHistory(doc, sel, options) {
+ var done = doc.history.done, last = lst(done);
+ if (last && last.ranges) {
+ done[done.length - 1] = sel;
+ setSelectionNoUndo(doc, sel, options);
+ } else {
+ setSelection(doc, sel, options);
}
}
- // Case 3: Could not move within this bidi part in this visual line, so leave
- // the current bidi part
+ // Set a new selection.
+ function setSelection(doc, sel, options) {
+ setSelectionNoUndo(doc, sel, options);
+ addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
+ }
+
+ function setSelectionNoUndo(doc, sel, options) {
+ if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
+ { sel = filterSelectionChange(doc, sel, options); }
+
+ var bias = options && options.bias ||
+ (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
+ setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
+
+ if (!(options && options.scroll === false) && doc.cm)
+ { ensureCursorVisible(doc.cm); }
+ }
+
+ function setSelectionInner(doc, sel) {
+ if (sel.equals(doc.sel)) { return }
- var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
- var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
- ? new Pos(start.line, mv(ch, 1), "before")
- : new Pos(start.line, ch, "after"); };
+ doc.sel = sel;
- for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
- var part = bidi[partPos];
- var moveInStorageOrder = (dir > 0) == (part.level != 1);
- var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
- if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
- ch = moveInStorageOrder ? part.from : mv(part.to, -1);
- if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
+ if (doc.cm) {
+ doc.cm.curOp.updateInput = 1;
+ doc.cm.curOp.selectionChanged = true;
+ signalCursorActivity(doc.cm);
}
- };
+ signalLater(doc, "cursorActivity", doc);
+ }
- // Case 3a: Look for other bidi parts on the same visual line
- var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
- if (res) { return res }
+ // Verify that the selection does not partially select any atomic
+ // marked ranges.
+ function reCheckSelection(doc) {
+ setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
+ }
- // Case 3b: Look for other bidi parts on the next visual line
- var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
- if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
- res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
- if (res) { return res }
+ // Return a selection that does not partially select any atomic
+ // ranges.
+ function skipAtomicInSelection(doc, sel, bias, mayClear) {
+ var out;
+ for (var i = 0; i < sel.ranges.length; i++) {
+ var range = sel.ranges[i];
+ var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
+ var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
+ var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
+ if (out || newAnchor != range.anchor || newHead != range.head) {
+ if (!out) { out = sel.ranges.slice(0, i); }
+ out[i] = new Range(newAnchor, newHead);
+ }
+ }
+ return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel
}
- // Case 4: Nowhere to move
- return null
-}
-
-// Commands are parameter-less actions that can be performed on an
-// editor, mostly used for keybindings.
-var commands = {
- selectAll: selectAll,
- singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
- killLine: function (cm) { return deleteNearSelection(cm, function (range) {
- if (range.empty()) {
- var len = getLine(cm.doc, range.head.line).text.length;
- if (range.head.ch == len && range.head.line < cm.lastLine())
- { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
- else
- { return {from: range.head, to: Pos(range.head.line, len)} }
- } else {
- return {from: range.from(), to: range.to()}
- }
- }); },
- deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
- from: Pos(range.from().line, 0),
- to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
- }); }); },
- delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
- from: Pos(range.from().line, 0), to: range.from()
- }); }); },
- delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
- var top = cm.charCoords(range.head, "div").top + 5;
- var leftPos = cm.coordsChar({left: 0, top: top}, "div");
- return {from: leftPos, to: range.from()}
- }); },
- delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
- var top = cm.charCoords(range.head, "div").top + 5;
- var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
- return {from: range.from(), to: rightPos }
- }); },
- undo: function (cm) { return cm.undo(); },
- redo: function (cm) { return cm.redo(); },
- undoSelection: function (cm) { return cm.undoSelection(); },
- redoSelection: function (cm) { return cm.redoSelection(); },
- goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
- goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
- goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
- {origin: "+move", bias: 1}
- ); },
- goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
- {origin: "+move", bias: 1}
- ); },
- goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
- {origin: "+move", bias: -1}
- ); },
- goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
- var top = cm.cursorCoords(range.head, "div").top + 5;
- return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
- }, sel_move); },
- goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
- var top = cm.cursorCoords(range.head, "div").top + 5;
- return cm.coordsChar({left: 0, top: top}, "div")
- }, sel_move); },
- goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
- var top = cm.cursorCoords(range.head, "div").top + 5;
- var pos = cm.coordsChar({left: 0, top: top}, "div");
- if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
- return pos
- }, sel_move); },
- goLineUp: function (cm) { return cm.moveV(-1, "line"); },
- goLineDown: function (cm) { return cm.moveV(1, "line"); },
- goPageUp: function (cm) { return cm.moveV(-1, "page"); },
- goPageDown: function (cm) { return cm.moveV(1, "page"); },
- goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
- goCharRight: function (cm) { return cm.moveH(1, "char"); },
- goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
- goColumnRight: function (cm) { return cm.moveH(1, "column"); },
- goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
- goGroupRight: function (cm) { return cm.moveH(1, "group"); },
- goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
- goWordRight: function (cm) { return cm.moveH(1, "word"); },
- delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
- delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
- delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
- delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
- delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
- delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
- indentAuto: function (cm) { return cm.indentSelection("smart"); },
- indentMore: function (cm) { return cm.indentSelection("add"); },
- indentLess: function (cm) { return cm.indentSelection("subtract"); },
- insertTab: function (cm) { return cm.replaceSelection("\t"); },
- insertSoftTab: function (cm) {
- var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
- for (var i = 0; i < ranges.length; i++) {
- var pos = ranges[i].from();
- var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
- spaces.push(spaceStr(tabSize - col % tabSize));
- }
- cm.replaceSelections(spaces);
- },
- defaultTab: function (cm) {
- if (cm.somethingSelected()) { cm.indentSelection("add"); }
- else { cm.execCommand("insertTab"); }
- },
- // Swap the two chars left and right of each selection's head.
- // Move cursor behind the two swapped characters afterwards.
- //
- // Doesn't consider line feeds a character.
- // Doesn't scan more than one line above to find a character.
- // Doesn't do anything on an empty line.
- // Doesn't do anything with non-empty selections.
- transposeChars: function (cm) { return runInOp(cm, function () {
- var ranges = cm.listSelections(), newSel = [];
- for (var i = 0; i < ranges.length; i++) {
- if (!ranges[i].empty()) { continue }
- var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
- if (line) {
- if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
- if (cur.ch > 0) {
- cur = new Pos(cur.line, cur.ch + 1);
- cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
- Pos(cur.line, cur.ch - 2), cur, "+transpose");
- } else if (cur.line > cm.doc.first) {
- var prev = getLine(cm.doc, cur.line - 1).text;
- if (prev) {
- cur = new Pos(cur.line, 1);
- cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
- prev.charAt(prev.length - 1),
- Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
+ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
+ var line = getLine(doc, pos.line);
+ if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
+ var sp = line.markedSpans[i], m = sp.marker;
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
+ (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
+ if (mayClear) {
+ signal(m, "beforeCursorEnter");
+ if (m.explicitlyCleared) {
+ if (!line.markedSpans) { break }
+ else {--i; continue}
}
}
- }
- newSel.push(new Range(cur, cur));
- }
- cm.setSelections(newSel);
- }); },
- newlineAndIndent: function (cm) { return runInOp(cm, function () {
- var sels = cm.listSelections();
- for (var i = sels.length - 1; i >= 0; i--)
- { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
- sels = cm.listSelections();
- for (var i$1 = 0; i$1 < sels.length; i$1++)
- { cm.indentLine(sels[i$1].from().line, null, true); }
- ensureCursorVisible(cm);
- }); },
- openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
- toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
-};
-
-
-function lineStart(cm, lineN) {
- var line = getLine(cm.doc, lineN);
- var visual = visualLine(line);
- if (visual != line) { lineN = lineNo(visual); }
- return endOfLine(true, cm, visual, lineN, 1)
-}
-function lineEnd(cm, lineN) {
- var line = getLine(cm.doc, lineN);
- var visual = visualLineEnd(line);
- if (visual != line) { lineN = lineNo(visual); }
- return endOfLine(true, cm, line, lineN, -1)
-}
-function lineStartSmart(cm, pos) {
- var start = lineStart(cm, pos.line);
- var line = getLine(cm.doc, start.line);
- var order = getOrder(line, cm.doc.direction);
- if (!order || order[0].level == 0) {
- var firstNonWS = Math.max(0, line.text.search(/\S/));
- var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
- return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
- }
- return start
-}
-
-// Run a handler that was bound to a key.
-function doHandleBinding(cm, bound, dropShift) {
- if (typeof bound == "string") {
- bound = commands[bound];
- if (!bound) { return false }
- }
- // Ensure previous input has been read, so that the handler sees a
- // consistent view of the document
- cm.display.input.ensurePolled();
- var prevShift = cm.display.shift, done = false;
- try {
- if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
- if (dropShift) { cm.display.shift = false; }
- done = bound(cm) != Pass;
- } finally {
- cm.display.shift = prevShift;
- cm.state.suppressEdits = false;
- }
- return done
-}
-
-function lookupKeyForEditor(cm, name, handle) {
- for (var i = 0; i < cm.state.keyMaps.length; i++) {
- var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
- if (result) { return result }
- }
- return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
- || lookupKey(name, cm.options.keyMap, handle, cm)
-}
-
-// Note that, despite the name, this function is also used to check
-// for bound mouse clicks.
-
-var stopSeq = new Delayed;
-
-function dispatchKey(cm, name, e, handle) {
- var seq = cm.state.keySeq;
- if (seq) {
- if (isModifierKey(name)) { return "handled" }
- if (/\'$/.test(name))
- { cm.state.keySeq = null; }
- else
- { stopSeq.set(50, function () {
- if (cm.state.keySeq == seq) {
- cm.state.keySeq = null;
- cm.display.input.reset();
+ if (!m.atomic) { continue }
+
+ if (oldPos) {
+ var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
+ if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
+ { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
+ if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
+ { return skipAtomicInner(doc, near, pos, dir, mayClear) }
}
- }); }
- if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
+
+ var far = m.find(dir < 0 ? -1 : 1);
+ if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
+ { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
+ return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
+ }
+ } }
+ return pos
}
- return dispatchKeyInner(cm, name, e, handle)
-}
-function dispatchKeyInner(cm, name, e, handle) {
- var result = lookupKeyForEditor(cm, name, handle);
+ // Ensure a given position is not inside an atomic range.
+ function skipAtomic(doc, pos, oldPos, bias, mayClear) {
+ var dir = bias || 1;
+ var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
+ skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
+ if (!found) {
+ doc.cantEdit = true;
+ return Pos(doc.first, 0)
+ }
+ return found
+ }
- if (result == "multi")
- { cm.state.keySeq = name; }
- if (result == "handled")
- { signalLater(cm, "keyHandled", cm, name, e); }
+ function movePos(doc, pos, dir, line) {
+ if (dir < 0 && pos.ch == 0) {
+ if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
+ else { return null }
+ } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
+ if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
+ else { return null }
+ } else {
+ return new Pos(pos.line, pos.ch + dir)
+ }
+ }
- if (result == "handled" || result == "multi") {
- e_preventDefault(e);
- restartBlink(cm);
+ function selectAll(cm) {
+ cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
}
- return !!result
-}
-
-// Handle a key from the keydown event.
-function handleKeyBinding(cm, e) {
- var name = keyName(e, true);
- if (!name) { return false }
-
- if (e.shiftKey && !cm.state.keySeq) {
- // First try to resolve full name (including 'Shift-'). Failing
- // that, see if there is a cursor-motion command (starting with
- // 'go') bound to the keyname without 'Shift-'.
- return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
- || dispatchKey(cm, name, e, function (b) {
- if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
- { return doHandleBinding(cm, b) }
- })
- } else {
- return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
- }
-}
-
-// Handle a key from the keypress event
-function handleCharBinding(cm, e, ch) {
- return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
-}
-
-var lastStoppedKey = null;
-function onKeyDown(e) {
- var cm = this;
- cm.curOp.focus = activeElt();
- if (signalDOMEvent(cm, e)) { return }
- // IE does strange things with escape.
- if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
- var code = e.keyCode;
- cm.display.shift = code == 16 || e.shiftKey;
- var handled = handleKeyBinding(cm, e);
- if (presto) {
- lastStoppedKey = handled ? code : null;
- // Opera has no cut event... we try to at least catch the key combo
- if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
- { cm.replaceSelection("", null, "cut"); }
- }
-
- // Turn mouse into crosshair when Alt is held on Mac.
- if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
- { showCrossHair(cm); }
-}
-
-function showCrossHair(cm) {
- var lineDiv = cm.display.lineDiv;
- addClass(lineDiv, "CodeMirror-crosshair");
-
- function up(e) {
- if (e.keyCode == 18 || !e.altKey) {
- rmClass(lineDiv, "CodeMirror-crosshair");
- off(document, "keyup", up);
- off(document, "mouseover", up);
- }
- }
- on(document, "keyup", up);
- on(document, "mouseover", up);
-}
-
-function onKeyUp(e) {
- if (e.keyCode == 16) { this.doc.sel.shift = false; }
- signalDOMEvent(this, e);
-}
-
-function onKeyPress(e) {
- var cm = this;
- if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
- var keyCode = e.keyCode, charCode = e.charCode;
- if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
- if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
- var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
- // Some browsers fire keypress events for backspace
- if (ch == "\x08") { return }
- if (handleCharBinding(cm, e, ch)) { return }
- cm.display.input.onKeyPress(e);
-}
-
-var DOUBLECLICK_DELAY = 400;
-
-var PastClick = function(time, pos, button) {
- this.time = time;
- this.pos = pos;
- this.button = button;
-};
-
-PastClick.prototype.compare = function (time, pos, button) {
- return this.time + DOUBLECLICK_DELAY > time &&
- cmp(pos, this.pos) == 0 && button == this.button
-};
-
-var lastClick;
-var lastDoubleClick;
-function clickRepeat(pos, button) {
- var now = +new Date;
- if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
- lastClick = lastDoubleClick = null;
- return "triple"
- } else if (lastClick && lastClick.compare(now, pos, button)) {
- lastDoubleClick = new PastClick(now, pos, button);
- lastClick = null;
- return "double"
- } else {
- lastClick = new PastClick(now, pos, button);
- lastDoubleClick = null;
- return "single"
- }
-}
-
-// A mouse down can be a single click, double click, triple click,
-// start of selection drag, start of text drag, new cursor
-// (ctrl-click), rectangle drag (alt-drag), or xwin
-// middle-click-paste. Or it might be a click on something we should
-// not interfere with, such as a scrollbar or widget.
-function onMouseDown(e) {
- var cm = this, display = cm.display;
- if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
- display.input.ensurePolled();
- display.shift = e.shiftKey;
-
- if (eventInWidget(display, e)) {
- if (!webkit) {
- // Briefly turn off draggability, to allow widgets to do
- // normal dragging things.
- display.scroller.draggable = false;
- setTimeout(function () { return display.scroller.draggable = true; }, 100);
- }
- return
- }
- if (clickInGutter(cm, e)) { return }
- var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
- window.focus();
-
- // #3261: make sure, that we're not starting a second selection
- if (button == 1 && cm.state.selectingText)
- { cm.state.selectingText(e); }
-
- if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
-
- if (button == 1) {
- if (pos) { leftButtonDown(cm, pos, repeat, e); }
- else if (e_target(e) == display.scroller) { e_preventDefault(e); }
- } else if (button == 2) {
- if (pos) { extendSelection(cm.doc, pos); }
- setTimeout(function () { return display.input.focus(); }, 20);
- } else if (button == 3) {
- if (captureRightClick) { onContextMenu(cm, e); }
- else { delayBlurEvent(cm); }
- }
-}
-
-function handleMappedButton(cm, button, pos, repeat, event) {
- var name = "Click";
- if (repeat == "double") { name = "Double" + name; }
- else if (repeat == "triple") { name = "Triple" + name; }
- name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
-
- return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
- if (typeof bound == "string") { bound = commands[bound]; }
- if (!bound) { return false }
- var done = false;
- try {
- if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
- done = bound(cm, pos) != Pass;
- } finally {
- cm.state.suppressEdits = false;
+ // UPDATING
+
+ // Allow "beforeChange" event handlers to influence a change
+ function filterChange(doc, change, update) {
+ var obj = {
+ canceled: false,
+ from: change.from,
+ to: change.to,
+ text: change.text,
+ origin: change.origin,
+ cancel: function () { return obj.canceled = true; }
+ };
+ if (update) { obj.update = function (from, to, text, origin) {
+ if (from) { obj.from = clipPos(doc, from); }
+ if (to) { obj.to = clipPos(doc, to); }
+ if (text) { obj.text = text; }
+ if (origin !== undefined) { obj.origin = origin; }
+ }; }
+ signal(doc, "beforeChange", doc, obj);
+ if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
+
+ if (obj.canceled) {
+ if (doc.cm) { doc.cm.curOp.updateInput = 2; }
+ return null
}
- return done
- })
-}
-
-function configureMouse(cm, repeat, event) {
- var option = cm.getOption("configureMouse");
- var value = option ? option(cm, repeat, event) : {};
- if (value.unit == null) {
- var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
- value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
- }
- if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
- if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
- if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
- return value
-}
-
-function leftButtonDown(cm, pos, repeat, event) {
- if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
- else { cm.curOp.focus = activeElt(); }
-
- var behavior = configureMouse(cm, repeat, event);
-
- var sel = cm.doc.sel, contained;
- if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
- repeat == "single" && (contained = sel.contains(pos)) > -1 &&
- (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
- (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
- { leftButtonStartDrag(cm, event, pos, behavior); }
- else
- { leftButtonSelect(cm, event, pos, behavior); }
-}
-
-// Start a text drag. When it ends, see if any dragging actually
-// happen, and treat as a click if it didn't.
-function leftButtonStartDrag(cm, event, pos, behavior) {
- var display = cm.display, moved = false;
- var dragEnd = operation(cm, function (e) {
- if (webkit) { display.scroller.draggable = false; }
- cm.state.draggingText = false;
- off(display.wrapper.ownerDocument, "mouseup", dragEnd);
- off(display.wrapper.ownerDocument, "mousemove", mouseMove);
- off(display.scroller, "dragstart", dragStart);
- off(display.scroller, "drop", dragEnd);
- if (!moved) {
- e_preventDefault(e);
- if (!behavior.addNew)
- { extendSelection(cm.doc, pos, null, null, behavior.extend); }
- // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
- if (webkit || ie && ie_version == 9)
- { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
- else
- { display.input.focus(); }
+ return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
+ }
+
+ // Apply a change to a document, and add it to the document's
+ // history, and propagating it to all linked documents.
+ function makeChange(doc, change, ignoreReadOnly) {
+ if (doc.cm) {
+ if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
+ if (doc.cm.state.suppressEdits) { return }
}
- });
- var mouseMove = function(e2) {
- moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
- };
- var dragStart = function () { return moved = true; };
- // Let the drag handler handle this.
- if (webkit) { display.scroller.draggable = true; }
- cm.state.draggingText = dragEnd;
- dragEnd.copy = !behavior.moveOnDrag;
- // IE's approach to draggable
- if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
- on(display.wrapper.ownerDocument, "mouseup", dragEnd);
- on(display.wrapper.ownerDocument, "mousemove", mouseMove);
- on(display.scroller, "dragstart", dragStart);
- on(display.scroller, "drop", dragEnd);
-
- delayBlurEvent(cm);
- setTimeout(function () { return display.input.focus(); }, 20);
-}
-
-function rangeForUnit(cm, pos, unit) {
- if (unit == "char") { return new Range(pos, pos) }
- if (unit == "word") { return cm.findWordAt(pos) }
- if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
- var result = unit(cm, pos);
- return new Range(result.from, result.to)
-}
-
-// Normal selection, as opposed to text dragging.
-function leftButtonSelect(cm, event, start, behavior) {
- var display = cm.display, doc = cm.doc;
- e_preventDefault(event);
-
- var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
- if (behavior.addNew && !behavior.extend) {
- ourIndex = doc.sel.contains(start);
- if (ourIndex > -1)
- { ourRange = ranges[ourIndex]; }
- else
- { ourRange = new Range(start, start); }
- } else {
- ourRange = doc.sel.primary();
- ourIndex = doc.sel.primIndex;
- }
-
- if (behavior.unit == "rectangle") {
- if (!behavior.addNew) { ourRange = new Range(start, start); }
- start = posFromMouse(cm, event, true, true);
- ourIndex = -1;
- } else {
- var range$$1 = rangeForUnit(cm, start, behavior.unit);
- if (behavior.extend)
- { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
- else
- { ourRange = range$$1; }
- }
-
- if (!behavior.addNew) {
- ourIndex = 0;
- setSelection(doc, new Selection([ourRange], 0), sel_mouse);
- startSel = doc.sel;
- } else if (ourIndex == -1) {
- ourIndex = ranges.length;
- setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
- {scroll: false, origin: "*mouse"});
- } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
- setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
- {scroll: false, origin: "*mouse"});
- startSel = doc.sel;
- } else {
- replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
- }
-
- var lastPos = start;
- function extendTo(pos) {
- if (cmp(lastPos, pos) == 0) { return }
- lastPos = pos;
- if (behavior.unit == "rectangle") {
- var ranges = [], tabSize = cm.options.tabSize;
- var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
- var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
- var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
- for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
- line <= end; line++) {
- var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
- if (left == right)
- { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
- else if (text.length > leftPos)
- { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
- }
- if (!ranges.length) { ranges.push(new Range(start, start)); }
- setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
- {origin: "*mouse", scroll: false});
- cm.scrollIntoView(pos);
- } else {
- var oldRange = ourRange;
- var range$$1 = rangeForUnit(cm, pos, behavior.unit);
- var anchor = oldRange.anchor, head;
- if (cmp(range$$1.anchor, anchor) > 0) {
- head = range$$1.head;
- anchor = minPos(oldRange.from(), range$$1.anchor);
- } else {
- head = range$$1.anchor;
- anchor = maxPos(oldRange.to(), range$$1.head);
- }
- var ranges$1 = startSel.ranges.slice(0);
- ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
- setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse);
- }
- }
-
- var editorSize = display.wrapper.getBoundingClientRect();
- // Used to ensure timeout re-tries don't fire when another extend
- // happened in the meantime (clearTimeout isn't reliable -- at
- // least on Chrome, the timeouts still happen even when cleared,
- // if the clear happens after their scheduled firing time).
- var counter = 0;
-
- function extend(e) {
- var curCount = ++counter;
- var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
- if (!cur) { return }
- if (cmp(cur, lastPos) != 0) {
- cm.curOp.focus = activeElt();
- extendTo(cur);
- var visible = visibleLines(display, doc);
- if (cur.line >= visible.to || cur.line < visible.from)
- { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
+ if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
+ change = filterChange(doc, change, true);
+ if (!change) { return }
+ }
+
+ // Possibly split or suppress the update based on the presence
+ // of read-only spans in its range.
+ var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
+ if (split) {
+ for (var i = split.length - 1; i >= 0; --i)
+ { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
} else {
- var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
- if (outside) { setTimeout(operation(cm, function () {
- if (counter != curCount) { return }
- display.scroller.scrollTop += outside;
- extend(e);
- }), 50); }
+ makeChangeInner(doc, change);
}
}
- function done(e) {
- cm.state.selectingText = false;
- counter = Infinity;
- e_preventDefault(e);
- display.input.focus();
- off(display.wrapper.ownerDocument, "mousemove", move);
- off(display.wrapper.ownerDocument, "mouseup", up);
- doc.history.lastSelOrigin = null;
+ function makeChangeInner(doc, change) {
+ if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
+ var selAfter = computeSelAfterChange(doc, change);
+ addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
+
+ makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
+ var rebased = [];
+
+ linkedDocs(doc, function (doc, sharedHist) {
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+ rebaseHist(doc.history, change);
+ rebased.push(doc.history);
+ }
+ makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
+ });
}
- var move = operation(cm, function (e) {
- if (e.buttons === 0 || !e_button(e)) { done(e); }
- else { extend(e); }
- });
- var up = operation(cm, done);
- cm.state.selectingText = up;
- on(display.wrapper.ownerDocument, "mousemove", move);
- on(display.wrapper.ownerDocument, "mouseup", up);
-}
-
-// Used when mouse-selecting to adjust the anchor to the proper side
-// of a bidi jump depending on the visual position of the head.
-function bidiSimplify(cm, range$$1) {
- var anchor = range$$1.anchor;
- var head = range$$1.head;
- var anchorLine = getLine(cm.doc, anchor.line);
- if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
- var order = getOrder(anchorLine);
- if (!order) { return range$$1 }
- var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
- if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
- var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
- if (boundary == 0 || boundary == order.length) { return range$$1 }
-
- // Compute the relative visual position of the head compared to the
- // anchor (<0 is to the left, >0 to the right)
- var leftSide;
- if (head.line != anchor.line) {
- leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
- } else {
- var headIndex = getBidiPartAt(order, head.ch, head.sticky);
- var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
- if (headIndex == boundary - 1 || headIndex == boundary)
- { leftSide = dir < 0; }
- else
- { leftSide = dir > 0; }
+ // Revert a change stored in a document's history.
+ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
+ var suppress = doc.cm && doc.cm.state.suppressEdits;
+ if (suppress && !allowSelectionOnly) { return }
+
+ var hist = doc.history, event, selAfter = doc.sel;
+ var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
+
+ // Verify that there is a useable event (so that ctrl-z won't
+ // needlessly clear selection events)
+ var i = 0;
+ for (; i < source.length; i++) {
+ event = source[i];
+ if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
+ { break }
+ }
+ if (i == source.length) { return }
+ hist.lastOrigin = hist.lastSelOrigin = null;
+
+ for (;;) {
+ event = source.pop();
+ if (event.ranges) {
+ pushSelectionToHistory(event, dest);
+ if (allowSelectionOnly && !event.equals(doc.sel)) {
+ setSelection(doc, event, {clearRedo: false});
+ return
+ }
+ selAfter = event;
+ } else if (suppress) {
+ source.push(event);
+ return
+ } else { break }
+ }
+
+ // Build up a reverse change object to add to the opposite history
+ // stack (redo when undoing, and vice versa).
+ var antiChanges = [];
+ pushSelectionToHistory(selAfter, dest);
+ dest.push({changes: antiChanges, generation: hist.generation});
+ hist.generation = event.generation || ++hist.maxGeneration;
+
+ var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
+
+ var loop = function ( i ) {
+ var change = event.changes[i];
+ change.origin = type;
+ if (filter && !filterChange(doc, change, false)) {
+ source.length = 0;
+ return {}
+ }
+
+ antiChanges.push(historyChangeFromChange(doc, change));
+
+ var after = i ? computeSelAfterChange(doc, change) : lst(source);
+ makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
+ if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
+ var rebased = [];
+
+ // Propagate to the linked documents
+ linkedDocs(doc, function (doc, sharedHist) {
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+ rebaseHist(doc.history, change);
+ rebased.push(doc.history);
+ }
+ makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
+ });
+ };
+
+ for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
+ var returned = loop( i$1 );
+
+ if ( returned ) return returned.v;
+ }
}
- var usePart = order[boundary + (leftSide ? -1 : 0)];
- var from = leftSide == (usePart.level == 1);
- var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
- return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
-}
+ // Sub-views need their line numbers shifted when text is added
+ // above or below them in the parent document.
+ function shiftDoc(doc, distance) {
+ if (distance == 0) { return }
+ doc.first += distance;
+ doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
+ Pos(range.anchor.line + distance, range.anchor.ch),
+ Pos(range.head.line + distance, range.head.ch)
+ ); }), doc.sel.primIndex);
+ if (doc.cm) {
+ regChange(doc.cm, doc.first, doc.first - distance, distance);
+ for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
+ { regLineChange(doc.cm, l, "gutter"); }
+ }
+ }
+ // More lower-level change function, handling only a single document
+ // (not linked ones).
+ function makeChangeSingleDoc(doc, change, selAfter, spans) {
+ if (doc.cm && !doc.cm.curOp)
+ { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
-// Determines whether an event happened in the gutter, and fires the
-// handlers for the corresponding event.
-function gutterEvent(cm, e, type, prevent) {
- var mX, mY;
- if (e.touches) {
- mX = e.touches[0].clientX;
- mY = e.touches[0].clientY;
- } else {
- try { mX = e.clientX; mY = e.clientY; }
- catch(e) { return false }
+ if (change.to.line < doc.first) {
+ shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
+ return
+ }
+ if (change.from.line > doc.lastLine()) { return }
+
+ // Clip the change to the size of this doc
+ if (change.from.line < doc.first) {
+ var shift = change.text.length - 1 - (doc.first - change.from.line);
+ shiftDoc(doc, shift);
+ change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
+ text: [lst(change.text)], origin: change.origin};
+ }
+ var last = doc.lastLine();
+ if (change.to.line > last) {
+ change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
+ text: [change.text[0]], origin: change.origin};
+ }
+
+ change.removed = getBetween(doc, change.from, change.to);
+
+ if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
+ if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
+ else { updateDoc(doc, change, spans); }
+ setSelectionNoUndo(doc, selAfter, sel_dontScroll);
}
- if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
- if (prevent) { e_preventDefault(e); }
- var display = cm.display;
- var lineBox = display.lineDiv.getBoundingClientRect();
+ // Handle the interaction of a change to a document with the editor
+ // that this document is part of.
+ function makeChangeSingleDocInEditor(cm, change, spans) {
+ var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
+
+ var recomputeMaxLength = false, checkWidthStart = from.line;
+ if (!cm.options.lineWrapping) {
+ checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
+ doc.iter(checkWidthStart, to.line + 1, function (line) {
+ if (line == display.maxLine) {
+ recomputeMaxLength = true;
+ return true
+ }
+ });
+ }
+
+ if (doc.sel.contains(change.from, change.to) > -1)
+ { signalCursorActivity(cm); }
+
+ updateDoc(doc, change, spans, estimateHeight(cm));
+
+ if (!cm.options.lineWrapping) {
+ doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
+ var len = lineLength(line);
+ if (len > display.maxLineLength) {
+ display.maxLine = line;
+ display.maxLineLength = len;
+ display.maxLineChanged = true;
+ recomputeMaxLength = false;
+ }
+ });
+ if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
+ }
- if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
- mY -= lineBox.top - display.viewOffset;
+ retreatFrontier(doc, from.line);
+ startWorker(cm, 400);
- for (var i = 0; i < cm.options.gutters.length; ++i) {
- var g = display.gutters.childNodes[i];
- if (g && g.getBoundingClientRect().right >= mX) {
- var line = lineAtHeight(cm.doc, mY);
- var gutter = cm.options.gutters[i];
- signal(cm, type, cm, line, gutter, e);
- return e_defaultPrevented(e)
+ var lendiff = change.text.length - (to.line - from.line) - 1;
+ // Remember that these lines changed, for updating the display
+ if (change.full)
+ { regChange(cm); }
+ else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
+ { regLineChange(cm, from.line, "text"); }
+ else
+ { regChange(cm, from.line, to.line + 1, lendiff); }
+
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
+ if (changeHandler || changesHandler) {
+ var obj = {
+ from: from, to: to,
+ text: change.text,
+ removed: change.removed,
+ origin: change.origin
+ };
+ if (changeHandler) { signalLater(cm, "change", cm, obj); }
+ if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
}
+ cm.display.selForContextMenu = null;
}
-}
-function clickInGutter(cm, e) {
- return gutterEvent(cm, e, "gutterClick", true)
-}
+ function replaceRange(doc, code, from, to, origin) {
+ var assign;
-// CONTEXT MENU HANDLING
+ if (!to) { to = from; }
+ if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); }
+ if (typeof code == "string") { code = doc.splitLines(code); }
+ makeChange(doc, {from: from, to: to, text: code, origin: origin});
+ }
-// To make the context menu work, we need to briefly unhide the
-// textarea (making it as unobtrusive as possible) to let the
-// right-click take effect on it.
-function onContextMenu(cm, e) {
- if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
- if (signalDOMEvent(cm, e, "contextmenu")) { return }
- cm.display.input.onContextMenu(e);
-}
+ // Rebasing/resetting history to deal with externally-sourced changes
-function contextMenuInGutter(cm, e) {
- if (!hasHandler(cm, "gutterContextMenu")) { return false }
- return gutterEvent(cm, e, "gutterContextMenu", false)
-}
+ function rebaseHistSelSingle(pos, from, to, diff) {
+ if (to < pos.line) {
+ pos.line += diff;
+ } else if (from < pos.line) {
+ pos.line = from;
+ pos.ch = 0;
+ }
+ }
-function themeChanged(cm) {
- cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
- cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
- clearCaches(cm);
-}
+ // Tries to rebase an array of history events given a change in the
+ // document. If the change touches the same lines as the event, the
+ // event, and everything 'behind' it, is discarded. If the change is
+ // before the event, the event's positions are updated. Uses a
+ // copy-on-write scheme for the positions, to avoid having to
+ // reallocate them all on every rebase, but also avoid problems with
+ // shared position objects being unsafely updated.
+ function rebaseHistArray(array, from, to, diff) {
+ for (var i = 0; i < array.length; ++i) {
+ var sub = array[i], ok = true;
+ if (sub.ranges) {
+ if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
+ for (var j = 0; j < sub.ranges.length; j++) {
+ rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
+ rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
+ }
+ continue
+ }
+ for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
+ var cur = sub.changes[j$1];
+ if (to < cur.from.line) {
+ cur.from = Pos(cur.from.line + diff, cur.from.ch);
+ cur.to = Pos(cur.to.line + diff, cur.to.ch);
+ } else if (from <= cur.to.line) {
+ ok = false;
+ break
+ }
+ }
+ if (!ok) {
+ array.splice(0, i + 1);
+ i = 0;
+ }
+ }
+ }
-var Init = {toString: function(){return "CodeMirror.Init"}};
+ function rebaseHist(hist, change) {
+ var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
+ rebaseHistArray(hist.done, from, to, diff);
+ rebaseHistArray(hist.undone, from, to, diff);
+ }
-var defaults = {};
-var optionHandlers = {};
+ // Utility for applying a change to a line by handle or number,
+ // returning the number and optionally registering the line as
+ // changed.
+ function changeLine(doc, handle, changeType, op) {
+ var no = handle, line = handle;
+ if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
+ else { no = lineNo(handle); }
+ if (no == null) { return null }
+ if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
+ return line
+ }
-function defineOptions(CodeMirror) {
- var optionHandlers = CodeMirror.optionHandlers;
+ // The document is represented as a BTree consisting of leaves, with
+ // chunk of lines in them, and branches, with up to ten leaves or
+ // other branch nodes below them. The top node is always a branch
+ // node, and is the document object itself (meaning it has
+ // additional methods and properties).
+ //
+ // All nodes have parent links. The tree is used both to go from
+ // line numbers to line objects, and to go from objects to numbers.
+ // It also indexes by height, and is used to convert between height
+ // and line object, and to find the total height of the document.
+ //
+ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
- function option(name, deflt, handle, notOnInit) {
- CodeMirror.defaults[name] = deflt;
- if (handle) { optionHandlers[name] =
- notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
+ function LeafChunk(lines) {
+ this.lines = lines;
+ this.parent = null;
+ var height = 0;
+ for (var i = 0; i < lines.length; ++i) {
+ lines[i].parent = this;
+ height += lines[i].height;
+ }
+ this.height = height;
}
- CodeMirror.defineOption = option;
+ LeafChunk.prototype = {
+ chunkSize: function() { return this.lines.length },
- // Passed to option handlers when there is no old value.
- CodeMirror.Init = Init;
+ // Remove the n lines at offset 'at'.
+ removeInner: function(at, n) {
+ for (var i = at, e = at + n; i < e; ++i) {
+ var line = this.lines[i];
+ this.height -= line.height;
+ cleanUpLine(line);
+ signalLater(line, "delete");
+ }
+ this.lines.splice(at, n);
+ },
- // These two are, on init, called from the constructor because they
- // have to be initialized before the editor can start at all.
- option("value", "", function (cm, val) { return cm.setValue(val); }, true);
- option("mode", null, function (cm, val) {
- cm.doc.modeOption = val;
- loadMode(cm);
- }, true);
+ // Helper used to collapse a small branch into a single leaf.
+ collapse: function(lines) {
+ lines.push.apply(lines, this.lines);
+ },
- option("indentUnit", 2, loadMode, true);
- option("indentWithTabs", false);
- option("smartIndent", true);
- option("tabSize", 4, function (cm) {
- resetModeState(cm);
- clearCaches(cm);
- regChange(cm);
- }, true);
+ // Insert the given array of lines at offset 'at', count them as
+ // having the given height.
+ insertInner: function(at, lines, height) {
+ this.height += height;
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
+ for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; }
+ },
- option("lineSeparator", null, function (cm, val) {
- cm.doc.lineSep = val;
- if (!val) { return }
- var newBreaks = [], lineNo = cm.doc.first;
- cm.doc.iter(function (line) {
- for (var pos = 0;;) {
- var found = line.text.indexOf(val, pos);
- if (found == -1) { break }
- pos = found + val.length;
- newBreaks.push(Pos(lineNo, found));
+ // Used to iterate over a part of the tree.
+ iterN: function(at, n, op) {
+ for (var e = at + n; at < e; ++at)
+ { if (op(this.lines[at])) { return true } }
+ }
+ };
+
+ function BranchChunk(children) {
+ this.children = children;
+ var size = 0, height = 0;
+ for (var i = 0; i < children.length; ++i) {
+ var ch = children[i];
+ size += ch.chunkSize(); height += ch.height;
+ ch.parent = this;
+ }
+ this.size = size;
+ this.height = height;
+ this.parent = null;
+ }
+
+ BranchChunk.prototype = {
+ chunkSize: function() { return this.size },
+
+ removeInner: function(at, n) {
+ this.size -= n;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var rm = Math.min(n, sz - at), oldHeight = child.height;
+ child.removeInner(at, rm);
+ this.height -= oldHeight - child.height;
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
+ if ((n -= rm) == 0) { break }
+ at = 0;
+ } else { at -= sz; }
+ }
+ // If the result is smaller than 25 lines, ensure that it is a
+ // single leaf node.
+ if (this.size - n < 25 &&
+ (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
+ var lines = [];
+ this.collapse(lines);
+ this.children = [new LeafChunk(lines)];
+ this.children[0].parent = this;
+ }
+ },
+
+ collapse: function(lines) {
+ for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); }
+ },
+
+ insertInner: function(at, lines, height) {
+ this.size += lines.length;
+ this.height += height;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at <= sz) {
+ child.insertInner(at, lines, height);
+ if (child.lines && child.lines.length > 50) {
+ // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
+ // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
+ var remaining = child.lines.length % 25 + 25;
+ for (var pos = remaining; pos < child.lines.length;) {
+ var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
+ child.height -= leaf.height;
+ this.children.splice(++i, 0, leaf);
+ leaf.parent = this;
+ }
+ child.lines = child.lines.slice(0, remaining);
+ this.maybeSpill();
+ }
+ break
+ }
+ at -= sz;
+ }
+ },
+
+ // When a node has grown, check whether it should be split.
+ maybeSpill: function() {
+ if (this.children.length <= 10) { return }
+ var me = this;
+ do {
+ var spilled = me.children.splice(me.children.length - 5, 5);
+ var sibling = new BranchChunk(spilled);
+ if (!me.parent) { // Become the parent node
+ var copy = new BranchChunk(me.children);
+ copy.parent = me;
+ me.children = [copy, sibling];
+ me = copy;
+ } else {
+ me.size -= sibling.size;
+ me.height -= sibling.height;
+ var myIndex = indexOf(me.parent.children, me);
+ me.parent.children.splice(myIndex + 1, 0, sibling);
+ }
+ sibling.parent = me.parent;
+ } while (me.children.length > 10)
+ me.parent.maybeSpill();
+ },
+
+ iterN: function(at, n, op) {
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var used = Math.min(n, sz - at);
+ if (child.iterN(at, used, op)) { return true }
+ if ((n -= used) == 0) { break }
+ at = 0;
+ } else { at -= sz; }
}
- lineNo++;
- });
- for (var i = newBreaks.length - 1; i >= 0; i--)
- { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
- });
- option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
- cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
- if (old != Init) { cm.refresh(); }
- });
- option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
- option("electricChars", true);
- option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
- throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
- }, true);
- option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
- option("rtlMoveVisually", !windows);
- option("wholeLineUpdateBefore", true);
-
- option("theme", "default", function (cm) {
- themeChanged(cm);
- guttersChanged(cm);
- }, true);
- option("keyMap", "default", function (cm, val, old) {
- var next = getKeyMap(val);
- var prev = old != Init && getKeyMap(old);
- if (prev && prev.detach) { prev.detach(cm, next); }
- if (next.attach) { next.attach(cm, prev || null); }
- });
- option("extraKeys", null);
- option("configureMouse", null);
-
- option("lineWrapping", false, wrappingChanged, true);
- option("gutters", [], function (cm) {
- setGuttersForLineNumbers(cm.options);
- guttersChanged(cm);
- }, true);
- option("fixedGutter", true, function (cm, val) {
- cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
- cm.refresh();
- }, true);
- option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
- option("scrollbarStyle", "native", function (cm) {
- initScrollbars(cm);
- updateScrollbars(cm);
- cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
- cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
- }, true);
- option("lineNumbers", false, function (cm) {
- setGuttersForLineNumbers(cm.options);
- guttersChanged(cm);
- }, true);
- option("firstLineNumber", 1, guttersChanged, true);
- option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
- option("showCursorWhenSelecting", false, updateSelection, true);
-
- option("resetSelectionOnContextMenu", true);
- option("lineWiseCopyCut", true);
- option("pasteLinesPerSelection", true);
-
- option("readOnly", false, function (cm, val) {
- if (val == "nocursor") {
- onBlur(cm);
- cm.display.input.blur();
}
- cm.display.input.readOnlyChanged(val);
- });
- option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
- option("dragDrop", true, dragDropChanged);
- option("allowDropFileTypes", null);
-
- option("cursorBlinkRate", 530);
- option("cursorScrollMargin", 0);
- option("cursorHeight", 1, updateSelection, true);
- option("singleCursorHeightPerLine", true, updateSelection, true);
- option("workTime", 100);
- option("workDelay", 100);
- option("flattenSpans", true, resetModeState, true);
- option("addModeClass", false, resetModeState, true);
- option("pollInterval", 100);
- option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
- option("historyEventDelay", 1250);
- option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
- option("maxHighlightLength", 10000, resetModeState, true);
- option("moveInputWithCursor", true, function (cm, val) {
- if (!val) { cm.display.input.resetPosition(); }
- });
+ };
- option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
- option("autofocus", null);
- option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
- option("phrases", null);
-}
-
-function guttersChanged(cm) {
- updateGutters(cm);
- regChange(cm);
- alignHorizontally(cm);
-}
-
-function dragDropChanged(cm, value, old) {
- var wasOn = old && old != Init;
- if (!value != !wasOn) {
- var funcs = cm.display.dragFunctions;
- var toggle = value ? on : off;
- toggle(cm.display.scroller, "dragstart", funcs.start);
- toggle(cm.display.scroller, "dragenter", funcs.enter);
- toggle(cm.display.scroller, "dragover", funcs.over);
- toggle(cm.display.scroller, "dragleave", funcs.leave);
- toggle(cm.display.scroller, "drop", funcs.drop);
- }
-}
-
-function wrappingChanged(cm) {
- if (cm.options.lineWrapping) {
- addClass(cm.display.wrapper, "CodeMirror-wrap");
- cm.display.sizer.style.minWidth = "";
- cm.display.sizerWidth = null;
- } else {
- rmClass(cm.display.wrapper, "CodeMirror-wrap");
- findMaxLine(cm);
- }
- estimateLineHeights(cm);
- regChange(cm);
- clearCaches(cm);
- setTimeout(function () { return updateScrollbars(cm); }, 100);
-}
-
-// A CodeMirror instance represents an editor. This is the object
-// that user code is usually dealing with.
-
-function CodeMirror$1(place, options) {
- var this$1 = this;
-
- if (!(this instanceof CodeMirror$1)) { return new CodeMirror$1(place, options) }
-
- this.options = options = options ? copyObj(options) : {};
- // Determine effective options based on given values and defaults.
- copyObj(defaults, options, false);
- setGuttersForLineNumbers(options);
-
- var doc = options.value;
- if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
- else if (options.mode) { doc.modeOption = options.mode; }
- this.doc = doc;
-
- var input = new CodeMirror$1.inputStyles[options.inputStyle](this);
- var display = this.display = new Display(place, doc, input);
- display.wrapper.CodeMirror = this;
- updateGutters(this);
- themeChanged(this);
- if (options.lineWrapping)
- { this.display.wrapper.className += " CodeMirror-wrap"; }
- initScrollbars(this);
-
- this.state = {
- keyMaps: [], // stores maps added by addKeyMap
- overlays: [], // highlighting overlays, as added by addOverlay
- modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
- overwrite: false,
- delayingBlurEvent: false,
- focused: false,
- suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
- pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
- selectingText: false,
- draggingText: false,
- highlight: new Delayed(), // stores highlight worker timeout
- keySeq: null, // Unfinished key sequence
- specialChars: null
+ // Line widgets are block elements displayed above or below a line.
+
+ var LineWidget = function(doc, node, options) {
+ if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
+ { this[opt] = options[opt]; } } }
+ this.doc = doc;
+ this.node = node;
};
- if (options.autofocus && !mobile) { display.input.focus(); }
-
- // Override magic textarea content restore that IE sometimes does
- // on our hidden textarea on reload
- if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
-
- registerEventHandlers(this);
- ensureGlobalHandlers();
-
- startOperation(this);
- this.curOp.forceUpdate = true;
- attachDoc(this, doc);
-
- if ((options.autofocus && !mobile) || this.hasFocus())
- { setTimeout(bind(onFocus, this), 20); }
- else
- { onBlur(this); }
-
- for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
- { optionHandlers[opt](this$1, options[opt], Init); } }
- maybeUpdateLineNumberWidth(this);
- if (options.finishInit) { options.finishInit(this); }
- for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
- endOperation(this);
- // Suppress optimizelegibility in Webkit, since it breaks text
- // measuring on line wrapping boundaries.
- if (webkit && options.lineWrapping &&
- getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
- { display.lineDiv.style.textRendering = "auto"; }
-}
-
-// The default configuration options.
-CodeMirror$1.defaults = defaults;
-// Functions to run when options are changed.
-CodeMirror$1.optionHandlers = optionHandlers;
-
-// Attach the necessary event handlers when initializing the editor
-function registerEventHandlers(cm) {
- var d = cm.display;
- on(d.scroller, "mousedown", operation(cm, onMouseDown));
- // Older IE's will not fire a second mousedown for a double click
- if (ie && ie_version < 11)
- { on(d.scroller, "dblclick", operation(cm, function (e) {
- if (signalDOMEvent(cm, e)) { return }
- var pos = posFromMouse(cm, e);
- if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
- e_preventDefault(e);
- var word = cm.findWordAt(pos);
- extendSelection(cm.doc, word.anchor, word.head);
- })); }
- else
- { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
- // Some browsers fire contextmenu *after* opening the menu, at
- // which point we can't mess with it anymore. Context menu is
- // handled in onMouseDown for these browsers.
- if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); }
-
- // Used to suppress mouse event handling when a touch happens
- var touchFinished, prevTouch = {end: 0};
- function finishTouch() {
- if (d.activeTouch) {
- touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
- prevTouch = d.activeTouch;
- prevTouch.end = +new Date;
- }
- }
- function isMouseLikeTouchEvent(e) {
- if (e.touches.length != 1) { return false }
- var touch = e.touches[0];
- return touch.radiusX <= 1 && touch.radiusY <= 1
- }
- function farAway(touch, other) {
- if (other.left == null) { return true }
- var dx = other.left - touch.left, dy = other.top - touch.top;
- return dx * dx + dy * dy > 20 * 20
- }
- on(d.scroller, "touchstart", function (e) {
- if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
- d.input.ensurePolled();
- clearTimeout(touchFinished);
- var now = +new Date;
- d.activeTouch = {start: now, moved: false,
- prev: now - prevTouch.end <= 300 ? prevTouch : null};
- if (e.touches.length == 1) {
- d.activeTouch.left = e.touches[0].pageX;
- d.activeTouch.top = e.touches[0].pageY;
+ LineWidget.prototype.clear = function () {
+ var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
+ if (no == null || !ws) { return }
+ for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } }
+ if (!ws.length) { line.widgets = null; }
+ var height = widgetHeight(this);
+ updateLineHeight(line, Math.max(0, line.height - height));
+ if (cm) {
+ runInOp(cm, function () {
+ adjustScrollWhenAboveVisible(cm, line, -height);
+ regLineChange(cm, no, "widget");
+ });
+ signalLater(cm, "lineWidgetCleared", cm, this, no);
+ }
+ };
+
+ LineWidget.prototype.changed = function () {
+ var this$1 = this;
+
+ var oldH = this.height, cm = this.doc.cm, line = this.line;
+ this.height = null;
+ var diff = widgetHeight(this) - oldH;
+ if (!diff) { return }
+ if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }
+ if (cm) {
+ runInOp(cm, function () {
+ cm.curOp.forceUpdate = true;
+ adjustScrollWhenAboveVisible(cm, line, diff);
+ signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
+ });
+ }
+ };
+ eventMixin(LineWidget);
+
+ function adjustScrollWhenAboveVisible(cm, line, diff) {
+ if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
+ { addToScrollTop(cm, diff); }
+ }
+
+ function addLineWidget(doc, handle, node, options) {
+ var widget = new LineWidget(doc, node, options);
+ var cm = doc.cm;
+ if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
+ changeLine(doc, handle, "widget", function (line) {
+ var widgets = line.widgets || (line.widgets = []);
+ if (widget.insertAt == null) { widgets.push(widget); }
+ else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
+ widget.line = line;
+ if (cm && !lineIsHidden(doc, line)) {
+ var aboveVisible = heightAtLine(line) < doc.scrollTop;
+ updateLineHeight(line, line.height + widgetHeight(widget));
+ if (aboveVisible) { addToScrollTop(cm, widget.height); }
+ cm.curOp.forceUpdate = true;
+ }
+ return true
+ });
+ if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); }
+ return widget
+ }
+
+ // TEXTMARKERS
+
+ // Created with markText and setBookmark methods. A TextMarker is a
+ // handle that can be used to clear or find a marked position in the
+ // document. Line objects hold arrays (markedSpans) containing
+ // {from, to, marker} object pointing to such marker objects, and
+ // indicating that such a marker is present on that line. Multiple
+ // lines may point to the same marker when it spans across lines.
+ // The spans will have null for their from/to properties when the
+ // marker continues beyond the start/end of the line. Markers have
+ // links back to the lines they currently touch.
+
+ // Collapsed markers have unique ids, in order to be able to order
+ // them, which is needed for uniquely determining an outer marker
+ // when they overlap (they may nest, but not partially overlap).
+ var nextMarkerId = 0;
+
+ var TextMarker = function(doc, type) {
+ this.lines = [];
+ this.type = type;
+ this.doc = doc;
+ this.id = ++nextMarkerId;
+ };
+
+ // Clear the marker.
+ TextMarker.prototype.clear = function () {
+ if (this.explicitlyCleared) { return }
+ var cm = this.doc.cm, withOp = cm && !cm.curOp;
+ if (withOp) { startOperation(cm); }
+ if (hasHandler(this, "clear")) {
+ var found = this.find();
+ if (found) { signalLater(this, "clear", found.from, found.to); }
+ }
+ var min = null, max = null;
+ for (var i = 0; i < this.lines.length; ++i) {
+ var line = this.lines[i];
+ var span = getMarkedSpanFor(line.markedSpans, this);
+ if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); }
+ else if (cm) {
+ if (span.to != null) { max = lineNo(line); }
+ if (span.from != null) { min = lineNo(line); }
+ }
+ line.markedSpans = removeMarkedSpan(line.markedSpans, span);
+ if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
+ { updateLineHeight(line, textHeight(cm.display)); }
+ }
+ if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
+ var visual = visualLine(this.lines[i$1]), len = lineLength(visual);
+ if (len > cm.display.maxLineLength) {
+ cm.display.maxLine = visual;
+ cm.display.maxLineLength = len;
+ cm.display.maxLineChanged = true;
}
+ } }
+
+ if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
+ this.lines.length = 0;
+ this.explicitlyCleared = true;
+ if (this.atomic && this.doc.cantEdit) {
+ this.doc.cantEdit = false;
+ if (cm) { reCheckSelection(cm.doc); }
}
- });
- on(d.scroller, "touchmove", function () {
- if (d.activeTouch) { d.activeTouch.moved = true; }
- });
- on(d.scroller, "touchend", function (e) {
- var touch = d.activeTouch;
- if (touch && !eventInWidget(d, e) && touch.left != null &&
- !touch.moved && new Date - touch.start < 300) {
- var pos = cm.coordsChar(d.activeTouch, "page"), range;
- if (!touch.prev || farAway(touch, touch.prev)) // Single tap
- { range = new Range(pos, pos); }
- else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
- { range = cm.findWordAt(pos); }
- else // Triple tap
- { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
- cm.setSelection(range.anchor, range.head);
- cm.focus();
- e_preventDefault(e);
+ if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
+ if (withOp) { endOperation(cm); }
+ if (this.parent) { this.parent.clear(); }
+ };
+
+ // Find the position of the marker in the document. Returns a {from,
+ // to} object by default. Side can be passed to get a specific side
+ // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
+ // Pos objects returned contain a line object, rather than a line
+ // number (used to prevent looking up the same line twice).
+ TextMarker.prototype.find = function (side, lineObj) {
+ if (side == null && this.type == "bookmark") { side = 1; }
+ var from, to;
+ for (var i = 0; i < this.lines.length; ++i) {
+ var line = this.lines[i];
+ var span = getMarkedSpanFor(line.markedSpans, this);
+ if (span.from != null) {
+ from = Pos(lineObj ? line : lineNo(line), span.from);
+ if (side == -1) { return from }
+ }
+ if (span.to != null) {
+ to = Pos(lineObj ? line : lineNo(line), span.to);
+ if (side == 1) { return to }
+ }
}
- finishTouch();
- });
- on(d.scroller, "touchcancel", finishTouch);
+ return from && {from: from, to: to}
+ };
+
+ // Signals that the marker's widget changed, and surrounding layout
+ // should be recomputed.
+ TextMarker.prototype.changed = function () {
+ var this$1 = this;
- // Sync scrolling between fake scrollbars and real scrollable
- // area, ensure viewport is updated when scrolling.
- on(d.scroller, "scroll", function () {
- if (d.scroller.clientHeight) {
- updateScrollTop(cm, d.scroller.scrollTop);
- setScrollLeft(cm, d.scroller.scrollLeft, true);
- signal(cm, "scroll", cm);
+ var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
+ if (!pos || !cm) { return }
+ runInOp(cm, function () {
+ var line = pos.line, lineN = lineNo(pos.line);
+ var view = findViewForLine(cm, lineN);
+ if (view) {
+ clearLineMeasurementCacheFor(view);
+ cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
+ }
+ cm.curOp.updateMaxLine = true;
+ if (!lineIsHidden(widget.doc, line) && widget.height != null) {
+ var oldHeight = widget.height;
+ widget.height = null;
+ var dHeight = widgetHeight(widget) - oldHeight;
+ if (dHeight)
+ { updateLineHeight(line, line.height + dHeight); }
+ }
+ signalLater(cm, "markerChanged", cm, this$1);
+ });
+ };
+
+ TextMarker.prototype.attachLine = function (line) {
+ if (!this.lines.length && this.doc.cm) {
+ var op = this.doc.cm.curOp;
+ if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
+ { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
}
- });
+ this.lines.push(line);
+ };
- // Listen to wheel events in order to try and update the viewport on time.
- on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
- on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
+ TextMarker.prototype.detachLine = function (line) {
+ this.lines.splice(indexOf(this.lines, line), 1);
+ if (!this.lines.length && this.doc.cm) {
+ var op = this.doc.cm.curOp
+ ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
+ }
+ };
+ eventMixin(TextMarker);
+
+ // Create a marker, wire it up to the right lines, and
+ function markText(doc, from, to, options, type) {
+ // Shared markers (across linked documents) are handled separately
+ // (markTextShared will call out to this again, once per
+ // document).
+ if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
+ // Ensure we are in an operation.
+ if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
+
+ var marker = new TextMarker(doc, type), diff = cmp(from, to);
+ if (options) { copyObj(options, marker, false); }
+ // Don't connect empty markers unless clearWhenEmpty is false
+ if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
+ { return marker }
+ if (marker.replacedWith) {
+ // Showing up as a widget implies collapsed (widget replaces text)
+ marker.collapsed = true;
+ marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
+ if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
+ if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
+ }
+ if (marker.collapsed) {
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
+ { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
+ seeCollapsedSpans();
+ }
+
+ if (marker.addToHistory)
+ { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
+
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
+ doc.iter(curLine, to.line + 1, function (line) {
+ if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
+ { updateMaxLine = true; }
+ if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
+ addMarkedSpan(line, new MarkedSpan(marker,
+ curLine == from.line ? from.ch : null,
+ curLine == to.line ? to.ch : null));
+ ++curLine;
+ });
+ // lineIsHidden depends on the presence of the spans, so needs a second pass
+ if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
+ if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
+ }); }
+
+ if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
+
+ if (marker.readOnly) {
+ seeReadOnlySpans();
+ if (doc.history.done.length || doc.history.undone.length)
+ { doc.clearHistory(); }
+ }
+ if (marker.collapsed) {
+ marker.id = ++nextMarkerId;
+ marker.atomic = true;
+ }
+ if (cm) {
+ // Sync editor state
+ if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
+ if (marker.collapsed)
+ { regChange(cm, from.line, to.line + 1); }
+ else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
+ marker.attributes || marker.title)
+ { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
+ if (marker.atomic) { reCheckSelection(cm.doc); }
+ signalLater(cm, "markerAdded", cm, marker);
+ }
+ return marker
+ }
+
+ // SHARED TEXTMARKERS
+
+ // A shared marker spans multiple linked documents. It is
+ // implemented as a meta-marker-object controlling multiple normal
+ // markers.
+ var SharedTextMarker = function(markers, primary) {
+ this.markers = markers;
+ this.primary = primary;
+ for (var i = 0; i < markers.length; ++i)
+ { markers[i].parent = this; }
+ };
- // Prevent wrapper from ever scrolling
- on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
+ SharedTextMarker.prototype.clear = function () {
+ if (this.explicitlyCleared) { return }
+ this.explicitlyCleared = true;
+ for (var i = 0; i < this.markers.length; ++i)
+ { this.markers[i].clear(); }
+ signalLater(this, "clear");
+ };
- d.dragFunctions = {
- enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
- over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
- start: function (e) { return onDragStart(cm, e); },
- drop: operation(cm, onDrop),
- leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
+ SharedTextMarker.prototype.find = function (side, lineObj) {
+ return this.primary.find(side, lineObj)
};
+ eventMixin(SharedTextMarker);
+
+ function markTextShared(doc, from, to, options, type) {
+ options = copyObj(options);
+ options.shared = false;
+ var markers = [markText(doc, from, to, options, type)], primary = markers[0];
+ var widget = options.widgetNode;
+ linkedDocs(doc, function (doc) {
+ if (widget) { options.widgetNode = widget.cloneNode(true); }
+ markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
+ for (var i = 0; i < doc.linked.length; ++i)
+ { if (doc.linked[i].isParent) { return } }
+ primary = lst(markers);
+ });
+ return new SharedTextMarker(markers, primary)
+ }
- var inp = d.input.getField();
- on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
- on(inp, "keydown", operation(cm, onKeyDown));
- on(inp, "keypress", operation(cm, onKeyPress));
- on(inp, "focus", function (e) { return onFocus(cm, e); });
- on(inp, "blur", function (e) { return onBlur(cm, e); });
-}
-
-var initHooks = [];
-CodeMirror$1.defineInitHook = function (f) { return initHooks.push(f); };
-
-// Indent the given line. The how parameter can be "smart",
-// "add"/null, "subtract", or "prev". When aggressive is false
-// (typically set to true for forced single-line indents), empty
-// lines are not indented, and places where the mode returns Pass
-// are left alone.
-function indentLine(cm, n, how, aggressive) {
- var doc = cm.doc, state;
- if (how == null) { how = "add"; }
- if (how == "smart") {
- // Fall back to "prev" when the mode doesn't have an indentation
- // method.
- if (!doc.mode.indent) { how = "prev"; }
- else { state = getContextBefore(cm, n).state; }
- }
-
- var tabSize = cm.options.tabSize;
- var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
- if (line.stateAfter) { line.stateAfter = null; }
- var curSpaceString = line.text.match(/^\s*/)[0], indentation;
- if (!aggressive && !/\S/.test(line.text)) {
- indentation = 0;
- how = "not";
- } else if (how == "smart") {
- indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
- if (indentation == Pass || indentation > 150) {
- if (!aggressive) { return }
- how = "prev";
- }
- }
- if (how == "prev") {
- if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
- else { indentation = 0; }
- } else if (how == "add") {
- indentation = curSpace + cm.options.indentUnit;
- } else if (how == "subtract") {
- indentation = curSpace - cm.options.indentUnit;
- } else if (typeof how == "number") {
- indentation = curSpace + how;
- }
- indentation = Math.max(0, indentation);
-
- var indentString = "", pos = 0;
- if (cm.options.indentWithTabs)
- { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
- if (pos < indentation) { indentString += spaceStr(indentation - pos); }
-
- if (indentString != curSpaceString) {
- replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
- line.stateAfter = null;
- return true
- } else {
- // Ensure that, if the cursor was in the whitespace at the start
- // of the line, it is moved to the end of that space.
- for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
- var range = doc.sel.ranges[i$1];
- if (range.head.line == n && range.head.ch < curSpaceString.length) {
- var pos$1 = Pos(n, curSpaceString.length);
- replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
- break
+ function findSharedMarkers(doc) {
+ return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
+ }
+
+ function copySharedMarkers(doc, markers) {
+ for (var i = 0; i < markers.length; i++) {
+ var marker = markers[i], pos = marker.find();
+ var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
+ if (cmp(mFrom, mTo)) {
+ var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
+ marker.markers.push(subMark);
+ subMark.parent = marker;
}
}
}
-}
-
-// This will be set to a {lineWise: bool, text: [string]} object, so
-// that, when pasting, we know what kind of selections the copied
-// text was made out of.
-var lastCopied = null;
-
-function setLastCopied(newLastCopied) {
- lastCopied = newLastCopied;
-}
-
-function applyTextInput(cm, inserted, deleted, sel, origin) {
- var doc = cm.doc;
- cm.display.shift = false;
- if (!sel) { sel = doc.sel; }
-
- var paste = cm.state.pasteIncoming || origin == "paste";
- var textLines = splitLinesAuto(inserted), multiPaste = null;
- // When pasting N lines into N selections, insert one line per selection
- if (paste && sel.ranges.length > 1) {
- if (lastCopied && lastCopied.text.join("\n") == inserted) {
- if (sel.ranges.length % lastCopied.text.length == 0) {
- multiPaste = [];
- for (var i = 0; i < lastCopied.text.length; i++)
- { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
- }
- } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
- multiPaste = map(textLines, function (l) { return [l]; });
- }
- }
-
- var updateInput;
- // Normal behavior is to insert the new text into every selection
- for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
- var range$$1 = sel.ranges[i$1];
- var from = range$$1.from(), to = range$$1.to();
- if (range$$1.empty()) {
- if (deleted && deleted > 0) // Handle deletion
- { from = Pos(from.line, from.ch - deleted); }
- else if (cm.state.overwrite && !paste) // Handle overwrite
- { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
- else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
- { from = to = Pos(from.line, 0); }
- }
- updateInput = cm.curOp.updateInput;
- var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
- origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
- makeChange(cm.doc, changeEvent);
- signalLater(cm, "inputRead", cm, changeEvent);
- }
- if (inserted && !paste)
- { triggerElectric(cm, inserted); }
-
- ensureCursorVisible(cm);
- cm.curOp.updateInput = updateInput;
- cm.curOp.typing = true;
- cm.state.pasteIncoming = cm.state.cutIncoming = false;
-}
-
-function handlePaste(e, cm) {
- var pasted = e.clipboardData && e.clipboardData.getData("Text");
- if (pasted) {
- e.preventDefault();
- if (!cm.isReadOnly() && !cm.options.disableInput)
- { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
- return true
- }
-}
-
-function triggerElectric(cm, inserted) {
- // When an 'electric' character is inserted, immediately trigger a reindent
- if (!cm.options.electricChars || !cm.options.smartIndent) { return }
- var sel = cm.doc.sel;
-
- for (var i = sel.ranges.length - 1; i >= 0; i--) {
- var range$$1 = sel.ranges[i];
- if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
- var mode = cm.getModeAt(range$$1.head);
- var indented = false;
- if (mode.electricChars) {
- for (var j = 0; j < mode.electricChars.length; j++)
- { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
- indented = indentLine(cm, range$$1.head.line, "smart");
- break
- } }
- } else if (mode.electricInput) {
- if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
- { indented = indentLine(cm, range$$1.head.line, "smart"); }
- }
- if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
- }
-}
-
-function copyableRanges(cm) {
- var text = [], ranges = [];
- for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
- var line = cm.doc.sel.ranges[i].head.line;
- var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
- ranges.push(lineRange);
- text.push(cm.getRange(lineRange.anchor, lineRange.head));
- }
- return {text: text, ranges: ranges}
-}
-
-function disableBrowserMagic(field, spellcheck) {
- field.setAttribute("autocorrect", "off");
- field.setAttribute("autocapitalize", "off");
- field.setAttribute("spellcheck", !!spellcheck);
-}
-
-function hiddenTextarea() {
- var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
- var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
- // The textarea is kept positioned near the cursor to prevent the
- // fact that it'll be scrolled into view on input from scrolling
- // our fake cursor out of view. On webkit, when wrap=off, paste is
- // very slow. So make the area wide instead.
- if (webkit) { te.style.width = "1000px"; }
- else { te.setAttribute("wrap", "off"); }
- // If border: 0; -- iOS fails to open keyboard (issue #1287)
- if (ios) { te.style.border = "1px solid black"; }
- disableBrowserMagic(te);
- return div
-}
-
-// The publicly visible API. Note that methodOp(f) means
-// 'wrap f in an operation, performed on its `this` parameter'.
-
-// This is not the complete set of editor methods. Most of the
-// methods defined on the Doc type are also injected into
-// CodeMirror.prototype, for backwards compatibility and
-// convenience.
-
-var addEditorMethods = function(CodeMirror) {
- var optionHandlers = CodeMirror.optionHandlers;
-
- var helpers = CodeMirror.helpers = {};
-
- CodeMirror.prototype = {
- constructor: CodeMirror,
- focus: function(){window.focus(); this.display.input.focus();},
-
- setOption: function(option, value) {
- var options = this.options, old = options[option];
- if (options[option] == value && option != "mode") { return }
- options[option] = value;
- if (optionHandlers.hasOwnProperty(option))
- { operation(this, optionHandlers[option])(this, value, old); }
- signal(this, "optionChange", this, option);
+
+ function detachSharedMarkers(markers) {
+ var loop = function ( i ) {
+ var marker = markers[i], linked = [marker.primary.doc];
+ linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
+ for (var j = 0; j < marker.markers.length; j++) {
+ var subMarker = marker.markers[j];
+ if (indexOf(linked, subMarker.doc) == -1) {
+ subMarker.parent = null;
+ marker.markers.splice(j--, 1);
+ }
+ }
+ };
+
+ for (var i = 0; i < markers.length; i++) loop( i );
+ }
+
+ var nextDocId = 0;
+ var Doc = function(text, mode, firstLine, lineSep, direction) {
+ if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
+ if (firstLine == null) { firstLine = 0; }
+
+ BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
+ this.first = firstLine;
+ this.scrollTop = this.scrollLeft = 0;
+ this.cantEdit = false;
+ this.cleanGeneration = 1;
+ this.modeFrontier = this.highlightFrontier = firstLine;
+ var start = Pos(firstLine, 0);
+ this.sel = simpleSelection(start);
+ this.history = new History(null);
+ this.id = ++nextDocId;
+ this.modeOption = mode;
+ this.lineSep = lineSep;
+ this.direction = (direction == "rtl") ? "rtl" : "ltr";
+ this.extend = false;
+
+ if (typeof text == "string") { text = this.splitLines(text); }
+ updateDoc(this, {from: start, to: start, text: text});
+ setSelection(this, simpleSelection(start), sel_dontScroll);
+ };
+
+ Doc.prototype = createObj(BranchChunk.prototype, {
+ constructor: Doc,
+ // Iterate over the document. Supports two forms -- with only one
+ // argument, it calls that for each line in the document. With
+ // three, it iterates over the range given by the first two (with
+ // the second being non-inclusive).
+ iter: function(from, to, op) {
+ if (op) { this.iterN(from - this.first, to - from, op); }
+ else { this.iterN(this.first, this.first + this.size, from); }
},
- getOption: function(option) {return this.options[option]},
- getDoc: function() {return this.doc},
+ // Non-public interface for adding and removing lines.
+ insert: function(at, lines) {
+ var height = 0;
+ for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
+ this.insertInner(at - this.first, lines, height);
+ },
+ remove: function(at, n) { this.removeInner(at - this.first, n); },
- addKeyMap: function(map$$1, bottom) {
- this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
+ // From here, the methods are part of the public interface. Most
+ // are also available from CodeMirror (editor) instances.
+
+ getValue: function(lineSep) {
+ var lines = getLines(this, this.first, this.first + this.size);
+ if (lineSep === false) { return lines }
+ return lines.join(lineSep || this.lineSeparator())
},
- removeKeyMap: function(map$$1) {
- var maps = this.state.keyMaps;
- for (var i = 0; i < maps.length; ++i)
- { if (maps[i] == map$$1 || maps[i].name == map$$1) {
- maps.splice(i, 1);
- return true
- } }
+ setValue: docMethodOp(function(code) {
+ var top = Pos(this.first, 0), last = this.first + this.size - 1;
+ makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
+ text: this.splitLines(code), origin: "setValue", full: true}, true);
+ if (this.cm) { scrollToCoords(this.cm, 0, 0); }
+ setSelection(this, simpleSelection(top), sel_dontScroll);
+ }),
+ replaceRange: function(code, from, to, origin) {
+ from = clipPos(this, from);
+ to = to ? clipPos(this, to) : from;
+ replaceRange(this, code, from, to, origin);
+ },
+ getRange: function(from, to, lineSep) {
+ var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
+ if (lineSep === false) { return lines }
+ return lines.join(lineSep || this.lineSeparator())
+ },
+
+ getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
+
+ getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
+ getLineNumber: function(line) {return lineNo(line)},
+
+ getLineHandleVisualStart: function(line) {
+ if (typeof line == "number") { line = getLine(this, line); }
+ return visualLine(line)
},
- addOverlay: methodOp(function(spec, options) {
- var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
- if (mode.startState) { throw new Error("Overlays may not be stateful.") }
- insertSorted(this.state.overlays,
- {mode: mode, modeSpec: spec, opaque: options && options.opaque,
- priority: (options && options.priority) || 0},
- function (overlay) { return overlay.priority; });
- this.state.modeGen++;
- regChange(this);
+ lineCount: function() {return this.size},
+ firstLine: function() {return this.first},
+ lastLine: function() {return this.first + this.size - 1},
+
+ clipPos: function(pos) {return clipPos(this, pos)},
+
+ getCursor: function(start) {
+ var range$$1 = this.sel.primary(), pos;
+ if (start == null || start == "head") { pos = range$$1.head; }
+ else if (start == "anchor") { pos = range$$1.anchor; }
+ else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
+ else { pos = range$$1.from(); }
+ return pos
+ },
+ listSelections: function() { return this.sel.ranges },
+ somethingSelected: function() {return this.sel.somethingSelected()},
+
+ setCursor: docMethodOp(function(line, ch, options) {
+ setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
+ }),
+ setSelection: docMethodOp(function(anchor, head, options) {
+ setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
+ }),
+ extendSelection: docMethodOp(function(head, other, options) {
+ extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
+ }),
+ extendSelections: docMethodOp(function(heads, options) {
+ extendSelections(this, clipPosArray(this, heads), options);
+ }),
+ extendSelectionsBy: docMethodOp(function(f, options) {
+ var heads = map(this.sel.ranges, f);
+ extendSelections(this, clipPosArray(this, heads), options);
+ }),
+ setSelections: docMethodOp(function(ranges, primary, options) {
+ if (!ranges.length) { return }
+ var out = [];
+ for (var i = 0; i < ranges.length; i++)
+ { out[i] = new Range(clipPos(this, ranges[i].anchor),
+ clipPos(this, ranges[i].head)); }
+ if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
+ setSelection(this, normalizeSelection(this.cm, out, primary), options);
+ }),
+ addSelection: docMethodOp(function(anchor, head, options) {
+ var ranges = this.sel.ranges.slice(0);
+ ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
+ setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options);
}),
- removeOverlay: methodOp(function(spec) {
- var this$1 = this;
- var overlays = this.state.overlays;
- for (var i = 0; i < overlays.length; ++i) {
- var cur = overlays[i].modeSpec;
- if (cur == spec || typeof spec == "string" && cur.name == spec) {
- overlays.splice(i, 1);
- this$1.state.modeGen++;
- regChange(this$1);
- return
- }
+ getSelection: function(lineSep) {
+ var ranges = this.sel.ranges, lines;
+ for (var i = 0; i < ranges.length; i++) {
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+ lines = lines ? lines.concat(sel) : sel;
+ }
+ if (lineSep === false) { return lines }
+ else { return lines.join(lineSep || this.lineSeparator()) }
+ },
+ getSelections: function(lineSep) {
+ var parts = [], ranges = this.sel.ranges;
+ for (var i = 0; i < ranges.length; i++) {
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+ if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); }
+ parts[i] = sel;
}
+ return parts
+ },
+ replaceSelection: function(code, collapse, origin) {
+ var dup = [];
+ for (var i = 0; i < this.sel.ranges.length; i++)
+ { dup[i] = code; }
+ this.replaceSelections(dup, collapse, origin || "+input");
+ },
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
+ var changes = [], sel = this.sel;
+ for (var i = 0; i < sel.ranges.length; i++) {
+ var range$$1 = sel.ranges[i];
+ changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this.splitLines(code[i]), origin: origin};
+ }
+ var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
+ for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
+ { makeChange(this, changes[i$1]); }
+ if (newSel) { setSelectionReplaceHistory(this, newSel); }
+ else if (this.cm) { ensureCursorVisible(this.cm); }
}),
+ undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
+ redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
+ undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
+ redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
+
+ setExtending: function(val) {this.extend = val;},
+ getExtending: function() {return this.extend},
+
+ historySize: function() {
+ var hist = this.history, done = 0, undone = 0;
+ for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
+ for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
+ return {undo: done, redo: undone}
+ },
+ clearHistory: function() {this.history = new History(this.history.maxGeneration);},
- indentLine: methodOp(function(n, dir, aggressive) {
- if (typeof dir != "string" && typeof dir != "number") {
- if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
- else { dir = dir ? "add" : "subtract"; }
- }
- if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
+ markClean: function() {
+ this.cleanGeneration = this.changeGeneration(true);
+ },
+ changeGeneration: function(forceSplit) {
+ if (forceSplit)
+ { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
+ return this.history.generation
+ },
+ isClean: function (gen) {
+ return this.history.generation == (gen || this.cleanGeneration)
+ },
+
+ getHistory: function() {
+ return {done: copyHistoryArray(this.history.done),
+ undone: copyHistoryArray(this.history.undone)}
+ },
+ setHistory: function(histData) {
+ var hist = this.history = new History(this.history.maxGeneration);
+ hist.done = copyHistoryArray(histData.done.slice(0), null, true);
+ hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
+ },
+
+ setGutterMarker: docMethodOp(function(line, gutterID, value) {
+ return changeLine(this, line, "gutter", function (line) {
+ var markers = line.gutterMarkers || (line.gutterMarkers = {});
+ markers[gutterID] = value;
+ if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
+ return true
+ })
}),
- indentSelection: methodOp(function(how) {
+
+ clearGutter: docMethodOp(function(gutterID) {
var this$1 = this;
- var ranges = this.doc.sel.ranges, end = -1;
- for (var i = 0; i < ranges.length; i++) {
- var range$$1 = ranges[i];
- if (!range$$1.empty()) {
- var from = range$$1.from(), to = range$$1.to();
- var start = Math.max(end, from.line);
- end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
- for (var j = start; j < end; ++j)
- { indentLine(this$1, j, how); }
- var newRanges = this$1.doc.sel.ranges;
- if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
- { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
- } else if (range$$1.head.line > end) {
- indentLine(this$1, range$$1.head.line, how, true);
- end = range$$1.head.line;
- if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
+ this.iter(function (line) {
+ if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
+ changeLine(this$1, line, "gutter", function () {
+ line.gutterMarkers[gutterID] = null;
+ if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
+ return true
+ });
}
+ });
+ }),
+
+ lineInfo: function(line) {
+ var n;
+ if (typeof line == "number") {
+ if (!isLine(this, line)) { return null }
+ n = line;
+ line = getLine(this, line);
+ if (!line) { return null }
+ } else {
+ n = lineNo(line);
+ if (n == null) { return null }
}
+ return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
+ textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
+ widgets: line.widgets}
+ },
+
+ addLineClass: docMethodOp(function(handle, where, cls) {
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
+ var prop = where == "text" ? "textClass"
+ : where == "background" ? "bgClass"
+ : where == "gutter" ? "gutterClass" : "wrapClass";
+ if (!line[prop]) { line[prop] = cls; }
+ else if (classTest(cls).test(line[prop])) { return false }
+ else { line[prop] += " " + cls; }
+ return true
+ })
+ }),
+ removeLineClass: docMethodOp(function(handle, where, cls) {
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
+ var prop = where == "text" ? "textClass"
+ : where == "background" ? "bgClass"
+ : where == "gutter" ? "gutterClass" : "wrapClass";
+ var cur = line[prop];
+ if (!cur) { return false }
+ else if (cls == null) { line[prop] = null; }
+ else {
+ var found = cur.match(classTest(cls));
+ if (!found) { return false }
+ var end = found.index + found[0].length;
+ line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
+ }
+ return true
+ })
+ }),
+
+ addLineWidget: docMethodOp(function(handle, node, options) {
+ return addLineWidget(this, handle, node, options)
}),
+ removeLineWidget: function(widget) { widget.clear(); },
- // Fetch the parser token for a given character. Useful for hacks
- // that want to inspect the mode state (say, for completion).
- getTokenAt: function(pos, precise) {
- return takeToken(this, pos, precise)
+ markText: function(from, to, options) {
+ return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
+ },
+ setBookmark: function(pos, options) {
+ var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
+ insertLeft: options && options.insertLeft,
+ clearWhenEmpty: false, shared: options && options.shared,
+ handleMouseEvents: options && options.handleMouseEvents};
+ pos = clipPos(this, pos);
+ return markText(this, pos, pos, realOpts, "bookmark")
+ },
+ findMarksAt: function(pos) {
+ pos = clipPos(this, pos);
+ var markers = [], spans = getLine(this, pos.line).markedSpans;
+ if (spans) { for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if ((span.from == null || span.from <= pos.ch) &&
+ (span.to == null || span.to >= pos.ch))
+ { markers.push(span.marker.parent || span.marker); }
+ } }
+ return markers
+ },
+ findMarks: function(from, to, filter) {
+ from = clipPos(this, from); to = clipPos(this, to);
+ var found = [], lineNo$$1 = from.line;
+ this.iter(from.line, to.line + 1, function (line) {
+ var spans = line.markedSpans;
+ if (spans) { for (var i = 0; i < spans.length; i++) {
+ var span = spans[i];
+ if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
+ span.from == null && lineNo$$1 != from.line ||
+ span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
+ (!filter || filter(span.marker)))
+ { found.push(span.marker.parent || span.marker); }
+ } }
+ ++lineNo$$1;
+ });
+ return found
+ },
+ getAllMarks: function() {
+ var markers = [];
+ this.iter(function (line) {
+ var sps = line.markedSpans;
+ if (sps) { for (var i = 0; i < sps.length; ++i)
+ { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
+ });
+ return markers
+ },
+
+ posFromIndex: function(off) {
+ var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
+ this.iter(function (line) {
+ var sz = line.text.length + sepSize;
+ if (sz > off) { ch = off; return true }
+ off -= sz;
+ ++lineNo$$1;
+ });
+ return clipPos(this, Pos(lineNo$$1, ch))
+ },
+ indexFromPos: function (coords) {
+ coords = clipPos(this, coords);
+ var index = coords.ch;
+ if (coords.line < this.first || coords.ch < 0) { return 0 }
+ var sepSize = this.lineSeparator().length;
+ this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
+ index += line.text.length + sepSize;
+ });
+ return index
},
- getLineTokens: function(line, precise) {
- return takeToken(this, Pos(line), precise, true)
+ copy: function(copyHistory) {
+ var doc = new Doc(getLines(this, this.first, this.first + this.size),
+ this.modeOption, this.first, this.lineSep, this.direction);
+ doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
+ doc.sel = this.sel;
+ doc.extend = false;
+ if (copyHistory) {
+ doc.history.undoDepth = this.history.undoDepth;
+ doc.setHistory(this.getHistory());
+ }
+ return doc
},
- getTokenTypeAt: function(pos) {
- pos = clipPos(this.doc, pos);
- var styles = getLineStyles(this, getLine(this.doc, pos.line));
- var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
- var type;
- if (ch == 0) { type = styles[2]; }
- else { for (;;) {
- var mid = (before + after) >> 1;
- if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
- else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
- else { type = styles[mid * 2 + 2]; break }
+ linkedDoc: function(options) {
+ if (!options) { options = {}; }
+ var from = this.first, to = this.first + this.size;
+ if (options.from != null && options.from > from) { from = options.from; }
+ if (options.to != null && options.to < to) { to = options.to; }
+ var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
+ if (options.sharedHist) { copy.history = this.history
+ ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
+ copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
+ copySharedMarkers(copy, findSharedMarkers(this));
+ return copy
+ },
+ unlinkDoc: function(other) {
+ if (other instanceof CodeMirror) { other = other.doc; }
+ if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
+ var link = this.linked[i];
+ if (link.doc != other) { continue }
+ this.linked.splice(i, 1);
+ other.unlinkDoc(this);
+ detachSharedMarkers(findSharedMarkers(this));
+ break
} }
- var cut = type ? type.indexOf("overlay ") : -1;
- return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
+ // If the histories were shared, split them again
+ if (other.history == this.history) {
+ var splitIds = [other.id];
+ linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
+ other.history = new History(null);
+ other.history.done = copyHistoryArray(this.history.done, splitIds);
+ other.history.undone = copyHistoryArray(this.history.undone, splitIds);
+ }
},
+ iterLinkedDocs: function(f) {linkedDocs(this, f);},
- getModeAt: function(pos) {
- var mode = this.doc.mode;
- if (!mode.innerMode) { return mode }
- return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
- },
+ getMode: function() {return this.mode},
+ getEditor: function() {return this.cm},
- getHelper: function(pos, type) {
- return this.getHelpers(pos, type)[0]
+ splitLines: function(str) {
+ if (this.lineSep) { return str.split(this.lineSep) }
+ return splitLinesAuto(str)
},
+ lineSeparator: function() { return this.lineSep || "\n" },
+
+ setDirection: docMethodOp(function (dir) {
+ if (dir != "rtl") { dir = "ltr"; }
+ if (dir == this.direction) { return }
+ this.direction = dir;
+ this.iter(function (line) { return line.order = null; });
+ if (this.cm) { directionChanged(this.cm); }
+ })
+ });
- getHelpers: function(pos, type) {
- var this$1 = this;
+ // Public alias.
+ Doc.prototype.eachLine = Doc.prototype.iter;
- var found = [];
- if (!helpers.hasOwnProperty(type)) { return found }
- var help = helpers[type], mode = this.getModeAt(pos);
- if (typeof mode[type] == "string") {
- if (help[mode[type]]) { found.push(help[mode[type]]); }
- } else if (mode[type]) {
- for (var i = 0; i < mode[type].length; i++) {
- var val = help[mode[type][i]];
- if (val) { found.push(val); }
+ // Kludge to work around strange IE behavior where it'll sometimes
+ // re-fire a series of drag-related events right after the drop (#1551)
+ var lastDrop = 0;
+
+ function onDrop(e) {
+ var cm = this;
+ clearDragCursor(cm);
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
+ { return }
+ e_preventDefault(e);
+ if (ie) { lastDrop = +new Date; }
+ var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
+ if (!pos || cm.isReadOnly()) { return }
+ // Might be a file drop, in which case we simply extract the text
+ // and insert it.
+ if (files && files.length && window.FileReader && window.File) {
+ var n = files.length, text = Array(n), read = 0;
+ var loadFile = function (file, i) {
+ if (cm.options.allowDropFileTypes &&
+ indexOf(cm.options.allowDropFileTypes, file.type) == -1)
+ { return }
+
+ var reader = new FileReader;
+ reader.onload = operation(cm, function () {
+ var content = reader.result;
+ if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
+ text[i] = content;
+ if (++read == n) {
+ pos = clipPos(cm.doc, pos);
+ var change = {from: pos, to: pos,
+ text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
+ origin: "paste"};
+ makeChange(cm.doc, change);
+ setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
+ }
+ });
+ reader.readAsText(file);
+ };
+ for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
+ } else { // Normal drop
+ // Don't do a replace if the drop happened inside of the selected text.
+ if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
+ cm.state.draggingText(e);
+ // Ensure the editor is re-focused
+ setTimeout(function () { return cm.display.input.focus(); }, 20);
+ return
+ }
+ try {
+ var text$1 = e.dataTransfer.getData("Text");
+ if (text$1) {
+ var selected;
+ if (cm.state.draggingText && !cm.state.draggingText.copy)
+ { selected = cm.listSelections(); }
+ setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
+ if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
+ { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
+ cm.replaceSelection(text$1, "around", "paste");
+ cm.display.input.focus();
}
- } else if (mode.helperType && help[mode.helperType]) {
- found.push(help[mode.helperType]);
- } else if (help[mode.name]) {
- found.push(help[mode.name]);
}
- for (var i$1 = 0; i$1 < help._global.length; i$1++) {
- var cur = help._global[i$1];
- if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
- { found.push(cur.val); }
+ catch(e){}
+ }
+ }
+
+ function onDragStart(cm, e) {
+ if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
+
+ e.dataTransfer.setData("Text", cm.getSelection());
+ e.dataTransfer.effectAllowed = "copyMove";
+
+ // Use dummy image instead of default browsers image.
+ // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
+ if (e.dataTransfer.setDragImage && !safari) {
+ var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
+ img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
+ if (presto) {
+ img.width = img.height = 1;
+ cm.display.wrapper.appendChild(img);
+ // Force a relayout, or Opera won't use our image for some obscure reason
+ img._top = img.offsetTop;
}
- return found
- },
+ e.dataTransfer.setDragImage(img, 0, 0);
+ if (presto) { img.parentNode.removeChild(img); }
+ }
+ }
- getStateAfter: function(line, precise) {
- var doc = this.doc;
- line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
- return getContextBefore(this, line + 1, precise).state
- },
+ function onDragOver(cm, e) {
+ var pos = posFromMouse(cm, e);
+ if (!pos) { return }
+ var frag = document.createDocumentFragment();
+ drawSelectionCursor(cm, pos, frag);
+ if (!cm.display.dragCursor) {
+ cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
+ cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
+ }
+ removeChildrenAndAdd(cm.display.dragCursor, frag);
+ }
- cursorCoords: function(start, mode) {
- var pos, range$$1 = this.doc.sel.primary();
- if (start == null) { pos = range$$1.head; }
- else if (typeof start == "object") { pos = clipPos(this.doc, start); }
- else { pos = start ? range$$1.from() : range$$1.to(); }
- return cursorCoords(this, pos, mode || "page")
- },
+ function clearDragCursor(cm) {
+ if (cm.display.dragCursor) {
+ cm.display.lineSpace.removeChild(cm.display.dragCursor);
+ cm.display.dragCursor = null;
+ }
+ }
- charCoords: function(pos, mode) {
- return charCoords(this, clipPos(this.doc, pos), mode || "page")
- },
+ // These must be handled carefully, because naively registering a
+ // handler for each editor will cause the editors to never be
+ // garbage collected.
- coordsChar: function(coords, mode) {
- coords = fromCoordSystem(this, coords, mode || "page");
- return coordsChar(this, coords.left, coords.top)
- },
+ function forEachCodeMirror(f) {
+ if (!document.getElementsByClassName) { return }
+ var byClass = document.getElementsByClassName("CodeMirror"), editors = [];
+ for (var i = 0; i < byClass.length; i++) {
+ var cm = byClass[i].CodeMirror;
+ if (cm) { editors.push(cm); }
+ }
+ if (editors.length) { editors[0].operation(function () {
+ for (var i = 0; i < editors.length; i++) { f(editors[i]); }
+ }); }
+ }
- lineAtHeight: function(height, mode) {
- height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
- return lineAtHeight(this.doc, height + this.display.viewOffset)
- },
- heightAtLine: function(line, mode, includeWidgets) {
- var end = false, lineObj;
- if (typeof line == "number") {
- var last = this.doc.first + this.doc.size - 1;
- if (line < this.doc.first) { line = this.doc.first; }
- else if (line > last) { line = last; end = true; }
- lineObj = getLine(this.doc, line);
- } else {
- lineObj = line;
+ var globalsRegistered = false;
+ function ensureGlobalHandlers() {
+ if (globalsRegistered) { return }
+ registerGlobalHandlers();
+ globalsRegistered = true;
+ }
+ function registerGlobalHandlers() {
+ // When the window resizes, we need to refresh active editors.
+ var resizeTimer;
+ on(window, "resize", function () {
+ if (resizeTimer == null) { resizeTimer = setTimeout(function () {
+ resizeTimer = null;
+ forEachCodeMirror(onResize);
+ }, 100); }
+ });
+ // When the window loses focus, we want to show the editor as blurred
+ on(window, "blur", function () { return forEachCodeMirror(onBlur); });
+ }
+ // Called when the window resizes
+ function onResize(cm) {
+ var d = cm.display;
+ // Might be a text scaling operation, clear size caches.
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+ d.scrollbarsClipped = false;
+ cm.setSize();
+ }
+
+ var keyNames = {
+ 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
+ 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
+ };
+
+ // Number keys
+ for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
+ // Alphabetic keys
+ for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
+ // Function keys
+ for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
+
+ var keyMap = {};
+
+ keyMap.basic = {
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
+ "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
+ "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
+ "Esc": "singleSelection"
+ };
+ // Note that the save and find-related commands aren't defined by
+ // default. User code or addons can define them. Unknown commands
+ // are simply ignored.
+ keyMap.pcDefault = {
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
+ "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
+ "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
+ "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
+ "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
+ "fallthrough": "basic"
+ };
+ // Very basic readline/emacs-style bindings, which are standard on Mac.
+ keyMap.emacsy = {
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+ "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
+ "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
+ "Ctrl-O": "openLine"
+ };
+ keyMap.macDefault = {
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
+ "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
+ "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
+ "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
+ "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
+ "fallthrough": ["basic", "emacsy"]
+ };
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
+
+ // KEYMAP DISPATCH
+
+ function normalizeKeyName(name) {
+ var parts = name.split(/-(?!$)/);
+ name = parts[parts.length - 1];
+ var alt, ctrl, shift, cmd;
+ for (var i = 0; i < parts.length - 1; i++) {
+ var mod = parts[i];
+ if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
+ else if (/^a(lt)?$/i.test(mod)) { alt = true; }
+ else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
+ else if (/^s(hift)?$/i.test(mod)) { shift = true; }
+ else { throw new Error("Unrecognized modifier name: " + mod) }
+ }
+ if (alt) { name = "Alt-" + name; }
+ if (ctrl) { name = "Ctrl-" + name; }
+ if (cmd) { name = "Cmd-" + name; }
+ if (shift) { name = "Shift-" + name; }
+ return name
+ }
+
+ // This is a kludge to keep keymaps mostly working as raw objects
+ // (backwards compatibility) while at the same time support features
+ // like normalization and multi-stroke key bindings. It compiles a
+ // new normalized keymap, and then updates the old object to reflect
+ // this.
+ function normalizeKeyMap(keymap) {
+ var copy = {};
+ for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
+ var value = keymap[keyname];
+ if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
+ if (value == "...") { delete keymap[keyname]; continue }
+
+ var keys = map(keyname.split(" "), normalizeKeyName);
+ for (var i = 0; i < keys.length; i++) {
+ var val = (void 0), name = (void 0);
+ if (i == keys.length - 1) {
+ name = keys.join(" ");
+ val = value;
+ } else {
+ name = keys.slice(0, i + 1).join(" ");
+ val = "...";
+ }
+ var prev = copy[name];
+ if (!prev) { copy[name] = val; }
+ else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
}
- return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
- (end ? this.doc.height - heightAtLine(lineObj) : 0)
- },
+ delete keymap[keyname];
+ } }
+ for (var prop in copy) { keymap[prop] = copy[prop]; }
+ return keymap
+ }
+
+ function lookupKey(key, map$$1, handle, context) {
+ map$$1 = getKeyMap(map$$1);
+ var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
+ if (found === false) { return "nothing" }
+ if (found === "...") { return "multi" }
+ if (found != null && handle(found)) { return "handled" }
+
+ if (map$$1.fallthrough) {
+ if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
+ { return lookupKey(key, map$$1.fallthrough, handle, context) }
+ for (var i = 0; i < map$$1.fallthrough.length; i++) {
+ var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
+ if (result) { return result }
+ }
+ }
+ }
- defaultTextHeight: function() { return textHeight(this.display) },
- defaultCharWidth: function() { return charWidth(this.display) },
-
- getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
-
- addWidget: function(pos, node, scroll, vert, horiz) {
- var display = this.display;
- pos = cursorCoords(this, clipPos(this.doc, pos));
- var top = pos.bottom, left = pos.left;
- node.style.position = "absolute";
- node.setAttribute("cm-ignore-events", "true");
- this.display.input.setUneditable(node);
- display.sizer.appendChild(node);
- if (vert == "over") {
- top = pos.top;
- } else if (vert == "above" || vert == "near") {
- var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
- hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
- // Default to positioning above (if specified and possible); otherwise default to positioning below
- if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
- { top = pos.top - node.offsetHeight; }
- else if (pos.bottom + node.offsetHeight <= vspace)
- { top = pos.bottom; }
- if (left + node.offsetWidth > hspace)
- { left = hspace - node.offsetWidth; }
- }
- node.style.top = top + "px";
- node.style.left = node.style.right = "";
- if (horiz == "right") {
- left = display.sizer.clientWidth - node.offsetWidth;
- node.style.right = "0px";
- } else {
- if (horiz == "left") { left = 0; }
- else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
- node.style.left = left + "px";
+ // Modifier key presses don't count as 'real' key presses for the
+ // purpose of keymap fallthrough.
+ function isModifierKey(value) {
+ var name = typeof value == "string" ? value : keyNames[value.keyCode];
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
+ }
+
+ function addModifierNames(name, event, noShift) {
+ var base = name;
+ if (event.altKey && base != "Alt") { name = "Alt-" + name; }
+ if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
+ if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
+ if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
+ return name
+ }
+
+ // Look up the name of a key as indicated by an event object.
+ function keyName(event, noShift) {
+ if (presto && event.keyCode == 34 && event["char"]) { return false }
+ var name = keyNames[event.keyCode];
+ if (name == null || event.altGraphKey) { return false }
+ // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
+ // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
+ if (event.keyCode == 3 && event.code) { name = event.code; }
+ return addModifierNames(name, event, noShift)
+ }
+
+ function getKeyMap(val) {
+ return typeof val == "string" ? keyMap[val] : val
+ }
+
+ // Helper for deleting text near the selection(s), used to implement
+ // backspace, delete, and similar functionality.
+ function deleteNearSelection(cm, compute) {
+ var ranges = cm.doc.sel.ranges, kill = [];
+ // Build up a set of ranges to kill first, merging overlapping
+ // ranges.
+ for (var i = 0; i < ranges.length; i++) {
+ var toKill = compute(ranges[i]);
+ while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
+ var replaced = kill.pop();
+ if (cmp(replaced.from, toKill.from) < 0) {
+ toKill.from = replaced.from;
+ break
+ }
}
- if (scroll)
- { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
- },
+ kill.push(toKill);
+ }
+ // Next, remove those actual ranges.
+ runInOp(cm, function () {
+ for (var i = kill.length - 1; i >= 0; i--)
+ { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
+ ensureCursorVisible(cm);
+ });
+ }
- triggerOnKeyDown: methodOp(onKeyDown),
- triggerOnKeyPress: methodOp(onKeyPress),
- triggerOnKeyUp: onKeyUp,
- triggerOnMouseDown: methodOp(onMouseDown),
+ function moveCharLogically(line, ch, dir) {
+ var target = skipExtendingChars(line.text, ch + dir, dir);
+ return target < 0 || target > line.text.length ? null : target
+ }
- execCommand: function(cmd) {
- if (commands.hasOwnProperty(cmd))
- { return commands[cmd].call(null, this) }
- },
+ function moveLogically(line, start, dir) {
+ var ch = moveCharLogically(line, start.ch, dir);
+ return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
+ }
- triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
+ function endOfLine(visually, cm, lineObj, lineNo, dir) {
+ if (visually) {
+ var order = getOrder(lineObj, cm.doc.direction);
+ if (order) {
+ var part = dir < 0 ? lst(order) : order[0];
+ var moveInStorageOrder = (dir < 0) == (part.level == 1);
+ var sticky = moveInStorageOrder ? "after" : "before";
+ var ch;
+ // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
+ // it could be that the last bidi part is not on the last visual line,
+ // since visual lines contain content order-consecutive chunks.
+ // Thus, in rtl, we are looking for the first (content-order) character
+ // in the rtl chunk that is on the last line (that is, the same line
+ // as the last (content-order) character).
+ if (part.level > 0 || cm.doc.direction == "rtl") {
+ var prep = prepareMeasureForLine(cm, lineObj);
+ ch = dir < 0 ? lineObj.text.length - 1 : 0;
+ var targetTop = measureCharPrepared(cm, prep, ch).top;
+ ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
+ if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
+ } else { ch = dir < 0 ? part.to : part.from; }
+ return new Pos(lineNo, ch, sticky)
+ }
+ }
+ return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
+ }
- findPosH: function(from, amount, unit, visually) {
- var this$1 = this;
+ function moveVisually(cm, line, start, dir) {
+ var bidi = getOrder(line, cm.doc.direction);
+ if (!bidi) { return moveLogically(line, start, dir) }
+ if (start.ch >= line.text.length) {
+ start.ch = line.text.length;
+ start.sticky = "before";
+ } else if (start.ch <= 0) {
+ start.ch = 0;
+ start.sticky = "after";
+ }
+ var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
+ if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
+ // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
+ // nothing interesting happens.
+ return moveLogically(line, start, dir)
+ }
- var dir = 1;
- if (amount < 0) { dir = -1; amount = -amount; }
- var cur = clipPos(this.doc, from);
- for (var i = 0; i < amount; ++i) {
- cur = findPosH(this$1.doc, cur, dir, unit, visually);
- if (cur.hitSide) { break }
+ var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
+ var prep;
+ var getWrappedLineExtent = function (ch) {
+ if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
+ prep = prep || prepareMeasureForLine(cm, line);
+ return wrappedLineExtentChar(cm, line, prep, ch)
+ };
+ var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
+
+ if (cm.doc.direction == "rtl" || part.level == 1) {
+ var moveInStorageOrder = (part.level == 1) == (dir < 0);
+ var ch = mv(start, moveInStorageOrder ? 1 : -1);
+ if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
+ // Case 2: We move within an rtl part or in an rtl editor on the same visual line
+ var sticky = moveInStorageOrder ? "before" : "after";
+ return new Pos(start.line, ch, sticky)
}
- return cur
- },
+ }
- moveH: methodOp(function(dir, unit) {
- var this$1 = this;
+ // Case 3: Could not move within this bidi part in this visual line, so leave
+ // the current bidi part
+
+ var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
+ var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
+ ? new Pos(start.line, mv(ch, 1), "before")
+ : new Pos(start.line, ch, "after"); };
+
+ for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
+ var part = bidi[partPos];
+ var moveInStorageOrder = (dir > 0) == (part.level != 1);
+ var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
+ if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
+ ch = moveInStorageOrder ? part.from : mv(part.to, -1);
+ if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
+ }
+ };
+
+ // Case 3a: Look for other bidi parts on the same visual line
+ var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
+ if (res) { return res }
+
+ // Case 3b: Look for other bidi parts on the next visual line
+ var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
+ if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
+ res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
+ if (res) { return res }
+ }
+
+ // Case 4: Nowhere to move
+ return null
+ }
- this.extendSelectionsBy(function (range$$1) {
- if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
- { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
+ // Commands are parameter-less actions that can be performed on an
+ // editor, mostly used for keybindings.
+ var commands = {
+ selectAll: selectAll,
+ singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
+ killLine: function (cm) { return deleteNearSelection(cm, function (range) {
+ if (range.empty()) {
+ var len = getLine(cm.doc, range.head.line).text.length;
+ if (range.head.ch == len && range.head.line < cm.lastLine())
+ { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
else
- { return dir < 0 ? range$$1.from() : range$$1.to() }
- }, sel_move);
- }),
+ { return {from: range.head, to: Pos(range.head.line, len)} }
+ } else {
+ return {from: range.from(), to: range.to()}
+ }
+ }); },
+ deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
+ from: Pos(range.from().line, 0),
+ to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
+ }); }); },
+ delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
+ from: Pos(range.from().line, 0), to: range.from()
+ }); }); },
+ delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var leftPos = cm.coordsChar({left: 0, top: top}, "div");
+ return {from: leftPos, to: range.from()}
+ }); },
+ delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+ return {from: range.from(), to: rightPos }
+ }); },
+ undo: function (cm) { return cm.undo(); },
+ redo: function (cm) { return cm.redo(); },
+ undoSelection: function (cm) { return cm.undoSelection(); },
+ redoSelection: function (cm) { return cm.redoSelection(); },
+ goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
+ goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
+ goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
+ {origin: "+move", bias: 1}
+ ); },
+ goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
+ {origin: "+move", bias: 1}
+ ); },
+ goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
+ {origin: "+move", bias: -1}
+ ); },
+ goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
+ var top = cm.cursorCoords(range.head, "div").top + 5;
+ return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
+ }, sel_move); },
+ goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
+ var top = cm.cursorCoords(range.head, "div").top + 5;
+ return cm.coordsChar({left: 0, top: top}, "div")
+ }, sel_move); },
+ goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
+ var top = cm.cursorCoords(range.head, "div").top + 5;
+ var pos = cm.coordsChar({left: 0, top: top}, "div");
+ if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
+ return pos
+ }, sel_move); },
+ goLineUp: function (cm) { return cm.moveV(-1, "line"); },
+ goLineDown: function (cm) { return cm.moveV(1, "line"); },
+ goPageUp: function (cm) { return cm.moveV(-1, "page"); },
+ goPageDown: function (cm) { return cm.moveV(1, "page"); },
+ goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
+ goCharRight: function (cm) { return cm.moveH(1, "char"); },
+ goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
+ goColumnRight: function (cm) { return cm.moveH(1, "column"); },
+ goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
+ goGroupRight: function (cm) { return cm.moveH(1, "group"); },
+ goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
+ goWordRight: function (cm) { return cm.moveH(1, "word"); },
+ delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
+ delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
+ delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
+ delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
+ delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
+ delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
+ indentAuto: function (cm) { return cm.indentSelection("smart"); },
+ indentMore: function (cm) { return cm.indentSelection("add"); },
+ indentLess: function (cm) { return cm.indentSelection("subtract"); },
+ insertTab: function (cm) { return cm.replaceSelection("\t"); },
+ insertSoftTab: function (cm) {
+ var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
+ for (var i = 0; i < ranges.length; i++) {
+ var pos = ranges[i].from();
+ var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
+ spaces.push(spaceStr(tabSize - col % tabSize));
+ }
+ cm.replaceSelections(spaces);
+ },
+ defaultTab: function (cm) {
+ if (cm.somethingSelected()) { cm.indentSelection("add"); }
+ else { cm.execCommand("insertTab"); }
+ },
+ // Swap the two chars left and right of each selection's head.
+ // Move cursor behind the two swapped characters afterwards.
+ //
+ // Doesn't consider line feeds a character.
+ // Doesn't scan more than one line above to find a character.
+ // Doesn't do anything on an empty line.
+ // Doesn't do anything with non-empty selections.
+ transposeChars: function (cm) { return runInOp(cm, function () {
+ var ranges = cm.listSelections(), newSel = [];
+ for (var i = 0; i < ranges.length; i++) {
+ if (!ranges[i].empty()) { continue }
+ var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
+ if (line) {
+ if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
+ if (cur.ch > 0) {
+ cur = new Pos(cur.line, cur.ch + 1);
+ cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
+ Pos(cur.line, cur.ch - 2), cur, "+transpose");
+ } else if (cur.line > cm.doc.first) {
+ var prev = getLine(cm.doc, cur.line - 1).text;
+ if (prev) {
+ cur = new Pos(cur.line, 1);
+ cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
+ prev.charAt(prev.length - 1),
+ Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
+ }
+ }
+ }
+ newSel.push(new Range(cur, cur));
+ }
+ cm.setSelections(newSel);
+ }); },
+ newlineAndIndent: function (cm) { return runInOp(cm, function () {
+ var sels = cm.listSelections();
+ for (var i = sels.length - 1; i >= 0; i--)
+ { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
+ sels = cm.listSelections();
+ for (var i$1 = 0; i$1 < sels.length; i$1++)
+ { cm.indentLine(sels[i$1].from().line, null, true); }
+ ensureCursorVisible(cm);
+ }); },
+ openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
+ toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
+ };
+
+
+ function lineStart(cm, lineN) {
+ var line = getLine(cm.doc, lineN);
+ var visual = visualLine(line);
+ if (visual != line) { lineN = lineNo(visual); }
+ return endOfLine(true, cm, visual, lineN, 1)
+ }
+ function lineEnd(cm, lineN) {
+ var line = getLine(cm.doc, lineN);
+ var visual = visualLineEnd(line);
+ if (visual != line) { lineN = lineNo(visual); }
+ return endOfLine(true, cm, line, lineN, -1)
+ }
+ function lineStartSmart(cm, pos) {
+ var start = lineStart(cm, pos.line);
+ var line = getLine(cm.doc, start.line);
+ var order = getOrder(line, cm.doc.direction);
+ if (!order || order[0].level == 0) {
+ var firstNonWS = Math.max(0, line.text.search(/\S/));
+ var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
+ return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
+ }
+ return start
+ }
+
+ // Run a handler that was bound to a key.
+ function doHandleBinding(cm, bound, dropShift) {
+ if (typeof bound == "string") {
+ bound = commands[bound];
+ if (!bound) { return false }
+ }
+ // Ensure previous input has been read, so that the handler sees a
+ // consistent view of the document
+ cm.display.input.ensurePolled();
+ var prevShift = cm.display.shift, done = false;
+ try {
+ if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
+ if (dropShift) { cm.display.shift = false; }
+ done = bound(cm) != Pass;
+ } finally {
+ cm.display.shift = prevShift;
+ cm.state.suppressEdits = false;
+ }
+ return done
+ }
- deleteH: methodOp(function(dir, unit) {
- var sel = this.doc.sel, doc = this.doc;
- if (sel.somethingSelected())
- { doc.replaceSelection("", null, "+delete"); }
+ function lookupKeyForEditor(cm, name, handle) {
+ for (var i = 0; i < cm.state.keyMaps.length; i++) {
+ var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
+ if (result) { return result }
+ }
+ return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
+ || lookupKey(name, cm.options.keyMap, handle, cm)
+ }
+
+ // Note that, despite the name, this function is also used to check
+ // for bound mouse clicks.
+
+ var stopSeq = new Delayed;
+
+ function dispatchKey(cm, name, e, handle) {
+ var seq = cm.state.keySeq;
+ if (seq) {
+ if (isModifierKey(name)) { return "handled" }
+ if (/\'$/.test(name))
+ { cm.state.keySeq = null; }
else
- { deleteNearSelection(this, function (range$$1) {
- var other = findPosH(doc, range$$1.head, dir, unit, false);
- return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
+ { stopSeq.set(50, function () {
+ if (cm.state.keySeq == seq) {
+ cm.state.keySeq = null;
+ cm.display.input.reset();
+ }
}); }
- }),
+ if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
+ }
+ return dispatchKeyInner(cm, name, e, handle)
+ }
- findPosV: function(from, amount, unit, goalColumn) {
- var this$1 = this;
+ function dispatchKeyInner(cm, name, e, handle) {
+ var result = lookupKeyForEditor(cm, name, handle);
- var dir = 1, x = goalColumn;
- if (amount < 0) { dir = -1; amount = -amount; }
- var cur = clipPos(this.doc, from);
- for (var i = 0; i < amount; ++i) {
- var coords = cursorCoords(this$1, cur, "div");
- if (x == null) { x = coords.left; }
- else { coords.left = x; }
- cur = findPosV(this$1, coords, dir, unit);
- if (cur.hitSide) { break }
- }
- return cur
- },
+ if (result == "multi")
+ { cm.state.keySeq = name; }
+ if (result == "handled")
+ { signalLater(cm, "keyHandled", cm, name, e); }
- moveV: methodOp(function(dir, unit) {
- var this$1 = this;
+ if (result == "handled" || result == "multi") {
+ e_preventDefault(e);
+ restartBlink(cm);
+ }
- var doc = this.doc, goals = [];
- var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
- doc.extendSelectionsBy(function (range$$1) {
- if (collapse)
- { return dir < 0 ? range$$1.from() : range$$1.to() }
- var headPos = cursorCoords(this$1, range$$1.head, "div");
- if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
- goals.push(headPos.left);
- var pos = findPosV(this$1, headPos, dir, unit);
- if (unit == "page" && range$$1 == doc.sel.primary())
- { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
- return pos
- }, sel_move);
- if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
- { doc.sel.ranges[i].goalColumn = goals[i]; } }
- }),
+ return !!result
+ }
- // Find the word at the given position (as returned by coordsChar).
- findWordAt: function(pos) {
- var doc = this.doc, line = getLine(doc, pos.line).text;
- var start = pos.ch, end = pos.ch;
- if (line) {
- var helper = this.getHelper(pos, "wordChars");
- if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
- var startChar = line.charAt(start);
- var check = isWordChar(startChar, helper)
- ? function (ch) { return isWordChar(ch, helper); }
- : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
- : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
- while (start > 0 && check(line.charAt(start - 1))) { --start; }
- while (end < line.length && check(line.charAt(end))) { ++end; }
- }
- return new Range(Pos(pos.line, start), Pos(pos.line, end))
- },
+ // Handle a key from the keydown event.
+ function handleKeyBinding(cm, e) {
+ var name = keyName(e, true);
+ if (!name) { return false }
- toggleOverwrite: function(value) {
- if (value != null && value == this.state.overwrite) { return }
- if (this.state.overwrite = !this.state.overwrite)
- { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
- else
- { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
+ if (e.shiftKey && !cm.state.keySeq) {
+ // First try to resolve full name (including 'Shift-'). Failing
+ // that, see if there is a cursor-motion command (starting with
+ // 'go') bound to the keyname without 'Shift-'.
+ return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
+ || dispatchKey(cm, name, e, function (b) {
+ if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
+ { return doHandleBinding(cm, b) }
+ })
+ } else {
+ return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
+ }
+ }
- signal(this, "overwriteToggle", this, this.state.overwrite);
- },
- hasFocus: function() { return this.display.input.getField() == activeElt() },
- isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
-
- scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
- getScrollInfo: function() {
- var scroller = this.display.scroller;
- return {left: scroller.scrollLeft, top: scroller.scrollTop,
- height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
- width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
- clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
- },
+ // Handle a key from the keypress event
+ function handleCharBinding(cm, e, ch) {
+ return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
+ }
- scrollIntoView: methodOp(function(range$$1, margin) {
- if (range$$1 == null) {
- range$$1 = {from: this.doc.sel.primary().head, to: null};
- if (margin == null) { margin = this.options.cursorScrollMargin; }
- } else if (typeof range$$1 == "number") {
- range$$1 = {from: Pos(range$$1, 0), to: null};
- } else if (range$$1.from == null) {
- range$$1 = {from: range$$1, to: null};
- }
- if (!range$$1.to) { range$$1.to = range$$1.from; }
- range$$1.margin = margin || 0;
+ var lastStoppedKey = null;
+ function onKeyDown(e) {
+ var cm = this;
+ cm.curOp.focus = activeElt();
+ if (signalDOMEvent(cm, e)) { return }
+ // IE does strange things with escape.
+ if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
+ var code = e.keyCode;
+ cm.display.shift = code == 16 || e.shiftKey;
+ var handled = handleKeyBinding(cm, e);
+ if (presto) {
+ lastStoppedKey = handled ? code : null;
+ // Opera has no cut event... we try to at least catch the key combo
+ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
+ { cm.replaceSelection("", null, "cut"); }
+ }
- if (range$$1.from.line != null) {
- scrollToRange(this, range$$1);
- } else {
- scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
- }
- }),
+ // Turn mouse into crosshair when Alt is held on Mac.
+ if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
+ { showCrossHair(cm); }
+ }
- setSize: methodOp(function(width, height) {
- var this$1 = this;
+ function showCrossHair(cm) {
+ var lineDiv = cm.display.lineDiv;
+ addClass(lineDiv, "CodeMirror-crosshair");
- var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
- if (width != null) { this.display.wrapper.style.width = interpret(width); }
- if (height != null) { this.display.wrapper.style.height = interpret(height); }
- if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
- var lineNo$$1 = this.display.viewFrom;
- this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
- if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
- { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
- ++lineNo$$1;
- });
- this.curOp.forceUpdate = true;
- signal(this, "refresh", this);
- }),
+ function up(e) {
+ if (e.keyCode == 18 || !e.altKey) {
+ rmClass(lineDiv, "CodeMirror-crosshair");
+ off(document, "keyup", up);
+ off(document, "mouseover", up);
+ }
+ }
+ on(document, "keyup", up);
+ on(document, "mouseover", up);
+ }
- operation: function(f){return runInOp(this, f)},
- startOperation: function(){return startOperation(this)},
- endOperation: function(){return endOperation(this)},
-
- refresh: methodOp(function() {
- var oldHeight = this.display.cachedTextHeight;
- regChange(this);
- this.curOp.forceUpdate = true;
- clearCaches(this);
- scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
- updateGutterSpace(this);
- if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
- { estimateLineHeights(this); }
- signal(this, "refresh", this);
- }),
+ function onKeyUp(e) {
+ if (e.keyCode == 16) { this.doc.sel.shift = false; }
+ signalDOMEvent(this, e);
+ }
- swapDoc: methodOp(function(doc) {
- var old = this.doc;
- old.cm = null;
- attachDoc(this, doc);
- clearCaches(this);
- this.display.input.reset();
- scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
- this.curOp.forceScroll = true;
- signalLater(this, "swapDoc", this, old);
- return old
- }),
+ function onKeyPress(e) {
+ var cm = this;
+ if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
+ var keyCode = e.keyCode, charCode = e.charCode;
+ if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
+ if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
+ // Some browsers fire keypress events for backspace
+ if (ch == "\x08") { return }
+ if (handleCharBinding(cm, e, ch)) { return }
+ cm.display.input.onKeyPress(e);
+ }
- phrase: function(phraseText) {
- var phrases = this.options.phrases;
- return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText
- },
+ var DOUBLECLICK_DELAY = 400;
- getInputField: function(){return this.display.input.getField()},
- getWrapperElement: function(){return this.display.wrapper},
- getScrollerElement: function(){return this.display.scroller},
- getGutterElement: function(){return this.display.gutters}
+ var PastClick = function(time, pos, button) {
+ this.time = time;
+ this.pos = pos;
+ this.button = button;
};
- eventMixin(CodeMirror);
- CodeMirror.registerHelper = function(type, name, value) {
- if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
- helpers[type][name] = value;
- };
- CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
- CodeMirror.registerHelper(type, name, value);
- helpers[type]._global.push({pred: predicate, val: value});
+ PastClick.prototype.compare = function (time, pos, button) {
+ return this.time + DOUBLECLICK_DELAY > time &&
+ cmp(pos, this.pos) == 0 && button == this.button
};
-};
-
-// Used for horizontal relative motion. Dir is -1 or 1 (left or
-// right), unit can be "char", "column" (like char, but doesn't
-// cross line boundaries), "word" (across next word), or "group" (to
-// the start of next group of word or non-word-non-whitespace
-// chars). The visually param controls whether, in right-to-left
-// text, direction 1 means to move towards the next index in the
-// string, or towards the character to the right of the current
-// position. The resulting position will have a hitSide=true
-// property if it reached the end of the document.
-function findPosH(doc, pos, dir, unit, visually) {
- var oldPos = pos;
- var origDir = dir;
- var lineObj = getLine(doc, pos.line);
- function findNextLine() {
- var l = pos.line + dir;
- if (l < doc.first || l >= doc.first + doc.size) { return false }
- pos = new Pos(l, pos.ch, pos.sticky);
- return lineObj = getLine(doc, l)
- }
- function moveOnce(boundToLine) {
- var next;
- if (visually) {
- next = moveVisually(doc.cm, lineObj, pos, dir);
+
+ var lastClick, lastDoubleClick;
+ function clickRepeat(pos, button) {
+ var now = +new Date;
+ if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
+ lastClick = lastDoubleClick = null;
+ return "triple"
+ } else if (lastClick && lastClick.compare(now, pos, button)) {
+ lastDoubleClick = new PastClick(now, pos, button);
+ lastClick = null;
+ return "double"
} else {
- next = moveLogically(lineObj, pos, dir);
+ lastClick = new PastClick(now, pos, button);
+ lastDoubleClick = null;
+ return "single"
+ }
+ }
+
+ // A mouse down can be a single click, double click, triple click,
+ // start of selection drag, start of text drag, new cursor
+ // (ctrl-click), rectangle drag (alt-drag), or xwin
+ // middle-click-paste. Or it might be a click on something we should
+ // not interfere with, such as a scrollbar or widget.
+ function onMouseDown(e) {
+ var cm = this, display = cm.display;
+ if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
+ display.input.ensurePolled();
+ display.shift = e.shiftKey;
+
+ if (eventInWidget(display, e)) {
+ if (!webkit) {
+ // Briefly turn off draggability, to allow widgets to do
+ // normal dragging things.
+ display.scroller.draggable = false;
+ setTimeout(function () { return display.scroller.draggable = true; }, 100);
+ }
+ return
}
- if (next == null) {
- if (!boundToLine && findNextLine())
- { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
- else
- { return false }
- } else {
- pos = next;
+ if (clickInGutter(cm, e)) { return }
+ var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
+ window.focus();
+
+ // #3261: make sure, that we're not starting a second selection
+ if (button == 1 && cm.state.selectingText)
+ { cm.state.selectingText(e); }
+
+ if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
+
+ if (button == 1) {
+ if (pos) { leftButtonDown(cm, pos, repeat, e); }
+ else if (e_target(e) == display.scroller) { e_preventDefault(e); }
+ } else if (button == 2) {
+ if (pos) { extendSelection(cm.doc, pos); }
+ setTimeout(function () { return display.input.focus(); }, 20);
+ } else if (button == 3) {
+ if (captureRightClick) { cm.display.input.onContextMenu(e); }
+ else { delayBlurEvent(cm); }
}
- return true
}
- if (unit == "char") {
- moveOnce();
- } else if (unit == "column") {
- moveOnce(true);
- } else if (unit == "word" || unit == "group") {
- var sawType = null, group = unit == "group";
- var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
- for (var first = true;; first = false) {
- if (dir < 0 && !moveOnce(!first)) { break }
- var cur = lineObj.text.charAt(pos.ch) || "\n";
- var type = isWordChar(cur, helper) ? "w"
- : group && cur == "\n" ? "n"
- : !group || /\s/.test(cur) ? null
- : "p";
- if (group && !first && !type) { type = "s"; }
- if (sawType && sawType != type) {
- if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
- break
+ function handleMappedButton(cm, button, pos, repeat, event) {
+ var name = "Click";
+ if (repeat == "double") { name = "Double" + name; }
+ else if (repeat == "triple") { name = "Triple" + name; }
+ name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
+
+ return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
+ if (typeof bound == "string") { bound = commands[bound]; }
+ if (!bound) { return false }
+ var done = false;
+ try {
+ if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
+ done = bound(cm, pos) != Pass;
+ } finally {
+ cm.state.suppressEdits = false;
}
+ return done
+ })
+ }
- if (type) { sawType = type; }
- if (dir > 0 && !moveOnce(!first)) { break }
+ function configureMouse(cm, repeat, event) {
+ var option = cm.getOption("configureMouse");
+ var value = option ? option(cm, repeat, event) : {};
+ if (value.unit == null) {
+ var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
+ value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
}
+ if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
+ if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
+ if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
+ return value
}
- var result = skipAtomic(doc, pos, oldPos, origDir, true);
- if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
- return result
-}
-// For relative vertical movement. Dir may be -1 or 1. Unit can be
-// "page" or "line". The resulting position will have a hitSide=true
-// property if it reached the end of the document.
-function findPosV(cm, pos, dir, unit) {
- var doc = cm.doc, x = pos.left, y;
- if (unit == "page") {
- var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
- var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
- y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
+ function leftButtonDown(cm, pos, repeat, event) {
+ if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
+ else { cm.curOp.focus = activeElt(); }
- } else if (unit == "line") {
- y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
+ var behavior = configureMouse(cm, repeat, event);
+
+ var sel = cm.doc.sel, contained;
+ if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
+ repeat == "single" && (contained = sel.contains(pos)) > -1 &&
+ (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
+ (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
+ { leftButtonStartDrag(cm, event, pos, behavior); }
+ else
+ { leftButtonSelect(cm, event, pos, behavior); }
+ }
+
+ // Start a text drag. When it ends, see if any dragging actually
+ // happen, and treat as a click if it didn't.
+ function leftButtonStartDrag(cm, event, pos, behavior) {
+ var display = cm.display, moved = false;
+ var dragEnd = operation(cm, function (e) {
+ if (webkit) { display.scroller.draggable = false; }
+ cm.state.draggingText = false;
+ off(display.wrapper.ownerDocument, "mouseup", dragEnd);
+ off(display.wrapper.ownerDocument, "mousemove", mouseMove);
+ off(display.scroller, "dragstart", dragStart);
+ off(display.scroller, "drop", dragEnd);
+ if (!moved) {
+ e_preventDefault(e);
+ if (!behavior.addNew)
+ { extendSelection(cm.doc, pos, null, null, behavior.extend); }
+ // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
+ if (webkit || ie && ie_version == 9)
+ { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
+ else
+ { display.input.focus(); }
+ }
+ });
+ var mouseMove = function(e2) {
+ moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
+ };
+ var dragStart = function () { return moved = true; };
+ // Let the drag handler handle this.
+ if (webkit) { display.scroller.draggable = true; }
+ cm.state.draggingText = dragEnd;
+ dragEnd.copy = !behavior.moveOnDrag;
+ // IE's approach to draggable
+ if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
+ on(display.wrapper.ownerDocument, "mouseup", dragEnd);
+ on(display.wrapper.ownerDocument, "mousemove", mouseMove);
+ on(display.scroller, "dragstart", dragStart);
+ on(display.scroller, "drop", dragEnd);
+
+ delayBlurEvent(cm);
+ setTimeout(function () { return display.input.focus(); }, 20);
}
- var target;
- for (;;) {
- target = coordsChar(cm, x, y);
- if (!target.outside) { break }
- if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
- y += dir * 5;
+
+ function rangeForUnit(cm, pos, unit) {
+ if (unit == "char") { return new Range(pos, pos) }
+ if (unit == "word") { return cm.findWordAt(pos) }
+ if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
+ var result = unit(cm, pos);
+ return new Range(result.from, result.to)
}
- return target
-}
-// CONTENTEDITABLE INPUT STYLE
+ // Normal selection, as opposed to text dragging.
+ function leftButtonSelect(cm, event, start, behavior) {
+ var display = cm.display, doc = cm.doc;
+ e_preventDefault(event);
-var ContentEditableInput = function(cm) {
- this.cm = cm;
- this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
- this.polling = new Delayed();
- this.composing = null;
- this.gracePeriod = false;
- this.readDOMTimeout = null;
-};
+ var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
+ if (behavior.addNew && !behavior.extend) {
+ ourIndex = doc.sel.contains(start);
+ if (ourIndex > -1)
+ { ourRange = ranges[ourIndex]; }
+ else
+ { ourRange = new Range(start, start); }
+ } else {
+ ourRange = doc.sel.primary();
+ ourIndex = doc.sel.primIndex;
+ }
-ContentEditableInput.prototype.init = function (display) {
- var this$1 = this;
+ if (behavior.unit == "rectangle") {
+ if (!behavior.addNew) { ourRange = new Range(start, start); }
+ start = posFromMouse(cm, event, true, true);
+ ourIndex = -1;
+ } else {
+ var range$$1 = rangeForUnit(cm, start, behavior.unit);
+ if (behavior.extend)
+ { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
+ else
+ { ourRange = range$$1; }
+ }
+
+ if (!behavior.addNew) {
+ ourIndex = 0;
+ setSelection(doc, new Selection([ourRange], 0), sel_mouse);
+ startSel = doc.sel;
+ } else if (ourIndex == -1) {
+ ourIndex = ranges.length;
+ setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex),
+ {scroll: false, origin: "*mouse"});
+ } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
+ setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
+ {scroll: false, origin: "*mouse"});
+ startSel = doc.sel;
+ } else {
+ replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
+ }
+
+ var lastPos = start;
+ function extendTo(pos) {
+ if (cmp(lastPos, pos) == 0) { return }
+ lastPos = pos;
+
+ if (behavior.unit == "rectangle") {
+ var ranges = [], tabSize = cm.options.tabSize;
+ var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
+ var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
+ var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
+ for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
+ line <= end; line++) {
+ var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
+ if (left == right)
+ { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
+ else if (text.length > leftPos)
+ { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
+ }
+ if (!ranges.length) { ranges.push(new Range(start, start)); }
+ setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
+ {origin: "*mouse", scroll: false});
+ cm.scrollIntoView(pos);
+ } else {
+ var oldRange = ourRange;
+ var range$$1 = rangeForUnit(cm, pos, behavior.unit);
+ var anchor = oldRange.anchor, head;
+ if (cmp(range$$1.anchor, anchor) > 0) {
+ head = range$$1.head;
+ anchor = minPos(oldRange.from(), range$$1.anchor);
+ } else {
+ head = range$$1.anchor;
+ anchor = maxPos(oldRange.to(), range$$1.head);
+ }
+ var ranges$1 = startSel.ranges.slice(0);
+ ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
+ setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse);
+ }
+ }
- var input = this, cm = input.cm;
- var div = input.div = display.lineDiv;
- disableBrowserMagic(div, cm.options.spellcheck);
+ var editorSize = display.wrapper.getBoundingClientRect();
+ // Used to ensure timeout re-tries don't fire when another extend
+ // happened in the meantime (clearTimeout isn't reliable -- at
+ // least on Chrome, the timeouts still happen even when cleared,
+ // if the clear happens after their scheduled firing time).
+ var counter = 0;
+
+ function extend(e) {
+ var curCount = ++counter;
+ var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
+ if (!cur) { return }
+ if (cmp(cur, lastPos) != 0) {
+ cm.curOp.focus = activeElt();
+ extendTo(cur);
+ var visible = visibleLines(display, doc);
+ if (cur.line >= visible.to || cur.line < visible.from)
+ { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
+ } else {
+ var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
+ if (outside) { setTimeout(operation(cm, function () {
+ if (counter != curCount) { return }
+ display.scroller.scrollTop += outside;
+ extend(e);
+ }), 50); }
+ }
+ }
- on(div, "paste", function (e) {
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
- // IE doesn't fire input events, so we schedule a read for the pasted content in this way
- if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
- });
+ function done(e) {
+ cm.state.selectingText = false;
+ counter = Infinity;
+ e_preventDefault(e);
+ display.input.focus();
+ off(display.wrapper.ownerDocument, "mousemove", move);
+ off(display.wrapper.ownerDocument, "mouseup", up);
+ doc.history.lastSelOrigin = null;
+ }
- on(div, "compositionstart", function (e) {
- this$1.composing = {data: e.data, done: false};
- });
- on(div, "compositionupdate", function (e) {
- if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
- });
- on(div, "compositionend", function (e) {
- if (this$1.composing) {
- if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
- this$1.composing.done = true;
+ var move = operation(cm, function (e) {
+ if (e.buttons === 0 || !e_button(e)) { done(e); }
+ else { extend(e); }
+ });
+ var up = operation(cm, done);
+ cm.state.selectingText = up;
+ on(display.wrapper.ownerDocument, "mousemove", move);
+ on(display.wrapper.ownerDocument, "mouseup", up);
+ }
+
+ // Used when mouse-selecting to adjust the anchor to the proper side
+ // of a bidi jump depending on the visual position of the head.
+ function bidiSimplify(cm, range$$1) {
+ var anchor = range$$1.anchor;
+ var head = range$$1.head;
+ var anchorLine = getLine(cm.doc, anchor.line);
+ if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
+ var order = getOrder(anchorLine);
+ if (!order) { return range$$1 }
+ var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
+ if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
+ var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
+ if (boundary == 0 || boundary == order.length) { return range$$1 }
+
+ // Compute the relative visual position of the head compared to the
+ // anchor (<0 is to the left, >0 to the right)
+ var leftSide;
+ if (head.line != anchor.line) {
+ leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
+ } else {
+ var headIndex = getBidiPartAt(order, head.ch, head.sticky);
+ var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
+ if (headIndex == boundary - 1 || headIndex == boundary)
+ { leftSide = dir < 0; }
+ else
+ { leftSide = dir > 0; }
}
- });
- on(div, "touchstart", function () { return input.forceCompositionEnd(); });
+ var usePart = order[boundary + (leftSide ? -1 : 0)];
+ var from = leftSide == (usePart.level == 1);
+ var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
+ return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
+ }
- on(div, "input", function () {
- if (!this$1.composing) { this$1.readFromDOMSoon(); }
- });
- function onCopyCut(e) {
- if (signalDOMEvent(cm, e)) { return }
- if (cm.somethingSelected()) {
- setLastCopied({lineWise: false, text: cm.getSelections()});
- if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
- } else if (!cm.options.lineWiseCopyCut) {
- return
+ // Determines whether an event happened in the gutter, and fires the
+ // handlers for the corresponding event.
+ function gutterEvent(cm, e, type, prevent) {
+ var mX, mY;
+ if (e.touches) {
+ mX = e.touches[0].clientX;
+ mY = e.touches[0].clientY;
} else {
- var ranges = copyableRanges(cm);
- setLastCopied({lineWise: true, text: ranges.text});
- if (e.type == "cut") {
- cm.operation(function () {
- cm.setSelections(ranges.ranges, 0, sel_dontScroll);
- cm.replaceSelection("", null, "cut");
- });
- }
+ try { mX = e.clientX; mY = e.clientY; }
+ catch(e) { return false }
}
- if (e.clipboardData) {
- e.clipboardData.clearData();
- var content = lastCopied.text.join("\n");
- // iOS exposes the clipboard API, but seems to discard content inserted into it
- e.clipboardData.setData("Text", content);
- if (e.clipboardData.getData("Text") == content) {
- e.preventDefault();
- return
+ if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
+ if (prevent) { e_preventDefault(e); }
+
+ var display = cm.display;
+ var lineBox = display.lineDiv.getBoundingClientRect();
+
+ if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
+ mY -= lineBox.top - display.viewOffset;
+
+ for (var i = 0; i < cm.options.gutters.length; ++i) {
+ var g = display.gutters.childNodes[i];
+ if (g && g.getBoundingClientRect().right >= mX) {
+ var line = lineAtHeight(cm.doc, mY);
+ var gutter = cm.options.gutters[i];
+ signal(cm, type, cm, line, gutter, e);
+ return e_defaultPrevented(e)
}
}
- // Old-fashioned briefly-focus-a-textarea hack
- var kludge = hiddenTextarea(), te = kludge.firstChild;
- cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
- te.value = lastCopied.text.join("\n");
- var hadFocus = document.activeElement;
- selectInput(te);
- setTimeout(function () {
- cm.display.lineSpace.removeChild(kludge);
- hadFocus.focus();
- if (hadFocus == div) { input.showPrimarySelection(); }
- }, 50);
- }
- on(div, "copy", onCopyCut);
- on(div, "cut", onCopyCut);
-};
-
-ContentEditableInput.prototype.prepareSelection = function () {
- var result = prepareSelection(this.cm, false);
- result.focus = this.cm.state.focused;
- return result
-};
-
-ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
- if (!info || !this.cm.display.view.length) { return }
- if (info.focus || takeFocus) { this.showPrimarySelection(); }
- this.showMultipleSelections(info);
-};
-
-ContentEditableInput.prototype.getSelection = function () {
- return this.cm.display.wrapper.ownerDocument.getSelection()
-};
-
-ContentEditableInput.prototype.showPrimarySelection = function () {
- var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
- var from = prim.from(), to = prim.to();
-
- if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
- sel.removeAllRanges();
- return
- }
-
- var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
- var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
- if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
- cmp(minPos(curAnchor, curFocus), from) == 0 &&
- cmp(maxPos(curAnchor, curFocus), to) == 0)
- { return }
-
- var view = cm.display.view;
- var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
- {node: view[0].measure.map[2], offset: 0};
- var end = to.line < cm.display.viewTo && posToDOM(cm, to);
- if (!end) {
- var measure = view[view.length - 1].measure;
- var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
- end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
- }
-
- if (!start || !end) {
- sel.removeAllRanges();
- return
- }
-
- var old = sel.rangeCount && sel.getRangeAt(0), rng;
- try { rng = range(start.node, start.offset, end.offset, end.node); }
- catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
- if (rng) {
- if (!gecko && cm.state.focused) {
- sel.collapse(start.node, start.offset);
- if (!rng.collapsed) {
- sel.removeAllRanges();
- sel.addRange(rng);
+ }
+
+ function clickInGutter(cm, e) {
+ return gutterEvent(cm, e, "gutterClick", true)
+ }
+
+ // CONTEXT MENU HANDLING
+
+ // To make the context menu work, we need to briefly unhide the
+ // textarea (making it as unobtrusive as possible) to let the
+ // right-click take effect on it.
+ function onContextMenu(cm, e) {
+ if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
+ if (signalDOMEvent(cm, e, "contextmenu")) { return }
+ if (!captureRightClick) { cm.display.input.onContextMenu(e); }
+ }
+
+ function contextMenuInGutter(cm, e) {
+ if (!hasHandler(cm, "gutterContextMenu")) { return false }
+ return gutterEvent(cm, e, "gutterContextMenu", false)
+ }
+
+ function themeChanged(cm) {
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
+ cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
+ clearCaches(cm);
+ }
+
+ var Init = {toString: function(){return "CodeMirror.Init"}};
+
+ var defaults = {};
+ var optionHandlers = {};
+
+ function defineOptions(CodeMirror) {
+ var optionHandlers = CodeMirror.optionHandlers;
+
+ function option(name, deflt, handle, notOnInit) {
+ CodeMirror.defaults[name] = deflt;
+ if (handle) { optionHandlers[name] =
+ notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
+ }
+
+ CodeMirror.defineOption = option;
+
+ // Passed to option handlers when there is no old value.
+ CodeMirror.Init = Init;
+
+ // These two are, on init, called from the constructor because they
+ // have to be initialized before the editor can start at all.
+ option("value", "", function (cm, val) { return cm.setValue(val); }, true);
+ option("mode", null, function (cm, val) {
+ cm.doc.modeOption = val;
+ loadMode(cm);
+ }, true);
+
+ option("indentUnit", 2, loadMode, true);
+ option("indentWithTabs", false);
+ option("smartIndent", true);
+ option("tabSize", 4, function (cm) {
+ resetModeState(cm);
+ clearCaches(cm);
+ regChange(cm);
+ }, true);
+
+ option("lineSeparator", null, function (cm, val) {
+ cm.doc.lineSep = val;
+ if (!val) { return }
+ var newBreaks = [], lineNo = cm.doc.first;
+ cm.doc.iter(function (line) {
+ for (var pos = 0;;) {
+ var found = line.text.indexOf(val, pos);
+ if (found == -1) { break }
+ pos = found + val.length;
+ newBreaks.push(Pos(lineNo, found));
+ }
+ lineNo++;
+ });
+ for (var i = newBreaks.length - 1; i >= 0; i--)
+ { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
+ });
+ option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
+ cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
+ if (old != Init) { cm.refresh(); }
+ });
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
+ option("electricChars", true);
+ option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
+ throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
+ }, true);
+ option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
+ option("rtlMoveVisually", !windows);
+ option("wholeLineUpdateBefore", true);
+
+ option("theme", "default", function (cm) {
+ themeChanged(cm);
+ guttersChanged(cm);
+ }, true);
+ option("keyMap", "default", function (cm, val, old) {
+ var next = getKeyMap(val);
+ var prev = old != Init && getKeyMap(old);
+ if (prev && prev.detach) { prev.detach(cm, next); }
+ if (next.attach) { next.attach(cm, prev || null); }
+ });
+ option("extraKeys", null);
+ option("configureMouse", null);
+
+ option("lineWrapping", false, wrappingChanged, true);
+ option("gutters", [], function (cm) {
+ setGuttersForLineNumbers(cm.options);
+ guttersChanged(cm);
+ }, true);
+ option("fixedGutter", true, function (cm, val) {
+ cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
+ cm.refresh();
+ }, true);
+ option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
+ option("scrollbarStyle", "native", function (cm) {
+ initScrollbars(cm);
+ updateScrollbars(cm);
+ cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
+ cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
+ }, true);
+ option("lineNumbers", false, function (cm) {
+ setGuttersForLineNumbers(cm.options);
+ guttersChanged(cm);
+ }, true);
+ option("firstLineNumber", 1, guttersChanged, true);
+ option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
+ option("showCursorWhenSelecting", false, updateSelection, true);
+
+ option("resetSelectionOnContextMenu", true);
+ option("lineWiseCopyCut", true);
+ option("pasteLinesPerSelection", true);
+ option("selectionsMayTouch", false);
+
+ option("readOnly", false, function (cm, val) {
+ if (val == "nocursor") {
+ onBlur(cm);
+ cm.display.input.blur();
}
+ cm.display.input.readOnlyChanged(val);
+ });
+ option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
+ option("dragDrop", true, dragDropChanged);
+ option("allowDropFileTypes", null);
+
+ option("cursorBlinkRate", 530);
+ option("cursorScrollMargin", 0);
+ option("cursorHeight", 1, updateSelection, true);
+ option("singleCursorHeightPerLine", true, updateSelection, true);
+ option("workTime", 100);
+ option("workDelay", 100);
+ option("flattenSpans", true, resetModeState, true);
+ option("addModeClass", false, resetModeState, true);
+ option("pollInterval", 100);
+ option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
+ option("historyEventDelay", 1250);
+ option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
+ option("maxHighlightLength", 10000, resetModeState, true);
+ option("moveInputWithCursor", true, function (cm, val) {
+ if (!val) { cm.display.input.resetPosition(); }
+ });
+
+ option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
+ option("autofocus", null);
+ option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
+ option("phrases", null);
+ }
+
+ function guttersChanged(cm) {
+ updateGutters(cm);
+ regChange(cm);
+ alignHorizontally(cm);
+ }
+
+ function dragDropChanged(cm, value, old) {
+ var wasOn = old && old != Init;
+ if (!value != !wasOn) {
+ var funcs = cm.display.dragFunctions;
+ var toggle = value ? on : off;
+ toggle(cm.display.scroller, "dragstart", funcs.start);
+ toggle(cm.display.scroller, "dragenter", funcs.enter);
+ toggle(cm.display.scroller, "dragover", funcs.over);
+ toggle(cm.display.scroller, "dragleave", funcs.leave);
+ toggle(cm.display.scroller, "drop", funcs.drop);
+ }
+ }
+
+ function wrappingChanged(cm) {
+ if (cm.options.lineWrapping) {
+ addClass(cm.display.wrapper, "CodeMirror-wrap");
+ cm.display.sizer.style.minWidth = "";
+ cm.display.sizerWidth = null;
} else {
- sel.removeAllRanges();
- sel.addRange(rng);
+ rmClass(cm.display.wrapper, "CodeMirror-wrap");
+ findMaxLine(cm);
}
- if (old && sel.anchorNode == null) { sel.addRange(old); }
- else if (gecko) { this.startGracePeriod(); }
+ estimateLineHeights(cm);
+ regChange(cm);
+ clearCaches(cm);
+ setTimeout(function () { return updateScrollbars(cm); }, 100);
}
- this.rememberSelection();
-};
-ContentEditableInput.prototype.startGracePeriod = function () {
+ // A CodeMirror instance represents an editor. This is the object
+ // that user code is usually dealing with.
+
+ function CodeMirror(place, options) {
var this$1 = this;
- clearTimeout(this.gracePeriod);
- this.gracePeriod = setTimeout(function () {
- this$1.gracePeriod = false;
- if (this$1.selectionChanged())
- { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
- }, 20);
-};
-
-ContentEditableInput.prototype.showMultipleSelections = function (info) {
- removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
- removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
-};
-
-ContentEditableInput.prototype.rememberSelection = function () {
- var sel = this.getSelection();
- this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
- this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
-};
-
-ContentEditableInput.prototype.selectionInEditor = function () {
- var sel = this.getSelection();
- if (!sel.rangeCount) { return false }
- var node = sel.getRangeAt(0).commonAncestorContainer;
- return contains(this.div, node)
-};
-
-ContentEditableInput.prototype.focus = function () {
- if (this.cm.options.readOnly != "nocursor") {
- if (!this.selectionInEditor())
- { this.showSelection(this.prepareSelection(), true); }
- this.div.focus();
+ if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }
+
+ this.options = options = options ? copyObj(options) : {};
+ // Determine effective options based on given values and defaults.
+ copyObj(defaults, options, false);
+ setGuttersForLineNumbers(options);
+
+ var doc = options.value;
+ if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
+ else if (options.mode) { doc.modeOption = options.mode; }
+ this.doc = doc;
+
+ var input = new CodeMirror.inputStyles[options.inputStyle](this);
+ var display = this.display = new Display(place, doc, input);
+ display.wrapper.CodeMirror = this;
+ updateGutters(this);
+ themeChanged(this);
+ if (options.lineWrapping)
+ { this.display.wrapper.className += " CodeMirror-wrap"; }
+ initScrollbars(this);
+
+ this.state = {
+ keyMaps: [], // stores maps added by addKeyMap
+ overlays: [], // highlighting overlays, as added by addOverlay
+ modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
+ overwrite: false,
+ delayingBlurEvent: false,
+ focused: false,
+ suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
+ pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
+ selectingText: false,
+ draggingText: false,
+ highlight: new Delayed(), // stores highlight worker timeout
+ keySeq: null, // Unfinished key sequence
+ specialChars: null
+ };
+
+ if (options.autofocus && !mobile) { display.input.focus(); }
+
+ // Override magic textarea content restore that IE sometimes does
+ // on our hidden textarea on reload
+ if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
+
+ registerEventHandlers(this);
+ ensureGlobalHandlers();
+
+ startOperation(this);
+ this.curOp.forceUpdate = true;
+ attachDoc(this, doc);
+
+ if ((options.autofocus && !mobile) || this.hasFocus())
+ { setTimeout(bind(onFocus, this), 20); }
+ else
+ { onBlur(this); }
+
+ for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
+ { optionHandlers[opt](this, options[opt], Init); } }
+ maybeUpdateLineNumberWidth(this);
+ if (options.finishInit) { options.finishInit(this); }
+ for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); }
+ endOperation(this);
+ // Suppress optimizelegibility in Webkit, since it breaks text
+ // measuring on line wrapping boundaries.
+ if (webkit && options.lineWrapping &&
+ getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
+ { display.lineDiv.style.textRendering = "auto"; }
+ }
+
+ // The default configuration options.
+ CodeMirror.defaults = defaults;
+ // Functions to run when options are changed.
+ CodeMirror.optionHandlers = optionHandlers;
+
+ // Attach the necessary event handlers when initializing the editor
+ function registerEventHandlers(cm) {
+ var d = cm.display;
+ on(d.scroller, "mousedown", operation(cm, onMouseDown));
+ // Older IE's will not fire a second mousedown for a double click
+ if (ie && ie_version < 11)
+ { on(d.scroller, "dblclick", operation(cm, function (e) {
+ if (signalDOMEvent(cm, e)) { return }
+ var pos = posFromMouse(cm, e);
+ if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
+ e_preventDefault(e);
+ var word = cm.findWordAt(pos);
+ extendSelection(cm.doc, word.anchor, word.head);
+ })); }
+ else
+ { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
+ // Some browsers fire contextmenu *after* opening the menu, at
+ // which point we can't mess with it anymore. Context menu is
+ // handled in onMouseDown for these browsers.
+ on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); });
+
+ // Used to suppress mouse event handling when a touch happens
+ var touchFinished, prevTouch = {end: 0};
+ function finishTouch() {
+ if (d.activeTouch) {
+ touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
+ prevTouch = d.activeTouch;
+ prevTouch.end = +new Date;
+ }
+ }
+ function isMouseLikeTouchEvent(e) {
+ if (e.touches.length != 1) { return false }
+ var touch = e.touches[0];
+ return touch.radiusX <= 1 && touch.radiusY <= 1
+ }
+ function farAway(touch, other) {
+ if (other.left == null) { return true }
+ var dx = other.left - touch.left, dy = other.top - touch.top;
+ return dx * dx + dy * dy > 20 * 20
+ }
+ on(d.scroller, "touchstart", function (e) {
+ if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
+ d.input.ensurePolled();
+ clearTimeout(touchFinished);
+ var now = +new Date;
+ d.activeTouch = {start: now, moved: false,
+ prev: now - prevTouch.end <= 300 ? prevTouch : null};
+ if (e.touches.length == 1) {
+ d.activeTouch.left = e.touches[0].pageX;
+ d.activeTouch.top = e.touches[0].pageY;
+ }
+ }
+ });
+ on(d.scroller, "touchmove", function () {
+ if (d.activeTouch) { d.activeTouch.moved = true; }
+ });
+ on(d.scroller, "touchend", function (e) {
+ var touch = d.activeTouch;
+ if (touch && !eventInWidget(d, e) && touch.left != null &&
+ !touch.moved && new Date - touch.start < 300) {
+ var pos = cm.coordsChar(d.activeTouch, "page"), range;
+ if (!touch.prev || farAway(touch, touch.prev)) // Single tap
+ { range = new Range(pos, pos); }
+ else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
+ { range = cm.findWordAt(pos); }
+ else // Triple tap
+ { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
+ cm.setSelection(range.anchor, range.head);
+ cm.focus();
+ e_preventDefault(e);
+ }
+ finishTouch();
+ });
+ on(d.scroller, "touchcancel", finishTouch);
+
+ // Sync scrolling between fake scrollbars and real scrollable
+ // area, ensure viewport is updated when scrolling.
+ on(d.scroller, "scroll", function () {
+ if (d.scroller.clientHeight) {
+ updateScrollTop(cm, d.scroller.scrollTop);
+ setScrollLeft(cm, d.scroller.scrollLeft, true);
+ signal(cm, "scroll", cm);
+ }
+ });
+
+ // Listen to wheel events in order to try and update the viewport on time.
+ on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
+ on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
+
+ // Prevent wrapper from ever scrolling
+ on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
+
+ d.dragFunctions = {
+ enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
+ over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
+ start: function (e) { return onDragStart(cm, e); },
+ drop: operation(cm, onDrop),
+ leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
+ };
+
+ var inp = d.input.getField();
+ on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
+ on(inp, "keydown", operation(cm, onKeyDown));
+ on(inp, "keypress", operation(cm, onKeyPress));
+ on(inp, "focus", function (e) { return onFocus(cm, e); });
+ on(inp, "blur", function (e) { return onBlur(cm, e); });
+ }
+
+ var initHooks = [];
+ CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };
+
+ // Indent the given line. The how parameter can be "smart",
+ // "add"/null, "subtract", or "prev". When aggressive is false
+ // (typically set to true for forced single-line indents), empty
+ // lines are not indented, and places where the mode returns Pass
+ // are left alone.
+ function indentLine(cm, n, how, aggressive) {
+ var doc = cm.doc, state;
+ if (how == null) { how = "add"; }
+ if (how == "smart") {
+ // Fall back to "prev" when the mode doesn't have an indentation
+ // method.
+ if (!doc.mode.indent) { how = "prev"; }
+ else { state = getContextBefore(cm, n).state; }
+ }
+
+ var tabSize = cm.options.tabSize;
+ var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
+ if (line.stateAfter) { line.stateAfter = null; }
+ var curSpaceString = line.text.match(/^\s*/)[0], indentation;
+ if (!aggressive && !/\S/.test(line.text)) {
+ indentation = 0;
+ how = "not";
+ } else if (how == "smart") {
+ indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+ if (indentation == Pass || indentation > 150) {
+ if (!aggressive) { return }
+ how = "prev";
+ }
+ }
+ if (how == "prev") {
+ if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
+ else { indentation = 0; }
+ } else if (how == "add") {
+ indentation = curSpace + cm.options.indentUnit;
+ } else if (how == "subtract") {
+ indentation = curSpace - cm.options.indentUnit;
+ } else if (typeof how == "number") {
+ indentation = curSpace + how;
+ }
+ indentation = Math.max(0, indentation);
+
+ var indentString = "", pos = 0;
+ if (cm.options.indentWithTabs)
+ { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
+ if (pos < indentation) { indentString += spaceStr(indentation - pos); }
+
+ if (indentString != curSpaceString) {
+ replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
+ line.stateAfter = null;
+ return true
+ } else {
+ // Ensure that, if the cursor was in the whitespace at the start
+ // of the line, it is moved to the end of that space.
+ for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
+ var range = doc.sel.ranges[i$1];
+ if (range.head.line == n && range.head.ch < curSpaceString.length) {
+ var pos$1 = Pos(n, curSpaceString.length);
+ replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
+ break
+ }
+ }
+ }
}
-};
-ContentEditableInput.prototype.blur = function () { this.div.blur(); };
-ContentEditableInput.prototype.getField = function () { return this.div };
-
-ContentEditableInput.prototype.supportsTouch = function () { return true };
-
-ContentEditableInput.prototype.receivedFocus = function () {
- var input = this;
- if (this.selectionInEditor())
- { this.pollSelection(); }
- else
- { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
-
- function poll() {
- if (input.cm.state.focused) {
- input.pollSelection();
- input.polling.set(input.cm.options.pollInterval, poll);
- }
- }
- this.polling.set(this.cm.options.pollInterval, poll);
-};
-
-ContentEditableInput.prototype.selectionChanged = function () {
- var sel = this.getSelection();
- return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
- sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
-};
-
-ContentEditableInput.prototype.pollSelection = function () {
- if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
- var sel = this.getSelection(), cm = this.cm;
- // On Android Chrome (version 56, at least), backspacing into an
- // uneditable block element will put the cursor in that element,
- // and then, because it's not editable, hide the virtual keyboard.
- // Because Android doesn't allow us to actually detect backspace
- // presses in a sane way, this code checks for when that happens
- // and simulates a backspace press in this case.
- if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
- this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
- this.blur();
- this.focus();
- return
- }
- if (this.composing) { return }
- this.rememberSelection();
- var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
- var head = domToPos(cm, sel.focusNode, sel.focusOffset);
- if (anchor && head) { runInOp(cm, function () {
- setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
- if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
- }); }
-};
-
-ContentEditableInput.prototype.pollContent = function () {
- if (this.readDOMTimeout != null) {
- clearTimeout(this.readDOMTimeout);
- this.readDOMTimeout = null;
+
+ // This will be set to a {lineWise: bool, text: [string]} object, so
+ // that, when pasting, we know what kind of selections the copied
+ // text was made out of.
+ var lastCopied = null;
+
+ function setLastCopied(newLastCopied) {
+ lastCopied = newLastCopied;
}
- var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
- var from = sel.from(), to = sel.to();
- if (from.ch == 0 && from.line > cm.firstLine())
- { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
- if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
- { to = Pos(to.line + 1, 0); }
- if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
-
- var fromIndex, fromLine, fromNode;
- if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
- fromLine = lineNo(display.view[0].line);
- fromNode = display.view[0].node;
- } else {
- fromLine = lineNo(display.view[fromIndex].line);
- fromNode = display.view[fromIndex - 1].node.nextSibling;
- }
- var toIndex = findViewIndex(cm, to.line);
- var toLine, toNode;
- if (toIndex == display.view.length - 1) {
- toLine = display.viewTo - 1;
- toNode = display.lineDiv.lastChild;
- } else {
- toLine = lineNo(display.view[toIndex + 1].line) - 1;
- toNode = display.view[toIndex + 1].node.previousSibling;
- }
-
- if (!fromNode) { return false }
- var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
- var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
- while (newText.length > 1 && oldText.length > 1) {
- if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
- else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
- else { break }
- }
-
- var cutFront = 0, cutEnd = 0;
- var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
- while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
- { ++cutFront; }
- var newBot = lst(newText), oldBot = lst(oldText);
- var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
- oldBot.length - (oldText.length == 1 ? cutFront : 0));
- while (cutEnd < maxCutEnd &&
- newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
- { ++cutEnd; }
- // Try to move start of change to start of selection if ambiguous
- if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
- while (cutFront && cutFront > from.ch &&
- newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
- cutFront--;
- cutEnd++;
- }
- }
-
- newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
- newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
-
- var chFrom = Pos(fromLine, cutFront);
- var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
- if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
- replaceRange(cm.doc, newText, chFrom, chTo, "+input");
- return true
+ function applyTextInput(cm, inserted, deleted, sel, origin) {
+ var doc = cm.doc;
+ cm.display.shift = false;
+ if (!sel) { sel = doc.sel; }
+
+ var paste = cm.state.pasteIncoming || origin == "paste";
+ var textLines = splitLinesAuto(inserted), multiPaste = null;
+ // When pasting N lines into N selections, insert one line per selection
+ if (paste && sel.ranges.length > 1) {
+ if (lastCopied && lastCopied.text.join("\n") == inserted) {
+ if (sel.ranges.length % lastCopied.text.length == 0) {
+ multiPaste = [];
+ for (var i = 0; i < lastCopied.text.length; i++)
+ { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
+ }
+ } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
+ multiPaste = map(textLines, function (l) { return [l]; });
+ }
+ }
+
+ var updateInput = cm.curOp.updateInput;
+ // Normal behavior is to insert the new text into every selection
+ for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
+ var range$$1 = sel.ranges[i$1];
+ var from = range$$1.from(), to = range$$1.to();
+ if (range$$1.empty()) {
+ if (deleted && deleted > 0) // Handle deletion
+ { from = Pos(from.line, from.ch - deleted); }
+ else if (cm.state.overwrite && !paste) // Handle overwrite
+ { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
+ else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
+ { from = to = Pos(from.line, 0); }
+ }
+ var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
+ origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
+ makeChange(cm.doc, changeEvent);
+ signalLater(cm, "inputRead", cm, changeEvent);
+ }
+ if (inserted && !paste)
+ { triggerElectric(cm, inserted); }
+
+ ensureCursorVisible(cm);
+ if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; }
+ cm.curOp.typing = true;
+ cm.state.pasteIncoming = cm.state.cutIncoming = false;
}
-};
-
-ContentEditableInput.prototype.ensurePolled = function () {
- this.forceCompositionEnd();
-};
-ContentEditableInput.prototype.reset = function () {
- this.forceCompositionEnd();
-};
-ContentEditableInput.prototype.forceCompositionEnd = function () {
- if (!this.composing) { return }
- clearTimeout(this.readDOMTimeout);
- this.composing = null;
- this.updateFromDOM();
- this.div.blur();
- this.div.focus();
-};
-ContentEditableInput.prototype.readFromDOMSoon = function () {
- var this$1 = this;
- if (this.readDOMTimeout != null) { return }
- this.readDOMTimeout = setTimeout(function () {
- this$1.readDOMTimeout = null;
- if (this$1.composing) {
- if (this$1.composing.done) { this$1.composing = null; }
- else { return }
+ function handlePaste(e, cm) {
+ var pasted = e.clipboardData && e.clipboardData.getData("Text");
+ if (pasted) {
+ e.preventDefault();
+ if (!cm.isReadOnly() && !cm.options.disableInput)
+ { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
+ return true
}
- this$1.updateFromDOM();
- }, 80);
-};
+ }
-ContentEditableInput.prototype.updateFromDOM = function () {
- var this$1 = this;
+ function triggerElectric(cm, inserted) {
+ // When an 'electric' character is inserted, immediately trigger a reindent
+ if (!cm.options.electricChars || !cm.options.smartIndent) { return }
+ var sel = cm.doc.sel;
- if (this.cm.isReadOnly() || !this.pollContent())
- { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
-};
-
-ContentEditableInput.prototype.setUneditable = function (node) {
- node.contentEditable = "false";
-};
-
-ContentEditableInput.prototype.onKeyPress = function (e) {
- if (e.charCode == 0 || this.composing) { return }
- e.preventDefault();
- if (!this.cm.isReadOnly())
- { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
-};
-
-ContentEditableInput.prototype.readOnlyChanged = function (val) {
- this.div.contentEditable = String(val != "nocursor");
-};
-
-ContentEditableInput.prototype.onContextMenu = function () {};
-ContentEditableInput.prototype.resetPosition = function () {};
-
-ContentEditableInput.prototype.needsContentAttribute = true;
-
-function posToDOM(cm, pos) {
- var view = findViewForLine(cm, pos.line);
- if (!view || view.hidden) { return null }
- var line = getLine(cm.doc, pos.line);
- var info = mapFromLineView(view, line, pos.line);
-
- var order = getOrder(line, cm.doc.direction), side = "left";
- if (order) {
- var partPos = getBidiPartAt(order, pos.ch);
- side = partPos % 2 ? "right" : "left";
- }
- var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
- result.offset = result.collapse == "right" ? result.end : result.start;
- return result
-}
-
-function isInGutter(node) {
- for (var scan = node; scan; scan = scan.parentNode)
- { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
- return false
-}
-
-function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
-
-function domTextBetween(cm, from, to, fromLine, toLine) {
- var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;
- function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
- function close() {
- if (closing) {
- text += lineSep;
- if (extraLinebreak) { text += lineSep; }
- closing = extraLinebreak = false;
- }
- }
- function addText(str) {
- if (str) {
- close();
- text += str;
- }
- }
- function walk(node) {
- if (node.nodeType == 1) {
- var cmText = node.getAttribute("cm-text");
- if (cmText) {
- addText(cmText);
- return
+ for (var i = sel.ranges.length - 1; i >= 0; i--) {
+ var range$$1 = sel.ranges[i];
+ if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
+ var mode = cm.getModeAt(range$$1.head);
+ var indented = false;
+ if (mode.electricChars) {
+ for (var j = 0; j < mode.electricChars.length; j++)
+ { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
+ indented = indentLine(cm, range$$1.head.line, "smart");
+ break
+ } }
+ } else if (mode.electricInput) {
+ if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
+ { indented = indentLine(cm, range$$1.head.line, "smart"); }
}
- var markerID = node.getAttribute("cm-marker"), range$$1;
- if (markerID) {
- var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
- if (found.length && (range$$1 = found[0].find(0)))
- { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
- return
+ if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
+ }
+ }
+
+ function copyableRanges(cm) {
+ var text = [], ranges = [];
+ for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
+ var line = cm.doc.sel.ranges[i].head.line;
+ var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
+ ranges.push(lineRange);
+ text.push(cm.getRange(lineRange.anchor, lineRange.head));
+ }
+ return {text: text, ranges: ranges}
+ }
+
+ function disableBrowserMagic(field, spellcheck) {
+ field.setAttribute("autocorrect", "off");
+ field.setAttribute("autocapitalize", "off");
+ field.setAttribute("spellcheck", !!spellcheck);
+ }
+
+ function hiddenTextarea() {
+ var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
+ var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
+ // The textarea is kept positioned near the cursor to prevent the
+ // fact that it'll be scrolled into view on input from scrolling
+ // our fake cursor out of view. On webkit, when wrap=off, paste is
+ // very slow. So make the area wide instead.
+ if (webkit) { te.style.width = "1000px"; }
+ else { te.setAttribute("wrap", "off"); }
+ // If border: 0; -- iOS fails to open keyboard (issue #1287)
+ if (ios) { te.style.border = "1px solid black"; }
+ disableBrowserMagic(te);
+ return div
+ }
+
+ // The publicly visible API. Note that methodOp(f) means
+ // 'wrap f in an operation, performed on its `this` parameter'.
+
+ // This is not the complete set of editor methods. Most of the
+ // methods defined on the Doc type are also injected into
+ // CodeMirror.prototype, for backwards compatibility and
+ // convenience.
+
+ function addEditorMethods(CodeMirror) {
+ var optionHandlers = CodeMirror.optionHandlers;
+
+ var helpers = CodeMirror.helpers = {};
+
+ CodeMirror.prototype = {
+ constructor: CodeMirror,
+ focus: function(){window.focus(); this.display.input.focus();},
+
+ setOption: function(option, value) {
+ var options = this.options, old = options[option];
+ if (options[option] == value && option != "mode") { return }
+ options[option] = value;
+ if (optionHandlers.hasOwnProperty(option))
+ { operation(this, optionHandlers[option])(this, value, old); }
+ signal(this, "optionChange", this, option);
+ },
+
+ getOption: function(option) {return this.options[option]},
+ getDoc: function() {return this.doc},
+
+ addKeyMap: function(map$$1, bottom) {
+ this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
+ },
+ removeKeyMap: function(map$$1) {
+ var maps = this.state.keyMaps;
+ for (var i = 0; i < maps.length; ++i)
+ { if (maps[i] == map$$1 || maps[i].name == map$$1) {
+ maps.splice(i, 1);
+ return true
+ } }
+ },
+
+ addOverlay: methodOp(function(spec, options) {
+ var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
+ if (mode.startState) { throw new Error("Overlays may not be stateful.") }
+ insertSorted(this.state.overlays,
+ {mode: mode, modeSpec: spec, opaque: options && options.opaque,
+ priority: (options && options.priority) || 0},
+ function (overlay) { return overlay.priority; });
+ this.state.modeGen++;
+ regChange(this);
+ }),
+ removeOverlay: methodOp(function(spec) {
+ var overlays = this.state.overlays;
+ for (var i = 0; i < overlays.length; ++i) {
+ var cur = overlays[i].modeSpec;
+ if (cur == spec || typeof spec == "string" && cur.name == spec) {
+ overlays.splice(i, 1);
+ this.state.modeGen++;
+ regChange(this);
+ return
+ }
+ }
+ }),
+
+ indentLine: methodOp(function(n, dir, aggressive) {
+ if (typeof dir != "string" && typeof dir != "number") {
+ if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
+ else { dir = dir ? "add" : "subtract"; }
+ }
+ if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
+ }),
+ indentSelection: methodOp(function(how) {
+ var ranges = this.doc.sel.ranges, end = -1;
+ for (var i = 0; i < ranges.length; i++) {
+ var range$$1 = ranges[i];
+ if (!range$$1.empty()) {
+ var from = range$$1.from(), to = range$$1.to();
+ var start = Math.max(end, from.line);
+ end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
+ for (var j = start; j < end; ++j)
+ { indentLine(this, j, how); }
+ var newRanges = this.doc.sel.ranges;
+ if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
+ { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
+ } else if (range$$1.head.line > end) {
+ indentLine(this, range$$1.head.line, how, true);
+ end = range$$1.head.line;
+ if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); }
+ }
+ }
+ }),
+
+ // Fetch the parser token for a given character. Useful for hacks
+ // that want to inspect the mode state (say, for completion).
+ getTokenAt: function(pos, precise) {
+ return takeToken(this, pos, precise)
+ },
+
+ getLineTokens: function(line, precise) {
+ return takeToken(this, Pos(line), precise, true)
+ },
+
+ getTokenTypeAt: function(pos) {
+ pos = clipPos(this.doc, pos);
+ var styles = getLineStyles(this, getLine(this.doc, pos.line));
+ var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
+ var type;
+ if (ch == 0) { type = styles[2]; }
+ else { for (;;) {
+ var mid = (before + after) >> 1;
+ if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
+ else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
+ else { type = styles[mid * 2 + 2]; break }
+ } }
+ var cut = type ? type.indexOf("overlay ") : -1;
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
+ },
+
+ getModeAt: function(pos) {
+ var mode = this.doc.mode;
+ if (!mode.innerMode) { return mode }
+ return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
+ },
+
+ getHelper: function(pos, type) {
+ return this.getHelpers(pos, type)[0]
+ },
+
+ getHelpers: function(pos, type) {
+ var found = [];
+ if (!helpers.hasOwnProperty(type)) { return found }
+ var help = helpers[type], mode = this.getModeAt(pos);
+ if (typeof mode[type] == "string") {
+ if (help[mode[type]]) { found.push(help[mode[type]]); }
+ } else if (mode[type]) {
+ for (var i = 0; i < mode[type].length; i++) {
+ var val = help[mode[type][i]];
+ if (val) { found.push(val); }
+ }
+ } else if (mode.helperType && help[mode.helperType]) {
+ found.push(help[mode.helperType]);
+ } else if (help[mode.name]) {
+ found.push(help[mode.name]);
+ }
+ for (var i$1 = 0; i$1 < help._global.length; i$1++) {
+ var cur = help._global[i$1];
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
+ { found.push(cur.val); }
+ }
+ return found
+ },
+
+ getStateAfter: function(line, precise) {
+ var doc = this.doc;
+ line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
+ return getContextBefore(this, line + 1, precise).state
+ },
+
+ cursorCoords: function(start, mode) {
+ var pos, range$$1 = this.doc.sel.primary();
+ if (start == null) { pos = range$$1.head; }
+ else if (typeof start == "object") { pos = clipPos(this.doc, start); }
+ else { pos = start ? range$$1.from() : range$$1.to(); }
+ return cursorCoords(this, pos, mode || "page")
+ },
+
+ charCoords: function(pos, mode) {
+ return charCoords(this, clipPos(this.doc, pos), mode || "page")
+ },
+
+ coordsChar: function(coords, mode) {
+ coords = fromCoordSystem(this, coords, mode || "page");
+ return coordsChar(this, coords.left, coords.top)
+ },
+
+ lineAtHeight: function(height, mode) {
+ height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
+ return lineAtHeight(this.doc, height + this.display.viewOffset)
+ },
+ heightAtLine: function(line, mode, includeWidgets) {
+ var end = false, lineObj;
+ if (typeof line == "number") {
+ var last = this.doc.first + this.doc.size - 1;
+ if (line < this.doc.first) { line = this.doc.first; }
+ else if (line > last) { line = last; end = true; }
+ lineObj = getLine(this.doc, line);
+ } else {
+ lineObj = line;
+ }
+ return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
+ (end ? this.doc.height - heightAtLine(lineObj) : 0)
+ },
+
+ defaultTextHeight: function() { return textHeight(this.display) },
+ defaultCharWidth: function() { return charWidth(this.display) },
+
+ getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
+
+ addWidget: function(pos, node, scroll, vert, horiz) {
+ var display = this.display;
+ pos = cursorCoords(this, clipPos(this.doc, pos));
+ var top = pos.bottom, left = pos.left;
+ node.style.position = "absolute";
+ node.setAttribute("cm-ignore-events", "true");
+ this.display.input.setUneditable(node);
+ display.sizer.appendChild(node);
+ if (vert == "over") {
+ top = pos.top;
+ } else if (vert == "above" || vert == "near") {
+ var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
+ hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
+ // Default to positioning above (if specified and possible); otherwise default to positioning below
+ if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
+ { top = pos.top - node.offsetHeight; }
+ else if (pos.bottom + node.offsetHeight <= vspace)
+ { top = pos.bottom; }
+ if (left + node.offsetWidth > hspace)
+ { left = hspace - node.offsetWidth; }
+ }
+ node.style.top = top + "px";
+ node.style.left = node.style.right = "";
+ if (horiz == "right") {
+ left = display.sizer.clientWidth - node.offsetWidth;
+ node.style.right = "0px";
+ } else {
+ if (horiz == "left") { left = 0; }
+ else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
+ node.style.left = left + "px";
+ }
+ if (scroll)
+ { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
+ },
+
+ triggerOnKeyDown: methodOp(onKeyDown),
+ triggerOnKeyPress: methodOp(onKeyPress),
+ triggerOnKeyUp: onKeyUp,
+ triggerOnMouseDown: methodOp(onMouseDown),
+
+ execCommand: function(cmd) {
+ if (commands.hasOwnProperty(cmd))
+ { return commands[cmd].call(null, this) }
+ },
+
+ triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
+
+ findPosH: function(from, amount, unit, visually) {
+ var dir = 1;
+ if (amount < 0) { dir = -1; amount = -amount; }
+ var cur = clipPos(this.doc, from);
+ for (var i = 0; i < amount; ++i) {
+ cur = findPosH(this.doc, cur, dir, unit, visually);
+ if (cur.hitSide) { break }
+ }
+ return cur
+ },
+
+ moveH: methodOp(function(dir, unit) {
+ var this$1 = this;
+
+ this.extendSelectionsBy(function (range$$1) {
+ if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
+ { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
+ else
+ { return dir < 0 ? range$$1.from() : range$$1.to() }
+ }, sel_move);
+ }),
+
+ deleteH: methodOp(function(dir, unit) {
+ var sel = this.doc.sel, doc = this.doc;
+ if (sel.somethingSelected())
+ { doc.replaceSelection("", null, "+delete"); }
+ else
+ { deleteNearSelection(this, function (range$$1) {
+ var other = findPosH(doc, range$$1.head, dir, unit, false);
+ return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
+ }); }
+ }),
+
+ findPosV: function(from, amount, unit, goalColumn) {
+ var dir = 1, x = goalColumn;
+ if (amount < 0) { dir = -1; amount = -amount; }
+ var cur = clipPos(this.doc, from);
+ for (var i = 0; i < amount; ++i) {
+ var coords = cursorCoords(this, cur, "div");
+ if (x == null) { x = coords.left; }
+ else { coords.left = x; }
+ cur = findPosV(this, coords, dir, unit);
+ if (cur.hitSide) { break }
+ }
+ return cur
+ },
+
+ moveV: methodOp(function(dir, unit) {
+ var this$1 = this;
+
+ var doc = this.doc, goals = [];
+ var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
+ doc.extendSelectionsBy(function (range$$1) {
+ if (collapse)
+ { return dir < 0 ? range$$1.from() : range$$1.to() }
+ var headPos = cursorCoords(this$1, range$$1.head, "div");
+ if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
+ goals.push(headPos.left);
+ var pos = findPosV(this$1, headPos, dir, unit);
+ if (unit == "page" && range$$1 == doc.sel.primary())
+ { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
+ return pos
+ }, sel_move);
+ if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
+ { doc.sel.ranges[i].goalColumn = goals[i]; } }
+ }),
+
+ // Find the word at the given position (as returned by coordsChar).
+ findWordAt: function(pos) {
+ var doc = this.doc, line = getLine(doc, pos.line).text;
+ var start = pos.ch, end = pos.ch;
+ if (line) {
+ var helper = this.getHelper(pos, "wordChars");
+ if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
+ var startChar = line.charAt(start);
+ var check = isWordChar(startChar, helper)
+ ? function (ch) { return isWordChar(ch, helper); }
+ : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
+ : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
+ while (start > 0 && check(line.charAt(start - 1))) { --start; }
+ while (end < line.length && check(line.charAt(end))) { ++end; }
+ }
+ return new Range(Pos(pos.line, start), Pos(pos.line, end))
+ },
+
+ toggleOverwrite: function(value) {
+ if (value != null && value == this.state.overwrite) { return }
+ if (this.state.overwrite = !this.state.overwrite)
+ { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
+ else
+ { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
+
+ signal(this, "overwriteToggle", this, this.state.overwrite);
+ },
+ hasFocus: function() { return this.display.input.getField() == activeElt() },
+ isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
+
+ scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
+ getScrollInfo: function() {
+ var scroller = this.display.scroller;
+ return {left: scroller.scrollLeft, top: scroller.scrollTop,
+ height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
+ width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
+ clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
+ },
+
+ scrollIntoView: methodOp(function(range$$1, margin) {
+ if (range$$1 == null) {
+ range$$1 = {from: this.doc.sel.primary().head, to: null};
+ if (margin == null) { margin = this.options.cursorScrollMargin; }
+ } else if (typeof range$$1 == "number") {
+ range$$1 = {from: Pos(range$$1, 0), to: null};
+ } else if (range$$1.from == null) {
+ range$$1 = {from: range$$1, to: null};
+ }
+ if (!range$$1.to) { range$$1.to = range$$1.from; }
+ range$$1.margin = margin || 0;
+
+ if (range$$1.from.line != null) {
+ scrollToRange(this, range$$1);
+ } else {
+ scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
+ }
+ }),
+
+ setSize: methodOp(function(width, height) {
+ var this$1 = this;
+
+ var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
+ if (width != null) { this.display.wrapper.style.width = interpret(width); }
+ if (height != null) { this.display.wrapper.style.height = interpret(height); }
+ if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
+ var lineNo$$1 = this.display.viewFrom;
+ this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
+ if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
+ { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
+ ++lineNo$$1;
+ });
+ this.curOp.forceUpdate = true;
+ signal(this, "refresh", this);
+ }),
+
+ operation: function(f){return runInOp(this, f)},
+ startOperation: function(){return startOperation(this)},
+ endOperation: function(){return endOperation(this)},
+
+ refresh: methodOp(function() {
+ var oldHeight = this.display.cachedTextHeight;
+ regChange(this);
+ this.curOp.forceUpdate = true;
+ clearCaches(this);
+ scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
+ updateGutterSpace(this);
+ if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
+ { estimateLineHeights(this); }
+ signal(this, "refresh", this);
+ }),
+
+ swapDoc: methodOp(function(doc) {
+ var old = this.doc;
+ old.cm = null;
+ attachDoc(this, doc);
+ clearCaches(this);
+ this.display.input.reset();
+ scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
+ this.curOp.forceScroll = true;
+ signalLater(this, "swapDoc", this, old);
+ return old
+ }),
+
+ phrase: function(phraseText) {
+ var phrases = this.options.phrases;
+ return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText
+ },
+
+ getInputField: function(){return this.display.input.getField()},
+ getWrapperElement: function(){return this.display.wrapper},
+ getScrollerElement: function(){return this.display.scroller},
+ getGutterElement: function(){return this.display.gutters}
+ };
+ eventMixin(CodeMirror);
+
+ CodeMirror.registerHelper = function(type, name, value) {
+ if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
+ helpers[type][name] = value;
+ };
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
+ CodeMirror.registerHelper(type, name, value);
+ helpers[type]._global.push({pred: predicate, val: value});
+ };
+ }
+
+ // Used for horizontal relative motion. Dir is -1 or 1 (left or
+ // right), unit can be "char", "column" (like char, but doesn't
+ // cross line boundaries), "word" (across next word), or "group" (to
+ // the start of next group of word or non-word-non-whitespace
+ // chars). The visually param controls whether, in right-to-left
+ // text, direction 1 means to move towards the next index in the
+ // string, or towards the character to the right of the current
+ // position. The resulting position will have a hitSide=true
+ // property if it reached the end of the document.
+ function findPosH(doc, pos, dir, unit, visually) {
+ var oldPos = pos;
+ var origDir = dir;
+ var lineObj = getLine(doc, pos.line);
+ function findNextLine() {
+ var l = pos.line + dir;
+ if (l < doc.first || l >= doc.first + doc.size) { return false }
+ pos = new Pos(l, pos.ch, pos.sticky);
+ return lineObj = getLine(doc, l)
+ }
+ function moveOnce(boundToLine) {
+ var next;
+ if (visually) {
+ next = moveVisually(doc.cm, lineObj, pos, dir);
+ } else {
+ next = moveLogically(lineObj, pos, dir);
}
- if (node.getAttribute("contenteditable") == "false") { return }
- var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);
- if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }
-
- if (isBlock) { close(); }
- for (var i = 0; i < node.childNodes.length; i++)
- { walk(node.childNodes[i]); }
-
- if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }
- if (isBlock) { closing = true; }
- } else if (node.nodeType == 3) {
- addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "));
- }
- }
- for (;;) {
- walk(from);
- if (from == to) { break }
- from = from.nextSibling;
- extraLinebreak = false;
- }
- return text
-}
-
-function domToPos(cm, node, offset) {
- var lineNode;
- if (node == cm.display.lineDiv) {
- lineNode = cm.display.lineDiv.childNodes[offset];
- if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
- node = null; offset = 0;
- } else {
- for (lineNode = node;; lineNode = lineNode.parentNode) {
- if (!lineNode || lineNode == cm.display.lineDiv) { return null }
- if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
- }
- }
- for (var i = 0; i < cm.display.view.length; i++) {
- var lineView = cm.display.view[i];
- if (lineView.node == lineNode)
- { return locateNodeInLineView(lineView, node, offset) }
- }
-}
-
-function locateNodeInLineView(lineView, node, offset) {
- var wrapper = lineView.text.firstChild, bad = false;
- if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
- if (node == wrapper) {
- bad = true;
- node = wrapper.childNodes[offset];
- offset = 0;
- if (!node) {
- var line = lineView.rest ? lst(lineView.rest) : lineView.line;
- return badPos(Pos(lineNo(line), line.text.length), bad)
- }
- }
-
- var textNode = node.nodeType == 3 ? node : null, topNode = node;
- if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
- textNode = node.firstChild;
- if (offset) { offset = textNode.nodeValue.length; }
- }
- while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
- var measure = lineView.measure, maps = measure.maps;
-
- function find(textNode, topNode, offset) {
- for (var i = -1; i < (maps ? maps.length : 0); i++) {
- var map$$1 = i < 0 ? measure.map : maps[i];
- for (var j = 0; j < map$$1.length; j += 3) {
- var curNode = map$$1[j + 2];
- if (curNode == textNode || curNode == topNode) {
- var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
- var ch = map$$1[j] + offset;
- if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
- return Pos(line, ch)
+ if (next == null) {
+ if (!boundToLine && findNextLine())
+ { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
+ else
+ { return false }
+ } else {
+ pos = next;
+ }
+ return true
+ }
+
+ if (unit == "char") {
+ moveOnce();
+ } else if (unit == "column") {
+ moveOnce(true);
+ } else if (unit == "word" || unit == "group") {
+ var sawType = null, group = unit == "group";
+ var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
+ for (var first = true;; first = false) {
+ if (dir < 0 && !moveOnce(!first)) { break }
+ var cur = lineObj.text.charAt(pos.ch) || "\n";
+ var type = isWordChar(cur, helper) ? "w"
+ : group && cur == "\n" ? "n"
+ : !group || /\s/.test(cur) ? null
+ : "p";
+ if (group && !first && !type) { type = "s"; }
+ if (sawType && sawType != type) {
+ if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
+ break
}
+
+ if (type) { sawType = type; }
+ if (dir > 0 && !moveOnce(!first)) { break }
}
}
+ var result = skipAtomic(doc, pos, oldPos, origDir, true);
+ if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
+ return result
}
- var found = find(textNode, topNode, offset);
- if (found) { return badPos(found, bad) }
- // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
- for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
- found = find(after, after.firstChild, 0);
- if (found)
- { return badPos(Pos(found.line, found.ch - dist), bad) }
- else
- { dist += after.textContent.length; }
- }
- for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
- found = find(before, before.firstChild, -1);
- if (found)
- { return badPos(Pos(found.line, found.ch + dist$1), bad) }
- else
- { dist$1 += before.textContent.length; }
+ // For relative vertical movement. Dir may be -1 or 1. Unit can be
+ // "page" or "line". The resulting position will have a hitSide=true
+ // property if it reached the end of the document.
+ function findPosV(cm, pos, dir, unit) {
+ var doc = cm.doc, x = pos.left, y;
+ if (unit == "page") {
+ var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+ var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
+ y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
+
+ } else if (unit == "line") {
+ y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
+ }
+ var target;
+ for (;;) {
+ target = coordsChar(cm, x, y);
+ if (!target.outside) { break }
+ if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
+ y += dir * 5;
+ }
+ return target
}
-}
-// TEXTAREA INPUT STYLE
+ // CONTENTEDITABLE INPUT STYLE
-var TextareaInput = function(cm) {
- this.cm = cm;
- // See input.poll and input.reset
- this.prevInput = "";
+ var ContentEditableInput = function(cm) {
+ this.cm = cm;
+ this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
+ this.polling = new Delayed();
+ this.composing = null;
+ this.gracePeriod = false;
+ this.readDOMTimeout = null;
+ };
- // Flag that indicates whether we expect input to appear real soon
- // now (after some event like 'keypress' or 'input') and are
- // polling intensively.
- this.pollingFast = false;
- // Self-resetting timeout for the poller
- this.polling = new Delayed();
- // Used to work around IE issue with selection being forgotten when focus moves away from textarea
- this.hasSelection = false;
- this.composing = null;
-};
+ ContentEditableInput.prototype.init = function (display) {
+ var this$1 = this;
-TextareaInput.prototype.init = function (display) {
- var this$1 = this;
+ var input = this, cm = input.cm;
+ var div = input.div = display.lineDiv;
+ disableBrowserMagic(div, cm.options.spellcheck);
- var input = this, cm = this.cm;
- this.createField(display);
- var te = this.textarea;
+ on(div, "paste", function (e) {
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
+ // IE doesn't fire input events, so we schedule a read for the pasted content in this way
+ if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
+ });
- display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);
+ on(div, "compositionstart", function (e) {
+ this$1.composing = {data: e.data, done: false};
+ });
+ on(div, "compositionupdate", function (e) {
+ if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
+ });
+ on(div, "compositionend", function (e) {
+ if (this$1.composing) {
+ if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
+ this$1.composing.done = true;
+ }
+ });
- // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
- if (ios) { te.style.width = "0px"; }
+ on(div, "touchstart", function () { return input.forceCompositionEnd(); });
- on(te, "input", function () {
- if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
- input.poll();
- });
+ on(div, "input", function () {
+ if (!this$1.composing) { this$1.readFromDOMSoon(); }
+ });
- on(te, "paste", function (e) {
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
+ function onCopyCut(e) {
+ if (signalDOMEvent(cm, e)) { return }
+ if (cm.somethingSelected()) {
+ setLastCopied({lineWise: false, text: cm.getSelections()});
+ if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
+ } else if (!cm.options.lineWiseCopyCut) {
+ return
+ } else {
+ var ranges = copyableRanges(cm);
+ setLastCopied({lineWise: true, text: ranges.text});
+ if (e.type == "cut") {
+ cm.operation(function () {
+ cm.setSelections(ranges.ranges, 0, sel_dontScroll);
+ cm.replaceSelection("", null, "cut");
+ });
+ }
+ }
+ if (e.clipboardData) {
+ e.clipboardData.clearData();
+ var content = lastCopied.text.join("\n");
+ // iOS exposes the clipboard API, but seems to discard content inserted into it
+ e.clipboardData.setData("Text", content);
+ if (e.clipboardData.getData("Text") == content) {
+ e.preventDefault();
+ return
+ }
+ }
+ // Old-fashioned briefly-focus-a-textarea hack
+ var kludge = hiddenTextarea(), te = kludge.firstChild;
+ cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
+ te.value = lastCopied.text.join("\n");
+ var hadFocus = document.activeElement;
+ selectInput(te);
+ setTimeout(function () {
+ cm.display.lineSpace.removeChild(kludge);
+ hadFocus.focus();
+ if (hadFocus == div) { input.showPrimarySelection(); }
+ }, 50);
+ }
+ on(div, "copy", onCopyCut);
+ on(div, "cut", onCopyCut);
+ };
- cm.state.pasteIncoming = true;
- input.fastPoll();
- });
+ ContentEditableInput.prototype.prepareSelection = function () {
+ var result = prepareSelection(this.cm, false);
+ result.focus = this.cm.state.focused;
+ return result
+ };
- function prepareCopyCut(e) {
- if (signalDOMEvent(cm, e)) { return }
- if (cm.somethingSelected()) {
- setLastCopied({lineWise: false, text: cm.getSelections()});
- } else if (!cm.options.lineWiseCopyCut) {
+ ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
+ if (!info || !this.cm.display.view.length) { return }
+ if (info.focus || takeFocus) { this.showPrimarySelection(); }
+ this.showMultipleSelections(info);
+ };
+
+ ContentEditableInput.prototype.getSelection = function () {
+ return this.cm.display.wrapper.ownerDocument.getSelection()
+ };
+
+ ContentEditableInput.prototype.showPrimarySelection = function () {
+ var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
+ var from = prim.from(), to = prim.to();
+
+ if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
+ sel.removeAllRanges();
return
- } else {
- var ranges = copyableRanges(cm);
- setLastCopied({lineWise: true, text: ranges.text});
- if (e.type == "cut") {
- cm.setSelections(ranges.ranges, null, sel_dontScroll);
+ }
+
+ var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
+ var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
+ if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
+ cmp(minPos(curAnchor, curFocus), from) == 0 &&
+ cmp(maxPos(curAnchor, curFocus), to) == 0)
+ { return }
+
+ var view = cm.display.view;
+ var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
+ {node: view[0].measure.map[2], offset: 0};
+ var end = to.line < cm.display.viewTo && posToDOM(cm, to);
+ if (!end) {
+ var measure = view[view.length - 1].measure;
+ var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
+ end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
+ }
+
+ if (!start || !end) {
+ sel.removeAllRanges();
+ return
+ }
+
+ var old = sel.rangeCount && sel.getRangeAt(0), rng;
+ try { rng = range(start.node, start.offset, end.offset, end.node); }
+ catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
+ if (rng) {
+ if (!gecko && cm.state.focused) {
+ sel.collapse(start.node, start.offset);
+ if (!rng.collapsed) {
+ sel.removeAllRanges();
+ sel.addRange(rng);
+ }
} else {
- input.prevInput = "";
- te.value = ranges.text.join("\n");
- selectInput(te);
+ sel.removeAllRanges();
+ sel.addRange(rng);
}
+ if (old && sel.anchorNode == null) { sel.addRange(old); }
+ else if (gecko) { this.startGracePeriod(); }
}
- if (e.type == "cut") { cm.state.cutIncoming = true; }
- }
- on(te, "cut", prepareCopyCut);
- on(te, "copy", prepareCopyCut);
+ this.rememberSelection();
+ };
- on(display.scroller, "paste", function (e) {
- if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
- cm.state.pasteIncoming = true;
- input.focus();
- });
+ ContentEditableInput.prototype.startGracePeriod = function () {
+ var this$1 = this;
- // Prevent normal selection in the editor (we handle our own)
- on(display.lineSpace, "selectstart", function (e) {
- if (!eventInWidget(display, e)) { e_preventDefault(e); }
- });
+ clearTimeout(this.gracePeriod);
+ this.gracePeriod = setTimeout(function () {
+ this$1.gracePeriod = false;
+ if (this$1.selectionChanged())
+ { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
+ }, 20);
+ };
- on(te, "compositionstart", function () {
- var start = cm.getCursor("from");
- if (input.composing) { input.composing.range.clear(); }
- input.composing = {
- start: start,
- range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
- };
- });
- on(te, "compositionend", function () {
- if (input.composing) {
- input.poll();
- input.composing.range.clear();
- input.composing = null;
+ ContentEditableInput.prototype.showMultipleSelections = function (info) {
+ removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
+ removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
+ };
+
+ ContentEditableInput.prototype.rememberSelection = function () {
+ var sel = this.getSelection();
+ this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
+ this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
+ };
+
+ ContentEditableInput.prototype.selectionInEditor = function () {
+ var sel = this.getSelection();
+ if (!sel.rangeCount) { return false }
+ var node = sel.getRangeAt(0).commonAncestorContainer;
+ return contains(this.div, node)
+ };
+
+ ContentEditableInput.prototype.focus = function () {
+ if (this.cm.options.readOnly != "nocursor") {
+ if (!this.selectionInEditor())
+ { this.showSelection(this.prepareSelection(), true); }
+ this.div.focus();
}
- });
-};
-
-TextareaInput.prototype.createField = function (_display) {
- // Wraps and hides input textarea
- this.wrapper = hiddenTextarea();
- // The semihidden textarea that is focused when the editor is
- // focused, and receives input.
- this.textarea = this.wrapper.firstChild;
-};
-
-TextareaInput.prototype.prepareSelection = function () {
- // Redraw the selection and/or cursor
- var cm = this.cm, display = cm.display, doc = cm.doc;
- var result = prepareSelection(cm);
-
- // Move the hidden textarea near the cursor to prevent scrolling artifacts
- if (cm.options.moveInputWithCursor) {
- var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
- var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
- result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
- headPos.top + lineOff.top - wrapOff.top));
- result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
- headPos.left + lineOff.left - wrapOff.left));
- }
-
- return result
-};
-
-TextareaInput.prototype.showSelection = function (drawn) {
- var cm = this.cm, display = cm.display;
- removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
- removeChildrenAndAdd(display.selectionDiv, drawn.selection);
- if (drawn.teTop != null) {
- this.wrapper.style.top = drawn.teTop + "px";
- this.wrapper.style.left = drawn.teLeft + "px";
- }
-};
-
-// Reset the input to correspond to the selection (or to be empty,
-// when not typing and nothing is selected)
-TextareaInput.prototype.reset = function (typing) {
- if (this.contextMenuPending || this.composing) { return }
- var cm = this.cm;
- if (cm.somethingSelected()) {
- this.prevInput = "";
- var content = cm.getSelection();
- this.textarea.value = content;
- if (cm.state.focused) { selectInput(this.textarea); }
- if (ie && ie_version >= 9) { this.hasSelection = content; }
- } else if (!typing) {
- this.prevInput = this.textarea.value = "";
- if (ie && ie_version >= 9) { this.hasSelection = null; }
- }
-};
+ };
+ ContentEditableInput.prototype.blur = function () { this.div.blur(); };
+ ContentEditableInput.prototype.getField = function () { return this.div };
+
+ ContentEditableInput.prototype.supportsTouch = function () { return true };
-TextareaInput.prototype.getField = function () { return this.textarea };
+ ContentEditableInput.prototype.receivedFocus = function () {
+ var input = this;
+ if (this.selectionInEditor())
+ { this.pollSelection(); }
+ else
+ { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
-TextareaInput.prototype.supportsTouch = function () { return false };
+ function poll() {
+ if (input.cm.state.focused) {
+ input.pollSelection();
+ input.polling.set(input.cm.options.pollInterval, poll);
+ }
+ }
+ this.polling.set(this.cm.options.pollInterval, poll);
+ };
-TextareaInput.prototype.focus = function () {
- if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
- try { this.textarea.focus(); }
- catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
- }
-};
+ ContentEditableInput.prototype.selectionChanged = function () {
+ var sel = this.getSelection();
+ return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
+ sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
+ };
-TextareaInput.prototype.blur = function () { this.textarea.blur(); };
+ ContentEditableInput.prototype.pollSelection = function () {
+ if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
+ var sel = this.getSelection(), cm = this.cm;
+ // On Android Chrome (version 56, at least), backspacing into an
+ // uneditable block element will put the cursor in that element,
+ // and then, because it's not editable, hide the virtual keyboard.
+ // Because Android doesn't allow us to actually detect backspace
+ // presses in a sane way, this code checks for when that happens
+ // and simulates a backspace press in this case.
+ if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
+ this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
+ this.blur();
+ this.focus();
+ return
+ }
+ if (this.composing) { return }
+ this.rememberSelection();
+ var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
+ var head = domToPos(cm, sel.focusNode, sel.focusOffset);
+ if (anchor && head) { runInOp(cm, function () {
+ setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
+ if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
+ }); }
+ };
-TextareaInput.prototype.resetPosition = function () {
- this.wrapper.style.top = this.wrapper.style.left = 0;
-};
+ ContentEditableInput.prototype.pollContent = function () {
+ if (this.readDOMTimeout != null) {
+ clearTimeout(this.readDOMTimeout);
+ this.readDOMTimeout = null;
+ }
-TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
+ var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
+ var from = sel.from(), to = sel.to();
+ if (from.ch == 0 && from.line > cm.firstLine())
+ { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
+ if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
+ { to = Pos(to.line + 1, 0); }
+ if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
-// Poll for input changes, using the normal rate of polling. This
-// runs as long as the editor is focused.
-TextareaInput.prototype.slowPoll = function () {
- var this$1 = this;
+ var fromIndex, fromLine, fromNode;
+ if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
+ fromLine = lineNo(display.view[0].line);
+ fromNode = display.view[0].node;
+ } else {
+ fromLine = lineNo(display.view[fromIndex].line);
+ fromNode = display.view[fromIndex - 1].node.nextSibling;
+ }
+ var toIndex = findViewIndex(cm, to.line);
+ var toLine, toNode;
+ if (toIndex == display.view.length - 1) {
+ toLine = display.viewTo - 1;
+ toNode = display.lineDiv.lastChild;
+ } else {
+ toLine = lineNo(display.view[toIndex + 1].line) - 1;
+ toNode = display.view[toIndex + 1].node.previousSibling;
+ }
+
+ if (!fromNode) { return false }
+ var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
+ var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
+ while (newText.length > 1 && oldText.length > 1) {
+ if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
+ else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
+ else { break }
+ }
+
+ var cutFront = 0, cutEnd = 0;
+ var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
+ while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
+ { ++cutFront; }
+ var newBot = lst(newText), oldBot = lst(oldText);
+ var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
+ oldBot.length - (oldText.length == 1 ? cutFront : 0));
+ while (cutEnd < maxCutEnd &&
+ newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
+ { ++cutEnd; }
+ // Try to move start of change to start of selection if ambiguous
+ if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
+ while (cutFront && cutFront > from.ch &&
+ newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
+ cutFront--;
+ cutEnd++;
+ }
+ }
- if (this.pollingFast) { return }
- this.polling.set(this.cm.options.pollInterval, function () {
- this$1.poll();
- if (this$1.cm.state.focused) { this$1.slowPoll(); }
- });
-};
-
-// When an event has just come in that is likely to add or change
-// something in the input textarea, we poll faster, to ensure that
-// the change appears on the screen quickly.
-TextareaInput.prototype.fastPoll = function () {
- var missed = false, input = this;
- input.pollingFast = true;
- function p() {
- var changed = input.poll();
- if (!changed && !missed) {missed = true; input.polling.set(60, p);}
- else {input.pollingFast = false; input.slowPoll();}
- }
- input.polling.set(20, p);
-};
-
-// Read input from the textarea, and update the document to match.
-// When something is selected, it is present in the textarea, and
-// selected (unless it is huge, in which case a placeholder is
-// used). When nothing is selected, the cursor sits after previously
-// seen text (can be empty), which is stored in prevInput (we must
-// not reset the textarea when typing, because that breaks IME).
-TextareaInput.prototype.poll = function () {
- var this$1 = this;
+ newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
+ newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
+
+ var chFrom = Pos(fromLine, cutFront);
+ var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
+ if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
+ replaceRange(cm.doc, newText, chFrom, chTo, "+input");
+ return true
+ }
+ };
+
+ ContentEditableInput.prototype.ensurePolled = function () {
+ this.forceCompositionEnd();
+ };
+ ContentEditableInput.prototype.reset = function () {
+ this.forceCompositionEnd();
+ };
+ ContentEditableInput.prototype.forceCompositionEnd = function () {
+ if (!this.composing) { return }
+ clearTimeout(this.readDOMTimeout);
+ this.composing = null;
+ this.updateFromDOM();
+ this.div.blur();
+ this.div.focus();
+ };
+ ContentEditableInput.prototype.readFromDOMSoon = function () {
+ var this$1 = this;
- var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
- // Since this is called a *lot*, try to bail out as cheaply as
- // possible when it is clear that nothing happened. hasSelection
- // will be the case when there is a lot of text in the textarea,
- // in which case reading its value would be expensive.
- if (this.contextMenuPending || !cm.state.focused ||
- (hasSelection(input) && !prevInput && !this.composing) ||
- cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
- { return false }
-
- var text = input.value;
- // If nothing changed, bail.
- if (text == prevInput && !cm.somethingSelected()) { return false }
- // Work around nonsensical selection resetting in IE9/10, and
- // inexplicable appearance of private area unicode characters on
- // some key combos in Mac (#2689).
- if (ie && ie_version >= 9 && this.hasSelection === text ||
- mac && /[\uf700-\uf7ff]/.test(text)) {
- cm.display.input.reset();
+ if (this.readDOMTimeout != null) { return }
+ this.readDOMTimeout = setTimeout(function () {
+ this$1.readDOMTimeout = null;
+ if (this$1.composing) {
+ if (this$1.composing.done) { this$1.composing = null; }
+ else { return }
+ }
+ this$1.updateFromDOM();
+ }, 80);
+ };
+
+ ContentEditableInput.prototype.updateFromDOM = function () {
+ var this$1 = this;
+
+ if (this.cm.isReadOnly() || !this.pollContent())
+ { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
+ };
+
+ ContentEditableInput.prototype.setUneditable = function (node) {
+ node.contentEditable = "false";
+ };
+
+ ContentEditableInput.prototype.onKeyPress = function (e) {
+ if (e.charCode == 0 || this.composing) { return }
+ e.preventDefault();
+ if (!this.cm.isReadOnly())
+ { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
+ };
+
+ ContentEditableInput.prototype.readOnlyChanged = function (val) {
+ this.div.contentEditable = String(val != "nocursor");
+ };
+
+ ContentEditableInput.prototype.onContextMenu = function () {};
+ ContentEditableInput.prototype.resetPosition = function () {};
+
+ ContentEditableInput.prototype.needsContentAttribute = true;
+
+ function posToDOM(cm, pos) {
+ var view = findViewForLine(cm, pos.line);
+ if (!view || view.hidden) { return null }
+ var line = getLine(cm.doc, pos.line);
+ var info = mapFromLineView(view, line, pos.line);
+
+ var order = getOrder(line, cm.doc.direction), side = "left";
+ if (order) {
+ var partPos = getBidiPartAt(order, pos.ch);
+ side = partPos % 2 ? "right" : "left";
+ }
+ var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
+ result.offset = result.collapse == "right" ? result.end : result.start;
+ return result
+ }
+
+ function isInGutter(node) {
+ for (var scan = node; scan; scan = scan.parentNode)
+ { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
return false
}
- if (cm.doc.sel == cm.display.selForContextMenu) {
- var first = text.charCodeAt(0);
- if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
- if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
+ function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
+
+ function domTextBetween(cm, from, to, fromLine, toLine) {
+ var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;
+ function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
+ function close() {
+ if (closing) {
+ text += lineSep;
+ if (extraLinebreak) { text += lineSep; }
+ closing = extraLinebreak = false;
+ }
+ }
+ function addText(str) {
+ if (str) {
+ close();
+ text += str;
+ }
+ }
+ function walk(node) {
+ if (node.nodeType == 1) {
+ var cmText = node.getAttribute("cm-text");
+ if (cmText) {
+ addText(cmText);
+ return
+ }
+ var markerID = node.getAttribute("cm-marker"), range$$1;
+ if (markerID) {
+ var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
+ if (found.length && (range$$1 = found[0].find(0)))
+ { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
+ return
+ }
+ if (node.getAttribute("contenteditable") == "false") { return }
+ var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);
+ if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }
+
+ if (isBlock) { close(); }
+ for (var i = 0; i < node.childNodes.length; i++)
+ { walk(node.childNodes[i]); }
+
+ if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }
+ if (isBlock) { closing = true; }
+ } else if (node.nodeType == 3) {
+ addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "));
+ }
+ }
+ for (;;) {
+ walk(from);
+ if (from == to) { break }
+ from = from.nextSibling;
+ extraLinebreak = false;
+ }
+ return text
}
- // Find the part of the input that is actually new
- var same = 0, l = Math.min(prevInput.length, text.length);
- while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
- runInOp(cm, function () {
- applyTextInput(cm, text.slice(same), prevInput.length - same,
- null, this$1.composing ? "*compose" : null);
+ function domToPos(cm, node, offset) {
+ var lineNode;
+ if (node == cm.display.lineDiv) {
+ lineNode = cm.display.lineDiv.childNodes[offset];
+ if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
+ node = null; offset = 0;
+ } else {
+ for (lineNode = node;; lineNode = lineNode.parentNode) {
+ if (!lineNode || lineNode == cm.display.lineDiv) { return null }
+ if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
+ }
+ }
+ for (var i = 0; i < cm.display.view.length; i++) {
+ var lineView = cm.display.view[i];
+ if (lineView.node == lineNode)
+ { return locateNodeInLineView(lineView, node, offset) }
+ }
+ }
- // Don't leave long text in the textarea, since it makes further polling slow
- if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
- else { this$1.prevInput = text; }
+ function locateNodeInLineView(lineView, node, offset) {
+ var wrapper = lineView.text.firstChild, bad = false;
+ if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
+ if (node == wrapper) {
+ bad = true;
+ node = wrapper.childNodes[offset];
+ offset = 0;
+ if (!node) {
+ var line = lineView.rest ? lst(lineView.rest) : lineView.line;
+ return badPos(Pos(lineNo(line), line.text.length), bad)
+ }
+ }
- if (this$1.composing) {
- this$1.composing.range.clear();
- this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
- {className: "CodeMirror-composing"});
+ var textNode = node.nodeType == 3 ? node : null, topNode = node;
+ if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
+ textNode = node.firstChild;
+ if (offset) { offset = textNode.nodeValue.length; }
+ }
+ while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
+ var measure = lineView.measure, maps = measure.maps;
+
+ function find(textNode, topNode, offset) {
+ for (var i = -1; i < (maps ? maps.length : 0); i++) {
+ var map$$1 = i < 0 ? measure.map : maps[i];
+ for (var j = 0; j < map$$1.length; j += 3) {
+ var curNode = map$$1[j + 2];
+ if (curNode == textNode || curNode == topNode) {
+ var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
+ var ch = map$$1[j] + offset;
+ if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
+ return Pos(line, ch)
+ }
+ }
+ }
}
- });
- return true
-};
-
-TextareaInput.prototype.ensurePolled = function () {
- if (this.pollingFast && this.poll()) { this.pollingFast = false; }
-};
-
-TextareaInput.prototype.onKeyPress = function () {
- if (ie && ie_version >= 9) { this.hasSelection = null; }
- this.fastPoll();
-};
-
-TextareaInput.prototype.onContextMenu = function (e) {
- var input = this, cm = input.cm, display = cm.display, te = input.textarea;
- var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
- if (!pos || presto) { return } // Opera is difficult.
-
- // Reset the current text selection only if the click is done outside of the selection
- // and 'resetSelectionOnContextMenu' option is true.
- var reset = cm.options.resetSelectionOnContextMenu;
- if (reset && cm.doc.sel.contains(pos) == -1)
- { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
-
- var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
- input.wrapper.style.cssText = "position: absolute";
- var wrapperBox = input.wrapper.getBoundingClientRect();
- te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
- var oldScrollY;
- if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
- display.input.focus();
- if (webkit) { window.scrollTo(null, oldScrollY); }
- display.input.reset();
- // Adds "Select all" to context menu in FF
- if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
- input.contextMenuPending = true;
- display.selForContextMenu = cm.doc.sel;
- clearTimeout(display.detectingSelectAll);
-
- // Select-all will be greyed out if there's nothing to select, so
- // this adds a zero-width space so that we can later check whether
- // it got selected.
- function prepareSelectAllHack() {
- if (te.selectionStart != null) {
- var selected = cm.somethingSelected();
- var extval = "\u200b" + (selected ? te.value : "");
- te.value = "\u21da"; // Used to catch context-menu undo
- te.value = extval;
- input.prevInput = selected ? "" : "\u200b";
- te.selectionStart = 1; te.selectionEnd = extval.length;
- // Re-set this, in case some other handler touched the
- // selection in the meantime.
- display.selForContextMenu = cm.doc.sel;
- }
- }
- function rehide() {
- input.contextMenuPending = false;
- input.wrapper.style.cssText = oldWrapperCSS;
- te.style.cssText = oldCSS;
- if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
-
- // Try to detect the user choosing select-all
- if (te.selectionStart != null) {
- if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
- var i = 0, poll = function () {
- if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
- te.selectionEnd > 0 && input.prevInput == "\u200b") {
- operation(cm, selectAll)(cm);
- } else if (i++ < 10) {
- display.detectingSelectAll = setTimeout(poll, 500);
+ var found = find(textNode, topNode, offset);
+ if (found) { return badPos(found, bad) }
+
+ // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
+ for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
+ found = find(after, after.firstChild, 0);
+ if (found)
+ { return badPos(Pos(found.line, found.ch - dist), bad) }
+ else
+ { dist += after.textContent.length; }
+ }
+ for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
+ found = find(before, before.firstChild, -1);
+ if (found)
+ { return badPos(Pos(found.line, found.ch + dist$1), bad) }
+ else
+ { dist$1 += before.textContent.length; }
+ }
+ }
+
+ // TEXTAREA INPUT STYLE
+
+ var TextareaInput = function(cm) {
+ this.cm = cm;
+ // See input.poll and input.reset
+ this.prevInput = "";
+
+ // Flag that indicates whether we expect input to appear real soon
+ // now (after some event like 'keypress' or 'input') and are
+ // polling intensively.
+ this.pollingFast = false;
+ // Self-resetting timeout for the poller
+ this.polling = new Delayed();
+ // Used to work around IE issue with selection being forgotten when focus moves away from textarea
+ this.hasSelection = false;
+ this.composing = null;
+ };
+
+ TextareaInput.prototype.init = function (display) {
+ var this$1 = this;
+
+ var input = this, cm = this.cm;
+ this.createField(display);
+ var te = this.textarea;
+
+ display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);
+
+ // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
+ if (ios) { te.style.width = "0px"; }
+
+ on(te, "input", function () {
+ if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
+ input.poll();
+ });
+
+ on(te, "paste", function (e) {
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
+
+ cm.state.pasteIncoming = true;
+ input.fastPoll();
+ });
+
+ function prepareCopyCut(e) {
+ if (signalDOMEvent(cm, e)) { return }
+ if (cm.somethingSelected()) {
+ setLastCopied({lineWise: false, text: cm.getSelections()});
+ } else if (!cm.options.lineWiseCopyCut) {
+ return
+ } else {
+ var ranges = copyableRanges(cm);
+ setLastCopied({lineWise: true, text: ranges.text});
+ if (e.type == "cut") {
+ cm.setSelections(ranges.ranges, null, sel_dontScroll);
} else {
- display.selForContextMenu = null;
- display.input.reset();
+ input.prevInput = "";
+ te.value = ranges.text.join("\n");
+ selectInput(te);
}
+ }
+ if (e.type == "cut") { cm.state.cutIncoming = true; }
+ }
+ on(te, "cut", prepareCopyCut);
+ on(te, "copy", prepareCopyCut);
+
+ on(display.scroller, "paste", function (e) {
+ if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
+ cm.state.pasteIncoming = true;
+ input.focus();
+ });
+
+ // Prevent normal selection in the editor (we handle our own)
+ on(display.lineSpace, "selectstart", function (e) {
+ if (!eventInWidget(display, e)) { e_preventDefault(e); }
+ });
+
+ on(te, "compositionstart", function () {
+ var start = cm.getCursor("from");
+ if (input.composing) { input.composing.range.clear(); }
+ input.composing = {
+ start: start,
+ range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
};
- display.detectingSelectAll = setTimeout(poll, 200);
+ });
+ on(te, "compositionend", function () {
+ if (input.composing) {
+ input.poll();
+ input.composing.range.clear();
+ input.composing = null;
+ }
+ });
+ };
+
+ TextareaInput.prototype.createField = function (_display) {
+ // Wraps and hides input textarea
+ this.wrapper = hiddenTextarea();
+ // The semihidden textarea that is focused when the editor is
+ // focused, and receives input.
+ this.textarea = this.wrapper.firstChild;
+ };
+
+ TextareaInput.prototype.prepareSelection = function () {
+ // Redraw the selection and/or cursor
+ var cm = this.cm, display = cm.display, doc = cm.doc;
+ var result = prepareSelection(cm);
+
+ // Move the hidden textarea near the cursor to prevent scrolling artifacts
+ if (cm.options.moveInputWithCursor) {
+ var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
+ var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
+ result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
+ headPos.top + lineOff.top - wrapOff.top));
+ result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
+ headPos.left + lineOff.left - wrapOff.left));
}
- }
- if (ie && ie_version >= 9) { prepareSelectAllHack(); }
- if (captureRightClick) {
- e_stop(e);
- var mouseup = function () {
- off(window, "mouseup", mouseup);
- setTimeout(rehide, 20);
- };
- on(window, "mouseup", mouseup);
- } else {
- setTimeout(rehide, 50);
- }
-};
-
-TextareaInput.prototype.readOnlyChanged = function (val) {
- if (!val) { this.reset(); }
- this.textarea.disabled = val == "nocursor";
-};
-
-TextareaInput.prototype.setUneditable = function () {};
-
-TextareaInput.prototype.needsContentAttribute = false;
-
-function fromTextArea(textarea, options) {
- options = options ? copyObj(options) : {};
- options.value = textarea.value;
- if (!options.tabindex && textarea.tabIndex)
- { options.tabindex = textarea.tabIndex; }
- if (!options.placeholder && textarea.placeholder)
- { options.placeholder = textarea.placeholder; }
- // Set autofocus to true if this textarea is focused, or if it has
- // autofocus and no other element is focused.
- if (options.autofocus == null) {
- var hasFocus = activeElt();
- options.autofocus = hasFocus == textarea ||
- textarea.getAttribute("autofocus") != null && hasFocus == document.body;
- }
-
- function save() {textarea.value = cm.getValue();}
-
- var realSubmit;
- if (textarea.form) {
- on(textarea.form, "submit", save);
- // Deplorable hack to make the submit method do the right thing.
- if (!options.leaveSubmitMethodAlone) {
- var form = textarea.form;
- realSubmit = form.submit;
- try {
- var wrappedSubmit = form.submit = function () {
- save();
- form.submit = realSubmit;
- form.submit();
- form.submit = wrappedSubmit;
+ return result
+ };
+
+ TextareaInput.prototype.showSelection = function (drawn) {
+ var cm = this.cm, display = cm.display;
+ removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
+ removeChildrenAndAdd(display.selectionDiv, drawn.selection);
+ if (drawn.teTop != null) {
+ this.wrapper.style.top = drawn.teTop + "px";
+ this.wrapper.style.left = drawn.teLeft + "px";
+ }
+ };
+
+ // Reset the input to correspond to the selection (or to be empty,
+ // when not typing and nothing is selected)
+ TextareaInput.prototype.reset = function (typing) {
+ if (this.contextMenuPending || this.composing) { return }
+ var cm = this.cm;
+ if (cm.somethingSelected()) {
+ this.prevInput = "";
+ var content = cm.getSelection();
+ this.textarea.value = content;
+ if (cm.state.focused) { selectInput(this.textarea); }
+ if (ie && ie_version >= 9) { this.hasSelection = content; }
+ } else if (!typing) {
+ this.prevInput = this.textarea.value = "";
+ if (ie && ie_version >= 9) { this.hasSelection = null; }
+ }
+ };
+
+ TextareaInput.prototype.getField = function () { return this.textarea };
+
+ TextareaInput.prototype.supportsTouch = function () { return false };
+
+ TextareaInput.prototype.focus = function () {
+ if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
+ try { this.textarea.focus(); }
+ catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
+ }
+ };
+
+ TextareaInput.prototype.blur = function () { this.textarea.blur(); };
+
+ TextareaInput.prototype.resetPosition = function () {
+ this.wrapper.style.top = this.wrapper.style.left = 0;
+ };
+
+ TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
+
+ // Poll for input changes, using the normal rate of polling. This
+ // runs as long as the editor is focused.
+ TextareaInput.prototype.slowPoll = function () {
+ var this$1 = this;
+
+ if (this.pollingFast) { return }
+ this.polling.set(this.cm.options.pollInterval, function () {
+ this$1.poll();
+ if (this$1.cm.state.focused) { this$1.slowPoll(); }
+ });
+ };
+
+ // When an event has just come in that is likely to add or change
+ // something in the input textarea, we poll faster, to ensure that
+ // the change appears on the screen quickly.
+ TextareaInput.prototype.fastPoll = function () {
+ var missed = false, input = this;
+ input.pollingFast = true;
+ function p() {
+ var changed = input.poll();
+ if (!changed && !missed) {missed = true; input.polling.set(60, p);}
+ else {input.pollingFast = false; input.slowPoll();}
+ }
+ input.polling.set(20, p);
+ };
+
+ // Read input from the textarea, and update the document to match.
+ // When something is selected, it is present in the textarea, and
+ // selected (unless it is huge, in which case a placeholder is
+ // used). When nothing is selected, the cursor sits after previously
+ // seen text (can be empty), which is stored in prevInput (we must
+ // not reset the textarea when typing, because that breaks IME).
+ TextareaInput.prototype.poll = function () {
+ var this$1 = this;
+
+ var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
+ // Since this is called a *lot*, try to bail out as cheaply as
+ // possible when it is clear that nothing happened. hasSelection
+ // will be the case when there is a lot of text in the textarea,
+ // in which case reading its value would be expensive.
+ if (this.contextMenuPending || !cm.state.focused ||
+ (hasSelection(input) && !prevInput && !this.composing) ||
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
+ { return false }
+
+ var text = input.value;
+ // If nothing changed, bail.
+ if (text == prevInput && !cm.somethingSelected()) { return false }
+ // Work around nonsensical selection resetting in IE9/10, and
+ // inexplicable appearance of private area unicode characters on
+ // some key combos in Mac (#2689).
+ if (ie && ie_version >= 9 && this.hasSelection === text ||
+ mac && /[\uf700-\uf7ff]/.test(text)) {
+ cm.display.input.reset();
+ return false
+ }
+
+ if (cm.doc.sel == cm.display.selForContextMenu) {
+ var first = text.charCodeAt(0);
+ if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
+ if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
+ }
+ // Find the part of the input that is actually new
+ var same = 0, l = Math.min(prevInput.length, text.length);
+ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
+
+ runInOp(cm, function () {
+ applyTextInput(cm, text.slice(same), prevInput.length - same,
+ null, this$1.composing ? "*compose" : null);
+
+ // Don't leave long text in the textarea, since it makes further polling slow
+ if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
+ else { this$1.prevInput = text; }
+
+ if (this$1.composing) {
+ this$1.composing.range.clear();
+ this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
+ {className: "CodeMirror-composing"});
+ }
+ });
+ return true
+ };
+
+ TextareaInput.prototype.ensurePolled = function () {
+ if (this.pollingFast && this.poll()) { this.pollingFast = false; }
+ };
+
+ TextareaInput.prototype.onKeyPress = function () {
+ if (ie && ie_version >= 9) { this.hasSelection = null; }
+ this.fastPoll();
+ };
+
+ TextareaInput.prototype.onContextMenu = function (e) {
+ var input = this, cm = input.cm, display = cm.display, te = input.textarea;
+ var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
+ if (!pos || presto) { return } // Opera is difficult.
+
+ // Reset the current text selection only if the click is done outside of the selection
+ // and 'resetSelectionOnContextMenu' option is true.
+ var reset = cm.options.resetSelectionOnContextMenu;
+ if (reset && cm.doc.sel.contains(pos) == -1)
+ { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
+
+ var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
+ input.wrapper.style.cssText = "position: absolute";
+ var wrapperBox = input.wrapper.getBoundingClientRect();
+ te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
+ var oldScrollY;
+ if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
+ display.input.focus();
+ if (webkit) { window.scrollTo(null, oldScrollY); }
+ display.input.reset();
+ // Adds "Select all" to context menu in FF
+ if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
+ input.contextMenuPending = true;
+ display.selForContextMenu = cm.doc.sel;
+ clearTimeout(display.detectingSelectAll);
+
+ // Select-all will be greyed out if there's nothing to select, so
+ // this adds a zero-width space so that we can later check whether
+ // it got selected.
+ function prepareSelectAllHack() {
+ if (te.selectionStart != null) {
+ var selected = cm.somethingSelected();
+ var extval = "\u200b" + (selected ? te.value : "");
+ te.value = "\u21da"; // Used to catch context-menu undo
+ te.value = extval;
+ input.prevInput = selected ? "" : "\u200b";
+ te.selectionStart = 1; te.selectionEnd = extval.length;
+ // Re-set this, in case some other handler touched the
+ // selection in the meantime.
+ display.selForContextMenu = cm.doc.sel;
+ }
+ }
+ function rehide() {
+ input.contextMenuPending = false;
+ input.wrapper.style.cssText = oldWrapperCSS;
+ te.style.cssText = oldCSS;
+ if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
+
+ // Try to detect the user choosing select-all
+ if (te.selectionStart != null) {
+ if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
+ var i = 0, poll = function () {
+ if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
+ te.selectionEnd > 0 && input.prevInput == "\u200b") {
+ operation(cm, selectAll)(cm);
+ } else if (i++ < 10) {
+ display.detectingSelectAll = setTimeout(poll, 500);
+ } else {
+ display.selForContextMenu = null;
+ display.input.reset();
+ }
};
- } catch(e) {}
+ display.detectingSelectAll = setTimeout(poll, 200);
+ }
}
- }
- options.finishInit = function (cm) {
- cm.save = save;
- cm.getTextArea = function () { return textarea; };
- cm.toTextArea = function () {
- cm.toTextArea = isNaN; // Prevent this from being ran twice
- save();
- textarea.parentNode.removeChild(cm.getWrapperElement());
- textarea.style.display = "";
- if (textarea.form) {
- off(textarea.form, "submit", save);
- if (typeof textarea.form.submit == "function")
- { textarea.form.submit = realSubmit; }
+ if (ie && ie_version >= 9) { prepareSelectAllHack(); }
+ if (captureRightClick) {
+ e_stop(e);
+ var mouseup = function () {
+ off(window, "mouseup", mouseup);
+ setTimeout(rehide, 20);
+ };
+ on(window, "mouseup", mouseup);
+ } else {
+ setTimeout(rehide, 50);
+ }
+ };
+
+ TextareaInput.prototype.readOnlyChanged = function (val) {
+ if (!val) { this.reset(); }
+ this.textarea.disabled = val == "nocursor";
+ };
+
+ TextareaInput.prototype.setUneditable = function () {};
+
+ TextareaInput.prototype.needsContentAttribute = false;
+
+ function fromTextArea(textarea, options) {
+ options = options ? copyObj(options) : {};
+ options.value = textarea.value;
+ if (!options.tabindex && textarea.tabIndex)
+ { options.tabindex = textarea.tabIndex; }
+ if (!options.placeholder && textarea.placeholder)
+ { options.placeholder = textarea.placeholder; }
+ // Set autofocus to true if this textarea is focused, or if it has
+ // autofocus and no other element is focused.
+ if (options.autofocus == null) {
+ var hasFocus = activeElt();
+ options.autofocus = hasFocus == textarea ||
+ textarea.getAttribute("autofocus") != null && hasFocus == document.body;
+ }
+
+ function save() {textarea.value = cm.getValue();}
+
+ var realSubmit;
+ if (textarea.form) {
+ on(textarea.form, "submit", save);
+ // Deplorable hack to make the submit method do the right thing.
+ if (!options.leaveSubmitMethodAlone) {
+ var form = textarea.form;
+ realSubmit = form.submit;
+ try {
+ var wrappedSubmit = form.submit = function () {
+ save();
+ form.submit = realSubmit;
+ form.submit();
+ form.submit = wrappedSubmit;
+ };
+ } catch(e) {}
}
+ }
+
+ options.finishInit = function (cm) {
+ cm.save = save;
+ cm.getTextArea = function () { return textarea; };
+ cm.toTextArea = function () {
+ cm.toTextArea = isNaN; // Prevent this from being ran twice
+ save();
+ textarea.parentNode.removeChild(cm.getWrapperElement());
+ textarea.style.display = "";
+ if (textarea.form) {
+ off(textarea.form, "submit", save);
+ if (typeof textarea.form.submit == "function")
+ { textarea.form.submit = realSubmit; }
+ }
+ };
};
+
+ textarea.style.display = "none";
+ var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
+ options);
+ return cm
+ }
+
+ function addLegacyProps(CodeMirror) {
+ CodeMirror.off = off;
+ CodeMirror.on = on;
+ CodeMirror.wheelEventPixels = wheelEventPixels;
+ CodeMirror.Doc = Doc;
+ CodeMirror.splitLines = splitLinesAuto;
+ CodeMirror.countColumn = countColumn;
+ CodeMirror.findColumn = findColumn;
+ CodeMirror.isWordChar = isWordCharBasic;
+ CodeMirror.Pass = Pass;
+ CodeMirror.signal = signal;
+ CodeMirror.Line = Line;
+ CodeMirror.changeEnd = changeEnd;
+ CodeMirror.scrollbarModel = scrollbarModel;
+ CodeMirror.Pos = Pos;
+ CodeMirror.cmpPos = cmp;
+ CodeMirror.modes = modes;
+ CodeMirror.mimeModes = mimeModes;
+ CodeMirror.resolveMode = resolveMode;
+ CodeMirror.getMode = getMode;
+ CodeMirror.modeExtensions = modeExtensions;
+ CodeMirror.extendMode = extendMode;
+ CodeMirror.copyState = copyState;
+ CodeMirror.startState = startState;
+ CodeMirror.innerMode = innerMode;
+ CodeMirror.commands = commands;
+ CodeMirror.keyMap = keyMap;
+ CodeMirror.keyName = keyName;
+ CodeMirror.isModifierKey = isModifierKey;
+ CodeMirror.lookupKey = lookupKey;
+ CodeMirror.normalizeKeyMap = normalizeKeyMap;
+ CodeMirror.StringStream = StringStream;
+ CodeMirror.SharedTextMarker = SharedTextMarker;
+ CodeMirror.TextMarker = TextMarker;
+ CodeMirror.LineWidget = LineWidget;
+ CodeMirror.e_preventDefault = e_preventDefault;
+ CodeMirror.e_stopPropagation = e_stopPropagation;
+ CodeMirror.e_stop = e_stop;
+ CodeMirror.addClass = addClass;
+ CodeMirror.contains = contains;
+ CodeMirror.rmClass = rmClass;
+ CodeMirror.keyNames = keyNames;
+ }
+
+ // EDITOR CONSTRUCTOR
+
+ defineOptions(CodeMirror);
+
+ addEditorMethods(CodeMirror);
+
+ // Set up methods on CodeMirror's prototype to redirect to the editor's document.
+ var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
+ for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
+ { CodeMirror.prototype[prop] = (function(method) {
+ return function() {return method.apply(this.doc, arguments)}
+ })(Doc.prototype[prop]); } }
+
+ eventMixin(Doc);
+ CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
+
+ // Extra arguments are stored as the mode's dependencies, which is
+ // used by (legacy) mechanisms like loadmode.js to automatically
+ // load a mode. (Preferred mechanism is the require/define calls.)
+ CodeMirror.defineMode = function(name/*, mode, …*/) {
+ if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name; }
+ defineMode.apply(this, arguments);
};
- textarea.style.display = "none";
- var cm = CodeMirror$1(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
- options);
- return cm
-}
-
-function addLegacyProps(CodeMirror) {
- CodeMirror.off = off;
- CodeMirror.on = on;
- CodeMirror.wheelEventPixels = wheelEventPixels;
- CodeMirror.Doc = Doc;
- CodeMirror.splitLines = splitLinesAuto;
- CodeMirror.countColumn = countColumn;
- CodeMirror.findColumn = findColumn;
- CodeMirror.isWordChar = isWordCharBasic;
- CodeMirror.Pass = Pass;
- CodeMirror.signal = signal;
- CodeMirror.Line = Line;
- CodeMirror.changeEnd = changeEnd;
- CodeMirror.scrollbarModel = scrollbarModel;
- CodeMirror.Pos = Pos;
- CodeMirror.cmpPos = cmp;
- CodeMirror.modes = modes;
- CodeMirror.mimeModes = mimeModes;
- CodeMirror.resolveMode = resolveMode;
- CodeMirror.getMode = getMode;
- CodeMirror.modeExtensions = modeExtensions;
- CodeMirror.extendMode = extendMode;
- CodeMirror.copyState = copyState;
- CodeMirror.startState = startState;
- CodeMirror.innerMode = innerMode;
- CodeMirror.commands = commands;
- CodeMirror.keyMap = keyMap;
- CodeMirror.keyName = keyName;
- CodeMirror.isModifierKey = isModifierKey;
- CodeMirror.lookupKey = lookupKey;
- CodeMirror.normalizeKeyMap = normalizeKeyMap;
- CodeMirror.StringStream = StringStream;
- CodeMirror.SharedTextMarker = SharedTextMarker;
- CodeMirror.TextMarker = TextMarker;
- CodeMirror.LineWidget = LineWidget;
- CodeMirror.e_preventDefault = e_preventDefault;
- CodeMirror.e_stopPropagation = e_stopPropagation;
- CodeMirror.e_stop = e_stop;
- CodeMirror.addClass = addClass;
- CodeMirror.contains = contains;
- CodeMirror.rmClass = rmClass;
- CodeMirror.keyNames = keyNames;
-}
-
-// EDITOR CONSTRUCTOR
-
-defineOptions(CodeMirror$1);
-
-addEditorMethods(CodeMirror$1);
-
-// Set up methods on CodeMirror's prototype to redirect to the editor's document.
-var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
-for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
- { CodeMirror$1.prototype[prop] = (function(method) {
- return function() {return method.apply(this.doc, arguments)}
- })(Doc.prototype[prop]); } }
-
-eventMixin(Doc);
-
-// INPUT HANDLING
-
-CodeMirror$1.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
-
-// MODE DEFINITION AND QUERYING
-
-// Extra arguments are stored as the mode's dependencies, which is
-// used by (legacy) mechanisms like loadmode.js to automatically
-// load a mode. (Preferred mechanism is the require/define calls.)
-CodeMirror$1.defineMode = function(name/*, mode, …*/) {
- if (!CodeMirror$1.defaults.mode && name != "null") { CodeMirror$1.defaults.mode = name; }
- defineMode.apply(this, arguments);
-};
-
-CodeMirror$1.defineMIME = defineMIME;
-
-// Minimal default mode.
-CodeMirror$1.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
-CodeMirror$1.defineMIME("text/plain", "null");
-
-// EXTENSIONS
-
-CodeMirror$1.defineExtension = function (name, func) {
- CodeMirror$1.prototype[name] = func;
-};
-CodeMirror$1.defineDocExtension = function (name, func) {
- Doc.prototype[name] = func;
-};
-
-CodeMirror$1.fromTextArea = fromTextArea;
-
-addLegacyProps(CodeMirror$1);
-
-CodeMirror$1.version = "5.39.3";
-
-return CodeMirror$1;
+ CodeMirror.defineMIME = defineMIME;
+
+ // Minimal default mode.
+ CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
+ CodeMirror.defineMIME("text/plain", "null");
+
+ // EXTENSIONS
+
+ CodeMirror.defineExtension = function (name, func) {
+ CodeMirror.prototype[name] = func;
+ };
+ CodeMirror.defineDocExtension = function (name, func) {
+ Doc.prototype[name] = func;
+ };
+
+ CodeMirror.fromTextArea = fromTextArea;
+
+ addLegacyProps(CodeMirror);
+
+ CodeMirror.version = "5.42.1";
+
+ return CodeMirror;
})));
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/foldcode.js b/chromium/third_party/blink/renderer/devtools/front_end/cm/foldcode.js
new file mode 100644
index 00000000000..0727bf48e5a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/foldcode.js
@@ -0,0 +1,155 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+if (typeof exports == 'object' && typeof module == 'object') // CommonJS
+ mod(require('../../lib/codemirror'));
+else if (typeof define == 'function' && define.amd) // AMD
+ define(['../../lib/codemirror'], mod);
+else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+'use strict';
+
+function doFold(cm, pos, options, force) {
+ if (options && options.call) {
+ var finder = options;
+ options = null;
+ } else {
+ var finder = getOption(cm, options, 'rangeFinder');
+ }
+ if (typeof pos == 'number')
+ pos = CodeMirror.Pos(pos, 0);
+ var minSize = getOption(cm, options, 'minFoldSize');
+
+ function getRange(allowFolded) {
+ var range = finder(cm, pos);
+ if (!range || range.to.line - range.from.line < minSize)
+ return null;
+ var marks = cm.findMarksAt(range.from);
+ for (var i = 0; i < marks.length; ++i) {
+ if (marks[i].__isFold && force !== 'fold') {
+ if (!allowFolded)
+ return null;
+ range.cleared = true;
+ marks[i].clear();
+ }
+ }
+ return range;
+ }
+
+ var range = getRange(true);
+ if (getOption(cm, options, 'scanUp'))
+ while (!range && pos.line > cm.firstLine()) {
+ pos = CodeMirror.Pos(pos.line - 1, 0);
+ range = getRange(false);
+ }
+ if (!range || range.cleared || force === 'unfold')
+ return;
+
+ var myWidget = makeWidget(cm, options);
+ CodeMirror.on(myWidget, 'mousedown', function(e) {
+ myRange.clear();
+ CodeMirror.e_preventDefault(e);
+ });
+ var myRange = cm.markText(
+ range.from, range.to,
+ {replacedWith: myWidget, clearOnEnter: getOption(cm, options, 'clearOnEnter'), __isFold: true});
+ myRange.on('clear', function(from, to) {
+ CodeMirror.signal(cm, 'unfold', cm, from, to);
+ });
+ CodeMirror.signal(cm, 'fold', cm, range.from, range.to);
+}
+
+function makeWidget(cm, options) {
+ var widget = getOption(cm, options, 'widget');
+ if (typeof widget == 'string') {
+ var text = document.createTextNode(widget);
+ widget = document.createElement('span');
+ widget.appendChild(text);
+ widget.className = 'CodeMirror-foldmarker';
+ } else if (widget) {
+ widget = widget.cloneNode(true)
+ }
+ return widget;
+}
+
+// Clumsy backwards-compatible interface
+CodeMirror.newFoldFunction = function(rangeFinder, widget) {
+ return function(cm, pos) {
+ doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget});
+ };
+};
+
+// New-style interface
+CodeMirror.defineExtension('foldCode', function(pos, options, force) {
+ doFold(this, pos, options, force);
+});
+
+CodeMirror.defineExtension('isFolded', function(pos) {
+ var marks = this.findMarksAt(pos);
+ for (var i = 0; i < marks.length; ++i)
+ if (marks[i].__isFold)
+ return true;
+});
+
+CodeMirror.commands.toggleFold = function(cm) {
+ cm.foldCode(cm.getCursor());
+};
+CodeMirror.commands.fold = function(cm) {
+ cm.foldCode(cm.getCursor(), null, 'fold');
+};
+CodeMirror.commands.unfold = function(cm) {
+ cm.foldCode(cm.getCursor(), null, 'unfold');
+};
+CodeMirror.commands.foldAll = function(cm) {
+ cm.operation(function() {
+ for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
+ cm.foldCode(CodeMirror.Pos(i, 0), null, 'fold');
+ });
+};
+CodeMirror.commands.unfoldAll = function(cm) {
+ cm.operation(function() {
+ for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
+ cm.foldCode(CodeMirror.Pos(i, 0), null, 'unfold');
+ });
+};
+
+CodeMirror.registerHelper('fold', 'combine', function() {
+ var funcs = Array.prototype.slice.call(arguments, 0);
+ return function(cm, start) {
+ for (var i = 0; i < funcs.length; ++i) {
+ var found = funcs[i](cm, start);
+ if (found)
+ return found;
+ }
+ };
+});
+
+CodeMirror.registerHelper('fold', 'auto', function(cm, start) {
+ var helpers = cm.getHelpers(start, 'fold');
+ for (var i = 0; i < helpers.length; i++) {
+ var cur = helpers[i](cm, start);
+ if (cur)
+ return cur;
+ }
+});
+
+var defaultOptions =
+ {rangeFinder: CodeMirror.fold.auto, widget: '\u2194', minFoldSize: 0, scanUp: false, clearOnEnter: true};
+
+CodeMirror.defineOption('foldOptions', null);
+
+function getOption(cm, options, name) {
+ if (options && options[name] !== undefined)
+ return options[name];
+ var editorOptions = cm.options.foldOptions;
+ if (editorOptions && editorOptions[name] !== undefined)
+ return editorOptions[name];
+ return defaultOptions[name];
+}
+
+CodeMirror.defineExtension('foldOption', function(options, name) {
+ return getOption(this, options, name);
+});
+}); \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/foldgutter.js b/chromium/third_party/blink/renderer/devtools/front_end/cm/foldgutter.js
new file mode 100644
index 00000000000..979bccea906
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/foldgutter.js
@@ -0,0 +1,162 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+if (typeof exports == 'object' && typeof module == 'object') // CommonJS
+ mod(require('../../lib/codemirror'), require('./foldcode'));
+else if (typeof define == 'function' && define.amd) // AMD
+ define(['../../lib/codemirror', './foldcode'], mod);
+else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+'use strict';
+
+CodeMirror.defineOption('foldGutter', false, function(cm, val, old) {
+ if (old && old != CodeMirror.Init) {
+ cm.clearGutter(cm.state.foldGutter.options.gutter);
+ cm.state.foldGutter = null;
+ cm.off('gutterClick', onGutterClick);
+ cm.off('change', onChange);
+ cm.off('viewportChange', onViewportChange);
+ cm.off('fold', onFold);
+ cm.off('unfold', onFold);
+ cm.off('swapDoc', onChange);
+ }
+ if (val) {
+ cm.state.foldGutter = new State(parseOptions(val));
+ updateInViewport(cm);
+ cm.on('gutterClick', onGutterClick);
+ cm.on('change', onChange);
+ cm.on('viewportChange', onViewportChange);
+ cm.on('fold', onFold);
+ cm.on('unfold', onFold);
+ cm.on('swapDoc', onChange);
+ }
+});
+
+var Pos = CodeMirror.Pos;
+
+function State(options) {
+ this.options = options;
+ this.from = this.to = 0;
+}
+
+function parseOptions(opts) {
+ if (opts === true)
+ opts = {};
+ if (opts.gutter == null)
+ opts.gutter = 'CodeMirror-foldgutter';
+ if (opts.indicatorOpen == null)
+ opts.indicatorOpen = 'CodeMirror-foldgutter-open';
+ if (opts.indicatorFolded == null)
+ opts.indicatorFolded = 'CodeMirror-foldgutter-folded';
+ return opts;
+}
+
+function isFolded(cm, line) {
+ var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
+ for (var i = 0; i < marks.length; ++i)
+ if (marks[i].__isFold && marks[i].find().from.line == line)
+ return marks[i];
+}
+
+function marker(spec) {
+ if (typeof spec == 'string') {
+ var elt = document.createElement('div');
+ elt.className = spec + ' CodeMirror-guttermarker-subtle';
+ return elt;
+ } else {
+ return spec.cloneNode(true);
+ }
+}
+
+function updateFoldInfo(cm, from, to) {
+ var opts = cm.state.foldGutter.options, cur = from;
+ var minSize = cm.foldOption(opts, 'minFoldSize');
+ var func = cm.foldOption(opts, 'rangeFinder');
+ cm.eachLine(from, to, function(line) {
+ var mark = null;
+ if (isFolded(cm, cur)) {
+ mark = marker(opts.indicatorFolded);
+ } else {
+ var pos = Pos(cur, 0);
+ var range = func && func(cm, pos);
+ if (range && range.to.line - range.from.line >= minSize)
+ mark = marker(opts.indicatorOpen);
+ }
+ cm.setGutterMarker(line, opts.gutter, mark);
+ ++cur;
+ });
+}
+
+function updateInViewport(cm) {
+ var vp = cm.getViewport(), state = cm.state.foldGutter;
+ if (!state)
+ return;
+ cm.operation(function() {
+ updateFoldInfo(cm, vp.from, vp.to);
+ });
+ state.from = vp.from;
+ state.to = vp.to;
+}
+
+function onGutterClick(cm, line, gutter) {
+ var state = cm.state.foldGutter;
+ if (!state)
+ return;
+ var opts = state.options;
+ if (gutter != opts.gutter)
+ return;
+ var folded = isFolded(cm, line);
+ if (folded)
+ folded.clear();
+ else
+ cm.foldCode(Pos(line, 0), opts.rangeFinder);
+}
+
+function onChange(cm) {
+ var state = cm.state.foldGutter;
+ if (!state)
+ return;
+ var opts = state.options;
+ state.from = state.to = 0;
+ clearTimeout(state.changeUpdate);
+ state.changeUpdate = setTimeout(function() {
+ updateInViewport(cm);
+ }, opts.foldOnChangeTimeSpan || 600);
+}
+
+function onViewportChange(cm) {
+ var state = cm.state.foldGutter;
+ if (!state)
+ return;
+ var opts = state.options;
+ clearTimeout(state.changeUpdate);
+ state.changeUpdate = setTimeout(function() {
+ var vp = cm.getViewport();
+ if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
+ updateInViewport(cm);
+ } else {
+ cm.operation(function() {
+ if (vp.from < state.from) {
+ updateFoldInfo(cm, vp.from, state.from);
+ state.from = vp.from;
+ }
+ if (vp.to > state.to) {
+ updateFoldInfo(cm, state.to, vp.to);
+ state.to = vp.to;
+ }
+ });
+ }
+ }, opts.updateViewportTimeSpan || 400);
+}
+
+function onFold(cm, from) {
+ var state = cm.state.foldGutter;
+ if (!state)
+ return;
+ var line = from.line;
+ if (line >= state.from && line < state.to)
+ updateFoldInfo(cm, line, line + 1);
+}
+}); \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/matchbrackets.js b/chromium/third_party/blink/renderer/devtools/front_end/cm/matchbrackets.js
index c918c3f99f1..6ad5a012292 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm/matchbrackets.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/matchbrackets.js
@@ -14,7 +14,7 @@
var Pos = CodeMirror.Pos;
- var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
+ var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
function findMatchingBracket(cm, where, config) {
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
@@ -51,7 +51,7 @@
var maxScanLines = (config && config.maxScanLines) || 1000;
var stack = [];
- var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
+ var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]<>]/;
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm/module.json b/chromium/third_party/blink/renderer/devtools/front_end/cm/module.json
index 7ed2f5e80b5..ecabb5f7957 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm/module.json
@@ -7,7 +7,10 @@
"markselection.js",
"comment.js",
"overlay.js",
- "activeline.js"
+ "activeline.js",
+ "foldcode.js",
+ "foldgutter.js",
+ "brace-fold.js"
],
"skip_compilation": [
"codemirror.js",
@@ -17,7 +20,10 @@
"markselection.js",
"comment.js",
"overlay.js",
- "activeline.js"
+ "activeline.js",
+ "foldcode.js",
+ "foldgutter.js",
+ "brace-fold.js"
],
"resources": [
"codemirror.css"
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clike.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clike.js
index 42033bd0a0d..924a0fc0926 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clike.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clike.js
@@ -65,7 +65,10 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
numberStart = parserConfig.numberStart || /[\d\.]/,
number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
- isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/;
+ isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/,
+ // An optional function that takes a {string} token and returns true if it
+ // should be treated as a builtin.
+ isReservedIdentifier = parserConfig.isReservedIdentifier || false;
var curPunc, isDefKeyword;
@@ -113,7 +116,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return "keyword";
}
if (contains(types, cur)) return "type";
- if (contains(builtin, cur)) {
+ if (contains(builtin, cur)
+ || (isReservedIdentifier && isReservedIdentifier(cur))) {
if (contains(blockKeywords, cur)) curPunc = "newstatement";
return "builtin";
}
@@ -263,8 +267,33 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
}
var cKeywords = "auto if break case register continue return default do sizeof " +
- "static else struct switch extern typedef union for goto while enum const volatile";
- var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
+ "static else struct switch extern typedef union for goto while enum const " +
+ "volatile inline restrict asm fortran";
+
+ // Do not use this. Use the cTypes function below. This is global just to avoid
+ // excessive calls when cTypes is being called multiple times during a parse.
+ var basicCTypes = words("int long char short double float unsigned signed " +
+ "void bool");
+
+ // Do not use this. Use the objCTypes function below. This is global just to avoid
+ // excessive calls when objCTypes is being called multiple times during a parse.
+ var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL");
+
+ // Returns true if identifier is a "C" type.
+ // C type is defined as those that are reserved by the compiler (basicTypes),
+ // and those that end in _t (Reserved by POSIX for types)
+ // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
+ function cTypes(identifier) {
+ return contains(basicCTypes, identifier) || /.+_t/.test(identifier);
+ }
+
+ // Returns true if identifier is a "Objective C" type.
+ function objCTypes(identifier) {
+ return cTypes(identifier) || contains(basicObjCTypes, identifier);
+ }
+
+ var cBlockKeywords = "case do else for if switch while struct enum union";
+ var cDefKeywords = "struct enum union";
function cppHook(stream, state) {
if (!state.startOfLine) return false
@@ -286,6 +315,14 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return false;
}
+ // For C and C++ (and ObjC): identifiers starting with __
+ // or _ followed by a capital letter are reserved for the compiler.
+ function cIsReservedIdentifier(token) {
+ if (!token || token.length < 2) return false;
+ if (token[0] != '_') return false;
+ return (token[1] == '_') || (token[1] !== token[1].toLowerCase());
+ }
+
function cpp14Literal(stream) {
stream.eatWhile(/[\w\.']/);
return "number";
@@ -368,31 +405,36 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
name: "clike",
keywords: words(cKeywords),
- types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " +
- "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " +
- "uint32_t uint64_t"),
- blockKeywords: words("case do else for if switch while struct"),
- defKeywords: words("struct"),
+ types: cTypes,
+ blockKeywords: words(cBlockKeywords),
+ defKeywords: words(cDefKeywords),
typeFirstDefinitions: true,
atoms: words("NULL true false"),
- hooks: {"#": cppHook, "*": pointerHook},
+ isReservedIdentifier: cIsReservedIdentifier,
+ hooks: {
+ "#": cppHook,
+ "*": pointerHook,
+ },
modeProps: {fold: ["brace", "include"]}
});
def(["text/x-c++src", "text/x-c++hdr"], {
name: "clike",
- keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " +
- "static_cast typeid catch operator template typename class friend private " +
- "this using const_cast inline public throw virtual delete mutable protected " +
- "alignas alignof constexpr decltype nullptr noexcept thread_local final " +
- "static_assert override"),
- types: words(cTypes + " bool wchar_t"),
- blockKeywords: words("catch class do else finally for if struct switch try while"),
- defKeywords: words("class namespace struct enum union"),
+ // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20.
+ keywords: words(cKeywords + "alignas alignof and and_eq audit axiom bitand bitor catch " +
+ "class compl concept constexpr const_cast decltype delete dynamic_cast " +
+ "explicit export final friend import module mutable namespace new noexcept " +
+ "not not_eq operator or or_eq override private protected public " +
+ "reinterpret_cast requires static_assert static_cast template this " +
+ "thread_local throw try typeid typename using virtual xor xor_eq"),
+ types: cTypes,
+ blockKeywords: words(cBlockKeywords + " class try catch"),
+ defKeywords: words(cDefKeywords + " class namespace"),
typeFirstDefinitions: true,
- atoms: words("true false NULL"),
+ atoms: words("true false NULL nullptr"),
dontIndentStatements: /^template$/,
isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
+ isReservedIdentifier: cIsReservedIdentifier,
hooks: {
"#": cppHook,
"*": pointerHook,
@@ -513,7 +555,6 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
def("text/x-scala", {
name: "clike",
keywords: words(
-
/* scala */
"abstract case catch class def do else extends final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " +
@@ -573,7 +614,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return state.tokenize(stream, state)
}
},
- modeProps: {closeBrackets: {triples: '"'}}
+ modeProps: {closeBrackets: {pairs: '()[]{}""', triples: '"'}}
});
function tokenKotlinString(tripleString){
@@ -628,6 +669,9 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
stream.eatWhile(/[\w\$_]/);
return "meta";
},
+ '*': function(_stream, state) {
+ return state.prevToken == '.' ? 'variable' : 'operator';
+ },
'"': function(stream, state) {
state.tokenize = tokenKotlinString(stream.match('""'));
return state.tokenize(stream, state);
@@ -708,11 +752,11 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
def("text/x-nesc", {
name: "clike",
- keywords: words(cKeywords + "as atomic async call command component components configuration event generic " +
+ keywords: words(cKeywords + " as atomic async call command component components configuration event generic " +
"implementation includes interface module new norace nx_struct nx_union post provides " +
"signal task uses abstract extends"),
- types: words(cTypes),
- blockKeywords: words("case do else for if switch while struct"),
+ types: cTypes,
+ blockKeywords: words(cBlockKeywords),
atoms: words("null true false"),
hooks: {"#": cppHook},
modeProps: {fold: ["brace", "include"]}
@@ -720,28 +764,34 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
def("text/x-objectivec", {
name: "clike",
- keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " +
- "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
- types: words(cTypes),
- atoms: words("YES NO NULL NILL ON OFF true false"),
+ keywords: words(cKeywords + " bycopy byref in inout oneway out self super atomic nonatomic retain copy " +
+ "readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " +
+ "@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " +
+ "@public @package @private @protected @required @optional @try @catch @finally @import " +
+ "@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available"),
+ types: objCTypes,
+ builtin: words("FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION NS_RETURNS_RETAINED " +
+ "NS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER NS_DESIGNATED_INITIALIZER " +
+ "NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION NS_ASSUME_NONNULL_BEGIN " +
+ "NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT"),
+ blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized"),
+ defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class"),
+ dontIndentStatements: /^@.*$/,
+ typeFirstDefinitions: true,
+ atoms: words("YES NO NULL Nil nil true false nullptr"),
+ isReservedIdentifier: cIsReservedIdentifier,
hooks: {
- "@": function(stream) {
- stream.eatWhile(/[\w\$]/);
- return "keyword";
- },
"#": cppHook,
- indent: function(_state, ctx, textAfter) {
- if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
- }
+ "*": pointerHook,
},
- modeProps: {fold: "brace"}
+ modeProps: {fold: ["brace", "include"]}
});
def("text/x-squirrel", {
name: "clike",
keywords: words("base break clone continue const default delete enum extends function in class" +
" foreach local resume return this throw typeof yield constructor instanceof static"),
- types: words(cTypes),
+ types: cTypes,
blockKeywords: words("case catch class else for foreach if switch try while"),
defKeywords: words("function local class"),
typeFirstDefinitions: true,
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clojure.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clojure.js
index 2015edff148..9823d812c57 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clojure.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/clojure.js
@@ -1,15 +1,10 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
-/**
- * Author: Hans Engel
- * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
- */
-
(function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
+ if (typeof exports === "object" && typeof module === "object") // CommonJS
mod(require("../../lib/codemirror"));
- else if (typeof define == "function" && define.amd) // AMD
+ else if (typeof define === "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
@@ -17,286 +12,277 @@
"use strict";
CodeMirror.defineMode("clojure", function (options) {
- var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2",
- ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword", VAR = "variable";
- var INDENT_WORD_SKIP = options.indentUnit || 2;
- var NORMAL_INDENT_UNIT = options.indentUnit || 2;
-
- function makeKeywords(str) {
- var obj = {}, words = str.split(" ");
- for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
- return obj;
+ var atoms = ["false", "nil", "true"];
+ var specialForms = [".", "catch", "def", "do", "if", "monitor-enter",
+ "monitor-exit", "new", "quote", "recur", "set!", "throw", "try", "var"];
+ var coreSymbols = ["*", "*'", "*1", "*2", "*3", "*agent*",
+ "*allow-unresolved-vars*", "*assert*", "*clojure-version*",
+ "*command-line-args*", "*compile-files*", "*compile-path*",
+ "*compiler-options*", "*data-readers*", "*default-data-reader-fn*", "*e",
+ "*err*", "*file*", "*flush-on-newline*", "*fn-loader*", "*in*",
+ "*math-context*", "*ns*", "*out*", "*print-dup*", "*print-length*",
+ "*print-level*", "*print-meta*", "*print-namespace-maps*",
+ "*print-readably*", "*read-eval*", "*reader-resolver*", "*source-path*",
+ "*suppress-read*", "*unchecked-math*", "*use-context-classloader*",
+ "*verbose-defrecords*", "*warn-on-reflection*", "+", "+'", "-", "-'",
+ "->", "->>", "->ArrayChunk", "->Eduction", "->Vec", "->VecNode",
+ "->VecSeq", "-cache-protocol-fn", "-reset-methods", "..", "/", "<", "<=",
+ "=", "==", ">", ">=", "EMPTY-NODE", "Inst", "StackTraceElement->vec",
+ "Throwable->map", "accessor", "aclone", "add-classpath", "add-watch",
+ "agent", "agent-error", "agent-errors", "aget", "alength", "alias",
+ "all-ns", "alter", "alter-meta!", "alter-var-root", "amap", "ancestors",
+ "and", "any?", "apply", "areduce", "array-map", "as->", "aset",
+ "aset-boolean", "aset-byte", "aset-char", "aset-double", "aset-float",
+ "aset-int", "aset-long", "aset-short", "assert", "assoc", "assoc!",
+ "assoc-in", "associative?", "atom", "await", "await-for", "await1",
+ "bases", "bean", "bigdec", "bigint", "biginteger", "binding", "bit-and",
+ "bit-and-not", "bit-clear", "bit-flip", "bit-not", "bit-or", "bit-set",
+ "bit-shift-left", "bit-shift-right", "bit-test", "bit-xor", "boolean",
+ "boolean-array", "boolean?", "booleans", "bound-fn", "bound-fn*",
+ "bound?", "bounded-count", "butlast", "byte", "byte-array", "bytes",
+ "bytes?", "case", "cast", "cat", "char", "char-array",
+ "char-escape-string", "char-name-string", "char?", "chars", "chunk",
+ "chunk-append", "chunk-buffer", "chunk-cons", "chunk-first", "chunk-next",
+ "chunk-rest", "chunked-seq?", "class", "class?", "clear-agent-errors",
+ "clojure-version", "coll?", "comment", "commute", "comp", "comparator",
+ "compare", "compare-and-set!", "compile", "complement", "completing",
+ "concat", "cond", "cond->", "cond->>", "condp", "conj", "conj!", "cons",
+ "constantly", "construct-proxy", "contains?", "count", "counted?",
+ "create-ns", "create-struct", "cycle", "dec", "dec'", "decimal?",
+ "declare", "dedupe", "default-data-readers", "definline", "definterface",
+ "defmacro", "defmethod", "defmulti", "defn", "defn-", "defonce",
+ "defprotocol", "defrecord", "defstruct", "deftype", "delay", "delay?",
+ "deliver", "denominator", "deref", "derive", "descendants", "destructure",
+ "disj", "disj!", "dissoc", "dissoc!", "distinct", "distinct?", "doall",
+ "dorun", "doseq", "dosync", "dotimes", "doto", "double", "double-array",
+ "double?", "doubles", "drop", "drop-last", "drop-while", "eduction",
+ "empty", "empty?", "ensure", "ensure-reduced", "enumeration-seq",
+ "error-handler", "error-mode", "eval", "even?", "every-pred", "every?",
+ "ex-data", "ex-info", "extend", "extend-protocol", "extend-type",
+ "extenders", "extends?", "false?", "ffirst", "file-seq", "filter",
+ "filterv", "find", "find-keyword", "find-ns", "find-protocol-impl",
+ "find-protocol-method", "find-var", "first", "flatten", "float",
+ "float-array", "float?", "floats", "flush", "fn", "fn?", "fnext", "fnil",
+ "for", "force", "format", "frequencies", "future", "future-call",
+ "future-cancel", "future-cancelled?", "future-done?", "future?",
+ "gen-class", "gen-interface", "gensym", "get", "get-in", "get-method",
+ "get-proxy-class", "get-thread-bindings", "get-validator", "group-by",
+ "halt-when", "hash", "hash-combine", "hash-map", "hash-ordered-coll",
+ "hash-set", "hash-unordered-coll", "ident?", "identical?", "identity",
+ "if-let", "if-not", "if-some", "ifn?", "import", "in-ns", "inc", "inc'",
+ "indexed?", "init-proxy", "inst-ms", "inst-ms*", "inst?", "instance?",
+ "int", "int-array", "int?", "integer?", "interleave", "intern",
+ "interpose", "into", "into-array", "ints", "io!", "isa?", "iterate",
+ "iterator-seq", "juxt", "keep", "keep-indexed", "key", "keys", "keyword",
+ "keyword?", "last", "lazy-cat", "lazy-seq", "let", "letfn", "line-seq",
+ "list", "list*", "list?", "load", "load-file", "load-reader",
+ "load-string", "loaded-libs", "locking", "long", "long-array", "longs",
+ "loop", "macroexpand", "macroexpand-1", "make-array", "make-hierarchy",
+ "map", "map-entry?", "map-indexed", "map?", "mapcat", "mapv", "max",
+ "max-key", "memfn", "memoize", "merge", "merge-with", "meta",
+ "method-sig", "methods", "min", "min-key", "mix-collection-hash", "mod",
+ "munge", "name", "namespace", "namespace-munge", "nat-int?", "neg-int?",
+ "neg?", "newline", "next", "nfirst", "nil?", "nnext", "not", "not-any?",
+ "not-empty", "not-every?", "not=", "ns", "ns-aliases", "ns-imports",
+ "ns-interns", "ns-map", "ns-name", "ns-publics", "ns-refers",
+ "ns-resolve", "ns-unalias", "ns-unmap", "nth", "nthnext", "nthrest",
+ "num", "number?", "numerator", "object-array", "odd?", "or", "parents",
+ "partial", "partition", "partition-all", "partition-by", "pcalls", "peek",
+ "persistent!", "pmap", "pop", "pop!", "pop-thread-bindings", "pos-int?",
+ "pos?", "pr", "pr-str", "prefer-method", "prefers",
+ "primitives-classnames", "print", "print-ctor", "print-dup",
+ "print-method", "print-simple", "print-str", "printf", "println",
+ "println-str", "prn", "prn-str", "promise", "proxy",
+ "proxy-call-with-super", "proxy-mappings", "proxy-name", "proxy-super",
+ "push-thread-bindings", "pvalues", "qualified-ident?",
+ "qualified-keyword?", "qualified-symbol?", "quot", "rand", "rand-int",
+ "rand-nth", "random-sample", "range", "ratio?", "rational?",
+ "rationalize", "re-find", "re-groups", "re-matcher", "re-matches",
+ "re-pattern", "re-seq", "read", "read-line", "read-string",
+ "reader-conditional", "reader-conditional?", "realized?", "record?",
+ "reduce", "reduce-kv", "reduced", "reduced?", "reductions", "ref",
+ "ref-history-count", "ref-max-history", "ref-min-history", "ref-set",
+ "refer", "refer-clojure", "reify", "release-pending-sends", "rem",
+ "remove", "remove-all-methods", "remove-method", "remove-ns",
+ "remove-watch", "repeat", "repeatedly", "replace", "replicate", "require",
+ "reset!", "reset-meta!", "reset-vals!", "resolve", "rest",
+ "restart-agent", "resultset-seq", "reverse", "reversible?", "rseq",
+ "rsubseq", "run!", "satisfies?", "second", "select-keys", "send",
+ "send-off", "send-via", "seq", "seq?", "seqable?", "seque", "sequence",
+ "sequential?", "set", "set-agent-send-executor!",
+ "set-agent-send-off-executor!", "set-error-handler!", "set-error-mode!",
+ "set-validator!", "set?", "short", "short-array", "shorts", "shuffle",
+ "shutdown-agents", "simple-ident?", "simple-keyword?", "simple-symbol?",
+ "slurp", "some", "some->", "some->>", "some-fn", "some?", "sort",
+ "sort-by", "sorted-map", "sorted-map-by", "sorted-set", "sorted-set-by",
+ "sorted?", "special-symbol?", "spit", "split-at", "split-with", "str",
+ "string?", "struct", "struct-map", "subs", "subseq", "subvec", "supers",
+ "swap!", "swap-vals!", "symbol", "symbol?", "sync", "tagged-literal",
+ "tagged-literal?", "take", "take-last", "take-nth", "take-while", "test",
+ "the-ns", "thread-bound?", "time", "to-array", "to-array-2d",
+ "trampoline", "transduce", "transient", "tree-seq", "true?", "type",
+ "unchecked-add", "unchecked-add-int", "unchecked-byte", "unchecked-char",
+ "unchecked-dec", "unchecked-dec-int", "unchecked-divide-int",
+ "unchecked-double", "unchecked-float", "unchecked-inc",
+ "unchecked-inc-int", "unchecked-int", "unchecked-long",
+ "unchecked-multiply", "unchecked-multiply-int", "unchecked-negate",
+ "unchecked-negate-int", "unchecked-remainder-int", "unchecked-short",
+ "unchecked-subtract", "unchecked-subtract-int", "underive", "unquote",
+ "unquote-splicing", "unreduced", "unsigned-bit-shift-right", "update",
+ "update-in", "update-proxy", "uri?", "use", "uuid?", "val", "vals",
+ "var-get", "var-set", "var?", "vary-meta", "vec", "vector", "vector-of",
+ "vector?", "volatile!", "volatile?", "vreset!", "vswap!", "when",
+ "when-first", "when-let", "when-not", "when-some", "while",
+ "with-bindings", "with-bindings*", "with-in-str", "with-loading-context",
+ "with-local-vars", "with-meta", "with-open", "with-out-str",
+ "with-precision", "with-redefs", "with-redefs-fn", "xml-seq", "zero?",
+ "zipmap"];
+ var haveBodyParameter = [
+ "->", "->>", "as->", "binding", "bound-fn", "case", "catch", "comment",
+ "cond", "cond->", "cond->>", "condp", "def", "definterface", "defmethod",
+ "defn", "defmacro", "defprotocol", "defrecord", "defstruct", "deftype",
+ "do", "doseq", "dotimes", "doto", "extend", "extend-protocol",
+ "extend-type", "fn", "for", "future", "if", "if-let", "if-not", "if-some",
+ "let", "letfn", "locking", "loop", "ns", "proxy", "reify", "struct-map",
+ "some->", "some->>", "try", "when", "when-first", "when-let", "when-not",
+ "when-some", "while", "with-bindings", "with-bindings*", "with-in-str",
+ "with-loading-context", "with-local-vars", "with-meta", "with-open",
+ "with-out-str", "with-precision", "with-redefs", "with-redefs-fn"];
+
+ CodeMirror.registerHelper("hintWords", "clojure",
+ [].concat(atoms, specialForms, coreSymbols));
+
+ var atom = createLookupMap(atoms);
+ var specialForm = createLookupMap(specialForms);
+ var coreSymbol = createLookupMap(coreSymbols);
+ var hasBodyParameter = createLookupMap(haveBodyParameter);
+ var delimiter = /^(?:[\\\[\]\s"(),;@^`{}~]|$)/;
+ var numberLiteral = /^(?:[+\-]?\d+(?:(?:N|(?:[eE][+\-]?\d+))|(?:\.?\d*(?:M|(?:[eE][+\-]?\d+))?)|\/\d+|[xX][0-9a-fA-F]+|r[0-9a-zA-Z]+)?(?=[\\\[\]\s"#'(),;@^`{}~]|$))/;
+ var characterLiteral = /^(?:\\(?:backspace|formfeed|newline|return|space|tab|o[0-7]{3}|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{4}|.)?(?=[\\\[\]\s"(),;@^`{}~]|$))/;
+
+ // simple-namespace := /^[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*/
+ // simple-symbol := /^(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)/
+ // qualified-symbol := (<simple-namespace>(<.><simple-namespace>)*</>)?<simple-symbol>
+ var qualifiedSymbol = /^(?:(?:[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*(?:\.[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*\/)?(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*(?=[\\\[\]\s"(),;@^`{}~]|$))/;
+
+ function base(stream, state) {
+ if (stream.eatSpace()) return ["space", null];
+ if (stream.match(numberLiteral)) return [null, "number"];
+ if (stream.match(characterLiteral)) return [null, "string-2"];
+ if (stream.eat(/^"/)) return (state.tokenize = inString)(stream, state);
+ if (stream.eat(/^[(\[{]/)) return ["open", "bracket"];
+ if (stream.eat(/^[)\]}]/)) return ["close", "bracket"];
+ if (stream.eat(/^;/)) {stream.skipToEnd(); return ["space", "comment"];}
+ if (stream.eat(/^[#'@^`~]/)) return [null, "meta"];
+
+ var matches = stream.match(qualifiedSymbol);
+ var symbol = matches && matches[0];
+
+ if (!symbol) {
+ // advance stream by at least one character so we don't get stuck.
+ stream.next();
+ stream.eatWhile(function (c) {return !is(c, delimiter);});
+ return [null, "error"];
}
- var atoms = makeKeywords("true false nil");
-
- var keywords = makeKeywords(
- "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest " +
- "slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn " +
- "do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync " +
- "doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars " +
- "binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
-
- var builtins = makeKeywords(
- "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* " +
- "*compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* " +
- "*math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* " +
- "*source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> " +
- "->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor " +
- "aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! " +
- "alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double " +
- "aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 " +
- "bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set " +
- "bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast " +
- "byte byte-array bytes case cat cast char char-array char-escape-string char-name-string char? chars chunk chunk-append " +
- "chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors " +
- "clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement completing concat cond condp " +
- "conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? " +
- "declare dedupe default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol " +
- "defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc " +
- "dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last " +
- "drop-while eduction empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info " +
- "extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword " +
- "find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? " +
- "fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? " +
- "gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash " +
- "hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? " +
- "int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep " +
- "keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file " +
- "load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array " +
- "make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods " +
- "min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty " +
- "not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias " +
- "ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all " +
- "partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers " +
- "primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str " +
- "prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues " +
- "quot rand rand-int rand-nth random-sample range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern " +
- "re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history " +
- "ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods " +
- "remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest " +
- "restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? " +
- "seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts " +
- "shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? " +
- "special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol " +
- "symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transduce " +
- "transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec " +
- "unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int " +
- "unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int "+
- "unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote " +
- "unquote-splicing update update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of " +
- "vector? volatile! volatile? vreset! vswap! when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context " +
- "with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap " +
- "*default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! " +
- "set-agent-send-off-executor! some-> some->>");
-
- var indentKeys = makeKeywords(
- // Built-ins
- "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto " +
- "locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type " +
- "try catch " +
-
- // Binding forms
- "let letfn binding loop for doseq dotimes when-let if-let " +
-
- // Data structures
- "defstruct struct-map assoc " +
-
- // clojure.test
- "testing deftest " +
-
- // contrib
- "handler-case handle dotrace deftrace");
-
- var tests = {
- digit: /\d/,
- digit_or_colon: /[\d:]/,
- hex: /[0-9a-f]/i,
- sign: /[+-]/,
- exponent: /e/i,
- keyword_char: /[^\s\(\[\;\)\]]/,
- symbol: /[\w*+!\-\._?:<>\/\xa1-\uffff]/,
- block_indent: /^(?:def|with)[^\/]+$|\/(?:def|with)/
- };
-
- function stateStack(indent, type, prev) { // represents a state stack object
- this.indent = indent;
- this.type = type;
- this.prev = prev;
- }
+ if (symbol === "comment" && state.lastToken === "(")
+ return (state.tokenize = inComment)(stream, state);
+ if (is(symbol, atom) || symbol.charAt(0) === ":") return ["symbol", "atom"];
+ if (is(symbol, specialForm) || is(symbol, coreSymbol)) return ["symbol", "keyword"];
+ if (state.lastToken === "(") return ["symbol", "builtin"]; // other operator
- function pushStack(state, indent, type) {
- state.indentStack = new stateStack(indent, type, state.indentStack);
- }
+ return ["symbol", "variable"];
+ }
- function popStack(state) {
- state.indentStack = state.indentStack.prev;
+ function inString(stream, state) {
+ var escaped = false, next;
+
+ while (next = stream.next()) {
+ if (next === "\"" && !escaped) {state.tokenize = base; break;}
+ escaped = !escaped && next === "\\";
}
- function isNumber(ch, stream){
- // hex
- if ( ch === '0' && stream.eat(/x/i) ) {
- stream.eatWhile(tests.hex);
- return true;
- }
+ return [null, "string"];
+ }
+
+ function inComment(stream, state) {
+ var parenthesisCount = 1;
+ var next;
+
+ while (next = stream.next()) {
+ if (next === ")") parenthesisCount--;
+ if (next === "(") parenthesisCount++;
+ if (parenthesisCount === 0) {
+ stream.backUp(1);
+ state.tokenize = base;
+ break;
+ }
+ }
- // leading sign
- if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) {
- stream.eat(tests.sign);
- ch = stream.next();
+ return ["space", "comment"];
+ }
+
+ function createLookupMap(words) {
+ var obj = {};
+
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+
+ return obj;
+ }
+
+ function is(value, test) {
+ if (test instanceof RegExp) return test.test(value);
+ if (test instanceof Object) return test.propertyIsEnumerable(value);
+ }
+
+ return {
+ startState: function () {
+ return {
+ ctx: {prev: null, start: 0, indentTo: 0},
+ lastToken: null,
+ tokenize: base
+ };
+ },
+
+ token: function (stream, state) {
+ if (stream.sol() && (typeof state.ctx.indentTo !== "number"))
+ state.ctx.indentTo = state.ctx.start + 1;
+
+ var typeStylePair = state.tokenize(stream, state);
+ var type = typeStylePair[0];
+ var style = typeStylePair[1];
+ var current = stream.current();
+
+ if (type !== "space") {
+ if (state.lastToken === "(" && state.ctx.indentTo === null) {
+ if (type === "symbol" && is(current, hasBodyParameter))
+ state.ctx.indentTo = state.ctx.start + options.indentUnit;
+ else state.ctx.indentTo = "next";
+ } else if (state.ctx.indentTo === "next") {
+ state.ctx.indentTo = stream.column();
}
- if ( tests.digit.test(ch) ) {
- stream.eat(ch);
- stream.eatWhile(tests.digit);
+ state.lastToken = current;
+ }
- if ( '.' == stream.peek() ) {
- stream.eat('.');
- stream.eatWhile(tests.digit);
- } else if ('/' == stream.peek() ) {
- stream.eat('/');
- stream.eatWhile(tests.digit);
- }
+ if (type === "open")
+ state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
+ else if (type === "close") state.ctx = state.ctx.prev || state.ctx;
- if ( stream.eat(tests.exponent) ) {
- stream.eat(tests.sign);
- stream.eatWhile(tests.digit);
- }
+ return style;
+ },
- return true;
- }
-
- return false;
- }
+ indent: function (state) {
+ var i = state.ctx.indentTo;
- // Eat character that starts after backslash \
- function eatCharacter(stream) {
- var first = stream.next();
- // Read special literals: backspace, newline, space, return.
- // Just read all lowercase letters.
- if (first && first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {
- return;
- }
- // Read unicode character: \u1000 \uA0a1
- if (first === "u") {
- stream.match(/[0-9a-z]{4}/i, true);
- }
- }
+ return (typeof i === "number") ?
+ i :
+ state.ctx.start + 1;
+ },
- return {
- startState: function () {
- return {
- indentStack: null,
- indentation: 0,
- mode: false
- };
- },
-
- token: function (stream, state) {
- if (state.indentStack == null && stream.sol()) {
- // update indentation, but only if indentStack is empty
- state.indentation = stream.indentation();
- }
-
- // skip spaces
- if (state.mode != "string" && stream.eatSpace()) {
- return null;
- }
- var returnType = null;
-
- switch(state.mode){
- case "string": // multi-line string parsing mode
- var next, escaped = false;
- while ((next = stream.next()) != null) {
- if (next == "\"" && !escaped) {
-
- state.mode = false;
- break;
- }
- escaped = !escaped && next == "\\";
- }
- returnType = STRING; // continue on in string mode
- break;
- default: // default parsing mode
- var ch = stream.next();
-
- if (ch == "\"") {
- state.mode = "string";
- returnType = STRING;
- } else if (ch == "\\") {
- eatCharacter(stream);
- returnType = CHARACTER;
- } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) {
- returnType = ATOM;
- } else if (ch == ";") { // comment
- stream.skipToEnd(); // rest of the line is a comment
- returnType = COMMENT;
- } else if (isNumber(ch,stream)){
- returnType = NUMBER;
- } else if (ch == "(" || ch == "[" || ch == "{" ) {
- var keyWord = '', indentTemp = stream.column(), letter;
- /**
- Either
- (indent-word ..
- (non-indent-word ..
- (;something else, bracket, etc.
- */
-
- if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
- keyWord += letter;
- }
-
- if (keyWord.length > 0 && (indentKeys.propertyIsEnumerable(keyWord) ||
- tests.block_indent.test(keyWord))) { // indent-word
- pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
- } else { // non-indent word
- // we continue eating the spaces
- stream.eatSpace();
- if (stream.eol() || stream.peek() == ";") {
- // nothing significant after
- // we restart indentation the user defined spaces after
- pushStack(state, indentTemp + NORMAL_INDENT_UNIT, ch);
- } else {
- pushStack(state, indentTemp + stream.current().length, ch); // else we match
- }
- }
- stream.backUp(stream.current().length - 1); // undo all the eating
-
- returnType = BRACKET;
- } else if (ch == ")" || ch == "]" || ch == "}") {
- returnType = BRACKET;
- if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : (ch == "]" ? "[" :"{"))) {
- popStack(state);
- }
- } else if ( ch == ":" ) {
- stream.eatWhile(tests.symbol);
- return ATOM;
- } else {
- stream.eatWhile(tests.symbol);
-
- if (keywords && keywords.propertyIsEnumerable(stream.current())) {
- returnType = KEYWORD;
- } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
- returnType = BUILTIN;
- } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
- returnType = ATOM;
- } else {
- returnType = VAR;
- }
- }
- }
-
- return returnType;
- },
-
- indent: function (state) {
- if (state.indentStack == null) return state.indentation;
- return state.indentStack.indent;
- },
-
- closeBrackets: {pairs: "()[]{}\"\""},
- lineComment: ";;"
- };
+ closeBrackets: {pairs: "()[]{}\"\""},
+ lineComment: ";;"
+ };
});
CodeMirror.defineMIME("text/x-clojure", "clojure");
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/markdown.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/markdown.js
index 442ab6b95b9..7aa3a3e17e6 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/markdown.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/markdown.js
@@ -91,7 +91,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
, textRE = /^[^#!\[\]*_\\<>` "'(~:]+/
, fencedCodeRE = /^(~~~+|```+)[ \t]*([\w+#-]*)[^\n`]*$/
, linkDefRE = /^\s*\[[^\]]+?\]:.*$/ // naive link-definition
- , punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~\u2014]/
+ , punctuation = /[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/
, expandedTab = " " // CommonMark specifies tab as 4 spaces
function switchInline(stream, state, f) {
@@ -620,7 +620,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
}
- if (modeCfg.emoji && ch === ":" && stream.match(/^[a-z_\d+-]+:/)) {
+ if (modeCfg.emoji && ch === ":" && stream.match(/^(?:[a-z_\d+][a-z_\d+-]*|\-[a-z_\d+][a-z_\d+-]*):/)) {
state.emoji = true;
if (modeCfg.highlightFormatting) state.formatting = "emoji";
var retType = getType(state);
@@ -869,6 +869,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
getType: getType,
+ blockCommentStart: "<!--",
+ blockCommentEnd: "-->",
closeBrackets: "()[]{}''\"\"``",
fold: "markdown"
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/python.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/python.js
index 623c03f7f0f..1ebe180a977 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/python.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/python.js
@@ -144,7 +144,7 @@
if (stream.match(stringPrefixes)) {
var isFmtString = stream.current().toLowerCase().indexOf('f') !== -1;
if (!isFmtString) {
- state.tokenize = tokenStringFactory(stream.current());
+ state.tokenize = tokenStringFactory(stream.current(), state.tokenize);
return state.tokenize(stream, state);
} else {
state.tokenize = formatStringFactory(stream.current(), state.tokenize);
@@ -251,7 +251,7 @@
return tokenString;
}
- function tokenStringFactory(delimiter) {
+ function tokenStringFactory(delimiter, tokenOuter) {
while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
delimiter = delimiter.substr(1);
@@ -266,7 +266,7 @@
if (singleline && stream.eol())
return OUTCLASS;
} else if (stream.match(delimiter)) {
- state.tokenize = tokenBase;
+ state.tokenize = tokenOuter;
return OUTCLASS;
} else {
stream.eat(/['"]/);
@@ -276,7 +276,7 @@
if (parserConf.singleLineStringErrors)
return ERRORCLASS;
else
- state.tokenize = tokenBase;
+ state.tokenize = tokenOuter;
}
return OUTCLASS;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/shell.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/shell.js
index 0e667e6a54f..5af12413b03 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/shell.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_modes/shell.js
@@ -14,26 +14,27 @@
CodeMirror.defineMode('shell', function() {
var words = {};
- function define(style, string) {
- var split = string.split(' ');
- for(var i = 0; i < split.length; i++) {
- words[split[i]] = style;
+ function define(style, dict) {
+ for(var i = 0; i < dict.length; i++) {
+ words[dict[i]] = style;
}
};
- // Atoms
- define('atom', 'true false');
-
- // Keywords
- define('keyword', 'if then do else elif while until for in esac fi fin ' +
- 'fil done exit set unset export function');
-
- // Commands
- define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' +
- 'curl cut diff echo find gawk gcc get git grep hg kill killall ln ls make ' +
- 'mkdir openssl mv nc nl node npm ping ps restart rm rmdir sed service sh ' +
- 'shopt shred source sort sleep ssh start stop su sudo svn tee telnet top ' +
- 'touch vi vim wall wc wget who write yes zsh');
+ var commonAtoms = ["true", "false"];
+ var commonKeywords = ["if", "then", "do", "else", "elif", "while", "until", "for", "in", "esac", "fi",
+ "fin", "fil", "done", "exit", "set", "unset", "export", "function"];
+ var commonCommands = ["ab", "awk", "bash", "beep", "cat", "cc", "cd", "chown", "chmod", "chroot", "clear",
+ "cp", "curl", "cut", "diff", "echo", "find", "gawk", "gcc", "get", "git", "grep", "hg", "kill", "killall",
+ "ln", "ls", "make", "mkdir", "openssl", "mv", "nc", "nl", "node", "npm", "ping", "ps", "restart", "rm",
+ "rmdir", "sed", "service", "sh", "shopt", "shred", "source", "sort", "sleep", "ssh", "start", "stop",
+ "su", "sudo", "svn", "tee", "telnet", "top", "touch", "vi", "vim", "wall", "wc", "wget", "who", "write",
+ "yes", "zsh"];
+
+ CodeMirror.registerHelper("hintWords", "shell", commonAtoms.concat(commonKeywords, commonCommands));
+
+ define('atom', commonAtoms);
+ define('keyword', commonKeywords);
+ define('builtin', commonCommands);
function tokenBase(stream, state) {
if (stream.eatSpace()) return null;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/css.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/css.js
index 8b5722905de..d82de4045d7 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/css.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/css.js
@@ -63,7 +63,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
- } else if (stream.match(/^-[\w\\\-]+/)) {
+ } else if (stream.match(/^-[\w\\\-]*/)) {
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ret("variable-2", "variable-definition");
@@ -501,7 +501,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
- "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
+ "max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
"opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js b/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js
index a31ffff8ef3..42b4b191f15 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js
@@ -644,7 +644,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
if (type == "variable") { register(value); return cont(); }
if (type == "spread") return cont(pattern);
- if (type == "[") return contCommasep(pattern, "]");
+ if (type == "[") return contCommasep(eltpattern, "]");
if (type == "{") return contCommasep(proppattern, "}");
}
function proppattern(type, value) {
@@ -655,8 +655,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "variable") cx.marked = "property";
if (type == "spread") return cont(pattern);
if (type == "}") return pass();
+ if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern);
return cont(expect(":"), pattern, maybeAssign);
}
+ function eltpattern() {
+ return pass(pattern, maybeAssign)
+ }
function maybeAssign(_type, value) {
if (value == "=") return cont(expressionNoComma);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastDetails.js b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastDetails.js
index 0ad9aa1bf9f..77e5086db5e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastDetails.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastDetails.js
@@ -99,8 +99,9 @@ ColorPicker.ContrastDetails = class {
this.setVisible(true);
const contrastRatio = this._contrastInfo.contrastRatio();
+ const fgColor = this._contrastInfo.color();
const bgColor = this._contrastInfo.bgColor();
- if (!contrastRatio || !bgColor) {
+ if (!contrastRatio || !bgColor || !fgColor) {
this._contrastUnknown = true;
this._contrastValue.textContent = '';
this._contrastValueBubble.classList.add('contrast-unknown');
@@ -115,8 +116,7 @@ ColorPicker.ContrastDetails = class {
this._contrastValueBubble.classList.remove('contrast-unknown');
this._contrastValue.textContent = contrastRatio.toFixed(2);
- this._bgColorSwatch.setBackgroundColor(bgColor);
- this._bgColorSwatch.setTextColor(this._contrastInfo.colorString());
+ this._bgColorSwatch.setColors(fgColor, bgColor);
const aa = this._contrastInfo.contrastRatioThreshold('aa');
this._passesAA = this._contrastInfo.contrastRatio() >= aa;
@@ -265,19 +265,14 @@ ColorPicker.ContrastDetails.Swatch = class {
}
/**
- * @param {!Common.Color} color
+ * @param {!Common.Color} fgColor
+ * @param {!Common.Color} bgColor
*/
- setBackgroundColor(color) {
- this._swatchInnerElement.style.background =
- /** @type {string} */ (color.asString(Common.Color.Format.RGBA));
+ setColors(fgColor, bgColor) {
+ this._textPreview.style.color = /** @type {string} */ (fgColor.asString(Common.Color.Format.RGBA));
+ this._swatchInnerElement.style.backgroundColor =
+ /** @type {string} */ (bgColor.asString(Common.Color.Format.RGBA));
// Show border if the swatch is white.
- this._swatchElement.classList.toggle('swatch-inner-white', color.hsla()[2] > 0.9);
- }
-
- /**
- * @param {string} colorString
- */
- setTextColor(colorString) {
- this._textPreview.style.color = colorString;
+ this._swatchElement.classList.toggle('swatch-inner-white', bgColor.hsla()[2] > 0.9);
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastInfo.js b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastInfo.js
index 25c5899a871..245576841a3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastInfo.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastInfo.js
@@ -3,57 +3,38 @@
// found in the LICENSE file.
ColorPicker.ContrastInfo = class extends Common.Object {
- constructor() {
- super();
-
- /** @type {?Array<number>} */
- this._hsva = null;
-
- /** @type {?Common.Color} */
- this._fgColor = null;
-
- /** @type {?Common.Color} */
- this._bgColor = null;
-
- /** @type {?number} */
- this._contrastRatio = null;
-
- /** @type {?Object<string, number>} */
- this._contrastRatioThresholds = null;
-
- /** @type {string} */
- this._colorString = '';
-
- /** @type {boolean} */
- this._isNull = true;
- }
-
/**
* @param {?SDK.CSSModel.ContrastInfo} contrastInfo
*/
- update(contrastInfo) {
+ constructor(contrastInfo) {
+ super();
this._isNull = true;
+ /** @type {?number} */
this._contrastRatio = null;
+ /** @type {?Object<string, number>} */
this._contrastRatioThresholds = null;
+ /** @type {?Common.Color} */
+ this._fgColor = null;
+ /** @type {?Common.Color} */
this._bgColor = null;
- if (contrastInfo.computedFontSize && contrastInfo.computedFontWeight && contrastInfo.computedBodyFontSize) {
- this._isNull = false;
- const isLargeFont = ColorPicker.ContrastInfo.computeIsLargeFont(
- contrastInfo.computedFontSize, contrastInfo.computedFontWeight, contrastInfo.computedBodyFontSize);
+ if (!contrastInfo)
+ return;
- this._contrastRatioThresholds =
- ColorPicker.ContrastInfo._ContrastThresholds[(isLargeFont ? 'largeFont' : 'normalFont')];
- }
+ if (!contrastInfo.computedFontSize || !contrastInfo.computedFontWeight || !contrastInfo.backgroundColors ||
+ contrastInfo.backgroundColors.length !== 1)
+ return;
- if (contrastInfo.backgroundColors && contrastInfo.backgroundColors.length === 1) {
- const bgColorText = contrastInfo.backgroundColors[0];
- const bgColor = Common.Color.parse(bgColorText);
- if (bgColor)
- this._setBgColorInternal(bgColor);
- }
+ this._isNull = false;
+ const isLargeFont =
+ ColorPicker.ContrastInfo.computeIsLargeFont(contrastInfo.computedFontSize, contrastInfo.computedFontWeight);
- this.dispatchEventToListeners(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated);
+ this._contrastRatioThresholds =
+ ColorPicker.ContrastInfo._ContrastThresholds[(isLargeFont ? 'largeFont' : 'normalFont')];
+ const bgColorText = contrastInfo.backgroundColors[0];
+ const bgColor = Common.Color.parse(bgColorText);
+ if (bgColor)
+ this._setBgColorInternal(bgColor);
}
/**
@@ -64,36 +45,26 @@ ColorPicker.ContrastInfo = class extends Common.Object {
}
/**
- * @param {!Array<number>} hsva
- * @param {string} colorString
+ * @param {!Common.Color} fgColor
*/
- setColor(hsva, colorString) {
- this._hsva = hsva;
- this._fgColor = Common.Color.fromHSVA(hsva);
- this._colorString = colorString;
+ setColor(fgColor) {
+ this._fgColor = fgColor;
this._updateContrastRatio();
this.dispatchEventToListeners(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated);
}
/**
- * @return {?number}
- */
- contrastRatio() {
- return this._contrastRatio;
- }
-
- /**
- * @return {string}
+ * @return {?Common.Color}
*/
- colorString() {
- return this._colorString;
+ color() {
+ return this._fgColor;
}
/**
- * @return {?Array<number>}
+ * @return {?number}
*/
- hsva() {
- return this._hsva;
+ contrastRatio() {
+ return this._contrastRatio;
}
/**
@@ -118,7 +89,7 @@ ColorPicker.ContrastInfo = class extends Common.Object {
// If we have a semi-transparent background color over an unknown
// background, draw the line for the "worst case" scenario: where
// the unknown background is the same color as the text.
- if (bgColor.hasAlpha) {
+ if (bgColor.hasAlpha()) {
const blendedRGBA = [];
Common.Color.blendColors(bgColor.rgba(), fgRGBA, blendedRGBA);
this._bgColor = new Common.Color(blendedRGBA, Common.Color.Format.RGBA);
@@ -153,10 +124,9 @@ ColorPicker.ContrastInfo = class extends Common.Object {
/**
* @param {string} fontSize
* @param {string} fontWeight
- * @param {?string} bodyFontSize
* @return {boolean}
*/
- static computeIsLargeFont(fontSize, fontWeight, bodyFontSize) {
+ static computeIsLargeFont(fontSize, fontWeight) {
const boldWeights = ['bold', 'bolder', '600', '700', '800', '900'];
const fontSizePx = parseFloat(fontSize.replace('px', ''));
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastOverlay.js b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastOverlay.js
index 573da0e796e..2ea28636dc5 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastOverlay.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/ContrastOverlay.js
@@ -13,15 +13,19 @@ ColorPicker.ContrastOverlay = class {
this._visible = false;
- const contrastRatioSVG = colorElement.createSVGChild('svg', 'spectrum-contrast-container fill');
- this._contrastRatioLine = contrastRatioSVG.createSVGChild('path', 'spectrum-contrast-line');
+ this._contrastRatioSVG = colorElement.createSVGChild('svg', 'spectrum-contrast-container fill');
+ this._contrastRatioLines = {
+ aa: this._contrastRatioSVG.createSVGChild('path', 'spectrum-contrast-line'),
+ aaa: this._contrastRatioSVG.createSVGChild('path', 'spectrum-contrast-line')
+ };
this._width = 0;
this._height = 0;
this._contrastRatioLineBuilder = new ColorPicker.ContrastRatioLineBuilder(this._contrastInfo);
- this._contrastRatioLineThrottler = new Common.Throttler(0);
- this._drawContrastRatioLineBound = this._drawContrastRatioLine.bind(this);
+
+ this._contrastRatioLinesThrottler = new Common.Throttler(0);
+ this._drawContrastRatioLinesBound = this._drawContrastRatioLines.bind(this);
this._contrastInfo.addEventListener(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated, this._update.bind(this));
}
@@ -30,7 +34,7 @@ ColorPicker.ContrastOverlay = class {
if (!this._visible || this._contrastInfo.isNull() || !this._contrastInfo.contrastRatio())
return;
- this._contrastRatioLineThrottler.schedule(this._drawContrastRatioLineBound);
+ this._contrastRatioLinesThrottler.schedule(this._drawContrastRatioLinesBound);
}
/**
@@ -48,18 +52,18 @@ ColorPicker.ContrastOverlay = class {
*/
setVisible(visible) {
this._visible = visible;
- this._contrastRatioLine.classList.toggle('hidden', !visible);
+ this._contrastRatioSVG.classList.toggle('hidden', !visible);
this._update();
}
- /**
- * @return {!Promise}
- */
- _drawContrastRatioLine() {
- const path = this._contrastRatioLineBuilder.drawContrastRatioLine(this._width, this._height);
- if (path)
- this._contrastRatioLine.setAttribute('d', path);
- return Promise.resolve();
+ async _drawContrastRatioLines() {
+ for (const level in this._contrastRatioLines) {
+ const path = this._contrastRatioLineBuilder.drawContrastRatioLine(this._width, this._height, level);
+ if (path)
+ this._contrastRatioLines[level].setAttribute('d', path);
+ else
+ this._contrastRatioLines[level].removeAttribute('d');
+ }
}
};
@@ -70,21 +74,16 @@ ColorPicker.ContrastRatioLineBuilder = class {
constructor(contrastInfo) {
/** @type {!ColorPicker.ContrastInfo} */
this._contrastInfo = contrastInfo;
-
- /** @type {?string} */
- this._bgColorForPreviousLine = null;
-
- this._hueForPreviousLine = 0;
- this._alphaForPreviousLine = 0;
}
/**
* @param {number} width
* @param {number} height
+ * @param {string} level
* @return {?string}
*/
- drawContrastRatioLine(width, height) {
- const requiredContrast = this._contrastInfo.contrastRatioThreshold('aa');
+ drawContrastRatioLine(width, height, level) {
+ const requiredContrast = this._contrastInfo.contrastRatioThreshold(level);
if (!width || !height || !requiredContrast)
return null;
@@ -95,20 +94,13 @@ ColorPicker.ContrastRatioLineBuilder = class {
const V = 2;
const A = 3;
- const hsva = this._contrastInfo.hsva();
+ const color = this._contrastInfo.color();
const bgColor = this._contrastInfo.bgColor();
- if (!hsva || !bgColor)
+ if (!color || !bgColor)
return null;
- const bgColorString = bgColor.asString(Common.Color.Format.RGBA);
-
- // Don't compute a new line if it would be identical to the previous line.
- if (hsva[H] === this._hueForPreviousLine && hsva[A] === this._alphaForPreviousLine &&
- bgColorString === this._bgColorForPreviousLine)
- return null;
-
- const fgRGBA = [];
- Common.Color.hsva2rgba(hsva, fgRGBA);
+ const fgRGBA = color.rgba();
+ const fgHSVA = color.hsva();
const bgRGBA = bgColor.rgba();
const bgLuminance = Common.Color.luminance(bgRGBA);
const blendedRGBA = [];
@@ -117,9 +109,9 @@ ColorPicker.ContrastRatioLineBuilder = class {
const fgIsLighter = fgLuminance > bgLuminance;
const desiredLuminance = Common.Color.desiredLuminance(bgLuminance, requiredContrast, fgIsLighter);
- let lastV = hsva[V];
+ let lastV = fgHSVA[V];
let currentSlope = 0;
- const candidateHSVA = [hsva[H], 0, 0, hsva[A]];
+ const candidateHSVA = [fgHSVA[H], 0, 0, fgHSVA[A]];
let pathBuilder = [];
const candidateRGBA = [];
Common.Color.hsva2rgba(candidateHSVA, candidateRGBA);
@@ -209,11 +201,8 @@ ColorPicker.ContrastRatioLineBuilder = class {
if (s !== null)
pathBuilder = pathBuilder.concat(['L', (s * width).toFixed(2), '-0.1']);
}
-
- this._bgColorForPreviousLine = bgColorString;
- this._hueForPreviousLine = hsva[H];
- this._alphaForPreviousLine = hsva[A];
-
+ if (pathBuilder.length === 0)
+ return null;
return pathBuilder.join(' ');
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js
index 572cab363e5..d66fc3756c1 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js
@@ -30,7 +30,10 @@
* @unrestricted
*/
ColorPicker.Spectrum = class extends UI.VBox {
- constructor() {
+ /**
+ * @param {?ColorPicker.ContrastInfo=} contrastInfo
+ */
+ constructor(contrastInfo) {
/**
* @param {!Element} parentElement
*/
@@ -112,20 +115,20 @@ ColorPicker.Spectrum = class extends UI.VBox {
this._colorElement, dragStart.bind(this, positionColor.bind(this)), positionColor.bind(this), null, 'pointer',
'default');
- if (Runtime.experiments.isEnabled('colorContrastRatio')) {
- const boundToggleColorPicker = this._toggleColorPicker.bind(this);
- const boundContrastPanelExpanded = this._contrastPanelExpanded.bind(this);
- /** @type {!ColorPicker.ContrastInfo} */
- this._contrastInfo = new ColorPicker.ContrastInfo();
+ // Color contrast business.
+ if (contrastInfo) {
+ this._contrastInfo = contrastInfo;
this._contrastOverlay = new ColorPicker.ContrastOverlay(this._contrastInfo, this._colorElement);
this._contrastDetails = new ColorPicker.ContrastDetails(
- this._contrastInfo, this.contentElement, boundToggleColorPicker, boundContrastPanelExpanded);
+ this._contrastInfo, this.contentElement, this._toggleColorPicker.bind(this),
+ this._contrastPanelExpanded.bind(this));
}
- this.element.classList.add('palettes-enabled', 'flex-none');
+ this.element.classList.add('flex-none');
/** @type {!Map.<string, !ColorPicker.Spectrum.Palette>} */
this._palettes = new Map();
this._palettePanel = this.contentElement.createChild('div', 'palette-panel');
+ this._palettePanel.tabIndex = -1;
this._palettePanelShowing = false;
this._paletteSectionContainer = this.contentElement.createChild('div', 'spectrum-palette-container');
this._paletteContainer = this._paletteSectionContainer.createChild('div', 'spectrum-palette');
@@ -209,10 +212,7 @@ ColorPicker.Spectrum = class extends UI.VBox {
}
_contrastPanelExpanded() {
- if (this._contrastDetails.expanded())
- this._contrastOverlay.setVisible(true);
- else
- this._contrastOverlay.setVisible(false);
+ this._contrastOverlay.setVisible(this._contrastDetails.expanded());
this._resizeForSelectedPalette(true);
}
@@ -236,13 +236,21 @@ ColorPicker.Spectrum = class extends UI.VBox {
return;
if (show)
this._updatePalettePanel();
- this._focus();
this._palettePanelShowing = show;
this.contentElement.classList.toggle('palette-panel-showing', show);
+ this._focus();
}
+ /**
+ * (Suppress warning about preventScroll)
+ * @suppress {checkTypes}
+ */
_focus() {
- if (this.isShowing())
+ if (!this.isShowing())
+ return;
+ if (this._palettePanelShowing)
+ this._palettePanel.focus({preventScroll: true});
+ else
this.contentElement.focus();
}
@@ -330,7 +338,7 @@ ColorPicker.Spectrum = class extends UI.VBox {
[{transform: 'scaleY(0)', opacity: '0'}, {transform: 'scaleY(1)', opacity: '1'}],
{duration: 200, easing: 'cubic-bezier(0.4, 0, 0.2, 1)'});
let shadesTop = this._paletteContainer.offsetTop + colorElement.offsetTop + colorElement.parentElement.offsetTop;
- if (this._contrastDetails && this._contrastDetails.visible())
+ if (this._contrastDetails)
shadesTop += this._contrastDetails.element().offsetHeight;
this._shadesContainer.style.top = shadesTop + 'px';
this._shadesContainer.style.left = colorElement.offsetLeft + 'px';
@@ -527,7 +535,7 @@ ColorPicker.Spectrum = class extends UI.VBox {
const paletteColorHeight = 12;
const paletteMargin = 12;
let paletteTop = 236;
- if (this._contrastDetails && this._contrastDetails.visible()) {
+ if (this._contrastDetails) {
if (this._contrastDetails.expanded())
paletteTop += 78;
else
@@ -605,20 +613,6 @@ ColorPicker.Spectrum = class extends UI.VBox {
}
/**
- * @param {?SDK.CSSModel.ContrastInfo} contrastInfo
- */
- setContrastInfo(contrastInfo) {
- if (!this._contrastInfo)
- return;
-
- this._contrastInfo.update(contrastInfo);
-
- // Contrast info may cause contrast details to become visible.
- if (this._contrastDetails.visible())
- this._resizeForSelectedPalette(true);
- }
-
- /**
* @param {!Array<number>|undefined} hsva
* @param {string|undefined} colorString
* @param {string|undefined} colorName
@@ -646,7 +640,7 @@ ColorPicker.Spectrum = class extends UI.VBox {
}
if (hsva && this._contrastInfo)
- this._contrastInfo.setColor(hsva, this.colorString());
+ this._contrastInfo.setColor(Common.Color.fromHSVA(hsva));
this._updateHelperLocations();
this._updateUI();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/spectrum.css b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/spectrum.css
index fdb3c8722c3..a46f872f897 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/color_picker/spectrum.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/color_picker/spectrum.css
@@ -1,15 +1,11 @@
/* https://github.com/bgrins/spectrum */
:host {
width: 232px;
- height: 240px;
+ height: 319px;
-webkit-user-select: none;
overflow: hidden;
}
-:host-context(.palettes-enabled) {
- height: 319px;
-}
-
:selection {
background-color: blue;
color: white;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/components/JSPresentationUtils.js b/chromium/third_party/blink/renderer/devtools/front_end/components/JSPresentationUtils.js
index 05753751de3..3e74bea526b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/components/JSPresentationUtils.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/components/JSPresentationUtils.js
@@ -44,6 +44,7 @@ Components.JSPresentationUtils.buildStackTracePreviewContents = function(
const shadowRoot = UI.createShadowRootWithCoreStyles(element, 'components/jsUtils.css');
const contentElement = shadowRoot.createChild('table', 'stack-preview-container');
let totalHiddenCallFramesCount = 0;
+ let totalCallFramesCount = 0;
/** @type {!Array<!Element>} */
const links = [];
@@ -54,6 +55,8 @@ Components.JSPresentationUtils.buildStackTracePreviewContents = function(
function appendStackTrace(stackTrace) {
let hiddenCallFrames = 0;
for (const stackFrame of stackTrace.callFrames) {
+ totalCallFramesCount++;
+ let shouldHide = totalCallFramesCount > 30 && stackTrace.callFrames.length > 31;
const row = createElement('tr');
row.createChild('td').textContent = '\n';
row.createChild('td', 'function-name').textContent = UI.beautifyFunctionName(stackFrame.functionName);
@@ -61,14 +64,16 @@ Components.JSPresentationUtils.buildStackTracePreviewContents = function(
if (link) {
link.addEventListener('contextmenu', populateContextMenu.bind(null, link));
const uiLocation = Components.Linkifier.uiLocation(link);
- if (uiLocation && Bindings.blackboxManager.isBlackboxedUISourceCode(uiLocation.uiSourceCode)) {
- row.classList.add('blackboxed');
- ++hiddenCallFrames;
- }
+ if (uiLocation && Bindings.blackboxManager.isBlackboxedUISourceCode(uiLocation.uiSourceCode))
+ shouldHide = true;
row.createChild('td').textContent = ' @ ';
row.createChild('td').appendChild(link);
links.push(link);
}
+ if (shouldHide) {
+ row.classList.add('blackboxed');
+ ++hiddenCallFrames;
+ }
contentElement.appendChild(row);
}
totalHiddenCallFramesCount += hiddenCallFrames;
@@ -125,9 +130,9 @@ Components.JSPresentationUtils.buildStackTracePreviewContents = function(
cell.colSpan = 4;
const showAllLink = cell.createChild('span', 'link');
if (totalHiddenCallFramesCount === 1)
- showAllLink.textContent = ls`Show 1 more blackboxed frame`;
+ showAllLink.textContent = ls`Show 1 more frame`;
else
- showAllLink.textContent = ls`Show ${totalHiddenCallFramesCount} more blackboxed frames`;
+ showAllLink.textContent = ls`Show ${totalHiddenCallFramesCount} more frames`;
showAllLink.addEventListener('click', () => {
contentElement.classList.add('show-blackboxed');
if (contentUpdated)
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsolePanel.js b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsolePanel.js
index 862721f83d8..9a16cf09666 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsolePanel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsolePanel.js
@@ -42,6 +42,11 @@ Console.ConsolePanel = class extends UI.Panel {
return /** @type {!Console.ConsolePanel} */ (self.runtime.sharedInstance(Console.ConsolePanel));
}
+ static _updateContextFlavor() {
+ const consoleView = Console.ConsolePanel.instance()._view;
+ UI.context.setFlavor(Console.ConsoleView, consoleView.isShowing() ? consoleView : null);
+ }
+
/**
* @override
*/
@@ -51,6 +56,7 @@ Console.ConsolePanel = class extends UI.Panel {
if (wrapper && wrapper.isShowing())
UI.inspectorView.setDrawerMinimized(true);
this._view.show(this.element);
+ Console.ConsolePanel._updateContextFlavor();
}
/**
@@ -63,6 +69,7 @@ Console.ConsolePanel = class extends UI.Panel {
UI.inspectorView.setDrawerMinimized(false);
if (Console.ConsolePanel.WrapperView._instance)
Console.ConsolePanel.WrapperView._instance._showViewInWrapper();
+ Console.ConsolePanel._updateContextFlavor();
}
/**
@@ -95,6 +102,7 @@ Console.ConsolePanel.WrapperView = class extends UI.VBox {
this._showViewInWrapper();
else
UI.inspectorView.setDrawerMinimized(true);
+ Console.ConsolePanel._updateContextFlavor();
}
/**
@@ -102,6 +110,7 @@ Console.ConsolePanel.WrapperView = class extends UI.VBox {
*/
willHide() {
UI.inspectorView.setDrawerMinimized(false);
+ Console.ConsolePanel._updateContextFlavor();
}
_showViewInWrapper() {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
index 0579fff41ce..c41a659884a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
@@ -183,6 +183,8 @@ Console.ConsoleView = class extends UI.VBox {
this._messagesElement.addEventListener('clipboard-paste', this._messagesPasted.bind(this), true);
this._viewportThrottler = new Common.Throttler(50);
+ this._pendingBatchResize = false;
+ this._onMessageResizedBound = this._onMessageResized.bind(this);
this._topGroup = Console.ConsoleGroup.createTopGroup();
this._currentGroup = this._topGroup;
@@ -215,8 +217,13 @@ Console.ConsoleView = class extends UI.VBox {
this._prompt.addEventListener(Console.ConsolePrompt.Events.TextChanged, this._promptTextChanged, this);
this._keyboardNavigationEnabled = Runtime.experiments.isEnabled('consoleKeyboardNavigation');
- if (this._keyboardNavigationEnabled)
+ if (this._keyboardNavigationEnabled) {
this._messagesElement.addEventListener('keydown', this._messagesKeyDown.bind(this), false);
+ this._prompt.element.addEventListener('focusin', () => {
+ if (this._isScrolledToBottom())
+ this._viewport.setStickToBottom(true);
+ });
+ }
this._consoleHistoryAutocompleteSetting.addChangeListener(this._consoleHistoryAutocompleteChanged, this);
@@ -388,9 +395,22 @@ Console.ConsoleView = class extends UI.VBox {
* @override
*/
focus() {
+ if (!this._keyboardNavigationEnabled) {
+ this._focusPrompt();
+ return;
+ }
+ if (this._viewport.hasVirtualSelection())
+ this._viewport.contentElement().focus();
+ else
+ this._focusPrompt();
+ }
+
+ _focusPrompt() {
if (!this._prompt.hasFocus()) {
+ const oldStickToBottom = this._viewport.stickToBottom();
const oldScrollTop = this._viewport.element.scrollTop;
this._prompt.focus();
+ this._viewport.setStickToBottom(oldStickToBottom);
this._viewport.element.scrollTop = oldScrollTop;
}
}
@@ -625,18 +645,43 @@ Console.ConsoleView = class extends UI.VBox {
const nestingLevel = this._currentGroup.nestingLevel();
switch (message.type) {
case SDK.ConsoleMessage.MessageType.Command:
- return new Console.ConsoleCommand(message, this._linkifier, this._badgePool, nestingLevel);
+ return new Console.ConsoleCommand(
+ message, this._linkifier, this._badgePool, nestingLevel, this._onMessageResizedBound);
case SDK.ConsoleMessage.MessageType.Result:
- return new Console.ConsoleCommandResult(message, this._linkifier, this._badgePool, nestingLevel);
+ return new Console.ConsoleCommandResult(
+ message, this._linkifier, this._badgePool, nestingLevel, this._onMessageResizedBound);
case SDK.ConsoleMessage.MessageType.StartGroupCollapsed:
case SDK.ConsoleMessage.MessageType.StartGroup:
return new Console.ConsoleGroupViewMessage(
- message, this._linkifier, this._badgePool, nestingLevel, this._updateMessageList.bind(this));
+ message, this._linkifier, this._badgePool, nestingLevel, this._updateMessageList.bind(this),
+ this._onMessageResizedBound);
default:
- return new Console.ConsoleViewMessage(message, this._linkifier, this._badgePool, nestingLevel);
+ return new Console.ConsoleViewMessage(
+ message, this._linkifier, this._badgePool, nestingLevel, this._onMessageResizedBound);
}
}
+ /**
+ * @param {!Common.Event} event
+ * @return {!Promise}
+ */
+ async _onMessageResized(event) {
+ if (!this._keyboardNavigationEnabled)
+ return;
+ const treeElement = /** @type {!UI.TreeElement} */ (event.data);
+ if (this._pendingBatchResize || !treeElement.treeOutline)
+ return;
+ this._pendingBatchResize = true;
+ await Promise.resolve();
+ const treeOutlineElement = treeElement.treeOutline.element;
+ this._viewport.setStickToBottom(this._isScrolledToBottom());
+ // Scroll, in case mutations moved the element below the visible area.
+ if (treeOutlineElement.offsetHeight <= this._messagesElement.offsetHeight)
+ treeOutlineElement.scrollIntoViewIfNeeded();
+
+ this._pendingBatchResize = false;
+ }
+
_consoleCleared() {
const hadFocus = this._viewport.element.hasFocus();
this._cancelBuildHiddenCache();
@@ -866,12 +911,12 @@ Console.ConsoleView = class extends UI.VBox {
if (this._keyboardNavigationEnabled) {
if (clickedOutsideMessageList) {
this._prompt.moveCaretToEndOfPrompt();
- this.focus();
+ this._focusPrompt();
}
} else {
if (clickedOutsideMessageList)
this._prompt.moveCaretToEndOfPrompt();
- this.focus();
+ this._focusPrompt();
}
}
}
@@ -884,7 +929,7 @@ Console.ConsoleView = class extends UI.VBox {
if (hasActionModifier || event.key.length !== 1 || UI.isEditing() || this._messagesElement.hasSelection())
return;
this._prompt.moveCaretToEndOfPrompt();
- this.focus();
+ this._focusPrompt();
}
/**
@@ -1194,7 +1239,11 @@ Console.ConsoleView = class extends UI.VBox {
}
_promptTextChanged() {
- this._viewport.setStickToBottom(this._isScrolledToBottom());
+ const oldStickToBottom = this._viewport.stickToBottom();
+ const willStickToBottom = this._isScrolledToBottom();
+ this._viewport.setStickToBottom(willStickToBottom);
+ if (willStickToBottom && !oldStickToBottom)
+ this._scheduleViewportRefresh();
this._promptTextChangedForTest();
}
@@ -1395,16 +1444,6 @@ Console.ConsoleViewFilter = class {
*/
Console.ConsoleCommand = class extends Console.ConsoleViewMessage {
/**
- * @param {!SDK.ConsoleMessage} message
- * @param {!Components.Linkifier} linkifier
- * @param {!ProductRegistry.BadgePool} badgePool
- * @param {number} nestingLevel
- */
- constructor(message, linkifier, badgePool, nestingLevel) {
- super(message, linkifier, badgePool, nestingLevel);
- }
-
- /**
* @override
* @return {!Element}
*/
@@ -1446,16 +1485,6 @@ Console.ConsoleCommand.MaxLengthToIgnoreHighlighter = 10000;
Console.ConsoleCommandResult = class extends Console.ConsoleViewMessage {
/**
- * @param {!SDK.ConsoleMessage} message
- * @param {!Components.Linkifier} linkifier
- * @param {!ProductRegistry.BadgePool} badgePool
- * @param {number} nestingLevel
- */
- constructor(message, linkifier, badgePool, nestingLevel) {
- super(message, linkifier, badgePool, nestingLevel);
- }
-
- /**
* @override
* @return {!Element}
*/
@@ -1528,6 +1557,7 @@ Console.ConsoleView.ActionDelegate = class {
case 'console.show':
InspectorFrontendHost.bringToFront();
Common.console.show();
+ Console.ConsoleView.instance()._focusPrompt();
return true;
case 'console.clear':
Console.ConsoleView.clearConsole();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
index 19a988e3162..5279e4e13e5 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -37,16 +37,18 @@ Console.ConsoleViewMessage = class {
* @param {!Components.Linkifier} linkifier
* @param {!ProductRegistry.BadgePool} badgePool
* @param {number} nestingLevel
+ * @param {function(!Common.Event)} onResize
*/
- constructor(consoleMessage, linkifier, badgePool, nestingLevel) {
+ constructor(consoleMessage, linkifier, badgePool, nestingLevel, onResize) {
this._message = consoleMessage;
this._linkifier = linkifier;
this._badgePool = badgePool;
this._repeatCount = 1;
this._closeGroupDecorationCount = 0;
this._nestingLevel = nestingLevel;
- /** @type {!Array<{element: !Element, selectFirst: function()}>} */
+ /** @type {!Array<{element: !Element, forceSelect: function()}>} */
this._selectableChildren = [];
+ this._messageResized = onResize;
/** @type {?DataGrid.DataGrid} */
this._dataGrid = null;
@@ -214,13 +216,6 @@ Console.ConsoleViewMessage = class {
messageElement.title =
Common.UIString('Clear all messages with ' + UI.shortcutRegistry.shortcutTitleForAction('console.clear'));
break;
- case SDK.ConsoleMessage.MessageType.Assert: {
- let args = [Common.UIString('Assertion failed:')];
- if (this._message.parameters)
- args = args.concat(this._message.parameters);
- messageElement = this._format(args);
- break;
- }
case SDK.ConsoleMessage.MessageType.Dir: {
const obj = this._message.parameters ? this._message.parameters[0] : undefined;
const args = ['%O', obj];
@@ -231,6 +226,9 @@ Console.ConsoleViewMessage = class {
case SDK.ConsoleMessage.MessageType.ProfileEnd:
messageElement = this._format([messageText]);
break;
+ case SDK.ConsoleMessage.MessageType.Assert:
+ this._messagePrefix = ls`Assertion failed: `;
+ // Fall through.
default: {
if (this._message.parameters && this._message.parameters.length === 1 &&
this._message.parameters[0].type === 'string')
@@ -283,7 +281,7 @@ Console.ConsoleViewMessage = class {
const linkElement = Components.Linkifier.linkifyRevealable(request, request.url(), request.url());
// Focus is handled by the viewport.
linkElement.tabIndex = -1;
- this._selectableChildren.push({element: linkElement, selectFirst: () => linkElement.focus()});
+ this._selectableChildren.push({element: linkElement, forceSelect: () => linkElement.focus()});
messageElement.appendChild(linkElement);
if (request.failed)
messageElement.createTextChildren(' ', request.localizedFailDescription);
@@ -296,7 +294,7 @@ Console.ConsoleViewMessage = class {
const linkElement = Components.Linkifier.linkifyRevealable(
/** @type {!SDK.NetworkRequest} */ (request), title, request.url());
linkElement.tabIndex = -1;
- this._selectableChildren.push({element: linkElement, selectFirst: () => linkElement.focus()});
+ this._selectableChildren.push({element: linkElement, forceSelect: () => linkElement.focus()});
return linkElement;
});
messageElement.appendChild(fragment);
@@ -393,7 +391,7 @@ Console.ConsoleViewMessage = class {
stackTraceElement.appendChild(stackTracePreview.element);
for (const linkElement of stackTracePreview.links) {
linkElement.tabIndex = -1;
- this._selectableChildren.push({element: linkElement, selectFirst: () => linkElement.focus()});
+ this._selectableChildren.push({element: linkElement, forceSelect: () => linkElement.focus()});
}
stackTraceElement.classList.add('hidden');
this._expandTrace = expand => {
@@ -480,6 +478,8 @@ Console.ConsoleViewMessage = class {
_format(rawParameters) {
// This node is used like a Builder. Values are continually appended onto it.
const formattedResult = createElement('span');
+ if (this._messagePrefix)
+ formattedResult.createChild('span').textContent = this._messagePrefix;
if (!rawParameters.length)
return formattedResult;
@@ -626,6 +626,9 @@ Console.ConsoleViewMessage = class {
section.enableContextMenu();
section.setShowSelectionOnKeyboardFocus(true, true);
this._selectableChildren.push(section);
+ section.addEventListener(UI.TreeOutline.Events.ElementAttached, this._messageResized);
+ section.addEventListener(UI.TreeOutline.Events.ElementExpanded, this._messageResized);
+ section.addEventListener(UI.TreeOutline.Events.ElementCollapsed, this._messageResized);
return section.element;
}
@@ -645,16 +648,21 @@ Console.ConsoleViewMessage = class {
*/
function formatTargetFunction(targetFunction) {
const functionElement = createElement('span');
- ObjectUI.ObjectPropertiesSection.formatObjectAsFunction(targetFunction, functionElement, true, includePreview);
+ const promise = ObjectUI.ObjectPropertiesSection.formatObjectAsFunction(
+ targetFunction, functionElement, true, includePreview);
result.appendChild(functionElement);
if (targetFunction !== func) {
const note = result.createChild('span', 'object-info-state-note');
note.title = Common.UIString('Function was resolved from bound function.');
}
result.addEventListener('contextmenu', this._contextMenuEventFired.bind(this, targetFunction), false);
+ promise.then(() => this._formattedParameterAsFunctionForTest());
}
}
+ _formattedParameterAsFunctionForTest() {
+ }
+
/**
* @param {!SDK.RemoteObject} obj
* @param {!Event} event
@@ -695,8 +703,12 @@ Console.ConsoleViewMessage = class {
}
const renderResult = await UI.Renderer.render(/** @type {!Object} */ (node));
if (renderResult) {
- if (renderResult.tree)
+ if (renderResult.tree) {
this._selectableChildren.push(renderResult.tree);
+ renderResult.tree.addEventListener(UI.TreeOutline.Events.ElementAttached, this._messageResized);
+ renderResult.tree.addEventListener(UI.TreeOutline.Events.ElementExpanded, this._messageResized);
+ renderResult.tree.addEventListener(UI.TreeOutline.Events.ElementCollapsed, this._messageResized);
+ }
result.appendChild(renderResult.node);
} else {
result.appendChild(this._formatParameterAsObject(remoteObject, false));
@@ -1123,7 +1135,7 @@ Console.ConsoleViewMessage = class {
_selectNearestVisibleChild(fromIndex, backwards) {
const nearestChild = this._nearestVisibleChild(fromIndex, backwards);
if (nearestChild) {
- nearestChild.selectFirst();
+ nearestChild.forceSelect();
return true;
}
return false;
@@ -1132,7 +1144,7 @@ Console.ConsoleViewMessage = class {
/**
* @param {number} fromIndex
* @param {boolean=} backwards
- * @return {?{element: !Element, selectFirst: function()}}
+ * @return {?{element: !Element, forceSelect: function()}}
*/
_nearestVisibleChild(fromIndex, backwards) {
const childCount = this._selectableChildren.length;
@@ -1316,7 +1328,7 @@ Console.ConsoleViewMessage = class {
return;
if (!this._repeatCountElement) {
- this._repeatCountElement = createElementWithClass('label', 'console-message-repeat-count', 'dt-small-bubble');
+ this._repeatCountElement = createElementWithClass('span', 'console-message-repeat-count', 'dt-small-bubble');
switch (this._message.level) {
case SDK.ConsoleMessage.MessageLevel.Warning:
this._repeatCountElement.type = 'warning';
@@ -1480,7 +1492,7 @@ Console.ConsoleViewMessage = class {
const scriptLocationLink = this._linkifier.linkifyScriptLocation(
debuggerModel.target(), null, links[i].url, links[i].lineNumber, links[i].columnNumber);
scriptLocationLink.tabIndex = -1;
- this._selectableChildren.push({element: scriptLocationLink, selectFirst: () => scriptLocationLink.focus()});
+ this._selectableChildren.push({element: scriptLocationLink, forceSelect: () => scriptLocationLink.focus()});
formattedResult.appendChild(scriptLocationLink);
start = links[i].positionRight;
}
@@ -1547,7 +1559,7 @@ Console.ConsoleViewMessage = class {
return this._linkifyWithCustomLinkifier(string, (text, url, lineNumber, columnNumber) => {
const linkElement = Components.Linkifier.linkifyURL(url, {text, lineNumber, columnNumber});
linkElement.tabIndex = -1;
- this._selectableChildren.push({element: linkElement, selectFirst: () => linkElement.focus()});
+ this._selectableChildren.push({element: linkElement, forceSelect: () => linkElement.focus()});
return linkElement;
});
}
@@ -1627,10 +1639,11 @@ Console.ConsoleGroupViewMessage = class extends Console.ConsoleViewMessage {
* @param {!ProductRegistry.BadgePool} badgePool
* @param {number} nestingLevel
* @param {function()} onToggle
+ * @param {function(!Common.Event)} onResize
*/
- constructor(consoleMessage, linkifier, badgePool, nestingLevel, onToggle) {
+ constructor(consoleMessage, linkifier, badgePool, nestingLevel, onToggle, onResize) {
console.assert(consoleMessage.isGroupStartMessage());
- super(consoleMessage, linkifier, badgePool, nestingLevel);
+ super(consoleMessage, linkifier, badgePool, nestingLevel, onResize);
this._collapsed = consoleMessage.type === SDK.ConsoleMessage.MessageType.StartGroupCollapsed;
/** @type {?UI.Icon} */
this._expandGroupIcon = null;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
index 5b93a99f516..11b6fd852dd 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
@@ -101,6 +101,13 @@ Console.ConsoleViewport = class {
this._observer.disconnect();
}
+ /**
+ * @return {boolean}
+ */
+ hasVirtualSelection() {
+ return this._virtualSelectedIndex !== -1;
+ }
+
copyWithStyles() {
this._muteCopyHandler = true;
this.element.ownerDocument.execCommand('copy');
@@ -130,9 +137,13 @@ Console.ConsoleViewport = class {
let focusLastChild = false;
// Make default selection when moving from external (e.g. prompt) to the container.
if (this._virtualSelectedIndex === -1 && this._isOutsideViewport(/** @type {?Element} */ (event.relatedTarget)) &&
- event.target === this._contentElement) {
+ event.target === this._contentElement && this._itemCount) {
focusLastChild = true;
this._virtualSelectedIndex = this._itemCount - 1;
+
+ // Update stick to bottom before scrolling into view.
+ this.refresh();
+ this.scrollItemIntoView(this._virtualSelectedIndex);
}
this._updateFocusedItem(focusLastChild);
}
@@ -213,14 +224,14 @@ Console.ConsoleViewport = class {
const containerHasFocus = this._contentElement === this.element.ownerDocument.deepActiveElement();
if (this._lastSelectedElement && changed)
this._lastSelectedElement.classList.remove('console-selected');
- if (selectedElement && (changed || containerHasFocus) && this.element.hasFocus()) {
+ if (selectedElement && (focusLastChild || changed || containerHasFocus) && this.element.hasFocus()) {
selectedElement.classList.add('console-selected');
// Do not focus the message if something within holds focus (e.g. object).
- if (!selectedElement.hasFocus()) {
- if (focusLastChild)
- this._renderedItems[this._virtualSelectedIndex - this._firstActiveIndex].focusLastChildOrSelf();
- else
- focusWithoutScroll(selectedElement);
+ if (focusLastChild) {
+ this.setStickToBottom(false);
+ this._renderedItems[this._virtualSelectedIndex - this._firstActiveIndex].focusLastChildOrSelf();
+ } else if (!selectedElement.hasFocus()) {
+ focusWithoutScroll(selectedElement);
}
}
if (this._itemCount && !this._contentElement.hasFocus())
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console/consoleView.css b/chromium/third_party/blink/renderer/devtools/front_end/console/consoleView.css
index 1bebaf91a5e..4fa8cf38fdf 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console/consoleView.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console/consoleView.css
@@ -82,6 +82,7 @@
word-wrap: break-word;
-webkit-user-select: text;
transform: translateZ(0);
+ overflow-anchor: none; /* Chrome-specific scroll-anchoring opt-out */
}
#console-prompt {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console/module.json b/chromium/third_party/blink/renderer/devtools/front_end/console/module.json
index a60af8b676d..9f04380d03b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console/module.json
@@ -37,6 +37,9 @@
{
"type": "action",
"category": "Console",
+ "contextTypes": [
+ "Console.ConsoleView"
+ ],
"actionId": "console.clear",
"title": "Clear console",
"iconClass": "largeicon-clear",
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js b/chromium/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js
index b51e2ef3c7b..b17e8aede1b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js
@@ -39,7 +39,7 @@ ConsoleCounters.WarningErrorCounter = class {
*/
_createItem(shadowRoot, iconType) {
const item = createElementWithClass('span', 'counter-item');
- const icon = item.createChild('label', '', 'dt-icon-label');
+ const icon = item.createChild('span', '', 'dt-icon-label');
icon.type = iconType;
const text = icon.createChild('span');
shadowRoot.appendChild(item);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css b/chromium/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css
index d6ad447d8fe..ee6de7a575d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css
@@ -18,10 +18,6 @@
margin-left: 6px;
}
-.counter-item label {
- cursor: inherit;
-}
-
.counter-item.counter-item-first {
margin-left: 0;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
index d4d78c8a50e..451be307465 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
@@ -29,8 +29,10 @@ ConsoleTestRunner.dumpConsoleMessages = function(printOriginatingCommand, dumpCl
ConsoleTestRunner.dumpConsoleMessagesIntoArray = function(printOriginatingCommand, dumpClassNames, formatter) {
formatter = formatter || ConsoleTestRunner.prepareConsoleMessageText;
const result = [];
- ConsoleTestRunner.disableConsoleViewport();
const consoleView = Console.ConsoleView.instance();
+ const originalViewportStyle = consoleView._viewport.element.style;
+ const originalSize = {width: originalViewportStyle.width, height: originalViewportStyle.height};
+ ConsoleTestRunner.disableConsoleViewport();
if (consoleView._needsFullUpdate)
consoleView._updateMessageList();
const viewMessages = consoleView._visibleViewMessages;
@@ -72,6 +74,8 @@ ConsoleTestRunner.dumpConsoleMessagesIntoArray = function(printOriginatingComman
if (printOriginatingCommand && uiMessage.consoleMessage().originatingMessage())
result.push('Originating from: ' + uiMessage.consoleMessage().originatingMessage().messageText);
}
+ consoleView._viewport.element.style.width = originalSize.width;
+ consoleView._viewport.element.style.height = originalSize.height;
return result;
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/cookie_table/CookiesTable.js b/chromium/third_party/blink/renderer/devtools/front_end/cookie_table/CookiesTable.js
index 051561f18b1..cee144fbd5d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/cookie_table/CookiesTable.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/cookie_table/CookiesTable.js
@@ -349,12 +349,16 @@ CookieTable.CookiesTable = class extends UI.VBox {
} else {
data.domain = cookie.domain() || '';
data.path = cookie.path() || '';
- if (cookie.maxAge())
+ if (cookie.maxAge()) {
data.expires = Number.secondsToString(parseInt(cookie.maxAge(), 10));
- else if (cookie.expires())
- data.expires = new Date(cookie.expires()).toISOString();
- else
+ } else if (cookie.expires()) {
+ if (cookie.expires() < 0)
+ data.expires = 'N/A';
+ else
+ data.expires = new Date(cookie.expires()).toISOString();
+ } else {
data.expires = CookieTable.CookiesTable._expiresSessionValue;
+ }
}
data.size = cookie.size();
const checkmark = '\u2713';
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js b/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js
index ff58087041f..a76a687d523 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageModel.js
@@ -274,6 +274,65 @@ Coverage.CoverageModel = class extends SDK.SDKModel {
urlCoverage._usedSize += coverageInfo._usedSize - oldUsedSize;
return coverageInfo;
}
+
+ /**
+ * @param {!Bindings.FileOutputStream} fos
+ */
+ async exportReport(fos) {
+ const result = [];
+ for (const urlInfo of this._coverageByURL.values()) {
+ const url = urlInfo.url();
+ if (url.startsWith('extensions::') || url.startsWith('chrome-extension://'))
+ continue;
+
+ // For .html resources, multiple scripts share URL, but have different offsets.
+ let useFullText = false;
+ for (const info of urlInfo._coverageInfoByLocation.values()) {
+ if (info._lineOffset || info._columnOffset) {
+ useFullText = !!url;
+ break;
+ }
+ }
+
+ let fullText = null;
+ if (useFullText) {
+ const resource = SDK.ResourceTreeModel.resourceForURL(url);
+ fullText = resource ? new TextUtils.Text(await resource.requestContent()) : null;
+ }
+
+ // We have full text for this resource, resolve the offsets using the text line endings.
+ if (fullText) {
+ const entry = {url, ranges: [], text: fullText.value()};
+ for (const info of urlInfo._coverageInfoByLocation.values()) {
+ const offset = fullText ? fullText.offsetFromPosition(info._lineOffset, info._columnOffset) : 0;
+ let start = 0;
+ for (const segment of info._segments) {
+ if (segment.count)
+ entry.ranges.push({start: start + offset, end: segment.end + offset});
+ else
+ start = segment.end;
+ }
+ }
+ result.push(entry);
+ continue;
+ }
+
+ // Fall back to the per-script operation.
+ for (const info of urlInfo._coverageInfoByLocation.values()) {
+ const entry = {url, ranges: [], text: await info.contentProvider().requestContent()};
+ let start = 0;
+ for (const segment of info._segments) {
+ if (segment.count)
+ entry.ranges.push({start: start, end: segment.end});
+ else
+ start = segment.end;
+ }
+ result.push(entry);
+ }
+ }
+ await fos.write(JSON.stringify(result, undefined, 2));
+ fos.close();
+ }
};
Coverage.URLCoverageInfo = class {
@@ -357,7 +416,7 @@ Coverage.URLCoverageInfo = class {
if ((type & Coverage.CoverageType.JavaScript) && !this._coverageInfoByLocation.size)
this._isContentScript = /** @type {!SDK.Script} */ (contentProvider).isContentScript();
- entry = new Coverage.CoverageInfo(contentProvider, contentLength, type);
+ entry = new Coverage.CoverageInfo(contentProvider, contentLength, lineOffset, columnOffset, type);
this._coverageInfoByLocation.set(key, entry);
this._size += contentLength;
@@ -369,12 +428,16 @@ Coverage.CoverageInfo = class {
/**
* @param {!Common.ContentProvider} contentProvider
* @param {number} size
+ * @param {number} lineOffset
+ * @param {number} columnOffset
* @param {!Coverage.CoverageType} type
*/
- constructor(contentProvider, size, type) {
+ constructor(contentProvider, size, lineOffset, columnOffset, type) {
this._contentProvider = contentProvider;
this._size = size;
this._usedSize = 0;
+ this._lineOffset = lineOffset;
+ this._columnOffset = columnOffset;
this._coverageType = type;
/** !Array<!Coverage.CoverageSegment> */
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js b/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
index b0367faaf2f..c4816ee2b56 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
@@ -36,9 +36,13 @@ Coverage.CoverageView = class extends UI.VBox {
this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clear.bind(this));
toolbar.appendToolbarItem(this._clearButton);
+ toolbar.appendSeparator();
+ const saveButton = new UI.ToolbarButton(Common.UIString('Export...'), 'largeicon-download');
+ saveButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._exportReport());
+ toolbar.appendToolbarItem(saveButton);
+
/** @type {?RegExp} */
this._textFilterRegExp = null;
-
toolbar.appendSeparator();
this._filterInput = new UI.ToolbarInput(Common.UIString('URL filter'), 0.4, 1);
this._filterInput.setEnabled(false);
@@ -222,6 +226,15 @@ Coverage.CoverageView = class extends UI.VBox {
return false;
return ignoreTextFilter || !this._textFilterRegExp || this._textFilterRegExp.test(url);
}
+
+ async _exportReport() {
+ const fos = new Bindings.FileOutputStream();
+ const fileName = `Coverage-${new Date().toISO8601Compact()}.json`;
+ const accepted = await fos.open(fileName);
+ if (!accepted)
+ return;
+ this._model.exportReport(fos);
+ }
};
Coverage.CoverageView._extensionBindingsURLPrefix = 'extensions::';
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
index 0757efb4d0f..c944baf9b71 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/coverage_test_runner/CoverageTestRunner.js
@@ -30,6 +30,16 @@ CoverageTestRunner.pollCoverage = function() {
};
/**
+ * @return {!Promise<string>}
+ */
+CoverageTestRunner.exportReport = async function() {
+ const coverageView = self.runtime.sharedInstance(Coverage.CoverageView);
+ let data;
+ await coverageView._model.exportReport({write: d => data = d, close: _ => 0});
+ return data;
+};
+
+/**
* @return {!Promise<!SourceFrame.SourceFrame>}
*/
CoverageTestRunner.sourceDecorated = async function(source) {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js b/chromium/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
index 79f42c2cc16..5ac6b179eef 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
@@ -592,7 +592,7 @@ DataGrid.DataGrid = class extends Common.Object {
for (let i = 0; i < children.length; ++i) {
const node = children[i];
for (let j = 0; j < this._columnsArray.length; ++j) {
- const text = node.data[this._columnsArray[j].id];
+ const text = String(node.data[this._columnsArray[j].id]);
if (text.length > widths[j])
widths[j] = text.length;
}
@@ -810,7 +810,7 @@ DataGrid.DataGrid = class extends Common.Object {
* @param {!Event} event
*/
_keyDown(event) {
- if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing)
+ if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing || UI.isEditing())
return;
let handled = false;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/devices/devicesView.css b/chromium/third_party/blink/renderer/devtools/front_end/devices/devicesView.css
index 6836381b5fa..60421188719 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/devices/devicesView.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/devices/devicesView.css
@@ -14,14 +14,15 @@
display: flex;
flex-direction: column;
align-items: stretch;
- padding-top: 15px;
+ margin: 15px 10px 0 0;
}
.devices-sidebar-list {
- flex: none;
+ flex: auto;
display: flex;
flex-direction: column;
align-items: stretch;
+ overflow: auto;
}
.devices-sidebar-item {
@@ -32,6 +33,7 @@
flex-direction: column;
justify-content: center;
font-size: 14px;
+ flex: none;
}
.devices-sidebar-item.selected {
@@ -60,6 +62,7 @@
font-size: 16px;
margin: 0 0 15px 15px;
padding-top: 1px;
+ flex: none;
}
.view-title {
@@ -266,6 +269,7 @@
overflow: auto;
-webkit-user-select: text;
flex: auto;
+ padding-top: 15px;
}
.device-text-row {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js b/chromium/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js
index 1319616f3ac..010108b9903 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/devtools_compatibility.js
@@ -320,35 +320,31 @@
*/
const InspectorFrontendHostImpl = class {
/**
- * @override
* @return {string}
*/
getSelectionBackgroundColor() {
- return DevToolsHost.getSelectionBackgroundColor();
+ return '#6e86ff';
}
/**
- * @override
* @return {string}
*/
getSelectionForegroundColor() {
- return DevToolsHost.getSelectionForegroundColor();
+ return '#ffffff';
}
/**
- * @override
* @return {string}
*/
getInactiveSelectionBackgroundColor() {
- return DevToolsHost.getInactiveSelectionBackgroundColor();
+ return '#c9c8c8';
}
/**
- * @override
* @return {string}
*/
getInactiveSelectionForegroundColor() {
- return DevToolsHost.getInactiveSelectionForegroundColor();
+ return '#323232';
}
/**
@@ -1172,6 +1168,108 @@
/** @type {!Array<string>} */
const styleRules = [];
+ // Shadow DOM V0 polyfill
+ if (majorVersion <= 73 && !Element.prototype.createShadowRoot) {
+ Element.prototype.createShadowRoot = function() {
+ try {
+ return this.attachShadow({mode: 'open'});
+ } catch (e) {
+ // some elements we use to add shadow roots can no
+ // longer have shadow roots.
+ const fakeShadowHost = document.createElement('span');
+ this.appendChild(fakeShadowHost);
+ fakeShadowHost.className = 'fake-shadow-host';
+ return fakeShadowHost.createShadowRoot();
+ }
+ };
+
+ const origAdd = DOMTokenList.prototype.add;
+ DOMTokenList.prototype.add = function(...tokens) {
+ if (tokens[0].startsWith('insertion-point') || tokens[0].startsWith('tabbed-pane-header'))
+ this._myElement.slot = '.' + tokens[0];
+ return origAdd.apply(this, tokens);
+ };
+
+ const origCreateElement = Document.prototype.createElement;
+ Document.prototype.createElement = function(tagName, ...rest) {
+ if (tagName === 'content')
+ tagName = 'slot';
+ const element = origCreateElement.call(this, tagName, ...rest);
+ element.classList._myElement = element;
+ return element;
+ };
+
+ Object.defineProperty(HTMLSlotElement.prototype, 'select', {
+ async set(selector) {
+ this.name = selector;
+ }
+ });
+
+ // Document.prototype.createElementWithClass is a DevTools method, so we
+ // need to wait for DOMContentLoaded in order to override it.
+ if (window.document.head &&
+ (window.document.readyState === 'complete' || window.document.readyState === 'interactive'))
+ overrideCreateElementWithClass();
+ else
+ window.addEventListener('DOMContentLoaded', overrideCreateElementWithClass);
+
+ function overrideCreateElementWithClass() {
+ window.removeEventListener('DOMContentLoaded', overrideCreateElementWithClass);
+
+ const origCreateElementWithClass = Document.prototype.createElementWithClass;
+ Document.prototype.createElementWithClass = function(tagName, className, ...rest) {
+ if (tagName !== 'button' || (className !== 'soft-dropdown' && className !== 'dropdown-button'))
+ return origCreateElementWithClass.call(this, tagName, className, ...rest);
+ const element = origCreateElementWithClass.call(this, 'div', className, ...rest);
+ element.tabIndex = 0;
+ element.role = 'button';
+ return element;
+ };
+ }
+ }
+
+ // Custom Elements V0 polyfill
+ if (majorVersion <= 73 && !Document.prototype.registerElement) {
+ const fakeRegistry = new Map();
+ Document.prototype.registerElement = function(typeExtension, options) {
+ const {prototype, extends: localName} = options;
+ const document = this;
+ const callback = function() {
+ const element = document.createElement(localName || typeExtension);
+ const skip = new Set(['constructor', '__proto__']);
+ for (const key of Object.keys(Object.getOwnPropertyDescriptors(prototype.__proto__ || {}))) {
+ if (skip.has(key))
+ continue;
+ element[key] = prototype[key];
+ }
+ element.setAttribute('is', typeExtension);
+ if (element['createdCallback'])
+ element['createdCallback']();
+ return element;
+ };
+ fakeRegistry.set(typeExtension, callback);
+ return callback;
+ };
+
+ const origCreateElement = Document.prototype.createElement;
+ Document.prototype.createElement = function(tagName, fakeCustomElementType) {
+ const fakeConstructor = fakeRegistry.get(fakeCustomElementType);
+ if (fakeConstructor)
+ return fakeConstructor();
+ return origCreateElement.call(this, tagName, fakeCustomElementType);
+ };
+
+ // DevTools front-ends mistakenly assume that
+ // classList.toggle('a', undefined) works as
+ // classList.toggle('a', false) rather than as
+ // classList.toggle('a');
+ const originalDOMTokenListToggle = DOMTokenList.prototype.toggle;
+ DOMTokenList.prototype.toggle = function(token, force) {
+ if (arguments.length === 1)
+ force = !this.contains(token);
+ return originalDOMTokenListToggle.call(this, token, !!force);
+ };
+ }
if (majorVersion <= 66) {
/** @type {(!function(number, number):Element|undefined)} */
@@ -1313,32 +1411,6 @@
return style;
}
- function windowLoaded() {
- window.removeEventListener('DOMContentLoaded', windowLoaded, false);
- installBackwardsCompatibility();
- }
-
- if (window.document.head &&
- (window.document.readyState === 'complete' || window.document.readyState === 'interactive'))
- installBackwardsCompatibility();
- else
- window.addEventListener('DOMContentLoaded', windowLoaded, false);
-
- /** @type {(!function(string, boolean=):boolean)|undefined} */
- DOMTokenList.prototype.__originalDOMTokenListToggle;
-
- if (!DOMTokenList.prototype.__originalDOMTokenListToggle) {
- DOMTokenList.prototype.__originalDOMTokenListToggle = DOMTokenList.prototype.toggle;
- /**
- * @param {string} token
- * @param {boolean=} force
- * @return {boolean}
- */
- DOMTokenList.prototype.toggle = function(token, force) {
- if (arguments.length === 1)
- force = !this.contains(token);
- return this.__originalDOMTokenListToggle(token, !!force);
- };
- }
+ installBackwardsCompatibility();
})(window);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js b/chromium/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js
index baa287994cd..708adc2dd85 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js
@@ -270,10 +270,12 @@ Node.prototype.getComponentSelection = function() {
*/
Node.prototype.hasSelection = function() {
// TODO(luoe): use contains(node, {includeShadow: true}) when it is fixed for shadow dom.
- const contents = this.querySelectorAll('content');
- for (const content of contents) {
- if (Array.prototype.some.call(content.getDistributedNodes(), node => node.hasSelection()))
- return true;
+ if (this instanceof Element) {
+ const slots = this.querySelectorAll('slot');
+ for (const slot of slots) {
+ if (Array.prototype.some.call(slot.assignedNodes(), node => node.hasSelection()))
+ return true;
+ }
}
const selection = this.getComponentSelection();
@@ -299,10 +301,11 @@ Element.prototype.removeChildren = function() {
* @param {string} tagName
* @param {string=} customElementType
* @return {!Element}
+ * @suppress {checkTypes}
* @suppressGlobalPropertiesCheck
*/
function createElement(tagName, customElementType) {
- return document.createElement(tagName, customElementType || '');
+ return document.createElement(tagName, {is: customElementType});
}
/**
@@ -318,10 +321,11 @@ function createTextNode(data) {
* @param {string} elementName
* @param {string=} className
* @param {string=} customElementType
+ * @suppress {checkTypes}
* @return {!Element}
*/
Document.prototype.createElementWithClass = function(elementName, className, customElementType) {
- const element = this.createElement(elementName, customElementType || '');
+ const element = this.createElement(elementName, {is: customElementType});
if (className)
element.className = className;
return element;
@@ -651,7 +655,7 @@ Node.prototype.traverseNextNode = function(stayWithin) {
if (this.shadowRoot)
return this.shadowRoot;
- const distributedNodes = this.getDistributedNodes ? this.getDistributedNodes() : [];
+ const distributedNodes = this instanceof HTMLSlotElement ? this.assignedNodes() : [];
if (distributedNodes.length)
return distributedNodes[0];
@@ -668,7 +672,7 @@ Node.prototype.traverseNextNode = function(stayWithin) {
if (sibling)
return sibling;
- node = insertionPoint(node) || node.parentNodeOrShadowHost();
+ node = node.assignedSlot || node.parentNodeOrShadowHost();
}
/**
@@ -676,10 +680,9 @@ Node.prototype.traverseNextNode = function(stayWithin) {
* @return {?Node}
*/
function nextSibling(node) {
- const parent = insertionPoint(node);
- if (!parent)
+ if (!node.assignedSlot)
return node.nextSibling;
- const distributedNodes = parent.getDistributedNodes ? parent.getDistributedNodes() : [];
+ const distributedNodes = node.assignedSlot.assignedNodes();
const position = Array.prototype.indexOf.call(distributedNodes, node);
if (position + 1 < distributedNodes.length)
@@ -687,15 +690,6 @@ Node.prototype.traverseNextNode = function(stayWithin) {
return null;
}
- /**
- * @param {!Node} node
- * @return {?Node}
- */
- function insertionPoint(node) {
- const insertionPoints = node.getDestinationInsertionPoints ? node.getDestinationInsertionPoints() : [];
- return insertionPoints.length > 0 ? insertionPoints[insertionPoints.length - 1] : null;
- }
-
return null;
};
@@ -811,3 +805,16 @@ function isEnterKey(event) {
function isEscKey(event) {
return event.keyCode === 27;
}
+
+// DevTools front-end still assumes that
+// classList.toggle('a', undefined) works as
+// classList.toggle('a', false) rather than as
+// classList.toggle('a');
+(function() {
+const originalToggle = DOMTokenList.prototype.toggle;
+DOMTokenList.prototype['toggle'] = function(token, force) {
+ if (arguments.length === 1)
+ force = !this.contains(token);
+ return originalToggle.call(this, token, !!force);
+};
+})();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/ColorSwatchPopoverIcon.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/ColorSwatchPopoverIcon.js
index 5f43629f47f..c2bb78b4c3c 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/ColorSwatchPopoverIcon.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/ColorSwatchPopoverIcon.js
@@ -143,12 +143,10 @@ Elements.ColorSwatchPopoverIcon = class {
}
/**
- * @param {?SDK.CSSModel.ContrastInfo} contrastInfo
+ * @param {!ColorPicker.ContrastInfo} contrastInfo
*/
setContrastInfo(contrastInfo) {
this._contrastInfo = contrastInfo;
- if (this._spectrum)
- this._spectrum.setContrastInfo(contrastInfo);
}
/**
@@ -169,11 +167,9 @@ Elements.ColorSwatchPopoverIcon = class {
let format = this._swatch.format();
if (format === Common.Color.Format.Original)
format = color.format();
- this._spectrum = new ColorPicker.Spectrum();
+ this._spectrum = new ColorPicker.Spectrum(this._contrastInfo);
this._spectrum.setColor(color, format);
this._spectrum.addPalette(this._generateCSSVariablesPalette());
- if (this._contrastInfo)
- this._spectrum.setContrastInfo(this._contrastInfo);
this._spectrum.addEventListener(ColorPicker.Spectrum.Events.SizeChanged, this._spectrumResized, this);
this._spectrum.addEventListener(ColorPicker.Spectrum.Events.ColorChanged, this._boundSpectrumChanged);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/DOMLinkifier.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/DOMLinkifier.js
index b6d3cc56106..c62906af703 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/DOMLinkifier.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/DOMLinkifier.js
@@ -75,7 +75,7 @@ Elements.DOMLinkifier.linkifyNodeReference = function(node, tooltipContent) {
Elements.DOMLinkifier.decorateNodeLabel(node, link, tooltipContent);
link.addEventListener('click', () => Common.Revealer.reveal(node, false) && false, false);
- link.addEventListener('mouseover', node.highlight.bind(node, undefined, undefined), false);
+ link.addEventListener('mouseover', node.highlight.bind(node, undefined), false);
link.addEventListener('mouseleave', () => SDK.OverlayModel.hideDOMNodeHighlight(), false);
return root;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js
index c29c85c3a99..bee736bcc9a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js
@@ -271,6 +271,7 @@ Elements.ElementsPanel = class extends UI.Panel {
if (this._popoverHelper)
this._popoverHelper.hidePopover();
super.willHide();
+ UI.context.setFlavor(Elements.ElementsPanel, null);
}
/**
@@ -647,16 +648,15 @@ Elements.ElementsPanel = class extends UI.Panel {
/**
* @param {!SDK.DOMNode} node
* @param {boolean} focus
+ * @param {boolean=} omitHighlight
* @return {!Promise}
*/
- revealAndSelectNode(node, focus) {
- if (Elements.inspectElementModeController && Elements.inspectElementModeController.isInInspectElementMode())
- Elements.inspectElementModeController.stopInspection();
-
+ revealAndSelectNode(node, focus, omitHighlight) {
this._omitDefaultSelection = true;
node = Common.moduleSetting('showUAShadowDOM').get() ? node : this._leaveUserAgentShadowDOM(node);
- node.highlightForTwoSeconds();
+ if (!omitHighlight)
+ node.highlightForTwoSeconds();
return UI.viewManager.showView('elements', false, !focus).then(() => {
this.selectDOMNode(node, focus);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js
index 5676b094e64..1f76f3d0341 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js
@@ -5,8 +5,11 @@
* @unrestricted
*/
Elements.ElementsSidebarPane = class extends UI.VBox {
- constructor() {
- super(true);
+ /**
+ * @param {boolean=} delegatesFocus
+ */
+ constructor(delegatesFocus) {
+ super(true, delegatesFocus);
this.element.classList.add('flex-none');
this._computedStyleModel = new Elements.ComputedStyleModel();
this._computedStyleModel.addEventListener(
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeElement.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeElement.js
index be96605f59d..4ead19d47b1 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeElement.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeElement.js
@@ -338,8 +338,10 @@ Elements.ElementsTreeElement = class extends UI.TreeElement {
onselect(selectedByUser) {
this.treeOutline.suppressRevealAndSelect = true;
this.treeOutline.selectDOMNode(this._node, selectedByUser);
- if (selectedByUser)
+ if (selectedByUser) {
+ this._node.highlight();
Host.userMetrics.actionTaken(Host.UserMetrics.Action.ChangeInspectedNodeInElementsPanel);
+ }
this._createSelection();
this._createHint();
this.treeOutline.suppressRevealAndSelect = false;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
index 083d3089f1c..215f897f63d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
@@ -50,7 +50,6 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
if (hideGutter)
this._element.classList.add('elements-hide-gutter');
UI.ARIAUtils.setAccessibleName(this._element, Common.UIString('Page DOM'));
- this._element.addEventListener('focusin', this._onfocusin.bind(this), false);
this._element.addEventListener('focusout', this._onfocusout.bind(this), false);
this._element.addEventListener('mousedown', this._onmousedown.bind(this), false);
this._element.addEventListener('mousemove', this._onmousemove.bind(this), false);
@@ -90,6 +89,7 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
this._showHTMLCommentsSetting = Common.moduleSetting('showHTMLComments');
this._showHTMLCommentsSetting.addChangeListener(this._onShowHTMLCommentsChange.bind(this));
+ this.useLightSelectionColor();
}
/**
@@ -291,6 +291,8 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
* @param {boolean} visible
*/
setVisible(visible) {
+ if (visible === this._visible)
+ return;
this._visible = visible;
if (!this._visible) {
this._popoverHelper.hidePopover();
@@ -441,9 +443,13 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
// Walk down to populate each ancestor's children, to fill in the tree and the cache.
for (let i = ancestors.length - 1; i >= 0; --i) {
+ const child = ancestors[i - 1] || node;
const treeElement = ancestors[i][this._treeElementSymbol];
- if (treeElement)
+ if (treeElement) {
treeElement.onpopulate(); // fill the cache with the children of treeElement
+ if (child.index >= treeElement.expandedChildrenLimit())
+ this.setExpandedChildrenLimit(treeElement, child.index + 1);
+ }
}
return node[this._treeElementSymbol];
@@ -546,17 +552,6 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
/**
* @param {!Event} event
*/
- _onfocusin(event) {
- const listItem = event.target.enclosingNodeOrSelfWithNodeName('li');
- if (!listItem || !listItem.treeElement || !listItem.treeElement.selected)
- return;
- if (event.relatedTarget)
- this._highlightTreeElement(/** @type {!UI.TreeElement} */ (listItem.treeElement), true /* showInfo */);
- }
-
- /**
- * @param {!Event} event
- */
_onfocusout(event) {
SDK.OverlayModel.hideDOMNodeHighlight();
}
@@ -568,6 +563,7 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
return;
element.select();
+ event.consume(true);
}
/**
@@ -604,14 +600,12 @@ Elements.ElementsTreeOutline = class extends UI.TreeOutline {
*/
_highlightTreeElement(element, showInfo) {
if (element instanceof Elements.ElementsTreeElement) {
- element.node().domModel().overlayModel().highlightDOMNodeWithConfig(element.node().id, {mode: 'all', showInfo});
+ element.node().domModel().overlayModel().highlightInOverlay({node: element.node()}, 'all', showInfo);
return;
}
- if (element instanceof Elements.ElementsTreeOutline.ShortcutTreeElement) {
- element.domModel().overlayModel().highlightDOMNodeWithConfig(
- undefined, {mode: 'all', showInfo}, element.backendNodeId());
- }
+ if (element instanceof Elements.ElementsTreeOutline.ShortcutTreeElement)
+ element.domModel().overlayModel().highlightInOverlay({deferredNode: element.deferredNode()}, 'all', showInfo);
}
_onmouseleave(event) {
@@ -1647,10 +1641,10 @@ Elements.ElementsTreeOutline.ShortcutTreeElement = class extends UI.TreeElement
}
/**
- * @return {number}
+ * @return {!SDK.DeferredDOMNode}
*/
- backendNodeId() {
- return this._nodeShortcut.deferredNode.backendNodeId();
+ deferredNode() {
+ return this._nodeShortcut.deferredNode;
}
/**
@@ -1668,6 +1662,7 @@ Elements.ElementsTreeOutline.ShortcutTreeElement = class extends UI.TreeElement
onselect(selectedByUser) {
if (!selectedByUser)
return true;
+ this._nodeShortcut.deferredNode.highlight();
this._nodeShortcut.deferredNode.resolve(resolved.bind(this));
/**
* @param {?SDK.DOMNode} node
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/InspectElementModeController.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/InspectElementModeController.js
index 7cbbe075fc9..92dcee92eca 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/InspectElementModeController.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/InspectElementModeController.js
@@ -30,14 +30,27 @@
* @unrestricted
*/
Elements.InspectElementModeController = class {
+ /**
+ * @suppressGlobalPropertiesCheck
+ */
constructor() {
this._toggleSearchAction = UI.actionRegistry.action('elements.toggle-element-search');
this._mode = Protocol.Overlay.InspectMode.None;
SDK.targetManager.addEventListener(SDK.TargetManager.Events.SuspendStateChanged, this._suspendStateChanged, this);
SDK.targetManager.addModelListener(
- SDK.OverlayModel, SDK.OverlayModel.Events.ScreenshotRequested,
+ SDK.OverlayModel, SDK.OverlayModel.Events.ExitedInspectMode,
() => this._setMode(Protocol.Overlay.InspectMode.None));
+ SDK.OverlayModel.setInspectNodeHandler(this._inspectNode.bind(this));
SDK.targetManager.observeModels(SDK.OverlayModel, this);
+
+ document.addEventListener('keydown', event => {
+ if (event.keyCode !== UI.KeyboardShortcut.Keys.Esc.code)
+ return;
+ if (!this._isInInspectElementMode())
+ return;
+ this._setMode(Protocol.Overlay.InspectMode.None);
+ event.consume(true);
+ }, true);
}
/**
@@ -62,39 +75,35 @@ Elements.InspectElementModeController = class {
/**
* @return {boolean}
*/
- isInInspectElementMode() {
- return this._mode === Protocol.Overlay.InspectMode.SearchForNode ||
- this._mode === Protocol.Overlay.InspectMode.SearchForUAShadowDOM;
- }
-
- stopInspection() {
- if (this._mode && this._mode !== Protocol.Overlay.InspectMode.None)
- this._toggleInspectMode();
+ _isInInspectElementMode() {
+ return this._mode !== Protocol.Overlay.InspectMode.None;
}
_toggleInspectMode() {
- if (SDK.targetManager.allTargetsSuspended())
- return;
-
let mode;
- if (this.isInInspectElementMode()) {
+ if (this._isInInspectElementMode()) {
mode = Protocol.Overlay.InspectMode.None;
} else {
mode = Common.moduleSetting('showUAShadowDOM').get() ? Protocol.Overlay.InspectMode.SearchForUAShadowDOM :
Protocol.Overlay.InspectMode.SearchForNode;
}
-
this._setMode(mode);
}
+ _captureScreenshotMode() {
+ this._setMode(Protocol.Overlay.InspectMode.CaptureAreaScreenshot);
+ }
+
/**
* @param {!Protocol.Overlay.InspectMode} mode
*/
_setMode(mode) {
+ if (SDK.targetManager.allTargetsSuspended())
+ return;
this._mode = mode;
for (const overlayModel of SDK.targetManager.models(SDK.OverlayModel))
overlayModel.setInspectMode(mode);
- this._toggleSearchAction.setToggled(this.isInInspectElementMode());
+ this._toggleSearchAction.setToggled(this._isInInspectElementMode());
}
_suspendStateChanged() {
@@ -104,6 +113,13 @@ Elements.InspectElementModeController = class {
this._mode = Protocol.Overlay.InspectMode.None;
this._toggleSearchAction.setToggled(false);
}
+
+ /**
+ * @param {!SDK.DOMNode} node
+ */
+ async _inspectNode(node) {
+ Elements.ElementsPanel.instance().revealAndSelectNode(node, true, true);
+ }
};
/**
@@ -120,7 +136,10 @@ Elements.InspectElementModeController.ToggleSearchActionDelegate = class {
handleAction(context, actionId) {
if (!Elements.inspectElementModeController)
return false;
- Elements.inspectElementModeController._toggleInspectMode();
+ if (actionId === 'elements.toggle-element-search')
+ Elements.inspectElementModeController._toggleInspectMode();
+ else if (actionId === 'elements.capture-area-screenshot')
+ Elements.inspectElementModeController._captureScreenshotMode();
return true;
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/StylePropertyTreeElement.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/StylePropertyTreeElement.js
index 29a567d7ce5..fc355e8cda1 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/StylePropertyTreeElement.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/StylePropertyTreeElement.js
@@ -126,11 +126,10 @@ Elements.StylePropertyTreeElement = class extends UI.TreeElement {
return swatch;
}
- const swatchPopoverHelper = this._parentPane.swatchPopoverHelper();
const swatch = InlineEditor.ColorSwatch.create();
swatch.setColor(color);
swatch.setFormat(Common.Color.detectColorFormat(swatch.color()));
- this._addColorContrastInfo(new Elements.ColorSwatchPopoverIcon(this, swatchPopoverHelper, swatch));
+ this._addColorContrastInfo(swatch);
return swatch;
}
@@ -157,24 +156,24 @@ Elements.StylePropertyTreeElement = class extends UI.TreeElement {
return swatch;
}
- const swatchPopoverHelper = this._parentPane.swatchPopoverHelper();
const swatch = InlineEditor.ColorSwatch.create();
swatch.setColor(color);
swatch.setFormat(Common.Color.detectColorFormat(swatch.color()));
swatch.setText(text, computedValue);
- this._addColorContrastInfo(new Elements.ColorSwatchPopoverIcon(this, swatchPopoverHelper, swatch));
+ this._addColorContrastInfo(swatch);
return swatch;
}
/**
- * @param {!Elements.ColorSwatchPopoverIcon} swatchIcon
+ * @param {!InlineEditor.ColorSwatch} swatch
*/
- async _addColorContrastInfo(swatchIcon) {
- if (!Runtime.experiments.isEnabled('colorContrastRatio') || this.property.name !== 'color' ||
- !this._parentPane.cssModel() || !this.node())
+ async _addColorContrastInfo(swatch) {
+ const swatchPopoverHelper = this._parentPane.swatchPopoverHelper();
+ const swatchIcon = new Elements.ColorSwatchPopoverIcon(this, swatchPopoverHelper, swatch);
+ if (this.property.name !== 'color' || !this._parentPane.cssModel() || !this.node())
return;
const cssModel = this._parentPane.cssModel();
- const contrastInfo = await cssModel.backgroundColorsPromise(this.node().id);
+ const contrastInfo = new ColorPicker.ContrastInfo(await cssModel.backgroundColorsPromise(this.node().id));
swatchIcon.setContrastInfo(contrastInfo);
}
@@ -604,7 +603,7 @@ Elements.StylePropertyTreeElement = class extends UI.TreeElement {
this._originalPropertyText = this.property.propertyText;
- this._parentPane.setEditingStyle(true);
+ this._parentPane.setEditingStyle(true, this);
if (selectElement.parentElement)
selectElement.parentElement.scrollIntoViewIfNeeded(false);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js b/chromium/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
index c0eeb86973b..9198aa859ee 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
@@ -29,10 +29,9 @@
Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
constructor() {
- super();
+ super(true /* delegatesFocus */);
this.setMinimumSize(96, 26);
this.registerRequiredCSS('elements/stylesSidebarPane.css');
- this.element.tabIndex = -1;
Common.moduleSetting('colorFormat').addChangeListener(this.update.bind(this));
Common.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this));
@@ -64,6 +63,7 @@ Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
this._isEditingStyle = false;
/** @type {?RegExp} */
this._filterRegex = null;
+ this._isActivePropertyHighlighted = false;
this.contentElement.classList.add('styles-pane');
@@ -94,7 +94,7 @@ Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
* @return {!Element}
*/
static createExclamationMark(property) {
- const exclamationElement = createElement('label', 'dt-icon-label');
+ const exclamationElement = createElement('span', 'dt-icon-label');
exclamationElement.className = 'exclamation-mark';
if (!Elements.StylesSidebarPane.ignoreErrorsForProperty(property))
exclamationElement.type = 'smallicon-warning';
@@ -378,12 +378,40 @@ Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
/**
* @param {boolean} editing
+ * @param {!Elements.StylePropertyTreeElement=} treeElement
*/
- setEditingStyle(editing) {
+ setEditingStyle(editing, treeElement) {
if (this._isEditingStyle === editing)
return;
this.contentElement.classList.toggle('is-editing-style', editing);
this._isEditingStyle = editing;
+ this._setActiveProperty(editing ? treeElement || null : null);
+ }
+
+ /**
+ * @param {?Elements.StylePropertyTreeElement} treeElement
+ */
+ _setActiveProperty(treeElement) {
+ if (this._isActivePropertyHighlighted)
+ SDK.OverlayModel.hideDOMNodeHighlight();
+ this._isActivePropertyHighlighted = false;
+
+ if (!this.node())
+ return;
+
+ if (!treeElement || treeElement.overloaded() || treeElement.inherited())
+ return;
+
+ const rule = treeElement.property.ownerStyle.parentRule;
+ const selectorList = rule ? rule.selectorText() : undefined;
+ for (const mode of ['padding', 'border', 'margin']) {
+ if (!treeElement.name.startsWith(mode))
+ continue;
+ this.node().domModel().overlayModel().highlightInOverlay(
+ {node: /** @type {!SDK.DOMNode} */ (this.node()), selectorList}, mode);
+ this._isActivePropertyHighlighted = true;
+ break;
+ }
}
/**
@@ -628,7 +656,7 @@ Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
filterContainerElement.appendChild(filterInput);
const toolbar = new UI.Toolbar('styles-pane-toolbar', hbox);
toolbar.makeToggledGray();
- toolbar.appendLocationItems('styles-sidebarpane-toolbar');
+ toolbar.appendItemsAtLocation('styles-sidebarpane-toolbar');
const toolbarPaneContainer = container.createChild('div', 'styles-sidebar-toolbar-pane-container');
const toolbarPaneContent = toolbarPaneContainer.createChild('div', 'styles-sidebar-toolbar-pane');
@@ -813,6 +841,7 @@ Elements.StylePropertiesSection = class {
this._selectorElement.textContent = this._headerText();
selectorContainer.appendChild(this._selectorElement);
this._selectorElement.addEventListener('mouseenter', this._onMouseEnterSelector.bind(this), false);
+ this._selectorElement.addEventListener('mousemove', event => event.consume(), false);
this._selectorElement.addEventListener('mouseleave', this._onMouseOutSelector.bind(this), false);
const openBrace = createElement('span');
@@ -830,7 +859,7 @@ Elements.StylePropertiesSection = class {
this.element.addEventListener('mousedown', this._handleEmptySpaceMouseDown.bind(this), false);
this.element.addEventListener('click', this._handleEmptySpaceClick.bind(this), false);
this.element.addEventListener('mousemove', this._onMouseMove.bind(this), false);
- this.element.addEventListener('mouseleave', this._setSectionHovered.bind(this, false), false);
+ this.element.addEventListener('mouseleave', this._onMouseLeave.bind(this), false);
if (rule) {
// Prevent editing the user agent and user rules.
@@ -956,9 +985,23 @@ Elements.StylePropertiesSection = class {
/**
* @param {!Event} event
*/
+ _onMouseLeave(event) {
+ this._setSectionHovered(false);
+ this._parentPane._setActiveProperty(null);
+ }
+
+ /**
+ * @param {!Event} event
+ */
_onMouseMove(event) {
const hasCtrlOrMeta = UI.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */ (event));
this._setSectionHovered(hasCtrlOrMeta);
+
+ const treeElement = this.propertiesTreeOutline.treeElementFromEvent(event);
+ if (treeElement instanceof Elements.StylePropertyTreeElement)
+ this._parentPane._setActiveProperty(/** @type {!Elements.StylePropertyTreeElement} */ (treeElement));
+ else
+ this._parentPane._setActiveProperty(null);
}
/**
@@ -1054,14 +1097,16 @@ Elements.StylePropertiesSection = class {
this._hoverTimer = setTimeout(this._highlight.bind(this), 300);
}
- _highlight() {
+ /**
+ * @param {string=} mode
+ */
+ _highlight(mode = 'all') {
SDK.OverlayModel.hideDOMNodeHighlight();
const node = this._parentPane.node();
if (!node)
return;
- const selectors = this._style.parentRule ? this._style.parentRule.selectorText() : undefined;
- node.domModel().overlayModel().highlightDOMNodeWithConfig(
- node.id, {mode: 'all', showInfo: undefined, selectors: selectors});
+ const selectorList = this._style.parentRule ? this._style.parentRule.selectorText() : undefined;
+ node.domModel().overlayModel().highlightInOverlay({node, selectorList}, mode);
}
/**
@@ -1331,6 +1376,7 @@ Elements.StylePropertiesSection = class {
}
onpopulate() {
+ this._parentPane._setActiveProperty(null);
this.propertiesTreeOutline.removeChildren();
const style = this._style;
let count = 0;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css b/chromium/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css
index ee810fec593..01aec132f31 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css
@@ -16,7 +16,7 @@
justify-content: flex-start;
}
-.styles-element-classes-pane label {
+.styles-element-classes-pane [is=dt-checkbox] {
margin-right: 15px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css b/chromium/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css
index 775a2cc3144..31e1a8fe6d7 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/elementsTreeOutline.css
@@ -36,11 +36,6 @@
.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected .selected-hint:before {
opacity: 0.6;
- color: var(--selection-inactive-fg-color);
-}
-
-.elements-disclosure li.selected:focus .selected-hint:before {
- color: var(--selection-fg-color);
}
.elements-disclosure li.parent::before {
@@ -94,12 +89,13 @@
}
.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) .selection {
- background-color: var(--selection-inactive-bg-color);
+ background-color: var(--editor-selection-inactive-bg-color);
}
-.elements-disclosure .elements-tree-outline.hide-selection-when-blurred li.selected:focus[data-keyboard-focus="true"] .selection {
- background: rgba(0, 0, 0, 0.08);
+.elements-disclosure .elements-tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] .highlight > * {
+ background: var(--focus-bg-color);
border-radius: 2px;
+ box-shadow: 0px 0px 0px 2px var(--focus-bg-color);
}
.elements-disclosure ol {
@@ -130,20 +126,8 @@
padding-left: 2px;
}
-.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus {
- color: var(--selection-fg-color);
-}
-
-.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.parent.selected:focus::before {
- background-color: var(--selection-fg-color);
-}
-
-.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus * {
- color: inherit;
-}
-
.elements-disclosure .elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .selection {
- background-color: var(--selection-bg-color);
+ background-color: var(--editor-selection-bg-color);
}
.elements-tree-outline ol.shadow-root-depth-4 {
@@ -307,13 +291,6 @@ ol:hover > li > .elements-tree-shortcut-link {
display: none;
}
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .webkit-html-tag-name,
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .webkit-html-close-tag-name,
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .webkit-html-attribute-value,
-.elements-tree-outline:not(.hide-selection-when-blurred) li.selected:focus .devtools-link {
- color: var(--selection-fg-color);
-}
-
.elements-disclosure .gutter-container {
position: absolute;
top: 0;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/metricsSidebarPane.css b/chromium/third_party/blink/renderer/devtools/front_end/elements/metricsSidebarPane.css
index 9f9266b58a0..5453f9d624f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/metricsSidebarPane.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/metricsSidebarPane.css
@@ -53,7 +53,7 @@
display: inline-block;
text-align: center;
vertical-align: middle;
- padding: 3px;
+ padding: 3px 6px;
margin: 3px;
}
@@ -63,7 +63,7 @@
display: inline-block;
text-align: center;
vertical-align: middle;
- padding: 3px;
+ padding: 3px 6px;
margin: 3px;
}
@@ -73,7 +73,7 @@
display: inline-block;
text-align: center;
vertical-align: middle;
- padding: 3px;
+ padding: 3px 6px;
margin: 3px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements/module.json b/chromium/third_party/blink/renderer/devtools/front_end/elements/module.json
index d4996e0def5..381e09c62ad 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements/module.json
@@ -257,6 +257,13 @@
]
},
{
+ "type": "action",
+ "actionId": "elements.capture-area-screenshot",
+ "className": "Elements.InspectElementModeController.ToggleSearchActionDelegate",
+ "title": "Capture area screenshot",
+ "category": "Screenshot"
+ },
+ {
"type": "@UI.ToolbarItem.Provider",
"actionId": "elements.toggle-element-search",
"location": "main-toolbar-left",
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/elements_test_runner/ElementsTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/elements_test_runner/ElementsTestRunner.js
index 7195398b961..c6601860105 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/elements_test_runner/ElementsTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/elements_test_runner/ElementsTestRunner.js
@@ -613,8 +613,8 @@ ElementsTestRunner.dumpStyleTreeOutline = function(treeItem, depth) {
};
ElementsTestRunner.dumpStyleTreeItem = function(treeItem, prefix, depth) {
- if (treeItem.listItemElement.textContent.indexOf(' width:') !== -1 ||
- treeItem.listItemElement.textContent.indexOf(' height:') !== -1)
+ const textContent = TestRunner.textContentWithoutStyles(treeItem.listItemElement);
+ if (textContent.indexOf(' width:') !== -1 || textContent.indexOf(' height:') !== -1)
return;
if (treeItem.listItemElement.classList.contains('inherited'))
@@ -630,7 +630,6 @@ ElementsTestRunner.dumpStyleTreeItem = function(treeItem, prefix, depth) {
if (treeItem.listItemElement.classList.contains('disabled'))
typePrefix += '/-- disabled --/ ';
- const textContent = treeItem.listItemElement.textContent;
TestRunner.addResult(prefix + typePrefix + textContent);
if (--depth) {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js b/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
index e77cf263785..144a61b6a7a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
@@ -74,7 +74,7 @@ Emulation.DeviceModeView = class extends UI.VBox {
this._bottomResizerElement.title = Common.UIString('Double-click for full height');
this._pageArea = this._screenArea.createChild('div', 'device-mode-page-area');
- this._pageArea.createChild('content');
+ this._pageArea.createChild('slot');
}
_populatePresetsContainer() {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeWrapper.js b/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeWrapper.js
index f125997ac0c..742d0e13363 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeWrapper.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeWrapper.js
@@ -118,6 +118,12 @@ Emulation.DeviceModeWrapper.ActionDelegate = class {
});
});
const clip = /** @type {!Protocol.Page.Viewport} */ (JSON.parse(result.object.value));
+ const response = await node.domModel().target().pageAgent().invoke_getLayoutMetrics({});
+ const page_zoom = !response[Protocol.Error] && response.visualViewport.zoom || 1;
+ clip.x *= page_zoom;
+ clip.y *= page_zoom;
+ clip.width *= page_zoom;
+ clip.height *= page_zoom;
Emulation.DeviceModeView._wrapperInstance._captureScreenshot(false, clip);
}
captureClip();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/GeolocationsSettingsTab.js b/chromium/third_party/blink/renderer/devtools/front_end/emulation/GeolocationsSettingsTab.js
new file mode 100644
index 00000000000..5cae4d289ed
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/GeolocationsSettingsTab.js
@@ -0,0 +1,188 @@
+// 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.
+
+/**
+ * @implements {UI.ListWidget.Delegate}
+ * @unrestricted
+ */
+Emulation.GeolocationsSettingsTab = class extends UI.VBox {
+ constructor() {
+ super(true);
+ this.registerRequiredCSS('emulation/geolocationsSettingsTab.css');
+
+ this.contentElement.createChild('div', 'header').textContent = Common.UIString('Custom Geolocations');
+
+ const addButton = UI.createTextButton(
+ Common.UIString('Add location...'), this._addButtonClicked.bind(this), 'add-geolocations-button');
+ this.contentElement.appendChild(addButton);
+
+ this._list = new UI.ListWidget(this);
+ this._list.element.classList.add('geolocations-list');
+ this._list.registerRequiredCSS('emulation/geolocationsSettingsTab.css');
+ this._list.show(this.contentElement);
+
+ this._customSetting = Common.moduleSetting('emulation.geolocations');
+ this._customSetting.addChangeListener(this._geolocationsUpdated, this);
+
+ this.setDefaultFocusedElement(addButton);
+ this.contentElement.tabIndex = 0;
+ }
+
+ /**
+ * @override
+ */
+ wasShown() {
+ super.wasShown();
+ this._geolocationsUpdated();
+ }
+
+ _geolocationsUpdated() {
+ this._list.clear();
+
+ const conditions = this._customSetting.get();
+ for (let i = 0; i < conditions.length; ++i)
+ this._list.appendItem(conditions[i], true);
+
+ this._list.appendSeparator();
+ }
+
+ _addButtonClicked() {
+ this._list.addNewItem(this._customSetting.get().length, {title: '', lat: 0, long: 0});
+ }
+
+ /**
+ * @override
+ * @param {*} item
+ * @param {boolean} editable
+ * @return {!Element}
+ */
+ renderItem(item, editable) {
+ const geolocation = /** @type {!Emulation.GeolocationsSettingsTab.Item} */ (item);
+ const element = createElementWithClass('div', 'geolocations-list-item');
+ const title = element.createChild('div', 'geolocations-list-text geolocations-list-title');
+ const titleText = title.createChild('div', 'geolocations-list-title-text');
+ titleText.textContent = geolocation.title;
+ titleText.title = geolocation.title;
+ element.createChild('div', 'geolocations-list-separator');
+ element.createChild('div', 'geolocations-list-text').textContent = geolocation.lat;
+ element.createChild('div', 'geolocations-list-separator');
+ element.createChild('div', 'geolocations-list-text').textContent = geolocation.long;
+ return element;
+ }
+
+ /**
+ * @override
+ * @param {*} item
+ * @param {number} index
+ */
+ removeItemRequested(item, index) {
+ const list = this._customSetting.get();
+ list.splice(index, 1);
+ this._customSetting.set(list);
+ }
+
+ /**
+ * @override
+ * @param {*} item
+ * @param {!UI.ListWidget.Editor} editor
+ * @param {boolean} isNew
+ */
+ commitEdit(item, editor, isNew) {
+ const geolocation = /** @type {?Emulation.GeolocationsSettingsTab.Item} */ (item);
+ geolocation.title = editor.control('title').value.trim();
+ const lat = editor.control('lat').value.trim();
+ geolocation.lat = lat ? parseFloat(lat) : 0;
+ const long = editor.control('long').value.trim();
+ geolocation.long = long ? parseFloat(long) : 0;
+
+ const list = this._customSetting.get();
+ if (isNew)
+ list.push(geolocation);
+ this._customSetting.set(list);
+ }
+
+ /**
+ * @override
+ * @param {*} item
+ * @return {!UI.ListWidget.Editor}
+ */
+ beginEdit(item) {
+ const geolocation = /** @type {?Emulation.GeolocationsSettingsTab.Item} */ (item);
+ const editor = this._createEditor();
+ editor.control('title').value = geolocation.title;
+ editor.control('lat').value = String(geolocation.lat);
+ editor.control('long').value = String(geolocation.long);
+ return editor;
+ }
+
+ /**
+ * @return {!UI.ListWidget.Editor}
+ */
+ _createEditor() {
+ if (this._editor)
+ return this._editor;
+
+ const editor = new UI.ListWidget.Editor();
+ this._editor = editor;
+ const content = editor.contentElement();
+
+ const titles = content.createChild('div', 'geolocations-edit-row');
+ titles.createChild('div', 'geolocations-list-text geolocations-list-title').textContent =
+ Common.UIString('Location name');
+ titles.createChild('div', 'geolocations-list-separator geolocations-list-separator-invisible');
+ titles.createChild('div', 'geolocations-list-text').textContent = Common.UIString('Lat');
+ titles.createChild('div', 'geolocations-list-separator geolocations-list-separator-invisible');
+ titles.createChild('div', 'geolocations-list-text').textContent = Common.UIString('Long');
+
+ const fields = content.createChild('div', 'geolocations-edit-row');
+ fields.createChild('div', 'geolocations-list-text geolocations-list-title')
+ .appendChild(editor.createInput('title', 'text', '', titleValidator));
+ fields.createChild('div', 'geolocations-list-separator geolocations-list-separator-invisible');
+
+ let cell = fields.createChild('div', 'geolocations-list-text');
+ cell.appendChild(editor.createInput('lat', 'text', '', latValidator));
+ fields.createChild('div', 'geolocations-list-separator geolocations-list-separator-invisible');
+
+ cell = fields.createChild('div', 'geolocations-list-text');
+ cell.appendChild(editor.createInput('long', 'text', '', longValidator));
+
+ return editor;
+
+ /**
+ * @param {*} item
+ * @param {number} index
+ * @param {!HTMLInputElement|!HTMLSelectElement} input
+ * @return {boolean}
+ */
+ function titleValidator(item, index, input) {
+ const value = input.value.trim();
+ return value.length > 0 && value.length < 50;
+ }
+
+ /**
+ * @param {*} item
+ * @param {number} index
+ * @param {!HTMLInputElement|!HTMLSelectElement} input
+ * @return {boolean}
+ */
+ function latValidator(item, index, input) {
+ const value = input.value.trim();
+ return !value || (/^-?[\d]+(\.\d+)?|\.\d+$/.test(value) && value >= -90 && value <= 90);
+ }
+
+ /**
+ * @param {*} item
+ * @param {number} index
+ * @param {!HTMLInputElement|!HTMLSelectElement} input
+ * @return {boolean}
+ */
+ function longValidator(item, index, input) {
+ const value = input.value.trim();
+ return !value || (/^-?[\d]+(\.\d+)?|\.\d+$/.test(value) && value >= -180 && value <= 180);
+ }
+ }
+};
+
+/** @typedef {{title: string, lat: number, long: number}} */
+Emulation.GeolocationsSettingsTab.Item; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/SensorsView.js b/chromium/third_party/blink/renderer/devtools/front_end/emulation/SensorsView.js
index 9bb1e558870..514b5657e59 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/emulation/SensorsView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/SensorsView.js
@@ -48,24 +48,38 @@ Emulation.SensorsView = class extends UI.VBox {
title: Common.UIString('No override'),
location: Emulation.SensorsView.NonPresetOptions.NoOverride
};
+
+ this._locationSelectElement = fields.createChild('select', 'chrome-select');
+
+ // No override
+ this._locationSelectElement.appendChild(new Option(noOverrideOption.title, noOverrideOption.location));
+
+ // Locations
+ this._customLocationsGroup = this._locationSelectElement.createChild('optgroup');
+ this._customLocationsGroup.label = ls`Overrides`;
+ const customGeolocations = Common.moduleSetting('emulation.geolocations');
+ fields.appendChild(UI.createTextButton(ls`Manage`, () => Common.Revealer.reveal(customGeolocations)));
+ const fillCustomSettings = () => {
+ this._customLocationsGroup.removeChildren();
+ for (const geolocation of customGeolocations.get())
+ this._customLocationsGroup.appendChild(new Option(geolocation.title, JSON.stringify(geolocation)));
+ };
+ customGeolocations.addChangeListener(fillCustomSettings);
+ fillCustomSettings();
+
+ // Other location
const customLocationOption = {
- title: Common.UIString('Custom location...'),
+ title: Common.UIString('Other\u2026'),
location: Emulation.SensorsView.NonPresetOptions.Custom
};
- this._locationSelectElement = this.contentElement.createChild('select', 'chrome-select');
- this._locationSelectElement.appendChild(new Option(noOverrideOption.title, noOverrideOption.location));
this._locationSelectElement.appendChild(new Option(customLocationOption.title, customLocationOption.location));
- const locationGroups = Emulation.SensorsView.PresetLocations;
- for (let i = 0; i < locationGroups.length; ++i) {
- const group = locationGroups[i].value;
- const groupElement = this._locationSelectElement.createChild('optgroup');
- groupElement.label = locationGroups[i].title;
- for (let j = 0; j < group.length; ++j)
- groupElement.appendChild(new Option(group[j].title, group[j].location));
- }
+ // Error location.
+ const group = this._locationSelectElement.createChild('optgroup');
+ group.label = ls`Error`;
+ group.appendChild(new Option(ls`Location unavailable`, Emulation.SensorsView.NonPresetOptions.Unavailable));
+
this._locationSelectElement.selectedIndex = 0;
- fields.appendChild(this._locationSelectElement);
this._locationSelectElement.addEventListener('change', this._geolocationSelectChanged.bind(this));
// Validated input fieldset.
@@ -111,15 +125,20 @@ Emulation.SensorsView = class extends UI.VBox {
this._fieldsetElement.disabled = true;
} else if (value === Emulation.SensorsView.NonPresetOptions.Custom) {
this._geolocationOverrideEnabled = true;
+ const geolocation = SDK.EmulationModel.Geolocation.parseUserInput(
+ this._latitudeInput.value.trim(), this._longitudeInput.value.trim(), '');
+ if (!geolocation)
+ return;
+ this._geolocation = geolocation;
} else if (value === Emulation.SensorsView.NonPresetOptions.Unavailable) {
this._geolocationOverrideEnabled = true;
this._geolocation = new SDK.EmulationModel.Geolocation(0, 0, true);
} else {
this._geolocationOverrideEnabled = true;
const coordinates = JSON.parse(value);
- this._geolocation = new SDK.EmulationModel.Geolocation(coordinates[0], coordinates[1], false);
- this._latitudeSetter(coordinates[0]);
- this._longitudeSetter(coordinates[1]);
+ this._geolocation = new SDK.EmulationModel.Geolocation(coordinates.lat, coordinates.long, false);
+ this._latitudeSetter(coordinates.lat);
+ this._longitudeSetter(coordinates.long);
}
this._applyGeolocation();
@@ -462,35 +481,11 @@ Emulation.SensorsView.DeviceOrientationModificationSource = {
/** {string} */
Emulation.SensorsView.NonPresetOptions = {
- 'NoOverride': 'noOverride',
- 'Custom': 'custom',
- 'Unavailable': 'unavailable'
+ NoOverride: 'noOverride',
+ Custom: 'custom',
+ Unavailable: 'unavailable'
};
-/** @type {!Array.<{title: string, value: !Array.<{title: string, location: string}>}>} */
-Emulation.SensorsView.PresetLocations = [
- {
- title: 'Presets',
- value: [
- {title: Common.UIString('Berlin'), location: '[52.520007, 13.404954]'},
- {title: Common.UIString('London'), location: '[51.507351, -0.127758]'},
- {title: Common.UIString('Moscow'), location: '[55.755826, 37.617300]'},
- {title: Common.UIString('Mountain View'), location: '[37.386052, -122.083851]'},
- {title: Common.UIString('Mumbai'), location: '[19.075984, 72.877656]'},
- {title: Common.UIString('San Francisco'), location: '[37.774929, -122.419416]'},
- {title: Common.UIString('Shanghai'), location: '[31.230416, 121.473701]'},
- {title: Common.UIString('São Paulo'), location: '[-23.550520, -46.633309]'},
- {title: Common.UIString('Tokyo'), location: '[35.689487, 139.691706]'},
- ]
- },
- {
- title: 'Error',
- value: [
- {title: Common.UIString('Location unavailable'), location: Emulation.SensorsView.NonPresetOptions.Unavailable}
- ]
- }
-];
-
/** @type {!Array.<{title: string, value: !Array.<{title: string, orientation: string}>}>} */
Emulation.SensorsView.PresetOrientations = [{
title: 'Presets',
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/geolocationsSettingsTab.css b/chromium/third_party/blink/renderer/devtools/front_end/emulation/geolocationsSettingsTab.css
new file mode 100644
index 00000000000..53c1f185e34
--- /dev/null
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/geolocationsSettingsTab.css
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+:host {
+ overflow:hidden;
+}
+
+.header {
+ padding: 0 0 6px;
+ border-bottom: 1px solid #EEEEEE;
+ font-size: 18px;
+ font-weight: normal;
+ flex: none;
+}
+
+.add-geolocations-button {
+ flex: none;
+ margin: 10px 2px;
+ min-width: 140px;
+ align-self: flex-start;
+}
+
+.geolocations-list {
+ max-width: 500px;
+ min-width: 340px;
+ flex: auto;
+}
+
+.geolocations-list-item {
+ padding: 3px 5px 3px 5px;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ position: relative;
+ flex: auto 1 1;
+}
+
+.geolocations-list-text {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ flex: 0 0 70px;
+ -webkit-user-select: none;
+ color: #222;
+ text-align: end;
+ position: relative;
+}
+
+.geolocations-list-title {
+ text-align: start;
+ flex: auto;
+ display: flex;
+ align-items: flex-start;
+}
+
+.geolocations-list-title-text {
+ overflow: hidden;
+ flex: auto;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.geolocations-list-separator {
+ flex: 0 0 1px;
+ background-color: rgb(231, 231, 231);
+ height: 30px;
+ margin: 0 4px;
+}
+
+.geolocations-list-separator-invisible {
+ visibility: hidden;
+ height: 100% !important;
+}
+
+.geolocations-edit-row {
+ flex: none;
+ display: flex;
+ flex-direction: row;
+ margin: 6px 5px;
+}
+
+.geolocations-edit-row input {
+ width: 100%;
+ text-align: inherit;
+}
+
+.geolocations-edit-optional {
+ position: absolute;
+ bottom: -20px;
+ right: 0;
+ color: rgb(128, 128, 128);
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/module.json b/chromium/third_party/blink/renderer/devtools/front_end/emulation/module.json
index 51b0d641d9c..7968cff712d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/emulation/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/module.json
@@ -28,10 +28,9 @@
{
"type": "action",
"actionId": "emulation.capture-screenshot",
- "category": "Mobile",
+ "category": "Screenshot",
"className": "Emulation.DeviceModeWrapper.ActionDelegate",
- "title": "Capture screenshot",
- "tags": "device"
+ "title": "Capture screenshot"
},
{
"type": "context-menu-item",
@@ -49,18 +48,16 @@
{
"type": "action",
"actionId": "emulation.capture-full-height-screenshot",
- "category": "Mobile",
+ "category": "Screenshot",
"className": "Emulation.DeviceModeWrapper.ActionDelegate",
- "title": "Capture full size screenshot",
- "tags": "device"
+ "title": "Capture full size screenshot"
},
{
"type": "action",
"actionId": "emulation.capture-node-screenshot",
- "category": "Mobile",
+ "category": "Screenshot",
"className": "Emulation.DeviceModeWrapper.ActionDelegate",
- "title": "Capture node screenshot",
- "tags": "device"
+ "title": "Capture node screenshot"
},
{
"type": "context-menu-item",
@@ -149,6 +146,33 @@
"order": 100,
"className": "Emulation.SensorsView",
"tags": "geolocation, accelerometer, device orientation"
+ },
+ {
+ "type": "setting",
+ "settingName": "emulation.geolocations",
+ "settingType": "array",
+ "defaultValue": [
+ {"title": "Berlin", "lat": 52.520007, "long": 13.404954},
+ {"title": "London", "lat": 51.507351, "long": -0.127758},
+ {"title": "Moscow", "lat": 55.755826, "long": 37.617300},
+ {"title": "Mountain View", "lat": 37.386052, "long": -122.083851},
+ {"title": "Mumbai", "lat": 19.075984, "long": 72.877656},
+ {"title": "San Francisco", "lat": 37.774929, "long": -122.419416},
+ {"title": "Shanghai", "lat": 31.230416, "long": 121.473701},
+ {"title": "São Paulo", "lat": -23.550520, "long": -46.633309},
+ {"title": "Tokyo", "lat": 35.689487, "long": 139.691706}
+ ]
+ },
+ {
+ "type": "view",
+ "location": "settings-view",
+ "id": "emulation-geolocations",
+ "title": "Geolocations",
+ "order": 40,
+ "className": "Emulation.GeolocationsSettingsTab",
+ "settings": [
+ "emulation.geolocations"
+ ]
}
],
"dependencies": [
@@ -168,12 +192,14 @@
"DeviceModeModel.js",
"DeviceModeToolbar.js",
"DeviceModeView.js",
- "DeviceModeWrapper.js"
+ "DeviceModeWrapper.js",
+ "GeolocationsSettingsTab.js"
],
"resources": [
"devicesSettingsTab.css",
"deviceModeToolbar.css",
"deviceModeView.css",
+ "geolocationsSettingsTab.css",
"inspectedPagePlaceholder.css",
"mediaQueryInspector.css",
"sensors.css"
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/emulation/sensors.css b/chromium/third_party/blink/renderer/devtools/front_end/emulation/sensors.css
index 03c1311c677..acac8d9ff25 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/emulation/sensors.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/emulation/sensors.css
@@ -9,10 +9,6 @@
display: block;
}
-.sensors-view label {
- margin-bottom: 10px;
-}
-
.sensors-view input {
width: 100%;
max-width: 100px;
@@ -113,7 +109,7 @@
}
.orientation-box {
- width: 66px;
+ width: 62px;
height: 122px;
left: 0;
right: 0;
@@ -136,31 +132,31 @@
.orientation-front,
.orientation-back
{
- width: 66px;
+ width: 62px;
height: 122px;
border-radius: 8px;
}
.orientation-front {
- background-image: url(Images/accelerometer-front.png);
+ background-image: url(Images/accelerometer-front.svg);
}
.orientation-back {
- transform: rotateY(180deg) translateZ(12px);
- background-image: url(Images/accelerometer-back.png);
+ transform: rotateY(180deg) translateZ(8px);
+ background-image: url(Images/accelerometer-back.svg);
}
.orientation-left,
.orientation-right {
- width: 12px;
+ width: 8px;
height: 106px;
top: 8px;
background-position: center center;
}
.orientation-left {
- left: -12px;
+ left: -8px;
transform-origin: right center;
transform: rotateY(-90deg);
background-image: url(Images/accelerometer-left.png);
@@ -168,7 +164,7 @@
.orientation-right {
- right: -12px;
+ right: -8px;
transform-origin: left center;
transform: rotateY(90deg);
background-image: url(Images/accelerometer-right.png);
@@ -180,7 +176,7 @@
.orientation-right::after
{
content: '';
- width: 12px;
+ width: 8px;
height: 6px;
}
@@ -215,13 +211,13 @@
.orientation-top,
.orientation-bottom {
width: 50px;
- height: 12px;
+ height: 8px;
left: 8px;
background-position: center center;
}
.orientation-top {
- top: -12px;
+ top: -8px;
transform-origin: center bottom;
transform: rotateX(90deg);
background-image: url(Images/accelerometer-top.png);
@@ -229,7 +225,7 @@
.orientation-bottom {
- bottom: -12px;
+ bottom: -8px;
transform-origin: center top;
transform: rotateX(-90deg);
background-image: url(Images/accelerometer-bottom.png);
@@ -243,7 +239,7 @@
{
content: '';
width: 8px;
- height: 12px;
+ height: 8px;
}
.orientation-top::before,
@@ -301,7 +297,7 @@ fieldset.device-orientation-override-section {
.panel-section-separator {
height: 2px;
- margin-bottom: 12px;
+ margin-bottom: 8px;
background: #f1f1f1;
}
@@ -309,3 +305,7 @@ fieldset.device-orientation-override-section {
align-self: center;
margin-left: 10px;
}
+
+button.text-button {
+ margin: 0 10px;
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/extensions/ExtensionView.js b/chromium/third_party/blink/renderer/devtools/front_end/extensions/ExtensionView.js
index 5ce50e1df46..f1ec73ef29c 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/extensions/ExtensionView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/extensions/ExtensionView.js
@@ -43,13 +43,18 @@ Extensions.ExtensionView = class extends UI.Widget {
this.setHideOnDetach();
this.element.className = 'vbox flex-auto'; // Override
+ // TODO(crbug.com/872438): remove once we can use this._iframe instead
+ this.element.tabIndex = -1;
+
this._server = server;
this._id = id;
this._iframe = createElement('iframe');
this._iframe.addEventListener('load', this._onLoad.bind(this), false);
this._iframe.src = src;
this._iframe.className = className;
- this.setDefaultFocusedElement(this._iframe);
+
+ // TODO(crbug.com/872438): make this._iframe the default focused element
+ this.setDefaultFocusedElement(this.element);
this.element.appendChild(this._iframe);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/externs.js b/chromium/third_party/blink/renderer/devtools/front_end/externs.js
index 6f7fcbc3e90..1353a7e2695 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/externs.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/externs.js
@@ -542,7 +542,7 @@ CodeMirror.prototype = {
undo: function() {},
unlinkDoc: function(other) {}
};
-/** @type {!{cursorDiv: Element, lineSpace: Element}} */
+/** @type {!{cursorDiv: Element, lineSpace: Element, gutters: Element}} */
CodeMirror.prototype.display;
/** @type {!{mode: string, lineWrapping: boolean}} */
CodeMirror.prototype.options;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/heap_profiler_test_runner/HeapProfilerTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/heap_profiler_test_runner/HeapProfilerTestRunner.js
index 91193f4f3cd..30509ab1443 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/heap_profiler_test_runner/HeapProfilerTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/heap_profiler_test_runner/HeapProfilerTestRunner.js
@@ -43,9 +43,10 @@ HeapProfilerTestRunner.createHeapSnapshotMockFactories = function() {
node_types: [['hidden', 'object'], '', '', '', '', '', ''],
edge_fields: ['type', 'name_or_index', 'to_node'],
edge_types: [['element', 'property', 'shortcut'], '', ''],
- location_fields: ['object_index', 'script_id', 'line', 'column']
+ location_fields: ['object_index', 'script_id', 'line', 'column'],
+ trace_function_info_fields: ['function_id', 'name', 'script_name', 'script_id', 'line', 'column'],
+ trace_node_fields: ['id', 'function_info_index', 'count', 'size', 'children']
},
-
node_count: 6,
edge_count: 7
},
@@ -57,6 +58,10 @@ HeapProfilerTestRunner.createHeapSnapshotMockFactories = function() {
edges: [1, 6, 7, 1, 7, 14, 0, 1, 14, 1, 8, 21, 1, 9, 21, 1, 10, 28, 1, 11, 35],
+ trace_function_infos: [0, 2, 1, 0, 0, 0],
+
+ trace_tree: [1, 0, 0, 0, []],
+
locations: [0, 1, 2, 3, 18, 2, 3, 4],
strings: ['', 'A', 'B', 'C', 'D', 'E', 'a', 'b', 'ac', 'bc', 'bd', 'ce']
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js b/chromium/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js
index 6f49288eba4..9261c50df23 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js
@@ -38,6 +38,10 @@ HeapSnapshotWorker.HeapSnapshotLoader = class {
constructor(dispatcher) {
this._reset();
this._progress = new HeapSnapshotWorker.HeapSnapshotProgress(dispatcher);
+ this._buffer = '';
+ this._dataCallback = null;
+ this._done = false;
+ this._parseInput();
}
dispose() {
@@ -46,20 +50,20 @@ HeapSnapshotWorker.HeapSnapshotLoader = class {
_reset() {
this._json = '';
- this._state = 'find-snapshot-info';
this._snapshot = {};
}
close() {
- if (this._json)
- this._parseStringsArray();
+ this._done = true;
+ if (this._dataCallback)
+ this._dataCallback('');
}
/**
* @return {!HeapSnapshotWorker.JSHeapSnapshot}
*/
buildSnapshot() {
- this._progress.updateStatus('Processing snapshot\u2026');
+ this._progress.updateStatus(ls`Processing snapshot\u2026`);
const result = new HeapSnapshotWorker.JSHeapSnapshot(this._snapshot, this._progress);
this._reset();
return result;
@@ -107,7 +111,7 @@ HeapSnapshotWorker.HeapSnapshotLoader = class {
_parseStringsArray() {
this._progress.updateStatus('Parsing strings\u2026');
const closingBracketIndex = this._json.lastIndexOf(']');
- if (closingBracketIndex === -1 || this._state !== 'accumulate-strings')
+ if (closingBracketIndex === -1)
throw new Error('Incomplete JSON');
this._json = this._json.slice(0, closingBracketIndex + 1);
this._snapshot.strings = JSON.parse(this._json);
@@ -117,228 +121,110 @@ HeapSnapshotWorker.HeapSnapshotLoader = class {
* @param {string} chunk
*/
write(chunk) {
- if (this._json !== null)
- this._json += chunk;
- while (true) {
- switch (this._state) {
- case 'find-snapshot-info': {
- const snapshotToken = '"snapshot"';
- const snapshotTokenIndex = this._json.indexOf(snapshotToken);
- if (snapshotTokenIndex === -1)
- throw new Error('Snapshot token not found');
-
- const json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1);
- this._state = 'parse-snapshot-info';
- this._progress.updateStatus('Loading snapshot info\u2026');
- this._json = null; // tokenizer takes over input.
- this._jsonTokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(this._writeBalancedJSON.bind(this));
- // Fall through with adjusted payload.
- chunk = json;
- }
- case 'parse-snapshot-info': {
- this._jsonTokenizer.write(chunk);
- if (this._jsonTokenizer)
- return; // no remainder to process.
- break;
- }
- case 'find-nodes': {
- const nodesToken = '"nodes"';
- const nodesTokenIndex = this._json.indexOf(nodesToken);
- if (nodesTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', nodesTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex + 1);
- const node_fields_count = this._snapshot.snapshot.meta.node_fields.length;
- const nodes_length = this._snapshot.snapshot.node_count * node_fields_count;
- this._array = new Uint32Array(nodes_length);
- this._arrayIndex = 0;
- this._state = 'parse-nodes';
- break;
- }
- case 'parse-nodes': {
- const hasMoreData = this._parseUintArray();
- this._progress.updateProgress('Loading nodes\u2026 %d%%', this._arrayIndex, this._array.length);
- if (hasMoreData)
- return;
- this._snapshot.nodes = this._array;
- this._state = 'find-edges';
- this._array = null;
- break;
- }
- case 'find-edges': {
- const edgesToken = '"edges"';
- const edgesTokenIndex = this._json.indexOf(edgesToken);
- if (edgesTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', edgesTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex + 1);
- const edge_fields_count = this._snapshot.snapshot.meta.edge_fields.length;
- const edges_length = this._snapshot.snapshot.edge_count * edge_fields_count;
- this._array = new Uint32Array(edges_length);
- this._arrayIndex = 0;
- this._state = 'parse-edges';
- break;
- }
- case 'parse-edges': {
- const hasMoreData = this._parseUintArray();
- this._progress.updateProgress('Loading edges\u2026 %d%%', this._arrayIndex, this._array.length);
- if (hasMoreData)
- return;
- this._snapshot.edges = this._array;
- this._array = null;
- // If there is allocation info parse it, otherwise jump straight to strings.
- if (this._snapshot.snapshot.trace_function_count) {
- this._state = 'find-trace-function-infos';
- this._progress.updateStatus('Loading allocation traces\u2026');
- } else if (this._snapshot.snapshot.meta.sample_fields) {
- this._state = 'find-samples';
- this._progress.updateStatus('Loading samples\u2026');
- } else {
- this._state = 'find-locations';
- }
- break;
- }
- case 'find-trace-function-infos': {
- const tracesToken = '"trace_function_infos"';
- const tracesTokenIndex = this._json.indexOf(tracesToken);
- if (tracesTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', tracesTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex + 1);
+ this._buffer += chunk;
+ if (!this._dataCallback)
+ return;
+ this._dataCallback(this._buffer);
+ this._dataCallback = null;
+ this._buffer = '';
+ }
- const trace_function_info_field_count = this._snapshot.snapshot.meta.trace_function_info_fields.length;
- const trace_function_info_length =
- this._snapshot.snapshot.trace_function_count * trace_function_info_field_count;
- this._array = new Uint32Array(trace_function_info_length);
- this._arrayIndex = 0;
- this._state = 'parse-trace-function-infos';
- break;
- }
- case 'parse-trace-function-infos': {
- if (this._parseUintArray())
- return;
- this._snapshot.trace_function_infos = this._array;
- this._array = null;
- this._state = 'find-trace-tree';
- break;
- }
- case 'find-trace-tree': {
- const tracesToken = '"trace_tree"';
- const tracesTokenIndex = this._json.indexOf(tracesToken);
- if (tracesTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', tracesTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex);
- this._state = 'parse-trace-tree';
- break;
- }
- case 'parse-trace-tree': {
- // If there is samples array parse it, otherwise jump straight to strings.
- const nextToken = this._snapshot.snapshot.meta.sample_fields ? '"samples"' : '"strings"';
- const nextTokenIndex = this._json.indexOf(nextToken);
- if (nextTokenIndex === -1)
- return;
- const bracketIndex = this._json.lastIndexOf(']', nextTokenIndex);
- this._snapshot.trace_tree = JSON.parse(this._json.substring(0, bracketIndex + 1));
- this._json = this._json.slice(bracketIndex + 1);
- if (this._snapshot.snapshot.meta.sample_fields) {
- this._state = 'find-samples';
- this._progress.updateStatus('Loading samples\u2026');
- } else {
- this._state = 'find-strings';
- this._progress.updateStatus('Loading strings\u2026');
- }
- break;
- }
- case 'find-samples': {
- const samplesToken = '"samples"';
- const samplesTokenIndex = this._json.indexOf(samplesToken);
- if (samplesTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', samplesTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex + 1);
- this._array = [];
- this._arrayIndex = 0;
- this._state = 'parse-samples';
- break;
- }
- case 'parse-samples': {
- if (this._parseUintArray())
- return;
- this._snapshot.samples = this._array;
- this._array = null;
- this._state = 'find-locations';
- this._progress.updateStatus('Loading locations\u2026');
- break;
- }
- case 'find-locations': {
- if (!this._snapshot.snapshot.meta.location_fields) {
- // The property `locations` was added retroactively, so older
- // snapshots might not contain it. In this case just expect `strings`
- // as next property.
- this._snapshot.locations = [];
- this._array = null;
- this._state = 'find-strings';
- break;
- }
+ /**
+ * @return {!Promise<string>}
+ */
+ _fetchChunk() {
+ return this._done ? Promise.resolve(this._buffer) : new Promise(r => this._dataCallback = r);
+ }
- const locationsToken = '"locations"';
- const locationsTokenIndex = this._json.indexOf(locationsToken);
- if (locationsTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', locationsTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex + 1);
- this._array = [];
- this._arrayIndex = 0;
- this._state = 'parse-locations';
- break;
- }
- case 'parse-locations': {
- if (this._parseUintArray())
- return;
- this._snapshot.locations = this._array;
- this._array = null;
- this._state = 'find-strings';
- this._progress.updateStatus('Loading strings\u2026');
- break;
- }
- case 'find-strings': {
- const stringsToken = '"strings"';
- const stringsTokenIndex = this._json.indexOf(stringsToken);
- if (stringsTokenIndex === -1)
- return;
- const bracketIndex = this._json.indexOf('[', stringsTokenIndex);
- if (bracketIndex === -1)
- return;
- this._json = this._json.slice(bracketIndex);
- this._state = 'accumulate-strings';
- break;
- }
- case 'accumulate-strings':
- return;
- }
+ /**
+ * @param {string} token
+ * @param {number=} startIndex
+ * @return {!Promise<number>}
+ */
+ async _findToken(token, startIndex) {
+ while (true) {
+ const pos = this._json.indexOf(token, startIndex || 0);
+ if (pos !== -1)
+ return pos;
+ startIndex = this._json.length - token.length + 1;
+ this._json += await this._fetchChunk();
}
}
/**
- * @param {string} data
+ * @param {string} name
+ * @param {string} title
+ * @param {number=} length
+ * @return {!Promise<!Uint32Array|!Array<number>>}
*/
- _writeBalancedJSON(data) {
- this._json = this._jsonTokenizer.remainder(); // tokenizer releases input.
- this._jsonTokenizer = null;
- this._state = 'find-nodes';
- this._snapshot.snapshot = /** @type {!HeapSnapshotHeader} */ (JSON.parse(data));
+ async _parseArray(name, title, length) {
+ const nameIndex = await this._findToken(name);
+ const bracketIndex = await this._findToken('[', nameIndex);
+ this._json = this._json.slice(bracketIndex + 1);
+ this._array = length ? new Uint32Array(length) : [];
+ this._arrayIndex = 0;
+ while (this._parseUintArray()) {
+ this._progress.updateProgress(title, this._arrayIndex, this._array.length);
+ this._json += await this._fetchChunk();
+ }
+ const result = this._array;
+ this._array = null;
+ return result;
+ }
+
+ async _parseInput() {
+ const snapshotToken = '"snapshot"';
+ const snapshotTokenIndex = await this._findToken(snapshotToken);
+ if (snapshotTokenIndex === -1)
+ throw new Error('Snapshot token not found');
+
+ this._progress.updateStatus(ls`Loading snapshot info\u2026`);
+ const json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1);
+ this._jsonTokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(metaJSON => {
+ this._json = this._jsonTokenizer.remainder();
+ this._jsonTokenizer = null;
+ this._snapshot.snapshot = /** @type {!HeapSnapshotHeader} */ (JSON.parse(metaJSON));
+ });
+ this._jsonTokenizer.write(json);
+ while (this._jsonTokenizer)
+ this._jsonTokenizer.write(await this._fetchChunk());
+
+ this._snapshot.nodes = await this._parseArray(
+ '"nodes"', ls`Loading nodes\u2026 %d%%`,
+ this._snapshot.snapshot.meta.node_fields.length * this._snapshot.snapshot.node_count);
+
+ this._snapshot.edges = await this._parseArray(
+ '"edges"', ls`Loading edges\u2026 %d%%`,
+ this._snapshot.snapshot.meta.edge_fields.length * this._snapshot.snapshot.edge_count);
+
+ if (this._snapshot.snapshot.trace_function_count) {
+ this._snapshot.trace_function_infos = await this._parseArray(
+ '"trace_function_infos"', ls`Loading allocation traces\u2026 %d%%`,
+ this._snapshot.snapshot.meta.trace_function_info_fields.length *
+ this._snapshot.snapshot.trace_function_count);
+
+ const thisTokenEndIndex = await this._findToken(':');
+ const nextTokenIndex = await this._findToken('"', thisTokenEndIndex);
+ const openBracketIndex = this._json.indexOf('[');
+ const closeBracketIndex = this._json.lastIndexOf(']', nextTokenIndex);
+ this._snapshot.trace_tree = JSON.parse(this._json.substring(openBracketIndex, closeBracketIndex + 1));
+ this._json = this._json.slice(closeBracketIndex + 1);
+ }
+
+ if (this._snapshot.snapshot.meta.sample_fields)
+ this._snapshot.samples = await this._parseArray('"samples"', ls`Loading samples\u2026`);
+
+ if (this._snapshot.snapshot.meta['location_fields'])
+ this._snapshot.locations = await this._parseArray('"locations"', ls`Loading locations\u2026`);
+ else
+ this._snapshot.locations = [];
+
+ this._progress.updateStatus(ls`Loading strings\u2026`);
+ const stringsTokenIndex = await this._findToken('"strings"');
+ const bracketIndex = await this._findToken('[', stringsTokenIndex);
+ this._json = this._json.slice(bracketIndex);
+ while (!this._done)
+ this._json += await this._fetchChunk();
+ this._parseStringsArray();
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/help/ReleaseNoteText.js b/chromium/third_party/blink/renderer/devtools/front_end/help/ReleaseNoteText.js
index 9e9640e0d03..7c3dd62da17 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/help/ReleaseNoteText.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/help/ReleaseNoteText.js
@@ -13,6 +13,45 @@ const commandMenuShortcut = Host.isMac() ? 'Command + Shift + P' : 'Control + Sh
/** @type {!Array<!Help.ReleaseNote>} */
Help.releaseNoteText = [
{
+ version: 15,
+ header: 'Highlights from the Chrome 73 update',
+ highlights: [
+ {
+ title: 'Logpoints',
+ subtitle: 'Log messages to the Console without cluttering up your code with console.log() calls.',
+ link: 'https://developers.google.com/web/updates/2019/01/devtools#logpoints',
+ },
+ {
+ title: 'Detailed tooltips in Inspect Mode',
+ subtitle: 'When inspecting a node, DevTools now shows an expanded tooltip containing text, ' +
+ 'color contrast, and box model information.',
+ link: 'https://developers.google.com/web/updates/2019/01/devtools#inspect',
+ },
+ {
+ title: 'Export code coverage data',
+ subtitle: 'The Coverage tab now supports exporting coverage data as JSON.',
+ link: 'https://developers.google.com/web/updates/2019/01/devtools#coverage',
+ },
+ {
+ title: 'Navigate the Console with the keyboard',
+ subtitle: 'Press Shift+Tab to focus the last message and then use the arrow keys to navigate.',
+ link: 'https://developers.google.com/web/updates/2019/01/devtools#keyboard',
+ },
+ {
+ title: 'Save custom geolocation overrides',
+ subtitle: 'Click Manage in the Sensors tab or open Settings > Geolocations.',
+ link: 'https://developers.google.com/web/updates/2019/01/devtools#geolocation',
+ },
+ {
+ title: 'Code folding',
+ subtitle: 'Go to Settings > Preferences > Sources and enable Code Folding to fold ' +
+ 'code in the Sources panel.',
+ link: 'https://developers.google.com/web/updates/2019/01/devtools#folding',
+ },
+ ],
+ link: 'https://developers.google.com/web/updates/2019/01/devtools',
+ },
+ {
version: 14,
header: 'Highlights from the Chrome 72 update',
highlights: [
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js b/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js
index 3a5bc6cd1d3..06d4a8fafc3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHost.js
@@ -56,38 +56,6 @@ Host.InspectorFrontendHostStub = class {
* @override
* @return {string}
*/
- getSelectionBackgroundColor() {
- return '#6e86ff';
- }
-
- /**
- * @override
- * @return {string}
- */
- getSelectionForegroundColor() {
- return '#ffffff';
- }
-
- /**
- * @override
- * @return {string}
- */
- getInactiveSelectionBackgroundColor() {
- return '#c9c8c8';
- }
-
- /**
- * @override
- * @return {string}
- */
- getInactiveSelectionForegroundColor() {
- return '#323232';
- }
-
- /**
- * @override
- * @return {string}
- */
platform() {
let match = navigator.userAgent.match(/Windows NT/);
if (match)
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js b/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js
index 93b1dc56a89..def267535f8 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -110,26 +110,6 @@ InspectorFrontendHostAPI.prototype = {
indexPath(requestId, fileSystemPath, excludedFolders) {},
/**
- * @return {string}
- */
- getSelectionBackgroundColor() {},
-
- /**
- * @return {string}
- */
- getSelectionForegroundColor() {},
-
- /**
- * @return {string}
- */
- getInactiveSelectionBackgroundColor() {},
-
- /**
- * @return {string}
- */
- getInactiveSelectionForegroundColor() {},
-
- /**
* Requests inspected page to be placed atop of the inspector frontend with specified bounds.
* @param {{x: number, y: number, width: number, height: number}} bounds
*/
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js b/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js
index 5bf765f6c9c..07ef71fef7f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js
@@ -68,7 +68,7 @@ InlineEditor.CSSShadowEditor = class extends UI.VBox {
* @return {!Element}
*/
_createSlider(field) {
- const slider = UI.createSliderLabel(0, InlineEditor.CSSShadowEditor.maxRange, -1);
+ const slider = UI.createSlider(0, InlineEditor.CSSShadowEditor.maxRange, -1);
slider.addEventListener('input', this._onSliderInput.bind(this), false);
field.appendChild(slider);
return slider;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js b/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js
index 5f5eb0bc85a..2dfc68abca0 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js
@@ -7,6 +7,17 @@
InlineEditor.ColorSwatch = class extends HTMLSpanElement {
constructor() {
super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css');
+
+ this._iconElement = root.createChild('span', 'color-swatch');
+ this._iconElement.title = Common.UIString('Shift-click to change color format');
+ this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner');
+ this._swatchInner.addEventListener('dblclick', e => e.consume(), false);
+ this._swatchInner.addEventListener('mousedown', e => e.consume(), false);
+ this._swatchInner.addEventListener('click', this._handleClick.bind(this), true);
+
+ root.createChild('slot');
+ this._colorValueElement = this.createChild('span');
}
/**
@@ -15,11 +26,11 @@ InlineEditor.ColorSwatch = class extends HTMLSpanElement {
static create() {
if (!InlineEditor.ColorSwatch._constructor) {
InlineEditor.ColorSwatch._constructor =
- UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch.prototype);
+ UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch);
}
- return /** @type {!InlineEditor.ColorSwatch} */ (new InlineEditor.ColorSwatch._constructor());
+ return /** @type {!InlineEditor.ColorSwatch} */ (InlineEditor.ColorSwatch._constructor());
}
/**
@@ -134,23 +145,6 @@ InlineEditor.ColorSwatch = class extends HTMLSpanElement {
}
/**
- * @override
- */
- createdCallback() {
- const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css');
-
- this._iconElement = root.createChild('span', 'color-swatch');
- this._iconElement.title = Common.UIString('Shift-click to change color format');
- this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner');
- this._swatchInner.addEventListener('dblclick', e => e.consume(), false);
- this._swatchInner.addEventListener('mousedown', e => e.consume(), false);
- this._swatchInner.addEventListener('click', this._handleClick.bind(this), true);
-
- root.createChild('content');
- this._colorValueElement = this.createChild('span');
- }
-
- /**
* @param {!Event} event
*/
_handleClick(event) {
@@ -168,6 +162,11 @@ InlineEditor.ColorSwatch = class extends HTMLSpanElement {
InlineEditor.BezierSwatch = class extends HTMLSpanElement {
constructor() {
super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css');
+ this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon');
+ root.appendChild(this._iconElement);
+ this._textElement = this.createChild('span');
+ root.createChild('slot');
}
/**
@@ -176,11 +175,11 @@ InlineEditor.BezierSwatch = class extends HTMLSpanElement {
static create() {
if (!InlineEditor.BezierSwatch._constructor) {
InlineEditor.BezierSwatch._constructor =
- UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch.prototype);
+ UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch);
}
- return /** @type {!InlineEditor.BezierSwatch} */ (new InlineEditor.BezierSwatch._constructor());
+ return /** @type {!InlineEditor.BezierSwatch} */ (InlineEditor.BezierSwatch._constructor());
}
/**
@@ -210,17 +209,6 @@ InlineEditor.BezierSwatch = class extends HTMLSpanElement {
iconElement() {
return this._iconElement;
}
-
- /**
- * @override
- */
- createdCallback() {
- const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css');
- this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon');
- root.appendChild(this._iconElement);
- this._textElement = this.createChild('span');
- root.createChild('content');
- }
};
/**
@@ -229,6 +217,11 @@ InlineEditor.BezierSwatch = class extends HTMLSpanElement {
InlineEditor.CSSShadowSwatch = class extends HTMLSpanElement {
constructor() {
super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css');
+ this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon');
+ root.appendChild(this._iconElement);
+ root.createChild('slot');
+ this._contentElement = this.createChild('span');
}
/**
@@ -237,10 +230,10 @@ InlineEditor.CSSShadowSwatch = class extends HTMLSpanElement {
static create() {
if (!InlineEditor.CSSShadowSwatch._constructor) {
InlineEditor.CSSShadowSwatch._constructor =
- UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch.prototype);
+ UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch);
}
- return /** @type {!InlineEditor.CSSShadowSwatch} */ (new InlineEditor.CSSShadowSwatch._constructor());
+ return /** @type {!InlineEditor.CSSShadowSwatch} */ (InlineEditor.CSSShadowSwatch._constructor());
}
/**
@@ -290,15 +283,4 @@ InlineEditor.CSSShadowSwatch = class extends HTMLSpanElement {
colorSwatch() {
return this._colorSwatch;
}
-
- /**
- * @override
- */
- createdCallback() {
- const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css');
- this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon');
- root.appendChild(this._iconElement);
- root.createChild('content');
- this._contentElement = this.createChild('span');
- }
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/colorSwatch.css b/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/colorSwatch.css
index 9f04d73ed25..bb50620761f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/colorSwatch.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inline_editor/colorSwatch.css
@@ -32,4 +32,3 @@
.color-swatch-inner:hover {
border: 1px solid rgba(64, 64, 64, 0.8);
}
-
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/InspectorMain.js b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/InspectorMain.js
index 7f8e3a0011d..6808e0b6908 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/InspectorMain.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/InspectorMain.js
@@ -9,14 +9,31 @@ InspectorMain.InspectorMain = class extends Common.Object {
/**
* @override
*/
- run() {
- SDK.initMainConnection(() => {
+ async run() {
+ let firstCall = true;
+ await SDK.initMainConnection(async () => {
const type = Runtime.queryParam('v8only') ? SDK.Target.Type.Node : SDK.Target.Type.Frame;
- const target = SDK.targetManager.createTarget('main', Common.UIString('Main'), type, null);
+ const waitForDebuggerInPage = type === SDK.Target.Type.Frame && Runtime.queryParam('panel') === 'sources';
+ const target =
+ SDK.targetManager.createTarget('main', Common.UIString('Main'), type, null, undefined, waitForDebuggerInPage);
+
+ // Only resume target during the first connection,
+ // subsequent connections are due to connection hand-over,
+ // there is no need to pause in debugger.
+ if (!firstCall)
+ return;
+ firstCall = false;
+
+ if (waitForDebuggerInPage) {
+ const debuggerModel = target.model(SDK.DebuggerModel);
+ if (!debuggerModel.isReadyToPause())
+ await debuggerModel.once(SDK.DebuggerModel.Events.DebuggerIsReadyToPause);
+ debuggerModel.pause();
+ }
+
target.runtimeAgent().runIfWaitingForDebugger();
}, Components.TargetDetachedDialog.webSocketConnectionLost);
- new InspectorMain.InspectedNodeRevealer();
new InspectorMain.SourcesPanelIndicator();
new InspectorMain.BackendSettingsSync();
new MobileThrottling.NetworkPanelIndicator();
@@ -127,24 +144,6 @@ InspectorMain.SourcesPanelIndicator = class {
};
/**
- * @unrestricted
- */
-InspectorMain.InspectedNodeRevealer = class {
- constructor() {
- SDK.targetManager.addModelListener(
- SDK.OverlayModel, SDK.OverlayModel.Events.InspectNodeRequested, this._inspectNode, this);
- }
-
- /**
- * @param {!Common.Event} event
- */
- _inspectNode(event) {
- const deferredNode = /** @type {!SDK.DeferredDOMNode} */ (event.data);
- Common.Revealer.reveal(deferredNode);
- }
-};
-
-/**
* @implements {SDK.TargetManager.Observer}
* @unrestricted
*/
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RenderingOptions.js b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RenderingOptions.js
index 4ccb6721c34..9c35be8fd24 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RenderingOptions.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RenderingOptions.js
@@ -50,6 +50,9 @@ InspectorMain.RenderingOptionsView = class extends UI.VBox {
'Highlights elements (teal) that can slow down scrolling, including touch & wheel event handlers and other main-thread scrolling situations.'),
Common.moduleSetting('showScrollBottleneckRects'));
this._appendCheckbox(
+ Common.UIString('Highlight ad frames'), Common.UIString('Highlights frames (red) detected to be ads.'),
+ Common.moduleSetting('showAdHighlights'));
+ this._appendCheckbox(
Common.UIString('Hit-test borders'), Common.UIString('Shows borders around hit-test regions'),
Common.moduleSetting('showHitTestBorders'));
this.contentElement.createChild('div').classList.add('panel-section-separator');
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RequestAppBannerActionDelegate.js b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RequestAppBannerActionDelegate.js
deleted file mode 100644
index 9dc8491bba6..00000000000
--- a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/RequestAppBannerActionDelegate.js
+++ /dev/null
@@ -1,23 +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.
-/**
- * @implements {UI.ActionDelegate}
- * @unrestricted
- */
-InspectorMain.RequestAppBannerActionDelegate = class {
- /**
- * @override
- * @param {!UI.Context} context
- * @param {string} actionId
- * @return {boolean}
- */
- handleAction(context, actionId) {
- const target = SDK.targetManager.mainTarget();
- if (target && target.type() === SDK.Target.Type.Frame) {
- target.pageAgent().requestAppBanner();
- Common.console.show();
- }
- return true;
- }
-};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/module.json b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/module.json
index 35ad608dead..49003d37312 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/module.json
@@ -127,13 +127,6 @@
"persistence": "closeable",
"order": 50,
"className": "InspectorMain.RenderingOptionsView"
- },
- {
- "type": "action",
- "category": "Mobile",
- "actionId": "components.request-app-banner",
- "className": "InspectorMain.RequestAppBannerActionDelegate",
- "title": "Add to homescreen"
}
],
"dependencies": [
@@ -142,7 +135,6 @@
],
"scripts": [
"RenderingOptions.js",
- "RequestAppBannerActionDelegate.js",
"InspectorMain.js"
],
"resources": [
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css
index 77eeb51b864..b478b442ab8 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css
@@ -8,7 +8,7 @@
padding: 12px;
}
-label {
+[is=dt-checkbox] {
margin: 0px 0px 10px 0px;
flex: none;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js
index d5c69d7e127..20e51c3df12 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js
@@ -106,7 +106,8 @@ LayersTestRunner.dispatchMouseEvent = function(eventType, button, element, offse
screenY: totalOffset.top - element.scrollTop + offsetY,
clientX: totalOffset.left + offsetX,
clientY: totalOffset.top + offsetY,
- button: button
+ button: button,
+ composed: true
};
if (eventType === 'mouseout') {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/main/Main.js b/chromium/third_party/blink/renderer/devtools/front_end/main/Main.js
index d22ecf4e2da..f8a51b93cda 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/main/Main.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -107,7 +107,6 @@ Main.Main = class {
// Keep this sorted alphabetically: both keys and values.
Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true);
- Runtime.experiments.register('colorContrastRatio', 'Color contrast ratio line in color picker', true);
Runtime.experiments.register('consoleBelowPrompt', 'Console eager evaluation');
Runtime.experiments.register('consoleKeyboardNavigation', 'Console keyboard navigation', true);
Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
@@ -119,6 +118,7 @@ Main.Main = class {
Runtime.experiments.register('protocolMonitor', 'Protocol Monitor');
Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
Runtime.experiments.register('sourceDiff', 'Source diff');
+ Runtime.experiments.register('sourcesLogpoints', 'Sources: logpoints');
Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel');
Runtime.experiments.register(
'stepIntoAsync', 'Introduce separate step action, stepInto becomes powerful enough to go inside async call');
@@ -150,8 +150,8 @@ Main.Main = class {
}
Runtime.experiments.setDefaultExperiments([
- 'colorContrastRatio', 'stepIntoAsync', 'oopifInlineDOM', 'consoleBelowPrompt', 'timelineTracingJSProfile',
- 'pinnedExpressions'
+ 'stepIntoAsync', 'oopifInlineDOM', 'consoleBelowPrompt', 'timelineTracingJSProfile', 'pinnedExpressions',
+ 'consoleKeyboardNavigation', 'sourcesLogpoints'
]);
}
@@ -274,7 +274,7 @@ Main.Main = class {
const instances =
await Promise.all(self.runtime.extensions('early-initialization').map(extension => extension.instance()));
for (const instance of instances)
- /** @type {!Common.Runnable} */ (instance).run();
+ await /** @type {!Common.Runnable} */ (instance).run();
// Used for browser tests.
InspectorFrontendHost.readyForTest();
// Asynchronously run the extensions.
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkDataGridNode.js b/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkDataGridNode.js
index 9b28ddf85f4..e243eeeabde 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkDataGridNode.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkDataGridNode.js
@@ -365,7 +365,8 @@ Network.NetworkRequestNode = class extends Network.NetworkNode {
return 1;
if (aRequest.cached() && !bRequest.cached())
return -1;
- return (aRequest.transferSize - bRequest.transferSize) || aRequest.indentityCompare(bRequest);
+ return (aRequest.transferSize - bRequest.transferSize) || (aRequest.resourceSize - bRequest.resourceSize) ||
+ aRequest.indentityCompare(bRequest);
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkItemView.js b/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkItemView.js
index fce1e91853f..09955a6c9f9 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkItemView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkItemView.js
@@ -49,8 +49,8 @@ Network.NetworkItemView = class extends UI.TabbedPane {
if (request.resourceType() === Common.resourceTypes.WebSocket) {
const frameView = new Network.ResourceWebSocketFrameView(request);
this.appendTab(
- Network.NetworkItemView.Tabs.WsFrames, Common.UIString('Frames'), frameView,
- Common.UIString('WebSocket frames'));
+ Network.NetworkItemView.Tabs.WsFrames, Common.UIString('Messages'), frameView,
+ Common.UIString('WebSocket messages'));
} else if (request.mimeType === 'text/event-stream') {
this.appendTab(
Network.NetworkItemView.Tabs.EventSource, Common.UIString('EventStream'),
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js b/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js
index 20a28059eab..7f81b836cb9 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js
@@ -696,8 +696,10 @@ Network.NetworkLogView = class extends UI.VBox {
this._hideRecordingHint();
let transferSize = 0;
+ let resourceSize = 0;
let selectedNodeNumber = 0;
let selectedTransferSize = 0;
+ let selectedResourceSize = 0;
let baseTime = -1;
let maxTime = -1;
@@ -709,9 +711,12 @@ Network.NetworkLogView = class extends UI.VBox {
nodeCount++;
const requestTransferSize = request.transferSize;
transferSize += requestTransferSize;
+ const requestResourceSize = request.resourceSize;
+ resourceSize += requestResourceSize;
if (!node[Network.NetworkLogView._isFilteredOutSymbol]) {
selectedNodeNumber++;
selectedTransferSize += requestTransferSize;
+ selectedResourceSize += requestResourceSize;
}
const networkManager = SDK.NetworkManager.forRequest(request);
// TODO(allada) inspectedURL should be stored in PageLoad used instead of target so HAR requests can have an
@@ -748,11 +753,17 @@ Network.NetworkLogView = class extends UI.VBox {
appendChunk(separator);
appendChunk(Common.UIString(
'%s / %s transferred', Number.bytesToString(selectedTransferSize), Number.bytesToString(transferSize)));
+ appendChunk(separator);
+ appendChunk(Common.UIString(
+ '%s / %s resources', Number.bytesToString(selectedResourceSize), Number.bytesToString(resourceSize)));
} else {
appendChunk(Common.UIString('%d requests', nodeCount));
appendChunk(separator);
appendChunk(Common.UIString('%s transferred', Number.bytesToString(transferSize)));
+ appendChunk(separator);
+ appendChunk(Common.UIString('%s resources', Number.bytesToString(resourceSize)));
}
+
if (baseTime !== -1 && maxTime !== -1) {
appendChunk(separator);
appendChunk(Common.UIString('Finish: %s', Number.secondsToString(maxTime - baseTime)));
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js b/chromium/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js
index b69345c7414..03f766868ef 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js
@@ -379,7 +379,7 @@ Network.RequestHeadersView = class extends UI.VBox {
statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ': ';
statusCodeFragment.createChild('span', 'header-separator');
- const statusCodeImage = statusCodeFragment.createChild('label', 'resource-status-image', 'dt-icon-label');
+ const statusCodeImage = statusCodeFragment.createChild('span', 'resource-status-image', 'dt-icon-label');
statusCodeImage.title = this._request.statusCode + ' ' + this._request.statusText;
if (this._request.statusCode < 300 || this._request.statusCode === 304)
@@ -442,7 +442,7 @@ Network.RequestHeadersView = class extends UI.VBox {
if (provisionalHeaders) {
const cautionText = Common.UIString('Provisional headers are shown');
const cautionFragment = createDocumentFragment();
- cautionFragment.createChild('label', '', 'dt-icon-label').type = 'smallicon-warning';
+ cautionFragment.createChild('span', '', 'dt-icon-label').type = 'smallicon-warning';
cautionFragment.createChild('div', 'caution').textContent = cautionText;
const cautionTreeElement = new UI.TreeElement(cautionFragment);
cautionTreeElement.selectable = false;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js b/chromium/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js
index 42e8b4115cb..bf364c1230e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js
@@ -84,7 +84,7 @@ Network.ResourceWebSocketFrameView = class extends UI.VBox {
mainContainer.setMinimumSize(0, 72);
this._splitWidget.setMainWidget(mainContainer);
- this._frameEmptyWidget = new UI.EmptyWidget(Common.UIString('Select frame to browse its content.'));
+ this._frameEmptyWidget = new UI.EmptyWidget(Common.UIString('Select message to browse its content.'));
this._splitWidget.setSidebarWidget(this._frameEmptyWidget);
/** @type {?Network.ResourceWebSocketFrameNode} */
@@ -220,11 +220,11 @@ Network.ResourceWebSocketFrameView.opCodeDescriptions = (function() {
const opCodes = Network.ResourceWebSocketFrameView.OpCodes;
const map = [];
map[opCodes.ContinuationFrame] = 'Continuation Frame';
- map[opCodes.TextFrame] = 'Text Frame';
- map[opCodes.BinaryFrame] = 'Binary Frame';
- map[opCodes.ContinuationFrame] = 'Connection Close Frame';
- map[opCodes.PingFrame] = 'Ping Frame';
- map[opCodes.PongFrame] = 'Pong Frame';
+ map[opCodes.TextFrame] = 'Text Message';
+ map[opCodes.BinaryFrame] = 'Binary Message';
+ map[opCodes.ContinuationFrame] = 'Connection Close Message';
+ map[opCodes.PingFrame] = 'Ping Message';
+ map[opCodes.PongFrame] = 'Pong Message';
return map;
})();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js b/chromium/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js
index 9de48346d50..dfd8daef95f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js
@@ -59,7 +59,6 @@ Network.SignedExchangeInfoView = class extends UI.VBox {
requestURLElement.appendChild(viewRequestLink);
}
headerCategory.createLeaf(requestURLElement);
- headerCategory.createLeaf(this._formatHeader(Common.UIString('Request method'), header.requestMethod));
headerCategory.createLeaf(this._formatHeader(Common.UIString('Response code'), header.responseCode + ''));
this._responseHeadersItem =
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css b/chromium/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css
index 6c5ede0de91..df86aa28e24 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css
@@ -57,11 +57,11 @@
line-height: 20px;
}
-.network-config-ua label[is="dt-radio"].checked > * {
+.network-config-ua span[is="dt-radio"].checked > * {
display: none
}
-.network-config-ua input:not(.dt-radio-button) {
+.network-config-ua input {
display: block;
width: calc(100% - 20px);
}
@@ -79,7 +79,7 @@
max-width: 250px;
}
-.network-config-ua label[is="dt-radio"] {
+.network-config-ua span[is="dt-radio"] {
display: block;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/networkLogView.css b/chromium/third_party/blink/renderer/devtools/front_end/network/networkLogView.css
index 2a1d831bf0a..eaeb07a478f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/networkLogView.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/networkLogView.css
@@ -44,7 +44,7 @@
overflow: hidden;
}
-.network-summary-bar label[is=dt-icon-label] {
+.network-summary-bar span[is=dt-icon-label] {
margin-right: 6px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/network/networkPanel.css b/chromium/third_party/blink/renderer/devtools/front_end/network/networkPanel.css
index 1791144dc4e..7e31424b366 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/network/networkPanel.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/network/networkPanel.css
@@ -37,7 +37,7 @@
}
.network-details-view-tall-header {
- margin-top: 4px;
+ border-top: 4px solid var(--toolbar-bg-color);
}
.network-item-view {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js b/chromium/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js
index 238c19d13c9..7ecef0ee879 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js
@@ -489,7 +489,9 @@ ObjectUI.JavaScriptAutocomplete = class {
'queryObjects',
'$',
'$$',
- '$x'
+ '$x',
+ '$0',
+ '$_'
];
propertyGroups.push({items: commandLineAPI});
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js b/chromium/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
index 745339d1ae9..0f5acb892e9 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
@@ -344,9 +344,10 @@ ObjectUI.ObjectPropertiesSection = class extends UI.TreeOutlineInShadow {
* @param {!Element} element
* @param {boolean} linkify
* @param {boolean=} includePreview
+ * @return {!Promise}
*/
static formatObjectAsFunction(func, element, linkify, includePreview) {
- func.debuggerModel().functionDetailsPromise(func).then(didGetDetails);
+ return func.debuggerModel().functionDetailsPromise(func).then(didGetDetails);
/**
* @param {?SDK.DebuggerModel.FunctionDetails} response
@@ -431,7 +432,7 @@ ObjectUI.ObjectPropertiesSection.RootElement = class extends UI.TreeElement {
* @param {!Array.<!SDK.RemoteObjectProperty>=} extraProperties
*/
constructor(object, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties) {
- const contentElement = createElement('content');
+ const contentElement = createElement('slot');
super(contentElement);
this._object = object;
@@ -1402,4 +1403,4 @@ ObjectUI.ObjectPropertiesSection.Renderer = class {
return Promise.resolve(
/** @type {?{node: !Node, tree: ?UI.TreeOutline}} */ ({node: section.element, tree: section}));
}
-}; \ No newline at end of file
+};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css b/chromium/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
index 1ef1a87609d..89892c72c96 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
@@ -54,7 +54,7 @@
.name-and-value {
overflow: hidden;
text-overflow: ellipsis;
- line-height: normal;
+ line-height: 16px;
}
.editing-sub-part .name-and-value {
@@ -65,3 +65,14 @@
.property-prompt {
margin-left: 4px;
}
+
+.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] {
+ background: none;
+}
+
+.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] ::slotted(*),
+.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] .name-and-value {
+ background: var(--focus-bg-color);
+ border-radius: 2px;
+ box-shadow: 0px 0px 0px 2px var(--focus-bg-color);
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/performance_test_runner/TimelineTestRunner.js b/chromium/third_party/blink/renderer/devtools/front_end/performance_test_runner/TimelineTestRunner.js
index c6efc2de4ec..34dd1939afb 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/performance_test_runner/TimelineTestRunner.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/performance_test_runner/TimelineTestRunner.js
@@ -82,8 +82,8 @@ PerformanceTestRunner.tracingModel = function() {
};
PerformanceTestRunner.invokeWithTracing = function(functionName, callback, additionalCategories, enableJSSampling) {
- let categories =
- '-*,disabled-by-default-devtools.timeline*,devtools.timeline,' + SDK.TracingModel.TopLevelEventCategory;
+ let categories = '-*,disabled-by-default-devtools.timeline*,devtools.timeline,blink.user_timing,' +
+ SDK.TracingModel.TopLevelEventCategory;
if (additionalCategories)
categories += ',' + additionalCategories;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/platform/utilities.js b/chromium/third_party/blink/renderer/devtools/front_end/platform/utilities.js
index fb0d8d1eaa9..ae7c0764cf3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/platform/utilities.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/platform/utilities.js
@@ -144,6 +144,32 @@ String.filterRegex = function(query) {
};
/**
+ * @param {string} text
+ * @return {string}
+ */
+String.escapeInvalidUnicodeCharacters = function(text) {
+ if (!String._invalidCharactersRegExp) {
+ // Escape orphan surrogates and invalid characters.
+ let invalidCharacters = '';
+ for (let i = 0xfffe; i <= 0x10ffff; i += 0x10000)
+ invalidCharacters += String.fromCodePoint(i, i + 1);
+ String._invalidCharactersRegExp = new RegExp(`[${invalidCharacters}\uD800-\uDFFF\uFDD0-\uFDEF]`, 'gu');
+ }
+ let result = '';
+ let lastPos = 0;
+ while (true) {
+ const match = String._invalidCharactersRegExp.exec(text);
+ if (!match)
+ break;
+ result += text.substring(lastPos, match.index) + '\\u' + text.charCodeAt(match.index).toString(16);
+ if (match.index + 1 < String._invalidCharactersRegExp.lastIndex)
+ result += '\\u' + text.charCodeAt(match.index + 1).toString(16);
+ lastPos = String._invalidCharactersRegExp.lastIndex;
+ }
+ return result + text.substring(lastPos);
+};
+
+/**
* @return {string}
*/
String.prototype.escapeHTML = function() {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js b/chromium/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
index e60c72bfab1..09f2ed554dd 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
@@ -231,9 +231,9 @@ Profiler.HeapTimelineOverview = class extends UI.VBox {
const minIndex = timestamps.lowerBound(timeLeft);
const maxIndex = timestamps.upperBound(timeRight);
let size = 0;
- for (let i = minIndex; i < maxIndex; ++i)
+ for (let i = minIndex; i <= maxIndex; ++i)
size += sizes[i];
- const minId = minIndex < ids.length ? ids[minIndex] : Infinity;
+ const minId = minIndex > 0 ? ids[minIndex - 1] : 0;
const maxId = maxIndex < ids.length ? ids[maxIndex] : Infinity;
this.dispatchEventToListeners(Profiler.HeapTimelineOverview.IdsRangeChanged, {minId, maxId, size});
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/profiler/ProfilesPanel.js b/chromium/third_party/blink/renderer/devtools/front_end/profiler/ProfilesPanel.js
index eb7ffe825b1..d3383a05d0b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/profiler/ProfilesPanel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/profiler/ProfilesPanel.js
@@ -98,6 +98,8 @@ Profiler.ProfilesPanel = class extends UI.PanelWithSidebar {
this.contentElement.addEventListener('keydown', this._onKeyDown.bind(this), false);
SDK.targetManager.addEventListener(SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged, this);
+ UI.context.addFlavorChangeListener(SDK.CPUProfilerModel, this._updateProfileTypeSpecificUI, this);
+ UI.context.addFlavorChangeListener(SDK.HeapProfilerModel, this._updateProfileTypeSpecificUI, this);
}
/**
@@ -189,7 +191,8 @@ Profiler.ProfilesPanel = class extends UI.PanelWithSidebar {
* @param {boolean} toggled
*/
_updateToggleRecordAction(toggled) {
- const enable = toggled || !SDK.targetManager.allTargetsSuspended();
+ const hasSelectedTarget = !!(UI.context.flavor(SDK.CPUProfilerModel) || UI.context.flavor(SDK.HeapProfilerModel));
+ const enable = toggled || (!SDK.targetManager.allTargetsSuspended() && hasSelectedTarget);
this._toggleRecordAction.setEnabled(enable);
this._toggleRecordAction.setToggled(toggled);
if (enable)
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css b/chromium/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css
index a44bd156ab2..4849d7b36c3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css
@@ -128,7 +128,7 @@
margin: 0 0 5px 0;
}
-.profile-launcher-view-content label {
+.profile-launcher-view-content [is=dt-radio] {
font-size: 13px;
}
@@ -165,7 +165,7 @@
margin-left: 22px;
}
-.profile-launcher-view-content p label {
+.profile-launcher-view-content p [is=dt-checkbox] {
display: flex;
}
@@ -190,7 +190,7 @@ body.inactive .profile-launcher-view-content button.running:not(.toolbar-item) {
to { background-color: rgba(255, 255, 120, 0); }
}
-.profile-canvas-decoration label[is=dt-icon-label] {
+.profile-canvas-decoration span[is=dt-icon-label] {
margin-right: 4px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/ProtocolMonitor.js b/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/ProtocolMonitor.js
index b7208303b3e..cb0f4365af5 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/ProtocolMonitor.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/ProtocolMonitor.js
@@ -48,6 +48,8 @@ ProtocolMonitor.ProtocolMonitor = class extends UI.VBox {
DataGrid.DataGrid.Events.SelectedNode, event => this._infoWidget.render(event.data.data));
this._dataGrid.addEventListener(DataGrid.DataGrid.Events.DeselectedNode, event => this._infoWidget.render(null));
this._dataGrid.setHeaderContextMenuCallback(this._innerHeaderContextMenu.bind(this));
+ this._dataGrid.setRowContextMenuCallback(this._innerRowContextMenu.bind(this));
+
this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged, this._sortDataGrid.bind(this));
this._dataGrid.setStickToBottom(true);
@@ -65,9 +67,12 @@ ProtocolMonitor.ProtocolMonitor = class extends UI.VBox {
const filters = this._filterParser.parse(query);
this._filter = node => {
for (const {key, text, negative} of filters) {
- if (!(key in node.data) || !text)
+ if (!text)
+ continue;
+ const data = key ? node.data[key] : node.data;
+ if (!data)
continue;
- const found = JSON.stringify(node.data[key]).indexOf(text) !== -1;
+ const found = JSON.stringify(data).toLowerCase().indexOf(text.toLowerCase()) !== -1;
if (found === negative)
return false;
}
@@ -102,6 +107,22 @@ ProtocolMonitor.ProtocolMonitor = class extends UI.VBox {
}
/**
+ * @param {!UI.ContextMenu} contextMenu
+ * @param {!ProtocolMonitor.ProtocolMonitor.ProtocolNode} node
+ */
+ _innerRowContextMenu(contextMenu, node) {
+ contextMenu.defaultSection().appendItem(ls`Filter`, () => {
+ this._textFilterUI.setValue(`method:${node.data.method}`, true);
+ });
+ contextMenu.defaultSection().appendItem(ls`Documentation`, () => {
+ const [domain, method] = node.data.method.split('.');
+ const type = node.data.direction === 'sent' ? 'method' : 'event';
+ InspectorFrontendHost.openInNewTab(
+ `https://chromedevtools.github.io/devtools-protocol/tot/${domain}#${type}-${method}`);
+ });
+ }
+
+ /**
* @param {!Object} columnConfig
*/
_toggleColumnVisibility(columnConfig) {
@@ -164,7 +185,8 @@ ProtocolMonitor.ProtocolMonitor = class extends UI.VBox {
const node = this._nodeForId[message.id];
if (!node)
return;
- node.data.response = message.result;
+ node.data.response = message.result || message.error;
+ node.hasError = !!message.error;
node.refresh();
if (this._dataGrid.selectedNode === node)
this._infoWidget.render(node.data);
@@ -201,6 +223,7 @@ ProtocolMonitor.ProtocolMonitor = class extends UI.VBox {
ProtocolMonitor.ProtocolMonitor.ProtocolNode = class extends DataGrid.SortableDataGridNode {
constructor(data) {
super(data);
+ this.hasError = false;
}
/**
@@ -241,6 +264,7 @@ ProtocolMonitor.ProtocolMonitor.ProtocolNode = class extends DataGrid.SortableDa
const element = super.element();
element.classList.toggle('protocol-message-sent', this.data.direction === 'sent');
element.classList.toggle('protocol-message-recieved', this.data.direction !== 'sent');
+ element.classList.toggle('error', this.hasError);
return element;
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/protocolMonitor.css b/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/protocolMonitor.css
index 5787a072253..1c511de8d5c 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/protocolMonitor.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/protocol_monitor/protocolMonitor.css
@@ -30,3 +30,8 @@
.protocol-monitor-toolbar {
border-bottom:var(--divider-border);
}
+
+.error {
+ background-color: hsl(0, 100%, 97%);
+ color: red;
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js
index 58cef467d77..b0af86b000b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
- * @implements {SDK.SDKModelObserver<!SDK.ResourceTreeModel>}
+ * @implements {SDK.TargetManager.Observer}
* @unrestricted
*/
Resources.AppManifestView = class extends UI.VBox {
@@ -25,13 +25,8 @@ Resources.AppManifestView = class extends UI.VBox {
this._reportView.hideWidget();
this._errorsSection = this._reportView.appendSection(Common.UIString('Errors and warnings'));
+ this._installabilitySection = this._reportView.appendSection(Common.UIString('Installability'));
this._identitySection = this._reportView.appendSection(Common.UIString('Identity'));
- const toolbar = this._identitySection.createToolbar();
- toolbar.renderAsLinks();
- const addToHomeScreen =
- new UI.ToolbarButton(Common.UIString('Add to homescreen'), undefined, Common.UIString('Add to homescreen'));
- addToHomeScreen.addEventListener(UI.ToolbarButton.Events.Click, this._addToHomescreen, this);
- toolbar.appendToolbarItem(addToHomeScreen);
this._presentationSection = this._reportView.appendSection(Common.UIString('Presentation'));
this._iconsSection = this._reportView.appendSection(Common.UIString('Icons'));
@@ -52,34 +47,53 @@ Resources.AppManifestView = class extends UI.VBox {
this._orientationField = this._presentationSection.appendField(Common.UIString('Orientation'));
this._displayField = this._presentationSection.appendField(Common.UIString('Display'));
- SDK.targetManager.observeModels(SDK.ResourceTreeModel, this);
+ this._throttler = new Common.Throttler(1000);
+ SDK.targetManager.observeTargets(this);
}
/**
* @override
- * @param {!SDK.ResourceTreeModel} resourceTreeModel
+ * @param {!SDK.Target} target
*/
- modelAdded(resourceTreeModel) {
- if (this._resourceTreeModel)
+ targetAdded(target) {
+ if (this._target)
return;
- this._resourceTreeModel = resourceTreeModel;
- this._updateManifest();
- resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.MainFrameNavigated, this._updateManifest, this);
+ this._target = target;
+ this._resourceTreeModel = target.model(SDK.ResourceTreeModel);
+ this._serviceWorkerManager = target.model(SDK.ServiceWorkerManager);
+ if (!this._resourceTreeModel || !this._serviceWorkerManager)
+ return;
+
+ this._updateManifest(true);
+
+ this._registeredListeners = [
+ this._resourceTreeModel.addEventListener(
+ SDK.ResourceTreeModel.Events.DOMContentLoaded, this._updateManifest.bind(this, true)),
+ this._serviceWorkerManager.addEventListener(
+ SDK.ServiceWorkerManager.Events.RegistrationUpdated, this._updateManifest.bind(this, false))
+ ];
}
/**
* @override
- * @param {!SDK.ResourceTreeModel} resourceTreeModel
+ * @param {!SDK.Target} target
*/
- modelRemoved(resourceTreeModel) {
- if (!this._resourceTreeModel || this._resourceTreeModel !== resourceTreeModel)
+ targetRemoved(target) {
+ if (this._target !== target)
+ return;
+ if (!this._resourceTreeModel || !this._serviceWorkerManager)
return;
- resourceTreeModel.removeEventListener(SDK.ResourceTreeModel.Events.MainFrameNavigated, this._updateManifest, this);
delete this._resourceTreeModel;
+ delete this._serviceWorkerManager;
+ Common.EventTarget.removeEventListeners(this._registeredListeners);
}
- _updateManifest() {
- this._resourceTreeModel.fetchAppManifest(this._renderManifest.bind(this));
+ /**
+ * @param {boolean} immediately
+ */
+ async _updateManifest(immediately) {
+ const {url, data, errors} = await this._resourceTreeModel.fetchAppManifest();
+ this._throttler.schedule(() => this._renderManifest(url, data, errors), immediately);
}
/**
@@ -87,7 +101,7 @@ Resources.AppManifestView = class extends UI.VBox {
* @param {?string} data
* @param {!Array<!Protocol.Page.AppManifestError>} errors
*/
- _renderManifest(url, data, errors) {
+ async _renderManifest(url, data, errors) {
if (!data && !errors.length) {
this._emptyView.showWidget();
this._reportView.hideWidget();
@@ -107,19 +121,31 @@ Resources.AppManifestView = class extends UI.VBox {
if (!data)
return;
+ const installabilityErrors = [];
+
if (data.charCodeAt(0) === 0xFEFF)
data = data.slice(1); // Trim the BOM as per https://tools.ietf.org/html/rfc7159#section-8.1.
const parsedManifest = JSON.parse(data);
this._nameField.textContent = stringProperty('name');
this._shortNameField.textContent = stringProperty('short_name');
+ if (!this._nameField.textContent && !this._shortNameField.textContent)
+ installabilityErrors.push(ls`Either 'name' or 'short_name' is required`);
+
this._startURLField.removeChildren();
const startURL = stringProperty('start_url');
if (startURL) {
const completeURL = /** @type {string} */ (Common.ParsedURL.completeURL(url, startURL));
this._startURLField.appendChild(Components.Linkifier.linkifyURL(completeURL, {text: startURL}));
+ if (!this._serviceWorkerManager.hasRegistrationForURLs([completeURL, this._target.inspectedURL()]))
+ installabilityErrors.push(ls`Service worker is not registered or does not control the Start URL`);
+ else if (!await this._swHasFetchHandler())
+ installabilityErrors.push(ls`Service worker does not have the 'fetch' handler`);
+ } else {
+ installabilityErrors.push(ls`'start_url' needs to be a valid URL`);
}
+
this._themeColorSwatch.classList.toggle('hidden', !stringProperty('theme_color'));
const themeColor = Common.Color.parse(stringProperty('theme_color') || 'white') || Common.Color.parse('white');
this._themeColorSwatch.setColor(/** @type {!Common.Color} */ (themeColor));
@@ -129,18 +155,40 @@ Resources.AppManifestView = class extends UI.VBox {
this._backgroundColorSwatch.setColor(/** @type {!Common.Color} */ (backgroundColor));
this._orientationField.textContent = stringProperty('orientation');
- this._displayField.textContent = stringProperty('display');
+ const displayType = stringProperty('display');
+ this._displayField.textContent = displayType;
+ if (!['minimal-ui', 'standalone', 'fullscreen'].includes(displayType))
+ installabilityErrors.push(ls`'display' property must be set to 'standalone', 'fullscreen' or 'minimal-ui'`);
const icons = parsedManifest['icons'] || [];
+ let hasInstallableIcon = false;
this._iconsSection.clearContent();
+
for (const icon of icons) {
+ if (!icon.sizes)
+ hasInstallableIcon = true; // any
const title = (icon['sizes'] || '') + '\n' + (icon['type'] || '');
+ try {
+ const widthHeight = icon['sizes'].split('x');
+ if (parseInt(widthHeight[0], 10) >= 144 && parseInt(widthHeight[1], 10) >= 144)
+ hasInstallableIcon = true;
+ } catch (e) {
+ }
+
const field = this._iconsSection.appendField(title);
- const imageElement = field.createChild('img');
- imageElement.style.maxWidth = '200px';
- imageElement.style.maxHeight = '200px';
- imageElement.src = Common.ParsedURL.completeURL(url, icon['src']);
+ const image = await this._loadImage(Common.ParsedURL.completeURL(url, icon['src']));
+ if (image)
+ field.appendChild(image);
+ else
+ installabilityErrors.push(ls`Some of the icons could not be loaded`);
}
+ if (!hasInstallableIcon)
+ installabilityErrors.push(ls`An icon at least 144px x 144px large is required`);
+
+ this._installabilitySection.clearContent();
+ this._installabilitySection.element.classList.toggle('hidden', !installabilityErrors.length);
+ for (const error of installabilityErrors)
+ this._installabilitySection.appendRow().appendChild(UI.createLabel(error, 'smallicon-warning'));
/**
* @param {string} name
@@ -155,13 +203,49 @@ Resources.AppManifestView = class extends UI.VBox {
}
/**
- * @param {!Common.Event} event
+ * @return {!Promise<boolean>}
+ */
+ async _swHasFetchHandler() {
+ for (const target of SDK.targetManager.targets()) {
+ if (target.type() !== SDK.Target.Type.Worker)
+ continue;
+ if (!target.parentTarget() || target.parentTarget().type() !== SDK.Target.Type.ServiceWorker)
+ continue;
+
+ const ec = target.model(SDK.RuntimeModel).defaultExecutionContext();
+ const result = await ec.evaluate(
+ {
+ expression: `'fetch' in getEventListeners(self)`,
+ includeCommandLineAPI: true,
+ silent: true,
+ returnByValue: true
+ },
+ false, false);
+ if (!result.object || !result.object.value)
+ continue;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param {?string} url
+ * @return {!Promise<?Image>}
*/
- _addToHomescreen(event) {
- const target = SDK.targetManager.mainTarget();
- if (target && target.type() === SDK.Target.Type.Frame) {
- target.pageAgent().requestAppBanner();
- Common.console.show();
+ async _loadImage(url) {
+ const image = createElement('img');
+ image.style.maxWidth = '200px';
+ image.style.maxHeight = '200px';
+ const result = new Promise((f, r) => {
+ image.onload = f;
+ image.onerror = r;
+ });
+ image.src = url;
+ try {
+ await result;
+ return image;
+ } catch (e) {
}
+ return null;
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js
index 6c2373b78ea..f83a6b6660d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js
@@ -38,9 +38,9 @@ Resources.ApplicationCacheItemsView = class extends UI.SimpleView {
this._deleteButton.setVisible(false);
this._deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteButtonClicked, this);
- this._connectivityIcon = createElement('label', 'dt-icon-label');
+ this._connectivityIcon = createElement('span', 'dt-icon-label');
this._connectivityIcon.style.margin = '0 2px 0 5px';
- this._statusIcon = createElement('label', 'dt-icon-label');
+ this._statusIcon = createElement('span', 'dt-icon-label');
this._statusIcon.style.margin = '0 2px 0 5px';
this._frameId = frameId;
@@ -105,20 +105,26 @@ Resources.ApplicationCacheItemsView = class extends UI.SimpleView {
const statusInformation = {};
// We should never have UNCACHED status, since we remove frames with UNCACHED application cache status from the tree.
- statusInformation[applicationCache.UNCACHED] = {type: 'smallicon-red-ball', text: 'UNCACHED'};
- statusInformation[applicationCache.IDLE] = {type: 'smallicon-green-ball', text: 'IDLE'};
- statusInformation[applicationCache.CHECKING] = {type: 'smallicon-orange-ball', text: 'CHECKING'};
- statusInformation[applicationCache.DOWNLOADING] = {type: 'smallicon-orange-ball', text: 'DOWNLOADING'};
- statusInformation[applicationCache.UPDATEREADY] = {type: 'smallicon-green-ball', text: 'UPDATEREADY'};
- statusInformation[applicationCache.OBSOLETE] = {type: 'smallicon-red-ball', text: 'OBSOLETE'};
-
- const info = statusInformation[status] || statusInformation[applicationCache.UNCACHED];
+ statusInformation[Resources.ApplicationCacheModel.UNCACHED] = {type: 'smallicon-red-ball', text: 'UNCACHED'};
+ statusInformation[Resources.ApplicationCacheModel.IDLE] = {type: 'smallicon-green-ball', text: 'IDLE'};
+ statusInformation[Resources.ApplicationCacheModel.CHECKING] = {type: 'smallicon-orange-ball', text: 'CHECKING'};
+ statusInformation[Resources.ApplicationCacheModel.DOWNLOADING] = {
+ type: 'smallicon-orange-ball',
+ text: 'DOWNLOADING'
+ };
+ statusInformation[Resources.ApplicationCacheModel.UPDATEREADY] = {
+ type: 'smallicon-green-ball',
+ text: 'UPDATEREADY'
+ };
+ statusInformation[Resources.ApplicationCacheModel.OBSOLETE] = {type: 'smallicon-red-ball', text: 'OBSOLETE'};
+
+ const info = statusInformation[status] || statusInformation[Resources.ApplicationCacheModel.UNCACHED];
this._statusIcon.type = info.type;
this._statusIcon.textContent = info.text;
- if (this.isShowing() && this._status === applicationCache.IDLE &&
- (oldStatus === applicationCache.UPDATEREADY || !this._resources))
+ if (this.isShowing() && this._status === Resources.ApplicationCacheModel.IDLE &&
+ (oldStatus === Resources.ApplicationCacheModel.UPDATEREADY || !this._resources))
this._markDirty();
this._maybeUpdate();
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheModel.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheModel.js
index ffed9b60bbd..41c076e3bef 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheModel.js
@@ -93,7 +93,7 @@ Resources.ApplicationCacheModel = class extends SDK.SDKModel {
* @param {number} status
*/
_frameManifestUpdated(frameId, manifestURL, status) {
- if (status === applicationCache.UNCACHED) {
+ if (status === Resources.ApplicationCacheModel.UNCACHED) {
this._frameManifestRemoved(frameId);
return;
}
@@ -142,7 +142,7 @@ Resources.ApplicationCacheModel = class extends SDK.SDKModel {
* @return {number}
*/
frameManifestStatus(frameId) {
- return this._statuses[frameId] || applicationCache.UNCACHED;
+ return this._statuses[frameId] || Resources.ApplicationCacheModel.UNCACHED;
}
/**
@@ -216,3 +216,10 @@ Resources.ApplicationCacheDispatcher = class {
this._applicationCacheModel._networkStateUpdated(isNowOnline);
}
};
+
+Resources.ApplicationCacheModel.UNCACHED = 0;
+Resources.ApplicationCacheModel.IDLE = 1;
+Resources.ApplicationCacheModel.CHECKING = 2;
+Resources.ApplicationCacheModel.DOWNLOADING = 3;
+Resources.ApplicationCacheModel.UPDATEREADY = 4;
+Resources.ApplicationCacheModel.OBSOLETE = 5;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js
index 4d6b72765bd..9c6e6ad9e31 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js
@@ -1211,7 +1211,8 @@ Resources.IDBDatabaseTreeElement = class extends Resources.BaseStorageTreeElemen
update(database, entriesUpdated) {
this._database = database;
const objectStoreNames = {};
- for (const objectStoreName in this._database.objectStores) {
+ const objectStoreNamesSorted = Object.keys(this._database.objectStores).sort();
+ for (const objectStoreName of objectStoreNamesSorted) {
const objectStore = this._database.objectStores[objectStoreName];
objectStoreNames[objectStore.name] = true;
if (!this._idbObjectStoreTreeElements[objectStore.name]) {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
index c102c67324a..63382fb718a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
@@ -209,8 +209,6 @@ Resources.IDBDataView = class extends UI.SimpleView {
const editorToolbar = new UI.Toolbar('data-view-toolbar', this.element);
editorToolbar.appendToolbarItem(this._refreshButton);
- editorToolbar.appendToolbarItem(this._clearButton);
- editorToolbar.appendToolbarItem(this._deleteSelectedButton);
editorToolbar.appendToolbarItem(new UI.ToolbarSeparator());
@@ -226,6 +224,9 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._keyInput = new UI.ToolbarInput(ls`Start from key`, 0.5);
this._keyInput.addEventListener(UI.ToolbarInput.Event.TextChanged, this._updateData.bind(this, false));
editorToolbar.appendToolbarItem(this._keyInput);
+ editorToolbar.appendToolbarItem(new UI.ToolbarSeparator());
+ editorToolbar.appendToolbarItem(this._clearButton);
+ editorToolbar.appendToolbarItem(this._deleteSelectedButton);
editorToolbar.appendToolbarItem(this._needsRefresh);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkerCacheViews.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkerCacheViews.js
index 1b43324e8df..f8f553afbe1 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkerCacheViews.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkerCacheViews.js
@@ -55,12 +55,32 @@ Resources.ServiceWorkerCacheView = class extends UI.SimpleView {
this._deleteSelectedButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._deleteButtonClicked(null));
editorToolbar.appendToolbarItem(this._deleteSelectedButton);
+ const entryPathFilterBox = new UI.ToolbarInput(ls`Filter by Path`, 1);
+ editorToolbar.appendToolbarItem(entryPathFilterBox);
+ const entryPathFilterThrottler = new Common.Throttler(300);
+ this._entryPathFilter = '';
+ entryPathFilterBox.addEventListener(UI.ToolbarInput.Event.TextChanged, () => {
+ entryPathFilterThrottler.schedule(() => {
+ this._entryPathFilter = entryPathFilterBox.value();
+ this._skipCount = 0;
+ return this._updateData(true);
+ });
+ });
+
this._pageSize = 50;
this._skipCount = 0;
this.update(cache);
}
+ _resetDataGrid() {
+ if (this._dataGrid)
+ this._dataGrid.asWidget().detach();
+ this._dataGrid = this._createDataGrid();
+ this._splitWidget.setSidebarWidget(this._dataGrid.asWidget());
+ this._skipCount = 0;
+ }
+
/**
* @override
*/
@@ -185,12 +205,7 @@ Resources.ServiceWorkerCacheView = class extends UI.SimpleView {
*/
update(cache) {
this._cache = cache;
-
- if (this._dataGrid)
- this._dataGrid.asWidget().detach();
- this._dataGrid = this._createDataGrid();
- this._splitWidget.setSidebarWidget(this._dataGrid.asWidget());
- this._skipCount = 0;
+ this._resetDataGrid();
this._updateData(true);
}
@@ -247,7 +262,13 @@ Resources.ServiceWorkerCacheView = class extends UI.SimpleView {
}
this._lastPageSize = pageSize;
this._lastSkipCount = skipCount;
- this._model.loadCacheData(this._cache, skipCount, pageSize, this._updateDataCallback.bind(this, skipCount));
+
+ return new Promise(resolve => {
+ this._model.loadCacheData(this._cache, skipCount, pageSize, this._entryPathFilter, (entries, hasMore) => {
+ this._updateDataCallback(skipCount, entries, hasMore);
+ resolve();
+ });
+ });
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js
index c0ef89cb815..d4bd116d6e0 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js
@@ -60,12 +60,12 @@ Resources.ServiceWorkersView = class extends UI.VBox {
const updateOnReloadSetting = Common.settings.createSetting('serviceWorkerUpdateOnReload', false);
updateOnReloadSetting.setTitle(Common.UIString('Update on reload'));
const forceUpdate = new UI.ToolbarSettingCheckbox(
- updateOnReloadSetting, Common.UIString('Force update Service Worker on page reload'));
+ updateOnReloadSetting, ls`On page reload, force the service worker to update, and activate it`);
this._toolbar.appendToolbarItem(forceUpdate);
const bypassServiceWorkerSetting = Common.settings.createSetting('bypassServiceWorker', false);
bypassServiceWorkerSetting.setTitle(Common.UIString('Bypass for network'));
const fallbackToNetwork = new UI.ToolbarSettingCheckbox(
- bypassServiceWorkerSetting, Common.UIString('Bypass Service Worker and load resources from the network'));
+ bypassServiceWorkerSetting, ls`Bypass the service worker and load resources from the network`);
this._toolbar.appendToolbarItem(fallbackToNetwork);
/** @type {!Map<!SDK.ServiceWorkerManager, !Array<!Common.EventTarget.EventDescriptor>>}*/
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/resources/StorageItemsView.js b/chromium/third_party/blink/renderer/devtools/front_end/resources/StorageItemsView.js
index eae64142d8b..dcc937e6bf2 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/resources/StorageItemsView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/resources/StorageItemsView.js
@@ -12,9 +12,6 @@ Resources.StorageItemsView = class extends UI.VBox {
/** @type {?RegExp} */
this._filterRegex = null;
- this._deleteAllButton = this._addButton(Common.UIString('Clear All'), 'largeicon-clear', this.deleteAllItems);
- this._deleteSelectedButton =
- this._addButton(Common.UIString('Delete Selected'), 'largeicon-delete', this.deleteSelectedItem);
this._refreshButton = this._addButton(Common.UIString('Refresh'), 'largeicon-refresh', this.refreshItems);
this._mainToolbar = new UI.Toolbar('top-resources-toolbar', this.element);
@@ -22,7 +19,13 @@ Resources.StorageItemsView = class extends UI.VBox {
this._filterItem = new UI.ToolbarInput(Common.UIString('Filter'), 0.4);
this._filterItem.addEventListener(UI.ToolbarInput.Event.TextChanged, this._filterChanged, this);
- const toolbarItems = [this._refreshButton, this._deleteAllButton, this._deleteSelectedButton, this._filterItem];
+ const toolbarSeparator = new UI.ToolbarSeparator();
+ this._deleteAllButton = this._addButton(Common.UIString('Clear All'), 'largeicon-clear', this.deleteAllItems);
+ this._deleteSelectedButton =
+ this._addButton(Common.UIString('Delete Selected'), 'largeicon-delete', this.deleteSelectedItem);
+
+ const toolbarItems =
+ [this._refreshButton, this._filterItem, toolbarSeparator, this._deleteAllButton, this._deleteSelectedButton];
for (const item of toolbarItems)
this._mainToolbar.appendToolbarItem(item);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/screencast/InputModel.js b/chromium/third_party/blink/renderer/devtools/front_end/screencast/InputModel.js
index 3006f396256..e4d674ce917 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/screencast/InputModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/screencast/InputModel.js
@@ -94,7 +94,7 @@ Screencast.InputModel = class extends SDK.SDKModel {
}
cancelTouch() {
- if (this._activeTouchOffsetTop !== null) {
+ if (this._activeTouchParams !== null) {
const params = this._activeTouchParams;
this._activeTouchParams = null;
params.type = 'mouseReleased';
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/screencast/ScreencastView.js b/chromium/third_party/blink/renderer/devtools/front_end/screencast/ScreencastView.js
index 8117e9d2faf..6378f85f867 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/screencast/ScreencastView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/screencast/ScreencastView.js
@@ -172,7 +172,7 @@ Screencast.ScreencastView = class extends UI.VBox {
this._viewportElement.style.width = metadata.deviceWidth * this._screenZoom + bordersSize + 'px';
this._viewportElement.style.height = metadata.deviceHeight * this._screenZoom + bordersSize + 'px';
- this.highlightDOMNode(this._highlightNode, this._highlightConfig);
+ this.highlightInOverlay({node: this._highlightNode}, this._highlightConfig);
};
this._imageElement.src = 'data:image/jpg;base64,' + base64Data;
}
@@ -243,10 +243,10 @@ Screencast.ScreencastView = class extends UI.VBox {
if (!node)
return;
if (event.type === 'mousemove') {
- this.highlightDOMNode(node, this._inspectModeConfig);
+ this.highlightInOverlay({node}, this._inspectModeConfig);
this._domModel.overlayModel().nodeHighlightRequested(node.id);
} else if (event.type === 'click') {
- Common.Revealer.reveal(node);
+ this._domModel.overlayModel().inspectNodeRequested(node.backendNodeId());
}
}
@@ -313,12 +313,28 @@ Screencast.ScreencastView = class extends UI.VBox {
/**
* @override
- * @param {?SDK.DOMNode} node
+ * @param {!SDK.OverlayModel.HighlightData} data
* @param {?Protocol.Overlay.HighlightConfig} config
- * @param {!Protocol.DOM.BackendNodeId=} backendNodeId
- * @param {!Protocol.Runtime.RemoteObjectId=} objectId
*/
- highlightDOMNode(node, config, backendNodeId, objectId) {
+ highlightInOverlay(data, config) {
+ this._highlightInOverlay(data, config);
+ }
+
+ /**
+ * @param {!SDK.OverlayModel.HighlightData} data
+ * @param {?Protocol.Overlay.HighlightConfig} config
+ */
+ async _highlightInOverlay(data, config) {
+ const {node: n, deferredNode, object} = data;
+ let node = n;
+ if (!node && deferredNode)
+ node = await deferredNode.resolvePromise();
+ if (!node && object) {
+ const domModel = object.runtimeModel().target().model(SDK.DOMModel);
+ if (domModel)
+ node = await domModel.pushObjectAsNodeToFrontend(object);
+ }
+
this._highlightNode = node;
this._highlightConfig = config;
if (!node) {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js
index b27a970036a..506d30b8162 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/CSSModel.js
@@ -641,7 +641,7 @@ SDK.SDKModel.register(SDK.CSSModel, SDK.Target.Capability.DOM, true);
/** @typedef {!{range: !Protocol.CSS.SourceRange, styleSheetId: !Protocol.CSS.StyleSheetId, wasUsed: boolean}} */
SDK.CSSModel.RuleUsage;
-/** @typedef {{backgroundColors: ?Array<string>, computedFontSize: string, computedFontWeights: string, computedBodyFontSize: string}} */
+/** @typedef {{backgroundColors: ?Array<string>, computedFontSize: string, computedFontWeights: string}} */
SDK.CSSModel.ContrastInfo;
/** @enum {symbol} */
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/Connections.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/Connections.js
index 7bd231e8c56..15537d5d8de 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/Connections.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/Connections.js
@@ -256,13 +256,15 @@ SDK.StubConnection = class {
/**
* @param {function()} createMainTarget
* @param {function()} websocketConnectionLost
+ * @return {!Promise}
*/
-SDK.initMainConnection = function(createMainTarget, websocketConnectionLost) {
+SDK.initMainConnection = async function(createMainTarget, websocketConnectionLost) {
SDK._websocketConnectionLost = websocketConnectionLost;
SDK._createMainTarget = createMainTarget;
Protocol.Connection.setFactory(SDK._createMainConnection);
- SDK._createMainTarget();
+ await SDK._createMainTarget();
InspectorFrontendHost.connectionReady();
+ return Promise.resolve();
};
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ConsoleModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ConsoleModel.js
index edddf4695e2..90c3892bb84 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ConsoleModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ConsoleModel.js
@@ -159,9 +159,6 @@ SDK.ConsoleModel = class extends Common.Object {
* @param {!SDK.ConsoleMessage} msg
*/
addMessage(msg) {
- if (msg.source === SDK.ConsoleMessage.MessageSource.Worker && SDK.targetManager.targetById(msg.workerId))
- return;
-
msg._pageLoadSequenceNumber = this._pageLoadSequenceNumber;
if (msg.source === SDK.ConsoleMessage.MessageSource.ConsoleAPI && msg.type === SDK.ConsoleMessage.MessageType.Clear)
this._clearIfNecessary();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js
index eebd73a792d..b305bf9fbaa 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js
@@ -870,14 +870,13 @@ SDK.DOMNode = class {
/**
* @param {string=} mode
- * @param {!Protocol.Runtime.RemoteObjectId=} objectId
*/
- highlight(mode, objectId) {
- this._domModel.overlayModel().highlightDOMNode(this.id, mode, undefined, objectId);
+ highlight(mode) {
+ this._domModel.overlayModel().highlightInOverlay({node: this}, mode);
}
highlightForTwoSeconds() {
- this._domModel.overlayModel().highlightDOMNodeForTwoSeconds(this.id);
+ this._domModel.overlayModel().highlightInOverlayForTwoSeconds({node: this});
}
/**
@@ -1044,7 +1043,7 @@ SDK.DeferredDOMNode = class {
}
highlight() {
- this._domModel.overlayModel().highlightDOMNode(undefined, undefined, this._backendNodeId);
+ this._domModel.overlayModel().highlightInOverlay({deferredNode: this});
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/DebuggerModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/DebuggerModel.js
index d77ced84d19..039ac57a494 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/DebuggerModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/DebuggerModel.js
@@ -228,9 +228,6 @@ SDK.DebuggerModel = class extends SDK.SDKModel {
}
scheduleStepIntoAsync() {
- // Node v8.x does not support breakOnAsyncCall flag but supports old style schdeuleStepIntoAsync.
- // End-of-life of Node 8.x is around December 2019.
- this._agent.scheduleStepIntoAsync();
this._agent.invoke_stepInto({breakOnAsyncCall: true});
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/HARLog.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/HARLog.js
index 6bc75d286b2..3abb962fdf4 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/HARLog.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/HARLog.js
@@ -198,7 +198,7 @@ SDK.HARLog.Entry = class {
queryString: this._buildParameters(this._request.queryParameters || []),
cookies: this._buildCookies(this._request.requestCookies || []),
headersSize: headersText ? headersText.length : -1,
- bodySize: this.requestBodySize
+ bodySize: await this._requestBodySize()
};
const postData = await this._buildPostData();
if (postData)
@@ -376,10 +376,18 @@ SDK.HARLog.Entry = class {
}
/**
- * @return {number}
+ * @return {!Promise<number>}
*/
- get requestBodySize() {
- return !this._request.requestFormData ? 0 : this._request.requestFormData.length;
+ async _requestBodySize() {
+ const postData = await this._request.requestFormData();
+ if (!postData)
+ return 0;
+
+ // As per the har spec, returns the length in bytes of the posted data.
+ // TODO(jarhar): This will be wrong if the underlying encoding is not UTF-8. NetworkRequest.requestFormData is
+ // assumed to be UTF-8 because the backend decodes post data to a UTF-8 string regardless of the provided
+ // content-type/charset in InspectorNetworkAgent::FormDataToString
+ return new TextEncoder('utf-8').encode(postData).length;
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js
index bcb9bf82b25..4248c0bf2d4 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/NetworkLog.js
@@ -299,6 +299,7 @@ SDK.NetworkLog = class extends Common.Object {
if (!manager || mainFrame.resourceTreeModel().target().parentTarget())
return;
+ const oldRequests = this._requests;
const oldManagerRequests = this._requests.filter(request => SDK.NetworkManager.forRequest(request) === manager);
const oldRequestsSet = this._requestsSet;
this._requests = [];
@@ -322,6 +323,24 @@ SDK.NetworkLog = class extends Common.Object {
requestsToAdd.push(request);
}
+ // Preserve service worker requests from the new session.
+ const serviceWorkerRequestsToAdd = [];
+ for (const swRequest of oldRequests) {
+ const networkManager = SDK.NetworkManager.forRequest(swRequest);
+ if (!networkManager)
+ continue;
+ const target = networkManager.target();
+ if (!(target.type() === SDK.Target.Type.Worker && target.parentTarget().type() === SDK.Target.Type.ServiceWorker))
+ continue;
+
+ // If there is a matching request that came before this one, keep it.
+ const keepRequest = requestsToAdd.some(
+ request => request.url() === swRequest.url() && request.issueTime() <= swRequest.issueTime());
+ if (keepRequest)
+ serviceWorkerRequestsToAdd.push(swRequest);
+ }
+ requestsToAdd.push(...serviceWorkerRequestsToAdd);
+
for (const request of requestsToAdd) {
oldRequestsSet.delete(request);
this._requests.push(request);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js
index ad2bd2d2014..8df73766f8e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js
@@ -41,6 +41,12 @@ SDK.OverlayModel = class extends SDK.SDKModel {
if (this._showPaintRectsSetting.get())
this._overlayAgent.setShowPaintRects(true);
+ this._showAdHighlightsSetting = Common.moduleSetting('showAdHighlights');
+ this._showAdHighlightsSetting.addChangeListener(
+ () => this._overlayAgent.setShowAdHighlights(this._showAdHighlightsSetting.get()));
+ if (this._showAdHighlightsSetting.get())
+ this._overlayAgent.setShowAdHighlights(true);
+
this._showDebugBordersSetting = Common.moduleSetting('showDebugBorders');
this._showDebugBordersSetting.addChangeListener(
() => this._overlayAgent.setShowDebugBorders(this._showDebugBordersSetting.get()));
@@ -75,21 +81,25 @@ SDK.OverlayModel = class extends SDK.SDKModel {
static highlightObjectAsDOMNode(object) {
const domModel = object.runtimeModel().target().model(SDK.DOMModel);
if (domModel)
- domModel.overlayModel().highlightDOMNode(undefined, undefined, undefined, object.objectId);
+ domModel.overlayModel().highlightInOverlay({object});
}
static hideDOMNodeHighlight() {
for (const overlayModel of SDK.targetManager.models(SDK.OverlayModel))
- overlayModel.highlightDOMNode(0);
+ overlayModel._delayedHideHighlight(0);
}
static muteHighlight() {
SDK.OverlayModel.hideDOMNodeHighlight();
SDK.OverlayModel._highlightDisabled = true;
+ for (const overlayModel of SDK.targetManager.models(SDK.OverlayModel))
+ overlayModel._updatePausedInDebuggerMessage();
}
static unmuteHighlight() {
SDK.OverlayModel._highlightDisabled = false;
+ for (const overlayModel of SDK.targetManager.models(SDK.OverlayModel))
+ overlayModel._updatePausedInDebuggerMessage();
}
/**
@@ -113,7 +123,8 @@ SDK.OverlayModel = class extends SDK.SDKModel {
}
_updatePausedInDebuggerMessage() {
- const message = this._debuggerModel.isPaused() && !Common.moduleSetting('disablePausedStateOverlay').get() ?
+ const message = this._debuggerModel.isPaused() && !Common.moduleSetting('disablePausedStateOverlay').get() &&
+ !SDK.OverlayModel._highlightDisabled ?
Common.UIString('Paused in debugger') :
undefined;
this._overlayAgent.setPausedInDebuggerMessage(message);
@@ -134,7 +145,7 @@ SDK.OverlayModel = class extends SDK.SDKModel {
await this._domModel.requestDocument();
this._inspectModeEnabled = mode !== Protocol.Overlay.InspectMode.None;
this.dispatchEventToListeners(SDK.OverlayModel.Events.InspectModeWillBeToggled, this);
- this._highlighter.setInspectMode(mode, this._buildHighlightConfig());
+ this._highlighter.setInspectMode(mode, this._buildHighlightConfig('all', true));
}
/**
@@ -145,43 +156,37 @@ SDK.OverlayModel = class extends SDK.SDKModel {
}
/**
- * @param {!Protocol.DOM.NodeId=} nodeId
+ * @param {!SDK.OverlayModel.HighlightData} data
* @param {string=} mode
- * @param {!Protocol.DOM.BackendNodeId=} backendNodeId
- * @param {!Protocol.Runtime.RemoteObjectId=} objectId
- */
- highlightDOMNode(nodeId, mode, backendNodeId, objectId) {
- this.highlightDOMNodeWithConfig(nodeId, {mode: mode}, backendNodeId, objectId);
- }
-
- /**
- * @param {!Protocol.DOM.NodeId=} nodeId
- * @param {!{mode: (string|undefined), showInfo: (boolean|undefined), selectors: (string|undefined)}=} config
- * @param {!Protocol.DOM.BackendNodeId=} backendNodeId
- * @param {!Protocol.Runtime.RemoteObjectId=} objectId
+ * @param {boolean=} showInfo
*/
- highlightDOMNodeWithConfig(nodeId, config, backendNodeId, objectId) {
+ highlightInOverlay(data, mode, showInfo) {
if (SDK.OverlayModel._highlightDisabled)
return;
- config = config || {mode: 'all', showInfo: undefined, selectors: undefined};
if (this._hideHighlightTimeout) {
clearTimeout(this._hideHighlightTimeout);
this._hideHighlightTimeout = null;
}
- const highlightConfig = this._buildHighlightConfig(config.mode);
- if (typeof config.showInfo !== 'undefined')
- highlightConfig.showInfo = config.showInfo;
- if (typeof config.selectors !== 'undefined')
- highlightConfig.selectorList = config.selectors;
- this._highlighter.highlightDOMNode(this._domModel.nodeForId(nodeId || 0), highlightConfig, backendNodeId, objectId);
+ const highlightConfig = this._buildHighlightConfig(mode);
+ if (typeof showInfo !== 'undefined')
+ highlightConfig.showInfo = showInfo;
+ this._highlighter.highlightInOverlay(data, highlightConfig);
}
/**
- * @param {!Protocol.DOM.NodeId} nodeId
+ * @param {!SDK.OverlayModel.HighlightData} data
+ */
+ highlightInOverlayForTwoSeconds(data) {
+ this.highlightInOverlay(data);
+ this._delayedHideHighlight(2000);
+ }
+
+ /**
+ * @param {number} delay
*/
- highlightDOMNodeForTwoSeconds(nodeId) {
- this.highlightDOMNode(nodeId);
- this._hideHighlightTimeout = setTimeout(() => this.highlightDOMNode(0), 2000);
+ _delayedHideHighlight(delay) {
+ if (this._hideHighlightTimeout === null)
+ this._hideHighlightTimeout = setTimeout(() => this.highlightInOverlay({}), delay);
}
/**
@@ -195,12 +200,13 @@ SDK.OverlayModel = class extends SDK.SDKModel {
/**
* @param {string=} mode
+ * @param {boolean=} showStyles
* @return {!Protocol.Overlay.HighlightConfig}
*/
- _buildHighlightConfig(mode) {
- mode = mode || 'all';
+ _buildHighlightConfig(mode = 'all', showStyles = false) {
const showRulers = Common.moduleSetting('showMetricsRulers').get();
- const highlightConfig = {showInfo: mode === 'all', showRulers: showRulers, showExtensionLines: showRulers};
+ const highlightConfig =
+ {showInfo: mode === 'all', showRulers: showRulers, showStyles, showExtensionLines: showRulers};
if (mode === 'all' || mode === 'content')
highlightConfig.contentColor = Common.Color.PageHighlight.Content.toProtocolRGBA();
@@ -217,7 +223,6 @@ SDK.OverlayModel = class extends SDK.SDKModel {
highlightConfig.eventTargetColor = Common.Color.PageHighlight.EventTarget.toProtocolRGBA();
highlightConfig.shapeColor = Common.Color.PageHighlight.Shape.toProtocolRGBA();
highlightConfig.shapeMarginColor = Common.Color.PageHighlight.ShapeMargin.toProtocolRGBA();
- highlightConfig.displayAsMaterial = true;
}
if (mode === 'all')
@@ -237,12 +242,27 @@ SDK.OverlayModel = class extends SDK.SDKModel {
}
/**
+ * @param {function(!SDK.DOMNode)} handler
+ */
+ static setInspectNodeHandler(handler) {
+ SDK.OverlayModel._inspectNodeHandler = handler;
+ }
+
+ /**
* @override
* @param {!Protocol.DOM.BackendNodeId} backendNodeId
*/
inspectNodeRequested(backendNodeId) {
const deferredNode = new SDK.DeferredDOMNode(this.target(), backendNodeId);
- this.dispatchEventToListeners(SDK.OverlayModel.Events.InspectNodeRequested, deferredNode);
+ if (SDK.OverlayModel._inspectNodeHandler) {
+ deferredNode.resolvePromise().then(node => {
+ if (node)
+ SDK.OverlayModel._inspectNodeHandler(node);
+ });
+ } else {
+ Common.Revealer.reveal(deferredNode);
+ }
+ this.dispatchEventToListeners(SDK.OverlayModel.Events.ExitedInspectMode);
}
/**
@@ -251,6 +271,14 @@ SDK.OverlayModel = class extends SDK.SDKModel {
*/
screenshotRequested(viewport) {
this.dispatchEventToListeners(SDK.OverlayModel.Events.ScreenshotRequested, viewport);
+ this.dispatchEventToListeners(SDK.OverlayModel.Events.ExitedInspectMode);
+ }
+
+ /**
+ * @override
+ */
+ inspectModeCanceled() {
+ this.dispatchEventToListeners(SDK.OverlayModel.Events.ExitedInspectMode);
}
};
@@ -259,8 +287,8 @@ SDK.SDKModel.register(SDK.OverlayModel, SDK.Target.Capability.DOM, true);
/** @enum {symbol} */
SDK.OverlayModel.Events = {
InspectModeWillBeToggled: Symbol('InspectModeWillBeToggled'),
+ ExitedInspectMode: Symbol('InspectModeExited'),
HighlightNodeRequested: Symbol('HighlightNodeRequested'),
- InspectNodeRequested: Symbol('InspectNodeRequested'),
ScreenshotRequested: Symbol('ScreenshotRequested'),
};
@@ -269,14 +297,18 @@ SDK.OverlayModel.Events = {
*/
SDK.OverlayModel.Highlighter = function() {};
+/** @typedef {{node: (!SDK.DOMNode|undefined),
+ deferredNode: (!SDK.DeferredDOMNode|undefined),
+ selectorList: (string|undefined),
+ object:(!SDK.RemoteObject|undefined)}} */
+SDK.OverlayModel.HighlightData;
+
SDK.OverlayModel.Highlighter.prototype = {
/**
- * @param {?SDK.DOMNode} node
+ * @param {!SDK.OverlayModel.HighlightData} data
* @param {!Protocol.Overlay.HighlightConfig} config
- * @param {!Protocol.DOM.BackendNodeId=} backendNodeId
- * @param {!Protocol.Runtime.RemoteObjectId=} objectId
*/
- highlightDOMNode(node, config, backendNodeId, objectId) {},
+ highlightInOverlay(data, config) {},
/**
* @param {!Protocol.Overlay.InspectMode} mode
@@ -304,18 +336,18 @@ SDK.OverlayModel.DefaultHighlighter = class {
/**
* @override
- * @param {?SDK.DOMNode} node
+ * @param {!SDK.OverlayModel.HighlightData} data
* @param {!Protocol.Overlay.HighlightConfig} config
- * @param {!Protocol.DOM.BackendNodeId=} backendNodeId
- * @param {!Protocol.Runtime.RemoteObjectId=} objectId
*/
- highlightDOMNode(node, config, backendNodeId, objectId) {
- if (objectId || node || backendNodeId) {
- this._model._overlayAgent.highlightNode(
- config, (objectId || backendNodeId) ? undefined : node.id, backendNodeId, objectId);
- } else {
+ highlightInOverlay(data, config) {
+ const {node, deferredNode, object, selectorList} = data;
+ const nodeId = node ? node.id : undefined;
+ const backendNodeId = deferredNode ? deferredNode.backendNodeId() : undefined;
+ const objectId = object ? object.objectId : undefined;
+ if (nodeId || backendNodeId || objectId)
+ this._model._overlayAgent.highlightNode(config, nodeId, backendNodeId, objectId, selectorList);
+ else
this._model._overlayAgent.hideHighlight();
- }
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ResourceTreeModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ResourceTreeModel.js
index 824cd76720d..4f13075df99 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ResourceTreeModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ResourceTreeModel.js
@@ -403,14 +403,13 @@ SDK.ResourceTreeModel = class extends SDK.SDKModel {
}
/**
- * @param {function(string, ?string, !Array<!Protocol.Page.AppManifestError>)} callback
+ * @return {!Promise<{url: string, data: ?string, errors: !Array<!Protocol.Page.AppManifestError>}>}
*/
- async fetchAppManifest(callback) {
+ async fetchAppManifest() {
const response = await this._agent.invoke_getAppManifest({});
if (response[Protocol.Error])
- callback(response.url, null, []);
- else
- callback(response.url, response.data || null, response.errors);
+ return {url: response.url, data: null, errors: []};
+ return {url: response.url, data: response.data || null, errors: response.errors};
}
/**
* @param {!SDK.ExecutionContext} a
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/RuntimeModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/RuntimeModel.js
index 3262081af36..f92c374136b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/RuntimeModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/RuntimeModel.js
@@ -243,7 +243,7 @@ SDK.RuntimeModel = class extends SDK.SDKModel {
*/
async compileScript(expression, sourceURL, persistScript, executionContextId) {
const response = await this._agent.invoke_compileScript({
- expression: expression,
+ expression: String.escapeInvalidUnicodeCharacters(expression),
sourceURL: sourceURL,
persistScript: persistScript,
executionContextId: executionContextId
@@ -489,8 +489,11 @@ SDK.RuntimeModel = class extends SDK.SDKModel {
if (!testContext)
return false;
// Check for a positive throwOnSideEffect response without triggering side effects.
- const response = await this._agent.invoke_evaluate(
- {expression: SDK.RuntimeModel._sideEffectTestExpression, contextId: testContext.id, throwOnSideEffect: true});
+ const response = await this._agent.invoke_evaluate({
+ expression: String.escapeInvalidUnicodeCharacters(SDK.RuntimeModel._sideEffectTestExpression),
+ contextId: testContext.id,
+ throwOnSideEffect: true
+ });
this._hasSideEffectSupport = SDK.RuntimeModel.isSideEffectFailure(response);
return this._hasSideEffectSupport;
@@ -775,7 +778,7 @@ SDK.ExecutionContext = class {
}
const response = await this.runtimeModel._agent.invoke_evaluate({
- expression: options.expression,
+ expression: String.escapeInvalidUnicodeCharacters(options.expression),
objectGroup: options.objectGroup,
includeCommandLineAPI: options.includeCommandLineAPI,
silent: options.silent,
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerCacheModel.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerCacheModel.js
index 2c502a230f5..d8f23f54ded 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerCacheModel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerCacheModel.js
@@ -91,10 +91,11 @@ SDK.ServiceWorkerCacheModel = class extends SDK.SDKModel {
* @param {!SDK.ServiceWorkerCacheModel.Cache} cache
* @param {number} skipCount
* @param {number} pageSize
+ * @param {string} pathFilter
* @param {function(!Array.<!Protocol.CacheStorage.DataEntry>, boolean)} callback
*/
- loadCacheData(cache, skipCount, pageSize, callback) {
- this._requestEntries(cache, skipCount, pageSize, callback);
+ loadCacheData(cache, skipCount, pageSize, pathFilter, callback) {
+ this._requestEntries(cache, skipCount, pageSize, pathFilter, callback);
}
/**
@@ -233,10 +234,12 @@ SDK.ServiceWorkerCacheModel = class extends SDK.SDKModel {
* @param {!SDK.ServiceWorkerCacheModel.Cache} cache
* @param {number} skipCount
* @param {number} pageSize
+ * @param {string} pathFilter
* @param {function(!Array<!Protocol.CacheStorage.DataEntry>, boolean)} callback
*/
- async _requestEntries(cache, skipCount, pageSize, callback) {
- const response = await this._cacheAgent.invoke_requestEntries({cacheId: cache.cacheId, skipCount, pageSize});
+ async _requestEntries(cache, skipCount, pageSize, pathFilter, callback) {
+ const response =
+ await this._cacheAgent.invoke_requestEntries({cacheId: cache.cacheId, skipCount, pageSize, pathFilter});
if (response[Protocol.Error]) {
console.error('ServiceWorkerCacheAgent error while requesting entries: ', response[Protocol.Error]);
return;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerManager.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerManager.js
index 4a6e9084e55..4f7694042f0 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerManager.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/ServiceWorkerManager.js
@@ -73,6 +73,18 @@ SDK.ServiceWorkerManager = class extends SDK.SDKModel {
}
/**
+ * @param {!Array<string>} urls
+ * @return {boolean}
+ */
+ hasRegistrationForURLs(urls) {
+ for (const registration of this._registrations.values()) {
+ if (urls.filter(url => url && url.startsWith(registration.scopeURL)).length === urls.length)
+ return true;
+ }
+ return false;
+ }
+
+ /**
* @param {string} versionId
* @return {?SDK.ServiceWorkerVersion}
*/
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js
index 1a40f512f05..d552ceb871b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js
@@ -183,6 +183,11 @@ SDK.TextSourceMap = class {
this._mappings = null;
/** @type {!Map<string, !SDK.TextSourceMap.SourceInfo>} */
this._sourceInfos = new Map();
+ if (this._json.sections) {
+ const sectionWithURL = !!this._json.sections.find(section => !!section.url);
+ if (sectionWithURL)
+ Common.console.warn(`SourceMap "${sourceMappingURL}" contains unsupported "URL" field in one of its sections.`);
+ }
this._eachSection(this._parseSources.bind(this));
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/TargetManager.js b/chromium/third_party/blink/renderer/devtools/front_end/sdk/TargetManager.js
index 976eba20150..7cbfa961507 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/TargetManager.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/TargetManager.js
@@ -171,10 +171,13 @@ SDK.TargetManager = class extends Common.Object {
* @param {!SDK.Target.Type} type
* @param {?SDK.Target} parentTarget
* @param {string=} sessionId
+ * @param {boolean=} waitForDebuggerInPage
* @return {!SDK.Target}
*/
- createTarget(id, name, type, parentTarget, sessionId) {
+ createTarget(id, name, type, parentTarget, sessionId, waitForDebuggerInPage) {
const target = new SDK.Target(this, id, name, type, parentTarget, sessionId || '', this._isSuspended);
+ if (waitForDebuggerInPage)
+ target.pageAgent().waitForDebugger();
target.createModels(new Set(this._modelObservers.keysArray()));
this._targets.push(target);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sdk/module.json b/chromium/third_party/blink/renderer/devtools/front_end/sdk/module.json
index 2ece8d277b6..d58a50b1663 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sdk/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sdk/module.json
@@ -135,6 +135,24 @@
{
"type": "setting",
"category": "Rendering",
+ "settingName": "showAdHighlights",
+ "settingType": "boolean",
+ "storageType": "session",
+ "options": [
+ {
+ "value": true,
+ "title": "Highlight ad frames"
+ },
+ {
+ "value": false,
+ "title": "Do not highlight ad frames"
+ }
+ ],
+ "defaultValue": false
+ },
+ {
+ "type": "setting",
+ "category": "Rendering",
"settingName": "showDebugBorders",
"settingType": "boolean",
"storageType": "session",
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js b/chromium/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
index 833df59f21d..7306cf31115 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
@@ -79,7 +79,7 @@ Security.SecurityPanel = class extends UI.PanelWithSidebar {
return text;
}
- const highlightedUrl = createElement('span', 'url-text');
+ const highlightedUrl = createElement('span');
const scheme = url.substr(0, index);
const content = url.substr(index + schemeSeparator.length);
@@ -376,7 +376,6 @@ Security.SecurityPanel.Origin;
* @typedef {Object}
* @property {!Protocol.Security.SecurityState} securityState
* @property {?Protocol.Network.SecurityDetails} securityDetails
- * @property {?Promise<>} certificateDetailsPromise
* @property {?bool} loadedFromCache
* @property {?Security.SecurityOriginView} originView
*/
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css b/chromium/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css
index 47c80a7c9bc..99890414946 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css
@@ -211,15 +211,11 @@ fieldset {
margin-left: 10px;
}
-.settings-indent-labels label {
- padding-left: 10px;
-}
-
.settings-experiment-hidden {
display: none;
}
-.settings-experiment-hidden label {
+.settings-experiment-hidden [is=dt-checkbox] {
background-color: #ddd;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/snippets/ScriptSnippetFileSystem.js b/chromium/third_party/blink/renderer/devtools/front_end/snippets/ScriptSnippetFileSystem.js
index 2f3c1c4ce4c..a6d611d035d 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/snippets/ScriptSnippetFileSystem.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/snippets/ScriptSnippetFileSystem.js
@@ -168,33 +168,33 @@ Snippets.evaluateScriptSnippet = async function(uiSourceCode) {
Common.console.show();
const url = uiSourceCode.url();
- let scriptId;
- {
- const result = await runtimeModel.compileScript(expression, url, true, executionContext.id);
- if (!result.scriptId && !result.exceptionDetails)
- return;
- if (!result.scriptId) {
- SDK.consoleModel.addMessage(SDK.ConsoleMessage.fromException(
- runtimeModel, result.exceptionDetails, /* messageType */ undefined, /* timestamp */ undefined, url));
- return;
- }
- scriptId = result.scriptId;
- }
- const result = await runtimeModel.runScript(
- scriptId, executionContext.id, 'console', /* silent */ false, /* includeCommandLineAPI */ true,
- /* returnByValue */ false, /* generatePreview */ true);
- if (!result.object && !result.exceptionDetails)
+
+ const result = await executionContext.evaluate(
+ {
+ expression: `${expression}\n//# sourceURL=${url}`,
+ objectGroup: 'console',
+ silent: false,
+ includeCommandLineAPI: true,
+ returnByValue: false,
+ generatePreview: true,
+ },
+ /* userGesture */ false,
+ /* awaitPromise */ true);
+
+ if (result.exceptionDetails) {
+ SDK.consoleModel.addMessage(SDK.ConsoleMessage.fromException(
+ runtimeModel, result.exceptionDetails, /* messageType */ undefined, /* timestamp */ undefined, url));
return;
- if (result.object) {
- const consoleMessage = new SDK.ConsoleMessage(
- runtimeModel, SDK.ConsoleMessage.MessageSource.JS, SDK.ConsoleMessage.MessageLevel.Info, '',
- SDK.ConsoleMessage.MessageType.Result, url, undefined, undefined, [result.object], undefined, undefined,
- executionContext.id, scriptId);
- SDK.consoleModel.addMessage(consoleMessage);
- } else {
- SDK.consoleModel.addMessage(
- SDK.ConsoleMessage.fromException(runtimeModel, result.exceptionDetails, undefined, undefined, url));
}
+ if (!result.object)
+ return;
+
+ const scripts = executionContext.debuggerModel.scriptsForSourceURL(url);
+ const scriptId = scripts[scripts.length - 1].scriptId;
+ SDK.consoleModel.addMessage(new SDK.ConsoleMessage(
+ runtimeModel, SDK.ConsoleMessage.MessageSource.JS, SDK.ConsoleMessage.MessageLevel.Info, '',
+ SDK.ConsoleMessage.MessageType.Result, url, undefined, undefined, [result.object], undefined, undefined,
+ executionContext.id, scriptId));
};
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js b/chromium/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js
index 3abefa40fc1..7b104c15407 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/source_frame/SourcesTextEditor.js
@@ -28,6 +28,15 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
this.codeMirror().on('beforeSelectionChange', this._fireBeforeSelectionChanged.bind(this));
this.element.addEventListener('contextmenu', this._contextMenu.bind(this), false);
+ this._gutterMouseMove = event => {
+ this.element.classList.toggle(
+ 'CodeMirror-gutter-hovered',
+ event.clientX < this.codeMirror().getGutterElement().getBoundingClientRect().right);
+ };
+ this._gutterMouseOut = event => {
+ this.element.classList.toggle('CodeMirror-gutter-hovered', false);
+ };
+
this.codeMirror().addKeyMap(SourceFrame.SourcesTextEditor._BlockIndentController);
this._tokenHighlighter = new SourceFrame.SourcesTextEditor.TokenHighlighter(this, this.codeMirror());
@@ -50,6 +59,8 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
Common.moduleSetting('textEditorIndent').addChangeListener(this._onUpdateEditorIndentation, this);
Common.moduleSetting('textEditorAutoDetectIndent').addChangeListener(this._onUpdateEditorIndentation, this);
Common.moduleSetting('showWhitespacesInEditor').addChangeListener(this._updateWhitespace, this);
+ Common.moduleSetting('textEditorCodeFolding').addChangeListener(this._updateCodeFolding, this);
+ this._updateCodeFolding();
/** @type {?UI.AutocompleteConfig} */
this._autocompleteConfig = {isWordChar: TextUtils.TextUtils.isWordChar};
@@ -308,6 +319,8 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
}
_gutterClick(instance, lineNumber, gutter, event) {
+ if (gutter !== 'CodeMirror-linenumbers')
+ return;
this.dispatchEventToListeners(
SourceFrame.SourcesTextEditor.Events.GutterClick, {lineNumber: lineNumber, event: event});
}
@@ -469,6 +482,7 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
Common.moduleSetting('textEditorIndent').removeChangeListener(this._onUpdateEditorIndentation, this);
Common.moduleSetting('textEditorAutoDetectIndent').removeChangeListener(this._onUpdateEditorIndentation, this);
Common.moduleSetting('showWhitespacesInEditor').removeChangeListener(this._updateWhitespace, this);
+ Common.moduleSetting('textEditorCodeFolding').removeChangeListener(this._updateCodeFolding, this);
}
/**
@@ -485,6 +499,22 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
this.setMimeType(this.mimeType());
}
+ _updateCodeFolding() {
+ if (Common.moduleSetting('textEditorCodeFolding').get()) {
+ this.installGutter('CodeMirror-foldgutter', false);
+ this.element.addEventListener('mousemove', this._gutterMouseMove);
+ this.element.addEventListener('mouseout', this._gutterMouseOut);
+ this.codeMirror().setOption('foldGutter', true);
+ this.codeMirror().setOption('foldOptions', {minFoldSize: 1});
+ } else {
+ this.codeMirror().execCommand('unfoldAll');
+ this.element.removeEventListener('mousemove', this._gutterMouseMove);
+ this.element.removeEventListener('mouseout', this._gutterMouseOut);
+ this.uninstallGutter('CodeMirror-foldgutter');
+ this.codeMirror().setOption('foldGutter', false);
+ }
+ }
+
/**
* @override
* @param {string} mimeType
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
index 7e34fd60680..3c1346030d0 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
@@ -8,40 +8,101 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
/**
* @param {number} editorLineNumber
* @param {string} oldCondition
+ * @param {boolean} preferLogpoint
* @param {function({committed: boolean, condition: string})} onFinish
*/
- constructor(editorLineNumber, oldCondition, onFinish) {
+ constructor(editorLineNumber, oldCondition, preferLogpoint, onFinish) {
super(true);
this.registerRequiredCSS('sources/breakpointEditDialog.css');
this._onFinish = onFinish;
this._finished = false;
/** @type {?UI.TextEditor} */
this._editor = null;
+ const isNewBreakpointsEnabled = Runtime.experiments.isEnabled('sourcesLogpoints');
+ this.element.tabIndex = -1;
- const labelElement = this.contentElement.createChild('label', 'source-frame-breakpoint-message');
- labelElement.htmlFor = 'source-frame-breakpoint-condition';
- labelElement.createTextChild(
- Common.UIString('The breakpoint on line %d will stop only if this expression is true:', editorLineNumber + 1));
+ const logpointPrefix = Sources.BreakpointEditDialog._LogpointPrefix;
+ const logpointSuffix = Sources.BreakpointEditDialog._LogpointSuffix;
+ this._isLogpoint = oldCondition.startsWith(logpointPrefix) && oldCondition.endsWith(logpointSuffix);
+ if (this._isLogpoint)
+ oldCondition = oldCondition.substring(logpointPrefix.length, oldCondition.length - logpointSuffix.length);
+ this._isLogpoint = this._isLogpoint || preferLogpoint;
+
+ if (isNewBreakpointsEnabled) {
+ this.element.classList.add('sources-edit-breakpoint-dialog');
+ const toolbar = new UI.Toolbar('source-frame-breakpoint-toolbar', this.contentElement);
+ toolbar.appendText(`Line ${editorLineNumber + 1}:`);
+
+ this._typeSelector = new UI.ToolbarComboBox(this._onTypeChanged.bind(this));
+ this._typeSelector.createOption(ls`Breakpoint`, '', Sources.BreakpointEditDialog.BreakpointType.Breakpoint);
+ const conditionalOption = this._typeSelector.createOption(
+ ls`Conditional breakpoint`, '', Sources.BreakpointEditDialog.BreakpointType.Conditional);
+ const logpointOption =
+ this._typeSelector.createOption(ls`Logpoint`, '', Sources.BreakpointEditDialog.BreakpointType.Logpoint);
+ this._typeSelector.select(this._isLogpoint ? logpointOption : conditionalOption);
+ toolbar.appendToolbarItem(this._typeSelector);
+
+ } else {
+ const labelElement = this.contentElement.createChild('label', 'source-frame-breakpoint-message');
+ labelElement.htmlFor = 'source-frame-breakpoint-condition';
+ const labelText = this._isLogpoint ? ls`On line ${editorLineNumber + 1}, log to the Console:` : ls
+ `The breakpoint on line ${editorLineNumber + 1} will stop only if this expression is true:`;
+ labelElement.createTextChild(labelText);
+ }
self.runtime.extension(UI.TextEditorFactory).instance().then(factory => {
- this._editor =
- factory.createEditor({lineNumbers: false, lineWrapping: true, mimeType: 'javascript', autoHeight: true});
+ const editorOptions = {lineNumbers: false, lineWrapping: true, mimeType: 'javascript', autoHeight: true};
+ this._editor = factory.createEditor(editorOptions);
+ if (isNewBreakpointsEnabled) {
+ this._updatePlaceholder();
+ this._editor.widget().element.classList.add('condition-editor');
+ } else {
+ this._editor.widget().element.id = 'source-frame-breakpoint-condition';
+ }
this._editor.configureAutocomplete(ObjectUI.JavaScriptAutocompleteConfig.createConfigForEditor(this._editor));
if (oldCondition)
this._editor.setText(oldCondition);
this._editor.widget().show(this.contentElement);
- this._editor.widget().element.id = 'source-frame-breakpoint-condition';
this._editor.setSelection(this._editor.fullRange());
this._editor.widget().focus();
this._editor.widget().element.addEventListener('keydown', this._onKeyDown.bind(this), true);
- this._editor.widget().element.addEventListener('blur', event => {
- if (event.relatedTarget && !event.relatedTarget.isSelfOrDescendant(this._editor.widget().element))
+ this.contentElement.addEventListener('blur', event => {
+ if (event.relatedTarget && !event.relatedTarget.isSelfOrDescendant(this.element))
this._finishEditing(true);
}, true);
});
}
/**
+ * @param {string} condition
+ * @return {string}
+ */
+ static _conditionForLogpoint(condition) {
+ return `${Sources.BreakpointEditDialog._LogpointPrefix}${condition}${Sources.BreakpointEditDialog._LogpointSuffix}`;
+ }
+
+ _onTypeChanged() {
+ const value = this._typeSelector.selectedOption().value;
+ this._isLogpoint = value === Sources.BreakpointEditDialog.BreakpointType.Logpoint;
+ this._updatePlaceholder();
+ if (value === Sources.BreakpointEditDialog.BreakpointType.Breakpoint) {
+ this._editor.setText('');
+ this._finishEditing(true);
+ }
+ }
+
+ _updatePlaceholder() {
+ const selectedValue = this._typeSelector.selectedOption().value;
+ if (selectedValue === Sources.BreakpointEditDialog.BreakpointType.Conditional) {
+ this._editor.setPlaceholder(ls`Expression to check before pausing, e.g. x > 5`);
+ this._typeSelector.element.title = ls`Pause only when the condition is true`;
+ } else if (selectedValue === Sources.BreakpointEditDialog.BreakpointType.Logpoint) {
+ this._editor.setPlaceholder(ls`Log message, e.g. 'x is', x`);
+ this._typeSelector.element.title = ls`Log a message to Console, do not break`;
+ }
+ }
+
+ /**
* @param {boolean} committed
*/
_finishEditing(committed) {
@@ -49,7 +110,9 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
return;
this._finished = true;
this._editor.widget().detach();
- const condition = this._editor.text();
+ let condition = this._editor.text();
+ if (this._isLogpoint)
+ condition = Sources.BreakpointEditDialog._conditionForLogpoint(condition);
this._onFinish({committed, condition});
}
@@ -69,3 +132,12 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
this._finishEditing(false);
}
};
+
+Sources.BreakpointEditDialog._LogpointPrefix = '/** DEVTOOLS_LOGPOINT */ console.log(';
+Sources.BreakpointEditDialog._LogpointSuffix = ')';
+
+Sources.BreakpointEditDialog.BreakpointType = {
+ Breakpoint: 'Breakpoint',
+ Conditional: 'Conditional',
+ Logpoint: 'Logpoint',
+};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js
index 11e54def1a8..652c7da132b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/DebuggerPlugin.js
@@ -151,21 +151,6 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
return uiSourceCode.contentType().hasScripts();
}
- /**
- * @override
- * @return {!Array<!UI.ToolbarItem>}
- */
- rightToolbarItems() {
- const originURL = Bindings.CompilerScriptMapping.uiSourceCodeOrigin(this._uiSourceCode);
- if (originURL) {
- const parsedURL = originURL.asParsedURL();
- if (parsedURL)
- return [new UI.ToolbarText(Common.UIString('(source mapped from %s)', parsedURL.displayName))];
- }
-
- return [];
- }
-
_showBlackboxInfobarIfNeeded() {
const uiSourceCode = this._uiSourceCode;
if (!uiSourceCode.contentType().hasScripts())
@@ -253,6 +238,11 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
contextMenu.debugSection().appendItem(
Common.UIString('Add conditional breakpoint\u2026'),
this._editBreakpointCondition.bind(this, editorLineNumber, null, null));
+ if (Runtime.experiments.isEnabled('sourcesLogpoints')) {
+ contextMenu.debugSection().appendItem(
+ ls`Add logpoint\u2026`,
+ this._editBreakpointCondition.bind(this, editorLineNumber, null, null, true /* preferLogpoint */));
+ }
contextMenu.debugSection().appendItem(
Common.UIString('Never pause here'), this._createNewBreakpoint.bind(this, editorLineNumber, 'false', true));
} else {
@@ -632,11 +622,12 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
* @param {number} editorLineNumber
* @param {?Bindings.BreakpointManager.Breakpoint} breakpoint
* @param {?{lineNumber: number, columnNumber: number}} location
+ * @param {boolean=} preferLogpoint
*/
- async _editBreakpointCondition(editorLineNumber, breakpoint, location) {
+ async _editBreakpointCondition(editorLineNumber, breakpoint, location, preferLogpoint) {
const oldCondition = breakpoint ? breakpoint.condition() : '';
const decorationElement = createElement('div');
- const dialog = new Sources.BreakpointEditDialog(editorLineNumber, oldCondition, result => {
+ const dialog = new Sources.BreakpointEditDialog(editorLineNumber, oldCondition, !!preferLogpoint, result => {
dialog.detach();
this._textEditor.removeDecoration(decorationElement, editorLineNumber);
if (!result.committed)
@@ -1210,6 +1201,12 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
contextMenu.debugSection().appendItem(
Common.UIString('Add conditional breakpoint\u2026'),
this._editBreakpointCondition.bind(this, editorLocation.lineNumber, null, editorLocation));
+ if (Runtime.experiments.isEnabled('sourcesLogpoints')) {
+ contextMenu.debugSection().appendItem(
+ ls`Add logpoint\u2026`,
+ this._editBreakpointCondition.bind(
+ this, editorLocation.lineNumber, null, editorLocation, true /* preferLogpoint */));
+ }
contextMenu.debugSection().appendItem(
Common.UIString('Never pause here'), this._setBreakpoint.bind(this, location[0], location[1], 'false', true));
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/NavigatorView.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/NavigatorView.js
index a2016cac9e2..ef0c313ca7a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/NavigatorView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/NavigatorView.js
@@ -115,18 +115,6 @@ Sources.NavigatorView = class extends UI.VBox {
/**
* @param {!UI.ContextMenu} contextMenu
- */
- static appendAddFolderItem(contextMenu) {
- function addFolder() {
- Persistence.isolatedFileSystemManager.addFileSystem();
- }
-
- const addFolderLabel = Common.UIString('Add folder to workspace');
- contextMenu.defaultSection().appendItem(addFolderLabel, addFolder);
- }
-
- /**
- * @param {!UI.ContextMenu} contextMenu
* @param {string=} path
*/
static appendSearchItem(contextMenu, path) {
@@ -753,7 +741,7 @@ Sources.NavigatorView = class extends UI.VBox {
}
if (project.type() === Workspace.projectTypes.FileSystem) {
- Sources.NavigatorView.appendAddFolderItem(contextMenu);
+ contextMenu.defaultSection().appendAction('sources.add-folder-to-workspace', undefined, true);
if (node instanceof Sources.NavigatorGroupTreeNode)
contextMenu.defaultSection().appendItem(Common.UIString('Remove folder from workspace'), removeFolder);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/ScriptOriginPlugin.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/ScriptOriginPlugin.js
index 238f2483737..706d4f29c96 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/ScriptOriginPlugin.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/ScriptOriginPlugin.js
@@ -19,7 +19,7 @@ Sources.ScriptOriginPlugin = class extends Sources.UISourceCodeFrame.Plugin {
* @return {boolean}
*/
static accepts(uiSourceCode) {
- return !!Sources.ScriptOriginPlugin._script(uiSourceCode);
+ return uiSourceCode.contentType().hasScripts() || !!Sources.ScriptOriginPlugin._script(uiSourceCode);
}
/**
@@ -27,6 +27,13 @@ Sources.ScriptOriginPlugin = class extends Sources.UISourceCodeFrame.Plugin {
* @return {!Array<!UI.ToolbarItem>}
*/
rightToolbarItems() {
+ const originURL = Bindings.CompilerScriptMapping.uiSourceCodeOrigin(this._uiSourceCode);
+ if (originURL) {
+ const item = UI.formatLocalized('(source mapped from %s)', [Components.Linkifier.linkifyURL(originURL)]);
+ return [new UI.ToolbarItem(item)];
+ }
+
+ // Handle anonymous scripts with an originStackTrace.
const script = Sources.ScriptOriginPlugin._script(this._uiSourceCode);
if (!script || !script.originStackTrace)
return [];
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesNavigator.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesNavigator.js
index 072c3238073..9c7faceac42 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesNavigator.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesNavigator.js
@@ -81,12 +81,10 @@ Sources.FilesNavigatorView = class extends Sources.NavigatorView {
constructor() {
super();
const toolbar = new UI.Toolbar('navigator-toolbar');
- const title = Common.UIString('Add folder to workspace');
- const addButton = new UI.ToolbarButton(title, 'largeicon-add', title);
- addButton.addEventListener(
- UI.ToolbarButton.Events.Click, () => Persistence.isolatedFileSystemManager.addFileSystem());
- toolbar.appendToolbarItem(addButton);
- this.contentElement.insertBefore(toolbar.element, this.contentElement.firstChild);
+ toolbar.appendItemsAtLocation('files-navigator-toolbar').then(() => {
+ if (!toolbar.empty())
+ this.contentElement.insertBefore(toolbar.element, this.contentElement.firstChild);
+ });
}
/**
@@ -106,7 +104,7 @@ Sources.FilesNavigatorView = class extends Sources.NavigatorView {
*/
handleContextMenu(event) {
const contextMenu = new UI.ContextMenu(event);
- Sources.NavigatorView.appendAddFolderItem(contextMenu);
+ contextMenu.defaultSection().appendAction('sources.add-folder-to-workspace', undefined, true);
contextMenu.show();
}
};
@@ -263,7 +261,7 @@ Sources.SnippetsNavigatorView = class extends Sources.NavigatorView {
/**
* @implements {UI.ActionDelegate}
*/
-Sources.SnippetsNavigatorView.CreatingActionDelegate = class {
+Sources.ActionDelegate = class {
/**
* @override
* @param {!UI.Context} context
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesPanel.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesPanel.js
index c704d766e14..a28b9479fd2 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesPanel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesPanel.js
@@ -177,14 +177,13 @@ Sources.SourcesPanel = class extends UI.Panel {
_showThreadsIfNeeded() {
if (Sources.ThreadsSidebarPane.shouldBeShown() && !this._threadsSidebarPane) {
this._threadsSidebarPane = /** @type {!UI.View} */ (UI.viewManager.view('sources.threads'));
- if (this._sidebarPaneStack) {
+ if (this._sidebarPaneStack && this._threadsSidebarPane) {
this._sidebarPaneStack.showView(
this._threadsSidebarPane, this._splitWidget.isVertical() ? this._watchSidebarPane : this._callstackPane);
}
}
}
-
/**
* @param {?SDK.Target} target
*/
@@ -252,7 +251,8 @@ Sources.SourcesPanel = class extends UI.Panel {
* @return {?UI.ViewLocation}
*/
resolveLocation(locationName) {
- if (locationName === 'sources-sidebar')
+ if (locationName === 'sources.sidebar-top' || locationName === 'sources.sidebar-bottom' ||
+ locationName === 'sources.sidebar-tabs')
return this._sidebarPaneStack;
else
return this._navigatorTabbedLocation;
@@ -767,7 +767,7 @@ Sources.SourcesPanel = class extends UI.Panel {
_appendUISourceCodeFrameItems(event, contextMenu, target) {
if (!(target instanceof Sources.UISourceCodeFrame))
return;
- if (target.uiSourceCode().contentType().isFromSourceMap())
+ if (target.uiSourceCode().contentType().isFromSourceMap() || target.textEditor.selection().isEmpty())
return;
contextMenu.debugSection().appendAction('debugger.evaluate-selection');
}
@@ -900,6 +900,7 @@ Sources.SourcesPanel = class extends UI.Panel {
this._sidebarPaneStack.widget().element.classList.add('overflow-auto');
this._sidebarPaneStack.widget().show(vbox.element);
this._sidebarPaneStack.widget().element.appendChild(this._debuggerPausedMessage.element());
+ this._sidebarPaneStack.appendApplicableItems('sources.sidebar-top');
vbox.element.appendChild(this._debugToolbar.element);
if (this._threadsSidebarPane)
@@ -938,11 +939,12 @@ Sources.SourcesPanel = class extends UI.Panel {
this._splitWidget.installResizer(this._debugToolbar.gripElementForResize());
tabbedLocation.appendView(scopeChainView);
tabbedLocation.appendView(this._watchSidebarPane);
+ tabbedLocation.appendApplicableItems('sources.sidebar-tabs');
this._extensionSidebarPanesContainer = tabbedLocation;
this.sidebarPaneView = splitWidget;
}
- this._sidebarPaneStack.appendApplicableItems('sources-sidebar');
+ this._sidebarPaneStack.appendApplicableItems('sources.sidebar-bottom');
const extensionSidebarPanes = Extensions.extensionServer.sidebarPanes();
for (let i = 0; i < extensionSidebarPanes.length; ++i)
this._addExtensionSidebarPane(extensionSidebarPanes[i]);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesSearchScope.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesSearchScope.js
index 23dafdd9813..3d19de6f8c9 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesSearchScope.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/SourcesSearchScope.js
@@ -52,6 +52,12 @@ Sources.SourcesSearchScope = class {
return -1;
if (!uiSourceCode1.isDirty() && uiSourceCode2.isDirty())
return 1;
+ const isFileSystem1 = uiSourceCode1.project().type() === Workspace.projectTypes.FileSystem &&
+ !Persistence.persistence.binding(uiSourceCode1);
+ const isFileSystem2 = uiSourceCode2.project().type() === Workspace.projectTypes.FileSystem &&
+ !Persistence.persistence.binding(uiSourceCode2);
+ if (isFileSystem1 !== isFileSystem2)
+ return isFileSystem1 ? 1 : -1;
const url1 = uiSourceCode1.url();
const url2 = uiSourceCode2.url();
if (url1 && !url2)
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/TabbedEditorContainer.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/TabbedEditorContainer.js
index caf96b1982f..ce8cb058c4f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/TabbedEditorContainer.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/TabbedEditorContainer.js
@@ -185,7 +185,7 @@ Sources.TabbedEditorContainer = class extends Common.Object {
}
closeAllFiles() {
- this._closeTabs(this._tabbedPane.allTabs());
+ this._closeTabs(this._tabbedPane.tabIds());
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js
index 47cb6bc733e..08014391ecf 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js
@@ -584,7 +584,7 @@ Sources.UISourceCodeFrame.RowMessage = class {
this._icon = this.element.createChild('label', '', 'dt-icon-label');
this._icon.type = Sources.UISourceCodeFrame._iconClassPerLevel[message.level()];
this._repeatCountElement =
- this.element.createChild('label', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
+ this.element.createChild('span', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
this._repeatCountElement.type = Sources.UISourceCodeFrame._bubbleTypePerLevel[message.level()];
const linesContainer = this.element.createChild('div');
const lines = this._message.text().split('\n');
@@ -636,7 +636,7 @@ Sources.UISourceCodeFrame.RowMessageBucket = class {
this._decoration = createElementWithClass('div', 'text-editor-line-decoration');
this._decoration._messageBucket = this;
this._wave = this._decoration.createChild('div', 'text-editor-line-decoration-wave');
- this._icon = this._wave.createChild('label', 'text-editor-line-decoration-icon', 'dt-icon-label');
+ this._icon = this._wave.createChild('span', 'text-editor-line-decoration-icon', 'dt-icon-label');
/** @type {?number} */
this._decorationStartColumn = null;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js b/chromium/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
index 733509e4af9..f7098577c2e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
@@ -365,9 +365,10 @@ Sources.WatchExpression = class extends Common.Object {
this._result = result || null;
const headerElement = createElementWithClass('div', 'watch-expression-header');
- const deleteButton = headerElement.createChild('button', 'watch-expression-delete-button');
- deleteButton.title = Common.UIString('Delete watch expression');
+ const deleteButton = UI.Icon.create('smallicon-cross', 'watch-expression-delete-button');
+ deleteButton.title = ls`Delete watch expression`;
deleteButton.addEventListener('click', this._deleteWatchExpression.bind(this), false);
+ headerElement.appendChild(deleteButton);
const titleElement = headerElement.createChild('div', 'watch-expression-title');
this._nameElement = ObjectUI.ObjectPropertiesSection.createNameElement(this._expression);
@@ -389,6 +390,7 @@ Sources.WatchExpression = class extends Common.Object {
headerElement.classList.add('watch-expression-object-header');
this._objectPropertiesSection = new ObjectUI.ObjectPropertiesSection(result, headerElement, this._linkifier);
this._objectPresentationElement = this._objectPropertiesSection.element;
+ this._objectPresentationElement.classList.add('watch-expression-object');
this._expandController.watchSection(/** @type {string} */ (this._expression), this._objectPropertiesSection);
const objectTreeElement = this._objectPropertiesSection.objectTreeElement();
objectTreeElement.toggleOnClick = false;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css b/chromium/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css
index 4555060cf55..154d0a05ebe 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/breakpointEditDialog.css
@@ -32,3 +32,30 @@
outline: none !important;
background: white;
}
+
+:host(.sources-edit-breakpoint-dialog) {
+ border: none;
+ border-radius: 0;
+ z-index: 30;
+ background-color: var(--toolbar-bg-color);
+ width: 555px;
+ pointer-events: auto;
+ margin: 2px 0 2px -1px;
+ padding: 0 10px 10px 5px;
+ border: 1px solid var(--divider-color);
+}
+
+:host-context(.sources-edit-breakpoint-dialog) .condition-editor {
+ background-color: #fff;
+ margin-left: 3px;
+}
+
+:host-context(.sources-edit-breakpoint-dialog) .source-frame-breakpoint-toolbar {
+ font-family: sans-serif;
+ font-size: 12px;
+}
+
+:host-context(.sources-edit-breakpoint-dialog) .source-frame-breakpoint-editor:hover,
+:host-context(.sources-edit-breakpoint-dialog) .source-frame-breakpoint-editor:focus-within {
+ box-shadow: var(--focus-ring-inactive-shadow);
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/debuggerPausedMessage.css b/chromium/third_party/blink/renderer/devtools/front_end/sources/debuggerPausedMessage.css
index ef539438a9e..652278fd31c 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/debuggerPausedMessage.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/debuggerPausedMessage.css
@@ -39,6 +39,7 @@
color: red;
line-height: 11px;
max-height: 27px;
+ -webkit-user-select: text;
}
.status-icon {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/module.json b/chromium/third_party/blink/renderer/devtools/front_end/sources/module.json
index 472a8670feb..2bad0b32dc8 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/module.json
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/module.json
@@ -222,7 +222,7 @@
"type": "action",
"actionId": "debugger.evaluate-selection",
"className": "Sources.SourcesPanel.DebuggingActionDelegate",
- "title": "Evaluate in console",
+ "title": "Evaluate selected text in console",
"contextTypes": [
"Sources.UISourceCodeFrame"
],
@@ -481,6 +481,24 @@
{
"type": "setting",
"category": "Sources",
+ "title": "Code folding",
+ "settingName": "textEditorCodeFolding",
+ "settingType": "boolean",
+ "defaultValue": false,
+ "options": [
+ {
+ "value": true,
+ "title": "Enable code folding"
+ },
+ {
+ "value": false,
+ "title": "Disable code folding"
+ }
+ ]
+ },
+ {
+ "type": "setting",
+ "category": "Sources",
"title": "Show whitespace characters:",
"settingName": "showWhitespacesInEditor",
"settingType": "enum",
@@ -693,24 +711,46 @@
"type": "action",
"category": "Sources",
"actionId": "sources.create-snippet",
- "className": "Sources.SnippetsNavigatorView.CreatingActionDelegate",
+ "className": "Sources.ActionDelegate",
"title": "Create new snippet"
},
{
"type": "action",
"category": "Sources",
"actionId": "sources.add-folder-to-workspace",
- "className": "Sources.SnippetsNavigatorView.CreatingActionDelegate",
- "title": "Add folder to workspace"
+ "className": "Sources.ActionDelegate",
+ "iconClass": "largeicon-add",
+ "title": "Add folder to workspace",
+ "condition": "!sources.hide_add_folder"
+ },
+ {
+ "type": "@UI.ToolbarItem.Provider",
+ "actionId": "sources.add-folder-to-workspace",
+ "location": "files-navigator-toolbar",
+ "showLabel": true,
+ "condition": "!sources.hide_add_folder"
},
{
"type": "@UI.ViewLocationResolver",
"name": "navigator-view",
+ "category": "Sources",
+ "className": "Sources.SourcesPanel"
+ },
+ {
+ "type": "@UI.ViewLocationResolver",
+ "name": "sources.sidebar-top",
+ "category": "Sources",
+ "className": "Sources.SourcesPanel"
+ },
+ {
+ "type": "@UI.ViewLocationResolver",
+ "name": "sources.sidebar-bottom",
+ "category": "Sources",
"className": "Sources.SourcesPanel"
},
{
"type": "@UI.ViewLocationResolver",
- "name": "sources-sidebar",
+ "name": "sources.sidebar-tabs",
"category": "Sources",
"className": "Sources.SourcesPanel"
},
@@ -719,7 +759,8 @@
"id": "sources.threads",
"title": "Threads",
"persistence": "permanent",
- "className": "Sources.ThreadsSidebarPane"
+ "className": "Sources.ThreadsSidebarPane",
+ "condition": "!sources.hide_thread_sidebar"
},
{
"type": "view",
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css b/chromium/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css
index 4b497870e97..17d4d4aff62 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css
@@ -50,7 +50,7 @@
margin-top: 0;
}
-.scripts-debug-toolbar-drawer > label {
+.scripts-debug-toolbar-drawer > [is=dt-checkbox] {
display: flex;
padding-left: 3px;
height: 28px;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/sources/watchExpressionsSidebarPane.css b/chromium/third_party/blink/renderer/devtools/front_end/sources/watchExpressionsSidebarPane.css
index 4d2d52d6168..45472a7bdee 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/sources/watchExpressionsSidebarPane.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/sources/watchExpressionsSidebarPane.css
@@ -5,21 +5,20 @@
*/
.watch-expression-delete-button {
- width: 10px;
- height: 10px;
- background-image: url(Images/deleteIcon.png);
- background-position: 0 0;
- background-color: transparent;
- background-repeat: no-repeat;
- border: 0 none transparent;
position: absolute;
- top: 4px;
- right: 3px;
- display: none;
+ top: 5px;
+ right: 6px;
+ cursor: pointer;
+ opacity: 0;
+ min-width: 20px;
}
.watch-expression-header:hover .watch-expression-delete-button {
- display: inline;
+ opacity: 0.5;
+}
+
+.watch-expression-header:hover .watch-expression-delete-button:hover {
+ opacity: 1;
}
.watch-expressions {
@@ -36,7 +35,7 @@
text-overflow: ellipsis;
overflow: hidden;
line-height: 20px;
- margin-left: 11px;
+ margin-left: 16px;
}
.watch-expression-object-header .watch-expression-title {
@@ -86,19 +85,23 @@
.watch-expression-text-prompt-proxy {
margin: 2px 12px;
+ padding-bottom: 3px;
}
.watch-expression-header {
flex: auto;
- padding: 0 6px;
}
.watch-expression-object-header {
- margin-left: -12px;
- padding-left: 12px;
+ margin-left: -16px;
+ padding-left: 15px;
}
.watch-expression-header:hover {
background-color: #F0F0F0;
- padding-right: 14px;
+ padding-right: 28px;
+}
+
+.watch-expression-object {
+ padding-left: 5px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
index 65317dd75f5..1335b70ad86 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
@@ -42,8 +42,6 @@ TextEditor.CodeMirrorTextEditor = class extends UI.VBox {
this.registerRequiredCSS('cm/codemirror.css');
this.registerRequiredCSS('text_editor/cmdevtools.css');
- TextEditor.CodeMirrorUtils.appendThemeStyle(this.element);
-
this._codeMirror = new CodeMirror(this.element, {
lineNumbers: options.lineNumbers,
matchBrackets: true,
@@ -374,6 +372,19 @@ TextEditor.CodeMirrorTextEditor = class extends UI.VBox {
}
/**
+ * @override
+ * @param {string} placeholder
+ */
+ setPlaceholder(placeholder) {
+ if (!this._placeholderElement) {
+ this._placeholderElement = createElement('pre');
+ this._placeholderElement.classList.add('placeholder-text');
+ }
+ this._placeholderElement.textContent = placeholder || '';
+ this._updatePlaceholder();
+ }
+
+ /**
* @param {number} lineNumber
* @param {number} lineLength
* @param {number} charNumber
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js
index 3adbe95cd15..2ad76a59248 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorUtils.js
@@ -89,46 +89,6 @@ TextEditor.CodeMirrorUtils.pullLines = function(codeMirror, linesCount) {
};
/**
- * @param {!Element} element
- */
-TextEditor.CodeMirrorUtils.appendThemeStyle = function(element) {
- if (UI.themeSupport.hasTheme())
- return;
-
- const backgroundColor = InspectorFrontendHost.getSelectionBackgroundColor();
- const foregroundColor = InspectorFrontendHost.getSelectionForegroundColor();
- const inactiveBackgroundColor = InspectorFrontendHost.getInactiveSelectionBackgroundColor();
- const inactiveForegroundColor = InspectorFrontendHost.getInactiveSelectionForegroundColor();
- const style = createElement('style');
- style.textContent = `
- .CodeMirror .CodeMirror-selected {
- background-color: ${inactiveBackgroundColor};
- }
-
- .CodeMirror .CodeMirror-selectedtext:not(.CodeMirror-persist-highlight) {
- color: ${inactiveForegroundColor} !important;
- }
-
- .CodeMirror-focused .CodeMirror-selected {
- background-color: ${backgroundColor};
- }
-
- .CodeMirror-focused .CodeMirror-selectedtext:not(.CodeMirror-persist-highlight) {
- color: ${foregroundColor} !important;
- }
-
- .CodeMirror .CodeMirror-line::selection,
- .CodeMirror .CodeMirror-line > span::selection,
- .CodeMirror .CodeMirror-line > span > span::selection {
- background: ${backgroundColor};
- color: ${foregroundColor} !important;
- }
- `;
- element.appendChild(style);
-};
-
-
-/**
* @implements {TextUtils.TokenizerFactory}
* @unrestricted
*/
@@ -153,19 +113,3 @@ TextEditor.CodeMirrorUtils.TokenizerFactory = class {
return tokenize;
}
};
-
-/**
- * @unrestricted
- */
-TextEditor.CodeMirrorCSSLoadView = class extends UI.VBox {
- /**
- * This bogus view is needed to load/unload CodeMirror-related CSS on demand.
- */
- constructor() {
- super();
- this.element.classList.add('hidden');
- this.registerRequiredCSS('cm/codemirror.css');
- this.registerRequiredCSS('text_editor/cmdevtools.css');
- TextEditor.CodeMirrorUtils.appendThemeStyle(this.element);
- }
-};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
index 6d42b866b0e..c690f4e1a99 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
@@ -53,10 +53,12 @@
background-color: rgb(171, 191, 254);
}
+:host-context(.-theme-with-dark-background) .CodeMirror .source-frame-continue-to-location,
.-theme-with-dark-background .CodeMirror .source-frame-continue-to-location {
background-color: #14522b;
}
+:host-context(.-theme-with-dark-background) .CodeMirror .source-frame-continue-to-location:hover,
.-theme-with-dark-background .CodeMirror .source-frame-continue-to-location:hover {
border: 1px solid #33cc6b;
background-color: #14522b;
@@ -115,12 +117,13 @@
}
.pretty-printed .CodeMirror-linenumber {
- color: var( --accent-color-b);
+ color: var(--accent-color);
}
.cm-highlight {
-webkit-animation: fadeout 2s 0s;
}
+:host-context(.-theme-with-dark-background) .cm-highlight,
.-theme-with-dark-background .cm-highlight {
-webkit-animation: fadeout-dark 2s 0s;
}
@@ -136,6 +139,7 @@
.cm-readonly-highlight {
background-color: rgb(255, 255, 120);
}
+:host-context(.-theme-with-dark-background) .cm-readonly-highlight,
.-theme-with-dark-background .cm-readonly-highlight {
background-color: hsla(133, 100%, 30%, 0.5);
}
@@ -143,6 +147,7 @@
.cm-highlight.cm-execution-line {
-webkit-animation: fadeout-execution-line 1s 0s;
}
+:host-context(.-theme-with-dark-background) .cm-highlight.cm-execution-line,
.-theme-with-dark-background .cm-highlight.cm-execution-line {
-webkit-animation: fadeout-execution-line-dark 1s 0s;
}
@@ -185,6 +190,7 @@
}
} /* media */
+:host-context(.-theme-with-dark-background) .cm-breakpoint:not(.cm-breakpoint-conditional) .CodeMirror-gutter-wrapper .CodeMirror-linenumber,
.-theme-with-dark-background .cm-breakpoint:not(.cm-breakpoint-conditional) .CodeMirror-gutter-wrapper .CodeMirror-linenumber {
filter: hue-rotate(-139deg);
}
@@ -255,11 +261,13 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
border-bottom: 1px solid rgba(255, 0, 0, 0.5);
}
+:host-context(.-theme-with-dark-background) div.CodeMirror:focus-within span.CodeMirror-matchingbracket,
.-theme-with-dark-background div.CodeMirror:focus-within span.CodeMirror-matchingbracket {
border-bottom: 1px solid rgb(217,217,217);
background-color:initial;
}
+:host-context(.-theme-with-dark-background) div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket,
.-theme-with-dark-background div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
border-bottom: 1px solid rgb(255, 26, 26);
background-color:initial;
@@ -304,18 +312,26 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
background-color: rgb(171, 191, 254);
}
-.cm-execution-line .CodeMirror-linenumber {
+.cm-execution-line .CodeMirror-linenumber::after {
+ position: absolute;
+ top:-1px;
+ bottom:-1px;
+ right:-1.5em;
+ content:"";
border-right: 1px solid rgb(64, 115, 244);
}
+:host-context(.-theme-with-dark-background) .cm-execution-line,
.-theme-with-dark-background .cm-execution-line {
background-color: #14522b;
}
+:host-context(.-theme-with-dark-background) .cm-execution-line-outline,
.-theme-with-dark-background .cm-execution-line-outline {
outline: 1px solid #33cc6b;
}
+:host-context(.-theme-with-dark-background) .cm-execution-line-tail,
.-theme-with-dark-background .cm-execution-line-tail {
background-color: #347132;
}
@@ -399,10 +415,12 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
z-index: -1;
}
+:host-context(.-theme-with-dark-background) .cm-line-with-selection .cm-column-with-selection.cm-search-highlight:before,
.-theme-with-dark-background .cm-line-with-selection .cm-column-with-selection.cm-search-highlight:before {
background-color: hsl(133, 100%, 30%);
}
+:host-context(.-theme-with-dark-background) .cm-line-with-selection .cm-search-highlight,
.-theme-with-dark-background .cm-line-with-selection .cm-search-highlight {
color: #eee;
}
@@ -505,6 +523,7 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
background-color: transparent;
}
+:host-context(.-theme-with-dark-background) .CodeMirror .CodeMirror-selected,
.-theme-with-dark-background .CodeMirror .CodeMirror-selected {
background-color: #454545;
}
@@ -552,5 +571,79 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
}
.pretty-printed .CodeMirror-linenumber {
- color: var(--accent-color-b);
+ color: var(--accent-color);
+}
+
+.CodeMirror-foldmarker {
+ cursor: pointer;
+ font-size: 0;
+ line-height: 0;
+ height:0px;
+}
+
+.CodeMirror-foldmarker::before {
+ content: '\2026';
+ font-size: 13px;
+ color: #666;
+}
+
+.CodeMirror-foldgutter {
+ width: 1.5em;
+}
+
+.CodeMirror-gutters:hover .CodeMirror-foldgutter {
+ background-color: transparent;
+}
+
+.CodeMirror-foldgutter-open,
+.CodeMirror-foldgutter-folded {
+ cursor: pointer;
+ position: relative;
+}
+
+.CodeMirror-foldgutter-open {
+ transition: opacity .2s;
+ opacity: 0;
+}
+
+.CodeMirror-gutter-hovered .CodeMirror-foldgutter-open {
+ opacity: 1;
+}
+
+.CodeMirror-foldgutter-open::before,
+.CodeMirror-foldgutter-folded::before {
+ background-color: #727272;
+ -webkit-user-select: none;
+ -webkit-mask-image: url(Images/treeoutlineTriangles.png);
+ -webkit-mask-size: 32px 24px;
+ content: "";
+ display:block;
+ width: 8px;
+ color: transparent;
+ text-shadow: none;
+ height: 12px;
+ position: absolute;
+ right: 4px;
+}
+
+.CodeMirror-foldgutter-open::before {
+ -webkit-mask-position: -16px 0;
+}
+
+.CodeMirror-foldgutter-folded::before {
+ -webkit-mask-position: 0 0;
+}
+
+.CodeMirror .CodeMirror-selected {
+ background-color: var(--editor-selection-inactive-bg-color);
+}
+
+.CodeMirror-focused .CodeMirror-selected {
+ background-color: var(--editor-selection-bg-color);
+}
+
+.CodeMirror .CodeMirror-line::selection,
+.CodeMirror .CodeMirror-line > span::selection,
+.CodeMirror .CodeMirror-line > span > span::selection {
+ background: var(--editor-selection-bg-color);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js b/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js
index 1ed148b09b3..fba7235466e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js
@@ -126,8 +126,10 @@ Timeline.TimelineDetailsView = class extends UI.VBox {
}
_updateContentsFromWindow() {
- if (!this._model)
+ if (!this._model) {
+ this._setContent(UI.html`<div/>`);
return;
+ }
const window = this._model.window();
this._updateSelectedRangeStats(window.left, window.right);
this._updateContents();
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js b/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js
index 7bd3fc06a89..ecd5308d74e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js
@@ -426,12 +426,11 @@ Timeline.TimelineHistoryManager.ToolbarButton = class extends UI.ToolbarItem {
* @param {!UI.Action} action
*/
constructor(action) {
- super(createElementWithClass('button', 'dropdown-button'));
- const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'timeline/historyToolbarButton.css');
-
- this._contentElement = shadowRoot.createChild('span', 'content');
+ super(createElementWithClass('button', 'history-dropdown-button'));
+ UI.appendStyle(this.element, 'timeline/historyToolbarButton.css');
+ this._contentElement = this.element.createChild('span', 'content');
const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
- shadowRoot.appendChild(dropdownArrowIcon);
+ this.element.appendChild(dropdownArrowIcon);
this.element.addEventListener('click', () => void action.execute(), false);
this.setEnabled(action.enabled());
action.addEventListener(UI.Action.Events.Enabled, event => this.setEnabled(/** @type {boolean} */ (event.data)));
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js b/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
index 8318111afaf..2ec17b2e43b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
@@ -410,7 +410,7 @@ Timeline.TimelinePanel = class extends UI.Panel {
this._overviewControls.push(new Timeline.TimelineEventOverviewCPUActivity());
this._overviewControls.push(new Timeline.TimelineEventOverviewNetwork());
if (this._showScreenshotsSetting.get() && this._performanceModel &&
- this._performanceModel.frameModel().frames().length)
+ this._performanceModel.filmStripModel().frames().length)
this._overviewControls.push(new Timeline.TimelineFilmStripOverview());
if (this._showMemorySetting.get())
this._overviewControls.push(new Timeline.TimelineEventOverviewMemory());
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css b/chromium/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css
index f66188bfff8..0259abf6ca7 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css
@@ -4,18 +4,18 @@
* found in the LICENSE file.
*/
-:host {
+.history-dropdown-button {
width: 160px;
height: 26px;
text-align: left;
display: flex;
}
-:host([disabled]) {
+.history-dropdown-button[disabled] {
opacity: .5;
}
-.content {
+.history-dropdown-button > .content {
padding-right: 5px;
overflow: hidden;
text-overflow: ellipsis;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css b/chromium/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
index 24a3e64bc15..7ee4ac9091a 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
@@ -99,7 +99,7 @@
}
.timeline.panel .status-pane-container.tinted {
- background-color: hsla(0, 0%, 90%, 0.8);
+ background-color: lightgray;
pointer-events: auto;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineProfileTree.js b/chromium/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineProfileTree.js
index 47af9d6458f..fa6e010d961 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineProfileTree.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineProfileTree.js
@@ -345,7 +345,7 @@ TimelineModel.TimelineProfileTree.BottomUpRootNode = class extends TimelineModel
const id = TimelineModel.TimelineProfileTree._eventId(e);
let node = nodeById.get(id);
if (!node) {
- node = new TimelineModel.TimelineProfileTree.BottomUpNode(root, id, e, true, root);
+ node = new TimelineModel.TimelineProfileTree.BottomUpNode(root, id, e, false, root);
nodeById.set(id, node);
}
node.selfTime += selfTimeStack.pop();
@@ -353,6 +353,8 @@ TimelineModel.TimelineProfileTree.BottomUpRootNode = class extends TimelineModel
node.totalTime += totalTimeById.get(id);
totalTimeById.delete(id);
}
+ if (firstNodeStack.length)
+ node.setHasChildren();
}
this.selfTime = selfTimeStack.pop();
@@ -447,6 +449,10 @@ TimelineModel.TimelineProfileTree.BottomUpNode = class extends TimelineModel.Tim
this._hasChildren = hasChildren;
}
+ setHasChildren() {
+ this._hasChildren = true;
+ }
+
/**
* @override
* @return {boolean}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js
index 759b485e2c2..3aded9679f7 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js
@@ -145,11 +145,13 @@ UI.ContextMenuSection = class {
/**
* @param {string} actionId
* @param {string=} label
+ * @param {boolean=} optional
*/
- appendAction(actionId, label) {
+ appendAction(actionId, label, optional) {
const action = UI.actionRegistry.action(actionId);
if (!action) {
- console.error(`Action ${actionId} was not defined`);
+ if (!optional)
+ console.error(`Action ${actionId} was not defined`);
return;
}
if (!label)
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/Dialog.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/Dialog.js
index ee18e276b11..a60ba4f3bd0 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/Dialog.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/Dialog.js
@@ -120,7 +120,8 @@ UI.Dialog = class extends UI.GlassPane {
* @param {!Event} event
*/
_onKeyDown(event) {
- if (this._closeOnEscape && event.keyCode === UI.KeyboardShortcut.Keys.Esc.code) {
+ if (this._closeOnEscape && event.keyCode === UI.KeyboardShortcut.Keys.Esc.code &&
+ UI.KeyboardShortcut.hasNoModifiers(event)) {
event.consume(true);
this.hide();
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js
index b5cefa74f86..81784fc8db6 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js
@@ -5,24 +5,21 @@
* @unrestricted
*/
UI.HistoryInput = class extends HTMLInputElement {
+ constructor() {
+ super();
+ this._history = [''];
+ this._historyPosition = 0;
+ this.addEventListener('keydown', this._onKeyDown.bind(this), false);
+ this.addEventListener('input', this._onInput.bind(this), false);
+ }
/**
* @return {!UI.HistoryInput}
*/
static create() {
if (!UI.HistoryInput._constructor)
- UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput.prototype);
-
- return /** @type {!UI.HistoryInput} */ (new UI.HistoryInput._constructor());
- }
+ UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput);
- /**
- * @override
- */
- createdCallback() {
- this._history = [''];
- this._historyPosition = 0;
- this.addEventListener('keydown', this._onKeyDown.bind(this), false);
- this.addEventListener('input', this._onInput.bind(this), false);
+ return /** @type {!UI.HistoryInput} */ (UI.HistoryInput._constructor());
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/Icon.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/Icon.js
index 11b6d980e1d..9d1fd5e6500 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/Icon.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/Icon.js
@@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * @constructor
- * @extends {HTMLSpanElement}
- */
UI.Icon = class extends HTMLSpanElement {
constructor() {
super();
- throw new Error('icon must be created via factory method.');
+ /** @type {?UI.Icon.Descriptor} */
+ this._descriptor = null;
+ /** @type {?UI.Icon.SpriteSheet} */
+ this._spriteSheet = null;
+ /** @type {string} */
+ this._iconType = '';
}
/**
@@ -19,9 +20,9 @@ UI.Icon = class extends HTMLSpanElement {
*/
static create(iconType, className) {
if (!UI.Icon._constructor)
- UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon.prototype);
+ UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon);
- const icon = /** @type {!UI.Icon} */ (new UI.Icon._constructor());
+ const icon = /** @type {!UI.Icon} */ (UI.Icon._constructor());
if (className)
icon.className = className;
if (iconType)
@@ -30,18 +31,6 @@ UI.Icon = class extends HTMLSpanElement {
}
/**
- * @override
- */
- createdCallback() {
- /** @type {?UI.Icon.Descriptor} */
- this._descriptor = null;
- /** @type {?UI.Icon.SpriteSheet} */
- this._spriteSheet = null;
- /** @type {string} */
- this._iconType = '';
- }
-
- /**
* @param {string} iconType
*/
setIconType(iconType) {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js
index 6697a3fb7a7..ab7f88af160 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js
@@ -138,8 +138,8 @@ UI.InspectorView = class extends UI.VBox {
}
createToolbars() {
- this._tabbedPane.leftToolbar().appendLocationItems('main-toolbar-left');
- this._tabbedPane.rightToolbar().appendLocationItems('main-toolbar-right');
+ this._tabbedPane.leftToolbar().appendItemsAtLocation('main-toolbar-left');
+ this._tabbedPane.rightToolbar().appendItemsAtLocation('main-toolbar-right');
}
/**
@@ -276,7 +276,7 @@ UI.InspectorView = class extends UI.VBox {
keyboardEvent.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD)
panelIndex = event.keyCode - 0x61;
if (panelIndex !== -1) {
- const panelName = this._tabbedPane.allTabs()[panelIndex];
+ const panelName = this._tabbedPane.tabIds()[panelIndex];
if (panelName) {
if (!UI.Dialog.hasInstance() && !this._currentPanelLocked)
this.showPanel(panelName);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js
index c11ae3aeb36..0ba477754e9 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js
@@ -9,12 +9,11 @@ UI.ListWidget = class extends UI.VBox {
* @param {!UI.ListWidget.Delegate<T>} delegate
*/
constructor(delegate) {
- super(true);
+ super(true, true /* delegatesFocus */);
this.registerRequiredCSS('ui/listWidget.css');
this._delegate = delegate;
this._list = this.contentElement.createChild('div', 'list');
- this.element.tabIndex = -1;
this._lastSeparator = false;
/** @type {?UI.ElementFocusRestorer} */
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js
index a0fa78f0b80..f03af0f6914 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js
@@ -46,7 +46,7 @@ UI.SearchableView = class extends UI.VBox {
this._setting = settingName ? Common.settings.createSetting(settingName, {}) : null;
this._replaceable = false;
- this.contentElement.createChild('content');
+ this.contentElement.createChild('slot');
this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
this._footerElementContainer.style.order = 100;
this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
index 88e8e97f301..6d21c347456 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
@@ -16,10 +16,10 @@ UI.SoftDropDown = class {
this._model = model;
this.element = createElementWithClass('button', 'soft-dropdown');
- const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/softDropDownButton.css');
- this._titleElement = shadowRoot.createChild('span', 'title');
+ UI.appendStyle(this.element, 'ui/softDropDownButton.css');
+ this._titleElement = this.element.createChild('span', 'title');
const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
- shadowRoot.appendChild(dropdownArrowIcon);
+ this.element.appendChild(dropdownArrowIcon);
this._glassPane = new UI.GlassPane();
this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js
index f0b55ed6c54..950b2302ae1 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js
@@ -46,10 +46,10 @@ UI.SplitWidget = class extends UI.Widget {
this.contentElement.classList.add('shadow-split-widget');
this._mainElement =
this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-main vbox');
- this._mainElement.createChild('content').select = '.insertion-point-main';
+ this._mainElement.createChild('slot').name = 'insertion-point-main';
this._sidebarElement =
this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-sidebar vbox');
- this._sidebarElement.createChild('content').select = '.insertion-point-sidebar';
+ this._sidebarElement.createChild('slot').name = 'insertion-point-sidebar';
this._resizerElement = this.contentElement.createChild('div', 'shadow-split-widget-resizer');
this._resizerElementSize = null;
@@ -165,8 +165,7 @@ UI.SplitWidget = class extends UI.Widget {
this._mainWidget.detach();
this._mainWidget = widget;
if (widget) {
- widget.element.classList.add('insertion-point-main');
- widget.element.classList.remove('insertion-point-sidebar');
+ widget.element.slot = 'insertion-point-main';
if (this._showMode === UI.SplitWidget.ShowMode.OnlyMain || this._showMode === UI.SplitWidget.ShowMode.Both)
widget.show(this.element);
}
@@ -184,8 +183,7 @@ UI.SplitWidget = class extends UI.Widget {
this._sidebarWidget.detach();
this._sidebarWidget = widget;
if (widget) {
- widget.element.classList.add('insertion-point-sidebar');
- widget.element.classList.remove('insertion-point-main');
+ widget.element.slot = 'insertion-point-sidebar';
if (this._showMode === UI.SplitWidget.ShowMode.OnlySidebar || this._showMode === UI.SplitWidget.ShowMode.Both)
widget.show(this.element);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js
index b1d9560bc79..f51f82d6df2 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js
@@ -46,7 +46,7 @@ UI.TabbedPane = class extends UI.VBox {
this._tabsElement.addEventListener('keydown', this._keyDown.bind(this), false);
this._contentElement = this.contentElement.createChild('div', 'tabbed-pane-content');
this._contentElement.setAttribute('role', 'tabpanel');
- this._contentElement.createChild('content');
+ this._contentElement.createChild('slot');
/** @type {!Array.<!UI.TabbedPaneTab>} */
this._tabs = [];
/** @type {!Array.<!UI.TabbedPaneTab>} */
@@ -268,15 +268,6 @@ UI.TabbedPane = class extends UI.VBox {
}
/**
- * @return {!Array.<string>}
- */
- allTabs() {
- return this._tabs.map(function(tab) {
- return tab.id;
- });
- }
-
- /**
* @param {string} id
* @return {!Array.<string>}
*/
@@ -844,7 +835,7 @@ UI.TabbedPane = class extends UI.VBox {
if (oldIndex < index)
--index;
this._tabs.splice(index, 0, tab);
- this.dispatchEventToListeners(UI.TabbedPane.Events.TabOrderChanged, this._tabs);
+ this.dispatchEventToListeners(UI.TabbedPane.Events.TabOrderChanged, {tabId: tab.id});
}
/**
@@ -1194,7 +1185,7 @@ UI.TabbedPaneTab = class {
* @this {UI.TabbedPaneTab}
*/
function closeAll() {
- this._closeTabs(this._tabbedPane.allTabs());
+ this._closeTabs(this._tabbedPane.tabIds());
}
/**
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/TextEditor.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/TextEditor.js
index a06fa966a9a..2c2597bd4ae 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/TextEditor.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/TextEditor.js
@@ -90,7 +90,12 @@ UI.TextEditor.prototype = {
* @param {number} columnNumber
* @return {?{startColumn: number, endColumn: number, type: string}}
*/
- tokenAtTextPosition(lineNumber, columnNumber) {}
+ tokenAtTextPosition(lineNumber, columnNumber) {},
+
+ /**
+ * @param {string} placeholder
+ */
+ setPlaceholder(placeholder) {}
};
/** @enum {symbol} */
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/TextPrompt.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/TextPrompt.js
index f3305be972b..9aeaf150395 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/TextPrompt.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/TextPrompt.js
@@ -110,12 +110,11 @@ UI.TextPrompt = class extends Common.Object {
this._boundOnMouseWheel = this.onMouseWheel.bind(this);
this._boundClearAutocomplete = this.clearAutocomplete.bind(this);
this._proxyElement = element.ownerDocument.createElement('span');
- const shadowRoot = UI.createShadowRootWithCoreStyles(this._proxyElement, 'ui/textPrompt.css');
- this._contentElement = shadowRoot.createChild('div', 'text-prompt-root');
- this._contentElement.createChild('content');
+ UI.appendStyle(this._proxyElement, 'ui/textPrompt.css');
+ this._contentElement = this._proxyElement.createChild('div', 'text-prompt-root');
this._proxyElement.style.display = this._proxyElementDisplay;
element.parentElement.insertBefore(this._proxyElement, element);
- this._proxyElement.appendChild(element);
+ this._contentElement.appendChild(element);
this._element.classList.add('text-prompt');
UI.ARIAUtils.markAsTextBox(this._element);
this._element.setAttribute('contenteditable', 'plaintext-only');
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
index 73cd26678ff..34953109e0c 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
@@ -45,17 +45,20 @@ UI.Toolbar = class {
this._enabled = true;
this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/toolbar.css');
this._contentElement = this._shadowRoot.createChild('div', 'toolbar-shadow');
- this._insertionPoint = this._contentElement.createChild('content');
+ this._insertionPoint = this._contentElement.createChild('slot');
}
/**
* @param {!UI.Action} action
* @param {!Array<!UI.ToolbarButton>=} toggledOptions
* @param {!Array<!UI.ToolbarButton>=} untoggledOptions
+ * @param {boolean=} showLabel
* @return {!UI.ToolbarToggle}
*/
- static createActionButton(action, toggledOptions, untoggledOptions) {
+ static createActionButton(action, toggledOptions, untoggledOptions, showLabel) {
const button = new UI.ToolbarToggle(action.title(), action.icon(), action.toggledIcon());
+ if (showLabel)
+ button.setText(action.title());
button.setToggleWithRedColor(action.toggleWithRedColor());
button.addEventListener(UI.ToolbarButton.Events.Click, action.execute, action);
action.addEventListener(UI.Action.Events.Enabled, enabledChanged);
@@ -185,11 +188,13 @@ UI.Toolbar = class {
/**
* @param {string} actionId
+ * @param {boolean=} showLabel
* @return {!UI.ToolbarToggle}
*/
- static createActionButtonForId(actionId) {
+ static createActionButtonForId(actionId, showLabel) {
const action = UI.actionRegistry.action(actionId);
- return UI.Toolbar.createActionButton(/** @type {!UI.Action} */ (action));
+ return UI.Toolbar.createActionButton(
+ /** @type {!UI.Action} */ (action), undefined, undefined, showLabel);
}
/**
@@ -225,6 +230,13 @@ UI.Toolbar = class {
}
/**
+ * @return {boolean}
+ */
+ empty() {
+ return !this._items.length;
+ }
+
+ /**
* @param {boolean} enabled
*/
setEnabled(enabled) {
@@ -265,7 +277,7 @@ UI.Toolbar = class {
delete item._toolbar;
this._items = [];
this._contentElement.removeChildren();
- this._insertionPoint = this._contentElement.createChild('content');
+ this._insertionPoint = this._contentElement.createChild('slot');
}
/**
@@ -315,50 +327,20 @@ UI.Toolbar = class {
/**
* @param {string} location
+ * @return {!Promise}
*/
- appendLocationItems(location) {
+ async appendItemsAtLocation(location) {
const extensions = self.runtime.extensions(UI.ToolbarItem.Provider);
- const promises = [];
- for (let i = 0; i < extensions.length; ++i) {
- if (extensions[i].descriptor()['location'] === location)
- promises.push(resolveItem(extensions[i]));
- }
- Promise.all(promises).then(appendItemsInOrder.bind(this));
-
- /**
- * @param {!Runtime.Extension} extension
- * @return {!Promise<?UI.ToolbarItem>}
- */
- function resolveItem(extension) {
+ const filtered = extensions.filter(e => e.descriptor()['location'] === location);
+ const items = await Promise.all(filtered.map(extension => {
const descriptor = extension.descriptor();
if (descriptor['separator'])
- return Promise.resolve(/** @type {?UI.ToolbarItem} */ (new UI.ToolbarSeparator()));
- if (descriptor['actionId']) {
- return Promise.resolve(
- /** @type {?UI.ToolbarItem} */ (UI.Toolbar.createActionButtonForId(descriptor['actionId'])));
- }
- return extension.instance().then(fetchItemFromProvider);
-
- /**
- * @param {!Object} provider
- * @return {?UI.ToolbarItem}
- */
- function fetchItemFromProvider(provider) {
- return /** @type {!UI.ToolbarItem.Provider} */ (provider).item();
- }
- }
-
- /**
- * @param {!Array.<?UI.ToolbarItem>} items
- * @this {UI.Toolbar}
- */
- function appendItemsInOrder(items) {
- for (let i = 0; i < items.length; ++i) {
- const item = items[i];
- if (item)
- this.appendToolbarItem(item);
- }
- }
+ return new UI.ToolbarSeparator();
+ if (descriptor['actionId'])
+ return UI.Toolbar.createActionButtonForId(descriptor['actionId'], descriptor['showLabel']);
+ return extension.instance().then(p => p.item());
+ }));
+ items.filter(item => item).forEach(item => this.appendToolbarItem(item));
}
};
@@ -596,7 +578,7 @@ UI.ToolbarInput = class extends UI.ToolbarItem {
const clearButton = this.element.createChild('div', 'toolbar-input-clear-button');
clearButton.appendChild(UI.Icon.create('mediumicon-gray-cross-hover', 'search-cancel-button'));
clearButton.addEventListener('click', () => {
- this._internalSetValue('', true);
+ this.setValue('', true);
this._prompt.focus();
});
@@ -613,16 +595,9 @@ UI.ToolbarInput = class extends UI.ToolbarItem {
/**
* @param {string} value
+ * @param {boolean=} notify
*/
- setValue(value) {
- this._internalSetValue(value, false);
- }
-
- /**
- * @param {string} value
- * @param {boolean} notify
- */
- _internalSetValue(value, notify) {
+ setValue(value, notify) {
this._prompt.setText(value);
if (notify)
this._onChangeCallback();
@@ -642,7 +617,7 @@ UI.ToolbarInput = class extends UI.ToolbarItem {
_onKeydownCallback(event) {
if (!isEscKey(event) || !this._prompt.text())
return;
- this._internalSetValue('', true);
+ this.setValue('', true);
event.consume(true);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js
index a8034a04284..253f22fe793 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js
@@ -54,7 +54,7 @@ UI.Tooltip = class {
*/
_mouseMove(event) {
const mouseEvent = /** @type {!MouseEvent} */ (event);
- const path = mouseEvent.path;
+ const path = mouseEvent.composedPath();
if (!path || mouseEvent.buttons !== 0 || (mouseEvent.movementX === 0 && mouseEvent.movementY === 0))
return;
@@ -63,7 +63,8 @@ UI.Tooltip = class {
for (const element of path) {
// The offsetParent is null when the element or an ancestor has 'display: none'.
- if (element === this._anchorElement || (element.nodeName !== 'CONTENT' && element.offsetParent === null)) {
+ if (!(element instanceof Element) || element === this._anchorElement ||
+ (element.nodeName !== 'SLOT' && element.offsetParent === null)) {
return;
} else if (element[UI.Tooltip._symbol]) {
this._show(element, mouseEvent);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js
index 7531b84bb83..9820f1efa3e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js
@@ -674,9 +674,7 @@ UI.asyncStackTraceLabel = function(description) {
* @param {!Element} element
*/
UI.installComponentRootStyles = function(element) {
- UI.appendStyle(element, 'ui/inspectorCommon.css');
- UI.themeSupport.injectHighlightStyleSheets(element);
- UI.themeSupport.injectCustomStyleSheets(element);
+ UI._injectCoreStyles(element);
element.classList.add('platform-' + Host.platform());
// Detect overlay scrollbar enable by checking for nonzero scrollbar width.
@@ -704,13 +702,12 @@ UI.measuredScrollbarWidth = function(document) {
/**
* @param {!Element} element
* @param {string=} cssFile
+ * @param {boolean=} delegatesFocus
* @return {!DocumentFragment}
*/
-UI.createShadowRootWithCoreStyles = function(element, cssFile) {
- const shadowRoot = element.createShadowRoot();
- UI.appendStyle(shadowRoot, 'ui/inspectorCommon.css');
- UI.themeSupport.injectHighlightStyleSheets(shadowRoot);
- UI.themeSupport.injectCustomStyleSheets(shadowRoot);
+UI.createShadowRootWithCoreStyles = function(element, cssFile, delegatesFocus) {
+ const shadowRoot = element.attachShadow({mode: 'open', delegatesFocus});
+ UI._injectCoreStyles(shadowRoot);
if (cssFile)
UI.appendStyle(shadowRoot, cssFile);
shadowRoot.addEventListener('focus', UI._focusChanged.bind(UI), true);
@@ -718,6 +715,16 @@ UI.createShadowRootWithCoreStyles = function(element, cssFile) {
};
/**
+ * @param {!Element|!ShadowRoot} root
+ */
+UI._injectCoreStyles = function(root) {
+ UI.appendStyle(root, 'ui/inspectorCommon.css');
+ UI.appendStyle(root, 'ui/textButton.css');
+ UI.themeSupport.injectHighlightStyleSheets(root);
+ UI.themeSupport.injectCustomStyleSheets(root);
+};
+
+/**
* @param {!Document} document
* @param {!Event} event
*/
@@ -1166,13 +1173,19 @@ UI.beautifyFunctionName = function(name) {
/**
* @param {string} localName
* @param {string} typeExtension
- * @param {!Object} prototype
+ * @param {function(new:HTMLElement, *)} definition
* @return {function()}
* @suppressGlobalPropertiesCheck
- * @template T
*/
-UI.registerCustomElement = function(localName, typeExtension, prototype) {
- return document.registerElement(typeExtension, {prototype: Object.create(prototype), extends: localName});
+UI.registerCustomElement = function(localName, typeExtension, definition) {
+ self.customElements.define(typeExtension, class extends definition {
+ constructor() {
+ super();
+ // TODO(einbinder) convert to classes and custom element tags
+ this.setAttribute('is', typeExtension);
+ }
+ }, {extends: localName});
+ return () => createElement(localName, typeExtension);
};
/**
@@ -1183,12 +1196,14 @@ UI.registerCustomElement = function(localName, typeExtension, prototype) {
* @return {!Element}
*/
UI.createTextButton = function(text, clickHandler, className, primary) {
- const element = createElementWithClass('button', className || '', 'text-button');
+ const element = createElementWithClass('button', className || '');
element.textContent = text;
+ element.classList.add('text-button');
if (primary)
element.classList.add('primary-button');
if (clickHandler)
element.addEventListener('click', clickHandler, false);
+ element.type = 'button';
return element;
};
@@ -1213,10 +1228,10 @@ UI.createInput = function(className, type) {
* @return {!Element}
*/
UI.createRadioLabel = function(name, title, checked) {
- const element = createElement('label', 'dt-radio');
+ const element = createElement('span', 'dt-radio');
element.radioElement.name = name;
element.radioElement.checked = !!checked;
- element.createTextChild(title);
+ element.labelElement.createTextChild(title);
return element;
};
@@ -1226,7 +1241,7 @@ UI.createRadioLabel = function(name, title, checked) {
* @return {!Element}
*/
UI.createLabel = function(title, iconClass) {
- const element = createElement('label', 'dt-icon-label');
+ const element = createElement('span', 'dt-icon-label');
element.createChild('span').textContent = title;
element.type = iconClass;
return element;
@@ -1238,8 +1253,8 @@ UI.createLabel = function(title, iconClass) {
* @param {number} max
* @param {number} tabIndex
*/
-UI.createSliderLabel = function(min, max, tabIndex) {
- const element = createElement('label', 'dt-slider');
+UI.createSlider = function(min, max, tabIndex) {
+ const element = createElement('span', 'dt-slider');
element.sliderElement.min = min;
element.sliderElement.max = max;
element.sliderElement.step = 1;
@@ -1270,10 +1285,7 @@ UI.appendStyle = function(node, cssFile) {
}
};
-/**
- * @extends {HTMLLabelElement}
- */
-UI.CheckboxLabel = class extends HTMLLabelElement {
+UI.CheckboxLabel = class extends HTMLSpanElement {
constructor() {
super();
/** @type {!DocumentFragment} */
@@ -1282,13 +1294,6 @@ UI.CheckboxLabel = class extends HTMLLabelElement {
this.checkboxElement;
/** @type {!Element} */
this.textElement;
- throw new Error('Checkbox must be created via factory method.');
- }
-
- /**
- * @override
- */
- createdCallback() {
UI.CheckboxLabel._lastId = (UI.CheckboxLabel._lastId || 0) + 1;
const id = 'ui-checkbox-label' + UI.CheckboxLabel._lastId;
this._shadowRoot = UI.createShadowRootWithCoreStyles(this, 'ui/checkboxTextLabel.css');
@@ -1297,7 +1302,7 @@ UI.CheckboxLabel = class extends HTMLLabelElement {
this.checkboxElement.setAttribute('id', id);
this.textElement = this._shadowRoot.createChild('label', 'dt-checkbox-text');
this.textElement.setAttribute('for', id);
- this._shadowRoot.createChild('content');
+ this._shadowRoot.createChild('slot');
}
/**
@@ -1308,8 +1313,8 @@ UI.CheckboxLabel = class extends HTMLLabelElement {
*/
static create(title, checked, subtitle) {
if (!UI.CheckboxLabel._constructor)
- UI.CheckboxLabel._constructor = UI.registerCustomElement('label', 'dt-checkbox', UI.CheckboxLabel.prototype);
- const element = /** @type {!UI.CheckboxLabel} */ (new UI.CheckboxLabel._constructor());
+ UI.CheckboxLabel._constructor = UI.registerCustomElement('span', 'dt-checkbox', UI.CheckboxLabel);
+ const element = /** @type {!UI.CheckboxLabel} */ (UI.CheckboxLabel._constructor());
element.checkboxElement.checked = !!checked;
if (title !== undefined) {
element.textElement.textContent = title;
@@ -1350,152 +1355,124 @@ UI.CheckboxLabel = class extends HTMLLabelElement {
};
(function() {
- UI.registerCustomElement('button', 'text-button', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- this.type = 'button';
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/textButton.css');
- root.createChild('content');
- },
-
- __proto__: HTMLButtonElement.prototype
- });
+let labelId = 0;
+UI.registerCustomElement('span', 'dt-radio', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ this.radioElement = this.createChild('input', 'dt-radio-button');
+ this.labelElement = this.createChild('label');
- UI.registerCustomElement('label', 'dt-radio', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- this.radioElement = this.createChild('input', 'dt-radio-button');
- this.radioElement.type = 'radio';
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css');
- root.createChild('content').select = '.dt-radio-button';
- root.createChild('content');
- this.addEventListener('click', radioClickHandler, false);
- },
-
- __proto__: HTMLLabelElement.prototype
- });
+ const id = 'dt-radio-button-id' + (++labelId);
+ this.radioElement.id = id;
+ this.radioElement.type = 'radio';
+ this.labelElement.htmlFor = id;
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css');
+ root.createChild('slot');
+ this.addEventListener('click', radioClickHandler, false);
+ }
+});
- /**
+/**
* @param {!Event} event
* @suppressReceiverCheck
* @this {Element}
*/
- function radioClickHandler(event) {
- if (this.radioElement.checked || this.radioElement.disabled)
- return;
- this.radioElement.checked = true;
- this.radioElement.dispatchEvent(new Event('change'));
- }
+function radioClickHandler(event) {
+ if (this.radioElement.checked || this.radioElement.disabled)
+ return;
+ this.radioElement.checked = true;
+ this.radioElement.dispatchEvent(new Event('change'));
+}
- UI.registerCustomElement('label', 'dt-icon-label', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this);
- this._iconElement = UI.Icon.create();
- this._iconElement.style.setProperty('margin-right', '4px');
- root.appendChild(this._iconElement);
- root.createChild('content');
- },
+UI.registerCustomElement('span', 'dt-icon-label', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this);
+ this._iconElement = UI.Icon.create();
+ this._iconElement.style.setProperty('margin-right', '4px');
+ root.appendChild(this._iconElement);
+ root.createChild('slot');
+ }
- /**
+ /**
* @param {string} type
* @this {Element}
*/
- set type(type) {
- this._iconElement.setIconType(type);
- },
-
- __proto__: HTMLLabelElement.prototype
- });
+ set type(type) {
+ this._iconElement.setIconType(type);
+ }
+});
- UI.registerCustomElement('label', 'dt-slider', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css');
- this.sliderElement = createElementWithClass('input', 'dt-range-input');
- this.sliderElement.type = 'range';
- root.appendChild(this.sliderElement);
- },
+UI.registerCustomElement('span', 'dt-slider', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css');
+ this.sliderElement = createElementWithClass('input', 'dt-range-input');
+ this.sliderElement.type = 'range';
+ root.appendChild(this.sliderElement);
+ }
- /**
+ /**
* @param {number} amount
* @this {Element}
*/
- set value(amount) {
- this.sliderElement.value = amount;
- },
+ set value(amount) {
+ this.sliderElement.value = amount;
+ }
- /**
+ /**
* @this {Element}
*/
- get value() {
- return this.sliderElement.value;
- },
-
- __proto__: HTMLLabelElement.prototype
- });
+ get value() {
+ return this.sliderElement.value;
+ }
+});
- UI.registerCustomElement('label', 'dt-small-bubble', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css');
- this._textElement = root.createChild('div');
- this._textElement.className = 'info';
- this._textElement.createChild('content');
- },
+UI.registerCustomElement('span', 'dt-small-bubble', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css');
+ this._textElement = root.createChild('div');
+ this._textElement.className = 'info';
+ this._textElement.createChild('slot');
+ }
- /**
+ /**
* @param {string} type
* @this {Element}
*/
- set type(type) {
- this._textElement.className = type;
- },
-
- __proto__: HTMLLabelElement.prototype
- });
+ set type(type) {
+ this._textElement.className = type;
+ }
+});
- UI.registerCustomElement('div', 'dt-close-button', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css');
- this._buttonElement = root.createChild('div', 'close-button');
- const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon');
- this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon');
- this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon');
- this._buttonElement.appendChild(regularIcon);
- this._buttonElement.appendChild(this._hoverIcon);
- this._buttonElement.appendChild(this._activeIcon);
- },
+UI.registerCustomElement('div', 'dt-close-button', class extends HTMLDivElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css');
+ this._buttonElement = root.createChild('div', 'close-button');
+ const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon');
+ this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon');
+ this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon');
+ this._buttonElement.appendChild(regularIcon);
+ this._buttonElement.appendChild(this._hoverIcon);
+ this._buttonElement.appendChild(this._activeIcon);
+ }
- /**
+ /**
* @param {boolean} gray
* @this {Element}
*/
- set gray(gray) {
- if (gray) {
- this._hoverIcon.setIconType('mediumicon-gray-cross-hover');
- this._activeIcon.setIconType('mediumicon-gray-cross-active');
- } else {
- this._hoverIcon.setIconType('mediumicon-red-cross-hover');
- this._activeIcon.setIconType('mediumicon-red-cross-active');
- }
- },
-
- __proto__: HTMLDivElement.prototype
- });
+ set gray(gray) {
+ if (gray) {
+ this._hoverIcon.setIconType('mediumicon-gray-cross-hover');
+ this._activeIcon.setIconType('mediumicon-gray-cross-active');
+ } else {
+ this._hoverIcon.setIconType('mediumicon-red-cross-hover');
+ this._activeIcon.setIconType('mediumicon-red-cross-active');
+ }
+ }
+});
})();
/**
@@ -1681,7 +1658,7 @@ UI.ThemeSupport = class {
}
/**
- * @param {!Element} element
+ * @param {!Element|!ShadowRoot} element
*/
injectHighlightStyleSheets(element) {
this._injectingStyleSheet = true;
@@ -2028,15 +2005,20 @@ UI.createInlineButton = function(toolbarButton) {
UI.createExpandableText = function(text, maxLength) {
const fragment = createDocumentFragment();
fragment.textContent = text.slice(0, maxLength);
- const hiddenText = text.slice(maxLength);
-
- const expandButton = fragment.createChild('span', 'expandable-inline-button');
- expandButton.setAttribute('data-text', ls`Show ${Number.withThousandsSeparator(hiddenText.length)} more`);
- expandButton.addEventListener('click', () => {
- if (expandButton.parentElement)
- expandButton.parentElement.insertBefore(createTextNode(hiddenText), expandButton);
- expandButton.remove();
- });
+ const expandElement = fragment.createChild('span');
+ const totalBytes = Number.bytesToString(2 * text.length);
+ if (text.length < 10000000) {
+ expandElement.setAttribute('data-text', ls`Show more (${totalBytes})`);
+ expandElement.classList.add('expandable-inline-button');
+ expandElement.addEventListener('click', () => {
+ if (expandElement.parentElement)
+ expandElement.parentElement.insertBefore(createTextNode(text.slice(maxLength)), expandElement);
+ expandElement.remove();
+ });
+ } else {
+ expandElement.setAttribute('data-text', ls`long text was truncated (${totalBytes})`);
+ expandElement.classList.add('undisplayable-text');
+ }
const copyButton = fragment.createChild('span', 'expandable-inline-button');
copyButton.setAttribute('data-text', ls`Copy`);
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/View.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/View.js
index bc3d3be579b..0cf76eef38e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/View.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/View.js
@@ -506,7 +506,7 @@ UI.ViewManager._ExpandableContainerWidget = class extends UI.VBox {
this._titleElement.addEventListener('keydown', this._onTitleKeyDown.bind(this), false);
this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild);
- this.contentElement.createChild('content');
+ this.contentElement.createChild('slot');
this._view = view;
view[UI.ViewManager._ExpandableContainerWidget._symbol] = this;
}
@@ -632,7 +632,8 @@ UI.ViewManager._TabbedLocation = class extends UI.ViewManager._Location {
this._tabbedPane.addEventListener(UI.TabbedPane.Events.TabClosed, this._tabClosed, this);
this._closeableTabSetting = Common.settings.createSetting(location + '-closeableTabs', {});
this._tabOrderSetting = Common.settings.createSetting(location + '-tabOrder', {});
- this._tabbedPane.addEventListener(UI.TabbedPane.Events.TabOrderChanged, this._persistTabOrder, this);
+ this._tabbedPane.addEventListener(
+ UI.TabbedPane.Events.TabOrderChanged, event => this._persistTabOrder(event.data['tabId']));
if (restoreSelection)
this._lastSelectedTabSetting = Common.settings.createSetting(location + '-selectedTab', '');
this._defaultTab = defaultTab;
@@ -765,7 +766,7 @@ UI.ViewManager._TabbedLocation = class extends UI.ViewManager._Location {
this._closeableTabSetting.set(tabs);
}
}
- this._persistTabOrder();
+ this._persistTabOrder(view.viewId());
}
/**
@@ -821,11 +822,20 @@ UI.ViewManager._TabbedLocation = class extends UI.ViewManager._Location {
this._views.get(id).disposeView();
}
- _persistTabOrder() {
+ /**
+ * @param {string} tabId
+ */
+ _persistTabOrder(tabId) {
const tabIds = this._tabbedPane.tabIds();
+ const previousId = tabIds[tabIds.indexOf(tabId) - 1];
+ const orders = this._tabOrderSetting.get();
+ orders[tabId] = previousId && orders[previousId] ? orders[previousId] + 1 : 0;
+ const keys = Object.keys(orders);
+ keys.sort((a, b) => orders[a] - orders[b]);
+
const tabOrders = {};
- for (let i = 0; i < tabIds.length; i++)
- tabOrders[tabIds[i]] = (i + 1) * UI.ViewManager._TabbedLocation.orderStep;
+ for (let i = 0; i < keys.length; i++)
+ tabOrders[keys[i]] = (i + 1) * UI.ViewManager._TabbedLocation.orderStep;
this._tabOrderSetting.set(tabOrders);
}
};
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/Widget.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/Widget.js
index 861f157d943..611890d3f81 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/Widget.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/Widget.js
@@ -30,13 +30,14 @@
UI.Widget = class extends Common.Object {
/**
* @param {boolean=} isWebComponent
+ * @param {boolean=} delegatesFocus
*/
- constructor(isWebComponent) {
+ constructor(isWebComponent, delegatesFocus) {
super();
this.contentElement = createElementWithClass('div', 'widget');
if (isWebComponent) {
this.element = createElementWithClass('div', 'vbox flex-auto');
- this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element);
+ this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, undefined, delegatesFocus);
this._shadowRoot.appendChild(this.contentElement);
} else {
this.element = this.contentElement;
@@ -599,9 +600,10 @@ UI.Widget._originalRemoveChildren = Element.prototype.removeChildren;
UI.VBox = class extends UI.Widget {
/**
* @param {boolean=} isWebComponent
+ * @param {boolean=} delegatesFocus
*/
- constructor(isWebComponent) {
- super(isWebComponent);
+ constructor(isWebComponent, delegatesFocus) {
+ super(isWebComponent, delegatesFocus);
this.contentElement.classList.add('vbox');
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/filter.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/filter.css
index 025789e4331..b09df818315 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/filter.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/filter.css
@@ -46,10 +46,6 @@
align-items: center;
}
-.filter-text-filter label {
- margin: auto 0;
-}
-
.filter-bitset-filter {
padding: 2px;
display: inline-flex;
@@ -116,7 +112,7 @@
position: relative;
}
-.filter-checkbox-filter > label {
+.filter-checkbox-filter > [is=dt-checkbox] {
display: flex;
margin: auto 0;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
index 824db97feb5..365d09a6e51 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
@@ -50,6 +50,10 @@
outline-width: 0;
}
+input[type=radio]:focus {
+ outline: auto 5px -webkit-focus-ring-color;
+}
+
img {
-webkit-user-drag: none;
}
@@ -156,13 +160,14 @@ iframe.widget {
button,
input,
select {
+ /* Form elements do not automatically inherit font style from ancestors. */
font-family: inherit;
font-size: inherit;
- color: inherit;
}
input {
background-color: white;
+ color: inherit;
}
:host-context(.-theme-with-dark-background) input[type="checkbox"]::not(.-theme-preserve) {
@@ -305,7 +310,7 @@ input {
white-space: nowrap;
}
-label[is=dt-icon-label] {
+span[is=dt-icon-label] {
flex: none;
}
@@ -398,21 +403,40 @@ label[is=dt-icon-label] {
.expandable-inline-button {
background-color: #dedede;
- padding: 2px 4px;
- margin: 0 2px;
color: #333;
cursor: pointer;
border-radius: 3px;
+}
+
+.undisplayable-text,
+.expandable-inline-button {
+ padding: 2px 4px;
+ margin: 0 2px;
font-size: 12px;
font-family: sans-serif;
white-space: nowrap;
display: inline-block;
}
+.undisplayable-text::after,
.expandable-inline-button::after {
content: attr(data-text);
}
+.undisplayable-text {
+ color: rgb(128, 128, 128);
+ font-style: italic;
+}
+
.expandable-inline-button:hover {
background-color: #d5d5d5;
}
+
+::selection {
+ background-color: #bbdefb;
+}
+
+.-theme-with-dark-background *::selection,
+:host-context(.-theme-with-dark-background) *::selection {
+ background-color: #9e9e9e;
+}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css
index e384f54fc49..5a577375951 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/inspectorStyle.css
@@ -33,9 +33,10 @@
}
:root {
- --accent-color: #03a9f4;
- --accent-color-b: #2196f3;
- --accent-color-c: #3e82f7;
+ --accent-color: #1a73e8;
+ --accent-fg-color: #1a73e8;
+ --accent-color-hover: #3b86e8;
+ --focus-bg-color: hsl(214, 40%, 92%);
--toolbar-bg-color: #f3f3f3;
--toolbar-hover-bg-color: #eaeaea;
--selection-fg-color: white;
@@ -47,12 +48,15 @@
0 2px 6px rgba(0, 0, 0, 0.1);
--divider-color: #d0d0d0;
--focus-ring-inactive-shadow: 0 0 0 1px #e0e0e0;
+ --editor-selection-bg-color: #cfe8fc;
+ --editor-selection-inactive-bg-color: #e0e0e0;
}
.-theme-with-dark-background {
- --accent-color: #32699f;
- --accent-color-b: #2f84da;
- --accent-color-c: #1f4061;
+ --accent-color: #0e639c;
+ --accent-fg-color: #cccccc;
+ --accent-color-hover: rgb(17, 119, 187);
+ --focus-bg-color: hsl(214, 19%, 27%);
--toolbar-bg-color: #333333;
--toolbar-hover-bg-color: #202020;
--selection-fg-color: #cdcdcd;
@@ -64,11 +68,13 @@
0 2px 6px 2px rgba(0, 0, 0, 0.1);
--divider-color: #525252;
--focus-ring-inactive-shadow: 0 0 0 1px #5a5a5a;
+ --editor-selection-bg-color: hsl(207, 88%, 22%);
+ --editor-selection-inactive-bg-color: #454545;
}
:root {
--focus-ring-active-shadow: 0 0 0 1px var(--accent-color);
- --selection-bg-color: var(--accent-color-b);
+ --selection-bg-color: var(--accent-color);
--divider-border: 1px solid var(--divider-color);
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/radioButton.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/radioButton.css
index 47f4775bb47..cadf3a738e3 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/radioButton.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/radioButton.css
@@ -4,7 +4,7 @@
* found in the LICENSE file.
*/
-::content .dt-radio-button {
+::slotted(input.dt-radio-button) {
height: 17px;
width: 17px;
min-width: 17px;
@@ -16,16 +16,16 @@
margin: 0 5px 5px 0;
}
-::content .dt-radio-button:active:not(:disabled) {
+::slotted(input.dt-radio-button:active:not(:disabled)) {
background-image: linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239));
}
-::content .dt-radio-button:checked {
+::slotted(input.dt-radio-button:checked) {
background: url(Images/radioDot.png) center no-repeat,
linear-gradient(to bottom, rgb(252, 252, 252), rgb(223, 223, 223));
}
-::content .dt-radio-button:checked:active {
+::slotted(input.dt-radio-button:checked:active) {
background: url(Images/radioDot.png) center no-repeat,
linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239));
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css
index 3812ef15420..2270d27b53b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css
@@ -3,7 +3,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-:host {
+button.soft-dropdown {
height: 26px;
text-align: left;
position: relative;
@@ -11,18 +11,18 @@
background: none;
}
-:host([disabled]) {
+button.soft-dropdown[disabled] {
opacity: .5;
}
-:host .title {
+button.soft-dropdown > .title {
padding-right: 5px;
width: 120px;
overflow: hidden;
text-overflow: ellipsis;
}
-:host([data-keyboard-focus="true"]:focus)::before {
+button.soft-dropdown[data-keyboard-focus="true"]:focus::before {
content: "";
position: absolute;
top: 2px;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css
index fff72480cec..0e94772ad6b 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/tabbedPane.css
@@ -246,7 +246,7 @@
height: 2px;
position: absolute;
bottom: -1px;
- background-color: #03a9f4;
+ background-color: var(--accent-color);
left: 0;
z-index: 50;
transform-origin: 0 100%;
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/textButton.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/textButton.css
index 001189a1c8b..05fd2cacd72 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/textButton.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/textButton.css
@@ -4,66 +4,63 @@
* found in the LICENSE file.
*/
-:host {
+.text-button {
margin: 2px;
height: 24px;
font-size: 12px;
border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 2px;
+ border-radius: 4px;
padding: 0px 12px;
font-weight: 500;
- color: #333;
+ color: var(--accent-fg-color);
background-color: #fff;
flex: none;
white-space: nowrap;
}
-:host(:not(:disabled):focus),
-:host(:not(:disabled):hover),
-:host(:not(:disabled):active) {
+.text-button:not(:disabled):focus,
+.text-button:not(:disabled):hover,
+.text-button:not(:disabled):active {
background-color: var(--toolbar-bg-color);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
cursor: pointer;
}
-:host(:not(:disabled):active) {
+.text-button:not(:disabled):active {
background-color: #f2f2f2;
}
-:host(:not(:disabled):focus) {
+.text-button:not(:disabled):focus {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(66, 133, 244, 0.4);
}
-:host(:disabled) {
+.text-button:disabled {
opacity: 0.38;
}
-:host(.primary-button), -theme-preserve {
- background-color: #4285F4;
+.text-button.primary-button, -theme-preserve {
+ background-color: var(--accent-color);
border: none;
color: #fff;
}
-:host(.primary-button:not(:disabled):focus),
-:host(.primary-button:not(:disabled):hover), -theme-preserve {
- background-color: #3B78E7;
+.text-button.primary-button:not(:disabled):focus,
+.text-button.primary-button:not(:disabled):hover,
+.text-button.primary-button:not(:disabled):active, -theme-preserve {
+ background-color: var(--accent-color-hover);
}
-:host(.primary-button:not(:disabled):active), -theme-preserve {
- background-color: #3367D6;
-}
-
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):focus),
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):hover),
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):active) {
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):focus,
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):hover,
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):active {
background-color: #313131;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):focus) {
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):focus {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(94, 151, 246, 0.6);
}
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):active) {
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):active {
background-color: #3e3e3e;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/textPrompt.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/textPrompt.css
index 5fb0dd61738..b229032214f 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/textPrompt.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/textPrompt.css
@@ -4,7 +4,7 @@
* found in the LICENSE file.
*/
-.text-prompt-root {
+ .text-prompt-root {
display: flex;
align-items: center;
}
@@ -22,46 +22,45 @@
opacity: 1.0 !important;
}
-.text-prompt-editing,
-.text-prompt-editing ::content * {
+.text-prompt-editing > .text-prompt {
color: #222 !important;
text-decoration: none !important;
white-space: pre;
}
-::content .auto-complete-text {
+.text-prompt > .auto-complete-text {
color: rgb(128, 128, 128) !important;
}
-::content .text-prompt[data-placeholder]:empty::before {
+.text-prompt[data-placeholder]:empty::before {
content: attr(data-placeholder);
color: rgb(128, 128, 128);
}
-::content .text-prompt:not([data-placeholder]):empty::after {
+.text-prompt:not([data-placeholder]):empty::after {
content: '\00A0';
width: 0;
display: block;
}
-::content .text-prompt {
+.text-prompt {
cursor: text;
overflow-x: visible;
}
-::content .text-prompt::-webkit-scrollbar {
+.text-prompt::-webkit-scrollbar {
display: none;
}
-::content .text-prompt.disabled {
+.text-prompt.disabled {
opacity: 0.5;
cursor: default;
}
-.text-prompt-editing ::content br {
+.text-prompt-editing br {
display: none;
}
-:host-context(:not(:focus-within)) ::content ::selection {
+.text-prompt-root:not(:focus-within) ::selection {
background: transparent;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/toolbar.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/toolbar.css
index d45a3f95bf8..fb5e0db7b68 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/toolbar.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/toolbar.css
@@ -45,6 +45,11 @@
padding: 0;
height: 26px;
border: none;
+ white-space: pre;
+}
+
+.toolbar-item,
+.toolbar-item .devtools-link {
color: #5a5a5a;
}
@@ -144,12 +149,12 @@ select.toolbar-item:disabled + .toolbar-dropdown-arrow {
.toolbar-button.toolbar-state-on .toolbar-glyph,
.toolbar-blue-on-hover .toolbar-button:not(.toolbar-state-on):enabled:hover:not(:active),
.-theme-selection-color {
- background-color: var(--accent-color-b);
+ background-color: var(--accent-color);
}
.toolbar-button.toolbar-state-on .toolbar-text,
.-theme-selection-color {
- color: var(--accent-color-b);
+ color: var(--accent-color);
}
.toolbar-blue-on-hover .toolbar-button:not(.toolbar-state-on):enabled:hover .toolbar-glyph {
@@ -163,12 +168,12 @@ select.toolbar-item:disabled + .toolbar-dropdown-arrow {
.toolbar-button.toolbar-state-on:enabled:hover:not(:active) .toolbar-glyph,
.toolbar-blue-on-hover .toolbar-button:not(.toolbar-state-on):enabled:active:hover,
.-theme-selection-color {
- background-color: var(--accent-color-b);
+ background-color: var(--accent-color);
}
.toolbar-button.toolbar-state-on:enabled:hover:not(:active) .toolbar-text,
.-theme-selection-color {
- color: var(--accent-color-b);
+ color: var(--accent-color);
}
.toolbar-toggled-gray .toolbar-button.toolbar-state-on {
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.css b/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.css
index d8610f5cc42..5a0529bfd16 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.css
@@ -159,7 +159,7 @@ ol.tree-outline:not(.hide-selection-when-blurred) li.selected:focus * {
}
.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] {
- background: rgba(0, 0, 0, 0.08);
+ background: var(--focus-bg-color);
border-radius: 2px;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js b/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js
index cb4ed7cdd78..2a722ffd7a2 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js
+++ b/chromium/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js
@@ -177,6 +177,10 @@ UI.TreeOutline = class extends Common.Object {
this.contentElement.focus();
}
+ useLightSelectionColor() {
+ this._useLightSelectionColor = true;
+ }
+
/**
* @param {!UI.TreeElement} element
*/
@@ -225,10 +229,16 @@ UI.TreeOutline = class extends Common.Object {
return true;
}
+ forceSelect() {
+ if (this.selectedTreeElement)
+ this.selectedTreeElement.deselect();
+ this._selectFirst();
+ }
+
/**
* @return {boolean}
*/
- selectFirst() {
+ _selectFirst() {
let first = this.firstChild();
while (first && !first.selectable)
first = first.traverseNextTreeElement(true);
@@ -279,7 +289,7 @@ UI.TreeOutline = class extends Common.Object {
} else if (event.keyCode === UI.KeyboardShortcut.Keys.Space.code) {
handled = this.selectedTreeElement.onspace();
} else if (event.key === 'Home') {
- handled = this.selectFirst();
+ handled = this._selectFirst();
} else if (event.key === 'End') {
handled = this._selectLast();
}
@@ -1086,11 +1096,15 @@ UI.TreeElement = class {
}
_onFocus() {
+ if (this.treeOutline._useLightSelectionColor)
+ return;
if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred'))
this._listItemNode.classList.add('force-white-icons');
}
_onBlur() {
+ if (this.treeOutline._useLightSelectionColor)
+ return;
if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred'))
this._listItemNode.classList.remove('force-white-icons');
}
diff --git a/chromium/third_party/blink/renderer/devtools/readme.md b/chromium/third_party/blink/renderer/devtools/readme.md
index 12f7aa175a4..3e49169b90e 100644
--- a/chromium/third_party/blink/renderer/devtools/readme.md
+++ b/chromium/third_party/blink/renderer/devtools/readme.md
@@ -1,5 +1,9 @@
# Chrome DevTools frontend
+<!-- [START badges] -->
+[![NPM package](https://img.shields.io/npm/v/chrome-devtools-frontend.svg)](https://npmjs.org/package/chrome-devtools-frontend)
+<!-- [END badges] -->
+
The client-side of the Chrome DevTools, including all JS & CSS to run the DevTools webapp.
It is available on NPM as the [chrome-devtools-frontend](https://www.npmjs.com/package/chrome-devtools-frontend) package. It's not currently available via CJS or ES2015 modules, so consuming this package in other tools may require [some effort](https://github.com/paulirish/devtools-timeline-model/blob/master/index.js).
@@ -70,7 +74,7 @@ Formats your Python code using [yapf](https://github.com/google/yapf)
> Note: Yapf is a command line tool. You will have to install this manually, either from PyPi through `pip install yapf` or if you want to enable multiprocessing in Python 2.7, `pip install futures`
#### `npm test`
-Builds devtools and runs all inspector/devtools layout tests.
+Builds devtools and runs all inspector/devtools web tests.
> Note: If you're using a full chromium checkout and compiled content shell in out/Release, then `npm test` uses that. Otherwise, with only a front-end checkout (i.e. cloning from GitHub), then `npm test` will fetch a previously compiled content shell from the cloud (and cache it for future test runs).
diff --git a/chromium/third_party/blink/renderer/devtools/scripts/extract_module/extract_module.js b/chromium/third_party/blink/renderer/devtools/scripts/extract_module/extract_module.js
index 6a8cdd8a709..14a80e3b844 100644
--- a/chromium/third_party/blink/renderer/devtools/scripts/extract_module/extract_module.js
+++ b/chromium/third_party/blink/renderer/devtools/scripts/extract_module/extract_module.js
@@ -399,7 +399,7 @@ function renameIdentifiers(identifierMap) {
return;
if (filePath.includes('externs.js'))
return;
- if (filePath.includes('eslint') || filePath.includes('lighthouse-background.js') || filePath.includes('/cm/') ||
+ if (filePath.includes('eslint') || filePath.includes('lighthouse-dt-bundle.js') || filePath.includes('/cm/') ||
filePath.includes('/xterm.js/') || filePath.includes('/acorn/'))
return;
if (filePath.includes('/cm_modes/') && !filePath.includes('DefaultCodeMirror') &&
diff --git a/chromium/third_party/blink/renderer/devtools/scripts/npm_test.js b/chromium/third_party/blink/renderer/devtools/scripts/npm_test.js
index 113faa8f16a..fc498859cf8 100644
--- a/chromium/third_party/blink/renderer/devtools/scripts/npm_test.js
+++ b/chromium/third_party/blink/renderer/devtools/scripts/npm_test.js
@@ -254,7 +254,7 @@ function runTests(buildDirectoryPath, useDebugDevtools) {
console.log('=============================================\n');
}
var args = [BLINK_TEST_PATH].concat(testArgs).concat(getTestFlags());
- console.log(`Running layout tests with args: ${args}`);
+ console.log(`Running web tests with args: ${args}`);
childProcess.spawn(PYTHON, args, {stdio: 'inherit'});
}
@@ -277,4 +277,4 @@ function getInspectorTests() {
'http/tests/inspector*',
'http/tests/devtools',
];
-} \ No newline at end of file
+}
diff --git a/chromium/third_party/blink/renderer/modules/BUILD.gn b/chromium/third_party/blink/renderer/modules/BUILD.gn
index 051ab3a286f..e2d05b47fe0 100644
--- a/chromium/third_party/blink/renderer/modules/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/BUILD.gn
@@ -2,8 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/split_static_library.gni")
import("//build/config/chromecast_build.gni")
+import("//build/split_static_library.gni")
import("//third_party/blink/renderer/bindings/bindings.gni")
import("//third_party/blink/renderer/bindings/modules/v8/generated.gni")
import("//third_party/blink/renderer/bindings/modules/v8/v8.gni")
@@ -117,6 +117,7 @@ target("jumbo_" + modules_target_type, "modules") {
"//third_party/blink/renderer/modules/filesystem",
"//third_party/blink/renderer/modules/gamepad",
"//third_party/blink/renderer/modules/geolocation",
+ "//third_party/blink/renderer/modules/idle",
"//third_party/blink/renderer/modules/imagecapture",
"//third_party/blink/renderer/modules/indexeddb",
"//third_party/blink/renderer/modules/installation",
@@ -189,10 +190,6 @@ jumbo_source_set("modules_testing") {
"accessibility/testing/internals_accessibility.h",
"mediastream/testing/internals_media_stream.cc",
"mediastream/testing/internals_media_stream.h",
- "navigatorcontentutils/testing/internals_navigator_content_utils.cc",
- "navigatorcontentutils/testing/internals_navigator_content_utils.h",
- "navigatorcontentutils/testing/navigator_content_utils_client_mock.cc",
- "navigatorcontentutils/testing/navigator_content_utils_client_mock.h",
"peerconnection/adapters/test/mock_ice_transport_adapter.h",
"peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h",
"peerconnection/adapters/test/mock_p2p_quic_packet_transport.h",
@@ -277,6 +274,7 @@ jumbo_source_set("unit_tests") {
"indexeddb/idb_test_helper.cc",
"indexeddb/idb_transaction_test.cc",
"indexeddb/idb_value_wrapping_test.cc",
+ "indexeddb/indexed_db_blink_mojom_traits_test.cc",
"indexeddb/mock_web_idb_callbacks.cc",
"indexeddb/mock_web_idb_callbacks.h",
"indexeddb/mock_web_idb_database.cc",
@@ -318,6 +316,7 @@ jumbo_source_set("unit_tests") {
"payments/payments_validators_test.cc",
"peerconnection/adapters/p2p_quic_stream_unittest.cc",
"peerconnection/adapters/p2p_quic_transport_test.cc",
+ "peerconnection/adapters/quic_packet_transport_adapter_test.cc",
"peerconnection/byte_buffer_queue_test.cc",
"peerconnection/call_setup_state_tracker_unittest.cc",
"peerconnection/rtc_data_channel_test.cc",
@@ -346,6 +345,7 @@ jumbo_source_set("unit_tests") {
"webaudio/audio_basic_processor_handler_test.cc",
"webaudio/audio_context_autoplay_test.cc",
"webaudio/audio_context_test.cc",
+ "webaudio/audio_node_input_test.cc",
"webaudio/audio_worklet_global_scope_test.cc",
"webaudio/audio_worklet_thread_test.cc",
"webaudio/convolver_node_test.cc",
@@ -373,8 +373,8 @@ jumbo_source_set("unit_tests") {
"//skia",
"//testing/gmock",
"//testing/gtest",
- "//third_party/blink/public:media_devices_mojo_bindings_blink",
"//third_party/blink/renderer/core",
+ "//third_party/blink/renderer/modules/gamepad:unit_tests",
"//third_party/blink/renderer/modules/storage:unit_tests",
"//third_party/blink/renderer/platform",
"//third_party/blink/renderer/platform/wtf",
diff --git a/chromium/third_party/blink/renderer/modules/DEPS b/chromium/third_party/blink/renderer/modules/DEPS
index 20352caf078..b0697f005b4 100644
--- a/chromium/third_party/blink/renderer/modules/DEPS
+++ b/chromium/third_party/blink/renderer/modules/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+base/atomic_sequence_num.h",
"+base/memory/scoped_refptr.h",
+ "+base/strings/char_traits.h",
"+mojo/public/cpp/bindings",
"+services/network/public/cpp/shared_url_loader_factory.h",
"+services/service_manager/public/mojom/interface_provider.mojom-blink.h",
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
index c4478a9d087..ae01f5a58e4 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
@@ -54,6 +54,8 @@ blink_modules_sources("accessibility") {
"ax_sparse_attribute_setter.h",
"ax_svg_root.cc",
"ax_svg_root.h",
+ "ax_validation_message.cc",
+ "ax_validation_message.h",
"ax_virtual_object.cc",
"ax_virtual_object.h",
"inspector_accessibility_agent.cc",
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc
index 99cd4415844..fff684f7f3e 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc
@@ -240,8 +240,8 @@ TEST_F(AccessibilityObjectModelTest, Grid) {
auto* ax_cell = cache->GetOrCreate(cell);
EXPECT_TRUE(ax_cell->IsTableCellLikeRole());
- EXPECT_EQ(8U, ax_cell->AriaColumnIndex());
- EXPECT_EQ(5U, ax_cell->AriaRowIndex());
+ EXPECT_EQ(0U, ax_cell->AriaColumnIndex());
+ EXPECT_EQ(0U, ax_cell->AriaRowIndex());
auto* ax_cell2 = cache->GetOrCreate(cell2);
EXPECT_TRUE(ax_cell2->IsTableCellLikeRole());
@@ -388,7 +388,7 @@ TEST_F(AccessibilityObjectModelTest, LabeledBy) {
AccessibleNodeList* node_list = target->accessibleNode()->labeledBy();
ASSERT_EQ(nullptr, node_list);
- node_list = new AccessibleNodeList();
+ node_list = MakeGarbageCollected<AccessibleNodeList>();
node_list->add(l3->accessibleNode());
target->accessibleNode()->setLabeledBy(node_list);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
index 2a7d7bafc10..a9c06509651 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
@@ -111,20 +111,19 @@ void AXInlineTextBox::TextCharacterOffsets(Vector<int>& offsets) const {
}
}
-void AXInlineTextBox::GetWordBoundaries(Vector<AXRange>& words) const {
+void AXInlineTextBox::GetWordBoundaries(Vector<int>& word_starts,
+ Vector<int>& word_ends) const {
if (!inline_text_box_ ||
inline_text_box_->GetText().ContainsOnlyWhitespaceOrEmpty())
return;
Vector<AbstractInlineTextBox::WordBoundaries> boundaries;
inline_text_box_->GetWordBoundaries(boundaries);
- words.ReserveCapacity(boundaries.size());
+ word_starts.ReserveCapacity(boundaries.size());
+ word_ends.ReserveCapacity(boundaries.size());
for (const auto& boundary : boundaries) {
- const AXRange range(
- AXPosition::CreatePositionInTextObject(*this, boundary.start_index),
- AXPosition::CreatePositionInTextObject(*this, boundary.end_index));
- if (range.IsValid())
- words.push_back(range);
+ word_starts.push_back(boundary.start_index);
+ word_ends.push_back(boundary.end_index);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
index 7ca785d7268..3514d42b380 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
@@ -58,7 +58,8 @@ class AXInlineTextBox final : public AXObject {
String GetName(ax::mojom::NameFrom&,
AXObject::AXObjectVector* name_objects) const override;
void TextCharacterOffsets(Vector<int>&) const override;
- void GetWordBoundaries(Vector<AXRange>&) const override;
+ void GetWordBoundaries(Vector<int>& word_starts,
+ Vector<int>& word_ends) const override;
void GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index 2b21d5cfb33..8d0e93e1715 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -664,10 +664,12 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
// Find out if this element is inside of a label element. If so, it may be
// ignored because it's the label for a checkbox or radio button.
AXObject* control_object = CorrespondingControlForLabelElement();
+ HTMLLabelElement* label = LabelElementContainer();
if (control_object && control_object->IsCheckboxOrRadio() &&
- control_object->NameFromLabelElement()) {
+ control_object->NameFromLabelElement() &&
+ AccessibleNode::GetPropertyOrARIAAttribute(
+ label, AOMStringProperty::kRole) == g_null_atom) {
if (ignored_reasons) {
- HTMLLabelElement* label = LabelElementContainer();
if (label && label != GetNode()) {
AXObject* label_ax_object = AXObjectCache().GetOrCreate(label);
ignored_reasons->push_back(
@@ -2089,6 +2091,7 @@ void AXLayoutObject::AddChildren() {
AddRemoteSVGChildren();
AddTableChildren();
AddInlineTextBoxChildren(false);
+ AddValidationMessageChild();
AddAccessibleNodeChildren();
for (const auto& child : children_) {
@@ -2562,6 +2565,18 @@ bool AXLayoutObject::OnNativeSetValueAction(const String& string) {
return true;
}
+ if (HasContentEditableAttributeSet()) {
+ ExceptionState exception_state(v8::Isolate::GetCurrent(),
+ ExceptionState::kExecutionContext, nullptr,
+ nullptr);
+ ToHTMLElement(GetNode())->setInnerText(string, exception_state);
+ if (exception_state.HadException()) {
+ exception_state.ClearException();
+ return false;
+ }
+ return true;
+ }
+
return false;
}
@@ -2767,6 +2782,30 @@ void AXLayoutObject::AddInlineTextBoxChildren(bool force) {
}
}
+void AXLayoutObject::AddValidationMessageChild() {
+ if (!IsWebArea())
+ return;
+ AXObject* ax_object = AXObjectCache().ValidationMessageObjectIfVisible();
+ if (ax_object)
+ children_.push_back(ax_object);
+}
+
+AXObject* AXLayoutObject::ErrorMessage() const {
+ // Check for aria-errormessage.
+ Element* existing_error_message =
+ GetAOMPropertyOrARIAAttribute(AOMRelationProperty::kErrorMessage);
+ if (existing_error_message)
+ return AXObjectCache().GetOrCreate(existing_error_message);
+
+ // Check for visible validationMessage. This can only be visible for a focused
+ // control. Corollary: if there is a visible validationMessage alert box, then
+ // it is related to the current focus.
+ if (this != AXObjectCache().FocusedObject())
+ return nullptr;
+
+ return AXObjectCache().ValidationMessageObjectIfVisible();
+}
+
void AXLayoutObject::LineBreaks(Vector<int>& line_breaks) const {
if (!IsTextControl())
return;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
index 9e1d6adb678..cf75d73cbb3 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -207,6 +207,10 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
// For a table row or column.
AXObject* HeaderObject() const override;
+ // The aria-errormessage object or native object from a validationMessage
+ // alert.
+ AXObject* ErrorMessage() const override;
+
private:
bool IsTabItemSelected() const;
bool IsValidSelectionBound(const AXObject*) const;
@@ -224,6 +228,7 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
void AddRemoteSVGChildren();
void AddTableChildren();
void AddInlineTextBoxChildren(bool force);
+ void AddValidationMessageChild();
ax::mojom::Role DetermineTableCellRole() const;
ax::mojom::Role DetermineTableRowRole() const;
bool FindAllTableCellsWithRole(ax::mojom::Role, AXObjectVector&) const;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
index 3f809473685..dd9627cf78c 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
@@ -58,49 +58,34 @@ AXObject* AccessibilityMediaControl::Create(
case kMediaSlider:
return AccessibilityMediaTimeline::Create(layout_object, ax_object_cache);
- case kMediaVolumeSlider:
- return AccessibilityMediaVolumeSlider::Create(layout_object,
- ax_object_cache);
-
- case kMediaCurrentTimeDisplay:
- case kMediaTimeRemainingDisplay:
- return AccessibilityMediaTimeDisplay::Create(layout_object,
- ax_object_cache);
-
case kMediaControlsPanel:
return AXMediaControlsContainer::Create(layout_object, ax_object_cache);
- case kMediaEnterFullscreenButton:
- case kMediaMuteButton:
- case kMediaPlayButton:
case kMediaSliderThumb:
- case kMediaShowClosedCaptionsButton:
- case kMediaHideClosedCaptionsButton:
case kMediaTextTrackList:
- case kMediaUnMuteButton:
- case kMediaPauseButton:
case kMediaTimelineContainer:
case kMediaTrackSelectionCheckmark:
- case kMediaVolumeSliderContainer:
- case kMediaVolumeSliderThumb:
- case kMediaExitFullscreenButton:
case kMediaCastOffButton:
case kMediaCastOnButton:
case kMediaOverlayCastOffButton:
case kMediaOverlayCastOnButton:
case kMediaOverflowButton:
case kMediaOverflowList:
- case kMediaDownloadButton:
case kMediaScrubbingMessage:
- case kMediaEnterPictureInPictureButton:
- case kMediaExitPictureInPictureButton:
case kMediaDisplayCutoutFullscreenButton:
case kMediaAnimatedArrowContainer:
- return new AccessibilityMediaControl(layout_object, ax_object_cache);
+ return MakeGarbageCollected<AccessibilityMediaControl>(layout_object,
+ ax_object_cache);
+ // Removed as a part of the a11y tree rewrite https://crbug/836549.
+ case kMediaIgnore:
+ NOTREACHED();
+ return MakeGarbageCollected<AccessibilityMediaControl>(layout_object,
+ ax_object_cache);
}
NOTREACHED();
- return new AccessibilityMediaControl(layout_object, ax_object_cache);
+ return MakeGarbageCollected<AccessibilityMediaControl>(layout_object,
+ ax_object_cache);
}
MediaControlElementType AccessibilityMediaControl::ControlType() const {
@@ -129,34 +114,12 @@ String AccessibilityMediaControl::TextAlternative(
AXRelatedObjectVector* related_objects,
NameSources* name_sources) const {
switch (ControlType()) {
- case kMediaEnterFullscreenButton:
- return QueryString(WebLocalizedString::kAXMediaEnterFullscreenButton);
- case kMediaExitFullscreenButton:
- return QueryString(WebLocalizedString::kAXMediaExitFullscreenButton);
- case kMediaMuteButton:
- return QueryString(WebLocalizedString::kAXMediaMuteButton);
- case kMediaPlayButton:
- return QueryString(WebLocalizedString::kAXMediaPlayButton);
- case kMediaUnMuteButton:
- return QueryString(WebLocalizedString::kAXMediaUnMuteButton);
- case kMediaPauseButton:
- return QueryString(WebLocalizedString::kAXMediaPauseButton);
- case kMediaCurrentTimeDisplay:
- return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplay);
- case kMediaTimeRemainingDisplay:
- return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplay);
- case kMediaShowClosedCaptionsButton:
- return QueryString(WebLocalizedString::kAXMediaShowClosedCaptionsButton);
- case kMediaHideClosedCaptionsButton:
- return QueryString(WebLocalizedString::kAXMediaHideClosedCaptionsButton);
case kMediaCastOffButton:
case kMediaOverlayCastOffButton:
return QueryString(WebLocalizedString::kAXMediaCastOffButton);
case kMediaCastOnButton:
case kMediaOverlayCastOnButton:
return QueryString(WebLocalizedString::kAXMediaCastOnButton);
- case kMediaDownloadButton:
- return QueryString(WebLocalizedString::kAXMediaDownloadButton);
case kMediaOverflowButton:
return QueryString(WebLocalizedString::kAXMediaOverflowButton);
case kMediaSliderThumb:
@@ -164,23 +127,16 @@ String AccessibilityMediaControl::TextAlternative(
case kMediaTimelineContainer:
case kMediaTrackSelectionCheckmark:
case kMediaControlsPanel:
- case kMediaVolumeSliderContainer:
- case kMediaVolumeSliderThumb:
case kMediaOverflowList:
case kMediaScrubbingMessage:
case kMediaAnimatedArrowContainer:
return QueryString(WebLocalizedString::kAXMediaDefault);
- case kMediaEnterPictureInPictureButton:
- return QueryString(
- WebLocalizedString::kAXMediaEnterPictureInPictureButton);
- case kMediaExitPictureInPictureButton:
- return QueryString(
- WebLocalizedString::kAXMediaExitPictureInPictureButton);
case kMediaDisplayCutoutFullscreenButton:
return QueryString(
WebLocalizedString::kAXMediaDisplayCutoutFullscreenButton);
case kMediaSlider:
- case kMediaVolumeSlider:
+ // Removed as a part of the a11y tree rewrite https://crbug/836549.
+ case kMediaIgnore:
NOTREACHED();
return QueryString(WebLocalizedString::kAXMediaDefault);
}
@@ -194,45 +150,29 @@ String AccessibilityMediaControl::Description(
ax::mojom::DescriptionFrom& description_from,
AXObjectVector* description_objects) const {
switch (ControlType()) {
- case kMediaCurrentTimeDisplay:
- return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplayHelp);
- case kMediaTimeRemainingDisplay:
- return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplayHelp);
case kMediaOverflowButton:
return QueryString(WebLocalizedString::kAXMediaOverflowButtonHelp);
// The following descriptions are repeats of their respective titles. When
// read by accessibility, we get the same thing said twice, with no value
// added. So instead, we just return an empty string.
- case kMediaEnterFullscreenButton:
- case kMediaExitFullscreenButton:
case kMediaDisplayCutoutFullscreenButton:
- case kMediaMuteButton:
- case kMediaUnMuteButton:
- case kMediaPlayButton:
- case kMediaPauseButton:
- case kMediaShowClosedCaptionsButton:
- case kMediaHideClosedCaptionsButton:
case kMediaCastOffButton:
case kMediaOverlayCastOffButton:
case kMediaCastOnButton:
case kMediaOverlayCastOnButton:
- case kMediaEnterPictureInPictureButton:
- case kMediaExitPictureInPictureButton:
return "";
case kMediaSliderThumb:
case kMediaTextTrackList:
case kMediaTimelineContainer:
case kMediaTrackSelectionCheckmark:
case kMediaControlsPanel:
- case kMediaVolumeSliderContainer:
- case kMediaVolumeSliderThumb:
case kMediaOverflowList:
- case kMediaDownloadButton:
case kMediaScrubbingMessage:
case kMediaAnimatedArrowContainer:
return QueryString(WebLocalizedString::kAXMediaDefault);
case kMediaSlider:
- case kMediaVolumeSlider:
+ // Removed as a part of the a11y tree rewrite https://crbug/836549.
+ case kMediaIgnore:
NOTREACHED();
return QueryString(WebLocalizedString::kAXMediaDefault);
}
@@ -253,43 +193,28 @@ bool AccessibilityMediaControl::ComputeAccessibilityIsIgnored(
ax::mojom::Role AccessibilityMediaControl::RoleValue() const {
switch (ControlType()) {
- case kMediaEnterFullscreenButton:
- case kMediaExitFullscreenButton:
- case kMediaMuteButton:
- case kMediaPlayButton:
- case kMediaUnMuteButton:
- case kMediaPauseButton:
- case kMediaShowClosedCaptionsButton:
- case kMediaHideClosedCaptionsButton:
case kMediaOverlayCastOffButton:
case kMediaOverlayCastOnButton:
case kMediaOverflowButton:
- case kMediaDownloadButton:
case kMediaCastOnButton:
case kMediaCastOffButton:
- case kMediaEnterPictureInPictureButton:
- case kMediaExitPictureInPictureButton:
case kMediaDisplayCutoutFullscreenButton:
return ax::mojom::Role::kButton;
case kMediaTimelineContainer:
- case kMediaVolumeSliderContainer:
case kMediaTextTrackList:
case kMediaOverflowList:
return ax::mojom::Role::kGroup;
case kMediaControlsPanel:
- case kMediaCurrentTimeDisplay:
- case kMediaTimeRemainingDisplay:
case kMediaSliderThumb:
case kMediaTrackSelectionCheckmark:
- case kMediaVolumeSliderThumb:
case kMediaScrubbingMessage:
case kMediaAnimatedArrowContainer:
return ax::mojom::Role::kUnknown;
case kMediaSlider:
- case kMediaVolumeSlider:
+ case kMediaIgnore:
// Not using AccessibilityMediaControl.
NOTREACHED();
return ax::mojom::Role::kUnknown;
@@ -342,12 +267,6 @@ bool AXMediaControlsContainer::ComputeAccessibilityIsIgnored(
//
// AccessibilityMediaTimeline
-static String LocalizedMediaTimeDescription(float /*time*/) {
- // FIXME: To be fixed. See
- // http://trac.webkit.org/browser/trunk/Source/WebCore/platform/LocalizedStrings.cpp#L928
- return String();
-}
-
AccessibilityMediaTimeline::AccessibilityMediaTimeline(
LayoutObject* layout_object,
AXObjectCacheImpl& ax_object_cache)
@@ -356,7 +275,8 @@ AccessibilityMediaTimeline::AccessibilityMediaTimeline(
AXObject* AccessibilityMediaTimeline::Create(
LayoutObject* layout_object,
AXObjectCacheImpl& ax_object_cache) {
- return new AccessibilityMediaTimeline(layout_object, ax_object_cache);
+ return MakeGarbageCollected<AccessibilityMediaTimeline>(layout_object,
+ ax_object_cache);
}
String AccessibilityMediaTimeline::Description(
@@ -368,83 +288,4 @@ String AccessibilityMediaTimeline::Description(
: WebLocalizedString::kAXMediaAudioSliderHelp);
}
-//
-// AccessibilityMediaVolumeSlider
-
-AccessibilityMediaVolumeSlider::AccessibilityMediaVolumeSlider(
- LayoutObject* layout_object,
- AXObjectCacheImpl& ax_object_cache)
- : AXSlider(layout_object, ax_object_cache) {}
-
-AXObject* AccessibilityMediaVolumeSlider::Create(
- LayoutObject* layout_object,
- AXObjectCacheImpl& ax_object_cache) {
- return new AccessibilityMediaVolumeSlider(layout_object, ax_object_cache);
-}
-
-String AccessibilityMediaVolumeSlider::Description(
- ax::mojom::NameFrom name_from,
- ax::mojom::DescriptionFrom& description_from,
- AXObjectVector* description_objects) const {
- return QueryString(WebLocalizedString::kAXMediaVolumeSliderHelp);
-}
-
-bool AccessibilityMediaVolumeSlider::InternalSetAccessibilityFocusAction() {
- MediaControlElementsHelper::NotifyMediaControlAccessibleFocus(GetElement());
- return AXSlider::InternalSetAccessibilityFocusAction();
-}
-
-bool AccessibilityMediaVolumeSlider::InternalClearAccessibilityFocusAction() {
- MediaControlElementsHelper::NotifyMediaControlAccessibleBlur(GetElement());
- return AXSlider::InternalClearAccessibilityFocusAction();
-}
-
-//
-// AccessibilityMediaTimeDisplay
-
-AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay(
- LayoutObject* layout_object,
- AXObjectCacheImpl& ax_object_cache)
- : AccessibilityMediaControl(layout_object, ax_object_cache) {}
-
-AXObject* AccessibilityMediaTimeDisplay::Create(
- LayoutObject* layout_object,
- AXObjectCacheImpl& ax_object_cache) {
- return new AccessibilityMediaTimeDisplay(layout_object, ax_object_cache);
-}
-
-bool AccessibilityMediaTimeDisplay::ComputeAccessibilityIsIgnored(
- IgnoredReasons* ignored_reasons) const {
- if (!layout_object_ || !layout_object_->Style() ||
- layout_object_->Style()->Visibility() != EVisibility::kVisible)
- return true;
-
- if (!layout_object_->Style()->Width().Value())
- return true;
-
- return AccessibilityIsIgnoredByDefault(ignored_reasons);
-}
-
-String AccessibilityMediaTimeDisplay::TextAlternative(
- bool recursive,
- bool in_aria_labelled_by_traversal,
- AXObjectSet& visited,
- ax::mojom::NameFrom& name_from,
- AXRelatedObjectVector* related_objects,
- NameSources* name_sources) const {
- if (ControlType() == kMediaCurrentTimeDisplay)
- return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplay);
- return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplay);
-}
-
-String AccessibilityMediaTimeDisplay::StringValue() const {
- if (!layout_object_ || !layout_object_->GetNode())
- return String();
-
- MediaControlTimeDisplayElement* element =
- static_cast<MediaControlTimeDisplayElement*>(layout_object_->GetNode());
- float time = element->CurrentValue();
- return LocalizedMediaTimeDescription(fabsf(time));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h
index 17f5f96ec85..ad9846671fc 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h
@@ -40,6 +40,8 @@ class AXObjectCacheImpl;
class AccessibilityMediaControl : public AXLayoutObject {
public:
static AXObject* Create(LayoutObject*, AXObjectCacheImpl&);
+
+ AccessibilityMediaControl(LayoutObject*, AXObjectCacheImpl&);
~AccessibilityMediaControl() override = default;
ax::mojom::Role RoleValue() const override;
@@ -58,7 +60,6 @@ class AccessibilityMediaControl : public AXLayoutObject {
bool InternalClearAccessibilityFocusAction() override;
protected:
- AccessibilityMediaControl(LayoutObject*, AXObjectCacheImpl&);
MediaControlElementType ControlType() const;
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
@@ -68,34 +69,16 @@ class AccessibilityMediaControl : public AXLayoutObject {
class AccessibilityMediaTimeline final : public AXSlider {
public:
static AXObject* Create(LayoutObject*, AXObjectCacheImpl&);
- ~AccessibilityMediaTimeline() override = default;
-
- String Description(ax::mojom::NameFrom,
- ax::mojom::DescriptionFrom&,
- AXObjectVector* description_objects) const override;
- private:
AccessibilityMediaTimeline(LayoutObject*, AXObjectCacheImpl&);
-
- DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaTimeline);
-};
-
-class AccessibilityMediaVolumeSlider final : public AXSlider {
- public:
- static AXObject* Create(LayoutObject*, AXObjectCacheImpl&);
- ~AccessibilityMediaVolumeSlider() override = default;
+ ~AccessibilityMediaTimeline() override = default;
String Description(ax::mojom::NameFrom,
ax::mojom::DescriptionFrom&,
AXObjectVector* description_objects) const override;
- bool InternalSetAccessibilityFocusAction() override;
- bool InternalClearAccessibilityFocusAction() override;
-
private:
- AccessibilityMediaVolumeSlider(LayoutObject*, AXObjectCacheImpl&);
-
- DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaVolumeSlider);
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaTimeline);
};
class AXMediaControlsContainer final : public AccessibilityMediaControl {
@@ -128,6 +111,8 @@ class AXMediaControlsContainer final : public AccessibilityMediaControl {
class AccessibilityMediaTimeDisplay final : public AccessibilityMediaControl {
public:
static AXObject* Create(LayoutObject*, AXObjectCacheImpl&);
+
+ AccessibilityMediaTimeDisplay(LayoutObject*, AXObjectCacheImpl&);
~AccessibilityMediaTimeDisplay() override = default;
ax::mojom::Role RoleValue() const override {
@@ -143,7 +128,6 @@ class AccessibilityMediaTimeDisplay final : public AccessibilityMediaControl {
NameSources*) const override;
private:
- AccessibilityMediaTimeDisplay(LayoutObject*, AXObjectCacheImpl&);
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaTimeDisplay);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 8db0b0c092c..6f67e81f0b9 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -150,10 +150,12 @@ bool AXNodeObject::ComputeAccessibilityIsIgnored(
// Ignore labels that are already referenced by a control.
AXObject* control_object = CorrespondingControlForLabelElement();
+ HTMLLabelElement* label = LabelElementContainer();
if (control_object && control_object->IsCheckboxOrRadio() &&
- control_object->NameFromLabelElement()) {
+ control_object->NameFromLabelElement() &&
+ AccessibleNode::GetPropertyOrARIAAttribute(
+ label, AOMStringProperty::kRole) == g_null_atom) {
if (ignored_reasons) {
- HTMLLabelElement* label = LabelElementContainer();
if (label && label != GetNode()) {
AXObject* label_ax_object = AXObjectCache().GetOrCreate(label);
ignored_reasons->push_back(
@@ -1422,11 +1424,8 @@ ax::mojom::InvalidState AXNodeObject::GetInvalidState() const {
if (GetNode() && GetNode()->IsElementNode() &&
ToElement(GetNode())->IsFormControlElement()) {
HTMLFormControlElement* element = ToHTMLFormControlElement(GetNode());
- HeapVector<Member<HTMLFormControlElement>> invalid_controls;
- bool is_invalid = !element->checkValidity(&invalid_controls,
- kCheckValidityDispatchNoEvent);
- return is_invalid ? ax::mojom::InvalidState::kTrue
- : ax::mojom::InvalidState::kFalse;
+ return element->IsNotCandidateOrValid() ? ax::mojom::InvalidState::kFalse
+ : ax::mojom::InvalidState::kTrue;
}
return AXObject::GetInvalidState();
@@ -1437,10 +1436,7 @@ int AXNodeObject::PosInSet() const {
uint32_t pos_in_set;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kPosInSet, pos_in_set))
return pos_in_set;
-
- return AutoPosInSet();
}
-
return 0;
}
@@ -1449,88 +1445,10 @@ int AXNodeObject::SetSize() const {
int32_t set_size;
if (HasAOMPropertyOrARIAAttribute(AOMIntProperty::kSetSize, set_size))
return set_size;
-
- return AutoSetSize();
}
-
return 0;
}
-int AXNodeObject::AutoPosInSet() const {
- AXObject* parent = ParentObjectUnignored();
-
- // Do not continue if the children will need updating soon, because
- // the calculation requires all the siblings to remain stable.
- if (!parent || parent->NeedsToUpdateChildren())
- return 0;
-
- int pos_in_set = 1;
- const AXObject::AXObjectVector siblings = parent->Children();
-
- ax::mojom::Role role = RoleValue();
- int level = HierarchicalLevel();
- int index_in_parent = IndexInParent();
-
- for (int index = index_in_parent - 1; index >= 0; index--) {
- const AXObject* sibling = siblings[index];
- ax::mojom::Role sibling_role = sibling->RoleValue();
- if (sibling_role == ax::mojom::Role::kSplitter ||
- sibling_role == ax::mojom::Role::kGroup)
- break; // Set stops at a separator or an optgroup.
- if (sibling_role != role || sibling->AccessibilityIsIgnored())
- continue;
-
- int sibling_level = sibling->HierarchicalLevel();
- if (sibling_level < level)
- break;
-
- if (sibling_level > level)
- continue; // Skip subset
-
- ++pos_in_set;
- }
-
- return pos_in_set;
-}
-
-int AXNodeObject::AutoSetSize() const {
- AXObject* parent = ParentObjectUnignored();
-
- // Do not continue if the children will need updating soon, because
- // the calculation requires all the siblings to remain stable.
- if (!parent || parent->NeedsToUpdateChildren())
- return 0;
-
- int set_size = AutoPosInSet();
- auto siblings = parent->Children();
-
- ax::mojom::Role role = RoleValue();
- int level = HierarchicalLevel();
- int index_in_parent = IndexInParent();
- int sibling_count = siblings.size();
-
- for (int index = index_in_parent + 1; index < sibling_count; index++) {
- const auto sibling = siblings[index];
- ax::mojom::Role sibling_role = sibling->RoleValue();
- if (sibling_role == ax::mojom::Role::kSplitter ||
- sibling_role == ax::mojom::Role::kGroup)
- break; // Set stops at a separator or an optgroup.
- if (sibling_role != role || sibling->AccessibilityIsIgnored())
- continue;
-
- int sibling_level = sibling->HierarchicalLevel();
- if (sibling_level < level)
- break;
-
- if (sibling_level > level)
- continue; // Skip subset
-
- ++set_size;
- }
-
- return set_size;
-}
-
String AXNodeObject::AriaInvalidValue() const {
if (GetInvalidState() == ax::mojom::InvalidState::kOther)
return GetAOMPropertyOrARIAAttribute(AOMStringProperty::kInvalid);
@@ -2061,9 +1979,8 @@ bool AXNodeObject::NameFromLabelElement() const {
HTMLElement* html_element = nullptr;
if (GetNode()->IsHTMLElement())
html_element = ToHTMLElement(GetNode());
- if (html_element && IsLabelableElement(html_element)) {
- if (ToLabelableElement(html_element)->labels() &&
- ToLabelableElement(html_element)->labels()->length() > 0)
+ if (html_element && html_element->IsLabelable()) {
+ if (html_element->labels() && html_element->labels()->length() > 0)
return true;
}
@@ -2534,17 +2451,25 @@ void AXNodeObject::ChildrenChanged() {
// update.
// If this element supports ARIA live regions, then notify the AT of
- // changes.
- if (parent->IsLiveRegion()) {
- AXObjectCache().PostNotification(parent,
- ax::mojom::Event::kLiveRegionChanged);
+ // changes. Do not fire live region changed events if aria-live="off".
+ if (parent->IsLiveRegionRoot()) {
+ if (parent->IsActiveLiveRegionRoot()) {
+ AXObjectCache().PostNotification(parent,
+ ax::mojom::Event::kLiveRegionChanged);
+ }
+ break;
}
+ }
+ for (AXObject* parent = this; parent;
+ parent = parent->ParentObjectIfExists()) {
// If this element is an ARIA text box or content editable, post a "value
// changed" notification on it so that it behaves just like a native input
// element or textarea.
- if (IsNonNativeTextControl())
+ if (IsNonNativeTextControl()) {
AXObjectCache().PostNotification(parent, ax::mojom::Event::kValueChanged);
+ break;
+ }
}
}
@@ -2614,14 +2539,27 @@ void AXNodeObject::TextChanged() {
if (!parent)
continue;
- if (parent->IsLiveRegion())
- cache.PostNotification(parent_node, ax::mojom::Event::kLiveRegionChanged);
+ if (parent->IsLiveRegionRoot()) {
+ if (parent->IsActiveLiveRegionRoot()) {
+ cache.PostNotification(parent_node,
+ ax::mojom::Event::kLiveRegionChanged);
+ }
+ break;
+ }
+ }
- // If this element is an ARIA text box or content editable, post a "value
- // changed" notification on it so that it behaves just like a native input
- // element or textarea.
- if (parent->IsNonNativeTextControl())
+ // If this element is an ARIA text box or content editable, post a "value
+ // changed" notification on it so that it behaves just like a native input
+ // element or textarea.
+ for (Node* parent_node = GetNode(); parent_node;
+ parent_node = parent_node->parentNode()) {
+ AXObject* parent = cache.Get(parent_node);
+ if (!parent)
+ continue;
+ if (parent->IsNonNativeTextControl()) {
cache.PostNotification(parent_node, ax::mojom::Event::kValueChanged);
+ break;
+ }
}
}
@@ -2693,7 +2631,7 @@ String AXNodeObject::NativeTextAlternative(
name_sources->back().native_source = kAXTextFromNativeHTMLLabel;
}
- LabelsNodeList* labels = ToLabelableElement(html_element)->labels();
+ LabelsNodeList* labels = html_element->labels();
if (labels && labels->length() > 0) {
HeapVector<Member<Element>> label_elements;
for (unsigned label_index = 0; label_index < labels->length();
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h
index b3768b6c445..9873147ecc5 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -216,11 +216,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
// Position in set and Size of set
int PosInSet() const override;
int SetSize() const override;
- // Compute the number of siblings that have the same role before |this|,
- // following rules for counting the number of items in a set.
- int AutoPosInSet() const;
- // Compute the number of unignored siblings with the same role as |this|.
- int AutoSetSize() const;
// Aria-owns.
void ComputeAriaOwnsChildren(
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 74d530e7748..e3bae41102c 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -340,8 +340,9 @@ const InternalRoleEntry kInternalRoles[] = {
{ax::mojom::Role::kLegend, "Legend"},
{ax::mojom::Role::kLink, "Link"},
{ax::mojom::Role::kLineBreak, "LineBreak"},
- {ax::mojom::Role::kListBoxOption, "ListBoxOption"},
{ax::mojom::Role::kListBox, "ListBox"},
+ {ax::mojom::Role::kListBoxOption, "ListBoxOption"},
+ {ax::mojom::Role::kListGrid, "ListGrid"},
{ax::mojom::Role::kListItem, "ListItem"},
{ax::mojom::Role::kListMarker, "ListMarker"},
{ax::mojom::Role::kList, "List"},
@@ -386,11 +387,11 @@ const InternalRoleEntry kInternalRoles[] = {
{ax::mojom::Role::kStaticText, "StaticText"},
{ax::mojom::Role::kStatus, "Status"},
{ax::mojom::Role::kSwitch, "Switch"},
+ {ax::mojom::Role::kTab, "Tab"},
{ax::mojom::Role::kTabList, "TabList"},
{ax::mojom::Role::kTabPanel, "TabPanel"},
- {ax::mojom::Role::kTab, "Tab"},
- {ax::mojom::Role::kTableHeaderContainer, "TableHeaderContainer"},
{ax::mojom::Role::kTable, "Table"},
+ {ax::mojom::Role::kTableHeaderContainer, "TableHeaderContainer"},
{ax::mojom::Role::kTerm, "Term"},
{ax::mojom::Role::kTextField, "TextField"},
{ax::mojom::Role::kTextFieldWithComboBox, "ComboBox"},
@@ -901,9 +902,12 @@ void AXObject::UpdateCachedAttributeValuesIfNeeded() const {
!!InheritsPresentationalRoleFrom();
cached_is_ignored_ = ComputeAccessibilityIsIgnored();
cached_is_editable_root_ = ComputeIsEditableRoot();
+ // Compute live region root, which can be from any ARIA live value, including
+ // "off", or from an automatic ARIA live value, e.g. from role="status".
// TODO(dmazzoni): remove this const_cast.
+ AtomicString aria_live;
cached_live_region_root_ =
- IsLiveRegion()
+ IsLiveRegionRoot()
? const_cast<AXObject*>(this)
: (ParentObjectIfExists() ? ParentObjectIfExists()->LiveRegionRoot()
: nullptr);
@@ -1723,7 +1727,8 @@ void AXObject::Markers(Vector<DocumentMarker::MarkerType>&,
void AXObject::TextCharacterOffsets(Vector<int>&) const {}
-void AXObject::GetWordBoundaries(Vector<AXRange>&) const {}
+void AXObject::GetWordBoundaries(Vector<int>& word_starts,
+ Vector<int>& word_ends) const {}
ax::mojom::DefaultActionVerb AXObject::Action() const {
Element* action_element = ActionElement();
@@ -1911,7 +1916,12 @@ int AXObject::IndexInParent() const {
return (index == kNotFound) ? 0 : static_cast<int>(index);
}
-bool AXObject::IsLiveRegion() const {
+bool AXObject::IsLiveRegionRoot() const {
+ const AtomicString& live_region = LiveRegionStatus();
+ return !live_region.IsEmpty();
+}
+
+bool AXObject::IsActiveLiveRegionRoot() const {
const AtomicString& live_region = LiveRegionStatus();
return !live_region.IsEmpty() && !EqualIgnoringASCIICase(live_region, "off");
}
@@ -2526,7 +2536,7 @@ AXObject* AXObject::CellForColumnAndRow(unsigned target_column_index,
// i.e. it's an ARIA grid/table.
//
// TODO(dmazzoni): delete this code or rename it "for testing only"
- // since it's only needed for Blink layout tests and not for production.
+ // since it's only needed for Blink web tests and not for production.
unsigned row_index = 0;
for (const auto& row : TableRowChildren()) {
unsigned column_index = 0;
@@ -2585,45 +2595,11 @@ int AXObject::AriaRowCount() const {
}
unsigned AXObject::ColumnIndex() const {
- if (!IsTableCellLikeRole())
- return 0;
-
- const AXObject* row = TableRowParent();
- if (!row)
- return 0;
-
- unsigned column_index = 0;
- for (const auto& child : row->TableCellChildren()) {
- if (child == this)
- break;
- column_index++;
- }
- return column_index;
+ return 0;
}
unsigned AXObject::RowIndex() const {
- const AXObject* row = nullptr;
- if (IsTableRowLikeRole())
- row = this;
- else if (IsTableCellLikeRole())
- row = TableRowParent();
-
- if (!row)
- return 0;
-
- const AXObject* table = row->TableParent();
- if (!table)
- return 0;
-
- unsigned row_index = 0;
- for (const auto& child : table->TableRowChildren()) {
- if (child == row)
- break;
- if (!child->IsTableRowLikeRole())
- continue;
- row_index++;
- }
- return row_index;
+ return 0;
}
unsigned AXObject::ColumnSpan() const {
@@ -2645,84 +2621,19 @@ unsigned AXObject::AriaRowIndex() const {
}
unsigned AXObject::ComputeAriaColumnIndex() const {
- if (!IsTableCellLikeRole())
- return 0;
-
- // First see if it has an ARIA column index explicitly set.
- uint32_t col_index;
- if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex, col_index) &&
- col_index >= 1) {
- return col_index;
- }
-
- // Get the previous sibling.
- // TODO(dmazzoni): this code depends on the DOM; move this code out of Blink
- // and make it more general.
- AXObject* previous = nullptr;
- if (GetNode()) {
- Node* previousNode = ElementTraversal::PreviousSibling(*GetNode());
- previous = AXObjectCache().GetOrCreate(previousNode);
- }
-
- // It has a previous sibling, so if that cell has a column index, this one's
- // index is one greater.
- if (previous) {
- col_index = previous->AriaColumnIndex();
- if (col_index)
- return col_index + 1;
- return 0;
- }
-
- // No previous cell, so check the row to see if it sets a column index.
- const AXObject* row = TableRowParent();
- if (!row)
- return 0;
- if (row->HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex,
- col_index)) {
- return col_index;
- }
-
- // Otherwise there's no ARIA column index.
- return 0;
+ // Return the ARIA column index if it has been set. Otherwise return a default
+ // value of 0.
+ uint32_t col_index = 0;
+ HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex, col_index);
+ return col_index;
}
unsigned AXObject::ComputeAriaRowIndex() const {
- if (!IsTableCellLikeRole() && !IsTableRowLikeRole())
- return 0;
-
- // First check if there's an ARIA row index explicitly set.
- uint32_t row_index;
- if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kRowIndex, row_index) &&
- row_index >= 1) {
- return row_index;
- }
-
- // If this is a cell, return the ARIA row index of the containing row.
- if (IsTableCellLikeRole()) {
- const AXObject* row = TableRowParent();
- if (row)
- return row->AriaRowIndex();
- return 0;
- }
-
- // Otherwise, this is a row. Find the previous sibling row.
- // TODO(dmazzoni): this code depends on the DOM; move this code out of Blink
- // and make it more general.
- if (!GetNode())
- return 0;
- Node* previousNode = ElementTraversal::PreviousSibling(*GetNode());
- AXObject* previous = AXObjectCache().GetOrCreate(previousNode);
- if (!previous || !previous->IsTableRowLikeRole())
- return 0;
-
- // If the previous row has an ARIA row index, this one is the same index
- // plus one.
- row_index = previous->AriaRowIndex();
- if (row_index)
- return row_index + 1;
-
- // Otherwise there's no ARIA row index.
- return 0;
+ // Return the ARIA row index if it has been set. Otherwise return a default
+ // value of 0.
+ uint32_t row_index = 0;
+ HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kRowIndex, row_index);
+ return row_index;
}
AXObject::AXObjectVector AXObject::TableRowChildren() const {
@@ -2933,6 +2844,9 @@ bool AXObject::OnNativeClickAction() {
if (!element && GetNode())
element = GetNode()->parentElement();
+ if (IsTextControl())
+ return OnNativeFocusAction();
+
if (element) {
element->AccessKeyAction(true);
return true;
@@ -3319,6 +3233,7 @@ bool AXObject::NameFromContents(bool recursive) const {
case ax::mojom::Role::kInputTime:
case ax::mojom::Role::kKeyboard:
case ax::mojom::Role::kListBox:
+ case ax::mojom::Role::kListGrid:
case ax::mojom::Role::kLog:
case ax::mojom::Role::kMain:
case ax::mojom::Role::kMarquee:
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
index 88cb1e84c82..7d11bb33a91 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -528,6 +528,7 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> {
virtual bool IsTextControl() const { return false; }
bool IsTextObject() const;
bool IsTree() const { return RoleValue() == ax::mojom::Role::kTree; }
+ virtual bool IsValidationMessage() const { return false; }
virtual bool IsVirtualObject() const { return false; }
bool IsWebArea() const {
return RoleValue() == ax::mojom::Role::kRootWebArea;
@@ -714,7 +715,8 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> {
// negative values for RTL.
virtual void TextCharacterOffsets(Vector<int>&) const;
// The start and end character offset of each word in the object's text.
- virtual void GetWordBoundaries(Vector<AXRange>&) const;
+ virtual void GetWordBoundaries(Vector<int>& word_starts,
+ Vector<int>& word_ends) const;
// Properties of interactive elements.
ax::mojom::DefaultActionVerb Action() const;
@@ -743,6 +745,7 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> {
virtual String AriaAutoComplete() const { return String(); }
virtual void AriaOwnsElements(AXObjectVector& owns) const {}
virtual void AriaDescribedbyElements(AXObjectVector&) const {}
+ virtual AXObject* ErrorMessage() const { return nullptr; }
virtual ax::mojom::HasPopup HasPopup() const {
return ax::mojom::HasPopup::kFalse;
}
@@ -771,8 +774,9 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> {
bool SupportsARIASetSizeAndPosInSet() const;
// ARIA live-region features.
- bool IsLiveRegion() const;
- AXObject* LiveRegionRoot() const;
+ bool IsLiveRegionRoot() const; // Any live region, including polite="off".
+ bool IsActiveLiveRegionRoot() const; // Live region that is not polite="off".
+ AXObject* LiveRegionRoot() const; // Container that controls live politeness.
virtual const AtomicString& LiveRegionStatus() const { return g_null_atom; }
virtual const AtomicString& LiveRegionRelevant() const { return g_null_atom; }
bool LiveRegionAtomic() const;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index a2b707ddda3..1606304ac1c 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -45,6 +45,7 @@
#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
+#include "third_party/blink/renderer/core/html/forms/listed_element.h"
#include "third_party/blink/renderer/core/html/html_area_element.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
@@ -81,7 +82,9 @@
#include "third_party/blink/renderer/modules/accessibility/ax_relation_cache.h"
#include "third_party/blink/renderer/modules/accessibility/ax_slider.h"
#include "third_party/blink/renderer/modules/accessibility/ax_svg_root.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_validation_message.h"
#include "third_party/blink/renderer/modules/accessibility/ax_virtual_object.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
namespace blink {
@@ -97,6 +100,7 @@ AXObjectCacheImpl::AXObjectCacheImpl(Document& document)
: AXObjectCacheBase(document),
document_(document),
modification_count_(0),
+ validation_message_axid_(0),
relation_cache_(new AXRelationCache(this)),
notification_post_timer_(
document.GetTaskRunner(TaskType::kInternalDefault),
@@ -311,8 +315,12 @@ AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
return AXList::Create(layout_object, *this);
// media controls
- if (node && node->IsMediaControlElement())
+ // TODO(836549): Remove for the rest of the controls.
+ if (node && node->IsMediaControlElement() &&
+ MediaControlElementsHelper::GetMediaControlElementType(node) !=
+ kMediaIgnore) {
return AccessibilityMediaControl::Create(layout_object, *this);
+ }
if (IsHTMLOptionElement(node))
return AXListBoxOption::Create(layout_object, *this);
@@ -726,8 +734,8 @@ void AXObjectCacheImpl::DidInsertChildrenOfNode(Node* node) {
void AXObjectCacheImpl::ChildrenChanged(Node* node) {
if (!node)
return;
-
- if (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) {
+ if (node->GetDocument().IsFlatTreeTraversalForbidden() ||
+ node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) {
nodes_changed_during_layout_.push_back(node);
return;
}
@@ -748,7 +756,8 @@ void AXObjectCacheImpl::ChildrenChanged(LayoutObject* layout_object) {
Node* node = GetClosestNodeForLayoutObject(layout_object);
- if (node && (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node) ||
+ if (node && (node->GetDocument().IsFlatTreeTraversalForbidden() ||
+ node->GetDocument().NeedsLayoutTreeUpdateForNode(*node) ||
node->NeedsDistributionRecalc())) {
nodes_changed_during_layout_.push_back(node);
return;
@@ -1007,7 +1016,7 @@ void AXObjectCacheImpl::HandleActiveDescendantChanged(Node* node) {
// as this may require a different subclass of AXObject.
// Role changes are disallowed by the spec but we must handle it gracefully, see
// https://www.w3.org/TR/wai-aria-1.1/#h-roles for more information.
-void AXObjectCacheImpl::HandlePossibleRoleChange(Node* node) {
+void AXObjectCacheImpl::HandleRoleChange(Node* node) {
if (!node)
return; // Virtual AOM node.
@@ -1036,6 +1045,25 @@ void AXObjectCacheImpl::HandlePossibleRoleChange(Node* node) {
}
}
+void AXObjectCacheImpl::HandleRoleChangeIfNotEditable(Node* node) {
+ if (!node)
+ return;
+
+ // Do not invalidate object if the role doesn't actually change when it's a
+ // text control, otherwise unique id will change on platform side, and confuse
+ // some screen readers as user edits.
+ // TODO(aleventhal) Ideally the text control check would be removed, and
+ // HandleRoleChange() and only ever invalidate when the role actually changes.
+ // For example:
+ // if (obj->RoleValue() == obj->ComputeAccessibilityRole()) return;
+ // However, doing that would require waiting for layout to complete, as
+ // ComputeAccessibilityRole() looks at layout objects.
+ if (AXObject* obj = Get(node)) {
+ if (!obj->IsTextControl())
+ HandleRoleChange(node);
+ }
+}
+
void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name,
Element* element) {
if (!element)
@@ -1048,9 +1076,10 @@ void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name,
return;
}
- if (attr_name == kRoleAttr || attr_name == kTypeAttr ||
- attr_name == kSizeAttr || attr_name == kAriaHaspopupAttr)
- HandlePossibleRoleChange(element);
+ if (attr_name == kRoleAttr || attr_name == kTypeAttr)
+ HandleRoleChange(element);
+ else if (attr_name == kSizeAttr || attr_name == kAriaHaspopupAttr)
+ HandleRoleChangeIfNotEditable(element); // Role won't change on edits.
else if (attr_name == kAltAttr || attr_name == kTitleAttr)
TextChanged(element);
else if (attr_name == kForAttr && IsHTMLLabelElement(*element))
@@ -1085,6 +1114,8 @@ void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name,
ChildrenChanged(element->parentNode());
else if (attr_name == kAriaInvalidAttr)
PostNotification(element, ax::mojom::Event::kInvalidStatusChanged);
+ else if (attr_name == kAriaErrormessageAttr)
+ MarkElementDirty(element, false);
else if (attr_name == kAriaOwnsAttr)
ChildrenChanged(element);
else
@@ -1097,6 +1128,68 @@ void AXObjectCacheImpl::HandleAutofillStateChanged(Element* elem,
obj->HandleAutofillStateChanged(is_available);
}
+AXObject* AXObjectCacheImpl::GetOrCreateValidationMessageObject() {
+ AXObject* message_ax_object = nullptr;
+ // Create only if it does not already exist.
+ if (validation_message_axid_) {
+ message_ax_object = ObjectFromAXID(validation_message_axid_);
+ }
+ if (!message_ax_object) {
+ message_ax_object = AXValidationMessage::Create(*this);
+ DCHECK(message_ax_object);
+ // Cache the validation message container for reuse.
+ validation_message_axid_ = GetOrCreateAXID(message_ax_object);
+ message_ax_object->Init();
+ }
+ return message_ax_object;
+}
+
+AXObject* AXObjectCacheImpl::ValidationMessageObjectIfVisible() {
+ Element* focused_element = document_->FocusedElement();
+ if (!focused_element)
+ return nullptr;
+ ListedElement* form_control = ListedElement::From(*focused_element);
+ if (!form_control || !form_control->IsValidationMessageVisible())
+ return nullptr;
+
+ AXObject* focused_object = this->FocusedObject();
+ DCHECK(focused_object);
+
+ // Return as long as the focused form control isn't overriding with a
+ // different message via aria-errormessage.
+ bool override_native_validation_message =
+ focused_object->GetAOMPropertyOrARIAAttribute(
+ AOMRelationProperty::kErrorMessage);
+ if (override_native_validation_message)
+ return nullptr;
+
+ return GetOrCreateValidationMessageObject();
+}
+
+// Native validation error popup for focused form control in current document.
+void AXObjectCacheImpl::HandleValidationMessageVisibilityChanged(
+ const Element* form_control) {
+ AXObject* message_ax_object = ValidationMessageObjectIfVisible();
+ if (!message_ax_object && validation_message_axid_) {
+ // Remove when it becomes hidden, so that a new object is created the next
+ // time the message becomes visible. It's not possible to reuse the same
+ // alert, because the event generator will not generate an alert event if
+ // the same object is hidden and made visible quickly, which occurs if the
+ // user submits the form when an alert is already visible.
+ Remove(validation_message_axid_);
+ validation_message_axid_ = 0;
+ }
+
+ // Form control will now have an error message relation to message container.
+ MarkElementDirty(form_control, false);
+
+ // Validation message alert object is a child of the document, as not all form
+ // controls can have a child. Also, there are form controls such as listbox
+ // that technically can have children, but they are probably not expected to
+ // have alerts within AT client code.
+ ChildrenChanged(document_);
+}
+
void AXObjectCacheImpl::LabelChanged(Element* element) {
TextChanged(ToHTMLLabelElement(element)->control());
}
@@ -1209,6 +1302,11 @@ void AXObjectCacheImpl::MarkAXObjectDirty(AXObject* obj, bool subtree) {
webframe->Client()->MarkWebAXObjectDirty(WebAXObject(obj), subtree);
}
+void AXObjectCacheImpl::MarkElementDirty(const Element* element, bool subtree) {
+ if (AXObject* obj = Get(element))
+ MarkAXObjectDirty(obj, subtree);
+}
+
void AXObjectCacheImpl::HandleFocusedUIElementChanged(Node* old_focused_node,
Node* new_focused_node) {
if (!new_focused_node)
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 9e12cae261f..684b1f4713c 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -107,6 +107,8 @@ class MODULES_EXPORT AXObjectCacheImpl
void HandleAttributeChanged(const QualifiedName& attr_name,
Element*) override;
void HandleAutofillStateChanged(Element*, bool) override;
+ void HandleValidationMessageVisibilityChanged(
+ const Element* form_control) override;
void HandleFocusedUIElementChanged(Node* old_focused_node,
Node* new_focused_node) override;
void HandleInitialFocus() override;
@@ -173,7 +175,8 @@ class MODULES_EXPORT AXObjectCacheImpl
void MaybeNewRelationTarget(Node* node, AXObject* obj);
void HandleActiveDescendantChanged(Node*);
- void HandlePossibleRoleChange(Node*);
+ void HandleRoleChange(Node*);
+ void HandleRoleChangeIfNotEditable(Node*);
void HandleAriaExpandedChange(Node*);
void HandleAriaSelectedChanged(Node*);
@@ -192,6 +195,7 @@ class MODULES_EXPORT AXObjectCacheImpl
void PostNotification(Node*, ax::mojom::Event);
void PostNotification(AXObject*, ax::mojom::Event);
void MarkAXObjectDirty(AXObject*, bool subtree);
+ void MarkElementDirty(const Element*, bool subtree);
//
// Aria-owns support.
@@ -227,6 +231,9 @@ class MODULES_EXPORT AXObjectCacheImpl
// granted, it only applies to the next event received.
void RequestAOMEventListenerPermission();
+ // For built-in HTML form validation messages.
+ AXObject* ValidationMessageObjectIfVisible();
+
protected:
void PostPlatformNotification(AXObject*, ax::mojom::Event);
void LabelChanged(Element*);
@@ -248,6 +255,12 @@ class MODULES_EXPORT AXObjectCacheImpl
HashSet<AXID> ids_in_use_;
+ // Used for a mock AXObject representing the message displayed in the
+ // validation message bubble.
+ // There can be only one of these per document with invalid form controls,
+ // and it will always be related to the currently focused control.
+ AXID validation_message_axid_;
+
std::unique_ptr<AXRelationCache> relation_cache_;
#if DCHECK_IS_ON()
@@ -288,6 +301,9 @@ class MODULES_EXPORT AXObjectCacheImpl
// Must be called an entire subtree of accessible objects are no longer valid.
void InvalidateTableSubtree(AXObject* subtree);
+ // Object for HTML validation alerts. Created at most once per object cache.
+ AXObject* GetOrCreateValidationMessageObject();
+
// Whether the user has granted permission for the user to install event
// listeners for accessibility events using the AOM.
mojom::PermissionStatus accessibility_event_permission_;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
index c3d9cafbd5c..3bda74c1366 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
@@ -28,8 +28,10 @@ const AXPosition AXPosition::CreatePositionBeforeObject(
if (child.IsDetached())
return {};
- // If |child| is a text object, make behavior the same as
- // |CreateFirstPositionInObject| so that equality would hold.
+ // If |child| is a text object, but not a text control, make behavior the same
+ // as |CreateFirstPositionInObject| so that equality would hold. Text controls
+ // behave differently because you should be able to set a position before the
+ // text control in case you want to e.g. select it as a whole.
if (child.IsTextObject())
return CreateFirstPositionInObject(child, adjustment_behavior);
@@ -48,8 +50,10 @@ const AXPosition AXPosition::CreatePositionAfterObject(
if (child.IsDetached())
return {};
- // If |child| is a text object, make behavior the same as
- // |CreateLastPositionInObject| so that equality would hold.
+ // If |child| is a text object, but not a text control, make behavior the same
+ // as |CreateLastPositionInObject| so that equality would hold. Text controls
+ // behave differently because you should be able to set a position after the
+ // text control in case you want to e.g. select it as a whole.
if (child.IsTextObject())
return CreateLastPositionInObject(child, adjustment_behavior);
@@ -68,7 +72,7 @@ const AXPosition AXPosition::CreateFirstPositionInObject(
if (container.IsDetached())
return {};
- if (container.IsTextObject()) {
+ if (container.IsTextObject() || container.IsNativeTextControl()) {
AXPosition position(container);
position.text_offset_or_child_index_ = 0;
DCHECK(position.IsValid());
@@ -92,7 +96,7 @@ const AXPosition AXPosition::CreateLastPositionInObject(
if (container.IsDetached())
return {};
- if (container.IsTextObject()) {
+ if (container.IsTextObject() || container.IsNativeTextControl()) {
AXPosition position(container);
position.text_offset_or_child_index_ = position.MaxTextOffset();
DCHECK(position.IsValid());
@@ -115,8 +119,10 @@ const AXPosition AXPosition::CreatePositionInTextObject(
const int offset,
const TextAffinity affinity,
const AXPositionAdjustmentBehavior adjustment_behavior) {
- if (container.IsDetached() || !container.IsTextObject())
+ if (container.IsDetached() ||
+ !(container.IsTextObject() || container.IsTextControl())) {
return {};
+ }
AXPosition position(container);
position.text_offset_or_child_index_ = offset;
@@ -330,6 +336,9 @@ int AXPosition::MaxTextOffset() const {
return 0;
}
+ if (container_object_->IsNativeTextControl())
+ return container_object_->StringValue().length();
+
if (container_object_->IsAXInlineTextBox() || !container_object_->GetNode()) {
// 1. The |Node| associated with an inline text box contains all the text in
// the static text object parent, whilst the inline text box might contain
@@ -391,7 +400,8 @@ bool AXPosition::IsTextPosition() const {
// We don't call |IsValid| from here because |IsValid| uses this method.
if (!container_object_)
return false;
- return container_object_->IsTextObject();
+ return container_object_->IsTextObject() ||
+ container_object_->IsNativeTextControl();
}
const AXPosition AXPosition::CreateNextPosition() const {
@@ -441,7 +451,7 @@ const AXPosition AXPosition::CreatePreviousPosition() const {
if (container_object_->ChildCount()) {
const AXObject* last_child = container_object_->LastChild();
// Dont skip over any intervening text.
- if (last_child->IsTextObject()) {
+ if (last_child->IsTextObject() || last_child->IsNativeTextControl()) {
return CreatePositionAfterObject(
*last_child, AXPositionAdjustmentBehavior::kMoveLeft);
}
@@ -461,7 +471,8 @@ const AXPosition AXPosition::CreatePreviousPosition() const {
}
// Dont skip over any intervening text.
- if (object_before_position->IsTextObject()) {
+ if (object_before_position->IsTextObject() ||
+ object_before_position->IsNativeTextControl()) {
return CreatePositionAfterObject(*object_before_position,
AXPositionAdjustmentBehavior::kMoveLeft);
}
@@ -650,7 +661,7 @@ const PositionWithAffinity AXPosition::ToPositionWithAffinity(
DCHECK(child_node) << "AX objects used in AX positions that are valid "
"DOM positions should always be connected to their "
"DOM nodes.";
- if (child_node->NodeIndex() == 0) {
+ if (!child_node->previousSibling()) {
// Creates a |PositionAnchorType::kBeforeChildren| position.
container_node = child_node->parentNode();
DCHECK(container_node);
@@ -672,8 +683,7 @@ const PositionWithAffinity AXPosition::ToPositionWithAffinity(
"connected to their DOM nodes.";
// Check if this is an "after children" position in the DOM as well.
- if ((last_child_node->NodeIndex() + 1) ==
- container_node->CountChildren()) {
+ if (!last_child_node->nextSibling()) {
// Creates a |PositionAnchorType::kAfterChildren| position.
container_node = last_child_node->parentNode();
DCHECK(container_node);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc
index 2ebc65a39b8..a0fb32e367e 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc
@@ -70,7 +70,7 @@ constexpr char kAOM[] = R"HTML(
<p id="after">After virtual AOM node.</p>
<script>
let parent = document.getElementById("aomParent");
- let node = new AccessibleNode();
+ let node = MakeGarbageCollected<AccessibleNode>();
node.role = "button";
node.label = "Button";
parent.accessibleNode.appendChild(node);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
index 9a01cb2ba90..c587778440b 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -6,7 +6,6 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
-#include "third_party/blink/renderer/core/html/forms/labelable_element.h"
namespace blink {
@@ -258,7 +257,7 @@ void AXRelationCache::TextChanged(AXObject* object) {
}
void AXRelationCache::LabelChanged(Node* node) {
- if (LabelableElement* control = ToHTMLLabelElement(node)->control())
+ if (HTMLElement* control = ToHTMLLabelElement(node)->control())
TextChanged(Get(control));
}
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc
index 71e240e746c..0aceee8edd7 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc
@@ -15,11 +15,20 @@
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
namespace blink {
namespace {
+// TODO(nektar): Add Web tests for this event.
+void ScheduleSelectEvent(TextControlElement& text_control) {
+ Event* event = Event::CreateBubble(event_type_names::kSelect);
+ event->SetTarget(&text_control);
+ text_control.GetDocument().EnqueueAnimationFrameEvent(event);
+}
+
+// TODO(nektar): Add Web tests for this event.
DispatchEventResult DispatchSelectStart(Node* node) {
if (!node)
return DispatchEventResult::kNotCanceled;
@@ -111,11 +120,11 @@ void AXSelection::ClearCurrentSelection(Document& document) {
AXSelection AXSelection::FromCurrentSelection(
const Document& document,
const AXSelectionBehavior selection_behavior) {
- LocalFrame* frame = document.GetFrame();
+ const LocalFrame* frame = document.GetFrame();
if (!frame)
return {};
- FrameSelection& frame_selection = frame->Selection();
+ const FrameSelection& frame_selection = frame->Selection();
if (!frame_selection.IsAvailable())
return {};
@@ -124,6 +133,30 @@ AXSelection AXSelection::FromCurrentSelection(
}
// static
+AXSelection AXSelection::FromCurrentSelection(
+ const TextControlElement& text_control) {
+ const Document& document = text_control.GetDocument();
+ AXObjectCache* ax_object_cache = document.ExistingAXObjectCache();
+ if (!ax_object_cache)
+ return {};
+
+ auto* ax_object_cache_impl = static_cast<AXObjectCacheImpl*>(ax_object_cache);
+ const AXObject* ax_text_control =
+ ax_object_cache_impl->GetOrCreate(&text_control);
+ DCHECK(ax_text_control);
+ const TextAffinity affinity = text_control.Selection().Affinity();
+ const auto ax_base = AXPosition::CreatePositionInTextObject(
+ *ax_text_control, static_cast<int>(text_control.selectionStart()));
+ const auto ax_extent = AXPosition::CreatePositionInTextObject(
+ *ax_text_control, static_cast<int>(text_control.selectionEnd()),
+ affinity);
+
+ AXSelection::Builder selection_builder;
+ selection_builder.SetBase(ax_base).SetExtent(ax_extent);
+ return selection_builder.Build();
+}
+
+// static
AXSelection AXSelection::FromSelection(
const SelectionInDOMTree& selection,
const AXSelectionBehavior selection_behavior) {
@@ -188,6 +221,33 @@ bool AXSelection::IsValid() const {
return false;
}
+ //
+ // The following code checks if a text position in a text control is valid.
+ // Since the contents of a text control are implemented using user agent
+ // shadow DOM, we want to prevent users from selecting across the shadow DOM
+ // boundary.
+ //
+ // TODO(nektar): Generalize this logic to adjust user selection if it crosses
+ // disallowed shadow DOM boundaries such as user agent shadow DOM, editing
+ // boundaries, replaced elements, CSS user-select, etc.
+ //
+
+ if (base_.IsTextPosition() &&
+ base_.ContainerObject()->IsNativeTextControl() &&
+ !(base_.ContainerObject() == extent_.ContainerObject() &&
+ extent_.IsTextPosition() &&
+ extent_.ContainerObject()->IsNativeTextControl())) {
+ return false;
+ }
+
+ if (extent_.IsTextPosition() &&
+ extent_.ContainerObject()->IsNativeTextControl() &&
+ !(base_.ContainerObject() == extent_.ContainerObject() &&
+ base_.IsTextPosition() &&
+ base_.ContainerObject()->IsNativeTextControl())) {
+ return false;
+ }
+
DCHECK(!base_.ContainerObject()->GetDocument()->NeedsLayoutTreeUpdate());
#if DCHECK_IS_ON()
DCHECK_EQ(base_.ContainerObject()->GetDocument()->DomTreeVersion(),
@@ -244,6 +304,22 @@ bool AXSelection::Select(const AXSelectionBehavior selection_behavior) {
return false;
}
+ base::Optional<AXSelection::TextControlSelection> text_control_selection =
+ AsTextControlSelection();
+ if (text_control_selection.has_value()) {
+ DCHECK_LE(text_control_selection->start, text_control_selection->end);
+ TextControlElement& text_control =
+ ToTextControl(*base_.ContainerObject()->GetNode());
+ if (!text_control.SetSelectionRange(text_control_selection->start,
+ text_control_selection->end,
+ text_control_selection->direction)) {
+ return false;
+ }
+
+ ScheduleSelectEvent(text_control);
+ return true;
+ }
+
const SelectionInDOMTree selection = AsSelection(selection_behavior);
DCHECK(selection.AssertValid());
Document* document = selection.Base().GetDocument();
@@ -313,6 +389,24 @@ String AXSelection::ToString() const {
return "AXSelection from " + Base().ToString() + " to " + Extent().ToString();
}
+base::Optional<AXSelection::TextControlSelection>
+AXSelection::AsTextControlSelection() const {
+ if (!IsValid() || !base_.IsTextPosition() || !extent_.IsTextPosition() ||
+ base_.ContainerObject() != extent_.ContainerObject() ||
+ !base_.ContainerObject()->IsNativeTextControl() ||
+ !IsTextControl(base_.ContainerObject()->GetNode())) {
+ return {};
+ }
+
+ if (base_ <= extent_) {
+ return TextControlSelection(base_.TextOffset(), extent_.TextOffset(),
+ kSelectionHasForwardDirection);
+ } else {
+ return TextControlSelection(extent_.TextOffset(), base_.TextOffset(),
+ kSelectionHasBackwardDirection);
+ }
+}
+
bool operator==(const AXSelection& a, const AXSelection& b) {
DCHECK(a.IsValid() && b.IsValid());
return a.Base() == b.Base() && a.Extent() == b.Extent();
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h
index ca3d8a96f10..24dc03696f4 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h
@@ -10,8 +10,10 @@
#include <ostream>
#include <base/logging.h>
+#include <base/optional.h>
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/modules/accessibility/ax_position.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -45,6 +47,8 @@ class MODULES_EXPORT AXSelection final {
const Document&,
const AXSelectionBehavior = AXSelectionBehavior::kExtendToValidDOMRange);
+ static AXSelection FromCurrentSelection(const TextControlElement&);
+
static AXSelection FromSelection(
const SelectionInDOMTree&,
const AXSelectionBehavior = AXSelectionBehavior::kExtendToValidDOMRange);
@@ -76,8 +80,28 @@ class MODULES_EXPORT AXSelection final {
String ToString() const;
private:
+ // Holds the endpoints of a selection that affects the value of a text
+ // control, i.e. that is inside its shadow tree.
+ struct TextControlSelection final {
+ TextControlSelection(int start,
+ int end,
+ TextFieldSelectionDirection direction)
+ : start(start), end(end), direction(direction) {}
+ TextControlSelection()
+ : start(-1), end(-1), direction(kSelectionHasNoDirection) {}
+
+ int start;
+ int end;
+ TextFieldSelectionDirection direction;
+ };
+
AXSelection();
+ // Determines whether this selection is targeted to the contents of a text
+ // field, and returns the start and end text offsets, as well as its
+ // direction. |start| should always be less than equal to |end|.
+ base::Optional<TextControlSelection> AsTextControlSelection() const;
+
// The |AXPosition| where the selection starts.
AXPosition base_;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc
index 3477e1d4159..c3ad8c92ad5 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc
@@ -11,10 +11,13 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/range.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_position.h"
@@ -432,6 +435,506 @@ TEST_F(AccessibilitySelectionTest, SetSelectionAroundListBullet) {
}
//
+// Tests that involve selection inside, outside, and spanning text controls.
+//
+
+TEST_F(AccessibilitySelectionTest, FromCurrentSelectionInTextField) {
+ GetPage().GetSettings().SetScriptEnabled(true);
+ SetBodyInnerHTML(R"HTML(
+ <input id="input" value="Inside text field.">
+ )HTML");
+
+ ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
+
+ Element* const script_element =
+ GetDocument().CreateRawElement(html_names::kScriptTag);
+ ASSERT_NE(nullptr, script_element);
+ script_element->setTextContent(R"SCRIPT(
+ let input = document.querySelector('input');
+ input.focus();
+ input.selectionStart = 0;
+ input.selectionEnd = input.value.length;
+ )SCRIPT");
+ GetDocument().body()->AppendChild(script_element);
+ UpdateAllLifecyclePhasesForTest();
+
+ const Element* input = GetDocument().QuerySelector("input");
+ ASSERT_NE(nullptr, input);
+ ASSERT_TRUE(IsTextControl(input));
+
+ const AXObject* ax_input = GetAXObjectByElementId("input");
+ ASSERT_NE(nullptr, ax_input);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_input->RoleValue());
+
+ const auto ax_selection =
+ AXSelection::FromCurrentSelection(ToTextControl(*input));
+ ASSERT_TRUE(ax_selection.IsValid());
+
+ EXPECT_TRUE(ax_selection.Base().IsTextPosition());
+ EXPECT_EQ(ax_input, ax_selection.Base().ContainerObject());
+ EXPECT_EQ(0, ax_selection.Base().TextOffset());
+ EXPECT_TRUE(ax_selection.Extent().IsTextPosition());
+ EXPECT_EQ(ax_input, ax_selection.Extent().ContainerObject());
+ EXPECT_EQ(18, ax_selection.Extent().TextOffset());
+}
+
+TEST_F(AccessibilitySelectionTest, FromCurrentSelectionInTextarea) {
+ GetPage().GetSettings().SetScriptEnabled(true);
+ SetBodyInnerHTML(R"HTML(
+ <textarea id="textarea">
+ Inside
+ textarea
+ field.
+ </textarea>
+ )HTML");
+
+ ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
+
+ Element* const script_element =
+ GetDocument().CreateRawElement(html_names::kScriptTag);
+ ASSERT_NE(nullptr, script_element);
+ script_element->setTextContent(R"SCRIPT(
+ let textarea = document.querySelector('textarea');
+ textarea.focus();
+ textarea.selectionStart = 0;
+ textarea.selectionEnd = textarea.textLength;
+ )SCRIPT");
+ GetDocument().body()->AppendChild(script_element);
+ UpdateAllLifecyclePhasesForTest();
+
+ const Element* textarea = GetDocument().QuerySelector("textarea");
+ ASSERT_NE(nullptr, textarea);
+ ASSERT_TRUE(IsTextControl(textarea));
+
+ const AXObject* ax_textarea = GetAXObjectByElementId("textarea");
+ ASSERT_NE(nullptr, ax_textarea);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_textarea->RoleValue());
+
+ const auto ax_selection =
+ AXSelection::FromCurrentSelection(ToTextControl(*textarea));
+ ASSERT_TRUE(ax_selection.IsValid());
+
+ EXPECT_TRUE(ax_selection.Base().IsTextPosition());
+ EXPECT_EQ(ax_textarea, ax_selection.Base().ContainerObject());
+ EXPECT_EQ(0, ax_selection.Base().TextOffset());
+ EXPECT_TRUE(ax_selection.Extent().IsTextPosition());
+ EXPECT_EQ(ax_textarea, ax_selection.Extent().ContainerObject());
+ EXPECT_EQ(53, ax_selection.Extent().TextOffset());
+}
+
+TEST_F(AccessibilitySelectionTest, ClearCurrentSelectionInTextField) {
+ GetPage().GetSettings().SetScriptEnabled(true);
+ SetBodyInnerHTML(R"HTML(
+ <input id="input" value="Inside text field.">
+ )HTML");
+
+ ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
+
+ Element* const script_element =
+ GetDocument().CreateRawElement(html_names::kScriptTag);
+ ASSERT_NE(nullptr, script_element);
+ script_element->setTextContent(R"SCRIPT(
+ let input = document.querySelector('input');
+ input.focus();
+ input.selectionStart = 0;
+ input.selectionEnd = input.textLength;
+ )SCRIPT");
+ GetDocument().body()->AppendChild(script_element);
+ UpdateAllLifecyclePhasesForTest();
+
+ SelectionInDOMTree selection = Selection().GetSelectionInDOMTree();
+ ASSERT_FALSE(selection.IsNone());
+
+ AXSelection::ClearCurrentSelection(GetDocument());
+ selection = Selection().GetSelectionInDOMTree();
+ EXPECT_TRUE(selection.IsNone());
+
+ const auto ax_selection = AXSelection::FromCurrentSelection(GetDocument());
+ EXPECT_FALSE(ax_selection.IsValid());
+ EXPECT_EQ("", GetSelectionText(ax_selection));
+}
+
+TEST_F(AccessibilitySelectionTest, ClearCurrentSelectionInTextarea) {
+ GetPage().GetSettings().SetScriptEnabled(true);
+ SetBodyInnerHTML(R"HTML(
+ <textarea id="textarea">
+ Inside
+ textarea
+ field.
+ </textarea>
+ )HTML");
+
+ ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
+
+ Element* const script_element =
+ GetDocument().CreateRawElement(html_names::kScriptTag);
+ ASSERT_NE(nullptr, script_element);
+ script_element->setTextContent(R"SCRIPT(
+ let textarea = document.querySelector('textarea');
+ textarea.focus();
+ textarea.selectionStart = 0;
+ textarea.selectionEnd = textarea.textLength;
+ )SCRIPT");
+ GetDocument().body()->AppendChild(script_element);
+ UpdateAllLifecyclePhasesForTest();
+
+ SelectionInDOMTree selection = Selection().GetSelectionInDOMTree();
+ ASSERT_FALSE(selection.IsNone());
+
+ AXSelection::ClearCurrentSelection(GetDocument());
+ selection = Selection().GetSelectionInDOMTree();
+ EXPECT_TRUE(selection.IsNone());
+
+ const auto ax_selection = AXSelection::FromCurrentSelection(GetDocument());
+ EXPECT_FALSE(ax_selection.IsValid());
+ EXPECT_EQ("", GetSelectionText(ax_selection));
+}
+
+TEST_F(AccessibilitySelectionTest, ForwardSelectionInTextField) {
+ SetBodyInnerHTML(R"HTML(
+ <input id="input" value="Inside text field.">
+ )HTML");
+
+ Element* const input = GetDocument().QuerySelector("input");
+ ASSERT_NE(nullptr, input);
+ ASSERT_TRUE(IsTextControl(input));
+ input->focus(FocusOptions::Create());
+ ASSERT_TRUE(input->IsFocusedElementInDocument());
+
+ const AXObject* ax_input = GetAXObjectByElementId("input");
+ ASSERT_NE(nullptr, ax_input);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_input->RoleValue());
+
+ // Forward selection.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreateFirstPositionInObject(*ax_input))
+ .SetExtent(AXPosition::CreateLastPositionInObject(*ax_input))
+ .Build();
+
+ EXPECT_TRUE(ax_selection.Select());
+
+ EXPECT_EQ(0u, ToTextControl(*input).selectionStart());
+ EXPECT_EQ(18u, ToTextControl(*input).selectionEnd());
+ EXPECT_EQ("forward", ToTextControl(*input).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, BackwardSelectionInTextField) {
+ SetBodyInnerHTML(R"HTML(
+ <input id="input" value="Inside text field.">
+ )HTML");
+
+ Element* const input = GetDocument().QuerySelector("input");
+ ASSERT_NE(nullptr, input);
+ ASSERT_TRUE(IsTextControl(input));
+ input->focus(FocusOptions::Create());
+ ASSERT_TRUE(input->IsFocusedElementInDocument());
+
+ const AXObject* ax_input = GetAXObjectByElementId("input");
+ ASSERT_NE(nullptr, ax_input);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_input->RoleValue());
+
+ // Backward selection.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionInTextObject(*ax_input, 10))
+ .SetExtent(AXPosition::CreatePositionInTextObject(*ax_input, 3))
+ .Build();
+
+ EXPECT_TRUE(ax_selection.Select());
+
+ EXPECT_EQ(3u, ToTextControl(*input).selectionStart());
+ EXPECT_EQ(10u, ToTextControl(*input).selectionEnd());
+ EXPECT_EQ("backward", ToTextControl(*input).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, SelectingTheWholeOfTheTextField) {
+ SetBodyInnerHTML(R"HTML(
+ <p id="before">Before text field.</p>
+ <input id="input" value="Inside text field.">
+ <p id="after">After text field.</p>
+ )HTML");
+
+ Element* const input = GetDocument().QuerySelector("input");
+ ASSERT_NE(nullptr, input);
+ ASSERT_TRUE(IsTextControl(input));
+ ASSERT_TRUE(ToTextControl(*input).SetSelectionRange(
+ 3u, 10u, kSelectionHasBackwardDirection));
+
+ const AXObject* ax_before = GetAXObjectByElementId("before");
+ ASSERT_NE(nullptr, ax_before);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_before->RoleValue());
+ const AXObject* ax_input = GetAXObjectByElementId("input");
+ ASSERT_NE(nullptr, ax_input);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_input->RoleValue());
+
+ // Light tree only selection. Selects the whole of the text field.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionBeforeObject(*ax_before))
+ .SetExtent(AXPosition::CreatePositionAfterObject(*ax_input))
+ .Build();
+
+ EXPECT_TRUE(ax_selection.Select());
+
+ const SelectionInDOMTree dom_selection = Selection().GetSelectionInDOMTree();
+ EXPECT_EQ(GetDocument().body(), dom_selection.Base().AnchorNode());
+ EXPECT_EQ(1, dom_selection.Base().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("before"),
+ dom_selection.Base().ComputeNodeAfterPosition());
+ EXPECT_EQ(GetDocument().body(), dom_selection.Extent().AnchorNode());
+ EXPECT_EQ(5, dom_selection.Extent().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("after"),
+ dom_selection.Extent().ComputeNodeAfterPosition());
+
+ // The selection in the text field should remain unchanged because the field
+ // is not focused.
+ EXPECT_EQ(3u, ToTextControl(*input).selectionStart());
+ EXPECT_EQ(10u, ToTextControl(*input).selectionEnd());
+ EXPECT_EQ("backward", ToTextControl(*input).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, InvalidSelectionInTextField) {
+ SetBodyInnerHTML(R"HTML(
+ <p id="before">Before text field.</p>
+ <input id="input" value="Inside text field.">
+ <p id="after">After text field.</p>
+ )HTML");
+
+ Element* const input = GetDocument().QuerySelector("input");
+ ASSERT_NE(nullptr, input);
+ ASSERT_TRUE(IsTextControl(input));
+ ASSERT_TRUE(ToTextControl(*input).SetSelectionRange(
+ 3u, 10u, kSelectionHasBackwardDirection));
+
+ const AXObject* ax_before = GetAXObjectByElementId("before");
+ ASSERT_NE(nullptr, ax_before);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_before->RoleValue());
+ const AXObject* ax_input = GetAXObjectByElementId("input");
+ ASSERT_NE(nullptr, ax_input);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_input->RoleValue());
+ const AXObject* ax_after = GetAXObjectByElementId("after");
+ ASSERT_NE(nullptr, ax_after);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue());
+
+ {
+ // Light tree only selection. Selects the whole of the text field.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionBeforeObject(*ax_before))
+ .SetExtent(AXPosition::CreatePositionAfterObject(*ax_input))
+ .Build();
+ ax_selection.Select();
+ }
+
+ // Invalid selection because it crosses a user agent shadow tree boundary.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionInTextObject(*ax_input, 0))
+ .SetExtent(AXPosition::CreatePositionBeforeObject(*ax_after))
+ .Build();
+
+ EXPECT_FALSE(ax_selection.IsValid());
+
+ // The selection in the light DOM should remain unchanged.
+ const SelectionInDOMTree dom_selection = Selection().GetSelectionInDOMTree();
+ EXPECT_EQ(GetDocument().body(), dom_selection.Base().AnchorNode());
+ EXPECT_EQ(1, dom_selection.Base().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("before"),
+ dom_selection.Base().ComputeNodeAfterPosition());
+ EXPECT_EQ(GetDocument().body(), dom_selection.Extent().AnchorNode());
+ EXPECT_EQ(5, dom_selection.Extent().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("after"),
+ dom_selection.Extent().ComputeNodeAfterPosition());
+
+ // The selection in the text field should remain unchanged because the field
+ // is not focused.
+ EXPECT_EQ(3u, ToTextControl(*input).selectionStart());
+ EXPECT_EQ(10u, ToTextControl(*input).selectionEnd());
+ EXPECT_EQ("backward", ToTextControl(*input).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, ForwardSelectionInTextarea) {
+ SetBodyInnerHTML(R"HTML(
+ <textarea id="textarea">
+ Inside
+ textarea
+ field.
+ </textarea>
+ )HTML");
+
+ Element* const textarea = GetDocument().QuerySelector("textarea");
+ ASSERT_NE(nullptr, textarea);
+ ASSERT_TRUE(IsTextControl(textarea));
+ textarea->focus(FocusOptions::Create());
+ ASSERT_TRUE(textarea->IsFocusedElementInDocument());
+
+ const AXObject* ax_textarea = GetAXObjectByElementId("textarea");
+ ASSERT_NE(nullptr, ax_textarea);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_textarea->RoleValue());
+
+ // Forward selection.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreateFirstPositionInObject(*ax_textarea))
+ .SetExtent(AXPosition::CreateLastPositionInObject(*ax_textarea))
+ .Build();
+
+ EXPECT_TRUE(ax_selection.Select());
+
+ EXPECT_EQ(0u, ToTextControl(*textarea).selectionStart());
+ EXPECT_EQ(53u, ToTextControl(*textarea).selectionEnd());
+ EXPECT_EQ("forward", ToTextControl(*textarea).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, BackwardSelectionInTextarea) {
+ SetBodyInnerHTML(R"HTML(
+ <textarea id="textarea">
+ Inside
+ textarea
+ field.
+ </textarea>
+ )HTML");
+
+ Element* const textarea = GetDocument().QuerySelector("textarea");
+ ASSERT_NE(nullptr, textarea);
+ ASSERT_TRUE(IsTextControl(textarea));
+ textarea->focus(FocusOptions::Create());
+ ASSERT_TRUE(textarea->IsFocusedElementInDocument());
+
+ const AXObject* ax_textarea = GetAXObjectByElementId("textarea");
+ ASSERT_NE(nullptr, ax_textarea);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_textarea->RoleValue());
+
+ // Backward selection.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionInTextObject(*ax_textarea, 10))
+ .SetExtent(AXPosition::CreatePositionInTextObject(*ax_textarea, 3))
+ .Build();
+
+ EXPECT_TRUE(ax_selection.Select());
+
+ EXPECT_EQ(3u, ToTextControl(*textarea).selectionStart());
+ EXPECT_EQ(10u, ToTextControl(*textarea).selectionEnd());
+ EXPECT_EQ("backward", ToTextControl(*textarea).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, SelectTheWholeOfTheTextarea) {
+ SetBodyInnerHTML(R"HTML(
+ <p id="before">Before textarea field.</p>
+ <textarea id="textarea">
+ Inside
+ textarea
+ field.
+ </textarea>
+ <p id="after">After textarea field.</p>
+ )HTML");
+
+ Element* const textarea = GetDocument().QuerySelector("textarea");
+ ASSERT_NE(nullptr, textarea);
+ ASSERT_TRUE(IsTextControl(textarea));
+ ASSERT_TRUE(ToTextControl(*textarea).SetSelectionRange(
+ 3u, 10u, kSelectionHasBackwardDirection));
+
+ const AXObject* ax_before = GetAXObjectByElementId("before");
+ ASSERT_NE(nullptr, ax_before);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_before->RoleValue());
+ const AXObject* ax_textarea = GetAXObjectByElementId("textarea");
+ ASSERT_NE(nullptr, ax_textarea);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_textarea->RoleValue());
+
+ // Light tree only selection. Selects the whole of the textarea field.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionBeforeObject(*ax_before))
+ .SetExtent(AXPosition::CreatePositionAfterObject(*ax_textarea))
+ .Build();
+
+ EXPECT_TRUE(ax_selection.Select());
+
+ const SelectionInDOMTree dom_selection = Selection().GetSelectionInDOMTree();
+ EXPECT_EQ(GetDocument().body(), dom_selection.Base().AnchorNode());
+ EXPECT_EQ(1, dom_selection.Base().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("before"),
+ dom_selection.Base().ComputeNodeAfterPosition());
+ EXPECT_EQ(GetDocument().body(), dom_selection.Extent().AnchorNode());
+ EXPECT_EQ(5, dom_selection.Extent().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("after"),
+ dom_selection.Extent().ComputeNodeAfterPosition());
+
+ // The selection in the textarea field should remain unchanged because the
+ // field is not focused.
+ EXPECT_EQ(3u, ToTextControl(*textarea).selectionStart());
+ EXPECT_EQ(10u, ToTextControl(*textarea).selectionEnd());
+ EXPECT_EQ("backward", ToTextControl(*textarea).selectionDirection());
+}
+
+TEST_F(AccessibilitySelectionTest, InvalidSelectionInTextarea) {
+ SetBodyInnerHTML(R"HTML(
+ <p id="before">Before textarea field.</p>
+ <textarea id="textarea">
+ Inside
+ textarea
+ field.
+ </textarea>
+ <p id="after">After textarea field.</p>
+ )HTML");
+
+ Element* const textarea = GetDocument().QuerySelector("textarea");
+ ASSERT_NE(nullptr, textarea);
+ ASSERT_TRUE(IsTextControl(textarea));
+ ASSERT_TRUE(ToTextControl(*textarea).SetSelectionRange(
+ 3u, 10u, kSelectionHasBackwardDirection));
+
+ const AXObject* ax_before = GetAXObjectByElementId("before");
+ ASSERT_NE(nullptr, ax_before);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_before->RoleValue());
+ const AXObject* ax_textarea = GetAXObjectByElementId("textarea");
+ ASSERT_NE(nullptr, ax_textarea);
+ ASSERT_EQ(ax::mojom::Role::kTextField, ax_textarea->RoleValue());
+ const AXObject* ax_after = GetAXObjectByElementId("after");
+ ASSERT_NE(nullptr, ax_after);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue());
+
+ {
+ // Light tree only selection. Selects the whole of the textarea field.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionBeforeObject(*ax_before))
+ .SetExtent(AXPosition::CreatePositionAfterObject(*ax_textarea))
+ .Build();
+ ax_selection.Select();
+ }
+
+ // Invalid selection because it crosses a user agent shadow tree boundary.
+ AXSelection::Builder builder;
+ AXSelection ax_selection =
+ builder.SetBase(AXPosition::CreatePositionInTextObject(*ax_textarea, 0))
+ .SetExtent(AXPosition::CreatePositionBeforeObject(*ax_after))
+ .Build();
+
+ EXPECT_FALSE(ax_selection.IsValid());
+
+ // The selection in the light DOM should remain unchanged.
+ const SelectionInDOMTree dom_selection = Selection().GetSelectionInDOMTree();
+ EXPECT_EQ(GetDocument().body(), dom_selection.Base().AnchorNode());
+ EXPECT_EQ(1, dom_selection.Base().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("before"),
+ dom_selection.Base().ComputeNodeAfterPosition());
+ EXPECT_EQ(GetDocument().body(), dom_selection.Extent().AnchorNode());
+ EXPECT_EQ(5, dom_selection.Extent().OffsetInContainerNode());
+ EXPECT_EQ(GetElementById("after"),
+ dom_selection.Extent().ComputeNodeAfterPosition());
+
+ // The selection in the textarea field should remain unchanged because the
+ // field is not focused.
+ EXPECT_EQ(3u, ToTextControl(*textarea).selectionStart());
+ EXPECT_EQ(10u, ToTextControl(*textarea).selectionEnd());
+ EXPECT_EQ("backward", ToTextControl(*textarea).selectionDirection());
+}
+
+//
// Declarative tests.
//
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
new file mode 100644
index 00000000000..7e391f32004
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
@@ -0,0 +1,134 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/accessibility/ax_validation_message.h"
+
+#include "SkMatrix44.h"
+#include "third_party/blink/renderer/core/html/forms/listed_element.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
+
+namespace blink {
+
+AXValidationMessage::AXValidationMessage(AXObjectCacheImpl& ax_object_cache)
+ : AXMockObject(ax_object_cache) {}
+
+AXValidationMessage::~AXValidationMessage() {}
+
+AXObject* AXValidationMessage::ComputeParent() const {
+ return AXObjectCache().Root();
+}
+
+bool AXValidationMessage::ComputeAccessibilityIsIgnored(
+ IgnoredReasons* ignored_reasons) const {
+ return false;
+}
+
+// TODO(accessibility) Currently we return the bounds of the focused form
+// control. If this becomes an issue, return the bounds of the alert itself.
+void AXValidationMessage::GetRelativeBounds(AXObject** out_container,
+ FloatRect& out_bounds_in_container,
+ SkMatrix44& out_container_transform,
+ bool* clips_children) const {
+ DCHECK(out_container);
+ *out_container = nullptr;
+ out_bounds_in_container = FloatRect();
+ out_container_transform.setIdentity();
+ if (clips_children)
+ *clips_children = false;
+
+ ListedElement* listed_element = RelatedFormControlIfVisible();
+ if (!listed_element)
+ return;
+
+ HTMLElement* form_control = ToHTMLElement(listed_element);
+ if (!form_control || !form_control->GetLayoutObject())
+ return;
+
+ *out_container = ParentObject();
+
+ if (form_control->GetLayoutObject()) {
+ out_bounds_in_container =
+ FloatRect(form_control->GetLayoutObject()->AbsoluteBoundingBoxRect());
+ }
+}
+
+bool AXValidationMessage::IsOffScreen() const {
+ return false;
+}
+
+bool AXValidationMessage::IsVisible() const {
+ return RelatedFormControlIfVisible();
+}
+
+const AtomicString& AXValidationMessage::LiveRegionStatus() const {
+ DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_assertive,
+ ("assertive"));
+ return live_region_status_assertive;
+}
+
+const AtomicString& AXValidationMessage::LiveRegionRelevant() const {
+ DEFINE_STATIC_LOCAL(const AtomicString, live_region_relevant_additions,
+ ("additions"));
+ return live_region_relevant_additions;
+}
+
+ax::mojom::Role AXValidationMessage::RoleValue() const {
+ return ax::mojom::Role::kAlert;
+}
+
+ListedElement* AXValidationMessage::RelatedFormControlIfVisible() const {
+ AXObject* focused_object = AXObjectCache().FocusedObject();
+ if (!focused_object)
+ return nullptr;
+
+ Element* element = focused_object->GetElement();
+ if (!element)
+ return nullptr;
+
+ ListedElement* form_control = ListedElement::From(*element);
+ if (!form_control || !form_control->IsValidationMessageVisible())
+ return nullptr;
+
+ // The method IsValidationMessageVisible() is a superset of
+ // IsNotCandidateOrValid(), but has the benefit of not being true until user
+ // has tried to submit data. Waiting until the error message is visible
+ // before presenting to screen reader is preferable over hearing about the
+ // error while the user is still attempting to input data in the first place.
+ return form_control->IsValidationMessageVisible() ? form_control : nullptr;
+}
+
+String AXValidationMessage::TextAlternative(
+ bool recursive,
+ bool in_aria_labelled_by_traversal,
+ AXObjectSet& visited,
+ ax::mojom::NameFrom& name_from,
+ AXRelatedObjectVector* related_objects,
+ NameSources* name_sources) const {
+ // If nameSources is non-null, relatedObjects is used in filling it in, so it
+ // must be non-null as well.
+ if (name_sources)
+ DCHECK(related_objects);
+
+ ListedElement* form_control_element = RelatedFormControlIfVisible();
+ if (!form_control_element)
+ return String();
+
+ String message = form_control_element->validationMessage();
+ if (form_control_element->ValidationSubMessage()) {
+ message.append(' ');
+ message.append(form_control_element->ValidationSubMessage());
+ }
+
+ if (name_sources) {
+ name_sources->push_back(NameSource(true));
+ name_sources->back().type = ax::mojom::NameFrom::kContents;
+ name_sources->back().text = message;
+ }
+
+ return message;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
new file mode 100644
index 00000000000..55fc5ed7c08
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
@@ -0,0 +1,60 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_VALIDATION_MESSAGE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_VALIDATION_MESSAGE_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_mock_object.h"
+
+namespace blink {
+
+class AXObjectCacheImpl;
+class ListedElement;
+
+// The AXValidationMessage is a mock object that exposes an alert for a native
+// error message popup for an invalid HTML control, aka a validation message.
+// The alert is exposed with a name containing the text of the popup..
+
+class AXValidationMessage final : public AXMockObject {
+ public:
+ static AXValidationMessage* Create(AXObjectCacheImpl& ax_object_cache) {
+ return MakeGarbageCollected<AXValidationMessage>(ax_object_cache);
+ }
+
+ explicit AXValidationMessage(AXObjectCacheImpl&);
+ ~AXValidationMessage() override;
+
+ private:
+ // AXObject:
+ bool CanHaveChildren() const override { return false; }
+ bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
+ AXObject* ComputeParent() const override;
+ void GetRelativeBounds(AXObject** out_container,
+ FloatRect& out_bounds_in_container,
+ SkMatrix44& out_container_transform,
+ bool* clips_children) const override;
+ const AtomicString& LiveRegionStatus() const override;
+ const AtomicString& LiveRegionRelevant() const override;
+ bool IsOffScreen() const override;
+ bool IsValidationMessage() const override { return true; }
+ bool IsVisible() const override;
+ String TextAlternative(bool recursive,
+ bool in_aria_labelled_by_traversal,
+ AXObjectSet& visited,
+ ax::mojom::NameFrom&,
+ AXRelatedObjectVector*,
+ NameSources*) const override;
+ ax::mojom::Role RoleValue() const override;
+
+ ListedElement* RelatedFormControlIfVisible() const;
+
+ DISALLOW_COPY_AND_ASSIGN(AXValidationMessage);
+};
+
+DEFINE_AX_OBJECT_TYPE_CASTS(AXValidationMessage, IsValidationMessage());
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_VALIDATION_MESSAGE_H_
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
index eedef03b104..b33fcefd2c3 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
@@ -96,7 +96,7 @@ void FillLiveRegionProperties(AXObject& ax_object,
CreateValue(ax_object.ContainerLiveRegionRelevant(),
AXValueTypeEnum::TokenList)));
- if (!ax_object.IsLiveRegion()) {
+ if (!ax_object.IsLiveRegionRoot()) {
properties.addItem(CreateProperty(
AXPropertyNameEnum::Root,
CreateRelatedNodeListValue(*(ax_object.LiveRegionRoot()))));
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.cc
index 09fab64048f..088088fa299 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -29,6 +30,10 @@ AXObjectCacheImpl& AccessibilityTest::GetAXObjectCache() const {
return *ax_object_cache;
}
+AXObject* AccessibilityTest::GetAXObject(const Node& node) const {
+ return GetAXObjectCache().GetOrCreate(&node);
+}
+
AXObject* AccessibilityTest::GetAXRootObject() const {
return GetAXObjectCache().GetOrCreate(&GetLayoutView());
}
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h b/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h
index 6e9186776d7..bd126b23e8f 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h
@@ -18,6 +18,7 @@ namespace blink {
class AXObject;
class AXObjectCacheImpl;
class LocalFrameClient;
+class Node;
namespace test {
@@ -32,6 +33,8 @@ class AccessibilityTest : public RenderingTest {
AXObjectCacheImpl& GetAXObjectCache() const;
+ AXObject* GetAXObject(const Node& node) const;
+
AXObject* GetAXRootObject() const;
// Returns the object with the accessibility focus.
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/README.md b/chromium/third_party/blink/renderer/modules/animationworklet/README.md
index b9078bcfff7..ea938515877 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/README.md
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/README.md
@@ -74,7 +74,7 @@ updates from compositor (this is not yet in place).
## Testing
-Layout tests that cover web-exposed API for Animation Worklet are tested in
+Web tests that cover web-exposed API for Animation Worklet are tested in
[`web_tests/virtual/threaded/fast/animationworklet/`](../../../web_tests/virtual/threaded/fast/animationworklet/).
There are unit tests covering animation worklet and global scope in [`modules/animationworklet`](.).
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
index d6e0a464357..3753be8275b 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
@@ -23,7 +23,7 @@ int NextId() {
namespace blink {
AnimationWorklet::AnimationWorklet(Document* document)
- : Worklet(document), scope_id_(NextId()), last_animation_id_(0) {}
+ : Worklet(document), worklet_id_(NextId()), last_animation_id_(0) {}
AnimationWorklet::~AnimationWorklet() = default;
@@ -38,13 +38,14 @@ WorkletGlobalScopeProxy* AnimationWorklet::CreateGlobalScope() {
Document* document = To<Document>(GetExecutionContext());
AnimationWorkletProxyClient* proxy_client =
- AnimationWorkletProxyClient::FromDocument(document, scope_id_);
+ AnimationWorkletProxyClient::FromDocument(document, worklet_id_);
WorkerClients* worker_clients = WorkerClients::Create();
ProvideAnimationWorkletProxyClientTo(worker_clients, proxy_client);
AnimationWorkletMessagingProxy* proxy =
- new AnimationWorkletMessagingProxy(GetExecutionContext());
+ MakeGarbageCollected<AnimationWorkletMessagingProxy>(
+ GetExecutionContext());
proxy->Initialize(worker_clients, ModuleResponsesMap());
return proxy;
}
@@ -52,7 +53,7 @@ WorkletGlobalScopeProxy* AnimationWorklet::CreateGlobalScope() {
WorkletAnimationId AnimationWorklet::NextWorkletAnimationId() {
// Id starts from 1. This way it safe to use it as key in hashmap with default
// key traits.
- return {.scope_id = scope_id_, .animation_id = ++last_animation_id_};
+ return {.worklet_id = worklet_id_, .animation_id = ++last_animation_id_};
}
void AnimationWorklet::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h
index 5cd1e179f90..aa4abd118a6 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h
@@ -32,7 +32,7 @@ class MODULES_EXPORT AnimationWorklet final : public Worklet {
private:
// Unique id associated with this worklet that is used by cc to identify all
// animations associated it.
- int scope_id_;
+ int worklet_id_;
int last_animation_id_;
// Implements Worklet.
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
index b20356e4a65..9865edadd3a 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
@@ -39,7 +39,8 @@ void UpdateAnimation(Animator* animator,
AnimationWorkletGlobalScope* AnimationWorkletGlobalScope::Create(
std::unique_ptr<GlobalScopeCreationParams> creation_params,
WorkerThread* thread) {
- return new AnimationWorkletGlobalScope(std::move(creation_params), thread);
+ return MakeGarbageCollected<AnimationWorkletGlobalScope>(
+ std::move(creation_params), thread);
}
AnimationWorkletGlobalScope::AnimationWorkletGlobalScope(
@@ -191,9 +192,16 @@ void AnimationWorkletGlobalScope::registerAnimator(
return;
AnimatorDefinition* definition =
- new AnimatorDefinition(isolate, constructor, animate);
+ MakeGarbageCollected<AnimatorDefinition>(isolate, constructor, animate);
animator_definitions_.Set(name, definition);
+ // TODO(yigu): Currently one animator name is synced back per registration.
+ // Eventually all registered names should be synced in batch once a module
+ // completes its loading in the worklet scope. https://crbug.com/920722.
+ if (AnimationWorkletProxyClient* proxy_client =
+ AnimationWorkletProxyClient::From(Clients())) {
+ proxy_client->SynchronizeAnimatorName(name);
+ }
}
Animator* AnimationWorkletGlobalScope::CreateInstance(
@@ -220,7 +228,8 @@ Animator* AnimationWorkletGlobalScope::CreateInstance(
.ToLocal(&instance))
return nullptr;
- return new Animator(isolate, definition, instance, num_effects);
+ return MakeGarbageCollected<Animator>(isolate, definition, instance,
+ num_effects);
}
AnimatorDefinition* AnimationWorkletGlobalScope::FindDefinitionForTest(
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
index 395ce9a9888..90c7d001ef6 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
@@ -35,7 +35,11 @@ class MODULES_EXPORT AnimationWorkletGlobalScope : public WorkletGlobalScope {
static AnimationWorkletGlobalScope* Create(
std::unique_ptr<GlobalScopeCreationParams>,
WorkerThread*);
+
+ AnimationWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
+ WorkerThread*);
~AnimationWorkletGlobalScope() override;
+
void Trace(blink::Visitor*) override;
void Dispose() override;
bool IsAnimationWorkletGlobalScope() const final { return true; }
@@ -52,9 +56,6 @@ class MODULES_EXPORT AnimationWorkletGlobalScope : public WorkletGlobalScope {
unsigned GetAnimatorsSizeForTest() { return animators_.size(); }
private:
- AnimationWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
- WorkerThread*);
-
void RegisterWithProxyClientIfNeeded();
Animator* CreateInstance(const String& name,
WorkletAnimationOptions* options,
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
index b168b93001b..718d367b90a 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
@@ -44,6 +44,7 @@ class MockAnimationWorkletProxyClient : public AnimationWorkletProxyClient {
void SetGlobalScope(WorkletGlobalScope*) override {
did_set_global_scope_ = true;
}
+ void SynchronizeAnimatorName(const String&) override{};
bool did_set_global_scope() { return did_set_global_scope_; }
private:
@@ -78,14 +79,16 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
Document* document = &GetDocument();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
- document->GetReferrerPolicy(), document->GetSecurityOrigin(),
- document->IsSecureContext(), document->GetHttpsState(), clients,
- document->AddressSpace(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled,
+ document->UserAgent(), nullptr /* web_worker_fetch_context */,
+ Vector<CSPHeaderAndType>(), document->GetReferrerPolicy(),
+ document->GetSecurityOrigin(), document->IsSecureContext(),
+ document->GetHttpsState(), clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap),
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>()),
base::nullopt, std::make_unique<WorkerDevToolsParams>(),
ParentExecutionContextTaskRunners::Create());
return thread;
@@ -439,7 +442,7 @@ TEST_F(AnimationWorkletGlobalScopeTest, AnimatorInstanceUpdate) {
TEST_F(AnimationWorkletGlobalScopeTest,
ShouldRegisterItselfAfterFirstAnimatorRegistration) {
MockAnimationWorkletProxyClient* proxy_client =
- new MockAnimationWorkletProxyClient();
+ MakeGarbageCollected<MockAnimationWorkletProxyClient>();
std::unique_ptr<WorkerThread> worklet =
CreateAnimationAndPaintWorkletThread(proxy_client);
// Animation worklet global scope (AWGS) should not register itself upon
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc
index 2c9082e2901..ed1c349320d 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc
@@ -18,14 +18,14 @@ const char AnimationWorkletProxyClient::kSupplementName[] =
"AnimationWorkletProxyClient";
AnimationWorkletProxyClient::AnimationWorkletProxyClient(
- int scope_id,
+ int worklet_id,
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
compositor_mutator_dispatcher,
scoped_refptr<base::SingleThreadTaskRunner> compositor_mutator_runner,
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
main_thread_mutator_dispatcher,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_mutator_runner)
- : scope_id_(scope_id), state_(RunState::kUninitialized) {
+ : worklet_id_(worklet_id), state_(RunState::kUninitialized) {
DCHECK(IsMainThread());
mutator_items_.emplace_back(std::move(compositor_mutator_dispatcher),
std::move(compositor_mutator_runner));
@@ -38,6 +38,27 @@ void AnimationWorkletProxyClient::Trace(blink::Visitor* visitor) {
AnimationWorkletMutator::Trace(visitor);
}
+void AnimationWorkletProxyClient::SynchronizeAnimatorName(
+ const String& animator_name) {
+ if (state_ == RunState::kDisposed)
+ return;
+
+ // Animator registration is processed before the loading promise being
+ // resolved which is also done with a posted task (See
+ // WorkletModuleTreeClient::NotifyModuleTreeLoadFinished). Since both are
+ // posted task and a SequencedTaskRunner is used, we are guaranteed that
+ // registered names are synced before resolving the load promise therefore it
+ // is safe to use a post task here.
+ for (auto& mutator_item : mutator_items_) {
+ DCHECK(mutator_item.mutator_runner);
+ PostCrossThreadTask(
+ *mutator_item.mutator_runner, FROM_HERE,
+ CrossThreadBind(
+ &AnimationWorkletMutatorDispatcherImpl::SynchronizeAnimatorName,
+ mutator_item.mutator_dispatcher, animator_name));
+ }
+}
+
void AnimationWorkletProxyClient::SetGlobalScope(
WorkletGlobalScope* global_scope) {
DCHECK(global_scope);
@@ -95,9 +116,9 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletProxyClient::Mutate(
std::unique_ptr<AnimationWorkletInput> input) {
DCHECK(input);
#if DCHECK_IS_ON()
- DCHECK(input->ValidateScope(scope_id_))
+ DCHECK(input->ValidateId(worklet_id_))
<< "Input has state that does not belong to this global scope: "
- << scope_id_;
+ << worklet_id_;
#endif
if (!global_scope_)
@@ -113,7 +134,7 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletProxyClient::Mutate(
// static
AnimationWorkletProxyClient* AnimationWorkletProxyClient::FromDocument(
Document* document,
- int scope_id) {
+ int worklet_id) {
WebLocalFrameImpl* local_frame =
WebLocalFrameImpl::FromFrame(document->GetFrame());
@@ -129,8 +150,8 @@ AnimationWorkletProxyClient* AnimationWorkletProxyClient::FromDocument(
document->GetWorkletAnimationController()
.EnsureMainThreadMutatorDispatcher(&main_thread_host_queue);
- return new AnimationWorkletProxyClient(
- scope_id, std::move(compositor_mutator_dispatcher),
+ return MakeGarbageCollected<AnimationWorkletProxyClient>(
+ worklet_id, std::move(compositor_mutator_dispatcher),
std::move(compositor_host_queue),
std::move(main_thread_mutator_dispatcher),
std::move(main_thread_host_queue));
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h
index 6de77a34940..193707f06d0 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h
@@ -38,27 +38,28 @@ class MODULES_EXPORT AnimationWorkletProxyClient
// This client is hooked to the given |mutatee|, on the given
// |mutatee_runner|.
explicit AnimationWorkletProxyClient(
- int scope_id,
+ int worklet_id,
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> compositor_mutatee,
scoped_refptr<base::SingleThreadTaskRunner> compositor_mutatee_runner,
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> main_thread_mutatee,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_mutatee_runner);
void Trace(blink::Visitor*) override;
+ virtual void SynchronizeAnimatorName(const String& animator_name);
virtual void SetGlobalScope(WorkletGlobalScope*);
void Dispose();
// AnimationWorkletMutator:
// These methods are invoked on the animation worklet thread.
- int GetScopeId() const override { return scope_id_; }
+ int GetWorkletId() const override { return worklet_id_; }
std::unique_ptr<AnimationWorkletOutput> Mutate(
std::unique_ptr<AnimationWorkletInput> input) override;
- static AnimationWorkletProxyClient* FromDocument(Document*, int scope_id);
+ static AnimationWorkletProxyClient* FromDocument(Document*, int worklet_id);
static AnimationWorkletProxyClient* From(WorkerClients*);
private:
- const int scope_id_;
+ const int worklet_id_;
struct MutatorItem {
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher;
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc
index a8c3fe6100d..10a8d057992 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/animationworklet/animator.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/animationworklet/animator_definition.h"
@@ -19,7 +20,8 @@ Animator::Animator(v8::Isolate* isolate,
int num_effects)
: definition_(definition),
instance_(isolate, instance),
- group_effect_(new WorkletGroupEffectProxy(num_effects)) {
+ group_effect_(
+ MakeGarbageCollected<WorkletGroupEffectProxy>(num_effects)) {
DCHECK_GE(num_effects, 1);
}
@@ -64,7 +66,7 @@ bool Animator::Animate(
v8::Local<v8::Value> argv[] = {v8_current_time, v8_effect};
V8ScriptRunner::CallFunction(animate, ExecutionContext::From(script_state),
- instance, arraysize(argv), argv, isolate);
+ instance, base::size(argv), argv, isolate);
// The animate function may have produced an error!
// TODO(majidvp): We should probably just throw here.
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animator_definition.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animator_definition.cc
index 8df2f128721..50d04af893a 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animator_definition.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animator_definition.cc
@@ -20,8 +20,8 @@ AnimatorDefinition::AnimatorDefinition(v8::Isolate* isolate,
AnimatorDefinition::~AnimatorDefinition() = default;
void AnimatorDefinition::Trace(Visitor* visitor) {
- visitor->Trace(constructor_.Cast<v8::Value>());
- visitor->Trace(animate_.Cast<v8::Value>());
+ visitor->Trace(constructor_);
+ visitor->Trace(animate_);
}
v8::Local<v8::Function> AnimatorDefinition::ConstructorLocal(
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/css_animation_worklet.cc b/chromium/third_party/blink/renderer/modules/animationworklet/css_animation_worklet.cc
index 21c490310a4..c86f7630566 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/css_animation_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/css_animation_worklet.cc
@@ -54,7 +54,7 @@ CSSAnimationWorklet& CSSAnimationWorklet::From(LocalDOMWindow& window) {
CSSAnimationWorklet::CSSAnimationWorklet(Document* document)
: ContextLifecycleObserver(document),
- animation_worklet_(new AnimationWorklet(document)) {
+ animation_worklet_(MakeGarbageCollected<AnimationWorklet>(document)) {
DCHECK(GetExecutionContext());
}
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index 1cb3c988cef..966439c6dda 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/animation/element_animations.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
+#include "third_party/blink/renderer/core/animation/scroll_timeline_util.h"
#include "third_party/blink/renderer/core/animation/timing.h"
#include "third_party/blink/renderer/core/animation/worklet_animation_controller.h"
#include "third_party/blink/renderer/core/dom/node.h"
@@ -121,120 +122,6 @@ bool CheckElementComposited(const Node& target) {
kPaintsIntoOwnBacking;
}
-base::Optional<CompositorElementId> GetCompositorScrollElementId(
- const Node& node) {
- if (!node.GetLayoutObject() || !node.GetLayoutObject()->UniqueId())
- return base::nullopt;
- return CompositorElementIdFromUniqueObjectId(
- node.GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kScroll);
-}
-
-// Convert the blink concept of a ScrollTimeline orientation into the cc one.
-//
-// The compositor does not know about writing modes, so we have to convert the
-// web concepts of 'block' and 'inline' direction into absolute vertical or
-// horizontal directions.
-//
-// This implements a subset of the conversions documented in
-// https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical
-//
-// TODO(smcgruer): If the writing mode of a scroller changes, we have to update
-// any related cc::ScrollTimeline somehow.
-CompositorScrollTimeline::ScrollDirection ConvertOrientation(
- ScrollTimeline::ScrollDirection orientation,
- const ComputedStyle* style) {
- // Easy cases; physical is always physical.
- if (orientation == ScrollTimeline::Horizontal)
- return CompositorScrollTimeline::ScrollRight;
- if (orientation == ScrollTimeline::Vertical)
- return CompositorScrollTimeline::ScrollDown;
-
- // Harder cases; first work out which axis is which, and then for each check
- // which edge we start at.
-
- // writing-mode: horizontal-tb
- bool is_horizontal_writing_mode =
- style ? style->IsHorizontalWritingMode() : true;
- // writing-mode: vertical-lr
- bool is_flipped_lines_writing_mode =
- style ? style->IsFlippedLinesWritingMode() : false;
- // direction: ltr;
- bool is_ltr_direction = style ? style->IsLeftToRightDirection() : true;
-
- if (orientation == ScrollTimeline::Block) {
- if (is_horizontal_writing_mode) {
- // For horizontal writing mode, block is vertical. The starting edge is
- // always the top.
- return CompositorScrollTimeline::ScrollDown;
- }
- // For vertical writing mode, the block axis is horizontal. The starting
- // edge depends on if we are lr or rl.
- return is_flipped_lines_writing_mode ? CompositorScrollTimeline::ScrollRight
- : CompositorScrollTimeline::ScrollLeft;
- }
-
- DCHECK_EQ(orientation, ScrollTimeline::Inline);
- if (is_horizontal_writing_mode) {
- // For horizontal writing mode, inline is horizontal. The starting edge
- // depends on the directionality.
- return is_ltr_direction ? CompositorScrollTimeline::ScrollRight
- : CompositorScrollTimeline::ScrollLeft;
- }
- // For vertical writing mode, inline is vertical. The starting edge still
- // depends on the directionality; whether it is vertical-lr or vertical-rl
- // does not matter.
- return is_ltr_direction ? CompositorScrollTimeline::ScrollDown
- : CompositorScrollTimeline::ScrollUp;
-}
-
-// Converts a blink::ScrollTimeline into a cc::ScrollTimeline.
-//
-// If the timeline cannot be converted, returns nullptr.
-std::unique_ptr<CompositorScrollTimeline> ToCompositorScrollTimeline(
- AnimationTimeline* timeline) {
- if (!timeline || timeline->IsDocumentTimeline())
- return nullptr;
-
- ScrollTimeline* scroll_timeline = ToScrollTimeline(timeline);
- Node* scroll_source = scroll_timeline->ResolvedScrollSource();
- base::Optional<CompositorElementId> element_id =
- GetCompositorScrollElementId(*scroll_source);
-
- DoubleOrScrollTimelineAutoKeyword time_range;
- scroll_timeline->timeRange(time_range);
- // TODO(smcgruer): Handle 'auto' time range value.
- DCHECK(time_range.IsDouble());
-
- // TODO(smcgruer): If the scroll source later gets a LayoutBox (e.g. was
- // display:none and now isn't), we need to update the compositor to have the
- // correct orientation and start/end offset information.
- LayoutBox* box = scroll_source->GetLayoutBox();
-
- CompositorScrollTimeline::ScrollDirection orientation = ConvertOrientation(
- scroll_timeline->GetOrientation(), box ? box->Style() : nullptr);
-
- base::Optional<double> start_scroll_offset;
- base::Optional<double> end_scroll_offset;
- if (box) {
- double current_offset;
- double max_offset;
- scroll_timeline->GetCurrentAndMaxOffset(box, current_offset, max_offset);
-
- double resolved_start_scroll_offset = 0;
- double resolved_end_scroll_offset = max_offset;
- scroll_timeline->ResolveScrollStartAndEnd(box, max_offset,
- resolved_start_scroll_offset,
- resolved_end_scroll_offset);
- start_scroll_offset = resolved_start_scroll_offset;
- end_scroll_offset = resolved_end_scroll_offset;
- }
-
- return std::make_unique<CompositorScrollTimeline>(
- element_id, orientation, start_scroll_offset, end_scroll_offset,
- time_range.GetAsDouble());
-}
-
void StartEffectOnCompositor(CompositorAnimation* animation,
KeyframeEffect* effect) {
DCHECK(effect);
@@ -257,6 +144,12 @@ unsigned NextSequenceNumber() {
static unsigned next = 0;
return ++next;
}
+
+double ToMilliseconds(base::Optional<base::TimeDelta> time) {
+ return time ? time->InMillisecondsF()
+ : std::numeric_limits<double>::quiet_NaN();
+}
+
} // namespace
WorkletAnimation* WorkletAnimation::Create(
@@ -300,12 +193,20 @@ WorkletAnimation* WorkletAnimation::Create(
return nullptr;
}
+ Document& document = keyframe_effects.at(0)->target()->GetDocument();
+ if (!document.GetWorkletAnimationController().IsAnimatorRegistered(
+ animator_name)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The animator '" + animator_name + "' has not yet been registered.");
+ return nullptr;
+ }
+
AnimationWorklet* worklet =
CSSAnimationWorklet::animationWorklet(script_state);
WorkletAnimationId id = worklet->NextWorkletAnimationId();
- Document& document = keyframe_effects.at(0)->target()->GetDocument();
AnimationTimeline* animation_timeline =
ConvertAnimationTimeline(document, timeline);
@@ -378,6 +279,12 @@ void WorkletAnimation::play(ExceptionState& exception_state) {
}
}
+double WorkletAnimation::currentTime(bool& is_null) {
+ base::Optional<base::TimeDelta> current_time = CurrentTime();
+ is_null = !current_time.has_value();
+ return ToMilliseconds(current_time);
+}
+
void WorkletAnimation::cancel() {
DCHECK(IsMainThread());
if (play_state_ == Animation::kIdle)
@@ -460,9 +367,9 @@ bool WorkletAnimation::CheckCanStart(String* failure_message) {
void WorkletAnimation::SetStartTimeToNow() {
DCHECK(!start_time_);
bool is_null;
- double time = timeline_->currentTime(is_null);
+ double time_ms = timeline_->currentTime(is_null);
if (!is_null)
- start_time_ = base::TimeDelta::FromSecondsD(time);
+ start_time_ = base::TimeDelta::FromMillisecondsD(time_ms);
}
void WorkletAnimation::UpdateCompositingState() {
@@ -533,8 +440,13 @@ bool WorkletAnimation::StartOnCompositor() {
return false;
if (!compositor_animation_) {
+ // TODO(smcgruer): If the scroll source later gets a LayoutBox (e.g. was
+ // display:none and now isn't) or the writing mode changes, we need to
+ // update the compositor to have the correct orientation and start/end
+ // offset information.
compositor_animation_ = CompositorAnimation::CreateWorkletAnimation(
- id_, animator_name_, ToCompositorScrollTimeline(timeline_),
+ id_, animator_name_,
+ scroll_timeline_util::ToCompositorScrollTimeline(timeline_),
std::move(options_));
compositor_animation_->SetAnimationDelegate(this);
}
@@ -553,9 +465,9 @@ bool WorkletAnimation::StartOnCompositor() {
SetPlayState(Animation::kRunning);
bool is_null;
- double time = timeline_->currentTime(is_null);
+ double time_ms = timeline_->currentTime(is_null);
if (!is_null)
- start_time_ = base::TimeDelta::FromSecondsD(time);
+ start_time_ = base::TimeDelta::FromMillisecondsD(time_ms);
return true;
}
@@ -572,7 +484,7 @@ void WorkletAnimation::UpdateOnCompositor() {
if (timeline_->IsScrollTimeline()) {
Node* scroll_source = ToScrollTimeline(timeline_)->ResolvedScrollSource();
- LayoutBox* box = scroll_source->GetLayoutBox();
+ LayoutBox* box = scroll_source ? scroll_source->GetLayoutBox() : nullptr;
base::Optional<double> start_scroll_offset;
base::Optional<double> end_scroll_offset;
@@ -591,8 +503,8 @@ void WorkletAnimation::UpdateOnCompositor() {
end_scroll_offset = resolved_end_scroll_offset;
}
compositor_animation_->UpdateScrollTimeline(
- GetCompositorScrollElementId(*scroll_source), start_scroll_offset,
- end_scroll_offset);
+ scroll_timeline_util::GetCompositorScrollElementId(scroll_source),
+ start_scroll_offset, end_scroll_offset);
}
}
@@ -619,20 +531,55 @@ bool WorkletAnimation::IsActiveAnimation() const {
return IsActive(play_state_);
}
-base::Optional<double> WorkletAnimation::CurrentTime() const {
+base::Optional<base::TimeDelta> WorkletAnimation::CurrentTime() const {
+ if (play_state_ == Animation::kIdle || play_state_ == Animation::kUnset)
+ return base::nullopt;
+
+ // TODO(majidvp): Animation has a hold time while it waits for animation
+ // to truly start and returns that instead. Replace with with hold time
+ // once pause logic is implemented.
+ if (play_state_ == Animation::kPending)
+ return base::TimeDelta();
+
bool is_null;
- double timeline_time = timeline_->currentTime(is_null);
+ double timeline_time_ms = timeline_->currentTime(is_null);
if (is_null)
return base::nullopt;
+
+ base::TimeDelta timeline_time =
+ base::TimeDelta::FromMillisecondsD(timeline_time_ms);
if (timeline_->IsScrollTimeline())
return timeline_time;
DCHECK(start_time_);
- return timeline_time - start_time_->InSecondsF();
+ return timeline_time - start_time_.value();
+}
+
+bool WorkletAnimation::NeedsPeek(base::TimeDelta current_time) {
+ bool local_time_is_set = false;
+ for (auto& time : local_times_) {
+ if (time) {
+ local_time_is_set = true;
+ break;
+ }
+ }
+
+ // If any of the local times has been set, a previous peek must have
+ // completed. Request a new peek only if the input time changes.
+ if (local_time_is_set)
+ return last_peek_request_time_ != current_time;
+
+ return true;
}
void WorkletAnimation::UpdateInputState(
AnimationWorkletDispatcherInput* input_state) {
if (!running_on_main_thread_) {
+ if (!CurrentTime())
+ return;
+ base::TimeDelta current_time = CurrentTime().value();
+ if (!NeedsPeek(current_time))
+ return;
+ last_peek_request_time_ = current_time;
input_state->Peek(id_);
return;
}
@@ -642,25 +589,23 @@ void WorkletAnimation::UpdateInputState(
// ScrollTimeline animation doesn't require start_time_ to be set.
DCHECK(start_time_ || timeline_->IsScrollTimeline());
- DCHECK(last_current_time_ || !was_active);
- double current_time =
- CurrentTime().value_or(std::numeric_limits<double>::quiet_NaN());
+ base::Optional<base::TimeDelta> current_time = CurrentTime();
+ double current_time_ms = ToMilliseconds(current_time);
- bool did_time_change =
- !last_current_time_ || current_time != last_current_time_->InSecondsF();
+ bool did_time_change = current_time != last_current_time_;
// TODO(yigu): If current_time becomes newly unresolved and last_current_time_
// is resolved, we apply the last current time to the animation if the scroll
// timeline becomes newly inactive. See https://crbug.com/906050.
- last_current_time_ = base::TimeDelta::FromSecondsD(current_time);
+ last_current_time_ = current_time;
if (!was_active && is_active) {
input_state->Add(
{id_,
std::string(animator_name_.Ascii().data(), animator_name_.length()),
- current_time, CloneOptions(), effects_.size()});
+ current_time_ms, CloneOptions(), effects_.size()});
} else if (was_active && is_active) {
// Skip if the input time is not changed.
if (did_time_change)
- input_state->Update({id_, current_time});
+ input_state->Update({id_, current_time_ms});
} else if (was_active && !is_active) {
input_state->Remove(id_);
}
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
index e680957199f..4cf8ccb0f90 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
@@ -72,6 +72,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
AnimationTimeline* timeline() { return timeline_; }
String playState();
+ double currentTime(bool& is_null);
void play(ExceptionState& exception_state);
void cancel();
@@ -118,10 +119,16 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
}
bool IsActiveAnimation() const override;
+ bool NeedsPeek(base::TimeDelta current_time);
+
void UpdateInputState(AnimationWorkletDispatcherInput* input_state) override;
void SetOutputState(
const AnimationWorkletOutput::AnimationState& state) override;
+ void SetRunningOnMainThreadForTesting(bool running_on_main_thread) {
+ running_on_main_thread_ = running_on_main_thread;
+ }
+
void Trace(blink::Visitor*) override;
private:
@@ -145,7 +152,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
void SetPlayState(const Animation::AnimationPlayState& state) {
play_state_ = state;
}
- base::Optional<double> CurrentTime() const;
+ base::Optional<base::TimeDelta> CurrentTime() const;
unsigned sequence_number_;
@@ -154,12 +161,13 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
const String animator_name_;
Animation::AnimationPlayState play_state_;
Animation::AnimationPlayState last_play_state_;
- // Start time in ms.
base::Optional<base::TimeDelta> start_time_;
Vector<base::Optional<base::TimeDelta>> local_times_;
// We use this to skip updating if current time has not changed since last
// update.
base::Optional<base::TimeDelta> last_current_time_;
+ // Time the main thread sends a peek request.
+ base::Optional<base::TimeDelta> last_peek_request_time_;
Member<Document> document_;
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl
index 0f7a4feb633..3f77238e1ee 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl
@@ -18,6 +18,7 @@
] interface WorkletAnimation {
readonly attribute AnimationTimeline? timeline;
readonly attribute AnimationPlayState playState;
+ readonly attribute double? currentTime;
[RaisesException] void play();
void cancel();
};
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
index e9239db8c4b..3d4f0e1f5e7 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/animation/keyframe_effect.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
+#include "third_party/blink/renderer/core/animation/worklet_animation_controller.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -44,6 +45,7 @@ KeyframeEffect* CreateKeyframeEffect(Element* element) {
WorkletAnimation* CreateWorkletAnimation(
ScriptState* script_state,
Element* element,
+ const String& animator_name,
ScrollTimeline* scroll_timeline = nullptr) {
AnimationEffectOrAnimationEffectSequence effects;
AnimationEffect* effect = CreateKeyframeEffect(element);
@@ -55,7 +57,7 @@ WorkletAnimation* CreateWorkletAnimation(
ScriptState::Scope scope(script_state);
DummyExceptionStateForTesting exception_state;
- return WorkletAnimation::Create(script_state, "WorkletAnimation", effects,
+ return WorkletAnimation::Create(script_state, animator_name, effects,
timeline, std::move(options),
exception_state);
}
@@ -70,7 +72,14 @@ class WorkletAnimationTest : public RenderingTest {
void SetUp() override {
RenderingTest::SetUp();
element_ = GetDocument().CreateElementForBinding("test");
- worklet_animation_ = CreateWorkletAnimation(GetScriptState(), element_);
+ // Animator has to be registored before constructing WorkletAnimation. For
+ // unit test this is faked by adding the animator name to
+ // WorkletAnimationController.
+ animator_name_ = "WorkletAnimationTest";
+ GetDocument().GetWorkletAnimationController().SynchronizeAnimatorName(
+ animator_name_);
+ worklet_animation_ =
+ CreateWorkletAnimation(GetScriptState(), element_, animator_name_);
}
ScriptState* GetScriptState() {
@@ -79,6 +88,7 @@ class WorkletAnimationTest : public RenderingTest {
Persistent<Element> element_;
Persistent<WorkletAnimation> worklet_animation_;
+ String animator_name_;
};
TEST_F(WorkletAnimationTest, WorkletAnimationInElementAnimations) {
@@ -103,15 +113,18 @@ TEST_F(WorkletAnimationTest, StyleHasCurrentAnimation) {
TEST_F(WorkletAnimationTest,
CurrentTimeFromDocumentTimelineIsOffsetByStartTime) {
- GetDocument().GetAnimationClock().ResetTimeForTesting();
- double error = base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF();
+ // Only expect precision up to 1 microsecond with an additional smaller
+ // component to account for double rounding/conversion error.
+ double error =
+ base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF() + 1e-13;
+
WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
base::TimeTicks first_ticks =
base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111);
base::TimeTicks second_ticks =
base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 123.4);
- GetDocument().GetAnimationClock().UpdateTime(first_ticks);
+ GetDocument().GetAnimationClock().ResetTimeForTesting(first_ticks);
DummyExceptionStateForTesting exception_state;
worklet_animation_->play(exception_state);
worklet_animation_->UpdateCompositingState();
@@ -121,12 +134,12 @@ TEST_F(WorkletAnimationTest,
worklet_animation_->UpdateInputState(state.get());
// First state request sets the start time and thus current time should be 0.
std::unique_ptr<AnimationWorkletInput> input =
- state->TakeWorkletState(id.scope_id);
+ state->TakeWorkletState(id.worklet_id);
EXPECT_NEAR(0, input->added_and_updated_animations[0].current_time, error);
state.reset(new AnimationWorkletDispatcherInput);
- GetDocument().GetAnimationClock().UpdateTime(second_ticks);
+ GetDocument().GetAnimationClock().ResetTimeForTesting(second_ticks);
worklet_animation_->UpdateInputState(state.get());
- input = state->TakeWorkletState(id.scope_id);
+ input = state->TakeWorkletState(id.worklet_id);
EXPECT_NEAR(123.4, input->updated_animations[0].current_time, error);
}
@@ -156,29 +169,91 @@ TEST_F(WorkletAnimationTest,
options->setScrollSource(GetElementById("scroller"));
ScrollTimeline* scroll_timeline =
ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
- WorkletAnimation* worklet_animation =
- CreateWorkletAnimation(GetScriptState(), element_, scroll_timeline);
+ WorkletAnimation* worklet_animation = CreateWorkletAnimation(
+ GetScriptState(), element_, animator_name_, scroll_timeline);
WorkletAnimationId id = worklet_animation->GetWorkletAnimationId();
DummyExceptionStateForTesting exception_state;
worklet_animation->play(exception_state);
worklet_animation->UpdateCompositingState();
- double error = base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF();
+ // Only expect precision up to 1 microsecond with an additional smaller
+ // component to account for double rounding/conversion error.
+ double error =
+ base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF() + 1e-13;
scrollable_area->SetScrollOffset(ScrollOffset(0, 40), kProgrammaticScroll);
std::unique_ptr<AnimationWorkletDispatcherInput> state =
std::make_unique<AnimationWorkletDispatcherInput>();
worklet_animation->UpdateInputState(state.get());
std::unique_ptr<AnimationWorkletInput> input =
- state->TakeWorkletState(id.scope_id);
+ state->TakeWorkletState(id.worklet_id);
EXPECT_NEAR(40, input->added_and_updated_animations[0].current_time, error);
state.reset(new AnimationWorkletDispatcherInput);
scrollable_area->SetScrollOffset(ScrollOffset(0, 70), kProgrammaticScroll);
worklet_animation->UpdateInputState(state.get());
- input = state->TakeWorkletState(id.scope_id);
+ input = state->TakeWorkletState(id.worklet_id);
EXPECT_NEAR(70, input->updated_animations[0].current_time, error);
}
+TEST_F(WorkletAnimationTest, MainThreadSendsPeekRequestTest) {
+ WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
+ base::TimeTicks first_ticks =
+ base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111);
+ base::TimeTicks second_ticks =
+ base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 123.4);
+
+ GetDocument().GetAnimationClock().ResetTimeForTesting(first_ticks);
+ DummyExceptionStateForTesting exception_state;
+ worklet_animation_->play(exception_state);
+ worklet_animation_->UpdateCompositingState();
+
+ // Only peek if animation is running on compositor.
+ worklet_animation_->SetRunningOnMainThreadForTesting(false);
+
+ std::unique_ptr<AnimationWorkletDispatcherInput> state =
+ std::make_unique<AnimationWorkletDispatcherInput>();
+ worklet_animation_->UpdateInputState(state.get());
+ std::unique_ptr<AnimationWorkletInput> input =
+ state->TakeWorkletState(id.worklet_id);
+ EXPECT_EQ(input->peeked_animations.size(), 1u);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+ EXPECT_EQ(input->removed_animations.size(), 0u);
+ state.reset(new AnimationWorkletDispatcherInput);
+
+ // Local times not set yet. Need to peek again.
+ AnimationWorkletOutput::AnimationState output(id);
+ worklet_animation_->SetOutputState(output);
+ worklet_animation_->UpdateInputState(state.get());
+ input = state->TakeWorkletState(id.worklet_id);
+ EXPECT_EQ(input->peeked_animations.size(), 1u);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+ EXPECT_EQ(input->removed_animations.size(), 0u);
+ state.reset(new AnimationWorkletDispatcherInput);
+
+ // Last peek request fulfilled. No need to peek.
+ std::vector<base::Optional<TimeDelta>> local_times;
+ local_times.push_back(TimeDelta());
+ AnimationWorkletOutput::AnimationState output_with_value(id);
+ output_with_value.local_times = local_times;
+ worklet_animation_->SetOutputState(output_with_value);
+ worklet_animation_->UpdateInputState(state.get());
+ input = state->TakeWorkletState(id.worklet_id);
+ EXPECT_FALSE(input);
+ state.reset(new AnimationWorkletDispatcherInput);
+
+ // Input time changes. Need to peek again.
+ GetDocument().GetAnimationClock().ResetTimeForTesting(second_ticks);
+ worklet_animation_->UpdateInputState(state.get());
+ input = state->TakeWorkletState(id.worklet_id);
+ EXPECT_EQ(input->peeked_animations.size(), 1u);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+ EXPECT_EQ(input->removed_animations.size(), 0u);
+ state.reset(new AnimationWorkletDispatcherInput);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc b/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
index 83b52ef173c..dd1c1477f45 100644
--- a/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
@@ -26,8 +26,10 @@ void AppBannerController::BindMojoRequest(
mojom::blink::AppBannerControllerRequest request) {
DCHECK(frame);
+ // See https://bit.ly/2S0zRAS for task types.
mojo::MakeStrongBinding(std::make_unique<AppBannerController>(*frame),
- std::move(request));
+ std::move(request),
+ frame->GetTaskRunner(TaskType::kMiscPlatformAPI));
}
void AppBannerController::BannerPromptRequest(
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc
index 6a09b2fefe5..d74526725cb 100644
--- a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc
+++ b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc
@@ -22,11 +22,14 @@ BeforeInstallPromptEvent::BeforeInstallPromptEvent(
: Event(name, Bubbles::kNo, Cancelable::kYes),
ContextClient(&frame),
banner_service_(std::move(service_ptr)),
- binding_(this, std::move(event_request)),
+ binding_(this,
+ std::move(event_request),
+ frame.GetTaskRunner(TaskType::kApplicationLifeCycle)),
platforms_(platforms),
- user_choice_(new UserChoiceProperty(frame.GetDocument(),
- this,
- UserChoiceProperty::kUserChoice)),
+ user_choice_(MakeGarbageCollected<UserChoiceProperty>(
+ frame.GetDocument(),
+ this,
+ UserChoiceProperty::kUserChoice)),
require_gesture_(require_gesture) {
DCHECK(banner_service_);
DCHECK(binding_.is_bound());
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.h b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.h
index 0d1a7eafacb..b0d2a217729 100644
--- a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.h
+++ b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.h
@@ -36,6 +36,15 @@ class BeforeInstallPromptEvent final
USING_GARBAGE_COLLECTED_MIXIN(BeforeInstallPromptEvent);
public:
+ BeforeInstallPromptEvent(const AtomicString& name,
+ LocalFrame&,
+ mojom::blink::AppBannerServicePtr,
+ mojom::blink::AppBannerEventRequest,
+ const Vector<String>& platforms,
+ bool require_gesture);
+ BeforeInstallPromptEvent(ExecutionContext*,
+ const AtomicString& name,
+ const BeforeInstallPromptEventInit*);
~BeforeInstallPromptEvent() override;
static BeforeInstallPromptEvent* Create(
@@ -45,16 +54,17 @@ class BeforeInstallPromptEvent final
mojom::blink::AppBannerEventRequest event_request,
const Vector<String>& platforms,
bool require_gesture) {
- return new BeforeInstallPromptEvent(name, frame, std::move(service_ptr),
- std::move(event_request), platforms,
- require_gesture);
+ return MakeGarbageCollected<BeforeInstallPromptEvent>(
+ name, frame, std::move(service_ptr), std::move(event_request),
+ platforms, require_gesture);
}
static BeforeInstallPromptEvent* Create(
ExecutionContext* execution_context,
const AtomicString& name,
const BeforeInstallPromptEventInit* init) {
- return new BeforeInstallPromptEvent(execution_context, name, init);
+ return MakeGarbageCollected<BeforeInstallPromptEvent>(execution_context,
+ name, init);
}
void Dispose();
@@ -72,16 +82,6 @@ class BeforeInstallPromptEvent final
void Trace(blink::Visitor*) override;
private:
- BeforeInstallPromptEvent(const AtomicString& name,
- LocalFrame&,
- mojom::blink::AppBannerServicePtr,
- mojom::blink::AppBannerEventRequest,
- const Vector<String>& platforms,
- bool require_gesture);
- BeforeInstallPromptEvent(ExecutionContext*,
- const AtomicString& name,
- const BeforeInstallPromptEventInit*);
-
// mojom::blink::AppBannerEvent methods:
void BannerAccepted(const String& platform) override;
void BannerDismissed() override;
diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc
index 369c1242759..1185ee2eee3 100644
--- a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc
+++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc
@@ -28,13 +28,13 @@ class SetSinkIdResolver : public ScriptPromiseResolver {
static SetSinkIdResolver* Create(ScriptState*,
HTMLMediaElement&,
const String& sink_id);
+ SetSinkIdResolver(ScriptState*, HTMLMediaElement&, const String& sink_id);
~SetSinkIdResolver() override = default;
void StartAsync();
void Trace(blink::Visitor*) override;
private:
- SetSinkIdResolver(ScriptState*, HTMLMediaElement&, const String& sink_id);
void TimerFired(TimerBase*);
Member<HTMLMediaElement> element_;
@@ -46,8 +46,7 @@ SetSinkIdResolver* SetSinkIdResolver::Create(ScriptState* script_state,
HTMLMediaElement& element,
const String& sink_id) {
SetSinkIdResolver* resolver =
- new SetSinkIdResolver(script_state, element, sink_id);
- resolver->PauseIfNeeded();
+ MakeGarbageCollected<SetSinkIdResolver>(script_state, element, sink_id);
resolver->KeepAliveWhilePending();
return resolver;
}
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn b/chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn
index 5dec3654ced..2c396ef9810 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn
@@ -10,8 +10,6 @@ blink_modules_sources("background_fetch") {
"background_fetch_bridge.h",
"background_fetch_event.cc",
"background_fetch_event.h",
- "background_fetch_fetch.cc",
- "background_fetch_fetch.h",
"background_fetch_icon_loader.cc",
"background_fetch_icon_loader.h",
"background_fetch_manager.cc",
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
index fba9ac808ae..1e85daf30f8 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
@@ -23,7 +23,8 @@ BackgroundFetchBridge* BackgroundFetchBridge::From(
service_worker_registration);
if (!bridge) {
- bridge = new BackgroundFetchBridge(*service_worker_registration);
+ bridge = MakeGarbageCollected<BackgroundFetchBridge>(
+ *service_worker_registration);
ProvideTo(*service_worker_registration, bridge);
}
@@ -130,7 +131,10 @@ void BackgroundFetchBridge::AddRegistrationObserver(
mojom::blink::BackgroundFetchService* BackgroundFetchBridge::GetService() {
if (!background_fetch_service_) {
- auto request = mojo::MakeRequest(&background_fetch_service_);
+ auto request = mojo::MakeRequest(
+ &background_fetch_service_,
+ GetSupplementable()->GetExecutionContext()->GetTaskRunner(
+ TaskType::kBackgroundFetch));
if (auto* interface_provider = GetSupplementable()
->GetExecutionContext()
->GetInterfaceProvider()) {
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h
index 1ca427abf8f..12212a8c453 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_BRIDGE_H_
#include <memory>
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -44,6 +44,7 @@ class BackgroundFetchBridge final
static BackgroundFetchBridge* From(ServiceWorkerRegistration* registration);
+ explicit BackgroundFetchBridge(ServiceWorkerRegistration& registration);
virtual ~BackgroundFetchBridge();
// Creates a new Background Fetch registration identified by |developer_id|
@@ -108,8 +109,6 @@ class BackgroundFetchBridge final
mojom::blink::BackgroundFetchRegistrationObserverPtr observer);
private:
- explicit BackgroundFetchBridge(ServiceWorkerRegistration& registration);
-
// Returns an initialized BackgroundFetchService*. A connection will be
// established after the first call to this method.
mojom::blink::BackgroundFetchService* GetService();
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.h
index 5712e9f7dd7..5f50663ec8d 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_EVENT_H_
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/service_worker/extendable_event.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -24,16 +24,21 @@ class MODULES_EXPORT BackgroundFetchEvent : public ExtendableEvent {
static BackgroundFetchEvent* Create(
const AtomicString& type,
const BackgroundFetchEventInit* initializer) {
- return new BackgroundFetchEvent(type, initializer, nullptr /* observer */);
+ return MakeGarbageCollected<BackgroundFetchEvent>(type, initializer,
+ nullptr /* observer */);
}
static BackgroundFetchEvent* Create(
const AtomicString& type,
const BackgroundFetchEventInit* initializer,
WaitUntilObserver* observer) {
- return new BackgroundFetchEvent(type, initializer, observer);
+ return MakeGarbageCollected<BackgroundFetchEvent>(type, initializer,
+ observer);
}
+ BackgroundFetchEvent(const AtomicString& type,
+ const BackgroundFetchEventInit* initializer,
+ WaitUntilObserver* observer);
~BackgroundFetchEvent() override;
// Web Exposed attribute defined in the IDL file.
@@ -45,10 +50,6 @@ class MODULES_EXPORT BackgroundFetchEvent : public ExtendableEvent {
void Trace(blink::Visitor* visitor) override;
protected:
- BackgroundFetchEvent(const AtomicString& type,
- const BackgroundFetchEventInit* initializer,
- WaitUntilObserver* observer);
-
// Corresponds to the 'registration' attribute in the idl.
Member<BackgroundFetchRegistration> registration_;
};
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fail_event_init.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fail_event_init.idl
deleted file mode 100644
index 69b314c39f4..00000000000
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fail_event_init.idl
+++ /dev/null
@@ -1,9 +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.
-
-// https://wicg.github.io/background-fetch/#background-fetch-fail-event
-
-dictionary BackgroundFetchFailEventInit : BackgroundFetchEventInit {
- required sequence<BackgroundFetchSettledFetch> fetches;
-};
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.cc
deleted file mode 100644
index 07bffef39d7..00000000000
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.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 "third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.h"
-
-#include "third_party/blink/renderer/core/fetch/request.h"
-
-namespace blink {
-
-BackgroundFetchFetch::BackgroundFetchFetch(Request* request)
- : request_(request) {}
-
-Request* BackgroundFetchFetch::request() const {
- return request_;
-}
-
-void BackgroundFetchFetch::Trace(blink::Visitor* visitor) {
- visitor->Trace(request_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.h
deleted file mode 100644
index 1f68cf01058..00000000000
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.h
+++ /dev/null
@@ -1,35 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_FETCH_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_FETCH_H_
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class Request;
-
-// Base interface for providing developers with access to the fetch
-// information associated with a background fetch.
-class BackgroundFetchFetch : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- // Web Exposed attribute defined in the IDL file.
- Request* request() const;
-
- void Trace(blink::Visitor* visitor) override;
-
- protected:
- explicit BackgroundFetchFetch(Request* request);
-
- private:
- Member<Request> request_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_FETCH_H_
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl
deleted file mode 100644
index df03e494252..00000000000
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl
+++ /dev/null
@@ -1,12 +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.
-
-// https://wicg.github.io/background-fetch/#backgroundfetchfetch
-
-[
- Exposed=(Window,Worker),
- OriginTrialEnabled=BackgroundFetch
-] interface BackgroundFetchFetch {
- readonly attribute Request request;
-};
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
index 13acb071646..d5215261b3f 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
@@ -38,7 +38,8 @@ constexpr char kBackgroundFetchImageLoaderIcon3000x2000[] = "3000x2000.png";
class BackgroundFetchIconLoaderTest : public PageTestBase {
public:
- BackgroundFetchIconLoaderTest() : loader_(new BackgroundFetchIconLoader()) {}
+ BackgroundFetchIconLoaderTest()
+ : loader_(MakeGarbageCollected<BackgroundFetchIconLoader>()) {}
~BackgroundFetchIconLoaderTest() override {
loader_->Stop();
platform_->GetURLLoaderMockFactory()
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index bb8c162e3c5..806b3ee55a8 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -123,9 +123,6 @@ scoped_refptr<BlobDataHandle> ExtractBlobHandle(
ExceptionState& exception_state) {
DCHECK(request);
- if (!RuntimeEnabledFeatures::BackgroundFetchUploadsEnabled())
- return nullptr;
-
if (request->IsBodyLocked(exception_state) == Body::BodyLocked::kLocked ||
request->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) {
DCHECK(!exception_state.HadException());
@@ -184,15 +181,6 @@ ScriptPromise BackgroundFetchManager::fetch(
UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.HasRequestsWithBody",
has_requests_with_body);
- if (has_requests_with_body &&
- !RuntimeEnabledFeatures::BackgroundFetchUploadsEnabled()) {
- return ScriptPromise::Reject(
- script_state, V8ThrowException::CreateTypeError(
- script_state->GetIsolate(),
- "Requests with a body are not yet supported. "
- "For updates check http://crbug.com/774054"));
- }
-
ExecutionContext* execution_context = ExecutionContext::From(script_state);
// A HashSet to find whether there are any duplicate requests within the
@@ -257,24 +245,8 @@ ScriptPromise BackgroundFetchManager::fetch(
kurls.insert(request_url);
}
- const bool has_duplicate_requests = kurls.size() != fetch_api_requests.size();
-
UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.HasDuplicateRequests",
- has_duplicate_requests);
-
- // Note: This is a proprietary check, due to the way Chrome currently handles
- // storing background fetch records. Entries are keyed by the URL, so if two
- // requests have the same URL, and different responses, the first response
- // will be lost when the second request/response pair is stored.
- if (has_duplicate_requests) {
- return ScriptPromise::Reject(
- script_state,
- V8ThrowException::CreateTypeError(
- script_state->GetIsolate(),
- "Fetches with duplicate requests are not yet supported. "
- "Consider adding query params to make the requests unique. "
- "For updates check http://crbug.com/871174"));
- }
+ kurls.size() != fetch_api_requests.size());
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
@@ -284,7 +256,8 @@ ScriptPromise BackgroundFetchManager::fetch(
mojom::blink::BackgroundFetchOptionsPtr options_ptr =
mojom::blink::BackgroundFetchOptions::From(options);
if (options->icons().size()) {
- BackgroundFetchIconLoader* loader = new BackgroundFetchIconLoader();
+ BackgroundFetchIconLoader* loader =
+ MakeGarbageCollected<BackgroundFetchIconLoader>();
loaders_.push_back(loader);
loader->Start(
bridge_.Get(), execution_context, options->icons(),
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h
index 7001f931e7c..763762ce988 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_MANAGER_H_
#include "base/time/time.h"
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -38,10 +38,12 @@ class MODULES_EXPORT BackgroundFetchManager final
DEFINE_WRAPPERTYPEINFO();
public:
+ explicit BackgroundFetchManager(ServiceWorkerRegistration* registration);
~BackgroundFetchManager() override = default;
+
static BackgroundFetchManager* Create(
ServiceWorkerRegistration* registration) {
- return new BackgroundFetchManager(registration);
+ return MakeGarbageCollected<BackgroundFetchManager>(registration);
}
// Web Exposed methods defined in the IDL file.
@@ -62,8 +64,6 @@ class MODULES_EXPORT BackgroundFetchManager final
private:
friend class BackgroundFetchManagerTest;
- explicit BackgroundFetchManager(ServiceWorkerRegistration* registration);
-
// Creates a vector of mojom::blink::FetchAPIRequestPtr objects for the given
// set of |requests|, which can be either Request objects or URL strings.
// |has_requests_with_body| will be set if any of the |requests| has a body.
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.cc
index ce168cd3a8e..0e37d459bd3 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.cc
@@ -14,17 +14,17 @@ BackgroundFetchRecord::BackgroundFetchRecord(Request* request,
: request_(request), script_state_(script_state) {
DCHECK(request_);
DCHECK(script_state_);
- response_ready_property_ =
- new ResponseReadyProperty(ExecutionContext::From(script_state), this,
- ResponseReadyProperty::kResponseReady);
+
+ response_ready_property_ = MakeGarbageCollected<ResponseReadyProperty>(
+ ExecutionContext::From(script_state), this,
+ ResponseReadyProperty::kResponseReady);
}
BackgroundFetchRecord::~BackgroundFetchRecord() = default;
void BackgroundFetchRecord::ResolveResponseReadyProperty(Response* response) {
- if (!response_ready_property_ ||
- response_ready_property_->GetState() !=
- ScriptPromisePropertyBase::State::kPending) {
+ if (response_ready_property_->GetState() !=
+ ScriptPromisePropertyBase::State::kPending) {
return;
}
@@ -45,7 +45,7 @@ void BackgroundFetchRecord::ResolveResponseReadyProperty(Response* response) {
if (!script_state_->ContextIsValid())
return;
- // TODO(crbug.com/875201):Per https://wicg.github.io/background-fetch/
+ // TODO(crbug.com/875201): Per https://wicg.github.io/background-fetch/
// #background-fetch-response-exposed, this should be resolved with a
// TypeError. Figure out a way to do so.
// Rejecting this with a TypeError here doesn't work because the
@@ -68,6 +68,8 @@ void BackgroundFetchRecord::UpdateState(
BackgroundFetchRecord::State updated_state) {
DCHECK_EQ(record_state_, State::kPending);
+ if (!script_state_->ContextIsValid())
+ return;
record_state_ = updated_state;
ResolveResponseReadyProperty(/* updated_response = */ nullptr);
}
@@ -81,6 +83,7 @@ void BackgroundFetchRecord::SetResponseAndUpdateState(
return;
record_state_ = State::kSettled;
+ ScriptState::Scope scope(script_state_);
ResolveResponseReadyProperty(Response::Create(script_state_, *response));
}
@@ -88,6 +91,18 @@ bool BackgroundFetchRecord::IsRecordPending() {
return record_state_ == State::kPending;
}
+void BackgroundFetchRecord::OnRequestCompleted(
+ mojom::blink::FetchAPIResponsePtr response) {
+ if (!response.is_null())
+ SetResponseAndUpdateState(response);
+ else
+ UpdateState(State::kSettled);
+}
+
+const KURL& BackgroundFetchRecord::ObservedUrl() const {
+ return request_->url();
+}
+
void BackgroundFetchRecord::Trace(blink::Visitor* visitor) {
visitor->Trace(request_);
visitor->Trace(response_ready_property_);
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.h
index 673a3093933..d150009b428 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_RECORD_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_RECORD_H_
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_property.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/testing/garbage_collected_script_wrappable.h"
#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
@@ -50,13 +50,16 @@ class MODULES_EXPORT BackgroundFetchRecord final : public ScriptWrappable {
bool IsRecordPending();
void Trace(blink::Visitor* visitor) override;
+ void OnRequestCompleted(mojom::blink::FetchAPIResponsePtr response);
+ const KURL& ObservedUrl() const;
+
private:
using ResponseReadyProperty =
ScriptPromiseProperty<Member<BackgroundFetchRecord>,
Member<Response>,
Member<DOMException>>;
- // Resolves a pending |response_read_property_| with |response|, if it's not
+ // Resolves a pending |response_ready_property_| with |response|, if it's not
// null.
// If |response| is null, we do nothing if the record isn't final yet. If
// |record_state_| is State::kSettled in this case, we reject the promise.
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl
index bf812380814..f902243dec7 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl
@@ -5,9 +5,9 @@
// https://wicg.github.io/background-fetch/#background-fetch-record
[
- Exposed=(ServiceWorker),
+ Exposed=(Window,Worker),
OriginTrialEnabled=BackgroundFetch
] interface BackgroundFetchRecord {
readonly attribute Request request;
[CallWith=ScriptState] readonly attribute Promise<Response> responseReady;
-}; \ No newline at end of file
+};
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
index 282e58cc60d..5c48f4071ce 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -4,9 +4,10 @@
#include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
+#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/fetch/request.h"
@@ -67,8 +68,11 @@ void BackgroundFetchRegistration::Initialize(
registration_ = registration;
+ auto task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kBackgroundFetch);
mojom::blink::BackgroundFetchRegistrationObserverPtr observer;
- observer_binding_.Bind(mojo::MakeRequest(&observer));
+ observer_binding_.Bind(mojo::MakeRequest(&observer, task_runner),
+ task_runner);
BackgroundFetchBridge::From(registration_)
->AddRegistrationObserver(unique_id_, std::move(observer));
@@ -88,8 +92,6 @@ void BackgroundFetchRegistration::OnProgress(
result_ = result;
failure_reason_ = failure_reason;
- // TODO(crbug.com/875201): Update records in |records_|.
-
ExecutionContext* context = GetExecutionContext();
if (!context || context->IsContextDestroyed())
return;
@@ -102,6 +104,20 @@ void BackgroundFetchRegistration::OnRecordsUnavailable() {
records_available_ = false;
}
+void BackgroundFetchRegistration::OnRequestCompleted(
+ mojom::blink::FetchAPIRequestPtr request,
+ mojom::blink::FetchAPIResponsePtr response) {
+ for (auto* it = observers_.begin(); it != observers_.end();) {
+ BackgroundFetchRecord* observer = it->Get();
+ if (observer->ObservedUrl() == request->url) {
+ observer->OnRequestCompleted(response->Clone());
+ it = observers_.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
String BackgroundFetchRegistration::id() const {
return developer_id_;
}
@@ -153,9 +169,10 @@ ScriptPromise BackgroundFetchRegistration::match(
const RequestOrUSVString& request,
const CacheQueryOptions* options,
ExceptionState& exception_state) {
- return MatchImpl(
- script_state, base::make_optional<RequestOrUSVString>(request),
- Cache::ToQueryParams(options), exception_state, /* match_all = */ false);
+ return MatchImpl(script_state,
+ base::make_optional<RequestOrUSVString>(request),
+ Cache::ToQueryParams(options), exception_state,
+ /* match_all = */ false);
}
ScriptPromise BackgroundFetchRegistration::matchAll(
@@ -182,17 +199,11 @@ ScriptPromise BackgroundFetchRegistration::MatchImpl(
mojom::blink::QueryParamsPtr cache_query_params,
ExceptionState& exception_state,
bool match_all) {
- // TODO(crbug.com/875201): Update this check once we support access to active
- // fetches.
- if (result_ == mojom::BackgroundFetchResult::UNSET &&
- !RuntimeEnabledFeatures::BackgroundFetchAccessActiveFetchesEnabled()) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- DOMException::Create(
- DOMExceptionCode::kInvalidStateError,
- "Access to records for in-progress background fetches is not yet "
- "implemented. Please see crbug.com/875201 for more details."));
- }
+ DCHECK(script_state);
+ UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.MatchCalledFromDocumentScope",
+ ExecutionContext::From(script_state)->IsDocument());
+ UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.MatchCalledWhenFetchIsIncomplete",
+ result_ == mojom::BackgroundFetchResult::UNSET);
if (!records_available_) {
return ScriptPromise::RejectWithDOMException(
@@ -242,20 +253,16 @@ void BackgroundFetchRegistration::DidGetMatchingRequests(
ScriptState::Scope scope(script_state);
HeapVector<Member<BackgroundFetchRecord>> to_return;
to_return.ReserveInitialCapacity(settled_fetches.size());
+
for (auto& fetch : settled_fetches) {
- // If there isn't a record for this fetch in records_ already, create one.
- auto iter = records_.find(fetch->request->url);
- BackgroundFetchRecord* record = nullptr;
- if (iter == records_.end()) {
- Request* request = Request::Create(script_state, *(fetch->request));
- auto* new_record = new BackgroundFetchRecord(request, script_state);
- DCHECK(new_record);
- records_.Set(request->url(), new_record);
-
- record = new_record;
- } else {
- record = iter->value;
- }
+ Request* request = Request::Create(script_state, *(fetch->request));
+ auto* record =
+ MakeGarbageCollected<BackgroundFetchRecord>(request, script_state);
+
+ // If this request is incomplete, enlist this record to receive updates on
+ // the request.
+ if (fetch->response.is_null() && !IsAborted())
+ observers_.push_back(*record);
UpdateRecord(record, fetch->response);
to_return.push_back(record);
@@ -267,11 +274,13 @@ void BackgroundFetchRegistration::DidGetMatchingRequests(
resolver->Resolve();
return;
}
+
DCHECK_EQ(settled_fetches.size(), 1u);
DCHECK_EQ(to_return.size(), 1u);
resolver->Resolve(to_return[0]);
return;
}
+
resolver->Resolve(to_return);
}
@@ -360,8 +369,8 @@ const String BackgroundFetchRegistration::failureReason() const {
return "fetch-error";
case mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED:
return "quota-exceeded";
- case mojom::BackgroundFetchFailureReason::TOTAL_DOWNLOAD_SIZE_EXCEEDED:
- return "total-download-exceeded";
+ case mojom::BackgroundFetchFailureReason::DOWNLOAD_TOTAL_EXCEEDED:
+ return "download-total-exceeded";
}
NOTREACHED();
}
@@ -370,10 +379,20 @@ void BackgroundFetchRegistration::Dispose() {
observer_binding_.Close();
}
+bool BackgroundFetchRegistration::HasPendingActivity() const {
+ if (!GetExecutionContext())
+ return false;
+ if (GetExecutionContext()->IsContextDestroyed())
+ return false;
+
+ return !observers_.IsEmpty();
+}
+
void BackgroundFetchRegistration::Trace(Visitor* visitor) {
visitor->Trace(registration_);
- visitor->Trace(records_);
+ visitor->Trace(observers_);
EventTargetWithInlineData::Trace(visitor);
+ ActiveScriptWrappable::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
index 715709c42f2..4c8b41aa5a7 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
@@ -6,13 +6,13 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_REGISTRATION_H_
#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -29,9 +29,11 @@ struct WebBackgroundFetchRegistration;
// access to its properties, options, and enables them to abort the fetch.
class BackgroundFetchRegistration final
: public EventTargetWithInlineData,
+ public ActiveScriptWrappable<BackgroundFetchRegistration>,
public blink::mojom::blink::BackgroundFetchRegistrationObserver {
DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(BackgroundFetchRegistration, Dispose);
+ USING_GARBAGE_COLLECTED_MIXIN(BackgroundFetchRegistration);
public:
BackgroundFetchRegistration(
@@ -64,6 +66,11 @@ class BackgroundFetchRegistration final
mojom::BackgroundFetchFailureReason failure_reason) override;
void OnRecordsUnavailable() override;
+ // Called when the |request| is complete. |response| points to the response
+ // received, if any.
+ void OnRequestCompleted(mojom::blink::FetchAPIRequestPtr request,
+ mojom::blink::FetchAPIResponsePtr response) override;
+
// Web Exposed attribute defined in the IDL file. Corresponds to the
// |developer_id| used elsewhere in the codebase.
String id() const;
@@ -100,6 +107,9 @@ class BackgroundFetchRegistration final
void Trace(blink::Visitor* visitor) override;
+ // Keeps the object alive until there are non-zero number of |observers_|.
+ bool HasPendingActivity() const final;
+
private:
void DidAbort(ScriptPromiseResolver* resolver,
mojom::blink::BackgroundFetchError error);
@@ -122,9 +132,6 @@ class BackgroundFetchRegistration final
Member<ServiceWorkerRegistration> registration_;
- // TODO(crbug.com/774054): Update the key once we support duplicate requests.
- HeapHashMap<KURL, Member<BackgroundFetchRecord>> records_;
-
// Corresponds to IDL 'id' attribute. Not unique - an active registration can
// have the same |developer_id_| as one or more inactive registrations.
String developer_id_;
@@ -141,6 +148,7 @@ class BackgroundFetchRegistration final
bool records_available_ = true;
mojom::BackgroundFetchResult result_;
mojom::BackgroundFetchFailureReason failure_reason_;
+ HeapVector<Member<BackgroundFetchRecord>> observers_;
mojo::Binding<blink::mojom::blink::BackgroundFetchRegistrationObserver>
observer_binding_;
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
index 5760956f4d0..6442de9d063 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
@@ -3,26 +3,10 @@
// found in the LICENSE file.
// https://wicg.github.io/background-fetch/#background-fetch-registration
-enum BackgroundFetchFailureReason {
- "",
- // The operation was aborted by the user, or abort() was called.
- "aborted",
- // A response had a not-ok-status.
- "bad-status",
- // A fetch failed for other reasons, e.g. CORS, MIX, an invalid partial response,
- // or a general network failure for a fetch that cannot be retried.
- "fetch-error",
- // Storage quota was reached during the operation.
- "quota-exceeded",
- // The provided downloadTotal was exceeded.
- "total-download-exceeded"
-};
-
-enum BackgroundFetchResult { "", "success", "failure" };
-
[
Exposed=(Window,Worker),
- OriginTrialEnabled=BackgroundFetch
+ OriginTrialEnabled=BackgroundFetch,
+ ActiveScriptWrappable
] interface BackgroundFetchRegistration : EventTarget {
readonly attribute DOMString id;
readonly attribute unsigned long long uploadTotal;
@@ -36,9 +20,25 @@ enum BackgroundFetchResult { "", "success", "failure" };
attribute EventHandler onprogress;
[CallWith=ScriptState, MeasureAs=BackgroundFetchRegistrationAbort] Promise<boolean> abort();
+ [CallWith=ScriptState, RaisesException, MeasureAs=BackgroundFetchRegistrationMatch] Promise<BackgroundFetchRecord> match(RequestInfo request, optional CacheQueryOptions options);
+ [CallWith=ScriptState, RaisesException, MeasureAs=BackgroundFetchRegistrationMatchAll] Promise<sequence<BackgroundFetchRecord>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
+};
+
+enum BackgroundFetchResult { "", "success", "failure" };
- // TODO(crbug.com/875201): Change to (Window,Worker) once we support
- // match() and matchAll() for active fetches.
- [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException, MeasureAs=BackgroundFetchRegistrationMatch] Promise<BackgroundFetchRecord> match(RequestInfo request, optional CacheQueryOptions options);
- [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException, MeasureAs=BackgroundFetchRegistrationMatchAll] Promise<sequence<BackgroundFetchRecord>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
+enum BackgroundFetchFailureReason {
+ // The background fetch has not completed yet, or was successful.
+ "",
+ // The operation was aborted by the user, or abort() was called.
+ "aborted",
+ // A response had a not-ok-status.
+ "bad-status",
+ // A fetch failed for other reasons, e.g. CORS, MIX, an invalid partial response,
+ // or a general network failure for a fetch that cannot be retried.
+ "fetch-error",
+ // Storage quota was reached during the operation.
+ "quota-exceeded",
+ // The provided downloadTotal was exceeded.
+ "download-total-exceeded"
};
+
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
index ccde3bb86c0..410e8cecf1b 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
@@ -19,7 +19,7 @@ TypeConverter<blink::BackgroundFetchRegistration*,
if (!mojo_registration)
return nullptr;
- return new blink::BackgroundFetchRegistration(
+ return blink::MakeGarbageCollected<blink::BackgroundFetchRegistration>(
mojo_registration->developer_id, mojo_registration->unique_id,
mojo_registration->upload_total, mojo_registration->uploaded,
mojo_registration->download_total, mojo_registration->downloaded,
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.h
index 08aa085da9d..3d64bbc6d29 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_TYPE_CONVERTERS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_TYPE_CONVERTERS_H_
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
#include "third_party/blink/renderer/modules/background_fetch/background_fetch_options.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
index 0ba564868a6..285f99cadf2 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
@@ -83,7 +83,7 @@ ScriptPromise BackgroundFetchUpdateUIEvent::updateUI(
-1 /* ideal_to_chosen_icon_size */);
} else {
DCHECK(!loader_);
- loader_ = new BackgroundFetchIconLoader();
+ loader_ = MakeGarbageCollected<BackgroundFetchIconLoader>();
DCHECK(loader_);
loader_->Start(BackgroundFetchBridge::From(service_worker_registration_),
ExecutionContext::From(script_state), ui_options->icons(),
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h
index c6baa7f2029..7e5aba36679 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_UPDATE_UI_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_BACKGROUND_FETCH_BACKGROUND_FETCH_UPDATE_UI_EVENT_H_
-#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-blink.h"
+#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/modules/background_fetch/background_fetch_event.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
@@ -30,7 +30,8 @@ class MODULES_EXPORT BackgroundFetchUpdateUIEvent final
static BackgroundFetchUpdateUIEvent* Create(
const AtomicString& type,
const BackgroundFetchEventInit* initializer) {
- return new BackgroundFetchUpdateUIEvent(type, initializer);
+ return MakeGarbageCollected<BackgroundFetchUpdateUIEvent>(type,
+ initializer);
}
static BackgroundFetchUpdateUIEvent* Create(
@@ -38,10 +39,16 @@ class MODULES_EXPORT BackgroundFetchUpdateUIEvent final
const BackgroundFetchEventInit* initializer,
WaitUntilObserver* observer,
ServiceWorkerRegistration* registration) {
- return new BackgroundFetchUpdateUIEvent(type, initializer, observer,
- registration);
+ return MakeGarbageCollected<BackgroundFetchUpdateUIEvent>(
+ type, initializer, observer, registration);
}
+ BackgroundFetchUpdateUIEvent(const AtomicString& type,
+ const BackgroundFetchEventInit* initializer);
+ BackgroundFetchUpdateUIEvent(const AtomicString& type,
+ const BackgroundFetchEventInit* init,
+ WaitUntilObserver* observer,
+ ServiceWorkerRegistration* registration);
~BackgroundFetchUpdateUIEvent() override;
// Web Exposed method defined in the IDL file.
@@ -51,14 +58,6 @@ class MODULES_EXPORT BackgroundFetchUpdateUIEvent final
void Trace(blink::Visitor* visitor) override;
private:
- BackgroundFetchUpdateUIEvent(const AtomicString& type,
- const BackgroundFetchEventInit* initializer);
-
- BackgroundFetchUpdateUIEvent(const AtomicString& type,
- const BackgroundFetchEventInit* init,
- WaitUntilObserver* observer,
- ServiceWorkerRegistration* registration);
-
void DidGetIcon(ScriptPromiseResolver* resolver,
const String& title,
const SkBitmap& icon,
diff --git a/chromium/third_party/blink/renderer/modules/badging/badge.cc b/chromium/third_party/blink/renderer/modules/badging/badge.cc
index e751f41bb75..b7c7ca2383a 100644
--- a/chromium/third_party/blink/renderer/modules/badging/badge.cc
+++ b/chromium/third_party/blink/renderer/modules/badging/badge.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/modules/badging/badge.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/renderer/bindings/modules/v8/usv_string_or_long.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -21,7 +20,7 @@ Badge::~Badge() = default;
Badge* Badge::From(ExecutionContext* context) {
Badge* supplement = Supplement<ExecutionContext>::From<Badge>(context);
if (!supplement) {
- supplement = new Badge(context);
+ supplement = MakeGarbageCollected<Badge>(context);
ProvideTo(*context, supplement);
}
return supplement;
@@ -29,14 +28,17 @@ Badge* Badge::From(ExecutionContext* context) {
// static
void Badge::set(ScriptState* script_state, ExceptionState& exception_state) {
- BadgeFromState(script_state)->Set(nullptr, exception_state);
+ BadgeFromState(script_state)->SetFlag();
}
// static
void Badge::set(ScriptState* script_state,
- USVStringOrLong& contents,
+ uint64_t content,
ExceptionState& exception_state) {
- BadgeFromState(script_state)->Set(&contents, exception_state);
+ if (content == 0)
+ BadgeFromState(script_state)->Clear();
+ else
+ BadgeFromState(script_state)->SetInteger(content);
}
// static
@@ -44,21 +46,12 @@ void Badge::clear(ScriptState* script_state) {
BadgeFromState(script_state)->Clear();
}
-void Badge::Set(USVStringOrLong* contents, ExceptionState& exception_state) {
- if (contents) {
- if (contents->IsLong() && contents->GetAsLong() <= 0) {
- exception_state.ThrowTypeError("Badge contents should be > 0");
- return;
- }
- if (contents->IsUSVString() && contents->GetAsUSVString() == "") {
- exception_state.ThrowTypeError(
- "Badge contents cannot be the empty string");
- return;
- }
- }
- // TODO(estevenson): Add support for sending badge contents to the browser.
- // TODO(estevenson): Verify that contents is a single grapheme cluster.
- badge_service_->SetBadge();
+void Badge::SetInteger(uint64_t content) {
+ badge_service_->SetInteger(content);
+}
+
+void Badge::SetFlag() {
+ badge_service_->SetFlag();
}
void Badge::Clear() {
diff --git a/chromium/third_party/blink/renderer/modules/badging/badge.h b/chromium/third_party/blink/renderer/modules/badging/badge.h
index c6a742a659e..1c53cc324d5 100644
--- a/chromium/third_party/blink/renderer/modules/badging/badge.h
+++ b/chromium/third_party/blink/renderer/modules/badging/badge.h
@@ -14,7 +14,6 @@ namespace blink {
class ExceptionState;
class ExecutionContext;
class ScriptState;
-class USVStringOrLong;
class Badge final : public ScriptWrappable,
public Supplement<ExecutionContext> {
@@ -26,21 +25,21 @@ class Badge final : public ScriptWrappable,
static Badge* From(ExecutionContext*);
+ explicit Badge(ExecutionContext*);
~Badge() override;
// Badge IDL interface.
static void set(ScriptState*, ExceptionState&);
- static void set(ScriptState*, USVStringOrLong&, ExceptionState&);
+ static void set(ScriptState*, uint64_t content, ExceptionState&);
static void clear(ScriptState*);
- void Set(USVStringOrLong*, ExceptionState&);
+ void SetInteger(uint64_t content);
+ void SetFlag();
void Clear();
void Trace(blink::Visitor*) override;
private:
- explicit Badge(ExecutionContext*);
-
static Badge* BadgeFromState(ScriptState* script_state);
blink::mojom::blink::BadgeServicePtr badge_service_;
diff --git a/chromium/third_party/blink/renderer/modules/badging/badge.idl b/chromium/third_party/blink/renderer/modules/badging/experimental_badge.idl
index 3c5ec519b2d..35ccd0ae365 100644
--- a/chromium/third_party/blink/renderer/modules/badging/badge.idl
+++ b/chromium/third_party/blink/renderer/modules/badging/experimental_badge.idl
@@ -6,11 +6,12 @@
// https://github.com/WICG/badging/blob/master/explainer.md
[
- RuntimeEnabled=Badging,
+ OriginTrialEnabled=Badging,
// TODO(estevenson): Expose the Badge interface to Worker.
- Exposed=Window
-] interface Badge {
- [CallWith=ScriptState, RaisesException]
- static void set(optional (USVString or long) contents);
- [CallWith=ScriptState] static void clear();
+ Exposed=Window,
+ ImplementedAs=Badge
+] interface ExperimentalBadge {
+ [CallWith=ScriptState, RaisesException, MeasureAs=BadgeSet]
+ static void set(optional [EnforceRange] unsigned long long contents);
+ [CallWith=ScriptState, MeasureAs=BadgeClear] static void clear();
};
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc
index a5948bf7b64..aa084b61237 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc
@@ -7,6 +7,7 @@
#include "services/device/public/mojom/constants.mojom-blink.h"
#include "third_party/blink/public/platform/interface_provider.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -14,7 +15,7 @@ namespace blink {
BatteryDispatcher& BatteryDispatcher::Instance() {
DEFINE_STATIC_LOCAL(Persistent<BatteryDispatcher>, battery_dispatcher,
- (new BatteryDispatcher));
+ (MakeGarbageCollected<BatteryDispatcher>()));
return *battery_dispatcher;
}
@@ -45,8 +46,9 @@ void BatteryDispatcher::UpdateBatteryStatus(
void BatteryDispatcher::StartListening(LocalFrame* frame) {
DCHECK(!monitor_.is_bound());
- Platform::Current()->GetInterfaceProvider()->GetInterface(
- mojo::MakeRequest(&monitor_));
+ // See https://bit.ly/2S0zRAS for task types.
+ Platform::Current()->GetInterfaceProvider()->GetInterface(mojo::MakeRequest(
+ &monitor_, frame->GetTaskRunner(TaskType::kMiscPlatformAPI)));
QueryNextStatus();
}
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h
index 78c6592262c..165c3f82ae4 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h
@@ -22,13 +22,13 @@ class MODULES_EXPORT BatteryDispatcher final
public:
static BatteryDispatcher& Instance();
+ BatteryDispatcher();
+
const BatteryStatus* LatestData() const {
return has_latest_data_ ? &battery_status_ : nullptr;
}
private:
- BatteryDispatcher();
-
void QueryNextStatus();
void OnDidChange(device::mojom::blink::BatteryStatusPtr);
void UpdateBatteryStatus(const BatteryStatus&);
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc b/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc
index b47d0a6f5e5..e216d890ee8 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc
@@ -14,7 +14,8 @@
namespace blink {
BatteryManager* BatteryManager::Create(ExecutionContext* context) {
- BatteryManager* battery_manager = new BatteryManager(context);
+ BatteryManager* battery_manager =
+ MakeGarbageCollected<BatteryManager>(context);
battery_manager->PauseIfNeeded();
return battery_manager;
}
@@ -26,7 +27,7 @@ BatteryManager::BatteryManager(ExecutionContext* context)
ScriptPromise BatteryManager::StartRequest(ScriptState* script_state) {
if (!battery_property_) {
- battery_property_ = new BatteryProperty(
+ battery_property_ = MakeGarbageCollected<BatteryProperty>(
ExecutionContext::From(script_state), this, BatteryProperty::kReady);
// If the context is in a stopped state already, do not start updating.
@@ -95,12 +96,12 @@ bool BatteryManager::HasLastData() {
return BatteryDispatcher::Instance().LatestData();
}
-void BatteryManager::Pause() {
+void BatteryManager::ContextPaused(PauseState) {
has_event_listener_ = false;
StopUpdating();
}
-void BatteryManager::Unpause() {
+void BatteryManager::ContextUnpaused() {
has_event_listener_ = true;
StartUpdating();
}
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_manager.h b/chromium/third_party/blink/renderer/modules/battery/battery_manager.h
index 93b1acfaf6f..d062efb088a 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_manager.h
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_manager.h
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_property.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/frame/platform_event_controller.h"
#include "third_party/blink/renderer/modules/battery/battery_status.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -26,6 +26,8 @@ class BatteryManager final : public EventTargetWithInlineData,
public:
static BatteryManager* Create(ExecutionContext*);
+
+ explicit BatteryManager(ExecutionContext*);
~BatteryManager() override;
// Returns a promise object that will be resolved with this BatteryManager.
@@ -57,8 +59,8 @@ class BatteryManager final : public EventTargetWithInlineData,
bool HasLastData() override;
// PausableObject implementation.
- void Pause() override;
- void Unpause() override;
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
void ContextDestroyed(ExecutionContext*) override;
// ScriptWrappable implementation.
@@ -67,8 +69,6 @@ class BatteryManager final : public EventTargetWithInlineData,
void Trace(blink::Visitor*) override;
private:
- explicit BatteryManager(ExecutionContext*);
-
using BatteryProperty = ScriptPromiseProperty<Member<BatteryManager>,
Member<BatteryManager>,
Member<DOMException>>;
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_manager.idl b/chromium/third_party/blink/renderer/modules/battery/battery_manager.idl
index 412eb2dcde1..4343edf566f 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_manager.idl
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_manager.idl
@@ -7,10 +7,10 @@
ActiveScriptWrappable,
Exposed=Window
] interface BatteryManager : EventTarget {
- readonly attribute boolean charging;
- readonly attribute unrestricted double chargingTime;
- readonly attribute unrestricted double dischargingTime;
- readonly attribute double level;
+ [HighEntropy, Measure] readonly attribute boolean charging;
+ [HighEntropy, Measure] readonly attribute unrestricted double chargingTime;
+ [HighEntropy, Measure] readonly attribute unrestricted double dischargingTime;
+ [HighEntropy, Measure] readonly attribute double level;
attribute EventHandler onchargingchange;
attribute EventHandler onchargingtimechange;
diff --git a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl
index 579ee188799..ce0f3997f81 100644
--- a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl
+++ b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl
@@ -6,5 +6,5 @@
[
ImplementedAs=NavigatorBattery
] partial interface Navigator {
- [CallWith=ScriptState, MeasureAs=BatteryStatusGetBattery] Promise getBattery();
+ [CallWith=ScriptState, MeasureAs=BatteryStatusGetBattery] Promise<BatteryManager> getBattery();
};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/BUILD.gn b/chromium/third_party/blink/renderer/modules/bluetooth/BUILD.gn
index 86525ded88b..eb3b1c8033c 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/BUILD.gn
@@ -8,6 +8,8 @@ blink_modules_sources("bluetooth") {
sources = [
"bluetooth.cc",
"bluetooth.h",
+ "bluetooth_advertising_event.cc",
+ "bluetooth_advertising_event.h",
"bluetooth_attribute_instance_map.cc",
"bluetooth_attribute_instance_map.h",
"bluetooth_characteristic_properties.cc",
@@ -16,6 +18,10 @@ blink_modules_sources("bluetooth") {
"bluetooth_device.h",
"bluetooth_error.cc",
"bluetooth_error.h",
+ "bluetooth_le_scan.cc",
+ "bluetooth_le_scan.h",
+ "bluetooth_manufacturer_data_map.cc",
+ "bluetooth_manufacturer_data_map.h",
"bluetooth_remote_gatt_characteristic.cc",
"bluetooth_remote_gatt_characteristic.h",
"bluetooth_remote_gatt_descriptor.cc",
@@ -26,6 +32,8 @@ blink_modules_sources("bluetooth") {
"bluetooth_remote_gatt_service.h",
"bluetooth_remote_gatt_utils.cc",
"bluetooth_remote_gatt_utils.h",
+ "bluetooth_service_data_map.cc",
+ "bluetooth_service_data_map.h",
"bluetooth_uuid.cc",
"bluetooth_uuid.h",
"navigator_bluetooth.cc",
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS b/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS
index 0448c8c044e..9d049d44c15 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS
@@ -1,5 +1,4 @@
-jyasskin@chromium.org
-ortuno@chromium.org
+file://content/browser/bluetooth/OWNERS
# TEAM: web-bluetooth@chromium.org
# COMPONENT: Blink>Bluetooth
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/README.md b/chromium/third_party/blink/renderer/modules/bluetooth/README.md
index 6e6299cb079..7122fdaa8fe 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/README.md
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/README.md
@@ -36,9 +36,9 @@ Web Bluetooth implementation details are tested at several layers:
(as opposed to untrusted renderer process).
* `web_tests/bluetooth/*/*.html`
* `blink/tools/run_layout_tests.sh bluetooth`
- * Layout tests in `web_tests/bluetooth/` rely on
+ * Web tests in `web_tests/bluetooth/` rely on
fake Bluetooth implementation classes constructed in
- `content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider`.
+ `content/shell/browser/web_test/web_test_bluetooth_adapter_provider`.
These tests span JavaScript binding to the `device/bluetooth` platform
abstraction layer.
* `testing/clusterfuzz`
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
index 594f207e606..61d24e2d6b1 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
@@ -6,21 +6,26 @@
#include <memory>
#include <utility>
-#include "build/build_config.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/frame.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.h"
#include "third_party/blink/renderer/modules/bluetooth/bluetooth_device.h"
#include "third_party/blink/renderer/modules/bluetooth/bluetooth_error.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_options.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h"
#include "third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h"
#include "third_party/blink/renderer/modules/bluetooth/bluetooth_uuid.h"
#include "third_party/blink/renderer/modules/bluetooth/request_device_options.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -117,7 +122,7 @@ static void ConvertRequestDeviceOptions(
if (exception_state.HadException())
return;
- result->filters.value().push_back(std::move(canonicalized_filter));
+ result->filters->push_back(std::move(canonicalized_filter));
}
}
@@ -138,12 +143,13 @@ void Bluetooth::RequestDeviceCallback(
mojom::blink::WebBluetoothResult result,
mojom::blink::WebBluetoothDevicePtr device) {
if (!resolver->GetExecutionContext() ||
- resolver->GetExecutionContext()->IsContextDestroyed())
+ resolver->GetExecutionContext()->IsContextDestroyed()) {
return;
+ }
if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
- BluetoothDevice* bluetooth_device =
- GetBluetoothDeviceRepresentingDevice(std::move(device), resolver);
+ BluetoothDevice* bluetooth_device = GetBluetoothDeviceRepresentingDevice(
+ std::move(device), resolver->GetExecutionContext());
resolver->Resolve(bluetooth_device);
} else {
resolver->Reject(BluetoothError::CreateDOMException(result));
@@ -157,7 +163,8 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
ExecutionContext* context = ExecutionContext::From(script_state);
// Remind developers when they are using Web Bluetooth on unsupported platforms.
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
+ !defined(OS_WIN)
context->AddConsoleMessage(ConsoleMessage::Create(
kJSMessageSource, kInfoMessageLevel,
"Web Bluetooth is experimental on this platform. See "
@@ -170,7 +177,14 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
// If the algorithm is not allowed to show a popup, reject promise with a
// SecurityError and abort these steps.
auto& doc = *To<Document>(context);
- if (!LocalFrame::HasTransientUserActivation(doc.GetFrame())) {
+ auto* frame = doc.GetFrame();
+ if (!frame) {
+ return ScriptPromise::Reject(
+ script_state, V8ThrowException::CreateTypeError(
+ script_state->GetIsolate(), "Document not active"));
+ }
+
+ if (!LocalFrame::HasTransientUserActivation(frame)) {
return ScriptPromise::RejectWithDOMException(
script_state,
DOMException::Create(
@@ -179,16 +193,9 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
}
if (!service_) {
- LocalFrame* frame = doc.GetFrame();
- if (frame) {
- frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
- }
- }
-
- if (!service_) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- DOMException::Create(DOMExceptionCode::kNotSupportedError));
+ // See https://bit.ly/2S0zRAS for task types.
+ frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(
+ &service_, context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
}
// In order to convert the arguments from service names and aliases to just
@@ -213,20 +220,202 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
return promise;
}
+static void ConvertRequestLEScanOptions(
+ const BluetoothLEScanOptions* options,
+ mojom::blink::WebBluetoothRequestLEScanOptionsPtr& result,
+ ExceptionState& exception_state) {
+ if (!(options->hasFilters() ^ options->acceptAllAdvertisements())) {
+ exception_state.ThrowTypeError(
+ "Either 'filters' should be present or 'acceptAllAdvertisements' "
+ "should be true, but not both.");
+ return;
+ }
+
+ result->accept_all_advertisements = options->acceptAllAdvertisements();
+ result->keep_repeated_devices = options->keepRepeatedDevices();
+
+ if (options->hasFilters()) {
+ if (options->filters().IsEmpty()) {
+ exception_state.ThrowTypeError(
+ "'filters' member must be non-empty to find any devices.");
+ return;
+ }
+
+ result->filters.emplace();
+
+ for (const BluetoothLEScanFilterInit* filter : options->filters()) {
+ auto canonicalized_filter = mojom::blink::WebBluetoothLeScanFilter::New();
+
+ CanonicalizeFilter(filter, canonicalized_filter, exception_state);
+
+ if (exception_state.HadException())
+ return;
+
+ result->filters->push_back(std::move(canonicalized_filter));
+ }
+ }
+}
+
+void Bluetooth::RequestScanningCallback(
+ ScriptPromiseResolver* resolver,
+ mojo::BindingId id,
+ mojom::blink::RequestScanningStartResultPtr result) {
+ if (!resolver->GetExecutionContext() ||
+ resolver->GetExecutionContext()->IsContextDestroyed()) {
+ return;
+ }
+
+ if (result->is_error_result()) {
+ resolver->Reject(
+ BluetoothError::CreateDOMException(result->get_error_result()));
+ return;
+ }
+
+ auto* scan =
+ BluetoothLEScan::Create(id, this, std::move(result->get_options()));
+ resolver->Resolve(scan);
+}
+
+// https://webbluetoothcg.github.io/web-bluetooth/scanning.html#dom-bluetooth-requestlescan
+ScriptPromise Bluetooth::requestLEScan(ScriptState* script_state,
+ const BluetoothLEScanOptions* options,
+ ExceptionState& exception_state) {
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ DCHECK(context);
+
+ // Remind developers when they are using Web Bluetooth on unsupported
+ // platforms.
+ context->AddConsoleMessage(ConsoleMessage::Create(
+ kJSMessageSource, kInfoMessageLevel,
+ "Web Bluetooth Scanning is experimental on this platform. See "
+ "https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/"
+ "implementation-status.md"));
+
+ CHECK(context->IsSecureContext());
+
+ // If the algorithm is not allowed to show a popup, reject promise with a
+ // SecurityError and abort these steps.
+ auto& doc = *To<Document>(context);
+ auto* frame = doc.GetFrame();
+ if (!frame) {
+ return ScriptPromise::Reject(
+ script_state, V8ThrowException::CreateTypeError(
+ script_state->GetIsolate(), "Document not active"));
+ }
+
+ if (!LocalFrame::HasTransientUserActivation(frame)) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(
+ DOMExceptionCode::kSecurityError,
+ "Must be handling a user gesture to show a permission request."));
+ }
+
+ if (!service_) {
+ // See https://bit.ly/2S0zRAS for task types.
+ frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(
+ &service_, context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ }
+
+ auto scan_options = mojom::blink::WebBluetoothRequestLEScanOptions::New();
+ ConvertRequestLEScanOptions(options, scan_options, exception_state);
+
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ // Record the eTLD+1 of the frame using the API.
+ Platform::Current()->RecordRapporURL("Bluetooth.APIUsage.Origin", doc.Url());
+
+ // Subsequent steps are handled in the browser process.
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ mojom::blink::WebBluetoothScanClientAssociatedPtrInfo client;
+ mojo::BindingId id =
+ client_bindings_.AddBinding(this, mojo::MakeRequest(&client));
+
+ service_->RequestScanningStart(
+ std::move(client), std::move(scan_options),
+ WTF::Bind(&Bluetooth::RequestScanningCallback, WrapPersistent(this),
+ WrapPersistent(resolver), id));
+
+ return promise;
+}
+
+void Bluetooth::ScanEvent(mojom::blink::WebBluetoothScanResultPtr result) {
+ ExecutionContext* context = ContextLifecycleObserver::GetExecutionContext();
+ DCHECK(context);
+
+ BluetoothDevice* bluetooth_device =
+ GetBluetoothDeviceRepresentingDevice(std::move(result->device), context);
+
+ HeapVector<blink::StringOrUnsignedLong> uuids;
+ for (const String& uuid : result->uuids) {
+ StringOrUnsignedLong value;
+ value.SetString(uuid);
+ uuids.push_back(value);
+ }
+
+ auto* manufacturer_data = MakeGarbageCollected<BluetoothManufacturerDataMap>(
+ result->manufacturer_data);
+ auto* service_data =
+ MakeGarbageCollected<BluetoothServiceDataMap>(result->service_data);
+
+ base::Optional<int8_t> rssi;
+ if (result->rssi_is_set)
+ rssi = result->rssi;
+
+ base::Optional<int8_t> tx_power;
+ if (result->tx_power_is_set)
+ tx_power = result->tx_power;
+
+ base::Optional<int16_t> appearance;
+ if (result->appearance_is_set)
+ appearance = result->appearance;
+
+ auto* event = BluetoothAdvertisingEvent::Create(
+ event_type_names::kAdvertisementreceived, bluetooth_device, result->name,
+ uuids, appearance, tx_power, rssi, manufacturer_data, service_data);
+ DispatchEvent(*event);
+}
+
+void Bluetooth::CancelScan(mojo::BindingId id) {
+ client_bindings_.RemoveBinding(id);
+}
+
+const WTF::AtomicString& Bluetooth::InterfaceName() const {
+ return event_type_names::kAdvertisementreceived;
+}
+
+ExecutionContext* Bluetooth::GetExecutionContext() const {
+ return ContextLifecycleObserver::GetExecutionContext();
+}
+
+void Bluetooth::ContextDestroyed(ExecutionContext*) {
+ client_bindings_.CloseAllBindings();
+}
+
void Bluetooth::Trace(blink::Visitor* visitor) {
visitor->Trace(device_instance_map_);
- ScriptWrappable::Trace(visitor);
+ EventTargetWithInlineData::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
-Bluetooth::Bluetooth() = default;
+Bluetooth::Bluetooth(ExecutionContext* context)
+ : ContextLifecycleObserver(context) {}
+
+Bluetooth::~Bluetooth() {
+ DCHECK(client_bindings_.empty());
+}
BluetoothDevice* Bluetooth::GetBluetoothDeviceRepresentingDevice(
mojom::blink::WebBluetoothDevicePtr device_ptr,
- ScriptPromiseResolver* resolver) {
- WTF::String id = device_ptr->id;
+ ExecutionContext* context) {
+ String& id = device_ptr->id;
BluetoothDevice* device = device_instance_map_.at(id);
if (!device) {
- device = BluetoothDevice::Take(resolver, std::move(device_ptr), this);
+ device = MakeGarbageCollected<BluetoothDevice>(context,
+ std::move(device_ptr), this);
auto result = device_instance_map_.insert(id, device);
DCHECK(result.is_new_entry);
}
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.h
index 835ba811ac5..725f016967b 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.h
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.h
@@ -14,42 +14,75 @@
namespace blink {
+class BluetoothLEScanOptions;
class RequestDeviceOptions;
class ScriptPromise;
class ScriptState;
-class Bluetooth final : public ScriptWrappable {
+class Bluetooth final : public EventTargetWithInlineData,
+ public ContextLifecycleObserver,
+ public mojom::blink::WebBluetoothScanClient {
DEFINE_WRAPPERTYPEINFO();
+ USING_GARBAGE_COLLECTED_MIXIN(Bluetooth);
public:
- static Bluetooth* Create() { return new Bluetooth(); }
+ static Bluetooth* Create(ExecutionContext* context) {
+ return MakeGarbageCollected<Bluetooth>(context);
+ }
+
+ explicit Bluetooth(ExecutionContext*);
+ ~Bluetooth() override;
// IDL exposed interface:
ScriptPromise requestDevice(ScriptState*,
const RequestDeviceOptions*,
ExceptionState&);
+ ScriptPromise requestLEScan(ScriptState*,
+ const BluetoothLEScanOptions*,
+ ExceptionState&);
+
mojom::blink::WebBluetoothService* Service() { return service_.get(); }
+ // mojom::blink::WebBluetoothScanClient:
+ void ScanEvent(mojom::blink::WebBluetoothScanResultPtr result) override;
+
+ // EventTarget methods:
+ const AtomicString& InterfaceName() const override;
+ ExecutionContext* GetExecutionContext() const override;
+
// Interface required by Garbage Collection:
void Trace(blink::Visitor*) override;
- private:
- Bluetooth();
+ // ContextLifecycleObserver interface.
+ void ContextDestroyed(ExecutionContext*) override;
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(advertisementreceived,
+ kAdvertisementreceived);
+
+ void CancelScan(mojo::BindingId);
+
+ private:
BluetoothDevice* GetBluetoothDeviceRepresentingDevice(
mojom::blink::WebBluetoothDevicePtr,
- ScriptPromiseResolver*);
+ ExecutionContext*);
void RequestDeviceCallback(ScriptPromiseResolver*,
mojom::blink::WebBluetoothResult,
mojom::blink::WebBluetoothDevicePtr);
+ void RequestScanningCallback(ScriptPromiseResolver*,
+ mojo::BindingId id,
+ mojom::blink::RequestScanningStartResultPtr);
+
// Map of device ids to BluetoothDevice objects.
// Ensures only one BluetoothDevice instance represents each
// Bluetooth device inside a single global object.
HeapHashMap<String, Member<BluetoothDevice>> device_instance_map_;
+ mojo::AssociatedBindingSet<mojom::blink::WebBluetoothScanClient>
+ client_bindings_;
+
mojom::blink::WebBluetoothServicePtr service_;
};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.idl
index ade4e8ddc2f..3e2272c99e9 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.idl
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.idl
@@ -7,6 +7,12 @@
[
RuntimeEnabled=WebBluetooth,
SecureContext
-] interface Bluetooth {
+] interface Bluetooth : EventTarget {
[CallWith=ScriptState, RaisesException, MeasureAs=WebBluetoothRequestDevice] Promise<BluetoothDevice> requestDevice (optional RequestDeviceOptions options);
-};
+
+ // https://webbluetoothcg.github.io/web-bluetooth/scanning.html#dom-bluetooth-requestlescan
+ [RuntimeEnabled=WebBluetoothScanning, CallWith=ScriptState, RaisesException, MeasureAs=WebBluetoothRequestScan]
+ Promise<BluetoothLEScan> requestLEScan (optional BluetoothLEScanOptions options);
+
+ [RuntimeEnabled=WebBluetoothScanning] attribute EventHandler onadvertisementreceived;
+};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.cc
new file mode 100644
index 00000000000..e9c75dc38ee
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.cc
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.h"
+#include "third_party/blink/renderer/bindings/modules/v8/string_or_unsigned_long.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_device.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h"
+
+namespace blink {
+
+BluetoothAdvertisingEvent::BluetoothAdvertisingEvent(
+ const AtomicString& event_type,
+ const BluetoothAdvertisingEventInit* initializer)
+ : Event(event_type, initializer),
+ device_(initializer->device()),
+ name_(initializer->name()),
+ uuids_(initializer->uuids()),
+ appearance_(initializer->hasAppearance() ? initializer->appearance() : 0),
+ txPower_(initializer->hasTxPower() ? initializer->txPower() : 0),
+ rssi_(initializer->hasRssi() ? initializer->rssi() : 0),
+ manufacturer_data_map_(initializer->manufacturerData()),
+ service_data_map_(initializer->serviceData()) {}
+
+BluetoothAdvertisingEvent::BluetoothAdvertisingEvent(
+ const AtomicString& event_type,
+ BluetoothDevice* device,
+ const String& name,
+ const HeapVector<StringOrUnsignedLong>& uuids,
+ base::Optional<short> appearance,
+ base::Optional<int8_t> txPower,
+ base::Optional<int8_t> rssi,
+ BluetoothManufacturerDataMap* manufacturerData,
+ BluetoothServiceDataMap* serviceData)
+ : Event(event_type, Bubbles::kYes, Cancelable::kYes),
+ device_(std::move(device)),
+ name_(name),
+ uuids_(uuids),
+ appearance_(appearance),
+ txPower_(txPower),
+ rssi_(rssi),
+ manufacturer_data_map_(manufacturerData),
+ service_data_map_(serviceData) {}
+
+BluetoothAdvertisingEvent::~BluetoothAdvertisingEvent() {}
+
+void BluetoothAdvertisingEvent::Trace(blink::Visitor* visitor) {
+ visitor->Trace(device_);
+ visitor->Trace(uuids_);
+ visitor->Trace(manufacturer_data_map_);
+ visitor->Trace(service_data_map_);
+ Event::Trace(visitor);
+}
+
+const AtomicString& BluetoothAdvertisingEvent::InterfaceName() const {
+ return event_type_names::kAdvertisementreceived;
+}
+
+BluetoothDevice* BluetoothAdvertisingEvent::device() const {
+ return device_;
+};
+
+const String& BluetoothAdvertisingEvent::name() const {
+ return name_;
+}
+
+const HeapVector<StringOrUnsignedLong>& BluetoothAdvertisingEvent::uuids()
+ const {
+ return uuids_;
+}
+
+short BluetoothAdvertisingEvent::appearance(bool& is_null) const {
+ is_null = !appearance_.has_value();
+ return appearance_.value_or(0);
+}
+
+int8_t BluetoothAdvertisingEvent::txPower(bool& is_null) const {
+ is_null = !txPower_.has_value();
+ return txPower_.value_or(0);
+}
+
+int8_t BluetoothAdvertisingEvent::rssi(bool& is_null) const {
+ is_null = !rssi_.has_value();
+ return rssi_.value_or(0);
+}
+
+BluetoothManufacturerDataMap* BluetoothAdvertisingEvent::manufacturerData()
+ const {
+ return manufacturer_data_map_;
+}
+
+BluetoothServiceDataMap* BluetoothAdvertisingEvent::serviceData() const {
+ return service_data_map_;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.h
new file mode 100644
index 00000000000..6b904c63c7c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.h
@@ -0,0 +1,85 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_ADVERTISING_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_ADVERTISING_EVENT_H_
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+
+namespace blink {
+
+class BluetoothDevice;
+class BluetoothAdvertisingEventInit;
+class BluetoothManufacturerDataMap;
+class BluetoothServiceDataMap;
+class StringOrUnsignedLong;
+
+class BluetoothAdvertisingEvent final : public Event {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static BluetoothAdvertisingEvent* Create(
+ const AtomicString& event_type,
+ const BluetoothAdvertisingEventInit* initializer) {
+ return MakeGarbageCollected<BluetoothAdvertisingEvent>(event_type,
+ initializer);
+ }
+
+ static BluetoothAdvertisingEvent* Create(
+ const AtomicString& event_type,
+ BluetoothDevice* device,
+ const String& name,
+ const HeapVector<StringOrUnsignedLong>& uuids,
+ base::Optional<short> appearance,
+ base::Optional<int8_t> txPower,
+ base::Optional<int8_t> rssi,
+ BluetoothManufacturerDataMap* manufacturer_data_map,
+ BluetoothServiceDataMap* service_data_map) {
+ return MakeGarbageCollected<BluetoothAdvertisingEvent>(
+ event_type, device, name, uuids, appearance, txPower, rssi,
+ manufacturer_data_map, service_data_map);
+ }
+
+ BluetoothAdvertisingEvent(const AtomicString& event_type,
+ const BluetoothAdvertisingEventInit* initializer);
+
+ BluetoothAdvertisingEvent(const AtomicString& event_type,
+ BluetoothDevice* device,
+ const String& name,
+ const HeapVector<StringOrUnsignedLong>& uuids,
+ base::Optional<short> appearance,
+ base::Optional<int8_t> txPower,
+ base::Optional<int8_t> rssi,
+ BluetoothManufacturerDataMap* manufacturer_data_map,
+ BluetoothServiceDataMap* service_data_map);
+
+ ~BluetoothAdvertisingEvent() override;
+
+ void Trace(blink::Visitor*) override;
+
+ const AtomicString& InterfaceName() const override;
+
+ BluetoothDevice* device() const;
+ const String& name() const;
+ const HeapVector<StringOrUnsignedLong>& uuids() const;
+ short appearance(bool& is_null) const;
+ int8_t txPower(bool& is_null) const;
+ int8_t rssi(bool& is_null) const;
+ BluetoothManufacturerDataMap* manufacturerData() const;
+ BluetoothServiceDataMap* serviceData() const;
+
+ private:
+ Member<BluetoothDevice> device_;
+ String name_;
+ HeapVector<StringOrUnsignedLong> uuids_;
+ base::Optional<short> appearance_;
+ base::Optional<int8_t> txPower_;
+ base::Optional<int8_t> rssi_;
+ const Member<BluetoothManufacturerDataMap> manufacturer_data_map_;
+ const Member<BluetoothServiceDataMap> service_data_map_;
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.idl
new file mode 100644
index 00000000000..1cd29942fd1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event.idl
@@ -0,0 +1,20 @@
+// 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.
+
+// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingevent
+
+[
+ RuntimeEnabled=WebBluetoothScanning,
+ SecureContext
+] interface BluetoothAdvertisingEvent : Event {
+
+ readonly attribute BluetoothDevice device;
+ readonly attribute FrozenArray<UUID> uuids;
+ readonly attribute DOMString? name;
+ readonly attribute unsigned short? appearance;
+ readonly attribute byte? txPower;
+ readonly attribute byte? rssi;
+ readonly attribute BluetoothManufacturerDataMap manufacturerData;
+ readonly attribute BluetoothServiceDataMap serviceData;
+};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.idl
new file mode 100644
index 00000000000..0cb58569b0b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_advertising_event_init.idl
@@ -0,0 +1,16 @@
+// 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.
+
+// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingevent
+
+dictionary BluetoothAdvertisingEventInit : EventInit {
+ required BluetoothDevice device;
+ sequence<(DOMString or unsigned long)> uuids;
+ DOMString name;
+ unsigned short appearance;
+ byte txPower;
+ byte rssi;
+ BluetoothManufacturerDataMap manufacturerData;
+ BluetoothServiceDataMap serviceData;
+};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_attribute_instance_map.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_attribute_instance_map.cc
index de0aa052473..76c96872b96 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_attribute_instance_map.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_attribute_instance_map.cc
@@ -25,9 +25,9 @@ BluetoothAttributeInstanceMap::GetOrCreateRemoteGATTService(
service_id_to_object_.at(service_instance_id);
if (!service) {
- service =
- new BluetoothRemoteGATTService(std::move(remote_gatt_service),
- is_primary, device_instance_id, device_);
+ service = MakeGarbageCollected<BluetoothRemoteGATTService>(
+ std::move(remote_gatt_service), is_primary, device_instance_id,
+ device_);
service_id_to_object_.insert(service_instance_id, service);
}
@@ -74,8 +74,8 @@ BluetoothAttributeInstanceMap::GetOrCreateBluetoothRemoteGATTDescriptor(
if (result)
return result;
- result =
- new BluetoothRemoteGATTDescriptor(std::move(descriptor), characteristic);
+ result = MakeGarbageCollected<BluetoothRemoteGATTDescriptor>(
+ std::move(descriptor), characteristic);
descriptor_id_to_object_.insert(instance_id, result);
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.cc
index 98b50684a87..041806dc8e7 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.cc
@@ -8,7 +8,7 @@ namespace blink {
BluetoothCharacteristicProperties* BluetoothCharacteristicProperties::Create(
uint32_t properties) {
- return new BluetoothCharacteristicProperties(properties);
+ return MakeGarbageCollected<BluetoothCharacteristicProperties>(properties);
}
bool BluetoothCharacteristicProperties::broadcast() const {
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.h
index 43ccaba4752..7a3d3da677e 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.h
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_characteristic_properties.h
@@ -18,6 +18,8 @@ class BluetoothCharacteristicProperties final : public ScriptWrappable {
public:
static BluetoothCharacteristicProperties* Create(uint32_t properties);
+ explicit BluetoothCharacteristicProperties(uint32_t properties);
+
// IDL exposed interface:
bool broadcast() const;
bool read() const;
@@ -30,8 +32,6 @@ class BluetoothCharacteristicProperties final : public ScriptWrappable {
bool writableAuxiliaries() const;
private:
- explicit BluetoothCharacteristicProperties(uint32_t properties);
-
enum Property {
kNone = 0,
kBroadcast = 1 << 0,
@@ -51,4 +51,4 @@ class BluetoothCharacteristicProperties final : public ScriptWrappable {
} // namespace blink
-#endif // GamepadButton_h
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_CHARACTERISTIC_PROPERTIES_H_
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc
index dbc56440ff9..d69d3a29ded 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc
@@ -24,20 +24,12 @@ BluetoothDevice::BluetoothDevice(ExecutionContext* context,
mojom::blink::WebBluetoothDevicePtr device,
Bluetooth* bluetooth)
: ContextLifecycleObserver(context),
- attribute_instance_map_(new BluetoothAttributeInstanceMap(this)),
+ attribute_instance_map_(
+ MakeGarbageCollected<BluetoothAttributeInstanceMap>(this)),
device_(std::move(device)),
gatt_(BluetoothRemoteGATTServer::Create(context, this)),
bluetooth_(bluetooth) {}
-// static
-BluetoothDevice* BluetoothDevice::Take(
- ScriptPromiseResolver* resolver,
- mojom::blink::WebBluetoothDevicePtr device,
- Bluetooth* bluetooth) {
- return new BluetoothDevice(resolver->GetExecutionContext(), std::move(device),
- bluetooth);
-}
-
BluetoothRemoteGATTService* BluetoothDevice::GetOrCreateRemoteGATTService(
mojom::blink::WebBluetoothRemoteGATTServicePtr service,
bool is_primary,
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.h
index e0ad24c33bd..41d8b8de776 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.h
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.h
@@ -22,7 +22,6 @@ class BluetoothRemoteGATTCharacteristic;
class BluetoothRemoteGATTDescriptor;
class BluetoothRemoteGATTServer;
class BluetoothRemoteGATTService;
-class ScriptPromiseResolver;
// BluetoothDevice represents a physical bluetooth device in the DOM. See IDL.
//
@@ -40,11 +39,6 @@ class BluetoothDevice final : public EventTargetWithInlineData,
mojom::blink::WebBluetoothDevicePtr,
Bluetooth*);
- // Interface required by CallbackPromiseAdapter:
- static BluetoothDevice* Take(ScriptPromiseResolver*,
- mojom::blink::WebBluetoothDevicePtr,
- Bluetooth*);
-
BluetoothRemoteGATTService* GetOrCreateRemoteGATTService(
mojom::blink::WebBluetoothRemoteGATTServicePtr,
bool is_primary,
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.cc
new file mode 100644
index 00000000000..8b6bfc97fa4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.cc
@@ -0,0 +1,80 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.h"
+
+namespace blink {
+
+BluetoothLEScan* BluetoothLEScan::Create(
+ mojo::BindingId id,
+ Bluetooth* bluetooth,
+ mojom::blink::WebBluetoothRequestLEScanOptionsPtr options) {
+ return MakeGarbageCollected<BluetoothLEScan>(id, bluetooth,
+ std::move(options));
+}
+
+BluetoothLEScan::BluetoothLEScan(
+ mojo::BindingId id,
+ Bluetooth* bluetooth,
+ mojom::blink::WebBluetoothRequestLEScanOptionsPtr options)
+ : id_(id),
+ bluetooth_(bluetooth),
+ keep_repeated_devices_(options ? options->keep_repeated_devices : false),
+ accept_all_advertisements_(options ? options->accept_all_advertisements
+ : false) {
+ DCHECK(options->filters.has_value() ^ options->accept_all_advertisements);
+
+ if (options && options->filters.has_value()) {
+ for (const auto& filter : options->filters.value()) {
+ auto* filter_init = BluetoothLEScanFilterInit::Create();
+
+ if (filter->name)
+ filter_init->setName(filter->name);
+
+ if (filter->name_prefix)
+ filter_init->setNamePrefix(filter->name_prefix);
+
+ if (filter->services && filter->services.has_value()) {
+ HeapVector<blink::StringOrUnsignedLong> services;
+ for (const auto& uuid : filter->services.value()) {
+ blink::StringOrUnsignedLong uuid_string;
+ uuid_string.SetString(uuid);
+ services.push_back(uuid_string);
+ }
+ filter_init->setServices(services);
+ }
+ filters_.push_back(std::move(filter_init));
+ }
+ }
+}
+
+const HeapVector<Member<BluetoothLEScanFilterInit>>& BluetoothLEScan::filters()
+ const {
+ return filters_;
+}
+
+bool BluetoothLEScan::keepRepeatedDevices() const {
+ return keep_repeated_devices_;
+}
+bool BluetoothLEScan::acceptAllAdvertisements() const {
+ return accept_all_advertisements_;
+}
+
+bool BluetoothLEScan::active() const {
+ return is_active_;
+}
+
+bool BluetoothLEScan::stop() {
+ bluetooth_->CancelScan(id_);
+ is_active_ = false;
+ return true;
+}
+
+void BluetoothLEScan::Trace(blink::Visitor* visitor) {
+ visitor->Trace(filters_);
+ visitor->Trace(bluetooth_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.h
new file mode 100644
index 00000000000..881007c59b3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_LE_SCAN_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_LE_SCAN_H_
+
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_filter_init.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class BluetoothLEScan final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static BluetoothLEScan* Create(
+ mojo::BindingId,
+ Bluetooth*,
+ mojom::blink::WebBluetoothRequestLEScanOptionsPtr);
+
+ BluetoothLEScan(mojo::BindingId,
+ Bluetooth*,
+ mojom::blink::WebBluetoothRequestLEScanOptionsPtr);
+
+ // IDL exposed interface:
+ const HeapVector<Member<BluetoothLEScanFilterInit>>& filters() const;
+ bool keepRepeatedDevices() const;
+ bool acceptAllAdvertisements() const;
+ bool active() const;
+ bool stop();
+
+ // Interface required by garbage collection.
+ void Trace(blink::Visitor*) override;
+
+ private:
+ mojo::BindingId id_;
+ HeapVector<Member<BluetoothLEScanFilterInit>> filters_;
+ Member<Bluetooth> bluetooth_;
+ const bool keep_repeated_devices_;
+ const bool accept_all_advertisements_;
+ bool is_active_ = true;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_LE_SCAN_H_
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.idl
new file mode 100644
index 00000000000..7ffb1c346d7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan.idl
@@ -0,0 +1,16 @@
+// 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.
+
+// https://webbluetoothcg.github.io/web-bluetooth/scanning.html#bluetoothlescan
+
+[
+ RuntimeEnabled=WebBluetoothScanning,
+ SecureContext
+] interface BluetoothLEScan {
+ readonly attribute FrozenArray<BluetoothLEScanFilter> filters;
+ readonly attribute boolean keepRepeatedDevices;
+ readonly attribute boolean acceptAllAdvertisements;
+ readonly attribute boolean active;
+ void stop();
+};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_options.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_options.idl
new file mode 100644
index 00000000000..8d6c500a6b0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_le_scan_options.idl
@@ -0,0 +1,11 @@
+// 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.
+
+// https://webbluetoothcg.github.io/web-bluetooth/scanning.html#dictdef-bluetoothlescanoptions
+
+dictionary BluetoothLEScanOptions {
+ sequence<BluetoothLEScanFilterInit> filters;
+ boolean keepRepeatedDevices = false;
+ boolean acceptAllAdvertisements = false;
+};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.cc
new file mode 100644
index 00000000000..e4af2f6c781
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.cc
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h"
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_utils.h"
+
+namespace blink {
+
+class BluetoothManufacturerDataMapIterationSource final
+ : public PairIterable<unsigned short,
+ Member<DOMDataView>>::IterationSource {
+ public:
+ explicit BluetoothManufacturerDataMapIterationSource(
+ const BluetoothManufacturerDataMap& map)
+ : map_(map), iterator_(map_->Map().begin()) {}
+
+ bool Next(ScriptState* script_state,
+ unsigned short& map_key,
+ Member<DOMDataView>& map_value,
+ ExceptionState&) override {
+ if (iterator_ == map_->Map().end())
+ return false;
+ map_key = iterator_->key;
+ map_value =
+ BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(iterator_->value);
+ ++iterator_;
+ return true;
+ }
+
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(map_);
+ PairIterable<unsigned short, Member<DOMDataView>>::IterationSource::Trace(
+ visitor);
+ }
+
+ private:
+ // Needs to be kept alive while we're iterating over it.
+ const Member<const BluetoothManufacturerDataMap> map_;
+ BluetoothManufacturerDataMap::MapType::const_iterator iterator_;
+};
+
+BluetoothManufacturerDataMap::BluetoothManufacturerDataMap(
+ const BluetoothManufacturerDataMap::MapType& map)
+ : parameter_map_(map) {}
+
+BluetoothManufacturerDataMap::~BluetoothManufacturerDataMap() {}
+
+PairIterable<unsigned short, Member<DOMDataView>>::IterationSource*
+BluetoothManufacturerDataMap::StartIteration(ScriptState*, ExceptionState&) {
+ return MakeGarbageCollected<BluetoothManufacturerDataMapIterationSource>(
+ *this);
+}
+
+bool BluetoothManufacturerDataMap::GetMapEntry(ScriptState*,
+ const unsigned short& key,
+ Member<DOMDataView>& value,
+ ExceptionState&) {
+ auto it = parameter_map_.find(key);
+ if (it == parameter_map_.end())
+ return false;
+
+ DOMDataView* dom_data_view =
+ BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(it->value);
+
+ value = dom_data_view;
+ return true;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h
new file mode 100644
index 00000000000..a4eeeaf83ea
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_MANUFACTURER_DATA_MAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_MANUFACTURER_DATA_MAP_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/maplike.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+
+namespace blink {
+
+class BluetoothManufacturerDataMap final
+ : public ScriptWrappable,
+ public Maplike<unsigned short, Member<DOMDataView>> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ using MapType = HashMap<unsigned short, WTF::Vector<unsigned char>>;
+
+ explicit BluetoothManufacturerDataMap(const MapType&);
+
+ ~BluetoothManufacturerDataMap() override;
+
+ const MapType& Map() const { return parameter_map_; }
+
+ // IDL attributes / methods
+ uint32_t size() const { return parameter_map_.size(); }
+
+ private:
+ PairIterable<unsigned short, Member<DOMDataView>>::IterationSource*
+ StartIteration(ScriptState*, ExceptionState&) override;
+ bool GetMapEntry(ScriptState*,
+ const unsigned short& key,
+ Member<DOMDataView>&,
+ ExceptionState&) override;
+
+ const MapType parameter_map_;
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.idl
new file mode 100644
index 00000000000..78aaa1c03ff
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_manufacturer_data_map.idl
@@ -0,0 +1,10 @@
+// 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.
+
+// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingevent
+
+[RuntimeEnabled=WebBluetoothScanning, SecureContext]
+interface BluetoothManufacturerDataMap {
+ readonly maplike<unsigned short, DataView>;
+};
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc
index 5a771115df3..f256bd69922 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -43,7 +43,7 @@ BluetoothRemoteGATTCharacteristic* BluetoothRemoteGATTCharacteristic::Create(
mojom::blink::WebBluetoothRemoteGATTCharacteristicPtr characteristic,
BluetoothRemoteGATTService* service,
BluetoothDevice* device) {
- return new BluetoothRemoteGATTCharacteristic(
+ return MakeGarbageCollected<BluetoothRemoteGATTCharacteristic>(
context, std::move(characteristic), service, device);
}
@@ -259,7 +259,10 @@ ScriptPromise BluetoothRemoteGATTCharacteristic::startNotifications(
device_->GetBluetooth()->Service();
mojom::blink::WebBluetoothCharacteristicClientAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
- client_bindings_.AddBinding(this, std::move(request));
+ // See https://bit.ly/2S0zRAS for task types.
+ client_bindings_.AddBinding(
+ this, std::move(request),
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
service->RemoteCharacteristicStartNotifications(
characteristic_->instance_id, std::move(ptr_info),
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.cc
index 6e37ea020ec..af956437f66 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.cc
@@ -25,7 +25,8 @@ BluetoothRemoteGATTDescriptor* BluetoothRemoteGATTDescriptor::Create(
BluetoothRemoteGATTCharacteristic* characteristic) {
BluetoothRemoteGATTDescriptor* result =
- new BluetoothRemoteGATTDescriptor(std::move(descriptor), characteristic);
+ MakeGarbageCollected<BluetoothRemoteGATTDescriptor>(std::move(descriptor),
+ characteristic);
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_server.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_server.cc
index e371e82132d..33b727f03ad 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_server.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_server.cc
@@ -27,7 +27,7 @@ BluetoothRemoteGATTServer::BluetoothRemoteGATTServer(ExecutionContext* context,
BluetoothRemoteGATTServer* BluetoothRemoteGATTServer::Create(
ExecutionContext* context,
BluetoothDevice* device) {
- return new BluetoothRemoteGATTServer(context, device);
+ return MakeGarbageCollected<BluetoothRemoteGATTServer>(context, device);
}
void BluetoothRemoteGATTServer::ContextDestroyed(ExecutionContext*) {
@@ -113,8 +113,11 @@ ScriptPromise BluetoothRemoteGATTServer::connect(ScriptState* script_state) {
mojom::blink::WebBluetoothService* service =
device_->GetBluetooth()->Service();
mojom::blink::WebBluetoothServerClientAssociatedPtrInfo ptr_info;
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
auto request = mojo::MakeRequest(&ptr_info);
- client_bindings_.AddBinding(this, std::move(request));
+ client_bindings_.AddBinding(this, std::move(request), std::move(task_runner));
service->RemoteServerConnect(
device_->id(), std::move(ptr_info),
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.cc
new file mode 100644
index 00000000000..e0c3feaef68
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.cc
@@ -0,0 +1,68 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h"
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
+#include "third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_utils.h"
+
+namespace blink {
+
+class BluetoothServiceDataMapIterationSource final
+ : public PairIterable<String, Member<DOMDataView>>::IterationSource {
+ public:
+ BluetoothServiceDataMapIterationSource(const BluetoothServiceDataMap& map)
+ : map_(map), iterator_(map_->Map().begin()) {}
+
+ bool Next(ScriptState* script_state,
+ String& map_key,
+ Member<DOMDataView>& map_value,
+ ExceptionState&) override {
+ if (iterator_ == map_->Map().end())
+ return false;
+ map_key = iterator_->key;
+ map_value =
+ BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(iterator_->value);
+ ++iterator_;
+ return true;
+ }
+
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(map_);
+ PairIterable<String, Member<DOMDataView>>::IterationSource::Trace(visitor);
+ }
+
+ private:
+ // Needs to be kept alive while we're iterating over it.
+ const Member<const BluetoothServiceDataMap> map_;
+ BluetoothServiceDataMap::MapType::const_iterator iterator_;
+};
+
+BluetoothServiceDataMap::BluetoothServiceDataMap(
+ const BluetoothServiceDataMap::MapType& map)
+ : parameter_map_(map) {}
+
+BluetoothServiceDataMap::~BluetoothServiceDataMap() {}
+
+PairIterable<String, Member<DOMDataView>>::IterationSource*
+BluetoothServiceDataMap::StartIteration(ScriptState*, ExceptionState&) {
+ return MakeGarbageCollected<BluetoothServiceDataMapIterationSource>(*this);
+}
+
+bool BluetoothServiceDataMap::GetMapEntry(ScriptState*,
+ const String& key,
+ Member<DOMDataView>& value,
+ ExceptionState&) {
+ auto it = parameter_map_.find(key);
+ if (it == parameter_map_.end())
+ return false;
+
+ DOMDataView* dom_data_view =
+ BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(it->value);
+
+ value = dom_data_view;
+ return true;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h
new file mode 100644
index 00000000000..42d2c5dab4f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_SERVICE_DATA_MAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_BLUETOOTH_BLUETOOTH_SERVICE_DATA_MAP_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/maplike.h"
+#include "third_party/blink/renderer/bindings/modules/v8/string_or_unsigned_long.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+
+namespace blink {
+
+class BluetoothServiceDataMap final
+ : public ScriptWrappable,
+ public Maplike<String, Member<DOMDataView>> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ using MapType = HashMap<String, WTF::Vector<uint8_t>>;
+
+ explicit BluetoothServiceDataMap(const MapType&);
+
+ ~BluetoothServiceDataMap() override;
+
+ const MapType& Map() const { return parameter_map_; }
+
+ // IDL attributes / methods
+ uint32_t size() const { return parameter_map_.size(); }
+
+ private:
+ PairIterable<String, Member<DOMDataView>>::IterationSource* StartIteration(
+ ScriptState*,
+ ExceptionState&) override;
+ bool GetMapEntry(ScriptState*,
+ const String& key,
+ Member<DOMDataView>&,
+ ExceptionState&) override;
+
+ const MapType parameter_map_;
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.idl
new file mode 100644
index 00000000000..6be92440176
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_service_data_map.idl
@@ -0,0 +1,10 @@
+// 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.
+
+// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingevent
+
+[RuntimeEnabled=WebBluetoothScanning, SecureContext]
+interface BluetoothServiceDataMap {
+ readonly maplike<UUID, DataView>;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/navigator_bluetooth.cc b/chromium/third_party/blink/renderer/modules/bluetooth/navigator_bluetooth.cc
index 207382be36d..74a31c53179 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/navigator_bluetooth.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/navigator_bluetooth.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/bluetooth/navigator_bluetooth.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/modules/bluetooth/bluetooth.h"
@@ -24,8 +26,14 @@ Bluetooth* NavigatorBluetooth::bluetooth(Navigator& navigator) {
}
Bluetooth* NavigatorBluetooth::bluetooth() {
- if (!bluetooth_)
- bluetooth_ = Bluetooth::Create();
+ if (bluetooth_)
+ return bluetooth_.Get();
+
+ if (!GetSupplementable()->GetFrame())
+ return nullptr;
+
+ bluetooth_ = Bluetooth::Create(
+ GetSupplementable()->GetFrame()->GetDocument()->GetExecutionContext());
return bluetooth_.Get();
}
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/README.md b/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/README.md
index 9f1f483cc2f..cf5f5d9b5dd 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/README.md
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/README.md
@@ -1,6 +1,6 @@
# Web Bluetooth Fuzzer
-The Web Bluetooth Fuzzer generates test pages that can be run as layout tests.
+The Web Bluetooth Fuzzer generates test pages that can be run as web tests.
These pages consist of a sequence of calls to the [Web Bluetooth API](../..)
whose purpose is to stress test the API's implementation and catch any bugs
or regressions.
@@ -17,7 +17,7 @@ To generate test pages the fuzzer performs the following steps:
collection.
2. Replace the template parameters with random values.
-These generated test pages can then be run as Layout Tests in content_shell.
+These generated test pages can then be run as web tests in content_shell.
## ClusterFuzz
This fuzzer is designed to be run by ClusterFuzz and therefore takes three
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/fuzz_main_run.py b/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/fuzz_main_run.py
index 500f52c721e..d4f2f055f38 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/fuzz_main_run.py
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/fuzz_main_run.py
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Script to generate Web Bluetooth Layout Tests that can be run in ClusterFuzz.
+"""Script to generate Web Bluetooth web tests that can be run in ClusterFuzz.
This script uses templates in the templates/ directory to generate html files
-that can be run as Layout Tests. The script reads a template, includes files
-necessary to run as a layout test, fuzzes its parameters and saves the result in
+that can be run as web tests. The script reads a template, includes files
+necessary to run as a web test, fuzzes its parameters and saves the result in
a new file in the directory specified when running the script.
"""
@@ -58,10 +58,10 @@ def _GetArguments():
def FuzzTemplate(template_path, resources_path):
- """Uses a template to return a test case that can be run as a layout test.
+ """Uses a template to return a test case that can be run as a web test.
This functions reads the template in |template_path|, injects the necessary
- js files to run as a layout test and fuzzes the template's parameters to
+ js files to run as a web test and fuzzes the template's parameters to
generate a test case.
Args:
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/setup.py b/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/setup.py
index 3bd4809c8a1..3805fbc026b 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/setup.py
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/setup.py
@@ -21,7 +21,7 @@ import sys
# src path from this file's path.
SRC_PATH = os.path.join(
os.pardir, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir)
-LAYOUT_TESTS_RESOURCES_PATH = os.path.join(
+WEB_TESTS_RESOURCES_PATH = os.path.join(
SRC_PATH, 'third_party', 'blink', 'web_tests', 'resources')
WEB_PLATFORM_TESTS_RESOURCES_PATH = os.path.join(
SRC_PATH, 'third_party', 'blink', 'web_tests', 'external', 'wpt',
@@ -29,8 +29,8 @@ WEB_PLATFORM_TESTS_RESOURCES_PATH = os.path.join(
COMMON_FUZZER_RESOURCES_PATH = os.path.join(
SRC_PATH, 'testing', 'clusterfuzz', 'common')
RESOURCES = [
- os.path.join(LAYOUT_TESTS_RESOURCES_PATH, 'testharness.js'),
- os.path.join(LAYOUT_TESTS_RESOURCES_PATH, 'testharnessreport.js'),
+ os.path.join(WEB_TESTS_RESOURCES_PATH, 'testharness.js'),
+ os.path.join(WEB_TESTS_RESOURCES_PATH, 'testharnessreport.js'),
os.path.join(WEB_PLATFORM_TESTS_RESOURCES_PATH, 'bluetooth-helpers.js'),
os.path.join(COMMON_FUZZER_RESOURCES_PATH, 'fuzzy_types.py'),
os.path.join(COMMON_FUZZER_RESOURCES_PATH, 'utils.py'),
diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
index 6c666280f97..582a091f27b 100644
--- a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
+++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
@@ -44,7 +44,7 @@ BroadcastChannel* BroadcastChannel::Create(ExecutionContext* execution_context,
"Can't create BroadcastChannel in an opaque origin");
return nullptr;
}
- return new BroadcastChannel(execution_context, name);
+ return MakeGarbageCollected<BroadcastChannel>(execution_context, name);
}
BroadcastChannel::~BroadcastChannel() = default;
diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h
index 052a1f063c5..e399256c184 100644
--- a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h
+++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h
@@ -29,6 +29,8 @@ class BroadcastChannel final : public EventTargetWithInlineData,
static BroadcastChannel* Create(ExecutionContext*,
const String& name,
ExceptionState&);
+
+ BroadcastChannel(ExecutionContext*, const String& name);
~BroadcastChannel() override;
void Dispose();
@@ -54,8 +56,6 @@ class BroadcastChannel final : public EventTargetWithInlineData,
void Trace(blink::Visitor*) override;
private:
- BroadcastChannel(ExecutionContext*, const String& name);
-
// mojom::blink::BroadcastChannelClient:
void OnMessage(BlinkCloneableMessage) override;
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS b/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS
index 9ba85db50d7..f8dfe14fe70 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS
@@ -1,11 +1,4 @@
-kinuko@chromium.org
-jsbell@chromium.org
-dominicc@chromium.org
-falken@chromium.org
-horo@chromium.org
-nhiroki@chromium.org
-jkarlin@chromium.org
-pwnall@chromium.org
+file://content/browser/cache_storage/OWNERS
# TEAM: storage-dev@chromium.org
# COMPONENT: Blink>Storage>CacheStorage
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
index 95e252a1639..8f8750fc83d 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -6,10 +6,13 @@
#include <memory>
#include <utility>
+#include "base/feature_list.h"
#include "base/optional.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "third_party/blink/public/common/cache_storage/cache_storage_utils.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
@@ -28,6 +31,7 @@
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/modules/cache_storage/cache_storage.h"
#include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -38,6 +42,7 @@
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h"
namespace blink {
@@ -61,21 +66,40 @@ bool VaryHeaderContainsAsterisk(const Response* response) {
return false;
}
-bool ShouldGenerateV8CodeCache(ScriptState* script_state,
- const Response* response) {
+enum class CodeCacheGenerateTiming {
+ kDontGenerate,
+ kGenerateNow,
+ kGenerateWhenIdle,
+};
+
+CodeCacheGenerateTiming ShouldGenerateV8CodeCache(ScriptState* script_state,
+ const Response* response) {
+ EagerCodeCacheStrategy strategy =
+ ServiceWorkerUtils::GetEagerCodeCacheStrategy();
+ if (strategy == EagerCodeCacheStrategy::kDontGenerate)
+ return CodeCacheGenerateTiming::kDontGenerate;
+
ExecutionContext* context = ExecutionContext::From(script_state);
auto* global_scope = DynamicTo<ServiceWorkerGlobalScope>(context);
if (!global_scope)
- return false;
- if (!global_scope->IsInstalling())
- return false;
+ return CodeCacheGenerateTiming::kDontGenerate;
+
if (!MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
response->InternalMIMEType())) {
- return false;
+ return CodeCacheGenerateTiming::kDontGenerate;
}
+
if (!response->InternalBodyBuffer())
- return false;
- return true;
+ return CodeCacheGenerateTiming::kDontGenerate;
+
+ if (global_scope->IsInstalling())
+ return CodeCacheGenerateTiming::kGenerateNow;
+
+ if (strategy == EagerCodeCacheStrategy::kOnIdleTask) {
+ return CodeCacheGenerateTiming::kGenerateWhenIdle;
+ }
+
+ return CodeCacheGenerateTiming::kDontGenerate;
}
} // namespace
@@ -93,11 +117,24 @@ class Cache::FetchResolvedForAdd final : public ScriptFunction {
const String& method_name,
const HeapVector<Member<Request>>& requests,
const ExceptionState& exception_state) {
- FetchResolvedForAdd* self = new FetchResolvedForAdd(
+ FetchResolvedForAdd* self = MakeGarbageCollected<FetchResolvedForAdd>(
script_state, cache, method_name, requests, exception_state);
return self->BindToV8Function();
}
+ FetchResolvedForAdd(ScriptState* script_state,
+ Cache* cache,
+ const String& method_name,
+ const HeapVector<Member<Request>>& requests,
+ const ExceptionState& exception_state)
+ : ScriptFunction(script_state),
+ cache_(cache),
+ method_name_(method_name),
+ requests_(requests),
+ context_type_(exception_state.Context()),
+ property_name_(exception_state.PropertyName()),
+ interface_name_(exception_state.InterfaceName()) {}
+
ScriptValue Call(ScriptValue value) override {
ExceptionState exception_state(GetScriptState()->GetIsolate(),
context_type_, property_name_,
@@ -143,19 +180,6 @@ class Cache::FetchResolvedForAdd final : public ScriptFunction {
}
private:
- FetchResolvedForAdd(ScriptState* script_state,
- Cache* cache,
- const String& method_name,
- const HeapVector<Member<Request>>& requests,
- const ExceptionState& exception_state)
- : ScriptFunction(script_state),
- cache_(cache),
- method_name_(method_name),
- requests_(requests),
- context_type_(exception_state.Context()),
- property_name_(exception_state.PropertyName()),
- interface_name_(exception_state.InterfaceName()) {}
-
Member<Cache> cache_;
const String method_name_;
HeapVector<Member<Request>> requests_;
@@ -362,20 +386,30 @@ class Cache::CodeCacheHandleCallbackForPut final
public:
CodeCacheHandleCallbackForPut(ScriptState* script_state,
+ Cache* cache,
wtf_size_t index,
BarrierCallbackForPut* barrier_callback,
Request* request,
- Response* response)
+ Response* response,
+ CodeCacheGenerateTiming timing)
: script_state_(script_state),
+ cache_(cache),
index_(index),
barrier_callback_(barrier_callback),
- mime_type_(response->InternalMIMEType()) {
+ mime_type_(response->InternalMIMEType()),
+ timing_(timing) {
fetch_api_request_ = request->CreateFetchAPIRequest();
fetch_api_response_ = response->PopulateFetchAPIResponse();
+ url_ = fetch_api_request_->url;
+ opaque_mode_ = fetch_api_response_->response_type ==
+ network::mojom::FetchResponseType::kOpaque
+ ? V8CodeCache::OpaqueMode::kOpaque
+ : V8CodeCache::OpaqueMode::kNotOpaque;
}
~CodeCacheHandleCallbackForPut() override = default;
void DidFetchDataLoadedArrayBuffer(DOMArrayBuffer* array_buffer) override {
+ base::Time response_time = fetch_api_response_->response_time;
mojom::blink::BatchOperationPtr batch_operation =
mojom::blink::BatchOperation::New();
batch_operation->operation_type = mojom::blink::OperationType::kPut;
@@ -388,34 +422,33 @@ class Cache::CodeCacheHandleCallbackForPut final
batch_operation->response->blob = BlobDataHandle::Create(
std::move(blob_data), array_buffer->ByteLength());
- // Currently we only support UTF8 encoding.
- // TODO(horo): Use the charset in Content-type header of the response.
- // See crbug.com/743311.
- std::unique_ptr<TextResourceDecoder> text_decoder =
- TextResourceDecoder::Create(
- TextResourceDecoderOptions::CreateAlwaysUseUTF8ForText());
-
- scoped_refptr<CachedMetadata> cached_metadata =
- V8CodeCache::GenerateFullCodeCache(
- script_state_,
- text_decoder->Decode(static_cast<const char*>(array_buffer->Data()),
- array_buffer->ByteLength()),
- batch_operation->request->url.GetString(), text_decoder->Encoding(),
- batch_operation->response->response_type ==
- network::mojom::FetchResponseType::kOpaque
- ? V8CodeCache::OpaqueMode::kOpaque
- : V8CodeCache::OpaqueMode::kNotOpaque);
- if (!cached_metadata) {
- barrier_callback_->OnSuccess(index_, std::move(batch_operation));
- return;
+ if (timing_ == CodeCacheGenerateTiming::kGenerateNow) {
+ scoped_refptr<CachedMetadata> cached_metadata =
+ GenerateFullCodeCache(array_buffer);
+ if (cached_metadata) {
+ const Vector<uint8_t>& serialized_data =
+ cached_metadata->SerializedData();
+ std::unique_ptr<BlobData> side_data_blob_data = BlobData::Create();
+ side_data_blob_data->AppendBytes(serialized_data.data(),
+ serialized_data.size());
+
+ batch_operation->response->side_data_blob = BlobDataHandle::Create(
+ std::move(side_data_blob_data), serialized_data.size());
+ }
+ } else {
+ // Schedule an idle task to generate code cache later.
+ ServiceWorkerGlobalScope* global_scope = GetServiceWorkerGlobalScope();
+ auto* thread_scheduler =
+ global_scope->GetScheduler()->GetWorkerThreadScheduler();
+ DCHECK(thread_scheduler);
+ int task_id = global_scope->WillStartTask();
+ thread_scheduler->IdleTaskRunner()->PostIdleTask(
+ FROM_HERE, WTF::Bind(&Cache::CodeCacheHandleCallbackForPut::
+ GenerateCodeCacheOnIdleTask,
+ WrapPersistent(this), task_id,
+ WrapPersistent(array_buffer), response_time));
}
- const Vector<char>& serialized_data = cached_metadata->SerializedData();
- std::unique_ptr<BlobData> side_data_blob_data = BlobData::Create();
- side_data_blob_data->AppendBytes(serialized_data.data(),
- serialized_data.size());
- batch_operation->response->side_data_blob = BlobDataHandle::Create(
- std::move(side_data_blob_data), serialized_data.size());
barrier_callback_->OnSuccess(index_, std::move(batch_operation));
}
@@ -427,15 +460,67 @@ class Cache::CodeCacheHandleCallbackForPut final
void Trace(blink::Visitor* visitor) override {
visitor->Trace(script_state_);
+ visitor->Trace(cache_);
visitor->Trace(barrier_callback_);
FetchDataLoader::Client::Trace(visitor);
}
private:
+ ServiceWorkerGlobalScope* GetServiceWorkerGlobalScope() {
+ // Currently |this| is only created for triggering V8 code caching after
+ // Cache#put() is used by a service worker so |script_state_| should be
+ // ServiceWorkerGlobalScope.
+ ExecutionContext* context = ExecutionContext::From(script_state_);
+ auto* global_scope = DynamicTo<ServiceWorkerGlobalScope>(context);
+ DCHECK(global_scope);
+ return global_scope;
+ }
+
+ scoped_refptr<CachedMetadata> GenerateFullCodeCache(
+ DOMArrayBuffer* array_buffer) {
+ // Currently we only support UTF8 encoding.
+ // TODO(horo): Use the charset in Content-type header of the response.
+ // See crbug.com/743311.
+ std::unique_ptr<TextResourceDecoder> text_decoder =
+ TextResourceDecoder::Create(
+ TextResourceDecoderOptions::CreateAlwaysUseUTF8ForText());
+
+ return V8CodeCache::GenerateFullCodeCache(
+ script_state_,
+ text_decoder->Decode(static_cast<const char*>(array_buffer->Data()),
+ array_buffer->ByteLength()),
+ url_, text_decoder->Encoding(), opaque_mode_);
+ }
+
+ void GenerateCodeCacheOnIdleTask(int task_id,
+ DOMArrayBuffer* array_buffer,
+ base::Time response_time,
+ base::TimeTicks) {
+ ServiceWorkerGlobalScope* global_scope = GetServiceWorkerGlobalScope();
+ scoped_refptr<CachedMetadata> cached_metadata =
+ GenerateFullCodeCache(array_buffer);
+ if (!cached_metadata) {
+ global_scope->DidEndTask(task_id);
+ return;
+ }
+ cache_->cache_ptr_->SetSideData(
+ url_, response_time, cached_metadata->SerializedData(),
+ WTF::Bind(
+ [](ServiceWorkerGlobalScope* global_scope, int task_id,
+ mojom::blink::CacheStorageError error) {
+ global_scope->DidEndTask(task_id);
+ },
+ WrapPersistent(global_scope), task_id));
+ }
+
const Member<ScriptState> script_state_;
+ const Member<Cache> cache_;
const wtf_size_t index_;
Member<BarrierCallbackForPut> barrier_callback_;
const String mime_type_;
+ KURL url_;
+ V8CodeCache::OpaqueMode opaque_mode_;
+ CodeCacheGenerateTiming timing_;
mojom::blink::FetchAPIRequestPtr fetch_api_request_;
mojom::blink::FetchAPIResponsePtr fetch_api_response_;
@@ -443,8 +528,12 @@ class Cache::CodeCacheHandleCallbackForPut final
Cache* Cache::Create(
GlobalFetch::ScopedFetcher* fetcher,
- mojom::blink::CacheStorageCacheAssociatedPtrInfo cache_ptr_info) {
- return new Cache(fetcher, std::move(cache_ptr_info));
+ CacheStorage* cache_storage,
+ mojom::blink::CacheStorageCacheAssociatedPtrInfo cache_ptr_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ return MakeGarbageCollected<Cache>(fetcher, cache_storage,
+ std::move(cache_ptr_info),
+ std::move(task_runner));
}
ScriptPromise Cache::match(ScriptState* script_state,
@@ -578,13 +667,16 @@ mojom::blink::QueryParamsPtr Cache::ToQueryParams(
}
Cache::Cache(GlobalFetch::ScopedFetcher* fetcher,
- mojom::blink::CacheStorageCacheAssociatedPtrInfo cache_ptr_info)
- : scoped_fetcher_(fetcher) {
- cache_ptr_.Bind(std::move(cache_ptr_info));
+ CacheStorage* cache_storage,
+ mojom::blink::CacheStorageCacheAssociatedPtrInfo cache_ptr_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : scoped_fetcher_(fetcher), cache_storage_(cache_storage) {
+ cache_ptr_.Bind(std::move(cache_ptr_info), std::move(task_runner));
}
void Cache::Trace(blink::Visitor* visitor) {
visitor->Trace(scoped_fetcher_);
+ visitor->Trace(cache_storage_);
ScriptWrappable::Trace(visitor);
}
@@ -821,7 +913,8 @@ ScriptPromise Cache::PutImpl(ScriptState* script_state,
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
const ScriptPromise promise = resolver->Promise();
BarrierCallbackForPut* barrier_callback =
- new BarrierCallbackForPut(requests.size(), this, method_name, resolver);
+ MakeGarbageCollected<BarrierCallbackForPut>(requests.size(), this,
+ method_name, resolver);
for (wtf_size_t i = 0; i < requests.size(); ++i) {
KURL url(NullURL(), requests[i]->url());
@@ -861,12 +954,15 @@ ScriptPromise Cache::PutImpl(ScriptState* script_state,
BodyStreamBuffer* buffer = responses[i]->InternalBodyBuffer();
- if (ShouldGenerateV8CodeCache(script_state, responses[i])) {
+ CodeCacheGenerateTiming cache_generate_timing =
+ ShouldGenerateV8CodeCache(script_state, responses[i]);
+ if (cache_generate_timing != CodeCacheGenerateTiming::kDontGenerate) {
FetchDataLoader* loader = FetchDataLoader::CreateLoaderAsArrayBuffer();
buffer->StartLoading(
loader,
- new CodeCacheHandleCallbackForPut(script_state, i, barrier_callback,
- requests[i], responses[i]),
+ MakeGarbageCollected<CodeCacheHandleCallbackForPut>(
+ script_state, this, i, barrier_callback, requests[i],
+ responses[i], cache_generate_timing),
exception_state);
if (exception_state.HadException()) {
barrier_callback->OnError("Could not inspect response body state");
@@ -881,7 +977,7 @@ ScriptPromise Cache::PutImpl(ScriptState* script_state,
FetchDataLoader* loader = FetchDataLoader::CreateLoaderAsBlobHandle(
responses[i]->InternalMIMEType());
buffer->StartLoading(loader,
- new BlobHandleCallbackForPut(
+ MakeGarbageCollected<BlobHandleCallbackForPut>(
i, barrier_callback, requests[i], responses[i]),
exception_state);
if (exception_state.HadException()) {
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache.h b/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
index 935145ffef9..e7fe15830b9 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
@@ -8,7 +8,7 @@
#include <memory>
#include "base/macros.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/fetch/global_fetch.h"
#include "third_party/blink/renderer/modules/cache_storage/cache_query_options.h"
@@ -20,6 +20,7 @@
namespace blink {
+class CacheStorage;
class ExceptionState;
class Response;
class Request;
@@ -32,7 +33,14 @@ class MODULES_EXPORT Cache final : public ScriptWrappable {
public:
static Cache* Create(GlobalFetch::ScopedFetcher*,
- mojom::blink::CacheStorageCacheAssociatedPtrInfo);
+ CacheStorage*,
+ mojom::blink::CacheStorageCacheAssociatedPtrInfo,
+ scoped_refptr<base::SingleThreadTaskRunner>);
+
+ Cache(GlobalFetch::ScopedFetcher*,
+ CacheStorage*,
+ mojom::blink::CacheStorageCacheAssociatedPtrInfo,
+ scoped_refptr<base::SingleThreadTaskRunner>);
// From Cache.idl:
ScriptPromise match(ScriptState*,
@@ -72,8 +80,6 @@ class MODULES_EXPORT Cache final : public ScriptWrappable {
class CodeCacheHandleCallbackForPut;
class FetchResolvedForAdd;
friend class FetchResolvedForAdd;
- Cache(GlobalFetch::ScopedFetcher*,
- mojom::blink::CacheStorageCacheAssociatedPtrInfo);
ScriptPromise MatchImpl(ScriptState*,
const Request*,
@@ -98,6 +104,10 @@ class MODULES_EXPORT Cache final : public ScriptWrappable {
const CacheQueryOptions*);
Member<GlobalFetch::ScopedFetcher> scoped_fetcher_;
+ // Hold a reference to CacheStorage to keep |cache_ptr_| alive.
+ // This is required because |cache_ptr_| is associated with CacheStorage's
+ // mojo message pipe.
+ Member<CacheStorage> cache_storage_;
mojom::blink::CacheStorageCacheAssociatedPtr cache_ptr_;
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 6206905ea0b..2f6303f90cf 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -25,7 +25,7 @@ namespace blink {
CacheStorage* CacheStorage::Create(ExecutionContext* context,
GlobalFetch::ScopedFetcher* fetcher) {
- return new CacheStorage(context, fetcher);
+ return MakeGarbageCollected<CacheStorage>(context, fetcher);
}
ScriptPromise CacheStorage::open(ScriptState* script_state,
@@ -40,10 +40,11 @@ ScriptPromise CacheStorage::open(ScriptState* script_state,
WTF::Bind(
[](ScriptPromiseResolver* resolver,
GlobalFetch::ScopedFetcher* fetcher, TimeTicks start_time,
- CacheStorage* _, mojom::blink::OpenResultPtr result) {
+ CacheStorage* cache_storage, mojom::blink::OpenResultPtr result) {
if (!resolver->GetExecutionContext() ||
- resolver->GetExecutionContext()->IsContextDestroyed())
+ resolver->GetExecutionContext()->IsContextDestroyed()) {
return;
+ }
if (result->is_status()) {
switch (result->get_status()) {
case mojom::blink::CacheStorageError::kErrorNotFound:
@@ -58,8 +59,11 @@ ScriptPromise CacheStorage::open(ScriptState* script_state,
} else {
UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Open",
TimeTicks::Now() - start_time);
- resolver->Resolve(
- Cache::Create(fetcher, std::move(result->get_cache())));
+ // See https://bit.ly/2S0zRAS for task types.
+ resolver->Resolve(Cache::Create(
+ fetcher, cache_storage, std::move(result->get_cache()),
+ resolver->GetExecutionContext()->GetTaskRunner(
+ blink::TaskType::kMiscPlatformAPI)));
}
},
WrapPersistent(resolver), WrapPersistent(scoped_fetcher_.Get()),
@@ -237,19 +241,23 @@ ScriptPromise CacheStorage::MatchImpl(ScriptState* script_state,
CacheStorage::CacheStorage(ExecutionContext* context,
GlobalFetch::ScopedFetcher* fetcher)
: scoped_fetcher_(fetcher) {
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ context->GetTaskRunner(blink::TaskType::kMiscPlatformAPI);
+
// Service workers may already have a CacheStoragePtr provided as an
// optimization.
if (auto* service_worker = DynamicTo<ServiceWorkerGlobalScope>(context)) {
mojom::blink::CacheStoragePtrInfo info = service_worker->TakeCacheStorage();
if (info) {
cache_storage_ptr_ = RevocableInterfacePtr<mojom::blink::CacheStorage>(
- std::move(info), context->GetInterfaceInvalidator());
+ std::move(info), context->GetInterfaceInvalidator(), task_runner);
return;
}
}
- context->GetInterfaceProvider()->GetInterface(
- MakeRequest(&cache_storage_ptr_, context->GetInterfaceInvalidator()));
+ context->GetInterfaceProvider()->GetInterface(MakeRequest(
+ &cache_storage_ptr_, context->GetInterfaceInvalidator(), task_runner));
}
CacheStorage::~CacheStorage() = default;
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.h b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.h
index 86c96236673..38bf54e5377 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.h
@@ -7,7 +7,7 @@
#include <memory>
#include "base/macros.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/fetch/global_fetch.h"
#include "third_party/blink/renderer/modules/cache_storage/cache.h"
@@ -25,6 +25,8 @@ class CacheStorage final : public ScriptWrappable {
public:
static CacheStorage* Create(ExecutionContext*, GlobalFetch::ScopedFetcher*);
+
+ CacheStorage(ExecutionContext*, GlobalFetch::ScopedFetcher*);
~CacheStorage() override;
ScriptPromise open(ScriptState*, const String& cache_name);
@@ -39,7 +41,6 @@ class CacheStorage final : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
- CacheStorage(ExecutionContext*, GlobalFetch::ScopedFetcher*);
ScriptPromise MatchImpl(ScriptState*,
const Request*,
const CacheQueryOptions*);
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.cc
index 7ecd2d0ca81..31e8413d972 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/cache_storage/cache.h"
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.h b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.h
index 515fe9de7c9..a2befd1e66e 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_error.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_STORAGE_ERROR_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_STORAGE_ERROR_H_
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc
index 349032c5205..7a1586286a1 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc
@@ -13,7 +13,8 @@
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
@@ -54,7 +55,11 @@ class ScopedFetcherForTests final
USING_GARBAGE_COLLECTED_MIXIN(ScopedFetcherForTests);
public:
- static ScopedFetcherForTests* Create() { return new ScopedFetcherForTests(); }
+ static ScopedFetcherForTests* Create() {
+ return MakeGarbageCollected<ScopedFetcherForTests>();
+ }
+
+ ScopedFetcherForTests() : fetch_count_(0), expected_url_(nullptr) {}
ScriptPromise Fetch(ScriptState* script_state,
const RequestInfo& request_info,
@@ -98,8 +103,6 @@ class ScopedFetcherForTests final
}
private:
- ScopedFetcherForTests() : fetch_count_(0), expected_url_(nullptr) {}
-
int fetch_count_;
const String* expected_url_;
Member<Response> response_;
@@ -180,6 +183,13 @@ class ErrorCacheForTests : public mojom::blink::CacheStorageCache {
CheckBatchOperationsIfProvided(batch_operations);
std::move(callback).Run(CacheStorageVerboseError::New(error_, String()));
}
+ void SetSideData(const KURL& url,
+ base::Time response_time,
+ const Vector<uint8_t>& side_data,
+ SetSideDataCallback callback) override {
+ std::move(callback).Run(
+ blink::mojom::CacheStorageError::kErrorNotImplemented);
+ }
protected:
void CheckUrlIfProvided(const KURL& url) {
@@ -267,7 +277,9 @@ class CacheStorageTest : public PageTestBase {
binding_ = std::make_unique<
mojo::AssociatedBinding<mojom::blink::CacheStorageCache>>(
cache_.get(), std::move(request));
- return Cache::Create(fetcher, cache_ptr.PassInterface());
+ return Cache::Create(
+ fetcher, nullptr /* cache_storage */, cache_ptr.PassInterface(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
}
ErrorCacheForTests* test_cache() { return cache_.get(); }
@@ -328,18 +340,18 @@ class CacheStorageTest : public PageTestBase {
class UnreachableFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> Create(ScriptState* script_state) {
- UnreachableFunction* self = new UnreachableFunction(script_state);
+ UnreachableFunction* self =
+ MakeGarbageCollected<UnreachableFunction>(script_state);
return self->BindToV8Function();
}
+ UnreachableFunction(ScriptState* script_state)
+ : ScriptFunction(script_state) {}
+
ScriptValue Call(ScriptValue value) override {
ADD_FAILURE() << "Unexpected call to a null ScriptFunction.";
return value;
}
-
- private:
- UnreachableFunction(ScriptState* script_state)
- : ScriptFunction(script_state) {}
};
// A ScriptFunction that saves its parameter; used by tests to assert on
@@ -348,10 +360,14 @@ class CacheStorageTest : public PageTestBase {
public:
static v8::Local<v8::Function> Create(ScriptState* script_state,
ScriptValue* out_value) {
- TestFunction* self = new TestFunction(script_state, out_value);
+ TestFunction* self =
+ MakeGarbageCollected<TestFunction>(script_state, out_value);
return self->BindToV8Function();
}
+ TestFunction(ScriptState* script_state, ScriptValue* out_value)
+ : ScriptFunction(script_state), value_(out_value) {}
+
ScriptValue Call(ScriptValue value) override {
DCHECK(!value.IsEmpty());
*value_ = value;
@@ -359,9 +375,6 @@ class CacheStorageTest : public PageTestBase {
}
private:
- TestFunction(ScriptState* script_state, ScriptValue* out_value)
- : ScriptFunction(script_state), value_(out_value) {}
-
ScriptValue* value_;
};
@@ -767,9 +780,9 @@ TEST_F(CacheStorageTest, Add) {
Request* request = NewRequestFromUrl(url);
Response* response = Response::Create(
GetScriptState(),
- new BodyStreamBuffer(GetScriptState(),
- MakeGarbageCollected<FormDataBytesConsumer>(content),
- nullptr),
+ MakeGarbageCollected<BodyStreamBuffer>(
+ GetScriptState(),
+ MakeGarbageCollected<FormDataBytesConsumer>(content), nullptr),
content_type, ResponseInit::Create(), exception_state);
fetcher->SetResponse(response);
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/global_cache_storage.cc b/chromium/third_party/blink/renderer/modules/cache_storage/global_cache_storage.cc
index 25d412d8c3b..8862b8847f1 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/global_cache_storage.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/global_cache_storage.cc
@@ -31,12 +31,13 @@ class GlobalCacheStorageImpl final
GlobalCacheStorageImpl* supplement =
Supplement<T>::template From<GlobalCacheStorageImpl>(supplementable);
if (!supplement) {
- supplement = new GlobalCacheStorageImpl;
+ supplement = MakeGarbageCollected<GlobalCacheStorageImpl>();
Supplement<T>::ProvideTo(supplementable, supplement);
}
return *supplement;
}
+ GlobalCacheStorageImpl() = default;
~GlobalCacheStorageImpl() {}
CacheStorage* Caches(T& fetching_scope, ExceptionState& exception_state) {
@@ -81,8 +82,6 @@ class GlobalCacheStorageImpl final
}
private:
- GlobalCacheStorageImpl() = default;
-
Member<CacheStorage> caches_;
};
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
index ce51f53cd90..96bd49525fe 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
@@ -11,7 +11,7 @@
#include "base/memory/scoped_refptr.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -194,6 +194,7 @@ struct DataRequestParams {
String cache_name;
int skip_count;
int page_size;
+ String path_filter;
};
struct RequestResponse {
@@ -215,26 +216,57 @@ class ResponsesAccumulator : public RefCounted<ResponsesAccumulator> {
std::unique_ptr<RequestEntriesCallback> callback)
: params_(params),
num_responses_left_(num_responses),
- responses_(num_responses),
cache_ptr_(std::move(cache_ptr)),
callback_(std::move(callback)) {}
- void Dispatch(Vector<mojom::blink::FetchAPIRequestPtr> requests) {
- for (const auto& request : requests) {
- cache_ptr_->Match(
- request.Clone(), mojom::blink::QueryParams::New(),
- WTF::Bind(
- [](scoped_refptr<ResponsesAccumulator> accumulator,
- mojom::blink::FetchAPIRequestPtr request,
- mojom::blink::MatchResultPtr result) {
- if (result->is_status()) {
- accumulator->SendFailure(result->get_status());
- } else {
- accumulator->AddRequestResponsePair(request,
- result->get_response());
- }
- },
- scoped_refptr<ResponsesAccumulator>(this), request.Clone()));
+ void Dispatch(Vector<mojom::blink::FetchAPIRequestPtr> old_requests) {
+ Vector<mojom::blink::FetchAPIRequestPtr> requests;
+ if (params_.path_filter.IsEmpty()) {
+ requests = std::move(old_requests);
+ } else {
+ for (auto& request : old_requests) {
+ String urlPath(request->url.GetPath());
+ if (!urlPath.Contains(params_.path_filter,
+ WTF::kTextCaseUnicodeInsensitive))
+ continue;
+ requests.push_back(std::move(request));
+ }
+ }
+ wtf_size_t requestSize = requests.size();
+ if (!requestSize) {
+ callback_->sendSuccess(Array<DataEntry>::create(), false);
+ return;
+ }
+
+ responses_ = Vector<RequestResponse>(requestSize);
+ num_responses_left_ = requestSize;
+ for (auto& request : requests) {
+ // All FetchAPIRequests in cache_storage code are supposed to not contain
+ // a body.
+ DCHECK(!request->blob && !request->body);
+ auto request_clone_without_body = mojom::blink::FetchAPIRequest::New(
+ request->mode, request->is_main_resource_load,
+ request->request_context_type, request->frame_type, request->url,
+ request->method, request->headers, nullptr /* blob */,
+ nullptr /* body */, request->referrer.Clone(),
+ request->credentials_mode, request->cache_mode,
+ request->redirect_mode, request->integrity, request->priority,
+ request->fetch_window_id, request->keepalive, request->is_reload,
+ request->is_history_navigation);
+ cache_ptr_->Match(std::move(request), mojom::blink::QueryParams::New(),
+ WTF::Bind(
+ [](scoped_refptr<ResponsesAccumulator> accumulator,
+ mojom::blink::FetchAPIRequestPtr request,
+ mojom::blink::MatchResultPtr result) {
+ if (result->is_status()) {
+ accumulator->SendFailure(result->get_status());
+ } else {
+ accumulator->AddRequestResponsePair(
+ request, result->get_response());
+ }
+ },
+ scoped_refptr<ResponsesAccumulator>(this),
+ std::move(request_clone_without_body)));
}
}
@@ -486,6 +518,7 @@ void InspectorCacheStorageAgent::requestEntries(
const String& cache_id,
int skip_count,
int page_size,
+ protocol::Maybe<String> path_filter,
std::unique_ptr<RequestEntriesCallback> callback) {
String cache_name;
mojom::blink::CacheStorage* cache_storage = nullptr;
@@ -499,6 +532,7 @@ void InspectorCacheStorageAgent::requestEntries(
params.cache_name = cache_name;
params.page_size = page_size;
params.skip_count = skip_count;
+ params.path_filter = path_filter.fromMaybe("");
cache_storage->Open(
cache_name,
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h b/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h
index e0bba936a7f..2377b666960 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h
@@ -8,7 +8,7 @@
#include <memory>
#include "base/macros.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
#include "third_party/blink/renderer/core/inspector/protocol/CacheStorage.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -36,6 +36,7 @@ class MODULES_EXPORT InspectorCacheStorageAgent final
void requestEntries(const String& cache_id,
int skip_count,
int page_size,
+ protocol::Maybe<String> path_filter,
std::unique_ptr<RequestEntriesCallback>) override;
void deleteCache(const String& cache_id,
std::unique_ptr<DeleteCacheCallback>) override;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index 30075bc6b02..d9fa696c9a9 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -9,6 +9,8 @@
#include <memory>
#include "base/metrics/histogram_functions.h"
+#include "base/numerics/checked_math.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/css/cssom/css_url_image_value.h"
#include "third_party/blink/renderer/core/css/parser/css_parser.h"
#include "third_party/blink/renderer/core/html/canvas/text_metrics.h"
@@ -1233,7 +1235,8 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
// overhead.
// See comments in canvas_heuristic_parameters.h for explanation.
if (CanCreateCanvas2dResourceProvider() && IsAccelerated() &&
- !image_source->IsAccelerated()) {
+ !image_source->IsAccelerated() &&
+ !base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) {
float src_area = src_rect.Width() * src_rect.Height();
if (src_area >
canvas_heuristic_parameters::kDrawImageTextureUploadHardSizeLimit) {
@@ -1254,8 +1257,7 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
ValidateStateStack();
- if (!origin_tainted_by_content_ &&
- WouldTaintOrigin(image_source, ExecutionContext::From(script_state)))
+ if (!origin_tainted_by_content_ && WouldTaintOrigin(image_source))
SetOriginTaintedByContent();
Draw(
@@ -1460,8 +1462,7 @@ CanvasPattern* BaseRenderingContext2D::createPattern(
}
DCHECK(image_for_rendering);
- bool origin_clean =
- !WouldTaintOrigin(image_source, ExecutionContext::From(script_state));
+ bool origin_clean = !WouldTaintOrigin(image_source);
return CanvasPattern::Create(std::move(image_for_rendering), repeat_mode,
origin_clean);
@@ -1604,7 +1605,7 @@ ImageData* BaseRenderingContext2D::getImageData(
return nullptr;
}
sx += sw;
- sw = -sw;
+ sw = base::saturated_cast<int>(base::SafeUnsignedAbs(sw));
}
if (sh < 0) {
if (!base::CheckAdd(sy, sh).IsValid<int>()) {
@@ -1612,7 +1613,7 @@ ImageData* BaseRenderingContext2D::getImageData(
return nullptr;
}
sy += sh;
- sh = -sh;
+ sh = base::saturated_cast<int>(base::SafeUnsignedAbs(sh));
}
if (!base::CheckAdd(sx, sw).IsValid<int>() ||
@@ -1735,12 +1736,13 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
if (dirty_width < 0) {
dirty_x += dirty_width;
- dirty_width = -dirty_width;
+ dirty_width = base::saturated_cast<int>(base::SafeUnsignedAbs(dirty_width));
}
if (dirty_height < 0) {
dirty_y += dirty_height;
- dirty_height = -dirty_height;
+ dirty_height =
+ base::saturated_cast<int>(base::SafeUnsignedAbs(dirty_height));
}
IntRect dest_rect(dirty_x, dirty_y, dirty_width, dirty_height);
@@ -1767,9 +1769,12 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
CanvasColorParams(ColorParams().ColorSpace(), PixelFormat(), kNonOpaque);
if (data_color_params.NeedsColorConversion(context_color_params) ||
PixelFormat() == kF16CanvasPixelFormat) {
- size_t data_length =
- data->Size().Area() * context_color_params.BytesPerPixel();
- std::unique_ptr<uint8_t[]> converted_pixels(new uint8_t[data_length]);
+ base::CheckedNumeric<size_t> data_length = data->Size().Area();
+ data_length *= context_color_params.BytesPerPixel();
+ if (!data_length.IsValid())
+ return;
+ std::unique_ptr<uint8_t[]> converted_pixels(
+ new uint8_t[data_length.ValueOrDie()]);
if (data->ImageDataInCanvasColorSettings(
ColorParams().ColorSpace(), PixelFormat(), converted_pixels.get(),
kRGBAColorType)) {
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
index e1aaadb27a8..3004f0613aa 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -212,7 +212,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
virtual bool OriginClean() const = 0;
virtual void SetOriginTainted() = 0;
- virtual bool WouldTaintOrigin(CanvasImageSource*, ExecutionContext*) = 0;
+ virtual bool WouldTaintOrigin(CanvasImageSource*) = 0;
virtual int Width() const = 0;
virtual int Height() const = 0;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc
index 6ddad03501b..c3770835c81 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc
@@ -193,6 +193,8 @@ float AdjustEndAngle(float start_angle, float end_angle, bool anticlockwise) {
}
DCHECK(EllipseIsRenderable(start_angle, new_end_angle));
+ DCHECK((anticlockwise && (start_angle >= new_end_angle)) ||
+ (!anticlockwise && (new_end_angle >= start_angle)));
return new_end_angle;
}
@@ -339,10 +341,8 @@ void CanvasPath::arc(float x,
}
CanonicalizeAngle(&start_angle, &end_angle);
- float adjusted_end_angle =
- AdjustEndAngle(start_angle, end_angle, anticlockwise);
- path_.AddArc(FloatPoint(x, y), radius, start_angle, adjusted_end_angle,
- anticlockwise);
+ path_.AddArc(FloatPoint(x, y), radius, start_angle,
+ AdjustEndAngle(start_angle, end_angle, anticlockwise));
}
void CanvasPath::ellipse(float x,
@@ -389,7 +389,7 @@ void CanvasPath::ellipse(float x,
}
path_.AddEllipse(FloatPoint(x, y), radius_x, radius_y, rotation, start_angle,
- adjusted_end_angle, anticlockwise);
+ adjusted_end_angle);
}
void CanvasPath::rect(float x, float y, float width, float height) {
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
index 0fcd2ab0d0a..81799c8a957 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
@@ -15,6 +15,6 @@
void bezierCurveTo(unrestricted float cp1x, unrestricted float cp1y, unrestricted float cp2x, unrestricted float cp2y, unrestricted float x, unrestricted float y);
[RaisesException] void arcTo(unrestricted float x1, unrestricted float y1, unrestricted float x2, unrestricted float y2, unrestricted float radius);
void rect(unrestricted float x, unrestricted float y, unrestricted float width, unrestricted float height);
- [RaisesException] void arc(unrestricted float x, unrestricted float y, unrestricted float radius, unrestricted float startAngle, unrestricted float endAngle, [Default=Undefined] optional boolean anticlockwise);
- [RaisesException] void ellipse(unrestricted float x, unrestricted float y, unrestricted float radiusX, unrestricted float radiusY, unrestricted float rotation, unrestricted float startAngle, unrestricted float endAngle, [Default=Undefined] optional boolean anticlockwise);
+ [RaisesException] void arc(unrestricted float x, unrestricted float y, unrestricted float radius, unrestricted float startAngle, unrestricted float endAngle, [DefaultValue=Undefined] optional boolean anticlockwise);
+ [RaisesException] void ellipse(unrestricted float x, unrestricted float y, unrestricted float radiusX, unrestricted float radiusY, unrestricted float rotation, unrestricted float startAngle, unrestricted float endAngle, [DefaultValue=Undefined] optional boolean anticlockwise);
};
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 9d14c1309e7..6fc3bfa2d87 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
@@ -51,6 +52,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_canvas_result.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/hit_region.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/path_2d.h"
@@ -504,9 +506,8 @@ void CanvasRenderingContext2D::setFont(const String& new_font) {
HashMap<String, Font>::iterator i =
fonts_resolved_using_current_style_.find(new_font);
if (i != fonts_resolved_using_current_style_.end()) {
- DCHECK(font_lru_list_.Contains(new_font));
- font_lru_list_.erase(new_font);
- font_lru_list_.insert(new_font);
+ auto add_result = font_lru_list_.PrependOrMoveToFirst(new_font);
+ DCHECK(!add_result.is_new_entry);
ModifiableState().SetFont(i->value, Host()->GetFontSelector());
} else {
MutableCSSPropertyValueSet* parsed_style =
@@ -537,8 +538,8 @@ void CanvasRenderingContext2D::setFont(const String& new_font) {
Font final_font(final_description);
fonts_resolved_using_current_style_.insert(new_font, final_font);
- DCHECK(!font_lru_list_.Contains(new_font));
- font_lru_list_.insert(new_font);
+ auto add_result = font_lru_list_.PrependOrMoveToFirst(new_font);
+ DCHECK(add_result.is_new_entry);
PruneLocalFontCache(canvas_font_cache->HardMaxFonts()); // hard limit
should_prune_local_font_cache_ = true; // apply soft limit
ModifiableState().SetFont(final_font, Host()->GetFontSelector());
@@ -582,8 +583,8 @@ void CanvasRenderingContext2D::PruneLocalFontCache(size_t target_size) {
return;
}
while (font_lru_list_.size() > target_size) {
- fonts_resolved_using_current_style_.erase(font_lru_list_.front());
- font_lru_list_.RemoveFirst();
+ fonts_resolved_using_current_style_.erase(font_lru_list_.back());
+ font_lru_list_.pop_back();
}
}
@@ -932,8 +933,12 @@ CanvasRenderingContext2D::getContextAttributes() const {
CanvasRenderingContext2DSettings* settings =
CanvasRenderingContext2DSettings::Create();
settings->setAlpha(CreationAttributes().alpha);
- settings->setColorSpace(ColorSpaceAsString());
- settings->setPixelFormat(PixelFormatAsString());
+ if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
+ settings->setColorSpace(ColorSpaceAsString());
+ settings->setPixelFormat(PixelFormatAsString());
+ }
+ if (origin_trials::LowLatencyCanvasEnabled(&canvas()->GetDocument()))
+ settings->setLowLatency(canvas()->LowLatencyEnabled());
return settings;
}
@@ -1099,6 +1104,9 @@ unsigned CanvasRenderingContext2D::HitRegionsCount() const {
}
void CanvasRenderingContext2D::DisableAcceleration() {
+ if (base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) {
+ NOTREACHED();
+ }
canvas()->DisableAcceleration();
}
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 14777dae85d..6c8d41a1fb8 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -40,6 +40,7 @@
#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace cc {
@@ -161,10 +162,8 @@ class MODULES_EXPORT CanvasRenderingContext2D final
// BaseRenderingContext2D implementation
bool OriginClean() const final;
void SetOriginTainted() final;
- bool WouldTaintOrigin(CanvasImageSource* source,
- ExecutionContext* execution_context) final {
- return CanvasRenderingContext::WouldTaintOrigin(
- source, execution_context->GetSecurityOrigin());
+ bool WouldTaintOrigin(CanvasImageSource* source) final {
+ return CanvasRenderingContext::WouldTaintOrigin(source);
}
void DisableAcceleration() override;
void DidInvokeGPUReadbackInCurrentFrame() override;
@@ -269,7 +268,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final
FilterOperations filter_operations_;
HashMap<String, Font> fonts_resolved_using_current_style_;
bool should_prune_local_font_cache_;
- ListHashSet<String> font_lru_list_;
+ LinkedHashSet<String> font_lru_list_;
};
DEFINE_TYPE_CASTS(CanvasRenderingContext2D,
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
index fee85211f2b..b8f1ecd9a8a 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
@@ -138,8 +138,7 @@ interface CanvasRenderingContext2D {
// Should be merged with WebGL counterpart in CanvasRenderingContext, once no-longer experimental
[RuntimeEnabled=Canvas2dContextLostRestored] boolean isContextLost();
- // TODO: This will have to be standardized for feature detection as part of the Canvas ColorSpace proposal.
- [RuntimeEnabled=CanvasColorManagement, MeasureAs=GetCanvas2DContextAttributes] CanvasRenderingContext2DSettings getContextAttributes();
+ [MeasureAs=GetCanvas2DContextAttributes] CanvasRenderingContext2DSettings getContextAttributes();
// FIXME: factor out to CanvasDrawingStyles
// line caps/joins
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl
index 93c38d72a27..abcef84503d 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl
@@ -9,5 +9,7 @@ dictionary CanvasRenderingContext2DSettings {
boolean alpha = true;
[RuntimeEnabled=CanvasColorManagement] CanvasColorSpace colorSpace = "srgb";
[RuntimeEnabled=CanvasColorManagement] CanvasPixelFormat pixelFormat = "uint8";
+ // TODO(crbug.com/788439): remove OriginTrialEnabled.
+ [OriginTrialEnabled=LowLatencyCanvas] boolean lowLatency = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
index fd6dd2a495d..d840e518232 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -432,7 +432,7 @@ SkDrawLooper* CanvasRenderingContext2DState::ShadowAndForegroundDrawLooper()
sk_sp<PaintFilter> CanvasRenderingContext2DState::ShadowOnlyImageFilter()
const {
if (!shadow_only_image_filter_) {
- double sigma = SkBlurRadiusToSigma(shadow_blur_);
+ const auto sigma = BlurRadiusToStdDev(shadow_blur_);
shadow_only_image_filter_ = sk_make_sp<DropShadowPaintFilter>(
shadow_offset_.Width(), shadow_offset_.Height(), sigma, sigma,
shadow_color_, SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
@@ -444,7 +444,7 @@ sk_sp<PaintFilter> CanvasRenderingContext2DState::ShadowOnlyImageFilter()
sk_sp<PaintFilter>
CanvasRenderingContext2DState::ShadowAndForegroundImageFilter() const {
if (!shadow_and_foreground_image_filter_) {
- double sigma = SkBlurRadiusToSigma(shadow_blur_);
+ const auto sigma = BlurRadiusToStdDev(shadow_blur_);
shadow_and_foreground_image_filter_ = sk_make_sp<DropShadowPaintFilter>(
shadow_offset_.Width(), shadow_offset_.Height(), sigma, sigma,
shadow_color_,
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
index 0a69b639042..06e5d278dd7 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
@@ -52,7 +52,7 @@ class CanvasRenderingContext2DState final
static CanvasRenderingContext2DState* Create(
const CanvasRenderingContext2DState& other,
ClipListCopyMode mode) {
- return new CanvasRenderingContext2DState(other, mode);
+ return MakeGarbageCollected<CanvasRenderingContext2DState>(other, mode);
}
// FontSelectorClient implementation
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index a96eb474894..52c1987309f 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -5,9 +5,9 @@
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h"
#include <memory>
+#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
@@ -59,10 +59,7 @@ class FakeImageSource : public CanvasImageSource {
AccelerationHint,
const FloatSize&) override;
- bool WouldTaintOrigin(
- const SecurityOrigin* destination_security_origin) const override {
- return false;
- }
+ bool WouldTaintOrigin() const override { return false; }
FloatSize ElementSize(const FloatSize&) const override {
return FloatSize(size_);
}
@@ -1196,8 +1193,8 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform,
UpdateAllLifecyclePhasesForTest();
// Hide element to trigger hibernation (if enabled).
- GetDocument().GetPage()->SetVisibilityState(
- mojom::PageVisibilityState::kHidden, false);
+ GetDocument().GetPage()->SetIsHidden(/*is_hidden=*/true,
+ /*is_initial_state=*/false);
RunUntilIdle(); // Run hibernation task.
// If enabled, hibernation should cause compositing update.
EXPECT_EQ(!!CANVAS2D_HIBERNATION_ENABLED,
@@ -1209,8 +1206,8 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform,
EXPECT_FALSE(layer->NeedsCompositingInputsUpdate());
// Wake up again, which should request a compositing update synchronously.
- GetDocument().GetPage()->SetVisibilityState(
- mojom::PageVisibilityState::kVisible, false);
+ GetDocument().GetPage()->SetIsHidden(/*is_hidden=*/false,
+ /*is_initial_state=*/false);
EXPECT_EQ(!!CANVAS2D_HIBERNATION_ENABLED,
layer->NeedsCompositingInputsUpdate());
RunUntilIdle(); // Clear task queue.
@@ -1235,8 +1232,8 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform,
UpdateAllLifecyclePhasesForTest();
// Hide element to trigger hibernation (if enabled).
- GetDocument().GetPage()->SetVisibilityState(
- mojom::PageVisibilityState::kHidden, false);
+ GetDocument().GetPage()->SetIsHidden(/*is_hidden=*/true,
+ /*is_initial_state=*/false);
RunUntilIdle(); // Run hibernation task.
// Never hibernate a canvas with no resource provider
@@ -1244,6 +1241,10 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform,
}
TEST_F(CanvasRenderingContext2DTest, LowLatencyIsSingleBuffered) {
+#if defined(OS_MACOSX)
+ // TODO(crbug.com/922218): enable lowLatency on Mac.
+ return;
+#endif
CreateContext(kNonOpaque, kLowLatency);
// No need to set-up the layer bridge when testing low latency mode.
DrawSomething();
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc
index 8ef083779c9..cdc87407875 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc
@@ -100,12 +100,12 @@ CanvasStyle::CanvasStyle(CanvasPattern* pattern)
CanvasStyle* CanvasStyle::CreateFromGradient(CanvasGradient* gradient) {
DCHECK(gradient);
- return new CanvasStyle(gradient);
+ return MakeGarbageCollected<CanvasStyle>(gradient);
}
CanvasStyle* CanvasStyle::CreateFromPattern(CanvasPattern* pattern) {
DCHECK(pattern);
- return new CanvasStyle(pattern);
+ return MakeGarbageCollected<CanvasStyle>(pattern);
}
void CanvasStyle::ApplyToFlags(PaintFlags& flags) const {
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h
index 504d0baf673..c5c55670009 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h
@@ -42,11 +42,15 @@ class HTMLCanvasElement;
class CanvasStyle final : public GarbageCollected<CanvasStyle> {
public:
static CanvasStyle* CreateFromRGBA(RGBA32 rgba) {
- return new CanvasStyle(rgba);
+ return MakeGarbageCollected<CanvasStyle>(rgba);
}
static CanvasStyle* CreateFromGradient(CanvasGradient*);
static CanvasStyle* CreateFromPattern(CanvasPattern*);
+ CanvasStyle(RGBA32);
+ CanvasStyle(CanvasGradient*);
+ CanvasStyle(CanvasPattern*);
+
String GetColor() const {
DCHECK_EQ(type_, kColorRGBA);
return Color(rgba_).Serialized();
@@ -66,10 +70,6 @@ class CanvasStyle final : public GarbageCollected<CanvasStyle> {
private:
enum Type { kColorRGBA, kGradient, kImagePattern };
- CanvasStyle(RGBA32);
- CanvasStyle(CanvasGradient*);
- CanvasStyle(CanvasPattern*);
-
Type type_;
RGBA32 rgba_;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.cc b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.cc
index fa11d4bf074..40c3babd3b7 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.h"
+#include "build/build_config.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
#include "third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
namespace blink {
@@ -18,12 +18,17 @@ CanvasContextCreationAttributesCore ToCanvasContextCreationAttributes(
result.depth = attrs->depth();
result.fail_if_major_performance_caveat =
attrs->failIfMajorPerformanceCaveat();
+#if defined(OS_MACOSX)
+ // TODO(crbug.com/922218): enable lowLatency on Mac.
+ result.low_latency = false;
+#else
result.low_latency = attrs->lowLatency();
+#endif
result.pixel_format = attrs->pixelFormat();
result.premultiplied_alpha = attrs->premultipliedAlpha();
result.preserve_drawing_buffer = attrs->preserveDrawingBuffer();
result.stencil = attrs->stencil();
- result.compatible_xr_device = attrs->compatibleXRDevice();
+ result.xr_compatible = attrs->xrCompatible();
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl
index 98875e974f5..ad9f867f46b 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl
+++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl
@@ -48,5 +48,5 @@ dictionary CanvasContextCreationAttributesModule {
boolean premultipliedAlpha = true;
boolean preserveDrawingBuffer = false;
boolean failIfMajorPerformanceCaveat = false;
- [OriginTrialEnabled=WebXR] XRDevice compatibleXRDevice = null;
+ [OriginTrialEnabled=WebXR] boolean xrCompatible = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
index 121b82b5c80..6be47fe03ef 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom-blink.h"
@@ -74,6 +75,11 @@ TEST_F(HTMLCanvasElementModuleTest, TransferControlToOffscreen) {
// Verifies that a lowLatency canvas has the appropriate opacity/blending
// information sent to the CompositorFrameSink.
TEST_P(HTMLCanvasElementModuleTest, LowLatencyCanvasCompositorFrameOpacity) {
+#if defined(OS_MACOSX)
+ // TODO(crbug.com/922218): enable lowLatency on Mac.
+ return;
+#endif
+
ScopedTestingPlatformSupport<TestingPlatformSupportWithGenerateFrameSinkId>
platform;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
index 061ca895e20..93955ace6fd 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
@@ -6,7 +6,6 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
index 930608c0eaf..eddb0b2c784 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@@ -68,17 +68,8 @@ void OffscreenCanvasRenderingContext2D::SetOriginTainted() {
}
bool OffscreenCanvasRenderingContext2D::WouldTaintOrigin(
- CanvasImageSource* source,
- ExecutionContext* execution_context) {
- if (execution_context->IsWorkerGlobalScope()) {
- // We only support passing in ImageBitmap and OffscreenCanvases as
- // source images in drawImage() or createPattern() in a
- // OffscreenCanvas2d in worker.
- DCHECK(source->IsImageBitmap() || source->IsOffscreenCanvas());
- }
-
- return CanvasRenderingContext::WouldTaintOrigin(
- source, execution_context->GetSecurityOrigin());
+ CanvasImageSource* source) {
+ return CanvasRenderingContext::WouldTaintOrigin(source);
}
int OffscreenCanvasRenderingContext2D::Width() const {
diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
index ce33c788092..40460193c0b 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -87,7 +87,7 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
// BaseRenderingContext2D implementation
bool OriginClean() const final;
void SetOriginTainted() final;
- bool WouldTaintOrigin(CanvasImageSource*, ExecutionContext*) final;
+ bool WouldTaintOrigin(CanvasImageSource*) final;
int Width() const final;
int Height() const final;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
index b9a3f6e7f1b..b53ed13ec6d 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
+++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
@@ -60,15 +60,15 @@
void stroke(Path2D path);
void clip();
void clip(Path2D path);
- boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
- boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
- boolean isPointInStroke(unrestricted double x, unrestricted double y);
- boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
+ [HighEntropy, MeasureAs=OffscreenCanvasIsPointInPath] boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
+ [HighEntropy, MeasureAs=OffscreenCanvasIsPointInPath] boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
+ [HighEntropy, MeasureAs=OffscreenCanvasIsPointInStroke] boolean isPointInStroke(unrestricted double x, unrestricted double y);
+ [HighEntropy, MeasureAs=OffscreenCanvasIsPointInStroke] boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
// text (see also the CanvasDrawingStyles interface)
void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
- TextMetrics measureText(DOMString text);
+ [HighEntropy, MeasureAs=OffscreenCanvasMeasureText] TextMetrics measureText(DOMString text);
// drawing images
[CallWith=ScriptState, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y);
@@ -78,7 +78,7 @@
// pixel manipulation
[RaisesException] ImageData createImageData(ImageData imagedata);
[RaisesException] ImageData createImageData(long sw, long sh);
- [RaisesException] ImageData getImageData(long sx, long sy, long sw, long sh);
+ [HighEntropy, MeasureAs=OffscreenCanvasGetImageData, RaisesException] ImageData getImageData(long sx, long sy, long sw, long sh);
[RaisesException] void putImageData(ImageData imagedata, long dx, long dy);
[RaisesException] void putImageData(ImageData imagedata, long dx, long dy, long dirtyX, long dirtyY, long dirtyWidth, long dirtyHeight);
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/BUILD.gn b/chromium/third_party/blink/renderer/modules/clipboard/BUILD.gn
index 3748b48a618..fc5058ea663 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/clipboard/BUILD.gn
@@ -8,6 +8,8 @@ blink_modules_sources("clipboard") {
sources = [
"clipboard.cc",
"clipboard.h",
+ "clipboard_file_reader.cc",
+ "clipboard_file_reader.h",
"clipboard_promise.cc",
"clipboard_promise.h",
"navigator_clipboard.cc",
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/OWNERS b/chromium/third_party/blink/renderer/modules/clipboard/OWNERS
new file mode 100644
index 00000000000..d637b215ee9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/clipboard/OWNERS
@@ -0,0 +1,6 @@
+garykac@chromium.org
+pwnall@chromium.org
+jsbell@chromium.org
+
+# TEAM: storage-dev@chromium.org
+# COMPONENT: Blink>DataTransfer
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard.cc
index 457b37b183f..f0ced281ee8 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard.cc
@@ -20,6 +20,10 @@ ScriptPromise Clipboard::readText(ScriptState* script_state) {
return ClipboardPromise::CreateForReadText(script_state);
}
+ScriptPromise Clipboard::readImageExperimental(ScriptState* script_state) {
+ return ClipboardPromise::CreateForReadImage(script_state);
+}
+
ScriptPromise Clipboard::write(ScriptState* script_state, DataTransfer* data) {
return ClipboardPromise::CreateForWrite(script_state, data);
}
@@ -29,6 +33,11 @@ ScriptPromise Clipboard::writeText(ScriptState* script_state,
return ClipboardPromise::CreateForWriteText(script_state, data);
}
+ScriptPromise Clipboard::writeImageExperimental(ScriptState* script_state,
+ Blob* data) {
+ return ClipboardPromise::CreateForWriteImage(script_state, data);
+}
+
const AtomicString& Clipboard::InterfaceName() const {
return event_target_names::kClipboard;
}
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard.h b/chromium/third_party/blink/renderer/modules/clipboard/clipboard.h
index d6e1e58cd6c..92d08a5bfe5 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard.h
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
namespace blink {
@@ -26,9 +27,11 @@ class Clipboard : public EventTargetWithInlineData,
ScriptPromise read(ScriptState*);
ScriptPromise readText(ScriptState*);
+ ScriptPromise readImageExperimental(ScriptState*);
ScriptPromise write(ScriptState*, DataTransfer*);
ScriptPromise writeText(ScriptState*, const String&);
+ ScriptPromise writeImageExperimental(ScriptState*, Blob*);
// EventTarget
const AtomicString& InterfaceName() const override;
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard.idl b/chromium/third_party/blink/renderer/modules/clipboard/clipboard.idl
index ecbf5d16a00..0aa39d8b3b9 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard.idl
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard.idl
@@ -17,6 +17,12 @@
CallWith=ScriptState
] Promise<DOMString> readText();
+ [
+ CallWith=ScriptState,
+ RuntimeEnabled=AsyncClipboardImages
+ ] Promise<Blob> readImageExperimental();
+
+
[MeasureAs=AsyncClipboardAPIWrite,
CallWith=ScriptState,
RuntimeEnabled=AsyncClipboard
@@ -25,4 +31,9 @@
[MeasureAs=AsyncClipboardAPIWriteText,
CallWith=ScriptState
] Promise<void> writeText(DOMString data);
+
+ [
+ CallWith=ScriptState,
+ RuntimeEnabled=AsyncClipboardImages
+ ] Promise<void> writeImageExperimental(Blob data);
};
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc
new file mode 100644
index 00000000000..84c6650edb2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h"
+
+#include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
+#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
+
+namespace blink {
+ClipboardFileReader::ClipboardFileReader(Blob* blob, ClipboardPromise* promise)
+ : loader_(
+ FileReaderLoader::Create(FileReaderLoader::kReadAsArrayBuffer, this)),
+ promise_(promise) {
+ loader_->Start(blob->GetBlobDataHandle());
+}
+
+ClipboardFileReader::~ClipboardFileReader() = default;
+
+// FileReaderLoaderClient implementation.
+void ClipboardFileReader::DidFinishLoading() {
+ DOMArrayBuffer* array_buffer = loader_->ArrayBufferResult();
+ promise_->OnLoadComplete(array_buffer);
+}
+
+void ClipboardFileReader::DidFail(FileErrorCode error_code) {
+ promise_->Reject();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h
new file mode 100644
index 00000000000..0abd07a901b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_FILE_READER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_FILE_READER_H_
+
+#include "third_party/blink/renderer/core/fileapi/blob.h"
+#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
+
+namespace blink {
+
+class FileReaderLoader;
+class ClipboardPromise;
+
+// Single-use object for reading a Blob or File asynchronously.
+//
+// Takes in a Blob* and ClipboardPromise, and outputs the contents of the Blob
+// back to the ClipboardPromise.
+//
+// Created for the intent of use with clipboard, but may be generic enough for
+// other uses.
+//
+// TODO (crbug.com/916821): This class is very similar to ImageBitmapFactories::
+// ImageBitmapLoader. Ask ImageBitmapLoader creators if there's potential to
+// merge code and reduce duplicate code.
+class ClipboardFileReader final : public FileReaderLoaderClient {
+ public:
+ ClipboardFileReader(Blob*, ClipboardPromise*);
+ ~ClipboardFileReader() override;
+
+ // FileReaderLoaderClient.
+ void DidStartLoading() override {}
+ void DidReceiveData() override {}
+ void DidFinishLoading() override;
+ void DidFail(FileErrorCode) override;
+
+ private:
+ // This FileReaderLoader will load the Blob.
+ const std::unique_ptr<FileReaderLoader> loader_;
+ // This ClipboardPromise owns this loader.
+ Persistent<ClipboardPromise> promise_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_FILE_READER_H_
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index 1378ca96d53..f6571686020 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
#include "base/single_thread_task_runner.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
+#include "base/task/post_task.h"
#include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -20,7 +20,14 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
+#include "third_party/blink/renderer/platform/scheduler/public/background_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
// And now, a brief note about clipboard permissions.
@@ -39,10 +46,12 @@ namespace blink {
using mojom::blink::PermissionStatus;
using mojom::blink::PermissionService;
-using mojom::PageVisibilityState;
+
+ClipboardPromise::~ClipboardPromise() = default;
ScriptPromise ClipboardPromise::CreateForRead(ScriptState* script_state) {
- ClipboardPromise* clipboard_promise = new ClipboardPromise(script_state);
+ ClipboardPromise* clipboard_promise =
+ MakeGarbageCollected<ClipboardPromise>(script_state);
clipboard_promise->GetTaskRunner()->PostTask(
FROM_HERE, WTF::Bind(&ClipboardPromise::HandleRead,
WrapPersistent(clipboard_promise)));
@@ -50,16 +59,27 @@ ScriptPromise ClipboardPromise::CreateForRead(ScriptState* script_state) {
}
ScriptPromise ClipboardPromise::CreateForReadText(ScriptState* script_state) {
- ClipboardPromise* clipboard_promise = new ClipboardPromise(script_state);
+ ClipboardPromise* clipboard_promise =
+ MakeGarbageCollected<ClipboardPromise>(script_state);
clipboard_promise->GetTaskRunner()->PostTask(
FROM_HERE, WTF::Bind(&ClipboardPromise::HandleReadText,
WrapPersistent(clipboard_promise)));
return clipboard_promise->script_promise_resolver_->Promise();
}
+ScriptPromise ClipboardPromise::CreateForReadImage(ScriptState* script_state) {
+ ClipboardPromise* clipboard_promise =
+ MakeGarbageCollected<ClipboardPromise>(script_state);
+ clipboard_promise->GetTaskRunner()->PostTask(
+ FROM_HERE, WTF::Bind(&ClipboardPromise::HandleReadImage,
+ WrapPersistent(clipboard_promise)));
+ return clipboard_promise->script_promise_resolver_->Promise();
+}
+
ScriptPromise ClipboardPromise::CreateForWrite(ScriptState* script_state,
DataTransfer* data) {
- ClipboardPromise* clipboard_promise = new ClipboardPromise(script_state);
+ ClipboardPromise* clipboard_promise =
+ MakeGarbageCollected<ClipboardPromise>(script_state);
clipboard_promise->GetTaskRunner()->PostTask(
FROM_HERE,
WTF::Bind(&ClipboardPromise::HandleWrite,
@@ -69,13 +89,25 @@ ScriptPromise ClipboardPromise::CreateForWrite(ScriptState* script_state,
ScriptPromise ClipboardPromise::CreateForWriteText(ScriptState* script_state,
const String& data) {
- ClipboardPromise* clipboard_promise = new ClipboardPromise(script_state);
+ ClipboardPromise* clipboard_promise =
+ MakeGarbageCollected<ClipboardPromise>(script_state);
clipboard_promise->GetTaskRunner()->PostTask(
FROM_HERE, WTF::Bind(&ClipboardPromise::HandleWriteText,
WrapPersistent(clipboard_promise), data));
return clipboard_promise->script_promise_resolver_->Promise();
}
+ScriptPromise ClipboardPromise::CreateForWriteImage(ScriptState* script_state,
+ Blob* data) {
+ ClipboardPromise* clipboard_promise =
+ MakeGarbageCollected<ClipboardPromise>(script_state);
+ clipboard_promise->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ WTF::Bind(&ClipboardPromise::HandleWriteImage,
+ WrapPersistent(clipboard_promise), WrapPersistent(data)));
+ return clipboard_promise->script_promise_resolver_->Promise();
+}
+
ClipboardPromise::ClipboardPromise(ScriptState* script_state)
: ContextLifecycleObserver(blink::ExecutionContext::From(script_state)),
script_state_(script_state),
@@ -179,6 +211,41 @@ void ClipboardPromise::HandleReadTextWithPermission(PermissionStatus status) {
script_promise_resolver_->Resolve(text);
}
+void ClipboardPromise::HandleReadImage() {
+ RequestReadPermission(WTF::Bind(
+ &ClipboardPromise::HandleReadImageWithPermission, WrapPersistent(this)));
+}
+
+void ClipboardPromise::HandleReadImageWithPermission(PermissionStatus status) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
+ if (status != PermissionStatus::GRANTED) {
+ script_promise_resolver_->Reject();
+ return;
+ }
+
+ SkBitmap bitmap = SystemClipboard::GetInstance().ReadImage(buffer_);
+
+ SkPixmap pixmap;
+ bitmap.peekPixels(&pixmap);
+
+ Vector<uint8_t> png_data;
+ SkPngEncoder::Options options;
+ if (!ImageEncoder::Encode(&png_data, pixmap, options)) {
+ script_promise_resolver_->Reject();
+ return;
+ }
+
+ std::unique_ptr<BlobData> data = BlobData::Create();
+ data->SetContentType(kMimeTypeImagePng);
+ data->AppendBytes(png_data.data(), png_data.size());
+ const uint64_t length = data->length();
+ scoped_refptr<BlobDataHandle> blob_data_handle =
+ BlobDataHandle::Create(std::move(data), length);
+
+ Blob* blob = Blob::Create(blob_data_handle);
+ script_promise_resolver_->Resolve(blob);
+}
+
// TODO(garykac): This currently only handles plain text.
void ClipboardPromise::HandleWrite(DataTransfer* data) {
// Scan DataTransfer and extract data types that we support.
@@ -212,20 +279,100 @@ void ClipboardPromise::HandleWriteText(const String& data) {
&ClipboardPromise::HandleWriteTextWithPermission, WrapPersistent(this)));
}
+void ClipboardPromise::HandleWriteImage(Blob* data) {
+ write_image_data_ = data;
+
+ CheckWritePermission(WTF::Bind(
+ &ClipboardPromise::HandleWriteImageWithPermission, WrapPersistent(this)));
+}
+
+void ClipboardPromise::HandleWriteImageWithPermission(PermissionStatus status) {
+ if (status != PermissionStatus::GRANTED) {
+ script_promise_resolver_->Reject();
+ return;
+ }
+
+ file_reader_ = std::make_unique<ClipboardFileReader>(write_image_data_, this);
+}
+
void ClipboardPromise::HandleWriteTextWithPermission(PermissionStatus status) {
if (status != PermissionStatus::GRANTED) {
script_promise_resolver_->Reject();
return;
}
- DCHECK(script_promise_resolver_);
SystemClipboard::GetInstance().WritePlainText(write_data_);
script_promise_resolver_->Resolve();
}
+void ClipboardPromise::OnLoadComplete(DOMArrayBuffer* array_buffer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
+ file_reader_.reset();
+
+ // Schedule async image decode on another thread.
+ background_scheduler::PostOnBackgroundThread(
+ FROM_HERE,
+ CrossThreadBind(&ClipboardPromise::DecodeImageOnBackgroundThread,
+ WrapCrossThreadPersistent(this), GetTaskRunner(),
+ WrapCrossThreadPersistent(array_buffer)));
+}
+
+// Reference: third_party/blink/renderer/core/imagebitmap/
+// TODO (crbug.com/916821): Ask ImageBitmapFactory owners if they can help
+// refactor and merge this very similar image decoding logic.
+void ClipboardPromise::DecodeImageOnBackgroundThread(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ DOMArrayBuffer* png_data) {
+ DCHECK(!IsMainThread());
+
+ std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
+ SegmentReader::CreateFromSkData(
+ SkData::MakeWithoutCopy(png_data->Data(), png_data->ByteLength())),
+ true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth,
+ ColorBehavior::Tag());
+
+ if (!decoder) {
+ PostCrossThreadTask(*task_runner, FROM_HERE,
+ CrossThreadBind(&ClipboardPromise::Reject,
+ WrapCrossThreadPersistent(this)));
+ return;
+ }
+
+ sk_sp<SkImage> image = ImageBitmap::GetSkImageFromDecoder(std::move(decoder));
+
+ if (!image) {
+ PostCrossThreadTask(*task_runner, FROM_HERE,
+ CrossThreadBind(&ClipboardPromise::Reject,
+ WrapCrossThreadPersistent(this)));
+ return;
+ }
+
+ PostCrossThreadTask(
+ *task_runner, FROM_HERE,
+ CrossThreadBind(&ClipboardPromise::ResolveAndWriteImage,
+ WrapCrossThreadPersistent(this), std::move(image)));
+}
+
+void ClipboardPromise::ResolveAndWriteImage(sk_sp<SkImage> image) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
+
+ SkBitmap bitmap;
+ image->asLegacyBitmap(&bitmap);
+
+ SystemClipboard::GetInstance().WriteImage(std::move(bitmap));
+ script_promise_resolver_->Resolve();
+}
+
+void ClipboardPromise::Reject() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
+
+ script_promise_resolver_->Reject();
+}
+
void ClipboardPromise::Trace(blink::Visitor* visitor) {
visitor->Trace(script_state_);
visitor->Trace(script_promise_resolver_);
+ visitor->Trace(write_image_data_);
ContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index e009bf4ec4f..061c691b0c3 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -5,11 +5,15 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_PROMISE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_PROMISE_H_
+#include "base/sequence_checker.h"
#include "third_party/blink/public/mojom/clipboard/clipboard.mojom-blink.h"
#include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/fileapi/blob.h"
+#include "third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h"
+#include "third_party/skia/include/core/SkImage.h"
namespace blink {
@@ -23,21 +27,32 @@ class ClipboardPromise final
WTF_MAKE_NONCOPYABLE(ClipboardPromise);
public:
- virtual ~ClipboardPromise() = default;
+ ClipboardPromise(ScriptState*);
+ virtual ~ClipboardPromise();
static ScriptPromise CreateForRead(ScriptState*);
static ScriptPromise CreateForReadText(ScriptState*);
+ // TODO (crbug.com/916823): Move ReadImage and WriteImage into Read/Write
+ // functions, so that the API surface doesn't change.
+ static ScriptPromise CreateForReadImage(ScriptState*);
static ScriptPromise CreateForWrite(ScriptState*, DataTransfer*);
static ScriptPromise CreateForWriteText(ScriptState*, const String&);
+ static ScriptPromise CreateForWriteImage(ScriptState*, Blob*);
+
+ void OnLoadComplete(DOMArrayBuffer*);
+ void Reject();
void Trace(blink::Visitor*) override;
private:
- ClipboardPromise(ScriptState*);
-
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner();
mojom::blink::PermissionService* GetPermissionService();
+ void DecodeImageOnBackgroundThread(
+ scoped_refptr<base::SingleThreadTaskRunner>,
+ DOMArrayBuffer*);
+ void ResolveAndWriteImage(sk_sp<SkImage>);
+
bool IsFocusedDocument(ExecutionContext*);
void RequestReadPermission(
@@ -51,18 +66,28 @@ class ClipboardPromise final
void HandleReadText();
void HandleReadTextWithPermission(mojom::blink::PermissionStatus);
+ void HandleReadImage();
+ void HandleReadImageWithPermission(mojom::blink::PermissionStatus);
+
void HandleWrite(DataTransfer*);
void HandleWriteWithPermission(mojom::blink::PermissionStatus);
void HandleWriteText(const String&);
void HandleWriteTextWithPermission(mojom::blink::PermissionStatus);
+ void HandleWriteImage(Blob*);
+ void HandleWriteImageWithPermission(mojom::blink::PermissionStatus);
+
Member<ScriptState> script_state_;
Member<ScriptPromiseResolver> script_promise_resolver_;
+ std::unique_ptr<ClipboardFileReader> file_reader_;
mojom::blink::PermissionServicePtr permission_service_;
mojom::ClipboardBuffer buffer_;
String write_data_;
+ Member<Blob> write_image_data_;
+
+ SEQUENCE_CHECKER(async_clipboard_sequence_checker);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/navigator_clipboard.cc b/chromium/third_party/blink/renderer/modules/clipboard/navigator_clipboard.cc
index dd69ceed67d..6042a93e35f 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/navigator_clipboard.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/navigator_clipboard.cc
@@ -32,10 +32,10 @@ void NavigatorClipboard::Trace(blink::Visitor* visitor) {
NavigatorClipboard::NavigatorClipboard(Navigator& navigator)
: Supplement<Navigator>(navigator) {
- clipboard_ =
- new Clipboard(GetSupplementable()->GetFrame()
- ? GetSupplementable()->GetFrame()->GetDocument()
- : nullptr);
+ clipboard_ = MakeGarbageCollected<Clipboard>(
+ GetSupplementable()->GetFrame()
+ ? GetSupplementable()->GetFrame()->GetDocument()
+ : nullptr);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/BUILD.gn b/chromium/third_party/blink/renderer/modules/contacts_picker/BUILD.gn
index d16f3e4282a..7a543ada813 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/BUILD.gn
@@ -6,8 +6,6 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("contacts_picker") {
sources = [
- "contact_info.cc",
- "contact_info.h",
"contacts_manager.cc",
"contacts_manager.h",
"navigator_contacts.cc",
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.cc b/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.cc
deleted file mode 100644
index 4da19fbcf59..00000000000
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/contacts_picker/contact_info.h"
-
-namespace blink {
-
-ContactInfo::ContactInfo(base::Optional<Vector<String>> name,
- base::Optional<Vector<String>> email,
- base::Optional<Vector<String>> tel)
- : name_(std::move(name)), email_(std::move(email)), tel_(std::move(tel)) {}
-
-ContactInfo::~ContactInfo() = default;
-
-const Vector<String> ContactInfo::name(bool& is_null) const {
- is_null = name_.has_value();
- return is_null ? Vector<String>() : name_.value();
-}
-
-const Vector<String> ContactInfo::email(bool& is_null) const {
- is_null = email_.has_value();
- return is_null ? Vector<String>() : email_.value();
-}
-
-const Vector<String> ContactInfo::tel(bool& is_null) const {
- is_null = tel_.has_value();
- return is_null ? Vector<String>() : tel_.value();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.h b/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.h
deleted file mode 100644
index 69fc36158b7..00000000000
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_INFO_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_INFO_H_
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-// Represents an individual Contact in the Contacts Picker.
-class ContactInfo final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- ContactInfo(base::Optional<Vector<String>> name,
- base::Optional<Vector<String>> email,
- base::Optional<Vector<String>> tel);
- ~ContactInfo() override;
-
- // Web-exposed attributes defined in the IDL file.
- const Vector<String> name(bool& is_null) const;
- const Vector<String> email(bool& is_null) const;
- const Vector<String> tel(bool& is_null) const;
-
- private:
- base::Optional<Vector<String>> name_;
- base::Optional<Vector<String>> email_;
- base::Optional<Vector<String>> tel_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_INFO_H_
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.idl b/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
index b9a5c45cf8a..82f06c5166f 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
@@ -4,12 +4,8 @@
// https://github.com/beverloo/contact-api
-[
- SecureContext,
- Exposed=Window,
- RuntimeEnabled=ContactsManager
-] interface ContactInfo {
- readonly attribute FrozenArray<DOMString>? name;
- readonly attribute FrozenArray<DOMString>? email;
- readonly attribute FrozenArray<DOMString>? tel;
+dictionary ContactInfo {
+ sequence<USVString> name;
+ sequence<USVString> email;
+ sequence<USVString> tel;
};
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc b/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
index ff5e8964abb..2512851c735 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
@@ -4,21 +4,141 @@
#include "third_party/blink/renderer/modules/contacts_picker/contacts_manager.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/contacts_picker/contact_info.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace mojo {
+
+template <>
+struct TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr> {
+ static blink::ContactInfo* Convert(
+ const blink::mojom::blink::ContactInfoPtr& contact);
+};
+
+blink::ContactInfo*
+TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr>::
+ Convert(const blink::mojom::blink::ContactInfoPtr& contact) {
+ blink::ContactInfo* contact_info = blink::ContactInfo::Create();
+
+ if (contact->name.has_value()) {
+ Vector<String> names;
+ names.ReserveInitialCapacity(contact->name->size());
+
+ for (const String& name : *contact->name)
+ names.push_back(name);
+
+ contact_info->setName(names);
+ }
+
+ if (contact->email.has_value()) {
+ Vector<String> emails;
+ emails.ReserveInitialCapacity(contact->email->size());
+
+ for (const String& email : *contact->email)
+ emails.push_back(email);
+
+ contact_info->setEmail(emails);
+ }
+
+ if (contact->tel.has_value()) {
+ Vector<String> numbers;
+ numbers.ReserveInitialCapacity(contact->tel->size());
+
+ for (const String& number : *contact->tel)
+ numbers.push_back(number);
+
+ contact_info->setTel(numbers);
+ }
+
+ return contact_info;
+}
+
+} // namespace mojo
namespace blink {
ContactsManager::ContactsManager() = default;
ContactsManager::~ContactsManager() = default;
+mojom::blink::ContactsManagerPtr& ContactsManager::GetContactsManager(
+ ScriptState* script_state) {
+ if (!contacts_manager_) {
+ ExecutionContext::From(script_state)
+ ->GetInterfaceProvider()
+ ->GetInterface(mojo::MakeRequest(&contacts_manager_));
+ }
+ return contacts_manager_;
+}
+
ScriptPromise ContactsManager::select(ScriptState* script_state,
ContactsSelectOptions* options) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- DOMException::Create(DOMExceptionCode::kNotSupportedError,
- "ContactsManager::select is not yet implemented"));
+ Document* document = To<Document>(ExecutionContext::From(script_state));
+ if (!LocalFrame::HasTransientUserActivation(document ? document->GetFrame()
+ : nullptr)) {
+ return ScriptPromise::Reject(
+ script_state, V8ThrowException::CreateTypeError(
+ script_state->GetIsolate(),
+ "A user gesture is required to call this method"));
+ }
+
+ if (!options->hasProperties() || !options->properties().size()) {
+ return ScriptPromise::Reject(script_state,
+ V8ThrowException::CreateTypeError(
+ script_state->GetIsolate(),
+ "At least one property must be provided"));
+ }
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ bool include_names = false;
+ bool include_emails = false;
+ bool include_tel = false;
+
+ for (const String& property : options->properties()) {
+ if (property == "name")
+ include_names = true;
+ else if (property == "email")
+ include_emails = true;
+ else if (property == "tel")
+ include_tel = true;
+ }
+
+ GetContactsManager(script_state)
+ ->Select(options->multiple(), include_names, include_emails, include_tel,
+ WTF::Bind(&ContactsManager::OnContactsSelected,
+ WrapPersistent(this), WrapPersistent(resolver)));
+
+ return promise;
+}
+
+void ContactsManager::OnContactsSelected(
+ ScriptPromiseResolver* resolver,
+ base::Optional<Vector<mojom::blink::ContactInfoPtr>> contacts) {
+ ScriptState* script_state = resolver->GetScriptState();
+ ScriptState::Scope scope(script_state);
+
+ if (!contacts.has_value()) {
+ resolver->Reject(V8ThrowException::CreateTypeError(
+ script_state->GetIsolate(), "Unable to open a contact selector"));
+ return;
+ }
+
+ HeapVector<Member<ContactInfo>> contacts_list;
+ for (const auto& contact : *contacts)
+ contacts_list.push_back(contact.To<blink::ContactInfo*>());
+
+ resolver->Resolve(contacts_list);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.h b/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.h
index 607c85db4cb..9bc77135cbe 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.h
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACTS_MANAGER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACTS_MANAGER_H_
+#include "third_party/blink/public/mojom/contacts/contacts_manager.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/modules/contacts_picker/contacts_select_options.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -12,6 +13,7 @@
namespace blink {
+class ScriptPromiseResolver;
class ScriptState;
// Represents an the ContactManager, providing access to Contacts.
@@ -25,6 +27,17 @@ class ContactsManager final : public ScriptWrappable {
// Web-exposed function defined in the IDL file.
ScriptPromise select(ScriptState* script_state,
ContactsSelectOptions* options);
+
+ private:
+ mojom::blink::ContactsManagerPtr& GetContactsManager(
+ ScriptState* script_state);
+
+ void OnContactsSelected(
+ ScriptPromiseResolver* resolver,
+ base::Optional<Vector<mojom::blink::ContactInfoPtr>> contacts);
+
+ // Created lazily.
+ mojom::blink::ContactsManagerPtr contacts_manager_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl b/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
index 06c67e76a8d..be86b928830 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
@@ -7,7 +7,7 @@
[
Exposed=Window,
SecureContext,
- RuntimeEnabled=ContactsManager
+ OriginTrialEnabled=ContactsManager
] interface ContactsManager {
- [CallWith=ScriptState] Promise<FrozenArray<ContactInfo>> select(ContactsSelectOptions options);
+ [CallWith=ScriptState] Promise<sequence<ContactInfo>> select(ContactsSelectOptions options);
};
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.cc b/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.cc
index 006c354a17c..f1afab2f319 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.cc
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.cc
@@ -17,7 +17,7 @@ NavigatorContacts& NavigatorContacts::From(Navigator& navigator) {
NavigatorContacts* supplement =
Supplement<Navigator>::From<NavigatorContacts>(navigator);
if (!supplement) {
- supplement = new NavigatorContacts(navigator);
+ supplement = MakeGarbageCollected<NavigatorContacts>(navigator);
ProvideTo(navigator, supplement);
}
return *supplement;
@@ -31,7 +31,7 @@ ContactsManager* NavigatorContacts::contacts(Navigator& navigator) {
ContactsManager* NavigatorContacts::contacts() {
if (!contacts_manager_)
- contacts_manager_ = new ContactsManager();
+ contacts_manager_ = MakeGarbageCollected<ContactsManager>();
return contacts_manager_;
}
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.h b/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.h
index b5b16b03628..2014315ae0b 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.h
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.h
@@ -27,11 +27,11 @@ class NavigatorContacts final : public GarbageCollected<NavigatorContacts>,
static ContactsManager* contacts(Navigator& navigator);
ContactsManager* contacts();
+ explicit NavigatorContacts(Navigator& navigator);
+
void Trace(Visitor* visitor) override;
private:
- explicit NavigatorContacts(Navigator& navigator);
-
Member<ContactsManager> contacts_manager_;
};
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl b/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl
index bb47e9c72ef..cfc26d1bba1 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl
@@ -8,5 +8,5 @@
Exposed=Window,
ImplementedAs=NavigatorContacts
] partial interface Navigator {
- [SecureContext, RuntimeEnabled=ContactsManager] readonly attribute ContactsManager contacts;
+ [SecureContext, OriginTrialEnabled=ContactsManager] readonly attribute ContactsManager contacts;
};
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h
index 910e49a78ac..c473dfbe7ac 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h
@@ -20,7 +20,9 @@ class CookieChangeEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
- static CookieChangeEvent* Create() { return new CookieChangeEvent(); }
+ static CookieChangeEvent* Create() {
+ return MakeGarbageCollected<CookieChangeEvent>();
+ }
// Used by Blink.
//
@@ -29,15 +31,22 @@ class CookieChangeEvent final : public Event {
static CookieChangeEvent* Create(const AtomicString& type,
HeapVector<Member<CookieListItem>> changed,
HeapVector<Member<CookieListItem>> deleted) {
- return new CookieChangeEvent(type, std::move(changed), std::move(deleted));
+ return MakeGarbageCollected<CookieChangeEvent>(type, std::move(changed),
+ std::move(deleted));
}
// Used by JavaScript, via the V8 bindings.
static CookieChangeEvent* Create(const AtomicString& type,
const CookieChangeEventInit* initializer) {
- return new CookieChangeEvent(type, initializer);
+ return MakeGarbageCollected<CookieChangeEvent>(type, initializer);
}
+ CookieChangeEvent();
+ CookieChangeEvent(const AtomicString& type,
+ HeapVector<Member<CookieListItem>> changed,
+ HeapVector<Member<CookieListItem>> deleted);
+ CookieChangeEvent(const AtomicString& type,
+ const CookieChangeEventInit* initializer);
~CookieChangeEvent() override;
const HeapVector<Member<CookieListItem>>& changed() const { return changed_; }
@@ -60,13 +69,6 @@ class CookieChangeEvent final : public Event {
HeapVector<Member<CookieListItem>>& deleted);
private:
- CookieChangeEvent();
- CookieChangeEvent(const AtomicString& type,
- HeapVector<Member<CookieListItem>> changed,
- HeapVector<Member<CookieListItem>> deleted);
- CookieChangeEvent(const AtomicString& type,
- const CookieChangeEventInit* initializer);
-
HeapVector<Member<CookieListItem>> changed_;
HeapVector<Member<CookieListItem>> deleted_;
};
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
index 0f5e5a02ae5..81930536591 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -592,8 +592,12 @@ void CookieStore::StartObserving() {
if (change_listener_binding_ || !backend_)
return;
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
network::mojom::blink::CookieChangeListenerPtr change_listener;
- change_listener_binding_.Bind(mojo::MakeRequest(&change_listener));
+ change_listener_binding_.Bind(
+ mojo::MakeRequest(&change_listener, task_runner), task_runner);
backend_->AddChangeListener(default_cookie_url_, default_site_for_cookies_,
std::move(change_listener), {});
}
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.h b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.h
index 3eb76bf3fd9..ef8204a3a93 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.h
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.h
@@ -34,6 +34,9 @@ class CookieStore final : public EventTargetWithInlineData,
USING_GARBAGE_COLLECTED_MIXIN(CookieStore);
public:
+ CookieStore(ExecutionContext*,
+ network::mojom::blink::RestrictedCookieManagerPtr backend,
+ blink::mojom::blink::CookieStorePtr subscription_backend);
// Needed because of the network::mojom::blink::RestrictedCookieManagerPtr
~CookieStore() override;
@@ -41,8 +44,8 @@ class CookieStore final : public EventTargetWithInlineData,
ExecutionContext* execution_context,
network::mojom::blink::RestrictedCookieManagerPtr backend,
blink::mojom::blink::CookieStorePtr subscription_backend) {
- return new CookieStore(execution_context, std::move(backend),
- std::move(subscription_backend));
+ return MakeGarbageCollected<CookieStore>(
+ execution_context, std::move(backend), std::move(subscription_backend));
}
ScriptPromise getAll(ScriptState*, const String& name, ExceptionState&);
@@ -78,7 +81,7 @@ class CookieStore final : public EventTargetWithInlineData,
ContextLifecycleObserver::Trace(visitor);
}
- // ActiveScriptWrappable
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// EventTargetWithInlineData
@@ -102,10 +105,6 @@ class CookieStore final : public EventTargetWithInlineData,
using DoReadBackendResultConverter =
void (*)(ScriptPromiseResolver*, const Vector<WebCanonicalCookie>&);
- CookieStore(ExecutionContext*,
- network::mojom::blink::RestrictedCookieManagerPtr backend,
- blink::mojom::blink::CookieStorePtr subscription_backend);
-
// Common code in CookieStore::{get,getAll}.
//
// All cookie-reading methods use the same RestrictedCookieManager API, and
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc b/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
index eb378d47a7d..2e80e9ba730 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
@@ -20,8 +20,10 @@ CookieStore* GlobalCookieStoreImpl<LocalDOMWindow>::BuildCookieStore(
ExecutionContext* execution_context,
service_manager::InterfaceProvider* interface_provider) {
network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr;
- interface_provider->GetInterface(mojo::MakeRequest(&cookie_manager_ptr));
-
+ // See https://bit.ly/2S0zRAS for task types.
+ interface_provider->GetInterface(mojo::MakeRequest(
+ &cookie_manager_ptr,
+ execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
return CookieStore::Create(execution_context, std::move(cookie_manager_ptr),
blink::mojom::blink::CookieStorePtr());
}
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.cc
index 75a3817d0df..d0439a8e356 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.cc
@@ -11,7 +11,7 @@ AuthenticatorAssertionResponse* AuthenticatorAssertionResponse::Create(
DOMArrayBuffer* authenticator_data,
DOMArrayBuffer* signature,
DOMArrayBuffer* user_handle) {
- return new AuthenticatorAssertionResponse(
+ return MakeGarbageCollected<AuthenticatorAssertionResponse>(
client_data_json, authenticator_data, signature, user_handle);
}
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.h b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.h
index be369cdc710..358816ef18b 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_assertion_response.h
@@ -23,6 +23,10 @@ class MODULES_EXPORT AuthenticatorAssertionResponse final
DOMArrayBuffer* signature,
DOMArrayBuffer* user_handle);
+ explicit AuthenticatorAssertionResponse(DOMArrayBuffer* client_data_json,
+ DOMArrayBuffer* authenticator_data,
+ DOMArrayBuffer* signature,
+ DOMArrayBuffer* user_handle);
~AuthenticatorAssertionResponse() override;
DOMArrayBuffer* authenticatorData() const {
@@ -36,10 +40,6 @@ class MODULES_EXPORT AuthenticatorAssertionResponse final
void Trace(blink::Visitor*) override;
private:
- explicit AuthenticatorAssertionResponse(DOMArrayBuffer* client_data_json,
- DOMArrayBuffer* authenticator_data,
- DOMArrayBuffer* signature,
- DOMArrayBuffer* user_handle);
const Member<DOMArrayBuffer> authenticator_data_;
const Member<DOMArrayBuffer> signature_;
const Member<DOMArrayBuffer> user_handle_;
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc
index e7b9e67b932..0d8e9672122 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc
@@ -12,7 +12,7 @@ AuthenticatorAttestationResponse* AuthenticatorAttestationResponse::Create(
DOMArrayBuffer* client_data_json,
DOMArrayBuffer* attestation_object,
Vector<mojom::AuthenticatorTransport> transports) {
- return new AuthenticatorAttestationResponse(
+ return MakeGarbageCollected<AuthenticatorAttestationResponse>(
client_data_json, attestation_object, std::move(transports));
}
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h
index c0ffb0cb22d..98309d29d56 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h
@@ -25,6 +25,10 @@ class MODULES_EXPORT AuthenticatorAttestationResponse final
DOMArrayBuffer* attestation_object,
Vector<mojom::AuthenticatorTransport> transports);
+ AuthenticatorAttestationResponse(
+ DOMArrayBuffer* client_data_json,
+ DOMArrayBuffer* attestation_object,
+ Vector<mojom::AuthenticatorTransport> transports);
~AuthenticatorAttestationResponse() override;
DOMArrayBuffer* attestationObject() const {
@@ -36,11 +40,6 @@ class MODULES_EXPORT AuthenticatorAttestationResponse final
void Trace(blink::Visitor*) override;
private:
- AuthenticatorAttestationResponse(
- DOMArrayBuffer* client_data_json,
- DOMArrayBuffer* attestation_object,
- Vector<mojom::AuthenticatorTransport> transports);
-
const Member<DOMArrayBuffer> attestation_object_;
const Vector<mojom::AuthenticatorTransport> transports_;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.cc
index d874e2aa075..014ae326c3a 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.cc
@@ -8,7 +8,7 @@ namespace blink {
AuthenticatorResponse* AuthenticatorResponse::Create(
DOMArrayBuffer* client_data_json) {
- return new AuthenticatorResponse(client_data_json);
+ return MakeGarbageCollected<AuthenticatorResponse>(client_data_json);
}
AuthenticatorResponse::AuthenticatorResponse(DOMArrayBuffer* client_data_json)
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.h b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.h
index 8a99424f283..2fb89f7d14b 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_response.h
@@ -18,15 +18,13 @@ class MODULES_EXPORT AuthenticatorResponse : public ScriptWrappable {
public:
static AuthenticatorResponse* Create(DOMArrayBuffer* client_data_json);
+ explicit AuthenticatorResponse(DOMArrayBuffer* client_data_json);
~AuthenticatorResponse() override;
DOMArrayBuffer* clientDataJSON() const { return client_data_json_.Get(); }
void Trace(blink::Visitor*) override;
- protected:
- explicit AuthenticatorResponse(DOMArrayBuffer* client_data_json);
-
private:
const Member<DOMArrayBuffer> client_data_json_;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_creation_options.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_creation_options.idl
index 9b6eb3c2bb3..ec630b60e8b 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_creation_options.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_creation_options.idl
@@ -9,7 +9,7 @@
typedef (PasswordCredentialData or HTMLFormElement) PasswordCredentialInit;
dictionary CredentialCreationOptions {
- PasswordCredentialInit? password;
- FederatedCredentialInit? federated;
- PublicKeyCredentialCreationOptions? publicKey;
+ PasswordCredentialInit password;
+ FederatedCredentialInit federated;
+ PublicKeyCredentialCreationOptions publicKey;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc
index aa6950e46b3..774efbc8f05 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc
@@ -15,9 +15,10 @@ namespace blink {
CredentialManagerProxy::CredentialManagerProxy(Document& document) {
LocalFrame* frame = document.GetFrame();
DCHECK(frame);
- frame->GetInterfaceProvider().GetInterface(&credential_manager_);
frame->GetInterfaceProvider().GetInterface(
- mojo::MakeRequest(&authenticator_));
+ &credential_manager_, frame->GetTaskRunner(TaskType::kUserInteraction));
+ frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(
+ &authenticator_, frame->GetTaskRunner(TaskType::kUserInteraction)));
}
CredentialManagerProxy::~CredentialManagerProxy() {}
@@ -27,7 +28,7 @@ CredentialManagerProxy* CredentialManagerProxy::From(Document& document) {
auto* supplement =
Supplement<Document>::From<CredentialManagerProxy>(document);
if (!supplement) {
- supplement = new CredentialManagerProxy(document);
+ supplement = MakeGarbageCollected<CredentialManagerProxy>(document);
ProvideTo(document, supplement);
}
return supplement;
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl
index 8e472655cf8..d413c468527 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl
@@ -11,10 +11,10 @@ enum CredentialMediationRequirement {
};
dictionary CredentialRequestOptions {
- FederatedCredentialRequestOptions? federated;
+ FederatedCredentialRequestOptions federated;
boolean password = false;
CredentialMediationRequirement mediation = "optional";
- PublicKeyCredentialRequestOptions? publicKey;
+ PublicKeyCredentialRequestOptions publicKey;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index a2e73b6710e..fee856ff982 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -417,7 +417,7 @@ void OnGetAssertionComplete(
} // namespace
CredentialsContainer* CredentialsContainer::Create() {
- return new CredentialsContainer();
+ return MakeGarbageCollected<CredentialsContainer>();
}
CredentialsContainer::CredentialsContainer() = default;
@@ -622,7 +622,16 @@ ScriptPromise CredentialsContainer::create(
auto mojo_options =
MojoPublicKeyCredentialCreationOptions::From(options->publicKey());
- if (mojo_options) {
+ if (!mojo_options) {
+ resolver->Reject(DOMException::Create(
+ DOMExceptionCode::kNotSupportedError,
+ "Required parameters missing in `options.publicKey`."));
+ } else if (mojo_options->user->id.size() > 64) {
+ // https://www.w3.org/TR/webauthn/#user-handle
+ v8::Isolate* isolate = resolver->GetScriptState()->GetIsolate();
+ resolver->Reject(V8ThrowException::CreateTypeError(
+ isolate, "User handle exceeds 64 bytes."));
+ } else {
if (!mojo_options->relying_party->id) {
mojo_options->relying_party->id = resolver->GetFrame()
->GetSecurityContext()
@@ -636,10 +645,6 @@ ScriptPromise CredentialsContainer::create(
WTF::Bind(
&OnMakePublicKeyCredentialComplete,
WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver))));
- } else {
- resolver->Reject(DOMException::Create(
- DOMExceptionCode::kNotSupportedError,
- "Required parameters missing in `options.publicKey`."));
}
}
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.h
index 0c82cc68361..78eae043005 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.h
@@ -24,6 +24,8 @@ class MODULES_EXPORT CredentialsContainer final : public ScriptWrappable {
public:
static CredentialsContainer* Create();
+ CredentialsContainer();
+
// CredentialsContainer.idl
ScriptPromise get(ScriptState*, const CredentialRequestOptions*);
ScriptPromise store(ScriptState*, Credential* = nullptr);
@@ -31,9 +33,6 @@ class MODULES_EXPORT CredentialsContainer final : public ScriptWrappable {
const CredentialCreationOptions*,
ExceptionState&);
ScriptPromise preventSilentAccess(ScriptState*);
-
- private:
- CredentialsContainer();
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.idl
index 075f8ee3f10..1ff690c2b7e 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.idl
@@ -6,8 +6,8 @@
[Exposed=Window, SecureContext]
interface CredentialsContainer {
- [CallWith=ScriptState, MeasureAs=CredentialManagerGet] Promise get(optional CredentialRequestOptions options);
- [CallWith=ScriptState, MeasureAs=CredentialManagerStore] Promise store(Credential credential);
- [CallWith=ScriptState, RaisesException, MeasureAs=CredentialManagerCreate] Promise create(optional CredentialCreationOptions options);
- [CallWith=ScriptState, MeasureAs=CredentialManagerPreventSilentAccess] Promise preventSilentAccess();
+ [CallWith=ScriptState, MeasureAs=CredentialManagerGet] Promise<Credential?> get(optional CredentialRequestOptions options);
+ [CallWith=ScriptState, MeasureAs=CredentialManagerStore] Promise<Credential> store(Credential credential);
+ [CallWith=ScriptState, RaisesException, MeasureAs=CredentialManagerCreate] Promise<Credential?> create(optional CredentialCreationOptions options);
+ [CallWith=ScriptState, MeasureAs=CredentialManagerPreventSilentAccess] Promise<void> preventSilentAccess();
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.idl
index cb5b0919a55..76bcc33083a 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.idl
@@ -11,6 +11,6 @@
] interface PublicKeyCredential : Credential {
[SameObject] readonly attribute ArrayBuffer rawId;
[SameObject] readonly attribute AuthenticatorResponse response;
- [CallWith=ScriptState] static Promise <boolean> isUserVerifyingPlatformAuthenticatorAvailable();
+ [CallWith=ScriptState] static Promise<boolean> isUserVerifyingPlatformAuthenticatorAvailable();
AuthenticationExtensionsClientOutputs getClientExtensionResults();
};
diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto.h b/chromium/third_party/blink/renderer/modules/crypto/crypto.h
index 8d9affb425b..e65387dc0cd 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/crypto.h
+++ b/chromium/third_party/blink/renderer/modules/crypto/crypto.h
@@ -42,7 +42,9 @@ class Crypto final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static Crypto* Create() { return new Crypto(); }
+ static Crypto* Create() { return MakeGarbageCollected<Crypto>(); }
+
+ Crypto() = default;
NotShared<DOMArrayBufferView> getRandomValues(NotShared<DOMArrayBufferView>,
ExceptionState&);
@@ -52,8 +54,6 @@ class Crypto final : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
- Crypto() = default;
-
Member<SubtleCrypto> subtle_crypto_;
};
diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc b/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc
index 8d2319a5a68..39da74d770c 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc
+++ b/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/modules/crypto/crypto_key.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
#include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -80,7 +81,7 @@ static_assert(kEndOfWebCryptoKeyUsage == (1 << 7) + 1,
"keyUsageMappings needs to be updated");
const char* KeyUsageToString(WebCryptoKeyUsage usage) {
- for (size_t i = 0; i < arraysize(kKeyUsageMappings); ++i) {
+ for (size_t i = 0; i < base::size(kKeyUsageMappings); ++i) {
if (kKeyUsageMappings[i].value == usage)
return kKeyUsageMappings[i].name;
}
@@ -89,7 +90,7 @@ const char* KeyUsageToString(WebCryptoKeyUsage usage) {
}
WebCryptoKeyUsageMask KeyUsageStringToMask(const String& usage_string) {
- for (size_t i = 0; i < arraysize(kKeyUsageMappings); ++i) {
+ for (size_t i = 0; i < base::size(kKeyUsageMappings); ++i) {
if (kKeyUsageMappings[i].name == usage_string)
return kKeyUsageMappings[i].value;
}
@@ -158,7 +159,7 @@ ScriptValue CryptoKey::algorithm(ScriptState* script_state) {
// different).
ScriptValue CryptoKey::usages(ScriptState* script_state) {
Vector<String> result;
- for (size_t i = 0; i < arraysize(kKeyUsageMappings); ++i) {
+ for (size_t i = 0; i < base::size(kKeyUsageMappings); ++i) {
WebCryptoKeyUsage usage = kKeyUsageMappings[i].value;
if (key_.Usages() & usage)
result.push_back(KeyUsageToString(usage));
diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto_key.h b/chromium/third_party/blink/renderer/modules/crypto/crypto_key.h
index 25956370cbc..5ad72462b07 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/crypto_key.h
+++ b/chromium/third_party/blink/renderer/modules/crypto/crypto_key.h
@@ -48,9 +48,10 @@ class MODULES_EXPORT CryptoKey final : public ScriptWrappable {
public:
static CryptoKey* Create(const WebCryptoKey& key) {
- return new CryptoKey(key);
+ return MakeGarbageCollected<CryptoKey>(key);
}
+ explicit CryptoKey(const WebCryptoKey&);
~CryptoKey() override;
String type() const;
@@ -73,8 +74,6 @@ class MODULES_EXPORT CryptoKey final : public ScriptWrappable {
CryptoResult*);
protected:
- explicit CryptoKey(const WebCryptoKey&);
-
const WebCryptoKey key_;
};
diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc b/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc
index 91e9cb555e8..5252b6db429 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc
@@ -65,12 +65,14 @@ class CryptoResultImpl::Resolver final : public ScriptPromiseResolver {
public:
static Resolver* Create(ScriptState* script_state, CryptoResultImpl* result) {
DCHECK(script_state->ContextIsValid());
- Resolver* resolver = new Resolver(script_state, result);
- resolver->PauseIfNeeded();
+ Resolver* resolver = MakeGarbageCollected<Resolver>(script_state, result);
resolver->KeepAliveWhilePending();
return resolver;
}
+ Resolver(ScriptState* script_state, CryptoResultImpl* result)
+ : ScriptPromiseResolver(script_state), result_(result) {}
+
void ContextDestroyed(ExecutionContext* destroyed_context) override {
result_->Cancel();
result_ = nullptr;
@@ -83,22 +85,9 @@ class CryptoResultImpl::Resolver final : public ScriptPromiseResolver {
}
private:
- Resolver(ScriptState* script_state, CryptoResultImpl* result)
- : ScriptPromiseResolver(script_state), result_(result) {}
-
Member<CryptoResultImpl> result_;
};
-CryptoResultImpl::ResultCancel::ResultCancel() : cancelled_(0) {}
-
-bool CryptoResultImpl::ResultCancel::Cancelled() const {
- return AcquireLoad(&cancelled_);
-}
-
-void CryptoResultImpl::ResultCancel::Cancel() {
- ReleaseStore(&cancelled_, 1);
-}
-
ExceptionCode WebCryptoErrorToExceptionCode(WebCryptoErrorType error_type) {
switch (error_type) {
case kWebCryptoErrorTypeNotSupported:
@@ -121,7 +110,7 @@ ExceptionCode WebCryptoErrorToExceptionCode(WebCryptoErrorType error_type) {
CryptoResultImpl::CryptoResultImpl(ScriptState* script_state)
: resolver_(Resolver::Create(script_state, this)),
- cancel_(ResultCancel::Create()) {
+ cancel_(base::MakeRefCounted<CryptoResultCancel>()) {
// Sync cancellation state.
if (ExecutionContext::From(script_state)->IsContextDestroyed())
cancel_->Cancel();
@@ -141,7 +130,7 @@ void CryptoResultImpl::ClearResolver() {
}
CryptoResultImpl* CryptoResultImpl::Create(ScriptState* script_state) {
- return new CryptoResultImpl(script_state);
+ return MakeGarbageCollected<CryptoResultImpl>(script_state);
}
void CryptoResultImpl::CompleteWithError(WebCryptoErrorType error_type,
diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.h b/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.h
index f404121d8fc..f1e97954d79 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.h
+++ b/chromium/third_party/blink/renderer/modules/crypto/crypto_result_impl.h
@@ -57,6 +57,7 @@ class MODULES_EXPORT CryptoResultImpl final : public CryptoResult {
public:
static CryptoResultImpl* Create(ScriptState*);
+ explicit CryptoResultImpl(ScriptState*);
~CryptoResultImpl() override;
void CompleteWithError(WebCryptoErrorType, const WebString&) override;
@@ -77,23 +78,6 @@ class MODULES_EXPORT CryptoResultImpl final : public CryptoResult {
private:
class Resolver;
- class ResultCancel : public CryptoResultCancel {
- public:
- static scoped_refptr<ResultCancel> Create() {
- return base::AdoptRef(new ResultCancel);
- }
-
- bool Cancelled() const override;
-
- void Cancel();
-
- private:
- ResultCancel();
-
- int cancelled_;
- };
-
- explicit CryptoResultImpl(ScriptState*);
void Cancel();
void ClearResolver();
@@ -109,7 +93,7 @@ class MODULES_EXPORT CryptoResultImpl final : public CryptoResult {
// check cancellation status via this result object. So, keep a separate
// cancellation status object for the purpose, which will outlive the
// result object and can be safely accessed by multiple threads.
- scoped_refptr<ResultCancel> cancel_;
+ scoped_refptr<CryptoResultCancel> cancel_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc b/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc
index d2b2e118d7e..89e26470f6f 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc
+++ b/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc
@@ -32,6 +32,9 @@
#include <algorithm>
#include <memory>
+
+#include "base/stl_util.h"
+#include "base/strings/char_traits.h"
#include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
@@ -86,7 +89,7 @@ const AlgorithmNameMapping kAlgorithmNameMappings[] = {
// Reminder to update the table mapping names to IDs whenever adding a new
// algorithm ID.
static_assert(kWebCryptoAlgorithmIdLast + 1 ==
- arraysize(kAlgorithmNameMappings),
+ base::size(kAlgorithmNameMappings),
"algorithmNameMappings needs to be updated");
#if DCHECK_IS_ON()
@@ -177,7 +180,7 @@ bool LookupAlgorithmIdByName(const String& algorithm_name,
WebCryptoAlgorithmId& id) {
const AlgorithmNameMapping* begin = kAlgorithmNameMappings;
const AlgorithmNameMapping* end =
- kAlgorithmNameMappings + arraysize(kAlgorithmNameMappings);
+ kAlgorithmNameMappings + base::size(kAlgorithmNameMappings);
#if DCHECK_IS_ON()
DCHECK(VerifyAlgorithmNameMappings(begin, end));
@@ -228,16 +231,18 @@ class ErrorContext {
return String();
StringBuilder result;
- constexpr const char* separator = ": ";
+ constexpr const char* const separator = ": ";
+ constexpr wtf_size_t separator_length =
+ base::CharTraits<char>::length(separator);
- wtf_size_t length = (messages_.size() - 1) * strlen(separator);
+ wtf_size_t length = (messages_.size() - 1) * separator_length;
for (wtf_size_t i = 0; i < messages_.size(); ++i)
length += strlen(messages_[i]);
result.ReserveCapacity(length);
for (wtf_size_t i = 0; i < messages_.size(); ++i) {
if (i)
- result.Append(separator, strlen(separator));
+ result.Append(separator, separator_length);
result.Append(messages_[i],
static_cast<wtf_size_t>(strlen(messages_[i])));
}
@@ -772,7 +777,7 @@ const CurveNameMapping kCurveNameMappings[] = {
{"P-521", kWebCryptoNamedCurveP521}};
// Reminder to update curveNameMappings when adding a new curve.
-static_assert(kWebCryptoNamedCurveLast + 1 == arraysize(kCurveNameMappings),
+static_assert(kWebCryptoNamedCurveLast + 1 == base::size(kCurveNameMappings),
"curveNameMappings needs to be updated");
bool ParseNamedCurve(const Dictionary& raw,
@@ -786,7 +791,7 @@ bool ParseNamedCurve(const Dictionary& raw,
return false;
}
- for (size_t i = 0; i < arraysize(kCurveNameMappings); ++i) {
+ for (size_t i = 0; i < base::size(kCurveNameMappings); ++i) {
if (kCurveNameMappings[i].name == named_curve_string) {
named_curve = kCurveNameMappings[i].value;
return true;
diff --git a/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc b/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc
index 5ea5e94ae14..5ab2feffd4f 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc
+++ b/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/modules/crypto/subtle_crypto.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_crypto.h"
@@ -149,7 +150,7 @@ static bool ParseJsonWebKey(const Dictionary& dict,
const char* const kPropertyNames[] = {"d", "n", "e", "p", "q", "dp",
"dq", "qi", "k", "crv", "x", "y"};
- for (unsigned i = 0; i < arraysize(kPropertyNames); ++i)
+ for (unsigned i = 0; i < base::size(kPropertyNames); ++i)
CopyStringProperty(kPropertyNames[i], dict, json_object.get());
String json = json_object->ToJSONString();
diff --git a/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.idl b/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.idl
index c5c75b0150a..e7287cba725 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.idl
+++ b/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.idl
@@ -37,16 +37,19 @@ typedef (Dictionary or DOMString) AlgorithmIdentifier;
[
Exposed=(Window,Worker)
] interface SubtleCrypto {
- [CallWith=ScriptState, MeasureAs=SubtleCryptoEncrypt] Promise encrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoDecrypt] Promise decrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoSign] Promise sign(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
- [CallWith=ScriptState, ImplementedAs=verifySignature, MeasureAs=SubtleCryptoVerify] Promise verify(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource signature, BufferSource data);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoDigest] Promise digest(AlgorithmIdentifier algorithm, BufferSource data);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoGenerateKey] Promise generateKey(AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoImportKey] Promise importKey(KeyFormat format, (ArrayBuffer or ArrayBufferView or Dictionary) keyData, AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoExportKey] Promise exportKey(KeyFormat format, CryptoKey key);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoDeriveBits] Promise deriveBits(AlgorithmIdentifier algorithm, CryptoKey baseKey, unsigned long length);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoDeriveKey] Promise deriveKey(AlgorithmIdentifier algorithm, CryptoKey baseKey, AlgorithmIdentifier derivedKeyType, boolean extractable, sequence<KeyUsage> keyUsages);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoWrapKey] Promise wrapKey(KeyFormat format, CryptoKey key, CryptoKey wrappingKey, AlgorithmIdentifier wrapAlgorithm);
- [CallWith=ScriptState, MeasureAs=SubtleCryptoUnwrapKey] Promise unwrapKey(KeyFormat format, BufferSource wrappedKey, CryptoKey unwrappingKey, AlgorithmIdentifier unwrapAlgorithm, AlgorithmIdentifier unwrappedKeyAlgorithm, boolean extractable, sequence<KeyUsage> keyUsages);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoEncrypt] Promise<any> encrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoDecrypt] Promise<any> decrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoSign] Promise<any> sign(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
+ [CallWith=ScriptState, ImplementedAs=verifySignature, MeasureAs=SubtleCryptoVerify] Promise<any> verify(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource signature, BufferSource data);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoDigest] Promise<any> digest(AlgorithmIdentifier algorithm, BufferSource data);
+
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoGenerateKey] Promise<any> generateKey(AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoDeriveKey] Promise<any> deriveKey(AlgorithmIdentifier algorithm, CryptoKey baseKey, AlgorithmIdentifier derivedKeyType, boolean extractable, sequence<KeyUsage> keyUsages);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoDeriveBits] Promise<ArrayBuffer> deriveBits(AlgorithmIdentifier algorithm, CryptoKey baseKey, unsigned long length);
+
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoImportKey] Promise<CryptoKey> importKey(KeyFormat format, (ArrayBuffer or ArrayBufferView or Dictionary) keyData, AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoExportKey] Promise<any> exportKey(KeyFormat format, CryptoKey key);
+
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoWrapKey] Promise<any> wrapKey(KeyFormat format, CryptoKey key, CryptoKey wrappingKey, AlgorithmIdentifier wrapAlgorithm);
+ [CallWith=ScriptState, MeasureAs=SubtleCryptoUnwrapKey] Promise<CryptoKey> unwrapKey(KeyFormat format, BufferSource wrappedKey, CryptoKey unwrappingKey, AlgorithmIdentifier unwrapAlgorithm, AlgorithmIdentifier unwrappedKeyAlgorithm, boolean extractable, sequence<KeyUsage> keyUsages);
};
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc b/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc
index e27b374024f..444a6279b39 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc
@@ -154,8 +154,8 @@ void CSSPaintDefinition::MaybeCreatePaintInstance() {
}
void CSSPaintDefinition::Trace(Visitor* visitor) {
- visitor->Trace(constructor_.Cast<v8::Value>());
- visitor->Trace(paint_.Cast<v8::Value>());
+ visitor->Trace(constructor_);
+ visitor->Trace(paint_);
visitor->Trace(instance_);
visitor->Trace(context_settings_);
visitor->Trace(script_state_);
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
index ddfbde175a4..9d390fa346e 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
@@ -49,9 +49,7 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
// is always clean, and unable to taint it.
bool OriginClean() const final { return true; }
void SetOriginTainted() final {}
- bool WouldTaintOrigin(CanvasImageSource*, ExecutionContext*) final {
- return false;
- }
+ bool WouldTaintOrigin(CanvasImageSource*) final { return false; }
int Width() const final;
int Height() const final;
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
index e7f43a5a2d2..a9a9f03ca4d 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
@@ -58,10 +58,10 @@
void clip(optional CanvasFillRule winding);
void clip(Path2D path, optional CanvasFillRule winding);
- boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
- boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
- boolean isPointInStroke(unrestricted double x, unrestricted double y);
- boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
+ [HighEntropy, Measure] boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
+ [HighEntropy, Measure] boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule winding);
+ [HighEntropy, Measure] boolean isPointInStroke(unrestricted double x, unrestricted double y);
+ [HighEntropy, Measure] boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
// drawing images
[CallWith=ScriptState, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y);
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc
index 62ef724e5d4..aeb254e4a58 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc
@@ -40,7 +40,8 @@ PaintWorklet* PaintWorklet::Create(LocalFrame* frame) {
PaintWorklet::PaintWorklet(LocalFrame* frame)
: Worklet(frame->GetDocument()),
Supplement<LocalDOMWindow>(*frame->DomWindow()),
- pending_generator_registry_(new PaintWorkletPendingGeneratorRegistry) {}
+ pending_generator_registry_(
+ MakeGarbageCollected<PaintWorkletPendingGeneratorRegistry>()) {}
PaintWorklet::~PaintWorklet() = default;
@@ -139,7 +140,7 @@ WorkletGlobalScopeProxy* PaintWorklet::CreateGlobalScope() {
ProvidePaintWorkletProxyClientTo(worker_clients, proxy_client);
PaintWorkletMessagingProxy* proxy =
- new PaintWorkletMessagingProxy(GetExecutionContext());
+ MakeGarbageCollected<PaintWorkletMessagingProxy>(GetExecutionContext());
proxy->Initialize(worker_clients, ModuleResponsesMap());
return proxy;
}
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc
index 833e8272875..523e734dcd8 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc
@@ -41,7 +41,8 @@ PaintWorkletGlobalScopeProxy::PaintWorkletGlobalScopeProxy(
worker_clients, frame->Client()->CreateWorkerContentSettingsClient());
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled, document->UserAgent(),
frame->Client()->CreateWorkerFetchContext(),
document->GetContentSecurityPolicy()->Headers(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_test.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_test.cc
index 8efc3188a48..7ba26c617d3 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_test.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_test.cc
@@ -61,14 +61,16 @@ class PaintWorkletGlobalScopeTest : public PageTestBase {
Document* document = &GetDocument();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
- document->GetReferrerPolicy(), document->GetSecurityOrigin(),
- document->IsSecureContext(), document->GetHttpsState(), clients,
- document->AddressSpace(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled,
+ document->UserAgent(), nullptr /* web_worker_fetch_context */,
+ Vector<CSPHeaderAndType>(), document->GetReferrerPolicy(),
+ document->GetSecurityOrigin(), document->IsSecureContext(),
+ document->GetHttpsState(), clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap),
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>()),
base::nullopt, std::make_unique<WorkerDevToolsParams>(),
ParentExecutionContextTaskRunners::Create());
return thread;
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
index a46565a9c5c..a21ae09ec60 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
@@ -19,7 +19,7 @@ const char PaintWorkletProxyClient::kSupplementName[] =
// static
PaintWorkletProxyClient* PaintWorkletProxyClient::Create() {
- return new PaintWorkletProxyClient;
+ return MakeGarbageCollected<PaintWorkletProxyClient>();
}
PaintWorkletProxyClient::PaintWorkletProxyClient()
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h
index 78248601c42..79b3570ff47 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h
@@ -33,6 +33,8 @@ class MODULES_EXPORT PaintWorkletProxyClient
static const char kSupplementName[];
static PaintWorkletProxyClient* Create();
+
+ PaintWorkletProxyClient();
virtual ~PaintWorkletProxyClient() = default;
void Trace(blink::Visitor*) override;
@@ -42,9 +44,6 @@ class MODULES_EXPORT PaintWorkletProxyClient
static PaintWorkletProxyClient* From(WorkerClients*);
- protected:
- PaintWorkletProxyClient();
-
private:
CrossThreadPersistent<PaintWorkletGlobalScope> global_scope_;
diff --git a/chromium/third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl b/chromium/third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl
index ef59beb05c9..d5e33bec509 100644
--- a/chromium/third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl
+++ b/chromium/third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl
@@ -31,5 +31,5 @@
[
ImplementedAs=NavigatorDoNotTrack
] partial interface Navigator {
- readonly attribute DOMString? doNotTrack;
+ [HighEntropy, MeasureAs=NavigatorDoNotTrack] readonly attribute DOMString? doNotTrack;
};
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc b/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc
index 12da076d1f8..50d8e508cf6 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc
@@ -60,7 +60,6 @@ TextDecoder::TextDecoder(const WTF::TextEncoding& encoding,
bool fatal,
bool ignore_bom)
: encoding_(encoding),
- codec_(NewTextCodec(encoding)),
fatal_(fatal),
ignore_bom_(ignore_bom),
bom_seen_(false) {}
@@ -100,8 +99,15 @@ String TextDecoder::decode(const char* start,
const TextDecodeOptions* options,
ExceptionState& exception_state) {
DCHECK(options);
- WTF::FlushBehavior flush = options->stream() ? WTF::FlushBehavior::kDoNotFlush
- : WTF::FlushBehavior::kDataEOF;
+ if (!do_not_flush_) {
+ codec_ = NewTextCodec(encoding_);
+ bom_seen_ = false;
+ }
+
+ DCHECK(codec_);
+ do_not_flush_ = options->stream();
+ WTF::FlushBehavior flush = do_not_flush_ ? WTF::FlushBehavior::kDoNotFlush
+ : WTF::FlushBehavior::kDataEOF;
bool saw_error = false;
String s = codec_->Decode(start, length, flush, fatal_, saw_error);
@@ -119,9 +125,6 @@ String TextDecoder::decode(const char* start,
s.Remove(0);
}
- if (flush != WTF::FlushBehavior::kDoNotFlush)
- bom_seen_ = false;
-
return s;
}
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder.h b/chromium/third_party/blink/renderer/modules/encoding/text_decoder.h
index cbad582e339..f4637fb2b94 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder.h
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder.h
@@ -73,6 +73,7 @@ class TextDecoder final : public ScriptWrappable {
WTF::TextEncoding encoding_;
std::unique_ptr<WTF::TextCodec> codec_;
+ bool do_not_flush_ = false;
bool fatal_;
bool ignore_bom_;
bool bom_seen_;
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc
index 62e5dba4060..08ae21485fa 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc
@@ -53,12 +53,6 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
// algorithm (https://heycam.github.io/webidl/#dfn-get-buffer-source-copy).
if (bufferSource.IsArrayBufferView()) {
const auto* view = bufferSource.GetAsArrayBufferView().View();
- // If IsDetachedBuffer(O), then throw a TypeError.
- if (view->buffer()->IsNeutered()) {
- exception_state.ThrowTypeError(
- ExceptionMessages::FailedToConvertJSValue("BufferSource"));
- return;
- }
const char* start = static_cast<const char*>(view->BaseAddress());
uint32_t length = view->byteLength();
DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush,
@@ -67,12 +61,6 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
}
DCHECK(bufferSource.IsArrayBuffer());
const auto* array_buffer = bufferSource.GetAsArrayBuffer();
- // If IsDetachedBuffer(O), then throw a TypeError.
- if (array_buffer->IsNeutered()) {
- exception_state.ThrowTypeError(
- ExceptionMessages::FailedToConvertJSValue("BufferSource"));
- return;
- }
const char* start = static_cast<const char*>(array_buffer->Data());
uint32_t length = array_buffer->ByteLength();
DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush, controller,
@@ -157,8 +145,8 @@ TextDecoderStream* TextDecoderStream::Create(ScriptState* script_state,
return nullptr;
}
- return new TextDecoderStream(script_state, encoding, options,
- exception_state);
+ return MakeGarbageCollected<TextDecoderStream>(script_state, encoding,
+ options, exception_state);
}
TextDecoderStream::~TextDecoderStream() = default;
@@ -193,7 +181,8 @@ TextDecoderStream::TextDecoderStream(ScriptState* script_state,
"Cannot queue task to retain wrapper");
return;
}
- transform_->Init(new Transformer(script_state, encoding, fatal_, ignore_bom_),
+ transform_->Init(MakeGarbageCollected<Transformer>(script_state, encoding,
+ fatal_, ignore_bom_),
script_state, exception_state);
}
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h
index bbfa4d4bee4..59941ccb9d5 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h
@@ -34,6 +34,11 @@ class TextDecoderStream final : public ScriptWrappable {
const String& label,
const TextDecoderOptions*,
ExceptionState&);
+
+ TextDecoderStream(ScriptState*,
+ const WTF::TextEncoding&,
+ const TextDecoderOptions*,
+ ExceptionState&);
~TextDecoderStream() override;
// From text_decoder_stream.idl
@@ -48,11 +53,6 @@ class TextDecoderStream final : public ScriptWrappable {
private:
class Transformer;
- TextDecoderStream(ScriptState*,
- const WTF::TextEncoding&,
- const TextDecoderOptions*,
- ExceptionState&);
-
const TraceWrapperMember<TransformStream> transform_;
const WTF::TextEncoding encoding_;
const bool fatal_;
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl
index 9fe584233f6..286489d726e 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl
@@ -8,8 +8,7 @@
Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options),
ConstructorCallWith=ScriptState,
RaisesException=Constructor,
- MeasureAs=TextDecoderStreamConstructor,
- RuntimeEnabled=EncodingStreams
+ MeasureAs=TextDecoderStreamConstructor
] interface TextDecoderStream {
readonly attribute DOMString encoding;
readonly attribute boolean fatal;
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc
index cedf987bc8c..5d827fc2781 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc
@@ -161,7 +161,7 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
TextEncoderStream* TextEncoderStream::Create(ScriptState* script_state,
ExceptionState& exception_state) {
- return new TextEncoderStream(script_state, exception_state);
+ return MakeGarbageCollected<TextEncoderStream>(script_state, exception_state);
}
TextEncoderStream::~TextEncoderStream() = default;
@@ -191,8 +191,8 @@ TextEncoderStream::TextEncoderStream(ScriptState* script_state,
"Cannot queue task to retain wrapper");
return;
}
- transform_->Init(new Transformer(script_state), script_state,
- exception_state);
+ transform_->Init(MakeGarbageCollected<Transformer>(script_state),
+ script_state, exception_state);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h
index 1e34400212f..561f25c841d 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h
@@ -29,6 +29,8 @@ class TextEncoderStream final : public ScriptWrappable {
public:
static TextEncoderStream* Create(ScriptState*, ExceptionState&);
+
+ TextEncoderStream(ScriptState*, ExceptionState&);
~TextEncoderStream() override;
// From text_encoder_stream.idl
@@ -41,8 +43,6 @@ class TextEncoderStream final : public ScriptWrappable {
private:
class Transformer;
- TextEncoderStream(ScriptState*, ExceptionState&);
-
const TraceWrapperMember<TransformStream> transform_;
DISALLOW_COPY_AND_ASSIGN(TextEncoderStream);
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl
index 73f60a89316..b28dd76acab 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl
@@ -8,8 +8,7 @@
Constructor(),
ConstructorCallWith=ScriptState,
RaisesException=Constructor,
- MeasureAs=TextEncoderStreamConstructor,
- RuntimeEnabled=EncodingStreams
+ MeasureAs=TextEncoderStreamConstructor
] interface TextEncoderStream {
readonly attribute DOMString encoding;
readonly attribute ReadableStream readable;
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/DEPS b/chromium/third_party/blink/renderer/modules/encryptedmedia/DEPS
index ed15789d3d9..5d7c0cb3e82 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/DEPS
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/DEPS
@@ -1,5 +1,7 @@
include_rules = [
"-third_party/blink/renderer/modules",
+ "+services/metrics/public/cpp/ukm_builders.h",
+ "+services/metrics/public/cpp/ukm_recorder.h",
"+third_party/blink/renderer/modules/encryptedmedia",
"+third_party/blink/renderer/modules/event_modules.h",
"+third_party/blink/renderer/modules/event_target_modules.h",
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc
index 256e30be550..5ff20d8daa8 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc
@@ -132,7 +132,6 @@ ScriptPromise SetMediaKeysHandler::Create(ScriptState* script_state,
MediaKeys* media_keys) {
SetMediaKeysHandler* handler = MakeGarbageCollected<SetMediaKeysHandler>(
script_state, element, media_keys);
- handler->PauseIfNeeded();
handler->KeepAliveWhilePending();
return handler->Promise();
}
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.idl b/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.idl
index c8e54ea9201..8c1a02583ed 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.idl
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.idl
@@ -1,11 +1,13 @@
// 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.
+
+// https://w3c.github.io/encrypted-media/#htmlmediaelement-extensions
[
ImplementedAs=HTMLMediaElementEncryptedMedia
] partial interface HTMLMediaElement {
[SecureContext] readonly attribute MediaKeys mediaKeys;
- [SecureContext, CallWith=ScriptState] Promise setMediaKeys(MediaKeys? mediaKeys);
+ [SecureContext, CallWith=ScriptState] Promise<void> setMediaKeys(MediaKeys? mediaKeys);
attribute EventHandler onencrypted;
attribute EventHandler onwaitingforkey;
};
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
index e478c4d1a33..a208dac96e3 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
@@ -358,9 +358,10 @@ MediaKeySession::MediaKeySession(ScriptState* script_state,
is_uninitialized_(true),
is_callable_(false),
is_closing_or_closed_(false),
- closed_promise_(new ClosedPromise(ExecutionContext::From(script_state),
- this,
- ClosedPromise::kClosed)),
+ closed_promise_(MakeGarbageCollected<ClosedPromise>(
+ ExecutionContext::From(script_state),
+ this,
+ ClosedPromise::kClosed)),
action_timer_(ExecutionContext::From(script_state)
->GetTaskRunner(TaskType::kMiscPlatformAPI),
this,
@@ -378,7 +379,7 @@ MediaKeySession::MediaKeySession(ScriptState* script_state,
// From https://w3c.github.io/encrypted-media/#createSession:
// MediaKeys::createSession(), step 3.
// 3.1 Let the sessionId attribute be the empty string.
- DCHECK(sessionId().IsEmpty());
+ DCHECK(session_id_.IsEmpty());
// 3.2 Let the expiration attribute be NaN.
DCHECK(std::isnan(expiration_));
@@ -418,7 +419,7 @@ void MediaKeySession::Dispose() {
}
String MediaKeySession::sessionId() const {
- return session_->SessionId();
+ return session_id_;
}
ScriptPromise MediaKeySession::closed(ScriptState* script_state) {
@@ -536,7 +537,8 @@ void MediaKeySession::FinishGenerateRequest() {
// new DOMException whose name is the appropriate error name.
// (Done by CDM calling result.completeWithError() as appropriate.)
// 10.10.2 Set the sessionId attribute to session id.
- DCHECK(!sessionId().IsEmpty());
+ session_id_ = session_->SessionId();
+ DCHECK(!session_id_.IsEmpty());
// 10.10.3 Let this object's callable be true.
is_callable_ = true;
@@ -654,7 +656,8 @@ void MediaKeySession::FinishLoad() {
// (Done by CDM calling result.completeWithError() as appropriate.)
// 8.9.2 Set the sessionId attribute to sanitized session ID.
- DCHECK(!sessionId().IsEmpty());
+ session_id_ = session_->SessionId();
+ DCHECK(!session_id_.IsEmpty());
// 8.9.3 Let this object's callable be true.
is_callable_ = true;
@@ -910,6 +913,11 @@ void MediaKeySession::Message(MessageType message_type,
}
void MediaKeySession::Close() {
+ // Note that this is the event from the CDM when this session is actually
+ // closed. The CDM can close a session at any time. Normally it would happen
+ // as the result of a close() call, but also happens when update() has been
+ // called with a record of license destruction or if the CDM crashes or
+ // otherwise becomes unavailable.
DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
// From http://w3c.github.io/encrypted-media/#session-closed
@@ -931,6 +939,22 @@ void MediaKeySession::Close() {
// 7. Resolve promise.
closed_promise_->ResolveWithUndefined();
+
+ // Stop the CDM from firing any more events for this session.
+ session_.reset();
+
+ // Fail any pending events, except if it's a close request.
+ action_timer_.Stop();
+ while (!pending_actions_.IsEmpty()) {
+ PendingAction* action = pending_actions_.TakeFirst();
+ if (action->GetType() == PendingAction::kClose) {
+ action->Result()->Complete();
+ } else {
+ action->Result()->CompleteWithError(
+ kWebContentDecryptionModuleExceptionInvalidStateError, 0,
+ "Session has been closed");
+ }
+ }
}
void MediaKeySession::ExpirationChanged(double updated_expiry_time_in_ms) {
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
index d4d44c2c5e9..5338e6fa9c3 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
@@ -142,6 +142,7 @@ class MediaKeySession final
WeakMember<MediaKeys> media_keys_;
// Session properties.
+ String session_id_;
WebEncryptedMediaSessionType session_type_;
double expiration_;
Member<MediaKeyStatusMap> key_statuses_map_;
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc
index 2f518b1a5d1..8d7506f897e 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc
@@ -160,9 +160,9 @@ ScriptPromise MediaKeySystemAccess::createMediaKeys(ScriptState* script_state) {
WebMediaKeySystemConfiguration configuration = access_->GetConfiguration();
// 1. Let promise be a new promise.
- NewCdmResultPromise* helper =
- new NewCdmResultPromise(script_state, configuration.session_types,
- "MediaKeySystemAccess", "createMediaKeys");
+ NewCdmResultPromise* helper = MakeGarbageCollected<NewCdmResultPromise>(
+ script_state, configuration.session_types, "MediaKeySystemAccess",
+ "createMediaKeys");
ScriptPromise promise = helper->Promise();
// 2. Asynchronously create and initialize the MediaKeys object.
@@ -171,7 +171,9 @@ ScriptPromise MediaKeySystemAccess::createMediaKeys(ScriptState* script_state) {
// 2.3 If cdm fails to load or initialize, reject promise with a new
// DOMException whose name is the appropriate error name.
// (Done if completeWithException() called).
- access_->CreateContentDecryptionModule(helper->Result());
+ access_->CreateContentDecryptionModule(
+ helper->Result(), ExecutionContext::From(script_state)
+ ->GetTaskRunner(TaskType::kInternalMedia));
// 3. Return promise.
return promise;
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl
index 61aaf39af0f..15a6ca073ec 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl
@@ -6,7 +6,6 @@
[
ImplementedAs=MediaKeysGetStatusForPolicy,
- OriginTrialEnabled=EncryptedMediaHdcpPolicyCheck,
SecureContext
] partial interface MediaKeys {
[Measure, CallWith=ScriptState] Promise<MediaKeyStatus> getStatusForPolicy(MediaKeysPolicy policy);
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index 9ac6db76044..1640a59040d 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -7,6 +7,8 @@
#include <algorithm>
#include "base/memory/ptr_util.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/public/platform/web_encrypted_media_client.h"
#include "third_party/blink/public/platform/web_encrypted_media_request.h"
@@ -214,6 +216,8 @@ const SecurityOrigin* MediaKeySystemAccessInitializer::GetSecurityOrigin()
void MediaKeySystemAccessInitializer::RequestSucceeded(
WebContentDecryptionModuleAccess* access) {
+ DVLOG(3) << __func__;
+
if (!IsExecutionContextValid())
return;
@@ -224,6 +228,8 @@ void MediaKeySystemAccessInitializer::RequestSucceeded(
void MediaKeySystemAccessInitializer::RequestNotSupported(
const WebString& error_message) {
+ DVLOG(3) << __func__ << " error: " << error_message.Ascii();
+
if (!IsExecutionContextValid())
return;
@@ -241,23 +247,38 @@ bool MediaKeySystemAccessInitializer::IsExecutionContextValid() const {
}
void MediaKeySystemAccessInitializer::CheckVideoCapabilityRobustness() const {
- // Only check for widevine key system.
- if (KeySystem() != "com.widevine.alpha")
+ const char kWidevineKeySystem[] = "com.widevine.alpha";
+ const char kWidevineHwSecureAllRobustness[] = "HW_SECURE_ALL";
+
+ // Reported to UKM. Existing values must not change and new values must be
+ // added at the end of the list.
+ enum KeySystemForUkm {
+ kClearKey = 0,
+ kWidevine = 1,
+ };
+
+ // Only check for widevine key system for now.
+ if (KeySystem() != kWidevineKeySystem)
return;
bool has_video_capabilities = false;
bool has_empty_robustness = false;
+ bool has_hw_secure_all = false;
for (const auto& config : supported_configurations_) {
for (const auto& capability : config.video_capabilities) {
has_video_capabilities = true;
if (capability.robustness.IsEmpty()) {
has_empty_robustness = true;
- break;
+ } else if (capability.robustness == kWidevineHwSecureAllRobustness) {
+ has_hw_secure_all = true;
}
+
+ if (has_empty_robustness && has_hw_secure_all)
+ break;
}
- if (has_empty_robustness)
+ if (has_empty_robustness && has_hw_secure_all)
break;
}
@@ -278,6 +299,20 @@ void MediaKeySystemAccessInitializer::CheckVideoCapabilityRobustness() const {
"specifying the robustness level could result in unexpected "
"behavior."));
}
+
+ Document* document = To<Document>(resolver_->GetExecutionContext());
+ if (!document)
+ return;
+
+ ukm::builders::Media_EME_RequestMediaKeySystemAccess builder(
+ document->UkmSourceID());
+ builder.SetKeySystem(KeySystemForUkm::kWidevine);
+ builder.SetVideoCapabilities(static_cast<int>(has_video_capabilities));
+ builder.SetVideoCapabilities_HasEmptyRobustness(
+ static_cast<int>(has_empty_robustness));
+ builder.SetVideoCapabilities_HasHwSecureAllRobustness(
+ static_cast<int>(has_hw_secure_all));
+ builder.Record(document->UkmRecorder());
}
} // namespace
@@ -346,8 +381,8 @@ ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess(
// 5. Let promise be a new promise.
MediaKeySystemAccessInitializer* initializer =
- new MediaKeySystemAccessInitializer(script_state, key_system,
- supported_configurations);
+ MakeGarbageCollected<MediaKeySystemAccessInitializer>(
+ script_state, key_system, supported_configurations);
ScriptPromise promise = initializer->Promise();
// 6. Asynchronously determine support, and if allowed, create and
diff --git a/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5 b/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5
index 3f5aec4821b..a1b3935c2fc 100644
--- a/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5
+++ b/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5
@@ -10,11 +10,13 @@
data: [
"BackgroundFetchRegistration",
"BatteryManager",
+ "Bluetooth",
"BluetoothDevice",
"BluetoothRemoteGATTCharacteristic",
"CookieStore",
"MediaKeySession",
"FileWriter",
+ "IdleStatus",
"ImageCapture",
"IDBDatabase",
"IDBOpenDBRequest",
@@ -64,8 +66,8 @@
"MIDIInput",
"MIDIPort",
"XR",
- "XRCoordinateSystem",
"XRSession",
+ "XRSpace",
{
name: "WebSocket",
ImplementedAs: "DOMWebSocket",
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc
index 0b27bcaeb16..2e4d6a12586 100644
--- a/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc
+++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc
@@ -228,8 +228,9 @@ void EventSource::DidReceiveResponse(
DCHECK(loader_);
resource_identifier_ = identifier;
- current_url_ = response.Url();
- event_stream_origin_ = SecurityOrigin::Create(response.Url())->ToString();
+ current_url_ = response.CurrentRequestUrl();
+ event_stream_origin_ =
+ SecurityOrigin::Create(response.CurrentRequestUrl())->ToString();
int status_code = response.HttpStatusCode();
bool mime_type_is_valid = response.MimeType() == "text/event-stream";
bool response_is_valid = status_code == 200 && mime_type_is_valid;
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc
index 6f1506f1188..eb65abb67a9 100644
--- a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc
+++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/eventsource/event_source_parser.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/event_type_names.h"
#include "third_party/blink/renderer/modules/eventsource/event_source.h"
#include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
@@ -30,10 +31,10 @@ void EventSourceParser::AddBytes(const char* bytes, uint32_t size) {
for (uint32_t i = 0; i < size && !is_stopped_; ++i) {
// As kBOM contains neither CR nor LF, we can think BOM and the line
// break separately.
- if (is_recognizing_bom_ && line_.size() + (i - start) == arraysize(kBOM)) {
+ if (is_recognizing_bom_ && line_.size() + (i - start) == base::size(kBOM)) {
Vector<char> line = line_;
line.Append(&bytes[start], i - start);
- DCHECK_EQ(line.size(), arraysize(kBOM));
+ DCHECK_EQ(line.size(), base::size(kBOM));
is_recognizing_bom_ = false;
if (memcmp(line.data(), kBOM, sizeof(kBOM)) == 0) {
start = i;
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc
index ab1db0f3b3e..a9f33d92e91 100644
--- a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc
+++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc
@@ -91,7 +91,7 @@ class EventSourceParserTest : public testing::Test {
protected:
using Type = EventOrReconnectionTimeSetting::Type;
EventSourceParserTest()
- : client_(new Client),
+ : client_(MakeGarbageCollected<Client>()),
parser_(
MakeGarbageCollected<EventSourceParser>(AtomicString(), client_)) {}
~EventSourceParserTest() override = default;
@@ -376,7 +376,7 @@ TEST_F(EventSourceParserTest, InvalidUTF8Sequence) {
}
TEST(EventSourceParserStoppingTest, StopWhileParsing) {
- StoppingClient* client = new StoppingClient();
+ StoppingClient* client = MakeGarbageCollected<StoppingClient>();
EventSourceParser* parser =
MakeGarbageCollected<EventSourceParser>(AtomicString(), client);
client->SetParser(parser);
diff --git a/chromium/third_party/blink/renderer/modules/exported/BUILD.gn b/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
index bfc6251ccf7..c034cde319a 100644
--- a/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
@@ -5,7 +5,6 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("exported") {
sources = [
- "indexed_db_key_builder.cc",
"web_apply_constraints_request.cc",
"web_ax_context.cc",
"web_ax_object.cc",
@@ -14,9 +13,6 @@ blink_modules_sources("exported") {
"web_dom_media_stream_track.cc",
"web_embedded_worker_impl.cc",
"web_embedded_worker_impl.h",
- "web_idb_key.cc",
- "web_idb_key_range.cc",
- "web_idb_value.cc",
"web_storage_event_dispatcher_impl.cc",
"web_user_media_request.cc",
]
diff --git a/chromium/third_party/blink/renderer/modules/exported/indexed_db_key_builder.cc b/chromium/third_party/blink/renderer/modules/exported/indexed_db_key_builder.cc
deleted file mode 100644
index 8c2b8985925..00000000000
--- a/chromium/third_party/blink/renderer/modules/exported/indexed_db_key_builder.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// 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 "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h"
-#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-
-namespace blink {
-
-namespace {
-
-IndexedDBKey::KeyArray CopyKeyArray(WebIDBKeyArrayView array) {
- IndexedDBKey::KeyArray result;
- const size_t array_size = array.size();
- result.reserve(array_size);
- for (size_t i = 0; i < array_size; ++i)
- result.emplace_back(IndexedDBKeyBuilder::Build(array[i]));
- return result;
-}
-
-std::vector<base::string16> CopyArray(const WebVector<WebString>& array) {
- std::vector<base::string16> result;
- result.reserve(array.size());
- for (const WebString& element : array)
- result.emplace_back(element.Utf16());
- return result;
-}
-
-} // anonymous namespace
-
-// static
-IndexedDBKey IndexedDBKeyBuilder::Build(WebIDBKeyView key) {
- switch (key.KeyType()) {
- case kWebIDBKeyTypeArray:
- return IndexedDBKey(CopyKeyArray(key.ArrayView()));
- case kWebIDBKeyTypeBinary: {
- const WebData data = key.Binary();
- std::string key_string;
- key_string.reserve(data.size());
-
- data.ForEachSegment([&key_string](const char* segment,
- size_t segment_size,
- size_t segment_offset) {
- key_string.append(segment, segment_size);
- return true;
- });
- return IndexedDBKey(std::move(key_string));
- }
- case kWebIDBKeyTypeString:
- return IndexedDBKey(key.String().Utf16());
- case kWebIDBKeyTypeDate:
- return IndexedDBKey(key.Date(), kWebIDBKeyTypeDate);
- case kWebIDBKeyTypeNumber:
- return IndexedDBKey(key.Number(), kWebIDBKeyTypeNumber);
- case kWebIDBKeyTypeNull:
- case kWebIDBKeyTypeInvalid:
- return IndexedDBKey(key.KeyType());
- case kWebIDBKeyTypeMin:
- NOTREACHED();
- return IndexedDBKey();
- }
-}
-
-// static
-WebIDBKey WebIDBKeyBuilder::Build(const WebIDBKeyView& key) {
- switch (key.KeyType()) {
- case kWebIDBKeyTypeArray: {
- const WebIDBKeyArrayView& array = key.ArrayView();
- WebVector<WebIDBKey> web_idb_keys;
- const size_t array_size = array.size();
- web_idb_keys.reserve(array_size);
- for (size_t i = 0; i < array_size; ++i)
- web_idb_keys.emplace_back(Build(array[i]));
- return WebIDBKey::CreateArray(std::move(web_idb_keys));
- }
- case kWebIDBKeyTypeBinary: {
- const WebData data = key.Binary();
- return WebIDBKey::CreateBinary(data);
- }
- case kWebIDBKeyTypeString:
- return WebIDBKey::CreateString(key.String());
- case kWebIDBKeyTypeDate:
- return WebIDBKey::CreateDate(key.Date());
- case kWebIDBKeyTypeNumber:
- return WebIDBKey::CreateNumber(key.Number());
- case kWebIDBKeyTypeInvalid:
- return WebIDBKey::CreateInvalid();
- case kWebIDBKeyTypeNull:
- return WebIDBKey::CreateNull();
- case kWebIDBKeyTypeMin:
- NOTREACHED();
- return WebIDBKey::CreateInvalid();
- }
-}
-
-// static
-WebIDBKey WebIDBKeyBuilder::Build(const IndexedDBKey& key) {
- switch (key.type()) {
- case kWebIDBKeyTypeArray: {
- const IndexedDBKey::KeyArray& array = key.array();
- WebVector<WebIDBKey> web_idb_keys;
- web_idb_keys.reserve(array.size());
- for (const IndexedDBKey& array_element : array)
- web_idb_keys.emplace_back(Build(array_element));
- return WebIDBKey::CreateArray(std::move(web_idb_keys));
- }
- case kWebIDBKeyTypeBinary: {
- const std::string& str = key.binary();
- const WebData& data = WebData(str.c_str(), str.length());
- return WebIDBKey::CreateBinary(data);
- }
- case kWebIDBKeyTypeString:
- return WebIDBKey::CreateString(WebString::FromUTF16(key.string()));
- case kWebIDBKeyTypeDate:
- return WebIDBKey::CreateDate(key.date());
- case kWebIDBKeyTypeNumber:
- return WebIDBKey::CreateNumber(key.number());
- case kWebIDBKeyTypeInvalid:
- return WebIDBKey::CreateInvalid();
- case kWebIDBKeyTypeNull:
- return WebIDBKey::CreateNull();
- case kWebIDBKeyTypeMin:
- NOTREACHED();
- return WebIDBKey::CreateInvalid();
- }
-}
-
-// static
-IndexedDBKeyRange IndexedDBKeyRangeBuilder::Build(
- const WebIDBKeyRange& key_range) {
- return IndexedDBKeyRange(IndexedDBKeyBuilder::Build(key_range.Lower()),
- IndexedDBKeyBuilder::Build(key_range.Upper()),
- key_range.LowerOpen(), key_range.UpperOpen());
-}
-
-// static
-IndexedDBKeyRange IndexedDBKeyRangeBuilder::Build(WebIDBKeyView key) {
- return IndexedDBKeyRange(IndexedDBKeyBuilder::Build(key),
- IndexedDBKeyBuilder::Build(key),
- false /* lower_open */, false /* upper_open */);
-}
-
-// static
-WebIDBKeyRange WebIDBKeyRangeBuilder::Build(WebIDBKeyView key) {
- return WebIDBKeyRange(WebIDBKeyBuilder::Build(key),
- WebIDBKeyBuilder::Build(key), false /* lower_open */,
- false /* upper_open */);
-}
-
-// static
-WebIDBKeyRange WebIDBKeyRangeBuilder::Build(
- const IndexedDBKeyRange& key_range) {
- return WebIDBKeyRange(WebIDBKeyBuilder::Build(key_range.lower()),
- WebIDBKeyBuilder::Build(key_range.upper()),
- key_range.lower_open(), key_range.upper_open());
-}
-
-// static
-IndexedDBKeyPath IndexedDBKeyPathBuilder::Build(const WebIDBKeyPath& key_path) {
- switch (key_path.KeyPathType()) {
- case kWebIDBKeyPathTypeString:
- return IndexedDBKeyPath(key_path.String().Utf16());
- case kWebIDBKeyPathTypeArray:
- return IndexedDBKeyPath(CopyArray(key_path.Array()));
- case kWebIDBKeyPathTypeNull:
- return IndexedDBKeyPath();
- }
-}
-
-// static
-WebIDBKeyPath WebIDBKeyPathBuilder::Build(const IndexedDBKeyPath& key_path) {
- switch (key_path.type()) {
- case kWebIDBKeyPathTypeString:
- return WebIDBKeyPath::Create(WebString::FromUTF16(key_path.string()));
- case kWebIDBKeyPathTypeArray: {
- WebVector<WebString> key_path_vector(key_path.array().size());
- for (const auto& item : key_path.array())
- key_path_vector.emplace_back(WebString::FromUTF16(item));
- return WebIDBKeyPath::Create(key_path_vector);
- }
- case kWebIDBKeyPathTypeNull:
- return WebIDBKeyPath::CreateNull();
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc b/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc
index 4c2310dcaa8..ef79de3cb11 100644
--- a/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc
+++ b/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -427,6 +427,13 @@ WebAXObject WebAXObject::AriaActiveDescendant() const {
return WebAXObject(private_->ActiveDescendant());
}
+WebAXObject WebAXObject::ErrorMessage() const {
+ if (IsDetached())
+ return WebAXObject();
+
+ return WebAXObject(private_->ErrorMessage());
+}
+
ax::mojom::HasPopup WebAXObject::HasPopup() const {
if (IsDetached())
return ax::mojom::HasPopup::kFalse;
@@ -1096,7 +1103,7 @@ unsigned WebAXObject::AriaColumnIndex() const {
if (IsDetached())
return 0;
- return private_->IsTableCellLikeRole() ? private_->AriaColumnIndex() : 0;
+ return private_->AriaColumnIndex();
}
int WebAXObject::AriaRowCount() const {
@@ -1324,17 +1331,16 @@ void WebAXObject::GetWordBoundaries(WebVector<int>& starts,
if (IsDetached())
return;
- Vector<AXRange> word_boundaries;
- private_->GetWordBoundaries(word_boundaries);
-
- WebVector<int> word_start_offsets(word_boundaries.size());
- WebVector<int> word_end_offsets(word_boundaries.size());
- for (wtf_size_t i = 0; i < word_boundaries.size(); ++i) {
- DCHECK(word_boundaries[i].IsValid());
- DCHECK_EQ(word_boundaries[i].Start().ContainerObject(),
- word_boundaries[i].End().ContainerObject());
- word_start_offsets[i] = word_boundaries[i].Start().TextOffset();
- word_end_offsets[i] = word_boundaries[i].End().TextOffset();
+ Vector<int> src_starts;
+ Vector<int> src_ends;
+ private_->GetWordBoundaries(src_starts, src_ends);
+ DCHECK_EQ(src_starts.size(), src_ends.size());
+
+ WebVector<int> word_start_offsets(src_starts.size());
+ WebVector<int> word_end_offsets(src_ends.size());
+ for (wtf_size_t i = 0; i < src_starts.size(); ++i) {
+ word_start_offsets[i] = src_starts[i];
+ word_end_offsets[i] = src_ends[i];
}
starts.Swap(word_start_offsets);
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 5bcb80cdff8..519d1b4627e 100644
--- a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -64,7 +64,9 @@
#include "third_party/blink/renderer/modules/service_worker/service_worker_thread.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
-#include "third_party/blink/renderer/platform/loader/fetch/substitute_data.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -177,11 +179,15 @@ void WebEmbeddedWorkerImpl::StartWorkerContext(
pause_after_download_state_ = kDoPauseAfterDownload;
devtools_worker_token_ = data.devtools_worker_token;
- // |loader_factory| is null since all loads for new scripts go through
- // ServiceWorkerNetworkProvider::script_loader_factory() rather than the
- // shadow page's loader. This is different to shared workers, which use the
- // script loader factory for the main script only, and the shadow page loader
- // for importScripts().
+ // S13nServiceWorker: |loader_factory| is null since all loads for new scripts
+ // go through ServiceWorkerNetworkProvider::script_loader_factory() rather
+ // than the shadow page's loader. This is different to shared workers, which
+ // use script_loader_factory() for the main script only, and the shadow page
+ // loader for importScripts().
+ //
+ // Non-S13nServiceWorker: |loader_factory| is null since the main script load
+ // goes through the shadow page loader which uses the default loader that goes
+ // to ResourceDispatcherHost.
shadow_page_ = std::make_unique<WorkerShadowPage>(
this, nullptr /* loader_factory */,
std::move(worker_start_data_.privacy_preferences));
@@ -245,16 +251,16 @@ void WebEmbeddedWorkerImpl::AddMessageToConsole(
const WebConsoleMessage& message) {
MessageLevel web_core_message_level;
switch (message.level) {
- case WebConsoleMessage::kLevelVerbose:
+ case mojom::ConsoleMessageLevel::kVerbose:
web_core_message_level = kVerboseMessageLevel;
break;
- case WebConsoleMessage::kLevelInfo:
+ case mojom::ConsoleMessageLevel::kInfo:
web_core_message_level = kInfoMessageLevel;
break;
- case WebConsoleMessage::kLevelWarning:
+ case mojom::ConsoleMessageLevel::kWarning:
web_core_message_level = kWarningMessageLevel;
break;
- case WebConsoleMessage::kLevelError:
+ case mojom::ConsoleMessageLevel::kError:
web_core_message_level = kErrorMessageLevel;
break;
default:
@@ -316,12 +322,11 @@ void WebEmbeddedWorkerImpl::OnShadowPageInitialized() {
DCHECK(!main_script_loader_);
main_script_loader_ = MakeGarbageCollected<WorkerClassicScriptLoader>();
main_script_loader_->LoadTopLevelScriptAsynchronously(
- *shadow_page_->GetDocument(), worker_start_data_.script_url,
- mojom::RequestContextType::SERVICE_WORKER,
+ *shadow_page_->GetDocument(), shadow_page_->GetDocument()->Fetcher(),
+ worker_start_data_.script_url, mojom::RequestContextType::SERVICE_WORKER,
network::mojom::FetchRequestMode::kSameOrigin,
network::mojom::FetchCredentialsMode::kSameOrigin,
- worker_start_data_.address_space, false /* is_nested_worker */,
- base::OnceClosure(),
+ worker_start_data_.address_space, base::OnceClosure(),
Bind(&WebEmbeddedWorkerImpl::OnScriptLoaderFinished,
WTF::Unretained(this)));
// Do nothing here since OnScriptLoaderFinished() might have been already
@@ -389,7 +394,14 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
std::unique_ptr<GlobalScopeCreationParams> global_scope_creation_params;
String source_code;
- std::unique_ptr<Vector<char>> cached_meta_data;
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data;
+
+ // TODO(nhiroki): Implement off-the-main-thread worker script fetch for
+ // service workers (https://crbug.com/835717).
+ const OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option =
+ worker_start_data_.script_type == mojom::ScriptType::kModule
+ ? OffMainThreadWorkerScriptFetchOption::kEnabled
+ : OffMainThreadWorkerScriptFetchOption::kDisabled;
// |main_script_loader_| isn't created if the InstalledScriptsManager had the
// script.
@@ -405,7 +417,8 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
}
global_scope_creation_params = std::make_unique<GlobalScopeCreationParams>(
worker_start_data_.script_url, worker_start_data_.script_type,
- worker_start_data_.user_agent, std::move(web_worker_fetch_context),
+ off_main_thread_fetch_option, worker_start_data_.user_agent,
+ std::move(web_worker_fetch_context),
content_security_policy ? content_security_policy->Headers()
: Vector<CSPHeaderAndType>(),
referrer_policy, starter_origin, starter_secure_context,
@@ -424,12 +437,12 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
// served by the installed scripts manager on the worker thread.
global_scope_creation_params = std::make_unique<GlobalScopeCreationParams>(
worker_start_data_.script_url, worker_start_data_.script_type,
- worker_start_data_.user_agent, std::move(web_worker_fetch_context),
- Vector<CSPHeaderAndType>(), network::mojom::ReferrerPolicy::kDefault,
- starter_origin, starter_secure_context, starter_https_state,
- worker_clients, worker_start_data_.address_space,
- nullptr /* OriginTrialTokens */, devtools_worker_token_,
- std::move(worker_settings),
+ off_main_thread_fetch_option, worker_start_data_.user_agent,
+ std::move(web_worker_fetch_context), Vector<CSPHeaderAndType>(),
+ network::mojom::ReferrerPolicy::kDefault, starter_origin,
+ starter_secure_context, starter_https_state, worker_clients,
+ worker_start_data_.address_space, nullptr /* OriginTrialTokens */,
+ devtools_worker_token_, std::move(worker_settings),
static_cast<V8CacheOptions>(worker_start_data_.v8_cache_options),
nullptr /* worklet_module_respones_map */,
std::move(interface_provider_info_));
@@ -474,7 +487,10 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
// called navigator.ServiceWorker.register(). To do it, we need to make a
// way to pass the settings object over mojo IPCs.
auto* outside_settings_object =
- document->CreateFetchClientSettingsObjectSnapshot();
+ MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ document->Fetcher()
+ ->GetProperties()
+ .GetFetchClientSettingsObject());
network::mojom::FetchCredentialsMode credentials_mode =
network::mojom::FetchCredentialsMode::kOmit;
worker_thread_->ImportModuleScript(worker_start_data_.script_url,
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
index 4c6dee13232..342b79cb4da 100644
--- a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
+++ b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -34,7 +34,7 @@
#include <memory>
#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/public/web/web_embedded_worker.h"
#include "third_party/blink/public/web/web_embedded_worker_start_data.h"
#include "third_party/blink/renderer/core/exported/worker_shadow_page.h"
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc b/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc
deleted file mode 100644
index 2d0dbfd23e6..00000000000
--- a/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-
-#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
-#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-
-namespace blink {
-
-size_t WebIDBKeyArrayView::size() const {
- return private_->Array().size();
-}
-
-WebIDBKeyView WebIDBKeyArrayView::operator[](size_t index) const {
- return WebIDBKeyView(private_->Array()[SafeCast<wtf_size_t>(index)].get());
-}
-
-WebIDBKeyType WebIDBKeyView::KeyType() const {
- if (!private_)
- return kWebIDBKeyTypeNull;
- return static_cast<WebIDBKeyType>(private_->GetType());
-}
-
-bool WebIDBKeyView::IsValid() const {
- if (!private_)
- return false;
- return private_->IsValid();
-}
-
-WebData WebIDBKeyView::Binary() const {
- return private_->Binary();
-}
-
-WebString WebIDBKeyView::String() const {
- return private_->GetString();
-}
-
-double WebIDBKeyView::Date() const {
- return private_->Date();
-}
-
-double WebIDBKeyView::Number() const {
- return private_->Number();
-}
-
-size_t WebIDBKeyView::SizeEstimate() const {
- // TODO(cmp): Ensure |private_| can never be null.
- //
- // SizeEstimate() can be called when |private_| is null. That happens if and
- // only if the |WebIDBKey| instance is created using WebIDBKey::CreateNull().
- //
- // Eventually, WebIDBKey::CreateNull() will change so that case will lead to
- // a non-null |private_|. At that time, this null check can change to a
- // DCHECK that |private_| is not null and the special null case handling can
- // be removed.
- if (this->IsNull()) {
- return IDBKey::kIDBKeyOverheadSize;
- }
-
- return private_->SizeEstimate();
-}
-
-WebIDBKey WebIDBKey::CreateArray(WebVector<WebIDBKey> array) {
- IDBKey::KeyArray keys;
- keys.ReserveCapacity(SafeCast<wtf_size_t>(array.size()));
- for (WebIDBKey& key : array) {
- DCHECK(key.View().KeyType() != kWebIDBKeyTypeNull);
- keys.emplace_back(key.ReleaseIdbKey());
- }
- return WebIDBKey(IDBKey::CreateArray(std::move(keys)));
-}
-
-WebIDBKey WebIDBKey::CreateBinary(const WebData& binary) {
- return WebIDBKey(IDBKey::CreateBinary(binary));
-}
-
-WebIDBKey WebIDBKey::CreateString(const WebString& string) {
- return WebIDBKey(IDBKey::CreateString(string));
-}
-
-WebIDBKey WebIDBKey::CreateDate(double date) {
- return WebIDBKey(IDBKey::CreateDate(date));
-}
-
-WebIDBKey WebIDBKey::CreateNumber(double number) {
- return WebIDBKey(IDBKey::CreateNumber(number));
-}
-
-WebIDBKey WebIDBKey::CreateInvalid() {
- return WebIDBKey(IDBKey::CreateInvalid());
-}
-
-WebIDBKey::WebIDBKey() noexcept = default;
-
-WebIDBKey::WebIDBKey(WebIDBKey&&) noexcept = default;
-WebIDBKey& WebIDBKey::operator=(WebIDBKey&&) noexcept = default;
-
-WebIDBKey::~WebIDBKey() noexcept = default;
-
-std::unique_ptr<IDBKey> WebIDBKey::ReleaseIdbKey() noexcept {
- return std::move(private_);
-}
-
-WebIDBKey::WebIDBKey(std::unique_ptr<IDBKey> idb_key) noexcept
- : private_(std::move(idb_key)) {}
-WebIDBKey& WebIDBKey::operator=(std::unique_ptr<IDBKey> idb_key) noexcept {
- private_ = std::move(idb_key);
- return *this;
-}
-
-WebIDBKey::WebIDBKey(const WebIDBKey& rkey)
- : private_(IDBKey::Clone(rkey.private_)) {}
-WebIDBKey& WebIDBKey::operator=(const WebIDBKey& rkey) {
- private_ = IDBKey::Clone(rkey.private_);
- return *this;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_idb_key_range.cc b/chromium/third_party/blink/renderer/modules/exported/web_idb_key_range.cc
deleted file mode 100644
index 0cdee1eb9b2..00000000000
--- a/chromium/third_party/blink/renderer/modules/exported/web_idb_key_range.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-
-namespace blink {
-
-void WebIDBKeyRange::Assign(const WebIDBKeyRange& other) {
- private_ = other.private_;
-}
-
-void WebIDBKeyRange::Assign(WebIDBKey lower,
- WebIDBKey upper,
- bool lower_open,
- bool upper_open) {
- if (!lower.View().IsValid() && !upper.View().IsValid()) {
- private_.Reset();
- } else {
- private_ = IDBKeyRange::Create(lower.ReleaseIdbKey(), upper.ReleaseIdbKey(),
- lower_open ? IDBKeyRange::kLowerBoundOpen
- : IDBKeyRange::kLowerBoundClosed,
- upper_open ? IDBKeyRange::kUpperBoundOpen
- : IDBKeyRange::kUpperBoundClosed);
- }
-}
-
-void WebIDBKeyRange::Reset() {
- private_.Reset();
-}
-
-WebIDBKeyView WebIDBKeyRange::Lower() const {
- if (!private_.Get())
- return WebIDBKeyView(nullptr);
- return WebIDBKeyView(private_->Lower());
-}
-
-WebIDBKeyView WebIDBKeyRange::Upper() const {
- if (!private_.Get())
- return WebIDBKeyView(nullptr);
- return WebIDBKeyView(private_->Upper());
-}
-
-bool WebIDBKeyRange::LowerOpen() const {
- return private_.Get() && private_->lowerOpen();
-}
-
-bool WebIDBKeyRange::UpperOpen() const {
- return private_.Get() && private_->upperOpen();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_idb_value.cc b/chromium/third_party/blink/renderer/modules/exported/web_idb_value.cc
deleted file mode 100644
index 11ea6453954..00000000000
--- a/chromium/third_party/blink/renderer/modules/exported/web_idb_value.cc
+++ /dev/null
@@ -1,56 +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 "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
-#include "third_party/blink/public/platform/web_blob_info.h"
-#include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
-
-namespace blink {
-
-WebIDBValue::WebIDBValue(const WebData& data,
- const WebVector<WebBlobInfo>& blob_info)
- : private_(IDBValue::Create(data, blob_info)) {
-#if DCHECK_IS_ON()
- private_->SetIsOwnedByWebIDBValue(true);
-#endif // DCHECK_IS_ON()
-}
-
-WebIDBValue::WebIDBValue(WebIDBValue&&) noexcept = default;
-WebIDBValue& WebIDBValue::operator=(WebIDBValue&&) noexcept = default;
-
-WebIDBValue::~WebIDBValue() noexcept = default;
-
-void WebIDBValue::SetInjectedPrimaryKey(WebIDBKey primary_key,
- const WebIDBKeyPath& primary_key_path) {
- private_->SetInjectedPrimaryKey(primary_key.ReleaseIdbKey(),
- IDBKeyPath(primary_key_path));
-}
-
-WebVector<WebBlobInfo> WebIDBValue::BlobInfoForTesting() const {
- return private_->BlobInfo();
-}
-
-std::unique_ptr<IDBValue> WebIDBValue::ReleaseIdbValue() noexcept {
-#if DCHECK_IS_ON()
- ReleaseIdbValueOwnership();
-#endif // DCHECK_IS_ON()
- return std::move(private_);
-}
-
-#if DCHECK_IS_ON()
-
-void WebIDBValue::ReleaseIdbValueOwnership() {
- private_->SetIsOwnedByWebIDBValue(false);
-}
-
-#endif // DCHECK_IS_ON()
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
index ef664f7d585..014c2e13c02 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
@@ -79,16 +79,17 @@ class CreateFileHelper final : public AsyncFileSystemCallbacks {
public:
class CreateFileResult : public GarbageCollected<CreateFileResult> {
public:
- static CreateFileResult* Create() { return new CreateFileResult(); }
+ static CreateFileResult* Create() {
+ return MakeGarbageCollected<CreateFileResult>();
+ }
+
+ CreateFileResult() : failed_(false), error_(base::File::FILE_OK) {}
bool failed_;
base::File::Error error_;
Member<File> file_;
void Trace(blink::Visitor* visitor) { visitor->Trace(file_); }
-
- private:
- CreateFileResult() : failed_(false), error_(base::File::FILE_OK) {}
};
static std::unique_ptr<AsyncFileSystemCallbacks> Create(
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc
index c6c2d0525e3..985793bff20 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc
@@ -52,9 +52,10 @@ ScriptPromise FileSystemBaseHandle::copyTo(ScriptState* script_state,
ScriptPromise FileSystemBaseHandle::remove(ScriptState* script_state) {
auto* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise result = resolver->Promise();
- filesystem()->Remove(this,
- new VoidCallbacks::OnDidSucceedPromiseImpl(resolver),
- MakeGarbageCollected<PromiseErrorCallback>(resolver));
+ filesystem()->Remove(
+ this,
+ MakeGarbageCollected<VoidCallbacks::OnDidSucceedPromiseImpl>(resolver),
+ MakeGarbageCollected<PromiseErrorCallback>(resolver));
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc
index 2afc8215e5f..0be01e921e8 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc
@@ -59,7 +59,8 @@ ScriptPromise FileSystemDirectoryHandle::getSystemDirectory(
LocalFileSystem::From(*context)->RequestFileSystem(
context, mojom::blink::FileSystemType::kTemporary, /*size=*/0,
FileSystemCallbacks::Create(
- new FileSystemCallbacks::OnDidOpenFileSystemPromiseImpl(resolver),
+ MakeGarbageCollected<
+ FileSystemCallbacks::OnDidOpenFileSystemPromiseImpl>(resolver),
MakeGarbageCollected<PromiseErrorCallback>(resolver), context,
mojom::blink::FileSystemType::kTemporary),
LocalFileSystem::kAsynchronous);
@@ -75,7 +76,8 @@ void ReturnDataFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
} // namespace
ScriptValue FileSystemDirectoryHandle::getEntries(ScriptState* script_state) {
- auto* iterator = new FileSystemDirectoryIterator(filesystem(), fullPath());
+ auto* iterator = MakeGarbageCollected<FileSystemDirectoryIterator>(
+ filesystem(), fullPath());
auto* isolate = script_state->GetIsolate();
auto context = script_state->GetContext();
v8::Local<v8::Object> result = v8::Object::New(isolate);
@@ -95,7 +97,8 @@ ScriptPromise FileSystemDirectoryHandle::removeRecursively(
auto* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise result = resolver->Promise();
filesystem()->RemoveRecursively(
- this, new VoidCallbacks::OnDidSucceedPromiseImpl(resolver),
+ this,
+ MakeGarbageCollected<VoidCallbacks::OnDidSucceedPromiseImpl>(resolver),
MakeGarbageCollected<PromiseErrorCallback>(resolver));
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl
index bb376bb9220..85c7bfd383d 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl
@@ -9,6 +9,6 @@
NoInterfaceObject,
RuntimeEnabled=WritableFiles
] interface FileSystemDirectoryIterator {
- [CallWith=ScriptState] Promise next();
+ [CallWith=ScriptState] Promise<any> next();
[ImplementedAs=IteratorReturn] void return();
};
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
index a910df063c9..91de230246c 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -4,6 +4,9 @@
#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h"
+#include <memory>
+#include <utility>
+
#include "build/build_config.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
@@ -81,7 +84,7 @@ FileSystemDispatcher& FileSystemDispatcher::From(ExecutionContext* context) {
FileSystemDispatcher* dispatcher =
Supplement<ExecutionContext>::From<FileSystemDispatcher>(context);
if (!dispatcher) {
- dispatcher = new FileSystemDispatcher(*context);
+ dispatcher = MakeGarbageCollected<FileSystemDispatcher>(*context);
Supplement<ExecutionContext>::ProvideTo(*context, dispatcher);
}
return *dispatcher;
@@ -105,23 +108,23 @@ mojom::blink::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() {
}
void FileSystemDispatcher::OpenFileSystem(
- const KURL& origin_url,
+ const SecurityOrigin* origin,
mojom::blink::FileSystemType type,
std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
GetFileSystemManager().Open(
- origin_url, type,
+ origin, type,
WTF::Bind(&FileSystemDispatcher::DidOpenFileSystem,
WrapWeakPersistent(this), std::move(callbacks)));
}
void FileSystemDispatcher::OpenFileSystemSync(
- const KURL& origin_url,
+ const SecurityOrigin* origin,
mojom::blink::FileSystemType type,
std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
String name;
KURL root_url;
base::File::Error error_code = base::File::FILE_ERROR_FAILED;
- GetFileSystemManager().Open(origin_url, type, &name, &root_url, &error_code);
+ GetFileSystemManager().Open(origin, type, &name, &root_url, &error_code);
DidOpenFileSystem(std::move(callbacks), std::move(name), root_url,
error_code);
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
index ec5f5e8c77b..163d0db1d9b 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DISPATCHER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DISPATCHER_H_
+#include <memory>
+
#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h"
#include "third_party/blink/public/platform/web_callbacks.h"
@@ -20,6 +22,7 @@ namespace blink {
class KURL;
class ExecutionContext;
+class SecurityOrigin;
// Sends messages via mojo to the blink::mojom::FileSystemManager service
// running in the browser process. It is owned by ExecutionContext, and
@@ -37,14 +40,16 @@ class FileSystemDispatcher
static const char kSupplementName[];
static FileSystemDispatcher& From(ExecutionContext* context);
+
+ explicit FileSystemDispatcher(ExecutionContext& context);
virtual ~FileSystemDispatcher();
mojom::blink::FileSystemManager& GetFileSystemManager();
- void OpenFileSystem(const KURL& url,
+ void OpenFileSystem(const SecurityOrigin* origin,
mojom::blink::FileSystemType type,
std::unique_ptr<AsyncFileSystemCallbacks> callbacks);
- void OpenFileSystemSync(const KURL& url,
+ void OpenFileSystemSync(const SecurityOrigin* origin,
mojom::blink::FileSystemType type,
std::unique_ptr<AsyncFileSystemCallbacks> callbacks);
@@ -142,8 +147,6 @@ class FileSystemDispatcher
class WriteListener;
class ReadDirectoryListener;
- explicit FileSystemDispatcher(ExecutionContext& context);
-
void DidOpenFileSystem(std::unique_ptr<AsyncFileSystemCallbacks> callbacks,
const String& name,
const KURL& root,
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
index 95e9823fce2..7a7b1408245 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
@@ -70,7 +70,7 @@ ScriptPromise FileSystemFileHandle::getFile(ScriptState* script_state) {
file_system_url,
SnapshotFileCallback::Create(
filesystem(), name(), file_system_url,
- new OnDidCreateSnapshotFilePromise(resolver),
+ MakeGarbageCollected<OnDidCreateSnapshotFilePromise>(resolver),
MakeGarbageCollected<PromiseErrorCallback>(resolver),
ExecutionContext::From(script_state)));
return result;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc
index 9a0dcd3f2bc..04c1556bd8a 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc
@@ -164,7 +164,7 @@ ScriptPromise FileSystemWriter::WriteStream(ScriptState* script_state,
->GetTaskRunner(TaskType::kInternalDefault));
pending_operation_ = ScriptPromiseResolver::Create(script_state);
ScriptPromise result = pending_operation_->Promise();
- auto* client = new StreamWriterClient(this);
+ auto* client = MakeGarbageCollected<StreamWriterClient>(this);
stream_loader_->Start(consumer, client);
writer_->WriteStream(
position, client->TakeDataPipe(),
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc
index efd3679bafa..262e8097419 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc
@@ -161,7 +161,7 @@ class FileWriterTest : public testing::Test {
protected:
void SetUp() override {
- testable_writer_ = new TestableFileWriter();
+ testable_writer_ = MakeGarbageCollected<TestableFileWriter>();
testable_writer_->Initialize(mock_path_as_kurl(), 10);
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc
index b08ad890d0e..041d72f18fc 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/modules/filesystem/local_file_system.h"
#include <memory>
+#include <utility>
+
#include "base/feature_list.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
@@ -65,7 +67,7 @@ void ReportFailure(std::unique_ptr<AsyncFileSystemCallbacks> callbacks,
class CallbackWrapper final
: public GarbageCollectedFinalized<CallbackWrapper> {
public:
- CallbackWrapper(std::unique_ptr<AsyncFileSystemCallbacks> c)
+ explicit CallbackWrapper(std::unique_ptr<AsyncFileSystemCallbacks> c)
: callbacks_(std::move(c)) {}
virtual ~CallbackWrapper() = default;
std::unique_ptr<AsyncFileSystemCallbacks> Release() {
@@ -85,7 +87,8 @@ void LocalFileSystem::ResolveURL(
const KURL& file_system_url,
std::unique_ptr<AsyncFileSystemCallbacks> callbacks,
SynchronousType type) {
- CallbackWrapper* wrapper = new CallbackWrapper(std::move(callbacks));
+ CallbackWrapper* wrapper =
+ MakeGarbageCollected<CallbackWrapper>(std::move(callbacks));
RequestFileSystemAccessInternal(
context,
WTF::Bind(&LocalFileSystem::ResolveURLInternal,
@@ -102,7 +105,8 @@ void LocalFileSystem::RequestFileSystem(
long long size,
std::unique_ptr<AsyncFileSystemCallbacks> callbacks,
SynchronousType sync_type) {
- CallbackWrapper* wrapper = new CallbackWrapper(std::move(callbacks));
+ CallbackWrapper* wrapper =
+ MakeGarbageCollected<CallbackWrapper>(std::move(callbacks));
RequestFileSystemAccessInternal(
context,
WTF::Bind(&LocalFileSystem::FileSystemAllowedInternal,
@@ -151,16 +155,14 @@ void LocalFileSystem::FileSystemAllowedInternal(
mojom::blink::FileSystemType type,
CallbackWrapper* callbacks,
SynchronousType sync_type) {
- KURL storage_partition =
- KURL(NullURL(), context->GetSecurityOrigin()->ToString());
std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks =
callbacks->Release();
FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context);
if (sync_type == kSynchronous) {
- dispatcher.OpenFileSystemSync(storage_partition, type,
+ dispatcher.OpenFileSystemSync(context->GetSecurityOrigin(), type,
std::move(async_callbacks));
} else {
- dispatcher.OpenFileSystem(storage_partition, type,
+ dispatcher.OpenFileSystem(context->GetSecurityOrigin(), type,
std::move(async_callbacks));
}
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h b/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h
index 805ce4c2114..89aa7d3c75e 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h
+++ b/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h
@@ -53,7 +53,7 @@ class DOMFileSystemCallbacksSyncHelper final
void Trace(blink::Visitor* visitor) { visitor->Trace(result_); }
SuccessCallback* GetSuccessCallback() {
- return new SuccessCallbackImpl(this);
+ return MakeGarbageCollected<SuccessCallbackImpl>(this);
}
ErrorCallbackBase* GetErrorCallback() {
return MakeGarbageCollected<ErrorCallbackImpl>(this);
@@ -71,6 +71,9 @@ class DOMFileSystemCallbacksSyncHelper final
private:
class SuccessCallbackImpl final : public SuccessCallback {
public:
+ explicit SuccessCallbackImpl(DOMFileSystemCallbacksSyncHelper* helper)
+ : helper_(helper) {}
+
void Trace(blink::Visitor* visitor) override {
visitor->Trace(helper_);
SuccessCallback::Trace(visitor);
@@ -81,8 +84,6 @@ class DOMFileSystemCallbacksSyncHelper final
}
private:
- explicit SuccessCallbackImpl(DOMFileSystemCallbacksSyncHelper* helper)
- : helper_(helper) {}
Member<DOMFileSystemCallbacksSyncHelper> helper_;
friend class DOMFileSystemCallbacksSyncHelper;
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/BUILD.gn b/chromium/third_party/blink/renderer/modules/gamepad/BUILD.gn
index e50e5a69392..5835c74d2ab 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/gamepad/BUILD.gn
@@ -14,6 +14,8 @@ blink_modules_sources("gamepad") {
"gamepad_button.h",
"gamepad_button_event.cc",
"gamepad_button_event.h",
+ "gamepad_comparisons.cc",
+ "gamepad_comparisons.h",
"gamepad_dispatcher.cc",
"gamepad_dispatcher.h",
"gamepad_event.cc",
@@ -36,3 +38,24 @@ blink_modules_sources("gamepad") {
"//third_party/blink/public:blink_headers",
]
}
+
+jumbo_source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "gamepad_comparisons_test.cc",
+ ]
+
+ configs += [
+ "//third_party/blink/renderer:config",
+ "//third_party/blink/renderer:inside_blink",
+ "//third_party/blink/renderer/core:blink_core_pch",
+ ]
+
+ deps = [
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/blink/renderer/modules",
+ "//third_party/blink/renderer/platform",
+ "//third_party/blink/renderer/platform/wtf",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc
index b131b170f05..5db3a292274 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc
@@ -29,8 +29,9 @@
namespace blink {
-Gamepad::Gamepad()
- : index_(0),
+Gamepad::Gamepad(ExecutionContext* context)
+ : ContextClient(context),
+ index_(0),
timestamp_(0.0),
display_id_(0),
is_axis_data_dirty_(true),
@@ -38,6 +39,11 @@ Gamepad::Gamepad()
Gamepad::~Gamepad() = default;
+// static
+Gamepad* Gamepad::Create(ExecutionContext* context) {
+ return MakeGarbageCollected<Gamepad>(context);
+}
+
const Gamepad::DoubleVector& Gamepad::axes() {
is_axis_data_dirty_ = false;
return axes_;
@@ -89,8 +95,10 @@ void Gamepad::SetVibrationActuator(
return;
}
- if (!vibration_actuator_)
- vibration_actuator_ = GamepadHapticActuator::Create(index_);
+ if (!vibration_actuator_) {
+ vibration_actuator_ =
+ GamepadHapticActuator::Create(GetExecutionContext(), index_);
+ }
vibration_actuator_->SetType(actuator.type);
}
@@ -129,6 +137,7 @@ void Gamepad::Trace(blink::Visitor* visitor) {
visitor->Trace(vibration_actuator_);
visitor->Trace(pose_);
ScriptWrappable::Trace(visitor);
+ ContextClient::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.h
index 0d60c72d6a3..6aef9ad6fee 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.h
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/modules/gamepad/gamepad_button.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_pose.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -38,13 +39,15 @@
namespace blink {
-class Gamepad final : public ScriptWrappable {
+class MODULES_EXPORT Gamepad final : public ScriptWrappable,
+ public ContextClient {
DEFINE_WRAPPERTYPEINFO();
+ USING_GARBAGE_COLLECTED_MIXIN(Gamepad);
public:
- static Gamepad* Create() { return MakeGarbageCollected<Gamepad>(); }
+ static Gamepad* Create(ExecutionContext* context);
- Gamepad();
+ explicit Gamepad(ExecutionContext*);
~Gamepad() override;
typedef Vector<double> DoubleVector;
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.idl b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.idl
index e4abab52994..b34667beb1b 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.idl
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.idl
@@ -43,7 +43,7 @@ interface Gamepad {
// https://github.com/w3c/gamepad/pull/68
[RuntimeEnabled=GamepadVibration, MeasureAs=GamepadVibrationActuator] readonly attribute GamepadHapticActuator? vibrationActuator;
- [OriginTrialEnabled=GamepadExtensions, MeasureAs=GamepadPose] readonly attribute GamepadPose? pose;
+ [RuntimeEnabled=WebVRGamepadSupport, MeasureAs=GamepadPose] readonly attribute GamepadPose? pose;
[OriginTrialEnabled=WebXRGamepadSupport, MeasureAs=GamepadHand] readonly attribute GamepadHand hand;
// https://w3c.github.io/webvr/#interface-gamepad
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_axis_event.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_axis_event.h
index 09edeea4d67..d97b0aaf8d5 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_axis_event.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_axis_event.h
@@ -21,21 +21,14 @@ class GamepadAxisEvent final : public GamepadEvent {
Gamepad* gamepad,
uint32_t axis,
double value) {
- return new GamepadAxisEvent(type, bubbles, cancelable, gamepad, axis,
- value);
+ return MakeGarbageCollected<GamepadAxisEvent>(type, bubbles, cancelable,
+ gamepad, axis, value);
}
static GamepadAxisEvent* Create(const AtomicString& type,
const GamepadAxisEventInit* initializer) {
- return new GamepadAxisEvent(type, initializer);
+ return MakeGarbageCollected<GamepadAxisEvent>(type, initializer);
}
- ~GamepadAxisEvent() override;
-
- uint32_t getAxis() const { return axis_; }
- double getValue() const { return value_; }
- const AtomicString& InterfaceName() const override;
-
- private:
GamepadAxisEvent(const AtomicString& type,
Bubbles,
Cancelable,
@@ -43,7 +36,14 @@ class GamepadAxisEvent final : public GamepadEvent {
uint32_t axis,
double value);
GamepadAxisEvent(const AtomicString&, const GamepadAxisEventInit*);
+ ~GamepadAxisEvent() override;
+
+ uint32_t getAxis() const { return axis_; }
+ double getValue() const { return value_; }
+ const AtomicString& InterfaceName() const override;
+
+ private:
uint32_t axis_ = 0;
double value_ = 0.0;
};
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button.idl b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button.idl
index a36a3b8ec57..99fae2f2517 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button.idl
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button.idl
@@ -4,7 +4,6 @@
interface GamepadButton {
readonly attribute boolean pressed;
- // TODO(bajones): Enable this by default as it is part of the core spec.
- [OriginTrialEnabled=WebXRGamepadSupport, MeasureAs=GamepadButtonTouched] readonly attribute boolean touched;
+ [MeasureAs=GamepadButtonTouched] readonly attribute boolean touched;
readonly attribute double value;
};
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button_event.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button_event.h
index 0ad4ac9455a..60efaf6955d 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button_event.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_button_event.h
@@ -22,21 +22,14 @@ class GamepadButtonEvent final : public GamepadEvent {
Gamepad* gamepad,
uint32_t button,
double value) {
- return new GamepadButtonEvent(type, bubbles, cancelable, gamepad, button,
- value);
+ return MakeGarbageCollected<GamepadButtonEvent>(type, bubbles, cancelable,
+ gamepad, button, value);
}
static GamepadButtonEvent* Create(const AtomicString& type,
const GamepadButtonEventInit* initializer) {
- return new GamepadButtonEvent(type, initializer);
+ return MakeGarbageCollected<GamepadButtonEvent>(type, initializer);
}
- ~GamepadButtonEvent() override;
-
- uint32_t getButton() const { return button_; }
- double getValue() const { return value_; }
- const AtomicString& InterfaceName() const override;
-
- private:
GamepadButtonEvent(const AtomicString& type,
Bubbles,
Cancelable,
@@ -44,7 +37,14 @@ class GamepadButtonEvent final : public GamepadEvent {
uint32_t button,
double value);
GamepadButtonEvent(const AtomicString&, const GamepadButtonEventInit*);
+ ~GamepadButtonEvent() override;
+
+ uint32_t getButton() const { return button_; }
+ double getValue() const { return value_; }
+ const AtomicString& InterfaceName() const override;
+
+ private:
uint32_t button_ = 0;
double value_ = 0.0;
};
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.cc
new file mode 100644
index 00000000000..a3f11417bd8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.cc
@@ -0,0 +1,237 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h"
+
+#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
+
+namespace blink {
+
+namespace {
+
+// A button press must have a value at least this large to qualify as a user
+// activation. The selected value should be greater than 0.5 so that axes
+// incorrectly mapped as triggers do not generate activations in the idle
+// position.
+const double kButtonActivationThreshold = 0.9;
+
+} // namespace
+
+// static
+bool GamepadComparisons::HasUserActivation(GamepadList* gamepads) {
+ if (!gamepads)
+ return false;
+ // A button press counts as a user activation if the button's value is greater
+ // than the activation threshold. A threshold is used so that analog buttons
+ // or triggers do not generate an activation from a light touch.
+ for (wtf_size_t pad_index = 0; pad_index < gamepads->length(); ++pad_index) {
+ Gamepad* pad = gamepads->item(pad_index);
+ if (pad) {
+ for (auto button : pad->buttons()) {
+ if (button->value() > kButtonActivationThreshold)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// static
+void GamepadComparisons::HasGamepadConnectionChanged(bool old_connected,
+ bool new_connected,
+ bool id_changed,
+ bool* gamepad_found,
+ bool* gamepad_lost) {
+ if (gamepad_found)
+ *gamepad_found = id_changed || (!old_connected && new_connected);
+ if (gamepad_lost)
+ *gamepad_lost = id_changed || (old_connected && !new_connected);
+}
+
+GamepadStateCompareResult::GamepadStateCompareResult(GamepadList* old_gamepads,
+ GamepadList* new_gamepads,
+ bool compare_all_axes,
+ bool compare_all_buttons) {
+ any_change_ = CompareGamepads(old_gamepads, new_gamepads, compare_all_axes,
+ compare_all_buttons);
+}
+
+bool GamepadStateCompareResult::IsDifferent() const {
+ return any_change_;
+}
+
+bool GamepadStateCompareResult::IsGamepadConnected(size_t pad_index) const {
+ DCHECK_LT(pad_index, device::Gamepads::kItemsLengthCap);
+ return gamepad_connected_.test(pad_index);
+}
+
+bool GamepadStateCompareResult::IsGamepadDisconnected(size_t pad_index) const {
+ DCHECK_LT(pad_index, device::Gamepads::kItemsLengthCap);
+ return gamepad_disconnected_.test(pad_index);
+}
+
+bool GamepadStateCompareResult::IsAxisChanged(size_t pad_index,
+ size_t axis_index) const {
+ DCHECK_LT(pad_index, device::Gamepads::kItemsLengthCap);
+ DCHECK_LT(axis_index, device::Gamepad::kAxesLengthCap);
+ return axis_changed_[pad_index].test(axis_index);
+}
+
+bool GamepadStateCompareResult::IsButtonChanged(size_t pad_index,
+ size_t button_index) const {
+ DCHECK_LT(pad_index, device::Gamepads::kItemsLengthCap);
+ DCHECK_LT(button_index, device::Gamepad::kButtonsLengthCap);
+ return button_changed_[pad_index].test(button_index);
+}
+
+bool GamepadStateCompareResult::IsButtonDown(size_t pad_index,
+ size_t button_index) const {
+ DCHECK_LT(pad_index, device::Gamepads::kItemsLengthCap);
+ DCHECK_LT(button_index, device::Gamepad::kButtonsLengthCap);
+ return button_down_[pad_index].test(button_index);
+}
+
+bool GamepadStateCompareResult::IsButtonUp(size_t pad_index,
+ size_t button_index) const {
+ DCHECK_LT(pad_index, device::Gamepads::kItemsLengthCap);
+ DCHECK_LT(button_index, device::Gamepad::kButtonsLengthCap);
+ return button_up_[pad_index].test(button_index);
+}
+
+bool GamepadStateCompareResult::CompareGamepads(GamepadList* old_gamepads,
+ GamepadList* new_gamepads,
+ bool compare_all_axes,
+ bool compare_all_buttons) {
+ if (!new_gamepads)
+ return false;
+ bool any_change = false;
+ for (uint32_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
+ Gamepad* old_gamepad = old_gamepads ? old_gamepads->item(i) : nullptr;
+ Gamepad* new_gamepad = new_gamepads->item(i);
+ // Check whether the gamepad is newly connected or disconnected.
+ bool newly_connected = false;
+ bool newly_disconnected = false;
+ bool old_connected = old_gamepad && old_gamepad->connected();
+ bool new_connected = new_gamepad && new_gamepad->connected();
+ if (old_gamepad && new_gamepad) {
+ GamepadComparisons::HasGamepadConnectionChanged(
+ old_connected, new_connected, old_gamepad->id() != new_gamepad->id(),
+ &newly_connected, &newly_disconnected);
+ } else {
+ newly_connected = new_connected;
+ newly_disconnected = old_connected;
+ }
+
+ bool any_axis_updated =
+ CompareAxes(old_gamepad, new_gamepad, i, compare_all_axes);
+ bool any_button_updated =
+ CompareButtons(old_gamepad, new_gamepad, i, compare_all_buttons);
+
+ if (newly_connected)
+ gamepad_connected_.set(i);
+ if (newly_disconnected)
+ gamepad_disconnected_.set(i);
+ if (newly_connected || newly_disconnected || any_axis_updated ||
+ any_button_updated) {
+ any_change = true;
+ }
+ }
+ return any_change;
+}
+
+bool GamepadStateCompareResult::CompareAxes(Gamepad* old_gamepad,
+ Gamepad* new_gamepad,
+ size_t index,
+ bool compare_all) {
+ DCHECK_LT(index, device::Gamepads::kItemsLengthCap);
+ if (!new_gamepad)
+ return false;
+ auto& changed_set = axis_changed_[index];
+ const auto& new_axes = new_gamepad->axes();
+ const auto* old_axes = old_gamepad ? &old_gamepad->axes() : nullptr;
+ bool any_axis_changed = false;
+ for (wtf_size_t i = 0; i < new_axes.size(); ++i) {
+ double new_value = new_axes[i];
+ if (old_axes && i < old_axes->size()) {
+ double old_value = old_axes->at(i);
+ if (old_value != new_value) {
+ any_axis_changed = true;
+ if (!compare_all)
+ break;
+ changed_set.set(i);
+ }
+ } else {
+ if (new_value) {
+ any_axis_changed = true;
+ if (!compare_all)
+ break;
+ changed_set.set(i);
+ }
+ }
+ }
+ return any_axis_changed;
+}
+
+bool GamepadStateCompareResult::CompareButtons(Gamepad* old_gamepad,
+ Gamepad* new_gamepad,
+ size_t index,
+ bool compare_all) {
+ DCHECK_LT(index, device::Gamepads::kItemsLengthCap);
+ if (!new_gamepad)
+ return false;
+ auto& changed_set = button_changed_[index];
+ auto& down_set = button_down_[index];
+ auto& up_set = button_up_[index];
+ const auto& new_buttons = new_gamepad->buttons();
+ const auto* old_buttons = old_gamepad ? &old_gamepad->buttons() : nullptr;
+ bool any_button_changed = false;
+ for (wtf_size_t i = 0; i < new_buttons.size(); ++i) {
+ double new_value = new_buttons[i]->value();
+ bool new_pressed = new_buttons[i]->pressed();
+ if (old_buttons && i < old_buttons->size()) {
+ double old_value = old_buttons->at(i)->value();
+ bool old_pressed = old_buttons->at(i)->pressed();
+ if (old_value != new_value) {
+ any_button_changed = true;
+ if (!compare_all)
+ break;
+ changed_set.set(i);
+ }
+ if (old_pressed != new_pressed) {
+ any_button_changed = true;
+ if (!compare_all)
+ break;
+ if (new_pressed)
+ down_set.set(i);
+ else
+ up_set.set(i);
+ }
+ } else {
+ if (new_value > 0.0) {
+ any_button_changed = true;
+ if (!compare_all)
+ break;
+ changed_set.set(i);
+ }
+ if (new_pressed) {
+ any_button_changed = true;
+ if (!compare_all)
+ break;
+ down_set.set(i);
+ }
+ }
+ }
+ return any_button_changed;
+}
+
+GamepadStateCompareResult GamepadComparisons::Compare(
+ GamepadList* old_gamepads,
+ GamepadList* new_gamepads,
+ bool compare_all_axes,
+ bool compare_all_buttons) {
+ return GamepadStateCompareResult(old_gamepads, new_gamepads, compare_all_axes,
+ compare_all_buttons);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h
new file mode 100644
index 00000000000..770488e0042
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h
@@ -0,0 +1,90 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_COMPARISONS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_COMPARISONS_H_
+
+#include <bitset>
+
+#include "device/gamepad/public/cpp/gamepads.h"
+#include "third_party/blink/renderer/modules/gamepad/gamepad_list.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+// Stores the result of a comparison between two GamepadLists.
+class MODULES_EXPORT GamepadStateCompareResult {
+ public:
+ GamepadStateCompareResult(GamepadList* old_gamepads,
+ GamepadList* new_gamepads,
+ bool compare_all_axes,
+ bool compare_all_buttons);
+ ~GamepadStateCompareResult() = default;
+
+ // True if any difference was detected (besides timestamp).
+ bool IsDifferent() const;
+
+ // True if the corresponding gamepad event should be dispatched.
+ bool IsGamepadConnected(size_t pad_index) const;
+ bool IsGamepadDisconnected(size_t pad_index) const;
+ bool IsAxisChanged(size_t pad_index, size_t axis_index) const;
+ bool IsButtonChanged(size_t pad_index, size_t button_index) const;
+ bool IsButtonDown(size_t pad_index, size_t button_index) const;
+ bool IsButtonUp(size_t pad_index, size_t button_index) const;
+
+ private:
+ bool CompareGamepads(GamepadList* old_gamepads,
+ GamepadList* new_gamepads,
+ bool compare_all_axes,
+ bool compare_all_buttons);
+ bool CompareAxes(Gamepad* old_gamepad,
+ Gamepad* new_gamepad,
+ size_t gamepad_index,
+ bool compare_all);
+ bool CompareButtons(Gamepad* old_gamepad,
+ Gamepad* new_gamepad,
+ size_t gamepad_index,
+ bool compare_all);
+
+ bool any_change_ = false;
+ std::bitset<device::Gamepads::kItemsLengthCap> gamepad_connected_;
+ std::bitset<device::Gamepads::kItemsLengthCap> gamepad_disconnected_;
+ std::bitset<device::Gamepad::kAxesLengthCap>
+ axis_changed_[device::Gamepads::kItemsLengthCap];
+ std::bitset<device::Gamepad::kButtonsLengthCap>
+ button_changed_[device::Gamepads::kItemsLengthCap];
+ std::bitset<device::Gamepad::kButtonsLengthCap>
+ button_down_[device::Gamepads::kItemsLengthCap];
+ std::bitset<device::Gamepad::kButtonsLengthCap>
+ button_up_[device::Gamepads::kItemsLengthCap];
+};
+
+class MODULES_EXPORT GamepadComparisons {
+ public:
+ // Inspect the gamepad state in |gamepads| and return true if any gamepads
+ // have a user activation gesture.
+ static bool HasUserActivation(GamepadList* gamepads);
+
+ // Given the connection state of a gamepad in consecutive samples and whether
+ // the ID string changed, return whether the gamepad was newly connected in
+ // |gamepad_found| and whether it was newly disconnected in |gamepad_lost|.
+ static void HasGamepadConnectionChanged(bool old_connected,
+ bool new_connected,
+ bool id_changed,
+ bool* gamepad_found,
+ bool* gamepad_lost);
+
+ // Compare the previously sampled gamepad state in |old_gamepads| with a new
+ // sample in |new_gamepads|. If |compare_all_axes| or |compare_all_buttons|
+ // is true, all axes or buttons will be compared. Otherwise, the comparison
+ // will short-circuit after the first difference.
+ static GamepadStateCompareResult Compare(GamepadList* old_gamepads,
+ GamepadList* new_gamepads,
+ bool compare_all_axes,
+ bool compare_all_buttons);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_COMPARISONS_H_
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc
new file mode 100644
index 00000000000..78a61e450ab
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc
@@ -0,0 +1,362 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h"
+
+#include "base/macros.h"
+#include "device/gamepad/public/cpp/gamepad.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
+#include "third_party/blink/renderer/modules/gamepad/gamepad_list.h"
+
+namespace blink {
+
+class GamepadComparisonsTest : public testing::Test {
+ public:
+ GamepadComparisonsTest() = default;
+
+ protected:
+ GamepadList* CreateEmptyGamepadList() { return GamepadList::Create(); }
+
+ GamepadList* CreateGamepadListWithNeutralGamepad() {
+ double axes[1] = {0.0};
+ device::GamepadButton buttons[1] = {{false, false, 0.0}};
+ auto* list = GamepadList::Create();
+ auto* gamepad = Gamepad::Create(nullptr);
+ gamepad->SetId("gamepad");
+ gamepad->SetIndex(0);
+ gamepad->SetAxes(1, axes);
+ gamepad->SetButtons(1, buttons);
+ gamepad->SetConnected(true);
+ list->Set(0, gamepad);
+ return list;
+ }
+
+ GamepadList* CreateGamepadListWithAxisTilt() {
+ double axes[1] = {0.95};
+ device::GamepadButton buttons[1] = {{false, false, 0.0}};
+
+ auto* list = GamepadList::Create();
+ auto* gamepad = Gamepad::Create(nullptr);
+ gamepad->SetId("gamepad");
+ gamepad->SetIndex(0);
+ gamepad->SetAxes(1, axes);
+ gamepad->SetButtons(1, buttons);
+ gamepad->SetConnected(true);
+ list->Set(0, gamepad);
+ return list;
+ }
+
+ GamepadList* CreateGamepadListWithButtonDown() {
+ double axes[1] = {0.0};
+ device::GamepadButton buttons[1] = {{true, true, 1.0}};
+
+ auto* list = GamepadList::Create();
+ auto* gamepad = Gamepad::Create(nullptr);
+ gamepad->SetId("gamepad");
+ gamepad->SetIndex(0);
+ gamepad->SetAxes(1, axes);
+ gamepad->SetButtons(1, buttons);
+ gamepad->SetConnected(true);
+ list->Set(0, gamepad);
+ return list;
+ }
+
+ GamepadList* CreateGamepadListWithButtonTouched() {
+ double axes[1] = {0.0};
+ device::GamepadButton buttons[1] = {{
+ false,
+ true,
+ // Just before the "pressed" threshold.
+ device::GamepadButton::kDefaultButtonPressedThreshold - 0.01,
+ }};
+
+ auto* list = GamepadList::Create();
+ auto* gamepad = Gamepad::Create(nullptr);
+ gamepad->SetId("gamepad");
+ gamepad->SetIndex(0);
+ gamepad->SetAxes(1, axes);
+ gamepad->SetButtons(1, buttons);
+ gamepad->SetConnected(true);
+ list->Set(0, gamepad);
+ return list;
+ }
+
+ GamepadList* CreateGamepadListWithButtonJustDown() {
+ double axes[1] = {0.0};
+ device::GamepadButton buttons[1] = {{
+ true,
+ true,
+ // Just beyond the "pressed" threshold.
+ device::GamepadButton::kDefaultButtonPressedThreshold + 0.01,
+ }};
+
+ auto* list = GamepadList::Create();
+ auto* gamepad = Gamepad::Create(nullptr);
+ gamepad->SetId("gamepad");
+ gamepad->SetIndex(0);
+ gamepad->SetAxes(1, axes);
+ gamepad->SetButtons(1, buttons);
+ gamepad->SetConnected(true);
+ list->Set(0, gamepad);
+ return list;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GamepadComparisonsTest);
+};
+
+TEST_F(GamepadComparisonsTest, EmptyListCausesNoActivation) {
+ auto* list = CreateEmptyGamepadList();
+ EXPECT_FALSE(GamepadComparisons::HasUserActivation(list));
+}
+
+TEST_F(GamepadComparisonsTest, NeutralGamepadCausesNoActivation) {
+ auto* list = CreateGamepadListWithNeutralGamepad();
+ EXPECT_FALSE(GamepadComparisons::HasUserActivation(list));
+}
+
+TEST_F(GamepadComparisonsTest, AxisTiltCausesNoActivation) {
+ auto* list = CreateGamepadListWithAxisTilt();
+ EXPECT_FALSE(GamepadComparisons::HasUserActivation(list));
+}
+
+TEST_F(GamepadComparisonsTest, ButtonDownCausesActivation) {
+ auto* list = CreateGamepadListWithButtonDown();
+ EXPECT_TRUE(GamepadComparisons::HasUserActivation(list));
+}
+
+TEST_F(GamepadComparisonsTest, CompareEmptyLists) {
+ // Simulate no connected gamepads.
+ auto* list1 = CreateEmptyGamepadList();
+ auto* list2 = CreateEmptyGamepadList();
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_FALSE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareNeutrals) {
+ // Simulate a neutral gamepad with no input changes.
+ auto* list1 = CreateGamepadListWithNeutralGamepad();
+ auto* list2 = CreateGamepadListWithNeutralGamepad();
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_FALSE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareEmptyListWithNeutral) {
+ // Simulate a connection.
+ auto* list1 = CreateEmptyGamepadList();
+ auto* list2 = CreateGamepadListWithNeutralGamepad();
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_TRUE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareNeutralWithEmptyList) {
+ // Simulate a disconnection.
+ auto* list1 = CreateGamepadListWithNeutralGamepad();
+ auto* list2 = CreateEmptyGamepadList();
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_TRUE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareNeutralWithAxisTilt) {
+ // Simulate tilting an axis away from neutral.
+ auto* list1 = CreateGamepadListWithNeutralGamepad();
+ auto* list2 = CreateGamepadListWithAxisTilt();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_TRUE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+
+ // Using compare_all_axes=false, comparison flags are not set for individual
+ // axes.
+ auto compareResult2 = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes*/ false, /*compare_all_buttons*/ true);
+ EXPECT_TRUE(compareResult2.IsDifferent());
+ EXPECT_FALSE(compareResult2.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult2.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult2.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult2.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult2.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult2.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareNeutralWithButtonDown) {
+ // Simulate pressing a digital (on/off) button.
+ auto* list1 = CreateGamepadListWithNeutralGamepad();
+ auto* list2 = CreateGamepadListWithButtonDown();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+
+ // Using compare_all_buttons=false, comparison flags are not set for
+ // individual buttons.
+ auto compareResult2 = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes*/ true, /*compare_all_buttons*/ false);
+ EXPECT_TRUE(compareResult2.IsDifferent());
+ EXPECT_FALSE(compareResult2.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult2.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult2.IsAxisChanged(0, 0));
+ EXPECT_FALSE(compareResult2.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult2.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult2.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareButtonDownWithNeutral) {
+ // Simulate releasing a digital (on/off) button.
+ auto* list1 = CreateGamepadListWithButtonDown();
+ auto* list2 = CreateGamepadListWithNeutralGamepad();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareNeutralWithButtonTouched) {
+ // Simulate touching an analog button or trigger.
+ auto* list1 = CreateGamepadListWithNeutralGamepad();
+ auto* list2 = CreateGamepadListWithButtonTouched();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareButtonTouchedWithButtonJustDown) {
+ // Simulate pressing an analog button or trigger enough to register a button
+ // press.
+ auto* list1 = CreateGamepadListWithButtonTouched();
+ auto* list2 = CreateGamepadListWithButtonJustDown();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareButtonJustDownWithButtonDown) {
+ // Simulate continuing to press an analog button or trigger until it reaches
+ // the maximum value.
+ auto* list1 = CreateGamepadListWithButtonJustDown();
+ auto* list2 = CreateGamepadListWithButtonDown();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareButtonDownWithButtonJustDown) {
+ // Simulate releasing an analog button or trigger until it is just barely
+ // pressed.
+ auto* list1 = CreateGamepadListWithButtonDown();
+ auto* list2 = CreateGamepadListWithButtonJustDown();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareButtonJustDownWithButtonTouched) {
+ // Simulate releasing an analog button or trigger until it is no longer
+ // pressed.
+ auto* list1 = CreateGamepadListWithButtonJustDown();
+ auto* list2 = CreateGamepadListWithButtonTouched();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonUp(0, 0));
+}
+
+TEST_F(GamepadComparisonsTest, CompareButtonTouchedWithNeutral) {
+ // Simulate releasing an analog button or trigger until it is neutral.
+ auto* list1 = CreateGamepadListWithButtonTouched();
+ auto* list2 = CreateGamepadListWithNeutralGamepad();
+
+ auto compareResult = GamepadComparisons::Compare(
+ list1, list2, /*compare_all_axes=*/true, /*compare_all_buttons=*/true);
+ EXPECT_TRUE(compareResult.IsDifferent());
+ EXPECT_FALSE(compareResult.IsGamepadConnected(0));
+ EXPECT_FALSE(compareResult.IsGamepadDisconnected(0));
+ EXPECT_FALSE(compareResult.IsAxisChanged(0, 0));
+ EXPECT_TRUE(compareResult.IsButtonChanged(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonDown(0, 0));
+ EXPECT_FALSE(compareResult.IsButtonUp(0, 0));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
index 78725b41274..7c910200baa 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
@@ -15,7 +15,7 @@ using device::mojom::blink::GamepadHapticsManager;
GamepadDispatcher& GamepadDispatcher::Instance() {
DEFINE_STATIC_LOCAL(Persistent<GamepadDispatcher>, gamepad_dispatcher,
- (new GamepadDispatcher));
+ (MakeGarbageCollected<GamepadDispatcher>()));
return *gamepad_dispatcher;
}
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
index b809d7b3f33..5ed28ab1862 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
@@ -23,6 +23,8 @@ class GamepadDispatcher final
public:
static GamepadDispatcher& Instance();
+
+ GamepadDispatcher();
~GamepadDispatcher() override;
void SampleGamepads(device::Gamepads&);
@@ -39,8 +41,6 @@ class GamepadDispatcher final
void Trace(blink::Visitor*) override;
private:
- GamepadDispatcher();
-
void InitializeHaptics();
// WebGamepadListener
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.cc
index 723626dac92..72a1c55f0c0 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.cc
@@ -52,15 +52,17 @@ String ResultToString(GamepadHapticsResult result) {
namespace blink {
// static
-GamepadHapticActuator* GamepadHapticActuator::Create(int pad_index) {
+GamepadHapticActuator* GamepadHapticActuator::Create(ExecutionContext* context,
+ int pad_index) {
return MakeGarbageCollected<GamepadHapticActuator>(
- pad_index, device::GamepadHapticActuatorType::kDualRumble);
+ context, pad_index, device::GamepadHapticActuatorType::kDualRumble);
}
GamepadHapticActuator::GamepadHapticActuator(
+ ExecutionContext* context,
int pad_index,
device::GamepadHapticActuatorType type)
- : pad_index_(pad_index) {
+ : ContextClient(context), pad_index_(pad_index) {
SetType(type);
}
@@ -102,6 +104,9 @@ ScriptPromise GamepadHapticActuator::playEffect(
return promise;
}
+ // Avoid resetting vibration for a preempted effect.
+ should_reset_ = false;
+
auto callback = WTF::Bind(&GamepadHapticActuator::OnPlayEffectCompleted,
WrapPersistent(this), WrapPersistent(resolver));
@@ -121,10 +126,37 @@ void GamepadHapticActuator::OnPlayEffectCompleted(
if (result == GamepadHapticsResult::GamepadHapticsResultError) {
resolver->Reject();
return;
+ } else if (result == GamepadHapticsResult::GamepadHapticsResultComplete) {
+ should_reset_ = true;
+ ExecutionContext* context = GetExecutionContext();
+ if (context) {
+ // Post a delayed task to stop vibration. The task will be run after all
+ // callbacks have run for the effect Promise, and may be ignored by
+ // setting |should_reset_| to false. The intention is to only stop
+ // vibration if the user did not chain another vibration effect in the
+ // Promise callback.
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->PostTask(
+ FROM_HERE,
+ WTF::Bind(&GamepadHapticActuator::ResetVibrationIfNotPreempted,
+ WrapPersistent(this)));
+ } else {
+ // The execution context is gone, meaning no new effects can be issued by
+ // the page. Stop vibration without waiting for Promise callbacks.
+ ResetVibrationIfNotPreempted();
+ }
}
resolver->Resolve(ResultToString(result));
}
+void GamepadHapticActuator::ResetVibrationIfNotPreempted() {
+ if (should_reset_) {
+ should_reset_ = false;
+ GamepadDispatcher::Instance().ResetVibrationActuator(pad_index_,
+ base::DoNothing());
+ }
+}
+
ScriptPromise GamepadHapticActuator::reset(ScriptState* script_state) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
@@ -149,6 +181,7 @@ void GamepadHapticActuator::OnResetCompleted(
void GamepadHapticActuator::Trace(blink::Visitor* visitor) {
ScriptWrappable::Trace(visitor);
+ ContextClient::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h
index 57fe1468134..ba2396d07a6 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h
@@ -17,13 +17,18 @@
namespace blink {
-class GamepadHapticActuator final : public ScriptWrappable {
+class GamepadHapticActuator final : public ScriptWrappable,
+ public ContextClient {
DEFINE_WRAPPERTYPEINFO();
+ USING_GARBAGE_COLLECTED_MIXIN(GamepadHapticActuator);
public:
- static GamepadHapticActuator* Create(int pad_index);
+ static GamepadHapticActuator* Create(ExecutionContext* context,
+ int pad_index);
- GamepadHapticActuator(int pad_index, device::GamepadHapticActuatorType);
+ GamepadHapticActuator(ExecutionContext* context,
+ int pad_index,
+ device::GamepadHapticActuatorType type);
~GamepadHapticActuator() override;
const String& type() const { return type_; }
@@ -42,9 +47,11 @@ class GamepadHapticActuator final : public ScriptWrappable {
device::mojom::GamepadHapticsResult);
void OnResetCompleted(ScriptPromiseResolver*,
device::mojom::GamepadHapticsResult);
+ void ResetVibrationIfNotPreempted();
int pad_index_;
String type_;
+ bool should_reset_ = false;
};
typedef HeapVector<Member<GamepadHapticActuator>> GamepadHapticActuatorVector;
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.h
index 631abecf597..9bf52560c2d 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.h
@@ -28,12 +28,13 @@
#include "device/gamepad/public/cpp/gamepads.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
-class GamepadList final : public ScriptWrappable {
+class MODULES_EXPORT GamepadList final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl
index de8254c2dba..1d280b28d61 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl
@@ -27,5 +27,5 @@
NoInterfaceObject
] interface GamepadList {
readonly attribute unsigned long length;
- getter Gamepad item([Default=Undefined] optional unsigned long index);
+ getter Gamepad item([DefaultValue=Undefined] optional unsigned long index);
};
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl
index 05495f25d8c..f74524c347f 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl
@@ -4,7 +4,7 @@
// https://w3c.github.io/gamepad/extensions.html#gamepadpose-interface
[
- OriginTrialEnabled=GamepadExtensions
+ RuntimeEnabled=WebVRGamepadSupport
] interface GamepadPose {
[MeasureAs=GamepadPoseHasOrientation] readonly attribute boolean hasOrientation;
[MeasureAs=GamepadPoseHasPosition] readonly attribute boolean hasPosition;
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
index 3f027a1ad5a..3df145867ba 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -25,7 +25,8 @@
#include "third_party/blink/renderer/modules/gamepad/navigator_gamepad.h"
-#include "device/gamepad/public/cpp/gamepad.h"
+#include "base/auto_reset.h"
+#include "device/gamepad/public/cpp/gamepads.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
@@ -35,6 +36,7 @@
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/timing/performance.h"
+#include "third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_event.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_list.h"
@@ -44,59 +46,29 @@ namespace blink {
namespace {
-// A button press must have a value at least this large to qualify as a user
-// activation. The selected value should be greater than 0.5 so that axes
-// incorrectly mapped as triggers do not generate activations in the idle
-// position.
-const double kButtonActivationThreshold = 0.9;
-
-void HasGamepadConnectionChanged(const String& old_id,
- const String& new_id,
- bool old_connected,
- bool new_connected,
- bool* gamepad_found,
- bool* gamepad_lost) {
- // If the gamepad ID changes, treat it as a disconnection and connection.
- bool id_changed = old_connected && new_connected && old_id != new_id;
-
- if (gamepad_found)
- *gamepad_found = id_changed || (!old_connected && new_connected);
- if (gamepad_lost)
- *gamepad_lost = id_changed || (old_connected && !new_connected);
+bool IsGamepadConnectionEvent(const AtomicString& event_type) {
+ return event_type == event_type_names::kGamepadconnected ||
+ event_type == event_type_names::kGamepaddisconnected;
}
-bool HasUserActivation(GamepadList* gamepads) {
- if (!gamepads)
- return false;
- // A button press counts as a user activation if the button's value is greater
- // than the activation threshold. A threshold is used so that analog buttons
- // or triggers do not generate an activation from a light touch.
- for (wtf_size_t pad_index = 0; pad_index < gamepads->length(); ++pad_index) {
- Gamepad* pad = gamepads->item(pad_index);
- if (pad) {
- const GamepadButtonVector& buttons = pad->buttons();
- for (auto button : buttons) {
- double value = button->value();
- if (value > kButtonActivationThreshold)
- return true;
- }
- }
- }
- return false;
+bool HasConnectionEventListeners(LocalDOMWindow* window) {
+ return window->HasEventListeners(event_type_names::kGamepadconnected) ||
+ window->HasEventListeners(event_type_names::kGamepaddisconnected);
}
-} // namespace
-
-template <typename T>
-static void SampleGamepad(unsigned index,
- T& gamepad,
+static void SampleGamepad(uint32_t index,
+ Gamepad& gamepad,
const device::Gamepad& device_gamepad,
- const TimeTicks& navigation_start) {
+ const TimeTicks& navigation_start,
+ const TimeTicks& gamepads_start) {
String old_id = gamepad.id();
bool old_was_connected = gamepad.connected();
TimeTicks last_updated =
TimeTicks() + TimeDelta::FromMicroseconds(device_gamepad.timestamp);
+ if (last_updated < gamepads_start)
+ last_updated = gamepads_start;
+
DOMHighResTimeStamp timestamp =
Performance::MonotonicTimeToDOMHighResTimeStamp(navigation_start,
last_updated, false);
@@ -115,8 +87,9 @@ static void SampleGamepad(unsigned index,
}
bool newly_connected;
- HasGamepadConnectionChanged(old_id, gamepad.id(), old_was_connected,
- gamepad.connected(), &newly_connected, nullptr);
+ GamepadComparisons::HasGamepadConnectionChanged(
+ old_was_connected, gamepad.connected(), old_id != gamepad.id(),
+ &newly_connected, nullptr);
// These fields are not expected to change and will only be written when the
// gamepad is newly connected.
@@ -136,15 +109,15 @@ static void SampleGamepad(unsigned index,
}
}
-template <typename GamepadType, typename ListType>
-static void SampleGamepads(ListType* into,
- const ExecutionContext* context,
- const TimeTicks& navigation_start) {
+static void SampleGamepads(GamepadList* into,
+ ExecutionContext* context,
+ const TimeTicks& navigation_start,
+ const TimeTicks& gamepads_start) {
device::Gamepads gamepads;
GamepadDispatcher::Instance().SampleGamepads(gamepads);
- for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
+ for (uint32_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
device::Gamepad& web_gamepad = gamepads.items[i];
bool hide_xr_gamepad = false;
@@ -164,10 +137,10 @@ static void SampleGamepads(ListType* into,
if (hide_xr_gamepad) {
into->Set(i, nullptr);
} else if (web_gamepad.connected) {
- GamepadType* gamepad = into->item(i);
+ Gamepad* gamepad = into->item(i);
if (!gamepad)
- gamepad = GamepadType::Create();
- SampleGamepad(i, *gamepad, web_gamepad, navigation_start);
+ gamepad = Gamepad::Create(context);
+ SampleGamepad(i, *gamepad, web_gamepad, navigation_start, gamepads_start);
into->Set(i, gamepad);
} else {
into->Set(i, nullptr);
@@ -175,6 +148,8 @@ static void SampleGamepads(ListType* into,
}
}
+} // namespace
+
// static
const char NavigatorGamepad::kSupplementName[] = "NavigatorGamepad";
@@ -210,14 +185,20 @@ GamepadList* NavigatorGamepad::Gamepads() {
}
}
- SampleAndCheckConnectedGamepads();
+ SampleAndCompareGamepadState();
+
+ // Ensure |gamepads_| is not null.
+ if (!gamepads_)
+ gamepads_ = GamepadList::Create();
// Allow gamepad button presses to qualify as user activations if the page is
// visible.
if (RuntimeEnabledFeatures::UserActivationV2Enabled() && GetFrame() &&
- GetPage() && GetPage()->IsPageVisible() && HasUserActivation(gamepads_)) {
+ GetPage() && GetPage()->IsPageVisible() &&
+ GamepadComparisons::HasUserActivation(gamepads_)) {
LocalFrame::NotifyUserActivation(GetFrame(), UserGestureToken::kNewGesture);
}
+ is_gamepads_exposed_ = true;
return gamepads_.Get();
}
@@ -225,8 +206,6 @@ GamepadList* NavigatorGamepad::Gamepads() {
void NavigatorGamepad::Trace(blink::Visitor* visitor) {
visitor->Trace(gamepads_);
visitor->Trace(gamepads_back_);
- visitor->Trace(pending_events_);
- visitor->Trace(dispatch_one_event_runner_);
Supplement<Navigator>::Trace(visitor);
DOMWindowClient::Trace(visitor);
PlatformEventController::Trace(visitor);
@@ -246,43 +225,21 @@ void NavigatorGamepad::DidUpdateData() {
DCHECK(GetFrame());
DCHECK(DomWindow());
- // We register to the dispatcher before sampling gamepads so we need to check
- // if we actually have an event listener.
- if (!has_event_listener_)
- return;
+ // Record when gamepad data was first made available to the page.
+ if (gamepads_start_.is_null())
+ gamepads_start_ = base::TimeTicks::Now();
- SampleAndCheckConnectedGamepads();
-}
-
-void NavigatorGamepad::DispatchOneEvent() {
- DCHECK(DomWindow());
- DCHECK(!pending_events_.IsEmpty());
-
- Gamepad* gamepad = pending_events_.TakeFirst();
- const AtomicString& event_name = gamepad->connected()
- ? event_type_names::kGamepadconnected
- : event_type_names::kGamepaddisconnected;
- DomWindow()->DispatchEvent(*GamepadEvent::Create(
- event_name, Event::Bubbles::kNo, Event::Cancelable::kYes, gamepad));
-
- if (!pending_events_.IsEmpty()) {
- DCHECK(dispatch_one_event_runner_);
- dispatch_one_event_runner_->RunAsync();
- }
+ // Fetch the new gamepad state and dispatch gamepad events.
+ if (has_event_listener_)
+ SampleAndCompareGamepadState();
}
NavigatorGamepad::NavigatorGamepad(Navigator& navigator)
: Supplement<Navigator>(navigator),
DOMWindowClient(navigator.DomWindow()),
- PlatformEventController(
- navigator.GetFrame() ? navigator.GetFrame()->GetDocument() : nullptr),
- dispatch_one_event_runner_(
- navigator.GetFrame() ? AsyncMethodRunner<NavigatorGamepad>::Create(
- this,
- &NavigatorGamepad::DispatchOneEvent,
- navigator.GetFrame()->GetTaskRunner(
- TaskType::kMiscPlatformAPI))
- : nullptr) {
+ PlatformEventController(navigator.GetFrame()
+ ? navigator.GetFrame()->GetDocument()
+ : nullptr) {
if (navigator.DomWindow())
navigator.DomWindow()->RegisterEventListenerObserver(this);
@@ -299,13 +256,9 @@ NavigatorGamepad::~NavigatorGamepad() = default;
void NavigatorGamepad::RegisterWithDispatcher() {
GamepadDispatcher::Instance().AddController(this);
- if (dispatch_one_event_runner_)
- dispatch_one_event_runner_->Unpause();
}
void NavigatorGamepad::UnregisterWithDispatcher() {
- if (dispatch_one_event_runner_)
- dispatch_one_event_runner_->Pause();
GamepadDispatcher::Instance().RemoveController(this);
}
@@ -314,32 +267,27 @@ bool NavigatorGamepad::HasLastData() {
return false;
}
-static bool IsGamepadEvent(const AtomicString& event_type) {
- return event_type == event_type_names::kGamepadconnected ||
- event_type == event_type_names::kGamepaddisconnected;
-}
-
void NavigatorGamepad::DidAddEventListener(LocalDOMWindow*,
const AtomicString& event_type) {
- if (!IsGamepadEvent(event_type))
- return;
-
- bool first_event_listener = !has_event_listener_;
- has_event_listener_ = true;
-
- if (GetPage() && GetPage()->IsPageVisible()) {
- StartUpdatingIfAttached();
- if (first_event_listener)
- SampleAndCheckConnectedGamepads();
+ if (IsGamepadConnectionEvent(event_type)) {
+ has_connection_event_listener_ = true;
+ bool first_event_listener = !has_event_listener_;
+ has_event_listener_ = true;
+
+ if (GetPage() && GetPage()->IsPageVisible()) {
+ StartUpdatingIfAttached();
+ if (first_event_listener)
+ SampleAndCompareGamepadState();
+ }
}
}
void NavigatorGamepad::DidRemoveEventListener(LocalDOMWindow* window,
const AtomicString& event_type) {
- if (IsGamepadEvent(event_type) &&
- !window->HasEventListeners(event_type_names::kGamepadconnected) &&
- !window->HasEventListeners(event_type_names::kGamepaddisconnected)) {
- DidRemoveGamepadEventListeners();
+ if (IsGamepadConnectionEvent(event_type)) {
+ has_connection_event_listener_ = HasConnectionEventListeners(window);
+ if (!has_connection_event_listener_)
+ DidRemoveGamepadEventListeners();
}
}
@@ -349,82 +297,83 @@ void NavigatorGamepad::DidRemoveAllEventListeners(LocalDOMWindow*) {
void NavigatorGamepad::DidRemoveGamepadEventListeners() {
has_event_listener_ = false;
- if (dispatch_one_event_runner_)
- dispatch_one_event_runner_->Stop();
- pending_events_.clear();
StopUpdating();
}
-void NavigatorGamepad::SampleAndCheckConnectedGamepads() {
+void NavigatorGamepad::SampleAndCompareGamepadState() {
+ // Avoid re-entry. Do not fetch a new sample until we are finished dispatching
+ // events from the previous sample.
+ if (processing_events_)
+ return;
+
ExecutionContext* execution_context =
DomWindow() ? DomWindow()->GetExecutionContext() : nullptr;
+ base::AutoReset<bool>(&processing_events_, true);
if (StartUpdatingIfAttached()) {
- if (!gamepads_)
- gamepads_ = GamepadList::Create();
- if (GetPage()->IsPageVisible() && has_event_listener_) {
+ if (GetPage()->IsPageVisible()) {
+ // Allocate a buffer to hold the new gamepad state, if needed.
if (!gamepads_back_)
gamepads_back_ = GamepadList::Create();
-
- // Compare the current sample with the old data and enqueue connection
- // events for any differences.
- SampleGamepads<Gamepad>(gamepads_back_.Get(), execution_context,
- navigation_start_);
- if (CheckConnectedGamepads(gamepads_.Get(), gamepads_back_.Get())) {
- // If we had any disconnected gamepads, we can't overwrite gamepads_
- // because the Gamepad object from the old buffer is reused as the
- // disconnection event and will be overwritten with new data. Instead,
- // recreate the buffer.
- gamepads_ = GamepadList::Create();
+ SampleGamepads(gamepads_back_.Get(), execution_context, navigation_start_,
+ gamepads_start_);
+
+ // Compare the new sample with the previous sample and record which
+ // gamepad events should be dispatched. Swap buffers if the gamepad
+ // state changed. We must swap buffers before dispatching events to
+ // ensure |gamepads_| holds the correct data when getGamepads is called
+ // from inside a gamepad event listener.
+ auto compare_result = GamepadComparisons::Compare(
+ gamepads_.Get(), gamepads_back_.Get(), false, false);
+ if (compare_result.IsDifferent()) {
+ gamepads_.Swap(gamepads_back_);
+ bool is_gamepads_back_exposed = is_gamepads_exposed_;
+ is_gamepads_exposed_ = false;
+
+ // Dispatch gamepad events. Dispatching an event calls the event
+ // listeners synchronously.
+ //
+ // Note: In some instances the gamepad connection state may change while
+ // inside an event listener. This is most common when using test APIs
+ // that allow the gamepad state to be changed from javascript. The set
+ // of event listeners may also change if listeners are added or removed
+ // by another listener.
+ for (uint32_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
+ // When a gamepad is disconnected and connected in the same update,
+ // dispatch the gamepaddisconnected event first.
+ if (has_connection_event_listener_ &&
+ compare_result.IsGamepadDisconnected(i)) {
+ Gamepad* pad = gamepads_back_->item(i);
+ DCHECK(pad);
+ pad->SetConnected(false);
+ is_gamepads_back_exposed = true;
+ DispatchGamepadEvent(event_type_names::kGamepaddisconnected, pad);
+ }
+ if (has_connection_event_listener_ &&
+ compare_result.IsGamepadConnected(i)) {
+ Gamepad* pad = gamepads_->item(i);
+ DCHECK(pad);
+ is_gamepads_exposed_ = true;
+ DispatchGamepadEvent(event_type_names::kGamepadconnected, pad);
+ }
+ }
+
+ // Clear |gamepads_back_| if it was ever exposed to the page so it can
+ // be garbage collected when no active references remain. If it was
+ // never exposed, retain the buffer so it can be reused.
+ if (is_gamepads_back_exposed)
+ gamepads_back_.Clear();
}
- if (!pending_events_.IsEmpty()) {
- DCHECK(dispatch_one_event_runner_);
- dispatch_one_event_runner_->RunAsync();
- }
- }
- SampleGamepads<Gamepad>(gamepads_.Get(), execution_context,
- navigation_start_);
- }
-}
-
-bool NavigatorGamepad::CheckConnectedGamepads(GamepadList* old_gamepads,
- GamepadList* new_gamepads) {
- int disconnection_count = 0;
- for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
- Gamepad* old_gamepad = old_gamepads ? old_gamepads->item(i) : nullptr;
- Gamepad* new_gamepad = new_gamepads->item(i);
- bool connected, disconnected;
- CheckConnectedGamepad(old_gamepad, new_gamepad, &connected, &disconnected);
-
- if (disconnected) {
- old_gamepad->SetConnected(false);
- pending_events_.push_back(old_gamepad);
- disconnection_count++;
- }
- if (connected) {
- pending_events_.push_back(new_gamepad);
}
}
- return disconnection_count > 0;
}
-void NavigatorGamepad::CheckConnectedGamepad(Gamepad* old_gamepad,
- Gamepad* new_gamepad,
- bool* gamepad_found,
- bool* gamepad_lost) {
- bool old_connected = old_gamepad && old_gamepad->connected();
- bool new_connected = new_gamepad && new_gamepad->connected();
- if (old_gamepad && new_gamepad) {
- HasGamepadConnectionChanged(old_gamepad->id(), new_gamepad->id(),
- old_connected, new_connected, gamepad_found,
- gamepad_lost);
- return;
- }
-
- if (gamepad_found)
- *gamepad_found = new_connected;
- if (gamepad_lost)
- *gamepad_lost = old_connected;
+void NavigatorGamepad::DispatchGamepadEvent(const AtomicString& event_name,
+ Gamepad* gamepad) {
+ DCHECK(has_connection_event_listener_);
+ DCHECK(gamepad);
+ DomWindow()->DispatchEvent(*GamepadEvent::Create(
+ event_name, Event::Bubbles::kNo, Event::Cancelable::kYes, gamepad));
}
void NavigatorGamepad::PageVisibilityChanged() {
@@ -437,7 +386,7 @@ void NavigatorGamepad::PageVisibilityChanged() {
}
if (visible && has_event_listener_)
- SampleAndCheckConnectedGamepads();
+ SampleAndCompareGamepadState();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.h b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.h
index 3e03be576e8..3b6e2f950b3 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.h
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/core/frame/platform_event_controller.h"
#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -66,12 +65,10 @@ class MODULES_EXPORT NavigatorGamepad final
void Trace(blink::Visitor*) override;
private:
- void DispatchOneEvent();
void DidRemoveGamepadEventListeners();
bool StartUpdatingIfAttached();
- void SampleAndCheckConnectedGamepads();
- bool CheckConnectedGamepads(GamepadList*, GamepadList*);
- void CheckConnectedGamepad(Gamepad*, Gamepad*, bool*, bool*);
+ void SampleAndCompareGamepadState();
+ void DispatchGamepadEvent(const AtomicString&, Gamepad*);
// PageVisibilityObserver
void PageVisibilityChanged() override;
@@ -87,11 +84,35 @@ class MODULES_EXPORT NavigatorGamepad final
void DidRemoveEventListener(LocalDOMWindow*, const AtomicString&) override;
void DidRemoveAllEventListeners(LocalDOMWindow*) override;
+ // A reference to the buffer containing the last-received gamepad state. May
+ // be nullptr if no data has been received yet. Do not overwrite this buffer
+ // as it may have already been returned to the page. Instead, write to
+ // |gamepads_back_| and swap buffers.
Member<GamepadList> gamepads_;
+
+ // True if the buffer referenced by |gamepads_| has been exposed to the page.
+ // When the buffer is not exposed, prefer to reuse it.
+ bool is_gamepads_exposed_ = false;
+
+ // A reference to the buffer for receiving new gamepad state. May be
+ // overwritten.
Member<GamepadList> gamepads_back_;
- HeapDeque<Member<Gamepad>> pending_events_;
- Member<AsyncMethodRunner<NavigatorGamepad>> dispatch_one_event_runner_;
+
+ // The timestamp for the navigationStart attribute. Gamepad timestamps are
+ // reported relative to this value.
TimeTicks navigation_start_;
+
+ // The timestamp when gamepads were made available to the page. If no data has
+ // been received from the hardware, the gamepad timestamp should be equal to
+ // this value.
+ TimeTicks gamepads_start_;
+
+ // True if there is at least one listener for gamepad connection or
+ // disconnection events.
+ bool has_connection_event_listener_ = false;
+
+ // True while processing gamepad events.
+ bool processing_events_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/coordinates.h b/chromium/third_party/blink/renderer/modules/geolocation/coordinates.h
index 216c348361f..6a5281aa7a7 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/coordinates.h
+++ b/chromium/third_party/blink/renderer/modules/geolocation/coordinates.h
@@ -47,21 +47,12 @@ class Coordinates : public ScriptWrappable {
double heading,
bool provides_speed,
double speed) {
- return new Coordinates(latitude, longitude, provides_altitude, altitude,
- accuracy, provides_altitude_accuracy,
- altitude_accuracy, provides_heading, heading,
- provides_speed, speed);
+ return MakeGarbageCollected<Coordinates>(
+ latitude, longitude, provides_altitude, altitude, accuracy,
+ provides_altitude_accuracy, altitude_accuracy, provides_heading,
+ heading, provides_speed, speed);
}
- double latitude() const { return latitude_; }
- double longitude() const { return longitude_; }
- double altitude(bool& is_null) const;
- double accuracy() const { return accuracy_; }
- double altitudeAccuracy(bool& is_null) const;
- double heading(bool& is_null) const;
- double speed(bool& is_null) const;
-
- private:
Coordinates(double latitude,
double longitude,
bool provides_altitude,
@@ -85,6 +76,15 @@ class Coordinates : public ScriptWrappable {
can_provide_heading_(provides_heading),
can_provide_speed_(provides_speed) {}
+ double latitude() const { return latitude_; }
+ double longitude() const { return longitude_; }
+ double altitude(bool& is_null) const;
+ double accuracy() const { return accuracy_; }
+ double altitudeAccuracy(bool& is_null) const;
+ double heading(bool& is_null) const;
+ double speed(bool& is_null) const;
+
+ private:
double latitude_;
double longitude_;
double altitude_;
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc
index dff776ceef6..cdc7edc1dc1 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -457,10 +457,13 @@ void Geolocation::UpdateGeolocationConnection() {
if (geolocation_)
return;
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
InterfaceInvalidator* invalidator =
GetExecutionContext()->GetInterfaceInvalidator();
GetFrame()->GetInterfaceProvider().GetInterface(&geolocation_service_,
- invalidator);
+ invalidator, task_runner);
geolocation_service_->CreateGeolocation(
MakeRequest(&geolocation_, invalidator),
LocalFrame::HasTransientUserActivation(GetFrame()));
diff --git a/chromium/third_party/blink/renderer/modules/idle/BUILD.gn b/chromium/third_party/blink/renderer/modules/idle/BUILD.gn
new file mode 100644
index 00000000000..94fe0371c29
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/BUILD.gn
@@ -0,0 +1,16 @@
+# 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.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("idle") {
+ sources = [
+ "idle_manager.cc",
+ "idle_manager.h",
+ "idle_status.cc",
+ "idle_status.h",
+ "navigator_idle.cc",
+ "navigator_idle.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/idle/DEPS b/chromium/third_party/blink/renderer/modules/idle/DEPS
new file mode 100644
index 00000000000..6d1e8c355ef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ "+mojo/public/cpp/bindings/binding.h",
+ "-third_party/blink/renderer/modules",
+ "+third_party/blink/renderer/modules/event_modules.h",
+ "+third_party/blink/renderer/modules/event_target_modules.h",
+ "+third_party/blink/renderer/modules/modules_export.h",
+ "+third_party/blink/renderer/modules/idle",
+]
diff --git a/chromium/third_party/blink/renderer/modules/idle/OWNERS b/chromium/third_party/blink/renderer/modules/idle/OWNERS
new file mode 100644
index 00000000000..5a67a3277ca
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/OWNERS
@@ -0,0 +1 @@
+file://content/browser/idle/OWNERS
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_manager.cc b/chromium/third_party/blink/renderer/modules/idle/idle_manager.cc
new file mode 100644
index 00000000000..28ad7ddf6c8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_manager.cc
@@ -0,0 +1,94 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/idle/idle_manager.h"
+
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/idle/idle_status.h"
+#include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+const uint32_t kDefaultThresholdSeconds = 60;
+
+IdleManager::IdleManager(ExecutionContext* context) {}
+
+ScriptPromise IdleManager::query(ScriptState* script_state,
+ const IdleOptions* options,
+ ExceptionState& exception_state) {
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ DCHECK(context->IsContextThread());
+
+ // Validate options.
+ int32_t threshold_seconds =
+ options->hasThreshold() ? options->threshold() : kDefaultThresholdSeconds;
+
+ if (threshold_seconds <= 0) {
+ exception_state.ThrowTypeError("Invalid threshold");
+ return ScriptPromise();
+ }
+
+ // TODO: Permission check.
+
+ if (!service_) {
+ // NOTE(goto): what are the benefits of initializing this here
+ // as opposed to the constructor? lazy loading?
+ context->GetInterfaceProvider()->GetInterface(mojo::MakeRequest(&service_));
+ service_.set_connection_error_handler(WTF::Bind(
+ &IdleManager::OnIdleManagerConnectionError, WrapWeakPersistent(this)));
+ }
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ mojom::blink::IdleMonitorPtr monitor_ptr;
+ IdleStatus* status = MakeGarbageCollected<IdleStatus>(
+ ExecutionContext::From(script_state), threshold_seconds,
+ mojo::MakeRequest(&monitor_ptr));
+
+ requests_.insert(resolver);
+ service_->AddMonitor(
+ threshold_seconds, std::move(monitor_ptr),
+ WTF::Bind(&IdleManager::OnAddMonitor, WrapPersistent(this),
+ WrapPersistent(resolver), WrapPersistent(status)));
+
+ return promise;
+}
+
+IdleManager* IdleManager::Create(ExecutionContext* context) {
+ IdleManager* idle_manager = MakeGarbageCollected<IdleManager>(context);
+ return idle_manager;
+}
+
+void IdleManager::OnAddMonitor(ScriptPromiseResolver* resolver,
+ IdleStatus* status,
+ mojom::blink::IdleState state) {
+ DCHECK(requests_.Contains(resolver));
+ requests_.erase(resolver);
+
+ status->Init(state);
+ resolver->Resolve(status);
+}
+
+void IdleManager::Trace(blink::Visitor* visitor) {
+ ScriptWrappable::Trace(visitor);
+ visitor->Trace(requests_);
+}
+
+void IdleManager::OnIdleManagerConnectionError() {
+ // TODO(goto): write a unittest to cover this.
+ for (const auto& request : requests_) {
+ request->Reject(DOMException::Create(DOMExceptionCode::kNotSupportedError,
+ "Idle detection not available"));
+ }
+ requests_.clear();
+ service_.reset();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_manager.h b/chromium/third_party/blink/renderer/modules/idle/idle_manager.h
new file mode 100644
index 00000000000..bb32ae2976a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_manager.h
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_MANAGER_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/public/platform/modules/idle/idle_manager.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/idle/idle_options.h"
+#include "third_party/blink/renderer/modules/idle/idle_status.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+
+namespace blink {
+
+class IdleOptions;
+class IdleStatus;
+class ExecutionContext;
+class ExceptionState;
+class ScriptPromiseResolver;
+class ScriptPromise;
+class ScriptState;
+
+class IdleManager final : public ScriptWrappable {
+ WTF_MAKE_NONCOPYABLE(IdleManager);
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit IdleManager(ExecutionContext*);
+
+ // IdleManager IDL interface.
+ ScriptPromise query(ScriptState*,
+ const IdleOptions* options,
+ ExceptionState&);
+
+ static IdleManager* Create(ExecutionContext* context);
+ void Trace(blink::Visitor*) override;
+
+ private:
+ void OnIdleManagerConnectionError();
+ void OnAddMonitor(ScriptPromiseResolver*,
+ IdleStatus*,
+ mojom::blink::IdleState);
+
+ HeapHashSet<Member<ScriptPromiseResolver>> requests_;
+ mojom::blink::IdleManagerPtr service_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_manager.idl b/chromium/third_party/blink/renderer/modules/idle/idle_manager.idl
new file mode 100644
index 00000000000..a0d30896aa2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_manager.idl
@@ -0,0 +1,14 @@
+// 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.
+
+// https://github.com/inexorabletash/idle-detection
+
+[
+ SecureContext,
+ Exposed=(Window,DedicatedWorker),
+ RuntimeEnabled=IdleDetection
+] interface IdleManager {
+ [CallWith=ScriptState, RaisesException]
+ Promise<IdleStatus> query(optional IdleOptions options);
+};
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_options.idl b/chromium/third_party/blink/renderer/modules/idle/idle_options.idl
new file mode 100644
index 00000000000..f9cee740f16
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_options.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://github.com/inexorabletash/idle-detection
+
+dictionary IdleOptions {
+ unsigned long threshold;
+};
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_status.cc b/chromium/third_party/blink/renderer/modules/idle/idle_status.cc
new file mode 100644
index 00000000000..edac0d8826d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_status.cc
@@ -0,0 +1,107 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/idle/idle_status.h"
+
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+IdleStatus::IdleStatus(ExecutionContext* context,
+ uint32_t threshold,
+ mojom::blink::IdleMonitorRequest request)
+ : PausableObject(context),
+ threshold_(threshold),
+ binding_(this, std::move(request)) {
+ PauseIfNeeded();
+}
+
+void IdleStatus::Init(IdleState state) {
+ state_ = state;
+}
+
+IdleStatus::~IdleStatus() = default;
+
+void IdleStatus::Dispose() {
+ StopMonitoring();
+}
+
+const AtomicString& IdleStatus::InterfaceName() const {
+ return event_target_names::kIdleStatus;
+}
+
+ExecutionContext* IdleStatus::GetExecutionContext() const {
+ return ContextLifecycleObserver::GetExecutionContext();
+}
+
+bool IdleStatus::HasPendingActivity() const {
+ return binding_.is_bound();
+}
+
+void IdleStatus::ContextUnpaused() {
+ StartMonitoring();
+}
+
+void IdleStatus::ContextPaused(PauseState) {
+ StopMonitoring();
+}
+
+void IdleStatus::ContextDestroyed(ExecutionContext*) {
+ StopMonitoring();
+}
+
+void IdleStatus::StartMonitoring() {
+ DCHECK(!binding_.is_bound());
+
+ mojom::blink::IdleManagerPtr service;
+ GetExecutionContext()->GetInterfaceProvider()->GetInterface(
+ mojo::MakeRequest(&service));
+
+ mojom::blink::IdleMonitorPtr monitor_ptr;
+ binding_.Bind(mojo::MakeRequest(&monitor_ptr));
+
+ service->AddMonitor(threshold_, std::move(monitor_ptr),
+ WTF::Bind(
+ [](IdleStatus* status, IdleState state) {
+ if (state != status->state_)
+ status->Update(state);
+ },
+ WrapWeakPersistent(this)));
+}
+
+void IdleStatus::StopMonitoring() {
+ binding_.Close();
+}
+
+String IdleStatus::state() const {
+ switch (state_) {
+ case IdleState::ACTIVE:
+ return "active";
+ case IdleState::IDLE:
+ return "idle";
+ case IdleState::LOCKED:
+ return "locked";
+ }
+}
+
+void IdleStatus::Update(IdleState state) {
+ DCHECK(binding_.is_bound());
+ if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed())
+ return;
+
+ state_ = state;
+ DispatchEvent(*Event::Create(event_type_names::kChange));
+}
+
+void IdleStatus::Trace(blink::Visitor* visitor) {
+ EventTargetWithInlineData::Trace(visitor);
+ PausableObject::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_status.h b/chromium/third_party/blink/renderer/modules/idle/idle_status.h
new file mode 100644
index 00000000000..51390f9c3cb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_status.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_STATUS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_STATUS_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/public/platform/modules/idle/idle_manager.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/modules/event_modules.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+class IdleStatus final : public EventTargetWithInlineData,
+ public ActiveScriptWrappable<IdleStatus>,
+ public PausableObject,
+ public mojom::blink::IdleMonitor {
+ USING_GARBAGE_COLLECTED_MIXIN(IdleStatus);
+ DEFINE_WRAPPERTYPEINFO();
+ USING_PRE_FINALIZER(IdleStatus, Dispose);
+ WTF_MAKE_NONCOPYABLE(IdleStatus);
+
+ using IdleState = mojom::blink::IdleState;
+
+ public:
+ // Constructed by the IdleManager when queried by script, but not returned
+ // to script until the monitor has been registered by the service and
+ // returned an initial state.
+ IdleStatus(ExecutionContext*,
+ uint32_t threshold,
+ mojom::blink::IdleMonitorRequest);
+
+ ~IdleStatus() override;
+ void Dispose();
+
+ // Called when the service has returned an initial state.
+ void Init(IdleState);
+
+ // EventTarget implementation.
+ const AtomicString& InterfaceName() const override;
+ ExecutionContext* GetExecutionContext() const override;
+
+ // ActiveScriptWrappable implementation.
+ bool HasPendingActivity() const final;
+
+ // PausableObject implementation.
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
+ void ContextDestroyed(ExecutionContext*) override;
+
+ // IdleStatus IDL interface.
+ String state() const;
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(change, kChange);
+
+ // mojom::blink::IdleMonitor implementation. Invoked on a state change, and
+ // causes an event to be dispatched.
+ void Update(IdleState state) override;
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ // Called internally to re-start monitoring by establishing a new binding,
+ // after a previous call to StopMonitoring().
+ void StartMonitoring();
+
+ // Close the binding, for example when paused or the context has been
+ // destroyed.
+ void StopMonitoring();
+
+ IdleState state_;
+
+ const uint32_t threshold_;
+
+ // Holds a pipe which the service uses to notify this object
+ // when the idle state has changed.
+ mojo::Binding<mojom::blink::IdleMonitor> binding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_STATUS_H_
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_status.idl b/chromium/third_party/blink/renderer/modules/idle/idle_status.idl
new file mode 100644
index 00000000000..33faf719203
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_status.idl
@@ -0,0 +1,21 @@
+// 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.
+
+// https://github.com/inexorabletash/idle-detection
+
+enum IdleState {
+ "active",
+ "idle",
+ "locked"
+};
+
+[
+ SecureContext,
+ Exposed=(Window,DedicatedWorker),
+ ActiveScriptWrappable,
+ RuntimeEnabled=IdleDetection
+] interface IdleStatus : EventTarget {
+ readonly attribute IdleState state;
+ attribute EventHandler onchange;
+};
diff --git a/chromium/third_party/blink/renderer/modules/idle/navigator_idle.cc b/chromium/third_party/blink/renderer/modules/idle/navigator_idle.cc
new file mode 100644
index 00000000000..e6bfeb25d41
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/navigator_idle.cc
@@ -0,0 +1,79 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/idle/navigator_idle.h"
+
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/core/workers/worker_navigator.h"
+#include "third_party/blink/renderer/modules/idle/idle_manager.h"
+#include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+namespace {
+
+template <typename T>
+class NavigatorIdleImpl final : public GarbageCollected<NavigatorIdleImpl<T>>,
+ public Supplement<T> {
+ USING_GARBAGE_COLLECTED_MIXIN(NavigatorIdleImpl);
+
+ public:
+ static const char kSupplementName[];
+
+ NavigatorIdleImpl(T& navigator) : Supplement<T>(navigator) {}
+
+ static NavigatorIdleImpl& From(T& navigator) {
+ NavigatorIdleImpl* supplement = static_cast<NavigatorIdleImpl*>(
+ Supplement<T>::template From<NavigatorIdleImpl>(navigator));
+ if (!supplement) {
+ supplement = MakeGarbageCollected<NavigatorIdleImpl>(navigator);
+ // MakeGarbageCollected seems appropriate, but why was the following
+ // working prior to my rebase? it doesn't seem like the new operator
+ // was deleted since my rebase from GarbageCollected. What changed?
+ // supplement = new NavigatorIdleImpl(navigator);
+ Supplement<T>::ProvideTo(navigator, supplement);
+ }
+ return *supplement;
+ }
+
+ IdleManager* GetIdleManager(ExecutionContext* context) {
+ if (!idle_manager_ && context) {
+ // idle_manager_ = new IdleManager(context);
+ // Supplement<T>::GetSupplementable()->GetFrame()->GetDocument()
+ idle_manager_ = IdleManager::Create(context);
+ }
+ return idle_manager_.Get();
+ }
+
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(idle_manager_);
+ Supplement<T>::Trace(visitor);
+ }
+
+ private:
+ mutable TraceWrapperMember<IdleManager> idle_manager_;
+};
+
+// static
+template <typename T>
+const char NavigatorIdleImpl<T>::kSupplementName[] = "NavigatorIdleImpl";
+
+} // namespace
+
+IdleManager* NavigatorIdle::idle(ScriptState* script_state,
+ Navigator& navigator) {
+ return NavigatorIdleImpl<Navigator>::From(navigator).GetIdleManager(
+ ExecutionContext::From(script_state));
+}
+
+IdleManager* NavigatorIdle::idle(ScriptState* script_state,
+ WorkerNavigator& navigator) {
+ return NavigatorIdleImpl<WorkerNavigator>::From(navigator).GetIdleManager(
+ ExecutionContext::From(script_state));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/idle/navigator_idle.h b/chromium/third_party/blink/renderer/modules/idle/navigator_idle.h
new file mode 100644
index 00000000000..1f7cb3f0f99
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/navigator_idle.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_NAVIGATOR_IDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_NAVIGATOR_IDLE_H_
+
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+class IdleManager;
+class Navigator;
+class ScriptState;
+class WorkerNavigator;
+
+class NavigatorIdle final {
+ STATIC_ONLY(NavigatorIdle);
+
+ public:
+ static IdleManager* idle(ScriptState*, Navigator&);
+ static IdleManager* idle(ScriptState*, WorkerNavigator&);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_NAVIGATOR_IDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/idle/navigator_idle.idl b/chromium/third_party/blink/renderer/modules/idle/navigator_idle.idl
new file mode 100644
index 00000000000..d0d2bd836dd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/navigator_idle.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://github.com/inexorabletash/idle-detection
+[
+ SecureContext,
+ Exposed=Window,
+ ImplementedAs=NavigatorIdle,
+ RuntimeEnabled=IdleDetection
+] partial interface Navigator {
+ [CallWith=ScriptState] readonly attribute IdleManager idle;
+};
diff --git a/chromium/third_party/blink/renderer/modules/idle/worker_navigator_idle.idl b/chromium/third_party/blink/renderer/modules/idle/worker_navigator_idle.idl
new file mode 100644
index 00000000000..136f21aaf41
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/worker_navigator_idle.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://github.com/inexorabletash/idle-detection
+[
+ SecureContext,
+ Exposed=DedicatedWorker,
+ ImplementedAs=NavigatorIdle,
+ RuntimeEnabled=IdleDetection
+] partial interface WorkerNavigator {
+ [CallWith=ScriptState] readonly attribute IdleManager idle;
+};
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/README.md b/chromium/third_party/blink/renderer/modules/imagecapture/README.md
index 6a92c9f8bbf..f0411f8777f 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/README.md
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/README.md
@@ -123,7 +123,7 @@ of modifying it can only be seen after taking a picture.
## Testing
-Image Capture layout tests are located in [web_tests/imagecapture],
+Image Capture web tests are located in [web_tests/imagecapture],
[web_tests/fast/imagecapture] and [web_tests/external/mediacapture-image].
[web_tests/imagecapture]: https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/web_tests/imagecapture
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc
index b82bf3a86c7..ae6608b0219 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -177,6 +177,8 @@ ScriptPromise ImageCapture::getPhotoSettings(ScriptState* script_state) {
ScriptPromise ImageCapture::setOptions(ScriptState* script_state,
const PhotoSettings* photo_settings,
bool trigger_take_photo /* = false */) {
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
+ "ImageCapture::setOptions", TRACE_EVENT_SCOPE_PROCESS);
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
@@ -256,6 +258,8 @@ ScriptPromise ImageCapture::setOptions(ScriptState* script_state,
}
ScriptPromise ImageCapture::takePhoto(ScriptState* script_state) {
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
+ "ImageCapture::takePhoto", TRACE_EVENT_SCOPE_PROCESS);
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
@@ -277,6 +281,8 @@ ScriptPromise ImageCapture::takePhoto(ScriptState* script_state) {
// camera;
// TODO(mcasas) consider sending the security origin as well:
// scriptState->getExecutionContext()->getSecurityOrigin()->toString()
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
+ "ImageCapture::takePhoto", TRACE_EVENT_SCOPE_PROCESS);
service_->TakePhoto(
stream_track_->Component()->Source()->Id(),
WTF::Bind(&ImageCapture::OnMojoTakePhoto, WrapPersistent(this),
@@ -286,6 +292,10 @@ ScriptPromise ImageCapture::takePhoto(ScriptState* script_state) {
ScriptPromise ImageCapture::takePhoto(ScriptState* script_state,
const PhotoSettings* photo_settings) {
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
+ "ImageCapture::takePhoto (with settings)",
+ TRACE_EVENT_SCOPE_PROCESS);
+
return setOptions(script_state, photo_settings,
true /* trigger_take_photo */);
}
@@ -724,6 +734,9 @@ void ImageCapture::OnMojoSetOptions(ScriptPromiseResolver* resolver,
bool trigger_take_photo,
bool result) {
DCHECK(service_requests_.Contains(resolver));
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
+ "ImageCapture::OnMojoSetOptions",
+ TRACE_EVENT_SCOPE_PROCESS);
if (!result) {
resolver->Reject(DOMException::Create(DOMExceptionCode::kUnknownError,
@@ -746,6 +759,9 @@ void ImageCapture::OnMojoSetOptions(ScriptPromiseResolver* resolver,
void ImageCapture::OnMojoTakePhoto(ScriptPromiseResolver* resolver,
media::mojom::blink::BlobPtr blob) {
DCHECK(service_requests_.Contains(resolver));
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
+ "ImageCapture::OnMojoTakePhoto",
+ TRACE_EVENT_SCOPE_PROCESS);
// TODO(mcasas): Should be using a mojo::StructTraits.
if (blob->data.IsEmpty()) {
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h
index a88b8689e75..36fc68e155a 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h
@@ -27,7 +27,7 @@ class PhotoCapabilities;
class ScriptPromiseResolver;
class WebImageCaptureFrameGrabber;
-// TODO(mcasas): Consider adding a LayoutTest checking that this class is not
+// TODO(mcasas): Consider adding a web test checking that this class is not
// garbage collected while it has event listeners.
class MODULES_EXPORT ImageCapture final
: public EventTargetWithInlineData,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn b/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn
index 624dbe229fb..f520827568b 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn
@@ -18,6 +18,7 @@ blink_modules_sources("indexeddb") {
"idb_database.h",
"idb_database_callbacks.cc",
"idb_database_callbacks.h",
+ "idb_database_error.h",
"idb_event_dispatcher.cc",
"idb_event_dispatcher.h",
"idb_factory.cc",
@@ -32,6 +33,7 @@ blink_modules_sources("indexeddb") {
"idb_key_range.h",
"idb_metadata.cc",
"idb_metadata.h",
+ "idb_name_and_version.h",
"idb_object_store.cc",
"idb_object_store.h",
"idb_observation.cc",
@@ -60,8 +62,6 @@ blink_modules_sources("indexeddb") {
"indexed_db.h",
"indexed_db_blink_mojom_traits.cc",
"indexed_db_blink_mojom_traits.h",
- "indexed_db_callbacks_impl.cc",
- "indexed_db_callbacks_impl.h",
"indexed_db_client.cc",
"indexed_db_client.h",
"indexed_db_database_callbacks_impl.cc",
@@ -70,12 +70,14 @@ blink_modules_sources("indexeddb") {
"indexed_db_dispatcher.h",
"inspector_indexed_db_agent.cc",
"inspector_indexed_db_agent.h",
+ "web_idb_callbacks.h",
"web_idb_callbacks_impl.cc",
"web_idb_callbacks_impl.h",
"web_idb_cursor.h",
"web_idb_cursor_impl.cc",
"web_idb_cursor_impl.h",
"web_idb_database.h",
+ "web_idb_database_callbacks.h",
"web_idb_database_callbacks_impl.cc",
"web_idb_database_callbacks_impl.h",
"web_idb_database_impl.cc",
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/DEPS b/chromium/third_party/blink/renderer/modules/indexeddb/DEPS
index db25c26f962..d75469e0e5e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/DEPS
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/DEPS
@@ -1,4 +1,7 @@
include_rules = [
+ "+mojo/public/cpp/base/file_path_mojom_traits.h",
+ "+mojo/public/cpp/base/string16_mojom_traits.h",
+ "+mojo/public/cpp/base/time_mojom_traits.h",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/event_modules.h",
"+third_party/blink/renderer/modules/event_target_modules.h",
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/global_indexed_db.cc b/chromium/third_party/blink/renderer/modules/indexeddb/global_indexed_db.cc
index c967e423941..ea3e68ce721 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/global_indexed_db.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/global_indexed_db.cc
@@ -27,12 +27,14 @@ class GlobalIndexedDBImpl final
GlobalIndexedDBImpl* supplement =
Supplement<T>::template From<GlobalIndexedDBImpl>(supplementable);
if (!supplement) {
- supplement = new GlobalIndexedDBImpl;
+ supplement = MakeGarbageCollected<GlobalIndexedDBImpl>();
Supplement<T>::ProvideTo(supplementable, supplement);
}
return *supplement;
}
+ GlobalIndexedDBImpl() = default;
+
IDBFactory* IdbFactory(T& fetching_scope) {
if (!idb_factory_)
idb_factory_ = IDBFactory::Create();
@@ -45,8 +47,6 @@ class GlobalIndexedDBImpl final
}
private:
- GlobalIndexedDBImpl() = default;
-
Member<IDBFactory> idb_factory_;
};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
index 07bad6af1d3..7e97b25d2f7 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
@@ -27,7 +27,6 @@
#include <limits>
#include <memory>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_idb_request.h"
@@ -42,9 +41,6 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
-using blink::WebIDBCursor;
-using blink::WebIDBDatabase;
-
namespace blink {
IDBCursor* IDBCursor::Create(std::unique_ptr<WebIDBCursor> backend,
@@ -281,7 +277,10 @@ void IDBCursor::Continue(std::unique_ptr<IDBKey> key,
const IDBKey* current_primary_key = IdbPrimaryKey();
- if (key) {
+ if (!key)
+ key = IDBKey::CreateNull();
+
+ if (key->GetType() != mojom::IDBKeyType::Null) {
DCHECK(key_);
if (direction_ == mojom::IDBCursorDirection::Next ||
direction_ == mojom::IDBCursorDirection::NextNoDuplicate) {
@@ -308,14 +307,16 @@ void IDBCursor::Continue(std::unique_ptr<IDBKey> key,
}
}
+ if (!primary_key)
+ primary_key = IDBKey::CreateNull();
+
// FIXME: We're not using the context from when continue was called, which
// means the callback will be on the original context openCursor was called
// on. Is this right?
request_->SetPendingCursor(this);
request_->AssignNewMetrics(std::move(metrics));
got_value_ = false;
- backend_->CursorContinue(WebIDBKeyView(key.get()),
- WebIDBKeyView(primary_key.get()),
+ backend_->CursorContinue(key.get(), primary_key.get(),
request_->CreateWebCallbacks().release());
}
@@ -359,8 +360,8 @@ IDBRequest* IDBCursor::Delete(ScriptState* script_state,
IDBRequest* request = IDBRequest::Create(
script_state, this, transaction_.Get(), std::move(metrics));
transaction_->BackendDB()->Delete(
- transaction_->Id(), EffectiveObjectStore()->Id(),
- WebIDBKeyView(IdbPrimaryKey()), request->CreateWebCallbacks().release());
+ transaction_->Id(), EffectiveObjectStore()->Id(), IdbPrimaryKey(),
+ request->CreateWebCallbacks().release());
return request;
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
index b5d5b6383bc..aa1ce76c453 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
@@ -43,7 +43,7 @@ enum IDBCursorDirection {
[CallWith=ScriptState, CachedAttribute=isPrimaryKeyDirty] readonly attribute any primaryKey;
[RaisesException] void advance([EnforceRange] unsigned long count);
- [CallWith=ScriptState, ImplementedAs=Continue, RaisesException] void continue([Default=Undefined] optional any key);
+ [CallWith=ScriptState, ImplementedAs=Continue, RaisesException] void continue([DefaultValue=Undefined] optional any key);
[CallWith=ScriptState, RaisesException] void continuePrimaryKey(any key, any primaryKey);
[NewObject, CallWith=ScriptState, RaisesException] IDBRequest update(any value);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc
index b9bad7823eb..7df7371d33f 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc
@@ -28,8 +28,6 @@
#include <memory>
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
-using blink::WebIDBCursor;
-
namespace blink {
IDBCursorWithValue* IDBCursorWithValue::Create(
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc
index c8764dc38ca..6c48bda9eab 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc
@@ -25,13 +25,13 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
+#include <limits>
+#include <memory>
+
#include "base/atomic_sequence_num.h"
#include "base/optional.h"
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h"
@@ -45,17 +45,13 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include <limits>
-#include <memory>
-
-using blink::WebIDBDatabase;
-
namespace blink {
const char IDBDatabase::kCannotObserveVersionChangeTransaction[] =
@@ -190,14 +186,10 @@ void IDBDatabase::OnComplete(int64_t transaction_id) {
void IDBDatabase::OnChanges(
const WebIDBDatabaseCallbacks::ObservationIndexMap& observation_index_map,
- WebVector<WebIDBObservation> web_observations,
+ Vector<Persistent<IDBObservation>> observations,
const WebIDBDatabaseCallbacks::TransactionMap& transactions) {
- HeapVector<Member<IDBObservation>> observations;
- observations.ReserveInitialCapacity(
- SafeCast<wtf_size_t>(web_observations.size()));
- for (WebIDBObservation& web_observation : web_observations) {
- observations.emplace_back(
- IDBObservation::Create(std::move(web_observation), isolate_));
+ for (const auto& observation : observations) {
+ observation->SetIsolate(isolate_);
}
for (const auto& map_entry : observation_index_map) {
@@ -208,7 +200,7 @@ void IDBDatabase::OnChanges(
IDBTransaction* transaction = nullptr;
auto it = transactions.find(map_entry.first);
if (it != transactions.end()) {
- const std::pair<int64_t, WebVector<int64_t>>& obs_txn = it->second;
+ const std::pair<int64_t, Vector<int64_t>>& obs_txn = it->second;
HashSet<String> stores;
for (int64_t store_id : obs_txn.second) {
stores.insert(metadata_.object_stores.at(store_id)->name);
@@ -219,9 +211,8 @@ void IDBDatabase::OnChanges(
}
observer->Callback()->InvokeAndReportException(
- observer,
- IDBObserverChanges::Create(this, transaction, web_observations,
- observations, map_entry.second));
+ observer, IDBObserverChanges::Create(this, transaction, observations,
+ map_entry.second));
if (transaction)
transaction->SetActive(false);
}
@@ -295,9 +286,9 @@ IDBObjectStore* IDBDatabase::createObjectStore(
return nullptr;
}
- if (auto_increment && ((key_path.GetType() == IDBKeyPath::kStringType &&
+ if (auto_increment && ((key_path.GetType() == mojom::IDBKeyPathType::String &&
key_path.GetString().IsEmpty()) ||
- key_path.GetType() == IDBKeyPath::kArrayType)) {
+ key_path.GetType() == mojom::IDBKeyPathType::Array)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidAccessError,
"The autoIncrement option was set but the "
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h
index 1e2f20782d1..d68c2b78c53 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h
@@ -29,7 +29,6 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_string_sequence.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
@@ -43,6 +42,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
@@ -53,8 +53,8 @@ namespace blink {
class DOMException;
class ExceptionState;
class ExecutionContext;
+class IDBObservation;
class IDBObserver;
-struct WebIDBObservation;
class MODULES_EXPORT IDBDatabase final
: public EventTargetWithInlineData,
@@ -123,7 +123,7 @@ class MODULES_EXPORT IDBDatabase final
void OnAbort(int64_t, DOMException*);
void OnComplete(int64_t);
void OnChanges(const WebIDBDatabaseCallbacks::ObservationIndexMap&,
- WebVector<WebIDBObservation> observations,
+ Vector<Persistent<IDBObservation>> observations,
const WebIDBDatabaseCallbacks::TransactionMap& transactions);
// ScriptWrappable
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc
index 7fa1f036ed7..284072da599 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc
@@ -25,8 +25,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
-#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h"
@@ -68,7 +66,7 @@ void IDBDatabaseCallbacks::OnComplete(int64_t transaction_id) {
void IDBDatabaseCallbacks::OnChanges(
const WebIDBDatabaseCallbacks::ObservationIndexMap& observation_index_map,
- WebVector<WebIDBObservation> observations,
+ Vector<Persistent<IDBObservation>> observations,
const WebIDBDatabaseCallbacks::TransactionMap& transactions) {
if (!database_)
return;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h
index 2a4a0c30890..1da199ae00e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h
@@ -26,8 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_CALLBACKS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_CALLBACKS_H_
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
-#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -37,7 +36,7 @@ namespace blink {
class DOMException;
class IDBDatabase;
-struct WebIDBObservation;
+class IDBObservation;
class MODULES_EXPORT IDBDatabaseCallbacks
: public GarbageCollectedFinalized<IDBDatabaseCallbacks> {
@@ -56,7 +55,7 @@ class MODULES_EXPORT IDBDatabaseCallbacks
virtual void OnComplete(int64_t transaction_id);
virtual void OnChanges(
const WebIDBDatabaseCallbacks::ObservationIndexMap&,
- WebVector<WebIDBObservation> observations,
+ Vector<Persistent<IDBObservation>> observations,
const WebIDBDatabaseCallbacks::TransactionMap& transactions);
void Connect(IDBDatabase*);
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h
index f6dc017f550..fed841d671d 100644
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h
@@ -26,35 +26,35 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_DATABASE_ERROR_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_DATABASE_ERROR_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_ERROR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_ERROR_H_
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-class WebIDBDatabaseError {
+class IDBDatabaseError {
public:
- explicit WebIDBDatabaseError(unsigned short code) : code_(code) {}
+ explicit IDBDatabaseError(unsigned short code) : code_(code) {}
- WebIDBDatabaseError(unsigned short code, const WebString& message)
- : code_(code), message_(message) {}
+ IDBDatabaseError(unsigned short code, String message)
+ : code_(code), message_(std::move(message)) {}
- WebIDBDatabaseError(const WebIDBDatabaseError& error) = default;
+ IDBDatabaseError(const IDBDatabaseError& error) = default;
- ~WebIDBDatabaseError() = default;
+ ~IDBDatabaseError() = default;
- WebIDBDatabaseError& operator=(const WebIDBDatabaseError& error) = default;
+ IDBDatabaseError& operator=(const IDBDatabaseError& error) = default;
unsigned short Code() const { return code_; }
- const WebString& Message() const { return message_; }
+ const String& Message() const { return message_; }
private:
unsigned short code_;
- WebString message_;
+ String message_;
};
} // namespace blink
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_DATABASE_ERROR_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_ERROR_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
index 45b8196e6fc..ac2d5cae2d6 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
@@ -31,15 +31,11 @@
#include <memory>
#include <utility>
+#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
#include "third_party/blink/public/platform/interface_provider.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -52,8 +48,11 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database_info.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_client.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_factory.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -93,7 +92,10 @@ class WebIDBGetDBNamesCallbacksImpl : public WebIDBCallbacks {
}
}
- void OnError(const WebIDBDatabaseError& error) override {
+ void SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
+ int64_t transaction_id) override {}
+
+ void Error(int32_t code, const String& message) override {
if (!promise_resolver_)
return;
@@ -106,66 +108,84 @@ class WebIDBGetDBNamesCallbacksImpl : public WebIDBCallbacks {
promise_resolver_.Clear();
}
- void OnSuccess(const WebVector<WebIDBNameAndVersion>&
- web_database_name_and_version_list) override {
+ void SuccessNamesAndVersionsList(
+ Vector<mojom::blink::IDBNameAndVersionPtr> names_and_versions) override {
if (!promise_resolver_)
return;
- HeapVector<Member<IDBDatabaseInfo>> database_name_and_version_list;
- for (size_t i = 0; i < web_database_name_and_version_list.size(); ++i) {
+ HeapVector<Member<IDBDatabaseInfo>> name_and_version_list;
+ name_and_version_list.ReserveInitialCapacity(name_and_version_list.size());
+ for (const mojom::blink::IDBNameAndVersionPtr& name_version :
+ names_and_versions) {
+ const IDBNameAndVersion idb_name_and_version(name_version->name,
+ name_version->version);
IDBDatabaseInfo* idb_info = IDBDatabaseInfo::Create();
- idb_info->setName(web_database_name_and_version_list[i].name);
- idb_info->setVersion(web_database_name_and_version_list[i].version);
- database_name_and_version_list.push_back(idb_info);
+ idb_info->setName(name_version->name);
+ idb_info->setVersion(name_version->version);
+ name_and_version_list.push_back(idb_info);
}
+
probe::AsyncTask async_task(
ExecutionContext::From(promise_resolver_->GetScriptState()), this,
"success");
- promise_resolver_->Resolve(database_name_and_version_list);
+ promise_resolver_->Resolve(name_and_version_list);
promise_resolver_.Clear();
}
- void OnSuccess(const WebVector<WebString>&) override { NOTREACHED(); }
+ void SuccessStringList(const Vector<String>&) override { NOTREACHED(); }
- void OnSuccess(WebIDBCursor* cursor,
- WebIDBKey key,
- WebIDBKey primary_key,
- WebIDBValue value) override {
+ void SuccessCursor(
+ mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> optional_value) override {
NOTREACHED();
}
- void OnSuccess(WebIDBDatabase* backend,
- const WebIDBMetadata& metadata) override {
+ void SuccessCursorPrefetch(
+ Vector<std::unique_ptr<IDBKey>> keys,
+ Vector<std::unique_ptr<IDBKey>> primary_keys,
+ Vector<std::unique_ptr<IDBValue>> values) override {
NOTREACHED();
}
- void OnSuccess(WebIDBKey key) override { NOTREACHED(); }
+ void SuccessDatabase(mojom::blink::IDBDatabaseAssociatedPtrInfo backend,
+ const IDBDatabaseMetadata& metadata) override {
+ NOTREACHED();
+ }
- void OnSuccess(WebIDBValue value) override { NOTREACHED(); }
+ void SuccessKey(std::unique_ptr<IDBKey> key) override { NOTREACHED(); }
- void OnSuccess(WebVector<WebIDBValue> values) override { NOTREACHED(); }
+ void SuccessValue(mojom::blink::IDBReturnValuePtr return_value) override {
+ NOTREACHED();
+ }
+
+ void SuccessArray(Vector<mojom::blink::IDBReturnValuePtr> values) override {
+ NOTREACHED();
+ }
- void OnSuccess(long long value) override { NOTREACHED(); }
+ void SuccessInteger(int64_t value) override { NOTREACHED(); }
- void OnSuccess() override { NOTREACHED(); }
+ void Success() override { NOTREACHED(); }
- void OnSuccess(WebIDBKey key,
- WebIDBKey primary_key,
- WebIDBValue value) override {
+ void SuccessCursorContinue(
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> value) override {
NOTREACHED();
}
- void OnBlocked(long long old_version) override { NOTREACHED(); }
+ void Blocked(int64_t old_version) override { NOTREACHED(); }
- void OnUpgradeNeeded(long long old_version,
- WebIDBDatabase* database,
- const WebIDBMetadata& metadata,
- mojom::IDBDataLoss data_loss,
- WebString data_loss_message) override {
+ void UpgradeNeeded(mojom::blink::IDBDatabaseAssociatedPtrInfo database,
+ int64_t old_version,
+ mojom::IDBDataLoss data_loss,
+ const String& data_loss_message,
+ const IDBDatabaseMetadata& metadata) override {
NOTREACHED();
}
- void Detach() override { NOTREACHED(); }
+ void DetachRequestFromCallback() override { NOTREACHED(); }
private:
Persistent<ScriptPromiseResolver> promise_resolver_;
@@ -188,13 +208,18 @@ static bool IsContextValid(ExecutionContext* context) {
return true;
}
-WebIDBFactory* IDBFactory::GetFactory() {
+WebIDBFactory* IDBFactory::GetFactory(ExecutionContext* execution_context) {
if (!web_idb_factory_) {
mojom::blink::IDBFactoryPtrInfo web_idb_factory_host_info;
- Platform::Current()->GetInterfaceProvider()->GetInterface(
+ service_manager::InterfaceProvider* interface_provider =
+ execution_context->GetInterfaceProvider();
+ if (!interface_provider)
+ return nullptr;
+ interface_provider->GetInterface(
mojo::MakeRequest(&web_idb_factory_host_info));
web_idb_factory_ = std::make_unique<WebIDBFactoryImpl>(
- std::move(web_idb_factory_host_info));
+ std::move(web_idb_factory_host_info),
+ execution_context->GetTaskRunner(TaskType::kInternalIndexedDB));
}
return web_idb_factory_.get();
}
@@ -212,12 +237,14 @@ ScriptPromise IDBFactory::GetDatabaseInfo(ScriptState* script_state,
return resolver->Promise();
}
- GetFactory()->GetDatabaseInfo(
- WebIDBGetDBNamesCallbacksImpl::Create(resolver).release(),
- WebSecurityOrigin(
- ExecutionContext::From(script_state)->GetSecurityOrigin()),
- ExecutionContext::From(script_state)
- ->GetTaskRunner(TaskType::kInternalIndexedDB));
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ WebIDBFactory* factory = GetFactory(execution_context);
+ if (!factory) {
+ exception_state.ThrowSecurityError("An internal error occurred.");
+ resolver->Reject();
+ return resolver->Promise();
+ }
+ factory->GetDatabaseInfo(WebIDBGetDBNamesCallbacksImpl::Create(resolver));
ScriptPromise promise = resolver->Promise();
return promise;
}
@@ -251,12 +278,13 @@ IDBRequest* IDBFactory::GetDatabaseNames(ScriptState* script_state,
return request;
}
- GetFactory()->GetDatabaseNames(
- request->CreateWebCallbacks().release(),
- WebSecurityOrigin(
- ExecutionContext::From(script_state)->GetSecurityOrigin()),
- ExecutionContext::From(script_state)
- ->GetTaskRunner(TaskType::kInternalIndexedDB));
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ WebIDBFactory* factory = GetFactory(execution_context);
+ if (!factory) {
+ exception_state.ThrowSecurityError("An internal error occurred.");
+ return nullptr;
+ }
+ factory->GetDatabaseNames(request->CreateWebCallbacks());
return request;
}
@@ -306,13 +334,14 @@ IDBOpenDBRequest* IDBFactory::OpenInternal(ScriptState* script_state,
return request;
}
- GetFactory()->Open(
- name, version, transaction_id, request->CreateWebCallbacks().release(),
- database_callbacks->CreateWebCallbacks().release(),
- WebSecurityOrigin(
- ExecutionContext::From(script_state)->GetSecurityOrigin()),
- ExecutionContext::From(script_state)
- ->GetTaskRunner(TaskType::kInternalIndexedDB));
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ WebIDBFactory* factory = GetFactory(execution_context);
+ if (!factory) {
+ exception_state.ThrowSecurityError("An internal error occurred.");
+ return nullptr;
+ }
+ factory->Open(name, version, transaction_id, request->CreateWebCallbacks(),
+ database_callbacks->CreateWebCallbacks());
return request;
}
@@ -372,13 +401,13 @@ IDBOpenDBRequest* IDBFactory::DeleteDatabaseInternal(
return request;
}
- GetFactory()->DeleteDatabase(
- name, request->CreateWebCallbacks().release(),
- WebSecurityOrigin(
- ExecutionContext::From(script_state)->GetSecurityOrigin()),
- force_close,
- ExecutionContext::From(script_state)
- ->GetTaskRunner(TaskType::kInternalIndexedDB));
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ WebIDBFactory* factory = GetFactory(execution_context);
+ if (!factory) {
+ exception_state.ThrowSecurityError("An internal error occurred.");
+ return nullptr;
+ }
+ factory->DeleteDatabase(name, request->CreateWebCallbacks(), force_close);
return request;
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
index 68b8234455c..46485497b4a 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
@@ -78,7 +78,7 @@ class MODULES_EXPORT IDBFactory final : public ScriptWrappable {
ScriptPromise GetDatabaseInfo(ScriptState*, ExceptionState&);
private:
- WebIDBFactory* GetFactory();
+ WebIDBFactory* GetFactory(ExecutionContext* execution_context);
IDBOpenDBRequest* OpenInternal(ScriptState*,
const String& name,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.idl
index 291900fde26..c4c19c5c047 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.idl
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.idl
@@ -40,6 +40,7 @@
[
CallWith=ScriptState,
ImplementedAs=GetDatabaseInfo,
+ Measure,
RaisesException
] Promise<sequence<IDBDatabaseInfo>> databases();
};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
index 7cdb287cb84..ec0725a2795 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
@@ -9,8 +9,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -18,6 +17,8 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h"
#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -29,14 +30,15 @@ class TestHelperFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
bool* called_flag) {
- auto* self = new TestHelperFunction(script_state, called_flag);
+ auto* self =
+ MakeGarbageCollected<TestHelperFunction>(script_state, called_flag);
return self->BindToV8Function();
}
- private:
TestHelperFunction(ScriptState* script_state, bool* called_flag)
: ScriptFunction(script_state), called_flag_(called_flag) {}
+ private:
ScriptValue Call(ScriptValue value) override {
*called_flag_ = true;
return value;
@@ -52,21 +54,13 @@ class IDBFactoryTest : public testing::Test {
~IDBFactoryTest() override {}
};
-ACTION_TEMPLATE(SaveUniquePointer,
- HAS_1_TEMPLATE_PARAMS(int, k),
- AND_1_VALUE_PARAMS(unique_pointer)) {
- *unique_pointer = base::WrapUnique(std::get<k>(args));
-}
-
TEST_F(IDBFactoryTest, WebIDBGetDBInfoCallbacksResolvesPromise) {
V8TestingScope scope;
scope.GetDocument().SetSecurityOrigin(
SecurityOrigin::Create(KURL("https://example.com")));
std::unique_ptr<MockWebIDBFactory> web_factory = MockWebIDBFactory::Create();
- std::unique_ptr<WebIDBCallbacks> wc;
- EXPECT_CALL(*web_factory, GetDatabaseInfo(testing::_, testing::_, testing::_))
- .Times(1)
- .WillOnce(SaveUniquePointer<0>(&wc));
+ std::unique_ptr<WebIDBCallbacks> callbacks;
+ web_factory->SetCallbacksPointer(&callbacks);
IDBFactory* factory = IDBFactory::CreateForTest(std::move(web_factory));
DummyExceptionStateForTesting exception_state;
@@ -81,8 +75,8 @@ TEST_F(IDBFactoryTest, WebIDBGetDBInfoCallbacksResolvesPromise) {
EXPECT_FALSE(on_fulfilled);
EXPECT_FALSE(on_rejected);
- const WebVector<WebIDBNameAndVersion> wv;
- wc->OnSuccess(wv);
+ Vector<mojom::blink::IDBNameAndVersionPtr> name_and_info_list;
+ callbacks->SuccessNamesAndVersionsList(std::move(name_and_info_list));
EXPECT_FALSE(on_fulfilled);
EXPECT_FALSE(on_rejected);
@@ -98,10 +92,8 @@ TEST_F(IDBFactoryTest, WebIDBGetDBNamesCallbacksRejectsPromise) {
scope.GetDocument().SetSecurityOrigin(
SecurityOrigin::Create(KURL("https://example.com")));
std::unique_ptr<MockWebIDBFactory> web_factory = MockWebIDBFactory::Create();
- std::unique_ptr<WebIDBCallbacks> wc;
- EXPECT_CALL(*web_factory, GetDatabaseInfo(testing::_, testing::_, testing::_))
- .Times(1)
- .WillOnce(SaveUniquePointer<0>(&wc));
+ std::unique_ptr<WebIDBCallbacks> callbacks;
+ web_factory->SetCallbacksPointer(&callbacks);
IDBFactory* factory = IDBFactory::CreateForTest(std::move(web_factory));
DummyExceptionStateForTesting exception_state;
@@ -116,8 +108,7 @@ TEST_F(IDBFactoryTest, WebIDBGetDBNamesCallbacksRejectsPromise) {
EXPECT_FALSE(on_fulfilled);
EXPECT_FALSE(on_rejected);
- const WebVector<WebIDBNameAndVersion> wv;
- wc->OnError(WebIDBDatabaseError(1));
+ callbacks->Error(0, String());
EXPECT_FALSE(on_fulfilled);
EXPECT_FALSE(on_rejected);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc
index 06564cbfadc..a20657b0031 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc
@@ -26,7 +26,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
#include <memory>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
+
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
@@ -39,10 +39,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-using blink::WebIDBCallbacks;
-using blink::WebIDBCursor;
-using blink::WebIDBDatabase;
-
namespace blink {
IDBIndex::IDBIndex(scoped_refptr<IDBIndexMetadata> metadata,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.idl
index 84eca6dfafa..cc8becb0227 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.idl
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.idl
@@ -36,14 +36,14 @@
[NewObject, CallWith=ScriptState, RaisesException] IDBRequest get(any key);
[NewObject, CallWith=ScriptState, RaisesException] IDBRequest getKey(any key);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([Default=Undefined] optional any query,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([DefaultValue=Undefined] optional any query,
optional [EnforceRange] unsigned long count);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([Default=Undefined] optional any query,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([DefaultValue=Undefined] optional any query,
optional [EnforceRange] unsigned long count);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([Default=Undefined] optional any key);
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([DefaultValue=Undefined] optional any key);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([Default=Undefined] optional any range,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([DefaultValue=Undefined] optional any range,
optional IDBCursorDirection direction = "next");
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([Default=Undefined] optional any range,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([DefaultValue=Undefined] optional any range,
optional IDBCursorDirection direction = "next");
};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc
index d061b3e3fed..3223cc205a1 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc
@@ -29,13 +29,15 @@
#include <memory>
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
namespace blink {
namespace {
+// Very rough estimate of minimum key size overhead.
+const size_t kIDBKeyOverheadSize = 16;
+
size_t CalculateIDBKeyArraySize(const IDBKey::KeyArray& keys) {
size_t size(0);
for (const auto& key : keys)
@@ -45,36 +47,81 @@ size_t CalculateIDBKeyArraySize(const IDBKey::KeyArray& keys) {
} // namespace
-IDBKey::IDBKey() : type_(kInvalidType), size_estimate_(kIDBKeyOverheadSize) {}
+// static
+std::unique_ptr<IDBKey> IDBKey::Clone(const IDBKey* rkey) {
+ if (!rkey)
+ return IDBKey::CreateNull();
+
+ switch (rkey->GetType()) {
+ case mojom::IDBKeyType::Invalid:
+ return IDBKey::CreateInvalid();
+ case mojom::IDBKeyType::Null:
+ return IDBKey::CreateNull();
+ case mojom::IDBKeyType::Array: {
+ IDBKey::KeyArray lkey_array;
+ const auto& rkey_array = rkey->Array();
+ for (const auto& rkey_item : rkey_array)
+ lkey_array.push_back(IDBKey::Clone(rkey_item));
+ return IDBKey::CreateArray(std::move(lkey_array));
+ }
+ case mojom::IDBKeyType::Binary:
+ return IDBKey::CreateBinary(rkey->Binary());
+ case mojom::IDBKeyType::String:
+ return IDBKey::CreateString(rkey->GetString());
+ case mojom::IDBKeyType::Date:
+ return IDBKey::CreateDate(rkey->Date());
+ case mojom::IDBKeyType::Number:
+ return IDBKey::CreateNumber(rkey->Number());
+
+ case mojom::IDBKeyType::Min:
+ break; // Not used, NOTREACHED.
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+IDBKey::IDBKey()
+ : type_(mojom::IDBKeyType::Invalid), size_estimate_(kIDBKeyOverheadSize) {}
+
+// Must be Invalid or Null.
+IDBKey::IDBKey(mojom::IDBKeyType type)
+ : type_(type), size_estimate_(kIDBKeyOverheadSize) {
+ DCHECK(type_ == mojom::IDBKeyType::Invalid ||
+ type_ == mojom::IDBKeyType::Null);
+}
-IDBKey::IDBKey(Type type, double number)
+// Must be Number or Date.
+IDBKey::IDBKey(mojom::IDBKeyType type, double number)
: type_(type),
number_(number),
- size_estimate_(kIDBKeyOverheadSize + sizeof(number_)) {}
+ size_estimate_(kIDBKeyOverheadSize + sizeof(number_)) {
+ DCHECK(type_ == mojom::IDBKeyType::Number ||
+ type_ == mojom::IDBKeyType::Date);
+}
IDBKey::IDBKey(const String& value)
- : type_(kStringType),
+ : type_(mojom::IDBKeyType::String),
string_(value),
size_estimate_(kIDBKeyOverheadSize + (string_.length() * sizeof(UChar))) {
}
IDBKey::IDBKey(scoped_refptr<SharedBuffer> value)
- : type_(kBinaryType),
+ : type_(mojom::IDBKeyType::Binary),
binary_(std::move(value)),
size_estimate_(kIDBKeyOverheadSize + binary_.get()->size()) {}
IDBKey::IDBKey(KeyArray key_array)
- : type_(kArrayType),
+ : type_(mojom::IDBKeyType::Array),
array_(std::move(key_array)),
size_estimate_(kIDBKeyOverheadSize + CalculateIDBKeyArraySize(array_)) {}
IDBKey::~IDBKey() = default;
bool IDBKey::IsValid() const {
- if (type_ == kInvalidType)
+ if (type_ == mojom::IDBKeyType::Invalid)
return false;
- if (type_ == kArrayType) {
+ if (type_ == mojom::IDBKeyType::Array) {
for (const auto& element : array_) {
if (!element->IsValid())
return false;
@@ -100,26 +147,29 @@ int IDBKey::Compare(const IDBKey* other) const {
return type_ > other->type_ ? -1 : 1;
switch (type_) {
- case kArrayType:
+ case mojom::IDBKeyType::Array:
for (wtf_size_t i = 0; i < array_.size() && i < other->array_.size();
++i) {
if (int result = array_[i]->Compare(other->array_[i].get()))
return result;
}
return CompareNumbers(array_.size(), other->array_.size());
- case kBinaryType:
+ case mojom::IDBKeyType::Binary:
if (int result =
memcmp(binary_->Data(), other->binary_->Data(),
std::min(binary_->size(), other->binary_->size())))
return result < 0 ? -1 : 1;
return CompareNumbers(binary_->size(), other->binary_->size());
- case kStringType:
+ case mojom::IDBKeyType::String:
return CodePointCompare(string_, other->string_);
- case kDateType:
- case kNumberType:
+ case mojom::IDBKeyType::Date:
+ case mojom::IDBKeyType::Number:
return CompareNumbers(number_, other->number_);
- case kInvalidType:
- case kTypeEnumMax:
+
+ // These values cannot be compared to each other.
+ case mojom::IDBKeyType::Invalid:
+ case mojom::IDBKeyType::Null:
+ case mojom::IDBKeyType::Min:
NOTREACHED();
return 0;
}
@@ -141,11 +191,11 @@ bool IDBKey::IsEqual(const IDBKey* other) const {
}
// static
-WebVector<WebIDBKey> IDBKey::ToMultiEntryArray(
+Vector<std::unique_ptr<IDBKey>> IDBKey::ToMultiEntryArray(
std::unique_ptr<IDBKey> array_key) {
- DCHECK_EQ(array_key->type_, kArrayType);
- WebVector<WebIDBKey> result;
- result.reserve(array_key->array_.size());
+ DCHECK_EQ(array_key->type_, mojom::IDBKeyType::Array);
+ Vector<std::unique_ptr<IDBKey>> result;
+ result.ReserveInitialCapacity(array_key->array_.size());
for (std::unique_ptr<IDBKey>& key : array_key->array_) {
if (key->IsValid())
result.emplace_back(std::move(key));
@@ -154,21 +204,15 @@ WebVector<WebIDBKey> IDBKey::ToMultiEntryArray(
// Remove duplicates using std::sort/std::unique rather than a hashtable to
// avoid the complexity of implementing DefaultHash<IDBKey>.
std::sort(
- result.begin(), result.end(), [](const WebIDBKey& a, const WebIDBKey& b) {
- return static_cast<IDBKey*>(a)->IsLessThan(static_cast<IDBKey*>(b));
+ result.begin(), result.end(),
+ [](const std::unique_ptr<IDBKey>& a, const std::unique_ptr<IDBKey>& b) {
+ return (a)->IsLessThan(b.get());
});
- const auto end = std::unique(result.begin(), result.end());
+ std::unique_ptr<IDBKey>* end = std::unique(result.begin(), result.end());
DCHECK_LE(static_cast<wtf_size_t>(end - result.begin()), result.size());
- result.resize(end - result.begin());
+ result.resize(static_cast<wtf_size_t>(end - result.begin()));
return result;
}
-STATIC_ASSERT_ENUM(kWebIDBKeyTypeInvalid, IDBKey::kInvalidType);
-STATIC_ASSERT_ENUM(kWebIDBKeyTypeArray, IDBKey::kArrayType);
-STATIC_ASSERT_ENUM(kWebIDBKeyTypeBinary, IDBKey::kBinaryType);
-STATIC_ASSERT_ENUM(kWebIDBKeyTypeString, IDBKey::kStringType);
-STATIC_ASSERT_ENUM(kWebIDBKeyTypeDate, IDBKey::kDateType);
-STATIC_ASSERT_ENUM(kWebIDBKeyTypeNumber, IDBKey::kNumberType);
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h
index 9c8e9addf5d..2bfada42877 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h
@@ -32,8 +32,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -57,8 +56,12 @@ class MODULES_EXPORT IDBKey {
return base::WrapUnique(new IDBKey());
}
+ static std::unique_ptr<IDBKey> CreateNull() {
+ return base::WrapUnique(new IDBKey(mojom::IDBKeyType::Null));
+ }
+
static std::unique_ptr<IDBKey> CreateNumber(double number) {
- return base::WrapUnique(new IDBKey(kNumberType, number));
+ return base::WrapUnique(new IDBKey(mojom::IDBKeyType::Number, number));
}
static std::unique_ptr<IDBKey> CreateBinary(
@@ -71,95 +74,46 @@ class MODULES_EXPORT IDBKey {
}
static std::unique_ptr<IDBKey> CreateDate(double date) {
- return base::WrapUnique(new IDBKey(kDateType, date));
+ return base::WrapUnique(new IDBKey(mojom::IDBKeyType::Date, date));
}
static std::unique_ptr<IDBKey> CreateArray(KeyArray array) {
return base::WrapUnique(new IDBKey(std::move(array)));
}
- // TODO(cmp): This |Clone| function is necessary for WebIDBKey's ctor
- // functions. It needs to be available in this header file so
- // web_idb_key.cc can use it. When the IDB Blink variant typemap
- // moves to the renderer/modules/indexeddb/ types and off of the
- // WebIDB* types, this |Clone| function should be removed.
static std::unique_ptr<IDBKey> Clone(const std::unique_ptr<IDBKey>& rkey_in) {
- IDBKey* rkey = rkey_in.get();
- if (!rkey_in.get())
- return nullptr;
-
- switch (rkey->GetType()) {
- case kInvalidType:
- return IDBKey::CreateInvalid();
- case kArrayType: {
- IDBKey::KeyArray lkey_array;
- const auto& rkey_array = rkey->Array();
- for (const auto& rkey_item : rkey_array)
- lkey_array.push_back(IDBKey::Clone(rkey_item));
- return IDBKey::CreateArray(std::move(lkey_array));
- }
- case kBinaryType:
- return IDBKey::CreateBinary(rkey->Binary());
- case kStringType:
- return IDBKey::CreateString(rkey->GetString());
- case kDateType:
- return IDBKey::CreateDate(rkey->Date());
- case kNumberType:
- return IDBKey::CreateNumber(rkey->Number());
-
- case kTypeEnumMax:
- break; // Not used, NOTREACHED.
- }
- NOTREACHED();
- return nullptr;
+ return IDBKey::Clone(rkey_in.get());
}
+ static std::unique_ptr<IDBKey> Clone(const IDBKey* rkey);
+
~IDBKey();
- // Very rough estimate of minimum key size overhead.
- //
- // TODO(cmp): When the reference to this in web_idb_key.cc goes away, move
- // this variable back to idb_key.cc's anonymous namespace.
- static const size_t kIDBKeyOverheadSize = 16;
-
- // In order of the least to the highest precedent in terms of sort order.
- // These values are written to logs. New enum values can be added, but
- // existing enums must never be renumbered or deleted and reused.
- enum Type {
- kInvalidType = 0,
- kArrayType = 1,
- kBinaryType = 2,
- kStringType = 3,
- kDateType = 4,
- kNumberType = 5,
- kTypeEnumMax,
- };
-
- Type GetType() const { return type_; }
+ mojom::IDBKeyType GetType() const { return type_; }
bool IsValid() const;
const KeyArray& Array() const {
- DCHECK_EQ(type_, kArrayType);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Array);
return array_;
}
scoped_refptr<SharedBuffer> Binary() const {
- DCHECK_EQ(type_, kBinaryType);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Binary);
return binary_;
}
const String& GetString() const {
- DCHECK_EQ(type_, kStringType);
+ DCHECK_EQ(type_, mojom::IDBKeyType::String);
return string_;
}
double Date() const {
- DCHECK_EQ(type_, kDateType);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Date);
return number_;
}
double Number() const {
- DCHECK_EQ(type_, kNumberType);
+ DCHECK_EQ(type_, mojom::IDBKeyType::Number);
return number_;
}
@@ -177,19 +131,20 @@ class MODULES_EXPORT IDBKey {
// The return value will be pasesd to the backing store, which requires
// Web types. Returning the correct types directly avoids copying later on
// (wasted CPU cycles and code size).
- static WebVector<WebIDBKey> ToMultiEntryArray(
+ static Vector<std::unique_ptr<IDBKey>> ToMultiEntryArray(
std::unique_ptr<IDBKey> array_key);
private:
DISALLOW_COPY_AND_ASSIGN(IDBKey);
IDBKey();
- IDBKey(Type type, double number);
+ IDBKey(mojom::IDBKeyType type);
+ IDBKey(mojom::IDBKeyType type, double number);
explicit IDBKey(const String& value);
explicit IDBKey(scoped_refptr<SharedBuffer> value);
explicit IDBKey(KeyArray key_array);
- Type type_;
+ mojom::IDBKeyType type_;
KeyArray array_;
scoped_refptr<SharedBuffer> binary_;
const String string_;
@@ -201,6 +156,8 @@ class MODULES_EXPORT IDBKey {
size_t size_estimate_;
};
+using IDBIndexKeys = std::pair<int64_t, Vector<std::unique_ptr<IDBKey>>>;
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_KEY_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc
index ca3f5c67ced..5ac71bf54a0 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc
@@ -103,12 +103,12 @@ void IDBParseKeyPath(const String& key_path,
}
IDBKeyPath::IDBKeyPath(const class String& string)
- : type_(kStringType), string_(string) {
+ : type_(mojom::IDBKeyPathType::String), string_(string) {
DCHECK(!string_.IsNull());
}
IDBKeyPath::IDBKeyPath(const Vector<class String>& array)
- : type_(kArrayType), array_(array) {
+ : type_(mojom::IDBKeyPathType::Array), array_(array) {
#if DCHECK_IS_ON()
for (const auto& element : array_)
DCHECK(!element.IsNull());
@@ -117,14 +117,14 @@ IDBKeyPath::IDBKeyPath(const Vector<class String>& array)
IDBKeyPath::IDBKeyPath(const StringOrStringSequence& key_path) {
if (key_path.IsNull()) {
- type_ = kNullType;
+ type_ = mojom::IDBKeyPathType::Null;
} else if (key_path.IsString()) {
- type_ = kStringType;
+ type_ = mojom::IDBKeyPathType::String;
string_ = key_path.GetAsString();
DCHECK(!string_.IsNull());
} else {
DCHECK(key_path.IsStringSequence());
- type_ = kArrayType;
+ type_ = mojom::IDBKeyPathType::Array;
array_ = key_path.GetAsStringSequence();
#if DCHECK_IS_ON()
for (const auto& element : array_)
@@ -133,48 +133,15 @@ IDBKeyPath::IDBKeyPath(const StringOrStringSequence& key_path) {
}
}
-IDBKeyPath::IDBKeyPath(const WebIDBKeyPath& key_path) {
- switch (key_path.KeyPathType()) {
- case kWebIDBKeyPathTypeNull:
- type_ = kNullType;
- return;
-
- case kWebIDBKeyPathTypeString:
- type_ = kStringType;
- string_ = key_path.String();
- return;
-
- case kWebIDBKeyPathTypeArray:
- type_ = kArrayType;
- for (size_t i = 0, size = key_path.Array().size(); i < size; ++i)
- array_.push_back(key_path.Array()[i]);
- return;
- }
- NOTREACHED();
-}
-
-IDBKeyPath::operator WebIDBKeyPath() const {
- switch (type_) {
- case kNullType:
- return WebIDBKeyPath();
- case kStringType:
- return WebIDBKeyPath(WebString(string_));
- case kArrayType:
- return WebIDBKeyPath(array_);
- }
- NOTREACHED();
- return WebIDBKeyPath();
-}
-
bool IDBKeyPath::IsValid() const {
switch (type_) {
- case kNullType:
+ case mojom::IDBKeyPathType::Null:
return false;
- case kStringType:
+ case mojom::IDBKeyPathType::String:
return IDBIsValidKeyPath(string_);
- case kArrayType:
+ case mojom::IDBKeyPathType::Array:
if (array_.IsEmpty())
return false;
for (const auto& element : array_) {
@@ -192,19 +159,15 @@ bool IDBKeyPath::operator==(const IDBKeyPath& other) const {
return false;
switch (type_) {
- case kNullType:
+ case mojom::IDBKeyPathType::Null:
return true;
- case kStringType:
+ case mojom::IDBKeyPathType::String:
return string_ == other.string_;
- case kArrayType:
+ case mojom::IDBKeyPathType::Array:
return array_ == other.array_;
}
NOTREACHED();
return false;
}
-STATIC_ASSERT_ENUM(kWebIDBKeyPathTypeNull, IDBKeyPath::kNullType);
-STATIC_ASSERT_ENUM(kWebIDBKeyPathTypeString, IDBKeyPath::kStringType);
-STATIC_ASSERT_ENUM(kWebIDBKeyPathTypeArray, IDBKeyPath::kArrayType);
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.h
index f78a1dda2ef..c31407fca36 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.h
@@ -26,7 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_KEY_PATH_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_KEY_PATH_H_
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_string_sequence.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -48,34 +48,29 @@ class MODULES_EXPORT IDBKeyPath {
DISALLOW_NEW();
public:
- IDBKeyPath() : type_(kNullType) {}
+ IDBKeyPath() : type_(mojom::IDBKeyPathType::Null) {}
explicit IDBKeyPath(const String&);
explicit IDBKeyPath(const Vector<String>& array);
explicit IDBKeyPath(const StringOrStringSequence& key_path);
- IDBKeyPath(const WebIDBKeyPath&);
- operator WebIDBKeyPath() const;
-
- enum Type { kNullType = 0, kStringType, kArrayType };
-
- Type GetType() const { return type_; }
+ mojom::IDBKeyPathType GetType() const { return type_; }
const Vector<String>& Array() const {
- DCHECK_EQ(type_, kArrayType);
+ DCHECK_EQ(type_, mojom::IDBKeyPathType::Array);
return array_;
}
const String& GetString() const {
- DCHECK_EQ(type_, kStringType);
+ DCHECK_EQ(type_, mojom::IDBKeyPathType::String);
return string_;
}
- bool IsNull() const { return type_ == kNullType; }
+ bool IsNull() const { return type_ == mojom::IDBKeyPathType::Null; }
bool IsValid() const;
bool operator==(const IDBKeyPath& other) const;
private:
- Type type_;
+ mojom::IDBKeyPathType type_;
class String string_;
Vector<class String> array_;
};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc
index 92e1f492f9d..9524c19e451 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc
@@ -38,7 +38,7 @@ void CheckKeyPath(const String& key_path,
const Vector<String>& expected,
int parser_error) {
IDBKeyPath idb_key_path(key_path);
- ASSERT_EQ(idb_key_path.GetType(), IDBKeyPath::kStringType);
+ ASSERT_EQ(idb_key_path.GetType(), mojom::IDBKeyPathType::String);
ASSERT_EQ(idb_key_path.IsValid(),
(parser_error == kIDBKeyPathParseErrorNone));
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.cc
index 193c0cfaf43..f9af24895aa 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.cc
@@ -40,13 +40,13 @@ IDBKeyRange* IDBKeyRange::FromScriptValue(ExecutionContext* context,
if (value.IsUndefined() || value.IsNull())
return nullptr;
- IDBKeyRange* const range =
- ScriptValue::To<IDBKeyRange*>(ToIsolate(context), value, exception_state);
+ IDBKeyRange* const range = ScriptValue::To<IDBKeyRange*>(
+ context->GetIsolate(), value, exception_state);
if (range)
return range;
std::unique_ptr<IDBKey> key = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(context), value, exception_state);
+ context->GetIsolate(), value, exception_state);
if (exception_state.HadException())
return nullptr;
if (!key || !key->IsValid()) {
@@ -105,8 +105,7 @@ IDBKeyRange* IDBKeyRange::only(ScriptState* script_state,
const ScriptValue& key_value,
ExceptionState& exception_state) {
std::unique_ptr<IDBKey> key = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(ExecutionContext::From(script_state)), key_value,
- exception_state);
+ script_state->GetIsolate(), key_value, exception_state);
if (exception_state.HadException())
return nullptr;
if (!key || !key->IsValid()) {
@@ -126,7 +125,7 @@ IDBKeyRange* IDBKeyRange::lowerBound(ScriptState* script_state,
bool open,
ExceptionState& exception_state) {
std::unique_ptr<IDBKey> bound = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(ExecutionContext::From(script_state)), bound_value,
+ ExecutionContext::From(script_state)->GetIsolate(), bound_value,
exception_state);
if (exception_state.HadException())
return nullptr;
@@ -146,7 +145,7 @@ IDBKeyRange* IDBKeyRange::upperBound(ScriptState* script_state,
bool open,
ExceptionState& exception_state) {
std::unique_ptr<IDBKey> bound = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(ExecutionContext::From(script_state)), bound_value,
+ ExecutionContext::From(script_state)->GetIsolate(), bound_value,
exception_state);
if (exception_state.HadException())
return nullptr;
@@ -167,7 +166,7 @@ IDBKeyRange* IDBKeyRange::bound(ScriptState* script_state,
bool upper_open,
ExceptionState& exception_state) {
std::unique_ptr<IDBKey> lower = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(ExecutionContext::From(script_state)), lower_value,
+ ExecutionContext::From(script_state)->GetIsolate(), lower_value,
exception_state);
if (exception_state.HadException())
return nullptr;
@@ -178,7 +177,7 @@ IDBKeyRange* IDBKeyRange::bound(ScriptState* script_state,
}
std::unique_ptr<IDBKey> upper = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(ExecutionContext::From(script_state)), upper_value,
+ ExecutionContext::From(script_state)->GetIsolate(), upper_value,
exception_state);
if (exception_state.HadException())
@@ -214,7 +213,7 @@ bool IDBKeyRange::includes(ScriptState* script_state,
const ScriptValue& key_value,
ExceptionState& exception_state) {
std::unique_ptr<IDBKey> key = ScriptValue::To<std::unique_ptr<IDBKey>>(
- ToIsolate(ExecutionContext::From(script_state)), key_value,
+ ExecutionContext::From(script_state)->GetIsolate(), key_value,
exception_state);
if (exception_state.HadException())
return false;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h
index fb8132b90d7..80fb9535737 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h
@@ -44,10 +44,20 @@ class MODULES_EXPORT IDBKeyRange final : public ScriptWrappable {
enum LowerBoundType { kLowerBoundOpen, kLowerBoundClosed };
enum UpperBoundType { kUpperBoundOpen, kUpperBoundClosed };
+ static IDBKeyRange* Create(const IDBKey* key) {
+ std::unique_ptr<IDBKey> lower_key = IDBKey::Clone(key);
+ std::unique_ptr<IDBKey> upper_key = IDBKey::Clone(key);
+ return IDBKeyRange::Create(std::move(lower_key), std::move(upper_key),
+ kLowerBoundClosed, kUpperBoundClosed);
+ }
+
static IDBKeyRange* Create(std::unique_ptr<IDBKey> lower,
std::unique_ptr<IDBKey> upper,
LowerBoundType lower_type,
UpperBoundType upper_type) {
+ if ((!lower || !lower->IsValid()) && (!upper || !upper->IsValid()))
+ return nullptr;
+
IDBKey* upper_compressed = upper.get();
return MakeGarbageCollected<IDBKeyRange>(std::move(lower), upper_compressed,
std::move(upper), lower_type,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc
index c49a735a2b2..0f7f8d8129e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc
@@ -4,9 +4,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-
namespace blink {
constexpr int64_t IDBIndexMetadata::kInvalidId;
@@ -26,6 +23,11 @@ IDBIndexMetadata::IDBIndexMetadata(const String& name,
unique(unique),
multi_entry(multi_entry) {}
+// static
+scoped_refptr<IDBIndexMetadata> IDBIndexMetadata::Create() {
+ return base::AdoptRef(new IDBIndexMetadata());
+}
+
IDBObjectStoreMetadata::IDBObjectStoreMetadata() = default;
IDBObjectStoreMetadata::IDBObjectStoreMetadata(const String& name,
@@ -39,6 +41,11 @@ IDBObjectStoreMetadata::IDBObjectStoreMetadata(const String& name,
auto_increment(auto_increment),
max_index_id(max_index_id) {}
+// static
+scoped_refptr<IDBObjectStoreMetadata> IDBObjectStoreMetadata::Create() {
+ return base::AdoptRef(new IDBObjectStoreMetadata());
+}
+
scoped_refptr<IDBObjectStoreMetadata> IDBObjectStoreMetadata::CreateCopy()
const {
scoped_refptr<IDBObjectStoreMetadata> copy =
@@ -67,32 +74,6 @@ IDBDatabaseMetadata::IDBDatabaseMetadata(const String& name,
version(version),
max_object_store_id(max_object_store_id) {}
-IDBDatabaseMetadata::IDBDatabaseMetadata(const WebIDBMetadata& web_metadata)
- : name(web_metadata.name),
- id(web_metadata.id),
- version(web_metadata.version),
- max_object_store_id(web_metadata.max_object_store_id) {
- for (size_t i = 0; i < web_metadata.object_stores.size(); ++i) {
- const WebIDBMetadata::ObjectStore& web_object_store =
- web_metadata.object_stores[i];
- scoped_refptr<IDBObjectStoreMetadata> object_store =
- base::AdoptRef(new IDBObjectStoreMetadata(
- web_object_store.name, web_object_store.id,
- IDBKeyPath(web_object_store.key_path),
- web_object_store.auto_increment, web_object_store.max_index_id));
-
- for (size_t j = 0; j < web_object_store.indexes.size(); ++j) {
- const WebIDBMetadata::Index& web_index = web_object_store.indexes[j];
- scoped_refptr<IDBIndexMetadata> index =
- base::AdoptRef(new IDBIndexMetadata(
- web_index.name, web_index.id, IDBKeyPath(web_index.key_path),
- web_index.unique, web_index.multi_entry));
- object_store->indexes.Set(web_index.id, std::move(index));
- }
- object_stores.Set(web_object_store.id, std::move(object_store));
- }
-}
-
void IDBDatabaseMetadata::CopyFrom(const IDBDatabaseMetadata& metadata) {
name = metadata.name;
id = metadata.id;
@@ -100,6 +81,4 @@ void IDBDatabaseMetadata::CopyFrom(const IDBDatabaseMetadata& metadata) {
max_object_store_id = metadata.max_object_store_id;
}
-STATIC_ASSERT_ENUM(WebIDBMetadata::kNoVersion, IDBDatabaseMetadata::kNoVersion);
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.h
index c20cf15f79d..6bda5a227a5 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.h
@@ -30,7 +30,6 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_METADATA_H_
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -58,6 +57,8 @@ class IDBIndexMetadata : public RefCounted<IDBIndexMetadata> {
bool unique,
bool multi_entry);
+ static scoped_refptr<IDBIndexMetadata> Create();
+
String name;
int64_t id;
IDBKeyPath key_path;
@@ -79,6 +80,8 @@ class MODULES_EXPORT IDBObjectStoreMetadata
bool auto_increment,
int64_t max_index_id);
+ static scoped_refptr<IDBObjectStoreMetadata> Create();
+
// Creates a deep copy of the object metadata, which includes copies of index
// metadata items.
scoped_refptr<IDBObjectStoreMetadata> CreateCopy() const;
@@ -103,8 +106,6 @@ struct MODULES_EXPORT IDBDatabaseMetadata {
int64_t version,
int64_t max_object_store_id);
- explicit IDBDatabaseMetadata(const WebIDBMetadata&);
-
// Overwrites the database metadata, but does not change the object store and
// index metadata.
void CopyFrom(const IDBDatabaseMetadata&);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h
new file mode 100644
index 00000000000..ac96affd8ba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h
@@ -0,0 +1,20 @@
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_NAME_AND_VERSION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_NAME_AND_VERSION_H_
+
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+struct IDBNameAndVersion {
+ enum { kNoVersion = -1 };
+ String name;
+ int64_t version;
+
+ IDBNameAndVersion() : version(kNoVersion) {}
+ IDBNameAndVersion(String name, int64_t version)
+ : name(name), version(version) {}
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_NAME_AND_VERSION_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
index 7f2f23dc118..0fe51333559 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
@@ -30,16 +30,13 @@
#include "base/feature_list.h"
#include "base/memory/scoped_refptr.h"
#include "base/numerics/safe_conversions.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
#include "third_party/blink/public/platform/web_blob_info.h"
-#include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "third_party/blink/renderer/core/dom/dom_string_list.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.h"
@@ -55,11 +52,6 @@
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "v8/include/v8.h"
-using blink::WebBlobInfo;
-using blink::WebIDBCallbacks;
-using blink::WebIDBCursor;
-using blink::WebIDBDatabase;
-
namespace blink {
IDBObjectStore::IDBObjectStore(scoped_refptr<IDBObjectStoreMetadata> metadata,
@@ -306,7 +298,7 @@ IDBRequest* IDBObjectStore::getAllKeys(ScriptState* script_state,
return request;
}
-static WebVector<WebIDBKey> GenerateIndexKeysForValue(
+static Vector<std::unique_ptr<IDBKey>> GenerateIndexKeysForValue(
v8::Isolate* isolate,
const IDBIndexMetadata& index_metadata,
const ScriptValue& object_value) {
@@ -314,30 +306,30 @@ static WebVector<WebIDBKey> GenerateIndexKeysForValue(
std::unique_ptr<IDBKey> index_key = ScriptValue::To<std::unique_ptr<IDBKey>>(
isolate, object_value, exception_state, index_metadata.key_path);
if (!index_key)
- return WebVector<WebIDBKey>();
+ return Vector<std::unique_ptr<IDBKey>>();
DEFINE_THREAD_SAFE_STATIC_LOCAL(
EnumerationHistogram, key_type_histogram,
("WebCore.IndexedDB.ObjectStore.IndexEntry.KeyType",
- static_cast<int>(IDBKey::kTypeEnumMax)));
+ static_cast<int>(mojom::IDBKeyType::kMaxValue)));
if (!index_metadata.multi_entry ||
- index_key->GetType() != IDBKey::kArrayType) {
+ index_key->GetType() != mojom::IDBKeyType::Array) {
if (!index_key->IsValid())
- return WebVector<WebIDBKey>();
+ return Vector<std::unique_ptr<IDBKey>>();
- WebVector<WebIDBKey> index_keys;
- index_keys.reserve(1);
+ Vector<std::unique_ptr<IDBKey>> index_keys;
+ index_keys.ReserveInitialCapacity(1);
index_keys.emplace_back(std::move(index_key));
- key_type_histogram.Count(static_cast<int>(index_keys[0].View().KeyType()));
- return WebVector<WebIDBKey>(std::move(index_keys));
+ key_type_histogram.Count(static_cast<int>(index_keys[0]->GetType()));
+ return index_keys;
} else {
DCHECK(index_metadata.multi_entry);
- DCHECK_EQ(index_key->GetType(), IDBKey::kArrayType);
- WebVector<WebIDBKey> index_keys =
+ DCHECK_EQ(index_key->GetType(), mojom::IDBKeyType::Array);
+ Vector<std::unique_ptr<IDBKey>> index_keys =
IDBKey::ToMultiEntryArray(std::move(index_key));
- for (const WebIDBKey& key : index_keys)
- key_type_histogram.Count(static_cast<int>(key.View().KeyType()));
+ for (std::unique_ptr<IDBKey>& key : index_keys)
+ key_type_histogram.Count(static_cast<int>(key->GetType()));
return index_keys;
}
}
@@ -554,11 +546,11 @@ IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state,
DEFINE_THREAD_SAFE_STATIC_LOCAL(
EnumerationHistogram, key_type_histogram,
("WebCore.IndexedDB.ObjectStore.Record.KeyType",
- static_cast<int>(IDBKey::kTypeEnumMax)));
+ static_cast<int>(mojom::IDBKeyType::kMaxValue)));
key_type_histogram.Count(static_cast<int>(key->GetType()));
}
- Vector<WebIDBIndexKeys> index_keys;
+ Vector<IDBIndexKeys> index_keys;
index_keys.ReserveInitialCapacity(Metadata().indexes.size());
for (const auto& it : Metadata().indexes) {
if (clone.IsEmpty())
@@ -581,11 +573,13 @@ IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state,
if (base::FeatureList::IsEnabled(kIndexedDBLargeValueWrapping))
value_wrapper.WrapIfBiggerThan(IDBValueWrapper::kWrapThreshold);
+ std::unique_ptr<IDBValue> idb_value = IDBValue::Create(
+ value_wrapper.TakeWireBytes(), value_wrapper.TakeBlobInfo());
+
request->transit_blob_handles() = value_wrapper.TakeBlobDataHandles();
BackendDB()->Put(
- transaction_->Id(), Id(), WebData(value_wrapper.TakeWireBytes()),
- value_wrapper.TakeBlobInfo(), WebIDBKeyView(key), put_mode,
- request->CreateWebCallbacks().release(), std::move(index_keys));
+ transaction_->Id(), Id(), std::move(idb_value), IDBKey::Clone(key),
+ put_mode, request->CreateWebCallbacks().release(), std::move(index_keys));
return request;
}
@@ -687,7 +681,7 @@ namespace {
// the object store. It only needs to be kept alive by virtue of being
// a listener on an IDBRequest object, in the same way that JavaScript
// cursor success handlers are kept alive.
-class IndexPopulator final : public EventListener {
+class IndexPopulator final : public NativeEventListener {
public:
static IndexPopulator* Create(
ScriptState* script_state,
@@ -695,28 +689,17 @@ class IndexPopulator final : public EventListener {
int64_t transaction_id,
int64_t object_store_id,
scoped_refptr<const IDBIndexMetadata> index_metadata) {
- return new IndexPopulator(script_state, database, transaction_id,
- object_store_id, std::move(index_metadata));
- }
-
- bool operator==(const EventListener& other) const override {
- return this == &other;
+ return MakeGarbageCollected<IndexPopulator>(script_state, database,
+ transaction_id, object_store_id,
+ std::move(index_metadata));
}
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(script_state_);
- visitor->Trace(database_);
- EventListener::Trace(visitor);
- }
-
- private:
IndexPopulator(ScriptState* script_state,
IDBDatabase* database,
int64_t transaction_id,
int64_t object_store_id,
scoped_refptr<const IDBIndexMetadata> index_metadata)
- : EventListener(kCPPEventListenerType),
- script_state_(script_state),
+ : script_state_(script_state),
database_(database),
transaction_id_(transaction_id),
object_store_id_(object_store_id),
@@ -724,6 +707,13 @@ class IndexPopulator final : public EventListener {
DCHECK(index_metadata_.get());
}
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(script_state_);
+ visitor->Trace(database_);
+ NativeEventListener::Trace(visitor);
+ }
+
+ private:
const IDBIndexMetadata& IndexMetadata() const { return *index_metadata_; }
void Invoke(ExecutionContext* execution_context, Event* event) override {
@@ -753,7 +743,7 @@ class IndexPopulator final : public EventListener {
const IDBKey* primary_key = cursor->IdbPrimaryKey();
ScriptValue value = cursor->value(script_state_);
- Vector<WebIDBIndexKeys> index_keys;
+ Vector<IDBIndexKeys> index_keys;
index_keys.ReserveInitialCapacity(1);
index_keys.emplace_back(
IndexMetadata().id,
@@ -761,7 +751,7 @@ class IndexPopulator final : public EventListener {
IndexMetadata(), value));
database_->Backend()->SetIndexKeys(transaction_id_, object_store_id_,
- WebIDBKeyView(primary_key),
+ IDBKey::Clone(primary_key),
std::move(index_keys));
} else {
// Now that we are done indexing, tell the backend to go
@@ -819,7 +809,8 @@ IDBIndex* IDBObjectStore::createIndex(ScriptState* script_state,
"The keyPath argument contains an invalid key path.");
return nullptr;
}
- if (key_path.GetType() == IDBKeyPath::kArrayType && options->multiEntry()) {
+ if (key_path.GetType() == mojom::IDBKeyPathType::Array &&
+ options->multiEntry()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidAccessError,
"The keyPath argument was an array and the multiEntry option is true.");
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
index 24c6371df38..c113f5fe3a7 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
@@ -34,21 +34,21 @@
[SameObject] readonly attribute IDBTransaction transaction;
readonly attribute boolean autoIncrement;
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest put(any value, [Default=Undefined] optional any key);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest add(any value, [Default=Undefined] optional any key);
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest put(any value, [DefaultValue=Undefined] optional any key);
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest add(any value, [DefaultValue=Undefined] optional any key);
[NewObject, CallWith=ScriptState, ImplementedAs=Delete, RaisesException] IDBRequest delete(any key);
[NewObject, CallWith=ScriptState, RaisesException] IDBRequest clear();
[NewObject, CallWith=ScriptState, RaisesException] IDBRequest get(any key);
[NewObject, CallWith=ScriptState, RaisesException] IDBRequest getKey(any key);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([Default=Undefined] optional any query,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([DefaultValue=Undefined] optional any query,
optional [EnforceRange] unsigned long count);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([Default=Undefined] optional any query,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([DefaultValue=Undefined] optional any query,
optional [EnforceRange] unsigned long count);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([Default=Undefined] optional any key);
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([DefaultValue=Undefined] optional any key);
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([Default=Undefined] optional any range,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([DefaultValue=Undefined] optional any range,
optional IDBCursorDirection direction = "next");
- [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([Default=Undefined] optional any range,
+ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([DefaultValue=Undefined] optional any range,
optional IDBCursorDirection direction = "next");
[RaisesException] IDBIndex index(DOMString name);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc
index 1c67cf44264..6abddbad083 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
@@ -66,19 +65,29 @@ const String& IDBObservation::type() const {
}
}
-IDBObservation* IDBObservation::Create(WebIDBObservation observation,
- v8::Isolate* isolate) {
- return MakeGarbageCollected<IDBObservation>(std::move(observation), isolate);
+IDBObservation* IDBObservation::Create(int64_t object_store_id,
+ mojom::IDBOperationType type,
+ IDBKeyRange* key_range,
+ std::unique_ptr<IDBValue> value) {
+ return MakeGarbageCollected<IDBObservation>(object_store_id, type, key_range,
+ std::move(value));
}
-IDBObservation::IDBObservation(WebIDBObservation observation,
- v8::Isolate* isolate)
- : key_range_(observation.key_range), operation_type_(observation.type) {
- std::unique_ptr<IDBValue> value = observation.value.ReleaseIdbValue();
- value->SetIsolate(isolate);
+IDBObservation::IDBObservation(int64_t object_store_id,
+ mojom::IDBOperationType type,
+ IDBKeyRange* key_range,
+ std::unique_ptr<IDBValue> value)
+ : object_store_id_(object_store_id),
+ operation_type_(type),
+ key_range_(key_range) {
value_ = IDBAny::Create(std::move(value));
}
+void IDBObservation::SetIsolate(v8::Isolate* isolate) {
+ DCHECK(value_ && value_->Value());
+ value_->Value()->SetIsolate(isolate);
+}
+
void IDBObservation::Trace(blink::Visitor* visitor) {
visitor->Trace(key_range_);
visitor->Trace(value_);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h
index 339043ee3c9..8964fd9e79c 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h
@@ -18,7 +18,6 @@ namespace blink {
class IDBAny;
class IDBKeyRange;
class ScriptState;
-struct WebIDBObservation;
class IDBObservation final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -26,12 +25,18 @@ class IDBObservation final : public ScriptWrappable {
public:
static mojom::IDBOperationType StringToOperationType(const String&);
- // Consumes the WebIDBObservation.
- static IDBObservation* Create(WebIDBObservation, v8::Isolate*);
+ static IDBObservation* Create(int64_t object_store_id,
+ mojom::IDBOperationType type,
+ IDBKeyRange* key_range,
+ std::unique_ptr<IDBValue> value);
- IDBObservation(WebIDBObservation, v8::Isolate*);
+ IDBObservation(int64_t object_store_id,
+ mojom::IDBOperationType type,
+ IDBKeyRange* key_range,
+ std::unique_ptr<IDBValue> value);
~IDBObservation() override;
+ void SetIsolate(v8::Isolate* isolate);
void Trace(blink::Visitor*) override;
// Implement the IDL
@@ -39,10 +44,14 @@ class IDBObservation final : public ScriptWrappable {
ScriptValue value(ScriptState*);
const String& type() const;
+ // Helpers.
+ int64_t object_store_id() const { return object_store_id_; }
+
private:
+ int64_t object_store_id_;
+ const mojom::IDBOperationType operation_type_;
Member<IDBKeyRange> key_range_;
Member<IDBAny> value_;
- const mojom::IDBOperationType operation_type_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc
index af876c85b10..cbf4b7337d4 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
@@ -32,36 +31,28 @@ ScriptValue IDBObserverChanges::records(ScriptState* script_state) {
IDBObserverChanges* IDBObserverChanges::Create(
IDBDatabase* database,
IDBTransaction* transaction,
- const WebVector<WebIDBObservation>& web_observations,
- const HeapVector<Member<IDBObservation>>& observations,
- const WebVector<int32_t>& observation_indices) {
- DCHECK_EQ(web_observations.size(), observations.size());
+ const Vector<Persistent<IDBObservation>>& observations,
+ const Vector<int32_t>& observation_indices) {
return MakeGarbageCollected<IDBObserverChanges>(
- database, transaction, web_observations, observations,
- observation_indices);
+ database, transaction, observations, observation_indices);
}
IDBObserverChanges::IDBObserverChanges(
IDBDatabase* database,
IDBTransaction* transaction,
- const WebVector<WebIDBObservation>& web_observations,
- const HeapVector<Member<IDBObservation>>& observations,
- const WebVector<int32_t>& observation_indices)
+ const Vector<Persistent<IDBObservation>>& observations,
+ const Vector<int32_t>& observation_indices)
: database_(database), transaction_(transaction) {
- DCHECK_EQ(web_observations.size(), observations.size());
- ExtractChanges(web_observations, observations, observation_indices);
+ ExtractChanges(observations, observation_indices);
}
void IDBObserverChanges::ExtractChanges(
- const WebVector<WebIDBObservation>& web_observations,
- const HeapVector<Member<IDBObservation>>& observations,
- const WebVector<int32_t>& observation_indices) {
- DCHECK_EQ(web_observations.size(), observations.size());
-
+ const Vector<Persistent<IDBObservation>>& observations,
+ const Vector<int32_t>& observation_indices) {
// TODO(dmurph): Avoid getting and setting repeated times.
for (const auto& idx : observation_indices) {
records_
- .insert(web_observations[idx].object_store_id,
+ .insert(observations[idx]->object_store_id(),
HeapVector<Member<IDBObservation>>())
.stored_value->value.emplace_back(observations[idx]);
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h
index 53bc5deebb4..aa7a3a078de 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h
@@ -5,7 +5,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_CHANGES_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_CHANGES_H_
-#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
@@ -24,16 +23,13 @@ class IDBObserverChanges final : public ScriptWrappable {
static IDBObserverChanges* Create(
IDBDatabase*,
IDBTransaction*,
- const WebVector<WebIDBObservation>& web_observations,
- const HeapVector<Member<IDBObservation>>& observations,
- const WebVector<int32_t>& observation_indices);
+ const Vector<Persistent<IDBObservation>>& observations,
+ const Vector<int32_t>& observation_indices);
IDBObserverChanges(IDBDatabase*,
IDBTransaction*,
-
- const WebVector<WebIDBObservation>& web_observations,
- const HeapVector<Member<IDBObservation>>& observations,
- const WebVector<int32_t>& observation_indices);
+ const Vector<Persistent<IDBObservation>>& observations,
+ const Vector<int32_t>& observation_indices);
void Trace(blink::Visitor*) override;
@@ -43,9 +39,8 @@ class IDBObserverChanges final : public ScriptWrappable {
ScriptValue records(ScriptState*);
private:
- void ExtractChanges(const WebVector<WebIDBObservation>& web_observations,
- const HeapVector<Member<IDBObservation>>& observations,
- const WebVector<int32_t>& observation_indices);
+ void ExtractChanges(const Vector<Persistent<IDBObservation>>& observations,
+ const Vector<int32_t>& observation_indices);
Member<IDBDatabase> database_;
Member<IDBTransaction> transaction_;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc
index f8a81ea7ed1..9e8fcda38d4 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_open_db_request.h"
#include <memory>
+
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -35,8 +36,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"
-using blink::WebIDBDatabase;
-
namespace blink {
IDBOpenDBRequest* IDBOpenDBRequest::Create(
@@ -45,10 +44,8 @@ IDBOpenDBRequest* IDBOpenDBRequest::Create(
int64_t transaction_id,
int64_t version,
IDBRequest::AsyncTraceState metrics) {
- IDBOpenDBRequest* request = MakeGarbageCollected<IDBOpenDBRequest>(
+ return MakeGarbageCollected<IDBOpenDBRequest>(
script_state, callbacks, transaction_id, version, std::move(metrics));
- request->PauseIfNeeded();
- return request;
}
IDBOpenDBRequest::IDBOpenDBRequest(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc
index a457f84c9d5..0434292ce7f 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc
@@ -55,8 +55,6 @@
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
-using blink::WebIDBCursor;
-
namespace blink {
IDBRequest::AsyncTraceState::AsyncTraceState(const char* trace_event_name)
@@ -122,7 +120,6 @@ IDBRequest* IDBRequest::Create(ScriptState* script_state,
IDBRequest::AsyncTraceState metrics) {
IDBRequest* request = MakeGarbageCollected<IDBRequest>(
script_state, source, transaction, std::move(metrics));
- request->PauseIfNeeded();
// Requests associated with IDBFactory (open/deleteDatabase/getDatabaseNames)
// do not have an associated transaction.
if (transaction)
@@ -134,7 +131,7 @@ IDBRequest::IDBRequest(ScriptState* script_state,
const Source& source,
IDBTransaction* transaction,
AsyncTraceState metrics)
- : PausableObject(ExecutionContext::From(script_state)),
+ : ContextLifecycleObserver(ExecutionContext::From(script_state)),
transaction_(transaction),
isolate_(script_state->GetIsolate()),
metrics_(std::move(metrics)),
@@ -155,7 +152,7 @@ void IDBRequest::Trace(blink::Visitor* visitor) {
visitor->Trace(event_queue_);
visitor->Trace(pending_cursor_);
EventTargetWithInlineData::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
ScriptValue IDBRequest::result(ScriptState* script_state,
@@ -619,7 +616,7 @@ void IDBRequest::ContextDestroyed(ExecutionContext*) {
if (pending_cursor_)
pending_cursor_->ContextWillBeDestroyed();
if (web_callbacks_) {
- web_callbacks_->Detach();
+ web_callbacks_->DetachRequestFromCallback();
web_callbacks_ = nullptr;
}
}
@@ -629,7 +626,7 @@ const AtomicString& IDBRequest::InterfaceName() const {
}
ExecutionContext* IDBRequest::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
+ return ContextLifecycleObserver::GetExecutionContext();
}
DispatchEventResult IDBRequest::DispatchEventInternal(Event& event) {
@@ -694,6 +691,9 @@ DispatchEventResult IDBRequest::DispatchEventInternal(Event& event) {
if (transaction_ && ready_state_ == DONE)
transaction_->UnregisterRequest(this);
+ if (event.type() == event_type_names::kError && transaction_)
+ transaction_->IncrementNumErrorsHandled();
+
event.SetTarget(this);
DispatchEventResult dispatch_result =
IDBEventDispatcher::Dispatch(event, targets);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h
index 48226908cce..640051ef99a 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h
@@ -40,11 +40,11 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/dom_string_list.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/modules/event_modules.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
@@ -67,7 +67,7 @@ class IDBValue;
class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData,
public ActiveScriptWrappable<IDBRequest>,
- public PausableObject {
+ public ContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(IDBRequest);
@@ -155,7 +155,7 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData,
// cannot be null.
const char* trace_event_name_ = nullptr;
// Uniquely generated ID that ties an async trace's begin and end events.
- size_t id_;
+ size_t id_ = 0;
DISALLOW_COPY_AND_ASSIGN(AsyncTraceState);
};
@@ -292,7 +292,7 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData,
// ScriptWrappable
bool HasPendingActivity() const final;
- // PausableObject
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// EventTarget
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc
index 1556b71144f..a8067877426 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc
@@ -28,8 +28,10 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
@@ -49,6 +51,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h"
#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -59,12 +62,120 @@
namespace blink {
namespace {
+class BackendDatabaseWithMockedClose
+ : public testing::StrictMock<mojom::blink::IDBDatabase> {
+ public:
+ explicit BackendDatabaseWithMockedClose(
+ mojom::blink::IDBDatabaseAssociatedRequest request)
+ : binding_(this, std::move(request)) {
+ binding_.set_connection_error_handler(
+ base::BindOnce(&BackendDatabaseWithMockedClose::DatabaseDestroyed,
+ base::Unretained(this)));
+ }
+
+ void DatabaseDestroyed() { destroyed_ = true; }
+
+ void CreateObjectStore(int64_t transaction_id,
+ int64_t object_store_id,
+ const WTF::String& name,
+ const ::blink::IDBKeyPath& key_path,
+ bool auto_increment) override {}
+ void DeleteObjectStore(int64_t transaction_id,
+ int64_t object_store_id) override {}
+ void RenameObjectStore(int64_t transaction_id,
+ int64_t object_store_id,
+ const WTF::String& new_name) override {}
+ void CreateTransaction(int64_t transaction_id,
+ const WTF::Vector<int64_t>& object_store_ids,
+ mojom::blink::IDBTransactionMode mode) override {}
+ MOCK_METHOD0(Close, void());
+ void VersionChangeIgnored() override {}
+ void AddObserver(int64_t transaction_id,
+ int32_t observer_id,
+ bool include_transaction,
+ bool no_records,
+ bool values,
+ uint32_t operation_types) override {}
+ void RemoveObservers(const WTF::Vector<int32_t>& observers) override {}
+ void Get(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ mojom::blink::IDBKeyRangePtr key_range,
+ bool key_only,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void GetAll(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ mojom::blink::IDBKeyRangePtr key_range,
+ bool key_only,
+ int64_t max_count,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void Put(int64_t transaction_id,
+ int64_t object_store_id,
+ std::unique_ptr<::blink::IDBValue> value,
+ std::unique_ptr<::blink::IDBKey> key,
+ mojom::blink::IDBPutMode mode,
+ WTF::Vector<::blink::IDBIndexKeys> index_keys,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void SetIndexKeys(int64_t transaction_id,
+ int64_t object_store_id,
+ std::unique_ptr<::blink::IDBKey> primary_key,
+ WTF::Vector<::blink::IDBIndexKeys> index_keys) override {}
+ void SetIndexesReady(int64_t transaction_id,
+ int64_t object_store_id,
+ const WTF::Vector<int64_t>& index_ids) override {}
+ void OpenCursor(
+ int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ mojom::blink::IDBKeyRangePtr key_range,
+ mojom::blink::IDBCursorDirection direction,
+ bool key_only,
+ mojom::blink::IDBTaskType task_type,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void Count(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ mojom::blink::IDBKeyRangePtr key_range,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void DeleteRange(
+ int64_t transaction_id,
+ int64_t object_store_id,
+ mojom::blink::IDBKeyRangePtr key_range,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void Clear(int64_t transaction_id,
+ int64_t object_store_id,
+ mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {}
+ void CreateIndex(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ const WTF::String& name,
+ const ::blink::IDBKeyPath& key_path,
+ bool unique,
+ bool multi_entry) override {}
+ void DeleteIndex(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id) override {}
+ void RenameIndex(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ const WTF::String& new_name) override {}
+ void Abort(int64_t transaction_id) override {}
+ void Commit(int64_t transaction_id, int64_t num_errors_handled) override {}
+
+ bool destroyed() { return destroyed_; }
+
+ private:
+ bool destroyed_ = false;
+ mojo::AssociatedBinding<mojom::blink::IDBDatabase> binding_;
+};
+
class IDBRequestTest : public testing::Test {
protected:
void SetUp() override {
url_loader_mock_factory_ = platform_->GetURLLoaderMockFactory();
WebURLResponse response;
- response.SetURL(KURL("blob:"));
+ response.SetCurrentRequestUrl(KURL("blob:"));
url_loader_mock_factory_->RegisterURLProtocol(WebString("blob"), response,
"");
}
@@ -243,12 +354,16 @@ TEST_F(IDBRequestTest, ConnectionsAfterStopping) {
const int64_t kTransactionId = 1234;
const int64_t kVersion = 1;
const int64_t kOldVersion = 0;
- const WebIDBMetadata metadata;
+ const IDBDatabaseMetadata metadata;
Persistent<IDBDatabaseCallbacks> callbacks = IDBDatabaseCallbacks::Create();
{
- std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create();
- EXPECT_CALL(*backend, Close()).Times(1);
+ mojom::blink::IDBDatabaseAssociatedPtr ptr;
+ std::unique_ptr<BackendDatabaseWithMockedClose> mock_database =
+ std::make_unique<BackendDatabaseWithMockedClose>(
+ mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr));
+ EXPECT_CALL(*mock_database, Close()).Times(1);
+
IDBOpenDBRequest* request = IDBOpenDBRequest::Create(
scope.GetScriptState(), callbacks, kTransactionId, kVersion,
IDBRequest::AsyncTraceState());
@@ -256,13 +371,18 @@ TEST_F(IDBRequestTest, ConnectionsAfterStopping) {
std::unique_ptr<WebIDBCallbacks> callbacks = request->CreateWebCallbacks();
scope.GetExecutionContext()->NotifyContextDestroyed();
- callbacks->OnUpgradeNeeded(kOldVersion, backend.release(), metadata,
- mojom::IDBDataLoss::None, String());
+ callbacks->UpgradeNeeded(ptr.PassInterface(), kOldVersion,
+ mojom::IDBDataLoss::None, String(), metadata);
+ platform_->RunUntilIdle();
}
{
- std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create();
- EXPECT_CALL(*backend, Close()).Times(1);
+ mojom::blink::IDBDatabaseAssociatedPtr ptr;
+ std::unique_ptr<BackendDatabaseWithMockedClose> mock_database =
+ std::make_unique<BackendDatabaseWithMockedClose>(
+ mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr));
+ EXPECT_CALL(*mock_database, Close()).Times(1);
+
IDBOpenDBRequest* request = IDBOpenDBRequest::Create(
scope.GetScriptState(), callbacks, kTransactionId, kVersion,
IDBRequest::AsyncTraceState());
@@ -270,7 +390,8 @@ TEST_F(IDBRequestTest, ConnectionsAfterStopping) {
std::unique_ptr<WebIDBCallbacks> callbacks = request->CreateWebCallbacks();
scope.GetExecutionContext()->NotifyContextDestroyed();
- callbacks->OnSuccess(backend.release(), metadata);
+ callbacks->SuccessDatabase(ptr.PassInterface(), metadata);
+ platform_->RunUntilIdle();
}
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
index f04b84cc5fa..c962574f1ef 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
#include <memory>
+#include <utility>
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
@@ -43,8 +44,6 @@
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
-using blink::WebIDBDatabase;
-
namespace blink {
IDBTransaction* IDBTransaction::CreateObserver(
@@ -338,7 +337,7 @@ void IDBTransaction::SetActive(bool active) {
state_ = active ? kActive : kInactive;
if (!active && request_list_.IsEmpty() && BackendDB())
- BackendDB()->Commit(id_);
+ BackendDB()->Commit(id_, num_errors_handled_);
}
void IDBTransaction::abort(ExceptionState& exception_state) {
@@ -361,6 +360,30 @@ void IDBTransaction::abort(ExceptionState& exception_state) {
BackendDB()->Abort(id_);
}
+void IDBTransaction::commit(ExceptionState& exception_state) {
+ if (state_ == kFinishing || state_ == kFinished) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ IDBDatabase::kTransactionFinishedErrorMessage);
+ return;
+ }
+
+ if (state_ == kInactive) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ IDBDatabase::kTransactionInactiveErrorMessage);
+ return;
+ }
+
+ if (!GetExecutionContext())
+ return;
+
+ state_ = kFinishing;
+
+ if (BackendDB())
+ BackendDB()->Commit(id_, num_errors_handled_);
+}
+
void IDBTransaction::RegisterRequest(IDBRequest* request) {
DCHECK(request);
DCHECK(!request_list_.Contains(request));
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
index f589fe3ed16..86ddff0a00c 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
@@ -120,6 +120,8 @@ class MODULES_EXPORT IDBTransaction final
bool IsVersionChange() const {
return mode_ == mojom::IDBTransactionMode::VersionChange;
}
+ int64_t NumErrorsHandled() const { return num_errors_handled_; }
+ void IncrementNumErrorsHandled() { ++num_errors_handled_; }
// Implement the IDBTransaction IDL
const String& mode() const;
@@ -128,6 +130,7 @@ class MODULES_EXPORT IDBTransaction final
DOMException* error() const { return error_; }
IDBObjectStore* objectStore(const String& name, ExceptionState&);
void abort(ExceptionState&);
+ void commit(ExceptionState&);
void RegisterRequest(IDBRequest*);
void UnregisterRequest(IDBRequest*);
@@ -224,6 +227,7 @@ class MODULES_EXPORT IDBTransaction final
State state_ = kActive;
bool has_pending_activity_ = true;
+ int64_t num_errors_handled_ = 0;
Member<DOMException> error_;
HeapListHashSet<Member<IDBRequest>> request_list_;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl
index 7bf4f8f3e1e..4a09acb0f46 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl
@@ -46,8 +46,12 @@ enum IDBTransactionMode {
readonly attribute DOMException error;
// Methods
- [RaisesException] IDBObjectStore objectStore (DOMString name);
- [RaisesException] void abort ();
+ [RaisesException] IDBObjectStore objectStore(DOMString name);
+ [
+ RaisesException,
+ RuntimeEnabled=IDBTransactionCommit
+ ] void commit();
+ [RaisesException] void abort();
// Events
attribute EventHandler onabort;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
index 075397815ed..889759b1874 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
@@ -64,15 +64,13 @@ void DeactivateNewTransactions(v8::Isolate* isolate) {
class FakeIDBDatabaseCallbacks final : public IDBDatabaseCallbacks {
public:
static FakeIDBDatabaseCallbacks* Create() {
- return new FakeIDBDatabaseCallbacks();
+ return MakeGarbageCollected<FakeIDBDatabaseCallbacks>();
}
+ FakeIDBDatabaseCallbacks() = default;
void OnVersionChange(int64_t old_version, int64_t new_version) override {}
void OnForcedClose() override {}
void OnAbort(int64_t transaction_id, DOMException* error) override {}
void OnComplete(int64_t transaction_id) override {}
-
- private:
- FakeIDBDatabaseCallbacks() = default;
};
class IDBTransactionTest : public testing::Test {
@@ -80,7 +78,7 @@ class IDBTransactionTest : public testing::Test {
void SetUp() override {
url_loader_mock_factory_ = platform_->GetURLLoaderMockFactory();
WebURLResponse response;
- response.SetURL(KURL("blob:"));
+ response.SetCurrentRequestUrl(KURL("blob:"));
url_loader_mock_factory_->RegisterURLProtocol(WebString("blob"), response,
"");
}
@@ -326,7 +324,7 @@ TEST_F(IDBTransactionTest, DocumentShutdownWithQueuedAndBlockedResults) {
TEST_F(IDBTransactionTest, TransactionFinish) {
V8TestingScope scope;
std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create();
- EXPECT_CALL(*backend, Commit(kTransactionId)).Times(1);
+ EXPECT_CALL(*backend, Commit(kTransactionId, 0)).Times(1);
EXPECT_CALL(*backend, Close()).Times(1);
BuildTransaction(scope, std::move(backend));
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc
index 21626735dde..74a851e38f5 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc
@@ -9,7 +9,6 @@
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
@@ -18,44 +17,18 @@
namespace blink {
-IDBValue::IDBValue(const WebData& data,
- const WebVector<WebBlobInfo>& web_blob_info)
- : data_(data) {
- blob_info_.ReserveInitialCapacity(SafeCast<wtf_size_t>(web_blob_info.size()));
-
- for (const WebBlobInfo& info : web_blob_info) {
- blob_info_.push_back(info);
- }
-}
-
-IDBValue::IDBValue(scoped_refptr<SharedBuffer> unwrapped_data,
+IDBValue::IDBValue(scoped_refptr<SharedBuffer> data,
Vector<WebBlobInfo> blob_info)
- : data_(std::move(unwrapped_data)),
- blob_info_(std::move(blob_info)) {
-}
+ : data_(std::move(data)), blob_info_(std::move(blob_info)) {}
IDBValue::~IDBValue() {
-#if DCHECK_IS_ON()
- DCHECK_EQ(!!is_owned_by_web_idb_value_, !isolate_)
- << "IDBValues shold have associated isolates if and only if not owned by "
- "an WebIDBValue";
-#endif // DCHECK_IS_ON()
-
if (isolate_ && external_allocated_size_)
isolate_->AdjustAmountOfExternalAllocatedMemory(-external_allocated_size_);
}
-std::unique_ptr<IDBValue> IDBValue::Create(
- const WebData& data,
- const WebVector<WebBlobInfo>& web_blob_info) {
- return base::WrapUnique(new IDBValue(data, web_blob_info));
-}
-
-std::unique_ptr<IDBValue> IDBValue::Create(
- scoped_refptr<SharedBuffer> unwrapped_data,
- Vector<WebBlobInfo> blob_info) {
- return base::WrapUnique(
- new IDBValue(std::move(unwrapped_data), std::move(blob_info)));
+std::unique_ptr<IDBValue> IDBValue::Create(scoped_refptr<SharedBuffer> data,
+ Vector<WebBlobInfo> blob_info) {
+ return base::WrapUnique(new IDBValue(std::move(data), std::move(blob_info)));
}
scoped_refptr<SerializedScriptValue> IDBValue::CreateSerializedValue() const {
@@ -70,11 +43,6 @@ void IDBValue::SetIsolate(v8::Isolate* isolate) {
DCHECK(isolate);
DCHECK(!isolate_) << "SetIsolate must be called at most once";
-#if DCHECK_IS_ON()
- DCHECK(!is_owned_by_web_idb_value_)
- << "IDBValues owned by an WebIDBValue cannot have associated isolates";
-#endif // DCHECK_IS_ON()
-
isolate_ = isolate;
external_allocated_size_ = data_ ? static_cast<int64_t>(data_->size()) : 0l;
if (external_allocated_size_)
@@ -105,14 +73,4 @@ scoped_refptr<BlobDataHandle> IDBValue::TakeLastBlob() {
return return_value;
}
-#if DCHECK_IS_ON()
-
-void IDBValue::SetIsOwnedByWebIDBValue(bool is_owned_by_web_idb_value) {
- DCHECK(!isolate_ || !is_owned_by_web_idb_value)
- << "IDBValues owned by an WebIDBValue cannot have associated isolates";
- is_owned_by_web_idb_value_ = is_owned_by_web_idb_value;
-}
-
-#endif // DCHECK_IS_ON()
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
index fd54d85d966..f5ffd05c64a 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
@@ -9,7 +9,6 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -20,7 +19,6 @@ namespace blink {
class BlobDataHandle;
class SerializedScriptValue;
class WebBlobInfo;
-class WebIDBValue;
// Represents an IndexedDB Object Store value retrieved from the backing store.
//
@@ -38,14 +36,8 @@ class WebIDBValue;
// the values before returning them to the user.
class MODULES_EXPORT IDBValue final {
public:
- // Creates an IDBValue from backing store information.
- static std::unique_ptr<IDBValue> Create(const WebData&,
- const WebVector<WebBlobInfo>&);
-
- // Used by IDBValueUnwrapper tests.
- static std::unique_ptr<IDBValue> Create(
- scoped_refptr<SharedBuffer> unwrapped_data,
- Vector<WebBlobInfo>);
+ static std::unique_ptr<IDBValue> Create(scoped_refptr<SharedBuffer>,
+ Vector<WebBlobInfo>);
~IDBValue();
@@ -54,12 +46,16 @@ class MODULES_EXPORT IDBValue final {
bool IsNull() const;
scoped_refptr<SerializedScriptValue> CreateSerializedValue() const;
const Vector<WebBlobInfo>& BlobInfo() const { return blob_info_; }
+ const scoped_refptr<SharedBuffer>& Data() const { return data_; }
const IDBKey* PrimaryKey() const { return primary_key_.get(); }
const IDBKeyPath& KeyPath() const { return key_path_; }
// Injects a primary key into a value coming from the backend.
void SetInjectedPrimaryKey(std::unique_ptr<IDBKey> primary_key,
IDBKeyPath primary_key_path) {
+ // If the given key is type Null, ignore it.
+ if (primary_key && primary_key->GetType() == mojom::IDBKeyType::Null)
+ primary_key.reset();
primary_key_ = std::move(primary_key);
key_path_ = std::move(primary_key_path);
}
@@ -84,19 +80,12 @@ class MODULES_EXPORT IDBValue final {
// last Blob from an IDBValue is used when unwrapping values.
scoped_refptr<BlobDataHandle> TakeLastBlob();
-#if DCHECK_IS_ON()
- // Called by WebIDBValue to inform IDBValue of owneship changes.
- void SetIsOwnedByWebIDBValue(bool);
-#endif // DCHECK_IS_ON()
-
private:
DISALLOW_COPY_AND_ASSIGN(IDBValue);
friend class IDBValueUnwrapper;
- IDBValue(const WebData&, const WebVector<WebBlobInfo>&);
- IDBValue(scoped_refptr<SharedBuffer> unwrapped_data,
- Vector<WebBlobInfo>);
+ IDBValue(scoped_refptr<SharedBuffer>, Vector<WebBlobInfo>);
// Keep this private to prevent new refs because we manually bookkeep the
// memory to V8.
@@ -107,18 +96,11 @@ class MODULES_EXPORT IDBValue final {
std::unique_ptr<IDBKey> primary_key_;
IDBKeyPath key_path_;
- // Used to register memory externally allocated by the WebIDBValue, and to
+ // Used to register memory externally allocated by the IDBValue, and to
// unregister that memory in the destructor. Unused in other construction
// paths.
v8::Isolate* isolate_ = nullptr;
int64_t external_allocated_size_ = 0;
-#if DCHECK_IS_ON()
- // True if the IDBValue is owned by a WebIDBValue.
- //
- // IDBValue instances that are not owned by WebIDBValue are owned by Blink
- // objects, and must have a V8 isolate associated with them.
- bool is_owned_by_web_idb_value_ = false;
-#endif // DCHECK_IS_ON()
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc
index f78b2600392..f06e7ce3417 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc
@@ -483,23 +483,24 @@ TEST(IDBValueUnwrapperTest, IsWrapped) {
scoped_refptr<SharedBuffer> wrapped_marker_buffer = wrapper.TakeWireBytes();
IDBKeyPath key_path(String("primaryKey"));
- std::unique_ptr<IDBValue> wrapped_value =
- IDBValue::Create(wrapped_marker_buffer, blob_infos);
- wrapped_value->SetIsolate(scope.GetIsolate());
- EXPECT_TRUE(IDBValueUnwrapper::IsWrapped(wrapped_value.get()));
-
Vector<char> wrapped_marker_bytes(
static_cast<wtf_size_t>(wrapped_marker_buffer->size()));
ASSERT_TRUE(wrapped_marker_buffer->GetBytes(wrapped_marker_bytes.data(),
wrapped_marker_bytes.size()));
+ std::unique_ptr<IDBValue> wrapped_value =
+ IDBValue::Create(std::move(wrapped_marker_buffer), std::move(blob_infos));
+ wrapped_value->SetIsolate(scope.GetIsolate());
+ EXPECT_TRUE(IDBValueUnwrapper::IsWrapped(wrapped_value.get()));
+
// IsWrapped() looks at the first 3 bytes in the value's byte array.
// Truncating the array to fewer than 3 bytes should cause IsWrapped() to
// return false.
ASSERT_LT(3U, wrapped_marker_bytes.size());
for (wtf_size_t i = 0; i < 3; ++i) {
- std::unique_ptr<IDBValue> mutant_value = IDBValue::Create(
- SharedBuffer::Create(wrapped_marker_bytes.data(), i), blob_infos);
+ std::unique_ptr<IDBValue> mutant_value =
+ IDBValue::Create(SharedBuffer::Create(wrapped_marker_bytes.data(), i),
+ std::move(blob_infos));
mutant_value->SetIsolate(scope.GetIsolate());
EXPECT_FALSE(IDBValueUnwrapper::IsWrapped(mutant_value.get()));
@@ -515,7 +516,7 @@ TEST(IDBValueUnwrapperTest, IsWrapped) {
std::unique_ptr<IDBValue> mutant_value =
IDBValue::Create(SharedBuffer::Create(wrapped_marker_bytes.data(),
wrapped_marker_bytes.size()),
- blob_infos);
+ std::move(blob_infos));
mutant_value->SetIsolate(scope.GetIsolate());
EXPECT_FALSE(IDBValueUnwrapper::IsWrapped(mutant_value.get()));
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink.typemap b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink.typemap
index fd306fa458d..536050efa78 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink.typemap
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink.typemap
@@ -5,18 +5,15 @@
mojom = "//third_party/blink/public/mojom/indexeddb/indexeddb.mojom"
public_headers = [
"//third_party/blink/public/common/indexeddb/web_idb_types.h",
- "//third_party/blink/public/platform/modules/indexeddb/web_idb_key.h",
- "//third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h",
- "//third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h",
- "//third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h",
- "//third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h",
+ "//third_party/blink/renderer/modules/indexeddb/idb_key_path.h",
"//third_party/blink/renderer/modules/indexeddb/idb_key_range.h",
+ "//third_party/blink/renderer/modules/indexeddb/idb_metadata.h",
+ "//third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h",
+ "//third_party/blink/renderer/modules/indexeddb/idb_value.h",
]
traits_headers = [
"//mojo/public/cpp/base/string16_mojom_traits.h",
- "//mojo/public/cpp/bindings/array_traits_web_vector.h",
"//mojo/public/cpp/bindings/array_traits_wtf_vector.h",
- "//third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h",
"//third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h",
"//third_party/blink/renderer/platform/mojo/string16_mojom_traits.h",
]
@@ -25,11 +22,11 @@ deps = [
"//third_party/blink/renderer/platform/wtf",
]
type_mappings = [
- "blink.mojom.IDBDatabaseMetadata=::blink::WebIDBMetadata",
- "blink.mojom.IDBIndexKeys=::blink::WebIDBIndexKeys",
- "blink.mojom.IDBIndexMetadata=::blink::WebIDBMetadata::Index",
- "blink.mojom.IDBKey=::blink::WebIDBKey[move_only]",
- "blink.mojom.IDBKeyPath=::blink::WebIDBKeyPath",
- "blink.mojom.IDBKeyRange=::blink::WebIDBKeyRange",
- "blink.mojom.IDBObjectStoreMetadata=::blink::WebIDBMetadata::ObjectStore",
+ "blink.mojom.IDBDatabaseMetadata=::blink::IDBDatabaseMetadata",
+ "blink.mojom.IDBIndexKeys=::blink::IDBIndexKeys[move_only]",
+ "blink.mojom.IDBIndexMetadata=scoped_refptr<::blink::IDBIndexMetadata>",
+ "blink.mojom.IDBKey=std::unique_ptr<::blink::IDBKey>[move_only]",
+ "blink.mojom.IDBKeyPath=::blink::IDBKeyPath",
+ "blink.mojom.IDBObjectStoreMetadata=scoped_refptr<::blink::IDBObjectStoreMetadata>",
+ "blink.mojom.IDBValue=std::unique_ptr<::blink::IDBValue>[move_only]",
]
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
index 280c6462210..4e253d1816a 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
@@ -5,12 +5,9 @@
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
#include "base/stl_util.h"
-#include "mojo/public/cpp/bindings/array_traits_web_vector.h"
#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
-#include "third_party/blink/public/common/indexeddb/indexed_db_default_mojom_traits.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
+#include "third_party/blink/public/platform/file_path_conversion.h"
+#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/platform/mojo/string16_mojom_traits.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -23,10 +20,10 @@ using blink::mojom::IDBOperationType;
namespace mojo {
// static
-bool StructTraits<
- blink::mojom::IDBDatabaseMetadataDataView,
- blink::WebIDBMetadata>::Read(blink::mojom::IDBDatabaseMetadataDataView data,
- blink::WebIDBMetadata* out) {
+bool StructTraits<blink::mojom::IDBDatabaseMetadataDataView,
+ blink::IDBDatabaseMetadata>::
+ Read(blink::mojom::IDBDatabaseMetadataDataView data,
+ blink::IDBDatabaseMetadata* out) {
out->id = data.id();
String name;
if (!data.ReadName(&name))
@@ -34,14 +31,26 @@ bool StructTraits<
out->name = name;
out->version = data.version();
out->max_object_store_id = data.max_object_store_id();
- if (!data.ReadObjectStores(&out->object_stores))
- return false;
+ MapDataView<int64_t, blink::mojom::IDBObjectStoreMetadataDataView>
+ object_stores;
+ data.GetObjectStoresDataView(&object_stores);
+ out->object_stores.ReserveCapacityForSize(
+ SafeCast<wtf_size_t>(object_stores.size()));
+ for (size_t i = 0; i < object_stores.size(); ++i) {
+ const int64_t key = object_stores.keys()[i];
+ scoped_refptr<blink::IDBObjectStoreMetadata> object_store;
+ if (!object_stores.values().Read(i, &object_store)) {
+ return false;
+ }
+ DCHECK(!out->object_stores.Contains(key));
+ out->object_stores.insert(key, object_store);
+ }
return true;
}
// static
-bool StructTraits<blink::mojom::IDBIndexKeysDataView, blink::WebIDBIndexKeys>::
- Read(blink::mojom::IDBIndexKeysDataView data, blink::WebIDBIndexKeys* out) {
+bool StructTraits<blink::mojom::IDBIndexKeysDataView, blink::IDBIndexKeys>::
+ Read(blink::mojom::IDBIndexKeysDataView data, blink::IDBIndexKeys* out) {
out->first = data.index_id();
if (!data.ReadIndexKeys(&out->second))
return false;
@@ -50,69 +59,69 @@ bool StructTraits<blink::mojom::IDBIndexKeysDataView, blink::WebIDBIndexKeys>::
// static
bool StructTraits<blink::mojom::IDBIndexMetadataDataView,
- blink::WebIDBMetadata::Index>::
+ scoped_refptr<blink::IDBIndexMetadata>>::
Read(blink::mojom::IDBIndexMetadataDataView data,
- blink::WebIDBMetadata::Index* out) {
- out->id = data.id();
+ scoped_refptr<blink::IDBIndexMetadata>* out) {
+ scoped_refptr<blink::IDBIndexMetadata> value =
+ blink::IDBIndexMetadata::Create();
+ value->id = data.id();
String name;
if (!data.ReadName(&name))
return false;
- out->name = name;
- if (!data.ReadKeyPath(&out->key_path))
+ value->name = name;
+ if (!data.ReadKeyPath(&value->key_path))
return false;
- out->unique = data.unique();
- out->multi_entry = data.multi_entry();
+ value->unique = data.unique();
+ value->multi_entry = data.multi_entry();
+ *out = std::move(value);
return true;
}
// static
blink::mojom::IDBKeyDataDataView::Tag
-UnionTraits<blink::mojom::IDBKeyDataDataView, blink::WebIDBKey>::GetTag(
- const blink::WebIDBKey& key) {
- switch (key.View().KeyType()) {
- case blink::kWebIDBKeyTypeInvalid:
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER;
- case blink::kWebIDBKeyTypeArray:
+UnionTraits<blink::mojom::IDBKeyDataDataView, std::unique_ptr<blink::IDBKey>>::
+ GetTag(const std::unique_ptr<blink::IDBKey>& key) {
+ DCHECK(key.get());
+ switch (key->GetType()) {
+ case blink::mojom::IDBKeyType::Invalid:
+ return blink::mojom::IDBKeyDataDataView::Tag::OTHER_INVALID;
+ case blink::mojom::IDBKeyType::Array:
return blink::mojom::IDBKeyDataDataView::Tag::KEY_ARRAY;
- case blink::kWebIDBKeyTypeBinary:
+ case blink::mojom::IDBKeyType::Binary:
return blink::mojom::IDBKeyDataDataView::Tag::BINARY;
- case blink::kWebIDBKeyTypeString:
+ case blink::mojom::IDBKeyType::String:
return blink::mojom::IDBKeyDataDataView::Tag::STRING;
- case blink::kWebIDBKeyTypeDate:
+ case blink::mojom::IDBKeyType::Date:
return blink::mojom::IDBKeyDataDataView::Tag::DATE;
- case blink::kWebIDBKeyTypeNumber:
+ case blink::mojom::IDBKeyType::Number:
return blink::mojom::IDBKeyDataDataView::Tag::NUMBER;
- case blink::kWebIDBKeyTypeNull:
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER;
+ case blink::mojom::IDBKeyType::Null:
+ return blink::mojom::IDBKeyDataDataView::Tag::OTHER_NULL;
// Not used, fall through to NOTREACHED.
- case blink::kWebIDBKeyTypeMin:;
+ case blink::mojom::IDBKeyType::Min:;
}
NOTREACHED();
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER;
+ return blink::mojom::IDBKeyDataDataView::Tag::OTHER_INVALID;
}
// static
-bool UnionTraits<blink::mojom::IDBKeyDataDataView, blink::WebIDBKey>::Read(
- blink::mojom::IDBKeyDataDataView data,
- blink::WebIDBKey* out) {
+bool UnionTraits<
+ blink::mojom::IDBKeyDataDataView,
+ std::unique_ptr<blink::IDBKey>>::Read(blink::mojom::IDBKeyDataDataView data,
+ std::unique_ptr<blink::IDBKey>* out) {
switch (data.tag()) {
case blink::mojom::IDBKeyDataDataView::Tag::KEY_ARRAY: {
- Vector<blink::WebIDBKey> array;
+ Vector<std::unique_ptr<blink::IDBKey>> array;
if (!data.ReadKeyArray(&array))
return false;
- blink::WebVector<blink::WebIDBKey> webvector_array;
- for (const auto& item : array) {
- webvector_array.emplace_back(
- blink::WebIDBKeyBuilder::Build(item.View()));
- }
- *out = blink::WebIDBKey::CreateArray(std::move(webvector_array));
+ *out = blink::IDBKey::CreateArray(std::move(array));
return true;
}
case blink::mojom::IDBKeyDataDataView::Tag::BINARY: {
ArrayDataView<uint8_t> bytes;
data.GetBinaryDataView(&bytes);
- *out = blink::WebIDBKey::CreateBinary(blink::WebData(
+ *out = blink::IDBKey::CreateBinary(blink::SharedBuffer::Create(
reinterpret_cast<const char*>(bytes.data()), bytes.size()));
return true;
}
@@ -120,92 +129,153 @@ bool UnionTraits<blink::mojom::IDBKeyDataDataView, blink::WebIDBKey>::Read(
String string;
if (!data.ReadString(&string))
return false;
- *out = blink::WebIDBKey::CreateString(blink::WebString(string));
+ *out = blink::IDBKey::CreateString(String(string));
return true;
}
case blink::mojom::IDBKeyDataDataView::Tag::DATE:
- *out = blink::WebIDBKey::CreateDate(data.date());
+ *out = blink::IDBKey::CreateDate(data.date());
return true;
case blink::mojom::IDBKeyDataDataView::Tag::NUMBER:
- *out = blink::WebIDBKey::CreateNumber(data.number());
+ *out = blink::IDBKey::CreateNumber(data.number());
+ return true;
+ case blink::mojom::IDBKeyDataDataView::Tag::OTHER_INVALID:
+ *out = blink::IDBKey::CreateInvalid();
+ return true;
+ case blink::mojom::IDBKeyDataDataView::Tag::OTHER_NULL:
+ *out = blink::IDBKey::CreateNull();
return true;
- case blink::mojom::IDBKeyDataDataView::Tag::OTHER:
- switch (data.other()) {
- case blink::mojom::IDBDatalessKeyType::Invalid:
- *out = blink::WebIDBKey::CreateInvalid();
- return true;
- case blink::mojom::IDBDatalessKeyType::Null:
- *out = blink::WebIDBKey::CreateNull();
- return true;
- }
}
return false;
}
// static
-const blink::WebVector<blink::WebIDBKey>
-UnionTraits<blink::mojom::IDBKeyDataDataView, blink::WebIDBKey>::key_array(
- const blink::WebIDBKey& key) {
- const auto& array_view = key.View().ArrayView();
- const size_t array_size = array_view.size();
- Vector<blink::WebIDBKey> result;
- result.ReserveInitialCapacity(SafeCast<wtf_size_t>(array_view.size()));
- // |array_view| is of type WebIDBKeyArrayView which only implements size()
- // and operator[]. Since it doesn't have other typical array functions, we
- // must use an iterator-style for loop.
- for (size_t i = 0; i < array_size; ++i)
- result.emplace_back(blink::WebIDBKeyBuilder::Build(array_view[i]));
- return result;
+const Vector<std::unique_ptr<blink::IDBKey>>&
+UnionTraits<blink::mojom::IDBKeyDataDataView, std::unique_ptr<blink::IDBKey>>::
+ key_array(const std::unique_ptr<blink::IDBKey>& key) {
+ return key->Array();
}
// static
-const Vector<uint8_t>
-UnionTraits<blink::mojom::IDBKeyDataDataView, blink::WebIDBKey>::binary(
- const blink::WebIDBKey& key) {
- const auto& data = key.View().Binary();
- Vector<uint8_t> result;
- result.ReserveInitialCapacity(SafeCast<wtf_size_t>(data.size()));
- data.ForEachSegment([&result](const char* segment, size_t segment_size,
- size_t segment_offset) {
- const auto& segment_span = base::make_span(segment, segment + segment_size);
- result.AppendRange(segment_span.begin(), segment_span.end());
- return true;
- });
- return result;
+Vector<uint8_t>
+UnionTraits<blink::mojom::IDBKeyDataDataView, std::unique_ptr<blink::IDBKey>>::
+ binary(const std::unique_ptr<blink::IDBKey>& key) {
+ return key->Binary()->CopyAs<Vector<uint8_t>>();
}
// static
-const blink::WebIDBKey&
-StructTraits<blink::mojom::IDBKeyDataView, blink::WebIDBKey>::data(
- const blink::WebIDBKey& key) {
+const std::unique_ptr<blink::IDBKey>&
+StructTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>>::
+ data(const std::unique_ptr<blink::IDBKey>& key) {
return key;
}
// static
-bool StructTraits<blink::mojom::IDBKeyDataView, blink::WebIDBKey>::Read(
- blink::mojom::IDBKeyDataView data,
- blink::WebIDBKey* out) {
+bool StructTraits<
+ blink::mojom::IDBKeyDataView,
+ std::unique_ptr<blink::IDBKey>>::Read(blink::mojom::IDBKeyDataView data,
+ std::unique_ptr<blink::IDBKey>* out) {
return data.ReadData(out);
}
// static
+Vector<uint8_t>
+StructTraits<blink::mojom::IDBValueDataView, std::unique_ptr<blink::IDBValue>>::
+ bits(const std::unique_ptr<blink::IDBValue>& input) {
+ return input->Data()->CopyAs<Vector<uint8_t>>();
+}
+
+// static
+Vector<blink::mojom::blink::IDBBlobInfoPtr>
+StructTraits<blink::mojom::IDBValueDataView, std::unique_ptr<blink::IDBValue>>::
+ blob_or_file_info(const std::unique_ptr<blink::IDBValue>& input) {
+ Vector<blink::mojom::blink::IDBBlobInfoPtr> blob_or_file_info;
+ blob_or_file_info.ReserveInitialCapacity(input->BlobInfo().size());
+ for (const blink::WebBlobInfo& info : input->BlobInfo()) {
+ auto blob_info = blink::mojom::blink::IDBBlobInfo::New();
+ if (info.IsFile()) {
+ blob_info->file = blink::mojom::blink::IDBFileInfo::New();
+ blob_info->file->path = blink::WebStringToFilePath(info.FilePath());
+ String name = info.FileName();
+ if (name.IsNull())
+ name = g_empty_string;
+ blob_info->file->name = name;
+ blob_info->file->last_modified =
+ base::Time::FromDoubleT(info.LastModified());
+ }
+ blob_info->size = info.size();
+ blob_info->uuid = info.Uuid();
+ DCHECK(!blob_info->uuid.IsEmpty());
+ String mime_type = info.GetType();
+ if (mime_type.IsNull())
+ mime_type = g_empty_string;
+ blob_info->mime_type = mime_type;
+ blob_info->blob = blink::mojom::blink::BlobPtrInfo(
+ info.CloneBlobHandle(), blink::mojom::blink::Blob::Version_);
+ blob_or_file_info.push_back(std::move(blob_info));
+ }
+ return blob_or_file_info;
+}
+
+// static
+bool StructTraits<blink::mojom::IDBValueDataView,
+ std::unique_ptr<blink::IDBValue>>::
+ Read(blink::mojom::IDBValueDataView data,
+ std::unique_ptr<blink::IDBValue>* out) {
+ Vector<uint8_t> value_bits;
+ if (!data.ReadBits(&value_bits))
+ return false;
+
+ if (value_bits.IsEmpty()) {
+ *out = blink::IDBValue::Create(scoped_refptr<blink::SharedBuffer>(),
+ Vector<blink::WebBlobInfo>());
+ return true;
+ }
+
+ scoped_refptr<blink::SharedBuffer> value_buffer = blink::SharedBuffer::Create(
+ reinterpret_cast<const char*>(value_bits.data()), value_bits.size());
+
+ Vector<blink::mojom::blink::IDBBlobInfoPtr> blob_or_file_info;
+ if (!data.ReadBlobOrFileInfo(&blob_or_file_info))
+ return false;
+
+ Vector<blink::WebBlobInfo> value_blob_info;
+ value_blob_info.ReserveInitialCapacity(blob_or_file_info.size());
+ for (const auto& info : blob_or_file_info) {
+ if (info->file) {
+ value_blob_info.emplace_back(info->uuid,
+ blink::FilePathToWebString(info->file->path),
+ info->file->name, info->mime_type,
+ info->file->last_modified.ToDoubleT(),
+ info->size, info->blob.PassHandle());
+ } else {
+ value_blob_info.emplace_back(info->uuid, info->mime_type, info->size,
+ info->blob.PassHandle());
+ }
+ }
+
+ *out = blink::IDBValue::Create(std::move(value_buffer),
+ std::move(value_blob_info));
+ return true;
+}
+
+// static
blink::mojom::blink::IDBKeyPathDataPtr
-StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath>::data(
- const blink::WebIDBKeyPath& key_path) {
- if (key_path.KeyPathType() == blink::kWebIDBKeyPathTypeNull)
+StructTraits<blink::mojom::IDBKeyPathDataView, blink::IDBKeyPath>::data(
+ const blink::IDBKeyPath& key_path) {
+ if (key_path.GetType() == blink::mojom::IDBKeyPathType::Null)
return nullptr;
auto data = blink::mojom::blink::IDBKeyPathData::New();
- switch (key_path.KeyPathType()) {
- case blink::kWebIDBKeyPathTypeString: {
- String key_path_string = key_path.String();
+ switch (key_path.GetType()) {
+ case blink::mojom::IDBKeyPathType::String: {
+ String key_path_string = key_path.GetString();
if (key_path_string.IsNull())
key_path_string = g_empty_string;
data->set_string(key_path_string);
return data;
}
- case blink::kWebIDBKeyPathTypeArray: {
+ case blink::mojom::IDBKeyPathType::Array: {
const auto& array = key_path.Array();
Vector<String> result;
result.ReserveInitialCapacity(SafeCast<wtf_size_t>(array.size()));
@@ -215,7 +285,7 @@ StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath>::data(
return data;
}
- case blink::kWebIDBKeyPathTypeNull:
+ case blink::mojom::IDBKeyPathType::Null:
break; // Not used, NOTREACHED.
}
NOTREACHED();
@@ -223,14 +293,14 @@ StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath>::data(
}
// static
-bool StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath>::Read(
+bool StructTraits<blink::mojom::IDBKeyPathDataView, blink::IDBKeyPath>::Read(
blink::mojom::IDBKeyPathDataView data,
- blink::WebIDBKeyPath* out) {
+ blink::IDBKeyPath* out) {
blink::mojom::IDBKeyPathDataDataView data_view;
data.GetDataDataView(&data_view);
if (data_view.is_null()) {
- *out = blink::WebIDBKeyPath();
+ *out = blink::IDBKeyPath();
return true;
}
@@ -239,14 +309,14 @@ bool StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath>::Read(
String string;
if (!data_view.ReadString(&string))
return false;
- *out = blink::WebIDBKeyPath(blink::WebString(string));
+ *out = blink::IDBKeyPath(string);
return true;
}
case blink::mojom::IDBKeyPathDataDataView::Tag::STRING_ARRAY: {
Vector<String> array;
if (!data_view.ReadStringArray(&array))
return false;
- *out = blink::WebIDBKeyPath(array);
+ *out = blink::IDBKeyPath(array);
return true;
}
}
@@ -255,37 +325,91 @@ bool StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath>::Read(
}
// static
-bool StructTraits<blink::mojom::IDBKeyRangeDataView, blink::WebIDBKeyRange>::
- Read(blink::mojom::IDBKeyRangeDataView data, blink::WebIDBKeyRange* out) {
- // TODO(cmp): Use WebIDBKey and WebIDBKeyRange directly.
- blink::IndexedDBKey lower;
- blink::IndexedDBKey upper;
- if (!data.ReadLower(&lower) || !data.ReadUpper(&upper))
- return false;
-
- blink::IndexedDBKeyRange temp(lower, upper, data.lower_open(),
- data.upper_open());
- *out = blink::WebIDBKeyRangeBuilder::Build(temp);
- return true;
-}
-
-// static
bool StructTraits<blink::mojom::IDBObjectStoreMetadataDataView,
- blink::WebIDBMetadata::ObjectStore>::
+ scoped_refptr<blink::IDBObjectStoreMetadata>>::
Read(blink::mojom::IDBObjectStoreMetadataDataView data,
- blink::WebIDBMetadata::ObjectStore* out) {
- out->id = data.id();
+ scoped_refptr<blink::IDBObjectStoreMetadata>* out) {
+ scoped_refptr<blink::IDBObjectStoreMetadata> value =
+ blink::IDBObjectStoreMetadata::Create();
+ value->id = data.id();
String name;
if (!data.ReadName(&name))
return false;
- out->name = name;
- if (!data.ReadKeyPath(&out->key_path))
- return false;
- out->auto_increment = data.auto_increment();
- out->max_index_id = data.max_index_id();
- if (!data.ReadIndexes(&out->indexes))
+ value->name = name;
+ if (!data.ReadKeyPath(&value->key_path))
return false;
+ value->auto_increment = data.auto_increment();
+ value->max_index_id = data.max_index_id();
+ MapDataView<int64_t, blink::mojom::IDBIndexMetadataDataView> indexes;
+ data.GetIndexesDataView(&indexes);
+ value->indexes.ReserveCapacityForSize(SafeCast<wtf_size_t>(indexes.size()));
+ for (size_t i = 0; i < indexes.size(); ++i) {
+ const int64_t key = indexes.keys()[i];
+ scoped_refptr<blink::IDBIndexMetadata> index;
+ if (!indexes.values().Read(i, &index))
+ return false;
+ DCHECK(!value->indexes.Contains(key));
+ value->indexes.insert(key, index);
+ }
+ *out = std::move(value);
return true;
}
+// static
+blink::mojom::blink::IDBKeyRangePtr TypeConverter<
+ blink::mojom::blink::IDBKeyRangePtr,
+ const blink::IDBKeyRange*>::Convert(const blink::IDBKeyRange* input) {
+ if (!input) {
+ std::unique_ptr<blink::IDBKey> lower = blink::IDBKey::CreateNull();
+ std::unique_ptr<blink::IDBKey> upper = blink::IDBKey::CreateNull();
+ return blink::mojom::blink::IDBKeyRange::New(
+ std::move(lower), std::move(upper), false /* lower_open */,
+ false /* upper_open */);
+ }
+
+ return blink::mojom::blink::IDBKeyRange::New(
+ blink::IDBKey::Clone(input->Lower()),
+ blink::IDBKey::Clone(input->Upper()), input->lowerOpen(),
+ input->upperOpen());
+}
+
+// static
+blink::mojom::blink::IDBKeyRangePtr
+TypeConverter<blink::mojom::blink::IDBKeyRangePtr,
+ blink::IDBKeyRange*>::Convert(blink::IDBKeyRange* input) {
+ if (!input) {
+ std::unique_ptr<blink::IDBKey> lower = blink::IDBKey::CreateNull();
+ std::unique_ptr<blink::IDBKey> upper = blink::IDBKey::CreateNull();
+ return blink::mojom::blink::IDBKeyRange::New(
+ std::move(lower), std::move(upper), false /* lower_open */,
+ false /* upper_open */);
+ }
+
+ return blink::mojom::blink::IDBKeyRange::New(
+ blink::IDBKey::Clone(input->Lower()),
+ blink::IDBKey::Clone(input->Upper()), input->lowerOpen(),
+ input->upperOpen());
+}
+
+// static
+blink::IDBKeyRange*
+TypeConverter<blink::IDBKeyRange*, blink::mojom::blink::IDBKeyRangePtr>::
+ Convert(const blink::mojom::blink::IDBKeyRangePtr& input) {
+ if (!input)
+ return nullptr;
+
+ blink::IDBKeyRange::LowerBoundType lower_type =
+ blink::IDBKeyRange::kLowerBoundClosed;
+ if (input->lower_open)
+ lower_type = blink::IDBKeyRange::kLowerBoundOpen;
+
+ blink::IDBKeyRange::UpperBoundType upper_type =
+ blink::IDBKeyRange::kUpperBoundClosed;
+ if (input->upper_open)
+ upper_type = blink::IDBKeyRange::kUpperBoundOpen;
+
+ return blink::IDBKeyRange::Create(
+ std::move(input->lower), std::move(input->upper), lower_type, upper_type);
+}
+
} // namespace mojo
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h
index 408631a1a40..946b20c78be 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h
@@ -7,15 +7,9 @@
#include <stdint.h>
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
+#include "mojo/public/cpp/bindings/map_traits_wtf_hash_map.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
-#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -23,163 +17,179 @@ namespace mojo {
template <>
struct MODULES_EXPORT StructTraits<blink::mojom::IDBDatabaseMetadataDataView,
- blink::WebIDBMetadata> {
- static int64_t id(const blink::WebIDBMetadata& metadata) {
+ blink::IDBDatabaseMetadata> {
+ static int64_t id(const blink::IDBDatabaseMetadata& metadata) {
return metadata.id;
}
- static WTF::String name(const blink::WebIDBMetadata& metadata) {
+ static WTF::String name(const blink::IDBDatabaseMetadata& metadata) {
if (metadata.name.IsNull())
return g_empty_string;
return metadata.name;
}
- static int64_t version(const blink::WebIDBMetadata& metadata) {
+ static int64_t version(const blink::IDBDatabaseMetadata& metadata) {
return metadata.version;
}
- static int64_t max_object_store_id(const blink::WebIDBMetadata& metadata) {
+ static int64_t max_object_store_id(
+ const blink::IDBDatabaseMetadata& metadata) {
return metadata.max_object_store_id;
}
- static const blink::WebVector<blink::WebIDBMetadata::ObjectStore>&
- object_stores(const blink::WebIDBMetadata& metadata) {
+ static const HashMap<int64_t, scoped_refptr<blink::IDBObjectStoreMetadata>>&
+ object_stores(const blink::IDBDatabaseMetadata& metadata) {
return metadata.object_stores;
}
static bool Read(blink::mojom::IDBDatabaseMetadataDataView data,
- blink::WebIDBMetadata* out);
+ blink::IDBDatabaseMetadata* out);
};
template <>
struct MODULES_EXPORT
- StructTraits<blink::mojom::IDBIndexKeysDataView, blink::WebIDBIndexKeys> {
- static int64_t index_id(const blink::WebIDBIndexKeys& index_keys) {
+ StructTraits<blink::mojom::IDBIndexKeysDataView, blink::IDBIndexKeys> {
+ static int64_t index_id(const blink::IDBIndexKeys& index_keys) {
return index_keys.first;
}
- static const blink::WebVector<blink::WebIDBKey>& index_keys(
- const blink::WebIDBIndexKeys& index_keys) {
+ static const Vector<std::unique_ptr<blink::IDBKey>>& index_keys(
+ const blink::IDBIndexKeys& index_keys) {
return index_keys.second;
}
static bool Read(blink::mojom::IDBIndexKeysDataView data,
- blink::WebIDBIndexKeys* out);
+ blink::IDBIndexKeys* out);
};
template <>
struct MODULES_EXPORT StructTraits<blink::mojom::IDBIndexMetadataDataView,
- blink::WebIDBMetadata::Index> {
- static int64_t id(const blink::WebIDBMetadata::Index& metadata) {
- return metadata.id;
+ scoped_refptr<blink::IDBIndexMetadata>> {
+ static int64_t id(const scoped_refptr<blink::IDBIndexMetadata>& metadata) {
+ return metadata->id;
}
- static WTF::String name(const blink::WebIDBMetadata::Index& metadata) {
- if (metadata.name.IsNull())
+ static WTF::String name(
+ const scoped_refptr<blink::IDBIndexMetadata>& metadata) {
+ if (metadata->name.IsNull())
return g_empty_string;
- return metadata.name;
+ return metadata->name;
}
- static const blink::WebIDBKeyPath& key_path(
- const blink::WebIDBMetadata::Index& metadata) {
- return metadata.key_path;
+ static const blink::IDBKeyPath& key_path(
+ const scoped_refptr<blink::IDBIndexMetadata>& metadata) {
+ return metadata->key_path;
}
- static bool unique(const blink::WebIDBMetadata::Index& metadata) {
- return metadata.unique;
+ static bool unique(const scoped_refptr<blink::IDBIndexMetadata>& metadata) {
+ return metadata->unique;
}
- static bool multi_entry(const blink::WebIDBMetadata::Index& metadata) {
- return metadata.multi_entry;
+ static bool multi_entry(
+ const scoped_refptr<blink::IDBIndexMetadata>& metadata) {
+ return metadata->multi_entry;
}
static bool Read(blink::mojom::IDBIndexMetadataDataView data,
- blink::WebIDBMetadata::Index* out);
+ scoped_refptr<blink::IDBIndexMetadata>* out);
};
template <>
-struct MODULES_EXPORT
- UnionTraits<blink::mojom::IDBKeyDataDataView, blink::WebIDBKey> {
+struct MODULES_EXPORT UnionTraits<blink::mojom::IDBKeyDataDataView,
+ std::unique_ptr<blink::IDBKey>> {
static blink::mojom::IDBKeyDataDataView::Tag GetTag(
- const blink::WebIDBKey& key);
+ const std::unique_ptr<blink::IDBKey>& key);
static bool Read(blink::mojom::IDBKeyDataDataView data,
- blink::WebIDBKey* out);
- static const blink::WebVector<blink::WebIDBKey> key_array(
- const blink::WebIDBKey& key);
- static const Vector<uint8_t> binary(const blink::WebIDBKey& key);
- static const WTF::String string(const blink::WebIDBKey& key) {
- String key_string = key.View().String();
+ std::unique_ptr<blink::IDBKey>* out);
+ static const Vector<std::unique_ptr<blink::IDBKey>>& key_array(
+ const std::unique_ptr<blink::IDBKey>& key);
+ static Vector<uint8_t> binary(const std::unique_ptr<blink::IDBKey>& key);
+ static const WTF::String string(const std::unique_ptr<blink::IDBKey>& key) {
+ String key_string = key->GetString();
if (key_string.IsNull())
key_string = g_empty_string;
return key_string;
}
- static double date(const blink::WebIDBKey& key) { return key.View().Date(); }
- static double number(const blink::WebIDBKey& key) {
- return key.View().Number();
- }
- static blink::mojom::IDBDatalessKeyType other(const blink::WebIDBKey& key) {
- switch (key.View().KeyType()) {
- case blink::kWebIDBKeyTypeInvalid:
- return blink::mojom::IDBDatalessKeyType::Invalid;
- case blink::kWebIDBKeyTypeNull:
- return blink::mojom::IDBDatalessKeyType::Null;
- default:
- NOTREACHED();
- return blink::mojom::IDBDatalessKeyType::Invalid;
- }
+ static double date(const std::unique_ptr<blink::IDBKey>& key) {
+ return key->Date();
+ }
+ static double number(const std::unique_ptr<blink::IDBKey>& key) {
+ return key->Number();
+ }
+ static bool other_invalid(const std::unique_ptr<blink::IDBKey>& key) {
+ return key->GetType() == blink::mojom::IDBKeyType::Invalid;
+ }
+ static bool other_null(const std::unique_ptr<blink::IDBKey>& key) {
+ return key->GetType() == blink::mojom::IDBKeyType::Null;
}
};
template <>
struct MODULES_EXPORT
- StructTraits<blink::mojom::IDBKeyDataView, blink::WebIDBKey> {
- static const blink::WebIDBKey& data(const blink::WebIDBKey& key);
- static bool Read(blink::mojom::IDBKeyDataView data, blink::WebIDBKey* out);
+ StructTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>> {
+ static const std::unique_ptr<blink::IDBKey>& data(
+ const std::unique_ptr<blink::IDBKey>& key);
+ static bool Read(blink::mojom::IDBKeyDataView data,
+ std::unique_ptr<blink::IDBKey>* out);
};
template <>
-struct MODULES_EXPORT
- StructTraits<blink::mojom::IDBKeyPathDataView, blink::WebIDBKeyPath> {
- static blink::mojom::blink::IDBKeyPathDataPtr data(
- const blink::WebIDBKeyPath& key_path);
- static bool Read(blink::mojom::IDBKeyPathDataView data,
- blink::WebIDBKeyPath* out);
+struct MODULES_EXPORT StructTraits<blink::mojom::IDBValueDataView,
+ std::unique_ptr<blink::IDBValue>> {
+ static Vector<uint8_t> bits(const std::unique_ptr<blink::IDBValue>& input);
+ static Vector<blink::mojom::blink::IDBBlobInfoPtr> blob_or_file_info(
+ const std::unique_ptr<blink::IDBValue>& input);
+ static bool Read(blink::mojom::IDBValueDataView data,
+ std::unique_ptr<blink::IDBValue>* out);
};
template <>
struct MODULES_EXPORT
- StructTraits<blink::mojom::IDBKeyRangeDataView, blink::WebIDBKeyRange> {
- static blink::WebIDBKey lower(const blink::WebIDBKeyRange& key_range) {
- return blink::WebIDBKeyBuilder::Build(key_range.Lower());
- }
- static blink::WebIDBKey upper(const blink::WebIDBKeyRange& key_range) {
- return blink::WebIDBKeyBuilder::Build(key_range.Upper());
- }
- static bool lower_open(const blink::WebIDBKeyRange& key_range) {
- return key_range.LowerOpen();
- }
- static bool upper_open(const blink::WebIDBKeyRange& key_range) {
- return key_range.UpperOpen();
- }
- static bool Read(blink::mojom::IDBKeyRangeDataView data,
- blink::WebIDBKeyRange* out);
+ StructTraits<blink::mojom::IDBKeyPathDataView, blink::IDBKeyPath> {
+ static blink::mojom::blink::IDBKeyPathDataPtr data(
+ const blink::IDBKeyPath& key_path);
+ static bool Read(blink::mojom::IDBKeyPathDataView data,
+ blink::IDBKeyPath* out);
};
template <>
-struct MODULES_EXPORT StructTraits<blink::mojom::IDBObjectStoreMetadataDataView,
- blink::WebIDBMetadata::ObjectStore> {
- static int64_t id(const blink::WebIDBMetadata::ObjectStore& metadata) {
- return metadata.id;
- }
- static WTF::String name(const blink::WebIDBMetadata::ObjectStore& metadata) {
- return metadata.name;
+struct MODULES_EXPORT
+ StructTraits<blink::mojom::IDBObjectStoreMetadataDataView,
+ scoped_refptr<blink::IDBObjectStoreMetadata>> {
+ static int64_t id(
+ const scoped_refptr<blink::IDBObjectStoreMetadata>& metadata) {
+ return metadata->id;
+ }
+ static WTF::String name(
+ const scoped_refptr<blink::IDBObjectStoreMetadata>& metadata) {
+ if (metadata->name.IsNull())
+ return g_empty_string;
+ return metadata->name;
}
- static const blink::WebIDBKeyPath& key_path(
- const blink::WebIDBMetadata::ObjectStore& metadata) {
- return metadata.key_path;
+ static const blink::IDBKeyPath& key_path(
+ const scoped_refptr<blink::IDBObjectStoreMetadata>& metadata) {
+ return metadata->key_path;
}
static bool auto_increment(
- const blink::WebIDBMetadata::ObjectStore& metadata) {
- return metadata.auto_increment;
+ const scoped_refptr<blink::IDBObjectStoreMetadata>& metadata) {
+ return metadata->auto_increment;
}
static int64_t max_index_id(
- const blink::WebIDBMetadata::ObjectStore& metadata) {
- return metadata.max_index_id;
+ const scoped_refptr<blink::IDBObjectStoreMetadata>& metadata) {
+ return metadata->max_index_id;
}
- static const blink::WebVector<blink::WebIDBMetadata::Index>& indexes(
- const blink::WebIDBMetadata::ObjectStore& metadata) {
- return metadata.indexes;
+ static const HashMap<int64_t, scoped_refptr<blink::IDBIndexMetadata>>&
+ indexes(const scoped_refptr<blink::IDBObjectStoreMetadata>& metadata) {
+ return metadata->indexes;
}
static bool Read(blink::mojom::IDBObjectStoreMetadataDataView data,
- blink::WebIDBMetadata::ObjectStore* out);
+ scoped_refptr<blink::IDBObjectStoreMetadata>* out);
+};
+
+template <>
+struct TypeConverter<blink::mojom::blink::IDBKeyRangePtr,
+ const blink::IDBKeyRange*> {
+ static blink::mojom::blink::IDBKeyRangePtr Convert(
+ const blink::IDBKeyRange* input);
+};
+
+template <>
+struct TypeConverter<blink::mojom::blink::IDBKeyRangePtr, blink::IDBKeyRange*> {
+ static blink::mojom::blink::IDBKeyRangePtr Convert(blink::IDBKeyRange* input);
+};
+
+template <>
+struct TypeConverter<blink::IDBKeyRange*, blink::mojom::blink::IDBKeyRangePtr> {
+ static blink::IDBKeyRange* Convert(
+ const blink::mojom::blink::IDBKeyRangePtr& input);
};
} // namespace mojo
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc
new file mode 100644
index 00000000000..98b29dd6b2e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
+
+#include <random>
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "mojo/public/cpp/base/file_path_mojom_traits.h"
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
+#include "mojo/public/cpp/bindings/string_traits_wtf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_blob_info.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
+#include "third_party/blink/renderer/platform/mojo/string16_mojom_traits.h"
+
+namespace blink {
+
+TEST(IDBMojomTraitsTest, IDBKeyBinary) {
+ // Generate test data.
+ std::mt19937 rng(5);
+ size_t test_data_size = 10000;
+ Vector<char> test_data(test_data_size);
+ std::generate(test_data.begin(), test_data.end(), rng);
+ scoped_refptr<SharedBuffer> input_data =
+ SharedBuffer::Create(test_data.data(), test_data.size());
+ Vector<uint8_t> input_vector = input_data->CopyAs<Vector<uint8_t>>();
+
+ // Verify expectations.
+ ASSERT_EQ(input_data->size(), test_data_size);
+ ASSERT_EQ(input_vector.size(), test_data_size);
+
+ // Create IDBKey binary key type mojom message.
+ std::unique_ptr<IDBKey> input = IDBKey::CreateBinary(input_data);
+ mojo::Message mojo_message = mojom::blink::IDBKey::SerializeAsMessage(&input);
+
+ // Deserialize the mojo message.
+ std::unique_ptr<IDBKey> output;
+ ASSERT_TRUE(mojom::blink::IDBKey::DeserializeFromMessage(
+ std::move(mojo_message), &output));
+ scoped_refptr<SharedBuffer> output_data = output->Binary();
+ Vector<uint8_t> output_vector = output_data->CopyAs<Vector<uint8_t>>();
+
+ // Verify expectations.
+ ASSERT_EQ(output_data->size(), test_data_size);
+ ASSERT_EQ(output_vector.size(), test_data_size);
+ ASSERT_EQ(input_vector, output_vector);
+}
+
+TEST(IDBMojomTraitsTest, IDBValue) {
+ // Generate test data.
+ std::mt19937 rng(5);
+ size_t test_data_size = 10000;
+ Vector<char> test_data(test_data_size);
+ std::generate(test_data.begin(), test_data.end(), rng);
+ scoped_refptr<SharedBuffer> input_data =
+ SharedBuffer::Create(test_data.data(), test_data.size());
+ Vector<uint8_t> input_vector = input_data->CopyAs<Vector<uint8_t>>();
+
+ // Verify expectations.
+ ASSERT_EQ(input_data->size(), test_data_size);
+ ASSERT_EQ(input_vector.size(), test_data_size);
+
+ // Create IDBValue mojom message.
+ std::unique_ptr<IDBValue> input =
+ IDBValue::Create(std::move(input_data), Vector<WebBlobInfo>());
+ mojo::Message mojo_message =
+ mojom::blink::IDBValue::SerializeAsMessage(&input);
+
+ // Deserialize the mojo message.
+ std::unique_ptr<IDBValue> output;
+ ASSERT_TRUE(mojom::blink::IDBValue::DeserializeFromMessage(
+ std::move(mojo_message), &output));
+ scoped_refptr<SharedBuffer> output_data = output->Data();
+ Vector<uint8_t> output_vector = output_data->CopyAs<Vector<uint8_t>>();
+
+ // Verify expectations.
+ ASSERT_EQ(output_data->size(), test_data_size);
+ ASSERT_EQ(output_vector.size(), test_data_size);
+ ASSERT_EQ(input_vector, output_vector);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.cc
deleted file mode 100644
index 360bdffd726..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.cc
+++ /dev/null
@@ -1,216 +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 "third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h"
-
-#include "third_party/blink/public/platform/file_path_conversion.h"
-#include "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h"
-#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h"
-#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h"
-
-using blink::IndexedDBDatabaseMetadata;
-using blink::WebBlobInfo;
-using blink::WebData;
-using blink::WebIDBCallbacks;
-using blink::WebIDBDatabase;
-using blink::WebIDBMetadata;
-using blink::WebIDBNameAndVersion;
-using blink::WebIDBValue;
-using blink::WebString;
-using blink::WebVector;
-using blink::mojom::blink::IDBDatabaseAssociatedPtrInfo;
-
-namespace blink {
-
-namespace {
-
-WebIDBValue ConvertReturnValue(const mojom::blink::IDBReturnValuePtr& value) {
- if (!value)
- return WebIDBValue(WebData(), WebVector<WebBlobInfo>());
-
- WebIDBValue web_value = IndexedDBCallbacksImpl::ConvertValue(value->value);
- web_value.SetInjectedPrimaryKey(value->primary_key, value->key_path);
- return web_value;
-}
-
-WebIDBNameAndVersion ConvertNameVersion(
- const mojom::blink::IDBNameAndVersionPtr& name_and_version) {
- return WebIDBNameAndVersion(name_and_version->name,
- name_and_version->version);
-}
-
-} // namespace
-
-// static
-WebIDBValue IndexedDBCallbacksImpl::ConvertValue(
- const mojom::blink::IDBValuePtr& value) {
- if (!value || value->bits.IsEmpty())
- return WebIDBValue(WebData(), WebVector<WebBlobInfo>());
-
- WebVector<WebBlobInfo> local_blob_info;
- local_blob_info.reserve(value->blob_or_file_info.size());
- for (const auto& info : value->blob_or_file_info) {
- if (info->file) {
- local_blob_info.emplace_back(
- WebString(info->uuid), FilePathToWebString(info->file->path),
- WebString(info->file->name), WebString(info->mime_type),
- info->file->last_modified.ToDoubleT(), info->size,
- info->blob.PassHandle());
- } else {
- local_blob_info.emplace_back(WebString(info->uuid),
- WebString(info->mime_type), info->size,
- info->blob.PassHandle());
- }
- }
-
- // TODO(crbug.com/902498): Use mojom traits to map directly to WebData.
- WebData web_data(reinterpret_cast<const char*>(value->bits.data()),
- value->bits.size());
- // Release value->bits std::vector.
- value->bits.clear();
- return WebIDBValue(std::move(web_data), std::move(local_blob_info));
-}
-
-IndexedDBCallbacksImpl::IndexedDBCallbacksImpl(
- std::unique_ptr<WebIDBCallbacks> callbacks,
- int64_t transaction_id,
- const base::WeakPtr<WebIDBCursorImpl>& cursor)
- : callbacks_(std::move(callbacks)),
- cursor_(cursor),
- transaction_id_(transaction_id) {}
-
-IndexedDBCallbacksImpl::~IndexedDBCallbacksImpl() = default;
-
-void IndexedDBCallbacksImpl::Error(int32_t code, const WTF::String& message) {
- callbacks_->OnError(WebIDBDatabaseError(code, WebString(message)));
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessNamesAndVersionsList(
- Vector<mojom::blink::IDBNameAndVersionPtr> names_and_versions) {
- WebVector<WebIDBNameAndVersion> web_names_and_versions;
- web_names_and_versions.reserve(names_and_versions.size());
- for (const mojom::blink::IDBNameAndVersionPtr& name_version :
- names_and_versions)
- web_names_and_versions.emplace_back(ConvertNameVersion(name_version));
- callbacks_->OnSuccess(web_names_and_versions);
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessStringList(const Vector<String>& value) {
- WebVector<WebString> web_value(value.size());
- std::transform(value.begin(), value.end(), web_value.begin(),
- [](const WTF::String& s) { return WebString(s); });
- callbacks_->OnSuccess(web_value);
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::Blocked(int64_t existing_version) {
- callbacks_->OnBlocked(existing_version);
- // Not resetting |callbacks_|. In this instance we will have to forward at
- // least one other call in the set OnUpgradeNeeded() / OnSuccess() /
- // OnError().
-}
-
-void IndexedDBCallbacksImpl::UpgradeNeeded(
- IDBDatabaseAssociatedPtrInfo database_info,
- int64_t old_version,
- mojom::IDBDataLoss data_loss,
- const String& data_loss_message,
- const WebIDBMetadata& web_metadata) {
- WebIDBDatabase* database = new WebIDBDatabaseImpl(std::move(database_info));
- callbacks_->OnUpgradeNeeded(old_version, database, web_metadata, data_loss,
- WebString(data_loss_message));
- // Not resetting |callbacks_|. In this instance we will have to forward at
- // least one other call in the set OnSuccess() / OnError().
-}
-
-void IndexedDBCallbacksImpl::SuccessDatabase(
- IDBDatabaseAssociatedPtrInfo database_info,
- const WebIDBMetadata& web_metadata) {
- WebIDBDatabase* database = nullptr;
- if (database_info.is_valid())
- database = new WebIDBDatabaseImpl(std::move(database_info));
-
- callbacks_->OnSuccess(database, web_metadata);
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessCursor(
- mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
- WebIDBKey key,
- WebIDBKey primary_key,
- mojom::blink::IDBValuePtr value) {
- WebIDBCursorImpl* cursor =
- new WebIDBCursorImpl(std::move(cursor_info), transaction_id_);
- callbacks_->OnSuccess(cursor, std::move(key), std::move(primary_key),
- ConvertValue(value));
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessValue(
- mojom::blink::IDBReturnValuePtr value) {
- callbacks_->OnSuccess(ConvertReturnValue(value));
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessCursorContinue(
- WebIDBKey key,
- WebIDBKey primary_key,
- mojom::blink::IDBValuePtr value) {
- callbacks_->OnSuccess(std::move(key), std::move(primary_key),
- ConvertValue(value));
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessCursorPrefetch(
- Vector<WebIDBKey> keys,
- Vector<WebIDBKey> primary_keys,
- Vector<mojom::blink::IDBValuePtr> values) {
- Vector<WebIDBValue> web_values;
- web_values.ReserveInitialCapacity(values.size());
- for (const mojom::blink::IDBValuePtr& value : values)
- web_values.emplace_back(ConvertValue(value));
-
- if (cursor_) {
- cursor_->SetPrefetchData(std::move(keys), std::move(primary_keys),
- std::move(web_values));
- cursor_->CachedContinue(callbacks_.get());
- }
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessArray(
- Vector<mojom::blink::IDBReturnValuePtr> values) {
- WebVector<WebIDBValue> web_values;
- web_values.reserve(values.size());
- for (const mojom::blink::IDBReturnValuePtr& value : values)
- web_values.emplace_back(ConvertReturnValue(value));
- callbacks_->OnSuccess(std::move(web_values));
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessKey(WebIDBKey key) {
- callbacks_->OnSuccess(std::move(key));
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::SuccessInteger(int64_t value) {
- callbacks_->OnSuccess(value);
- callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::Success() {
- callbacks_->OnSuccess();
- callbacks_.reset();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h
deleted file mode 100644
index efbaeb80604..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h
+++ /dev/null
@@ -1,82 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_INDEXED_DB_CALLBACKS_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_INDEXED_DB_CALLBACKS_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
-#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
-
-namespace blink {
-
-class WebIDBCallbacks;
-class WebIDBCursorImpl;
-class WebIDBValue;
-
-// Implements the child-process end of the pipe used to deliver callbacks.
-// |callback_runner_| is used to post tasks back to the thread which owns the
-// blink::WebIDBCallbacks.
-class IndexedDBCallbacksImpl : public mojom::blink::IDBCallbacks {
- public:
- // |kNoTransaction| is used as the default transaction ID when instantiating
- // an IndexedDBCallbacksImpl instance. See web_idb_factory_impl.cc for those
- // cases.
- enum : int64_t { kNoTransaction = -1 };
-
- static WebIDBValue ConvertValue(const mojom::blink::IDBValuePtr& value);
-
- IndexedDBCallbacksImpl(std::unique_ptr<WebIDBCallbacks> callbacks,
- int64_t transaction_id,
- const base::WeakPtr<WebIDBCursorImpl>& cursor);
- ~IndexedDBCallbacksImpl() override;
-
- // mojom::blink::IDBCallbacks implementation:
- void Error(int32_t code, const String& message) override;
- void SuccessNamesAndVersionsList(
- Vector<mojom::blink::IDBNameAndVersionPtr> names_and_versions) override;
- void SuccessStringList(const Vector<String>& value) override;
- void Blocked(int64_t existing_version) override;
- void UpgradeNeeded(mojom::blink::IDBDatabaseAssociatedPtrInfo database_info,
- int64_t old_version,
- mojom::IDBDataLoss data_loss,
- const String& data_loss_message,
- const WebIDBMetadata& metadata) override;
- void SuccessDatabase(mojom::blink::IDBDatabaseAssociatedPtrInfo database_info,
- const WebIDBMetadata& metadata) override;
- void SuccessCursor(mojom::blink::IDBCursorAssociatedPtrInfo cursor,
- WebIDBKey key,
- WebIDBKey primary_key,
- mojom::blink::IDBValuePtr value) override;
- void SuccessValue(mojom::blink::IDBReturnValuePtr value) override;
- void SuccessCursorContinue(WebIDBKey key,
- WebIDBKey primary_key,
- mojom::blink::IDBValuePtr value) override;
- void SuccessCursorPrefetch(Vector<WebIDBKey> keys,
- Vector<WebIDBKey> primary_keys,
- Vector<mojom::blink::IDBValuePtr> values) override;
- void SuccessArray(Vector<mojom::blink::IDBReturnValuePtr> values) override;
- void SuccessKey(WebIDBKey key) override;
- void SuccessInteger(int64_t value) override;
- void Success() override;
-
- private:
- scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
- std::unique_ptr<WebIDBCallbacks> callbacks_;
- base::WeakPtr<WebIDBCursorImpl> cursor_;
- int64_t transaction_id_;
-
- DISALLOW_COPY_AND_ASSIGN(IndexedDBCallbacksImpl);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_INDEXED_DB_CALLBACKS_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc
index 1149fab7b61..a73dcb5011e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc
@@ -7,16 +7,11 @@
#include <unordered_map>
#include <utility>
-#include "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
+#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h"
-
-using blink::WebVector;
-using blink::WebIDBDatabaseCallbacks;
-using blink::WebIDBObservation;
+#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
+#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
namespace blink {
@@ -38,8 +33,7 @@ void IndexedDBDatabaseCallbacksImpl::VersionChange(int64_t old_version,
void IndexedDBDatabaseCallbacksImpl::Abort(int64_t transaction_id,
int32_t code,
const String& message) {
- callbacks_->OnAbort(transaction_id,
- blink::WebIDBDatabaseError(code, message));
+ callbacks_->OnAbort(transaction_id, IDBDatabaseError(code, message));
}
void IndexedDBDatabaseCallbacksImpl::Complete(int64_t transaction_id) {
@@ -48,21 +42,29 @@ void IndexedDBDatabaseCallbacksImpl::Complete(int64_t transaction_id) {
void IndexedDBDatabaseCallbacksImpl::Changes(
mojom::blink::IDBObserverChangesPtr changes) {
- WebVector<WebIDBObservation> web_observations;
- web_observations.reserve(changes->observations.size());
+ Vector<Persistent<IDBObservation>> observations;
+ observations.ReserveInitialCapacity(changes->observations.size());
for (const auto& observation : changes->observations) {
- web_observations.emplace_back(
- observation->object_store_id, observation->type, observation->key_range,
- IndexedDBCallbacksImpl::ConvertValue(observation->value));
+ IDBKeyRange* key_range = observation->key_range.To<IDBKeyRange*>();
+ std::unique_ptr<IDBValue> value;
+ if (observation->value.has_value())
+ value = std::move(observation->value.value());
+ if (!value || value->Data()->IsEmpty()) {
+ value = IDBValue::Create(scoped_refptr<SharedBuffer>(),
+ Vector<WebBlobInfo>());
+ }
+ observations.emplace_back(
+ IDBObservation::Create(observation->object_store_id, observation->type,
+ key_range, std::move(value)));
}
- std::unordered_map<int32_t, WebVector<int32_t>> observation_index_map;
+ std::unordered_map<int32_t, Vector<int32_t>> observation_index_map;
for (const auto& observation_pair : changes->observation_index_map) {
observation_index_map[observation_pair.key] =
- WebVector<int32_t>(observation_pair.value);
+ Vector<int32_t>(observation_pair.value);
}
- std::unordered_map<int32_t, std::pair<int64_t, WebVector<int64_t>>>
+ std::unordered_map<int32_t, std::pair<int64_t, Vector<int64_t>>>
observer_transactions;
for (const auto& transaction_pair : changes->transaction_map) {
// Moving an int64_t is rather silly. Sadly, std::make_pair's overloads
@@ -73,7 +75,7 @@ void IndexedDBDatabaseCallbacksImpl::Changes(
std::move(transaction_pair.value->scope));
}
- callbacks_->OnChanges(observation_index_map, std::move(web_observations),
+ callbacks_->OnChanges(observation_index_map, std::move(observations),
observer_transactions);
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.cc
index 84198c49edf..46ae0a7dec3 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.cc
@@ -6,10 +6,9 @@
#include <utility>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
namespace blink {
// static
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h
index 906d7068018..8d7b07f6137 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h
@@ -10,9 +10,8 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
index 5cf1906a645..426c2f7d39e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
@@ -38,7 +38,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_string_list.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
@@ -107,23 +107,22 @@ Response AssertIDBFactory(Document* document, IDBFactory*& result) {
return Response::OK();
}
-class GetDatabaseNamesCallback final : public EventListener {
- WTF_MAKE_NONCOPYABLE(GetDatabaseNamesCallback);
-
+class GetDatabaseNamesCallback final : public NativeEventListener {
public:
static GetDatabaseNamesCallback* Create(
std::unique_ptr<RequestDatabaseNamesCallback> request_callback,
const String& security_origin) {
- return new GetDatabaseNamesCallback(std::move(request_callback),
- security_origin);
+ return MakeGarbageCollected<GetDatabaseNamesCallback>(
+ std::move(request_callback), security_origin);
}
+ GetDatabaseNamesCallback(
+ std::unique_ptr<RequestDatabaseNamesCallback> request_callback,
+ const String& security_origin)
+ : request_callback_(std::move(request_callback)),
+ security_origin_(security_origin) {}
~GetDatabaseNamesCallback() override = default;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
void Invoke(ExecutionContext*, Event* event) override {
if (event->type() != event_type_names::kSuccess) {
request_callback_->sendFailure(Response::Error("Unexpected event type."));
@@ -147,32 +146,25 @@ class GetDatabaseNamesCallback final : public EventListener {
}
private:
- GetDatabaseNamesCallback(
- std::unique_ptr<RequestDatabaseNamesCallback> request_callback,
- const String& security_origin)
- : EventListener(EventListener::kCPPEventListenerType),
- request_callback_(std::move(request_callback)),
- security_origin_(security_origin) {}
std::unique_ptr<RequestDatabaseNamesCallback> request_callback_;
String security_origin_;
};
-class DeleteCallback final : public EventListener {
- WTF_MAKE_NONCOPYABLE(DeleteCallback);
-
+class DeleteCallback final : public NativeEventListener {
public:
static DeleteCallback* Create(
std::unique_ptr<DeleteDatabaseCallback> request_callback,
const String& security_origin) {
- return new DeleteCallback(std::move(request_callback), security_origin);
+ return MakeGarbageCollected<DeleteCallback>(std::move(request_callback),
+ security_origin);
}
+ DeleteCallback(std::unique_ptr<DeleteDatabaseCallback> request_callback,
+ const String& security_origin)
+ : request_callback_(std::move(request_callback)),
+ security_origin_(security_origin) {}
~DeleteCallback() override = default;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
void Invoke(ExecutionContext*, Event* event) override {
if (event->type() != event_type_names::kSuccess) {
request_callback_->sendFailure(
@@ -183,11 +175,6 @@ class DeleteCallback final : public EventListener {
}
private:
- DeleteCallback(std::unique_ptr<DeleteDatabaseCallback> request_callback,
- const String& security_origin)
- : EventListener(EventListener::kCPPEventListenerType),
- request_callback_(std::move(request_callback)),
- security_origin_(security_origin) {}
std::unique_ptr<DeleteDatabaseCallback> request_callback_;
String security_origin_;
};
@@ -256,20 +243,22 @@ class ExecutableWithDatabase
};
template <typename RequestCallback>
-class OpenDatabaseCallback final : public EventListener {
+class OpenDatabaseCallback final : public NativeEventListener {
public:
static OpenDatabaseCallback* Create(
ExecutableWithDatabase<RequestCallback>* executable_with_database,
ScriptState* script_state) {
- return new OpenDatabaseCallback(executable_with_database, script_state);
+ return MakeGarbageCollected<OpenDatabaseCallback>(executable_with_database,
+ script_state);
}
+ OpenDatabaseCallback(
+ ExecutableWithDatabase<RequestCallback>* executable_with_database,
+ ScriptState* script_state)
+ : executable_with_database_(executable_with_database),
+ script_state_(script_state) {}
~OpenDatabaseCallback() override = default;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
void Invoke(ExecutionContext* context, Event* event) override {
if (event->type() != event_type_names::kSuccess) {
executable_with_database_->GetRequestCallback()->sendFailure(
@@ -294,35 +283,29 @@ class OpenDatabaseCallback final : public EventListener {
void Trace(blink::Visitor* visitor) override {
visitor->Trace(script_state_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
}
private:
- OpenDatabaseCallback(
- ExecutableWithDatabase<RequestCallback>* executable_with_database,
- ScriptState* script_state)
- : EventListener(EventListener::kCPPEventListenerType),
- executable_with_database_(executable_with_database),
- script_state_(script_state) {}
scoped_refptr<ExecutableWithDatabase<RequestCallback>>
executable_with_database_;
Member<ScriptState> script_state_;
};
template <typename RequestCallback>
-class UpgradeDatabaseCallback final : public EventListener {
+class UpgradeDatabaseCallback final : public NativeEventListener {
public:
static UpgradeDatabaseCallback* Create(
ExecutableWithDatabase<RequestCallback>* executable_with_database) {
- return new UpgradeDatabaseCallback(executable_with_database);
+ return MakeGarbageCollected<UpgradeDatabaseCallback>(
+ executable_with_database);
}
+ UpgradeDatabaseCallback(
+ ExecutableWithDatabase<RequestCallback>* executable_with_database)
+ : executable_with_database_(executable_with_database) {}
~UpgradeDatabaseCallback() override = default;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
void Invoke(ExecutionContext* context, Event* event) override {
if (event->type() != event_type_names::kUpgradeneeded) {
executable_with_database_->GetRequestCallback()->sendFailure(
@@ -342,10 +325,6 @@ class UpgradeDatabaseCallback final : public EventListener {
}
private:
- UpgradeDatabaseCallback(
- ExecutableWithDatabase<RequestCallback>* executable_with_database)
- : EventListener(EventListener::kCPPEventListenerType),
- executable_with_database_(executable_with_database) {}
scoped_refptr<ExecutableWithDatabase<RequestCallback>>
executable_with_database_;
};
@@ -387,16 +366,16 @@ IDBIndex* IndexForObjectStore(IDBObjectStore* idb_object_store,
std::unique_ptr<KeyPath> KeyPathFromIDBKeyPath(const IDBKeyPath& idb_key_path) {
std::unique_ptr<KeyPath> key_path;
switch (idb_key_path.GetType()) {
- case IDBKeyPath::kNullType:
+ case mojom::IDBKeyPathType::Null:
key_path = KeyPath::create().setType(KeyPath::TypeEnum::Null).build();
break;
- case IDBKeyPath::kStringType:
+ case mojom::IDBKeyPathType::String:
key_path = KeyPath::create()
.setType(KeyPath::TypeEnum::String)
.setString(idb_key_path.GetString())
.build();
break;
- case IDBKeyPath::kArrayType: {
+ case mojom::IDBKeyPathType::Array: {
key_path = KeyPath::create().setType(KeyPath::TypeEnum::Array).build();
std::unique_ptr<protocol::Array<String>> array =
protocol::Array<String>::create();
@@ -463,7 +442,8 @@ class DatabaseLoader final
std::unique_ptr<DatabaseWithObjectStores> result =
DatabaseWithObjectStores::create()
.setName(idb_database->name())
- .setVersion(static_cast<int>(idb_database->version()))
+ .setVersion(
+ static_cast<unsigned long long>(idb_database->version()))
.setObjectStores(std::move(object_stores))
.build();
@@ -542,7 +522,7 @@ static IDBKeyRange* IdbKeyRangeFromKeyRange(
class DataLoader;
-class OpenCursorCallback final : public EventListener {
+class OpenCursorCallback final : public NativeEventListener {
public:
static OpenCursorCallback* Create(
v8_inspector::V8InspectorSession* v8_session,
@@ -550,16 +530,24 @@ class OpenCursorCallback final : public EventListener {
std::unique_ptr<RequestDataCallback> request_callback,
int skip_count,
unsigned page_size) {
- return new OpenCursorCallback(v8_session, script_state,
- std::move(request_callback), skip_count,
- page_size);
+ return MakeGarbageCollected<OpenCursorCallback>(v8_session, script_state,
+ std::move(request_callback),
+ skip_count, page_size);
}
- ~OpenCursorCallback() override = default;
-
- bool operator==(const EventListener& other) const override {
- return this == &other;
+ OpenCursorCallback(v8_inspector::V8InspectorSession* v8_session,
+ ScriptState* script_state,
+ std::unique_ptr<RequestDataCallback> request_callback,
+ int skip_count,
+ unsigned page_size)
+ : v8_session_(v8_session),
+ script_state_(script_state),
+ request_callback_(std::move(request_callback)),
+ skip_count_(skip_count),
+ page_size_(page_size) {
+ result_ = Array<DataEntry>::create();
}
+ ~OpenCursorCallback() override = default;
void Invoke(ExecutionContext*, Event* event) override {
if (event->type() != event_type_names::kSuccess) {
@@ -636,24 +624,10 @@ class OpenCursorCallback final : public EventListener {
void Trace(blink::Visitor* visitor) override {
visitor->Trace(script_state_);
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
}
private:
- OpenCursorCallback(v8_inspector::V8InspectorSession* v8_session,
- ScriptState* script_state,
- std::unique_ptr<RequestDataCallback> request_callback,
- int skip_count,
- unsigned page_size)
- : EventListener(EventListener::kCPPEventListenerType),
- v8_session_(v8_session),
- script_state_(script_state),
- request_callback_(std::move(request_callback)),
- skip_count_(skip_count),
- page_size_(page_size) {
- result_ = Array<DataEntry>::create();
- }
-
v8_inspector::V8InspectorSession* v8_session_;
Member<ScriptState> script_state_;
std::unique_ptr<RequestDataCallback> request_callback_;
@@ -855,9 +829,7 @@ void InspectorIndexedDBAgent::requestData(
database_name);
}
-class DeleteObjectStoreEntriesListener final : public EventListener {
- WTF_MAKE_NONCOPYABLE(DeleteObjectStoreEntriesListener);
-
+class DeleteObjectStoreEntriesListener final : public NativeEventListener {
public:
static DeleteObjectStoreEntriesListener* Create(
std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback) {
@@ -867,14 +839,9 @@ class DeleteObjectStoreEntriesListener final : public EventListener {
DeleteObjectStoreEntriesListener(
std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback)
- : EventListener(EventListener::kCPPEventListenerType),
- request_callback_(std::move(request_callback)) {}
+ : request_callback_(std::move(request_callback)) {}
~DeleteObjectStoreEntriesListener() override = default;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
void Invoke(ExecutionContext*, Event* event) override {
if (event->type() != event_type_names::kSuccess) {
request_callback_->sendFailure(
@@ -962,21 +929,19 @@ void InspectorIndexedDBAgent::deleteObjectStoreEntries(
database_name);
}
-class ClearObjectStoreListener final : public EventListener {
- WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
-
+class ClearObjectStoreListener final : public NativeEventListener {
public:
static ClearObjectStoreListener* Create(
std::unique_ptr<ClearObjectStoreCallback> request_callback) {
- return new ClearObjectStoreListener(std::move(request_callback));
+ return MakeGarbageCollected<ClearObjectStoreListener>(
+ std::move(request_callback));
}
+ ClearObjectStoreListener(
+ std::unique_ptr<ClearObjectStoreCallback> request_callback)
+ : request_callback_(std::move(request_callback)) {}
~ClearObjectStoreListener() override = default;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
void Invoke(ExecutionContext*, Event* event) override {
if (event->type() != event_type_names::kComplete) {
request_callback_->sendFailure(Response::Error("Unexpected event type."));
@@ -987,11 +952,6 @@ class ClearObjectStoreListener final : public EventListener {
}
private:
- ClearObjectStoreListener(
- std::unique_ptr<ClearObjectStoreCallback> request_callback)
- : EventListener(EventListener::kCPPEventListenerType),
- request_callback_(std::move(request_callback)) {}
-
std::unique_ptr<ClearObjectStoreCallback> request_callback_;
};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.cc b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.cc
index 1f7839527ff..3a4254d8eee 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.cc
@@ -4,36 +4,44 @@
#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
+
namespace blink {
MockWebIDBCallbacks::MockWebIDBCallbacks() {}
MockWebIDBCallbacks::~MockWebIDBCallbacks() {}
-void MockWebIDBCallbacks::OnSuccess(blink::WebIDBKey key,
- blink::WebIDBKey primaryKey,
- blink::WebIDBValue value) {
- DoOnSuccess(key, primaryKey, value);
+void MockWebIDBCallbacks::SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
+ int64_t transaction_id) {}
+
+void MockWebIDBCallbacks::SuccessCursorContinue(
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> value) {
+ DoSuccessCursorContinue(key, primary_key, value);
}
-void MockWebIDBCallbacks::OnSuccess(blink::WebIDBCursor* cursor,
- blink::WebIDBKey key,
- blink::WebIDBKey primaryKey,
- blink::WebIDBValue value) {
- DoOnSuccess(cursor, key, primaryKey, value);
+void MockWebIDBCallbacks::SuccessCursor(
+ mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> optional_value) {
+ DoSuccessCursor(cursor_info, key, primary_key, optional_value);
}
-void MockWebIDBCallbacks::OnSuccess(blink::WebIDBKey key) {
- DoOnSuccess(key);
+void MockWebIDBCallbacks::SuccessKey(std::unique_ptr<IDBKey> key) {
+ DoSuccessKey(key);
}
-void MockWebIDBCallbacks::OnSuccess(blink::WebIDBValue value) {
- DoOnSuccess(value);
+void MockWebIDBCallbacks::SuccessValue(mojom::blink::IDBReturnValuePtr value) {
+ DoSuccessValue(value);
}
-void MockWebIDBCallbacks::OnSuccess(
- blink::WebVector<blink::WebIDBValue> values) {
- DoOnSuccess(values);
+void MockWebIDBCallbacks::SuccessArray(
+ Vector<mojom::blink::IDBReturnValuePtr> values) {
+ DoSuccessArray(values);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h
index 97fe12544ea..14b466b1ea2 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h
@@ -6,66 +6,86 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_CALLBACKS_H_
#include "base/macros.h"
+#include "base/optional.h"
#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
namespace blink {
-class MockWebIDBCallbacks : public blink::WebIDBCallbacks {
+class MockWebIDBCallbacks : public WebIDBCallbacks {
public:
MockWebIDBCallbacks();
~MockWebIDBCallbacks() override;
- MOCK_METHOD1(OnError, void(const blink::WebIDBDatabaseError&));
-
- void OnSuccess(blink::WebIDBKey,
- blink::WebIDBKey primaryKey,
- blink::WebIDBValue) override;
- MOCK_METHOD3(DoOnSuccess,
- void(const blink::WebIDBKey& key,
- const blink::WebIDBKey& primaryKey,
- const blink::WebIDBValue& value));
-
- MOCK_METHOD1(OnSuccess,
- void(const blink::WebVector<blink::WebIDBNameAndVersion>&));
- MOCK_METHOD1(OnSuccess, void(const blink::WebVector<blink::WebString>&));
-
- void OnSuccess(blink::WebIDBCursor* cursor,
- blink::WebIDBKey key,
- blink::WebIDBKey primaryKey,
- blink::WebIDBValue value) override;
- MOCK_METHOD4(DoOnSuccess,
- void(blink::WebIDBCursor*,
- const blink::WebIDBKey&,
- const blink::WebIDBKey& primaryKey,
- const blink::WebIDBValue&));
-
- MOCK_METHOD2(OnSuccess,
- void(blink::WebIDBDatabase*, const blink::WebIDBMetadata&));
- void OnSuccess(blink::WebIDBKey) override;
- MOCK_METHOD1(DoOnSuccess, void(const blink::WebIDBKey&));
-
- void OnSuccess(blink::WebIDBValue) override;
- MOCK_METHOD1(DoOnSuccess, void(const blink::WebIDBValue&));
-
- void OnSuccess(blink::WebVector<blink::WebIDBValue>) override;
- MOCK_METHOD1(DoOnSuccess, void(const blink::WebVector<blink::WebIDBValue>&));
-
- MOCK_METHOD1(OnSuccess, void(long long));
- MOCK_METHOD0(OnSuccess, void());
- MOCK_METHOD1(OnBlocked, void(long long oldVersion));
- MOCK_METHOD5(OnUpgradeNeeded,
- void(long long oldVersion,
- blink::WebIDBDatabase*,
- const blink::WebIDBMetadata&,
+
+ void SetState(base::WeakPtr<WebIDBCursorImpl>, int64_t);
+
+ MOCK_METHOD2(Error, void(int32_t, const String&));
+
+ void SuccessCursorContinue(
+ std::unique_ptr<IDBKey>,
+ std::unique_ptr<IDBKey> primaryKey,
+ base::Optional<std::unique_ptr<IDBValue>>) override;
+ MOCK_METHOD3(DoSuccessCursorContinue,
+ void(const std::unique_ptr<IDBKey>& key,
+ const std::unique_ptr<IDBKey>& primaryKey,
+ const base::Optional<std::unique_ptr<IDBValue>>& value));
+
+ MOCK_METHOD1(SuccessNamesAndVersionsList,
+ void(Vector<mojom::blink::IDBNameAndVersionPtr>));
+
+ MOCK_METHOD1(SuccessStringList, void(const Vector<String>&));
+
+ void SuccessCursor(
+ mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> optional_value) override;
+ MOCK_METHOD4(
+ DoSuccessCursor,
+ void(const mojom::blink::IDBCursorAssociatedPtrInfo& cursor_info,
+ const std::unique_ptr<IDBKey>& key,
+ const std::unique_ptr<IDBKey>& primary_key,
+ const base::Optional<std::unique_ptr<IDBValue>>& optional_value));
+
+ MOCK_METHOD3(SuccessCursorPrefetch,
+ void(Vector<std::unique_ptr<IDBKey>> keys,
+ Vector<std::unique_ptr<IDBKey>> primary_keys,
+ Vector<std::unique_ptr<IDBValue>> values));
+
+ MOCK_METHOD2(SuccessDatabase,
+ void(mojom::blink::IDBDatabaseAssociatedPtrInfo,
+ const IDBDatabaseMetadata&));
+
+ void SuccessKey(std::unique_ptr<IDBKey>) override;
+ MOCK_METHOD1(DoSuccessKey, void(const std::unique_ptr<IDBKey>&));
+
+ void SuccessValue(mojom::blink::IDBReturnValuePtr) override;
+ MOCK_METHOD1(DoSuccessValue, void(const mojom::blink::IDBReturnValuePtr&));
+
+ void SuccessArray(Vector<mojom::blink::IDBReturnValuePtr>) override;
+ MOCK_METHOD1(DoSuccessArray,
+ void(const Vector<mojom::blink::IDBReturnValuePtr>&));
+
+ MOCK_METHOD1(SuccessInteger, void(int64_t));
+
+ MOCK_METHOD0(Success, void());
+
+ MOCK_METHOD1(Blocked, void(int64_t oldVersion));
+
+ MOCK_METHOD5(UpgradeNeeded,
+ void(mojom::blink::IDBDatabaseAssociatedPtrInfo,
+ int64_t oldVersion,
mojom::IDBDataLoss dataLoss,
- blink::WebString dataLossMessage));
- MOCK_METHOD0(Detach, void());
+ const String& dataLossMessage,
+ const IDBDatabaseMetadata&));
+
+ MOCK_METHOD0(DetachRequestFromCallback, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockWebIDBCallbacks);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h
index 04f7a5acda6..0ed42f39503 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h
@@ -7,7 +7,6 @@
#include <gmock/gmock.h>
#include <memory>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
@@ -24,7 +23,7 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> {
void(long long transaction_id,
long long object_store_id,
const String& name,
- const WebIDBKeyPath&,
+ const IDBKeyPath&,
bool auto_increment));
MOCK_METHOD2(DeleteObjectStore,
void(long long transaction_id, long long object_store_id));
@@ -39,13 +38,14 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> {
MOCK_METHOD0(Close, void());
MOCK_METHOD0(VersionChangeIgnored, void());
MOCK_METHOD1(Abort, void(long long transaction_id));
- MOCK_METHOD1(Commit, void(long long transaction_id));
+ MOCK_METHOD2(Commit,
+ void(long long transaction_id, long long num_errors_handled));
MOCK_METHOD7(CreateIndex,
void(long long transaction_id,
long long object_store_id,
long long index_id,
const String& name,
- const WebIDBKeyPath&,
+ const IDBKeyPath&,
bool unique,
bool multi_entry));
MOCK_METHOD3(DeleteIndex,
@@ -72,33 +72,32 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> {
void(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
bool key_only,
WebIDBCallbacks*));
MOCK_METHOD7(GetAll,
void(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
long long max_count,
bool key_only,
WebIDBCallbacks*));
- MOCK_METHOD8(Put,
+ MOCK_METHOD7(Put,
void(long long transaction_id,
long long object_store_id,
- const WebData& value,
- const Vector<WebBlobInfo>&,
- WebIDBKeyView primary_key,
+ std::unique_ptr<IDBValue> value,
+ std::unique_ptr<IDBKey> primary_key,
mojom::IDBPutMode,
WebIDBCallbacks*,
- const Vector<WebIDBIndexKeys>&));
+ Vector<IDBIndexKeys>));
MOCK_METHOD4(SetIndexKeys,
void(long long transaction_id,
long long object_store_id,
- WebIDBKeyView primary_key,
- const Vector<WebIDBIndexKeys>&));
+ std::unique_ptr<IDBKey> primary_key,
+ Vector<IDBIndexKeys>));
MOCK_METHOD3(SetIndexesReady,
void(long long transaction_id,
long long object_store_id,
@@ -107,7 +106,7 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> {
void(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
mojom::IDBCursorDirection,
bool key_only,
mojom::IDBTaskType,
@@ -116,17 +115,17 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> {
void(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
WebIDBCallbacks*));
MOCK_METHOD4(Delete,
void(long long transaction_id,
long long object_store_id,
- WebIDBKeyView primary_key,
+ const IDBKey* primary_key,
WebIDBCallbacks*));
MOCK_METHOD4(DeleteRange,
void(long long transaction_id,
long long object_store_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
WebIDBCallbacks*));
MOCK_METHOD3(Clear,
void(long long transaction_id,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc
index 80cf343612e..a1ce311907f 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -17,4 +18,15 @@ MockWebIDBFactory::~MockWebIDBFactory() = default;
std::unique_ptr<MockWebIDBFactory> MockWebIDBFactory::Create() {
return base::WrapUnique(new MockWebIDBFactory());
}
+
+void MockWebIDBFactory::GetDatabaseInfo(
+ std::unique_ptr<WebIDBCallbacks> callbacks) {
+ *callbacks_ptr_ = std::move(callbacks);
+}
+
+void MockWebIDBFactory::SetCallbacksPointer(
+ std::unique_ptr<WebIDBCallbacks>* callbacks_ptr) {
+ callbacks_ptr_ = callbacks_ptr;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h
index 47ffe2f93e6..bf0bea1c734 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h
@@ -5,56 +5,44 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_FACTORY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_FACTORY_H_
-#include <gmock/gmock.h>
#include <memory>
-#include "base/single_thread_task_runner.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_factory.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
-namespace base {
-class SingleThreadTaskRunner;
+namespace WTF {
+class String;
}
namespace blink {
-class WebIDBCallbacks;
-class WebIDBDatabaseCallbacks;
-class WebSecurityOrigin;
-class WebString;
-
class MockWebIDBFactory : public testing::StrictMock<blink::WebIDBFactory> {
public:
~MockWebIDBFactory() override;
static std::unique_ptr<MockWebIDBFactory> Create();
- MOCK_METHOD3(GetDatabaseInfo,
- void(WebIDBCallbacks*,
- const WebSecurityOrigin&,
- scoped_refptr<base::SingleThreadTaskRunner>));
- MOCK_METHOD3(GetDatabaseNames,
- void(WebIDBCallbacks*,
- const WebSecurityOrigin&,
- scoped_refptr<base::SingleThreadTaskRunner>));
- MOCK_METHOD7(Open,
- void(const WebString& name,
+ void GetDatabaseInfo(std::unique_ptr<WebIDBCallbacks>);
+ MOCK_METHOD1(GetDatabaseNames, void(std::unique_ptr<WebIDBCallbacks>));
+ MOCK_METHOD5(Open,
+ void(const WTF::String& name,
long long version,
long long transaction_id,
- WebIDBCallbacks*,
- WebIDBDatabaseCallbacks*,
- const WebSecurityOrigin&,
- scoped_refptr<base::SingleThreadTaskRunner>));
- MOCK_METHOD5(DeleteDatabase,
- void(const WebString& name,
- WebIDBCallbacks*,
- const WebSecurityOrigin&,
- bool force_close,
- scoped_refptr<base::SingleThreadTaskRunner>));
+ std::unique_ptr<WebIDBCallbacks>,
+ std::unique_ptr<WebIDBDatabaseCallbacks>));
+ MOCK_METHOD3(DeleteDatabase,
+ void(const WTF::String& name,
+ std::unique_ptr<WebIDBCallbacks>,
+ bool force_close));
+
+ void SetCallbacksPointer(std::unique_ptr<WebIDBCallbacks>* callbacks);
private:
MockWebIDBFactory();
+ std::unique_ptr<WebIDBCallbacks>* callbacks_ptr_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h
index 5be6cdbf9e3..ff1a49d08ad 100644
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,52 +23,24 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_METADATA_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_METADATA_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_CALLBACKS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_CALLBACKS_H_
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
-struct WebIDBMetadata {
- enum { kNoVersion = -1 };
- struct Index;
- struct ObjectStore;
+class WebIDBCursorImpl;
- WebString name;
- long long version;
- long long id;
- long long max_object_store_id;
- WebVector<ObjectStore> object_stores;
- WebIDBMetadata() : version(kNoVersion) {}
-
- struct ObjectStore {
- WebString name;
- WebIDBKeyPath key_path;
- bool auto_increment;
- long long id;
- long long max_index_id;
- WebVector<Index> indexes;
- ObjectStore()
- : key_path(WebIDBKeyPath::CreateNull()), auto_increment(false) {}
- };
-
- struct Index {
- WebString name;
- WebIDBKeyPath key_path;
- bool unique;
- bool multi_entry;
- long long id;
- Index()
- : key_path(WebIDBKeyPath::CreateNull()),
- unique(false),
- multi_entry(false) {}
- };
+class WebIDBCallbacks : public mojom::blink::IDBCallbacks {
+ public:
+ virtual void DetachRequestFromCallback() = 0;
+ virtual void SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
+ int64_t transaction_id) = 0;
};
} // namespace blink
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_METADATA_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_CALLBACKS_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
index b4904837f97..2e1709ebd5d 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
@@ -31,33 +31,39 @@
#include <memory>
#include "base/memory/ptr_util.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/modules/indexed_db_names.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_request.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-using blink::WebIDBCursor;
-using blink::WebIDBDatabase;
-using blink::WebIDBDatabaseError;
-using blink::WebIDBKey;
-using blink::WebIDBKeyPath;
-using blink::WebIDBMetadata;
-using blink::WebIDBNameAndVersion;
-using blink::WebIDBValue;
-using blink::WebVector;
-
namespace blink {
+namespace {
+
+std::unique_ptr<IDBValue> ConvertReturnValue(
+ const mojom::blink::IDBReturnValuePtr& input) {
+ if (!input) {
+ return IDBValue::Create(scoped_refptr<SharedBuffer>(),
+ Vector<WebBlobInfo>());
+ }
+
+ std::unique_ptr<IDBValue> output = std::move(input->value);
+ output->SetInjectedPrimaryKey(std::move(input->primary_key), input->key_path);
+ return output;
+}
+
+} // namespace
+
// static
std::unique_ptr<WebIDBCallbacksImpl> WebIDBCallbacksImpl::Create(
IDBRequest* request) {
@@ -66,11 +72,22 @@ std::unique_ptr<WebIDBCallbacksImpl> WebIDBCallbacksImpl::Create(
WebIDBCallbacksImpl::WebIDBCallbacksImpl(IDBRequest* request)
: request_(request) {
+ task_runner_ = request_->GetExecutionContext()->GetTaskRunner(
+ TaskType::kInternalIndexedDB);
probe::AsyncTaskScheduled(request_->GetExecutionContext(),
indexed_db_names::kIndexedDB, this);
}
WebIDBCallbacksImpl::~WebIDBCallbacksImpl() {
+ Detach();
+}
+
+void WebIDBCallbacksImpl::Detach() {
+ DetachCallbackFromRequest();
+ DetachRequestFromCallback();
+}
+
+void WebIDBCallbacksImpl::DetachCallbackFromRequest() {
if (request_) {
probe::AsyncTaskCanceled(request_->GetExecutionContext(), this);
#if DCHECK_IS_ON()
@@ -80,53 +97,90 @@ WebIDBCallbacksImpl::~WebIDBCallbacksImpl() {
}
}
-void WebIDBCallbacksImpl::OnError(const WebIDBDatabaseError& error) {
+void WebIDBCallbacksImpl::DetachRequestFromCallback() {
+ request_.Clear();
+}
+
+void WebIDBCallbacksImpl::SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
+ int64_t transaction_id) {
+ cursor_ = cursor;
+ transaction_id_ = transaction_id;
+}
+
+void WebIDBCallbacksImpl::Error(int32_t code, const String& message) {
if (!request_)
return;
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "error");
- request_->HandleResponse(DOMException::Create(
- static_cast<DOMExceptionCode>(error.Code()), error.Message()));
+ request_->HandleResponse(
+ DOMException::Create(static_cast<DOMExceptionCode>(code), message));
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(
- const WebVector<WebIDBNameAndVersion>& web_name_and_version_list) {
+void WebIDBCallbacksImpl::SuccessNamesAndVersionsList(
+ Vector<mojom::blink::IDBNameAndVersionPtr> name_and_version_list) {
// Only implemented in idb_factory.cc for the promise-based databases() call.
NOTREACHED();
}
-void WebIDBCallbacksImpl::OnSuccess(
- const WebVector<WebString>& web_string_list) {
+void WebIDBCallbacksImpl::SuccessStringList(const Vector<String>& string_list) {
if (!request_)
return;
- Vector<String> string_list;
- for (size_t i = 0; i < web_string_list.size(); ++i)
- string_list.push_back(web_string_list[i]);
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
#if DCHECK_IS_ON()
DCHECK(!request_->TransactionHasQueuedResults());
#endif // DCHECK_IS_ON()
- request_->EnqueueResponse(string_list);
+ request_->EnqueueResponse(std::move(string_list));
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(WebIDBCursor* cursor,
- WebIDBKey key,
- WebIDBKey primary_key,
- WebIDBValue value) {
+void WebIDBCallbacksImpl::SuccessCursor(
+ mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> optional_value) {
if (!request_)
return;
+ std::unique_ptr<WebIDBCursorImpl> cursor = std::make_unique<WebIDBCursorImpl>(
+ std::move(cursor_info), transaction_id_, task_runner_);
+ std::unique_ptr<IDBValue> value;
+ if (optional_value.has_value()) {
+ value = std::move(optional_value.value());
+ } else {
+ value =
+ IDBValue::Create(scoped_refptr<SharedBuffer>(), Vector<WebBlobInfo>());
+ }
+ DCHECK(value);
+
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
- std::unique_ptr<IDBValue> idb_value = value.ReleaseIdbValue();
- idb_value->SetIsolate(request_->GetIsolate());
- request_->HandleResponse(base::WrapUnique(cursor), key.ReleaseIdbKey(),
- primary_key.ReleaseIdbKey(), std::move(idb_value));
+ value->SetIsolate(request_->GetIsolate());
+ request_->HandleResponse(std::move(cursor), std::move(key),
+ std::move(primary_key), std::move(value));
+ Detach();
+}
+
+void WebIDBCallbacksImpl::SuccessCursorPrefetch(
+ Vector<std::unique_ptr<IDBKey>> keys,
+ Vector<std::unique_ptr<IDBKey>> primary_keys,
+ Vector<std::unique_ptr<IDBValue>> values) {
+ if (cursor_) {
+ cursor_->SetPrefetchData(std::move(keys), std::move(primary_keys),
+ std::move(values));
+ cursor_->CachedContinue(this);
+ }
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(WebIDBDatabase* backend,
- const WebIDBMetadata& metadata) {
- std::unique_ptr<WebIDBDatabase> db = base::WrapUnique(backend);
+void WebIDBCallbacksImpl::SuccessDatabase(
+ mojom::blink::IDBDatabaseAssociatedPtrInfo database_info,
+ const IDBDatabaseMetadata& metadata) {
+ std::unique_ptr<WebIDBDatabase> db;
+ if (database_info.is_valid()) {
+ db = std::make_unique<WebIDBDatabaseImpl>(std::move(database_info),
+ task_runner_);
+ }
if (request_) {
probe::AsyncTask async_task(request_->GetExecutionContext(), this,
"success");
@@ -134,74 +188,91 @@ void WebIDBCallbacksImpl::OnSuccess(WebIDBDatabase* backend,
DCHECK(!request_->TransactionHasQueuedResults());
#endif // DCHECK_IS_ON()
request_->EnqueueResponse(std::move(db), IDBDatabaseMetadata(metadata));
+ Detach();
} else if (db) {
db->Close();
}
}
-void WebIDBCallbacksImpl::OnSuccess(WebIDBKey key) {
+void WebIDBCallbacksImpl::SuccessKey(std::unique_ptr<IDBKey> key) {
if (!request_)
return;
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
- request_->HandleResponse(key.ReleaseIdbKey());
+ request_->HandleResponse(std::move(key));
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(WebIDBValue value) {
+void WebIDBCallbacksImpl::SuccessValue(
+ mojom::blink::IDBReturnValuePtr return_value) {
if (!request_)
return;
+ std::unique_ptr<IDBValue> value = ConvertReturnValue(return_value);
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
- std::unique_ptr<IDBValue> idb_value = value.ReleaseIdbValue();
- idb_value->SetIsolate(request_->GetIsolate());
- request_->HandleResponse(std::move(idb_value));
+ value->SetIsolate(request_->GetIsolate());
+ request_->HandleResponse(std::move(value));
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(WebVector<WebIDBValue> values) {
+void WebIDBCallbacksImpl::SuccessArray(
+ Vector<mojom::blink::IDBReturnValuePtr> values) {
if (!request_)
return;
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
Vector<std::unique_ptr<IDBValue>> idb_values;
- idb_values.ReserveInitialCapacity(SafeCast<wtf_size_t>(values.size()));
- for (WebIDBValue& value : values) {
- std::unique_ptr<IDBValue> idb_value = value.ReleaseIdbValue();
+ idb_values.ReserveInitialCapacity(values.size());
+ for (const mojom::blink::IDBReturnValuePtr& value : values) {
+ std::unique_ptr<IDBValue> idb_value = ConvertReturnValue(value);
idb_value->SetIsolate(request_->GetIsolate());
idb_values.emplace_back(std::move(idb_value));
}
request_->HandleResponse(std::move(idb_values));
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(long long value) {
+void WebIDBCallbacksImpl::SuccessInteger(int64_t value) {
if (!request_)
return;
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
request_->HandleResponse(value);
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess() {
+void WebIDBCallbacksImpl::Success() {
if (!request_)
return;
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
request_->HandleResponse();
+ Detach();
}
-void WebIDBCallbacksImpl::OnSuccess(WebIDBKey key,
- WebIDBKey primary_key,
- WebIDBValue value) {
+void WebIDBCallbacksImpl::SuccessCursorContinue(
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> optional_value) {
if (!request_)
return;
probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success");
- std::unique_ptr<IDBValue> idb_value = value.ReleaseIdbValue();
- idb_value->SetIsolate(request_->GetIsolate());
- request_->HandleResponse(key.ReleaseIdbKey(), primary_key.ReleaseIdbKey(),
- std::move(idb_value));
+ std::unique_ptr<IDBValue> value;
+ if (optional_value.has_value()) {
+ value = std::move(optional_value.value());
+ } else {
+ value =
+ IDBValue::Create(scoped_refptr<SharedBuffer>(), Vector<WebBlobInfo>());
+ }
+ DCHECK(value);
+ value->SetIsolate(request_->GetIsolate());
+ request_->HandleResponse(std::move(key), std::move(primary_key),
+ std::move(value));
+ Detach();
}
-void WebIDBCallbacksImpl::OnBlocked(long long old_version) {
+void WebIDBCallbacksImpl::Blocked(int64_t old_version) {
if (!request_)
return;
@@ -210,14 +281,22 @@ void WebIDBCallbacksImpl::OnBlocked(long long old_version) {
DCHECK(!request_->TransactionHasQueuedResults());
#endif // DCHECK_IS_ON()
request_->EnqueueBlocked(old_version);
+ // Not resetting |request_|. In this instance we will have to forward at
+ // least one other call in the set UpgradeNeeded() / Success() /
+ // Error().
}
-void WebIDBCallbacksImpl::OnUpgradeNeeded(long long old_version,
- WebIDBDatabase* database,
- const WebIDBMetadata& metadata,
- mojom::IDBDataLoss data_loss,
- WebString data_loss_message) {
- std::unique_ptr<WebIDBDatabase> db = base::WrapUnique(database);
+void WebIDBCallbacksImpl::UpgradeNeeded(
+ mojom::blink::IDBDatabaseAssociatedPtrInfo database_info,
+ int64_t old_version,
+ mojom::IDBDataLoss data_loss,
+ const String& data_loss_message,
+ const IDBDatabaseMetadata& metadata) {
+ std::unique_ptr<WebIDBDatabase> db;
+ if (database_info.is_valid()) {
+ db = std::make_unique<WebIDBDatabaseImpl>(std::move(database_info),
+ task_runner_);
+ }
if (request_) {
probe::AsyncTask async_task(request_->GetExecutionContext(), this,
"upgradeNeeded");
@@ -227,13 +306,12 @@ void WebIDBCallbacksImpl::OnUpgradeNeeded(long long old_version,
request_->EnqueueUpgradeNeeded(old_version, std::move(db),
IDBDatabaseMetadata(metadata), data_loss,
data_loss_message);
- } else {
+ // Not resetting |request_|. In this instance we will have to forward at
+ // least one other call in the set UpgradeNeeded() / Success() /
+ // Error().
+ } else if (db) {
db->Close();
}
}
-void WebIDBCallbacksImpl::Detach() {
- request_.Clear();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
index 8cf4cb7ac8a..cc8dc628be5 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
@@ -31,56 +31,78 @@
#include <memory>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
+#include "base/memory/weak_ptr.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
+class IDBKey;
class IDBRequest;
-class WebIDBCursor;
-class WebIDBDatabase;
-class WebIDBDatabaseError;
-class WebIDBKey;
-struct WebIDBMetadata;
-struct WebIDBNameAndVersion;
-class WebIDBValue;
+class IDBValue;
+class WebIDBCursorImpl;
+struct IDBDatabaseMetadata;
class WebIDBCallbacksImpl final : public WebIDBCallbacks {
USING_FAST_MALLOC(WebIDBCallbacksImpl);
public:
+ // |kNoTransaction| is used as the default transaction ID when instantiating
+ // an WebIDBCallbacksImpl instance. See web_idb_factory_impl.cc for those
+ // cases.
+ enum : int64_t { kNoTransaction = -1 };
+
static std::unique_ptr<WebIDBCallbacksImpl> Create(IDBRequest*);
~WebIDBCallbacksImpl() override;
+ void SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
+ int64_t transaction_id) override;
+
// Pointers transfer ownership.
- void OnError(const WebIDBDatabaseError&) override;
- void OnSuccess(const WebVector<WebIDBNameAndVersion>&) override;
- void OnSuccess(const WebVector<WebString>&) override;
- void OnSuccess(WebIDBCursor*,
- WebIDBKey,
- WebIDBKey primary_key,
- WebIDBValue) override;
- void OnSuccess(WebIDBDatabase*, const WebIDBMetadata&) override;
- void OnSuccess(WebIDBKey) override;
- void OnSuccess(WebIDBValue) override;
- void OnSuccess(WebVector<WebIDBValue>) override;
- void OnSuccess(long long) override;
- void OnSuccess() override;
- void OnSuccess(WebIDBKey, WebIDBKey primary_key, WebIDBValue) override;
- void OnBlocked(long long old_version) override;
- void OnUpgradeNeeded(long long old_version,
- WebIDBDatabase*,
- const WebIDBMetadata&,
- mojom::IDBDataLoss data_loss,
- WebString data_loss_message) override;
- void Detach() override;
+ void Error(int32_t code, const String& message) override;
+ void SuccessNamesAndVersionsList(
+ Vector<mojom::blink::IDBNameAndVersionPtr>) override;
+ void SuccessStringList(const Vector<String>&) override;
+ void SuccessCursor(
+ mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>> optional_value) override;
+ void SuccessCursorPrefetch(Vector<std::unique_ptr<IDBKey>> keys,
+ Vector<std::unique_ptr<IDBKey>> primary_keys,
+ Vector<std::unique_ptr<IDBValue>> values) override;
+ void SuccessDatabase(mojom::blink::IDBDatabaseAssociatedPtrInfo database_info,
+ const IDBDatabaseMetadata& metadata) override;
+ void SuccessKey(std::unique_ptr<IDBKey>) override;
+ void SuccessValue(mojom::blink::IDBReturnValuePtr) override;
+ void SuccessArray(Vector<mojom::blink::IDBReturnValuePtr>) override;
+ void SuccessInteger(int64_t) override;
+ void Success() override;
+ void SuccessCursorContinue(
+ std::unique_ptr<IDBKey>,
+ std::unique_ptr<IDBKey> primary_key,
+ base::Optional<std::unique_ptr<IDBValue>>) override;
+ void Blocked(int64_t old_version) override;
+ void UpgradeNeeded(mojom::blink::IDBDatabaseAssociatedPtrInfo,
+ int64_t old_version,
+ mojom::IDBDataLoss data_loss,
+ const String& data_loss_message,
+ const IDBDatabaseMetadata&) override;
+ void DetachRequestFromCallback() override;
private:
explicit WebIDBCallbacksImpl(IDBRequest*);
+ void Detach();
+ void DetachCallbackFromRequest();
+
Persistent<IDBRequest> request_;
+ base::WeakPtr<WebIDBCursorImpl> cursor_;
+ int64_t transaction_id_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h
index 998daa93b4c..786a51f18d5 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h
@@ -27,9 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_CURSOR_H_
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
@@ -47,10 +45,10 @@ class MODULES_EXPORT WebIDBCursor {
// application. When both arguments are null, the cursor advances by one
// entry.
//
- // The keys pointed to by WebIDBKeyView are only guaranteed to be alive for
+ // The keys pointed to by IDBKey* are only guaranteed to be alive for
// the duration of the call.
- virtual void CursorContinue(WebIDBKeyView,
- WebIDBKeyView primary_key,
+ virtual void CursorContinue(const IDBKey*,
+ const IDBKey* primary_key,
WebIDBCallbacks*) = 0;
// Called after a cursor request's success handler is executed.
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
index c308cf7cab9..e65a8840ba8 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
@@ -11,17 +11,10 @@
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
-#include "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
-using blink::WebBlobInfo;
-using blink::WebData;
-using blink::WebIDBCallbacks;
-using blink::WebIDBKey;
-using blink::WebIDBKeyView;
-using blink::WebIDBValue;
using blink::mojom::blink::IDBCallbacksAssociatedPtrInfo;
using blink::mojom::blink::IDBCursorAssociatedPtrInfo;
@@ -29,14 +22,16 @@ namespace blink {
WebIDBCursorImpl::WebIDBCursorImpl(
mojom::blink::IDBCursorAssociatedPtrInfo cursor_info,
- int64_t transaction_id)
+ int64_t transaction_id,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: transaction_id_(transaction_id),
- cursor_(std::move(cursor_info)),
continue_count_(0),
used_prefetches_(0),
pending_onsuccess_callbacks_(0),
prefetch_amount_(kMinPrefetchAmount),
+ task_runner_(task_runner),
weak_factory_(this) {
+ cursor_.Bind(std::move(cursor_info), std::move(task_runner));
IndexedDBDispatcher::RegisterCursor(this);
}
@@ -56,21 +51,42 @@ void WebIDBCursorImpl::Advance(uint32_t count, WebIDBCallbacks* callbacks_ptr) {
}
ResetPrefetchCache();
- // Reset all cursor prefetch caches except for this cursor.
- IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id_, this);
+ callbacks->SetState(weak_factory_.GetWeakPtr(), transaction_id_);
+ cursor_->Advance(count,
+ WTF::Bind(&WebIDBCursorImpl::AdvanceCallback,
+ WTF::Unretained(this), std::move(callbacks)));
+}
+
+void WebIDBCursorImpl::AdvanceCallback(
+ std::unique_ptr<WebIDBCallbacks> callbacks,
+ mojom::blink::IDBErrorPtr error,
+ mojom::blink::IDBCursorValuePtr cursor_value) {
+ if (error) {
+ callbacks->Error(error->error_code, error->error_message);
+ callbacks.reset();
+ return;
+ }
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
- cursor_->Advance(count, GetCallbacksProxy(std::move(callbacks_impl)));
+ if (!cursor_value) {
+ callbacks->SuccessValue(nullptr);
+ callbacks.reset();
+ return;
+ }
+
+ callbacks->SuccessCursorContinue(std::move(cursor_value->key),
+ std::move(cursor_value->primary_key),
+ std::move(cursor_value->value));
+ callbacks.reset();
}
-void WebIDBCursorImpl::CursorContinue(WebIDBKeyView key,
- WebIDBKeyView primary_key,
+void WebIDBCursorImpl::CursorContinue(const IDBKey* key,
+ const IDBKey* primary_key,
WebIDBCallbacks* callbacks_ptr) {
+ DCHECK(key && primary_key);
std::unique_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
- if (key.KeyType() == kWebIDBKeyTypeNull &&
- primary_key.KeyType() == kWebIDBKeyTypeNull) {
+ if (key->GetType() == mojom::IDBKeyType::Null &&
+ primary_key->GetType() == mojom::IDBKeyType::Null) {
// No key(s), so this would qualify for a prefetch.
++continue_count_;
@@ -84,10 +100,9 @@ void WebIDBCursorImpl::CursorContinue(WebIDBKeyView key,
// Request pre-fetch.
++pending_onsuccess_callbacks_;
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
+ callbacks->SetState(weak_factory_.GetWeakPtr(), transaction_id_);
cursor_->Prefetch(prefetch_amount_,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ GetCallbacksProxy(std::move(callbacks)));
// Increase prefetch_amount_ exponentially.
prefetch_amount_ *= 2;
@@ -101,14 +116,9 @@ void WebIDBCursorImpl::CursorContinue(WebIDBKeyView key,
ResetPrefetchCache();
}
- // Reset all cursor prefetch caches except for this cursor.
- IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id_, this);
-
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
- cursor_->CursorContinue(WebIDBKeyBuilder::Build(key),
- WebIDBKeyBuilder::Build(primary_key),
- GetCallbacksProxy(std::move(callbacks_impl)));
+ callbacks->SetState(weak_factory_.GetWeakPtr(), transaction_id_);
+ cursor_->CursorContinue(IDBKey::Clone(key), IDBKey::Clone(primary_key),
+ GetCallbacksProxy(std::move(callbacks)));
}
void WebIDBCursorImpl::PostSuccessHandlerCallback() {
@@ -124,9 +134,10 @@ void WebIDBCursorImpl::PostSuccessHandlerCallback() {
ResetPrefetchCache();
}
-void WebIDBCursorImpl::SetPrefetchData(Vector<WebIDBKey> keys,
- Vector<WebIDBKey> primary_keys,
- Vector<WebIDBValue> values) {
+void WebIDBCursorImpl::SetPrefetchData(
+ Vector<std::unique_ptr<IDBKey>> keys,
+ Vector<std::unique_ptr<IDBKey>> primary_keys,
+ Vector<std::unique_ptr<IDBValue>> values) {
// Keys and values are stored in reverse order so that a cache'd continue can
// pop a value off of the back and prevent new memory allocations.
prefetch_keys_.AppendRange(std::make_move_iterator(keys.rbegin()),
@@ -165,9 +176,10 @@ void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks* callbacks) {
// Keys and values are stored in reverse order so that a cache'd continue can
// pop a value off of the back and prevent new memory allocations.
- WebIDBKey key = std::move(prefetch_keys_.back());
- WebIDBKey primary_key = std::move(prefetch_primary_keys_.back());
- WebIDBValue value = std::move(prefetch_values_.back());
+ std::unique_ptr<IDBKey> key = std::move(prefetch_keys_.back());
+ std::unique_ptr<IDBKey> primary_key =
+ std::move(prefetch_primary_keys_.back());
+ std::unique_ptr<IDBValue> value = std::move(prefetch_values_.back());
prefetch_keys_.pop_back();
prefetch_primary_keys_.pop_back();
@@ -184,8 +196,8 @@ void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks* callbacks) {
ResetPrefetchCache();
}
- callbacks->OnSuccess(std::move(key), std::move(primary_key),
- std::move(value));
+ callbacks->SuccessCursorContinue(std::move(key), std::move(primary_key),
+ std::move(value));
}
void WebIDBCursorImpl::ResetPrefetchCache() {
@@ -209,10 +221,11 @@ void WebIDBCursorImpl::ResetPrefetchCache() {
}
IDBCallbacksAssociatedPtrInfo WebIDBCursorImpl::GetCallbacksProxy(
- std::unique_ptr<IndexedDBCallbacksImpl> callbacks) {
+ std::unique_ptr<WebIDBCallbacks> callbacks) {
IDBCallbacksAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
- mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request));
+ mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request),
+ task_runner_);
return ptr_info;
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
index 58e953fa26e..746c8d5b450 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
@@ -10,33 +10,31 @@
#include <vector>
#include "base/gtest_prod_util.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
-class IndexedDBCallbacksImpl;
-
class MODULES_EXPORT WebIDBCursorImpl : public WebIDBCursor {
public:
WebIDBCursorImpl(mojom::blink::IDBCursorAssociatedPtrInfo cursor,
- int64_t transaction_id);
+ int64_t transaction_id,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~WebIDBCursorImpl() override;
void Advance(uint32_t count, WebIDBCallbacks* callback) override;
- void CursorContinue(WebIDBKeyView key,
- WebIDBKeyView primary_key,
+
+ void CursorContinue(const IDBKey* key,
+ const IDBKey* primary_key,
WebIDBCallbacks* callback) override;
void PostSuccessHandlerCallback() override;
- void SetPrefetchData(Vector<WebIDBKey> keys,
- Vector<WebIDBKey> primary_keys,
- Vector<WebIDBValue> values);
+ void SetPrefetchData(Vector<std::unique_ptr<IDBKey>> keys,
+ Vector<std::unique_ptr<IDBKey>> primary_keys,
+ Vector<std::unique_ptr<IDBValue>> values);
void CachedAdvance(unsigned long count, WebIDBCallbacks* callbacks);
void CachedContinue(WebIDBCallbacks* callbacks);
@@ -47,8 +45,11 @@ class MODULES_EXPORT WebIDBCursorImpl : public WebIDBCursor {
int64_t transaction_id() const { return transaction_id_; }
private:
+ void AdvanceCallback(std::unique_ptr<WebIDBCallbacks> callbacks,
+ mojom::blink::IDBErrorPtr error,
+ mojom::blink::IDBCursorValuePtr value);
mojom::blink::IDBCallbacksAssociatedPtrInfo GetCallbacksProxy(
- std::unique_ptr<IndexedDBCallbacksImpl> callbacks);
+ std::unique_ptr<WebIDBCallbacks> callbacks);
FRIEND_TEST_ALL_PREFIXES(IndexedDBDispatcherTest, CursorReset);
FRIEND_TEST_ALL_PREFIXES(IndexedDBDispatcherTest, CursorTransactionId);
@@ -67,9 +68,9 @@ class MODULES_EXPORT WebIDBCursorImpl : public WebIDBCursor {
// Prefetch cache. Keys and values are stored in reverse order so that a
// cache'd continue can pop a value off of the back and prevent new memory
// allocations.
- Vector<WebIDBKey> prefetch_keys_;
- Vector<WebIDBKey> prefetch_primary_keys_;
- Vector<WebIDBValue> prefetch_values_;
+ Vector<std::unique_ptr<IDBKey>> prefetch_keys_;
+ Vector<std::unique_ptr<IDBKey>> prefetch_primary_keys_;
+ Vector<std::unique_ptr<IDBValue>> prefetch_values_;
// Number of continue calls that would qualify for a pre-fetch.
int continue_count_;
@@ -83,6 +84,8 @@ class MODULES_EXPORT WebIDBCursorImpl : public WebIDBCursor {
// Number of items to request in next prefetch.
int prefetch_amount_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
base::WeakPtrFactory<WebIDBCursorImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImpl);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc
index 76fa9b2ad2b..8ddd4e5b2e4 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc
@@ -12,9 +12,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
-#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -46,13 +44,15 @@ class MockCursorImpl : public mojom::blink::IDBCursor {
}
void Advance(uint32_t count,
- mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {
+ mojom::blink::IDBCursor::AdvanceCallback callback) override {
++advance_calls_;
+ std::move(callback).Run(mojom::blink::IDBErrorPtr(),
+ mojom::blink::IDBCursorValuePtr());
}
void CursorContinue(
- WebIDBKey key,
- WebIDBKey primary_key,
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primary_key,
mojom::blink::IDBCallbacksAssociatedPtrInfo callbacks) override {
++continue_calls_;
}
@@ -81,38 +81,45 @@ class MockCursorImpl : public mojom::blink::IDBCursor {
class MockContinueCallbacks : public testing::StrictMock<MockWebIDBCallbacks> {
public:
- MockContinueCallbacks(IndexedDBKey* key = nullptr,
- WebVector<WebBlobInfo>* blobs = nullptr)
+ MockContinueCallbacks(std::unique_ptr<IDBKey>* key = nullptr,
+ Vector<WebBlobInfo>* blobs = nullptr)
: key_(key), blobs_(blobs) {}
- void OnSuccess(WebIDBKey key,
- WebIDBKey primaryKey,
- WebIDBValue value) override {
+ void SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
+ int64_t transaction_id) override {}
+ void SuccessValue(mojom::blink::IDBReturnValuePtr return_value) override {}
+
+ void SuccessCursorContinue(
+ std::unique_ptr<IDBKey> key,
+ std::unique_ptr<IDBKey> primaryKey,
+ base::Optional<std::unique_ptr<IDBValue>> value) override {
if (key_)
- *key_ = IndexedDBKeyBuilder::Build(key.View());
- if (blobs_)
- *blobs_ = value.BlobInfoForTesting();
+ *key_ = IDBKey::Clone(key);
+ if (blobs_ && value.has_value())
+ *blobs_ = value.value()->BlobInfo();
}
private:
- IndexedDBKey* key_;
- WebVector<WebBlobInfo>* blobs_;
+ std::unique_ptr<IDBKey>* key_;
+ Vector<WebBlobInfo>* blobs_;
};
} // namespace
class WebIDBCursorImplTest : public testing::Test {
public:
- WebIDBCursorImplTest() : null_key_(WebIDBKey::CreateNull()) {
+ WebIDBCursorImplTest() : null_key_(IDBKey::CreateNull()) {
mojom::blink::IDBCursorAssociatedPtr ptr;
mock_cursor_ = std::make_unique<MockCursorImpl>(
mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr));
- cursor_ = std::make_unique<WebIDBCursorImpl>(ptr.PassInterface(), 1);
+ cursor_ = std::make_unique<WebIDBCursorImpl>(
+ ptr.PassInterface(), 1,
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
}
protected:
ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
- WebIDBKey null_key_;
+ std::unique_ptr<IDBKey> null_key_;
std::unique_ptr<WebIDBCursorImpl> cursor_;
std::unique_ptr<MockCursorImpl> mock_cursor_;
@@ -125,7 +132,7 @@ TEST_F(WebIDBCursorImplTest, PrefetchTest) {
int continue_calls = 0;
EXPECT_EQ(mock_cursor_->continue_calls(), 0);
for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) {
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks());
platform_->RunUntilIdle();
EXPECT_EQ(++continue_calls, mock_cursor_->continue_calls());
@@ -140,7 +147,7 @@ TEST_F(WebIDBCursorImplTest, PrefetchTest) {
int last_prefetch_count = 0;
for (int repetitions = 0; repetitions < kPrefetchRepetitions; ++repetitions) {
// Initiate the prefetch
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks());
platform_->RunUntilIdle();
EXPECT_EQ(continue_calls, mock_cursor_->continue_calls());
@@ -152,24 +159,25 @@ TEST_F(WebIDBCursorImplTest, PrefetchTest) {
last_prefetch_count = prefetch_count;
// Fill the prefetch cache as requested.
- Vector<WebIDBKey> keys;
- Vector<WebIDBKey> primary_keys;
- Vector<WebIDBValue> values;
+ Vector<std::unique_ptr<IDBKey>> keys;
+ Vector<std::unique_ptr<IDBKey>> primary_keys;
+ Vector<std::unique_ptr<IDBValue>> values;
size_t expected_size = 0;
for (int i = 0; i < prefetch_count; ++i) {
- WebIDBKey key = WebIDBKey::CreateNumber(expected_key + i);
+ std::unique_ptr<IDBKey> key = IDBKey::CreateNumber(expected_key + i);
keys.emplace_back(std::move(key));
primary_keys.emplace_back();
expected_size++;
EXPECT_EQ(expected_size, keys.size());
EXPECT_EQ(expected_size, primary_keys.size());
- WebVector<WebBlobInfo> blob_info;
- blob_info.reserve(expected_key + i);
+ Vector<WebBlobInfo> blob_info;
+ blob_info.ReserveInitialCapacity(expected_key + i);
for (int j = 0; j < expected_key + i; ++j) {
blob_info.emplace_back(WebBlobInfo::BlobForTesting(
WebString("blobuuid"), "text/plain", 123));
}
- values.emplace_back(WebData(), std::move(blob_info));
+ values.emplace_back(IDBValue::Create(scoped_refptr<SharedBuffer>(),
+ std::move(blob_info)));
}
cursor_->SetPrefetchData(std::move(keys), std::move(primary_keys),
std::move(values));
@@ -180,17 +188,17 @@ TEST_F(WebIDBCursorImplTest, PrefetchTest) {
// Verify that the cache is used for subsequent continue() calls.
for (int i = 0; i < prefetch_count; ++i) {
- IndexedDBKey key;
- WebVector<WebBlobInfo> blobs;
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ std::unique_ptr<IDBKey> key;
+ Vector<WebBlobInfo> blobs;
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks(&key, &blobs));
platform_->RunUntilIdle();
EXPECT_EQ(continue_calls, mock_cursor_->continue_calls());
EXPECT_EQ(repetitions + 1, mock_cursor_->prefetch_calls());
- EXPECT_EQ(kWebIDBKeyTypeNumber, key.type());
+ EXPECT_EQ(mojom::IDBKeyType::Number, key->GetType());
EXPECT_EQ(expected_key, static_cast<int>(blobs.size()));
- EXPECT_EQ(expected_key++, key.number());
+ EXPECT_EQ(expected_key++, key->Number());
}
}
@@ -203,14 +211,14 @@ TEST_F(WebIDBCursorImplTest, AdvancePrefetchTest) {
// Call continue() until prefetching should kick in.
EXPECT_EQ(0, mock_cursor_->continue_calls());
for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) {
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks());
}
platform_->RunUntilIdle();
EXPECT_EQ(0, mock_cursor_->prefetch_calls());
// Initiate the prefetch
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks());
platform_->RunUntilIdle();
@@ -223,24 +231,25 @@ TEST_F(WebIDBCursorImplTest, AdvancePrefetchTest) {
// Fill the prefetch cache as requested.
int expected_key = 0;
- Vector<WebIDBKey> keys;
- Vector<WebIDBKey> primary_keys;
- Vector<WebIDBValue> values;
+ Vector<std::unique_ptr<IDBKey>> keys;
+ Vector<std::unique_ptr<IDBKey>> primary_keys;
+ Vector<std::unique_ptr<IDBValue>> values;
size_t expected_size = 0;
for (int i = 0; i < prefetch_count; ++i) {
- WebIDBKey key = WebIDBKey::CreateNumber(expected_key + i);
+ std::unique_ptr<IDBKey> key = IDBKey::CreateNumber(expected_key + i);
keys.emplace_back(std::move(key));
primary_keys.emplace_back();
expected_size++;
EXPECT_EQ(expected_size, keys.size());
EXPECT_EQ(expected_size, primary_keys.size());
- WebVector<WebBlobInfo> blob_info;
- blob_info.reserve(expected_key + i);
+ Vector<WebBlobInfo> blob_info;
+ blob_info.ReserveInitialCapacity(expected_key + i);
for (int j = 0; j < expected_key + i; ++j) {
blob_info.emplace_back(WebBlobInfo::BlobForTesting(WebString("blobuuid"),
"text/plain", 123));
}
- values.emplace_back(WebData(), std::move(blob_info));
+ values.emplace_back(
+ IDBValue::Create(scoped_refptr<SharedBuffer>(), std::move(blob_info)));
}
cursor_->SetPrefetchData(std::move(keys), std::move(primary_keys),
std::move(values));
@@ -253,27 +262,27 @@ TEST_F(WebIDBCursorImplTest, AdvancePrefetchTest) {
ASSERT_GE(prefetch_count, 5);
// IDBCursor.continue()
- IndexedDBKey key;
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ std::unique_ptr<IDBKey> key;
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks(&key));
platform_->RunUntilIdle();
- EXPECT_EQ(0, key.number());
+ EXPECT_EQ(0, key->Number());
// IDBCursor.advance(1)
cursor_->Advance(1, new MockContinueCallbacks(&key));
platform_->RunUntilIdle();
- EXPECT_EQ(1, key.number());
+ EXPECT_EQ(1, key->Number());
// IDBCursor.continue()
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks(&key));
platform_->RunUntilIdle();
- EXPECT_EQ(2, key.number());
+ EXPECT_EQ(2, key->Number());
// IDBCursor.advance(2)
cursor_->Advance(2, new MockContinueCallbacks(&key));
platform_->RunUntilIdle();
- EXPECT_EQ(4, key.number());
+ EXPECT_EQ(4, key->Number());
EXPECT_EQ(0, mock_cursor_->advance_calls());
@@ -296,7 +305,7 @@ TEST_F(WebIDBCursorImplTest, PrefetchReset) {
int continue_calls = 0;
EXPECT_EQ(mock_cursor_->continue_calls(), 0);
for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) {
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks());
platform_->RunUntilIdle();
EXPECT_EQ(++continue_calls, mock_cursor_->continue_calls());
@@ -304,7 +313,7 @@ TEST_F(WebIDBCursorImplTest, PrefetchReset) {
}
// Initiate the prefetch
- cursor_->CursorContinue(null_key_.View(), null_key_.View(),
+ cursor_->CursorContinue(null_key_.get(), null_key_.get(),
new MockContinueCallbacks());
platform_->RunUntilIdle();
EXPECT_EQ(continue_calls, mock_cursor_->continue_calls());
@@ -320,11 +329,13 @@ TEST_F(WebIDBCursorImplTest, PrefetchReset) {
// Fill the prefetch cache as requested.
int prefetch_count = mock_cursor_->last_prefetch_count();
- Vector<WebIDBKey> keys(prefetch_count);
- Vector<WebIDBKey> primary_keys(prefetch_count);
- Vector<WebIDBValue> values;
- for (int i = 0; i < prefetch_count; ++i)
- values.emplace_back(WebData(), WebVector<WebBlobInfo>());
+ Vector<std::unique_ptr<IDBKey>> keys(prefetch_count);
+ Vector<std::unique_ptr<IDBKey>> primary_keys(prefetch_count);
+ Vector<std::unique_ptr<IDBValue>> values;
+ for (int i = 0; i < prefetch_count; ++i) {
+ values.emplace_back(
+ IDBValue::Create(scoped_refptr<SharedBuffer>(), Vector<WebBlobInfo>()));
+ }
cursor_->SetPrefetchData(std::move(keys), std::move(primary_keys),
std::move(values));
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h
index c98ae6098ff..f2b70896ae3 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h
@@ -30,18 +30,14 @@
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
-#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
-class WebData;
+class IDBKeyRange;
class WebIDBCallbacks;
-class WebIDBKeyPath;
-class WebIDBKeyRange;
class MODULES_EXPORT WebIDBDatabase {
public:
@@ -50,7 +46,7 @@ class MODULES_EXPORT WebIDBDatabase {
virtual void CreateObjectStore(long long transaction_id,
long long object_store_id,
const String& name,
- const WebIDBKeyPath&,
+ const IDBKeyPath&,
bool auto_increment) = 0;
virtual void DeleteObjectStore(long long transaction_id,
long long object_store_id) = 0;
@@ -64,13 +60,14 @@ class MODULES_EXPORT WebIDBDatabase {
virtual void VersionChangeIgnored() = 0;
virtual void Abort(long long transaction_id) = 0;
- virtual void Commit(long long transaction_id) = 0;
+ virtual void Commit(long long transaction_id,
+ long long num_errors_handled) = 0;
virtual void CreateIndex(long long transaction_id,
long long object_store_id,
long long index_id,
const String& name,
- const WebIDBKeyPath&,
+ const IDBKeyPath&,
bool unique,
bool multi_entry) = 0;
virtual void DeleteIndex(long long transaction_id,
@@ -95,35 +92,34 @@ class MODULES_EXPORT WebIDBDatabase {
virtual void Get(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
bool key_only,
WebIDBCallbacks*) = 0;
virtual void GetAll(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
long long max_count,
bool key_only,
WebIDBCallbacks*) = 0;
virtual void Put(long long transaction_id,
long long object_store_id,
- const WebData& value,
- const Vector<WebBlobInfo>&,
- WebIDBKeyView primary_key,
+ std::unique_ptr<IDBValue> value,
+ std::unique_ptr<IDBKey> primary_key,
mojom::IDBPutMode,
WebIDBCallbacks*,
- const Vector<WebIDBIndexKeys>&) = 0;
+ Vector<IDBIndexKeys>) = 0;
virtual void SetIndexKeys(long long transaction_id,
long long object_store_id,
- WebIDBKeyView primary_key,
- const Vector<WebIDBIndexKeys>&) = 0;
+ std::unique_ptr<IDBKey> primary_key,
+ Vector<IDBIndexKeys>) = 0;
virtual void SetIndexesReady(long long transaction_id,
long long object_store_id,
const Vector<int64_t>& index_ids) = 0;
virtual void OpenCursor(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
mojom::IDBCursorDirection,
bool key_only,
mojom::IDBTaskType,
@@ -131,15 +127,15 @@ class MODULES_EXPORT WebIDBDatabase {
virtual void Count(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
WebIDBCallbacks*) = 0;
virtual void Delete(long long transaction_id,
long long object_store_id,
- WebIDBKeyView primary_key,
+ const IDBKey* primary_key,
WebIDBCallbacks*) = 0;
virtual void DeleteRange(long long transaction_id,
long long object_store_id,
- const WebIDBKeyRange&,
+ const IDBKeyRange*,
WebIDBCallbacks*) = 0;
virtual void Clear(long long transaction_id,
long long object_store_id,
diff --git a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h
index deac9f44d73..88a5513961c 100644
--- a/chromium/third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h
@@ -23,28 +23,28 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_DATABASE_CALLBACKS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_DATABASE_CALLBACKS_H_
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_vector.h"
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_DATABASE_CALLBACKS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_DATABASE_CALLBACKS_H_
#include <unordered_map>
#include <utility>
#include <vector>
+#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
namespace blink {
-struct WebIDBObservation;
+class IDBObservation;
class WebIDBDatabaseCallbacks {
public:
- using ObservationIndexMap = std::unordered_map<int32_t, WebVector<int32_t>>;
+ using ObservationIndexMap = std::unordered_map<int32_t, Vector<int32_t>>;
// Maps observer to transaction, which needs an id and a scope.
using TransactionMap =
- std::unordered_map<int32_t, std::pair<int64_t, WebVector<int64_t>>>;
+ std::unordered_map<int32_t, std::pair<int64_t, Vector<int64_t>>>;
virtual ~WebIDBDatabaseCallbacks() = default;
@@ -52,15 +52,14 @@ class WebIDBDatabaseCallbacks {
virtual void OnVersionChange(long long old_version,
long long new_version) = 0;
- virtual void OnAbort(long long transaction_id,
- const WebIDBDatabaseError&) = 0;
+ virtual void OnAbort(long long transaction_id, const IDBDatabaseError&) = 0;
virtual void OnComplete(long long transaction_id) = 0;
virtual void OnChanges(const ObservationIndexMap&,
- WebVector<WebIDBObservation> observations,
+ Vector<Persistent<IDBObservation>> observations,
const TransactionMap& transactions) = 0;
virtual void Detach() = 0;
};
} // namespace blink
-#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_DATABASE_CALLBACKS_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_DATABASE_CALLBACKS_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc
index fc7c46b8722..ec213953425 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc
@@ -29,12 +29,8 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
-
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
-#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
@@ -68,7 +64,7 @@ void WebIDBDatabaseCallbacksImpl::OnVersionChange(long long old_version,
}
void WebIDBDatabaseCallbacksImpl::OnAbort(long long transaction_id,
- const WebIDBDatabaseError& error) {
+ const IDBDatabaseError& error) {
if (callbacks_) {
callbacks_->OnAbort(
transaction_id,
@@ -84,7 +80,7 @@ void WebIDBDatabaseCallbacksImpl::OnComplete(long long transaction_id) {
void WebIDBDatabaseCallbacksImpl::OnChanges(
const ObservationIndexMap& observation_index_map,
- WebVector<WebIDBObservation> observations,
+ Vector<Persistent<IDBObservation>> observations,
const TransactionMap& transactions) {
if (callbacks_) {
callbacks_->OnChanges(observation_index_map, std::move(observations),
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h
index 0bd37944e50..e4cd614c2cc 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h
@@ -28,12 +28,8 @@
#include <memory>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_observation.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -50,10 +46,10 @@ class WebIDBDatabaseCallbacksImpl final : public WebIDBDatabaseCallbacks {
void OnForcedClose() override;
void OnVersionChange(long long old_version, long long new_version) override;
- void OnAbort(long long transaction_id, const WebIDBDatabaseError&) override;
+ void OnAbort(long long transaction_id, const IDBDatabaseError&) override;
void OnComplete(long long transaction_id) override;
void OnChanges(const ObservationIndexMap&,
- WebVector<WebIDBObservation> observations,
+ Vector<Persistent<IDBObservation>> observations,
const TransactionMap& transactions) override;
void Detach() override;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc
index c41c23e249f..c8f5339954e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc
@@ -4,40 +4,30 @@
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h"
-#include <stddef.h>
-
-#include <string>
-#include <vector>
-
#include "base/format_macros.h"
-#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
-#include "third_party/blink/public/platform/file_path_conversion.h"
-#include "third_party/blink/public/platform/modules/indexeddb/indexed_db_key_builder.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_path.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
-#include "third_party/blink/public/platform/web_blob_info.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h"
+#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_dispatcher.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
WebIDBDatabaseImpl::WebIDBDatabaseImpl(
- mojom::blink::IDBDatabaseAssociatedPtrInfo database_info)
- : database_(std::move(database_info)) {}
+ mojom::blink::IDBDatabaseAssociatedPtrInfo database_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {
+ database_.Bind(std::move(database_info), task_runner_);
+}
WebIDBDatabaseImpl::~WebIDBDatabaseImpl() = default;
void WebIDBDatabaseImpl::CreateObjectStore(long long transaction_id,
long long object_store_id,
const String& name,
- const WebIDBKeyPath& key_path,
+ const IDBKeyPath& key_path,
bool auto_increment) {
database_->CreateObjectStore(transaction_id, object_store_id, name, key_path,
auto_increment);
@@ -90,116 +80,76 @@ void WebIDBDatabaseImpl::RemoveObservers(const Vector<int32_t>& observer_ids) {
void WebIDBDatabaseImpl::Get(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange& key_range,
+ const IDBKeyRange* key_range,
bool key_only,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
- database_->Get(transaction_id, object_store_id, index_id, key_range, key_only,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ mojom::blink::IDBKeyRangePtr key_range_ptr =
+ mojom::blink::IDBKeyRange::From(key_range);
+ callbacks->SetState(nullptr, transaction_id);
+ database_->Get(transaction_id, object_store_id, index_id,
+ std::move(key_range_ptr), key_only,
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::GetAll(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange& key_range,
+ const IDBKeyRange* key_range,
long long max_count,
bool key_only,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
- database_->GetAll(transaction_id, object_store_id, index_id, key_range,
- key_only, max_count,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ mojom::blink::IDBKeyRangePtr key_range_ptr =
+ mojom::blink::IDBKeyRange::From(key_range);
+ callbacks->SetState(nullptr, transaction_id);
+ database_->GetAll(transaction_id, object_store_id, index_id,
+ std::move(key_range_ptr), key_only, max_count,
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::Put(long long transaction_id,
long long object_store_id,
- const WebData& value,
- const Vector<WebBlobInfo>& web_blob_info,
- WebIDBKeyView web_primary_key,
+ std::unique_ptr<IDBValue> value,
+ std::unique_ptr<IDBKey> primary_key,
mojom::IDBPutMode put_mode,
WebIDBCallbacks* callbacks,
- const Vector<WebIDBIndexKeys>& index_keys) {
- WebIDBKey primary_key = WebIDBKeyBuilder::Build(web_primary_key);
-
+ Vector<IDBIndexKeys> index_keys) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto mojo_value = mojom::blink::IDBValue::New();
-
- // mojo_value->bits initialization.
- value.ForEachSegment([&mojo_value](const char* segment, size_t segment_size,
- size_t segment_offset) {
- const auto& segment_span = base::make_span(segment, segment + segment_size);
- mojo_value->bits.AppendRange(segment_span.begin(), segment_span.end());
- return true;
- });
-
- // mojo_value->blob_or_file_info initialization.
- mojo_value->blob_or_file_info.ReserveInitialCapacity(web_blob_info.size());
- for (const WebBlobInfo& info : web_blob_info) {
- auto blob_info = mojom::blink::IDBBlobInfo::New();
- if (info.IsFile()) {
- blob_info->file = mojom::blink::IDBFileInfo::New();
- blob_info->file->path = WebStringToFilePath(info.FilePath());
- String name = info.FileName();
- if (name.IsNull())
- name = g_empty_string;
- blob_info->file->name = name;
- blob_info->file->last_modified =
- base::Time::FromDoubleT(info.LastModified());
- }
- blob_info->size = info.size();
- blob_info->uuid = info.Uuid();
- DCHECK(!blob_info->uuid.IsEmpty());
- String mime_type = info.GetType();
- if (mime_type.IsNull())
- mime_type = g_empty_string;
- blob_info->mime_type = mime_type;
- blob_info->blob = mojom::blink::BlobPtrInfo(info.CloneBlobHandle(),
- mojom::blink::Blob::Version_);
- mojo_value->blob_or_file_info.push_back(std::move(blob_info));
- }
-
size_t index_keys_size = 0;
for (const auto& index_key : index_keys) {
index_keys_size++; // Account for index_key.first (int64_t).
for (const auto& key : index_key.second) {
- index_keys_size += key.SizeEstimate();
+ index_keys_size += key->SizeEstimate();
}
}
size_t arg_size =
- mojo_value->bits.size() + primary_key.SizeEstimate() + index_keys_size;
+ value->DataSize() + primary_key->SizeEstimate() + index_keys_size;
if (arg_size >= max_put_value_size_) {
- callbacks->OnError(blink::WebIDBDatabaseError(
+ callbacks->Error(
blink::kWebIDBDatabaseExceptionUnknownError,
- WebString(
- String::Format("The serialized keys and/or value are too large"
- " (size=%" PRIuS " bytes, max=%" PRIuS " bytes).",
- arg_size, max_put_value_size_))));
+ String::Format("The serialized keys and/or value are too large"
+ " (size=%" PRIuS " bytes, max=%" PRIuS " bytes).",
+ arg_size, max_put_value_size_));
return;
}
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
- database_->Put(transaction_id, object_store_id, std::move(mojo_value),
- std::move(primary_key), put_mode, index_keys,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ callbacks->SetState(nullptr, transaction_id);
+ database_->Put(transaction_id, object_store_id, std::move(value),
+ std::move(primary_key), put_mode, std::move(index_keys),
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
-void WebIDBDatabaseImpl::SetIndexKeys(
- long long transaction_id,
- long long object_store_id,
- WebIDBKeyView primary_key,
- const Vector<WebIDBIndexKeys>& index_keys) {
- IndexedDBKey temp(IndexedDBKeyBuilder::Build(primary_key));
+void WebIDBDatabaseImpl::SetIndexKeys(long long transaction_id,
+ long long object_store_id,
+ std::unique_ptr<IDBKey> primary_key,
+ Vector<IDBIndexKeys> index_keys) {
database_->SetIndexKeys(transaction_id, object_store_id,
- WebIDBKeyBuilder::Build(temp), std::move(index_keys));
+ std::move(primary_key), std::move(index_keys));
}
void WebIDBDatabaseImpl::SetIndexesReady(long long transaction_id,
@@ -212,56 +162,63 @@ void WebIDBDatabaseImpl::SetIndexesReady(long long transaction_id,
void WebIDBDatabaseImpl::OpenCursor(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange& key_range,
+ const IDBKeyRange* key_range,
mojom::IDBCursorDirection direction,
bool key_only,
mojom::IDBTaskType task_type,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
- database_->OpenCursor(transaction_id, object_store_id, index_id, key_range,
- direction, key_only, task_type,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ mojom::blink::IDBKeyRangePtr key_range_ptr =
+ mojom::blink::IDBKeyRange::From(key_range);
+ callbacks->SetState(nullptr, transaction_id);
+ database_->OpenCursor(transaction_id, object_store_id, index_id,
+ std::move(key_range_ptr), direction, key_only,
+ task_type,
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::Count(long long transaction_id,
long long object_store_id,
long long index_id,
- const WebIDBKeyRange& key_range,
+ const IDBKeyRange* key_range,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
- database_->Count(transaction_id, object_store_id, index_id, key_range,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ mojom::blink::IDBKeyRangePtr key_range_ptr =
+ mojom::blink::IDBKeyRange::From(key_range);
+ callbacks->SetState(nullptr, transaction_id);
+ database_->Count(transaction_id, object_store_id, index_id,
+ std::move(key_range_ptr),
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::Delete(long long transaction_id,
long long object_store_id,
- WebIDBKeyView primary_key,
+ const IDBKey* primary_key,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
+ mojom::blink::IDBKeyRangePtr key_range_ptr =
+ mojom::blink::IDBKeyRange::From(IDBKeyRange::Create(primary_key));
+ callbacks->SetState(nullptr, transaction_id);
database_->DeleteRange(transaction_id, object_store_id,
- WebIDBKeyRangeBuilder::Build(primary_key),
- GetCallbacksProxy(std::move(callbacks_impl)));
+ std::move(key_range_ptr),
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::DeleteRange(long long transaction_id,
long long object_store_id,
- const WebIDBKeyRange& key_range,
+ const IDBKeyRange* key_range,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
- database_->DeleteRange(transaction_id, object_store_id, key_range,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ mojom::blink::IDBKeyRangePtr key_range_ptr =
+ mojom::blink::IDBKeyRange::From(key_range);
+ callbacks->SetState(nullptr, transaction_id);
+ database_->DeleteRange(transaction_id, object_store_id,
+ std::move(key_range_ptr),
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::Clear(long long transaction_id,
@@ -269,17 +226,16 @@ void WebIDBDatabaseImpl::Clear(long long transaction_id,
WebIDBCallbacks* callbacks) {
IndexedDBDispatcher::ResetCursorPrefetchCaches(transaction_id, nullptr);
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
+ callbacks->SetState(nullptr, transaction_id);
database_->Clear(transaction_id, object_store_id,
- GetCallbacksProxy(std::move(callbacks_impl)));
+ GetCallbacksProxy(base::WrapUnique(callbacks)));
}
void WebIDBDatabaseImpl::CreateIndex(long long transaction_id,
long long object_store_id,
long long index_id,
const String& name,
- const WebIDBKeyPath& key_path,
+ const IDBKeyPath& key_path,
bool unique,
bool multi_entry) {
database_->CreateIndex(transaction_id, object_store_id, index_id, name,
@@ -304,16 +260,18 @@ void WebIDBDatabaseImpl::Abort(long long transaction_id) {
database_->Abort(transaction_id);
}
-void WebIDBDatabaseImpl::Commit(long long transaction_id) {
- database_->Commit(transaction_id);
+void WebIDBDatabaseImpl::Commit(long long transaction_id,
+ long long num_errors_handled) {
+ database_->Commit(transaction_id, num_errors_handled);
}
mojom::blink::IDBCallbacksAssociatedPtrInfo
WebIDBDatabaseImpl::GetCallbacksProxy(
- std::unique_ptr<IndexedDBCallbacksImpl> callbacks) {
+ std::unique_ptr<WebIDBCallbacks> callbacks) {
mojom::blink::IDBCallbacksAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
- mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request));
+ mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request),
+ task_runner_);
return ptr_info;
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h
index b4df30eb822..a69c90e0951 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h
@@ -17,20 +17,19 @@
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
-class IndexedDBCallbacksImpl;
-class WebBlobInfo;
class WebIDBCallbacks;
-class MODULES_EXPORT WebIDBDatabaseImpl : public blink::WebIDBDatabase {
+class MODULES_EXPORT WebIDBDatabaseImpl : public WebIDBDatabase {
public:
- WebIDBDatabaseImpl(mojom::blink::IDBDatabaseAssociatedPtrInfo database);
+ WebIDBDatabaseImpl(mojom::blink::IDBDatabaseAssociatedPtrInfo database,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~WebIDBDatabaseImpl() override;
- // blink::WebIDBDatabase
+ // WebIDBDatabase
void CreateObjectStore(long long transaction_id,
long long objectstore_id,
const String& name,
- const blink::WebIDBKeyPath&,
+ const IDBKeyPath&,
bool auto_increment) override;
void DeleteObjectStore(long long transaction_id,
long long object_store_id) override;
@@ -50,66 +49,65 @@ class MODULES_EXPORT WebIDBDatabaseImpl : public blink::WebIDBDatabase {
bool include_transaction,
bool no_records,
bool values,
- std::bitset<blink::kIDBOperationTypeCount> operation_types) override;
+ std::bitset<kIDBOperationTypeCount> operation_types) override;
void RemoveObservers(const Vector<int32_t>& observer_ids) override;
void Get(long long transaction_id,
long long object_store_id,
long long index_id,
- const blink::WebIDBKeyRange&,
+ const IDBKeyRange*,
bool key_only,
- blink::WebIDBCallbacks*) override;
+ WebIDBCallbacks*) override;
void GetAll(long long transaction_id,
long long object_store_id,
long long index_id,
- const blink::WebIDBKeyRange&,
+ const IDBKeyRange*,
long long max_count,
bool key_only,
- blink::WebIDBCallbacks*) override;
+ WebIDBCallbacks*) override;
void Put(long long transaction_id,
long long object_store_id,
- const blink::WebData& value,
- const Vector<blink::WebBlobInfo>&,
- blink::WebIDBKeyView primary_key,
+ std::unique_ptr<IDBValue> value,
+ std::unique_ptr<IDBKey> primary_key,
mojom::IDBPutMode,
- blink::WebIDBCallbacks*,
- const Vector<blink::WebIDBIndexKeys>&) override;
+ WebIDBCallbacks*,
+ Vector<IDBIndexKeys>) override;
void SetIndexKeys(long long transaction_id,
long long object_store_id,
- blink::WebIDBKeyView primary_key,
- const Vector<blink::WebIDBIndexKeys>&) override;
+ std::unique_ptr<IDBKey> primary_key,
+ Vector<IDBIndexKeys>) override;
void SetIndexesReady(long long transaction_id,
long long object_store_id,
const Vector<int64_t>& index_ids) override;
void OpenCursor(long long transaction_id,
long long object_store_id,
long long index_id,
- const blink::WebIDBKeyRange&,
+ const IDBKeyRange*,
mojom::IDBCursorDirection direction,
bool key_only,
mojom::IDBTaskType,
- blink::WebIDBCallbacks*) override;
+ WebIDBCallbacks*) override;
void Count(long long transaction_id,
long long object_store_id,
long long index_id,
- const blink::WebIDBKeyRange&,
- blink::WebIDBCallbacks*) override;
+ const IDBKeyRange*,
+ WebIDBCallbacks*) override;
void Delete(long long transaction_id,
long long object_store_id,
- blink::WebIDBKeyView primary_key,
- blink::WebIDBCallbacks*) override;
+ const IDBKey* primary_key,
+ WebIDBCallbacks*) override;
void DeleteRange(long long transaction_id,
long long object_store_id,
- const blink::WebIDBKeyRange&,
- blink::WebIDBCallbacks*) override;
+ const IDBKeyRange*,
+ WebIDBCallbacks*) override;
void Clear(long long transaction_id,
long long object_store_id,
- blink::WebIDBCallbacks*) override;
+ WebIDBCallbacks*) override;
void CreateIndex(long long transaction_id,
long long object_store_id,
long long index_id,
const String& name,
- const blink::WebIDBKeyPath&,
+ const IDBKeyPath&,
bool unique,
bool multi_entry) override;
void DeleteIndex(long long transaction_id,
@@ -120,11 +118,11 @@ class MODULES_EXPORT WebIDBDatabaseImpl : public blink::WebIDBDatabase {
long long index_id,
const String& new_name) override;
void Abort(long long transaction_id) override;
- void Commit(long long transaction_id) override;
+ void Commit(long long transaction_id, long long num_errors_handled) override;
private:
mojom::blink::IDBCallbacksAssociatedPtrInfo GetCallbacksProxy(
- std::unique_ptr<IndexedDBCallbacksImpl> callbacks);
+ std::unique_ptr<WebIDBCallbacks> callbacks);
FRIEND_TEST_ALL_PREFIXES(WebIDBDatabaseImplTest, ValueSizeTest);
FRIEND_TEST_ALL_PREFIXES(WebIDBDatabaseImplTest, KeyAndValueSizeTest);
@@ -138,6 +136,7 @@ class MODULES_EXPORT WebIDBDatabaseImpl : public blink::WebIDBDatabase {
std::set<int32_t> observer_ids_;
mojom::blink::IDBDatabaseAssociatedPtr database_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc
index 42f434233c4..4b27268cf51 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc
@@ -9,10 +9,8 @@
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_blob_info.h"
-#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h"
@@ -33,22 +31,25 @@ TEST_F(WebIDBDatabaseImplTest, ValueSizeTest) {
const size_t kMaxValueSizeForTesting = 10 * 1024 * 1024; // 10 MB
const std::vector<char> data(kMaxValueSizeForTesting + 1);
- const WebData value(&data.front(), data.size());
+ const scoped_refptr<SharedBuffer> value_data =
+ SharedBuffer::Create(&data.front(), data.size());
const Vector<WebBlobInfo> blob_info;
- const WebIDBKey key = WebIDBKey::CreateNumber(0);
+ std::unique_ptr<IDBValue> value = IDBValue::Create(value_data, blob_info);
+ std::unique_ptr<IDBKey> key = IDBKey::CreateNumber(0);
const int64_t transaction_id = 1;
const int64_t object_store_id = 2;
StrictMock<MockWebIDBCallbacks> callbacks;
- ASSERT_GT(value.size() + key.SizeEstimate(), kMaxValueSizeForTesting);
+ ASSERT_GT(value_data->size() + key->SizeEstimate(), kMaxValueSizeForTesting);
ThreadState::Current()->CollectAllGarbage();
- EXPECT_CALL(callbacks, OnError(_)).Times(1);
+ EXPECT_CALL(callbacks, Error(_, _)).Times(1);
- WebIDBDatabaseImpl database_impl(nullptr);
+ WebIDBDatabaseImpl database_impl(
+ nullptr, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
database_impl.max_put_value_size_ = kMaxValueSizeForTesting;
- database_impl.Put(transaction_id, object_store_id, value, blob_info,
- key.View(), mojom::IDBPutMode::AddOrUpdate, &callbacks,
- Vector<blink::WebIDBIndexKeys>());
+ database_impl.Put(transaction_id, object_store_id, std::move(value),
+ std::move(key), mojom::IDBPutMode::AddOrUpdate, &callbacks,
+ Vector<IDBIndexKeys>());
}
TEST_F(WebIDBDatabaseImplTest, KeyAndValueSizeTest) {
@@ -58,8 +59,10 @@ TEST_F(WebIDBDatabaseImplTest, KeyAndValueSizeTest) {
const size_t kKeySize = 1024 * 1024;
const std::vector<char> data(kMaxValueSizeForTesting - kKeySize);
- const WebData value(&data.front(), data.size());
+ const scoped_refptr<SharedBuffer> value_data =
+ SharedBuffer::Create(&data.front(), data.size());
const Vector<WebBlobInfo> blob_info;
+ std::unique_ptr<IDBValue> value = IDBValue::Create(value_data, blob_info);
const int64_t transaction_id = 1;
const int64_t object_store_id = 2;
StrictMock<MockWebIDBCallbacks> callbacks;
@@ -75,19 +78,20 @@ TEST_F(WebIDBDatabaseImplTest, KeyAndValueSizeTest) {
String key_string(key_string_vector);
DCHECK_EQ(key_string.length(), number_of_chars);
- WebIDBKey key = WebIDBKey::CreateString(key_string);
- DCHECK_EQ(value.size(), kMaxValueSizeForTesting - kKeySize);
- DCHECK_GT(key.SizeEstimate() - kKeySize, static_cast<unsigned long>(0));
- DCHECK_GT(value.size() + key.SizeEstimate(), kMaxValueSizeForTesting);
+ std::unique_ptr<IDBKey> key = IDBKey::CreateString(key_string);
+ DCHECK_EQ(value_data->size(), kMaxValueSizeForTesting - kKeySize);
+ DCHECK_GT(key->SizeEstimate() - kKeySize, static_cast<unsigned long>(0));
+ DCHECK_GT(value_data->size() + key->SizeEstimate(), kMaxValueSizeForTesting);
ThreadState::Current()->CollectAllGarbage();
- EXPECT_CALL(callbacks, OnError(_)).Times(1);
+ EXPECT_CALL(callbacks, Error(_, _)).Times(1);
- WebIDBDatabaseImpl database_impl(nullptr);
+ WebIDBDatabaseImpl database_impl(
+ nullptr, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
database_impl.max_put_value_size_ = kMaxValueSizeForTesting;
- database_impl.Put(transaction_id, object_store_id, value, blob_info,
- key.View(), mojom::IDBPutMode::AddOrUpdate, &callbacks,
- Vector<blink::WebIDBIndexKeys>());
+ database_impl.Put(transaction_id, object_store_id, std::move(value),
+ std::move(key), mojom::IDBPutMode::AddOrUpdate, &callbacks,
+ Vector<IDBIndexKeys>());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory.h
index 71a2ce00a59..a18d051aaca 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory.h
@@ -29,43 +29,31 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_FACTORY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_FACTORY_H_
-#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/modules/modules_export.h"
-namespace base {
-class SingleThreadTaskRunner;
+namespace WTF {
+class String;
}
namespace blink {
class WebIDBCallbacks;
class WebIDBDatabaseCallbacks;
-class WebSecurityOrigin;
-class WebString;
class MODULES_EXPORT WebIDBFactory {
public:
virtual ~WebIDBFactory() = default;
- virtual void GetDatabaseInfo(WebIDBCallbacks*,
- const WebSecurityOrigin&,
- scoped_refptr<base::SingleThreadTaskRunner>) = 0;
- virtual void GetDatabaseNames(
- WebIDBCallbacks*,
- const WebSecurityOrigin&,
- scoped_refptr<base::SingleThreadTaskRunner>) = 0;
- virtual void Open(const WebString& name,
+ virtual void GetDatabaseInfo(std::unique_ptr<WebIDBCallbacks>) = 0;
+ virtual void GetDatabaseNames(std::unique_ptr<WebIDBCallbacks>) = 0;
+ virtual void Open(const WTF::String& name,
long long version,
long long transaction_id,
- WebIDBCallbacks*,
- WebIDBDatabaseCallbacks*,
- const WebSecurityOrigin&,
- scoped_refptr<base::SingleThreadTaskRunner>) = 0;
- virtual void DeleteDatabase(const WebString& name,
- WebIDBCallbacks*,
- const WebSecurityOrigin&,
- bool force_close,
- scoped_refptr<base::SingleThreadTaskRunner>) = 0;
+ std::unique_ptr<WebIDBCallbacks>,
+ std::unique_ptr<WebIDBDatabaseCallbacks>) = 0;
+ virtual void DeleteDatabase(const WTF::String& name,
+ std::unique_ptr<WebIDBCallbacks>,
+ bool force_close) = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.cc
index f158e08cd10..ebf933214e6 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.cc
@@ -6,80 +6,66 @@
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
WebIDBFactoryImpl::WebIDBFactoryImpl(
- mojom::blink::IDBFactoryPtrInfo factory_info)
- : factory_(std::move(factory_info)) {}
+ mojom::blink::IDBFactoryPtrInfo factory_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {
+ factory_.Bind(std::move(factory_info), task_runner_);
+}
WebIDBFactoryImpl::~WebIDBFactoryImpl() = default;
void WebIDBFactoryImpl::GetDatabaseInfo(
- WebIDBCallbacks* callbacks,
- const WebSecurityOrigin& origin,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), IndexedDBCallbacksImpl::kNoTransaction,
- nullptr);
- factory_->GetDatabaseInfo(GetCallbacksProxy(std::move(callbacks_impl)),
- origin);
+ std::unique_ptr<WebIDBCallbacks> callbacks) {
+ callbacks->SetState(nullptr, WebIDBCallbacksImpl::kNoTransaction);
+ factory_->GetDatabaseInfo(GetCallbacksProxy(std::move(callbacks)));
}
void WebIDBFactoryImpl::GetDatabaseNames(
- WebIDBCallbacks* callbacks,
- const WebSecurityOrigin& origin,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), IndexedDBCallbacksImpl::kNoTransaction,
- nullptr);
- factory_->GetDatabaseNames(GetCallbacksProxy(std::move(callbacks_impl)),
- origin);
+ std::unique_ptr<WebIDBCallbacks> callbacks) {
+ callbacks->SetState(nullptr, WebIDBCallbacksImpl::kNoTransaction);
+ factory_->GetDatabaseNames(GetCallbacksProxy(std::move(callbacks)));
}
void WebIDBFactoryImpl::Open(
- const WebString& name,
+ const String& name,
long long version,
long long transaction_id,
- WebIDBCallbacks* callbacks,
- WebIDBDatabaseCallbacks* database_callbacks,
- const WebSecurityOrigin& origin,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), transaction_id, nullptr);
+ std::unique_ptr<WebIDBCallbacks> callbacks,
+ std::unique_ptr<WebIDBDatabaseCallbacks> database_callbacks) {
+ callbacks->SetState(nullptr, WebIDBCallbacksImpl::kNoTransaction);
auto database_callbacks_impl =
std::make_unique<IndexedDBDatabaseCallbacksImpl>(
- base::WrapUnique(database_callbacks));
+ std::move(database_callbacks));
DCHECK(!name.IsNull());
- factory_->Open(GetCallbacksProxy(std::move(callbacks_impl)),
+ factory_->Open(GetCallbacksProxy(std::move(callbacks)),
GetDatabaseCallbacksProxy(std::move(database_callbacks_impl)),
- origin, name, version, transaction_id);
+ name, version, transaction_id);
}
void WebIDBFactoryImpl::DeleteDatabase(
- const WebString& name,
- WebIDBCallbacks* callbacks,
- const WebSecurityOrigin& origin,
- bool force_close,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
- base::WrapUnique(callbacks), IndexedDBCallbacksImpl::kNoTransaction,
- nullptr);
+ const String& name,
+ std::unique_ptr<WebIDBCallbacks> callbacks,
+ bool force_close) {
+ callbacks->SetState(nullptr, WebIDBCallbacksImpl::kNoTransaction);
DCHECK(!name.IsNull());
- factory_->DeleteDatabase(GetCallbacksProxy(std::move(callbacks_impl)), origin,
- name, force_close);
+ factory_->DeleteDatabase(GetCallbacksProxy(std::move(callbacks)), name,
+ force_close);
}
mojom::blink::IDBCallbacksAssociatedPtrInfo
WebIDBFactoryImpl::GetCallbacksProxy(
- std::unique_ptr<IndexedDBCallbacksImpl> callbacks) {
+ std::unique_ptr<WebIDBCallbacks> callbacks) {
mojom::blink::IDBCallbacksAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
- mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request));
+ mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request),
+ task_runner_);
return ptr_info;
}
@@ -88,7 +74,8 @@ WebIDBFactoryImpl::GetDatabaseCallbacksProxy(
std::unique_ptr<IndexedDBDatabaseCallbacksImpl> callbacks) {
mojom::blink::IDBDatabaseCallbacksAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
- mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request));
+ mojo::MakeStrongAssociatedBinding(std::move(callbacks), std::move(request),
+ task_runner_);
return ptr_info;
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.h
index dbc69d838e3..692d92013b7 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_factory_impl.h
@@ -6,52 +6,46 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_FACTORY_IMPL_H_
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/indexed_db_callbacks_impl.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_factory.h"
+namespace WTF {
+class String;
+}
+
namespace blink {
-class WebSecurityOrigin;
-class WebString;
-class WebIDBFactoryImpl : public blink::WebIDBFactory {
+class WebIDBFactoryImpl : public WebIDBFactory {
public:
- explicit WebIDBFactoryImpl(mojom::blink::IDBFactoryPtrInfo factory_info);
+ explicit WebIDBFactoryImpl(
+ mojom::blink::IDBFactoryPtrInfo factory_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~WebIDBFactoryImpl() override;
- // See WebIDBFactory.h for documentation on these functions.
- void GetDatabaseInfo(
- blink::WebIDBCallbacks* callbacks,
- const blink::WebSecurityOrigin& origin,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
- void GetDatabaseNames(
- blink::WebIDBCallbacks* callbacks,
- const blink::WebSecurityOrigin& origin,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
- void Open(const blink::WebString& name,
- long long version,
- long long transaction_id,
- blink::WebIDBCallbacks* callbacks,
- blink::WebIDBDatabaseCallbacks* databaseCallbacks,
- const blink::WebSecurityOrigin& origin,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
- void DeleteDatabase(
- const blink::WebString& name,
- blink::WebIDBCallbacks* callbacks,
- const blink::WebSecurityOrigin& origin,
- bool force_close,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
+ // See web_idb_factory.h for documentation on these functions.
+ void GetDatabaseInfo(std::unique_ptr<WebIDBCallbacks> callbacks) override;
+ void GetDatabaseNames(std::unique_ptr<WebIDBCallbacks> callbacks) override;
+ void Open(
+ const WTF::String& name,
+ long long version,
+ long long transaction_id,
+ std::unique_ptr<WebIDBCallbacks> callbacks,
+ std::unique_ptr<WebIDBDatabaseCallbacks> database_callbacks) override;
+ void DeleteDatabase(const WTF::String& name,
+ std::unique_ptr<WebIDBCallbacks> callbacks,
+ bool force_close) override;
private:
mojom::blink::IDBCallbacksAssociatedPtrInfo GetCallbacksProxy(
- std::unique_ptr<blink::IndexedDBCallbacksImpl> callbacks);
+ std::unique_ptr<WebIDBCallbacks> callbacks);
mojom::blink::IDBDatabaseCallbacksAssociatedPtrInfo GetDatabaseCallbacksProxy(
- std::unique_ptr<blink::IndexedDBDatabaseCallbacksImpl> callbacks);
+ std::unique_ptr<IndexedDBDatabaseCallbacksImpl> callbacks);
mojom::blink::IDBFactoryPtr factory_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc b/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
index 8524dc496c4..2c50eae1eec 100644
--- a/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
@@ -103,8 +103,10 @@ void InstalledAppController::FilterByInstalledApps(
}
if (!provider_) {
+ // See https://bit.ly/2S0zRAS for task types.
GetSupplementable()->GetInterfaceProvider().GetInterface(
- mojo::MakeRequest(&provider_));
+ mojo::MakeRequest(&provider_, GetExecutionContext()->GetTaskRunner(
+ blink::TaskType::kMiscPlatformAPI)));
// TODO(mgiuca): Set a connection error handler. This requires a refactor to
// work like NavigatorShare.cpp (retain a persistent list of clients to
// reject all of their promises).
diff --git a/chromium/third_party/blink/renderer/modules/keyboard/keyboard.idl b/chromium/third_party/blink/renderer/modules/keyboard/keyboard.idl
index 86832c9d1d4..6e2bb694f71 100644
--- a/chromium/third_party/blink/renderer/modules/keyboard/keyboard.idl
+++ b/chromium/third_party/blink/renderer/modules/keyboard/keyboard.idl
@@ -17,6 +17,7 @@
// Keyboard Map specification: https://wicg.github.io/keyboard-map/
[CallWith=ScriptState,
+ HighEntropy,
MeasureAs=KeyboardApiGetLayoutMap
] Promise<KeyboardLayoutMap> getLayoutMap();
};
diff --git a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
index af4f02e627b..ce239998fef 100644
--- a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
+++ b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/modules/keyboard/keyboard_layout.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -29,8 +28,6 @@ constexpr char kKeyboardMapRequestFailedErrorMsg[] =
} // namespace
-using mojom::PageVisibilityState;
-
KeyboardLayout::KeyboardLayout(ExecutionContext* context)
: ContextLifecycleObserver(context) {}
diff --git a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_lock.cc b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_lock.cc
index 274e38e53ea..b61ce674040 100644
--- a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_lock.cc
+++ b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_lock.cc
@@ -94,7 +94,9 @@ bool KeyboardLock::EnsureServiceConnected() {
if (!frame) {
return false;
}
- frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
+ // See https://bit.ly/2S0zRAS for task types.
+ frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(
+ &service_, frame->GetTaskRunner(TaskType::kMiscPlatformAPI)));
DCHECK(service_);
}
diff --git a/chromium/third_party/blink/renderer/modules/locks/lock.cc b/chromium/third_party/blink/renderer/modules/locks/lock.cc
index f8fd457420b..8238cd56c42 100644
--- a/chromium/third_party/blink/renderer/modules/locks/lock.cc
+++ b/chromium/third_party/blink/renderer/modules/locks/lock.cc
@@ -64,7 +64,7 @@ class Lock::ThenFunction final : public ScriptFunction {
Lock* Lock::Create(ScriptState* script_state,
const String& name,
mojom::blink::LockMode mode,
- mojom::blink::LockHandlePtr handle,
+ mojom::blink::LockHandleAssociatedPtr handle,
LockManager* manager) {
return MakeGarbageCollected<Lock>(script_state, name, mode, std::move(handle),
manager);
@@ -73,15 +73,13 @@ Lock* Lock::Create(ScriptState* script_state,
Lock::Lock(ScriptState* script_state,
const String& name,
mojom::blink::LockMode mode,
- mojom::blink::LockHandlePtr handle,
+ mojom::blink::LockHandleAssociatedPtr handle,
LockManager* manager)
- : PausableObject(ExecutionContext::From(script_state)),
+ : ContextLifecycleObserver(ExecutionContext::From(script_state)),
name_(name),
mode_(mode),
handle_(std::move(handle)),
manager_(manager) {
- PauseIfNeeded();
-
handle_.set_connection_error_handler(
WTF::Bind(&Lock::OnConnectionError, WrapWeakPersistent(this)));
}
@@ -130,7 +128,7 @@ void Lock::ContextDestroyed(ExecutionContext* context) {
}
void Lock::Trace(blink::Visitor* visitor) {
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
ScriptWrappable::Trace(visitor);
visitor->Trace(resolver_);
visitor->Trace(manager_);
diff --git a/chromium/third_party/blink/renderer/modules/locks/lock.h b/chromium/third_party/blink/renderer/modules/locks/lock.h
index a7bdc4f462f..a76b291fc2a 100644
--- a/chromium/third_party/blink/renderer/modules/locks/lock.h
+++ b/chromium/third_party/blink/renderer/modules/locks/lock.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_LOCK_H_
#include "third_party/blink/public/platform/modules/locks/lock_manager.mojom-blink.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -19,7 +19,7 @@ class ScriptPromise;
class ScriptPromiseResolver;
class ScriptState;
-class Lock final : public ScriptWrappable, public PausableObject {
+class Lock final : public ScriptWrappable, public ContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(Lock);
@@ -27,13 +27,13 @@ class Lock final : public ScriptWrappable, public PausableObject {
static Lock* Create(ScriptState*,
const String& name,
mojom::blink::LockMode,
- mojom::blink::LockHandlePtr,
+ mojom::blink::LockHandleAssociatedPtr,
LockManager*);
Lock(ScriptState*,
const String& name,
mojom::blink::LockMode,
- mojom::blink::LockHandlePtr,
+ mojom::blink::LockHandleAssociatedPtr,
LockManager*);
~Lock() override;
@@ -44,7 +44,7 @@ class Lock final : public ScriptWrappable, public PausableObject {
String name() const { return name_; }
String mode() const;
- // PausableObject
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// The lock is held until the passed promise resolves. When it is released,
@@ -68,7 +68,7 @@ class Lock final : public ScriptWrappable, public PausableObject {
// An opaque handle; this one end of a mojo pipe. When this is closed,
// the lock is released by the back end.
- mojom::blink::LockHandlePtr handle_;
+ mojom::blink::LockHandleAssociatedPtr handle_;
// LockManager::OnLockReleased() is called when this lock is released, to
// stop artificially keeping this instance alive. It is necessary in the
diff --git a/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc b/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
index 85ec1925765..f293c02c027 100644
--- a/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/locks/lock_manager.h"
#include <algorithm>
+#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -62,13 +63,17 @@ class LockManager::LockRequestImpl final
ScriptPromiseResolver* resolver,
const String& name,
mojom::blink::LockMode mode,
- mojom::blink::LockRequestRequest request,
+ mojom::blink::LockRequestAssociatedRequest request,
LockManager* manager)
: callback_(callback),
resolver_(resolver),
name_(name),
mode_(mode),
- binding_(this, std::move(request)),
+ // See https://bit.ly/2S0zRAS for task types.
+ binding_(this,
+ std::move(request),
+ manager->GetExecutionContext()->GetTaskRunner(
+ TaskType::kMiscPlatformAPI)),
manager_(manager) {}
~LockRequestImpl() override = default;
@@ -126,9 +131,11 @@ class LockManager::LockRequestImpl final
}
}
- void Granted(mojom::blink::LockHandlePtr handle) override {
+ void Granted(mojom::blink::LockHandleAssociatedPtrInfo handle_info) override {
DCHECK(binding_.is_bound());
- DCHECK(handle.is_bound());
+
+ mojom::blink::LockHandleAssociatedPtr handle;
+ handle.Bind(std::move(handle_info));
// Ensure a local reference to the callback's wrapper is retained, as it
// can no longer be traced once removed from |manager_|'s list.
@@ -174,7 +181,7 @@ class LockManager::LockRequestImpl final
// Held to stamp the Lock object's |mode| property.
mojom::blink::LockMode mode_;
- mojo::Binding<mojom::blink::LockRequest> binding_;
+ mojo::AssociatedBinding<mojom::blink::LockRequest> binding_;
// The |manager_| keeps |this| alive until a response comes in and this is
// registered. If the context is destroyed then |manager_| will dispose of
@@ -198,6 +205,10 @@ ScriptPromise LockManager::request(ScriptState* script_state,
const LockOptions* options,
V8LockGrantedCallback* callback,
ExceptionState& exception_state) {
+ // Observed context may be gone if frame is detached.
+ if (!GetExecutionContext())
+ return ScriptPromise();
+
ExecutionContext* context = ExecutionContext::From(script_state);
DCHECK(context->IsContextThread());
@@ -285,13 +296,13 @@ ScriptPromise LockManager::request(ScriptState* script_state,
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
- mojom::blink::LockRequestPtr request_ptr;
+ mojom::blink::LockRequestAssociatedPtrInfo request_info;
// 11.1. Let request be the result of running the steps to request a lock with
// promise, the current agent, environment’s id, origin, callback, name,
// options’ mode dictionary member, options’ ifAvailable dictionary member,
// and options’ steal dictionary member.
LockRequestImpl* request = MakeGarbageCollected<LockRequestImpl>(
- callback, resolver, name, mode, mojo::MakeRequest(&request_ptr), this);
+ callback, resolver, name, mode, mojo::MakeRequest(&request_info), this);
AddPendingRequest(request);
// 11.2. If options’ signal dictionary member is present, then add the
@@ -305,7 +316,7 @@ ScriptPromise LockManager::request(ScriptState* script_state,
String(kRequestAbortedMessage)));
}
- service_->RequestLock(name, mode, wait, std::move(request_ptr));
+ service_->RequestLock(name, mode, wait, std::move(request_info));
// 12. Return promise.
return promise;
@@ -313,6 +324,10 @@ ScriptPromise LockManager::request(ScriptState* script_state,
ScriptPromise LockManager::query(ScriptState* script_state,
ExceptionState& exception_state) {
+ // Observed context may be gone if frame is detached.
+ if (!GetExecutionContext())
+ return ScriptPromise();
+
ExecutionContext* context = ExecutionContext::From(script_state);
DCHECK(context->IsContextThread());
diff --git a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc b/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc
index 2ee6981a9e7..6a6f326108a 100644
--- a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc
+++ b/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc
@@ -29,12 +29,14 @@ class NavigatorLocksImpl final : public GarbageCollected<NavigatorLocksImpl<T>>,
NavigatorLocksImpl* supplement = static_cast<NavigatorLocksImpl*>(
Supplement<T>::template From<NavigatorLocksImpl>(navigator));
if (!supplement) {
- supplement = new NavigatorLocksImpl(navigator);
+ supplement = MakeGarbageCollected<NavigatorLocksImpl>(navigator);
Supplement<T>::ProvideTo(navigator, supplement);
}
return *supplement;
}
+ explicit NavigatorLocksImpl(T& navigator) : Supplement<T>(navigator) {}
+
LockManager* GetLockManager(ExecutionContext* context) const {
if (!lock_manager_ && context) {
lock_manager_ = MakeGarbageCollected<LockManager>(context);
@@ -52,8 +54,6 @@ class NavigatorLocksImpl final : public GarbageCollected<NavigatorLocksImpl<T>>,
}
private:
- explicit NavigatorLocksImpl(T& navigator) : Supplement<T>(navigator) {}
-
mutable TraceWrapperMember<LockManager> lock_manager_;
};
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info_callbacks.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info_callbacks.cc
index b40129b619c..e4e9fbdefb4 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info_callbacks.cc
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info_callbacks.cc
@@ -34,7 +34,7 @@ void MediaCapabilitiesDecodingInfoCallbacks::OnSuccess(
// is supported.
DCHECK(result->supported);
- info->setKeySystemAccess(new MediaKeySystemAccess(
+ info->setKeySystemAccess(MakeGarbageCollected<MediaKeySystemAccess>(
std::move(result->content_decryption_module_access)));
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.cc
index f31e1b45fe6..21d882f4481 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.cc
@@ -11,7 +11,7 @@ namespace blink {
MediaControlAnimationEventListener::MediaControlAnimationEventListener(
Observer* observer)
- : EventListener(EventListener::kCPPEventListenerType), observer_(observer) {
+ : observer_(observer) {
observer_->WatchedAnimationElement().addEventListener(
event_type_names::kAnimationend, this, false);
observer_->WatchedAnimationElement().addEventListener(
@@ -25,11 +25,6 @@ void MediaControlAnimationEventListener::Detach() {
event_type_names::kAnimationiteration, this, false);
}
-bool MediaControlAnimationEventListener::operator==(
- const EventListener& other) const {
- return this == &other;
-}
-
void MediaControlAnimationEventListener::Trace(Visitor* visitor) {
visitor->Trace(observer_);
EventListener::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h
index 987e3ea6ea5..36088f32903 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h
@@ -5,9 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ANIMATION_EVENT_LISTENER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ANIMATION_EVENT_LISTENER_H_
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
namespace blink {
@@ -24,7 +23,7 @@ class Event;
// animation has gone through so we can nicely stop the animation at the end of
// the current one.
class MODULES_EXPORT MediaControlAnimationEventListener final
- : public EventListener {
+ : public NativeEventListener {
public:
// To use this class you need to use Observer as a mixin and return an element
// to watch. You then instanitate a MediaControlAnimationEventListener from
@@ -47,13 +46,11 @@ class MODULES_EXPORT MediaControlAnimationEventListener final
explicit MediaControlAnimationEventListener(Observer*);
void Detach();
- bool operator==(const EventListener& other) const override;
-
void Trace(Visitor*) override;
- private:
void Invoke(ExecutionContext*, Event*) override;
+ private:
Member<Observer> observer_;
};
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
index 40f5426e955..0d7524f17c1 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
-#include "third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h"
#include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
namespace blink {
@@ -106,10 +105,7 @@ void MediaControlCastButtonElement::DefaultEventHandler(Event& event) {
WebURL(GetDocument().Url()));
}
- RemotePlayback* remote =
- HTMLMediaElementRemotePlayback::remote(MediaElement());
- if (remote)
- remote->PromptInternal();
+ RemotePlayback::From(MediaElement()).PromptInternal();
}
MediaControlInputElement::DefaultEventHandler(event);
}
@@ -119,9 +115,8 @@ bool MediaControlCastButtonElement::KeepEventInNode(const Event& event) const {
}
bool MediaControlCastButtonElement::IsPlayingRemotely() const {
- RemotePlayback* remote =
- HTMLMediaElementRemotePlayback::remote(MediaElement());
- return remote && remote->GetState() != WebRemotePlaybackState::kDisconnected;
+ return RemotePlayback::From(MediaElement()).GetState() !=
+ WebRemotePlaybackState::kDisconnected;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc
index 034ce03cfbd..92d077b7c00 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc
@@ -10,7 +10,9 @@ namespace blink {
MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(
MediaControlsImpl& media_controls)
- : MediaControlTimeDisplayElement(media_controls, kMediaCurrentTimeDisplay) {
+ : MediaControlTimeDisplayElement(
+ media_controls,
+ WebLocalizedString::kAXMediaCurrentTimeDisplay) {
SetShadowPseudoId(
AtomicString("-webkit-media-controls-current-time-display"));
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.cc
index e6646c3e770..27faded7125 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.cc
@@ -31,7 +31,8 @@ bool MediaControlDisplayCutoutFullscreenButtonElement::
void MediaControlDisplayCutoutFullscreenButtonElement::DefaultEventHandler(
Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
// The button shouldn't be visible if not in fullscreen.
DCHECK(MediaElement().IsFullscreen());
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc
index 455234995f4..ab067b7a36e 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc
@@ -41,7 +41,7 @@ class MediaControlDisplayCutoutFullscreenButtonElementTest
}
void SetUp() override {
- chrome_client_ = new MockDisplayCutoutChromeClient();
+ chrome_client_ = MakeGarbageCollected<MockDisplayCutoutChromeClient>();
Page::PageClients clients;
FillWithEmptyClients(clients);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
index af3d60a8d98..9185021999d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
@@ -15,13 +15,18 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
MediaControlDownloadButtonElement::MediaControlDownloadButtonElement(
MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaDownloadButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
setType(input_type_names::kButton);
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(
+ WebLocalizedString::kAXMediaDownloadButton)));
+
SetShadowPseudoId(AtomicString("-internal-media-controls-download-button"));
SetIsWanted(false);
}
@@ -71,7 +76,8 @@ void MediaControlDownloadButtonElement::UpdateShownState() {
void MediaControlDownloadButtonElement::DefaultEventHandler(Event& event) {
const KURL& url = MediaElement().currentSrc();
- if (event.type() == event_type_names::kClick &&
+ if ((event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) &&
!(url.IsNull() || url.IsEmpty())) {
Platform::Current()->RecordAction(
UserMetricsAction("Media.Controls.Download"));
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
index 06df6aa5204..611590554ca 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
@@ -9,37 +9,22 @@
// from this list. It is used by code that need to know what type of media
// control element it is interacting with.
enum MediaControlElementType {
- kMediaEnterFullscreenButton = 0,
- kMediaMuteButton,
- kMediaPlayButton,
kMediaSlider,
kMediaSliderThumb,
- kMediaShowClosedCaptionsButton,
- kMediaHideClosedCaptionsButton,
kMediaTextTrackList,
- kMediaUnMuteButton,
- kMediaPauseButton,
kMediaTimelineContainer,
- kMediaCurrentTimeDisplay,
- kMediaTimeRemainingDisplay,
kMediaTrackSelectionCheckmark,
kMediaControlsPanel,
- kMediaVolumeSliderContainer,
- kMediaVolumeSlider,
- kMediaVolumeSliderThumb,
- kMediaExitFullscreenButton,
kMediaCastOffButton,
kMediaCastOnButton,
kMediaOverlayCastOffButton,
kMediaOverlayCastOnButton,
kMediaOverflowButton,
kMediaOverflowList,
- kMediaDownloadButton,
kMediaScrubbingMessage,
- kMediaEnterPictureInPictureButton,
- kMediaExitPictureInPictureButton,
kMediaDisplayCutoutFullscreenButton,
kMediaAnimatedArrowContainer,
+ kMediaIgnore
};
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ELEMENT_TYPE_H_
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc
index 93483865e9f..26b8f330e42 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc
@@ -24,7 +24,8 @@ bool MediaControlElementsHelper::IsUserInteractionEvent(const Event& event) {
type == event_type_names::kMousedown ||
type == event_type_names::kMouseup ||
type == event_type_names::kClick ||
- type == event_type_names::kDblclick || event.IsKeyboardEvent() ||
+ type == event_type_names::kDblclick ||
+ type == event_type_names::kGesturetap || event.IsKeyboardEvent() ||
event.IsTouchEvent();
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc
index b8368826c34..4e1bae1767e 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc
@@ -11,12 +11,13 @@
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(
MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaEnterFullscreenButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
setType(input_type_names::kButton);
SetShadowPseudoId(AtomicString("-webkit-media-controls-fullscreen-button"));
SetIsFullscreen(MediaElement().IsFullscreen());
@@ -24,8 +25,15 @@ MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(
}
void MediaControlFullscreenButtonElement::SetIsFullscreen(bool is_fullscreen) {
- SetDisplayType(is_fullscreen ? kMediaExitFullscreenButton
- : kMediaEnterFullscreenButton);
+ if (is_fullscreen) {
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(
+ WebLocalizedString::kAXMediaExitFullscreenButton)));
+ } else {
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(
+ WebLocalizedString::kAXMediaEnterFullscreenButton)));
+ }
SetClass("fullscreen", is_fullscreen);
}
@@ -49,7 +57,8 @@ const char* MediaControlFullscreenButtonElement::GetNameForHistograms() const {
}
void MediaControlFullscreenButtonElement::DefaultEventHandler(Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
RecordClickMetrics();
if (MediaElement().IsFullscreen())
GetMediaControls().ExitFullscreen();
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
index db9cb7d426c..441b1ae4112 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
@@ -20,7 +20,7 @@
namespace {
// The default size of an overflow button in pixels.
-constexpr int kDefaultButtonSize = 36;
+constexpr int kDefaultButtonSize = 48;
const char kOverflowContainerWithSubtitleCSSClass[] = "with-subtitle";
const char kOverflowSubtitleCSSClass[] = "subtitle";
@@ -127,6 +127,10 @@ void MediaControlInputElement::RemoveOverflowSubtitleElement() {
overflow_menu_subtitle_ = nullptr;
}
+bool MediaControlInputElement::OverflowElementIsWanted() {
+ return overflow_element_ && overflow_element_->IsWanted();
+}
+
void MediaControlInputElement::SetOverflowElementIsWanted(bool wanted) {
if (!overflow_element_)
return;
@@ -199,8 +203,15 @@ void MediaControlInputElement::UpdateShownState() {
}
void MediaControlInputElement::DefaultEventHandler(Event& event) {
- if (event.type() == event_type_names::kClick)
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
MaybeRecordInteracted();
+ }
+
+ // Unhover the element if the hover is triggered by a tap on
+ // a touch screen device to avoid showing hover circle indefinitely.
+ if (event.IsGestureEvent() && IsHovered())
+ SetHovered(false);
HTMLInputElement::DefaultEventHandler(event);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h
index 0fc1d31cbd1..d3e5c257d9d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h
@@ -25,6 +25,8 @@ class MODULES_EXPORT MediaControlInputElement : public HTMLInputElement,
// Creates an overflow menu element with the given button as a child.
HTMLElement* CreateOverflowElement(MediaControlInputElement*);
+ bool OverflowElementIsWanted();
+
// Implements MediaControlElementBase.
void SetOverflowElementIsWanted(bool) final;
void MaybeRecordDisplayed() final;
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc
index e948fe7222e..30c1de815fc 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc
@@ -29,7 +29,7 @@ class MediaControlInputElementImpl final : public MediaControlInputElement {
public:
MediaControlInputElementImpl(MediaControlsImpl& media_controls)
// Using arbitrary MediaControlElementType. It should have no impact.
- : MediaControlInputElement(media_controls, kMediaDownloadButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
setType(input_type_names::kButton);
SetIsWanted(false);
}
@@ -64,7 +64,8 @@ class MediaControlInputElementTest : public PageTestBase {
media_controls_ =
static_cast<MediaControlsImpl*>(media_element_->GetMediaControls());
ASSERT_NE(media_controls_, nullptr);
- control_input_element_ = new MediaControlInputElementImpl(*media_controls_);
+ control_input_element_ =
+ MakeGarbageCollected<MediaControlInputElementImpl>(*media_controls_);
}
protected:
@@ -181,7 +182,7 @@ TEST_F(MediaControlInputElementTest, OverflowElement_DisplayFallback) {
Persistent<HTMLElement> overflow_container =
ControlInputElement().CreateOverflowElement(
- new MediaControlInputElementImpl(MediaControls()));
+ MakeGarbageCollected<MediaControlInputElementImpl>(MediaControls()));
ControlInputElement().SetIsWanted(true);
ControlInputElement().SetDoesFit(false);
@@ -198,7 +199,7 @@ TEST_F(MediaControlInputElementTest, OverflowElement_DisplayRequiresWanted) {
Persistent<HTMLElement> overflow_container =
ControlInputElement().CreateOverflowElement(
- new MediaControlInputElementImpl(MediaControls()));
+ MakeGarbageCollected<MediaControlInputElementImpl>(MediaControls()));
ControlInputElement().SetIsWanted(true);
ControlInputElement().SetDoesFit(false);
@@ -220,7 +221,7 @@ TEST_F(MediaControlInputElementTest, OverflowElement_DisplayAfterInline) {
Persistent<HTMLElement> overflow_container =
ControlInputElement().CreateOverflowElement(
- new MediaControlInputElementImpl(MediaControls()));
+ MakeGarbageCollected<MediaControlInputElementImpl>(MediaControls()));
ControlInputElement().SetIsWanted(true);
ControlInputElement().SetDoesFit(true);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc
index f1c96f981ec..631f997ee97 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc
@@ -9,12 +9,13 @@
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
MediaControlMuteButtonElement::MediaControlMuteButtonElement(
MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaMuteButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
setType(input_type_names::kButton);
SetShadowPseudoId(AtomicString("-webkit-media-controls-mute-button"));
}
@@ -28,7 +29,10 @@ void MediaControlMuteButtonElement::UpdateDisplayType() {
// 'muted' when the volume is 0 even if the element is not muted. This allows
// the painting and the display type to actually match.
bool muted = MediaElement().muted() || MediaElement().volume() == 0;
- SetDisplayType(muted ? kMediaUnMuteButton : kMediaMuteButton);
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(
+ muted ? WebLocalizedString::kAXMediaUnMuteButton
+ : WebLocalizedString::kAXMediaMuteButton)));
SetClass("muted", muted);
UpdateOverflowString();
@@ -51,7 +55,8 @@ const char* MediaControlMuteButtonElement::GetNameForHistograms() const {
}
void MediaControlMuteButtonElement::DefaultEventHandler(Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
if (MediaElement().muted()) {
Platform::Current()->RecordAction(
UserMetricsAction("Media.Controls.Unmute"));
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
index a33e4b429cc..7b08f01bff2 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
@@ -44,7 +44,8 @@ void MediaControlOverflowMenuButtonElement::UpdateShownState() {
void MediaControlOverflowMenuButtonElement::DefaultEventHandler(Event& event) {
// Only respond to a click event if we are not disabled.
if (!hasAttribute(html_names::kDisabledAttr) &&
- event.type() == event_type_names::kClick) {
+ (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap)) {
if (GetMediaControls().OverflowMenuVisible()) {
Platform::Current()->RecordAction(
UserMetricsAction("Media.Controls.OverflowClose"));
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
index 0c1668197c1..0d6d6a2f87d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace {
@@ -36,7 +37,7 @@ namespace blink {
// This contains the inner circle with the actual play/pause icon.
MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(
MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaPlayButton),
+ : MediaControlInputElement(media_controls, kMediaIgnore),
internal_button_(nullptr) {
EnsureUserAgentShadowRoot();
setType(input_type_names::kButton);
@@ -53,8 +54,11 @@ void MediaControlOverlayPlayButtonElement::UpdateDisplayType() {
SetIsWanted(MediaElement().ShouldShowControls() &&
(MediaControlsImpl::IsModern() || MediaElement().paused()));
if (MediaControlsImpl::IsModern()) {
- SetDisplayType(MediaElement().paused() ? kMediaPlayButton
- : kMediaPauseButton);
+ WebLocalizedString::Name state =
+ MediaElement().paused() ? WebLocalizedString::kAXMediaPlayButton
+ : WebLocalizedString::kAXMediaPauseButton;
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(state)));
}
MediaControlInputElement::UpdateDisplayType();
}
@@ -91,7 +95,8 @@ void MediaControlOverlayPlayButtonElement::MaybePlayPause() {
}
void MediaControlOverlayPlayButtonElement::DefaultEventHandler(Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
event.SetDefaultHandled();
MaybePlayPause();
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc
index 2a6da96b45d..23d48e46c6d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc
@@ -6,7 +6,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
@@ -23,16 +23,14 @@ const char kTransparentClassName[] = "transparent";
// Listens for the 'transitionend' event.
class MediaControlPanelElement::TransitionEventListener final
- : public EventListener {
+ : public NativeEventListener {
public:
using Callback = base::RepeatingCallback<void()>;
// |element| is the element to listen for the 'transitionend' event on.
// |callback| is the callback to call when the event is handled.
explicit TransitionEventListener(Element* element, Callback callback)
- : EventListener(EventListener::kCPPEventListenerType),
- callback_(callback),
- element_(element) {
+ : callback_(callback), element_(element) {
DCHECK(callback_);
DCHECK(element_);
}
@@ -54,16 +52,6 @@ class MediaControlPanelElement::TransitionEventListener final
bool IsAttached() const { return attached_; }
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
-
- void Trace(blink::Visitor* visitor) override {
- EventListener::Trace(visitor);
- visitor->Trace(element_);
- }
-
- private:
void Invoke(ExecutionContext* context, Event* event) override {
if (event->target() != element_)
return;
@@ -76,6 +64,12 @@ class MediaControlPanelElement::TransitionEventListener final
NOTREACHED();
}
+ void Trace(blink::Visitor* visitor) override {
+ NativeEventListener::Trace(visitor);
+ visitor->Trace(element_);
+ }
+
+ private:
bool attached_ = false;
Callback callback_;
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.cc
index 7e1968d6860..11ebb65f0c4 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.cc
@@ -12,13 +12,22 @@
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
MediaControlPictureInPictureButtonElement::
MediaControlPictureInPictureButtonElement(MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaPlayButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
setType(input_type_names::kButton);
+ setAttribute(html_names::kRoleAttr, "button");
+
+ bool isInPictureInPicture =
+ PictureInPictureController::IsElementInPictureInPicture(
+ &ToHTMLVideoElement(MediaElement()));
+
+ UpdateAriaString(isInPictureInPicture);
+
SetShadowPseudoId(
AtomicString("-internal-media-controls-picture-in-picture-button"));
SetIsWanted(false);
@@ -32,13 +41,13 @@ bool MediaControlPictureInPictureButtonElement::
void MediaControlPictureInPictureButtonElement::UpdateDisplayType() {
DCHECK(MediaElement().IsHTMLVideoElement());
bool isInPictureInPicture =
- PictureInPictureControllerImpl::From(MediaElement().GetDocument())
- .IsPictureInPictureElement(&ToHTMLVideoElement(MediaElement()));
- SetDisplayType(isInPictureInPicture ? kMediaExitPictureInPictureButton
- : kMediaEnterPictureInPictureButton);
+ PictureInPictureController::IsElementInPictureInPicture(
+ &ToHTMLVideoElement(MediaElement()));
SetClass("on", isInPictureInPicture);
UpdateOverflowString();
+ UpdateAriaString(isInPictureInPicture);
+
MediaControlInputElement::UpdateDisplayType();
}
@@ -46,8 +55,8 @@ WebLocalizedString::Name
MediaControlPictureInPictureButtonElement::GetOverflowStringName() const {
DCHECK(MediaElement().IsHTMLVideoElement());
bool isInPictureInPicture =
- PictureInPictureControllerImpl::From(MediaElement().GetDocument())
- .IsPictureInPictureElement(&ToHTMLVideoElement(MediaElement()));
+ PictureInPictureController::IsElementInPictureInPicture(
+ &ToHTMLVideoElement(MediaElement()));
return isInPictureInPicture
? WebLocalizedString::kOverflowMenuExitPictureInPicture
@@ -66,13 +75,14 @@ const char* MediaControlPictureInPictureButtonElement::GetNameForHistograms()
void MediaControlPictureInPictureButtonElement::DefaultEventHandler(
Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
PictureInPictureControllerImpl& controller =
PictureInPictureControllerImpl::From(MediaElement().GetDocument());
DCHECK(MediaElement().IsHTMLVideoElement());
HTMLVideoElement* video_element = &ToHTMLVideoElement(MediaElement());
- if (controller.IsPictureInPictureElement(video_element))
+ if (PictureInPictureController::IsElementInPictureInPicture(video_element))
controller.ExitPictureInPicture(video_element, nullptr);
else
controller.EnterPictureInPicture(video_element, nullptr);
@@ -81,4 +91,16 @@ void MediaControlPictureInPictureButtonElement::DefaultEventHandler(
MediaControlInputElement::DefaultEventHandler(event);
}
+void MediaControlPictureInPictureButtonElement::UpdateAriaString(
+ bool isInPictureInPicture) {
+ String aria_string =
+ isInPictureInPicture
+ ? GetLocale().QueryString(
+ WebLocalizedString::kAXMediaExitPictureInPictureButton)
+ : GetLocale().QueryString(
+ WebLocalizedString::kAXMediaEnterPictureInPictureButton);
+
+ setAttribute(html_names::kAriaLabelAttr, WTF::AtomicString(aria_string));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.h
index 4a395d2bf12..548a3c34577 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.h
@@ -30,6 +30,8 @@ class MediaControlPictureInPictureButtonElement final
private:
void DefaultEventHandler(Event&) override;
+
+ void UpdateAriaString(bool);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc
index 843c19eb35c..5d1246bf8c9 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc
@@ -10,12 +10,13 @@
#include "third_party/blink/renderer/core/html/media/html_media_source.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
MediaControlPlayButtonElement::MediaControlPlayButtonElement(
MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaPlayButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
setType(input_type_names::kButton);
SetShadowPseudoId(AtomicString("-webkit-media-controls-play-button"));
}
@@ -25,8 +26,11 @@ bool MediaControlPlayButtonElement::WillRespondToMouseClickEvents() {
}
void MediaControlPlayButtonElement::UpdateDisplayType() {
- SetDisplayType(MediaElement().paused() ? kMediaPlayButton
- : kMediaPauseButton);
+ WebLocalizedString::Name state =
+ MediaElement().paused() ? WebLocalizedString::kAXMediaPlayButton
+ : WebLocalizedString::kAXMediaPauseButton;
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(state)));
SetClass("pause", MediaElement().paused());
UpdateOverflowString();
@@ -49,7 +53,8 @@ const char* MediaControlPlayButtonElement::GetNameForHistograms() const {
}
void MediaControlPlayButtonElement::DefaultEventHandler(Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
if (MediaElement().paused()) {
Platform::Current()->RecordAction(
UserMetricsAction("Media.Controls.Play"));
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
index 95aace33bc7..9e63a1ed362 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
@@ -8,7 +8,7 @@
#include "third_party/blink/renderer/core/css/css_style_declaration.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
@@ -40,10 +40,10 @@ bool FocusListItemIfDisplayed(Node* node) {
} // anonymous namespace
class MediaControlPopupMenuElement::EventListener final
- : public blink::EventListener {
+ : public NativeEventListener {
public:
explicit EventListener(MediaControlPopupMenuElement* popup_menu)
- : blink::EventListener(kCPPEventListenerType), popup_menu_(popup_menu) {}
+ : popup_menu_(popup_menu) {}
~EventListener() final = default;
@@ -73,12 +73,8 @@ class MediaControlPopupMenuElement::EventListener final
}
}
- bool operator==(const blink::EventListener& other) const final {
- return &other == this;
- }
-
void Trace(blink::Visitor* visitor) final {
- blink::EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
visitor->Trace(popup_menu_);
}
@@ -148,7 +144,8 @@ void MediaControlPopupMenuElement::OnItemSelected() {
}
void MediaControlPopupMenuElement::DefaultEventHandler(Event& event) {
- if (event.type() == event_type_names::kPointermove) {
+ if (event.type() == event_type_names::kPointermove &&
+ event.target() != this) {
ToElement(event.target()->ToNode())->focus();
} else if (event.type() == event_type_names::kFocusout) {
GetDocument()
@@ -230,7 +227,8 @@ void MediaControlPopupMenuElement::HideIfNotFocused() {
return;
if (!GetDocument().FocusedElement() ||
- GetDocument().FocusedElement()->parentElement() != this) {
+ (GetDocument().FocusedElement()->parentElement() != this &&
+ GetDocument().FocusedElement() != this)) {
SetIsWanted(false);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h
index a538d3ee566..67808d74b53 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h
@@ -31,6 +31,13 @@ class MediaControlPopupMenuElement : public MediaControlDivElement {
void Trace(blink::Visitor*) override;
+ // When clicking the scroll bar, chrome will find its first focusable parent
+ // and focus on it. In order to prevent popup menu from losing focus (which
+ // will close the menu), we are setting the popup menu support focus and mouse
+ // focusable.
+ bool IsMouseFocusable() const override { return true; }
+ bool SupportsFocus() const override { return true; }
+
protected:
MediaControlPopupMenuElement(MediaControlsImpl&, MediaControlElementType);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc
index 0ef8bb5ef59..1622c84e74f 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc
@@ -6,16 +6,31 @@
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
+namespace {
+
+// The during element has extra '/ ' in the text which takes approximately
+// 9 pixels.
+constexpr int kTimeDisplayExtraCharacterWidth = 9;
+
+} // namespace
+
namespace blink {
MediaControlRemainingTimeDisplayElement::
MediaControlRemainingTimeDisplayElement(MediaControlsImpl& media_controls)
- : MediaControlTimeDisplayElement(media_controls,
- kMediaTimeRemainingDisplay) {
+ : MediaControlTimeDisplayElement(
+ media_controls,
+ WebLocalizedString::kAXMediaTimeRemainingDisplay) {
SetShadowPseudoId(
AtomicString("-webkit-media-controls-time-remaining-display"));
}
+int MediaControlRemainingTimeDisplayElement::EstimateElementWidth() const {
+ // Add extra pixel width for during display since we have an extra "/ ".
+ return kTimeDisplayExtraCharacterWidth +
+ MediaControlTimeDisplayElement::EstimateElementWidth();
+}
+
String MediaControlRemainingTimeDisplayElement::FormatTime() const {
// For the duration display, we prepend a "/ " to deliminate the current time
// from the duration, e.g. "0:12 / 3:45".
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h
index 241b8507e41..bcec717339b 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h
@@ -17,6 +17,8 @@ class MediaControlRemainingTimeDisplayElement final
explicit MediaControlRemainingTimeDisplayElement(MediaControlsImpl&);
private:
+ int EstimateElementWidth() const override;
+
String FormatTime() const override;
};
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
index ec67e954426..0bb25a54116 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
@@ -52,6 +52,10 @@ bool HasDuplicateLabel(TextTrack* current_track) {
MediaControlTextTrackListElement::MediaControlTextTrackListElement(
MediaControlsImpl& media_controls)
: MediaControlPopupMenuElement(media_controls, kMediaTextTrackList) {
+ setAttribute(html_names::kRoleAttr, "menu");
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(
+ WebLocalizedString::kOverflowMenuCaptionsSubmenuTitle)));
SetShadowPseudoId(AtomicString("-internal-media-controls-text-track-list"));
}
@@ -111,16 +115,23 @@ Element* MediaControlTextTrackListElement::CreateTextTrackListItem(
HTMLInputElement::Create(GetDocument(), CreateElementFlags());
track_item_input->SetShadowPseudoId(
AtomicString("-internal-media-controls-text-track-list-item-input"));
+ track_item_input->setAttribute(html_names::kAriaHiddenAttr, "true");
track_item_input->setType(input_type_names::kCheckbox);
track_item_input->SetIntegralAttribute(TrackIndexAttrName(), track_index);
if (!MediaElement().TextTracksVisible()) {
- if (!track)
+ if (!track) {
track_item_input->setChecked(true);
+ track_item->setAttribute(html_names::kAriaCheckedAttr, "true");
+ }
} else {
// If there are multiple text tracks set to showing, they must all have
// checkmarks displayed.
- if (track && track->mode() == TextTrack::ShowingKeyword())
+ if (track && track->mode() == TextTrack::ShowingKeyword()) {
track_item_input->setChecked(true);
+ track_item->setAttribute(html_names::kAriaCheckedAttr, "true");
+ } else {
+ track_item->setAttribute(html_names::kAriaCheckedAttr, "false");
+ }
}
// Allows to focus the list entry instead of the button.
@@ -131,8 +142,16 @@ Element* MediaControlTextTrackListElement::CreateTextTrackListItem(
// the other way around.
if (!MediaControlsImpl::IsModern())
track_item->ParserAppendChild(track_item_input);
+
+ // Set track label into an aria-hidden span so that aria will not repeat the
+ // contents twice.
String track_label = GetMediaControls().GetTextTrackLabel(track);
- track_item->ParserAppendChild(Text::Create(GetDocument(), track_label));
+ HTMLSpanElement* track_label_span = HTMLSpanElement::Create(GetDocument());
+ track_label_span->setInnerText(track_label, ASSERT_NO_EXCEPTION);
+ track_label_span->setAttribute(html_names::kAriaHiddenAttr, "true");
+ track_item->setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(track_label));
+ track_item->ParserAppendChild(track_label_span);
if (MediaControlsImpl::IsModern())
track_item->ParserAppendChild(track_item_input);
@@ -161,6 +180,11 @@ Element* MediaControlTextTrackListElement::CreateTextTrackHeaderItem() {
Text::Create(GetDocument(),
GetLocale().QueryString(
WebLocalizedString::kOverflowMenuCaptionsSubmenuTitle)));
+ header_item->setAttribute(html_names::kRoleAttr, "button");
+ header_item->setAttribute(
+ html_names::kAriaLabelAttr,
+ AtomicString(GetLocale().QueryString(
+ WebLocalizedString::kAXMediaHideClosedCaptionsMenuButton)));
header_item->setTabIndex(0);
return header_item;
}
@@ -177,16 +201,33 @@ void MediaControlTextTrackListElement::RefreshTextTrackListMenu() {
if (MediaControlsImpl::IsModern())
ParserAppendChild(CreateTextTrackHeaderItem());
+ TextTrackList* track_list = MediaElement().textTracks();
+
// Construct a menu for subtitles and captions. Pass in a nullptr to
// createTextTrackListItem to create the "Off" track item.
- ParserAppendChild(CreateTextTrackListItem(nullptr));
+ auto* off_track = CreateTextTrackListItem(nullptr);
+ off_track->setAttribute(html_names::kAriaSetsizeAttr,
+ WTF::AtomicString::Number(track_list->length() + 1));
+ off_track->setAttribute(html_names::kAriaPosinsetAttr,
+ WTF::AtomicString::Number(1));
+ off_track->setAttribute(html_names::kRoleAttr, "menuitemcheckbox");
+ ParserAppendChild(off_track);
- TextTrackList* track_list = MediaElement().textTracks();
for (unsigned i = 0; i < track_list->length(); i++) {
TextTrack* track = track_list->AnonymousIndexedGetter(i);
if (!track->CanBeRendered())
continue;
- ParserAppendChild(CreateTextTrackListItem(track));
+ auto* track_item = CreateTextTrackListItem(track);
+ track_item->setAttribute(
+ html_names::kAriaSetsizeAttr,
+ WTF::AtomicString::Number(track_list->length() + 1));
+ // We set the position with an offset of 2 because we want to start the
+ // count at 1 (versus 0), and the "Off" track item holds the first position
+ // and isnt included in this loop.
+ track_item->setAttribute(html_names::kAriaPosinsetAttr,
+ WTF::AtomicString::Number(i + 2));
+ track_item->setAttribute(html_names::kRoleAttr, "menuitemcheckbox");
+ ParserAppendChild(track_item);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc
index 2b72e374ee2..b6dbc0983cf 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc
@@ -4,18 +4,35 @@
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h"
+#include "third_party/blink/public/platform/web_size.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
+
+namespace {
+
+// These constants are used to estimate the size of time display element
+// when the time display is hidden.
+constexpr int kDefaultTimeDisplayDigitWidth = 8;
+constexpr int kDefaultTimeDisplayColonWidth = 3;
+constexpr int kDefaultTimeDisplayHeight = 48;
+
+} // namespace
namespace blink {
MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(
MediaControlsImpl& media_controls,
- MediaControlElementType display_type)
- : MediaControlDivElement(media_controls, display_type) {}
+ blink::WebLocalizedString::Name localized_label)
+ : MediaControlDivElement(media_controls, kMediaIgnore),
+ localized_label_(localized_label) {
+ SetAriaLabel();
+}
void MediaControlTimeDisplayElement::SetCurrentValue(double time) {
current_value_ = time;
+ SetAriaLabel();
setInnerText(FormatTime(), ASSERT_NO_EXCEPTION);
}
@@ -23,6 +40,18 @@ double MediaControlTimeDisplayElement::CurrentValue() const {
return current_value_;
}
+WebSize MediaControlTimeDisplayElement::GetSizeOrDefault() const {
+ return MediaControlElementsHelper::GetSizeOrDefault(
+ *this, WebSize(EstimateElementWidth(), kDefaultTimeDisplayHeight));
+}
+
+int MediaControlTimeDisplayElement::EstimateElementWidth() const {
+ String formatted_time = MediaControlTimeDisplayElement::FormatTime();
+ int colons = formatted_time.length() > 5 ? 2 : 1;
+ return kDefaultTimeDisplayColonWidth * colons +
+ kDefaultTimeDisplayDigitWidth * (formatted_time.length() - colons);
+}
+
String MediaControlTimeDisplayElement::FormatTime() const {
double time = std::isfinite(current_value_) ? current_value_ : 0;
@@ -50,4 +79,9 @@ String MediaControlTimeDisplayElement::FormatTime() const {
return String::Format("%s%d:%02d", negative_sign, minutes, seconds);
}
+void MediaControlTimeDisplayElement::SetAriaLabel() {
+ String aria_label = GetLocale().QueryString(localized_label_, FormatTime());
+ setAttribute(html_names::kAriaLabelAttr, AtomicString(aria_label));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h
index 28ce2852299..2176a8601fe 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h
@@ -16,16 +16,23 @@ class MediaControlTimeDisplayElement : public MediaControlDivElement {
public:
// Exported to be used in unit tests.
MODULES_EXPORT void SetCurrentValue(double);
- // Exported to be used by modules/accessibility.
MODULES_EXPORT double CurrentValue() const;
+ WebSize GetSizeOrDefault() const override;
+
protected:
- MediaControlTimeDisplayElement(MediaControlsImpl&, MediaControlElementType);
+ MediaControlTimeDisplayElement(MediaControlsImpl&,
+ blink::WebLocalizedString::Name);
+
+ virtual int EstimateElementWidth() const;
virtual String FormatTime() const;
private:
+ void SetAriaLabel();
+
double current_value_ = 0;
+ blink::WebLocalizedString::Name localized_label_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_metrics.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_metrics.cc
index fd0ab0a8bf4..90735801234 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_metrics.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_metrics.cc
@@ -7,7 +7,9 @@
#include <stdint.h>
#include <cmath>
#include <limits>
+
#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -40,7 +42,7 @@ constexpr double kPercentIntervals[] = {
};
// Must match length of UMA MediaTimelinePercent enum.
constexpr int32_t kPercentBucketCount = 51;
-static_assert(arraysize(kPercentIntervals) * 2 - 1 == kPercentBucketCount,
+static_assert(base::size(kPercentIntervals) * 2 - 1 == kPercentBucketCount,
"Intervals must match UMA MediaTimelinePercent enum");
// Corresponds to two UMA enums of different sizes! Values are the exclusive
@@ -81,16 +83,17 @@ constexpr double kTimeDeltaMSIntervals[] = {
constexpr int32_t kAbsTimeDeltaBucketCount = 25;
// Must match length of UMA MediaTimelineTimeDelta enum.
constexpr int32_t kTimeDeltaBucketCount = 49;
-static_assert(arraysize(kTimeDeltaMSIntervals) == kAbsTimeDeltaBucketCount,
+static_assert(base::size(kTimeDeltaMSIntervals) == kAbsTimeDeltaBucketCount,
"Intervals must match UMA MediaTimelineAbsTimeDelta enum");
-static_assert(arraysize(kTimeDeltaMSIntervals) * 2 - 1 == kTimeDeltaBucketCount,
+static_assert(base::size(kTimeDeltaMSIntervals) * 2 - 1 ==
+ kTimeDeltaBucketCount,
"Intervals must match UMA MediaTimelineTimeDelta enum");
// Calculates index of UMA MediaTimelinePercent enum corresponding to |percent|.
// Negative values use kPercentIntervals in reverse.
int32_t ToPercentSample(double percent) {
- constexpr int32_t kNonNegativeBucketCount = arraysize(kPercentIntervals);
- constexpr int32_t kNegativeBucketCount = arraysize(kPercentIntervals) - 1;
+ constexpr int32_t kNonNegativeBucketCount = base::size(kPercentIntervals);
+ constexpr int32_t kNegativeBucketCount = base::size(kPercentIntervals) - 1;
bool negative = percent < 0;
double abs_percent = std::abs(percent);
if (abs_percent == 0)
@@ -121,8 +124,9 @@ int32_t ToAbsTimeDeltaSample(double sum_abs_delta_seconds) {
// Calculates index of UMA MediaTimelineTimeDelta enum corresponding to
// |deltaSeconds|. Negative values use kTimeDeltaMSIntervals in reverse.
int32_t ToTimeDeltaSample(double delta_seconds) {
- constexpr int32_t kNonNegativeBucketCount = arraysize(kTimeDeltaMSIntervals);
- constexpr int32_t kNegativeBucketCount = arraysize(kTimeDeltaMSIntervals) - 1;
+ constexpr int32_t kNonNegativeBucketCount = base::size(kTimeDeltaMSIntervals);
+ constexpr int32_t kNegativeBucketCount =
+ base::size(kTimeDeltaMSIntervals) - 1;
bool negative = delta_seconds < 0;
double abs_delta_ms = 1000 * std::abs(delta_seconds);
if (abs_delta_ms == 0)
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_toggle_closed_captions_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_toggle_closed_captions_button_element.cc
index 3b9c4470345..7236ac4f571 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_toggle_closed_captions_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_toggle_closed_captions_button_element.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/platform/language.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
@@ -45,7 +46,10 @@ bool UseClosedCaptionsIcon() {
MediaControlToggleClosedCaptionsButtonElement::
MediaControlToggleClosedCaptionsButtonElement(
MediaControlsImpl& media_controls)
- : MediaControlInputElement(media_controls, kMediaShowClosedCaptionsButton) {
+ : MediaControlInputElement(media_controls, kMediaIgnore) {
+ setAttribute(html_names::kAriaLabelAttr,
+ WTF::AtomicString(GetLocale().QueryString(
+ WebLocalizedString::kAXMediaShowClosedCaptionsMenuButton)));
setType(input_type_names::kButton);
SetShadowPseudoId(
AtomicString("-webkit-media-controls-toggle-closed-captions-button"));
@@ -59,8 +63,6 @@ bool MediaControlToggleClosedCaptionsButtonElement::
void MediaControlToggleClosedCaptionsButtonElement::UpdateDisplayType() {
bool captions_visible = MediaElement().TextTracksVisible();
- SetDisplayType(captions_visible ? kMediaHideClosedCaptionsButton
- : kMediaShowClosedCaptionsButton);
SetClass("visible", captions_visible);
UpdateOverflowString();
@@ -104,7 +106,8 @@ MediaControlToggleClosedCaptionsButtonElement::GetNameForHistograms() const {
void MediaControlToggleClosedCaptionsButtonElement::DefaultEventHandler(
Event& event) {
- if (event.type() == event_type_names::kClick) {
+ if (event.type() == event_type_names::kClick ||
+ event.type() == event_type_names::kGesturetap) {
if (MediaElement().textTracks()->length() == 1) {
// If only one track exists, toggle it on/off
if (MediaElement().textTracks()->HasShowingTracks())
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
index c5dc536c6d0..4c23feba495 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
@@ -18,8 +18,11 @@ namespace blink {
MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(
MediaControlsImpl& media_controls)
- : MediaControlSliderElement(media_controls, kMediaVolumeSlider) {
+ : MediaControlSliderElement(media_controls, kMediaIgnore) {
setAttribute(html_names::kMaxAttr, "1");
+ setAttribute(html_names::kAriaValuemaxAttr, "100");
+ setAttribute(html_names::kAriaValueminAttr, "0");
+ setAttribute(html_names::kAriaLabelAttr, "volume");
SetShadowPseudoId(AtomicString("-webkit-media-controls-volume-slider"));
SetVolumeInternal(MediaElement().volume());
@@ -104,6 +107,9 @@ void MediaControlVolumeSliderElement::DefaultEventHandler(Event& event) {
void MediaControlVolumeSliderElement::SetVolumeInternal(double volume) {
SetupBarSegments();
SetAfterSegmentPosition(MediaControlSliderElement::Position(0, volume));
+ int percent_vol = 100 * volume;
+ setAttribute(html_names::kAriaValuenowAttr,
+ WTF::AtomicString::Number(percent_vol));
}
bool MediaControlVolumeSliderElement::KeepEventInNode(
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.cc
index 6ec2a003c3e..6fe4120049a 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.cc
@@ -38,7 +38,7 @@ bool MediaControlsDisplayCutoutDelegate::IsEnabled() {
MediaControlsDisplayCutoutDelegate::MediaControlsDisplayCutoutDelegate(
HTMLVideoElement& video_element)
- : EventListener(kCPPEventListenerType), video_element_(video_element) {}
+ : video_element_(video_element) {}
void MediaControlsDisplayCutoutDelegate::Attach() {
DCHECK(video_element_->isConnected());
@@ -58,13 +58,8 @@ void MediaControlsDisplayCutoutDelegate::Detach() {
this, true);
}
-bool MediaControlsDisplayCutoutDelegate::operator==(
- const EventListener& other) const {
- return this == &other;
-}
-
void MediaControlsDisplayCutoutDelegate::Trace(blink::Visitor* visitor) {
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
visitor->Trace(video_element_);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.h
index 3ccce82c0a7..345d8f15992 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_DISPLAY_CUTOUT_DELEGATE_H_
#include "base/optional.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
@@ -19,7 +19,7 @@ class TouchEvent;
// to expand the video element into the display cutout when the video is
// fullscreen.
class MODULES_EXPORT MediaControlsDisplayCutoutDelegate final
- : public EventListener {
+ : public NativeEventListener {
public:
static bool IsEnabled();
@@ -34,7 +34,8 @@ class MODULES_EXPORT MediaControlsDisplayCutoutDelegate final
// object to be garbage collected.
void Detach();
- bool operator==(const EventListener&) const override;
+ // EventListener implementation.
+ void Invoke(ExecutionContext*, Event*) override;
void Trace(blink::Visitor*) override;
@@ -56,9 +57,6 @@ class MODULES_EXPORT MediaControlsDisplayCutoutDelegate final
void DidEnterFullscreen();
void DidExitFullscreen();
- // EventListener implementation.
- void Invoke(ExecutionContext*, Event*) override;
-
void HandleTouchEvent(TouchEvent*);
Document& GetDocument();
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc
index 7400de9b652..d770f96482d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc
@@ -39,7 +39,7 @@ class DisplayCutoutMockChromeClient : public EmptyChromeClient {
class MediaControlsDisplayCutoutDelegateTest : public PageTestBase {
public:
void SetUp() override {
- chrome_client_ = new DisplayCutoutMockChromeClient();
+ chrome_client_ = MakeGarbageCollected<DisplayCutoutMockChromeClient>();
Page::PageClients clients;
FillWithEmptyClients(clients);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 94816019705..1e45d068182 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -30,11 +30,14 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html.h"
+#include "third_party/blink/renderer/core/css/css_property_value_set.h"
+#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/mutation_observer.h"
#include "third_party/blink/renderer/core/dom/mutation_observer_init.h"
#include "third_party/blink/renderer/core/dom/mutation_record.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/events/gesture_event.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/frame/settings.h"
@@ -55,6 +58,7 @@
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_consts.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h"
@@ -82,7 +86,6 @@
#include "third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h"
#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
-#include "third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h"
#include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -133,6 +136,7 @@ const char kActAsAudioControlsCSSClass[] = "audio-only";
const char kScrubbingMessageCSSClass[] = "scrubbing-message";
const char kTestModeCSSClass[] = "test-mode";
const char kImmersiveModeCSSClass[] = "immersive-mode";
+const char kPipPresentedCSSClass[] = "pip-presented";
// The delay between two taps to be recognized as a double tap gesture.
constexpr WTF::TimeDelta kDoubleTapDelay = TimeDelta::FromMilliseconds(300);
@@ -208,9 +212,7 @@ bool ShouldShowCastButton(HTMLMediaElement& media_element) {
return false;
}
- RemotePlayback* remote =
- HTMLMediaElementRemotePlayback::remote(media_element);
- return remote && remote->RemotePlaybackAvailable();
+ return RemotePlayback::From(media_element).RemotePlaybackAvailable();
}
bool PreferHiddenVolumeControls(const Document& document) {
@@ -693,8 +695,14 @@ void MediaControlsImpl::PopulatePanel() {
// On modern controls, the volume slider is to the left of the mute button.
if (IsModern()) {
- MaybeParserAppendChild(button_panel, volume_slider_);
- button_panel->ParserAppendChild(mute_button_);
+ volume_control_container_ = MediaControlElementsHelper::CreateDiv(
+ "-webkit-media-controls-volume-control-container", button_panel);
+ MediaControlElementsHelper::CreateDiv(
+ "-webkit-media-controls-volume-control-hover-background",
+ volume_control_container_);
+ MaybeParserAppendChild(volume_control_container_, volume_slider_);
+ volume_control_container_->ParserAppendChild(mute_button_);
+ HideVolumeControlHoverBackground();
} else {
button_panel->ParserAppendChild(mute_button_);
MaybeParserAppendChild(button_panel, volume_slider_);
@@ -713,6 +721,19 @@ void MediaControlsImpl::PopulatePanel() {
}
button_panel->ParserAppendChild(overflow_menu_);
+
+ // Attach hover background div to modern controls
+ if (IsModern()) {
+ AttachHoverBackground(play_button_);
+ AttachHoverBackground(fullscreen_button_);
+ AttachHoverBackground(overflow_menu_);
+ }
+}
+
+void MediaControlsImpl::AttachHoverBackground(Element* element) {
+ MediaControlElementsHelper::CreateDiv(
+ "-internal-media-controls-button-hover-background",
+ element->GetShadowRoot());
}
Node::InsertionNotificationRequest MediaControlsImpl::InsertedInto(
@@ -1062,10 +1083,10 @@ bool MediaControlsImpl::ShouldHideMediaControls(unsigned behavior_flags) const {
return false;
}
- RemotePlayback* remote =
- HTMLMediaElementRemotePlayback::remote(MediaElement());
- if (remote && remote->GetState() != WebRemotePlaybackState::kDisconnected)
+ if (RemotePlayback::From(MediaElement()).GetState() !=
+ WebRemotePlaybackState::kDisconnected) {
return false;
+ }
// Keep the controls visible as long as the timer is running.
const bool ignore_wait_for_timer = behavior_flags & kIgnoreWaitForTimer;
@@ -1073,8 +1094,10 @@ bool MediaControlsImpl::ShouldHideMediaControls(unsigned behavior_flags) const {
return false;
// Don't hide if the mouse is over the controls.
+ // Touch focus shouldn't affect controls visibility.
const bool ignore_controls_hover = behavior_flags & kIgnoreControlsHover;
- if (!ignore_controls_hover && AreVideoControlsHovered())
+ if (!ignore_controls_hover && AreVideoControlsHovered() &&
+ !is_touch_interaction_)
return false;
// Don't hide if the mouse is over the video area.
@@ -1128,6 +1151,11 @@ HTMLDivElement* MediaControlsImpl::PanelElement() {
return panel_;
}
+HTMLDivElement* MediaControlsImpl::ButtonPanelElement() {
+ DCHECK(IsModern());
+ return media_button_panel_;
+}
+
void MediaControlsImpl::BeginScrubbing(bool is_touch_event) {
if (!MediaElement().paused()) {
is_paused_for_scrubbing_ = true;
@@ -1377,6 +1405,9 @@ void MediaControlsImpl::UpdateOverflowMenuWanted() const {
((controls_size.width - element_size.width) >= 0);
element->SetDoesFit(does_fit);
+ if (element == mute_button_.Get() && IsModern())
+ SetVolumeControlContainerIsWanted(does_fit);
+
// The element does fit and is sticky so we should allocate space for it. If
// we cannot fit this element we should stop allocating space for other
// elements.
@@ -1405,12 +1436,40 @@ void MediaControlsImpl::UpdateOverflowMenuWanted() const {
controls_size.width < overflow_icon_width) {
last_element->SetDoesFit(false);
last_element->SetOverflowElementIsWanted(true);
+
+ if (last_element == mute_button_.Get() && IsModern())
+ SetVolumeControlContainerIsWanted(false);
}
MaybeRecordElementsDisplayed();
if (download_iph_manager_)
download_iph_manager_->UpdateInProductHelp();
+
+ UpdateOverflowAndTrackListCSSClassForPip();
+ UpdateOverflowMenuItemCSSClass();
+}
+
+// This method is responsible for adding css class to overflow menu list
+// items to achieve the animation that items appears one after another when
+// open the overflow menu.
+void MediaControlsImpl::UpdateOverflowMenuItemCSSClass() const {
+ unsigned int id = 0;
+ for (Element* item = ElementTraversal::LastChild(*overflow_list_); item;
+ item = ElementTraversal::PreviousSibling(*item)) {
+ const CSSPropertyValueSet* inline_style = item->InlineStyle();
+ DOMTokenList& class_list = item->classList();
+
+ // We don't care if the hidden element still have animated-* CSS class
+ if (inline_style &&
+ inline_style->GetPropertyValue(CSSPropertyDisplay) == "none")
+ continue;
+
+ AtomicString css_class =
+ AtomicString("animated-") + AtomicString::Number(id++);
+ if (!class_list.contains(css_class))
+ class_list.setValue(css_class);
+ }
}
void MediaControlsImpl::UpdateScrubbingMessageFits() const {
@@ -1418,6 +1477,21 @@ void MediaControlsImpl::UpdateScrubbingMessageFits() const {
scrubbing_message_->SetDoesFit(size_.Width() >= kMinScrubbingMessageWidth);
}
+// We want to have wider menu when pip is enabled so that "Exit picture in
+// picture" text won't be truncated. When pip is disable (e.g. on mobile
+// device), we don't want to enlarged the menu because it would look empty
+// when "picture in picture" text is not presented.
+void MediaControlsImpl::UpdateOverflowAndTrackListCSSClassForPip() const {
+ if (picture_in_picture_button_.Get() &&
+ picture_in_picture_button_.Get()->OverflowElementIsWanted()) {
+ overflow_list_->classList().Add(kPipPresentedCSSClass);
+ text_track_list_->classList().Add(kPipPresentedCSSClass);
+ } else {
+ overflow_list_->classList().Remove(kPipPresentedCSSClass);
+ text_track_list_->classList().Remove(kPipPresentedCSSClass);
+ }
+}
+
void MediaControlsImpl::UpdateSizingCSSClass() {
MediaControlsSizingClass sizing_class =
MediaControls::GetSizingClass(size_.Width());
@@ -1441,7 +1515,8 @@ void MediaControlsImpl::MaybeToggleControlsFromTap() {
MakeTransparent();
} else {
MakeOpaque();
- if (ShouldHideMediaControls(kIgnoreWaitForTimer)) {
+ // Touch focus shouldn't affect controls visibility.
+ if (ShouldHideMediaControls(kIgnoreWaitForTimer | kIgnoreFocus)) {
keep_showing_until_timer_fires_ = true;
StartHideMediaControlsTimer();
}
@@ -1556,13 +1631,22 @@ void MediaControlsImpl::HandlePointerEvent(Event* event) {
if (!ContainsRelatedTarget(event)) {
is_mouse_over_controls_ = false;
StopHideMediaControlsTimer();
+
+ // When we get a mouse out, if video is playing and control should
+ // hide regardless of focus, hide the control.
+ // This will fix the issue that when mouse out event happen while video is
+ // focused, control never hides.
+ if (!MediaElement().paused() && ShouldHideMediaControls(kIgnoreFocus))
+ MakeTransparent();
}
} else if (event->type() == event_type_names::kPointermove) {
// When we get a mouse move, show the media controls, and start a timer
// that will hide the media controls after a 3 seconds without a mouse move.
is_mouse_over_controls_ = true;
MakeOpaqueFromPointerEvent();
- if (ShouldHideMediaControls(kIgnoreVideoHover))
+
+ // Start the timer regardless of focus state
+ if (ShouldHideMediaControls(kIgnoreVideoHover | kIgnoreFocus))
StartHideMediaControlsTimer();
}
}
@@ -1603,10 +1687,14 @@ void MediaControlsImpl::HandleTouchEvent(Event* event) {
is_mouse_over_controls_ = false;
is_touch_interaction_ = true;
- if (event->type() == event_type_names::kClick &&
+ if (event->type() == event_type_names::kGesturetap &&
!ContainsRelatedTarget(event)) {
event->SetDefaultHandled();
+ // Since handling the gesturetap event will prevent the click event from
+ // happening, we need to manually hide any popups.
+ HidePopupMenu();
+
// In immersive mode we don't use double-tap features, so instead of
// waiting 300 ms for a potential second tap, we just immediately toggle
// controls visiblity.
@@ -1671,16 +1759,14 @@ void MediaControlsImpl::MaybeJump(int seconds) {
}
bool MediaControlsImpl::IsOnLeftSide(Event* event) {
- if (!event->IsMouseEvent())
+ if (!event->IsGestureEvent())
return false;
- MouseEvent* mouse_event = ToMouseEvent(event);
- if (!mouse_event->HasPosition())
- return false;
+ float tap_x = ToGestureEvent(event)->NativeEvent().PositionInWidget().x;
DOMRect* rect = getBoundingClientRect();
double middle = rect->x() + (rect->width() / 2);
- return mouse_event->clientX() < middle;
+ return tap_x < middle;
}
void MediaControlsImpl::TapTimerFired(TimerBase*) {
@@ -1784,7 +1870,9 @@ void MediaControlsImpl::OnVolumeChange() {
}
void MediaControlsImpl::OnFocusIn() {
- if (!MediaElement().ShouldShowControls())
+ // If the tap timer is active, then we will toggle the controls when the timer
+ // completes, so we don't want to start showing here.
+ if (!MediaElement().ShouldShowControls() || tap_timer_.IsActive())
return;
ResetHideMediaControlsTimer();
@@ -1948,6 +2036,9 @@ void MediaControlsImpl::NotifyElementSizeChanged(DOMRectReadOnly* new_size) {
void MediaControlsImpl::ElementSizeChangedTimerFired(TimerBase*) {
ComputeWhichControlsFit();
+
+ // Rerender timeline bar segments when size changed.
+ timeline_->RenderBarSegments();
}
void MediaControlsImpl::OnLoadingProgress() {
@@ -2202,6 +2293,14 @@ void MediaControlsImpl::ToggleOverflowMenu() {
overflow_list_->SetIsWanted(!overflow_list_->IsWanted());
}
+void MediaControlsImpl::HidePopupMenu() {
+ if (OverflowMenuVisible())
+ ToggleOverflowMenu();
+
+ if (TextTrackListIsWanted())
+ ToggleTextTrackList();
+}
+
void MediaControlsImpl::StartHideMediaControlsIfNecessary() {
if (ShouldHideMediaControls())
StartHideMediaControlsTimer();
@@ -2209,6 +2308,7 @@ void MediaControlsImpl::StartHideMediaControlsIfNecessary() {
void MediaControlsImpl::VolumeSliderWantedTimerFired(TimerBase*) {
volume_slider_->OpenSlider();
+ ShowVolumeControlHoverBackground();
}
void MediaControlsImpl::OpenVolumeSliderIfNecessary() {
@@ -2216,6 +2316,7 @@ void MediaControlsImpl::OpenVolumeSliderIfNecessary() {
if (volume_slider_->IsFocused() || mute_button_->IsFocused()) {
// When we're focusing with the keyboard, we don't need the delay.
volume_slider_->OpenSlider();
+ ShowVolumeControlHoverBackground();
} else {
volume_slider_wanted_timer_.StartOneShot(
WebTestSupport::IsRunningWebTest() ? kTimeToShowVolumeSliderTest
@@ -2228,12 +2329,31 @@ void MediaControlsImpl::OpenVolumeSliderIfNecessary() {
void MediaControlsImpl::CloseVolumeSliderIfNecessary() {
if (ShouldCloseVolumeSlider()) {
volume_slider_->CloseSlider();
+ HideVolumeControlHoverBackground();
if (volume_slider_wanted_timer_.IsActive())
volume_slider_wanted_timer_.Stop();
}
}
+void MediaControlsImpl::ShowVolumeControlHoverBackground() {
+ volume_control_container_->classList().Remove(kClosedCSSClass);
+}
+
+void MediaControlsImpl::HideVolumeControlHoverBackground() {
+ volume_control_container_->classList().Add(kClosedCSSClass);
+}
+
+void MediaControlsImpl::SetVolumeControlContainerIsWanted(
+ bool is_wanted) const {
+ if (is_wanted) {
+ volume_control_container_->RemoveInlineStyleProperty(CSSPropertyDisplay);
+ } else {
+ volume_control_container_->SetInlineStyleProperty(CSSPropertyDisplay,
+ CSSValueNone);
+ }
+}
+
bool MediaControlsImpl::ShouldOpenVolumeSlider() const {
if (!volume_slider_ || !IsModern())
return false;
@@ -2316,6 +2436,7 @@ void MediaControlsImpl::Trace(blink::Visitor* visitor) {
visitor->Trace(media_button_panel_);
visitor->Trace(loading_panel_);
visitor->Trace(display_cutout_fullscreen_button_);
+ visitor->Trace(volume_control_container_);
MediaControls::Trace(visitor);
HTMLDivElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
index fc5927e83a6..393f4e73f2f 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -111,6 +111,7 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
// Return the internal elements, which is used by registering clicking
// EventHandlers from MediaControlsWindowEventListener.
HTMLDivElement* PanelElement() override;
+ HTMLDivElement* ButtonPanelElement();
// TODO(mlamouri): this method is needed in order to notify the controls that
// the `MediaControlsEnabled` setting has changed.
void OnMediaControlsEnabledChange() override {
@@ -248,6 +249,9 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
void InitializeControls();
void PopulatePanel();
+ // Attach hover background div to buttons
+ void AttachHoverBackground(Element*);
+
void MakeOpaque();
void MakeOpaqueFromPointerEvent();
void MakeTransparent();
@@ -278,6 +282,9 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
bool ShouldOpenVolumeSlider() const;
bool ShouldCloseVolumeSlider() const;
+ void ShowVolumeControlHoverBackground();
+ void HideVolumeControlHoverBackground();
+ void SetVolumeControlContainerIsWanted(bool) const;
void ElementSizeChangedTimerFired(TimerBase*);
@@ -286,8 +293,11 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
// current.
void ComputeWhichControlsFit();
+ void HidePopupMenu();
void UpdateOverflowMenuWanted() const;
+ void UpdateOverflowMenuItemCSSClass() const;
void UpdateScrubbingMessageFits() const;
+ void UpdateOverflowAndTrackListCSSClassForPip() const;
void UpdateSizingCSSClass();
void MaybeRecordElementsDisplayed() const;
@@ -389,6 +399,8 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
bool is_paused_for_scrubbing_ : 1;
bool is_scrubbing_ = false;
+ Member<HTMLDivElement> volume_control_container_;
+
// Watches the video element for resize and updates media controls as
// necessary.
Member<ResizeObserver> resize_observer_;
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
index dadc1b88038..24970dfd94b 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -34,12 +34,12 @@
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h"
#include "third_party/blink/renderer/modules/media_controls/media_download_in_product_help_manager.h"
-#include "third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h"
#include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
@@ -109,7 +109,7 @@ class MockLayoutObject : public LayoutObject {
class StubLocalFrameClientForImpl : public EmptyLocalFrameClient {
public:
static StubLocalFrameClientForImpl* Create() {
- return new StubLocalFrameClientForImpl;
+ return MakeGarbageCollected<StubLocalFrameClientForImpl>();
}
std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
@@ -122,7 +122,7 @@ class StubLocalFrameClientForImpl : public EmptyLocalFrameClient {
WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
HTMLMediaElement& element) override {
- return HTMLMediaElementRemotePlayback::remote(element);
+ return &RemotePlayback::From(element);
}
};
@@ -210,7 +210,7 @@ class MediaControlsImplTest : public PageTestBase,
void InitializePage() {
Page::PageClients clients;
FillWithEmptyClients(clients);
- clients.chrome_client = new MockChromeClientForImpl();
+ clients.chrome_client = MakeGarbageCollected<MockChromeClientForImpl>();
SetupPageWithClients(&clients, StubLocalFrameClientForImpl::Create());
GetDocument().GetSettings()->SetMediaDownloadInProductHelpEnabled(
EnableDownloadInProductHelp());
@@ -256,6 +256,9 @@ class MediaControlsImplTest : public PageTestBase,
const {
return media_controls_->duration_display_;
}
+ MediaControlMuteButtonElement* MuteButtonElement() const {
+ return media_controls_->mute_button_;
+ }
MockWebMediaPlayerForImpl* WebMediaPlayer() {
return static_cast<MockWebMediaPlayerForImpl*>(
MediaControls().MediaElement().GetWebMediaPlayer());
@@ -291,8 +294,8 @@ class MediaControlsImplTest : public PageTestBase,
void MouseMoveTo(WebFloatPoint pos);
void MouseUpAt(WebFloatPoint pos);
- bool HasAvailabilityCallbacks(RemotePlayback* remote_playback) {
- return !remote_playback->availability_callbacks_.IsEmpty();
+ bool HasAvailabilityCallbacks(RemotePlayback& remote_playback) {
+ return !remote_playback.availability_callbacks_.IsEmpty();
}
virtual bool EnableDownloadInProductHelp() { return false; }
@@ -1050,17 +1053,17 @@ TEST_F(MediaControlsImplTestWithMockScheduler,
// Tabbing between controls prevents controls from hiding.
platform()->RunForPeriodSeconds(2);
- MediaControls().DispatchEvent(*Event::Create("focusin"));
+ MuteButtonElement()->DispatchEvent(*Event::CreateBubble("focusin"));
platform()->RunForPeriodSeconds(2);
EXPECT_TRUE(IsElementVisible(*panel));
// Seeking on the timeline or volume bar prevents controls from hiding.
- MediaControls().DispatchEvent(*Event::Create("input"));
+ TimelineElement()->DispatchEvent(*Event::CreateBubble("input"));
platform()->RunForPeriodSeconds(2);
EXPECT_TRUE(IsElementVisible(*panel));
// Pressing a key prevents controls from hiding.
- MediaControls().PanelElement()->DispatchEvent(*Event::Create("keypress"));
+ MuteButtonElement()->DispatchEvent(*Event::CreateBubble("keypress"));
platform()->RunForPeriodSeconds(2);
EXPECT_TRUE(IsElementVisible(*panel));
@@ -1070,6 +1073,53 @@ TEST_F(MediaControlsImplTestWithMockScheduler,
EXPECT_FALSE(IsElementVisible(*panel));
}
+TEST_F(MediaControlsImplTestWithMockScheduler,
+ ControlsHideAfterFocusedAndMouseMovement) {
+ EnsureSizing();
+
+ Element* panel = MediaControls().PanelElement();
+ MediaControls().MediaElement().SetSrc("http://example.com");
+ MediaControls().MediaElement().Play();
+
+ // Controls start out visible
+ EXPECT_TRUE(IsElementVisible(*panel));
+ platform()->RunForPeriodSeconds(1);
+
+ // Mouse move while focused
+ MediaControls().DispatchEvent(*Event::Create("focusin"));
+ MediaControls().MediaElement().SetFocused(true,
+ WebFocusType::kWebFocusTypeNone);
+ MediaControls().DispatchEvent(*Event::Create("pointermove"));
+
+ // Controls should remain visible
+ platform()->RunForPeriodSeconds(2);
+ EXPECT_TRUE(IsElementVisible(*panel));
+
+ // Controls should hide after being inactive for 4 seconds.
+ platform()->RunForPeriodSeconds(2);
+ EXPECT_FALSE(IsElementVisible(*panel));
+}
+
+TEST_F(MediaControlsImplTestWithMockScheduler,
+ ControlsHideAfterFocusedAndMouseMoveout) {
+ EnsureSizing();
+
+ Element* panel = MediaControls().PanelElement();
+ MediaControls().MediaElement().SetSrc("http://example.com");
+ MediaControls().MediaElement().Play();
+
+ // Controls start out visible
+ EXPECT_TRUE(IsElementVisible(*panel));
+ platform()->RunForPeriodSeconds(1);
+
+ // Mouse move out while focused, controls should hide
+ MediaControls().DispatchEvent(*Event::Create("focusin"));
+ MediaControls().MediaElement().SetFocused(true,
+ WebFocusType::kWebFocusTypeNone);
+ MediaControls().DispatchEvent(*Event::Create("pointerout"));
+ EXPECT_FALSE(IsElementVisible(*panel));
+}
+
TEST_F(MediaControlsImplTestWithMockScheduler, CursorHidesWhenControlsHide) {
EnsureSizing();
@@ -1131,10 +1181,9 @@ TEST_F(MediaControlsImplTest,
HTMLVideoElement::Create(page_holder->GetDocument());
page_holder->GetDocument().body()->AppendChild(element);
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
- EXPECT_TRUE(remote_playback->HasEventListeners());
+ EXPECT_TRUE(remote_playback.HasEventListeners());
EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback));
WeakPersistent<HTMLMediaElement> weak_persistent_video = element;
@@ -1144,7 +1193,7 @@ TEST_F(MediaControlsImplTest,
// When removed from the document, the event listeners should have been
// dropped.
- EXPECT_FALSE(remote_playback->HasEventListeners());
+ EXPECT_FALSE(remote_playback.HasEventListeners());
EXPECT_FALSE(HasAvailabilityCallbacks(remote_playback));
}
@@ -1164,8 +1213,7 @@ TEST_F(MediaControlsImplTest,
HTMLVideoElement::Create(page_holder->GetDocument());
page_holder->GetDocument().body()->AppendChild(element);
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
// This should be a no-op. We keep a reference on the media element to avoid
// an unexpected GC.
@@ -1173,7 +1221,7 @@ TEST_F(MediaControlsImplTest,
Persistent<HTMLMediaElement> video_holder = element;
page_holder->GetDocument().body()->RemoveChild(element);
page_holder->GetDocument().body()->AppendChild(video_holder.Get());
- EXPECT_TRUE(remote_playback->HasEventListeners());
+ EXPECT_TRUE(remote_playback.HasEventListeners());
EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback));
}
}
@@ -1292,10 +1340,8 @@ TEST_F(MediaControlsImplTestWithMockScheduler,
WebTestSupport::SetIsRunningWebTest(false);
- Element* volume_slider = GetElementByShadowPseudoId(
- MediaControls(), "-webkit-media-controls-volume-slider");
- Element* mute_btn = GetElementByShadowPseudoId(
- MediaControls(), "-webkit-media-controls-mute-button");
+ Element* volume_slider = VolumeSliderElement();
+ Element* mute_btn = MuteButtonElement();
ASSERT_NE(nullptr, volume_slider);
ASSERT_NE(nullptr, mute_btn);
@@ -1337,8 +1383,7 @@ TEST_F(MediaControlsImplTestWithMockScheduler,
WebTestSupport::SetIsRunningWebTest(false);
- Element* volume_slider = GetElementByShadowPseudoId(
- MediaControls(), "-webkit-media-controls-volume-slider");
+ Element* volume_slider = VolumeSliderElement();
ASSERT_NE(nullptr, volume_slider);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.cc
index 088f046bf30..358122070b6 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.cc
@@ -11,7 +11,6 @@
#include "third_party/blink/renderer/core/html/track/text_track_list.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h"
-#include "third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h"
#include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -19,7 +18,7 @@ namespace blink {
MediaControlsMediaEventListener::MediaControlsMediaEventListener(
MediaControlsImpl* media_controls)
- : EventListener(kCPPEventListenerType), media_controls_(media_controls) {
+ : media_controls_(media_controls) {
if (GetMediaElement().isConnected())
Attach();
}
@@ -75,26 +74,32 @@ void MediaControlsMediaEventListener::Attach() {
text_tracks->addEventListener(event_type_names::kRemovetrack, this, false);
// Keypress events.
- if (media_controls_->PanelElement()) {
- media_controls_->PanelElement()->addEventListener(
- event_type_names::kKeypress, this, false);
+ if (MediaControlsImpl::IsModern()) {
+ if (media_controls_->ButtonPanelElement()) {
+ media_controls_->ButtonPanelElement()->addEventListener(
+ event_type_names::kKeypress, this, false);
+ }
+ } else {
+ if (media_controls_->PanelElement()) {
+ media_controls_->PanelElement()->addEventListener(
+ event_type_names::kKeypress, this, false);
+ }
}
- RemotePlayback* remote = GetRemotePlayback();
- if (remote) {
- remote->addEventListener(event_type_names::kConnect, this);
- remote->addEventListener(event_type_names::kConnecting, this);
- remote->addEventListener(event_type_names::kDisconnect, this);
-
- // TODO(avayvod, mlamouri): Attach can be called twice. See
- // https://crbug.com/713275.
- if (!remote_playback_availability_callback_id_.has_value()) {
- remote_playback_availability_callback_id_ = base::make_optional(
- remote->WatchAvailabilityInternal(new AvailabilityCallbackWrapper(
- WTF::BindRepeating(&MediaControlsMediaEventListener::
- OnRemotePlaybackAvailabilityChanged,
- WrapWeakPersistent(this)))));
- }
+ RemotePlayback& remote = RemotePlayback::From(GetMediaElement());
+ remote.addEventListener(event_type_names::kConnect, this);
+ remote.addEventListener(event_type_names::kConnecting, this);
+ remote.addEventListener(event_type_names::kDisconnect, this);
+
+ // TODO(avayvod, mlamouri): Attach can be called twice. See
+ // https://crbug.com/713275.
+ if (!remote_playback_availability_callback_id_.has_value()) {
+ remote_playback_availability_callback_id_ =
+ base::make_optional(remote.WatchAvailabilityInternal(
+ MakeGarbageCollected<AvailabilityCallbackWrapper>(
+ WTF::BindRepeating(&MediaControlsMediaEventListener::
+ OnRemotePlaybackAvailabilityChanged,
+ WrapWeakPersistent(this)))));
}
}
@@ -109,42 +114,38 @@ void MediaControlsMediaEventListener::Detach() {
text_tracks->removeEventListener(event_type_names::kChange, this, false);
text_tracks->removeEventListener(event_type_names::kRemovetrack, this, false);
- if (media_controls_->PanelElement()) {
- media_controls_->PanelElement()->removeEventListener(
- event_type_names::kKeypress, this, false);
- }
-
- RemotePlayback* remote = GetRemotePlayback();
- if (remote) {
- remote->removeEventListener(event_type_names::kConnect, this);
- remote->removeEventListener(event_type_names::kConnecting, this);
- remote->removeEventListener(event_type_names::kDisconnect, this);
-
- // TODO(avayvod): apparently Detach() can be called without a previous
- // Attach() call. See https://crbug.com/713275 for more details.
- if (remote_playback_availability_callback_id_.has_value() &&
- remote_playback_availability_callback_id_.value() !=
- RemotePlayback::kWatchAvailabilityNotSupported) {
- remote->CancelWatchAvailabilityInternal(
- remote_playback_availability_callback_id_.value());
- remote_playback_availability_callback_id_.reset();
+ if (MediaControlsImpl::IsModern()) {
+ if (media_controls_->ButtonPanelElement()) {
+ media_controls_->ButtonPanelElement()->removeEventListener(
+ event_type_names::kKeypress, this, false);
+ }
+ } else {
+ if (media_controls_->PanelElement()) {
+ media_controls_->PanelElement()->removeEventListener(
+ event_type_names::kKeypress, this, false);
}
}
-}
-bool MediaControlsMediaEventListener::operator==(
- const EventListener& other) const {
- return this == &other;
+ RemotePlayback& remote = RemotePlayback::From(GetMediaElement());
+ remote.removeEventListener(event_type_names::kConnect, this);
+ remote.removeEventListener(event_type_names::kConnecting, this);
+ remote.removeEventListener(event_type_names::kDisconnect, this);
+
+ // TODO(avayvod): apparently Detach() can be called without a previous
+ // Attach() call. See https://crbug.com/713275 for more details.
+ if (remote_playback_availability_callback_id_.has_value() &&
+ remote_playback_availability_callback_id_.value() !=
+ RemotePlayback::kWatchAvailabilityNotSupported) {
+ remote.CancelWatchAvailabilityInternal(
+ remote_playback_availability_callback_id_.value());
+ remote_playback_availability_callback_id_.reset();
+ }
}
HTMLMediaElement& MediaControlsMediaEventListener::GetMediaElement() {
return media_controls_->MediaElement();
}
-RemotePlayback* MediaControlsMediaEventListener::GetRemotePlayback() {
- return HTMLMediaElementRemotePlayback::remote(GetMediaElement());
-}
-
void MediaControlsMediaEventListener::Invoke(
ExecutionContext* execution_context,
Event* event) {
@@ -227,9 +228,16 @@ void MediaControlsMediaEventListener::Invoke(
// Keypress events.
if (event->type() == event_type_names::kKeypress) {
- if (event->currentTarget() == media_controls_->PanelElement()) {
- media_controls_->OnPanelKeypress();
- return;
+ if (MediaControlsImpl::IsModern()) {
+ if (event->currentTarget() == media_controls_->ButtonPanelElement()) {
+ media_controls_->OnPanelKeypress();
+ return;
+ }
+ } else {
+ if (event->currentTarget() == media_controls_->PanelElement()) {
+ media_controls_->OnPanelKeypress();
+ return;
+ }
}
}
@@ -256,7 +264,7 @@ void MediaControlsMediaEventListener::OnRemotePlaybackAvailabilityChanged() {
}
void MediaControlsMediaEventListener::Trace(blink::Visitor* visitor) {
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
visitor->Trace(media_controls_);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.h
index 78bc61a1e16..15b691ef2ed 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.h
@@ -6,15 +6,14 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_MEDIA_EVENT_LISTENER_H_
#include "base/optional.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
namespace blink {
class HTMLMediaElement;
class MediaControlsImpl;
-class RemotePlayback;
-class MediaControlsMediaEventListener final : public EventListener {
+class MediaControlsMediaEventListener final : public NativeEventListener {
public:
explicit MediaControlsMediaEventListener(MediaControlsImpl*);
@@ -27,15 +26,12 @@ class MediaControlsMediaEventListener final : public EventListener {
// object to be garbage collected.
void Detach();
- bool operator==(const EventListener&) const override;
-
void Trace(blink::Visitor*) override;
+ void Invoke(ExecutionContext*, Event*) override;
+
private:
HTMLMediaElement& GetMediaElement();
- RemotePlayback* GetRemotePlayback();
-
- void Invoke(ExecutionContext*, Event*) override;
void OnRemotePlaybackAvailabilityChanged();
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc
index e679fc0249d..1136784cc32 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc
@@ -96,7 +96,7 @@ constexpr TimeDelta MediaControlsOrientationLockDelegate::kLockToAnyDelay;
MediaControlsOrientationLockDelegate::MediaControlsOrientationLockDelegate(
HTMLVideoElement& video)
- : EventListener(kCPPEventListenerType), video_element_(video) {
+ : video_element_(video) {
if (VideoElement().isConnected())
Attach();
}
@@ -123,11 +123,6 @@ void MediaControlsOrientationLockDelegate::Detach() {
true);
}
-bool MediaControlsOrientationLockDelegate::operator==(
- const EventListener& other) const {
- return this == &other;
-}
-
void MediaControlsOrientationLockDelegate::MaybeLockOrientation() {
DCHECK(state_ != State::kMaybeLockedFullscreen);
@@ -479,7 +474,7 @@ void MediaControlsOrientationLockDelegate::
}
void MediaControlsOrientationLockDelegate::Trace(blink::Visitor* visitor) {
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
visitor->Trace(video_element_);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h
index 37e14f2ee31..0e934a42de1 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h
@@ -8,7 +8,7 @@
#include "base/optional.h"
#include "services/device/public/mojom/screen_orientation.mojom-blink.h"
#include "third_party/blink/public/common/screen_orientation/web_screen_orientation_lock_type.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
@@ -53,7 +53,7 @@ class HTMLVideoElement;
// - MaybeLockedFullscreen => PendingFullscreen: on fullscreenchange event
// (exiting fullscreen) or on deviceorientation event (rotated to match the
// orientation of the video).
-class MediaControlsOrientationLockDelegate final : public EventListener {
+class MediaControlsOrientationLockDelegate final : public NativeEventListener {
public:
explicit MediaControlsOrientationLockDelegate(HTMLVideoElement&);
@@ -66,9 +66,8 @@ class MediaControlsOrientationLockDelegate final : public EventListener {
// object to be garbage collected.
void Detach();
- // EventListener implementation.
- bool operator==(const EventListener&) const override;
-
+ // NativeEventListener implementation.
+ void Invoke(ExecutionContext*, Event*) override;
void Trace(blink::Visitor*) override;
private:
@@ -89,9 +88,6 @@ class MediaControlsOrientationLockDelegate final : public EventListener {
kLandscape
};
- // EventListener implementation.
- void Invoke(ExecutionContext*, Event*) override;
-
HTMLVideoElement& VideoElement() const;
Document& GetDocument() const;
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
index 12def003f73..09e9f75c6b0 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
@@ -140,7 +140,8 @@ class StubLocalFrameClientForOrientationLockDelegate final
: public EmptyLocalFrameClient {
public:
static StubLocalFrameClientForOrientationLockDelegate* Create() {
- return new StubLocalFrameClientForOrientationLockDelegate;
+ return MakeGarbageCollected<
+ StubLocalFrameClientForOrientationLockDelegate>();
}
std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
@@ -176,7 +177,8 @@ class MediaControlsOrientationLockDelegateTest
}
void SetUp() override {
- chrome_client_ = new MockChromeClientForOrientationLockDelegate();
+ chrome_client_ =
+ MakeGarbageCollected<MockChromeClientForOrientationLockDelegate>();
Page::PageClients clients;
FillWithEmptyClients(clients);
@@ -298,7 +300,7 @@ class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
void SetUp() override {
// Unset this to fix ScreenOrientationControllerImpl::ComputeOrientation.
// TODO(mlamouri): Refactor to avoid this (crbug.com/726817).
- was_running_layout_test_ = WebTestSupport::IsRunningWebTest();
+ was_running_web_test_ = WebTestSupport::IsRunningWebTest();
WebTestSupport::SetIsRunningWebTest(false);
MediaControlsOrientationLockDelegateTest::SetUp();
@@ -315,7 +317,7 @@ class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
void TearDown() override {
MediaControlsOrientationLockDelegateTest::TearDown();
- WebTestSupport::SetIsRunningWebTest(was_running_layout_test_);
+ WebTestSupport::SetIsRunningWebTest(was_running_web_test_);
}
void SetIsAutoRotateEnabledByUser(bool enabled) {
@@ -424,7 +426,7 @@ class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
->orientation_lock_delegate_->ComputeDeviceOrientation(data);
}
- bool was_running_layout_test_ = false;
+ bool was_running_web_test_ = false;
bool natural_orientation_is_portrait_ = true;
};
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
index 47e05800320..1ff0a8c7c5a 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
@@ -34,7 +34,7 @@ constexpr float kVisibilityThreshold = 0.75;
MediaControlsRotateToFullscreenDelegate::
MediaControlsRotateToFullscreenDelegate(HTMLVideoElement& video)
- : EventListener(kCPPEventListenerType), video_element_(video) {}
+ : video_element_(video) {}
void MediaControlsRotateToFullscreenDelegate::Attach() {
DCHECK(video_element_->isConnected());
@@ -97,11 +97,6 @@ void MediaControlsRotateToFullscreenDelegate::Detach() {
false);
}
-bool MediaControlsRotateToFullscreenDelegate::operator==(
- const EventListener& other) const {
- return this == &other;
-}
-
void MediaControlsRotateToFullscreenDelegate::Invoke(
ExecutionContext* execution_context,
Event* event) {
@@ -292,7 +287,7 @@ MediaControlsRotateToFullscreenDelegate::ComputeScreenOrientation() const {
}
void MediaControlsRotateToFullscreenDelegate::Trace(blink::Visitor* visitor) {
- EventListener::Trace(visitor);
+ NativeEventListener::Trace(visitor);
visitor->Trace(video_element_);
visitor->Trace(visibility_observer_);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h
index 6f537c994a9..e30dcb3869e 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_ROTATE_TO_FULLSCREEN_DELEGATE_H_
#include "base/optional.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
@@ -19,7 +19,8 @@ class ElementVisibilityObserver;
// fullscreen when the device is rotated whilst watching a <video>. It is meant
// to be created by `MediaControlsImpl` when the feature applies. Once created,
// it will listen for events.
-class MediaControlsRotateToFullscreenDelegate final : public EventListener {
+class MediaControlsRotateToFullscreenDelegate final
+ : public NativeEventListener {
public:
explicit MediaControlsRotateToFullscreenDelegate(HTMLVideoElement&);
@@ -33,7 +34,7 @@ class MediaControlsRotateToFullscreenDelegate final : public EventListener {
void Detach();
// EventListener implementation.
- bool operator==(const EventListener&) const override;
+ void Invoke(ExecutionContext*, Event*) override;
void Trace(blink::Visitor*) override;
@@ -43,9 +44,6 @@ class MediaControlsRotateToFullscreenDelegate final : public EventListener {
// Represents either screen orientation or video aspect ratio.
enum class SimpleOrientation { kPortrait, kLandscape, kUnknown };
- // EventListener implementation.
- void Invoke(ExecutionContext*, Event*) override;
-
void OnStateChange();
void OnVisibilityChange(bool is_visible);
void OnDeviceOrientationAvailable(DeviceOrientationEvent*);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
index 77d754ff02c..ef84bc9f8a4 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -74,7 +74,9 @@ class MockChromeClient : public EmptyChromeClient {
class StubLocalFrameClient : public EmptyLocalFrameClient {
public:
- static StubLocalFrameClient* Create() { return new StubLocalFrameClient; }
+ static StubLocalFrameClient* Create() {
+ return MakeGarbageCollected<StubLocalFrameClient>();
+ }
std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
HTMLMediaElement&,
@@ -101,7 +103,7 @@ class MediaControlsRotateToFullscreenDelegateTest
MediaControlsRotateToFullscreenDelegate::SimpleOrientation;
void SetUp() override {
- chrome_client_ = new MockChromeClient();
+ chrome_client_ = MakeGarbageCollected<MockChromeClient>();
Page::PageClients clients;
FillWithEmptyClients(clients);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
index f247426e660..fdd7774cd1b 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -170,7 +170,6 @@ video::-webkit-media-controls-timeline {
/**
* Media Buttons
*/
-
audio::-webkit-media-controls-play-button,
video::-webkit-media-controls-play-button,
audio::-webkit-media-controls-mute-button,
@@ -191,13 +190,110 @@ video::-internal-media-controls-picture-in-picture-button {
background-size: 24px;
background-repeat: no-repeat;
background-position: center center;
+
+ /*
+ * Width should change to 48px when we have new audio
+ * control specs. Button tap target in audio and video
+ * controls should be same.
+ */
width: 32px;
- height: 32px;
+ height: 48px;
min-width: 32px;
padding: 0;
border-width: 0;
background-color: initial;
color: inherit;
+ cursor: pointer;
+
+ /* Cursor: pointer will cause a highlight when touch on it, this will disable it */
+ -webkit-tap-highlight-color: transparent;
+}
+
+/*
+ * Each hover background div's positioning rules
+ * are relative to their parent.
+ */
+video::-webkit-media-controls-play-button,
+audio::-webkit-media-controls-play-button,
+video::-webkit-media-controls-fullscreen-button,
+audio::-webkit-media-controls-fullscreen-button,
+video::-internal-media-controls-overflow-button,
+audio::-internal-media-controls-overflow-button {
+ position: relative;
+}
+
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background {
+ background-color: rgba(32, 33, 36, 0);
+ background-size: 24px;
+ background-repeat: no-repeat;
+ background-position: center center;
+ position: absolute;
+ width: 36px;
+ height: 36px;
+ border-radius: 18px;
+ left: 6px;
+ top: 6px;
+ transition: background-color .25s;
+ pointer-events: none;
+ z-index: -1;
+}
+
+/*
+ * Audio control hover circle size should be same as video controls'. Due to increase of audio control tap target
+ * will break the layout when width is 300. We'll shrink the hover circle here. Should remove this rule once the new
+ * audio control layout specs are out
+ */
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background {
+ width: 32px;
+ height: 32px;
+ left: 0;
+ top: 8px;
+ border-radius: 16px;
+}
+
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:focus::-internal-media-controls-button-hover-background {
+ background-color: rgba(32, 33, 36, 0.71);
+}
+
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-play-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-play-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-internal-media-controls-overflow-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-internal-media-controls-overflow-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:focus::-internal-media-controls-button-hover-background {
+ background-color: rgba(32, 33, 36, 0.06);
+}
+
+video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.sizing-medium input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background {
+ background-size: 32px;
+ width: 44px;
+ height: 44px;
+ border-radius: 22px;
+ left: 10px;
+ top: 10px;
}
video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-play-button" i],
@@ -354,6 +450,97 @@ video::-webkit-media-controls-overlay-play-button {
border: 0;
}
+/*
+ * Volume control container
+ */
+audio::-webkit-media-controls-volume-control-container,
+video::-webkit-media-controls-volume-control-container {
+ display: flex;
+ justify-content: flex-end;
+ position: relative;
+ height: 48px;
+
+ /* 48(Mute button) + 52(Slider) + 16(Left padding) */
+ min-width: 116px;
+ transition: min-width .3s;
+}
+
+audio::-webkit-media-controls-volume-control-container.closed,
+video::-webkit-media-controls-volume-control-container.closed {
+ min-width: 48px;
+}
+
+/*
+ * Audio control hover container size should be same as video controls'. Due to increase of audio control tap target
+ * will break the layout when width is 300. We'll shrink the hover container here. Should remove the min-width rule
+ * once the new audio control layout specs are out.
+ */
+video::-webkit-media-controls.audio-only div[pseudo="-webkit-media-controls-volume-control-container" i],
+audio::-webkit-media-controls-volume-control-container {
+ min-width: 100px;
+}
+
+video::-webkit-media-controls.audio-only div[pseudo="-webkit-media-controls-volume-control-container" i].closed,
+audio::-webkit-media-controls-volume-control-container.closed {
+ min-width: 32px;
+}
+
+audio::-webkit-media-controls-volume-control-hover-background,
+video::-webkit-media-controls-volume-control-hover-background {
+ position: absolute;
+ z-index: -1;
+ background-color: #202124;
+ opacity: .71;
+ height: 36px;
+ width: 112px;
+ border-radius: 18px;
+ top: 6px;
+ right: 4px;
+ transition: width .3s ease, opacity .25s ease;
+}
+
+/*
+ * Audio control hover size should be same as video controls'. Due to increase of audio control tap target
+ * will break the layout when width is 300. We'll shrink the hover size here. Should remove this rule once the new
+ * audio control layout specs are out. (Don't remove the opacity rule)
+ */
+video::-webkit-media-controls.audio-only div[pseudo="-webkit-media-controls-volume-control-hover-background" i],
+audio::-webkit-media-controls-volume-control-hover-background {
+ height: 32px;
+ width: 100px;
+ border-radius: 16px;
+ top: 8px;
+ right: 0;
+ opacity: .06;
+}
+
+audio::-webkit-media-controls [pseudo="-webkit-media-controls-volume-control-container"].closed [pseudo="-webkit-media-controls-volume-control-hover-background"],
+video::-webkit-media-controls [pseudo="-webkit-media-controls-volume-control-container"].closed [pseudo="-webkit-media-controls-volume-control-hover-background"] {
+ width: 36px;
+ opacity: 0;
+}
+
+video::-webkit-media-controls.sizing-medium div[pseudo="-webkit-media-controls-volume-control-container" i] {
+ height: 64px;
+ min-width: 132px;
+}
+
+video::-webkit-media-controls.sizing-medium div[pseudo="-webkit-media-controls-volume-control-container" i].closed {
+ min-width: 64px;
+}
+
+video::-webkit-media-controls.sizing-medium div[pseudo="-webkit-media-controls-volume-control-hover-background" i] {
+ height: 44px;
+ width: 124px;
+ border-radius: 22px;
+ top: 10px;
+ right: 8px;
+}
+
+video::-webkit-media-controls.sizing-medum [pseudo="-webkit-media-controls-volume-control-container"].closed [pseudo="-webkit-media-controls-volume-control-hover-background"] {
+ width: 44px;
+}
+
/**
* The overlay-play-button is disabled if the video element is loaded via
* MHTML, and a ruleset for input[type=button]:disabled in win.css has
@@ -392,7 +579,7 @@ input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-co
background-image: -webkit-image-set(url(ic_pause.svg) 1x);
}
-video::-webkit-media-controls.state-playing:not(.audio-only) input[pseudo="-webkit-media-controls-play-button" i] {
+video::-webkit-media-controls.state-playing:not(.audio-only) [pseudo="-webkit-media-controls-panel"] input[pseudo="-webkit-media-controls-play-button" i] {
background-image: -webkit-image-set(url(ic_pause_white.svg) 1x);
}
@@ -416,6 +603,11 @@ video::-webkit-media-controls-timeline {
padding-right: 16px;
margin: 0;
background: transparent;
+ cursor: pointer;
+
+ /* Cursor: pointer will cause a highlight when touch on it, this will disable it */
+ -webkit-tap-highlight-color: transparent;
+
/* This prevents layout issues in quirks mode */
box-sizing: unset !important;
}
@@ -574,6 +766,11 @@ video::-webkit-media-controls-volume-slider {
margin: 0;
padding: 22px 0; /* (48px button panel height - 4px slider height) / 2 */
background: transparent;
+ cursor: pointer;
+
+ /* Cursor: pointer will cause a highlight when touch on it, this will disable it */
+ -webkit-tap-highlight-color: transparent;
+
/* This prevents layout issues in quirks mode. */
box-sizing: unset !important;
}
@@ -637,29 +834,21 @@ video::-internal-media-controls-overflow-menu-list {
background: #FFFFFF;
box-shadow: 0 1px 9px 0 rgba(0,0,0,0.40);
border-radius: 2px;
- transition: transform .2s ease-out, opacity .2s linear;
+ transition: transform .4s ease-out, opacity .3s linear;
transform-origin: bottom right;
}
+audio::-internal-media-controls-overflow-menu-list:focus,
+video::-internal-media-controls-overflow-menu-list:focus {
+ outline: none;
+}
+
audio::-internal-media-controls-overflow-menu-list.closed,
video::-internal-media-controls-overflow-menu-list.closed {
transform: scale(0);
opacity: 0;
}
-
-audio::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > *,
-video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > * {
- opacity: 0;
-}
-
-audio::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i] > *,
-video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i] > * {
- transition: opacity .2s linear .2s;
-}
-
-
-
audio::-internal-media-controls-text-track-list-header,
video::-internal-media-controls-text-track-list-header,
audio::-internal-media-controls-text-track-list-item,
@@ -678,12 +867,16 @@ video::-internal-media-controls-overflow-menu-list-item {
line-height: 48px;
padding-left: 16px;
padding-right: 16px;
+ cursor: pointer;
+
+ /* Cursor: pointer will cause a highlight when touch on it, this will disable it */
+ -webkit-tap-highlight-color: transparent;
}
-video::-internal-media-controls-text-track-list,
-video::-internal-media-controls-overflow-menu-list {
+video::-webkit-media-controls div[pseudo="-internal-media-controls-text-track-list" i].pip-presented,
+video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].pip-presented {
max-width: 260px;
- width: 95%;
+ width: 100%;
}
video::-webkit-media-controls.sizing-small label[pseudo="-internal-media-controls-overflow-menu-list-item" i] input,
@@ -722,6 +915,55 @@ label[pseudo="-internal-media-controls-overflow-menu-list-item"] div span.subtit
color: rgba(0,0,0,0.54);
}
+/*
+ * Overflow menu list item animation
+ */
+audio::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > label,
+video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > label {
+ transform: translate(0px, 15px);
+ opacity: 0;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i],
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i] {
+ transition: transform .3s, opacity .5s;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-0,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-0 {
+ transition: opacity .5s .2s ease-in;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-1,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-1 {
+ transition-delay: .25s;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-2,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-2 {
+ transition-delay: .3s;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-3,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-3 {
+ transition-delay: .35s;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-4,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-4 {
+ transition-delay: .4s;
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-5,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-5 {
+ transition-delay: .45s
+}
+
+audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-6,
+video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-6 {
+ transition-delay: .5s
+}
+
audio::-internal-media-controls-text-track-list-header:focus,
video::-internal-media-controls-text-track-list-header:focus,
audio::-internal-media-controls-overflow-menu-list-item:focus,
@@ -1120,7 +1362,7 @@ video::-webkit-media-controls.immersive-mode input[pseudo="-internal-media-contr
}
/**
- * Test mode styles to remove animations/transitions to make layout tests
+ * Test mode styles to remove animations/transitions to make web tests
* simpler.
*/
/* Hide the loading panel. */
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc
index c844083b4e0..7b172990c20 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc
@@ -15,7 +15,7 @@ AutoCanvasDrawListener::AutoCanvasDrawListener(
// static
AutoCanvasDrawListener* AutoCanvasDrawListener::Create(
std::unique_ptr<WebCanvasCaptureHandler> handler) {
- return new AutoCanvasDrawListener(std::move(handler));
+ return MakeGarbageCollected<AutoCanvasDrawListener>(std::move(handler));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h
index 96498511130..343731a02fa 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h
@@ -20,12 +20,11 @@ class AutoCanvasDrawListener final
public:
static AutoCanvasDrawListener* Create(
std::unique_ptr<WebCanvasCaptureHandler>);
+
+ AutoCanvasDrawListener(std::unique_ptr<WebCanvasCaptureHandler>);
~AutoCanvasDrawListener() override = default;
void Trace(blink::Visitor* visitor) override {}
-
- private:
- AutoCanvasDrawListener(std::unique_ptr<WebCanvasCaptureHandler>);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.idl b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.idl
index 73eb3bb9f6a..4fe2c11c909 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.idl
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.idl
@@ -6,5 +6,5 @@
[
ImplementedAs=HTMLCanvasElementCapture
] partial interface HTMLCanvasElement {
- [RaisesException, CallWith=ScriptState] MediaStream captureStream (optional double frameRate);
+ [HighEntropy, MeasureAs=CanvasCaptureStream, RaisesException, CallWith=ScriptState] MediaStream captureStream (optional double frameRate);
};
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
index d993c18da1c..feddaea56bf 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
@@ -8,7 +8,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_media_stream.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/track/audio_track_list.h"
#include "third_party/blink/renderer/core/html/track/video_track_list.h"
@@ -23,22 +23,17 @@ namespace {
// Class to register to the events of |m_mediaElement|, acting accordingly on
// the tracks of |m_mediaStream|.
-class MediaElementEventListener final : public EventListener {
- WTF_MAKE_NONCOPYABLE(MediaElementEventListener);
-
+class MediaElementEventListener final : public NativeEventListener {
public:
MediaElementEventListener(HTMLMediaElement*, MediaStream*);
void UpdateSources(ExecutionContext*);
void Trace(blink::Visitor*) override;
- private:
// EventListener implementation.
void Invoke(ExecutionContext*, Event*) override;
- bool operator==(const EventListener& other) const override {
- return this == &other;
- }
+ private:
Member<HTMLMediaElement> media_element_;
Member<MediaStream> media_stream_;
HeapHashSet<WeakMember<MediaStreamSource>> sources_;
@@ -46,9 +41,7 @@ class MediaElementEventListener final : public EventListener {
MediaElementEventListener::MediaElementEventListener(HTMLMediaElement* element,
MediaStream* stream)
- : EventListener(kCPPEventListenerType),
- media_element_(element),
- media_stream_(stream) {
+ : NativeEventListener(), media_element_(element), media_stream_(stream) {
UpdateSources(element->GetExecutionContext());
}
@@ -169,7 +162,7 @@ MediaStream* HTMLMediaElementCapture::captureStream(
MediaStream* stream = MediaStream::Create(context, web_stream);
MediaElementEventListener* listener =
- new MediaElementEventListener(&element, stream);
+ MakeGarbageCollected<MediaElementEventListener>(&element, stream);
element.addEventListener(event_type_names::kLoadedmetadata, listener, false);
element.addEventListener(event_type_names::kEnded, listener, false);
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.idl b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.idl
index f8e28bb90fa..139c10fb935 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.idl
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.idl
@@ -7,5 +7,5 @@
[
ImplementedAs=HTMLMediaElementCapture
] partial interface HTMLMediaElement {
- [RaisesException, CallWith=ScriptState] MediaStream captureStream();
+ [RaisesException, Measure, CallWith=ScriptState] MediaStream captureStream();
};
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/README.md b/chromium/third_party/blink/renderer/modules/mediarecorder/README.md
index 46ef24f1ceb..14cdb05a26a 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/README.md
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/README.md
@@ -91,7 +91,7 @@ alternative is to use a Javascript library to reconstruct the Cues (see the
## Testing
-Media Recorder layout tests are located in [web_tests/fast/mediarecorder], and
+Media Recorder web tests are located in [web_tests/fast/mediarecorder], and
[web_tests/external/mediacapture-record], unittests in [content] and [media]
and [browsertests].
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.cc
index 6ff4daa2946..44aafb7115b 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.cc
@@ -12,14 +12,14 @@ namespace blink {
// static
BlobEvent* BlobEvent::Create(const AtomicString& type,
const BlobEventInit* initializer) {
- return new BlobEvent(type, initializer);
+ return MakeGarbageCollected<BlobEvent>(type, initializer);
}
// static
BlobEvent* BlobEvent::Create(const AtomicString& type,
Blob* blob,
double timecode) {
- return new BlobEvent(type, blob, timecode);
+ return MakeGarbageCollected<BlobEvent>(type, blob, timecode);
}
const AtomicString& BlobEvent::InterfaceName() const {
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.h b/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.h
index cf7328a2d47..97c29189c8f 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/blob_event.h
@@ -28,6 +28,9 @@ class MODULES_EXPORT BlobEvent final : public Event {
Blob* blob,
double timecode);
+ BlobEvent(const AtomicString& type, const BlobEventInit* initializer);
+ BlobEvent(const AtomicString& type, Blob* blob, double timecode);
+
Blob* data() const { return blob_.Get(); }
DOMHighResTimeStamp timecode() const { return timecode_; }
@@ -37,9 +40,6 @@ class MODULES_EXPORT BlobEvent final : public Event {
void Trace(blink::Visitor* visitor) override;
private:
- BlobEvent(const AtomicString& type, const BlobEventInit* initializer);
- BlobEvent(const AtomicString& type, Blob* blob, double timecode);
-
Member<Blob> blob_;
DOMHighResTimeStamp timecode_;
};
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
index e09ad439569..01b79e31246 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/modules/mediarecorder/blob_event.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/network/mime/content_type.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
@@ -139,48 +140,35 @@ void AllocateVideoAndAudioBitrates(ExceptionState& exception_state,
MediaRecorder* MediaRecorder::Create(ExecutionContext* context,
MediaStream* stream,
ExceptionState& exception_state) {
- MediaRecorder* recorder = MakeGarbageCollected<MediaRecorder>(
+ return MakeGarbageCollected<MediaRecorder>(
context, stream, MediaRecorderOptions::Create(), exception_state);
- recorder->PauseIfNeeded();
-
- return recorder;
}
MediaRecorder* MediaRecorder::Create(ExecutionContext* context,
MediaStream* stream,
const MediaRecorderOptions* options,
ExceptionState& exception_state) {
- MediaRecorder* recorder = MakeGarbageCollected<MediaRecorder>(
- context, stream, options, exception_state);
- recorder->PauseIfNeeded();
-
- return recorder;
+ return MakeGarbageCollected<MediaRecorder>(context, stream, options,
+ exception_state);
}
MediaRecorder::MediaRecorder(ExecutionContext* context,
MediaStream* stream,
const MediaRecorderOptions* options,
ExceptionState& exception_state)
- : PausableObject(context),
+ : ContextLifecycleObserver(context),
stream_(stream),
mime_type_(options->hasMimeType() ? options->mimeType()
: kDefaultMimeType),
stopped_(true),
audio_bits_per_second_(0),
video_bits_per_second_(0),
- state_(State::kInactive),
- // MediaStream recording should use DOM manipulation task source.
- // https://www.w3.org/TR/mediastream-recording/
- dispatch_scheduled_event_runner_(AsyncMethodRunner<MediaRecorder>::Create(
- this,
- &MediaRecorder::DispatchScheduledEvent,
- context->GetTaskRunner(TaskType::kDOMManipulation))) {
+ state_(State::kInactive) {
if (context->IsContextDestroyed()) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
"Execution context is detached.");
return;
}
-
DCHECK(stream_->getTracks().size());
recorder_handler_ = Platform::Current()->CreateMediaRecorderHandler(
context->GetTaskRunner(TaskType::kInternalMediaRealTime));
@@ -324,15 +312,7 @@ const AtomicString& MediaRecorder::InterfaceName() const {
}
ExecutionContext* MediaRecorder::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
-}
-
-void MediaRecorder::Pause() {
- dispatch_scheduled_event_runner_->Pause();
-}
-
-void MediaRecorder::Unpause() {
- dispatch_scheduled_event_runner_->Unpause();
+ return ContextLifecycleObserver::GetExecutionContext();
}
void MediaRecorder::ContextDestroyed(ExecutionContext*) {
@@ -394,8 +374,17 @@ void MediaRecorder::StopRecording() {
void MediaRecorder::ScheduleDispatchEvent(Event* event) {
scheduled_events_.push_back(event);
-
- dispatch_scheduled_event_runner_->RunAsync();
+ // Only schedule a post if we are placing the first item in the queue.
+ if (scheduled_events_.size() == 1) {
+ if (auto* context = GetExecutionContext()) {
+ // MediaStream recording should use DOM manipulation task source.
+ // https://www.w3.org/TR/mediastream-recording/
+ context->GetTaskRunner(TaskType::kDOMManipulation)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&MediaRecorder::DispatchScheduledEvent,
+ WrapPersistent(this)));
+ }
+ }
}
void MediaRecorder::DispatchScheduledEvent() {
@@ -408,10 +397,9 @@ void MediaRecorder::DispatchScheduledEvent() {
void MediaRecorder::Trace(blink::Visitor* visitor) {
visitor->Trace(stream_);
- visitor->Trace(dispatch_scheduled_event_runner_);
visitor->Trace(scheduled_events_);
EventTargetWithInlineData::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
index aaf3ab16c0a..1ee3d182e2d 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
@@ -10,12 +10,10 @@
#include "third_party/blink/public/platform/web_media_recorder_handler_client.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/mediarecorder/media_recorder_options.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream.h"
#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
namespace blink {
@@ -27,7 +25,7 @@ class MODULES_EXPORT MediaRecorder final
: public EventTargetWithInlineData,
public WebMediaRecorderHandlerClient,
public ActiveScriptWrappable<MediaRecorder>,
- public PausableObject {
+ public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(MediaRecorder);
DEFINE_WRAPPERTYPEINFO();
@@ -74,9 +72,7 @@ class MODULES_EXPORT MediaRecorder final
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
- // PausableObject
- void Pause() override;
- void Unpause() override;
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext* context) override;
// ScriptWrappable
@@ -110,7 +106,6 @@ class MODULES_EXPORT MediaRecorder final
std::unique_ptr<WebMediaRecorderHandler> recorder_handler_;
- Member<AsyncMethodRunner<MediaRecorder>> dispatch_scheduled_event_runner_;
HeapVector<Member<Event>> scheduled_events_;
};
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/DEPS b/chromium/third_party/blink/renderer/modules/mediasession/DEPS
index 481f934f672..4704ab16dae 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/DEPS
+++ b/chromium/third_party/blink/renderer/modules/mediasession/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+mojo/public/cpp/bindings/binding.h",
+ "+services/media_session/public/mojom",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/event_target_modules.h",
"+third_party/blink/renderer/modules/modules_export.h",
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc
index 0db31ca016a..501686fa4c2 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc
@@ -59,16 +59,16 @@ bool CheckMediaImageSrcSanity(const KURL& src, ExecutionContext* context) {
// Sanitize MediaImage and do mojo serialization. Returns null when
// |image.src()| is bad.
-blink::mojom::blink::MediaImagePtr SanitizeMediaImageAndConvertToMojo(
+media_session::mojom::blink::MediaImagePtr SanitizeMediaImageAndConvertToMojo(
const MediaImage* image,
ExecutionContext* context) {
- blink::mojom::blink::MediaImagePtr mojo_image;
+ media_session::mojom::blink::MediaImagePtr mojo_image;
KURL url = KURL(image->src());
if (!CheckMediaImageSrcSanity(url, context))
return mojo_image;
- mojo_image = blink::mojom::blink::MediaImage::New();
+ mojo_image = media_session::mojom::blink::MediaImage::New();
mojo_image->src = url;
mojo_image->type = image->type().Left(kMaxImageTypeLength);
for (const auto& web_size :
@@ -87,21 +87,24 @@ blink::mojom::blink::MediaImagePtr SanitizeMediaImageAndConvertToMojo(
} // anonymous namespace
-blink::mojom::blink::MediaMetadataPtr
+media_session::mojom::blink::MediaMetadataPtr
MediaMetadataSanitizer::SanitizeAndConvertToMojo(const MediaMetadata* metadata,
ExecutionContext* context) {
- blink::mojom::blink::MediaMetadataPtr mojo_metadata;
+ media_session::mojom::blink::MediaMetadataPtr mojo_metadata;
if (!metadata)
return mojo_metadata;
- mojo_metadata = blink::mojom::blink::MediaMetadata::New();
+ mojo_metadata = media_session::mojom::blink::MediaMetadata::New();
mojo_metadata->title = metadata->title().Left(kMaxStringLength);
mojo_metadata->artist = metadata->artist().Left(kMaxStringLength);
mojo_metadata->album = metadata->album().Left(kMaxStringLength);
+ // |source_title_| is populated by content::MediaSessionImpl.
+ mojo_metadata->source_title = g_empty_string16_bit;
+
for (const MediaImage* image : metadata->artwork()) {
- blink::mojom::blink::MediaImagePtr mojo_image =
+ media_session::mojom::blink::MediaImagePtr mojo_image =
SanitizeMediaImageAndConvertToMojo(image, context);
if (!mojo_image.is_null())
mojo_metadata->artwork.push_back(std::move(mojo_image));
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h
index 3c6eef6a8ff..1c78dabca7c 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASESSION_MEDIA_METADATA_SANITIZER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASESSION_MEDIA_METADATA_SANITIZER_H_
-#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom-blink.h"
+#include "services/media_session/public/mojom/media_session.mojom-blink.h"
namespace blink {
@@ -16,7 +16,7 @@ class MediaMetadataSanitizer {
public:
// Produce the sanitized metadata, which will later be sent to the
// MediaSession mojo service.
- static blink::mojom::blink::MediaMetadataPtr SanitizeAndConvertToMojo(
+ static media_session::mojom::blink::MediaMetadataPtr SanitizeAndConvertToMojo(
const MediaMetadata*,
ExecutionContext*);
};
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc
index 80ded6b5ef6..1394c64857a 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc
@@ -13,8 +13,11 @@
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/modules/mediasession/media_metadata.h"
#include "third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
@@ -33,6 +36,7 @@ const AtomicString& MojomActionToActionName(MediaSessionAction action) {
("seekbackward"));
DEFINE_STATIC_LOCAL(const AtomicString, seek_forward_action_name,
("seekforward"));
+ DEFINE_STATIC_LOCAL(const AtomicString, skip_ad_action_name, ("skipad"));
switch (action) {
case MediaSessionAction::kPlay:
@@ -47,6 +51,8 @@ const AtomicString& MojomActionToActionName(MediaSessionAction action) {
return seek_backward_action_name;
case MediaSessionAction::kSeekForward:
return seek_forward_action_name;
+ case MediaSessionAction::kSkipAd:
+ return skip_ad_action_name;
default:
NOTREACHED();
}
@@ -67,6 +73,8 @@ base::Optional<MediaSessionAction> ActionNameToMojomAction(
return MediaSessionAction::kSeekBackward;
if ("seekforward" == action_name)
return MediaSessionAction::kSeekForward;
+ if ("skipad" == action_name)
+ return MediaSessionAction::kSkipAd;
NOTREACHED();
return base::nullopt;
@@ -151,7 +159,19 @@ void MediaSession::OnMetadataChanged() {
}
void MediaSession::setActionHandler(const String& action,
- V8MediaSessionActionHandler* handler) {
+ V8MediaSessionActionHandler* handler,
+ ExceptionState& exception_state) {
+ if (action == "skipad") {
+ if (!origin_trials::SkipAdEnabled(GetExecutionContext())) {
+ exception_state.ThrowTypeError(
+ "The provided value 'skipad' is not a valid enum "
+ "value of type MediaSessionAction.");
+ return;
+ }
+
+ UseCounter::Count(GetExecutionContext(), WebFeature::kMediaSessionSkipAd);
+ }
+
if (handler) {
auto add_result = action_handlers_.Set(action, handler);
@@ -199,13 +219,17 @@ mojom::blink::MediaSessionService* MediaSession::GetService() {
if (!frame)
return nullptr;
- frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ frame->GetInterfaceProvider().GetInterface(
+ mojo::MakeRequest(&service_, task_runner));
if (service_.get()) {
// Record the eTLD+1 of the frame using the API.
Platform::Current()->RecordRapporURL("Media.Session.APIUsage.Origin",
document->Url());
blink::mojom::blink::MediaSessionClientPtr client;
- client_binding_.Bind(mojo::MakeRequest(&client));
+ client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
service_->SetClient(std::move(client));
}
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session.h b/chromium/third_party/blink/renderer/modules/mediasession/media_session.h
index 0f48b8095d7..2e267ec5bda 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_session.h
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session.h
@@ -18,6 +18,7 @@
namespace blink {
class ExecutionContext;
+class ExceptionState;
class MediaMetadata;
class V8MediaSessionActionHandler;
@@ -42,7 +43,9 @@ class MODULES_EXPORT MediaSession final
void setMetadata(MediaMetadata*);
MediaMetadata* metadata() const;
- void setActionHandler(const String& action, V8MediaSessionActionHandler*);
+ void setActionHandler(const String& action,
+ V8MediaSessionActionHandler*,
+ ExceptionState&);
// Called by the MediaMetadata owned by |this| when it has updates. Also used
// internally when a new MediaMetadata object is set.
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session.idl b/chromium/third_party/blink/renderer/modules/mediasession/media_session.idl
index e47398d2665..ac749c036fe 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_session.idl
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session.idl
@@ -18,7 +18,8 @@ enum MediaSessionAction {
"previoustrack",
"nexttrack",
"seekbackward",
- "seekforward"
+ "seekforward",
+ "skipad",
};
callback MediaSessionActionHandler = void ();
@@ -29,6 +30,6 @@ callback MediaSessionActionHandler = void ();
[Measure] attribute MediaMetadata? metadata;
[Measure] attribute MediaSessionPlaybackState playbackState;
- [Measure] void setActionHandler(MediaSessionAction action,
+ [Measure, RaisesException] void setActionHandler(MediaSessionAction action,
MediaSessionActionHandler? handler);
};
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
index 3224fbd5f7c..0262fe6209f 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -128,7 +128,6 @@ MediaSource::MediaSource(ExecutionContext* context)
MediaSource::~MediaSource() {
BLINK_MSLOG << __func__ << " this=" << this;
- DCHECK(IsClosed());
}
void MediaSource::LogAndThrowDOMException(ExceptionState& exception_state,
@@ -432,6 +431,9 @@ TimeRanges* MediaSource::Buffered() const {
}
TimeRanges* MediaSource::Seekable() const {
+ DCHECK(attached_element_)
+ << "Seekable should only be used when attached to HTMLMediaElement";
+
// Implements MediaSource algorithm for HTMLMediaElement.seekable.
// http://w3c.github.io/media-source/#htmlmediaelement-extensions
@@ -442,7 +444,7 @@ TimeRanges* MediaSource::Seekable() const {
// If duration equals positive Infinity:
if (source_duration == std::numeric_limits<double>::infinity()) {
- TimeRanges* buffered = attached_element_->buffered();
+ TimeRanges* buffered = Buffered();
// 1. If live seekable range is not empty:
if (live_seekable_range_->length() != 0) {
@@ -503,6 +505,8 @@ void MediaSource::OnTrackChanged(TrackBase* track) {
void MediaSource::setDuration(double duration,
ExceptionState& exception_state) {
+ BLINK_MSLOG << __func__ << " this=" << this << " : duration=" << duration;
+
// 2.1 https://www.w3.org/TR/media-source/#widl-MediaSource-duration
// 1. If the value being set is negative or NaN then throw a TypeError
// exception and abort these steps.
@@ -624,6 +628,8 @@ void MediaSource::endOfStream(const AtomicString& error,
DEFINE_STATIC_LOCAL(const AtomicString, network, ("network"));
DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode"));
+ BLINK_MSLOG << __func__ << " this=" << this << " : error=" << error;
+
// https://www.w3.org/TR/media-source/#dom-mediasource-endofstream
// 1. If the readyState attribute is not in the "open" state then throw an
// InvalidStateError exception and abort these steps.
@@ -649,6 +655,9 @@ void MediaSource::endOfStream(ExceptionState& exception_state) {
void MediaSource::setLiveSeekableRange(double start,
double end,
ExceptionState& exception_state) {
+ BLINK_MSLOG << __func__ << " this=" << this << " : start=" << start
+ << ", end=" << end;
+
// http://w3c.github.io/media-source/#widl-MediaSource-setLiveSeekableRange-void-double-start-double-end
// 1. If the readyState attribute is not "open" then throw an
// InvalidStateError exception and abort these steps.
@@ -678,6 +687,8 @@ void MediaSource::setLiveSeekableRange(double start,
}
void MediaSource::clearLiveSeekableRange(ExceptionState& exception_state) {
+ BLINK_MSLOG << __func__ << " this=" << this;
+
// http://w3c.github.io/media-source/#widl-MediaSource-clearLiveSeekableRange-void
// 1. If the readyState attribute is not "open" then throw an
// InvalidStateError exception and abort these steps.
@@ -795,8 +806,15 @@ void MediaSource::OpenIfInEndedState() {
}
bool MediaSource::HasPendingActivity() const {
- return attached_element_ || web_media_source_ ||
- async_event_queue_->HasPendingEvents() ||
+ // Note that an unrevoked MediaSource objectUrl for an otherwise inactive,
+ // unreferenced HTMLME with MSE still attached will prevent GC of the whole
+ // group of objects. This is unfortunate, because it's conceivable that the
+ // app may actually still have a "reference" to the underlying MediaSource if
+ // it has the objectUrl in a string somewhere, for example. This is yet
+ // further motivation for apps to properly revokeObjectUrl and for the MSE
+ // spec, implementations and API users to transition to using HTMLME srcObject
+ // for MSE attachment instead of objectUrl.
+ return async_event_queue_->HasPendingEvents() ||
added_to_registry_counter_ > 0;
}
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
index 5cb42cf9b8b..bee9642de32 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
@@ -43,6 +43,7 @@
#include "third_party/blink/renderer/modules/mediasource/source_buffer.h"
#include "third_party/blink/renderer/modules/mediasource/source_buffer_list.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
namespace blink {
@@ -147,10 +148,17 @@ class MediaSource final : public EventTargetWithInlineData,
std::unique_ptr<WebMediaSource> web_media_source_;
AtomicString ready_state_;
Member<EventQueue> async_event_queue_;
- Member<HTMLMediaElement> attached_element_;
- Member<SourceBufferList> source_buffers_;
- Member<SourceBufferList> active_source_buffers_;
+ // Here, using TraceWrapperMember, instead of Member, to keep
+ // |attached_element_|, |source_buffers_|, |active_source_buffers_|, and their
+ // wrappers from being collected if we are alive or traceable from a GC root.
+ // Activity by this MediaSource or on references to objects returned by
+ // exercising this MediaSource (such as an app manipulating a SourceBuffer
+ // retrieved via activeSourceBuffers()) may cause events to be dispatched by
+ // these other objects.
+ TraceWrapperMember<HTMLMediaElement> attached_element_;
+ TraceWrapperMember<SourceBufferList> source_buffers_;
+ TraceWrapperMember<SourceBufferList> active_source_buffers_;
Member<TimeRanges> live_seekable_range_;
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
index c265d3370ba..3dadf5628df 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -56,6 +56,7 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/network/mime/content_type.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#ifndef BLINK_SBLOG
@@ -108,16 +109,14 @@ SourceBuffer* SourceBuffer::Create(
std::unique_ptr<WebSourceBuffer> web_source_buffer,
MediaSource* source,
EventQueue* async_event_queue) {
- SourceBuffer* source_buffer = MakeGarbageCollected<SourceBuffer>(
- std::move(web_source_buffer), source, async_event_queue);
- source_buffer->PauseIfNeeded();
- return source_buffer;
+ return MakeGarbageCollected<SourceBuffer>(std::move(web_source_buffer),
+ source, async_event_queue);
}
SourceBuffer::SourceBuffer(std::unique_ptr<WebSourceBuffer> web_source_buffer,
MediaSource* source,
EventQueue* async_event_queue)
- : PausableObject(source->GetExecutionContext()),
+ : ContextLifecycleObserver(source->GetExecutionContext()),
web_source_buffer_(std::move(web_source_buffer)),
source_(source),
track_defaults_(TrackDefaultList::Create()),
@@ -129,16 +128,8 @@ SourceBuffer::SourceBuffer(std::unique_ptr<WebSourceBuffer> web_source_buffer,
append_window_end_(std::numeric_limits<double>::infinity()),
first_initialization_segment_received_(false),
pending_append_data_offset_(0),
- append_buffer_async_part_runner_(AsyncMethodRunner<SourceBuffer>::Create(
- this,
- &SourceBuffer::AppendBufferAsyncPart,
- GetExecutionContext()->GetTaskRunner(TaskType::kMediaElementEvent))),
pending_remove_start_(-1),
- pending_remove_end_(-1),
- remove_async_part_runner_(AsyncMethodRunner<SourceBuffer>::Create(
- this,
- &SourceBuffer::RemoveAsyncPart,
- GetExecutionContext()->GetTaskRunner(TaskType::kMediaElementEvent))) {
+ pending_remove_end_(-1) {
BLINK_SBLOG << __func__ << " this=" << this;
DCHECK(web_source_buffer_);
@@ -171,7 +162,7 @@ const AtomicString& SourceBuffer::SequenceKeyword() {
void SourceBuffer::setMode(const AtomicString& new_mode,
ExceptionState& exception_state) {
- BLINK_SBLOG << __func__ << " this=" << this << " newMode=" << new_mode;
+ BLINK_SBLOG << __func__ << " this=" << this << " new_mode=" << new_mode;
// Section 3.1 On setting mode attribute steps.
// https://www.w3.org/TR/media-source/#dom-sourcebuffer-mode
// 1. If this object has been removed from the sourceBuffers attribute of the
@@ -514,7 +505,10 @@ void SourceBuffer::remove(double start,
// asynchronously.
pending_remove_start_ = start;
pending_remove_end_ = end;
- remove_async_part_runner_->RunAsync();
+ remove_async_task_handle_ = PostCancellableTask(
+ *GetExecutionContext()->GetTaskRunner(TaskType::kMediaElementEvent),
+ FROM_HERE,
+ WTF::Bind(&SourceBuffer::RemoveAsyncPart, WrapPersistent(this)));
}
void SourceBuffer::changeType(const String& type,
@@ -604,7 +598,7 @@ void SourceBuffer::setTrackDefaults(TrackDefaultList* track_defaults,
void SourceBuffer::CancelRemove() {
DCHECK(updating_);
DCHECK_NE(pending_remove_start_, -1);
- remove_async_part_runner_->Stop();
+ remove_async_task_handle_.Cancel();
pending_remove_start_ = -1;
pending_remove_end_ = -1;
updating_ = false;
@@ -630,7 +624,7 @@ void SourceBuffer::AbortIfUpdating() {
// 4.1. Abort the buffer append and stream append loop algorithms if they are
// running.
- append_buffer_async_part_runner_->Stop();
+ append_buffer_async_task_handle_.Cancel();
pending_append_data_.clear();
pending_append_data_offset_ = 0;
@@ -1152,26 +1146,19 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
}
bool SourceBuffer::HasPendingActivity() const {
- return source_;
-}
-
-void SourceBuffer::Pause() {
- append_buffer_async_part_runner_->Pause();
- remove_async_part_runner_->Pause();
-}
-
-void SourceBuffer::Unpause() {
- append_buffer_async_part_runner_->Unpause();
- remove_async_part_runner_->Unpause();
+ return updating_ || append_buffer_async_task_handle_.IsActive() ||
+ remove_async_task_handle_.IsActive() ||
+ (async_event_queue_ && async_event_queue_->HasPendingEvents());
}
void SourceBuffer::ContextDestroyed(ExecutionContext*) {
- append_buffer_async_part_runner_->Stop();
- remove_async_part_runner_->Stop();
+ append_buffer_async_task_handle_.Cancel();
+ remove_async_task_handle_.Cancel();
+ updating_ = false;
}
ExecutionContext* SourceBuffer::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
+ return ContextLifecycleObserver::GetExecutionContext();
}
const AtomicString& SourceBuffer::InterfaceName() const {
@@ -1297,7 +1284,10 @@ void SourceBuffer::AppendBufferInternal(double media_time,
ScheduleEvent(event_type_names::kUpdatestart);
// 5. Asynchronously run the buffer append algorithm.
- append_buffer_async_part_runner_->RunAsync();
+ append_buffer_async_task_handle_ = PostCancellableTask(
+ *GetExecutionContext()->GetTaskRunner(TaskType::kMediaElementEvent),
+ FROM_HERE,
+ WTF::Bind(&SourceBuffer::AppendBufferAsyncPart, WrapPersistent(this)));
TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this,
"initialDelay");
@@ -1346,7 +1336,11 @@ void SourceBuffer::AppendBufferAsyncPart() {
pending_append_data_offset_ += append_size;
if (pending_append_data_offset_ < pending_append_data_.size()) {
- append_buffer_async_part_runner_->RunAsync();
+ append_buffer_async_task_handle_ = PostCancellableTask(
+ *GetExecutionContext()->GetTaskRunner(TaskType::kMediaElementEvent),
+ FROM_HERE,
+ WTF::Bind(&SourceBuffer::AppendBufferAsyncPart,
+ WrapPersistent(this)));
TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this,
"nextPieceDelay");
return;
@@ -1427,12 +1421,10 @@ void SourceBuffer::Trace(blink::Visitor* visitor) {
visitor->Trace(source_);
visitor->Trace(track_defaults_);
visitor->Trace(async_event_queue_);
- visitor->Trace(append_buffer_async_part_runner_);
- visitor->Trace(remove_async_part_runner_);
visitor->Trace(audio_tracks_);
visitor->Trace(video_tracks_);
EventTargetWithInlineData::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
index dcf697403ee..56117420814 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
@@ -34,11 +34,12 @@
#include <memory>
#include "third_party/blink/public/platform/web_source_buffer_client.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/mediasource/track_default_list.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -56,7 +57,7 @@ class WebSourceBuffer;
class SourceBuffer final : public EventTargetWithInlineData,
public ActiveScriptWrappable<SourceBuffer>,
- public PausableObject,
+ public ContextLifecycleObserver,
public WebSourceBufferClient {
USING_GARBAGE_COLLECTED_MIXIN(SourceBuffer);
DEFINE_WRAPPERTYPEINFO();
@@ -105,9 +106,7 @@ class SourceBuffer final : public EventTargetWithInlineData,
// ScriptWrappable
bool HasPendingActivity() const final;
- // PausableObject
- void Pause() override;
- void Unpause() override;
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// EventTarget interface
@@ -157,26 +156,34 @@ class SourceBuffer final : public EventTargetWithInlineData,
const AtomicString& byte_stream_track_id) const;
std::unique_ptr<WebSourceBuffer> web_source_buffer_;
- Member<MediaSource> source_;
- Member<TrackDefaultList> track_defaults_;
+
+ // If any portion of an attached HTMLMediaElement (HTMLME) and the MediaSource
+ // Extensions (MSE) API is alive (having pending activity or traceable from a
+ // GC root), the whole group is not GC'ed. Here, using TraceWrapperMember,
+ // instead of Member, because |source_|'s and |track_defaults_|'s wrappers
+ // need to remain alive at least to successfully dispatch any events enqueued
+ // by the behavior of the HTMLME+MSE API. It makes those wrappers remain alive
+ // as long as this SourceBuffer's wrapper is alive.
+ TraceWrapperMember<MediaSource> source_;
+ TraceWrapperMember<TrackDefaultList> track_defaults_;
Member<EventQueue> async_event_queue_;
AtomicString mode_;
bool updating_;
double timestamp_offset_;
- Member<AudioTrackList> audio_tracks_;
- Member<VideoTrackList> video_tracks_;
+ TraceWrapperMember<AudioTrackList> audio_tracks_;
+ TraceWrapperMember<VideoTrackList> video_tracks_;
double append_window_start_;
double append_window_end_;
bool first_initialization_segment_received_;
Vector<unsigned char> pending_append_data_;
wtf_size_t pending_append_data_offset_;
- Member<AsyncMethodRunner<SourceBuffer>> append_buffer_async_part_runner_;
+ TaskHandle append_buffer_async_task_handle_;
double pending_remove_start_;
double pending_remove_end_;
- Member<AsyncMethodRunner<SourceBuffer>> remove_async_part_runner_;
+ TaskHandle remove_async_task_handle_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_list.h b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_list.h
index 658138513c1..d011c0564dc 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_list.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_list.h
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
@@ -85,7 +86,23 @@ class SourceBufferList final : public EventTargetWithInlineData,
Member<EventQueue> async_event_queue_;
- HeapVector<Member<SourceBuffer>> list_;
+ // If any portion of an attached HTMLMediaElement (HTMLME) and the MediaSource
+ // Extensions (MSE) API is alive (having pending activity or traceable from a
+ // GC root), the whole group is not GC'ed. Here, using TraceWrapperMember,
+ // instead of Member, because the |list_|'s SourceBuffers' wrappers need to
+ // remain alive at least to successfully dispatch any events enqueued by
+ // behavior of the HTMLME+MSE API. TraceWrapperMember usage here keeps the
+ // SourceBuffers in |list_|, and their wrappers, from being collected if we
+ // are alive or traceable from a GC root.
+ // For instance, suppose the only reference to the group of HTMLME+MSE API
+ // objects is one held by the app to the wrapper of this SourceBufferList.
+ // The app could do any of a number of actions on any of the SourceBuffers in
+ // |list_|, such as appending more media, causing events to be enqueued for
+ // later dispatch on at least those SourceBuffers. None of the app's event
+ // listeners on objects in HTMLME+MSE are counted as references, but events
+ // pending for dispatch to them must keep the HTML+MSE group of objects alive
+ // through at least their dispatch.
+ HeapVector<TraceWrapperMember<SourceBuffer>> list_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
index 00f60af5280..418f1981224 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -41,8 +41,4 @@ blink_modules_sources("mediastream") {
"user_media_request.cc",
"user_media_request.h",
]
-
- deps = [
- "//third_party/blink/public:media_devices_mojo_bindings_blink",
- ]
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/DEPS b/chromium/third_party/blink/renderer/modules/mediastream/DEPS
index 7ea86f33883..d7193fff93c 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/DEPS
+++ b/chromium/third_party/blink/renderer/modules/mediastream/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+media/base",
"+mojo/public/cpp/bindings/binding.h",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/event_modules.h",
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc b/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc
index e141f8a2a2c..65752f51e68 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc
@@ -14,7 +14,8 @@ ApplyConstraintsRequest* ApplyConstraintsRequest::Create(
const WebMediaStreamTrack& track,
const WebMediaConstraints& constraints,
ScriptPromiseResolver* resolver) {
- return new ApplyConstraintsRequest(track, constraints, resolver);
+ return MakeGarbageCollected<ApplyConstraintsRequest>(track, constraints,
+ resolver);
}
ApplyConstraintsRequest* ApplyConstraintsRequest::CreateForTesting(
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h b/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h
index 382ea67c8f8..61b4d961d0c 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h
@@ -24,6 +24,10 @@ class MODULES_EXPORT ApplyConstraintsRequest final
static ApplyConstraintsRequest* CreateForTesting(const WebMediaStreamTrack&,
const WebMediaConstraints&);
+ ApplyConstraintsRequest(const WebMediaStreamTrack&,
+ const WebMediaConstraints&,
+ ScriptPromiseResolver*);
+
WebMediaStreamTrack Track() const;
WebMediaConstraints Constraints() const;
@@ -33,10 +37,6 @@ class MODULES_EXPORT ApplyConstraintsRequest final
virtual void Trace(blink::Visitor*);
private:
- ApplyConstraintsRequest(const WebMediaStreamTrack&,
- const WebMediaConstraints&,
- ScriptPromiseResolver*);
-
WebMediaStreamTrack track_;
WebMediaConstraints constraints_;
Member<ScriptPromiseResolver> resolver_;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/input_device_info.cc b/chromium/third_party/blink/renderer/modules/mediastream/input_device_info.cc
index 7a3fa46572d..a746278a953 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/input_device_info.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/input_device_info.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "media/base/sample_format.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/blink/renderer/modules/mediastream/media_track_capabilities.h"
@@ -89,6 +90,13 @@ MediaTrackCapabilities* InputDeviceInfo::getCapabilities() const {
capabilities->setEchoCancellation({true, false});
capabilities->setAutoGainControl({true, false});
capabilities->setNoiseSuppression({true, false});
+ // Sample size.
+ LongRange* sample_size = LongRange::Create();
+ sample_size->setMin(
+ media::SampleFormatToBitsPerChannel(media::kSampleFormatS16));
+ sample_size->setMax(
+ media::SampleFormatToBitsPerChannel(media::kSampleFormatS16));
+ capabilities->setSampleSize(sample_size);
}
if (DeviceType() == MediaDeviceType::MEDIA_VIDEO_INPUT) {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.h b/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.h
index 737a37b4846..d91fa4524f6 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.h
@@ -26,7 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_DEVICE_INFO_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_DEVICE_INFO_H_
-#include "third_party/blink/public/platform/modules/mediastream/media_devices.mojom-blink.h"
+#include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.idl
index 3ff1e1d84bb..ffd2619f6ab 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_device_info.idl
@@ -36,5 +36,5 @@ interface MediaDeviceInfo {
readonly attribute MediaDeviceKind kind;
readonly attribute DOMString label;
readonly attribute DOMString groupId;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 7d099e57634..223370b5618 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -33,9 +33,11 @@ namespace {
class PromiseResolverCallbacks final : public UserMediaRequest::Callbacks {
public:
static PromiseResolverCallbacks* Create(ScriptPromiseResolver* resolver) {
- return new PromiseResolverCallbacks(resolver);
+ return MakeGarbageCollected<PromiseResolverCallbacks>(resolver);
}
+ explicit PromiseResolverCallbacks(ScriptPromiseResolver* resolver)
+ : resolver_(resolver) {}
~PromiseResolverCallbacks() override = default;
void OnSuccess(ScriptWrappable* callback_this_value,
@@ -53,30 +55,17 @@ class PromiseResolverCallbacks final : public UserMediaRequest::Callbacks {
}
private:
- explicit PromiseResolverCallbacks(ScriptPromiseResolver* resolver)
- : resolver_(resolver) {}
-
Member<ScriptPromiseResolver> resolver_;
};
} // namespace
MediaDevices* MediaDevices::Create(ExecutionContext* context) {
- MediaDevices* media_devices = MakeGarbageCollected<MediaDevices>(context);
- media_devices->PauseIfNeeded();
- return media_devices;
+ return MakeGarbageCollected<MediaDevices>(context);
}
MediaDevices::MediaDevices(ExecutionContext* context)
- : PausableObject(context),
- stopped_(false),
- dispatch_scheduled_event_runner_(
- context ? AsyncMethodRunner<MediaDevices>::Create(
- this,
- &MediaDevices::DispatchScheduledEvent,
- context->GetTaskRunner(TaskType::kMediaElementEvent))
- : nullptr),
- binding_(this) {}
+ : ContextLifecycleObserver(context), stopped_(false), binding_(this) {}
MediaDevices::~MediaDevices() = default;
@@ -172,7 +161,7 @@ const AtomicString& MediaDevices::InterfaceName() const {
}
ExecutionContext* MediaDevices::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
+ return ContextLifecycleObserver::GetExecutionContext();
}
void MediaDevices::RemoveAllEventListeners() {
@@ -213,16 +202,6 @@ void MediaDevices::ContextDestroyed(ExecutionContext*) {
dispatcher_host_.reset();
}
-void MediaDevices::Pause() {
- DCHECK(dispatch_scheduled_event_runner_);
- dispatch_scheduled_event_runner_->Pause();
-}
-
-void MediaDevices::Unpause() {
- DCHECK(dispatch_scheduled_event_runner_);
- dispatch_scheduled_event_runner_->Unpause();
-}
-
void MediaDevices::OnDevicesChanged(
MediaDeviceType type,
Vector<mojom::blink::MediaDeviceInfoPtr> device_infos) {
@@ -238,11 +217,19 @@ void MediaDevices::OnDevicesChanged(
void MediaDevices::ScheduleDispatchEvent(Event* event) {
scheduled_events_.push_back(event);
- DCHECK(dispatch_scheduled_event_runner_);
- dispatch_scheduled_event_runner_->RunAsync();
+ if (dispatch_scheduled_events_task_handle_.IsActive())
+ return;
+
+ auto* context = GetExecutionContext();
+ DCHECK(context);
+ dispatch_scheduled_events_task_handle_ = PostCancellableTask(
+ *context->GetTaskRunner(TaskType::kMediaElementEvent), FROM_HERE,
+ WTF::Bind(&MediaDevices::DispatchScheduledEvents, WrapPersistent(this)));
}
-void MediaDevices::DispatchScheduledEvent() {
+void MediaDevices::DispatchScheduledEvents() {
+ if (stopped_)
+ return;
HeapVector<Member<Event>> events;
events.swap(scheduled_events_);
@@ -368,11 +355,10 @@ void MediaDevices::SetDispatcherHostForTesting(
}
void MediaDevices::Trace(blink::Visitor* visitor) {
- visitor->Trace(dispatch_scheduled_event_runner_);
visitor->Trace(scheduled_events_);
visitor->Trace(requests_);
EventTargetWithInlineData::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.h b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.h
index 563cf4a174e..59dfeaea594 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.h
@@ -7,16 +7,16 @@
#include "base/callback.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/platform/modules/mediastream/media_devices.mojom-blink.h"
+#include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/mediastream/media_device_info.h"
#include "third_party/blink/renderer/modules/mediastream/user_media_request.h"
#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
namespace blink {
@@ -30,7 +30,7 @@ class ScriptState;
class MODULES_EXPORT MediaDevices final
: public EventTargetWithInlineData,
public ActiveScriptWrappable<MediaDevices>,
- public PausableObject,
+ public ContextLifecycleObserver,
public mojom::blink::MediaDevicesListener {
USING_GARBAGE_COLLECTED_MIXIN(MediaDevices);
DEFINE_WRAPPERTYPEINFO();
@@ -64,10 +64,8 @@ class MODULES_EXPORT MediaDevices final
// ScriptWrappable
bool HasPendingActivity() const override;
- // PausableObject overrides.
+ // ContextLifecycleObserver overrides.
void ContextDestroyed(ExecutionContext*) override;
- void Pause() override;
- void Unpause() override;
// mojom::blink::MediaDevicesListener implementation.
void OnDevicesChanged(MediaDeviceType,
@@ -106,7 +104,7 @@ class MODULES_EXPORT MediaDevices final
private:
FRIEND_TEST_ALL_PREFIXES(MediaDevicesTest, ObserveDeviceChangeEvent);
void ScheduleDispatchEvent(Event*);
- void DispatchScheduledEvent();
+ void DispatchScheduledEvents();
void StartObserving();
void StopObserving();
void Dispose();
@@ -120,7 +118,7 @@ class MODULES_EXPORT MediaDevices final
bool stopped_;
// Async runner may be null when there is no valid execution context.
// No async work may be posted in this scenario.
- Member<AsyncMethodRunner<MediaDevices>> dispatch_scheduled_event_runner_;
+ TaskHandle dispatch_scheduled_events_task_handle_;
HeapVector<Member<Event>> scheduled_events_;
mojom::blink::MediaDevicesDispatcherHostPtr dispatcher_host_;
mojo::Binding<mojom::blink::MediaDevicesListener> binding_;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.idl
index 8e803c593b4..71fbfd5112f 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.idl
@@ -11,7 +11,7 @@
] interface MediaDevices : EventTarget {
[RuntimeEnabled=OnDeviceChange] attribute EventHandler ondevicechange;
[
- CallWith = ScriptState, MeasureAs = MediaDevicesEnumerateDevices
+ CallWith = ScriptState, HighEntropy, MeasureAs = MediaDevicesEnumerateDevices
] Promise<sequence<MediaDeviceInfo>>
enumerateDevices();
MediaTrackSupportedConstraints getSupportedConstraints();
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
index 7406b72ea54..9cc99c54838 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
@@ -87,6 +87,8 @@ bool ConstraintSetHasNonImageCapture(
constraint_set->hasChannelCount() || constraint_set->hasDepthFar() ||
constraint_set->hasDepthNear() || constraint_set->hasDeviceId() ||
constraint_set->hasEchoCancellation() ||
+ constraint_set->hasNoiseSuppression() ||
+ constraint_set->hasAutoGainControl() ||
constraint_set->hasFacingMode() || constraint_set->hasResizeMode() ||
constraint_set->hasFocalLengthX() ||
constraint_set->hasFocalLengthY() || constraint_set->hasFrameRate() ||
@@ -348,6 +350,13 @@ MediaTrackCapabilities* MediaStreamTrack::getCapabilities() const {
for (String value : platform_capabilities.echo_cancellation_type)
echo_cancellation_type.push_back(value);
capabilities->setEchoCancellationType(echo_cancellation_type);
+ // Sample size.
+ if (platform_capabilities.sample_size.size() == 2) {
+ LongRange* sample_size = LongRange::Create();
+ sample_size->setMin(platform_capabilities.sample_size[0]);
+ sample_size->setMax(platform_capabilities.sample_size[1]);
+ capabilities->setSampleSize(sample_size);
+ }
}
if (component_->Source()->GetType() == MediaStreamSource::kTypeVideo) {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl
index 8fa90be86d3..deb815f57ab 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl
@@ -14,6 +14,7 @@ dictionary MediaTrackCapabilities {
[OriginTrialEnabled=ExperimentalHardwareEchoCancellation] sequence<DOMString> echoCancellationType;
sequence<boolean> autoGainControl;
sequence<boolean> noiseSuppression;
+ LongRange sampleSize;
DOMString deviceId;
DOMString groupId;
// W3C Image Capture API
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index 8a2ca93c251..367f3589c6d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -596,6 +596,7 @@ void UserMediaRequest::Fail(WebUserMediaRequest::Error name,
case WebUserMediaRequest::Error::kInvalidState:
case WebUserMediaRequest::Error::kFailedDueToShutdown:
case WebUserMediaRequest::Error::kKillSwitchOn:
+ case WebUserMediaRequest::Error::kSystemPermissionDenied:
exception_code = DOMExceptionCode::kNotAllowedError;
break;
case WebUserMediaRequest::Error::kDevicesNotFound:
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h
index 5afb383f6dc..6424f4b5d78 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h
@@ -35,7 +35,7 @@
#include "third_party/blink/public/web/web_user_media_request.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_navigator_user_media_error_callback.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_navigator_user_media_success_callback.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/chromium/third_party/blink/renderer/modules/modules_idl_files.gni b/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
index ce6f8931996..54bb218b82d 100644
--- a/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -66,22 +66,25 @@ modules_idl_files =
"animationworklet/worklet_group_effect_proxy.idl",
"app_banner/before_install_prompt_event.idl",
"background_fetch/background_fetch_event.idl",
- "background_fetch/background_fetch_fetch.idl",
"background_fetch/background_fetch_manager.idl",
"background_fetch/background_fetch_record.idl",
"background_fetch/background_fetch_registration.idl",
"background_fetch/background_fetch_update_ui_event.idl",
"background_sync/sync_event.idl",
"background_sync/sync_manager.idl",
- "badging/badge.idl",
+ "badging/experimental_badge.idl",
"battery/battery_manager.idl",
"bluetooth/bluetooth.idl",
+ "bluetooth/bluetooth_advertising_event.idl",
"bluetooth/bluetooth_characteristic_properties.idl",
"bluetooth/bluetooth_device.idl",
+ "bluetooth/bluetooth_le_scan.idl",
+ "bluetooth/bluetooth_manufacturer_data_map.idl",
"bluetooth/bluetooth_remote_gatt_characteristic.idl",
"bluetooth/bluetooth_remote_gatt_descriptor.idl",
"bluetooth/bluetooth_remote_gatt_server.idl",
"bluetooth/bluetooth_remote_gatt_service.idl",
+ "bluetooth/bluetooth_service_data_map.idl",
"bluetooth/bluetooth_uuid.idl",
"broadcastchannel/broadcast_channel.idl",
"cache_storage/cache.idl",
@@ -93,7 +96,6 @@ modules_idl_files =
"canvas/imagebitmap/image_bitmap_rendering_context.idl",
"canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl",
"clipboard/clipboard.idl",
- "contacts_picker/contact_info.idl",
"contacts_picker/contacts_manager.idl",
"cookie_store/cookie_change_event.idl",
"cookie_store/cookie_store.idl",
@@ -164,6 +166,8 @@ modules_idl_files =
"geolocation/geolocation.idl",
"geolocation/position.idl",
"geolocation/position_error.idl",
+ "idle/idle_manager.idl",
+ "idle/idle_status.idl",
"imagecapture/image_capture.idl",
"imagecapture/media_settings_range.idl",
"imagecapture/photo_capabilities.idl",
@@ -234,7 +238,6 @@ modules_idl_files =
"peerconnection/rtc_quic_stream.idl",
"peerconnection/rtc_quic_stream_event.idl",
"peerconnection/rtc_quic_transport.idl",
- "peerconnection/rtc_rtp_contributing_source.idl",
"peerconnection/rtc_rtp_receiver.idl",
"peerconnection/rtc_rtp_sender.idl",
"peerconnection/rtc_rtp_transceiver.idl",
@@ -403,6 +406,8 @@ modules_idl_files =
"webgl/webgl_draw_buffers.idl",
"webgl/webgl_framebuffer.idl",
"webgl/webgl_lose_context.idl",
+ "webgl/webgl_multi_draw_instanced.idl",
+ "webgl/webgl_multi_draw.idl",
"webgl/webgl_multiview.idl",
"webgl/webgl_program.idl",
"webgl/webgl_query.idl",
@@ -445,11 +450,8 @@ modules_idl_files =
"webusb/usb_isochronous_out_transfer_result.idl",
"webusb/usb_out_transfer_result.idl",
"xr/xr.idl",
- "xr/xr_coordinate_system.idl",
- "xr/xr_device.idl",
- "xr/xr_device_pose.idl",
+ "xr/xr_bounded_reference_space.idl",
"xr/xr_frame.idl",
- "xr/xr_frame_of_reference.idl",
"xr/xr_hit_result.idl",
"xr/xr_input_pose.idl",
"xr/xr_input_source.idl",
@@ -457,10 +459,16 @@ modules_idl_files =
"xr/xr_layer.idl",
"xr/xr_presentation_context.idl",
"xr/xr_ray.idl",
+ "xr/xr_reference_space.idl",
+ "xr/xr_rigid_transform.idl",
"xr/xr_session.idl",
"xr/xr_session_event.idl",
+ "xr/xr_space.idl",
"xr/xr_stage_bounds.idl",
+ "xr/xr_stationary_reference_space.idl",
+ "xr/xr_unbounded_reference_space.idl",
"xr/xr_view.idl",
+ "xr/xr_viewer_pose.idl",
"xr/xr_viewport.idl",
"xr/xr_webgl_layer.idl",
],
@@ -487,12 +495,15 @@ modules_dictionary_idl_files =
"background_fetch/background_fetch_options.idl",
"background_fetch/background_fetch_ui_options.idl",
"background_sync/sync_event_init.idl",
+ "bluetooth/bluetooth_advertising_event_init.idl",
"bluetooth/bluetooth_le_scan_filter_init.idl",
+ "bluetooth/bluetooth_le_scan_options.idl",
"bluetooth/request_device_options.idl",
"cache_storage/cache_query_options.idl",
"canvas/canvas2d/canvas_rendering_context_2d_settings.idl",
"canvas/canvas2d/hit_region_options.idl",
"canvas/htmlcanvas/canvas_context_creation_attributes_module.idl",
+ "contacts_picker/contact_info.idl",
"contacts_picker/contacts_select_options.idl",
"cookie_store/cookie_change_event_init.idl",
"cookie_store/cookie_list_item.idl",
@@ -545,6 +556,7 @@ modules_dictionary_idl_files =
"gamepad/gamepad_effect_parameters.idl",
"gamepad/gamepad_event_init.idl",
"geolocation/position_options.idl",
+ "idle/idle_options.idl",
"imagecapture/constrain_point_2d_parameters.idl",
"imagecapture/photo_settings.idl",
"imagecapture/point_2d.idl",
@@ -630,16 +642,22 @@ modules_dictionary_idl_files =
"peerconnection/rtc_quic_parameters.idl",
"peerconnection/rtc_quic_stream_event_init.idl",
"peerconnection/rtc_quic_stream_read_result.idl",
+ "peerconnection/rtc_quic_stream_write_parameters.idl",
+ "peerconnection/rtc_quic_transport_stats.idl",
"peerconnection/rtc_rtcp_parameters.idl",
"peerconnection/rtc_rtp_capabilities.idl",
"peerconnection/rtc_rtp_codec_capability.idl",
"peerconnection/rtc_rtp_codec_parameters.idl",
"peerconnection/rtc_rtp_coding_parameters.idl",
+ "peerconnection/rtc_rtp_contributing_source.idl",
+ "peerconnection/rtc_rtp_decoding_parameters.idl",
"peerconnection/rtc_rtp_encoding_parameters.idl",
"peerconnection/rtc_rtp_header_extension_capability.idl",
"peerconnection/rtc_rtp_header_extension_parameters.idl",
"peerconnection/rtc_rtp_parameters.idl",
+ "peerconnection/rtc_rtp_receive_parameters.idl",
"peerconnection/rtc_rtp_send_parameters.idl",
+ "peerconnection/rtc_rtp_synchronization_source.idl",
"peerconnection/rtc_rtp_transceiver_init.idl",
"peerconnection/rtc_session_description_init.idl",
"peerconnection/rtc_track_event_init.idl",
@@ -715,8 +733,8 @@ modules_dictionary_idl_files =
"webusb/usb_control_transfer_parameters.idl",
"webusb/usb_device_filter.idl",
"webusb/usb_device_request_options.idl",
- "xr/xr_frame_of_reference_options.idl",
"xr/xr_input_source_event_init.idl",
+ "xr/xr_reference_space_options.idl",
"xr/xr_session_creation_options.idl",
"xr/xr_session_event_init.idl",
"xr/xr_webgl_layer_init.idl",
@@ -763,6 +781,8 @@ modules_dependency_idl_files =
"filesystem/window_file_system.idl",
"gamepad/navigator_gamepad.idl",
"geolocation/navigator_geolocation.idl",
+ "idle/navigator_idle.idl",
+ "idle/worker_navigator_idle.idl",
"indexeddb/window_indexed_database.idl",
"indexeddb/worker_global_scope_indexed_database.idl",
"installedapp/navigator_installed_app.idl",
@@ -839,25 +859,22 @@ if (support_webgl2_compute_context) {
get_path_info([
"canvas/htmlcanvas/html_canvas_element_module.idl",
"canvas/offscreencanvas/offscreen_canvas_module.idl",
- "webgl/webgl2_compute_rendering_context_base.idl",
],
"abspath")
}
modules_testing_dependency_idl_files =
- get_path_info(
- [
- "accessibility/testing/internals_accessibility.idl",
- "mediastream/testing/internals_media_stream.idl",
- "navigatorcontentutils/testing/internals_navigator_content_utils.idl",
- "peerconnection/testing/internals_rtc_certificate.idl",
- "peerconnection/testing/internals_rtc_peer_connection.idl",
- "service_worker/testing/internals_service_worker.idl",
- "speech/testing/internals_speech_synthesis.idl",
- "vibration/testing/internals_vibration.idl",
- "webaudio/testing/internals_web_audio.idl",
- ],
- "abspath")
+ get_path_info([
+ "accessibility/testing/internals_accessibility.idl",
+ "mediastream/testing/internals_media_stream.idl",
+ "peerconnection/testing/internals_rtc_certificate.idl",
+ "peerconnection/testing/internals_rtc_peer_connection.idl",
+ "service_worker/testing/internals_service_worker.idl",
+ "speech/testing/internals_speech_synthesis.idl",
+ "vibration/testing/internals_vibration.idl",
+ "webaudio/testing/internals_web_audio.idl",
+ ],
+ "abspath")
modules_definition_idl_files = modules_dictionary_idl_files + modules_idl_files
diff --git a/chromium/third_party/blink/renderer/modules/modules_initializer.cc b/chromium/third_party/blink/renderer/modules/modules_initializer.cc
index 0774044b411..5bfaf63e047 100644
--- a/chromium/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/chromium/third_party/blink/renderer/modules/modules_initializer.cc
@@ -222,10 +222,10 @@ void ModulesInitializer::InitInspectorAgentSession(
MakeGarbageCollected<DeviceOrientationInspectorAgent>(inspected_frames));
session->Append(
MakeGarbageCollected<InspectorDOMStorageAgent>(inspected_frames));
+ session->Append(MakeGarbageCollected<InspectorAccessibilityAgent>(
+ inspected_frames, dom_agent));
if (allow_view_agents) {
session->Append(InspectorDatabaseAgent::Create(page));
- session->Append(MakeGarbageCollected<InspectorAccessibilityAgent>(
- inspected_frames, dom_agent));
session->Append(InspectorCacheStorageAgent::Create(inspected_frames));
}
}
@@ -266,14 +266,15 @@ std::unique_ptr<WebMediaPlayer> ModulesInitializer::CreateWebMediaPlayer(
WebRemotePlaybackClient* ModulesInitializer::CreateWebRemotePlaybackClient(
HTMLMediaElement& html_media_element) const {
- return HTMLMediaElementRemotePlayback::remote(html_media_element);
+ return &RemotePlayback::From(html_media_element);
}
void ModulesInitializer::ProvideModulesToPage(Page& page,
WebViewClient* client) const {
MediaKeysController::ProvideMediaKeysTo(page);
::blink::ProvideContextFeaturesTo(page, ContextFeaturesClientImpl::Create());
- ::blink::ProvideDatabaseClientTo(page, new DatabaseClient);
+ ::blink::ProvideDatabaseClientTo(page,
+ MakeGarbageCollected<DatabaseClient>());
StorageNamespace::ProvideSessionStorageNamespaceTo(page, client);
}
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS
index 4a108e15962..2781695adae 100644
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS
@@ -1,3 +1,3 @@
-gyuyoung.kim@lge.com
+gyuyoung@igalia.com
# COMPONENT: Blink>HTML>CustomHandlers
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc
index d333b14e3f5..15eae4e2f2b 100644
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
@@ -44,7 +45,7 @@ static void InitCustomSchemeHandlerWhitelist() {
"mms", "news", "nntp", "openpgp4fpr", "sip", "sms", "smsto",
"ssh", "tel", "urn", "webcal", "wtai", "xmpp",
};
- for (size_t i = 0; i < arraysize(kSchemes); ++i)
+ for (size_t i = 0; i < base::size(kSchemes); ++i)
g_scheme_whitelist->insert(kSchemes[i]);
}
@@ -65,7 +66,7 @@ static bool VerifyCustomHandlerURL(const Document& document,
// It is also a SyntaxError if the custom handler URL, as created by removing
// the "%s" token and prepending the base url, does not resolve.
String new_url = url;
- new_url.Remove(index, arraysize(kToken) - 1);
+ new_url.Remove(index, base::size(kToken) - 1);
KURL kurl = document.CompleteURL(new_url);
if (kurl.IsEmpty() || !kurl.IsValid()) {
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc
deleted file mode 100644
index 7c76008c652..00000000000
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc
+++ /dev/null
@@ -1,26 +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 "third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/testing/internals.h"
-#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h"
-#include "third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h"
-
-namespace blink {
-
-void InternalsNavigatorContentUtils::setNavigatorContentUtilsClientMock(
- Internals&,
- Document* document) {
- DCHECK(document);
- DCHECK(document->GetPage());
- NavigatorContentUtils* navigator_content_utils =
- NavigatorContentUtils::From(*document->domWindow()->navigator());
- navigator_content_utils->SetClientForTest(
- NavigatorContentUtilsClientMock::Create());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h
deleted file mode 100644
index 598fb461624..00000000000
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h
+++ /dev/null
@@ -1,24 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_INTERNALS_NAVIGATOR_CONTENT_UTILS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_INTERNALS_NAVIGATOR_CONTENT_UTILS_H_
-
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-
-namespace blink {
-
-class Document;
-class Internals;
-
-class InternalsNavigatorContentUtils {
- STATIC_ONLY(InternalsNavigatorContentUtils);
-
- public:
- static void setNavigatorContentUtilsClientMock(Internals&, Document*);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_INTERNALS_NAVIGATOR_CONTENT_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl
deleted file mode 100644
index a8430ed4129..00000000000
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl
+++ /dev/null
@@ -1,9 +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.
-
-[
- ImplementedAs=InternalsNavigatorContentUtils
-] partial interface Internals {
- void setNavigatorContentUtilsClientMock(Document document);
-};
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc
deleted file mode 100644
index aaa7e14ee85..00000000000
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc
+++ /dev/null
@@ -1,30 +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 "third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h"
-
-#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
-
-namespace blink {
-
-void NavigatorContentUtilsClientMock::RegisterProtocolHandler(
- const String& scheme,
- const KURL& url,
- const String& title) {
- ProtocolInfo info;
- info.scheme = scheme;
- info.url = url;
- info.title = title;
-
- protocol_map_.Set(scheme, info);
-}
-
-void NavigatorContentUtilsClientMock::UnregisterProtocolHandler(
- const String& scheme,
- const KURL& url) {
- protocol_map_.erase(scheme);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h
deleted file mode 100644
index bbdb43d0d56..00000000000
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.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 THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_NAVIGATOR_CONTENT_UTILS_CLIENT_MOCK_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_NAVIGATOR_CONTENT_UTILS_CLIENT_MOCK_H_
-
-#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-// Provides a mock object for the navigatorcontentutils client.
-class NavigatorContentUtilsClientMock final
- : public NavigatorContentUtilsClient {
- public:
- static NavigatorContentUtilsClientMock* Create() {
- return MakeGarbageCollected<NavigatorContentUtilsClientMock>();
- }
-
- // TODO(sashab): Make NavigatorContentUtilsClientMock non-virtual and test it
- // using a WebLocalFrameClient mock.
- NavigatorContentUtilsClientMock() : NavigatorContentUtilsClient(nullptr) {}
- ~NavigatorContentUtilsClientMock() override = default;
-
- void RegisterProtocolHandler(const String& scheme,
- const KURL&,
- const String& title) override;
-
- void UnregisterProtocolHandler(const String& scheme, const KURL&) override;
-
- private:
- typedef struct {
- String scheme;
- KURL url;
- String title;
- } ProtocolInfo;
-
- typedef HashMap<String, ProtocolInfo> RegisteredProtocolMap;
- RegisteredProtocolMap protocol_map_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_NAVIGATOR_CONTENT_UTILS_CLIENT_MOCK_H_
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc.cc b/chromium/third_party/blink/renderer/modules/nfc/nfc.cc
index 5a41f334447..f778384df45 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/modules/nfc/nfc.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
@@ -646,11 +645,14 @@ NFC::NFC(LocalFrame* frame)
if (!IsSupportedInContext(GetExecutionContext(), error_message))
return;
- frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&nfc_));
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner = frame->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ frame->GetInterfaceProvider().GetInterface(
+ mojo::MakeRequest(&nfc_, task_runner));
nfc_.set_connection_error_handler(
WTF::Bind(&NFC::OnConnectionError, WrapWeakPersistent(this)));
device::mojom::blink::NFCClientPtr client;
- client_binding_.Bind(mojo::MakeRequest(&client));
+ client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
nfc_->SetClient(std::move(client));
}
@@ -819,7 +821,7 @@ void NFC::PageVisibilityChanged() {
// NFC operations should be suspended.
// https://w3c.github.io/web-nfc/#nfc-suspended
- if (GetPage()->VisibilityState() == mojom::PageVisibilityState::kVisible)
+ if (GetPage()->IsPageVisible())
nfc_->ResumeNFCOperations();
else
nfc_->SuspendNFCOperations();
@@ -859,8 +861,10 @@ void NFC::OnWatch(const Vector<uint32_t>& ids,
auto it = callbacks_.find(id);
if (it != callbacks_.end()) {
V8MessageCallback* callback = it->value;
- ScriptState* script_state = callback->CallbackRelevantScriptState();
- DCHECK(script_state);
+ ScriptState* script_state =
+ callback->CallbackRelevantScriptStateOrReportError("NFC", "watch");
+ if (!script_state)
+ continue;
ScriptState::Scope scope(script_state);
const NFCMessage* nfc_message = ToNFCMessage(script_state, message);
callback->InvokeAndReportException(nullptr, nfc_message);
diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc
index 2005d93042d..1a099e28948 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc
+++ b/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/notifications/notification_data.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/testing/null_execution_context.h"
#include "third_party/blink/renderer/modules/notifications/notification.h"
@@ -66,7 +67,8 @@ class CompleteUrlExecutionContext final : public NullExecutionContext {
class NotificationDataTest : public testing::Test {
public:
void SetUp() override {
- execution_context_ = new CompleteUrlExecutionContext(kNotificationBaseUrl);
+ execution_context_ =
+ MakeGarbageCollected<CompleteUrlExecutionContext>(kNotificationBaseUrl);
}
ExecutionContext* GetExecutionContext() { return execution_context_.Get(); }
@@ -77,7 +79,7 @@ class NotificationDataTest : public testing::Test {
TEST_F(NotificationDataTest, ReflectProperties) {
Vector<unsigned> vibration_pattern;
- for (size_t i = 0; i < arraysize(kNotificationVibration); ++i)
+ for (size_t i = 0; i < base::size(kNotificationVibration); ++i)
vibration_pattern.push_back(kNotificationVibration[i]);
UnsignedLongOrUnsignedLongSequence vibration_sequence;
@@ -156,7 +158,7 @@ TEST_F(NotificationDataTest, ReflectProperties) {
TEST_F(NotificationDataTest, SilentNotificationWithVibration) {
Vector<unsigned> vibration_pattern;
- for (size_t i = 0; i < arraysize(kNotificationVibration); ++i)
+ for (size_t i = 0; i < base::size(kNotificationVibration); ++i)
vibration_pattern.push_back(kNotificationVibration[i]);
UnsignedLongOrUnsignedLongSequence vibration_sequence;
@@ -239,7 +241,7 @@ TEST_F(NotificationDataTest, InvalidIconUrls) {
TEST_F(NotificationDataTest, VibrationNormalization) {
Vector<unsigned> unnormalized_pattern;
- for (size_t i = 0; i < arraysize(kNotificationVibrationUnnormalized); ++i)
+ for (size_t i = 0; i < base::size(kNotificationVibrationUnnormalized); ++i)
unnormalized_pattern.push_back(kNotificationVibrationUnnormalized[i]);
UnsignedLongOrUnsignedLongSequence vibration_sequence;
@@ -254,7 +256,7 @@ TEST_F(NotificationDataTest, VibrationNormalization) {
EXPECT_FALSE(exception_state.HadException());
Vector<int> normalized_pattern;
- for (size_t i = 0; i < arraysize(kNotificationVibrationNormalized); ++i)
+ for (size_t i = 0; i < base::size(kNotificationVibrationNormalized); ++i)
normalized_pattern.push_back(kNotificationVibrationNormalized[i]);
ASSERT_EQ(normalized_pattern.size(),
diff --git a/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.idl b/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.idl
index 587cb1f4e00..d40f95de00c 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.idl
+++ b/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.idl
@@ -9,6 +9,6 @@
ImplementedAs=ServiceWorkerRegistrationNotifications,
RuntimeEnabled=Notifications
] partial interface ServiceWorkerRegistration {
- [CallWith=ScriptState, RaisesException] Promise showNotification(DOMString title, optional NotificationOptions options);
+ [CallWith=ScriptState, RaisesException] Promise<void> showNotification(DOMString title, optional NotificationOptions options);
[CallWith=ScriptState] Promise<sequence<Notification>> getNotifications(optional GetNotificationOptions filter);
};
diff --git a/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.cc b/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.cc
index 752bbc1728d..99dcad8a830 100644
--- a/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.cc
@@ -19,7 +19,8 @@ namespace blink {
AbortPaymentEvent* AbortPaymentEvent::Create(
const AtomicString& type,
const ExtendableEventInit* initializer) {
- return new AbortPaymentEvent(type, initializer, nullptr, nullptr);
+ return MakeGarbageCollected<AbortPaymentEvent>(type, initializer, nullptr,
+ nullptr);
}
AbortPaymentEvent* AbortPaymentEvent::Create(
@@ -27,8 +28,8 @@ AbortPaymentEvent* AbortPaymentEvent::Create(
const ExtendableEventInit* initializer,
RespondWithObserver* respond_with_observer,
WaitUntilObserver* wait_until_observer) {
- return new AbortPaymentEvent(type, initializer, respond_with_observer,
- wait_until_observer);
+ return MakeGarbageCollected<AbortPaymentEvent>(
+ type, initializer, respond_with_observer, wait_until_observer);
}
AbortPaymentEvent::~AbortPaymentEvent() = default;
diff --git a/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.h b/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.h
index 6f77bbd5275..c40bce34239 100644
--- a/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.h
+++ b/chromium/third_party/blink/renderer/modules/payments/abort_payment_event.h
@@ -32,6 +32,11 @@ class MODULES_EXPORT AbortPaymentEvent final : public ExtendableEvent {
const ExtendableEventInit*,
RespondWithObserver*,
WaitUntilObserver*);
+
+ AbortPaymentEvent(const AtomicString& type,
+ const ExtendableEventInit*,
+ RespondWithObserver*,
+ WaitUntilObserver*);
~AbortPaymentEvent() override;
const AtomicString& InterfaceName() const override;
@@ -41,11 +46,6 @@ class MODULES_EXPORT AbortPaymentEvent final : public ExtendableEvent {
void Trace(blink::Visitor*) override;
private:
- AbortPaymentEvent(const AtomicString& type,
- const ExtendableEventInit*,
- RespondWithObserver*,
- WaitUntilObserver*);
-
Member<RespondWithObserver> observer_;
};
diff --git a/chromium/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
index 55992d19323..3d864138811 100644
--- a/chromium/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
@@ -38,8 +38,8 @@ void AbortPaymentRespondWithObserver::OnResponseFulfilled(
DCHECK(GetExecutionContext());
ExceptionState exception_state(value.GetIsolate(), context_type,
interface_name, property_name);
- bool response = ToBoolean(ToIsolate(GetExecutionContext()), value.V8Value(),
- exception_state);
+ bool response =
+ ToBoolean(value.GetIsolate(), value.V8Value(), exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
OnResponseRejected(blink::mojom::ServiceWorkerResponseError::kNoV8Instance);
diff --git a/chromium/third_party/blink/renderer/modules/payments/basic_card_helper.cc b/chromium/third_party/blink/renderer/modules/payments/basic_card_helper.cc
index c454b57ccec..6f3ca2d6c48 100644
--- a/chromium/third_party/blink/renderer/modules/payments/basic_card_helper.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/basic_card_helper.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/payments/basic_card_helper.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_basic_card_request.h"
#include "third_party/blink/renderer/modules/payments/basic_card_request.h"
#include "third_party/blink/renderer/modules/payments/payment_request.h"
@@ -57,7 +58,7 @@ void BasicCardHelper::ParseBasiccardData(
}
for (const String& network : basic_card->supportedNetworks()) {
- for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
+ for (size_t i = 0; i < base::size(kBasicCardNetworks); ++i) {
if (network == kBasicCardNetworks[i].name) {
supported_networks_output.push_back(kBasicCardNetworks[i].code);
break;
@@ -74,7 +75,7 @@ void BasicCardHelper::ParseBasiccardData(
}
for (const String& type : basic_card->supportedTypes()) {
- for (size_t i = 0; i < arraysize(kBasicCardTypes); ++i) {
+ for (size_t i = 0; i < base::size(kBasicCardTypes); ++i) {
if (type == kBasicCardTypes[i].name) {
supported_types_output.push_back(kBasicCardTypes[i].code);
break;
@@ -85,7 +86,7 @@ void BasicCardHelper::ParseBasiccardData(
}
bool BasicCardHelper::IsNetworkName(const String& input) {
- for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
+ for (size_t i = 0; i < base::size(kBasicCardNetworks); ++i) {
if (input == kBasicCardNetworks[i].name) {
return true;
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc
index a03a1d06f5c..f428edea3b4 100644
--- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc
@@ -18,7 +18,8 @@ namespace blink {
CanMakePaymentEvent* CanMakePaymentEvent::Create(
const AtomicString& type,
const CanMakePaymentEventInit* initializer) {
- return new CanMakePaymentEvent(type, initializer, nullptr, nullptr);
+ return MakeGarbageCollected<CanMakePaymentEvent>(type, initializer, nullptr,
+ nullptr);
}
CanMakePaymentEvent* CanMakePaymentEvent::Create(
@@ -26,8 +27,8 @@ CanMakePaymentEvent* CanMakePaymentEvent::Create(
const CanMakePaymentEventInit* initializer,
RespondWithObserver* respond_with_observer,
WaitUntilObserver* wait_until_observer) {
- return new CanMakePaymentEvent(type, initializer, respond_with_observer,
- wait_until_observer);
+ return MakeGarbageCollected<CanMakePaymentEvent>(
+ type, initializer, respond_with_observer, wait_until_observer);
}
CanMakePaymentEvent::~CanMakePaymentEvent() = default;
diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.h b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.h
index 3931550f133..b38d40ef6f7 100644
--- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.h
+++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.h
@@ -33,6 +33,11 @@ class MODULES_EXPORT CanMakePaymentEvent final : public ExtendableEvent {
const CanMakePaymentEventInit*,
RespondWithObserver*,
WaitUntilObserver*);
+
+ CanMakePaymentEvent(const AtomicString& type,
+ const CanMakePaymentEventInit*,
+ RespondWithObserver*,
+ WaitUntilObserver*);
~CanMakePaymentEvent() override;
const AtomicString& InterfaceName() const override;
@@ -47,11 +52,6 @@ class MODULES_EXPORT CanMakePaymentEvent final : public ExtendableEvent {
void Trace(blink::Visitor*) override;
private:
- CanMakePaymentEvent(const AtomicString& type,
- const CanMakePaymentEventInit*,
- RespondWithObserver*,
- WaitUntilObserver*);
-
String top_origin_;
String payment_request_origin_;
HeapVector<Member<PaymentMethodData>> method_data_;
diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
index 41e87e2b80a..0a610481546 100644
--- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
@@ -38,8 +38,8 @@ void CanMakePaymentRespondWithObserver::OnResponseFulfilled(
DCHECK(GetExecutionContext());
ExceptionState exception_state(value.GetIsolate(), context_type,
interface_name, property_name);
- bool response = ToBoolean(ToIsolate(GetExecutionContext()), value.V8Value(),
- exception_state);
+ bool response =
+ ToBoolean(value.GetIsolate(), value.V8Value(), exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
OnResponseRejected(blink::mojom::ServiceWorkerResponseError::kNoV8Instance);
diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
index 503bbf16bb1..ac712f722f9 100644
--- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
@@ -13,10 +13,26 @@ namespace blink {
namespace {
using payments::mojom::blink::CanMakePaymentQueryResult;
+using payments::mojom::blink::HasEnrolledInstrumentQueryResult;
using payments::mojom::blink::PaymentErrorReason;
using payments::mojom::blink::PaymentRequestClient;
-TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) {
+// HasEnrolledInstrumentTest is parameterized on this enum to test that
+// canMakePayment when PaymentRequestHasEnrolledInstrumentEnabled is false
+// behaves identically to hasEnrolledInstrument.
+enum class HasEnrolledInstrumentEnabled { kYes, kNo };
+
+class HasEnrolledInstrumentTest
+ : public testing::Test,
+ public testing::WithParamInterface<HasEnrolledInstrumentEnabled> {
+ void SetUp() override {
+ testing::Test::SetUp();
+ RuntimeEnabledFeatures::SetPaymentRequestHasEnrolledInstrumentEnabled(
+ GetParam() == HasEnrolledInstrumentEnabled::kYes);
+ }
+};
+
+TEST_P(HasEnrolledInstrumentTest, RejectPromiseOnUserCancel) {
V8TestingScope scope;
PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -24,14 +40,19 @@ TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) {
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
- request->canMakePayment(scope.GetScriptState())
- .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ if (GetParam() == HasEnrolledInstrumentEnabled::kYes) {
+ request->hasEnrolledInstrument(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ } else {
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ }
static_cast<PaymentRequestClient*>(request)->OnError(
PaymentErrorReason::USER_CANCEL);
}
-TEST(CanMakePaymentTest, RejectPromiseOnUnknownError) {
+TEST_P(HasEnrolledInstrumentTest, RejectPromiseOnUnknownError) {
V8TestingScope scope;
PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -39,27 +60,133 @@ TEST(CanMakePaymentTest, RejectPromiseOnUnknownError) {
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
- request->canMakePayment(scope.GetScriptState())
- .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ if (GetParam() == HasEnrolledInstrumentEnabled::kYes) {
+ request->hasEnrolledInstrument(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ } else {
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ }
static_cast<PaymentRequestClient*>(request)->OnError(
PaymentErrorReason::UNKNOWN);
}
-TEST(CanMakePaymentTest, RejectDuplicateRequest) {
+TEST_P(HasEnrolledInstrumentTest, RejectDuplicateRequest) {
+ V8TestingScope scope;
+ PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MakePaymentRequestOriginSecure(scope.GetDocument());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+ if (GetParam() == HasEnrolledInstrumentEnabled::kYes) {
+ request->hasEnrolledInstrument(scope.GetScriptState());
+ request->hasEnrolledInstrument(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ } else {
+ request->canMakePayment(scope.GetScriptState());
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ }
+}
+
+TEST_P(HasEnrolledInstrumentTest, RejectQueryQuotaExceeded) {
+ RuntimeEnabledFeatures::SetPaymentRequestHasEnrolledInstrumentEnabled(false);
+ V8TestingScope scope;
+ PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MakePaymentRequestOriginSecure(scope.GetDocument());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+
+ if (GetParam() == HasEnrolledInstrumentEnabled::kYes) {
+ request->hasEnrolledInstrument(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ } else {
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+ }
+
+ static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
+ HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED);
+}
+
+TEST_P(HasEnrolledInstrumentTest, ReturnHasNoEnrolledInstrument) {
+ V8TestingScope scope;
+ PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MakePaymentRequestOriginSecure(scope.GetDocument());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+ String captor;
+ if (GetParam() == HasEnrolledInstrumentEnabled::kYes) {
+ request->hasEnrolledInstrument(scope.GetScriptState())
+ .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+ } else {
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+ }
+
+ static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
+ HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT);
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
+ EXPECT_EQ("false", captor);
+}
+
+TEST_P(HasEnrolledInstrumentTest, ReturnHasEnrolledInstrument) {
+ V8TestingScope scope;
+ PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MakePaymentRequestOriginSecure(scope.GetDocument());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+ String captor;
+ if (GetParam() == HasEnrolledInstrumentEnabled::kYes) {
+ request->hasEnrolledInstrument(scope.GetScriptState())
+ .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+ } else {
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+ }
+
+ static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
+ HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT);
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
+ EXPECT_EQ("true", captor);
+}
+
+INSTANTIATE_TEST_CASE_P(ProgrammaticHasEnrolledInstrumentTest,
+ HasEnrolledInstrumentTest,
+ ::testing::Values(HasEnrolledInstrumentEnabled::kYes,
+ HasEnrolledInstrumentEnabled::kNo));
+
+// Test fixture for canMakePayment when
+// PaymentRequestHasEnrolledInstrumentEnabled is true.
+class CanMakePaymentTest : public testing::Test {
+ void SetUp() override {
+ testing::Test::SetUp();
+ RuntimeEnabledFeatures::SetPaymentRequestHasEnrolledInstrumentEnabled(true);
+ }
+};
+
+TEST_F(CanMakePaymentTest, RejectPromiseOnUserCancel) {
V8TestingScope scope;
PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
MakePaymentRequestOriginSecure(scope.GetDocument());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
- request->canMakePayment(scope.GetScriptState());
request->canMakePayment(scope.GetScriptState())
.Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+
+ static_cast<PaymentRequestClient*>(request)->OnError(
+ PaymentErrorReason::USER_CANCEL);
}
-TEST(CanMakePaymentTest, RejectQueryQuotaExceeded) {
+TEST_F(CanMakePaymentTest, RejectPromiseOnUnknownError) {
V8TestingScope scope;
PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -70,11 +197,24 @@ TEST(CanMakePaymentTest, RejectQueryQuotaExceeded) {
request->canMakePayment(scope.GetScriptState())
.Then(funcs.ExpectNoCall(), funcs.ExpectCall());
- static_cast<PaymentRequestClient*>(request)->OnCanMakePayment(
- CanMakePaymentQueryResult::QUERY_QUOTA_EXCEEDED);
+ static_cast<PaymentRequestClient*>(request)->OnError(
+ PaymentErrorReason::UNKNOWN);
+}
+
+TEST_F(CanMakePaymentTest, RejectDuplicateRequest) {
+ V8TestingScope scope;
+ PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MakePaymentRequestOriginSecure(scope.GetDocument());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+ request->canMakePayment(scope.GetScriptState());
+
+ request->canMakePayment(scope.GetScriptState())
+ .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
}
-TEST(CanMakePaymentTest, ReturnCannotMakeCanMakePayment) {
+TEST_F(CanMakePaymentTest, ReturnCannotMakePayment) {
V8TestingScope scope;
PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -92,7 +232,7 @@ TEST(CanMakePaymentTest, ReturnCannotMakeCanMakePayment) {
EXPECT_EQ("false", captor);
}
-TEST(CanMakePaymentTest, ReturnCanMakePayment) {
+TEST_F(CanMakePaymentTest, ReturnCanMakePayment) {
V8TestingScope scope;
PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
MakePaymentRequestOriginSecure(scope.GetDocument());
diff --git a/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc b/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
index 5c3852d70b1..49a42630dbb 100644
--- a/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
@@ -399,16 +399,16 @@ class PaymentResponseFunction : public ScriptFunction {
static v8::Local<v8::Function> Create(ScriptState* script_state,
ScriptValue* out_value) {
PaymentResponseFunction* self =
- new PaymentResponseFunction(script_state, out_value);
+ MakeGarbageCollected<PaymentResponseFunction>(script_state, out_value);
return self->BindToV8Function();
}
- private:
PaymentResponseFunction(ScriptState* script_state, ScriptValue* out_value)
: ScriptFunction(script_state), value_(out_value) {
DCHECK(value_);
}
+ private:
ScriptValue Call(ScriptValue value) override {
DCHECK(!value.IsEmpty());
*value_ = value;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_address.idl b/chromium/third_party/blink/renderer/modules/payments/payment_address.idl
index 58901857b34..01e2a3e5645 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_address.idl
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_address.idl
@@ -9,7 +9,7 @@
SecureContext,
Exposed=Window
] interface PaymentAddress {
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
readonly attribute DOMString city;
readonly attribute DOMString country;
readonly attribute DOMString dependentLocality;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_manager.cc b/chromium/third_party/blink/renderer/modules/payments/payment_manager.cc
index f9db07d10b6..8d92b022e48 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_manager.cc
@@ -44,8 +44,9 @@ PaymentManager::PaymentManager(ServiceWorkerRegistration* registration)
: registration_(registration), instruments_(nullptr) {
DCHECK(registration);
- auto request = mojo::MakeRequest(&manager_);
if (ExecutionContext* context = registration->GetExecutionContext()) {
+ auto request = mojo::MakeRequest(
+ &manager_, context->GetTaskRunner(TaskType::kUserInteraction));
if (auto* interface_provider = context->GetInterfaceProvider()) {
interface_provider->GetInterface(std::move(request));
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
index 72ad2483129..05f90cd14b3 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc
@@ -17,7 +17,8 @@ PaymentMethodChangeEvent* PaymentMethodChangeEvent::Create(
ScriptState* script_state,
const AtomicString& type,
const PaymentMethodChangeEventInit* init) {
- return new PaymentMethodChangeEvent(script_state, type, init);
+ return MakeGarbageCollected<PaymentMethodChangeEvent>(script_state, type,
+ init);
}
const String& PaymentMethodChangeEvent::methodName() const {
@@ -28,7 +29,8 @@ const ScriptValue PaymentMethodChangeEvent::methodDetails(
ScriptState* script_state) const {
if (method_details_.IsEmpty())
return ScriptValue::CreateNull(script_state);
- return ScriptValue::ToWorldSafeScriptValue(script_state, method_details_);
+ return ScriptValue(script_state,
+ method_details_.GetAcrossWorld(script_state));
}
void PaymentMethodChangeEvent::Trace(Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h
index 5783b009983..162ce1e3e1d 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h
@@ -6,12 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_METHOD_CHANGE_EVENT_H_
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/payments/payment_method_change_event_init.h"
#include "third_party/blink/renderer/modules/payments/payment_request_update_event.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -35,15 +34,15 @@ class MODULES_EXPORT PaymentMethodChangeEvent final
const String& methodName() const;
const ScriptValue methodDetails(ScriptState*) const;
- void Trace(Visitor* visitor) override;
-
- private:
PaymentMethodChangeEvent(ScriptState*,
const AtomicString& type,
const PaymentMethodChangeEventInit*);
+ void Trace(Visitor* visitor) override;
+
+ private:
String method_name_;
- TraceWrapperV8Reference<v8::Value> method_details_;
+ WorldSafeV8Reference<v8::Value> method_details_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
index 34f940dabdc..3564c977e57 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -6,7 +6,9 @@
#include <stddef.h>
#include <utility>
+
#include "base/location.h"
+#include "base/stl_util.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
@@ -66,6 +68,7 @@ namespace {
using ::payments::mojom::blink::AddressErrors;
using ::payments::mojom::blink::AddressErrorsPtr;
using ::payments::mojom::blink::CanMakePaymentQueryResult;
+using ::payments::mojom::blink::HasEnrolledInstrumentQueryResult;
using ::payments::mojom::blink::PayerErrors;
using ::payments::mojom::blink::PayerErrorsPtr;
using ::payments::mojom::blink::PaymentAddress;
@@ -413,7 +416,7 @@ void SetAndroidPayMethodData(const ScriptValue& input,
for (const String& allowed_card_network :
android_pay->allowedCardNetworks()) {
- for (size_t i = 0; i < arraysize(kAndroidPayNetwork); ++i) {
+ for (size_t i = 0; i < base::size(kAndroidPayNetwork); ++i) {
if (allowed_card_network == kAndroidPayNetwork[i].name) {
output->allowed_card_networks.push_back(kAndroidPayNetwork[i].code);
break;
@@ -437,7 +440,7 @@ void SetAndroidPayMethodData(const ScriptValue& input,
{AndroidPayTokenization::GATEWAY_TOKEN, "GATEWAY_TOKEN"},
{AndroidPayTokenization::NETWORK_TOKEN, "NETWORK_TOKEN"}};
- for (size_t i = 0; i < arraysize(kAndroidPayTokenization); ++i) {
+ for (size_t i = 0; i < base::size(kAndroidPayTokenization); ++i) {
if (tokenization->tokenizationType() ==
kAndroidPayTokenization[i].name) {
output->tokenization_type = kAndroidPayTokenization[i].code;
@@ -630,8 +633,9 @@ void ValidateAndConvertPaymentDetailsBase(const PaymentDetailsBase* input,
// If requestShipping is specified and there are shipping options to validate,
// proceed with validation.
if (options->requestShipping() && input->hasShippingOptions()) {
+ output->shipping_options = Vector<PaymentShippingOptionPtr>();
ValidateAndConvertShippingOptions(
- input->shippingOptions(), output->shipping_options,
+ input->shippingOptions(), *output->shipping_options,
shipping_option_output, execution_context, exception_state);
if (exception_state.HadException())
return;
@@ -861,6 +865,12 @@ ScriptPromise PaymentRequest::abort(ScriptState* script_state) {
}
ScriptPromise PaymentRequest::canMakePayment(ScriptState* script_state) {
+ if (!RuntimeEnabledFeatures::PaymentRequestHasEnrolledInstrumentEnabled()) {
+ // Fallback to backward-compatible definition of canMakePayment, which is
+ // now implemented as hasEnrolledInstrument.
+ return hasEnrolledInstrument(script_state);
+ }
+
if (!payment_provider_.is_bound() || GetPendingAcceptPromiseResolver() ||
can_make_payment_resolver_ || !script_state->ContextIsValid()) {
return ScriptPromise::RejectWithDOMException(
@@ -874,6 +884,21 @@ ScriptPromise PaymentRequest::canMakePayment(ScriptState* script_state) {
return can_make_payment_resolver_->Promise();
}
+ScriptPromise PaymentRequest::hasEnrolledInstrument(ScriptState* script_state) {
+ if (!payment_provider_.is_bound() || GetPendingAcceptPromiseResolver() ||
+ has_enrolled_instrument_resolver_ || !script_state->ContextIsValid()) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
+ "Cannot query payment request"));
+ }
+
+ payment_provider_->HasEnrolledInstrument();
+
+ has_enrolled_instrument_resolver_ =
+ ScriptPromiseResolver::Create(script_state);
+ return has_enrolled_instrument_resolver_->Promise();
+}
+
bool PaymentRequest::HasPendingActivity() const {
return GetPendingAcceptPromiseResolver() || complete_resolver_;
}
@@ -924,6 +949,37 @@ ScriptPromise PaymentRequest::Retry(ScriptState* script_state,
script_state->GetIsolate(), error_message));
}
+ if (!options_->requestPayerName() && errors->hasPayer() &&
+ errors->payer()->hasName()) {
+ GetExecutionContext()->AddConsoleMessage(
+ ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
+ "The payer.name passed to retry() may not be "
+ "shown because requestPayerName is false"));
+ }
+
+ if (!options_->requestPayerEmail() && errors->hasPayer() &&
+ errors->payer()->hasEmail()) {
+ GetExecutionContext()->AddConsoleMessage(
+ ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
+ "The payer.email passed to retry() may not be "
+ "shown because requestPayerEmail is false"));
+ }
+
+ if (!options_->requestPayerPhone() && errors->hasPayer() &&
+ errors->payer()->hasPhone()) {
+ GetExecutionContext()->AddConsoleMessage(
+ ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
+ "The payer.phone passed to retry() may not be "
+ "shown because requestPayerPhone is false"));
+ }
+
+ if (!options_->requestShipping() && errors->hasShippingAddress()) {
+ GetExecutionContext()->AddConsoleMessage(
+ ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
+ "The shippingAddress passed to retry() may not "
+ "be shown because requestShipping is false"));
+ }
+
complete_timer_.Stop();
// The payment provider should respond in PaymentRequest::OnPaymentResponse().
@@ -1025,16 +1081,18 @@ void PaymentRequest::OnUpdatePaymentDetails(
UseCounter::Count(
GetExecutionContext(),
WebFeature::kUpdateWithoutShippingOptionOnShippingAddressChange);
+ validated_details->shipping_options = Vector<PaymentShippingOptionPtr>();
}
if (event_type == event_type_names::kShippingoptionchange) {
UseCounter::Count(
GetExecutionContext(),
WebFeature::kUpdateWithoutShippingOptionOnShippingOptionChange);
+ validated_details->shipping_options = Vector<PaymentShippingOptionPtr>();
}
}
if (!options_->requestShipping())
- validated_details->shipping_options.clear();
+ validated_details->shipping_options = base::nullopt;
payment_provider_->UpdateWith(std::move(validated_details));
}
@@ -1061,6 +1119,7 @@ void PaymentRequest::Trace(blink::Visitor* visitor) {
visitor->Trace(complete_resolver_);
visitor->Trace(abort_resolver_);
visitor->Trace(can_make_payment_resolver_);
+ visitor->Trace(has_enrolled_instrument_resolver_);
EventTargetWithInlineData::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
}
@@ -1119,19 +1178,22 @@ PaymentRequest::PaymentRequest(
if (options_->requestShipping())
shipping_type_ = options_->shippingType();
else
- validated_details->shipping_options.clear();
+ validated_details->shipping_options = base::nullopt;
DCHECK(shipping_type_.IsNull() || shipping_type_ == "shipping" ||
shipping_type_ == "delivery" || shipping_type_ == "pickup");
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ execution_context->GetTaskRunner(TaskType::kUserInteraction);
+
GetFrame()->GetInterfaceProvider().GetInterface(
- mojo::MakeRequest(&payment_provider_));
+ mojo::MakeRequest(&payment_provider_, task_runner));
payment_provider_.set_connection_error_handler(
WTF::Bind(&PaymentRequest::OnError, WrapWeakPersistent(this),
PaymentErrorReason::UNKNOWN));
payments::mojom::blink::PaymentRequestClientPtr client;
- client_binding_.Bind(mojo::MakeRequest(&client));
+ client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
payment_provider_->Init(std::move(client), std::move(validated_method_data),
std::move(validated_details),
payments::mojom::blink::PaymentOptions::From(
@@ -1343,6 +1405,11 @@ void PaymentRequest::OnError(PaymentErrorReason error) {
DOMException::Create(exception_code, message));
}
+ if (has_enrolled_instrument_resolver_) {
+ has_enrolled_instrument_resolver_->Reject(
+ DOMException::Create(exception_code, message));
+ }
+
ClearResolversAndCloseMojoConnection();
}
@@ -1371,32 +1438,49 @@ void PaymentRequest::OnAbort(bool aborted_successfully) {
}
void PaymentRequest::OnCanMakePayment(CanMakePaymentQueryResult result) {
+ if (!can_make_payment_resolver_)
+ return;
+
+ switch (result) {
+ case CanMakePaymentQueryResult::CAN_MAKE_PAYMENT:
+ can_make_payment_resolver_->Resolve(true);
+ break;
+ case CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT:
+ can_make_payment_resolver_->Resolve(false);
+ break;
+ }
+
+ can_make_payment_resolver_.Clear();
+}
+
+void PaymentRequest::OnHasEnrolledInstrument(
+ HasEnrolledInstrumentQueryResult result) {
// TODO(https://crbug.com/891371): Understand how the resolver could be null
// here and prevent it.
- if (!can_make_payment_resolver_)
+ if (!has_enrolled_instrument_resolver_)
return;
switch (result) {
- case CanMakePaymentQueryResult::WARNING_CAN_MAKE_PAYMENT:
+ case HasEnrolledInstrumentQueryResult::WARNING_HAS_ENROLLED_INSTRUMENT:
WarnIgnoringQueryQuotaForCanMakePayment(*GetExecutionContext());
FALLTHROUGH;
- case CanMakePaymentQueryResult::CAN_MAKE_PAYMENT:
- can_make_payment_resolver_->Resolve(true);
+ case HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT:
+ has_enrolled_instrument_resolver_->Resolve(true);
break;
- case CanMakePaymentQueryResult::WARNING_CANNOT_MAKE_PAYMENT:
+ case HasEnrolledInstrumentQueryResult::WARNING_HAS_NO_ENROLLED_INSTRUMENT:
WarnIgnoringQueryQuotaForCanMakePayment(*GetExecutionContext());
FALLTHROUGH;
- case CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT:
- can_make_payment_resolver_->Resolve(false);
+ case HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT:
+ has_enrolled_instrument_resolver_->Resolve(false);
break;
- case CanMakePaymentQueryResult::QUERY_QUOTA_EXCEEDED:
- can_make_payment_resolver_->Reject(DOMException::Create(
+ case HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED:
+ has_enrolled_instrument_resolver_->Reject(DOMException::Create(
DOMExceptionCode::kNotAllowedError,
"Not allowed to check whether can make payment"));
break;
}
- can_make_payment_resolver_.Clear();
+ has_enrolled_instrument_resolver_.Clear();
}
void PaymentRequest::WarnNoFavicon() {
@@ -1421,6 +1505,7 @@ void PaymentRequest::ClearResolversAndCloseMojoConnection() {
retry_resolver_.Clear();
abort_resolver_.Clear();
can_make_payment_resolver_.Clear();
+ has_enrolled_instrument_resolver_.Clear();
if (client_binding_.is_bound())
client_binding_.Close();
payment_provider_.reset();
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request.h b/chromium/third_party/blink/renderer/modules/payments/payment_request.h
index 9045d3505a7..089fd8b1b8a 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.h
@@ -80,6 +80,7 @@ class MODULES_EXPORT PaymentRequest final
DEFINE_ATTRIBUTE_EVENT_LISTENER(paymentmethodchange, kPaymentmethodchange);
ScriptPromise canMakePayment(ScriptState*);
+ ScriptPromise hasEnrolledInstrument(ScriptState*);
// ScriptWrappable:
bool HasPendingActivity() const override;
@@ -125,6 +126,8 @@ class MODULES_EXPORT PaymentRequest final
void OnAbort(bool aborted_successfully) override;
void OnCanMakePayment(
payments::mojom::blink::CanMakePaymentQueryResult) override;
+ void OnHasEnrolledInstrument(
+ payments::mojom::blink::HasEnrolledInstrumentQueryResult) override;
void WarnNoFavicon() override;
void OnCompleteTimeout(TimerBase*);
@@ -150,6 +153,7 @@ class MODULES_EXPORT PaymentRequest final
Member<ScriptPromiseResolver> retry_resolver_;
Member<ScriptPromiseResolver> abort_resolver_;
Member<ScriptPromiseResolver> can_make_payment_resolver_;
+ Member<ScriptPromiseResolver> has_enrolled_instrument_resolver_;
payments::mojom::blink::PaymentRequestPtr payment_provider_;
mojo::Binding<payments::mojom::blink::PaymentRequestClient> client_binding_;
TaskRunnerTimer<PaymentRequest> complete_timer_;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request.idl b/chromium/third_party/blink/renderer/modules/payments/payment_request.idl
index f7837401510..e2a1c83d7f2 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.idl
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.idl
@@ -16,7 +16,8 @@
] interface PaymentRequest : EventTarget {
[CallWith=ScriptState, NewObject] Promise<PaymentResponse> show();
[CallWith=ScriptState, NewObject] Promise<void> abort();
- [CallWith=ScriptState, NewObject] Promise<boolean> canMakePayment();
+ [CallWith=ScriptState, HighEntropy, Measure, NewObject] Promise<boolean> canMakePayment();
+ [CallWith=ScriptState, HighEntropy, Measure, NewObject, RuntimeEnabled=PaymentRequestHasEnrolledInstrument] Promise<boolean> hasEnrolledInstrument();
readonly attribute DOMString id;
[ImplementedAs=getShippingAddress] readonly attribute PaymentAddress? shippingAddress;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc
index c8e5ee19d13..cfdcd13b07f 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc
@@ -47,7 +47,7 @@ void PaymentRequestRespondWithObserver::OnResponseFulfilled(
interface_name, property_name);
PaymentHandlerResponse* response =
NativeValueTraits<PaymentHandlerResponse>::NativeValue(
- ToIsolate(GetExecutionContext()), value.V8Value(), exception_state);
+ value.GetIsolate(), value.V8Value(), exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
OnResponseRejected(mojom::ServiceWorkerResponseError::kNoV8Instance);
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.cc
index 080fc25b647..4035b7f6cd8 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.cc
@@ -27,22 +27,23 @@ class UpdatePaymentDetailsFunction : public ScriptFunction {
ScriptState* script_state,
PaymentRequestUpdateEvent* update_event) {
UpdatePaymentDetailsFunction* self =
- new UpdatePaymentDetailsFunction(script_state, update_event);
+ MakeGarbageCollected<UpdatePaymentDetailsFunction>(script_state,
+ update_event);
return self->BindToV8Function();
}
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(update_event_);
- ScriptFunction::Trace(visitor);
- }
-
- private:
UpdatePaymentDetailsFunction(ScriptState* script_state,
PaymentRequestUpdateEvent* update_event)
: ScriptFunction(script_state), update_event_(update_event) {
DCHECK(update_event_);
}
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(update_event_);
+ ScriptFunction::Trace(visitor);
+ }
+
+ private:
ScriptValue Call(ScriptValue value) override {
update_event_->OnUpdatePaymentDetails(update_event_->type(), value);
return ScriptValue();
@@ -56,22 +57,23 @@ class UpdatePaymentDetailsErrorFunction : public ScriptFunction {
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
PaymentUpdater* updater) {
UpdatePaymentDetailsErrorFunction* self =
- new UpdatePaymentDetailsErrorFunction(script_state, updater);
+ MakeGarbageCollected<UpdatePaymentDetailsErrorFunction>(script_state,
+ updater);
return self->BindToV8Function();
}
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(updater_);
- ScriptFunction::Trace(visitor);
- }
-
- private:
UpdatePaymentDetailsErrorFunction(ScriptState* script_state,
PaymentUpdater* updater)
: ScriptFunction(script_state), updater_(updater) {
DCHECK(updater_);
}
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(updater_);
+ ScriptFunction::Trace(visitor);
+ }
+
+ private:
ScriptValue Call(ScriptValue value) override {
updater_->OnUpdatePaymentDetailsFailure(
ToCoreString(value.V8Value()
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
index 4e2148cba1d..6e44d1abef5 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
@@ -40,7 +40,7 @@ TEST(PaymentRequestUpdateEventTest, OnUpdatePaymentDetailsCalled) {
V8TestingScope scope;
PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
- MockPaymentUpdater* updater = new MockPaymentUpdater;
+ MockPaymentUpdater* updater = MakeGarbageCollected<MockPaymentUpdater>();
event->SetTrusted(true);
event->SetPaymentDetailsUpdater(updater);
event->SetEventPhase(Event::kCapturingPhase);
@@ -62,7 +62,7 @@ TEST(PaymentRequestUpdateEventTest, OnUpdatePaymentDetailsFailureCalled) {
V8TestingScope scope;
PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
- MockPaymentUpdater* updater = new MockPaymentUpdater;
+ MockPaymentUpdater* updater = MakeGarbageCollected<MockPaymentUpdater>();
event->SetTrusted(true);
event->SetPaymentDetailsUpdater(updater);
event->SetEventPhase(Event::kCapturingPhase);
@@ -85,7 +85,7 @@ TEST(PaymentRequestUpdateEventTest, CannotUpdateWithoutDispatching) {
V8TestingScope scope;
PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
- event->SetPaymentDetailsUpdater(new MockPaymentUpdater);
+ event->SetPaymentDetailsUpdater((MakeGarbageCollected<MockPaymentUpdater>()));
event->updateWith(
scope.GetScriptState(),
@@ -99,7 +99,7 @@ TEST(PaymentRequestUpdateEventTest, CannotUpdateTwice) {
V8TestingScope scope;
PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
- MockPaymentUpdater* updater = new MockPaymentUpdater;
+ MockPaymentUpdater* updater = MakeGarbageCollected<MockPaymentUpdater>();
event->SetTrusted(true);
event->SetPaymentDetailsUpdater(updater);
event->SetEventPhase(Event::kCapturingPhase);
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response.cc b/chromium/third_party/blink/renderer/modules/payments/payment_response.cc
index d49786f98ed..0116fdc0351 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_response.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_response.cc
@@ -104,7 +104,7 @@ ScriptValue PaymentResponse::toJSONForBinding(ScriptState* script_state) const {
}
ScriptValue PaymentResponse::details(ScriptState* script_state) const {
- return ScriptValue::ToWorldSafeScriptValue(script_state, details_);
+ return ScriptValue(script_state, details_.GetAcrossWorld(script_state));
}
ScriptPromise PaymentResponse::complete(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response.h b/chromium/third_party/blink/renderer/modules/payments/payment_response.h
index c404239ebcd..14d51f6930f 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_response.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_response.h
@@ -9,12 +9,12 @@
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/payments/payment_currency_amount.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -74,7 +74,7 @@ class MODULES_EXPORT PaymentResponse final
private:
String request_id_;
String method_name_;
- TraceWrapperV8Reference<v8::Value> details_;
+ WorldSafeV8Reference<v8::Value> details_;
Member<PaymentAddress> shipping_address_;
String shipping_option_;
String payer_name_;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response.idl b/chromium/third_party/blink/renderer/modules/payments/payment_response.idl
index f5d94a35018..6401233f885 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_response.idl
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_response.idl
@@ -18,7 +18,7 @@ enum PaymentComplete {
Exposed=Window,
ActiveScriptWrappable
] interface PaymentResponse : EventTarget {
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
readonly attribute DOMString requestId;
readonly attribute DOMString methodName;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc b/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc
index e95f4eff0fc..1d39bc9ac12 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc
@@ -57,7 +57,8 @@ TEST(PaymentResponseTest, DataCopiedOver) {
input->payer->name = "Jon Doe";
input->payer->email = "abc@gmail.com";
input->payer->phone = "0123";
- MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver;
+ MockPaymentStateResolver* complete_callback =
+ MakeGarbageCollected<MockPaymentStateResolver>();
PaymentResponse* output = MakeGarbageCollected<PaymentResponse>(
scope.GetScriptState(), std::move(input), nullptr, complete_callback,
@@ -90,7 +91,8 @@ TEST(PaymentResponseTest,
payments::mojom::blink::PaymentResponsePtr input =
BuildPaymentResponseForTest();
input->stringified_details = "transactionId";
- MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver;
+ MockPaymentStateResolver* complete_callback =
+ MakeGarbageCollected<MockPaymentStateResolver>();
PaymentResponse* output = MakeGarbageCollected<PaymentResponse>(
scope.GetScriptState(), std::move(input), nullptr, complete_callback,
"id");
@@ -113,7 +115,8 @@ TEST(PaymentResponseTest, PaymentResponseDetailsRetrunsTheSameObject) {
BuildPaymentResponseForTest();
input->method_name = "foo";
input->stringified_details = "{\"transactionId\": 123}";
- MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver;
+ MockPaymentStateResolver* complete_callback =
+ MakeGarbageCollected<MockPaymentStateResolver>();
PaymentResponse* output = MakeGarbageCollected<PaymentResponse>(
scope.GetScriptState(), std::move(input), nullptr, complete_callback,
"id");
@@ -127,7 +130,8 @@ TEST(PaymentResponseTest, CompleteCalledWithSuccess) {
BuildPaymentResponseForTest();
input->method_name = "foo";
input->stringified_details = "{\"transactionId\": 123}";
- MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver;
+ MockPaymentStateResolver* complete_callback =
+ MakeGarbageCollected<MockPaymentStateResolver>();
PaymentResponse* output = MakeGarbageCollected<PaymentResponse>(
scope.GetScriptState(), std::move(input), nullptr, complete_callback,
"id");
@@ -144,7 +148,8 @@ TEST(PaymentResponseTest, CompleteCalledWithFailure) {
BuildPaymentResponseForTest();
input->method_name = "foo";
input->stringified_details = "{\"transactionId\": 123}";
- MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver;
+ MockPaymentStateResolver* complete_callback =
+ MakeGarbageCollected<MockPaymentStateResolver>();
PaymentResponse* output = MakeGarbageCollected<PaymentResponse>(
scope.GetScriptState(), std::move(input), nullptr, complete_callback,
"id");
@@ -177,7 +182,7 @@ TEST(PaymentResponseTest, JSONSerializerTest) {
PaymentResponse* output = MakeGarbageCollected<PaymentResponse>(
scope.GetScriptState(), std::move(input), address,
- new MockPaymentStateResolver, "id");
+ MakeGarbageCollected<MockPaymentStateResolver>(), "id");
ScriptValue json_object = output->toJSONForBinding(scope.GetScriptState());
EXPECT_TRUE(json_object.IsObject());
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn
index 0054f5936aa..63bf60375aa 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -6,6 +6,8 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("peerconnection") {
sources = [
+ "adapters/dtls_transport_proxy.cc",
+ "adapters/dtls_transport_proxy.h",
"adapters/ice_transport_adapter.h",
"adapters/ice_transport_adapter_cross_thread_factory.h",
"adapters/ice_transport_adapter_impl.cc",
@@ -14,6 +16,9 @@ blink_modules_sources("peerconnection") {
"adapters/ice_transport_host.h",
"adapters/ice_transport_proxy.cc",
"adapters/ice_transport_proxy.h",
+ "adapters/p2p_quic_crypto_config_factory.h",
+ "adapters/p2p_quic_crypto_config_factory_impl.cc",
+ "adapters/p2p_quic_crypto_config_factory_impl.h",
"adapters/p2p_quic_packet_transport.h",
"adapters/p2p_quic_stream.h",
"adapters/p2p_quic_stream_impl.cc",
@@ -24,6 +29,10 @@ blink_modules_sources("peerconnection") {
"adapters/p2p_quic_transport_factory_impl.h",
"adapters/p2p_quic_transport_impl.cc",
"adapters/p2p_quic_transport_impl.h",
+ "adapters/p2p_quic_transport_stats.cc",
+ "adapters/p2p_quic_transport_stats.h",
+ "adapters/quic_packet_transport_adapter.cc",
+ "adapters/quic_packet_transport_adapter.h",
"adapters/quic_stream_host.cc",
"adapters/quic_stream_host.h",
"adapters/quic_stream_proxy.cc",
@@ -70,8 +79,6 @@ blink_modules_sources("peerconnection") {
"rtc_quic_stream_event.h",
"rtc_quic_transport.cc",
"rtc_quic_transport.h",
- "rtc_rtp_contributing_source.cc",
- "rtc_rtp_contributing_source.h",
"rtc_rtp_receiver.cc",
"rtc_rtp_receiver.h",
"rtc_rtp_sender.cc",
@@ -102,4 +109,8 @@ blink_modules_sources("peerconnection") {
"web_rtc_stats_report_callback_resolver.cc",
"web_rtc_stats_report_callback_resolver.h",
]
+
+ public_deps = [
+ "//third_party/webrtc/api:scoped_refptr",
+ ]
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc
new file mode 100644
index 00000000000..0d4862646a7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h"
+
+#include "base/location.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+
+namespace blink {
+
+// Static
+std::unique_ptr<DtlsTransportProxy> DtlsTransportProxy::Create(
+ LocalFrame& frame,
+ scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> host_thread,
+ webrtc::DtlsTransportInterface* dtls_transport,
+ Delegate* delegate) {
+ DCHECK(proxy_thread->BelongsToCurrentThread());
+ std::unique_ptr<DtlsTransportProxy> proxy =
+ base::WrapUnique(new DtlsTransportProxy(frame, proxy_thread, host_thread,
+ dtls_transport, delegate));
+ // TODO(hta): Delete this thread jump once creation can be initiated
+ // from the host thread (=webrtc signalling thread).
+ PostCrossThreadTask(*host_thread, FROM_HERE,
+ CrossThreadBind(&DtlsTransportProxy::StartOnHostThread,
+ CrossThreadUnretained(proxy.get())));
+ return proxy;
+}
+
+DtlsTransportProxy::DtlsTransportProxy(
+ LocalFrame& frame,
+ scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> host_thread,
+ webrtc::DtlsTransportInterface* dtls_transport,
+ Delegate* delegate)
+ : proxy_thread_(std::move(proxy_thread)),
+ host_thread_(std::move(host_thread)),
+ dtls_transport_(dtls_transport),
+ delegate_(delegate) {}
+
+void DtlsTransportProxy::StartOnHostThread() {
+ DCHECK(host_thread_->BelongsToCurrentThread());
+ dtls_transport_->RegisterObserver(this);
+ PostCrossThreadTask(*proxy_thread_, FROM_HERE,
+ CrossThreadBind(&Delegate::OnStartCompleted,
+ CrossThreadUnretained(delegate_),
+ dtls_transport_->Information()));
+}
+
+void DtlsTransportProxy::OnStateChange(webrtc::DtlsTransportInformation info) {
+ DCHECK(host_thread_->BelongsToCurrentThread());
+ // Closed is the last state that can happen, so unregister when we see this.
+ // Unregistering allows us to safely delete the proxy independent of the
+ // state of the webrtc::DtlsTransport.
+ if (info.state() == webrtc::DtlsTransportState::kClosed) {
+ dtls_transport_->UnregisterObserver();
+ }
+ PostCrossThreadTask(*proxy_thread_, FROM_HERE,
+ CrossThreadBind(&Delegate::OnStateChange,
+ CrossThreadUnretained(delegate_), info));
+}
+
+void DtlsTransportProxy::OnError(webrtc::RTCError error) {
+ DCHECK(host_thread_->BelongsToCurrentThread());
+ NOTIMPLEMENTED();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h
new file mode 100644
index 00000000000..ec2b1191ff6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_DTLS_TRANSPORT_PROXY_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_DTLS_TRANSPORT_PROXY_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/single_thread_task_runner.h"
+#include "third_party/webrtc/api/dtls_transport_interface.h"
+
+// The DtlsTransportProxy class takes care of thread-jumping when
+// connecting callbacks from a webrtc::DtlsTransport to a
+// blink::RTCDtlsTransport object.
+
+// Its design is modeled on the IceTransportProxy design,
+// but does not use so many layers of indirection - there is
+// no control, and all information is passed via callbacks on the Delegate.
+
+// The proxy thread = the Blink main thread
+// The host thread = the webrtc signalling thread (the one that gets callbacks)
+
+namespace blink {
+
+class LocalFrame;
+
+class DtlsTransportProxy : public webrtc::DtlsTransportObserverInterface {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+
+ // Called when the Create() function is complete. Sends current state,
+ // but does not indicate a state change.
+ virtual void OnStartCompleted(webrtc::DtlsTransportInformation info) = 0;
+ // Called when a state change is signalled from transport.
+ virtual void OnStateChange(webrtc::DtlsTransportInformation info) = 0;
+ };
+ // Constructs a DtlsTransportProxy.
+ // The caller is responsible for keeping |dtls_transport| and |delegate|
+ // alive until after the DtlsTransportProxy is deleted.
+ // The DtlsTransportProxy can be safely deleted after seeing the
+ // state |kClosed|, since this is the last event that can happen
+ // on the transport.
+ static std::unique_ptr<DtlsTransportProxy> Create(
+ LocalFrame& frame,
+ scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> host_thread,
+ webrtc::DtlsTransportInterface* dtls_transport,
+ Delegate* delegate);
+
+ private:
+ DtlsTransportProxy(LocalFrame& frame,
+ scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> host_thread,
+ webrtc::DtlsTransportInterface* dtls_transport,
+ Delegate* delegate);
+ // Implementation of webrtc::DtlsTransportObserver
+ void OnStateChange(webrtc::DtlsTransportInformation info) override;
+ void OnError(webrtc::RTCError error) override;
+
+ // Internal helper for Create()
+ void StartOnHostThread();
+
+ const scoped_refptr<base::SingleThreadTaskRunner> proxy_thread_;
+ const scoped_refptr<base::SingleThreadTaskRunner> host_thread_;
+ webrtc::DtlsTransportInterface* dtls_transport_;
+ Delegate* const delegate_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_DTLS_TRANSPORT_PROXY_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h
index 77354113979..bbe20a5f7e6 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_H_
-#include "third_party/webrtc/p2p/base/p2ptransportchannel.h"
+#include "third_party/webrtc/p2p/base/p2p_transport_channel.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
index 9bb782218be..1bed259d797 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
@@ -4,84 +4,18 @@
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h"
namespace blink {
-namespace {
-
-// Implementation of P2PQuicPacketTransport backed by a P2PTransportChannel.
-class QuicPacketTransportAdapter : public P2PQuicPacketTransport,
- public sigslot::has_slots<> {
- public:
- QuicPacketTransportAdapter(
- cricket::P2PTransportChannel* p2p_transport_channel)
- : p2p_transport_channel_(p2p_transport_channel) {
- DCHECK(p2p_transport_channel_);
- p2p_transport_channel_->SignalReadPacket.connect(
- this, &QuicPacketTransportAdapter::OnReadPacket);
- p2p_transport_channel_->SignalReadyToSend.connect(
- this, &QuicPacketTransportAdapter::OnReadyToSend);
- }
-
- ~QuicPacketTransportAdapter() override {
- // Caller is responsible for unsetting the write observer and receive
- // delegate before destroying this.
- DCHECK(!write_observer_);
- DCHECK(!receive_delegate_);
- }
-
- int WritePacket(const QuicPacket& packet) override {
- rtc::PacketOptions options;
- options.packet_id = packet.packet_number;
- int flags = 0;
- return p2p_transport_channel_->SendPacket(packet.buffer, packet.buf_len,
- options, flags);
- }
-
- void SetReceiveDelegate(ReceiveDelegate* receive_delegate) override {
- receive_delegate_ = receive_delegate;
- }
-
- void SetWriteObserver(WriteObserver* write_observer) override {
- write_observer_ = write_observer;
- }
-
- bool Writable() override { return p2p_transport_channel_->writable(); }
-
- private:
- // P2PTransportChannel callbacks.
- void OnReadPacket(rtc::PacketTransportInternal* packet_transport,
- const char* buffer,
- size_t buffer_length,
- const rtc::PacketTime& packet_time,
- int flags) {
- DCHECK_EQ(packet_transport, p2p_transport_channel_);
- if (!receive_delegate_) {
- // TODO(crbug.com/874296): Consider providing a small buffer.
- return;
- }
- receive_delegate_->OnPacketDataReceived(buffer, buffer_length);
- }
- void OnReadyToSend(rtc::PacketTransportInternal* packet_transport) {
- DCHECK_EQ(packet_transport, p2p_transport_channel_);
- if (!write_observer_) {
- return;
- }
- write_observer_->OnCanWrite();
- }
-
- cricket::P2PTransportChannel* p2p_transport_channel_;
- ReceiveDelegate* receive_delegate_ = nullptr;
- WriteObserver* write_observer_ = nullptr;
-};
-
-} // namespace
IceTransportAdapterImpl::IceTransportAdapterImpl(
Delegate* delegate,
std::unique_ptr<cricket::PortAllocator> port_allocator,
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory,
rtc::Thread* thread)
- : delegate_(delegate), port_allocator_(std::move(port_allocator)) {
+ : delegate_(delegate),
+ port_allocator_(std::move(port_allocator)),
+ async_resolver_factory_(std::move(async_resolver_factory)) {
// TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component.
if (!rtc::ThreadManager::Instance()->CurrentThread()) {
rtc::ThreadManager::Instance()->SetCurrentThread(thread);
@@ -97,7 +31,7 @@ IceTransportAdapterImpl::IceTransportAdapterImpl(
port_allocator_->Initialize();
p2p_transport_channel_ = std::make_unique<cricket::P2PTransportChannel>(
- "", 0, port_allocator_.get());
+ "", 0, port_allocator_.get(), async_resolver_factory.get());
p2p_transport_channel_->SignalGatheringState.connect(
this, &IceTransportAdapterImpl::OnGatheringStateChanged);
p2p_transport_channel_->SignalCandidateGathered.connect(
@@ -106,6 +40,8 @@ IceTransportAdapterImpl::IceTransportAdapterImpl(
this, &IceTransportAdapterImpl::OnStateChanged);
p2p_transport_channel_->SignalNetworkRouteChanged.connect(
this, &IceTransportAdapterImpl::OnNetworkRouteChanged);
+ p2p_transport_channel_->SignalRoleConflict.connect(
+ this, &IceTransportAdapterImpl::OnRoleConflict);
// We need to set the ICE role even before Start is called since the Port
// assumes that the role has been set before receiving incoming connectivity
// checks. These checks can race with the information signaled for Start.
@@ -161,10 +97,7 @@ void IceTransportAdapterImpl::Start(
void IceTransportAdapterImpl::HandleRemoteRestart(
const cricket::IceParameters& new_remote_parameters) {
- auto remote_candidates = p2p_transport_channel_->remote_candidates();
- for (const auto& remote_candidate : remote_candidates) {
- p2p_transport_channel_->RemoveRemoteCandidate(remote_candidate);
- }
+ p2p_transport_channel_->RemoveAllRemoteCandidates();
p2p_transport_channel_->SetRemoteIceParameters(new_remote_parameters);
}
@@ -213,4 +146,37 @@ void IceTransportAdapterImpl::OnNetworkRouteChanged(
selected_connection->remote_candidate()));
}
+static const char* IceRoleToString(cricket::IceRole role) {
+ switch (role) {
+ case cricket::ICEROLE_CONTROLLING:
+ return "controlling";
+ case cricket::ICEROLE_CONTROLLED:
+ return "controlled";
+ default:
+ return "unknown";
+ }
+}
+
+static cricket::IceRole IceRoleReversed(cricket::IceRole role) {
+ switch (role) {
+ case cricket::ICEROLE_CONTROLLING:
+ return cricket::ICEROLE_CONTROLLED;
+ case cricket::ICEROLE_CONTROLLED:
+ return cricket::ICEROLE_CONTROLLING;
+ default:
+ return cricket::ICEROLE_UNKNOWN;
+ }
+}
+
+void IceTransportAdapterImpl::OnRoleConflict(
+ cricket::IceTransportInternal* transport) {
+ DCHECK_EQ(transport, p2p_transport_channel_.get());
+ // This logic is copied from JsepTransportController.
+ cricket::IceRole reversed_role =
+ IceRoleReversed(p2p_transport_channel_->GetIceRole());
+ LOG(INFO) << "Got role conflict; switching to "
+ << IceRoleToString(reversed_role) << " role.";
+ p2p_transport_channel_->SetIceRole(reversed_role);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
index 0b92df88e9a..5293bd23a89 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
@@ -21,6 +21,7 @@ class IceTransportAdapterImpl final : public IceTransportAdapter,
IceTransportAdapterImpl(
Delegate* delegate,
std::unique_ptr<cricket::PortAllocator> port_allocator,
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory,
rtc::Thread* thread);
~IceTransportAdapterImpl() override;
@@ -47,10 +48,12 @@ class IceTransportAdapterImpl final : public IceTransportAdapter,
void OnStateChanged(cricket::IceTransportInternal* transport);
void OnNetworkRouteChanged(
absl::optional<rtc::NetworkRoute> new_network_route);
+ void OnRoleConflict(cricket::IceTransportInternal* transport);
Delegate* const delegate_;
std::unique_ptr<cricket::PortAllocator> port_allocator_;
- std::unique_ptr<cricket::P2PTransportChannel> p2p_transport_channel_;
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
+ std::unique_ptr<cricket::IceTransportInternal> p2p_transport_channel_;
std::unique_ptr<P2PQuicPacketTransport> quic_packet_transport_adapter_;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
index 6907f860070..c3e9ade9882 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
@@ -12,7 +12,7 @@
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/webrtc/p2p/base/p2ptransportchannel.h"
+#include "third_party/webrtc/p2p/base/p2p_transport_channel.h"
namespace rtc {
class Thread;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h
new file mode 100644
index 00000000000..fbcb8a088c5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_H_
+
+#include "net/third_party/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/third_party/quic/core/crypto/quic_crypto_server_config.h"
+
+namespace blink {
+
+// Builds the crypto configurations to be used by the P2PQuicTransport.
+class P2PQuicCryptoConfigFactory {
+ public:
+ virtual ~P2PQuicCryptoConfigFactory() = default;
+
+ // Creates the client crypto configuration to be used by a
+ // quic::QuicCryptoClientStream. This includes a ProofVerifier object that
+ // verifies the server's certificate and is used in the QUIC handshake.
+ virtual std::unique_ptr<quic::QuicCryptoClientConfig>
+ CreateClientCryptoConfig() = 0;
+
+ // Creates the server crypto configuration to be used by a
+ // quic::QuicCryptoServerStream. This includes a ProofSource object that gives
+ // the server's certificate.
+ virtual std::unique_ptr<quic::QuicCryptoServerConfig>
+ CreateServerCryptoConfig() = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc
new file mode 100644
index 00000000000..58b3b365681
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc
@@ -0,0 +1,135 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quic/core/crypto/proof_source.h"
+#include "net/third_party/quic/core/crypto/proof_verifier.h"
+
+#include "net/third_party/quic/core/tls_client_handshaker.h"
+#include "net/third_party/quic/core/tls_server_handshaker.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h"
+
+namespace blink {
+
+namespace {
+
+// Length of HKDF input keying material, equal to its number of bytes.
+// https://tools.ietf.org/html/rfc5869#section-2.2.
+const size_t kInputKeyingMaterialLength = 32;
+
+// TODO(https://crbug.com/874300): Implement a secure QUIC handshake, meaning
+// that both side's certificates are verified. This can be done by creating a
+// P2PProofSource and P2PProofVerifier, and removing these objects once the
+// TLS 1.3 handshake is implemented for QUIC.
+// - The self signed certificate fingerprint matches the remote
+// fingerprint that was signaled.
+// - The peer owns the certificate, by verifying the signature of the hash of
+// the handshake context.
+//
+// Ignores the peer's credentials (taken from quic/quartc).
+class InsecureProofVerifier : public quic::ProofVerifier {
+ public:
+ InsecureProofVerifier() {}
+ ~InsecureProofVerifier() override {}
+
+ // ProofVerifier override.
+ quic::QuicAsyncStatus VerifyProof(
+ const quic::QuicString& hostname,
+ const uint16_t port,
+ const quic::QuicString& server_config,
+ quic::QuicTransportVersion transport_version,
+ quic::QuicStringPiece chlo_hash,
+ const std::vector<quic::QuicString>& certs,
+ const quic::QuicString& cert_sct,
+ const quic::QuicString& signature,
+ const quic::ProofVerifyContext* context,
+ quic::QuicString* error_details,
+ std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
+ std::unique_ptr<quic::ProofVerifierCallback> callback) override {
+ return quic::QUIC_SUCCESS;
+ }
+
+ quic::QuicAsyncStatus VerifyCertChain(
+ const quic::QuicString& hostname,
+ const std::vector<quic::QuicString>& certs,
+ const quic::ProofVerifyContext* context,
+ quic::QuicString* error_details,
+ std::unique_ptr<quic::ProofVerifyDetails>* details,
+ std::unique_ptr<quic::ProofVerifierCallback> callback) override {
+ return quic::QUIC_SUCCESS;
+ }
+
+ std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override {
+ return nullptr;
+ }
+};
+
+} // namespace
+
+// Used by QuicCryptoServerConfig to provide dummy proof credentials
+// (taken from quic/quartc).
+class DummyProofSource : public quic::ProofSource {
+ public:
+ DummyProofSource() {}
+ ~DummyProofSource() override {}
+
+ // ProofSource override.
+ void GetProof(const quic::QuicSocketAddress& server_addr,
+ const quic::QuicString& hostname,
+ const quic::QuicString& server_config,
+ quic::QuicTransportVersion transport_version,
+ quic::QuicStringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override {
+ quic::QuicCryptoProof proof;
+ proof.signature = "Dummy signature";
+ proof.leaf_cert_scts = "Dummy timestamp";
+ callback->Run(true, GetCertChain(server_addr, hostname), proof,
+ nullptr /* details */);
+ }
+
+ quic::QuicReferenceCountedPointer<Chain> GetCertChain(
+ const quic::QuicSocketAddress& server_address,
+ const quic::QuicString& hostname) override {
+ std::vector<quic::QuicString> certs;
+ certs.push_back("Dummy cert");
+ return quic::QuicReferenceCountedPointer<Chain>(
+ new quic::ProofSource::Chain(certs));
+ }
+ void ComputeTlsSignature(
+ const quic::QuicSocketAddress& server_address,
+ const quic::QuicString& hostname,
+ uint16_t signature_algorithm,
+ quic::QuicStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) override {
+ callback->Run(true, "Dummy signature");
+ }
+};
+
+P2PQuicCryptoConfigFactoryImpl::P2PQuicCryptoConfigFactoryImpl(
+ quic::QuicRandom* const random_generator)
+ : random_generator_(random_generator) {}
+
+std::unique_ptr<quic::QuicCryptoClientConfig>
+P2PQuicCryptoConfigFactoryImpl::CreateClientCryptoConfig() {
+ std::unique_ptr<quic::ProofVerifier> proof_verifier(
+ new InsecureProofVerifier);
+ return std::make_unique<quic::QuicCryptoClientConfig>(
+ std::move(proof_verifier), quic::TlsClientHandshaker::CreateSslCtx());
+}
+
+std::unique_ptr<quic::QuicCryptoServerConfig>
+P2PQuicCryptoConfigFactoryImpl::CreateServerCryptoConfig() {
+ // Generate a random source address token secret every time since this is
+ // a transient client.
+ char source_address_token_secret[kInputKeyingMaterialLength];
+ random_generator_->RandBytes(source_address_token_secret,
+ kInputKeyingMaterialLength);
+ std::unique_ptr<quic::ProofSource> proof_source(new DummyProofSource);
+ return std::make_unique<quic::QuicCryptoServerConfig>(
+ quic::QuicString(source_address_token_secret, kInputKeyingMaterialLength),
+ random_generator_, std::move(proof_source),
+ quic::KeyExchangeSource::Default(),
+ quic::TlsServerHandshaker::CreateSslCtx());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h
new file mode 100644
index 00000000000..780d914ad80
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_IMPL_H_
+
+#include "net/third_party/quic/core/crypto/proof_source.h"
+#include "net/third_party/quic/core/crypto/quic_random.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate.h"
+
+namespace blink {
+
+// An abstraction for building the crypto configurations to be used by the
+// P2PQuicTransport.
+class MODULES_EXPORT P2PQuicCryptoConfigFactoryImpl final
+ : public P2PQuicCryptoConfigFactory {
+ public:
+ P2PQuicCryptoConfigFactoryImpl(
+ quic::QuicRandom* const random_generator);
+
+ ~P2PQuicCryptoConfigFactoryImpl() override{};
+
+ // P2PQuicCryptoConfigFactory overrides.
+ //
+ // Creates a client config that accepts any remote certificate.
+ std::unique_ptr<quic::QuicCryptoClientConfig> CreateClientCryptoConfig()
+ override;
+ // Creates a server config with a DummyProofSource.
+ std::unique_ptr<quic::QuicCryptoServerConfig> CreateServerCryptoConfig()
+ override;
+
+ private:
+ // TODO(crbug.com/874296): Add certificate(s) to create a proof source
+ // that comes from the self signed certificate given to the RTCQuicTransport.
+ quic::QuicRandom* const random_generator_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h
index a6d923eda71..c3ce1dfed2e 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h
@@ -77,7 +77,8 @@ class P2PQuicStream {
// for reading and writing and deleted by the quic::QuicSession.
virtual void WriteData(Vector<uint8_t> data, bool fin) = 0;
- // Sets the delegate object, which must outlive the P2PQuicStream.
+ // Sets the delegate object. In the case that the Delegate does not outlive
+ // the P2PQuicStream object, it must unset itself before destructing.
virtual void SetDelegate(Delegate* delegate) = 0;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc
index a01078cee8b..b53479f2443 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc
@@ -4,7 +4,9 @@
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h"
+#include <utility>
#include "net/third_party/quic/core/quic_error_codes.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
@@ -19,16 +21,28 @@ P2PQuicStreamImpl::P2PQuicStreamImpl(quic::QuicStreamId id,
DCHECK_GT(write_buffer_size_, 0u);
}
+P2PQuicStreamImpl::P2PQuicStreamImpl(quic::PendingStream pending,
+ quic::QuicSession* session,
+ uint32_t delegate_read_buffer_size,
+ uint32_t write_buffer_size)
+ : quic::QuicStream(std::move(pending), quic::BIDIRECTIONAL),
+ delegate_read_buffer_size_(delegate_read_buffer_size),
+ write_buffer_size_(write_buffer_size) {
+ DCHECK_GT(delegate_read_buffer_size_, 0u);
+ DCHECK_GT(write_buffer_size_, 0u);
+}
+
P2PQuicStreamImpl::~P2PQuicStreamImpl() {}
void P2PQuicStreamImpl::OnDataAvailable() {
- DCHECK(delegate_);
if (!sequencer()->HasBytesToRead() && sequencer()->IsClosed()) {
// We have consumed all data from the sequencer up to the FIN bit. This can
// only occur by receiving an empty STREAM frame with the FIN bit set.
quic::QuicStream::OnFinRead();
- delegate_->OnDataReceived({}, /*fin=*/true);
consumed_fin_ = true;
+ if (delegate_) {
+ delegate_->OnDataReceived({}, /*fin=*/true);
+ }
}
uint32_t delegate_read_buffer_available =
@@ -75,17 +89,20 @@ void P2PQuicStreamImpl::OnDataAvailable() {
quic::QuicStream::OnFinRead();
consumed_fin_ = fin;
}
- delegate_->OnDataReceived(std::move(data), fin);
+ if (delegate_) {
+ delegate_->OnDataReceived(std::move(data), fin);
+ }
}
void P2PQuicStreamImpl::OnStreamDataConsumed(size_t bytes_consumed) {
- DCHECK(delegate_);
// We should never consume more than has been written.
DCHECK_GE(write_buffered_amount_, bytes_consumed);
QuicStream::OnStreamDataConsumed(bytes_consumed);
if (bytes_consumed > 0) {
write_buffered_amount_ -= bytes_consumed;
- delegate_->OnWriteDataConsumed(bytes_consumed);
+ if (delegate_) {
+ delegate_->OnWriteDataConsumed(SafeCast<uint32_t>(bytes_consumed));
+ }
}
}
@@ -122,12 +139,13 @@ void P2PQuicStreamImpl::SetDelegate(P2PQuicStream::Delegate* delegate) {
}
void P2PQuicStreamImpl::OnStreamReset(const quic::QuicRstStreamFrame& frame) {
- DCHECK(delegate_);
// Calling this on the QuicStream will ensure that the stream is closed
// for reading and writing and we send a RST frame to the remote side if
// we have not already.
quic::QuicStream::OnStreamReset(frame);
- delegate_->OnRemoteReset();
+ if (delegate_) {
+ delegate_->OnRemoteReset();
+ }
}
void P2PQuicStreamImpl::OnClose() {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h
index f4553acd8f5..2af3a5f45db 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h
@@ -11,13 +11,17 @@
namespace blink {
-class MODULES_EXPORT P2PQuicStreamImpl final : public P2PQuicStream,
- public quic::QuicStream {
+class MODULES_EXPORT P2PQuicStreamImpl final : public quic::QuicStream,
+ public P2PQuicStream {
public:
P2PQuicStreamImpl(quic::QuicStreamId id,
quic::QuicSession* session,
uint32_t delegate_read_buffer_size,
uint32_t write_buffer_size);
+ P2PQuicStreamImpl(quic::PendingStream pending,
+ quic::QuicSession* session,
+ uint32_t delegate_read_buffer_size,
+ uint32_t write_buffer_size);
~P2PQuicStreamImpl() override;
// P2PQuicStream overrides
void SetDelegate(P2PQuicStream::Delegate* delegate) override;
@@ -63,7 +67,7 @@ class MODULES_EXPORT P2PQuicStreamImpl final : public P2PQuicStream,
private:
using quic::QuicStream::Reset;
- // Outlives the P2PQuicStreamImpl.
+ // Must either outlive the P2PQuicStream or unset itself upon destruction.
Delegate* delegate_;
// The read buffer size of the delegate. The |delegate_read_buffered_amount_|
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
index 0a36ce345dc..d3c03c73186 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
@@ -439,4 +439,64 @@ TEST_F(P2PQuicStreamTest, StreamReceivesMoreDataThanDelegateReadBufferSize) {
// Just the last data received ("ta") is held in the delegate's read buffer.
EXPECT_EQ(2u, stream_->DelegateReadBufferedAmountForTesting());
}
+
+// Tests that after a delegate unsets itself, it will no longer receive the
+// OnWriteDataConsumed callback.
+TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnWriteDataConsumed) {
+ InitializeStream();
+ stream_->SetDelegate(nullptr);
+ // Mock out the QuicSession to get the QuicStream::OnStreamDataConsumed
+ // callback to fire.
+ EXPECT_CALL(session_,
+ WritevData(stream_, kStreamId,
+ /*write_length=*/base::size(kSomeData), _, _))
+ .WillOnce(Invoke([](quic::QuicStream* stream, quic::QuicStreamId id,
+ size_t write_length, quic::QuicStreamOffset offset,
+ quic::StreamSendingState state) {
+ return quic::QuicConsumedData(
+ write_length, state != quic::StreamSendingState::NO_FIN);
+ }));
+
+ EXPECT_CALL(delegate_, OnWriteDataConsumed(_)).Times(0);
+
+ stream_->WriteData(VectorFromArray(kSomeData), /*fin=*/false);
+}
+
+// Tests that after a delegate unsets itself, it will no longer receive the
+// OnRemoteReset callback.
+TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnRemoteReset) {
+ InitializeStream();
+ stream_->SetDelegate(nullptr);
+ EXPECT_CALL(delegate_, OnRemoteReset()).Times(0);
+
+ quic::QuicRstStreamFrame rst_frame(quic::kInvalidControlFrameId, kStreamId,
+ quic::QUIC_STREAM_CANCELLED, 0);
+ stream_->OnStreamReset(rst_frame);
+}
+
+// Tests that after a delegate unsets itself, it will no longer receive the
+// OnDataReceived callback when receiving a stream frame with data and no FIN
+// bit.
+TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnDataReceivedWithData) {
+ InitializeStream();
+ stream_->SetDelegate(nullptr);
+
+ EXPECT_CALL(delegate_, OnDataReceived(_, _)).Times(0);
+
+ quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
+ StringPieceFromArray(kSomeData));
+ stream_->OnStreamFrame(stream_frame);
+}
+
+// Tests that after a delegate unsets itself, it will no longer receive the
+// OnDataReceived callback when receiving a stream frame with the FIN bit.
+TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnDataReceivedWithFin) {
+ InitializeStream();
+ stream_->SetDelegate(nullptr);
+
+ EXPECT_CALL(delegate_, OnDataReceived(_, _)).Times(0);
+
+ quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/true, 0, {});
+ stream_->OnStreamFrame(stream_frame);
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h
index ace4820ebcf..2aad93675c8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h
@@ -5,7 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_
-#include "third_party/webrtc/rtc_base/sslfingerprint.h"
+#include "base/logging.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
+#include "third_party/webrtc/rtc_base/ssl_fingerprint.h"
namespace blink {
@@ -21,6 +23,28 @@ class P2PQuicStream;
// This object should be run entirely on the webrtc worker thread.
class P2PQuicTransport {
public:
+ // A config used when starting the QUIC handshake.
+ struct StartConfig final {
+ explicit StartConfig(std::vector<std::unique_ptr<rtc::SSLFingerprint>>
+ remote_fingerprints_in)
+ : remote_fingerprints(std::move(remote_fingerprints_in)) {
+ DCHECK_GT(remote_fingerprints.size(), 0u);
+ }
+
+ explicit StartConfig(const std::string pre_shared_key_in)
+ : pre_shared_key(pre_shared_key_in) {
+ DCHECK(!pre_shared_key.empty());
+ }
+
+ // These fingerprints are used to verify the self signed remote certificate
+ // used in the QUIC handshake. See:
+ // https://w3c.github.io/webrtc-quic/#quic-transport*
+ std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints;
+
+ // The pre shared key to be used in the handshake.
+ const std::string pre_shared_key;
+ };
+
// Used for receiving callbacks from the P2PQuicTransport regarding QUIC
// connection changes, handshake success/failures and new QuicStreams being
// added from the remote side.
@@ -51,15 +75,13 @@ class P2PQuicTransport {
// Closes the QuicConnection and sends a close frame to the remote side.
// This will trigger P2PQuicTransport::Delegate::OnRemoteClosed() on the
- // remote side.
+ // remote side. This must not be called before Start().
virtual void Stop() = 0;
- // Starts the QUIC handshake negotiation and sets the remote fingerprints
- // that were signaled through a secure channel. These fingerprints are used to
- // verify the self signed remote certificate used in the QUIC handshake. See:
- // https://w3c.github.io/webrtc-quic/#quic-transport*
- virtual void Start(std::vector<std::unique_ptr<rtc::SSLFingerprint>>
- remote_fingerprints) = 0;
+ // Starts the QUIC handshake negotiation. If this is a client perspective
+ // this means initiating the QUIC handshake with a CHLO, while for
+ // a server perspective this means now listening and responding to a CHLO.
+ virtual void Start(StartConfig config) = 0;
// Creates a new outgoing stream. This stream is owned by the
// P2PQuicTransport. Its lifetime is managed by the P2PQuicTransport,
@@ -69,6 +91,9 @@ class P2PQuicTransport {
// - The P2PQuicTransport is deleted.
virtual P2PQuicStream* CreateStream() = 0;
+ // Gets the associated stats. These are QUIC connection level stats.
+ virtual P2PQuicTransportStats GetStats() const = 0;
+
// TODO(https://crbug.com/874296): Consider adding a getter for the
// local fingerprints of the certificate(s) set in the constructor.
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h
index 1d9b695c330..ee49af3b176 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h
@@ -8,8 +8,8 @@
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/webrtc/rtc_base/rtccertificate.h"
-#include "third_party/webrtc/rtc_base/scoped_ref_ptr.h"
+#include "third_party/webrtc/api/scoped_refptr.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate.h"
namespace blink {
@@ -28,7 +28,6 @@ struct P2PQuicTransportConfig final {
certificates(certificates_in),
stream_delegate_read_buffer_size(stream_delegate_read_buffer_size_in),
stream_write_buffer_size(stream_write_buffer_size_in) {
- DCHECK_GT(certificates.size(), 0u);
DCHECK_GT(stream_delegate_read_buffer_size, 0u);
DCHECK_GT(stream_write_buffer_size, 0u);
}
@@ -37,11 +36,9 @@ struct P2PQuicTransportConfig final {
quic::Perspective perspective;
// The certificates are owned by the P2PQuicTransport. These come from
// blink::RTCCertificates: https://www.w3.org/TR/webrtc/#dom-rtccertificate
+ // This can be empty if pre shared keys are being used to establish a
+ // connection.
const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates;
- // When set to true the P2PQuicTransport will immediately be able
- // to listen and respond to a crypto handshake upon construction.
- // This will NOT start a handshake.
- bool can_respond_to_crypto_handshake = true;
// The amount that the delegate can store in its read buffer. This is a
// mandatory field that must be set to ensure that the
// P2PQuicStream::Delegate will not give the delegate more data than it can
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc
index 532871719bd..b08d86f373e 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc
@@ -3,156 +3,15 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h"
+#include "net/third_party/quic/core/quic_connection_id.h"
#include "net/third_party/quic/core/quic_packet_writer.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
-#include "third_party/webrtc/rtc_base/rtccertificate.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate.h"
namespace blink {
-namespace {
-
-// The P2PQuicPacketWriter is a private helper class that implements the
-// QuicPacketWriter using a P2PQuicPacketTransport. This allows us to
-// connect our own packet transport for writing into the QuicConnection.
-// The normal case is using an ICE transport (packet_transport) for writing.
-class P2PQuicPacketWriter : public quic::QuicPacketWriter,
- public P2PQuicPacketTransport::WriteObserver {
- public:
- P2PQuicPacketWriter(P2PQuicPacketTransport* packet_transport)
- : packet_transport_(packet_transport) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(packet_transport_);
- packet_transport_->SetWriteObserver(this);
- }
-
- // This way the packet transport knows it no longer has a write observer and
- // can DCHECK this on destruction.
- ~P2PQuicPacketWriter() override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- packet_transport_->SetWriteObserver(nullptr);
- }
-
- // Sets the QuicConnection (which owns this packet writer). This allows us
- // to get the packet numbers of QUIC packets we write. The QuicConnection
- // is created with a quic::QuicPacketWriter, so we can't set the connection
- // in the constructor.
- void InitializeWithQuicConnection(quic::QuicConnection* connection) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(connection);
- if (packet_transport_->Writable()) {
- SetWritable();
- }
- connection_ = connection;
- }
-
- // quic::QuicPacketWriter overrides.
-
- // Writes a QUIC packet to the network with the packet number as additional
- // packet info.
- quic::WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const quic::QuicIpAddress& self_address,
- const quic::QuicSocketAddress& peer_address,
- quic::PerPacketOptions* options) override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(connection_);
- if (IsWriteBlocked()) {
- return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK);
- }
-
- P2PQuicPacketTransport::QuicPacket packet;
- packet.packet_number = connection_->packet_generator().packet_number();
- packet.buffer = buffer;
- packet.buf_len = buf_len;
- int bytes_written = packet_transport_->WritePacket(packet);
- if (bytes_written <= 0) {
- writable_ = false;
- return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK);
- }
- return quic::WriteResult(quic::WRITE_STATUS_OK, bytes_written);
- }
-
- bool IsWriteBlockedDataBuffered() const override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return false;
- }
-
- bool IsWriteBlocked() const override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return !writable_;
- }
-
- quic::QuicByteCount GetMaxPacketSize(
- const quic::QuicSocketAddress& peer_address) const override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // This can be configured later.
- return 1200;
- }
-
- void SetWritable() override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- writable_ = true;
- }
-
- bool SupportsReleaseTime() const override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return false;
- }
-
- bool IsBatchMode() const override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return false;
- }
-
- char* GetNextWriteLocation(
- const quic::QuicIpAddress& self_address,
- const quic::QuicSocketAddress& peer_address) override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return nullptr;
- }
-
- quic::WriteResult Flush() override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return quic::WriteResult(quic::WRITE_STATUS_OK, 0);
- }
-
- // P2PQuicPacketTransport::WriteDelegate override.
- void OnCanWrite() override {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- SetWritable();
- connection_->OnCanWrite();
- }
-
- private:
- // The packet transport is owned by the P2PQuicSession, not the
- // BlinkPacketWriter.
- P2PQuicPacketTransport* packet_transport_;
- // The QuicConnection owns this packet writer and will outlive it.
- quic::QuicConnection* connection_;
-
- bool writable_ = false;
- THREAD_CHECKER(thread_checker_);
-};
-
-// Creates the QuicConnection for the QuicSession. Currently this connection
-// uses a dummy address and ID. The |packet_writer| is a basic implementation
-// using the QuicTransportConfig::packet_transport for writing. The |helper|
-// and |alarm_factory| should be chromium specific implementations.
-std::unique_ptr<quic::QuicConnection> CreateQuicConnection(
- quic::Perspective perspective,
- quic::QuicConnectionHelperInterface* helper,
- quic::QuicPacketWriter* packet_writer,
- quic::QuicAlarmFactory* alarm_factory) {
- quic::QuicIpAddress ip;
- ip.FromString("0.0.0.0");
- quic::QuicSocketAddress dummy_address(ip, 0 /* Port */);
- return std::make_unique<quic::QuicConnection>(
- 0 /* dummy ID */, dummy_address, helper, alarm_factory, packet_writer,
- /* owns_writer */ true, perspective, quic::CurrentSupportedVersions());
-}
-} // namespace
-
P2PQuicTransportFactoryImpl::P2PQuicTransportFactoryImpl(
quic::QuicClock* clock,
std::unique_ptr<quic::QuicAlarmFactory> alarm_factory)
@@ -172,24 +31,9 @@ P2PQuicTransportFactoryImpl::CreateQuicTransport(
DCHECK(packet_transport);
quic::QuicRandom* quic_random = quic::QuicRandom::GetInstance();
- // The P2PQuicSession owns these chromium specific objects required
- // by the QuicConnection. These outlive the QuicConnection itself.
- std::unique_ptr<net::QuicChromiumConnectionHelper> helper =
- std::make_unique<net::QuicChromiumConnectionHelper>(clock_, quic_random);
-
- P2PQuicPacketWriter* packet_writer =
- new P2PQuicPacketWriter(packet_transport);
- std::unique_ptr<quic::QuicConnection> quic_connection = CreateQuicConnection(
- config.perspective, helper.get(), packet_writer, alarm_factory_.get());
- // It's okay for the quic::QuicConnection to have a P2PQuicPacketWriter before
- // the P2PQuicPacketWriter is initialized, because the P2QuicPacketWriter
- // won't be writable until this occurs.
- packet_writer->InitializeWithQuicConnection(quic_connection.get());
-
- // QUIC configurations for the session are specified here.
- quic::QuicConfig quic_config;
- return std::make_unique<P2PQuicTransportImpl>(
- delegate, packet_transport, std::move(config), std::move(helper),
- std::move(quic_connection), quic_config, clock_);
+ return P2PQuicTransportImpl::Create(
+ clock_, alarm_factory_.get(), quic_random, delegate, packet_transport,
+ std::move(config),
+ std::make_unique<P2PQuicCryptoConfigFactoryImpl>(quic_random));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc
index 47c2b2ceebc..a7622f32d01 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc
@@ -4,9 +4,9 @@
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/third_party/quic/core/crypto/proof_source.h"
#include "net/third_party/quic/core/crypto/quic_random.h"
#include "net/third_party/quic/core/quic_config.h"
+#include "net/third_party/quic/core/quic_utils.h"
#include "net/third_party/quic/core/tls_client_handshaker.h"
#include "net/third_party/quic/core/tls_server_handshaker.h"
#include "net/third_party/quic/tools/quic_simple_crypto_server_stream_helper.h"
@@ -18,94 +18,159 @@ namespace {
static const char kClosingDetails[] = "Application closed connection.";
static const size_t kHostnameLength = 32;
-// TODO(https://crbug.com/874300): Create a secure connection by implementing a
-// P2PProofSource and P2PProofVerifier and remove these once the TLS 1.3
-// handshake is implemented for QUIC. This will allow us to verify for both the
-// server and client:
-// - The self signed certificate fingerprint matches the remote
-// fingerprint that was signaled.
-// - The peer owns the certificate, by verifying the signature of the hash of
-// the handshake context.
-//
-// Used by QuicCryptoServerConfig to provide dummy proof credentials
-// (taken from quic/quartc).
-class DummyProofSource : public quic::ProofSource {
+// QUIC's default is 100. Setting this value to 10000 allows room for QUIC to
+// not refuse new incoming streams in the case that an application wants to send
+// a small chunk of data per stream (and immediately close) unreliably.
+uint32_t kMaxIncomingDynamicStreams = 10000;
+
+// The P2PQuicPacketWriter is a private helper class that implements the
+// QuicPacketWriter using a P2PQuicPacketTransport. This allows us to
+// connect our own packet transport for writing into the QuicConnection.
+// The normal case is using an ICE transport (packet_transport) for writing.
+class P2PQuicPacketWriter : public quic::QuicPacketWriter,
+ public P2PQuicPacketTransport::WriteObserver {
public:
- DummyProofSource() {}
- ~DummyProofSource() override {}
-
- // ProofSource override.
- void GetProof(const quic::QuicSocketAddress& server_addr,
- const quic::QuicString& hostname,
- const quic::QuicString& server_config,
- quic::QuicTransportVersion transport_version,
- quic::QuicStringPiece chlo_hash,
- std::unique_ptr<Callback> callback) override {
- quic::QuicReferenceCountedPointer<ProofSource::Chain> chain;
- quic::QuicCryptoProof proof;
- std::vector<quic::QuicString> certs;
- certs.push_back("Dummy cert");
- chain = new ProofSource::Chain(certs);
- proof.signature = "Dummy signature";
- proof.leaf_cert_scts = "Dummy timestamp";
- callback->Run(true, chain, proof, nullptr /* details */);
+ P2PQuicPacketWriter(P2PQuicPacketTransport* packet_transport)
+ : packet_transport_(packet_transport) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(packet_transport_);
+ packet_transport_->SetWriteObserver(this);
}
- quic::QuicReferenceCountedPointer<Chain> GetCertChain(
- const quic::QuicSocketAddress& server_address,
- const quic::QuicString& hostname) override {
- return quic::QuicReferenceCountedPointer<Chain>();
+ // This way the packet transport knows it no longer has a write observer and
+ // can DCHECK this on destruction.
+ ~P2PQuicPacketWriter() override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ packet_transport_->SetWriteObserver(nullptr);
}
- void ComputeTlsSignature(
- const quic::QuicSocketAddress& server_address,
- const quic::QuicString& hostname,
- uint16_t signature_algorithm,
- quic::QuicStringPiece in,
- std::unique_ptr<SignatureCallback> callback) override {
- callback->Run(true, "Dummy signature");
+ // Sets the QuicConnection (which owns this packet writer). This allows us
+ // to get the packet numbers of QUIC packets we write. The QuicConnection
+ // is created with a quic::QuicPacketWriter, so we can't set the connection
+ // in the constructor.
+ void InitializeWithQuicConnection(quic::QuicConnection* connection) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(connection);
+ if (packet_transport_->Writable()) {
+ SetWritable();
+ }
+ connection_ = connection;
}
-};
-// Used by QuicCryptoClientConfig to ignore the peer's credentials
-// and establish an insecure QUIC connection (taken from quic/quartc).
-class InsecureProofVerifier : public quic::ProofVerifier {
- public:
- InsecureProofVerifier() {}
- ~InsecureProofVerifier() override {}
-
- // ProofVerifier override.
- quic::QuicAsyncStatus VerifyProof(
- const quic::QuicString& hostname,
- const uint16_t port,
- const quic::QuicString& server_config,
- quic::QuicTransportVersion transport_version,
- quic::QuicStringPiece chlo_hash,
- const std::vector<quic::QuicString>& certs,
- const quic::QuicString& cert_sct,
- const quic::QuicString& signature,
- const quic::ProofVerifyContext* context,
- quic::QuicString* error_details,
- std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
- std::unique_ptr<quic::ProofVerifierCallback> callback) override {
- return quic::QUIC_SUCCESS;
+ // quic::QuicPacketWriter overrides.
+
+ // Writes a QUIC packet to the network with the packet number as additional
+ // packet info.
+ quic::WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const quic::QuicIpAddress& self_address,
+ const quic::QuicSocketAddress& peer_address,
+ quic::PerPacketOptions* options) override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(connection_);
+ if (IsWriteBlocked()) {
+ return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK);
+ }
+
+ P2PQuicPacketTransport::QuicPacket packet;
+ packet.packet_number = connection_->packet_generator().packet_number();
+ packet.buffer = buffer;
+ packet.buf_len = buf_len;
+ int bytes_written = packet_transport_->WritePacket(packet);
+ if (bytes_written <= 0) {
+ writable_ = false;
+ return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK);
+ }
+ return quic::WriteResult(quic::WRITE_STATUS_OK, bytes_written);
+ }
+
+ bool IsWriteBlockedDataBuffered() const override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return false;
+ }
+
+ bool IsWriteBlocked() const override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return !writable_;
}
- quic::QuicAsyncStatus VerifyCertChain(
- const quic::QuicString& hostname,
- const std::vector<quic::QuicString>& certs,
- const quic::ProofVerifyContext* context,
- quic::QuicString* error_details,
- std::unique_ptr<quic::ProofVerifyDetails>* details,
- std::unique_ptr<quic::ProofVerifierCallback> callback) override {
- return quic::QUIC_SUCCESS;
+ quic::QuicByteCount GetMaxPacketSize(
+ const quic::QuicSocketAddress& peer_address) const override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ // This can be configured later.
+ return 1200;
}
- std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override {
+ void SetWritable() override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ writable_ = true;
+ }
+
+ bool SupportsReleaseTime() const override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return false;
+ }
+
+ bool IsBatchMode() const override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return false;
+ }
+
+ char* GetNextWriteLocation(
+ const quic::QuicIpAddress& self_address,
+ const quic::QuicSocketAddress& peer_address) override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return nullptr;
}
+
+ quic::WriteResult Flush() override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return quic::WriteResult(quic::WRITE_STATUS_OK, 0);
+ }
+
+ // P2PQuicPacketTransport::WriteDelegate override.
+ void OnCanWrite() override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ SetWritable();
+ connection_->OnCanWrite();
+ }
+
+ private:
+ // The packet transport is owned by the P2PQuicSession, not the
+ // BlinkPacketWriter.
+ P2PQuicPacketTransport* packet_transport_;
+ // The QuicConnection owns this packet writer and will outlive it.
+ quic::QuicConnection* connection_;
+
+ bool writable_ = false;
+ THREAD_CHECKER(thread_checker_);
};
+// Creates the QuicConnection for the QuicSession. Currently this connection
+// uses a dummy address and ID. The |packet_writer| is a basic implementation
+// using the QuicTransportConfig::packet_transport for writing. The |helper|
+// and |alarm_factory| should be chromium specific implementations.
+std::unique_ptr<quic::QuicConnection> CreateQuicConnection(
+ quic::Perspective perspective,
+ quic::QuicConnectionHelperInterface* helper,
+ quic::QuicPacketWriter* packet_writer,
+ quic::QuicAlarmFactory* alarm_factory) {
+ quic::QuicIpAddress ip;
+ ip.FromString("0.0.0.0");
+ quic::QuicSocketAddress dummy_address(ip, 0 /* Port */);
+ quic::QuicConnectionId dummy_connection_id;
+ if (GetQuicRestartFlag(quic_variable_length_connection_ids_client)) {
+ char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ dummy_connection_id = quic::QuicConnectionId(connection_id_bytes,
+ sizeof(connection_id_bytes));
+ } else {
+ dummy_connection_id = quic::EmptyQuicConnectionId();
+ }
+ return std::make_unique<quic::QuicConnection>(
+ dummy_connection_id, dummy_address, helper, alarm_factory, packet_writer,
+ /* owns_writer */ true, perspective, quic::CurrentSupportedVersions());
+}
+
// A dummy helper for a server crypto stream that accepts all client hellos
// and generates a random connection ID.
class DummyCryptoServerStreamHelper
@@ -117,7 +182,7 @@ class DummyCryptoServerStreamHelper
quic::QuicConnectionId GenerateConnectionIdForReject(
quic::QuicConnectionId connection_id) const override {
- return random_->RandUint64();
+ return quic::QuicUtils::CreateRandomConnectionId(random_);
}
bool CanAcceptClientHello(const quic::CryptoHandshakeMessage& message,
@@ -134,6 +199,56 @@ class DummyCryptoServerStreamHelper
};
} // namespace
+std::unique_ptr<P2PQuicTransportImpl> P2PQuicTransportImpl::Create(
+ quic::QuicClock* clock,
+ quic::QuicAlarmFactory* alarm_factory,
+ quic::QuicRandom* quic_random,
+ P2PQuicTransport::Delegate* delegate,
+ P2PQuicPacketTransport* packet_transport,
+ const P2PQuicTransportConfig& config,
+ std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory) {
+ DCHECK(delegate);
+ DCHECK(packet_transport);
+ DCHECK(crypto_config_factory);
+
+ // The P2PQuicSession owns these chromium specific objects required
+ // by the QuicConnection. These outlive the QuicConnection itself.
+ std::unique_ptr<net::QuicChromiumConnectionHelper> helper =
+ std::make_unique<net::QuicChromiumConnectionHelper>(clock, quic_random);
+
+ P2PQuicPacketWriter* packet_writer =
+ new P2PQuicPacketWriter(packet_transport);
+ std::unique_ptr<quic::QuicConnection> quic_connection = CreateQuicConnection(
+ config.perspective, helper.get(), packet_writer, alarm_factory);
+ // It's okay for the quic::QuicConnection to have a P2PQuicPacketWriter before
+ // the P2PQuicPacketWriter is initialized, because the P2QuicPacketWriter
+ // won't be writable until this occurs.
+ packet_writer->InitializeWithQuicConnection(quic_connection.get());
+
+ // QUIC configurations for the session are specified here.
+ // TODO(shampson): Consider setting larger initial flow control window sizes
+ // so that the default limit doesn't cause initial undersending.
+ quic::QuicConfig quic_config;
+ quic_config.SetMaxIncomingDynamicStreamsToSend(kMaxIncomingDynamicStreams);
+ // The handshake network timeouts are configured to large values to prevent
+ // the QUIC connection from being closed on a slow connection. This can occur
+ // if signaling is slow and one side begins the handshake early.
+ // See ICE related bug: bugs.webrtc.org/9869.
+ //
+ // This timeout is from time of creation of the quic::QuicConnection object to
+ // the completion of the handshake. It must be larger than the idle time.
+ quic_config.set_max_time_before_crypto_handshake(
+ quic::QuicTime::Delta::FromSeconds(50));
+ // This is the timeout for idle time in the handshake. This value allows
+ // time for slow signaling to complete.
+ quic_config.set_max_idle_time_before_crypto_handshake(
+ quic::QuicTime::Delta::FromSeconds(30));
+ return std::make_unique<P2PQuicTransportImpl>(
+ delegate, packet_transport, std::move(config), std::move(helper),
+ std::move(quic_connection), quic_config, std::move(crypto_config_factory),
+ clock);
+}
+
P2PQuicTransportImpl::P2PQuicTransportImpl(
Delegate* delegate,
P2PQuicPacketTransport* packet_transport,
@@ -141,6 +256,7 @@ P2PQuicTransportImpl::P2PQuicTransportImpl(
std::unique_ptr<net::QuicChromiumConnectionHelper> helper,
std::unique_ptr<quic::QuicConnection> connection,
const quic::QuicConfig& quic_config,
+ std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory,
quic::QuicClock* clock)
: quic::QuicSession(connection.get(),
nullptr /* visitor */,
@@ -148,6 +264,7 @@ P2PQuicTransportImpl::P2PQuicTransportImpl(
quic::CurrentSupportedVersions()),
helper_(std::move(helper)),
connection_(std::move(connection)),
+ crypto_config_factory_(std::move(crypto_config_factory)),
perspective_(p2p_transport_config.perspective),
packet_transport_(packet_transport),
delegate_(delegate),
@@ -157,18 +274,32 @@ P2PQuicTransportImpl::P2PQuicTransportImpl(
stream_write_buffer_size_(p2p_transport_config.stream_write_buffer_size) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(delegate_);
+ DCHECK(crypto_config_factory_);
DCHECK(clock_);
DCHECK(packet_transport_);
DCHECK_GT(stream_delegate_read_buffer_size_, 0u);
DCHECK_GT(stream_write_buffer_size_, 0u);
- DCHECK_GT(p2p_transport_config.certificates.size(), 0u);
- if (p2p_transport_config.can_respond_to_crypto_handshake) {
- InitializeCryptoStream();
+ if (!p2p_transport_config.certificates.empty()) {
+ // TODO(https://crbug.com/874296): The web API accepts multiple
+ // certificates, and we might want to pass these down to let QUIC decide on
+ // what to use.
+ certificate_ = p2p_transport_config.certificates[0];
+ }
+ switch (perspective_) {
+ case quic::Perspective::IS_CLIENT: {
+ crypto_client_config_ =
+ crypto_config_factory_->CreateClientCryptoConfig();
+ break;
+ }
+ case quic::Perspective::IS_SERVER: {
+ crypto_server_config_ =
+ crypto_config_factory_->CreateServerCryptoConfig();
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
}
- // TODO(https://crbug.com/874296): The web API accepts multiple certificates,
- // and we might want to pass these down to let QUIC decide on what to use.
- certificate_ = p2p_transport_config.certificates[0];
- packet_transport_->SetReceiveDelegate(this);
}
P2PQuicTransportImpl::~P2PQuicTransportImpl() {
@@ -176,6 +307,8 @@ P2PQuicTransportImpl::~P2PQuicTransportImpl() {
}
void P2PQuicTransportImpl::Stop() {
+ // This shouldn't be called before Start().
+ DCHECK(crypto_stream_);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (IsClosed()) {
return;
@@ -189,23 +322,38 @@ void P2PQuicTransportImpl::Stop() {
quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
-void P2PQuicTransportImpl::Start(
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints) {
+void P2PQuicTransportImpl::Start(StartConfig config) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK_EQ(remote_fingerprints_.size(), 0u);
- DCHECK_GT(remote_fingerprints.size(), 0u);
- if (IsClosed()) {
- // We could have received a close from the remote side before calling this.
- return;
+ // Either the remote fingerprints are being verified or a pre shared key is
+ // set.
+ DCHECK((certificate_ && !config.remote_fingerprints.empty()) ||
+ !config.pre_shared_key.empty());
+ DCHECK(!crypto_stream_);
+
+ remote_fingerprints_ = std::move(config.remote_fingerprints);
+ switch (perspective_) {
+ case quic::Perspective::IS_CLIENT: {
+ crypto_client_config_->set_pre_shared_key(config.pre_shared_key);
+ break;
+ }
+ case quic::Perspective::IS_SERVER: {
+ crypto_server_config_->set_pre_shared_key(config.pre_shared_key);
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
}
- // These will be used to verify the remote certificate during the handshake.
- remote_fingerprints_ = std::move(remote_fingerprints);
+
+ InitializeCryptoStream();
if (perspective_ == quic::Perspective::IS_CLIENT) {
quic::QuicCryptoClientStream* client_crypto_stream =
static_cast<quic::QuicCryptoClientStream*>(crypto_stream_.get());
client_crypto_stream->CryptoConnect();
}
+ // Now that crypto streams are setup we are ready to receive QUIC packets.
+ packet_transport_->SetReceiveDelegate(this);
}
void P2PQuicTransportImpl::OnPacketDataReceived(const char* data,
@@ -233,9 +381,17 @@ P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStream() {
return CreateOutgoingBidirectionalStream();
}
+P2PQuicTransportStats P2PQuicTransportImpl::GetStats() const {
+ return P2PQuicTransportStats(connection_->GetStats(),
+ num_outgoing_streams_created_,
+ num_incoming_streams_created_);
+}
+
P2PQuicStreamImpl* P2PQuicTransportImpl::CreateOutgoingBidirectionalStream() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- P2PQuicStreamImpl* stream = CreateStreamInternal(GetNextOutgoingStreamId());
+ num_outgoing_streams_created_++;
+ P2PQuicStreamImpl* stream =
+ CreateStreamInternal(GetNextOutgoingBidirectionalStreamId());
ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream));
return stream;
}
@@ -243,12 +399,23 @@ P2PQuicStreamImpl* P2PQuicTransportImpl::CreateOutgoingBidirectionalStream() {
P2PQuicStreamImpl* P2PQuicTransportImpl::CreateIncomingStream(
quic::QuicStreamId id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ num_incoming_streams_created_++;
P2PQuicStreamImpl* stream = CreateStreamInternal(id);
ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream));
delegate_->OnStream(stream);
return stream;
}
+P2PQuicStreamImpl* P2PQuicTransportImpl::CreateIncomingStream(
+ quic::PendingStream pending) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ num_incoming_streams_created_++;
+ P2PQuicStreamImpl* stream = CreateStreamInternal(std::move(pending));
+ ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream));
+ delegate_->OnStream(stream);
+ return stream;
+}
+
P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStreamInternal(
quic::QuicStreamId id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -259,19 +426,26 @@ P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStreamInternal(
stream_write_buffer_size_);
}
+P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStreamInternal(
+ quic::PendingStream pending) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(crypto_stream_);
+ DCHECK(IsEncryptionEstablished());
+ DCHECK(!IsClosed());
+ return new P2PQuicStreamImpl(std::move(pending), this,
+ stream_delegate_read_buffer_size_,
+ stream_write_buffer_size_);
+}
+
void P2PQuicTransportImpl::InitializeCryptoStream() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!crypto_stream_);
+ // TODO(shampson): If the P2PQuicTransportImpl is subclassed into a client
+ // and server class we can call this as a virtual function and not need this
+ // switch statement.
switch (perspective_) {
case quic::Perspective::IS_CLIENT: {
- if (!crypto_client_config_) {
- // The |crypto_client_config_| has not already been set (by the test).
- std::unique_ptr<quic::ProofVerifier> proof_verifier(
- new InsecureProofVerifier);
- crypto_client_config_ = std::make_unique<quic::QuicCryptoClientConfig>(
- std::move(proof_verifier),
- quic::TlsClientHandshaker::CreateSslCtx());
- }
+ DCHECK(crypto_client_config_);
// The host must be unique for every endpoint the client communicates
// with.
char random_hostname[kHostnameLength];
@@ -289,11 +463,7 @@ void P2PQuicTransportImpl::InitializeCryptoStream() {
break;
}
case quic::Perspective::IS_SERVER: {
- std::unique_ptr<quic::ProofSource> proof_source(new DummyProofSource);
- crypto_server_config_ = std::make_unique<quic::QuicCryptoServerConfig>(
- quic::QuicCryptoServerConfig::TESTING, helper_->GetRandomGenerator(),
- std::move(proof_source), quic::KeyExchangeSource::Default(),
- quic::TlsServerHandshaker::CreateSslCtx());
+ DCHECK(crypto_server_config_);
// Provide server with serialized config string to prove ownership.
quic::QuicCryptoServerConfig::ConfigOptions options;
// The |message| is used to handle the return value of AddDefaultConfig
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h
index 4eeeaee9930..7b20ed065ed 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h
@@ -15,11 +15,12 @@
#include "net/third_party/quic/core/quic_session.h"
#include "net/third_party/quic/tools/quic_simple_crypto_server_stream_helper.h"
#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/webrtc/rtc_base/rtccertificate.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate.h"
namespace blink {
@@ -43,6 +44,17 @@ class MODULES_EXPORT P2PQuicTransportImpl final
public P2PQuicPacketTransport::ReceiveDelegate,
public quic::QuicCryptoClientStream::ProofHandler {
public:
+ // Creates the necessary QUIC and Chromium specific objects before
+ // creating P2PQuicTransportImpl.
+ static std::unique_ptr<P2PQuicTransportImpl> Create(
+ quic::QuicClock* clock,
+ quic::QuicAlarmFactory* alarm_factory,
+ quic::QuicRandom* quic_random,
+ Delegate* delegate,
+ P2PQuicPacketTransport* packet_transport,
+ const P2PQuicTransportConfig& config,
+ std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory);
+
P2PQuicTransportImpl(
Delegate* delegate,
P2PQuicPacketTransport* packet_transport,
@@ -50,33 +62,26 @@ class MODULES_EXPORT P2PQuicTransportImpl final
std::unique_ptr<net::QuicChromiumConnectionHelper> helper,
std::unique_ptr<quic::QuicConnection> connection,
const quic::QuicConfig& quic_config,
+ std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory,
quic::QuicClock* clock);
~P2PQuicTransportImpl() override;
// P2PQuicTransport overrides.
-
void Stop() override;
-
- // Sets the remote fingerprints, and if the the P2PQuicTransportImpl is a
- // client starts the QUIC handshake . This handshake is currently insecure,
- // meaning that the certificates used are fake and are not verified. It also
- // assumes a handshake for a server/client case. This must be called before
- // creating any streams.
+ // This handshake is currently insecure in the case of using remote
+ // fingerprints to verify the remote certificate. For a secure handshake, set
+ // the pre_shared_key attribute of the |config| before calling this. This
+ // function must be called before creating any streams.
//
// TODO(https://crbug.com/874300): Verify both the client and server
// certificates with the signaled remote fingerprints. Until the TLS 1.3
// handshake is supported in the QUIC core library we can only verify the
- // server's certificate, but not the client's. Note that this means
- // implementing the handshake for a P2P case, in which case verification
- // completes after both receiving the signaled remote fingerprint and getting
- // a client hello. Because either can come first, a synchronous call to verify
- // the remote fingerprint is not possible.
- void Start(std::vector<std::unique_ptr<rtc::SSLFingerprint>>
- remote_fingerprints) override;
-
+ // server's certificate, but not the client's.
+ void Start(StartConfig config) override;
// Creates an outgoing stream that is owned by the quic::QuicSession.
P2PQuicStreamImpl* CreateStream() override;
+ P2PQuicTransportStats GetStats() const override;
// P2PQuicPacketTransport::Delegate override.
void OnPacketDataReceived(const char* data, size_t data_len) override;
@@ -108,6 +113,7 @@ class MODULES_EXPORT P2PQuicTransportImpl final
// quic::QuicSession.
P2PQuicStreamImpl* CreateIncomingStream(
quic::QuicStreamId id) override;
+ P2PQuicStreamImpl* CreateIncomingStream(quic::PendingStream pending) override;
// Creates a new outgoing stream. The caller does not own the
// stream, so the stream is activated and ownership is moved to the
@@ -142,6 +148,7 @@ class MODULES_EXPORT P2PQuicTransportImpl final
// Creates a new stream. This helper function is used when we need to create
// a new incoming stream or outgoing stream.
P2PQuicStreamImpl* CreateStreamInternal(quic::QuicStreamId id);
+ P2PQuicStreamImpl* CreateStreamInternal(quic::PendingStream pending);
// The server_config and client_config are used for setting up the crypto
// connection. The ownership of these objects or the objects they own
@@ -159,12 +166,17 @@ class MODULES_EXPORT P2PQuicTransportImpl final
std::unique_ptr<quic::QuicConnection> connection_;
+ // Used to create either a crypto client or server config.
+ std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory_;
+
std::unique_ptr<quic::QuicCryptoStream> crypto_stream_;
- // Crypto information. Note that currently the handshake is insecure and these
- // are not used...
+ // Crypto certificate information. Note that currently the handshake is
+ // insecure and these are not used...
rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints_;
+ bool pre_shared_key_set_ = false;
+
quic::Perspective perspective_;
// Outlives the P2PQuicTransport.
P2PQuicPacketTransport* packet_transport_;
@@ -178,6 +190,10 @@ class MODULES_EXPORT P2PQuicTransportImpl final
// Determines the size of the write buffer when P2PQuicStreams.
uint32_t stream_write_buffer_size_;
+ // For stats:
+ uint32_t num_outgoing_streams_created_ = 0;
+ uint32_t num_incoming_streams_created_ = 0;
+
THREAD_CHECKER(thread_checker_);
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc
new file mode 100644
index 00000000000..8e574ed6b8b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
+
+namespace blink {
+
+P2PQuicTransportStats::P2PQuicTransportStats()
+ : timestamp(base::TimeTicks::Now()) {}
+
+P2PQuicTransportStats::P2PQuicTransportStats(
+ const quic::QuicConnectionStats& quic_stats,
+ uint32_t num_outgoing_streams_created,
+ uint32_t num_incoming_streams_created)
+ : timestamp(base::TimeTicks::Now()),
+ bytes_sent(quic_stats.bytes_sent),
+ packets_sent(quic_stats.packets_sent),
+ stream_bytes_sent(quic_stats.stream_bytes_sent),
+ stream_bytes_received(quic_stats.stream_bytes_received),
+ num_outgoing_streams_created(num_outgoing_streams_created),
+ num_incoming_streams_created(num_incoming_streams_created),
+ bytes_received(quic_stats.bytes_received),
+ packets_received(quic_stats.packets_received),
+ packets_processed(quic_stats.packets_processed),
+ bytes_retransmitted(quic_stats.bytes_retransmitted),
+ packets_retransmitted(quic_stats.packets_retransmitted),
+ packets_lost(quic_stats.packets_lost),
+ packets_dropped(quic_stats.packets_dropped),
+ crypto_retransmit_count(quic_stats.crypto_retransmit_count),
+ min_rtt_us(quic_stats.min_rtt_us),
+ srtt_us(quic_stats.srtt_us),
+ max_packet_size(quic_stats.max_packet_size),
+ max_received_packet_size(quic_stats.max_received_packet_size),
+ estimated_bandwidth_bps(quic_stats.estimated_bandwidth.ToBitsPerSecond()),
+ packets_reordered(quic_stats.packets_reordered),
+ blocked_frames_received(quic_stats.blocked_frames_received),
+ blocked_frames_sent(quic_stats.blocked_frames_sent),
+ connectivity_probing_packets_received(
+ quic_stats.num_connectivity_probing_received) {}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h
new file mode 100644
index 00000000000..c8694179c68
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h
@@ -0,0 +1,80 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_STATS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_STATS_H_
+
+#include "base/time/time.h"
+#include "net/third_party/quic/core/quic_connection_stats.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+// These are stats associated with the P2PQuicTransport object. These
+// stats are mostly copied from quic::QuicConnectionStats, which includes
+// stats for a quic::QuicConnection. These are connection level stats.
+// Currently QUIC does not have stats at the stream level.
+struct MODULES_EXPORT P2PQuicTransportStats {
+ P2PQuicTransportStats();
+ // Note: The following stats are ignored form the QuicConnectionStats:
+ // -packets_spuriously_retransmitted
+ // -bytes_spuriously_retransmitted
+ // -slowstart_packets_sent
+ // -slowstart_packets_lost
+ // -slowstart_bytes_lost
+ // -loss_timeout_count
+ // -tlp_count
+ // -rto_count
+ // -max_sequence_reordering
+ // -max_time_reordering_us
+ // -tcp_loss_events
+ // -connection_creation_time
+ explicit P2PQuicTransportStats(const quic::QuicConnectionStats& stats,
+ uint32_t num_outgoing_streams_created,
+ uint32_t num_incoming_streams_created);
+ ~P2PQuicTransportStats() = default;
+
+ base::TimeTicks timestamp;
+ // |bytes_sent| includes retransmissions.
+ uint64_t bytes_sent = 0;
+ uint64_t packets_sent = 0;
+ // |stream_bytes_sent| does not include retransmissions.
+ uint64_t stream_bytes_sent = 0;
+ uint64_t stream_bytes_received = 0;
+ uint32_t num_outgoing_streams_created = 0;
+ uint32_t num_incoming_streams_created = 0;
+
+ // These include version negotiation and public reset packets.
+ //
+ // |bytes_received| includes duplicate data for a stream.
+ uint64_t bytes_received = 0;
+ // |packets_received| includes packets which were not processable.
+ uint64_t packets_received = 0;
+ uint64_t packets_processed = 0;
+
+ uint64_t bytes_retransmitted = 0;
+ uint64_t packets_retransmitted = 0;
+ // Number of packets abandoned as lost by the loss detection algorithm.
+ uint64_t packets_lost = 0;
+ uint64_t packets_dropped = 0;
+ size_t crypto_retransmit_count = 0;
+ // Minimum RTT in microseconds.
+ uint64_t min_rtt_us = 0;
+ // Smoothed RTT in microseconds.
+ uint64_t srtt_us = 0;
+ uint64_t max_packet_size = 0;
+ uint64_t max_received_packet_size = 0;
+ // Bits per second.
+ uint64_t estimated_bandwidth_bps = 0;
+ // Reordering stats for received packets.
+ // Number of packets received out of packet number order.
+ uint64_t packets_reordered = 0;
+ uint64_t blocked_frames_received = 0;
+ uint64_t blocked_frames_sent = 0;
+ // Number of connectivity probing packets received by this connection.
+ uint64_t connectivity_probing_packets_received = 0;
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_STATS_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc
index e126df37213..6ff911afded 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc
@@ -6,15 +6,17 @@
#include "net/quic/test_task_runner.h"
#include "net/test/gtest_util.h"
#include "net/third_party/quic/core/tls_client_handshaker.h"
+#include "net/third_party/quic/core/tls_server_handshaker.h"
#include "net/third_party/quic/test_tools/mock_clock.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_delegate.h"
-#include "third_party/webrtc/rtc_base/rtccertificate.h"
-#include "third_party/webrtc/rtc_base/sslfingerprint.h"
-#include "third_party/webrtc/rtc_base/sslidentity.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate.h"
+#include "third_party/webrtc/rtc_base/ssl_fingerprint.h"
+#include "third_party/webrtc/rtc_base/ssl_identity.h"
namespace blink {
@@ -175,7 +177,7 @@ class FakePacketTransport : public P2PQuicPacketTransport,
delegate_->OnPacketDataReceived(data, data_len);
}
- int last_packet_num() { return last_packet_num_; }
+ uint64_t last_packet_num() { return last_packet_num_; }
private:
// Wraps the FakePacketTransport so that we can pass in a raw pointer that can
@@ -304,10 +306,10 @@ rtc::scoped_refptr<rtc::RTCCertificate> CreateTestCertificate() {
}
// Allows faking a failing handshake.
-class FailingProofVerifier : public quic::ProofVerifier {
+class FailingProofVerifierStub : public quic::ProofVerifier {
public:
- FailingProofVerifier() {}
- ~FailingProofVerifier() override {}
+ FailingProofVerifierStub() {}
+ ~FailingProofVerifierStub() override {}
// ProofVerifier override.
quic::QuicAsyncStatus VerifyProof(
@@ -340,6 +342,70 @@ class FailingProofVerifier : public quic::ProofVerifier {
return nullptr;
}
};
+
+// A dummy implementation of a quic::ProofSource.
+class ProofSourceStub : public quic::ProofSource {
+ public:
+ ProofSourceStub() {}
+ ~ProofSourceStub() override {}
+
+ // ProofSource override.
+ void GetProof(const quic::QuicSocketAddress& server_addr,
+ const quic::QuicString& hostname,
+ const quic::QuicString& server_config,
+ quic::QuicTransportVersion transport_version,
+ quic::QuicStringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override {
+ quic::QuicCryptoProof proof;
+ proof.signature = "Test signature";
+ proof.leaf_cert_scts = "Test timestamp";
+ callback->Run(true, GetCertChain(server_addr, hostname), proof,
+ nullptr /* details */);
+ }
+
+ quic::QuicReferenceCountedPointer<Chain> GetCertChain(
+ const quic::QuicSocketAddress& server_address,
+ const quic::QuicString& hostname) override {
+ std::vector<quic::QuicString> certs;
+ certs.push_back("Test cert");
+ return quic::QuicReferenceCountedPointer<Chain>(
+ new ProofSource::Chain(certs));
+ }
+ void ComputeTlsSignature(
+ const quic::QuicSocketAddress& server_address,
+ const quic::QuicString& hostname,
+ uint16_t signature_algorithm,
+ quic::QuicStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) override {
+ callback->Run(true, "Test signature");
+ }
+};
+
+// Creates crypto configs that will fail a QUIC handshake.
+class FailingQuicCryptoConfigFactory final : public P2PQuicCryptoConfigFactory {
+ public:
+ FailingQuicCryptoConfigFactory(quic::QuicRandom* quic_random)
+ : quic_random_(quic_random) {}
+
+ std::unique_ptr<quic::QuicCryptoClientConfig> CreateClientCryptoConfig()
+ override {
+ return std::make_unique<quic::QuicCryptoClientConfig>(
+ std::make_unique<FailingProofVerifierStub>(),
+ quic::TlsClientHandshaker::CreateSslCtx());
+ }
+
+ std::unique_ptr<quic::QuicCryptoServerConfig> CreateServerCryptoConfig()
+ override {
+ return std::make_unique<quic::QuicCryptoServerConfig>(
+ quic::QuicCryptoServerConfig::TESTING, quic_random_,
+ std::make_unique<ProofSourceStub>(), quic::KeyExchangeSource::Default(),
+ quic::TlsServerHandshaker::CreateSslCtx());
+ }
+
+ private:
+ quic::QuicRandom* quic_random_;
+};
+
} // namespace
// Unit tests for the P2PQuicTransport, using an underlying fake packet
@@ -353,7 +419,14 @@ class FailingProofVerifier : public quic::ProofVerifier {
// callbacks have been fired.
class P2PQuicTransportTest : public testing::Test {
public:
- P2PQuicTransportTest() {}
+ P2PQuicTransportTest() {
+ // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
+ clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(1000));
+ quic_random_ = quic::QuicRandom::GetInstance();
+ runner_ = base::MakeRefCounted<net::test::TestTaskRunner>(&clock_);
+ alarm_factory_ =
+ std::make_unique<net::QuicChromiumAlarmFactory>(runner_.get(), &clock_);
+ }
~P2PQuicTransportTest() override {
// This must be done before desctructing the transports so that we don't
@@ -364,100 +437,75 @@ class P2PQuicTransportTest : public testing::Test {
client_peer_->packet_transport());
}
- // Connects both peer's underlying transports and creates both
- // P2PQuicTransportImpls.
- void Initialize(bool can_respond_to_crypto_handshake = true) {
- // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
- clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(1000));
- runner_ = new net::test::TestTaskRunner(&clock_);
- net::QuicChromiumAlarmFactory* alarm_factory =
- new net::QuicChromiumAlarmFactory(runner_.get(), &clock_);
- quic_transport_factory_ = std::make_unique<P2PQuicTransportFactoryImpl>(
- &clock_, std::unique_ptr<net::QuicChromiumAlarmFactory>(alarm_factory));
-
+ // Supplying the |client_crypto_factory| and |server_crypto_factory| allows
+ // testing a failing QUIC handshake. The |client_certificate| and
+ // |server_certificate| must be the same certificates used in the crypto
+ // factories.
+ void Initialize(
+ std::unique_ptr<P2PQuicCryptoConfigFactory> client_crypto_factory,
+ std::unique_ptr<P2PQuicCryptoConfigFactory> server_crypto_factory) {
auto client_packet_transport =
- std::make_unique<FakePacketTransport>(alarm_factory, &clock_);
+ std::make_unique<FakePacketTransport>(alarm_factory_.get(), &clock_);
auto server_packet_transport =
- std::make_unique<FakePacketTransport>(alarm_factory, &clock_);
+ std::make_unique<FakePacketTransport>(alarm_factory_.get(), &clock_);
// Connect the transports so that they can speak to each other.
client_packet_transport->ConnectPeerTransport(
server_packet_transport.get());
server_packet_transport->ConnectPeerTransport(
client_packet_transport.get());
- rtc::scoped_refptr<rtc::RTCCertificate> client_cert =
- CreateTestCertificate();
+ rtc::scoped_refptr<rtc::RTCCertificate> client_certificate =
+ CreateTestCertificate();
auto client_quic_transport_delegate =
std::make_unique<MockP2PQuicTransportDelegate>();
- std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> client_certificates;
- client_certificates.push_back(client_cert);
P2PQuicTransportConfig client_config(
- quic::Perspective::IS_CLIENT, client_certificates,
+ quic::Perspective::IS_CLIENT, {client_certificate},
kTransportDelegateReadBufferSize, kTransportWriteBufferSize);
- client_config.can_respond_to_crypto_handshake =
- can_respond_to_crypto_handshake;
- // We can't downcast a unique_ptr to an object, so we have to release, cast
- // it, then create a unique_ptr of the downcasted pointer.
- P2PQuicTransportImpl* client_quic_transport_ptr =
- static_cast<P2PQuicTransportImpl*>(
- quic_transport_factory_
- ->CreateQuicTransport(client_quic_transport_delegate.get(),
- client_packet_transport.get(),
- client_config)
- .release());
+
std::unique_ptr<P2PQuicTransportImpl> client_quic_transport =
- std::unique_ptr<P2PQuicTransportImpl>(client_quic_transport_ptr);
+ P2PQuicTransportImpl::Create(
+ &clock_, alarm_factory_.get(), quic_random_,
+ client_quic_transport_delegate.get(), client_packet_transport.get(),
+ client_config, std::move(client_crypto_factory));
+
client_peer_ = std::make_unique<QuicPeerForTest>(
std::move(client_packet_transport),
std::move(client_quic_transport_delegate),
- std::move(client_quic_transport), client_cert);
+ std::move(client_quic_transport), client_certificate);
auto server_quic_transport_delegate =
std::make_unique<MockP2PQuicTransportDelegate>();
- rtc::scoped_refptr<rtc::RTCCertificate> server_cert =
+ rtc::scoped_refptr<rtc::RTCCertificate> server_certificate =
CreateTestCertificate();
- std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> server_certificates;
- server_certificates.push_back(server_cert);
P2PQuicTransportConfig server_config(
- quic::Perspective::IS_SERVER, server_certificates,
+ quic::Perspective::IS_SERVER, {server_certificate},
kTransportDelegateReadBufferSize, kTransportWriteBufferSize);
- server_config.can_respond_to_crypto_handshake =
- can_respond_to_crypto_handshake;
- P2PQuicTransportImpl* server_quic_transport_ptr =
- static_cast<P2PQuicTransportImpl*>(
- quic_transport_factory_
- ->CreateQuicTransport(server_quic_transport_delegate.get(),
- server_packet_transport.get(),
- server_config)
- .release());
+
std::unique_ptr<P2PQuicTransportImpl> server_quic_transport =
- std::unique_ptr<P2PQuicTransportImpl>(server_quic_transport_ptr);
+ P2PQuicTransportImpl::Create(
+ &clock_, alarm_factory_.get(), quic_random_,
+ server_quic_transport_delegate.get(), server_packet_transport.get(),
+ server_config, std::move(server_crypto_factory));
+
server_peer_ = std::make_unique<QuicPeerForTest>(
std::move(server_packet_transport),
std::move(server_quic_transport_delegate),
- std::move(server_quic_transport), server_cert);
+ std::move(server_quic_transport), server_certificate);
+ }
+
+ // Connects both peer's underlying packet transports and creates both
+ // P2PQuicTransportImpls.
+ void Initialize() {
+ Initialize(std::make_unique<P2PQuicCryptoConfigFactoryImpl>(quic_random_),
+ std::make_unique<P2PQuicCryptoConfigFactoryImpl>(quic_random_));
}
- // Sets a FailingProofVerifier to the client transport before initializing
- // the its crypto stream. This allows the client to fail the proof
- // verification step during the crypto handshake.
+ // Uses a crypto config factory that returns a client configuration that
+ // will reject the QUIC handshake. This lets us simulate a failng handshake.
void InitializeWithFailingProofVerification() {
- // Allows us to initialize the crypto streams after constructing the
- // objects.
- Initialize(false);
- // Create the client crypto config and insert it into the client transport.
- std::unique_ptr<quic::ProofVerifier> proof_verifier(
- new FailingProofVerifier);
- std::unique_ptr<quic::QuicCryptoClientConfig> crypto_client_config =
- std::make_unique<quic::QuicCryptoClientConfig>(
- std::move(proof_verifier),
- quic::TlsClientHandshaker::CreateSslCtx());
- client_peer_->quic_transport()->set_crypto_client_config(
- std::move(crypto_client_config));
- // Now initialize the crypto streams.
- client_peer_->quic_transport()->InitializeCryptoStream();
- server_peer_->quic_transport()->InitializeCryptoStream();
+ Initialize(std::make_unique<FailingQuicCryptoConfigFactory>(quic_random_),
+ std::make_unique<FailingQuicCryptoConfigFactory>(quic_random_));
}
// Drives the test by running the current tasks that are posted.
@@ -468,33 +516,19 @@ class P2PQuicTransportTest : public testing::Test {
}
}
- // Starts the handshake, by setting the remote fingerprints and kicking off
- // the handshake from the client.
- void StartHandshake() {
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> server_fingerprints;
- server_fingerprints.emplace_back(rtc::SSLFingerprint::Create(
- "sha-256", server_peer_->certificate()->identity()));
- // The server side doesn't currently need call this to set the remote
- // fingerprints, but once P2P certificate verification is supported in the
- // TLS 1.3 handshake this will ben necessary.
- server_peer_->quic_transport()->Start(std::move(server_fingerprints));
-
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> client_fingerprints;
- client_fingerprints.emplace_back(rtc::SSLFingerprint::Create(
- "sha-256", client_peer_->certificate()->identity()));
- client_peer_->quic_transport()->Start(std::move(client_fingerprints));
- }
-
// Sets up an initial handshake and connection between peers.
+ // This is done using a pre shared key.
void Connect() {
CallbackRunLoop run_loop(runner());
-
EXPECT_CALL(*client_peer_->quic_transport_delegate(), OnConnected())
.WillOnce(FireCallback(run_loop.CreateCallback()));
EXPECT_CALL(*server_peer_->quic_transport_delegate(), OnConnected())
.WillOnce(FireCallback(run_loop.CreateCallback()));
- StartHandshake();
+ server_peer_->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
+ client_peer_->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
run_loop.RunUntilCallbacksFired();
}
@@ -593,20 +627,34 @@ class P2PQuicTransportTest : public testing::Test {
private:
quic::MockClock clock_;
+ quic::QuicRandom* quic_random_;
// The TestTaskRunner is used by the QUIC library for setting/firing alarms.
// We are able to explicitly run these tasks ourselves with the
// TestTaskRunner.
scoped_refptr<net::test::TestTaskRunner> runner_;
+ // This is eventually passed down to the QUIC library.
+ std::unique_ptr<net::QuicChromiumAlarmFactory> alarm_factory_;
std::unique_ptr<P2PQuicTransportFactoryImpl> quic_transport_factory_;
std::unique_ptr<QuicPeerForTest> client_peer_;
std::unique_ptr<QuicPeerForTest> server_peer_;
};
-// Tests that we can connect two quic transports.
-TEST_F(P2PQuicTransportTest, HandshakeConnectsPeers) {
+// Tests that we can connect two quic transports using pre shared keys.
+TEST_F(P2PQuicTransportTest, HandshakeConnectsPeersWithPreSharedKeys) {
Initialize();
- Connect();
+
+ CallbackRunLoop run_loop(runner());
+ EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnConnected())
+ .WillOnce(FireCallback(run_loop.CreateCallback()));
+ EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnConnected())
+ .WillOnce(FireCallback(run_loop.CreateCallback()));
+
+ server_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
+ client_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
+ run_loop.RunUntilCallbacksFired();
EXPECT_TRUE(client_peer()->quic_transport()->IsEncryptionEstablished());
EXPECT_TRUE(client_peer()->quic_transport()->IsCryptoHandshakeConfirmed());
@@ -614,6 +662,38 @@ TEST_F(P2PQuicTransportTest, HandshakeConnectsPeers) {
EXPECT_TRUE(server_peer()->quic_transport()->IsEncryptionEstablished());
}
+// Tests that we can connect two quic transports using remote certificate
+// fingerprints. Note that the fingerprints aren't currently used for
+// verification.
+TEST_F(P2PQuicTransportTest, HandshakeConnectsPeersWithRemoteCertificates) {
+ Initialize();
+
+ CallbackRunLoop run_loop(runner());
+ EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnConnected())
+ .WillOnce(FireCallback(run_loop.CreateCallback()));
+ EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnConnected())
+ .WillOnce(FireCallback(run_loop.CreateCallback()));
+
+ // Start the handshake with the remote fingerprints.
+ std::vector<std::unique_ptr<rtc::SSLFingerprint>> server_fingerprints;
+ server_fingerprints.emplace_back(rtc::SSLFingerprint::Create(
+ "sha-256", server_peer()->certificate()->identity()));
+ server_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig(std::move(server_fingerprints)));
+
+ std::vector<std::unique_ptr<rtc::SSLFingerprint>> client_fingerprints;
+ client_fingerprints.emplace_back(rtc::SSLFingerprint::Create(
+ "sha-256", client_peer()->certificate()->identity()));
+ client_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig(std::move(client_fingerprints)));
+
+ run_loop.RunUntilCallbacksFired();
+
+ EXPECT_TRUE(client_peer()->quic_transport()->IsEncryptionEstablished());
+ EXPECT_TRUE(client_peer()->quic_transport()->IsCryptoHandshakeConfirmed());
+ EXPECT_TRUE(server_peer()->quic_transport()->IsCryptoHandshakeConfirmed());
+ EXPECT_TRUE(server_peer()->quic_transport()->IsEncryptionEstablished());
+}
// Tests the standard case for the server side closing the connection.
TEST_F(P2PQuicTransportTest, ServerStops) {
Initialize();
@@ -669,44 +749,9 @@ TEST_F(P2PQuicTransportTest, StopAfterStopped) {
ExpectTransportsClosed();
}
-// Tests that when the client closes the connection the subsequent call to
-// StartHandshake() will be ignored.
-TEST_F(P2PQuicTransportTest, ClientStopsBeforeClientStarts) {
- Initialize();
- CallbackRunLoop run_loop(runner());
- EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnRemoteStopped())
- .WillOnce(FireCallback(run_loop.CreateCallback()));
- client_peer()->quic_transport()->Stop();
- StartHandshake();
- run_loop.RunUntilCallbacksFired();
-
- ExpectConnectionNotEstablished();
- ExpectTransportsClosed();
-}
-
-// Tests that if the server closes the connection before the client starts the
-// handshake, the client side will already be closed and Start() will be
-// ignored.
-TEST_F(P2PQuicTransportTest, ServerStopsBeforeClientStarts) {
- Initialize();
- CallbackRunLoop run_loop(runner());
- EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnRemoteStopped())
- .WillOnce(FireCallback(run_loop.CreateCallback()));
- EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnRemoteStopped())
- .Times(0);
-
- server_peer()->quic_transport()->Stop();
- StartHandshake();
- run_loop.RunUntilCallbacksFired();
-
- ExpectConnectionNotEstablished();
- ExpectTransportsClosed();
-}
-
-// Tests that when the server's connection fails and then a handshake is
-// attempted the transports will not become connected.
-TEST_F(P2PQuicTransportTest, ClientConnectionClosesBeforeHandshake) {
- Initialize();
+// Tests that the appropriate callbacks are fired when the handshake fails.
+TEST_F(P2PQuicTransportTest, HandshakeFailure) {
+ InitializeWithFailingProofVerification();
CallbackRunLoop run_loop(runner());
EXPECT_CALL(*client_peer()->quic_transport_delegate(),
OnConnectionFailed(_, _))
@@ -715,18 +760,20 @@ TEST_F(P2PQuicTransportTest, ClientConnectionClosesBeforeHandshake) {
OnConnectionFailed(_, _))
.WillOnce(FireCallback(run_loop.CreateCallback()));
- client_connection()->CloseConnection(
- quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error",
- quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- StartHandshake();
+ server_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
+ client_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
run_loop.RunUntilCallbacksFired();
ExpectConnectionNotEstablished();
+ ExpectTransportsClosed();
}
-// Tests that when the server's connection fails and then a handshake is
-// attempted the transports will not become connected.
-TEST_F(P2PQuicTransportTest, ServerConnectionClosesBeforeHandshake) {
+// Tests that the handshake fails if the pre shared keys don't match.
+// In this case the handshake finishes, but the connection fails because packets
+// can't be decrypted.
+TEST_F(P2PQuicTransportTest, HandshakeFailsBecauseKeysDontMatch) {
Initialize();
CallbackRunLoop run_loop(runner());
EXPECT_CALL(*client_peer()->quic_transport_delegate(),
@@ -736,30 +783,12 @@ TEST_F(P2PQuicTransportTest, ServerConnectionClosesBeforeHandshake) {
OnConnectionFailed(_, _))
.WillOnce(FireCallback(run_loop.CreateCallback()));
- server_connection()->CloseConnection(
- quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error",
- quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- StartHandshake();
+ server_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("foobar"));
+ client_peer()->quic_transport()->Start(
+ P2PQuicTransport::StartConfig("barfoo"));
run_loop.RunUntilCallbacksFired();
- ExpectConnectionNotEstablished();
-}
-
-// Tests that the appropriate callbacks are fired when the handshake fails.
-TEST_F(P2PQuicTransportTest, HandshakeFailure) {
- InitializeWithFailingProofVerification();
- CallbackRunLoop run_loop(runner());
- EXPECT_CALL(*client_peer()->quic_transport_delegate(),
- OnConnectionFailed(_, _))
- .WillOnce(FireCallback(run_loop.CreateCallback()));
- EXPECT_CALL(*server_peer()->quic_transport_delegate(),
- OnConnectionFailed(_, _))
- .WillOnce(FireCallback(run_loop.CreateCallback()));
-
- StartHandshake();
- run_loop.RunUntilCallbacksFired();
-
- ExpectConnectionNotEstablished();
ExpectTransportsClosed();
}
@@ -1132,4 +1161,48 @@ TEST_F(P2PQuicTransportTest, StreamDataSentWithFinClosesStreams) {
ExpectStreamsClosed();
}
+// Tests that the stats returned by the P2PQuicTransportImpl have the correct
+// number of incoming and outgoing streams.
+TEST_F(P2PQuicTransportTest, GetStatsForNumberOfStreams) {
+ Initialize();
+ Connect();
+
+ P2PQuicTransportStats client_stats_1 =
+ client_peer()->quic_transport()->GetStats();
+ EXPECT_EQ(0u, client_stats_1.num_incoming_streams_created);
+ EXPECT_EQ(0u, client_stats_1.num_outgoing_streams_created);
+ P2PQuicTransportStats server_stats_1 =
+ server_peer()->quic_transport()->GetStats();
+ EXPECT_EQ(0u, server_stats_1.num_incoming_streams_created);
+ EXPECT_EQ(0u, server_stats_1.num_outgoing_streams_created);
+
+ // Create a stream on the client side and send some data to trigger a stream
+ // creation on the remote side.
+ client_peer()->CreateStreamWithDelegate();
+ CallbackRunLoop run_loop(runner());
+ base::RepeatingCallback<void()> callback = run_loop.CreateCallback();
+ MockP2PQuicStreamDelegate server_stream_delegate;
+ EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnStream(_))
+ .WillOnce(
+ Invoke([&callback, &server_stream_delegate](P2PQuicStream* stream) {
+ stream->SetDelegate(&server_stream_delegate);
+ callback.Run();
+ }));
+ client_peer()->stream()->WriteData(
+ VectorFromArray(kTriggerRemoteStreamPhrase),
+ /*fin=*/false);
+ run_loop.RunUntilCallbacksFired();
+
+ P2PQuicTransportStats client_stats_2 =
+ client_peer()->quic_transport()->GetStats();
+ EXPECT_EQ(0u, client_stats_2.num_incoming_streams_created);
+ EXPECT_EQ(1u, client_stats_2.num_outgoing_streams_created);
+ EXPECT_GT(client_stats_2.timestamp, client_stats_1.timestamp);
+ P2PQuicTransportStats server_stats_2 =
+ server_peer()->quic_transport()->GetStats();
+ EXPECT_EQ(1u, server_stats_2.num_incoming_streams_created);
+ EXPECT_EQ(0u, server_stats_2.num_outgoing_streams_created);
+ EXPECT_GT(server_stats_2.timestamp, server_stats_1.timestamp);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc
new file mode 100644
index 00000000000..c74ac2ba8ff
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc
@@ -0,0 +1,84 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h"
+#include "net/third_party/quic/platform/api/quic_logging.h"
+
+namespace blink {
+
+QuicPacketTransportAdapter::QuicPacketTransportAdapter(
+ cricket::IceTransportInternal* ice_transport)
+ : ice_transport_(ice_transport) {
+ DCHECK(ice_transport_);
+ ice_transport_->SignalReadPacket.connect(
+ this, &QuicPacketTransportAdapter::OnReadPacket);
+ ice_transport_->SignalReadyToSend.connect(
+ this, &QuicPacketTransportAdapter::OnReadyToSend);
+}
+
+QuicPacketTransportAdapter::~QuicPacketTransportAdapter() {
+ // Caller is responsible for unsetting the write observer and receive
+ // delegate before destroying this.
+ DCHECK(!write_observer_);
+ DCHECK(!receive_delegate_);
+}
+
+int QuicPacketTransportAdapter::WritePacket(const QuicPacket& packet) {
+ rtc::PacketOptions options;
+ options.packet_id = packet.packet_number;
+ int flags = 0;
+ return ice_transport_->SendPacket(packet.buffer, packet.buf_len, options,
+ flags);
+}
+
+void QuicPacketTransportAdapter::SetReceiveDelegate(
+ ReceiveDelegate* receive_delegate) {
+ receive_delegate_ = receive_delegate;
+ if (!cached_client_hello_packet_.empty() && receive_delegate_) {
+ // If a CHLO was received early, give it to the delegate.
+ receive_delegate_->OnPacketDataReceived(cached_client_hello_packet_.c_str(),
+ cached_client_hello_packet_.size());
+ cached_client_hello_packet_.clear();
+ }
+}
+
+void QuicPacketTransportAdapter::SetWriteObserver(
+ WriteObserver* write_observer) {
+ write_observer_ = write_observer;
+}
+
+bool QuicPacketTransportAdapter::Writable() {
+ return ice_transport_->writable();
+}
+
+// IceTransportInternal callbacks.
+void QuicPacketTransportAdapter::OnReadPacket(
+ rtc::PacketTransportInternal* packet_transport,
+ const char* buffer,
+ size_t buffer_length,
+ const int64_t& packet_time,
+ int flags) {
+ DCHECK_EQ(packet_transport, ice_transport_);
+ if (!receive_delegate_) {
+ // Cache the early CHLO from the QUIC handshake.
+ // The CHLO is stored in a single packet. All packets before the most recent
+ // can be discarded because they are no longer relevant, since at this point
+ // we have not responded. The packet could also be a connection close packet
+ // in the case that QUIC times out waiting for a response.
+ cached_client_hello_packet_ = std::string(buffer, buffer_length);
+ return;
+ }
+ receive_delegate_->OnPacketDataReceived(buffer, buffer_length);
+}
+
+void QuicPacketTransportAdapter::OnReadyToSend(
+ rtc::PacketTransportInternal* packet_transport) {
+ DCHECK_EQ(packet_transport, ice_transport_);
+ if (!write_observer_) {
+ return;
+ }
+ write_observer_->OnCanWrite();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h
new file mode 100644
index 00000000000..97689998ae5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h
@@ -0,0 +1,56 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_PACKET_TRANSPORT_ADAPTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_PACKET_TRANSPORT_ADAPTER_H_
+
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
+#include "third_party/webrtc/p2p/base/p2p_transport_channel.h"
+
+namespace blink {
+
+// Implementation of P2PQuicPacketTransport backed by a IceTransportInternal.
+// It adapts the underlying ICE transport to be used with the QUIC library.
+// This does not filter packets. It requires that the IceTransportInternal is
+// only being used for QUIC packets.
+class MODULES_EXPORT QuicPacketTransportAdapter : public P2PQuicPacketTransport,
+ public sigslot::has_slots<> {
+ public:
+ QuicPacketTransportAdapter(
+ cricket::IceTransportInternal* p2p_transport_channel);
+
+ ~QuicPacketTransportAdapter() override;
+
+ // P2PQuicPacketTransport overrides.
+ int WritePacket(const QuicPacket& packet) override;
+ void SetReceiveDelegate(ReceiveDelegate* receive_delegate) override;
+ void SetWriteObserver(WriteObserver* write_observer) override;
+ bool Writable() override;
+
+ private:
+ // IceTransportInternal callbacks.
+ void OnReadPacket(rtc::PacketTransportInternal* packet_transport,
+ const char* buffer,
+ size_t buffer_length,
+ const int64_t& packet_time,
+ int flags);
+
+ void OnReadyToSend(rtc::PacketTransportInternal* packet_transport);
+
+ // Owned by the IceTransportAdapter and will outlive this object.
+ cricket::IceTransportInternal* ice_transport_;
+ // The ReceiveDelegate and WriteObserver must be unset before
+ // this object is destroyed.
+ ReceiveDelegate* receive_delegate_ = nullptr;
+ WriteObserver* write_observer_ = nullptr;
+ // If the CHLO arrives early it is cached. This can occur if the QUIC
+ // handshake begins on the client side before the remote parameters are
+ // received on the server side.
+ std::string cached_client_hello_packet_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_PACKET_TRANSPORT_ADAPTER_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc
new file mode 100644
index 00000000000..2c3785e1ef8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc
@@ -0,0 +1,126 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h"
+
+#include "net/test/gtest_util.h"
+#include "third_party/webrtc/p2p/base/mock_ice_transport.h"
+
+namespace blink {
+
+namespace {
+using testing::StrEq;
+} // namespace
+
+class MockWriteObserver : public P2PQuicPacketTransport::WriteObserver {
+ public:
+ MOCK_METHOD0(OnCanWrite, void());
+};
+
+class MockReceiveDelegate : public P2PQuicPacketTransport::ReceiveDelegate {
+ public:
+ MOCK_METHOD2(OnPacketDataReceived, void(const char*, size_t));
+};
+
+class QuicPacketTransportAdapterTest : public testing::Test {
+ public:
+ QuicPacketTransportAdapterTest()
+ : quic_packet_transport_adapter_(&mock_ice_transport_) {}
+
+ ~QuicPacketTransportAdapterTest() override {
+ quic_packet_transport_adapter_.SetReceiveDelegate(nullptr);
+ quic_packet_transport_adapter_.SetWriteObserver(nullptr);
+ }
+
+ cricket::MockIceTransport* mock_ice_transport() {
+ return &mock_ice_transport_;
+ }
+
+ QuicPacketTransportAdapter* quic_packet_transport_adapter() {
+ return &quic_packet_transport_adapter_;
+ }
+
+ private:
+ cricket::MockIceTransport mock_ice_transport_;
+ QuicPacketTransportAdapter quic_packet_transport_adapter_;
+};
+
+// Tests that when the underlying ICE transport is ready to send data that
+// the QuicPacketTransportAdapter will tell the WriteObserver.
+TEST_F(QuicPacketTransportAdapterTest, IceTransportReadyTriggersCanWrite) {
+ MockWriteObserver mock_write_observer;
+ quic_packet_transport_adapter()->SetWriteObserver(&mock_write_observer);
+
+ EXPECT_CALL(mock_write_observer, OnCanWrite());
+
+ mock_ice_transport()->SignalReadyToSend(mock_ice_transport());
+}
+
+// Tests that writing a packet to the QuicPacketTransportAdapter will write
+// the data to the underlying ICE transport.
+TEST_F(QuicPacketTransportAdapterTest, WritePacketWritesToIceTransport) {
+ std::string packet("hola");
+
+ EXPECT_CALL(*mock_ice_transport(),
+ SendPacket(StrEq(packet), packet.size(), _, _));
+
+ P2PQuicPacketTransport::QuicPacket quic_packet;
+ quic_packet.buffer = packet.c_str();
+ quic_packet.buf_len = packet.size();
+ quic_packet_transport_adapter()->WritePacket(quic_packet);
+}
+
+// Tests that when the underlying ICE transport receives data it it
+// is passed appropriately to the ReceiveDelegate.
+TEST_F(QuicPacketTransportAdapterTest, ReadPacketGivenToReceiveDelegate) {
+ MockReceiveDelegate mock_receive_delegate;
+ quic_packet_transport_adapter()->SetReceiveDelegate(&mock_receive_delegate);
+
+ std::string packet("hola");
+ EXPECT_CALL(mock_receive_delegate,
+ OnPacketDataReceived(StrEq(packet), packet.size()));
+
+ mock_ice_transport()->SignalReadPacket(mock_ice_transport(), packet.c_str(),
+ packet.size(), 0, 0);
+}
+
+// Tests that the most recent packet that was received before the
+// ReceiveDelegate is hooked up will be given to the ReceiveDelegate once it is
+// set. This is used as an optimization in the case that a QUIC CHLO is received
+// early.
+TEST_F(QuicPacketTransportAdapterTest,
+ MostRecentCachedPacketGivenToReceiveDelegate) {
+ std::string packet("hola");
+ std::string latest_packet("bonjour");
+
+ mock_ice_transport()->SignalReadPacket(mock_ice_transport(), packet.c_str(),
+ packet.size(), 0, 0);
+ mock_ice_transport()->SignalReadPacket(
+ mock_ice_transport(), latest_packet.c_str(), latest_packet.size(), 0, 0);
+
+ // The receive delegate is set after packets have been received.
+ MockReceiveDelegate mock_receive_delegate;
+ EXPECT_CALL(mock_receive_delegate,
+ OnPacketDataReceived(StrEq(latest_packet), latest_packet.size()));
+
+ quic_packet_transport_adapter()->SetReceiveDelegate(&mock_receive_delegate);
+}
+
+// Tests that the cached packet is not reused once it has been handed off to
+// a set ReceiveDelegate.
+TEST_F(QuicPacketTransportAdapterTest, CachedPacketIsNotReused) {
+ std::string packet("hola");
+ mock_ice_transport()->SignalReadPacket(mock_ice_transport(), packet.c_str(),
+ packet.size(), 0, 0);
+
+ MockReceiveDelegate mock_receive_delegate;
+ EXPECT_CALL(mock_receive_delegate, OnPacketDataReceived(_, _));
+ quic_packet_transport_adapter()->SetReceiveDelegate(&mock_receive_delegate);
+
+ MockReceiveDelegate latest_receive_delegate;
+ EXPECT_CALL(latest_receive_delegate, OnPacketDataReceived(_, _)).Times(0);
+ quic_packet_transport_adapter()->SetReceiveDelegate(&latest_receive_delegate);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc
index a0937ef43e3..70debe1cfe8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc
@@ -99,6 +99,7 @@ void QuicStreamHost::OnWriteDataConsumed(uint32_t amount) {
void QuicStreamHost::Delete() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(transport_host_);
+ p2p_stream_->SetDelegate(nullptr);
// OnRemoveStream will delete |this|.
transport_host_->OnRemoveStream(this);
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc
index 5cddf17200a..d112cdc76e8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc
@@ -60,10 +60,9 @@ scoped_refptr<base::SingleThreadTaskRunner> QuicTransportHost::host_thread()
return ice_transport_host_->host_thread();
}
-void QuicTransportHost::Start(
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints) {
+void QuicTransportHost::Start(P2PQuicTransport::StartConfig config) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- quic_transport_->Start(std::move(remote_fingerprints));
+ quic_transport_->Start(std::move(config));
}
void QuicTransportHost::Stop() {
@@ -81,6 +80,15 @@ void QuicTransportHost::CreateStream(
std::make_pair(stream_host.get(), std::move(stream_host)));
}
+void QuicTransportHost::GetStats(uint32_t request_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ P2PQuicTransportStats stats = quic_transport_->GetStats();
+ PostCrossThreadTask(
+ *proxy_thread(), FROM_HERE,
+ CrossThreadBind(&QuicTransportProxy::OnStats, proxy_, request_id, stats));
+}
+
void QuicTransportHost::OnRemoveStream(QuicStreamHost* stream_host_to_remove) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h
index 8a8927b400a..53548d6ed21 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h
@@ -56,12 +56,13 @@ class QuicTransportHost final : public P2PQuicTransport::Delegate {
scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const;
scoped_refptr<base::SingleThreadTaskRunner> host_thread() const;
- void Start(
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints);
+ void Start(P2PQuicTransport::StartConfig config);
void Stop();
void CreateStream(std::unique_ptr<QuicStreamHost> stream_host);
+ void GetStats(uint32_t request_id);
+
// QuicStreamHost callbacks.
void OnRemoveStream(QuicStreamHost* stream_host_to_remove);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
index 66343f40130..cbc29fef9a5 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
@@ -70,14 +70,12 @@ scoped_refptr<base::SingleThreadTaskRunner> QuicTransportProxy::host_thread()
return ice_transport_proxy_->host_thread();
}
-void QuicTransportProxy::Start(
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints) {
+void QuicTransportProxy::Start(P2PQuicTransport::StartConfig config) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- PostCrossThreadTask(
- *host_thread(), FROM_HERE,
- CrossThreadBind(&QuicTransportHost::Start,
- CrossThreadUnretained(host_.get()),
- WTF::Passed(std::move(remote_fingerprints))));
+ PostCrossThreadTask(*host_thread(), FROM_HERE,
+ CrossThreadBind(&QuicTransportHost::Start,
+ CrossThreadUnretained(host_.get()),
+ WTF::Passed(std::move(config))));
}
void QuicTransportProxy::Stop() {
@@ -108,6 +106,15 @@ QuicStreamProxy* QuicTransportProxy::CreateStream() {
return stream_proxy_ptr;
}
+void QuicTransportProxy::GetStats(uint32_t request_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ PostCrossThreadTask(
+ *host_thread(), FROM_HERE,
+ CrossThreadBind(&QuicTransportHost::GetStats,
+ CrossThreadUnretained(host_.get()), request_id));
+}
+
void QuicTransportProxy::OnRemoveStream(
QuicStreamProxy* stream_proxy_to_remove) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -131,8 +138,8 @@ void QuicTransportProxy::OnRemoteStopped() {
void QuicTransportProxy::OnConnectionFailed(const std::string& error_details,
bool from_remote) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- delegate_->OnConnectionFailed(error_details, from_remote);
stream_proxies_.clear();
+ delegate_->OnConnectionFailed(error_details, from_remote);
}
void QuicTransportProxy::OnStream(
@@ -147,4 +154,11 @@ void QuicTransportProxy::OnStream(
delegate_->OnStream(stream_proxy_ptr);
}
+void QuicTransportProxy::OnStats(uint32_t request_id,
+ const P2PQuicTransportStats& stats) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ delegate_->OnStats(request_id, stats);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
index c0eaa7aecda..d04dec77c8b 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
@@ -13,11 +13,8 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/webrtc/rtc_base/scoped_ref_ptr.h"
-
-namespace rtc {
-struct SSLFingerprint;
-} // namespace rtc
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
+#include "third_party/webrtc/api/scoped_refptr.h"
namespace blink {
@@ -52,6 +49,11 @@ class QuicTransportProxy final {
bool from_remote) {}
// Called when the remote side has created a new stream.
virtual void OnStream(QuicStreamProxy* stream_proxy) {}
+
+ // Called after the stats have been gathered on the host thread. The
+ // |request_id| maps to |request_id| used in GetStats().
+ virtual void OnStats(uint32_t request_id,
+ const P2PQuicTransportStats& stats) {}
};
// Construct a Proxy with the underlying QUIC implementation running on the
@@ -71,12 +73,16 @@ class QuicTransportProxy final {
scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const;
scoped_refptr<base::SingleThreadTaskRunner> host_thread() const;
- void Start(
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints);
+ void Start(P2PQuicTransport::StartConfig config);
void Stop();
QuicStreamProxy* CreateStream();
+ // Gathers stats on the host thread, then returns them asynchronously with
+ // Delegate::OnStats. The |request_id| is used to map the GetStats call to the
+ // returned stats.
+ void GetStats(uint32_t request_id);
+
// QuicStreamProxy callbacks.
void OnRemoveStream(QuicStreamProxy* stream_proxy);
@@ -87,6 +93,7 @@ class QuicTransportProxy final {
void OnRemoteStopped();
void OnConnectionFailed(const std::string& error_details, bool from_remote);
void OnStream(std::unique_ptr<QuicStreamProxy> stream_proxy);
+ void OnStats(uint32_t request_id, const P2PQuicTransportStats& stats);
// Since the Host is deleted on the host thread (Via OnTaskRunnerDeleter), as
// long as this is alive it is safe to post tasks to it (using unretained).
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
index 1f11477a4ca..caf51a85e36 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
@@ -12,8 +12,9 @@
#include <set>
#include <vector>
+#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
#include "third_party/blink/renderer/platform/cross_thread_copier.h"
-#include "third_party/webrtc/rtc_base/scoped_ref_ptr.h"
+#include "third_party/webrtc/api/scoped_refptr.h"
namespace cricket {
class Candidate;
@@ -26,6 +27,10 @@ class RTCCertificate;
class SocketAddress;
}
+namespace webrtc {
+class DtlsTransportInformation;
+}
+
namespace blink {
struct P2PQuicTransportConfig;
@@ -94,6 +99,30 @@ struct CrossThreadCopier<P2PQuicTransportConfig>
STATIC_ONLY(CrossThreadCopier);
};
+template <>
+struct CrossThreadCopier<webrtc::DtlsTransportInformation>
+ : public CrossThreadCopierPassThrough<webrtc::DtlsTransportInformation> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
+template <>
+struct CrossThreadCopier<P2PQuicTransport::StartConfig>
+ : public CrossThreadCopierPassThrough<P2PQuicTransport::StartConfig> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = P2PQuicTransport::StartConfig;
+ static P2PQuicTransport::StartConfig Copy(
+ P2PQuicTransport::StartConfig config) {
+ // This is in fact a move.
+ return config;
+ }
+};
+
+template <>
+struct CrossThreadCopier<P2PQuicTransportStats>
+ : public CrossThreadCopierPassThrough<P2PQuicTransportStats> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc b/chromium/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc
index defda76f8e3..b8540b6a681 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc
@@ -14,7 +14,8 @@ wtf_size_t ByteBufferQueue::ReadInto(base::span<uint8_t> buffer_out) {
.subspan(front_buffer_offset_);
DCHECK_GT(front_buffer.size(), 0u);
wtf_size_t buffer_read_amount =
- std::min(buffer_out.size(), front_buffer.size());
+ std::min(static_cast<wtf_size_t>(buffer_out.size()),
+ static_cast<wtf_size_t>(front_buffer.size()));
memcpy(buffer_out.data(), front_buffer.data(), buffer_read_amount);
read_amount += buffer_read_amount;
buffer_out = buffer_out.subspan(buffer_read_amount);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.cc
index d6ac0d6314d..c07ad33c277 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.cc
@@ -33,7 +33,7 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/webrtc/rtc_base/sslcertificate.h"
+#include "third_party/webrtc/rtc_base/ssl_certificate.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.h
index 69dbc5a908b..76304d73009 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.h
@@ -40,7 +40,7 @@
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
-#include "third_party/webrtc/rtc_base/rtccertificate.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_configuration.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_configuration.idl
index 280480bcc0d..b339ece2971 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_configuration.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_configuration.idl
@@ -48,6 +48,9 @@ dictionary RTCConfiguration {
[EnforceRange] octet iceCandidatePoolSize = 0;
// Nonstandard, added for Unified Plan migration
[RuntimeEnabled=RTCUnifiedPlan] SdpSemantics sdpSemantics;
+ // Nonstandard, added for backward compatibility reasons during a
+ // transitional phase. https://crbug.com/908377
+ boolean offerExtmapAllowMixed;
[OriginTrialEnabled=RtcAudioJitterBufferMaxPackets] long rtcAudioJitterBufferMaxPackets;
[OriginTrialEnabled=RtcAudioJitterBufferMaxPackets] boolean rtcAudioJitterBufferFastAccelerate;
[OriginTrialEnabled=RtcAudioJitterBufferMaxPackets] long rtcAudioJitterBufferMinDelayMs;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
index f5d3e244130..9dda85f4d79 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
@@ -60,11 +60,7 @@ RTCDataChannel* RTCDataChannel::Create(
ExecutionContext* context,
std::unique_ptr<WebRTCDataChannelHandler> handler) {
DCHECK(handler);
- RTCDataChannel* channel =
- MakeGarbageCollected<RTCDataChannel>(context, std::move(handler));
- channel->PauseIfNeeded();
-
- return channel;
+ return MakeGarbageCollected<RTCDataChannel>(context, std::move(handler));
}
RTCDataChannel* RTCDataChannel::Create(
@@ -80,17 +76,13 @@ RTCDataChannel* RTCDataChannel::Create(
"RTCDataChannel is not supported");
return nullptr;
}
- RTCDataChannel* channel =
- MakeGarbageCollected<RTCDataChannel>(context, std::move(handler));
- channel->PauseIfNeeded();
-
- return channel;
+ return MakeGarbageCollected<RTCDataChannel>(context, std::move(handler));
}
RTCDataChannel::RTCDataChannel(
ExecutionContext* context,
std::unique_ptr<WebRTCDataChannelHandler> handler)
- : PausableObject(context),
+ : ContextLifecycleObserver(context),
handler_(std::move(handler)),
ready_state_(kReadyStateConnecting),
binary_type_(kBinaryTypeArrayBuffer),
@@ -305,17 +297,7 @@ const AtomicString& RTCDataChannel::InterfaceName() const {
}
ExecutionContext* RTCDataChannel::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
-}
-
-// PausableObject
-void RTCDataChannel::Pause() {
- scheduled_event_timer_.Stop();
-}
-
-void RTCDataChannel::Unpause() {
- if (!scheduled_events_.IsEmpty() && !scheduled_event_timer_.IsActive())
- scheduled_event_timer_.StartOneShot(TimeDelta(), FROM_HERE);
+ return ContextLifecycleObserver::GetExecutionContext();
}
void RTCDataChannel::ContextDestroyed(ExecutionContext*) {
@@ -385,7 +367,7 @@ void RTCDataChannel::ScheduledEventTimerFired(TimerBase*) {
void RTCDataChannel::Trace(blink::Visitor* visitor) {
visitor->Trace(scheduled_events_);
EventTargetWithInlineData::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
index bcc0e81bb14..df83d14c56a 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
@@ -30,7 +30,7 @@
#include "third_party/blink/public/platform/web_rtc_data_channel_handler.h"
#include "third_party/blink/public/platform/web_rtc_data_channel_handler_client.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -51,7 +51,7 @@ class MODULES_EXPORT RTCDataChannel final
: public EventTargetWithInlineData,
public WebRTCDataChannelHandlerClient,
public ActiveScriptWrappable<RTCDataChannel>,
- public PausableObject {
+ public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(RTCDataChannel);
DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(RTCDataChannel, Dispose);
@@ -107,9 +107,7 @@ class MODULES_EXPORT RTCDataChannel final
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
- // PausableObject
- void Pause() override;
- void Unpause() override;
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// ScriptWrappable
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
index ceab4fae201..75a50bd5df7 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
@@ -79,8 +79,8 @@ class MockHandler final : public WebRTCDataChannelHandler {
TEST(RTCDataChannelTest, BufferedAmount) {
MockHandler* handler = new MockHandler();
- RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
- base::WrapUnique(handler));
+ RTCDataChannel* channel = RTCDataChannel::Create(
+ MakeGarbageCollected<NullExecutionContext>(), base::WrapUnique(handler));
handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
String message(std::string(100, 'A').c_str());
@@ -90,8 +90,8 @@ TEST(RTCDataChannelTest, BufferedAmount) {
TEST(RTCDataChannelTest, BufferedAmountLow) {
MockHandler* handler = new MockHandler();
- RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
- base::WrapUnique(handler));
+ RTCDataChannel* channel = RTCDataChannel::Create(
+ MakeGarbageCollected<NullExecutionContext>(), base::WrapUnique(handler));
// Add and drain 100 bytes
handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
@@ -154,8 +154,8 @@ TEST(RTCDataChannelTest, BufferedAmountLow) {
TEST(RTCDataChannelTest, SendAfterContextDestroyed) {
MockHandler* handler = new MockHandler();
- RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
- base::WrapUnique(handler));
+ RTCDataChannel* channel = RTCDataChannel::Create(
+ MakeGarbageCollected<NullExecutionContext>(), base::WrapUnique(handler));
handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
channel->ContextDestroyed(nullptr);
@@ -168,8 +168,8 @@ TEST(RTCDataChannelTest, SendAfterContextDestroyed) {
TEST(RTCDataChannelTest, CloseAfterContextDestroyed) {
MockHandler* handler = new MockHandler();
- RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
- base::WrapUnique(handler));
+ RTCDataChannel* channel = RTCDataChannel::Create(
+ MakeGarbageCollected<NullExecutionContext>(), base::WrapUnique(handler));
handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
channel->ContextDestroyed(nullptr);
channel->close();
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
index feadf0ac9d6..059ad0495c2 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
@@ -10,9 +10,9 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h"
@@ -21,27 +21,68 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event_init.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/webrtc/api/jsepicecandidate.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
-#include "third_party/webrtc/p2p/base/portallocator.h"
-#include "third_party/webrtc/p2p/base/transportdescription.h"
-#include "third_party/webrtc/pc/iceserverparsing.h"
-#include "third_party/webrtc/pc/webrtcsdp.h"
+#include "third_party/webrtc/api/dtls_transport_interface.h"
+#include "third_party/webrtc/api/jsep_ice_candidate.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
+#include "third_party/webrtc/p2p/base/port_allocator.h"
+#include "third_party/webrtc/p2p/base/transport_description.h"
+#include "third_party/webrtc/pc/ice_server_parsing.h"
+#include "third_party/webrtc/pc/webrtc_sdp.h"
namespace blink {
-RTCDtlsTransport* RTCDtlsTransport::Create(ExecutionContext* context) {
- return new RTCDtlsTransport(context);
+namespace {
+String TransportStateToString(webrtc::DtlsTransportState state) {
+ switch (state) {
+ case webrtc::DtlsTransportState::kNew:
+ return String("new");
+ break;
+ case webrtc::DtlsTransportState::kConnecting:
+ return String("connecting");
+ break;
+ case webrtc::DtlsTransportState::kConnected:
+ return String("connected");
+ break;
+ case webrtc::DtlsTransportState::kClosed:
+ return String("closed");
+ break;
+ case webrtc::DtlsTransportState::kFailed:
+ return String("failed");
+ break;
+ default:
+ NOTREACHED();
+ return String("failed");
+ break;
+ }
}
-RTCDtlsTransport::RTCDtlsTransport(ExecutionContext* context)
- : ContextClient(context) {}
+std::unique_ptr<DtlsTransportProxy> CreateProxy(
+ ExecutionContext* context,
+ webrtc::DtlsTransportInterface* native_transport,
+ DtlsTransportProxy::Delegate* delegate) {
+ LocalFrame* frame = To<Document>(context)->GetFrame();
+ scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
+ frame->GetTaskRunner(TaskType::kNetworking);
+ scoped_refptr<base::SingleThreadTaskRunner> host_thread =
+ Platform::Current()->GetWebRtcWorkerThread();
+ return DtlsTransportProxy::Create(*frame, proxy_thread, host_thread,
+ native_transport, delegate);
+}
+
+} // namespace
+
+RTCDtlsTransport::RTCDtlsTransport(
+ ExecutionContext* context,
+ rtc::scoped_refptr<webrtc::DtlsTransportInterface> native_transport)
+ : ContextClient(context),
+ current_state_(webrtc::DtlsTransportState::kNew),
+ native_transport_(native_transport),
+ proxy_(CreateProxy(context, native_transport, this)) {}
RTCDtlsTransport::~RTCDtlsTransport() {}
String RTCDtlsTransport::state() const {
- NOTIMPLEMENTED();
- return "";
+ return TransportStateToString(current_state_.state());
}
const HeapVector<Member<DOMArrayBuffer>>&
@@ -55,6 +96,22 @@ RTCIceTransport* RTCDtlsTransport::iceTransport() const {
return nullptr;
}
+webrtc::DtlsTransportInterface* RTCDtlsTransport::native_transport() {
+ return native_transport_.get();
+}
+
+// Implementation of DtlsTransportProxy::Delegate
+void RTCDtlsTransport::OnStartCompleted(webrtc::DtlsTransportInformation info) {
+ current_state_ = info;
+}
+
+void RTCDtlsTransport::OnStateChange(webrtc::DtlsTransportInformation info) {
+ // We depend on closed only happening once for safe garbage collection.
+ DCHECK(current_state_.state() != webrtc::DtlsTransportState::kClosed);
+ current_state_ = info;
+ DispatchEvent(*Event::Create(event_type_names::kStatechange));
+}
+
const AtomicString& RTCDtlsTransport::InterfaceName() const {
return event_target_names::kRTCDtlsTransport;
}
@@ -63,6 +120,14 @@ ExecutionContext* RTCDtlsTransport::GetExecutionContext() const {
return ContextClient::GetExecutionContext();
}
+bool RTCDtlsTransport::HasPendingActivity() const {
+ // We have to keep the RTCDtlsTransport alive while new notifications
+ // may arrive.
+ // The closed state is final, so no more events will happen after
+ // seeing that state.
+ return current_state_.state() != webrtc::DtlsTransportState::kClosed;
+}
+
void RTCDtlsTransport::Trace(Visitor* visitor) {
visitor->Trace(remote_certificates_);
EventTargetWithInlineData::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h
index afe492c7dca..557761026f1 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h
@@ -8,9 +8,13 @@
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h"
+#include "third_party/webrtc/api/dtls_transport_interface.h"
+#include "third_party/webrtc/api/scoped_refptr.h"
namespace blink {
+class DtlsTransportProxy;
class DOMArrayBuffer;
class RTCIceTransport;
@@ -26,14 +30,18 @@ enum class RTCDtlsTransportState {
// Blink bindings for the RTCDtlsTransport JavaScript object.
//
-class MODULES_EXPORT RTCDtlsTransport final : public EventTargetWithInlineData,
- public ContextClient {
+class MODULES_EXPORT RTCDtlsTransport final
+ : public EventTargetWithInlineData,
+ public ContextClient,
+ public ActiveScriptWrappable<RTCDtlsTransport>,
+ public DtlsTransportProxy::Delegate {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(RTCDtlsTransport);
public:
- static RTCDtlsTransport* Create(ExecutionContext* context);
-
+ RTCDtlsTransport(
+ ExecutionContext* context,
+ rtc::scoped_refptr<webrtc::DtlsTransportInterface> native_context);
~RTCDtlsTransport() override;
// rtc_dtls_transport.idl
@@ -44,15 +52,25 @@ class MODULES_EXPORT RTCDtlsTransport final : public EventTargetWithInlineData,
DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange, kStatechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError);
+ // DtlsTransportProxy::Delegate
+ void OnStartCompleted(webrtc::DtlsTransportInformation info) override;
+ void OnStateChange(webrtc::DtlsTransportInformation info) override;
+
+ // ActiveScriptWrappable overrides
+ bool HasPendingActivity() const override;
+
// EventTarget overrides.
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
// For garbage collection.
void Trace(blink::Visitor* visitor) override;
+ webrtc::DtlsTransportInterface* native_transport();
private:
- explicit RTCDtlsTransport(ExecutionContext* context);
+ webrtc::DtlsTransportInformation current_state_;
HeapVector<Member<DOMArrayBuffer>> remote_certificates_;
+ rtc::scoped_refptr<webrtc::DtlsTransportInterface> native_transport_;
+ std::unique_ptr<DtlsTransportProxy> proxy_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl
index c514ca92801..3c46b0588ef 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl
@@ -14,6 +14,7 @@ enum RTCDtlsTransportState {
[
Exposed=Window,
+ ActiveScriptWrappable,
RuntimeEnabled=RTCDtlsTransport
] interface RTCDtlsTransport : EventTarget {
readonly attribute RTCIceTransport iceTransport;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_error_util.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_error_util.h
index 0fd2dce39a5..6a61f1308a3 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_error_util.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_error_util.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ERROR_UTIL_H_
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/webrtc/api/rtcerror.h"
+#include "third_party/webrtc/api/rtc_error.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.idl
index 3bb7c975c4e..afbe83ccada 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.idl
@@ -28,6 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface
[
Constructor(RTCIceCandidateInit candidateInitDict),
ConstructorCallWith=ExecutionContext,
@@ -37,5 +38,6 @@
attribute DOMString candidate;
attribute DOMString sdpMid;
attribute unsigned short sdpMLineIndex;
- serializer = {attribute};
+ // TODO(peria): Return type should be RTCIceCandidateInit.
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
index 32caf50cd84..65a727db3ce 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -22,12 +22,12 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event_init.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/webrtc/api/jsepicecandidate.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
-#include "third_party/webrtc/p2p/base/portallocator.h"
-#include "third_party/webrtc/p2p/base/transportdescription.h"
-#include "third_party/webrtc/pc/iceserverparsing.h"
-#include "third_party/webrtc/pc/webrtcsdp.h"
+#include "third_party/webrtc/api/jsep_ice_candidate.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
+#include "third_party/webrtc/p2p/base/port_allocator.h"
+#include "third_party/webrtc/p2p/base/transport_description.h"
+#include "third_party/webrtc/pc/ice_server_parsing.h"
+#include "third_party/webrtc/pc/webrtc_sdp.h"
namespace blink {
namespace {
@@ -58,8 +58,11 @@ class DefaultIceTransportAdapterCrossThreadFactory
void InitializeOnMainThread(LocalFrame& frame) override {
DCHECK(!port_allocator_);
DCHECK(!worker_thread_rtc_thread_);
+ DCHECK(!async_resolver_factory_);
port_allocator_ = Platform::Current()->CreateWebRtcPortAllocator(
frame.Client()->GetWebFrame());
+ async_resolver_factory_ =
+ Platform::Current()->CreateWebRtcAsyncResolverFactory();
worker_thread_rtc_thread_ =
Platform::Current()->GetWebRtcWorkerThreadRtcThread();
}
@@ -68,12 +71,15 @@ class DefaultIceTransportAdapterCrossThreadFactory
IceTransportAdapter::Delegate* delegate) override {
DCHECK(port_allocator_);
DCHECK(worker_thread_rtc_thread_);
+ DCHECK(async_resolver_factory_);
return std::make_unique<IceTransportAdapterImpl>(
- delegate, std::move(port_allocator_), worker_thread_rtc_thread_);
+ delegate, std::move(port_allocator_),
+ std::move(async_resolver_factory_), worker_thread_rtc_thread_);
}
private:
std::unique_ptr<cricket::PortAllocator> port_allocator_;
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
rtc::Thread* worker_thread_rtc_thread_ = nullptr;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
index 76656b1b2cf..cef48a91cd6 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
@@ -33,18 +33,20 @@ enum RTCIceGatheringState {
Constructor(),
ConstructorCallWith=ExecutionContext,
Exposed=Window,
- RuntimeEnabled=RTCIceTransportExtension
+ Measure,
+ OriginTrialEnabled=RTCIceTransportExtension,
+ SecureContext
] interface RTCIceTransport : EventTarget {
// TODO(github.com/w3c/webrtc-ice/issues/4): role is non-null in the
// WebRTC-PC specification.
- readonly attribute RTCIceRole? role;
- readonly attribute RTCIceTransportState state;
- readonly attribute RTCIceGatheringState gatheringState;
- sequence<RTCIceCandidate> getLocalCandidates();
- sequence<RTCIceCandidate> getRemoteCandidates();
- RTCIceCandidatePair? getSelectedCandidatePair();
- RTCIceParameters? getLocalParameters();
- RTCIceParameters? getRemoteParameters();
+ [Measure] readonly attribute RTCIceRole? role;
+ [Measure] readonly attribute RTCIceTransportState state;
+ [Measure] readonly attribute RTCIceGatheringState gatheringState;
+ [Measure] sequence<RTCIceCandidate> getLocalCandidates();
+ [Measure] sequence<RTCIceCandidate> getRemoteCandidates();
+ [Measure] RTCIceCandidatePair? getSelectedCandidatePair();
+ [Measure] RTCIceParameters? getLocalParameters();
+ [Measure] RTCIceParameters? getRemoteParameters();
attribute EventHandler onstatechange;
attribute EventHandler ongatheringstatechange;
attribute EventHandler onselectedcandidatepairchange;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc
index a4b6e648b16..06d3d768486 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc
@@ -15,7 +15,7 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_init.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
-#include "third_party/webrtc/pc/webrtcsdp.h"
+#include "third_party/webrtc/pc/webrtc_sdp.h"
namespace blink {
namespace {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h
index 4cc2bff8a5e..6a84ee50ea4 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h
@@ -7,20 +7,14 @@
#include "base/test/test_simple_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
namespace blink {
-class MockEventListener final : public EventListener {
+class MockEventListener final : public NativeEventListener {
public:
- MockEventListener() : EventListener(ListenerType::kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
MOCK_METHOD2(Invoke, void(ExecutionContext*, Event*));
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index e21602e3d2a..6139ec8db34 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -33,6 +33,7 @@
#include <algorithm>
#include <memory>
#include <set>
+#include <string>
#include <utility>
#include "base/memory/ptr_util.h"
@@ -86,6 +87,7 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_data_channel_event.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_data_channel_init.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_server.h"
@@ -116,9 +118,10 @@
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
+#include "third_party/webrtc/api/dtls_transport_interface.h"
#include "third_party/webrtc/api/jsep.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
-#include "third_party/webrtc/pc/sessiondescription.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
+#include "third_party/webrtc/pc/session_description.h"
namespace blink {
@@ -135,7 +138,7 @@ const char kOnlySupportedInUnifiedPlanMessage[] =
"sdpSemantics:'unified-plan' present in the RTCConfiguration argument.";
// The maximum number of PeerConnections that can exist simultaneously.
-const long kMaxPeerConnections = 500;
+const int64_t kMaxPeerConnections = 500;
bool ThrowExceptionIfSignalingStateClosed(
webrtc::PeerConnectionInterface::SignalingState state,
@@ -216,7 +219,7 @@ scoped_refptr<WebRTCICECandidate> ConvertToWebRTCIceCandidate(
const RTCIceCandidateInit* ice_candidate_init =
candidate.GetAsRTCIceCandidateInit();
// TODO(guidou): Change default value to -1. crbug.com/614958.
- unsigned short sdp_m_line_index = 0;
+ uint16_t sdp_m_line_index = 0;
if (ice_candidate_init->hasSdpMLineIndex()) {
sdp_m_line_index = ice_candidate_init->sdpMLineIndex();
} else {
@@ -255,6 +258,24 @@ SdpSemanticRequested GetSdpSemanticRequested(
return kSdpSemanticRequestedDefault;
}
+enum class OfferExtmapAllowMixedSetting {
+ kDefault,
+ kEnabled,
+ kDisabled,
+ kMaxValue = kDisabled
+};
+
+OfferExtmapAllowMixedSetting GetOfferExtmapAllowMixedSetting(
+ const blink::RTCConfiguration* configuration) {
+ if (!configuration->hasOfferExtmapAllowMixed()) {
+ return OfferExtmapAllowMixedSetting::kDefault;
+ }
+
+ return configuration->offerExtmapAllowMixed()
+ ? OfferExtmapAllowMixedSetting::kEnabled
+ : OfferExtmapAllowMixedSetting::kDisabled;
+}
+
// Helper class for RTCPeerConnection::generateCertificate.
class WebRTCCertificateObserver : public WebRTCCertificateCallback {
public:
@@ -343,6 +364,14 @@ webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration(
}
}
+ if (configuration->hasOfferExtmapAllowMixed()) {
+ web_configuration.offer_extmap_allow_mixed =
+ configuration->offerExtmapAllowMixed();
+ } else {
+ web_configuration.offer_extmap_allow_mixed =
+ base::FeatureList::IsEnabled(features::kRTCOfferExtmapAllowMixed);
+ }
+
if (configuration->hasIceServers()) {
std::vector<webrtc::PeerConnectionInterface::IceServer> ice_servers;
for (const RTCIceServer* ice_server : configuration->iceServers()) {
@@ -434,6 +463,11 @@ webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration(
static_cast<int>(configuration->rtcAudioJitterBufferMinDelayMs());
}
+ if (origin_trials::RtcAudioJitterBufferRtxHandlingEnabled(context)) {
+ UseCounter::Count(context, WebFeature::kRTCAudioJitterBufferRtxHandling);
+ web_configuration.audio_jitter_buffer_enable_rtx_handling = true;
+ }
+
return web_configuration;
}
@@ -666,7 +700,6 @@ RTCPeerConnection* RTCPeerConnection::Create(
RTCPeerConnection* peer_connection = MakeGarbageCollected<RTCPeerConnection>(
context, std::move(configuration), rtc_configuration->hasSdpSemantics(),
constraints, exception_state);
- peer_connection->PauseIfNeeded();
if (exception_state.HadException())
return nullptr;
@@ -674,6 +707,9 @@ RTCPeerConnection* RTCPeerConnection::Create(
GetSdpSemanticRequested(rtc_configuration),
kSdpSemanticRequestedMax);
+ UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.OfferExtmapAllowMixed",
+ GetOfferExtmapAllowMixedSetting(rtc_configuration));
+
return peer_connection;
}
@@ -683,20 +719,13 @@ RTCPeerConnection::RTCPeerConnection(
bool sdp_semantics_specified,
WebMediaConstraints constraints,
ExceptionState& exception_state)
- : PausableObject(context),
+ : ContextLifecycleObserver(context),
signaling_state_(
webrtc::PeerConnectionInterface::SignalingState::kStable),
ice_gathering_state_(webrtc::PeerConnectionInterface::kIceGatheringNew),
ice_connection_state_(webrtc::PeerConnectionInterface::kIceConnectionNew),
peer_connection_state_(
webrtc::PeerConnectionInterface::PeerConnectionState::kNew),
- // WebRTC spec specifies kNetworking as task source.
- // https://www.w3.org/TR/webrtc/#operation
- dispatch_scheduled_event_runner_(
- AsyncMethodRunner<RTCPeerConnection>::Create(
- this,
- &RTCPeerConnection::DispatchScheduledEvent,
- context->GetTaskRunner(TaskType::kNetworking))),
negotiation_needed_(false),
stopped_(false),
closed_(false),
@@ -760,8 +789,9 @@ RTCPeerConnection::~RTCPeerConnection() {
DCHECK(closed_ || stopped_);
InstanceCounters::DecrementCounter(
InstanceCounters::kRTCPeerConnectionCounter);
- DCHECK(InstanceCounters::CounterValue(
- InstanceCounters::kRTCPeerConnectionCounter) >= 0);
+ DCHECK_GE(InstanceCounters::CounterValue(
+ InstanceCounters::kRTCPeerConnectionCounter),
+ 0);
}
void RTCPeerConnection::Dispose() {
@@ -818,7 +848,10 @@ ScriptPromise RTCPeerConnection::createOffer(ScriptState* script_state,
context,
WebFeature::kRTCPeerConnectionCreateOfferOptionsOfferToReceive);
}
- peer_handler_->CreateOffer(request, ConvertToWebRTCOfferOptions(options));
+ auto web_transceivers =
+ peer_handler_->CreateOffer(request, ConvertToWebRTCOfferOptions(options));
+ for (auto& web_transceiver : web_transceivers)
+ CreateOrUpdateTransceiver(std::move(web_transceiver));
return promise;
}
@@ -848,6 +881,7 @@ ScriptPromise RTCPeerConnection::createOffer(
RTCCreateSessionDescriptionOperation::kCreateOffer, this,
success_callback, error_callback);
+ std::vector<std::unique_ptr<WebRTCRtpTransceiver>> web_transceivers;
if (offer_options) {
if (offer_options->OfferToReceiveAudio() != -1 ||
offer_options->OfferToReceiveVideo() != -1) {
@@ -858,7 +892,8 @@ ScriptPromise RTCPeerConnection::createOffer(
context, WebFeature::kRTCPeerConnectionCreateOfferLegacyCompliant);
}
- peer_handler_->CreateOffer(request, WebRTCOfferOptions(offer_options));
+ web_transceivers =
+ peer_handler_->CreateOffer(request, WebRTCOfferOptions(offer_options));
} else {
MediaErrorState media_error_state;
WebMediaConstraints constraints = media_constraints_impl::Create(
@@ -882,8 +917,10 @@ ScriptPromise RTCPeerConnection::createOffer(
context, WebFeature::kRTCPeerConnectionCreateOfferLegacyCompliant);
}
- peer_handler_->CreateOffer(request, constraints);
+ web_transceivers = peer_handler_->CreateOffer(request, constraints);
}
+ for (auto& web_transceiver : web_transceivers)
+ CreateOrUpdateTransceiver(std::move(web_transceiver));
return ScriptPromise::CastUndefined(script_state);
}
@@ -1134,6 +1171,49 @@ bool RTCPeerConnection::HasDocumentMedia() const {
user_media_controller->HasRequestedUserMedia();
}
+RTCDtlsTransport* RTCPeerConnection::LookupDtlsTransportByMid(String mid) {
+ if (mid.IsNull())
+ return nullptr;
+ webrtc::PeerConnectionInterface* native_pc =
+ peer_handler_->NativePeerConnection();
+ if (!native_pc)
+ return nullptr;
+ auto native_transport =
+ native_pc->LookupDtlsTransportByMid(std::string(mid.Utf8().data()));
+ if (!native_transport)
+ return nullptr;
+ // Check for previously created RTCDtlsTransport objects referencing
+ // this transport.
+ auto transport_iterator = dtls_transports_by_mid_.find(mid);
+ if (transport_iterator != dtls_transports_by_mid_.end()) {
+ if (transport_iterator->value->native_transport() !=
+ native_transport.get()) {
+ // The mid's transport has changed. Erase the reference to
+ // the old transport, and continue.
+ dtls_transports_by_mid_.erase(transport_iterator);
+ } else {
+ return transport_iterator->value;
+ }
+ }
+
+ // Check if the same transport has been returned for another mid.
+ for (auto const& transport_iterator : dtls_transports_by_mid_) {
+ if (transport_iterator.value->native_transport() ==
+ native_transport.get()) {
+ // insert might invalidate the iterator (or not), so be safe.
+ RTCDtlsTransport* transport = transport_iterator.value;
+ dtls_transports_by_mid_.insert(mid, transport);
+ return transport;
+ }
+ }
+ // The transport is previously unseen. Create object and hold on to
+ // a reference to it.
+ RTCDtlsTransport* transport = MakeGarbageCollected<RTCDtlsTransport>(
+ GetExecutionContext(), native_transport);
+ dtls_transports_by_mid_.insert(mid, transport);
+ return transport;
+}
+
void RTCPeerConnection::ReportSetSdpUsage(
SetSdpOperationType operation_type,
const RTCSessionDescriptionInit* session_description_init) const {
@@ -1753,7 +1833,6 @@ String RTCPeerConnection::iceConnectionState() const {
case webrtc::PeerConnectionInterface::kIceConnectionMax:
NOTREACHED();
}
-
NOTREACHED();
return String();
}
@@ -1914,17 +1993,14 @@ ScriptPromise RTCPeerConnection::getStats(
// Custom binding for spec-compliant "getStats(MediaStreamTrack? selector)".
// null is a valid selector value, but value of wrong type isn't. |selector|
// set to no value means type error.
- base::Optional<MediaStreamTrack*> selector;
- if (argument->IsNull()) {
- selector = base::Optional<MediaStreamTrack*>(nullptr);
- } else {
- MediaStreamTrack* track =
- V8MediaStreamTrack::ToImplWithTypeCheck(isolate, argument);
- if (track)
- selector = base::Optional<MediaStreamTrack*>(track);
- }
- if (selector.has_value())
- return PromiseBasedGetStats(script_state, *selector);
+ if (argument->IsNull())
+ return PromiseBasedGetStats(script_state, nullptr);
+
+ MediaStreamTrack* track =
+ V8MediaStreamTrack::ToImplWithTypeCheck(isolate, argument);
+ if (track)
+ return PromiseBasedGetStats(script_state, track);
+
ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
"RTCPeerConnection", "getStats");
exception_state.ThrowTypeError(
@@ -2336,8 +2412,8 @@ RTCRtpReceiver* RTCPeerConnection::CreateOrUpdateReceiver(
RTCRtpReceiver* receiver;
if (receiver_it == rtp_receivers_.end()) {
// Create new receiver.
- receiver = MakeGarbageCollected<RTCRtpReceiver>(std::move(web_receiver),
- track, MediaStreamVector());
+ receiver = MakeGarbageCollected<RTCRtpReceiver>(
+ this, std::move(web_receiver), track, MediaStreamVector());
// Receiving tracks should be muted by default. SetReadyState() propagates
// the related state changes to ensure it is muted on all layers. It also
// fires events - which is not desired - but because they fire synchronously
@@ -2573,7 +2649,7 @@ void RTCPeerConnection::DidAddReceiverPlanB(
}
DCHECK(FindReceiver(*web_receiver) == rtp_receivers_.end());
RTCRtpReceiver* rtp_receiver = MakeGarbageCollected<RTCRtpReceiver>(
- std::move(web_receiver), track, streams);
+ this, std::move(web_receiver), track, streams);
rtp_receivers_.push_back(rtp_receiver);
ScheduleDispatchEvent(MakeGarbageCollected<RTCTrackEvent>(
rtp_receiver, rtp_receiver->track(), streams, nullptr));
@@ -2794,10 +2870,8 @@ void RTCPeerConnection::ReleasePeerConnectionHandler() {
ice_connection_state_ = webrtc::PeerConnectionInterface::kIceConnectionClosed;
signaling_state_ = webrtc::PeerConnectionInterface::SignalingState::kClosed;
- dispatch_scheduled_event_runner_->Stop();
-
peer_handler_.reset();
-
+ dispatch_scheduled_events_task_handle_.Cancel();
connection_handle_for_scheduler_.reset();
}
@@ -2812,15 +2886,7 @@ const AtomicString& RTCPeerConnection::InterfaceName() const {
}
ExecutionContext* RTCPeerConnection::GetExecutionContext() const {
- return PausableObject::GetExecutionContext();
-}
-
-void RTCPeerConnection::Pause() {
- dispatch_scheduled_event_runner_->Pause();
-}
-
-void RTCPeerConnection::Unpause() {
- dispatch_scheduled_event_runner_->Unpause();
+ return ContextLifecycleObserver::GetExecutionContext();
}
void RTCPeerConnection::ContextDestroyed(ExecutionContext*) {
@@ -2952,10 +3018,20 @@ void RTCPeerConnection::ScheduleDispatchEvent(Event* event,
scheduled_events_.push_back(
MakeGarbageCollected<EventWrapper>(event, std::move(setup_function)));
- dispatch_scheduled_event_runner_->RunAsync();
+ if (dispatch_scheduled_events_task_handle_.IsActive())
+ return;
+
+ if (auto* context = GetExecutionContext()) {
+ // WebRTC spec specifies kNetworking as task source.
+ // https://www.w3.org/TR/webrtc/#operation
+ dispatch_scheduled_events_task_handle_ = PostCancellableTask(
+ *context->GetTaskRunner(TaskType::kNetworking), FROM_HERE,
+ WTF::Bind(&RTCPeerConnection::DispatchScheduledEvents,
+ WrapPersistent(this)));
+ }
}
-void RTCPeerConnection::DispatchScheduledEvent() {
+void RTCPeerConnection::DispatchScheduledEvents() {
if (stopped_)
return;
@@ -2999,10 +3075,10 @@ void RTCPeerConnection::Trace(blink::Visitor* visitor) {
visitor->Trace(rtp_senders_);
visitor->Trace(rtp_receivers_);
visitor->Trace(transceivers_);
- visitor->Trace(dispatch_scheduled_event_runner_);
visitor->Trace(scheduled_events_);
+ visitor->Trace(dtls_transports_by_mid_);
EventTargetWithInlineData::Trace(visitor);
- PausableObject::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
MediaStreamObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
index 43782a7271e..b4556cfd979 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -32,13 +32,15 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_PEER_CONNECTION_H_
#include <memory>
+#include <utility>
+#include <vector>
#include "third_party/blink/public/platform/web_media_constraints.h"
#include "third_party/blink/public/platform/web_rtc_peer_connection_handler.h"
#include "third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/crypto/normalize_algorithm.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream.h"
@@ -47,11 +49,11 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_enums.h"
-#include "third_party/blink/renderer/platform/async_method_runner.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_session_description_request.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_void_request.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
namespace blink {
@@ -60,6 +62,7 @@ class MediaStreamTrack;
class MediaStreamTrackOrString;
class RTCAnswerOptions;
class RTCConfiguration;
+class RTCDtlsTransport;
class RTCDTMFSender;
class RTCDataChannel;
class RTCDataChannelInit;
@@ -103,7 +106,7 @@ class MODULES_EXPORT RTCPeerConnection final
: public EventTargetWithInlineData,
public WebRTCPeerConnectionHandlerClient,
public ActiveScriptWrappable<RTCPeerConnection>,
- public PausableObject,
+ public ContextLifecycleObserver,
public MediaStreamObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(RTCPeerConnection);
@@ -296,9 +299,7 @@ class MODULES_EXPORT RTCPeerConnection final
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
- // PausableObject
- void Pause() override;
- void Unpause() override;
+ // ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) override;
// ScriptWrappable
@@ -332,6 +333,8 @@ class MODULES_EXPORT RTCPeerConnection final
// getUserMedia().
bool HasDocumentMedia() const;
+ // Look up, and potentially create, a DTLSTransport object.
+ RTCDtlsTransport* LookupDtlsTransportByMid(String mid);
void Trace(blink::Visitor*) override;
private:
@@ -363,7 +366,7 @@ class MODULES_EXPORT RTCPeerConnection final
void ScheduleDispatchEvent(Event*);
void ScheduleDispatchEvent(Event*, BoolFunction);
- void DispatchScheduledEvent();
+ void DispatchScheduledEvents();
void MaybeFireNegotiationNeeded();
MediaStreamTrack* GetTrack(const WebMediaStreamTrack&) const;
RTCRtpSender* FindSenderForTrackAndStream(MediaStreamTrack*, MediaStream*);
@@ -479,9 +482,14 @@ class MODULES_EXPORT RTCPeerConnection final
HeapVector<Member<RTCRtpReceiver>> rtp_receivers_;
HeapVector<Member<RTCRtpTransceiver>> transceivers_;
+ // A map of all transports that have been looked up by MID.
+ // A transport may be referenced by more than one mid, so may
+ // be present multiple times in the table.
+ HeapHashMap<String, Member<RTCDtlsTransport>> dtls_transports_by_mid_;
+
std::unique_ptr<WebRTCPeerConnectionHandler> peer_handler_;
- Member<AsyncMethodRunner<RTCPeerConnection>> dispatch_scheduled_event_runner_;
+ TaskHandle dispatch_scheduled_events_task_handle_;
HeapVector<Member<EventWrapper>> scheduled_events_;
// This handle notifies scheduler about an active connection associated
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.cc
index b09cf4dcaae..c5e426df9b0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.cc
@@ -18,7 +18,7 @@ RTCPeerConnectionController& RTCPeerConnectionController::From(
RTCPeerConnectionController* supplement =
Supplement<Document>::From<RTCPeerConnectionController>(document);
if (!supplement) {
- supplement = new RTCPeerConnectionController(document);
+ supplement = MakeGarbageCollected<RTCPeerConnectionController>(document);
Supplement<Document>::ProvideTo(document, supplement);
}
return *supplement;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.h
index 281ddbaba20..597fc11ab71 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_controller.h
@@ -38,11 +38,11 @@ class RTCPeerConnectionController
void MaybeReportComplexSdp(ComplexSdpCategory);
+ explicit RTCPeerConnectionController(Document&);
+
void Trace(Visitor*) override;
private:
- explicit RTCPeerConnectionController(Document&);
-
bool has_reported_ukm_ = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
index 0e433dd021e..40a96aba194 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
@@ -32,7 +32,7 @@
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h"
-#include "third_party/webrtc/api/rtcerror.h"
+#include "third_party/webrtc/api/rtc_error.h"
#include "v8/include/v8.h"
namespace blink {
@@ -513,6 +513,11 @@ TEST_F(RTCPeerConnectionTest, GetTrackRemoveStreamAndGCAll) {
EXPECT_TRUE(pc->GetTrack(track_component));
RemoveStream(scope, pc, stream);
+ // In Unified Plan, transceivers will still reference the stream even after
+ // it is "removed". To make the GC tests work, clear the stream from tracks
+ // so that the stream does not keep tracks alive.
+ while (!stream->getTracks().IsEmpty())
+ stream->removeTrack(stream->getTracks()[0], scope.GetExceptionState());
}
// This will destroy |MediaStream|, |MediaStreamTrack| and its
@@ -545,6 +550,11 @@ TEST_F(RTCPeerConnectionTest,
EXPECT_TRUE(pc->GetTrack(track_component.Get()));
RemoveStream(scope, pc, stream);
+ // In Unified Plan, transceivers will still reference the stream even after
+ // it is "removed". To make the GC tests work, clear the stream from tracks
+ // so that the stream does not keep tracks alive.
+ while (!stream->getTracks().IsEmpty())
+ stream->removeTrack(stream->getTracks()[0], scope.GetExceptionState());
}
// This will destroy |MediaStream| and |MediaStreamTrack| (but not
@@ -554,43 +564,6 @@ TEST_F(RTCPeerConnectionTest,
EXPECT_FALSE(pc->GetTrack(track_component.Get()));
}
-TEST_F(RTCPeerConnectionTest, GetTrackRemoveStreamAndGCWithPersistentStream) {
- V8TestingScope scope;
- Persistent<RTCPeerConnection> pc = CreatePC(scope);
- EXPECT_EQ("", GetExceptionMessage(scope));
- ASSERT_TRUE(pc);
-
- MediaStreamTrack* track =
- CreateTrack(scope, MediaStreamSource::kTypeAudio, "audioTrack");
- MediaStreamComponent* track_component = track->Component();
- Persistent<MediaStream> stream;
-
- {
- HeapVector<Member<MediaStreamTrack>> tracks;
- tracks.push_back(track);
- stream = MediaStream::Create(scope.GetExecutionContext(), tracks);
- ASSERT_TRUE(stream);
-
- EXPECT_FALSE(pc->GetTrack(track_component));
- AddStream(scope, pc, stream);
- EXPECT_TRUE(pc->GetTrack(track_component));
-
- RemoveStream(scope, pc, stream);
- }
-
- // With a persistent |MediaStream|, the |MediaStreamTrack| and
- // |MediaStreamComponent| will not be destroyed and continue to be mapped by
- // peer connection.
- WebHeap::CollectAllGarbageForTesting();
- EXPECT_TRUE(pc->GetTrack(track_component));
-
- stream = nullptr;
- // Now |MediaStream|, |MediaStreamTrack| and |MediaStreamComponent| will be
- // destroyed and the mapping removed from the peer connection.
- WebHeap::CollectAllGarbageForTesting();
- EXPECT_FALSE(pc->GetTrack(track_component));
-}
-
TEST_F(RTCPeerConnectionTest, CheckForComplexSdpWithSdpSemanticsPlanB) {
V8TestingScope scope;
Persistent<RTCPeerConnection> pc = CreatePC(scope, "plan-b");
@@ -715,16 +688,20 @@ void PostToCompleteRequest(AsyncOperationAction action,
class FakeWebRTCPeerConnectionHandler : public MockWebRTCPeerConnectionHandler {
public:
- void CreateOffer(const WebRTCSessionDescriptionRequest& request,
- const WebMediaConstraints&) override {
+ std::vector<std::unique_ptr<WebRTCRtpTransceiver>> CreateOffer(
+ const WebRTCSessionDescriptionRequest& request,
+ const WebMediaConstraints&) override {
PostToCompleteRequest<WebRTCSessionDescriptionRequest>(
async_operation_action_, request);
+ return {};
}
- void CreateOffer(const WebRTCSessionDescriptionRequest& request,
- const WebRTCOfferOptions&) override {
+ std::vector<std::unique_ptr<WebRTCRtpTransceiver>> CreateOffer(
+ const WebRTCSessionDescriptionRequest& request,
+ const WebRTCOfferOptions&) override {
PostToCompleteRequest<WebRTCSessionDescriptionRequest>(
async_operation_action_, request);
+ return {};
}
void CreateAnswer(const WebRTCSessionDescriptionRequest& request,
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc
index 5b654f4bf3b..ac4de7c5ff8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc
@@ -4,14 +4,17 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
#include "base/containers/span.h"
+#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
-const uint32_t RTCQuicStream::kWriteBufferSize = 4 * 1024;
-const uint32_t RTCQuicStream::kReadBufferSize = 4 * 1024;
+// 6 MB allows a reasonable amount to buffer on the read and write side.
+// TODO(https://crbug.com/874296): Consider exposing these configurations.
+const uint32_t RTCQuicStream::kWriteBufferSize = 6 * 1024 * 1024;
+const uint32_t RTCQuicStream::kReadBufferSize = 6 * 1024 * 1024;
class RTCQuicStream::PendingReadBufferedAmountPromise
: public GarbageCollected<PendingReadBufferedAmountPromise> {
@@ -94,6 +97,19 @@ uint32_t RTCQuicStream::maxWriteBufferedAmount() const {
return kWriteBufferSize;
}
+static ReadIntoResult GetReadIntoResult(uint32_t read_amount, bool read_fin) {
+ if (read_fin) {
+ if (read_amount > 0) {
+ return ReadIntoResult::kSomeDataWithFin;
+ }
+ return ReadIntoResult::kNoDataWithFin;
+ }
+ if (read_amount > 0) {
+ return ReadIntoResult::kSomeDataNoFin;
+ }
+ return ReadIntoResult::kNoDataNoFin;
+}
+
RTCQuicStreamReadResult* RTCQuicStream::readInto(
NotShared<DOMUint8Array> data,
ExceptionState& exception_state) {
@@ -115,52 +131,77 @@ RTCQuicStreamReadResult* RTCQuicStream::readInto(
state_ = RTCQuicStreamState::kClosing;
}
}
+ UMA_HISTOGRAM_ENUMERATION("RTCQuicStream.ReadIntoResult",
+ GetReadIntoResult(read_amount, read_fin_));
+ // Collects metrics for how large the read is. This histogram has a max of
+ // 24MB and 50 buckets.
+ UMA_HISTOGRAM_CUSTOM_COUNTS("RTCQuicStream.ReadIntoAmountBytes", read_amount,
+ 1, 24000000, 50);
auto* result = RTCQuicStreamReadResult::Create();
result->setAmount(read_amount);
result->setFinished(read_fin_);
return result;
}
-void RTCQuicStream::write(NotShared<DOMUint8Array> data,
- ExceptionState& exception_state) {
- if (RaiseIfNotWritable(exception_state)) {
- return;
- }
- if (data.View()->length() == 0) {
- return;
- }
- uint32_t remaining_write_buffer_size =
- kWriteBufferSize - writeBufferedAmount();
- if (data.View()->length() > remaining_write_buffer_size) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kOperationError,
- "The write data size of " + String::Number(data.View()->length()) +
- " bytes would exceed the remaining write buffer size of " +
- String::Number(remaining_write_buffer_size) + " bytes.");
- return;
+static WriteUsage GetWriteUsage(uint32_t write_amount, bool write_fin) {
+ // It's not possible to write nothing.
+ DCHECK(write_amount > 0 || write_fin);
+ if (write_fin) {
+ if (write_amount > 0) {
+ return WriteUsage::kSomeDataWithFin;
+ }
+ return WriteUsage::kNoDataWithFin;
}
- Vector<uint8_t> data_vector(data.View()->length());
- memcpy(data_vector.data(), data.View()->Data(), data.View()->length());
- proxy_->WriteData(std::move(data_vector), /*fin=*/false);
- write_buffered_amount_ += data.View()->length();
+ return WriteUsage::kSomeDataNoFin;
}
-void RTCQuicStream::finish() {
- if (IsClosed()) {
+void RTCQuicStream::write(const RTCQuicStreamWriteParameters* data,
+ ExceptionState& exception_state) {
+ bool finish = data->finish();
+ bool has_write_data = data->hasData() && data->data().View()->length() > 0;
+ if (!has_write_data && !finish) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "Cannot write empty data, unless data.finish is set to true.");
return;
}
- if (wrote_fin_) {
+ if (RaiseIfNotWritable(exception_state)) {
return;
}
- proxy_->WriteData({}, /*fin=*/true);
- wrote_fin_ = true;
- if (!read_fin_) {
- DCHECK_EQ(state_, RTCQuicStreamState::kOpen);
- state_ = RTCQuicStreamState::kClosing;
- RejectPendingWaitForWriteBufferedAmountBelowPromises();
- } else {
- DCHECK_EQ(state_, RTCQuicStreamState::kClosing);
- Close(CloseReason::kReadWriteFinished);
+ Vector<uint8_t> data_vector;
+ if (has_write_data) {
+ DOMUint8Array* write_data = data->data().View();
+ uint32_t remaining_write_buffer_size =
+ kWriteBufferSize - writeBufferedAmount();
+ if (write_data->length() > remaining_write_buffer_size) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kOperationError,
+ "The write data size of " + String::Number(write_data->length()) +
+ " bytes would exceed the remaining write buffer size of " +
+ String::Number(remaining_write_buffer_size) + " bytes.");
+ return;
+ }
+ data_vector.resize(write_data->length());
+ memcpy(data_vector.data(), write_data->Data(), write_data->length());
+ write_buffered_amount_ += write_data->length();
+ }
+ UMA_HISTOGRAM_ENUMERATION("RTCQuicStream.WriteUsage",
+ GetWriteUsage(data_vector.size(), finish));
+ // Collects metrics for how large the write is. This histogram has a max of
+ // 24MB and 50 buckets.
+ UMA_HISTOGRAM_CUSTOM_COUNTS("RTCQuicStream.WriteAmountBytes",
+ data_vector.size(), 1, 24000000, 50);
+ proxy_->WriteData(std::move(data_vector), finish);
+ if (finish) {
+ wrote_fin_ = true;
+ if (!read_fin_) {
+ DCHECK_EQ(state_, RTCQuicStreamState::kOpen);
+ state_ = RTCQuicStreamState::kClosing;
+ RejectPendingWaitForWriteBufferedAmountBelowPromises();
+ } else {
+ DCHECK_EQ(state_, RTCQuicStreamState::kClosing);
+ Close(CloseReason::kReadWriteFinished);
+ }
}
}
@@ -191,7 +232,8 @@ ScriptPromise RTCQuicStream::waitForReadable(ScriptState* script_state,
promise_resolver->Resolve();
} else {
pending_read_buffered_amount_promises_.push_back(
- new PendingReadBufferedAmountPromise(promise_resolver, amount));
+ MakeGarbageCollected<PendingReadBufferedAmountPromise>(promise_resolver,
+ amount));
}
return promise;
}
@@ -210,7 +252,8 @@ ScriptPromise RTCQuicStream::waitForWriteBufferedAmountBelow(
promise_resolver->Resolve();
} else {
pending_write_buffered_amount_promises_.push_back(
- new PendingWriteBufferedAmountPromise(promise_resolver, threshold));
+ MakeGarbageCollected<PendingWriteBufferedAmountPromise>(
+ promise_resolver, threshold));
}
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h
index 98a4e2941f0..b61cd28f8f7 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_read_result.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
namespace blink {
@@ -21,6 +22,35 @@ class ScriptPromise;
enum class RTCQuicStreamState { kNew, kOpening, kOpen, kClosing, kClosed };
+// This enum is used to track how the readInto() API is used in
+// the origin trial. This tracks what the result type is when reading.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ReadIntoResult {
+ // Reading data with the FIN bit (finish).
+ kSomeDataWithFin = 0,
+ // Reading data without a FIN bit (finish).
+ kSomeDataNoFin = 1,
+ // Reading just the FIN bit (finished reading).
+ kNoDataWithFin = 2,
+ // Nothing read.
+ kNoDataNoFin = 3,
+ kMaxValue = kNoDataNoFin,
+};
+
+// This enum is used to track how the write() API is used in the origin trial.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class WriteUsage {
+ // Writing data with the FIN bit (finish).
+ kSomeDataWithFin = 0,
+ // Writing data without the FIN bit (finish).
+ kSomeDataNoFin = 1,
+ // Writing only the FIN bit (finished writing).
+ kNoDataWithFin = 2,
+ kMaxValue = kNoDataWithFin,
+};
+
// The RTCQuicStream does not need to be ActiveScriptWrappable since the
// RTCQuicTransport that it is associated with holds a strong reference to it
// as long as it is not closed.
@@ -65,8 +95,8 @@ class MODULES_EXPORT RTCQuicStream final : public EventTargetWithInlineData,
uint32_t maxWriteBufferedAmount() const;
RTCQuicStreamReadResult* readInto(NotShared<DOMUint8Array> data,
ExceptionState& exception_state);
- void write(NotShared<DOMUint8Array> data, ExceptionState& exception_state);
- void finish();
+ void write(const RTCQuicStreamWriteParameters* data,
+ ExceptionState& exception_state);
void reset();
ScriptPromise waitForWriteBufferedAmountBelow(
ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl
index 6bb9b72f553..92404fba1ad 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl
@@ -14,21 +14,21 @@ enum RTCQuicStreamState {
// https://w3c.github.io/webrtc-quic/#quicstream*
[
Exposed=Window,
- RuntimeEnabled=RTCQuicTransport
+ OriginTrialEnabled=RTCQuicTransport,
+ SecureContext
] interface RTCQuicStream : EventTarget {
- readonly attribute RTCQuicTransport transport;
- readonly attribute RTCQuicStreamState state;
- readonly attribute unsigned long readBufferedAmount;
- readonly attribute unsigned long maxReadBufferedAmount;
- readonly attribute unsigned long writeBufferedAmount;
- readonly attribute unsigned long maxWriteBufferedAmount;
- [RaisesException] RTCQuicStreamReadResult readInto(Uint8Array data);
- [RaisesException] void write(Uint8Array data);
- void finish();
- void reset();
- [CallWith=ScriptState, RaisesException]
+ [Measure] readonly attribute RTCQuicTransport transport;
+ [Measure] readonly attribute RTCQuicStreamState state;
+ [Measure] readonly attribute unsigned long readBufferedAmount;
+ [Measure] readonly attribute unsigned long maxReadBufferedAmount;
+ [Measure] readonly attribute unsigned long writeBufferedAmount;
+ [Measure] readonly attribute unsigned long maxWriteBufferedAmount;
+ [Measure, RaisesException] RTCQuicStreamReadResult readInto(Uint8Array data);
+ [Measure, RaisesException] void write(RTCQuicStreamWriteParameters data);
+ [Measure] void reset();
+ [CallWith=ScriptState, Measure, RaisesException]
Promise<void> waitForWriteBufferedAmountBelow(unsigned long amount);
- [CallWith=ScriptState, RaisesException]
+ [CallWith=ScriptState, Measure, RaisesException]
Promise<void> waitForReadable(unsigned long amount);
attribute EventHandler onstatechange;
// TODO(crbug.com/868068): Implement remaining methods, attributes, and events.
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc
index b7a102ba6ac..f6eaaba0657 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc
@@ -9,13 +9,13 @@
namespace blink {
RTCQuicStreamEvent* RTCQuicStreamEvent::Create(RTCQuicStream* stream) {
- return new RTCQuicStreamEvent(stream);
+ return MakeGarbageCollected<RTCQuicStreamEvent>(stream);
}
RTCQuicStreamEvent* RTCQuicStreamEvent::Create(
const AtomicString& type,
const RTCQuicStreamEventInit* initializer) {
- return new RTCQuicStreamEvent(type, initializer);
+ return MakeGarbageCollected<RTCQuicStreamEvent>(type, initializer);
}
RTCQuicStreamEvent::RTCQuicStreamEvent(RTCQuicStream* stream)
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h
index 227b68cfc3f..8f924f93335 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h
@@ -20,6 +20,9 @@ class MODULES_EXPORT RTCQuicStreamEvent final : public Event {
static RTCQuicStreamEvent* Create(const AtomicString& type,
const RTCQuicStreamEventInit* init);
+ RTCQuicStreamEvent(RTCQuicStream* stream);
+ RTCQuicStreamEvent(const AtomicString& type,
+ const RTCQuicStreamEventInit* init);
~RTCQuicStreamEvent() override;
// rtc_quic_stream_event.idl
@@ -32,10 +35,6 @@ class MODULES_EXPORT RTCQuicStreamEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- RTCQuicStreamEvent(RTCQuicStream* stream);
- RTCQuicStreamEvent(const AtomicString& type,
- const RTCQuicStreamEventInit* init);
-
Member<RTCQuicStream> stream_;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl
index ced237c75eb..d37709827f8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl
@@ -4,7 +4,7 @@
// https://w3c.github.io/webrtc-quic/#rtcquicstreamevent
[
- RuntimeEnabled=RTCQuicTransport,
+ OriginTrialEnabled=RTCQuicTransport,
Constructor(DOMString type, optional RTCQuicStreamEventInit eventInitDict),
Exposed=Window
] interface RTCQuicStreamEvent : Event {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc
index 5392c2b8882..8ae23b737d4 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc
@@ -8,6 +8,8 @@
// for the main thread / worker thread.
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
+#include <memory>
+#include "base/test/metrics/histogram_tester.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h"
@@ -22,13 +24,32 @@ using testing::InvokeWithoutArgs;
using testing::Return;
using testing::SaveArg;
-NotShared<DOMUint8Array> CreateUint8Array(const Vector<uint8_t>& data) {
- return NotShared<DOMUint8Array>(
- DOMUint8Array::Create(data.data(), data.size()));
+RTCQuicStreamWriteParameters* CreateWriteParametersWithData(
+ const Vector<uint8_t>& data) {
+ RTCQuicStreamWriteParameters* write_parameters =
+ RTCQuicStreamWriteParameters::Create();
+ write_parameters->setData(NotShared<DOMUint8Array>(
+ DOMUint8Array::Create(data.data(), data.size())));
+ write_parameters->setFinish(false);
+ return write_parameters;
}
-NotShared<DOMUint8Array> CreateUint8ArrayOfLength(uint32_t length) {
- return NotShared<DOMUint8Array>(DOMUint8Array::Create(length));
+RTCQuicStreamWriteParameters* CreateWriteParametersWithDataOfLength(
+ uint32_t length,
+ bool finish = false) {
+ RTCQuicStreamWriteParameters* write_parameters =
+ RTCQuicStreamWriteParameters::Create();
+ write_parameters->setData(
+ NotShared<DOMUint8Array>(DOMUint8Array::Create(length)));
+ write_parameters->setFinish(finish);
+ return write_parameters;
+}
+
+RTCQuicStreamWriteParameters* CreateWriteParametersWithoutData(bool finish) {
+ RTCQuicStreamWriteParameters* write_parameters =
+ RTCQuicStreamWriteParameters::Create();
+ write_parameters->setFinish(finish);
+ return write_parameters;
}
} // namespace
@@ -150,6 +171,8 @@ TEST_F(RTCQuicStreamTest, OnRemoteResetFiresStateChangeToClosed) {
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnRemoteReset();
RunUntilIdle();
@@ -184,6 +207,8 @@ TEST_F(RTCQuicStreamTest, PendingOnRemoteResetIgnoredAfterReset) {
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnRemoteReset();
quic_stream->reset();
EXPECT_EQ("closed", quic_stream->state());
@@ -193,7 +218,7 @@ TEST_F(RTCQuicStreamTest, PendingOnRemoteResetIgnoredAfterReset) {
EXPECT_EQ("closed", quic_stream->state());
}
-// The following group tests write(), finish(), writeBufferedAmount(), and
+// The following group tests write(), writeBufferedAmount(), and
// maxWriteBufferdAmount().
// Test that write() adds to writeBufferedAmount().
@@ -204,10 +229,10 @@ TEST_F(RTCQuicStreamTest, WriteAddsToWriteBufferedAmount) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8Array({1, 2}), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithData({1, 2}), ASSERT_NO_EXCEPTION);
EXPECT_EQ(2u, stream->writeBufferedAmount());
- stream->write(CreateUint8Array({3, 4, 5}), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithData({3, 4, 5}), ASSERT_NO_EXCEPTION);
EXPECT_EQ(5u, stream->writeBufferedAmount());
RunUntilIdle();
@@ -226,14 +251,15 @@ TEST_F(RTCQuicStreamTest, WriteCallsWriteData) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8Array({1, 2, 3, 4}), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithData({1, 2, 3, 4}),
+ ASSERT_NO_EXCEPTION);
RunUntilIdle();
}
-// Test that write() with no data succeeds but does not post a WriteData() to
-// the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, WriteWithEmptyArrayDoesNotCallWriteData) {
+// Test that write() with no data throws a NotSupportedError and does not post a
+// WriteData() to the underlying P2PQuicStream.
+TEST_F(RTCQuicStreamTest, WriteWithoutDataThrowsNotSupportedError) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
@@ -241,13 +267,17 @@ TEST_F(RTCQuicStreamTest, WriteWithEmptyArrayDoesNotCallWriteData) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8Array({}), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithoutData(/*finish=*/false),
+ scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kNotSupportedError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
RunUntilIdle();
}
-// Test that finish() calls WriteData() on the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, FinishCallsWriteData) {
+// Test that writing a finish without data calls WriteData() on the underlying
+// P2PQuicStream.
+TEST_F(RTCQuicStreamTest, WriteFinishWithoutDataCallsWriteData) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
@@ -259,7 +289,8 @@ TEST_F(RTCQuicStreamTest, FinishCallsWriteData) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->finish();
+ stream->write(CreateWriteParametersWithoutData(/*finish=*/true),
+ ASSERT_NO_EXCEPTION);
RunUntilIdle();
}
@@ -274,7 +305,7 @@ TEST_F(RTCQuicStreamTest, OnWriteDataConsumedSubtractsFromWriteBufferedAmount) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(4), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithDataOfLength(4), ASSERT_NO_EXCEPTION);
RunUntilIdle();
@@ -296,11 +327,13 @@ TEST_F(RTCQuicStreamTest, OnRemoteResetSetsWriteBufferedAmountToZero) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(4), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithDataOfLength(4), ASSERT_NO_EXCEPTION);
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnRemoteReset();
RunUntilIdle();
@@ -310,8 +343,9 @@ TEST_F(RTCQuicStreamTest, OnRemoteResetSetsWriteBufferedAmountToZero) {
RunUntilIdle();
}
-// Test that writeBufferedAmount is set to 0 if the stream calls finish(),
-// followed by receiving a finish from the remote side, and reading it out.
+// Test that writeBufferedAmount is set to 0 if the stream calls write() with
+// a finish, followed by receiving a finish from the remote side, and reading
+// it out.
//
// TODO(https://crbug.com/874296): It doesn't really make sense the write buffer
// gets cleared in this case. Consider changing this.
@@ -324,12 +358,14 @@ TEST_F(RTCQuicStreamTest,
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(4), ASSERT_NO_EXCEPTION);
- stream->finish();
+ stream->write(CreateWriteParametersWithDataOfLength(4, /*finish=*/true),
+ ASSERT_NO_EXCEPTION);
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnDataReceived({}, /*fin=*/true);
RunUntilIdle();
@@ -356,11 +392,14 @@ TEST_F(RTCQuicStreamTest, WriteThrowsIfRemoteReset) {
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnRemoteReset();
RunUntilIdle();
- stream->write(CreateUint8ArrayOfLength(1), scope.GetExceptionState());
+ stream->write(CreateWriteParametersWithDataOfLength(1),
+ scope.GetExceptionState());
EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
scope.GetExceptionState().CodeAs<DOMExceptionCode>());
@@ -379,8 +418,10 @@ TEST_F(RTCQuicStreamTest, WaitForWriteBufferedAmountBelowResolves) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(stream->maxWriteBufferedAmount()),
- ASSERT_NO_EXCEPTION);
+
+ stream->write(
+ CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
+ ASSERT_NO_EXCEPTION);
ScriptPromise promise = stream->waitForWriteBufferedAmountBelow(
scope.GetScriptState(), stream->maxWriteBufferedAmount() - 1,
@@ -410,8 +451,9 @@ TEST_F(RTCQuicStreamTest,
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(stream->maxWriteBufferedAmount()),
- ASSERT_NO_EXCEPTION);
+ stream->write(
+ CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
+ ASSERT_NO_EXCEPTION);
ScriptPromise promise = stream->waitForWriteBufferedAmountBelow(
scope.GetScriptState(), stream->maxWriteBufferedAmount() - 10,
@@ -455,8 +497,9 @@ TEST_F(RTCQuicStreamTest,
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(stream->maxWriteBufferedAmount()),
- ASSERT_NO_EXCEPTION);
+ stream->write(
+ CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
+ ASSERT_NO_EXCEPTION);
ScriptPromise promise_10 = stream->waitForWriteBufferedAmountBelow(
scope.GetScriptState(), stream->maxWriteBufferedAmount() - 10,
@@ -497,8 +540,9 @@ TEST_F(RTCQuicStreamTest,
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(stream->maxWriteBufferedAmount()),
- ASSERT_NO_EXCEPTION);
+ stream->write(
+ CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
+ ASSERT_NO_EXCEPTION);
ScriptPromise promise_10 = stream->waitForWriteBufferedAmountBelow(
scope.GetScriptState(), stream->maxWriteBufferedAmount() - 10,
@@ -531,8 +575,9 @@ TEST_F(RTCQuicStreamTest,
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(stream->maxWriteBufferedAmount()),
- ASSERT_NO_EXCEPTION);
+ stream->write(
+ CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
+ ASSERT_NO_EXCEPTION);
ScriptPromise promise = stream->waitForWriteBufferedAmountBelow(
scope.GetScriptState(), 0, ASSERT_NO_EXCEPTION);
@@ -540,6 +585,8 @@ TEST_F(RTCQuicStreamTest,
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnRemoteReset();
RunUntilIdle();
@@ -561,8 +608,9 @@ TEST_F(
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->write(CreateUint8ArrayOfLength(stream->maxWriteBufferedAmount()),
- ASSERT_NO_EXCEPTION);
+ stream->write(
+ CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
+ ASSERT_NO_EXCEPTION);
stream->waitForWriteBufferedAmountBelow(scope.GetScriptState(), 0,
ASSERT_NO_EXCEPTION);
@@ -734,7 +782,7 @@ TEST_F(RTCQuicStreamTest, ReadIntoReadsBufferedDataAndFinish) {
}
// Test that readInto() does not indicate finished until all buffered data has
-// been read out, even if the fin has already been received.
+// been read out, even if the finish has already been received.
TEST_F(RTCQuicStreamTest, ReadIntoReadsPartialDataBeforeFin) {
V8TestingScope scope;
@@ -842,6 +890,8 @@ TEST_F(RTCQuicStreamTest, ReadIntoThrowsIfClosed) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream->reset();
NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(2));
@@ -1084,8 +1134,8 @@ TEST_F(RTCQuicStreamTest, WaitForReadableResolvesImmediatelyIfRemoteFinished) {
promise.V8Value().As<v8::Promise>()->State());
}
-// The following group tests state transitions with reset(), finish(), remote
-// reset() and remote finish()
+// The following group tests state transitions with reset(), write() with a
+// finish, remote reset() and remote write() with a finish.
// Test that a OnRemoteReset() immediately transitions the state to 'closed'.
TEST_F(RTCQuicStreamTest, OnRemoteResetTransitionsToClosed) {
@@ -1100,6 +1150,8 @@ TEST_F(RTCQuicStreamTest, OnRemoteResetTransitionsToClosed) {
ASSERT_TRUE(stream_delegate);
EXPECT_EQ("open", stream->state());
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnRemoteReset();
RunUntilIdle();
@@ -1109,7 +1161,7 @@ TEST_F(RTCQuicStreamTest, OnRemoteResetTransitionsToClosed) {
RunUntilIdle();
}
-// Test that calling finish() after reading out a remote finish transitions
+// Test that writing a finish after reading out a remote finish transitions
// state to 'closed'.
TEST_F(RTCQuicStreamTest, FinishAfterReadingRemoteFinishTransitionsToClosed) {
V8TestingScope scope;
@@ -1131,15 +1183,17 @@ TEST_F(RTCQuicStreamTest, FinishAfterReadingRemoteFinishTransitionsToClosed) {
EXPECT_TRUE(stream->readInto(read_buffer, ASSERT_NO_EXCEPTION)->finished());
EXPECT_EQ("closing", stream->state());
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
- stream->finish();
+ stream->write(CreateWriteParametersWithoutData(/*finish=*/true),
+ ASSERT_NO_EXCEPTION);
EXPECT_EQ("closed", stream->state());
RunUntilIdle();
}
-// Test that reading out a remote finish after calling finish() transitions
+// Test that reading out a remote finish after writing a finish transitions
// state to 'closed'.
TEST_F(RTCQuicStreamTest, ReadingRemoteFinishAfterFinishTransitionsToClosed) {
V8TestingScope scope;
@@ -1150,13 +1204,16 @@ TEST_F(RTCQuicStreamTest, ReadingRemoteFinishAfterFinishTransitionsToClosed) {
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
- stream->finish();
+ stream->write(CreateWriteParametersWithoutData(/*finish=*/true),
+ ASSERT_NO_EXCEPTION);
EXPECT_EQ("closing", stream->state());
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
+ EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
+
stream_delegate->OnDataReceived({}, /*fin=*/true);
RunUntilIdle();
@@ -1169,4 +1226,205 @@ TEST_F(RTCQuicStreamTest, ReadingRemoteFinishAfterFinishTransitionsToClosed) {
EXPECT_EQ("closed", stream->state());
}
+TEST_F(RTCQuicStreamTest, HistogramWriteUsageOnlyData) {
+ V8TestingScope scope;
+
+ auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream =
+ CreateQuicStream(scope, p2p_quic_stream.get());
+
+ base::HistogramTester tester;
+ stream->write(CreateWriteParametersWithDataOfLength(2), ASSERT_NO_EXCEPTION);
+ stream->write(CreateWriteParametersWithDataOfLength(2), ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.WriteUsage",
+ WriteUsage::kSomeDataNoFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramWriteUsageDataWithFin) {
+ V8TestingScope scope;
+
+ auto p2p_quic_stream_1 = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream_1 =
+ CreateQuicStream(scope, p2p_quic_stream_1.get());
+ auto p2p_quic_stream_2 = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream_2 =
+ CreateQuicStream(scope, p2p_quic_stream_2.get());
+
+ base::HistogramTester tester;
+ stream_1->write(CreateWriteParametersWithDataOfLength(2, /*finish=*/true),
+ ASSERT_NO_EXCEPTION);
+ stream_2->write(CreateWriteParametersWithDataOfLength(2, /*finish=*/true),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.WriteUsage",
+ WriteUsage::kSomeDataWithFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramWriteUsageDataOnlyFin) {
+ V8TestingScope scope;
+
+ auto p2p_quic_stream_1 = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream_1 =
+ CreateQuicStream(scope, p2p_quic_stream_1.get());
+ auto p2p_quic_stream_2 = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream_2 =
+ CreateQuicStream(scope, p2p_quic_stream_2.get());
+
+ base::HistogramTester tester;
+ stream_1->write(CreateWriteParametersWithoutData(/*finish=*/true),
+ ASSERT_NO_EXCEPTION);
+ stream_2->write(CreateWriteParametersWithoutData(/*finish=*/true),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.WriteUsage",
+ WriteUsage::kNoDataWithFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramWriteAmountBytes) {
+ V8TestingScope scope;
+
+ auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream =
+ CreateQuicStream(scope, p2p_quic_stream.get());
+
+ base::HistogramTester tester;
+ stream->write(CreateWriteParametersWithDataOfLength(4), ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ // Expect that 4 bytes were written once.
+ tester.ExpectBucketCount("RTCQuicStream.WriteAmountBytes", 4, 1);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramReadIntoResultOnlyData) {
+ V8TestingScope scope;
+
+ P2PQuicStream::Delegate* stream_delegate = nullptr;
+ auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
+ Persistent<RTCQuicStream> stream =
+ CreateQuicStream(scope, p2p_quic_stream.get());
+ RunUntilIdle();
+
+ ASSERT_TRUE(stream_delegate);
+ stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
+ RunUntilIdle();
+
+ base::HistogramTester tester;
+ stream->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(2)),
+ ASSERT_NO_EXCEPTION);
+ stream->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(1)),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.ReadIntoResult",
+ ReadIntoResult::kSomeDataNoFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramReadIntoResultDataWithFin) {
+ V8TestingScope scope;
+
+ P2PQuicStream::Delegate* stream_delegate_1 = nullptr;
+ auto p2p_quic_stream_1 =
+ std::make_unique<MockP2PQuicStream>(&stream_delegate_1);
+ Persistent<RTCQuicStream> stream_1 =
+ CreateQuicStream(scope, p2p_quic_stream_1.get());
+ P2PQuicStream::Delegate* stream_delegate_2 = nullptr;
+ auto p2p_quic_stream_2 =
+ std::make_unique<MockP2PQuicStream>(&stream_delegate_2);
+ Persistent<RTCQuicStream> stream_2 =
+ CreateQuicStream(scope, p2p_quic_stream_2.get());
+ RunUntilIdle();
+
+ ASSERT_TRUE(stream_delegate_1);
+ ASSERT_TRUE(stream_delegate_2);
+ stream_delegate_1->OnDataReceived({1, 2, 3}, /*fin=*/true);
+ stream_delegate_2->OnDataReceived({1, 2, 3}, /*fin=*/true);
+ RunUntilIdle();
+
+ base::HistogramTester tester;
+ stream_1->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(4)),
+ ASSERT_NO_EXCEPTION);
+ stream_2->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(4)),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.ReadIntoResult",
+ ReadIntoResult::kSomeDataWithFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramReadIntoResultOnlyFin) {
+ V8TestingScope scope;
+
+ P2PQuicStream::Delegate* stream_delegate_1 = nullptr;
+ auto p2p_quic_stream_1 =
+ std::make_unique<MockP2PQuicStream>(&stream_delegate_1);
+ Persistent<RTCQuicStream> stream_1 =
+ CreateQuicStream(scope, p2p_quic_stream_1.get());
+ P2PQuicStream::Delegate* stream_delegate_2 = nullptr;
+ auto p2p_quic_stream_2 =
+ std::make_unique<MockP2PQuicStream>(&stream_delegate_2);
+ Persistent<RTCQuicStream> stream_2 =
+ CreateQuicStream(scope, p2p_quic_stream_2.get());
+ RunUntilIdle();
+
+ ASSERT_TRUE(stream_delegate_1);
+ ASSERT_TRUE(stream_delegate_2);
+ stream_delegate_1->OnDataReceived({}, /*fin=*/true);
+ stream_delegate_2->OnDataReceived({}, /*fin=*/true);
+ RunUntilIdle();
+
+ base::HistogramTester tester;
+ stream_1->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(0)),
+ ASSERT_NO_EXCEPTION);
+ stream_2->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(0)),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.ReadIntoResult",
+ ReadIntoResult::kNoDataWithFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramReadIntoResultNothing) {
+ V8TestingScope scope;
+
+ auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
+ Persistent<RTCQuicStream> stream =
+ CreateQuicStream(scope, p2p_quic_stream.get());
+
+ base::HistogramTester tester;
+ stream->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(0)),
+ ASSERT_NO_EXCEPTION);
+ stream->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(0)),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ tester.ExpectUniqueSample("RTCQuicStream.ReadIntoResult",
+ ReadIntoResult::kNoDataNoFin, 2);
+}
+
+TEST_F(RTCQuicStreamTest, HistogramReadCount) {
+ V8TestingScope scope;
+
+ P2PQuicStream::Delegate* stream_delegate = nullptr;
+ auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
+ Persistent<RTCQuicStream> stream =
+ CreateQuicStream(scope, p2p_quic_stream.get());
+ RunUntilIdle();
+
+ ASSERT_TRUE(stream_delegate);
+ stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
+ RunUntilIdle();
+
+ base::HistogramTester tester;
+ stream->readInto(NotShared<DOMUint8Array>(DOMUint8Array::Create(3)),
+ ASSERT_NO_EXCEPTION);
+ RunUntilIdle();
+
+ // Expect that the 3 bytes recorded has a count of 1.
+ tester.ExpectBucketCount("RTCQuicStream.ReadIntoAmountBytes", 3, 1);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl
new file mode 100644
index 00000000000..2d8d47c2c4d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://w3c.github.io/webrtc-quic/#dom-rtcquicstreamwriteparameters
+dictionary RTCQuicStreamWriteParameters {
+ Uint8Array data;
+ boolean finish = false;
+};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
index 77a09482c0a..0f5037361c7 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
@@ -8,6 +8,7 @@
#include "net/third_party/quic/platform/impl/quic_chromium_clock.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -16,9 +17,12 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.h"
namespace blink {
namespace {
+// QUIC requires 128 bits of entropy for the pre shared key.
+const size_t kPreSharedKeyLength = 128 / 8;
// This class wraps a P2PQuicTransportFactoryImpl but does not construct it
// until CreateQuicTransport is called for the first time. This ensures that it
@@ -60,6 +64,12 @@ class DefaultP2PQuicTransportFactory : public P2PQuicTransportFactory {
} // namespace
+RTCQuicTransport* RTCQuicTransport::Create(ExecutionContext* context,
+ RTCIceTransport* transport,
+ ExceptionState& exception_state) {
+ return Create(context, transport, {}, exception_state);
+}
+
RTCQuicTransport* RTCQuicTransport::Create(
ExecutionContext* context,
RTCIceTransport* transport,
@@ -80,9 +90,9 @@ RTCQuicTransport* RTCQuicTransport::Create(
DCHECK(transport);
DCHECK(p2p_quic_transport_factory);
if (transport->IsClosed()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- "Cannot construct an RTCQuicTransport with a closed RTCIceTransport.");
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Cannot construct an RTCQuicTransport "
+ "with a closed RTCIceTransport.");
return nullptr;
}
if (transport->HasConsumer()) {
@@ -95,25 +105,33 @@ RTCQuicTransport* RTCQuicTransport::Create(
for (const auto& certificate : certificates) {
if (certificate->expires() < ConvertSecondsToDOMTimeStamp(CurrentTime())) {
exception_state.ThrowTypeError(
- "Cannot construct an RTCQuicTransport with an expired certificate.");
+ "Cannot construct an RTCQuicTransport with an expired "
+ "certificate.");
return nullptr;
}
}
+ uint8_t generated_key[kPreSharedKeyLength];
+ quic::QuicRandom::GetInstance()->RandBytes(generated_key,
+ base::size(generated_key));
return MakeGarbageCollected<RTCQuicTransport>(
- context, transport, certificates, exception_state,
- std::move(p2p_quic_transport_factory));
+ context, transport,
+ DOMArrayBuffer::Create(generated_key, base::size(generated_key)),
+ certificates, exception_state, std::move(p2p_quic_transport_factory));
}
RTCQuicTransport::RTCQuicTransport(
ExecutionContext* context,
RTCIceTransport* transport,
+ DOMArrayBuffer* key,
const HeapVector<Member<RTCCertificate>>& certificates,
ExceptionState& exception_state,
std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory)
: ContextClient(context),
transport_(transport),
+ key_(key),
certificates_(certificates),
p2p_quic_transport_factory_(std::move(p2p_quic_transport_factory)) {
+ DCHECK_GT(key_->ByteLength(), 0u);
transport->ConnectConsumer(this);
}
@@ -141,6 +159,44 @@ String RTCQuicTransport::state() const {
return String();
}
+DOMArrayBuffer* RTCQuicTransport::getKey() const {
+ return DOMArrayBuffer::Create(key_->Data(), key_->ByteLength());
+}
+
+void RTCQuicTransport::connect(ExceptionState& exception_state) {
+ if (RaiseExceptionIfClosed(exception_state)) {
+ return;
+ }
+ if (RaiseExceptionIfStarted(exception_state)) {
+ return;
+ }
+ start_reason_ = StartReason::kClientConnecting;
+ std::string pre_shared_key(static_cast<const char*>(key_->Data()),
+ key_->ByteLength());
+ StartConnection(quic::Perspective::IS_CLIENT,
+ P2PQuicTransport::StartConfig(pre_shared_key));
+}
+
+void RTCQuicTransport::listen(const DOMArrayPiece& remote_key,
+ ExceptionState& exception_state) {
+ if (remote_key.ByteLength() == 0u) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ "Cannot listen with an empty key.");
+ return;
+ }
+ if (RaiseExceptionIfClosed(exception_state)) {
+ return;
+ }
+ if (RaiseExceptionIfStarted(exception_state)) {
+ return;
+ }
+ start_reason_ = StartReason::kServerListening;
+ std::string pre_shared_key(static_cast<const char*>(remote_key.Data()),
+ remote_key.ByteLength());
+ StartConnection(quic::Perspective::IS_SERVER,
+ P2PQuicTransport::StartConfig(pre_shared_key));
+}
+
RTCQuicParameters* RTCQuicTransport::getLocalParameters() const {
RTCQuicParameters* result = RTCQuicParameters::Create();
@@ -184,22 +240,6 @@ static quic::Perspective QuicPerspectiveFromIceRole(cricket::IceRole ice_role) {
return quic::Perspective::IS_CLIENT;
}
-void RTCQuicTransport::start(const RTCQuicParameters* remote_parameters,
- ExceptionState& exception_state) {
- if (RaiseExceptionIfClosed(exception_state)) {
- return;
- }
- if (remote_parameters_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Cannot start() multiple times.");
- return;
- }
- remote_parameters_ = const_cast<RTCQuicParameters*>(remote_parameters);
- if (transport_->IsStarted()) {
- StartConnection();
- }
-}
-
static std::unique_ptr<rtc::SSLFingerprint> RTCDtlsFingerprintToSSLFingerprint(
const RTCDtlsFingerprint* dtls_fingerprint) {
std::string algorithm = WebString(dtls_fingerprint->algorithm()).Utf8();
@@ -210,45 +250,77 @@ static std::unique_ptr<rtc::SSLFingerprint> RTCDtlsFingerprintToSSLFingerprint(
return rtc_fingerprint;
}
-void RTCQuicTransport::StartConnection() {
+void RTCQuicTransport::start(RTCQuicParameters* remote_parameters,
+ ExceptionState& exception_state) {
+ if (RaiseExceptionIfClosed(exception_state)) {
+ return;
+ }
+ if (RaiseExceptionIfStarted(exception_state)) {
+ return;
+ }
+ remote_parameters_ = remote_parameters;
+ start_reason_ = StartReason::kP2PWithRemoteFingerprints;
+ if (transport_->IsStarted()) {
+ std::vector<std::unique_ptr<rtc::SSLFingerprint>> rtc_fingerprints;
+ for (const RTCDtlsFingerprint* fingerprint :
+ remote_parameters_->fingerprints()) {
+ rtc_fingerprints.push_back(
+ RTCDtlsFingerprintToSSLFingerprint(fingerprint));
+ };
+ StartConnection(QuicPerspectiveFromIceRole(transport_->GetRole()),
+ P2PQuicTransport::StartConfig(std::move(rtc_fingerprints)));
+ }
+}
+
+void RTCQuicTransport::StartConnection(
+ quic::Perspective perspective,
+ P2PQuicTransport::StartConfig start_config) {
DCHECK_EQ(state_, RTCQuicTransportState::kNew);
- DCHECK(remote_parameters_);
+ DCHECK_NE(start_reason_, StartReason::kNotStarted);
state_ = RTCQuicTransportState::kConnecting;
-
+ // We don't create the underlying transports until we are starting
+ // to connect.
std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> rtc_certificates;
for (const auto& certificate : certificates_) {
rtc_certificates.push_back(certificate->Certificate());
}
IceTransportProxy* transport_proxy = transport_->ConnectConsumer(this);
- // TODO(https://crbug.com/874296): Use the proper read/write buffer sizees
- // once write() and readInto() are implemented.
- const uint32_t stream_buffer_size = 24 * 1024 * 1024;
P2PQuicTransportConfig quic_transport_config(
- QuicPerspectiveFromIceRole(transport_->GetRole()), rtc_certificates,
- /*stream_delegate_read_buffer_size_in=*/stream_buffer_size,
- /*stream_write_buffer_size_in=*/stream_buffer_size);
+ perspective, rtc_certificates,
+ /*stream_delegate_read_buffer_size_in=*/RTCQuicStream::kReadBufferSize,
+ /*stream_write_buffer_size_in=*/RTCQuicStream::kWriteBufferSize);
proxy_.reset(new QuicTransportProxy(this, transport_proxy,
std::move(p2p_quic_transport_factory_),
quic_transport_config));
-
- std::vector<std::unique_ptr<rtc::SSLFingerprint>> rtc_fingerprints;
- for (const RTCDtlsFingerprint* fingerprint :
- remote_parameters_->fingerprints()) {
- rtc_fingerprints.push_back(RTCDtlsFingerprintToSSLFingerprint(fingerprint));
- }
- proxy_->Start(std::move(rtc_fingerprints));
+ proxy_->Start(std::move(start_config));
}
void RTCQuicTransport::OnIceTransportStarted() {
- // The RTCIceTransport has now been started.
- if (remote_parameters_) {
- StartConnection();
+ // If start() has already been called, we now start up the connection,
+ // since start() determines its quic::Perspective based upon ICE.
+ if (start_reason_ == StartReason::kP2PWithRemoteFingerprints) {
+ DCHECK(remote_parameters_);
+ std::vector<std::unique_ptr<rtc::SSLFingerprint>> rtc_fingerprints;
+ for (const RTCDtlsFingerprint* fingerprint :
+ remote_parameters_->fingerprints()) {
+ rtc_fingerprints.push_back(
+ RTCDtlsFingerprintToSSLFingerprint(fingerprint));
+ };
+ StartConnection(QuicPerspectiveFromIceRole(transport_->GetRole()),
+ P2PQuicTransport::StartConfig(std::move(rtc_fingerprints)));
}
}
void RTCQuicTransport::stop() {
if (IsClosed()) {
+ // The transport could have already been closed due to the context being
+ // destroyed, the RTCIceTransport closing or a remote/local stop().
+ return;
+ }
+ if (IsDisposed()) {
+ // This occurs in the "failed" state.
+ state_ = RTCQuicTransportState::kClosed;
return;
}
Close(CloseReason::kLocalStopped);
@@ -266,8 +338,29 @@ RTCQuicStream* RTCQuicTransport::createStream(ExceptionState& exception_state) {
return AddStream(proxy_->CreateStream());
}
+ScriptPromise RTCQuicTransport::getStats(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ // TODO(https://crbug.com/874296): If a shutdown procedure is implemented, we
+ // can cache the stats before the underlying transport is torn down. This
+ // would allow getting stats after your transport has closed.
+ if (state_ != RTCQuicTransportState::kConnected &&
+ state_ != RTCQuicTransportState::kConnecting) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The RTCQuicTransport's state is not 'connecting' or 'connected'.");
+ return ScriptPromise();
+ }
+ ScriptPromiseResolver* promise_resolver =
+ ScriptPromiseResolver::Create(script_state);
+ uint32_t request_id = ++get_stats_id_counter_;
+ stats_promise_map_.Set(request_id, promise_resolver);
+ proxy_->GetStats(request_id);
+ return promise_resolver->Promise();
+}
+
RTCQuicStream* RTCQuicTransport::AddStream(QuicStreamProxy* stream_proxy) {
- auto* stream = new RTCQuicStream(GetExecutionContext(), this, stream_proxy);
+ auto* stream = MakeGarbageCollected<RTCQuicStream>(GetExecutionContext(),
+ this, stream_proxy);
stream_proxy->set_delegate(stream);
streams_.insert(stream);
return stream;
@@ -299,6 +392,48 @@ void RTCQuicTransport::OnStream(QuicStreamProxy* stream_proxy) {
DispatchEvent(*RTCQuicStreamEvent::Create(stream));
}
+static RTCQuicTransportStats* CreateRTCQuicTransportStats(
+ const P2PQuicTransportStats& p2p_stats) {
+ RTCQuicTransportStats* rtc_stats = RTCQuicTransportStats::Create();
+ rtc_stats->setTimestamp(
+ ConvertTimeTicksToDOMHighResTimeStamp(p2p_stats.timestamp));
+ rtc_stats->setBytesSent(p2p_stats.bytes_sent);
+ rtc_stats->setPacketsSent(p2p_stats.packets_sent);
+ rtc_stats->setStreamBytesSent(p2p_stats.stream_bytes_sent);
+ rtc_stats->setStreamBytesReceived(p2p_stats.stream_bytes_received);
+ rtc_stats->setNumOutgoingStreamsCreated(
+ p2p_stats.num_outgoing_streams_created);
+ rtc_stats->setNumIncomingStreamsCreated(
+ p2p_stats.num_incoming_streams_created);
+ rtc_stats->setBytesReceived(p2p_stats.bytes_received);
+ rtc_stats->setPacketsReceived(p2p_stats.packets_received);
+ rtc_stats->setPacketsProcessed(p2p_stats.packets_processed);
+ rtc_stats->setBytesRetransmitted(p2p_stats.bytes_retransmitted);
+ rtc_stats->setPacketsRetransmitted(p2p_stats.packets_retransmitted);
+ rtc_stats->setPacketsLost(p2p_stats.packets_lost);
+ rtc_stats->setPacketsDropped(p2p_stats.packets_dropped);
+ rtc_stats->setCryptoRetransmitCount(p2p_stats.crypto_retransmit_count);
+ rtc_stats->setMinRttUs(p2p_stats.min_rtt_us);
+ rtc_stats->setSmoothedRttUs(p2p_stats.srtt_us);
+ rtc_stats->setMaxPacketSize(p2p_stats.max_packet_size);
+ rtc_stats->setMaxReceivedPacketSize(p2p_stats.max_received_packet_size);
+ rtc_stats->setEstimatedBandwidthBps(p2p_stats.estimated_bandwidth_bps);
+ rtc_stats->setPacketsReordered(p2p_stats.packets_reordered);
+ rtc_stats->setBlockedFramesReceived(p2p_stats.blocked_frames_received);
+ rtc_stats->setBlockedFramesSent(p2p_stats.blocked_frames_sent);
+ rtc_stats->setConnectivityProbingPacketsReceived(
+ p2p_stats.connectivity_probing_packets_received);
+ return rtc_stats;
+}
+
+void RTCQuicTransport::OnStats(uint32_t request_id,
+ const P2PQuicTransportStats& stats) {
+ auto it = stats_promise_map_.find(request_id);
+ DCHECK(it != stats_promise_map_.end());
+ it->value->Resolve(CreateRTCQuicTransportStats(stats));
+ stats_promise_map_.erase(it);
+}
+
void RTCQuicTransport::OnIceTransportClosed(
RTCIceTransport::CloseReason reason) {
if (reason == RTCIceTransport::CloseReason::kContextDestroyed) {
@@ -309,7 +444,7 @@ void RTCQuicTransport::OnIceTransportClosed(
}
void RTCQuicTransport::Close(CloseReason reason) {
- DCHECK(!IsClosed());
+ DCHECK(!IsDisposed());
// Disconnect from the RTCIceTransport, allowing a new RTCQuicTransport to
// connect to it.
@@ -336,8 +471,8 @@ void RTCQuicTransport::Close(CloseReason reason) {
break;
case CloseReason::kRemoteStopped:
case CloseReason::kFailed:
- // The QuicTransportProxy has already been closed by the event, so just go
- // ahead and delete it.
+ // The QuicTransportProxy has already been closed by the event, so just
+ // go ahead and delete it.
proxy_.reset();
state_ =
(reason == CloseReason::kFailed ? RTCQuicTransportState::kFailed
@@ -346,8 +481,13 @@ void RTCQuicTransport::Close(CloseReason reason) {
break;
}
+ if (reason != CloseReason::kContextDestroyed) {
+ // Cannot reject/resolve promises when ExecutionContext is being destroyed.
+ RejectPendingStatsPromises();
+ }
+
DCHECK(!proxy_);
- DCHECK(IsClosed());
+ DCHECK(IsDisposed());
}
bool RTCQuicTransport::RaiseExceptionIfClosed(
@@ -361,6 +501,42 @@ bool RTCQuicTransport::RaiseExceptionIfClosed(
return false;
}
+bool RTCQuicTransport::RaiseExceptionIfStarted(
+ ExceptionState& exception_state) const {
+ if (start_reason_ == StartReason::kServerListening) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The RTCQuicTransport has already called listen().");
+ return true;
+ }
+ if (start_reason_ == StartReason::kClientConnecting) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The RTCQuicTransport has already called connect().");
+ return true;
+ }
+ if (start_reason_ == StartReason::kP2PWithRemoteFingerprints) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The RTCQuicTransport has already called start().");
+ return true;
+ }
+ return false;
+}
+
+void RTCQuicTransport::RejectPendingStatsPromises() {
+ for (ScriptPromiseResolver* promise_resolver : stats_promise_map_.Values()) {
+ ScriptState::Scope scope(promise_resolver->GetScriptState());
+ ExceptionState exception_state(
+ promise_resolver->GetScriptState()->GetIsolate(),
+ ExceptionState::kExecutionContext, "RTCQuicStream", "getStats");
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The RTCQuicTransport is closed.");
+ promise_resolver->Reject(exception_state);
+ }
+ stats_promise_map_.clear();
+}
+
const AtomicString& RTCQuicTransport::InterfaceName() const {
return event_target_names::kRTCQuicTransport;
}
@@ -375,6 +551,8 @@ void RTCQuicTransport::Trace(blink::Visitor* visitor) {
visitor->Trace(remote_certificates_);
visitor->Trace(remote_parameters_);
visitor->Trace(streams_);
+ visitor->Trace(key_);
+ visitor->Trace(stats_promise_map_);
EventTargetWithInlineData::Trace(visitor);
ContextClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
index c69f9e7dc8e..3093e455aa8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
@@ -5,7 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
@@ -51,6 +53,9 @@ class MODULES_EXPORT RTCQuicTransport final
kContextDestroyed,
};
+ static RTCQuicTransport* Create(ExecutionContext* context,
+ RTCIceTransport* transport,
+ ExceptionState& exception_state);
static RTCQuicTransport* Create(
ExecutionContext* context,
RTCIceTransport* transport,
@@ -66,6 +71,7 @@ class MODULES_EXPORT RTCQuicTransport final
RTCQuicTransport(
ExecutionContext* context,
RTCIceTransport* transport,
+ DOMArrayBuffer* key,
const HeapVector<Member<RTCCertificate>>& certificates,
ExceptionState& exception_state,
std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory);
@@ -82,15 +88,45 @@ class MODULES_EXPORT RTCQuicTransport final
// https://w3c.github.io/webrtc-quic/#quic-transport*
RTCIceTransport* transport() const;
+
+ // The pre shared key to be used in the QUIC handshake with connect().
+ // This should be signaled to the remote endpoint and used with the remote
+ // endpoint's listen() function to begin a connection.
+ DOMArrayBuffer* getKey() const;
+
String state() const;
+ // Note: The listen/connect functions encourage an API user to connect()
+ // before the remote endpoint has called listen(), which can result in the
+ // CHLO being sent before the server side is ready. Although the CHLO is
+ // cached by the RTCIceTransport (if it is connected), the API user is
+ // encouraged to not connect() until the remote endpoint has called listen().
+ // An API design with the server side generating the pre shared key would
+ // enforce this, but we purposely constrained the client side to generate the
+ // key to enforce that a browser endpoint is generating the key in the case of
+ // communicating with a non-browser, server side endpoint.
+ //
+ // Begins the QUIC handshake as a client endpoint, using the internal |key_|
+ // as the pre shared key for the QUIC handshake.
+ void connect(ExceptionState& exception_state);
+ // Begins listening for the QUIC handshake as a server endpoint. Uses
+ // the |remote_key| from the remote side as a pre shared key in the QUIC
+ // handshake.
+ void listen(const DOMArrayPiece& remote_key, ExceptionState& exception_state);
+ // The following APIs that include certificates/parameters (including start())
+ // are not used (or exposed to JavaScript) until QUIC supports both side
+ // certificate verification.
RTCQuicParameters* getLocalParameters() const;
RTCQuicParameters* getRemoteParameters() const;
const HeapVector<Member<RTCCertificate>>& getCertificates() const;
const HeapVector<Member<DOMArrayBuffer>>& getRemoteCertificates() const;
- void start(const RTCQuicParameters* remote_parameters,
+ void start(RTCQuicParameters* remote_parameters,
ExceptionState& exception_state);
+
void stop();
RTCQuicStream* createStream(ExceptionState& exception_state);
+ // Resolves the promise with an RTCQuicTransportStats dictionary.
+ ScriptPromise getStats(ScriptState* script_state,
+ ExceptionState& exception_state);
DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange, kStatechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError);
DEFINE_ATTRIBUTE_EVENT_LISTENER(quicstream, kQuicstream);
@@ -103,15 +139,31 @@ class MODULES_EXPORT RTCQuicTransport final
void Trace(blink::Visitor* visitor) override;
private:
+ enum class StartReason {
+ // listen() was called with the remote key.
+ kServerListening,
+ // connect() was called.
+ kClientConnecting,
+ // start() was called with the remote fingerprints.
+ // Note that start() is not currently exposed to JavaScript.
+ kP2PWithRemoteFingerprints,
+ // Initial default state.
+ kNotStarted,
+ };
+
// QuicTransportProxy::Delegate overrides;
void OnConnected() override;
void OnConnectionFailed(const std::string& error_details,
bool from_remote) override;
void OnRemoteStopped() override;
void OnStream(QuicStreamProxy* stream_proxy) override;
+ void OnStats(uint32_t request_id,
+ const P2PQuicTransportStats& stats) override;
- // Starts the underlying QUIC connection.
- void StartConnection();
+ // Starts the underlying QUIC connection, by creating the underlying QUIC
+ // transport objects and starting the QUIC handshake.
+ void StartConnection(quic::Perspective role,
+ P2PQuicTransport::StartConfig start_config);
// Permenantly closes the RTCQuicTransport with the given reason.
// The RTCQuicTransport must not already be closed or failed.
@@ -120,16 +172,33 @@ class MODULES_EXPORT RTCQuicTransport final
void Close(CloseReason reason);
bool IsClosed() const { return state_ == RTCQuicTransportState::kClosed; }
+ // The transport is no longer usable once it has reached the "failed" or
+ // "closed" state.
+ bool IsDisposed() const {
+ return (state_ == RTCQuicTransportState::kClosed ||
+ state_ == RTCQuicTransportState::kFailed);
+ }
bool RaiseExceptionIfClosed(ExceptionState& exception_state) const;
+ bool RaiseExceptionIfStarted(ExceptionState& exception_state) const;
+ void RejectPendingStatsPromises();
Member<RTCIceTransport> transport_;
RTCQuicTransportState state_ = RTCQuicTransportState::kNew;
+ StartReason start_reason_ = StartReason::kNotStarted;
+ // The pre shared key to be used in the QUIC handshake. It is used with
+ // connect() on the local side, and listen() on the remote side.
+ Member<DOMArrayBuffer> key_;
+ // The certificates/parameters are not being used until the QUIC library
+ // supports both side certificate verification in the crypto handshake.
HeapVector<Member<RTCCertificate>> certificates_;
HeapVector<Member<DOMArrayBuffer>> remote_certificates_;
Member<RTCQuicParameters> remote_parameters_;
std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory_;
std::unique_ptr<QuicTransportProxy> proxy_;
HeapHashSet<Member<RTCQuicStream>> streams_;
+ // Maps from the ID of the stats request to the promise to be resolved.
+ HeapHashMap<uint32_t, Member<ScriptPromiseResolver>> stats_promise_map_;
+ uint32_t get_stats_id_counter_ = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl
index 89a2a696071..d45489f0612 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl
@@ -13,21 +13,23 @@ enum RTCQuicTransportState {
// https://w3c.github.io/webrtc-quic/#quic-transport*
[
- Constructor(RTCIceTransport transport, sequence<RTCCertificate> certificates),
+ Constructor(RTCIceTransport transport),
ConstructorCallWith=ExecutionContext,
RaisesException=Constructor,
Exposed=Window,
- RuntimeEnabled=RTCQuicTransport
+ Measure,
+ OriginTrialEnabled=RTCQuicTransport,
+ SecureContext
] interface RTCQuicTransport : EventTarget {
- readonly attribute RTCIceTransport transport;
- readonly attribute RTCQuicTransportState state;
- RTCQuicParameters getLocalParameters();
- RTCQuicParameters? getRemoteParameters();
- sequence<RTCCertificate> getCertificates();
- sequence<ArrayBuffer> getRemoteCertificates();
- [RaisesException] void start(RTCQuicParameters remoteParameters);
- void stop();
- [RaisesException] RTCQuicStream createStream();
+ [Measure] readonly attribute RTCIceTransport transport;
+ [Measure] readonly attribute RTCQuicTransportState state;
+ [Measure] ArrayBuffer getKey();
+ [Measure, RaisesException] void connect();
+ [Measure, RaisesException] void listen(BufferSource remote_key);
+ [Measure] void stop();
+ [Measure, RaisesException] RTCQuicStream createStream();
+ [CallWith=ScriptState, Measure, RaisesException]
+ Promise<RTCQuicTransportStats> getStats();
attribute EventHandler onstatechange;
attribute EventHandler onerror;
attribute EventHandler onquicstream;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl
new file mode 100644
index 00000000000..aa8e8302ebd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+dictionary RTCQuicTransportStats {
+ double timestamp;
+ unsigned long long bytesSent;
+ unsigned long long packetsSent;
+ unsigned long long streamBytesSent;
+ unsigned long long streamBytesReceived;
+ unsigned long numOutgoingStreamsCreated;
+ unsigned long numIncomingStreamsCreated;
+ unsigned long long bytesReceived;
+ unsigned long long packetsReceived;
+ unsigned long long packetsProcessed;
+ unsigned long long bytesRetransmitted;
+ unsigned long long packetsRetransmitted;
+ unsigned long long packetsLost;
+ unsigned long long packetsDropped;
+ unsigned long long cryptoRetransmitCount;
+ unsigned long long minRttUs;
+ unsigned long long smoothedRttUs;
+ unsigned long long maxPacketSize;
+ unsigned long long maxReceivedPacketSize;
+ unsigned long long estimatedBandwidthBps;
+ unsigned long long packetsReordered;
+ unsigned long long blockedFramesReceived;
+ unsigned long long blockedFramesSent;
+ unsigned long long connectivityProbingPacketsReceived;
+};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
index 5c2df982b99..f4b17da28e9 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
@@ -9,9 +9,11 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_stats.h"
+#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h"
-#include "third_party/webrtc/rtc_base/rtccertificategenerator.h"
+#include "third_party/webrtc/rtc_base/rtc_certificate_generator.h"
namespace blink {
namespace {
@@ -21,6 +23,7 @@ using testing::Assign;
using testing::ElementsAre;
using testing::Invoke;
using testing::Mock;
+using testing::Return;
HeapVector<Member<RTCCertificate>> GenerateLocalRTCCertificates() {
HeapVector<Member<RTCCertificate>> certificates;
@@ -34,6 +37,9 @@ constexpr char kRemoteFingerprintAlgorithm1[] = "sha-256";
constexpr char kRemoteFingerprintValue1[] =
"8E:57:5F:8E:65:D2:83:7B:05:97:BB:72:DE:09:DE:03:BD:95:9B:A0:03:10:50:82:"
"5E:73:38:16:4C:E0:C5:84";
+const size_t kKeyLength = 16;
+const uint8_t kKey[kKeyLength] = {0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15};
RTCDtlsFingerprint* CreateRemoteFingerprint1() {
RTCDtlsFingerprint* dtls_fingerprint = RTCDtlsFingerprint::Create();
@@ -141,6 +147,71 @@ TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByStart) {
quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
}
+// Test that calling connect() creates a P2PQuicTransport with the correct
+// P2PQuicTransportConfig. The config should have:
+// 1. The P2PQuicPacketTransport returned by the MockIceTransportAdapter.
+// 2. Client mode configured.
+TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByConnect) {
+ V8TestingScope scope;
+
+ auto quic_packet_transport = std::make_unique<MockP2PQuicPacketTransport>();
+ auto* quic_packet_transport_ptr = quic_packet_transport.get();
+ auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>(
+ std::move(quic_packet_transport));
+ Persistent<RTCIceTransport> ice_transport =
+ CreateIceTransport(scope, std::move(ice_transport_adapter_mock));
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
+ EXPECT_CALL(*mock_factory, CreateQuicTransport(_, _, _))
+ .WillOnce(Invoke(
+ [quic_packet_transport_ptr](P2PQuicTransport::Delegate* delegate,
+ P2PQuicPacketTransport* packet_transport,
+ const P2PQuicTransportConfig& config) {
+ EXPECT_EQ(quic_packet_transport_ptr, packet_transport);
+ EXPECT_EQ(quic::Perspective::IS_CLIENT, config.perspective);
+ return std::make_unique<MockP2PQuicTransport>();
+ }));
+
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, {}, std::move(mock_factory));
+ quic_transport->connect(ASSERT_NO_EXCEPTION);
+}
+
+// Test that calling listen() creates a P2PQuicTransport with the correct
+// P2PQuicTransportConfig. The config should have:
+// 1. The P2PQuicPacketTransport returned by the MockIceTransportAdapter.
+// 2. Server mode configured.
+TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByListen) {
+ V8TestingScope scope;
+
+ auto quic_packet_transport = std::make_unique<MockP2PQuicPacketTransport>();
+ auto* quic_packet_transport_ptr = quic_packet_transport.get();
+ auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>(
+ std::move(quic_packet_transport));
+ Persistent<RTCIceTransport> ice_transport =
+ CreateIceTransport(scope, std::move(ice_transport_adapter_mock));
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
+ EXPECT_CALL(*mock_factory, CreateQuicTransport(_, _, _))
+ .WillOnce(Invoke(
+ [quic_packet_transport_ptr](P2PQuicTransport::Delegate* delegate,
+ P2PQuicPacketTransport* packet_transport,
+ const P2PQuicTransportConfig& config) {
+ EXPECT_EQ(quic_packet_transport_ptr, packet_transport);
+ EXPECT_EQ(quic::Perspective::IS_SERVER, config.perspective);
+ return std::make_unique<MockP2PQuicTransport>();
+ }));
+
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, {}, std::move(mock_factory));
+ quic_transport->listen(DOMArrayBuffer::Create(kKey, kKeyLength),
+ ASSERT_NO_EXCEPTION);
+}
+
// Test that calling start() creates a P2PQuicTransport with client perspective
// if the RTCIceTransport role is 'controlled'.
TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByStartClient) {
@@ -179,19 +250,205 @@ TEST_F(RTCQuicTransportTest, StartPassesRemoteFingerprints) {
auto mock_transport = std::make_unique<MockP2PQuicTransport>();
EXPECT_CALL(*mock_transport, MockStart(_))
- .WillOnce(
- Invoke([](const std::vector<std::unique_ptr<rtc::SSLFingerprint>>&
- remote_fingerprints) {
- ASSERT_EQ(1u, remote_fingerprints.size());
- EXPECT_EQ(kRemoteFingerprintAlgorithm1,
- remote_fingerprints[0]->algorithm);
- EXPECT_EQ(kRemoteFingerprintValue1,
- remote_fingerprints[0]->GetRfc4572Fingerprint());
- }));
+ .WillOnce(Invoke([](const P2PQuicTransport::StartConfig& config) {
+ ASSERT_EQ(1u, config.remote_fingerprints.size());
+ EXPECT_EQ(kRemoteFingerprintAlgorithm1,
+ config.remote_fingerprints[0]->algorithm);
+ EXPECT_EQ(kRemoteFingerprintValue1,
+ config.remote_fingerprints[0]->GetRfc4572Fingerprint());
+ }));
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+ quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
+}
+
+// Test that calling start() with a started RTCIceTransport changes its state to
+// connecting.
+TEST_F(RTCQuicTransportTest, StartWithConnectedTransportChangesToConnecting) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+ quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
+ EXPECT_EQ("connecting", quic_transport->state());
+}
+
+// Test that calling start() changes its state to connecting once
+// RTCIceTransport starts.
+TEST_F(RTCQuicTransportTest, StartChangesToConnectingWhenIceStarts) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
Persistent<RTCQuicTransport> quic_transport =
CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
std::move(mock_transport));
quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
+ EXPECT_EQ("new", quic_transport->state());
+
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+ EXPECT_EQ("connecting", quic_transport->state());
+}
+
+// Test that calling start() twice throws a kInvalidStateError.
+TEST_F(RTCQuicTransportTest, StartTwiceThrowsError) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+ quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
+
+ quic_transport->start(CreateRemoteRTCQuicParameters1(),
+ scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
+}
+
+// Test that calling start() after connect() throws a kInvalidStateError.
+TEST_F(RTCQuicTransportTest, StartAfterConnectThrowsError) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+ quic_transport->connect(ASSERT_NO_EXCEPTION);
+
+ quic_transport->start(CreateRemoteRTCQuicParameters1(),
+ scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
+}
+
+// Test that calling start() after listen() throws a kInvalidStateError.
+TEST_F(RTCQuicTransportTest, StartAfterListenThrowsError) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+ quic_transport->listen(DOMArrayBuffer::Create(kKey, kKeyLength),
+ ASSERT_NO_EXCEPTION);
+
+ quic_transport->start(CreateRemoteRTCQuicParameters1(),
+ scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
+}
+
+// Test that calling start() after stop() throws a kInvalidStateError.
+TEST_F(RTCQuicTransportTest, StartAfterStopThrowsError) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+
+ quic_transport->stop();
+ quic_transport->start(CreateRemoteRTCQuicParameters1(),
+ scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
+}
+
+// Test that calling start() after RTCIceTransport::stop() throws a
+// kInvalidStateError.
+TEST_F(RTCQuicTransportTest, StartAfterIceStopsThrowsError) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
+ std::move(mock_transport));
+
+ ice_transport->stop();
+ quic_transport->start(CreateRemoteRTCQuicParameters1(),
+ scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
+}
+
+// Test that calling connect() calls Start() on the P2PQuicTransport with the
+// generated pre shared key from the local side.
+TEST_F(RTCQuicTransportTest, ConnectPassesPreSharedKey) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ auto* mock_transport_ptr = mock_transport.get();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, {}, std::move(mock_transport));
+ DOMArrayBuffer* key = quic_transport->getKey();
+ std::string pre_shared_key(static_cast<const char*>(key->Data()),
+ key->ByteLength());
+
+ EXPECT_CALL(*mock_transport_ptr, MockStart(_))
+ .WillOnce(
+ Invoke([pre_shared_key](const P2PQuicTransport::StartConfig& config) {
+ EXPECT_EQ(pre_shared_key, config.pre_shared_key);
+ }));
+ quic_transport->connect(ASSERT_NO_EXCEPTION);
+}
+
+// Test that calling listen() calls Start() on the P2PQuicTransport with the
+// correct given pre shared key from the remote side.
+TEST_F(RTCQuicTransportTest, ListenPassesPreSharedKey) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
+ ASSERT_NO_EXCEPTION);
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ auto* mock_transport_ptr = mock_transport.get();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, {}, std::move(mock_transport));
+
+ std::string pre_shared_key = "foobar";
+ EXPECT_CALL(*mock_transport_ptr, MockStart(_))
+ .WillOnce(
+ Invoke([pre_shared_key](const P2PQuicTransport::StartConfig& config) {
+ EXPECT_EQ(pre_shared_key, config.pre_shared_key);
+ }));
+
+ quic_transport->listen(
+ DOMArrayBuffer::Create(pre_shared_key.c_str(), pre_shared_key.length()),
+ ASSERT_NO_EXCEPTION);
}
// Test that calling stop() deletes the underlying P2PQuicTransport.
@@ -242,6 +499,45 @@ TEST_F(RTCQuicTransportTest, RTCIceTransportStopDeletesP2PQuicTransport) {
EXPECT_TRUE(mock_deleted);
}
+// Test that the P2PQuicTransport is deleted and the RTCQuicTransport goes to
+// the "failed" state when the QUIC connection fails.
+TEST_F(RTCQuicTransportTest,
+ ConnectionFailedBecomesClosedAndDeletesP2PQuicTransport) {
+ V8TestingScope scope;
+
+ bool mock_deleted = false;
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true));
+
+ P2PQuicTransport::Delegate* delegate = nullptr;
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
+ DCHECK(delegate);
+ delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
+ RunUntilIdle();
+
+ EXPECT_TRUE(mock_deleted);
+ EXPECT_EQ("failed", quic_transport->state());
+}
+
+// Test that after the connection fails, stop() will change the state
+// of the transport to "closed".
+TEST_F(RTCQuicTransportTest, StopAfterConnectionFailed) {
+ V8TestingScope scope;
+
+ P2PQuicTransport::Delegate* delegate = nullptr;
+ Persistent<RTCQuicTransport> quic_transport = CreateConnectedQuicTransport(
+ scope, std::make_unique<MockP2PQuicTransport>(), &delegate);
+ DCHECK(delegate);
+ delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
+ RunUntilIdle();
+
+ EXPECT_EQ("failed", quic_transport->state());
+
+ quic_transport->stop();
+ EXPECT_EQ("closed", quic_transport->state());
+}
+
// Test that the P2PQuicTransport is deleted when the underlying RTCIceTransport
// is ContextDestroyed.
TEST_F(RTCQuicTransportTest,
@@ -269,4 +565,251 @@ TEST_F(RTCQuicTransportTest,
EXPECT_TRUE(mock_deleted);
}
+// Test that the certificate passed to RTCQuicTransport is the same
+// returned by getCertificates().
+TEST_F(RTCQuicTransportTest, GetCertificatesReturnsGivenCertificates) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ auto certificates = GenerateLocalRTCCertificates();
+ Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport(
+ scope, ice_transport, certificates, std::move(mock_transport));
+ auto returned_certificates = quic_transport->getCertificates();
+
+ EXPECT_EQ(certificates[0], returned_certificates[0]);
+}
+
+// Test that the fingerprint returned by getLocalParameters() is
+// the fingerprint of the certificate passed to the RTCQuicTransport.
+TEST_F(RTCQuicTransportTest,
+ GetLocalParametersReturnsGivenCertificatesFingerprints) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ auto certificates = GenerateLocalRTCCertificates();
+ auto fingerprints = certificates[0]->getFingerprints();
+ Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport(
+ scope, ice_transport, certificates, std::move(mock_transport));
+ auto returned_fingerprints =
+ quic_transport->getLocalParameters()->fingerprints();
+
+ EXPECT_EQ(1u, returned_fingerprints.size());
+ EXPECT_EQ(fingerprints.size(), returned_fingerprints.size());
+ EXPECT_EQ(fingerprints[0]->value(), returned_fingerprints[0]->value());
+ EXPECT_EQ(fingerprints[0]->algorithm(),
+ returned_fingerprints[0]->algorithm());
+}
+
+TEST_F(RTCQuicTransportTest, ExpiredCertificateThrowsError) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
+ HeapVector<Member<RTCCertificate>> certificates;
+ certificates.push_back(MakeGarbageCollected<RTCCertificate>(
+ rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams::ECDSA(),
+ /*expires_ms=*/0)));
+ RTCQuicTransport::Create(scope.GetExecutionContext(), ice_transport,
+ certificates, scope.GetExceptionState(),
+ std::move(mock_factory));
+ EXPECT_EQ(ESErrorType::kTypeError,
+ scope.GetExceptionState().CodeAs<ESErrorType>());
+}
+
+// Test that the key returned has at least 128 bits of entropy as required by
+// QUIC.
+TEST_F(RTCQuicTransportTest, GetKeyReturnsValidKey) {
+ V8TestingScope scope;
+
+ Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateQuicTransport(scope, ice_transport, {}, std::move(mock_transport));
+ auto* key = quic_transport->getKey();
+
+ EXPECT_GE(key->ByteLength(), 16u);
+}
+
+// Test that stats are converted correctly to the RTCQuicTransportStats
+// dictionary.
+TEST_F(RTCQuicTransportTest, OnStatsConvertsRTCStatsDictionary) {
+ V8TestingScope scope;
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ MockP2PQuicTransport* mock_transport_ptr = mock_transport.get();
+ P2PQuicTransport::Delegate* delegate = nullptr;
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
+ DCHECK(delegate);
+
+ // Create some dummy values.
+ P2PQuicTransportStats stats;
+ stats.bytes_sent = 0;
+ stats.packets_sent = 1;
+ stats.stream_bytes_sent = 2;
+ stats.stream_bytes_received = 3;
+ stats.num_outgoing_streams_created = 4;
+ stats.num_incoming_streams_created = 5;
+ stats.bytes_received = 6;
+ stats.packets_received = 7;
+ stats.packets_processed = 8;
+ stats.bytes_retransmitted = 9;
+ stats.packets_retransmitted = 10;
+ stats.packets_lost = 11;
+ stats.packets_dropped = 12;
+ stats.crypto_retransmit_count = 13;
+ stats.min_rtt_us = 14;
+ stats.srtt_us = 15;
+ stats.max_packet_size = 16;
+ stats.max_received_packet_size = 17;
+ stats.estimated_bandwidth_bps = 18;
+ stats.packets_reordered = 19;
+ stats.blocked_frames_received = 20;
+ stats.blocked_frames_sent = 21;
+ stats.connectivity_probing_packets_received = 22;
+ EXPECT_CALL(*mock_transport_ptr, GetStats()).WillOnce(Return(stats));
+ ScriptPromise stats_promise =
+ quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+
+ RunUntilIdle();
+
+ ASSERT_EQ(v8::Promise::kFulfilled,
+ stats_promise.V8Value().As<v8::Promise>()->State());
+
+ RTCQuicTransportStats* rtc_quic_stats =
+ NativeValueTraits<RTCQuicTransportStats>::NativeValue(
+ scope.GetIsolate(),
+ stats_promise.V8Value().As<v8::Promise>()->Result(),
+ ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(rtc_quic_stats->hasTimestamp());
+ EXPECT_EQ(ConvertTimeTicksToDOMHighResTimeStamp(stats.timestamp),
+ rtc_quic_stats->timestamp());
+ ASSERT_TRUE(rtc_quic_stats->hasBytesSent());
+ EXPECT_EQ(stats.bytes_sent, rtc_quic_stats->bytesSent());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsSent());
+ EXPECT_EQ(stats.packets_sent, rtc_quic_stats->packetsSent());
+ ASSERT_TRUE(rtc_quic_stats->hasStreamBytesSent());
+ EXPECT_EQ(stats.stream_bytes_sent, rtc_quic_stats->streamBytesSent());
+ ASSERT_TRUE(rtc_quic_stats->hasStreamBytesSent());
+ EXPECT_EQ(stats.stream_bytes_received, rtc_quic_stats->streamBytesReceived());
+ ASSERT_TRUE(rtc_quic_stats->hasNumOutgoingStreamsCreated());
+ EXPECT_EQ(stats.num_outgoing_streams_created,
+ rtc_quic_stats->numOutgoingStreamsCreated());
+ ASSERT_TRUE(rtc_quic_stats->hasNumIncomingStreamsCreated());
+ EXPECT_EQ(stats.num_incoming_streams_created,
+ rtc_quic_stats->numIncomingStreamsCreated());
+ ASSERT_TRUE(rtc_quic_stats->hasBytesReceived());
+ EXPECT_EQ(stats.bytes_received, rtc_quic_stats->bytesReceived());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsReceived());
+ EXPECT_EQ(stats.packets_received, rtc_quic_stats->packetsReceived());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsProcessed());
+ EXPECT_EQ(stats.packets_processed, rtc_quic_stats->packetsProcessed());
+ ASSERT_TRUE(rtc_quic_stats->hasBytesRetransmitted());
+ EXPECT_EQ(stats.bytes_retransmitted, rtc_quic_stats->bytesRetransmitted());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsRetransmitted());
+ EXPECT_EQ(stats.packets_retransmitted,
+ rtc_quic_stats->packetsRetransmitted());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsLost());
+ EXPECT_EQ(stats.packets_lost, rtc_quic_stats->packetsLost());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsDropped());
+ EXPECT_EQ(stats.packets_dropped, rtc_quic_stats->packetsDropped());
+ ASSERT_TRUE(rtc_quic_stats->hasCryptoRetransmitCount());
+ EXPECT_EQ(stats.crypto_retransmit_count,
+ rtc_quic_stats->cryptoRetransmitCount());
+ ASSERT_TRUE(rtc_quic_stats->hasMinRttUs());
+ EXPECT_EQ(stats.min_rtt_us, rtc_quic_stats->minRttUs());
+ ASSERT_TRUE(rtc_quic_stats->hasSmoothedRttUs());
+ EXPECT_EQ(stats.srtt_us, rtc_quic_stats->smoothedRttUs());
+ ASSERT_TRUE(rtc_quic_stats->hasMaxPacketSize());
+ EXPECT_EQ(stats.max_packet_size, rtc_quic_stats->maxPacketSize());
+ ASSERT_TRUE(rtc_quic_stats->hasMaxReceivedPacketSize());
+ EXPECT_EQ(stats.max_received_packet_size,
+ rtc_quic_stats->maxReceivedPacketSize());
+ ASSERT_TRUE(rtc_quic_stats->hasEstimatedBandwidthBps());
+ EXPECT_EQ(stats.estimated_bandwidth_bps,
+ rtc_quic_stats->estimatedBandwidthBps());
+ ASSERT_TRUE(rtc_quic_stats->hasPacketsReordered());
+ EXPECT_EQ(stats.packets_reordered, rtc_quic_stats->packetsReordered());
+ ASSERT_TRUE(rtc_quic_stats->hasBlockedFramesReceived());
+ EXPECT_EQ(stats.blocked_frames_received,
+ rtc_quic_stats->blockedFramesReceived());
+ ASSERT_TRUE(rtc_quic_stats->hasBlockedFramesSent());
+ EXPECT_EQ(stats.blocked_frames_sent, rtc_quic_stats->blockedFramesSent());
+ ASSERT_TRUE(rtc_quic_stats->hasConnectivityProbingPacketsReceived());
+ EXPECT_EQ(stats.connectivity_probing_packets_received,
+ rtc_quic_stats->connectivityProbingPacketsReceived());
+}
+
+// Test that all promises are rejected if the connection closes before
+// the OnStats callback is called.
+TEST_F(RTCQuicTransportTest, FailedConnectionRejectsStatsPromises) {
+ V8TestingScope scope;
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ P2PQuicTransport::Delegate* delegate = nullptr;
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
+ DCHECK(delegate);
+
+ ScriptPromise promise_1 =
+ quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ ScriptPromise promise_2 =
+ quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
+
+ RunUntilIdle();
+
+ EXPECT_EQ(v8::Promise::kRejected,
+ promise_1.V8Value().As<v8::Promise>()->State());
+ EXPECT_EQ(v8::Promise::kRejected,
+ promise_2.V8Value().As<v8::Promise>()->State());
+}
+
+// Test that all promises are rejected if the remote side closes before
+// the OnStats callback is called.
+TEST_F(RTCQuicTransportTest, RemoteStopRejectsStatsPromises) {
+ V8TestingScope scope;
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ P2PQuicTransport::Delegate* delegate = nullptr;
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
+ DCHECK(delegate);
+
+ ScriptPromise promise_1 =
+ quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ ScriptPromise promise_2 =
+ quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ delegate->OnRemoteStopped();
+
+ RunUntilIdle();
+
+ EXPECT_EQ(v8::Promise::kRejected,
+ promise_1.V8Value().As<v8::Promise>()->State());
+ EXPECT_EQ(v8::Promise::kRejected,
+ promise_2.V8Value().As<v8::Promise>()->State());
+}
+
+// Test that calling getStats() after going to the "failed" state
+// raises a kInvalidStateError.
+TEST_F(RTCQuicTransportTest, FailedStateGetStatsRaisesInvalidStateError) {
+ V8TestingScope scope;
+
+ auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+ P2PQuicTransport::Delegate* delegate = nullptr;
+ Persistent<RTCQuicTransport> quic_transport =
+ CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
+ DCHECK(delegate);
+
+ delegate->OnRemoteStopped();
+ RunUntilIdle();
+
+ quic_transport->getStats(scope.GetScriptState(), scope.GetExceptionState());
+ EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
+ scope.GetExceptionState().CodeAs<DOMExceptionCode>());
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.cc
deleted file mode 100644
index a64fccbbb23..00000000000
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.cc
+++ /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.
-
-#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.h"
-
-#include "third_party/blink/public/platform/web_rtc_rtp_contributing_source.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h"
-
-namespace blink {
-
-RTCRtpContributingSource::RTCRtpContributingSource(
- RTCRtpReceiver* receiver,
- const WebRTCRtpContributingSource& webContributingSource)
- : receiver_(receiver),
- timestamp_ms_(webContributingSource.TimestampMs()),
- source_(webContributingSource.Source()) {
- DCHECK(receiver_);
-}
-
-double RTCRtpContributingSource::timestamp() const {
- return timestamp_ms_;
-}
-
-uint32_t RTCRtpContributingSource::source() const {
- return source_;
-}
-
-void RTCRtpContributingSource::Trace(blink::Visitor* visitor) {
- visitor->Trace(receiver_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.h
deleted file mode 100644
index 14a1c5a670c..00000000000
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.h
+++ /dev/null
@@ -1,38 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_RTP_CONTRIBUTING_SOURCE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_RTP_CONTRIBUTING_SOURCE_H_
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-
-namespace blink {
-
-class RTCRtpReceiver;
-class WebRTCRtpContributingSource;
-
-// https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource
-class RTCRtpContributingSource final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- RTCRtpContributingSource(RTCRtpReceiver*, const WebRTCRtpContributingSource&);
-
- double timestamp() const;
- uint32_t source() const;
-
- void Trace(blink::Visitor*) override;
-
- private:
- Member<RTCRtpReceiver> receiver_;
- double timestamp_ms_;
- const uint32_t source_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_RTP_CONTRIBUTING_SOURCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.idl
index 0a0ff1fc185..0fb6e54aa73 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.idl
@@ -3,9 +3,8 @@
// found in the LICENSE file.
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource
-interface RTCRtpContributingSource {
- readonly attribute DOMHighResTimeStamp timestamp;
- readonly attribute unsigned long source;
-
- // TODO(hbos): Support every member of the spec. https://crbug.com/705993
+dictionary RTCRtpContributingSource {
+ required DOMHighResTimeStamp timestamp;
+ required unsigned long source;
+ double audioLevel;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_decoding_parameters.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_decoding_parameters.idl
new file mode 100644
index 00000000000..bd0471ef4b5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_decoding_parameters.idl
@@ -0,0 +1,7 @@
+// 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.
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtpdecodingparameters
+dictionary RTCRtpDecodingParameters : RTCRtpCodingParameters {
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receive_parameters.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receive_parameters.idl
new file mode 100644
index 00000000000..57e4e6df8b5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receive_parameters.idl
@@ -0,0 +1,8 @@
+// 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.
+
+// https://w3c.github.io/webrtc-pc/#rtcreceivertpparameters
+dictionary RTCRtpReceiveParameters : RTCRtpParameters {
+ required sequence<RTCRtpDecodingParameters> encodings;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
index 341b2320360..b540e0810bb 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
@@ -6,21 +6,25 @@
#include "third_party/blink/public/platform/web_media_stream.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
-#include "third_party/blink/public/platform/web_rtc_rtp_contributing_source.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_source.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_capabilities.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_stats_report.h"
#include "third_party/blink/renderer/modules/peerconnection/web_rtc_stats_report_callback_resolver.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/webrtc/api/rtpparameters.h"
+#include "third_party/webrtc/api/rtp_parameters.h"
namespace blink {
-RTCRtpReceiver::RTCRtpReceiver(std::unique_ptr<WebRTCRtpReceiver> receiver,
+RTCRtpReceiver::RTCRtpReceiver(RTCPeerConnection* pc,
+ std::unique_ptr<WebRTCRtpReceiver> receiver,
MediaStreamTrack* track,
MediaStreamVector streams)
- : receiver_(std::move(receiver)),
+ : pc_(pc),
+ receiver_(std::move(receiver)),
track_(track),
streams_(std::move(streams)) {
DCHECK(receiver_);
@@ -31,10 +35,51 @@ MediaStreamTrack* RTCRtpReceiver::track() const {
return track_;
}
-const HeapVector<Member<RTCRtpContributingSource>>&
+RTCDtlsTransport* RTCRtpReceiver::transport() {
+ if (!transceiver_)
+ return nullptr;
+ return pc_->LookupDtlsTransportByMid(transceiver_->mid());
+}
+
+RTCDtlsTransport* RTCRtpReceiver::rtcp_transport() {
+ // Chrome does not support turning off RTCP-mux.
+ return nullptr;
+}
+
+HeapVector<Member<RTCRtpSynchronizationSource>>
+RTCRtpReceiver::getSynchronizationSources() {
+ UpdateSourcesIfNeeded();
+ HeapVector<Member<RTCRtpSynchronizationSource>> synchronization_sources;
+ for (const auto& web_source : web_sources_) {
+ if (web_source->SourceType() != WebRTCRtpSource::Type::kSSRC)
+ continue;
+ RTCRtpSynchronizationSource* synchronization_source =
+ MakeGarbageCollected<RTCRtpSynchronizationSource>();
+ synchronization_source->setTimestamp(web_source->TimestampMs());
+ synchronization_source->setSource(web_source->Source());
+ if (web_source->AudioLevel())
+ synchronization_source->setAudioLevel(*web_source->AudioLevel());
+ synchronization_sources.push_back(synchronization_source);
+ }
+ return synchronization_sources;
+}
+
+HeapVector<Member<RTCRtpContributingSource>>
RTCRtpReceiver::getContributingSources() {
UpdateSourcesIfNeeded();
- return contributing_sources_;
+ HeapVector<Member<RTCRtpContributingSource>> contributing_sources;
+ for (const auto& web_source : web_sources_) {
+ if (web_source->SourceType() != WebRTCRtpSource::Type::kCSRC)
+ continue;
+ RTCRtpContributingSource* contributing_source =
+ MakeGarbageCollected<RTCRtpContributingSource>();
+ contributing_source->setTimestamp(web_source->TimestampMs());
+ contributing_source->setSource(web_source->Source());
+ if (web_source->AudioLevel())
+ contributing_source->setAudioLevel(*web_source->AudioLevel());
+ contributing_sources.push_back(contributing_source);
+ }
+ return contributing_sources;
}
ScriptPromise RTCRtpReceiver::getStats(ScriptState* script_state) {
@@ -57,44 +102,34 @@ void RTCRtpReceiver::set_streams(MediaStreamVector streams) {
streams_ = std::move(streams);
}
+void RTCRtpReceiver::set_transceiver(RTCRtpTransceiver* transceiver) {
+ transceiver_ = transceiver;
+}
+
void RTCRtpReceiver::UpdateSourcesIfNeeded() {
- if (!contributing_sources_needs_updating_)
+ if (!web_sources_needs_updating_)
return;
- contributing_sources_.clear();
- for (const std::unique_ptr<WebRTCRtpContributingSource>&
- web_contributing_source : receiver_->GetSources()) {
- if (web_contributing_source->SourceType() ==
- WebRTCRtpContributingSourceType::SSRC) {
- // TODO(hbos): When |getSynchronizationSources| is added to get SSRC
- // sources don't ignore SSRCs here.
- continue;
- }
- DCHECK_EQ(web_contributing_source->SourceType(),
- WebRTCRtpContributingSourceType::CSRC);
- RTCRtpContributingSource* contributing_source =
- MakeGarbageCollected<RTCRtpContributingSource>(
- this, *web_contributing_source);
- contributing_sources_.push_back(contributing_source);
- }
+ web_sources_ = receiver_->GetSources();
// Clear the flag and schedule a microtask to reset it to true. This makes
// the cache valid until the next microtask checkpoint. As such, sources
// represent a snapshot and can be compared reliably in .js code, no risk of
// being updated due to an RTP packet arriving. E.g.
// "source.timestamp == source.timestamp" will always be true.
- contributing_sources_needs_updating_ = false;
+ web_sources_needs_updating_ = false;
Microtask::EnqueueMicrotask(
WTF::Bind(&RTCRtpReceiver::SetContributingSourcesNeedsUpdating,
WrapWeakPersistent(this)));
}
void RTCRtpReceiver::SetContributingSourcesNeedsUpdating() {
- contributing_sources_needs_updating_ = true;
+ web_sources_needs_updating_ = true;
}
void RTCRtpReceiver::Trace(blink::Visitor* visitor) {
+ visitor->Trace(pc_);
visitor->Trace(track_);
visitor->Trace(streams_);
- visitor->Trace(contributing_sources_);
+ visitor->Trace(transceiver_);
ScriptWrappable::Trace(visitor);
}
@@ -147,4 +182,44 @@ RTCRtpCapabilities* RTCRtpReceiver::getCapabilities(const String& kind) {
return capabilities;
}
+RTCRtpReceiveParameters* RTCRtpReceiver::getParameters() {
+ RTCRtpReceiveParameters* parameters = RTCRtpReceiveParameters::Create();
+ std::unique_ptr<webrtc::RtpParameters> webrtc_parameters =
+ receiver_->GetParameters();
+
+ RTCRtcpParameters* rtcp = RTCRtcpParameters::Create();
+ rtcp->setReducedSize(webrtc_parameters->rtcp.reduced_size);
+ parameters->setRtcp(rtcp);
+
+ HeapVector<Member<RTCRtpDecodingParameters>> encodings;
+ encodings.ReserveCapacity(
+ SafeCast<wtf_size_t>(webrtc_parameters->encodings.size()));
+ for (const auto& webrtc_encoding : webrtc_parameters->encodings) {
+ RTCRtpDecodingParameters* encoding = RTCRtpDecodingParameters::Create();
+ if (!webrtc_encoding.rid.empty()) {
+ // TODO(orphis): Add rid when supported by WebRTC
+ }
+ encodings.push_back(encoding);
+ }
+ parameters->setEncodings(encodings);
+
+ HeapVector<Member<RTCRtpHeaderExtensionParameters>> headers;
+ headers.ReserveCapacity(
+ SafeCast<wtf_size_t>(webrtc_parameters->header_extensions.size()));
+ for (const auto& webrtc_header : webrtc_parameters->header_extensions) {
+ headers.push_back(ToRtpHeaderExtensionParameters(webrtc_header));
+ }
+ parameters->setHeaderExtensions(headers);
+
+ HeapVector<Member<RTCRtpCodecParameters>> codecs;
+ codecs.ReserveCapacity(
+ SafeCast<wtf_size_t>(webrtc_parameters->codecs.size()));
+ for (const auto& webrtc_codec : webrtc_parameters->codecs) {
+ codecs.push_back(ToRtpCodecParameters(webrtc_codec));
+ }
+ parameters->setCodecs(codecs);
+
+ return parameters;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h
index 5e560ec3139..60a17bfcd7b 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h
@@ -9,16 +9,23 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_rtc_rtp_receiver.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_source.h"
+#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_contributing_source.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_receive_parameters.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_synchronization_source.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
+class RTCDtlsTransport;
+class RTCPeerConnection;
class RTCRtpCapabilities;
+class RTCRtpTransceiver;
// https://w3c.github.io/webrtc-pc/#rtcrtpreceiver-interface
class RTCRtpReceiver final : public ScriptWrappable {
@@ -26,33 +33,42 @@ class RTCRtpReceiver final : public ScriptWrappable {
public:
// Takes ownership of the receiver.
- RTCRtpReceiver(std::unique_ptr<WebRTCRtpReceiver>,
+ RTCRtpReceiver(RTCPeerConnection*,
+ std::unique_ptr<WebRTCRtpReceiver>,
MediaStreamTrack*,
MediaStreamVector);
static RTCRtpCapabilities* getCapabilities(const String& kind);
MediaStreamTrack* track() const;
- const HeapVector<Member<RTCRtpContributingSource>>& getContributingSources();
+ RTCDtlsTransport* transport();
+ RTCDtlsTransport* rtcp_transport();
+ RTCRtpReceiveParameters* getParameters();
+ HeapVector<Member<RTCRtpSynchronizationSource>> getSynchronizationSources();
+ HeapVector<Member<RTCRtpContributingSource>> getContributingSources();
ScriptPromise getStats(ScriptState*);
const WebRTCRtpReceiver& web_receiver() const;
MediaStreamVector streams() const;
void set_streams(MediaStreamVector streams);
+ void set_transceiver(RTCRtpTransceiver*);
void UpdateSourcesIfNeeded();
void Trace(blink::Visitor*) override;
private:
+ Member<RTCPeerConnection> pc_;
void SetContributingSourcesNeedsUpdating();
std::unique_ptr<WebRTCRtpReceiver> receiver_;
Member<MediaStreamTrack> track_;
MediaStreamVector streams_;
- // The current contributing sources (|getContributingSources|).
- HeapVector<Member<RTCRtpContributingSource>> contributing_sources_;
- bool contributing_sources_needs_updating_ = true;
+ // The current SSRCs and CSRCs. getSynchronizationSources() returns the SSRCs
+ // and getContributingSources() returns the CSRCs.
+ WebVector<std::unique_ptr<WebRTCRtpSource>> web_sources_;
+ bool web_sources_needs_updating_ = true;
+ Member<RTCRtpTransceiver> transceiver_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.idl
index c31fddbb40e..49b24559fe7 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.idl
@@ -6,8 +6,11 @@
[Exposed=Window]
interface RTCRtpReceiver {
readonly attribute MediaStreamTrack track;
- static RTCRtpCapabilities? getCapabilities(DOMString kind);
+ [RuntimeEnabled=RTCDtlsTransport] readonly attribute RTCDtlsTransport? transport;
+ [RuntimeEnabled=RTCDtlsTransport] readonly attribute RTCDtlsTransport? rtcp_transport;
+ static RTCRtpCapabilities? getCapabilities(DOMString kind);
+ RTCRtpReceiveParameters getParameters();
+ sequence<RTCRtpSynchronizationSource> getSynchronizationSources();
sequence<RTCRtpContributingSource> getContributingSources();
[CallWith=ScriptState] Promise<RTCStatsReport> getStats();
- // TODO(hbos): Support every member of the spec. https://crbug.com/700916
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
index d6977a5437c..5df696b04eb 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
@@ -255,6 +255,37 @@ webrtc::RtpEncodingParameters ToRtpEncodingParameters(
return webrtc_encoding;
}
+RTCRtpHeaderExtensionParameters* ToRtpHeaderExtensionParameters(
+ const webrtc::RtpHeaderExtensionParameters& webrtc_header) {
+ RTCRtpHeaderExtensionParameters* header =
+ RTCRtpHeaderExtensionParameters::Create();
+ header->setUri(webrtc_header.uri.c_str());
+ header->setId(webrtc_header.id);
+ header->setEncrypted(webrtc_header.encrypt);
+ return header;
+}
+
+RTCRtpCodecParameters* ToRtpCodecParameters(
+ const webrtc::RtpCodecParameters& webrtc_codec) {
+ RTCRtpCodecParameters* codec = RTCRtpCodecParameters::Create();
+ codec->setPayloadType(webrtc_codec.payload_type);
+ codec->setMimeType(WTF::String::FromUTF8(webrtc_codec.mime_type().c_str()));
+ if (webrtc_codec.clock_rate)
+ codec->setClockRate(webrtc_codec.clock_rate.value());
+ if (webrtc_codec.num_channels)
+ codec->setChannels(webrtc_codec.num_channels.value());
+ if (webrtc_codec.parameters.size()) {
+ std::string sdp_fmtp_line;
+ for (const auto& parameter : webrtc_codec.parameters) {
+ if (sdp_fmtp_line.size())
+ sdp_fmtp_line += ";";
+ sdp_fmtp_line += parameter.first + "=" + parameter.second;
+ }
+ codec->setSdpFmtpLine(sdp_fmtp_line.c_str());
+ }
+ return codec;
+}
+
RTCRtpSender::RTCRtpSender(RTCPeerConnection* pc,
std::unique_ptr<WebRTCRtpSender> sender,
String kind,
@@ -274,6 +305,17 @@ MediaStreamTrack* RTCRtpSender::track() {
return track_;
}
+RTCDtlsTransport* RTCRtpSender::transport() {
+ if (!transceiver_)
+ return nullptr;
+ return pc_->LookupDtlsTransportByMid(transceiver_->mid());
+}
+
+RTCDtlsTransport* RTCRtpSender::rtcp_transport() {
+ // Chrome does not support turning off RTCP-mux.
+ return nullptr;
+}
+
ScriptPromise RTCRtpSender::replaceTrack(ScriptState* script_state,
MediaStreamTrack* with_track) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
@@ -289,7 +331,7 @@ ScriptPromise RTCRtpSender::replaceTrack(ScriptState* script_state,
web_track = with_track->Component();
}
ReplaceTrackRequest* request =
- new ReplaceTrackRequest(this, with_track, resolver);
+ MakeGarbageCollected<ReplaceTrackRequest>(this, with_track, resolver);
sender_->ReplaceTrack(web_track, request);
return promise;
}
@@ -311,17 +353,17 @@ RTCRtpSendParameters* RTCRtpSender::getParameters() {
HeapVector<Member<RTCRtpEncodingParameters>> encodings;
encodings.ReserveCapacity(
SafeCast<wtf_size_t>(webrtc_parameters->encodings.size()));
- for (const auto& web_encoding : webrtc_parameters->encodings) {
+ for (const auto& webrtc_encoding : webrtc_parameters->encodings) {
// TODO(orphis): Forward missing fields from the WebRTC library:
// codecPayloadType, dtx, ptime, maxFramerate, scaleResolutionDownBy, rid
RTCRtpEncodingParameters* encoding = RTCRtpEncodingParameters::Create();
- encoding->setActive(web_encoding.active);
- if (web_encoding.max_bitrate_bps)
- encoding->setMaxBitrate(web_encoding.max_bitrate_bps.value());
+ encoding->setActive(webrtc_encoding.active);
+ if (webrtc_encoding.max_bitrate_bps)
+ encoding->setMaxBitrate(webrtc_encoding.max_bitrate_bps.value());
encoding->setPriority(
- PriorityFromDouble(web_encoding.bitrate_priority).c_str());
+ PriorityFromDouble(webrtc_encoding.bitrate_priority).c_str());
encoding->setNetworkPriority(
- PriorityFromDouble(web_encoding.network_priority).c_str());
+ PriorityFromDouble(webrtc_encoding.network_priority).c_str());
encodings.push_back(encoding);
}
parameters->setEncodings(encodings);
@@ -329,36 +371,16 @@ RTCRtpSendParameters* RTCRtpSender::getParameters() {
HeapVector<Member<RTCRtpHeaderExtensionParameters>> headers;
headers.ReserveCapacity(
SafeCast<wtf_size_t>(webrtc_parameters->header_extensions.size()));
- for (const auto& web_header : webrtc_parameters->header_extensions) {
- auto* header = RTCRtpHeaderExtensionParameters::Create();
- header->setUri(web_header.uri.c_str());
- header->setId(web_header.id);
- header->setEncrypted(web_header.encrypt);
- headers.push_back(header);
+ for (const auto& webrtc_header : webrtc_parameters->header_extensions) {
+ headers.push_back(ToRtpHeaderExtensionParameters(webrtc_header));
}
parameters->setHeaderExtensions(headers);
HeapVector<Member<RTCRtpCodecParameters>> codecs;
codecs.ReserveCapacity(
SafeCast<wtf_size_t>(webrtc_parameters->codecs.size()));
- for (const auto& web_codec : webrtc_parameters->codecs) {
- auto* codec = RTCRtpCodecParameters::Create();
- codec->setPayloadType(web_codec.payload_type);
- codec->setMimeType(WTF::String::FromUTF8(web_codec.mime_type().c_str()));
- if (web_codec.clock_rate)
- codec->setClockRate(web_codec.clock_rate.value());
- if (web_codec.num_channels)
- codec->setChannels(web_codec.num_channels.value());
- if (web_codec.parameters.size()) {
- std::string sdp_fmtp_line;
- for (const auto& parameter : web_codec.parameters) {
- if (sdp_fmtp_line.size())
- sdp_fmtp_line += ";";
- sdp_fmtp_line += parameter.first + "=" + parameter.second;
- }
- codec->setSdpFmtpLine(sdp_fmtp_line.c_str());
- }
- codecs.push_back(codec);
+ for (const auto& webrtc_codec : webrtc_parameters->codecs) {
+ codecs.push_back(ToRtpCodecParameters(webrtc_codec));
}
parameters->setCodecs(codecs);
@@ -399,7 +421,7 @@ ScriptPromise RTCRtpSender::setParameters(
webrtc::DegradationPreference degradation_preference;
std::tie(encodings, degradation_preference) = ToRtpParameters(parameters);
- auto* request = new SetParametersRequest(resolver, this);
+ auto* request = MakeGarbageCollected<SetParametersRequest>(resolver, this);
sender_->SetParameters(std::move(encodings), degradation_preference, request);
return promise;
}
@@ -441,6 +463,10 @@ void RTCRtpSender::set_streams(MediaStreamVector streams) {
streams_ = std::move(streams);
}
+void RTCRtpSender::set_transceiver(RTCRtpTransceiver* transceiver) {
+ transceiver_ = transceiver;
+}
+
RTCDTMFSender* RTCRtpSender::dtmf() {
// Lazy initialization of dtmf_ to avoid overhead when not used.
if (!dtmf_ && kind_ == "audio") {
@@ -461,6 +487,7 @@ void RTCRtpSender::Trace(blink::Visitor* visitor) {
visitor->Trace(dtmf_);
visitor->Trace(streams_);
visitor->Trace(last_returned_parameters_);
+ visitor->Trace(transceiver_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
index c35d6ff39bc..1abbf95abd0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
@@ -15,17 +15,23 @@
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/webrtc/api/rtptransceiverinterface.h"
+#include "third_party/webrtc/api/rtp_transceiver_interface.h"
namespace blink {
class MediaStreamTrack;
+class RTCDtlsTransport;
class RTCDTMFSender;
class RTCPeerConnection;
class RTCRtpCapabilities;
+class RTCRtpTransceiver;
webrtc::RtpEncodingParameters ToRtpEncodingParameters(
const RTCRtpEncodingParameters*);
+RTCRtpHeaderExtensionParameters* ToRtpHeaderExtensionParameters(
+ const webrtc::RtpHeaderExtensionParameters& headers);
+RTCRtpCodecParameters* ToRtpCodecParameters(
+ const webrtc::RtpCodecParameters& codecs);
// https://w3c.github.io/webrtc-pc/#rtcrtpsender-interface
class RTCRtpSender final : public ScriptWrappable {
@@ -41,6 +47,8 @@ class RTCRtpSender final : public ScriptWrappable {
MediaStreamVector streams);
MediaStreamTrack* track();
+ RTCDtlsTransport* transport();
+ RTCDtlsTransport* rtcp_transport();
ScriptPromise replaceTrack(ScriptState*, MediaStreamTrack*);
RTCDTMFSender* dtmf();
static RTCRtpCapabilities* getCapabilities(const String& kind);
@@ -55,6 +63,7 @@ class RTCRtpSender final : public ScriptWrappable {
void ClearLastReturnedParameters();
MediaStreamVector streams() const;
void set_streams(MediaStreamVector streams);
+ void set_transceiver(RTCRtpTransceiver*);
void Trace(blink::Visitor*) override;
@@ -68,6 +77,7 @@ class RTCRtpSender final : public ScriptWrappable {
Member<RTCDTMFSender> dtmf_;
MediaStreamVector streams_;
Member<RTCRtpSendParameters> last_returned_parameters_;
+ Member<RTCRtpTransceiver> transceiver_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.idl
index dcf54c4adb3..c9bcb4bf05e 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.idl
@@ -6,6 +6,8 @@
[Exposed=Window]
interface RTCRtpSender {
readonly attribute MediaStreamTrack? track;
+ [RuntimeEnabled=RTCDtlsTransport] readonly attribute RTCDtlsTransport? transport;
+ [RuntimeEnabled=RTCDtlsTransport] readonly attribute RTCDtlsTransport? rtcp_transport;
static RTCRtpCapabilities? getCapabilities(DOMString kind);
[RuntimeEnabled=RTCRtpSenderParameters, CallWith=ScriptState] Promise<void> setParameters(optional RTCRtpSendParameters parameters);
[RuntimeEnabled=RTCRtpSenderParameters] RTCRtpSendParameters getParameters();
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_synchronization_source.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_synchronization_source.idl
new file mode 100644
index 00000000000..8ba4c431fe3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_synchronization_source.idl
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtpsynchronizationsource
+dictionary RTCRtpSynchronizationSource : RTCRtpContributingSource {
+ // TODO(hbos): Implement voiceActivityFlag. https://crbug.com/893159
+};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
index 887f3cb0496..11b6db4b140 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
@@ -100,6 +100,8 @@ RTCRtpTransceiver::RTCRtpTransceiver(
DCHECK(sender_);
DCHECK(receiver_);
UpdateMembers();
+ sender_->set_transceiver(this);
+ receiver_->set_transceiver(this);
}
String RTCRtpTransceiver::mid() const {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
index 117771105de..0fc44e336a3 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
@@ -14,7 +14,7 @@
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/webrtc/api/rtptransceiverinterface.h"
+#include "third_party/webrtc/api/rtp_transceiver_interface.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_session_description.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_session_description.idl
index 7f6ba6ddf01..37e6ece1256 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_session_description.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_session_description.idl
@@ -46,5 +46,5 @@ enum RTCSdpType {
// https://crbug.com/662898
[Measure] attribute RTCSdpType? type;
[Measure] attribute DOMString? sdp;
- serializer = {attribute};
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
index 7f73c9b6d54..71b11c11f91 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
@@ -136,7 +136,8 @@ uint32_t RTCStatsReport::size() const {
PairIterable<String, v8::Local<v8::Value>>::IterationSource*
RTCStatsReport::StartIteration(ScriptState*, ExceptionState&) {
- return new RTCStatsReportIterationSource(report_->CopyHandle());
+ return MakeGarbageCollected<RTCStatsReportIterationSource>(
+ report_->CopyHandle());
}
bool RTCStatsReport::GetMapEntry(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl
index 641ca05b68d..97bf7400749 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl
@@ -27,6 +27,6 @@
NoInterfaceObject
] interface RTCStatsResponse {
sequence<RTCLegacyStatsReport> result();
- RTCLegacyStatsReport namedItem([Default=Undefined] optional DOMString name);
- [NotEnumerable, ImplementedAs=namedItem] getter RTCLegacyStatsReport ([Default=Undefined] optional DOMString name);
+ RTCLegacyStatsReport namedItem([DefaultValue=Undefined] optional DOMString name);
+ [NotEnumerable, ImplementedAs=namedItem] getter RTCLegacyStatsReport ([DefaultValue=Undefined] optional DOMString name);
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.cc
index bc83ff1648f..83aa2cb595e 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.cc
@@ -49,7 +49,7 @@ MediaStreamTrack* RTCTrackEvent::track() const {
return track_;
}
-HeapVector<Member<MediaStream>> RTCTrackEvent::streams() const {
+const HeapVector<Member<MediaStream>>& RTCTrackEvent::streams() const {
return streams_;
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.h
index dedd3ce8546..dc39e9b29fe 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_track_event.h
@@ -34,7 +34,7 @@ class RTCTrackEvent final : public Event {
RTCRtpReceiver* receiver() const;
MediaStreamTrack* track() const;
- HeapVector<Member<MediaStream>> streams() const;
+ const HeapVector<Member<MediaStream>>& streams() const;
RTCRtpTransceiver* transceiver() const;
void Trace(blink::Visitor*) override;
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl b/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl
index d222ccbd270..5e94009db3e 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl
@@ -27,6 +27,7 @@ enum PermissionName {
"clipboard-read",
"clipboard-write",
"payment-handler",
+ "idle-detection",
};
// The PermissionDescriptor dictionary is a base to describe permissions. Some
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permission_status.cc b/chromium/third_party/blink/renderer/modules/permissions/permission_status.cc
index 5e83c7f688a..8fbd71da011 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permission_status.cc
+++ b/chromium/third_party/blink/renderer/modules/permissions/permission_status.cc
@@ -59,11 +59,11 @@ bool PermissionStatus::HasPendingActivity() const {
return binding_.is_bound();
}
-void PermissionStatus::Unpause() {
+void PermissionStatus::ContextUnpaused() {
StartListening();
}
-void PermissionStatus::Pause() {
+void PermissionStatus::ContextPaused(PauseState) {
StopListening();
}
@@ -88,11 +88,13 @@ String PermissionStatus::state() const {
void PermissionStatus::StartListening() {
DCHECK(!binding_.is_bound());
mojom::blink::PermissionObserverPtr observer;
- binding_.Bind(mojo::MakeRequest(&observer));
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kPermission);
+ binding_.Bind(mojo::MakeRequest(&observer, task_runner), task_runner);
mojom::blink::PermissionServicePtr service;
ConnectToPermissionService(GetExecutionContext(),
- mojo::MakeRequest(&service));
+ mojo::MakeRequest(&service, task_runner));
service->AddPermissionObserver(descriptor_->Clone(), status_,
std::move(observer));
}
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permission_status.h b/chromium/third_party/blink/renderer/modules/permissions/permission_status.h
index 797286c2ba1..0e4d8ad2269 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permission_status.h
+++ b/chromium/third_party/blink/renderer/modules/permissions/permission_status.h
@@ -9,7 +9,7 @@
#include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -55,8 +55,8 @@ class PermissionStatus final : public EventTargetWithInlineData,
bool HasPendingActivity() const final;
// PausableObject implementation.
- void Pause() override;
- void Unpause() override;
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
void ContextDestroyed(ExecutionContext*) override;
String state() const;
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc
index 137ae641237..a116cf6f1aa 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc
+++ b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -147,6 +147,8 @@ PermissionDescriptorPtr ParsePermission(ScriptState* script_state,
}
return CreatePermissionDescriptor(PermissionName::BACKGROUND_FETCH);
}
+ if (name == "idle-detection")
+ return CreatePermissionDescriptor(PermissionName::IDLE_DETECTION);
return nullptr;
}
@@ -282,7 +284,10 @@ ScriptPromise Permissions::requestAll(
PermissionService& Permissions::GetService(
ExecutionContext* execution_context) {
if (!service_) {
- ConnectToPermissionService(execution_context, mojo::MakeRequest(&service_));
+ ConnectToPermissionService(
+ execution_context,
+ mojo::MakeRequest(&service_, execution_context->GetTaskRunner(
+ TaskType::kPermission)));
service_.set_connection_error_handler(WTF::Bind(
&Permissions::ServiceConnectionError, WrapWeakPersistent(this)));
}
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.cc
index 4839db8a6cc..438d36f5b13 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.cc
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.cc
@@ -9,13 +9,14 @@ namespace blink {
EnterPictureInPictureEvent* EnterPictureInPictureEvent::Create(
const AtomicString& type,
PictureInPictureWindow* picture_in_picture_window) {
- return new EnterPictureInPictureEvent(type, picture_in_picture_window);
+ return MakeGarbageCollected<EnterPictureInPictureEvent>(
+ type, picture_in_picture_window);
}
EnterPictureInPictureEvent* EnterPictureInPictureEvent::Create(
const AtomicString& type,
const EnterPictureInPictureEventInit* initializer) {
- return new EnterPictureInPictureEvent(type, initializer);
+ return MakeGarbageCollected<EnterPictureInPictureEvent>(type, initializer);
}
PictureInPictureWindow* EnterPictureInPictureEvent::pictureInPictureWindow()
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.h b/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.h
index 73989f0aa43..e931afcba05 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.h
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.h
@@ -24,15 +24,15 @@ class MODULES_EXPORT EnterPictureInPictureEvent final : public Event {
const AtomicString&,
const EnterPictureInPictureEventInit*);
+ EnterPictureInPictureEvent(AtomicString const&, PictureInPictureWindow*);
+ EnterPictureInPictureEvent(AtomicString const&,
+ const EnterPictureInPictureEventInit*);
+
PictureInPictureWindow* pictureInPictureWindow() const;
void Trace(blink::Visitor*) override;
private:
- EnterPictureInPictureEvent(AtomicString const&, PictureInPictureWindow*);
- EnterPictureInPictureEvent(AtomicString const&,
- const EnterPictureInPictureEventInit*);
-
Member<PictureInPictureWindow> picture_in_picture_window_;
};
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
index b6a8505674f..69b975cfc37 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
@@ -119,7 +119,8 @@ void HTMLVideoElementPictureInPicture::setPictureInPictureControls(
bool HTMLVideoElementPictureInPicture::FastHasAttribute(
const QualifiedName& name,
const HTMLVideoElement& element) {
- DCHECK(name == html_names::kDisablepictureinpictureAttr);
+ DCHECK(name == html_names::kDisablepictureinpictureAttr ||
+ name == html_names::kAutopictureinpictureAttr);
return element.FastHasAttribute(name);
}
@@ -128,17 +129,17 @@ void HTMLVideoElementPictureInPicture::SetBooleanAttribute(
const QualifiedName& name,
HTMLVideoElement& element,
bool value) {
- DCHECK(name == html_names::kDisablepictureinpictureAttr);
+ DCHECK(name == html_names::kDisablepictureinpictureAttr ||
+ name == html_names::kAutopictureinpictureAttr);
element.SetBooleanAttribute(name, value);
- if (!value)
- return;
-
Document& document = element.GetDocument();
TreeScope& scope = element.GetTreeScope();
PictureInPictureControllerImpl& controller =
PictureInPictureControllerImpl::From(document);
- if (controller.PictureInPictureElement(scope) == &element) {
+
+ if (name == html_names::kDisablepictureinpictureAttr && value &&
+ controller.PictureInPictureElement(scope) == &element) {
controller.ExitPictureInPicture(&element, nullptr);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
index f46c613d102..18f4a01a72c 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
@@ -4,16 +4,16 @@
// https://wicg.github.io/picture-in-picture/#htmlvideoelement-extensions
[
- ImplementedAs=HTMLVideoElementPictureInPicture,
- RuntimeEnabled=PictureInPictureAPI
+ ImplementedAs=HTMLVideoElementPictureInPicture
]
partial interface HTMLVideoElement {
- [CallWith=ScriptState, Measure, NewObject] Promise<PictureInPictureWindow> requestPictureInPicture();
+ [RuntimeEnabled=PictureInPictureAPI, CallWith=ScriptState, Measure, NewObject] Promise<PictureInPictureWindow> requestPictureInPicture();
[RuntimeEnabled=PictureInPictureControl] void setPictureInPictureControls(sequence<PictureInPictureControl> pipControls);
- attribute EventHandler onenterpictureinpicture;
- attribute EventHandler onleavepictureinpicture;
+ [RuntimeEnabled=PictureInPictureAPI] attribute EventHandler onenterpictureinpicture;
+ [RuntimeEnabled=PictureInPictureAPI] attribute EventHandler onleavepictureinpicture;
[RuntimeEnabled=PictureInPictureControl] attribute EventHandler onpictureinpicturecontrolclick;
- [CEReactions, Measure, Reflect] attribute boolean disablePictureInPicture;
+ [OriginTrialEnabled=AutoPictureInPicture, CEReactions, Measure, Reflect] attribute boolean autoPictureInPicture;
+ [RuntimeEnabled=PictureInPictureAPI, CEReactions, Measure, Reflect] attribute boolean disablePictureInPicture;
};
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index fdf447f6a87..6d722e099e6 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h"
+#include "third_party/blink/public/common/manifest/web_display_mode.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -130,9 +131,11 @@ void PictureInPictureControllerImpl::OnEnteredPictureInPicture(
event_type_names::kEnterpictureinpicture,
WrapPersistent(picture_in_picture_window_.Get())));
- element->GetWebMediaPlayer()->RegisterPictureInPictureWindowResizeCallback(
- WTF::BindRepeating(&PictureInPictureWindow::OnResize,
- WrapPersistent(picture_in_picture_window_.Get())));
+ if (element->GetWebMediaPlayer()) {
+ element->GetWebMediaPlayer()->RegisterPictureInPictureWindowResizeCallback(
+ WTF::BindRepeating(&PictureInPictureWindow::OnResize,
+ WrapPersistent(picture_in_picture_window_.Get())));
+ }
if (resolver)
resolver->Resolve(picture_in_picture_window_);
@@ -212,14 +215,75 @@ bool PictureInPictureControllerImpl::IsPictureInPictureElement(
return element == picture_in_picture_element_;
}
+void PictureInPictureControllerImpl::AddToAutoPictureInPictureElementsList(
+ HTMLVideoElement* element) {
+ RemoveFromAutoPictureInPictureElementsList(element);
+ auto_picture_in_picture_elements_.push_back(element);
+}
+
+void PictureInPictureControllerImpl::RemoveFromAutoPictureInPictureElementsList(
+ HTMLVideoElement* element) {
+ DCHECK(element);
+ auto it = std::find(auto_picture_in_picture_elements_.begin(),
+ auto_picture_in_picture_elements_.end(), element);
+ if (it != auto_picture_in_picture_elements_.end())
+ auto_picture_in_picture_elements_.erase(it);
+}
+
+HTMLVideoElement* PictureInPictureControllerImpl::AutoPictureInPictureElement()
+ const {
+ return auto_picture_in_picture_elements_.IsEmpty()
+ ? nullptr
+ : auto_picture_in_picture_elements_.back();
+}
+
+void PictureInPictureControllerImpl::PageVisibilityChanged() {
+ DCHECK(GetSupplementable());
+
+ // Auto Picture-in-Picture is allowed only in a PWA window.
+ if (!GetSupplementable()->GetFrame() ||
+ !GetSupplementable()->GetFrame()->View() ||
+ GetSupplementable()->GetFrame()->View()->DisplayMode() ==
+ WebDisplayMode::kWebDisplayModeBrowser) {
+ return;
+ }
+
+ // Auto Picture-in-Picture is allowed only in the scope of a PWA.
+ if (!GetSupplementable()->IsInWebAppScope())
+ return;
+
+ // If page becomes visible and Picture-in-Picture element has entered
+ // automatically Picture-in-Picture and is still eligible to Auto
+ // Picture-in-Picture, exit Picture-in-Picture.
+ if (GetSupplementable()->IsPageVisible() && picture_in_picture_element_ &&
+ picture_in_picture_element_ == AutoPictureInPictureElement() &&
+ picture_in_picture_element_->FastHasAttribute(
+ html_names::kAutopictureinpictureAttr)) {
+ ExitPictureInPicture(picture_in_picture_element_, nullptr);
+ return;
+ }
+
+ // If page becomes hidden with no video in Picture-in-Picture and a video
+ // element is allowed to, enter Picture-in-Picture.
+ if (GetSupplementable()->hidden() && !picture_in_picture_element_ &&
+ AutoPictureInPictureElement() &&
+ !AutoPictureInPictureElement()->PausedWhenVisible() &&
+ IsElementAllowed(*AutoPictureInPictureElement()) == Status::kEnabled) {
+ EnterPictureInPicture(AutoPictureInPictureElement(), nullptr);
+ }
+}
+
void PictureInPictureControllerImpl::Trace(blink::Visitor* visitor) {
visitor->Trace(picture_in_picture_element_);
+ visitor->Trace(auto_picture_in_picture_elements_);
visitor->Trace(picture_in_picture_window_);
- Supplement<Document>::Trace(visitor);
+ PictureInPictureController::Trace(visitor);
+ PageVisibilityObserver::Trace(visitor);
}
PictureInPictureControllerImpl::PictureInPictureControllerImpl(
Document& document)
- : PictureInPictureController(document) {}
+ : PictureInPictureController(document),
+ PageVisibilityObserver(document.GetPage()) {}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
index 1c5c2f36baa..af8a3f96c37 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_CONTROLLER_IMPL_H_
#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
+#include "third_party/blink/renderer/core/page/page_visibility_observer.h"
namespace blink {
@@ -22,7 +23,8 @@ struct WebSize;
// PictureInPictureControllerImpl instance is associated to a Document. It is
// supplement and therefore can be lazy-initiated. Callers should consider
// whether they want to instantiate an object when they make a call.
-class PictureInPictureControllerImpl : public PictureInPictureController {
+class PictureInPictureControllerImpl : public PictureInPictureController,
+ public PageVisibilityObserver {
USING_GARBAGE_COLLECTED_MIXIN(PictureInPictureControllerImpl);
WTF_MAKE_NONCOPYABLE(PictureInPictureControllerImpl);
@@ -50,16 +52,25 @@ class PictureInPictureControllerImpl : public PictureInPictureController {
Element* PictureInPictureElement() const;
Element* PictureInPictureElement(TreeScope&) const;
+ // Returns video element whose autoPictureInPicture attribute was set most
+ // recently.
+ HTMLVideoElement* AutoPictureInPictureElement() const;
+
// Implementation of PictureInPictureController.
void EnterPictureInPicture(HTMLVideoElement*,
ScriptPromiseResolver*) override;
void ExitPictureInPicture(HTMLVideoElement*, ScriptPromiseResolver*) override;
+ void AddToAutoPictureInPictureElementsList(HTMLVideoElement*) override;
+ void RemoveFromAutoPictureInPictureElementsList(HTMLVideoElement*) override;
void SetPictureInPictureCustomControls(
HTMLVideoElement*,
const std::vector<PictureInPictureControlInfo>&) override;
Status IsElementAllowed(const HTMLVideoElement&) const override;
bool IsPictureInPictureElement(const Element*) const override;
+ // PageVisibilityObserver implementation.
+ void PageVisibilityChanged() override;
+
void Trace(blink::Visitor*) override;
private:
@@ -72,6 +83,10 @@ class PictureInPictureControllerImpl : public PictureInPictureController {
// The Picture-in-Picture element for the associated document.
Member<HTMLVideoElement> picture_in_picture_element_;
+ // The list of video elements for the associated document that are eligible
+ // to Auto Picture-in-Picture.
+ HeapDeque<Member<HTMLVideoElement>> auto_picture_in_picture_elements_;
+
// The Picture-in-Picture window for the associated document.
Member<PictureInPictureWindow> picture_in_picture_window_;
};
diff --git a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl
index 8c2ee1dbaf6..767905efa34 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl
+++ b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl
@@ -6,7 +6,7 @@
[
ImplementedAs=NavigatorPlugins
] partial interface Navigator {
- readonly attribute PluginArray plugins;
- readonly attribute MimeTypeArray mimeTypes;
+ [HighEntropy, MeasureAs=NavigatorPlugins] readonly attribute PluginArray plugins;
+ [HighEntropy, MeasureAs=NavigatorMimeTypes] readonly attribute MimeTypeArray mimeTypes;
boolean javaEnabled();
};
diff --git a/chromium/third_party/blink/renderer/modules/plugins/plugin_array.idl b/chromium/third_party/blink/renderer/modules/plugins/plugin_array.idl
index 8b744aa03be..2ada86b9970 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/plugin_array.idl
+++ b/chromium/third_party/blink/renderer/modules/plugins/plugin_array.idl
@@ -27,5 +27,5 @@
readonly attribute unsigned long length;
getter Plugin? item(unsigned long index);
getter Plugin? namedItem(DOMString name);
- void refresh([Default=Undefined] optional boolean reload);
+ void refresh([DefaultValue=Undefined] optional boolean reload);
};
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc
index f4510ba9820..eec6565df41 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/modules/presentation/presentation_availability.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -77,11 +76,11 @@ bool PresentationAvailability::HasPendingActivity() const {
return state_ != State::kInactive;
}
-void PresentationAvailability::Unpause() {
+void PresentationAvailability::ContextUnpaused() {
SetState(State::kActive);
}
-void PresentationAvailability::Pause() {
+void PresentationAvailability::ContextPaused(PauseState) {
SetState(State::kSuspended);
}
@@ -107,8 +106,7 @@ void PresentationAvailability::UpdateListening() {
return;
if (state_ == State::kActive &&
- (To<Document>(GetExecutionContext())->GetPageVisibilityState() ==
- mojom::PageVisibilityState::kVisible))
+ (To<Document>(GetExecutionContext())->IsPageVisible()))
controller->GetAvailabilityState()->AddObserver(this);
else
controller->GetAvailabilityState()->RemoveObserver(this);
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.h b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.h
index bbef7b4daf6..c311012dc2b 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.h
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.h
@@ -9,7 +9,7 @@
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/page/page_visibility_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/presentation/presentation_availability_observer.h"
@@ -54,8 +54,8 @@ class MODULES_EXPORT PresentationAvailability final
bool HasPendingActivity() const final;
// PausableObject implementation.
- void Pause() override;
- void Unpause() override;
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
void ContextDestroyed(ExecutionContext*) override;
// PageVisibilityObserver implementation.
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_test.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_test.cc
index b2a654b5770..20adb7e1b09 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_test.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_test.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/modules/presentation/presentation_availability.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -30,7 +29,7 @@ TEST(PresentationAvailabilityTest, NoPageVisibilityChangeAfterDetach) {
urls.push_back(url_test_helpers::ToKURL("https://another.com"));
Persistent<PresentationAvailabilityProperty> resolver =
- new PresentationAvailabilityProperty(
+ MakeGarbageCollected<PresentationAvailabilityProperty>(
scope.GetExecutionContext(), nullptr,
PresentationAvailabilityProperty::kReady);
Persistent<PresentationAvailability> availability =
@@ -42,7 +41,7 @@ TEST(PresentationAvailabilityTest, NoPageVisibilityChangeAfterDetach) {
// TODO(dcheng): Why are we calling functions on Page after it's been closed?
// This case doesn't seem like it should be reachable as we should be shutting
// down communication from the embedder on context detach.
- page->SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
+ page->SetIsHidden(/*is_hidden=*/true, /*initial_state=*/false);
}
} // anonymous namespace
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc
index 0c3875d4336..f1f1d433fb1 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc
@@ -235,7 +235,7 @@ ControllerPresentationConnection* ControllerPresentationConnection::Take(
DCHECK(controller);
DCHECK(request);
- auto* connection = new ControllerPresentationConnection(
+ auto* connection = MakeGarbageCollected<ControllerPresentationConnection>(
*controller->GetFrame(), controller, presentation_info.id,
presentation_info.url);
controller->RegisterConnection(connection);
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc
index 3e97d5479b9..cfcda230e7e 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc
@@ -156,10 +156,15 @@ mojom::blink::PresentationServicePtr&
PresentationController::GetPresentationService() {
if (!presentation_service_ && GetFrame() && GetFrame()->Client()) {
auto* interface_provider = GetFrame()->Client()->GetInterfaceProvider();
- interface_provider->GetInterface(mojo::MakeRequest(&presentation_service_));
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetFrame()->GetTaskRunner(TaskType::kPresentation);
+ interface_provider->GetInterface(
+ mojo::MakeRequest(&presentation_service_, task_runner));
mojom::blink::PresentationControllerPtr controller_ptr;
- controller_binding_.Bind(mojo::MakeRequest(&controller_ptr));
+ controller_binding_.Bind(mojo::MakeRequest(&controller_ptr, task_runner),
+ task_runner);
presentation_service_->SetController(std::move(controller_ptr));
}
return presentation_service_;
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
index 4a0d6af3cdd..48c231d611c 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
@@ -32,7 +32,10 @@ PresentationReceiver::PresentationReceiver(LocalFrame* frame)
interface_provider->GetInterface(mojo::MakeRequest(&presentation_service_));
mojom::blink::PresentationReceiverPtr receiver_ptr;
- receiver_binding_.Bind(mojo::MakeRequest(&receiver_ptr));
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ frame->GetTaskRunner(TaskType::kPresentation);
+ receiver_binding_.Bind(mojo::MakeRequest(&receiver_ptr, task_runner),
+ task_runner);
presentation_service_->SetReceiver(std::move(receiver_ptr));
}
@@ -52,7 +55,7 @@ ScriptPromise PresentationReceiver::connectionList(ScriptState* script_state) {
ExecutionContext* execution_context = ExecutionContext::From(script_state);
RecordOriginTypeAccess(*execution_context);
if (!connection_list_property_) {
- connection_list_property_ = new ConnectionListProperty(
+ connection_list_property_ = MakeGarbageCollected<ConnectionListProperty>(
execution_context, this, ConnectionListProperty::kReady);
}
@@ -71,7 +74,7 @@ void PresentationReceiver::Terminate() {
if (!window || window->closed())
return;
- window->close(window);
+ window->Close(window);
}
void PresentationReceiver::RemoveConnection(
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc
index e09a5126395..61b676c52b3 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc
@@ -10,7 +10,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/modules/presentation/presentation_connection.h"
@@ -20,15 +20,8 @@
namespace blink {
-class MockEventListenerForPresentationReceiver : public EventListener {
+class MockEventListenerForPresentationReceiver : public NativeEventListener {
public:
- MockEventListenerForPresentationReceiver()
- : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
MOCK_METHOD2(Invoke, void(ExecutionContext* executionContext, Event*));
};
@@ -82,8 +75,8 @@ TEST_F(PresentationReceiverTest, NoConnectionUnresolvedConnectionList) {
auto* receiver =
MakeGarbageCollected<PresentationReceiver>(&scope.GetFrame());
- auto* event_handler =
- new StrictMock<MockEventListenerForPresentationReceiver>();
+ auto* event_handler = MakeGarbageCollected<
+ StrictMock<MockEventListenerForPresentationReceiver>>();
AddConnectionavailableEventListener(event_handler, receiver);
EXPECT_CALL(*event_handler, Invoke(testing::_, testing::_)).Times(0);
@@ -99,8 +92,8 @@ TEST_F(PresentationReceiverTest, OneConnectionResolvedConnectionListNoEvent) {
auto* receiver =
MakeGarbageCollected<PresentationReceiver>(&scope.GetFrame());
- auto* event_handler =
- new StrictMock<MockEventListenerForPresentationReceiver>();
+ auto* event_handler = MakeGarbageCollected<
+ StrictMock<MockEventListenerForPresentationReceiver>>();
AddConnectionavailableEventListener(event_handler, receiver);
EXPECT_CALL(*event_handler, Invoke(testing::_, testing::_)).Times(0);
@@ -122,7 +115,8 @@ TEST_F(PresentationReceiverTest, TwoConnectionsFireOnconnectionavailableEvent) {
MakeGarbageCollected<PresentationReceiver>(&scope.GetFrame());
StrictMock<MockEventListenerForPresentationReceiver>* event_handler =
- new StrictMock<MockEventListenerForPresentationReceiver>();
+ MakeGarbageCollected<
+ StrictMock<MockEventListenerForPresentationReceiver>>();
AddConnectionavailableEventListener(event_handler, receiver);
EXPECT_CALL(*event_handler, Invoke(testing::_, testing::_)).Times(1);
@@ -154,7 +148,8 @@ TEST_F(PresentationReceiverTest, TwoConnectionsNoEvent) {
MakeGarbageCollected<PresentationReceiver>(&scope.GetFrame());
StrictMock<MockEventListenerForPresentationReceiver>* event_handler =
- new StrictMock<MockEventListenerForPresentationReceiver>();
+ MakeGarbageCollected<
+ StrictMock<MockEventListenerForPresentationReceiver>>();
AddConnectionavailableEventListener(event_handler, receiver);
EXPECT_CALL(*event_handler, Invoke(testing::_, testing::_)).Times(0);
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc
index 3258500b76f..7d5c646ba8b 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc
@@ -210,9 +210,10 @@ ScriptPromise PresentationRequest::getAvailability(ScriptState* script_state) {
"The PresentationRequest is no longer associated to a frame."));
if (!availability_property_) {
- availability_property_ = new PresentationAvailabilityProperty(
- ExecutionContext::From(script_state), this,
- PresentationAvailabilityProperty::kReady);
+ availability_property_ =
+ MakeGarbageCollected<PresentationAvailabilityProperty>(
+ ExecutionContext::From(script_state), this,
+ PresentationAvailabilityProperty::kReady);
controller->GetAvailabilityState()->RequestAvailability(
urls_, std::make_unique<PresentationAvailabilityCallbacks>(
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.idl b/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.idl
index 144112304cd..d9ace9fa912 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.idl
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.idl
@@ -13,5 +13,5 @@
[CallWith=ScriptState, RaisesException] Promise<PushSubscription> subscribe(optional PushSubscriptionOptionsInit options);
[CallWith=ScriptState] Promise<PushSubscription?> getSubscription();
- [CallWith=ScriptState, RaisesException] Promise permissionState(optional PushSubscriptionOptionsInit options);
+ [CallWith=ScriptState, RaisesException] Promise<PushPermissionState> permissionState(optional PushSubscriptionOptionsInit options);
};
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription.idl b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription.idl
index 9304c0258c2..62bdefe6094 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription.idl
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription.idl
@@ -20,5 +20,6 @@ enum PushEncryptionKeyName {
ArrayBuffer? getKey(PushEncryptionKeyName name);
[CallWith=ScriptState] Promise<boolean> unsubscribe();
- serializer;
+ // TODO(peria): Return type should be PushSubscriptionJSON.
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_test.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_test.cc
index f547d844d78..b8c7f895534 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_test.cc
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_test.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/modules/push_messaging/push_subscription.h"
-#include "base/macros.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/push_messaging/web_push_subscription.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
@@ -35,8 +35,8 @@ TEST(PushSubscriptionTest, SerializesToBase64URLWithoutPadding) {
WebPushSubscription web_subscription(
WebURL() /* endpoint */, true /* user_visible_only */,
WebString() /* application_server_key */,
- WebVector<unsigned char>(kP256DH, arraysize(kP256DH)),
- WebVector<unsigned char>(kAuthSecret, arraysize(kAuthSecret)));
+ WebVector<unsigned char>(kP256DH, base::size(kP256DH)),
+ WebVector<unsigned char>(kAuthSecret, base::size(kAuthSecret)));
PushSubscription subscription(web_subscription,
nullptr /* service_worker_registration */);
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.cc
index 617d273383b..9def6729425 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.cc
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.cc
@@ -28,47 +28,20 @@ void HTMLMediaElementRemotePlayback::SetBooleanAttribute(
DCHECK(name == html_names::kDisableremoteplaybackAttr);
element.SetBooleanAttribute(name, value);
- HTMLMediaElementRemotePlayback& self =
- HTMLMediaElementRemotePlayback::From(element);
- if (self.remote_ && value)
- self.remote_->RemotePlaybackDisabled();
-}
-
-// static
-HTMLMediaElementRemotePlayback& HTMLMediaElementRemotePlayback::From(
- HTMLMediaElement& element) {
- HTMLMediaElementRemotePlayback* supplement =
- Supplement<HTMLMediaElement>::From<HTMLMediaElementRemotePlayback>(
- element);
- if (!supplement) {
- supplement = MakeGarbageCollected<HTMLMediaElementRemotePlayback>();
- ProvideTo(element, supplement);
- }
- return *supplement;
+ RemotePlayback& remote_playback = RemotePlayback::From(element);
+ if (value)
+ remote_playback.RemotePlaybackDisabled();
}
// static
RemotePlayback* HTMLMediaElementRemotePlayback::remote(
HTMLMediaElement& element) {
- HTMLMediaElementRemotePlayback& self =
- HTMLMediaElementRemotePlayback::From(element);
+ RemotePlayback& remote_playback = RemotePlayback::From(element);
Document& document = element.GetDocument();
if (!document.GetFrame())
return nullptr;
- if (!self.remote_)
- self.remote_ = RemotePlayback::Create(element);
-
- return self.remote_;
-}
-
-// static
-const char HTMLMediaElementRemotePlayback::kSupplementName[] =
- "HTMLMediaElementRemotePlayback";
-
-void HTMLMediaElementRemotePlayback::Trace(blink::Visitor* visitor) {
- visitor->Trace(remote_);
- Supplement<HTMLMediaElement>::Trace(visitor);
+ return &remote_playback;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h b/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h
index c23bb61184b..e4a04679567 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/html_media_element_remote_playback.h
@@ -16,16 +16,10 @@ class HTMLMediaElement;
class QualifiedName;
class RemotePlayback;
-// Class used to implement the Remote Playback API. It is a supplement to
-// HTMLMediaElement.
-class MODULES_EXPORT HTMLMediaElementRemotePlayback final
- : public GarbageCollected<HTMLMediaElementRemotePlayback>,
- public Supplement<HTMLMediaElement> {
- USING_GARBAGE_COLLECTED_MIXIN(HTMLMediaElementRemotePlayback);
-
+// Collection of static methods only used for bindings in the context of the
+// Remote Playback API.
+class MODULES_EXPORT HTMLMediaElementRemotePlayback final {
public:
- static const char kSupplementName[];
-
static bool FastHasAttribute(const QualifiedName&, const HTMLMediaElement&);
static void SetBooleanAttribute(const QualifiedName&,
HTMLMediaElement&,
@@ -33,11 +27,6 @@ class MODULES_EXPORT HTMLMediaElementRemotePlayback final
static HTMLMediaElementRemotePlayback& From(HTMLMediaElement&);
static RemotePlayback* remote(HTMLMediaElement&);
-
- void Trace(blink::Visitor*) override;
-
- private:
- Member<RemotePlayback> remote_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
index bc20e505cbb..bc1154f5242 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/core/html/media/remote_playback_observer.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -72,12 +73,19 @@ bool IsBackgroundAvailabilityMonitoringDisabled() {
} // anonymous namespace
// static
-RemotePlayback* RemotePlayback::Create(HTMLMediaElement& element) {
- return MakeGarbageCollected<RemotePlayback>(element);
+RemotePlayback& RemotePlayback::From(HTMLMediaElement& element) {
+ RemotePlayback* self =
+ static_cast<RemotePlayback*>(RemotePlaybackController::From(element));
+ if (!self) {
+ self = MakeGarbageCollected<RemotePlayback>(element);
+ RemotePlaybackController::ProvideTo(element, self);
+ }
+ return *self;
}
RemotePlayback::RemotePlayback(HTMLMediaElement& element)
: ContextLifecycleObserver(element.GetExecutionContext()),
+ RemotePlaybackController(element),
state_(element.IsPlayingRemotely()
? WebRemotePlaybackState::kConnected
: WebRemotePlaybackState::kDisconnected),
@@ -108,7 +116,8 @@ ScriptPromise RemotePlayback::watchAvailability(
return promise;
}
- int id = WatchAvailabilityInternal(new AvailabilityCallbackWrapper(callback));
+ int id = WatchAvailabilityInternal(
+ MakeGarbageCollected<AvailabilityCallbackWrapper>(callback));
if (id == kWatchAvailabilityNotSupported) {
resolver->Reject(DOMException::Create(
DOMExceptionCode::kNotSupportedError,
@@ -380,6 +389,9 @@ void RemotePlayback::StateChanged(WebRemotePlaybackState state) {
}
break;
}
+
+ for (auto observer : observers_)
+ observer->OnRemotePlaybackStateChanged(state_);
}
void RemotePlayback::AvailabilityChanged(
@@ -395,6 +407,9 @@ void RemotePlayback::AvailabilityChanged(
for (auto& callback : availability_callbacks_.Values())
callback->Run(this, new_availability);
+
+ for (auto observer : observers_)
+ observer->OnRemotePlaybackAvailabilityChanged(availability_);
}
void RemotePlayback::PromptCancelled() {
@@ -435,6 +450,14 @@ WebString RemotePlayback::GetPresentationId() {
return presentation_id_;
}
+void RemotePlayback::AddObserver(RemotePlaybackObserver* observer) {
+ observers_.insert(observer);
+}
+
+void RemotePlayback::RemoveObserver(RemotePlaybackObserver* observer) {
+ observers_.erase(observer);
+}
+
bool RemotePlayback::RemotePlaybackAvailable() const {
if (IsBackgroundAvailabilityMonitoringDisabled() &&
RuntimeEnabledFeatures::RemotePlaybackBackendEnabled() &&
@@ -622,8 +645,10 @@ void RemotePlayback::Trace(blink::Visitor* visitor) {
visitor->Trace(availability_callbacks_);
visitor->Trace(prompt_promise_resolver_);
visitor->Trace(media_element_);
+ visitor->Trace(observers_);
EventTargetWithInlineData::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
+ RemotePlaybackController::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h
index bed56ca4273..8002acd5dbe 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/html/media/remote_playback_controller.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/presentation/presentation_availability_observer.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
@@ -46,16 +47,18 @@ class MODULES_EXPORT RemotePlayback final
public ActiveScriptWrappable<RemotePlayback>,
public WebRemotePlaybackClient,
public PresentationAvailabilityObserver,
- public mojom::blink::PresentationConnection {
+ public mojom::blink::PresentationConnection,
+ public RemotePlaybackController {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(RemotePlayback);
+ WTF_MAKE_NONCOPYABLE(RemotePlayback);
public:
// Result of WatchAvailabilityInternal that means availability is not
// supported.
static const int kWatchAvailabilityNotSupported = -1;
- static RemotePlayback* Create(HTMLMediaElement&);
+ static RemotePlayback& From(HTMLMediaElement&);
explicit RemotePlayback(HTMLMediaElement&);
@@ -120,6 +123,10 @@ class MODULES_EXPORT RemotePlayback final
void SourceChanged(const WebURL&, bool is_source_supported) override;
WebString GetPresentationId() override;
+ // RemotePlaybackController implementation.
+ void AddObserver(RemotePlaybackObserver*) override;
+ void RemoveObserver(RemotePlaybackObserver*) override;
+
// ScriptWrappable implementation.
bool HasPendingActivity() const final;
@@ -168,6 +175,8 @@ class MODULES_EXPORT RemotePlayback final
mojo::Binding<mojom::blink::PresentationConnection>
presentation_connection_binding_;
mojom::blink::PresentationConnectionPtr target_presentation_connection_;
+
+ HeapHashSet<Member<RemotePlaybackObserver>> observers_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc
index 4c000cc6816..5464f63bb7a 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc
@@ -10,7 +10,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_remote_playback_availability_callback.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
@@ -27,7 +27,8 @@ namespace blink {
class MockFunction : public ScriptFunction {
public:
static testing::StrictMock<MockFunction>* Create(ScriptState* script_state) {
- return new testing::StrictMock<MockFunction>(script_state);
+ return MakeGarbageCollected<testing::StrictMock<MockFunction>>(
+ script_state);
}
v8::Local<v8::Function> Bind() { return BindToV8Function(); }
@@ -39,14 +40,8 @@ class MockFunction : public ScriptFunction {
: ScriptFunction(script_state) {}
};
-class MockEventListenerForRemotePlayback : public EventListener {
+class MockEventListenerForRemotePlayback : public NativeEventListener {
public:
- MockEventListenerForRemotePlayback() : EventListener(kCPPEventListenerType) {}
-
- bool operator==(const EventListener& other) const final {
- return this == &other;
- }
-
MOCK_METHOD2(Invoke, void(ExecutionContext* executionContext, Event*));
};
@@ -68,16 +63,16 @@ class RemotePlaybackTest : public testing::Test,
RemotePlaybackTest() : ScopedRemotePlaybackBackendForTest(true) {}
protected:
- void CancelPrompt(RemotePlayback* remote_playback) {
- remote_playback->PromptCancelled();
+ void CancelPrompt(RemotePlayback& remote_playback) {
+ remote_playback.PromptCancelled();
}
- void SetState(RemotePlayback* remote_playback, WebRemotePlaybackState state) {
- remote_playback->StateChanged(state);
+ void SetState(RemotePlayback& remote_playback, WebRemotePlaybackState state) {
+ remote_playback.StateChanged(state);
}
- bool IsListening(RemotePlayback* remote_playback) {
- return remote_playback->is_listening_;
+ bool IsListening(RemotePlayback& remote_playback) {
+ return remote_playback.is_listening_;
}
};
@@ -88,8 +83,7 @@ TEST_F(RemotePlaybackTest, PromptCancelledRejectsWithNotAllowedError) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
auto* resolve = MockFunction::Create(scope.GetScriptState());
auto* reject = MockFunction::Create(scope.GetScriptState());
@@ -100,7 +94,7 @@ TEST_F(RemotePlaybackTest, PromptCancelledRejectsWithNotAllowedError) {
std::unique_ptr<UserGestureIndicator> indicator =
LocalFrame::NotifyUserActivation(&page_holder->GetFrame(),
UserGestureToken::kNewGesture);
- remote_playback->prompt(scope.GetScriptState())
+ remote_playback.prompt(scope.GetScriptState())
.Then(resolve->Bind(), reject->Bind());
CancelPrompt(remote_playback);
@@ -120,8 +114,7 @@ TEST_F(RemotePlaybackTest, PromptConnectedRejectsWhenCancelled) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
auto* resolve = MockFunction::Create(scope.GetScriptState());
auto* reject = MockFunction::Create(scope.GetScriptState());
@@ -134,7 +127,7 @@ TEST_F(RemotePlaybackTest, PromptConnectedRejectsWhenCancelled) {
std::unique_ptr<UserGestureIndicator> indicator =
LocalFrame::NotifyUserActivation(&page_holder->GetFrame(),
UserGestureToken::kNewGesture);
- remote_playback->prompt(scope.GetScriptState())
+ remote_playback.prompt(scope.GetScriptState())
.Then(resolve->Bind(), reject->Bind());
CancelPrompt(remote_playback);
@@ -154,8 +147,7 @@ TEST_F(RemotePlaybackTest, PromptConnectedResolvesWhenDisconnected) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
auto* resolve = MockFunction::Create(scope.GetScriptState());
auto* reject = MockFunction::Create(scope.GetScriptState());
@@ -168,7 +160,7 @@ TEST_F(RemotePlaybackTest, PromptConnectedResolvesWhenDisconnected) {
std::unique_ptr<UserGestureIndicator> indicator =
LocalFrame::NotifyUserActivation(&page_holder->GetFrame(),
UserGestureToken::kNewGesture);
- remote_playback->prompt(scope.GetScriptState())
+ remote_playback.prompt(scope.GetScriptState())
.Then(resolve->Bind(), reject->Bind());
SetState(remote_playback, WebRemotePlaybackState::kDisconnected);
@@ -189,22 +181,20 @@ TEST_F(RemotePlaybackTest, StateChangeEvents) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
-
- auto* connecting_handler =
- new testing::StrictMock<MockEventListenerForRemotePlayback>();
- auto* connect_handler =
- new testing::StrictMock<MockEventListenerForRemotePlayback>();
- auto* disconnect_handler =
- new testing::StrictMock<MockEventListenerForRemotePlayback>();
-
- remote_playback->addEventListener(event_type_names::kConnecting,
- connecting_handler);
- remote_playback->addEventListener(event_type_names::kConnect,
- connect_handler);
- remote_playback->addEventListener(event_type_names::kDisconnect,
- disconnect_handler);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
+
+ auto* connecting_handler = MakeGarbageCollected<
+ testing::StrictMock<MockEventListenerForRemotePlayback>>();
+ auto* connect_handler = MakeGarbageCollected<
+ testing::StrictMock<MockEventListenerForRemotePlayback>>();
+ auto* disconnect_handler = MakeGarbageCollected<
+ testing::StrictMock<MockEventListenerForRemotePlayback>>();
+
+ remote_playback.addEventListener(event_type_names::kConnecting,
+ connecting_handler);
+ remote_playback.addEventListener(event_type_names::kConnect, connect_handler);
+ remote_playback.addEventListener(event_type_names::kDisconnect,
+ disconnect_handler);
EXPECT_CALL(*connecting_handler, Invoke(testing::_, testing::_)).Times(1);
EXPECT_CALL(*connect_handler, Invoke(testing::_, testing::_)).Times(1);
@@ -232,8 +222,7 @@ TEST_F(RemotePlaybackTest,
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
MockFunction* resolve = MockFunction::Create(scope.GetScriptState());
MockFunction* reject = MockFunction::Create(scope.GetScriptState());
@@ -244,7 +233,7 @@ TEST_F(RemotePlaybackTest,
std::unique_ptr<UserGestureIndicator> indicator =
LocalFrame::NotifyUserActivation(&page_holder->GetFrame(),
UserGestureToken::kNewGesture);
- remote_playback->prompt(scope.GetScriptState())
+ remote_playback.prompt(scope.GetScriptState())
.Then(resolve->Bind(), reject->Bind());
HTMLMediaElementRemotePlayback::SetBooleanAttribute(
html_names::kDisableremoteplaybackAttr, *element, true);
@@ -265,8 +254,7 @@ TEST_F(RemotePlaybackTest, DisableRemotePlaybackCancelsAvailabilityCallbacks) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
MockFunction* callback_function =
MockFunction::Create(scope.GetScriptState());
@@ -284,7 +272,7 @@ TEST_F(RemotePlaybackTest, DisableRemotePlaybackCancelsAvailabilityCallbacks) {
EXPECT_CALL(*reject, Call(testing::_)).Times(0);
remote_playback
- ->watchAvailability(scope.GetScriptState(), availability_callback)
+ .watchAvailability(scope.GetScriptState(), availability_callback)
.Then(resolve->Bind(), reject->Bind());
HTMLMediaElementRemotePlayback::SetBooleanAttribute(
@@ -308,8 +296,7 @@ TEST_F(RemotePlaybackTest, PromptThrowsWhenBackendDisabled) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
auto* resolve = MockFunction::Create(scope.GetScriptState());
auto* reject = MockFunction::Create(scope.GetScriptState());
@@ -320,7 +307,7 @@ TEST_F(RemotePlaybackTest, PromptThrowsWhenBackendDisabled) {
std::unique_ptr<UserGestureIndicator> indicator =
LocalFrame::NotifyUserActivation(&page_holder->GetFrame(),
UserGestureToken::kNewGesture);
- remote_playback->prompt(scope.GetScriptState())
+ remote_playback.prompt(scope.GetScriptState())
.Then(resolve->Bind(), reject->Bind());
// Runs pending promises.
@@ -340,8 +327,7 @@ TEST_F(RemotePlaybackTest, WatchAvailabilityWorksWhenBackendDisabled) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
MockFunction* callback_function =
MockFunction::Create(scope.GetScriptState());
@@ -359,7 +345,7 @@ TEST_F(RemotePlaybackTest, WatchAvailabilityWorksWhenBackendDisabled) {
EXPECT_CALL(*reject, Call(testing::_)).Times(0);
remote_playback
- ->watchAvailability(scope.GetScriptState(), availability_callback)
+ .watchAvailability(scope.GetScriptState(), availability_callback)
.Then(resolve->Bind(), reject->Bind());
// Runs pending promises.
@@ -380,8 +366,7 @@ TEST_F(RemotePlaybackTest, IsListening) {
HTMLMediaElement* element =
HTMLVideoElement::Create(page_holder->GetDocument());
- RemotePlayback* remote_playback =
- HTMLMediaElementRemotePlayback::remote(*element);
+ RemotePlayback& remote_playback = RemotePlayback::From(*element);
LocalFrame& frame = page_holder->GetFrame();
MockPresentationController* mock_controller =
@@ -390,10 +375,10 @@ TEST_F(RemotePlaybackTest, IsListening) {
frame, static_cast<PresentationController*>(mock_controller));
EXPECT_CALL(*mock_controller,
- AddAvailabilityObserver(testing::Eq(remote_playback)))
+ AddAvailabilityObserver(testing::Eq(&remote_playback)))
.Times(2);
EXPECT_CALL(*mock_controller,
- RemoveAvailabilityObserver(testing::Eq(remote_playback)))
+ RemoveAvailabilityObserver(testing::Eq(&remote_playback)))
.Times(2);
MockFunction* callback_function =
@@ -405,33 +390,33 @@ TEST_F(RemotePlaybackTest, IsListening) {
// message loop.
EXPECT_CALL(*callback_function, Call(testing::_)).Times(2);
- remote_playback->watchAvailability(scope.GetScriptState(),
- availability_callback);
+ remote_playback.watchAvailability(scope.GetScriptState(),
+ availability_callback);
- ASSERT_TRUE(remote_playback->Urls().IsEmpty());
+ ASSERT_TRUE(remote_playback.Urls().IsEmpty());
ASSERT_FALSE(IsListening(remote_playback));
- remote_playback->SourceChanged(WebURL(KURL("http://www.example.com")), true);
- ASSERT_EQ((size_t)1, remote_playback->Urls().size());
+ remote_playback.SourceChanged(WebURL(KURL("http://www.example.com")), true);
+ ASSERT_EQ((size_t)1, remote_playback.Urls().size());
ASSERT_TRUE(IsListening(remote_playback));
- remote_playback->AvailabilityChanged(mojom::ScreenAvailability::AVAILABLE);
+ remote_playback.AvailabilityChanged(mojom::ScreenAvailability::AVAILABLE);
- remote_playback->cancelWatchAvailability(scope.GetScriptState());
- ASSERT_EQ((size_t)1, remote_playback->Urls().size());
+ remote_playback.cancelWatchAvailability(scope.GetScriptState());
+ ASSERT_EQ((size_t)1, remote_playback.Urls().size());
ASSERT_FALSE(IsListening(remote_playback));
- remote_playback->watchAvailability(scope.GetScriptState(),
- availability_callback);
- ASSERT_EQ((size_t)1, remote_playback->Urls().size());
+ remote_playback.watchAvailability(scope.GetScriptState(),
+ availability_callback);
+ ASSERT_EQ((size_t)1, remote_playback.Urls().size());
ASSERT_TRUE(IsListening(remote_playback));
- remote_playback->AvailabilityChanged(mojom::ScreenAvailability::AVAILABLE);
+ remote_playback.AvailabilityChanged(mojom::ScreenAvailability::AVAILABLE);
- remote_playback->SourceChanged(WebURL(), false);
- ASSERT_TRUE(remote_playback->Urls().IsEmpty());
+ remote_playback.SourceChanged(WebURL(), false);
+ ASSERT_TRUE(remote_playback.Urls().IsEmpty());
ASSERT_FALSE(IsListening(remote_playback));
- remote_playback->SourceChanged(WebURL(KURL("@$@#@#")), true);
- ASSERT_TRUE(remote_playback->Urls().IsEmpty());
+ remote_playback.SourceChanged(WebURL(KURL("@$@#@#")), true);
+ ASSERT_TRUE(remote_playback.Urls().IsEmpty());
ASSERT_FALSE(IsListening(remote_playback));
// Runs pending promises.
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.cc b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.cc
index f3bcbaceab8..a046c68cac2 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.cc
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "base/stl_util.h"
#include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -58,7 +59,7 @@ static ScreenOrientationInfo* OrientationsMap(unsigned& length) {
{portrait, kWebScreenOrientationLockPortrait},
{landscape, kWebScreenOrientationLockLandscape},
{natural, kWebScreenOrientationLockNatural}};
- length = arraysize(orientation_map);
+ length = base::size(orientation_map);
return orientation_map;
}
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.idl b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.idl
index f46ee2916ae..3343e61c99b 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.idl
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation.idl
@@ -26,7 +26,7 @@ interface ScreenOrientation : EventTarget {
[MeasureAs=ScreenOrientationAngle] readonly attribute unsigned short angle;
[MeasureAs=ScreenOrientationType] readonly attribute DOMString type;
- [CallWith=ScriptState, MeasureAs=ScreenOrientationLock] Promise lock(OrientationLockType orientation);
+ [CallWith=ScriptState, MeasureAs=ScreenOrientationLock] Promise<void> lock(OrientationLockType orientation);
[MeasureAs=ScreenOrientationUnlock] void unlock();
attribute EventHandler onchange;
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc
index 67512ed90df..2688832bcfa 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc
@@ -13,7 +13,7 @@ namespace blink {
ScreenOrientationDispatcher& ScreenOrientationDispatcher::Instance() {
DEFINE_STATIC_LOCAL(Persistent<ScreenOrientationDispatcher>,
screen_orientation_dispatcher,
- (new ScreenOrientationDispatcher));
+ (MakeGarbageCollected<ScreenOrientationDispatcher>()));
return *screen_orientation_dispatcher;
}
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.h b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.h
index e928d510e6c..8b22668a2ae 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.h
@@ -28,13 +28,12 @@ class ScreenOrientationDispatcher final
public:
static ScreenOrientationDispatcher& Instance();
+ ScreenOrientationDispatcher();
~ScreenOrientationDispatcher();
void Trace(blink::Visitor*) override;
private:
- ScreenOrientationDispatcher();
-
// Inherited from PlatformEventDispatcher.
void StartListening(LocalFrame*) override;
void StopListening() override;
diff --git a/chromium/third_party/blink/renderer/modules/sensor/README.md b/chromium/third_party/blink/renderer/modules/sensor/README.md
index 2b6e9024e5d..4231db0e4b7 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/README.md
+++ b/chromium/third_party/blink/renderer/modules/sensor/README.md
@@ -15,7 +15,7 @@ The platform-specific parts of the implementation are located in
## Testing
-Sensors layout tests are located in `web_tests/sensor`.
+Sensors web tests are located in `web_tests/sensor`.
Sensors browser tests are located in `content/test/data/generic_sensor`.
diff --git a/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.cc
index b2f1a985b35..17b391a5817 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.cc
@@ -12,8 +12,8 @@ AbsoluteOrientationSensor* AbsoluteOrientationSensor::Create(
ExecutionContext* execution_context,
const SpatialSensorOptions* options,
ExceptionState& exception_state) {
- return new AbsoluteOrientationSensor(execution_context, options,
- exception_state);
+ return MakeGarbageCollected<AbsoluteOrientationSensor>(
+ execution_context, options, exception_state);
}
// static
diff --git a/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.h b/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.h
index 5820f49f8c6..225282f9faf 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.h
@@ -19,12 +19,11 @@ class AbsoluteOrientationSensor final : public OrientationSensor {
ExceptionState&);
static AbsoluteOrientationSensor* Create(ExecutionContext*, ExceptionState&);
- void Trace(blink::Visitor*) override;
-
- private:
AbsoluteOrientationSensor(ExecutionContext*,
const SpatialSensorOptions*,
ExceptionState&);
+
+ void Trace(blink::Visitor*) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sensor/accelerometer.cc b/chromium/third_party/blink/renderer/modules/sensor/accelerometer.cc
index 26b5ec437ae..e9f332e53cc 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/accelerometer.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/accelerometer.cc
@@ -11,9 +11,11 @@ namespace blink {
Accelerometer* Accelerometer::Create(ExecutionContext* execution_context,
const SpatialSensorOptions* options,
ExceptionState& exception_state) {
- return new Accelerometer(execution_context, options, exception_state,
- SensorType::ACCELEROMETER,
- {mojom::FeaturePolicyFeature::kAccelerometer});
+ const Vector<mojom::FeaturePolicyFeature> features(
+ {mojom::FeaturePolicyFeature::kAccelerometer});
+ return MakeGarbageCollected<Accelerometer>(
+ execution_context, options, exception_state, SensorType::ACCELEROMETER,
+ features);
}
// static
diff --git a/chromium/third_party/blink/renderer/modules/sensor/accelerometer.h b/chromium/third_party/blink/renderer/modules/sensor/accelerometer.h
index 38bf7715205..5005db7f04c 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/accelerometer.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/accelerometer.h
@@ -19,18 +19,17 @@ class Accelerometer : public Sensor {
ExceptionState&);
static Accelerometer* Create(ExecutionContext*, ExceptionState&);
- double x(bool& is_null) const;
- double y(bool& is_null) const;
- double z(bool& is_null) const;
-
- void Trace(blink::Visitor*) override;
-
- protected:
Accelerometer(ExecutionContext*,
const SpatialSensorOptions*,
ExceptionState&,
device::mojom::blink::SensorType,
const Vector<mojom::FeaturePolicyFeature>&);
+
+ double x(bool& is_null) const;
+ double y(bool& is_null) const;
+ double z(bool& is_null) const;
+
+ void Trace(blink::Visitor*) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.cc
index f4695887b7c..58e3961a5a7 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.cc
@@ -16,7 +16,8 @@ AmbientLightSensor* AmbientLightSensor::Create(
ExecutionContext* execution_context,
const SensorOptions* options,
ExceptionState& exception_state) {
- return new AmbientLightSensor(execution_context, options, exception_state);
+ return MakeGarbageCollected<AmbientLightSensor>(execution_context, options,
+ exception_state);
}
// static
diff --git a/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.h b/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.h
index c7dfcbdcd4f..34b3f1e0ec0 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor.h
@@ -18,12 +18,11 @@ class AmbientLightSensor final : public Sensor {
ExceptionState&);
static AmbientLightSensor* Create(ExecutionContext*, ExceptionState&);
+ AmbientLightSensor(ExecutionContext*, const SensorOptions*, ExceptionState&);
+
double illuminance(bool& is_null) const;
void Trace(blink::Visitor*) override;
-
- private:
- AmbientLightSensor(ExecutionContext*, const SensorOptions*, ExceptionState&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
index b4efc3b615e..1d362011d3e 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -131,7 +131,7 @@ DOMHighResTimeStamp Sensor::timestamp(ScriptState* script_state,
is_null = false;
if (WebTestSupport::IsRunningWebTest()) {
- // In layout tests performance.now() * 0.001 is passed to the shared buffer.
+ // In web tests performance.now() * 0.001 is passed to the shared buffer.
return sensor_proxy_->GetReading().timestamp() * 1000;
}
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor.h b/chromium/third_party/blink/renderer/modules/sensor/sensor.h
index 1be8636e93a..a47b82f4a4a 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor.h
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/core/dom/dom_time_stamp.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
#include "third_party/blink/renderer/core/frame/platform_event_controller.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/sensor/sensor_options.h"
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
index 9b3fed19a89..e32c2c7df62 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/modules/sensor/sensor_proxy.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_screen_info.h"
@@ -111,7 +110,7 @@ void SensorProxy::UpdateSuspendedStatus() {
}
bool SensorProxy::ShouldSuspendUpdates() const {
- if (GetPage()->VisibilityState() != mojom::PageVisibilityState::kVisible)
+ if (!GetPage()->IsPageVisible())
return true;
LocalFrame* focused_frame = GetPage()->GetFocusController().FocusedFrame();
diff --git a/chromium/third_party/blink/renderer/modules/serial/DEPS b/chromium/third_party/blink/renderer/modules/serial/DEPS
new file mode 100644
index 00000000000..755fee55635
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/serial/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+base/unguessable_token.h"
+]
diff --git a/chromium/third_party/blink/renderer/modules/serial/OWNERS b/chromium/third_party/blink/renderer/modules/serial/OWNERS
new file mode 100644
index 00000000000..4ae83cac16e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/serial/OWNERS
@@ -0,0 +1,3 @@
+file://content/browser/serial/OWNERS
+
+# COMPONENT: Blink>Serial
diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc
index e9f8bd406b4..aaaa503d94b 100644
--- a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc
@@ -16,7 +16,7 @@ NavigatorSerial& NavigatorSerial::From(Navigator& navigator) {
NavigatorSerial* supplement =
Supplement<Navigator>::From<NavigatorSerial>(navigator);
if (!supplement) {
- supplement = new NavigatorSerial(navigator);
+ supplement = MakeGarbageCollected<NavigatorSerial>(navigator);
ProvideTo(navigator, supplement);
}
return *supplement;
diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h
index 7267c3597ec..6ffce8e109c 100644
--- a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h
+++ b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h
@@ -25,11 +25,11 @@ class NavigatorSerial final : public GarbageCollected<NavigatorSerial>,
static Serial* serial(Navigator&);
Serial* serial() { return serial_; }
+ explicit NavigatorSerial(Navigator&);
+
void Trace(Visitor*) override;
private:
- explicit NavigatorSerial(Navigator&);
-
Member<Serial> serial_;
};
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.cc b/chromium/third_party/blink/renderer/modules/serial/serial.cc
index e88aa55560c..ff015fd601a 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/serial.cc
@@ -3,16 +3,41 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/serial/serial.h"
+
+#include <inttypes.h>
+
+#include "base/unguessable_token.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/event_target_modules_names.h"
+#include "third_party/blink/renderer/modules/serial/serial_port.h"
namespace blink {
+namespace {
+
+const char kNoPortSelected[] = "No port selected by the user.";
+
+String TokenToString(const base::UnguessableToken& token) {
+ // TODO(crbug.com/918702): Implement HashTraits for UnguessableToken.
+ return String::Format("%016" PRIX64 "%016" PRIX64,
+ token.GetHighForSerialization(),
+ token.GetLowForSerialization());
+}
+
+} // namespace
+
// static
Serial* Serial::Create(ExecutionContext& execution_context) {
- return new Serial(execution_context);
+ return MakeGarbageCollected<Serial>(execution_context);
}
+Serial::Serial(ExecutionContext& execution_context)
+ : ContextLifecycleObserver(&execution_context) {}
+
ExecutionContext* Serial::GetExecutionContext() const {
return ContextLifecycleObserver::GetExecutionContext();
}
@@ -22,22 +47,123 @@ const AtomicString& Serial::InterfaceName() const {
}
ScriptPromise Serial::getPorts(ScriptState* script_state) {
- return ScriptPromise::RejectWithDOMException(
- script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
+ if (!GetExecutionContext()) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(DOMExceptionCode::kNotSupportedError));
+ }
+
+ auto* resolver = ScriptPromiseResolver::Create(script_state);
+ get_ports_promises_.insert(resolver);
+
+ EnsureServiceConnection();
+ service_->GetPorts(WTF::Bind(&Serial::OnGetPorts, WrapPersistent(this),
+ WrapPersistent(resolver)));
+
+ return resolver->Promise();
}
ScriptPromise Serial::requestPort(ScriptState* script_state,
const SerialPortRequestOptions* options) {
- return ScriptPromise::RejectWithDOMException(
- script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
+ auto* frame = GetFrame();
+ if (!frame) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(DOMExceptionCode::kNotSupportedError));
+ }
+
+ if (!LocalFrame::HasTransientUserActivation(frame)) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(
+ DOMExceptionCode::kSecurityError,
+ "Must be handling a user gesture to show a permission request."));
+ }
+
+ auto* resolver = ScriptPromiseResolver::Create(script_state);
+ request_port_promises_.insert(resolver);
+
+ EnsureServiceConnection();
+ service_->RequestPort(Vector<mojom::blink::SerialPortFilterPtr>(),
+ WTF::Bind(&Serial::OnRequestPort, WrapPersistent(this),
+ WrapPersistent(resolver)));
+
+ return resolver->Promise();
}
void Serial::Trace(Visitor* visitor) {
+ visitor->Trace(get_ports_promises_);
+ visitor->Trace(request_port_promises_);
+ visitor->Trace(port_cache_);
EventTargetWithInlineData::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
}
-Serial::Serial(ExecutionContext& execution_context)
- : ContextLifecycleObserver(&execution_context) {}
+void Serial::EnsureServiceConnection() {
+ DCHECK(GetExecutionContext());
+
+ if (service_)
+ return;
+
+ auto task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ GetExecutionContext()->GetInterfaceProvider()->GetInterface(
+ mojo::MakeRequest(&service_, task_runner));
+ service_.set_connection_error_handler(
+ WTF::Bind(&Serial::OnServiceConnectionError, WrapWeakPersistent(this)));
+}
+
+void Serial::OnServiceConnectionError() {
+ service_.reset();
+
+ // Script may execute during a call to Resolve(). Swap these sets to prevent
+ // concurrent modification.
+ HeapHashSet<Member<ScriptPromiseResolver>> get_ports_promises;
+ get_ports_promises_.swap(get_ports_promises);
+ for (ScriptPromiseResolver* resolver : get_ports_promises)
+ resolver->Resolve(HeapVector<Member<SerialPort>>());
+
+ HeapHashSet<Member<ScriptPromiseResolver>> request_port_promises;
+ request_port_promises_.swap(request_port_promises);
+ for (ScriptPromiseResolver* resolver : request_port_promises) {
+ resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError,
+ kNoPortSelected));
+ }
+}
+
+SerialPort* Serial::GetOrCreatePort(mojom::blink::SerialPortInfoPtr info) {
+ SerialPort* port = port_cache_.at(TokenToString(info->token));
+ if (!port) {
+ port = MakeGarbageCollected<SerialPort>(std::move(info));
+ port_cache_.insert(TokenToString(port->Token()), port);
+ }
+ return port;
+}
+
+void Serial::OnGetPorts(ScriptPromiseResolver* resolver,
+ Vector<mojom::blink::SerialPortInfoPtr> port_infos) {
+ DCHECK(get_ports_promises_.Contains(resolver));
+ get_ports_promises_.erase(resolver);
+
+ HeapVector<Member<SerialPort>> ports;
+ for (auto& port_info : port_infos)
+ ports.push_back(GetOrCreatePort(std::move(port_info)));
+
+ resolver->Resolve(ports);
+}
+
+void Serial::OnRequestPort(ScriptPromiseResolver* resolver,
+ mojom::blink::SerialPortInfoPtr port_info) {
+ DCHECK(request_port_promises_.Contains(resolver));
+ request_port_promises_.erase(resolver);
+
+ if (!port_info) {
+ resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError,
+ kNoPortSelected));
+ return;
+ }
+
+ resolver->Resolve(GetOrCreatePort(std::move(port_info)));
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.h b/chromium/third_party/blink/renderer/modules/serial/serial.h
index 3edf86105e1..930871ee276 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial.h
+++ b/chromium/third_party/blink/renderer/modules/serial/serial.h
@@ -5,17 +5,21 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_
+#include "third_party/blink/public/mojom/serial/serial.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
class ExecutionContext;
+class ScriptPromiseResolver;
class ScriptState;
+class SerialPort;
class SerialPortRequestOptions;
class Serial final : public EventTargetWithInlineData,
@@ -26,6 +30,8 @@ class Serial final : public EventTargetWithInlineData,
public:
static Serial* Create(ExecutionContext& executionContext);
+ explicit Serial(ExecutionContext&);
+
// EventTarget
ExecutionContext* GetExecutionContext() const override;
const AtomicString& InterfaceName() const override;
@@ -38,7 +44,17 @@ class Serial final : public EventTargetWithInlineData,
void Trace(Visitor*) override;
private:
- explicit Serial(ExecutionContext&);
+ void EnsureServiceConnection();
+ void OnServiceConnectionError();
+ SerialPort* GetOrCreatePort(mojom::blink::SerialPortInfoPtr);
+ void OnGetPorts(ScriptPromiseResolver*,
+ Vector<mojom::blink::SerialPortInfoPtr>);
+ void OnRequestPort(ScriptPromiseResolver*, mojom::blink::SerialPortInfoPtr);
+
+ mojom::blink::SerialServicePtr service_;
+ HeapHashSet<Member<ScriptPromiseResolver>> get_ports_promises_;
+ HeapHashSet<Member<ScriptPromiseResolver>> request_port_promises_;
+ HeapHashMap<String, WeakMember<SerialPort>> port_cache_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.cc b/chromium/third_party/blink/renderer/modules/serial/serial_port.cc
index d8b125de03f..e46dccb1349 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.cc
@@ -7,12 +7,17 @@
namespace blink {
-ScriptValue SerialPort::in(ScriptState* script_state) {
- return ScriptValue::CreateNull(script_state);
+SerialPort::SerialPort(mojom::blink::SerialPortInfoPtr info)
+ : info_(std::move(info)) {}
+
+SerialPort::~SerialPort() = default;
+
+ReadableStream* SerialPort::in() {
+ return nullptr;
}
-ScriptValue SerialPort::out(ScriptState* script_state) {
- return ScriptValue::CreateNull(script_state);
+WritableStream* SerialPort::out() {
+ return nullptr;
}
ScriptPromise SerialPort::open(ScriptState* script_state,
@@ -26,4 +31,8 @@ ScriptPromise SerialPort::close(ScriptState* script_state) {
script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
}
+const base::UnguessableToken& SerialPort::Token() const {
+ return info_->token;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.h b/chromium/third_party/blink/renderer/modules/serial/serial_port.h
index 82211e20265..631f1d15920 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port.h
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.h
@@ -5,24 +5,39 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_
+#include "third_party/blink/public/mojom/serial/serial.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+namespace base {
+class UnguessableToken;
+}
+
namespace blink {
+class ReadableStream;
class ScriptState;
class SerialOptions;
+class WritableStream;
class SerialPort final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- ScriptValue in(ScriptState*);
- ScriptValue out(ScriptState*);
+ explicit SerialPort(mojom::blink::SerialPortInfoPtr info);
+ ~SerialPort() override;
+
+ ReadableStream* in();
+ WritableStream* out();
ScriptPromise open(ScriptState*, const SerialOptions* options);
ScriptPromise close(ScriptState*);
+
+ const base::UnguessableToken& Token() const;
+
+ private:
+ mojom::blink::SerialPortInfoPtr info_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.idl b/chromium/third_party/blink/renderer/modules/serial/serial_port.idl
index 794b9875eca..d525b937607 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port.idl
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.idl
@@ -8,11 +8,8 @@
Exposed(Window Serial,DedicatedWorker Serial),
SecureContext
] interface SerialPort {
- // TODO(https://crbug.com/888165): "any" is used here because the IDL
- // processor does not recognize ReadableStream or WritableStream when
- // implemented with V8 extras.
- [CallWith=ScriptState] readonly attribute any in;
- [CallWith=ScriptState] readonly attribute any out;
+ readonly attribute ReadableStream in;
+ readonly attribute WritableStream out;
[CallWith=ScriptState, MeasureAs=SerialPortOpen]
Promise<void> open(SerialOptions options);
diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
index a5a6b08694c..25e60bb7ccb 100644
--- a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
@@ -14,7 +14,7 @@ WorkerNavigatorSerial& WorkerNavigatorSerial::From(WorkerNavigator& navigator) {
WorkerNavigatorSerial* supplement =
Supplement<WorkerNavigator>::From<WorkerNavigatorSerial>(navigator);
if (!supplement) {
- supplement = new WorkerNavigatorSerial(navigator);
+ supplement = MakeGarbageCollected<WorkerNavigatorSerial>(navigator);
ProvideTo(navigator, supplement);
}
return *supplement;
diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
index 8ff078d3503..5305bfd6e63 100644
--- a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
+++ b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
@@ -27,11 +27,11 @@ class WorkerNavigatorSerial final
static Serial* serial(ScriptState*, WorkerNavigator&);
Serial* serial(ScriptState*);
+ explicit WorkerNavigatorSerial(WorkerNavigator&);
+
void Trace(Visitor*) override;
private:
- explicit WorkerNavigatorSerial(WorkerNavigator&);
-
Member<Serial> serial_;
};
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
index c95d157c353..27d5757101a 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
@@ -96,7 +96,7 @@ FetchEvent::FetchEvent(ScriptState* script_state,
: ExtendableEvent(type, initializer, wait_until_observer),
ContextClient(ExecutionContext::From(script_state)),
observer_(respond_with_observer),
- preload_response_property_(new PreloadResponseProperty(
+ preload_response_property_(MakeGarbageCollected<PreloadResponseProperty>(
ExecutionContext::From(script_state),
this,
PreloadResponseProperty::kPreloadResponse)) {
@@ -124,20 +124,21 @@ void FetchEvent::OnNavigationPreloadResponse(
DataPipeBytesConsumer* bytes_consumer = nullptr;
if (data_pipe.is_valid()) {
DataPipeBytesConsumer::CompletionNotifier* completion_notifier = nullptr;
- bytes_consumer =
- new DataPipeBytesConsumer(ExecutionContext::From(script_state),
- std::move(data_pipe), &completion_notifier);
+ bytes_consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
+ ExecutionContext::From(script_state), std::move(data_pipe),
+ &completion_notifier);
body_completion_notifier_ = completion_notifier;
}
// TODO(ricea): Verify that this response can't be aborted from JS.
FetchResponseData* response_data =
- bytes_consumer
- ? FetchResponseData::CreateWithBuffer(new BodyStreamBuffer(
- script_state, bytes_consumer,
- new AbortSignal(ExecutionContext::From(script_state))))
- : FetchResponseData::Create();
+ bytes_consumer ? FetchResponseData::CreateWithBuffer(
+ MakeGarbageCollected<BodyStreamBuffer>(
+ script_state, bytes_consumer,
+ MakeGarbageCollected<AbortSignal>(
+ ExecutionContext::From(script_state))))
+ : FetchResponseData::Create();
Vector<KURL> url_list(1);
- url_list[0] = preload_response_->Url();
+ url_list[0] = preload_response_->CurrentRequestUrl();
response_data->SetURLList(url_list);
response_data->SetStatus(preload_response_->HttpStatusCode());
response_data->SetStatusMessage(preload_response_->HttpStatusText());
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
index 3fd575b24a5..c21c0f7efbd 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -233,13 +233,12 @@ void FetchRespondWithObserver::OnResponseFulfilled(
const char* interface_name,
const char* property_name) {
DCHECK(GetExecutionContext());
- if (!V8Response::HasInstance(value.V8Value(),
- ToIsolate(GetExecutionContext()))) {
+ if (!V8Response::HasInstance(value.V8Value(), value.GetIsolate())) {
OnResponseRejected(ServiceWorkerResponseError::kNoV8Instance);
return;
}
- Response* response = V8Response::ToImplWithTypeCheck(
- ToIsolate(GetExecutionContext()), value.V8Value());
+ Response* response =
+ V8Response::ToImplWithTypeCheck(value.GetIsolate(), value.V8Value());
// "If one of the following conditions is true, return a network error:
// - |response|'s type is |error|.
// - |request|'s mode is |same-origin| and |response|'s type is |cors|.
@@ -335,7 +334,8 @@ void FetchRespondWithObserver::OnResponseFulfilled(
// Load the Response as a mojo::DataPipe. The resulting pipe consumer
// handle will be passed to the FetchLoaderClient on start.
- FetchLoaderClient* fetch_loader_client = new FetchLoaderClient();
+ FetchLoaderClient* fetch_loader_client =
+ MakeGarbageCollected<FetchLoaderClient>();
buffer->StartLoading(FetchDataLoader::CreateLoaderAsDataPipe(task_runner_),
fetch_loader_client, exception_state);
if (exception_state.HadException()) {
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
index 4b90c36e91d..d943705163e 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
@@ -551,7 +551,8 @@ ServiceWorkerContainer::ServiceWorkerContainer(Document* document)
ServiceWorkerContainer::ReadyProperty*
ServiceWorkerContainer::CreateReadyProperty() {
- return new ReadyProperty(GetExecutionContext(), this, ReadyProperty::kReady);
+ return MakeGarbageCollected<ReadyProperty>(GetExecutionContext(), this,
+ ReadyProperty::kReady);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
index 072c0a84efc..f2838ed468d 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
@@ -55,14 +55,15 @@ struct StubScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
StubScriptFunction& owner) {
- ScriptFunctionImpl* self = new ScriptFunctionImpl(script_state, owner);
+ ScriptFunctionImpl* self =
+ MakeGarbageCollected<ScriptFunctionImpl>(script_state, owner);
return self->BindToV8Function();
}
- private:
ScriptFunctionImpl(ScriptState* script_state, StubScriptFunction& owner)
: ScriptFunction(script_state), owner_(owner) {}
+ private:
ScriptValue Call(ScriptValue arg) override {
owner_.arg_ = arg;
owner_.call_count_++;
@@ -139,8 +140,10 @@ class ExpectTypeError : public ScriptValueTest {
error_object->Get(context, V8String(isolate, "message"))
.ToLocalChecked();
- EXPECT_EQ("TypeError", ToCoreString(name->ToString(isolate)));
- EXPECT_EQ(expected_message_, ToCoreString(message->ToString(isolate)));
+ EXPECT_EQ("TypeError",
+ ToCoreString(name->ToString(context).ToLocalChecked()));
+ EXPECT_EQ(expected_message_,
+ ToCoreString(message->ToString(context).ToLocalChecked()));
}
private:
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
index 75ce9b1fb02..99b66ac494f 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
@@ -5,9 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CONTENT_SETTINGS_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CONTENT_SETTINGS_PROXY_H_
+#include "third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/web/worker_content_settings_proxy.mojom-blink.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index b8e62374a1a..f905f026e30 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script_url.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -50,6 +51,7 @@
#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
#include "third_party/blink/renderer/core/workers/installed_scripts_manager.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
@@ -133,62 +135,6 @@ bool ServiceWorkerGlobalScope::ShouldInstallV8Extensions() const {
return Platform::Current()->AllowScriptExtensionForServiceWorker(Url());
}
-void ServiceWorkerGlobalScope::EvaluateClassicScript(
- const KURL& script_url,
- String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data) {
- DCHECK(IsContextThread());
-
- if (!evaluate_script_ready_) {
- evaluate_script_ =
- WTF::Bind(&ServiceWorkerGlobalScope::EvaluateClassicScript,
- WrapWeakPersistent(this), script_url, std::move(source_code),
- std::move(cached_meta_data));
- return;
- }
-
- // Receive the main script via script streaming if needed.
- InstalledScriptsManager* installed_scripts_manager =
- GetThread()->GetInstalledScriptsManager();
- if (installed_scripts_manager &&
- installed_scripts_manager->IsScriptInstalled(script_url)) {
- // GetScriptData blocks until the script is received from the browser.
- std::unique_ptr<InstalledScriptsManager::ScriptData> script_data =
- installed_scripts_manager->GetScriptData(script_url);
- if (!script_data) {
- ReportingProxy().DidFailToLoadInstalledClassicScript();
- // This will eventually initiate worker thread termination. See
- // ServiceWorkerGlobalScopeProxy::DidCloseWorkerGlobalScope() for details.
- close();
- return;
- }
-
- DCHECK(source_code.IsEmpty());
- DCHECK(!cached_meta_data);
- source_code = script_data->TakeSourceText();
- cached_meta_data = script_data->TakeMetaData();
-
- base::Optional<ContentSecurityPolicyResponseHeaders>
- content_security_policy_raw_headers =
- script_data->GetContentSecurityPolicyResponseHeaders();
- ApplyContentSecurityPolicyFromHeaders(
- content_security_policy_raw_headers.value());
-
- String referrer_policy = script_data->GetReferrerPolicy();
- if (!referrer_policy.IsNull())
- ParseAndSetReferrerPolicy(referrer_policy);
-
- std::unique_ptr<Vector<String>> origin_trial_tokens =
- script_data->CreateOriginTrialTokens();
- OriginTrialContext::AddTokens(this, origin_trial_tokens.get());
-
- ReportingProxy().DidLoadInstalledScript();
- }
-
- WorkerGlobalScope::EvaluateClassicScript(script_url, source_code,
- std::move(cached_meta_data));
-}
-
void ServiceWorkerGlobalScope::ImportModuleScript(
const KURL& module_url_record,
FetchClientSettingsObjectSnapshot* outside_settings_object,
@@ -204,9 +150,10 @@ void ServiceWorkerGlobalScope::ImportModuleScript(
fetch_type = ModuleScriptCustomFetchType::kInstalledServiceWorker;
}
- FetchModuleScript(module_url_record, outside_settings_object,
- mojom::RequestContextType::SERVICE_WORKER, credentials_mode,
- fetch_type, new ServiceWorkerModuleTreeClient(modulator));
+ FetchModuleScript(
+ module_url_record, outside_settings_object,
+ mojom::RequestContextType::SERVICE_WORKER, credentials_mode, fetch_type,
+ MakeGarbageCollected<ServiceWorkerModuleTreeClient>(modulator));
}
void ServiceWorkerGlobalScope::Dispose() {
@@ -348,6 +295,62 @@ bool ServiceWorkerGlobalScope::AddEventListenerInternal(
options);
}
+void ServiceWorkerGlobalScope::EvaluateClassicScriptInternal(
+ const KURL& script_url,
+ String source_code,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data) {
+ DCHECK(IsContextThread());
+
+ if (!evaluate_script_ready_) {
+ evaluate_script_ =
+ WTF::Bind(&ServiceWorkerGlobalScope::EvaluateClassicScriptInternal,
+ WrapWeakPersistent(this), script_url, std::move(source_code),
+ std::move(cached_meta_data));
+ return;
+ }
+
+ // Receive the main script via script streaming if needed.
+ InstalledScriptsManager* installed_scripts_manager =
+ GetThread()->GetInstalledScriptsManager();
+ if (installed_scripts_manager &&
+ installed_scripts_manager->IsScriptInstalled(script_url)) {
+ // GetScriptData blocks until the script is received from the browser.
+ std::unique_ptr<InstalledScriptsManager::ScriptData> script_data =
+ installed_scripts_manager->GetScriptData(script_url);
+ if (!script_data) {
+ ReportingProxy().DidFailToLoadInstalledClassicScript();
+ // This will eventually initiate worker thread termination. See
+ // ServiceWorkerGlobalScopeProxy::DidCloseWorkerGlobalScope() for details.
+ close();
+ return;
+ }
+
+ DCHECK(source_code.IsEmpty());
+ DCHECK(!cached_meta_data);
+ source_code = script_data->TakeSourceText();
+ cached_meta_data = script_data->TakeMetaData();
+
+ base::Optional<ContentSecurityPolicyResponseHeaders>
+ content_security_policy_raw_headers =
+ script_data->GetContentSecurityPolicyResponseHeaders();
+ ApplyContentSecurityPolicyFromHeaders(
+ content_security_policy_raw_headers.value());
+
+ String referrer_policy = script_data->GetReferrerPolicy();
+ if (!referrer_policy.IsNull())
+ ParseAndSetReferrerPolicy(referrer_policy);
+
+ std::unique_ptr<Vector<String>> origin_trial_tokens =
+ script_data->CreateOriginTrialTokens();
+ OriginTrialContext::AddTokens(this, origin_trial_tokens.get());
+
+ ReportingProxy().DidLoadInstalledScript();
+ }
+
+ WorkerGlobalScope::EvaluateClassicScriptInternal(script_url, source_code,
+ std::move(cached_meta_data));
+}
+
const AtomicString& ServiceWorkerGlobalScope::InterfaceName() const {
return event_target_names::kServiceWorkerGlobalScope;
}
@@ -383,12 +386,17 @@ void ServiceWorkerGlobalScope::Trace(blink::Visitor* visitor) {
WorkerGlobalScope::Trace(visitor);
}
-void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls,
- ExceptionState& exception_state) {
+void ServiceWorkerGlobalScope::importScripts(
+ const HeapVector<StringOrTrustedScriptURL>& urls,
+ ExceptionState& exception_state) {
InstalledScriptsManager* installed_scripts_manager =
GetThread()->GetInstalledScriptsManager();
- for (auto& url : urls) {
- KURL completed_url = CompleteURL(url);
+ for (const StringOrTrustedScriptURL& stringOrUrl : urls) {
+ String string_url = stringOrUrl.IsString()
+ ? stringOrUrl.GetAsString()
+ : stringOrUrl.GetAsTrustedScriptURL()->toString();
+
+ KURL completed_url = CompleteURL(string_url);
// Bust the MemoryCache to ensure script requests reach the browser-side
// and get added to and retrieved from the ServiceWorker's script cache.
// FIXME: Revisit in light of the solution to crbug/388375.
@@ -411,7 +419,7 @@ void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls,
SingleCachedMetadataHandler*
ServiceWorkerGlobalScope::CreateWorkerScriptCachedMetadataHandler(
const KURL& script_url,
- const Vector<char>* meta_data) {
+ const Vector<uint8_t>* meta_data) {
return ServiceWorkerScriptCachedMetadataHandler::Create(this, script_url,
meta_data);
}
@@ -430,6 +438,11 @@ void ServiceWorkerGlobalScope::ExceptionThrown(ErrorEvent* event) {
debugger->ExceptionThrown(GetThread(), event);
}
+mojom::RequestContextType
+ServiceWorkerGlobalScope::GetDestinationForMainScript() {
+ return mojom::RequestContextType::SERVICE_WORKER;
+}
+
void ServiceWorkerGlobalScope::CountCacheStorageInstalledScript(
uint64_t script_size,
uint64_t script_metadata_size) {
@@ -491,4 +504,14 @@ mojom::blink::CacheStoragePtrInfo ServiceWorkerGlobalScope::TakeCacheStorage() {
return std::move(cache_storage_info_);
}
+int ServiceWorkerGlobalScope::WillStartTask() {
+ return ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+ ->WillStartTask();
+}
+
+void ServiceWorkerGlobalScope::DidEndTask(int task_id) {
+ ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+ ->DidEndTask(task_id);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index 1abbcf9aa9a..a37587508ee 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -31,8 +31,8 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_GLOBAL_SCOPE_H_
#include <memory>
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -42,6 +42,7 @@
namespace blink {
+class ExceptionState;
class RespondWithObserver;
class RequestInit;
class ScriptPromise;
@@ -50,6 +51,7 @@ class ServiceWorker;
class ServiceWorkerClients;
class ServiceWorkerRegistration;
class ServiceWorkerThread;
+class StringOrTrustedScriptURL;
class WaitUntilObserver;
struct GlobalScopeCreationParams;
struct WebServiceWorkerObjectInfo;
@@ -78,10 +80,6 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope {
bool ShouldInstallV8Extensions() const final;
// Implements WorkerGlobalScope.
- void EvaluateClassicScript(
- const KURL& script_url,
- String source_code,
- std::unique_ptr<Vector<char>> cached_meta_data) override;
void ImportModuleScript(
const KURL& module_url_record,
FetchClientSettingsObjectSnapshot* outside_settings_object,
@@ -138,6 +136,10 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope {
mojom::blink::CacheStoragePtrInfo TakeCacheStorage();
+ // See the functions of the same name in WebServiceWorkerContextClient.
+ int WillStartTask();
+ void DidEndTask(int task_id);
+
DEFINE_ATTRIBUTE_EVENT_LISTENER(install, kInstall);
DEFINE_ATTRIBUTE_EVENT_LISTENER(activate, kActivate);
DEFINE_ATTRIBUTE_EVENT_LISTENER(fetch, kFetch);
@@ -152,12 +154,20 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope {
EventListener*,
const AddEventListenerOptionsResolved*) override;
+ // WorkerGlobalScope
+ void EvaluateClassicScriptInternal(
+ const KURL& script_url,
+ String source_code,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data) override;
+
private:
- void importScripts(const Vector<String>& urls, ExceptionState&) override;
+ void importScripts(const HeapVector<StringOrTrustedScriptURL>& urls,
+ ExceptionState&) override;
SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
const KURL& script_url,
- const Vector<char>* meta_data) override;
+ const Vector<uint8_t>* meta_data) override;
void ExceptionThrown(ErrorEvent*) override;
+ mojom::RequestContextType GetDestinationForMainScript() override;
// Counts the |script_size| and |cached_metadata_size| for UMA to measure the
// number of scripts and the total bytes of scripts.
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
index a90f55499f8..4389ab3703b 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
@@ -109,7 +109,7 @@ void ServiceWorkerGlobalScopeClient::OpenWindowForPaymentHandler(
}
void ServiceWorkerGlobalScopeClient::SetCachedMetadata(const KURL& url,
- const char* data,
+ const uint8_t* data,
size_t size) {
Vector<uint8_t> meta_data;
meta_data.Append(data, SafeCast<wtf_size_t>(size));
@@ -300,12 +300,21 @@ void ServiceWorkerGlobalScopeClient::WillDestroyWorkerContext() {
service_worker_host_.reset();
}
+int ServiceWorkerGlobalScopeClient::WillStartTask() {
+ return client_.WillStartTask();
+}
+
+void ServiceWorkerGlobalScopeClient::DidEndTask(int task_id) {
+ client_.DidEndTask(task_id);
+}
+
const char ServiceWorkerGlobalScopeClient::kSupplementName[] =
"ServiceWorkerGlobalScopeClient";
ServiceWorkerGlobalScopeClient* ServiceWorkerGlobalScopeClient::From(
ExecutionContext* context) {
- // TODO(horo): Replace CHECK() to DCHECK() when crbug.com/749930 is fixed.
+ // TODO(crbug.com/920854): Replace CHECK() with DCHECK() after crashes are
+ // gone.
CHECK(context);
WorkerClients* worker_clients = To<WorkerGlobalScope>(context)->Clients();
CHECK(worker_clients);
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
index 1959da5b993..6649b7c0f30 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
@@ -79,7 +79,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScopeClient final
GetClientsCallback);
void OpenWindowForClients(const KURL&, ScriptPromiseResolver*);
void OpenWindowForPaymentHandler(const KURL&, ScriptPromiseResolver*);
- void SetCachedMetadata(const KURL&, const char*, size_t);
+ void SetCachedMetadata(const KURL&, const uint8_t*, size_t);
void ClearCachedMetadata(const KURL&);
void PostMessageToClient(const String& client_uuid, BlinkTransferableMessage);
void SkipWaiting(SkipWaitingCallback);
@@ -139,6 +139,9 @@ class MODULES_EXPORT ServiceWorkerGlobalScopeClient final
void WillDestroyWorkerContext();
+ int WillStartTask();
+ void DidEndTask(int task_id);
+
static ServiceWorkerGlobalScopeClient* From(ExecutionContext*);
void Trace(blink::Visitor*) override;
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 8b71293e79f..679002e8a0a 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -93,21 +93,6 @@ namespace mojo {
namespace {
-blink::mojom::NotificationDirection ToMojomNotificationDirection(
- blink::WebNotificationData::Direction input) {
- switch (input) {
- case blink::WebNotificationData::kDirectionLeftToRight:
- return blink::mojom::NotificationDirection::LEFT_TO_RIGHT;
- case blink::WebNotificationData::kDirectionRightToLeft:
- return blink::mojom::NotificationDirection::RIGHT_TO_LEFT;
- case blink::WebNotificationData::kDirectionAuto:
- return blink::mojom::NotificationDirection::AUTO;
- }
-
- NOTREACHED();
- return blink::mojom::NotificationDirection::AUTO;
-}
-
blink::mojom::NotificationActionType ToMojomNotificationActionType(
blink::WebNotificationAction::Type input) {
switch (input) {
@@ -158,11 +143,10 @@ struct TypeConverter<blink::mojom::blink::NotificationDataPtr,
}
return blink::mojom::blink::NotificationData::New(
- input.title, ToMojomNotificationDirection(input.direction), input.lang,
- input.body, input.tag, input.image, input.icon, input.badge,
- std::move(vibration_pattern), input.timestamp, input.renotify,
- input.silent, input.require_interaction, std::move(data),
- std::move(actions));
+ input.title, input.direction, input.lang, input.body, input.tag,
+ input.image, input.icon, input.badge, std::move(vibration_pattern),
+ input.timestamp, input.renotify, input.silent,
+ input.require_interaction, std::move(data), std::move(actions));
}
};
@@ -220,7 +204,7 @@ void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchAbortEvent(
ScriptState::Scope scope(script_state);
BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
- init->setRegistration(new BackgroundFetchRegistration(
+ init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
WorkerGlobalScope()->registration() /* service_worker_registration */,
registration));
@@ -238,7 +222,7 @@ void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchClickEvent(
WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchClick, event_id);
BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
- init->setRegistration(new BackgroundFetchRegistration(
+ init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
WorkerGlobalScope()->registration() /* service_worker_registration */,
registration));
@@ -263,7 +247,7 @@ void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchFailEvent(
ScriptState::Scope scope(script_state);
BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
- init->setRegistration(new BackgroundFetchRegistration(
+ init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
WorkerGlobalScope()->registration() /* service_worker_registration */,
registration));
@@ -290,7 +274,7 @@ void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchSuccessEvent(
ScriptState::Scope scope(script_state);
BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
- init->setRegistration(new BackgroundFetchRegistration(
+ init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
WorkerGlobalScope()->registration() /* service_worker_registration */,
registration));
@@ -545,8 +529,8 @@ void ServiceWorkerGlobalScopeProxy::DispatchAbortPaymentEvent(int event_id) {
WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
WorkerGlobalScope(), WaitUntilObserver::kAbortPayment, event_id);
AbortPaymentRespondWithObserver* respond_with_observer =
- new AbortPaymentRespondWithObserver(WorkerGlobalScope(), event_id,
- wait_until_observer);
+ MakeGarbageCollected<AbortPaymentRespondWithObserver>(
+ WorkerGlobalScope(), event_id, wait_until_observer);
Event* event = AbortPaymentEvent::Create(
event_type_names::kAbortpayment, ExtendableEventInit::Create(),
@@ -563,8 +547,8 @@ void ServiceWorkerGlobalScopeProxy::DispatchCanMakePaymentEvent(
WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
WorkerGlobalScope(), WaitUntilObserver::kCanMakePayment, event_id);
CanMakePaymentRespondWithObserver* respond_with_observer =
- new CanMakePaymentRespondWithObserver(WorkerGlobalScope(), event_id,
- wait_until_observer);
+ MakeGarbageCollected<CanMakePaymentRespondWithObserver>(
+ WorkerGlobalScope(), event_id, wait_until_observer);
Event* event = CanMakePaymentEvent::Create(
event_type_names::kCanmakepayment,
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
index 6f42d50bb47..0725ddccc62 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
@@ -284,12 +284,12 @@ ServiceWorkerInstalledScriptsManager::GetScriptData(const KURL& script_url) {
for (const auto& chunk : raw_script_data->ScriptTextChunks())
source_text_builder.Append(decoder->Decode(chunk.data(), chunk.size()));
- std::unique_ptr<Vector<char>> meta_data;
+ std::unique_ptr<Vector<uint8_t>> meta_data;
if (raw_script_data->MetaDataChunks().size() > 0) {
size_t total_metadata_size = 0;
for (const auto& chunk : raw_script_data->MetaDataChunks())
total_metadata_size += chunk.size();
- meta_data = std::make_unique<Vector<char>>();
+ meta_data = std::make_unique<Vector<uint8_t>>();
meta_data->ReserveInitialCapacity(
SafeCast<wtf_size_t>(total_metadata_size));
for (const auto& chunk : raw_script_data->MetaDataChunks())
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
index bc867582b85..8d60af66824 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
@@ -16,7 +16,7 @@ ServiceWorkerModuleTreeClient::ServiceWorkerModuleTreeClient(
: modulator_(modulator) {}
// This client is used for both new and installed scripts. In the new scripts
-// case, this is a partial implementation of the custom "perfom the fetch" hook
+// case, this is a partial implementation of the custom "perform the fetch" hook
// in the spec: https://w3c.github.io/ServiceWorker/#update-algorithm For
// installed scripts, there is no corresponding specification text because there
// is no fetching process there. The service worker simply uses its associated
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
index dc278077fda..1f9aba8b0a0 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
@@ -131,7 +131,6 @@ ServiceWorkerRegistration::ServiceWorkerRegistration(
: ContextLifecycleObserver(execution_context),
registration_id_(info.registration_id),
scope_(std::move(info.scope)),
- type_(info.type),
binding_(this),
stopped_(false) {
DCHECK_NE(mojom::blink::kInvalidServiceWorkerRegistrationId,
@@ -143,7 +142,6 @@ void ServiceWorkerRegistration::Attach(
WebServiceWorkerRegistrationObjectInfo info) {
DCHECK_EQ(registration_id_, info.registration_id);
DCHECK_EQ(scope_.GetString(), WTF::String(info.scope.GetString()));
- DCHECK_EQ(type_, info.type);
// If |host_| is bound, it already points to the same object host as
// |info.host_ptr_info|, so there is no need to bind again.
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
index 9884fb02968..452a0449b98 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
@@ -111,7 +111,6 @@ class ServiceWorkerRegistration final
const int64_t registration_id_;
const KURL scope_;
- const mojom::ScriptType type_;
mojom::ServiceWorkerUpdateViaCache update_via_cache_;
// Both |host_| and |binding_| are associated with
// content.mojom.ServiceWorkerContainer interface for a Document, and
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc
index 5d06b1c74c6..bc9029d00a9 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc
@@ -14,7 +14,7 @@ ServiceWorkerScriptCachedMetadataHandler::
ServiceWorkerScriptCachedMetadataHandler(
WorkerGlobalScope* worker_global_scope,
const KURL& script_url,
- const Vector<char>* meta_data)
+ const Vector<uint8_t>* meta_data)
: worker_global_scope_(worker_global_scope), script_url_(script_url) {
if (meta_data)
cached_metadata_ = CachedMetadata::CreateFromSerializedData(
@@ -31,13 +31,13 @@ void ServiceWorkerScriptCachedMetadataHandler::Trace(blink::Visitor* visitor) {
void ServiceWorkerScriptCachedMetadataHandler::SetCachedMetadata(
uint32_t data_type_id,
- const char* data,
+ const uint8_t* data,
size_t size,
CacheType type) {
if (type != kSendToPlatform)
return;
cached_metadata_ = CachedMetadata::Create(data_type_id, data, size);
- const Vector<char>& serialized_data = cached_metadata_->SerializedData();
+ const Vector<uint8_t>& serialized_data = cached_metadata_->SerializedData();
ServiceWorkerGlobalScopeClient::From(worker_global_scope_)
->SetCachedMetadata(script_url_, serialized_data.data(),
serialized_data.size());
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h
index cd9325eed6e..2eb8432e129 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h
@@ -22,18 +22,18 @@ class ServiceWorkerScriptCachedMetadataHandler
static ServiceWorkerScriptCachedMetadataHandler* Create(
WorkerGlobalScope* worker_global_scope,
const KURL& script_url,
- const Vector<char>* meta_data) {
+ const Vector<uint8_t>* meta_data) {
return MakeGarbageCollected<ServiceWorkerScriptCachedMetadataHandler>(
worker_global_scope, script_url, meta_data);
}
ServiceWorkerScriptCachedMetadataHandler(WorkerGlobalScope*,
const KURL& script_url,
- const Vector<char>* meta_data);
+ const Vector<uint8_t>* meta_data);
~ServiceWorkerScriptCachedMetadataHandler() override;
void Trace(blink::Visitor*) override;
void SetCachedMetadata(uint32_t data_type_id,
- const char*,
+ const uint8_t*,
size_t,
CacheType) override;
void ClearCachedMetadata(CacheType) override;
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
index d07384160df..348e33f16d1 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
@@ -31,7 +31,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_THREAD_H_
#include <memory>
-#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc
index 07c3edf4f25..72637d13b2d 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/page/page_visibility_state.h"
+#include "third_party/blink/renderer/core/page/page_hidden_state.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_location.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_error.h"
@@ -55,19 +55,19 @@ ServiceWorkerWindowClient* ServiceWorkerWindowClient::Create(
ServiceWorkerWindowClient::ServiceWorkerWindowClient(
const WebServiceWorkerClientInfo& info)
: ServiceWorkerClient(info),
- page_visibility_state_(info.page_visibility_state),
+ page_hidden_(info.page_hidden),
is_focused_(info.is_focused) {}
ServiceWorkerWindowClient::ServiceWorkerWindowClient(
const mojom::blink::ServiceWorkerClientInfo& info)
: ServiceWorkerClient(info),
- page_visibility_state_(info.page_visibility_state),
+ page_hidden_(info.page_hidden),
is_focused_(info.is_focused) {}
ServiceWorkerWindowClient::~ServiceWorkerWindowClient() = default;
String ServiceWorkerWindowClient::visibilityState() const {
- return PageVisibilityStateString(page_visibility_state_);
+ return PageHiddenStateString(page_hidden_);
}
ScriptPromise ServiceWorkerWindowClient::focus(ScriptState* script_state) {
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h
index 59988a85e20..1e1f553b805 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h
@@ -39,7 +39,7 @@ class MODULES_EXPORT ServiceWorkerWindowClient final
void Trace(blink::Visitor*) override;
private:
- mojom::PageVisibilityState page_visibility_state_;
+ bool page_hidden_;
bool is_focused_;
};
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
index 20b174044d9..473f8b106fb 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -161,17 +161,11 @@ void WaitUntilObserver::WaitUntil(ScriptState* script_state,
}
IncrementPendingPromiseCount();
-
- // Call Then() separately for fulfilled and rejected cases. This ensures
- // throwing an exception in |on_promise_fulfilled| doesn't invoke
- // |on_promise_rejected|.
script_promise.Then(
ThenFunction::CreateFunction(script_state, this, ThenFunction::kFulfilled,
std::move(on_promise_fulfilled)),
- {});
- script_promise.Then({}, ThenFunction::CreateFunction(
- script_state, this, ThenFunction::kRejected,
- std::move(on_promise_rejected)));
+ ThenFunction::CreateFunction(script_state, this, ThenFunction::kRejected,
+ std::move(on_promise_rejected)));
}
bool WaitUntilObserver::IsEventActive(ScriptState* script_state) const {
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index 17abf021c46..413cec9ea16 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -30,6 +30,24 @@
namespace blink {
namespace {
+// Fake network provider for service worker execution contexts.
+class FakeServiceWorkerNetworkProvider
+ : public WebServiceWorkerNetworkProvider {
+ public:
+ FakeServiceWorkerNetworkProvider() = default;
+ ~FakeServiceWorkerNetworkProvider() override = default;
+
+ // Return a loader from the mock factory. In production code, this uses the
+ // factory provided at worker startup to load non-installed scripts via
+ // ServiceWorkerScriptLoaderFactory.
+ std::unique_ptr<WebURLLoader> CreateURLLoader(
+ const WebURLRequest& request,
+ std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>) override {
+ return Platform::Current()->GetURLLoaderMockFactory()->CreateURLLoader(
+ nullptr);
+ }
+};
+
class MockServiceWorkerContextClient : public WebServiceWorkerContextClient {
public:
MockServiceWorkerContextClient() = default;
@@ -49,13 +67,9 @@ class MockServiceWorkerContextClient : public WebServiceWorkerContextClient {
script_evaluated_event_.Signal();
}
- // Work-around for mocking a method that return unique_ptr.
- MOCK_METHOD0(CreateServiceWorkerNetworkProviderProxy,
- WebServiceWorkerNetworkProvider*());
std::unique_ptr<WebServiceWorkerNetworkProvider>
CreateServiceWorkerNetworkProvider() override {
- return std::unique_ptr<WebServiceWorkerNetworkProvider>(
- CreateServiceWorkerNetworkProviderProxy());
+ return std::make_unique<FakeServiceWorkerNetworkProvider>();
}
void WorkerContextDestroyed() override { termination_event_.Signal(); }
@@ -162,8 +176,6 @@ TEST_F(WebEmbeddedWorkerImplTest, TerminateWhileLoadingScript) {
testing::Mock::VerifyAndClearExpectations(mock_client_);
// Load the shadow page.
- EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy())
- .WillOnce(testing::Return(nullptr));
EXPECT_CALL(*mock_installed_scripts_manager_,
IsScriptInstalled(KURL(start_data_.script_url)))
.Times(testing::AtLeast(1))
@@ -186,8 +198,6 @@ TEST_F(WebEmbeddedWorkerImplTest, TerminateWhilePausedAfterDownload) {
testing::Mock::VerifyAndClearExpectations(mock_client_);
// Load the shadow page.
- EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy())
- .WillOnce(testing::Return(nullptr));
EXPECT_CALL(*mock_installed_scripts_manager_,
IsScriptInstalled(KURL(start_data_.script_url)))
.Times(testing::AtLeast(1))
@@ -224,8 +234,6 @@ TEST_F(WebEmbeddedWorkerImplTest, ScriptNotFound) {
testing::Mock::VerifyAndClearExpectations(mock_client_);
// Load the shadow page.
- EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy())
- .WillOnce(testing::Return(nullptr));
EXPECT_CALL(*mock_installed_scripts_manager_,
IsScriptInstalled(KURL(start_data_.script_url)))
.Times(testing::AtLeast(1))
@@ -255,8 +263,6 @@ TEST_F(WebEmbeddedWorkerImplTest, MAYBE_DontPauseAfterDownload) {
testing::Mock::VerifyAndClearExpectations(mock_client_);
// Load the shadow page.
- EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy())
- .WillOnce(testing::Return(nullptr));
EXPECT_CALL(*mock_installed_scripts_manager_,
IsScriptInstalled(KURL(start_data_.script_url)))
.Times(testing::AtLeast(1))
@@ -298,8 +304,6 @@ TEST_F(WebEmbeddedWorkerImplTest, MAYBE_PauseAfterDownload) {
testing::Mock::VerifyAndClearExpectations(mock_client_);
// Load the shadow page.
- EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy())
- .WillOnce(testing::Return(nullptr));
EXPECT_CALL(*mock_installed_scripts_manager_,
IsScriptInstalled(KURL(start_data_.script_url)))
.Times(testing::AtLeast(1))
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc
index 66a43d4ff58..2060b0a7933 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc
@@ -17,17 +17,19 @@
namespace blink {
BarcodeDetector* BarcodeDetector::Create(ExecutionContext* context) {
- return new BarcodeDetector(context);
+ return MakeGarbageCollected<BarcodeDetector>(context);
}
BarcodeDetector::BarcodeDetector(ExecutionContext* context) : ShapeDetector() {
shape_detection::mojom::blink::BarcodeDetectionProviderPtr provider;
- auto request = mojo::MakeRequest(&provider);
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner = context->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ auto request = mojo::MakeRequest(&provider, task_runner);
if (auto* interface_provider = context->GetInterfaceProvider()) {
interface_provider->GetInterface(std::move(request));
}
provider->CreateBarcodeDetection(
- mojo::MakeRequest(&barcode_service_),
+ mojo::MakeRequest(&barcode_service_, task_runner),
shape_detection::mojom::blink::BarcodeDetectorOptions::New());
barcode_service_.set_connection_error_handler(
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
index ba14b55016e..d5960790733 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
@@ -22,10 +22,11 @@ class MODULES_EXPORT BarcodeDetector final : public ShapeDetector {
public:
static BarcodeDetector* Create(ExecutionContext*);
+ explicit BarcodeDetector(ExecutionContext*);
+
void Trace(blink::Visitor*) override;
private:
- explicit BarcodeDetector(ExecutionContext*);
~BarcodeDetector() override = default;
ScriptPromise DoDetect(ScriptPromiseResolver*, SkBitmap) override;
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl
index 7df4129c703..e9ac10817c8 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl
@@ -16,5 +16,6 @@
// possible perspective distortions, this is not necessarily a rectangle.
[SameObject, SaveSameObject] readonly attribute FrozenArray<Point2D> cornerPoints;
- serializer = { attribute };
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl
index f367b6af6b9..d7f7985dd85 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl
@@ -13,5 +13,6 @@
[SameObject] readonly attribute DOMRectReadOnly boundingBox;
[SameObject, SaveSameObject] readonly attribute FrozenArray<Landmark> landmarks;
- serializer = { attribute };
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl
index 7afa4c66f2b..b549c86666d 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl
@@ -15,5 +15,6 @@
// possible perspective distortions, this is not necessarily a rectangle.
[SameObject] readonly attribute FrozenArray<Point2D> cornerPoints;
- serializer = { attribute };
+ // TODO(peria): toJSON is not in spec. https://crbug.com/736332
+ [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.cc b/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.cc
index fa7a0723460..83eef1ebc63 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.cc
@@ -35,11 +35,13 @@ FaceDetector::FaceDetector(ExecutionContext* context,
face_detector_options->fast_mode = options->fastMode();
shape_detection::mojom::blink::FaceDetectionProviderPtr provider;
- auto request = mojo::MakeRequest(&provider);
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner = context->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ auto request = mojo::MakeRequest(&provider, task_runner);
if (auto* interface_provider = context->GetInterfaceProvider()) {
interface_provider->GetInterface(std::move(request));
}
- provider->CreateFaceDetection(mojo::MakeRequest(&face_service_),
+ provider->CreateFaceDetection(mojo::MakeRequest(&face_service_, task_runner),
std::move(face_detector_options));
face_service_.set_connection_error_handler(WTF::Bind(
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc b/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
index d05cc4af604..7127f3ca2bc 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
@@ -49,8 +49,7 @@ ScriptPromise ShapeDetector::detect(
return promise;
}
- if (canvas_image_source->WouldTaintOrigin(
- ExecutionContext::From(script_state)->GetSecurityOrigin())) {
+ if (canvas_image_source->WouldTaintOrigin()) {
resolver->Reject(DOMException::Create(DOMExceptionCode::kSecurityError,
"Source would taint origin."));
return promise;
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.cc b/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.cc
index 3e0e6ae66dc..4e3fb73d1c4 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.cc
@@ -20,7 +20,9 @@ TextDetector* TextDetector::Create(ExecutionContext* context) {
}
TextDetector::TextDetector(ExecutionContext* context) : ShapeDetector() {
- auto request = mojo::MakeRequest(&text_service_);
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner = context->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ auto request = mojo::MakeRequest(&text_service_, task_runner);
if (auto* interface_provider = context->GetInterfaceProvider()) {
interface_provider->GetInterface(std::move(request));
}
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc
index 681ecf0c9a0..a8180d706ee 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc
@@ -53,9 +53,12 @@ void SpeechRecognition::start(ExceptionState& exception_state) {
final_results_.clear();
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetExecutionContext()->GetTaskRunner(blink::TaskType::kMiscPlatformAPI);
mojom::blink::SpeechRecognitionSessionClientPtrInfo session_client;
binding_.Bind(mojo::MakeRequest(&session_client),
- GetExecutionContext()->GetInterfaceInvalidator());
+ GetExecutionContext()->GetInterfaceInvalidator(), task_runner);
binding_.set_connection_error_handler(WTF::Bind(
&SpeechRecognition::OnConnectionError, WrapWeakPersistent(this)));
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc
index 54e4bbbf6e4..db8ff33135f 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc
@@ -10,7 +10,7 @@ namespace blink {
SpeechSynthesisErrorEvent* SpeechSynthesisErrorEvent::Create(
const AtomicString& type,
const SpeechSynthesisErrorEventInit* init) {
- return new SpeechSynthesisErrorEvent(type, init);
+ return MakeGarbageCollected<SpeechSynthesisErrorEvent>(type, init);
}
SpeechSynthesisErrorEvent::SpeechSynthesisErrorEvent(
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h
index 62f5a5f301d..75122f905e7 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h
@@ -20,11 +20,12 @@ class SpeechSynthesisErrorEvent : public SpeechSynthesisEvent {
const AtomicString& type,
const SpeechSynthesisErrorEventInit* init);
+ SpeechSynthesisErrorEvent(const AtomicString& type,
+ const SpeechSynthesisErrorEventInit* init);
+
const String error() const { return error_; }
private:
- SpeechSynthesisErrorEvent(const AtomicString& type,
- const SpeechSynthesisErrorEventInit* init);
const String error_;
};
diff --git a/chromium/third_party/blink/renderer/modules/storage/README.md b/chromium/third_party/blink/renderer/modules/storage/README.md
index 68e29ac989c..d5d8a33888f 100644
--- a/chromium/third_party/blink/renderer/modules/storage/README.md
+++ b/chromium/third_party/blink/renderer/modules/storage/README.md
@@ -10,7 +10,7 @@ This file describes only the post-onion-souped version of the code, where
`features::kOnionSoupDOMStorage` is turned on. This is not yet the default.
## Class Responsibilities
-### [`DOMWindowStorage`](dom_storage_window.h)
+### [`DOMWindowStorage`](dom_window_storage.h)
This implements the partial `Window` interface in
[window_storage.idl](window_storage.idl), and provides bindings for
`window.localStorage` and `window.sessionStorage` to the web platform. This
diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc b/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc
index 185d8f576a4..69a119e58cd 100644
--- a/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc
@@ -76,14 +76,14 @@ StorageNamespace* StorageController::CreateSessionStorageNamespace(
return it->value;
StorageNamespace* ns = nullptr;
if (base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)) {
- ns = new StorageNamespace(this, namespace_id);
+ ns = MakeGarbageCollected<StorageNamespace>(this, namespace_id);
} else {
auto namespace_str = StringUTF8Adaptor(namespace_id);
auto web_namespace = Platform::Current()->CreateSessionStorageNamespace(
namespace_str.AsStringPiece());
if (!web_namespace)
return nullptr;
- ns = new StorageNamespace(std::move(web_namespace));
+ ns = MakeGarbageCollected<StorageNamespace>(std::move(web_namespace));
}
namespaces_->insert(namespace_id, ns);
return ns;
@@ -154,9 +154,9 @@ void StorageController::EnsureLocalStorageNamespaceCreated() {
if (local_storage_namespace_)
return;
if (base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)) {
- local_storage_namespace_ = new StorageNamespace(this);
+ local_storage_namespace_ = MakeGarbageCollected<StorageNamespace>(this);
} else {
- local_storage_namespace_ = new StorageNamespace(
+ local_storage_namespace_ = MakeGarbageCollected<StorageNamespace>(
Platform::Current()->CreateLocalStorageNamespace());
}
}
diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_controller.h b/chromium/third_party/blink/renderer/modules/storage/storage_controller.h
index f706c84df2f..5d7140bc74f 100644
--- a/chromium/third_party/blink/renderer/modules/storage/storage_controller.h
+++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller.h
@@ -57,9 +57,9 @@ class MODULES_EXPORT StorageController {
mojom::blink::StoragePartitionServicePtr storage_partition_service,
size_t total_cache_limit);
- // Creates a new StorageNamespace for Session storage, and holds a weak
- // reference for accounting & clearing. If there is already a StorageNamespace
- // created for the given id, it is returned.
+ // Creates a MakeGarbageCollected<StorageNamespace> for Session storage, and
+ // holds a weak reference for accounting & clearing. If there is already a
+ // StorageNamespace created for the given id, it is returned.
StorageNamespace* CreateSessionStorageNamespace(const String& namespace_id);
// Returns the total size of all cached areas in namespaces this controller
diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_event.idl b/chromium/third_party/blink/renderer/modules/storage/storage_event.idl
index 6cf1d6855fd..e6cc1512d7f 100644
--- a/chromium/third_party/blink/renderer/modules/storage/storage_event.idl
+++ b/chromium/third_party/blink/renderer/modules/storage/storage_event.idl
@@ -26,6 +26,7 @@
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
[
+ Exposed=Window,
Constructor(DOMString type, optional StorageEventInit eventInitDict)
] interface StorageEvent : Event {
readonly attribute DOMString? key;
@@ -34,13 +35,12 @@
readonly attribute USVString url;
readonly attribute Storage? storageArea;
- // Non-standard API
- [Measure, LegacyInterfaceTypeChecking] void initStorageEvent([Default=Undefined] optional DOMString typeArg,
- [Default=Undefined] optional boolean canBubbleArg,
- [Default=Undefined] optional boolean cancelableArg,
- [Default=Undefined] optional DOMString keyArg,
- [Default=Undefined] optional DOMString? oldValueArg,
- [Default=Undefined] optional DOMString? newValueArg,
- [Default=Undefined] optional USVString urlArg,
- [Default=Undefined] optional Storage storageAreaArg);
+ [Measure] void initStorageEvent(DOMString type,
+ optional boolean bubbles = false,
+ optional boolean cancelable = false,
+ optional DOMString? key = null,
+ optional DOMString? oldValue = null,
+ optional DOMString? newValue = null,
+ optional USVString url = "",
+ optional Storage? storageArea = null);
};
diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc b/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc
index 31d1b306b08..24ed63a4ba7 100644
--- a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc
+++ b/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc
@@ -70,9 +70,10 @@ TEST_F(StorageNamespaceTest, BasicStorageAreas) {
StorageController controller(scheduler::GetSingleThreadTaskRunnerForTesting(),
std::move(storage_partition_service_ptr),
kTestCacheLimit);
- StorageNamespace* localStorage = new StorageNamespace(&controller);
- StorageNamespace* sessionStorage =
- new StorageNamespace(&controller, kSessionStorageNamespace);
+ StorageNamespace* localStorage =
+ MakeGarbageCollected<StorageNamespace>(&controller);
+ StorageNamespace* sessionStorage = MakeGarbageCollected<StorageNamespace>(
+ &controller, kSessionStorageNamespace);
EXPECT_FALSE(localStorage->IsSessionStorage());
EXPECT_TRUE(sessionStorage->IsSessionStorage());
diff --git a/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc b/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc
index 7438528c735..73e7a46a0ed 100644
--- a/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc
+++ b/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc
@@ -30,7 +30,7 @@ void NotifyTimezoneChangeToV8(v8::Isolate* isolate) {
void NotifyTimezoneChangeOnWorkerThread(WorkerThread* worker_thread) {
DCHECK(worker_thread->IsCurrentThread());
- NotifyTimezoneChangeToV8(ToIsolate(worker_thread->GlobalScope()));
+ NotifyTimezoneChangeToV8(worker_thread->GlobalScope()->GetIsolate());
}
} // namespace
@@ -65,7 +65,8 @@ void TimeZoneMonitorClient::OnTimeZoneChange(const String& time_zone_info) {
}
NotifyTimezoneChangeToV8(V8PerIsolateData::MainThreadIsolate());
- WorkerThread::CallOnAllWorkerThreads(&NotifyTimezoneChangeOnWorkerThread);
+ WorkerThread::CallOnAllWorkerThreads(&NotifyTimezoneChangeOnWorkerThread,
+ TaskType::kInternalDefault);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/vr/navigator_vr.idl b/chromium/third_party/blink/renderer/modules/vr/navigator_vr.idl
index 7e7fc582542..86ae2c92cb0 100644
--- a/chromium/third_party/blink/renderer/modules/vr/navigator_vr.idl
+++ b/chromium/third_party/blink/renderer/modules/vr/navigator_vr.idl
@@ -10,5 +10,5 @@
[SecureContext, OriginTrialEnabled=WebXR, MeasureAs=NavigatorXR] readonly attribute XR xr;
// Legacy API
- [OriginTrialEnabled=WebVR, CallWith=ScriptState] Promise getVRDisplays();
+ [OriginTrialEnabled=WebVR, CallWith=ScriptState] Promise<sequence<VRDisplay>> getVRDisplays();
};
diff --git a/chromium/third_party/blink/renderer/modules/vr/vr_controller.cc b/chromium/third_party/blink/renderer/modules/vr/vr_controller.cc
index 27cf491ed64..45bcb147b29 100644
--- a/chromium/third_party/blink/renderer/modules/vr/vr_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/vr/vr_controller.cc
@@ -21,13 +21,16 @@ VRController::VRController(NavigatorVR* navigator_vr)
navigator_vr_(navigator_vr),
display_synced_(false),
binding_(this) {
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ navigator_vr->GetDocument()->GetTaskRunner(TaskType::kMiscPlatformAPI);
navigator_vr->GetDocument()->GetFrame()->GetInterfaceProvider().GetInterface(
- mojo::MakeRequest(&service_));
+ mojo::MakeRequest(&service_, task_runner));
service_.set_connection_error_handler(
WTF::Bind(&VRController::Dispose, WrapWeakPersistent(this)));
device::mojom::blink::VRServiceClientPtr client;
- binding_.Bind(mojo::MakeRequest(&client));
+ binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
service_->SetClient(std::move(client));
service_->RequestDevice(
diff --git a/chromium/third_party/blink/renderer/modules/vr/vr_display.cc b/chromium/third_party/blink/renderer/modules/vr/vr_display.cc
index 850e5feb206..c9e0b796223 100644
--- a/chromium/third_party/blink/renderer/modules/vr/vr_display.cc
+++ b/chromium/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
#include "third_party/blink/renderer/core/dom/scripted_animation_controller.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/frame.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -38,7 +39,6 @@
#include "third_party/blink/renderer/platform/wtf/time.h"
#include <array>
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
namespace blink {
@@ -151,9 +151,7 @@ VRDisplay::VRDisplay(NavigatorVR* navigator_vr,
VRDisplay::~VRDisplay() = default;
-void VRDisplay::Pause() {}
-
-void VRDisplay::Unpause() {
+void VRDisplay::ContextUnpaused() {
RequestVSync();
}
@@ -295,8 +293,8 @@ void VRDisplay::RequestVSync() {
non_immersive_provider_->GetFrameData(WTF::Bind(
&VRDisplay::OnNonImmersiveFrameData, WrapWeakPersistent(this)));
pending_non_immersive_vsync_ = true;
- pending_non_immersive_vsync_id_ =
- doc->RequestAnimationFrame(new VRDisplayFrameRequestCallback(this));
+ pending_non_immersive_vsync_id_ = doc->RequestAnimationFrame(
+ MakeGarbageCollected<VRDisplayFrameRequestCallback>(this));
DVLOG(2) << __FUNCTION__ << " done: pending_non_immersive_vsync_="
<< pending_non_immersive_vsync_;
}
@@ -750,7 +748,7 @@ scoped_refptr<Image> VRDisplay::GetFrameImage(
// path.
if (!image_ref.get() || !image_ref->IsTextureBacked()) {
TRACE_EVENT0("gpu", "VRDisplay::GetImage_SlowFallback");
- // We get a non-texture-backed image when running layout tests
+ // We get a non-texture-backed image when running web tests
// on desktop builds. Add a slow fallback so that these continue
// working.
image_ref = rendering_context_->GetImage(kPreferAcceleration);
@@ -856,7 +854,11 @@ Document* VRDisplay::GetDocument() {
device::mojom::blink::VRDisplayClientPtr VRDisplay::GetDisplayClient() {
display_client_binding_.Close();
device::mojom::blink::VRDisplayClientPtr client;
- display_client_binding_.Bind(mojo::MakeRequest(&client));
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ display_client_binding_.Bind(mojo::MakeRequest(&client, task_runner),
+ task_runner);
return client;
}
diff --git a/chromium/third_party/blink/renderer/modules/vr/vr_display.h b/chromium/third_party/blink/renderer/modules/vr/vr_display.h
index 03a7faa80ea..998343fcc04 100644
--- a/chromium/third_party/blink/renderer/modules/vr/vr_display.h
+++ b/chromium/third_party/blink/renderer/modules/vr/vr_display.h
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_frame_request_callback.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/modules/vr/vr_display_capabilities.h"
#include "third_party/blink/renderer/modules/vr/vr_layer_init.h"
#include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h"
@@ -131,8 +131,7 @@ class VRDisplay final : public EventTargetWithInlineData,
bool HasPendingActivity() const final;
// PausableObject:
- void Pause() override;
- void Unpause() override;
+ void ContextUnpaused() override;
void OnChanged(device::mojom::blink::VRDisplayInfoPtr, bool is_immersive);
void OnExitPresent(bool is_immersive);
diff --git a/chromium/third_party/blink/renderer/modules/vr/vr_display.idl b/chromium/third_party/blink/renderer/modules/vr/vr_display.idl
index 026d6ce8317..5f8be46c46c 100644
--- a/chromium/third_party/blink/renderer/modules/vr/vr_display.idl
+++ b/chromium/third_party/blink/renderer/modules/vr/vr_display.idl
@@ -38,10 +38,10 @@ enum VREye {
// Begin presenting to the VRDisplay. Must be called in response to a user
// gesture. Repeat calls while already presenting will update the layer
// being displayed.
- [CallWith=ScriptState] Promise requestPresent(sequence<VRLayerInit> layers);
+ [CallWith=ScriptState] Promise<void> requestPresent(sequence<VRLayerInit> layers);
// Stops presenting to the VRDisplay.
- [CallWith=ScriptState] Promise exitPresent();
+ [CallWith=ScriptState] Promise<void> exitPresent();
// Get the sources currently being presented.
sequence<VRLayerInit> getLayers();
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/DEPS b/chromium/third_party/blink/renderer/modules/wake_lock/DEPS
index 5f009fc2d9a..23424fb8031 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/DEPS
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/DEPS
@@ -3,6 +3,5 @@ include_rules = [
"+services/device/public/mojom",
"+services/device/public/interfaces/constants.mojom-blink.h",
"+services/device/public/mojom/wake_lock.mojom-blink.h",
- "+services/device/public/mojom/wake_lock_provider.mojom-blink.h",
"+third_party/blink/renderer/modules/event_target_modules.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc
index 8856158e88d..1f5d29d013c 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h"
+#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -27,6 +28,17 @@ ScriptPromise NavigatorWakeLock::getWakeLock(ScriptState* script_state,
ScriptPromise NavigatorWakeLock::getWakeLock(ScriptState* script_state,
String lock_type) {
+ if (!ExecutionContext::From(script_state)
+ ->GetSecurityContext()
+ .IsFeatureEnabled(mojom::FeaturePolicyFeature::kWakeLock,
+ ReportOptions::kReportOnFailure)) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(
+ DOMExceptionCode::kSecurityError,
+ "Access to WakeLock features is disallowed by feature policy"));
+ }
+
if (lock_type == "screen") {
if (!wake_lock_screen_)
wake_lock_screen_ = WakeLock::CreateScreenWakeLock(script_state);
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.idl b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.idl
index 609ac6e849c..3e14fe2d287 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.idl
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.idl
@@ -9,5 +9,5 @@
ImplementedAs=NavigatorWakeLock,
RuntimeEnabled=WakeLockNavigator
] partial interface Navigator {
- [CallWith=ScriptState] Promise getWakeLock(WakeLockType type);
-}; \ No newline at end of file
+ [CallWith=ScriptState] Promise<WakeLock> getWakeLock(WakeLockType type);
+};
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock.cc
index 90d19e5a29b..1f9fe4fca0f 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock.cc
@@ -8,7 +8,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/screen.h"
-#include "third_party/blink/renderer/core/page/page_visibility_state.h"
+#include "third_party/blink/renderer/core/page/page_hidden_state.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock_test.cc b/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock_test.cc
index 6e776116afe..d7db637aa94 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock_test.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/screen_wake_lock_test.cc
@@ -8,7 +8,6 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
@@ -112,16 +111,16 @@ class ScreenWakeLockTest : public testing::Test {
void Show() {
DCHECK(web_view_helper_.GetWebView());
- web_view_helper_.GetWebView()->SetVisibilityState(
- mojom::blink::PageVisibilityState::kVisible, false);
+ web_view_helper_.GetWebView()->SetIsHidden(
+ /*is_hidden=*/false, /*initial_state=*/false);
// Let the notification sink through the mojo pipes.
test::RunPendingTasks();
}
void Hide() {
DCHECK(web_view_helper_.GetWebView());
- web_view_helper_.GetWebView()->SetVisibilityState(
- mojom::blink::PageVisibilityState::kHidden, false);
+ web_view_helper_.GetWebView()->SetIsHidden(
+ /*is_hidden=*/true, /*initial_state=*/false);
// Let the notification sink through the mojo pipes.
test::RunPendingTasks();
}
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
index 1b281c9d0c3..a7d14d0bbe4 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
@@ -5,10 +5,10 @@
#include "third_party/blink/renderer/modules/wake_lock/wake_lock.h"
#include "services/device/public/mojom/constants.mojom-blink.h"
-#include "services/device/public/mojom/wake_lock_provider.mojom-blink.h"
+#include "services/device/public/mojom/wake_lock.mojom-blink.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
@@ -38,7 +38,7 @@ WakeLock::WakeLock(ScriptState* script_state, LockType type)
ScriptPromise WakeLock::GetPromise(ScriptState* script_state) {
if (!wake_lock_property_) {
- wake_lock_property_ = new WakeLockProperty(
+ wake_lock_property_ = MakeGarbageCollected<WakeLockProperty>(
ExecutionContext::From(script_state), this, WakeLockProperty::kReady);
wake_lock_property_->Resolve(this);
}
@@ -94,17 +94,23 @@ void WakeLock::BindToServiceIfNeeded() {
break;
}
- device::mojom::blink::WakeLockProviderPtr provider;
- Platform::Current()->GetConnector()->BindInterface(
- device::mojom::blink::kServiceName, mojo::MakeRequest(&provider));
- provider->GetWakeLockWithoutContext(
- type, device::mojom::blink::WakeLockReason::kOther, "Blink Wake Lock",
- mojo::MakeRequest(&wake_lock_service_));
+ if (!GetDocument() || !GetDocument()->GetFrame())
+ return;
+ blink::mojom::blink::WakeLockServicePtr service;
+ GetDocument()->GetFrame()->GetInterfaceProvider().GetInterface(
+ mojo::MakeRequest(&service));
+ service->GetWakeLock(type, device::mojom::blink::WakeLockReason::kOther,
+ "Blink Wake Lock",
+ mojo::MakeRequest(&wake_lock_service_));
wake_lock_service_.set_connection_error_handler(
WTF::Bind(&WakeLock::OnConnectionError, WrapWeakPersistent(this)));
}
+Document* WakeLock::GetDocument() {
+ return To<Document>(GetExecutionContext());
+}
+
WakeLockRequest* WakeLock::createRequest() {
if (!active_ && request_counter_ == 0)
ChangeActiveStatus(true);
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h
index 0355ec62969..709c2860917 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h
@@ -16,6 +16,7 @@
namespace blink {
+class Document;
class WakeLockRequest;
class WakeLock final : public EventTargetWithInlineData,
@@ -73,6 +74,9 @@ class WakeLock final : public EventTargetWithInlineData,
// Binds to the Wake Lock mojo service
void BindToServiceIfNeeded();
+ // Returns the document associated with the object. nullptr if there is none.
+ Document* GetDocument();
+
device::mojom::blink::WakeLockPtr wake_lock_service_;
int request_counter_ = 0;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn b/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
index 52ec0bf8837..7ca12c1de88 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
@@ -30,6 +30,8 @@ blink_modules_sources("webaudio") {
"audio_node_input.h",
"audio_node_output.cc",
"audio_node_output.h",
+ "audio_node_wiring.cc",
+ "audio_node_wiring.h",
"audio_param.cc",
"audio_param.h",
"audio_param_map.cc",
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc
index a6887cfd30d..c6ee14df1cd 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc
@@ -201,7 +201,7 @@ AnalyserNode* AnalyserNode::Create(BaseAudioContext& context,
return nullptr;
}
- return new AnalyserNode(context);
+ return MakeGarbageCollected<AnalyserNode>(context);
}
AnalyserNode* AnalyserNode::Create(BaseAudioContext* context,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.h b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.h
index 235bfd7c0cb..21a366ebab1 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.h
@@ -106,6 +106,8 @@ class AnalyserNode final : public AudioBasicInspectorNode {
const AnalyserOptions*,
ExceptionState&);
+ AnalyserNode(BaseAudioContext&);
+
unsigned fftSize() const;
void setFftSize(unsigned size, ExceptionState&);
unsigned frequencyBinCount() const;
@@ -121,7 +123,6 @@ class AnalyserNode final : public AudioBasicInspectorNode {
void getByteTimeDomainData(NotShared<DOMUint8Array>);
private:
- AnalyserNode(BaseAudioContext&);
AnalyserHandler& GetAnalyserHandler() const;
void SetMinMaxDecibels(double min, double max, ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.idl b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.idl
index 7593662430a..d6578a7dd22 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.idl
+++ b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.idl
@@ -42,10 +42,10 @@ interface AnalyserNode : AudioNode {
// Copies the current frequency data into the passed array.
// If the array has fewer elements than the frequencyBinCount, the excess elements will be dropped.
- void getFloatFrequencyData(Float32Array array);
- void getByteFrequencyData(Uint8Array array);
+ [HighEntropy, Measure] void getFloatFrequencyData(Float32Array array);
+ [HighEntropy, Measure] void getByteFrequencyData(Uint8Array array);
// Real-time waveform data
- void getFloatTimeDomainData(Float32Array array);
- void getByteTimeDomainData(Uint8Array array);
+ [HighEntropy, Measure] void getFloatTimeDomainData(Float32Array array);
+ [HighEntropy, Measure] void getByteTimeDomainData(Uint8Array array);
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc
index 37818f29ab1..ae02dde85c7 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc
@@ -47,8 +47,8 @@ AudioBuffer* AudioBuffer::Create(unsigned number_of_channels,
!number_of_channels || !number_of_frames)
return nullptr;
- AudioBuffer* buffer =
- new AudioBuffer(number_of_channels, number_of_frames, sample_rate);
+ AudioBuffer* buffer = MakeGarbageCollected<AudioBuffer>(
+ number_of_channels, number_of_frames, sample_rate);
if (!buffer->CreatedSuccessfully(number_of_channels))
return nullptr;
@@ -119,8 +119,8 @@ AudioBuffer* AudioBuffer::CreateUninitialized(unsigned number_of_channels,
!number_of_channels || !number_of_frames)
return nullptr;
- AudioBuffer* buffer = new AudioBuffer(number_of_channels, number_of_frames,
- sample_rate, kDontInitialize);
+ AudioBuffer* buffer = MakeGarbageCollected<AudioBuffer>(
+ number_of_channels, number_of_frames, sample_rate, kDontInitialize);
if (!buffer->CreatedSuccessfully(number_of_channels))
return nullptr;
@@ -134,7 +134,7 @@ AudioBuffer* AudioBuffer::CreateFromAudioFileData(const void* data,
scoped_refptr<AudioBus> bus =
CreateBusFromInMemoryAudioFile(data, data_size, mix_to_mono, sample_rate);
if (bus) {
- AudioBuffer* buffer = new AudioBuffer(bus.get());
+ AudioBuffer* buffer = MakeGarbageCollected<AudioBuffer>(bus.get());
if (buffer->CreatedSuccessfully(bus->NumberOfChannels()))
return buffer;
}
@@ -145,7 +145,7 @@ AudioBuffer* AudioBuffer::CreateFromAudioFileData(const void* data,
AudioBuffer* AudioBuffer::CreateFromAudioBus(AudioBus* bus) {
if (!bus)
return nullptr;
- AudioBuffer* buffer = new AudioBuffer(bus);
+ AudioBuffer* buffer = MakeGarbageCollected<AudioBuffer>(bus);
if (buffer->CreatedSuccessfully(bus->NumberOfChannels()))
return buffer;
return nullptr;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.h
index 9867f77b9ac..ae3389cbc3c 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.h
@@ -72,6 +72,16 @@ class MODULES_EXPORT AudioBuffer final : public ScriptWrappable {
static AudioBuffer* CreateFromAudioBus(AudioBus*);
+ explicit AudioBuffer(AudioBus*);
+ // How to initialize the contents of an AudioBuffer. Default is to
+ // zero-initialize (|kZeroInitialize|). Otherwise, leave the array
+ // uninitialized (|kDontInitialize|).
+ enum InitializationPolicy { kZeroInitialize, kDontInitialize };
+ AudioBuffer(unsigned number_of_channels,
+ uint32_t number_of_frames,
+ float sample_rate,
+ InitializationPolicy allocation_policy = kZeroInitialize);
+
// Format
uint32_t length() const { return length_; }
double duration() const {
@@ -107,21 +117,10 @@ class MODULES_EXPORT AudioBuffer final : public ScriptWrappable {
}
private:
- // How to initialize the contents of an AudioBuffer. Default is to
- // zero-initialize (|kZeroInitialize|). Otherwise, leave the array
- // uninitialized (|kDontInitialize|).
- enum InitializationPolicy { kZeroInitialize, kDontInitialize };
-
- explicit AudioBuffer(AudioBus*);
-
static DOMFloat32Array* CreateFloat32ArrayOrNull(
uint32_t length,
InitializationPolicy allocation_policy = kZeroInitialize);
- AudioBuffer(unsigned number_of_channels,
- uint32_t number_of_frames,
- float sample_rate,
- InitializationPolicy allocation_policy = kZeroInitialize);
bool CreatedSuccessfully(unsigned desired_number_of_channels) const;
float sample_rate_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.idl b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.idl
index 08e683ee254..650c785fb28 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.idl
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.idl
@@ -38,7 +38,7 @@
// Channel access
readonly attribute unsigned long numberOfChannels;
- [RaisesException] Float32Array getChannelData(unsigned long channelIndex);
- [RaisesException] void copyFromChannel(Float32Array destination, long channelNumber, optional unsigned long startInChannel = 0);
+ [HighEntropy, Measure, RaisesException] Float32Array getChannelData(unsigned long channelIndex);
+ [HighEntropy, Measure, RaisesException] void copyFromChannel(Float32Array destination, long channelNumber, optional unsigned long startInChannel = 0);
[RaisesException] void copyToChannel(Float32Array source, long channelNumber, optional unsigned long startInChannel = 0);
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc
index 5f1162e3425..0f6eea331eb 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc
@@ -25,6 +25,7 @@
#include <algorithm>
+#include "base/numerics/safe_conversions.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h"
#include "third_party/blink/renderer/modules/webaudio/audio_buffer_source_options.h"
@@ -227,9 +228,10 @@ bool AudioBufferSourceHandler::RenderFromBuffer(
// Avoid converting from time to sample-frames twice by computing
// the grain end time first before computing the sample frame.
unsigned end_frame =
- is_grain_ ? audio_utilities::TimeToSampleFrame(
- grain_offset_ + grain_duration_, buffer_sample_rate)
- : buffer_length;
+ is_grain_
+ ? base::saturated_cast<uint32_t>(audio_utilities::TimeToSampleFrame(
+ grain_offset_ + grain_duration_, buffer_sample_rate))
+ : buffer_length;
// Do some sanity checking.
if (end_frame > buffer_length)
@@ -682,7 +684,7 @@ AudioBufferSourceNode* AudioBufferSourceNode::Create(
return nullptr;
}
- return new AudioBufferSourceNode(context);
+ return MakeGarbageCollected<AudioBufferSourceNode>(context);
}
AudioBufferSourceNode* AudioBufferSourceNode::Create(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h
index 27e28265e96..19bd49cb454 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_BUFFER_SOURCE_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_BUFFER_SOURCE_NODE_H_
+#include <atomic>
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
@@ -133,10 +134,12 @@ class AudioBufferSourceHandler final : public AudioScheduledSourceHandler {
scoped_refptr<AudioParamHandler> playback_rate_;
scoped_refptr<AudioParamHandler> detune_;
- bool DidSetLooping() const { return AcquireLoad(&did_set_looping_); }
+ bool DidSetLooping() const {
+ return did_set_looping_.load(std::memory_order_acquire);
+ }
void SetDidSetLooping(bool loop) {
- bool new_looping = DidSetLooping() || loop;
- ReleaseStore(&did_set_looping_, new_looping);
+ if (loop)
+ did_set_looping_.store(true, std::memory_order_release);
}
// If m_isLooping is false, then this node will be done playing and become
@@ -146,7 +149,7 @@ class AudioBufferSourceHandler final : public AudioScheduledSourceHandler {
bool is_looping_;
// True if the source .loop attribute was ever set.
- int did_set_looping_;
+ std::atomic_bool did_set_looping_;
double loop_start_;
double loop_end_;
@@ -193,6 +196,7 @@ class AudioBufferSourceNode final : public AudioScheduledSourceNode {
static AudioBufferSourceNode* Create(BaseAudioContext*,
AudioBufferSourceOptions*,
ExceptionState&);
+ AudioBufferSourceNode(BaseAudioContext&);
void Trace(blink::Visitor*) override;
AudioBufferSourceHandler& GetAudioBufferSourceHandler() const;
@@ -216,8 +220,6 @@ class AudioBufferSourceNode final : public AudioScheduledSourceNode {
ExceptionState&);
private:
- AudioBufferSourceNode(BaseAudioContext&);
-
Member<AudioParam> playback_rate_;
Member<AudioParam> detune_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 51c52a2d08c..5cf8a84008d 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -49,7 +49,6 @@ AudioContext* AudioContext::Create(Document& document,
const AudioContextOptions* context_options,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
- LOG(ERROR) << __func__;
UseCounter::CountCrossOriginIframe(
document, WebFeature::kAudioContextCrossOriginIframe);
@@ -65,7 +64,8 @@ AudioContext* AudioContext::Create(Document& document,
WebAudioLatencyHint(context_options->latencyHint().GetAsDouble());
}
- AudioContext* audio_context = new AudioContext(document, latency_hint);
+ AudioContext* audio_context =
+ MakeGarbageCollected<AudioContext>(document, latency_hint);
audio_context->PauseIfNeeded();
if (!audio_utilities::IsValidAudioBufferSampleRate(
@@ -90,7 +90,6 @@ AudioContext* AudioContext::Create(Document& document,
audio_context->MaybeAllowAutoplayWithUnlockType(
AutoplayUnlockType::kContextConstructor);
if (audio_context->IsAllowedToStart()) {
- LOG(ERROR) << "starting";
audio_context->StartRendering();
audio_context->SetContextState(kRunning);
}
@@ -108,15 +107,6 @@ AudioContext* AudioContext::Create(Document& document,
audio_context->destination()->maxChannelCount());
sample_rate_histogram.Sample(audio_context->sampleRate());
- // Warn users about new autoplay policy when it does not apply to them.
- if (RuntimeEnabledFeatures::AutoplayIgnoresWebAudioEnabled()) {
- document.AddConsoleMessage(ConsoleMessage::Create(
- kOtherMessageSource, kWarningMessageLevel,
- "The Web Audio autoplay policy will be re-enabled in Chrome 71 ("
- "December 2018). Please check that your website is compatible with it. "
- "https://goo.gl/7K7WLu"));
- }
-
probe::didCreateAudioContext(&document);
return audio_context;
@@ -127,15 +117,12 @@ AudioContext::AudioContext(Document& document,
: BaseAudioContext(&document, kRealtimeContext),
context_id_(g_context_id++) {
destination_node_ = DefaultAudioDestinationNode::Create(this, latency_hint);
- LOG(ERROR) << __func__;
switch (GetAutoplayPolicy()) {
case AutoplayPolicy::Type::kNoUserGestureRequired:
- LOG(ERROR) << "no user gesture";
break;
case AutoplayPolicy::Type::kUserGestureRequired:
case AutoplayPolicy::Type::kUserGestureRequiredForCrossOrigin:
- LOG(ERROR) << "user gesture";
if (document.GetFrame() &&
document.GetFrame()->IsCrossOriginSubframe()) {
autoplay_status_ = AutoplayStatus::kAutoplayStatusFailed;
@@ -143,7 +130,6 @@ AudioContext::AudioContext(Document& document,
}
break;
case AutoplayPolicy::Type::kDocumentUserActivationRequired:
- LOG(ERROR) << "document user activation";
autoplay_status_ = AutoplayStatus::kAutoplayStatusFailed;
user_gesture_required_ = true;
break;
@@ -203,7 +189,6 @@ ScriptPromise AudioContext::suspendContext(ScriptState* script_state) {
ScriptPromise AudioContext::resumeContext(ScriptState* script_state) {
DCHECK(IsMainThread());
- LOG(ERROR) << __func__;
if (IsContextClosed()) {
return ScriptPromise::RejectWithDOMException(
@@ -369,14 +354,18 @@ MediaStreamAudioDestinationNode* AudioContext::createMediaStreamDestination(
}
void AudioContext::NotifySourceNodeStart() {
+ DCHECK(IsMainThread());
+
source_node_started_ = true;
if (!user_gesture_required_)
return;
MaybeAllowAutoplayWithUnlockType(AutoplayUnlockType::kSourceNodeStart);
- if (IsAllowedToStart())
+ if (IsAllowedToStart()) {
StartRendering();
+ SetContextState(kRunning);
+ }
}
AutoplayPolicy::Type AudioContext::GetAutoplayPolicy() const {
@@ -433,7 +422,6 @@ void AudioContext::MaybeAllowAutoplayWithUnlockType(AutoplayUnlockType type) {
}
bool AudioContext::IsAllowedToStart() const {
- LOG(ERROR) << __func__;
if (!user_gesture_required_)
return true;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h
index c9bd2a53bbd..85858464be2 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h
@@ -37,6 +37,7 @@ class MODULES_EXPORT AudioContext : public BaseAudioContext {
const AudioContextOptions*,
ExceptionState&);
+ AudioContext(Document&, const WebAudioLatencyHint&);
~AudioContext() override;
void Trace(blink::Visitor*) override;
@@ -67,7 +68,6 @@ class MODULES_EXPORT AudioContext : public BaseAudioContext {
void NotifySourceNodeStart() final;
protected:
- AudioContext(Document&, const WebAudioLatencyHint&);
void Uninitialize() final;
private:
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
index e58c2f40042..b26067a9f00 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
@@ -14,15 +14,13 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
-#include "third_party/blink/renderer/core/frame/frame_owner.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/frame_types.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
-#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/modules/webaudio/audio_context_options.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h"
#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
@@ -38,9 +36,11 @@ const char* const kAutoplayCrossOriginMetric = "WebAudio.Autoplay.CrossOrigin";
class MockCrossOriginLocalFrameClient final : public EmptyLocalFrameClient {
public:
static MockCrossOriginLocalFrameClient* Create(Frame* parent) {
- return new MockCrossOriginLocalFrameClient(parent);
+ return MakeGarbageCollected<MockCrossOriginLocalFrameClient>(parent);
}
+ explicit MockCrossOriginLocalFrameClient(Frame* parent) : parent_(parent) {}
+
void Trace(blink::Visitor* visitor) override {
visitor->Trace(parent_);
EmptyLocalFrameClient::Trace(visitor);
@@ -50,8 +50,6 @@ class MockCrossOriginLocalFrameClient final : public EmptyLocalFrameClient {
Frame* Top() const override { return parent_.Get(); }
private:
- explicit MockCrossOriginLocalFrameClient(Frame* parent) : parent_(parent) {}
-
Member<Frame> parent_;
};
@@ -98,12 +96,15 @@ class AudioContextAutoplayTest
using AutoplayStatus = AudioContext::AutoplayStatus;
void SetUp() override {
- dummy_page_holder_ = DummyPageHolder::Create();
- dummy_frame_owner_ = DummyFrameOwner::Create();
+ helper_.Initialize();
+ frame_test_helpers::LoadFrame(helper_.LocalMainFrame(),
+ "data:text/html,<iframe></iframe>");
+
GetDocument().UpdateSecurityOrigin(
SecurityOrigin::Create("https", "example.com", 80));
- CreateChildFrame();
+ ChildDocument().UpdateSecurityOrigin(
+ SecurityOrigin::Create("https", "cross-origin.com", 80));
GetDocument().GetSettings()->SetAutoplayPolicy(GetParam());
ChildDocument().GetSettings()->SetAutoplayPolicy(GetParam());
@@ -111,27 +112,16 @@ class AudioContextAutoplayTest
histogram_tester_ = std::make_unique<HistogramTester>();
}
- void TearDown() override {
- if (child_frame_)
- child_frame_->Detach(FrameDetachType::kRemove);
+ Document& GetDocument() {
+ return *helper_.LocalMainFrame()->GetFrame()->GetDocument();
}
- void CreateChildFrame() {
- child_frame_ = LocalFrame::Create(
- MockCrossOriginLocalFrameClient::Create(GetDocument().GetFrame()),
- *GetDocument().GetFrame()->GetPage(), dummy_frame_owner_.Get());
- child_frame_->SetView(
- LocalFrameView::Create(*child_frame_, IntSize(500, 500)));
- child_frame_->Init();
-
- ChildDocument().UpdateSecurityOrigin(
- SecurityOrigin::Create("https", "cross-origin.com", 80));
+ Document& ChildDocument() {
+ return *ToWebLocalFrameImpl(helper_.LocalMainFrame()->FirstChild())
+ ->GetFrame()
+ ->GetDocument();
}
- Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
-
- Document& ChildDocument() { return *child_frame_->GetDocument(); }
-
ScriptState* GetScriptStateFrom(const Document& document) {
return ToScriptStateForMainWorld(document.GetFrame());
}
@@ -149,9 +139,7 @@ class AudioContextAutoplayTest
}
private:
- std::unique_ptr<DummyPageHolder> dummy_page_holder_;
- Persistent<DummyFrameOwner> dummy_frame_owner_;
- Persistent<LocalFrame> child_frame_;
+ frame_test_helpers::WebViewHelper helper_;
std::unique_ptr<HistogramTester> histogram_tester_;
ScopedTestingPlatformSupport<AudioContextAutoplayTestPlatform> platform_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
index 9a7cbde4e5c..e164c124082 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
@@ -17,6 +17,7 @@
namespace blink {
namespace {
+static bool web_audio_device_paused_;
class MockWebAudioDeviceForAudioContext : public WebAudioDevice {
public:
@@ -27,8 +28,8 @@ class MockWebAudioDeviceForAudioContext : public WebAudioDevice {
void Start() override {}
void Stop() override {}
- void Pause() override {}
- void Resume() override {}
+ void Pause() override { web_audio_device_paused_ = true; }
+ void Resume() override { web_audio_device_paused_ = false; }
double SampleRate() override { return sample_rate_; }
int FramesPerBuffer() override { return frames_per_buffer_; }
@@ -171,4 +172,17 @@ TEST_F(AudioContextTest, AudioContextAudibility_ServiceUnbind) {
platform->RunUntilIdle();
}
+TEST_F(AudioContextTest, ExecutionContextPaused) {
+ AudioContextOptions* options = AudioContextOptions::Create();
+ AudioContext* audio_context =
+ AudioContext::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ audio_context->set_was_audible_for_testing(true);
+ EXPECT_FALSE(web_audio_device_paused_);
+ GetDocument().PausePausableObjects(PauseState::kFrozen);
+ EXPECT_TRUE(web_audio_device_paused_);
+ GetDocument().UnpausePausableObjects();
+ EXPECT_FALSE(web_audio_device_paused_);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_destination_node.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
index 818b3ac50b9..e0242160631 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
@@ -47,6 +47,8 @@ class AudioDestinationHandler : public AudioHandler {
virtual void StartRendering() = 0;
virtual void StopRendering() = 0;
+ virtual void Pause() = 0;
+ virtual void Resume() = 0;
// The render thread needs to be changed after Worklet JS code is loaded by
// AudioWorklet. This method ensures the switching of render thread and the
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_listener.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_listener.h
index 608bd4de29a..ffe857b3175 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_listener.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_listener.h
@@ -47,8 +47,10 @@ class AudioListener : public ScriptWrappable {
public:
static AudioListener* Create(BaseAudioContext& context) {
- return new AudioListener(context);
+ return MakeGarbageCollected<AudioListener>(context);
}
+
+ AudioListener(BaseAudioContext&);
~AudioListener() override;
// Location of the listener
@@ -131,8 +133,6 @@ class AudioListener : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
- AudioListener(BaseAudioContext&);
-
void setPosition(const FloatPoint3D&, ExceptionState&);
void setOrientation(const FloatPoint3D&, ExceptionState&);
void SetUpVector(const FloatPoint3D&, ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc
index 81343ac7a23..55a3610b629 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_options.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
@@ -46,6 +47,7 @@ AudioHandler::AudioHandler(NodeType node_type,
node_type_(kNodeTypeUnknown),
node_(&node),
context_(node.context()),
+ deferred_task_handler_(&context_->GetDeferredTaskHandler()),
last_processing_time_(-1),
last_non_silent_time_(0),
connection_ref_count_(0),
@@ -101,11 +103,11 @@ void AudioHandler::Uninitialize() {
void AudioHandler::Dispose() {
DCHECK(IsMainThread());
- Context()->AssertGraphOwner();
+ deferred_task_handler_->AssertGraphOwner();
- Context()->GetDeferredTaskHandler().RemoveChangedChannelCountMode(this);
- Context()->GetDeferredTaskHandler().RemoveChangedChannelInterpretation(this);
- Context()->GetDeferredTaskHandler().RemoveAutomaticPullNode(this);
+ deferred_task_handler_->RemoveChangedChannelCountMode(this);
+ deferred_task_handler_->RemoveChangedChannelInterpretation(this);
+ deferred_task_handler_->RemoveAutomaticPullNode(this);
for (auto& output : outputs_)
output->Dispose();
}
@@ -360,7 +362,7 @@ void AudioHandler::ProcessIfNecessary(uint32_t frames_to_process) {
void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) {
DCHECK(Context()->IsAudioThread());
- Context()->AssertGraphOwner();
+ deferred_task_handler_->AssertGraphOwner();
DCHECK(inputs_.Contains(input));
if (!inputs_.Contains(input))
@@ -402,7 +404,7 @@ void AudioHandler::UnsilenceOutputs() {
void AudioHandler::EnableOutputsIfNecessary() {
DCHECK(IsMainThread());
- Context()->AssertGraphOwner();
+ deferred_task_handler_->AssertGraphOwner();
// We're enabling outputs for this handler. Remove this from the tail
// processing list (if it's there) so that we don't inadvertently disable the
@@ -427,7 +429,7 @@ void AudioHandler::EnableOutputsIfNecessary() {
void AudioHandler::DisableOutputsIfNecessary() {
// This function calls other functions that require graph ownership,
// so assert that this needs graph ownership too.
- Context()->AssertGraphOwner();
+ deferred_task_handler_->AssertGraphOwner();
// Disable outputs if appropriate. We do this if the number of connections is
// 0 or 1. The case of 0 is from deref() where there are no connections left.
@@ -449,9 +451,8 @@ void AudioHandler::DisableOutputsIfNecessary() {
// the outputs so that the tail for the node can be output.
// Otherwise, we can disable the outputs right away.
if (RequiresTailProcessing()) {
- auto& deferred_task_handler = Context()->GetDeferredTaskHandler();
- if (deferred_task_handler.AcceptsTailProcessing())
- deferred_task_handler.AddTailProcessingHandler(this);
+ if (deferred_task_handler_->AcceptsTailProcessing())
+ deferred_task_handler_->AddTailProcessingHandler(this);
} else {
DisableOutputs();
}
@@ -465,7 +466,7 @@ void AudioHandler::DisableOutputs() {
}
void AudioHandler::MakeConnection() {
- Context()->AssertGraphOwner();
+ deferred_task_handler_->AssertGraphOwner();
connection_ref_count_++;
#if DEBUG_AUDIONODE_REFERENCES
@@ -507,7 +508,7 @@ void AudioHandler::BreakConnection() {
}
void AudioHandler::BreakConnectionWithLock() {
- Context()->AssertGraphOwner();
+ deferred_task_handler_->AssertGraphOwner();
connection_ref_count_--;
#if DEBUG_AUDIONODE_REFERENCES
@@ -729,9 +730,8 @@ AudioNode* AudioNode::connect(AudioNode* destination,
return nullptr;
}
- destination->Handler()
- .Input(input_index)
- .Connect(Handler().Output(output_index));
+ AudioNodeWiring::Connect(Handler().Output(output_index),
+ destination->Handler().Input(input_index));
if (!connected_nodes_[output_index]) {
connected_nodes_[output_index] =
MakeGarbageCollected<HeapHashSet<Member<AudioNode>>>();
@@ -779,7 +779,7 @@ void AudioNode::connect(AudioParam* param,
return;
}
- param->Handler().Connect(Handler().Output(output_index));
+ AudioNodeWiring::Connect(Handler().Output(output_index), param->Handler());
if (!connected_params_[output_index]) {
connected_params_[output_index] =
MakeGarbageCollected<HeapHashSet<Member<AudioParam>>>();
@@ -802,9 +802,9 @@ bool AudioNode::DisconnectFromOutputIfConnected(
AudioNodeOutput& output = Handler().Output(output_index);
AudioNodeInput& input =
destination.Handler().Input(input_index_of_destination);
- if (!output.IsConnectedToInput(input))
+ if (!AudioNodeWiring::IsConnected(output, input))
return false;
- output.DisconnectInput(input);
+ AudioNodeWiring::Disconnect(output, input);
connected_nodes_[output_index]->erase(&destination);
return true;
}
@@ -812,9 +812,9 @@ bool AudioNode::DisconnectFromOutputIfConnected(
bool AudioNode::DisconnectFromOutputIfConnected(unsigned output_index,
AudioParam& param) {
AudioNodeOutput& output = Handler().Output(output_index);
- if (!output.IsConnectedToAudioParam(param.Handler()))
+ if (!AudioNodeWiring::IsConnected(output, param.Handler()))
return false;
- output.DisconnectAudioParam(param.Handler());
+ AudioNodeWiring::Disconnect(output, param.Handler());
connected_params_[output_index]->erase(&param);
return true;
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.h
index a89174b2969..96d122bd141 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.h
@@ -121,6 +121,10 @@ class MODULES_EXPORT AudioHandler : public ThreadSafeRefCounted<AudioHandler> {
virtual BaseAudioContext* Context() const;
void ClearContext() { context_ = nullptr; }
+ DeferredTaskHandler& GetDeferredTaskHandler() const {
+ return *deferred_task_handler_;
+ }
+
enum ChannelCountMode { kMax, kClampedMax, kExplicit };
NodeType GetNodeType() const { return node_type_; }
@@ -275,6 +279,10 @@ class MODULES_EXPORT AudioHandler : public ThreadSafeRefCounted<AudioHandler> {
// See http://crbug.com/404527 for the detail.
UntracedMember<BaseAudioContext> context_;
+ // Legal to access even when |context_| may be gone, such as during the
+ // destructor.
+ const scoped_refptr<DeferredTaskHandler> deferred_task_handler_;
+
Vector<std::unique_ptr<AudioNodeInput>> inputs_;
Vector<std::unique_ptr<AudioNodeOutput>> outputs_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.cc
index 178b1bf0a39..10ee03adfda 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.cc
@@ -30,10 +30,11 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
namespace blink {
-inline AudioNodeInput::AudioNodeInput(AudioHandler& handler)
+AudioNodeInput::AudioNodeInput(AudioHandler& handler)
: AudioSummingJunction(handler.Context()->GetDeferredTaskHandler()),
handler_(handler) {
// Set to mono by default.
@@ -41,72 +42,12 @@ inline AudioNodeInput::AudioNodeInput(AudioHandler& handler)
AudioBus::Create(1, audio_utilities::kRenderQuantumFrames);
}
-std::unique_ptr<AudioNodeInput> AudioNodeInput::Create(AudioHandler& handler) {
- return base::WrapUnique(new AudioNodeInput(handler));
-}
-
-void AudioNodeInput::Connect(AudioNodeOutput& output) {
- GetDeferredTaskHandler().AssertGraphOwner();
-
- // Check if we're already connected to this output.
- if (outputs_.Contains(&output))
- return;
-
- output.AddInput(*this);
- outputs_.insert(&output);
- ChangedOutputs();
+AudioNodeInput::~AudioNodeInput() {
+ AudioNodeWiring::WillBeDestroyed(*this);
}
-void AudioNodeInput::Disconnect(AudioNodeOutput& output) {
- GetDeferredTaskHandler().AssertGraphOwner();
-
- // First try to disconnect from "active" connections.
- if (outputs_.Contains(&output)) {
- outputs_.erase(&output);
- ChangedOutputs();
- output.RemoveInput(*this);
- // Note: it's important to return immediately after removeInput() calls
- // since the node may be deleted.
- return;
- }
-
- // Otherwise, try to disconnect from disabled connections.
- if (disabled_outputs_.Contains(&output)) {
- disabled_outputs_.erase(&output);
- output.RemoveInput(*this);
- // Note: it's important to return immediately after all removeInput() calls
- // since the node may be deleted.
- return;
- }
-
- NOTREACHED();
-}
-
-void AudioNodeInput::Disable(AudioNodeOutput& output) {
- GetDeferredTaskHandler().AssertGraphOwner();
- DCHECK(outputs_.Contains(&output));
-
- disabled_outputs_.insert(&output);
- outputs_.erase(&output);
- ChangedOutputs();
-
- // Propagate disabled state to outputs.
- Handler().DisableOutputsIfNecessary();
-}
-
-void AudioNodeInput::Enable(AudioNodeOutput& output) {
- GetDeferredTaskHandler().AssertGraphOwner();
-
- // Move output from disabled list to active list.
- outputs_.insert(&output);
- if (disabled_outputs_.size() > 0) {
- DCHECK(disabled_outputs_.Contains(&output));
- disabled_outputs_.erase(&output);
- }
- ChangedOutputs();
-
- // Propagate enabled state to outputs.
- Handler().EnableOutputsIfNecessary();
+std::unique_ptr<AudioNodeInput> AudioNodeInput::Create(AudioHandler& handler) {
+ return base::WrapUnique(new AudioNodeInput(handler));
}
void AudioNodeInput::DidUpdate() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.h
index ae8a7b66fcf..3245e4d6a79 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input.h
@@ -27,6 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_NODE_INPUT_H_
#include <memory>
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
#include "third_party/blink/renderer/modules/webaudio/audio_summing_junction.h"
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
@@ -42,12 +43,15 @@ class AudioNodeOutput;
// input will act as a unity-gain summing junction, mixing all the outputs. The
// number of channels of the input's bus is the maximum of the number of
// channels of all its connections.
-
-class AudioNodeInput final : public AudioSummingJunction {
+//
+// Use AudioNodeWiring to connect the AudioNodeOutput of another node to this,
+// and to disconnect, enable or disable that connection afterward.
+class MODULES_EXPORT AudioNodeInput final : public AudioSummingJunction {
USING_FAST_MALLOC(AudioNodeInput);
public:
static std::unique_ptr<AudioNodeInput> Create(AudioHandler&);
+ ~AudioNodeInput() override;
// AudioSummingJunction
void DidUpdate() override;
@@ -55,17 +59,6 @@ class AudioNodeInput final : public AudioSummingJunction {
// Can be called from any thread.
AudioHandler& Handler() const { return handler_; }
- // Must be called with the context's graph lock.
- void Connect(AudioNodeOutput&);
- void Disconnect(AudioNodeOutput&);
-
- // disable() will take the output out of the active connections list and set
- // aside in a disabled list.
- // enable() will put the output back into the active connections list.
- // Must be called with the context's graph lock.
- void Enable(AudioNodeOutput&);
- void Disable(AudioNodeOutput&);
-
// pull() processes all of the AudioNodes connected to us.
// In the case of multiple connections it sums the result into an internal
// summing bus. In the single connection case, it allows in-place processing
@@ -110,6 +103,9 @@ class AudioNodeInput final : public AudioSummingJunction {
void SumAllConnections(AudioBus* summing_bus, uint32_t frames_to_process);
scoped_refptr<AudioBus> internal_summing_bus_;
+
+ // Used to connect inputs and outputs together.
+ friend class AudioNodeWiring;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input_test.cc
new file mode 100644
index 00000000000..3d00fb4e12f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_input_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
+
+#include <memory>
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
+#include "third_party/blink/renderer/modules/webaudio/delay_node.h"
+#include "third_party/blink/renderer/modules/webaudio/offline_audio_context.h"
+
+namespace blink {
+
+TEST(AudioNodeInputTest, InputDestroyedBeforeOutput) {
+ auto page = DummyPageHolder::Create();
+ OfflineAudioContext* context = OfflineAudioContext::Create(
+ &page->GetDocument(), 2, 1, 48000, ASSERT_NO_EXCEPTION);
+ DelayNode* node1 = context->createDelay(ASSERT_NO_EXCEPTION);
+ auto& handler1 = node1->Handler();
+ DelayNode* node2 = context->createDelay(ASSERT_NO_EXCEPTION);
+ auto& handler2 = node2->Handler();
+
+ auto input = AudioNodeInput::Create(handler1);
+ auto output = AudioNodeOutput::Create(&handler2, 0);
+
+ {
+ BaseAudioContext::GraphAutoLocker graph_lock(context);
+ AudioNodeWiring::Connect(*output, *input);
+ ASSERT_TRUE(output->IsConnected());
+
+ // This should not crash.
+ input.reset();
+ output->Dispose();
+ output.reset();
+ }
+}
+
+TEST(AudioNodeInputTest, OutputDestroyedBeforeInput) {
+ auto page = DummyPageHolder::Create();
+ OfflineAudioContext* context = OfflineAudioContext::Create(
+ &page->GetDocument(), 2, 1, 48000, ASSERT_NO_EXCEPTION);
+ DelayNode* node1 = context->createDelay(ASSERT_NO_EXCEPTION);
+ auto& handler1 = node1->Handler();
+ DelayNode* node2 = context->createDelay(ASSERT_NO_EXCEPTION);
+ auto& handler2 = node2->Handler();
+
+ auto input = AudioNodeInput::Create(handler1);
+ auto output = AudioNodeOutput::Create(&handler2, 0);
+
+ {
+ BaseAudioContext::GraphAutoLocker graph_lock(context);
+ AudioNodeWiring::Connect(*output, *input);
+ ASSERT_TRUE(output->IsConnected());
+
+ // This should not crash.
+ output->Dispose();
+ output.reset();
+ input.reset();
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.cc
index def68ddfe37..71019c0b09a 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.cc
@@ -29,6 +29,7 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
@@ -162,54 +163,26 @@ unsigned AudioNodeOutput::RenderingFanOutCount() const {
return rendering_fan_out_count_;
}
-void AudioNodeOutput::AddInput(AudioNodeInput& input) {
- GetDeferredTaskHandler().AssertGraphOwner();
- inputs_.insert(&input);
- input.Handler().MakeConnection();
-}
-
-void AudioNodeOutput::RemoveInput(AudioNodeInput& input) {
- GetDeferredTaskHandler().AssertGraphOwner();
- input.Handler().BreakConnectionWithLock();
- inputs_.erase(&input);
-}
-
void AudioNodeOutput::DisconnectAllInputs() {
GetDeferredTaskHandler().AssertGraphOwner();
- // AudioNodeInput::disconnect() changes m_inputs by calling removeInput().
- while (!inputs_.IsEmpty())
- (*inputs_.begin())->Disconnect(*this);
-}
-
-void AudioNodeOutput::DisconnectInput(AudioNodeInput& input) {
- GetDeferredTaskHandler().AssertGraphOwner();
- DCHECK(IsConnectedToInput(input));
- input.Disconnect(*this);
-}
-
-void AudioNodeOutput::DisconnectAudioParam(AudioParamHandler& param) {
- GetDeferredTaskHandler().AssertGraphOwner();
- DCHECK(IsConnectedToAudioParam(param));
- param.Disconnect(*this);
-}
-
-void AudioNodeOutput::AddParam(AudioParamHandler& param) {
- GetDeferredTaskHandler().AssertGraphOwner();
- params_.insert(&param);
-}
-
-void AudioNodeOutput::RemoveParam(AudioParamHandler& param) {
- GetDeferredTaskHandler().AssertGraphOwner();
- params_.erase(&param);
+ // Disconnect changes inputs_, so we can't iterate directly over the hash set.
+ Vector<AudioNodeInput*, 4> inputs;
+ CopyToVector(inputs_, inputs);
+ for (AudioNodeInput* input : inputs)
+ AudioNodeWiring::Disconnect(*this, *input);
+ DCHECK(inputs_.IsEmpty());
}
void AudioNodeOutput::DisconnectAllParams() {
GetDeferredTaskHandler().AssertGraphOwner();
- // AudioParam::disconnect() changes m_params by calling removeParam().
- while (!params_.IsEmpty())
- (*params_.begin())->Disconnect(*this);
+ // Disconnect changes params_, so we can't iterate directly over the hash set.
+ Vector<AudioParamHandler*, 4> params;
+ CopyToVector(params_, params);
+ for (AudioParamHandler* param : params)
+ AudioNodeWiring::Disconnect(*this, *param);
+ DCHECK(params_.IsEmpty());
}
void AudioNodeOutput::DisconnectAll() {
@@ -217,23 +190,13 @@ void AudioNodeOutput::DisconnectAll() {
DisconnectAllParams();
}
-bool AudioNodeOutput::IsConnectedToInput(AudioNodeInput& input) {
- GetDeferredTaskHandler().AssertGraphOwner();
- return inputs_.Contains(&input);
-}
-
-bool AudioNodeOutput::IsConnectedToAudioParam(AudioParamHandler& param) {
- GetDeferredTaskHandler().AssertGraphOwner();
- return params_.Contains(&param);
-}
-
void AudioNodeOutput::Disable() {
GetDeferredTaskHandler().AssertGraphOwner();
if (is_enabled_) {
is_enabled_ = false;
- for (AudioNodeInput* i : inputs_)
- i->Disable(*this);
+ for (AudioNodeInput* input : inputs_)
+ AudioNodeWiring::Disable(*this, *input);
}
}
@@ -242,8 +205,8 @@ void AudioNodeOutput::Enable() {
if (!is_enabled_) {
is_enabled_ = true;
- for (AudioNodeInput* i : inputs_)
- i->Enable(*this);
+ for (AudioNodeInput* input : inputs_)
+ AudioNodeWiring::Enable(*this, *input);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.h
index b8d63521d9d..dd84388c9ab 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_output.h
@@ -28,6 +28,7 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
@@ -39,7 +40,7 @@ class AudioNodeInput;
// AudioNodeOutput represents a single output for an AudioNode.
// It may be connected to one or more AudioNodeInputs.
-class AudioNodeOutput final {
+class MODULES_EXPORT AudioNodeOutput final {
USING_FAST_MALLOC(AudioNodeOutput);
public:
@@ -69,7 +70,6 @@ class AudioNodeOutput final {
void DisconnectAll();
// Disconnect a specific input or AudioParam.
- void DisconnectInput(AudioNodeInput&);
void DisconnectAudioParam(AudioParamHandler&);
void SetNumberOfChannels(unsigned);
@@ -78,10 +78,6 @@ class AudioNodeOutput final {
bool IsConnected() { return FanOutCount() > 0 || ParamFanOutCount() > 0; }
- // Probe if the output node is connected with a certain input or AudioParam
- bool IsConnectedToInput(AudioNodeInput&);
- bool IsConnectedToAudioParam(AudioParamHandler&);
-
// Disable/Enable happens when there are still JavaScript references to a
// node, but it has otherwise "finished" its work. For example, when a note
// has finished playing. It is kept around, because it may be played again at
@@ -99,23 +95,13 @@ class AudioNodeOutput final {
// Can be called from any thread.
AudioHandler& Handler() const { return handler_; }
DeferredTaskHandler& GetDeferredTaskHandler() const {
- return handler_.Context()->GetDeferredTaskHandler();
+ return handler_.GetDeferredTaskHandler();
}
// This reference is safe because the AudioHandler owns this AudioNodeOutput
// object.
AudioHandler& handler_;
- friend class AudioNodeInput;
- friend class AudioParamHandler;
-
- // These are called from AudioNodeInput.
- // They must be called with the context's graph lock.
- void AddInput(AudioNodeInput&);
- void RemoveInput(AudioNodeInput&);
- void AddParam(AudioParamHandler&);
- void RemoveParam(AudioParamHandler&);
-
// fanOutCount() is the number of AudioNodeInputs that we're connected to.
// This method should not be called in audio thread rendering code, instead
// renderingFanOutCount() should be used.
@@ -179,6 +165,8 @@ class AudioNodeOutput final {
// This collection of raw pointers is safe because they are retained by
// AudioParam objects retained by m_connectedParams of the owner AudioNode.
HashSet<AudioParamHandler*> params_;
+
+ friend class AudioNodeWiring;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc
new file mode 100644
index 00000000000..3cbe48a678f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc
@@ -0,0 +1,228 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
+
+#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
+#include "third_party/blink/renderer/modules/webaudio/deferred_task_handler.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+
+namespace blink {
+
+namespace {
+
+using AudioNodeOutputSet = HashSet<AudioNodeOutput*>;
+
+struct FindOutputResult {
+ AudioNodeOutputSet& output_set;
+ AudioNodeOutputSet::const_iterator iterator;
+ bool is_disabled;
+};
+
+// Given a connected output, finds it in the "active" or "disabled" set (e.g.
+// of the outputs connected to an input). Produces the set in which it was
+// found, an iterator into that set (so that it can be erased), and whether or
+// not the set it was found in was the disabled set.
+//
+// It is an error to pass an output which is *not* connected (i.e. is neither
+// active nor disabled).
+FindOutputResult FindOutput(AudioNodeOutput& output,
+ AudioNodeOutputSet& outputs,
+ AudioNodeOutputSet& disabled_outputs) {
+ auto it = outputs.find(&output);
+ if (it != outputs.end())
+ return {outputs, it, false};
+
+ it = disabled_outputs.find(&output);
+ if (it != disabled_outputs.end())
+ return {disabled_outputs, it, true};
+
+ NOTREACHED() << "The output must be connected to the input.";
+ return {outputs, {}, false};
+}
+
+} // namespace
+
+void AudioNodeWiring::Connect(AudioNodeOutput& output, AudioNodeInput& input) {
+ input.GetDeferredTaskHandler().AssertGraphOwner();
+
+ const bool input_connected_to_output =
+ input.outputs_.Contains(&output) ||
+ input.disabled_outputs_.Contains(&output);
+ const bool output_connected_to_input = output.inputs_.Contains(&input);
+ DCHECK_EQ(input_connected_to_output, output_connected_to_input);
+
+ // Do nothing if already connected.
+ if (input_connected_to_output)
+ return;
+
+ (output.is_enabled_ ? input.outputs_ : input.disabled_outputs_)
+ .insert(&output);
+ output.inputs_.insert(&input);
+
+ // If it has gained an active connection, the input may need to have its
+ // rendering state updated.
+ if (output.is_enabled_)
+ input.ChangedOutputs();
+
+ // The input node's handler needs to know about this connection. This may
+ // cause it to re-enable itself.
+ input.Handler().MakeConnection();
+}
+
+void AudioNodeWiring::Connect(AudioNodeOutput& output,
+ AudioParamHandler& param) {
+ param.GetDeferredTaskHandler().AssertGraphOwner();
+
+ const bool param_connected_to_output = param.outputs_.Contains(&output);
+ const bool output_connected_to_param = output.params_.Contains(&param);
+ DCHECK_EQ(param_connected_to_output, output_connected_to_param);
+
+ // Do nothing if already connected.
+ if (param_connected_to_output)
+ return;
+
+ param.outputs_.insert(&output);
+ output.params_.insert(&param);
+
+ // The param may need to have its rendering state updated.
+ param.ChangedOutputs();
+}
+
+void AudioNodeWiring::Disconnect(AudioNodeOutput& output,
+ AudioNodeInput& input) {
+ input.GetDeferredTaskHandler().AssertGraphOwner();
+
+ // These must be connected.
+ DCHECK(output.inputs_.Contains(&input));
+ DCHECK(input.outputs_.Contains(&output) ||
+ input.disabled_outputs_.Contains(&output));
+
+ // Find the output in the appropriate place.
+ auto result = FindOutput(output, input.outputs_, input.disabled_outputs_);
+
+ // Erase the pointers from both sets.
+ result.output_set.erase(result.iterator);
+ output.inputs_.erase(&input);
+
+ // If an active connection was disconnected, the input may need to have its
+ // rendering state updated.
+ if (!result.is_disabled)
+ input.ChangedOutputs();
+
+ // The input node's handler may try to disable itself if this was the last
+ // connection. This must happen after the set erasures above, or the disabling
+ // logic would observe an inconsistent state.
+ input.Handler().BreakConnectionWithLock();
+}
+
+void AudioNodeWiring::Disconnect(AudioNodeOutput& output,
+ AudioParamHandler& param) {
+ param.GetDeferredTaskHandler().AssertGraphOwner();
+
+ DCHECK(param.outputs_.Contains(&output));
+ DCHECK(output.params_.Contains(&param));
+
+ // Erase the pointers from both sets.
+ param.outputs_.erase(&output);
+ output.params_.erase(&param);
+
+ // The param may need to have its rendering state updated.
+ param.ChangedOutputs();
+}
+
+void AudioNodeWiring::Disable(AudioNodeOutput& output, AudioNodeInput& input) {
+ input.GetDeferredTaskHandler().AssertGraphOwner();
+
+ // These must be connected.
+ DCHECK(output.inputs_.Contains(&input));
+ DCHECK(input.outputs_.Contains(&output) ||
+ input.disabled_outputs_.Contains(&output));
+
+ // The output should have been marked as disabled.
+ DCHECK(!output.is_enabled_);
+
+ // Move from the active list to the disabled list.
+ // Do nothing if this is the current state.
+ if (!input.disabled_outputs_.insert(&output).is_new_entry)
+ return;
+ input.outputs_.erase(&output);
+
+ // Since it has lost an active connection, the input may need to have its
+ // rendering state updated.
+ input.ChangedOutputs();
+
+ // Propagate disabled state downstream. This must happen after the set
+ // manipulations above, or the disabling logic could observe an inconsistent
+ // state.
+ input.Handler().DisableOutputsIfNecessary();
+}
+
+void AudioNodeWiring::Enable(AudioNodeOutput& output, AudioNodeInput& input) {
+ input.GetDeferredTaskHandler().AssertGraphOwner();
+
+ // These must be connected.
+ DCHECK(output.inputs_.Contains(&input));
+ DCHECK(input.outputs_.Contains(&output) ||
+ input.disabled_outputs_.Contains(&output));
+
+ // The output should have been marked as enabled.
+ DCHECK(output.is_enabled_);
+
+ // Move from the disabled list to the active list.
+ // Do nothing if this is the current state.
+ if (!input.outputs_.insert(&output).is_new_entry)
+ return;
+ input.disabled_outputs_.erase(&output);
+
+ // Since it has gained an active connection, the input may need to have its
+ // rendering state updated.
+ input.ChangedOutputs();
+
+ // Propagate enabled state downstream. This must happen after the set
+ // manipulations above, or the disabling logic could observe an inconsistent
+ // state.
+ input.Handler().EnableOutputsIfNecessary();
+}
+
+bool AudioNodeWiring::IsConnected(AudioNodeOutput& output,
+ AudioNodeInput& input) {
+ input.GetDeferredTaskHandler().AssertGraphOwner();
+
+ bool is_connected = output.inputs_.Contains(&input);
+ DCHECK_EQ(is_connected, input.outputs_.Contains(&output) ||
+ input.disabled_outputs_.Contains(&output));
+ return is_connected;
+}
+
+bool AudioNodeWiring::IsConnected(AudioNodeOutput& output,
+ AudioParamHandler& param) {
+ param.GetDeferredTaskHandler().AssertGraphOwner();
+
+ bool is_connected = output.params_.Contains(&param);
+ DCHECK_EQ(is_connected, param.outputs_.Contains(&output));
+ return is_connected;
+}
+
+void AudioNodeWiring::WillBeDestroyed(AudioNodeInput& input) {
+ // This is more or less a streamlined version of calling Disconnect
+ // repeatedly. In particular it cannot happen while the input's handler is
+ // being destroyed, and so does not require any information about these final
+ // changes to its connections.
+ //
+ // What does matter, however, is ensuring that no AudioNodeOutput holds a
+ // dangling pointer to |input|.
+
+ input.GetDeferredTaskHandler().AssertGraphOwner();
+
+ for (AudioNodeOutput* output : input.outputs_)
+ output->inputs_.erase(&input);
+ for (AudioNodeOutput* output : input.disabled_outputs_)
+ output->inputs_.erase(&input);
+ input.outputs_.clear();
+ input.disabled_outputs_.clear();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.h
new file mode 100644
index 00000000000..239e8d83c4a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node_wiring.h
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_NODE_WIRING_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_NODE_WIRING_H_
+
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+class AudioNodeInput;
+class AudioNodeOutput;
+class AudioParamHandler;
+
+// Utilities for connecting AudioHandlers to one another, via AudioNodeInput and
+// AudioNodeOutput. Gathered into one place that can see the internals of both,
+// to avoid both needing to call one another back and forth.
+//
+// An AudioNodeOutput can also be connected to an AudioParamHandler.
+//
+// All functions require the graph lock.
+class MODULES_EXPORT AudioNodeWiring {
+ STATIC_ONLY(AudioNodeWiring);
+
+ public:
+ // Make or break a connection from an output of one audio node to an input of
+ // another.
+ static void Connect(AudioNodeOutput&, AudioNodeInput&);
+ static void Connect(AudioNodeOutput&, AudioParamHandler&);
+ static void Disconnect(AudioNodeOutput&, AudioNodeInput&);
+ static void Disconnect(AudioNodeOutput&, AudioParamHandler&);
+
+ // Disable the connection from an output to an input, setting it aside in
+ // a separate list of disabled connections. Enabling does the reverse.
+ // Should be called only from AudioNodeOutput, when its state has changed.
+ static void Disable(AudioNodeOutput&, AudioNodeInput&);
+ static void Enable(AudioNodeOutput&, AudioNodeInput&);
+
+ // Queries whether a connection exists, disabled or not.
+ static bool IsConnected(AudioNodeOutput&, AudioNodeInput&);
+ static bool IsConnected(AudioNodeOutput&, AudioParamHandler&);
+
+ // Called before complete destruction to remove any remaining connections.
+ static void WillBeDestroyed(AudioNodeInput&);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_NODE_WIRING_H_
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc
index 70af68e84cc..7fead11ff82 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc
@@ -167,7 +167,7 @@ float AudioParamHandler::Value() {
void AudioParamHandler::SetIntrinsicValue(float new_value) {
new_value = clampTo(new_value, min_value_, max_value_);
- NoBarrierStore(&intrinsic_value_, new_value);
+ intrinsic_value_.store(new_value, std::memory_order_relaxed);
}
void AudioParamHandler::SetValue(float value) {
@@ -298,27 +298,6 @@ void AudioParamHandler::CalculateTimelineValues(float* values,
sample_rate, sample_rate, MinValue(), MaxValue()));
}
-void AudioParamHandler::Connect(AudioNodeOutput& output) {
- GetDeferredTaskHandler().AssertGraphOwner();
-
- if (outputs_.Contains(&output))
- return;
-
- output.AddParam(*this);
- outputs_.insert(&output);
- ChangedOutputs();
-}
-
-void AudioParamHandler::Disconnect(AudioNodeOutput& output) {
- GetDeferredTaskHandler().AssertGraphOwner();
-
- if (outputs_.Contains(&output)) {
- outputs_.erase(&output);
- ChangedOutputs();
- output.RemoveParam(*this);
- }
-}
-
int AudioParamHandler::ComputeQHistogramValue(float new_value) const {
// For the Q value, assume a useful range is [0, 25] and that 0.25 dB
// resolution is good enough. Then, we can map the floating point Q value (in
@@ -349,11 +328,11 @@ AudioParam::AudioParam(BaseAudioContext& context,
AudioParam* AudioParam::Create(BaseAudioContext& context,
AudioParamType param_type,
double default_value) {
- return new AudioParam(context, param_type, default_value,
- AudioParamHandler::AutomationRate::kAudio,
- AudioParamHandler::AutomationRateMode::kVariable,
- -std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max());
+ return MakeGarbageCollected<AudioParam>(
+ context, param_type, default_value,
+ AudioParamHandler::AutomationRate::kAudio,
+ AudioParamHandler::AutomationRateMode::kVariable,
+ -std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
}
AudioParam* AudioParam::Create(BaseAudioContext& context,
@@ -365,8 +344,9 @@ AudioParam* AudioParam::Create(BaseAudioContext& context,
float max_value) {
DCHECK_LE(min_value, max_value);
- return new AudioParam(context, param_type, default_value, rate, rate_mode,
- min_value, max_value);
+ return MakeGarbageCollected<AudioParam>(context, param_type, default_value,
+ rate, rate_mode, min_value,
+ max_value);
}
AudioParam::~AudioParam() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h
index eca5b5875bd..b9cbdeb1b6a 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h
@@ -30,6 +30,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_PARAM_H_
#include <sys/types.h>
+#include <atomic>
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
@@ -91,6 +92,8 @@ enum AudioParamType {
// processing classes have additional references. An AudioParamHandler can
// outlive the owner AudioParam, and it never dies before the owner AudioParam
// dies.
+//
+// Connected to AudioNodeOutput using AudioNodeWiring.
class AudioParamHandler final : public ThreadSafeRefCounted<AudioParamHandler>,
public AudioSummingJunction {
public:
@@ -193,11 +196,9 @@ class AudioParamHandler final : public ThreadSafeRefCounted<AudioParamHandler>,
// Must be called in the context's render thread.
void CalculateSampleAccurateValues(float* values, unsigned number_of_values);
- // Connect an audio-rate signal to control this parameter.
- void Connect(AudioNodeOutput&);
- void Disconnect(AudioNodeOutput&);
-
- float IntrinsicValue() const { return NoBarrierLoad(&intrinsic_value_); }
+ float IntrinsicValue() const {
+ return intrinsic_value_.load(std::memory_order_relaxed);
+ }
private:
AudioParamHandler(BaseAudioContext&,
@@ -228,7 +229,7 @@ class AudioParamHandler final : public ThreadSafeRefCounted<AudioParamHandler>,
String custom_param_name_;
// Intrinsic value
- float intrinsic_value_;
+ std::atomic<float> intrinsic_value_;
void SetIntrinsicValue(float new_value);
float default_value_;
@@ -251,6 +252,8 @@ class AudioParamHandler final : public ThreadSafeRefCounted<AudioParamHandler>,
// Audio bus to sum in any connections to the AudioParam.
scoped_refptr<AudioBus> summing_bus_;
+
+ friend class AudioNodeWiring;
};
// AudioParam class represents web-exposed AudioParam interface.
@@ -273,6 +276,13 @@ class AudioParam final : public ScriptWrappable {
float min_value = -std::numeric_limits<float>::max(),
float max_value = std::numeric_limits<float>::max());
+ AudioParam(BaseAudioContext&,
+ AudioParamType,
+ double default_value,
+ AudioParamHandler::AutomationRate rate,
+ AudioParamHandler::AutomationRateMode rate_mode,
+ float min,
+ float max);
~AudioParam() override;
void Trace(blink::Visitor*) override;
@@ -317,14 +327,6 @@ class AudioParam final : public ScriptWrappable {
AudioParam* cancelAndHoldAtTime(double start_time, ExceptionState&);
private:
- AudioParam(BaseAudioContext&,
- AudioParamType,
- double default_value,
- AudioParamHandler::AutomationRate rate,
- AudioParamHandler::AutomationRateMode rate_mode,
- float min,
- float max);
-
void WarnIfOutsideRange(const String& param_methd, float value);
scoped_refptr<AudioParamHandler> handler_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_map.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_map.cc
index e310a529324..de7c7b1654e 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_map.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_map.cc
@@ -47,7 +47,7 @@ AudioParamMap::AudioParamMap(
PairIterable<String, AudioParam*>::IterationSource*
AudioParamMap::StartIteration(ScriptState*, ExceptionState&) {
- return new AudioParamMapIterationSource(parameter_map_);
+ return MakeGarbageCollected<AudioParamMapIterationSource>(parameter_map_);
}
bool AudioParamMap::GetMapEntry(ScriptState*,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
index cd7ad2e7b64..a16b9ac204c 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
@@ -969,9 +969,9 @@ float AudioParamTimeline::ValuesForFrameRangeImpl(size_t start_frame,
fill_to_end_frame = static_cast<size_t>(ceil(time2 * sample_rate));
DCHECK_GE(fill_to_end_frame, start_frame);
- size_t fill_to_frame = fill_to_end_frame - start_frame;
- fill_to_frame =
- std::min(fill_to_frame, static_cast<size_t>(number_of_values));
+ unsigned fill_to_frame =
+ static_cast<unsigned>(fill_to_end_frame - start_frame);
+ fill_to_frame = std::min(fill_to_frame, number_of_values);
const AutomationState current_state = {
number_of_values,
@@ -1089,15 +1089,15 @@ std::tuple<size_t, unsigned> AudioParamTimeline::HandleFirstEvent(
if (first_event_time > start_frame / sample_rate) {
// |fillToFrame| is an exclusive upper bound, so use ceil() to compute the
// bound from the firstEventTime.
- size_t fill_to_frame = end_frame;
+ size_t fill_to_end_frame = end_frame;
double first_event_frame = ceil(first_event_time * sample_rate);
if (end_frame > first_event_frame)
- fill_to_frame = static_cast<size_t>(first_event_frame);
- DCHECK_GE(fill_to_frame, start_frame);
+ fill_to_end_frame = first_event_frame;
+ DCHECK_GE(fill_to_end_frame, start_frame);
- fill_to_frame -= start_frame;
- fill_to_frame =
- std::min(fill_to_frame, static_cast<size_t>(number_of_values));
+ unsigned fill_to_frame =
+ static_cast<unsigned>(fill_to_end_frame - start_frame);
+ fill_to_frame = std::min(fill_to_frame, number_of_values);
write_index =
FillWithDefault(values, default_value, fill_to_frame, write_index);
@@ -1316,7 +1316,8 @@ AudioParamTimeline::HandleCancelValues(const ParamEvent* current_event,
ParamEvent::Type next_event_type =
next_event ? next_event->GetType() : ParamEvent::kLastType;
- if (next_event && next_event->GetType() == ParamEvent::kCancelValues) {
+ if (next_event && next_event->GetType() == ParamEvent::kCancelValues &&
+ next_event->SavedEvent()) {
float value1 = current_event->Value();
double time1 = current_event->Time();
@@ -1412,7 +1413,12 @@ std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessLinearRamp(
auto sample_rate = current_state.sample_rate;
double delta_time = time2 - time1;
- float k = delta_time > 0 ? 1 / delta_time : 0;
+ DCHECK_GE(delta_time, 0);
+ // Since delta_time is a double, 1/delta_time can easily overflow a float.
+ // Thus, if delta_time is close enough to zero (less than float min), treat it
+ // as zero.
+ float k =
+ delta_time <= std::numeric_limits<float>::min() ? 0 : 1 / delta_time;
const float value_delta = value2 - value1;
#if defined(ARCH_CPU_X86_FAMILY)
if (fill_to_frame > write_index) {
@@ -1703,10 +1709,10 @@ std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessSetValueCurve(
// has not yet started. In this case, |fillToFrame| is clipped to
// |time1|+|duration| above, but |startFrame| will keep increasing
// (because the current time is increasing).
- fill_to_frame =
- (fill_to_end_frame < start_frame) ? 0 : fill_to_end_frame - start_frame;
- fill_to_frame =
- std::min(fill_to_frame, static_cast<size_t>(number_of_values));
+ fill_to_frame = (fill_to_end_frame < start_frame)
+ ? 0
+ : static_cast<unsigned>(fill_to_end_frame - start_frame);
+ fill_to_frame = std::min(fill_to_frame, number_of_values);
// Index into the curve data using a floating-point value.
// We're scaling the number of curve points by the duration (see
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
index 34fe05fb890..aabe70d8d2f 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
@@ -279,7 +279,7 @@ class AudioParamTimeline {
const double control_rate;
// Parameters needed for processing the current event.
- const size_t fill_to_frame;
+ const unsigned fill_to_frame;
const size_t fill_to_end_frame;
// Value and time for the current event
@@ -367,7 +367,7 @@ class AudioParamTimeline {
// Handle processing of CancelValue event. If cancellation happens, value2,
// time2, and nextEventType will be updated with the new value due to
- // cancellation. The
+ // cancellation. Note that |next_event| or its member can be null.
std::tuple<float, double, ParamEvent::Type> HandleCancelValues(
const ParamEvent* current_event,
ParamEvent* next_event,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.cc
index c5629a61be9..5d26c22c213 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.cc
@@ -31,19 +31,20 @@
namespace blink {
AudioProcessingEvent* AudioProcessingEvent::Create() {
- return new AudioProcessingEvent;
+ return MakeGarbageCollected<AudioProcessingEvent>();
}
AudioProcessingEvent* AudioProcessingEvent::Create(AudioBuffer* input_buffer,
AudioBuffer* output_buffer,
double playback_time) {
- return new AudioProcessingEvent(input_buffer, output_buffer, playback_time);
+ return MakeGarbageCollected<AudioProcessingEvent>(input_buffer, output_buffer,
+ playback_time);
}
AudioProcessingEvent* AudioProcessingEvent::Create(
const AtomicString& type,
const AudioProcessingEventInit* initializer) {
- return new AudioProcessingEvent(type, initializer);
+ return MakeGarbageCollected<AudioProcessingEvent>(type, initializer);
}
AudioProcessingEvent::AudioProcessingEvent() = default;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.h
index 705a3d448bb..9c662f38d94 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_processing_event.h
@@ -48,6 +48,12 @@ class AudioProcessingEvent final : public Event {
static AudioProcessingEvent* Create(const AtomicString& type,
const AudioProcessingEventInit*);
+ AudioProcessingEvent();
+ AudioProcessingEvent(AudioBuffer* input_buffer,
+ AudioBuffer* output_buffer,
+ double playback_time);
+ AudioProcessingEvent(const AtomicString& type,
+ const AudioProcessingEventInit*);
~AudioProcessingEvent() override;
AudioBuffer* inputBuffer() { return input_buffer_.Get(); }
@@ -59,13 +65,6 @@ class AudioProcessingEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
- AudioProcessingEvent();
- AudioProcessingEvent(AudioBuffer* input_buffer,
- AudioBuffer* output_buffer,
- double playback_time);
- AudioProcessingEvent(const AtomicString& type,
- const AudioProcessingEventInit*);
-
Member<AudioBuffer> input_buffer_;
Member<AudioBuffer> output_buffer_;
double playback_time_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.h
index 27a25b70390..34b80e24caa 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.h
@@ -29,6 +29,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_SCHEDULED_SOURCE_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_SCHEDULED_SOURCE_NODE_H_
+#include <atomic>
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
@@ -67,11 +68,11 @@ class AudioScheduledSourceHandler : public AudioHandler {
double LatencyTime() const override { return 0; }
PlaybackState GetPlaybackState() const {
- return static_cast<PlaybackState>(AcquireLoad(&playback_state_));
+ return playback_state_.load(std::memory_order_acquire);
}
void SetPlaybackState(PlaybackState new_state) {
- ReleaseStore(&playback_state_, new_state);
+ playback_state_.store(new_state, std::memory_order_release);
}
bool IsPlayingOrScheduled() const {
@@ -137,7 +138,7 @@ class AudioScheduledSourceHandler : public AudioHandler {
private:
// This is accessed by both the main thread and audio thread. Use the setter
// and getter to protect the access to this.
- int playback_state_;
+ std::atomic<PlaybackState> playback_state_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
index 761113d9ecd..7403a9d7f32 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
@@ -17,7 +17,7 @@
namespace blink {
AudioWorklet* AudioWorklet::Create(BaseAudioContext* context) {
- return new AudioWorklet(context);
+ return MakeGarbageCollected<AudioWorklet>(context);
}
AudioWorklet::AudioWorklet(BaseAudioContext* context)
@@ -80,7 +80,8 @@ WorkletGlobalScopeProxy* AudioWorklet::CreateGlobalScope() {
DCHECK_EQ(GetNumberOfGlobalScopes(), 0u);
AudioWorkletMessagingProxy* proxy =
- new AudioWorkletMessagingProxy(GetExecutionContext(), this);
+ MakeGarbageCollected<AudioWorkletMessagingProxy>(GetExecutionContext(),
+ this);
proxy->Initialize(WorkerClients::Create(), ModuleResponsesMap());
return proxy;
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.h
index ab36e530610..0086815af75 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.h
@@ -26,6 +26,7 @@ class MODULES_EXPORT AudioWorklet final : public Worklet {
public:
static AudioWorklet* Create(BaseAudioContext*);
+ explicit AudioWorklet(BaseAudioContext*);
~AudioWorklet() override = default;
void CreateProcessor(scoped_refptr<AudioWorkletHandler>,
@@ -55,8 +56,6 @@ class MODULES_EXPORT AudioWorklet final : public Worklet {
void Trace(blink::Visitor*) override;
private:
- explicit AudioWorklet(BaseAudioContext*);
-
// Implements Worklet
bool NeedsToCreateGlobalScope() final;
WorkletGlobalScopeProxy* CreateGlobalScope() final;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
index b5f727fb2d5..380c7081fda 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
@@ -38,7 +39,8 @@ namespace blink {
AudioWorkletGlobalScope* AudioWorkletGlobalScope::Create(
std::unique_ptr<GlobalScopeCreationParams> creation_params,
WorkerThread* thread) {
- return new AudioWorkletGlobalScope(std::move(creation_params), thread);
+ return MakeGarbageCollected<AudioWorkletGlobalScope>(
+ std::move(creation_params), thread);
}
AudioWorkletGlobalScope::AudioWorkletGlobalScope(
@@ -163,7 +165,7 @@ AudioWorkletProcessor* AudioWorkletGlobalScope::CreateProcessor(
bool did_construct =
V8ScriptRunner::CallAsConstructor(
isolate, definition->ConstructorLocal(isolate),
- ExecutionContext::From(script_state), arraysize(argv), argv)
+ ExecutionContext::From(script_state), base::size(argv), argv)
.ToLocal(&result);
processor_creation_params_.reset();
@@ -326,7 +328,7 @@ bool AudioWorkletGlobalScope::Process(
v8::Local<v8::Value> local_result;
if (!V8ScriptRunner::CallFunction(definition->ProcessLocal(isolate),
ExecutionContext::From(script_state),
- processor_handle, arraysize(argv), argv,
+ processor_handle, base::size(argv), argv,
isolate)
.ToLocal(&local_result) ||
block.HasCaught()) {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
index d6154430dff..d3b430994b2 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
@@ -54,7 +54,11 @@ class MODULES_EXPORT AudioWorkletGlobalScope final : public WorkletGlobalScope {
static AudioWorkletGlobalScope* Create(
std::unique_ptr<GlobalScopeCreationParams>,
WorkerThread*);
+
+ AudioWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
+ WorkerThread*);
~AudioWorkletGlobalScope() override;
+
bool IsAudioWorkletGlobalScope() const final { return true; }
void Dispose() final;
bool IsClosing() const final { return is_closing_; }
@@ -104,9 +108,6 @@ class MODULES_EXPORT AudioWorkletGlobalScope final : public WorkletGlobalScope {
void Trace(blink::Visitor*) override;
private:
- AudioWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
- WorkerThread*);
-
bool is_closing_ = false;
typedef HeapHashMap<String,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
index c60b0414d34..5beab54f7fa 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
@@ -68,14 +68,17 @@ class AudioWorkletGlobalScopeTest : public PageTestBase {
Document* document = &GetDocument();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
- document->GetReferrerPolicy(), document->GetSecurityOrigin(),
- document->IsSecureContext(), document->GetHttpsState(),
- nullptr /* worker_clients */, document->AddressSpace(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled,
+ document->UserAgent(), nullptr /* web_worker_fetch_context */,
+ Vector<CSPHeaderAndType>(), document->GetReferrerPolicy(),
+ document->GetSecurityOrigin(), document->IsSecureContext(),
+ document->GetHttpsState(), nullptr /* worker_clients */,
+ document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap),
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>()),
base::nullopt, std::make_unique<WorkerDevToolsParams>(),
ParentExecutionContextTaskRunners::Create());
return thread;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
index 055cb2b54a2..e22cef3c28f 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
@@ -242,7 +242,7 @@ AudioWorkletNode::AudioWorkletNode(
}
}
}
- parameter_map_ = new AudioParamMap(audio_param_map);
+ parameter_map_ = MakeGarbageCollected<AudioParamMap>(audio_param_map);
SetHandler(AudioWorkletHandler::Create(*this,
context.sampleRate(),
@@ -320,10 +320,10 @@ AudioWorkletNode* AudioWorkletNode::Create(
MessageChannel::Create(context->GetExecutionContext());
MessagePortChannel processor_port_channel = channel->port2()->Disentangle();
- AudioWorkletNode* node =
- new AudioWorkletNode(*context, name, options,
- context->audioWorklet()->GetParamInfoListForProcessor(name),
- channel->port1());
+ AudioWorkletNode* node = MakeGarbageCollected<AudioWorkletNode>(
+ *context, name, options,
+ context->audioWorklet()->GetParamInfoListForProcessor(name),
+ channel->port1());
if (!node) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h
index 5a67d491922..ae5c54e3538 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h
@@ -102,6 +102,12 @@ class AudioWorkletNode final : public AudioNode,
const AudioWorkletNodeOptions*,
ExceptionState&);
+ AudioWorkletNode(BaseAudioContext&,
+ const String& name,
+ const AudioWorkletNodeOptions*,
+ const Vector<CrossThreadAudioParamInfo>,
+ MessagePort* node_port);
+
// ActiveScriptWrappable
bool HasPendingActivity() const final;
@@ -115,12 +121,6 @@ class AudioWorkletNode final : public AudioNode,
void Trace(blink::Visitor*) override;
private:
- AudioWorkletNode(BaseAudioContext&,
- const String& name,
- const AudioWorkletNodeOptions*,
- const Vector<CrossThreadAudioParamInfo>,
- MessagePort* node_port);
-
scoped_refptr<AudioWorkletHandler> GetWorkletHandler() const;
Member<AudioParamMap> parameter_map_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
index 67fa0edf9ce..bc094b7300e 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
@@ -23,7 +23,8 @@ AudioWorkletProcessor* AudioWorkletProcessor::Create(
MessagePort* port = MessagePort::Create(*global_scope);
port->Entangle(std::move(params->PortChannel()));
- return new AudioWorkletProcessor(global_scope, params->Name(), port);
+ return MakeGarbageCollected<AudioWorkletProcessor>(global_scope,
+ params->Name(), port);
}
AudioWorkletProcessor::AudioWorkletProcessor(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h
index 02abe39f466..e5e9aedcac0 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h
@@ -38,6 +38,9 @@ class MODULES_EXPORT AudioWorkletProcessor : public ScriptWrappable {
// |AudioWorkletGlobalScope|.
static AudioWorkletProcessor* Create(ExecutionContext*);
+ AudioWorkletProcessor(AudioWorkletGlobalScope*,
+ const String& name,
+ MessagePort*);
~AudioWorkletProcessor() override = default;
// |AudioWorkletHandler| invokes this method to process audio.
@@ -58,10 +61,6 @@ class MODULES_EXPORT AudioWorkletProcessor : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
- AudioWorkletProcessor(AudioWorkletGlobalScope*,
- const String& name,
- MessagePort*);
-
Member<AudioWorkletGlobalScope> global_scope_;
Member<MessagePort> processor_port_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.cc
index 80baa713901..772cc476c12 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.cc
@@ -12,8 +12,8 @@ AudioWorkletProcessorDefinition* AudioWorkletProcessorDefinition::Create(
v8::Local<v8::Object> constructor,
v8::Local<v8::Function> process) {
DCHECK(!IsMainThread());
- return new AudioWorkletProcessorDefinition(isolate, name, constructor,
- process);
+ return MakeGarbageCollected<AudioWorkletProcessorDefinition>(
+ isolate, name, constructor, process);
}
AudioWorkletProcessorDefinition::AudioWorkletProcessorDefinition(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
index d54fdb20ed1..7e1fa730299 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
@@ -32,6 +32,10 @@ class MODULES_EXPORT AudioWorkletProcessorDefinition final
v8::Local<v8::Object> constructor,
v8::Local<v8::Function> process);
+ AudioWorkletProcessorDefinition(v8::Isolate*,
+ const String& name,
+ v8::Local<v8::Object> constructor,
+ v8::Local<v8::Function> process);
virtual ~AudioWorkletProcessorDefinition();
const String& GetName() const { return name_; }
@@ -48,8 +52,8 @@ class MODULES_EXPORT AudioWorkletProcessorDefinition final
void MarkAsSynchronized() { is_synchronized_ = true; }
void Trace(blink::Visitor* visitor) {
- visitor->Trace(constructor_.Cast<v8::Value>());
- visitor->Trace(process_.Cast<v8::Value>());
+ visitor->Trace(constructor_);
+ visitor->Trace(process_);
visitor->Trace(audio_param_descriptors_);
};
const char* NameInHeapSnapshot() const override {
@@ -57,12 +61,6 @@ class MODULES_EXPORT AudioWorkletProcessorDefinition final
}
private:
- AudioWorkletProcessorDefinition(
- v8::Isolate*,
- const String& name,
- v8::Local<v8::Object> constructor,
- v8::Local<v8::Function> process);
-
const String name_;
bool is_synchronized_ = false;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
index 97250df4c50..52503a9e5b2 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
@@ -52,14 +52,17 @@ class AudioWorkletThreadTest : public PageTestBase {
Document* document = &GetDocument();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
- document->GetReferrerPolicy(), document->GetSecurityOrigin(),
- document->IsSecureContext(), document->GetHttpsState(),
- nullptr /* worker_clients */, document->AddressSpace(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled,
+ document->UserAgent(), nullptr /* web_worker_fetch_context */,
+ Vector<CSPHeaderAndType>(), document->GetReferrerPolicy(),
+ document->GetSecurityOrigin(), document->IsSecureContext(),
+ document->GetHttpsState(), nullptr /* worker_clients */,
+ document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap),
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>()),
base::nullopt, std::make_unique<WorkerDevToolsParams>(),
ParentExecutionContextTaskRunners::Create());
return thread;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
index 2102fef2103..4a55dfb1321 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -101,6 +101,7 @@ BaseAudioContext::BaseAudioContext(Document* document,
periodic_wave_sawtooth_(nullptr),
periodic_wave_triangle_(nullptr),
output_position_(),
+ callback_metric_(),
task_runner_(document->GetTaskRunner(TaskType::kInternalMedia)) {}
BaseAudioContext::~BaseAudioContext() {
@@ -175,6 +176,15 @@ void BaseAudioContext::Uninitialize() {
DCHECK_EQ(active_source_nodes_.size(), 0u);
}
+void BaseAudioContext::ContextPaused(PauseState pause_state) {
+ if (pause_state == PauseState::kFrozen)
+ destination()->GetAudioDestinationHandler().Pause();
+}
+
+void BaseAudioContext::ContextUnpaused() {
+ destination()->GetAudioDestinationHandler().Resume();
+}
+
void BaseAudioContext::ContextDestroyed(ExecutionContext*) {
destination()->GetAudioDestinationHandler().ContextDestroyed();
Uninitialize();
@@ -204,7 +214,7 @@ void BaseAudioContext::ThrowExceptionForClosedState(
"AudioContext has been closed.");
}
-AudioBuffer* BaseAudioContext::createBuffer(unsigned number_of_channels,
+AudioBuffer* BaseAudioContext::createBuffer(uint32_t number_of_channels,
uint32_t number_of_frames,
float sample_rate,
ExceptionState& exception_state) {
@@ -369,7 +379,7 @@ ScriptProcessorNode* BaseAudioContext::createScriptProcessor(
}
ScriptProcessorNode* BaseAudioContext::createScriptProcessor(
- size_t buffer_size,
+ uint32_t buffer_size,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -377,8 +387,8 @@ ScriptProcessorNode* BaseAudioContext::createScriptProcessor(
}
ScriptProcessorNode* BaseAudioContext::createScriptProcessor(
- size_t buffer_size,
- size_t number_of_input_channels,
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -387,9 +397,9 @@ ScriptProcessorNode* BaseAudioContext::createScriptProcessor(
}
ScriptProcessorNode* BaseAudioContext::createScriptProcessor(
- size_t buffer_size,
- size_t number_of_input_channels,
- size_t number_of_output_channels,
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -473,7 +483,7 @@ ChannelSplitterNode* BaseAudioContext::createChannelSplitter(
}
ChannelSplitterNode* BaseAudioContext::createChannelSplitter(
- size_t number_of_outputs,
+ uint32_t number_of_outputs,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -488,7 +498,7 @@ ChannelMergerNode* BaseAudioContext::createChannelMerger(
}
ChannelMergerNode* BaseAudioContext::createChannelMerger(
- size_t number_of_inputs,
+ uint32_t number_of_inputs,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -666,7 +676,8 @@ void BaseAudioContext::HandleStoppableSourceNodes() {
}
void BaseAudioContext::HandlePreRenderTasks(
- const AudioIOPosition& output_position) {
+ const AudioIOPosition& output_position,
+ const AudioIOCallbackMetric& metric) {
DCHECK(IsAudioThread());
// At the beginning of every render quantum, try to update the internal
@@ -684,8 +695,9 @@ void BaseAudioContext::HandlePreRenderTasks(
// Update the dirty state of the listener.
listener()->UpdateState();
- // Update output timestamp.
+ // Update output timestamp and metric.
output_position_ = output_position;
+ callback_metric_ = metric;
unlock();
}
@@ -697,8 +709,8 @@ static bool IsAudible(const AudioBus* rendered_data) {
// for the total energy.
float energy = 0;
- unsigned data_size = rendered_data->length();
- for (unsigned k = 0; k < rendered_data->NumberOfChannels(); ++k) {
+ uint32_t data_size = rendered_data->length();
+ for (uint32_t k = 0; k < rendered_data->NumberOfChannels(); ++k) {
const float* data = rendered_data->Channel(k)->Data();
float channel_energy;
vector_math::Vsvesq(data, 1, &channel_energy, data_size);
@@ -790,11 +802,11 @@ void BaseAudioContext::PerformCleanupOnMainThread() {
}
// Break the connection and release active nodes that have finished
// playing.
- unsigned remove_count = 0;
+ wtf_size_t remove_count = 0;
Vector<bool> removables;
removables.resize(active_source_nodes_.size());
for (AudioHandler* handler : finished_handlers) {
- for (unsigned i = 0; i < active_source_nodes_.size(); ++i) {
+ for (wtf_size_t i = 0; i < active_source_nodes_.size(); ++i) {
if (handler == &active_source_nodes_[i]->Handler()) {
handler->BreakConnectionWithLock();
removables[i] = true;
@@ -808,11 +820,11 @@ void BaseAudioContext::PerformCleanupOnMainThread() {
if (remove_count > 0) {
HeapVector<Member<AudioNode>> actives;
DCHECK_GE(active_source_nodes_.size(), remove_count);
- size_t initial_capacity =
+ wtf_size_t initial_capacity =
std::min(active_source_nodes_.size() - remove_count,
active_source_nodes_.size());
actives.ReserveInitialCapacity(initial_capacity);
- for (unsigned i = 0; i < removables.size(); ++i) {
+ for (wtf_size_t i = 0; i < removables.size(); ++i) {
if (!removables[i])
actives.push_back(active_source_nodes_[i]);
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h
index d2459fd07be..575b6059e90 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -33,7 +33,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_decode_error_callback.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -119,6 +119,8 @@ class MODULES_EXPORT BaseAudioContext
}
// Document notification
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
void ContextDestroyed(ExecutionContext*) override;
bool HasPendingActivity() const override;
@@ -137,7 +139,7 @@ class MODULES_EXPORT BaseAudioContext
AudioContextState ContextState() const { return context_state_; }
void ThrowExceptionForClosedState(ExceptionState&);
- AudioBuffer* createBuffer(unsigned number_of_channels,
+ AudioBuffer* createBuffer(uint32_t number_of_channels,
uint32_t number_of_frames,
float sample_rate,
ExceptionState&);
@@ -184,21 +186,21 @@ class MODULES_EXPORT BaseAudioContext
DynamicsCompressorNode* createDynamicsCompressor(ExceptionState&);
AnalyserNode* createAnalyser(ExceptionState&);
ScriptProcessorNode* createScriptProcessor(ExceptionState&);
- ScriptProcessorNode* createScriptProcessor(size_t buffer_size,
+ ScriptProcessorNode* createScriptProcessor(uint32_t buffer_size,
ExceptionState&);
- ScriptProcessorNode* createScriptProcessor(size_t buffer_size,
- size_t number_of_input_channels,
+ ScriptProcessorNode* createScriptProcessor(uint32_t buffer_size,
+ uint32_t number_of_input_channels,
ExceptionState&);
- ScriptProcessorNode* createScriptProcessor(size_t buffer_size,
- size_t number_of_input_channels,
- size_t number_of_output_channels,
+ ScriptProcessorNode* createScriptProcessor(uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels,
ExceptionState&);
StereoPannerNode* createStereoPanner(ExceptionState&);
ChannelSplitterNode* createChannelSplitter(ExceptionState&);
- ChannelSplitterNode* createChannelSplitter(size_t number_of_outputs,
+ ChannelSplitterNode* createChannelSplitter(uint32_t number_of_outputs,
ExceptionState&);
ChannelMergerNode* createChannelMerger(ExceptionState&);
- ChannelMergerNode* createChannelMerger(size_t number_of_inputs,
+ ChannelMergerNode* createChannelMerger(uint32_t number_of_inputs,
ExceptionState&);
OscillatorNode* createOscillator(ExceptionState&);
PeriodicWave* createPeriodicWave(const Vector<float>& real,
@@ -229,7 +231,8 @@ class MODULES_EXPORT BaseAudioContext
void NotifySourceNodeFinishedProcessing(AudioHandler*);
// Called at the start of each render quantum.
- void HandlePreRenderTasks(const AudioIOPosition& output_position);
+ void HandlePreRenderTasks(const AudioIOPosition& output_position,
+ const AudioIOCallbackMetric& metric);
// Called at the end of each render quantum.
void HandlePostRenderTasks(const AudioBus* destination_bus);
@@ -255,7 +258,7 @@ class MODULES_EXPORT BaseAudioContext
using GraphAutoLocker = DeferredTaskHandler::GraphAutoLocker;
// Returns the maximum numuber of channels we can support.
- static unsigned MaxNumberOfChannels() { return kMaxNumberOfChannels; }
+ static uint32_t MaxNumberOfChannels() { return kMaxNumberOfChannels; }
// EventTarget
const AtomicString& InterfaceName() const final;
@@ -420,6 +423,7 @@ class MODULES_EXPORT BaseAudioContext
enum { kMaxNumberOfChannels = 32 };
AudioIOPosition output_position_;
+ AudioIOCallbackMetric callback_metric_;
// The handler associated with the above |destination_node_|.
scoped_refptr<AudioDestinationHandler> destination_handler_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc
index 07cb774c2d2..825a68f11b4 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc
@@ -108,7 +108,7 @@ BiquadFilterNode* BiquadFilterNode::Create(BaseAudioContext& context,
return nullptr;
}
- return new BiquadFilterNode(context);
+ return MakeGarbageCollected<BiquadFilterNode>(context);
}
BiquadFilterNode* BiquadFilterNode::Create(BaseAudioContext* context,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.h b/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.h
index e4a7b177333..fb59ba2b00a 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.h
@@ -78,6 +78,8 @@ class BiquadFilterNode final : public AudioNode {
const BiquadFilterOptions*,
ExceptionState&);
+ BiquadFilterNode(BaseAudioContext&);
+
void Trace(blink::Visitor*) override;
String type() const;
@@ -96,8 +98,6 @@ class BiquadFilterNode final : public AudioNode {
ExceptionState&);
private:
- BiquadFilterNode(BaseAudioContext&);
-
BiquadProcessor* GetBiquadProcessor() const;
bool setType(unsigned); // Returns true on success.
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.cc
index a1d325c8c4e..e1c94d1271c 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.cc
@@ -160,7 +160,7 @@ ChannelMergerNode* ChannelMergerNode::Create(BaseAudioContext& context,
return nullptr;
}
- return new ChannelMergerNode(context, number_of_inputs);
+ return MakeGarbageCollected<ChannelMergerNode>(context, number_of_inputs);
}
ChannelMergerNode* ChannelMergerNode::Create(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.h b/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.h
index eb92527a920..19ec372e893 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/channel_merger_node.h
@@ -69,7 +69,6 @@ class ChannelMergerNode final : public AudioNode {
const ChannelMergerOptions*,
ExceptionState&);
- private:
ChannelMergerNode(BaseAudioContext&, unsigned number_of_inputs);
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.cc
index 6471c29edf2..7f6199cfe1b 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.cc
@@ -166,7 +166,7 @@ ChannelSplitterNode* ChannelSplitterNode::Create(
return nullptr;
}
- return new ChannelSplitterNode(context, number_of_outputs);
+ return MakeGarbageCollected<ChannelSplitterNode>(context, number_of_outputs);
}
ChannelSplitterNode* ChannelSplitterNode::Create(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.h b/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.h
index 155c8f17014..58d12439548 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/channel_splitter_node.h
@@ -67,7 +67,6 @@ class ChannelSplitterNode final : public AudioNode {
const ChannelSplitterOptions*,
ExceptionState&);
- private:
ChannelSplitterNode(BaseAudioContext&, unsigned number_of_outputs);
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.cc
index b56415124b2..26683090fe5 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.cc
@@ -127,7 +127,7 @@ ConstantSourceNode* ConstantSourceNode::Create(
return nullptr;
}
- return new ConstantSourceNode(context);
+ return MakeGarbageCollected<ConstantSourceNode>(context);
}
ConstantSourceNode* ConstantSourceNode::Create(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.h b/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.h
index 4885e2d78e7..436217bbbd6 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/constant_source_node.h
@@ -49,12 +49,13 @@ class ConstantSourceNode final : public AudioScheduledSourceNode {
static ConstantSourceNode* Create(BaseAudioContext*,
const ConstantSourceOptions*,
ExceptionState&);
+
+ ConstantSourceNode(BaseAudioContext&);
void Trace(blink::Visitor*) override;
AudioParam* offset();
private:
- ConstantSourceNode(BaseAudioContext&);
ConstantSourceHandler& GetConstantSourceHandler() const;
Member<AudioParam> offset_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
index 4886bab5e51..a0c05beab71 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
@@ -110,7 +110,7 @@ void ConvolverHandler::SetBuffer(AudioBuffer* buffer,
}
unsigned number_of_channels = buffer->numberOfChannels();
- size_t buffer_length = buffer->length();
+ uint32_t buffer_length = buffer->length();
// The current implementation supports only 1-, 2-, or 4-channel impulse
// responses, with the 4-channel response being interpreted as true-stereo
@@ -273,7 +273,7 @@ ConvolverNode* ConvolverNode::Create(BaseAudioContext& context,
return nullptr;
}
- return new ConvolverNode(context);
+ return MakeGarbageCollected<ConvolverNode>(context);
}
ConvolverNode* ConvolverNode::Create(BaseAudioContext* context,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h
index 9b28e5efd01..d615533e62e 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h
@@ -98,13 +98,14 @@ class MODULES_EXPORT ConvolverNode final : public AudioNode {
const ConvolverOptions*,
ExceptionState&);
+ ConvolverNode(BaseAudioContext&);
+
AudioBuffer* buffer() const;
void setBuffer(AudioBuffer*, ExceptionState&);
bool normalize() const;
void setNormalize(bool);
private:
- ConvolverNode(BaseAudioContext&);
ConvolverHandler& GetConvolverHandler() const;
FRIEND_TEST_ALL_PREFIXES(ConvolverNodeTest, ReverbLifetime);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc
index 9d8b35737b1..ce42fc0cea9 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc
@@ -126,6 +126,20 @@ void DefaultAudioDestinationHandler::StopRendering() {
StopPlatformDestination();
}
+void DefaultAudioDestinationHandler::Pause() {
+ DCHECK(IsMainThread());
+ if (platform_destination_) {
+ platform_destination_->Pause();
+ }
+}
+
+void DefaultAudioDestinationHandler::Resume() {
+ DCHECK(IsMainThread());
+ if (platform_destination_) {
+ platform_destination_->Resume();
+ }
+}
+
void DefaultAudioDestinationHandler::RestartRendering() {
DCHECK(IsMainThread());
@@ -147,7 +161,8 @@ double DefaultAudioDestinationHandler::SampleRate() const {
void DefaultAudioDestinationHandler::Render(
AudioBus* destination_bus,
uint32_t number_of_frames,
- const AudioIOPosition& output_position) {
+ const AudioIOPosition& output_position,
+ const AudioIOCallbackMetric& metric) {
TRACE_EVENT0("webaudio", "DefaultAudioDestinationHandler::Render");
// Denormals can seriously hurt performance of audio processing. This will
@@ -172,7 +187,7 @@ void DefaultAudioDestinationHandler::Render(
return;
}
- Context()->HandlePreRenderTasks(output_position);
+ Context()->HandlePreRenderTasks(output_position, metric);
// Renders the graph by pulling all the input(s) to this node. This will in
// turn pull on their input(s), all the way backwards through the graph.
@@ -202,7 +217,7 @@ void DefaultAudioDestinationHandler::Render(
Context()->UpdateWorkletGlobalScopeOnRenderingThread();
}
-size_t DefaultAudioDestinationHandler::GetCallbackBufferSize() const {
+uint32_t DefaultAudioDestinationHandler::GetCallbackBufferSize() const {
DCHECK(IsMainThread());
DCHECK(IsInitialized());
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h
index 1451f6cddc5..f693c0c1a35 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h
@@ -58,6 +58,8 @@ class DefaultAudioDestinationHandler final : public AudioDestinationHandler,
// For AudioDestinationHandler.
void StartRendering() override;
void StopRendering() override;
+ void Pause() override;
+ void Resume() override;
void RestartRendering() override;
uint32_t MaxChannelCount() const override;
double SampleRate() const override;
@@ -67,10 +69,11 @@ class DefaultAudioDestinationHandler final : public AudioDestinationHandler,
// |output_position|.
void Render(AudioBus* destination_bus,
uint32_t number_of_frames,
- const AudioIOPosition& output_position) final;
+ const AudioIOPosition& output_position,
+ const AudioIOCallbackMetric& metric) final;
// Returns a hadrware callback buffer size from audio infra.
- size_t GetCallbackBufferSize() const;
+ uint32_t GetCallbackBufferSize() const;
// Returns a given frames-per-buffer size from audio infra.
int GetFramesPerBuffer() const;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
index 9d409388f14..9b89eb8a8d7 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
@@ -350,8 +350,7 @@ void DeferredTaskHandler::ClearHandlersToBeDeleted() {
void DeferredTaskHandler::SetAudioThreadToCurrentThread() {
DCHECK(!IsMainThread());
- ThreadIdentifier thread = CurrentThread();
- ReleaseStore(&audio_thread_, thread);
+ audio_thread_.store(CurrentThread(), std::memory_order_relaxed);
}
void DeferredTaskHandler::DisableOutputsForTailProcessing() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h
index cc72c0b87aa..133061d5388 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_DEFERRED_TASK_HANDLER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_DEFERRED_TASK_HANDLER_H_
+#include <atomic>
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -134,15 +135,12 @@ class MODULES_EXPORT DeferredTaskHandler final
// Thread Safety and Graph Locking:
//
void SetAudioThreadToCurrentThread();
- ThreadIdentifier AudioThread() const { return AcquireLoad(&audio_thread_); }
- // TODO(hongchan): Use no-barrier load here. (crbug.com/247328)
- //
// It is okay to use a relaxed (no-barrier) load here. Because the data
// referenced by m_audioThread is not actually being used, thus we do not
// need a barrier between the load of m_audioThread and of that data.
bool IsAudioThread() const {
- return CurrentThread() == AcquireLoad(&audio_thread_);
+ return CurrentThread() == audio_thread_.load(std::memory_order_relaxed);
}
void lock();
@@ -245,7 +243,7 @@ class MODULES_EXPORT DeferredTaskHandler final
// Graph locking.
RecursiveMutex context_graph_mutex_;
- volatile ThreadIdentifier audio_thread_;
+ std::atomic<ThreadIdentifier> audio_thread_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.cc
index 099e5ce64be..0e8c1bf89ed 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.cc
@@ -101,7 +101,7 @@ void DynamicsCompressorHandler::Process(uint32_t frames_to_process) {
float reduction =
dynamics_compressor_->ParameterValue(DynamicsCompressor::kParamReduction);
- NoBarrierStore(&reduction_, reduction);
+ reduction_.store(reduction, std::memory_order_relaxed);
}
void DynamicsCompressorHandler::ProcessOnlyAudioParams(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.h b/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.h
index a4f681a96c4..452b320feb8 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_DYNAMICS_COMPRESSOR_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_DYNAMICS_COMPRESSOR_NODE_H_
+#include <atomic>
#include <memory>
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -56,7 +57,9 @@ class MODULES_EXPORT DynamicsCompressorHandler final : public AudioHandler {
void ProcessOnlyAudioParams(uint32_t frames_to_process) override;
void Initialize() override;
- float ReductionValue() const { return NoBarrierLoad(&reduction_); }
+ float ReductionValue() const {
+ return reduction_.load(std::memory_order_relaxed);
+ }
void SetChannelCount(unsigned, ExceptionState&) final;
void SetChannelCountMode(const String&, ExceptionState&) final;
@@ -77,7 +80,7 @@ class MODULES_EXPORT DynamicsCompressorHandler final : public AudioHandler {
scoped_refptr<AudioParamHandler> threshold_;
scoped_refptr<AudioParamHandler> knee_;
scoped_refptr<AudioParamHandler> ratio_;
- float reduction_;
+ std::atomic<float> reduction_;
scoped_refptr<AudioParamHandler> attack_;
scoped_refptr<AudioParamHandler> release_;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
index e854d861998..306368f492d 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
@@ -135,6 +135,14 @@ void OfflineAudioDestinationHandler::StopRendering() {
NOTREACHED();
}
+void OfflineAudioDestinationHandler::Pause() {
+ NOTREACHED();
+}
+
+void OfflineAudioDestinationHandler::Resume() {
+ NOTREACHED();
+}
+
void OfflineAudioDestinationHandler::InitializeOfflineRenderThread(
AudioBuffer* render_target) {
DCHECK(IsMainThread());
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h
index df9ffd4edb5..dc225454d7d 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h
@@ -62,6 +62,8 @@ class OfflineAudioDestinationHandler final : public AudioDestinationHandler {
// AudioDestinationHandler
void StartRendering() override;
void StopRendering() override;
+ void Pause() override;
+ void Resume() override;
uint32_t MaxChannelCount() const override;
void RestartRendering() override;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.cc b/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.cc
index d99e2f78af3..8f6cff42bf8 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.cc
@@ -220,7 +220,7 @@ unsigned PeriodicWave::NumberOfPartialsForRange(unsigned range_index) const {
// Tell V8 about the memory we're using so it can properly schedule garbage
// collects.
-void PeriodicWave::AdjustV8ExternalMemory(int delta) {
+void PeriodicWave::AdjustV8ExternalMemory(int64_t delta) {
v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(delta);
v8_external_memory_ += delta;
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.h b/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.h
index 685213fefbd..34f9fbb0a85 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.h
@@ -111,7 +111,7 @@ class PeriodicWave final : public ScriptWrappable {
unsigned NumberOfPartialsForRange(unsigned range_index) const;
- void AdjustV8ExternalMemory(int delta);
+ void AdjustV8ExternalMemory(int64_t delta);
// Creates tables based on numberOfComponents Fourier coefficients.
void CreateBandLimitedTables(const float* real,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.cc b/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.cc
index dbcee692acf..9d586951bf9 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.cc
@@ -48,7 +48,6 @@ const unsigned RealtimeAnalyser::kInputBufferSize =
RealtimeAnalyser::RealtimeAnalyser()
: input_buffer_(kInputBufferSize),
- write_index_(0),
down_mix_bus_(AudioBus::Create(1, audio_utilities::kRenderQuantumFrames)),
fft_size_(kDefaultFFTSize),
magnitude_buffer_(kDefaultFFTSize / 2),
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.h b/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.h
index 9bd21a25363..9918da490e7 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/realtime_analyser.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_REALTIME_ANALYSER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_REALTIME_ANALYSER_H_
+#include <atomic>
#include <memory>
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/platform/audio/audio_array.h"
@@ -77,11 +78,13 @@ class RealtimeAnalyser final {
private:
// The audio thread writes the input audio here.
AudioFloatArray input_buffer_;
- unsigned write_index_;
+ std::atomic_uint write_index_{0};
- unsigned GetWriteIndex() const { return AcquireLoad(&write_index_); }
+ unsigned GetWriteIndex() const {
+ return write_index_.load(std::memory_order_acquire);
+ }
void SetWriteIndex(unsigned new_index) {
- ReleaseStore(&write_index_, new_index);
+ write_index_.store(new_index, std::memory_order_release);
}
// Input audio is downmixed to this bus before copying to m_inputBuffer.
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
index 5c81ddbfaf1..0a2f754abf1 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
@@ -46,9 +46,9 @@ namespace blink {
ScriptProcessorHandler::ScriptProcessorHandler(
AudioNode& node,
float sample_rate,
- size_t buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels)
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels)
: AudioHandler(kNodeTypeScriptProcessor, node, sample_rate),
double_buffer_index_(0),
input_buffers_(MakeGarbageCollected<HeapVector<Member<AudioBuffer>>>()),
@@ -85,9 +85,9 @@ ScriptProcessorHandler::ScriptProcessorHandler(
scoped_refptr<ScriptProcessorHandler> ScriptProcessorHandler::Create(
AudioNode& node,
float sample_rate,
- size_t buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels) {
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels) {
return base::AdoptRef(new ScriptProcessorHandler(
node, sample_rate, buffer_size, number_of_input_channels,
number_of_output_channels));
@@ -106,7 +106,7 @@ void ScriptProcessorHandler::Initialize() {
// Create double buffers on both the input and output sides.
// These AudioBuffers will be directly accessed in the main thread by
// JavaScript.
- for (unsigned i = 0; i < 2; ++i) {
+ for (uint32_t i = 0; i < 2; ++i) {
AudioBuffer* input_buffer =
number_of_input_channels_
? AudioBuffer::Create(number_of_input_channels_, BufferSize(),
@@ -140,7 +140,7 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
// Get input and output buffers. We double-buffer both the input and output
// sides.
- unsigned double_buffer_index = this->DoubleBufferIndex();
+ uint32_t double_buffer_index = this->DoubleBufferIndex();
bool is_double_buffer_index_good =
double_buffer_index < 2 && double_buffer_index < input_buffers_->size() &&
double_buffer_index < output_buffers_->size();
@@ -152,7 +152,7 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
AudioBuffer* output_buffer = output_buffers_->at(double_buffer_index).Get();
// Check the consistency of input and output buffers.
- unsigned number_of_input_channels = internal_input_bus_->NumberOfChannels();
+ uint32_t number_of_input_channels = internal_input_bus_->NumberOfChannels();
bool buffers_are_good =
output_buffer && BufferSize() == output_buffer->length() &&
buffer_read_write_index_ + frames_to_process <= BufferSize();
@@ -175,7 +175,7 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
if (!is_frames_to_process_good)
return;
- unsigned number_of_output_channels = output_bus->NumberOfChannels();
+ uint32_t number_of_output_channels = output_bus->NumberOfChannels();
bool channels_are_good =
(number_of_input_channels == number_of_input_channels_) &&
@@ -184,7 +184,7 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
if (!channels_are_good)
return;
- for (unsigned i = 0; i < number_of_input_channels; ++i)
+ for (uint32_t i = 0; i < number_of_input_channels; ++i)
internal_input_bus_->SetChannelMemory(
i,
input_buffer->getChannelData(i).View()->Data() +
@@ -195,7 +195,7 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
internal_input_bus_->CopyFrom(*input_bus);
// Copy from the output buffer to the output.
- for (unsigned i = 0; i < number_of_output_channels; ++i) {
+ for (uint32_t i = 0; i < number_of_output_channels; ++i) {
memcpy(output_bus->Channel(i)->MutableData(),
output_buffer->getChannelData(i).View()->Data() +
buffer_read_write_index_,
@@ -253,7 +253,7 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
}
}
-void ScriptProcessorHandler::FireProcessEvent(unsigned double_buffer_index) {
+void ScriptProcessorHandler::FireProcessEvent(uint32_t double_buffer_index) {
DCHECK(IsMainThread());
if (!Context() || !Context()->GetExecutionContext())
@@ -288,7 +288,7 @@ void ScriptProcessorHandler::FireProcessEvent(unsigned double_buffer_index) {
}
void ScriptProcessorHandler::FireProcessEventForOfflineAudioContext(
- unsigned double_buffer_index,
+ uint32_t double_buffer_index,
WaitableEvent* waitable_event) {
DCHECK(IsMainThread());
@@ -334,7 +334,7 @@ double ScriptProcessorHandler::LatencyTime() const {
return std::numeric_limits<double>::infinity();
}
-void ScriptProcessorHandler::SetChannelCount(unsigned channel_count,
+void ScriptProcessorHandler::SetChannelCount(uint32_t channel_count,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
BaseAudioContext::GraphAutoLocker locker(Context());
@@ -365,22 +365,22 @@ void ScriptProcessorHandler::SetChannelCountMode(
ScriptProcessorNode::ScriptProcessorNode(BaseAudioContext& context,
float sample_rate,
- size_t buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels)
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels)
: AudioNode(context) {
SetHandler(ScriptProcessorHandler::Create(*this, sample_rate, buffer_size,
number_of_input_channels,
number_of_output_channels));
}
-static size_t ChooseBufferSize(size_t callback_buffer_size) {
+static uint32_t ChooseBufferSize(uint32_t callback_buffer_size) {
// Choose a buffer size based on the audio hardware buffer size. Arbitarily
// make it a power of two that is 4 times greater than the hardware buffer
// size.
// TODO(crbug.com/855758): What is the best way to choose this?
- size_t buffer_size =
- 1 << static_cast<unsigned>(log2(4 * callback_buffer_size) + 0.5);
+ uint32_t buffer_size =
+ 1 << static_cast<uint32_t>(log2(4 * callback_buffer_size) + 0.5);
if (buffer_size < 256)
return 256;
@@ -402,7 +402,7 @@ ScriptProcessorNode* ScriptProcessorNode::Create(
ScriptProcessorNode* ScriptProcessorNode::Create(
BaseAudioContext& context,
- size_t requested_buffer_size,
+ uint32_t requested_buffer_size,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -412,8 +412,8 @@ ScriptProcessorNode* ScriptProcessorNode::Create(
ScriptProcessorNode* ScriptProcessorNode::Create(
BaseAudioContext& context,
- size_t requested_buffer_size,
- unsigned number_of_input_channels,
+ uint32_t requested_buffer_size,
+ uint32_t number_of_input_channels,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -424,9 +424,9 @@ ScriptProcessorNode* ScriptProcessorNode::Create(
ScriptProcessorNode* ScriptProcessorNode::Create(
BaseAudioContext& context,
- size_t requested_buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels,
+ uint32_t requested_buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
@@ -461,7 +461,7 @@ ScriptProcessorNode* ScriptProcessorNode::Create(
}
// Sanitize user-supplied buffer size.
- size_t buffer_size;
+ uint32_t buffer_size;
switch (requested_buffer_size) {
case 0:
// Choose an appropriate size. For an AudioContext, we need to
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h
index 04161593dc1..11a7936a2e5 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h
@@ -54,52 +54,52 @@ class ScriptProcessorHandler final : public AudioHandler {
static scoped_refptr<ScriptProcessorHandler> Create(
AudioNode&,
float sample_rate,
- size_t buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels);
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels);
~ScriptProcessorHandler() override;
// AudioHandler
void Process(uint32_t frames_to_process) override;
void Initialize() override;
- uint32_t BufferSize() const { return static_cast<uint32_t>(buffer_size_); }
+ uint32_t BufferSize() const { return buffer_size_; }
- void SetChannelCount(unsigned, ExceptionState&) override;
+ void SetChannelCount(uint32_t, ExceptionState&) override;
void SetChannelCountMode(const String&, ExceptionState&) override;
- unsigned NumberOfOutputChannels() const override {
+ uint32_t NumberOfOutputChannels() const override {
return number_of_output_channels_;
}
private:
ScriptProcessorHandler(AudioNode&,
float sample_rate,
- size_t buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels);
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels);
double TailTime() const override;
double LatencyTime() const override;
bool RequiresTailProcessing() const final;
- void FireProcessEvent(unsigned);
- void FireProcessEventForOfflineAudioContext(unsigned, WaitableEvent*);
+ void FireProcessEvent(uint32_t);
+ void FireProcessEventForOfflineAudioContext(uint32_t, WaitableEvent*);
// Double buffering
- unsigned DoubleBufferIndex() const { return double_buffer_index_; }
+ uint32_t DoubleBufferIndex() const { return double_buffer_index_; }
void SwapBuffers() { double_buffer_index_ = 1 - double_buffer_index_; }
- unsigned double_buffer_index_;
+ uint32_t double_buffer_index_;
// These Persistent don't make reference cycles including the owner
// ScriptProcessorNode.
CrossThreadPersistent<HeapVector<Member<AudioBuffer>>> input_buffers_;
CrossThreadPersistent<HeapVector<Member<AudioBuffer>>> output_buffers_;
- size_t buffer_size_;
- unsigned buffer_read_write_index_;
+ uint32_t buffer_size_;
+ uint32_t buffer_read_write_index_;
- unsigned number_of_input_channels_;
- unsigned number_of_output_channels_;
+ uint32_t number_of_input_channels_;
+ uint32_t number_of_output_channels_;
scoped_refptr<AudioBus> internal_input_bus_;
// Synchronize process() with fireProcessEvent().
@@ -127,23 +127,23 @@ class ScriptProcessorNode final
// The value chosen must carefully balance between latency and audio quality.
static ScriptProcessorNode* Create(BaseAudioContext&, ExceptionState&);
static ScriptProcessorNode* Create(BaseAudioContext&,
- size_t requested_buffer_size,
+ uint32_t requested_buffer_size,
ExceptionState&);
static ScriptProcessorNode* Create(BaseAudioContext&,
- size_t requested_buffer_size,
- unsigned number_of_input_channels,
+ uint32_t requested_buffer_size,
+ uint32_t number_of_input_channels,
ExceptionState&);
static ScriptProcessorNode* Create(BaseAudioContext&,
- size_t requested_buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels,
+ uint32_t requested_buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels,
ExceptionState&);
ScriptProcessorNode(BaseAudioContext&,
float sample_rate,
- size_t buffer_size,
- unsigned number_of_input_channels,
- unsigned number_of_output_channels);
+ uint32_t buffer_size,
+ uint32_t number_of_input_channels,
+ uint32_t number_of_output_channels);
DEFINE_ATTRIBUTE_EVENT_LISTENER(audioprocess, kAudioprocess);
uint32_t bufferSize() const;
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/change_version_wrapper.h b/chromium/third_party/blink/renderer/modules/webdatabase/change_version_wrapper.h
index e071e80ffe7..f7c9896052b 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/change_version_wrapper.h
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/change_version_wrapper.h
@@ -41,17 +41,17 @@ class ChangeVersionWrapper final : public SQLTransactionWrapper {
public:
static ChangeVersionWrapper* Create(const String& old_version,
const String& new_version) {
- return new ChangeVersionWrapper(old_version, new_version);
+ return MakeGarbageCollected<ChangeVersionWrapper>(old_version, new_version);
}
+ ChangeVersionWrapper(const String& old_version, const String& new_version);
+
bool PerformPreflight(SQLTransactionBackend*) override;
bool PerformPostflight(SQLTransactionBackend*) override;
SQLErrorData* SqlError() const override { return sql_error_.get(); }
void HandleCommitFailedAfterPostflight(SQLTransactionBackend*) override;
private:
- ChangeVersionWrapper(const String& old_version, const String& new_version);
-
String old_version_;
String new_version_;
std::unique_ptr<SQLErrorData> sql_error_;
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database.cc
index dc8fcd38ba6..999d4bc666a 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/database.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/database.cc
@@ -53,7 +53,6 @@
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/waitable_event.h"
-#include "third_party/blink/renderer/platform/wtf/atomics.h"
// Registering "opened" databases with the DatabaseTracker
// =======================================================
@@ -225,7 +224,7 @@ Database::Database(DatabaseContext* database_context,
display_name_(display_name.IsolatedCopy()),
estimated_size_(estimated_size),
guid_(0),
- opened_(0),
+ opened_(false),
new_(false),
transaction_in_progress_(false),
is_transaction_queue_enabled_(true) {
@@ -266,7 +265,7 @@ Database::~Database() {
// DatabaseContext::stopDatabases()). By the time we get here, the SQLite
// database should have already been closed.
- DCHECK(!opened_);
+ DCHECK(!Opened());
}
void Database::Trace(blink::Visitor* visitor) {
@@ -411,10 +410,10 @@ const char* Database::DatabaseInfoTableName() {
}
void Database::CloseDatabase() {
- if (!opened_)
+ if (!opened_.load(std::memory_order_relaxed))
return;
- ReleaseStore(&opened_, 0);
+ opened_.store(false, std::memory_order_release);
sqlite_database_.Close();
// See comment at the top this file regarding calling removeOpenDatabase().
DatabaseTracker::Tracker().RemoveOpenDatabase(this);
@@ -590,7 +589,7 @@ bool Database::PerformOpenAndVerify(bool should_set_version_in_new_database,
// See comment at the top this file regarding calling addOpenDatabase().
DatabaseTracker::Tracker().AddOpenDatabase(this);
- opened_ = 1;
+ opened_.store(true, std::memory_order_release);
// Declare success:
error = DatabaseError::kNone; // Clear the presumed error from above.
@@ -924,10 +923,6 @@ const SecurityOrigin* Database::GetSecurityOrigin() const {
return nullptr;
}
-bool Database::Opened() {
- return static_cast<bool>(AcquireLoad(&opened_));
-}
-
base::SingleThreadTaskRunner* Database::GetDatabaseTaskRunner() const {
return database_task_runner_.get();
}
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database.h b/chromium/third_party/blink/renderer/modules/webdatabase/database.h
index f01a6852d61..48841e09c79 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/database.h
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/database.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBDATABASE_DATABASE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBDATABASE_DATABASE_H_
+#include <atomic>
#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_database_callback.h"
#include "third_party/blink/renderer/modules/webdatabase/database_basic_types.h"
@@ -94,7 +95,7 @@ class Database final : public ScriptWrappable {
SQLTransaction::OnErrorCallback*,
SQLTransaction::OnSuccessCallback*);
- bool Opened();
+ bool Opened() { return opened_.load(std::memory_order_acquire); }
bool IsNew() const { return new_; }
const SecurityOrigin* GetSecurityOrigin() const;
@@ -181,7 +182,11 @@ class Database final : public ScriptWrappable {
String filename_;
DatabaseGuid guid_;
- int opened_;
+
+ // Atomically written from the database thread only, but read from multiple
+ // threads.
+ std::atomic_bool opened_;
+
bool new_;
SQLiteDatabase sqlite_database_;
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.cc b/chromium/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.cc
index b28ced3c07a..4e21c51e09e 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.cc
@@ -84,9 +84,12 @@ class StatementCallback final : public SQLStatement::OnSuccessCallback {
public:
static StatementCallback* Create(
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback) {
- return new StatementCallback(std::move(request_callback));
+ return MakeGarbageCollected<StatementCallback>(std::move(request_callback));
}
+ explicit StatementCallback(
+ scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
+ : request_callback_(std::move(request_callback)) {}
~StatementCallback() override = default;
bool OnSuccess(SQLTransaction*, SQLResultSet* result_set) override {
@@ -122,10 +125,6 @@ class StatementCallback final : public SQLStatement::OnSuccessCallback {
}
private:
- explicit StatementCallback(
- scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
- : request_callback_(std::move(request_callback)) {}
-
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
};
@@ -133,9 +132,13 @@ class StatementErrorCallback final : public SQLStatement::OnErrorCallback {
public:
static StatementErrorCallback* Create(
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback) {
- return new StatementErrorCallback(std::move(request_callback));
+ return MakeGarbageCollected<StatementErrorCallback>(
+ std::move(request_callback));
}
+ explicit StatementErrorCallback(
+ scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
+ : request_callback_(std::move(request_callback)) {}
~StatementErrorCallback() override = default;
bool OnError(SQLTransaction*, SQLError* error) override {
@@ -144,10 +147,6 @@ class StatementErrorCallback final : public SQLStatement::OnErrorCallback {
}
private:
- explicit StatementErrorCallback(
- scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
- : request_callback_(std::move(request_callback)) {}
-
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
};
@@ -156,9 +155,15 @@ class TransactionCallback final : public SQLTransaction::OnProcessCallback {
static TransactionCallback* Create(
const String& sql_statement,
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback) {
- return new TransactionCallback(sql_statement, std::move(request_callback));
+ return MakeGarbageCollected<TransactionCallback>(
+ sql_statement, std::move(request_callback));
}
+ explicit TransactionCallback(
+ const String& sql_statement,
+ scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
+ : sql_statement_(sql_statement),
+ request_callback_(std::move(request_callback)) {}
~TransactionCallback() override = default;
bool OnProcess(SQLTransaction* transaction) override {
@@ -171,12 +176,6 @@ class TransactionCallback final : public SQLTransaction::OnProcessCallback {
}
private:
- explicit TransactionCallback(
- const String& sql_statement,
- scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
- : sql_statement_(sql_statement),
- request_callback_(std::move(request_callback)) {}
-
String sql_statement_;
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
};
@@ -185,9 +184,13 @@ class TransactionErrorCallback final : public SQLTransaction::OnErrorCallback {
public:
static TransactionErrorCallback* Create(
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback) {
- return new TransactionErrorCallback(std::move(request_callback));
+ return MakeGarbageCollected<TransactionErrorCallback>(
+ std::move(request_callback));
}
+ explicit TransactionErrorCallback(
+ scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
+ : request_callback_(std::move(request_callback)) {}
~TransactionErrorCallback() override = default;
bool OnError(SQLError* error) override {
@@ -196,10 +199,6 @@ class TransactionErrorCallback final : public SQLTransaction::OnErrorCallback {
}
private:
- explicit TransactionErrorCallback(
- scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
- : request_callback_(std::move(request_callback)) {}
-
scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.cc b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.cc
index b2fb0e7bdd4..a5ba0fe510c 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.cc
@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/modules/webdatabase/sql_transaction.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/modules/webdatabase/database.h"
#include "third_party/blink/renderer/modules/webdatabase/database_authorizer.h"
@@ -152,7 +153,7 @@ SQLTransaction::StateFunction SQLTransaction::StateFunctionFor(
&SQLTransaction::DeliverSuccessCallback // 12.
};
- DCHECK(arraysize(kStateFunctions) ==
+ DCHECK(base::size(kStateFunctions) ==
static_cast<int>(SQLTransactionState::kNumberOfStates));
DCHECK(state < SQLTransactionState::kNumberOfStates);
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_backend.cc b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_backend.cc
index 11ef20ccd07..fbd78bc7962 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_backend.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_backend.cc
@@ -29,6 +29,8 @@
#include "third_party/blink/renderer/modules/webdatabase/sql_transaction_backend.h"
#include <memory>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/modules/webdatabase/database.h"
#include "third_party/blink/renderer/modules/webdatabase/database_authorizer.h"
#include "third_party/blink/renderer/modules/webdatabase/database_context.h"
@@ -491,7 +493,7 @@ SQLTransactionBackend::StateFunction SQLTransactionBackend::StateFunctionFor(
&SQLTransactionBackend::SendToFrontendState,
};
- DCHECK(arraysize(kStateFunctions) ==
+ DCHECK(base::size(kStateFunctions) ==
static_cast<int>(SQLTransactionState::kNumberOfStates));
DCHECK_LT(state, SQLTransactionState::kNumberOfStates);
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
index ae8ea1994f3..c442185a8c0 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
@@ -81,6 +81,19 @@ bool SQLiteDatabase::Open(const String& filename) {
return false;
}
+ // Defensive mode is a layer of defense in depth for applications that must
+ // run SQL queries from an untrusted source, such as WebDatabase. Refuse to
+ // proceed if this layer cannot be enabled.
+ open_error_ = sqlite3_db_config(db_, SQLITE_DBCONFIG_DEFENSIVE, 1, nullptr);
+ if (open_error_ != SQLITE_OK) {
+ open_error_message_ = sqlite3_errmsg(db_);
+ DLOG(ERROR) << "SQLite database error when enabling defensive mode - "
+ << open_error_message_.data();
+ sqlite3_close(db_);
+ db_ = nullptr;
+ return false;
+ }
+
if (IsOpen())
opening_thread_ = CurrentThread();
else
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc
index fac805a93f0..faf6cac227a 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc
@@ -102,7 +102,7 @@ int SQLiteStatement::Prepare() {
// Pass the length of the string including the null character to
// sqlite3_prepare_v2; this lets SQLite avoid an extra string copy.
- size_t length_including_null_character = query.length() + 1;
+ wtf_size_t length_including_null_character = query.length() + 1;
error = sqlite3_prepare_v2(database_.Sqlite3Handle(), query.data(),
length_including_null_character, statement.get(),
diff --git a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
index db785e23255..24619b5376d 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
@@ -89,6 +89,12 @@ blink_modules_sources("webgl") {
"webgl_framebuffer.h",
"webgl_lose_context.cc",
"webgl_lose_context.h",
+ "webgl_multi_draw.cc",
+ "webgl_multi_draw.h",
+ "webgl_multi_draw_common.cc",
+ "webgl_multi_draw_common.h",
+ "webgl_multi_draw_instanced.cc",
+ "webgl_multi_draw_instanced.h",
"webgl_multiview.cc",
"webgl_multiview.h",
"webgl_object.cc",
diff --git a/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.cc b/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.cc
index 2499a82d6de..29f14d52b24 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.cc
@@ -46,7 +46,7 @@ WebGLExtensionName ANGLEInstancedArrays::GetName() const {
ANGLEInstancedArrays* ANGLEInstancedArrays::Create(
WebGLRenderingContextBase* context) {
- return new ANGLEInstancedArrays(context);
+ return MakeGarbageCollected<ANGLEInstancedArrays>(context);
}
bool ANGLEInstancedArrays::Supported(WebGLRenderingContextBase* context) {
diff --git a/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h b/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h
index f90bbcd743c..859a34ab7f0 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h
@@ -44,6 +44,8 @@ class ANGLEInstancedArrays final : public WebGLExtension {
static bool Supported(WebGLRenderingContextBase*);
static const char* ExtensionName();
+ explicit ANGLEInstancedArrays(WebGLRenderingContextBase*);
+
WebGLExtensionName GetName() const override;
void drawArraysInstancedANGLE(GLenum mode,
@@ -56,9 +58,6 @@ class ANGLEInstancedArrays final : public WebGLExtension {
long long offset,
GLsizei primcount);
void vertexAttribDivisorANGLE(GLuint index, GLuint divisor);
-
- private:
- explicit ANGLEInstancedArrays(WebGLRenderingContextBase*);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
index 4be645fb90e..c671a2a7776 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
@@ -49,7 +49,7 @@ void EXTDisjointTimerQuery::deleteQueryEXT(WebGLTimerQueryEXT* query) {
GLboolean EXTDisjointTimerQuery::isQueryEXT(WebGLTimerQueryEXT* query) {
WebGLExtensionScopedContext scoped(this);
- if (!query || scoped.IsLost() || query->IsDeleted() ||
+ if (!query || scoped.IsLost() || query->MarkedForDeletion() ||
!query->Validate(nullptr, scoped.Context())) {
return false;
}
@@ -63,12 +63,8 @@ void EXTDisjointTimerQuery::beginQueryEXT(GLenum target,
if (scoped.IsLost())
return;
- DCHECK(query);
- if (query->IsDeleted() || !query->Validate(nullptr, scoped.Context())) {
- scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, "beginQueryEXT",
- "invalid query");
+ if (!scoped.Context()->ValidateWebGLObject("beginQueryEXT", query))
return;
- }
if (target != GL_TIME_ELAPSED_EXT) {
scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "beginQueryEXT",
@@ -121,12 +117,8 @@ void EXTDisjointTimerQuery::queryCounterEXT(WebGLTimerQueryEXT* query,
if (scoped.IsLost())
return;
- DCHECK(query);
- if (query->IsDeleted() || !query->Validate(nullptr, scoped.Context())) {
- scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, "queryCounterEXT",
- "invalid query");
+ if (!scoped.Context()->ValidateWebGLObject("queryCounterEXT", query))
return;
- }
if (target != GL_TIMESTAMP_EXT) {
scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "queryCounterEXT",
@@ -186,11 +178,12 @@ ScriptValue EXTDisjointTimerQuery::getQueryObjectEXT(ScriptState* script_state,
if (scoped.IsLost())
return ScriptValue::CreateNull(script_state);
- DCHECK(query);
- if (query->IsDeleted() || !query->Validate(nullptr, scoped.Context()) ||
- current_elapsed_query_ == query) {
- scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION,
- "getQueryObjectEXT", "invalid query");
+ if (!scoped.Context()->ValidateWebGLObject("getQueryObjectEXT", query))
+ return ScriptValue::CreateNull(script_state);
+
+ if (current_elapsed_query_ == query) {
+ scoped.Context()->SynthesizeGLError(
+ GL_INVALID_OPERATION, "getQueryObjectEXT", "query is currently active");
return ScriptValue::CreateNull(script_state);
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc
index 8eba91c82ee..7e94d11109b 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc
@@ -37,13 +37,8 @@ void EXTDisjointTimerQueryWebGL2::queryCounterEXT(WebGLQuery* query,
if (scoped.IsLost())
return;
- DCHECK(query);
- if (query->IsDeleted() ||
- !query->Validate(scoped.Context()->ContextGroup(), scoped.Context())) {
- scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, "queryCounterEXT",
- "invalid query");
+ if (!scoped.Context()->ValidateWebGLObject("queryCounterEXT", query))
return;
- }
if (target != GL_TIMESTAMP_EXT) {
scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "queryCounterEXT",
diff --git a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc
index 649ee4bee7f..a2ea7c564d9 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc
@@ -44,7 +44,7 @@ WebGLExtensionName KHRParallelShaderCompile::GetName() const {
KHRParallelShaderCompile* KHRParallelShaderCompile::Create(
WebGLRenderingContextBase* context) {
- return new KHRParallelShaderCompile(context);
+ return MakeGarbageCollected<KHRParallelShaderCompile>(context);
}
void KHRParallelShaderCompile::maxShaderCompilerThreadsKHR(GLuint count) {
diff --git a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h
index e777123fa9c..0288610181f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h
@@ -42,7 +42,6 @@ class KHRParallelShaderCompile final : public WebGLExtension {
void maxShaderCompilerThreadsKHR(GLuint count);
- private:
explicit KHRParallelShaderCompile(WebGLRenderingContextBase*);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc b/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc
index 359498a4841..bdb1fd9369b 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc
@@ -77,6 +77,8 @@ GLboolean OESVertexArrayObject::isVertexArrayOES(
if (!array_object->HasEverBeenBound())
return 0;
+ if (array_object->MarkedForDeletion())
+ return 0;
return scoped.Context()->ContextGL()->IsVertexArrayOES(
array_object->Object());
@@ -88,12 +90,9 @@ void OESVertexArrayObject::bindVertexArrayOES(
if (scoped.IsLost())
return;
- if (array_object && (array_object->IsDeleted() ||
- !array_object->Validate(nullptr, scoped.Context()))) {
- scoped.Context()->SynthesizeGLError(
- GL_INVALID_OPERATION, "bindVertexArrayOES", "invalid arrayObject");
+ if (!scoped.Context()->ValidateNullableWebGLObject(
+ "OESVertexArrayObject.bindVertexArrayOES", array_object))
return;
- }
if (array_object && !array_object->IsDefaultObject() &&
array_object->Object()) {
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl
index 031802e5a98..1c8ac283f5e 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl
@@ -32,7 +32,7 @@
const unsigned long VERTEX_ARRAY_BINDING_OES = 0x85B5;
WebGLVertexArrayObjectOES createVertexArrayOES();
- void deleteVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES? arrayObject);
- boolean isVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES? arrayObject);
- void bindVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES? arrayObject);
+ void deleteVertexArrayOES([DefaultValue=Undefined] optional WebGLVertexArrayObjectOES? arrayObject);
+ boolean isVertexArrayOES([DefaultValue=Undefined] optional WebGLVertexArrayObjectOES? arrayObject);
+ void bindVertexArrayOES([DefaultValue=Undefined] optional WebGLVertexArrayObjectOES? arrayObject);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
index 198f039622d..5c581a1772b 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
@@ -30,6 +30,8 @@
#include "third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.h"
#include "third_party/blink/renderer/modules/webgl/webgl_debug_shaders.h"
#include "third_party/blink/renderer/modules/webgl/webgl_lose_context.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h"
#include "third_party/blink/renderer/modules/webgl/webgl_multiview.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
@@ -138,6 +140,9 @@ void WebGL2RenderingContext::RegisterContextExtensions() {
RegisterExtension<WebGLDebugRendererInfo>(webgl_debug_renderer_info_);
RegisterExtension<WebGLDebugShaders>(webgl_debug_shaders_);
RegisterExtension<WebGLLoseContext>(webgl_lose_context_);
+ RegisterExtension<WebGLMultiDraw>(webgl_multi_draw_, kDraftExtension);
+ RegisterExtension<WebGLMultiDrawInstanced>(webgl_multi_draw_instanced_,
+ kDraftExtension);
RegisterExtension<WebGLMultiview>(webgl_multiview_, kDraftExtension);
}
@@ -156,6 +161,8 @@ void WebGL2RenderingContext::Trace(blink::Visitor* visitor) {
visitor->Trace(webgl_debug_renderer_info_);
visitor->Trace(webgl_debug_shaders_);
visitor->Trace(webgl_lose_context_);
+ visitor->Trace(webgl_multi_draw_);
+ visitor->Trace(webgl_multi_draw_instanced_);
visitor->Trace(webgl_multiview_);
WebGL2RenderingContextBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
index 18a4af61f3a..da68105ce49 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
@@ -17,6 +17,8 @@ class EXTTextureFilterAnisotropic;
class OESTextureFloatLinear;
class WebGLDebugRendererInfo;
class WebGLLoseContext;
+class WebGLMultiDraw;
+class WebGLMultiDrawInstanced;
class WebGLMultiview;
class KHRParallelShaderCompile;
@@ -72,6 +74,8 @@ class WebGL2RenderingContext : public WebGL2RenderingContextBase {
Member<WebGLDebugRendererInfo> webgl_debug_renderer_info_;
Member<WebGLDebugShaders> webgl_debug_shaders_;
Member<WebGLLoseContext> webgl_lose_context_;
+ Member<WebGLMultiDraw> webgl_multi_draw_;
+ Member<WebGLMultiDrawInstanced> webgl_multi_draw_instanced_;
Member<WebGLMultiview> webgl_multiview_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 3bd6dac474b..66d8748afc4 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -5,8 +5,10 @@
#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
#include <memory>
+
#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
@@ -41,8 +43,8 @@ const GLuint64 kMaxClientWaitTimeout = 0u;
// TODO(kainino): Change outByteLength to GLuint and change the associated
// range checking (and all uses) - overflow becomes possible in cases below
bool ValidateSubSourceAndGetData(DOMArrayBufferView* view,
- GLuint sub_offset,
- GLuint sub_length,
+ long long sub_offset,
+ long long sub_length,
void** out_base_address,
long long* out_byte_length) {
// This is guaranteed to be non-null by DOM.
@@ -149,7 +151,7 @@ WebGL2RenderingContextBase::WebGL2RenderingContextBase(
supported_internal_formats_storage_.insert(
kSupportedInternalFormatsStorage,
kSupportedInternalFormatsStorage +
- arraysize(kSupportedInternalFormatsStorage));
+ base::size(kSupportedInternalFormatsStorage));
}
void WebGL2RenderingContextBase::DestroyContext() {
@@ -243,7 +245,8 @@ void WebGL2RenderingContextBase::bufferData(
"srcOffset + length too large");
return;
}
- BufferDataImpl(target, sub_byte_length, sub_base_address, usage);
+ BufferDataImpl(target, static_cast<GLsizeiptr>(sub_byte_length),
+ sub_base_address, usage);
}
void WebGL2RenderingContextBase::bufferData(GLenum target,
@@ -267,7 +270,7 @@ void WebGL2RenderingContextBase::bufferData(
void WebGL2RenderingContextBase::bufferSubData(
GLenum target,
- GLintptr dst_byte_offset,
+ long long dst_byte_offset,
MaybeShared<DOMArrayBufferView> src_data,
GLuint src_offset,
GLuint length) {
@@ -281,7 +284,8 @@ void WebGL2RenderingContextBase::bufferSubData(
"srcOffset + length too large");
return;
}
- BufferSubDataImpl(target, dst_byte_offset, sub_byte_length, sub_base_address);
+ BufferSubDataImpl(target, dst_byte_offset,
+ static_cast<GLsizeiptr>(sub_byte_length), sub_base_address);
}
void WebGL2RenderingContextBase::bufferSubData(GLenum target,
@@ -371,13 +375,14 @@ void WebGL2RenderingContextBase::getBufferSubData(
}
void* mapped_data = ContextGL()->MapBufferRange(
- target, static_cast<GLintptr>(src_byte_offset), destination_byte_length,
- GL_MAP_READ_BIT);
+ target, static_cast<GLintptr>(src_byte_offset),
+ static_cast<GLsizeiptr>(destination_byte_length), GL_MAP_READ_BIT);
if (!mapped_data)
return;
- memcpy(destination_data_ptr, mapped_data, destination_byte_length);
+ memcpy(destination_data_ptr, mapped_data,
+ static_cast<size_t>(destination_byte_length));
ContextGL()->UnmapBuffer(target);
}
@@ -437,14 +442,11 @@ void WebGL2RenderingContextBase::framebufferTextureLayer(GLenum target,
WebGLTexture* texture,
GLint level,
GLint layer) {
- if (isContextLost() || !ValidateFramebufferFuncParameters(
- "framebufferTextureLayer", target, attachment))
- return;
- if (texture && !texture->Validate(ContextGroup(), this)) {
- SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTextureLayer",
- "texture does not belong to this context");
+ if (isContextLost() ||
+ !ValidateFramebufferFuncParameters("framebufferTextureLayer", target,
+ attachment) ||
+ !ValidateNullableWebGLObject("framebufferTextureLayer", texture))
return;
- }
GLenum textarget = texture ? texture->GetTarget() : 0;
if (texture) {
if (textarget != GL_TEXTURE_3D && textarget != GL_TEXTURE_2D_ARRAY) {
@@ -1058,7 +1060,7 @@ void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint border,
GLenum format,
GLenum type,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!ValidateTexture2DBinding("texImage2D", target))
@@ -1094,7 +1096,7 @@ void WebGL2RenderingContextBase::texSubImage2D(GLenum target,
GLsizei height,
GLenum format,
GLenum type,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!ValidateTexture2DBinding("texSubImage2D", target))
@@ -1743,7 +1745,7 @@ void WebGL2RenderingContextBase::texImage3D(GLenum target,
GLint border,
GLenum format,
GLenum type,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!ValidateTexture3DBinding("texImage3D", target))
@@ -1940,7 +1942,7 @@ void WebGL2RenderingContextBase::texSubImage3D(GLenum target,
GLsizei depth,
GLenum format,
GLenum type,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!ValidateTexture3DBinding("texSubImage3D", target))
@@ -2195,7 +2197,7 @@ void WebGL2RenderingContextBase::compressedTexImage2D(GLenum target,
GLsizei height,
GLint border,
GLsizei image_size,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
@@ -2277,7 +2279,7 @@ void WebGL2RenderingContextBase::compressedTexSubImage2D(GLenum target,
GLsizei height,
GLenum format,
GLsizei image_size,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
@@ -2339,7 +2341,7 @@ void WebGL2RenderingContextBase::compressedTexImage3D(GLenum target,
GLsizei depth,
GLint border,
GLsizei image_size,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
@@ -2405,7 +2407,7 @@ void WebGL2RenderingContextBase::compressedTexSubImage3D(GLenum target,
GLsizei depth,
GLenum format,
GLsizei image_size,
- GLintptr offset) {
+ long long offset) {
if (isContextLost())
return;
if (!bound_pixel_unpack_buffer_) {
@@ -2420,7 +2422,7 @@ void WebGL2RenderingContextBase::compressedTexSubImage3D(GLenum target,
GLint WebGL2RenderingContextBase::getFragDataLocation(WebGLProgram* program,
const String& name) {
- if (isContextLost() || !ValidateWebGLObject("getFragDataLocation", program))
+ if (!ValidateWebGLProgramOrShader("getFragDataLocation", program))
return -1;
return ContextGL()->GetFragDataLocation(ObjectOrZero(program),
@@ -3815,22 +3817,18 @@ void WebGL2RenderingContextBase::deleteQuery(WebGLQuery* query) {
}
GLboolean WebGL2RenderingContextBase::isQuery(WebGLQuery* query) {
- if (isContextLost() || !query)
+ if (!query || isContextLost() || !query->Validate(ContextGroup(), this))
+ return 0;
+
+ if (query->MarkedForDeletion())
return 0;
return ContextGL()->IsQueryEXT(query->Object());
}
void WebGL2RenderingContextBase::beginQuery(GLenum target, WebGLQuery* query) {
- bool deleted;
- DCHECK(query);
- if (!CheckObjectToBeBound("beginQuery", query, deleted))
+ if (!ValidateWebGLObject("beginQuery", query))
return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "beginQuery",
- "attempted to begin a deleted query object");
- return;
- }
if (query->GetTarget() && query->GetTarget() != target) {
SynthesizeGLError(GL_INVALID_OPERATION, "beginQuery",
@@ -3984,15 +3982,8 @@ ScriptValue WebGL2RenderingContextBase::getQueryParameter(
ScriptState* script_state,
WebGLQuery* query,
GLenum pname) {
- DCHECK(query);
- bool deleted;
- if (!CheckObjectToBeBound("getQueryParameter", query, deleted))
+ if (!ValidateWebGLObject("getQueryParameter", query))
return ScriptValue::CreateNull(script_state);
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "getQueryParameter",
- "attempted to access to a deleted query object");
- return ScriptValue::CreateNull(script_state);
- }
// Query is non-null at this point.
if (!query->GetTarget()) {
@@ -4046,7 +4037,10 @@ void WebGL2RenderingContextBase::deleteSampler(WebGLSampler* sampler) {
}
GLboolean WebGL2RenderingContextBase::isSampler(WebGLSampler* sampler) {
- if (isContextLost() || !sampler)
+ if (!sampler || isContextLost() || !sampler->Validate(ContextGroup(), this))
+ return 0;
+
+ if (sampler->MarkedForDeletion())
return 0;
return ContextGL()->IsSampler(sampler->Object());
@@ -4054,14 +4048,8 @@ GLboolean WebGL2RenderingContextBase::isSampler(WebGLSampler* sampler) {
void WebGL2RenderingContextBase::bindSampler(GLuint unit,
WebGLSampler* sampler) {
- bool deleted;
- if (!CheckObjectToBeBound("bindSampler", sampler, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindSampler",
- "attempted to bind a deleted sampler");
+ if (!ValidateNullableWebGLObject("bindSampler", sampler))
return;
- }
if (unit >= sampler_units_.size()) {
SynthesizeGLError(GL_INVALID_VALUE, "bindSampler",
@@ -4079,7 +4067,7 @@ void WebGL2RenderingContextBase::SamplerParameter(WebGLSampler* sampler,
GLfloat paramf,
GLint parami,
bool is_float) {
- if (isContextLost() || !ValidateWebGLObject("samplerParameter", sampler))
+ if (!ValidateWebGLObject("samplerParameter", sampler))
return;
GLint param;
@@ -4189,7 +4177,7 @@ ScriptValue WebGL2RenderingContextBase::getSamplerParameter(
ScriptState* script_state,
WebGLSampler* sampler,
GLenum pname) {
- if (isContextLost() || !ValidateWebGLObject("getSamplerParameter", sampler))
+ if (!ValidateWebGLObject("getSamplerParameter", sampler))
return ScriptValue::CreateNull(script_state);
switch (pname) {
@@ -4235,7 +4223,10 @@ WebGLSync* WebGL2RenderingContextBase::fenceSync(GLenum condition,
}
GLboolean WebGL2RenderingContextBase::isSync(WebGLSync* sync) {
- if (isContextLost() || !sync || !sync->Validate(ContextGroup(), this))
+ if (!sync || isContextLost() || !sync->Validate(ContextGroup(), this))
+ return 0;
+
+ if (sync->MarkedForDeletion())
return 0;
return sync->Object() != 0;
@@ -4248,7 +4239,7 @@ void WebGL2RenderingContextBase::deleteSync(WebGLSync* sync) {
GLenum WebGL2RenderingContextBase::clientWaitSync(WebGLSync* sync,
GLbitfield flags,
GLuint64 timeout) {
- if (isContextLost() || !ValidateWebGLObject("clientWaitSync", sync))
+ if (!ValidateWebGLObject("clientWaitSync", sync))
return GL_WAIT_FAILED;
if (timeout > kMaxClientWaitTimeout) {
@@ -4281,7 +4272,7 @@ GLenum WebGL2RenderingContextBase::clientWaitSync(WebGLSync* sync,
void WebGL2RenderingContextBase::waitSync(WebGLSync* sync,
GLbitfield flags,
GLint64 timeout) {
- if (isContextLost() || !ValidateWebGLObject("waitSync", sync))
+ if (!ValidateWebGLObject("waitSync", sync))
return;
if (flags) {
@@ -4301,7 +4292,7 @@ ScriptValue WebGL2RenderingContextBase::getSyncParameter(
ScriptState* script_state,
WebGLSync* sync,
GLenum pname) {
- if (isContextLost() || !ValidateWebGLObject("getSyncParameter", sync))
+ if (!ValidateWebGLObject("getSyncParameter", sync))
return ScriptValue::CreateNull(script_state);
switch (pname) {
@@ -4328,34 +4319,44 @@ WebGLTransformFeedback* WebGL2RenderingContextBase::createTransformFeedback() {
void WebGL2RenderingContextBase::deleteTransformFeedback(
WebGLTransformFeedback* feedback) {
+ // We have to short-circuit the deletion process if the transform feedback is
+ // active. This requires duplication of some validation logic.
+ if (!isContextLost() && feedback &&
+ feedback->Validate(ContextGroup(), this)) {
+ if (feedback->active()) {
+ SynthesizeGLError(
+ GL_INVALID_OPERATION, "deleteTransformFeedback",
+ "attempt to delete an active transform feedback object");
+ return;
+ }
+ }
+
+ if (!DeleteObject(feedback))
+ return;
+
if (feedback == transform_feedback_binding_)
transform_feedback_binding_ = default_transform_feedback_;
-
- DeleteObject(feedback);
}
GLboolean WebGL2RenderingContextBase::isTransformFeedback(
WebGLTransformFeedback* feedback) {
- if (isContextLost() || !feedback || !feedback->Validate(ContextGroup(), this))
+ if (!feedback || isContextLost() || !feedback->Validate(ContextGroup(), this))
return 0;
if (!feedback->HasEverBeenBound())
return 0;
+ if (feedback->MarkedForDeletion())
+ return 0;
+
return ContextGL()->IsTransformFeedback(feedback->Object());
}
void WebGL2RenderingContextBase::bindTransformFeedback(
GLenum target,
WebGLTransformFeedback* feedback) {
- bool deleted;
- if (!CheckObjectToBeBound("bindTransformFeedback", feedback, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindTransformFeedback",
- "attempted to bind a deleted transform feedback object");
+ if (!ValidateNullableWebGLObject("bindTransformFeedback", feedback))
return;
- }
if (target != GL_TRANSFORM_FEEDBACK) {
SynthesizeGLError(GL_INVALID_ENUM, "bindTransformFeedback",
@@ -4441,8 +4442,7 @@ void WebGL2RenderingContextBase::transformFeedbackVaryings(
WebGLProgram* program,
const Vector<String>& varyings,
GLenum buffer_mode) {
- if (isContextLost() ||
- !ValidateWebGLObject("transformFeedbackVaryings", program))
+ if (!ValidateWebGLProgramOrShader("transformFeedbackVaryings", program))
return;
switch (buffer_mode) {
@@ -4480,8 +4480,7 @@ void WebGL2RenderingContextBase::transformFeedbackVaryings(
WebGLActiveInfo* WebGL2RenderingContextBase::getTransformFeedbackVarying(
WebGLProgram* program,
GLuint index) {
- if (isContextLost() ||
- !ValidateWebGLObject("getTransformFeedbackVarying", program))
+ if (!ValidateWebGLProgramOrShader("getTransformFeedbackVarying", program))
return nullptr;
if (!program->LinkStatus(this)) {
@@ -4598,14 +4597,8 @@ void WebGL2RenderingContextBase::bindBufferBase(GLenum target,
WebGLBuffer* buffer) {
if (isContextLost())
return;
- bool deleted;
- if (!CheckObjectToBeBound("bindBufferBase", buffer, deleted))
+ if (!ValidateNullableWebGLObject("bindBufferBase", buffer))
return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase",
- "attempt to bind a deleted buffer");
- return;
- }
if (target == GL_TRANSFORM_FEEDBACK_BUFFER &&
transform_feedback_binding_->active()) {
SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase",
@@ -4626,14 +4619,8 @@ void WebGL2RenderingContextBase::bindBufferRange(GLenum target,
long long size) {
if (isContextLost())
return;
- bool deleted;
- if (!CheckObjectToBeBound("bindBufferRange", buffer, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferRange",
- "attempt to bind a deleted buffer");
+ if (!ValidateNullableWebGLObject("bindBufferRange", buffer))
return;
- }
if (target == GL_TRANSFORM_FEEDBACK_BUFFER &&
transform_feedback_binding_->active()) {
SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase",
@@ -4740,7 +4727,7 @@ Vector<GLuint> WebGL2RenderingContextBase::getUniformIndices(
WebGLProgram* program,
const Vector<String>& uniform_names) {
Vector<GLuint> result;
- if (isContextLost() || !ValidateWebGLObject("getUniformIndices", program))
+ if (!ValidateWebGLProgramOrShader("getUniformIndices", program))
return result;
Vector<CString> keep_alive; // Must keep these instances alive while looking
@@ -4762,7 +4749,7 @@ ScriptValue WebGL2RenderingContextBase::getActiveUniforms(
WebGLProgram* program,
const Vector<GLuint>& uniform_indices,
GLenum pname) {
- if (isContextLost() || !ValidateWebGLObject("getActiveUniforms", program))
+ if (!ValidateWebGLProgramOrShader("getActiveUniforms", program))
return ScriptValue::CreateNull(script_state);
enum ReturnType { kEnumType, kUnsignedIntType, kIntType, kBoolType };
@@ -4839,7 +4826,7 @@ ScriptValue WebGL2RenderingContextBase::getActiveUniforms(
GLuint WebGL2RenderingContextBase::getUniformBlockIndex(
WebGLProgram* program,
const String& uniform_block_name) {
- if (isContextLost() || !ValidateWebGLObject("getUniformBlockIndex", program))
+ if (!ValidateWebGLProgramOrShader("getUniformBlockIndex", program))
return 0;
if (!ValidateString("getUniformBlockIndex", uniform_block_name))
return 0;
@@ -4874,8 +4861,7 @@ ScriptValue WebGL2RenderingContextBase::getActiveUniformBlockParameter(
WebGLProgram* program,
GLuint uniform_block_index,
GLenum pname) {
- if (isContextLost() ||
- !ValidateWebGLObject("getActiveUniformBlockParameter", program))
+ if (!ValidateWebGLProgramOrShader("getActiveUniformBlockParameter", program))
return ScriptValue::CreateNull(script_state);
if (!ValidateUniformBlockIndex("getActiveUniformBlockParameter", program,
@@ -4922,8 +4908,7 @@ ScriptValue WebGL2RenderingContextBase::getActiveUniformBlockParameter(
String WebGL2RenderingContextBase::getActiveUniformBlockName(
WebGLProgram* program,
GLuint uniform_block_index) {
- if (isContextLost() ||
- !ValidateWebGLObject("getActiveUniformBlockName", program))
+ if (!ValidateWebGLProgramOrShader("getActiveUniformBlockName", program))
return String();
if (!ValidateUniformBlockIndex("getActiveUniformBlockName", program,
@@ -4956,7 +4941,7 @@ void WebGL2RenderingContextBase::uniformBlockBinding(
WebGLProgram* program,
GLuint uniform_block_index,
GLuint uniform_block_binding) {
- if (isContextLost() || !ValidateWebGLObject("uniformBlockBinding", program))
+ if (!ValidateWebGLProgramOrShader("uniformBlockBinding", program))
return;
if (!ValidateUniformBlockIndex("uniformBlockBinding", program,
@@ -4977,8 +4962,16 @@ WebGLVertexArrayObject* WebGL2RenderingContextBase::createVertexArray() {
void WebGL2RenderingContextBase::deleteVertexArray(
WebGLVertexArrayObject* vertex_array) {
- if (isContextLost() || !vertex_array ||
- !ValidateWebGLObject("deleteVertexArray", vertex_array))
+ // ValidateWebGLObject generates an error if the object has already been
+ // deleted, so we must replicate most of its checks here.
+ if (isContextLost() || !vertex_array)
+ return;
+ if (!vertex_array->Validate(ContextGroup(), this)) {
+ SynthesizeGLError(GL_INVALID_OPERATION, "deleteVertexArray",
+ "object does not belong to this context");
+ return;
+ }
+ if (vertex_array->MarkedForDeletion())
return;
if (!vertex_array->IsDefaultObject() &&
@@ -4996,20 +4989,16 @@ GLboolean WebGL2RenderingContextBase::isVertexArray(
if (!vertex_array->HasEverBeenBound())
return 0;
+ if (vertex_array->MarkedForDeletion())
+ return 0;
return ContextGL()->IsVertexArrayOES(vertex_array->Object());
}
void WebGL2RenderingContextBase::bindVertexArray(
WebGLVertexArrayObject* vertex_array) {
- bool deleted;
- if (!CheckObjectToBeBound("bindVertexArray", vertex_array, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindVertexArray",
- "attempt to bind a deleted vertex array");
+ if (!ValidateNullableWebGLObject("bindVertexArray", vertex_array))
return;
- }
if (vertex_array && !vertex_array->IsDefaultObject() &&
vertex_array->Object()) {
@@ -5025,16 +5014,9 @@ void WebGL2RenderingContextBase::bindVertexArray(
void WebGL2RenderingContextBase::bindFramebuffer(GLenum target,
WebGLFramebuffer* buffer) {
- bool deleted;
- if (!CheckObjectToBeBound("bindFramebuffer", buffer, deleted))
+ if (!ValidateNullableWebGLObject("bindFramebuffer", buffer))
return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindFramebuffer",
- "attempt to bind a deleted framebuffer");
- return;
- }
-
switch (target) {
case GL_DRAW_FRAMEBUFFER:
break;
@@ -5990,7 +5972,7 @@ bool WebGL2RenderingContextBase::ValidateBufferDataUsage(
const char* WebGL2RenderingContextBase::ValidateGetBufferSubData(
const char* function_name,
GLenum target,
- GLintptr source_byte_offset,
+ long long source_byte_offset,
DOMArrayBufferView* destination_array_buffer_view,
GLuint destination_offset,
GLuint length,
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
index f8e36e4b031..730aa33ffdf 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
@@ -35,7 +35,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLuint,
GLuint);
void bufferSubData(GLenum,
- GLintptr,
+ long long offset,
MaybeShared<DOMArrayBufferView>,
GLuint,
GLuint);
@@ -98,7 +98,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLint,
GLenum,
GLenum,
- GLintptr);
+ long long);
void texImage2D(GLenum,
GLint,
GLint,
@@ -170,7 +170,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLsizei,
GLenum,
GLenum,
- GLintptr);
+ long long);
void texSubImage2D(GLenum,
GLint,
GLint,
@@ -395,7 +395,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLint,
GLenum,
GLenum,
- GLintptr);
+ long long);
void texSubImage3D(GLenum,
GLint,
GLint,
@@ -418,7 +418,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLsizei,
GLenum,
GLenum,
- GLintptr);
+ long long);
void texSubImage3D(GLenum,
GLint,
GLint,
@@ -559,7 +559,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLsizei height,
GLint border,
GLsizei image_size,
- GLintptr offset);
+ long long offset);
void compressedTexSubImage2D(GLenum target,
GLint level,
GLint xoffset,
@@ -568,7 +568,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLsizei height,
GLenum format,
GLsizei image_size,
- GLintptr offset);
+ long long offset);
void compressedTexImage3D(GLenum target,
GLint level,
GLenum internalformat,
@@ -577,7 +577,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLsizei depth,
GLint border,
GLsizei image_size,
- GLintptr offset);
+ long long offset);
void compressedTexSubImage3D(GLenum target,
GLint level,
GLint xoffset,
@@ -588,7 +588,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLsizei depth,
GLenum format,
GLsizei image_size,
- GLintptr offset);
+ long long offset);
// Have to re-declare/re-define the following compressedTex{Sub}Image2D
// functions from the base class. This is because the above
@@ -1088,7 +1088,7 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
const char* ValidateGetBufferSubData(const char* function_name,
GLenum target,
- GLintptr source_byte_offset,
+ long long source_byte_offset,
DOMArrayBufferView*,
GLuint destination_offset,
GLuint length,
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc
index 22c765f1f0f..f74c2967be7 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
namespace blink {
@@ -32,7 +33,8 @@ WebGLCompressedTextureASTC::WebGLCompressedTextureASTC(
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR - GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
for (size_t i = 0;
- i < arraysize(WebGLCompressedTextureASTC::kBlockSizeCompressASTC); i++) {
+ i < base::size(WebGLCompressedTextureASTC::kBlockSizeCompressASTC);
+ i++) {
/* GL_COMPRESSED_RGBA_ASTC(0x93B0 ~ 0x93BD) */
context->AddCompressedTextureFormat(
WebGLCompressedTextureASTC::kBlockSizeCompressASTC[i].compress_type);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
index 121b0fd8726..7a74942ab1f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
#include "third_party/blink/renderer/core/frame/settings.h"
@@ -20,8 +19,7 @@ WebGLContextAttributes* ToWebGLContextAttributes(
result->setPreserveDrawingBuffer(attrs.preserve_drawing_buffer);
result->setFailIfMajorPerformanceCaveat(
attrs.fail_if_major_performance_caveat);
- result->setCompatibleXRDevice(
- static_cast<XRDevice*>(attrs.compatible_xr_device.Get()));
+ result->setXrCompatible(attrs.xr_compatible);
result->setLowLatency(attrs.low_latency);
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl
index 39092f2acab..725dbfb351e 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl
@@ -34,7 +34,7 @@ dictionary WebGLContextAttributes {
boolean premultipliedAlpha = true;
boolean preserveDrawingBuffer = false;
boolean failIfMajorPerformanceCaveat = false;
- [OriginTrialEnabled=WebXR] XRDevice compatibleXRDevice = null;
+ [OriginTrialEnabled=WebXR] boolean xrCompatible = false;
// TODO(crbug.com/788439): remove OriginTrialEnabled.
[OriginTrialEnabled=LowLatencyCanvas] boolean lowLatency = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h
index 786b9e1230b..2c0d7044e29 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h
@@ -40,6 +40,8 @@ enum WebGLExtensionName {
kWebGLDrawBuffersName,
kWebGLGetBufferSubDataAsyncName,
kWebGLLoseContextName,
+ kWebGLMultiDrawName,
+ kWebGLMultiDrawInstancedName,
kWebGLMultiviewName,
kWebGLExtensionNameCount, // Must be the last entry
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
index 397c5966fe5..4637d403937 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
@@ -39,12 +39,12 @@ class WebGLRenderbufferAttachment final
public:
static WebGLFramebuffer::WebGLAttachment* Create(WebGLRenderbuffer*);
+ explicit WebGLRenderbufferAttachment(WebGLRenderbuffer*);
+
void Trace(blink::Visitor*) override;
const char* NameInHeapSnapshot() const override { return "WebGLAttachment"; }
private:
- explicit WebGLRenderbufferAttachment(WebGLRenderbuffer*);
-
WebGLSharedObject* Object() const override;
bool IsSharedObject(WebGLSharedObject*) const override;
bool Valid() const override;
@@ -61,7 +61,7 @@ class WebGLRenderbufferAttachment final
WebGLFramebuffer::WebGLAttachment* WebGLRenderbufferAttachment::Create(
WebGLRenderbuffer* renderbuffer) {
- return new WebGLRenderbufferAttachment(renderbuffer);
+ return MakeGarbageCollected<WebGLRenderbufferAttachment>(renderbuffer);
}
void WebGLRenderbufferAttachment::Trace(blink::Visitor* visitor) {
@@ -110,17 +110,17 @@ class WebGLTextureAttachment final : public WebGLFramebuffer::WebGLAttachment {
GLint level,
GLint layer);
+ WebGLTextureAttachment(WebGLTexture*,
+ GLenum target,
+ GLint level,
+ GLint layer);
+
void Trace(blink::Visitor*) override;
const char* NameInHeapSnapshot() const override {
return "WebGLTextureAttachment";
}
private:
- WebGLTextureAttachment(WebGLTexture*,
- GLenum target,
- GLint level,
- GLint layer);
-
WebGLSharedObject* Object() const override;
bool IsSharedObject(WebGLSharedObject*) const override;
bool Valid() const override;
@@ -143,7 +143,8 @@ WebGLFramebuffer::WebGLAttachment* WebGLTextureAttachment::Create(
GLenum target,
GLint level,
GLint layer) {
- return new WebGLTextureAttachment(texture, target, level, layer);
+ return MakeGarbageCollected<WebGLTextureAttachment>(texture, target, level,
+ layer);
}
void WebGLTextureAttachment::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc
new file mode 100644
index 00000000000..cd2a88e4932
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc
@@ -0,0 +1,81 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw.h"
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace blink {
+
+WebGLMultiDraw::WebGLMultiDraw(WebGLRenderingContextBase* context)
+ : WebGLExtension(context) {
+ context->ExtensionsUtil()->EnsureExtensionEnabled("GL_WEBGL_multi_draw");
+ context->ExtensionsUtil()->EnsureExtensionEnabled("GL_ANGLE_multi_draw");
+}
+
+WebGLMultiDraw* WebGLMultiDraw::Create(WebGLRenderingContextBase* context) {
+ return MakeGarbageCollected<WebGLMultiDraw>(context);
+}
+
+WebGLExtensionName WebGLMultiDraw::GetName() const {
+ return kWebGLMultiDrawName;
+}
+
+bool WebGLMultiDraw::Supported(WebGLRenderingContextBase* context) {
+ return context->ExtensionsUtil()->SupportsExtension("GL_WEBGL_multi_draw") ||
+ context->ExtensionsUtil()->SupportsExtension("GL_ANGLE_multi_draw");
+}
+
+const char* WebGLMultiDraw::ExtensionName() {
+ return "WEBGL_multi_draw";
+}
+
+void WebGLMultiDraw::multiDrawArraysImpl(
+ GLenum mode,
+ const base::span<const int32_t>& firsts,
+ GLuint firstsOffset,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ GLsizei drawcount) {
+ WebGLExtensionScopedContext scoped(this);
+ if (scoped.IsLost() ||
+ !ValidateDrawcount(&scoped, "glMultiDrawArraysWEBGL", drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawArraysWEBGL",
+ "firstsOffset out of bounds", firsts.size(), firstsOffset,
+ drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawArraysWEBGL",
+ "countsOffset out of bounds", counts.size(), countsOffset,
+ drawcount)) {
+ return;
+ }
+
+ scoped.Context()->ContextGL()->MultiDrawArraysWEBGL(
+ mode, &firsts[firstsOffset], &counts[countsOffset], drawcount);
+}
+
+void WebGLMultiDraw::multiDrawElementsImpl(
+ GLenum mode,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ GLenum type,
+ const base::span<const int32_t>& offsets,
+ GLuint offsetsOffset,
+ GLsizei drawcount) {
+ WebGLExtensionScopedContext scoped(this);
+ if (scoped.IsLost() ||
+ !ValidateDrawcount(&scoped, "glMultiDrawElementsWEBGL", drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawElementsWEBGL",
+ "countsOffset out of bounds", counts.size(), countsOffset,
+ drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawElementsWEBGL",
+ "offsetsOffset out of bounds", offsets.size(),
+ offsetsOffset, drawcount)) {
+ return;
+ }
+
+ scoped.Context()->ContextGL()->MultiDrawElementsWEBGL(
+ mode, &counts[countsOffset], type, &offsets[offsetsOffset], drawcount);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.h
new file mode 100644
index 00000000000..06d6bf36f71
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/int32_array_or_long_sequence.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class WebGLMultiDraw final : public WebGLExtension,
+ public WebGLMultiDrawCommon {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static WebGLMultiDraw* Create(WebGLRenderingContextBase*);
+ static bool Supported(WebGLRenderingContextBase*);
+ static const char* ExtensionName();
+
+ explicit WebGLMultiDraw(WebGLRenderingContextBase*);
+ WebGLExtensionName GetName() const override;
+
+ void multiDrawArraysWEBGL(GLenum mode,
+ Int32ArrayOrLongSequence firstsList,
+ GLuint firstsOffset,
+ Int32ArrayOrLongSequence countsList,
+ GLuint countsOffset,
+ GLsizei drawcount) {
+ multiDrawArraysImpl(mode, MakeSpan(firstsList), firstsOffset,
+ MakeSpan(countsList), countsOffset, drawcount);
+ }
+
+ void multiDrawElementsWEBGL(GLenum mode,
+ Int32ArrayOrLongSequence countsList,
+ GLuint countsOffset,
+ GLenum type,
+ Int32ArrayOrLongSequence offsetsList,
+ GLuint offsetsOffset,
+ GLsizei drawcount) {
+ multiDrawElementsImpl(mode, MakeSpan(countsList), countsOffset, type,
+ MakeSpan(offsetsList), offsetsOffset, drawcount);
+ }
+
+ private:
+ void multiDrawArraysImpl(GLenum mode,
+ const base::span<const int32_t>& firsts,
+ GLuint firstsOffset,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ GLsizei drawcount);
+
+ void multiDrawElementsImpl(GLenum mode,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ GLenum type,
+ const base::span<const int32_t>& offsets,
+ GLuint offsetsOffset,
+ GLsizei drawcount);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl
new file mode 100644
index 00000000000..37ea0354935
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl
@@ -0,0 +1,23 @@
+// 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.
+
+// https://www.khronos.org/registry/webgl/extensions/WEBGL_multi_draw/
+
+[NoInterfaceObject]
+interface WebGLMultiDraw {
+ void multiDrawArraysWEBGL(GLenum mode,
+ (Int32Array or sequence<long>) firstsList,
+ GLuint firstsOffset,
+ (Int32Array or sequence<long>) countsList,
+ GLuint countsOffset,
+ GLsizei drawcount);
+
+ void multiDrawElementsWEBGL(GLenum mode,
+ (Int32Array or sequence<long>) countsList,
+ GLuint countsOffset,
+ GLenum type,
+ (Int32Array or sequence<long>) offsetsList,
+ GLuint offsetsOffset,
+ GLsizei drawcount);
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
new file mode 100644
index 00000000000..93dca19698a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h"
+
+namespace blink {
+
+bool WebGLMultiDrawCommon::ValidateDrawcount(
+ WebGLExtensionScopedContext* scoped,
+ const char* function_name,
+ GLsizei drawcount) {
+ if (drawcount < 0) {
+ scoped->Context()->SynthesizeGLError(GL_INVALID_VALUE, function_name,
+ "negative drawcount");
+ return false;
+ }
+ return true;
+}
+
+bool WebGLMultiDrawCommon::ValidateArray(WebGLExtensionScopedContext* scoped,
+ const char* function_name,
+ const char* outOfBoundsDescription,
+ size_t size,
+ GLuint offset,
+ GLsizei drawcount) {
+ if (static_cast<uint32_t>(drawcount) > size) {
+ scoped->Context()->SynthesizeGLError(GL_INVALID_OPERATION, function_name,
+ "drawcount out of bounds");
+ return false;
+ }
+ if (offset >= size) {
+ scoped->Context()->SynthesizeGLError(GL_INVALID_OPERATION, function_name,
+ outOfBoundsDescription);
+ return false;
+ }
+ return true;
+}
+
+base::span<const int32_t> WebGLMultiDrawCommon::MakeSpan(
+ const Int32ArrayOrLongSequence& array) {
+ if (array.IsInt32Array()) {
+ return base::span<const int32_t>(array.GetAsInt32Array().View()->Data(),
+ array.GetAsInt32Array().View()->length());
+ }
+ return base::span<const int32_t>(array.GetAsLongSequence().data(),
+ array.GetAsLongSequence().size());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h
new file mode 100644
index 00000000000..d9c3a8434f0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_COMMON_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_COMMON_H_
+
+#include "base/containers/span.h"
+#include "third_party/blink/renderer/bindings/modules/v8/int32_array_or_long_sequence.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
+
+namespace blink {
+
+class WebGLExtensionScopedContext;
+class WebGLMultiDrawCommon {
+ protected:
+ bool ValidateDrawcount(WebGLExtensionScopedContext* scoped,
+ const char* function_name,
+ GLsizei drawcount);
+
+ bool ValidateArray(WebGLExtensionScopedContext* scoped,
+ const char* function_name,
+ const char* outOfBoundsDescription,
+ size_t size,
+ GLuint offset,
+ GLsizei drawcount);
+
+ static base::span<const int32_t> MakeSpan(
+ const Int32ArrayOrLongSequence& array);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_COMMON_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.cc
new file mode 100644
index 00000000000..4b914c10272
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.cc
@@ -0,0 +1,99 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h"
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace blink {
+
+WebGLMultiDrawInstanced::WebGLMultiDrawInstanced(
+ WebGLRenderingContextBase* context)
+ : WebGLExtension(context) {
+ context->ExtensionsUtil()->EnsureExtensionEnabled(
+ "GL_WEBGL_multi_draw_instanced");
+ context->ExtensionsUtil()->EnsureExtensionEnabled("GL_ANGLE_multi_draw");
+}
+
+WebGLMultiDrawInstanced* WebGLMultiDrawInstanced::Create(
+ WebGLRenderingContextBase* context) {
+ return MakeGarbageCollected<WebGLMultiDrawInstanced>(context);
+}
+
+WebGLExtensionName WebGLMultiDrawInstanced::GetName() const {
+ return kWebGLMultiDrawInstancedName;
+}
+
+bool WebGLMultiDrawInstanced::Supported(WebGLRenderingContextBase* context) {
+ return context->ExtensionsUtil()->SupportsExtension(
+ "GL_WEBGL_multi_draw_instanced") ||
+ (context->ExtensionsUtil()->SupportsExtension("GL_ANGLE_multi_draw") &&
+ context->ExtensionsUtil()->SupportsExtension(
+ "GL_ANGLE_instanced_arrays"));
+}
+
+const char* WebGLMultiDrawInstanced::ExtensionName() {
+ return "WEBGL_multi_draw_instanced";
+}
+
+void WebGLMultiDrawInstanced::multiDrawArraysInstancedImpl(
+ GLenum mode,
+ const base::span<const int32_t>& firsts,
+ GLuint firstsOffset,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ const base::span<const int32_t>& instanceCounts,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount) {
+ WebGLExtensionScopedContext scoped(this);
+ if (scoped.IsLost() ||
+ !ValidateDrawcount(&scoped, "glMultiDrawArraysWEBGL", drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawArraysWEBGL",
+ "firstsOffset out of bounds", firsts.size(), firstsOffset,
+ drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawArraysWEBGL",
+ "countsOffset out of bounds", counts.size(), countsOffset,
+ drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawElementsWEBGL",
+ "instanceCountsOffset out of bounds",
+ instanceCounts.size(), instanceCountsOffset, drawcount)) {
+ return;
+ }
+
+ scoped.Context()->ContextGL()->MultiDrawArraysInstancedWEBGL(
+ mode, &firsts[firstsOffset], &counts[countsOffset],
+ &instanceCounts[instanceCountsOffset], drawcount);
+}
+
+void WebGLMultiDrawInstanced::multiDrawElementsInstancedImpl(
+ GLenum mode,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ GLenum type,
+ const base::span<const int32_t>& offsets,
+ GLuint offsetsOffset,
+ const base::span<const int32_t>& instanceCounts,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount) {
+ WebGLExtensionScopedContext scoped(this);
+ if (scoped.IsLost() ||
+ !ValidateDrawcount(&scoped, "glMultiDrawElementsWEBGL", drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawElementsWEBGL",
+ "countsOffset out of bounds", counts.size(), countsOffset,
+ drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawElementsWEBGL",
+ "offsetsOffset out of bounds", offsets.size(),
+ offsetsOffset, drawcount) ||
+ !ValidateArray(&scoped, "glMultiDrawElementsWEBGL",
+ "instanceCountsOffset out of bounds",
+ instanceCounts.size(), instanceCountsOffset, drawcount)) {
+ return;
+ }
+
+ scoped.Context()->ContextGL()->MultiDrawElementsInstancedWEBGL(
+ mode, &counts[countsOffset], type, &offsets[offsetsOffset],
+ &instanceCounts[instanceCountsOffset], drawcount);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h
new file mode 100644
index 00000000000..540a4d704b9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h
@@ -0,0 +1,82 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_INSTANCED_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_INSTANCED_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/int32_array_or_long_sequence.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+class WebGLMultiDrawInstanced final : public WebGLExtension,
+ public WebGLMultiDrawCommon {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static WebGLMultiDrawInstanced* Create(WebGLRenderingContextBase*);
+ static bool Supported(WebGLRenderingContextBase*);
+ static const char* ExtensionName();
+
+ explicit WebGLMultiDrawInstanced(WebGLRenderingContextBase*);
+ WebGLExtensionName GetName() const override;
+
+ void multiDrawArraysInstancedWEBGL(
+ GLenum mode,
+ Int32ArrayOrLongSequence firstsList,
+ GLuint firstsOffset,
+ Int32ArrayOrLongSequence countsList,
+ GLuint countsOffset,
+ Int32ArrayOrLongSequence instanceCountsList,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount) {
+ multiDrawArraysInstancedImpl(mode, MakeSpan(firstsList), firstsOffset,
+ MakeSpan(countsList), countsOffset,
+ MakeSpan(instanceCountsList),
+ instanceCountsOffset, drawcount);
+ }
+
+ void multiDrawElementsInstancedWEBGL(
+ GLenum mode,
+ Int32ArrayOrLongSequence countsList,
+ GLuint countsOffset,
+ GLenum type,
+ Int32ArrayOrLongSequence offsetsList,
+ GLuint offsetsOffset,
+ Int32ArrayOrLongSequence instanceCountsList,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount) {
+ multiDrawElementsInstancedImpl(mode, MakeSpan(countsList), countsOffset,
+ type, MakeSpan(offsetsList), offsetsOffset,
+ MakeSpan(instanceCountsList),
+ instanceCountsOffset, drawcount);
+ }
+
+ private:
+ void multiDrawArraysInstancedImpl(
+ GLenum mode,
+ const base::span<const int32_t>& firsts,
+ GLuint firstsOffset,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ const base::span<const int32_t>& instanceCounts,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount);
+
+ void multiDrawElementsInstancedImpl(
+ GLenum mode,
+ const base::span<const int32_t>& counts,
+ GLuint countsOffset,
+ GLenum type,
+ const base::span<const int32_t>& offsets,
+ GLuint offsetsOffset,
+ const base::span<const int32_t>& instanceCounts,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_MULTI_DRAW_INSTANCED_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.idl
new file mode 100644
index 00000000000..b117010359c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.idl
@@ -0,0 +1,27 @@
+// 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.
+
+// https://www.khronos.org/registry/webgl/extensions/WEBGL_multi_draw_instanced/
+
+[NoInterfaceObject]
+interface WebGLMultiDrawInstanced {
+ void multiDrawArraysInstancedWEBGL(GLenum mode,
+ (Int32Array or sequence<long>) firstsList,
+ GLuint firstsOffset,
+ (Int32Array or sequence<long>) countsList,
+ GLuint countsOffset,
+ (Int32Array or sequence<long>) instanceCountsList,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount);
+
+ void multiDrawElementsInstancedWEBGL(GLenum mode,
+ (Int32Array or sequence<long>) countsList,
+ GLuint countsOffset,
+ GLenum type,
+ (Int32Array or sequence<long>) offsetsList,
+ GLuint offsetsOffset,
+ (Int32Array or sequence<long>) instanceCountsList,
+ GLuint instanceCountsOffset,
+ GLsizei drawcount);
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multiview.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multiview.cc
index 8e36180afbf..0419e8237b4 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_multiview.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multiview.cc
@@ -33,13 +33,9 @@ void WebGLMultiview::framebufferTextureMultiviewWEBGL(GLenum target,
WebGLExtensionScopedContext scoped(this);
if (scoped.IsLost())
return;
- if (texture &&
- !texture->Validate(scoped.Context()->ContextGroup(), scoped.Context())) {
- scoped.Context()->SynthesizeGLError(
- GL_INVALID_OPERATION, "framebufferTextureMultiviewWEBGL",
- "texture does not belong to this context");
+ if (!scoped.Context()->ValidateNullableWebGLObject(
+ "framebufferTextureMultiviewWEBGL", texture))
return;
- }
GLenum textarget = texture ? texture->GetTarget() : 0;
if (texture) {
if (textarget != GL_TEXTURE_2D_ARRAY) {
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_object.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_object.cc
index f89c52aa1cb..b3db68f499d 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_object.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_object.cc
@@ -32,7 +32,7 @@ namespace blink {
WebGLObject::WebGLObject(WebGLRenderingContextBase* context)
: cached_number_of_context_losses_(context->NumberOfContextLosses()),
attachment_count_(0),
- deleted_(false),
+ marked_for_deletion_(false),
destruction_in_progress_(false) {}
WebGLObject::~WebGLObject() = default;
@@ -42,7 +42,7 @@ uint32_t WebGLObject::CachedNumberOfContextLosses() const {
}
void WebGLObject::DeleteObject(gpu::gles2::GLES2Interface* gl) {
- deleted_ = true;
+ marked_for_deletion_ = true;
if (!HasObject())
return;
@@ -66,7 +66,7 @@ void WebGLObject::DeleteObject(gpu::gles2::GLES2Interface* gl) {
}
void WebGLObject::Detach() {
- attachment_count_ = 0; // Make sure OpenGL resource is deleted.
+ attachment_count_ = 0; // Make sure OpenGL resource is eventually deleted.
}
void WebGLObject::DetachAndDeleteObject() {
@@ -92,7 +92,7 @@ bool WebGLObject::DestructionInProgress() const {
void WebGLObject::OnDetached(gpu::gles2::GLES2Interface* gl) {
if (attachment_count_)
--attachment_count_;
- if (deleted_)
+ if (marked_for_deletion_)
DeleteObject(gl);
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_object.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_object.h
index 0fc06c6b954..08f3ccb9cec 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_object.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_object.h
@@ -75,10 +75,10 @@ class WebGLObject : public ScriptWrappable {
void OnAttached() { ++attachment_count_; }
void OnDetached(gpu::gles2::GLES2Interface*);
- // This indicates whether the client side issue a delete call already, not
- // whether the OpenGL resource is deleted.
- // object()==0 indicates the OpenGL resource is deleted.
- bool IsDeleted() { return deleted_; }
+ // This indicates whether the client side has already issued a delete call,
+ // not whether the OpenGL resource is deleted. Object()==0, or !HasObject(),
+ // indicates that the OpenGL resource has been deleted.
+ bool MarkedForDeletion() { return marked_for_deletion_; }
// True if this object belongs to the group or context.
virtual bool Validate(const WebGLContextGroup*,
@@ -130,9 +130,11 @@ class WebGLObject : public ScriptWrappable {
unsigned attachment_count_;
- // Indicates whether the WebGL context's deletion function for this
- // object (deleteBuffer, deleteTexture, etc.) has been called.
- bool deleted_;
+ // Indicates whether the WebGL context's deletion function for this object
+ // (deleteBuffer, deleteTexture, etc.) has been called. It does *not* indicate
+ // whether the underlying OpenGL resource has been destroyed; !HasObject()
+ // indicates that.
+ bool marked_for_deletion_;
// Indicates whether the destructor has been entered and we therefore
// need to be careful in subclasses to not touch other on-heap objects.
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
index 452ad896f36..d63223727ef 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
@@ -65,6 +65,8 @@
#include "third_party/blink/renderer/modules/webgl/webgl_depth_texture.h"
#include "third_party/blink/renderer/modules/webgl/webgl_draw_buffers.h"
#include "third_party/blink/renderer/modules/webgl/webgl_lose_context.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
namespace blink {
@@ -187,6 +189,9 @@ void WebGLRenderingContext::RegisterContextExtensions() {
RegisterExtension<WebGLDrawBuffers>(webgl_draw_buffers_);
RegisterExtension<WebGLLoseContext>(webgl_lose_context_, kApprovedExtension,
kBothPrefixes);
+ RegisterExtension<WebGLMultiDraw>(webgl_multi_draw_, kDraftExtension);
+ RegisterExtension<WebGLMultiDrawInstanced>(webgl_multi_draw_instanced_,
+ kDraftExtension);
}
void WebGLRenderingContext::Trace(blink::Visitor* visitor) {
@@ -218,6 +223,8 @@ void WebGLRenderingContext::Trace(blink::Visitor* visitor) {
visitor->Trace(webgl_depth_texture_);
visitor->Trace(webgl_draw_buffers_);
visitor->Trace(webgl_lose_context_);
+ visitor->Trace(webgl_multi_draw_);
+ visitor->Trace(webgl_multi_draw_instanced_);
WebGLRenderingContextBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
index 9c71981509e..610461cdb48 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
@@ -51,6 +51,8 @@ class WebGLColorBufferFloat;
class WebGLDebugRendererInfo;
class WebGLDepthTexture;
class WebGLLoseContext;
+class WebGLMultiDraw;
+class WebGLMultiDrawInstanced;
class WebGLRenderingContext final : public WebGLRenderingContextBase {
DEFINE_WRAPPERTYPEINFO();
@@ -119,6 +121,8 @@ class WebGLRenderingContext final : public WebGLRenderingContextBase {
Member<WebGLDepthTexture> webgl_depth_texture_;
Member<WebGLDrawBuffers> webgl_draw_buffers_;
Member<WebGLLoseContext> webgl_lose_context_;
+ Member<WebGLMultiDraw> webgl_multi_draw_;
+ Member<WebGLMultiDrawInstanced> webgl_multi_draw_instanced_;
};
DEFINE_TYPE_CASTS(WebGLRenderingContext,
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 9fd9c417aa7..5332c24e2b5 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -28,6 +28,7 @@
#include <memory>
#include "base/numerics/checked_math.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/capabilities.h"
@@ -37,6 +38,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/html_canvas_element_or_offscreen_canvas.h"
#include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/dactyloscoper.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/settings.h"
@@ -90,7 +92,6 @@
#include "third_party/blink/renderer/modules/webgl/webgl_uniform_location.h"
#include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h"
#include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable_visitor.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
@@ -814,38 +815,35 @@ scoped_refptr<StaticBitmapImage> WebGLRenderingContextBase::GetImage(
return resource_provider->Snapshot();
}
-ScriptPromise WebGLRenderingContextBase::setCompatibleXRDevice(
- ScriptState* script_state,
- XRDevice* xr_device) {
-
+ScriptPromise WebGLRenderingContextBase::makeXRCompatible(
+ ScriptState* script_state) {
if (isContextLost()) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
"Context lost."));
}
- if (xr_device == compatible_xr_device_) {
+ if (xr_compatible_) {
// Returns a script promise resolved with undefined.
return ScriptPromise::CastUndefined(script_state);
}
- if (ContextCreatedOnCompatibleAdapter(xr_device)) {
- compatible_xr_device_ = xr_device;
+ if (ContextCreatedOnXRCompatibleAdapter()) {
+ xr_compatible_ = true;
return ScriptPromise::CastUndefined(script_state);
- } else {
- // TODO(http://crbug.com/876140) Trigger context loss and recreate on
- // compatible GPU.
- return ScriptPromise::RejectWithDOMException(
- script_state,
- DOMException::Create(
- DOMExceptionCode::kNotSupportedError,
- "Context is not compatible. Switching not yet implemented."));
}
+
+ // TODO(http://crbug.com/876140) Trigger context loss and recreate on
+ // compatible GPU.
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(
+ DOMExceptionCode::kNotSupportedError,
+ "Context is not compatible. Switching not yet implemented."));
}
-bool WebGLRenderingContextBase::IsXRDeviceCompatible(
- const XRDevice* xr_device) {
- return xr_device == compatible_xr_device_;
+bool WebGLRenderingContextBase::IsXRCompatible() {
+ return xr_compatible_;
}
namespace {
@@ -1020,8 +1018,7 @@ WebGLRenderingContextBase::WebGLRenderingContextBase(
// TODO(http://crbug.com/876140) Make sure this is being created on a
// compatible adapter.
- compatible_xr_device_ =
- static_cast<XRDevice*>(requested_attributes.compatible_xr_device.Get());
+ xr_compatible_ = requested_attributes.xr_compatible;
context_group_->AddContext(this);
@@ -1052,9 +1049,9 @@ WebGLRenderingContextBase::WebGLRenderingContextBase(
disabled_extensions_.insert(entry);
}
-#define ADD_VALUES_TO_SET(set, values) \
- for (size_t i = 0; i < arraysize(values); ++i) { \
- set.insert(values[i]); \
+#define ADD_VALUES_TO_SET(set, values) \
+ for (size_t i = 0; i < base::size(values); ++i) { \
+ set.insert(values[i]); \
}
ADD_VALUES_TO_SET(supported_internal_formats_, kSupportedFormatsES2);
@@ -1574,8 +1571,7 @@ bool WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
return true;
}
-bool WebGLRenderingContextBase::ContextCreatedOnCompatibleAdapter(
- const XRDevice* device) {
+bool WebGLRenderingContextBase::ContextCreatedOnXRCompatibleAdapter() {
// TODO(http://crbug.com/876140) Determine if device is compatible with
// current context.
return true;
@@ -1708,8 +1704,8 @@ void WebGLRenderingContextBase::activeTexture(GLenum texture) {
void WebGLRenderingContextBase::attachShader(WebGLProgram* program,
WebGLShader* shader) {
- if (isContextLost() || !ValidateWebGLObject("attachShader", program) ||
- !ValidateWebGLObject("attachShader", shader))
+ if (!ValidateWebGLProgramOrShader("attachShader", program) ||
+ !ValidateWebGLProgramOrShader("attachShader", shader))
return;
if (!program->AttachShader(shader)) {
SynthesizeGLError(GL_INVALID_OPERATION, "attachShader",
@@ -1723,7 +1719,7 @@ void WebGLRenderingContextBase::attachShader(WebGLProgram* program,
void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program,
GLuint index,
const String& name) {
- if (isContextLost() || !ValidateWebGLObject("bindAttribLocation", program))
+ if (!ValidateWebGLObject("bindAttribLocation", program))
return;
if (!ValidateLocationLength("bindAttribLocation", name))
return;
@@ -1736,23 +1732,6 @@ void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program,
name.Utf8().data());
}
-bool WebGLRenderingContextBase::CheckObjectToBeBound(const char* function_name,
- WebGLObject* object,
- bool& deleted) {
- deleted = false;
- if (isContextLost())
- return false;
- if (object) {
- if (!object->Validate(ContextGroup(), this)) {
- SynthesizeGLError(GL_INVALID_OPERATION, function_name,
- "object not from this context");
- return false;
- }
- deleted = object->IsDeleted();
- }
- return true;
-}
-
bool WebGLRenderingContextBase::ValidateAndUpdateBufferBindTarget(
const char* function_name,
GLenum target,
@@ -1785,14 +1764,8 @@ bool WebGLRenderingContextBase::ValidateAndUpdateBufferBindTarget(
}
void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) {
- bool deleted;
- if (!CheckObjectToBeBound("bindBuffer", buffer, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindBuffer",
- "attempt to bind a deleted buffer");
+ if (!ValidateNullableWebGLObject("bindBuffer", buffer))
return;
- }
if (!ValidateAndUpdateBufferBindTarget("bindBuffer", target, buffer))
return;
ContextGL()->BindBuffer(target, ObjectOrZero(buffer));
@@ -1800,14 +1773,8 @@ void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) {
void WebGLRenderingContextBase::bindFramebuffer(GLenum target,
WebGLFramebuffer* buffer) {
- bool deleted;
- if (!CheckObjectToBeBound("bindFramebuffer", buffer, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindFramebuffer",
- "attempt to bind a deleted framebuffer");
+ if (!ValidateNullableWebGLObject("bindFramebuffer", buffer))
return;
- }
if (target != GL_FRAMEBUFFER) {
SynthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target");
@@ -1820,14 +1787,8 @@ void WebGLRenderingContextBase::bindFramebuffer(GLenum target,
void WebGLRenderingContextBase::bindRenderbuffer(
GLenum target,
WebGLRenderbuffer* render_buffer) {
- bool deleted;
- if (!CheckObjectToBeBound("bindRenderbuffer", render_buffer, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindRenderbuffer",
- "attempt to bind a deleted renderbuffer");
+ if (!ValidateNullableWebGLObject("bindRenderbuffer", render_buffer))
return;
- }
if (target != GL_RENDERBUFFER) {
SynthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target");
return;
@@ -1840,14 +1801,8 @@ void WebGLRenderingContextBase::bindRenderbuffer(
void WebGLRenderingContextBase::bindTexture(GLenum target,
WebGLTexture* texture) {
- bool deleted;
- if (!CheckObjectToBeBound("bindTexture", texture, deleted))
- return;
- if (deleted) {
- SynthesizeGLError(GL_INVALID_OPERATION, "bindTexture",
- "attempt to bind a deleted texture");
+ if (!ValidateNullableWebGLObject("bindTexture", texture))
return;
- }
if (texture && texture->GetTarget() && texture->GetTarget() != target) {
SynthesizeGLError(GL_INVALID_OPERATION, "bindTexture",
"textures can not be used with multiple targets");
@@ -2072,6 +2027,15 @@ void WebGLRenderingContextBase::clear(GLbitfield mask) {
return;
}
+ if (!mask) {
+ // Use OnErrorMessage because it's both rate-limited and obeys the
+ // webGLErrorsToConsole setting.
+ OnErrorMessage(
+ "Performance warning: clear() called with no buffers in bitmask", 0);
+ // Don't skip the call to ClearIfComposited below; it has side
+ // effects even without the user requesting to clear any buffers.
+ }
+
ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
drawing_buffer_.get());
@@ -2140,7 +2104,7 @@ void WebGLRenderingContextBase::colorMask(GLboolean red,
}
void WebGLRenderingContextBase::compileShader(WebGLShader* shader) {
- if (isContextLost() || !ValidateWebGLObject("compileShader", shader))
+ if (!ValidateWebGLProgramOrShader("compileShader", shader))
return;
ContextGL()->CompileShader(ObjectOrZero(shader));
}
@@ -2353,6 +2317,11 @@ bool WebGLRenderingContextBase::DeleteObject(WebGLObject* object) {
"object does not belong to this context");
return false;
}
+ if (object->MarkedForDeletion()) {
+ // This is specified to be a no-op, including skipping all unbinding from
+ // the context's attachment points that would otherwise happen.
+ return false;
+ }
if (object->HasObject()) {
// We need to pass in context here because we want
// things in this context unbound.
@@ -2476,8 +2445,8 @@ void WebGLRenderingContextBase::depthRange(GLfloat z_near, GLfloat z_far) {
void WebGLRenderingContextBase::detachShader(WebGLProgram* program,
WebGLShader* shader) {
- if (isContextLost() || !ValidateWebGLObject("detachShader", program) ||
- !ValidateWebGLObject("detachShader", shader))
+ if (!ValidateWebGLProgramOrShader("detachShader", program) ||
+ !ValidateWebGLProgramOrShader("detachShader", shader))
return;
if (!program->DetachShader(shader)) {
SynthesizeGLError(GL_INVALID_OPERATION, "detachShader",
@@ -2526,12 +2495,55 @@ bool WebGLRenderingContextBase::ValidateRenderingState(
return true;
}
+bool WebGLRenderingContextBase::ValidateNullableWebGLObject(
+ const char* function_name,
+ WebGLObject* object) {
+ if (isContextLost())
+ return false;
+ if (!object) {
+ // This differs in behavior to ValidateWebGLObject; null objects are allowed
+ // in these entry points.
+ return true;
+ }
+ return ValidateWebGLObject(function_name, object);
+}
+
bool WebGLRenderingContextBase::ValidateWebGLObject(const char* function_name,
WebGLObject* object) {
+ if (isContextLost())
+ return false;
+ DCHECK(object);
+ if (object->MarkedForDeletion()) {
+ SynthesizeGLError(GL_INVALID_OPERATION, function_name,
+ "attempt to use a deleted object");
+ return false;
+ }
+ if (!object->Validate(ContextGroup(), this)) {
+ SynthesizeGLError(GL_INVALID_OPERATION, function_name,
+ "object does not belong to this context");
+ return false;
+ }
+ return true;
+}
+
+bool WebGLRenderingContextBase::ValidateWebGLProgramOrShader(
+ const char* function_name,
+ WebGLObject* object) {
+ if (isContextLost())
+ return false;
DCHECK(object);
+ // OpenGL ES 3.0.5 p. 45:
+ // "Commands that accept shader or program object names will generate the
+ // error INVALID_VALUE if the provided name is not the name of either a shader
+ // or program object and INVALID_OPERATION if the provided name identifies an
+ // object that is not the expected type."
+ //
+ // Programs and shaders also have slightly different lifetime rules than other
+ // objects in the API; they continue to be usable after being marked for
+ // deletion.
if (!object->HasObject()) {
SynthesizeGLError(GL_INVALID_VALUE, function_name,
- "no object or object deleted");
+ "attempt to use a deleted object");
return false;
}
if (!object->Validate(ContextGroup(), this)) {
@@ -2673,10 +2685,11 @@ void WebGLRenderingContextBase::framebufferRenderbuffer(
"invalid target");
return;
}
- if (buffer && (!buffer->HasEverBeenBound() ||
- !buffer->Validate(ContextGroup(), this))) {
+ if (!ValidateNullableWebGLObject("framebufferRenderbuffer", buffer))
+ return;
+ if (buffer && (!buffer->HasEverBeenBound())) {
SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
- "buffer never bound or buffer not from this context");
+ "renderbuffer has never been bound");
return;
}
// Don't allow the default framebuffer to be mutated; all current
@@ -2707,11 +2720,10 @@ void WebGLRenderingContextBase::framebufferTexture2D(GLenum target,
if (isContextLost() || !ValidateFramebufferFuncParameters(
"framebufferTexture2D", target, attachment))
return;
- if (texture && !texture->Validate(ContextGroup(), this)) {
- SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D",
- "no texture or texture not from this context");
+ if (!ValidateNullableWebGLObject("framebufferTexture2D", texture))
return;
- }
+ // TODO(crbug.com/919711): validate texture's target against textarget.
+
// Don't allow the default framebuffer to be mutated; all current
// implementations use an FBO internally in place of the default
// FBO.
@@ -2749,7 +2761,7 @@ void WebGLRenderingContextBase::generateMipmap(GLenum target) {
WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib(
WebGLProgram* program,
GLuint index) {
- if (isContextLost() || !ValidateWebGLObject("getActiveAttrib", program))
+ if (!ValidateWebGLProgramOrShader("getActiveAttrib", program))
return nullptr;
GLuint program_id = ObjectNonZero(program);
GLint max_name_length = -1;
@@ -2779,7 +2791,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib(
WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform(
WebGLProgram* program,
GLuint index) {
- if (isContextLost() || !ValidateWebGLObject("getActiveUniform", program))
+ if (!ValidateWebGLProgramOrShader("getActiveUniform", program))
return nullptr;
GLuint program_id = ObjectNonZero(program);
GLint max_name_length = -1;
@@ -2808,7 +2820,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform(
base::Optional<HeapVector<Member<WebGLShader>>>
WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program) {
- if (isContextLost() || !ValidateWebGLObject("getAttachedShaders", program))
+ if (!ValidateWebGLProgramOrShader("getAttachedShaders", program))
return base::nullopt;
HeapVector<Member<WebGLShader>> shader_objects;
@@ -2824,7 +2836,7 @@ WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program) {
GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program,
const String& name) {
- if (isContextLost() || !ValidateWebGLObject("getAttribLocation", program))
+ if (!ValidateWebGLProgramOrShader("getAttribLocation", program))
return -1;
if (!ValidateLocationLength("getAttribLocation", name))
return -1;
@@ -2895,9 +2907,7 @@ WebGLContextAttributes* WebGLRenderingContextBase::getContextAttributes()
if (CreationAttributes().stencil && !GetDrawingBuffer()->HasStencilBuffer())
result->setStencil(false);
result->setAntialias(GetDrawingBuffer()->Multisample());
- if (compatible_xr_device_) {
- result->setCompatibleXRDevice(compatible_xr_device_);
- }
+ result->setXrCompatible(xr_compatible_);
return result;
}
@@ -2956,6 +2966,12 @@ ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* script_state,
const String& name) {
WebGLExtension* extension = nullptr;
+ if (name == WebGLDebugRendererInfo::ExtensionName()) {
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context, WebFeature::kWebGLDebugRendererInfo);
+ Dactyloscoper::Record(context, WebFeature::kWebGLDebugRendererInfo);
+ }
+
if (!isContextLost()) {
for (ExtensionTracker* tracker : extensions_) {
if (tracker->MatchesNameWithPrefixes(name)) {
@@ -3376,13 +3392,14 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter(
ScriptState* script_state,
WebGLProgram* program,
GLenum pname) {
- if (isContextLost() || !ValidateWebGLObject("getProgramParameter", program))
+ if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) {
return ScriptValue::CreateNull(script_state);
+ }
GLint value = 0;
switch (pname) {
case GL_DELETE_STATUS:
- return WebGLAny(script_state, program->IsDeleted());
+ return WebGLAny(script_state, program->MarkedForDeletion());
case GL_VALIDATE_STATUS:
ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
return WebGLAny(script_state, static_cast<bool>(value));
@@ -3423,7 +3440,7 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter(
}
String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program) {
- if (isContextLost() || !ValidateWebGLObject("getProgramInfoLog", program))
+ if (!ValidateWebGLProgramOrShader("getProgramInfoLog", program))
return String();
GLStringQuery query(ContextGL());
return query.Run<GLStringQuery::ProgramInfoLog>(ObjectNonZero(program));
@@ -3480,12 +3497,13 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter(
ScriptState* script_state,
WebGLShader* shader,
GLenum pname) {
- if (isContextLost() || !ValidateWebGLObject("getShaderParameter", shader))
+ if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) {
return ScriptValue::CreateNull(script_state);
+ }
GLint value = 0;
switch (pname) {
case GL_DELETE_STATUS:
- return WebGLAny(script_state, shader->IsDeleted());
+ return WebGLAny(script_state, shader->MarkedForDeletion());
case GL_COMPILE_STATUS:
ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
return WebGLAny(script_state, static_cast<bool>(value));
@@ -3508,7 +3526,7 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter(
}
String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) {
- if (isContextLost() || !ValidateWebGLObject("getShaderInfoLog", shader))
+ if (!ValidateWebGLProgramOrShader("getShaderInfoLog", shader))
return String();
GLStringQuery query(ContextGL());
return query.Run<GLStringQuery::ShaderInfoLog>(ObjectNonZero(shader));
@@ -3544,7 +3562,7 @@ WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat(
}
String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) {
- if (isContextLost() || !ValidateWebGLObject("getShaderSource", shader))
+ if (!ValidateWebGLProgramOrShader("getShaderSource", shader))
return String();
return EnsureNotNull(shader->Source());
}
@@ -3607,7 +3625,7 @@ ScriptValue WebGLRenderingContextBase::getUniform(
ScriptState* script_state,
WebGLProgram* program,
const WebGLUniformLocation* uniform_location) {
- if (isContextLost() || !ValidateWebGLObject("getUniform", program))
+ if (!ValidateWebGLProgramOrShader("getUniform", program))
return ScriptValue::CreateNull(script_state);
DCHECK(uniform_location);
if (uniform_location->Program() != program) {
@@ -3877,7 +3895,7 @@ ScriptValue WebGLRenderingContextBase::getUniform(
WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation(
WebGLProgram* program,
const String& name) {
- if (isContextLost() || !ValidateWebGLObject("getUniformLocation", program))
+ if (!ValidateWebGLProgramOrShader("getUniformLocation", program))
return nullptr;
if (!ValidateLocationLength("getUniformLocation", name))
return nullptr;
@@ -4013,7 +4031,7 @@ GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer) {
if (!buffer->HasEverBeenBound())
return 0;
- if (buffer->IsDeleted())
+ if (buffer->MarkedForDeletion())
return 0;
return ContextGL()->IsBuffer(buffer->Object());
@@ -4039,7 +4057,7 @@ GLboolean WebGLRenderingContextBase::isFramebuffer(
if (!framebuffer->HasEverBeenBound())
return 0;
- if (framebuffer->IsDeleted())
+ if (framebuffer->MarkedForDeletion())
return 0;
return ContextGL()->IsFramebuffer(framebuffer->Object());
@@ -4049,6 +4067,10 @@ GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program) {
if (!program || isContextLost() || !program->Validate(ContextGroup(), this))
return 0;
+ // OpenGL ES special-cases the behavior of program objects; if they're deleted
+ // while attached to the current context state, glIsProgram is supposed to
+ // still return true. For this reason, MarkedForDeletion is not checked here.
+
return ContextGL()->IsProgram(program->Object());
}
@@ -4060,7 +4082,7 @@ GLboolean WebGLRenderingContextBase::isRenderbuffer(
if (!renderbuffer->HasEverBeenBound())
return 0;
- if (renderbuffer->IsDeleted())
+ if (renderbuffer->MarkedForDeletion())
return 0;
return ContextGL()->IsRenderbuffer(renderbuffer->Object());
@@ -4070,6 +4092,10 @@ GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader) {
if (!shader || isContextLost() || !shader->Validate(ContextGroup(), this))
return 0;
+ // OpenGL ES special-cases the behavior of shader objects; if they're deleted
+ // while attached to a program, glIsShader is supposed to still return true.
+ // For this reason, MarkedForDeletion is not checked here.
+
return ContextGL()->IsShader(shader->Object());
}
@@ -4079,7 +4105,7 @@ GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture) {
if (!texture->HasEverBeenBound())
return 0;
- if (texture->IsDeleted())
+ if (texture->MarkedForDeletion())
return 0;
return ContextGL()->IsTexture(texture->Object());
@@ -4092,7 +4118,7 @@ void WebGLRenderingContextBase::lineWidth(GLfloat width) {
}
void WebGLRenderingContextBase::linkProgram(WebGLProgram* program) {
- if (isContextLost() || !ValidateWebGLObject("linkProgram", program))
+ if (!ValidateWebGLProgramOrShader("linkProgram", program))
return;
if (program->ActiveTransformFeedbackCount() > 0) {
@@ -4437,7 +4463,7 @@ void WebGLRenderingContextBase::scissor(GLint x,
void WebGLRenderingContextBase::shaderSource(WebGLShader* shader,
const String& string) {
- if (isContextLost() || !ValidateWebGLObject("shaderSource", shader))
+ if (!ValidateWebGLProgramOrShader("shaderSource", shader))
return;
String string_without_comments = StripComments(string).Result();
// TODO(danakj): Make validateShaderSource reject characters > 255 (or utf16
@@ -6216,11 +6242,8 @@ void WebGLRenderingContextBase::uniformMatrix4fv(
}
void WebGLRenderingContextBase::useProgram(WebGLProgram* program) {
- bool deleted;
- if (!CheckObjectToBeBound("useProgram", program, deleted))
+ if (!ValidateNullableWebGLObject("useProgram", program))
return;
- if (deleted)
- program = nullptr;
if (program && !program->LinkStatus(this)) {
SynthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid");
return;
@@ -6237,7 +6260,7 @@ void WebGLRenderingContextBase::useProgram(WebGLProgram* program) {
}
void WebGLRenderingContextBase::validateProgram(WebGLProgram* program) {
- if (isContextLost() || !ValidateWebGLObject("validateProgram", program))
+ if (!ValidateWebGLProgramOrShader("validateProgram", program))
return;
ContextGL()->ValidateProgram(ObjectOrZero(program));
}
@@ -7551,13 +7574,13 @@ bool WebGLRenderingContextBase::ValidateHTMLImageElement(
SynthesizeGLError(GL_INVALID_VALUE, function_name, "no image");
return false;
}
- const KURL& url = image->CachedImage()->GetResponse().Url();
+ const KURL& url = image->CachedImage()->GetResponse().CurrentRequestUrl();
if (url.IsNull() || url.IsEmpty() || !url.IsValid()) {
SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid image");
return false;
}
- if (WouldTaintOrigin(image, security_origin)) {
+ if (WouldTaintOrigin(image)) {
exception_state.ThrowSecurityError(
"The image element contains cross-origin data, and may not be loaded.");
return false;
@@ -7575,7 +7598,7 @@ bool WebGLRenderingContextBase::ValidateCanvasRenderingContextHost(
return false;
}
- if (WouldTaintOrigin(context_host, security_origin)) {
+ if (WouldTaintOrigin(context_host)) {
exception_state.ThrowSecurityError("Tainted canvases may not be loaded.");
return false;
}
@@ -7592,7 +7615,7 @@ bool WebGLRenderingContextBase::ValidateHTMLVideoElement(
return false;
}
- if (WouldTaintOrigin(video, security_origin)) {
+ if (WouldTaintOrigin(video)) {
exception_state.ThrowSecurityError(
"The video element contains cross-origin data, and may not be loaded.");
return false;
@@ -7981,7 +8004,6 @@ void WebGLRenderingContextBase::Trace(blink::Visitor* visitor) {
visitor->Trace(current_program_);
visitor->Trace(framebuffer_binding_);
visitor->Trace(renderbuffer_binding_);
- visitor->Trace(compatible_xr_device_);
visitor->Trace(texture_units_);
visitor->Trace(extensions_);
CanvasRenderingContext::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 58fbb7a45ed..a77c320d46c 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -46,7 +46,6 @@
#include "third_party/blink/renderer/modules/webgl/webgl_extension_name.h"
#include "third_party/blink/renderer/modules/webgl/webgl_texture.h"
#include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
@@ -614,8 +613,8 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
scoped_refptr<StaticBitmapImage> GetStaticBitmapImage(
std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
- ScriptPromise setCompatibleXRDevice(ScriptState*, XRDevice*);
- bool IsXRDeviceCompatible(const XRDevice*);
+ ScriptPromise makeXRCompatible(ScriptState*);
+ bool IsXRCompatible();
protected:
friend class EXTDisjointTimerQuery;
@@ -632,6 +631,9 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
friend class WebGLCompressedTexturePVRTC;
friend class WebGLCompressedTextureS3TC;
friend class WebGLCompressedTextureS3TCsRGB;
+ friend class WebGLMultiDraw;
+ friend class WebGLMultiDrawCommon;
+ friend class WebGLMultiDrawInstanced;
friend class WebGLMultiview;
friend class WebGLRenderingContextErrorMessageCallback;
friend class WebGLVertexArrayObjectBase;
@@ -686,7 +688,23 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
// Check if each enabled vertex attribute is bound to a buffer.
bool ValidateRenderingState(const char*);
- bool ValidateWebGLObject(const char*, WebGLObject*);
+ // Helper function for APIs which can legally receive null objects, including
+ // the bind* calls (bindBuffer, bindTexture, etc.) and useProgram. Checks that
+ // the object belongs to this context and that it's not marked for deletion.
+ // Returns false if the caller should return without further processing.
+ // Performs a context loss check internally.
+ // This returns true for null WebGLObject arguments!
+ bool ValidateNullableWebGLObject(const char* function_name, WebGLObject*);
+
+ // Validates the incoming WebGL object, which is assumed to be non-null.
+ // Checks that the object belongs to this context and that it's not marked for
+ // deletion. Performs a context loss check internally.
+ bool ValidateWebGLObject(const char* function_name, WebGLObject*);
+
+ // Validates the incoming WebGL program or shader, which is assumed to be
+ // non-null. OpenGL ES's validation rules differ for these types of objetcts
+ // compared to others. Performs a context loss check internally.
+ bool ValidateWebGLProgramOrShader(const char* function_name, WebGLObject*);
// Adds a compressed texture format.
void AddCompressedTextureFormat(GLenum);
@@ -757,7 +775,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
TraceWrapperMember<WebGLFramebuffer> framebuffer_binding_;
TraceWrapperMember<WebGLRenderbuffer> renderbuffer_binding_;
- Member<XRDevice> compatible_xr_device_;
+ bool xr_compatible_;
HeapVector<TextureUnitState> texture_units_;
wtf_size_t active_texture_unit_;
@@ -871,9 +889,16 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
static TypedExtensionTracker<T>* Create(Member<T>& extension_field,
ExtensionFlags flags,
const char* const* prefixes) {
- return new TypedExtensionTracker<T>(extension_field, flags, prefixes);
+ return MakeGarbageCollected<TypedExtensionTracker<T>>(extension_field,
+ flags, prefixes);
}
+ TypedExtensionTracker(Member<T>& extension_field,
+ ExtensionFlags flags,
+ const char* const* prefixes)
+ : ExtensionTracker(flags, prefixes),
+ extension_field_(extension_field) {}
+
WebGLExtension* GetExtension(WebGLRenderingContextBase* context) override {
if (!extension_) {
extension_ = T::Create(context);
@@ -907,12 +932,6 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
}
private:
- TypedExtensionTracker(Member<T>& extension_field,
- ExtensionFlags flags,
- const char* const* prefixes)
- : ExtensionTracker(flags, prefixes),
- extension_field_(extension_field) {}
-
GC_PLUGIN_IGNORE("http://crbug.com/519953")
Member<T>& extension_field_;
// ExtensionTracker holds it's own reference to the extension to ensure
@@ -1493,13 +1512,6 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
// Return false if caller should return without further processing.
bool DeleteObject(WebGLObject*);
- // Helper function for bind* (bindBuffer, bindTexture, etc) and useProgram.
- // If the object has already been deleted, set deleted to true upon return.
- // Return false if caller should return without further processing.
- bool CheckObjectToBeBound(const char* function_name,
- WebGLObject*,
- bool& deleted);
-
void DispatchContextLostEvent(TimerBase*);
// Helper for restoration after context lost.
void MaybeRestoreContext(TimerBase*);
@@ -1710,9 +1722,9 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
bool IsPaintable() const final { return GetDrawingBuffer(); }
- // Returns true if the context is compatible with the given device as defined
+ // Returns true if the context is compatible with the XR device as defined
// by https://immersive-web.github.io/webxr/spec/latest/#contextcompatibility
- bool ContextCreatedOnCompatibleAdapter(const XRDevice*);
+ bool ContextCreatedOnXRCompatibleAdapter();
bool CopyRenderingResultsFromDrawingBuffer(CanvasResourceProvider*,
SourceDrawingBuffer) const;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
index 5857522f575..d3a2f11423e 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
@@ -553,7 +553,7 @@ typedef unrestricted float GLclampf;
GLenum getError();
- [CallWith=ScriptState] object? getExtension(DOMString name);
+ [CallWith=ScriptState, HighEntropy, Measure] object? getExtension(DOMString name);
[CallWith=ScriptState] any getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname);
[CallWith=ScriptState] any getParameter(GLenum pname);
@@ -568,7 +568,7 @@ typedef unrestricted float GLclampf;
DOMString? getShaderSource(WebGLShader shader);
- sequence<DOMString>? getSupportedExtensions();
+ [HighEntropy, Measure] sequence<DOMString>? getSupportedExtensions();
[CallWith=ScriptState] any getTexParameter(GLenum target, GLenum pname);
@@ -714,5 +714,5 @@ typedef unrestricted float GLclampf;
[RuntimeEnabled=OffscreenCanvasCommit] void commit();
// WebXR Device API support
- [OriginTrialEnabled=WebXR, SecureContext, CallWith=ScriptState] Promise<void> setCompatibleXRDevice(XRDevice device);
+ [OriginTrialEnabled=WebXR, SecureContext, CallWith=ScriptState] Promise<void> makeXRCompatible();
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc
index 316d989c009..2024fbff159 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc
@@ -13,9 +13,10 @@ WebGLSharedPlatform3DObject::WebGLSharedPlatform3DObject(
: WebGLSharedObject(ctx), object_(0) {}
void WebGLSharedPlatform3DObject::SetObject(GLuint object) {
- // object==0 && deleted==false indicating an uninitialized state;
+ // SetObject may only be called when this container is in the
+ // uninitialized state: object==0 && marked_for_deletion==false.
DCHECK(!object_);
- DCHECK(!IsDeleted());
+ DCHECK(!MarkedForDeletion());
object_ = object;
}
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/BUILD.gn b/chromium/third_party/blink/renderer/modules/webmidi/BUILD.gn
index 65b0f4c878d..1d56cbd209e 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webmidi/BUILD.gn
@@ -15,6 +15,8 @@ blink_modules_sources("webmidi") {
"midi_accessor_client.h",
"midi_connection_event.cc",
"midi_connection_event.h",
+ "midi_dispatcher.cc",
+ "midi_dispatcher.h",
"midi_input.cc",
"midi_input.h",
"midi_input_map.cc",
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc
index e123c7fad26..ece5db01e33 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc
@@ -181,7 +181,7 @@ void MIDIAccess::DidSetOutputPortState(unsigned port_index, PortState state) {
void MIDIAccess::DidReceiveMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
TimeTicks time_stamp) {
DCHECK(IsMainThread());
if (port_index >= inputs_.size())
@@ -192,7 +192,7 @@ void MIDIAccess::DidReceiveMIDIData(unsigned port_index,
void MIDIAccess::SendMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
TimeTicks time_stamp) {
DCHECK(!time_stamp.is_null());
if (!GetExecutionContext() || !data || !length ||
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.h
index e0b5f9ab0ce..b120f003855 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.h
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.h
@@ -119,14 +119,14 @@ class MIDIAccess final : public EventTargetWithInlineData,
}
void DidReceiveMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
TimeTicks time_stamp) override;
// |timeStampInMilliseconds| is in the same time coordinate system as
// performance.now().
void SendMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
TimeTicks time_stamp);
// Eager finalization needed to promptly release m_accessor. Otherwise
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc
index f6be881d194..e47baa473dc 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc
@@ -40,8 +40,12 @@ ScriptPromise MIDIAccessInitializer::Start() {
ScriptPromise promise = this->Promise();
accessor_ = MIDIAccessor::Create(this);
- ConnectToPermissionService(GetExecutionContext(),
- mojo::MakeRequest(&permission_service_));
+ // See https://bit.ly/2S0zRAS for task types.
+ ConnectToPermissionService(
+ GetExecutionContext(),
+ mojo::MakeRequest(
+ &permission_service_,
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
Document& doc = To<Document>(*GetExecutionContext());
permission_service_->RequestPermission(
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h
index cf12df77925..e6a281e24c1 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h
@@ -53,7 +53,6 @@ class MODULES_EXPORT MIDIAccessInitializer : public ScriptPromiseResolver,
MIDIAccessInitializer* resolver =
MakeGarbageCollected<MIDIAccessInitializer>(script_state, options);
resolver->KeepAliveWhilePending();
- resolver->PauseIfNeeded();
return resolver->Start();
}
@@ -82,7 +81,7 @@ class MODULES_EXPORT MIDIAccessInitializer : public ScriptPromiseResolver,
void DidStartSession(midi::mojom::Result) override;
void DidReceiveMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
TimeTicks time_stamp) override {}
void Trace(Visitor*) override;
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.cc
index c27ead34c6b..0cdd945d93d 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.cc
@@ -33,14 +33,13 @@
#include <memory>
#include "base/memory/ptr_util.h"
-#include "third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/modules/webmidi/midi_accessor_client.h"
+#include "third_party/blink/renderer/modules/webmidi/midi_dispatcher.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-using blink::WebString;
-using midi::mojom::PortState;
-using midi::mojom::Result;
+using midi::mojom::blink::PortState;
+using midi::mojom::blink::Result;
namespace blink {
@@ -51,35 +50,37 @@ std::unique_ptr<MIDIAccessor> MIDIAccessor::Create(MIDIAccessorClient* client) {
MIDIAccessor::MIDIAccessor(MIDIAccessorClient* client) : client_(client) {
DCHECK(client);
+}
- accessor_ = Platform::Current()->CreateMIDIAccessor(this);
-
- DCHECK(accessor_);
+MIDIAccessor::~MIDIAccessor() {
+ if (called_start_session_)
+ MIDIDispatcher::Instance().RemoveAccessor(this);
}
void MIDIAccessor::StartSession() {
- accessor_->StartSession();
+ MIDIDispatcher::Instance().AddAccessor(this);
+ called_start_session_ = true;
}
void MIDIAccessor::SendMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
base::TimeTicks time_stamp) {
- accessor_->SendMIDIData(port_index, data, length, time_stamp);
+ MIDIDispatcher::Instance().SendMidiData(port_index, data, length, time_stamp);
}
-void MIDIAccessor::DidAddInputPort(const WebString& id,
- const WebString& manufacturer,
- const WebString& name,
- const WebString& version,
+void MIDIAccessor::DidAddInputPort(const String& id,
+ const String& manufacturer,
+ const String& name,
+ const String& version,
PortState state) {
client_->DidAddInputPort(id, manufacturer, name, version, state);
}
-void MIDIAccessor::DidAddOutputPort(const WebString& id,
- const WebString& manufacturer,
- const WebString& name,
- const WebString& version,
+void MIDIAccessor::DidAddOutputPort(const String& id,
+ const String& manufacturer,
+ const String& name,
+ const String& version,
PortState state) {
client_->DidAddOutputPort(id, manufacturer, name, version, state);
}
@@ -98,7 +99,7 @@ void MIDIAccessor::DidStartSession(Result result) {
void MIDIAccessor::DidReceiveMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
base::TimeTicks time_stamp) {
client_->DidReceiveMIDIData(port_index, data, length, time_stamp);
}
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.h
index fdd8214965e..dd8e950f026 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.h
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor.h
@@ -34,58 +34,57 @@
#include <memory>
#include "base/time/time.h"
#include "media/midi/midi_service.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h"
-#include "third_party/blink/public/platform/modules/webmidi/web_midi_accessor_client.h"
+#include "third_party/blink/renderer/modules/webmidi/midi_dispatcher.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
class MIDIAccessorClient;
-class MIDIAccessor final : public WebMIDIAccessorClient {
+// TODO(https://crbug.com/582328): Remove this class, and call MIDIDispatcher
+// directly.
+class MIDIAccessor final {
USING_FAST_MALLOC(MIDIAccessor);
public:
static std::unique_ptr<MIDIAccessor> Create(MIDIAccessorClient*);
-
- ~MIDIAccessor() override = default;
+ ~MIDIAccessor();
void StartSession();
void SendMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
base::TimeTicks time_stamp);
// MIDIAccessInitializer and MIDIAccess are both MIDIAccessClient.
// MIDIAccessInitializer is the first client and MIDIAccess takes over it
// once the initialization successfully finishes.
void SetClient(MIDIAccessorClient* client) { client_ = client; }
- // WebMIDIAccessorClient
- void DidAddInputPort(const WebString& id,
- const WebString& manufacturer,
- const WebString& name,
- const WebString& version,
- midi::mojom::PortState) override;
- void DidAddOutputPort(const WebString& id,
- const WebString& manufacturer,
- const WebString& name,
- const WebString& version,
- midi::mojom::PortState) override;
- void DidSetInputPortState(unsigned port_index,
- midi::mojom::PortState) override;
- void DidSetOutputPortState(unsigned port_index,
- midi::mojom::PortState) override;
- void DidStartSession(midi::mojom::Result) override;
+ // The following methods are used by MIDIDispatcher to forward messages from
+ // the browser process.
+ void DidAddInputPort(const String& id,
+ const String& manufacturer,
+ const String& name,
+ const String& version,
+ midi::mojom::PortState);
+ void DidAddOutputPort(const String& id,
+ const String& manufacturer,
+ const String& name,
+ const String& version,
+ midi::mojom::PortState);
+ void DidSetInputPortState(unsigned port_index, midi::mojom::PortState);
+ void DidSetOutputPortState(unsigned port_index, midi::mojom::PortState);
+ void DidStartSession(midi::mojom::Result);
void DidReceiveMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
- base::TimeTicks time_stamp) override;
+ wtf_size_t length,
+ base::TimeTicks time_stamp);
private:
explicit MIDIAccessor(MIDIAccessorClient*);
MIDIAccessorClient* client_;
- std::unique_ptr<WebMIDIAccessor> accessor_;
+ bool called_start_session_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor_client.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor_client.h
index d1b94128636..60d1564b318 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor_client.h
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_accessor_client.h
@@ -58,7 +58,7 @@ class MIDIAccessorClient {
virtual void DidStartSession(midi::mojom::Result) = 0;
virtual void DidReceiveMIDIData(unsigned port_index,
const unsigned char* data,
- size_t length,
+ wtf_size_t length,
base::TimeTicks time_stamp) = 0;
};
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
new file mode 100644
index 00000000000..065760ea9e0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
@@ -0,0 +1,182 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webmidi/midi_dispatcher.h"
+
+#include "third_party/blink/public/platform/interface_provider.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/modules/webmidi/midi_accessor.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+namespace {
+// The maximum number of bytes which we're allowed to send to the browser
+// before getting acknowledgement back from the browser that they've been
+// successfully sent.
+static const size_t kMaxUnacknowledgedBytesSent = 10 * 1024 * 1024; // 10 MB.
+} // namespace
+
+MIDIDispatcher::MIDIDispatcher() : binding_(this) {}
+
+MIDIDispatcher::~MIDIDispatcher() = default;
+
+MIDIDispatcher& MIDIDispatcher::Instance() {
+ DEFINE_STATIC_LOCAL(Persistent<MIDIDispatcher>, midi_dispatcher,
+ (MakeGarbageCollected<MIDIDispatcher>()));
+ return *midi_dispatcher;
+}
+
+void MIDIDispatcher::Trace(Visitor* visitor) {}
+
+void MIDIDispatcher::AddAccessor(MIDIAccessor* accessor) {
+ TRACE_EVENT0("midi", "MIDIDispatcher::AddAccessor");
+ accessors_waiting_session_queue_.push_back(accessor);
+ if (session_result_ != midi::mojom::Result::NOT_INITIALIZED) {
+ SessionStarted(session_result_);
+ } else if (accessors_waiting_session_queue_.size() == 1u) {
+ midi::mojom::blink::MidiSessionClientPtr client_ptr;
+ binding_.Bind(mojo::MakeRequest(&client_ptr));
+ GetMidiSessionProvider().StartSession(mojo::MakeRequest(&midi_session_),
+ std::move(client_ptr));
+ }
+}
+
+void MIDIDispatcher::RemoveAccessor(MIDIAccessor* accessor) {
+ // |accessor| should either be in |accessors_| or
+ // |accessors_waiting_session_queue_|, but not both.
+ DCHECK_NE(accessors_.Contains(accessor),
+ accessors_waiting_session_queue_.Contains(accessor))
+ << "RemoveAccessor call was not balanced with AddAccessor call";
+ auto** it = std::find(accessors_.begin(), accessors_.end(), accessor);
+ if (it != accessors_.end()) {
+ accessors_.erase(it);
+ } else {
+ accessors_waiting_session_queue_.erase(
+ std::find(accessors_waiting_session_queue_.begin(),
+ accessors_waiting_session_queue_.end(), accessor));
+ }
+ if (accessors_.IsEmpty() && accessors_waiting_session_queue_.IsEmpty()) {
+ session_result_ = midi::mojom::Result::NOT_INITIALIZED;
+ inputs_.clear();
+ outputs_.clear();
+ midi_session_.reset();
+ midi_session_provider_.reset();
+ binding_.Close();
+ }
+}
+
+void MIDIDispatcher::SendMidiData(uint32_t port,
+ const uint8_t* data,
+ wtf_size_t length,
+ base::TimeTicks timestamp) {
+ if ((kMaxUnacknowledgedBytesSent - unacknowledged_bytes_sent_) < length) {
+ // TODO(toyoshim): buffer up the data to send at a later time.
+ // For now we're just dropping these bytes on the floor.
+ return;
+ }
+
+ unacknowledged_bytes_sent_ += length;
+ Vector<uint8_t> v;
+ v.Append(data, length);
+ GetMidiSession().SendData(port, std::move(v), timestamp);
+}
+
+void MIDIDispatcher::AddInputPort(midi::mojom::blink::PortInfoPtr info) {
+ inputs_.push_back(*info);
+ // Iterating over a copy of |accessors_| as callback could result in
+ // |accessors_| being modified. Applies to for-loops later in this file as
+ // well.
+ for (auto* accessor : AccessorList(accessors_)) {
+ accessor->DidAddInputPort(info->id, info->manufacturer, info->name,
+ info->version, info->state);
+ }
+}
+
+void MIDIDispatcher::AddOutputPort(midi::mojom::blink::PortInfoPtr info) {
+ outputs_.push_back(*info);
+ for (auto* accessor : AccessorList(accessors_)) {
+ accessor->DidAddOutputPort(info->id, info->manufacturer, info->name,
+ info->version, info->state);
+ }
+}
+
+void MIDIDispatcher::SetInputPortState(uint32_t port,
+ midi::mojom::blink::PortState state) {
+ if (inputs_[port].state == state)
+ return;
+ inputs_[port].state = state;
+ for (auto* accessor : AccessorList(accessors_))
+ accessor->DidSetInputPortState(port, state);
+}
+
+void MIDIDispatcher::SetOutputPortState(uint32_t port,
+ midi::mojom::blink::PortState state) {
+ if (outputs_[port].state == state)
+ return;
+ outputs_[port].state = state;
+ for (auto* accessor : AccessorList(accessors_))
+ accessor->DidSetOutputPortState(port, state);
+}
+
+void MIDIDispatcher::SessionStarted(midi::mojom::blink::Result result) {
+ TRACE_EVENT0("midi", "MIDIDispatcher::OnSessionStarted");
+ session_result_ = result;
+
+ // A for-loop using iterators does not work because |accessor| may touch
+ // |accessors_waiting_session_queue_| in callbacks.
+ while (!accessors_waiting_session_queue_.IsEmpty()) {
+ auto* accessor = accessors_waiting_session_queue_.back();
+ accessors_waiting_session_queue_.pop_back();
+ if (result == midi::mojom::blink::Result::OK) {
+ // Add the accessor's input and output ports.
+ for (const auto& info : inputs_) {
+ accessor->DidAddInputPort(info.id, info.manufacturer, info.name,
+ info.version, info.state);
+ }
+
+ for (const auto& info : outputs_) {
+ accessor->DidAddOutputPort(info.id, info.manufacturer, info.name,
+ info.version, info.state);
+ }
+ }
+ accessor->DidStartSession(result);
+ accessors_.push_back(accessor);
+ }
+}
+
+void MIDIDispatcher::AcknowledgeSentData(uint32_t bytes_sent) {
+ DCHECK_GE(unacknowledged_bytes_sent_, bytes_sent);
+ if (unacknowledged_bytes_sent_ >= bytes_sent)
+ unacknowledged_bytes_sent_ -= bytes_sent;
+}
+
+void MIDIDispatcher::DataReceived(uint32_t port,
+ const Vector<uint8_t>& data,
+ base::TimeTicks timestamp) {
+ TRACE_EVENT0("midi", "MIDIDispatcher::DataReceived");
+ DCHECK(!data.IsEmpty());
+
+ for (auto* accessor : AccessorList(accessors_))
+ accessor->DidReceiveMIDIData(port, &data[0], data.size(), timestamp);
+}
+
+midi::mojom::blink::MidiSessionProvider&
+MIDIDispatcher::GetMidiSessionProvider() {
+ if (!midi_session_provider_) {
+ Platform::Current()->GetInterfaceProvider()->GetInterface(
+ mojo::MakeRequest(&midi_session_provider_));
+ }
+ return *midi_session_provider_;
+}
+
+midi::mojom::blink::MidiSession& MIDIDispatcher::GetMidiSession() {
+ DCHECK(midi_session_);
+ return *midi_session_;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h
new file mode 100644
index 00000000000..30be3425dc7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_DISPATCHER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_DISPATCHER_H_
+
+#include "media/midi/midi_service.mojom-blink.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class MIDIAccessor;
+
+class MIDIDispatcher : public GarbageCollectedFinalized<MIDIDispatcher>,
+ public midi::mojom::blink::MidiSessionClient {
+ public:
+ static MIDIDispatcher& Instance();
+ MIDIDispatcher();
+ ~MIDIDispatcher() override;
+
+ void Trace(Visitor* visitor);
+
+ void AddAccessor(MIDIAccessor* accessor);
+ void RemoveAccessor(MIDIAccessor* accessor);
+ void SendMidiData(uint32_t port,
+ const uint8_t* data,
+ wtf_size_t length,
+ base::TimeTicks timestamp);
+
+ // midi::mojom::blink::MidiSessionClient implementation.
+ // All of the following methods are run on the main thread.
+ void AddInputPort(midi::mojom::blink::PortInfoPtr info) override;
+ void AddOutputPort(midi::mojom::blink::PortInfoPtr info) override;
+ void SetInputPortState(uint32_t port,
+ midi::mojom::blink::PortState state) override;
+ void SetOutputPortState(uint32_t port,
+ midi::mojom::blink::PortState state) override;
+ void SessionStarted(midi::mojom::blink::Result result) override;
+ void AcknowledgeSentData(uint32_t bytes) override;
+ void DataReceived(uint32_t port,
+ const Vector<uint8_t>& data,
+ base::TimeTicks timestamp) override;
+
+ private:
+ midi::mojom::blink::MidiSessionProvider& GetMidiSessionProvider();
+ midi::mojom::blink::MidiSession& GetMidiSession();
+
+ // Keeps track of all MIDI accessors.
+ typedef Vector<MIDIAccessor*> AccessorList;
+ AccessorList accessors_;
+
+ // Represents accessors that are waiting for a session being open.
+ typedef Vector<MIDIAccessor*> AccessorQueue;
+ AccessorQueue accessors_waiting_session_queue_;
+
+ // Represents a result on starting a session.
+ midi::mojom::blink::Result session_result_ =
+ midi::mojom::Result::NOT_INITIALIZED;
+
+ // Holds MidiPortInfoList for input ports and output ports.
+ Vector<midi::mojom::blink::PortInfo> inputs_;
+ Vector<midi::mojom::blink::PortInfo> outputs_;
+
+ size_t unacknowledged_bytes_sent_ = 0u;
+
+ midi::mojom::blink::MidiSessionProviderPtr midi_session_provider_;
+ midi::mojom::blink::MidiSessionPtr midi_session_;
+
+ mojo::Binding<midi::mojom::blink::MidiSessionClient> binding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_DISPATCHER_H_
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_port.idl b/chromium/third_party/blink/renderer/modules/webmidi/midi_port.idl
index 7699de27ba7..eddf0f0983b 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_port.idl
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_port.idl
@@ -65,6 +65,6 @@ enum MIDIPortType {
attribute EventHandler onstatechange;
- [CallWith=ScriptState] Promise open();
- [CallWith=ScriptState] Promise close();
+ [CallWith=ScriptState] Promise<MIDIPort> open();
+ [CallWith=ScriptState] Promise<MIDIPort> close();
};
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.idl b/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.idl
index da51aec8eb7..fbc72c1d219 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.idl
+++ b/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.idl
@@ -33,8 +33,5 @@
[
ImplementedAs=NavigatorWebMIDI
] partial interface Navigator {
- [
- CallWith = ScriptState, MeasureAs = RequestMIDIAccess_ObscuredByFootprinting
- ] Promise
- requestMIDIAccess(optional MIDIOptions options);
+ [CallWith=ScriptState, MeasureAs=RequestMIDIAccess_ObscuredByFootprinting] Promise<MIDIAccess> requestMIDIAccess(optional MIDIOptions options);
};
diff --git a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
index 261658ce0a5..c6186163359 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/fileapi/file.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/modules/webshare/share_data.h"
@@ -35,6 +36,37 @@ String ErrorToString(mojom::blink::ShareError error) {
return String();
}
+bool HasFiles(const ShareData& share_data) {
+ if (!RuntimeEnabledFeatures::WebShareV2Enabled() || !share_data.hasFiles())
+ return false;
+
+ const HeapVector<Member<File>>& files = share_data.files();
+ return !files.IsEmpty();
+}
+
+// Returns a message for a TypeError if share(share_data) would reject with
+// TypeError. https://wicg.github.io/web-share/level-2/#canshare-method
+// Otherwise returns an empty string.
+// Populates full_url with the result of running the URL parser on
+// share_data.url
+String CheckForTypeError(const Document& doc,
+ const ShareData& share_data,
+ KURL* full_url) {
+ if (!share_data.hasTitle() && !share_data.hasText() && !share_data.hasURL() &&
+ !HasFiles(share_data)) {
+ return "No known share data fields supplied. If using only new fields "
+ "(other than title, text and url), you must feature-detect "
+ "them first.";
+ }
+
+ *full_url = doc.CompleteURL(share_data.url());
+ if (!full_url->IsNull() && !full_url->IsValid()) {
+ return "Invalid URL";
+ }
+
+ return g_empty_string;
+}
+
} // namespace
class NavigatorShare::ShareClientImpl final
@@ -100,23 +132,27 @@ NavigatorShare::NavigatorShare() = default;
const char NavigatorShare::kSupplementName[] = "NavigatorShare";
-ScriptPromise NavigatorShare::share(ScriptState* script_state,
- const ShareData* share_data) {
+bool NavigatorShare::canShare(ScriptState* script_state,
+ const ShareData* share_data) {
Document* doc = To<Document>(ExecutionContext::From(script_state));
+ KURL full_url;
+ return CheckForTypeError(*doc, *share_data, &full_url).IsEmpty();
+}
- if (!share_data->hasTitle() && !share_data->hasText() &&
- !share_data->hasURL()) {
- v8::Local<v8::Value> error = V8ThrowException::CreateTypeError(
- script_state->GetIsolate(),
- "No known share data fields supplied. If using only new fields (other "
- "than title, text and url), you must feature-detect them first.");
- return ScriptPromise::Reject(script_state, error);
- }
+bool NavigatorShare::canShare(ScriptState* script_state,
+ Navigator& navigator,
+ const ShareData* share_data) {
+ return From(navigator).canShare(script_state, share_data);
+}
- KURL full_url = doc->CompleteURL(share_data->url());
- if (!full_url.IsNull() && !full_url.IsValid()) {
+ScriptPromise NavigatorShare::share(ScriptState* script_state,
+ const ShareData* share_data) {
+ Document* doc = To<Document>(ExecutionContext::From(script_state));
+ KURL full_url;
+ String error_message = CheckForTypeError(*doc, *share_data, &full_url);
+ if (!error_message.IsEmpty()) {
v8::Local<v8::Value> error = V8ThrowException::CreateTypeError(
- script_state->GetIsolate(), "Invalid URL");
+ script_state->GetIsolate(), error_message);
return ScriptPromise::Reject(script_state, error);
}
@@ -137,7 +173,9 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
return ScriptPromise::RejectWithDOMException(script_state, error);
}
- frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
+ // See https://bit.ly/2S0zRAS for task types.
+ frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(
+ &service_, frame->GetTaskRunner(TaskType::kMiscPlatformAPI)));
service_.set_connection_error_handler(WTF::Bind(
&NavigatorShare::OnConnectionError, WrapWeakPersistent(this)));
DCHECK(service_);
diff --git a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.h b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.h
index b2ec8047a5c..fa04739b2be 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.h
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.h
@@ -36,6 +36,8 @@ class NavigatorShare final : public GarbageCollectedFinalized<NavigatorShare>,
static NavigatorShare& From(Navigator&);
// Navigator partial interface
+ bool canShare(ScriptState*, const ShareData*);
+ static bool canShare(ScriptState*, Navigator&, const ShareData*);
ScriptPromise share(ScriptState*, const ShareData*);
static ScriptPromise share(ScriptState*, Navigator&, const ShareData*);
diff --git a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.idl b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.idl
index 75f5b90c815..0c20961e11e 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.idl
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.idl
@@ -8,6 +8,9 @@
ImplementedAs=NavigatorShare,
RuntimeEnabled=WebShare
] partial interface Navigator {
+ [SecureContext, CallWith=ScriptState, MeasureAs=WebShareCanShare, RuntimeEnabled=WebShareV2]
+ boolean canShare(optional ShareData data);
+
[SecureContext, CallWith=ScriptState, MeasureAs=WebShareShare]
Promise<void> share(optional ShareData data);
};
diff --git a/chromium/third_party/blink/renderer/modules/webshare/share_data.idl b/chromium/third_party/blink/renderer/modules/webshare/share_data.idl
index 3911fe7940c..d9b8a86159c 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/share_data.idl
+++ b/chromium/third_party/blink/renderer/modules/webshare/share_data.idl
@@ -8,4 +8,5 @@ dictionary ShareData {
USVString title;
USVString text;
USVString url;
+ [RuntimeEnabled=WebShareV2] FrozenArray<File> files;
};
diff --git a/chromium/third_party/blink/renderer/modules/websockets/close_event.h b/chromium/third_party/blink/renderer/modules/websockets/close_event.h
index 96f686e616b..14c2774ec5a 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/close_event.h
+++ b/chromium/third_party/blink/renderer/modules/websockets/close_event.h
@@ -46,19 +46,27 @@ class CloseEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
- static CloseEvent* Create() { return new CloseEvent(); }
+ static CloseEvent* Create() { return MakeGarbageCollected<CloseEvent>(); }
static CloseEvent* Create(bool was_clean,
unsigned short code,
const String& reason) {
- return new CloseEvent(was_clean, code, reason);
+ return MakeGarbageCollected<CloseEvent>(was_clean, code, reason);
}
static CloseEvent* Create(const AtomicString& type,
const CloseEventInit* initializer) {
- return new CloseEvent(type, initializer);
+ return MakeGarbageCollected<CloseEvent>(type, initializer);
}
+ CloseEvent() : was_clean_(false), code_(0) {}
+ CloseEvent(bool was_clean, int code, const String& reason)
+ : Event(event_type_names::kClose, Bubbles::kNo, Cancelable::kNo),
+ was_clean_(was_clean),
+ code_(code),
+ reason_(reason) {}
+ CloseEvent(const AtomicString& type, const CloseEventInit* initializer);
+
bool wasClean() const { return was_clean_; }
unsigned short code() const { return code_; }
String reason() const { return reason_; }
@@ -71,16 +79,6 @@ class CloseEvent final : public Event {
void Trace(blink::Visitor* visitor) override { Event::Trace(visitor); }
private:
- CloseEvent() : was_clean_(false), code_(0) {}
-
- CloseEvent(bool was_clean, int code, const String& reason)
- : Event(event_type_names::kClose, Bubbles::kNo, Cancelable::kNo),
- was_clean_(was_clean),
- code_(code),
- reason_(reason) {}
-
- CloseEvent(const AtomicString& type, const CloseEventInit* initializer);
-
bool was_clean_;
unsigned short code_;
String reason_;
diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
index 68dc041aa60..b75ba886664 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -312,7 +312,7 @@ void DOMWebSocket::Connect(const String& url,
if ((upgrade_insecure_requests_set ||
MixedContentChecker::ShouldAutoupgrade(
- GetExecutionContext()->Url(),
+ GetExecutionContext()->GetHttpsState(),
WebMixedContentContextType::kBlockable)) &&
url_.Protocol() == "ws" &&
!SecurityOrigin::Create(url_)->IsPotentiallyTrustworthy()) {
@@ -690,11 +690,11 @@ bool DOMWebSocket::HasPendingActivity() const {
return channel_ || !event_queue_->IsEmpty();
}
-void DOMWebSocket::Pause() {
+void DOMWebSocket::ContextPaused(PauseState) {
event_queue_->Pause();
}
-void DOMWebSocket::Unpause() {
+void DOMWebSocket::ContextUnpaused() {
event_queue_->Unpause();
// If |consumed_buffered_amount_| was updated while the object was paused then
diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h
index b9e6bc94dc4..e4481bc0b84 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h
@@ -37,7 +37,7 @@
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/dom/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -124,8 +124,8 @@ class MODULES_EXPORT DOMWebSocket : public EventTargetWithInlineData,
// PausableObject functions.
void ContextDestroyed(ExecutionContext*) override;
- void Pause() override;
- void Unpause() override;
+ void ContextPaused(PauseState) override;
+ void ContextUnpaused() override;
// ScriptWrappable functions.
// Prevent this instance from being collected while it's not in CLOSED
diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index 784928d791f..61aa324ad53 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -44,7 +44,7 @@ typedef testing::StrictMock<testing::MockFunction<void(int)>>
class MockWebSocketChannel : public WebSocketChannel {
public:
static MockWebSocketChannel* Create() {
- return new testing::StrictMock<MockWebSocketChannel>();
+ return MakeGarbageCollected<testing::StrictMock<MockWebSocketChannel>>();
}
~MockWebSocketChannel() override = default;
@@ -81,11 +81,16 @@ class DOMWebSocketWithMockChannel final : public DOMWebSocket {
public:
static DOMWebSocketWithMockChannel* Create(ExecutionContext* context) {
DOMWebSocketWithMockChannel* websocket =
- new DOMWebSocketWithMockChannel(context);
+ MakeGarbageCollected<DOMWebSocketWithMockChannel>(context);
websocket->PauseIfNeeded();
return websocket;
}
+ explicit DOMWebSocketWithMockChannel(ExecutionContext* context)
+ : DOMWebSocket(context),
+ channel_(MockWebSocketChannel::Create()),
+ has_created_channel_(false) {}
+
MockWebSocketChannel* Channel() { return channel_.Get(); }
WebSocketChannel* CreateChannel(ExecutionContext*,
@@ -101,11 +106,6 @@ class DOMWebSocketWithMockChannel final : public DOMWebSocket {
}
private:
- explicit DOMWebSocketWithMockChannel(ExecutionContext* context)
- : DOMWebSocket(context),
- channel_(MockWebSocketChannel::Create()),
- has_created_channel_(false) {}
-
Member<MockWebSocketChannel> channel_;
bool has_created_channel_;
};
@@ -280,7 +280,8 @@ TEST(DOMWebSocketTest, mixedContentAutoUpgrade) {
Connect(KURL("wss://example.com/endpoint"), String()))
.WillOnce(Return(true));
}
- scope.GetDocument().SetURL(KURL("https://example.com"));
+ scope.GetDocument().SetSecurityOrigin(
+ SecurityOrigin::Create(KURL("https://example.com")));
scope.GetDocument().SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone);
websocket_scope.Socket().Connect("ws://example.com/endpoint",
Vector<String>(), scope.GetExceptionState());
diff --git a/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc b/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc
index 52655c4b097..4d6c3cbc1c6 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc
@@ -32,12 +32,10 @@
#include <stddef.h>
#include <memory>
-#include "third_party/blink/public/platform/web_feature.mojom-shared.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/web/web_array_buffer.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/inspector/console_types.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/modules/websockets/web_pepper_socket_channel_client_proxy.h"
@@ -66,7 +64,6 @@ WebPepperSocketImpl::WebPepperSocketImpl(const WebDocument& document,
Document* core_document = document;
private_ = WebSocketChannelImpl::Create(core_document, channel_proxy_.Get(),
SourceLocation::Capture());
- Deprecation::CountDeprecation(*core_document, WebFeature::kPPAPIWebSocket);
DCHECK(private_);
}
@@ -157,7 +154,7 @@ void WebPepperSocketImpl::DidError() {
client_->DidReceiveMessageError();
}
-void WebPepperSocketImpl::DidConsumeBufferedAmount(unsigned long consumed) {
+void WebPepperSocketImpl::DidConsumeBufferedAmount(uint64_t consumed) {
client_->DidConsumeBufferedAmount(consumed);
// FIXME: Deprecate the following statements.
diff --git a/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.h b/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.h
index 3a758e864f6..fd3aa86f455 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.h
+++ b/chromium/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.h
@@ -67,7 +67,7 @@ class WebPepperSocketImpl final : public WebPepperSocket {
void DidReceiveTextMessage(const String& payload);
void DidReceiveBinaryMessage(std::unique_ptr<Vector<char>> payload);
void DidError();
- void DidConsumeBufferedAmount(unsigned long consumed);
+ void DidConsumeBufferedAmount(uint64_t consumed);
void DidStartClosingHandshake();
void DidClose(WebSocketChannelClient::ClosingHandshakeCompletionStatus,
unsigned short code,
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
index 16f5c53bf85..2440eafec47 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -278,11 +278,9 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) {
void WebSocketChannelImpl::Send(const CString& message) {
NETWORK_DVLOG(1) << this << " Send(" << message << ") (CString argument)";
- // FIXME: Change the inspector API to show the entire message instead
- // of individual frames.
- probe::didSendWebSocketFrame(execution_context_, identifier_,
- WebSocketOpCode::kOpCodeText, true,
- message.data(), message.length());
+ probe::didSendWebSocketMessage(execution_context_, identifier_,
+ WebSocketOpCode::kOpCodeText, true,
+ message.data(), message.length());
messages_.push_back(MakeGarbageCollected<Message>(message));
ProcessSendQueue();
}
@@ -293,13 +291,11 @@ void WebSocketChannelImpl::Send(
<< blob_data_handle->GetType() << ", "
<< blob_data_handle->size() << ") "
<< "(BlobDataHandle argument)";
- // FIXME: Change the inspector API to show the entire message instead
- // of individual frames.
// FIXME: We can't access the data here.
// Since Binary data are not displayed in Inspector, this does not
// affect actual behavior.
- probe::didSendWebSocketFrame(execution_context_, identifier_,
- WebSocketOpCode::kOpCodeBinary, true, "", 0);
+ probe::didSendWebSocketMessage(execution_context_, identifier_,
+ WebSocketOpCode::kOpCodeBinary, true, "", 0);
messages_.push_back(
MakeGarbageCollected<Message>(std::move(blob_data_handle)));
ProcessSendQueue();
@@ -311,9 +307,7 @@ void WebSocketChannelImpl::Send(const DOMArrayBuffer& buffer,
NETWORK_DVLOG(1) << this << " Send(" << buffer.Data() << ", " << byte_offset
<< ", " << byte_length << ") "
<< "(DOMArrayBuffer argument)";
- // FIXME: Change the inspector API to show the entire message instead
- // of individual frames.
- probe::didSendWebSocketFrame(
+ probe::didSendWebSocketMessage(
execution_context_, identifier_, WebSocketOpCode::kOpCodeBinary, true,
static_cast<const char*>(buffer.Data()) + byte_offset, byte_length);
// buffer.slice copies its contents.
@@ -329,11 +323,9 @@ void WebSocketChannelImpl::SendTextAsCharVector(
NETWORK_DVLOG(1) << this << " SendTextAsCharVector("
<< static_cast<void*>(data.get()) << ", " << data->size()
<< ")";
- // FIXME: Change the inspector API to show the entire message instead
- // of individual frames.
- probe::didSendWebSocketFrame(execution_context_, identifier_,
- WebSocketOpCode::kOpCodeText, true, data->data(),
- data->size());
+ probe::didSendWebSocketMessage(execution_context_, identifier_,
+ WebSocketOpCode::kOpCodeText, true,
+ data->data(), data->size());
messages_.push_back(MakeGarbageCollected<Message>(
std::move(data), kMessageTypeTextAsCharVector));
ProcessSendQueue();
@@ -344,11 +336,9 @@ void WebSocketChannelImpl::SendBinaryAsCharVector(
NETWORK_DVLOG(1) << this << " SendBinaryAsCharVector("
<< static_cast<void*>(data.get()) << ", " << data->size()
<< ")";
- // FIXME: Change the inspector API to show the entire message instead
- // of individual frames.
- probe::didSendWebSocketFrame(execution_context_, identifier_,
- WebSocketOpCode::kOpCodeBinary, true,
- data->data(), data->size());
+ probe::didSendWebSocketMessage(execution_context_, identifier_,
+ WebSocketOpCode::kOpCodeBinary, true,
+ data->data(), data->size());
messages_.push_back(MakeGarbageCollected<Message>(
std::move(data), kMessageTypeBinaryAsCharVector));
ProcessSendQueue();
@@ -367,7 +357,8 @@ void WebSocketChannelImpl::Fail(const String& reason,
MessageLevel level,
std::unique_ptr<SourceLocation> location) {
NETWORK_DVLOG(1) << this << " Fail(" << reason << ")";
- probe::didReceiveWebSocketFrameError(execution_context_, identifier_, reason);
+ probe::didReceiveWebSocketMessageError(execution_context_, identifier_,
+ reason);
const String message =
"WebSocket connection to '" + url_.ElidedString() + "' failed: " + reason;
@@ -659,14 +650,12 @@ void WebSocketChannelImpl::DidReceiveData(WebSocketHandle* handle,
if (!fin) {
return;
}
- // FIXME: Change the inspector API to show the entire message instead
- // of individual frames.
auto opcode = receiving_message_type_is_text_
? WebSocketOpCode::kOpCodeText
: WebSocketOpCode::kOpCodeBinary;
- probe::didReceiveWebSocketFrame(execution_context_, identifier_, opcode,
- false, receiving_message_data_.data(),
- receiving_message_data_.size());
+ probe::didReceiveWebSocketMessage(execution_context_, identifier_, opcode,
+ false, receiving_message_data_.data(),
+ receiving_message_data_.size());
if (receiving_message_type_is_text_) {
String message = receiving_message_data_.IsEmpty()
? g_empty_string
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
index c13eb980d9f..a92e0072e9c 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
@@ -46,7 +46,8 @@ class MockWebSocketChannelClient
public:
static MockWebSocketChannelClient* Create() {
- return new testing::StrictMock<MockWebSocketChannelClient>();
+ return MakeGarbageCollected<
+ testing::StrictMock<MockWebSocketChannelClient>>();
}
MockWebSocketChannelClient() = default;
@@ -157,7 +158,7 @@ class WebSocketChannelImplTest : public PageTestBase {
MockWebSocketHandle* Handle() { return handle_; }
- void DidConsumeBufferedAmount(unsigned long a) {
+ void DidConsumeBufferedAmount(uint64_t a) {
sum_of_consumed_buffered_amount_ += a;
}
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc
index 981a4fed359..ae26f0ebb25 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc
@@ -58,7 +58,8 @@ void WebSocketHandleImpl::Connect(network::mojom::blink::WebSocketPtr websocket,
additional_headers.push_back(network::mojom::blink::HttpHeader::New(
http_names::kUserAgent, user_agent_override));
}
- client_binding_.Bind(mojo::MakeRequest(&client_proxy, task_runner));
+ client_binding_.Bind(mojo::MakeRequest(&client_proxy, task_runner),
+ task_runner);
websocket_->AddChannelRequest(url, protocols, site_for_cookies,
std::move(additional_headers),
std::move(client_proxy));
diff --git a/chromium/third_party/blink/renderer/modules/webusb/README.md b/chromium/third_party/blink/renderer/modules/webusb/README.md
index defb91149b7..0a64688cedc 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/README.md
+++ b/chromium/third_party/blink/renderer/modules/webusb/README.md
@@ -11,7 +11,7 @@ for the [WebUSB specification]. It communicates with the browser process through
## Testing
WebUSB is primarily tested in [Web Platform Tests].
-Chromium implementation details are tested in [Layout Tests].
+Chromium implementation details are tested in [web tests].
[Web Platform Tests]: ../../../web_tests/external/wpt/webusb/
-[Layout Tests]: ../../../web_tests/usb/
+[Web tests]: ../../../web_tests/usb/
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb.cc b/chromium/third_party/blink/renderer/modules/webusb/usb.cc
index d41521b2556..b834a2d8615 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb.cc
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb.cc
@@ -292,15 +292,18 @@ void USB::EnsureServiceConnection() {
DCHECK(IsContextSupported());
DCHECK(GetFeatureEnabledState() != FeatureEnabledState::kDisabled);
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
GetExecutionContext()->GetInterfaceProvider()->GetInterface(
- mojo::MakeRequest(&service_));
+ mojo::MakeRequest(&service_, task_runner));
service_.set_connection_error_handler(
WTF::Bind(&USB::OnServiceConnectionError, WrapWeakPersistent(this)));
DCHECK(!client_binding_.is_bound());
device::mojom::blink::UsbDeviceManagerClientAssociatedPtrInfo client;
- client_binding_.Bind(mojo::MakeRequest(&client));
+ client_binding_.Bind(mojo::MakeRequest(&client), task_runner);
service_->SetClient(std::move(client));
}
diff --git a/chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc b/chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
index 0928a5e240a..f021033a5d2 100644
--- a/chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
+++ b/chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
@@ -58,8 +58,8 @@ class AnimationAndPaintWorkletThreadTest : public PageTestBase {
std::unique_ptr<AnimationAndPaintWorkletThread>
CreateAnimationAndPaintWorkletThread() {
WorkerClients* clients = WorkerClients::Create();
- ProvideAnimationWorkletProxyClientTo(clients,
- new TestAnimationWorkletProxyClient());
+ ProvideAnimationWorkletProxyClientTo(
+ clients, MakeGarbageCollected<TestAnimationWorkletProxyClient>());
std::unique_ptr<AnimationAndPaintWorkletThread> thread =
AnimationAndPaintWorkletThread::CreateForAnimationWorklet(
@@ -67,14 +67,16 @@ class AnimationAndPaintWorkletThreadTest : public PageTestBase {
Document* document = &GetDocument();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule, document->UserAgent(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
- document->GetReferrerPolicy(), document->GetSecurityOrigin(),
- document->IsSecureContext(), document->GetHttpsState(), clients,
- document->AddressSpace(),
+ document->Url(), mojom::ScriptType::kModule,
+ OffMainThreadWorkerScriptFetchOption::kEnabled,
+ document->UserAgent(), nullptr /* web_worker_fetch_context */,
+ Vector<CSPHeaderAndType>(), document->GetReferrerPolicy(),
+ document->GetSecurityOrigin(), document->IsSecureContext(),
+ document->GetHttpsState(), clients, document->AddressSpace(),
OriginTrialContext::GetTokens(document).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, new WorkletModuleResponsesMap),
+ kV8CacheOptionsDefault,
+ MakeGarbageCollected<WorkletModuleResponsesMap>()),
base::nullopt, std::make_unique<WorkerDevToolsParams>(),
ParentExecutionContextTaskRunners::Create());
return thread;
diff --git a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
index e742a893b65..0f4806e5575 100644
--- a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -8,18 +8,12 @@ blink_modules_sources("xr") {
sources = [
"xr.cc",
"xr.h",
+ "xr_bounded_reference_space.cc",
+ "xr_bounded_reference_space.h",
"xr_canvas_input_provider.cc",
"xr_canvas_input_provider.h",
- "xr_coordinate_system.cc",
- "xr_coordinate_system.h",
- "xr_device.cc",
- "xr_device.h",
- "xr_device_pose.cc",
- "xr_device_pose.h",
"xr_frame.cc",
"xr_frame.h",
- "xr_frame_of_reference.cc",
- "xr_frame_of_reference.h",
"xr_frame_provider.cc",
"xr_frame_provider.h",
"xr_frame_request_callback_collection.cc",
@@ -38,16 +32,28 @@ blink_modules_sources("xr") {
"xr_presentation_context.h",
"xr_ray.cc",
"xr_ray.h",
+ "xr_reference_space.cc",
+ "xr_reference_space.h",
+ "xr_rigid_transform.cc",
+ "xr_rigid_transform.h",
"xr_session.cc",
"xr_session.h",
"xr_session_event.cc",
"xr_session_event.h",
+ "xr_space.cc",
+ "xr_space.h",
"xr_stage_bounds.cc",
"xr_stage_bounds.h",
+ "xr_stationary_reference_space.cc",
+ "xr_stationary_reference_space.h",
+ "xr_unbounded_reference_space.cc",
+ "xr_unbounded_reference_space.h",
"xr_utils.cc",
"xr_utils.h",
"xr_view.cc",
"xr_view.h",
+ "xr_viewer_pose.cc",
+ "xr_viewer_pose.h",
"xr_viewport.h",
"xr_webgl_layer.cc",
"xr_webgl_layer.h",
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.cc b/chromium/third_party/blink/renderer/modules/xr/xr.cc
index 95500107a54..a13967d07d1 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr.cc
@@ -12,9 +12,12 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/event_modules.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -27,24 +30,64 @@ const char kNavigatorDetachedError[] =
const char kFeaturePolicyBlocked[] =
"Access to the feature \"xr\" is disallowed by feature policy.";
-const char kNoDevicesMessage[] = "No devices found.";
+const char kActiveImmersiveSession[] =
+ "There is already an active, immersive XRSession.";
+
+const char kNoOutputContext[] =
+ "Inline sessions must be created with an outputContext.";
+
+const char kRequestRequiresUserActivation[] =
+ "The requested session requires user activation.";
+
+const char kSessionNotSupported[] =
+ "The specified session configuration is not supported.";
+
+const char kNoDevicesMessage[] = "No XR hardware found.";
+
+// Helper method to convert session mode into Mojo options.
+device::mojom::blink::XRSessionOptionsPtr convertModeToMojo(
+ XRSession::SessionMode mode) {
+ auto session_options = device::mojom::blink::XRSessionOptions::New();
+ session_options->immersive = (mode == XRSession::kModeImmersiveVR ||
+ mode == XRSession::kModeImmersiveAR);
+ session_options->environment_integration =
+ (mode == XRSession::kModeInlineAR || mode == XRSession::kModeImmersiveAR);
+
+ return session_options;
+}
} // namespace
+XR::PendingSessionQuery::PendingSessionQuery(
+ ScriptPromiseResolver* resolver,
+ XRSession::SessionMode session_mode)
+ : resolver(resolver), mode(session_mode) {}
+
+void XR::PendingSessionQuery::Trace(blink::Visitor* visitor) {
+ visitor->Trace(resolver);
+ visitor->Trace(output_context);
+}
+
XR::XR(LocalFrame& frame, int64_t ukm_source_id)
: ContextLifecycleObserver(frame.GetDocument()),
FocusChangedObserver(frame.GetPage()),
ukm_source_id_(ukm_source_id),
binding_(this) {
- frame.GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
+ // See https://bit.ly/2S0zRAS for task types.
+ frame.GetInterfaceProvider().GetInterface(mojo::MakeRequest(
+ &service_, frame.GetTaskRunner(TaskType::kMiscPlatformAPI)));
service_.set_connection_error_handler(
WTF::Bind(&XR::Dispose, WrapWeakPersistent(this)));
}
void XR::FocusedFrameChanged() {
- // Tell device that focus changed.
- if (device_)
- device_->OnFrameFocusChanged();
+ // Tell all sessions that focus changed.
+ for (const auto& session : sessions_) {
+ session->OnFocusChanged();
+ }
+
+ if (frame_provider_)
+ frame_provider_->OnFocusChanged();
}
bool XR::IsFrameFocused() {
@@ -59,7 +102,34 @@ const AtomicString& XR::InterfaceName() const {
return event_target_names::kXR;
}
-ScriptPromise XR::requestDevice(ScriptState* script_state) {
+XRFrameProvider* XR::frameProvider() {
+ if (!frame_provider_) {
+ frame_provider_ = MakeGarbageCollected<XRFrameProvider>(this);
+ }
+
+ return frame_provider_;
+}
+
+const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr&
+XR::xrEnvironmentProviderPtr() {
+ return environment_provider_;
+}
+
+const char* XR::checkSessionSupport(
+ const XRSessionCreationOptions* options) const {
+ if (options->mode() == "inline" || options->mode() == "legacy-inline-ar") {
+ // Validation for inline sessions. (Validation for immersive sessions
+ // happens browser-side.)
+ if (!options->hasOutputContext()) {
+ return kNoOutputContext;
+ }
+ }
+
+ return nullptr;
+}
+
+ScriptPromise XR::supportsSessionMode(ScriptState* script_state,
+ const String& mode) {
LocalFrame* frame = GetFrame();
if (!frame) {
// Reject if the frame is inaccessible.
@@ -68,13 +138,6 @@ ScriptPromise XR::requestDevice(ScriptState* script_state) {
kNavigatorDetachedError));
}
- if (!did_log_requestDevice_ && frame->GetDocument()) {
- ukm::builders::XR_WebXR(ukm_source_id_)
- .SetDidRequestAvailableDevices(1)
- .Record(frame->GetDocument()->UkmRecorder());
- did_log_requestDevice_ = true;
- }
-
if (!frame->GetDocument()->IsFeatureEnabled(
mojom::FeaturePolicyFeature::kWebVr,
ReportOptions::kReportOnFailure)) {
@@ -85,94 +148,288 @@ ScriptPromise XR::requestDevice(ScriptState* script_state) {
kFeaturePolicyBlocked));
}
- // If we're still waiting for a previous call to resolve return that promise
- // again.
- if (pending_devices_resolver_) {
- return pending_devices_resolver_->Promise();
- }
-
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
+ if (mode == "inline") {
+ // `inline` sessions are always supported if not blocked by feature policy.
+ resolver->Resolve();
+ } else {
+ // For all other modes we need to check with the service.
+ PendingSessionQuery* query = MakeGarbageCollected<PendingSessionQuery>(
+ resolver, XRSession::stringToSessionMode(mode));
+
+ if (!device_) {
+ pending_mode_queries_.push_back(query);
+
+ // The pending queries will be resolved once the device is returned.
+ EnsureDevice();
+ } else {
+ DispatchSupportsSessionMode(query);
+ }
+ }
+
+ return promise;
+}
+
+void XR::DispatchSupportsSessionMode(PendingSessionQuery* query) {
+ if (!device_) {
+ // If we don't have a device by the time we reach this call it indicates
+ // that there's no WebXR hardware. Reject as not supported.
+ query->resolver->Reject(DOMException::Create(
+ DOMExceptionCode::kNotSupportedError, kSessionNotSupported));
+ return;
+ }
+
+ device::mojom::blink::XRSessionOptionsPtr session_options =
+ convertModeToMojo(query->mode);
+
+ device_->SupportsSession(
+ std::move(session_options),
+ WTF::Bind(&XR::OnSupportsSessionReturned, WrapPersistent(this),
+ WrapPersistent(query)));
+}
+
+ScriptPromise XR::requestSession(ScriptState* script_state,
+ const XRSessionCreationOptions* options) {
+ LocalFrame* frame = GetFrame();
+ if (!frame) {
+ // Reject if the frame is inaccessible.
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
+ kNavigatorDetachedError));
+ }
+
+ Document* doc = frame->GetDocument();
+ bool immersive =
+ (options->mode() == "immersive-vr" || options->mode() == "immersive-ar");
+ if (immersive && !did_log_request_immersive_session_ && doc) {
+ ukm::builders::XR_WebXR(GetSourceId())
+ .SetDidRequestPresentation(1)
+ .Record(doc->UkmRecorder());
+ did_log_request_immersive_session_ = true;
+ }
+
+ if (!doc->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
+ ReportOptions::kReportOnFailure)) {
+ // Only allow the call to be made if the appropriate feature policy is in
+ // place.
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
+ kFeaturePolicyBlocked));
+ }
+
// If we no longer have a valid service connection reject the request.
if (!service_) {
- resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError,
- kNoDevicesMessage));
- return promise;
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kNotFoundError,
+ kNoDevicesMessage));
}
- // If we already have a device, use that.
- if (device_) {
- resolver->Resolve(device_);
- return promise;
+ // Check first to see if the device is capable of supporting the requested
+ // options.
+ const char* reject_reason = checkSessionSupport(options);
+ if (reject_reason) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
+ reject_reason));
}
- // Otherwise wait for device request callback.
- pending_devices_resolver_ = resolver;
+ // TODO(ijamardo): Should we just exit if there is not document?
+ bool has_user_activation =
+ LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr);
+
+ // Check if the current page state prevents the requested session from being
+ // created.
+ if (options->mode() == "immersive-vr" || options->mode() == "immersive-ar") {
+ if (frameProvider()->immersive_session()) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(DOMExceptionCode::kInvalidStateError,
+ kActiveImmersiveSession));
+ }
- // If we're waiting for sync, then request device is already underway.
- if (pending_sync_) {
- return promise;
+ if (!has_user_activation) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
+ kRequestRequiresUserActivation));
+ }
}
- service_->RequestDevice(
- WTF::Bind(&XR::OnRequestDeviceReturned, WrapPersistent(this)));
- pending_sync_ = true;
+ // All AR sessions require a user gesture.
+ if (options->mode() == "legacy-inline-ar") {
+ if (!has_user_activation) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
+ kRequestRequiresUserActivation));
+ }
+
+ doc->AddConsoleMessage(ConsoleMessage::Create(
+ kOtherMessageSource, kWarningMessageLevel,
+ "Inline AR is deprecated and will be removed soon."));
+ }
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ PendingSessionQuery* query = MakeGarbageCollected<PendingSessionQuery>(
+ resolver, XRSession::stringToSessionMode(options->mode()));
+ query->output_context =
+ options->hasOutputContext() ? options->outputContext() : nullptr;
+ query->has_user_activation = has_user_activation;
+
+ if (!device_) {
+ pending_session_requests_.push_back(query);
+
+ // The pending queries will be resolved once the device is returned.
+ EnsureDevice();
+ } else {
+ DispatchRequestSession(query);
+ }
return promise;
}
-// This will call when the XRDevice and its capabilities has potentially
+void XR::DispatchRequestSession(PendingSessionQuery* query) {
+ if (!device_) {
+ // If we don't have a device by the time we reach this call it indicates
+ // that there's no WebXR hardware. Reject as not supported.
+ query->resolver->Reject(DOMException::Create(
+ DOMExceptionCode::kNotSupportedError, kSessionNotSupported));
+ return;
+ }
+
+ device::mojom::blink::XRSessionOptionsPtr session_options =
+ convertModeToMojo(query->mode);
+ session_options->has_user_activation = query->has_user_activation;
+
+ // TODO(http://crbug.com/826899) Once device activation is sorted out for
+ // WebXR, either pass in the correct value for metrics to know whether
+ // this was triggered by device activation, or remove the value as soon as
+ // legacy API has been removed.
+ device_->RequestSession(
+ std::move(session_options), false /* triggered by display activate */,
+ WTF::Bind(&XR::OnRequestSessionReturned, WrapWeakPersistent(this),
+ WrapPersistent(query)));
+}
+
+void XR::EnsureDevice() {
+ // Exit if we have a device or are waiting for a device.
+ if (device_ || pending_device_) {
+ return;
+ }
+
+ service_->RequestDevice(
+ WTF::Bind(&XR::OnRequestDeviceReturned, WrapPersistent(this)));
+ pending_device_ = true;
+}
+
+// This will be called when the XR hardware or capabilities have potentially
// changed. For example, if a new physical device was connected to the system,
-// the XRDevice might now be able to support immersive sessions, where it
-// couldn't before.
+// it might be able to support immersive sessions, where it couldn't before.
void XR::OnDeviceChanged() {
DispatchEvent(*blink::Event::Create(event_type_names::kDevicechange));
}
void XR::OnRequestDeviceReturned(device::mojom::blink::XRDevicePtr device) {
- pending_sync_ = false;
+ pending_device_ = false;
if (device) {
- device_ = MakeGarbageCollected<XRDevice>(this, std::move(device));
+ device_ = std::move(device);
+
+ // Log metrics
+ if (!did_log_returned_device_ || !did_log_supports_immersive_) {
+ Document* doc = GetFrame() ? GetFrame()->GetDocument() : nullptr;
+ if (doc) {
+ ukm::builders::XR_WebXR ukm_builder(ukm_source_id_);
+ ukm_builder.SetReturnedDevice(1);
+ did_log_returned_device_ = true;
+
+ ukm_builder.Record(doc->UkmRecorder());
+
+ device::mojom::blink::XRSessionOptionsPtr session_options =
+ device::mojom::blink::XRSessionOptions::New();
+ session_options->immersive = true;
+
+ // TODO(http://crbug.com/872086) This shouldn't need to be called.
+ // This information should be logged on the browser side.
+ device_->SupportsSession(
+ std::move(session_options),
+ WTF::Bind(&XR::ReportImmersiveSupported, WrapPersistent(this)));
+ }
+ }
}
- ResolveRequestDevice();
+
+ DispatchPendingSessionCalls();
}
-// Called when details for every connected XRDevice has been received.
-void XR::ResolveRequestDevice() {
- if (pending_devices_resolver_) {
- if (!device_) {
- pending_devices_resolver_->Reject(DOMException::Create(
- DOMExceptionCode::kNotFoundError, kNoDevicesMessage));
- } else {
- // Log metrics
- if (!did_log_returned_device_ || !did_log_supports_immersive_) {
- Document* doc = GetFrame() ? GetFrame()->GetDocument() : nullptr;
- if (doc) {
- ukm::builders::XR_WebXR ukm_builder(ukm_source_id_);
- ukm_builder.SetReturnedDevice(1);
- did_log_returned_device_ = true;
-
- ukm_builder.Record(doc->UkmRecorder());
-
- device::mojom::blink::XRSessionOptionsPtr session_options =
- device::mojom::blink::XRSessionOptions::New();
- session_options->immersive = true;
-
- // TODO(http://crbug.com/872086) This shouldn't need to be called.
- // This information should be logged on the browser side.
- device_->xrDevicePtr()->SupportsSession(
- std::move(session_options),
- WTF::Bind(&XR::ReportImmersiveSupported, WrapPersistent(this)));
- }
- }
+void XR::DispatchPendingSessionCalls() {
+ // Process any calls that were waiting for the device query to be returned.
+ for (auto& query : pending_mode_queries_) {
+ DispatchSupportsSessionMode(query);
+ }
+ pending_mode_queries_.clear();
- // Return the device.
- pending_devices_resolver_->Resolve(device_);
- }
+ for (auto& query : pending_session_requests_) {
+ DispatchRequestSession(query);
+ }
+ pending_session_requests_.clear();
+}
+
+void XR::OnSupportsSessionReturned(PendingSessionQuery* query,
+ bool supports_session) {
+ supports_session
+ ? query->resolver->Resolve()
+ : query->resolver->Reject(DOMException::Create(
+ DOMExceptionCode::kNotSupportedError, kSessionNotSupported));
+}
- pending_devices_resolver_ = nullptr;
+void XR::OnRequestSessionReturned(
+ PendingSessionQuery* query,
+ device::mojom::blink::XRSessionPtr session_ptr) {
+ // TODO(https://crbug.com/872316) Improve the error messaging to indicate why
+ // a request failed.
+ if (!session_ptr) {
+ DOMException* exception = DOMException::Create(
+ DOMExceptionCode::kNotSupportedError, kSessionNotSupported);
+ query->resolver->Reject(exception);
+ return;
}
+
+ bool environment_integration = query->mode == XRSession::kModeInlineAR ||
+ query->mode == XRSession::kModeImmersiveAR;
+
+ // immersive sessions must supply display info.
+ DCHECK(session_ptr->display_info);
+ // If the session supports environment integration, ensure the device does
+ // as well.
+ DCHECK(!environment_integration || session_ptr->display_info->capabilities
+ ->canProvideEnvironmentIntegration);
+
+ XRSession::EnvironmentBlendMode blend_mode = XRSession::kBlendModeOpaque;
+ if (environment_integration)
+ blend_mode = XRSession::kBlendModeAlphaBlend;
+
+ XRSession* session = MakeGarbageCollected<XRSession>(
+ this, std::move(session_ptr->client_request), query->mode,
+ query->output_context, blend_mode);
+ session->SetXRDisplayInfo(std::move(session_ptr->display_info));
+ sessions_.insert(session);
+
+ if (query->mode == XRSession::kModeImmersiveVR ||
+ query->mode == XRSession::kModeImmersiveAR) {
+ frameProvider()->BeginImmersiveSession(session, std::move(session_ptr));
+ } else {
+ magic_window_provider_.Bind(std::move(session_ptr->data_provider));
+ if (environment_integration) {
+ // See https://bit.ly/2S0zRAS for task types.
+ magic_window_provider_->GetEnvironmentIntegrationProvider(
+ mojo::MakeRequest(&environment_provider_,
+ GetExecutionContext()->GetTaskRunner(
+ TaskType::kMiscPlatformAPI)));
+ }
+ }
+
+ query->resolver->Resolve(session);
}
void XR::ReportImmersiveSupported(bool supported) {
@@ -190,19 +447,20 @@ void XR::AddedEventListener(const AtomicString& event_type,
EventTargetWithInlineData::AddedEventListener(event_type,
registered_listener);
- // If we don't have device and there is no sync pending, then request the
- // device to ensure devices have been enumerated and register as a listener
- // for changes.
- if (event_type == event_type_names::kDevicechange && !device_ &&
- !pending_sync_) {
- device::mojom::blink::VRServiceClientPtr client;
- binding_.Bind(mojo::MakeRequest(&client));
-
- service_->RequestDevice(
- WTF::Bind(&XR::OnRequestDeviceReturned, WrapPersistent(this)));
- service_->SetClient(std::move(client));
+ if (event_type == event_type_names::kDevicechange) {
+ // Register for notifications if we haven't already.
+ //
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner =
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ if (!binding_.is_bound()) {
+ device::mojom::blink::VRServiceClientPtr client;
+ binding_.Bind(mojo::MakeRequest(&client, task_runner));
+ service_->SetClient(std::move(client));
+ }
- pending_sync_ = true;
+ // Make sure we have an active device to listen for changes with.
+ EnsureDevice();
}
};
@@ -216,18 +474,18 @@ void XR::Dispose() {
service_.reset();
binding_.Close();
- // Shutdown device's message pipe.
- if (device_)
- device_->Dispose();
+ // Shutdown frame provider, which manages the message pipes.
+ if (frame_provider_)
+ frame_provider_->Dispose();
- // Ensure that any outstanding requestDevice promises are resolved. They will
- // receive a null result.
- ResolveRequestDevice();
+ device_ = nullptr;
}
void XR::Trace(blink::Visitor* visitor) {
- visitor->Trace(device_);
- visitor->Trace(pending_devices_resolver_);
+ visitor->Trace(pending_mode_queries_);
+ visitor->Trace(pending_session_requests_);
+ visitor->Trace(frame_provider_);
+ visitor->Trace(sessions_);
ContextLifecycleObserver::Trace(visitor);
EventTargetWithInlineData::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.h b/chromium/third_party/blink/renderer/modules/xr/xr.h
index 346964a7608..0e885dffe13 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr.h
@@ -12,13 +12,16 @@
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/page/focus_changed_observer.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_session_creation_options.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
class ScriptPromiseResolver;
-class XRDevice;
+class XRFrameProvider;
class XR final : public EventTargetWithInlineData,
public ContextLifecycleObserver,
@@ -36,7 +39,20 @@ class XR final : public EventTargetWithInlineData,
DEFINE_ATTRIBUTE_EVENT_LISTENER(devicechange, kDevicechange);
- ScriptPromise requestDevice(ScriptState*);
+ ScriptPromise supportsSessionMode(ScriptState*, const String&);
+ ScriptPromise requestSession(ScriptState*, const XRSessionCreationOptions*);
+
+ XRFrameProvider* frameProvider();
+
+ const device::mojom::blink::XRDevicePtr& xrDevicePtr() const {
+ return device_;
+ }
+ const device::mojom::blink::XRFrameDataProviderPtr& xrMagicWindowProviderPtr()
+ const {
+ return magic_window_provider_;
+ }
+ const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr&
+ xrEnvironmentProviderPtr();
// VRServiceClient overrides.
void OnDeviceChanged() override;
@@ -56,8 +72,35 @@ class XR final : public EventTargetWithInlineData,
int64_t GetSourceId() const { return ukm_source_id_; }
private:
+ class PendingSessionQuery final
+ : public GarbageCollected<PendingSessionQuery> {
+ WTF_MAKE_NONCOPYABLE(PendingSessionQuery);
+
+ public:
+ PendingSessionQuery(ScriptPromiseResolver*, XRSession::SessionMode);
+ virtual ~PendingSessionQuery() = default;
+
+ virtual void Trace(blink::Visitor*);
+
+ Member<ScriptPromiseResolver> resolver;
+ const XRSession::SessionMode mode;
+ Member<XRPresentationContext> output_context;
+ bool has_user_activation = false;
+ };
+
+ const char* checkSessionSupport(const XRSessionCreationOptions*) const;
+
void OnRequestDeviceReturned(device::mojom::blink::XRDevicePtr device);
- void ResolveRequestDevice();
+ void DispatchPendingSessionCalls();
+
+ void DispatchRequestSession(PendingSessionQuery*);
+ void OnRequestSessionReturned(PendingSessionQuery*,
+ device::mojom::blink::XRSessionPtr);
+
+ void DispatchSupportsSessionMode(PendingSessionQuery*);
+ void OnSupportsSessionReturned(PendingSessionQuery*, bool supports_session);
+
+ void EnsureDevice();
void ReportImmersiveSupported(bool supported);
void AddedEventListener(const AtomicString& event_type,
@@ -65,17 +108,31 @@ class XR final : public EventTargetWithInlineData,
void Dispose();
- bool pending_sync_ = false;
+ bool pending_device_ = false;
// Indicates whether use of requestDevice has already been logged.
bool did_log_requestDevice_ = false;
bool did_log_returned_device_ = false;
bool did_log_supports_immersive_ = false;
+
+ // Indicates whether we've already logged a request for an immersive session.
+ bool did_log_request_immersive_session_ = false;
+
const int64_t ukm_source_id_;
- Member<XRDevice> device_;
- Member<ScriptPromiseResolver> pending_devices_resolver_;
+ // Track calls that were made prior to the internal device successfully being
+ // queried. Can be removed once the service has been updated to allow the
+ // respective calls to be made directly.
+ HeapVector<Member<PendingSessionQuery>> pending_mode_queries_;
+ HeapVector<Member<PendingSessionQuery>> pending_session_requests_;
+
+ Member<XRFrameProvider> frame_provider_;
+ HeapHashSet<WeakMember<XRSession>> sessions_;
device::mojom::blink::VRServicePtr service_;
+ device::mojom::blink::XRDevicePtr device_;
+ device::mojom::blink::XRFrameDataProviderPtr magic_window_provider_;
+ device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr
+ environment_provider_;
mojo::Binding<device::mojom::blink::VRServiceClient> binding_;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.idl b/chromium/third_party/blink/renderer/modules/xr/xr.idl
index de578ac5324..1337c09011f 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr.idl
@@ -9,5 +9,6 @@
OriginTrialEnabled=WebXR
] interface XR : EventTarget {
attribute EventHandler ondevicechange;
- [CallWith=ScriptState, MeasureAs=XRRequestDevice] Promise<XRDevice?> requestDevice();
+ [CallWith=ScriptState, MeasureAs=XRSupportsSession] Promise<void> supportsSessionMode(XRSessionMode mode);
+ [CallWith=ScriptState, MeasureAs=XRRequestSession] Promise<XRSession> requestSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc
new file mode 100644
index 00000000000..443f1172dda
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc
@@ -0,0 +1,83 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h"
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h"
+
+namespace blink {
+
+XRBoundedReferenceSpace::XRBoundedReferenceSpace(XRSession* session)
+ : XRReferenceSpace(session) {}
+
+XRBoundedReferenceSpace::~XRBoundedReferenceSpace() = default;
+
+void XRBoundedReferenceSpace::UpdateBoundsGeometry(
+ XRStageBounds* bounds_geometry) {
+ // TODO(https://crbug.com/917411): Support bounds geometry and fire a 'reset'
+ // event when the bounds change.
+}
+
+void XRBoundedReferenceSpace::UpdateFloorLevelTransform() {
+ const device::mojom::blink::VRDisplayInfoPtr& display_info =
+ session()->GetVRDisplayInfo();
+
+ if (display_info && display_info->stageParameters) {
+ // Use the transform given by xrDisplayInfo's stageParameters if available.
+ const WTF::Vector<float>& m =
+ display_info->stageParameters->standingTransform;
+ floor_level_transform_ = TransformationMatrix::Create(
+ m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
+ m[11], m[12], m[13], m[14], m[15]);
+ } else {
+ // If stage parameters aren't available set the transform to null, which
+ // will subsequently cause this reference space to return null poses.
+ floor_level_transform_.reset();
+ }
+
+ display_info_id_ = session()->DisplayInfoPtrId();
+}
+
+// Transforms a given pose from a "base" reference space used by the XR
+// service to the bounded (floor level) reference space. Ideally in the future
+// this reference space can be used without additional transforms, with
+// the various XR backends returning poses already in the right space.
+std::unique_ptr<TransformationMatrix>
+XRBoundedReferenceSpace::TransformBasePose(
+ const TransformationMatrix& base_pose) {
+ // Check first to see if the xrDisplayInfo has updated since the last
+ // call. If so, update the pose transform.
+ if (display_info_id_ != session()->DisplayInfoPtrId())
+ UpdateFloorLevelTransform();
+
+ // If the reference space has a transform apply it to the base pose and return
+ // that, otherwise return null.
+ if (floor_level_transform_) {
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(*floor_level_transform_));
+ pose->Multiply(base_pose);
+ return pose;
+ }
+
+ return nullptr;
+}
+
+// Serves the same purpose as TransformBasePose, but for input poses. Needs to
+// know the head pose so that cases like the head-model frame of reference can
+// properly adjust the input's relative position.
+std::unique_ptr<TransformationMatrix>
+XRBoundedReferenceSpace::TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) {
+ return TransformBasePose(base_input_pose);
+}
+
+void XRBoundedReferenceSpace::Trace(blink::Visitor* visitor) {
+ visitor->Trace(bounds_geometry_);
+ XRSpace::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h
new file mode 100644
index 00000000000..804996c2aa2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_BOUNDED_REFERENCE_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_BOUNDED_REFERENCE_SPACE_H_
+
+#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRStageBounds;
+
+class XRBoundedReferenceSpace final : public XRReferenceSpace {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRBoundedReferenceSpace(XRSession*);
+ ~XRBoundedReferenceSpace() override;
+
+ void UpdateBoundsGeometry(XRStageBounds*);
+
+ std::unique_ptr<TransformationMatrix> TransformBasePose(
+ const TransformationMatrix& base_pose) override;
+ std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) override;
+
+ HeapVector<Member<DOMPointReadOnly>> boundsGeometry() const {
+ return bounds_geometry_;
+ }
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ void UpdateFloorLevelTransform();
+
+ HeapVector<Member<DOMPointReadOnly>> bounds_geometry_;
+ std::unique_ptr<TransformationMatrix> floor_level_transform_;
+ unsigned int display_info_id_ = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_BOUNDED_REFERENCE_SPACE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.idl b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.idl
new file mode 100644
index 00000000000..ea8d30bd941
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://immersive-web.github.io/webxr/#xrboundedreferencespace-interface
+
+[
+ SecureContext,
+ Exposed=Window,
+ OriginTrialEnabled=WebXR
+] interface XRBoundedReferenceSpace : XRReferenceSpace {
+ readonly attribute FrozenArray<DOMPointReadOnly> boundsGeometry;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc b/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
index 9420e85f5d5..023699aed92 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
@@ -4,10 +4,10 @@
#include "third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h"
-#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr.h"
#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
@@ -17,14 +17,10 @@ namespace blink {
namespace {
-class XRCanvasInputEventListener : public EventListener {
+class XRCanvasInputEventListener : public NativeEventListener {
public:
XRCanvasInputEventListener(XRCanvasInputProvider* input_provider)
- : EventListener(kCPPEventListenerType), input_provider_(input_provider) {}
-
- bool operator==(const EventListener& that) const override {
- return this == &that;
- }
+ : input_provider_(input_provider) {}
void Invoke(ExecutionContext* execution_context, Event* event) override {
if (!input_provider_->ShouldProcessEvents())
@@ -52,7 +48,7 @@ class XRCanvasInputEventListener : public EventListener {
XRCanvasInputProvider::XRCanvasInputProvider(XRSession* session,
HTMLCanvasElement* canvas)
: session_(session), canvas_(canvas) {
- listener_ = new XRCanvasInputEventListener(this);
+ listener_ = MakeGarbageCollected<XRCanvasInputEventListener>(this);
canvas->addEventListener(event_type_names::kPointerdown, listener_);
canvas->addEventListener(event_type_names::kPointerup, listener_);
canvas->addEventListener(event_type_names::kPointercancel, listener_);
@@ -74,7 +70,7 @@ void XRCanvasInputProvider::Stop() {
bool XRCanvasInputProvider::ShouldProcessEvents() {
// Don't process canvas gestures if there's an active immersive session.
- return !(session_->device()->frameProvider()->immersive_session());
+ return !(session_->xr()->frameProvider()->immersive_session());
}
void XRCanvasInputProvider::OnPointerDown(PointerEvent* event) {
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
deleted file mode 100644
index 668360f27a0..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
+++ /dev/null
@@ -1,12 +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.
-
-// https://immersive-web.github.io/webxr/#xrcoordinatesystem-interface
-[
- SecureContext,
- Exposed=Window,
- OriginTrialEnabled=WebXR
-] interface XRCoordinateSystem : EventTarget {
- Float32Array? getTransformTo(XRCoordinateSystem other);
-};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.cc b/chromium/third_party/blink/renderer/modules/xr/xr_device.cc
deleted file mode 100644
index d48f157eeda..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_device.cc
+++ /dev/null
@@ -1,274 +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 "third_party/blink/renderer/modules/xr/xr_device.h"
-
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/core/frame/frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/modules/xr/xr.h"
-#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
-#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
-#include "third_party/blink/renderer/modules/xr/xr_session.h"
-
-namespace blink {
-
-namespace {
-
-const char kActiveImmersiveSession[] =
- "XRDevice already has an active, immersive session";
-
-const char kNoOutputContext[] =
- "Non-immersive sessions must be created with an outputContext.";
-
-const char kRequestRequiresUserActivation[] =
- "The requested session requires user activation.";
-
-const char kSessionNotSupported[] =
- "The specified session configuration is not supported.";
-
-/**
- * Helper method to convert IDL options into Mojo options.
- */
-device::mojom::blink::XRSessionOptionsPtr convertIdlOptionsToMojo(
- const XRSessionCreationOptions* options) {
- auto session_options = device::mojom::blink::XRSessionOptions::New();
- if (options->hasImmersive()) {
- session_options->immersive = options->immersive();
- }
- if (options->hasEnvironmentIntegration()) {
- session_options->environment_integration =
- options->environmentIntegration();
- }
-
- return session_options;
-}
-
-} // namespace
-
-XRDevice::XRDevice(XR* xr, device::mojom::blink::XRDevicePtr device)
- : xr_(xr), device_ptr_(std::move(device)) {}
-
-const char* XRDevice::checkSessionSupport(
- const XRSessionCreationOptions* options) const {
- if (!options->immersive()) {
- // Validation for non-immersive sessions. Validation for immersive sessions
- // happens browser side.
- if (!options->hasOutputContext()) {
- return kNoOutputContext;
- }
- }
-
- return nullptr;
-}
-
-ScriptPromise XRDevice::supportsSession(
- ScriptState* script_state,
- const XRSessionCreationOptions* options) {
- // Check to see if the device is capable of supporting the requested session
- // options. Note that reporting support here does not guarantee that creating
- // a session with those options will succeed, as other external and
- // time-sensitve factors (focus state, existence of another immersive session,
- // etc.) may prevent the creation of a session as well.
- const char* reject_reason = checkSessionSupport(options);
- if (reject_reason) {
- return ScriptPromise::RejectWithDOMException(
- script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
- reject_reason));
- }
-
- // If the above checks pass, resolve without a value. Future API iterations
- // may specify a value to be returned here.
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
- ScriptPromise promise = resolver->Promise();
-
- device::mojom::blink::XRSessionOptionsPtr session_options =
- convertIdlOptionsToMojo(options);
-
- device_ptr_->SupportsSession(
- std::move(session_options),
- WTF::Bind(&XRDevice::OnSupportsSessionReturned, WrapPersistent(this),
- WrapPersistent(resolver)));
-
- return promise;
-}
-
-void XRDevice::OnSupportsSessionReturned(ScriptPromiseResolver* resolver,
- bool supports_session) {
- supports_session
- ? resolver->Resolve()
- : resolver->Reject(DOMException::Create(
- DOMExceptionCode::kNotSupportedError, kSessionNotSupported));
-}
-
-int64_t XRDevice::GetSourceId() const {
- return xr_->GetSourceId();
-}
-
-const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr&
-XRDevice::xrEnvironmentProviderPtr() {
- return environment_provider_;
-}
-
-ScriptPromise XRDevice::requestSession(
- ScriptState* script_state,
- const XRSessionCreationOptions* options) {
- Document* doc = To<Document>(ExecutionContext::From(script_state));
-
- if (options->immersive() && !did_log_request_immersive_session_ && doc) {
- ukm::builders::XR_WebXR(GetSourceId())
- .SetDidRequestPresentation(1)
- .Record(doc->UkmRecorder());
- did_log_request_immersive_session_ = true;
- }
-
- // Check first to see if the device is capable of supporting the requested
- // options.
- const char* reject_reason = checkSessionSupport(options);
- if (reject_reason) {
- return ScriptPromise::RejectWithDOMException(
- script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
- reject_reason));
- }
-
- // TODO(ijamardo): Should we just exit if there is not document?
- bool has_user_activation =
- LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr);
-
- // Check if the current page state prevents the requested session from being
- // created.
- if (options->immersive()) {
- if (frameProvider()->immersive_session()) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- DOMException::Create(DOMExceptionCode::kInvalidStateError,
- kActiveImmersiveSession));
- }
-
- if (!has_user_activation) {
- return ScriptPromise::RejectWithDOMException(
- script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
- kRequestRequiresUserActivation));
- }
- }
-
- // All AR sessions require a user gesture.
- if (options->environmentIntegration()) {
- if (!has_user_activation) {
- return ScriptPromise::RejectWithDOMException(
- script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
- kRequestRequiresUserActivation));
- }
- }
-
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
- ScriptPromise promise = resolver->Promise();
-
- device::mojom::blink::XRSessionOptionsPtr session_options =
- convertIdlOptionsToMojo(options);
- session_options->has_user_activation = has_user_activation;
-
- XRPresentationContext* output_context =
- options->hasOutputContext() ? options->outputContext() : nullptr;
-
- // TODO(http://crbug.com/826899) Once device activation is sorted out for
- // WebXR, either pass in the correct value for metrics to know whether
- // this was triggered by device activation, or remove the value as soon as
- // legacy API has been removed.
- device_ptr_->RequestSession(
- std::move(session_options), false /* triggered by display activate */,
- WTF::Bind(&XRDevice::OnRequestSessionReturned, WrapWeakPersistent(this),
- WrapPersistent(resolver), WrapPersistent(output_context),
- options->environmentIntegration(), options->immersive()));
- return promise;
-}
-
-void XRDevice::OnRequestSessionReturned(
- ScriptPromiseResolver* resolver,
- XRPresentationContext* output_context,
- bool environment_integration,
- bool immersive,
- device::mojom::blink::XRSessionPtr session_ptr) {
- // TODO(https://crbug.com/872316) Improve the error messaging to indicate why
- // a request failed.
- if (!session_ptr) {
- DOMException* exception = DOMException::Create(
- DOMExceptionCode::kNotSupportedError, kSessionNotSupported);
- resolver->Reject(exception);
- return;
- }
-
- // immersive sessions must supply display info.
- DCHECK(session_ptr->display_info);
- // If the session supports environment integration, ensure the device does
- // as well.
- DCHECK(!environment_integration || session_ptr->display_info->capabilities
- ->canProvideEnvironmentIntegration);
-
- XRSession::EnvironmentBlendMode blend_mode = XRSession::kBlendModeOpaque;
- if (environment_integration)
- blend_mode = XRSession::kBlendModeAlphaBlend;
-
- XRSession* session = MakeGarbageCollected<XRSession>(
- this, std::move(session_ptr->client_request), immersive,
- environment_integration, output_context, blend_mode);
- session->SetXRDisplayInfo(std::move(session_ptr->display_info));
- sessions_.insert(session);
-
- if (immersive) {
- frameProvider()->BeginImmersiveSession(session, std::move(session_ptr));
- } else {
- magic_window_provider_.Bind(std::move(session_ptr->data_provider));
- if (environment_integration) {
- magic_window_provider_->GetEnvironmentIntegrationProvider(
- mojo::MakeRequest(&environment_provider_));
- }
- }
-
- resolver->Resolve(session);
-}
-
-void XRDevice::OnFrameFocusChanged() {
- OnFocusChanged();
-}
-
-void XRDevice::OnFocusChanged() {
- // Tell all sessions that focus changed.
- for (const auto& session : sessions_) {
- session->OnFocusChanged();
- }
-
- if (frame_provider_)
- frame_provider_->OnFocusChanged();
-}
-
-bool XRDevice::IsFrameFocused() {
- return xr_->IsFrameFocused();
-}
-
-XRFrameProvider* XRDevice::frameProvider() {
- if (!frame_provider_) {
- frame_provider_ = MakeGarbageCollected<XRFrameProvider>(this);
- }
-
- return frame_provider_;
-}
-
-void XRDevice::Dispose() {
- if (frame_provider_)
- frame_provider_->Dispose();
-}
-
-void XRDevice::Trace(blink::Visitor* visitor) {
- visitor->Trace(xr_);
- visitor->Trace(frame_provider_);
- visitor->Trace(sessions_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.h b/chromium/third_party/blink/renderer/modules/xr/xr_device.h
deleted file mode 100644
index 047a54ffadf..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_device.h
+++ /dev/null
@@ -1,89 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_H_
-
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/modules/xr/xr_session_creation_options.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class ScriptPromiseResolver;
-class XR;
-class XRFrameProvider;
-class XRSession;
-
-class XRDevice final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- XRDevice(XR*, device::mojom::blink::XRDevicePtr);
- XR* xr() const { return xr_; }
-
- ScriptPromise supportsSession(ScriptState*, const XRSessionCreationOptions*);
- ScriptPromise requestSession(ScriptState*, const XRSessionCreationOptions*);
-
- XRFrameProvider* frameProvider();
-
- void Dispose();
-
- const device::mojom::blink::XRDevicePtr& xrDevicePtr() const {
- return device_ptr_;
- }
- const device::mojom::blink::XRFrameDataProviderPtr& xrMagicWindowProviderPtr()
- const {
- return magic_window_provider_;
- }
- const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr&
- xrEnvironmentProviderPtr();
-
- void OnFrameFocusChanged();
- bool HasFrameFocus() { return IsFrameFocused(); }
-
- int64_t GetSourceId() const;
-
- void Trace(blink::Visitor*) override;
-
- private:
- const char* checkSessionSupport(const XRSessionCreationOptions*) const;
-
- void OnRequestSessionReturned(ScriptPromiseResolver* resolver,
- XRPresentationContext* output_context,
- bool environment_integration,
- bool immersive,
- device::mojom::blink::XRSessionPtr session);
- void OnSupportsSessionReturned(ScriptPromiseResolver* resolver,
- bool supports_session);
-
- // There are two components to focus - whether the frame itself has
- // traditional focus and whether the device reports that we have focus. These
- // are aggregated so we can hand out focus/blur events on sessions and
- // determine when to call animation frame callbacks.
- void OnFocusChanged();
- bool IsFrameFocused();
-
- Member<XR> xr_;
- Member<XRFrameProvider> frame_provider_;
- HeapHashSet<WeakMember<XRSession>> sessions_;
-
- // Indicates whether we've already logged a request for an immersive session.
- bool did_log_request_immersive_session_ = false;
-
- device::mojom::blink::XRFrameDataProviderPtr magic_window_provider_;
- device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr
- environment_provider_;
- device::mojom::blink::XRDevicePtr device_ptr_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.idl b/chromium/third_party/blink/renderer/modules/xr/xr_device.idl
deleted file mode 100644
index 5d5a879f95f..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_device.idl
+++ /dev/null
@@ -1,13 +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.
-
-// https://immersive-web.github.io/webxr/#xrdevice-interface
-[
- SecureContext,
- Exposed=Window,
- OriginTrialEnabled=WebXR
-] interface XRDevice {
- [CallWith=ScriptState, MeasureAs=XRSupportsSession] Promise<void> supportsSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
- [CallWith=ScriptState, MeasureAs=XRRequestSession] Promise<XRSession> requestSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
-};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc
deleted file mode 100644
index 1942968a5e3..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc
+++ /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.
-
-#include "third_party/blink/renderer/modules/xr/xr_device_pose.h"
-
-#include "third_party/blink/renderer/modules/xr/xr_session.h"
-#include "third_party/blink/renderer/modules/xr/xr_utils.h"
-#include "third_party/blink/renderer/modules/xr/xr_view.h"
-
-namespace blink {
-
-XRDevicePose::XRDevicePose(
- XRSession* session,
- std::unique_ptr<TransformationMatrix> pose_model_matrix)
- : session_(session), pose_model_matrix_(std::move(pose_model_matrix)) {}
-
-DOMFloat32Array* XRDevicePose::poseModelMatrix() const {
- if (!pose_model_matrix_)
- return nullptr;
- return transformationMatrixToDOMFloat32Array(*pose_model_matrix_);
-}
-
-DOMFloat32Array* XRDevicePose::getViewMatrix(XRView* view) {
- if (view->session() != session_)
- return nullptr;
-
- if (!pose_model_matrix_->IsInvertible())
- return nullptr;
-
- TransformationMatrix view_matrix(pose_model_matrix_->Inverse());
-
- // Transform by the negative offset, since we're operating on the inverted
- // matrix
- const FloatPoint3D& view_offset = view->offset();
- view_matrix.PostTranslate3d(-view_offset.X(), -view_offset.Y(),
- -view_offset.Z());
-
- return transformationMatrixToDOMFloat32Array(view_matrix);
-}
-
-void XRDevicePose::Trace(blink::Visitor* visitor) {
- visitor->Trace(session_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
index f4404b8a678..34e6219ead8 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
@@ -4,56 +4,55 @@
#include "third_party/blink/renderer/modules/xr/xr_frame.h"
-#include "third_party/blink/renderer/modules/xr/xr_coordinate_system.h"
-#include "third_party/blink/renderer/modules/xr/xr_device_pose.h"
#include "third_party/blink/renderer/modules/xr/xr_input_pose.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
+#include "third_party/blink/renderer/modules/xr/xr_viewer_pose.h"
namespace blink {
XRFrame::XRFrame(XRSession* session) : session_(session) {}
-const HeapVector<Member<XRView>>& XRFrame::views() const {
- return session_->views();
-}
-
-XRDevicePose* XRFrame::getDevicePose(
- XRCoordinateSystem* coordinate_system) const {
+XRViewerPose* XRFrame::getViewerPose(XRReferenceSpace* reference_space) const {
session_->LogGetPose();
// If we don't have a valid base pose return null. Most common when tracking
// is lost.
- if (!base_pose_matrix_ || !coordinate_system) {
+ if (!base_pose_matrix_ || !reference_space) {
return nullptr;
}
// Must use a coordinate system created from the same session.
- if (coordinate_system->session() != session_) {
+ if (reference_space->session() != session_) {
return nullptr;
}
std::unique_ptr<TransformationMatrix> pose =
- coordinate_system->TransformBasePose(*base_pose_matrix_);
+ reference_space->TransformBasePose(*base_pose_matrix_);
if (!pose) {
return nullptr;
}
- return MakeGarbageCollected<XRDevicePose>(session(), std::move(pose));
+ // Can only update an XRViewerPose's views with an invertible matrix.
+ if (!pose->IsInvertible()) {
+ return nullptr;
+ }
+
+ return MakeGarbageCollected<XRViewerPose>(session(), std::move(pose));
}
-XRInputPose* XRFrame::getInputPose(
- XRInputSource* input_source,
- XRCoordinateSystem* coordinate_system) const {
- if (!input_source || !coordinate_system) {
+XRInputPose* XRFrame::getInputPose(XRInputSource* input_source,
+ XRReferenceSpace* reference_space) const {
+ if (!input_source || !reference_space) {
return nullptr;
}
// Must use an input source and coordinate system from the same session.
if (input_source->session() != session_ ||
- coordinate_system->session() != session_) {
+ reference_space->session() != session_) {
return nullptr;
}
@@ -68,7 +67,7 @@ XRInputPose* XRFrame::getInputPose(
// Multiply the head pose and pointer transform to get the final pointer.
std::unique_ptr<TransformationMatrix> pointer_pose =
- coordinate_system->TransformBasePose(*base_pose_matrix_);
+ reference_space->TransformBasePose(*base_pose_matrix_);
pointer_pose->Multiply(*(input_source->pointer_transform_matrix_));
return MakeGarbageCollected<XRInputPose>(std::move(pointer_pose),
@@ -84,7 +83,7 @@ XRInputPose* XRFrame::getInputPose(
// Just return the head pose as the pointer pose.
std::unique_ptr<TransformationMatrix> pointer_pose =
- coordinate_system->TransformBasePose(*base_pose_matrix_);
+ reference_space->TransformBasePose(*base_pose_matrix_);
return MakeGarbageCollected<XRInputPose>(
std::move(pointer_pose), nullptr, input_source->emulatedPosition());
@@ -96,7 +95,7 @@ XRInputPose* XRFrame::getInputPose(
}
std::unique_ptr<TransformationMatrix> grip_pose =
- coordinate_system->TransformBaseInputPose(
+ reference_space->TransformBaseInputPose(
*(input_source->base_pose_matrix_), *base_pose_matrix_);
if (!grip_pose) {
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
index 0af9ba5c298..82adf5cae71 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
@@ -14,12 +14,11 @@
namespace blink {
-class XRCoordinateSystem;
-class XRDevicePose;
+class XRViewerPose;
class XRInputPose;
class XRInputSource;
+class XRReferenceSpace;
class XRSession;
-class XRView;
class XRFrame final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -29,9 +28,8 @@ class XRFrame final : public ScriptWrappable {
XRSession* session() const { return session_; }
- const HeapVector<Member<XRView>>& views() const;
- XRDevicePose* getDevicePose(XRCoordinateSystem*) const;
- XRInputPose* getInputPose(XRInputSource*, XRCoordinateSystem*) const;
+ XRViewerPose* getViewerPose(XRReferenceSpace*) const;
+ XRInputPose* getInputPose(XRInputSource*, XRReferenceSpace*) const;
void SetBasePoseMatrix(const TransformationMatrix&);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
index 5b3a9df3fbd..2235225a90a 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
@@ -9,9 +9,8 @@
OriginTrialEnabled=WebXR
] interface XRFrame {
readonly attribute XRSession session;
- readonly attribute FrozenArray<XRView> views;
- XRDevicePose? getDevicePose(XRCoordinateSystem coordinateSystem);
+ XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
XRInputPose? getInputPose(XRInputSource inputSource,
- XRCoordinateSystem coordinateSystem);
+ XRReferenceSpace referenceSpace);
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc
deleted file mode 100644
index 5c29f5d3d17..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc
+++ /dev/null
@@ -1,158 +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 "third_party/blink/renderer/modules/xr/xr_frame_of_reference.h"
-
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
-#include "third_party/blink/renderer/modules/xr/xr_session.h"
-#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h"
-
-namespace blink {
-
-// Rough estimate of avg human eye height in meters.
-const double kDefaultEmulationHeight = 1.6;
-
-XRFrameOfReference::XRFrameOfReference(XRSession* session, Type type)
- : XRCoordinateSystem(session), type_(type) {}
-
-XRFrameOfReference::~XRFrameOfReference() = default;
-
-void XRFrameOfReference::UpdatePoseTransform(
- std::unique_ptr<TransformationMatrix> transform) {
- pose_transform_ = std::move(transform);
-}
-
-void XRFrameOfReference::UpdateStageBounds(XRStageBounds* bounds) {
- bounds_ = bounds;
- // TODO(bajones): Fire a boundschange event
-}
-
-void XRFrameOfReference::UpdateStageTransform() {
- const device::mojom::blink::VRDisplayInfoPtr& display_info =
- session()->GetVRDisplayInfo();
-
- if (display_info && display_info->stageParameters) {
- // Use the transform given by xrDisplayInfo's stageParamters if available.
- const WTF::Vector<float>& m =
- display_info->stageParameters->standingTransform;
- pose_transform_ = TransformationMatrix::Create(
- m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
- m[11], m[12], m[13], m[14], m[15]);
- } else if (emulated_height_ != 0.0) {
- // Otherwise, if this frame of reference has specified that an emulated
- // height may be used, create a transform based on that.
- pose_transform_ = TransformationMatrix::Create();
- pose_transform_->Translate3d(0, emulated_height_, 0);
- } else {
- // If stage parameters aren't available and emulation is disabled, set the
- // transform to null, which will subsequently cause this frame of reference
- // to return null poses.
- pose_transform_.reset();
- }
-
- display_info_id_ = session()->DisplayInfoPtrId();
-}
-
-// Enables emulated height when using a stage frame of reference, which should
-// only be used if the sytem does not have a native concept of how far above the
-// floor the XRDevice is at any given moment. This applies a static vertical
-// offset to the coordinate system so that the user feels approximately like
-// they are standing on a floor plane located at Y = 0. An explicit offset in
-// meters can be given if the page has specific needs.
-void XRFrameOfReference::UseEmulatedHeight(double value) {
- if (value == 0.0)
- value = kDefaultEmulationHeight;
-
- emulated_height_ = value;
- UpdateStageTransform();
-}
-
-// Transforms a given pose from a "base" coordinate system used by the XR
-// service to the frame of reference's coordinate system. This model is a bit
-// over-simplified and will need to be made more robust when we start dealing
-// with world-scale 6DoF tracking.
-std::unique_ptr<TransformationMatrix> XRFrameOfReference::TransformBasePose(
- const TransformationMatrix& base_pose) {
- switch (type_) {
- case kTypeHeadModel: {
- // TODO(bajones): Detect if base pose is already neck modeled and return
- // it unchanged if so for better performance.
-
- // Strip out translation component.
- std::unique_ptr<TransformationMatrix> pose(
- TransformationMatrix::Create(base_pose));
- pose->SetM41(0.0);
- pose->SetM42(0.0);
- pose->SetM43(0.0);
- // TODO(bajones): Apply our own neck model
- return pose;
- } break;
- case kTypeEyeLevel:
- // For now we assume that all base poses are delivered as eye-level poses.
- // Thus in this case we just return the pose without transformation.
- return TransformationMatrix::Create(base_pose);
- break;
- case kTypeStage:
- // Check first to see if the xrDisplayInfo has updated since the last
- // call. If so, update the pose transform.
- if (display_info_id_ != session()->DisplayInfoPtrId())
- UpdateStageTransform();
-
- // If the stage has a transform apply it to the base pose and return that,
- // otherwise return null.
- if (pose_transform_) {
- std::unique_ptr<TransformationMatrix> pose(
- TransformationMatrix::Create(*pose_transform_));
- pose->Multiply(base_pose);
- return pose;
- }
- break;
- }
-
- return nullptr;
-}
-
-// Serves the same purpose as TransformBasePose, but for input poses. Needs to
-// know the head pose so that cases like the head-model frame of reference can
-// properly adjust the input's relative position.
-std::unique_ptr<TransformationMatrix>
-XRFrameOfReference::TransformBaseInputPose(
- const TransformationMatrix& base_input_pose,
- const TransformationMatrix& base_pose) {
- switch (type_) {
- case kTypeHeadModel: {
- std::unique_ptr<TransformationMatrix> head_model_pose(
- TransformBasePose(base_pose));
-
- // Get the positional delta between the base pose and the head model pose.
- float dx = head_model_pose->M41() - base_pose.M41();
- float dy = head_model_pose->M42() - base_pose.M42();
- float dz = head_model_pose->M43() - base_pose.M43();
-
- // Translate the controller by the same delta so that it shows up in the
- // right relative position.
- std::unique_ptr<TransformationMatrix> pose(
- TransformationMatrix::Create(base_input_pose));
- pose->SetM41(pose->M41() + dx);
- pose->SetM42(pose->M42() + dy);
- pose->SetM43(pose->M43() + dz);
-
- return pose;
- } break;
- case kTypeEyeLevel:
- case kTypeStage:
- return TransformBasePose(base_input_pose);
- break;
- }
-
- return nullptr;
-}
-
-void XRFrameOfReference::Trace(blink::Visitor* visitor) {
- visitor->Trace(bounds_);
- XRCoordinateSystem::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h
deleted file mode 100644
index eca778a2208..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h
+++ /dev/null
@@ -1,53 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_OF_REFERENCE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_OF_REFERENCE_H_
-
-#include "third_party/blink/renderer/modules/xr/xr_coordinate_system.h"
-#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
-
-namespace blink {
-
-class XRStageBounds;
-
-class XRFrameOfReference final : public XRCoordinateSystem {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- enum Type { kTypeHeadModel, kTypeEyeLevel, kTypeStage };
-
- XRFrameOfReference(XRSession*, Type);
- ~XRFrameOfReference() override;
-
- void UpdatePoseTransform(std::unique_ptr<TransformationMatrix>);
- void UpdateStageBounds(XRStageBounds*);
- void UseEmulatedHeight(double value);
-
- std::unique_ptr<TransformationMatrix> TransformBasePose(
- const TransformationMatrix& base_pose) override;
- std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
- const TransformationMatrix& base_input_pose,
- const TransformationMatrix& base_pose) override;
-
- XRStageBounds* bounds() const { return bounds_; }
- double emulatedHeight() const { return emulated_height_; }
-
- Type type() const { return type_; }
-
- void Trace(blink::Visitor*) override;
-
- private:
- void UpdateStageTransform();
-
- Member<XRStageBounds> bounds_;
- double emulated_height_ = 0.0;
- Type type_;
- std::unique_ptr<TransformationMatrix> pose_transform_;
- unsigned int display_info_id_ = 0;
-};
-
-} // namespace blink
-
-#endif // XRWebGLLayer_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
deleted file mode 100644
index b1b3856f596..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
+++ /dev/null
@@ -1,20 +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.
-
-// https://immersive-web.github.io/webxr/#xrframeofreference-interface
-
-enum XRFrameOfReferenceType {
- "head-model",
- "eye-level",
- "stage",
-};
-
-[
- SecureContext,
- Exposed=Window,
- OriginTrialEnabled=WebXR
-] interface XRFrameOfReference : XRCoordinateSystem {
- readonly attribute XRStageBounds? bounds;
- readonly attribute double emulatedHeight;
-};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl
deleted file mode 100644
index cdc2f098d12..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl
+++ /dev/null
@@ -1,9 +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.
-
-// https://immersive-web.github.io/webxr/#xrframeofreference-interface
-dictionary XRFrameOfReferenceOptions {
- boolean disableStageEmulation = false;
- double stageEmulationHeight = 0.0;
-};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
index e935fdb22b3..d6727c83a29 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -14,7 +14,6 @@
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/modules/xr/xr.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_viewport.h"
@@ -86,8 +85,8 @@ std::unique_ptr<TransformationMatrix> getPoseMatrix(
} // namespace
-XRFrameProvider::XRFrameProvider(XRDevice* device)
- : device_(device), last_has_focus_(device->HasFrameFocus()) {
+XRFrameProvider::XRFrameProvider(XR* xr)
+ : xr_(xr), last_has_focus_(xr->IsFrameFocused()) {
frame_transport_ = MakeGarbageCollected<XRFrameTransport>();
}
@@ -120,7 +119,7 @@ void XRFrameProvider::BeginImmersiveSession(
}
void XRFrameProvider::OnFocusChanged() {
- bool focus = device_->HasFrameFocus();
+ bool focus = xr_->IsFrameFocused();
// If we are gaining focus, schedule a frame for magic window. This accounts
// for skipping RAFs in ProcessScheduledFrame. Only do this when there are
@@ -148,7 +147,7 @@ void XRFrameProvider::OnImmersiveSessionEnded() {
if (!immersive_session_)
return;
- device_->xrDevicePtr()->ExitPresent();
+ xr_->xrDevicePtr()->ExitPresent();
immersive_session_ = nullptr;
pending_immersive_vsync_ = false;
@@ -214,14 +213,14 @@ void XRFrameProvider::ScheduleNonImmersiveFrame() {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(!immersive_session_)
<< "Scheduling should be done via the exclusive session if present.";
- DCHECK(device_->xrMagicWindowProviderPtr())
+ DCHECK(xr_->xrMagicWindowProviderPtr())
<< "If there is no exclusive session, it should be impossible to "
"schedule a frame without a MagicWindowProvider.";
if (pending_non_immersive_vsync_)
return;
- LocalFrame* frame = device_->xr()->GetFrame();
+ LocalFrame* frame = xr_->GetFrame();
if (!frame)
return;
@@ -233,7 +232,7 @@ void XRFrameProvider::ScheduleNonImmersiveFrame() {
pending_non_immersive_vsync_ = true;
- device_->xrMagicWindowProviderPtr()->GetFrameData(WTF::Bind(
+ xr_->xrMagicWindowProviderPtr()->GetFrameData(WTF::Bind(
&XRFrameProvider::OnNonImmersiveFrameData, WrapWeakPersistent(this)));
// TODO(https://crbug.com/839253): Generalize the pass-through images
@@ -242,7 +241,8 @@ void XRFrameProvider::ScheduleNonImmersiveFrame() {
// TODO(http://crbug.com/856257) Remove the special casing for AR and non-AR.
if (!HasARSession()) {
- doc->RequestAnimationFrame(new XRFrameProviderRequestCallback(this));
+ doc->RequestAnimationFrame(
+ MakeGarbageCollected<XRFrameProviderRequestCallback>(this));
}
}
@@ -262,7 +262,7 @@ void XRFrameProvider::OnImmersiveFrameData(
return;
}
- LocalFrame* frame = device_->xr()->GetFrame();
+ LocalFrame* frame = xr_->GetFrame();
if (!frame)
return;
Document* doc = frame->GetDocument();
@@ -306,7 +306,7 @@ void XRFrameProvider::OnNonImmersiveVSync(double high_res_now_ms) {
if (immersive_session_)
return;
- LocalFrame* frame = device_->xr()->GetFrame();
+ LocalFrame* frame = xr_->GetFrame();
if (!frame)
return;
@@ -324,7 +324,7 @@ void XRFrameProvider::OnNonImmersiveFrameData(
// TODO(https://crbug.com/837834): add unit tests for this code path.
pending_non_immersive_vsync_ = false;
- LocalFrame* frame = device_->xr()->GetFrame();
+ LocalFrame* frame = xr_->GetFrame();
if (!frame)
return;
Document* doc = frame->GetDocument();
@@ -336,7 +336,8 @@ void XRFrameProvider::OnNonImmersiveFrameData(
// Try to request a regular animation frame to avoid getting stuck.
DVLOG(1) << __FUNCTION__ << ": NO FRAME DATA!";
frame_pose_ = nullptr;
- doc->RequestAnimationFrame(new XRFrameProviderRequestCallback(this));
+ doc->RequestAnimationFrame(
+ MakeGarbageCollected<XRFrameProviderRequestCallback>(this));
return;
}
@@ -366,7 +367,7 @@ void XRFrameProvider::ProcessScheduledFrame(
TRACE_EVENT2("gpu", "XRFrameProvider::ProcessScheduledFrame", "frame",
frame_id_, "timestamp", high_res_now_ms);
- if (!device_->HasFrameFocus() && !immersive_session_) {
+ if (!xr_->IsFrameFocused() && !immersive_session_) {
return; // Not currently focused, so we won't expose poses (except to
// immersive sessions).
}
@@ -514,6 +515,8 @@ void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) {
presentation_provider_.get(), webgl_context->ContextGL(), webgl_context,
std::move(image_ref), std::move(image_release_callback), frame_id_,
needs_copy);
+ // If this layer is being mirrored, try to update the mirror.
+ layer->UpdateWebXRMirror();
// Reset our frame id, since anything we'd want to do (resizing/etc) can
// no-longer happen to this frame.
@@ -553,7 +556,7 @@ void XRFrameProvider::Dispose() {
}
void XRFrameProvider::Trace(blink::Visitor* visitor) {
- visitor->Trace(device_);
+ visitor->Trace(xr_);
visitor->Trace(frame_transport_);
visitor->Trace(immersive_session_);
visitor->Trace(requesting_sessions_);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h
index 945283df416..50024bfb962 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -14,7 +14,7 @@
namespace blink {
-class XRDevice;
+class XR;
class XRSession;
class XRFrameTransport;
class XRWebGLLayer;
@@ -24,7 +24,7 @@ class XRWebGLLayer;
class XRFrameProvider final
: public GarbageCollectedFinalized<XRFrameProvider> {
public:
- explicit XRFrameProvider(XRDevice*);
+ explicit XRFrameProvider(XR*);
XRSession* immersive_session() const { return immersive_session_; }
device::mojom::blink::XRPresentationClientPtr GetSubmitFrameClient();
@@ -58,7 +58,7 @@ class XRFrameProvider final
bool HasARSession();
- const Member<XRDevice> device_;
+ const Member<XR> xr_;
Member<XRSession> immersive_session_;
Member<XRFrameTransport> frame_transport_;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc
new file mode 100644
index 00000000000..4b41ac99528
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h"
+
+namespace blink {
+
+XRReferenceSpace::XRReferenceSpace(XRSession* session) : XRSpace(session) {}
+
+XRReferenceSpace::~XRReferenceSpace() = default;
+
+void XRReferenceSpace::Trace(blink::Visitor* visitor) {
+ XRSpace::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h
new file mode 100644
index 00000000000..0b64888d2e8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_H_
+
+#include "third_party/blink/renderer/modules/xr/xr_space.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRReferenceSpace : public XRSpace {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRReferenceSpace(XRSession*);
+ ~XRReferenceSpace() override;
+
+ virtual std::unique_ptr<TransformationMatrix> TransformBasePose(
+ const TransformationMatrix& base_pose) = 0;
+ virtual std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) = 0;
+
+ void Trace(blink::Visitor*) override;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.idl b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.idl
new file mode 100644
index 00000000000..6fc94da92a6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.idl
@@ -0,0 +1,19 @@
+// 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.
+
+// https://immersive-web.github.io/webxr/#xrreferencespace-interface
+
+enum XRReferenceSpaceType {
+ "stationary",
+ "bounded",
+ "unbounded"
+};
+
+[
+ SecureContext,
+ Exposed=Window,
+ OriginTrialEnabled=WebXR
+] interface XRReferenceSpace : XRSpace {
+ attribute EventHandler onreset;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_options.idl b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_options.idl
new file mode 100644
index 00000000000..76b5c285068
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_options.idl
@@ -0,0 +1,10 @@
+// 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.
+
+// https://immersive-web.github.io/webxr/#xrreferencespace-interface
+
+dictionary XRReferenceSpaceOptions {
+ required XRReferenceSpaceType type;
+ XRStationaryReferenceSpaceSubtype subtype;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
new file mode 100644
index 00000000000..bd1f7f2e4d4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
@@ -0,0 +1,66 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+
+namespace blink {
+
+XRRigidTransform::XRRigidTransform(DOMPointInit* position,
+ DOMPointInit* orientation) {
+ if (position) {
+ position_ = DOMPointReadOnly::Create(position->x(), position->y(),
+ position->z(), 1.0);
+ } else {
+ position_ = DOMPointReadOnly::Create(0.0, 0.0, 0.0, 1.0);
+ }
+
+ if (orientation) {
+ orientation_ = makeNormalizedQuaternion(orientation);
+ } else {
+ orientation_ = DOMPointReadOnly::Create(0.0, 0.0, 0.0, 1.0);
+ }
+
+ // Computing transformation matrix from position and orientation is expensive,
+ // so compute it lazily in matrix().
+}
+
+XRRigidTransform* XRRigidTransform::Create(DOMPointInit* position,
+ DOMPointInit* orientation) {
+ return MakeGarbageCollected<XRRigidTransform>(position, orientation);
+}
+
+DOMFloat32Array* XRRigidTransform::matrix() {
+ if (!matrix_) {
+ matrix_ = TransformationMatrix::Create();
+ TransformationMatrix::DecomposedType decomp;
+ memset(&decomp, 0, sizeof(decomp));
+ decomp.perspective_w = 1;
+ decomp.scale_x = 1;
+ decomp.scale_y = 1;
+ decomp.scale_z = 1;
+
+ decomp.quaternion_x = orientation_->x();
+ decomp.quaternion_y = orientation_->y();
+ decomp.quaternion_z = orientation_->z();
+ decomp.quaternion_w = orientation_->w();
+
+ decomp.translate_x = position_->x();
+ decomp.translate_y = position_->y();
+ decomp.translate_z = position_->z();
+
+ matrix_->Recompose(decomp);
+ }
+
+ return transformationMatrixToDOMFloat32Array(*matrix_);
+}
+
+void XRRigidTransform::Trace(blink::Visitor* visitor) {
+ visitor->Trace(position_);
+ visitor->Trace(orientation_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h
new file mode 100644
index 00000000000..247a3f74500
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_RIGID_TRANSFORM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_RIGID_TRANSFORM_H_
+
+#include <memory>
+
+#include "third_party/blink/renderer/core/geometry/dom_point_init.h"
+#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRRigidTransform : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRRigidTransform(DOMPointInit*, DOMPointInit*);
+ static XRRigidTransform* Create(DOMPointInit*, DOMPointInit*);
+
+ DOMPointReadOnly* position() const { return position_; }
+ DOMPointReadOnly* orientation() const { return orientation_; }
+ DOMFloat32Array* matrix();
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ Member<DOMPointReadOnly> position_;
+ Member<DOMPointReadOnly> orientation_;
+ std::unique_ptr<TransformationMatrix> matrix_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_RIGID_TRANSFORM_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl
new file mode 100644
index 00000000000..40dd716a48e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://immersive-web.github.io/webxr/#xrrigidtransform-interface
+
+[
+ SecureContext,
+ Exposed=Window,
+ OriginTrialEnabled=WebXR,
+ Constructor(optional DOMPointInit position, optional DOMPointInit orientation)
+] interface XRRigidTransform {
+ readonly attribute DOMPointReadOnly position;
+ readonly attribute DOMPointReadOnly orientation;
+ readonly attribute Float32Array matrix;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
index 1d1f2d9a1e7..f7307458b34 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -17,17 +17,19 @@
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/screen_orientation/screen_orientation.h"
#include "third_party/blink/renderer/modules/xr/xr.h"
+#include "third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
#include "third_party/blink/renderer/modules/xr/xr_frame.h"
-#include "third_party/blink/renderer/modules/xr/xr_frame_of_reference.h"
-#include "third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.h"
#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
#include "third_party/blink/renderer/modules/xr/xr_hit_result.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source_event.h"
#include "third_party/blink/renderer/modules/xr/xr_layer.h"
#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space_options.h"
#include "third_party/blink/renderer/modules/xr/xr_session_event.h"
+#include "third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h"
+#include "third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
#include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
@@ -38,10 +40,13 @@ namespace {
const char kSessionEnded[] = "XRSession has already ended.";
-const char kUnknownFrameOfReference[] = "Unknown frame of reference type.";
+const char kUnknownReferenceSpace[] = "Unknown reference space type.";
-const char kNonEmulatedStageNotSupported[] =
- "This device does not support a non-emulated 'stage' frame of reference.";
+const char kSubtypeRequired[] =
+ "Subtype must be specified when requesting a stationary reference space.";
+
+const char kReferenceSpaceNotSupported[] =
+ "This device does not support the requested reference space type.";
const double kDegToRad = M_PI / 180.0;
@@ -89,21 +94,57 @@ class XRSession::XRSessionResizeObserverDelegate final
Member<XRSession> session_;
};
+XRSession::SessionMode XRSession::stringToSessionMode(
+ const String& mode_string) {
+ if (mode_string == "inline") {
+ return kModeInline;
+ }
+ if (mode_string == "legacy-inline-ar") {
+ return kModeInlineAR;
+ }
+ if (mode_string == "immersive-vr") {
+ return kModeImmersiveVR;
+ }
+ if (mode_string == "immersive-ar") {
+ return kModeImmersiveAR;
+ }
+
+ return kModeUnknown;
+}
+
+String XRSession::sessionModeToString(XRSession::SessionMode mode) {
+ if (mode == kModeInline) {
+ return "inline";
+ }
+ if (mode == kModeInlineAR) {
+ return "legacy-inline-ar";
+ }
+ if (mode == kModeImmersiveVR) {
+ return "immersive-vr";
+ }
+ if (mode == kModeImmersiveAR) {
+ return "immersive-ar";
+ }
+
+ return "";
+}
+
XRSession::XRSession(
- XRDevice* device,
+ XR* xr,
device::mojom::blink::XRSessionClientRequest client_request,
- bool immersive,
- bool environment_integration,
+ XRSession::SessionMode mode,
XRPresentationContext* output_context,
EnvironmentBlendMode environment_blend_mode)
- : device_(device),
- immersive_(immersive),
- environment_integration_(environment_integration),
+ : xr_(xr),
+ mode_(mode),
+ mode_string_(sessionModeToString(mode)),
+ environment_integration_(mode == kModeInlineAR ||
+ mode == kModeImmersiveAR),
output_context_(output_context),
client_binding_(this, std::move(client_request)),
callback_collection_(
MakeGarbageCollected<XRFrameRequestCallbackCollection>(
- device->xr()->GetExecutionContext())) {
+ xr_->GetExecutionContext())) {
blurred_ = !HasAppropriateFocus();
// When an output context is provided, monitor it for resize events.
@@ -116,7 +157,7 @@ XRSession::XRSession(
resize_observer_->observe(canvas);
// Begin processing input events on the output context's canvas.
- if (!immersive_) {
+ if (!immersive()) {
canvas_input_provider_ =
MakeGarbageCollected<XRCanvasInputProvider>(this, canvas);
}
@@ -142,6 +183,10 @@ XRSession::XRSession(
}
}
+bool XRSession::immersive() const {
+ return mode_ == kModeImmersiveVR || mode_ == kModeImmersiveAR;
+}
+
void XRSession::setDepthNear(double value) {
if (depth_near_ != value) {
update_views_next_frame_ = true;
@@ -160,7 +205,7 @@ void XRSession::setBaseLayer(XRLayer* value) {
base_layer_ = value;
// Make sure that the layer's drawing buffer is updated to the right size
// if this is a non-immersive session.
- if (!immersive_ && base_layer_) {
+ if (!immersive() && base_layer_) {
base_layer_->OnResize();
}
}
@@ -176,55 +221,75 @@ void XRSession::SetNonImmersiveProjectionMatrix(
}
ExecutionContext* XRSession::GetExecutionContext() const {
- return device_->xr()->GetExecutionContext();
+ return xr_->GetExecutionContext();
}
const AtomicString& XRSession::InterfaceName() const {
return event_target_names::kXRSession;
}
-ScriptPromise XRSession::requestFrameOfReference(
+ScriptPromise XRSession::requestReferenceSpace(
ScriptState* script_state,
- const String& type,
- const XRFrameOfReferenceOptions* options) {
+ const XRReferenceSpaceOptions* options) {
if (ended_) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
kSessionEnded));
}
- XRFrameOfReference* frameOfRef = nullptr;
- if (type == "head-model") {
- frameOfRef = MakeGarbageCollected<XRFrameOfReference>(
- this, XRFrameOfReference::kTypeHeadModel);
- } else if (type == "eye-level") {
- frameOfRef = MakeGarbageCollected<XRFrameOfReference>(
- this, XRFrameOfReference::kTypeEyeLevel);
- } else if (type == "stage") {
- if (!options->disableStageEmulation()) {
- frameOfRef = MakeGarbageCollected<XRFrameOfReference>(
- this, XRFrameOfReference::kTypeStage);
- frameOfRef->UseEmulatedHeight(options->stageEmulationHeight());
- } else if (display_info_ && display_info_->stageParameters) {
- frameOfRef = MakeGarbageCollected<XRFrameOfReference>(
- this, XRFrameOfReference::kTypeStage);
+ XRReferenceSpace* reference_space = nullptr;
+ if (options->type() == "stationary") {
+ if (!options->hasSubtype()) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(DOMExceptionCode::kNotSupportedError,
+ kSubtypeRequired));
+ }
+
+ XRStationaryReferenceSpace::Subtype subtype;
+
+ if (options->subtype() == "eye-level") {
+ subtype = XRStationaryReferenceSpace::kSubtypeEyeLevel;
+ } else if (options->subtype() == "floor-level") {
+ subtype = XRStationaryReferenceSpace::kSubtypeFloorLevel;
+ } else if (options->subtype() == "position-disabled") {
+ subtype = XRStationaryReferenceSpace::kSubtypePositionDisabled;
+ } else {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(DOMExceptionCode::kNotSupportedError,
+ kSubtypeRequired));
+ }
+
+ reference_space =
+ MakeGarbageCollected<XRStationaryReferenceSpace>(this, subtype);
+ } else if (options->type() == "bounded") {
+ // TODO(https://crbug.com/917411): Bounded reference spaces cannot be
+ // returned unless they have bounds geometry. Until we implement that they
+ // will be considered unsupported.
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
+ kReferenceSpaceNotSupported));
+ } else if (options->type() == "unbounded") {
+ if (immersive() && environment_integration_) {
+ reference_space = MakeGarbageCollected<XRUnboundedReferenceSpace>(this);
} else {
return ScriptPromise::RejectWithDOMException(
script_state,
DOMException::Create(DOMExceptionCode::kNotSupportedError,
- kNonEmulatedStageNotSupported));
+ kReferenceSpaceNotSupported));
}
}
- if (!frameOfRef) {
+ if (!reference_space) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
- kUnknownFrameOfReference));
+ kUnknownReferenceSpace));
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
- resolver->Resolve(frameOfRef);
+ resolver->Resolve(reference_space);
return promise;
}
@@ -243,7 +308,7 @@ int XRSession::requestAnimationFrame(V8XRFrameRequestCallback* callback) {
int id = callback_collection_->RegisterCallback(callback);
if (!pending_frame_) {
// Kick off a request for a new XR frame.
- device_->frameProvider()->RequestFrame(this);
+ xr_->frameProvider()->RequestFrame(this);
pending_frame_ = true;
}
return id;
@@ -256,7 +321,7 @@ void XRSession::cancelAnimationFrame(int id) {
HeapVector<Member<XRInputSource>> XRSession::getInputSources() const {
Document* doc = To<Document>(GetExecutionContext());
if (!did_log_getInputSources_ && doc) {
- ukm::builders::XR_WebXR(device_->GetSourceId())
+ ukm::builders::XR_WebXR(xr_->GetSourceId())
.SetDidGetXRInputSources(1)
.Record(doc->UkmRecorder());
did_log_getInputSources_ = true;
@@ -280,33 +345,32 @@ HeapVector<Member<XRInputSource>> XRSession::getInputSources() const {
ScriptPromise XRSession::requestHitTest(ScriptState* script_state,
NotShared<DOMFloat32Array> origin,
NotShared<DOMFloat32Array> direction,
- XRCoordinateSystem* coordinate_system) {
+ XRSpace* space) {
if (ended_) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
kSessionEnded));
}
- if (!coordinate_system) {
+ if (!space) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
- script_state->GetIsolate(),
- "The coordinateSystem parameter is empty."));
+ script_state->GetIsolate(), "No XRSpace specified."));
}
if (origin.View()->length() != 3 || direction.View()->length() != 3) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
- "Invalid ray!"));
+ "Invalid ray"));
}
- // TODO(https://crbug.com/846411): use coordinate_system.
+ // TODO(https://crbug.com/846411): use space.
// Reject the promise if device doesn't support the hit-test API.
// TODO(https://crbug.com/878936): Get the environment provider without going
- // up to device_, since it doesn't know which runtime's environment provider
+ // up to xr_, since it doesn't know which runtime's environment provider
// we want.
- if (!device_->xrEnvironmentProviderPtr()) {
+ if (!xr_->xrEnvironmentProviderPtr()) {
return ScriptPromise::RejectWithDOMException(
script_state,
DOMException::Create(DOMExceptionCode::kNotSupportedError,
@@ -330,7 +394,7 @@ ScriptPromise XRSession::requestHitTest(ScriptState* script_state,
// TODO(https://crbug.com/845520): Promise should be rejected if session
// is deleted.
- device_->xrEnvironmentProviderPtr()->RequestHitTest(
+ xr_->xrEnvironmentProviderPtr()->RequestHitTest(
std::move(ray),
WTF::Bind(&XRSession::OnHitTestResults, WrapWeakPersistent(this),
WrapPersistent(resolver)));
@@ -384,7 +448,7 @@ ScriptPromise XRSession::end(ScriptState* script_state) {
}
void XRSession::ForceEnd() {
- // Detach this session from the device.
+ // Detach this session from the XR system.
ended_ = true;
pending_frame_ = false;
@@ -393,17 +457,17 @@ void XRSession::ForceEnd() {
canvas_input_provider_ = nullptr;
}
- // If this session is the active immersive session for the device, notify the
- // frameProvider that it's ended.
- if (device_->frameProvider()->immersive_session() == this) {
- device_->frameProvider()->OnImmersiveSessionEnded();
+ // If this session is the active immersive session, notify the frameProvider
+ // that it's ended.
+ if (xr_->frameProvider()->immersive_session() == this) {
+ xr_->frameProvider()->OnImmersiveSessionEnded();
}
DispatchEvent(*XRSessionEvent::Create(event_type_names::kEnd, this));
}
double XRSession::NativeFramebufferScale() const {
- if (immersive_) {
+ if (immersive()) {
double scale = display_info_->webxr_default_framebuffer_scale;
DCHECK(scale);
@@ -415,7 +479,7 @@ double XRSession::NativeFramebufferScale() const {
}
DoubleSize XRSession::DefaultFramebufferSize() const {
- if (!immersive_) {
+ if (!immersive()) {
return OutputCanvasSize();
}
@@ -456,8 +520,7 @@ void XRSession::OnBlur() {
// focused. This prevents the in-headset experience from freezing on an
// external display headset when the user clicks on another tab.
bool XRSession::HasAppropriateFocus() {
- return immersive_ ? has_device_focus_
- : has_device_focus_ && device_->HasFrameFocus();
+ return immersive() ? has_xr_focus_ : has_xr_focus_ && xr_->IsFrameFocused();
}
void XRSession::OnFocusChanged() {
@@ -526,10 +589,10 @@ void XRSession::OnFrame(
void XRSession::LogGetPose() const {
Document* doc = To<Document>(GetExecutionContext());
- if (!did_log_getDevicePose_ && doc) {
- did_log_getDevicePose_ = true;
+ if (!did_log_getViewerPose_ && doc) {
+ did_log_getViewerPose_ = true;
- ukm::builders::XR_WebXR(device_->GetSourceId())
+ ukm::builders::XR_WebXR(xr_->GetSourceId())
.SetDidRequestPose(1)
.Record(doc->UkmRecorder());
}
@@ -548,7 +611,7 @@ void XRSession::UpdateCanvasDimensions(Element* element) {
DCHECK(element);
double devicePixelRatio = 1.0;
- LocalFrame* frame = device_->xr()->GetFrame();
+ LocalFrame* frame = xr_->GetFrame();
if (frame) {
devicePixelRatio = frame->DevicePixelRatio();
}
@@ -567,8 +630,8 @@ void XRSession::UpdateCanvasDimensions(Element* element) {
DVLOG(2) << __FUNCTION__ << ": got angle=" << output_angle;
}
- if (device_->xrEnvironmentProviderPtr()) {
- device_->xrEnvironmentProviderPtr()->UpdateSessionGeometry(
+ if (xr_->xrEnvironmentProviderPtr()) {
+ xr_->xrEnvironmentProviderPtr()->UpdateSessionGeometry(
IntSize(output_width_, output_height_),
display::Display::DegreesToRotation(output_angle));
}
@@ -642,7 +705,7 @@ void XRSession::OnSelectEnd(XRInputSource* input_source) {
input_source->primary_input_pressed = false;
- LocalFrame* frame = device_->xr()->GetFrame();
+ LocalFrame* frame = xr_->GetFrame();
if (!frame)
return;
@@ -747,7 +810,7 @@ void XRSession::OnChanged(device::mojom::blink::VRDisplayInfoPtr display_info) {
}
void XRSession::OnExitPresent() {
- if (immersive_) {
+ if (immersive()) {
ForceEnd();
}
}
@@ -765,7 +828,7 @@ const HeapVector<Member<XRView>>& XRSession::views() {
// always hold true, however, so the view configuration should ultimately come
// from the backing service.
if (views_dirty_) {
- if (immersive_) {
+ if (immersive()) {
// If we don't already have the views allocated, do so now.
if (views_.IsEmpty()) {
views_.push_back(MakeGarbageCollected<XRView>(this, XRView::kEyeLeft));
@@ -823,7 +886,7 @@ bool XRSession::HasPendingActivity() const {
}
void XRSession::Trace(blink::Visitor* visitor) {
- visitor->Trace(device_);
+ visitor->Trace(xr_);
visitor->Trace(output_context_);
visitor->Trace(base_layer_);
visitor->Trace(views_);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.h b/chromium/third_party/blink/renderer/modules/xr/xr_session.h
index 21cae6dd4af..9bc84908fa3 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.h
@@ -27,13 +27,13 @@ class Element;
class ResizeObserver;
class ScriptPromiseResolver;
class V8XRFrameRequestCallback;
+class XR;
class XRCanvasInputProvider;
-class XRCoordinateSystem;
-class XRDevice;
-class XRFrameOfReferenceOptions;
+class XRSpace;
class XRInputSourceEvent;
class XRLayer;
class XRPresentationContext;
+class XRReferenceSpaceOptions;
class XRView;
class XRSession final : public EventTargetWithInlineData,
@@ -43,26 +43,38 @@ class XRSession final : public EventTargetWithInlineData,
USING_GARBAGE_COLLECTED_MIXIN(XRSession);
public:
+ enum SessionMode {
+ kModeUnknown = 0,
+ kModeInline = 1,
+ kModeImmersiveVR = 2,
+ kModeImmersiveAR = 3,
+ kModeInlineAR = 4
+ };
+
+ static SessionMode stringToSessionMode(const String&);
+ static String sessionModeToString(SessionMode);
+
enum EnvironmentBlendMode {
kBlendModeOpaque = 1,
kBlendModeAdditive = 2,
kBlendModeAlphaBlend = 3
};
- XRSession(XRDevice*,
+ XRSession(XR*,
device::mojom::blink::XRSessionClientRequest client_request,
- bool immersive,
- bool environment_integration,
+ SessionMode mode,
XRPresentationContext* output_context,
EnvironmentBlendMode environment_blend_mode);
~XRSession() override = default;
- XRDevice* device() const { return device_; }
- bool immersive() const { return immersive_; }
+ XR* xr() const { return xr_; }
+ const String& mode() const { return mode_string_; }
bool environmentIntegration() const { return environment_integration_; }
XRPresentationContext* outputContext() const { return output_context_; }
const String& environmentBlendMode() const { return blend_mode_string_; }
+ bool immersive() const;
+
// Near and far depths are used when computing projection matrices for this
// Session's views. Changes will propegate to the appropriate matrices on the
// next frame after these values are updated.
@@ -83,9 +95,8 @@ class XRSession final : public EventTargetWithInlineData,
DEFINE_ATTRIBUTE_EVENT_LISTENER(selectend, kSelectend);
DEFINE_ATTRIBUTE_EVENT_LISTENER(select, kSelect);
- ScriptPromise requestFrameOfReference(ScriptState*,
- const String& type,
- const XRFrameOfReferenceOptions*);
+ ScriptPromise requestReferenceSpace(ScriptState*,
+ const XRReferenceSpaceOptions*);
int requestAnimationFrame(V8XRFrameRequestCallback*);
void cancelAnimationFrame(int id);
@@ -98,7 +109,7 @@ class XRSession final : public EventTargetWithInlineData,
ScriptPromise requestHitTest(ScriptState* script_state,
NotShared<DOMFloat32Array> origin,
NotShared<DOMFloat32Array> direction,
- XRCoordinateSystem* coordinate_system);
+ XRSpace* space);
// Called by JavaScript to manually end the session.
ScriptPromise end(ScriptState*);
@@ -186,8 +197,9 @@ class XRSession final : public EventTargetWithInlineData,
base::Optional<WTF::Vector<device::mojom::blink::XRHitResultPtr>>
results);
- const Member<XRDevice> device_;
- const bool immersive_;
+ const Member<XR> xr_;
+ const SessionMode mode_;
+ const String mode_string_;
const bool environment_integration_;
const Member<XRPresentationContext> output_context_;
String blend_mode_string_;
@@ -197,7 +209,7 @@ class XRSession final : public EventTargetWithInlineData,
Member<ResizeObserver> resize_observer_;
Member<XRCanvasInputProvider> canvas_input_provider_;
- bool has_device_focus_ = true;
+ bool has_xr_focus_ = true;
bool is_external_ = false;
int display_info_id_ = 0;
device::mojom::blink::VRDisplayInfoPtr display_info_;
@@ -221,7 +233,7 @@ class XRSession final : public EventTargetWithInlineData,
// Indicates that we've already logged a metric, so don't need to log it
// again.
mutable bool did_log_getInputSources_ = false;
- mutable bool did_log_getDevicePose_ = false;
+ mutable bool did_log_getViewerPose_ = false;
// Dimensions of the output canvas.
int output_width_ = 1;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
index 01b791d5df5..319955fedb5 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -3,6 +3,13 @@
// found in the LICENSE file.
// https://immersive-web.github.io/webxr/#xrsession-interface
+enum XRSessionMode {
+ "inline",
+ "legacy-inline-ar",
+ "immersive-vr",
+ "immersive-ar",
+};
+
enum XREnvironmentBlendMode {
"opaque",
"additive",
@@ -15,8 +22,7 @@ enum XREnvironmentBlendMode {
Exposed=Window,
OriginTrialEnabled=WebXR
] interface XRSession : EventTarget {
- readonly attribute XRDevice device;
- readonly attribute boolean immersive;
+ readonly attribute XRSessionMode mode;
readonly attribute XRPresentationContext outputContext;
readonly attribute XREnvironmentBlendMode environmentBlendMode;
@@ -30,14 +36,14 @@ enum XREnvironmentBlendMode {
attribute EventHandler onresetpose;
attribute EventHandler onend;
- [CallWith=ScriptState] Promise<XRFrameOfReference> requestFrameOfReference(XRFrameOfReferenceType type, [PermissiveDictionaryConversion] optional XRFrameOfReferenceOptions options);
+ [CallWith=ScriptState] Promise<XRReferenceSpace> requestReferenceSpace([PermissiveDictionaryConversion] XRReferenceSpaceOptions options);
long requestAnimationFrame(XRFrameRequestCallback callback);
void cancelAnimationFrame(long handle);
[MeasureAs=XRSessionGetInputSources] FrozenArray<XRInputSource> getInputSources();
- [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState] Promise<FrozenArray<XRHitResult>> requestHitTest(Float32Array origin, Float32Array direction, XRCoordinateSystem coordinateSystem);
+ [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState] Promise<FrozenArray<XRHitResult>> requestHitTest(Float32Array origin, Float32Array direction, XRSpace space);
[CallWith=ScriptState] Promise<void> end();
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
index d66ce6fa69c..6a87694991c 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
@@ -4,7 +4,6 @@
// https://immersive-web.github.io/webxr/#xrsessioncreationoptions-interface
dictionary XRSessionCreationOptions {
- [RuntimeEnabled=WebXRHitTest] boolean environmentIntegration = false;
- boolean immersive = false;
+ XRSessionMode mode = "inline";
XRPresentationContext outputContext;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc b/chromium/third_party/blink/renderer/modules/xr/xr_space.cc
index 11c9f28cce0..066ab9ee7b7 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_space.cc
@@ -1,23 +1,21 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/xr/xr_coordinate_system.h"
+#include "third_party/blink/renderer/modules/xr/xr_space.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
namespace blink {
-XRCoordinateSystem::XRCoordinateSystem(XRSession* session)
- : session_(session) {}
+XRSpace::XRSpace(XRSession* session) : session_(session) {}
-XRCoordinateSystem::~XRCoordinateSystem() = default;
+XRSpace::~XRSpace() = default;
// If possible, get the matrix required to transform between two coordinate
// systems.
-DOMFloat32Array* XRCoordinateSystem::getTransformTo(
- XRCoordinateSystem* other) const {
+DOMFloat32Array* XRSpace::getTransformTo(XRSpace* other) const {
if (session_ != other->session()) {
// Cannot get relationships between coordinate systems that belong to
// different sessions.
@@ -30,15 +28,15 @@ DOMFloat32Array* XRCoordinateSystem::getTransformTo(
return nullptr;
}
-ExecutionContext* XRCoordinateSystem::GetExecutionContext() const {
+ExecutionContext* XRSpace::GetExecutionContext() const {
return session()->GetExecutionContext();
}
-const AtomicString& XRCoordinateSystem::InterfaceName() const {
- return event_target_names::kXRCoordinateSystem;
+const AtomicString& XRSpace::InterfaceName() const {
+ return event_target_names::kXRSpace;
}
-void XRCoordinateSystem::Trace(blink::Visitor* visitor) {
+void XRSpace::Trace(blink::Visitor* visitor) {
visitor->Trace(session_);
ScriptWrappable::Trace(visitor);
EventTargetWithInlineData::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h b/chromium/third_party/blink/renderer/modules/xr/xr_space.h
index 9ba5d6ece16..ca7460c9f9d 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_space.h
@@ -1,9 +1,9 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_COORDINATE_SYSTEM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_COORDINATE_SYSTEM_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SPACE_H_
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
@@ -13,30 +13,25 @@
namespace blink {
-class TransformationMatrix;
class XRSession;
-class XRCoordinateSystem : public EventTargetWithInlineData {
+class XRSpace : public EventTargetWithInlineData {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit XRCoordinateSystem(XRSession*);
- ~XRCoordinateSystem() override;
+ explicit XRSpace(XRSession*);
+ ~XRSpace() override;
- DOMFloat32Array* getTransformTo(XRCoordinateSystem*) const;
+ DOMFloat32Array* getTransformTo(XRSpace*) const;
XRSession* session() const { return session_; }
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(reset, kReset);
+
// EventTarget overrides.
ExecutionContext* GetExecutionContext() const override;
const AtomicString& InterfaceName() const override;
- virtual std::unique_ptr<TransformationMatrix> TransformBasePose(
- const TransformationMatrix& base_pose) = 0;
- virtual std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
- const TransformationMatrix& base_input_pose,
- const TransformationMatrix& base_pose) = 0;
-
void Trace(blink::Visitor*) override;
private:
@@ -45,4 +40,4 @@ class XRCoordinateSystem : public EventTargetWithInlineData {
} // namespace blink
-#endif // XRWebGLLayer_h
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SPACE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_space.idl b/chromium/third_party/blink/renderer/modules/xr/xr_space.idl
new file mode 100644
index 00000000000..0115c413a5a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_space.idl
@@ -0,0 +1,12 @@
+// 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.
+
+// https://immersive-web.github.io/webxr/#xrspace-interface
+[
+ SecureContext,
+ Exposed=Window,
+ OriginTrialEnabled=WebXR
+] interface XRSpace : EventTarget {
+ Float32Array? getTransformTo(XRSpace other);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc
new file mode 100644
index 00000000000..55c227e4ac7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc
@@ -0,0 +1,141 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h"
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h"
+
+namespace blink {
+
+// Rough estimate of avg human eye height in meters.
+const double kDefaultEmulationHeight = 1.6;
+
+XRStationaryReferenceSpace::XRStationaryReferenceSpace(XRSession* session,
+ Subtype subtype)
+ : XRReferenceSpace(session), subtype_(subtype) {
+ switch (subtype_) {
+ case kSubtypeEyeLevel:
+ subtype_string_ = "eye-level";
+ break;
+ case kSubtypeFloorLevel:
+ subtype_string_ = "floor-level";
+ UpdateFloorLevelTransform();
+ break;
+ case kSubtypePositionDisabled:
+ subtype_string_ = "position-disabled";
+ break;
+ default:
+ NOTREACHED() << "Unknown stationary reference space subtype: " << subtype;
+ }
+}
+
+XRStationaryReferenceSpace::~XRStationaryReferenceSpace() = default;
+
+void XRStationaryReferenceSpace::UpdateFloorLevelTransform() {
+ const device::mojom::blink::VRDisplayInfoPtr& display_info =
+ session()->GetVRDisplayInfo();
+
+ if (display_info && display_info->stageParameters) {
+ // Use the transform given by xrDisplayInfo's stageParameters if available.
+ const WTF::Vector<float>& m =
+ display_info->stageParameters->standingTransform;
+ floor_level_transform_ = TransformationMatrix::Create(
+ m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
+ m[11], m[12], m[13], m[14], m[15]);
+ } else {
+ // Otherwise, create a transform based on the default emulated height.
+ floor_level_transform_ = TransformationMatrix::Create();
+ floor_level_transform_->Translate3d(0, kDefaultEmulationHeight, 0);
+ }
+
+ display_info_id_ = session()->DisplayInfoPtrId();
+}
+
+// Transforms a pose into the correct space.
+std::unique_ptr<TransformationMatrix>
+XRStationaryReferenceSpace::TransformBasePose(
+ const TransformationMatrix& base_pose) {
+ switch (subtype_) {
+ case kSubtypeEyeLevel:
+ // Currently all base poses are 'eye-level' poses, so return directly.
+ return TransformationMatrix::Create(base_pose);
+ break;
+ case kSubtypeFloorLevel:
+ // Currently all base poses are 'eye-level' space, so use of 'floor-level'
+ // reference spaces requires adjustment. Ideally the service will
+ // eventually provide poses in the requested space directly, avoiding the
+ // need to do additional transformation here.
+
+ // Check first to see if the xrDisplayInfo has updated since the last
+ // call. If so, update the floor-level transform.
+ if (display_info_id_ != session()->DisplayInfoPtrId())
+ UpdateFloorLevelTransform();
+
+ // Apply the floor-level transform to the base pose.
+ if (floor_level_transform_) {
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(*floor_level_transform_));
+ pose->Multiply(base_pose);
+ return pose;
+ }
+ break;
+ case kSubtypePositionDisabled: {
+ // 'position-disabled' poses must not contain any translation components,
+ // and as a result the space the base pose is originally in doesn't matter
+ // much. Strip out translation component and return.
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(base_pose));
+ pose->SetM41(0.0);
+ pose->SetM42(0.0);
+ pose->SetM43(0.0);
+ return pose;
+ } break;
+ }
+
+ return nullptr;
+}
+
+// Serves the same purpose as TransformBasePose, but for input poses. Needs to
+// know the head pose so that cases like the head-model frame of reference can
+// properly adjust the input's relative position.
+std::unique_ptr<TransformationMatrix>
+XRStationaryReferenceSpace::TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) {
+ switch (subtype_) {
+ case kSubtypePositionDisabled: {
+ std::unique_ptr<TransformationMatrix> head_model_pose(
+ TransformBasePose(base_pose));
+
+ // Get the positional delta between the base pose and the head model pose.
+ float dx = head_model_pose->M41() - base_pose.M41();
+ float dy = head_model_pose->M42() - base_pose.M42();
+ float dz = head_model_pose->M43() - base_pose.M43();
+
+ // Translate the controller by the same delta so that it shows up in the
+ // right relative position.
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(base_input_pose));
+ pose->SetM41(pose->M41() + dx);
+ pose->SetM42(pose->M42() + dy);
+ pose->SetM43(pose->M43() + dz);
+
+ return pose;
+ } break;
+ case kSubtypeEyeLevel:
+ case kSubtypeFloorLevel:
+ return TransformBasePose(base_input_pose);
+ break;
+ }
+
+ return nullptr;
+}
+
+void XRStationaryReferenceSpace::Trace(blink::Visitor* visitor) {
+ XRReferenceSpace::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h
new file mode 100644
index 00000000000..d1065509bf6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STATIONARY_REFERENCE_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STATIONARY_REFERENCE_SPACE_H_
+
+#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRStationaryReferenceSpace final : public XRReferenceSpace {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ enum Subtype {
+ kSubtypeEyeLevel,
+ kSubtypeFloorLevel,
+ kSubtypePositionDisabled
+ };
+
+ XRStationaryReferenceSpace(XRSession*, Subtype);
+ ~XRStationaryReferenceSpace() override;
+
+ std::unique_ptr<TransformationMatrix> TransformBasePose(
+ const TransformationMatrix& base_pose) override;
+ std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) override;
+
+ const String& subtype() const { return subtype_string_; }
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ void UpdateFloorLevelTransform();
+
+ unsigned int display_info_id_ = 0;
+ Subtype subtype_;
+ String subtype_string_;
+ std::unique_ptr<TransformationMatrix> floor_level_transform_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STATIONARY_REFERENCE_SPACE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.idl b/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.idl
new file mode 100644
index 00000000000..ac30cc8e05b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.idl
@@ -0,0 +1,19 @@
+// 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.
+
+// https://immersive-web.github.io/webxr/#xrstationaryreferencespace-interface
+
+enum XRStationaryReferenceSpaceSubtype {
+ "eye-level",
+ "floor-level",
+ "position-disabled"
+};
+
+[
+ SecureContext,
+ Exposed=Window,
+ OriginTrialEnabled=WebXR
+] interface XRStationaryReferenceSpace : XRReferenceSpace {
+ readonly attribute XRStationaryReferenceSpaceSubtype subtype;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc
new file mode 100644
index 00000000000..4998f78922c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h"
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+namespace blink {
+
+XRUnboundedReferenceSpace::XRUnboundedReferenceSpace(XRSession* session)
+ : XRReferenceSpace(session) {}
+
+XRUnboundedReferenceSpace::~XRUnboundedReferenceSpace() = default;
+
+std::unique_ptr<TransformationMatrix>
+XRUnboundedReferenceSpace::TransformBasePose(
+ const TransformationMatrix& base_pose) {
+ // For now we assume that poses returned by systems that support unbounded
+ // reference spaces are already in the correct space.
+ return TransformationMatrix::Create(base_pose);
+}
+
+// Serves the same purpose as TransformBasePose, but for input poses. Needs to
+// know the head pose so that cases like the head-model frame of reference can
+// properly adjust the input's relative position.
+std::unique_ptr<TransformationMatrix>
+XRUnboundedReferenceSpace::TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) {
+ return TransformBasePose(base_input_pose);
+}
+
+void XRUnboundedReferenceSpace::Trace(blink::Visitor* visitor) {
+ XRReferenceSpace::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h
new file mode 100644
index 00000000000..750e90d4676
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UNBOUNDED_REFERENCE_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UNBOUNDED_REFERENCE_SPACE_H_
+
+#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRUnboundedReferenceSpace final : public XRReferenceSpace {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRUnboundedReferenceSpace(XRSession*);
+ ~XRUnboundedReferenceSpace() override;
+
+ std::unique_ptr<TransformationMatrix> TransformBasePose(
+ const TransformationMatrix& base_pose) override;
+ std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) override;
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ std::unique_ptr<TransformationMatrix> pose_transform_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UNBOUNDED_REFERENCE_SPACE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.idl b/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.idl
new file mode 100644
index 00000000000..4826c550b41
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.idl
@@ -0,0 +1,12 @@
+// 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.
+
+// https://immersive-web.github.io/webxr/#xrunboundedreferencespace-interface
+
+[
+ SecureContext,
+ Exposed=Window,
+ OriginTrialEnabled=WebXR
+] interface XRUnboundedReferenceSpace : XRReferenceSpace {
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc b/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
index 3b549c1abb2..96ea9fa2898 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+#include <cmath>
+
namespace blink {
DOMFloat32Array* transformationMatrixToDOMFloat32Array(
@@ -21,4 +23,19 @@ DOMFloat32Array* transformationMatrixToDOMFloat32Array(
return DOMFloat32Array::Create(array, 16);
}
+// Normalize to have length = 1.0
+DOMPointReadOnly* makeNormalizedQuaternion(DOMPointInit* q) {
+ double x = q->x();
+ double y = q->y();
+ double z = q->z();
+ double w = q->w();
+ double length = std::sqrt((x * x) + (y * y) + (z * z) + (w * w));
+ if (length == 0.0) {
+ // Return a default value instead of crashing.
+ return DOMPointReadOnly::Create(0.0, 0.0, 0.0, 1.0);
+ }
+ return DOMPointReadOnly::Create(x / length, y / length, z / length,
+ w / length);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_utils.h b/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
index a90d05c9d63..70c3a6c39fb 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
+#include "third_party/blink/renderer/core/geometry/dom_point_init.h"
+#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
@@ -13,6 +15,8 @@ namespace blink {
DOMFloat32Array* transformationMatrixToDOMFloat32Array(
const TransformationMatrix&);
+DOMPointReadOnly* makeNormalizedQuaternion(DOMPointInit*);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.cc b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
index 875c5e5b590..9fab0a42671 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/modules/xr/xr_frame.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
namespace blink {
@@ -13,10 +14,57 @@ namespace blink {
XRView::XRView(XRSession* session, XREye eye)
: eye_(eye),
session_(session),
- projection_matrix_(DOMFloat32Array::Create(16)) {
+ projection_matrix_(DOMFloat32Array::Create(16)),
+ view_matrix_(DOMFloat32Array::Create(16)) {
eye_string_ = (eye_ == kEyeLeft ? "left" : "right");
}
+XRView::XRView()
+ : eye_(XREye::kEyeLeft),
+ eye_string_("left"),
+ session_(nullptr),
+ projection_matrix_(DOMFloat32Array::Create(16)),
+ view_matrix_(DOMFloat32Array::Create(16)) {}
+
+// deep copy
+XRView::XRView(const XRView& other)
+ : projection_matrix_(DOMFloat32Array::Create(16)),
+ view_matrix_(DOMFloat32Array::Create(16)) {
+ *this = other;
+}
+
+// deep copy
+XRView& XRView::operator=(const XRView& other) {
+ if (&other == this)
+ return *this;
+
+ eye_ = other.eye_;
+ eye_string_ = other.eye_string_;
+ session_ = other.session_;
+ AssignMatrices(other);
+ offset_ = other.offset_;
+
+ // Don't copy the inverse projection matrix because it is rarely used.
+ // Just set this flag so that if UnprojectPointer is called, this matrix
+ // gets computed.
+ inv_projection_dirty_ = true;
+
+ return *this;
+}
+
+void XRView::AssignMatrices(const XRView& other) {
+ const float* src_projection_data = other.projection_matrix_->Data();
+ const float* src_view_data = other.view_matrix_->Data();
+
+ float* dst_projection_data = projection_matrix_->Data();
+ float* dst_view_data = view_matrix_->Data();
+
+ for (int i = 0; i < 16; ++i) {
+ dst_projection_data[i] = src_projection_data[i];
+ dst_view_data[i] = src_view_data[i];
+ }
+}
+
XRSession* XRView::session() const {
return session_;
}
@@ -166,9 +214,19 @@ std::unique_ptr<TransformationMatrix> XRView::UnprojectPointer(
return pointer;
}
+// Pass inv_pose_matrix by value because this method modifies its offset, but
+// the calling code doesn't want it changed.
+void XRView::UpdateViewMatrix(TransformationMatrix inv_pose_matrix) {
+ // Transform by the negative offset, since we're operating on the inverted
+ // matrix
+ inv_pose_matrix.PostTranslate3d(-offset_.X(), -offset_.Y(), -offset_.Z());
+ view_matrix_ = transformationMatrixToDOMFloat32Array(inv_pose_matrix);
+}
+
void XRView::Trace(blink::Visitor* visitor) {
visitor->Trace(session_);
visitor->Trace(projection_matrix_);
+ visitor->Trace(view_matrix_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.h b/chromium/third_party/blink/renderer/modules/xr/xr_view.h
index dbdb1c5697e..fe6f5153f95 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_view.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.h
@@ -25,11 +25,20 @@ class XRView final : public ScriptWrappable {
XRView(XRSession*, XREye);
+ // Default constructor, which I think is needed along with the copy
+ // constructors to make a deep copy of HeapVector<Member<XRView>>
+ XRView();
+
+ // Make deep copies.
+ XRView(const XRView& other);
+ XRView& operator=(const XRView& other);
+
const String& eye() const { return eye_string_; }
XREye EyeValue() const { return eye_; }
XRSession* session() const;
DOMFloat32Array* projectionMatrix() const { return projection_matrix_; }
+ DOMFloat32Array* viewMatrix() const { return view_matrix_; }
void UpdateProjectionMatrixFromRawValues(
const WTF::Vector<float>& projection_matrix,
@@ -53,6 +62,8 @@ class XRView final : public ScriptWrappable {
double canvas_width,
double canvas_height);
+ void UpdateViewMatrix(TransformationMatrix inv_pose_matrix);
+
// TODO(bajones): Should eventually represent this as a full transform.
const FloatPoint3D& offset() const { return offset_; }
void UpdateOffset(float x, float y, float z);
@@ -60,10 +71,13 @@ class XRView final : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
- const XREye eye_;
+ void AssignMatrices(const XRView& other);
+
+ XREye eye_;
String eye_string_;
Member<XRSession> session_;
Member<DOMFloat32Array> projection_matrix_;
+ Member<DOMFloat32Array> view_matrix_;
FloatPoint3D offset_;
std::unique_ptr<TransformationMatrix> inv_projection_;
bool inv_projection_dirty_ = true;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.idl b/chromium/third_party/blink/renderer/modules/xr/xr_view.idl
index 28f1436b60f..c632509ca60 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_view.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.idl
@@ -15,4 +15,5 @@ enum XREye {
] interface XRView {
readonly attribute XREye eye;
readonly attribute Float32Array projectionMatrix;
+ readonly attribute Float32Array viewMatrix;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc
new file mode 100644
index 00000000000..90693f3e5fa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.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 "third_party/blink/renderer/modules/xr/xr_viewer_pose.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+
+namespace blink {
+
+XRViewerPose::XRViewerPose(
+ XRSession* session,
+ std::unique_ptr<TransformationMatrix> pose_model_matrix)
+ : session_(session), pose_model_matrix_(std::move(pose_model_matrix)) {
+ // Can only update views with an invertible matrix.
+ DCHECK(pose_model_matrix_->IsInvertible());
+
+ TransformationMatrix inv_pose_matrix = pose_model_matrix_->Inverse();
+
+ // session will update views if required
+ // views array gets copied to views_
+ views_ = session->views();
+
+ for (Member<XRView>& view : views_) {
+ view->UpdateViewMatrix(inv_pose_matrix);
+ }
+}
+
+const HeapVector<Member<XRView>>& XRViewerPose::views() const {
+ return views_;
+}
+
+DOMFloat32Array* XRViewerPose::poseModelMatrix() const {
+ if (!pose_model_matrix_)
+ return nullptr;
+ return transformationMatrixToDOMFloat32Array(*pose_model_matrix_);
+}
+
+void XRViewerPose::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ visitor->Trace(views_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.h
index d1b80f46bcb..e565e2ce259 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_POSE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_POSE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEWER_POSE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEWER_POSE_H_
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -15,22 +15,23 @@ namespace blink {
class XRSession;
class XRView;
-class XRDevicePose final : public ScriptWrappable {
+class XRViewerPose final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- XRDevicePose(XRSession*, std::unique_ptr<TransformationMatrix>);
+ XRViewerPose(XRSession*, std::unique_ptr<TransformationMatrix>);
DOMFloat32Array* poseModelMatrix() const;
- DOMFloat32Array* getViewMatrix(XRView*);
+ const HeapVector<Member<XRView>>& views() const;
void Trace(blink::Visitor*) override;
private:
const Member<XRSession> session_;
std::unique_ptr<TransformationMatrix> pose_model_matrix_;
+ HeapVector<Member<XRView>> views_;
};
} // namespace blink
-#endif // XRWebGLLayer_h
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEWER_POSE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl
index f71be26d9ef..7b1de7005c7 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://immersive-web.github.io/webxr/#xrdevicepose-interface
+// https://immersive-web.github.io/webxr/#xrviewerpose-interface
+// TODO(https://crbug.com/915021): Update definition to match spec.
[
SecureContext,
Exposed=Window,
OriginTrialEnabled=WebXR
-] interface XRDevicePose {
+] interface XRViewerPose {
readonly attribute Float32Array poseModelMatrix;
-
- Float32Array getViewMatrix(XRView view);
+ readonly attribute FrozenArray<XRView> views;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
index a9f62d52bb6..802d72047d9 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -8,7 +8,7 @@
#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h"
#include "third_party/blink/renderer/modules/webgl/webgl_framebuffer.h"
#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context.h"
-#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr.h"
#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
@@ -61,10 +61,10 @@ XRWebGLLayer* XRWebGLLayer::Create(
return nullptr;
}
- if (!webgl_context->IsXRDeviceCompatible(session->device())) {
+ if (!webgl_context->IsXRCompatible()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
- "The session's device is not the compatible device for this context.");
+ "This context is not marked as XR compatible.");
return nullptr;
}
@@ -72,7 +72,6 @@ XRWebGLLayer* XRWebGLLayer::Create(
bool want_depth_buffer = initializer->depth();
bool want_stencil_buffer = initializer->stencil();
bool want_alpha_channel = initializer->alpha();
- bool want_multiview = initializer->multiview();
double framebuffer_scale = 1.0;
@@ -99,10 +98,10 @@ XRWebGLLayer* XRWebGLLayer::Create(
WebGLFramebuffer* framebuffer = WebGLFramebuffer::CreateOpaque(webgl_context);
scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer =
- XRWebGLDrawingBuffer::Create(
- webgl_context->GetDrawingBuffer(), framebuffer->Object(),
- desired_size, want_alpha_channel, want_depth_buffer,
- want_stencil_buffer, want_antialiasing, want_multiview);
+ XRWebGLDrawingBuffer::Create(webgl_context->GetDrawingBuffer(),
+ framebuffer->Object(), desired_size,
+ want_alpha_channel, want_depth_buffer,
+ want_stencil_buffer, want_antialiasing);
if (!drawing_buffer) {
exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
@@ -129,14 +128,19 @@ XRWebGLLayer::XRWebGLLayer(XRSession* session,
// If the contents need mirroring, indicate that to the drawing buffer.
if (session->immersive() && session->outputContext() && session->External()) {
mirroring_ = true;
- drawing_buffer_->SetMirrorClient(this);
+
+ mirror_client_ = base::AdoptRef(new XRWebGLDrawingBuffer::MirrorClient());
+ drawing_buffer_->SetMirrorClient(mirror_client_);
}
UpdateViewports();
}
XRWebGLLayer::~XRWebGLLayer() {
- if (mirroring_)
+ if (mirroring_) {
drawing_buffer_->SetMirrorClient(nullptr);
+ mirror_client_->BeginDestruction();
+ }
+ mirror_client_ = nullptr;
drawing_buffer_->BeginDestruction();
}
@@ -205,7 +209,7 @@ void XRWebGLLayer::UpdateViewports() {
framebuffer_width * 0.5 * viewport_scale_,
framebuffer_height * viewport_scale_);
- session()->device()->frameProvider()->UpdateWebGLLayerViewports(this);
+ session()->xr()->frameProvider()->UpdateWebGLLayerViewports(this);
// When mirroring make sure to also update the mirrored canvas UVs so it
// only shows a single eye's data, cropped to display proportionally.
@@ -285,7 +289,7 @@ void XRWebGLLayer::OnFrameEnd() {
// Submit the frame to the XR compositor.
if (session()->immersive()) {
// Always call submit, but notify if the contents were changed or not.
- session()->device()->frameProvider()->SubmitWebGLLayer(
+ session()->xr()->frameProvider()->SubmitWebGLLayer(
this, framebuffer_->HaveContentsChanged());
} else if (session()->outputContext()) {
// Nothing to do if the framebuffer contents have not changed.
@@ -324,21 +328,15 @@ scoped_refptr<StaticBitmapImage> XRWebGLLayer::TransferToStaticBitmapImage(
return drawing_buffer_->TransferToStaticBitmapImage(out_release_callback);
}
-void XRWebGLLayer::OnMirrorImageAvailable(
- scoped_refptr<StaticBitmapImage> image,
- std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
- ImageBitmap* image_bitmap = ImageBitmap::Create(std::move(image));
-
- session()->outputContext()->SetImage(image_bitmap);
-
- if (mirror_release_callback_) {
- // TODO(bajones): We should probably have the compositor report to us when
- // it's done with the image, rather than reporting back that it's usable as
- // soon as we receive a new one.
- mirror_release_callback_->Run(gpu::SyncToken(), false /* lost_resource */);
+void XRWebGLLayer::UpdateWebXRMirror() {
+ if (mirroring_) {
+ scoped_refptr<StaticBitmapImage> image = mirror_client_->GetLastImage();
+ if (image) {
+ ImageBitmap* image_bitmap = ImageBitmap::Create(std::move(image));
+ session()->outputContext()->SetImage(image_bitmap);
+ mirror_client_->CallLastReleaseCallback();
+ }
}
-
- mirror_release_callback_ = std::move(release_callback);
}
void XRWebGLLayer::Trace(blink::Visitor* visitor) {
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
index a23ece99225..ad5996b8439 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
@@ -26,8 +26,7 @@ class WebGLRenderingContextBase;
class XRSession;
class XRViewport;
-class XRWebGLLayer final : public XRLayer,
- public XRWebGLDrawingBuffer::MirrorClient {
+class XRWebGLLayer final : public XRLayer {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -58,7 +57,6 @@ class XRWebGLLayer final : public XRLayer,
bool depth() const { return drawing_buffer_->depth(); }
bool stencil() const { return drawing_buffer_->stencil(); }
bool alpha() const { return drawing_buffer_->alpha(); }
- bool multiview() const { return drawing_buffer_->multiview(); }
XRViewport* getViewport(XRView*);
void requestViewportScaling(double scale_factor);
@@ -78,26 +76,23 @@ class XRWebGLLayer final : public XRLayer,
void OverwriteColorBufferFromMailboxTexture(const gpu::MailboxHolder&,
const IntSize& size);
+ void UpdateWebXRMirror();
+
scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage(
std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
- // XRWebGLDrawingBuffer::MirrorClient impementation
- void OnMirrorImageAvailable(
- scoped_refptr<StaticBitmapImage>,
- std::unique_ptr<viz::SingleReleaseCallback>) override;
-
void Trace(blink::Visitor*) override;
private:
Member<XRViewport> left_viewport_;
Member<XRViewport> right_viewport_;
+ scoped_refptr<XRWebGLDrawingBuffer::MirrorClient> mirror_client_;
+
TraceWrapperMember<WebGLRenderingContextBase> webgl_context_;
scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer_;
Member<WebGLFramebuffer> framebuffer_;
- std::unique_ptr<viz::SingleReleaseCallback> mirror_release_callback_;
-
double framebuffer_scale_ = 1.0;
double requested_viewport_scale_ = 1.0;
double viewport_scale_ = 1.0;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
index f5d7a6fe99e..18efb809f86 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
@@ -17,7 +17,6 @@ typedef (WebGLRenderingContext or WebGL2RenderingContext) XRWebGLRenderingContex
readonly attribute boolean depth;
readonly attribute boolean stencil;
readonly attribute boolean alpha;
- readonly attribute boolean multiview;
readonly attribute unsigned long framebufferWidth;
readonly attribute unsigned long framebufferHeight;
diff --git a/chromium/third_party/blink/renderer/platform/BUILD.gn b/chromium/third_party/blink/renderer/platform/BUILD.gn
index ba938f7d750..1277dd8a03d 100644
--- a/chromium/third_party/blink/renderer/platform/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/BUILD.gn
@@ -27,7 +27,7 @@ make_names("font_family_names") {
output_dir = blink_platform_output_dir
}
-action("runtime_enabled_features") {
+blink_python_runner("runtime_enabled_features") {
script = "../build/scripts/make_runtime_features.py"
runtime_enabled_features_json5 = "runtime_enabled_features.json5"
@@ -51,7 +51,7 @@ action("runtime_enabled_features") {
]
}
-action("color_data") {
+blink_python_runner("color_data") {
script = "../build/scripts/gperf.py"
color_data_gperf = "color_data.gperf"
@@ -200,7 +200,7 @@ group("blink_platform_public_deps") {
]
public_configs = [ "//third_party/blink/renderer:features" ]
- if (is_android) {
+ if (is_android || is_win) {
public_deps +=
[ "//third_party/blink/public/common:font_unique_name_table_proto" ]
}
@@ -505,6 +505,7 @@ jumbo_component("platform") {
"exported/file_path_conversion.cc",
"exported/interface_registry.cc",
"exported/platform.cc",
+ "exported/platform_media_stream_source.cc",
"exported/service_registry.cc",
"exported/url_conversion.cc",
"exported/web_audio_bus.cc",
@@ -549,14 +550,15 @@ jumbo_component("platform") {
"exported/web_memory_coordinator.cc",
"exported/web_mixed_content.cc",
"exported/web_network_state_notifier.cc",
+ "exported/web_platform_media_stream_track.cc",
"exported/web_prerender.cc",
"exported/web_prerendering_support.cc",
"exported/web_rtc_answer_options.cc",
"exported/web_rtc_offer_options.cc",
"exported/web_rtc_peer_connection_handler_client.cc",
- "exported/web_rtc_rtp_contributing_source.cc",
"exported/web_rtc_rtp_receiver.cc",
"exported/web_rtc_rtp_sender.cc",
+ "exported/web_rtc_rtp_source.cc",
"exported/web_rtc_rtp_transceiver.cc",
"exported/web_rtc_session_description.cc",
"exported/web_rtc_session_description_request.cc",
@@ -746,6 +748,8 @@ jumbo_component("platform") {
"fonts/win/font_fallback_win.cc",
"fonts/win/font_fallback_win.h",
"fonts/win/font_platform_data_win.cc",
+ "fonts/win/font_unique_name_lookup_win.cc",
+ "fonts/win/font_unique_name_lookup_win.h",
"geometry/blend.h",
"geometry/calculation_value.h",
"geometry/cg/float_point_cg.cc",
@@ -1091,7 +1095,6 @@ jumbo_component("platform") {
"graphics/picture_snapshot.h",
"graphics/placeholder_image.cc",
"graphics/placeholder_image.h",
- "graphics/platform_paint_worklet_input.h",
"graphics/profiling_canvas.cc",
"graphics/profiling_canvas.h",
"graphics/replaying_canvas.cc",
@@ -1210,6 +1213,7 @@ jumbo_component("platform") {
"mojo/bluetooth_struct_traits.h",
"mojo/canonical_cookie_mojom_traits.cc",
"mojo/canonical_cookie_mojom_traits.h",
+ "mojo/fetch_api_request_headers_mojom_traits.h",
"mojo/interface_invalidator.cc",
"mojo/interface_invalidator.h",
"mojo/mojo_helper.h",
@@ -1364,7 +1368,6 @@ jumbo_component("platform") {
"web_mouse_event.cc",
"web_mouse_wheel_event.cc",
"web_pointer_event.cc",
- "web_task_runner.h",
"web_test_support.cc",
"web_test_support.h",
"web_text_input_info.cc",
@@ -1683,6 +1686,7 @@ jumbo_source_set("blink_platform_unittests_sources") {
"fonts/generic_font_family_settings_test.cc",
"fonts/mac/font_matcher_mac_test.mm",
"fonts/opentype/font_settings_test.cc",
+ "fonts/opentype/open_type_caps_support_test.cc",
"fonts/opentype/open_type_vertical_data_test.cc",
"fonts/orientation_iterator_test.cc",
"fonts/script_run_iterator_test.cc",
@@ -1749,7 +1753,6 @@ jumbo_source_set("blink_platform_unittests_sources") {
"graphics/paint_invalidation_reason_test.cc",
"graphics/path_test.cc",
"graphics/placeholder_image_test.cc",
- "graphics/skia/skia_utils_test.cc",
"graphics/static_bitmap_image_test.cc",
"graphics/video_frame_submitter_test.cc",
"histogram_test.cc",
@@ -1768,6 +1771,7 @@ jumbo_source_set("blink_platform_unittests_sources") {
"json/json_parser_test.cc",
"json/json_values_test.cc",
"lifecycle_context_test.cc",
+ "loader/allowed_by_nosniff_test.cc",
"loader/cors/cors_test.cc",
"mac/graphics_context_canvas_test.mm",
"mac/version_util_mac_test.mm",
diff --git a/chromium/third_party/blink/renderer/platform/DEPS b/chromium/third_party/blink/renderer/platform/DEPS
index 86b4080429c..59bdb6efea6 100644
--- a/chromium/third_party/blink/renderer/platform/DEPS
+++ b/chromium/third_party/blink/renderer/platform/DEPS
@@ -16,6 +16,7 @@ include_rules = [
"+base/json",
"+base/location.h",
"+base/logging.h",
+ "+base/mac/mac_util.h",
"+base/memory",
"+base/observer_list.h",
"+base/memory/shared_memory.h",
diff --git a/chromium/third_party/blink/renderer/platform/async_method_runner.h b/chromium/third_party/blink/renderer/platform/async_method_runner.h
index 0313d396639..e083ccc8216 100644
--- a/chromium/third_party/blink/renderer/platform/async_method_runner.h
+++ b/chromium/third_party/blink/renderer/platform/async_method_runner.h
@@ -50,9 +50,20 @@ class AsyncMethodRunner final
TargetClass* object,
TargetMethod method,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- return new AsyncMethodRunner(object, method, std::move(task_runner));
+ return MakeGarbageCollected<AsyncMethodRunner>(object, method,
+ std::move(task_runner));
}
+ AsyncMethodRunner(TargetClass* object,
+ TargetMethod method,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : timer_(std::move(task_runner),
+ this,
+ &AsyncMethodRunner<TargetClass>::Fired),
+ object_(object),
+ method_(method),
+ paused_(false),
+ run_when_unpaused_(false) {}
~AsyncMethodRunner() = default;
// Schedules to run the method asynchronously. Do nothing if it's already
@@ -116,17 +127,6 @@ class AsyncMethodRunner final
void Trace(blink::Visitor* visitor) { visitor->Trace(object_); }
private:
- AsyncMethodRunner(TargetClass* object,
- TargetMethod method,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : timer_(std::move(task_runner),
- this,
- &AsyncMethodRunner<TargetClass>::Fired),
- object_(object),
- method_(method),
- paused_(false),
- run_when_unpaused_(false) {}
-
void Fired(TimerBase*) { (object_->*method_)(); }
TaskRunnerTimer<AsyncMethodRunner<TargetClass>> timer_;
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc b/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc
index 98a5f1621ae..a6334dbeaac 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc
@@ -49,7 +49,7 @@ using namespace vector_math;
const unsigned kMaxBusChannels = 32;
scoped_refptr<AudioBus> AudioBus::Create(unsigned number_of_channels,
- size_t length,
+ uint32_t length,
bool allocate) {
DCHECK_LE(number_of_channels, kMaxBusChannels);
if (number_of_channels > kMaxBusChannels)
@@ -58,7 +58,7 @@ scoped_refptr<AudioBus> AudioBus::Create(unsigned number_of_channels,
return base::AdoptRef(new AudioBus(number_of_channels, length, allocate));
}
-AudioBus::AudioBus(unsigned number_of_channels, size_t length, bool allocate)
+AudioBus::AudioBus(unsigned number_of_channels, uint32_t length, bool allocate)
: length_(length), sample_rate_(0) {
channels_.ReserveInitialCapacity(number_of_channels);
@@ -74,7 +74,7 @@ AudioBus::AudioBus(unsigned number_of_channels, size_t length, bool allocate)
void AudioBus::SetChannelMemory(unsigned channel_index,
float* storage,
- size_t length) {
+ uint32_t length) {
if (channel_index < channels_.size()) {
Channel(channel_index)->Set(storage, length);
// FIXME: verify that this length matches all the other channel lengths
@@ -82,7 +82,7 @@ void AudioBus::SetChannelMemory(unsigned channel_index,
}
}
-void AudioBus::ResizeSmaller(size_t new_length) {
+void AudioBus::ResizeSmaller(uint32_t new_length) {
DCHECK_LE(new_length, length_);
if (new_length <= length_)
length_ = new_length;
@@ -190,7 +190,7 @@ scoped_refptr<AudioBus> AudioBus::CreateBufferFromRange(
const AudioBus* source_buffer,
unsigned start_frame,
unsigned end_frame) {
- size_t number_of_source_frames = source_buffer->length();
+ uint32_t number_of_source_frames = source_buffer->length();
unsigned number_of_channels = source_buffer->NumberOfChannels();
// Sanity checking
@@ -200,7 +200,7 @@ scoped_refptr<AudioBus> AudioBus::CreateBufferFromRange(
if (!is_range_safe)
return nullptr;
- size_t range_length = end_frame - start_frame;
+ uint32_t range_length = end_frame - start_frame;
scoped_refptr<AudioBus> audio_bus = Create(number_of_channels, range_length);
audio_bus->SetSampleRate(source_buffer->SampleRate());
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_bus.h b/chromium/third_party/blink/renderer/platform/audio/audio_bus.h
index 0d29198b79d..c0c8c24528a 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_bus.h
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_bus.h
@@ -70,11 +70,13 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
// is false then setChannelMemory() has to be called later on for each
// channel before the AudioBus is useable...
static scoped_refptr<AudioBus> Create(unsigned number_of_channels,
- size_t length,
+ uint32_t length,
bool allocate = true);
// Tells the given channel to use an externally allocated buffer.
- void SetChannelMemory(unsigned channel_index, float* storage, size_t length);
+ void SetChannelMemory(unsigned channel_index,
+ float* storage,
+ uint32_t length);
// Channels
unsigned NumberOfChannels() const { return channels_.size(); }
@@ -87,11 +89,11 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
const AudioChannel* ChannelByType(unsigned type) const;
// Number of sample-frames
- size_t length() const { return length_; }
+ uint32_t length() const { return length_; }
// resizeSmaller() can only be called with a new length <= the current length.
// The data stored in the bus will remain undisturbed.
- void ResizeSmaller(size_t new_length);
+ void ResizeSmaller(uint32_t new_length);
// Sample-rate : 0.0 if unknown or "don't care"
float SampleRate() const { return sample_rate_; }
@@ -167,7 +169,7 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
protected:
AudioBus() = default;
- AudioBus(unsigned number_of_channels, size_t length, bool allocate);
+ AudioBus(unsigned number_of_channels, uint32_t length, bool allocate);
void DiscreteSumFrom(const AudioBus&);
@@ -176,7 +178,7 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
void SumFromByUpMixing(const AudioBus&);
void SumFromByDownMixing(const AudioBus&);
- size_t length_;
+ uint32_t length_;
Vector<std::unique_ptr<AudioChannel>> channels_;
int layout_;
float sample_rate_; // 0.0 if unknown or N/A
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_destination.cc b/chromium/third_party/blink/renderer/platform/audio/audio_destination.cc
index 6f99b28263c..ad35bf76b27 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_destination.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_destination.cc
@@ -166,7 +166,12 @@ void AudioDestination::RequestRender(size_t frames_requested,
frames_elapsed_ / static_cast<double>(web_audio_device_->SampleRate()) -
delay;
output_position.timestamp = delay_timestamp;
- base::TimeTicks received_timestamp = base::TimeTicks::Now();
+
+ base::TimeTicks callback_request = base::TimeTicks::Now();
+ AudioIOCallbackMetric metric;
+ metric.callback_interval =
+ (callback_request - previous_callback_request_).InSecondsF();
+ metric.render_duration = previous_render_duration_.InSecondsF();
for (size_t pushed_frames = 0; pushed_frames < frames_to_render;
pushed_frames += audio_utilities::kRenderQuantumFrames) {
@@ -174,7 +179,7 @@ void AudioDestination::RequestRender(size_t frames_requested,
// we do not want output position to get stuck so we promote it
// using the elapsed time from the moment it was initially obtained.
if (callback_buffer_size_ > audio_utilities::kRenderQuantumFrames * 2) {
- double delta = (base::TimeTicks::Now() - received_timestamp).InSecondsF();
+ double delta = (base::TimeTicks::Now() - callback_request).InSecondsF();
output_position.position += delta;
output_position.timestamp += delta;
}
@@ -186,11 +191,16 @@ void AudioDestination::RequestRender(size_t frames_requested,
// Process WebAudio graph and push the rendered output to FIFO.
callback_.Render(render_bus_.get(), audio_utilities::kRenderQuantumFrames,
- output_position);
+ output_position, metric);
fifo_->Push(render_bus_.get());
}
+ // Update the IO callback metric with information from the current iteration.
+ // They are will be picked up in the next render request.
+ previous_callback_request_ = callback_request;
+ previous_render_duration_ = base::TimeTicks::Now() - callback_request;
+
frames_elapsed_ += frames_requested;
}
@@ -246,7 +256,7 @@ void AudioDestination::Resume() {
}
}
-size_t AudioDestination::CallbackBufferSize() const {
+uint32_t AudioDestination::CallbackBufferSize() const {
DCHECK(IsMainThread());
return callback_buffer_size_;
}
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_destination.h b/chromium/third_party/blink/renderer/platform/audio/audio_destination.h
index a6a93e629bd..5709fadb66b 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_destination.h
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_destination.h
@@ -99,7 +99,7 @@ class PLATFORM_EXPORT AudioDestination
scoped_refptr<base::SingleThreadTaskRunner> worklet_task_runner);
// Getters must be accessed from the main thread.
- size_t CallbackBufferSize() const;
+ uint32_t CallbackBufferSize() const;
bool IsPlaying();
// TODO(hongchan): this should not be called by the rendering thread.
@@ -124,7 +124,7 @@ class PLATFORM_EXPORT AudioDestination
// Accessed by the main thread.
std::unique_ptr<WebAudioDevice> web_audio_device_;
const unsigned number_of_output_channels_;
- size_t callback_buffer_size_;
+ uint32_t callback_buffer_size_;
PlayState play_state_;
// The task runner for AudioWorklet operation. This is only valid when
@@ -146,6 +146,12 @@ class PLATFORM_EXPORT AudioDestination
// engine. (i.e. DestinationNode)
AudioIOCallback& callback_;
+ // When the last callback function from the device is called.
+ base::TimeTicks previous_callback_request_;
+
+ // The time duration spent on rendering previous render quanta per callback.
+ base::TimeDelta previous_render_duration_;
+
// Accessed by rendering thread.
size_t frames_elapsed_;
};
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_io_callback.h b/chromium/third_party/blink/renderer/platform/audio/audio_io_callback.h
index 99f0372823a..cb9e87dcaec 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_io_callback.h
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_io_callback.h
@@ -35,6 +35,18 @@ namespace blink {
class AudioBus;
+// For the calculation of "render capacity". The render capacity can be
+// calculated by dividing |render_duration| by |callback_interval|.
+struct AudioIOCallbackMetric {
+ // The time interval in seconds between the onset of previous callback
+ // function and the current one.
+ double callback_interval;
+
+ // The time duration spent on rendering render quanta (i.e. batch pulling of
+ // audio graph) per a device callback request.
+ double render_duration;
+};
+
struct AudioIOPosition {
// Audio stream position in seconds.
double position;
@@ -50,7 +62,8 @@ class AudioIOCallback {
// |destination_bus|.
virtual void Render(AudioBus* destination_bus,
uint32_t frames_to_process,
- const AudioIOPosition& output_position) = 0;
+ const AudioIOPosition& output_position,
+ const AudioIOCallbackMetric& metric) = 0;
virtual ~AudioIOCallback() = default;
};
diff --git a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc
index 6d2eb3757b3..77350a1f66e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc
@@ -20,7 +20,7 @@ void ActiveScriptWrappableBase::TraceActiveScriptWrappables(
if (!active_script_wrappables)
return;
- for (auto active_wrappable : *active_script_wrappables) {
+ for (const auto& active_wrappable : *active_script_wrappables) {
if (!active_wrappable->DispatchHasPendingActivity())
continue;
diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc
index 07c8a4c7e8c..90fb952442e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc
@@ -4,18 +4,30 @@
#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
+#include "third_party/blink/renderer/platform/bindings/binding_security_for_platform.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
namespace blink {
CallbackFunctionBase::CallbackFunctionBase(
v8::Local<v8::Object> callback_function) {
DCHECK(!callback_function.IsEmpty());
- callback_relevant_script_state_ =
- ScriptState::From(callback_function->CreationContext());
- v8::Isolate* isolate = callback_relevant_script_state_->GetIsolate();
-
+ v8::Isolate* isolate = callback_function->GetIsolate();
callback_function_.Set(isolate, callback_function);
+
incumbent_script_state_ = ScriptState::From(isolate->GetIncumbentContext());
+
+ // Set |callback_relevant_script_state_| iff the creation context and the
+ // incumbent context are the same origin-domain. Otherwise, leave it as
+ // nullptr.
+ v8::Local<v8::Context> creation_context =
+ callback_function->CreationContext();
+ if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context(
+ incumbent_script_state_->GetContext(), creation_context,
+ BindingSecurityForPlatform::ErrorReportOption::kDoNotReport)) {
+ callback_relevant_script_state_ = ScriptState::From(creation_context);
+ }
}
void CallbackFunctionBase::Trace(Visitor* visitor) {
@@ -24,9 +36,44 @@ void CallbackFunctionBase::Trace(Visitor* visitor) {
visitor->Trace(incumbent_script_state_);
}
+ScriptState* CallbackFunctionBase::CallbackRelevantScriptStateOrReportError(
+ const char* interface,
+ const char* operation) {
+ if (callback_relevant_script_state_)
+ return callback_relevant_script_state_;
+
+ // Report a SecurityError due to a cross origin callback object.
+ ScriptState::Scope incumbent_scope(incumbent_script_state_);
+ v8::TryCatch try_catch(GetIsolate());
+ try_catch.SetVerbose(true);
+ ExceptionState exception_state(
+ GetIsolate(), ExceptionState::kExecutionContext, interface, operation);
+ exception_state.ThrowSecurityError(
+ "An invocation of the provided callback failed due to cross origin "
+ "access.");
+ return nullptr;
+}
+
+ScriptState* CallbackFunctionBase::CallbackRelevantScriptStateOrThrowException(
+ const char* interface,
+ const char* operation) {
+ if (callback_relevant_script_state_)
+ return callback_relevant_script_state_;
+
+ // Throw a SecurityError due to a cross origin callback object.
+ ScriptState::Scope incumbent_scope(incumbent_script_state_);
+ ExceptionState exception_state(
+ GetIsolate(), ExceptionState::kExecutionContext, interface, operation);
+ exception_state.ThrowSecurityError(
+ "An invocation of the provided callback failed due to cross origin "
+ "access.");
+ return nullptr;
+}
+
V8PersistentCallbackFunctionBase::V8PersistentCallbackFunctionBase(
CallbackFunctionBase* callback_function)
: callback_function_(callback_function) {
+ v8::HandleScope scope(callback_function_->GetIsolate());
v8_function_.Reset(callback_function_->GetIsolate(),
callback_function_->callback_function_.Get());
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h
index cc38447a2ad..e13ff148990 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h
@@ -36,22 +36,55 @@ class PLATFORM_EXPORT CallbackFunctionBase
}
v8::Isolate* GetIsolate() const {
- return callback_relevant_script_state_->GetIsolate();
+ return incumbent_script_state_->GetIsolate();
}
+ // Returns the ScriptState of the relevant realm of the callback object.
+ //
+ // NOTE: This function must be used only when it's pretty sure that the
+ // callcack object is the same origin-domain. Otherwise,
+ // |CallbackRelevantScriptStateOrReportError| or
+ // |CallbackRelevantScriptStateOrThrowException| must be used instead.
ScriptState* CallbackRelevantScriptState() {
+ DCHECK(callback_relevant_script_state_);
return callback_relevant_script_state_;
}
+ // Returns the ScriptState of the relevant realm of the callback object iff
+ // the callback is the same origin-domain. Otherwise, reports an error and
+ // returns nullptr.
+ ScriptState* CallbackRelevantScriptStateOrReportError(const char* interface,
+ const char* operation);
+
+ // Returns the ScriptState of the relevant realm of the callback object iff
+ // the callback is the same origin-domain. Otherwise, throws an exception and
+ // returns nullptr.
+ ScriptState* CallbackRelevantScriptStateOrThrowException(
+ const char* interface,
+ const char* operation);
+
+ DOMWrapperWorld& GetWorld() const { return incumbent_script_state_->World(); }
+
// Returns true if the ES function has a [[Construct]] internal method.
bool IsConstructor() const { return CallbackFunction()->IsConstructor(); }
+ // Makes the underlying V8 function collectable by V8 Scavenger GC. Do not
+ // use this function unless you really need a hacky performance optimization.
+ // The V8 function is collectable by V8 Full GC whenever this instance is no
+ // longer referenced, so there is no need to call this function unless you
+ // really need V8 *Scavenger* GC to collect the V8 function before V8 Full GC
+ // runs.
+ void DisposeV8FunctionImmediatelyToReduceMemoryFootprint() {
+ callback_function_.Clear();
+ }
+
protected:
explicit CallbackFunctionBase(v8::Local<v8::Object>);
v8::Local<v8::Function> CallbackFunction() const {
return callback_function_.NewLocal(GetIsolate()).As<v8::Function>();
}
+
ScriptState* IncumbentScriptState() { return incumbent_script_state_; }
private:
@@ -59,7 +92,8 @@ class PLATFORM_EXPORT CallbackFunctionBase
// Use v8::Object instead of v8::Function in order to handle
// [TreatNonObjectAsNull].
TraceWrapperV8Reference<v8::Object> callback_function_;
- // The associated Realm of the callback function type value.
+ // The associated Realm of the callback function type value iff it's the same
+ // origin-domain. Otherwise, nullptr.
Member<ScriptState> callback_relevant_script_state_;
// The callback context, i.e. the incumbent Realm when an ECMAScript value is
// converted to an IDL value.
@@ -67,9 +101,6 @@ class PLATFORM_EXPORT CallbackFunctionBase
Member<ScriptState> incumbent_script_state_;
friend class V8PersistentCallbackFunctionBase;
- friend v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback,
- v8::Local<v8::Object> creation_context,
- v8::Isolate*);
};
// V8PersistentCallbackFunctionBase retains the underlying v8::Function of a
@@ -124,7 +155,8 @@ ToV8PersistentCallbackFunction(V8CallbackFunction* callback_function) {
std::is_base_of<CallbackFunctionBase, V8CallbackFunction>::value,
"V8CallbackFunction must be a subclass of CallbackFunctionBase.");
return callback_function
- ? new V8PersistentCallbackFunction<V8CallbackFunction>(
+ ? MakeGarbageCollected<
+ V8PersistentCallbackFunction<V8CallbackFunction>>(
callback_function)
: nullptr;
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc
index 6523b794190..f5d336ffc0a 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc
@@ -4,25 +4,32 @@
#include "third_party/blink/renderer/platform/bindings/callback_interface_base.h"
+#include "third_party/blink/renderer/platform/bindings/binding_security_for_platform.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
namespace blink {
CallbackInterfaceBase::CallbackInterfaceBase(
v8::Local<v8::Object> callback_object,
- v8::Local<v8::Context> callback_object_creation_context,
SingleOperationOrNot single_op_or_not) {
DCHECK(!callback_object.IsEmpty());
- DCHECK(!callback_object_creation_context.IsEmpty());
- DCHECK(callback_object->CreationContext() ==
- callback_object_creation_context);
-
- callback_relevant_script_state_ =
- ScriptState::From(callback_object_creation_context);
- v8::Isolate* isolate = callback_relevant_script_state_->GetIsolate();
+ v8::Isolate* isolate = callback_object->GetIsolate();
callback_object_.Set(isolate, callback_object);
+
+ incumbent_script_state_ = ScriptState::From(isolate->GetIncumbentContext());
is_callback_object_callable_ =
(single_op_or_not == kSingleOperation) && callback_object->IsCallable();
- incumbent_script_state_ = ScriptState::From(isolate->GetIncumbentContext());
+
+ // Set |callback_relevant_script_state_| iff the creation context and the
+ // incumbent context are the same origin-domain. Otherwise, leave it as
+ // nullptr.
+ v8::Local<v8::Context> creation_context = callback_object->CreationContext();
+ if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context(
+ incumbent_script_state_->GetContext(), creation_context,
+ BindingSecurityForPlatform::ErrorReportOption::kDoNotReport)) {
+ callback_relevant_script_state_ = ScriptState::From(creation_context);
+ }
}
void CallbackInterfaceBase::Trace(Visitor* visitor) {
@@ -31,6 +38,40 @@ void CallbackInterfaceBase::Trace(Visitor* visitor) {
visitor->Trace(incumbent_script_state_);
}
+ScriptState* CallbackInterfaceBase::CallbackRelevantScriptStateOrReportError(
+ const char* interface,
+ const char* operation) {
+ if (callback_relevant_script_state_)
+ return callback_relevant_script_state_;
+
+ // Report a SecurityError due to a cross origin callback object.
+ ScriptState::Scope incumbent_scope(incumbent_script_state_);
+ v8::TryCatch try_catch(GetIsolate());
+ try_catch.SetVerbose(true);
+ ExceptionState exception_state(
+ GetIsolate(), ExceptionState::kExecutionContext, interface, operation);
+ exception_state.ThrowSecurityError(
+ "An invocation of the provided callback failed due to cross origin "
+ "access.");
+ return nullptr;
+}
+
+ScriptState* CallbackInterfaceBase::CallbackRelevantScriptStateOrThrowException(
+ const char* interface,
+ const char* operation) {
+ if (callback_relevant_script_state_)
+ return callback_relevant_script_state_;
+
+ // Throw a SecurityError due to a cross origin callback object.
+ ScriptState::Scope incumbent_scope(incumbent_script_state_);
+ ExceptionState exception_state(
+ GetIsolate(), ExceptionState::kExecutionContext, interface, operation);
+ exception_state.ThrowSecurityError(
+ "An invocation of the provided callback failed due to cross origin "
+ "access.");
+ return nullptr;
+}
+
V8PersistentCallbackInterfaceBase::V8PersistentCallbackInterfaceBase(
CallbackInterfaceBase* callback_interface)
: callback_interface_(callback_interface) {
diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h
index cdd141a3f2b..902d3badf87 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h
@@ -49,14 +49,34 @@ class PLATFORM_EXPORT CallbackInterfaceBase
return callback_object_.NewLocal(GetIsolate());
}
- v8::Isolate* GetIsolate() {
- return callback_relevant_script_state_->GetIsolate();
- }
-
+ v8::Isolate* GetIsolate() { return incumbent_script_state_->GetIsolate(); }
+
+ // Returns the ScriptState of the relevant realm of the callback object.
+ //
+ // NOTE: This function must be used only when it's pretty sure that the
+ // callcack object is the same origin-domain. Otherwise,
+ // |CallbackRelevantScriptStateOrReportError| or
+ // |CallbackRelevantScriptStateOrThrowException| must be used instead.
ScriptState* CallbackRelevantScriptState() {
+ DCHECK(callback_relevant_script_state_);
return callback_relevant_script_state_;
}
+ // Returns the ScriptState of the relevant realm of the callback object iff
+ // the callback is the same origin-domain. Otherwise, reports an error and
+ // returns nullptr.
+ ScriptState* CallbackRelevantScriptStateOrReportError(const char* interface,
+ const char* operation);
+
+ // Returns the ScriptState of the relevant realm of the callback object iff
+ // the callback is the same origin-domain. Otherwise, throws an exception and
+ // returns nullptr.
+ ScriptState* CallbackRelevantScriptStateOrThrowException(
+ const char* interface,
+ const char* operation);
+
+ DOMWrapperWorld& GetWorld() const { return incumbent_script_state_->World(); }
+
// NodeIteratorBase counts the invocation of those which are callable and
// those which are not.
bool IsCallbackObjectCallableForNodeIteratorBase() const {
@@ -64,13 +84,13 @@ class PLATFORM_EXPORT CallbackInterfaceBase
}
protected:
- CallbackInterfaceBase(v8::Local<v8::Object> callback_object,
- v8::Local<v8::Context> callback_object_creation_context,
- SingleOperationOrNot);
+ explicit CallbackInterfaceBase(v8::Local<v8::Object> callback_object,
+ SingleOperationOrNot);
// Returns true iff the callback interface is a single operation callback
// interface and the callback interface type value is callable.
bool IsCallbackObjectCallable() const { return is_callback_object_callable_; }
+
ScriptState* IncumbentScriptState() { return incumbent_script_state_; }
private:
@@ -87,10 +107,6 @@ class PLATFORM_EXPORT CallbackInterfaceBase
Member<ScriptState> incumbent_script_state_;
friend class V8PersistentCallbackInterfaceBase;
- // ToV8 needs to call |CallbackObject| member function.
- friend v8::Local<v8::Value> ToV8(CallbackInterfaceBase* callback,
- v8::Local<v8::Object> creation_context,
- v8::Isolate*);
};
// V8PersistentCallbackInterfaceBase retains the underlying v8::Object of a
@@ -145,7 +161,8 @@ ToV8PersistentCallbackInterface(V8CallbackInterface* callback_interface) {
std::is_base_of<CallbackInterfaceBase, V8CallbackInterface>::value,
"V8CallbackInterface must be a subclass of CallbackInterfaceBase.");
return callback_interface
- ? new V8PersistentCallbackInterface<V8CallbackInterface>(
+ ? MakeGarbageCollected<
+ V8PersistentCallbackInterface<V8CallbackInterface>>(
callback_interface)
: nullptr;
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc
index 2394eec2ba1..ba8e013d0c7 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc
@@ -18,8 +18,9 @@ CallbackMethodRetriever::CallbackMethodRetriever(
DCHECK(constructor_->IsConstructor());
}
-void CallbackMethodRetriever::GetPrototypeObject(
+v8::Local<v8::Object> CallbackMethodRetriever::GetPrototypeObject(
ExceptionState& exception_state) {
+ DCHECK(prototype_object_.IsEmpty()) << "Do not call GetPrototypeObject twice";
// https://html.spec.whatwg.org/C/custom-elements.html#element-definition
// step 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any
// exceptions.
@@ -29,15 +30,16 @@ void CallbackMethodRetriever::GetPrototypeObject(
->Get(current_context_, V8AtomicString(isolate_, "prototype"))
.ToLocal(&prototype)) {
exception_state.RethrowV8Exception(try_catch.Exception());
- return;
+ return v8::Local<v8::Object>();
}
// step 10.2. If Type(prototype) is not Object, then throw a TypeError
// exception.
if (!prototype->IsObject()) {
exception_state.ThrowTypeError("constructor prototype is not an object");
- return;
+ return v8::Local<v8::Object>();
}
prototype_object_ = prototype.As<v8::Object>();
+ return prototype_object_;
}
v8::Local<v8::Value> CallbackMethodRetriever::GetFunctionOrUndefined(
diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h
index 1207dbe811b..ee8f10acb2d 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h
@@ -28,7 +28,7 @@ class PLATFORM_EXPORT CallbackMethodRetriever {
// Get the prototype object from the callback function. Must be invoked prior
// to GetMethod or GetStaticMethod.
- void GetPrototypeObject(ExceptionState&);
+ v8::Local<v8::Object> GetPrototypeObject(ExceptionState&);
// Returns a function extracted from the prototype chain, or undefined.
// Throws if the property is neither of function nor undefined.
diff --git a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
index 0777e2cf2b6..7b69bb134e8 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
@@ -133,7 +133,6 @@ DOMWrapperWorld::~DOMWrapperWorld() {
}
void DOMWrapperWorld::Dispose() {
- dom_object_holders_.clear();
dom_data_store_.reset();
DCHECK(GetWorldMap().Contains(world_id_));
GetWorldMap().erase(world_id_);
@@ -207,26 +206,6 @@ void DOMWrapperWorld::SetNonMainWorldHumanReadableName(
IsolatedWorldHumanReadableNames().Set(world_id, human_readable_name);
}
-void DOMWrapperWorld::RegisterDOMObjectHolderInternal(
- std::unique_ptr<DOMObjectHolderBase> holder_base) {
- DCHECK(!dom_object_holders_.Contains(holder_base.get()));
- holder_base->SetWorld(this);
- holder_base->SetWeak(&DOMWrapperWorld::WeakCallbackForDOMObjectHolder);
- dom_object_holders_.insert(std::move(holder_base));
-}
-
-void DOMWrapperWorld::UnregisterDOMObjectHolder(
- DOMObjectHolderBase* holder_base) {
- DCHECK(dom_object_holders_.Contains(holder_base));
- dom_object_holders_.erase(holder_base);
-}
-
-void DOMWrapperWorld::WeakCallbackForDOMObjectHolder(
- const v8::WeakCallbackInfo<DOMObjectHolderBase>& data) {
- DOMObjectHolderBase* holder_base = data.GetParameter();
- holder_base->World()->UnregisterDOMObjectHolder(holder_base);
-}
-
// static
int DOMWrapperWorld::GenerateWorldIdForType(WorldType world_type) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<int>, next_world_id, ());
diff --git a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
index fca64772026..251116e7bc9 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
@@ -45,7 +45,6 @@
namespace blink {
class DOMDataStore;
-class DOMObjectHolderBase;
class ScriptWrappable;
class SecurityOrigin;
@@ -122,8 +121,11 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
// Associates an isolated world (see above for description) with a security
// origin. XMLHttpRequest instances used in that world will be considered
// to come from that origin, not the frame's.
- static void SetIsolatedWorldSecurityOrigin(int world_id,
- scoped_refptr<SecurityOrigin>);
+ // Note: if |security_origin| is null, the security origin stored for the
+ // isolated world is cleared.
+ static void SetIsolatedWorldSecurityOrigin(
+ int world_id,
+ scoped_refptr<SecurityOrigin> security_origin);
SecurityOrigin* IsolatedWorldSecurityOrigin();
static bool HasWrapperInAnyWorldInMainThread(ScriptWrappable*);
@@ -138,58 +140,9 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
int GetWorldId() const { return world_id_; }
DOMDataStore& DomDataStore() const { return *dom_data_store_; }
- template <typename T>
- void RegisterDOMObjectHolder(v8::Isolate* isolate,
- T* object,
- v8::Local<v8::Value> wrapper) {
- RegisterDOMObjectHolderInternal(
- DOMObjectHolder<T>::Create(isolate, object, wrapper));
- }
-
private:
- class DOMObjectHolderBase {
- USING_FAST_MALLOC(DOMObjectHolderBase);
-
- public:
- DOMObjectHolderBase(v8::Isolate* isolate, v8::Local<v8::Value> wrapper)
- : wrapper_(isolate, wrapper), world_(nullptr) {}
- virtual ~DOMObjectHolderBase() = default;
-
- DOMWrapperWorld* World() const { return world_; }
- void SetWorld(DOMWrapperWorld* world) { world_ = world; }
- void SetWeak(v8::WeakCallbackInfo<DOMObjectHolderBase>::Callback callback) {
- wrapper_.SetWeak(this, callback);
- }
-
- private:
- ScopedPersistent<v8::Value> wrapper_;
- DOMWrapperWorld* world_;
- };
-
- template <typename T>
- class DOMObjectHolder : public DOMObjectHolderBase {
- public:
- static std::unique_ptr<DOMObjectHolder<T>>
- Create(v8::Isolate* isolate, T* object, v8::Local<v8::Value> wrapper) {
- return base::WrapUnique(new DOMObjectHolder(isolate, object, wrapper));
- }
-
- private:
- DOMObjectHolder(v8::Isolate* isolate,
- T* object,
- v8::Local<v8::Value> wrapper)
- : DOMObjectHolderBase(isolate, wrapper), object_(object) {}
-
- Persistent<T> object_;
- };
-
DOMWrapperWorld(v8::Isolate*, WorldType, int world_id);
- static void WeakCallbackForDOMObjectHolder(
- const v8::WeakCallbackInfo<DOMObjectHolderBase>&);
- void RegisterDOMObjectHolderInternal(std::unique_ptr<DOMObjectHolderBase>);
- void UnregisterDOMObjectHolder(DOMObjectHolderBase*);
-
static unsigned number_of_non_main_worlds_in_main_thread_;
// Returns an identifier for a given world type. This must not be called for
@@ -224,7 +177,6 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
const WorldType world_type_;
const int world_id_;
std::unique_ptr<DOMDataStore> dom_data_store_;
- HashSet<std::unique_ptr<DOMObjectHolderBase>> dom_object_holders_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc
index f2189c0b52c..df13aa4ab0e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc
@@ -15,10 +15,12 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
#include "third_party/blink/renderer/platform/scheduler/public/background_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/address_sanitizer.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/zlib/google/compression_utils.h"
@@ -86,6 +88,32 @@ void AsanUnpoisonString(const String& string) {
#endif // defined(ADDRESS_SANITIZER)
}
+// Char buffer allocated using PartitionAlloc, may be nullptr.
+class NullableCharBuffer final {
+ public:
+ explicit NullableCharBuffer(size_t size) {
+ data_ =
+ reinterpret_cast<char*>(WTF::Partitions::BufferPartition()->AllocFlags(
+ base::PartitionAllocReturnNull, size, "NullableCharBuffer"));
+ size_ = size;
+ }
+
+ ~NullableCharBuffer() {
+ if (data_)
+ WTF::Partitions::BufferPartition()->Free(data_);
+ }
+
+ // May return nullptr.
+ char* data() const { return data_; }
+ size_t size() const { return size_; }
+
+ private:
+ char* data_;
+ size_t size_;
+
+ DISALLOW_COPY_AND_ASSIGN(NullableCharBuffer);
+};
+
} // namespace
// Created and destroyed on the same thread, accessed on a background thread as
@@ -185,6 +213,12 @@ void ParkableStringImpl::Unlock() {
#endif // defined(ADDRESS_SANITIZER) && DCHECK_IS_ON()
}
+void ParkableStringImpl::PurgeMemory() {
+ AssertOnValidThread();
+ if (state_ == State::kUnparked)
+ compressed_ = nullptr;
+}
+
const String& ParkableStringImpl::ToString() {
AssertOnValidThread();
MutexLocker locker(mutex_);
@@ -338,22 +372,43 @@ void ParkableStringImpl::CompressInBackground(
#endif // defined(ADDRESS_SANITIZER)
// Compression touches the string.
AsanUnpoisonString(params->string->string_);
+ bool ok;
base::StringPiece data(reinterpret_cast<const char*>(params->data),
params->size);
- std::string compressed_string;
- bool ok = compression::GzipCompress(data, &compressed_string);
-
std::unique_ptr<Vector<uint8_t>> compressed = nullptr;
- if (ok && compressed_string.size() < params->size) {
- compressed = std::make_unique<Vector<uint8_t>>();
- compressed->Append(
- reinterpret_cast<const uint8_t*>(compressed_string.c_str()),
- compressed_string.size());
- }
+
+ {
+ // Temporary vector. As we don't want to waste memory, the temporary buffer
+ // has the same size as the initial data. Compression will fail if this is
+ // not large enough.
+ //
+ // This is not using:
+ // - malloc() or any STL container: this is discouraged in blink, and there
+ // is a suspected memory regression caused by using it (crbug.com/920194).
+ // - WTF::Vector<> as allocation failures result in an OOM crash, whereas
+ // we can fail gracefully. See crbug.com/905777 for an example of OOM
+ // triggered from there.
+ NullableCharBuffer buffer(params->size);
+ ok = buffer.data();
+ size_t compressed_size;
+ if (ok) {
+ ok = compression::GzipCompress(data, buffer.data(), buffer.size(),
+ &compressed_size);
+ }
+
#if defined(ADDRESS_SANITIZER)
- params->string->Unlock();
+ params->string->Unlock();
#endif // defined(ADDRESS_SANITIZER)
+ if (ok) {
+ compressed = std::make_unique<Vector<uint8_t>>();
+ // Not using realloc() as we want the compressed data to be a regular
+ // WTF::Vector.
+ compressed->Append(reinterpret_cast<const uint8_t*>(buffer.data()),
+ compressed_size);
+ }
+ }
+
auto* task_runner = params->callback_task_runner.get();
size_t size = params->size;
PostCrossThreadTask(
@@ -396,6 +451,18 @@ void ParkableString::Unlock() const {
impl_->Unlock();
}
+void ParkableString::OnMemoryDump(WebProcessMemoryDump* pmd,
+ const String& name) const {
+ // Parkable strings are reported by ParkableStringManager.
+ if (!impl_ || may_be_parked())
+ return;
+
+ auto* dump = pmd->CreateMemoryAllocatorDump(name);
+ dump->AddScalar("size", "bytes", CharactersSizeInBytes());
+ pmd->AddSuballocation(dump->Guid(),
+ String(WTF::Partitions::kAllocatedObjectPoolName));
+}
+
bool ParkableString::Is8Bit() const {
return impl_->is_8bit();
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h
index d828bcc9c35..30cdf7bd3fb 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h
@@ -30,6 +30,7 @@
namespace blink {
+class WebProcessMemoryDump;
struct CompressionTaskParams;
// A parked string is parked by calling |Park()|, and unparked by calling
@@ -60,6 +61,8 @@ class PLATFORM_EXPORT ParkableStringImpl final
void Lock();
void Unlock();
+ void PurgeMemory();
+
// The returned string may be used as a normal one, as long as the
// returned value (or a copy of it) is alive.
const String& ToString();
@@ -153,6 +156,8 @@ class PLATFORM_EXPORT ParkableString final {
// Can be called from any thread.
void Unlock() const;
+ void OnMemoryDump(WebProcessMemoryDump* pmd, const String& name) const;
+
// See the matching String methods.
bool Is8Bit() const;
bool IsNull() const { return !impl_; }
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
index 11b9aa40e8b..b38c876b53c 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
@@ -10,6 +10,8 @@
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/process_memory_dump.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/memory_coordinator.h"
@@ -21,6 +23,8 @@
namespace blink {
+namespace {
+
class OnPurgeMemoryListener : public GarbageCollected<OnPurgeMemoryListener>,
public MemoryCoordinatorClient {
USING_GARBAGE_COLLECTED_MIXIN(OnPurgeMemoryListener);
@@ -28,12 +32,30 @@ class OnPurgeMemoryListener : public GarbageCollected<OnPurgeMemoryListener>,
void OnPurgeMemory() override {
if (!base::FeatureList::IsEnabled(kCompressParkableStringsInBackground))
return;
-
- ParkableStringManager::Instance().ParkAllIfRendererBackgrounded(
- ParkableStringImpl::ParkingMode::kAlways);
+ ParkableStringManager::Instance().PurgeMemory();
}
};
+} // namespace
+
+// static
+ParkableStringManagerDumpProvider*
+ParkableStringManagerDumpProvider::Instance() {
+ static ParkableStringManagerDumpProvider instance;
+ return &instance;
+}
+
+bool ParkableStringManagerDumpProvider::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ return ParkableStringManager::Instance().OnMemoryDump(pmd);
+}
+
+ParkableStringManagerDumpProvider::~ParkableStringManagerDumpProvider() =
+ default;
+ParkableStringManagerDumpProvider::ParkableStringManagerDumpProvider() =
+ default;
+
ParkableStringManager& ParkableStringManager::Instance() {
DCHECK(IsMainThread());
DEFINE_STATIC_LOCAL(ParkableStringManager, instance, ());
@@ -94,6 +116,43 @@ bool ParkableStringManager::IsRendererBackgrounded() const {
return backgrounded_;
}
+bool ParkableStringManager::OnMemoryDump(
+ base::trace_event::ProcessMemoryDump* pmd) {
+ DCHECK(IsMainThread());
+ base::trace_event::MemoryAllocatorDump* dump =
+ pmd->CreateAllocatorDump("parkable_strings");
+
+ size_t uncompressed_size = 0;
+ size_t compressed_size = 0;
+ size_t metadata_size = 0;
+ size_t overhead_size = 0;
+
+ for (ParkableStringImpl* str : unparked_strings_.Values()) {
+ uncompressed_size += str->CharactersSizeInBytes();
+ metadata_size += sizeof(ParkableStringImpl);
+
+ if (str->has_compressed_data())
+ overhead_size += str->compressed_size();
+ }
+
+ for (ParkableStringImpl* str : parked_strings_) {
+ compressed_size += str->compressed_size();
+ metadata_size += sizeof(ParkableStringImpl);
+ }
+
+ size_t total_size =
+ uncompressed_size + compressed_size + metadata_size + overhead_size;
+ dump->AddScalar("size", "bytes", total_size);
+ dump->AddScalar("uncompressed_size", "bytes", uncompressed_size);
+ dump->AddScalar("compressed_size", "bytes", compressed_size);
+ dump->AddScalar("metadata_size", "bytes", metadata_size);
+ dump->AddScalar("overhead_size", "bytes", overhead_size);
+
+ pmd->AddSuballocation(dump->guid(),
+ WTF::Partitions::kAllocatedObjectPoolName);
+ return true;
+}
+
// static
bool ParkableStringManager::ShouldPark(const StringImpl& string) {
// Don't attempt to park strings smaller than this size.
@@ -151,14 +210,10 @@ void ParkableStringManager::OnUnparked(ParkableStringImpl* was_parked_string,
unparked_strings_.insert(new_unparked_string, was_parked_string);
}
-void ParkableStringManager::ParkAllIfRendererBackgrounded(
- ParkableStringImpl::ParkingMode mode) {
+void ParkableStringManager::ParkAll(ParkableStringImpl::ParkingMode mode) {
DCHECK(IsMainThread());
DCHECK(base::FeatureList::IsEnabled(kCompressParkableStringsInBackground));
- if (!IsRendererBackgrounded())
- return;
-
size_t total_size = 0;
for (ParkableStringImpl* str : parked_strings_)
total_size += str->CharactersSizeInBytes();
@@ -182,8 +237,9 @@ void ParkableStringManager::ParkAllIfRendererBackgrounded(
total_size += str->CharactersSizeInBytes();
}
- // Only collect stats for "full" parking calls.
- if (mode == ParkableStringImpl::ParkingMode::kAlways) {
+ // Only collect stats for "full" parking calls in background.
+ if (mode == ParkableStringImpl::ParkingMode::kAlways &&
+ IsRendererBackgrounded()) {
size_t total_size_kb = total_size / 1000;
UMA_HISTOGRAM_COUNTS_100000("Memory.MovableStringsTotalSizeKb",
total_size_kb);
@@ -191,6 +247,14 @@ void ParkableStringManager::ParkAllIfRendererBackgrounded(
}
}
+void ParkableStringManager::ParkAllIfRendererBackgrounded(
+ ParkableStringImpl::ParkingMode mode) {
+ DCHECK(IsMainThread());
+
+ if (IsRendererBackgrounded())
+ ParkAll(mode);
+}
+
size_t ParkableStringManager::Size() const {
return parked_strings_.size() + unparked_strings_.size();
}
@@ -238,6 +302,23 @@ void ParkableStringManager::DropStringsWithCompressedDataAndRecordStatistics() {
}
}
+void ParkableStringManager::PurgeMemory() {
+ DCHECK(IsMainThread());
+ DCHECK(base::FeatureList::IsEnabled(kCompressParkableStringsInBackground));
+
+ ParkAll(ParkableStringImpl::ParkingMode::kAlways);
+ // Critical memory pressure: drop compressed data for strings that we cannot
+ // park now.
+ //
+ // After |ParkAll()| has been called, parkable strings have either been parked
+ // synchronously (and no longer in |unparked_strings_|), or being parked and
+ // purging is a no-op.
+ if (!IsRendererBackgrounded()) {
+ for (ParkableStringImpl* str : unparked_strings_.Values())
+ str->PurgeMemory();
+ }
+}
+
void ParkableStringManager::ResetForTesting() {
backgrounded_ = false;
waiting_to_record_stats_ = false;
@@ -254,7 +335,8 @@ ParkableStringManager::ParkableStringManager()
parked_strings_() {
// No need to ever unregister, as the only ParkableStringManager instance
// lives forever.
- MemoryCoordinator::Instance().RegisterClient(new OnPurgeMemoryListener());
+ MemoryCoordinator::Instance().RegisterClient(
+ MakeGarbageCollected<OnPurgeMemoryListener>());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
index 262b9ddea2f..54e763184f3 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
@@ -8,6 +8,7 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "base/trace_event/memory_dump_provider.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -23,6 +24,23 @@ class ParkableString;
const base::Feature kCompressParkableStringsInBackground{
"CompressParkableStringsInBackground", base::FEATURE_DISABLED_BY_DEFAULT};
+class PLATFORM_EXPORT ParkableStringManagerDumpProvider
+ : public base::trace_event::MemoryDumpProvider {
+ USING_FAST_MALLOC(ParkableStringManagerDumpProvider);
+
+ public:
+ static ParkableStringManagerDumpProvider* Instance();
+ ~ParkableStringManagerDumpProvider() override;
+
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
+ base::trace_event::ProcessMemoryDump*) override;
+
+ private:
+ ParkableStringManagerDumpProvider();
+
+ DISALLOW_COPY_AND_ASSIGN(ParkableStringManagerDumpProvider);
+};
+
// Manages all the ParkableStrings, and parks eligible strings after the
// renderer has been backgrounded.
// Main Thread only.
@@ -35,9 +53,12 @@ class PLATFORM_EXPORT ParkableStringManager {
void SetRendererBackgrounded(bool backgrounded);
bool IsRendererBackgrounded() const;
+ void PurgeMemory();
// Number of parked and unparked strings. Public for testing.
size_t Size() const;
+ bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd);
+
// Whether a string is parkable or not. Can be called from any thread.
static bool ShouldPark(const StringImpl& string);
@@ -48,7 +69,6 @@ class PLATFORM_EXPORT ParkableStringManager {
private:
friend class ParkableString;
friend class ParkableStringImpl;
- friend class OnPurgeMemoryListener;
scoped_refptr<ParkableStringImpl> Add(scoped_refptr<StringImpl>&&);
void Remove(ParkableStringImpl*, StringImpl*);
@@ -56,6 +76,7 @@ class PLATFORM_EXPORT ParkableStringManager {
void OnParked(ParkableStringImpl*, StringImpl*);
void OnUnparked(ParkableStringImpl*, StringImpl*);
+ void ParkAll(ParkableStringImpl::ParkingMode mode);
void ParkAllIfRendererBackgrounded(ParkableStringImpl::ParkingMode mode);
void DropStringsWithCompressedDataAndRecordStatistics();
void ResetForTesting();
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
index b186942e1e8..a42626e9944 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
@@ -2,12 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <limits>
+#include <random>
#include <thread>
#include <vector>
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
@@ -25,7 +31,7 @@ constexpr size_t kCompressedSize = 55;
String MakeLargeString() {
std::vector<char> data(kSizeKb * 1000, 'a');
- return String(String(data.data(), data.size()).ReleaseImpl());
+ return String(data.data(), data.size()).ReleaseImpl();
}
} // namespace
@@ -101,6 +107,37 @@ TEST_F(ParkableStringTest, CheckCompressedSize) {
EXPECT_EQ(kCompressedSize, parkable.Impl()->compressed_size());
}
+TEST_F(ParkableStringTest, DontCompressRandomString) {
+ // Make a large random string. Large to make sure it's parkable, and random to
+ // ensure its compressed size is larger than the initial size (at least from
+ // gzip's header). Mersenne-Twister implementation is specified, making the
+ // test deterministic.
+ std::vector<unsigned char> data(kSizeKb * 1000);
+ std::mt19937 engine(42);
+ // uniform_int_distribution<T> is undefined behavior for T = unsigned char.
+ std::uniform_int_distribution<int> dist(
+ 0, std::numeric_limits<unsigned char>::max());
+
+ for (size_t i = 0; i < data.size(); ++i) {
+ data[i] = static_cast<unsigned char>(dist(engine));
+ }
+ ParkableString parkable(String(data.data(), data.size()).ReleaseImpl());
+
+ EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+ RunPostedTasks();
+ // Not parked because the temporary buffer wasn't large enough.
+ EXPECT_FALSE(parkable.Impl()->is_parked());
+}
+
+TEST_F(ParkableStringTest, ParkUnparkIdenticalContent) {
+ ParkableString parkable(MakeLargeString().ReleaseImpl());
+ EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+ RunPostedTasks();
+ EXPECT_TRUE(parkable.Impl()->is_parked());
+
+ EXPECT_EQ(MakeLargeString(), parkable.ToString());
+}
+
TEST_F(ParkableStringTest, Simple) {
ParkableString parkable_abc(String("abc").ReleaseImpl());
@@ -543,14 +580,14 @@ TEST_F(ParkableStringTest, SynchronousCompression) {
parkable.ToString();
EXPECT_TRUE(parkable.Impl()->has_compressed_data());
// No waiting, synchronous compression.
- manager.ParkAllIfRendererBackgrounded(
- ParkableStringImpl::ParkingMode::kIfCompressedDataExists);
+ manager.ParkAll(ParkableStringImpl::ParkingMode::kIfCompressedDataExists);
EXPECT_TRUE(parkable.Impl()->is_parked());
scoped_task_environment_.FastForwardUntilNoTasksRemain();
}
-TEST_F(ParkableStringTest, OnPurgeMemory) {
+TEST_F(ParkableStringTest, OnPurgeMemoryInBackground) {
ParkableString parkable = CreateAndParkAll();
+ EXPECT_TRUE(ParkableStringManager::Instance().IsRendererBackgrounded());
parkable.ToString();
EXPECT_FALSE(parkable.Impl()->is_parked());
@@ -558,6 +595,80 @@ TEST_F(ParkableStringTest, OnPurgeMemory) {
MemoryCoordinator::Instance().OnPurgeMemory();
EXPECT_TRUE(parkable.Impl()->is_parked());
+
+ parkable.ToString();
+ EXPECT_TRUE(parkable.Impl()->has_compressed_data());
+}
+
+TEST_F(ParkableStringTest, OnPurgeMemoryInForeground) {
+ ParkableString parkable1 = CreateAndParkAll();
+ ParkableString parkable2(MakeLargeString().ReleaseImpl());
+
+ // Park everything.
+ ParkableStringManager::Instance().SetRendererBackgrounded(true);
+ WaitForDelayedParking();
+ EXPECT_TRUE(parkable1.Impl()->is_parked());
+ EXPECT_TRUE(parkable2.Impl()->is_parked());
+
+ ParkableStringManager::Instance().SetRendererBackgrounded(false);
+
+ // Different usage patterns:
+ // 1. Parkable, will be parked synchronouly.
+ // 2. Cannot be parked, compressed representation is purged.
+ parkable1.ToString();
+ String retained = parkable2.ToString();
+ EXPECT_TRUE(parkable2.Impl()->has_compressed_data());
+
+ MemoryCoordinator::Instance().OnPurgeMemory();
+ EXPECT_TRUE(parkable1.Impl()->is_parked()); // Parked synchronously.
+ EXPECT_FALSE(parkable2.Impl()->is_parked());
+ EXPECT_FALSE(parkable2.Impl()->has_compressed_data()); // Purged.
+
+ parkable1.ToString();
+ EXPECT_TRUE(parkable1.Impl()->has_compressed_data());
+}
+
+TEST_F(ParkableStringTest, ReportMemoryDump) {
+ using base::trace_event::MemoryAllocatorDump;
+ using testing::ByRef;
+ using testing::Contains;
+ using testing::Eq;
+
+ auto& manager = ParkableStringManager::Instance();
+ ParkableString parkable1(MakeLargeString().ReleaseImpl());
+ ParkableString parkable2(MakeLargeString().ReleaseImpl());
+ // Not reported in stats below.
+ ParkableString parkable3(String("short string, not parkable").ReleaseImpl());
+
+ manager.SetRendererBackgrounded(true);
+ WaitForDelayedParking();
+ parkable1.ToString();
+
+ base::trace_event::MemoryDumpArgs args = {
+ base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+ base::trace_event::ProcessMemoryDump pmd(args);
+ manager.OnMemoryDump(&pmd);
+ base::trace_event::MemoryAllocatorDump* dump =
+ pmd.GetAllocatorDump("parkable_strings");
+ ASSERT_NE(nullptr, dump);
+
+ // |parkable1| is unparked.
+ MemoryAllocatorDump::Entry uncompressed("uncompressed_size", "bytes",
+ kSizeKb * 1000);
+ EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(uncompressed))));
+
+ MemoryAllocatorDump::Entry compressed("compressed_size", "bytes",
+ kCompressedSize);
+ EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(compressed))));
+
+ // |parkable1| compressed data is overhead.
+ MemoryAllocatorDump::Entry overhead("overhead_size", "bytes",
+ kCompressedSize);
+ EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(overhead))));
+
+ MemoryAllocatorDump::Entry metadata("metadata_size", "bytes",
+ 2 * sizeof(ParkableStringImpl));
+ EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(metadata))));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h b/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h
index 24643901979..749837ee49c 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h
@@ -199,7 +199,6 @@ class PLATFORM_EXPORT RuntimeCallStats {
#define BINDINGS_COUNTERS(V) \
V(AssociateObjectWithWrapper) \
V(CreateWrapper) \
- V(GetEventListener) \
V(HasInstance) \
V(ToExecutionContext) \
V(ToV8DOMWindow) \
diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h
index 20778d6a0de..8433c4b8c5b 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h
@@ -57,6 +57,9 @@ class PLATFORM_EXPORT ScriptWrappableMarkingVisitor
template <typename T>
inline static void WriteBarrier(const T* dst_object);
+ template <typename T>
+ static void WriteBarrier(TraceWrapperMember<T>* array, size_t length);
+
static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, void*);
static void WriteBarrier(v8::Isolate*,
@@ -229,6 +232,25 @@ inline void ScriptWrappableMarkingVisitor::WriteBarrier(const T* dst_object) {
TraceDescriptorFor(dst_object));
}
+template <typename T>
+inline void ScriptWrappableMarkingVisitor::WriteBarrier(
+ TraceWrapperMember<T>* array,
+ size_t length) {
+ if (!ThreadState::IsAnyWrapperTracing() || !array)
+ return;
+
+ const ThreadState* thread_state =
+ ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
+ DCHECK(thread_state);
+ // Bail out if tracing is not in progress.
+ if (!thread_state->IsWrapperTracing())
+ return;
+
+ for (size_t i = 0; i < length; ++i) {
+ CurrentVisitor(thread_state->GetIsolate())->Trace(array[i]);
+ }
+}
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_SCRIPT_WRAPPABLE_MARKING_VISITOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/bindings/to_v8.h b/chromium/third_party/blink/renderer/platform/bindings/to_v8.h
index 75478328831..00370018f60 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/to_v8.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/to_v8.h
@@ -47,10 +47,11 @@ inline v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback,
v8::Isolate* isolate) {
// |creation_context| is intentionally ignored. Callback functions are not
// wrappers nor clonable. ToV8 on a callback function must be used only when
- // it's the same origin-domain in the same world.
- DCHECK(!callback || (callback->CallbackRelevantScriptState()->GetContext() ==
- creation_context->CreationContext()));
- return callback ? callback->CallbackFunction().As<v8::Value>()
+ // it's in the same world.
+ DCHECK(!callback ||
+ (&callback->GetWorld() ==
+ &ScriptState::From(creation_context->CreationContext())->World()));
+ return callback ? callback->CallbackObject().As<v8::Value>()
: v8::Null(isolate).As<v8::Value>();
}
@@ -59,11 +60,12 @@ inline v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback,
inline v8::Local<v8::Value> ToV8(CallbackInterfaceBase* callback,
v8::Local<v8::Object> creation_context,
v8::Isolate* isolate) {
- // |creation_context| is intentionally ignored. Callback interface objects
- // are not wrappers nor clonable. ToV8 on a callback interface object must
- // be used only when it's the same origin-domain in the same world.
- DCHECK(!callback || (callback->CallbackRelevantScriptState()->GetContext() ==
- creation_context->CreationContext()));
+ // |creation_context| is intentionally ignored. Callback interfaces are not
+ // wrappers nor clonable. ToV8 on a callback interface must be used only when
+ // it's in the same world.
+ DCHECK(!callback ||
+ (&callback->GetWorld() ==
+ &ScriptState::From(creation_context->CreationContext())->World()));
return callback ? callback->CallbackObject().As<v8::Value>()
: v8::Null(isolate).As<v8::Value>();
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h
index d021dcc8977..79304ef441e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h
@@ -61,30 +61,6 @@ class TraceWrapperMember : public Member<T> {
}
};
-// Swaps two HeapVectors specialized for TraceWrapperMember. The custom swap
-// function is required as TraceWrapperMember potentially requires emitting a
-// write barrier.
-template <typename T>
-void swap(HeapVector<TraceWrapperMember<T>>& a,
- HeapVector<TraceWrapperMember<T>>& b) {
- // HeapVector<Member<T>> and HeapVector<TraceWrapperMember<T>> have the
- // same size and semantics.
- HeapVector<Member<T>>& a_ = reinterpret_cast<HeapVector<Member<T>>&>(a);
- HeapVector<Member<T>>& b_ = reinterpret_cast<HeapVector<Member<T>>&>(b);
- a_.swap(b_);
- if (ThreadState::IsAnyWrapperTracing() &&
- ThreadState::Current()->IsWrapperTracing()) {
- // If incremental marking is enabled we need to emit the write barrier since
- // the swap was performed on HeapVector<Member<T>>.
- for (auto item : a) {
- ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
- }
- for (auto item : b) {
- ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
- }
- }
-}
-
// HeapVectorBacking<TraceWrapperMember<T>> need to map to
// HeapVectorBacking<Member<T>> for performing the swap method below.
template <typename T, typename Traits>
diff --git a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
index 21bb8db0d92..41c038346a5 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
@@ -11,8 +11,9 @@
namespace blink {
/**
- * TraceWrapperV8Reference is used to trace from Blink to V8. The reference is
- * (strongly) traced by wrapper tracing.
+ * TraceWrapperV8Reference is used to hold references from Blink to V8 that are
+ * known to both garbage collectors. The reference is a regular traced reference
+ * for wrapper tracing as well as unified heap garbage collections.
*
* TODO(mlippautz): Use a better handle type than v8::Persistent.
*/
@@ -37,16 +38,6 @@ class TraceWrapperV8Reference {
handle_.SetWeak();
}
- template <typename P>
- void Set(v8::Isolate* isolate,
- v8::Local<T> handle,
- P* parameters,
- void (*callback)(const v8::WeakCallbackInfo<P>&),
- v8::WeakCallbackType type = v8::WeakCallbackType::kParameter) {
- InternalSet(isolate, handle);
- handle_.SetWeak(parameters, callback, type);
- }
-
ALWAYS_INLINE v8::Local<T> NewLocal(v8::Isolate* isolate) const {
return v8::Local<T>::New(isolate, handle_);
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h b/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h
index 378f5434309..ba7445d3342 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h
@@ -276,9 +276,9 @@ inline v8::Local<v8::String> V8String(v8::Isolate* isolate,
DCHECK(isolate);
if (!string || string[0] == '\0')
return v8::String::Empty(isolate);
- return v8::String::NewFromOneByte(isolate,
- reinterpret_cast<const uint8_t*>(string),
- v8::NewStringType::kNormal, strlen(string))
+ return v8::String::NewFromOneByte(
+ isolate, reinterpret_cast<const uint8_t*>(string),
+ v8::NewStringType::kNormal, static_cast<int>(strlen(string)))
.ToLocalChecked();
}
@@ -324,7 +324,7 @@ inline v8::Local<v8::String> V8AtomicString(v8::Isolate* isolate,
return v8::String::Empty(isolate);
return v8::String::NewFromOneByte(
isolate, reinterpret_cast<const uint8_t*>(string),
- v8::NewStringType::kInternalized, strlen(string))
+ v8::NewStringType::kInternalized, static_cast<int>(strlen(string)))
.ToLocalChecked();
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h b/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h
index df0f8eb117c..6ca82aea230 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h
@@ -111,6 +111,8 @@ class V8GlobalValueMap : public v8::GlobalValueMap<
typedef V8GlobalValueMapTraits<KeyType, ValueType, type> Traits;
explicit V8GlobalValueMap(v8::Isolate* isolate)
: v8::GlobalValueMap<KeyType, ValueType, Traits>(isolate) {}
+ V8GlobalValueMap(v8::Isolate* isolate, const char* label)
+ : v8::GlobalValueMap<KeyType, ValueType, Traits>(isolate, label) {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
index 20c5c4df946..ee25586573c 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
@@ -45,16 +45,25 @@
namespace blink {
+namespace {
+
+constexpr char kWrapperBoilerplatesLabel[] =
+ "V8PerContextData::wrapper_boilerplates_";
+constexpr char kConstructorMapLabel[] = "V8PerContextData::constructor_map_";
+constexpr char kContextLabel[] = "V8PerContextData::context_";
+
+} // namespace
+
V8PerContextData::V8PerContextData(v8::Local<v8::Context> context)
: isolate_(context->GetIsolate()),
- wrapper_boilerplates_(isolate_),
- constructor_map_(isolate_),
+ wrapper_boilerplates_(isolate_, kWrapperBoilerplatesLabel),
+ constructor_map_(isolate_, kConstructorMapLabel),
context_holder_(std::make_unique<gin::ContextHolder>(isolate_)),
context_(isolate_, context),
activity_logger_(nullptr),
data_map_(MakeGarbageCollected<DataMap>()) {
context_holder_->SetContext(context);
- context_.Get().AnnotateStrongRetainer("blink::V8PerContextData::context_");
+ context_.Get().AnnotateStrongRetainer(kContextLabel);
if (IsMainThread()) {
InstanceCounters::IncrementCounter(
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
index eed599acde1..5766cb414fe 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -49,6 +49,13 @@
namespace blink {
+namespace {
+
+constexpr char kInterfaceMapLabel[] =
+ "V8PerIsolateData::interface_template_map_for_v8_context_snapshot_";
+
+} // namespace
+
// Wrapper function defined in WebKit.h
v8::Isolate* MainThreadIsolate() {
return V8PerIsolateData::MainThreadIsolate();
@@ -75,7 +82,8 @@ V8PerIsolateData::V8PerIsolateData(
: gin::IsolateHolder::kAllowAtomicsWait,
IsMainThread() ? gin::IsolateHolder::IsolateType::kBlinkMainThread
: gin::IsolateHolder::IsolateType::kBlinkWorkerThread),
- interface_template_map_for_v8_context_snapshot_(GetIsolate()),
+ interface_template_map_for_v8_context_snapshot_(GetIsolate(),
+ kInterfaceMapLabel),
string_cache_(std::make_unique<StringCache>(GetIsolate())),
private_property_(V8PrivateProperty::Create()),
constructor_mode_(ConstructorMode::kCreateNewObject),
@@ -86,8 +94,7 @@ V8PerIsolateData::V8PerIsolateData(
new ScriptWrappableMarkingVisitor(ThreadState::Current())),
unified_heap_controller_(
new UnifiedHeapController(ThreadState::Current())),
- runtime_call_stats_(base::DefaultTickClock::GetInstance()),
- handled_near_v8_heap_limit_(false) {
+ runtime_call_stats_(base::DefaultTickClock::GetInstance()) {
// FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone.
GetIsolate()->Enter();
GetIsolate()->AddBeforeCallEnteredCallback(&BeforeCallEnteredCallback);
@@ -112,8 +119,7 @@ V8PerIsolateData::V8PerIsolateData()
use_counter_disabled_(false),
is_handling_recursion_level_error_(false),
is_reporting_exception_(false),
- runtime_call_stats_(base::DefaultTickClock::GetInstance()),
- handled_near_v8_heap_limit_(false) {
+ runtime_call_stats_(base::DefaultTickClock::GetInstance()) {
CHECK(IsMainThread());
// SnapshotCreator enters the isolate, so we don't call Isolate::Enter() here.
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
index d126266a5c4..6599b4fed71 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
@@ -219,10 +219,6 @@ class PLATFORM_EXPORT V8PerIsolateData {
return unified_heap_controller_.get();
}
- int IsNearV8HeapLimitHandled() { return handled_near_v8_heap_limit_; }
-
- void HandledNearV8HeapLimit() { handled_near_v8_heap_limit_ = true; }
-
private:
V8PerIsolateData(scoped_refptr<base::SingleThreadTaskRunner>,
V8ContextSnapshotMode);
@@ -294,7 +290,6 @@ class PLATFORM_EXPORT V8PerIsolateData {
std::unique_ptr<UnifiedHeapController> unified_heap_controller_;
RuntimeCallStats runtime_call_stats_;
- bool handled_near_v8_heap_limit_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h b/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h
index 6eff732d5b3..8dfd6ec588c 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h
@@ -49,8 +49,6 @@ class ScriptWrappable;
X(SameObject, NotificationVibrate) \
X(SameObject, PerformanceLongTaskTimingAttribution) \
X(SameObject, PushManagerSupportedContentEncodings) \
- X(CustomWrappable, EventHandler) \
- X(CustomWrappable, EventListener) \
SCRIPT_PROMISE_PROPERTIES(X, Promise) \
SCRIPT_PROMISE_PROPERTIES(X, Resolver)
diff --git a/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc b/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc
index 4c06a7cf227..aa864fa515c 100644
--- a/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc
+++ b/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc
@@ -116,8 +116,8 @@ TEST_F(BlobBytesProviderTest, RequestAsReply) {
namespace {
struct FileTestData {
- uint64_t offset;
- uint64_t size;
+ uint32_t offset;
+ uint32_t size;
};
void PrintTo(const FileTestData& test, std::ostream* os) {
diff --git a/chromium/third_party/blink/renderer/platform/blob/blob_data_test.cc b/chromium/third_party/blink/renderer/platform/blob/blob_data_test.cc
index 495574b6b09..681517838ed 100644
--- a/chromium/third_party/blink/renderer/platform/blob/blob_data_test.cc
+++ b/chromium/third_party/blink/renderer/platform/blob/blob_data_test.cc
@@ -136,7 +136,7 @@ class BlobDataHandleTest : public testing::Test {
void TestCreateBlob(std::unique_ptr<BlobData> data,
Vector<ExpectedElement> expected_elements) {
- size_t blob_size = data->length();
+ uint64_t blob_size = data->length();
String type = data->ContentType();
bool is_single_unknown_size_file = data->IsSingleUnknownSizeFile();
diff --git a/chromium/third_party/blink/renderer/platform/crypto_result.h b/chromium/third_party/blink/renderer/platform/crypto_result.h
index b206f7bc46b..bd3860815c7 100644
--- a/chromium/third_party/blink/renderer/platform/crypto_result.h
+++ b/chromium/third_party/blink/renderer/platform/crypto_result.h
@@ -31,19 +31,21 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_CRYPTO_RESULT_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_CRYPTO_RESULT_H_
+#include "base/synchronization/atomic_flag.h"
#include "third_party/blink/public/platform/web_crypto.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
namespace blink {
-// Result cancellation status interface to allow non-Blink webcrypto threads
-// to query for status.
+// Allows non-Blink webcrypto threads to query for cancellation status.
class CryptoResultCancel : public ThreadSafeRefCounted<CryptoResultCancel> {
public:
- virtual ~CryptoResultCancel() = default;
+ bool Cancelled() const { return cancelled_.IsSet(); }
+ void Cancel() { cancelled_.Set(); }
- virtual bool Cancelled() const = 0;
+ private:
+ base::AtomicFlag cancelled_;
};
// Receives notification of completion of the crypto operation.
diff --git a/chromium/third_party/blink/renderer/platform/exported/platform.cc b/chromium/third_party/blink/renderer/platform/exported/platform.cc
index 5e03ba6e8ed..7626a6abd1b 100644
--- a/chromium/third_party/blink/renderer/platform/exported/platform.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/platform.cc
@@ -39,7 +39,6 @@
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/platform/interface_provider.h"
-#include "third_party/blink/public/platform/modules/webmidi/web_midi_accessor.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/public/platform/web_canvas_capture_handler.h"
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
@@ -51,6 +50,7 @@
#include "third_party/blink/public/platform/web_rtc_peer_connection_handler.h"
#include "third_party/blink/public/platform/web_storage_namespace.h"
#include "third_party/blink/public/platform/websocket_handshake_throttle.h"
+#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
#include "third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h"
@@ -67,8 +67,9 @@
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/webrtc/api/rtpparameters.h"
-#include "third_party/webrtc/p2p/base/portallocator.h"
+#include "third_party/webrtc/api/async_resolver_factory.h"
+#include "third_party/webrtc/api/rtp_parameters.h"
+#include "third_party/webrtc/p2p/base/port_allocator.h"
namespace blink {
@@ -215,6 +216,9 @@ void Platform::InitializeCommon(Platform* platform,
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
InstanceCountersMemoryDumpProvider::Instance(), "BlinkObjectCounters",
base::ThreadTaskRunnerHandle::Get());
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ ParkableStringManagerDumpProvider::Instance(), "ParkableStrings",
+ base::ThreadTaskRunnerHandle::Get());
RendererResourceCoordinator::Initialize();
}
@@ -264,11 +268,6 @@ InterfaceProvider* Platform::GetInterfaceProvider() {
return InterfaceProvider::GetEmptyInterfaceProvider();
}
-std::unique_ptr<WebMIDIAccessor> Platform::CreateMIDIAccessor(
- WebMIDIAccessorClient*) {
- return nullptr;
-}
-
std::unique_ptr<WebStorageNamespace> Platform::CreateLocalStorageNamespace() {
return nullptr;
}
@@ -333,6 +332,11 @@ std::unique_ptr<cricket::PortAllocator> Platform::CreateWebRtcPortAllocator(
return nullptr;
}
+std::unique_ptr<webrtc::AsyncResolverFactory>
+Platform::CreateWebRtcAsyncResolverFactory() {
+ return nullptr;
+}
+
std::unique_ptr<WebMediaRecorderHandler> Platform::CreateMediaRecorderHandler(
scoped_refptr<base::SingleThreadTaskRunner>) {
return nullptr;
diff --git a/chromium/third_party/blink/renderer/platform/exported/platform_media_stream_source.cc b/chromium/third_party/blink/renderer/platform/exported/platform_media_stream_source.cc
new file mode 100644
index 00000000000..343a7a8235c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/exported/platform_media_stream_source.cc
@@ -0,0 +1,83 @@
+// 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 "third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h"
+
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+
+#include "base/logging.h"
+
+namespace blink {
+
+const char kMediaStreamSourceTab[] = "tab";
+const char kMediaStreamSourceScreen[] = "screen";
+const char kMediaStreamSourceDesktop[] = "desktop";
+const char kMediaStreamSourceSystem[] = "system";
+
+const char WebPlatformMediaStreamSource::kSourceId[] = "sourceId";
+
+WebPlatformMediaStreamSource::WebPlatformMediaStreamSource() {}
+
+WebPlatformMediaStreamSource::~WebPlatformMediaStreamSource() {
+ DCHECK(stop_callback_.is_null());
+ owner_ = nullptr;
+}
+
+void WebPlatformMediaStreamSource::StopSource() {
+ DoStopSource();
+ FinalizeStopSource();
+}
+
+void WebPlatformMediaStreamSource::FinalizeStopSource() {
+ if (!stop_callback_.is_null())
+ base::ResetAndReturn(&stop_callback_).Run(Owner());
+ if (Owner())
+ Owner().SetReadyState(blink::WebMediaStreamSource::kReadyStateEnded);
+}
+
+void WebPlatformMediaStreamSource::SetSourceMuted(bool is_muted) {
+ // Although this change is valid only if the ready state isn't already Ended,
+ // there's code further along (like in blink::MediaStreamTrack) which filters
+ // that out already.
+ if (!Owner())
+ return;
+ Owner().SetReadyState(is_muted
+ ? blink::WebMediaStreamSource::kReadyStateMuted
+ : blink::WebMediaStreamSource::kReadyStateLive);
+}
+
+void WebPlatformMediaStreamSource::SetDevice(
+ const blink::MediaStreamDevice& device) {
+ device_ = device;
+}
+
+void WebPlatformMediaStreamSource::SetStopCallback(
+ const SourceStoppedCallback& stop_callback) {
+ DCHECK(stop_callback_.is_null());
+ stop_callback_ = stop_callback;
+}
+
+void WebPlatformMediaStreamSource::ResetSourceStoppedCallback() {
+ DCHECK(!stop_callback_.is_null());
+ stop_callback_.Reset();
+}
+
+void WebPlatformMediaStreamSource::ChangeSource(
+ const blink::MediaStreamDevice& new_device) {
+ DoChangeSource(new_device);
+}
+
+WebMediaStreamSource WebPlatformMediaStreamSource::Owner() {
+ DCHECK(owner_);
+ return WebMediaStreamSource(owner_.Get());
+}
+
+#if INSIDE_BLINK
+void WebPlatformMediaStreamSource::SetOwner(MediaStreamSource* owner) {
+ DCHECK(!owner_);
+ owner_ = owner;
+}
+#endif
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_crypto_algorithm.cc b/chromium/third_party/blink/renderer/platform/exported/web_crypto_algorithm.cc
index 1421bc6d411..67b793f5ca1 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_crypto_algorithm.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_crypto_algorithm.cc
@@ -34,6 +34,7 @@
#include <utility>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -343,7 +344,7 @@ WebCryptoAlgorithm WebCryptoAlgorithm::AdoptParamsAndCreate(
const WebCryptoAlgorithmInfo* WebCryptoAlgorithm::LookupAlgorithmInfo(
WebCryptoAlgorithmId id) {
const unsigned id_int = id;
- if (id_int >= arraysize(kAlgorithmIdToInfo))
+ if (id_int >= base::size(kAlgorithmIdToInfo))
return nullptr;
return &kAlgorithmIdToInfo[id];
}
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_media_constraints.cc b/chromium/third_party/blink/renderer/platform/exported/web_media_constraints.cc
index c6715848beb..05c0f75370d 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_media_constraints.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_media_constraints.cc
@@ -361,9 +361,9 @@ WebMediaTrackConstraintSet::WebMediaTrackConstraintSet()
hotword_enabled("hotwordEnabled"),
goog_echo_cancellation("googEchoCancellation"),
goog_experimental_echo_cancellation("googExperimentalEchoCancellation"),
- goog_auto_gain_control("googAutoGainControl"),
+ goog_auto_gain_control("autoGainControl"),
goog_experimental_auto_gain_control("googExperimentalAutoGainControl"),
- goog_noise_suppression("googNoiseSuppression"),
+ goog_noise_suppression("noiseSuppression"),
goog_highpass_filter("googHighpassFilter"),
goog_typing_noise_detection("googTypingNoiseDetection"),
goog_experimental_noise_suppression("googExperimentalNoiseSuppression"),
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_media_stream_source.cc b/chromium/third_party/blink/renderer/platform/exported/web_media_stream_source.cc
index 3af4b48de1d..d45ddd5f17e 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_media_stream_source.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_media_stream_source.cc
@@ -43,33 +43,6 @@
namespace blink {
-namespace {
-
-class MediaStreamSourceExtraDataContainer
- : public MediaStreamSource::ExtraData {
- public:
- MediaStreamSourceExtraDataContainer(
- std::unique_ptr<WebMediaStreamSource::ExtraData> extra_data)
- : extra_data_(std::move(extra_data)) {}
-
- WebMediaStreamSource::ExtraData* GetExtraData() { return extra_data_.get(); }
-
- private:
- std::unique_ptr<WebMediaStreamSource::ExtraData> extra_data_;
-};
-
-} // namespace
-
-WebMediaStreamSource WebMediaStreamSource::ExtraData::Owner() {
- DCHECK(owner_);
- return WebMediaStreamSource(owner_);
-}
-
-void WebMediaStreamSource::ExtraData::SetOwner(MediaStreamSource* owner) {
- DCHECK(!owner_);
- owner_ = owner;
-}
-
WebMediaStreamSource::WebMediaStreamSource(
MediaStreamSource* media_stream_source)
: private_(media_stream_source) {}
@@ -147,23 +120,19 @@ WebMediaStreamSource::ReadyState WebMediaStreamSource::GetReadyState() const {
return static_cast<ReadyState>(private_->GetReadyState());
}
-WebMediaStreamSource::ExtraData* WebMediaStreamSource::GetExtraData() const {
+WebPlatformMediaStreamSource* WebMediaStreamSource::GetPlatformSource() const {
DCHECK(!private_.IsNull());
- MediaStreamSource::ExtraData* data = private_->GetExtraData();
- if (!data)
- return nullptr;
- return static_cast<MediaStreamSourceExtraDataContainer*>(data)
- ->GetExtraData();
+ return private_->GetPlatformSource();
}
-void WebMediaStreamSource::SetExtraData(ExtraData* extra_data) {
+void WebMediaStreamSource::SetPlatformSource(
+ std::unique_ptr<WebPlatformMediaStreamSource> platform_source) {
DCHECK(!private_.IsNull());
- if (extra_data)
- extra_data->SetOwner(private_.Get());
+ if (platform_source)
+ platform_source->SetOwner(private_.Get());
- private_->SetExtraData(std::make_unique<MediaStreamSourceExtraDataContainer>(
- base::WrapUnique(extra_data)));
+ private_->SetPlatformSource(std::move(platform_source));
}
void WebMediaStreamSource::SetAudioProcessingProperties(
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_media_stream_track.cc b/chromium/third_party/blink/renderer/platform/exported/web_media_stream_track.cc
index 2e760bc6b2c..1718e0cf992 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_media_stream_track.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_media_stream_track.cc
@@ -38,25 +38,6 @@
namespace blink {
-namespace {
-
-class TrackDataContainer : public MediaStreamComponent::TrackData {
- public:
- explicit TrackDataContainer(
- std::unique_ptr<WebMediaStreamTrack::TrackData> extra_data)
- : extra_data_(std::move(extra_data)) {}
-
- WebMediaStreamTrack::TrackData* GetTrackData() { return extra_data_.get(); }
- void GetSettings(WebMediaStreamTrack::Settings& settings) override {
- extra_data_->GetSettings(settings);
- }
-
- private:
- std::unique_ptr<WebMediaStreamTrack::TrackData> extra_data_;
-};
-
-} // namespace
-
const char WebMediaStreamTrack::kResizeModeNone[] = "none";
const char WebMediaStreamTrack::kResizeModeRescale[] = "crop-and-scale";
@@ -128,18 +109,14 @@ WebMediaStreamSource WebMediaStreamTrack::Source() const {
return WebMediaStreamSource(private_->Source());
}
-WebMediaStreamTrack::TrackData* WebMediaStreamTrack::GetTrackData() const {
- MediaStreamComponent::TrackData* data = private_->GetTrackData();
- if (!data)
- return nullptr;
- return static_cast<TrackDataContainer*>(data)->GetTrackData();
+WebPlatformMediaStreamTrack* WebMediaStreamTrack::GetPlatformTrack() const {
+ return private_->GetPlatformTrack();
}
-void WebMediaStreamTrack::SetTrackData(TrackData* extra_data) {
+void WebMediaStreamTrack::SetPlatformTrack(
+ std::unique_ptr<WebPlatformMediaStreamTrack> platform_track) {
DCHECK(!private_.IsNull());
-
- private_->SetTrackData(
- std::make_unique<TrackDataContainer>(base::WrapUnique(extra_data)));
+ private_->SetPlatformTrack(std::move(platform_track));
}
void WebMediaStreamTrack::SetSourceProvider(WebAudioSourceProvider* provider) {
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_platform_media_stream_track.cc b/chromium/third_party/blink/renderer/platform/exported/web_platform_media_stream_track.cc
new file mode 100644
index 00000000000..8c8a25c80bb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/exported/web_platform_media_stream_track.cc
@@ -0,0 +1,20 @@
+// 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 "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h"
+
+namespace blink {
+
+// static
+WebPlatformMediaStreamTrack* WebPlatformMediaStreamTrack::GetTrack(
+ const blink::WebMediaStreamTrack& track) {
+ return track.IsNull() ? nullptr : track.GetPlatformTrack();
+}
+
+WebPlatformMediaStreamTrack::WebPlatformMediaStreamTrack(bool is_local_track)
+ : is_local_track_(is_local_track) {}
+
+WebPlatformMediaStreamTrack::~WebPlatformMediaStreamTrack() {}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_presentation_receiver.cc b/chromium/third_party/blink/renderer/platform/exported/web_presentation_receiver.cc
deleted file mode 100644
index 0e3d93d402e..00000000000
--- a/chromium/third_party/blink/renderer/platform/exported/web_presentation_receiver.cc
+++ /dev/null
@@ -1,11 +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 "third_party/blink/public/platform/modules/presentation/web_presentation_receiver.h"
-
-// This WebPresentationReceiver.cpp, which includes only
-// WebPresentationReceiver.h, should be in Source/platform/exported,
-// because WebPresentationReceiver is not compiled without this cpp.
-// So if we don't have this cpp, we will see unresolved symbol error
-// when constructor/destructor's address is required.
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_rtc_rtp_contributing_source.cc b/chromium/third_party/blink/renderer/platform/exported/web_rtc_rtp_source.cc
index 0453e96394a..621bbf77dda 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_rtc_rtp_contributing_source.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_rtc_rtp_source.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 "third_party/blink/public/platform/web_rtc_rtp_contributing_source.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_source.h"
namespace blink {
-WebRTCRtpContributingSource::~WebRTCRtpContributingSource() = default;
+WebRTCRtpSource::~WebRTCRtpSource() = default;
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 36c10eaccf7..e7aff6a8fdc 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -55,6 +55,10 @@ void WebRuntimeFeatures::EnableWebBluetooth(bool enable) {
RuntimeEnabledFeatures::SetWebBluetoothEnabled(enable);
}
+void WebRuntimeFeatures::EnableWebBluetoothScanning(bool enable) {
+ RuntimeEnabledFeatures::SetWebBluetoothScanningEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableWebNfc(bool enable) {
RuntimeEnabledFeatures::SetWebNFCEnabled(enable);
}
@@ -148,6 +152,10 @@ void WebRuntimeFeatures::EnableScrollTopLeftInterop(bool enable) {
RuntimeEnabledFeatures::SetScrollTopLeftInteropEnabled(enable);
}
+void WebRuntimeFeatures::EnableKeyboardFocusableScrollers(bool enable) {
+ RuntimeEnabledFeatures::SetKeyboardFocusableScrollersEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableDatabase(bool enable) {
RuntimeEnabledFeatures::SetDatabaseEnabled(enable);
}
@@ -172,10 +180,6 @@ void WebRuntimeFeatures::EnableForceTallerSelectPopup(bool enable) {
RuntimeEnabledFeatures::SetForceTallerSelectPopupEnabled(enable);
}
-void WebRuntimeFeatures::EnableGamepadExtensions(bool enable) {
- RuntimeEnabledFeatures::SetGamepadExtensionsEnabled(enable);
-}
-
void WebRuntimeFeatures::EnableGamepadVibration(bool enable) {
RuntimeEnabledFeatures::SetGamepadVibrationEnabled(enable);
}
@@ -200,8 +204,10 @@ void WebRuntimeFeatures::EnableInputMultipleFieldsUI(bool enable) {
RuntimeEnabledFeatures::SetInputMultipleFieldsUIEnabled(enable);
}
-void WebRuntimeFeatures::EnableJankTracking(bool enable) {
+void WebRuntimeFeatures::EnableJankTracking(bool enable, bool use_sweep_line) {
RuntimeEnabledFeatures::SetJankTrackingEnabled(enable);
+ RuntimeEnabledFeatures::SetJankTrackingSweepLineEnabled(enable &&
+ use_sweep_line);
}
void WebRuntimeFeatures::EnableLayeredAPI(bool enable) {
@@ -292,6 +298,10 @@ void WebRuntimeFeatures::EnableOverflowIconsForMediaControls(bool enable) {
RuntimeEnabledFeatures::SetOverflowIconsForMediaControlsEnabled(enable);
}
+void WebRuntimeFeatures::EnableOverscrollCustomization(bool enable) {
+ RuntimeEnabledFeatures::SetOverscrollCustomizationEnabled(enable);
+}
+
void WebRuntimeFeatures::EnablePageLifecycle(bool enable) {
RuntimeEnabledFeatures::SetPageLifecycleEnabled(enable);
}
@@ -352,8 +362,8 @@ void WebRuntimeFeatures::EnableScriptedSpeechSynthesis(bool enable) {
RuntimeEnabledFeatures::SetScriptedSpeechSynthesisEnabled(enable);
}
-bool WebRuntimeFeatures::IsSlimmingPaintV2Enabled() {
- return RuntimeEnabledFeatures::SlimmingPaintV2Enabled();
+bool WebRuntimeFeatures::IsCompositeAfterPaintEnabled() {
+ return RuntimeEnabledFeatures::CompositeAfterPaintEnabled();
}
void WebRuntimeFeatures::EnableUserActivationSameOriginVisibility(bool enable) {
@@ -400,10 +410,6 @@ void WebRuntimeFeatures::EnableSharedWorker(bool enable) {
RuntimeEnabledFeatures::SetSharedWorkerEnabled(enable);
}
-void WebRuntimeFeatures::EnableSignedHTTPExchange(bool enable) {
- RuntimeEnabledFeatures::SetSignedHTTPExchangeEnabled(enable);
-}
-
void WebRuntimeFeatures::EnablePreciseMemoryInfo(bool enable) {
RuntimeEnabledFeatures::SetPreciseMemoryInfoEnabled(enable);
}
@@ -554,18 +560,10 @@ void WebRuntimeFeatures::EnableMediaEngagementBypassAutoplayPolicies(
enable);
}
-void WebRuntimeFeatures::EnableV8ContextSnapshot(bool enable) {
- RuntimeEnabledFeatures::SetV8ContextSnapshotEnabled(enable);
-}
-
void WebRuntimeFeatures::EnableAutomationControlled(bool enable) {
RuntimeEnabledFeatures::SetAutomationControlledEnabled(enable);
}
-void WebRuntimeFeatures::EnableWorkStealingInScriptRunner(bool enable) {
- RuntimeEnabledFeatures::SetWorkStealingInScriptRunnerEnabled(enable);
-}
-
void WebRuntimeFeatures::EnableScheduledScriptStreaming(bool enable) {
RuntimeEnabledFeatures::SetScheduledScriptStreamingEnabled(enable);
}
@@ -598,14 +596,6 @@ void WebRuntimeFeatures::EnableBackgroundFetch(bool enable) {
RuntimeEnabledFeatures::SetBackgroundFetchEnabled(enable);
}
-void WebRuntimeFeatures::EnableBackgroundFetchAccessActiveFetches(bool enable) {
- RuntimeEnabledFeatures::SetBackgroundFetchAccessActiveFetchesEnabled(enable);
-}
-
-void WebRuntimeFeatures::EnableBackgroundFetchUploads(bool enable) {
- RuntimeEnabledFeatures::SetBackgroundFetchUploadsEnabled(enable);
-}
-
void WebRuntimeFeatures::EnableMergeBlockingNonBlockingPools(bool enable) {
RuntimeEnabledFeatures::SetMergeBlockingNonBlockingPoolsEnabled(enable);
}
@@ -614,4 +604,8 @@ void WebRuntimeFeatures::EnableGetDisplayMedia(bool enable) {
RuntimeEnabledFeatures::SetGetDisplayMediaEnabled(enable);
}
+void WebRuntimeFeatures::EnableForbidSyncXHRInPageDismissal(bool enable) {
+ RuntimeEnabledFeatures::SetForbidSyncXHRInPageDismissalEnabled(enable);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_service_worker_request.cc b/chromium/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
index 1a4b4ae2fbe..c1f8a8bca84 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/public/platform/web_http_header_visitor.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_request.h"
-#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -23,7 +22,6 @@ class WebServiceWorkerRequestPrivate
WebString method_;
HTTPHeaderMap headers_;
scoped_refptr<EncodedFormData> http_body;
- scoped_refptr<BlobDataHandle> blob_data_handle;
Referrer referrer_;
network::mojom::FetchRequestMode mode_ =
network::mojom::FetchRequestMode::kNoCors;
@@ -122,31 +120,6 @@ WebHTTPBody WebServiceWorkerRequest::Body() const {
return private_->http_body;
}
-void WebServiceWorkerRequest::SetBlob(const WebString& uuid,
- long long size,
- mojo::ScopedMessagePipeHandle blob_pipe) {
- SetBlob(uuid, size,
- mojom::blink::BlobPtrInfo(std::move(blob_pipe),
- mojom::blink::Blob::Version_));
-}
-
-void WebServiceWorkerRequest::SetBlob(const WebString& uuid,
- long long size,
- mojom::blink::BlobPtrInfo blob_info) {
- private_->blob_data_handle =
- BlobDataHandle::Create(uuid, String(), size, std::move(blob_info));
-}
-
-void WebServiceWorkerRequest::SetBlobDataHandle(
- scoped_refptr<BlobDataHandle> blob_data_handle) {
- private_->blob_data_handle = std::move(blob_data_handle);
-}
-
-scoped_refptr<BlobDataHandle> WebServiceWorkerRequest::GetBlobDataHandle()
- const {
- return private_->blob_data_handle;
-}
-
void WebServiceWorkerRequest::SetReferrer(
const WebString& web_referrer,
network::mojom::ReferrerPolicy referrer_policy) {
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_service_worker_response.cc b/chromium/third_party/blink/renderer/platform/exported/web_service_worker_response.cc
index 414a82a02c5..eedd67857de 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_service_worker_response.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_service_worker_response.cc
@@ -19,11 +19,13 @@ class WebServiceWorkerResponsePrivate
WebServiceWorkerResponsePrivate()
: status(0),
response_type(network::mojom::FetchResponseType::kDefault),
+ response_source(network::mojom::FetchResponseSource::kUnspecified),
error(mojom::ServiceWorkerResponseError::kUnknown) {}
WebVector<WebURL> url_list;
unsigned short status;
WebString status_text;
network::mojom::FetchResponseType response_type;
+ network::mojom::FetchResponseSource response_source;
HTTPHeaderMap headers;
scoped_refptr<BlobDataHandle> blob_data_handle;
mojom::ServiceWorkerResponseError error;
@@ -78,6 +80,16 @@ network::mojom::FetchResponseType WebServiceWorkerResponse::ResponseType()
return private_->response_type;
}
+void WebServiceWorkerResponse::SetResponseSource(
+ network::mojom::FetchResponseSource response_source) {
+ private_->response_source = response_source;
+}
+
+network::mojom::FetchResponseSource WebServiceWorkerResponse::ResponseSource()
+ const {
+ return private_->response_source;
+}
+
void WebServiceWorkerResponse::SetHeader(const WebString& key,
const WebString& value) {
private_->headers.Set(key, value);
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_load_timing.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_load_timing.cc
index 567469e81b2..82042f97ead 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_load_timing.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_load_timing.cc
@@ -135,6 +135,14 @@ void WebURLLoadTiming::SetSendEnd(base::TimeTicks end) {
private_->SetSendEnd(end);
}
+base::TimeTicks WebURLLoadTiming::ReceiveHeadersStart() const {
+ return private_->ReceiveHeadersStart();
+}
+
+void WebURLLoadTiming::SetReceiveHeadersStart(base::TimeTicks start) {
+ private_->SetReceiveHeadersStart(start);
+}
+
base::TimeTicks WebURLLoadTiming::ReceiveHeadersEnd() const {
return private_->ReceiveHeadersEnd();
}
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc
index c387c5d9492..476acd1c7a3 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc
@@ -101,6 +101,16 @@ void WebURLRequest::SetSiteForCookies(const WebURL& site_for_cookies) {
resource_request_->SetSiteForCookies(site_for_cookies);
}
+base::Optional<WebSecurityOrigin> WebURLRequest::TopFrameOrigin() const {
+ const SecurityOrigin* origin = resource_request_->TopFrameOrigin();
+ return origin ? base::Optional<WebSecurityOrigin>(origin)
+ : base::Optional<WebSecurityOrigin>();
+}
+
+void WebURLRequest::SetTopFrameOrigin(const WebSecurityOrigin& origin) {
+ resource_request_->SetTopFrameOrigin(origin);
+}
+
WebSecurityOrigin WebURLRequest::RequestorOrigin() const {
return resource_request_->RequestorOrigin();
}
@@ -383,11 +393,6 @@ network::mojom::CorsPreflightPolicy WebURLRequest::GetCorsPreflightPolicy()
return resource_request_->CorsPreflightPolicy();
}
-void WebURLRequest::SetNavigationStartTime(
- base::TimeTicks navigation_start_seconds) {
- resource_request_->SetNavigationStartTime(navigation_start_seconds);
-}
-
base::Optional<WebString> WebURLRequest::GetSuggestedFilename() const {
if (!resource_request_->GetSuggestedFilename().has_value())
return base::Optional<WebString>();
@@ -399,10 +404,6 @@ bool WebURLRequest::IsAdResource() const {
return resource_request_->IsAdResource();
}
-const WebContentSecurityPolicyList& WebURLRequest::GetInitiatorCSP() const {
- return resource_request_->GetInitiatorCSP();
-}
-
void WebURLRequest::SetUpgradeIfInsecure(bool upgrade_if_insecure) {
resource_request_->SetUpgradeIfInsecure(upgrade_if_insecure);
}
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
index 3dc90c58557..c592a503785 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -48,28 +48,6 @@
namespace blink {
-namespace {
-
-class URLResponseExtraDataContainer : public ResourceResponse::ExtraData {
- public:
- static scoped_refptr<URLResponseExtraDataContainer> Create(
- WebURLResponse::ExtraData* extra_data) {
- return base::AdoptRef(new URLResponseExtraDataContainer(extra_data));
- }
-
- ~URLResponseExtraDataContainer() override = default;
-
- WebURLResponse::ExtraData* GetExtraData() const { return extra_data_.get(); }
-
- private:
- explicit URLResponseExtraDataContainer(WebURLResponse::ExtraData* extra_data)
- : extra_data_(base::WrapUnique(extra_data)) {}
-
- std::unique_ptr<WebURLResponse::ExtraData> extra_data_;
-};
-
-} // namespace
-
WebURLResponse::~WebURLResponse() = default;
WebURLResponse::WebURLResponse()
@@ -81,8 +59,9 @@ WebURLResponse::WebURLResponse(const WebURLResponse& r)
std::make_unique<ResourceResponse>(*r.resource_response_)),
resource_response_(owned_resource_response_.get()) {}
-WebURLResponse::WebURLResponse(const WebURL& url) : WebURLResponse() {
- SetURL(url);
+WebURLResponse::WebURLResponse(const WebURL& current_request_url)
+ : WebURLResponse() {
+ SetCurrentRequestUrl(current_request_url);
}
WebURLResponse& WebURLResponse::operator=(const WebURLResponse& r) {
@@ -99,12 +78,16 @@ bool WebURLResponse::IsNull() const {
return resource_response_->IsNull();
}
-WebURL WebURLResponse::Url() const {
- return resource_response_->Url();
+WebURL WebURLResponse::CurrentRequestUrl() const {
+ return resource_response_->CurrentRequestUrl();
+}
+
+void WebURLResponse::SetCurrentRequestUrl(const WebURL& url) {
+ resource_response_->SetCurrentRequestUrl(url);
}
-void WebURLResponse::SetURL(const WebURL& url) {
- resource_response_->SetURL(url);
+WebURL WebURLResponse::ResponseUrl() const {
+ return resource_response_->ResponseUrl();
}
void WebURLResponse::SetConnectionID(unsigned connection_id) {
@@ -355,12 +338,10 @@ void WebURLResponse::SetURLListViaServiceWorker(
resource_response_->SetURLListViaServiceWorker(url_list);
}
-WebURL WebURLResponse::OriginalURLViaServiceWorker() const {
- return resource_response_->OriginalURLViaServiceWorker();
-}
-
-void WebURLResponse::SetMultipartBoundary(const char* bytes, size_t size) {
- resource_response_->SetMultipartBoundary(bytes, size);
+bool WebURLResponse::HasUrlListViaServiceWorker() const {
+ DCHECK(resource_response_->UrlListViaServiceWorker().size() == 0 ||
+ WasFetchedViaServiceWorker());
+ return resource_response_->UrlListViaServiceWorker().size() > 0;
}
void WebURLResponse::SetCacheStorageCacheName(
@@ -409,26 +390,6 @@ void WebURLResponse::SetIsSignedExchangeInnerResponse(
is_signed_exchange_inner_response);
}
-WebURLResponse::ExtraData* WebURLResponse::GetExtraData() const {
- scoped_refptr<ResourceResponse::ExtraData> data =
- resource_response_->GetExtraData();
- if (!data)
- return nullptr;
- return static_cast<URLResponseExtraDataContainer*>(data.get())
- ->GetExtraData();
-}
-
-void WebURLResponse::SetExtraData(WebURLResponse::ExtraData* extra_data) {
- if (extra_data != GetExtraData()) {
- resource_response_->SetExtraData(
- URLResponseExtraDataContainer::Create(extra_data));
- }
-}
-
-void WebURLResponse::AppendRedirectResponse(const WebURLResponse& response) {
- resource_response_->AppendRedirectResponse(response.ToResourceResponse());
-}
-
WebString WebURLResponse::AlpnNegotiatedProtocol() const {
return resource_response_->AlpnNegotiatedProtocol();
}
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc
index d27d0cd47b1..5e2ce559a81 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc
@@ -36,41 +36,6 @@
namespace blink {
-namespace {
-
-class ResponseTestExtraData : public WebURLResponse::ExtraData {
- public:
- explicit ResponseTestExtraData(bool* alive) : alive_(alive) { *alive = true; }
-
- ~ResponseTestExtraData() override { *alive_ = false; }
-
- private:
- bool* alive_;
-};
-
-} // anonymous namespace
-
-TEST(WebURLResponseTest, ExtraData) {
- bool alive = false;
- {
- WebURLResponse url_response;
- ResponseTestExtraData* extra_data = new ResponseTestExtraData(&alive);
- EXPECT_TRUE(alive);
-
- url_response.SetExtraData(extra_data);
- EXPECT_EQ(extra_data, url_response.GetExtraData());
- {
- WebURLResponse other_url_response = url_response;
- EXPECT_TRUE(alive);
- EXPECT_EQ(extra_data, other_url_response.GetExtraData());
- EXPECT_EQ(extra_data, url_response.GetExtraData());
- }
- EXPECT_TRUE(alive);
- EXPECT_EQ(extra_data, url_response.GetExtraData());
- }
- EXPECT_FALSE(alive);
-}
-
TEST(WebURLResponseTest, NewInstanceIsNull) {
WebURLResponse instance;
EXPECT_TRUE(instance.IsNull());
@@ -78,7 +43,7 @@ TEST(WebURLResponseTest, NewInstanceIsNull) {
TEST(WebURLResponseTest, NotNullAfterSetURL) {
WebURLResponse instance;
- instance.SetURL(KURL("http://localhost/"));
+ instance.SetCurrentRequestUrl(KURL("http://localhost/"));
EXPECT_FALSE(instance.IsNull());
}
diff --git a/chromium/third_party/blink/renderer/platform/feature_policy/DEPS b/chromium/third_party/blink/renderer/platform/feature_policy/DEPS
deleted file mode 100644
index 76ebef5528b..00000000000
--- a/chromium/third_party/blink/renderer/platform/feature_policy/DEPS
+++ /dev/null
@@ -1,17 +0,0 @@
-include_rules = [
- # Don't depend on platform/.
- "-third_party/blink/renderer/platform",
-
- # Module.
- "+third_party/blink/renderer/platform/feature_policy",
-
- # Dependencies.
- "+third_party/blink/renderer/platform/heap",
- "+third_party/blink/renderer/platform/json",
- "+third_party/blink/renderer/platform/network/http_parsers.h",
- "+third_party/blink/renderer/platform/platform_export.h",
- "+third_party/blink/renderer/platform/runtime_enabled_features.h",
- "+third_party/blink/renderer/platform/testing",
- "+third_party/blink/renderer/platform/weborigin/security_origin.h",
- "+third_party/blink/renderer/platform/wtf",
-]
diff --git a/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc b/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
index 0b211881222..be4552bc788 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
@@ -4,39 +4,15 @@
#include "third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h"
#include "mojo/public/mojom/base/shared_memory.mojom-blink.h"
-#include "third_party/blink/public/platform/interface_provider.h"
#include "third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h"
-#include "third_party/blink/public/platform/platform.h"
namespace blink {
FontUniqueNameLookupAndroid::~FontUniqueNameLookupAndroid() = default;
-bool FontUniqueNameLookupAndroid::EnsureMatchingServiceConnected() {
- if (font_table_matcher_)
- return true;
-
- mojom::blink::FontUniqueNameLookupPtr service;
- Platform::Current()->GetInterfaceProvider()->GetInterface(
- mojo::MakeRequest(&service));
-
- base::ReadOnlySharedMemoryRegion region_ptr;
- if (!service->GetUniqueNameLookupTable(&region_ptr)) {
- // Tests like StyleEngineTest do not set up a full browser where Blink can
- // connect to a browser side service for font lookups. Placing a DCHECK here
- // is too strict for such a case.
- LOG(ERROR) << "Unable to connect to browser side service for src: local() "
- "font lookup.";
- return false;
- }
-
- font_table_matcher_ = std::make_unique<FontTableMatcher>(region_ptr.Map());
- return true;
-}
-
sk_sp<SkTypeface> FontUniqueNameLookupAndroid::MatchUniqueName(
const String& font_unique_name) {
- if (!EnsureMatchingServiceConnected())
+ if (!EnsureMatchingServiceConnected<mojom::blink::FontUniqueNameLookupPtr>())
return nullptr;
base::Optional<FontTableMatcher::MatchResult> match_result =
font_table_matcher_->MatchName(font_unique_name.Utf8().data());
diff --git a/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h b/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
index 54b1cc7c177..4447709a405 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
@@ -19,8 +19,6 @@ class FontUniqueNameLookupAndroid : public FontUniqueNameLookup {
sk_sp<SkTypeface> MatchUniqueName(const String& font_unique_name) override;
private:
- bool EnsureMatchingServiceConnected();
- std::unique_ptr<FontTableMatcher> font_table_matcher_;
DISALLOW_COPY_AND_ASSIGN(FontUniqueNameLookupAndroid);
};
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc
index b72da9f7015..92d453b5a84 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc
@@ -46,6 +46,7 @@
#include "third_party/blink/renderer/platform/fonts/font_global_context.h"
#include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
#include "third_party/blink/renderer/platform/fonts/font_smoothing_mode.h"
+#include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_cache.h"
#include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
#include "third_party/blink/renderer/platform/fonts/text_rendering_mode.h"
@@ -117,7 +118,10 @@ FontPlatformData* FontCache::GetFontPlatformData(
float size = font_description.EffectiveFontSize();
unsigned rounded_size = size * FontCacheKey::PrecisionMultiplier();
- FontCacheKey key = font_description.CacheKey(creation_params);
+ bool is_unique_match =
+ alternate_font_name == AlternateFontName::kLocalUniqueFace;
+ FontCacheKey key =
+ font_description.CacheKey(creation_params, is_unique_match);
// Remove the font size from the cache key, and handle the font size
// separately in the inner HashMap. So that different size of FontPlatformData
@@ -440,4 +444,18 @@ void FontCache::DumpShapeResultCache(
WTF::Partitions::kAllocatedObjectPoolName);
}
+sk_sp<SkTypeface> FontCache::CreateTypefaceFromUniqueName(
+ const FontFaceCreationParams& creation_params,
+ CString& name) {
+ FontUniqueNameLookup* unique_name_lookup =
+ FontGlobalContext::Get()->GetFontUniqueNameLookup();
+ DCHECK(unique_name_lookup);
+ sk_sp<SkTypeface> uniquely_identified_font =
+ unique_name_lookup->MatchUniqueName(creation_params.Family());
+ if (uniquely_identified_font) {
+ return uniquely_identified_font;
+ }
+ return nullptr;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache.h b/chromium/third_party/blink/renderer/platform/fonts/font_cache.h
index f32563d2997..589e0baf11a 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.h
@@ -253,6 +253,9 @@ class PLATFORM_EXPORT FontCache {
UChar32,
const SimpleFontData* font_data_to_substitute,
FontFallbackPriority = FontFallbackPriority::kText);
+ sk_sp<SkTypeface> CreateTypefaceFromUniqueName(
+ const FontFaceCreationParams& creation_params,
+ CString& name);
friend class FontGlobalContext;
FontCache();
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h b/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h
index a7823cbb3e2..f9d07ff2efa 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h
@@ -53,17 +53,20 @@ struct FontCacheKey {
: creation_params_(),
font_size_(0),
options_(0),
- device_scale_factor_(0) {}
+ device_scale_factor_(0),
+ is_unique_match_(false) {}
FontCacheKey(FontFaceCreationParams creation_params,
float font_size,
unsigned options,
float device_scale_factor,
- scoped_refptr<FontVariationSettings> variation_settings)
+ scoped_refptr<FontVariationSettings> variation_settings,
+ bool is_unique_match)
: creation_params_(creation_params),
font_size_(font_size * kFontSizePrecisionMultiplier),
options_(options),
device_scale_factor_(device_scale_factor),
- variation_settings_(std::move(variation_settings)) {}
+ variation_settings_(std::move(variation_settings)),
+ is_unique_match_(is_unique_match) {}
FontCacheKey(WTF::HashTableDeletedValueType)
: font_size_(HashTableDeletedSize()) {}
@@ -71,10 +74,13 @@ struct FontCacheKey {
unsigned GetHash() const {
// Convert from float with 3 digit precision before hashing.
unsigned device_scale_factor_hash = device_scale_factor_ * 1000;
- unsigned hash_codes[5] = {
- creation_params_.GetHash(), font_size_, options_,
+ unsigned hash_codes[6] = {
+ creation_params_.GetHash(),
+ font_size_,
+ options_,
device_scale_factor_hash,
- variation_settings_ ? variation_settings_->GetHash() : 0};
+ variation_settings_ ? variation_settings_->GetHash() : 0,
+ is_unique_match_};
return StringHasher::HashMemory<sizeof(hash_codes)>(hash_codes);
}
@@ -82,7 +88,8 @@ struct FontCacheKey {
return creation_params_ == other.creation_params_ &&
font_size_ == other.font_size_ && options_ == other.options_ &&
device_scale_factor_ == other.device_scale_factor_ &&
- variation_settings_ == other.variation_settings_;
+ variation_settings_ == other.variation_settings_ &&
+ is_unique_match_ == other.is_unique_match_;
}
bool IsHashTableDeletedValue() const {
@@ -105,6 +112,7 @@ struct FontCacheKey {
// device_scale_factor_ to be a part of computing the cache key.
float device_scale_factor_;
scoped_refptr<FontVariationSettings> variation_settings_;
+ bool is_unique_match_;
};
struct FontCacheKeyHash {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description.cc b/chromium/third_party/blink/renderer/platform/fonts/font_description.cc
index 32d2a97d5a2..63eff2f4e24 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_description.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.cc
@@ -214,6 +214,7 @@ float FontDescription::EffectiveFontSize() const {
FontCacheKey FontDescription::CacheKey(
const FontFaceCreationParams& creation_params,
+ bool is_unique_match,
const FontSelectionRequest& font_selection_request) const {
unsigned options =
static_cast<unsigned>(fields_.synthetic_italic_) << 6 | // bit 7
@@ -229,7 +230,8 @@ FontCacheKey FontDescription::CacheKey(
#endif
FontCacheKey cache_key(creation_params, EffectiveFontSize(),
options | font_selection_request_.GetHash() << 8,
- device_scale_factor_for_key, variation_settings_);
+ device_scale_factor_for_key, variation_settings_,
+ is_unique_match);
return cache_key;
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description.h b/chromium/third_party/blink/renderer/platform/fonts/font_description.h
index 925923d8ff1..f97284d0220 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_description.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.h
@@ -252,6 +252,7 @@ class PLATFORM_EXPORT FontDescription {
const; // Returns either the computedSize or the computedPixelSize
FontCacheKey CacheKey(
const FontFaceCreationParams&,
+ bool is_unique_match,
const FontSelectionRequest& = FontSelectionRequest()) const;
void SetFamily(const FontFamily& family) { family_list_ = family; }
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc b/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc
index e573d634fb5..c5935c6bfb4 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/platform/fonts/font_description.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -48,11 +49,11 @@ TEST(FontDescriptionTest, TestHashCollision) {
FontDescription source;
WTF::Vector<unsigned> hashes;
- for (size_t i = 0; i < arraysize(weights); i++) {
+ for (size_t i = 0; i < base::size(weights); i++) {
source.SetWeight(weights[i]);
- for (size_t j = 0; j < arraysize(stretches); j++) {
+ for (size_t j = 0; j < base::size(stretches); j++) {
source.SetStretch(stretches[j]);
- for (size_t k = 0; k < arraysize(slopes); k++) {
+ for (size_t k = 0; k < base::size(slopes); k++) {
source.SetStyle(slopes[k]);
unsigned hash = source.StyleHashWithoutFamilyList();
ASSERT_FALSE(hashes.Contains(hash));
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
index 85e8fbc134c..be346f33c16 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
@@ -202,7 +202,8 @@ FallbackListCompositeKey FontFallbackList::CompositeKey(
platform_data);
}
if (result) {
- key.Add(font_description.CacheKey(params));
+ bool is_unique_match = false;
+ key.Add(font_description.CacheKey(params, is_unique_match));
if (!result->IsSegmented() && !result->IsCustomFont())
FontCache::GetFontCache()->ReleaseFontData(ToSimpleFontData(result));
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc b/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc
index abc03f40a1b..b4ed950174e 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/platform/fonts/vdmx_parser.h"
#include <SkFont.h>
+#include <SkFontMetrics.h>
#include <SkTypeface.h>
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc
index 64dd8218e9a..77b09a33375 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc
@@ -51,7 +51,7 @@ FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
is_hash_table_deleted_value_(true)
#if defined(OS_WIN)
,
- paint_text_flags_(0)
+ font_flags_(0)
#endif
{
}
@@ -65,7 +65,7 @@ FontPlatformData::FontPlatformData()
is_hash_table_deleted_value_(false)
#if defined(OS_WIN)
,
- paint_text_flags_(0)
+ font_flags_(0)
#endif
{
}
@@ -82,7 +82,7 @@ FontPlatformData::FontPlatformData(float size,
is_hash_table_deleted_value_(false)
#if defined(OS_WIN)
,
- paint_text_flags_(0)
+ font_flags_(0)
#endif
{
}
@@ -104,7 +104,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& source)
is_hash_table_deleted_value_(false)
#if defined(OS_WIN)
,
- paint_text_flags_(source.paint_text_flags_)
+ font_flags_(source.font_flags_)
#endif
{
}
@@ -140,7 +140,7 @@ FontPlatformData::FontPlatformData(sk_sp<SkTypeface> typeface,
is_hash_table_deleted_value_(false)
#if defined(OS_WIN)
,
- paint_text_flags_(0)
+ font_flags_(0)
#endif
{
#if !defined(OS_WIN) && !defined(OS_MACOSX)
@@ -200,7 +200,7 @@ const FontPlatformData& FontPlatformData::operator=(
#endif
#if defined(OS_WIN)
- paint_text_flags_ = 0;
+ font_flags_ = 0;
#endif
return *this;
@@ -311,20 +311,6 @@ WebFontRenderStyle FontPlatformData::QuerySystemRenderStyle(
return result;
}
-void FontPlatformData::SetupSkPaint(SkPaint* font,
- float device_scale_factor,
- const Font*) const {
- style_.ApplyToSkPaint(*font, device_scale_factor);
-
- const float ts = text_size_ >= 0 ? text_size_ : 12;
- font->setTextSize(SkFloatToScalar(ts));
- font->setTypeface(typeface_);
- font->setFakeBoldText(synthetic_bold_);
- font->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
-
- font->setEmbeddedBitmapText(!avoid_embedded_bitmaps_);
-}
-
void FontPlatformData::SetupSkFont(SkFont* font,
float device_scale_factor,
const Font*) const {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h
index 7c6939331e2..e2e018ff469 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h
@@ -31,8 +31,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_PLATFORM_DATA_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_PLATFORM_DATA_H_
-#include "SkPaint.h"
-#include "SkTypeface.h"
#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "third_party/blink/public/platform/web_font_render_style.h"
@@ -46,6 +44,7 @@
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
#include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkTypeface.h"
@@ -154,17 +153,17 @@ class PLATFORM_EXPORT FontPlatformData {
const WebFontRenderStyle& GetFontRenderStyle() const { return style_; }
#endif
- // TODO(reed): SetupSkPaint is deprecated. Remove this once all call sites
- // are moved to SetupSkFont.
- void SetupSkPaint(SkPaint*,
- float device_scale_factor = 1,
- const Font* = nullptr) const;
void SetupSkFont(SkFont*,
float device_scale_factor = 1,
const Font* = nullptr) const;
#if defined(OS_WIN)
- int PaintTextFlags() const { return paint_text_flags_; }
+ enum Flags {
+ kAntiAlias = 1 << 0,
+ kSubpixelsAntiAlias = 1 << 1,
+ kSubpixelMetrics = 1 << 2,
+ };
+ int FontFlags() const { return font_flags_; }
#endif
private:
@@ -199,8 +198,8 @@ class PLATFORM_EXPORT FontPlatformData {
mutable scoped_refptr<HarfBuzzFace> harfbuzz_face_;
bool is_hash_table_deleted_value_;
#if defined(OS_WIN)
- // TODO(https://crbug.com/808221): Replace |paint_text_flags_| with |style_|.
- int paint_text_flags_;
+ // TODO(https://crbug.com/808221): Replace |font_flags_| with |style_|.
+ int font_flags_;
#endif
};
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_selection_types.h b/chromium/third_party/blink/renderer/platform/fonts/font_selection_types.h
index 5fb1723e2fe..85d2cb47c23 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_selection_types.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_selection_types.h
@@ -185,6 +185,18 @@ static inline const FontSelectionValue& ItalicSlopeValue() {
return italicValue;
}
+static inline const FontSelectionValue& MaxObliqueValue() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, maxObliqueValue,
+ (90));
+ return maxObliqueValue;
+}
+
+static inline const FontSelectionValue& MinObliqueValue() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, minObliqueValue,
+ (-90));
+ return minObliqueValue;
+}
+
static inline const FontSelectionValue& BoldThreshold() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, boldThreshold,
(600));
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc b/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc
index 1a084984c34..ef45e9929b1 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc
@@ -4,12 +4,17 @@
#include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
#include "base/macros.h"
-#include "build/build_config.h"
+#include "third_party/blink/public/platform/interface_provider.h"
+#include "third_party/blink/public/platform/platform.h"
#if defined(OS_ANDROID)
+#include "third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h"
#include "third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h"
#elif defined(OS_LINUX)
#include "third_party/blink/renderer/platform/fonts/linux/font_unique_name_lookup_linux.h"
+#elif defined(OS_WIN)
+#include "third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom-blink.h"
+#include "third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h"
#endif
namespace blink {
@@ -23,10 +28,45 @@ FontUniqueNameLookup::GetPlatformUniqueNameLookup() {
return std::make_unique<FontUniqueNameLookupAndroid>();
#elif defined(OS_LINUX)
return std::make_unique<FontUniqueNameLookupLinux>();
+#elif defined(OS_WIN)
+ return std::make_unique<FontUniqueNameLookupWin>();
#else
NOTREACHED();
return nullptr;
#endif
}
+#if defined(OS_WIN) || defined(OS_ANDROID)
+template <class ServicePtrType>
+bool FontUniqueNameLookup::EnsureMatchingServiceConnected() {
+ if (font_table_matcher_)
+ return true;
+
+ ServicePtrType service;
+ Platform::Current()->GetInterfaceProvider()->GetInterface(
+ mojo::MakeRequest(&service));
+
+ base::ReadOnlySharedMemoryRegion region_ptr;
+ if (!service->GetUniqueNameLookupTable(&region_ptr)) {
+ // Tests like StyleEngineTest do not set up a full browser where Blink can
+ // connect to a browser side service for font lookups. Placing a DCHECK here
+ // is too strict for such a case.
+ LOG(ERROR) << "Unable to connect to browser side service for src: local() "
+ "font lookup.";
+ return false;
+ }
+
+ font_table_matcher_ = std::make_unique<FontTableMatcher>(region_ptr.Map());
+ return true;
+}
+#endif
+
+#if defined(OS_ANDROID)
+template bool FontUniqueNameLookup::EnsureMatchingServiceConnected<
+ mojom::blink::FontUniqueNameLookupPtr>();
+#elif defined(OS_WIN)
+template bool FontUniqueNameLookup::EnsureMatchingServiceConnected<
+ mojom::blink::DWriteFontProxyPtr>();
+#endif
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h b/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h
index 38428c7a9dc..58f5390436b 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h
@@ -6,14 +6,21 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_UNIQUE_NAME_LOOKUP_H_
#include "base/macros.h"
+#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#if defined(OS_ANDROID) || defined(OS_WIN)
+#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
+#endif
+
#include <SkRefCnt.h>
#include <SkTypeface.h>
#include <memory>
namespace blink {
+class FontTableMatcher;
+
class FontUniqueNameLookup {
public:
// Factory function to construct a platform specific font unique name lookup
@@ -28,6 +35,14 @@ class FontUniqueNameLookup {
protected:
FontUniqueNameLookup();
+ // Windows and Android share the concept of connecting to a Mojo service for
+ // retrieving a ReadOnlySharedMemoryRegion with the lookup table in it.
+#if defined(OS_WIN) || defined(OS_ANDROID)
+ template <class ServicePtrType>
+ bool EnsureMatchingServiceConnected();
+ std::unique_ptr<FontTableMatcher> font_table_matcher_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(FontUniqueNameLookup);
};
diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm
index 97bebbdb53a..1fcd34ea515 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm
+++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm
@@ -25,6 +25,8 @@
#import <AppKit/NSFont.h>
#import <AvailabilityMacros.h>
+
+#include "base/stl_util.h"
#import "third_party/blink/public/platform/mac/web_sandbox_support.h"
#import "third_party/blink/public/platform/platform.h"
#import "third_party/blink/renderer/platform/fonts/font.h"
@@ -59,13 +61,13 @@ static CTFontDescriptorRef CascadeToLastResortFontDescriptor() {
const void* descriptors[] = {last_resort.Get()};
RetainPtr<CFArrayRef> values_array(
kAdoptCF, CFArrayCreate(kCFAllocatorDefault, descriptors,
- arraysize(descriptors), &kCFTypeArrayCallBacks));
+ base::size(descriptors), &kCFTypeArrayCallBacks));
const void* keys[] = {kCTFontCascadeListAttribute};
const void* values[] = {values_array.Get()};
RetainPtr<CFDictionaryRef> attributes(
kAdoptCF,
- CFDictionaryCreate(kCFAllocatorDefault, keys, values, arraysize(keys),
+ CFDictionaryCreate(kCFAllocatorDefault, keys, values, base::size(keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
@@ -112,58 +114,6 @@ static sk_sp<SkTypeface> LoadFromBrowserProcess(NSFont* ns_font,
return return_font;
}
-void FontPlatformData::SetupSkPaint(SkPaint* paint,
- float,
- const Font* font) const {
- bool should_smooth_fonts = true;
- bool should_antialias = true;
- bool should_subpixel_position = true;
-
- if (font) {
- switch (font->GetFontDescription().FontSmoothing()) {
- case kAntialiased:
- should_smooth_fonts = false;
- break;
- case kSubpixelAntialiased:
- break;
- case kNoSmoothing:
- should_antialias = false;
- should_smooth_fonts = false;
- break;
- case kAutoSmoothing:
- // For the AutoSmooth case, don't do anything! Keep the default
- // settings.
- break;
- }
- }
-
- if (WebTestSupport::IsRunningWebTest()) {
- should_smooth_fonts = false;
- should_antialias =
- should_antialias && WebTestSupport::IsFontAntialiasingEnabledForTest();
- should_subpixel_position =
- WebTestSupport::IsTextSubpixelPositioningAllowedForTest();
- }
-
- paint->setAntiAlias(should_antialias);
- paint->setEmbeddedBitmapText(false);
- const float ts = text_size_ >= 0 ? text_size_ : 12;
- paint->setTextSize(SkFloatToScalar(ts));
- paint->setTypeface(typeface_);
- paint->setFakeBoldText(synthetic_bold_);
- paint->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
- paint->setLCDRenderText(should_smooth_fonts);
- paint->setSubpixelText(should_subpixel_position);
-
- // When rendering using CoreGraphics, disable hinting when
- // webkit-font-smoothing:antialiased or text-rendering:geometricPrecision is
- // used. See crbug.com/152304
- if (font &&
- (font->GetFontDescription().FontSmoothing() == kAntialiased ||
- font->GetFontDescription().TextRendering() == kGeometricPrecision))
- paint->setHinting(SkFontHinting::kNone);
-}
-
void FontPlatformData::SetupSkFont(SkFont* skfont,
float,
const Font* font) const {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
index 3365749c759..4c18c37138f 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
@@ -4,13 +4,43 @@
#include "third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h"
+#include <hb-aat.h>
+#include <hb.h>
+
namespace blink {
+namespace {
+
+bool activationSelectorPresent(
+ hb_face_t* hb_face,
+ const hb_aat_layout_feature_type_t feature_type,
+ const hb_aat_layout_feature_selector_t enabled_selector_expectation) {
+ Vector<hb_aat_layout_feature_selector_info_t> feature_selectors;
+ unsigned num_feature_selectors = 0;
+ unsigned default_index = 0;
+ num_feature_selectors = hb_aat_layout_feature_type_get_selector_infos(
+ hb_face, feature_type, 0, nullptr, nullptr, nullptr);
+ feature_selectors.resize(num_feature_selectors);
+ if (!hb_aat_layout_feature_type_get_selector_infos(
+ hb_face, feature_type, 0, &num_feature_selectors,
+ feature_selectors.data(), &default_index)) {
+ return false;
+ }
+ for (hb_aat_layout_feature_selector_info_t selector_info :
+ feature_selectors) {
+ if (selector_info.enable == enabled_selector_expectation)
+ return true;
+ }
+ return false;
+}
+} // namespace
+
OpenTypeCapsSupport::OpenTypeCapsSupport()
: harfbuzz_face_(nullptr),
requested_caps_(FontDescription::kCapsNormal),
font_support_(FontSupport::kFull),
- caps_synthesis_(CapsSynthesis::kNone) {}
+ caps_synthesis_(CapsSynthesis::kNone),
+ font_format_(FontFormat::kUndetermined) {}
OpenTypeCapsSupport::OpenTypeCapsSupport(
const HarfBuzzFace* harfbuzz_face,
@@ -19,7 +49,8 @@ OpenTypeCapsSupport::OpenTypeCapsSupport(
: harfbuzz_face_(harfbuzz_face),
requested_caps_(requested_caps),
font_support_(FontSupport::kFull),
- caps_synthesis_(CapsSynthesis::kNone) {
+ caps_synthesis_(CapsSynthesis::kNone),
+ font_format_(FontFormat::kUndetermined) {
if (requested_caps != FontDescription::kCapsNormal)
DetermineFontSupport(script);
}
@@ -102,24 +133,114 @@ CaseMapIntend OpenTypeCapsSupport::NeedsCaseChange(
return case_map_intend;
}
+OpenTypeCapsSupport::FontFormat OpenTypeCapsSupport::GetFontFormat() const {
+ if (font_format_ == FontFormat::kUndetermined) {
+ hb_face_t* hb_face = hb_font_get_face(
+ harfbuzz_face_->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout));
+
+ std::unique_ptr<hb_blob_t, decltype(&hb_blob_destroy)> morx_blob(
+ hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 'x')),
+ hb_blob_destroy);
+ std::unique_ptr<hb_blob_t, decltype(&hb_blob_destroy)> mort_blob(
+ hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 't')),
+ hb_blob_destroy);
+
+ // TODO(crbug.com/911149): Use hb_aat_layout_has_substitution() for
+ // has_morx_or_mort and hb_ot_layout_has_substitution() for has_gsub once is
+ // exposed in HarfBuzz.
+ bool has_morx_or_mort = hb_blob_get_length(morx_blob.get()) ||
+ hb_blob_get_length(mort_blob.get());
+ bool has_gsub = hb_ot_layout_has_substitution(hb_face);
+ font_format_ = has_morx_or_mort&& !has_gsub
+ ? font_format_ = FontFormat::kAat
+ : font_format_ = FontFormat::kOpenType;
+ }
+ return font_format_;
+}
+
+bool OpenTypeCapsSupport::SupportsFeature(hb_script_t script,
+ uint32_t tag) const {
+ if (GetFontFormat() == FontFormat::kAat)
+ return SupportsAatFeature(tag);
+ return SupportsOpenTypeFeature(script, tag);
+}
+
+bool OpenTypeCapsSupport::SupportsAatFeature(uint32_t tag) const {
+ // We only want to detect small-caps and capitals-to-small-capitals features
+ // for aat-fonts, any other requests are returned as not supported.
+ if (tag != HB_TAG('s', 'm', 'c', 'p') && tag != HB_TAG('c', '2', 's', 'c')) {
+ return false;
+ }
+
+ hb_face_t* hb_face = hb_font_get_face(
+ harfbuzz_face_->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout));
+
+ Vector<hb_aat_layout_feature_type_t> aat_features;
+ unsigned feature_count =
+ hb_aat_layout_get_feature_types(hb_face, 0, nullptr, nullptr);
+ aat_features.resize(feature_count);
+ if (!hb_aat_layout_get_feature_types(hb_face, 0, &feature_count,
+ aat_features.data()))
+ return false;
+
+ if (tag == HB_TAG('s', 'm', 'c', 'p')) {
+ // Check for presence of new style (feature id 38) or old style (letter
+ // case, feature id 3) small caps feature presence, then check for the
+ // specific required activation selectors.
+ if (!aat_features.Contains(HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE) &&
+ !aat_features.Contains(HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE))
+ return false;
+
+ // Check for new style small caps, feature id 38.
+ if (aat_features.Contains(HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE)) {
+ if (activationSelectorPresent(
+ hb_face, HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE,
+ HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS))
+ return true;
+ }
+
+ // Check for old style small caps enabling selector, feature id 3.
+ if (aat_features.Contains(HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE)) {
+ if (activationSelectorPresent(hb_face,
+ HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE,
+ HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS))
+ return true;
+ }
+
+ // Neither old or new style small caps present.
+ return false;
+ }
+
+ if (tag == HB_TAG('c', '2', 's', 'c')) {
+ if (!aat_features.Contains(HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE))
+ return false;
+
+ return activationSelectorPresent(
+ hb_face, HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE,
+ HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS);
+ }
+
+ return false;
+}
+
void OpenTypeCapsSupport::DetermineFontSupport(hb_script_t script) {
switch (requested_caps_) {
case FontDescription::kSmallCaps:
- if (!SupportsOpenTypeFeature(script, HB_TAG('s', 'm', 'c', 'p'))) {
+ if (!SupportsFeature(script, HB_TAG('s', 'm', 'c', 'p'))) {
font_support_ = FontSupport::kNone;
caps_synthesis_ = CapsSynthesis::kLowerToSmallCaps;
}
break;
case FontDescription::kAllSmallCaps:
- if (!(SupportsOpenTypeFeature(script, HB_TAG('s', 'm', 'c', 'p')) &&
- SupportsOpenTypeFeature(script, HB_TAG('c', '2', 's', 'c')))) {
+ if (!(SupportsFeature(script, HB_TAG('s', 'm', 'c', 'p')) &&
+ SupportsFeature(script, HB_TAG('c', '2', 's', 'c')))) {
font_support_ = FontSupport::kNone;
caps_synthesis_ = CapsSynthesis::kBothToSmallCaps;
}
break;
case FontDescription::kPetiteCaps:
- if (!SupportsOpenTypeFeature(script, HB_TAG('p', 'c', 'a', 'p'))) {
- if (SupportsOpenTypeFeature(script, HB_TAG('s', 'm', 'c', 'p'))) {
+ if (!SupportsFeature(script, HB_TAG('p', 'c', 'a', 'p'))) {
+ if (SupportsFeature(script, HB_TAG('s', 'm', 'c', 'p'))) {
font_support_ = FontSupport::kFallback;
} else {
font_support_ = FontSupport::kNone;
@@ -128,10 +249,10 @@ void OpenTypeCapsSupport::DetermineFontSupport(hb_script_t script) {
}
break;
case FontDescription::kAllPetiteCaps:
- if (!(SupportsOpenTypeFeature(script, HB_TAG('p', 'c', 'a', 'p')) &&
- SupportsOpenTypeFeature(script, HB_TAG('c', '2', 'p', 'c')))) {
- if (SupportsOpenTypeFeature(script, HB_TAG('s', 'm', 'c', 'p')) &&
- SupportsOpenTypeFeature(script, HB_TAG('c', '2', 's', 'c'))) {
+ if (!(SupportsFeature(script, HB_TAG('p', 'c', 'a', 'p')) &&
+ SupportsFeature(script, HB_TAG('c', '2', 'p', 'c')))) {
+ if (SupportsFeature(script, HB_TAG('s', 'm', 'c', 'p')) &&
+ SupportsFeature(script, HB_TAG('c', '2', 's', 'c'))) {
font_support_ = FontSupport::kFallback;
} else {
font_support_ = FontSupport::kNone;
@@ -140,9 +261,9 @@ void OpenTypeCapsSupport::DetermineFontSupport(hb_script_t script) {
}
break;
case FontDescription::kUnicase:
- if (!SupportsOpenTypeFeature(script, HB_TAG('u', 'n', 'i', 'c'))) {
+ if (!SupportsFeature(script, HB_TAG('u', 'n', 'i', 'c'))) {
caps_synthesis_ = CapsSynthesis::kUpperToSmallCaps;
- if (SupportsOpenTypeFeature(script, HB_TAG('s', 'm', 'c', 'p'))) {
+ if (SupportsFeature(script, HB_TAG('s', 'm', 'c', 'p'))) {
font_support_ = FontSupport::kFallback;
} else {
font_support_ = FontSupport::kNone;
@@ -150,7 +271,7 @@ void OpenTypeCapsSupport::DetermineFontSupport(hb_script_t script) {
}
break;
case FontDescription::kTitlingCaps:
- if (!SupportsOpenTypeFeature(script, HB_TAG('t', 'i', 't', 'l'))) {
+ if (!SupportsFeature(script, HB_TAG('t', 'i', 't', 'l'))) {
font_support_ = FontSupport::kNone;
}
break;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h
index 841e465c8a1..4f53191116f 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h
@@ -29,7 +29,13 @@ class PLATFORM_EXPORT OpenTypeCapsSupport {
CaseMapIntend NeedsCaseChange(SmallCapsIterator::SmallCapsBehavior run_case);
private:
+ enum class FontFormat { kUndetermined, kOpenType, kAat };
+ // Lazily intializes font_format_ when needed and returns the format of the
+ // underlying HarfBuzzFace/Font.
+ FontFormat GetFontFormat() const;
void DetermineFontSupport(hb_script_t);
+ bool SupportsFeature(hb_script_t, uint32_t tag) const;
+ bool SupportsAatFeature(uint32_t tag) const;
bool SupportsOpenTypeFeature(hb_script_t, uint32_t tag) const;
const HarfBuzzFace* harfbuzz_face_;
@@ -50,6 +56,7 @@ class PLATFORM_EXPORT OpenTypeCapsSupport {
FontSupport font_support_;
CapsSynthesis caps_synthesis_;
+ mutable FontFormat font_format_;
};
}; // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc
new file mode 100644
index 00000000000..f0097556ae1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/fonts/font_description.h"
+#include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
+
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+
+namespace blink {
+
+void ensureHasNativeSmallCaps(const std::string& font_family_name) {
+ sk_sp<SkTypeface> test_typeface =
+ SkTypeface::MakeFromName(font_family_name.c_str(), SkFontStyle());
+ FontPlatformData font_platform_data(test_typeface, font_family_name.c_str(),
+ 16, false, false);
+ ASSERT_EQ(font_platform_data.FontFamilyName(), font_family_name.c_str());
+
+ OpenTypeCapsSupport caps_support(font_platform_data.GetHarfBuzzFace(),
+ FontDescription::FontVariantCaps::kSmallCaps,
+ HB_SCRIPT_LATIN);
+ // If caps_support.NeedsRunCaseSplitting() is true, this means that synthetic
+ // upper-casing / lower-casing is required and the run needs to be segmented
+ // by upper-case, lower-case properties. If it is false, it means that the
+ // font feature can be used and no synthetic case-changing is needed.
+ ASSERT_FALSE(caps_support.NeedsRunCaseSplitting());
+}
+
+// The AAT fonts for testing are only available on Mac OS X 10.13.
+#if defined(OS_MACOSX)
+#define MAYBE_SmallCapsForSFNSText SmallCapsForSFNSText
+#else
+#define MAYBE_SmallCapsForSFNSText DISABLED_SmallCapsForSFNSText
+#endif
+TEST(OpenTypeCapsSupportTest, MAYBE_SmallCapsForSFNSText) {
+#if defined(OS_MACOSX)
+ if (!base::mac::IsAtLeastOS10_13())
+ return;
+#endif
+ std::vector<std::string> test_fonts = {
+ ".SF NS Text", // has OpenType small-caps
+ "Apple Chancery", // has old-style (feature id 3,"Letter Case")
+ // small-caps
+ "Baskerville"}; // has new-style (feature id 38, "Upper Case")
+ // small-case.
+ for (auto& test_font : test_fonts)
+ ensureHasNativeSmallCaps(test_font);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
index 012238f1901..cf3bf20955d 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
@@ -168,7 +168,7 @@ ScriptRunIterator::ScriptRunIterator(const UChar* text,
ScriptRunIterator::ScriptRunIterator(const UChar* text, wtf_size_t length)
: ScriptRunIterator(text, length, ICUScriptData::Instance()) {}
-bool ScriptRunIterator::Consume(unsigned& limit, UScriptCode& script) {
+bool ScriptRunIterator::Consume(unsigned* limit, UScriptCode* script) {
if (current_set_.IsEmpty()) {
return false;
}
@@ -188,16 +188,16 @@ bool ScriptRunIterator::Consume(unsigned& limit, UScriptCode& script) {
break;
}
if (!MergeSets()) {
- limit = pos;
- script = ResolveCurrentScript();
- FixupStack(script);
+ *limit = pos;
+ *script = ResolveCurrentScript();
+ FixupStack(*script);
current_set_ = *next_set_;
return true;
}
}
- limit = length_;
- script = ResolveCurrentScript();
+ *limit = length_;
+ *script = ResolveCurrentScript();
current_set_.clear();
return true;
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h
index 6f3f16aead4..39d23e3b64f 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h
@@ -31,7 +31,7 @@ class PLATFORM_EXPORT ScriptRunIterator {
// the process.
ScriptRunIterator(const UChar* text, wtf_size_t length, const ScriptData*);
- bool Consume(unsigned& limit, UScriptCode&);
+ bool Consume(unsigned* limit, UScriptCode*);
static constexpr int kMaxScriptCount = 20;
using UScriptCodeList = Vector<UScriptCode, kMaxScriptCount>;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc
index a792bdfb5c8..0432f686457 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc
@@ -316,7 +316,7 @@ class ScriptRunIteratorTest : public testing::Test {
unsigned limit;
UScriptCode code;
unsigned long run_count = 0;
- while (script_run_iterator->Consume(limit, code)) {
+ while (script_run_iterator->Consume(&limit, &code)) {
ASSERT_LT(run_count, expect.size());
ASSERT_EQ(expect[run_count].limit, limit);
ASSERT_EQ(expect[run_count].code, code);
@@ -331,7 +331,7 @@ TEST_F(ScriptRunIteratorTest, Empty) {
ScriptRunIterator script_run_iterator(empty.Characters16(), empty.length());
unsigned limit = 0;
UScriptCode code = USCRIPT_INVALID_CODE;
- DCHECK(!script_run_iterator.Consume(limit, code));
+ DCHECK(!script_run_iterator.Consume(&limit, &code));
ASSERT_EQ(limit, 0u);
ASSERT_EQ(code, USCRIPT_INVALID_CODE);
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index 3cef0162ce7..6e239ed1d33 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -553,7 +553,7 @@ void SplitUntilNextCaseChange(
}
}
-hb_feature_t CreateFeature(hb_tag_t tag, uint32_t value = 0) {
+constexpr hb_feature_t CreateFeature(hb_tag_t tag, uint32_t value = 0) {
return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */};
}
@@ -562,11 +562,11 @@ hb_feature_t CreateFeature(hb_tag_t tag, uint32_t value = 0) {
void SetFontFeatures(const Font* font, FeaturesVector* features) {
const FontDescription& description = font->GetFontDescription();
- static hb_feature_t no_kern = CreateFeature(HB_TAG('k', 'e', 'r', 'n'));
- static hb_feature_t no_vkrn = CreateFeature(HB_TAG('v', 'k', 'r', 'n'));
+ constexpr hb_feature_t no_kern = CreateFeature(HB_TAG('k', 'e', 'r', 'n'));
+ constexpr hb_feature_t no_vkrn = CreateFeature(HB_TAG('v', 'k', 'r', 'n'));
switch (description.GetKerning()) {
case FontDescription::kNormalKerning:
- // kern/vkrn are enabled by default
+ // kern/vkrn are enabled by default in HarfBuzz
break;
case FontDescription::kNoneKerning:
features->push_back(description.IsVerticalAnyUpright() ? no_vkrn
@@ -576,51 +576,41 @@ void SetFontFeatures(const Font* font, FeaturesVector* features) {
break;
}
- static hb_feature_t no_clig = CreateFeature(HB_TAG('c', 'l', 'i', 'g'));
- static hb_feature_t no_liga = CreateFeature(HB_TAG('l', 'i', 'g', 'a'));
- switch (description.CommonLigaturesState()) {
- case FontDescription::kDisabledLigaturesState:
+ {
+ bool default_is_off = description.TextRendering() == blink::kOptimizeSpeed;
+ bool letter_spacing = description.LetterSpacing() != 0;
+ constexpr auto normal = FontDescription::kNormalLigaturesState;
+ constexpr auto enabled = FontDescription::kEnabledLigaturesState;
+ constexpr auto disabled = FontDescription::kDisabledLigaturesState;
+
+ // clig and liga are on by default in HarfBuzz
+ constexpr hb_feature_t no_clig = CreateFeature(HB_TAG('c', 'l', 'i', 'g'));
+ constexpr hb_feature_t no_liga = CreateFeature(HB_TAG('l', 'i', 'g', 'a'));
+ auto common = description.CommonLigaturesState();
+ if (letter_spacing ||
+ (common == disabled || (common == normal && default_is_off))) {
features->push_back(no_liga);
features->push_back(no_clig);
- break;
- case FontDescription::kEnabledLigaturesState:
- // liga and clig are on by default
- break;
- case FontDescription::kNormalLigaturesState:
- break;
- }
- static hb_feature_t dlig = CreateFeature(HB_TAG('d', 'l', 'i', 'g'), 1);
- switch (description.DiscretionaryLigaturesState()) {
- case FontDescription::kDisabledLigaturesState:
- // dlig is off by default
- break;
- case FontDescription::kEnabledLigaturesState:
+ }
+ // dlig is off by default in HarfBuzz
+ constexpr hb_feature_t dlig = CreateFeature(HB_TAG('d', 'l', 'i', 'g'), 1);
+ auto discretionary = description.DiscretionaryLigaturesState();
+ if (!letter_spacing && discretionary == enabled) {
features->push_back(dlig);
- break;
- case FontDescription::kNormalLigaturesState:
- break;
- }
- static hb_feature_t hlig = CreateFeature(HB_TAG('h', 'l', 'i', 'g'), 1);
- switch (description.HistoricalLigaturesState()) {
- case FontDescription::kDisabledLigaturesState:
- // hlig is off by default
- break;
- case FontDescription::kEnabledLigaturesState:
+ }
+ // hlig is off by default in HarfBuzz
+ constexpr hb_feature_t hlig = CreateFeature(HB_TAG('h', 'l', 'i', 'g'), 1);
+ auto historical = description.HistoricalLigaturesState();
+ if (!letter_spacing && historical == enabled) {
features->push_back(hlig);
- break;
- case FontDescription::kNormalLigaturesState:
- break;
- }
- static hb_feature_t no_calt = CreateFeature(HB_TAG('c', 'a', 'l', 't'));
- switch (description.ContextualLigaturesState()) {
- case FontDescription::kDisabledLigaturesState:
+ }
+ // calt is on by default in HarfBuzz
+ constexpr hb_feature_t no_calt = CreateFeature(HB_TAG('c', 'a', 'l', 't'));
+ auto contextual = description.ContextualLigaturesState();
+ if (letter_spacing ||
+ (contextual == disabled || (contextual == normal && default_is_off))) {
features->push_back(no_calt);
- break;
- case FontDescription::kEnabledLigaturesState:
- // calt is on by default
- break;
- case FontDescription::kNormalLigaturesState:
- break;
+ }
}
static hb_feature_t hwid = CreateFeature(HB_TAG('h', 'w', 'i', 'd'), 1);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
index 35e0d66e541..8767c55f3cc 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -114,7 +114,7 @@ class HarfBuzzShaperTest : public testing::Test {
class ScopedSubpixelOverride {
public:
ScopedSubpixelOverride(bool b) {
- prev_layout_test_ = WebTestSupport::IsRunningWebTest();
+ prev_web_test_ = WebTestSupport::IsRunningWebTest();
prev_subpixel_allowed_ =
WebTestSupport::IsTextSubpixelPositioningAllowedForTest();
prev_antialias_ = WebTestSupport::IsFontAntialiasingEnabledForTest();
@@ -147,7 +147,7 @@ class ScopedSubpixelOverride {
WebTestSupport::SetFontAntialiasingEnabledForTest(prev_antialias_);
WebTestSupport::SetTextSubpixelPositioningAllowedForTest(
prev_subpixel_allowed_);
- WebTestSupport::SetIsRunningWebTest(prev_layout_test_);
+ WebTestSupport::SetIsRunningWebTest(prev_web_test_);
// Fonts cached with a different subpixel positioning state are not
// automatically invalidated and need to be cleared between test
@@ -156,7 +156,7 @@ class ScopedSubpixelOverride {
}
private:
- bool prev_layout_test_;
+ bool prev_web_test_;
bool prev_subpixel_allowed_;
bool prev_antialias_;
bool prev_fd_subpixel_;
@@ -1232,13 +1232,13 @@ TEST_F(HarfBuzzShaperTest, ShapeResultCopyRangeIntoArabicThaiHanLatin) {
composite_result->SnappedStartPositionForOffset(8));
}
-TEST_F(HarfBuzzShaperTest, ShapeResultCopyRangeAcrossRuns) {
+TEST_P(ShapeParameterTest, ShapeResultCopyRangeAcrossRuns) {
// Create 3 runs:
// [0]: 1 character.
// [1]: 5 characters.
// [2]: 2 character.
String mixed_string(u"\u65E5Hello\u65E5\u65E5");
- TextDirection direction = TextDirection::kLtr;
+ TextDirection direction = GetParam();
HarfBuzzShaper shaper(mixed_string);
scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
@@ -1251,6 +1251,23 @@ TEST_F(HarfBuzzShaperTest, ShapeResultCopyRangeAcrossRuns) {
EXPECT_EQ(2u, target->NumCharacters());
}
+TEST_P(ShapeParameterTest, ShapeResultCopyRangeContextMultiRuns) {
+ // Create 2 runs:
+ // [0]: 5 characters.
+ // [1]: 4 character.
+ String mixed_string(u"Hello\u65E5\u65E5\u65E5\u65E5");
+ TextDirection direction = GetParam();
+ HarfBuzzShaper shaper(mixed_string);
+ scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
+
+ // Copy multiple times using |context| from multiple runs
+ unsigned context = 0;
+ scoped_refptr<ShapeResult> sub2to4 = result->SubRange(2, 4, &context);
+ EXPECT_EQ(2u, sub2to4->NumCharacters());
+ scoped_refptr<ShapeResult> sub5to9 = result->SubRange(5, 9, &context);
+ EXPECT_EQ(4u, sub5to9->NumCharacters());
+}
+
TEST_F(HarfBuzzShaperTest, ShapeResultCopyRangeSegmentGlyphBoundingBox) {
String string(u"THello worldL");
TextDirection direction = TextDirection::kLtr;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc
index b6c634c08be..910b4ba8516 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h"
+#include <algorithm>
#include <memory>
#include "third_party/blink/renderer/platform/fonts/script_run_iterator.h"
@@ -37,38 +38,14 @@ RunSegmenter::RunSegmenter(const UChar* buffer,
symbols_iterator_position_(0),
at_end_(!buffer_size_) {}
-void RunSegmenter::ConsumeScriptIteratorPastLastSplit() {
- DCHECK(script_run_iterator_);
- if (script_run_iterator_position_ <= last_split_ &&
- script_run_iterator_position_ < buffer_size_) {
- while (script_run_iterator_->Consume(script_run_iterator_position_,
- candidate_range_.script)) {
- if (script_run_iterator_position_ > last_split_)
- return;
- }
- }
-}
-
-void RunSegmenter::ConsumeOrientationIteratorPastLastSplit() {
- if (orientation_iterator_ && orientation_iterator_position_ <= last_split_ &&
- orientation_iterator_position_ < buffer_size_) {
- while (
- orientation_iterator_->Consume(&orientation_iterator_position_,
- &candidate_range_.render_orientation)) {
- if (orientation_iterator_position_ > last_split_)
- return;
- }
- }
-}
-
-void RunSegmenter::ConsumeSymbolsIteratorPastLastSplit() {
- DCHECK(symbols_iterator_);
- if (symbols_iterator_position_ <= last_split_ &&
- symbols_iterator_position_ < buffer_size_) {
- while (
- symbols_iterator_->Consume(&symbols_iterator_position_,
- &candidate_range_.font_fallback_priority)) {
- if (symbols_iterator_position_ > last_split_)
+template <class Iterator, typename SegmentationCategory>
+void RunSegmenter::ConsumeIteratorPastLastSplit(
+ std::unique_ptr<Iterator>& iterator,
+ unsigned* iterator_position,
+ SegmentationCategory* segmentation_category) {
+ if (*iterator_position <= last_split_ && *iterator_position < buffer_size_) {
+ while (iterator->Consume(iterator_position, segmentation_category)) {
+ if (*iterator_position > last_split_)
return;
}
}
@@ -80,24 +57,20 @@ bool RunSegmenter::Consume(RunSegmenterRange* next_range) {
if (at_end_)
return false;
- ConsumeScriptIteratorPastLastSplit();
- ConsumeOrientationIteratorPastLastSplit();
- ConsumeSymbolsIteratorPastLastSplit();
+ ConsumeIteratorPastLastSplit(script_run_iterator_,
+ &script_run_iterator_position_,
+ &candidate_range_.script);
+ ConsumeIteratorPastLastSplit(orientation_iterator_,
+ &orientation_iterator_position_,
+ &candidate_range_.render_orientation);
+ ConsumeIteratorPastLastSplit(symbols_iterator_, &symbols_iterator_position_,
+ &candidate_range_.font_fallback_priority);
- if (script_run_iterator_position_ <= orientation_iterator_position_ &&
- script_run_iterator_position_ <= symbols_iterator_position_) {
- last_split_ = script_run_iterator_position_;
- }
+ unsigned positions[] = {script_run_iterator_position_,
+ orientation_iterator_position_,
+ symbols_iterator_position_};
- if (orientation_iterator_position_ <= script_run_iterator_position_ &&
- orientation_iterator_position_ <= symbols_iterator_position_) {
- last_split_ = orientation_iterator_position_;
- }
-
- if (symbols_iterator_position_ <= script_run_iterator_position_ &&
- symbols_iterator_position_ <= orientation_iterator_position_) {
- last_split_ = symbols_iterator_position_;
- }
+ last_split_ = *std::min_element(std::begin(positions), std::end(positions));
candidate_range_.start = candidate_range_.end;
candidate_range_.end = last_split_;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
index 86bfc774f28..84647cae75b 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
@@ -47,9 +47,11 @@ class PLATFORM_EXPORT RunSegmenter {
}
private:
- void ConsumeOrientationIteratorPastLastSplit();
- void ConsumeScriptIteratorPastLastSplit();
- void ConsumeSymbolsIteratorPastLastSplit();
+ template <class Iterator, typename SegmentationCategory>
+ void ConsumeIteratorPastLastSplit(
+ std::unique_ptr<Iterator>& iterator,
+ unsigned* iterator_position,
+ SegmentationCategory* segmentation_category);
unsigned buffer_size_;
RunSegmenterRange candidate_range_;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc
index 664b1fcf3fa..ccf3942cc92 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc
@@ -39,7 +39,8 @@ namespace blink {
void ShapeCache::SmallStringKey::HashString() {
// TODO(cavalcanti): next add xxhash.
#if defined(USE_FUNCTION_CITYHASH)
- hash_ = CityHash64((const char*)characters_, length_ * sizeof(UChar));
+ hash_ = static_cast<unsigned>(
+ CityHash64((const char*)characters_, length_ * sizeof(UChar)));
#endif
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 11ca1595552..42a823029a7 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -122,13 +122,14 @@ unsigned ShapeResult::RunInfo::NumGraphemes(unsigned start,
unsigned end) const {
if (graphemes_.size() == 0 || start >= num_characters_)
return 0;
- DCHECK_LT(start, end);
- DCHECK_LE(end, num_characters_);
+ CHECK_LT(start, end);
+ CHECK_LE(end, num_characters_);
+ CHECK_EQ(num_characters_, graphemes_.size());
return graphemes_[end - 1] - graphemes_[start] + 1;
}
void ShapeResult::EnsureGraphemes(const StringView& text) const {
- DCHECK_EQ(NumCharacters(), text.length());
+ CHECK_EQ(NumCharacters(), text.length());
// Hit-testing, canvas, etc. may still call this function for 0-length text,
// or glyphs may be missing at all.
@@ -144,7 +145,7 @@ void ShapeResult::EnsureGraphemes(const StringView& text) const {
return;
unsigned result_start_index = StartIndex();
- for (const auto& run : runs_) {
+ for (const scoped_refptr<RunInfo>& run : runs_) {
if (!run)
continue;
DCHECK_GE(run->start_index_, result_start_index);
@@ -289,7 +290,6 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
BreakGlyphsOption break_glyphs_option,
GlyphIndexResult* result) const {
DCHECK(target_x >= 0 && target_x <= width_);
- const unsigned num_glyphs = glyph_data_.size();
result->origin_x = 0;
unsigned glyph_sequence_start = 0;
@@ -301,12 +301,12 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
glyph_sequence_start = glyph_sequence_end = num_characters_;
}
- for (unsigned i = 0; i < num_glyphs; ++i) {
- unsigned current_glyph_char_index = glyph_data_[i].character_index;
+ for (const HarfBuzzRunGlyphData& glyph_data : glyph_data_) {
+ unsigned current_glyph_char_index = glyph_data.character_index;
// If the glyph is part of the same sequence, we just accumulate the
// advance.
if (glyph_sequence_start == current_glyph_char_index) {
- result->advance += glyph_data_[i].advance;
+ result->advance += glyph_data.advance;
continue;
}
@@ -328,7 +328,7 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
}
glyph_sequence_start = current_glyph_char_index;
result->origin_x += result->advance;
- result->advance = glyph_data_[i].advance;
+ result->advance = glyph_data.advance;
}
// At this point, we have [glyph_sequence_start, glyph_sequence_end)
@@ -512,19 +512,18 @@ void ShapeResult::OffsetForPosition(float target_x,
unsigned characters_so_far = Rtl() ? NumCharacters() : 0;
float current_x = 0;
- for (unsigned i = 0; i < runs_.size(); ++i) {
- const RunInfo* run = runs_[i].get();
+ for (const scoped_refptr<RunInfo>& run_ptr : runs_) {
+ const RunInfo* run = run_ptr.get();
if (!run)
continue;
if (Rtl())
- characters_so_far -= runs_[i]->num_characters_;
+ characters_so_far -= run->num_characters_;
float next_x = current_x + run->width_;
float offset_for_run = target_x - current_x;
if (offset_for_run >= 0 && offset_for_run < run->width_) {
// The x value in question is within this script run.
run->CharacterIndexForXPosition(offset_for_run, break_glyphs_option,
result);
- result->run_index = i;
result->characters_on_left_runs = characters_so_far;
if (Rtl()) {
result->left_character_index =
@@ -555,7 +554,6 @@ void ShapeResult::OffsetForPosition(float target_x,
result->right_character_index += characters_so_far;
}
- result->run_index = runs_.size() - 1;
result->characters_on_left_runs = characters_so_far;
DCHECK_LE(result->left_character_index, NumCharacters());
@@ -971,38 +969,67 @@ unsigned ShapeResult::RunInfo::LimitNumGlyphs(
const bool is_ltr,
const hb_glyph_info_t* glyph_infos) {
unsigned num_glyphs = *num_glyphs_in_out;
+ CHECK_GT(num_glyphs, 0u);
// If there were larger character indexes than kMaxCharacterIndex, reduce
// num_glyphs so that all character indexes can fit to kMaxCharacterIndex.
// Because code points and glyphs are not always 1:1, we need to check the
// first and the last cluster.
+ const hb_glyph_info_t* left_glyph_info = &glyph_infos[start_glyph];
+ const hb_glyph_info_t* right_glyph_info = &left_glyph_info[num_glyphs - 1];
unsigned start_cluster;
if (is_ltr) {
- start_cluster = glyph_infos[start_glyph].cluster;
- unsigned last_cluster = glyph_infos[start_glyph + num_glyphs - 1].cluster;
- unsigned last_character_index = last_cluster - start_cluster;
- if (UNLIKELY(last_character_index >
- HarfBuzzRunGlyphData::kMaxCharacterIndex)) {
- // Make sure the end is a cluster boundary.
- do {
- num_glyphs--;
- num_characters_ = last_character_index;
- last_cluster = glyph_infos[start_glyph + num_glyphs - 1].cluster;
- last_character_index = last_cluster - start_cluster;
- } while (last_character_index > HarfBuzzRunGlyphData::kMaxCharacterIndex);
+ start_cluster = left_glyph_info->cluster;
+ unsigned last_cluster = right_glyph_info->cluster;
+ unsigned max_cluster =
+ start_cluster + HarfBuzzRunGlyphData::kMaxCharacterIndex;
+ if (UNLIKELY(last_cluster > max_cluster)) {
+ // Limit at |max_cluster| in LTR. If |max_cluster| is 100:
+ // 0 1 2 ... 98 99 99 101 101 103 ...
+ // ^ limit here.
+ // Find |glyph_info| where |cluster| <= |max_cluster|.
+ const hb_glyph_info_t* limit_glyph_info = std::upper_bound(
+ left_glyph_info, right_glyph_info + 1, max_cluster,
+ [](unsigned cluster, const hb_glyph_info_t& glyph_info) {
+ return cluster < glyph_info.cluster;
+ });
+ --limit_glyph_info;
+ CHECK_GT(limit_glyph_info, left_glyph_info);
+ CHECK_LT(limit_glyph_info, right_glyph_info);
+ DCHECK_LE(limit_glyph_info->cluster, max_cluster);
+ // Adjust |right_glyph_info| and recompute dependent variables.
+ right_glyph_info = limit_glyph_info;
+ num_glyphs = right_glyph_info - left_glyph_info + 1;
+ num_characters_ = right_glyph_info[1].cluster - start_cluster;
}
} else {
- start_cluster = glyph_infos[start_glyph + num_glyphs - 1].cluster;
- const unsigned last_cluster = glyph_infos[start_glyph].cluster;
- unsigned last_character_index = last_cluster - start_cluster;
- if (UNLIKELY(last_character_index >
- HarfBuzzRunGlyphData::kMaxCharacterIndex)) {
- do {
- num_glyphs--;
- num_characters_ = last_character_index;
- start_cluster = glyph_infos[start_glyph + num_glyphs - 1].cluster;
- last_character_index = last_cluster - start_cluster;
- } while (last_character_index > HarfBuzzRunGlyphData::kMaxCharacterIndex);
+ start_cluster = right_glyph_info->cluster;
+ unsigned last_cluster = left_glyph_info->cluster;
+ unsigned max_cluster =
+ start_cluster + HarfBuzzRunGlyphData::kMaxCharacterIndex;
+ if (UNLIKELY(last_cluster > max_cluster)) {
+ // Limit the right edge, which is in the reverse order in RTL.
+ // If |min_cluster| is 3:
+ // 103 102 ... 4 4 2 2 ...
+ // ^ limit here.
+ // Find |glyph_info| where |cluster| >= |min_cluster|.
+ unsigned min_cluster =
+ last_cluster - HarfBuzzRunGlyphData::kMaxCharacterIndex;
+ DCHECK_LT(start_cluster, min_cluster);
+ const hb_glyph_info_t* limit_glyph_info = std::upper_bound(
+ left_glyph_info, right_glyph_info + 1, min_cluster,
+ [](unsigned cluster, const hb_glyph_info_t& glyph_info) {
+ return cluster > glyph_info.cluster;
+ });
+ --limit_glyph_info;
+ CHECK_GT(limit_glyph_info, left_glyph_info);
+ CHECK_LT(limit_glyph_info, right_glyph_info);
+ DCHECK_GE(limit_glyph_info->cluster, min_cluster);
+ // Adjust |right_glyph_info| and recompute dependent variables.
+ right_glyph_info = limit_glyph_info;
+ start_cluster = right_glyph_info->cluster;
+ num_glyphs = right_glyph_info - left_glyph_info + 1;
+ num_characters_ = last_cluster - right_glyph_info[1].cluster;
}
}
@@ -1331,7 +1358,9 @@ void ShapeResult::CopyRange(unsigned start_offset,
// No need to process runs after the end of the range.
if ((!Rtl() && end_offset <= run_end) ||
(Rtl() && start_offset > run_start)) {
- if (start_run_index)
+ // RTL cannot use |start_run_index| because runs are in the descending
+ // order.
+ if (!Rtl() && start_run_index)
*start_run_index = run_index;
break;
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 72e7d4ee9f9..05ff17be9dc 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -342,7 +342,6 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
STACK_ALLOCATED();
public:
- unsigned run_index = 0;
// The total number of characters of runs_[0..run_index - 1].
unsigned characters_on_left_runs = 0;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
index 22198066fef..d6864da1866 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
@@ -4,35 +4,24 @@
#include "third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h"
-#include "third_party/blink/renderer/platform/fonts/font.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
#include "third_party/blink/renderer/platform/text/text_break_iterator.h"
namespace blink {
ShapingLineBreaker::ShapingLineBreaker(
- const HarfBuzzShaper* shaper,
- const Font* font,
scoped_refptr<const ShapeResult> result,
const LazyLineBreakIterator* break_iterator,
- const RunSegmenter::RunSegmenterRange* pre_segmented,
- ShapeResultSpacing<String>* spacing,
- const Hyphenation* hyphenation)
- : shaper_(shaper),
- font_(font),
+ const Hyphenation* hyphenation,
+ ShapeCallback shape_callback,
+ void* shape_callback_context)
+ : shape_callback_(shape_callback),
+ shape_callback_context_(shape_callback_context),
result_(result),
- pre_segmented_(pre_segmented),
break_iterator_(break_iterator),
- spacing_(spacing),
hyphenation_(hyphenation),
is_soft_hyphen_enabled_(true) {
- // ShapeResultSpacing is stateful when it has expansions. We may use it in
- // arbitrary order that it cannot have expansions.
- DCHECK(!spacing_ || !spacing_->HasExpansion());
-
// Line breaking performance relies on high-performance x-position to
// character offset lookup. Ensure that the desired cache has been computed.
DCHECK(result_);
@@ -175,18 +164,6 @@ ShapingLineBreaker::BreakOpportunity ShapingLineBreaker::NextBreakOpportunity(
return {break_iterator_->NextBreakOpportunity(offset, len), false};
}
-inline scoped_refptr<ShapeResult> ShapingLineBreaker::Shape(TextDirection direction,
- unsigned start,
- unsigned end) {
- if (!spacing_ || !spacing_->HasSpacing())
- return shaper_->Shape(font_, direction, start, end, pre_segmented_);
-
- scoped_refptr<ShapeResult> result =
- shaper_->Shape(font_, direction, start, end, pre_segmented_);
- result->ApplySpacing(*spacing_);
- return result;
-}
-
// Shapes a line of text by finding a valid and appropriate break opportunity
// based on the shaping results for the entire paragraph. Re-shapes the start
// and end of the line as needed.
@@ -289,14 +266,14 @@ scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeLine(
// There is no safe-to-break, reshape the whole range.
result_out->break_offset = break_opportunity.offset;
return ShapeResultView::Create(
- Shape(direction, start, break_opportunity.offset).get());
+ Shape(start, break_opportunity.offset).get());
}
LayoutUnit original_width = FlipRtl(
SnapEnd(result_->CachedPositionForOffset(first_safe - range_start),
direction) -
start_position,
direction);
- line_start_result = Shape(direction, start, first_safe);
+ line_start_result = Shape(start, first_safe);
available_space += line_start_result->SnappedWidth() - original_width;
}
DCHECK_GE(first_safe, start);
@@ -320,12 +297,12 @@ scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeLine(
break;
DCHECK_LE(break_opportunity.offset, range_end);
if (is_overflow) {
- line_end_result = Shape(direction, last_safe, break_opportunity.offset);
+ line_end_result = Shape(last_safe, break_opportunity.offset);
break;
}
LayoutUnit safe_position = SnapStart(
result_->CachedPositionForOffset(last_safe - range_start), direction);
- line_end_result = Shape(direction, last_safe, break_opportunity.offset);
+ line_end_result = Shape(last_safe, break_opportunity.offset);
if (line_end_result->SnappedWidth() <=
FlipRtl(end_position - safe_position, direction))
break;
@@ -402,14 +379,13 @@ scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeToEnd(
return ShapeResultView::Create(result_.get(), start, range_end);
// If no safe-to-break offset is found in range, reshape the entire range.
- TextDirection direction = result_->Direction();
if (first_safe >= range_end) {
- scoped_refptr<ShapeResult> line_result = Shape(direction, start, range_end);
+ scoped_refptr<ShapeResult> line_result = Shape(start, range_end);
return ShapeResultView::Create(line_result.get());
}
// Otherwise reshape to |first_safe|, then copy the rest.
- scoped_refptr<ShapeResult> line_start = Shape(direction, start, first_safe);
+ scoped_refptr<ShapeResult> line_start = Shape(start, first_safe);
ShapeResultView::Segment segments[2] = {
{line_start.get(), 0, std::numeric_limits<unsigned>::max()},
{result_.get(), first_safe, range_end}};
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
index 159cd3e4068..14ed982839e 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
@@ -13,15 +13,11 @@
namespace blink {
-class Font;
class ShapeResult;
class ShapeResultView;
-class HarfBuzzShaper;
class Hyphenation;
class LazyLineBreakIterator;
enum class LineBreakType;
-template <typename TextContainerType>
-class ShapeResultSpacing;
// Shapes a line of text by finding the ideal break position as indicated by the
// available space and the shape results for the entire paragraph. Once an ideal
@@ -37,18 +33,20 @@ class PLATFORM_EXPORT ShapingLineBreaker final {
STACK_ALLOCATED();
public:
- // Construct a ShapingLineBreaker.
+ // Callback function to reshape line edges.
//
- // When the ShapeResult is from a RunSegmenterRange, giving it can skip
- // running RunSegmenter for much better performance.
- ShapingLineBreaker(const HarfBuzzShaper*,
- const Font*,
- scoped_refptr<const ShapeResult>,
- const LazyLineBreakIterator*,
- const RunSegmenter::RunSegmenterRange* = nullptr,
- ShapeResultSpacing<String>* = nullptr,
- const Hyphenation* = nullptr);
- ~ShapingLineBreaker() = default;
+ // std::function is forbidden in Chromium and base::Callback is way too
+ // expensive so we resort to a good old function pointer instead.
+ using ShapeCallback = scoped_refptr<ShapeResult> (*)(void* context,
+ unsigned start,
+ unsigned end);
+
+ // Construct a ShapingLineBreaker.
+ ShapingLineBreaker(scoped_refptr<const ShapeResult> result,
+ const LazyLineBreakIterator* break_iterator,
+ const Hyphenation* hyphenation,
+ ShapeCallback shape_callback,
+ void* shape_callback_context);
// Represents details of the result of |ShapeLine()|.
struct Result {
@@ -116,20 +114,18 @@ class PLATFORM_EXPORT ShapingLineBreaker final {
unsigned word_end,
bool backwards) const;
- scoped_refptr<ShapeResult> Shape(TextDirection, unsigned start, unsigned end);
+ scoped_refptr<ShapeResult> Shape(unsigned start, unsigned end) {
+ return (*shape_callback_)(shape_callback_context_, start, end);
+ }
scoped_refptr<const ShapeResultView> ShapeToEnd(unsigned start,
unsigned first_safe,
unsigned range_start,
unsigned range_end);
- const HarfBuzzShaper* shaper_;
- const Font* font_;
+ const ShapeCallback shape_callback_;
+ void* shape_callback_context_;
scoped_refptr<const ShapeResult> result_;
- const RunSegmenter::RunSegmenterRange* pre_segmented_;
const LazyLineBreakIterator* break_iterator_;
- // TODO(kojii): ShapeResultSpacing is not const because it's stateful when it
- // has expansions. Split spacing and expansions to make this const.
- ShapeResultSpacing<String>* spacing_;
const Hyphenation* hyphenation_;
bool is_soft_hyphen_enabled_;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc
index 25ba3d14546..2e05f3302cc 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc
@@ -20,6 +20,20 @@ namespace blink {
namespace {
+struct HarfBuzzShaperCallbackContext {
+ const HarfBuzzShaper* shaper;
+ const Font* font;
+ TextDirection direction;
+};
+
+scoped_refptr<ShapeResult> HarfBuzzShaperCallback(void* untyped_context,
+ unsigned start,
+ unsigned end) {
+ HarfBuzzShaperCallbackContext* context =
+ static_cast<HarfBuzzShaperCallbackContext*>(untyped_context);
+ return context->shaper->Shape(context->font, context->direction, start, end);
+}
+
scoped_refptr<const ShapeResultView> ShapeLine(ShapingLineBreaker* breaker,
unsigned start_offset,
LayoutUnit available_space,
@@ -109,7 +123,9 @@ TEST_F(ShapingLineBreakerTest, ShapeLineLatin) {
shaper.Shape(&font, direction, 0, 4);
ASSERT_LT(first1->SnappedWidth(), first2->SnappedWidth());
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
scoped_refptr<const ShapeResultView> line;
unsigned break_offset = 0;
@@ -168,7 +184,9 @@ TEST_F(ShapingLineBreakerTest, ShapeLineLatinMultiLine) {
scoped_refptr<const ShapeResult> mid_third =
shaper.Shape(&font, direction, 0, 16);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
unsigned break_offset = 0;
ShapeLine(&breaker, 0, result->SnappedWidth() - 1, &break_offset);
@@ -195,7 +213,9 @@ TEST_F(ShapingLineBreakerTest, ShapeLineLatinBreakAll) {
scoped_refptr<const ShapeResult> midpoint =
shaper.Shape(&font, direction, 0, 16);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
scoped_refptr<const ShapeResultView> line;
unsigned break_offset = 0;
@@ -216,7 +236,9 @@ TEST_F(ShapingLineBreakerTest, ShapeLineZeroAvailableWidth) {
HarfBuzzShaper shaper(string);
scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
scoped_refptr<const ShapeResultView> line;
unsigned break_offset = 0;
LayoutUnit zero(0);
@@ -259,7 +281,9 @@ TEST_F(ShapingLineBreakerTest, DISABLED_ShapeLineArabicThaiHanLatin) {
});
LayoutUnit longest_word_width = (*longest_word)->SnappedWidth();
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
scoped_refptr<const ShapeResult> line;
unsigned break_offset = 0;
@@ -288,7 +312,9 @@ TEST_F(ShapingLineBreakerTest, ShapeLineRangeEndMidWord) {
scoped_refptr<const ShapeResult> result =
shaper.Shape(&font, direction, 0, 2);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
scoped_refptr<const ShapeResultView> line;
unsigned break_offset = 0;
@@ -325,7 +351,9 @@ TEST_P(BreakOpportunityTest, Next) {
scoped_refptr<const ShapeResult> result =
shaper.Shape(&font, TextDirection::kLtr);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
EXPECT_THAT(BreakPositionsByNext(breaker, string),
testing::ElementsAreArray(data.break_positions));
@@ -345,7 +373,9 @@ TEST_P(BreakOpportunityTest, Previous) {
scoped_refptr<const ShapeResult> result =
shaper.Shape(&font, TextDirection::kLtr);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
EXPECT_THAT(BreakPositionsByPrevious(breaker, string),
testing::ElementsAreArray(data.break_positions));
diff --git a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index d742599579d..144c2272df3 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -35,6 +35,7 @@
#include <memory>
#include <utility>
+#include "SkFontMetrics.h"
#include "SkPath.h"
#include "SkTypeface.h"
#include "SkTypes.h"
diff --git a/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc b/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
index 90898dbc4a8..3eb56e5f013 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
@@ -43,7 +43,6 @@
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/fonts/font_face_creation_params.h"
#include "third_party/blink/renderer/platform/fonts/font_global_context.h"
-#include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
#include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
#include "third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.h"
#include "third_party/blink/renderer/platform/language.h"
@@ -57,25 +56,6 @@
namespace blink {
-#if defined(OS_ANDROID) || defined(OS_LINUX)
-namespace {
-
-static sk_sp<SkTypeface> CreateTypefaceFromUniqueName(
- const FontFaceCreationParams& creation_params,
- CString& name) {
- FontUniqueNameLookup* unique_name_lookup =
- FontGlobalContext::Get()->GetFontUniqueNameLookup();
- DCHECK(unique_name_lookup);
- sk_sp<SkTypeface> uniquely_identified_font =
- unique_name_lookup->MatchUniqueName(creation_params.Family());
- if (uniquely_identified_font) {
- return uniquely_identified_font;
- }
- return nullptr;
-}
-} // namespace
-#endif
-
AtomicString ToAtomicString(const SkString& str) {
return AtomicString::FromUTF8(str.c_str(), str.size());
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc b/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc
index bc300449603..dad31d2a64d 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc
@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
#include "third_party/ots/include/ots-memory-stream.h"
#include "third_party/skia/include/core/SkStream.h"
@@ -209,7 +210,7 @@ sk_sp<SkTypeface> WebFontDecoder::Decode(SharedBuffer* buffer) {
return nullptr;
}
- const size_t decoded_length = output.Tell();
+ const size_t decoded_length = SafeCast<size_t>(output.Tell());
RecordDecodeSpeedHistogram(data, buffer->size(), CurrentTime() - start,
decoded_length);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc b/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc
index b63f8a2051d..e78ea8c04c4 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc
@@ -97,25 +97,6 @@ void WebFontRenderStyle::OverrideWith(const WebFontRenderStyle& other) {
use_subpixel_positioning = other.use_subpixel_positioning;
}
-void WebFontRenderStyle::ApplyToSkPaint(SkPaint& font,
- float device_scale_factor) const {
- auto sk_hint_style = static_cast<SkFontHinting>(hint_style);
- font.setAntiAlias(use_anti_alias);
- font.setHinting(sk_hint_style);
- font.setEmbeddedBitmapText(use_bitmaps);
- font.setAutohinted(use_auto_hint);
- if (use_anti_alias)
- font.setLCDRenderText(use_subpixel_rendering);
-
- // Force-enable subpixel positioning, except when full hinting is requested on
- // low-dpi screen or when running web tests.
- bool force_subpixel_positioning =
- !WebTestSupport::IsRunningWebTest() &&
- (sk_hint_style != SkFontHinting::kFull || device_scale_factor > 1.0f);
-
- font.setSubpixelText(force_subpixel_positioning || use_subpixel_positioning);
-}
-
void WebFontRenderStyle::ApplyToSkFont(SkFont* font,
float device_scale_factor) const {
auto sk_hint_style = static_cast<SkFontHinting>(hint_style);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
index b3e09a38bc1..99641e3d337 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
@@ -35,6 +35,7 @@
#include <utility>
#include "base/debug/alias.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/fonts/bitmap_glyphs_blacklist.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/fonts/font_face_creation_params.h"
@@ -42,9 +43,14 @@
#include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
#include "third_party/blink/renderer/platform/fonts/win/font_fallback_win.h"
#include "third_party/blink/renderer/platform/language.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/skia/include/core/SkFontMgr.h"
+#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
+#include <ft2build.h>
+#include <freetype/freetype.h>
+
namespace blink {
HashMap<String, sk_sp<SkTypeface>, CaseFoldingHash>*
@@ -67,6 +73,44 @@ int32_t EnsureMinimumFontHeightIfNeeded(int32_t font_height) {
return (font_height < 12.0f) && (GetACP() == 936) ? 12.0f : font_height;
}
+// Test-only code for matching sideloaded fonts by postscript name. This
+// implementation is incomplete, as it does not match the full font name and
+// only uses FT_Get_Postscript_Name, which returns an ASCII font name. This is
+// intended to pass tests on Windows, where for example src: local(Ahem) is used
+// in @font-face CSS declarations. Skia does not expose getAdvancedMetrics, so
+// we use FreeType here to parse the font's postscript name.
+sk_sp<SkTypeface> FindUniqueFontNameFromSideloadedFonts(
+ const String& font_name,
+ HashMap<String, sk_sp<SkTypeface>, CaseFoldingHash>* sideloaded_fonts) {
+ CHECK(sideloaded_fonts);
+ FT_Library library;
+ FT_Init_FreeType(&library);
+
+ sk_sp<SkTypeface> return_typeface(nullptr);
+ for (auto& sideloaded_font : sideloaded_fonts->Values()) {
+ // Open ttc index zero as we can assume that we do not sideload TrueType
+ // collections.
+ SkStreamAsset* typeface_stream = sideloaded_font->openStream(0);
+ CHECK(typeface_stream->getMemoryBase());
+ std::string font_family_name;
+ FT_Face font_face;
+ FT_Open_Args open_args = {
+ FT_OPEN_MEMORY,
+ reinterpret_cast<const FT_Byte*>(typeface_stream->getMemoryBase()),
+ typeface_stream->getLength()};
+ CHECK_EQ(FT_Err_Ok, FT_Open_Face(library, &open_args, 0, &font_face));
+ font_family_name = FT_Get_Postscript_Name(font_face);
+ FT_Done_Face(font_face);
+
+ if (font_name.FoldCase() == String(font_family_name.c_str()).FoldCase()) {
+ return_typeface = sideloaded_font;
+ break;
+ }
+ }
+ FT_Done_FreeType(library);
+ return return_typeface;
+}
+
} // namespace
// static
@@ -215,10 +259,10 @@ scoped_refptr<SimpleFontData> FontCache::PlatformFallbackFontForCharacter(
int num_fonts = 0;
if (script == USCRIPT_HAN) {
pan_uni_fonts = kCjkFonts;
- num_fonts = arraysize(kCjkFonts);
+ num_fonts = base::size(kCjkFonts);
} else {
pan_uni_fonts = kCommonFonts;
- num_fonts = arraysize(kCommonFonts);
+ num_fonts = base::size(kCommonFonts);
}
// Font returned from getFallbackFamily may not cover |character|
// because it's based on script to font mapping. This problem is
@@ -294,7 +338,7 @@ static bool TypefacesHasWeightSuffix(const AtomicString& family,
{L" ultrabold", 10, FontSelectionValue(800)},
{L" black", 6, FontSelectionValue(900)},
{L" heavy", 6, FontSelectionValue(900)}};
- size_t num_variants = arraysize(kVariantForSuffix);
+ size_t num_variants = base::size(kVariantForSuffix);
for (size_t i = 0; i < num_variants; i++) {
const FamilyWeightSuffix& entry = kVariantForSuffix[i];
if (family.EndsWith(entry.suffix, kTextCaseUnicodeInsensitive)) {
@@ -331,7 +375,7 @@ static bool TypefacesHasStretchSuffix(const AtomicString& family,
{L" expanded", 9, ExpandedWidthValue()},
{L" extraexpanded", 14, ExtraExpandedWidthValue()},
{L" ultraexpanded", 14, UltraExpandedWidthValue()}};
- size_t num_variants = arraysize(kVariantForSuffix);
+ size_t num_variants = base::size(kVariantForSuffix);
for (size_t i = 0; i < num_variants; i++) {
const FamilyStretchSuffix& entry = kVariantForSuffix[i];
if (family.EndsWith(entry.suffix, kTextCaseUnicodeInsensitive)) {
@@ -352,59 +396,79 @@ std::unique_ptr<FontPlatformData> FontCache::CreateFontPlatformData(
float font_size,
AlternateFontName alternate_font_name) {
DCHECK_EQ(creation_params.CreationType(), kCreateFontByFamily);
+ sk_sp<SkTypeface> typeface;
CString name;
- sk_sp<SkTypeface> typeface =
- CreateTypeface(font_description, creation_params, name);
- // Windows will always give us a valid pointer here, even if the face name
- // is non-existent. We have to double-check and see if the family name was
- // really used.
- if (!typeface ||
- !TypefacesMatchesFamily(typeface.get(), creation_params.Family())) {
- AtomicString adjusted_name;
- FontSelectionValue variant_weight;
- FontSelectionValue variant_stretch;
-
- // TODO: crbug.com/627143 LocalFontFaceSource.cpp, which implements
- // retrieving src: local() font data uses getFontData, which in turn comes
- // here, to retrieve fonts from the cache and specifies the argument to
- // local() as family name. So we do not match by full font name or
- // postscript name as the spec says:
- // https://drafts.csswg.org/css-fonts-3/#src-desc
-
- // Prevent one side effect of the suffix translation below where when
- // matching local("Roboto Regular") it tries to find the closest match even
- // though that can be a bold font in case of Roboto Bold.
- if (alternate_font_name == AlternateFontName::kLocalUniqueFace) {
- return nullptr;
+
+ if (alternate_font_name == AlternateFontName::kLocalUniqueFace &&
+ RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled()) {
+ typeface = CreateTypefaceFromUniqueName(creation_params, name);
+
+ if (!typeface && sideloaded_fonts_) {
+ typeface = FindUniqueFontNameFromSideloadedFonts(creation_params.Family(),
+ sideloaded_fonts_);
}
- if (alternate_font_name == AlternateFontName::kLastResort) {
- if (!typeface)
- return nullptr;
- } else if (TypefacesHasWeightSuffix(creation_params.Family(), adjusted_name,
- variant_weight)) {
- FontFaceCreationParams adjusted_params(adjusted_name);
- FontDescription adjusted_font_description = font_description;
- adjusted_font_description.SetWeight(variant_weight);
- typeface =
- CreateTypeface(adjusted_font_description, adjusted_params, name);
- if (!typeface || !TypefacesMatchesFamily(typeface.get(), adjusted_name)) {
+ // We do not need to try any heuristic around the font name, as below, for
+ // family matching.
+ if (!typeface)
+ return nullptr;
+
+ } else {
+ typeface = CreateTypeface(font_description, creation_params, name);
+
+ // For a family match, Windows will always give us a valid pointer here,
+ // even if the face name is non-existent. We have to double-check and see if
+ // the family name was really used.
+ if (!typeface ||
+ !TypefacesMatchesFamily(typeface.get(), creation_params.Family())) {
+ AtomicString adjusted_name;
+ FontSelectionValue variant_weight;
+ FontSelectionValue variant_stretch;
+
+ // TODO: crbug.com/627143 LocalFontFaceSource.cpp, which implements
+ // retrieving src: local() font data uses getFontData, which in turn comes
+ // here, to retrieve fonts from the cache and specifies the argument to
+ // local() as family name. So we do not match by full font name or
+ // postscript name as the spec says:
+ // https://drafts.csswg.org/css-fonts-3/#src-desc
+
+ // Prevent one side effect of the suffix translation below where when
+ // matching local("Roboto Regular") it tries to find the closest match
+ // even though that can be a bold font in case of Roboto Bold.
+ if (alternate_font_name == AlternateFontName::kLocalUniqueFace) {
return nullptr;
}
- } else if (TypefacesHasStretchSuffix(creation_params.Family(),
- adjusted_name, variant_stretch)) {
- FontFaceCreationParams adjusted_params(adjusted_name);
- FontDescription adjusted_font_description = font_description;
- adjusted_font_description.SetStretch(variant_stretch);
- typeface =
- CreateTypeface(adjusted_font_description, adjusted_params, name);
- if (!typeface || !TypefacesMatchesFamily(typeface.get(), adjusted_name)) {
+ if (alternate_font_name == AlternateFontName::kLastResort) {
+ if (!typeface)
+ return nullptr;
+ } else if (TypefacesHasWeightSuffix(creation_params.Family(),
+ adjusted_name, variant_weight)) {
+ FontFaceCreationParams adjusted_params(adjusted_name);
+ FontDescription adjusted_font_description = font_description;
+ adjusted_font_description.SetWeight(variant_weight);
+ typeface =
+ CreateTypeface(adjusted_font_description, adjusted_params, name);
+ if (!typeface ||
+ !TypefacesMatchesFamily(typeface.get(), adjusted_name)) {
+ return nullptr;
+ }
+
+ } else if (TypefacesHasStretchSuffix(creation_params.Family(),
+ adjusted_name, variant_stretch)) {
+ FontFaceCreationParams adjusted_params(adjusted_name);
+ FontDescription adjusted_font_description = font_description;
+ adjusted_font_description.SetStretch(variant_stretch);
+ typeface =
+ CreateTypeface(adjusted_font_description, adjusted_params, name);
+ if (!typeface ||
+ !TypefacesMatchesFamily(typeface.get(), adjusted_name)) {
+ return nullptr;
+ }
+ } else {
return nullptr;
}
- } else {
- return nullptr;
}
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc
index ecb970bdd70..1c4ad7ccb81 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_fallback_win.cc
@@ -34,6 +34,7 @@
#include <unicode/uchar.h>
#include <limits>
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/text/icu_error.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -376,13 +377,13 @@ const UChar* GetFontBasedOnUnicodeBlock(UBlockCode block_code,
static const UChar* math_font = 0;
static bool initialized = false;
if (!initialized) {
- for (size_t i = 0; i < arraysize(kEmojiFonts); i++) {
+ for (size_t i = 0; i < base::size(kEmojiFonts); i++) {
if (IsFontPresent(kEmojiFonts[i], font_manager)) {
emoji_font = kEmojiFonts[i];
break;
}
}
- for (size_t i = 0; i < arraysize(kMathFonts); i++) {
+ for (size_t i = 0; i < base::size(kMathFonts); i++) {
if (IsFontPresent(kMathFonts[i], font_manager)) {
math_font = kMathFonts[i];
break;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc
index 4fc4b20ddfa..e5cc3293961 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc
@@ -39,55 +39,21 @@
namespace blink {
-void FontPlatformData::SetupSkPaint(SkPaint* font, float, const Font*) const {
- font->setTextSize(SkFloatToScalar(text_size_));
- font->setTypeface(typeface_);
- font->setFakeBoldText(synthetic_bold_);
- font->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
-
- uint32_t text_flags = PaintTextFlags();
- uint32_t flags = font->getFlags();
- static const uint32_t kTextFlagsMask =
- SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag |
- SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kSubpixelText_Flag;
- flags &= ~kTextFlagsMask;
-
- // Only use sub-pixel positioning if anti aliasing is enabled. Otherwise,
- // without font smoothing, subpixel text positioning leads to uneven spacing
- // since subpixel test placement coordinates would be passed to Skia, which
- // only has non-antialiased glyphs to draw, so they necessarily get clamped at
- // pixel positions, which leads to uneven spacing, either too close or too far
- // away from adjacent glyphs. We avoid this by linking the two flags.
- if (text_flags & SkPaint::kAntiAlias_Flag)
- flags |= SkPaint::kSubpixelText_Flag;
-
- if (WebTestSupport::IsRunningWebTest() &&
- !WebTestSupport::IsTextSubpixelPositioningAllowedForTest())
- flags &= ~SkPaint::kSubpixelText_Flag;
-
- SkASSERT(!(text_flags & ~kTextFlagsMask));
- flags |= text_flags;
-
- font->setFlags(flags);
-
- font->setEmbeddedBitmapText(!avoid_embedded_bitmaps_);
-}
-
void FontPlatformData::SetupSkFont(SkFont* font, float, const Font*) const {
font->setSize(SkFloatToScalar(text_size_));
font->setTypeface(typeface_);
font->setEmbolden(synthetic_bold_);
font->setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
- uint32_t text_flags = PaintTextFlags();
- if (text_flags & SkPaint::kLCDRenderText_Flag) {
+ uint32_t font_flags = FontFlags();
+ if (font_flags & kSubpixelsAntiAlias) {
font->setEdging(SkFont::Edging::kSubpixelAntiAlias);
- } else if (text_flags & SkPaint::kAntiAlias_Flag) {
+ } else if (font_flags & kAntiAlias) {
font->setEdging(SkFont::Edging::kAntiAlias);
} else {
font->setEdging(SkFont::Edging::kAlias);
}
- font->setSubpixel(SkToBool(text_flags & SkPaint::kSubpixelText_Flag));
+ font->setSubpixel(SkToBool(font_flags & kSubpixelMetrics));
// Only use sub-pixel positioning if anti aliasing is enabled. Otherwise,
// without font smoothing, subpixel text positioning leads to uneven spacing
@@ -95,7 +61,7 @@ void FontPlatformData::SetupSkFont(SkFont* font, float, const Font*) const {
// only has non-antialiased glyphs to draw, so they necessarily get clamped at
// pixel positions, which leads to uneven spacing, either too close or too far
// away from adjacent glyphs. We avoid this by linking the two flags.
- if (text_flags & SkPaint::kAntiAlias_Flag)
+ if (font_flags & kAntiAlias)
font->setSubpixel(true);
if (WebTestSupport::IsRunningWebTest() &&
@@ -113,18 +79,18 @@ static bool IsWebFont(const String& family_name) {
'=' == family_name[23];
}
-static int ComputePaintTextFlags(String font_family_name) {
+static int ComputeFontFlags(String font_family_name) {
if (WebTestSupport::IsRunningWebTest())
return WebTestSupport::IsFontAntialiasingEnabledForTest()
- ? SkPaint::kAntiAlias_Flag
+ ? FontPlatformData::kAntiAlias
: 0;
- int text_flags = 0;
+ int font_flags = 0;
if (FontCache::GetFontCache()->AntialiasedTextEnabled()) {
int lcd_flag = FontCache::GetFontCache()->LcdTextEnabled()
- ? SkPaint::kLCDRenderText_Flag
+ ? FontPlatformData::kSubpixelsAntiAlias
: 0;
- text_flags = SkPaint::kAntiAlias_Flag | lcd_flag;
+ font_flags = FontPlatformData::kAntiAlias | lcd_flag;
}
// Many web-fonts are so poorly hinted that they are terrible to read when
@@ -132,13 +98,13 @@ static int ComputePaintTextFlags(String font_family_name) {
// drawn with at least grayscale AA, even when the System (getSystemTextFlags)
// tells us to draw only in BW.
if (IsWebFont(font_family_name))
- text_flags |= SkPaint::kAntiAlias_Flag;
+ font_flags |= FontPlatformData::kAntiAlias;
- return text_flags;
+ return font_flags;
}
void FontPlatformData::QuerySystemForRenderStyle() {
- paint_text_flags_ = ComputePaintTextFlags(FontFamilyName());
+ font_flags_ = ComputeFontFlags(FontFamilyName());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc
new file mode 100644
index 00000000000..715ce8996a0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h"
+
+#include "base/files/file_path.h"
+#include "mojo/public/mojom/base/shared_memory.mojom-blink.h"
+#include "third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom-blink.h"
+#include "third_party/blink/renderer/platform/histogram.h"
+#include "third_party/skia/include/ports/SkTypeface_win.h"
+
+namespace {
+
+// These enum values correspond to the
+// "Blink.Fonts.WindowsUniqueLocalFontInstantiationResult" histogram, new values
+// can be added, but old values should never be reused.
+enum WindowsUniqueLocalFontInstantiationResult {
+ kSuccess = 0,
+ kErrorOutsideWindowsFontsDirectory = 1,
+ kErrorOther = 2,
+ kMaxWindowsUniqueLocalFontInstantiationResult = 3
+};
+
+} // namespace
+
+namespace blink {
+
+FontUniqueNameLookupWin::FontUniqueNameLookupWin() = default;
+
+FontUniqueNameLookupWin::~FontUniqueNameLookupWin() = default;
+
+sk_sp<SkTypeface> FontUniqueNameLookupWin::MatchUniqueName(
+ const String& font_unique_name) {
+ if (!EnsureMatchingServiceConnected<mojom::blink::DWriteFontProxyPtr>())
+ return nullptr;
+
+ base::Optional<FontTableMatcher::MatchResult> match_result =
+ font_table_matcher_->MatchName(font_unique_name.Utf8().data());
+ if (!match_result)
+ return nullptr;
+ // Record here when a locally uniquely matched font could not be
+ // instantiated. One reason could be that the font was outside the
+ // C:\Windows\Fonts directory and thus not accessible due to sandbox
+ // restrictions.
+ sk_sp<SkTypeface> local_typeface = SkTypeface::MakeFromFile(
+ match_result->font_path.c_str(), match_result->ttc_index);
+
+ WindowsUniqueLocalFontInstantiationResult result = kSuccess;
+
+ // There is a chance that some systems have managed to register fonts into the
+ // Windows system font collection outside the C:\Windows\Fonts directory. For
+ // sandboxing reasons, we are unable to access them here. This histogram
+ // serves to quantify how often this case occurs and whether we need and
+ // additional sandbox helper to open the file handle on the browser process
+ // side.
+ if (!local_typeface) {
+ base::FilePath windows_fonts_path(L"C:\\WINDOWS\\FONTS");
+ if (!windows_fonts_path.IsParent(
+ base::FilePath::FromUTF8Unsafe(match_result->font_path.c_str())))
+ result = kErrorOutsideWindowsFontsDirectory;
+ else
+ result = kErrorOther;
+ }
+
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(
+ EnumerationHistogram, windows_unique_local_font_instantiation_histogram,
+ ("Blink.Fonts.WindowsUniqueLocalFontInstantiationResult",
+ kMaxWindowsUniqueLocalFontInstantiationResult));
+ windows_unique_local_font_instantiation_histogram.Count(result);
+
+ return local_typeface;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h
new file mode 100644
index 00000000000..4593b9c5fee
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_WIN_FONT_UNIQUE_NAME_LOOKUP_WIN_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_WIN_FONT_UNIQUE_NAME_LOOKUP_WIN_H_
+
+#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
+#include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
+
+namespace blink {
+
+class FontUniqueNameLookupWin : public FontUniqueNameLookup {
+ public:
+ FontUniqueNameLookupWin();
+ ~FontUniqueNameLookupWin() override;
+ sk_sp<SkTypeface> MatchUniqueName(const String& font_unique_name) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FontUniqueNameLookupWin);
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc b/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc
index b61d48f5046..788a86a8012 100644
--- a/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc
+++ b/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc
@@ -89,14 +89,6 @@ LayoutUnit MinimumValueForLength(const Length& length,
return LayoutUnit();
}
-LayoutUnit RoundedMinimumValueForLength(const Length& length,
- LayoutUnit maximum_value) {
- if (length.GetType() == kPercent)
- return static_cast<LayoutUnit>(
- round(maximum_value * length.Percent() / 100.0f));
- return MinimumValueForLength(length, maximum_value);
-}
-
LayoutUnit ValueForLength(const Length& length, LayoutUnit maximum_value) {
switch (length.GetType()) {
case kFixed:
diff --git a/chromium/third_party/blink/renderer/platform/geometry/length_functions.h b/chromium/third_party/blink/renderer/platform/geometry/length_functions.h
index 13219213844..e72752c14a4 100644
--- a/chromium/third_party/blink/renderer/platform/geometry/length_functions.h
+++ b/chromium/third_party/blink/renderer/platform/geometry/length_functions.h
@@ -40,8 +40,6 @@ PLATFORM_EXPORT int IntValueForLength(const Length&, int maximum_value);
PLATFORM_EXPORT float FloatValueForLength(const Length&, float maximum_value);
PLATFORM_EXPORT LayoutUnit MinimumValueForLength(const Length&,
LayoutUnit maximum_value);
-PLATFORM_EXPORT LayoutUnit
-RoundedMinimumValueForLength(const Length&, LayoutUnit maximum_value);
PLATFORM_EXPORT LayoutUnit ValueForLength(const Length&,
LayoutUnit maximum_value);
PLATFORM_EXPORT FloatSize FloatSizeForLengthSize(const LengthSize&,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/DEPS b/chromium/third_party/blink/renderer/platform/graphics/DEPS
index 4a56a8d8607..e3412554492 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/DEPS
+++ b/chromium/third_party/blink/renderer/platform/graphics/DEPS
@@ -8,6 +8,7 @@ include_rules = [
# Dependencies.
"+base/threading/sequenced_task_runner_handle.h",
"+base/threading/thread_restrictions.h",
+ "+base/barrier_closure.h",
"+cc",
"+components/viz/client",
"+components/viz/common",
@@ -21,6 +22,7 @@ include_rules = [
"+gpu/ipc/common/mailbox.mojom-blink.h",
"+media/base/media_switches.h",
"+media/base/video_frame.h",
+ "+media/base/video_types.h",
"+media/renderers/video_resource_updater.h",
"+services/viz/public/interfaces",
"+services/ws/public/cpp/gpu/context_provider_command_buffer.h",
diff --git a/chromium/third_party/blink/renderer/platform/graphics/OWNERS b/chromium/third_party/blink/renderer/platform/graphics/OWNERS
index 78c0ada3f1e..28d1c1091e5 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/graphics/OWNERS
@@ -19,3 +19,11 @@ mcasas@chromium.org
# TEAM: paint-dev@chromium.org
# COMPONENT: Blink>Paint
+
+# Video SurfaceLayer functionality.
+per-file video_frame*=file://media/OWNERS
+per-file video_frame*=mlamouri@chromium.org
+per-file video_frame*=lethalantidote@chromium.org
+per-file surface_layer_bridge*=file://media/OWNERS
+per-file surface_layer_bridge*=mlamouri@chromium.org
+per-file surface_layer_bridge*=lethalantidote@chromium.org
diff --git a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
index 3214da58c82..851be76f139 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -289,9 +289,5 @@ bool AcceleratedStaticBitmapImage::CurrentFrameKnownToBeOpaque() {
return texture_holder_->CurrentFrameKnownToBeOpaque();
}
-void AcceleratedStaticBitmapImage::Abandon() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- texture_holder_->Abandon();
-}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
index fa769532993..7fc90d2a08f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
@@ -88,8 +88,6 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
PaintImage PaintImageForCurrentFrame() override;
- void Abandon() final;
-
TextureHolder* TextureHolderForTesting() { return texture_holder_.get(); }
private:
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h
index a8d19eda503..a35b7834192 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h
@@ -15,7 +15,7 @@ class PLATFORM_EXPORT AnimationWorkletMutator : public GarbageCollectedMixin {
public:
virtual ~AnimationWorkletMutator() = default;
- virtual int GetScopeId() const = 0;
+ virtual int GetWorkletId() const = 0;
// Runs the animation frame callback.
virtual std::unique_ptr<AnimationWorkletOutput> Mutate(
std::unique_ptr<AnimationWorkletInput>) = 0;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h
index 441c38143e5..a7db4f11508 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h
@@ -15,7 +15,11 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcher {
virtual ~AnimationWorkletMutatorDispatcher() = default;
// Run the animation frame callbacks from all connected AnimationWorklets.
- virtual void Mutate(std::unique_ptr<AnimationWorkletDispatcherInput>) = 0;
+ virtual void MutateSynchronously(
+ std::unique_ptr<AnimationWorkletDispatcherInput>) = 0;
+ virtual void MutateAsynchronously(
+ std::unique_ptr<AnimationWorkletDispatcherInput>) = 0;
+
// Returns true if Mutate may do something if called 'now'.
virtual bool HasMutators() = 0;
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
index 5fb4c57c500..a76626e1f0c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
+
+#include "base/barrier_closure.h"
#include "base/metrics/histogram_macros.h"
#include "base/timer/elapsed_timer.h"
#include "third_party/blink/public/platform/platform.h"
@@ -17,10 +19,39 @@
namespace blink {
+namespace {
+
+int next_async_mutation_id = 0;
+int GetNextAsyncMutationId() {
+ return next_async_mutation_id++;
+}
+
+} // end namespace
+
+// Wrap output vector in a thread safe and ref-counted object since it is
+// accessed from animation worklet threads and its lifetime must be guaranteed
+// to outlive the mutation update cycle.
+class AnimationWorkletMutatorDispatcherImpl::OutputVectorRef
+ : public ThreadSafeRefCounted<OutputVectorRef> {
+ public:
+ static scoped_refptr<OutputVectorRef> Create() {
+ return base::AdoptRef(new OutputVectorRef());
+ }
+ Vector<std::unique_ptr<AnimationWorkletDispatcherOutput>>& get() {
+ return vector_;
+ }
+
+ private:
+ OutputVectorRef() = default;
+ Vector<std::unique_ptr<AnimationWorkletDispatcherOutput>> vector_;
+};
+
AnimationWorkletMutatorDispatcherImpl::AnimationWorkletMutatorDispatcherImpl(
bool main_thread_task_runner)
- : client_(nullptr), weak_factory_(this) {
- // By default layout tests run without threaded compositing. See
+ : client_(nullptr),
+ outputs_(OutputVectorRef::Create()),
+ weak_factory_(this) {
+ // By default web tests run without threaded compositing. See
// https://crbug.com/770028 For these situations we run on the Main thread.
host_queue_ = main_thread_task_runner || !Thread::CompositorThread()
? Thread::MainThread()->GetTaskRunner()
@@ -62,63 +93,85 @@ AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient(
return CreateClient<MainThreadMutatorClient>(weak_interface, queue, true);
}
-void AnimationWorkletMutatorDispatcherImpl::Mutate(
+void AnimationWorkletMutatorDispatcherImpl::MutateSynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput> mutator_input) {
TRACE_EVENT0("cc", "AnimationWorkletMutatorDispatcherImpl::mutate");
- if (mutator_map_.IsEmpty())
+ if (mutator_map_.IsEmpty() || !mutator_input)
return;
base::ElapsedTimer timer;
DCHECK(client_);
+ DCHECK(host_queue_->BelongsToCurrentThread());
+ DCHECK(mutator_input_map_.IsEmpty());
+ DCHECK(outputs_->get().IsEmpty());
- Vector<std::unique_ptr<AnimationWorkletDispatcherOutput>> outputs(
- mutator_map_.size());
- Vector<WaitableEvent> done_events(mutator_map_.size());
+ mutator_input_map_ = CreateInputMap(*mutator_input);
+ if (mutator_input_map_.IsEmpty())
+ return;
- int index = 0;
- for (auto& pair : mutator_map_) {
- AnimationWorkletMutator* mutator = pair.key;
- scoped_refptr<base::SingleThreadTaskRunner> worklet_queue = pair.value;
+ WaitableEvent event;
+ WTF::CrossThreadClosure on_done = CrossThreadBind(
+ &WaitableEvent::Signal, WTF::CrossThreadUnretained(&event));
+ RequestMutations(std::move(on_done));
+ event.Wait();
- std::unique_ptr<AnimationWorkletInput> input =
- mutator_input->TakeWorkletState(mutator->GetScopeId());
+ ApplyMutationsOnHostThread();
- DCHECK(!worklet_queue->BelongsToCurrentThread());
- std::unique_ptr<AutoSignal> done =
- std::make_unique<AutoSignal>(&done_events[index]);
- std::unique_ptr<AnimationWorkletDispatcherOutput>& output = outputs[index];
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ "Animation.AnimationWorklet.Dispatcher.SynchronousMutateDuration",
+ timer.Elapsed(), base::TimeDelta::FromMicroseconds(1),
+ base::TimeDelta::FromMilliseconds(100), 50);
+}
- if (input) {
- PostCrossThreadTask(
- *worklet_queue, FROM_HERE,
- CrossThreadBind(
- [](AnimationWorkletMutator* mutator,
- std::unique_ptr<AnimationWorkletInput> input,
- std::unique_ptr<AutoSignal> completion,
- std::unique_ptr<AnimationWorkletDispatcherOutput>* output) {
- *output = mutator->Mutate(std::move(input));
- },
- WrapCrossThreadWeakPersistent(mutator),
- WTF::Passed(std::move(input)), WTF::Passed(std::move(done)),
- CrossThreadUnretained(&output)));
- }
- index++;
+void AnimationWorkletMutatorDispatcherImpl::MutateAsynchronously(
+ std::unique_ptr<AnimationWorkletDispatcherInput> mutator_input) {
+ if (mutator_map_.IsEmpty() || !mutator_input)
+ return;
+ DCHECK(client_);
+ DCHECK(host_queue_->BelongsToCurrentThread());
+ if (!mutator_input_map_.IsEmpty()) {
+ // Still running mutations from a previous frame. Skip this frame to avoid
+ // lagging behind.
+ // TODO(kevers): Consider queuing pending mutation cycle. A pending tree
+ // mutation should likely be queued an active tree mutation cycle is still
+ // running.
+ return;
}
- for (WaitableEvent& event : done_events) {
- event.Wait();
- }
+ mutator_input_map_ = CreateInputMap(*mutator_input);
+ if (mutator_input_map_.IsEmpty())
+ return;
- for (auto& output : outputs) {
- // Animator that has no input does not produce any output.
- if (!output)
- continue;
- client_->SetMutationUpdate(std::move(output));
- }
+ int next_async_mutation_id = GetNextAsyncMutationId();
+ TRACE_EVENT_ASYNC_BEGIN0("cc",
+ "AnimationWorkletMutatorDispatcherImpl::MutateAsync",
+ next_async_mutation_id);
- UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
- "Animation.AnimationWorklet.Dispatcher.SynchronousMutateDuration",
- timer.Elapsed(), base::TimeDelta::FromMicroseconds(1),
- base::TimeDelta::FromMilliseconds(100), 50);
+ WTF::CrossThreadClosure on_done = CrossThreadBind(
+ [](scoped_refptr<base::SingleThreadTaskRunner> host_queue,
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> dispatcher,
+ int next_async_mutation_id) {
+ PostCrossThreadTask(
+ *host_queue, FROM_HERE,
+ CrossThreadBind(
+ &AnimationWorkletMutatorDispatcherImpl::AsyncMutationsDone,
+ dispatcher, next_async_mutation_id));
+ },
+ host_queue_, weak_factory_.GetWeakPtr(), next_async_mutation_id);
+
+ client_->NotifyAnimationsPending();
+ RequestMutations(std::move(on_done));
+}
+
+void AnimationWorkletMutatorDispatcherImpl::AsyncMutationsDone(
+ int async_mutation_id) {
+ DCHECK(client_);
+ DCHECK(host_queue_->BelongsToCurrentThread());
+ ApplyMutationsOnHostThread();
+ client_->NotifyAnimationsReady();
+ TRACE_EVENT_ASYNC_END0("cc",
+ "AnimationWorkletMutatorDispatcherImpl::MutateAsync",
+ async_mutation_id);
+ // TODO(kevers): Add UMA metric to track the asynchronous mutate duration.
}
void AnimationWorkletMutatorDispatcherImpl::RegisterAnimationWorkletMutator(
@@ -145,18 +198,86 @@ void AnimationWorkletMutatorDispatcherImpl::UnregisterAnimationWorkletMutator(
mutator_map_.erase(mutator);
}
+void AnimationWorkletMutatorDispatcherImpl::SynchronizeAnimatorName(
+ const String& animator_name) {
+ client_->SynchronizeAnimatorName(animator_name);
+}
+
bool AnimationWorkletMutatorDispatcherImpl::HasMutators() {
return !mutator_map_.IsEmpty();
}
-AnimationWorkletMutatorDispatcherImpl::AutoSignal::AutoSignal(
- WaitableEvent* event)
- : event_(event) {
- DCHECK(event);
+AnimationWorkletMutatorDispatcherImpl::InputMap
+AnimationWorkletMutatorDispatcherImpl::CreateInputMap(
+ AnimationWorkletDispatcherInput& mutator_input) const {
+ InputMap input_map;
+ for (const auto& pair : mutator_map_) {
+ AnimationWorkletMutator* mutator = pair.key;
+ const int worklet_id = mutator->GetWorkletId();
+ std::unique_ptr<AnimationWorkletInput> input =
+ mutator_input.TakeWorkletState(worklet_id);
+ if (input) {
+ input_map.insert(worklet_id, std::move(input));
+ }
+ }
+ return input_map;
+}
+
+void AnimationWorkletMutatorDispatcherImpl::RequestMutations(
+ WTF::CrossThreadClosure done_callback) {
+ DCHECK(client_);
+ DCHECK(outputs_->get().IsEmpty());
+
+ int num_requests = mutator_map_.size();
+ int next_request_index = 0;
+ outputs_->get().Grow(num_requests);
+ base::RepeatingClosure on_mutator_done = base::BarrierClosure(
+ num_requests, ConvertToBaseCallback(std::move(done_callback)));
+
+ for (const auto& pair : mutator_map_) {
+ AnimationWorkletMutator* mutator = pair.key;
+ scoped_refptr<base::SingleThreadTaskRunner> worklet_queue = pair.value;
+ int worklet_id = mutator->GetWorkletId();
+ DCHECK(!worklet_queue->BelongsToCurrentThread());
+ auto it = mutator_input_map_.find(worklet_id);
+ if (it == mutator_input_map_.end()) {
+ // No input to process.
+ on_mutator_done.Run();
+ continue;
+ }
+ PostCrossThreadTask(
+ *worklet_queue, FROM_HERE,
+ CrossThreadBind(
+ [](AnimationWorkletMutator* mutator,
+ std::unique_ptr<AnimationWorkletInput> input,
+ scoped_refptr<OutputVectorRef> outputs, int index,
+ WTF::CrossThreadClosure on_mutator_done) {
+ std::unique_ptr<AnimationWorkletOutput> output =
+ mutator ? mutator->Mutate(std::move(input)) : nullptr;
+ outputs->get()[index] = std::move(output);
+ on_mutator_done.Run();
+ },
+ // The mutator is created and destroyed on the worklet thread.
+ WrapCrossThreadWeakPersistent(mutator),
+ // The worklet input is not required after the Mutate call.
+ WTF::Passed(std::move(it->value)),
+ // The vector of outputs is wrapped in a scoped_refptr initialized
+ // on the host thread. It can outlive the dispatcher during shutdown
+ // of a process with a running animation.
+ outputs_, next_request_index++,
+ WTF::Passed(WTF::CrossThreadClosure(on_mutator_done))));
+ }
}
-AnimationWorkletMutatorDispatcherImpl::AutoSignal::~AutoSignal() {
- event_->Signal();
+void AnimationWorkletMutatorDispatcherImpl::ApplyMutationsOnHostThread() {
+ DCHECK(client_);
+ DCHECK(host_queue_->BelongsToCurrentThread());
+ for (auto& output : outputs_->get()) {
+ if (output)
+ client_->SetMutationUpdate(std::move(output));
+ }
+ mutator_input_map_.clear();
+ outputs_->get().clear();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
index 27509cdea3e..4aa67917413 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
@@ -16,13 +16,14 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
namespace blink {
class CompositorMutatorClient;
class MainThreadMutatorClient;
-class WaitableEvent;
// Fans out requests to all of the registered AnimationWorkletMutators which can
// then run worklet animations to produce mutation updates. Requests for
@@ -47,7 +48,12 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
~AnimationWorkletMutatorDispatcherImpl() override;
// AnimationWorkletMutatorDispatcher implementation.
- void Mutate(std::unique_ptr<AnimationWorkletDispatcherInput>) override;
+ void MutateSynchronously(
+ std::unique_ptr<AnimationWorkletDispatcherInput>) override;
+
+ void MutateAsynchronously(
+ std::unique_ptr<AnimationWorkletDispatcherInput>) override;
+
// TODO(majidvp): Remove when timeline inputs are known.
bool HasMutators() override;
@@ -62,21 +68,29 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
void SetClient(MutatorClient* client) { client_ = client; }
+ void SynchronizeAnimatorName(const String& animator_name);
+
+ MutatorClient* client() { return client_; }
+
private:
+ class OutputVectorRef;
+
+ using InputMap = HashMap<int, std::unique_ptr<AnimationWorkletInput>>;
+
using AnimationWorkletMutatorToTaskRunnerMap =
HashMap<CrossThreadPersistent<AnimationWorkletMutator>,
scoped_refptr<base::SingleThreadTaskRunner>>;
- class AutoSignal {
- public:
- explicit AutoSignal(WaitableEvent*);
- ~AutoSignal();
+ InputMap CreateInputMap(AnimationWorkletDispatcherInput& mutator_input) const;
- private:
- WaitableEvent* event_;
+ // Dispatches mutation update requests. The callback is triggered once
+ // all mutation updates have been computed on the animation worklet thread
+ // associated with the last mutation to complete.
+ void RequestMutations(WTF::CrossThreadClosure done_callback);
- DISALLOW_COPY_AND_ASSIGN(AutoSignal);
- };
+ void AsyncMutationsDone(int async_mutation_id);
+
+ void ApplyMutationsOnHostThread();
// The AnimationWorkletProxyClients are also owned by the WorkerClients
// dictionary.
@@ -98,6 +112,21 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
// valid as long as this class exists.
MutatorClient* client_;
+ // Map of mutator scope IDs to mutator input. The Mutate methods safeguards
+ // against concurrent calls (important once async mutations are introduced) by
+ // checking that the map has been reset on entry. For this reason, it is
+ // important to reset the map at the end of the mutation cycle.
+ InputMap mutator_input_map_;
+
+ // Reference to a vector for collecting mutation output. The vector is
+ // accessed across threads, thus it must be guaranteed to persist until the
+ // last mutation update is complete, and updates must be done in a thread-safe
+ // manner. The Mutate method guards against concurrent calls (important once
+ // async mutations are introduced) by checking that the output vector is
+ // empty. For this reason, it is important to clear the output at the end of
+ // the mutation cycle.
+ scoped_refptr<OutputVectorRef> outputs_;
+
base::WeakPtrFactory<AnimationWorkletMutatorDispatcherImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AnimationWorkletMutatorDispatcherImpl);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
index 383fe843619..87b8dcd769c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
@@ -9,18 +9,24 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_thread_type.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h"
#include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+#include "third_party/blink/renderer/platform/waitable_event.h"
#include <memory>
using ::testing::_;
+using ::testing::AtLeast;
using ::testing::Mock;
-using ::testing::StrictMock;
using ::testing::Return;
+using ::testing::Sequence;
+using ::testing::StrictMock;
using ::testing::Truly;
// This test uses actual threads since mutator logic requires it. This means we
@@ -52,7 +58,7 @@ class MockAnimationWorkletMutator
return std::unique_ptr<AnimationWorkletOutput>(MutateRef(*input));
}
- MOCK_CONST_METHOD0(GetScopeId, int());
+ MOCK_CONST_METHOD0(GetWorkletId, int());
MOCK_METHOD1(MutateRef,
AnimationWorkletOutput*(const AnimationWorkletInput&));
@@ -63,7 +69,7 @@ class MockCompositorMutatorClient : public CompositorMutatorClient {
public:
MockCompositorMutatorClient(
std::unique_ptr<AnimationWorkletMutatorDispatcherImpl> mutator)
- : CompositorMutatorClient(std::move(mutator)) {}
+ : CompositorMutatorClient(std::move(mutator)), done_event_(nullptr) {}
~MockCompositorMutatorClient() override {}
// gmock cannot mock methods with move-only args so we forward it to ourself.
void SetMutationUpdate(
@@ -71,8 +77,26 @@ class MockCompositorMutatorClient : public CompositorMutatorClient {
SetMutationUpdateRef(output_state.get());
}
+ MOCK_METHOD0(NotifyAnimationsPending, void());
+
+ void NotifyAnimationsReady() override {
+ NotifyAnimationsReadyRef();
+ if (done_event_) {
+ done_event_->Signal();
+ }
+ }
+
+ MOCK_METHOD0(NotifyAnimationsReadyRef, void());
+
+ void SignalWhenComplete(WaitableEvent* done_event) {
+ done_event_ = done_event;
+ }
+
MOCK_METHOD1(SetMutationUpdateRef,
void(cc::MutatorOutputState* output_state));
+
+ private:
+ WaitableEvent* done_event_; // not owned.
};
class AnimationWorkletMutatorDispatcherImplTest : public ::testing::Test {
@@ -116,32 +140,35 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
RegisteredAnimatorShouldOnlyReceiveInputForItself) {
std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
MockAnimationWorkletMutator* first_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
mutator_->RegisterAnimationWorkletMutator(first_mutator,
first_thread->GetTaskRunner());
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11));
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
EXPECT_CALL(*first_mutator, MutateRef(Truly(OnlyIncludesAnimation1)))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
-
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
}
TEST_F(AnimationWorkletMutatorDispatcherImplTest,
RegisteredAnimatorShouldNotBeMutatedWhenNoInput) {
std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
MockAnimationWorkletMutator* first_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
mutator_->RegisterAnimationWorkletMutator(first_mutator,
first_thread->GetTaskRunner());
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11));
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0);
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
@@ -151,7 +178,7 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
auto input = std::make_unique<AnimationWorkletDispatcherInput>();
input->Add(std::move(state2));
- mutator_->Mutate(std::move(input));
+ mutator_->MutateSynchronously(std::move(input));
}
TEST_F(AnimationWorkletMutatorDispatcherImplTest,
@@ -159,7 +186,7 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
std::unique_ptr<AnimationWorkletDispatcherInput> input =
std::make_unique<AnimationWorkletDispatcherInput>();
- mutator_->Mutate(std::move(input));
+ mutator_->MutateSynchronously(std::move(input));
}
TEST_F(AnimationWorkletMutatorDispatcherImplTest,
@@ -167,15 +194,18 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
// Create a thread to run mutator tasks.
std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
MockAnimationWorkletMutator* first_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
mutator_->RegisterAnimationWorkletMutator(first_mutator,
first_thread->GetTaskRunner());
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11));
+
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
EXPECT_CALL(*first_mutator, MutateRef(_)).Times(1).WillOnce(Return(nullptr));
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
}
TEST_F(AnimationWorkletMutatorDispatcherImplTest,
@@ -183,17 +213,20 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
// Create a thread to run mutator tasks.
std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
MockAnimationWorkletMutator* first_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
mutator_->RegisterAnimationWorkletMutator(first_mutator,
first_thread->GetTaskRunner());
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11));
+
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
EXPECT_CALL(*first_mutator, MutateRef(_))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
// The above call blocks on mutator threads running their tasks so we can
// safely verify here.
@@ -201,10 +234,12 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
// Ensure mutator is not invoked after unregistration.
EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0);
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0);
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
+ EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(0);
mutator_->UnregisterAnimationWorkletMutator(first_mutator);
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
Mock::VerifyAndClearExpectations(client_.get());
}
@@ -212,10 +247,10 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread) {
std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
MockAnimationWorkletMutator* first_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
MockAnimationWorkletMutator* second_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
mutator_->RegisterAnimationWorkletMutator(first_mutator,
@@ -223,17 +258,20 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
mutator_->RegisterAnimationWorkletMutator(second_mutator,
first_thread->GetTaskRunner());
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11));
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
EXPECT_CALL(*first_mutator, MutateRef(_))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
- EXPECT_CALL(*second_mutator, GetScopeId()).Times(1).WillOnce(Return(22));
+ EXPECT_CALL(*second_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(22));
EXPECT_CALL(*second_mutator, MutateRef(_))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
-
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
}
TEST_F(
@@ -241,12 +279,12 @@ TEST_F(
MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads) {
std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
MockAnimationWorkletMutator* first_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
first_thread->GetTaskRunner());
std::unique_ptr<Thread> second_thread = CreateThread("SecondAnimationThread");
MockAnimationWorkletMutator* second_mutator =
- new ::testing::StrictMock<MockAnimationWorkletMutator>(
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
second_thread->GetTaskRunner());
mutator_->RegisterAnimationWorkletMutator(first_mutator,
@@ -254,35 +292,364 @@ TEST_F(
mutator_->RegisterAnimationWorkletMutator(second_mutator,
second_thread->GetTaskRunner());
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11));
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
EXPECT_CALL(*first_mutator, MutateRef(_))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
- EXPECT_CALL(*second_mutator, GetScopeId()).Times(1).WillOnce(Return(22));
+ EXPECT_CALL(*second_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(22));
EXPECT_CALL(*second_mutator, MutateRef(_))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
// The above call blocks on mutator threads running their tasks so we can
// safely verify here.
Mock::VerifyAndClearExpectations(client_.get());
- // Ensure mutator is not invoked after unregistration.
+ // Ensure first_mutator is not invoked after unregistration.
mutator_->UnregisterAnimationWorkletMutator(first_mutator);
- EXPECT_CALL(*first_mutator, GetScopeId()).Times(0);
+ EXPECT_CALL(*first_mutator, GetWorkletId()).Times(0);
EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0);
- EXPECT_CALL(*second_mutator, GetScopeId()).Times(1).WillOnce(Return(22));
+ EXPECT_CALL(*second_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(22));
EXPECT_CALL(*second_mutator, MutateRef(_))
.Times(1)
.WillOnce(Return(new AnimationWorkletOutput()));
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
- mutator_->Mutate(CreateTestMutatorInput());
+ mutator_->MutateSynchronously(CreateTestMutatorInput());
+
Mock::VerifyAndClearExpectations(client_.get());
}
+// -----------------------------------------------------------------------
+// Asynchronous version of tests.
+
+// Callback wrapping portion of the async test that is required to run on the
+// compositor thread.
+using MutateAsyncCallback = WTF::CrossThreadFunction<void()>;
+
+using MutatorDispatcherRef =
+ scoped_refptr<AnimationWorkletMutatorDispatcherImpl>;
+
+class AnimationWorkletMutatorDispatcherImplAsyncTest
+ : public AnimationWorkletMutatorDispatcherImplTest {
+ public:
+ void SetUp() override {
+ if (!Thread::CompositorThread()) {
+ Thread::CreateAndSetCompositorThread();
+ }
+ AnimationWorkletMutatorDispatcherImplTest::SetUp();
+ }
+
+ // Call this version of mutate and wait if expecting a mutate completion
+ // notification from the client.
+ void CallMutateAndWaitForClientCompletion(
+ MutateAsyncCallback mutate_callback) {
+ WaitableEvent done_event;
+ client_->SignalWhenComplete(&done_event);
+ PostCrossThreadTask(*Thread::CompositorThread()->GetTaskRunner(), FROM_HERE,
+ std::move(mutate_callback));
+ done_event.Wait();
+ }
+
+ // Call this version of mutate and wait if there is no expectation of client
+ // notifications. There are no notificaitons if the mutate call is a no-op
+ // such as when there are no inputs.
+ void CallMutateAndWaitForCallbackCompletion(
+ MutateAsyncCallback mutate_callback) {
+ WaitableEvent done_event;
+ PostCrossThreadTask(
+ *Thread::CompositorThread()->GetTaskRunner(), FROM_HERE,
+ CrossThreadBind(
+ [](MutateAsyncCallback mutate_callback, WaitableEvent* done_event) {
+ mutate_callback.Run();
+ done_event->Signal();
+ },
+ WTF::Passed(std::move(mutate_callback)),
+ WTF::CrossThreadUnretained(&done_event)));
+ done_event.Wait();
+ }
+};
+
+TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
+ RegisteredAnimatorShouldOnlyReceiveInputForItself) {
+ std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
+ MockAnimationWorkletMutator* first_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](std::unique_ptr<Thread> first_thread,
+ MockAnimationWorkletMutator* first_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ first_mutator, first_thread->GetTaskRunner());
+ async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput());
+ },
+ WTF::Passed(std::move(first_thread)),
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ Sequence s;
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
+ EXPECT_CALL(*first_mutator, MutateRef(_))
+ .Times(1)
+ .WillOnce(Return(new AnimationWorkletOutput()));
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s);
+ CallMutateAndWaitForClientCompletion(std::move(mutate_callback));
+}
+
+TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
+ RegisteredAnimatorShouldNotBeMutatedWhenNoInput) {
+ std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
+ MockAnimationWorkletMutator* first_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](std::unique_ptr<Thread> first_thread,
+ MockAnimationWorkletMutator* first_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ first_mutator, first_thread->GetTaskRunner());
+
+ AnimationWorkletInput::AddAndUpdateState state2{
+ {22, 2}, "test2", 5000, nullptr, 1};
+
+ auto input = std::make_unique<AnimationWorkletDispatcherInput>();
+ input->Add(std::move(state2));
+
+ async_test->mutator_->MutateAsynchronously(std::move(input));
+ },
+ WTF::Passed(std::move(first_thread)),
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ // The start of the mutation process will be synchronous. If a pending
+ // notification is not received by the time the callback returns, it will not
+ // be triggered later.
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0);
+ CallMutateAndWaitForCallbackCompletion(std::move(mutate_callback));
+}
+
+TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
+ MutationUpdateIsNotInvokedWithNoRegisteredAnimators) {
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ std::unique_ptr<AnimationWorkletDispatcherInput> input =
+ std::make_unique<AnimationWorkletDispatcherInput>();
+ async_test->mutator_->MutateAsynchronously(std::move(input));
+ },
+ WTF::CrossThreadUnretained(this));
+
+ // The start of the mutation process will be synchronous. If a pending
+ // notification is not received by the time the callback returns, it will not
+ // be triggered later.
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0);
+ CallMutateAndWaitForCallbackCompletion(std::move(mutate_callback));
+}
+
+TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
+ MutationUpdateIsNotInvokedWithNullOutput) {
+ // Create a thread to run mutator tasks.
+ std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
+ MockAnimationWorkletMutator* first_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](std::unique_ptr<Thread> first_thread,
+ MockAnimationWorkletMutator* first_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ first_mutator, first_thread->GetTaskRunner());
+ async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput());
+ },
+ WTF::Passed(std::move(first_thread)),
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ Sequence s;
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
+ EXPECT_CALL(*first_mutator, MutateRef(_)).Times(1).WillOnce(Return(nullptr));
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
+ EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s);
+ CallMutateAndWaitForClientCompletion(std::move(mutate_callback));
+}
+
+TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
+ MutationUpdateIsInvokedCorrectlyWithSingleRegisteredAnimator) {
+ // Create a thread to run mutator tasks.
+ std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
+ MockAnimationWorkletMutator* first_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](std::unique_ptr<Thread> first_thread,
+ MockAnimationWorkletMutator* first_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ first_mutator, first_thread->GetTaskRunner());
+ async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput());
+ },
+ WTF::Passed(std::move(first_thread)),
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ Sequence s;
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
+ EXPECT_CALL(*first_mutator, MutateRef(_))
+ .Times(1)
+ .WillOnce(Return(new AnimationWorkletOutput()));
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s);
+ CallMutateAndWaitForClientCompletion(std::move(mutate_callback));
+
+ // Above call blocks until complete signal is received.
+ Mock::VerifyAndClearExpectations(client_.get());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback2 = CrossThreadBind(
+ [](MockAnimationWorkletMutator* first_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ // Ensure mutator is not invoked after unregistration.
+ async_test->mutator_->UnregisterAnimationWorkletMutator(first_mutator);
+ async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput());
+ },
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ // The start of the mutation process will be synchronous. If a pending
+ // notification is not received by the time the callback returns, it will not
+ // be triggered later.
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0);
+ CallMutateAndWaitForCallbackCompletion(std::move(mutate_callback2));
+ Mock::VerifyAndClearExpectations(client_.get());
+}
+
+TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
+ MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread) {
+ std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
+ MockAnimationWorkletMutator* first_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+ MockAnimationWorkletMutator* second_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](std::unique_ptr<Thread> first_thread,
+ MockAnimationWorkletMutator* first_mutator,
+ MockAnimationWorkletMutator* second_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ first_mutator, first_thread->GetTaskRunner());
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ second_mutator, first_thread->GetTaskRunner());
+ async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput());
+ },
+ WTF::Passed(std::move(first_thread)),
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WrapCrossThreadWeakPersistent(second_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ Sequence s;
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
+ EXPECT_CALL(*first_mutator, MutateRef(_))
+ .Times(1)
+ .WillOnce(Return(new AnimationWorkletOutput()));
+ EXPECT_CALL(*second_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(22));
+ EXPECT_CALL(*second_mutator, MutateRef(_))
+ .Times(1)
+ .WillOnce(Return(new AnimationWorkletOutput()));
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2).InSequence(s);
+ EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s);
+ CallMutateAndWaitForClientCompletion(std::move(mutate_callback));
+}
+
+TEST_F(
+ AnimationWorkletMutatorDispatcherImplAsyncTest,
+ MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads) {
+ std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
+ MockAnimationWorkletMutator* first_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ first_thread->GetTaskRunner());
+
+ std::unique_ptr<Thread> second_thread = CreateThread("SecondAnimationThread");
+ MockAnimationWorkletMutator* second_mutator =
+ MakeGarbageCollected<MockAnimationWorkletMutator>(
+ second_thread->GetTaskRunner());
+
+ // Call MutateAsynchronously from the compositor thread.
+ MutateAsyncCallback mutate_callback = CrossThreadBind(
+ [](std::unique_ptr<Thread> first_thread,
+ std::unique_ptr<Thread> second_thread,
+ MockAnimationWorkletMutator* first_mutator,
+ MockAnimationWorkletMutator* second_mutator,
+ AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) {
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ first_mutator, first_thread->GetTaskRunner());
+ async_test->mutator_->RegisterAnimationWorkletMutator(
+ second_mutator, second_thread->GetTaskRunner());
+ async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput());
+ },
+ WTF::Passed(std::move(first_thread)),
+ WTF::Passed(std::move(second_thread)),
+ WrapCrossThreadWeakPersistent(first_mutator),
+ WrapCrossThreadWeakPersistent(second_mutator),
+ WTF::CrossThreadUnretained(this));
+
+ Sequence s;
+ EXPECT_CALL(*first_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(11));
+ EXPECT_CALL(*first_mutator, MutateRef(_))
+ .Times(1)
+ .WillOnce(Return(new AnimationWorkletOutput()));
+ EXPECT_CALL(*second_mutator, GetWorkletId())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(22));
+ EXPECT_CALL(*second_mutator, MutateRef(_))
+ .Times(1)
+ .WillOnce(Return(new AnimationWorkletOutput()));
+ EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s);
+ EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2).InSequence(s);
+ EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s);
+ CallMutateAndWaitForClientCompletion(std::move(mutate_callback));
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc
index 0fdd3dd61b2..8a56e382d36 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc
@@ -99,7 +99,7 @@ void BitmapImage::NotifyMemoryChanged() {
size_t BitmapImage::TotalFrameBytes() {
if (cached_frame_)
- return Size().Area() * sizeof(ImageFrame::PixelData);
+ return static_cast<size_t>(Size().Area()) * sizeof(ImageFrame::PixelData);
return 0u;
}
@@ -182,8 +182,8 @@ Image::SizeAvailability BitmapImage::SetData(scoped_refptr<SharedBuffer> data,
// Return the image density in 0.01 "bits per pixel" rounded to the nearest
// integer.
-static inline int ImageDensityInCentiBpp(IntSize size,
- size_t image_size_bytes) {
+static inline uint64_t ImageDensityInCentiBpp(IntSize size,
+ size_t image_size_bytes) {
uint64_t image_area = static_cast<uint64_t>(size.Width()) * size.Height();
return (static_cast<uint64_t>(image_size_bytes) * 100 * 8 + image_area / 2) /
image_area;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
index 3158dc5f284..965892c862e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
@@ -46,24 +46,27 @@ void BitmapImageMetrics::CountImageOrientation(
}
void BitmapImageMetrics::CountImageJpegDensity(int image_min_side,
- int64_t density_centi_bpp) {
+ uint64_t density_centi_bpp) {
// Values are reported in the range 0.01 to 10 bpp, in different metrics
// depending on the image category (small, medium, large).
if (image_min_side >= 1000) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, density_histogram,
("Blink.DecodedImage.JpegDensity.1000px", 1, 1000, 100));
- density_histogram.Count(density_centi_bpp);
+ density_histogram.Count(
+ base::saturated_cast<base::Histogram::Sample>(density_centi_bpp));
} else if (image_min_side >= 400) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, density_histogram,
("Blink.DecodedImage.JpegDensity.400px", 1, 1000, 100));
- density_histogram.Count(density_centi_bpp);
+ density_histogram.Count(
+ base::saturated_cast<base::Histogram::Sample>(density_centi_bpp));
} else if (image_min_side >= 100) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, density_histogram,
("Blink.DecodedImage.JpegDensity.100px", 1, 1000, 100));
- density_histogram.Count(density_centi_bpp);
+ density_histogram.Count(
+ base::saturated_cast<base::Histogram::Sample>(density_centi_bpp));
} else {
// We don't report for images with 0 to 99px on the smallest dimension.
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
index 3479690b4e5..ab67d76ca28 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
@@ -77,7 +77,7 @@ class PLATFORM_EXPORT BitmapImageMetrics {
// Report the JPEG compression density in 0.01 bits per pixel for an image
// with a smallest side (width or length) of |image_min_side|.
static void CountImageJpegDensity(int image_min_side,
- int64_t density_centi_bpp);
+ uint64_t density_centi_bpp);
static void CountImageGammaAndGamut(const skcms_ICCProfile*);
static void CountJpegArea(const IntSize& size);
static void CountJpegColorSpace(JpegColorSpace color_space);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc
index 616b61d76b9..618a32a8f91 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
#include "base/test/simple_test_tick_clock.h"
+#include "cc/paint/image_provider.h"
#include "cc/paint/skia_paint_canvas.h"
#include "cc/tiles/mipmap_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -233,7 +234,7 @@ class BitmapImageTest : public testing::Test {
protected:
void SetUp() override {
- image_observer_ = new FakeImageObserver;
+ image_observer_ = MakeGarbageCollected<FakeImageObserver>();
image_ = BitmapImage::Create(image_observer_.Get());
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index ca6a5261754..594dd36935a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -33,6 +33,7 @@
#include "cc/layers/texture_layer.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/graphics/canvas_heuristic_parameters.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
@@ -141,6 +142,9 @@ void Canvas2DLayerBridge::ResetResourceProvider() {
}
bool Canvas2DLayerBridge::ShouldAccelerate(AccelerationHint hint) const {
+ if (base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) {
+ return true;
+ }
bool accelerate;
if (software_rendering_while_hidden_) {
accelerate = false;
@@ -601,13 +605,12 @@ bool Canvas2DLayerBridge::PrepareTransferableResource(
return false;
scoped_refptr<CanvasResource> frame = ResourceProvider()->ProduceFrame();
- if (frame && frame->IsValid()) {
- // Note frame is kept alive via a reference kept in out_release_callback.
- bool success = frame->PrepareTransferableResource(
- out_resource, out_release_callback, kUnverifiedSyncToken);
- return success;
- }
- return false;
+ if (!frame || !frame->IsValid())
+ return false;
+
+ // Note frame is kept alive via a reference kept in out_release_callback.
+ return frame->PrepareTransferableResource(out_resource, out_release_callback,
+ kUnverifiedSyncToken);
}
cc::Layer* Canvas2DLayerBridge::Layer() {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
index 326c4f6727f..02c3c1c3528 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -193,7 +193,7 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient {
friend class Canvas2DLayerBridgeTest;
friend class CanvasRenderingContext2DTest;
- friend class HTMLCanvasPainterTestForSPv2;
+ friend class HTMLCanvasPainterTestForCAP;
AccelerationMode acceleration_mode_;
CanvasColorParams color_params_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
index e3079a828ba..cdcba06eaa4 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
@@ -140,24 +140,24 @@ sk_sp<SkColorSpace> CanvasColorParams::GetSkColorSpace() const {
sk_sp<SkColorSpace> CanvasColorParams::CanvasColorSpaceToSkColorSpace(
CanvasColorSpace color_space) {
- SkColorSpace::Gamut gamut = SkColorSpace::kSRGB_Gamut;
- SkColorSpace::RenderTargetGamma gamma = SkColorSpace::kSRGB_RenderTargetGamma;
+ skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB;
+ skcms_TransferFunction transferFn = SkNamedTransferFn::kSRGB;
switch (color_space) {
case kSRGBCanvasColorSpace:
break;
case kLinearRGBCanvasColorSpace:
- gamma = SkColorSpace::kLinear_RenderTargetGamma;
+ transferFn = SkNamedTransferFn::kLinear;
break;
case kRec2020CanvasColorSpace:
- gamut = SkColorSpace::kRec2020_Gamut;
- gamma = SkColorSpace::kLinear_RenderTargetGamma;
+ gamut = SkNamedGamut::kRec2020;
+ transferFn = SkNamedTransferFn::kLinear;
break;
case kP3CanvasColorSpace:
- gamut = SkColorSpace::kDCIP3_D65_Gamut;
- gamma = SkColorSpace::kLinear_RenderTargetGamma;
+ gamut = SkNamedGamut::kDCIP3;
+ transferFn = SkNamedTransferFn::kLinear;
break;
}
- return SkColorSpace::MakeRGB(gamma, gamut);
+ return SkColorSpace::MakeRGB(transferFn, gamut);
}
gfx::BufferFormat CanvasColorParams::GetBufferFormat() const {
@@ -240,14 +240,14 @@ CanvasColorParams::CanvasColorParams(const sk_sp<SkColorSpace> color_space,
color_space_ = kLinearRGBCanvasColorSpace;
} else if (SkColorSpace::Equals(
color_space.get(),
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kRec2020_Gamut)
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
+ SkNamedGamut::kRec2020)
.get())) {
color_space_ = kRec2020CanvasColorSpace;
} else if (SkColorSpace::Equals(
color_space.get(),
- SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut)
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
+ SkNamedGamut::kDCIP3)
.get())) {
color_space_ = kP3CanvasColorSpace;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 69d5a9a547f..46bb27f2346 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -82,12 +82,10 @@ static void ReleaseFrameResources(
const gpu::SyncToken& sync_token,
bool lost_resource) {
resource->WaitSyncToken(sync_token);
- if (lost_resource) {
+ if (lost_resource)
resource->Abandon();
- }
- if (resource_provider && !lost_resource && resource->IsRecycleable()) {
+ if (resource_provider && !lost_resource && resource->IsRecycleable())
resource_provider->RecycleResource(std::move(resource));
- }
}
bool CanvasResource::PrepareTransferableResource(
@@ -116,7 +114,8 @@ bool CanvasResource::PrepareAcceleratedTransferableResource(
// Gpu compositing is a prerequisite for compositing an accelerated resource
DCHECK(SharedGpuContext::IsGpuCompositingEnabled());
auto* gl = ContextGL();
- DCHECK(gl);
+ if (!gl)
+ return false;
const gpu::Mailbox& mailbox = GetOrCreateGpuMailbox(sync_mode);
if (mailbox.IsZero())
return false;
@@ -413,7 +412,6 @@ void CanvasResourceGpuMemoryBuffer::Abandon() {
const gpu::Mailbox& CanvasResourceGpuMemoryBuffer::GetOrCreateGpuMailbox(
MailboxSyncMode sync_mode) {
auto* gl = ContextGL();
- DCHECK(gl); // caller should already have early exited if !gl.
if (gpu_mailbox_.IsZero() && gl) {
gl->ProduceTextureDirectCHROMIUM(texture_id_, gpu_mailbox_.name);
mailbox_needs_new_sync_token_ = true;
@@ -431,16 +429,17 @@ GLuint CanvasResourceGpuMemoryBuffer::GetBackingTextureHandleForOverwrite() {
}
const gpu::SyncToken CanvasResourceGpuMemoryBuffer::GetSyncToken() {
- if (mailbox_needs_new_sync_token_) {
- auto* gl = ContextGL();
- DCHECK(gl); // caller should already have early exited if !gl.
- mailbox_needs_new_sync_token_ = false;
- if (mailbox_sync_mode_ == kVerifiedSyncToken) {
- gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
- } else {
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData());
- }
- }
+ if (!mailbox_needs_new_sync_token_)
+ return sync_token_;
+ auto* gl = ContextGL();
+ if (!gl)
+ return sync_token_;
+ mailbox_needs_new_sync_token_ = false;
+ if (mailbox_sync_mode_ == kVerifiedSyncToken)
+ gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
+ else
+ gl->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData());
+
return sync_token_;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
index d66820e97e0..75731e65285 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -60,7 +60,7 @@ CanvasResourceDispatcher::CanvasResourceDispatcher(
num_unreclaimed_frames_posted_(0),
client_(client),
enable_surface_synchronization_(
- features::IsSurfaceSynchronizationEnabled()),
+ ::features::IsSurfaceSynchronizationEnabled()),
weak_ptr_factory_(this) {
// Frameless canvas pass an invalid |frame_sink_id_|; don't create mojo
// channel for this special case.
@@ -75,8 +75,9 @@ CanvasResourceDispatcher::CanvasResourceDispatcher(
DCHECK(provider);
binding_.Bind(mojo::MakeRequest(&client_ptr_));
provider->CreateCompositorFrameSink(frame_sink_id_, std::move(client_ptr_),
- mojo::MakeRequest(&sink_),
- mojo::MakeRequest(&surface_embedder_));
+ mojo::MakeRequest(&sink_));
+ provider->ConnectToEmbedder(frame_sink_id_,
+ mojo::MakeRequest(&surface_embedder_));
}
CanvasResourceDispatcher::~CanvasResourceDispatcher() = default;
@@ -218,6 +219,8 @@ bool CanvasResourceDispatcher::PrepareFrame(
}
frame->metadata.begin_frame_ack = current_begin_frame_ack_;
+ frame->metadata.frame_token = ++next_frame_token_;
+
const gfx::Rect bounds(size_.Width(), size_.Height());
constexpr int kRenderPassId = 1;
constexpr bool is_clipped = false;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
index 299818c4434..cee6b36546f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
@@ -120,6 +120,8 @@ class PLATFORM_EXPORT CanvasResourceDispatcher
unsigned next_resource_id_ = 0;
ResourceMap resources_;
+ viz::FrameTokenGenerator next_frame_token_;
+
// The latest_unposted_resource_id_ always refers to the Id of the frame
// resource used by the latest_unposted_image_.
scoped_refptr<CanvasResource> latest_unposted_image_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index d04b01988af..e282da6a595 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "base/metrics/histogram_functions.h"
+#include "base/stl_util.h"
#include "cc/paint/decode_stashing_image_provider.h"
#include "cc/tiles/software_image_decode_cache.h"
#include "components/viz/common/resources/resource_format_utils.h"
@@ -435,53 +436,84 @@ class CanvasResourceProviderDirectGpuMemoryBuffer final
scoped_refptr<CanvasResource> resource_;
};
-enum CanvasResourceType {
- kDirectGpuMemoryBufferResourceType,
- kTextureGpuMemoryBufferResourceType,
- kBitmapGpuMemoryBufferResourceType,
- kSharedBitmapResourceType,
- kTextureResourceType,
- kBitmapResourceType,
-};
-
-constexpr CanvasResourceType kSoftwareCompositedFallbackList[] = {
- kBitmapGpuMemoryBufferResourceType,
- kSharedBitmapResourceType,
- // Fallback to no direct compositing support
- kBitmapResourceType,
-};
+namespace {
-constexpr CanvasResourceType kSoftwareFallbackList[] = {
- kBitmapResourceType,
+enum class CanvasResourceType {
+ kDirectGpuMemoryBuffer,
+ kTextureGpuMemoryBuffer,
+ kBitmapGpuMemoryBuffer,
+ kSharedBitmap,
+ kTexture,
+ kBitmap,
};
-constexpr CanvasResourceType kAcceleratedFallbackList[] = {
- kTextureResourceType,
- // Fallback to software
- kBitmapResourceType,
-};
+const std::vector<CanvasResourceType>& GetResourceTypeFallbackList(
+ CanvasResourceProvider::ResourceUsage usage) {
+ static const std::vector<CanvasResourceType> kSoftwareFallbackList({
+ CanvasResourceType::kBitmap,
+ });
+
+ static const std::vector<CanvasResourceType> kAcceleratedFallbackList({
+ CanvasResourceType::kTexture,
+ // Fallback to software
+ CanvasResourceType::kBitmap,
+ });
+
+ static const std::vector<CanvasResourceType> kSoftwareCompositedFallbackList({
+ CanvasResourceType::kBitmapGpuMemoryBuffer,
+ CanvasResourceType::kSharedBitmap,
+ // Fallback to no direct compositing support
+ CanvasResourceType::kBitmap,
+ });
+
+ static const std::vector<CanvasResourceType>
+ kAcceleratedCompositedFallbackList({
+ CanvasResourceType::kTextureGpuMemoryBuffer,
+ CanvasResourceType::kTexture,
+ // Fallback to software composited
+ // (|kSoftwareCompositedFallbackList|).
+ CanvasResourceType::kBitmapGpuMemoryBuffer,
+ CanvasResourceType::kSharedBitmap,
+ // Fallback to no direct compositing support
+ CanvasResourceType::kBitmap,
+ });
+ DCHECK(std::equal(kAcceleratedCompositedFallbackList.begin() + 2,
+ kAcceleratedCompositedFallbackList.end(),
+ kSoftwareCompositedFallbackList.begin(),
+ kSoftwareCompositedFallbackList.end()));
+
+ static const std::vector<CanvasResourceType> kAcceleratedDirectFallbackList({
+ CanvasResourceType::kDirectGpuMemoryBuffer,
+ // The rest is equal to |kAcceleratedCompositedFallbackList|.
+ CanvasResourceType::kTextureGpuMemoryBuffer,
+ CanvasResourceType::kTexture,
+ // Fallback to software composited
+ CanvasResourceType::kBitmapGpuMemoryBuffer,
+ CanvasResourceType::kSharedBitmap,
+ // Fallback to no direct compositing support
+ CanvasResourceType::kBitmap,
+ });
+ DCHECK(std::equal(kAcceleratedDirectFallbackList.begin() + 1,
+ kAcceleratedDirectFallbackList.end(),
+ kAcceleratedCompositedFallbackList.begin(),
+ kAcceleratedCompositedFallbackList.end()));
-constexpr CanvasResourceType kAcceleratedCompositedFallbackList[] = {
- kTextureGpuMemoryBufferResourceType,
- kTextureResourceType,
- // Fallback to software composited
- kBitmapGpuMemoryBufferResourceType,
- kSharedBitmapResourceType,
- // Fallback to no direct compositing support
- kBitmapResourceType,
-};
+ switch (usage) {
+ case CanvasResourceProvider::kSoftwareResourceUsage:
+ return kSoftwareFallbackList;
+ case CanvasResourceProvider::kSoftwareCompositedResourceUsage:
+ return kSoftwareCompositedFallbackList;
+ case CanvasResourceProvider::kAcceleratedResourceUsage:
+ return kAcceleratedFallbackList;
+ case CanvasResourceProvider::kAcceleratedCompositedResourceUsage:
+ return kAcceleratedCompositedFallbackList;
+ case CanvasResourceProvider::kAcceleratedDirectResourceUsage:
+ return kAcceleratedDirectFallbackList;
+ }
+ NOTREACHED();
+}
-constexpr CanvasResourceType kAcceleratedDirectFallbackList[] = {
- kDirectGpuMemoryBufferResourceType,
- // The rest is equal to |kAcceleratedCompositedFallbackList|.
- kTextureGpuMemoryBufferResourceType,
- kTextureResourceType,
- // Fallback to software composited
- kBitmapGpuMemoryBufferResourceType,
- kSharedBitmapResourceType,
- // Fallback to no direct compositing support
- kBitmapResourceType,
-};
+} // unnamed namespace
std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create(
const IntSize& size,
@@ -492,41 +524,17 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create(
PresentationMode presentation_mode,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
bool is_origin_top_left) {
- const CanvasResourceType* resource_type_fallback_list = nullptr;
- size_t list_length = 0;
-
- switch (usage) {
- case kSoftwareResourceUsage:
- resource_type_fallback_list = kSoftwareFallbackList;
- list_length = arraysize(kSoftwareFallbackList);
- break;
- case kSoftwareCompositedResourceUsage:
- resource_type_fallback_list = kSoftwareCompositedFallbackList;
- list_length = arraysize(kSoftwareCompositedFallbackList);
- break;
- case kAcceleratedResourceUsage:
- resource_type_fallback_list = kAcceleratedFallbackList;
- list_length = arraysize(kAcceleratedFallbackList);
- break;
- case kAcceleratedCompositedResourceUsage:
- resource_type_fallback_list = kAcceleratedCompositedFallbackList;
- list_length = arraysize(kAcceleratedCompositedFallbackList);
- break;
- case kAcceleratedDirectResourceUsage:
- resource_type_fallback_list = kAcceleratedDirectFallbackList;
- list_length = arraysize(kAcceleratedDirectFallbackList);
- break;
- }
-
std::unique_ptr<CanvasResourceProvider> provider;
- for (size_t i = 0; i < list_length; ++i) {
+ const std::vector<CanvasResourceType>& fallback_list =
+ GetResourceTypeFallbackList(usage);
+ for (CanvasResourceType resource_type : fallback_list) {
// Note: We are deliberately not using std::move() on
// |context_provider_wrapper| and |resource_dispatcher| to ensure that the
// pointers remain valid for the next iteration of this loop if necessary.
- switch (resource_type_fallback_list[i]) {
- case kTextureGpuMemoryBufferResourceType:
+ switch (resource_type) {
+ case CanvasResourceType::kTextureGpuMemoryBuffer:
FALLTHROUGH;
- case kDirectGpuMemoryBufferResourceType:
+ case CanvasResourceType::kDirectGpuMemoryBuffer:
if (!SharedGpuContext::IsGpuCompositingEnabled())
continue;
if (presentation_mode != kAllowImageChromiumPresentationMode)
@@ -546,8 +554,7 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create(
DCHECK_EQ(color_params.GLUnsizedInternalFormat(),
gpu::InternalFormatForGpuMemoryBufferFormat(
color_params.GetBufferFormat()));
- if (resource_type_fallback_list[i] ==
- kDirectGpuMemoryBufferResourceType) {
+ if (resource_type == CanvasResourceType::kDirectGpuMemoryBuffer) {
provider =
std::make_unique<CanvasResourceProviderDirectGpuMemoryBuffer>(
size, msaa_sample_count, color_params,
@@ -561,7 +568,7 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create(
is_origin_top_left);
}
break;
- case kBitmapGpuMemoryBufferResourceType:
+ case CanvasResourceType::kBitmapGpuMemoryBuffer:
if (!SharedGpuContext::IsGpuCompositingEnabled())
continue;
if (presentation_mode != kAllowImageChromiumPresentationMode)
@@ -579,20 +586,20 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create(
size, color_params, context_provider_wrapper,
resource_dispatcher);
break;
- case kSharedBitmapResourceType:
+ case CanvasResourceType::kSharedBitmap:
if (!resource_dispatcher)
continue;
provider = std::make_unique<CanvasResourceProviderSharedBitmap>(
size, color_params, resource_dispatcher);
break;
- case kTextureResourceType:
+ case CanvasResourceType::kTexture:
if (!context_provider_wrapper)
continue;
provider = std::make_unique<CanvasResourceProviderTexture>(
size, msaa_sample_count, color_params, context_provider_wrapper,
resource_dispatcher, is_origin_top_left);
break;
- case kBitmapResourceType:
+ case CanvasResourceType::kBitmap:
provider = std::make_unique<CanvasResourceProviderBitmap>(
size, color_params, context_provider_wrapper, resource_dispatcher);
break;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
index 25fdcaa6f59..9fa1a526ebe 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
@@ -77,12 +77,12 @@ ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
if (conversion == kColorSpaceConversion_LinearRGB)
return SkColorSpace::MakeSRGBLinear();
if (conversion == kColorSpaceConversion_P3) {
- return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
+ SkNamedGamut::kDCIP3);
}
if (conversion == kColorSpaceConversion_Rec2020) {
- return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kRec2020_Gamut);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
+ SkNamedGamut::kRec2020);
}
return nullptr;
}
@@ -286,9 +286,12 @@ bool ColorCorrectionTestUtils::MatchSkImages(sk_sp<SkImage> src_image,
return false;
// Color type is not checked since the decoded image does not have a specific
// color type, unless it is drawn onto a surface or readPixels() is called.
- if (!MatchColorSpace(src_image->refColorSpace(),
- dst_image->refColorSpace())) {
- return false;
+ // Only compare color spaces if both are non-null
+ if (src_image->refColorSpace() && dst_image->refColorSpace()) {
+ if (!MatchColorSpace(src_image->refColorSpace(),
+ dst_image->refColorSpace())) {
+ return false;
+ }
}
bool test_passed = true;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
index 4ce10d0025a..f052b58fdd8 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
@@ -73,6 +73,9 @@ class ColorCorrectionTestUtils {
static bool MatchColorSpace(sk_sp<SkColorSpace> src_color_space,
sk_sp<SkColorSpace> dst_color_space);
+ // Compares size, colorspace and pixel values of two images
+ // If the colorspace of either image is null the colorspaces are assumed
+ // to be equal
static bool MatchSkImages(sk_sp<SkImage> src_image,
sk_sp<SkImage> dst_image,
unsigned uint8_tolerance,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md b/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md
index 274707ffec5..f8334d739ce 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md
@@ -5,7 +5,7 @@ This directory contains the implementation of the "Blink compositing algorithm".
This code is owned by the [paint team][paint-team-site].
[paint-team-site]: https://www.chromium.org/teams/paint-team
-This document explains the SPv2 world as it develops, not the SPv1 world it
+This document explains the CAP world as it develops, not the SPv1 world it
replaces.
## Blink compositing algorithm
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
index a1b314914fd..c9c643ff9ef 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
@@ -37,7 +37,8 @@ class ChunkToLayerMapperTest : public testing::Test {
e0(), EffectPaintPropertyNode::State{
layer_transform_.get(), layer_clip_.get(),
kColorFilterLuminanceToAlpha, CompositorFilterOperations(),
- 0.789f, CompositorFilterOperations(), SkBlendMode::kSrcIn});
+ 0.789f, CompositorFilterOperations(), gfx::RectF(),
+ SkBlendMode::kSrcIn});
}
return PropertyTreeState(layer_transform_.get(), layer_clip_.get(),
layer_effect_.get());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
index 374222bd712..dc6ed8d6271 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
@@ -32,7 +32,9 @@ ContentLayerClientImpl::ContentLayerClientImpl()
cc_picture_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
}
-ContentLayerClientImpl::~ContentLayerClientImpl() = default;
+ContentLayerClientImpl::~ContentLayerClientImpl() {
+ cc_picture_layer_->ClearClient();
+}
static int GetTransformId(const TransformPaintPropertyNode* transform,
ContentLayerClientImpl::LayerAsJSONContext& context) {
@@ -84,7 +86,7 @@ static int GetTransformId(const TransformPaintPropertyNode* transform,
return transform_id;
}
-// This is the SPv2 version of GraphicsLayer::LayerAsJSONInternal().
+// This is the CAP version of GraphicsLayer::LayerAsJSONInternal().
std::unique_ptr<JSONObject> ContentLayerClientImpl::LayerAsJSON(
LayerAsJSONContext& context) const {
std::unique_ptr<JSONObject> json = JSONObject::Create();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 43aeb50ebdd..4d20e8dc113 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -10,6 +10,7 @@
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/paint/display_item_list.h"
+#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h"
@@ -67,8 +68,9 @@ PaintArtifactCompositor::PaintArtifactCompositor(
base::RepeatingCallback<void(const gfx::ScrollOffset&,
const cc::ElementId&)> scroll_callback)
: scroll_callback_(std::move(scroll_callback)),
- tracks_raster_invalidations_(false) {
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+ tracks_raster_invalidations_(false),
+ needs_update_(true) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
return;
root_layer_ = cc::Layer::Create();
@@ -86,6 +88,8 @@ PaintArtifactCompositor::~PaintArtifactCompositor() {
}
void PaintArtifactCompositor::EnableExtraDataForTesting() {
+ if (!extra_data_for_testing_enabled_)
+ SetNeedsUpdate(true);
extra_data_for_testing_enabled_ = true;
extra_data_for_testing_ = std::make_unique<ExtraDataForTesting>();
}
@@ -205,7 +209,7 @@ PaintArtifactCompositor::ScrollHitTestLayerForPendingLayer(
// match (see: crbug.com/753124).
auto bounds = scroll_node.ContainerRect().Size();
// Mark the layer as scrollable.
- // TODO(pdr): When SPV2 launches this parameter for bounds will not be needed.
+ // TODO(pdr): When CAP launches this parameter for bounds will not be needed.
scroll_layer->SetScrollable(static_cast<gfx::Size>(bounds));
// Set the layer's bounds equal to the container because the scroll layer
// does not scroll.
@@ -412,11 +416,13 @@ static bool CanUpcastTo(const PropertyTreeState& guest,
guest.Transform()->IsBackfaceHidden())
return false;
- auto* home_clip = home.Clip()->Unalias();
- for (const ClipPaintPropertyNode* current_clip = guest.Clip()->Unalias();
+ // TODO(crbug.com/923729): Note that SafeUnalias() is a speculative fix for
+ // the referenced bug. The home and guest Clips should always exist, so we can
+ // just call Unalias on them.
+ auto* home_clip = SafeUnalias(home.Clip());
+ for (const ClipPaintPropertyNode* current_clip = SafeUnalias(guest.Clip());
current_clip != home_clip;
- current_clip = current_clip->Parent() ? current_clip->Parent()->Unalias()
- : nullptr) {
+ current_clip = SafeUnalias(current_clip->Parent())) {
if (!current_clip || current_clip->HasDirectCompositingReasons())
return false;
if (!IsNonCompositingAncestorOf(
@@ -518,6 +524,7 @@ static bool SkipGroupIfEffectivelyInvisible(
void PaintArtifactCompositor::LayerizeGroup(
const PaintArtifact& paint_artifact,
+ const Settings& settings,
Vector<PendingLayer>& pending_layers,
const EffectPaintPropertyNode& current_group,
Vector<PaintChunk>::const_iterator& chunk_it) {
@@ -578,8 +585,8 @@ void PaintArtifactCompositor::LayerizeGroup(
// Case C: The following chunks belong to a subgroup. Process them by
// a recursion call.
wtf_size_t first_layer_in_subgroup = pending_layers.size();
- LayerizeGroup(paint_artifact, pending_layers, *unaliased_subgroup,
- chunk_it);
+ LayerizeGroup(paint_artifact, settings, pending_layers,
+ *unaliased_subgroup, chunk_it);
// Now the chunk iterator stepped over the subgroup we just saw.
// If the subgroup generated 2 or more layers then the subgroup must be
// composited to satisfy grouping requirement.
@@ -624,11 +631,12 @@ void PaintArtifactCompositor::LayerizeGroup(
void PaintArtifactCompositor::CollectPendingLayers(
const PaintArtifact& paint_artifact,
+ const Settings& settings,
Vector<PendingLayer>& pending_layers) {
Vector<PaintChunk>::const_iterator cursor =
paint_artifact.PaintChunks().begin();
- LayerizeGroup(paint_artifact, pending_layers, EffectPaintPropertyNode::Root(),
- cursor);
+ LayerizeGroup(paint_artifact, settings, pending_layers,
+ EffectPaintPropertyNode::Root(), cursor);
DCHECK_EQ(paint_artifact.PaintChunks().end(), cursor);
}
@@ -651,6 +659,7 @@ class SynthesizedClip : private cc::ContentLayerClient {
CompositorElementIdFromUniqueObjectId(NewUniqueObjectId());
layer_->SetIsDrawable(true);
}
+ ~SynthesizedClip() override { layer_->ClearClient(); }
void Update(const FloatRoundedRect& rrect,
scoped_refptr<const RefCountedPath> path) {
@@ -749,10 +758,32 @@ cc::Layer* PaintArtifactCompositor::CreateOrReuseSynthesizedClipLayer(
return synthesized_clip.GetLayer();
}
+static void UpdateCompositorViewportProperties(
+ const PaintArtifactCompositor::ViewportProperties& properties,
+ PropertyTreeManager& property_tree_manager,
+ cc::LayerTreeHost* layer_tree_host) {
+ cc::LayerTreeHost::ViewportPropertyIds ids;
+ // This is also needed by pre-CompositeAfterPaint, so is not guarded by
+ // CompositeAfterPaintEnabled().
+ if (properties.page_scale) {
+ ids.page_scale_transform =
+ property_tree_manager.EnsureCompositorPageScaleTransformNode(
+ properties.page_scale);
+ }
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ if (properties.inner_scroll_translation) {
+ ids.inner_scroll = property_tree_manager.EnsureCompositorScrollNode(
+ properties.inner_scroll_translation);
+ }
+ layer_tree_host->RegisterViewportPropertyIds(ids);
+ }
+}
+
void PaintArtifactCompositor::Update(
scoped_refptr<const PaintArtifact> paint_artifact,
CompositorElementIdSet& composited_element_ids,
- TransformPaintPropertyNode* viewport_scale_node) {
+ const ViewportProperties& viewport_properties,
+ const Settings& settings) {
DCHECK(root_layer_);
// The tree will be null after detaching and this update can be ignored.
@@ -761,6 +792,11 @@ void PaintArtifactCompositor::Update(
if (!host)
return;
+ // Skip updating property trees, pushing cc::Layers, and issuing raster
+ // invalidations if possible.
+ if (!NeedsUpdate())
+ return;
+
// When using BlinkGenPropertyTrees, the compositor accepts a list of layers
// and property trees instead of building property trees. This DCHECK ensures
// we have not forgotten to set |use_layer_lists|.
@@ -778,16 +814,10 @@ void PaintArtifactCompositor::Update(
PropertyTreeManager property_tree_manager(
*this, *host->property_trees(), root_layer_.get(), &layer_list_builder);
Vector<PendingLayer, 0> pending_layers;
- CollectPendingLayers(*paint_artifact, pending_layers);
+ CollectPendingLayers(*paint_artifact, settings, pending_layers);
- cc::LayerTreeHost::ViewportPropertyIds viewport_property_ids;
- if (viewport_scale_node) {
- viewport_property_ids.page_scale_transform =
- property_tree_manager.EnsureCompositorPageScaleTransformNode(
- viewport_scale_node);
- }
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
- host->RegisterViewportPropertyIds(viewport_property_ids);
+ UpdateCompositorViewportProperties(viewport_properties, property_tree_manager,
+ host);
Vector<std::unique_ptr<ContentLayerClientImpl>> new_content_layer_clients;
new_content_layer_clients.ReserveCapacity(pending_layers.size());
@@ -796,6 +826,8 @@ void PaintArtifactCompositor::Update(
for (auto& entry : synthesized_clip_cache_)
entry.in_use = false;
+ // Clear prior frame ids before inserting new ones.
+ composited_element_ids.clear();
for (auto& pending_layer : pending_layers) {
const auto& property_state = pending_layer.property_tree_state;
const auto* transform = property_state.Transform();
@@ -817,9 +849,9 @@ void PaintArtifactCompositor::Update(
paint_artifact, pending_layer, layer_offset, new_content_layer_clients,
new_scroll_hit_test_layers);
- // Pre-SPV2, touch action rects are updated through
+ // Pre-CompositeAfterPaint, touch action rects are updated through
// ScrollingCoordinator::UpdateLayerTouchActionRects.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
auto paint_chunks = paint_artifact->GetPaintChunkSubset(
pending_layer.paint_chunk_indices);
UpdateTouchActionRects(layer.get(), layer_offset, property_state,
@@ -866,8 +898,10 @@ void PaintArtifactCompositor::Update(
// Calling |PropertyTreeStateChanged| for every pending layer is
// O(|property nodes|^2) and could be optimized by caching the lookup of
// nodes known to be changed/unchanged.
- if (PropertyTreeStateChanged(property_state))
+ if (PropertyTreeStateChanged(property_state)) {
layer->SetSubtreePropertyChanged();
+ root_layer_->SetNeedsCommit();
+ }
}
property_tree_manager.Finalize();
content_layer_clients_.swap(new_content_layer_clients);
@@ -885,15 +919,21 @@ void PaintArtifactCompositor::Update(
}
}
- root_layer_->SetChildLayerList(layer_list_builder.Finalize());
+ // This should be done before UpdateRenderSurfaceForEffects() for which to
+ // get property tree node ids from the layers.
+ host->property_trees()->sequence_number = g_s_property_tree_sequence_number;
+
+ auto layers = layer_list_builder.Finalize();
+ UpdateRenderSurfaceForEffects(*host, layers);
+ root_layer_->SetChildLayerList(std::move(layers));
// Update the host's active registered element ids.
host->SetActiveRegisteredElementIds(composited_element_ids);
// Mark the property trees as having been rebuilt.
- host->property_trees()->sequence_number = g_s_property_tree_sequence_number;
host->property_trees()->needs_rebuild = false;
host->property_trees()->ResetCachedData();
+ SetNeedsUpdate(false);
g_s_property_tree_sequence_number++;
@@ -912,6 +952,33 @@ void PaintArtifactCompositor::Update(
#endif
}
+// Every effect is supposed to have render surface enabled for grouping, but we
+// can omit one if the effect is opacity-only, render surface is not forced,
+// and the effect has only one compositing child. This is both for optimization
+// and not introducing sub-pixel differences in web tests.
+// TODO(crbug.com/504464): There is ongoing work in cc to delay render surface
+// decision until later phase of the pipeline. Remove premature optimization
+// here once the work is ready.
+void PaintArtifactCompositor::UpdateRenderSurfaceForEffects(
+ cc::LayerTreeHost& host,
+ const cc::LayerList& layers) {
+ HashSet<int> pending_render_surfaces;
+ auto& effect_tree = host.property_trees()->effect_tree;
+ for (const auto& layer : layers) {
+ for (auto* effect = effect_tree.Node(layer->effect_tree_index());
+ !effect->has_render_surface;
+ effect = effect_tree.Node(effect->parent_id)) {
+ if (effect->opacity != 1.f &&
+ !pending_render_surfaces.insert(effect->id).is_new_entry) {
+ // The opacity-only effect is seen the second time, which means that it
+ // has more than one compositing child and needs a render surface.
+ effect->has_render_surface = true;
+ break;
+ }
+ }
+ }
+}
+
void LayerListBuilder::Add(scoped_refptr<cc::Layer> layer) {
DCHECK(list_valid_);
list_.push_back(layer);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index 1b04c0b9d04..26a8f15ebe3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -21,6 +21,7 @@
namespace cc {
struct ElementId;
class Layer;
+class LayerTreeHost;
}
namespace gfx {
@@ -53,7 +54,7 @@ class LayerListBuilder {
// changes in the paint artifact.
//
// PaintArtifactCompositor is the successor to PaintLayerCompositor, reflecting
-// the new home of compositing decisions after paint in Slimming Paint v2.
+// the new home of compositing decisions after paint with CompositeAfterPaint.
class PLATFORM_EXPORT PaintArtifactCompositor final
: private PropertyTreeManagerClient {
USING_FAST_MALLOC(PaintArtifactCompositor);
@@ -68,13 +69,25 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
new PaintArtifactCompositor(std::move(scroll_callback)));
}
+ struct ViewportProperties {
+ const TransformPaintPropertyNode* page_scale = nullptr;
+ const TransformPaintPropertyNode* inner_scroll_translation = nullptr;
+ // TODO(crbug.com/909750): Add other viewport properties, e.g.
+ // outer_scroll_translation.
+ };
+
+ struct Settings {
+ bool prefer_compositing_to_lcd_text = false;
+ };
+
// Updates the layer tree to match the provided paint artifact.
//
// Populates |composited_element_ids| with the CompositorElementId of all
// animations for which we saw a paint chunk and created a layer.
void Update(scoped_refptr<const PaintArtifact>,
CompositorElementIdSet& composited_element_ids,
- TransformPaintPropertyNode* viewport_scale_node);
+ const ViewportProperties& viewport_properties,
+ const Settings& settings);
// The root layer of the tree managed by this object.
cc::Layer* RootLayer() const { return root_layer_.get(); }
@@ -119,6 +132,9 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
const PropertyTreeState& layer_state,
const PaintChunkSubset& paint_chunks);
+ void SetNeedsUpdate(bool needs_update) { needs_update_ = needs_update; }
+ bool NeedsUpdate() const { return needs_update_; }
+
private:
// A pending layer is a collection of paint chunks that will end up in
// the same cc::Layer.
@@ -153,7 +169,9 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
// Collects the PaintChunks into groups which will end up in the same
// cc layer. This is the entry point of the layerization algorithm.
void CollectPendingLayers(const PaintArtifact&,
+ const Settings& settings,
Vector<PendingLayer>& pending_layers);
+
// This is the internal recursion of collectPendingLayers. This function
// loops over the list of paint chunks, scoped by an isolated group
// (i.e. effect node). Inside of the loop, chunks are tested for overlap
@@ -172,6 +190,7 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
// overlap with other chunks in the parent group, if grouping requirement
// can be satisfied (and the effect node has no direct reason).
static void LayerizeGroup(const PaintArtifact&,
+ const Settings& settings,
Vector<PendingLayer>& pending_layers,
const EffectPaintPropertyNode&,
Vector<PaintChunk>::const_iterator& chunk_cursor);
@@ -222,11 +241,15 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
CompositorElementId& mask_isolation_id,
CompositorElementId& mask_effect_id) final;
+ static void UpdateRenderSurfaceForEffects(cc::LayerTreeHost&,
+ const cc::LayerList&);
+
// Provides a callback for notifying blink of composited scrolling.
base::RepeatingCallback<void(const gfx::ScrollOffset&, const cc::ElementId&)>
scroll_callback_;
bool tracks_raster_invalidations_;
+ bool needs_update_;
scoped_refptr<cc::Layer> root_layer_;
Vector<std::unique_ptr<ContentLayerClientImpl>> content_layer_clients_;
@@ -242,7 +265,7 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
bool extra_data_for_testing_enabled_ = false;
std::unique_ptr<ExtraDataForTesting> extra_data_for_testing_;
- friend class StubChromeClientForSPv2;
+ friend class StubChromeClientForCAP;
friend class PaintArtifactCompositorTest;
DISALLOW_COPY_AND_ASSIGN(PaintArtifactCompositor);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index 1855e61bdf5..a601fe254bc 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -24,6 +24,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h"
+#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
#include "third_party/blink/renderer/platform/testing/fake_display_item_client.h"
@@ -130,18 +131,17 @@ class PaintArtifactCompositorTest : public testing::Test,
Update(artifact, element_ids);
}
- void Update(scoped_refptr<const PaintArtifact> artifact,
- CompositorElementIdSet& element_ids) {
- // Pass nullptr for the visual viewport paint property nodes since we're
- // really just checking the internals of PaintArtifactCompositor.
- Update(artifact, element_ids, nullptr);
- }
+ using ViewportProperties = PaintArtifactCompositor::ViewportProperties;
+ using Settings = PaintArtifactCompositor::Settings;
- void Update(scoped_refptr<const PaintArtifact> artifact,
- CompositorElementIdSet& element_ids,
- TransformPaintPropertyNode* viewport_scale_transform_node) {
+ void Update(
+ scoped_refptr<const PaintArtifact> artifact,
+ CompositorElementIdSet& element_ids,
+ const ViewportProperties& viewport_properties = ViewportProperties(),
+ const Settings& settings = Settings()) {
+ paint_artifact_compositor_->SetNeedsUpdate(true);
paint_artifact_compositor_->Update(artifact, element_ids,
- viewport_scale_transform_node);
+ viewport_properties, settings);
layer_tree_->layer_tree_host()->LayoutAndUpdateLayers();
}
@@ -151,8 +151,8 @@ class PaintArtifactCompositorTest : public testing::Test,
cc::Layer* RootLayer() { return paint_artifact_compositor_->RootLayer(); }
- // SlimmingPaintV2 creates scroll hit test display items (which create scroll
- // hit test layers in PaintArtifactCompositor) whereas in
+ // CompositeAfterPaint creates scroll hit test display items (which create
+ // scroll hit test layers in PaintArtifactCompositor) whereas in
// BlinkGenPropertyTrees, scrollable foreign layers are created in
// ScrollingCoordinator and passed to PaintArtifactCompositor. This function
// is used to create a chunk representing the scrollable layer in either of
@@ -182,8 +182,8 @@ class PaintArtifactCompositorTest : public testing::Test,
.ScrollHitTest(scroll_offset);
}
- // Returns the |num|th scrollable layer. In SlimmingPaintV2, this will be a
- // scroll hit test layer, whereas in BlinkGenPropertyTrees this will be a
+ // Returns the |num|th scrollable layer. In CompositeAfterPaint, this will be
+ // a scroll hit test layer, whereas in BlinkGenPropertyTrees this will be a
// content layer.
cc::Layer* ScrollableLayerAt(size_t num) {
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
@@ -203,7 +203,7 @@ class PaintArtifactCompositorTest : public testing::Test,
.get();
}
- // Returns the |num|th non-scrollable layer. In SlimmingPaintV2, content
+ // Returns the |num|th non-scrollable layer. In CompositeAfterPaint, content
// layers are not scrollable so this is the |num|th content layer. In
// BlinkGenPropertyTrees, content layers are scrollable and non-scrollable, so
// this will return the |num|th content layer that is not scrollable.
@@ -3254,8 +3254,10 @@ TEST_P(PaintArtifactCompositorTest, CreatesViewportNodes) {
TransformPaintPropertyNode::Root(), std::move(transform_state));
TestPaintArtifact artifact;
+ ViewportProperties viewport_properties;
+ viewport_properties.page_scale = scale_transform_node.get();
CompositorElementIdSet element_ids;
- Update(artifact.Build(), element_ids, scale_transform_node.get());
+ Update(artifact.Build(), element_ids, viewport_properties);
cc::TransformTree& transform_tree = GetPropertyTrees().transform_tree;
cc::TransformNode* cc_transform_node = transform_tree.FindNodeFromElementId(
@@ -3267,4 +3269,169 @@ TEST_P(PaintArtifactCompositorTest, CreatesViewportNodes) {
EXPECT_TRUE(cc_transform_node->pre_local.IsIdentity());
}
+enum { kNoRenderSurface, kHasRenderSurface };
+
+#define EXPECT_OPACITY(effect_id, expected_opacity, expected_render_surface) \
+ do { \
+ const auto* effect = GetPropertyTrees().effect_tree.Node(effect_id); \
+ EXPECT_EQ(expected_opacity, effect->opacity); \
+ EXPECT_EQ(expected_render_surface == kHasRenderSurface, \
+ effect->has_render_surface); \
+ } while (false)
+
+TEST_P(PaintArtifactCompositorTest, OpacityRenderSurfaces) {
+ // e
+ // / | \
+ // a b c -- L4
+ // / \ / \ \
+ // aa ab L2 L3 ca (L = layer)
+ // | | |
+ // L0 L1 L5
+ auto e = CreateOpacityEffect(e0(), 0.1f);
+ auto a = CreateOpacityEffect(*e, 0.2f);
+ auto b =
+ CreateOpacityEffect(*e, 0.3f, CompositingReason::kActiveOpacityAnimation);
+ auto c =
+ CreateOpacityEffect(*e, 0.4f, CompositingReason::kActiveOpacityAnimation);
+ auto aa =
+ CreateOpacityEffect(*a, 0.5f, CompositingReason::kActiveOpacityAnimation);
+ auto ab =
+ CreateOpacityEffect(*a, 0.6f, CompositingReason::kActiveOpacityAnimation);
+ auto ca =
+ CreateOpacityEffect(*c, 0.7f, CompositingReason::kActiveOpacityAnimation);
+ auto t = CreateTransform(t0(), TransformationMatrix().Rotate(90),
+ FloatPoint3D(), CompositingReason::k3DTransform);
+
+ TestPaintArtifact artifact;
+ FloatRect r(150, 150, 100, 100);
+ artifact.Chunk(t0(), c0(), *aa).RectDrawing(r, Color::kWhite);
+ artifact.Chunk(t0(), c0(), *ab).RectDrawing(r, Color::kWhite);
+ artifact.Chunk(t0(), c0(), *b).RectDrawing(r, Color::kWhite);
+ artifact.Chunk(*t, c0(), *b).RectDrawing(r, Color::kWhite);
+ artifact.Chunk(t0(), c0(), *c).RectDrawing(r, Color::kWhite);
+ artifact.Chunk(t0(), c0(), *ca).RectDrawing(r, Color::kWhite);
+ Update(artifact.Build());
+ ASSERT_EQ(6u, ContentLayerCount());
+
+ int effect_ids[6];
+ for (size_t i = 0; i < ContentLayerCount(); i++)
+ effect_ids[i] = ContentLayerAt(i)->effect_tree_index();
+
+ // Effects of layer 0, 1, 5 each has one compositing layer, so don't have
+ // render surface.
+ EXPECT_OPACITY(effect_ids[0], 0.5f, kNoRenderSurface);
+ EXPECT_OPACITY(effect_ids[1], 0.6f, kNoRenderSurface);
+ EXPECT_OPACITY(effect_ids[5], 0.7f, kNoRenderSurface);
+
+ // Layer 2 and 3 have the same effect state. The effect has render surface
+ // because it has two compositing layers.
+ EXPECT_EQ(effect_ids[2], effect_ids[3]);
+ EXPECT_OPACITY(effect_ids[2], 0.3f, kHasRenderSurface);
+
+ // Effect |a| has two indirect compositing layers, so has render surface.
+ const auto& effect_tree = GetPropertyTrees().effect_tree;
+ int id_a = effect_tree.Node(effect_ids[0])->parent_id;
+ EXPECT_EQ(id_a, effect_tree.Node(effect_ids[1])->parent_id);
+ EXPECT_OPACITY(id_a, 0.2f, kHasRenderSurface);
+
+ // Effect |c| has one direct and one indirect compositing layers, so has
+ // render surface.
+ EXPECT_OPACITY(effect_ids[4], 0.4f, kHasRenderSurface);
+
+ // Though all children of effect |e| have render surfaces and |e| doesn't
+ // control any compositing layer, we still give it a render surface for
+ // simplicity of the algorithm.
+ EXPECT_OPACITY(effect_tree.Node(effect_ids[4])->parent_id, 0.1f,
+ kHasRenderSurface);
+}
+
+TEST_P(PaintArtifactCompositorTest, OpacityIndirectlyAffectingTwoLayers) {
+ auto opacity = CreateOpacityEffect(e0(), 0.5f);
+ auto child_composited_effect = CreateOpacityEffect(
+ *opacity, 1.f, CompositingReason::kActiveOpacityAnimation);
+ auto grandchild_composited_effect =
+ CreateOpacityEffect(*child_composited_effect, 1.f,
+ CompositingReason::kActiveOpacityAnimation);
+
+ TestPaintArtifact artifact;
+ artifact.Chunk(t0(), c0(), *child_composited_effect)
+ .RectDrawing(FloatRect(150, 150, 100, 100), Color::kWhite);
+ artifact.Chunk(t0(), c0(), *grandchild_composited_effect)
+ .RectDrawing(FloatRect(150, 150, 100, 100), Color::kGray);
+ Update(artifact.Build());
+ ASSERT_EQ(2u, ContentLayerCount());
+
+ const auto& effect_tree = GetPropertyTrees().effect_tree;
+ int layer0_effect_id = ContentLayerAt(0)->effect_tree_index();
+ EXPECT_OPACITY(layer0_effect_id, 1.f, kNoRenderSurface);
+ int layer1_effect_id = ContentLayerAt(1)->effect_tree_index();
+ EXPECT_OPACITY(layer1_effect_id, 1.f, kNoRenderSurface);
+ int opacity_id = effect_tree.Node(layer0_effect_id)->parent_id;
+ EXPECT_OPACITY(opacity_id, 0.5f, kHasRenderSurface);
+}
+
+TEST_P(PaintArtifactCompositorTest, Non2dAxisAlignedClip) {
+ auto rotate = CreateTransform(t0(), TransformationMatrix().Rotate(45));
+ auto clip = CreateClip(c0(), rotate.get(), FloatRoundedRect(50, 50, 50, 50));
+ auto opacity = CreateOpacityEffect(
+ e0(), 0.5f, CompositingReason::kActiveOpacityAnimation);
+
+ TestPaintArtifact artifact;
+ artifact.Chunk(t0(), *clip, *opacity)
+ .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite);
+ Update(artifact.Build());
+ ASSERT_EQ(1u, ContentLayerCount());
+
+ // We should create a synthetic effect node for the non-2d-axis-aligned clip.
+ int clip_id = ContentLayerAt(0)->clip_tree_index();
+ const auto* cc_clip = GetPropertyTrees().clip_tree.Node(clip_id);
+ int effect_id = ContentLayerAt(0)->effect_tree_index();
+ const auto* cc_effect = GetPropertyTrees().effect_tree.Node(effect_id);
+ EXPECT_OPACITY(effect_id, 1.f, kHasRenderSurface);
+ EXPECT_OPACITY(cc_effect->parent_id, 0.5f, kNoRenderSurface);
+ EXPECT_EQ(cc_effect->clip_id, cc_clip->parent_id);
+}
+
+TEST_P(PaintArtifactCompositorTest,
+ Non2dAxisAlignedClipUnderLaterRenderSurface) {
+ auto rotate1 =
+ CreateTransform(t0(), TransformationMatrix().Rotate(45), FloatPoint3D(),
+ CompositingReason::k3DTransform);
+ auto rotate2 =
+ CreateTransform(*rotate1, TransformationMatrix().Rotate(-45),
+ FloatPoint3D(), CompositingReason::k3DTransform);
+ auto clip = CreateClip(c0(), rotate2.get(), FloatRoundedRect(50, 50, 50, 50));
+ auto opacity =
+ CreateOpacityEffect(e0(), rotate1.get(), &c0(), 0.5f,
+ CompositingReason::kActiveOpacityAnimation);
+
+ // This assert ensures the test actually tests the situation. If it fails
+ // due to floating-point errors, we should choose other transformation values
+ // to make it succeed.
+ ASSERT_TRUE(
+ GeometryMapper::SourceToDestinationProjection(&t0(), rotate2.get())
+ .Preserves2dAxisAlignment());
+
+ TestPaintArtifact artifact;
+ artifact.Chunk(t0(), c0(), *opacity)
+ .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite);
+ artifact.Chunk(*rotate1, c0(), *opacity)
+ .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite);
+ artifact.Chunk(*rotate2, *clip, *opacity)
+ .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite);
+ Update(artifact.Build());
+ ASSERT_EQ(3u, ContentLayerCount());
+
+ // We should create a synthetic effect node for the non-2d-axis-aligned clip,
+ // though the accumulated transform to the known render surface was identity
+ // when the cc clip node was created.
+ int clip_id = ContentLayerAt(2)->clip_tree_index();
+ const auto* cc_clip = GetPropertyTrees().clip_tree.Node(clip_id);
+ int effect_id = ContentLayerAt(2)->effect_tree_index();
+ const auto* cc_effect = GetPropertyTrees().effect_tree.Node(effect_id);
+ EXPECT_OPACITY(effect_id, 1.f, kHasRenderSurface);
+ EXPECT_OPACITY(cc_effect->parent_id, 0.5f, kHasRenderSurface);
+ EXPECT_EQ(cc_effect->clip_id, cc_clip->parent_id);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
index c14f863846a..9982f86778c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
@@ -341,8 +341,8 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) {
#endif
// This bug is known to happen in SPv1 due to some clip-escaping corner
// cases that are very difficult to fix in legacy architecture.
- // In SPv2 this should never happen.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // In CAP this should never happen.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
NOTREACHED();
break;
}
@@ -515,9 +515,7 @@ void ConversionContext::StartEffect(const EffectPaintPropertyNode* effect) {
effect->GetColorFilter()));
save_layer_id = cc_list_.push<cc::SaveLayerOp>(nullptr, &flags);
} else {
- constexpr bool preserve_lcd_text_requests = false;
- save_layer_id = cc_list_.push<cc::SaveLayerAlphaOp>(
- nullptr, alpha, preserve_lcd_text_requests);
+ save_layer_id = cc_list_.push<cc::SaveLayerAlphaOp>(nullptr, alpha);
}
saved_count++;
} else {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index 6bfb15050c0..eeaae7ecc63 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -51,9 +51,9 @@ namespace blink {
namespace {
class PaintChunksToCcLayerTest : public testing::Test,
- private ScopedSlimmingPaintV2ForTest {
+ private ScopedCompositeAfterPaintForTest {
protected:
- PaintChunksToCcLayerTest() : ScopedSlimmingPaintV2ForTest(true) {}
+ PaintChunksToCcLayerTest() : ScopedCompositeAfterPaintForTest(true) {}
};
// Matches PaintOpTypes in a PaintRecord.
@@ -1190,7 +1190,7 @@ TEST_F(PaintChunksToCcLayerTest, StartWithAliasClip) {
// release builds. A DCHECK'd build will trap instead.
#if !DCHECK_IS_ON()
TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) {
- ScopedSlimmingPaintV2ForTest spv2_disabler(false);
+ ScopedCompositeAfterPaintForTest cap_disabler(false);
// This test verifies the fail-safe path correctly recovers from a malformed
// chunk that escaped its layer's clip.
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
@@ -1210,7 +1210,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) {
}
TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) {
- ScopedSlimmingPaintV2ForTest spv2_disabler(false);
+ ScopedCompositeAfterPaintForTest cap_disabler(false);
// This test verifies the fail-safe path correctly recovers from a malformed
// chunk that escaped its effect's clip.
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
@@ -1234,7 +1234,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) {
}
TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipDoubleFault) {
- ScopedSlimmingPaintV2ForTest spv2_disabler(false);
+ ScopedCompositeAfterPaintForTest cap_disabler(false);
// This test verifies the fail-safe path correctly recovers from a series of
// malformed chunks that escaped their layer's clip.
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 83635ef9c2a..c521cf05576 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -32,6 +32,12 @@ static constexpr int kSecondaryRootNodeId = 1;
} // namespace
+inline const TransformPaintPropertyNode*
+PropertyTreeManager::EffectState::Transform() const {
+ return effect_type == CcEffectType::kEffect ? effect->LocalTransformSpace()
+ : clip->LocalTransformSpace();
+}
+
PropertyTreeManager::PropertyTreeManager(PropertyTreeManagerClient& client,
cc::PropertyTrees& property_trees,
cc::Layer* root_layer,
@@ -154,26 +160,39 @@ void PropertyTreeManager::SetupRootScrollNode() {
root_layer_->SetScrollTreeIndex(scroll_node.id);
}
+static bool TransformsAre2dAxisAligned(const TransformPaintPropertyNode* a,
+ const TransformPaintPropertyNode* b) {
+ return a == b || GeometryMapper::SourceToDestinationProjection(a, b)
+ .Preserves2dAxisAlignment();
+}
+
void PropertyTreeManager::SetCurrentEffectState(
const cc::EffectNode& cc_effect_node,
CcEffectType effect_type,
const EffectPaintPropertyNode* effect,
const ClipPaintPropertyNode* clip) {
+ const auto* previous_transform =
+ effect->IsRoot() ? nullptr : current_.Transform();
current_.effect_id = cc_effect_node.id;
current_.effect_type = effect_type;
DCHECK(!effect->IsParentAlias() || !effect->Parent());
current_.effect = effect;
DCHECK(!clip->IsParentAlias() || !clip->Parent());
current_.clip = clip;
- if (cc_effect_node.has_render_surface)
- current_.render_surface_transform = effect->LocalTransformSpace();
+
+ if (cc_effect_node.has_render_surface) {
+ current_.may_be_2d_axis_misaligned_to_render_surface = false;
+ } else if (previous_transform &&
+ !current_.may_be_2d_axis_misaligned_to_render_surface) {
+ current_.may_be_2d_axis_misaligned_to_render_surface =
+ !TransformsAre2dAxisAligned(current_.Transform(), previous_transform);
+ }
}
// TODO(crbug.com/504464): Remove this when move render surface decision logic
// into cc compositor thread.
void PropertyTreeManager::SetCurrentEffectHasRenderSurface() {
GetEffectTree().Node(current_.effect_id)->has_render_surface = true;
- current_.render_surface_transform = current_.effect->LocalTransformSpace();
}
int PropertyTreeManager::EnsureCompositorTransformNode(
@@ -458,12 +477,6 @@ void PropertyTreeManager::CloseCcEffect() {
}
}
-static bool TransformsAre2dAxisAligned(const TransformPaintPropertyNode* a,
- const TransformPaintPropertyNode* b) {
- return a == b || GeometryMapper::SourceToDestinationProjection(a, b)
- .Preserves2dAxisAlignment();
-}
-
int PropertyTreeManager::SwitchToEffectNodeWithSynthesizedClip(
const EffectPaintPropertyNode& next_effect,
const ClipPaintPropertyNode& next_clip) {
@@ -519,9 +532,8 @@ int PropertyTreeManager::SwitchToEffectNodeWithSynthesizedClip(
while (current_.effect != &ancestor)
CloseCcEffect();
- bool newly_built = BuildEffectNodesRecursively(&next_effect);
- SynthesizeCcEffectsForClipsIfNeeded(&next_clip, SkBlendMode::kSrcOver,
- newly_built);
+ BuildEffectNodesRecursively(&next_effect);
+ SynthesizeCcEffectsForClipsIfNeeded(&next_clip, SkBlendMode::kSrcOver);
return current_.effect_id;
}
@@ -549,8 +561,9 @@ PropertyTreeManager::NeedsSyntheticEffect(
// Cc requires that a rectangluar clip is 2d-axis-aligned with the render
// surface to correctly apply the clip.
- if (!TransformsAre2dAxisAligned(clip.LocalTransformSpace(),
- current_.render_surface_transform))
+ if (current_.may_be_2d_axis_misaligned_to_render_surface ||
+ !TransformsAre2dAxisAligned(clip.LocalTransformSpace(),
+ current_.Transform()))
return CcEffectType::kSyntheticFor2dAxisAlignment;
return base::nullopt;
@@ -558,8 +571,7 @@ PropertyTreeManager::NeedsSyntheticEffect(
SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded(
const ClipPaintPropertyNode* target_clip,
- SkBlendMode delegated_blend,
- bool effect_is_newly_built) {
+ SkBlendMode delegated_blend) {
auto* unaliased_target_clip = target_clip->Unalias();
if (delegated_blend != SkBlendMode::kSrcOver) {
// Exit all synthetic effect node if the next child has exotic blending mode
@@ -585,16 +597,6 @@ SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded(
if (IsNodeOnAncestorChain(lca, *pre_exit_clip, *current_.clip))
break;
}
-
- // If the effect is an existing node, i.e. already has at least one paint
- // chunk or child effect, and by reaching here it implies we are going to
- // attach either another paint chunk or child effect to it. We can no longer
- // omit render surface for it even for opacity-only node.
- // See comments in PropertyTreeManager::BuildEffectNodesRecursively().
- // TODO(crbug.com/504464): Remove premature optimization here.
- if (!effect_is_newly_built && !IsCurrentCcEffectSynthetic() &&
- current_.effect->Opacity() != 1.f)
- SetCurrentEffectHasRenderSurface();
}
DCHECK(current_.clip->IsAncestorOf(*unaliased_target_clip));
@@ -649,21 +651,19 @@ SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded(
effect_stack_.emplace_back(current_);
SetCurrentEffectState(synthetic_effect, pending_clip.type, current_.effect,
pending_clip.clip);
- current_.render_surface_transform =
- pending_clip.clip->LocalTransformSpace();
}
return delegated_blend;
}
-bool PropertyTreeManager::BuildEffectNodesRecursively(
+void PropertyTreeManager::BuildEffectNodesRecursively(
const EffectPaintPropertyNode* next_effect) {
next_effect = SafeUnalias(next_effect);
if (next_effect == current_.effect)
- return false;
+ return;
DCHECK(next_effect);
- bool newly_built = BuildEffectNodesRecursively(next_effect->Parent());
+ BuildEffectNodesRecursively(next_effect->Parent());
DCHECK_EQ(next_effect->Parent()->Unalias(), current_.effect);
#if DCHECK_IS_ON()
@@ -678,16 +678,15 @@ bool PropertyTreeManager::BuildEffectNodesRecursively(
const auto* output_clip = SafeUnalias(next_effect->OutputClip());
if (output_clip) {
used_blend_mode = SynthesizeCcEffectsForClipsIfNeeded(
- output_clip, next_effect->BlendMode(), newly_built);
+ output_clip, next_effect->BlendMode());
output_clip_id = EnsureCompositorClipNode(output_clip);
} else {
while (IsCurrentCcEffectSynthetic())
CloseCcEffect();
// An effect node can't omit render surface if it has child with exotic
- // blending mode, nor being opacity-only node with more than one child.
+ // blending mode.
// TODO(crbug.com/504464): Remove premature optimization here.
- if (next_effect->BlendMode() != SkBlendMode::kSrcOver ||
- (!newly_built && current_.effect->Opacity() != 1.f))
+ if (next_effect->BlendMode() != SkBlendMode::kSrcOver)
SetCurrentEffectHasRenderSurface();
used_blend_mode = next_effect->BlendMode();
@@ -701,16 +700,10 @@ bool PropertyTreeManager::BuildEffectNodesRecursively(
effect_node.stable_id =
next_effect->GetCompositorElementId().GetInternalValue();
effect_node.clip_id = output_clip_id;
- // Every effect is supposed to have render surface enabled for grouping,
- // but we can get away without one if the effect is opacity-only and has only
- // one compositing child with kSrcOver blend mode. This is both for
- // optimization and not introducing sub-pixel differences in layout tests.
- // See PropertyTreeManager::switchToEffectNode() and above where we
- // retrospectively enable render surface when more than one compositing child
- // or a child with exotic blend mode is detected.
- // TODO(crbug.com/504464): There is ongoing work in cc to delay render surface
- // decision until later phase of the pipeline. Remove premature optimization
- // here once the work is ready.
+
+ // An effect with filters, backdrop filters or non-kSrcOver blend mode needs
+ // a render surface. The render surface status of opacity-only effects will be
+ // updated in PaintArtifactCompositor::UpdateRenderSurfaceForEffects().
if (!next_effect->Filter().IsEmpty() ||
!next_effect->BackdropFilter().IsEmpty() ||
used_blend_mode != SkBlendMode::kSrcOver)
@@ -730,6 +723,7 @@ bool PropertyTreeManager::BuildEffectNodesRecursively(
effect_node.filters = next_effect->Filter().AsCcFilterOperations();
effect_node.backdrop_filters =
next_effect->BackdropFilter().AsCcFilterOperations();
+ effect_node.backdrop_filter_bounds = next_effect->BackdropFilterBounds();
effect_node.filters_origin = next_effect->FiltersOrigin();
effect_node.transform_id =
EnsureCompositorTransformNode(next_effect->LocalTransformSpace());
@@ -749,8 +743,6 @@ bool PropertyTreeManager::BuildEffectNodesRecursively(
effect_stack_.emplace_back(current_);
SetCurrentEffectState(effect_node, CcEffectType::kEffect, next_effect,
output_clip);
-
- return true;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
index 1bab20eea08..231b0411e19 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -119,11 +119,10 @@ class PropertyTreeManager {
void Finalize();
private:
- bool BuildEffectNodesRecursively(const EffectPaintPropertyNode* next_effect);
+ void BuildEffectNodesRecursively(const EffectPaintPropertyNode* next_effect);
SkBlendMode SynthesizeCcEffectsForClipsIfNeeded(
const ClipPaintPropertyNode* target_clip,
- SkBlendMode delegated_blend,
- bool effect_is_newly_built);
+ SkBlendMode delegated_blend);
void EmitClipMaskLayer();
void CloseCcEffect();
@@ -192,19 +191,34 @@ class PropertyTreeManager {
// effect and clip state from the last
// SwitchToEffectNodeWithSynthesizedClip.
int effect_id;
+
CcEffectType effect_type;
+
// The effect state of the cc effect node.
const EffectPaintPropertyNode* effect;
+
// The clip state of the cc effect node. This value may be shallower than
// the one passed into SwitchToEffectNodeWithSynthesizedClip because not
- // every clip needs to be synthesized as cc effect.
- // Is set to output clip of the effect if the type is kEffect, or set to the
- // synthesized clip node if the type is kSyntheticForNonTrivialClip.
+ // every clip needs to be synthesized as cc effect. Is set to output clip of
+ // the effect if the type is kEffect, or set to the synthesized clip node.
const ClipPaintPropertyNode* clip;
- // The transform space of the containing render surface.
- // TODO(crbug.com/504464): Remove this when move render surface decision
- // logic into cc compositor thread.
- const TransformPaintPropertyNode* render_surface_transform;
+
+ // Whether the transform space of this state may be 2d axis misaligned to
+ // the containing render surface. As there may be new render surfaces
+ // created between this state and the current known ancestor render surface
+ // after this state is created, we must conservatively accumulate this flag
+ // from the known render surface instead of checking if the combined
+ // transform is 2d axis aligned, in case of:
+ // Effect1 (Current known render surface)
+ // Rotate(45deg)
+ // Effect2 (Not known now, but may become render surface later)
+ // Rotate(-45deg)
+ // Clip (Would be mistakenly treated as 2d axis aligned if we used
+ // accumulated transform from the clip to the known render surface.)
+ bool may_be_2d_axis_misaligned_to_render_surface;
+
+ // The transform space of the state.
+ const TransformPaintPropertyNode* Transform() const;
};
// The current effect state. Virtually it's the top of the effect stack if
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index a9d700afff1..39a0bcff494 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -135,8 +135,7 @@ class PLATFORM_EXPORT CompositingReason {
kTransformWithCompositedDescendants | kIsolateCompositedDescendants |
kOpacityWithCompositedDescendants | kMaskWithCompositedDescendants |
kFilterWithCompositedDescendants | kBlendingWithCompositedDescendants |
- kReflectionWithCompositedDescendants | kClipsCompositingDescendants |
- kPositionFixedOrStickyWithCompositedDescendants,
+ kReflectionWithCompositedDescendants | kClipsCompositingDescendants,
kCombo3DDescendants =
kPreserve3DWith3DDescendants | kPerspectiveWith3DDescendants,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc
index 434c15b3333..ea742ddd65e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc
@@ -26,7 +26,9 @@ CompositorMutatorClient::~CompositorMutatorClient() {
void CompositorMutatorClient::Mutate(
std::unique_ptr<cc::MutatorInputState> input_state) {
TRACE_EVENT0("cc", "CompositorMutatorClient::Mutate");
- mutator_->Mutate(std::move(input_state));
+ // TODO(http://crbug.com/791280): Switch to asynchronous once plumbing is
+ // complete.
+ mutator_->MutateSynchronously(std::move(input_state));
}
void CompositorMutatorClient::SetMutationUpdate(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h
index 8823cf44e02..b6fb0b07ccf 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h
@@ -21,7 +21,11 @@ class PLATFORM_EXPORT CompositorMutatorClient : public cc::LayerTreeMutator,
std::unique_ptr<AnimationWorkletMutatorDispatcherImpl>);
~CompositorMutatorClient() override;
+ void SynchronizeAnimatorName(const String& animator_name) override {}
void SetMutationUpdate(std::unique_ptr<cc::MutatorOutputState>) override;
+ // TODO(http://crbug.com/791280): Plumb notifications through to cc scheduler.
+ void NotifyAnimationsPending() override {}
+ void NotifyAnimationsReady() override {}
// cc::LayerTreeMutator
void SetClient(cc::LayerTreeMutatorClient*) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
index 45501625ff7..59c68f69182 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
@@ -63,7 +63,6 @@ void CrossfadeGeneratedImage::DrawCrossfade(cc::PaintCanvas* canvas,
PaintFlags image_flags(flags);
image_flags.setBlendMode(SkBlendMode::kSrcOver);
image_flags.setColor(ScaleAlpha(flags.getColor(), 1 - percentage_));
- image_flags.setAntiAlias(flags.isAntiAlias());
// TODO(junov): This code should probably be propagating the
// RespectImageOrientationEnum from CrossfadeGeneratedImage::draw(). Code was
// written this way during refactoring to avoid modifying existing behavior,
@@ -106,7 +105,6 @@ void CrossfadeGeneratedImage::DrawTile(GraphicsContext& context,
PaintFlags flags = context.FillFlags();
flags.setBlendMode(SkBlendMode::kSrcOver);
- flags.setAntiAlias(context.ShouldAntialias());
FloatRect dest_rect((FloatPoint()), crossfade_size_);
flags.setFilterQuality(
context.ComputeFilterQuality(this, dest_rect, src_rect));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc b/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc
index ca469f07a27..edb90d9d9fa 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc
@@ -91,7 +91,7 @@ void DrawLooperBuilder::AddShadow(const FloatSize& offset,
SkPaint* paint = sk_draw_looper_builder_.addLayerOnTop(info);
if (blur) {
- const SkScalar sigma = SkBlurRadiusToSigma(blur);
+ const auto sigma = BlurRadiusToStdDev(blur);
const bool respectCTM = shadow_transform_mode != kShadowIgnoresTransforms;
paint->setMaskFilter(
SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, respectCTM));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc
index af4e32d69d9..6a33e1fded7 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc
@@ -25,7 +25,10 @@
#include "third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.h"
#include <algorithm>
+
#include "SkTableColorFilter.h"
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
@@ -161,7 +164,7 @@ void FEComponentTransfer::GetValues(unsigned char r_values[256],
for (unsigned channel = 0; channel < 4; channel++) {
SECURITY_DCHECK(static_cast<size_t>(transfer_function[channel].type) <
- arraysize(call_effect));
+ base::size(call_effect));
(*call_effect[transfer_function[channel].type])(tables[channel],
transfer_function[channel]);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
index 2fdde120800..655e3765a3d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
@@ -31,7 +31,9 @@
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
#include <memory>
+
#include "base/memory/scoped_refptr.h"
+#include "base/stl_util.h"
#include "components/viz/common/resources/single_release_callback.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/test/test_gpu_memory_buffer_manager.h"
@@ -635,7 +637,7 @@ TEST(DrawingBufferDepthStencilTest, packedDepthStencilSupported) {
DepthStencilTestCase(true, true, 1, "both"),
};
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
SCOPED_TRACE(cases[i].test_case_name);
auto gl = std::make_unique<DepthStencilTrackingGLES2Interface>();
DepthStencilTrackingGLES2Interface* tracking_gl = gl.get();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index 10ff62ac177..1fc321b4251 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -155,8 +155,9 @@ bool ImageLayerBridge::PrepareTransferableResource(
*out_resource = viz::TransferableResource::MakeSoftware(
registered.bitmap->id(), size, resource_format);
if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
- out_resource->color_space =
- SkColorSpaceToGfxColorSpace(sk_image->refColorSpace());
+ out_resource->color_space = sk_image->colorSpace()
+ ? gfx::ColorSpace(*sk_image->colorSpace())
+ : gfx::ColorSpace::CreateSRGB();
}
auto func = WTF::Bind(&ImageLayerBridge::ResourceReleasedSoftware,
WrapWeakPersistent(this), std::move(registered));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
index 6ad59bb2a61..2cc0ad8cc63 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
@@ -2721,8 +2721,8 @@ GLenum WebGLImageConversion::ComputeImageSizeInBytes(
}
unsigned padding = 0;
- base::CheckedNumeric<uint32_t> checked_residual =
- checked_value % params.alignment;
+ base::CheckedNumeric<uint32_t> checked_residual = checked_value;
+ checked_residual %= static_cast<uint32_t>(params.alignment);
if (!checked_residual.IsValid()) {
return GL_INVALID_VALUE;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
index a0ace7b10a9..158ee960343 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
@@ -130,15 +130,20 @@ void XRFrameTransport::FrameSubmit(
// for some out-of-memory situations.
// TODO(billorr): Consider whether we should just drop the frame or exit
// presentation.
- if (gpu_memory_buffer) {
- // We decompose the cloned handle, and use it to create a
- // mojo::ScopedHandle which will own cleanup of the handle, and will be
- // passed over IPC.
- gfx::GpuMemoryBufferHandle gpu_handle = gpu_memory_buffer->CloneHandle();
- vr_presentation_provider->SubmitFrameWithTextureHandle(
- vr_frame_id,
- mojo::WrapPlatformFile(gpu_handle.dxgi_handle.GetHandle()));
+ if (!gpu_memory_buffer) {
+ FrameSubmitMissing(vr_presentation_provider, gl, vr_frame_id);
+ // We didn't actually submit anything, so don't set
+ // the waiting_for_previous_frame_transfer_ and related state.
+ return;
}
+
+ // We decompose the cloned handle, and use it to create a
+ // mojo::ScopedHandle which will own cleanup of the handle, and will be
+ // passed over IPC.
+ gfx::GpuMemoryBufferHandle gpu_handle = gpu_memory_buffer->CloneHandle();
+ vr_presentation_provider->SubmitFrameWithTextureHandle(
+ vr_frame_id,
+ mojo::WrapPlatformFile(gpu_handle.dxgi_handle.GetHandle()));
#else
NOTIMPLEMENTED();
#endif
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc
index ab0754787ba..d866b64127c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc
@@ -42,8 +42,7 @@ scoped_refptr<XRWebGLDrawingBuffer> XRWebGLDrawingBuffer::Create(
bool want_alpha_channel,
bool want_depth_buffer,
bool want_stencil_buffer,
- bool want_antialiasing,
- bool want_multiview) {
+ bool want_antialiasing) {
DCHECK(drawing_buffer);
// Don't proceeed if the context is already lost.
@@ -83,16 +82,11 @@ scoped_refptr<XRWebGLDrawingBuffer> XRWebGLDrawingBuffer::Create(
if (discard_framebuffer_supported)
extensions_util->EnsureExtensionEnabled("GL_EXT_discard_framebuffer");
- // TODO(bajones): Support multiview.
- bool multiview_supported = false;
-
scoped_refptr<XRWebGLDrawingBuffer> xr_drawing_buffer =
base::AdoptRef(new XRWebGLDrawingBuffer(
drawing_buffer, framebuffer, discard_framebuffer_supported,
- want_alpha_channel, want_depth_buffer, want_stencil_buffer,
- multiview_supported));
- if (!xr_drawing_buffer->Initialize(size, multisample_supported,
- multiview_supported)) {
+ want_alpha_channel, want_depth_buffer, want_stencil_buffer));
+ if (!xr_drawing_buffer->Initialize(size, multisample_supported)) {
DLOG(ERROR) << "XRWebGLDrawingBuffer Initialization Failed";
return nullptr;
}
@@ -100,22 +94,83 @@ scoped_refptr<XRWebGLDrawingBuffer> XRWebGLDrawingBuffer::Create(
return xr_drawing_buffer;
}
+void XRWebGLDrawingBuffer::MirrorClient::OnMirrorImageAvailable(
+ scoped_refptr<StaticBitmapImage> image,
+ std::unique_ptr<viz::SingleReleaseCallback> callback) {
+ // Replace the next image if we have one already.
+ if (next_image_ && next_release_callback_) {
+ next_release_callback_->Run(gpu::SyncToken(), false);
+ }
+
+ // Set our new image.
+ next_image_ = image;
+ next_release_callback_ = std::move(callback);
+}
+
+void XRWebGLDrawingBuffer::MirrorClient::BeginDestruction() {
+ // Call all callbacks we have to clean up associated resources. For
+ // next_release_callback_, we report the previous image as "not lost", meaning
+ // we can reuse the texture/image. For previous_release_callback_
+ // and current_release_callback_, we report the image as lost, because we
+ // don't know if the consumer is still using them, so they should not be
+ // reused.
+ if (previous_release_callback_) {
+ previous_release_callback_->Run(gpu::SyncToken(), true);
+ previous_release_callback_ = nullptr;
+ }
+
+ if (current_release_callback_) {
+ current_release_callback_->Run(gpu::SyncToken(), true);
+ current_release_callback_ = nullptr;
+ }
+
+ if (next_release_callback_) {
+ next_release_callback_->Run(gpu::SyncToken(), false);
+ next_release_callback_ = nullptr;
+ }
+
+ next_image_ = nullptr;
+}
+
+scoped_refptr<StaticBitmapImage>
+XRWebGLDrawingBuffer::MirrorClient::GetLastImage() {
+ if (!next_image_)
+ return nullptr;
+
+ scoped_refptr<StaticBitmapImage> ret = next_image_;
+ next_image_ = nullptr;
+ DCHECK(!previous_release_callback_);
+ previous_release_callback_ = std::move(current_release_callback_);
+ DCHECK(!current_release_callback_);
+ current_release_callback_ = std::move(next_release_callback_);
+ return ret;
+}
+
+void XRWebGLDrawingBuffer::MirrorClient::CallLastReleaseCallback() {
+ if (previous_release_callback_)
+ previous_release_callback_->Run(gpu::SyncToken(), false);
+ previous_release_callback_ = nullptr;
+}
+
+XRWebGLDrawingBuffer::MirrorClient::~MirrorClient() {
+ BeginDestruction();
+}
+
XRWebGLDrawingBuffer::XRWebGLDrawingBuffer(DrawingBuffer* drawing_buffer,
GLuint framebuffer,
bool discard_framebuffer_supported,
bool want_alpha_channel,
bool want_depth_buffer,
- bool want_stencil_buffer,
- bool multiview_supported)
+ bool want_stencil_buffer)
: drawing_buffer_(drawing_buffer),
framebuffer_(framebuffer),
discard_framebuffer_supported_(discard_framebuffer_supported),
depth_(want_depth_buffer),
stencil_(want_stencil_buffer),
- alpha_(want_alpha_channel),
- multiview_(false) {}
+ alpha_(want_alpha_channel) {}
void XRWebGLDrawingBuffer::BeginDestruction() {
+ mirror_client_ = nullptr;
back_color_buffer_ = nullptr;
front_color_buffer_ = nullptr;
recycled_color_buffer_queue_.clear();
@@ -124,8 +179,7 @@ void XRWebGLDrawingBuffer::BeginDestruction() {
// TODO(bajones): The GL resources allocated in this function are leaking. Add
// a way to clean up the buffers when the layer is GCed or the session ends.
bool XRWebGLDrawingBuffer::Initialize(const IntSize& size,
- bool use_multisampling,
- bool use_multiview) {
+ bool use_multisampling) {
gpu::gles2::GLES2Interface* gl = drawing_buffer_->ContextGL();
std::unique_ptr<Extensions3DUtil> extensions_util =
@@ -179,7 +233,7 @@ gpu::gles2::GLES2Interface* XRWebGLDrawingBuffer::ContextGL() {
return drawing_buffer_->ContextGL();
}
-void XRWebGLDrawingBuffer::SetMirrorClient(MirrorClient* client) {
+void XRWebGLDrawingBuffer::SetMirrorClient(scoped_refptr<MirrorClient> client) {
mirror_client_ = client;
if (mirror_client_) {
// Immediately send a black 1x1 image to the mirror client to ensure that
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h
index 919566a74f6..157ce76910d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h
@@ -29,8 +29,7 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer
bool want_alpha_channel,
bool want_depth_buffer,
bool want_stencil_buffer,
- bool want_antialiasing,
- bool want_multiview);
+ bool want_antialiasing);
gpu::gles2::GLES2Interface* ContextGL();
bool ContextLost();
@@ -41,7 +40,6 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer
bool depth() const { return depth_; }
bool stencil() const { return stencil_; }
bool alpha() const { return alpha_; }
- bool multiview() const { return multiview_; }
void Resize(const IntSize&);
@@ -51,14 +49,25 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer
scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage(
std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
- class MirrorClient {
+ class PLATFORM_EXPORT MirrorClient : public RefCounted<MirrorClient> {
public:
- virtual void OnMirrorImageAvailable(
- scoped_refptr<StaticBitmapImage>,
- std::unique_ptr<viz::SingleReleaseCallback>) = 0;
+ void OnMirrorImageAvailable(scoped_refptr<StaticBitmapImage>,
+ std::unique_ptr<viz::SingleReleaseCallback>);
+
+ void BeginDestruction();
+ scoped_refptr<StaticBitmapImage> GetLastImage();
+ void CallLastReleaseCallback();
+
+ ~MirrorClient();
+
+ private:
+ scoped_refptr<StaticBitmapImage> next_image_;
+ std::unique_ptr<viz::SingleReleaseCallback> next_release_callback_;
+ std::unique_ptr<viz::SingleReleaseCallback> current_release_callback_;
+ std::unique_ptr<viz::SingleReleaseCallback> previous_release_callback_;
};
- void SetMirrorClient(MirrorClient*);
+ void SetMirrorClient(scoped_refptr<MirrorClient> mirror_client);
void UseSharedBuffer(const gpu::MailboxHolder&);
void DoneWithSharedBuffer();
@@ -99,10 +108,9 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer
bool discard_framebuffer_supported,
bool want_alpha_channel,
bool want_depth_buffer,
- bool want_stencil_buffer,
- bool multiview_supported);
+ bool want_stencil_buffer);
- bool Initialize(const IntSize&, bool use_multisampling, bool use_multiview);
+ bool Initialize(const IntSize&, bool use_multisampling);
IntSize AdjustSize(const IntSize&);
@@ -151,7 +159,6 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer
bool depth_;
bool stencil_;
bool alpha_;
- bool multiview_;
enum AntialiasingMode {
kNone,
@@ -166,7 +173,7 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer
int max_texture_size_ = 0;
int sample_count_ = 0;
- MirrorClient* mirror_client_ = nullptr;
+ scoped_refptr<MirrorClient> mirror_client_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 0f9141b2e29..4cc66dadfbf 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -28,6 +28,7 @@
#include <memory>
+#include "base/optional.h"
#include "build/build_config.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
@@ -58,6 +59,34 @@
namespace blink {
+class GraphicsContext::HighContrastFlags final {
+ STACK_ALLOCATED();
+
+ public:
+ // This helper's lifetime should never exceed |flags|'.
+ HighContrastFlags(const GraphicsContext* gc, const PaintFlags& flags) {
+ if (!gc->high_contrast_filter_) {
+ flags_ = &flags;
+ } else {
+ high_contrast_flags_ = flags;
+ if (flags.HasShader()) {
+ high_contrast_flags_->setColorFilter(gc->high_contrast_filter_);
+ } else {
+ high_contrast_flags_->setColor(
+ gc->high_contrast_filter_->filterColor(flags.getColor()));
+ }
+
+ flags_ = &high_contrast_flags_.value();
+ }
+ }
+
+ operator const PaintFlags&() const { return *flags_; }
+
+ private:
+ const PaintFlags* flags_;
+ base::Optional<PaintFlags> high_contrast_flags_;
+};
+
GraphicsContext::GraphicsContext(PaintController& paint_controller,
DisabledMode disable_context_or_painting,
SkMetaData* meta_data)
@@ -637,7 +666,7 @@ void GraphicsContext::DrawLine(const IntPoint& point1, const IntPoint& point2) {
// probably worth the speed up of no square root, which also won't be exact.
FloatSize disp = p2 - p1;
int length = SkScalarRoundToInt(disp.Width() + disp.Height());
- PaintFlags flags(ImmutableState()->StrokeFlags(length));
+ const HighContrastFlags flags(this, ImmutableState()->StrokeFlags(length));
if (pen_style == kDottedStroke) {
if (StrokeData::StrokeIsDashed(width, pen_style)) {
@@ -664,8 +693,7 @@ void GraphicsContext::DrawLine(const IntPoint& point1, const IntPoint& point2) {
}
AdjustLineToPixelBoundaries(p1, p2, width);
- canvas_->drawLine(p1.X(), p1.Y(), p2.X(), p2.Y(),
- ApplyHighContrastFilter(&flags));
+ canvas_->drawLine(p1.X(), p1.Y(), p2.X(), p2.Y(), flags);
}
void GraphicsContext::DrawLineForText(const FloatPoint& pt, float width) {
@@ -743,7 +771,7 @@ void GraphicsContext::DrawTextInternal(const Font& font,
return;
font.DrawText(canvas_, text_info, point, device_scale_factor_,
- ApplyHighContrastFilter(&flags));
+ HighContrastFlags(this, flags));
}
void GraphicsContext::DrawText(const Font& font,
@@ -788,7 +816,7 @@ void GraphicsContext::DrawTextInternal(const Font& font,
DrawTextPasses([&font, &text_info, &point, this](const PaintFlags& flags) {
font.DrawText(canvas_, text_info, point, device_scale_factor_,
- ApplyHighContrastFilter(&flags));
+ HighContrastFlags(this, flags));
});
}
@@ -816,7 +844,7 @@ void GraphicsContext::DrawEmphasisMarksInternal(const Font& font,
[&font, &text_info, &mark, &point, this](const PaintFlags& flags) {
font.DrawEmphasisMarks(canvas_, text_info, mark, point,
device_scale_factor_,
- ApplyHighContrastFilter(&flags));
+ HighContrastFlags(this, flags));
});
}
@@ -847,7 +875,7 @@ void GraphicsContext::DrawBidiText(
this](const PaintFlags& flags) {
if (font.DrawBidiText(canvas_, run_info, point,
custom_font_not_ready_action, device_scale_factor_,
- ApplyHighContrastFilter(&flags)))
+ HighContrastFlags(this, flags)))
paint_controller_.SetTextPainted();
});
}
@@ -882,7 +910,6 @@ void GraphicsContext::DrawImage(
image_flags.setBlendMode(op);
image_flags.setColor(SK_ColorBLACK);
image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src));
- image_flags.setAntiAlias(ShouldAntialias());
if (ShouldApplyHighContrastFilterToImage(*image))
image_flags.setColorFilter(high_contrast_filter_);
image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation,
@@ -918,7 +945,6 @@ void GraphicsContext::DrawImageRRect(
image_flags.setColor(SK_ColorBLACK);
image_flags.setFilterQuality(
ComputeFilterQuality(image, dest.Rect(), src_rect));
- image_flags.setAntiAlias(ShouldAntialias());
bool use_shader = (visible_src == src_rect) &&
(respect_orientation == kDoNotRespectImageOrientation);
@@ -1011,7 +1037,7 @@ void GraphicsContext::DrawOval(const SkRect& oval, const PaintFlags& flags) {
return;
DCHECK(canvas_);
- canvas_->drawOval(oval, ApplyHighContrastFilter(&flags));
+ canvas_->drawOval(oval, HighContrastFlags(this, flags));
}
void GraphicsContext::DrawPath(const SkPath& path, const PaintFlags& flags) {
@@ -1019,7 +1045,7 @@ void GraphicsContext::DrawPath(const SkPath& path, const PaintFlags& flags) {
return;
DCHECK(canvas_);
- canvas_->drawPath(path, ApplyHighContrastFilter(&flags));
+ canvas_->drawPath(path, HighContrastFlags(this, flags));
}
void GraphicsContext::DrawRect(const SkRect& rect, const PaintFlags& flags) {
@@ -1027,7 +1053,7 @@ void GraphicsContext::DrawRect(const SkRect& rect, const PaintFlags& flags) {
return;
DCHECK(canvas_);
- canvas_->drawRect(rect, ApplyHighContrastFilter(&flags));
+ canvas_->drawRect(rect, HighContrastFlags(this, flags));
}
void GraphicsContext::DrawRRect(const SkRRect& rrect, const PaintFlags& flags) {
@@ -1035,7 +1061,7 @@ void GraphicsContext::DrawRRect(const SkRRect& rrect, const PaintFlags& flags) {
return;
DCHECK(canvas_);
- canvas_->drawRRect(rrect, ApplyHighContrastFilter(&flags));
+ canvas_->drawRRect(rrect, HighContrastFlags(this, flags));
}
void GraphicsContext::FillPath(const Path& path_to_fill) {
@@ -1423,28 +1449,7 @@ bool GraphicsContext::ShouldApplyHighContrastFilterToImage(Image& image) {
Color GraphicsContext::ApplyHighContrastFilter(const Color& input) const {
if (!high_contrast_filter_)
return input;
-
- SkColor sk_input =
- SkColorSetARGB(input.Alpha(), input.Red(), input.Green(), input.Blue());
- SkColor sk_output = high_contrast_filter_->filterColor(sk_input);
- return Color(MakeRGBA(SkColorGetR(sk_output), SkColorGetG(sk_output),
- SkColorGetB(sk_output), SkColorGetA(sk_output)));
-}
-
-PaintFlags GraphicsContext::ApplyHighContrastFilter(
- const PaintFlags* input) const {
- if (input && !high_contrast_filter_)
- return *input;
-
- PaintFlags output;
- if (input)
- output = *input;
- if (output.HasShader()) {
- output.setColorFilter(high_contrast_filter_);
- } else {
- output.setColor(high_contrast_filter_->filterColor(output.getColor()));
- }
- return output;
+ return Color(high_contrast_filter_->filterColor(input.Rgb()));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h
index bcde7276eff..f46176a479d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -88,7 +88,7 @@ class PLATFORM_EXPORT GraphicsContext {
bool ContextDisabled() const { return disabled_state_; }
- const HighContrastSettings& high_contrast_settings() {
+ const HighContrastSettings& high_contrast_settings() const {
return high_contrast_settings_;
}
@@ -466,9 +466,9 @@ class PLATFORM_EXPORT GraphicsContext {
const SkMetaData& MetaData() const { return meta_data_; }
+ class HighContrastFlags;
bool ShouldApplyHighContrastFilterToImage(Image&);
Color ApplyHighContrastFilter(const Color& input) const;
- PaintFlags ApplyHighContrastFilter(const PaintFlags* input) const;
// null indicates painting is contextDisabled. Never delete this object.
cc::PaintCanvas* canvas_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index 5a8572622a4..589c9d31b1d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -80,6 +80,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client)
: client_(client),
prevent_contents_opaque_changes_(false),
draws_content_(false),
+ paints_hit_test_(false),
contents_visible_(true),
hit_testable_without_draws_content_(false),
needs_check_raster_invalidation_(false),
@@ -90,12 +91,12 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client)
parent_(nullptr),
mask_layer_(nullptr),
contents_clipping_mask_layer_(nullptr),
- paint_count_(0),
contents_layer_(nullptr),
contents_layer_id_(0),
rendering_context3d_(0),
weak_ptr_factory_(this) {
#if DCHECK_IS_ON()
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
client.VerifyNotPainting();
#endif
layer_ = cc::PictureLayer::Create(this);
@@ -106,6 +107,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client)
}
GraphicsLayer::~GraphicsLayer() {
+ CcLayer()->ClearClient();
CcLayer()->SetLayerClient(nullptr);
SetContentsLayer(nullptr);
for (size_t i = 0; i < link_highlights_.size(); ++i)
@@ -150,6 +152,18 @@ void GraphicsLayer::SetIsContainerForFixedPositionLayers(bool is_container) {
CcLayer()->SetIsContainerForFixedPositionLayers(is_container);
}
+void GraphicsLayer::SetCompositingReasons(CompositingReasons reasons) {
+ CcLayer()->set_compositing_reasons(reasons);
+}
+
+CompositingReasons GraphicsLayer::GetCompositingReasons() const {
+ return CcLayer()->compositing_reasons();
+}
+
+void GraphicsLayer::SetOwnerNodeId(int node_id) {
+ CcLayer()->set_owner_node_id(node_id);
+}
+
void GraphicsLayer::SetParent(GraphicsLayer* layer) {
#if DCHECK_IS_ON()
DCHECK(!layer || !layer->HasAncestor(this));
@@ -244,8 +258,10 @@ void GraphicsLayer::RemoveFromParent() {
// When using layer lists, cc::Layers are created and removed in
// PaintArtifactCompositor.
if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
CcLayer()->RemoveFromParent();
+ } else {
+ SetPaintArtifactCompositorNeedsUpdate();
}
}
@@ -287,8 +303,8 @@ void GraphicsLayer::PaintRecursively() {
void GraphicsLayer::PaintRecursivelyInternal(
Vector<GraphicsLayer*>& repainted_layers) {
- if (DrawsContent()) {
- if (Paint(nullptr))
+ if (PaintsContentOrHitTest()) {
+ if (Paint())
repainted_layers.push_back(this);
}
@@ -301,8 +317,7 @@ void GraphicsLayer::PaintRecursivelyInternal(
child->PaintRecursivelyInternal(repainted_layers);
}
-bool GraphicsLayer::Paint(const IntRect* interest_rect,
- GraphicsContext::DisabledMode disabled_mode) {
+bool GraphicsLayer::Paint(GraphicsContext::DisabledMode disabled_mode) {
#if !DCHECK_IS_ON()
// TODO(crbug.com/853096): Investigate why we can ever reach here without
// a valid layer state. Seems to only happen on Android builds.
@@ -310,7 +325,7 @@ bool GraphicsLayer::Paint(const IntRect* interest_rect,
return false;
#endif
- if (PaintWithoutCommit(interest_rect, disabled_mode))
+ if (PaintWithoutCommit(disabled_mode))
GetPaintController().CommitNewDisplayItems();
else if (!needs_check_raster_invalidation_)
return false;
@@ -330,7 +345,7 @@ bool GraphicsLayer::Paint(const IntRect* interest_rect,
layer_state_->state, VisualRectSubpixelOffset(), this);
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
- DrawsContent()) {
+ PaintsContentOrHitTest()) {
auto& tracking = EnsureRasterInvalidator().EnsureTracking();
tracking.CheckUnderInvalidations(DebugName(), CapturePaintRecord(),
InterestRect());
@@ -347,16 +362,20 @@ bool GraphicsLayer::Paint(const IntRect* interest_rect,
return true;
}
+bool GraphicsLayer::PaintWithoutCommitForTesting(
+ const base::Optional<IntRect>& interest_rect) {
+ return PaintWithoutCommit(GraphicsContext::kNothingDisabled,
+ base::OptionalOrNullptr(interest_rect));
+}
+
bool GraphicsLayer::PaintWithoutCommit(
- const IntRect* interest_rect,
- GraphicsContext::DisabledMode disabled_mode) {
- DCHECK(DrawsContent());
+ GraphicsContext::DisabledMode disabled_mode,
+ const IntRect* interest_rect) {
+ DCHECK(PaintsContentOrHitTest());
if (client_.ShouldThrottleRendering())
return false;
- IncrementPaintCount();
-
IntRect new_interest_rect;
if (!interest_rect) {
new_interest_rect =
@@ -384,7 +403,8 @@ bool GraphicsLayer::PaintWithoutCommit(
void GraphicsLayer::UpdateChildList() {
// When using layer lists, cc::Layers are created in PaintArtifactCompositor.
if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ SetPaintArtifactCompositorNeedsUpdate();
return;
}
@@ -431,6 +451,12 @@ void GraphicsLayer::UpdateContentsRect() {
if (!contents_layer)
return;
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ const auto& offset = GetContentsOffsetFromTransformNode();
+ contents_layer->SetOffsetToTransformParent(
+ gfx::Vector2dF(offset.X(), offset.Y()));
+ SetPaintArtifactCompositorNeedsUpdate();
+ }
contents_layer->SetPosition(
FloatPoint(contents_rect_.X(), contents_rect_.Y()));
if (!image_layer_) {
@@ -525,16 +551,13 @@ void GraphicsLayer::SetupContentsLayer(cc::Layer* contents_layer) {
// Insert the content layer first. Video elements require this, because they
// have shadow content that must display in front of the video.
if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
- !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
CcLayer()->InsertChild(contents_layer_, 0);
}
cc::PictureLayer* border_cc_layer =
contents_clipping_mask_layer_ ? contents_clipping_mask_layer_->CcLayer()
: nullptr;
contents_layer_->SetMaskLayer(border_cc_layer);
- if (border_cc_layer)
- border_cc_layer->set_is_rounded_corner_mask(true);
-
contents_layer_->Set3dSortingContextId(rendering_context3d_);
}
@@ -722,6 +745,10 @@ void GraphicsLayer::SetContentsVisible(bool contents_visible) {
UpdateLayerIsDrawable();
}
+void GraphicsLayer::SetPaintArtifactCompositorNeedsUpdate() const {
+ client_.SetPaintArtifactCompositorNeedsUpdate();
+}
+
void GraphicsLayer::SetClipParent(cc::Layer* parent) {
has_clip_parent_ = !!parent;
CcLayer()->SetClipParent(parent);
@@ -751,15 +778,12 @@ void GraphicsLayer::SetContentsOpaque(bool opaque) {
contents_layer_->SetContentsOpaque(opaque);
}
-void GraphicsLayer::SetMaskLayer(GraphicsLayer* mask_layer,
- bool is_rounded_corner_mask) {
+void GraphicsLayer::SetMaskLayer(GraphicsLayer* mask_layer) {
if (mask_layer == mask_layer_)
return;
mask_layer_ = mask_layer;
CcLayer()->SetMaskLayer(mask_layer_ ? mask_layer_->CcLayer() : nullptr);
- if (mask_layer_)
- mask_layer_->CcLayer()->set_is_rounded_corner_mask(is_rounded_corner_mask);
}
void GraphicsLayer::SetContentsClippingMaskLayer(
@@ -775,9 +799,6 @@ void GraphicsLayer::SetContentsClippingMaskLayer(
contents_clipping_mask_layer_ ? contents_clipping_mask_layer_->CcLayer()
: nullptr;
contents_layer->SetMaskLayer(contents_clipping_mask_cc_layer);
- // Contents clipping mask layesrs (aka child clipping mask layer) is always
- // a rounded corner mask.
- contents_layer->set_is_rounded_corner_mask(true);
UpdateContentsRect();
}
@@ -829,7 +850,7 @@ void GraphicsLayer::SetContentsNeedsDisplay() {
}
void GraphicsLayer::SetNeedsDisplay() {
- if (!DrawsContent())
+ if (!PaintsContentOrHitTest())
return;
CcLayer()->SetNeedsDisplay();
@@ -846,7 +867,7 @@ void GraphicsLayer::SetNeedsDisplay() {
}
void GraphicsLayer::SetNeedsDisplayInRect(const IntRect& rect) {
- DCHECK(DrawsContent());
+ DCHECK(PaintsContentOrHitTest());
CcLayer()->SetNeedsDisplayRect(rect);
for (auto* link_highlight : link_highlights_)
@@ -920,8 +941,11 @@ void GraphicsLayer::SetFilters(CompositorFilterOperations filters) {
CcLayer()->SetFilters(filters.ReleaseCcFilterOperations());
}
-void GraphicsLayer::SetBackdropFilters(CompositorFilterOperations filters) {
+void GraphicsLayer::SetBackdropFilters(
+ CompositorFilterOperations filters,
+ const gfx::RectF& backdrop_filter_bounds) {
CcLayer()->SetBackdropFilters(filters.ReleaseCcFilterOperations());
+ CcLayer()->SetBackdropFilterBounds(backdrop_filter_bounds);
}
void GraphicsLayer::SetStickyPositionConstraint(
@@ -962,7 +986,7 @@ std::unique_ptr<base::trace_event::TracedValue> GraphicsLayer::TakeDebugInfo(
traced_value->BeginArray("compositing_reasons");
for (const char* description :
- CompositingReason::Descriptions(compositing_reasons_))
+ CompositingReason::Descriptions(GetCompositingReasons()))
traced_value->AppendString(description);
traced_value->EndArray();
@@ -972,8 +996,8 @@ std::unique_ptr<base::trace_event::TracedValue> GraphicsLayer::TakeDebugInfo(
traced_value->AppendString(description);
traced_value->EndArray();
- if (owner_node_id_)
- traced_value->SetInteger("owner_node", owner_node_id_);
+ if (auto node_id = layer_->owner_node_id())
+ traced_value->SetInteger("owner_node", node_id);
if (auto* tracking = GetRasterInvalidationTracking()) {
tracking->AddToTracedValue(*traced_value);
@@ -988,7 +1012,7 @@ void GraphicsLayer::DidChangeScrollbarsHiddenIfOverlay(bool hidden) {
}
PaintController& GraphicsLayer::GetPaintController() const {
- CHECK(DrawsContent());
+ CHECK(PaintsContentOrHitTest());
if (!paint_controller_)
paint_controller_ = PaintController::Create();
return *paint_controller_;
@@ -1006,7 +1030,7 @@ CompositorElementId GraphicsLayer::GetElementId() const {
}
sk_sp<PaintRecord> GraphicsLayer::CapturePaintRecord() const {
- DCHECK(DrawsContent());
+ DCHECK(PaintsContentOrHitTest());
if (client_.ShouldThrottleRendering())
return sk_sp<PaintRecord>(new PaintRecord);
@@ -1025,6 +1049,9 @@ void GraphicsLayer::SetLayerState(const PropertyTreeState& layer_state,
DCHECK(layer_state.Transform() && layer_state.Clip() && layer_state.Effect());
if (layer_state_) {
+ if (layer_state_->state == layer_state &&
+ layer_state_->offset == layer_offset)
+ return;
layer_state_->state = layer_state;
layer_state_->offset = layer_offset;
} else {
@@ -1036,29 +1063,25 @@ void GraphicsLayer::SetLayerState(const PropertyTreeState& layer_state,
CcLayer()->SetOffsetToTransformParent(
gfx::Vector2dF(layer_offset.X(), layer_offset.Y()));
- if (!contents_layer_state_ && ContentsLayer()) {
+ if (ContentsLayer()) {
+ const auto& offset = GetContentsOffsetFromTransformNode();
ContentsLayer()->SetOffsetToTransformParent(
- gfx::Vector2dF(layer_offset.X(), layer_offset.Y()));
+ gfx::Vector2dF(offset.X(), offset.Y()));
}
+ SetPaintArtifactCompositorNeedsUpdate();
}
}
-void GraphicsLayer::SetContentsLayerState(const PropertyTreeState& layer_state,
- const IntPoint& layer_offset) {
+void GraphicsLayer::SetContentsPropertyTreeState(
+ const PropertyTreeState& layer_state) {
DCHECK(layer_state.Transform() && layer_state.Clip() && layer_state.Effect());
DCHECK(ContentsLayer());
- if (contents_layer_state_) {
- contents_layer_state_->state = layer_state;
- contents_layer_state_->offset = layer_offset;
+ if (contents_property_tree_state_) {
+ *contents_property_tree_state_ = layer_state;
} else {
- contents_layer_state_ =
- std::make_unique<LayerState>(LayerState{layer_state, layer_offset});
- }
-
- if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
- ContentsLayer()->SetOffsetToTransformParent(
- gfx::Vector2dF(layer_offset.X(), layer_offset.Y()));
+ contents_property_tree_state_ =
+ std::make_unique<PropertyTreeState>(layer_state);
}
}
@@ -1094,7 +1117,7 @@ scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList(
// occurs in LocalFrameView::PaintTree() which calls GraphicsLayer::Paint();
// this method merely copies the painted output to the cc::DisplayItemList.
if (painting_control != PAINTING_BEHAVIOR_NORMAL)
- Paint(nullptr, disabled_mode);
+ Paint(disabled_mode);
auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h
index 954f933c69e..71f07812a9c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -89,19 +89,17 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
GraphicsLayerClient& Client() const { return client_; }
- void SetCompositingReasons(CompositingReasons reasons) {
- compositing_reasons_ = reasons;
- }
- CompositingReasons GetCompositingReasons() const {
- return compositing_reasons_;
- }
+ void SetCompositingReasons(CompositingReasons reasons);
+ CompositingReasons GetCompositingReasons() const;
+
SquashingDisallowedReasons GetSquashingDisallowedReasons() const {
return squashing_disallowed_reasons_;
}
void SetSquashingDisallowedReasons(SquashingDisallowedReasons reasons) {
squashing_disallowed_reasons_ = reasons;
}
- void SetOwnerNodeId(int id) { owner_node_id_ = id; }
+
+ void SetOwnerNodeId(int id);
GraphicsLayer* Parent() const { return parent_; }
void SetParent(GraphicsLayer*); // Internal use only.
@@ -119,7 +117,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
void RemoveFromParent();
GraphicsLayer* MaskLayer() const { return mask_layer_; }
- void SetMaskLayer(GraphicsLayer*, bool is_rounded_corner_mask);
+ void SetMaskLayer(GraphicsLayer*);
GraphicsLayer* ContentsClippingMaskLayer() const {
return contents_clipping_mask_layer_;
@@ -159,12 +157,24 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
bool DrawsContent() const { return draws_content_; }
void SetDrawsContent(bool);
+ // False if no hit test display items will be painted onto this GraphicsLayer.
+ // This is different from |DrawsContent| because hit test display items are
+ // internal to blink and are not copied to the cc::Layer's display list.
+ bool PaintsHitTest() const { return paints_hit_test_; }
+ void SetPaintsHitTest(bool paints) { paints_hit_test_ = paints; };
+
+ bool PaintsContentOrHitTest() const {
+ return draws_content_ || paints_hit_test_;
+ }
+
bool ContentsAreVisible() const { return contents_visible_; }
void SetContentsVisible(bool);
void SetScrollParent(cc::Layer*);
void SetClipParent(cc::Layer*);
+ void SetPaintArtifactCompositorNeedsUpdate() const;
+
// For special cases, e.g. drawing missing tiles on Android.
// The compositor should never paint this color in normal cases because the
// Layer will paint the background by itself.
@@ -192,7 +202,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
}
void SetFilters(CompositorFilterOperations);
- void SetBackdropFilters(CompositorFilterOperations);
+ void SetBackdropFilters(CompositorFilterOperations, const gfx::RectF&);
void SetStickyPositionConstraint(const cc::LayerStickyPositionConstraint&);
@@ -227,8 +237,6 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
// For hosting this GraphicsLayer in a native layer hierarchy.
cc::PictureLayer* CcLayer() const;
- int PaintCount() const { return paint_count_; }
-
// Return a string with a human readable form of the layer tree. If debug is
// true, pointers for the layers and timing data will be included in the
// returned string.
@@ -256,8 +264,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
IntRect InterestRect();
void PaintRecursively();
// Returns true if this layer is repainted.
- bool Paint(const IntRect* interest_rect,
- GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled);
+ bool Paint(GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled);
// cc::LayerClient implementation.
std::unique_ptr<base::trace_event::TracedValue> TakeDebugInfo(
@@ -289,15 +296,16 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
}
IntPoint GetOffsetFromTransformNode() const { return layer_state_->offset; }
- void SetContentsLayerState(const PropertyTreeState&,
- const IntPoint& layer_offset);
+ void SetContentsPropertyTreeState(const PropertyTreeState&);
const PropertyTreeState& GetContentsPropertyTreeState() const {
- return contents_layer_state_ ? contents_layer_state_->state
- : GetPropertyTreeState();
+ return contents_property_tree_state_ ? *contents_property_tree_state_
+ : GetPropertyTreeState();
}
IntPoint GetContentsOffsetFromTransformNode() const {
- return contents_layer_state_ ? contents_layer_state_->offset
- : GetOffsetFromTransformNode();
+ auto offset = contents_rect_.Location();
+ if (layer_state_)
+ offset = offset + GetOffsetFromTransformNode();
+ return offset;
}
// Capture the last painted result into a PaintRecord. This GraphicsLayer
@@ -311,16 +319,18 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
bool HasScrollParent() const { return has_scroll_parent_; }
bool HasClipParent() const { return has_clip_parent_; }
+ bool PaintWithoutCommitForTesting(
+ const base::Optional<IntRect>& interest_rect = base::nullopt);
+
protected:
String DebugName(cc::Layer*) const;
explicit GraphicsLayer(GraphicsLayerClient&);
+ private:
friend class CompositedLayerMappingTest;
- friend class PaintControllerPaintTestBase;
friend class GraphicsLayerTest;
- private:
// cc::ContentLayerClient implementation.
gfx::Rect PaintableRegion() final { return InterestRect(); }
scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
@@ -330,10 +340,10 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
void PaintRecursivelyInternal(Vector<GraphicsLayer*>& repainted_layers);
- // Returns true if PaintController::paintArtifact() changed and needs commit.
+ // Returns true if PaintController::PaintArtifact() changed and needs commit.
bool PaintWithoutCommit(
- const IntRect* interest_rect,
- GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled);
+ GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled,
+ const IntRect* interest_rect = nullptr);
// Adds a child without calling updateChildList(), so that adding children
// can be batched before updating.
@@ -343,8 +353,6 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
bool HasAncestor(GraphicsLayer*) const;
#endif
- void IncrementPaintCount() { ++paint_count_; }
-
// Helper functions used by settors to keep layer's the state consistent.
void UpdateChildList();
void UpdateLayerIsDrawable();
@@ -370,6 +378,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
bool prevent_contents_opaque_changes_ : 1;
bool draws_content_ : 1;
+ bool paints_hit_test_ : 1;
bool contents_visible_ : 1;
bool hit_testable_without_draws_content_ : 1;
bool needs_check_raster_invalidation_ : 1;
@@ -391,8 +400,6 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
IntRect contents_rect_;
- int paint_count_;
-
scoped_refptr<cc::PictureLayer> layer_;
scoped_refptr<cc::PictureImageLayer> image_layer_;
IntSize image_size_;
@@ -408,10 +415,8 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
int rendering_context3d_;
- CompositingReasons compositing_reasons_ = CompositingReason::kNone;
SquashingDisallowedReasons squashing_disallowed_reasons_ =
SquashingDisallowedReason::kNone;
- int owner_node_id_ = 0;
mutable std::unique_ptr<PaintController> paint_controller_;
@@ -422,7 +427,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient,
IntPoint offset;
};
std::unique_ptr<LayerState> layer_state_;
- std::unique_ptr<LayerState> contents_layer_state_;
+ std::unique_ptr<PropertyTreeState> contents_property_tree_state_;
std::unique_ptr<RasterInvalidator> raster_invalidator_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
index 7561489f69c..f55c529d768 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
@@ -97,6 +97,8 @@ class PLATFORM_EXPORT GraphicsLayerClient {
virtual void SetOverlayScrollbarsHidden(bool) {}
+ virtual void SetPaintArtifactCompositorNeedsUpdate() const {}
+
virtual String DebugName(const GraphicsLayer*) const = 0;
virtual const ScrollableArea* GetScrollableAreaForTesting(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
index e79095e8fbf..ac3a7883312 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
@@ -49,10 +49,6 @@ class GraphicsLayerTest : public testing::Test, public PaintTestConfigurations {
~GraphicsLayerTest() = default;
protected:
- bool PaintWithoutCommit(GraphicsLayer& layer, const IntRect* interest_rect) {
- return layer.PaintWithoutCommit(interest_rect);
- }
-
void CommitAndFinishCycle(GraphicsLayer& layer) {
layer.GetPaintController().CommitNewDisplayItems();
layer.GetPaintController().FinishCycle();
@@ -82,25 +78,26 @@ INSTANTIATE_TEST_CASE_P(All,
TEST_P(GraphicsLayerTest, Paint) {
IntRect interest_rect(1, 2, 3, 4);
- EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
- CommitAndFinishCycle(layers_.graphics_layer());
+ auto& layer = layers_.graphics_layer();
+ EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect));
+ CommitAndFinishCycle(layer);
layers_.graphics_layer_client().SetNeedsRepaint(true);
- EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
- CommitAndFinishCycle(layers_.graphics_layer());
+ EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect));
+ CommitAndFinishCycle(layer);
layers_.graphics_layer_client().SetNeedsRepaint(false);
- EXPECT_FALSE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
+ EXPECT_FALSE(layer.PaintWithoutCommitForTesting(interest_rect));
interest_rect.Move(IntSize(10, 20));
- EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
- CommitAndFinishCycle(layers_.graphics_layer());
- EXPECT_FALSE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
+ EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect));
+ CommitAndFinishCycle(layer);
+ EXPECT_FALSE(layer.PaintWithoutCommitForTesting(interest_rect));
layers_.graphics_layer().SetNeedsDisplay();
- EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
- CommitAndFinishCycle(layers_.graphics_layer());
- EXPECT_FALSE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect));
+ EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect));
+ CommitAndFinishCycle(layer);
+ EXPECT_FALSE(layer.PaintWithoutCommitForTesting(interest_rect));
}
TEST_P(GraphicsLayerTest, PaintRecursively) {
@@ -158,4 +155,21 @@ TEST_P(GraphicsLayerTest, SetDrawsContentFalse) {
EXPECT_EQ(nullptr, GetInternalRasterInvalidator(layers_.graphics_layer()));
}
+TEST_P(GraphicsLayerTest, CcLayerClient) {
+ auto graphics_layer =
+ std::make_unique<FakeGraphicsLayer>(layers_.graphics_layer_client());
+ graphics_layer->SetDrawsContent(true);
+ scoped_refptr<cc::PictureLayer> cc_layer = graphics_layer->CcLayer();
+ ASSERT_TRUE(cc_layer);
+ EXPECT_TRUE(cc_layer->DrawsContent());
+ EXPECT_TRUE(cc_layer->client());
+ EXPECT_TRUE(cc_layer->GetLayerClientForTesting());
+
+ graphics_layer.reset();
+ EXPECT_FALSE(cc_layer->DrawsContent());
+ EXPECT_FALSE(cc_layer->client());
+ EXPECT_FALSE(cc_layer->GetLayerClientForTesting());
+ EXPECT_FALSE(cc_layer->GetPicture());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image.cc b/chromium/third_party/blink/renderer/platform/graphics/image.cc
index 4b07a4b2fdc..efa5fa09313 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/image.cc
@@ -303,7 +303,8 @@ namespace {
sk_sp<PaintShader> CreatePatternShader(const PaintImage& image,
const SkMatrix& shader_matrix,
- const PaintFlags& paint,
+ SkFilterQuality quality_to_use,
+ bool should_antialias,
const FloatSize& spacing,
SkShader::TileMode tmx,
SkShader::TileMode tmy) {
@@ -318,7 +319,10 @@ sk_sp<PaintShader> CreatePatternShader(const PaintImage& image,
PaintRecorder recorder;
cc::PaintCanvas* canvas = recorder.beginRecording(tile_rect);
- canvas->drawImage(image, 0, 0, &paint);
+ PaintFlags flags;
+ flags.setAntiAlias(should_antialias);
+ flags.setFilterQuality(quality_to_use);
+ canvas->drawImage(image, 0, 0, &flags);
return PaintShader::MakePaintRecord(recorder.finishRecordingAsPicture(),
tile_rect, tmx, tmy, &shader_matrix);
@@ -389,22 +393,22 @@ void Image::DrawPattern(GraphicsContext& context,
const auto tmy = ComputeTileMode(dest_rect.Y(), dest_rect.MaxY(), adjusted_y,
adjusted_y + tile_size.Height());
- PaintFlags flags = context.FillFlags();
- flags.setColor(SK_ColorBLACK);
- flags.setBlendMode(composite_op);
- flags.setFilterQuality(
- context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect)));
- flags.setAntiAlias(context.ShouldAntialias());
- flags.setShader(CreatePatternShader(
- image, local_matrix, flags,
+ SkFilterQuality quality_to_use =
+ context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect));
+ sk_sp<PaintShader> tile_shader = CreatePatternShader(
+ image, local_matrix, quality_to_use, context.ShouldAntialias(),
FloatSize(repeat_spacing.Width() / scale_src_to_dest.Width(),
repeat_spacing.Height() / scale_src_to_dest.Height()),
- tmx, tmy));
+ tmx, tmy);
+
+ PaintFlags flags = context.FillFlags();
// If the shader could not be instantiated (e.g. non-invertible matrix),
// draw transparent.
// Note: we can't simply bail, because of arbitrary blend mode.
- if (!flags.HasShader())
- flags.setColor(SK_ColorTRANSPARENT);
+ flags.setColor(tile_shader ? SK_ColorBLACK : SK_ColorTRANSPARENT);
+ flags.setBlendMode(composite_op);
+ flags.setFilterQuality(quality_to_use);
+ flags.setShader(std::move(tile_shader));
context.DrawRect(dest_rect, flags);
@@ -466,7 +470,7 @@ FloatRect Image::ComputeSubsetForBackground(const FloatRect& phase_and_size,
const FloatRect& subset,
const FloatSize& intrinsic_size) {
// TODO(schenney): Re-enable this after determining why it fails for
- // SPv2, and maybe other cases.
+ // CAP, and maybe other cases.
// DCHECK(phase_and_size.Contains(subset));
const FloatSize scale(phase_and_size.Width() / intrinsic_size.Width(),
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc
index 62a2e0e25d6..7632a4e9239 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc
@@ -5,11 +5,8 @@
#include "third_party/blink/renderer/platform/graphics/image_pattern.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_shader.h"
-#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/skia/include/core/SkImage.h"
-#include "third_party/skia/include/core/SkSurface.h"
namespace blink {
@@ -20,13 +17,6 @@ scoped_refptr<ImagePattern> ImagePattern::Create(scoped_refptr<Image> image,
ImagePattern::ImagePattern(scoped_refptr<Image> image, RepeatMode repeat_mode)
: Pattern(repeat_mode), tile_image_(image->PaintImageForCurrentFrame()) {
- previous_local_matrix_.setIdentity();
-}
-
-bool ImagePattern::IsLocalMatrixChanged(const SkMatrix& local_matrix) const {
- if (IsRepeatXY())
- return Pattern::IsLocalMatrixChanged(local_matrix);
- return local_matrix != previous_local_matrix_;
}
sk_sp<PaintShader> ImagePattern::CreateShader(const SkMatrix& local_matrix) {
@@ -34,45 +24,11 @@ sk_sp<PaintShader> ImagePattern::CreateShader(const SkMatrix& local_matrix) {
return PaintShader::MakeColor(SK_ColorTRANSPARENT);
}
- if (IsRepeatXY()) {
- // Fast path: for repeatXY we just return a shader from the original image.
- return PaintShader::MakeImage(tile_image_, SkShader::kRepeat_TileMode,
- SkShader::kRepeat_TileMode, &local_matrix);
- }
-
- // Skia does not have a "draw the tile only once" option. Clamp_TileMode
- // repeats the last line of the image after drawing one tile. To avoid
- // filling the space with arbitrary pixels, this workaround forces the
- // image to have a line of transparent pixels on the "repeated" edge(s),
- // thus causing extra space to be transparent filled.
- SkShader::TileMode tile_mode_x =
- IsRepeatX() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
- SkShader::TileMode tile_mode_y =
- IsRepeatY() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
- int border_pixel_x = IsRepeatX() ? 0 : 1;
- int border_pixel_y = IsRepeatY() ? 0 : 1;
-
- // Create a transparent image 2 pixels wider and/or taller than the
- // original, then copy the orignal into the middle of it.
- const SkRect tile_bounds =
- SkRect::MakeWH(tile_image_.width() + 2 * border_pixel_x,
- tile_image_.height() + 2 * border_pixel_y);
- PaintRecorder recorder;
- auto* canvas = recorder.beginRecording(tile_bounds);
-
- cc::PaintFlags paint;
- paint.setBlendMode(SkBlendMode::kSrc);
- canvas->drawImage(tile_image_, border_pixel_x, border_pixel_y, &paint);
-
- previous_local_matrix_ = local_matrix;
- SkMatrix adjusted_matrix(local_matrix);
- adjusted_matrix.postTranslate(-border_pixel_x, -border_pixel_y);
-
- // Note: we specify kFixedScale to lock-in the resolution (for 1px padding in
- // particular).
- return PaintShader::MakePaintRecord(
- recorder.finishRecordingAsPicture(), tile_bounds, tile_mode_x,
- tile_mode_y, &adjusted_matrix, PaintShader::ScalingBehavior::kFixedScale);
+ return PaintShader::MakeImage(
+ tile_image_,
+ IsRepeatX() ? SkShader::kRepeat_TileMode : SkShader::kDecal_TileMode,
+ IsRepeatY() ? SkShader::kRepeat_TileMode : SkShader::kDecal_TileMode,
+ &local_matrix);
}
bool ImagePattern::IsTextureBacked() const {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h
index db42125f29e..cea1b6b337d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h
@@ -20,11 +20,9 @@ class PLATFORM_EXPORT ImagePattern final : public Pattern {
protected:
sk_sp<PaintShader> CreateShader(const SkMatrix&) override;
- bool IsLocalMatrixChanged(const SkMatrix&) const override;
private:
ImagePattern(scoped_refptr<Image>, RepeatMode);
- SkMatrix previous_local_matrix_;
PaintImage tile_image_;
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
index f17b64acc09..78164e773fc 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
@@ -116,20 +116,6 @@ class InterceptingCanvasBase : public SkCanvas {
void onDrawDRRect(const SkRRect& outer,
const SkRRect& inner,
const SkPaint&) override = 0;
- void onDrawText(const void* text,
- size_t byte_length,
- SkScalar x,
- SkScalar y,
- const SkPaint&) override = 0;
- void onDrawPosText(const void* text,
- size_t byte_length,
- const SkPoint pos[],
- const SkPaint&) override = 0;
- void onDrawPosTextH(const void* text,
- size_t byte_length,
- const SkScalar xpos[],
- SkScalar const_y,
- const SkPaint&) override = 0;
void onDrawTextBlob(const SkTextBlob*,
SkScalar x,
SkScalar y,
@@ -258,32 +244,6 @@ class InterceptingCanvas : public InterceptingCanvasBase {
this->SkCanvas::onDrawDRRect(outer, inner, paint);
}
- void onDrawText(const void* text,
- size_t byte_length,
- SkScalar x,
- SkScalar y,
- const SkPaint& paint) override {
- Interceptor interceptor(this);
- this->SkCanvas::onDrawText(text, byte_length, x, y, paint);
- }
-
- void onDrawPosText(const void* text,
- size_t byte_length,
- const SkPoint pos[],
- const SkPaint& paint) override {
- Interceptor interceptor(this);
- this->SkCanvas::onDrawPosText(text, byte_length, pos, paint);
- }
-
- void onDrawPosTextH(const void* text,
- size_t byte_length,
- const SkScalar xpos[],
- SkScalar const_y,
- const SkPaint& paint) override {
- Interceptor interceptor(this);
- this->SkCanvas::onDrawPosTextH(text, byte_length, xpos, const_y, paint);
- }
-
void onDrawTextBlob(const SkTextBlob* blob,
SkScalar x,
SkScalar y,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h b/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h
index 4044ad955f3..4dfc5a27c60 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h
@@ -24,9 +24,11 @@ class PLATFORM_EXPORT LinkHighlight : public DisplayItemClient {
virtual void ClearCurrentGraphicsLayer() = 0;
virtual cc::Layer* Layer() = 0;
- virtual const EffectPaintPropertyNode* effect() = 0;
+ virtual const EffectPaintPropertyNode* effect() const = 0;
// DisplayItemClient methods
+ // TODO(wangxianzhu): This class doesn't need to be a DisplayItemClient in
+ // CompositeAfterPaint.
String DebugName() const final { return "LinkHighlight"; }
LayoutRect VisualRect() const final { return LayoutRect(); }
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc
index 0b830191a69..849372c2853 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/platform/graphics/logging_canvas.h"
#include <unicode/unistr.h>
+
+#include "base/stl_util.h"
#include "base/sys_byteorder.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
@@ -39,7 +41,6 @@
#include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
#include "third_party/blink/renderer/platform/wtf/hex_number.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
-#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPaint.h"
@@ -234,7 +235,7 @@ std::unique_ptr<JSONObject> ObjectForSkPath(const SkPath& path) {
std::unique_ptr<JSONObject> path_point_item = JSONObject::Create();
path_point_item->SetString("verb", verb_params.name);
DCHECK_LE(verb_params.point_count + verb_params.point_offset,
- arraysize(points));
+ base::size(points));
path_point_item->SetArray(
"points", ArrayForSkPoints(verb_params.point_count,
points + verb_params.point_offset));
@@ -341,18 +342,11 @@ void AppendFlagToString(String* flags_string, bool is_set, const String& name) {
}
String StringForSkPaintFlags(const SkPaint& paint) {
- if (!paint.getFlags())
+ if (!paint.isAntiAlias() && !paint.isDither())
return "none";
String flags_string = "";
AppendFlagToString(&flags_string, paint.isAntiAlias(), "AntiAlias");
AppendFlagToString(&flags_string, paint.isDither(), "Dither");
- AppendFlagToString(&flags_string, paint.isFakeBoldText(), "FakeBoldText");
- AppendFlagToString(&flags_string, paint.isLinearText(), "LinearText");
- AppendFlagToString(&flags_string, paint.isSubpixelText(), "SubpixelText");
- AppendFlagToString(&flags_string, paint.isLCDRenderText(), "LCDRenderText");
- AppendFlagToString(&flags_string, paint.isEmbeddedBitmapText(),
- "EmbeddedBitmapText");
- AppendFlagToString(&flags_string, paint.isAutohinted(), "Autohinted");
return flags_string;
}
@@ -414,43 +408,8 @@ String StyleName(SkPaint::Style style) {
};
}
-String TextEncodingName(SkPaint::TextEncoding encoding) {
- switch (encoding) {
- case SkPaint::kUTF8_TextEncoding:
- return "UTF-8";
- case SkPaint::kUTF16_TextEncoding:
- return "UTF-16";
- case SkPaint::kUTF32_TextEncoding:
- return "UTF-32";
- case SkPaint::kGlyphID_TextEncoding:
- return "GlyphID";
- default:
- NOTREACHED();
- return "?";
- };
-}
-
-String HintingName(SkFontHinting hinting) {
- switch (hinting) {
- case SkFontHinting::kNone:
- return "None";
- case SkFontHinting::kSlight:
- return "Slight";
- case SkFontHinting::kNormal:
- return "Normal";
- case SkFontHinting::kFull:
- return "Full";
- default:
- NOTREACHED();
- return "?";
- };
-}
-
std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) {
std::unique_ptr<JSONObject> paint_item = JSONObject::Create();
- paint_item->SetDouble("textSize", paint.getTextSize());
- paint_item->SetDouble("textScaleX", paint.getTextScaleX());
- paint_item->SetDouble("textSkewX", paint.getTextSkewX());
if (SkShader* shader = paint.getShader())
paint_item->SetObject("shader", ObjectForSkShader(*shader));
paint_item->SetString("color", StringForSkColor(paint.getColor()));
@@ -462,9 +421,6 @@ std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) {
paint_item->SetString("strokeCap", StrokeCapName(paint.getStrokeCap()));
paint_item->SetString("strokeJoin", StrokeJoinName(paint.getStrokeJoin()));
paint_item->SetString("styleName", StyleName(paint.getStyle()));
- paint_item->SetString("textEncoding",
- TextEncodingName(paint.getTextEncoding()));
- paint_item->SetString("hinting", HintingName(paint.getHinting()));
if (paint.getBlendMode() != SkBlendMode::kSrcOver)
paint_item->SetString("blendMode", SkBlendMode_Name(paint.getBlendMode()));
if (paint.getImageFilter())
@@ -472,14 +428,6 @@ std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) {
return paint_item;
}
-std::unique_ptr<JSONArray> ArrayForSkScalars(size_t n,
- const SkScalar scalars[]) {
- std::unique_ptr<JSONArray> scalars_array = JSONArray::Create();
- for (size_t i = 0; i < n; ++i)
- scalars_array->PushDouble(scalars[i]);
- return scalars_array;
-}
-
String ClipOpName(SkClipOp op) {
switch (op) {
case SkClipOp::kDifference:
@@ -491,58 +439,6 @@ String ClipOpName(SkClipOp op) {
};
}
-String SaveLayerFlagsToString(SkCanvas::SaveLayerFlags flags) {
- String flags_string = "";
- if (flags & SkCanvas::kPreserveLCDText_SaveLayerFlag)
- flags_string.append("kPreserveLCDText_SaveLayerFlag ");
- return flags_string;
-}
-
-String StringForUTF32LEText(const void* text, size_t byte_length) {
- icu::UnicodeString utf16;
-#if defined(ARCH_CPU_BIG_ENDIAN)
- // Swap LE to BE
- size_t char_length = length / sizeof(UChar32);
- WTF::Vector<UChar32> utf32be(char_length);
- const UChar32* utf32le = static_cast<const UChar32*>(text);
- for (size_t i = 0; i < char_length; ++i)
- utf32be[i] = base::ByteSwap(utf32le[i]);
- utf16 = icu::UnicodeString::fromUTF32(utf32be.data(),
- static_cast<int32_t>(byte_length));
-#else
- utf16 = icu::UnicodeString::fromUTF32(reinterpret_cast<const UChar32*>(text),
- static_cast<int32_t>(byte_length));
-#endif
- return String(icu::toUCharPtr(utf16.getBuffer()),
- static_cast<unsigned>(utf16.length()));
-}
-
-String StringForText(const void* text,
- size_t byte_length,
- const SkPaint& paint) {
- SkPaint::TextEncoding encoding = paint.getTextEncoding();
- switch (encoding) {
- case SkPaint::kUTF8_TextEncoding:
- return WTF::TextEncoding("UTF-8").Decode(
- reinterpret_cast<const char*>(text), byte_length);
- case SkPaint::kUTF16_TextEncoding:
- return WTF::TextEncoding("UTF-16LE")
- .Decode(reinterpret_cast<const char*>(text), byte_length);
- case SkPaint::kUTF32_TextEncoding:
- return StringForUTF32LEText(text, byte_length);
- case SkPaint::kGlyphID_TextEncoding: {
- WTF::Vector<SkUnichar> data_vector(byte_length / 2);
- SkUnichar* text_data = data_vector.data();
- paint.glyphsToUnichars(static_cast<const uint16_t*>(text),
- byte_length / 2, text_data);
- return StringForUTF32LEText(text, byte_length);
- }
- default:
- NOTREACHED();
- return "?";
- }
-}
-
} // namespace
class AutoLogger
@@ -725,48 +621,6 @@ void LoggingCanvas::onDrawDRRect(const SkRRect& outer,
this->SkCanvas::onDrawDRRect(outer, inner, paint);
}
-void LoggingCanvas::onDrawText(const void* text,
- size_t byte_length,
- SkScalar x,
- SkScalar y,
- const SkPaint& paint) {
- AutoLogger logger(this);
- JSONObject* params = logger.LogItemWithParams("drawText");
- params->SetString("text", StringForText(text, byte_length, paint));
- params->SetDouble("x", x);
- params->SetDouble("y", y);
- params->SetObject("paint", ObjectForSkPaint(paint));
- this->SkCanvas::onDrawText(text, byte_length, x, y, paint);
-}
-
-void LoggingCanvas::onDrawPosText(const void* text,
- size_t byte_length,
- const SkPoint pos[],
- const SkPaint& paint) {
- AutoLogger logger(this);
- JSONObject* params = logger.LogItemWithParams("drawPosText");
- params->SetString("text", StringForText(text, byte_length, paint));
- size_t points_count = paint.countText(text, byte_length);
- params->SetArray("pos", ArrayForSkPoints(points_count, pos));
- params->SetObject("paint", ObjectForSkPaint(paint));
- this->SkCanvas::onDrawPosText(text, byte_length, pos, paint);
-}
-
-void LoggingCanvas::onDrawPosTextH(const void* text,
- size_t byte_length,
- const SkScalar xpos[],
- SkScalar const_y,
- const SkPaint& paint) {
- AutoLogger logger(this);
- JSONObject* params = logger.LogItemWithParams("drawPosTextH");
- params->SetString("text", StringForText(text, byte_length, paint));
- size_t points_count = paint.countText(text, byte_length);
- params->SetArray("xpos", ArrayForSkScalars(points_count, xpos));
- params->SetDouble("constY", const_y);
- params->SetObject("paint", ObjectForSkPaint(paint));
- this->SkCanvas::onDrawPosTextH(text, byte_length, xpos, const_y, paint);
-}
-
void LoggingCanvas::onDrawTextBlob(const SkTextBlob* blob,
SkScalar x,
SkScalar y,
@@ -870,7 +724,7 @@ SkCanvas::SaveLayerStrategy LoggingCanvas::getSaveLayerStrategy(
params->SetObject("bounds", ObjectForSkRect(*rec.fBounds));
if (rec.fPaint)
params->SetObject("paint", ObjectForSkPaint(*rec.fPaint));
- params->SetString("saveFlags", SaveLayerFlagsToString(rec.fSaveLayerFlags));
+ params->SetInteger("saveFlags", static_cast<int>(rec.fSaveLayerFlags));
return this->SkCanvas::getSaveLayerStrategy(rec);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h
index eceee7d8ddd..3951bbf51da 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h
@@ -79,20 +79,6 @@ class LoggingCanvas : public InterceptingCanvasBase {
void onDrawDRRect(const SkRRect& outer,
const SkRRect& inner,
const SkPaint&) override;
- void onDrawText(const void* text,
- size_t byte_length,
- SkScalar x,
- SkScalar y,
- const SkPaint&) override;
- void onDrawPosText(const void* text,
- size_t byte_length,
- const SkPoint pos[],
- const SkPaint&) override;
- void onDrawPosTextH(const void* text,
- size_t byte_length,
- const SkScalar xpos[],
- SkScalar const_y,
- const SkPaint&) override;
void onDrawTextBlob(const SkTextBlob*,
SkScalar x,
SkScalar y,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc
index 76a59a710b6..da6cd935170 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc
@@ -79,7 +79,7 @@ void MailboxTextureHolder::Sync(MailboxSyncMode mode) {
return;
}
- if (!ContextProviderWrapper() || IsAbandoned())
+ if (!ContextProviderWrapper())
return;
TRACE_EVENT0("blink", "MailboxTextureHolder::Sync");
@@ -129,7 +129,7 @@ bool MailboxTextureHolder::IsValid() const {
// Just assume valid. Potential problem will be detected later.
return true;
}
- return !IsAbandoned() && !!ContextProviderWrapper();
+ return !!ContextProviderWrapper();
}
bool MailboxTextureHolder::IsCrossThread() const {
@@ -141,20 +141,18 @@ MailboxTextureHolder::~MailboxTextureHolder() {
new gpu::SyncToken(sync_token_));
std::unique_ptr<gpu::Mailbox> passed_mailbox(new gpu::Mailbox(mailbox_));
- if (!IsAbandoned()) {
- if (texture_thread_task_runner_ &&
- thread_id_ != Thread::Current()->ThreadId()) {
- PostCrossThreadTask(
- *texture_thread_task_runner_, FROM_HERE,
- CrossThreadBind(&ReleaseTexture, is_converted_from_skia_texture_,
- texture_id_, WTF::Passed(std::move(passed_mailbox)),
- WTF::Passed(ContextProviderWrapper()),
- WTF::Passed(std::move(passed_sync_token))));
- } else {
- ReleaseTexture(is_converted_from_skia_texture_, texture_id_,
- std::move(passed_mailbox), ContextProviderWrapper(),
- std::move(passed_sync_token));
- }
+ if (texture_thread_task_runner_ &&
+ thread_id_ != Thread::Current()->ThreadId()) {
+ PostCrossThreadTask(
+ *texture_thread_task_runner_, FROM_HERE,
+ CrossThreadBind(&ReleaseTexture, is_converted_from_skia_texture_,
+ texture_id_, WTF::Passed(std::move(passed_mailbox)),
+ WTF::Passed(ContextProviderWrapper()),
+ WTF::Passed(std::move(passed_sync_token))));
+ } else {
+ ReleaseTexture(is_converted_from_skia_texture_, texture_id_,
+ std::move(passed_mailbox), ContextProviderWrapper(),
+ std::move(passed_sync_token));
}
texture_id_ = 0u; // invalidate the texture.
diff --git a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc
index 378ec6a3fbf..37d3c6c172f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc
@@ -15,6 +15,11 @@ MainThreadMutatorClient::MainThreadMutatorClient(
mutator_->SetClient(this);
}
+void MainThreadMutatorClient::SynchronizeAnimatorName(
+ const String& animator_name) {
+ delegate_->SynchronizeAnimatorName(animator_name);
+}
+
void MainThreadMutatorClient::SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output_state) {
delegate_->SetMutationUpdate(std::move(output_state));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h
index 127d8f3da49..f776791ba10 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h
@@ -20,7 +20,10 @@ class PLATFORM_EXPORT MainThreadMutatorClient : public MutatorClient {
std::unique_ptr<AnimationWorkletMutatorDispatcherImpl>);
~MainThreadMutatorClient() override = default;
+ void SynchronizeAnimatorName(const String& animator_name) override;
void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) override;
+ void NotifyAnimationsPending() override {}
+ void NotifyAnimationsReady() override {}
void SetDelegate(MutatorClient* client);
AnimationWorkletMutatorDispatcherImpl* Mutator() { return mutator_.get(); }
diff --git a/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h b/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h
index b4b5845034f..e83018e168d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -14,7 +15,12 @@ class PLATFORM_EXPORT MutatorClient {
public:
virtual ~MutatorClient() = default;
+ virtual void SynchronizeAnimatorName(const String& animator_name) = 0;
virtual void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) = 0;
+
+ virtual void NotifyAnimationsPending() = 0;
+
+ virtual void NotifyAnimationsReady() = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/README.md b/chromium/third_party/blink/renderer/platform/graphics/paint/README.md
index 26a11012dab..2f2163bceda 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/README.md
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/README.md
@@ -6,18 +6,18 @@ concepts, such as DOM elements and layout objects.
This code is owned by the [paint team][paint-team-site].
-Slimming Paint v2 is currently being implemented. Unlike Slimming Paint v1, SPv2
-represents its paint artifact not as a flat display list, but as a list of
-drawings, and a list of paint chunks, stored together.
+CompositeAfterPaint is currently being implemented. Unlike Slimming Paint v1,
+CompositeAfterPaint represents its paint artifact not as a flat display list,
+but as a list of drawings, and a list of paint chunks, stored together.
-This document explains the SPv2 world as it develops, not the SPv1 world it
-replaces.
+This document explains the CompositeAfterPaint (CAP) world as it develops, not
+the SPv1 world it replaces.
-[paint-team-site]: https://www.chromium.org/developers/paint-team
+[paint-team-site]: https://www.chromium.org/teams/paint-team
## Paint artifact
-The SPv2 [paint artifact](paint_artifact.h) consists of a list of display items
+The CAP [paint artifact](paint_artifact.h) consists of a list of display items
in paint order (ideally mostly or all drawings), partitioned into *paint chunks*
which define certain *paint properties* which affect how the content should be
drawn or composited.
@@ -142,7 +142,7 @@ images.
*** note
It is illegal for there to be two display items with the same ID in a display
item list, except for display items that are marked uncacheable
-(see [DisplayItemCacheSkipper](DisplayItemCacheSkipper.h)).
+(see [DisplayItemCacheSkipper](display_item_cache_skipper.h)).
***
Generally, clients of this code should use stack-allocated recorder classes to
@@ -150,19 +150,19 @@ emit display items to a `PaintController` (using `GraphicsContext`).
### Standalone display items
-#### [DrawingDisplayItem](DrawingDisplayItem.h)
+#### [DrawingDisplayItem](drawing_display_item.h)
Holds a `PaintRecord` which contains the paint operations required to draw some
atom of content.
-#### [ForeignLayerDisplayItem](ForeignLayerDisplayItem.h)
+#### [ForeignLayerDisplayItem](foreign_layer_display_item.h)
Draws an atom of content, but using a `cc::Layer` produced by some agent outside
of the normal Blink paint system (for example, a plugin). Since they always map
to a `cc::Layer`, they are always the only display item in their paint chunk,
and are ineligible for squashing with other layers.
-#### [ScrollHitTestDisplayItem](ScrollHitTestDisplayItem.h)
+#### [ScrollHitTestDisplayItem](scroll_hit_test_display_item.h)
Placeholder for creating a cc::Layer for scrolling in paint order. Hit testing
in the compositor requires both property trees (scroll nodes) and a scrollable
@@ -199,9 +199,9 @@ module using `PaintController` API.
## Paint artifact compositor
-The [`PaintArtifactCompositor`](paint_artifact_compositor.h) is responsible for
-consuming the `PaintArtifact` produced by the `PaintController`, and converting
-it into a form suitable for the compositor to consume.
+[`PaintArtifactCompositor`](../compositing/paint_artifact_compositor.h) is
+responsible for consuming the `PaintArtifact` produced by the `PaintController`,
+and converting it into a form suitable for the compositor to consume.
At present, `PaintArtifactCompositor` creates a cc layer tree, with one layer
for each paint chunk. In the future, it is expected that we will use heuristics
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
index a79f58d730d..44f0dd87053 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
@@ -47,7 +47,7 @@ void CullRect::Move(const IntSize& offset) {
CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
const TransformPaintPropertyNode* transform) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (const auto* scroll = transform->ScrollNode()) {
rect_.Intersect(scroll->ContainerRect());
if (rect_.IsEmpty())
@@ -80,7 +80,7 @@ CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
void CullRect::ApplyTransforms(const TransformPaintPropertyNode* source,
const TransformPaintPropertyNode* destination,
const base::Optional<CullRect>& old_cull_rect) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
Vector<const TransformPaintPropertyNode*> scroll_translations;
for (const auto* t = destination; t != source; t = t->Parent()) {
@@ -115,7 +115,7 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode* source,
}
bool CullRect::ChangedEnough(const CullRect& old_cull_rect) const {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
const auto& new_rect = Rect();
const auto& old_rect = old_cull_rect.Rect();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h
index 73ef85de6e4..375174cf134 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h
@@ -42,8 +42,8 @@ class PLATFORM_EXPORT CullRect {
// Applies one transform to the cull rect. Before this function is called,
// the cull rect is in the space of the parent the transform node.
- // For SlimmingPaintV2, when the transform is a scroll translation, the cull
- // rect is converted in the following steps:
+ // For CompositeAfterPaint, when the transform is a scroll translation, the
+ // cull rect is converted in the following steps:
// 1. it's clipped by the container rect,
// 2. transformed by inverse of the scroll translation,
// 3. expanded by thousands of pixels for composited scrolling.
@@ -51,13 +51,13 @@ class PLATFORM_EXPORT CullRect {
ApplyTransformInternal(transform);
}
- // For SlimmingPaintV2 only. Applies transforms from |source| (not included)
- // to |destination| (included). For each scroll translation, the cull rect is
- // converted as described in ApplyTransform(). If |old_cull_rect| is provided,
- // and the cull rect converted by the last scroll translation doesn't cover
- // the whole scrolling contents, and the new cull rect doesn't change enough
- // (by hundreds of pixels) from |old_cull_rect|, the cull rect will be set to
- // |old_cull_rect| to avoid repaint on each composited scroll.
+ // For CompositeAfterPaint only. Applies transforms from |source| (not
+ // included) to |destination| (included). For each scroll translation, the
+ // cull rect is converted as described in ApplyTransform(). If |old_cull_rect|
+ // is provided, and the cull rect converted by the last scroll translation
+ // doesn't cover the whole scrolling contents, and the new cull rect doesn't
+ // change enough (by hundreds of pixels) from |old_cull_rect|, the cull rect
+ // will be set to |old_cull_rect| to avoid repaint on each composited scroll.
void ApplyTransforms(const TransformPaintPropertyNode* source,
const TransformPaintPropertyNode* destination,
const base::Optional<CullRect>& old_cull_rect);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
index 40081fb82f9..bff6f12945d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
@@ -114,7 +114,7 @@ TEST_F(CullRectTest, ApplyTransformInfinite) {
}
TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50);
@@ -142,7 +142,7 @@ TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
}
TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(200, 100, 40, 50);
@@ -157,7 +157,7 @@ TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
}
TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50);
@@ -184,7 +184,7 @@ TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
}
TEST_F(CullRectTest, ChangedEnoughEmpty) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
EXPECT_FALSE(ChangedEnough(IntRect(), IntRect()));
EXPECT_FALSE(ChangedEnough(IntRect(1, 1, 0, 0), IntRect(2, 2, 0, 0)));
EXPECT_TRUE(ChangedEnough(IntRect(), IntRect(0, 0, 1, 1)));
@@ -192,7 +192,7 @@ TEST_F(CullRectTest, ChangedEnoughEmpty) {
}
TEST_F(CullRectTest, ChangedNotEnough) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
IntRect old_rect(100, 100, 100, 100);
EXPECT_FALSE(ChangedEnough(old_rect, old_rect));
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 90, 90)));
@@ -201,7 +201,7 @@ TEST_F(CullRectTest, ChangedNotEnough) {
}
TEST_F(CullRectTest, ChangedEnoughScrollScenarios) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
IntRect old_rect(100, 100, 100, 100);
IntRect new_rect(old_rect);
new_rect.Move(500, 0);
@@ -215,7 +215,7 @@ TEST_F(CullRectTest, ChangedEnoughScrollScenarios) {
}
TEST_F(CullRectTest, ApplyTransformsSameTransform) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
CullRect cull_rect1(IntRect(1, 1, 50, 50));
@@ -235,7 +235,7 @@ TEST_F(CullRectTest, ApplyTransformsSameTransform) {
}
TEST_F(CullRectTest, ApplyTransformsWithoutScroll) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(10, 20));
@@ -260,7 +260,7 @@ TEST_F(CullRectTest, ApplyTransformsWithoutScroll) {
}
TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
ScrollPaintPropertyNode::State scroll_state;
@@ -290,7 +290,7 @@ TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) {
}
TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
ScrollPaintPropertyNode::State scroll_state;
@@ -326,7 +326,7 @@ TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) {
}
TEST_F(CullRectTest, ApplyTransformsEscapingScroll) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
ScrollPaintPropertyNode::State scroll_state;
@@ -352,7 +352,7 @@ TEST_F(CullRectTest, ApplyTransformsEscapingScroll) {
}
TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
ScrollPaintPropertyNode::State scroll_state1;
@@ -387,7 +387,7 @@ TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) {
}
TEST_F(CullRectTest, ApplyTransformsBigScrollContentsAfterSmallScrollContents) {
- ScopedSlimmingPaintV2ForTest spv2(true);
+ ScopedCompositeAfterPaintForTest cap(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
ScrollPaintPropertyNode::State scroll_state1;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc
index 8077c0e9b3a..9dfd70bbff2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc
@@ -82,7 +82,7 @@ static WTF::String SpecialDrawingTypeAsDebugString(DisplayItem::Type type) {
DEBUG_STRING_CASE(LinkHighlight);
DEBUG_STRING_CASE(ImageAreaFocusRing);
DEBUG_STRING_CASE(OverflowControls);
- DEBUG_STRING_CASE(PageOverlay);
+ DEBUG_STRING_CASE(FrameOverlay);
DEBUG_STRING_CASE(PopupContainerBorder);
DEBUG_STRING_CASE(PopupListBoxBackground);
DEBUG_STRING_CASE(PopupListBoxRow);
@@ -123,6 +123,7 @@ static WTF::String DrawingTypeAsDebugString(DisplayItem::Type type) {
static String ForeignLayerTypeAsDebugString(DisplayItem::Type type) {
switch (type) {
DEBUG_STRING_CASE(ForeignLayerCanvas);
+ DEBUG_STRING_CASE(ForeignLayerDevToolsOverlay);
DEBUG_STRING_CASE(ForeignLayerPlugin);
DEBUG_STRING_CASE(ForeignLayerVideo);
DEBUG_STRING_CASE(ForeignLayerWrapper);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h
index e0ff93900e2..2c5c6bb2bb2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h
@@ -18,14 +18,8 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#endif
-namespace cc {
-class DisplayItemList;
-}
-
namespace blink {
-class GraphicsContext;
-class FloatSize;
enum class PaintPhase;
class PLATFORM_EXPORT DisplayItem {
@@ -75,7 +69,7 @@ class PLATFORM_EXPORT DisplayItem {
kLinkHighlight,
kImageAreaFocusRing,
kOverflowControls,
- kPageOverlay,
+ kFrameOverlay,
kPopupContainerBorder,
kPopupListBoxBackground,
kPopupListBoxRow,
@@ -107,6 +101,7 @@ class PLATFORM_EXPORT DisplayItem {
kForeignLayerFirst,
kForeignLayerCanvas = kForeignLayerFirst,
+ kForeignLayerDevToolsOverlay,
kForeignLayerPlugin,
kForeignLayerVideo,
kForeignLayerWrapper,
@@ -147,11 +142,15 @@ class PLATFORM_EXPORT DisplayItem {
// Some fields are copied from |client|, because we need to access them in
// later paint cycles when |client| may have been destroyed.
- DisplayItem(const DisplayItemClient& client, Type type, size_t derived_size)
+ DisplayItem(const DisplayItemClient& client,
+ Type type,
+ size_t derived_size,
+ bool draws_content = false)
: client_(&client),
visual_rect_(client.VisualRect()),
outset_for_raster_effects_(client.VisualRectOutsetForRasterEffects()),
type_(type),
+ draws_content_(draws_content),
fragment_(0),
is_cacheable_(client.IsCacheable()),
is_tombstone_(false) {
@@ -181,8 +180,6 @@ class PLATFORM_EXPORT DisplayItem {
Id GetId() const { return Id(*client_, GetType(), fragment_); }
- virtual void Replay(GraphicsContext&) const {}
-
const DisplayItemClient& Client() const {
DCHECK(client_);
return *client_;
@@ -216,13 +213,6 @@ class PLATFORM_EXPORT DisplayItem {
fragment_ = fragment;
}
- // Appends this display item to the cc::DisplayItemList, if applicable.
- // |visual_rect_offset| is the offset between the space of the GraphicsLayer
- // which owns the display item and the coordinate space of VisualRect().
- // TODO(wangxianzhu): Remove the parameter for slimming paint v2.
- virtual void AppendToDisplayItemList(const FloatSize& visual_rect_offset,
- cc::DisplayItemList&) const {}
-
// See comments of enum Type for usage of the following macros.
#define DEFINE_CATEGORY_METHODS(Category) \
static constexpr bool Is##Category##Type(Type type) { \
@@ -269,7 +259,7 @@ class PLATFORM_EXPORT DisplayItem {
// DisplayItem.
bool IsTombstone() const { return is_tombstone_; }
- virtual bool DrawsContent() const { return false; }
+ bool DrawsContent() const { return draws_content_; }
#if DCHECK_IS_ON()
static WTF::String TypeAsDebugString(DisplayItem::Type);
@@ -284,18 +274,19 @@ class PLATFORM_EXPORT DisplayItem {
// The default DisplayItem constructor is only used by ContiguousContainer::
// AppendByMoving() where a tombstone DisplayItem is constructed at the source
- // location. Only set is_tombstone_ to true, leaving other fields as-is so
- // that we can get their original values. |visual_rect_| and
- // |outset_for_raster_effects_| are special, see DisplayItemList::
- // AppendByMoving().
- DisplayItem() : is_tombstone_(true) {}
+ // location. Only set draws_content_ to false and is_tombstone_ to true,
+ // leaving other fields as-is so that we can get their original values.
+ // |visual_rect_| and |outset_for_raster_effects_| are special, see
+ // DisplayItemList::AppendByMoving().
+ DisplayItem() : draws_content_(false), is_tombstone_(true) {}
const DisplayItemClient* client_;
FloatRect visual_rect_;
float outset_for_raster_effects_;
- static_assert(kTypeLast < (1 << 8), "DisplayItem::Type should fit in 8 bits");
- unsigned type_ : 8;
+ static_assert(kTypeLast < (1 << 7), "DisplayItem::Type should fit in 7 bits");
+ unsigned type_ : 7;
+ unsigned draws_content_ : 1;
unsigned derived_size_ : 8; // size of the actual derived class
unsigned fragment_ : 14;
unsigned is_cacheable_ : 1;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
index 97ffe553cd1..771392a0137 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
@@ -8,13 +8,15 @@
#include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h"
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
#include "third_party/blink/renderer/platform/testing/test_paint_artifact.h"
namespace blink {
using ::testing::UnorderedElementsAre;
-class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase {
+class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase,
+ public PaintTestConfigurations {
protected:
DisplayItemRasterInvalidatorTest() : invalidator_([](const IntRect&) {}) {}
@@ -26,6 +28,10 @@ class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase {
// invalidation rects.
IntRect(0, 0, 20000, 20000), PropertyTreeState::Root());
GetPaintController().FinishCycle();
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ GetPaintController().ClearPropertyTreeChangedStateTo(
+ PropertyTreeState::Root());
+ }
if (invalidator_.GetTracking())
return invalidator_.GetTracking()->Invalidations();
@@ -37,7 +43,9 @@ class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase {
RasterInvalidator invalidator_;
};
-TEST_F(DisplayItemRasterInvalidatorTest, RemoveItemInMiddle) {
+INSTANTIATE_PAINT_TEST_CASE_P(DisplayItemRasterInvalidatorTest);
+
+TEST_P(DisplayItemRasterInvalidatorTest, RemoveItemInMiddle) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 300, 300));
FakeDisplayItemClient second("second", LayoutRect(100, 100, 200, 200));
GraphicsContext context(GetPaintController());
@@ -60,7 +68,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, RemoveItemInMiddle) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrder) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrder) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200));
FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10));
@@ -91,7 +99,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrder) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateFirst) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateFirst) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200));
FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10));
@@ -117,7 +125,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateFirst) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateSecond) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateSecond) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200));
FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10));
@@ -143,7 +151,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateSecond) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithIncrementalInvalidation) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderWithIncrementalInvalidation) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200));
FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10));
@@ -171,7 +179,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithIncrementalInvalidation) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, NewItemInMiddle) {
+TEST_P(DisplayItemRasterInvalidatorTest, NewItemInMiddle) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200));
FakeDisplayItemClient third("third", LayoutRect(125, 100, 200, 50));
@@ -195,7 +203,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, NewItemInMiddle) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, Incremental) {
+TEST_P(DisplayItemRasterInvalidatorTest, Incremental) {
LayoutRect initial_rect(100, 100, 100, 100);
std::unique_ptr<FakeDisplayItemClient> clients[6];
for (size_t i = 0; i < base::size(clients); i++) {
@@ -259,7 +267,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, Incremental) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, AddRemoveFirstAndInvalidateSecond) {
+TEST_P(DisplayItemRasterInvalidatorTest, AddRemoveFirstAndInvalidateSecond) {
FakeDisplayItemClient chunk("chunk");
FakeDisplayItemClient first("first", LayoutRect(100, 100, 150, 150));
FakeDisplayItemClient second("second", LayoutRect(200, 200, 50, 50));
@@ -304,7 +312,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, AddRemoveFirstAndInvalidateSecond) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, InvalidateFirstAndAddRemoveSecond) {
+TEST_P(DisplayItemRasterInvalidatorTest, InvalidateFirstAndAddRemoveSecond) {
FakeDisplayItemClient first("first", LayoutRect(100, 100, 150, 150));
FakeDisplayItemClient second("second", LayoutRect(200, 200, 50, 50));
GraphicsContext context(GetPaintController());
@@ -351,7 +359,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, InvalidateFirstAndAddRemoveSecond) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildren) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderWithChildren) {
FakeDisplayItemClient container1("container1",
LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient content1("content1", LayoutRect(100, 100, 50, 200));
@@ -395,7 +403,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildren) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildrenAndInvalidation) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderWithChildrenAndInvalidation) {
FakeDisplayItemClient container1("container1",
LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient content1("content1", LayoutRect(100, 100, 50, 200));
@@ -443,7 +451,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildrenAndInvalidation) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderCrossingChunks) {
+TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderCrossingChunks) {
FakeDisplayItemClient container1("container1",
LayoutRect(100, 100, 100, 100));
FakeDisplayItemClient content1("content1", LayoutRect(100, 100, 50, 200));
@@ -492,7 +500,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderCrossingChunks) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, SkipCache) {
+TEST_P(DisplayItemRasterInvalidatorTest, SkipCache) {
FakeDisplayItemClient multicol("multicol", LayoutRect(100, 100, 200, 200));
FakeDisplayItemClient content("content", LayoutRect(100, 100, 100, 100));
GraphicsContext context(GetPaintController());
@@ -549,7 +557,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SkipCache) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, PartialSkipCache) {
+TEST_P(DisplayItemRasterInvalidatorTest, PartialSkipCache) {
FakeDisplayItemClient content("content", LayoutRect(100, 100, 250, 250));
GraphicsContext context(GetPaintController());
@@ -581,7 +589,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, PartialSkipCache) {
invalidator_.SetTracksRasterInvalidations(false);
}
-TEST_F(DisplayItemRasterInvalidatorTest, Partial) {
+TEST_P(DisplayItemRasterInvalidatorTest, Partial) {
FakeDisplayItemClient client("client", LayoutRect(100, 100, 300, 300));
GraphicsContext context(GetPaintController());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
index a9bf22f86f7..750ac8d93eb 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
@@ -13,28 +13,6 @@
namespace blink {
-void DrawingDisplayItem::Replay(GraphicsContext& context) const {
- if (record_)
- context.DrawRecord(record_);
-}
-
-void DrawingDisplayItem::AppendToDisplayItemList(
- const FloatSize& visual_rect_offset,
- cc::DisplayItemList& list) const {
- if (record_) {
- list.StartPaint();
- list.push<cc::DrawRecordOp>(record_);
- // Convert visual rect into the GraphicsLayer's coordinate space.
- auto visual_rect = VisualRect();
- visual_rect.Move(-visual_rect_offset);
- list.EndPaintOfUnpaired(EnclosingIntRect(visual_rect));
- }
-}
-
-bool DrawingDisplayItem::DrawsContent() const {
- return record_.get();
-}
-
#if DCHECK_IS_ON()
void DrawingDisplayItem::PropertiesAsJSON(JSONObject& json) const {
DisplayItem::PropertiesAsJSON(json);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
index dd79922e214..9f3c691c5ff 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
@@ -33,15 +33,10 @@ class PLATFORM_EXPORT DrawingDisplayItem final : public DisplayItem {
sk_sp<const PaintRecord> record,
bool known_to_be_opaque = false);
- void Replay(GraphicsContext&) const final;
- void AppendToDisplayItemList(const FloatSize& visual_rect_offset,
- cc::DisplayItemList&) const final;
- bool DrawsContent() const final;
-
const sk_sp<const PaintRecord>& GetPaintRecord() const { return record_; }
bool KnownToBeOpaque() const {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
return known_to_be_opaque_;
}
@@ -54,7 +49,7 @@ class PLATFORM_EXPORT DrawingDisplayItem final : public DisplayItem {
sk_sp<const PaintRecord> record_;
- // True if there are no transparent areas. Only used for SlimmingPaintV2.
+ // True if there are no transparent areas. Only used for CompositeAfterPaint.
const bool known_to_be_opaque_;
};
@@ -64,8 +59,11 @@ inline DrawingDisplayItem::DrawingDisplayItem(const DisplayItemClient& client,
Type type,
sk_sp<const PaintRecord> record,
bool known_to_be_opaque)
- : DisplayItem(client, type, sizeof(*this)),
- record_(record && record->size() ? std::move(record) : nullptr),
+ : DisplayItem(client,
+ type,
+ sizeof(*this),
+ /* draws_content*/ record && record->size()),
+ record_(DrawsContent() ? std::move(record) : nullptr),
known_to_be_opaque_(known_to_be_opaque) {
DCHECK(IsDrawingType(type));
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc
index 36d2fab5b7c..bde9029d80d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc
@@ -45,7 +45,7 @@ static sk_sp<PaintRecord> CreateRectRecordWithTranslate(
return recorder.finishRecordingAsPicture();
}
-TEST_F(DrawingDisplayItemTest, VisualRectAndDrawingBounds) {
+TEST_F(DrawingDisplayItemTest, DrawsContent) {
FloatRect record_bounds(5.5, 6.6, 7.7, 8.8);
LayoutRect drawing_bounds(record_bounds);
client_.SetVisualRect(drawing_bounds);
@@ -53,18 +53,19 @@ TEST_F(DrawingDisplayItemTest, VisualRectAndDrawingBounds) {
DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground,
CreateRectRecord(record_bounds));
EXPECT_EQ(FloatRect(drawing_bounds), item.VisualRect());
+ EXPECT_TRUE(item.DrawsContent());
+}
- auto list1 = base::MakeRefCounted<cc::DisplayItemList>();
- item.AppendToDisplayItemList(FloatSize(), *list1);
- EXPECT_EQ(EnclosingIntRect(drawing_bounds), list1->VisualRectForTesting(0));
-
- FloatSize offset(2.1, 3.6);
- auto list2 = base::MakeRefCounted<cc::DisplayItemList>();
- item.AppendToDisplayItemList(offset, *list2);
- FloatRect visual_rect_with_offset(drawing_bounds);
- visual_rect_with_offset.Move(-offset);
- EXPECT_EQ(EnclosingIntRect(visual_rect_with_offset),
- list2->VisualRectForTesting(0));
+TEST_F(DrawingDisplayItemTest, NullPaintRecord) {
+ DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground,
+ nullptr);
+ EXPECT_FALSE(item.DrawsContent());
+}
+
+TEST_F(DrawingDisplayItemTest, EmptyPaintRecord) {
+ DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground,
+ sk_make_sp<PaintRecord>());
+ EXPECT_FALSE(item.DrawsContent());
}
TEST_F(DrawingDisplayItemTest, Equals) {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h
index e51a61abb9f..260e452548f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h
@@ -51,7 +51,7 @@ class PLATFORM_EXPORT DrawingRecorder final {
~DrawingRecorder();
void SetKnownToBeOpaque() {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
known_to_be_opaque_ = true;
}
@@ -60,7 +60,7 @@ class PLATFORM_EXPORT DrawingRecorder final {
const DisplayItemClient& client_;
const DisplayItem::Type type_;
- // True if there are no transparent areas. Only used for SlimmingPaintV2.
+ // True if there are no transparent areas. Only used for CompositeAfterPaint.
bool known_to_be_opaque_;
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h b/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
index 09473c1ccdc..636a087901e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
@@ -44,6 +44,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
CompositorFilterOperations filter;
float opacity = 1;
CompositorFilterOperations backdrop_filter;
+ gfx::RectF backdrop_filter_bounds;
SkBlendMode blend_mode = SkBlendMode::kSrcOver;
// === End of effects ===
CompositingReasons direct_compositing_reasons = CompositingReason::kNone;
@@ -56,6 +57,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
output_clip == o.output_clip && color_filter == o.color_filter &&
filter == o.filter && opacity == o.opacity &&
backdrop_filter == o.backdrop_filter &&
+ backdrop_filter_bounds == o.backdrop_filter_bounds &&
blend_mode == o.blend_mode &&
direct_compositing_reasons == o.direct_compositing_reasons &&
compositor_element_id == o.compositor_element_id &&
@@ -130,6 +132,10 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
return state_.backdrop_filter;
}
+ const gfx::RectF& BackdropFilterBounds() const {
+ return state_.backdrop_filter_bounds;
+ }
+
bool HasFilterThatMovesPixels() const {
DCHECK(!Parent() || !IsParentAlias());
return state_.filter.HasFilterThatMovesPixels();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
index 810f41d8b6c..5e57ee51738 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
@@ -18,7 +18,9 @@ namespace {
class ForeignLayerDisplayItemClient final : public DisplayItemClient {
public:
ForeignLayerDisplayItemClient(scoped_refptr<cc::Layer> layer)
- : layer_(std::move(layer)) {}
+ : layer_(std::move(layer)) {
+ Invalidate(PaintInvalidationReason::kUncacheable);
+ }
String DebugName() const final { return "ForeignLayer"; }
@@ -41,10 +43,11 @@ ForeignLayerDisplayItem::ForeignLayerDisplayItem(Type type,
: DisplayItem(*new ForeignLayerDisplayItemClient(std::move(layer)),
type,
sizeof(*this)) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled());
DCHECK(IsForeignLayerType(type));
DCHECK(GetLayer());
+ DCHECK(!IsCacheable());
}
ForeignLayerDisplayItem::~ForeignLayerDisplayItem() {
@@ -55,22 +58,8 @@ cc::Layer* ForeignLayerDisplayItem::GetLayer() const {
return static_cast<const ForeignLayerDisplayItemClient&>(Client()).GetLayer();
}
-void ForeignLayerDisplayItem::Replay(GraphicsContext&) const {
- NOTREACHED();
-}
-
-void ForeignLayerDisplayItem::AppendToDisplayItemList(
- const FloatSize&,
- cc::DisplayItemList&) const {
- NOTREACHED();
-}
-
-bool ForeignLayerDisplayItem::DrawsContent() const {
- return false;
-}
-
bool ForeignLayerDisplayItem::Equals(const DisplayItem& other) const {
- return DisplayItem::Equals(other) &&
+ return GetType() == other.GetType() &&
GetLayer() ==
static_cast<const ForeignLayerDisplayItem&>(other).GetLayer();
}
@@ -84,13 +73,26 @@ void ForeignLayerDisplayItem::PropertiesAsJSON(JSONObject& json) const {
void RecordForeignLayer(GraphicsContext& context,
DisplayItem::Type type,
- scoped_refptr<cc::Layer> layer) {
+ scoped_refptr<cc::Layer> layer,
+ const base::Optional<PropertyTreeState>& properties) {
PaintController& paint_controller = context.GetPaintController();
if (paint_controller.DisplayItemConstructionIsDisabled())
return;
+ // This is like ScopedPaintChunkProperties but uses null id because foreign
+ // layer chunk doesn't need an id nor a client.
+ base::Optional<PropertyTreeState> previous_properties;
+ if (properties) {
+ previous_properties.emplace(paint_controller.CurrentPaintChunkProperties());
+ paint_controller.UpdateCurrentPaintChunkProperties(base::nullopt,
+ *properties);
+ }
paint_controller.CreateAndAppend<ForeignLayerDisplayItem>(type,
std::move(layer));
+ if (properties) {
+ paint_controller.UpdateCurrentPaintChunkProperties(base::nullopt,
+ *previous_properties);
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h
index 6b42d096d78..19765ba0ce6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h
@@ -7,6 +7,7 @@
#include "cc/layers/layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item.h"
+#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
#include "third_party/blink/renderer/platform/platform_export.h"
namespace blink {
@@ -17,7 +18,7 @@ class GraphicsContext;
// A client supplies a layer which can be unwrapped and inserted into the full
// layer tree.
//
-// Before SPv2, this content is not painted, but is instead inserted into the
+// Before CAP, this content is not painted, but is instead inserted into the
// GraphicsLayer tree.
class PLATFORM_EXPORT ForeignLayerDisplayItem final : public DisplayItem {
public:
@@ -27,10 +28,6 @@ class PLATFORM_EXPORT ForeignLayerDisplayItem final : public DisplayItem {
cc::Layer* GetLayer() const;
// DisplayItem
- void Replay(GraphicsContext&) const override;
- void AppendToDisplayItemList(const FloatSize&,
- cc::DisplayItemList&) const override;
- bool DrawsContent() const override;
bool Equals(const DisplayItem&) const override;
#if DCHECK_IS_ON()
void PropertiesAsJSON(JSONObject&) const override;
@@ -39,9 +36,11 @@ class PLATFORM_EXPORT ForeignLayerDisplayItem final : public DisplayItem {
// Records a foreign layer into a GraphicsContext.
// Use this where you would use a recorder class.
-PLATFORM_EXPORT void RecordForeignLayer(GraphicsContext&,
- DisplayItem::Type,
- scoped_refptr<cc::Layer>);
+PLATFORM_EXPORT void RecordForeignLayer(
+ GraphicsContext&,
+ DisplayItem::Type,
+ scoped_refptr<cc::Layer>,
+ const base::Optional<PropertyTreeState>& = base::nullopt);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc
index 24bae6a33f5..914e5dbd380 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc
@@ -233,10 +233,10 @@ bool GeometryMapper::LocalToAncestorVisualRectInternal(
return !rect_to_map.Rect().IsEmpty();
}
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// On SPv1 we may fail when the paint invalidation container creates an
// overflow clip (in ancestor_state) which is not in localState of an
- // out-of-flow positioned descendant. See crbug.com/513108 and layout test
+ // out-of-flow positioned descendant. See crbug.com/513108 and web test
// compositing/overflow/handle-non-ancestor-clip-parent.html (run with
// --enable-prefer-compositing-to-lcd-text) for details.
// Ignore it for SPv1 for now.
@@ -366,7 +366,7 @@ FloatClipRect GeometryMapper::LocalToAncestorClipRectInternal(
}
if (!clip_node) {
success = false;
- if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// On SPv1 we may fail when the paint invalidation container creates an
// overflow clip (in ancestor_state) which is not in localState of an
// out-of-flow positioned descendant. See crbug.com/513108 and layout
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc
index 4803e356871..4111f356e8a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc
@@ -656,7 +656,7 @@ TEST_P(GeometryMapperTest, SiblingTransformsWithClip) {
// Fails, because the clip of the destination state is not an ancestor of the
// clip of the source state. A known bug in SPv1 would make such query,
// in such case, no clips are applied.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_FALSE(success);
} else {
EXPECT_TRUE(success);
@@ -789,8 +789,8 @@ TEST_P(GeometryMapperTest, ReflectionWithPaintOffset) {
}
TEST_P(GeometryMapperTest, InvertedClip) {
- // This test is invalid for SPv2.
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ // This test is invalid for CAP.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
auto clip = CreateClip(c0(), &t0(), FloatRoundedRect(10, 10, 50, 50));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h
index 51af360bd8f..9fbce5ff645 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h
@@ -11,6 +11,8 @@
namespace blink {
+class GraphicsContext;
+
// A special DisplayItem containing hit test data.
class PLATFORM_EXPORT HitTestDisplayItem final : public DisplayItem {
public:
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
index f4d24ceb026..450676174ee 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
@@ -30,7 +30,8 @@ void ComputeChunkDerivedData(const DisplayItemList& display_items,
chunk.outset_for_raster_effects = std::max(chunk.outset_for_raster_effects,
item.OutsetForRasterEffects());
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && item.IsDrawing()) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ item.IsDrawing()) {
const auto& drawing = static_cast<const DrawingDisplayItem&>(item);
if (drawing.GetPaintRecord() && drawing.KnownToBeOpaque()) {
known_to_be_opaque_region.op(
@@ -100,7 +101,7 @@ void PaintArtifact::AppendDebugDrawing(
const PropertyTreeState& property_tree_state) {
DEFINE_STATIC_LOCAL(DebugDrawingClient, debug_drawing_client, ());
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
auto& display_item =
display_item_list_.AllocateAndConstruct<DrawingDisplayItem>(
debug_drawing_client, DisplayItem::kDebugDrawing, std::move(record));
@@ -121,20 +122,17 @@ void PaintArtifact::Replay(cc::PaintCanvas& canvas,
const PropertyTreeState& replay_state,
const IntPoint& offset) const {
TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay");
- scoped_refptr<cc::DisplayItemList> display_item_list =
- PaintChunksToCcLayer::Convert(
- PaintChunks(), replay_state, gfx::Vector2dF(offset.X(), offset.Y()),
- GetDisplayItemList(),
- cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
- canvas.drawPicture(display_item_list->ReleaseAsRecord());
+ canvas.drawPicture(GetPaintRecord(replay_state, offset));
}
-DISABLE_CFI_PERF
-void PaintArtifact::AppendToDisplayItemList(const FloatSize& visual_rect_offset,
- cc::DisplayItemList& list) const {
- TRACE_EVENT0("blink,benchmark", "PaintArtifact::AppendToDisplayItemList");
- for (const DisplayItem& item : display_item_list_)
- item.AppendToDisplayItemList(visual_rect_offset, list);
+sk_sp<PaintRecord> PaintArtifact::GetPaintRecord(
+ const PropertyTreeState& replay_state,
+ const IntPoint& offset) const {
+ return PaintChunksToCcLayer::Convert(
+ PaintChunks(), replay_state,
+ gfx::Vector2dF(offset.X(), offset.Y()), GetDisplayItemList(),
+ cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)
+ ->ReleaseAsRecord();
}
void PaintArtifact::FinishCycle() {
@@ -142,7 +140,8 @@ void PaintArtifact::FinishCycle() {
// for clearing the property tree changed state at the end of paint instead of
// in FinishCycle. See: LocalFrameView::RunPaintLifecyclePhase.
bool clear_property_tree_changed =
- !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled();
+ !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled();
for (auto& chunk : chunks_) {
chunk.client_is_just_created = false;
if (clear_property_tree_changed)
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
index a4fe34d21c8..8420222bab6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
@@ -81,9 +81,8 @@ class PLATFORM_EXPORT PaintArtifact final : public RefCounted<PaintArtifact> {
const PropertyTreeState& replay_state,
const IntPoint& offset = IntPoint()) const;
- // Writes the paint artifact into a cc::DisplayItemList.
- void AppendToDisplayItemList(const FloatSize& visual_rect_offset,
- cc::DisplayItemList& display_list) const;
+ sk_sp<PaintRecord> GetPaintRecord(const PropertyTreeState& replay_state,
+ const IntPoint& offset = IntPoint()) const;
// Called when the caller finishes updating a full document life cycle.
// Will cleanup data (e.g. raster invalidations) that will no longer be used
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h
index 4c8bb2876bc..e60c767797e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h
@@ -37,7 +37,14 @@ struct PLATFORM_EXPORT PaintChunk {
id(id),
properties(props),
is_cacheable(id.client.IsCacheable()),
- client_is_just_created(id.client.IsJustCreated()) {}
+ client_is_just_created(id.client.IsJustCreated()) {
+ // PaintChunk properties should not be null. If these checks are hit,
+ // we may be missing a call to ScopedPaintChunkProperties, see comment in
+ // PaintChunker::IncrementDisplayItemIndex for more information.
+ CHECK(props.Transform());
+ CHECK(props.Clip());
+ CHECK(props.Effect());
+ }
size_t size() const {
DCHECK_GE(end_index, begin_index);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc
index a96ab6fc5fa..b1c253ed477 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc
@@ -33,12 +33,6 @@ class TestChunkerDisplayItem : public DisplayItem {
TestChunkerDisplayItem(const DisplayItemClient& client,
DisplayItem::Type type = DisplayItem::kDrawingFirst)
: DisplayItem(client, type, sizeof(*this)) {}
-
- void Replay(GraphicsContext&) const final { NOTREACHED(); }
- void AppendToDisplayItemList(const FloatSize&,
- cc::DisplayItemList&) const final {
- NOTREACHED();
- }
};
class TestDisplayItemRequiringSeparateChunk : public TestChunkerDisplayItem {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
index 8af002eccdf..dc1799edeef 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -258,12 +258,12 @@ DisplayItem& PaintController::MoveItemFromCurrentListToNewList(size_t index) {
}
void PaintController::InvalidateAll() {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
InvalidateAllInternal();
}
void PaintController::InvalidateAllInternal() {
- // TODO(wangxianzhu): Rename this to InvalidateAllForTesting() for SPv2.
+ // TODO(wangxianzhu): Rename this to InvalidateAllForTesting() for CAP.
// Can only be called during layout/paintInvalidation, not during painting.
DCHECK(new_display_item_list_.IsEmpty());
current_paint_artifact_ = PaintArtifact::Empty();
@@ -272,7 +272,7 @@ void PaintController::InvalidateAllInternal() {
}
bool PaintController::CacheIsAllInvalid() const {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
DCHECK(!cache_is_all_invalid_ || current_paint_artifact_->IsEmpty());
return cache_is_all_invalid_;
}
@@ -588,7 +588,7 @@ size_t PaintController::ApproximateUnsharedMemoryUsage() const {
void PaintController::AppendDebugDrawingAfterCommit(
sk_sp<const PaintRecord> record,
const PropertyTreeState& property_tree_state) {
- DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
DCHECK(new_display_item_list_.IsEmpty());
current_paint_artifact_->AppendDebugDrawing(record, property_tree_state);
}
@@ -718,6 +718,9 @@ void PaintController::CheckDuplicatePaintChunkId(const PaintChunk::Id& id) {
if (IsSkippingCache())
return;
+ if (DisplayItem::IsForeignLayerType(id.type))
+ return;
+
auto it = new_paint_chunk_indices_by_client_.find(&id.client);
if (it != new_paint_chunk_indices_by_client_.end()) {
const auto& indices = it->value;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
index ad521693437..79d6e952277 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
@@ -35,10 +35,10 @@ INSTANTIATE_TEST_CASE_P(
PaintControllerTest,
testing::Values(0,
kBlinkGenPropertyTrees,
- kSlimmingPaintV2,
+ kCompositeAfterPaint,
kUnderInvalidationChecking,
kBlinkGenPropertyTrees | kUnderInvalidationChecking,
- kSlimmingPaintV2 | kUnderInvalidationChecking));
+ kCompositeAfterPaint | kUnderInvalidationChecking));
TEST_P(PaintControllerTest, NestedRecorders) {
GraphicsContext context(GetPaintController());
@@ -1453,7 +1453,7 @@ TEST_P(PaintControllerTest, BeginAndEndFrame) {
}
TEST_P(PaintControllerTest, InvalidateAll) {
- if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
EXPECT_TRUE(GetPaintController().CacheIsAllInvalid());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h
index 46899a783e8..06ec28e1666 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h
@@ -12,7 +12,7 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#if DCHECK_IS_ON()
-#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#endif
@@ -208,7 +208,7 @@ class PropertyTreePrinter {
return node;
}
- ListHashSet<const NodeType*> nodes_;
+ LinkedHashSet<const NodeType*> nodes_;
};
template <typename NodeType>
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
index 239f61dc8c5..2787d1ac80b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
@@ -48,11 +48,9 @@ PaintRecordBuilder::~PaintRecordBuilder() = default;
sk_sp<PaintRecord> PaintRecordBuilder::EndRecording(
const PropertyTreeState& replay_state) {
- context_->BeginRecording(FloatRect());
paint_controller_->CommitNewDisplayItems();
paint_controller_->FinishCycle();
- paint_controller_->GetPaintArtifact().Replay(*context_, replay_state);
- return context_->EndRecording();
+ return paint_controller_->GetPaintArtifact().GetPaintRecord(replay_state);
}
void PaintRecordBuilder::EndRecording(cc::PaintCanvas& canvas,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h
index 2ddaae4f2f8..22c55278198 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h
@@ -37,6 +37,8 @@ class PLATFORM_EXPORT PaintRecordBuilder final : public DisplayItemClient {
// transient PaintController is used for the duration of the picture building,
// which therefore has no caching. It also resets paint chunk state to
// PropertyTreeState::Root() before beginning to record.
+ // TODO(wangxianzhu): Remove the input PaintController feature for
+ // CompositeAfterPaint.
PaintRecordBuilder(SkMetaData* metadata = nullptr,
GraphicsContext* containing_context = nullptr,
PaintController* = nullptr);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h
index 1ba66b364d8..a80539f573f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h
@@ -31,7 +31,7 @@ struct RasterInvalidationInfo {
// died.
const DisplayItemClient* client = nullptr;
String client_debug_name;
- // For SPv2, this is set in PaintArtifactCompositor when converting chunk
+ // For CAP, this is set in PaintArtifactCompositor when converting chunk
// raster invalidations to cc raster invalidations.
IntRect rect;
PaintInvalidationReason reason = PaintInvalidationReason::kFull;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc
index e33be29d177..b985689d0fe 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc
@@ -160,6 +160,10 @@ void RasterInvalidator::GenerateRasterInvalidations(
mapper.SwitchToChunk(new_chunk);
auto& new_chunk_info = new_chunks_info.emplace_back(*this, mapper, it);
+ // Foreign layers take care of raster invalidation by themselves.
+ if (DisplayItem::IsForeignLayerType(new_chunk.id.type))
+ continue;
+
if (!new_chunk.is_cacheable) {
AddRasterInvalidation(new_chunk_info.bounds_in_layer, new_chunk.id.client,
PaintInvalidationReason::kChunkUncacheable,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc
index 13cbaaab2ea..6a7e25139ad 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc
@@ -8,13 +8,15 @@
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
#include "third_party/blink/renderer/platform/testing/test_paint_artifact.h"
namespace blink {
static const IntRect kDefaultLayerBounds(-9999, -7777, 18888, 16666);
-class RasterInvalidatorTest : public testing::Test {
+class RasterInvalidatorTest : public testing::Test,
+ public PaintTestConfigurations {
public:
static PropertyTreeState DefaultPropertyTreeState() {
return PropertyTreeState::Root();
@@ -31,6 +33,11 @@ class RasterInvalidatorTest : public testing::Test {
void FinishCycle(PaintArtifact& artifact) {
artifact.FinishCycle();
ClearGeometryMapperCache();
+ if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+ // See PaintArtifact::FinishCycle() for the reason of doing this.
+ for (auto& chunk : artifact.PaintChunks())
+ chunk.properties.ClearChangedToRoot();
+ }
}
static const Vector<RasterInvalidationInfo> TrackedRasterInvalidations(
@@ -54,6 +61,8 @@ class RasterInvalidatorTest : public testing::Test {
[](const IntRect& rect) {};
};
+INSTANTIATE_PAINT_TEST_CASE_P(RasterInvalidatorTest);
+
#define EXPECT_CHUNK_INVALIDATION_CUSTOM( \
invalidations, index, chunk, expected_reason, layer_offset, mapper) \
do { \
@@ -78,7 +87,7 @@ class RasterInvalidatorTest : public testing::Test {
EXPECT_EQ(PaintInvalidationReason::kIncremental, info.reason); \
} while (false)
-TEST_F(RasterInvalidatorTest, ImplicitFullLayerInvalidation) {
+TEST_P(RasterInvalidatorTest, ImplicitFullLayerInvalidation) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact = TestPaintArtifact().Chunk(0).Build();
@@ -94,7 +103,7 @@ TEST_F(RasterInvalidatorTest, ImplicitFullLayerInvalidation) {
invalidator.SetTracksRasterInvalidations(false);
}
-TEST_F(RasterInvalidatorTest, LayerBounds) {
+TEST_P(RasterInvalidatorTest, LayerBounds) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact = TestPaintArtifact().Chunk(0).Build();
@@ -122,7 +131,7 @@ TEST_F(RasterInvalidatorTest, LayerBounds) {
FinishCycle(*artifact);
}
-TEST_F(RasterInvalidatorTest, ReorderChunks) {
+TEST_P(RasterInvalidatorTest, ReorderChunks) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact = TestPaintArtifact().Chunk(0).Chunk(1).Chunk(2).Build();
invalidator.Generate(artifact, kDefaultLayerBounds,
@@ -150,7 +159,7 @@ TEST_F(RasterInvalidatorTest, ReorderChunks) {
FinishCycle(*new_artifact);
}
-TEST_F(RasterInvalidatorTest, ReorderChunkSubsequences) {
+TEST_P(RasterInvalidatorTest, ReorderChunkSubsequences) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact =
TestPaintArtifact().Chunk(0).Chunk(1).Chunk(2).Chunk(3).Chunk(4).Build();
@@ -185,7 +194,7 @@ TEST_F(RasterInvalidatorTest, ReorderChunkSubsequences) {
FinishCycle(*new_artifact);
}
-TEST_F(RasterInvalidatorTest, ChunkAppearAndDisappear) {
+TEST_P(RasterInvalidatorTest, ChunkAppearAndDisappear) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact = TestPaintArtifact().Chunk(0).Chunk(1).Chunk(2).Build();
invalidator.Generate(artifact, kDefaultLayerBounds,
@@ -210,7 +219,7 @@ TEST_F(RasterInvalidatorTest, ChunkAppearAndDisappear) {
FinishCycle(*new_artifact);
}
-TEST_F(RasterInvalidatorTest, ChunkAppearAtEnd) {
+TEST_P(RasterInvalidatorTest, ChunkAppearAtEnd) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact = TestPaintArtifact().Chunk(0).Build();
invalidator.Generate(artifact, kDefaultLayerBounds,
@@ -230,7 +239,7 @@ TEST_F(RasterInvalidatorTest, ChunkAppearAtEnd) {
FinishCycle(*new_artifact);
}
-TEST_F(RasterInvalidatorTest, UncacheableChunks) {
+TEST_P(RasterInvalidatorTest, UncacheableChunks) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto artifact =
TestPaintArtifact().Chunk(0).Chunk(1).Uncacheable().Chunk(2).Build();
@@ -254,7 +263,7 @@ TEST_F(RasterInvalidatorTest, UncacheableChunks) {
}
// Tests the path based on ClipPaintPropertyNode::Changed().
-TEST_F(RasterInvalidatorTest, ClipPropertyChangeRounded) {
+TEST_P(RasterInvalidatorTest, ClipPropertyChangeRounded) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
FloatRoundedRect::Radii radii(FloatSize(1, 2), FloatSize(2, 3),
FloatSize(3, 4), FloatSize(4, 5));
@@ -316,7 +325,7 @@ TEST_F(RasterInvalidatorTest, ClipPropertyChangeRounded) {
}
// Tests the path detecting change of PaintChunkInfo::chunk_to_layer_clip.
-TEST_F(RasterInvalidatorTest, ClipPropertyChangeSimple) {
+TEST_P(RasterInvalidatorTest, ClipPropertyChangeSimple) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
FloatRoundedRect clip_rect(-1000, -1000, 2000, 2000);
auto clip0 = CreateClip(c0(), &t0(), clip_rect);
@@ -385,7 +394,7 @@ TEST_F(RasterInvalidatorTest, ClipPropertyChangeSimple) {
FinishCycle(*artifact);
}
-TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChange) {
+TEST_P(RasterInvalidatorTest, ClipLocalTransformSpaceChange) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto t1 = CreateTransform(t0(), TransformationMatrix());
@@ -422,7 +431,7 @@ TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChange) {
// This is based on ClipLocalTransformSpaceChange, but tests the no-invalidation
// path by letting the clip's LocalTransformSpace be the same as the chunk's
// transform.
-TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChangeNoInvalidation) {
+TEST_P(RasterInvalidatorTest, ClipLocalTransformSpaceChangeNoInvalidation) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto t1 = CreateTransform(t0(), TransformationMatrix());
@@ -453,7 +462,7 @@ TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChangeNoInvalidation) {
FinishCycle(*artifact);
}
-TEST_F(RasterInvalidatorTest, TransformPropertyChange) {
+TEST_P(RasterInvalidatorTest, TransformPropertyChange) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto layer_transform = CreateTransform(t0(), TransformationMatrix().Scale(5));
@@ -534,7 +543,7 @@ TEST_F(RasterInvalidatorTest, TransformPropertyChange) {
FinishCycle(*artifact);
}
-TEST_F(RasterInvalidatorTest, TransformPropertyTinyChange) {
+TEST_P(RasterInvalidatorTest, TransformPropertyTinyChange) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto layer_transform = CreateTransform(t0(), TransformationMatrix().Scale(5));
@@ -580,7 +589,7 @@ TEST_F(RasterInvalidatorTest, TransformPropertyTinyChange) {
EXPECT_TRUE(invalidated);
}
-TEST_F(RasterInvalidatorTest, TransformPropertyTinyChangeScale) {
+TEST_P(RasterInvalidatorTest, TransformPropertyTinyChangeScale) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto layer_transform = CreateTransform(t0(), TransformationMatrix().Scale(5));
@@ -621,7 +630,7 @@ TEST_F(RasterInvalidatorTest, TransformPropertyTinyChangeScale) {
FinishCycle(*artifact);
}
-TEST_F(RasterInvalidatorTest, EffectLocalTransformSpaceChange) {
+TEST_P(RasterInvalidatorTest, EffectLocalTransformSpaceChange) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto t1 = CreateTransform(t0(), TransformationMatrix());
@@ -659,7 +668,7 @@ TEST_F(RasterInvalidatorTest, EffectLocalTransformSpaceChange) {
// This is based on EffectLocalTransformSpaceChange, but tests the no-
// invalidation path by letting the effect's LocalTransformSpace be the same as
// the chunk's transform.
-TEST_F(RasterInvalidatorTest, EffectLocalTransformSpaceChangeNoInvalidation) {
+TEST_P(RasterInvalidatorTest, EffectLocalTransformSpaceChangeNoInvalidation) {
RasterInvalidator invalidator(kNoopRasterInvalidation);
auto t1 = CreateTransform(t0(), TransformationMatrix());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc
index aa79d6d87d4..d5631ea7653 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc
@@ -15,23 +15,13 @@ ScrollHitTestDisplayItem::ScrollHitTestDisplayItem(
const TransformPaintPropertyNode& scroll_offset_node)
: DisplayItem(client, kScrollHitTest, sizeof(*this)),
scroll_offset_node_(scroll_offset_node) {
- DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
// The scroll offset transform node should have an associated scroll node.
DCHECK(scroll_offset_node_.ScrollNode());
}
ScrollHitTestDisplayItem::~ScrollHitTestDisplayItem() = default;
-void ScrollHitTestDisplayItem::Replay(GraphicsContext&) const {
- NOTREACHED();
-}
-
-void ScrollHitTestDisplayItem::AppendToDisplayItemList(
- const FloatSize&,
- cc::DisplayItemList&) const {
- NOTREACHED();
-}
-
bool ScrollHitTestDisplayItem::Equals(const DisplayItem& other) const {
return DisplayItem::Equals(other) &&
&scroll_node() ==
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h
index 4642790e9f8..082b202de2a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h
@@ -34,9 +34,6 @@ class PLATFORM_EXPORT ScrollHitTestDisplayItem final : public DisplayItem {
}
// DisplayItem
- void Replay(GraphicsContext&) const override;
- void AppendToDisplayItemList(const FloatSize&,
- cc::DisplayItemList&) const override;
bool Equals(const DisplayItem&) const override;
#if DCHECK_IS_ON()
void PropertiesAsJSON(JSONObject&) const override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/path.cc b/chromium/third_party/blink/renderer/platform/graphics/path.cc
index cde993cb82c..f8c90391af9 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/path.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/path.cc
@@ -353,13 +353,10 @@ void Path::AddEllipse(const FloatPoint& p,
float radius_x,
float radius_y,
float start_angle,
- float end_angle,
- bool anticlockwise) {
+ float end_angle) {
DCHECK(EllipseIsRenderable(start_angle, end_angle));
DCHECK_GE(start_angle, 0);
DCHECK_LT(start_angle, kTwoPiFloat);
- DCHECK((anticlockwise && (start_angle - end_angle) >= 0) ||
- (!anticlockwise && (end_angle - start_angle) >= 0));
SkScalar cx = WebCoreFloatToSkScalar(p.X());
SkScalar cy = WebCoreFloatToSkScalar(p.Y());
@@ -400,9 +397,8 @@ void Path::AddEllipse(const FloatPoint& p,
void Path::AddArc(const FloatPoint& p,
float radius,
float start_angle,
- float end_angle,
- bool anticlockwise) {
- AddEllipse(p, radius, radius, start_angle, end_angle, anticlockwise);
+ float end_angle) {
+ AddEllipse(p, radius, radius, start_angle, end_angle);
}
void Path::AddRect(const FloatRect& rect) {
@@ -415,17 +411,14 @@ void Path::AddEllipse(const FloatPoint& p,
float radius_y,
float rotation,
float start_angle,
- float end_angle,
- bool anticlockwise) {
+ float end_angle) {
DCHECK(EllipseIsRenderable(start_angle, end_angle));
DCHECK_GE(start_angle, 0);
DCHECK_LT(start_angle, kTwoPiFloat);
- DCHECK((anticlockwise && (start_angle - end_angle) >= 0) ||
- (!anticlockwise && (end_angle - start_angle) >= 0));
if (!rotation) {
AddEllipse(FloatPoint(p.X(), p.Y()), radius_x, radius_y, start_angle,
- end_angle, anticlockwise);
+ end_angle);
return;
}
@@ -435,8 +428,7 @@ void Path::AddEllipse(const FloatPoint& p,
DCHECK(ellipse_transform.IsInvertible());
AffineTransform inverse_ellipse_transform = ellipse_transform.Inverse();
Transform(inverse_ellipse_transform);
- AddEllipse(FloatPoint::Zero(), radius_x, radius_y, start_angle, end_angle,
- anticlockwise);
+ AddEllipse(FloatPoint::Zero(), radius_x, radius_y, start_angle, end_angle);
Transform(ellipse_transform);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/path.h b/chromium/third_party/blink/renderer/platform/graphics/path.h
index 395e02313a4..36f374597cc 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/path.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/path.h
@@ -77,6 +77,7 @@ class PLATFORM_EXPORT Path {
Path& operator=(const Path&);
Path& operator=(const SkPath&);
bool operator==(const Path&) const;
+ bool operator!=(const Path& other) const { return !(*this == other); }
bool Contains(const FloatPoint&) const;
bool Contains(const FloatPoint&, WindRule) const;
@@ -144,16 +145,14 @@ class PLATFORM_EXPORT Path {
void AddArc(const FloatPoint&,
float radius,
float start_angle,
- float end_angle,
- bool anticlockwise);
+ float end_angle);
void AddRect(const FloatRect&);
void AddEllipse(const FloatPoint&,
float radius_x,
float radius_y,
float rotation,
float start_angle,
- float end_angle,
- bool anticlockwise);
+ float end_angle);
void AddEllipse(const FloatRect&);
void AddRoundedRect(const FloatRect&, const FloatSize& rounding_radii);
@@ -192,8 +191,7 @@ class PLATFORM_EXPORT Path {
float radius_x,
float radius_y,
float start_angle,
- float end_angle,
- bool anticlockwise);
+ float end_angle);
SkPath StrokePath(const StrokeData&) const;
SkPath path_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/pattern.cc b/chromium/third_party/blink/renderer/platform/graphics/pattern.cc
index 45512c279b0..f38adf2831f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/pattern.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/pattern.cc
@@ -56,14 +56,10 @@ Pattern::Pattern(RepeatMode repeat_mode) : repeat_mode_(repeat_mode) {}
Pattern::~Pattern() = default;
void Pattern::ApplyToFlags(PaintFlags& flags, const SkMatrix& local_matrix) {
- if (!cached_shader_ || IsLocalMatrixChanged(local_matrix))
+ if (!cached_shader_ || local_matrix != cached_shader_->GetLocalMatrix())
cached_shader_ = CreateShader(local_matrix);
flags.setShader(cached_shader_);
}
-bool Pattern::IsLocalMatrixChanged(const SkMatrix& local_matrix) const {
- return local_matrix != cached_shader_->GetLocalMatrix();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/pattern.h b/chromium/third_party/blink/renderer/platform/graphics/pattern.h
index 821b360ebaa..2f4968c07e2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/pattern.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/pattern.h
@@ -71,7 +71,6 @@ class PLATFORM_EXPORT Pattern : public RefCounted<Pattern> {
protected:
virtual sk_sp<PaintShader> CreateShader(const SkMatrix&) = 0;
- virtual bool IsLocalMatrixChanged(const SkMatrix&) const;
RepeatMode repeat_mode_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc
index 67831cef073..be09c5f451a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/fonts/font_family.h"
@@ -126,7 +127,7 @@ String FormatOriginalResourceSizeBytes(int64_t bytes) {
// Find the smallest unit that can represent |bytes| in 3 digits or less.
// Round up to the next higher unit if possible when it would take 4 digits to
// display the amount, e.g. 1000 KB will be rounded up to 1 MB.
- for (; units < kUnitsNames + (arraysize(kUnitsNames) - 1) &&
+ for (; units < kUnitsNames + (base::size(kUnitsNames) - 1) &&
bytes >= denomenator * 1000;
++units, denomenator *= 1024) {
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h b/chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h
deleted file mode 100644
index 7eb83bad38f..00000000000
--- a/chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PLATFORM_PAINT_WORKLET_INPUT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PLATFORM_PAINT_WORKLET_INPUT_H_
-
-#include "cc/trees/layer_tree_painter.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT PlatformPaintWorkletInput : public cc::PaintWorkletInput {
- public:
- PlatformPaintWorkletInput(const std::string& name,
- const FloatSize& container_size,
- float effective_zoom)
- : name_(name),
- container_size_(container_size),
- effective_zoom_(effective_zoom) {}
-
- ~PlatformPaintWorkletInput() override = default;
-
- const std::string& Name() const { return name_; }
- const FloatSize& ContainerSize() const { return container_size_; }
- float EffectiveZoom() const { return effective_zoom_; }
-
- private:
- std::string name_;
- FloatSize container_size_;
- float effective_zoom_;
- // TODO(crbug.com/895579): add a cross thread style map.
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHIC_PLATFORM_PAINT_WORKLET_INPUT_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
index 38cd420db97..34559425faa 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
@@ -31,11 +31,11 @@
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "build/build_config.h"
+#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
#include "third_party/skia/include/effects/SkCornerPathEffect.h"
#include "third_party/skia/third_party/skcms/skcms.h"
-#include "ui/gfx/icc_profile.h"
#include <algorithm>
#include <cmath>
@@ -319,29 +319,6 @@ SkColor ScaleAlpha(SkColor color, float alpha) {
return SkColorSetA(color, rounded_alpha);
}
-gfx::ColorSpace SkColorSpaceToGfxColorSpace(
- const sk_sp<SkColorSpace> color_space) {
- if (!color_space)
- return gfx::ColorSpace::CreateSRGB();
-
- SkMatrix44 toXYZD50;
- SkColorSpaceTransferFn transfer_fn;
- if (color_space->toXYZD50(&toXYZD50) &&
- color_space->isNumericalTransferFn(&transfer_fn))
- return gfx::ColorSpace::CreateCustom(toXYZD50, transfer_fn);
-
- // Use an intermediate ICC profile to convert the color space data structure.
- // If this fails, we fall back to sRGB.
- sk_sp<SkData> sk_profile = color_space->serialize();
- if (sk_profile) {
- gfx::ICCProfile icc_profile =
- gfx::ICCProfile::FromData(sk_profile->data(), sk_profile->size());
- if (icc_profile.IsValid())
- return icc_profile.GetColorSpace();
- }
- return gfx::ColorSpace::CreateSRGB();
-}
-
bool ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space,
sk_sp<SkColorSpace> dst_color_space) {
if ((!src_color_space && dst_color_space) ||
@@ -355,6 +332,12 @@ bool ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space,
return skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile);
}
+SkRect LayoutRectToSkRect(const blink::LayoutRect& rect) {
+ return SkRect::MakeXYWH(SkFloatToScalar(rect.X()), SkFloatToScalar(rect.Y()),
+ SkFloatToScalar(rect.Width()),
+ SkFloatToScalar(rect.Height()));
+}
+
template <typename PrimitiveType>
void DrawFocusRingPrimitive(const PrimitiveType&,
cc::PaintCanvas*,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
index 9633ea90b44..7155983ee65 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
@@ -47,6 +47,7 @@
#include "third_party/skia/include/core/SkScalar.h"
namespace blink {
+class LayoutRect;
/**** constants ****/
@@ -56,8 +57,8 @@ enum {
// maximum dimensions, in exchange for a smaller maximum canvas size.
kMaxCanvasArea = 32768 * 8192, // Maximum canvas area in CSS pixels
- // In Skia, we will also limit width/height to 32767.
- kMaxSkiaDim = 32767 // Maximum width/height in CSS pixels.
+ // In Skia, we will also limit width/height to 65535.
+ kMaxSkiaDim = 65535 // Maximum width/height in CSS pixels.
};
bool PLATFORM_EXPORT IsValidImageSize(const IntSize&);
@@ -73,14 +74,12 @@ BlendMode PLATFORM_EXPORT BlendModeFromSkBlendMode(SkBlendMode);
// alpha is in the range [0, 1].
SkColor PLATFORM_EXPORT ScaleAlpha(SkColor, float);
-// Convert a SkColorSpace to a gfx::ColorSpace
-gfx::ColorSpace PLATFORM_EXPORT
-SkColorSpaceToGfxColorSpace(const sk_sp<SkColorSpace>);
-
bool PLATFORM_EXPORT
ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space,
sk_sp<SkColorSpace> dst_color_space);
+SkRect PLATFORM_EXPORT LayoutRectToSkRect(const blink::LayoutRect& rect);
+
// Skia has problems when passed infinite, etc floats, filter them to 0.
inline SkScalar WebCoreFloatToSkScalar(float f) {
return SkFloatToScalar(std::isfinite(f) ? f : 0);
@@ -126,13 +125,18 @@ InterpolationQuality ComputeInterpolationQuality(float src_width,
float dest_height,
bool is_data_complete = true);
-// This replicates the old skia behavior when it used to take radius for blur.
-// Now it takes sigma.
-inline SkScalar SkBlurRadiusToSigma(SkScalar radius) {
- SkASSERT(radius >= 0);
- if (radius == 0)
- return 0.0f;
- return 0.288675f * radius + 0.5f;
+// Technically, this is driven by the CSS/Canvas2D specs and unrelated to Skia.
+// It should probably live in the CSS layer, but the notion of a "blur radius"
+// leaks into platform/graphics currently (ideally we should only deal with
+// sigma at this level).
+// TODO(fmalita): find a better home for this helper.
+inline float BlurRadiusToStdDev(float radius) {
+ DCHECK_GE(radius, 0);
+
+ // Per spec, sigma is exactly half the blur radius:
+ // https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
+ // https://html.spec.whatwg.org/multipage/canvas.html#when-shadows-are-drawn
+ return radius * 0.5f;
}
template <typename PrimitiveType>
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc
deleted file mode 100644
index 7de98907099..00000000000
--- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace blink {
-
-class SkiaUtilsTest : public testing::Test {};
-
-// Tests converting a SkColorSpace to a gfx::ColorSpace
-TEST_F(SkiaUtilsTest, SkColorSpaceToGfxColorSpace) {
- std::vector<sk_sp<SkColorSpace>> skia_color_spaces;
-
- SkColorSpace::RenderTargetGamma gammas[] = {
- SkColorSpace::kLinear_RenderTargetGamma,
- SkColorSpace::kSRGB_RenderTargetGamma};
-
- SkColorSpace::Gamut gamuts[] = {
- SkColorSpace::kSRGB_Gamut, SkColorSpace::kAdobeRGB_Gamut,
- SkColorSpace::kDCIP3_D65_Gamut, SkColorSpace::kRec2020_Gamut,
- };
-
- skia_color_spaces.push_back((SkColorSpace::MakeSRGB())->makeColorSpin());
-
- for (unsigned gamma_itr = 0; gamma_itr < 2; gamma_itr++) {
- for (unsigned gamut_itr = 0; gamut_itr < 4; gamut_itr++) {
- skia_color_spaces.push_back(
- SkColorSpace::MakeRGB(gammas[gamma_itr], gamuts[gamut_itr]));
- }
- }
-
- std::vector<gfx::ColorSpace> gfx_color_spaces;
- for (unsigned i = 0; i < skia_color_spaces.size(); i++) {
- gfx::ColorSpace color_space =
- SkColorSpaceToGfxColorSpace(skia_color_spaces[i]);
- ASSERT_TRUE(SkColorSpace::Equals(color_space.ToSkColorSpace().get(),
- skia_color_spaces[i].get()));
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
index be22081f4f3..aae49942565 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
@@ -32,10 +32,6 @@ SkiaTextureHolder::SkiaTextureHolder(
if (!ContextProvider())
return;
- if (texture_holder->IsAbandoned()) {
- Abandon();
- return;
- }
gpu::gles2::GLES2Interface* shared_gl = ContextProvider()->ContextGL();
GrContext* shared_gr_context = ContextProvider()->GetGrContext();
@@ -66,14 +62,8 @@ SkiaTextureHolder::~SkiaTextureHolder() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
-void SkiaTextureHolder::Abandon() {
- if (image_ && image_->getTexture())
- image_->getTexture()->abandon();
- TextureHolder::Abandon();
-}
-
bool SkiaTextureHolder::IsValid() const {
- return !IsAbandoned() && !!ContextProviderWrapper();
+ return !!ContextProviderWrapper();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
index 9ccde9d01c5..d1c4687957a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
@@ -27,7 +27,6 @@ class PLATFORM_EXPORT SkiaTextureHolder final : public TextureHolder {
bool IsValid() const final;
bool CurrentFrameKnownToBeOpaque() final { return image_->isOpaque(); }
sk_sp<SkImage> GetSkImage() final { return image_; }
- void Abandon() final;
// When creating a AcceleratedStaticBitmap from a texture-backed SkImage, this
// function will be called to create a TextureHolder object.
diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
index 034ac1332ba..8550cb7bf48 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
@@ -84,6 +84,7 @@ scoped_refptr<StaticBitmapImage> StaticBitmapImage::ConvertToColorSpace(
SkColorType color_type) {
DCHECK(color_space);
sk_sp<SkImage> skia_image = PaintImageForCurrentFrame().GetSkImage();
+
// If we don't need to change the color type, use SkImage::makeColorSpace()
if (skia_image->colorType() == color_type) {
skia_image = skia_image->makeColorSpace(color_space);
@@ -92,23 +93,17 @@ scoped_refptr<StaticBitmapImage> StaticBitmapImage::ConvertToColorSpace(
: nullptr);
}
- // Otherwise, create a surface and draw on that to avoid GPU readback.
- sk_sp<SkColorSpace> src_color_space = skia_image->refColorSpace();
- if (!src_color_space.get())
- src_color_space = SkColorSpace::MakeSRGB();
- sk_sp<SkColorSpace> dst_color_space = color_space;
- if (!dst_color_space.get())
- dst_color_space = SkColorSpace::MakeSRGB();
-
+ // Otherwise we need to create a surface and redraw the image as it is a
+ // different size in memory
SkImageInfo info =
SkImageInfo::Make(skia_image->width(), skia_image->height(), color_type,
- skia_image->alphaType(), dst_color_space);
+ skia_image->alphaType(), color_space);
sk_sp<SkSurface> surface = nullptr;
if (skia_image->isTextureBacked()) {
GrContext* gr = ContextProviderWrapper()->ContextProvider()->GetGrContext();
surface = SkSurface::MakeRenderTarget(gr, SkBudgeted::kNo, info);
} else {
- surface = SkSurface::MakeRaster(info);
+ surface = SkSurface::MakeRaster(info);
}
SkPaint paint;
surface->getCanvas()->drawImage(skia_image, 0, 0, &paint);
@@ -136,7 +131,7 @@ bool StaticBitmapImage::ConvertToArrayBufferContents(
data_size.ValueOrDie() > v8::TypedArray::kMaxLength)
return false;
- size_t alloc_size_in_bytes = rect.Size().Area() * bytes_per_pixel;
+ int alloc_size_in_bytes = data_size.ValueOrDie();
if (!src_image) {
auto data = WTF::ArrayBufferContents::CreateDataHandle(
alloc_size_in_bytes, WTF::ArrayBufferContents::kZeroInitialize);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
index 28b6537fc87..e52affa47ff 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
@@ -65,7 +65,6 @@ class PLATFORM_EXPORT StaticBitmapImage : public Image {
virtual bool HasMailbox() const { return false; }
virtual bool IsValid() const { return true; }
virtual void Transfer() {}
- virtual void Abandon() {}
// Creates a non-gpu copy of the image, or returns this if image is already
// non-gpu.
diff --git a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc
index 47a08b29157..3a641879c4b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc
@@ -34,7 +34,7 @@ SurfaceLayerBridge::SurfaceLayerBridge(
binding_(this),
surface_embedder_binding_(this),
enable_surface_synchronization_(
- features::IsSurfaceSynchronizationEnabled()),
+ ::features::IsSurfaceSynchronizationEnabled()),
frame_sink_id_(Platform::Current()->GenerateFrameSinkId()),
parent_frame_sink_id_(layer_tree_view ? layer_tree_view->GetFrameSinkId()
: viz::FrameSinkId()) {
@@ -126,18 +126,8 @@ const viz::FrameSinkId& SurfaceLayerBridge::GetFrameSinkId() const {
return frame_sink_id_;
}
-void SurfaceLayerBridge::ClearSurfaceId() {
- current_surface_id_ = viz::SurfaceId();
-
- if (!surface_layer_)
- return;
-
- // We reset the Ids if we lose the context_provider (case: GPU process ended)
- // If we destroyed the surface_layer before that point, we need not update
- // the ids.
- surface_layer_->SetSurfaceId(viz::SurfaceId(),
- cc::DeadlinePolicy::UseDefaultDeadline());
- surface_layer_->SetOldestAcceptableFallback(viz::SurfaceId());
+void SurfaceLayerBridge::ClearObserver() {
+ observer_ = nullptr;
}
void SurfaceLayerBridge::SetContentsOpaque(bool opaque) {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h
index 6874555fd52..341300dba7c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h
@@ -57,9 +57,9 @@ class PLATFORM_EXPORT SurfaceLayerBridge
// Implementation of WebSurfaceLayerBridge.
cc::Layer* GetCcLayer() const override;
const viz::FrameSinkId& GetFrameSinkId() const override;
- void ClearSurfaceId() override;
void SetContentsOpaque(bool) override;
void CreateSurfaceLayer() override;
+ void ClearObserver() override;
const viz::SurfaceId& GetSurfaceId() const override {
return current_surface_id_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h b/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h
index def091d1f44..e57624df203 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h
@@ -48,7 +48,6 @@ class PLATFORM_EXPORT TextureHolder {
NOTREACHED();
return nullptr;
}
- virtual void Abandon() { is_abandoned_ = true; } // Overrides must call base.
// Methods that have exactly the same impelmentation for all sub-classes
base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
@@ -61,7 +60,6 @@ class PLATFORM_EXPORT TextureHolder {
? context_provider_wrapper_->ContextProvider()
: nullptr;
}
- bool IsAbandoned() const { return is_abandoned_; }
protected:
TextureHolder(base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&
@@ -75,7 +73,6 @@ class PLATFORM_EXPORT TextureHolder {
// and that we need to clear the resouces associated with that
// AcceleratedStaticBitmapImage on the original thread.
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
- bool is_abandoned_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index c20b1272045..32f6060223c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -8,12 +8,11 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
-#include "cc/paint/filter_operations.h"
-#include "cc/scheduler/video_frame_controller.h"
#include "components/viz/common/features.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/returned_resource.h"
#include "media/base/video_frame.h"
+#include "media/base/video_types.h"
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h"
#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/blink/public/platform/interface_provider.h"
@@ -23,14 +22,6 @@
namespace blink {
-namespace {
-
-// Delay to retry getting the context_provider.
-constexpr base::TimeDelta kGetContextProviderRetryTimeout =
- base::TimeDelta::FromMilliseconds(150);
-
-} // namespace
-
VideoFrameSubmitter::VideoFrameSubmitter(
WebContextProviderCallback context_provider_callback,
std::unique_ptr<VideoFrameResourceProvider> resource_provider)
@@ -39,36 +30,90 @@ VideoFrameSubmitter::VideoFrameSubmitter(
resource_provider_(std::move(resource_provider)),
rotation_(media::VIDEO_ROTATION_0),
enable_surface_synchronization_(
- features::IsSurfaceSynchronizationEnabled()),
+ ::features::IsSurfaceSynchronizationEnabled()),
weak_ptr_factory_(this) {
- DETACH_FROM_THREAD(media_thread_checker_);
+ DETACH_FROM_THREAD(thread_checker_);
}
VideoFrameSubmitter::~VideoFrameSubmitter() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (context_provider_)
context_provider_->RemoveObserver(this);
+
+ // Release VideoFrameResourceProvider early since its destruction will make
+ // calls back into this class via the viz::SharedBitmapReporter interface.
+ resource_provider_.reset();
}
-void VideoFrameSubmitter::SetRotation(media::VideoRotation rotation) {
- rotation_ = rotation;
+void VideoFrameSubmitter::StopUsingProvider() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (is_rendering_)
+ StopRendering();
+ video_frame_provider_ = nullptr;
}
-void VideoFrameSubmitter::SetIsOpaque(bool is_opaque) {
- if (is_opaque_ == is_opaque)
+void VideoFrameSubmitter::StartRendering() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!is_rendering_);
+ is_rendering_ = true;
+
+ if (compositor_frame_sink_)
+ compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && ShouldSubmit());
+}
+
+void VideoFrameSubmitter::StopRendering() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(is_rendering_);
+ DCHECK(video_frame_provider_);
+
+ is_rendering_ = false;
+ UpdateSubmissionState();
+}
+
+void VideoFrameSubmitter::DidReceiveFrame() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(video_frame_provider_);
+
+ // DidReceiveFrame is called before rendering has started, as a part of
+ // VideoRendererSink::PaintSingleFrame.
+ if (!is_rendering_)
+ SubmitSingleFrame();
+}
+
+bool VideoFrameSubmitter::IsDrivingFrameUpdates() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // We drive frame updates only when we believe that something is consuming
+ // them. This is different than VideoLayer, which drives updates any time
+ // they're in the layer tree.
+ return is_rendering_ && ShouldSubmit();
+}
+
+void VideoFrameSubmitter::Initialize(cc::VideoFrameProvider* provider) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!provider)
return;
- is_opaque_ = is_opaque;
- UpdateSubmissionStateInternal();
+ DCHECK(!video_frame_provider_);
+ video_frame_provider_ = provider;
+ context_provider_callback_.Run(
+ nullptr, base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void VideoFrameSubmitter::SetRotation(media::VideoRotation rotation) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ rotation_ = rotation;
}
void VideoFrameSubmitter::EnableSubmission(
viz::SurfaceId surface_id,
- base::TimeTicks local_surface_id_allocation_time,
- WebFrameSinkDestroyedCallback frame_sink_destroyed_callback) {
+ base::TimeTicks local_surface_id_allocation_time) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
// TODO(lethalantidote): Set these fields earlier in the constructor. Will
// need to construct VideoFrameSubmitter later in order to do this.
frame_sink_id_ = surface_id.frame_sink_id();
- frame_sink_destroyed_callback_ = frame_sink_destroyed_callback;
child_local_surface_id_allocator_.UpdateFromParent(
viz::LocalSurfaceIdAllocation(surface_id.local_surface_id(),
local_surface_id_allocation_time));
@@ -76,110 +121,128 @@ void VideoFrameSubmitter::EnableSubmission(
StartSubmitting();
}
-void VideoFrameSubmitter::UpdateSubmissionState(bool should_submit) {
- should_submit_internal_ = should_submit;
- UpdateSubmissionStateInternal();
+void VideoFrameSubmitter::SetIsSurfaceVisible(bool is_visible) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ is_surface_visible_ = is_visible;
+ UpdateSubmissionState();
+}
+
+void VideoFrameSubmitter::SetIsPageVisible(bool is_visible) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ is_page_visible_ = is_visible;
+ UpdateSubmissionState();
}
void VideoFrameSubmitter::SetForceSubmit(bool force_submit) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
force_submit_ = force_submit;
- UpdateSubmissionStateInternal();
+ UpdateSubmissionState();
}
-void VideoFrameSubmitter::UpdateSubmissionStateInternal() {
- if (compositor_frame_sink_) {
- compositor_frame_sink_->SetNeedsBeginFrame(IsDrivingFrameUpdates());
- if (ShouldSubmit())
- SubmitSingleFrame();
- else if (!frame_size_.IsEmpty())
- SubmitEmptyFrame();
- }
+void VideoFrameSubmitter::OnContextLost() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (binding_.is_bound())
+ binding_.Unbind();
+
+ if (context_provider_)
+ context_provider_->RemoveObserver(this);
+
+ waiting_for_compositor_ack_ = false;
+
+ resource_provider_->OnContextLost();
+
+ // |compositor_frame_sink_| should be reset last.
+ compositor_frame_sink_.reset();
+
+ context_provider_callback_.Run(
+ context_provider_,
+ base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider,
+ weak_ptr_factory_.GetWeakPtr()));
}
-void VideoFrameSubmitter::StopUsingProvider() {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- if (is_rendering_)
- StopRendering();
- video_frame_provider_ = nullptr;
+void VideoFrameSubmitter::DidReceiveCompositorFrameAck(
+ const WTF::Vector<viz::ReturnedResource>& resources) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ ReclaimResources(resources);
+ waiting_for_compositor_ack_ = false;
}
-void VideoFrameSubmitter::StopRendering() {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- DCHECK(is_rendering_);
- DCHECK(video_frame_provider_);
+void VideoFrameSubmitter::OnBeginFrame(
+ const viz::BeginFrameArgs& args,
+ WTF::HashMap<uint32_t, ::gfx::mojom::blink::PresentationFeedbackPtr>) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame");
- is_rendering_ = false;
- UpdateSubmissionStateInternal();
-}
+ viz::BeginFrameAck current_begin_frame_ack(args, false);
+ if (args.type == viz::BeginFrameArgs::MISSED) {
+ compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
+ return;
+ }
-void VideoFrameSubmitter::SubmitSingleFrame() {
- // If we haven't gotten a valid result yet from |context_provider_callback_|
- // |resource_provider_| will remain uninitalized.
- // |video_frame_provider_| may be null if StopUsingProvider has been called,
- // which could happen if the |video_frame_provider_| is destructing while we
- // are waiting for the ContextProvider.
- if (!resource_provider_->IsInitialized() || !video_frame_provider_)
+ // Update the current frame, even if we haven't gotten an ack for a previous
+ // frame yet. That probably signals a dropped frame, and this will let the
+ // provider know that it happened, since we won't PutCurrentFrame this one.
+ // Note that we should DidNotProduceFrame with or without the ack.
+ if (!video_frame_provider_ || !video_frame_provider_->UpdateCurrentFrame(
+ args.frame_time + args.interval,
+ args.frame_time + 2 * args.interval)) {
+ compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
return;
+ }
- viz::BeginFrameAck current_begin_frame_ack =
- viz::BeginFrameAck::CreateManualAckWithDamage();
scoped_refptr<media::VideoFrame> video_frame =
video_frame_provider_->GetCurrentFrame();
- if (video_frame) {
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(base::IgnoreResult(&VideoFrameSubmitter::SubmitFrame),
- weak_ptr_factory_.GetWeakPtr(), current_begin_frame_ack,
- video_frame));
- video_frame_provider_->PutCurrentFrame();
+
+ // We do have a new frame that we could display. See if we're supposed to
+ // actually submit a frame or not, and try to submit one.
+ //
+ // Not submitting a frame when waiting for a previous ack saves memory by
+ // not building up unused remote side resources. See https://crbug.com/830828.
+ //
+ // TODO(dalecurtis): Can |is_rendering_| ever be false here? Presumably if
+ // StopRendering() is called above we will not have gotten a BeginFrame.
+ if (!is_rendering_ || waiting_for_compositor_ack_ ||
+ !SubmitFrame(current_begin_frame_ack, std::move(video_frame))) {
+ compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
+ return;
}
-}
-bool VideoFrameSubmitter::ShouldSubmit() const {
- return should_submit_internal_ || force_submit_;
-}
+ // We submitted a frame!
-bool VideoFrameSubmitter::IsDrivingFrameUpdates() const {
- // We drive frame updates only when we believe that something is consuming
- // them. This is different than VideoLayer, which drives updates any time
- // they're in the layer tree.
- return is_rendering_ && ShouldSubmit();
+ // We still signal PutCurrentFrame here, rather than on the ack, so that it
+ // lines up with the correct frame. Otherwise, any intervening calls to
+ // OnBeginFrame => UpdateCurrentFrame will cause the put to signal that the
+ // later frame was displayed.
+ video_frame_provider_->PutCurrentFrame();
}
-void VideoFrameSubmitter::DidReceiveFrame() {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- DCHECK(video_frame_provider_);
-
- // DidReceiveFrame is called before renderering has started, as a part of
- // PaintSingleFrame.
- if (!is_rendering_) {
- SubmitSingleFrame();
- }
+void VideoFrameSubmitter::ReclaimResources(
+ const WTF::Vector<viz::ReturnedResource>& resources) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ resource_provider_->ReceiveReturnsFromParent(
+ WebVector<viz::ReturnedResource>(resources).ReleaseVector());
}
-void VideoFrameSubmitter::StartRendering() {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- DCHECK(!is_rendering_);
- is_rendering_ = true;
-
- if (compositor_frame_sink_)
- compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && ShouldSubmit());
+void VideoFrameSubmitter::DidAllocateSharedBitmap(
+ mojo::ScopedSharedBufferHandle buffer,
+ const viz::SharedBitmapId& id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(compositor_frame_sink_);
+ compositor_frame_sink_->DidAllocateSharedBitmap(
+ std::move(buffer), SharedBitmapIdToGpuMailboxPtr(id));
}
-void VideoFrameSubmitter::Initialize(cc::VideoFrameProvider* provider) {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- if (provider) {
- DCHECK(!video_frame_provider_);
- video_frame_provider_ = provider;
- context_provider_callback_.Run(
- nullptr, base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider,
- weak_ptr_factory_.GetWeakPtr()));
- }
+void VideoFrameSubmitter::DidDeleteSharedBitmap(const viz::SharedBitmapId& id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(compositor_frame_sink_);
+ compositor_frame_sink_->DidDeleteSharedBitmap(
+ SharedBitmapIdToGpuMailboxPtr(id));
}
void VideoFrameSubmitter::OnReceivedContextProvider(
bool use_gpu_compositing,
scoped_refptr<viz::ContextProvider> context_provider) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!use_gpu_compositing) {
resource_provider_->Initialize(nullptr, this);
return;
@@ -188,6 +251,10 @@ void VideoFrameSubmitter::OnReceivedContextProvider(
bool has_good_context = false;
while (!has_good_context) {
if (!context_provider) {
+ // Delay to retry getting the context_provider.
+ constexpr base::TimeDelta kGetContextProviderRetryTimeout =
+ base::TimeDelta::FromMilliseconds(150);
+
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
@@ -217,7 +284,7 @@ void VideoFrameSubmitter::OnReceivedContextProvider(
}
void VideoFrameSubmitter::StartSubmitting() {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(frame_sink_id_.is_valid());
mojom::blink::EmbeddedFrameSinkProviderPtr provider;
@@ -228,21 +295,55 @@ void VideoFrameSubmitter::StartSubmitting() {
binding_.Bind(mojo::MakeRequest(&client));
provider->CreateCompositorFrameSink(
frame_sink_id_, std::move(client),
- mojo::MakeRequest(&compositor_frame_sink_),
- mojo::MakeRequest(&surface_embedder_));
+ mojo::MakeRequest(&compositor_frame_sink_));
+ if (!surface_embedder_.is_bound()) {
+ provider->ConnectToEmbedder(frame_sink_id_,
+ mojo::MakeRequest(&surface_embedder_));
+ } else {
+ GenerateNewSurfaceId();
+ }
compositor_frame_sink_.set_connection_error_handler(base::BindOnce(
&VideoFrameSubmitter::OnContextLost, base::Unretained(this)));
- UpdateSubmissionStateInternal();
+ UpdateSubmissionState();
+}
+
+void VideoFrameSubmitter::UpdateSubmissionState() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!compositor_frame_sink_)
+ return;
+
+ compositor_frame_sink_->SetNeedsBeginFrame(IsDrivingFrameUpdates());
+
+ // These two calls are very important; they are responsible for significant
+ // memory savings when content is off-screen.
+ //
+ // While off-screen, we do not submit frames (unless |force_submit_| is true),
+ // which prevents GPU resource creation and accumulation on the remote side.
+ // During the transition to off-screen we further send an empty frame with the
+ // intent to evict any resources held for the previous frame. Combined these
+ // optimizations save 30-50% in cc:: resource memory usage.
+ //
+ // See https://crbug.com/829813 and https://crbug.com/829565.
+ if (ShouldSubmit()) {
+ // We don't want to submit when |is_rendering_| because OnBeginFrame() calls
+ // are already driving submissions. We should still submit the empty frame
+ // in the other branch for memory savings.
+ if (!is_rendering_)
+ SubmitSingleFrame();
+ } else if (!frame_size_.IsEmpty()) {
+ SubmitEmptyFrame();
+ }
}
bool VideoFrameSubmitter::SubmitFrame(
const viz::BeginFrameAck& begin_frame_ack,
scoped_refptr<media::VideoFrame> video_frame) {
- TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame");
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(video_frame);
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
+ TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame");
+
if (!compositor_frame_sink_ || !ShouldSubmit())
return false;
@@ -252,47 +353,23 @@ bool VideoFrameSubmitter::SubmitFrame(
frame_size = gfx::Size(frame_size.height(), frame_size.width());
}
if (frame_size_ != frame_size) {
- if (!frame_size_.IsEmpty()) {
- child_local_surface_id_allocator_.GenerateId();
- if (enable_surface_synchronization_) {
- surface_embedder_->SetLocalSurfaceId(
- child_local_surface_id_allocator_
- .GetCurrentLocalSurfaceIdAllocation()
- .local_surface_id());
- }
- }
+ if (!frame_size_.IsEmpty())
+ GenerateNewSurfaceId();
frame_size_ = frame_size;
}
- viz::CompositorFrame compositor_frame;
- std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
-
- render_pass->SetNew(1, gfx::Rect(frame_size_), gfx::Rect(frame_size_),
- gfx::Transform());
- render_pass->filters = cc::FilterOperations();
- resource_provider_->AppendQuads(render_pass.get(), video_frame, rotation_,
- is_opaque_);
- compositor_frame.metadata.begin_frame_ack = begin_frame_ack;
- // We don't assume that the ack is marked as having damage. However, we're
- // definitely emitting a CompositorFrame that damages the entire surface.
- compositor_frame.metadata.begin_frame_ack.has_damage = true;
- compositor_frame.metadata.device_scale_factor = 1;
- compositor_frame.metadata.may_contain_video = true;
+ auto compositor_frame =
+ CreateCompositorFrame(begin_frame_ack, std::move(video_frame));
std::vector<viz::ResourceId> resources;
- DCHECK_LE(render_pass->quad_list.size(), 1u);
- if (!render_pass->quad_list.empty()) {
- for (viz::ResourceId resource_id :
- render_pass->quad_list.front()->resources) {
- resources.push_back(resource_id);
- }
+ const auto& quad_list = compositor_frame.render_pass_list.back()->quad_list;
+ if (!quad_list.empty()) {
+ DCHECK_EQ(quad_list.size(), 1u);
+ resources.assign(quad_list.front()->resources.begin(),
+ quad_list.front()->resources.end());
}
resource_provider_->PrepareSendToParent(resources,
&compositor_frame.resource_list);
- compositor_frame.render_pass_list.push_back(std::move(render_pass));
- compositor_frame.metadata.local_surface_id_allocation_time =
- child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
- .allocation_time();
// TODO(lethalantidote): Address third/fourth arg in SubmitCompositorFrame.
compositor_frame_sink_->SubmitCompositorFrame(
@@ -306,143 +383,94 @@ bool VideoFrameSubmitter::SubmitFrame(
}
void VideoFrameSubmitter::SubmitEmptyFrame() {
- TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitEmptyFrame");
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(compositor_frame_sink_ && !ShouldSubmit());
DCHECK(!frame_size_.IsEmpty());
-
- viz::CompositorFrame compositor_frame;
-
- compositor_frame.metadata.begin_frame_ack =
- viz::BeginFrameAck::CreateManualAckWithDamage();
- compositor_frame.metadata.device_scale_factor = 1;
- compositor_frame.metadata.may_contain_video = true;
- compositor_frame.metadata.local_surface_id_allocation_time =
- child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
- .allocation_time();
-
- std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
- render_pass->SetNew(1, gfx::Rect(frame_size_), gfx::Rect(frame_size_),
- gfx::Transform());
- compositor_frame.render_pass_list.push_back(std::move(render_pass));
+ TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitEmptyFrame");
compositor_frame_sink_->SubmitCompositorFrame(
child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
.local_surface_id(),
- std::move(compositor_frame), nullptr, 0);
+ CreateCompositorFrame(viz::BeginFrameAck::CreateManualAckWithDamage(),
+ nullptr),
+ nullptr, 0);
waiting_for_compositor_ack_ = true;
}
-void VideoFrameSubmitter::OnBeginFrame(
- const viz::BeginFrameArgs& args,
- WTF::HashMap<uint32_t, ::gfx::mojom::blink::PresentationFeedbackPtr>) {
- TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame");
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- viz::BeginFrameAck current_begin_frame_ack(args, false);
- if (args.type == viz::BeginFrameArgs::MISSED) {
- compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
- return;
- }
+void VideoFrameSubmitter::SubmitSingleFrame() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Update the current frame, even if we haven't gotten an ack for a previous
- // frame yet. That probably signals a dropped frame, and this will let the
- // provider know that it happened, since we won't PutCurrentFrame this one.
- // Note that we should DidNotProduceFrame with or without the ack.
- if (!video_frame_provider_ || !video_frame_provider_->UpdateCurrentFrame(
- args.frame_time + args.interval,
- args.frame_time + 2 * args.interval)) {
- compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
+ // If we haven't gotten a valid result yet from |context_provider_callback_|
+ // |resource_provider_| will remain uninitialized.
+ // |video_frame_provider_| may be null if StopUsingProvider has been called,
+ // which could happen if the |video_frame_provider_| is destructing while we
+ // are waiting for the ContextProvider.
+ if (!resource_provider_->IsInitialized() || !video_frame_provider_)
return;
- }
-
- scoped_refptr<media::VideoFrame> video_frame =
- video_frame_provider_->GetCurrentFrame();
- // We do have a new frame that we could display. See if we're supposed to
- // actually submit a frame or not, and try to submit one.
- if (!is_rendering_ || waiting_for_compositor_ack_ ||
- !SubmitFrame(current_begin_frame_ack, std::move(video_frame))) {
- compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
+ auto video_frame = video_frame_provider_->GetCurrentFrame();
+ if (!video_frame)
return;
- }
- // We submitted a frame!
+ // TODO(dalecurtis): This probably shouldn't be posted since it runs the risk
+ // of having state change out from under it. All call sites into this method
+ // should be from posted tasks so it should be safe to remove the post.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(base::IgnoreResult(&VideoFrameSubmitter::SubmitFrame),
+ weak_ptr_factory_.GetWeakPtr(),
+ viz::BeginFrameAck::CreateManualAckWithDamage(),
+ std::move(video_frame)));
- // We still signal PutCurrentFrame here, rather than on the ack, so that it
- // lines up with the correct frame. Otherwise, any intervening calls to
- // OnBeginFrame => UpdateCurrentFrame will cause the put to signal that the
- // later frame was displayed.
video_frame_provider_->PutCurrentFrame();
}
-void VideoFrameSubmitter::OnContextLost() {
- // TODO(lethalantidote): This check will be obsolete once other TODO to move
- // field initialization earlier is fulfilled.
- if (frame_sink_destroyed_callback_)
- frame_sink_destroyed_callback_.Run();
-
- if (binding_.is_bound())
- binding_.Unbind();
-
- if (context_provider_) {
- context_provider_->RemoveObserver(this);
- }
- waiting_for_compositor_ack_ = false;
-
- resource_provider_->OnContextLost();
-
- // |compositor_frame_sink_| should be reset last.
- compositor_frame_sink_.reset();
+bool VideoFrameSubmitter::ShouldSubmit() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return (is_surface_visible_ && is_page_visible_) || force_submit_;
+}
- context_provider_callback_.Run(
- context_provider_,
- base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider,
- weak_ptr_factory_.GetWeakPtr()));
+viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame(
+ const viz::BeginFrameAck& begin_frame_ack,
+ scoped_refptr<media::VideoFrame> video_frame) {
+ DCHECK(!frame_size_.IsEmpty());
- // We need to trigger another submit so that surface_id's get propagated
- // correctly. If we don't, we don't get any more signals to update the
- // submission state.
- should_submit_internal_ = true;
-}
+ viz::CompositorFrame compositor_frame;
+ compositor_frame.metadata.begin_frame_ack = begin_frame_ack;
+ compositor_frame.metadata.frame_token = ++next_frame_token_;
-void VideoFrameSubmitter::DidReceiveCompositorFrameAck(
- const WTF::Vector<viz::ReturnedResource>& resources) {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- ReclaimResources(resources);
+ // We don't assume that the ack is marked as having damage. However, we're
+ // definitely emitting a CompositorFrame that damages the entire surface.
+ compositor_frame.metadata.begin_frame_ack.has_damage = true;
+ compositor_frame.metadata.device_scale_factor = 1;
+ compositor_frame.metadata.may_contain_video = true;
+ compositor_frame.metadata.local_surface_id_allocation_time =
+ child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
+ .allocation_time();
- waiting_for_compositor_ack_ = false;
-}
+ auto render_pass = viz::RenderPass::Create();
+ render_pass->SetNew(1, gfx::Rect(frame_size_), gfx::Rect(frame_size_),
+ gfx::Transform());
-void VideoFrameSubmitter::ReclaimResources(
- const WTF::Vector<viz::ReturnedResource>& resources) {
- DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
- WebVector<viz::ReturnedResource> temp_resources = resources;
- std::vector<viz::ReturnedResource> std_resources =
- temp_resources.ReleaseVector();
- resource_provider_->ReceiveReturnsFromParent(std_resources);
-}
+ if (video_frame) {
+ const bool is_opaque = media::IsOpaque(video_frame->format());
+ resource_provider_->AppendQuads(render_pass.get(), std::move(video_frame),
+ rotation_, is_opaque);
+ }
-void VideoFrameSubmitter::DidAllocateSharedBitmap(
- mojo::ScopedSharedBufferHandle buffer,
- const viz::SharedBitmapId& id) {
- DCHECK(compositor_frame_sink_);
- compositor_frame_sink_->DidAllocateSharedBitmap(
- std::move(buffer), SharedBitmapIdToGpuMailboxPtr(id));
+ compositor_frame.render_pass_list.emplace_back(std::move(render_pass));
+ return compositor_frame;
}
-void VideoFrameSubmitter::DidDeleteSharedBitmap(const viz::SharedBitmapId& id) {
- DCHECK(compositor_frame_sink_);
- compositor_frame_sink_->DidDeleteSharedBitmap(
- SharedBitmapIdToGpuMailboxPtr(id));
-}
+void VideoFrameSubmitter::GenerateNewSurfaceId() {
+ // We need a new id in the event of context loss.
+ child_local_surface_id_allocator_.GenerateId();
+ if (!enable_surface_synchronization_)
+ return;
-void VideoFrameSubmitter::SetSurfaceIdForTesting(
- const viz::SurfaceId& surface_id,
- base::TimeTicks allocation_time) {
- frame_sink_id_ = surface_id.frame_sink_id();
- child_local_surface_id_allocator_.UpdateFromParent(
- viz::LocalSurfaceIdAllocation(surface_id.local_surface_id(),
- allocation_time));
+ surface_embedder_->SetLocalSurfaceId(
+ child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
index 0a0f90deece..bc870137ee0 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -28,29 +28,20 @@ namespace blink {
// This single-threaded class facilitates the communication between the media
// stack and browser renderer, providing compositor frames containing video
-// frames and corresponding resources to the |compositor_frame_sink_|. This
-// class has dependencies on classes that use the media thread's OpenGL
-// ContextProvider, and thus, besides construction, should be consistently ran
-// from the same media SingleThreadTaskRunner.
+// frames and corresponding resources to the |compositor_frame_sink_|.
+//
+// This class requires and uses a viz::ContextProvider, and thus, besides
+// construction, must be consistently accessed from the same thread.
class PLATFORM_EXPORT VideoFrameSubmitter
: public WebVideoFrameSubmitter,
public viz::ContextLostObserver,
public viz::SharedBitmapReporter,
public viz::mojom::blink::CompositorFrameSinkClient {
public:
- explicit VideoFrameSubmitter(WebContextProviderCallback,
- std::unique_ptr<VideoFrameResourceProvider>);
-
+ VideoFrameSubmitter(WebContextProviderCallback,
+ std::unique_ptr<VideoFrameResourceProvider>);
~VideoFrameSubmitter() override;
- bool Rendering() { return is_rendering_; }
- cc::VideoFrameProvider* Provider() { return video_frame_provider_; }
- mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient>* Binding() {
- return &binding_;
- }
-
- void OnReceivedContextProvider(bool, scoped_refptr<viz::ContextProvider>);
-
// cc::VideoFrameProvider::Client implementation.
void StopUsingProvider() override;
void StartRendering() override;
@@ -61,11 +52,11 @@ class PLATFORM_EXPORT VideoFrameSubmitter
// WebVideoFrameSubmitter implementation.
void Initialize(cc::VideoFrameProvider*) override;
void SetRotation(media::VideoRotation) override;
- void SetIsOpaque(bool) override;
- void EnableSubmission(viz::SurfaceId,
- base::TimeTicks local_surface_id_allocation_time,
- WebFrameSinkDestroyedCallback) override;
- void UpdateSubmissionState(bool is_visible) override;
+ void EnableSubmission(
+ viz::SurfaceId,
+ base::TimeTicks local_surface_id_allocation_time) override;
+ void SetIsSurfaceVisible(bool is_visible) override;
+ void SetIsPageVisible(bool is_visible) override;
void SetForceSubmit(bool) override;
// viz::ContextLostObserver implementation.
@@ -87,43 +78,50 @@ class PLATFORM_EXPORT VideoFrameSubmitter
const viz::SharedBitmapId&) override;
void DidDeleteSharedBitmap(const viz::SharedBitmapId&) override;
- void SetCompositorFrameSinkPtrForTesting(
- viz::mojom::blink::CompositorFrameSinkPtr* sink) {
- compositor_frame_sink_ = std::move(*sink);
- }
- void SetSurfaceEmbedderPtrForTesting(
- mojom::blink::SurfaceEmbedderPtr embedder) {
- surface_embedder_ = std::move(embedder);
- }
- void SetSurfaceIdForTesting(const viz::SurfaceId&, base::TimeTicks);
-
private:
- FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, ContextLostDuringSubmit);
- FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest,
- ShouldSubmitPreventsSubmission);
- FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest,
- SetForceSubmitForcesSubmission);
- FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest,
- FrameSizeChangeUpdatesLocalSurfaceId);
- FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest,
- StopUsingProviderDuringContextLost);
+ friend class VideoFrameSubmitterTest;
+ // Called during Initialize() and OnContextLost() after a new ContextGL is
+ // requested.
+ void OnReceivedContextProvider(
+ bool use_gpu_compositing,
+ scoped_refptr<viz::ContextProvider> context_provider);
+
+ // Starts submission and calls UpdateSubmissionState(); which may submit.
void StartSubmitting();
- void UpdateSubmissionStateInternal();
+
+ // Sets CompositorFrameSink::SetNeedsBeginFrame() state and submits a frame if
+ // visible or an empty frame if not.
+ void UpdateSubmissionState();
+
// Returns whether a frame was submitted.
bool SubmitFrame(const viz::BeginFrameAck&, scoped_refptr<media::VideoFrame>);
+
+ // SubmitEmptyFrame() is used to force the remote CompositorFrameSink to
+ // release resources for the last submission; saving a significant amount of
+ // memory (~30%) when content goes off-screen. See https://crbug.com/829813.
void SubmitEmptyFrame();
- // Pulls frame and submits it to compositor.
- // Used in cases like PaintSingleFrame, which occurs before video rendering
- // has started to post a poster image, or to submit a final frame before
- // ending rendering.
+ // Pulls frame and submits it to compositor. Used in cases like
+ // DidReceiveFrame(), which occurs before video rendering has started to post
+ // the first frame or to submit a final frame before ending rendering.
void SubmitSingleFrame();
// Return whether the submitter should submit frames based on its current
- // state.
+ // state. It's important to only submit when this is true to save memory. See
+ // comments above and in UpdateSubmissionState().
bool ShouldSubmit() const;
+ // Generates a new surface ID using using |child_local_surface_id_allocator_|.
+ // Called during context loss or during a frame size change.
+ void GenerateNewSurfaceId();
+
+ // Helper method for creating viz::CompositorFrame. If |video_frame| is null
+ // then the frame will be empty.
+ viz::CompositorFrame CreateCompositorFrame(
+ const viz::BeginFrameAck& begin_frame_ack,
+ scoped_refptr<media::VideoFrame> video_frame);
+
cc::VideoFrameProvider* video_frame_provider_ = nullptr;
scoped_refptr<viz::ContextProvider> context_provider_;
viz::mojom::blink::CompositorFrameSinkPtr compositor_frame_sink_;
@@ -131,18 +129,27 @@ class PLATFORM_EXPORT VideoFrameSubmitter
mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient> binding_;
WebContextProviderCallback context_provider_callback_;
std::unique_ptr<VideoFrameResourceProvider> resource_provider_;
- WebFrameSinkDestroyedCallback frame_sink_destroyed_callback_;
bool waiting_for_compositor_ack_ = false;
+ // Current rendering state. Set by StartRendering() and StopRendering().
bool is_rendering_ = false;
- // If we are not on screen, we should not submit.
- bool should_submit_internal_ = false;
- // Whether frames should always be submitted, even if we're not visible.
+
+ // If the surface is not visible within in the current view port, we should
+ // not submit. Not submitting when off-screen saves significant memory.
+ bool is_surface_visible_ = false;
+
+ // Likewise, if the entire page is not visible, we should not submit. Not
+ // submitting in the background causes the VideoFrameProvider to enter a
+ // background rendering mode using lower frequency artificial BeginFrames.
+ bool is_page_visible_ = true;
+
+ // Whether frames should always be submitted, even if we're not visible. Used
+ // by Picture-in-Picture mode to ensure submission occurs even off-screen.
bool force_submit_ = false;
+
// Needs to be initialized in implementation because media isn't a public_dep
// of blink/platform.
media::VideoRotation rotation_;
- bool is_opaque_ = true;
viz::FrameSinkId frame_sink_id_;
@@ -156,8 +163,9 @@ class PLATFORM_EXPORT VideoFrameSubmitter
viz::ChildLocalSurfaceIdAllocator child_local_surface_id_allocator_;
const bool enable_surface_synchronization_;
+ viz::FrameTokenGenerator next_frame_token_;
- THREAD_CHECKER(media_thread_checker_);
+ THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
index 6ec09248d5b..7f7e3924e14 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -20,6 +20,8 @@
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h"
+#include "third_party/blink/renderer/platform/graphics/test/mock_embedded_frame_sink_provider.h"
#include "third_party/blink/renderer/platform/graphics/video_frame_resource_provider.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -47,12 +49,13 @@ class MockVideoFrameProvider : public cc::VideoFrameProvider {
DISALLOW_COPY_AND_ASSIGN(MockVideoFrameProvider);
};
-class MockCompositorFrameSink : public viz::mojom::blink::CompositorFrameSink {
+class VideoMockCompositorFrameSink
+ : public viz::mojom::blink::CompositorFrameSink {
public:
- MockCompositorFrameSink(
+ VideoMockCompositorFrameSink(
viz::mojom::blink::CompositorFrameSinkRequest* request)
: binding_(this, std::move(*request)) {}
- ~MockCompositorFrameSink() override = default;
+ ~VideoMockCompositorFrameSink() override = default;
const viz::CompositorFrame& last_submitted_compositor_frame() const {
return last_submitted_compositor_frame_;
@@ -101,7 +104,7 @@ class MockCompositorFrameSink : public viz::mojom::blink::CompositorFrameSink {
viz::CompositorFrame last_submitted_compositor_frame_;
- DISALLOW_COPY_AND_ASSIGN(MockCompositorFrameSink);
+ DISALLOW_COPY_AND_ASSIGN(VideoMockCompositorFrameSink);
};
class MockVideoFrameResourceProvider
@@ -145,9 +148,6 @@ class VideoFrameSubmitterTest : public testing::Test {
video_frame_provider_(new StrictMock<MockVideoFrameProvider>()),
context_provider_(viz::TestContextProvider::Create()) {
context_provider_->BindToCurrentThread();
- }
-
- void SetUp() override {
MakeSubmitter();
scoped_task_environment_.RunUntilIdle();
}
@@ -166,28 +166,55 @@ class VideoFrameSubmitterTest : public testing::Test {
viz::mojom::blink::CompositorFrameSinkPtr submitter_sink;
viz::mojom::blink::CompositorFrameSinkRequest request =
mojo::MakeRequest(&submitter_sink);
- sink_ = std::make_unique<StrictMock<MockCompositorFrameSink>>(&request);
+ sink_ =
+ std::make_unique<StrictMock<VideoMockCompositorFrameSink>>(&request);
// By setting the submission state before we set the sink, we can make
// testing easier without having to worry about the first sent frame.
- submitter_->UpdateSubmissionState(true);
- submitter_->SetCompositorFrameSinkPtrForTesting(&submitter_sink);
+ submitter_->SetIsSurfaceVisible(true);
+ submitter_->compositor_frame_sink_ = std::move(submitter_sink);
mojom::blink::SurfaceEmbedderPtr embedder;
mojo::MakeRequest(&embedder);
- submitter_->SetSurfaceEmbedderPtrForTesting(std::move(embedder));
- submitter_->SetSurfaceIdForTesting(
- viz::SurfaceId(
- viz::FrameSinkId(1, 1),
- viz::LocalSurfaceId(
- 11, base::UnguessableToken::Deserialize(0x111111, 0))),
- base::TimeTicks::Now());
+ submitter_->surface_embedder_ = std::move(embedder);
+ auto surface_id = viz::SurfaceId(
+ viz::FrameSinkId(1, 1),
+ viz::LocalSurfaceId(11,
+ base::UnguessableToken::Deserialize(0x111111, 0)));
+ submitter_->frame_sink_id_ = surface_id.frame_sink_id();
+ submitter_->child_local_surface_id_allocator_.UpdateFromParent(
+ viz::LocalSurfaceIdAllocation(surface_id.local_surface_id(),
+ base::TimeTicks::Now()));
+ }
+
+ bool IsRendering() const { return submitter_->is_rendering_; }
+
+ cc::VideoFrameProvider* GetProvider() const {
+ return submitter_->video_frame_provider_;
+ }
+
+ bool ShouldSubmit() const { return submitter_->ShouldSubmit(); }
+
+ void SubmitSingleFrame() { submitter_->SubmitSingleFrame(); }
+
+ const viz::ChildLocalSurfaceIdAllocator& child_local_surface_id_allocator()
+ const {
+ return submitter_->child_local_surface_id_allocator_;
+ }
+
+ gfx::Size frame_size() const { return submitter_->frame_size_; }
+
+ void OnReceivedContextProvider(
+ bool use_gpu_compositing,
+ scoped_refptr<viz::ContextProvider> context_provider) {
+ submitter_->OnReceivedContextProvider(use_gpu_compositing,
+ std::move(context_provider));
}
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<base::SimpleTestTickClock> now_src_;
std::unique_ptr<viz::FakeExternalBeginFrameSource> begin_frame_source_;
- std::unique_ptr<StrictMock<MockCompositorFrameSink>> sink_;
+ std::unique_ptr<StrictMock<VideoMockCompositorFrameSink>> sink_;
std::unique_ptr<StrictMock<MockVideoFrameProvider>> video_frame_provider_;
StrictMock<MockVideoFrameResourceProvider>* resource_provider_;
scoped_refptr<viz::TestContextProvider> context_provider_;
@@ -195,23 +222,23 @@ class VideoFrameSubmitterTest : public testing::Test {
};
TEST_F(VideoFrameSubmitterTest, StatRenderingFlipsBits) {
- EXPECT_FALSE(submitter_->Rendering());
+ EXPECT_FALSE(IsRendering());
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
submitter_->StartRendering();
scoped_task_environment_.RunUntilIdle();
- EXPECT_TRUE(submitter_->Rendering());
+ EXPECT_TRUE(IsRendering());
}
TEST_F(VideoFrameSubmitterTest, StopUsingProviderNullsProvider) {
- EXPECT_FALSE(submitter_->Rendering());
- EXPECT_EQ(video_frame_provider_.get(), submitter_->Provider());
+ EXPECT_FALSE(IsRendering());
+ EXPECT_EQ(video_frame_provider_.get(), GetProvider());
submitter_->StopUsingProvider();
- EXPECT_EQ(nullptr, submitter_->Provider());
+ EXPECT_EQ(nullptr, GetProvider());
}
TEST_F(VideoFrameSubmitterTest,
@@ -221,7 +248,7 @@ TEST_F(VideoFrameSubmitterTest,
submitter_->StartRendering();
scoped_task_environment_.RunUntilIdle();
- EXPECT_TRUE(submitter_->Rendering());
+ EXPECT_TRUE(IsRendering());
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillOnce(Return(media::VideoFrame::CreateFrame(
@@ -238,7 +265,7 @@ TEST_F(VideoFrameSubmitterTest,
scoped_task_environment_.RunUntilIdle();
- EXPECT_FALSE(submitter_->Rendering());
+ EXPECT_FALSE(IsRendering());
}
TEST_F(VideoFrameSubmitterTest, DidReceiveFrameDoesNothingIfRendering) {
@@ -247,14 +274,14 @@ TEST_F(VideoFrameSubmitterTest, DidReceiveFrameDoesNothingIfRendering) {
submitter_->StartRendering();
scoped_task_environment_.RunUntilIdle();
- EXPECT_TRUE(submitter_->Rendering());
+ EXPECT_TRUE(IsRendering());
submitter_->DidReceiveFrame();
scoped_task_environment_.RunUntilIdle();
}
TEST_F(VideoFrameSubmitterTest, DidReceiveFrameSubmitsFrame) {
- EXPECT_FALSE(submitter_->Rendering());
+ EXPECT_FALSE(IsRendering());
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillOnce(Return(media::VideoFrame::CreateFrame(
@@ -272,37 +299,27 @@ TEST_F(VideoFrameSubmitterTest, DidReceiveFrameSubmitsFrame) {
TEST_F(VideoFrameSubmitterTest, ShouldSubmitPreventsSubmission) {
EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
- submitter_->UpdateSubmissionState(false);
+ submitter_->SetIsSurfaceVisible(false);
scoped_task_environment_.RunUntilIdle();
- EXPECT_FALSE(submitter_->ShouldSubmit());
+ EXPECT_FALSE(ShouldSubmit());
EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
submitter_->StartRendering();
scoped_task_environment_.RunUntilIdle();
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
- submitter_->UpdateSubmissionState(true);
+ submitter_->SetIsSurfaceVisible(true);
scoped_task_environment_.RunUntilIdle();
- EXPECT_TRUE(submitter_->ShouldSubmit());
+ EXPECT_TRUE(ShouldSubmit());
EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).Times(0);
- submitter_->UpdateSubmissionState(false);
+ submitter_->SetIsSurfaceVisible(false);
scoped_task_environment_.RunUntilIdle();
- EXPECT_FALSE(submitter_->ShouldSubmit());
+ EXPECT_FALSE(ShouldSubmit());
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillOnce(Return(media::VideoFrame::CreateFrame(
@@ -310,17 +327,17 @@ TEST_F(VideoFrameSubmitterTest, ShouldSubmitPreventsSubmission) {
gfx::Size(8, 8), base::TimeDelta())));
EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- submitter_->SubmitSingleFrame();
+ SubmitSingleFrame();
}
// Tests that when set to true SetForceSubmit forces frame submissions.
// regardless of the internal submit state.
TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) {
EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
- submitter_->UpdateSubmissionState(false);
+ submitter_->SetIsSurfaceVisible(false);
scoped_task_environment_.RunUntilIdle();
- EXPECT_FALSE(submitter_->ShouldSubmit());
+ EXPECT_FALSE(ShouldSubmit());
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillOnce(Return(media::VideoFrame::CreateFrame(
@@ -328,7 +345,7 @@ TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) {
gfx::Size(8, 8), base::TimeDelta())));
EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
submitter_->SetForceSubmit(true);
- EXPECT_TRUE(submitter_->ShouldSubmit());
+ EXPECT_TRUE(ShouldSubmit());
EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
@@ -340,34 +357,14 @@ TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) {
scoped_task_environment_.RunUntilIdle();
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
- submitter_->UpdateSubmissionState(true);
+ submitter_->SetIsSurfaceVisible(true);
scoped_task_environment_.RunUntilIdle();
-
- EXPECT_TRUE(submitter_->ShouldSubmit());
+ EXPECT_TRUE(ShouldSubmit());
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
- submitter_->UpdateSubmissionState(false);
+ submitter_->SetIsSurfaceVisible(false);
scoped_task_environment_.RunUntilIdle();
-
- EXPECT_TRUE(submitter_->ShouldSubmit());
+ EXPECT_TRUE(ShouldSubmit());
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillOnce(Return(media::VideoFrame::CreateFrame(
@@ -375,12 +372,12 @@ TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) {
gfx::Size(8, 8), base::TimeDelta())));
EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- submitter_->SubmitSingleFrame();
+ SubmitSingleFrame();
}
TEST_F(VideoFrameSubmitterTest, RotationInformationPassedToResourceProvider) {
// Check to see if rotation is communicated pre-rendering.
- EXPECT_FALSE(submitter_->Rendering());
+ EXPECT_FALSE(IsRendering());
submitter_->SetRotation(media::VideoRotation::VIDEO_ROTATION_90);
@@ -462,138 +459,6 @@ TEST_F(VideoFrameSubmitterTest, RotationInformationPassedToResourceProvider) {
scoped_task_environment_.RunUntilIdle();
}
-TEST_F(VideoFrameSubmitterTest, IsOpaquePassedToResourceProvider) {
- // Check to see if is_opaque is communicated pre-rendering.
- EXPECT_FALSE(submitter_->Rendering());
-
- // We submit a frame on opacity change.
- EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
-
- submitter_->SetIsOpaque(false);
- scoped_task_environment_.RunUntilIdle();
-
- {
- WTF::Vector<viz::ReturnedResource> resources;
- EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
- submitter_->DidReceiveCompositorFrameAck(resources);
- }
-
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, false));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
-
- submitter_->DidReceiveFrame();
- scoped_task_environment_.RunUntilIdle();
-
- {
- WTF::Vector<viz::ReturnedResource> resources;
- EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
- submitter_->DidReceiveCompositorFrameAck(resources);
- }
-
- // Check to see if an update to is_opaque just before rendering is
- // communicated.
- EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
- submitter_->SetIsOpaque(true);
- scoped_task_environment_.RunUntilIdle();
-
- EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
- submitter_->StartRendering();
- scoped_task_environment_.RunUntilIdle();
-
- {
- WTF::Vector<viz::ReturnedResource> resources;
- EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
- submitter_->DidReceiveCompositorFrameAck(resources);
- }
-
- EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _))
- .WillOnce(Return(true));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, true));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
-
- viz::BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, now_src_.get());
- submitter_->OnBeginFrame(args, {});
- scoped_task_environment_.RunUntilIdle();
-
- {
- WTF::Vector<viz::ReturnedResource> resources;
- EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
- submitter_->DidReceiveCompositorFrameAck(resources);
- }
-
- // Check to see if changing is_opaque while rendering is handled.
- EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
-
- submitter_->SetIsOpaque(false);
- scoped_task_environment_.RunUntilIdle();
-
- {
- WTF::Vector<viz::ReturnedResource> resources;
- EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
- submitter_->DidReceiveCompositorFrameAck(resources);
- }
-
- EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _))
- .WillOnce(Return(true));
- EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
- .WillOnce(Return(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
- gfx::Size(8, 8), base::TimeDelta())));
- EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
- EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
- EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, false));
- EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
- EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
-
- submitter_->OnBeginFrame(args, {});
- scoped_task_environment_.RunUntilIdle();
-
- // Updating |is_opaque_| with the same value should not cause a frame submit.
- submitter_->SetIsOpaque(false);
-}
-
TEST_F(VideoFrameSubmitterTest, OnBeginFrameSubmitsFrame) {
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
@@ -718,6 +583,26 @@ TEST_F(VideoFrameSubmitterTest, WaitingForAckPreventsNewFrame) {
scoped_task_environment_.RunUntilIdle();
}
+// Test that after context is lost, the CompositorFrameSink is recreated but the
+// SurfaceEmbedder isn't.
+TEST_F(VideoFrameSubmitterTest, RecreateCompositorFrameSinkAfterContextLost) {
+ MockEmbeddedFrameSinkProvider mock_embedded_frame_sink_provider;
+ mojo::Binding<mojom::blink::EmbeddedFrameSinkProvider>
+ embedded_frame_sink_provider_binding(&mock_embedded_frame_sink_provider);
+ auto override =
+ mock_embedded_frame_sink_provider.CreateScopedOverrideMojoInterface(
+ &embedded_frame_sink_provider_binding);
+
+ EXPECT_CALL(*resource_provider_, Initialize(_, _));
+ EXPECT_CALL(mock_embedded_frame_sink_provider, ConnectToEmbedder(_, _))
+ .Times(0);
+ EXPECT_CALL(mock_embedded_frame_sink_provider, CreateCompositorFrameSink_(_))
+ .Times(1);
+ submitter_->OnContextLost();
+ OnReceivedContextProvider(true, context_provider_);
+ scoped_task_environment_.RunUntilIdle();
+}
+
// Test that no crash happens if the context is lost during a frame submission.
TEST_F(VideoFrameSubmitterTest, ContextLostDuringSubmit) {
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
@@ -733,7 +618,7 @@ TEST_F(VideoFrameSubmitterTest, ContextLostDuringSubmit) {
// This will post a task that will later call SubmitFrame(). The call will
// happen after OnContextLost().
- submitter_->SubmitSingleFrame();
+ SubmitSingleFrame();
submitter_->OnContextLost();
@@ -765,7 +650,7 @@ TEST_F(VideoFrameSubmitterTest, StopUsingProviderDuringContextLost) {
// OnReceivedContextProvider returns. We don't run the actual function
// because it would overwrite our fake |sink_| with a real one.
- submitter_->SubmitSingleFrame();
+ SubmitSingleFrame();
scoped_task_environment_.RunUntilIdle();
}
@@ -776,14 +661,14 @@ TEST_F(VideoFrameSubmitterTest, StopUsingProviderDuringContextLost) {
TEST_F(VideoFrameSubmitterTest, FrameSizeChangeUpdatesLocalSurfaceId) {
{
viz::LocalSurfaceId local_surface_id =
- submitter_->child_local_surface_id_allocator_
+ child_local_surface_id_allocator()
.GetCurrentLocalSurfaceIdAllocation()
.local_surface_id();
EXPECT_TRUE(local_surface_id.is_valid());
EXPECT_EQ(11u, local_surface_id.parent_sequence_number());
EXPECT_EQ(viz::kInitialChildSequenceNumber,
local_surface_id.child_sequence_number());
- EXPECT_TRUE(submitter_->frame_size_.IsEmpty());
+ EXPECT_TRUE(frame_size().IsEmpty());
}
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
@@ -801,19 +686,19 @@ TEST_F(VideoFrameSubmitterTest, FrameSizeChangeUpdatesLocalSurfaceId) {
EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
- submitter_->SubmitSingleFrame();
+ SubmitSingleFrame();
scoped_task_environment_.RunUntilIdle();
{
viz::LocalSurfaceId local_surface_id =
- submitter_->child_local_surface_id_allocator_
+ child_local_surface_id_allocator()
.GetCurrentLocalSurfaceIdAllocation()
.local_surface_id();
EXPECT_TRUE(local_surface_id.is_valid());
EXPECT_EQ(11u, local_surface_id.parent_sequence_number());
EXPECT_EQ(viz::kInitialChildSequenceNumber,
local_surface_id.child_sequence_number());
- EXPECT_EQ(gfx::Size(8, 8), submitter_->frame_size_);
+ EXPECT_EQ(gfx::Size(8, 8), frame_size());
}
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
@@ -826,19 +711,19 @@ TEST_F(VideoFrameSubmitterTest, FrameSizeChangeUpdatesLocalSurfaceId) {
EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
- submitter_->SubmitSingleFrame();
+ SubmitSingleFrame();
scoped_task_environment_.RunUntilIdle();
{
viz::LocalSurfaceId local_surface_id =
- submitter_->child_local_surface_id_allocator_
+ child_local_surface_id_allocator()
.GetCurrentLocalSurfaceIdAllocation()
.local_surface_id();
EXPECT_TRUE(local_surface_id.is_valid());
EXPECT_EQ(11u, local_surface_id.parent_sequence_number());
EXPECT_EQ(viz::kInitialChildSequenceNumber + 1,
local_surface_id.child_sequence_number());
- EXPECT_EQ(gfx::Size(2, 2), submitter_->frame_size_);
+ EXPECT_EQ(gfx::Size(2, 2), frame_size());
}
}
@@ -846,7 +731,7 @@ TEST_F(VideoFrameSubmitterTest, VideoRotationOutputRect) {
MakeSubmitter();
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
submitter_->StartRendering();
- EXPECT_TRUE(submitter_->Rendering());
+ EXPECT_TRUE(IsRendering());
gfx::Size coded_size(1280, 720);
gfx::Size natural_size(1280, 1024);
@@ -947,4 +832,30 @@ TEST_F(VideoFrameSubmitterTest, VideoRotationOutputRect) {
}
}
+TEST_F(VideoFrameSubmitterTest, PageVisibilityControlsSubmission) {
+ // Hide the page and ensure no begin frames are issued.
+ EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
+ submitter_->SetIsPageVisible(false);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(ShouldSubmit());
+
+ // Start rendering, but since page is hidden nothing should start yet.
+ EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
+ submitter_->StartRendering();
+ scoped_task_environment_.RunUntilIdle();
+
+ // Mark the page as visible and confirm frame submission. This should not
+ // submit since we're already rendering.
+ EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
+ submitter_->SetIsPageVisible(true);
+ scoped_task_environment_.RunUntilIdle();
+
+ // Transition back to the page being hidden and ensure begin frames stop.
+ EXPECT_TRUE(ShouldSubmit());
+ EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
+ EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).Times(0);
+ submitter_->SetIsPageVisible(false);
+ scoped_task_environment_.RunUntilIdle();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/BUILD.gn b/chromium/third_party/blink/renderer/platform/heap/BUILD.gn
index 470d7033ba4..197d649e9ff 100644
--- a/chromium/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -32,6 +32,7 @@ blink_platform_sources("heap") {
sources = [
"address_cache.cc",
"address_cache.h",
+ "atomic_entry_flag.h",
"blink_gc.h",
"blink_gc_memory_dump_provider.cc",
"blink_gc_memory_dump_provider.h",
@@ -119,6 +120,7 @@ jumbo_source_set("blink_heap_unittests_sources") {
"heap_test.cc",
"heap_test_utilities.cc",
"heap_test_utilities.h",
+ "heap_thread_test.cc",
"heap_traits_test.cc",
"incremental_marking_test.cc",
"name_trait_test.cc",
diff --git a/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md b/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
index 389b9b730f0..880f6b4db05 100644
--- a/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
+++ b/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
@@ -25,7 +25,7 @@ A class that wants the lifetime management of its instances to be managed by Bli
```c++
class YourClass : public GarbageCollected<YourClass> {
- // ...
+ // ...
};
```
@@ -68,10 +68,10 @@ void someFunction(P*);
class A : public GarbageCollected<A>, public P {
public:
- void someMemberFunction()
- {
- someFunction(this); // DANGEROUS, a raw pointer to an on-heap object.
- }
+ void someMemberFunction()
+ {
+ someFunction(this); // DANGEROUS, a raw pointer to an on-heap object.
+ }
};
```
@@ -88,10 +88,10 @@ A class is said to *need finalization* when it meets either of the following cri
```c++
class YourClass : public GarbageCollectedFinalized<YourClass> {
public:
- ~YourClass() { ... } // Non-empty destructor means finalization is needed.
+ ~YourClass() { ... } // Non-empty destructor means finalization is needed.
private:
- scoped_refptr<Something> m_something; // scoped_refptr<> has non-empty destructor, so finalization is needed.
+ scoped_refptr<Something> something_; // scoped_refptr<> has non-empty destructor, so finalization is needed.
};
```
@@ -146,17 +146,17 @@ class Q : public GarbageCollectedMixin { };
class R : public Q { };
class A : public GarbageCollected<A>, public P, public R {
- USING_GARBAGE_COLLECTED_MIXIN(A); // OK, resolving pure virtual functions of P and R.
+ USING_GARBAGE_COLLECTED_MIXIN(A); // OK, resolving pure virtual functions of P and R.
};
class B : public GarbageCollected<B>, public P {
- USING_GARBAGE_COLLECTED_MIXIN(B); // OK, different garbage-collected classes may inherit from the same mixin (P).
+ USING_GARBAGE_COLLECTED_MIXIN(B); // OK, different garbage-collected classes may inherit from the same mixin (P).
};
void someFunction()
{
- new A; // OK, A can be instantiated.
- // new R; // BAD, R has pure virtual functions.
+ MakeGarbageCollected<A>(); // OK, A can be instantiated.
+ // MakeGarbageCollected<R>(); // BAD, R has pure virtual functions.
}
```
@@ -183,19 +183,19 @@ A pre-finalizer must have the following function signature: `void preFinalizer()
```c++
class YourClass : public GarbageCollectedFinalized<YourClass> {
- USING_PRE_FINALIZER(YourClass, dispose);
+ USING_PRE_FINALIZER(YourClass, dispose);
public:
- void dispose()
- {
- m_other->dispose(); // OK; you can touch other on-heap objects in a pre-finalizer.
- }
- ~YourClass()
- {
- // m_other->dispose(); // BAD.
- }
+ void dispose()
+ {
+ other_->dispose(); // OK; you can touch other on-heap objects in a pre-finalizer.
+ }
+ ~YourClass()
+ {
+ // other_->dispose(); // BAD.
+ }
private:
- Member<OtherClass> m_other;
+ Member<OtherClass> other_;
};
```
@@ -254,8 +254,8 @@ On-stack references to on-heap objects must be raw pointers.
```c++
void someFunction()
{
- SomeGarbageCollectedClass* object = new SomeGarbageCollectedClass; // OK, retained by a pointer.
- ...
+ SomeGarbageCollectedClass* object = MakeGarbageCollected<SomeGarbageCollectedClass>(); // OK, retained by a pointer.
+ ...
}
// OK to leave the object behind. The Blink GC system will free it up when it becomes unused.
```
@@ -276,10 +276,10 @@ because this rewrite is only done within Blink GC's garbage collection period.
```c++
class SomeGarbageCollectedClass : public GarbageCollected<GarbageCollectedSomething> {
- ...
+ ...
private:
- Member<AnotherGarbageCollectedClass> m_another; // OK, retained by Member<T>.
- WeakMember<AnotherGarbageCollectedClass> m_anotherWeak; // OK, weak reference.
+ Member<AnotherGarbageCollectedClass> another_; // OK, retained by Member<T>.
+ WeakMember<AnotherGarbageCollectedClass> anotherWeak_; // OK, weak reference.
};
```
@@ -309,9 +309,9 @@ garbage-collected, just like `WeakMember<T>`.
#include "third_party/blink/renderer/platform/heap/persistent.h"
...
class NonGarbageCollectedClass {
- ...
+ ...
private:
- Persistent<SomeGarbageCollectedClass> m_something; // OK, the object will be alive while this persistent is alive.
+ Persistent<SomeGarbageCollectedClass> something_; // OK, the object will be alive while this persistent is alive.
};
```
@@ -399,10 +399,10 @@ class C : public B {
};
void C::Trace(Visitor* visitor) {
- visitor->Trace(x_);
- visitor->Trace(y_); // Weak member needs to be traced.
- visitor->Trace(z_); // Heap collection does, too.
- B::Trace(visitor); // Delegate to the parent. In this case it's empty, but this is required.
+ visitor->Trace(x_);
+ visitor->Trace(y_); // Weak member needs to be traced.
+ visitor->Trace(z_); // Heap collection does, too.
+ B::Trace(visitor); // Delegate to the parent. In this case it's empty, but this is required.
}
```
@@ -414,26 +414,26 @@ phase:
void C::ClearWeakMembers(Visitor* visitor)
{
- if (ThreadHeap::isHeapObjectAlive(y_))
- return;
-
- // |m_y| is not referred to by anyone else, clear the weak
- // reference along with updating state / clearing any other
- // resources at the same time. None of those operations are
- // allowed to perform heap allocations:
- y_->detach();
-
- // Note: if the weak callback merely clears the weak reference,
- // it is much simpler to just |trace| the field rather than
- // install a custom weak callback.
- y_ = nullptr;
+ if (ThreadHeap::isHeapObjectAlive(y_))
+ return;
+
+ // |y_| is not referred to by anyone else, clear the weak
+ // reference along with updating state / clearing any other
+ // resources at the same time. None of those operations are
+ // allowed to perform heap allocations:
+ y_->detach();
+
+ // Note: if the weak callback merely clears the weak reference,
+ // it is much simpler to just |trace| the field rather than
+ // install a custom weak callback.
+ y_ = nullptr;
}
void C::Trace(Visitor* visitor) {
- visitor->template registerWeakMembers<C, &C::ClearWeakMembers>(this);
- visitor->Trace(x_);
- visitor->Trace(z_); // Heap collection does, too.
- B::Trace(visitor); // Delegate to the parent. In this case it's empty, but this is required.
+ visitor->template registerWeakMembers<C, &C::ClearWeakMembers>(this);
+ visitor->Trace(x_);
+ visitor->Trace(z_); // Heap collection does, too.
+ B::Trace(visitor); // Delegate to the parent. In this case it's empty, but this is required.
}
```
diff --git a/chromium/third_party/blink/renderer/platform/heap/atomic_entry_flag.h b/chromium/third_party/blink/renderer/platform/heap/atomic_entry_flag.h
new file mode 100644
index 00000000000..0404e9e4c70
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/atomic_entry_flag.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_
+
+#include <atomic>
+
+namespace blink {
+
+// A flag which provides a fast check whether a scope may be entered on the
+// current thread, without needing to access thread-local storage or mutex.
+//
+// Can have false positives (i.e., spuriously report that it might be entered),
+// so it is expected that this will be used in tandem with a precise check that
+// the scope is in fact entered on that thread.
+//
+// Example:
+// g_frobnicating_flag.MightBeEntered() &&
+// ThreadLocalFrobnicator().IsFrobnicating()
+//
+// Relaxed atomic operations are sufficient, since:
+// - all accesses remain atomic
+// - each thread must observe its own operations in order
+// - no thread ever exits the flag more times than it enters (if used correctly)
+// And so if a thread observes zero, it must be because it has observed an equal
+// number of exits as entries.
+class AtomicEntryFlag {
+ public:
+ inline void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); }
+ inline void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); }
+
+ // Returns false only if the current thread is not between a call to Enter and
+ // a call to Exit. Returns true if this thread or another thread may currently
+ // be in the scope guarded by this flag.
+ inline bool MightBeEntered() const {
+ return entries_.load(std::memory_order_relaxed) != 0;
+ }
+
+ private:
+ std::atomic_int entries_{0};
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc.h b/chromium/third_party/blink/renderer/platform/heap/blink_gc.h
index 04dac693e11..bc35c3519ce 100644
--- a/chromium/third_party/blink/renderer/platform/heap/blink_gc.h
+++ b/chromium/third_party/blink/renderer/platform/heap/blink_gc.h
@@ -14,7 +14,6 @@
namespace blink {
-class HeapObjectHeader;
class MarkingVisitor;
class Visitor;
@@ -28,12 +27,6 @@ using WeakCallback = VisitorCallback;
using EphemeronCallback = VisitorCallback;
using NameCallback = const char* (*)(const void* self);
-// Callback used for unit testing the marking of conservative pointers
-// (|CheckAndMarkPointer|). For each pointer that has been discovered to point
-// to a heap object, the callback is invoked with a pointer to its header. If
-// the callback returns true, the object will not be marked.
-using MarkedPointerCallbackForTesting = bool (*)(HeapObjectHeader*);
-
// Simple alias to avoid heap compaction type signatures turning into
// a sea of generic |void*|s.
using MovableReference = void*;
diff --git a/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h
index d07e1e4cf23..2ccb869c823 100644
--- a/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h
+++ b/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h
@@ -47,12 +47,17 @@ struct IsGarbageCollectedMixin {
static const bool value = sizeof(CheckMarker<T>(nullptr)) == sizeof(YesType);
};
+// TraceDescriptor is used to describe how to trace an object.
struct TraceDescriptor {
STACK_ALLOCATED();
public:
+ // The adjusted base pointer of the object that should be traced.
void* base_object_payload;
+ // A callback for tracing the object.
TraceCallback callback;
+ // Indicator whether this object can be traced recursively or whether it
+ // requires iterative tracing.
bool can_trace_eagerly;
};
@@ -72,11 +77,14 @@ struct TraceDescriptor {
// USING_GARBAGE_COLLECTED_MIXIN(A);
// };
//
-// With the helper, as long as we are using Member<B>, TypeTrait<B> will
-// dispatch dynamically to retrieve the necessary tracing and header methods.
-// Note that this is only enabled for Member<B>. For Member<A> which we can
-// compute the necessary methods and pointers statically and this dynamic
-// dispatch is not used.
+// The classes involved and the helper macros allow for properly handling
+// definitions for Member<B> and friends. The mechanisms for handling Member<B>
+// involve dynamic dispatch. Note that for Member<A> all methods and pointers
+// are statically computed and no dynamic dispatch is involved.
+//
+// Note that garbage collections are allowed during mixin construction as
+// conservative scanning of objects does not rely on the Trace method but rather
+// scans the object field by field.
class PLATFORM_EXPORT GarbageCollectedMixin {
public:
typedef int IsGarbageCollectedMixinMarker;
@@ -86,7 +94,8 @@ class PLATFORM_EXPORT GarbageCollectedMixin {
// these objects can processed later on. This is necessary as
// not-fully-constructed mixin objects potentially require being processed
// as part emitting a write barrier for incremental marking. See
- // IncrementalMarkingTest::WriteBarrierDuringMixinConstruction as an example.
+ // |IncrementalMarkingTest::WriteBarrierDuringMixinConstruction| as an
+ // example.
//
// The not-fully-constructed objects are handled as follows:
// 1. Write barrier or marking of not fully constructed mixin gets called.
@@ -127,114 +136,48 @@ class PLATFORM_EXPORT GarbageCollectedMixin {
\
private:
-// A C++ object's vptr will be initialized to its leftmost base's vtable after
-// the constructors of all its subclasses have run, so if a subclass constructor
-// tries to access any of the vtbl entries of its leftmost base prematurely,
-// it'll find an as-yet incorrect vptr and fail. Which is exactly what a
-// garbage collector will try to do if it tries to access the leftmost base
-// while one of the subclass constructors of a GC mixin object triggers a GC.
-// It is consequently not safe to allow any GCs while these objects are under
-// (sub constructor) construction.
-//
-// To prevent GCs in that restricted window of a mixin object's construction:
-//
-// - The initial allocation of the mixin object will enter a no GC scope.
-// This is done by overriding 'operator new' for mixin instances.
-// - When the constructor for the mixin is invoked, after all the
-// derived constructors have run, it will invoke the constructor
-// for a field whose only purpose is to leave the GC scope.
-// GarbageCollectedMixinConstructorMarker's constructor takes care of
-// this and the field is declared by way of USING_GARBAGE_COLLECTED_MIXIN().
-
-#define DEFINE_GARBAGE_COLLECTED_MIXIN_CONSTRUCTOR_MARKER(TYPE) \
- public: \
- GC_PLUGIN_IGNORE("crbug.com/456823") \
- NO_SANITIZE_UNRELATED_CAST void* operator new(size_t size) { \
- CHECK_GE(kLargeObjectSizeThreshold, size) \
- << "GarbageCollectedMixin may not be a large object"; \
- void* object = \
- TYPE::AllocateObject(size, IsEagerlyFinalizedType<TYPE>::value); \
- ThreadState* state = \
- ThreadStateFor<ThreadingTrait<TYPE>::kAffinity>::GetState(); \
- state->EnterGCForbiddenScopeIfNeeded( \
- &(reinterpret_cast<TYPE*>(object)->mixin_constructor_marker_)); \
- return object; \
- } \
- GarbageCollectedMixinConstructorMarker<ThreadingTrait<TYPE>::kAffinity> \
- mixin_constructor_marker_; \
- \
+// The Oilpan GC plugin checks for proper usages of the
+// USING_GARBAGE_COLLECTED_MIXIN macro using a typedef marker.
+#define DEFINE_GARBAGE_COLLECTED_MIXIN_CONSTRUCTOR_MARKER(TYPE) \
+ public: \
+ typedef int HasUsingGarbageCollectedMixinMacro; \
+ \
private:
-// Mixins that wrap/nest others requires extra handling:
-//
-// class A : public GarbageCollected<A>, public GarbageCollectedMixin {
-// USING_GARBAGE_COLLECTED_MIXIN(A);
-// ...
-// }'
-// public B final : public A, public SomeOtherMixinInterface {
-// USING_GARBAGE_COLLECTED_MIXIN(B);
-// ...
-// };
-//
-// The "operator new" for B will enter the forbidden GC scope, but
-// upon construction, two GarbageCollectedMixinConstructorMarker constructors
-// will run -- one for A (first) and another for B (secondly). Only
-// the second one should leave the forbidden GC scope. This is realized by
-// recording the address of B's GarbageCollectedMixinConstructorMarker
-// when the "operator new" for B runs, and leaving the forbidden GC scope
-// when the constructor of the recorded GarbageCollectedMixinConstructorMarker
-// runs.
+// The USING_GARBAGE_COLLECTED_MIXIN macro defines all methods and markers
+// needed for handling mixins.
#define USING_GARBAGE_COLLECTED_MIXIN(TYPE) \
IS_GARBAGE_COLLECTED_TYPE(); \
DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(TYPE) \
DEFINE_GARBAGE_COLLECTED_MIXIN_CONSTRUCTOR_MARKER(TYPE)
-// An empty class with a constructor that's arranged invoked when all derived
-// constructors of a mixin instance have completed and it is safe to allow GCs
-// again. See AllocateObjectTrait<> comment for more.
-//
-// USING_GARBAGE_COLLECTED_MIXIN() declares a
-// GarbageCollectedMixinConstructorMarker<> private field. By following Blink
-// convention of using the macro at the top of a class declaration, its
-// constructor will run first.
-class GarbageCollectedMixinConstructorMarkerBase {};
-template <ThreadAffinity affinity>
-class GarbageCollectedMixinConstructorMarker
- : public GarbageCollectedMixinConstructorMarkerBase {
- public:
- GarbageCollectedMixinConstructorMarker() {
- // FIXME: if prompt conservative GCs are needed, forced GCs that
- // were denied while within this scope, could now be performed.
- // For now, assume the next out-of-line allocation request will
- // happen soon enough and take care of it. Mixin objects aren't
- // overly common.
- ThreadState* state = ThreadStateFor<affinity>::GetState();
- state->LeaveGCForbiddenScopeIfNeeded(this);
- }
-};
-
// Merge two or more Mixins into one:
//
// class A : public GarbageCollectedMixin {};
// class B : public GarbageCollectedMixin {};
// class C : public A, public B {
// // C::GetTraceDescriptor is now ambiguous because there are two
-// candidates:
-// // A::GetTraceDescriptor and B::GetTraceDescriptor. Ditto for other
-// functions.
+// // candidates: A::GetTraceDescriptor and B::GetTraceDescriptor. Ditto for
+// // other functions.
//
// MERGE_GARBAGE_COLLECTED_MIXINS();
-// // The macro defines C::GetTraceDescriptor, etc. so that they are no
-// longer
-// // ambiguous. USING_GARBAGE_COLLECTED_MIXIN(TYPE) overrides them later
-// // and provides the implementations.
+// // The macro defines C::GetTraceDescriptor, similar to
+// GarbageCollectedMixin,
+// // so that they are no longer ambiguous.
+// // USING_GARBAGE_COLLECTED_MIXIN(TYPE) overrides them later and provides
+// // the implementations.
// };
-#define MERGE_GARBAGE_COLLECTED_MIXINS() \
- public: \
- HeapObjectHeader* GetHeapObjectHeader() const override = 0; \
- TraceDescriptor GetTraceDescriptor() const override = 0; \
- \
- private: \
+#define MERGE_GARBAGE_COLLECTED_MIXINS() \
+ public: \
+ HeapObjectHeader* GetHeapObjectHeader() const override { \
+ return reinterpret_cast<HeapObjectHeader*>( \
+ BlinkGC::kNotFullyConstructedObject); \
+ } \
+ TraceDescriptor GetTraceDescriptor() const override { \
+ return {BlinkGC::kNotFullyConstructedObject, nullptr, false}; \
+ } \
+ \
+ private: \
using merge_garbage_collected_mixins_requires_semicolon = void
// Base class for objects allocated in the Blink garbage-collected heap.
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap.cc b/chromium/third_party/blink/renderer/platform/heap/heap.cc
index 8a1dc1bd0d8..cf507ab338a 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/heap.cc
@@ -142,29 +142,6 @@ Address ThreadHeap::CheckAndMarkPointer(MarkingVisitor* visitor,
return nullptr;
}
-#if DCHECK_IS_ON()
-// To support unit testing of the marking of off-heap root references
-// into the heap, provide a checkAndMarkPointer() version with an
-// extra notification argument.
-Address ThreadHeap::CheckAndMarkPointer(
- MarkingVisitor* visitor,
- Address address,
- MarkedPointerCallbackForTesting callback) {
- DCHECK(thread_state_->InAtomicMarkingPause());
-
- if (BasePage* page = LookupPageForAddress(address)) {
- DCHECK(page->Contains(address));
- DCHECK(!address_cache_->Lookup(address));
- DCHECK(&visitor->Heap() == &page->Arena()->GetThreadState()->Heap());
- visitor->ConservativelyMarkAddress(page, address, callback);
- return address;
- }
- if (!address_cache_->Lookup(address))
- address_cache_->AddEntry(address);
- return nullptr;
-}
-#endif // DCHECK_IS_ON()
-
void ThreadHeap::RegisterWeakTable(void* table,
EphemeronCallback iteration_callback) {
DCHECK(thread_state_->InAtomicMarkingPause());
@@ -180,15 +157,39 @@ void ThreadHeap::RegisterWeakTable(void* table,
void ThreadHeap::CommitCallbackStacks() {
marking_worklist_.reset(new MarkingWorklist());
not_fully_constructed_worklist_.reset(new NotFullyConstructedWorklist());
+ previously_not_fully_constructed_worklist_.reset(
+ new NotFullyConstructedWorklist());
weak_callback_worklist_.reset(new WeakCallbackWorklist());
DCHECK(ephemeron_callbacks_.IsEmpty());
}
void ThreadHeap::DecommitCallbackStacks() {
marking_worklist_.reset(nullptr);
- not_fully_constructed_worklist_.reset(nullptr);
+ previously_not_fully_constructed_worklist_.reset(nullptr);
weak_callback_worklist_.reset(nullptr);
ephemeron_callbacks_.clear();
+
+ // The fixed point iteration may have found not-fully-constructed objects.
+ // Such objects should have already been found through the stack scan though
+ // and should thus already be marked.
+ if (!not_fully_constructed_worklist_->IsGlobalEmpty()) {
+#if DCHECK_IS_ON()
+ NotFullyConstructedItem item;
+ while (not_fully_constructed_worklist_->Pop(WorklistTaskId::MainThread,
+ &item)) {
+ BasePage* const page = PageFromObject(item);
+ HeapObjectHeader* const header =
+ page->IsLargeObjectPage()
+ ? static_cast<LargeObjectPage*>(page)->ObjectHeader()
+ : static_cast<NormalPage*>(page)->FindHeaderFromAddress(
+ reinterpret_cast<Address>(const_cast<void*>(item)));
+ DCHECK(header->IsMarked());
+ }
+#else
+ not_fully_constructed_worklist_->Clear();
+#endif
+ }
+ not_fully_constructed_worklist_.reset(nullptr);
}
HeapCompact* ThreadHeap::Compaction() {
@@ -207,6 +208,15 @@ void ThreadHeap::RegisterMovingObjectCallback(MovableReference* slot,
Compaction()->RegisterMovingObjectCallback(slot, callback, callback_data);
}
+void ThreadHeap::FlushNotFullyConstructedObjects() {
+ if (!not_fully_constructed_worklist_->IsGlobalEmpty()) {
+ not_fully_constructed_worklist_->FlushToGlobal(WorklistTaskId::MainThread);
+ previously_not_fully_constructed_worklist_->MergeGlobalPool(
+ not_fully_constructed_worklist_.get());
+ }
+ DCHECK(not_fully_constructed_worklist_->IsGlobalEmpty());
+}
+
void ThreadHeap::MarkNotFullyConstructedObjects(MarkingVisitor* visitor) {
DCHECK(!thread_state_->IsIncrementalMarking());
ThreadHeapStatsCollector::Scope stats_scope(
@@ -245,9 +255,33 @@ void ThreadHeap::InvokeEphemeronCallbacks(Visitor* visitor) {
ephemeron_callbacks_ = std::move(final_set);
}
-bool ThreadHeap::AdvanceMarking(MarkingVisitor* visitor, TimeTicks deadline) {
+namespace {
+
+template <typename Worklist, typename Callback>
+bool DrainWorklistWithDeadline(TimeTicks deadline,
+ Worklist* worklist,
+ Callback callback) {
const size_t kDeadlineCheckInterval = 2500;
+
size_t processed_callback_count = 0;
+ typename Worklist::EntryType item;
+ while (worklist->Pop(WorklistTaskId::MainThread, &item)) {
+ callback(item);
+ processed_callback_count++;
+ if (++processed_callback_count == kDeadlineCheckInterval) {
+ if (deadline <= CurrentTimeTicks()) {
+ return false;
+ }
+ processed_callback_count = 0;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+bool ThreadHeap::AdvanceMarking(MarkingVisitor* visitor, TimeTicks deadline) {
+ bool finished;
// Ephemeron fixed point loop.
do {
{
@@ -255,16 +289,27 @@ bool ThreadHeap::AdvanceMarking(MarkingVisitor* visitor, TimeTicks deadline) {
// currently pushed onto the marking worklist.
ThreadHeapStatsCollector::Scope stats_scope(
stats_collector(), ThreadHeapStatsCollector::kMarkProcessWorklist);
- MarkingItem item;
- while (marking_worklist_->Pop(WorklistTaskId::MainThread, &item)) {
- item.callback(visitor, item.object);
- processed_callback_count++;
- if (processed_callback_count % kDeadlineCheckInterval == 0) {
- if (deadline <= CurrentTimeTicks()) {
- return false;
- }
- }
- }
+
+ finished = DrainWorklistWithDeadline(
+ deadline, marking_worklist_.get(),
+ [visitor](const MarkingItem& item) {
+ DCHECK(!HeapObjectHeader::FromPayload(item.object)
+ ->IsInConstruction());
+ item.callback(visitor, item.object);
+ });
+ if (!finished)
+ return false;
+
+ // Iteratively mark all objects that were previously discovered while
+ // being in construction. The objects can be processed incrementally once
+ // a safepoint was reached.
+ finished = DrainWorklistWithDeadline(
+ deadline, previously_not_fully_constructed_worklist_.get(),
+ [visitor](const NotFullyConstructedItem& item) {
+ visitor->DynamicallyMarkAddress(reinterpret_cast<Address>(item));
+ });
+ if (!finished)
+ return false;
}
InvokeEphemeronCallbacks(visitor);
@@ -576,6 +621,12 @@ void ThreadHeap::WriteBarrier(void* value) {
if (header->IsMarked())
return;
+ if (header->IsInConstruction()) {
+ not_fully_constructed_worklist_->Push(WorklistTaskId::MainThread,
+ header->Payload());
+ return;
+ }
+
// Mark and push trace callback.
header->Mark();
marking_worklist_->Push(
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap.h b/chromium/third_party/blink/renderer/platform/heap/heap.h
index 18d8498d8ea..0f81c2b2829 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap.h
@@ -47,7 +47,6 @@
#include "third_party/blink/renderer/platform/wtf/address_sanitizer.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/atomics.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
@@ -122,6 +121,8 @@ class WeakMember;
template <typename T>
class UntracedMember;
+namespace internal {
+
template <typename T, bool = NeedsAdjustPointer<T>::value>
class ObjectAliveTrait;
@@ -144,10 +145,17 @@ class ObjectAliveTrait<T, true> {
NO_SANITIZE_ADDRESS
static bool IsHeapObjectAlive(const T* object) {
static_assert(sizeof(T), "T must be fully defined");
- return object->GetHeapObjectHeader()->IsMarked();
+ const HeapObjectHeader* header = object->GetHeapObjectHeader();
+ if (header == BlinkGC::kNotFullyConstructedObject) {
+ // Objects under construction are always alive.
+ return true;
+ }
+ return header->IsMarked();
}
};
+} // namespace internal
+
class PLATFORM_EXPORT ThreadHeap {
public:
explicit ThreadHeap(ThreadState*);
@@ -174,7 +182,7 @@ class PLATFORM_EXPORT ThreadHeap {
return true;
DCHECK(&ThreadState::Current()->Heap() ==
&PageFromObject(object)->Arena()->GetThreadState()->Heap());
- return ObjectAliveTrait<T>::IsHeapObjectAlive(object);
+ return internal::ObjectAliveTrait<T>::IsHeapObjectAlive(object);
}
template <typename T>
static inline bool IsHeapObjectAlive(const Member<T>& member) {
@@ -284,6 +292,11 @@ class PLATFORM_EXPORT ThreadHeap {
void WeakProcessing(Visitor*);
+ // Moves not fully constructed objects to previously not fully constructed
+ // objects. Such objects can be iterated using the Trace() method and do
+ // not need to rely on conservative handling.
+ void FlushNotFullyConstructedObjects();
+
// Marks not fully constructed objects.
void MarkNotFullyConstructedObjects(MarkingVisitor*);
// Marks the transitive closure including ephemerons.
@@ -293,11 +306,6 @@ class PLATFORM_EXPORT ThreadHeap {
// Conservatively checks whether an address is a pointer in any of the
// thread heaps. If so marks the object pointed to as live.
Address CheckAndMarkPointer(MarkingVisitor*, Address);
-#if DCHECK_IS_ON()
- Address CheckAndMarkPointer(MarkingVisitor*,
- Address,
- MarkedPointerCallbackForTesting);
-#endif
size_t ObjectPayloadSizeForTesting();
@@ -436,9 +444,29 @@ class PLATFORM_EXPORT ThreadHeap {
std::unique_ptr<RegionTree> region_tree_;
std::unique_ptr<AddressCache> address_cache_;
std::unique_ptr<PagePool> free_page_pool_;
+
+ // All objects on this worklist have been fully initialized and assigned a
+ // trace callback for iterating the body of the object. This worklist should
+ // contain almost all objects.
std::unique_ptr<MarkingWorklist> marking_worklist_;
+
+ // Objects on this worklist were observed to be in construction (in their
+ // constructor) and thus have been delayed for processing. They have not yet
+ // been assigned a valid header and trace callback.
std::unique_ptr<NotFullyConstructedWorklist> not_fully_constructed_worklist_;
+
+ // Objects on this worklist were previously in construction but have been
+ // moved here upon observing a safepoint, i.e., processing without stack. They
+ // have not yet been assigned a valid header and trace callback but are fully
+ // specified and can thus be iterated using the trace callback (which can be
+ // looked up dynamically).
+ std::unique_ptr<NotFullyConstructedWorklist>
+ previously_not_fully_constructed_worklist_;
+
+ // Worklist of weak callbacks accumulated for objects. Such callbacks are
+ // processed after finishing marking objects.
std::unique_ptr<WeakCallbackWorklist> weak_callback_worklist_;
+
// No duplicates allowed for ephemeron callbacks. Hence, we use a hashmap
// with the key being the HashTable.
WTF::HashMap<void*, EphemeronCallback> ephemeron_callbacks_;
@@ -508,11 +536,14 @@ class GarbageCollected {
public:
using GarbageCollectedType = T;
- void* operator new(size_t size) {
- return AllocateObject(size, IsEagerlyFinalizedType<T>::value);
- }
+ void* operator new(size_t size) = delete; // Must use MakeGarbageCollected.
static void* AllocateObject(size_t size, bool eagerly_sweep) {
+ if (IsGarbageCollectedMixin<T>::value) {
+ // Ban large mixin so we can use PageFromObject() on them.
+ CHECK_GE(kLargeObjectSizeThreshold, size)
+ << "GarbageCollectedMixin may not be a large object";
+ }
return ThreadHeap::Allocate<T>(size, eagerly_sweep);
}
@@ -524,53 +555,18 @@ class GarbageCollected {
DISALLOW_COPY_AND_ASSIGN(GarbageCollected);
};
-template <typename T, bool is_mixin = IsGarbageCollectedMixin<T>::value>
-class ConstructTrait {
- public:
-};
-
-template <typename T>
-class ConstructTrait<T, false> {
- public:
- template <typename... Args>
- static T* Construct(Args&&... args) {
- void* memory =
- T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value);
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
- header->MarkIsInConstruction();
- // Placement new as regular operator new() is deleted.
- T* object = ::new (memory) T(std::forward<Args>(args)...);
- header->UnmarkIsInConstruction();
- return object;
- }
-};
-
-template <typename T>
-class ConstructTrait<T, true> {
- public:
- template <typename... Args>
- NO_SANITIZE_UNRELATED_CAST static T* Construct(Args&&... args) {
- void* memory =
- T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value);
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
- header->MarkIsInConstruction();
- ThreadState* state =
- ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
- state->EnterGCForbiddenScopeIfNeeded(
- &(reinterpret_cast<T*>(memory)->mixin_constructor_marker_));
- // Placement new as regular operator new() is deleted.
- T* object = ::new (memory) T(std::forward<Args>(args)...);
- header->UnmarkIsInConstruction();
- return object;
- }
-};
-
// Constructs an instance of T, which is a garbage collected type.
template <typename T, typename... Args>
T* MakeGarbageCollected(Args&&... args) {
static_assert(WTF::IsGarbageCollectedType<T>::value,
"T needs to be a garbage collected object");
- return ConstructTrait<T>::Construct(std::forward<Args>(args)...);
+ void* memory = T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value);
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
+ header->MarkIsInConstruction();
+ // Placement new as regular operator new() is deleted.
+ T* object = ::new (memory) T(std::forward<Args>(args)...);
+ header->UnmarkIsInConstruction();
+ return object;
}
// Assigning class types to their arenas.
@@ -731,7 +727,7 @@ void Visitor::HandleWeakCell(Visitor* self, void* object) {
// preserved to avoid reviving objects in containers.
return;
}
- if (!ObjectAliveTrait<T>::IsHeapObjectAlive(contents))
+ if (!ThreadHeap::IsHeapObjectAlive(contents))
*cell = nullptr;
}
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h
index fc47be71ac8..01d96002e48 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
#include "build/build_config.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
@@ -135,6 +136,17 @@ class PLATFORM_EXPORT HeapAllocator {
MarkingVisitor::WriteBarrier(address);
}
+ template <typename T>
+ static void BackingWriteBarrier(TraceWrapperMember<T>* address, size_t size) {
+ MarkingVisitor::WriteBarrier(address);
+ ScriptWrappableMarkingVisitor::WriteBarrier(address, size);
+ }
+
+ template <typename T>
+ static void BackingWriteBarrier(T* address, size_t size) {
+ MarkingVisitor::WriteBarrier(address);
+ }
+
template <typename Return, typename Metadata>
static Return Malloc(size_t size, const char* type_name) {
return reinterpret_cast<Return>(ThreadHeap::Allocate<Metadata>(
@@ -719,7 +731,8 @@ struct VectorTraits<blink::TraceWrapperMember<T>>
static const bool kCanInitializeWithMemset = true;
static const bool kCanClearUnusedSlotsWithMemset = true;
static const bool kCanMoveWithMemcpy = true;
- static const bool kCanSwapUsingCopyOrMove = false;
+ static const bool kCanCopyWithMemcpy = true;
+ static const bool kCanSwapUsingCopyOrMove = true;
};
template <typename T>
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_compact.cc b/chromium/third_party/blink/renderer/platform/heap/heap_compact.cc
index 551e0059f5a..055f2dc71ba 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "base/debug/alias.h"
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
@@ -191,6 +192,16 @@ class HeapCompact::MovableObjectFixups final {
DCHECK(relocatable_pages_.Contains(from_page));
#endif
+ // TODO(keishi): Code to determine if crash is related to interior fixups.
+ // Remove when finished. crbug.com/918064
+ enum DebugSlotType {
+ kNormalSlot,
+ kInteriorSlotPreMove,
+ kInteriorSlotPostMove,
+ };
+ DebugSlotType slot_type = kNormalSlot;
+ base::debug::Alias(&slot_type);
+
// If the object is referenced by a slot that is contained on a compacted
// area itself, check whether it can be updated already.
MovableReference* slot = reinterpret_cast<MovableReference*>(it->value);
@@ -200,10 +211,12 @@ class HeapCompact::MovableObjectFixups final {
reinterpret_cast<MovableReference*>(interior->value);
if (!slot_location) {
interior_fixups_.Set(slot, to);
+ slot_type = kInteriorSlotPreMove;
} else {
LOG_HEAP_COMPACTION()
<< "Redirected slot: " << slot << " => " << slot_location;
slot = slot_location;
+ slot_type = kInteriorSlotPostMove;
}
}
@@ -368,14 +381,10 @@ bool HeapCompact::ShouldCompact(ThreadHeap* heap,
return force_compaction_gc_;
}
- // TODO(keishi): Should be enable after fixing the crashes.
- if (marking_type == BlinkGC::kIncrementalMarking)
- return false;
-
- // TODO(harukamt): Add kIncrementalIdleGC and kIncrementalV8FollowupGC when we
- // enable heap compaction for incremental marking.
if (reason != BlinkGC::GCReason::kIdleGC &&
reason != BlinkGC::GCReason::kPreciseGC &&
+ reason != BlinkGC::GCReason::kIncrementalIdleGC &&
+ reason != BlinkGC::GCReason::kIncrementalV8FollowupGC &&
reason != BlinkGC::GCReason::kForcedGC)
return false;
@@ -512,6 +521,16 @@ void HeapCompact::FinishThreadCompaction() {
do_compact_ = false;
}
+void HeapCompact::CancelCompaction() {
+ if (!do_compact_)
+ return;
+
+ last_fixup_count_for_testing_ = 0;
+ traced_slots_.clear();
+ fixups_.reset();
+ do_compact_ = false;
+}
+
void HeapCompact::AddCompactingPage(BasePage* page) {
DCHECK(do_compact_);
DCHECK(IsCompactingArena(page->Arena()->ArenaIndex()));
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_compact.h b/chromium/third_party/blink/renderer/platform/heap/heap_compact.h
index a41c5d39ef0..ec0ef448537 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_compact.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_compact.h
@@ -105,6 +105,8 @@ class PLATFORM_EXPORT HeapCompact final {
void StartThreadCompaction();
void FinishThreadCompaction();
+ void CancelCompaction();
+
// Perform any relocation post-processing after having completed compacting
// the given arena. The number of pages that were freed together with the
// total size (in bytes) of freed heap storage, are passed in as arguments.
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_compact_test.cc b/chromium/third_party/blink/renderer/platform/heap/heap_compact_test.cc
index c7035774eab..a09b609e77c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_compact_test.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_compact_test.cc
@@ -30,7 +30,7 @@ class IntWrapper : public blink::GarbageCollectedFinalized<IntWrapper> {
static IntWrapper* Create(int x, VerifyArenaCompaction verify = NoVerify) {
did_verify_at_least_once = false;
- return new IntWrapper(x, verify);
+ return blink::MakeGarbageCollected<IntWrapper>(x, verify);
}
virtual ~IntWrapper() = default;
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_page.h b/chromium/third_party/blink/renderer/platform/heap/heap_page.h
index b2625f01a6a..063a6e0a78b 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_page.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_page.h
@@ -584,7 +584,7 @@ class PLATFORM_EXPORT NormalPage final : public BasePage {
// In order to use the same memory allocation routines for everything allocated
// in the heap, large objects are considered heap pages containing only one
// object.
-class LargeObjectPage final : public BasePage {
+class PLATFORM_EXPORT LargeObjectPage final : public BasePage {
public:
static size_t PageHeaderSize() {
// Compute the amount of padding we have to add to a header to make the size
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_test.cc b/chromium/third_party/blink/renderer/platform/heap/heap_test.cc
index d2f50322d53..64ab4fd551e 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_test.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -29,11 +29,14 @@
*/
#include <algorithm>
+#include <atomic>
#include <memory>
#include <utility>
+#include "base/atomic_ref_count.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
+#include "base/synchronization/waitable_event.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
@@ -61,11 +64,15 @@ namespace {
class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
public:
- static IntWrapper* Create(int x) { return new IntWrapper(x); }
+ static IntWrapper* Create(int x) {
+ return MakeGarbageCollected<IntWrapper>(x);
+ }
- virtual ~IntWrapper() { AtomicIncrement(&destructor_calls_); }
+ virtual ~IntWrapper() {
+ destructor_calls_.fetch_add(1, std::memory_order_relaxed);
+ }
- static int destructor_calls_;
+ static std::atomic_int destructor_calls_;
void Trace(blink::Visitor* visitor) {}
int Value() const { return x_; }
@@ -83,6 +90,8 @@ class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
int x_;
};
+std::atomic_int IntWrapper::destructor_calls_{0};
+
struct IntWrapperHash {
static unsigned GetHash(const IntWrapper& key) {
return WTF::HashInt(static_cast<uint32_t>(key.Value()));
@@ -381,7 +390,8 @@ class TestGCScope : public TestGCCollectGarbageScope {
class SimpleObject : public GarbageCollected<SimpleObject> {
public:
- static SimpleObject* Create() { return new SimpleObject(); }
+ static SimpleObject* Create() { return MakeGarbageCollected<SimpleObject>(); }
+ SimpleObject() = default;
void Trace(blink::Visitor* visitor) {}
char GetPayload(int i) { return payload[i]; }
// This virtual method is unused but it is here to make sure
@@ -393,22 +403,21 @@ class SimpleObject : public GarbageCollected<SimpleObject> {
virtual void VirtualMethod() {}
protected:
- SimpleObject() = default;
char payload[64];
};
class HeapTestSuperClass
: public GarbageCollectedFinalized<HeapTestSuperClass> {
public:
- static HeapTestSuperClass* Create() { return new HeapTestSuperClass(); }
+ static HeapTestSuperClass* Create() {
+ return MakeGarbageCollected<HeapTestSuperClass>();
+ }
+ HeapTestSuperClass() = default;
virtual ~HeapTestSuperClass() { ++destructor_calls_; }
static int destructor_calls_;
void Trace(blink::Visitor* visitor) {}
-
- protected:
- HeapTestSuperClass() = default;
};
int HeapTestSuperClass::destructor_calls_ = 0;
@@ -423,8 +432,11 @@ static const size_t kClassMagic = 0xABCDDBCA;
class HeapTestSubClass : public HeapTestOtherSuperClass,
public HeapTestSuperClass {
public:
- static HeapTestSubClass* Create() { return new HeapTestSubClass(); }
+ static HeapTestSubClass* Create() {
+ return MakeGarbageCollected<HeapTestSubClass>();
+ }
+ HeapTestSubClass() : magic_(kClassMagic) {}
~HeapTestSubClass() override {
EXPECT_EQ(kClassMagic, magic_);
++destructor_calls_;
@@ -433,8 +445,6 @@ class HeapTestSubClass : public HeapTestOtherSuperClass,
static int destructor_calls_;
private:
- HeapTestSubClass() : magic_(kClassMagic) {}
-
const size_t magic_;
};
@@ -483,24 +493,21 @@ class OffHeapInt : public RefCounted<OffHeapInt> {
int x_;
};
-int IntWrapper::destructor_calls_ = 0;
int OffHeapInt::destructor_calls_ = 0;
class ThreadedTesterBase {
protected:
static void Test(ThreadedTesterBase* tester) {
- Vector<std::unique_ptr<Thread>, kNumberOfThreads> threads;
- for (int i = 0; i < kNumberOfThreads; i++) {
- threads.push_back(Platform::Current()->CreateThread(
+ std::unique_ptr<Thread> threads[kNumberOfThreads];
+ for (auto& thread : threads) {
+ thread = Platform::Current()->CreateThread(
ThreadCreationParams(WebThreadType::kTestThread)
- .SetThreadNameForTest("blink gc testing thread")));
+ .SetThreadNameForTest("blink gc testing thread"));
PostCrossThreadTask(
- *threads.back()->GetTaskRunner(), FROM_HERE,
+ *thread->GetTaskRunner(), FROM_HERE,
CrossThreadBind(ThreadFunc, CrossThreadUnretained(tester)));
}
- while (AcquireLoad(&tester->threads_to_finish_)) {
- test::YieldCurrentThread();
- }
+ tester->done_.Wait();
delete tester;
}
@@ -511,21 +518,26 @@ class ThreadedTesterBase {
static const int kGcPerThread = 5;
static const int kNumberOfAllocations = 50;
- ThreadedTesterBase() : gc_count_(0), threads_to_finish_(kNumberOfThreads) {}
-
virtual ~ThreadedTesterBase() = default;
inline bool Done() const {
- return AcquireLoad(&gc_count_) >= kNumberOfThreads * kGcPerThread;
+ return gc_count_.load(std::memory_order_acquire) >=
+ kNumberOfThreads * kGcPerThread;
}
- volatile int gc_count_;
- volatile int threads_to_finish_;
+ std::atomic_int gc_count_{0};
private:
- static void ThreadFunc(void* data) {
- reinterpret_cast<ThreadedTesterBase*>(data)->RunThread();
+ static void ThreadFunc(ThreadedTesterBase* tester) {
+ ThreadState::AttachCurrentThread();
+ tester->RunThread();
+ ThreadState::DetachCurrentThread();
+ if (!tester->threads_to_finish_.Decrement())
+ tester->done_.Signal();
}
+
+ base::AtomicRefCount threads_to_finish_{kNumberOfThreads};
+ base::WaitableEvent done_;
};
// Needed to give this variable a definition (the initializer above is only a
@@ -563,8 +575,6 @@ class ThreadedHeapTester : public ThreadedTesterBase {
}
void RunThread() override {
- ThreadState::AttachCurrentThread();
-
// Add a cross-thread persistent from this thread; the test object
// verifies that it will have been cleared out after the threads
// have all detached, running their termination GCs while doing so.
@@ -589,7 +599,7 @@ class ThreadedHeapTester : public ThreadedTesterBase {
if (gc_count < kGcPerThread) {
PreciselyCollectGarbage();
gc_count++;
- AtomicIncrement(&gc_count_);
+ gc_count_.fetch_add(1, std::memory_order_release);
}
// Taking snapshot shouldn't have any bad side effect.
@@ -603,9 +613,6 @@ class ThreadedHeapTester : public ThreadedTesterBase {
}
test::YieldCurrentThread();
}
-
- ThreadState::DetachCurrentThread();
- AtomicDecrement(&threads_to_finish_);
}
};
@@ -615,8 +622,6 @@ class ThreadedWeaknessTester : public ThreadedTesterBase {
private:
void RunThread() override {
- ThreadState::AttachCurrentThread();
-
int gc_count = 0;
while (!Done()) {
{
@@ -632,7 +637,7 @@ class ThreadedWeaknessTester : public ThreadedTesterBase {
if (gc_count < kGcPerThread) {
PreciselyCollectGarbage();
gc_count++;
- AtomicIncrement(&gc_count_);
+ gc_count_.fetch_add(1, std::memory_order_release);
}
// Taking snapshot shouldn't have any bad side effect.
@@ -645,8 +650,6 @@ class ThreadedWeaknessTester : public ThreadedTesterBase {
}
test::YieldCurrentThread();
}
- ThreadState::DetachCurrentThread();
- AtomicDecrement(&threads_to_finish_);
}
};
@@ -686,30 +689,26 @@ class ThreadPersistentHeapTester : public ThreadedTesterBase {
class PersistentChain : public GarbageCollectedFinalized<PersistentChain> {
public:
static PersistentChain* Create(int count) {
- return new PersistentChain(count);
+ return MakeGarbageCollected<PersistentChain>(count);
}
- void Trace(blink::Visitor* visitor) {}
-
- private:
explicit PersistentChain(int count) {
ref_counted_chain_ = base::AdoptRef(RefCountedChain::Create(count));
}
+ void Trace(blink::Visitor* visitor) {}
+
+ private:
scoped_refptr<RefCountedChain> ref_counted_chain_;
};
void RunThread() override {
- ThreadState::AttachCurrentThread();
-
PersistentChain::Create(100);
// Upon thread detach, GCs will run until all persistents have been
// released. We verify that the draining of persistents proceeds
// as expected by dropping one Persistent<> per GC until there
// are none left.
- ThreadState::DetachCurrentThread();
- AtomicDecrement(&threads_to_finish_);
}
};
@@ -724,14 +723,14 @@ void CheckWithSlack(T expected, T actual, int slack) {
class TraceCounter : public GarbageCollectedFinalized<TraceCounter> {
public:
- static TraceCounter* Create() { return new TraceCounter(); }
+ static TraceCounter* Create() { return MakeGarbageCollected<TraceCounter>(); }
+
+ TraceCounter() : trace_count_(0) {}
void Trace(blink::Visitor* visitor) { trace_count_++; }
int TraceCount() const { return trace_count_; }
private:
- TraceCounter() : trace_count_(0) {}
-
int trace_count_;
};
@@ -747,7 +746,11 @@ TEST(HeapTest, IsHeapObjectAliveForConstPointer) {
class ClassWithMember : public GarbageCollected<ClassWithMember> {
public:
- static ClassWithMember* Create() { return new ClassWithMember(); }
+ static ClassWithMember* Create() {
+ return MakeGarbageCollected<ClassWithMember>();
+ }
+
+ ClassWithMember() : trace_counter_(TraceCounter::Create()) {}
void Trace(blink::Visitor* visitor) {
visitor->Trace(trace_counter_);
@@ -755,24 +758,22 @@ class ClassWithMember : public GarbageCollected<ClassWithMember> {
int TraceCount() const { return trace_counter_->TraceCount(); }
private:
- ClassWithMember() : trace_counter_(TraceCounter::Create()) {}
-
Member<TraceCounter> trace_counter_;
};
class SimpleFinalizedObject
: public GarbageCollectedFinalized<SimpleFinalizedObject> {
public:
- static SimpleFinalizedObject* Create() { return new SimpleFinalizedObject(); }
+ static SimpleFinalizedObject* Create() {
+ return MakeGarbageCollected<SimpleFinalizedObject>();
+ }
+ SimpleFinalizedObject() = default;
~SimpleFinalizedObject() { ++destructor_calls_; }
static int destructor_calls_;
void Trace(blink::Visitor* visitor) {}
-
- private:
- SimpleFinalizedObject() = default;
};
int SimpleFinalizedObject::destructor_calls_ = 0;
@@ -809,7 +810,9 @@ class IntNode : public GarbageCollected<IntNode> {
class Bar : public GarbageCollectedFinalized<Bar> {
public:
- static Bar* Create() { return new Bar(); }
+ static Bar* Create() { return MakeGarbageCollected<Bar>(); }
+
+ Bar() : magic_(kMagic) { live_++; }
void FinalizeGarbageCollectedObject() {
EXPECT_TRUE(magic_ == kMagic);
@@ -824,8 +827,6 @@ class Bar : public GarbageCollectedFinalized<Bar> {
protected:
static const int kMagic = 1337;
int magic_;
-
- Bar() : magic_(kMagic) { live_++; }
};
WILL_NOT_BE_EAGERLY_TRACED_CLASS(Bar);
@@ -834,7 +835,9 @@ unsigned Bar::live_ = 0;
class Baz : public GarbageCollected<Baz> {
public:
- static Baz* Create(Bar* bar) { return new Baz(bar); }
+ static Baz* Create(Bar* bar) { return MakeGarbageCollected<Baz>(bar); }
+
+ explicit Baz(Bar* bar) : bar_(bar) {}
void Trace(blink::Visitor* visitor) { visitor->Trace(bar_); }
@@ -844,16 +847,18 @@ class Baz : public GarbageCollected<Baz> {
void WillFinalize() { EXPECT_TRUE(!bar_->HasBeenFinalized()); }
private:
- explicit Baz(Bar* bar) : bar_(bar) {}
-
Member<Bar> bar_;
};
class Foo : public Bar {
public:
- static Foo* Create(Bar* bar) { return new Foo(bar); }
+ static Foo* Create(Bar* bar) { return MakeGarbageCollected<Foo>(bar); }
+
+ static Foo* Create(Foo* foo) { return MakeGarbageCollected<Foo>(foo); }
+
+ Foo(Bar* bar) : Bar(), bar_(bar), points_to_foo_(false) {}
- static Foo* Create(Foo* foo) { return new Foo(foo); }
+ Foo(Foo* foo) : Bar(), bar_(foo), points_to_foo_(true) {}
void Trace(blink::Visitor* visitor) override {
if (points_to_foo_)
@@ -863,10 +868,6 @@ class Foo : public Bar {
}
private:
- Foo(Bar* bar) : Bar(), bar_(bar), points_to_foo_(false) {}
-
- Foo(Foo* foo) : Bar(), bar_(foo), points_to_foo_(true) {}
-
Bar* bar_;
bool points_to_foo_;
};
@@ -875,7 +876,14 @@ WILL_NOT_BE_EAGERLY_TRACED_CLASS(Foo);
class Bars : public Bar {
public:
- static Bars* Create() { return new Bars(); }
+ static Bars* Create() { return MakeGarbageCollected<Bars>(); }
+
+ Bars() : width_(0) {
+ for (unsigned i = 0; i < kWidth; i++) {
+ bars_[i] = Bar::Create();
+ width_++;
+ }
+ }
void Trace(blink::Visitor* visitor) override {
for (unsigned i = 0; i < width_; i++)
@@ -887,13 +895,6 @@ class Bars : public Bar {
static const unsigned kWidth = 7500;
private:
- Bars() : width_(0) {
- for (unsigned i = 0; i < kWidth; i++) {
- bars_[i] = Bar::Create();
- width_++;
- }
- }
-
unsigned width_;
Member<Bar> bars_[kWidth];
};
@@ -902,20 +903,25 @@ WILL_NOT_BE_EAGERLY_TRACED_CLASS(Bars);
class ConstructorAllocation : public GarbageCollected<ConstructorAllocation> {
public:
- static ConstructorAllocation* Create() { return new ConstructorAllocation(); }
+ static ConstructorAllocation* Create() {
+ return MakeGarbageCollected<ConstructorAllocation>();
+ }
+
+ ConstructorAllocation() { int_wrapper_ = IntWrapper::Create(42); }
void Trace(blink::Visitor* visitor) { visitor->Trace(int_wrapper_); }
private:
- ConstructorAllocation() { int_wrapper_ = IntWrapper::Create(42); }
-
Member<IntWrapper> int_wrapper_;
};
class LargeHeapObject : public GarbageCollectedFinalized<LargeHeapObject> {
public:
+ LargeHeapObject() { int_wrapper_ = IntWrapper::Create(23); }
~LargeHeapObject() { destructor_calls_++; }
- static LargeHeapObject* Create() { return new LargeHeapObject(); }
+ static LargeHeapObject* Create() {
+ return MakeGarbageCollected<LargeHeapObject>();
+ }
char Get(size_t i) { return data_[i]; }
void Set(size_t i, char c) { data_[i] = c; }
size_t length() { return kLength; }
@@ -924,7 +930,6 @@ class LargeHeapObject : public GarbageCollectedFinalized<LargeHeapObject> {
private:
static const size_t kLength = 1024 * 1024;
- LargeHeapObject() { int_wrapper_ = IntWrapper::Create(23); }
Member<IntWrapper> int_wrapper_;
char data_[kLength];
};
@@ -946,9 +951,10 @@ class RefCountedAndGarbageCollected
: public GarbageCollectedFinalized<RefCountedAndGarbageCollected> {
public:
static RefCountedAndGarbageCollected* Create() {
- return new RefCountedAndGarbageCollected;
+ return MakeGarbageCollected<RefCountedAndGarbageCollected>();
}
+ RefCountedAndGarbageCollected() : ref_count_(0) {}
~RefCountedAndGarbageCollected() { ++destructor_calls_; }
void AddRef() {
@@ -973,8 +979,6 @@ class RefCountedAndGarbageCollected
static int destructor_calls_;
private:
- RefCountedAndGarbageCollected() : ref_count_(0) {}
-
int ref_count_;
SelfKeepAlive<RefCountedAndGarbageCollected> keep_alive_;
};
@@ -986,9 +990,10 @@ class RefCountedAndGarbageCollected2
public GarbageCollectedFinalized<RefCountedAndGarbageCollected2> {
public:
static RefCountedAndGarbageCollected2* Create() {
- return new RefCountedAndGarbageCollected2;
+ return MakeGarbageCollected<RefCountedAndGarbageCollected2>();
}
+ RefCountedAndGarbageCollected2() : ref_count_(0) {}
~RefCountedAndGarbageCollected2() { ++destructor_calls_; }
void Ref() {
@@ -1013,8 +1018,6 @@ class RefCountedAndGarbageCollected2
static int destructor_calls_;
private:
- RefCountedAndGarbageCollected2() : ref_count_(0) {}
-
int ref_count_;
SelfKeepAlive<RefCountedAndGarbageCollected2> keep_alive_;
};
@@ -1023,7 +1026,12 @@ int RefCountedAndGarbageCollected2::destructor_calls_ = 0;
class Weak : public Bar {
public:
- static Weak* Create(Bar* strong, Bar* weak) { return new Weak(strong, weak); }
+ static Weak* Create(Bar* strong, Bar* weak) {
+ return MakeGarbageCollected<Weak>(strong, weak);
+ }
+
+ Weak(Bar* strong_bar, Bar* weak_bar)
+ : Bar(), strong_bar_(strong_bar), weak_bar_(weak_bar) {}
void Trace(blink::Visitor* visitor) override {
visitor->Trace(strong_bar_);
@@ -1039,9 +1047,6 @@ class Weak : public Bar {
bool WeakIsThere() { return !!weak_bar_; }
private:
- Weak(Bar* strong_bar, Bar* weak_bar)
- : Bar(), strong_bar_(strong_bar), weak_bar_(weak_bar) {}
-
Member<Bar> strong_bar_;
Bar* weak_bar_;
};
@@ -1051,9 +1056,12 @@ WILL_NOT_BE_EAGERLY_TRACED_CLASS(Weak);
class WithWeakMember : public Bar {
public:
static WithWeakMember* Create(Bar* strong, Bar* weak) {
- return new WithWeakMember(strong, weak);
+ return MakeGarbageCollected<WithWeakMember>(strong, weak);
}
+ WithWeakMember(Bar* strong_bar, Bar* weak_bar)
+ : Bar(), strong_bar_(strong_bar), weak_bar_(weak_bar) {}
+
void Trace(blink::Visitor* visitor) override {
visitor->Trace(strong_bar_);
visitor->Trace(weak_bar_);
@@ -1063,9 +1071,6 @@ class WithWeakMember : public Bar {
bool WeakIsThere() { return !!weak_bar_; }
private:
- WithWeakMember(Bar* strong_bar, Bar* weak_bar)
- : Bar(), strong_bar_(strong_bar), weak_bar_(weak_bar) {}
-
Member<Bar> strong_bar_;
WeakMember<Bar> weak_bar_;
};
@@ -1076,7 +1081,10 @@ class Observable : public GarbageCollectedFinalized<Observable> {
USING_PRE_FINALIZER(Observable, WillFinalize);
public:
- static Observable* Create(Bar* bar) { return new Observable(bar); }
+ static Observable* Create(Bar* bar) {
+ return MakeGarbageCollected<Observable>(bar);
+ }
+ explicit Observable(Bar* bar) : bar_(bar), was_destructed_(false) {}
~Observable() { was_destructed_ = true; }
void Trace(blink::Visitor* visitor) { visitor->Trace(bar_); }
@@ -1090,8 +1098,6 @@ class Observable : public GarbageCollectedFinalized<Observable> {
static bool will_finalize_was_called_;
private:
- explicit Observable(Bar* bar) : bar_(bar), was_destructed_(false) {}
-
Member<Bar> bar_;
bool was_destructed_;
};
@@ -1104,8 +1110,9 @@ class ObservableWithPreFinalizer
public:
static ObservableWithPreFinalizer* Create() {
- return new ObservableWithPreFinalizer();
+ return MakeGarbageCollected<ObservableWithPreFinalizer>();
}
+ ObservableWithPreFinalizer() : was_destructed_(false) {}
~ObservableWithPreFinalizer() { was_destructed_ = true; }
void Trace(blink::Visitor* visitor) {}
void Dispose() {
@@ -1115,8 +1122,6 @@ class ObservableWithPreFinalizer
static bool dispose_was_called_;
protected:
- ObservableWithPreFinalizer() : was_destructed_(false) {}
-
bool was_destructed_;
};
@@ -1130,7 +1135,10 @@ class PreFinalizerBase : public GarbageCollectedFinalized<PreFinalizerBase> {
USING_PRE_FINALIZER(PreFinalizerBase, Dispose);
public:
- static PreFinalizerBase* Create() { return new PreFinalizerBase(); }
+ static PreFinalizerBase* Create() {
+ return MakeGarbageCollected<PreFinalizerBase>();
+ }
+ PreFinalizerBase() : was_destructed_(false) {}
virtual ~PreFinalizerBase() { was_destructed_ = true; }
virtual void Trace(blink::Visitor* visitor) {}
void Dispose() {
@@ -1142,7 +1150,6 @@ class PreFinalizerBase : public GarbageCollectedFinalized<PreFinalizerBase> {
}
protected:
- PreFinalizerBase() : was_destructed_(false) {}
bool was_destructed_;
};
@@ -1170,7 +1177,10 @@ class PreFinalizerSubClass : public PreFinalizerBase, public PreFinalizerMixin {
USING_PRE_FINALIZER(PreFinalizerSubClass, Dispose);
public:
- static PreFinalizerSubClass* Create() { return new PreFinalizerSubClass(); }
+ static PreFinalizerSubClass* Create() {
+ return MakeGarbageCollected<PreFinalizerSubClass>();
+ }
+ PreFinalizerSubClass() : was_destructed_(false) {}
~PreFinalizerSubClass() override { was_destructed_ = true; }
void Trace(blink::Visitor* visitor) override {}
void Dispose() {
@@ -1182,7 +1192,6 @@ class PreFinalizerSubClass : public PreFinalizerBase, public PreFinalizerMixin {
}
protected:
- PreFinalizerSubClass() : was_destructed_(false) {}
bool was_destructed_;
};
@@ -1190,8 +1199,11 @@ template <typename T>
class FinalizationObserver : public GarbageCollected<FinalizationObserver<T>> {
public:
static FinalizationObserver* Create(T* data) {
- return new FinalizationObserver(data);
+ return MakeGarbageCollected<FinalizationObserver>(data);
}
+
+ FinalizationObserver(T* data) : data_(data), did_call_will_finalize_(false) {}
+
bool DidCallWillFinalize() const { return did_call_will_finalize_; }
void Trace(blink::Visitor* visitor) {
@@ -1209,8 +1221,6 @@ class FinalizationObserver : public GarbageCollected<FinalizationObserver<T>> {
}
private:
- FinalizationObserver(T* data) : data_(data), did_call_will_finalize_(false) {}
-
WeakMember<T> data_;
bool did_call_will_finalize_;
};
@@ -1268,8 +1278,9 @@ class SuperClass;
class PointsBack : public GarbageCollectedFinalized<PointsBack> {
public:
- static PointsBack* Create() { return new PointsBack; }
+ static PointsBack* Create() { return MakeGarbageCollected<PointsBack>(); }
+ PointsBack() : back_pointer_(nullptr) { ++alive_count_; }
~PointsBack() { --alive_count_; }
void SetBackPointer(SuperClass* back_pointer) {
@@ -1283,8 +1294,6 @@ class PointsBack : public GarbageCollectedFinalized<PointsBack> {
static int alive_count_;
private:
- PointsBack() : back_pointer_(nullptr) { ++alive_count_; }
-
WeakMember<SuperClass> back_pointer_;
};
@@ -1293,9 +1302,13 @@ int PointsBack::alive_count_ = 0;
class SuperClass : public GarbageCollectedFinalized<SuperClass> {
public:
static SuperClass* Create(PointsBack* points_back) {
- return new SuperClass(points_back);
+ return MakeGarbageCollected<SuperClass>(points_back);
}
+ explicit SuperClass(PointsBack* points_back) : points_back_(points_back) {
+ points_back_->SetBackPointer(this);
+ ++alive_count_;
+ }
virtual ~SuperClass() { --alive_count_; }
void DoStuff(SuperClass* target,
@@ -1312,12 +1325,6 @@ class SuperClass : public GarbageCollectedFinalized<SuperClass> {
static int alive_count_;
- protected:
- explicit SuperClass(PointsBack* points_back) : points_back_(points_back) {
- points_back_->SetBackPointer(this);
- ++alive_count_;
- }
-
private:
Member<PointsBack> points_back_;
};
@@ -1338,9 +1345,13 @@ int SubData::alive_count_ = 0;
class SubClass : public SuperClass {
public:
static SubClass* Create(PointsBack* points_back) {
- return new SubClass(points_back);
+ return MakeGarbageCollected<SubClass>(points_back);
}
+ explicit SubClass(PointsBack* points_back)
+ : SuperClass(points_back), data_(MakeGarbageCollected<SubData>()) {
+ ++alive_count_;
+ }
~SubClass() override { --alive_count_; }
void Trace(blink::Visitor* visitor) override {
@@ -1351,12 +1362,6 @@ class SubClass : public SuperClass {
static int alive_count_;
private:
- explicit SubClass(PointsBack* points_back)
- : SuperClass(points_back), data_(new SubData) {
- ++alive_count_;
- }
-
- private:
Member<SubData> data_;
};
@@ -1375,22 +1380,21 @@ class Mixin : public GarbageCollectedMixin {
class UseMixin : public SimpleObject, public Mixin {
USING_GARBAGE_COLLECTED_MIXIN(UseMixin)
public:
- static UseMixin* Create() { return new UseMixin(); }
+ static UseMixin* Create() { return MakeGarbageCollected<UseMixin>(); }
- static int trace_count_;
- void Trace(blink::Visitor* visitor) override {
- SimpleObject::Trace(visitor);
- Mixin::Trace(visitor);
- ++trace_count_;
- }
-
- private:
UseMixin() {
// Verify that WTF::IsGarbageCollectedType<> works as expected for mixins.
static_assert(WTF::IsGarbageCollectedType<UseMixin>::value,
"IsGarbageCollectedType<> sanity check failed for GC mixin.");
trace_count_ = 0;
}
+
+ static int trace_count_;
+ void Trace(blink::Visitor* visitor) override {
+ SimpleObject::Trace(visitor);
+ Mixin::Trace(visitor);
+ ++trace_count_;
+ }
};
int UseMixin::trace_count_ = 0;
@@ -1488,7 +1492,7 @@ class FinalizationAllocator
for (int i = 0; i < 10; ++i)
*wrapper_ = IntWrapper::Create(42);
for (int i = 0; i < 512; ++i)
- new OneKiloByteObject();
+ MakeGarbageCollected<OneKiloByteObject>();
for (int i = 0; i < 32; ++i)
LargeHeapObject::Create();
}
@@ -1511,7 +1515,7 @@ class PreFinalizationAllocator
for (int i = 0; i < 10; ++i)
*wrapper_ = IntWrapper::Create(42);
for (int i = 0; i < 512; ++i)
- new OneKiloByteObject();
+ MakeGarbageCollected<OneKiloByteObject>();
for (int i = 0; i < 32; ++i)
LargeHeapObject::Create();
}
@@ -1529,12 +1533,12 @@ class PreFinalizerBackingShrinkForbidden
public:
PreFinalizerBackingShrinkForbidden() {
for (int i = 0; i < 32; ++i) {
- vector_.push_back(new IntWrapper(i));
+ vector_.push_back(MakeGarbageCollected<IntWrapper>(i));
}
EXPECT_LT(31ul, vector_.capacity());
for (int i = 0; i < 32; ++i) {
- map_.insert(i + 1, new IntWrapper(i + 1));
+ map_.insert(i + 1, MakeGarbageCollected<IntWrapper>(i + 1));
}
EXPECT_LT(31ul, map_.Capacity());
}
@@ -1572,7 +1576,7 @@ class PreFinalizerBackingShrinkForbidden
};
TEST(HeapTest, PreFinalizerBackingShrinkForbidden) {
- new PreFinalizerBackingShrinkForbidden();
+ MakeGarbageCollected<PreFinalizerBackingShrinkForbidden>();
PreciselyCollectGarbage();
}
@@ -1583,7 +1587,7 @@ class PreFinalizerVectorBackingExpandForbidden
public:
PreFinalizerVectorBackingExpandForbidden() {
- vector_.push_back(new IntWrapper(1));
+ vector_.push_back(MakeGarbageCollected<IntWrapper>(1));
}
void Dispose() { EXPECT_DEATH(Test(), ""); }
@@ -1602,7 +1606,7 @@ class PreFinalizerVectorBackingExpandForbidden
};
TEST(HeapDeathTest, PreFinalizerVectorBackingExpandForbidden) {
- new PreFinalizerVectorBackingExpandForbidden();
+ MakeGarbageCollected<PreFinalizerVectorBackingExpandForbidden>();
PreciselyCollectGarbage();
}
@@ -1613,7 +1617,7 @@ class PreFinalizerHashTableBackingExpandForbidden
public:
PreFinalizerHashTableBackingExpandForbidden() {
- map_.insert(123, new IntWrapper(123));
+ map_.insert(123, MakeGarbageCollected<IntWrapper>(123));
}
void Dispose() { EXPECT_DEATH(Test(), ""); }
@@ -1632,7 +1636,7 @@ class PreFinalizerHashTableBackingExpandForbidden
};
TEST(HeapDeathTest, PreFinalizerHashTableBackingExpandForbidden) {
- new PreFinalizerHashTableBackingExpandForbidden();
+ MakeGarbageCollected<PreFinalizerHashTableBackingExpandForbidden>();
PreciselyCollectGarbage();
}
@@ -1644,7 +1648,7 @@ class LargeMixin : public GarbageCollected<LargeMixin>, public Mixin {
};
TEST(HeapDeathTest, LargeGarbageCollectedMixin) {
- EXPECT_DEATH(new LargeMixin(), "");
+ EXPECT_DEATH(MakeGarbageCollected<LargeMixin>(), "");
}
TEST(HeapTest, Transition) {
@@ -1874,7 +1878,7 @@ TEST(HeapTest, SimpleAllocation) {
EXPECT_EQ(0ul, heap.ObjectPayloadSizeForTesting());
// Allocate an object in the heap.
- HeapAllocatedArray* array = new HeapAllocatedArray();
+ HeapAllocatedArray* array = MakeGarbageCollected<HeapAllocatedArray>();
EXPECT_TRUE(heap.ObjectPayloadSizeForTesting() >= sizeof(HeapAllocatedArray));
// Sanity check of the contents in the heap.
@@ -1918,13 +1922,13 @@ TEST(HeapTest, FreelistReuse) {
ClearOutOldGarbage();
for (int i = 0; i < 100; i++)
- new IntWrapper(i);
- IntWrapper* p1 = new IntWrapper(100);
+ MakeGarbageCollected<IntWrapper>(i);
+ IntWrapper* p1 = MakeGarbageCollected<IntWrapper>(100);
PreciselyCollectGarbage();
// In non-production builds, we delay reusing freed memory for at least
// one GC cycle.
for (int i = 0; i < 100; i++) {
- IntWrapper* p2 = new IntWrapper(i);
+ IntWrapper* p2 = MakeGarbageCollected<IntWrapper>(i);
EXPECT_NE(p1, p2);
}
@@ -1933,7 +1937,7 @@ TEST(HeapTest, FreelistReuse) {
// Now the freed memory in the first GC should be reused.
bool reused_memory_found = false;
for (int i = 0; i < 10000; i++) {
- IntWrapper* p2 = new IntWrapper(i);
+ IntWrapper* p2 = MakeGarbageCollected<IntWrapper>(i);
if (p1 == p2) {
reused_memory_found = true;
break;
@@ -1966,11 +1970,11 @@ TEST(HeapTest, LazySweepingLargeObjectPages) {
// Create free lists that can be reused for IntWrappers created in
// LargeHeapObject::create().
- Persistent<IntWrapper> p1 = new IntWrapper(1);
+ Persistent<IntWrapper> p1 = MakeGarbageCollected<IntWrapper>(1);
for (int i = 0; i < 100; i++) {
- new IntWrapper(i);
+ MakeGarbageCollected<IntWrapper>(i);
}
- Persistent<IntWrapper> p2 = new IntWrapper(2);
+ Persistent<IntWrapper> p2 = MakeGarbageCollected<IntWrapper>(2);
PreciselyCollectGarbage();
PreciselyCollectGarbage();
@@ -2012,15 +2016,13 @@ class SimpleFinalizedEagerObjectBase
class SimpleFinalizedEagerObject : public SimpleFinalizedEagerObjectBase {
public:
static SimpleFinalizedEagerObject* Create() {
- return new SimpleFinalizedEagerObject();
+ return MakeGarbageCollected<SimpleFinalizedEagerObject>();
}
+ SimpleFinalizedEagerObject() = default;
~SimpleFinalizedEagerObject() override { ++destructor_calls_; }
static int destructor_calls_;
-
- private:
- SimpleFinalizedEagerObject() = default;
};
template <typename T>
@@ -2034,16 +2036,15 @@ class SimpleFinalizedObjectInstanceOfTemplate final
public ParameterizedButEmpty<SimpleFinalizedObjectInstanceOfTemplate> {
public:
static SimpleFinalizedObjectInstanceOfTemplate* Create() {
- return new SimpleFinalizedObjectInstanceOfTemplate();
+ return MakeGarbageCollected<SimpleFinalizedObjectInstanceOfTemplate>();
}
+
+ SimpleFinalizedObjectInstanceOfTemplate() = default;
~SimpleFinalizedObjectInstanceOfTemplate() { ++destructor_calls_; }
void Trace(blink::Visitor* visitor) {}
static int destructor_calls_;
-
- private:
- SimpleFinalizedObjectInstanceOfTemplate() = default;
};
int SimpleFinalizedEagerObject::destructor_calls_ = 0;
@@ -2423,7 +2424,7 @@ typedef std::pair<int, WeakMember<IntWrapper>> PairUnwrappedWeak;
class Container : public GarbageCollected<Container> {
public:
- static Container* Create() { return new Container(); }
+ static Container* Create() { return MakeGarbageCollected<Container>(); }
HeapHashMap<Member<IntWrapper>, Member<IntWrapper>> map;
HeapHashSet<Member<IntWrapper>> set;
HeapHashSet<Member<IntWrapper>> set2;
@@ -3848,9 +3849,9 @@ TEST(HeapTest, HeapWeakCollectionTypes) {
TEST(HeapTest, HeapHashCountedSetToVector) {
HeapHashCountedSet<Member<IntWrapper>> set;
HeapVector<Member<IntWrapper>> vector;
- set.insert(new IntWrapper(1));
- set.insert(new IntWrapper(1));
- set.insert(new IntWrapper(2));
+ set.insert(MakeGarbageCollected<IntWrapper>(1));
+ set.insert(MakeGarbageCollected<IntWrapper>(1));
+ set.insert(MakeGarbageCollected<IntWrapper>(2));
CopyToVector(set, vector);
EXPECT_EQ(3u, vector.size());
@@ -3868,9 +3869,9 @@ TEST(HeapTest, HeapHashCountedSetToVector) {
TEST(HeapTest, WeakHeapHashCountedSetToVector) {
HeapHashCountedSet<WeakMember<IntWrapper>> set;
HeapVector<Member<IntWrapper>> vector;
- set.insert(new IntWrapper(1));
- set.insert(new IntWrapper(1));
- set.insert(new IntWrapper(2));
+ set.insert(MakeGarbageCollected<IntWrapper>(1));
+ set.insert(MakeGarbageCollected<IntWrapper>(1));
+ set.insert(MakeGarbageCollected<IntWrapper>(2));
CopyToVector(set, vector);
EXPECT_LE(3u, vector.size());
@@ -4014,104 +4015,96 @@ TEST(HeapTest, Comparisons) {
EXPECT_TRUE(bar_persistent == foo_persistent);
}
-#if DCHECK_IS_ON()
namespace {
-static size_t g_check_mark_count = 0;
-
-bool ReportMarkedPointer(HeapObjectHeader*) {
- g_check_mark_count++;
- // Do not try to mark the located heap object.
- return true;
+void ExpectObjectMarkedAndUnmark(MarkingWorklist* worklist, void* expected) {
+ MarkingItem item;
+ CHECK(worklist->Pop(0, &item));
+ CHECK_EQ(expected, item.object);
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(item.object);
+ CHECK(header->IsMarked());
+ header->Unmark();
+ CHECK(worklist->IsGlobalEmpty());
}
-}
-#endif
+
+} // namespace
TEST(HeapTest, CheckAndMarkPointer) {
-#if DCHECK_IS_ON()
+ // This test ensures that conservative marking primitives can use any address
+ // contained within an object to mark the corresponding object.
+
ThreadHeap& heap = ThreadState::Current()->Heap();
ClearOutOldGarbage();
Vector<Address> object_addresses;
Vector<Address> end_addresses;
- Address large_object_address;
- Address large_object_end_address;
for (int i = 0; i < 10; i++) {
SimpleObject* object = SimpleObject::Create();
Address object_address = reinterpret_cast<Address>(object);
object_addresses.push_back(object_address);
end_addresses.push_back(object_address + sizeof(SimpleObject) - 1);
}
- LargeHeapObject* large_object = LargeHeapObject::Create();
- large_object_address = reinterpret_cast<Address>(large_object);
- large_object_end_address = large_object_address + sizeof(LargeHeapObject) - 1;
-
- // This is a low-level test where we call checkAndMarkPointer. This method
- // causes the object start bitmap to be computed which requires the heap
- // to be in a consistent state (e.g. the free allocation area must be put
- // into a free list header). However when we call makeConsistentForGC it
- // also clears out the freelists so we have to rebuild those before trying
- // to allocate anything again. We do this by forcing a GC after doing the
- // checkAndMarkPointer tests.
+ Address large_object_address =
+ reinterpret_cast<Address>(LargeHeapObject::Create());
+ Address large_object_end_address =
+ large_object_address + sizeof(LargeHeapObject) - 1;
+
{
TestGCScope scope(BlinkGC::kHeapPointersOnStack);
MarkingVisitor visitor(ThreadState::Current(),
MarkingVisitor::kGlobalMarking);
heap.address_cache()->EnableLookup();
heap.address_cache()->Flush();
+
+ // Conservative marker should find the interesting objects by using anything
+ // between object start and end.
+ MarkingWorklist* worklist = heap.GetMarkingWorklist();
+ CHECK(worklist->IsGlobalEmpty());
for (wtf_size_t i = 0; i < object_addresses.size(); i++) {
- EXPECT_TRUE(heap.CheckAndMarkPointer(&visitor, object_addresses[i],
- ReportMarkedPointer));
- EXPECT_TRUE(heap.CheckAndMarkPointer(&visitor, end_addresses[i],
- ReportMarkedPointer));
+ heap.CheckAndMarkPointer(&visitor, object_addresses[i]);
+ ExpectObjectMarkedAndUnmark(worklist, object_addresses[i]);
+ heap.CheckAndMarkPointer(&visitor, end_addresses[i]);
+ ExpectObjectMarkedAndUnmark(worklist, object_addresses[i]);
}
- EXPECT_EQ(object_addresses.size() * 2, g_check_mark_count);
- g_check_mark_count = 0;
- EXPECT_TRUE(heap.CheckAndMarkPointer(&visitor, large_object_address,
- ReportMarkedPointer));
- EXPECT_TRUE(heap.CheckAndMarkPointer(&visitor, large_object_end_address,
- ReportMarkedPointer));
- EXPECT_EQ(2ul, g_check_mark_count);
- g_check_mark_count = 0ul;
+ heap.CheckAndMarkPointer(&visitor, large_object_address);
+ ExpectObjectMarkedAndUnmark(worklist, large_object_address);
+ heap.CheckAndMarkPointer(&visitor, large_object_end_address);
+ ExpectObjectMarkedAndUnmark(worklist, large_object_address);
}
+
// This forces a GC without stack scanning which results in the objects
// being collected. This will also rebuild the above mentioned freelists,
// however we don't rely on that below since we don't have any allocations.
ClearOutOldGarbage();
+
{
TestGCScope scope(BlinkGC::kHeapPointersOnStack);
MarkingVisitor visitor(ThreadState::Current(),
MarkingVisitor::kGlobalMarking);
heap.address_cache()->EnableLookup();
heap.address_cache()->Flush();
+
+ // After collecting all interesting objects the conservative marker should
+ // not find them anymore.
+ MarkingWorklist* worklist = heap.GetMarkingWorklist();
+ CHECK(worklist->IsGlobalEmpty());
for (wtf_size_t i = 0; i < object_addresses.size(); i++) {
- // We would like to assert that checkAndMarkPointer returned false
- // here because the pointers no longer point into a valid object
- // (it's been freed by the GCs. But checkAndMarkPointer will return
- // true for any pointer that points into a heap page, regardless of
- // whether it points at a valid object (this ensures the
- // correctness of the page-based on-heap address caches), so we
- // can't make that assert.
- heap.CheckAndMarkPointer(&visitor, object_addresses[i],
- ReportMarkedPointer);
- heap.CheckAndMarkPointer(&visitor, end_addresses[i], ReportMarkedPointer);
+ heap.CheckAndMarkPointer(&visitor, object_addresses[i]);
+ CHECK(worklist->IsGlobalEmpty());
+ heap.CheckAndMarkPointer(&visitor, end_addresses[i]);
+ CHECK(worklist->IsGlobalEmpty());
}
- EXPECT_EQ(0ul, g_check_mark_count);
- heap.CheckAndMarkPointer(&visitor, large_object_address,
- ReportMarkedPointer);
- heap.CheckAndMarkPointer(&visitor, large_object_end_address,
- ReportMarkedPointer);
- EXPECT_EQ(0ul, g_check_mark_count);
- }
- // This round of GC is important to make sure that the object start
- // bitmap are cleared out and that the free lists are rebuild.
- ClearOutOldGarbage();
-#endif
+ heap.CheckAndMarkPointer(&visitor, large_object_address);
+ CHECK(worklist->IsGlobalEmpty());
+ heap.CheckAndMarkPointer(&visitor, large_object_end_address);
+ CHECK(worklist->IsGlobalEmpty());
+ }
}
TEST(HeapTest, CollectionNesting) {
ClearOutOldGarbage();
- int* key = &IntWrapper::destructor_calls_;
+ int k;
+ int* key = &k;
IntWrapper::destructor_calls_ = 0;
typedef HeapVector<Member<IntWrapper>> IntVector;
typedef HeapDeque<Member<IntWrapper>> IntDeque;
@@ -4409,7 +4402,7 @@ TEST(HeapTest, VectorDestructors) {
InlinedVectorObject::destructor_calls_ = 0;
{
Persistent<InlinedVectorObjectWrapper> vector_wrapper =
- new InlinedVectorObjectWrapper();
+ MakeGarbageCollected<InlinedVectorObjectWrapper>();
ConservativelyCollectGarbage();
EXPECT_EQ(2, InlinedVectorObject::destructor_calls_);
}
@@ -4455,7 +4448,7 @@ TEST(HeapTest, VectorDestructorsWithVtable) {
InlinedVectorObjectWithVtable::destructor_calls_ = 0;
{
Persistent<InlinedVectorObjectWithVtableWrapper> vector_wrapper =
- new InlinedVectorObjectWithVtableWrapper();
+ MakeGarbageCollected<InlinedVectorObjectWithVtableWrapper>();
ConservativelyCollectGarbage();
EXPECT_EQ(3, InlinedVectorObjectWithVtable::destructor_calls_);
}
@@ -4481,7 +4474,7 @@ TEST(HeapTest, HeapLinkedStack) {
IntWrapper::destructor_calls_ = 0;
HeapLinkedStack<TerminatedArrayItem>* stack =
- new HeapLinkedStack<TerminatedArrayItem>();
+ MakeGarbageCollected<HeapLinkedStack<TerminatedArrayItem>>();
const wtf_size_t kStackSize = 10;
@@ -4511,7 +4504,7 @@ TEST(HeapTest, AllocationDuringFinalization) {
LargeHeapObject::destructor_calls_ = 0;
Persistent<IntWrapper> wrapper;
- new FinalizationAllocator(&wrapper);
+ MakeGarbageCollected<FinalizationAllocator>(&wrapper);
PreciselyCollectGarbage();
EXPECT_EQ(0, IntWrapper::destructor_calls_);
@@ -4537,7 +4530,7 @@ TEST(HeapTest, AllocationDuringPrefinalizer) {
LargeHeapObject::destructor_calls_ = 0;
Persistent<IntWrapper> wrapper;
- new PreFinalizationAllocator(&wrapper);
+ MakeGarbageCollected<PreFinalizationAllocator>(&wrapper);
PreciselyCollectGarbage();
EXPECT_EQ(0, IntWrapper::destructor_calls_);
@@ -4694,7 +4687,7 @@ TEST(HeapTest, MultipleMixins) {
ClearOutOldGarbage();
IntWrapper::destructor_calls_ = 0;
- MultipleMixins* obj = new MultipleMixins();
+ MultipleMixins* obj = MakeGarbageCollected<MultipleMixins>();
{
Persistent<MixinA> a = obj;
PreciselyCollectGarbage();
@@ -4714,7 +4707,7 @@ TEST(HeapTest, DerivedMultipleMixins) {
IntWrapper::destructor_calls_ = 0;
DerivedMultipleMixins::trace_called_ = 0;
- DerivedMultipleMixins* obj = new DerivedMultipleMixins();
+ DerivedMultipleMixins* obj = MakeGarbageCollected<DerivedMultipleMixins>();
{
Persistent<MixinA> a = obj;
PreciselyCollectGarbage();
@@ -4745,7 +4738,8 @@ TEST(HeapTest, MixinInstanceWithoutTrace) {
// references inherits the mixin's trace implementation.
ClearOutOldGarbage();
MixinA::trace_count_ = 0;
- MixinInstanceWithoutTrace* obj = new MixinInstanceWithoutTrace();
+ MixinInstanceWithoutTrace* obj =
+ MakeGarbageCollected<MixinInstanceWithoutTrace>();
int saved_trace_count = 0;
{
Persistent<MixinA> a = obj;
@@ -5216,12 +5210,13 @@ TEST(HeapTest, EphemeronsPointToEphemerons) {
Persistent<EphemeronWrapper> chain;
for (int i = 0; i < 100; i++) {
EphemeronWrapper* old_head = chain;
- chain = new EphemeronWrapper();
+ chain = MakeGarbageCollected<EphemeronWrapper>();
if (i == 50)
chain->GetMap().insert(key2, old_head);
else
chain->GetMap().insert(key, old_head);
- chain->GetMap().insert(IntWrapper::Create(103), new EphemeronWrapper());
+ chain->GetMap().insert(IntWrapper::Create(103),
+ MakeGarbageCollected<EphemeronWrapper>());
}
PreciselyCollectGarbage();
@@ -5351,8 +5346,8 @@ TEST(HeapTest, IndirectStrongToWeak) {
Persistent<IntWrapper> dead_object =
IntWrapper::Create(100); // Named for "Drowning by Numbers" (1988).
Persistent<IntWrapper> life_object = IntWrapper::Create(42);
- map->insert(dead_object, new Link1(dead_object));
- map->insert(life_object, new Link1(life_object));
+ map->insert(dead_object, MakeGarbageCollected<Link1>(dead_object));
+ map->insert(life_object, MakeGarbageCollected<Link1>(life_object));
EXPECT_EQ(2u, map->size());
PreciselyCollectGarbage();
EXPECT_EQ(2u, map->size());
@@ -5367,370 +5362,11 @@ TEST(HeapTest, IndirectStrongToWeak) {
EXPECT_EQ(0u, map->size());
}
-static Mutex& MainThreadMutex() {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, main_mutex, ());
- return main_mutex;
-}
-
-static ThreadCondition& MainThreadCondition() {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadCondition, main_condition,
- (MainThreadMutex()));
- return main_condition;
-}
-
-static void ParkMainThread() {
- MainThreadCondition().Wait();
-}
-
-static void WakeMainThread() {
- MutexLocker locker(MainThreadMutex());
- MainThreadCondition().Signal();
-}
-
-static Mutex& WorkerThreadMutex() {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, worker_mutex, ());
- return worker_mutex;
-}
-
-static ThreadCondition& WorkerThreadCondition() {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadCondition, worker_condition,
- (WorkerThreadMutex()));
- return worker_condition;
-}
-
-static void ParkWorkerThread() {
- WorkerThreadCondition().Wait();
-}
-
-static void WakeWorkerThread() {
- MutexLocker locker(WorkerThreadMutex());
- WorkerThreadCondition().Signal();
-}
-
-class ThreadedStrongificationTester {
- public:
- static void Test() {
- IntWrapper::destructor_calls_ = 0;
-
- MutexLocker locker(MainThreadMutex());
- std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
- ThreadCreationParams(WebThreadType::kTestThread)
- .SetThreadNameForTest("Test Worker Thread"));
- PostCrossThreadTask(*worker_thread->GetTaskRunner(), FROM_HERE,
- CrossThreadBind(WorkerThreadMain));
-
- // Wait for the worker thread initialization. The worker
- // allocates a weak collection where both collection and
- // contents are kept alive via persistent pointers.
- ParkMainThread();
-
- // Perform two garbage collections where the worker thread does
- // not wake up in between. This will cause us to remove marks
- // and mark unmarked objects dead. The collection on the worker
- // heap is found through the persistent and the backing should
- // be marked.
- PreciselyCollectGarbage();
- PreciselyCollectGarbage();
-
- // Wake up the worker thread so it can continue. It will sweep
- // and perform another GC where the backing store of its
- // collection should be strongified.
- WakeWorkerThread();
-
- // Wait for the worker thread to sweep its heaps before checking.
- ParkMainThread();
- }
-
- private:
- using WeakCollectionType =
- HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper>>;
-
- static WeakCollectionType* AllocateCollection() {
- // Create a weak collection that is kept alive by a persistent
- // and keep the contents alive with a persistents as
- // well.
- Persistent<IntWrapper> wrapper1 = IntWrapper::Create(32);
- Persistent<IntWrapper> wrapper2 = IntWrapper::Create(32);
- Persistent<IntWrapper> wrapper3 = IntWrapper::Create(32);
- Persistent<IntWrapper> wrapper4 = IntWrapper::Create(32);
- Persistent<IntWrapper> wrapper5 = IntWrapper::Create(32);
- Persistent<IntWrapper> wrapper6 = IntWrapper::Create(32);
- Persistent<WeakCollectionType> weak_collection =
- MakeGarbageCollected<WeakCollectionType>();
- weak_collection->insert(wrapper1, wrapper1);
- weak_collection->insert(wrapper2, wrapper2);
- weak_collection->insert(wrapper3, wrapper3);
- weak_collection->insert(wrapper4, wrapper4);
- weak_collection->insert(wrapper5, wrapper5);
- weak_collection->insert(wrapper6, wrapper6);
-
- // Signal the main thread that the worker is done with its allocation.
- WakeMainThread();
-
- // Wait for the main thread to do two GCs without sweeping
- // this thread heap.
- ParkWorkerThread();
-
- return weak_collection;
- }
-
- static void WorkerThreadMain() {
- MutexLocker locker(WorkerThreadMutex());
-
- ThreadState::AttachCurrentThread();
-
- {
- Persistent<WeakCollectionType> collection = AllocateCollection();
- {
- // Prevent weak processing with an iterator and GC.
- WeakCollectionType::iterator it = collection->begin();
- ConservativelyCollectGarbage();
-
- // The backing should be strongified because of the iterator.
- EXPECT_EQ(6u, collection->size());
- EXPECT_EQ(32, it->value->Value());
- }
-
- // Disregarding the iterator but keeping the collection alive
- // with a persistent should lead to weak processing.
- PreciselyCollectGarbage();
- EXPECT_EQ(0u, collection->size());
- }
-
- WakeMainThread();
- ThreadState::DetachCurrentThread();
- }
-
- static volatile uintptr_t worker_object_pointer_;
-};
-
-TEST(HeapTest, ThreadedStrongification) {
- ThreadedStrongificationTester::Test();
-}
-
-class MemberSameThreadCheckTester {
- public:
- void Test() {
- IntWrapper::destructor_calls_ = 0;
-
- MutexLocker locker(MainThreadMutex());
- std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
- ThreadCreationParams(WebThreadType::kTestThread)
- .SetThreadNameForTest("Test Worker Thread"));
- PostCrossThreadTask(
- *worker_thread->GetTaskRunner(), FROM_HERE,
- CrossThreadBind(&MemberSameThreadCheckTester::WorkerThreadMain,
- CrossThreadUnretained(this)));
-
- ParkMainThread();
- }
-
- private:
- Member<IntWrapper> wrapper_;
-
- void WorkerThreadMain() {
- MutexLocker locker(WorkerThreadMutex());
-
- ThreadState::AttachCurrentThread();
-
- // Setting an object created on the worker thread to a Member allocated on
- // the main thread is not allowed.
- wrapper_ = IntWrapper::Create(42);
-
- WakeMainThread();
- ThreadState::DetachCurrentThread();
- }
-};
-
-#if DCHECK_IS_ON()
-// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
-// crbug.com/709069
-#if !defined(OS_MACOSX)
-TEST(HeapDeathTest, MemberSameThreadCheck) {
- EXPECT_DEATH(MemberSameThreadCheckTester().Test(), "");
-}
-#endif
-#endif
-
-class PersistentSameThreadCheckTester {
- public:
- void Test() {
- IntWrapper::destructor_calls_ = 0;
-
- MutexLocker locker(MainThreadMutex());
- std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
- ThreadCreationParams(WebThreadType::kTestThread)
- .SetThreadNameForTest("Test Worker Thread"));
- PostCrossThreadTask(
- *worker_thread->GetTaskRunner(), FROM_HERE,
- CrossThreadBind(&PersistentSameThreadCheckTester::WorkerThreadMain,
- CrossThreadUnretained(this)));
-
- ParkMainThread();
- }
-
- private:
- Persistent<IntWrapper> wrapper_;
-
- void WorkerThreadMain() {
- MutexLocker locker(WorkerThreadMutex());
-
- ThreadState::AttachCurrentThread();
-
- // Setting an object created on the worker thread to a Persistent allocated
- // on the main thread is not allowed.
- wrapper_ = IntWrapper::Create(42);
-
- WakeMainThread();
- ThreadState::DetachCurrentThread();
- }
-};
-
-#if DCHECK_IS_ON()
-// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
-// crbug.com/709069
-#if !defined(OS_MACOSX)
-TEST(HeapDeathTest, PersistentSameThreadCheck) {
- EXPECT_DEATH(PersistentSameThreadCheckTester().Test(), "");
-}
-#endif
-#endif
-
-class MarkingSameThreadCheckTester {
- public:
- void Test() {
- IntWrapper::destructor_calls_ = 0;
-
- MutexLocker locker(MainThreadMutex());
- std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
- ThreadCreationParams(WebThreadType::kTestThread)
- .SetThreadNameForTest("Test Worker Thread"));
- Persistent<MainThreadObject> main_thread_object = new MainThreadObject();
- PostCrossThreadTask(
- *worker_thread->GetTaskRunner(), FROM_HERE,
- CrossThreadBind(&MarkingSameThreadCheckTester::WorkerThreadMain,
- CrossThreadUnretained(this),
- WrapCrossThreadPersistent(main_thread_object.Get())));
- ParkMainThread();
- // This will try to mark MainThreadObject when it tries to mark IntWrapper
- // it should crash.
- PreciselyCollectGarbage();
- }
-
- private:
- class MainThreadObject : public GarbageCollectedFinalized<MainThreadObject> {
- public:
- void Trace(blink::Visitor* visitor) { visitor->Trace(wrapper_set_); }
- void AddToSet(IntWrapper* wrapper) { wrapper_set_.insert(42, wrapper); }
-
- private:
- HeapHashMap<int, Member<IntWrapper>> wrapper_set_;
- };
-
- void WorkerThreadMain(MainThreadObject* main_thread_object) {
- MutexLocker locker(WorkerThreadMutex());
-
- ThreadState::AttachCurrentThread();
-
- // Adding a reference to an object created on the worker thread to a
- // HeapHashMap created on the main thread is not allowed.
- main_thread_object->AddToSet(IntWrapper::Create(42));
-
- WakeMainThread();
- ThreadState::DetachCurrentThread();
- }
-};
-
-#if DCHECK_IS_ON()
-// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
-// crbug.com/709069
-#if !defined(OS_MACOSX)
-TEST(HeapDeathTest, MarkingSameThreadCheck) {
- // This will crash during marking, at the DCHECK in Visitor::markHeader() or
- // earlier.
- EXPECT_DEATH(MarkingSameThreadCheckTester().Test(), "");
-}
-#endif
-#endif
-
static bool AllocateAndReturnBool() {
ConservativelyCollectGarbage();
return true;
}
-static bool CheckGCForbidden() {
- DCHECK(ThreadState::Current()->IsGCForbidden());
- return true;
-}
-
-class MixinClass : public GarbageCollectedMixin {
- public:
- MixinClass() : dummy_(CheckGCForbidden()) {}
-
- private:
- bool dummy_;
-};
-
-class ClassWithGarbageCollectingMixinConstructor
- : public GarbageCollected<ClassWithGarbageCollectingMixinConstructor>,
- public MixinClass {
- USING_GARBAGE_COLLECTED_MIXIN(ClassWithGarbageCollectingMixinConstructor);
-
- public:
- static int trace_called_;
-
- ClassWithGarbageCollectingMixinConstructor()
- : trace_counter_(TraceCounter::Create()),
- wrapper_(IntWrapper::Create(32)) {}
-
- void Trace(blink::Visitor* visitor) override {
- trace_called_++;
- visitor->Trace(trace_counter_);
- visitor->Trace(wrapper_);
- }
-
- void Verify() {
- EXPECT_EQ(32, wrapper_->Value());
- EXPECT_EQ(0, trace_counter_->TraceCount());
- EXPECT_EQ(0, trace_called_);
- }
-
- private:
- Member<TraceCounter> trace_counter_;
- Member<IntWrapper> wrapper_;
-};
-
-int ClassWithGarbageCollectingMixinConstructor::trace_called_ = 0;
-
-// Regression test for out of bounds call through vtable.
-// Passes if it doesn't crash.
-TEST(HeapTest, GarbageCollectionDuringMixinConstruction) {
- ClassWithGarbageCollectingMixinConstructor::trace_called_ = 0;
- ClassWithGarbageCollectingMixinConstructor* a =
- new ClassWithGarbageCollectingMixinConstructor();
- a->Verify();
-}
-
-class DestructorLockingObject
- : public GarbageCollectedFinalized<DestructorLockingObject> {
- public:
- static DestructorLockingObject* Create() {
- return new DestructorLockingObject();
- }
-
- virtual ~DestructorLockingObject() {
- ++destructor_calls_;
- }
-
- static int destructor_calls_;
- void Trace(blink::Visitor* visitor) {}
-
- private:
- DestructorLockingObject() = default;
-};
-
-int DestructorLockingObject::destructor_calls_ = 0;
-
template <typename T>
class TraceIfNeededTester
: public GarbageCollectedFinalized<TraceIfNeededTester<T>> {
@@ -5767,7 +5403,7 @@ class PartObject {
class AllocatesOnAssignment {
public:
AllocatesOnAssignment(std::nullptr_t) : value_(nullptr) {}
- AllocatesOnAssignment(int x) : value_(new IntWrapper(x)) {}
+ AllocatesOnAssignment(int x) : value_(MakeGarbageCollected<IntWrapper>(x)) {}
AllocatesOnAssignment(IntWrapper* x) : value_(x) {}
AllocatesOnAssignment& operator=(const AllocatesOnAssignment x) {
@@ -5780,7 +5416,7 @@ class AllocatesOnAssignment {
AllocatesOnAssignment(const AllocatesOnAssignment& other) {
if (!ThreadState::Current()->IsGCForbidden())
ConservativelyCollectGarbage();
- value_ = new IntWrapper(other.value_->Value());
+ value_ = MakeGarbageCollected<IntWrapper>(other.value_->Value());
}
AllocatesOnAssignment(DeletedMarker) : value_(WTF::kHashTableDeletedValue) {}
@@ -5852,7 +5488,7 @@ namespace blink {
TEST(HeapTest, GCInHashMapOperations) {
typedef HeapHashMap<AllocatesOnAssignment, AllocatesOnAssignment> Map;
Map* map = MakeGarbageCollected<Map>();
- IntWrapper* key = new IntWrapper(42);
+ IntWrapper* key = MakeGarbageCollected<IntWrapper>(42);
map->insert(key, AllocatesOnAssignment(103));
map->erase(key);
for (int i = 0; i < 10; i++)
@@ -5878,7 +5514,8 @@ class ObjectWithVirtualPartObject
};
TEST(HeapTest, PartObjectWithVirtualMethod) {
- ObjectWithVirtualPartObject* object = new ObjectWithVirtualPartObject();
+ ObjectWithVirtualPartObject* object =
+ MakeGarbageCollected<ObjectWithVirtualPartObject>();
EXPECT_TRUE(object);
}
@@ -5905,7 +5542,7 @@ class AllocInSuperConstructorArgument
// an object with an uninitialized vtable.
TEST(HeapTest, AllocationInSuperConstructorArgument) {
AllocInSuperConstructorArgument* object =
- new AllocInSuperConstructorArgument();
+ MakeGarbageCollected<AllocInSuperConstructorArgument>();
EXPECT_TRUE(object);
ThreadState::Current()->CollectAllGarbage();
}
@@ -5925,7 +5562,7 @@ class NonNodeAllocatingNodeInDestructor
Persistent<IntNode>* NonNodeAllocatingNodeInDestructor::node_ = nullptr;
TEST(HeapTest, NonNodeAllocatingNodeInDestructor) {
- new NonNodeAllocatingNodeInDestructor();
+ MakeGarbageCollected<NonNodeAllocatingNodeInDestructor>();
PreciselyCollectGarbage();
EXPECT_EQ(10, (*NonNodeAllocatingNodeInDestructor::node_)->Value());
delete NonNodeAllocatingNodeInDestructor::node_;
@@ -5999,7 +5636,7 @@ TEST(HeapTest, TraceDeepEagerly) {
#if !DCHECK_IS_ON() && !defined(OS_ANDROID)
DeepEagerly* obj = nullptr;
for (int i = 0; i < 10000000; i++)
- obj = new DeepEagerly(obj);
+ obj = MakeGarbageCollected<DeepEagerly>(obj);
Persistent<DeepEagerly> persistent(obj);
PreciselyCollectGarbage();
@@ -6238,11 +5875,7 @@ class TestMixinAllocationA : public GarbageCollected<TestMixinAllocationA>,
USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationA);
public:
- TestMixinAllocationA() {
- // Completely wrong in general, but test only
- // runs this constructor while constructing another mixin.
- DCHECK(ThreadState::Current()->IsGCForbidden());
- }
+ TestMixinAllocationA() = default;
void Trace(blink::Visitor* visitor) override {}
};
@@ -6252,13 +5885,8 @@ class TestMixinAllocationB : public TestMixinAllocationA {
public:
TestMixinAllocationB()
- : a_(new TestMixinAllocationA()) // Construct object during a mixin
- // construction.
- {
- // Completely wrong in general, but test only
- // runs this constructor while constructing another mixin.
- DCHECK(ThreadState::Current()->IsGCForbidden());
- }
+ // Construct object during a mixin construction.
+ : a_(MakeGarbageCollected<TestMixinAllocationA>()) {}
void Trace(blink::Visitor* visitor) override {
visitor->Trace(a_);
@@ -6281,7 +5909,7 @@ class TestMixinAllocationC final : public TestMixinAllocationB {
};
TEST(HeapTest, NestedMixinConstruction) {
- TestMixinAllocationC* object = new TestMixinAllocationC();
+ TestMixinAllocationC* object = MakeGarbageCollected<TestMixinAllocationC>();
EXPECT_TRUE(object);
}
@@ -6303,47 +5931,6 @@ class ObjectWithLargeAmountsOfAllocationInConstructor {
}
};
-class TestMixinAllocatingObject final
- : public TestMixinAllocationB,
- public ObjectWithLargeAmountsOfAllocationInConstructor {
- USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocatingObject);
-
- public:
- static TestMixinAllocatingObject* Create(ClassWithMember* member) {
- return new TestMixinAllocatingObject(member);
- }
-
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(trace_counter_);
- TestMixinAllocationB::Trace(visitor);
- }
-
- int TraceCount() const { return trace_counter_->TraceCount(); }
-
- private:
- TestMixinAllocatingObject(ClassWithMember* member)
- : ObjectWithLargeAmountsOfAllocationInConstructor(600, member),
- trace_counter_(TraceCounter::Create()) {
- DCHECK(!ThreadState::Current()->IsGCForbidden());
- ConservativelyCollectGarbage();
- EXPECT_GT(member->TraceCount(), 0);
- EXPECT_GT(TraceCount(), 0);
- }
-
- Member<TraceCounter> trace_counter_;
-};
-
-TEST(HeapTest, MixinConstructionNoGC) {
- ClearOutOldGarbage();
- Persistent<ClassWithMember> object = ClassWithMember::Create();
- EXPECT_EQ(0, object->TraceCount());
- TestMixinAllocatingObject* mixin =
- TestMixinAllocatingObject::Create(object.Get());
- EXPECT_TRUE(mixin);
- EXPECT_GT(object->TraceCount(), 0);
- EXPECT_GT(mixin->TraceCount(), 0);
-}
-
class WeakPersistentHolder final {
public:
explicit WeakPersistentHolder(IntWrapper* object) : object_(object) {}
@@ -6354,7 +5941,7 @@ class WeakPersistentHolder final {
};
TEST(HeapTest, WeakPersistent) {
- Persistent<IntWrapper> object = new IntWrapper(20);
+ Persistent<IntWrapper> object = MakeGarbageCollected<IntWrapper>(20);
std::unique_ptr<WeakPersistentHolder> holder =
std::make_unique<WeakPersistentHolder>(object);
PreciselyCollectGarbage();
@@ -6366,71 +5953,6 @@ TEST(HeapTest, WeakPersistent) {
namespace {
-void WorkerThreadMainForCrossThreadWeakPersistentTest(
- DestructorLockingObject** object) {
- // Step 2: Create an object and store the pointer.
- MutexLocker locker(WorkerThreadMutex());
- ThreadState::AttachCurrentThread();
- *object = DestructorLockingObject::Create();
- WakeMainThread();
- ParkWorkerThread();
-
- // Step 4: Run a GC.
- ThreadState::Current()->CollectGarbage(
- BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
- BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
- WakeMainThread();
- ParkWorkerThread();
-
- // Step 6: Finish.
- ThreadState::DetachCurrentThread();
- WakeMainThread();
-}
-
-} // anonymous namespace
-
-TEST(HeapTest, CrossThreadWeakPersistent) {
- // Create an object in the worker thread, have a CrossThreadWeakPersistent
- // pointing to it on the main thread, clear the reference in the worker
- // thread, run a GC in the worker thread, and see if the
- // CrossThreadWeakPersistent is cleared.
-
- DestructorLockingObject::destructor_calls_ = 0;
-
- // Step 1: Initiate a worker thread, and wait for |object| to get allocated on
- // the worker thread.
- MutexLocker main_thread_mutex_locker(MainThreadMutex());
- std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
- ThreadCreationParams(WebThreadType::kTestThread)
- .SetThreadNameForTest("Test Worker Thread"));
- DestructorLockingObject* object = nullptr;
- PostCrossThreadTask(
- *worker_thread->GetTaskRunner(), FROM_HERE,
- CrossThreadBind(WorkerThreadMainForCrossThreadWeakPersistentTest,
- CrossThreadUnretained(&object)));
- ParkMainThread();
-
- // Step 3: Set up a CrossThreadWeakPersistent.
- ASSERT_TRUE(object);
- CrossThreadWeakPersistent<DestructorLockingObject>
- cross_thread_weak_persistent(object);
- object = nullptr;
- EXPECT_EQ(0, DestructorLockingObject::destructor_calls_);
-
- // Pretend we have no pointers on stack during the step 4.
- WakeWorkerThread();
- ParkMainThread();
-
- // Step 5: Make sure the weak persistent is cleared.
- EXPECT_FALSE(cross_thread_weak_persistent.Get());
- EXPECT_EQ(1, DestructorLockingObject::destructor_calls_);
-
- WakeWorkerThread();
- ParkMainThread();
-}
-
-namespace {
-
class ThreadedClearOnShutdownTester : public ThreadedTesterBase {
public:
static void Test() {
@@ -6443,11 +5965,8 @@ class ThreadedClearOnShutdownTester : public ThreadedTesterBase {
void RunWhileAttached();
void RunThread() override {
- ThreadState::AttachCurrentThread();
EXPECT_EQ(42, ThreadSpecificIntWrapper().Value());
RunWhileAttached();
- ThreadState::DetachCurrentThread();
- AtomicDecrement(&threads_to_finish_);
}
class HeapObject;
@@ -6465,7 +5984,7 @@ class ThreadedClearOnShutdownTester : public ThreadedTesterBase {
int_wrapper, ());
Persistent<IntWrapper>& handle = *int_wrapper;
if (!handle) {
- handle = new IntWrapper(42);
+ handle = MakeGarbageCollected<IntWrapper>(42);
handle.RegisterAsStaticReference();
}
return *handle;
@@ -6477,9 +5996,11 @@ class ThreadedClearOnShutdownTester::HeapObject final
ThreadedClearOnShutdownTester::HeapObject> {
public:
static HeapObject* Create(bool test_destructor) {
- return new HeapObject(test_destructor);
+ return MakeGarbageCollected<HeapObject>(test_destructor);
}
+ explicit HeapObject(bool test_destructor)
+ : test_destructor_(test_destructor) {}
~HeapObject() {
if (!test_destructor_)
return;
@@ -6498,9 +6019,6 @@ class ThreadedClearOnShutdownTester::HeapObject final
void Trace(blink::Visitor* visitor) {}
private:
- explicit HeapObject(bool test_destructor)
- : test_destructor_(test_destructor) {}
-
bool test_destructor_;
};
@@ -6544,16 +6062,16 @@ TEST(HeapTest, TestClearOnShutdown) {
class WithWeakConstObject final : public GarbageCollected<WithWeakConstObject> {
public:
static WithWeakConstObject* Create(const IntWrapper* int_wrapper) {
- return new WithWeakConstObject(int_wrapper);
+ return MakeGarbageCollected<WithWeakConstObject>(int_wrapper);
}
+ WithWeakConstObject(const IntWrapper* int_wrapper) : wrapper_(int_wrapper) {}
+
void Trace(blink::Visitor* visitor) { visitor->Trace(wrapper_); }
const IntWrapper* Value() const { return wrapper_; }
private:
- WithWeakConstObject(const IntWrapper* int_wrapper) : wrapper_(int_wrapper) {}
-
WeakMember<const IntWrapper> wrapper_;
};
@@ -6649,7 +6167,7 @@ class DoublyLinkedListNodeImpl
public:
DoublyLinkedListNodeImpl() = default;
static DoublyLinkedListNodeImpl* Create() {
- return new DoublyLinkedListNodeImpl();
+ return MakeGarbageCollected<DoublyLinkedListNodeImpl>();
}
static int destructor_calls_;
@@ -6673,7 +6191,7 @@ class HeapDoublyLinkedListContainer
: public GarbageCollected<HeapDoublyLinkedListContainer<T>> {
public:
static HeapDoublyLinkedListContainer<T>* Create() {
- return new HeapDoublyLinkedListContainer<T>();
+ return MakeGarbageCollected<HeapDoublyLinkedListContainer<T>>();
}
HeapDoublyLinkedListContainer<T>() = default;
HeapDoublyLinkedList<T> list_;
@@ -6706,7 +6224,7 @@ TEST(HeapTest, PromptlyFreeStackAllocatedHeapVector) {
Address before;
{
HeapVector<Member<IntWrapper>> vector;
- vector.push_back(new IntWrapper(0));
+ vector.push_back(MakeGarbageCollected<IntWrapper>(0));
NormalPage* normal_page =
static_cast<NormalPage*>(PageFromObject(vector.data()));
normal_arena = normal_page->ArenaForNormalPage();
@@ -6723,7 +6241,7 @@ TEST(HeapTest, PromptlyFreeStackAllocatedHeapDeque) {
Address before;
{
HeapDeque<Member<IntWrapper>> deque;
- deque.push_back(new IntWrapper(0));
+ deque.push_back(MakeGarbageCollected<IntWrapper>(0));
NormalPage* normal_page =
static_cast<NormalPage*>(PageFromObject(&deque.front()));
normal_arena = normal_page->ArenaForNormalPage();
@@ -6742,7 +6260,7 @@ TEST(HeapTest, PromptlyFreeStackAllocatedHeapHashSet) {
Address before;
{
HeapHashSet<Member<IntWrapper>> hash_set;
- hash_set.insert(new IntWrapper(0));
+ hash_set.insert(MakeGarbageCollected<IntWrapper>(0));
before = normal_arena->CurrentAllocationPoint();
}
Address after = normal_arena->CurrentAllocationPoint();
@@ -6758,7 +6276,7 @@ TEST(HeapTest, PromptlyFreeStackAllocatedHeapListHashSet) {
Address before;
{
HeapListHashSet<Member<IntWrapper>> list_hash_set;
- list_hash_set.insert(new IntWrapper(0));
+ list_hash_set.insert(MakeGarbageCollected<IntWrapper>(0));
before = normal_arena->CurrentAllocationPoint();
}
Address after = normal_arena->CurrentAllocationPoint();
@@ -6773,7 +6291,7 @@ TEST(HeapTest, PromptlyFreeStackAllocatedHeapLinkedHashSet) {
Address before;
{
HeapLinkedHashSet<Member<IntWrapper>> linked_hash_set;
- linked_hash_set.insert(new IntWrapper(0));
+ linked_hash_set.insert(MakeGarbageCollected<IntWrapper>(0));
before = normal_arena->CurrentAllocationPoint();
}
Address after = normal_arena->CurrentAllocationPoint();
@@ -6787,7 +6305,7 @@ TEST(HeapTest, ShrinkVector) {
HeapVector<Member<IntWrapper>> vector;
vector.ReserveCapacity(32);
for (int i = 0; i < 4; i++) {
- vector.push_back(new IntWrapper(i));
+ vector.push_back(MakeGarbageCollected<IntWrapper>(i));
}
ConservativelyCollectGarbage(BlinkGC::kLazySweeping);
@@ -6798,85 +6316,30 @@ TEST(HeapTest, ShrinkVector) {
vector.ShrinkToFit();
}
-namespace {
-
-class MixinCheckingConstructionScope : public GarbageCollectedMixin {
- public:
- MixinCheckingConstructionScope() {
- // Oilpan treats mixin construction as forbidden scopes for garbage
- // collection.
- CHECK(ThreadState::Current()->IsMixinInConstruction());
- }
-};
-
-class UsingMixinCheckingConstructionScope
- : public GarbageCollected<UsingMixinCheckingConstructionScope>,
- public MixinCheckingConstructionScope {
- USING_GARBAGE_COLLECTED_MIXIN(UsingMixinCheckingConstructionScope);
-};
-
-} // namespace
-
-TEST(HeapTest, NoConservativeGCDuringMixinConstruction) {
- // Regression test: https://crbug.com/904546
- MakeGarbageCollected<UsingMixinCheckingConstructionScope>();
+TEST(HeapTest, GarbageCollectedInConstruction) {
+ using O = ObjectWithCallbackBeforeInitializer<IntWrapper>;
+ MakeGarbageCollected<O>(base::BindOnce([](O* thiz) {
+ CHECK(HeapObjectHeader::FromPayload(thiz)->IsInConstruction());
+ }));
}
-namespace {
-
-class ObjectCheckingForInConstruction
- : public GarbageCollected<ObjectCheckingForInConstruction> {
- public:
- ObjectCheckingForInConstruction() {
- CHECK(HeapObjectHeader::FromPayload(this)->IsInConstruction());
- }
-
- virtual void Trace(Visitor* v) { v->Trace(foo_); }
-
- private:
- Member<IntWrapper> foo_;
-};
-
-class MixinCheckingInConstruction : public GarbageCollectedMixin {
- public:
- MixinCheckingInConstruction() {
- BasePage* const page = PageFromObject(reinterpret_cast<Address>(this));
+TEST(HeapTest, GarbageCollectedMixinInConstruction) {
+ using O = ObjectWithMixinWithCallbackBeforeInitializer<IntWrapper>;
+ MakeGarbageCollected<O>(base::BindOnce([](O::Mixin* thiz) {
+ BasePage* const page = PageFromObject(thiz);
HeapObjectHeader* const header =
- static_cast<NormalPage*>(page)->FindHeaderFromAddress(
- reinterpret_cast<Address>(
- const_cast<MixinCheckingInConstruction*>(this)));
+ page->IsLargeObjectPage()
+ ? static_cast<LargeObjectPage*>(page)->ObjectHeader()
+ : static_cast<NormalPage*>(page)->FindHeaderFromAddress(
+ reinterpret_cast<Address>(thiz));
CHECK(header->IsInConstruction());
- }
-
- void Trace(Visitor* v) override { v->Trace(bar_); }
-
- private:
- Member<IntWrapper> bar_;
-};
-
-class MixinAppCheckingInConstruction
- : public GarbageCollected<MixinAppCheckingInConstruction>,
- public MixinCheckingInConstruction {
- USING_GARBAGE_COLLECTED_MIXIN(MixinAppCheckingInConstruction)
- public:
- MixinAppCheckingInConstruction() {
- CHECK(HeapObjectHeader::FromPayload(this)->IsInConstruction());
- }
-
- void Trace(Visitor* v) override { v->Trace(foo_); }
-
- private:
- Member<IntWrapper> foo_;
-};
-
-} // namespace
-
-TEST(HeapTest, GarbageCollectedInConstruction) {
- MakeGarbageCollected<ObjectCheckingForInConstruction>();
+ }));
}
-TEST(HeapTest, GarbageCollectedMixinInConstruction) {
- MakeGarbageCollected<MixinAppCheckingInConstruction>();
+TEST(HeapTest, GarbageCollectedMixinIsAliveDuringConstruction) {
+ using O = ObjectWithMixinWithCallbackBeforeInitializer<IntWrapper>;
+ MakeGarbageCollected<O>(base::BindOnce(
+ [](O::Mixin* thiz) { CHECK(ThreadHeap::IsHeapObjectAlive(thiz)); }));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h
index 97778731db1..31af7270aca 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h
@@ -7,7 +7,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
+#include "base/callback.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
@@ -16,6 +21,90 @@ void ConservativelyCollectGarbage(
BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
void ClearOutOldGarbage();
+template <typename T>
+class ObjectWithCallbackBeforeInitializer
+ : public GarbageCollected<ObjectWithCallbackBeforeInitializer<T>> {
+ public:
+ ObjectWithCallbackBeforeInitializer(
+ base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb,
+ T* value)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
+
+ ObjectWithCallbackBeforeInitializer(
+ base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
+
+ virtual void Trace(Visitor* visitor) { visitor->Trace(value_); }
+
+ T* value() const { return value_.Get(); }
+
+ private:
+ static bool ExecuteCallbackReturnTrue(
+ ObjectWithCallbackBeforeInitializer* thiz,
+ base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb) {
+ std::move(cb).Run(thiz);
+ return true;
+ }
+
+ bool bool_;
+ Member<T> value_;
+};
+
+template <typename T>
+class MixinWithCallbackBeforeInitializer : public GarbageCollectedMixin {
+ public:
+ MixinWithCallbackBeforeInitializer(
+ base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb,
+ T* value)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
+
+ MixinWithCallbackBeforeInitializer(
+ base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
+
+ void Trace(Visitor* visitor) override { visitor->Trace(value_); }
+
+ T* value() const { return value_.Get(); }
+
+ private:
+ static bool ExecuteCallbackReturnTrue(
+ MixinWithCallbackBeforeInitializer* thiz,
+ base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb) {
+ std::move(cb).Run(thiz);
+ return true;
+ }
+
+ bool bool_;
+ Member<T> value_;
+};
+
+class BoolMixin {
+ protected:
+ bool bool_ = false;
+};
+
+template <typename T>
+class ObjectWithMixinWithCallbackBeforeInitializer
+ : public GarbageCollected<ObjectWithMixinWithCallbackBeforeInitializer<T>>,
+ public BoolMixin,
+ public MixinWithCallbackBeforeInitializer<T> {
+ USING_GARBAGE_COLLECTED_MIXIN(ObjectWithMixinWithCallbackBeforeInitializer);
+
+ public:
+ using Mixin = MixinWithCallbackBeforeInitializer<T>;
+
+ ObjectWithMixinWithCallbackBeforeInitializer(
+ base::OnceCallback<void(Mixin*)>&& cb,
+ T* value)
+ : Mixin(std::move(cb), value) {}
+
+ ObjectWithMixinWithCallbackBeforeInitializer(
+ base::OnceCallback<void(Mixin*)>&& cb)
+ : Mixin(std::move(cb)) {}
+
+ void Trace(Visitor* visitor) override { Mixin::Trace(visitor); }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_thread_test.cc b/chromium/third_party/blink/renderer/platform/heap/heap_thread_test.cc
new file mode 100644
index 00000000000..b1f86ce0cee
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_thread_test.cc
@@ -0,0 +1,269 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+
+namespace blink {
+namespace heap_thread_test {
+
+static Mutex& ActiveThreadMutex() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, active_thread_mutex, ());
+ return active_thread_mutex;
+}
+
+static ThreadCondition& ActiveThreadCondition() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadCondition, active_thread_condition,
+ (ActiveThreadMutex()));
+ return active_thread_condition;
+}
+
+enum ActiveThreadState {
+ kNoThreadActive,
+ kMainThreadActive,
+ kWorkerThreadActive,
+};
+
+static ActiveThreadState& ActiveThread() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(ActiveThreadState, active_thread,
+ (kNoThreadActive));
+ return active_thread;
+}
+
+static void WakeMainThread() {
+ ActiveThread() = kMainThreadActive;
+ ActiveThreadCondition().Signal();
+}
+
+static void WakeWorkerThread() {
+ ActiveThread() = kWorkerThreadActive;
+ ActiveThreadCondition().Signal();
+}
+
+static void ParkMainThread() {
+ while (ActiveThread() != kMainThreadActive) {
+ ActiveThreadCondition().Wait();
+ }
+}
+
+static void ParkWorkerThread() {
+ while (ActiveThread() != kWorkerThreadActive) {
+ ActiveThreadCondition().Wait();
+ }
+}
+
+class Object : public GarbageCollected<Object> {
+ public:
+ Object() {}
+ ~Object() {}
+ void Trace(blink::Visitor* visitor) {}
+};
+
+class AlternatingThreadTester {
+ public:
+ void Test() {
+ MutexLocker locker(ActiveThreadMutex());
+ ActiveThread() = kMainThreadActive;
+
+ std::unique_ptr<Thread> worker_thread = Platform::Current()->CreateThread(
+ ThreadCreationParams(WebThreadType::kTestThread)
+ .SetThreadNameForTest("Test Worker Thread"));
+ PostCrossThreadTask(
+ *worker_thread->GetTaskRunner(), FROM_HERE,
+ CrossThreadBind(&AlternatingThreadTester::StartWorkerThread,
+ CrossThreadUnretained(this)));
+
+ MainThreadMain();
+ }
+
+ void SwitchToWorkerThread() {
+ WakeWorkerThread();
+ ParkMainThread();
+ }
+
+ void SwitchToMainThread() {
+ WakeMainThread();
+ ParkWorkerThread();
+ }
+
+ protected:
+ // Override with code you want to execute on the main thread.
+ virtual void MainThreadMain() = 0;
+ // Override with code you want to execute on the worker thread. At the end,
+ // the ThreadState is detached and we switch back to the main thread
+ // automatically.
+ virtual void WorkerThreadMain() = 0;
+
+ private:
+ void StartWorkerThread() {
+ ThreadState::AttachCurrentThread();
+
+ MutexLocker locker(ActiveThreadMutex());
+
+ WorkerThreadMain();
+
+ ThreadState::DetachCurrentThread();
+ WakeMainThread();
+ }
+};
+
+class MemberSameThreadCheckTester : public AlternatingThreadTester {
+ private:
+ void MainThreadMain() override { SwitchToWorkerThread(); }
+
+ void WorkerThreadMain() override {
+ // Setting an object created on the worker thread to a Member allocated on
+ // the main thread is not allowed.
+ object_ = MakeGarbageCollected<Object>();
+ }
+
+ Member<Object> object_;
+};
+
+#if DCHECK_IS_ON()
+// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
+// crbug.com/709069
+#if !defined(OS_MACOSX)
+TEST(HeapDeathTest, MemberSameThreadCheck) {
+ EXPECT_DEATH(MemberSameThreadCheckTester().Test(), "");
+}
+#endif
+#endif
+
+class PersistentSameThreadCheckTester : public AlternatingThreadTester {
+ private:
+ void MainThreadMain() override { SwitchToWorkerThread(); }
+
+ void WorkerThreadMain() override {
+ // Setting an object created on the worker thread to a Persistent allocated
+ // on the main thread is not allowed.
+ object_ = MakeGarbageCollected<Object>();
+ }
+
+ Persistent<Object> object_;
+};
+
+#if DCHECK_IS_ON()
+// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
+// crbug.com/709069
+#if !defined(OS_MACOSX)
+TEST(HeapDeathTest, PersistentSameThreadCheck) {
+ EXPECT_DEATH(PersistentSameThreadCheckTester().Test(), "");
+}
+#endif
+#endif
+
+class MarkingSameThreadCheckTester : public AlternatingThreadTester {
+ private:
+ class MainThreadObject : public GarbageCollectedFinalized<MainThreadObject> {
+ public:
+ void Trace(blink::Visitor* visitor) { visitor->Trace(set_); }
+ void AddToSet(Object* object) { set_.insert(42, object); }
+
+ private:
+ HeapHashMap<int, Member<Object>> set_;
+ };
+
+ void MainThreadMain() override {
+ main_thread_object_ = MakeGarbageCollected<MainThreadObject>();
+
+ SwitchToWorkerThread();
+
+ // This will try to mark MainThreadObject when it tries to mark Object
+ // it should crash.
+ PreciselyCollectGarbage();
+ }
+
+ void WorkerThreadMain() override {
+ // Adding a reference to an object created on the worker thread to a
+ // HeapHashMap created on the main thread is not allowed.
+ main_thread_object_->AddToSet(MakeGarbageCollected<Object>());
+ }
+
+ CrossThreadPersistent<MainThreadObject> main_thread_object_;
+};
+
+#if DCHECK_IS_ON()
+// TODO(keishi) This test is flaky on mac_chromium_rel_ng bot.
+// crbug.com/709069
+#if !defined(OS_MACOSX)
+TEST(HeapDeathTest, MarkingSameThreadCheck) {
+ // This will crash during marking, at the DCHECK in Visitor::markHeader() or
+ // earlier.
+ EXPECT_DEATH(MarkingSameThreadCheckTester().Test(), "");
+}
+#endif
+#endif
+
+class DestructorLockingObject
+ : public GarbageCollectedFinalized<DestructorLockingObject> {
+ public:
+ static DestructorLockingObject* Create() {
+ return MakeGarbageCollected<DestructorLockingObject>();
+ }
+
+ DestructorLockingObject() = default;
+ virtual ~DestructorLockingObject() { ++destructor_calls_; }
+
+ static int destructor_calls_;
+ void Trace(blink::Visitor* visitor) {}
+};
+
+int DestructorLockingObject::destructor_calls_ = 0;
+
+class CrossThreadWeakPersistentTester : public AlternatingThreadTester {
+ private:
+ void MainThreadMain() override {
+ // Create an object in the worker thread, have a CrossThreadWeakPersistent
+ // pointing to it on the main thread, run a GC in the worker thread, and see
+ // if the CrossThreadWeakPersistent is cleared.
+
+ DestructorLockingObject::destructor_calls_ = 0;
+
+ // Step 1: Initiate a worker thread, and wait for |Object| to get allocated
+ // on the worker thread.
+ SwitchToWorkerThread();
+
+ // Step 3: Set up a CrossThreadWeakPersistent.
+ ASSERT_TRUE(object_);
+ EXPECT_EQ(0, DestructorLockingObject::destructor_calls_);
+
+ // Pretend we have no pointers on stack during the step 4.
+ SwitchToWorkerThread();
+
+ // Step 5: Make sure the weak persistent is cleared.
+ EXPECT_FALSE(object_.Get());
+ EXPECT_EQ(1, DestructorLockingObject::destructor_calls_);
+
+ SwitchToWorkerThread();
+ }
+
+ void WorkerThreadMain() override {
+ // Step 2: Create an object and store the pointer.
+ object_ = DestructorLockingObject::Create();
+ SwitchToMainThread();
+
+ // Step 4: Run a GC.
+ ThreadState::Current()->CollectGarbage(
+ BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
+ BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
+ SwitchToMainThread();
+ }
+
+ CrossThreadWeakPersistent<DestructorLockingObject> object_;
+};
+
+TEST(HeapThreadTest, CrossThreadWeakPersistent) {
+ CrossThreadWeakPersistentTester().Test();
+}
+
+} // namespace heap_thread_test
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/incremental_marking_test.cc b/chromium/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
index f82eaf2df9c..b359297ba28 100644
--- a/chromium/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
@@ -223,8 +223,13 @@ class ExpectNoWriteBarrierFires : public IncrementalMarkingScope {
class Object : public GarbageCollected<Object> {
public:
- static Object* Create() { return new Object(); }
- static Object* Create(Object* next) { return new Object(next); }
+ static Object* Create() { return MakeGarbageCollected<Object>(); }
+ static Object* Create(Object* next) {
+ return MakeGarbageCollected<Object>(next);
+ }
+
+ Object() : next_(nullptr) {}
+ explicit Object(Object* next) : next_(next) {}
void set_next(Object* next) { next_ = next; }
@@ -237,9 +242,6 @@ class Object : public GarbageCollected<Object> {
Member<Object>& next_ref() { return next_; }
private:
- Object() : next_(nullptr) {}
- explicit Object(Object* next) : next_(next) {}
-
Member<Object> next_;
};
@@ -389,31 +391,30 @@ class Child : public GarbageCollected<Child>,
USING_GARBAGE_COLLECTED_MIXIN(Child);
public:
- static Child* Create() { return new Child(); }
+ static Child* Create() { return MakeGarbageCollected<Child>(); }
+
+ Child() : ClassWithVirtual(), Mixin() {}
~Child() override {}
void Trace(blink::Visitor* visitor) override { Mixin::Trace(visitor); }
void Foo() override {}
void Bar() override {}
-
- protected:
- Child() : ClassWithVirtual(), Mixin() {}
};
class ParentWithMixinPointer : public GarbageCollected<ParentWithMixinPointer> {
public:
static ParentWithMixinPointer* Create() {
- return new ParentWithMixinPointer();
+ return MakeGarbageCollected<ParentWithMixinPointer>();
}
+ ParentWithMixinPointer() : mixin_(nullptr) {}
+
void set_mixin(Mixin* mixin) { mixin_ = mixin; }
virtual void Trace(blink::Visitor* visitor) { visitor->Trace(mixin_); }
protected:
- ParentWithMixinPointer() : mixin_(nullptr) {}
-
Member<Mixin> mixin_;
};
@@ -700,7 +701,7 @@ class ObjectNode : public GarbageCollected<ObjectNode>,
TEST(IncrementalMarkingTest, HeapDoublyLinkedListPush) {
Object* obj = Object::Create();
- ObjectNode* obj_node = new ObjectNode(obj);
+ ObjectNode* obj_node = MakeGarbageCollected<ObjectNode>(obj);
HeapDoublyLinkedList<ObjectNode> list;
{
ExpectWriteBarrierFires scope(ThreadState::Current(), {obj_node});
@@ -712,7 +713,7 @@ TEST(IncrementalMarkingTest, HeapDoublyLinkedListPush) {
TEST(IncrementalMarkingTest, HeapDoublyLinkedListAppend) {
Object* obj = Object::Create();
- ObjectNode* obj_node = new ObjectNode(obj);
+ ObjectNode* obj_node = MakeGarbageCollected<ObjectNode>(obj);
HeapDoublyLinkedList<ObjectNode> list;
{
ExpectWriteBarrierFires scope(ThreadState::Current(), {obj_node});
@@ -1502,7 +1503,8 @@ class RegisteringObject : public GarbageCollected<RegisteringObject>,
TEST(IncrementalMarkingTest, WriteBarrierDuringMixinConstruction) {
IncrementalMarkingScope scope(ThreadState::Current());
ObjectRegistry registry;
- RegisteringObject* object = new RegisteringObject(&registry);
+ RegisteringObject* object =
+ MakeGarbageCollected<RegisteringObject>(&registry);
// Clear any objects that have been added to the regular marking worklist in
// the process of calling the constructor.
@@ -1536,7 +1538,7 @@ TEST(IncrementalMarkingTest, WriteBarrierDuringMixinConstruction) {
TEST(IncrementalMarkingTest, OverrideAfterMixinConstruction) {
ObjectRegistry registry;
- RegisteringMixin* mixin = new RegisteringObject(&registry);
+ RegisteringMixin* mixin = MakeGarbageCollected<RegisteringObject>(&registry);
HeapObjectHeader* header = mixin->GetHeapObjectHeader();
const void* uninitialized_value = BlinkGC::kNotFullyConstructedObject;
EXPECT_NE(uninitialized_value, header);
@@ -1561,28 +1563,30 @@ class IncrementalMarkingTestDriver {
thread_state_->IncrementalMarkingStart(BlinkGC::GCReason::kTesting);
}
- bool SingleStep() {
+ bool SingleStep(BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack) {
CHECK(thread_state_->IsIncrementalMarking());
if (thread_state_->GetGCState() ==
ThreadState::kIncrementalMarkingStepScheduled) {
- thread_state_->RunScheduledGC(BlinkGC::kNoHeapPointersOnStack);
+ thread_state_->IncrementalMarkingStep(stack_state);
return true;
}
return false;
}
- void FinishSteps() {
+ void FinishSteps(BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack) {
CHECK(thread_state_->IsIncrementalMarking());
- while (SingleStep()) {
+ while (SingleStep(stack_state)) {
}
}
void FinishGC() {
CHECK(thread_state_->IsIncrementalMarking());
- FinishSteps();
+ FinishSteps(BlinkGC::StackState::kNoHeapPointersOnStack);
CHECK_EQ(ThreadState::kIncrementalMarkingFinalizeScheduled,
thread_state_->GetGCState());
- thread_state_->RunScheduledGC(BlinkGC::kNoHeapPointersOnStack);
+ thread_state_->RunScheduledGC(BlinkGC::StackState::kNoHeapPointersOnStack);
CHECK(!thread_state_->IsIncrementalMarking());
thread_state_->CompleteSweep();
}
@@ -1728,10 +1732,28 @@ TEST(IncrementalMarkingTest, WeakHashMapHeapCompaction) {
persistent->insert(Object::Create());
driver.FinishGC();
- // Weak caallback should register the slot.
+ // Weak callback should register the slot.
EXPECT_EQ(driver.GetHeapCompactLastFixupCount(), 1u);
}
+TEST(IncrementalMarkingTest, ConservativeGCWhileCompactionScheduled) {
+ using Store = HeapVector<Member<Object>>;
+ Persistent<Store> persistent(MakeGarbageCollected<Store>());
+ persistent->push_back(Object::Create());
+
+ IncrementalMarkingTestDriver driver(ThreadState::Current());
+ HeapCompact::ScheduleCompactionGCForTesting(true);
+ driver.Start();
+ driver.FinishSteps();
+ ThreadState::Current()->CollectGarbage(
+ BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking,
+ BlinkGC::kLazySweeping, BlinkGC::GCReason::kConservativeGC);
+
+ // Heap compaction should be canceled if incremental marking finishes with a
+ // conservative GC.
+ EXPECT_EQ(driver.GetHeapCompactLastFixupCount(), 0u);
+}
+
namespace {
class ObjectWithWeakMember : public GarbageCollected<ObjectWithWeakMember> {
@@ -1781,6 +1803,80 @@ TEST(IncrementalMarkingTest, MemberSwap) {
ConservativelyCollectGarbage();
}
+namespace {
+
+template <typename T>
+class ObjectHolder : public GarbageCollected<ObjectHolder<T>> {
+ public:
+ ObjectHolder() = default;
+
+ virtual void Trace(Visitor* visitor) { visitor->Trace(holder_); }
+
+ void set_value(T* value) { holder_ = value; }
+ T* value() const { return holder_.Get(); }
+
+ private:
+ Member<T> holder_;
+};
+
+} // namespace
+
+TEST(IncrementalMarkingTest, StepDuringObjectConstruction) {
+ // Test ensures that objects in construction are delayed for processing to
+ // allow omitting write barriers on initializing stores.
+
+ using O = ObjectWithCallbackBeforeInitializer<Object>;
+ using Holder = ObjectHolder<O>;
+ Persistent<Holder> holder(MakeGarbageCollected<Holder>());
+ IncrementalMarkingTestDriver driver(ThreadState::Current());
+ driver.Start();
+ MakeGarbageCollected<O>(
+ base::BindOnce(
+ [](IncrementalMarkingTestDriver* driver, Holder* holder, O* thiz) {
+ // Publish not-fully-constructed object |thiz| by triggering write
+ // barrier for the object.
+ holder->set_value(thiz);
+ CHECK(HeapObjectHeader::FromPayload(holder->value())->IsValid());
+ // Finish call incremental steps.
+ driver->FinishSteps(BlinkGC::StackState::kHeapPointersOnStack);
+ },
+ &driver, holder.Get()),
+ MakeGarbageCollected<Object>());
+ driver.FinishGC();
+ CHECK(HeapObjectHeader::FromPayload(holder->value())->IsValid());
+ CHECK(HeapObjectHeader::FromPayload(holder->value()->value())->IsValid());
+ PreciselyCollectGarbage();
+}
+
+TEST(IncrementalMarkingTest, StepDuringMixinObjectConstruction) {
+ // Test ensures that mixin objects in construction are delayed for processing
+ // to allow omitting write barriers on initializing stores.
+
+ using Parent = ObjectWithMixinWithCallbackBeforeInitializer<Object>;
+ using Mixin = MixinWithCallbackBeforeInitializer<Object>;
+ using Holder = ObjectHolder<Mixin>;
+ Persistent<Holder> holder(MakeGarbageCollected<Holder>());
+ IncrementalMarkingTestDriver driver(ThreadState::Current());
+ driver.Start();
+ MakeGarbageCollected<Parent>(
+ base::BindOnce(
+ [](IncrementalMarkingTestDriver* driver, Holder* holder,
+ Mixin* thiz) {
+ // Publish not-fully-constructed object
+ // |thiz| by triggering write barrier for
+ // the object.
+ holder->set_value(thiz);
+ // Finish call incremental steps.
+ driver->FinishSteps(BlinkGC::StackState::kHeapPointersOnStack);
+ },
+ &driver, holder.Get()),
+ MakeGarbageCollected<Object>());
+ driver.FinishGC();
+ CHECK(holder->value()->GetHeapObjectHeader()->IsValid());
+ CHECK(HeapObjectHeader::FromPayload(holder->value()->value())->IsValid());
+ PreciselyCollectGarbage();
+}
+
} // namespace incremental_marking_test
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc b/chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc
index d803593d36d..b95eb732fcc 100644
--- a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc
@@ -39,74 +39,58 @@ MarkingVisitor::MarkingVisitor(ThreadState* state, MarkingMode marking_mode)
MarkingVisitor::~MarkingVisitor() = default;
-void MarkingVisitor::ConservativelyMarkAddress(BasePage* page,
- Address address) {
-#if DCHECK_IS_ON()
- DCHECK(page->Contains(address));
-#endif
+void MarkingVisitor::DynamicallyMarkAddress(Address address) {
+ BasePage* const page = PageFromObject(address);
HeapObjectHeader* const header =
page->IsLargeObjectPage()
? static_cast<LargeObjectPage*>(page)->ObjectHeader()
: static_cast<NormalPage*>(page)->FindHeaderFromAddress(address);
- if (!header)
- return;
- ConservativelyMarkHeader(header);
+ DCHECK(header);
+ DCHECK(!header->IsInConstruction());
+ const GCInfo* gc_info =
+ GCInfoTable::Get().GCInfoFromIndex(header->GcInfoIndex());
+ MarkHeader(header, gc_info->trace_);
}
+void MarkingVisitor::ConservativelyMarkAddress(BasePage* page,
+ Address address) {
#if DCHECK_IS_ON()
-void MarkingVisitor::ConservativelyMarkAddress(
- BasePage* page,
- Address address,
- MarkedPointerCallbackForTesting callback) {
DCHECK(page->Contains(address));
+#endif
HeapObjectHeader* const header =
page->IsLargeObjectPage()
? static_cast<LargeObjectPage*>(page)->ObjectHeader()
: static_cast<NormalPage*>(page)->FindHeaderFromAddress(address);
- if (!header)
+ if (!header || header->IsMarked())
return;
- if (!callback(header))
- ConservativelyMarkHeader(header);
-}
-#endif // DCHECK_IS_ON
-
-namespace {
-
-#if DCHECK_IS_ON()
-bool IsUninitializedMemory(void* object_pointer, size_t object_size) {
- // Scan through the object's fields and check that they are all zero.
- Address* object_fields = reinterpret_cast<Address*>(object_pointer);
- for (size_t i = 0; i < object_size / sizeof(Address); ++i) {
- if (object_fields[i])
- return false;
- }
- return true;
-}
-#endif
-} // namespace
-
-void MarkingVisitor::ConservativelyMarkHeader(HeapObjectHeader* header) {
+ // Simple case for fully constructed objects.
const GCInfo* gc_info =
GCInfoTable::Get().GCInfoFromIndex(header->GcInfoIndex());
- if (gc_info->HasVTable() && !VTableInitialized(header->Payload())) {
- // We hit this branch when a GC strikes before GarbageCollected<>'s
- // constructor runs.
- //
- // class A : public GarbageCollected<A> { virtual void f() = 0; };
- // class B : public A {
- // B() : A(foo()) { };
- // };
- //
- // If foo() allocates something and triggers a GC, the vtable of A
- // has not yet been initialized. In this case, we should mark the A
- // object without tracing any member of the A object.
- MarkHeaderNoTracing(header);
-#if DCHECK_IS_ON()
- DCHECK(IsUninitializedMemory(header->Payload(), header->PayloadSize()));
-#endif
- } else {
+ if (!header->IsInConstruction()) {
MarkHeader(header, gc_info->trace_);
+ return;
+ }
+
+ // This case is reached for not-fully-constructed objects with vtables.
+ // We can differentiate multiple cases:
+ // 1. No vtable set up. Example:
+ // class A : public GarbageCollected<A> { virtual void f() = 0; };
+ // class B : public A { B() : A(foo()) {}; };
+ // The vtable for A is not set up if foo() allocates and triggers a GC.
+ //
+ // 2. Vtables properly set up (non-mixin case).
+ // 3. Vtables not properly set up (mixin) if GC is allowed during mixin
+ // construction.
+ //
+ // We use a simple conservative approach for these cases as they are not
+ // performance critical.
+ MarkHeaderNoTracing(header);
+ Address* payload = reinterpret_cast<Address*>(header->Payload());
+ const size_t payload_size = header->PayloadSize();
+ for (size_t i = 0; i < (payload_size / sizeof(Address)); ++i) {
+ if (payload[i])
+ Heap().CheckAndMarkPointer(this, payload[i]);
}
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/marking_visitor.h
index 8892d9cc23b..a53f0bf90a4 100644
--- a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/marking_visitor.h
@@ -51,13 +51,15 @@ class PLATFORM_EXPORT MarkingVisitor : public Visitor {
// Marking implementation.
- // Conservatively marks an object if pointed to by Address.
+ // Conservatively marks an object if pointed to by Address. The object may
+ // be in construction as the scan is conservative without relying on a
+ // Trace method.
void ConservativelyMarkAddress(BasePage*, Address);
-#if DCHECK_IS_ON()
- void ConservativelyMarkAddress(BasePage*,
- Address,
- MarkedPointerCallbackForTesting);
-#endif // DCHECK_IS_ON()
+
+ // Marks an object dynamically using any address within its body and adds a
+ // tracing callback for processing of the object. The object is not allowed
+ // to be in construction.
+ void DynamicallyMarkAddress(Address);
// Marks an object and adds a tracing callback for processing of the object.
inline void MarkHeader(HeapObjectHeader*, TraceCallback);
@@ -98,8 +100,11 @@ class PLATFORM_EXPORT MarkingVisitor : public Visitor {
// that lead to many recursions.
DCHECK(Heap().GetStackFrameDepth().IsAcceptableStackUse());
if (LIKELY(Heap().GetStackFrameDepth().IsSafeToRecurse())) {
- if (MarkHeaderNoTracing(
- HeapObjectHeader::FromPayload(desc.base_object_payload))) {
+ HeapObjectHeader* header =
+ HeapObjectHeader::FromPayload(desc.base_object_payload);
+ if (header->IsInConstruction()) {
+ not_fully_constructed_worklist_.Push(desc.base_object_payload);
+ } else if (MarkHeaderNoTracing(header)) {
desc.callback(this, desc.base_object_payload);
}
return;
@@ -117,6 +122,12 @@ class PLATFORM_EXPORT MarkingVisitor : public Visitor {
void** object_slot,
TraceDescriptor desc,
WeakCallback callback) final {
+ // Filter out already marked values. The write barrier for WeakMember
+ // ensures that any newly set value after this point is kept alive and does
+ // not require the callback.
+ if (desc.base_object_payload != BlinkGC::kNotFullyConstructedObject &&
+ HeapObjectHeader::FromPayload(desc.base_object_payload)->IsMarked())
+ return;
RegisterWeakCallback(object_slot, callback);
}
@@ -170,8 +181,6 @@ class PLATFORM_EXPORT MarkingVisitor : public Visitor {
void RegisterBackingStoreReference(void** slot);
- void ConservativelyMarkHeader(HeapObjectHeader*);
-
MarkingWorklist::View marking_worklist_;
NotFullyConstructedWorklist::View not_fully_constructed_worklist_;
WeakCallbackWorklist::View weak_callback_worklist_;
@@ -196,7 +205,9 @@ inline void MarkingVisitor::MarkHeader(HeapObjectHeader* header,
DCHECK(header);
DCHECK(callback);
- if (MarkHeaderNoTracing(header)) {
+ if (header->IsInConstruction()) {
+ not_fully_constructed_worklist_.Push(header->Payload());
+ } else if (MarkHeaderNoTracing(header)) {
marking_worklist_.Push(
{reinterpret_cast<void*>(header->Payload()), callback});
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/name_trait_test.cc b/chromium/third_party/blink/renderer/platform/heap/name_trait_test.cc
index 4e4a43bfb4a..fac0052bd2c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/name_trait_test.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/name_trait_test.cc
@@ -4,8 +4,8 @@
#include <string.h>
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-
#include "third_party/blink/renderer/platform/heap/name_traits.h"
namespace blink {
@@ -29,10 +29,20 @@ class ClassWithName : public NameClient {
} // namespace
+TEST(NameTraitTest, InternalNamesHiddenInOfficialBuild) {
+#if defined(OFFICIAL_BUILD)
+ EXPECT_TRUE(NameTrait<ClassWithoutName>::HideInternalName());
+#endif
+}
+
TEST(NameTraitTest, DefaultName) {
ClassWithoutName no_name;
const char* name = NameTrait<ClassWithoutName>::GetName(&no_name);
- EXPECT_EQ(0, strcmp(name, "InternalNode"));
+ if (NameTrait<ClassWithoutName>::HideInternalName()) {
+ EXPECT_EQ(0, strcmp(name, "InternalNode"));
+ } else {
+ EXPECT_NE(nullptr, strstr(name, "ClassWithoutName"));
+ }
}
TEST(NameTraitTest, CustomName) {
diff --git a/chromium/third_party/blink/renderer/platform/heap/name_traits.h b/chromium/third_party/blink/renderer/platform/heap/name_traits.h
index d1261815876..941fc88b3bc 100644
--- a/chromium/third_party/blink/renderer/platform/heap/name_traits.h
+++ b/chromium/third_party/blink/renderer/platform/heap/name_traits.h
@@ -5,8 +5,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
+#include "build/build_config.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
namespace blink {
@@ -15,6 +17,14 @@ class NameTrait {
STATIC_ONLY(NameTrait);
public:
+ static constexpr bool HideInternalName() {
+#if defined(OFFICIAL_BUILD) || !(defined(COMPILER_GCC) || defined(__clang__))
+ return true;
+#else
+ return false;
+#endif
+ }
+
static const char* GetName(const void* obj) {
return GetNameFor(static_cast<const T*>(obj));
}
@@ -24,7 +34,34 @@ class NameTrait {
return wrapper_tracable->NameInHeapSnapshot();
}
- static const char* GetNameFor(...) { return "InternalNode"; }
+ static const char* GetNameFor(...) {
+ // For non-official builds construct the name of a type from a compiler
+ // intrinsic.
+ //
+ // Do not include such type information in official builds to
+ // (a) safe binary size on string literals, and
+ // (b) avoid exposing internal types until a proper DevTools frontend
+ // implementation is present.
+#if defined(OFFICIAL_BUILD) || !(defined(COMPILER_GCC) || defined(__clang__))
+ return "InternalNode";
+#else
+ DCHECK(!HideInternalName());
+ static const char* leaky_class_name = nullptr;
+ if (leaky_class_name)
+ return leaky_class_name;
+
+ // Parsing string of structure:
+ // const char *WTF::GetStringWithTypeName<TYPE>() [T = TYPE]
+ // Note that this only works on clang or GCC builds.
+ const std::string raw(WTF::GetStringWithTypeName<T>());
+ const auto start_pos = raw.rfind("T = ") + 4;
+ DCHECK(std::string::npos != start_pos);
+ const auto len = raw.length() - start_pos - 1;
+ const std::string name = raw.substr(start_pos, len).c_str();
+ leaky_class_name = strcpy(new char[name.length() + 1], name.c_str());
+ return leaky_class_name;
+#endif
+ }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/page_memory.cc b/chromium/third_party/blink/renderer/platform/heap/page_memory.cc
index 2a4d3f2117d..cce3dc9202d 100644
--- a/chromium/third_party/blink/renderer/platform/heap/page_memory.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/page_memory.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/address_sanitizer.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/atomics.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent.h b/chromium/third_party/blink/renderer/platform/heap/persistent.h
index 52dc689d86f..69db982b4a6 100644
--- a/chromium/third_party/blink/renderer/platform/heap/persistent.h
+++ b/chromium/third_party/blink/renderer/platform/heap/persistent.h
@@ -13,7 +13,6 @@
#include "third_party/blink/renderer/platform/heap/persistent_node.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/atomics.h"
namespace blink {
@@ -26,11 +25,6 @@ namespace blink {
\
private:
-enum WeaknessPersistentConfiguration {
- kNonWeakPersistentConfiguration,
- kWeakPersistentConfiguration
-};
-
enum CrossThreadnessPersistentConfiguration {
kSingleThreadPersistentConfiguration,
kCrossThreadPersistentConfiguration
@@ -172,10 +166,9 @@ class PersistentBase {
// needing to be cleared out before the thread is terminated.
PersistentBase* RegisterAsStaticReference() {
CHECK_EQ(weaknessConfiguration, kNonWeakPersistentConfiguration);
- if (persistent_node_) {
+ if (PersistentNode* node = persistent_node_.Get()) {
DCHECK(ThreadState::Current());
- ThreadState::Current()->RegisterStaticPersistentNode(persistent_node_,
- nullptr);
+ ThreadState::Current()->RegisterStaticPersistentNode(node, nullptr);
LEAK_SANITIZER_IGNORE_OBJECT(this);
}
return this;
@@ -190,11 +183,7 @@ class PersistentBase {
ProcessHeap::CrossThreadPersistentMutex().AssertAcquired();
#endif
raw_ = nullptr;
- CrossThreadPersistentRegion& region =
- weaknessConfiguration == kWeakPersistentConfiguration
- ? ProcessHeap::GetCrossThreadWeakPersistentRegion()
- : ProcessHeap::GetCrossThreadPersistentRegion();
- region.FreePersistentNode(persistent_node_);
+ persistent_node_.ClearWithLockHeld();
}
private:
@@ -208,7 +197,7 @@ class PersistentBase {
}
CheckPointer();
if (raw_) {
- if (!persistent_node_)
+ if (!persistent_node_.IsInitialized())
Initialize();
return;
}
@@ -229,64 +218,17 @@ class PersistentBase {
NO_SANITIZE_ADDRESS
void Initialize() {
- DCHECK(!persistent_node_);
+ DCHECK(!persistent_node_.IsInitialized());
if (!raw_ || IsHashTableDeletedValue())
return;
TraceCallback trace_callback =
TraceMethodDelegate<PersistentBase,
&PersistentBase::TracePersistent>::Trampoline;
- if (crossThreadnessConfiguration == kCrossThreadPersistentConfiguration) {
- CrossThreadPersistentRegion& region =
- weaknessConfiguration == kWeakPersistentConfiguration
- ? ProcessHeap::GetCrossThreadWeakPersistentRegion()
- : ProcessHeap::GetCrossThreadPersistentRegion();
- MutexLocker lock(ProcessHeap::CrossThreadPersistentMutex());
- region.AllocatePersistentNode(persistent_node_, this, trace_callback);
- return;
- }
- ThreadState* state =
- ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
- DCHECK(state->CheckThread());
- PersistentRegion* region =
- weaknessConfiguration == kWeakPersistentConfiguration
- ? state->GetWeakPersistentRegion()
- : state->GetPersistentRegion();
- persistent_node_ = region->AllocatePersistentNode(this, trace_callback);
-#if DCHECK_IS_ON()
- state_ = state;
-#endif
+ persistent_node_.Initialize(this, trace_callback);
}
- void Uninitialize() {
- if (crossThreadnessConfiguration == kCrossThreadPersistentConfiguration) {
- if (AcquireLoad(reinterpret_cast<void* volatile*>(&persistent_node_))) {
- CrossThreadPersistentRegion& region =
- weaknessConfiguration == kWeakPersistentConfiguration
- ? ProcessHeap::GetCrossThreadWeakPersistentRegion()
- : ProcessHeap::GetCrossThreadPersistentRegion();
- MutexLocker lock(ProcessHeap::CrossThreadPersistentMutex());
- region.FreePersistentNode(persistent_node_);
- }
- return;
- }
-
- if (!persistent_node_)
- return;
- ThreadState* state =
- ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
- DCHECK(state->CheckThread());
- // Persistent handle must be created and destructed in the same thread.
-#if DCHECK_IS_ON()
- DCHECK_EQ(state_, state);
-#endif
- PersistentRegion* region =
- weaknessConfiguration == kWeakPersistentConfiguration
- ? state->GetWeakPersistentRegion()
- : state->GetPersistentRegion();
- state->FreePersistentNode(region, persistent_node_);
- persistent_node_ = nullptr;
- }
+ void Uninitialize() { persistent_node_.Uninitialize(); }
void CheckPointer() const {
#if DCHECK_IS_ON()
@@ -327,7 +269,7 @@ class PersistentBase {
weaknessConfiguration, crossThreadnessConfiguration>;
Base* persistent = reinterpret_cast<Base*>(persistent_pointer);
T* object = persistent->Get();
- if (object && !ObjectAliveTrait<T>::IsHeapObjectAlive(object))
+ if (object && !ThreadHeap::IsHeapObjectAlive(object))
ClearWeakPersistent(persistent);
}
@@ -353,11 +295,22 @@ class PersistentBase {
NOTREACHED();
}
- // m_raw is accessed most, so put it at the first field.
+ // raw_ is accessed most, so put it at the first field.
T* raw_;
- PersistentNode* persistent_node_ = nullptr;
+
+ // The pointer to the underlying persistent node.
+ //
+ // Since accesses are atomics in the cross-thread case, a different type is
+ // needed to prevent the compiler producing an error when it encounters
+ // operations that are legal on raw pointers but not on atomics, or
+ // vice-versa.
+ std::conditional_t<
+ crossThreadnessConfiguration == kCrossThreadPersistentConfiguration,
+ CrossThreadPersistentNodePtr<weaknessConfiguration>,
+ PersistentNodePtr<ThreadingTrait<T>::kAffinity, weaknessConfiguration>>
+ persistent_node_;
+
#if DCHECK_IS_ON()
- ThreadState* state_ = nullptr;
const ThreadState* creation_thread_state_;
#endif
};
diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent_node.h b/chromium/third_party/blink/renderer/platform/heap/persistent_node.h
index 596ce270b33..31c31cd6f66 100644
--- a/chromium/third_party/blink/renderer/platform/heap/persistent_node.h
+++ b/chromium/third_party/blink/renderer/platform/heap/persistent_node.h
@@ -5,18 +5,24 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_NODE_H_
+#include <atomic>
#include <memory>
#include "third_party/blink/renderer/platform/heap/process_heap.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/atomics.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace blink {
class CrossThreadPersistentRegion;
+class PersistentRegion;
+
+enum WeaknessPersistentConfiguration {
+ kNonWeakPersistentConfiguration,
+ kWeakPersistentConfiguration
+};
class PersistentNode final {
DISALLOW_NEW();
@@ -97,6 +103,52 @@ struct PersistentNodeSlots final {
friend class CrossThreadPersistentRegion;
};
+// Used by PersistentBase to manage a pointer to a thread heap persistent node.
+// This class mostly passes accesses through, but provides an interface
+// compatible with CrossThreadPersistentNodePtr.
+template <ThreadAffinity affinity,
+ WeaknessPersistentConfiguration weakness_configuration>
+class PersistentNodePtr {
+ public:
+ PersistentNode* Get() const { return ptr_; }
+ bool IsInitialized() const { return ptr_; }
+
+ void Initialize(void* owner, TraceCallback);
+ void Uninitialize();
+
+ private:
+ PersistentNode* ptr_ = nullptr;
+#if DCHECK_IS_ON()
+ ThreadState* state_ = nullptr;
+#endif
+};
+
+// Used by PersistentBase to manage a pointer to a cross-thread persistent node.
+// It uses ProcessHeap::CrossThreadPersistentMutex() to protect most accesses,
+// but can be polled to see whether it is initialized without the mutex.
+template <WeaknessPersistentConfiguration weakness_configuration>
+class CrossThreadPersistentNodePtr {
+ public:
+ PersistentNode* Get() const {
+#if DCHECK_IS_ON()
+ ProcessHeap::CrossThreadPersistentMutex().AssertAcquired();
+#endif
+ return ptr_.load(std::memory_order_relaxed);
+ }
+ bool IsInitialized() const { return ptr_.load(std::memory_order_acquire); }
+
+ void Initialize(void* owner, TraceCallback);
+ void Uninitialize();
+
+ void ClearWithLockHeld();
+
+ private:
+ // Access must either be protected by the cross-thread persistent mutex or
+ // handle the fact that this may be changed concurrently (with a
+ // release-store).
+ std::atomic<PersistentNode*> ptr_{nullptr};
+};
+
// PersistentRegion provides a region of PersistentNodes. PersistentRegion
// holds a linked list of PersistentNodeSlots, each of which stores
// a predefined number of PersistentNodes. You can call allocatePersistentNode/
@@ -171,18 +223,14 @@ class CrossThreadPersistentRegion final {
USING_FAST_MALLOC(CrossThreadPersistentRegion);
public:
- void AllocatePersistentNode(PersistentNode*& persistent_node,
- void* self,
- TraceCallback trace) {
+ PersistentNode* AllocatePersistentNode(void* self, TraceCallback trace) {
#if DCHECK_IS_ON()
ProcessHeap::CrossThreadPersistentMutex().AssertAcquired();
#endif
- PersistentNode* node =
- persistent_region_.AllocatePersistentNode(self, trace);
- ReleaseStore(reinterpret_cast<void* volatile*>(&persistent_node), node);
+ return persistent_region_.AllocatePersistentNode(self, trace);
}
- void FreePersistentNode(PersistentNode*& persistent_node) {
+ void FreePersistentNode(PersistentNode* node) {
#if DCHECK_IS_ON()
ProcessHeap::CrossThreadPersistentMutex().AssertAcquired();
#endif
@@ -196,10 +244,9 @@ class CrossThreadPersistentRegion final {
// The lock ensures the updating is ordered, but by the time lock has been
// acquired the PersistentNode reference may have been cleared out already;
// check for this.
- if (!persistent_node)
+ if (!node)
return;
- persistent_region_.FreePersistentNode(persistent_node);
- ReleaseStore(reinterpret_cast<void* volatile*>(&persistent_node), nullptr);
+ persistent_region_.FreePersistentNode(node);
}
void TracePersistentNodes(Visitor* visitor) {
@@ -228,6 +275,92 @@ class CrossThreadPersistentRegion final {
PersistentRegion persistent_region_;
};
+template <ThreadAffinity affinity,
+ WeaknessPersistentConfiguration weakness_configuration>
+void PersistentNodePtr<affinity, weakness_configuration>::Initialize(
+ void* owner,
+ TraceCallback trace_callback) {
+ ThreadState* state = ThreadStateFor<affinity>::GetState();
+ DCHECK(state->CheckThread());
+ PersistentRegion* region =
+ weakness_configuration == kWeakPersistentConfiguration
+ ? state->GetWeakPersistentRegion()
+ : state->GetPersistentRegion();
+ ptr_ = region->AllocatePersistentNode(owner, trace_callback);
+#if DCHECK_IS_ON()
+ state_ = state;
+#endif
+}
+
+template <ThreadAffinity affinity,
+ WeaknessPersistentConfiguration weakness_configuration>
+void PersistentNodePtr<affinity, weakness_configuration>::Uninitialize() {
+ if (!ptr_)
+ return;
+ ThreadState* state = ThreadStateFor<affinity>::GetState();
+ DCHECK(state->CheckThread());
+#if DCHECK_IS_ON()
+ DCHECK_EQ(state_, state)
+ << "must be initialized and uninitialized on the same thread";
+ state_ = nullptr;
+#endif
+ PersistentRegion* region =
+ weakness_configuration == kWeakPersistentConfiguration
+ ? state->GetWeakPersistentRegion()
+ : state->GetPersistentRegion();
+ state->FreePersistentNode(region, ptr_);
+ ptr_ = nullptr;
+}
+
+template <WeaknessPersistentConfiguration weakness_configuration>
+void CrossThreadPersistentNodePtr<weakness_configuration>::Initialize(
+ void* owner,
+ TraceCallback trace_callback) {
+ CrossThreadPersistentRegion& region =
+ weakness_configuration == kWeakPersistentConfiguration
+ ? ProcessHeap::GetCrossThreadWeakPersistentRegion()
+ : ProcessHeap::GetCrossThreadPersistentRegion();
+ MutexLocker lock(ProcessHeap::CrossThreadPersistentMutex());
+ PersistentNode* node = region.AllocatePersistentNode(owner, trace_callback);
+ ptr_.store(node, std::memory_order_release);
+}
+
+template <WeaknessPersistentConfiguration weakness_configuration>
+void CrossThreadPersistentNodePtr<weakness_configuration>::Uninitialize() {
+ // As an optimization, skip the mutex acquisition.
+ //
+ // Persistent handles are often assigned or destroyed while being
+ // uninitialized.
+ //
+ // Calling code is still expected to synchronize mutations to persistent
+ // handles, so if this thread can see the node pointer as having been
+ // cleared and the program does not have a data race, then this pointer would
+ // still have been blank after waiting for the cross-thread persistent mutex.
+ if (!ptr_.load(std::memory_order_acquire))
+ return;
+
+ CrossThreadPersistentRegion& region =
+ weakness_configuration == kWeakPersistentConfiguration
+ ? ProcessHeap::GetCrossThreadWeakPersistentRegion()
+ : ProcessHeap::GetCrossThreadPersistentRegion();
+ MutexLocker lock(ProcessHeap::CrossThreadPersistentMutex());
+ region.FreePersistentNode(ptr_.load(std::memory_order_relaxed));
+ ptr_.store(nullptr, std::memory_order_release);
+}
+
+template <WeaknessPersistentConfiguration weakness_configuration>
+void CrossThreadPersistentNodePtr<weakness_configuration>::ClearWithLockHeld() {
+#if DCHECK_IS_ON()
+ ProcessHeap::CrossThreadPersistentMutex().AssertAcquired();
+#endif
+ CrossThreadPersistentRegion& region =
+ weakness_configuration == kWeakPersistentConfiguration
+ ? ProcessHeap::GetCrossThreadWeakPersistentRegion()
+ : ProcessHeap::GetCrossThreadPersistentRegion();
+ region.FreePersistentNode(ptr_.load(std::memory_order_relaxed));
+ ptr_.store(nullptr, std::memory_order_release);
+}
+
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent_test.cc b/chromium/third_party/blink/renderer/platform/heap/persistent_test.cc
index fad42771309..11d0dd51e57 100644
--- a/chromium/third_party/blink/renderer/platform/heap/persistent_test.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/persistent_test.cc
@@ -22,7 +22,7 @@ class Receiver : public GarbageCollected<Receiver> {
};
TEST(PersistentTest, BindCancellation) {
- Receiver* receiver = new Receiver;
+ Receiver* receiver = MakeGarbageCollected<Receiver>();
int counter = 0;
base::RepeatingClosure function =
WTF::BindRepeating(&Receiver::Increment, WrapWeakPersistent(receiver),
@@ -38,7 +38,7 @@ TEST(PersistentTest, BindCancellation) {
}
TEST(PersistentTest, CrossThreadBindCancellation) {
- Receiver* receiver = new Receiver;
+ Receiver* receiver = MakeGarbageCollected<Receiver>();
int counter = 0;
CrossThreadClosure function = blink::CrossThreadBind(
&Receiver::Increment, WrapCrossThreadWeakPersistent(receiver),
diff --git a/chromium/third_party/blink/renderer/platform/heap/run_all_tests.cc b/chromium/third_party/blink/renderer/platform/heap/run_all_tests.cc
index d8ee785ad2d..ea68f22d0c2 100644
--- a/chromium/third_party/blink/renderer/platform/heap/run_all_tests.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/run_all_tests.cc
@@ -35,24 +35,29 @@
#include "content/public/test/blink_test_environment.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
-class BlinkTestEnvironmentScope {
+class BlinkTestSuite : public base::TestSuite {
public:
- BlinkTestEnvironmentScope() { content::SetUpBlinkTestEnvironment(); }
- ~BlinkTestEnvironmentScope() { content::TearDownBlinkTestEnvironment(); }
-};
+ BlinkTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {}
-int runHelper(base::TestSuite* testSuite) {
- BlinkTestEnvironmentScope blinkTestEnvironment;
- blink::ThreadState* currentThreadState = blink::ThreadState::Current();
- currentThreadState->RegisterTraceDOMWrappers(nullptr, nullptr, nullptr,
- nullptr);
- int result = testSuite->Run();
- currentThreadState->CollectAllGarbage();
- return result;
-}
+ private:
+ void Initialize() override {
+ base::TestSuite::Initialize();
+ content::SetUpBlinkTestEnvironment();
+ blink::ThreadState::Current()->RegisterTraceDOMWrappers(nullptr, nullptr,
+ nullptr, nullptr);
+ }
+ void Shutdown() override {
+ blink::ThreadState::Current()->CollectAllGarbage();
+ content::TearDownBlinkTestEnvironment();
+ base::TestSuite::Shutdown();
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(BlinkTestSuite);
+};
int main(int argc, char** argv) {
- base::TestSuite testSuite(argc, argv);
+ BlinkTestSuite testSuite(argc, argv);
return base::LaunchUnitTests(
- argc, argv, base::BindOnce(runHelper, base::Unretained(&testSuite)));
+ argc, argv,
+ base::BindOnce(&base::TestSuite::Run, base::Unretained(&testSuite)));
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state.cc b/chromium/third_party/blink/renderer/platform/heap/thread_state.cc
index 198af3f0761..a35433abd8c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/thread_state.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -177,7 +177,6 @@ ThreadState::ThreadState()
mixins_being_constructed_count_(0),
object_resurrection_forbidden_(false),
in_atomic_pause_(false),
- gc_mixin_marker_(nullptr),
gc_state_(kNoGCScheduled),
gc_phase_(GCPhase::kNone),
reason_for_scheduled_gc_(BlinkGC::GCReason::kMaxValue),
@@ -511,9 +510,14 @@ void ThreadState::ScheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gc_type) {
if (IsGCForbidden())
return;
- // This completeSweep() will do nothing in common cases since we've
- // called completeSweep() before V8 starts minor/major GCs.
if (gc_type == BlinkGC::kV8MajorGC) {
+ // In case of unified heap garbage collections a V8 major GC also collects
+ // the Blink heap.
+ if (RuntimeEnabledFeatures::HeapUnifiedGarbageCollectionEnabled())
+ return;
+
+ // This CompleteSweep() will do nothing in common cases since we've
+ // called CompleteSweep() before V8 starts minor/major GCs.
// TODO(ulan): Try removing this for Major V8 GC too.
CompleteSweep();
DCHECK(!IsSweepingInProgress());
@@ -535,13 +539,10 @@ void ThreadState::ScheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gc_type) {
<< "ScheduleV8FollowupGCIfNeeded: Scheduled precise GC";
SchedulePreciseGC();
}
- return;
- }
- if (gc_type == BlinkGC::kV8MajorGC && ShouldScheduleIdleGC()) {
+ } else if (gc_type == BlinkGC::kV8MajorGC && ShouldScheduleIdleGC()) {
VLOG(2) << "[state:" << this << "] "
<< "ScheduleV8FollowupGCIfNeeded: Scheduled idle GC";
ScheduleIdleGC();
- return;
}
}
@@ -930,7 +931,7 @@ void ThreadState::RunScheduledGC(BlinkGC::StackState stack_state) {
// Idle time GC will be scheduled by Blink Scheduler.
break;
case kIncrementalMarkingStepScheduled:
- IncrementalMarkingStep();
+ IncrementalMarkingStep(stack_state);
break;
case kIncrementalMarkingFinalizeScheduled:
IncrementalMarkingFinalize();
@@ -1400,32 +1401,32 @@ void ThreadState::InvokePreFinalizers() {
}
// static
-base::subtle::AtomicWord ThreadState::incremental_marking_counter_ = 0;
+AtomicEntryFlag ThreadState::incremental_marking_flag_;
// static
-base::subtle::AtomicWord ThreadState::wrapper_tracing_counter_ = 0;
+AtomicEntryFlag ThreadState::wrapper_tracing_flag_;
void ThreadState::EnableIncrementalMarkingBarrier() {
CHECK(!IsIncrementalMarking());
- base::subtle::Barrier_AtomicIncrement(&incremental_marking_counter_, 1);
+ incremental_marking_flag_.Enter();
SetIncrementalMarking(true);
}
void ThreadState::DisableIncrementalMarkingBarrier() {
CHECK(IsIncrementalMarking());
- base::subtle::Barrier_AtomicIncrement(&incremental_marking_counter_, -1);
+ incremental_marking_flag_.Exit();
SetIncrementalMarking(false);
}
void ThreadState::EnableWrapperTracingBarrier() {
CHECK(!IsWrapperTracing());
- base::subtle::Barrier_AtomicIncrement(&wrapper_tracing_counter_, 1);
+ wrapper_tracing_flag_.Enter();
SetWrapperTracing(true);
}
void ThreadState::DisableWrapperTracingBarrier() {
CHECK(IsWrapperTracing());
- base::subtle::Barrier_AtomicIncrement(&wrapper_tracing_counter_, -1);
+ wrapper_tracing_flag_.Exit();
SetWrapperTracing(false);
}
@@ -1453,7 +1454,7 @@ void ThreadState::IncrementalMarkingStart(BlinkGC::GCReason reason) {
}
}
-void ThreadState::IncrementalMarkingStep() {
+void ThreadState::IncrementalMarkingStep(BlinkGC::StackState stack_state) {
DCHECK(IsMarkingInProgress());
ThreadHeapStatsCollector::EnabledScope stats_scope(
@@ -1463,6 +1464,9 @@ void ThreadState::IncrementalMarkingStep() {
<< "IncrementalMarking: Step "
<< "Reason: " << GcReasonString(current_gc_data_.reason);
AtomicPauseScope atomic_pause_scope(this);
+ if (stack_state == BlinkGC::kNoHeapPointersOnStack) {
+ Heap().FlushNotFullyConstructedObjects();
+ }
const bool complete = MarkPhaseAdvanceMarking(
CurrentTimeTicks() + next_incremental_marking_step_duration_);
if (complete) {
@@ -1695,6 +1699,11 @@ void ThreadState::MarkPhasePrologue(BlinkGC::StackState stack_state,
void ThreadState::AtomicPausePrologue(BlinkGC::StackState stack_state,
BlinkGC::MarkingType marking_type,
BlinkGC::GCReason reason) {
+ // Compaction needs to be canceled when incremental marking ends with a
+ // conservative GC.
+ if (stack_state == BlinkGC::kHeapPointersOnStack)
+ Heap().Compaction()->CancelCompaction();
+
if (IsMarkingInProgress()) {
// Incremental marking is already in progress. Only update the state
// that is necessary to update.
@@ -1713,6 +1722,10 @@ void ThreadState::AtomicPausePrologue(BlinkGC::StackState stack_state,
if (isolate_ && perform_cleanup_)
perform_cleanup_(isolate_);
+ if (stack_state == BlinkGC::kNoHeapPointersOnStack) {
+ Heap().FlushNotFullyConstructedObjects();
+ }
+
DCHECK(InAtomicMarkingPause());
Heap().MakeConsistentForGC();
Heap().ClearArenaAges();
diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/thread_state.h
index d04c2b07051..00282d672c4 100644
--- a/chromium/third_party/blink/renderer/platform/heap/thread_state.h
+++ b/chromium/third_party/blink/renderer/platform/heap/thread_state.h
@@ -33,10 +33,10 @@
#include <memory>
-#include "base/atomicops.h"
#include "base/macros.h"
#include "third_party/blink/public/platform/scheduler/web_rail_mode_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/heap/atomic_entry_flag.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
#include "third_party/blink/renderer/platform/heap/threading_traits.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -62,7 +62,6 @@ class IncrementalMarkingScope;
class IncrementalMarkingTestDriver;
} // namespace incremental_marking_test
-class GarbageCollectedMixinConstructorMarkerBase;
class MarkingVisitor;
class PersistentNode;
class PersistentRegion;
@@ -219,19 +218,23 @@ class PLATFORM_EXPORT ThreadState final
ThreadState* state_;
};
- // Returns true if any thread is currently incremental marking its heap and
- // false otherwise. For an exact check use
- // ThreadState::IsIncrementalMarking().
+ // Returns true if some thread (possibly the current thread) may be doing
+ // incremental marking. If false is returned, the *current* thread is
+ // definitely not doing incremental marking. See atomic_entry_flag.h for
+ // details.
+ //
+ // For an exact check, use ThreadState::IsIncrementalMarking.
ALWAYS_INLINE static bool IsAnyIncrementalMarking() {
- // Stores use full barrier to allow using the simplest relaxed load here.
- return base::subtle::NoBarrier_Load(&incremental_marking_counter_) > 0;
+ return incremental_marking_flag_.MightBeEntered();
}
- // Returns true if any thread is currently incremental marking its heap and
- // false otherwise. For an exact check use ThreadState::IsWrapperTracing().
+ // Returns true if some thread (possibly the current thread) may be doing
+ // wrapper tracing. If false is returned, the *current* thread is definitely
+ // not doing wrapper tracing. See atomic_entry_flag.h for details.
+ //
+ // For an exact check, use ThreadState::IsWrapperTracing.
static bool IsAnyWrapperTracing() {
- // Stores use full barrier to allow using the simplest relaxed load here.
- return base::subtle::NoBarrier_Load(&wrapper_tracing_counter_) > 0;
+ return wrapper_tracing_flag_.MightBeEntered();
}
static void AttachMainThread();
@@ -300,7 +303,7 @@ class PLATFORM_EXPORT ThreadState final
void ScheduleIncrementalMarkingFinalize();
void IncrementalMarkingStart(BlinkGC::GCReason);
- void IncrementalMarkingStep();
+ void IncrementalMarkingStep(BlinkGC::StackState);
void IncrementalMarkingFinalize();
bool FinishIncrementalMarkingIfRunning(BlinkGC::StackState,
BlinkGC::MarkingType,
@@ -476,29 +479,6 @@ class PLATFORM_EXPORT ThreadState final
perform_cleanup_ = perform_cleanup;
}
- // By entering a gc-forbidden scope, conservative GCs will not
- // be allowed while handling an out-of-line allocation request.
- // Intended used when constructing subclasses of GC mixins, where
- // the object being constructed cannot be safely traced & marked
- // fully should a GC be allowed while its subclasses are being
- // constructed.
- void EnterGCForbiddenScopeIfNeeded(
- GarbageCollectedMixinConstructorMarkerBase* gc_mixin_marker) {
- DCHECK(CheckThread());
- if (!gc_mixin_marker_) {
- EnterMixinConstructionScope();
- gc_mixin_marker_ = gc_mixin_marker;
- }
- }
- void LeaveGCForbiddenScopeIfNeeded(
- GarbageCollectedMixinConstructorMarkerBase* gc_mixin_marker) {
- DCHECK(CheckThread());
- if (gc_mixin_marker_ == gc_mixin_marker) {
- LeaveMixinConstructionScope();
- gc_mixin_marker_ = nullptr;
- }
- }
-
void FreePersistentNode(PersistentRegion*, PersistentNode*);
using PersistentClearCallback = void (*)(void*);
@@ -569,13 +549,11 @@ class PLATFORM_EXPORT ThreadState final
}
private:
- // Number of ThreadState's that are currently in incremental marking. The
- // counter is incremented by one when some ThreadState enters incremental
- // marking and decremented upon finishing.
- static base::subtle::AtomicWord incremental_marking_counter_;
+ // Stores whether some ThreadState is currently in incremental marking.
+ static AtomicEntryFlag incremental_marking_flag_;
- // Same semantic as |incremental_marking_counter_|.
- static base::subtle::AtomicWord wrapper_tracing_counter_;
+ // Same semantic as |incremental_marking_flag_|.
+ static AtomicEntryFlag wrapper_tracing_flag_;
ThreadState();
~ThreadState() override;
@@ -705,8 +683,6 @@ class PLATFORM_EXPORT ThreadState final
TimeDelta next_incremental_marking_step_duration_;
TimeDelta previous_incremental_marking_time_left_;
- GarbageCollectedMixinConstructorMarkerBase* gc_mixin_marker_;
-
GCState gc_state_;
GCPhase gc_phase_;
BlinkGC::GCReason reason_for_scheduled_gc_;
diff --git a/chromium/third_party/blink/renderer/platform/heap/worklist.h b/chromium/third_party/blink/renderer/platform/heap/worklist.h
index c5d96b22fed..fb5c5dd83b5 100644
--- a/chromium/third_party/blink/renderer/platform/heap/worklist.h
+++ b/chromium/third_party/blink/renderer/platform/heap/worklist.h
@@ -30,12 +30,14 @@ namespace blink {
//
// Work stealing is best effort, i.e., there is no way to inform other tasks
// of the need of items.
-template <typename EntryType, int segment_size, int max_tasks = 1>
+template <typename _EntryType, int segment_size, int max_tasks = 1>
class Worklist {
USING_FAST_MALLOC(Worklist);
- using WorklistType = Worklist<EntryType, segment_size, max_tasks>;
+ using WorklistType = Worklist<_EntryType, segment_size, max_tasks>;
public:
+ using EntryType = _EntryType;
+
class View {
public:
View(WorklistType* worklist, int task_id)
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index b9ad319e989..6133e01995c 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -21,6 +21,8 @@
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include <memory>
+
+#include "base/numerics/safe_conversions.h"
#include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
#include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
#include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
@@ -193,20 +195,16 @@ size_t ImageDecoder::FrameBytesAtIndex(size_t index) const {
frame_buffer_cache_[index].GetStatus() == ImageFrame::kFrameEmpty)
return 0;
- struct ImageSize {
- explicit ImageSize(IntSize size) {
- area = static_cast<uint64_t>(size.Width()) * size.Height();
- }
-
- uint64_t area;
- };
-
size_t decoded_bytes_per_pixel = k4BytesPerPixel;
if (frame_buffer_cache_[index].GetPixelFormat() ==
ImageFrame::PixelFormat::kRGBA_F16) {
decoded_bytes_per_pixel = k8BytesPerPixel;
}
- return ImageSize(FrameSizeAtIndex(index)).area * decoded_bytes_per_pixel;
+ IntSize size = FrameSizeAtIndex(index);
+ base::CheckedNumeric<size_t> area = size.Width();
+ area *= size.Height();
+ area *= decoded_bytes_per_pixel;
+ return area.ValueOrDie();
}
size_t ImageDecoder::ClearCacheExceptFrame(size_t clear_except_frame) {
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
index b6c6aaeb43b..d82c820df50 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -920,9 +920,16 @@ bool JPEGImageDecoder::ShouldGenerateAllSizes() const {
}
bool JPEGImageDecoder::CanDecodeToYUV() {
+ // TODO(crbug.com/919627): Re-enable the code below once JPEG YUV decoding is
+ // finished.
+ // Returning false here is a bit deceptive because the JPEG decoder does
+ // support YUV. But the rest of the infrastructure at levels above the decoder
+ // is not quite there yet to handle the resulting JPEG YUV data,
+ // so for now we disable that path.
+ return false;
// Calling IsSizeAvailable() ensures the reader is created and the output
// color space is set.
- return IsSizeAvailable() && reader_->Info()->out_color_space == JCS_YCbCr;
+ // return IsSizeAvailable() && reader_->Info()->out_color_space == JCS_YCbCr;
}
bool JPEGImageDecoder::DecodeToYUV() {
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc
index 45f2b954174..3f8d7e09bad 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc
@@ -39,6 +39,8 @@
#include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
#include <memory>
+
+#include "base/numerics/checked_math.h"
#include "third_party/skia/third_party/skcms/skcms.h"
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
@@ -528,10 +530,15 @@ void PNGImageDecoder::RowAvailable(unsigned char* row_buffer,
if (PNG_INTERLACE_ADAM7 ==
png_get_interlace_type(png, reader_->InfoPtr())) {
unsigned color_channels = has_alpha_channel_ ? 4 : 3;
- unsigned interlace_buffer_size = color_channels * Size().Area();
+ base::CheckedNumeric<int> interlace_buffer_size = color_channels;
+ interlace_buffer_size *= Size().Area();
if (decode_to_half_float_)
interlace_buffer_size *= 2;
- reader_->CreateInterlaceBuffer(interlace_buffer_size);
+ if (!interlace_buffer_size.IsValid()) {
+ longjmp(JMPBUF(png), 1);
+ return;
+ }
+ reader_->CreateInterlaceBuffer(interlace_buffer_size.ValueOrDie());
if (!reader_->InterlaceBuffer()) {
longjmp(JMPBUF(png), 1);
return;
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
index f95c8efdcc0..7c402fb54f1 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h"
#include <memory>
+
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_size.h"
@@ -127,7 +129,7 @@ TEST(AnimatedWebPTests, verifyAnimationParametersTransparentImage) {
true},
};
- for (size_t i = 0; i < arraysize(kFrameParameters); ++i) {
+ for (size_t i = 0; i < base::size(kFrameParameters); ++i) {
const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
EXPECT_EQ(kCanvasWidth, frame->Bitmap().width());
@@ -143,7 +145,7 @@ TEST(AnimatedWebPTests, verifyAnimationParametersTransparentImage) {
EXPECT_EQ(kFrameParameters[i].has_alpha, frame->HasAlpha());
}
- EXPECT_EQ(arraysize(kFrameParameters), decoder->FrameCount());
+ EXPECT_EQ(base::size(kFrameParameters), decoder->FrameCount());
EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
}
@@ -174,7 +176,7 @@ TEST(AnimatedWebPTests,
true},
};
- for (size_t i = 0; i < arraysize(kFrameParameters); ++i) {
+ for (size_t i = 0; i < base::size(kFrameParameters); ++i) {
const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
EXPECT_EQ(kCanvasWidth, frame->Bitmap().width());
@@ -190,7 +192,7 @@ TEST(AnimatedWebPTests,
EXPECT_EQ(kFrameParameters[i].has_alpha, frame->HasAlpha());
}
- EXPECT_EQ(arraysize(kFrameParameters), decoder->FrameCount());
+ EXPECT_EQ(base::size(kFrameParameters), decoder->FrameCount());
EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
}
@@ -216,7 +218,7 @@ TEST(AnimatedWebPTests, verifyAnimationParametersBlendOverwrite) {
ImageFrame::kBlendAtopBgcolor, TimeDelta::FromMilliseconds(1000), true},
};
- for (size_t i = 0; i < arraysize(kFrameParameters); ++i) {
+ for (size_t i = 0; i < base::size(kFrameParameters); ++i) {
const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
EXPECT_EQ(kCanvasWidth, frame->Bitmap().width());
@@ -232,7 +234,7 @@ TEST(AnimatedWebPTests, verifyAnimationParametersBlendOverwrite) {
EXPECT_EQ(kFrameParameters[i].has_alpha, frame->HasAlpha());
}
- EXPECT_EQ(arraysize(kFrameParameters), decoder->FrameCount());
+ EXPECT_EQ(base::size(kFrameParameters), decoder->FrameCount());
EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
}
diff --git a/chromium/third_party/blink/renderer/platform/image-encoders/image_encoder.h b/chromium/third_party/blink/renderer/platform/image-encoders/image_encoder.h
index 4cb32b170b6..a4a4f195380 100644
--- a/chromium/third_party/blink/renderer/platform/image-encoders/image_encoder.h
+++ b/chromium/third_party/blink/renderer/platform/image-encoders/image_encoder.h
@@ -23,7 +23,8 @@ class VectorWStream : public SkWStream {
}
bool write(const void* buffer, size_t size) override {
- dst_->Append((const unsigned char*)buffer, size);
+ DCHECK_LE(size, std::numeric_limits<wtf_size_t>::max());
+ dst_->Append((const unsigned char*)buffer, static_cast<wtf_size_t>(size));
return true;
}
diff --git a/chromium/third_party/blink/renderer/platform/instance_counters.cc b/chromium/third_party/blink/renderer/platform/instance_counters.cc
index 64734a7dff8..36251b56bbb 100644
--- a/chromium/third_party/blink/renderer/platform/instance_counters.cc
+++ b/chromium/third_party/blink/renderer/platform/instance_counters.cc
@@ -32,10 +32,14 @@
namespace blink {
-int InstanceCounters::counters_[kCounterTypeLength];
+// static
+std::atomic_int InstanceCounters::counters_[kCounterTypeLength];
+
+// static
+int InstanceCounters::node_counter_ = 0;
int InstanceCounters::CounterValue(CounterType type) {
- return AcquireLoad(&counters_[type]);
+ return counters_[type].load(std::memory_order_relaxed);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/instance_counters.h b/chromium/third_party/blink/renderer/platform/instance_counters.h
index b8384c5a304..f0dc08fa1bf 100644
--- a/chromium/third_party/blink/renderer/platform/instance_counters.h
+++ b/chromium/third_party/blink/renderer/platform/instance_counters.h
@@ -31,9 +31,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTANCE_COUNTERS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTANCE_COUNTERS_H_
+#include <atomic>
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/atomics.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
namespace blink {
@@ -58,6 +58,13 @@ namespace blink {
V(AdSubframe) \
V(DetachedScriptState)
+// Atomic counters of the number of instances of objects that exist.
+//
+// Note that while these operations are atomic, they do not imply that other
+// changes to memory are visible to the accessing thread. As a result, this
+// is primarily useful where either other synchronization exists (e.g. the
+// objects are only used on one thread), or an inconsistent answer is
+// acceptable.
class InstanceCounters {
STATIC_ONLY(InstanceCounters);
@@ -76,7 +83,7 @@ class InstanceCounters {
DCHECK(IsMainThread());
++counters_[kNodeCounter];
} else {
- AtomicIncrement(&counters_[type]);
+ counters_[type].fetch_add(1, std::memory_order_relaxed);
}
}
@@ -85,14 +92,15 @@ class InstanceCounters {
DCHECK(IsMainThread());
--counters_[kNodeCounter];
} else {
- AtomicDecrement(&counters_[type]);
+ counters_[type].fetch_sub(1, std::memory_order_relaxed);
}
}
PLATFORM_EXPORT static int CounterValue(CounterType);
private:
- PLATFORM_EXPORT static int counters_[];
+ PLATFORM_EXPORT static std::atomic_int counters_[];
+ PLATFORM_EXPORT static int node_counter_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc
index aa33be3abd4..1b5b1d39645 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc
@@ -9,6 +9,13 @@
namespace blink {
+namespace {
+
+using resource_coordinator::mojom::InterventionPolicy;
+using resource_coordinator::mojom::PolicyControlledIntervention;
+
+} // namespace
+
// static
std::unique_ptr<FrameResourceCoordinator> FrameResourceCoordinator::Create(
service_manager::InterfaceProvider* interface_provider) {
@@ -37,6 +44,12 @@ void FrameResourceCoordinator::SetHasNonEmptyBeforeUnload(
service_->SetHasNonEmptyBeforeUnload(has_nonempty_beforeunload);
}
+void FrameResourceCoordinator::SetInterventionPolicy(
+ PolicyControlledIntervention intervention,
+ InterventionPolicy policy) {
+ service_->SetInterventionPolicy(intervention, policy);
+}
+
void FrameResourceCoordinator::OnNonPersistentNotificationCreated() {
service_->OnNonPersistentNotificationCreated();
}
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h
index 483cf4f4633..819625c417b 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h
@@ -26,6 +26,9 @@ class PLATFORM_EXPORT FrameResourceCoordinator final {
void SetNetworkAlmostIdle(bool);
void SetLifecycleState(resource_coordinator::mojom::LifecycleState);
void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload);
+ void SetInterventionPolicy(
+ resource_coordinator::mojom::PolicyControlledIntervention intervention,
+ resource_coordinator::mojom::InterventionPolicy policy);
void OnNonPersistentNotificationCreated();
private:
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h b/chromium/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
index 97e1475fa58..5d8d61d3cd9 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
@@ -11,19 +11,14 @@
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-namespace WTF {
-
-// CString version of SetTraceValue so that trace arguments can be strings.
-static inline void SetTraceValue(const CString& arg,
- unsigned char* type,
- unsigned long long* value) {
- trace_event_internal::TraceValueUnion type_value;
- type_value.as_string = arg.data();
- *type = TRACE_VALUE_TYPE_COPY_STRING;
- *value = type_value.as_uint;
-}
-
-} // namespace WTF
+// Conversion from CString to TraceValue so that trace arguments can be strings.
+template <>
+struct base::trace_event::TraceValue::Helper<WTF::CString> {
+ static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
+ static inline void SetValue(TraceValue* v, const WTF::CString& value) {
+ v->as_string = value.data();
+ }
+};
namespace blink {
namespace trace_event {
diff --git a/chromium/third_party/blink/renderer/platform/lifecycle_context_test.cc b/chromium/third_party/blink/renderer/platform/lifecycle_context_test.cc
index fa3b3316653..d537ebedfef 100644
--- a/chromium/third_party/blink/renderer/platform/lifecycle_context_test.cc
+++ b/chromium/third_party/blink/renderer/platform/lifecycle_context_test.cc
@@ -159,7 +159,7 @@ TEST(LifecycleContextTest, ShouldNotHitCFICheckOnIncrementalMarking) {
while (thread_state->GetGCState() ==
ThreadState::kIncrementalMarkingStepScheduled)
- thread_state->IncrementalMarkingStep();
+ thread_state->IncrementalMarkingStep(BlinkGC::kNoHeapPointersOnStack);
thread_state->IncrementalMarkingFinalize();
RuntimeEnabledFeatures::SetHeapIncrementalMarkingEnabled(was_enabled);
diff --git a/chromium/third_party/blink/renderer/platform/loader/BUILD.gn b/chromium/third_party/blink/renderer/platform/loader/BUILD.gn
index 6f44d60d89e..28155342571 100644
--- a/chromium/third_party/blink/renderer/platform/loader/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/loader/BUILD.gn
@@ -14,6 +14,8 @@ make_names("make_platform_loader_generated_fetch_initiator_type_names") {
blink_platform_sources("loader") {
sources = [
+ "allowed_by_nosniff.cc",
+ "allowed_by_nosniff.h",
"cors/cors.cc",
"cors/cors.h",
"cors/cors_error_string.cc",
@@ -22,9 +24,11 @@ blink_platform_sources("loader") {
"fetch/buffering_data_pipe_writer.h",
"fetch/cached_metadata.cc",
"fetch/cached_metadata.h",
+ "fetch/cached_metadata_handler.cc",
"fetch/cached_metadata_handler.h",
"fetch/client_hints_preferences.cc",
"fetch/client_hints_preferences.h",
+ "fetch/console_logger.h",
"fetch/fetch_client_settings_object.h",
"fetch/fetch_client_settings_object_snapshot.cc",
"fetch/fetch_client_settings_object_snapshot.h",
@@ -41,6 +45,8 @@ blink_platform_sources("loader") {
"fetch/integrity_metadata.h",
"fetch/memory_cache.cc",
"fetch/memory_cache.h",
+ "fetch/null_resource_fetcher_properties.cc",
+ "fetch/null_resource_fetcher_properties.h",
"fetch/preload_key.h",
"fetch/raw_resource.cc",
"fetch/raw_resource.h",
@@ -53,6 +59,7 @@ blink_platform_sources("loader") {
"fetch/resource_error.h",
"fetch/resource_fetcher.cc",
"fetch/resource_fetcher.h",
+ "fetch/resource_fetcher_properties.h",
"fetch/resource_finish_observer.h",
"fetch/resource_load_info.h",
"fetch/resource_load_priority.h",
@@ -85,9 +92,13 @@ blink_platform_sources("loader") {
"fetch/text_resource_decoder_options.h",
"fetch/unique_identifier.cc",
"fetch/unique_identifier.h",
+ "ftp_directory_listing.cc",
+ "ftp_directory_listing.h",
"link_header.cc",
"link_header.h",
"mixed_content_autoupgrade_status.h",
+ "static_data_navigation_body_loader.cc",
+ "static_data_navigation_body_loader.h",
"subresource_integrity.cc",
"subresource_integrity.h",
]
@@ -125,7 +136,9 @@ jumbo_source_set("unit_tests") {
"fetch/resource_response_test.cc",
"fetch/resource_test.cc",
"fetch/source_keyed_cached_metadata_handler_test.cc",
+ "ftp_directory_listing_test.cc",
"link_header_test.cc",
+ "static_data_navigation_body_loader_test.cc",
"subresource_integrity_test.cc",
]
@@ -154,6 +167,8 @@ jumbo_source_set("test_support") {
"testing/mock_resource.cc",
"testing/mock_resource.h",
"testing/mock_resource_client.h",
+ "testing/test_resource_fetcher_properties.cc",
+ "testing/test_resource_fetcher_properties.h",
"testing/web_url_loader_factory_with_mock.cc",
"testing/web_url_loader_factory_with_mock.h",
]
diff --git a/chromium/third_party/blink/renderer/platform/loader/DEPS b/chromium/third_party/blink/renderer/platform/loader/DEPS
index edcb279fdff..1620cfa98f5 100644
--- a/chromium/third_party/blink/renderer/platform/loader/DEPS
+++ b/chromium/third_party/blink/renderer/platform/loader/DEPS
@@ -44,5 +44,21 @@ include_rules = [
specific_include_rules = {
"resource_error\.cc": [
"+net/base/net_errors.h"
+ ],
+ "ftp_directory_listing.cc": [
+ "+base/i18n/encoding_detection.h",
+ "+base/i18n/icu_string_conversions.h",
+ "+base/strings/string_util.h",
+ "+base/strings/sys_string_conversions.h",
+ "+base/strings/utf_string_conversions.h",
+ "+net/base/directory_listing.h",
+ "+net/base/escape.h",
+ "+net/base/net_errors.h",
+ "+net/ftp/ftp_directory_listing_parser.h",
+ "+net/net_buildflags.h",
+ ],
+ "ftp_directory_listing_test.cc": [
+ "+net/net_buildflags.h",
+ "+third_party/icu/source/i18n/unicode/timezone.h"
]
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/OWNERS b/chromium/third_party/blink/renderer/platform/loader/OWNERS
index 0e5b601a377..1c34e1edc6a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/loader/OWNERS
@@ -3,7 +3,7 @@ japhet@chromium.org
mkwst@chromium.org
toyoshim@chromium.org
yhirano@chromium.org
-yoav@yoav.ws
+yoavweiss@chromium.org
# TEAM: loading-dev@chromium.org
# COMPONENT: Blink>Loader
diff --git a/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
index d3eaed46e86..7c833731c34 100644
--- a/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/core/loader/allowed_by_nosniff.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
@@ -17,6 +18,8 @@ namespace blink {
namespace {
+using WebFeature = mojom::WebFeature;
+
// In addition to makeing an allowed/not-allowed decision,
// AllowedByNosniff::MimeTypeAsScript reports common usage patterns to support
// future decisions about which types can be safely be disallowed. Below
@@ -129,16 +132,19 @@ bool AllowMimeTypeAsScript(const String& mime_type,
} // namespace
-bool AllowedByNosniff::MimeTypeAsScript(ExecutionContext* execution_context,
+bool AllowedByNosniff::MimeTypeAsScript(FetchContext& context,
+ ConsoleLogger* console_logger,
const ResourceResponse& response,
- MimeTypeCheck mime_type_check_mode) {
+ MimeTypeCheck mime_type_check_mode,
+ bool is_worker_global_scope) {
// The content type is really only meaningful for the http:-family & data
// schemes.
- bool is_http_family_or_data = response.Url().ProtocolIsInHTTPFamily() ||
- response.Url().ProtocolIsData();
+ bool is_http_family_or_data =
+ response.CurrentRequestUrl().ProtocolIsInHTTPFamily() ||
+ response.CurrentRequestUrl().ProtocolIsData();
if (!is_http_family_or_data &&
- (response.Url().LastPathComponent().EndsWith(".js") ||
- response.Url().LastPathComponent().EndsWith(".mjs"))) {
+ (response.CurrentRequestUrl().LastPathComponent().EndsWith(".js") ||
+ response.CurrentRequestUrl().LastPathComponent().EndsWith(".mjs"))) {
return true;
}
@@ -148,53 +154,53 @@ bool AllowedByNosniff::MimeTypeAsScript(ExecutionContext* execution_context,
if (!(ParseContentTypeOptionsHeader(response.HttpHeaderField(
http_names::kXContentTypeOptions)) != kContentTypeOptionsNosniff ||
MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type))) {
- execution_context->AddConsoleMessage(ConsoleMessage::Create(
- kSecurityMessageSource, kErrorMessageLevel,
- "Refused to execute script from '" + response.Url().ElidedString() +
+ console_logger->AddErrorMessage(
+ ConsoleLogger::Source::kSecurity,
+ "Refused to execute script from '" +
+ response.CurrentRequestUrl().ElidedString() +
"' because its MIME type ('" + mime_type +
- "') is not executable, and "
- "strict MIME type checking is "
- "enabled."));
+ "') is not executable, and strict MIME type checking is enabled.");
return false;
}
// Check for certain non-executable MIME types.
// See:
// https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type
-
- bool same_origin =
- execution_context->GetSecurityOrigin()->CanRequest(response.Url());
+ bool same_origin = context.GetResourceFetcherProperties()
+ .GetFetchClientSettingsObject()
+ .GetSecurityOrigin()
+ ->CanRequest(response.CurrentRequestUrl());
// For any MIME type, we can do three things: accept/reject it, print a
// warning into the console, and count it using a use counter.
const WebFeature kWebFeatureNone = WebFeature::kNumberOfFeatures;
bool warn = false;
WebFeature counter = kWebFeatureNone;
- bool allow = AllowMimeTypeAsScript(
- mime_type, same_origin, mime_type_check_mode,
- execution_context->IsWorkerGlobalScope(), warn, counter);
+ bool allow =
+ AllowMimeTypeAsScript(mime_type, same_origin, mime_type_check_mode,
+ is_worker_global_scope, warn, counter);
// These record usages for two MIME types (without subtypes), per same/cross
// origin.
if (mime_type.StartsWithIgnoringASCIICase("application/")) {
- UseCounter::Count(execution_context, kApplicationFeatures[same_origin]);
+ context.CountUsage(kApplicationFeatures[same_origin]);
} else if (mime_type.StartsWithIgnoringASCIICase("text/")) {
- UseCounter::Count(execution_context, kTextFeatures[same_origin]);
+ context.CountUsage(kTextFeatures[same_origin]);
}
// The code above has made a decision and handed down the result in accept,
// warn, and counter.
if (counter != kWebFeatureNone) {
- UseCounter::Count(execution_context, counter);
+ context.CountUsage(counter);
}
if (!allow || warn) {
const char* msg =
allow ? "Deprecated: Future versions will refuse" : "Refused";
- execution_context->AddConsoleMessage(ConsoleMessage::Create(
- kSecurityMessageSource, kErrorMessageLevel,
+ console_logger->AddErrorMessage(
+ ConsoleLogger::Source::kSecurity,
String() + msg + " to execute script from '" +
- response.Url().ElidedString() + "' because its MIME type ('" +
- mime_type + "') is not executable."));
+ response.CurrentRequestUrl().ElidedString() +
+ "' because its MIME type ('" + mime_type + "') is not executable.");
}
return allow;
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.h b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.h
new file mode 100644
index 00000000000..c73a8ed93a5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_ALLOWED_BY_NOSNIFF_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_ALLOWED_BY_NOSNIFF_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+class ConsoleLogger;
+class FetchContext;
+class ResourceResponse;
+
+class PLATFORM_EXPORT AllowedByNosniff final {
+ public:
+ enum class MimeTypeCheck { kStrict, kLax };
+
+ static bool MimeTypeAsScript(FetchContext&,
+ ConsoleLogger*,
+ const ResourceResponse&,
+ MimeTypeCheck mime_type_check_mode,
+ bool is_worker_global_scope);
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
index 60163924838..ed048e870e0 100644
--- a/chromium/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
@@ -2,52 +2,53 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/core/loader/allowed_by_nosniff.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/inspector/console_message_storage.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
+namespace {
+
using MimeTypeCheck = AllowedByNosniff::MimeTypeCheck;
+using WebFeature = mojom::WebFeature;
+using ::testing::_;
-class AllowedByNosniffTest : public testing::Test {
+class CountUsageMockFetchContext : public MockFetchContext {
public:
- void SetUp() override {
- // Create a new dummy page holder for each test, so that we get a fresh
- // set of counters for each.
- dummy_page_holder_ = DummyPageHolder::Create();
- Page::InsertOrdinaryPageForTesting(&dummy_page_holder_->GetPage());
+ CountUsageMockFetchContext() : MockFetchContext(nullptr, nullptr) {}
+ static CountUsageMockFetchContext* Create() {
+ return MakeGarbageCollected<
+ ::testing::StrictMock<CountUsageMockFetchContext>>();
}
+ MOCK_CONST_METHOD1(CountUsage, void(mojom::WebFeature));
+};
- Document* doc() { return &dummy_page_holder_->GetDocument(); }
-
- size_t ConsoleMessageStoreSize() const {
- return dummy_page_holder_->GetPage().GetConsoleMessageStorage().size();
- }
+class MockConsoleLogger : public GarbageCollectedFinalized<MockConsoleLogger>,
+ public ConsoleLogger {
+ USING_GARBAGE_COLLECTED_MIXIN(MockConsoleLogger);
- private:
- std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+ public:
+ MOCK_METHOD2(AddInfoMessage, void(Source, const String&));
+ MOCK_METHOD2(AddWarningMessage, void(Source, const String&));
+ MOCK_METHOD2(AddErrorMessage, void(Source, const String&));
};
-TEST_F(AllowedByNosniffTest, SanityCheckSetUp) {
- // UseCounter counts will be silently swallowed under various conditions,
- // e.g. if the document doesn't actually hold a frame. This test is a sanity
- // test that UseCounter::Count + UseCounter::IsCounted work at all with the
- // current test setup. If this test fails, we know that the setup is wrong,
- // rather than the code under test.
- WebFeature f = WebFeature::kSameOriginTextScript;
- EXPECT_FALSE(UseCounter::IsCounted(*doc(), f));
- UseCounter::Count(doc(), f);
- EXPECT_TRUE(UseCounter::IsCounted(*doc(), f));
-
- EXPECT_EQ(ConsoleMessageStoreSize(), 0U);
-}
+} // namespace
+
+class AllowedByNosniffTest : public testing::Test {
+ public:
+ static scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() {
+ return base::MakeRefCounted<scheduler::FakeTaskRunner>();
+ }
+};
TEST_F(AllowedByNosniffTest, AllowedOrNot) {
struct {
@@ -101,7 +102,14 @@ TEST_F(AllowedByNosniffTest, AllowedOrNot) {
<< (testcase.strict_allowed ? "true" : "false"));
const KURL url("https://bla.com/");
- doc()->SetSecurityOrigin(SecurityOrigin::Create(url));
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(
+ SecurityOrigin::Create(url));
+ auto* context = CountUsageMockFetchContext::Create();
+ // Bind |properties| to |context| through a ResourceFetcher.
+ MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
+ Persistent<MockConsoleLogger> logger =
+ MakeGarbageCollected<MockConsoleLogger>();
ResourceResponse response(url);
response.SetHTTPHeaderField("Content-Type", testcase.mimetype);
@@ -109,39 +117,63 @@ TEST_F(AllowedByNosniffTest, AllowedOrNot) {
// setting. Warnings for any blocked script.
RuntimeEnabledFeatures::SetWorkerNosniffBlockEnabled(false);
RuntimeEnabledFeatures::SetWorkerNosniffWarnEnabled(false);
- size_t message_count = ConsoleMessageStoreSize();
- EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
- doc(), response, MimeTypeCheck::kLax));
- EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
- doc(), response, MimeTypeCheck::kStrict));
- EXPECT_EQ(ConsoleMessageStoreSize(), message_count + 2 * !testcase.allowed);
+ EXPECT_CALL(*context, CountUsage(_)).Times(::testing::AnyNumber());
+ if (!testcase.allowed)
+ EXPECT_CALL(*logger, AddErrorMessage(_, _));
+ EXPECT_EQ(testcase.allowed,
+ AllowedByNosniff::MimeTypeAsScript(*context, logger, response,
+ MimeTypeCheck::kLax, false));
+ ::testing::Mock::VerifyAndClear(context);
+
+ EXPECT_CALL(*context, CountUsage(_)).Times(::testing::AnyNumber());
+ if (!testcase.allowed)
+ EXPECT_CALL(*logger, AddErrorMessage(_, _));
+ EXPECT_EQ(testcase.allowed,
+ AllowedByNosniff::MimeTypeAsScript(
+ *context, logger, response, MimeTypeCheck::kStrict, false));
+ ::testing::Mock::VerifyAndClear(context);
// Nosniff worker blocked: Workers follow the 'strict_allow' setting.
// Warnings for any blocked scripts.
RuntimeEnabledFeatures::SetWorkerNosniffBlockEnabled(true);
RuntimeEnabledFeatures::SetWorkerNosniffWarnEnabled(false);
- message_count = ConsoleMessageStoreSize();
- EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
- doc(), response, MimeTypeCheck::kLax));
- EXPECT_EQ(ConsoleMessageStoreSize(), message_count + !testcase.allowed);
+
+ EXPECT_CALL(*context, CountUsage(_)).Times(::testing::AnyNumber());
+ if (!testcase.allowed)
+ EXPECT_CALL(*logger, AddErrorMessage(_, _));
+ EXPECT_EQ(testcase.allowed,
+ AllowedByNosniff::MimeTypeAsScript(*context, logger, response,
+ MimeTypeCheck::kLax, false));
+ ::testing::Mock::VerifyAndClear(context);
+
+ EXPECT_CALL(*context, CountUsage(_)).Times(::testing::AnyNumber());
+ if (!testcase.strict_allowed)
+ EXPECT_CALL(*logger, AddErrorMessage(_, _));
EXPECT_EQ(testcase.strict_allowed,
- AllowedByNosniff::MimeTypeAsScript(doc(), response,
- MimeTypeCheck::kStrict));
- EXPECT_EQ(ConsoleMessageStoreSize(),
- message_count + !testcase.allowed + !testcase.strict_allowed);
+ AllowedByNosniff::MimeTypeAsScript(
+ *context, logger, response, MimeTypeCheck::kStrict, false));
+ ::testing::Mock::VerifyAndClear(context);
// Nosniff 'legacy', but with warnings. The allowed setting follows the
// 'allowed' setting, but the warnings follow the 'strict' setting.
RuntimeEnabledFeatures::SetWorkerNosniffBlockEnabled(false);
RuntimeEnabledFeatures::SetWorkerNosniffWarnEnabled(true);
- message_count = ConsoleMessageStoreSize();
- EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
- doc(), response, MimeTypeCheck::kLax));
- EXPECT_EQ(ConsoleMessageStoreSize(), message_count + !testcase.allowed);
- EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
- doc(), response, MimeTypeCheck::kStrict));
- EXPECT_EQ(ConsoleMessageStoreSize(),
- message_count + !testcase.allowed + !testcase.strict_allowed);
+
+ EXPECT_CALL(*context, CountUsage(_)).Times(::testing::AnyNumber());
+ if (!testcase.allowed)
+ EXPECT_CALL(*logger, AddErrorMessage(_, _));
+ EXPECT_EQ(testcase.allowed,
+ AllowedByNosniff::MimeTypeAsScript(*context, logger, response,
+ MimeTypeCheck::kLax, false));
+ ::testing::Mock::VerifyAndClear(context);
+
+ EXPECT_CALL(*context, CountUsage(_)).Times(::testing::AnyNumber());
+ if (!testcase.strict_allowed)
+ EXPECT_CALL(*logger, AddErrorMessage(_, _));
+ EXPECT_EQ(testcase.allowed,
+ AllowedByNosniff::MimeTypeAsScript(
+ *context, logger, response, MimeTypeCheck::kStrict, false));
+ ::testing::Mock::VerifyAndClear(context);
}
}
@@ -177,17 +209,27 @@ TEST_F(AllowedByNosniffTest, Counters) {
};
for (auto& testcase : data) {
- SetUp();
SCOPED_TRACE(testing::Message() << "\n url: " << testcase.url
<< "\n origin: " << testcase.origin
<< "\n mime type: " << testcase.mimetype
<< "\n webfeature: " << testcase.expected);
- doc()->SetSecurityOrigin(SecurityOrigin::Create(KURL(testcase.origin)));
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(
+ SecurityOrigin::Create(KURL(testcase.origin)));
+ auto* context = CountUsageMockFetchContext::Create();
+ // Bind |properties| to |context| through a ResourceFetcher.
+ MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
+ Persistent<MockConsoleLogger> logger =
+ MakeGarbageCollected<MockConsoleLogger>();
ResourceResponse response(KURL(testcase.url));
response.SetHTTPHeaderField("Content-Type", testcase.mimetype);
- AllowedByNosniff::MimeTypeAsScript(doc(), response, MimeTypeCheck::kLax);
- EXPECT_TRUE(UseCounter::IsCounted(*doc(), testcase.expected));
+ EXPECT_CALL(*context, CountUsage(testcase.expected));
+ EXPECT_CALL(*context, CountUsage(::testing::Ne(testcase.expected)))
+ .Times(::testing::AnyNumber());
+ AllowedByNosniff::MimeTypeAsScript(*context, logger, response,
+ MimeTypeCheck::kLax, false);
+ ::testing::Mock::VerifyAndClear(context);
}
}
@@ -217,14 +259,22 @@ TEST_F(AllowedByNosniffTest, AllTheSchemes) {
};
for (auto& testcase : data) {
- SetUp();
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* context = CountUsageMockFetchContext::Create();
+ // Bind |properties| to |context| through a ResourceFetcher.
+ MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
+ Persistent<MockConsoleLogger> logger =
+ MakeGarbageCollected<MockConsoleLogger>();
+ EXPECT_CALL(*logger, AddErrorMessage(_, _)).Times(::testing::AnyNumber());
SCOPED_TRACE(testing::Message() << "\n url: " << testcase.url
<< "\n allowed: " << testcase.allowed);
ResourceResponse response(KURL(testcase.url));
response.SetHTTPHeaderField("Content-Type", "invalid");
response.SetHTTPHeaderField("X-Content-Type-Options", "nosniff");
- EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
- doc(), response, MimeTypeCheck::kLax));
+ EXPECT_EQ(testcase.allowed,
+ AllowedByNosniff::MimeTypeAsScript(*context, logger, response,
+ MimeTypeCheck::kLax, false));
}
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc b/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc
index ceab3bb784a..6b53740fd33 100644
--- a/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -272,16 +272,40 @@ bool CheckIfRequestCanSkipPreflight(
*CreateNetHttpRequestHeaders(request_header_map), is_revalidating);
}
+// Keep this in sync with the identical function
+// network::cors::CorsURLLoader::CalculateResponseTainting.
+//
+// This is the same as that function except using KURL and SecurityOrigin
+// instead of GURL and url::Origin. We can't combine them because converting
+// SecurityOrigin to url::Origin loses information about origins that are
+// whitelisted by SecurityPolicy.
+//
+// This function also doesn't use a |tainted_origin| flag because Blink loaders
+// mutate the origin instead of using such a flag.
network::mojom::FetchResponseType CalculateResponseTainting(
const KURL& url,
network::mojom::FetchRequestMode request_mode,
const SecurityOrigin* origin,
CorsFlag cors_flag) {
- base::Optional<url::Origin> origin_to_pass;
- if (origin)
- origin_to_pass = AsUrlOrigin(*origin);
- return network::cors::CalculateResponseTainting(
- url, request_mode, origin_to_pass, cors_flag == CorsFlag::Set);
+ if (url.ProtocolIsData())
+ return network::mojom::FetchResponseType::kBasic;
+
+ if (cors_flag == CorsFlag::Set) {
+ DCHECK(IsCorsEnabledRequestMode(request_mode));
+ return network::mojom::FetchResponseType::kCors;
+ }
+
+ if (!origin) {
+ // This is actually not defined in the fetch spec, but in this case CORS
+ // is disabled so no one should care this value.
+ return network::mojom::FetchResponseType::kBasic;
+ }
+
+ if (request_mode == network::mojom::FetchRequestMode::kNoCors &&
+ !origin->CanRequest(url)) {
+ return network::mojom::FetchResponseType::kOpaque;
+ }
+ return network::mojom::FetchResponseType::kBasic;
}
bool CalculateCredentialsFlag(
@@ -301,6 +325,16 @@ bool IsCorsSafelistedContentType(const String& media_type) {
WebString(media_type).Latin1());
}
+bool IsNoCorsSafelistedHeaderName(const String& name) {
+ DCHECK(!name.IsNull());
+ return network::cors::IsNoCorsSafelistedHeaderName(WebString(name).Latin1());
+}
+
+bool IsPrivilegedNoCorsHeaderName(const String& name) {
+ DCHECK(!name.IsNull());
+ return network::cors::IsPrivilegedNoCorsHeaderName(WebString(name).Latin1());
+}
+
bool IsNoCorsSafelistedHeader(const String& name, const String& value) {
DCHECK(!name.IsNull());
DCHECK(!value.IsNull());
diff --git a/chromium/third_party/blink/renderer/platform/loader/cors/cors.h b/chromium/third_party/blink/renderer/platform/loader/cors/cors.h
index 425930b9fb4..7704f158fcd 100644
--- a/chromium/third_party/blink/renderer/platform/loader/cors/cors.h
+++ b/chromium/third_party/blink/renderer/platform/loader/cors/cors.h
@@ -9,7 +9,7 @@
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/mojom/cors.mojom-shared.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/web_http_header_set.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -77,6 +77,10 @@ PLATFORM_EXPORT bool CheckIfRequestCanSkipPreflight(
const String& method,
const HTTPHeaderMap& request_header_map);
+// Returns the response tainting value
+// (https://fetch.spec.whatwg.org/#concept-request-response-tainting) for a
+// request and the CORS flag, as specified in
+// https://fetch.spec.whatwg.org/#main-fetch.
PLATFORM_EXPORT network::mojom::FetchResponseType CalculateResponseTainting(
const KURL& url,
network::mojom::FetchRequestMode request_mode,
@@ -93,6 +97,8 @@ PLATFORM_EXPORT bool IsCorsSafelistedMethod(const String& method);
PLATFORM_EXPORT bool IsCorsSafelistedContentType(const String&);
PLATFORM_EXPORT bool IsNoCorsSafelistedHeader(const String& name,
const String& value);
+PLATFORM_EXPORT bool IsPrivilegedNoCorsHeaderName(const String& name);
+PLATFORM_EXPORT bool IsNoCorsSafelistedHeaderName(const String& name);
PLATFORM_EXPORT Vector<String> CorsUnsafeRequestHeaderNames(
const HTTPHeaderMap& headers);
PLATFORM_EXPORT bool IsForbiddenHeaderName(const String& name);
diff --git a/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc b/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc
index 718a51fe3de..f6c652e1f9c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc
@@ -100,6 +100,90 @@ TEST_F(CorsExposedHeadersTest, Asterisk) {
WebHTTPHeaderSet({"a", "b", "*"}));
}
+// Keep this in sync with the CalculateResponseTainting test in
+// services/network/cors/cors_url_loader_unittest.cc.
+TEST(CorsTest, CalculateResponseTainting) {
+ using network::mojom::FetchRequestMode;
+ using network::mojom::FetchResponseType;
+
+ const KURL same_origin_url("https://example.com/");
+ const KURL cross_origin_url("https://example2.com/");
+ scoped_refptr<SecurityOrigin> origin_refptr =
+ SecurityOrigin::Create(same_origin_url);
+ const SecurityOrigin* origin = origin_refptr.get();
+ const SecurityOrigin* no_origin = nullptr;
+
+ // CORS flag is false, same-origin request
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(same_origin_url,
+ FetchRequestMode::kSameOrigin,
+ origin, CorsFlag::Unset));
+ EXPECT_EQ(
+ FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(
+ same_origin_url, FetchRequestMode::kNoCors, origin, CorsFlag::Unset));
+ EXPECT_EQ(
+ FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(same_origin_url, FetchRequestMode::kCors,
+ origin, CorsFlag::Unset));
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(
+ same_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
+ origin, CorsFlag::Unset));
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(same_origin_url,
+ FetchRequestMode::kNavigate, origin,
+ CorsFlag::Unset));
+
+ // CORS flag is false, cross-origin request
+ EXPECT_EQ(FetchResponseType::kOpaque,
+ cors::CalculateResponseTainting(cross_origin_url,
+ FetchRequestMode::kNoCors, origin,
+ CorsFlag::Unset));
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(cross_origin_url,
+ FetchRequestMode::kNavigate, origin,
+ CorsFlag::Unset));
+
+ // CORS flag is true, same-origin request
+ EXPECT_EQ(
+ FetchResponseType::kCors,
+ cors::CalculateResponseTainting(same_origin_url, FetchRequestMode::kCors,
+ origin, CorsFlag::Set));
+ EXPECT_EQ(FetchResponseType::kCors,
+ cors::CalculateResponseTainting(
+ same_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
+ origin, CorsFlag::Set));
+
+ // CORS flag is true, cross-origin request
+ EXPECT_EQ(
+ FetchResponseType::kCors,
+ cors::CalculateResponseTainting(cross_origin_url, FetchRequestMode::kCors,
+ origin, CorsFlag::Set));
+ EXPECT_EQ(FetchResponseType::kCors,
+ cors::CalculateResponseTainting(
+ cross_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
+ origin, CorsFlag::Set));
+
+ // Origin is not provided.
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(same_origin_url,
+ FetchRequestMode::kNoCors,
+ no_origin, CorsFlag::Unset));
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(same_origin_url,
+ FetchRequestMode::kNavigate,
+ no_origin, CorsFlag::Unset));
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(cross_origin_url,
+ FetchRequestMode::kNoCors,
+ no_origin, CorsFlag::Unset));
+ EXPECT_EQ(FetchResponseType::kBasic,
+ cors::CalculateResponseTainting(cross_origin_url,
+ FetchRequestMode::kNavigate,
+ no_origin, CorsFlag::Unset));
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc
index 1edafd9beac..0da3bd5aff3 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc
@@ -9,7 +9,7 @@
namespace blink {
scoped_refptr<CachedMetadata> CachedMetadata::CreateFromSerializedData(
- const char* data,
+ const uint8_t* data,
size_t size) {
// Ensure the data is big enough, otherwise discard the data.
if (size < kCachedMetaDataStart ||
@@ -24,7 +24,7 @@ scoped_refptr<CachedMetadata> CachedMetadata::CreateFromSerializedData(
return base::AdoptRef(
new CachedMetadata(data, static_cast<wtf_size_t>(size)));
}
-CachedMetadata::CachedMetadata(const char* data, wtf_size_t size) {
+CachedMetadata::CachedMetadata(const uint8_t* data, wtf_size_t size) {
// Serialized metadata should have non-empty data.
DCHECK_GT(size, kCachedMetaDataStart);
DCHECK(data);
@@ -37,7 +37,7 @@ CachedMetadata::CachedMetadata(const char* data, wtf_size_t size) {
}
CachedMetadata::CachedMetadata(uint32_t data_type_id,
- const char* data,
+ const uint8_t* data,
wtf_size_t size) {
// Don't allow an ID of 0, it is used internally to indicate errors.
DCHECK(data_type_id);
@@ -45,9 +45,9 @@ CachedMetadata::CachedMetadata(uint32_t data_type_id,
serialized_data_.ReserveInitialCapacity(kCachedMetaDataStart + size);
uint32_t marker = CachedMetadataHandler::kSingleEntry;
- serialized_data_.Append(reinterpret_cast<const char*>(&marker),
+ serialized_data_.Append(reinterpret_cast<const uint8_t*>(&marker),
sizeof(uint32_t));
- serialized_data_.Append(reinterpret_cast<const char*>(&data_type_id),
+ serialized_data_.Append(reinterpret_cast<const uint8_t*>(&data_type_id),
sizeof(uint32_t));
serialized_data_.Append(data, size);
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h
index 2657ea0972c..474c560ff1f 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h
@@ -53,27 +53,27 @@ constexpr size_t kCachedMetaDataStart = kCacheDataTypeStart + sizeof(uint32_t);
class PLATFORM_EXPORT CachedMetadata : public RefCounted<CachedMetadata> {
public:
static scoped_refptr<CachedMetadata> Create(uint32_t data_type_id,
- const char* data,
+ const uint8_t* data,
size_t size) {
return base::AdoptRef(
new CachedMetadata(data_type_id, data, SafeCast<wtf_size_t>(size)));
}
static scoped_refptr<CachedMetadata> CreateFromSerializedData(
- const char* data,
+ const uint8_t* data,
size_t);
~CachedMetadata() = default;
- const Vector<char>& SerializedData() const { return serialized_data_; }
+ const Vector<uint8_t>& SerializedData() const { return serialized_data_; }
uint32_t DataTypeID() const {
DCHECK_GE(serialized_data_.size(), kCachedMetaDataStart);
return *reinterpret_cast_ptr<uint32_t*>(
- const_cast<char*>(serialized_data_.data() + kCacheDataTypeStart));
+ const_cast<uint8_t*>(serialized_data_.data() + kCacheDataTypeStart));
}
- const char* Data() const {
+ const uint8_t* Data() const {
DCHECK_GE(serialized_data_.size(), kCachedMetaDataStart);
return serialized_data_.data() + kCachedMetaDataStart;
}
@@ -84,12 +84,12 @@ class PLATFORM_EXPORT CachedMetadata : public RefCounted<CachedMetadata> {
}
private:
- CachedMetadata(const char* data, wtf_size_t);
- CachedMetadata(uint32_t data_type_id, const char* data, wtf_size_t);
+ CachedMetadata(const uint8_t* data, wtf_size_t);
+ CachedMetadata(uint32_t data_type_id, const uint8_t* data, wtf_size_t);
// Since the serialization format supports random access, storing it in
// serialized form avoids need for a copy during serialization.
- Vector<char> serialized_data_;
+ Vector<uint8_t> serialized_data_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.cc
new file mode 100644
index 00000000000..b84a3ced33f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.cc
@@ -0,0 +1,139 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
+
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+// This is a CachedMetadataSender implementation for normal responses.
+class CachedMetadataSenderImpl : public CachedMetadataSender {
+ public:
+ CachedMetadataSenderImpl(const ResourceResponse&,
+ blink::mojom::CodeCacheType);
+ ~CachedMetadataSenderImpl() override = default;
+
+ void Send(const uint8_t*, size_t) override;
+ bool IsServedFromCacheStorage() override { return false; }
+
+ private:
+ const KURL response_url_;
+ const Time response_time_;
+ const blink::mojom::CodeCacheType code_cache_type_;
+};
+
+CachedMetadataSenderImpl::CachedMetadataSenderImpl(
+ const ResourceResponse& response,
+ blink::mojom::CodeCacheType code_cache_type)
+ : response_url_(response.CurrentRequestUrl()),
+ response_time_(response.ResponseTime()),
+ code_cache_type_(code_cache_type) {
+ DCHECK(response.CacheStorageCacheName().IsNull());
+ DCHECK(!response.WasFetchedViaServiceWorker() ||
+ response.IsServiceWorkerPassThrough());
+}
+
+void CachedMetadataSenderImpl::Send(const uint8_t* data, size_t size) {
+ Platform::Current()->CacheMetadata(code_cache_type_, response_url_,
+ response_time_, data, size);
+}
+
+// This is a CachedMetadataSender implementation that does nothing.
+class NullCachedMetadataSender : public CachedMetadataSender {
+ public:
+ NullCachedMetadataSender() = default;
+ ~NullCachedMetadataSender() override = default;
+
+ void Send(const uint8_t*, size_t) override {}
+ bool IsServedFromCacheStorage() override { return false; }
+};
+
+// This is a CachedMetadataSender implementation for responses that are served
+// by a ServiceWorker from cache storage.
+class ServiceWorkerCachedMetadataSender : public CachedMetadataSender {
+ public:
+ ServiceWorkerCachedMetadataSender(const ResourceResponse&,
+ scoped_refptr<const SecurityOrigin>);
+ ~ServiceWorkerCachedMetadataSender() override = default;
+
+ void Send(const uint8_t*, size_t) override;
+ bool IsServedFromCacheStorage() override { return true; }
+
+ private:
+ const KURL response_url_;
+ const Time response_time_;
+ const String cache_storage_cache_name_;
+ scoped_refptr<const SecurityOrigin> security_origin_;
+};
+
+ServiceWorkerCachedMetadataSender::ServiceWorkerCachedMetadataSender(
+ const ResourceResponse& response,
+ scoped_refptr<const SecurityOrigin> security_origin)
+ : response_url_(response.CurrentRequestUrl()),
+ response_time_(response.ResponseTime()),
+ cache_storage_cache_name_(response.CacheStorageCacheName()),
+ security_origin_(std::move(security_origin)) {
+ DCHECK(!cache_storage_cache_name_.IsNull());
+}
+
+void ServiceWorkerCachedMetadataSender::Send(const uint8_t* data, size_t size) {
+ Platform::Current()->CacheMetadataInCacheStorage(
+ response_url_, response_time_, data, size,
+ WebSecurityOrigin(security_origin_), cache_storage_cache_name_);
+}
+
+// static
+std::unique_ptr<CachedMetadataSender> CachedMetadataSender::Create(
+ const ResourceResponse& response,
+ blink::mojom::CodeCacheType code_cache_type,
+ scoped_refptr<const SecurityOrigin> requestor_origin) {
+ if (!response.WasFetchedViaServiceWorker()) {
+ return std::make_unique<CachedMetadataSenderImpl>(response,
+ code_cache_type);
+ }
+
+ // If the service worker provided a Response produced from cache_storage,
+ // then we need to use a different code cache sender.
+ if (!response.CacheStorageCacheName().IsNull()) {
+ // TODO(leszeks): Check whether it's correct that |origin| can be nullptr.
+ if (!requestor_origin) {
+ return std::make_unique<NullCachedMetadataSender>();
+ }
+ return std::make_unique<ServiceWorkerCachedMetadataSender>(
+ response, std::move(requestor_origin));
+ }
+
+ // If the service worker provides a synthetic `new Response()` or a
+ // Response with a different URL then we disable code caching. In the
+ // synthetic case there is no actual backing storage. In the case where
+ // the service worker uses a Response with a different URL we don't
+ // currently have a way to read the code cache since the we begin
+ // loading it based on the request URL before the response is available.
+ if (!response.IsServiceWorkerPassThrough()) {
+ return std::make_unique<NullCachedMetadataSender>();
+ }
+
+ return std::make_unique<CachedMetadataSenderImpl>(response, code_cache_type);
+}
+
+bool ShouldUseIsolatedCodeCache(mojom::RequestContextType request_context,
+ const ResourceResponse& response) {
+ return RuntimeEnabledFeatures::IsolatedCodeCacheEnabled() &&
+ // Service worker script has its own code cache.
+ request_context != mojom::RequestContextType::SERVICE_WORKER &&
+ // Also, we only support code cache for other service worker provided
+ // resources when a direct pass-through fetch handler is used. If the
+ // service worker synthesizes a new Response or provides a Response
+ // fetched from a different URL, then do not use the code cache.
+ // Also, responses coming from cache storage use a separate code
+ // cache mechanism.
+ (!response.WasFetchedViaServiceWorker() ||
+ response.IsServiceWorkerPassThrough());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h
index 626544fddef..80a609d0719 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h
@@ -6,12 +6,38 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_CACHED_METADATA_HANDLER_H_
#include <stdint.h>
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
class CachedMetadata;
+class ResourceResponse;
+
+// A callback for sending the serialized data of cached metadata back to the
+// platform.
+class PLATFORM_EXPORT CachedMetadataSender {
+ public:
+ static std::unique_ptr<CachedMetadataSender> Create(
+ const ResourceResponse&,
+ blink::mojom::CodeCacheType,
+ scoped_refptr<const SecurityOrigin> requestor_origin);
+
+ virtual ~CachedMetadataSender() = default;
+ virtual void Send(const uint8_t*, size_t) = 0;
+
+ // IsServedFromCacheStorage is used to alter caching strategy to be more
+ // aggressive. See V8CodeCache::GetCompileOptions() for an example.
+ virtual bool IsServedFromCacheStorage() = 0;
+};
+
+// Returns whether we should use isolated code cache for a particular response.
+PLATFORM_EXPORT bool ShouldUseIsolatedCodeCache(mojom::RequestContextType,
+ const ResourceResponse&);
// Handler class for caching operations.
class CachedMetadataHandler
@@ -52,7 +78,7 @@ class SingleCachedMetadataHandler : public CachedMetadataHandler {
// that the platform persist it. The dataTypeID is a pseudo-randomly chosen
// identifier that is used to distinguish data generated by the caller.
virtual void SetCachedMetadata(uint32_t data_type_id,
- const char*,
+ const uint8_t*,
size_t,
CacheType = kSendToPlatform) = 0;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/console_logger.h b/chromium/third_party/blink/renderer/platform/loader/fetch/console_logger.h
new file mode 100644
index 00000000000..680acc9f63a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/console_logger.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_CONSOLE_LOGGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_CONSOLE_LOGGER_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+// A pure virtual interface for console logging.
+class PLATFORM_EXPORT ConsoleLogger : public GarbageCollectedMixin {
+ public:
+ // This enum corresponds to blink::MessageSource. Expand this enum when
+ // needed.
+ enum class Source {
+ kScript,
+ kSecurity,
+ kOther,
+ };
+
+ ConsoleLogger() = default;
+ virtual ~ConsoleLogger() = default;
+
+ // Add a message with "info" level.
+ virtual void AddInfoMessage(Source source, const String& message) = 0;
+
+ // Add a message with "warning" level.
+ virtual void AddWarningMessage(Source source, const String& message) = 0;
+
+ // Add a message with "error" level.
+ virtual void AddErrorMessage(Source source, const String& message) = 0;
+};
+
+class PLATFORM_EXPORT NullConsoleLogger final
+ : public GarbageCollected<NullConsoleLogger>,
+ public ConsoleLogger {
+ USING_GARBAGE_COLLECTED_MIXIN(NullConsoleLogger);
+
+ public:
+ NullConsoleLogger() = default;
+ ~NullConsoleLogger() override = default;
+
+ void AddInfoMessage(Source source, const String&) override {}
+ void AddWarningMessage(Source source, const String&) override {}
+ void AddErrorMessage(Source source, const String&) override {}
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_CONSOLE_LOGGER_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
index 9e6f23327bd..13db2921995 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/platform/cross_thread_copier.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -51,6 +52,11 @@ class PLATFORM_EXPORT FetchClientSettingsObject
// https://html.spec.whatwg.org/multipage/webappapis.html#https-state
virtual HttpsState GetHttpsState() const = 0;
+ // Used for classic top-level scripts and importScripts().
+ // TODO(crbug.com/794548): Remove this once we deprecate kLax.
+ virtual AllowedByNosniff::MimeTypeCheck MimeTypeCheckForClassicWorkerScript()
+ const = 0;
+
virtual void Trace(Visitor*) {}
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
index 38c1829bd45..af21d758d74 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
@@ -9,23 +9,38 @@
namespace blink {
FetchClientSettingsObjectSnapshot::FetchClientSettingsObjectSnapshot(
+ const FetchClientSettingsObject& fetch_client_setting_object)
+ : FetchClientSettingsObjectSnapshot(
+ fetch_client_setting_object.BaseURL(),
+ fetch_client_setting_object.GetSecurityOrigin(),
+ fetch_client_setting_object.GetReferrerPolicy(),
+ fetch_client_setting_object.GetOutgoingReferrer(),
+ fetch_client_setting_object.GetHttpsState(),
+ fetch_client_setting_object.MimeTypeCheckForClassicWorkerScript()) {}
+
+FetchClientSettingsObjectSnapshot::FetchClientSettingsObjectSnapshot(
std::unique_ptr<CrossThreadFetchClientSettingsObjectData> data)
- : FetchClientSettingsObjectSnapshot(data->base_url,
- data->security_origin,
- data->referrer_policy,
- data->outgoing_referrer,
- data->https_state) {}
+ : FetchClientSettingsObjectSnapshot(
+ data->base_url,
+ data->security_origin,
+ data->referrer_policy,
+ data->outgoing_referrer,
+ data->https_state,
+ data->mime_type_check_for_classic_worker_script) {}
FetchClientSettingsObjectSnapshot::FetchClientSettingsObjectSnapshot(
const KURL& base_url,
const scoped_refptr<const SecurityOrigin> security_origin,
network::mojom::ReferrerPolicy referrer_policy,
const String& outgoing_referrer,
- HttpsState https_state)
+ HttpsState https_state,
+ AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script)
: base_url_(base_url),
security_origin_(std::move(security_origin)),
referrer_policy_(referrer_policy),
outgoing_referrer_(outgoing_referrer),
- https_state_(https_state) {}
+ https_state_(https_state),
+ mime_type_check_for_classic_worker_script_(
+ mime_type_check_for_classic_worker_script) {}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
index 09290decad4..2ba7402cacf 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
@@ -32,18 +32,23 @@ struct CrossThreadFetchClientSettingsObjectData {
scoped_refptr<const SecurityOrigin> security_origin,
network::mojom::ReferrerPolicy referrer_policy,
String outgoing_referrer,
- HttpsState https_state)
+ HttpsState https_state,
+ AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script)
: base_url(std::move(base_url)),
security_origin(std::move(security_origin)),
referrer_policy(referrer_policy),
outgoing_referrer(std::move(outgoing_referrer)),
- https_state(https_state) {}
+ https_state(https_state),
+ mime_type_check_for_classic_worker_script(
+ mime_type_check_for_classic_worker_script) {}
const KURL base_url;
const scoped_refptr<const SecurityOrigin> security_origin;
const network::mojom::ReferrerPolicy referrer_policy;
const String outgoing_referrer;
const HttpsState https_state;
+ const AllowedByNosniff::MimeTypeCheck
+ mime_type_check_for_classic_worker_script;
};
// This takes a partial snapshot of the execution context's states so that an
@@ -59,6 +64,7 @@ struct CrossThreadFetchClientSettingsObjectData {
class PLATFORM_EXPORT FetchClientSettingsObjectSnapshot final
: public FetchClientSettingsObject {
public:
+ explicit FetchClientSettingsObjectSnapshot(const FetchClientSettingsObject&);
explicit FetchClientSettingsObjectSnapshot(
std::unique_ptr<CrossThreadFetchClientSettingsObjectData>);
FetchClientSettingsObjectSnapshot(
@@ -66,7 +72,8 @@ class PLATFORM_EXPORT FetchClientSettingsObjectSnapshot final
const scoped_refptr<const SecurityOrigin> security_origin,
network::mojom::ReferrerPolicy referrer_policy,
const String& outgoing_referrer,
- HttpsState https_state);
+ HttpsState https_state,
+ AllowedByNosniff::MimeTypeCheck);
~FetchClientSettingsObjectSnapshot() override = default;
@@ -82,11 +89,17 @@ class PLATFORM_EXPORT FetchClientSettingsObjectSnapshot final
}
HttpsState GetHttpsState() const override { return https_state_; }
+ AllowedByNosniff::MimeTypeCheck MimeTypeCheckForClassicWorkerScript()
+ const override {
+ return mime_type_check_for_classic_worker_script_;
+ }
+
// Gets a copy of the data suitable for passing to another thread.
std::unique_ptr<CrossThreadFetchClientSettingsObjectData> CopyData() const {
return std::make_unique<CrossThreadFetchClientSettingsObjectData>(
base_url_.Copy(), security_origin_->IsolatedCopy(), referrer_policy_,
- outgoing_referrer_.IsolatedCopy(), https_state_);
+ outgoing_referrer_.IsolatedCopy(), https_state_,
+ mime_type_check_for_classic_worker_script_);
}
private:
@@ -95,6 +108,8 @@ class PLATFORM_EXPORT FetchClientSettingsObjectSnapshot final
const network::mojom::ReferrerPolicy referrer_policy_;
const String outgoing_referrer_;
const HttpsState https_state_;
+ const AllowedByNosniff::MimeTypeCheck
+ mime_type_check_for_classic_worker_script_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc
index b54b55038a0..d874c6a0d5e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc
@@ -30,7 +30,9 @@
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/platform_probe_sink.h"
#include "third_party/blink/renderer/platform/probe/platform_trace_events_agent.h"
@@ -40,47 +42,39 @@ namespace {
class NullFetchContext final : public FetchContext {
public:
- explicit NullFetchContext(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : FetchContext(std::move(task_runner)),
- fetch_client_settings_object_(
- MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
- KURL(),
- nullptr /* security_origin */,
- network::mojom::ReferrerPolicy::kDefault,
- String(),
- HttpsState::kNone)) {}
-
- const FetchClientSettingsObject* GetFetchClientSettingsObject()
- const override {
- return fetch_client_settings_object_;
- }
-
- void Trace(blink::Visitor* visitor) override {
- visitor->Trace(fetch_client_settings_object_);
- FetchContext::Trace(visitor);
- }
-
- private:
- const Member<const FetchClientSettingsObject> fetch_client_settings_object_;
+ NullFetchContext() = default;
+
+ void CountUsage(mojom::WebFeature) const override {}
+ void CountDeprecation(mojom::WebFeature) const override {}
};
} // namespace
-FetchContext& FetchContext::NullInstance(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- return *(new NullFetchContext(std::move(task_runner)));
+FetchContext& FetchContext::NullInstance() {
+ return *MakeGarbageCollected<NullFetchContext>();
+}
+
+FetchContext::FetchContext()
+ : platform_probe_sink_(MakeGarbageCollected<PlatformProbeSink>()) {
+ platform_probe_sink_->addPlatformTraceEvents(
+ MakeGarbageCollected<PlatformTraceEventsAgent>());
}
-FetchContext::FetchContext(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : platform_probe_sink_(new PlatformProbeSink),
- task_runner_(std::move(task_runner)) {
- platform_probe_sink_->addPlatformTraceEvents(new PlatformTraceEventsAgent);
+void FetchContext::Bind(ResourceFetcher* fetcher) {
+ DCHECK(fetcher);
+ DCHECK(!fetcher_);
+ DCHECK_EQ(&fetcher->Context(), this);
+ fetcher_ = fetcher;
}
void FetchContext::Trace(blink::Visitor* visitor) {
visitor->Trace(platform_probe_sink_);
+ visitor->Trace(fetcher_);
+}
+
+const ResourceFetcherProperties& FetchContext::GetResourceFetcherProperties()
+ const {
+ return fetcher_->GetProperties();
}
void FetchContext::DispatchDidChangeResourcePriority(unsigned long,
@@ -97,7 +91,9 @@ mojom::FetchCacheMode FetchContext::ResourceRequestCachePolicy(
return mojom::FetchCacheMode::kDefault;
}
-void FetchContext::PrepareRequest(ResourceRequest&, RedirectType) {}
+void FetchContext::PrepareRequest(ResourceRequest&,
+ WebScopedVirtualTimePauser&,
+ RedirectType) {}
void FetchContext::DispatchWillSendRequest(unsigned long,
ResourceRequest&,
@@ -105,20 +101,15 @@ void FetchContext::DispatchWillSendRequest(unsigned long,
ResourceType,
const FetchInitiatorInfo&) {}
-void FetchContext::DispatchDidLoadResourceFromMemoryCache(
- unsigned long,
- const ResourceRequest&,
- const ResourceResponse&) {}
-
-void FetchContext::DispatchDidReceiveResponse(
- unsigned long,
- const ResourceResponse&,
- network::mojom::RequestContextFrameType FrameType,
- mojom::RequestContextType,
- Resource*,
- ResourceResponseType) {}
+void FetchContext::DispatchDidReceiveResponse(unsigned long,
+ const ResourceRequest&,
+ const ResourceResponse&,
+ Resource*,
+ ResourceResponseType) {}
-void FetchContext::DispatchDidReceiveData(unsigned long, const char*, size_t) {}
+void FetchContext::DispatchDidReceiveData(unsigned long,
+ const char*,
+ uint64_t) {}
void FetchContext::DispatchDidReceiveEncodedData(unsigned long, size_t) {}
@@ -137,6 +128,12 @@ void FetchContext::DispatchDidFail(const KURL&,
int64_t,
bool) {}
+bool FetchContext::ShouldLoadNewResource(ResourceType type) const {
+ if (type == ResourceType::kMainResource)
+ return !GetResourceFetcherProperties().ShouldBlockLoadingMainResource();
+ return !GetResourceFetcherProperties().ShouldBlockLoadingSubResource();
+}
+
void FetchContext::RecordLoadingActivity(
const ResourceRequest&,
ResourceType,
@@ -148,16 +145,15 @@ void FetchContext::DidObserveLoadingBehavior(WebLoadingBehaviorFlag) {}
void FetchContext::AddResourceTiming(const ResourceTimingInfo&) {}
-void FetchContext::AddInfoConsoleMessage(const String&, LogSource) const {}
-
-void FetchContext::AddWarningConsoleMessage(const String&, LogSource) const {}
-
-void FetchContext::AddErrorConsoleMessage(const String&, LogSource) const {}
-
void FetchContext::PopulateResourceRequest(
ResourceType,
const ClientHintsPreferences&,
const FetchParameters::ResourceWidth&,
ResourceRequest&) {}
+scoped_refptr<base::SingleThreadTaskRunner>
+FetchContext::GetLoadingTaskRunner() {
+ return fetcher_->GetTaskRunner();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index 60875d2b2a3..4d084287dd1 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -36,13 +36,13 @@
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h"
#include "third_party/blink/public/platform/code_cache_loader.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
#include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
-#include "third_party/blink/public/platform/web_application_cache_host.h"
+#include "third_party/blink/public/platform/web_feature.mojom-blink.h"
#include "third_party/blink/public/platform/web_loading_behavior_flag.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_request.h"
@@ -61,15 +61,15 @@
namespace blink {
+enum class ResourceType : uint8_t;
class ClientHintsPreferences;
-class FetchClientSettingsObject;
class KURL;
-class MHTMLArchive;
class PlatformProbeSink;
class ResourceError;
+class ResourceFetcherProperties;
class ResourceResponse;
class ResourceTimingInfo;
-enum class ResourceType : uint8_t;
+class WebScopedVirtualTimePauser;
enum FetchResourceType { kFetchMainResource, kFetchSubresource };
@@ -85,38 +85,22 @@ class PLATFORM_EXPORT FetchContext
WTF_MAKE_NONCOPYABLE(FetchContext);
public:
- // This enum corresponds to blink::MessageSource. We have this not to
- // introduce any dependency to core/.
- //
- // Currently only kJSMessageSource, kSecurityMessageSource and
- // kOtherMessageSource are used, but not to impress readers that
- // AddConsoleMessage() call from FetchContext() should always use them,
- // which is not true, we ask users of the Add.*ConsoleMessage() methods
- // to explicitly specify the MessageSource to use.
- //
- // Extend this when needed.
- enum LogSource { kJSSource, kSecuritySource, kOtherSource };
-
- static FetchContext& NullInstance(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ FetchContext();
+
+ static FetchContext& NullInstance();
virtual ~FetchContext() = default;
- virtual void Trace(blink::Visitor*);
+ // Binds |fetcher| to |this|.
+ void Bind(ResourceFetcher* fetcher);
+ // Unbinds the fetcher.
+ void Unbind() { fetcher_ = nullptr; }
- virtual bool IsFrameFetchContext() { return false; }
+ virtual void Trace(blink::Visitor*);
virtual void AddAdditionalRequestHeaders(ResourceRequest&, FetchResourceType);
- virtual const FetchClientSettingsObject* GetFetchClientSettingsObject()
- const = 0;
-
- // Called when the ResourceFetcher observes a data: URI load that contains an
- // octothorpe ('#') character. This is a temporary method to support an Intent
- // to Deprecate for spec incompliant handling of '#' characters in data URIs.
- //
- // TODO(crbug.com/123004): Remove once we have enough data for the I2D.
- virtual void RecordDataUriWithOctothorpe() {}
+ const ResourceFetcherProperties& GetResourceFetcherProperties() const;
// Returns the cache policy for the resource. ResourceRequest is not passed as
// a const reference as a header needs to be added for doc.write blocking
@@ -130,11 +114,16 @@ class PLATFORM_EXPORT FetchContext
ResourceLoadPriority,
int intra_priority_value);
- // This internally dispatches WebLocalFrameClient::willSendRequest and hooks
+ // This internally dispatches WebLocalFrameClient::WillSendRequest and hooks
// request interceptors like ServiceWorker and ApplicationCache.
// This may modify the request.
+ // |virtual_time_pauser| is an output parameter. PrepareRequest may
+ // create a new WebScopedVirtualTimePauser and set it to
+ // |virtual_time_pauser|.
enum class RedirectType { kForRedirect, kNotForRedirect };
- virtual void PrepareRequest(ResourceRequest&, RedirectType);
+ virtual void PrepareRequest(ResourceRequest&,
+ WebScopedVirtualTimePauser& virtual_time_pauser,
+ RedirectType);
// The last callback before a request is actually sent to the browser process.
// TODO(https://crbug.com/632580): make this take const ResourceRequest&.
@@ -144,20 +133,19 @@ class PLATFORM_EXPORT FetchContext
const ResourceResponse& redirect_response,
ResourceType,
const FetchInitiatorInfo& = FetchInitiatorInfo());
- virtual void DispatchDidLoadResourceFromMemoryCache(unsigned long identifier,
- const ResourceRequest&,
- const ResourceResponse&);
enum class ResourceResponseType { kNotFromMemoryCache, kFromMemoryCache };
- virtual void DispatchDidReceiveResponse(
- unsigned long identifier,
- const ResourceResponse&,
- network::mojom::RequestContextFrameType,
- mojom::RequestContextType,
- Resource*,
- ResourceResponseType);
+ // |request| and |resource| are provided separately because when it's from
+ // the memory cache |request| and |resource->GetResourceRequest()| don't
+ // match. |response| may not yet be set to |resource| when this function is
+ // called.
+ virtual void DispatchDidReceiveResponse(unsigned long identifier,
+ const ResourceRequest& request,
+ const ResourceResponse& response,
+ Resource* resource,
+ ResourceResponseType);
virtual void DispatchDidReceiveData(unsigned long identifier,
const char* data,
- size_t data_length);
+ uint64_t data_length);
virtual void DispatchDidReceiveEncodedData(unsigned long identifier,
size_t encoded_data_length);
virtual void DispatchDidDownloadToBlob(unsigned long identifier,
@@ -173,7 +161,7 @@ class PLATFORM_EXPORT FetchContext
int64_t encoded_data_length,
bool is_internal_request);
- virtual bool ShouldLoadNewResource(ResourceType) const { return false; }
+ bool ShouldLoadNewResource(ResourceType) const;
// Called when a resource load is first requested, which may not be when the
// load actually begins.
@@ -204,27 +192,8 @@ class PLATFORM_EXPORT FetchContext
return ResourceRequestBlockedReason::kOther;
}
- virtual blink::mojom::ControllerServiceWorkerMode
- IsControlledByServiceWorker() const {
- return blink::mojom::ControllerServiceWorkerMode::kNoController;
- }
- virtual int64_t ServiceWorkerID() const { return -1; }
- virtual int ApplicationCacheHostID() const {
- return WebApplicationCacheHost::kAppCacheNoHostId;
- }
-
- virtual bool IsMainFrame() const { return true; }
- virtual bool DefersLoading() const { return false; }
- virtual bool IsLoadComplete() const { return false; }
- virtual bool UpdateTimingInfoForIFrameNavigation(ResourceTimingInfo*) {
- return false;
- }
-
- virtual void AddInfoConsoleMessage(const String&, LogSource) const;
- virtual void AddWarningConsoleMessage(const String&, LogSource) const;
- virtual void AddErrorConsoleMessage(const String&, LogSource) const;
-
- virtual const SecurityOrigin* GetSecurityOrigin() const { return nullptr; }
+ virtual void CountUsage(mojom::WebFeature) const = 0;
+ virtual void CountDeprecation(mojom::WebFeature) const = 0;
// Populates the ResourceRequest using the given values and information
// stored in the FetchContext implementation. Used by ResourceFetcher to
@@ -234,8 +203,6 @@ class PLATFORM_EXPORT FetchContext
const FetchParameters::ResourceWidth&,
ResourceRequest&);
- virtual MHTMLArchive* Archive() const { return nullptr; }
-
PlatformProbeSink* GetPlatformProbeSink() const {
return platform_probe_sink_;
}
@@ -252,43 +219,15 @@ class PLATFORM_EXPORT FetchContext
return Platform::Current()->CreateCodeCacheLoader();
}
- // Returns the initial throttling policy used by the associated
- // ResourceLoadScheduler.
- virtual ResourceLoadScheduler::ThrottlingPolicy InitialLoadThrottlingPolicy()
- const {
- return ResourceLoadScheduler::ThrottlingPolicy::kNormal;
- }
-
- virtual bool IsDetached() const { return false; }
-
// Obtains FrameScheduler instance that is used in the attached frame.
// May return nullptr if a frame is not attached or detached.
virtual FrameScheduler* GetFrameScheduler() const { return nullptr; }
- // Returns a task runner intended for loading tasks. Should work even in a
- // worker context, where FrameScheduler doesn't exist, but the returned
- // base::SingleThreadTaskRunner will not work after the context detaches
- // (after Detach() is called, this will return a generic timer suitable for
- // post-detach actions like keepalive requests.
- virtual scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() {
- return task_runner_;
- }
-
- // TODO(altimin): This is used when creating a URLLoader, and
- // FetchContext::GetLoadingTaskRunner is used whenever asynchronous tasks
- // around resource loading are posted. Modify the code so that all
- // the tasks related to loading a resource use the resource loader handle's
- // task runner.
- virtual std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
- CreateResourceLoadingTaskRunnerHandle() {
- return nullptr;
- }
-
// Called when the underlying context is detached. Note that some
// FetchContexts continue working after detached (e.g., for fetch() operations
// with "keepalive" specified).
- // Returns a "detached" fetch context which can be null.
- virtual FetchContext* Detach() { return nullptr; }
+ // Returns a "detached" fetch context which cannot be null.
+ virtual FetchContext* Detach() { return &NullInstance(); }
// Returns the updated priority of the resource based on the experiments that
// may be currently enabled.
@@ -308,12 +247,16 @@ class PLATFORM_EXPORT FetchContext
virtual void DispatchNetworkQuiet() {}
protected:
- explicit FetchContext(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ // The following methods are needed to make FetchContext cleanup smoother.
+ // Do not use these functions for other purposes.
+ // TODO(yhirano): Remove these.
+ virtual bool IsDetached() const { return false; }
+ scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner();
+ ResourceFetcher* GetFetcher() { return fetcher_; }
private:
Member<PlatformProbeSink> platform_probe_sink_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ Member<ResourceFetcher> fetcher_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
index 497d88babc2..01674de0c89 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
@@ -123,6 +123,13 @@ void FetchParameters::SetLazyImagePlaceholder() {
SetAllowImagePlaceholder();
}
+void FetchParameters::SetLazyImageDeferred() {
+ resource_request_.SetPreviewsState(resource_request_.GetPreviewsState() |
+ WebURLRequest::kLazyImageLoadDeferred);
+ DCHECK_EQ(kNone, image_request_optimization_);
+ image_request_optimization_ = kDeferImageLoad;
+}
+
void FetchParameters::SetAllowImagePlaceholder() {
DCHECK_EQ(kNone, image_request_optimization_);
if (!resource_request_.Url().ProtocolIsInHTTPFamily() ||
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
index 229410e1799..76b6099b865 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
@@ -182,9 +182,10 @@ class PLATFORM_EXPORT FetchParameters {
// Client LoFi preview bit.
void SetClientLoFiPlaceholder();
- // Configures the request to load an image as a placeholder and sets the
- // lazy image load bit.
+ // Configures the request to load an image as a placeholder or defers the
+ // image and sets the lazy image load bit.
void SetLazyImagePlaceholder();
+ void SetLazyImageDeferred();
// Configures the request to load an image placeholder if the request is
// eligible (e.g. the url's protocol is HTTP, etc.). If this request is
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
index 61413dc58ca..6baafa3705e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
@@ -260,10 +260,8 @@ void MemoryCache::PruneResources(PruneStrategy strategy) {
DCHECK(resource);
if (resource->IsLoaded() && resource->DecodedSize()) {
// Check to see if the remaining resources are too new to prune.
- double elapsed_time = prune_frame_time_stamp_ -
- resource_iter.value->last_decoded_access_time_;
if (strategy == kAutomaticPrune &&
- elapsed_time < delay_before_live_decoded_prune_)
+ prune_frame_time_stamp_ < delay_before_live_decoded_prune_)
continue;
resource->Prune();
if (size_ <= target_size)
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
index c452243a87a..4db0a2702b4 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
@@ -53,14 +53,11 @@ class MemoryCacheEntry final : public GarbageCollected<MemoryCacheEntry> {
return MakeGarbageCollected<MemoryCacheEntry>(resource);
}
- explicit MemoryCacheEntry(Resource* resource)
- : last_decoded_access_time_(0.0), resource_(resource) {}
+ explicit MemoryCacheEntry(Resource* resource) : resource_(resource) {}
void Trace(blink::Visitor*);
Resource* GetResource() const { return resource_; }
- double last_decoded_access_time_; // Used as a thrash guard
-
private:
void ClearResourceWeak(Visitor*);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
index aa91bb45165..04a6bdf5ac6 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
@@ -39,6 +39,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
namespace blink {
@@ -58,9 +59,9 @@ constexpr char kOneDayAfterOriginalRequest[] = "Fri, 26 May 1977 18:30:00 GMT";
class MemoryCacheCorrectnessTest : public testing::Test {
protected:
MockResource* ResourceFromResourceResponse(ResourceResponse response) {
- if (response.Url().IsNull())
- response.SetURL(KURL(kResourceURL));
- ResourceRequest request(response.Url());
+ if (response.CurrentRequestUrl().IsNull())
+ response.SetCurrentRequestUrl(KURL(kResourceURL));
+ ResourceRequest request(response.CurrentRequestUrl());
request.SetRequestorOrigin(GetSecurityOrigin());
MockResource* resource = MockResource::Create(request);
resource->SetResponse(response);
@@ -114,12 +115,15 @@ class MemoryCacheCorrectnessTest : public testing::Test {
global_memory_cache_ = ReplaceMemoryCacheForTesting(
MemoryCache::Create(platform_->test_task_runner()));
- MockFetchContext* context =
- MockFetchContext::Create(MockFetchContext::kShouldNotLoadNewResource);
security_origin_ = SecurityOrigin::CreateUniqueOpaque();
- context->SetSecurityOrigin(security_origin_);
-
- fetcher_ = ResourceFetcher::Create(context);
+ MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_);
+ properties->SetShouldBlockLoadingMainResource(true);
+ properties->SetShouldBlockLoadingSubResource(true);
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
}
void TearDown() override {
GetMemoryCache()->EvictResources();
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
index 837ad739e84..114d19cb603 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
@@ -39,6 +39,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -107,8 +108,10 @@ class MemoryCacheTest : public testing::Test {
// Save the global memory cache to restore it upon teardown.
global_memory_cache_ = ReplaceMemoryCacheForTesting(
MemoryCache::Create(platform_->test_task_runner()));
- fetcher_ = ResourceFetcher::Create(
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource));
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, MakeGarbageCollected<MockFetchContext>(),
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
}
void TearDown() override {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
new file mode 100644
index 00000000000..f1b24d507df
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
@@ -0,0 +1,31 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h"
+
+#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+NullResourceFetcherProperties::NullResourceFetcherProperties()
+ : fetch_client_settings_object_(
+ *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ KURL(),
+ nullptr /* security_origin */,
+ network::mojom::ReferrerPolicy::kDefault,
+ String(),
+ HttpsState::kNone,
+ AllowedByNosniff::MimeTypeCheck::kStrict)) {}
+
+void NullResourceFetcherProperties::Trace(Visitor* visitor) {
+ visitor->Trace(fetch_client_settings_object_);
+ ResourceFetcherProperties::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h b/chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h
new file mode 100644
index 00000000000..7f6867a44e9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_NULL_RESOURCE_FETCHER_PROPERTIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_NULL_RESOURCE_FETCHER_PROPERTIES_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+// NullResourceFetcherProperties is a ResourceFetcherProperties implementation
+// which returns default values.
+// This is used for ResourceFetchers with a detached document, as well as tests.
+class PLATFORM_EXPORT NullResourceFetcherProperties final
+ : public ResourceFetcherProperties {
+ public:
+ NullResourceFetcherProperties();
+ ~NullResourceFetcherProperties() override = default;
+
+ void Trace(Visitor*) override;
+
+ // ResourceFetcherProperties implementation
+ const FetchClientSettingsObject& GetFetchClientSettingsObject()
+ const override {
+ return *fetch_client_settings_object_;
+ }
+ bool IsMainFrame() const override { return false; }
+ ControllerServiceWorkerMode GetControllerServiceWorkerMode() const override {
+ return ControllerServiceWorkerMode::kNoController;
+ }
+ int64_t ServiceWorkerId() const override {
+ NOTREACHED();
+ return 0;
+ }
+ bool IsPaused() const override { return false; }
+ bool IsDetached() const override { return true; }
+ bool IsLoadComplete() const override { return true; }
+ bool ShouldBlockLoadingMainResource() const override { return true; }
+ bool ShouldBlockLoadingSubResource() const override { return true; }
+
+ private:
+ const Member<const FetchClientSettingsObject> fetch_client_settings_object_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_NULL_RESOURCE_FETCHER_PROPERTIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
index bbf09a00d31..a6f9b53523a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
@@ -75,7 +75,8 @@ RawResource* RawResource::FetchMainResource(
FetchParameters& params,
ResourceFetcher* fetcher,
RawResourceClient* client,
- const SubstituteData& substitute_data) {
+ const SubstituteData& substitute_data,
+ unsigned long identifier) {
DCHECK_NE(params.GetResourceRequest().GetFrameType(),
network::mojom::RequestContextFrameType::kNone);
DCHECK(params.GetResourceRequest().GetRequestContext() ==
@@ -93,7 +94,7 @@ RawResource* RawResource::FetchMainResource(
return ToRawResource(fetcher->RequestResource(
params, RawResourceFactory(ResourceType::kMainResource), client,
- substitute_data));
+ substitute_data, identifier));
}
RawResource* RawResource::FetchMedia(FetchParameters& params,
@@ -249,7 +250,8 @@ CachedMetadataHandler* RawResource::CreateCachedMetadataHandler(
return Resource::CreateCachedMetadataHandler(std::move(send_callback));
}
-void RawResource::SetSerializedCachedMetadata(const char* data, size_t size) {
+void RawResource::SetSerializedCachedMetadata(const uint8_t* data,
+ size_t size) {
Resource::SetSerializedCachedMetadata(data, size);
if (GetType() == ResourceType::kMainResource) {
@@ -278,7 +280,7 @@ void RawResource::DidSendData(unsigned long long bytes_sent,
c->DataSent(this, bytes_sent, total_bytes_to_be_sent);
}
-void RawResource::DidDownloadData(int data_length) {
+void RawResource::DidDownloadData(unsigned long long data_length) {
ResourceClientWalker<RawResourceClient> w(Clients());
while (RawResourceClient* c = w.Next())
c->DataDownloaded(this, data_length);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
index 7f5e4200ce9..7e496f98be2 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
@@ -52,7 +52,8 @@ class PLATFORM_EXPORT RawResource final : public Resource {
static RawResource* FetchMainResource(FetchParameters&,
ResourceFetcher*,
RawResourceClient*,
- const SubstituteData&);
+ const SubstituteData&,
+ unsigned long identifier);
static RawResource* FetchImport(FetchParameters&,
ResourceFetcher*,
RawResourceClient*);
@@ -89,7 +90,7 @@ class PLATFORM_EXPORT RawResource final : public Resource {
bool WillFollowRedirect(const ResourceRequest&,
const ResourceResponse&) override;
- void SetSerializedCachedMetadata(const char*, size_t) override;
+ void SetSerializedCachedMetadata(const uint8_t*, size_t) override;
// Used for code caching of scripts with source code inline in the HTML.
// Returns a cache handler which can store multiple cache metadata entries,
@@ -133,7 +134,7 @@ class PLATFORM_EXPORT RawResource final : public Resource {
std::unique_ptr<WebDataConsumerHandle>) override;
void DidSendData(unsigned long long bytes_sent,
unsigned long long total_bytes_to_be_sent) override;
- void DidDownloadData(int) override;
+ void DidDownloadData(unsigned long long) override;
void DidDownloadToBlob(scoped_refptr<BlobDataHandle>) override;
void ReportResourceTimingToClients(const ResourceTimingInfo&) override;
bool MatchPreload(const FetchParameters&,
@@ -190,14 +191,14 @@ class PLATFORM_EXPORT RawResourceClient : public ResourceClient {
virtual void ResponseReceived(Resource*,
const ResourceResponse&,
std::unique_ptr<WebDataConsumerHandle>) {}
- virtual void SetSerializedCachedMetadata(Resource*, const char*, size_t) {}
+ virtual void SetSerializedCachedMetadata(Resource*, const uint8_t*, size_t) {}
virtual bool RedirectReceived(Resource*,
const ResourceRequest&,
const ResourceResponse&) {
return true;
}
virtual void RedirectBlocked() {}
- virtual void DataDownloaded(Resource*, int) {}
+ virtual void DataDownloaded(Resource*, unsigned long long) {}
virtual void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) {}
// Called for requests that had DownloadToBlob set to true. Can be called with
// null if creating the blob failed for some reason (but the download itself
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
index a28d04aeafc..a33d67e27ed 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
@@ -167,7 +167,7 @@ TEST_F(RawResourceTest, AddClientDuringCallback) {
Persistent<DummyClient> dummy_client = MakeGarbageCollected<DummyClient>();
Persistent<AddingClient> adding_client =
- new AddingClient(dummy_client.Get(), raw);
+ MakeGarbageCollected<AddingClient>(dummy_client.Get(), raw);
raw->AddClient(adding_client, platform_->test_task_runner().get());
platform_->RunUntilIdle();
raw->RemoveClient(adding_client);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 335f6c1218d..a20c89be899 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -31,6 +31,7 @@
#include <memory>
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
@@ -69,6 +70,12 @@ void NotifyFinishObservers(
observer->NotifyFinished();
}
+blink::mojom::CodeCacheType ToCodeCacheType(ResourceType resource_type) {
+ return resource_type == ResourceType::kRaw
+ ? blink::mojom::CodeCacheType::kWebAssembly
+ : blink::mojom::CodeCacheType::kJavascript;
+}
+
} // namespace
// These response headers are not copied from a revalidated response to the
@@ -99,12 +106,12 @@ const char* const kHeaderPrefixesToIgnoreAfterRevalidation[] = {
static inline bool ShouldUpdateHeaderAfterRevalidation(
const AtomicString& header) {
- for (size_t i = 0; i < arraysize(kHeadersToIgnoreAfterRevalidation); i++) {
+ for (size_t i = 0; i < base::size(kHeadersToIgnoreAfterRevalidation); i++) {
if (DeprecatedEqualIgnoringCase(header,
kHeadersToIgnoreAfterRevalidation[i]))
return false;
}
- for (size_t i = 0; i < arraysize(kHeaderPrefixesToIgnoreAfterRevalidation);
+ for (size_t i = 0; i < base::size(kHeaderPrefixesToIgnoreAfterRevalidation);
i++) {
if (header.StartsWithIgnoringASCIICase(
kHeaderPrefixesToIgnoreAfterRevalidation[i]))
@@ -113,78 +120,6 @@ static inline bool ShouldUpdateHeaderAfterRevalidation(
return true;
}
-// This is a CachedMetadataSender implementation for normal responses.
-class CachedMetadataSenderImpl : public CachedMetadataSender {
- public:
- CachedMetadataSenderImpl(const Resource*);
- ~CachedMetadataSenderImpl() override = default;
-
- void Send(const char*, size_t) override;
- bool IsServedFromCacheStorage() override { return false; }
-
- private:
- const KURL response_url_;
- const Time response_time_;
- const ResourceType resource_type_;
-};
-
-CachedMetadataSenderImpl::CachedMetadataSenderImpl(const Resource* resource)
- : response_url_(resource->GetResponse().Url()),
- response_time_(resource->GetResponse().ResponseTime()),
- resource_type_(resource->GetType()) {
- DCHECK(resource->GetResponse().CacheStorageCacheName().IsNull());
-}
-
-void CachedMetadataSenderImpl::Send(const char* data, size_t size) {
- Platform::Current()->CacheMetadata(
- Resource::ResourceTypeToCodeCacheType(resource_type_), response_url_,
- response_time_, data, size);
-}
-
-// This is a CachedMetadataSender implementation that does nothing.
-class NullCachedMetadataSender : public CachedMetadataSender {
- public:
- NullCachedMetadataSender() = default;
- ~NullCachedMetadataSender() override = default;
-
- void Send(const char*, size_t) override {}
- bool IsServedFromCacheStorage() override { return false; }
-};
-
-// This is a CachedMetadataSender implementation for responses that are served
-// by a ServiceWorker from cache storage.
-class ServiceWorkerCachedMetadataSender : public CachedMetadataSender {
- public:
- ServiceWorkerCachedMetadataSender(const Resource*, const SecurityOrigin*);
- ~ServiceWorkerCachedMetadataSender() override = default;
-
- void Send(const char*, size_t) override;
- bool IsServedFromCacheStorage() override { return true; }
-
- private:
- const KURL response_url_;
- const Time response_time_;
- const String cache_storage_cache_name_;
- scoped_refptr<const SecurityOrigin> security_origin_;
-};
-
-ServiceWorkerCachedMetadataSender::ServiceWorkerCachedMetadataSender(
- const Resource* resource,
- const SecurityOrigin* security_origin)
- : response_url_(resource->GetResponse().Url()),
- response_time_(resource->GetResponse().ResponseTime()),
- cache_storage_cache_name_(
- resource->GetResponse().CacheStorageCacheName()),
- security_origin_(security_origin) {
- DCHECK(!cache_storage_cache_name_.IsNull());
-}
-
-void ServiceWorkerCachedMetadataSender::Send(const char* data, size_t size) {
- Platform::Current()->CacheMetadataInCacheStorage(
- response_url_, response_time_, data, size,
- WebSecurityOrigin(security_origin_), cache_storage_cache_name_);
-}
-
Resource::Resource(const ResourceRequest& request,
ResourceType type,
const ResourceLoaderOptions& options)
@@ -350,7 +285,7 @@ static bool NeedsSynchronousCacheHit(ResourceType type,
if (options.synchronous_policy == kRequestSynchronously)
return true;
// Some resources types default to return data synchronously. For most of
- // these, it's because there are layout tests that expect data to return
+ // these, it's because there are web tests that expect data to return
// synchronously in case of cache hit. In the case of fonts, there was a
// performance regression.
// FIXME: Get to the point where we don't need to special-case sync/async
@@ -452,13 +387,13 @@ static double FreshnessLifetime(const ResourceResponse& response,
double response_timestamp) {
#if !defined(OS_ANDROID)
// On desktop, local files should be reloaded in case they change.
- if (response.Url().IsLocalFile())
+ if (response.CurrentRequestUrl().IsLocalFile())
return 0;
#endif
// Cache other non-http / non-filesystem resources liberally.
- if (!response.Url().ProtocolIsInHTTPFamily() &&
- !response.Url().ProtocolIs("filesystem"))
+ if (!response.CurrentRequestUrl().ProtocolIsInHTTPFamily() &&
+ !response.CurrentRequestUrl().ProtocolIs("filesystem"))
return std::numeric_limits<double>::max();
// RFC2616 13.2.4
@@ -539,27 +474,14 @@ void Resource::SetResponse(const ResourceResponse& response) {
// Currently we support the metadata caching only for HTTP family.
if (!GetResourceRequest().Url().ProtocolIsInHTTPFamily() ||
- !GetResponse().Url().ProtocolIsInHTTPFamily()) {
+ !GetResponse().CurrentRequestUrl().ProtocolIsInHTTPFamily()) {
cache_handler_.Clear();
return;
}
- cache_handler_ = CreateCachedMetadataHandler(CreateCachedMetadataSender());
-}
-
-std::unique_ptr<CachedMetadataSender> Resource::CreateCachedMetadataSender()
- const {
- if (GetResponse().WasFetchedViaServiceWorker()) {
- scoped_refptr<const SecurityOrigin> origin =
- GetResourceRequest().RequestorOrigin();
- // TODO(leszeks): Check whether it's correct that |origin| can be nullptr.
- if (!origin || GetResponse().CacheStorageCacheName().IsNull()) {
- return std::make_unique<NullCachedMetadataSender>();
- }
- return std::make_unique<ServiceWorkerCachedMetadataSender>(this,
- origin.get());
- }
- return std::make_unique<CachedMetadataSenderImpl>(this);
+ cache_handler_ = CreateCachedMetadataHandler(
+ CachedMetadataSender::Create(GetResponse(), ToCodeCacheType(GetType()),
+ GetResourceRequest().RequestorOrigin()));
}
void Resource::ResponseReceived(const ResourceResponse& response,
@@ -578,7 +500,7 @@ void Resource::ResponseReceived(const ResourceResponse& response,
SetEncoding(encoding);
}
-void Resource::SetSerializedCachedMetadata(const char* data, size_t size) {
+void Resource::SetSerializedCachedMetadata(const uint8_t* data, size_t size) {
DCHECK(!is_revalidating_);
DCHECK(!GetResponse().IsNull());
}
@@ -1021,8 +943,9 @@ void Resource::ClearRangeRequestHeader() {
void Resource::RevalidationSucceeded(
const ResourceResponse& validating_response) {
SECURITY_CHECK(redirect_chain_.IsEmpty());
- SECURITY_CHECK(EqualIgnoringFragmentIdentifier(validating_response.Url(),
- GetResponse().Url()));
+ SECURITY_CHECK(
+ EqualIgnoringFragmentIdentifier(validating_response.CurrentRequestUrl(),
+ GetResponse().CurrentRequestUrl()));
response_.SetResourceLoadTiming(validating_response.GetResourceLoadTiming());
// RFC2616 10.3.5
@@ -1265,15 +1188,15 @@ const char* Resource::ResourceTypeToString(
// static
blink::mojom::CodeCacheType Resource::ResourceTypeToCodeCacheType(
ResourceType resource_type) {
- // Cacheable WebAssembly modules are fetched, so raw resource type.
- if (resource_type == ResourceType::kRaw)
- return blink::mojom::CodeCacheType::kWebAssembly;
- // Cacheable Javascript is a script or a document resource. Also accept mock
- // resources for testing.
- DCHECK(resource_type == ResourceType::kScript ||
- resource_type == ResourceType::kMainResource ||
- resource_type == ResourceType::kMock);
- return blink::mojom::CodeCacheType::kJavascript;
+ DCHECK(
+ // Cacheable WebAssembly modules are fetched, so raw resource type.
+ resource_type == ResourceType::kRaw ||
+ // Cacheable Javascript is a script or a document resource.
+ resource_type == ResourceType::kScript ||
+ resource_type == ResourceType::kMainResource ||
+ // Also accept mock resources for testing.
+ resource_type == ResourceType::kMock);
+ return ToCodeCacheType(resource_type);
}
bool Resource::ShouldBlockLoadEvent() const {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h
index 3847b60c346..ac52ace54cd 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -26,6 +26,7 @@
#include <memory>
#include "base/auto_reset.h"
+#include "base/callback.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
@@ -86,18 +87,6 @@ enum class ResourceType : uint8_t {
kMock // Only for testing
};
-// A callback for sending the serialized data of cached metadata back to the
-// platform.
-class CachedMetadataSender {
- public:
- virtual ~CachedMetadataSender() = default;
- virtual void Send(const char*, size_t) = 0;
-
- // IsServedFromCacheStorage is used to alter caching strategy to be more
- // aggressive. See ScriptController.cpp CacheOptions() for an example.
- virtual bool IsServedFromCacheStorage() = 0;
-};
-
// A resource that is held in the cache. Classes who want to use this object
// should derive from ResourceClient, to get the function calls in case the
// requested data has arrived. This class also does the actual communication
@@ -282,7 +271,7 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
// Sets the serialized metadata retrieved from the platform's cache.
// Subclasses of Resource that support cached metadata should override this
// method with one that fills the current CachedMetadataHandler.
- virtual void SetSerializedCachedMetadata(const char*, size_t);
+ virtual void SetSerializedCachedMetadata(const uint8_t*, size_t);
AtomicString HttpContentType() const;
@@ -350,7 +339,7 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
virtual void DidSendData(unsigned long long /* bytesSent */,
unsigned long long /* totalBytesToBeSent */) {}
- virtual void DidDownloadData(int) {}
+ virtual void DidDownloadData(unsigned long long) {}
virtual void DidDownloadToBlob(scoped_refptr<BlobDataHandle>) {}
TimeTicks LoadFinishTime() const { return load_finish_time_; }
@@ -428,6 +417,14 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
return virtual_time_pauser_;
}
+ // See WebURLLoaderClient.
+ base::OnceClosure TakeContinueNavigationRequestCallback() {
+ return std::move(continue_navigation_request_callback_);
+ }
+ void SetContinueNavigationRequestCallback(base::OnceClosure closure) {
+ continue_navigation_request_callback_ = std::move(closure);
+ }
+
protected:
Resource(const ResourceRequest&, ResourceType, const ResourceLoaderOptions&);
@@ -530,10 +527,6 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
void CheckResourceIntegrity();
void TriggerNotificationForFinishObservers(base::SingleThreadTaskRunner*);
- // Helper for creating the send callback function for the cached metadata
- // handler.
- std::unique_ptr<CachedMetadataSender> CreateCachedMetadataSender() const;
-
ResourceType type_;
ResourceStatus status_;
@@ -590,6 +583,7 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
scoped_refptr<SharedBuffer> data_;
WebScopedVirtualTimePauser virtual_time_pauser_;
+ base::OnceClosure continue_navigation_request_callback_;
};
class ResourceFactory {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 4b1f9320013..a8a972f4656 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -34,8 +34,9 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/time/time.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
@@ -44,10 +45,13 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
@@ -111,19 +115,6 @@ constexpr base::TimeDelta kKeepaliveLoadersTimeout =
DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, XSLStyleSheet) \
}
-void AddRedirectsToTimingInfo(Resource* resource, ResourceTimingInfo* info) {
- // Store redirect responses that were packed inside the final response.
- const auto& responses = resource->GetResponse().RedirectResponses();
- for (wtf_size_t i = 0; i < responses.size(); ++i) {
- const KURL& new_url = i + 1 < responses.size()
- ? KURL(responses[i + 1].Url())
- : resource->GetResourceRequest().Url();
- bool cross_origin =
- !SecurityOrigin::AreSameSchemeHostPort(responses[i].Url(), new_url);
- info->AddRedirect(responses[i], cross_origin);
- }
-}
-
ResourceLoadPriority TypeToPriority(ResourceType type) {
switch (type) {
case ResourceType::kMainResource:
@@ -195,9 +186,6 @@ ResourceLoadPriority AdjustPriorityWithPriorityHint(
mojom::FetchImportanceMode importance_mode =
resource_request.GetFetchImportanceMode();
- DCHECK(importance_mode == mojom::FetchImportanceMode::kImportanceAuto ||
- RuntimeEnabledFeatures::PriorityHintsEnabled());
-
ResourceLoadPriority new_priority = priority_so_far;
switch (importance_mode) {
@@ -243,25 +231,42 @@ const base::Feature kStaleWhileRevalidateExperiment{
"StaleWhileRevalidateExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
bool MatchesStaleWhileRevalidateControlList(const String& host) {
- DEFINE_STATIC_LOCAL(String, kStaleWhileRevalidateControlHosts,
- (GetFieldTrialParamValueByFeature(
- kStaleWhileRevalidateExperiment, "control_hosts")
- .c_str()));
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<String>,
+ stale_while_revalidate_control_hosts, ());
+ if (stale_while_revalidate_control_hosts->IsNull()) {
+ *stale_while_revalidate_control_hosts =
+ GetFieldTrialParamValueByFeature(kStaleWhileRevalidateExperiment,
+ "control_hosts")
+ .c_str();
+ }
return !host.IsEmpty() &&
- kStaleWhileRevalidateControlHosts.Find(host) != kNotFound;
+ stale_while_revalidate_control_hosts->Find(host) != kNotFound;
}
bool MatchesStaleWhileRevalidateAllowList(const String& host) {
- DEFINE_STATIC_LOCAL(String, kStaleWhileRevalidateAllowHosts,
- (GetFieldTrialParamValueByFeature(
- kStaleWhileRevalidateExperiment, "hosts")
- .c_str()));
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<String>,
+ stale_while_revalidate_allow_hosts, ());
+ if (stale_while_revalidate_allow_hosts->IsNull()) {
+ *stale_while_revalidate_allow_hosts =
+ GetFieldTrialParamValueByFeature(kStaleWhileRevalidateExperiment,
+ "hosts")
+ .c_str();
+ }
return !host.IsEmpty() &&
- kStaleWhileRevalidateAllowHosts.Find(host) != kNotFound;
+ stale_while_revalidate_allow_hosts->Find(host) != kNotFound;
}
} // namespace
+ResourceFetcherInit::ResourceFetcherInit(
+ const ResourceFetcherProperties& properties,
+ FetchContext* context,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : ResourceFetcherInit(properties,
+ context,
+ std::move(task_runner),
+ *MakeGarbageCollected<NullConsoleLogger>()) {}
+
ResourceLoadPriority ResourceFetcher::ComputeLoadPriority(
ResourceType type,
const ResourceRequest& resource_request,
@@ -328,14 +333,6 @@ ResourceLoadPriority ResourceFetcher::ComputeLoadPriority(
resource_request.Priority());
}
-static void PopulateTimingInfo(ResourceTimingInfo* info, Resource* resource) {
- KURL initial_url = resource->GetResponse().RedirectResponses().IsEmpty()
- ? resource->GetResourceRequest().Url()
- : resource->GetResponse().RedirectResponses()[0].Url();
- info->SetInitialURL(initial_url);
- info->SetFinalResponse(resource->GetResponse());
-}
-
mojom::RequestContextType ResourceFetcher::DetermineRequestContext(
ResourceType type,
IsImageSet is_image_set,
@@ -385,12 +382,93 @@ mojom::RequestContextType ResourceFetcher::DetermineRequestContext(
return mojom::RequestContextType::SUBRESOURCE;
}
-ResourceFetcher::ResourceFetcher(FetchContext* new_context)
- : context_(new_context),
- scheduler_(ResourceLoadScheduler::Create(&Context())),
- archive_(Context().IsMainFrame() ? nullptr : Context().Archive()),
+// A delegating ResourceFetcherProperties subclass which can be from the
+// original ResourceFetcherProperties.
+class ResourceFetcher::DetachableProperties final
+ : public ResourceFetcherProperties {
+ public:
+ explicit DetachableProperties(const ResourceFetcherProperties& properties)
+ : properties_(properties) {}
+ ~DetachableProperties() override = default;
+
+ void Detach() {
+ if (!properties_) {
+ // Already detached.
+ return;
+ }
+
+ fetch_client_settings_object_ =
+ MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ properties_->GetFetchClientSettingsObject());
+ is_main_frame_ = properties_->IsMainFrame();
+ paused_ = properties_->IsPaused();
+ load_complete_ = properties_->IsLoadComplete();
+
+ properties_ = nullptr;
+ }
+
+ void Trace(Visitor* visitor) override {
+ visitor->Trace(properties_);
+ visitor->Trace(fetch_client_settings_object_);
+ ResourceFetcherProperties::Trace(visitor);
+ }
+
+ // ResourceFetcherProperties implementation
+ // Add a test in resource_fetcher_test.cc when you change behaviors.
+ const FetchClientSettingsObject& GetFetchClientSettingsObject()
+ const override {
+ return properties_ ? properties_->GetFetchClientSettingsObject()
+ : *fetch_client_settings_object_;
+ }
+ bool IsMainFrame() const override {
+ return properties_ ? properties_->IsMainFrame() : is_main_frame_;
+ }
+ ControllerServiceWorkerMode GetControllerServiceWorkerMode() const override {
+ return properties_ ? properties_->GetControllerServiceWorkerMode()
+ : ControllerServiceWorkerMode::kNoController;
+ }
+ int64_t ServiceWorkerId() const override {
+ // When detached, GetControllerServiceWorkerMode returns kNoController, so
+ // this function must not be called.
+ DCHECK(properties_);
+ return properties_->ServiceWorkerId();
+ }
+ bool IsPaused() const override {
+ return properties_ ? properties_->IsPaused() : paused_;
+ }
+ bool IsDetached() const override { return !properties_; }
+ bool IsLoadComplete() const override {
+ return properties_ ? properties_->IsLoadComplete() : load_complete_;
+ }
+ bool ShouldBlockLoadingMainResource() const override {
+ // Returns true when detached in order to preserve the existing behavior.
+ return properties_ ? properties_->ShouldBlockLoadingMainResource() : true;
+ }
+ bool ShouldBlockLoadingSubResource() const override {
+ // Returns true when detached in order to preserve the existing behavior.
+ return properties_ ? properties_->ShouldBlockLoadingSubResource() : true;
+ }
+
+ private:
+ // |properties_| is null if and only if detached.
+ Member<const ResourceFetcherProperties> properties_;
+
+ // The following members are used when detached.
+ Member<const FetchClientSettingsObject> fetch_client_settings_object_;
+ bool is_main_frame_ = false;
+ bool paused_ = false;
+ bool load_complete_ = false;
+};
+
+ResourceFetcher::ResourceFetcher(const ResourceFetcherInit& init)
+ : properties_(
+ *MakeGarbageCollected<DetachableProperties>(*init.properties)),
+ context_(init.context),
+ task_runner_(init.task_runner),
+ console_logger_(init.console_logger),
+ archive_(init.archive),
resource_timing_report_timer_(
- Context().GetLoadingTaskRunner(),
+ task_runner_,
this,
&ResourceFetcher::ResourceTimingReportTimerFired),
auto_load_images_(true),
@@ -398,15 +476,23 @@ ResourceFetcher::ResourceFetcher(FetchContext* new_context)
allow_stale_resources_(false),
image_fetched_(false),
stale_while_revalidate_enabled_(false) {
+ DCHECK(console_logger_);
InstanceCounters::IncrementCounter(InstanceCounters::kResourceFetcherCounter);
if (IsMainThread())
MainThreadFetchersSet().insert(this);
+ context_->Bind(this);
+ scheduler_ = MakeGarbageCollected<ResourceLoadScheduler>(
+ init.initial_throttling_policy, context_);
}
ResourceFetcher::~ResourceFetcher() {
InstanceCounters::DecrementCounter(InstanceCounters::kResourceFetcherCounter);
}
+const ResourceFetcherProperties& ResourceFetcher::GetProperties() const {
+ return *properties_;
+}
+
Resource* ResourceFetcher::CachedResource(const KURL& resource_url) const {
if (resource_url.IsEmpty())
return nullptr;
@@ -415,22 +501,9 @@ Resource* ResourceFetcher::CachedResource(const KURL& resource_url) const {
return resource.Get();
}
-void ResourceFetcher::HoldResourcesFromPreviousFetcher(
- ResourceFetcher* old_fetcher) {
- DCHECK(resources_from_previous_fetcher_.IsEmpty());
- for (Resource* resource : old_fetcher->document_resources_) {
- if (GetMemoryCache()->Contains(resource))
- resources_from_previous_fetcher_.insert(resource);
- }
-}
-
-void ResourceFetcher::ClearResourcesFromPreviousFetcher() {
- resources_from_previous_fetcher_.clear();
-}
-
-blink::mojom::ControllerServiceWorkerMode
+mojom::ControllerServiceWorkerMode
ResourceFetcher::IsControlledByServiceWorker() const {
- return Context().IsControlledByServiceWorker();
+ return properties_->GetControllerServiceWorkerMode();
}
bool ResourceFetcher::ResourceNeedsLoad(Resource* resource,
@@ -476,8 +549,15 @@ void ResourceFetcher::RequestLoadStarted(unsigned long identifier,
scoped_refptr<ResourceTimingInfo> info = ResourceTimingInfo::Create(
params.Options().initiator_info.name, CurrentTimeTicks(),
resource->GetType() == ResourceType::kMainResource);
- PopulateTimingInfo(info.get(), resource);
- info->ClearLoadTimings();
+ // TODO(yoav): GetInitialUrlForResourceTiming() is only needed until
+ // Out-of-Blink CORS lands: https://crbug.com/736308
+ info->SetInitialURL(
+ resource->GetResourceRequest().GetInitialUrlForResourceTiming().IsNull()
+ ? resource->GetResourceRequest().Url()
+ : resource->GetResourceRequest().GetInitialUrlForResourceTiming());
+ ResourceResponse final_response = resource->GetResponse();
+ final_response.SetResourceLoadTiming(nullptr);
+ info->SetFinalResponse(final_response);
info->SetLoadFinishTime(info->InitialTime());
scheduled_resource_timing_reports_.push_back(std::move(info));
if (!resource_timing_report_timer_.IsActive())
@@ -488,22 +568,14 @@ void ResourceFetcher::RequestLoadStarted(unsigned long identifier,
void ResourceFetcher::DidLoadResourceFromMemoryCache(
unsigned long identifier,
Resource* resource,
- const ResourceRequest& original_resource_request) {
- ResourceRequest resource_request(resource->Url());
- resource_request.SetFrameType(original_resource_request.GetFrameType());
- resource_request.SetRequestContext(
- original_resource_request.GetRequestContext());
- if (original_resource_request.IsAdResource())
- resource_request.SetIsAdResource();
+ const ResourceRequest& original_request) {
+ ResourceRequest request = original_request;
- Context().DispatchDidLoadResourceFromMemoryCache(identifier, resource_request,
- resource->GetResponse());
Context().DispatchWillSendRequest(
- identifier, resource_request, ResourceResponse() /* redirects */,
+ identifier, request, ResourceResponse() /* redirects */,
resource->GetType(), resource->Options().initiator_info);
Context().DispatchDidReceiveResponse(
- identifier, resource->GetResponse(), resource_request.GetFrameType(),
- resource_request.GetRequestContext(), resource,
+ identifier, request, resource->GetResponse(), resource,
FetchContext::ResourceResponseType::kFromMemoryCache);
if (resource->EncodedSize() > 0) {
@@ -529,16 +601,10 @@ Resource* ResourceFetcher::ResourceForStaticData(
const KURL& url = params.GetResourceRequest().Url();
DCHECK(url.ProtocolIsData() || substitute_data.IsValid() || archive_);
- // TODO(japhet): We only send main resource data: urls through WebURLLoader
- // for the benefit of a service worker test
- // (RenderViewImplTest.ServiceWorkerNetworkProviderSetup), which is at a layer
- // where it isn't easy to mock out a network load. It uses data: urls to
- // emulate the behavior it wants to test, which would otherwise be reserved
- // for network loads.
if (!archive_ && !substitute_data.IsValid() &&
- (factory.GetType() == ResourceType::kMainResource ||
- factory.GetType() == ResourceType::kRaw))
+ factory.GetType() == ResourceType::kRaw) {
return nullptr;
+ }
const String cache_identifier = GetCacheIdentifier();
// Most off-main-thread resource fetches use Resource::kRaw and don't reach
@@ -558,7 +624,7 @@ Resource* ResourceFetcher::ResourceForStaticData(
scoped_refptr<SharedBuffer> data;
if (substitute_data.IsValid()) {
data = substitute_data.Content();
- response.SetURL(url);
+ response.SetCurrentRequestUrl(url);
response.SetMimeType(substitute_data.MimeType());
response.SetExpectedContentLength(data->size());
response.SetTextEncodingName(substitute_data.TextEncoding());
@@ -575,7 +641,7 @@ Resource* ResourceFetcher::ResourceForStaticData(
if (!archive_resource)
return nullptr;
data = archive_resource->Data();
- response.SetURL(url);
+ response.SetCurrentRequestUrl(url);
response.SetMimeType(archive_resource->MimeType());
response.SetExpectedContentLength(data->size());
response.SetTextEncodingName(archive_resource->TextEncoding());
@@ -591,7 +657,7 @@ Resource* ResourceFetcher::ResourceForStaticData(
resource->SetResourceBuffer(data);
resource->SetIdentifier(CreateUniqueIdentifier());
resource->SetCacheIdentifier(cache_identifier);
- resource->Finish(TimeTicks(), Context().GetLoadingTaskRunner().get());
+ resource->Finish(TimeTicks(), task_runner_.get());
if (!substitute_data.IsValid())
AddToMemoryCacheIfNeeded(params, resource);
@@ -607,10 +673,10 @@ Resource* ResourceFetcher::ResourceForBlockedRequest(
Resource* resource = factory.Create(
params.GetResourceRequest(), params.Options(), params.DecoderOptions());
if (client)
- client->SetResource(resource, Context().GetLoadingTaskRunner().get());
+ client->SetResource(resource, task_runner_.get());
resource->FinishAsError(ResourceError::CancelledDueToAccessCheckError(
params.Url(), blocked_reason),
- Context().GetLoadingTaskRunner().get());
+ task_runner_.get());
return resource;
}
@@ -673,7 +739,8 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
FetchParameters& params,
const ResourceFactory& factory,
const SubstituteData& substitute_data,
- unsigned long identifier) {
+ unsigned long identifier,
+ WebScopedVirtualTimePauser& virtual_time_pauser) {
ResourceRequest& resource_request = params.MutableResourceRequest();
ResourceType resource_type = factory.GetType();
const ResourceLoaderOptions& options = params.Options();
@@ -722,7 +789,7 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
if (resource_request.GetRequestContext() ==
mojom::RequestContextType::UNSPECIFIED) {
resource_request.SetRequestContext(DetermineRequestContext(
- resource_type, kImageNotImageSet, Context().IsMainFrame()));
+ resource_type, kImageNotImageSet, properties_->IsMainFrame()));
}
if (resource_type == ResourceType::kLinkPrefetch)
resource_request.SetHTTPHeaderField(http_names::kPurpose, "prefetch");
@@ -780,9 +847,9 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
if (blocked_reason)
return blocked_reason;
- // For initial requests, call prepareRequest() here before revalidation
+ // For initial requests, call PrepareRequest() here before revalidation
// policy is determined.
- Context().PrepareRequest(resource_request,
+ Context().PrepareRequest(resource_request, virtual_time_pauser,
FetchContext::RedirectType::kNotForRedirect);
if (!params.Url().IsValid())
@@ -819,8 +886,10 @@ Resource* ResourceFetcher::RequestResource(
FetchParameters& params,
const ResourceFactory& factory,
ResourceClient* client,
- const SubstituteData& substitute_data) {
- unsigned long identifier = CreateUniqueIdentifier();
+ const SubstituteData& substitute_data,
+ unsigned long identifier) {
+ if (!identifier)
+ identifier = CreateUniqueIdentifier();
ResourceRequest& resource_request = params.MutableResourceRequest();
network_instrumentation::ScopedResourceLoadTracker
scoped_resource_load_tracker(identifier, resource_request);
@@ -837,17 +906,20 @@ Resource* ResourceFetcher::RequestResource(
if (context_) {
const KURL& url = params.Url();
if (url.HasFragmentIdentifier() && url.ProtocolIsData()) {
- context_->RecordDataUriWithOctothorpe();
+ context_->CountUsage(mojom::WebFeature::kDataUriHasOctothorpe);
}
}
// |resource_request|'s origin can be null here, corresponding to the "client"
// value in the spec. In that case client's origin is used.
- if (!resource_request.RequestorOrigin())
- resource_request.SetRequestorOrigin(Context().GetSecurityOrigin());
+ if (!resource_request.RequestorOrigin()) {
+ resource_request.SetRequestorOrigin(
+ properties_->GetFetchClientSettingsObject().GetSecurityOrigin());
+ }
+ WebScopedVirtualTimePauser pauser;
base::Optional<ResourceRequestBlockedReason> blocked_reason =
- PrepareRequest(params, factory, substitute_data, identifier);
+ PrepareRequest(params, factory, substitute_data, identifier, pauser);
if (blocked_reason) {
return ResourceForBlockedRequest(params, factory, blocked_reason.value(),
client);
@@ -935,11 +1007,13 @@ Resource* ResourceFetcher::RequestResource(
// TODO(yoav): turn to a DCHECK. See https://crbug.com/690632
CHECK_EQ(resource->GetType(), resource_type);
- if (policy != kUse)
+ if (policy != kUse) {
resource->SetIdentifier(identifier);
+ resource->VirtualTimePauser() = std::move(pauser);
+ }
if (client)
- client->SetResource(resource, Context().GetLoadingTaskRunner().get());
+ client->SetResource(resource, task_runner_.get());
// TODO(yoav): It is not clear why preloads are exempt from this check. Can we
// remove the exemption?
@@ -972,7 +1046,7 @@ Resource* ResourceFetcher::RequestResource(
if (ResourceNeedsLoad(resource, params, policy)) {
if (!StartLoad(resource)) {
resource->FinishAsError(ResourceError::CancelledError(params.Url()),
- Context().GetLoadingTaskRunner().get());
+ task_runner_.get());
}
}
@@ -1003,8 +1077,8 @@ void ResourceFetcher::InitializeRevalidation(
DCHECK(resource->IsLoaded());
DCHECK(resource->CanUseCacheValidator());
DCHECK(!resource->IsCacheValidator());
- DCHECK(Context().IsControlledByServiceWorker() ==
- blink::mojom::ControllerServiceWorkerMode::kNoController);
+ DCHECK_EQ(properties_->GetControllerServiceWorkerMode(),
+ mojom::ControllerServiceWorkerMode::kNoController);
// RawResource doesn't support revalidation.
CHECK(!IsRawResource(*resource));
@@ -1067,25 +1141,11 @@ void ResourceFetcher::StorePerformanceTimingInitiatorInformation(
if (fetch_initiator == fetch_initiator_type_names::kInternal)
return;
- bool is_main_resource = resource->GetType() == ResourceType::kMainResource;
-
- // The request can already be fetched in a previous navigation. Thus
- // startTime must be set accordingly.
- TimeTicks start_time =
- !resource->GetResourceRequest().NavigationStartTime().is_null()
- ? resource->GetResourceRequest().NavigationStartTime()
- : CurrentTimeTicks();
-
- // This buffer is created and populated for providing transferSize
- // and redirect timing opt-in information.
- if (is_main_resource) {
- DCHECK(!navigation_timing_info_);
- navigation_timing_info_ = ResourceTimingInfo::Create(
- fetch_initiator, start_time, is_main_resource);
- }
+ if (resource->GetType() == ResourceType::kMainResource)
+ return;
- scoped_refptr<ResourceTimingInfo> info =
- ResourceTimingInfo::Create(fetch_initiator, start_time, is_main_resource);
+ scoped_refptr<ResourceTimingInfo> info = ResourceTimingInfo::Create(
+ fetch_initiator, CurrentTimeTicks(), false /* is_main_resource */);
if (resource->IsCacheValidator()) {
const AtomicString& timing_allow_origin =
@@ -1094,25 +1154,16 @@ void ResourceFetcher::StorePerformanceTimingInitiatorInformation(
info->SetOriginalTimingAllowOrigin(timing_allow_origin);
}
- if (!is_main_resource ||
- Context().UpdateTimingInfoForIFrameNavigation(info.get())) {
- resource_timing_info_map_.insert(resource, std::move(info));
- }
+ resource_timing_info_map_.insert(resource, std::move(info));
}
void ResourceFetcher::RecordResourceTimingOnRedirect(
Resource* resource,
const ResourceResponse& redirect_response,
- bool cross_origin) {
+ const KURL& new_url) {
ResourceTimingInfoMap::iterator it = resource_timing_info_map_.find(resource);
- if (it != resource_timing_info_map_.end()) {
- it->value->AddRedirect(redirect_response, cross_origin);
- }
-
- if (resource->GetType() == ResourceType::kMainResource) {
- DCHECK(navigation_timing_info_);
- navigation_timing_info_->AddRedirect(redirect_response, cross_origin);
- }
+ if (it != resource_timing_info_map_.end())
+ it->value->AddRedirect(redirect_response, new_url);
}
static bool IsDownloadOrStreamRequest(const ResourceRequest& request) {
@@ -1159,7 +1210,7 @@ Resource* ResourceFetcher::MatchPreload(const FetchParameters& params,
return nullptr;
}
- if (!resource->MatchPreload(params, Context().GetLoadingTaskRunner().get())) {
+ if (!resource->MatchPreload(params, task_runner_.get())) {
PrintPreloadWarning(resource, Resource::MatchStatus::kUnknownFailure);
return nullptr;
}
@@ -1219,8 +1270,8 @@ void ResourceFetcher::PrintPreloadWarning(Resource* resource,
builder.Append("due to different image placeholder policies.");
break;
}
- Context().AddWarningConsoleMessage(builder.ToString(),
- FetchContext::kOtherSource);
+ console_logger_->AddWarningMessage(ConsoleLogger::Source::kOther,
+ builder.ToString());
}
void ResourceFetcher::InsertAsPreloadIfNecessary(Resource* resource,
@@ -1229,7 +1280,7 @@ void ResourceFetcher::InsertAsPreloadIfNecessary(Resource* resource,
if (!params.IsSpeculativePreload() && !params.IsLinkPreload())
return;
DCHECK(!params.IsStaleRevalidation());
- // CSP layout tests verify that preloads are subject to access checks by
+ // CSP web tests verify that preloads are subject to access checks by
// seeing if they are in the `preload started` list. Therefore do not add
// them to the list if the load is immediately denied.
if (resource->LoadFailedOrCanceled() &&
@@ -1374,7 +1425,7 @@ ResourceFetcher::DetermineRevalidationPolicyInternal(
// XHRs fall into this category and may have user-set Cache-Control: headers
// or other factors that require separate requests.
if (type != ResourceType::kRaw) {
- if (!Context().IsLoadComplete() &&
+ if (!properties_->IsLoadComplete() &&
cached_resources_map_.Contains(
MemoryCache::RemoveFragmentIdentifierIfNeeded(
existing_resource.Url())))
@@ -1439,8 +1490,8 @@ ResourceFetcher::DetermineRevalidationPolicyInternal(
// non-S13nSW, we don't know what controller the request will ultimately go
// to (due to skipWaiting) so be conservative.
if (existing_resource.CanUseCacheValidator() &&
- Context().IsControlledByServiceWorker() ==
- blink::mojom::ControllerServiceWorkerMode::kNoController) {
+ properties_->GetControllerServiceWorkerMode() ==
+ mojom::ControllerServiceWorkerMode::kNoController) {
// If the resource is already a cache validator but not started yet, the
// |Use| policy should be applied to subsequent requests.
if (existing_resource.IsCacheValidator()) {
@@ -1496,16 +1547,28 @@ void ResourceFetcher::ReloadImagesIfNotDeferred() {
}
FetchContext& ResourceFetcher::Context() const {
- return context_
- ? *context_.Get()
- : FetchContext::NullInstance(Thread::Current()->GetTaskRunner());
+ return *context_;
}
void ResourceFetcher::ClearContext() {
- DCHECK(resources_from_previous_fetcher_.IsEmpty());
scheduler_->Shutdown();
ClearPreloads(ResourceFetcher::kClearAllPreloads);
- context_ = Context().Detach();
+
+ {
+ // This block used to be
+ // context_ = Context().Detach();
+ // While we are splitting FetchContext to multiple classes we need to call
+ // "detach" for multiple objects in a coordinated manner. See
+ // https://crbug.com/914739 for the progress.
+ // TODO(yhirano): Remove the cross-class dependency.
+ auto* context = context_.Get();
+ context_ = Context().Detach();
+ context->Unbind();
+ properties_->Detach();
+ context_->Bind(this);
+ }
+
+ console_logger_ = MakeGarbageCollected<NullConsoleLogger>();
// Make sure the only requests still going are keepalive requests.
// Callers of ClearContext() should be calling StopFetching() prior
@@ -1520,7 +1583,7 @@ void ResourceFetcher::ClearContext() {
// to keep the ResourceFetcher and ResourceLoaders alive until the requests
// complete or the timer fires.
keepalive_loaders_task_handle_ = PostDelayedCancellableTask(
- *Context().GetLoadingTaskRunner(), FROM_HERE,
+ *task_runner_, FROM_HERE,
WTF::Bind(&ResourceFetcher::StopFetchingIncludingKeepaliveLoaders,
WrapPersistent(this)),
kKeepaliveLoadersTimeout);
@@ -1579,32 +1642,30 @@ Vector<KURL> ResourceFetcher::GetUrlsOfUnusedPreloads() {
return urls;
}
-ArchiveResource* ResourceFetcher::CreateArchive(Resource* resource) {
+ArchiveResource* ResourceFetcher::CreateArchive(
+ const KURL& url,
+ scoped_refptr<const SharedBuffer> buffer) {
// Only the top-frame can load MHTML.
- if (!Context().IsMainFrame()) {
- Context().AddErrorConsoleMessage(
+ if (!properties_->IsMainFrame()) {
+ console_logger_->AddErrorMessage(
+ ConsoleLogger::Source::kScript,
"Attempted to load a multipart archive into an subframe: " +
- resource->Url().GetString(),
- FetchContext::kJSSource);
+ url.GetString());
return nullptr;
}
- archive_ = MHTMLArchive::Create(resource->Url(), resource->ResourceBuffer());
+ archive_ = MHTMLArchive::Create(url, buffer);
if (!archive_) {
// Log if attempting to load an invalid archive resource.
- Context().AddErrorConsoleMessage(
- "Malformed multipart archive: " + resource->Url().GetString(),
- FetchContext::kJSSource);
+ console_logger_->AddErrorMessage(
+ ConsoleLogger::Source::kScript,
+ "Malformed multipart archive: " + url.GetString());
return nullptr;
}
return archive_->MainResource();
}
-ResourceTimingInfo* ResourceFetcher::GetNavigationTimingInfo() {
- return navigation_timing_info_.get();
-}
-
void ResourceFetcher::HandleLoadCompletion(Resource* resource) {
Context().DidLoadResource(resource);
@@ -1638,24 +1699,17 @@ void ResourceFetcher::HandleLoaderFinish(
const int64_t encoded_data_length =
resource->GetResponse().EncodedDataLength();
- if (resource->GetType() == ResourceType::kMainResource) {
- DCHECK(navigation_timing_info_);
- // Store redirect responses that were packed inside the final response.
- AddRedirectsToTimingInfo(resource, navigation_timing_info_.get());
- if (resource->GetResponse().IsHTTP()) {
- PopulateTimingInfo(navigation_timing_info_.get(), resource);
- navigation_timing_info_->AddFinalTransferSize(
- encoded_data_length == -1 ? 0 : encoded_data_length);
- }
- }
if (scoped_refptr<ResourceTimingInfo> info =
resource_timing_info_map_.Take(resource)) {
- // Store redirect responses that were packed inside the final response.
- AddRedirectsToTimingInfo(resource, info.get());
-
if (resource->GetResponse().IsHTTP() &&
resource->GetResponse().HttpStatusCode() < 400) {
- PopulateTimingInfo(info.get(), resource);
+ info->SetInitialURL(resource->GetResourceRequest()
+ .GetInitialUrlForResourceTiming()
+ .IsNull()
+ ? resource->GetResourceRequest().Url()
+ : resource->GetResourceRequest()
+ .GetInitialUrlForResourceTiming());
+ info->SetFinalResponse(resource->GetResponse());
info->SetLoadFinishTime(finish_time);
// encodedDataLength == -1 means "not available".
// TODO(ricea): Find cases where it is not available but the
@@ -1701,7 +1755,7 @@ void ResourceFetcher::HandleLoaderFinish(
resource->GetResponse().DecodedBodyLength(), should_report_corb_blocking);
if (type == kDidFinishLoading) {
- resource->Finish(finish_time, Context().GetLoadingTaskRunner().get());
+ resource->Finish(finish_time, task_runner_.get());
// Since this resource came from the network stack we only schedule a stale
// while revalidate request if the network asked us to. If we called
@@ -1756,7 +1810,7 @@ void ResourceFetcher::HandleLoaderError(Resource* resource,
if (error.IsCancellation())
RemovePreload(resource);
- resource->FinishAsError(error, Context().GetLoadingTaskRunner().get());
+ resource->FinishAsError(error, task_runner_.get());
HandleLoadCompletion(resource);
}
@@ -1794,14 +1848,7 @@ bool ResourceFetcher::StartLoad(Resource* resource) {
request, response,
resource->Options().initiator_info);
- if (Context().GetFrameScheduler()) {
- WebScopedVirtualTimePauser virtual_time_pauser =
- Context().GetFrameScheduler()->CreateWebScopedVirtualTimePauser(
- resource->Url().GetString(),
- WebScopedVirtualTimePauser::VirtualTaskDuration::kNonInstant);
- virtual_time_pauser.PauseVirtualTime();
- resource->VirtualTimePauser() = std::move(virtual_time_pauser);
- }
+ resource->VirtualTimePauser().PauseVirtualTime();
Context().DispatchWillSendRequest(resource->Identifier(), request, response,
resource->GetType(),
resource->Options().initiator_info);
@@ -1908,9 +1955,9 @@ void ResourceFetcher::ReloadLoFiImages() {
}
String ResourceFetcher::GetCacheIdentifier() const {
- if (Context().IsControlledByServiceWorker() !=
- blink::mojom::ControllerServiceWorkerMode::kNoController)
- return String::Number(Context().ServiceWorkerID());
+ if (properties_->GetControllerServiceWorkerMode() !=
+ mojom::ControllerServiceWorkerMode::kNoController)
+ return String::Number(properties_->ServiceWorkerId());
return MemoryCache::DefaultCacheIdentifier();
}
@@ -1980,7 +2027,7 @@ void ResourceFetcher::ScheduleStaleRevalidate(Resource* stale_resource) {
if (stale_resource->StaleRevalidationStarted())
return;
stale_resource->SetStaleRevalidationStarted();
- Context().GetLoadingTaskRunner()->PostTask(
+ task_runner_->PostTask(
FROM_HERE,
WTF::Bind(&ResourceFetcher::RevalidateStaleResource,
WrapWeakPersistent(this), WrapPersistent(stale_resource)));
@@ -2001,13 +2048,14 @@ void ResourceFetcher::RevalidateStaleResource(Resource* stale_resource) {
void ResourceFetcher::Trace(blink::Visitor* visitor) {
visitor->Trace(context_);
+ visitor->Trace(properties_);
+ visitor->Trace(console_logger_);
visitor->Trace(scheduler_);
visitor->Trace(archive_);
visitor->Trace(loaders_);
visitor->Trace(non_blocking_loaders_);
visitor->Trace(cached_resources_map_);
visitor->Trace(document_resources_);
- visitor->Trace(resources_from_previous_fetcher_);
visitor->Trace(preloads_);
visitor->Trace(matched_preloads_);
visitor->Trace(resource_timing_info_map_);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index 86b375837ee..36a7669566b 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -29,6 +29,7 @@
#include <memory>
+#include "base/single_thread_task_runner.h"
#include "services/network/public/cpp/cors/preflight_timing_info.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -50,12 +51,48 @@
namespace blink {
class ArchiveResource;
+class ConsoleLogger;
class MHTMLArchive;
class KURL;
class Resource;
+class ResourceFetcherProperties;
class ResourceTimingInfo;
enum class ResourceType : uint8_t;
+// Used for ResourceFetcher construction.
+// Creators of ResourceFetcherInit are responsible for setting consistent
+// members to ensure the correctness of ResourceFetcher.
+struct PLATFORM_EXPORT ResourceFetcherInit final {
+ STACK_ALLOCATED();
+
+ public:
+ // |context| and |task_runner| must not be null.
+ // The given ResourceFetcherProperties is kept until ClearContext() is called.
+ ResourceFetcherInit(const ResourceFetcherProperties& properties,
+ FetchContext* context,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ ResourceFetcherInit(const ResourceFetcherProperties& properties,
+ FetchContext* context,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ ConsoleLogger& console_logger)
+ : properties(properties),
+ context(context),
+ task_runner(std::move(task_runner)),
+ console_logger(console_logger) {
+ DCHECK(this->context);
+ DCHECK(this->task_runner);
+ }
+ const Member<const ResourceFetcherProperties> properties;
+ const Member<FetchContext> context;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+ ResourceLoadScheduler::ThrottlingPolicy initial_throttling_policy =
+ ResourceLoadScheduler::ThrottlingPolicy::kNormal;
+ const Member<ConsoleLogger> console_logger;
+ Member<MHTMLArchive> archive;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceFetcherInit);
+};
+
// The ResourceFetcher provides a per-context interface to the MemoryCache and
// enforces a bunch of security checks and rules for resource revalidation. Its
// lifetime is roughly per-DocumentLoader, in that it is generally created in
@@ -74,14 +111,21 @@ class PLATFORM_EXPORT ResourceFetcher
USING_PRE_FINALIZER(ResourceFetcher, ClearPreloads);
public:
- static ResourceFetcher* Create(FetchContext* context) {
- return MakeGarbageCollected<ResourceFetcher>(context);
- }
-
- ResourceFetcher(FetchContext*);
+ // ResourceFetcher creators are responsible for setting consistent objects
+ // in ResourceFetcherInit to ensure correctness of this ResourceFetcher.
+ explicit ResourceFetcher(const ResourceFetcherInit&);
virtual ~ResourceFetcher();
virtual void Trace(blink::Visitor*);
+ // - This function returns the same object throughout this fetcher's
+ // entire life.
+ // - The returned object remains valid after ClearContext() is called.
+ // - This function returns a different object from the corresponding
+ // argument in the constructor.
+ // - This function should be used rather than the properties given
+ // to the ResourceFetcher constructor.
+ const ResourceFetcherProperties& GetProperties() const;
+
// Triggers a fetch based on the given FetchParameters (if there isn't a
// suitable Resource already cached) and registers the given ResourceClient
// with the Resource. Guaranteed to return a non-null Resource of the subtype
@@ -89,7 +133,15 @@ class PLATFORM_EXPORT ResourceFetcher
Resource* RequestResource(FetchParameters&,
const ResourceFactory&,
ResourceClient*,
- const SubstituteData& = SubstituteData());
+ const SubstituteData& = SubstituteData(),
+ unsigned long identifier = 0);
+
+ // Returns the task runner used by this fetcher, and loading operations
+ // this fetcher initiates. The returned task runner will keep working even
+ // after ClearContext is called.
+ const scoped_refptr<base::SingleThreadTaskRunner>& GetTaskRunner() const {
+ return task_runner_;
+ }
Resource* CachedResource(const KURL&) const;
@@ -98,9 +150,6 @@ class PLATFORM_EXPORT ResourceFetcher
return cached_resources_map_;
}
- void HoldResourcesFromPreviousFetcher(ResourceFetcher*);
- void ClearResourcesFromPreviousFetcher();
-
// Binds the given Resource instance to this ResourceFetcher instance to
// start loading the Resource actually.
// Usually, RequestResource() calls this method internally, but needs to
@@ -113,6 +162,11 @@ class PLATFORM_EXPORT ResourceFetcher
FetchContext& Context() const;
void ClearContext();
+ ConsoleLogger* GetConsoleLogger() { return console_logger_; }
+ void SetConsoleLogger(ConsoleLogger* console_logger) {
+ DCHECK(console_logger);
+ console_logger_ = console_logger;
+ }
int BlockingRequestCount() const;
int NonblockingRequestCount() const;
@@ -131,14 +185,17 @@ class PLATFORM_EXPORT ResourceFetcher
Vector<KURL> GetUrlsOfUnusedPreloads();
MHTMLArchive* Archive() const { return archive_.Get(); }
- ArchiveResource* CreateArchive(Resource*);
+ ArchiveResource* CreateArchive(const KURL&,
+ scoped_refptr<const SharedBuffer>);
void SetDefersLoading(bool);
void StopFetching();
bool ShouldDeferImageLoad(const KURL&) const;
- void RecordResourceTimingOnRedirect(Resource*, const ResourceResponse&, bool);
+ void RecordResourceTimingOnRedirect(Resource*,
+ const ResourceResponse&,
+ const KURL& new_url);
enum LoaderFinishType { kDidFinishLoading, kDidFinishFirstPartInMultipart };
void HandleLoaderFinish(Resource*,
@@ -164,9 +221,6 @@ class PLATFORM_EXPORT ResourceFetcher
void ReloadLoFiImages();
- // Calling this method before main document resource is fetched is invalid.
- ResourceTimingInfo* GetNavigationTimingInfo();
-
// Returns whether the given resource is contained as a preloaded resource.
bool ContainsAsPreload(Resource*) const;
@@ -182,7 +236,7 @@ class PLATFORM_EXPORT ResourceFetcher
mojom::RequestContextType,
const AtomicString& initiator_name);
- // This is called from leak detectors (Real-world leak detector & layout test
+ // This is called from leak detectors (Real-world leak detector & web test
// leak detector) to clean up loaders after page navigation before instance
// counting.
void PrepareForLeakDetection();
@@ -194,6 +248,7 @@ class PLATFORM_EXPORT ResourceFetcher
private:
friend class ResourceCacheValidationSuppressor;
+ class DetachableProperties;
enum class StopFetchingTarget {
kExcludingKeepaliveLoaders,
kIncludingKeepaliveLoaders,
@@ -217,11 +272,15 @@ class PLATFORM_EXPORT ResourceFetcher
FetchParameters::SpeculativePreloadType::kNotSpeculative,
bool is_link_preload = false);
+ // |virtual_time_pauser| is an output parameter. PrepareRequest may
+ // create a new WebScopedVirtualTimePauser and set it to
+ // |virtual_time_pauser|.
base::Optional<ResourceRequestBlockedReason> PrepareRequest(
FetchParameters&,
const ResourceFactory&,
const SubstituteData&,
- unsigned long identifier);
+ unsigned long identifier,
+ WebScopedVirtualTimePauser& virtual_time_pauser);
Resource* ResourceForStaticData(const FetchParameters&,
const ResourceFactory&,
@@ -291,17 +350,15 @@ class PLATFORM_EXPORT ResourceFetcher
void ScheduleStaleRevalidate(Resource* stale_resource);
void RevalidateStaleResource(Resource* stale_resource);
+ Member<DetachableProperties> properties_;
Member<FetchContext> context_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ Member<ConsoleLogger> console_logger_;
Member<ResourceLoadScheduler> scheduler_;
DocumentResourceMap cached_resources_map_;
HeapHashSet<WeakMember<Resource>> document_resources_;
- // When populated, forces Resources to remain alive across a navigation, to
- // increase the odds the next document will be able to reuse resources from
- // the previous page. Unpopulated unless experiment is enabled.
- HeapHashSet<Member<Resource>> resources_from_previous_fetcher_;
-
HeapHashMap<PreloadKey, Member<Resource>> preloads_;
HeapVector<Member<Resource>> matched_preloads_;
Member<MHTMLArchive> archive_;
@@ -312,8 +369,6 @@ class PLATFORM_EXPORT ResourceFetcher
HeapHashMap<Member<Resource>, scoped_refptr<ResourceTimingInfo>>;
ResourceTimingInfoMap resource_timing_info_map_;
- scoped_refptr<ResourceTimingInfo> navigation_timing_info_;
-
Vector<scoped_refptr<ResourceTimingInfo>> scheduled_resource_timing_reports_;
HeapHashSet<Member<ResourceLoader>> loaders_;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h
new file mode 100644
index 00000000000..dafb16d6884
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h
@@ -0,0 +1,78 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RESOURCE_FETCHER_PROPERTIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RESOURCE_FETCHER_PROPERTIES_H_
+
+#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-shared.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+class FetchClientSettingsObject;
+
+// ResourceFetcherProperties consists of properties of the global context (e.g.,
+// Frame, Worker) necessary to fetch resources. FetchClientSettingsObject
+// implementing https://html.spec.whatwg.org/C/webappapis.html#settings-object
+// is one such example.
+//
+// This class consists of pure virtual getters. Do not put operations. Do not
+// put getters for a specific request such as
+// GetCachePolicy(const ResourceRequest&, ResourceType). Do not put a function
+// with default implementation.
+//
+// The distinction between FetchClientSettingsObject and
+// ResourceFetcherProperties is sometimes ambiguous. Put a property in
+// FetchClientSettingsObject when the property is clearly defined in the spec.
+// Otherwise, put it to this class.
+class PLATFORM_EXPORT ResourceFetcherProperties
+ : public GarbageCollectedFinalized<ResourceFetcherProperties> {
+ public:
+ using ControllerServiceWorkerMode = mojom::ControllerServiceWorkerMode;
+
+ ResourceFetcherProperties() = default;
+ virtual ~ResourceFetcherProperties() = default;
+ virtual void Trace(Visitor*) {}
+
+ // Returns the client settings object bound to this global context.
+ virtual const FetchClientSettingsObject& GetFetchClientSettingsObject()
+ const = 0;
+
+ // Returns whether this global context is a top-level frame.
+ virtual bool IsMainFrame() const = 0;
+
+ // Returns whether a controller service worker exists and if it has a fetch
+ // handler.
+ virtual ControllerServiceWorkerMode GetControllerServiceWorkerMode()
+ const = 0;
+
+ // Returns an identifier for the service worker controlling this global
+ // context. This function cannot be called when
+ // GetControllerServiceWorkerMode returns kNoController.
+ virtual int64_t ServiceWorkerId() const = 0;
+
+ // Returns whether this global context is suspended, which means we should
+ // defer making a new request.
+ // https://html.spec.whatwg.org/C/webappapis.html#pause
+ virtual bool IsPaused() const = 0;
+
+ // Returns whether this global context is detached. Note that in some cases
+ // the loading pipeline continues working after detached (e.g., for fetch()
+ // operations with "keepalive" specified).
+ virtual bool IsDetached() const = 0;
+
+ // Returns whether the main resource for this global context is loaded.
+ virtual bool IsLoadComplete() const = 0;
+
+ // Returns whether we should disallow a main resource loading.
+ virtual bool ShouldBlockLoadingMainResource() const = 0;
+
+ // Returns whether we should disallow a sub resource loading.
+ virtual bool ShouldBlockLoadingSubResource() const = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RESOURCE_FETCHER_PROPERTIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 783d74edb74..c207cbe39e1 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -35,7 +35,7 @@
#include "build/build_config.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
@@ -48,16 +48,19 @@
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
+#include "third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
+#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -95,14 +98,14 @@ class ResourceFetcherTest : public testing::Test {
ResourceFetcherTest() = default;
~ResourceFetcherTest() override { GetMemoryCache()->EvictResources(); }
- void RunUntilIdle() {
- base::SingleThreadTaskRunner* runner =
- Context()->GetLoadingTaskRunner().get();
- static_cast<scheduler::FakeTaskRunner*>(runner)->RunUntilIdle();
+ protected:
+ scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() {
+ return base::MakeRefCounted<scheduler::FakeTaskRunner>();
}
- protected:
- MockFetchContext* Context() { return platform_->Context(); }
+ MockFetchContext* CreateFetchContext() {
+ return MakeGarbageCollected<MockFetchContext>();
+ }
void AddResourceToMemoryCache(Resource* resource) {
GetMemoryCache()->Add(resource);
}
@@ -117,8 +120,9 @@ TEST_F(ResourceFetcherTest, StartLoadAfterFrameDetach) {
KURL secure_url("https://secureorigin.test/image.png");
// Try to request a url. The request should fail, and a resource in an error
// state should be returned, and no resource should be present in the cache.
- ResourceFetcher* fetcher = ResourceFetcher::Create(
- &FetchContext::NullInstance(platform_->test_task_runner()));
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *MakeGarbageCollected<NullResourceFetcherProperties>(),
+ &FetchContext::NullInstance(), CreateTaskRunner()));
ResourceRequest resource_request(secure_url);
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
FetchParameters fetch_params(resource_request);
@@ -135,7 +139,9 @@ TEST_F(ResourceFetcherTest, StartLoadAfterFrameDetach) {
}
TEST_F(ResourceFetcherTest, UseExistingResource) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.html");
ResourceResponse response(url);
@@ -160,7 +166,9 @@ TEST_F(ResourceFetcherTest, WillSendRequestAdBit) {
// Add a resource to the memory cache.
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUniqueOpaque();
- Context()->SetSecurityOrigin(source_origin);
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin);
+ MockFetchContext* context = CreateFetchContext();
KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource =
RawResource::CreateForTest(url, source_origin, ResourceType::kRaw);
@@ -173,7 +181,8 @@ TEST_F(ResourceFetcherTest, WillSendRequestAdBit) {
// Fetch the cached resource. The request to DispatchWillSendRequest should
// preserve the ad bit.
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
ResourceRequest resource_request(url);
resource_request.SetIsAdResource();
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
@@ -183,7 +192,7 @@ TEST_F(ResourceFetcherTest, WillSendRequestAdBit) {
EXPECT_EQ(resource, new_resource);
base::Optional<ResourceRequest> new_request =
- Context()->RequestFromWillSendRequest();
+ context->RequestFromWillSendRequest();
EXPECT_TRUE(new_request.has_value());
EXPECT_TRUE(new_request.value().IsAdResource());
}
@@ -191,7 +200,9 @@ TEST_F(ResourceFetcherTest, WillSendRequestAdBit) {
TEST_F(ResourceFetcherTest, Vary) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUniqueOpaque();
- Context()->SetSecurityOrigin(source_origin);
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin);
+ MockFetchContext* context = CreateFetchContext();
KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource =
@@ -206,7 +217,8 @@ TEST_F(ResourceFetcherTest, Vary) {
resource->FinishForTest();
ASSERT_TRUE(resource->MustReloadDueToVaryHeader(ResourceRequest(url)));
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
FetchParameters fetch_params(resource_request);
@@ -216,50 +228,28 @@ TEST_F(ResourceFetcherTest, Vary) {
new_resource->Loader()->Cancel();
}
-TEST_F(ResourceFetcherTest, NavigationTimingInfo) {
- KURL url("http://127.0.0.1:8000/foo.html");
- ResourceResponse response(url);
- response.SetHTTPStatusCode(200);
-
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
- ResourceRequest resource_request(url);
- resource_request.SetFrameType(
- network::mojom::RequestContextFrameType::kNested);
- resource_request.SetRequestContext(mojom::RequestContextType::FORM);
- FetchParameters fetch_params(resource_request);
- platform_->GetURLLoaderMockFactory()->RegisterURL(url, WebURLResponse(), "");
- Resource* resource = RawResource::FetchMainResource(
- fetch_params, fetcher, nullptr, SubstituteData());
- resource->ResponseReceived(response, nullptr);
- EXPECT_EQ(resource->GetType(), ResourceType::kMainResource);
-
- ResourceTimingInfo* navigation_timing_info =
- fetcher->GetNavigationTimingInfo();
- ASSERT_TRUE(navigation_timing_info);
- long long encoded_data_length = 123;
- resource->Loader()->DidFinishLoading(
- TimeTicks(), encoded_data_length, 0, 0, false,
- std::vector<network::cors::PreflightTimingInfo>());
- EXPECT_EQ(navigation_timing_info->TransferSize(), encoded_data_length);
-
- // When there are redirects.
- KURL redirect_url("http://127.0.0.1:8000/redirect.html");
- ResourceResponse redirect_response(redirect_url);
+TEST_F(ResourceFetcherTest, ResourceTimingInfo) {
+ auto info = ResourceTimingInfo::Create(fetch_initiator_type_names::kDocument,
+ CurrentTimeTicks(),
+ true /* is_main_resource */);
+ info->AddFinalTransferSize(5);
+ EXPECT_EQ(info->TransferSize(), 5);
+ ResourceResponse redirect_response(KURL("https://example.com"));
redirect_response.SetHTTPStatusCode(200);
- long long redirect_encoded_data_length = 123;
- redirect_response.SetEncodedDataLength(redirect_encoded_data_length);
- ResourceRequest redirect_resource_request(url);
- fetcher->RecordResourceTimingOnRedirect(resource, redirect_response, false);
- EXPECT_EQ(navigation_timing_info->TransferSize(),
- encoded_data_length + redirect_encoded_data_length);
+ redirect_response.SetEncodedDataLength(7);
+ info->AddRedirect(redirect_response, KURL("https://example.com/redirect"));
+ EXPECT_EQ(info->TransferSize(), 12);
}
TEST_F(ResourceFetcherTest, VaryOnBack) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUniqueOpaque();
- Context()->SetSecurityOrigin(source_origin);
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin);
+ MockFetchContext* context = CreateFetchContext();
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource =
@@ -283,7 +273,9 @@ TEST_F(ResourceFetcherTest, VaryOnBack) {
}
TEST_F(ResourceFetcherTest, VaryResource) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.html");
ResourceResponse response(url);
@@ -313,16 +305,20 @@ class RequestSameResourceOnComplete
explicit RequestSameResourceOnComplete(FetchParameters& params,
ResourceFetcher* fetcher)
: notify_finished_called_(false),
- source_origin_(fetcher->Context().GetSecurityOrigin()) {
+ source_origin_(fetcher->GetProperties()
+ .GetFetchClientSettingsObject()
+ .GetSecurityOrigin()) {
MockResource::Fetch(params, fetcher, this);
}
void NotifyFinished(Resource* resource) override {
EXPECT_EQ(GetResource(), resource);
- MockFetchContext* context =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- context->SetSecurityOrigin(source_origin_);
- ResourceFetcher* fetcher2 = ResourceFetcher::Create(context);
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin_);
+ MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
+ auto* fetcher2 = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
ResourceRequest resource_request2(GetResource()->Url());
resource_request2.SetCacheMode(mojom::FetchCacheMode::kValidateCache);
FetchParameters fetch_params2(resource_request2);
@@ -347,7 +343,7 @@ class RequestSameResourceOnComplete
TEST_F(ResourceFetcherTest, RevalidateWhileFinishingLoading) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUniqueOpaque();
- Context()->SetSecurityOrigin(source_origin);
+ MockFetchContext* context = CreateFetchContext();
KURL url("http://127.0.0.1:8000/foo.png");
@@ -357,7 +353,10 @@ TEST_F(ResourceFetcherTest, RevalidateWhileFinishingLoading) {
response.SetHTTPHeaderField(http_names::kETag, "1234567890");
RegisterMockedURLLoadWithCustomResponse(url, response);
- ResourceFetcher* fetcher1 = ResourceFetcher::Create(Context());
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin);
+ ResourceFetcher* fetcher1 = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
ResourceRequest request1(url);
request1.SetHTTPHeaderField(http_names::kCacheControl, "no-cache");
FetchParameters fetch_params1(request1);
@@ -375,7 +374,9 @@ TEST_F(ResourceFetcherTest, RevalidateWhileFinishingLoading) {
#define MAYBE_DontReuseMediaDataUrl DontReuseMediaDataUrl
#endif
TEST_F(ResourceFetcherTest, MAYBE_DontReuseMediaDataUrl) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
ResourceRequest request(KURL("data:text/html,foo"));
request.SetRequestContext(mojom::RequestContextType::VIDEO);
request.SetFetchCredentialsMode(network::mojom::FetchCredentialsMode::kOmit);
@@ -409,7 +410,7 @@ class ServeRequestsOnCompleteClient final
std::unique_ptr<WebDataConsumerHandle>) override {
ASSERT_TRUE(false);
}
- void SetSerializedCachedMetadata(Resource*, const char*, size_t) override {
+ void SetSerializedCachedMetadata(Resource*, const uint8_t*, size_t) override {
ASSERT_TRUE(false);
}
void DataReceived(Resource*, const char*, size_t) override {
@@ -421,7 +422,9 @@ class ServeRequestsOnCompleteClient final
ADD_FAILURE();
return true;
}
- void DataDownloaded(Resource*, int) override { ASSERT_TRUE(false); }
+ void DataDownloaded(Resource*, unsigned long long) override {
+ ASSERT_TRUE(false);
+ }
void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) override {
ASSERT_TRUE(false);
}
@@ -442,7 +445,9 @@ TEST_F(ResourceFetcherTest, ResponseOnCancel) {
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
FetchParameters fetch_params(resource_request);
@@ -457,13 +462,15 @@ class ScopedMockRedirectRequester {
WTF_MAKE_NONCOPYABLE(ScopedMockRedirectRequester);
public:
- explicit ScopedMockRedirectRequester(MockFetchContext* context)
- : context_(context) {}
+ ScopedMockRedirectRequester(
+ MockFetchContext* context,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : context_(context), task_runner_(std::move(task_runner)) {}
void RegisterRedirect(const WebString& from_url, const WebString& to_url) {
KURL redirect_url(from_url);
WebURLResponse redirect_response;
- redirect_response.SetURL(redirect_url);
+ redirect_response.SetCurrentRequestUrl(redirect_url);
redirect_response.SetHTTPStatusCode(301);
redirect_response.SetHTTPHeaderField(http_names::kLocation, to_url);
redirect_response.SetEncodedDataLength(kRedirectResponseOverheadBytes);
@@ -477,7 +484,9 @@ class ScopedMockRedirectRequester {
}
void Request(const WebString& url) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context_, task_runner_));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
FetchParameters fetch_params(resource_request);
@@ -487,29 +496,32 @@ class ScopedMockRedirectRequester {
private:
Member<MockFetchContext> context_;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
TEST_F(ResourceFetcherTest, SameOriginRedirect) {
const char kRedirectURL[] = "http://127.0.0.1:8000/redirect.html";
const char kFinalURL[] = "http://127.0.0.1:8000/final.html";
- ScopedMockRedirectRequester requester(Context());
+ MockFetchContext* context = CreateFetchContext();
+ ScopedMockRedirectRequester requester(context, CreateTaskRunner());
requester.RegisterRedirect(kRedirectURL, kFinalURL);
requester.RegisterFinalResource(kFinalURL);
requester.Request(kRedirectURL);
EXPECT_EQ(kRedirectResponseOverheadBytes + kTestResourceSize,
- Context()->GetTransferSize());
+ context->GetTransferSize());
}
TEST_F(ResourceFetcherTest, CrossOriginRedirect) {
const char kRedirectURL[] = "http://otherorigin.test/redirect.html";
const char kFinalURL[] = "http://127.0.0.1:8000/final.html";
- ScopedMockRedirectRequester requester(Context());
+ MockFetchContext* context = CreateFetchContext();
+ ScopedMockRedirectRequester requester(context, CreateTaskRunner());
requester.RegisterRedirect(kRedirectURL, kFinalURL);
requester.RegisterFinalResource(kFinalURL);
requester.Request(kRedirectURL);
- EXPECT_EQ(kTestResourceSize, Context()->GetTransferSize());
+ EXPECT_EQ(kTestResourceSize, context->GetTransferSize());
}
TEST_F(ResourceFetcherTest, ComplexCrossOriginRedirect) {
@@ -517,21 +529,24 @@ TEST_F(ResourceFetcherTest, ComplexCrossOriginRedirect) {
const char kRedirectURL2[] = "http://otherorigin.test/redirect2.html";
const char kRedirectURL3[] = "http://127.0.0.1:8000/redirect3.html";
const char kFinalURL[] = "http://127.0.0.1:8000/final.html";
- ScopedMockRedirectRequester requester(Context());
+ MockFetchContext* context = CreateFetchContext();
+ ScopedMockRedirectRequester requester(context, CreateTaskRunner());
requester.RegisterRedirect(kRedirectURL1, kRedirectURL2);
requester.RegisterRedirect(kRedirectURL2, kRedirectURL3);
requester.RegisterRedirect(kRedirectURL3, kFinalURL);
requester.RegisterFinalResource(kFinalURL);
requester.Request(kRedirectURL1);
- EXPECT_EQ(kTestResourceSize, Context()->GetTransferSize());
+ EXPECT_EQ(kTestResourceSize, context->GetTransferSize());
}
TEST_F(ResourceFetcherTest, SynchronousRequest) {
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
FetchParameters fetch_params(resource_request);
@@ -546,7 +561,9 @@ TEST_F(ResourceFetcherTest, PingPriority) {
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::PING);
FetchParameters fetch_params(resource_request);
@@ -556,7 +573,9 @@ TEST_F(ResourceFetcherTest, PingPriority) {
}
TEST_F(ResourceFetcherTest, PreloadResourceTwice) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -583,7 +602,9 @@ TEST_F(ResourceFetcherTest, PreloadResourceTwice) {
}
TEST_F(ResourceFetcherTest, LinkPreloadResourceAndUse) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -619,7 +640,9 @@ TEST_F(ResourceFetcherTest, LinkPreloadResourceAndUse) {
}
TEST_F(ResourceFetcherTest, PreloadMatchWithBypassingCache) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -641,8 +664,13 @@ TEST_F(ResourceFetcherTest, PreloadMatchWithBypassingCache) {
}
TEST_F(ResourceFetcherTest, CrossFramePreloadMatchIsNotAllowed) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
- ResourceFetcher* fetcher2 = ResourceFetcher::Create(Context());
+ auto* properties1 = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* properties2 = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties1, CreateFetchContext(), CreateTaskRunner()));
+ ResourceFetcher* fetcher2 =
+ MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties2, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -666,7 +694,9 @@ TEST_F(ResourceFetcherTest, CrossFramePreloadMatchIsNotAllowed) {
}
TEST_F(ResourceFetcherTest, RepetitiveLinkPreloadShouldBeMerged) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -698,7 +728,9 @@ TEST_F(ResourceFetcherTest, RepetitiveLinkPreloadShouldBeMerged) {
}
TEST_F(ResourceFetcherTest, RepetitiveSpeculativePreloadShouldBeMerged) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -731,7 +763,9 @@ TEST_F(ResourceFetcherTest, RepetitiveSpeculativePreloadShouldBeMerged) {
}
TEST_F(ResourceFetcherTest, SpeculativePreloadShouldBePromotedToLinkePreload) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -771,7 +805,9 @@ TEST_F(ResourceFetcherTest, SpeculativePreloadShouldBePromotedToLinkePreload) {
TEST_F(ResourceFetcherTest, Revalidate304) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUniqueOpaque();
- Context()->SetSecurityOrigin(source_origin);
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin);
+ MockFetchContext* context = CreateFetchContext();
KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource =
@@ -784,7 +820,8 @@ TEST_F(ResourceFetcherTest, Revalidate304) {
resource->ResponseReceived(response, nullptr);
resource->FinishForTest();
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(mojom::RequestContextType::INTERNAL);
FetchParameters fetch_params(resource_request);
@@ -796,8 +833,13 @@ TEST_F(ResourceFetcherTest, Revalidate304) {
}
TEST_F(ResourceFetcherTest, LinkPreloadResourceMultipleFetchersAndMove) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
- ResourceFetcher* fetcher2 = ResourceFetcher::Create(Context());
+ auto* properties1 = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* properties2 = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties1, CreateFetchContext(), CreateTaskRunner()));
+ ResourceFetcher* fetcher2 =
+ MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties2, CreateFetchContext(), CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.png");
RegisterMockedURLLoad(url);
@@ -828,7 +870,9 @@ TEST_F(ResourceFetcherTest, LinkPreloadResourceMultipleFetchersAndMove) {
#define MAYBE_ContentTypeDataURL ContentTypeDataURL
#endif
TEST_F(ResourceFetcherTest, MAYBE_ContentTypeDataURL) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
FetchParameters fetch_params{ResourceRequest("data:text/testmimetype,foo")};
Resource* resource = MockResource::Fetch(fetch_params, fetcher, nullptr);
ASSERT_TRUE(resource);
@@ -848,7 +892,9 @@ TEST_F(ResourceFetcherTest, ContentIdURL) {
response.SetHTTPStatusCode(200);
RegisterMockedURLLoadWithCustomResponse(url, response);
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
// Main resource case.
{
@@ -858,7 +904,8 @@ TEST_F(ResourceFetcherTest, ContentIdURL) {
network::mojom::RequestContextFrameType::kNested);
FetchParameters fetch_params(resource_request);
RawResource* resource = RawResource::FetchMainResource(
- fetch_params, fetcher, nullptr, SubstituteData());
+ fetch_params, fetcher, nullptr, SubstituteData(),
+ CreateUniqueIdentifier());
ASSERT_NE(nullptr, resource);
EXPECT_FALSE(resource->ErrorOccurred());
}
@@ -878,8 +925,11 @@ TEST_F(ResourceFetcherTest, ContentIdURL) {
TEST_F(ResourceFetcherTest, StaleWhileRevalidate) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUniqueOpaque();
- Context()->SetSecurityOrigin(source_origin);
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(source_origin);
+ MockFetchContext* context = CreateFetchContext();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
KURL url("http://127.0.0.1:8000/foo.html");
FetchParameters fetch_params{ResourceRequest(url)};
@@ -916,13 +966,16 @@ TEST_F(ResourceFetcherTest, StaleWhileRevalidate) {
new_resource = MockResource::Fetch(fetch_params, fetcher, nullptr);
EXPECT_EQ(resource, new_resource);
EXPECT_TRUE(GetMemoryCache()->Contains(resource));
- RunUntilIdle();
+ static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get())
+ ->RunUntilIdle();
platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
EXPECT_FALSE(GetMemoryCache()->Contains(resource));
}
TEST_F(ResourceFetcherTest, CachedResourceShouldNotCrashByNullURL) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ *properties, CreateFetchContext(), CreateTaskRunner()));
// Make sure |cached_resources_map_| is not empty, so that HashMap lookup
// won't take a fast path.
@@ -937,4 +990,113 @@ TEST_F(ResourceFetcherTest, CachedResourceShouldNotCrashByNullURL) {
ASSERT_EQ(fetcher->CachedResource(KURL()), nullptr);
}
+TEST_F(ResourceFetcherTest, DetachedPropertiesWithDefaultValues) {
+ const auto& original_client_settings_object =
+ *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ KURL("https://example.com/foo.html"),
+ SecurityOrigin::Create(KURL("https://example.com/")),
+ network::mojom::ReferrerPolicy::kDefault,
+ "https://example.com/foo.html", HttpsState::kModern,
+ AllowedByNosniff::MimeTypeCheck::kStrict);
+ const auto& original_properties =
+ *MakeGarbageCollected<TestResourceFetcherProperties>(
+ original_client_settings_object);
+ auto* const fetcher =
+ MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ original_properties, CreateFetchContext(), CreateTaskRunner()));
+ const auto& properties = fetcher->GetProperties();
+
+ EXPECT_NE(&original_properties, &properties);
+
+ const auto& client_settings_object =
+ properties.GetFetchClientSettingsObject();
+ EXPECT_EQ(&original_client_settings_object, &client_settings_object);
+ EXPECT_FALSE(properties.IsMainFrame());
+ EXPECT_EQ(properties.GetControllerServiceWorkerMode(),
+ mojom::ControllerServiceWorkerMode::kNoController);
+ // We cannot call ServiceWorkerId as the service worker mode is kNoController.
+ EXPECT_FALSE(properties.IsPaused());
+ EXPECT_FALSE(properties.IsDetached());
+ EXPECT_FALSE(properties.IsLoadComplete());
+ EXPECT_FALSE(properties.ShouldBlockLoadingMainResource());
+ EXPECT_FALSE(properties.ShouldBlockLoadingSubResource());
+
+ fetcher->ClearContext();
+ // ResourceFetcher::GetProperties always returns the same object.
+ EXPECT_EQ(&properties, &fetcher->GetProperties());
+
+ EXPECT_NE(&client_settings_object,
+ &properties.GetFetchClientSettingsObject());
+ EXPECT_EQ(properties.GetFetchClientSettingsObject().BaseURL(),
+ KURL("https://example.com/foo.html"));
+ EXPECT_FALSE(properties.IsMainFrame());
+ EXPECT_EQ(properties.GetControllerServiceWorkerMode(),
+ mojom::ControllerServiceWorkerMode::kNoController);
+ // We cannot call ServiceWorkerId as the service worker mode is kNoController.
+ EXPECT_FALSE(properties.IsPaused());
+ EXPECT_TRUE(properties.IsDetached());
+ EXPECT_FALSE(properties.IsLoadComplete());
+ EXPECT_TRUE(properties.ShouldBlockLoadingMainResource());
+ EXPECT_TRUE(properties.ShouldBlockLoadingSubResource());
+}
+
+TEST_F(ResourceFetcherTest, DetachedPropertiesWithNonDefaultValues) {
+ const auto& original_client_settings_object =
+ *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ KURL("https://example.com/foo.html"),
+ SecurityOrigin::Create(KURL("https://example.com/")),
+ network::mojom::ReferrerPolicy::kDefault,
+ "https://example.com/foo.html", HttpsState::kModern,
+ AllowedByNosniff::MimeTypeCheck::kStrict);
+ auto& original_properties =
+ *MakeGarbageCollected<TestResourceFetcherProperties>(
+ original_client_settings_object);
+ auto* const fetcher =
+ MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ original_properties, CreateFetchContext(), CreateTaskRunner()));
+ const auto& properties = fetcher->GetProperties();
+
+ EXPECT_NE(&original_properties, &properties);
+
+ original_properties.SetIsMainFrame(true);
+ original_properties.SetControllerServiceWorkerMode(
+ mojom::ControllerServiceWorkerMode::kControlled);
+ original_properties.SetServiceWorkerId(133);
+ original_properties.SetIsPaused(true);
+ original_properties.SetIsLoadComplete(true);
+ original_properties.SetShouldBlockLoadingMainResource(true);
+ original_properties.SetShouldBlockLoadingSubResource(true);
+
+ const auto& client_settings_object =
+ properties.GetFetchClientSettingsObject();
+ EXPECT_EQ(&original_client_settings_object, &client_settings_object);
+ EXPECT_TRUE(properties.IsMainFrame());
+ EXPECT_EQ(properties.GetControllerServiceWorkerMode(),
+ mojom::ControllerServiceWorkerMode::kControlled);
+ EXPECT_EQ(properties.ServiceWorkerId(), 133);
+ EXPECT_TRUE(properties.IsPaused());
+ EXPECT_FALSE(properties.IsDetached());
+ EXPECT_TRUE(properties.IsLoadComplete());
+ EXPECT_TRUE(properties.ShouldBlockLoadingMainResource());
+ EXPECT_TRUE(properties.ShouldBlockLoadingSubResource());
+
+ fetcher->ClearContext();
+ // ResourceFetcher::GetProperties always returns the same object.
+ EXPECT_EQ(&properties, &fetcher->GetProperties());
+
+ EXPECT_NE(&client_settings_object,
+ &properties.GetFetchClientSettingsObject());
+ EXPECT_EQ(properties.GetFetchClientSettingsObject().BaseURL(),
+ KURL("https://example.com/foo.html"));
+ EXPECT_TRUE(properties.IsMainFrame());
+ EXPECT_EQ(properties.GetControllerServiceWorkerMode(),
+ mojom::ControllerServiceWorkerMode::kNoController);
+ // We cannot call ServiceWorkerId as the service worker mode is kNoController.
+ EXPECT_TRUE(properties.IsPaused());
+ EXPECT_TRUE(properties.IsDetached());
+ EXPECT_TRUE(properties.IsLoadComplete());
+ EXPECT_TRUE(properties.ShouldBlockLoadingMainResource());
+ EXPECT_TRUE(properties.ShouldBlockLoadingSubResource());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
index a9e198f9d32..b5d3569cfe0 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
@@ -10,7 +10,9 @@
#include "base/strings/string_number_conversions.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/histogram.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/public/aggregated_metric_reporter.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
@@ -90,9 +92,8 @@ uint32_t GetFieldTrialUint32Param(const char* trial_name,
return param;
}
-size_t GetOutstandingThrottledLimit(FetchContext* context) {
- DCHECK(context);
-
+size_t GetOutstandingThrottledLimit(
+ const ResourceFetcherProperties& properties) {
if (!RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled())
return ResourceLoadScheduler::kOutstandingUnlimited;
@@ -103,7 +104,7 @@ size_t GetOutstandingThrottledLimit(FetchContext* context) {
kResourceLoadThrottlingTrial, kOutstandingLimitForBackgroundSubFrameName,
kOutstandingLimitForBackgroundSubFrameDefault);
- return context->IsMainFrame() ? main_frame_limit : sub_frame_limit;
+ return properties.IsMainFrame() ? main_frame_limit : sub_frame_limit;
}
int TakeWholeKilobytes(int64_t& bytes) {
@@ -157,16 +158,14 @@ class ResourceLoadScheduler::TrafficMonitor {
};
ResourceLoadScheduler::TrafficMonitor::TrafficMonitor(FetchContext* context)
- : is_main_frame_(context->IsMainFrame()),
+ : is_main_frame_(context->GetResourceFetcherProperties().IsMainFrame()),
context_(context),
traffic_kilobytes_per_frame_status_(
"Blink.ResourceLoadScheduler.TrafficBytes.KBPerFrameStatus",
&TakeWholeKilobytes),
decoded_kilobytes_per_frame_status_(
"Blink.ResourceLoadScheduler.DecodedBytes.KBPerFrameStatus",
- &TakeWholeKilobytes) {
- DCHECK(context_);
-}
+ &TakeWholeKilobytes) {}
ResourceLoadScheduler::TrafficMonitor::~TrafficMonitor() {
ReportAll();
@@ -221,8 +220,8 @@ void ResourceLoadScheduler::TrafficMonitor::Report(
}
// Report kilobytes instead of bytes to avoid overflows.
- size_t encoded_kilobytes = hints.encoded_data_length() / 1024;
- size_t decoded_kilobytes = hints.decoded_body_length() / 1024;
+ int64_t encoded_kilobytes = hints.encoded_data_length() / 1024;
+ int64_t decoded_kilobytes = hints.decoded_body_length() / 1024;
if (encoded_kilobytes) {
traffic_kilobytes_per_frame_status_.RecordTask(
@@ -348,9 +347,13 @@ void ResourceLoadScheduler::TrafficMonitor::ReportAll() {
constexpr ResourceLoadScheduler::ClientId
ResourceLoadScheduler::kInvalidClientId;
-ResourceLoadScheduler::ResourceLoadScheduler(FetchContext* context)
- : outstanding_limit_for_throttled_frame_scheduler_(
- GetOutstandingThrottledLimit(context)),
+ResourceLoadScheduler::ResourceLoadScheduler(
+ ThrottlingPolicy initial_throttling_policy,
+ FetchContext* context)
+ : policy_(initial_throttling_policy),
+ outstanding_limit_for_throttled_frame_scheduler_(
+ GetOutstandingThrottledLimit(
+ context->GetResourceFetcherProperties())),
context_(context) {
traffic_monitor_ =
std::make_unique<ResourceLoadScheduler::TrafficMonitor>(context_);
@@ -359,7 +362,6 @@ ResourceLoadScheduler::ResourceLoadScheduler(FetchContext* context)
if (!scheduler)
return;
- policy_ = context->InitialLoadThrottlingPolicy();
normal_outstanding_limit_ =
GetFieldTrialUint32Param(kRendererSideResourceScheduler,
kLimitForRendererSideResourceSchedulerName,
@@ -373,13 +375,6 @@ ResourceLoadScheduler::ResourceLoadScheduler(FetchContext* context)
FrameScheduler::ObserverType::kLoader, this);
}
-ResourceLoadScheduler* ResourceLoadScheduler::Create(FetchContext* context) {
- return MakeGarbageCollected<ResourceLoadScheduler>(
- context
- ? context
- : &FetchContext::NullInstance(Thread::Current()->GetTaskRunner()));
-}
-
ResourceLoadScheduler::~ResourceLoadScheduler() = default;
void ResourceLoadScheduler::Trace(blink::Visitor* visitor) {
@@ -428,6 +423,8 @@ void ResourceLoadScheduler::Request(ResourceLoadSchedulerClient* client,
DCHECK(ThrottleOption::kStoppable == option ||
ThrottleOption::kThrottleable == option);
+ if (pending_requests_[option].empty())
+ pending_queue_update_times_[option] = base::TimeTicks::Now();
pending_requests_[option].insert(request_info);
pending_request_map_.insert(
*id, MakeGarbageCollected<ClientInfo>(client, option, priority,
@@ -435,22 +432,7 @@ void ResourceLoadScheduler::Request(ResourceLoadSchedulerClient* client,
// Remember the ClientId since MaybeRun() below may destruct the caller
// instance and |id| may be inaccessible after the call.
- ResourceLoadScheduler::ClientId client_id = *id;
MaybeRun();
-
- if (!omit_console_log_ && IsThrottledState() &&
- pending_request_map_.find(client_id) != pending_request_map_.end()) {
- // Note that this doesn't show the message when a frame is stopped (vs.
- // this DOES when throttled).
- context_->AddInfoConsoleMessage(
- "Active resource loading counts reached a per-frame limit while the "
- "tab was in background. Network requests will be delayed until a "
- "previous loading finishes, or the tab is brought to the foreground. "
- "See https://www.chromestatus.com/feature/5527160148197376 for more "
- "details",
- FetchContext::kOtherSource);
- omit_console_log_ = true;
- }
}
void ResourceLoadScheduler::SetPriority(ClientId client_id,
@@ -544,13 +526,13 @@ void ResourceLoadScheduler::OnNetworkQuiet() {
switch (throttling_history_) {
case ThrottlingHistory::kInitial:
case ThrottlingHistory::kNotThrottled:
- if (context_->IsMainFrame())
+ if (context_->GetResourceFetcherProperties().IsMainFrame())
main_frame_not_throttled.Count(maximum_running_requests_seen_);
else
sub_frame_not_throttled.Count(maximum_running_requests_seen_);
break;
case ThrottlingHistory::kThrottled:
- if (context_->IsMainFrame())
+ if (context_->GetResourceFetcherProperties().IsMainFrame())
main_frame_throttled.Count(maximum_running_requests_seen_);
else
sub_frame_throttled.Count(maximum_running_requests_seen_);
@@ -597,8 +579,6 @@ void ResourceLoadScheduler::OnLifecycleStateChanged(
frame_scheduler_lifecycle_state_ = state;
- omit_console_log_ = false;
-
switch (state) {
case scheduler::SchedulingLifecycleState::kHidden:
case scheduler::SchedulingLifecycleState::kThrottled:
@@ -612,6 +592,7 @@ void ResourceLoadScheduler::OnLifecycleStateChanged(
throttling_history_ = ThrottlingHistory::kNotThrottled;
else if (throttling_history_ == ThrottlingHistory::kThrottled)
throttling_history_ = ThrottlingHistory::kPartiallyThrottled;
+ ShowConsoleMessageIfNeeded();
break;
case scheduler::SchedulingLifecycleState::kStopped:
throttling_history_ = ThrottlingHistory::kStopped;
@@ -656,14 +637,19 @@ bool ResourceLoadScheduler::GetNextPendingRequest(ClientId* id) {
(!has_runnable_throttleable_request ||
compare(*stoppable_it, *throttleable_it));
- // Remove the iterator from the correct set of pending_requests_.
+ // Remove the iterator from the correct set of |pending_requests_|, and update
+ // corresponding |pending_queue_update_times_|.
if (use_stoppable) {
*id = stoppable_it->client_id;
stoppable_queue.erase(stoppable_it);
+ pending_queue_update_times_[ThrottleOption::kStoppable] =
+ base::TimeTicks::Now();
return true;
}
*id = throttleable_it->client_id;
throttleable_queue.erase(throttleable_it);
+ pending_queue_update_times_[ThrottleOption::kThrottleable] =
+ base::TimeTicks::Now();
return true;
}
@@ -723,16 +709,38 @@ size_t ResourceLoadScheduler::GetOutstandingLimit() const {
return limit;
}
-bool ResourceLoadScheduler::IsThrottledState() const {
- switch (frame_scheduler_lifecycle_state_) {
- case scheduler::SchedulingLifecycleState::kHidden:
- case scheduler::SchedulingLifecycleState::kThrottled:
- return true;
- case scheduler::SchedulingLifecycleState::kStopped:
- case scheduler::SchedulingLifecycleState::kNotThrottled:
- break;
+void ResourceLoadScheduler::ShowConsoleMessageIfNeeded() {
+ if (is_console_info_shown_ || pending_request_map_.IsEmpty())
+ return;
+
+ const base::TimeTicks limit =
+ base::TimeTicks::Now() - base::TimeDelta::FromMinutes(1);
+ ThrottleOption target_option;
+ if (pending_queue_update_times_[ThrottleOption::kThrottleable] < limit &&
+ !pending_requests_[ThrottleOption::kThrottleable].empty()) {
+ target_option = ThrottleOption::kThrottleable;
+ } else if (pending_queue_update_times_[ThrottleOption::kStoppable] < limit &&
+ !pending_requests_[ThrottleOption::kStoppable].empty()) {
+ target_option = ThrottleOption::kStoppable;
+ } else {
+ // At least, one of the top requests in pending queues was handled in the
+ // last 1 minutes, or there is no pending requests in the inactive queue.
+ return;
}
- return false;
+ auto client_it = pending_request_map_.find(
+ pending_requests_[target_option].begin()->client_id);
+ DCHECK_NE(pending_request_map_.end(), client_it);
+ ConsoleLogger* logger = client_it->value->client->GetConsoleLogger();
+ DCHECK(logger);
+
+ logger->AddInfoMessage(
+ ConsoleLogger::Source::kOther,
+ "Some resource load requests were throttled while the tab was in "
+ "background, and no request was sent from the queue in the last 1 "
+ "minute. This means previously requested in-flight requests haven't "
+ "received any response from servers. See"
+ "https://www.chromestatus.com/feature/5527160148197376 for more details");
+ is_console_info_shown_ = true;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
index 7f327a2c9ea..62814e13460 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
@@ -17,6 +17,7 @@
namespace blink {
+class ConsoleLogger;
class FetchContext;
// Client interface to use the throttling/scheduling functionality that
@@ -27,6 +28,10 @@ class PLATFORM_EXPORT ResourceLoadSchedulerClient
// Called when the request is granted to run.
virtual void Run() = 0;
+ // Called to obtain a ConsoleLogger instance.
+ // TODO(yhirano): Remove this once https://crbug.com/855189 is fixed.
+ virtual ConsoleLogger* GetConsoleLogger() = 0;
+
void Trace(blink::Visitor* visitor) override {}
};
@@ -147,9 +152,8 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
static constexpr size_t kOutstandingUnlimited =
std::numeric_limits<size_t>::max();
- static ResourceLoadScheduler* Create(FetchContext* = nullptr);
-
- ResourceLoadScheduler(FetchContext*);
+ ResourceLoadScheduler(ThrottlingPolicy initial_throttling_poilcy,
+ FetchContext*);
~ResourceLoadScheduler() override;
void Trace(blink::Visitor*);
@@ -265,7 +269,7 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
size_t GetOutstandingLimit() const;
- bool IsThrottledState() const;
+ void ShowConsoleMessageIfNeeded();
// A flag to indicate an internal running state.
// TODO(toyoshim): We may want to use enum once we start to have more states.
@@ -297,9 +301,8 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
// Largest number of running requests seen so far.
unsigned maximum_running_requests_seen_ = 0;
- // Holds a flag to omit repeating console messages. Will be reset on
- // SchedulingLifecycleState changes.
- bool omit_console_log_ = false;
+ // Holds a flag to omit repeating console messages.
+ bool is_console_info_shown_ = false;
enum class ThrottlingHistory {
kInitial,
@@ -320,6 +323,9 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
std::set<ClientIdWithPriority, ClientIdWithPriority::Compare>>
pending_requests_;
+ // Remembers times when the top request in each queue is processed.
+ std::map<ThrottleOption, base::TimeTicks> pending_queue_update_times_;
+
// Holds an internal class instance to monitor and report traffic.
std::unique_ptr<TrafficMonitor> traffic_monitor_;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
index 440a7e61b07..6a546a4425c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
@@ -6,7 +6,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -44,13 +47,17 @@ class MockClient final : public GarbageCollectedFinalized<MockClient>,
EXPECT_FALSE(was_run_);
was_run_ = true;
}
+ ConsoleLogger* GetConsoleLogger() override { return console_logger_; }
bool WasRun() { return was_run_; }
void Trace(blink::Visitor* visitor) override {
ResourceLoadSchedulerClient::Trace(visitor);
+ visitor->Trace(console_logger_);
}
private:
+ Member<ConsoleLogger> console_logger_ =
+ MakeGarbageCollected<NullConsoleLogger>();
MockClientDelegate* delegate_;
bool was_run_ = false;
};
@@ -60,8 +67,15 @@ class ResourceLoadSchedulerTest : public testing::Test {
using ThrottleOption = ResourceLoadScheduler::ThrottleOption;
void SetUp() override {
DCHECK(RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled());
- scheduler_ = ResourceLoadScheduler::Create(
- MockFetchContext::Create(MockFetchContext::kShouldNotLoadNewResource));
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ properties->SetShouldBlockLoadingMainResource(true);
+ properties->SetShouldBlockLoadingSubResource(true);
+ auto* context = MakeGarbageCollected<MockFetchContext>();
+ MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>()));
+ scheduler_ = MakeGarbageCollected<ResourceLoadScheduler>(
+ ResourceLoadScheduler::ThrottlingPolicy::kTight, context);
Scheduler()->SetOutstandingLimitForTesting(1);
}
void TearDown() override { Scheduler()->Shutdown(); }
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc
index ac8c07f7469..150a026b7ad 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc
@@ -27,6 +27,7 @@ scoped_refptr<ResourceLoadTiming> ResourceLoadTiming::DeepCopy() {
timing->worker_ready_ = worker_ready_;
timing->send_start_ = send_start_;
timing->send_end_ = send_end_;
+ timing->receive_headers_start_ = receive_headers_start_;
timing->receive_headers_end_ = receive_headers_end_;
timing->ssl_start_ = ssl_start_;
timing->ssl_end_ = ssl_end_;
@@ -44,6 +45,7 @@ bool ResourceLoadTiming::operator==(const ResourceLoadTiming& other) const {
worker_start_ == other.worker_start_ &&
worker_ready_ == other.worker_ready_ &&
send_start_ == other.send_start_ && send_end_ == other.send_end_ &&
+ receive_headers_start_ == other.receive_headers_start_ &&
receive_headers_end_ == other.receive_headers_end_ &&
ssl_start_ == other.ssl_start_ && ssl_end_ == other.ssl_end_ &&
push_start_ == other.push_start_ && push_end_ == other.push_end_;
@@ -99,6 +101,11 @@ void ResourceLoadTiming::SetSendEnd(TimeTicks send_end) {
send_end_ = send_end;
}
+void ResourceLoadTiming::SetReceiveHeadersStart(
+ TimeTicks receive_headers_start) {
+ receive_headers_start_ = receive_headers_start;
+}
+
void ResourceLoadTiming::SetReceiveHeadersEnd(TimeTicks receive_headers_end) {
receive_headers_end_ = receive_headers_end;
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h
index b5016d9beb8..9c978eb8af9 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h
@@ -53,6 +53,7 @@ class PLATFORM_EXPORT ResourceLoadTiming
void SetWorkerReady(TimeTicks);
void SetSendStart(TimeTicks);
void SetSendEnd(TimeTicks);
+ void SetReceiveHeadersStart(TimeTicks);
void SetReceiveHeadersEnd(TimeTicks);
void SetSslStart(TimeTicks);
void SetSslEnd(TimeTicks);
@@ -70,6 +71,7 @@ class PLATFORM_EXPORT ResourceLoadTiming
TimeTicks WorkerReady() const { return worker_ready_; }
TimeTicks SendStart() const { return send_start_; }
TimeTicks SendEnd() const { return send_end_; }
+ TimeTicks ReceiveHeadersStart() const { return receive_headers_start_; }
TimeTicks ReceiveHeadersEnd() const { return receive_headers_end_; }
TimeTicks SslStart() const { return ssl_start_; }
TimeTicks SslEnd() const { return ssl_end_; }
@@ -103,6 +105,7 @@ class PLATFORM_EXPORT ResourceLoadTiming
TimeTicks worker_ready_;
TimeTicks send_start_;
TimeTicks send_end_;
+ TimeTicks receive_headers_start_;
TimeTicks receive_headers_end_;
TimeTicks ssl_start_;
TimeTicks ssl_end_;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 5ff1ba1bda6..ef3d8915534 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -46,10 +46,12 @@
#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/mixed_content_autoupgrade_status.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -307,7 +309,7 @@ ResourceLoader::ResourceLoader(ResourceFetcher* fetcher,
inflight_keepalive_bytes_(inflight_keepalive_bytes),
is_cache_aware_loading_activated_(false),
progress_binding_(this),
- cancel_timer_(Context().GetLoadingTaskRunner(),
+ cancel_timer_(fetcher_->GetTaskRunner(),
this,
&ResourceLoader::CancelTimerFired) {
DCHECK(resource_);
@@ -347,23 +349,21 @@ bool ResourceLoader::ShouldFetchCodeCache() {
// with the resource from the cache storage.
if (request.GetRequestContext() == mojom::RequestContextType::SERVICE_WORKER)
return false;
- // These requests are serviced by the service worker. It is possible that the
- // service worker may not service the request in which case it is serviced
- // by the network. Assuming those fallback cases are not frequent, we don't
- // fetch from code cache. We may want to have some actual data, to make an
- // informed decision.
- // TODO(crbug.com/895850): Get UMA data to see if this check is necessary.
- if (ResourceLoader::Context().IsControlledByServiceWorker() ==
- mojom::ControllerServiceWorkerMode::kControlled)
- return false;
if (request.DownloadToBlob())
return false;
// Javascript resources have type kScript or kMainResource (for inline
- // scripts). WebAssembly module resources have type kRaw. Note that since we
- // can't easily distinguish WebAssembly modules from other raw resources, we
- // perform a code fetch for all raw resources. These fetches should be cheap,
- // however, requiring one additional IPC and no browser process disk IO since
- // the cache index is in memory and the resource key should not be present.
+ // scripts). WebAssembly module resources have type kRaw. Note that we
+ // always perform a code fetch for all of these resources because:
+ //
+ // * It is not easy to distinguish WebAssembly modules from other raw
+ // resources
+ // * The fetch might be handled by Service Workers, but we can't still know
+ // if the response comes from the CacheStorage (in such cases its own
+ // code cache will be used) or not.
+ //
+ // These fetches should be cheap, however, requiring one additional IPC and
+ // no browser process disk IO since the cache index is in memory and the
+ // resource key should not be present.
return resource_->GetType() == ResourceType::kScript ||
resource_->GetType() == ResourceType::kMainResource ||
resource_->GetType() == ResourceType::kRaw;
@@ -422,24 +422,28 @@ void ResourceLoader::Run() {
StartWith(resource_->GetResourceRequest());
}
+ConsoleLogger* ResourceLoader::GetConsoleLogger() {
+ return fetcher_->GetConsoleLogger();
+}
+
void ResourceLoader::StartWith(const ResourceRequest& request) {
DCHECK_NE(ResourceLoadScheduler::kInvalidClientId, scheduler_client_id_);
DCHECK(loader_);
if (resource_->Options().synchronous_policy == kRequestSynchronously &&
- Context().DefersLoading()) {
+ fetcher_->GetProperties().IsPaused()) {
Cancel();
return;
}
is_downloading_to_blob_ = request.DownloadToBlob();
- SetDefersLoading(Context().DefersLoading());
+ SetDefersLoading(fetcher_->GetProperties().IsPaused());
if (ShouldFetchCodeCache()) {
code_cache_request_ = std::make_unique<CodeCacheRequest>(
Context().CreateCodeCacheLoader(), request.Url(),
- Context().DefersLoading());
+ fetcher_->GetProperties().IsPaused());
}
if (is_cache_aware_loading_activated_) {
@@ -547,6 +551,7 @@ static bool IsManualRedirectFetchRequest(const ResourceRequest& request) {
bool ResourceLoader::WillFollowRedirect(
const WebURL& new_url,
const WebURL& new_site_for_cookies,
+ const base::Optional<WebSecurityOrigin>& new_top_frame_origin,
const WebString& new_referrer,
network::mojom::ReferrerPolicy new_referrer_policy,
const WebString& new_method,
@@ -561,10 +566,15 @@ bool ResourceLoader::WillFollowRedirect(
return false;
}
+ scoped_refptr<const SecurityOrigin> top_frame_origin =
+ new_top_frame_origin
+ ? base::WrapRefCounted(new_top_frame_origin.value().Get())
+ : scoped_refptr<SecurityOrigin>();
std::unique_ptr<ResourceRequest> new_request =
resource_->LastResourceRequest().CreateRedirectRequest(
- new_url, new_method, new_site_for_cookies, new_referrer,
- new_referrer_policy,
+ new_url, new_method, new_site_for_cookies, top_frame_origin,
+ new_referrer, new_referrer_policy,
+
!passed_redirect_response.WasFetchedViaServiceWorker());
ResourceType resource_type = resource_->GetType();
@@ -627,7 +637,8 @@ bool ResourceLoader::WillFollowRedirect(
fetch_credentials_mode, *origin);
}
if (cors_error) {
- HandleError(ResourceError(redirect_response.Url(), *cors_error));
+ HandleError(
+ ResourceError(redirect_response.CurrentRequestUrl(), *cors_error));
return false;
}
// If |actualResponse|’s location URL’s origin is not same origin with
@@ -635,9 +646,9 @@ bool ResourceLoader::WillFollowRedirect(
// origin with |request|’s current url’s origin, then set |request|’s
// tainted origin flag.
if (origin &&
- !SecurityOrigin::AreSameSchemeHostPort(new_url,
- redirect_response.Url()) &&
- !origin->CanRequest(redirect_response.Url())) {
+ !SecurityOrigin::AreSameSchemeHostPort(
+ new_url, redirect_response.CurrentRequestUrl()) &&
+ !origin->CanRequest(redirect_response.CurrentRequestUrl())) {
origin = SecurityOrigin::CreateUniqueOpaque();
new_request->SetRequestorOrigin(origin);
}
@@ -650,10 +661,8 @@ bool ResourceLoader::WillFollowRedirect(
}
}
- bool cross_origin =
- !SecurityOrigin::AreSameSchemeHostPort(redirect_response.Url(), new_url);
fetcher_->RecordResourceTimingOnRedirect(resource_.Get(), redirect_response,
- cross_origin);
+ new_url);
base::Optional<ResourceResponse> redirect_response_with_type;
if (ShouldCheckCorsInResourceLoader()) {
@@ -684,16 +693,9 @@ bool ResourceLoader::WillFollowRedirect(
// new_url after calling them, and return false to make the redirect fail on
// mismatch.
- Context().PrepareRequest(*new_request,
+ WebScopedVirtualTimePauser unused_virtual_time_pauser;
+ Context().PrepareRequest(*new_request, unused_virtual_time_pauser,
FetchContext::RedirectType::kForRedirect);
- if (Context().GetFrameScheduler()) {
- WebScopedVirtualTimePauser virtual_time_pauser =
- Context().GetFrameScheduler()->CreateWebScopedVirtualTimePauser(
- resource_->Url().GetString(),
- WebScopedVirtualTimePauser::VirtualTaskDuration::kNonInstant);
- virtual_time_pauser.PauseVirtualTime();
- resource_->VirtualTimePauser() = std::move(virtual_time_pauser);
- }
Context().DispatchWillSendRequest(
resource_->Identifier(), *new_request, redirect_response_to_pass,
resource_->GetType(), options.initiator_info);
@@ -747,7 +749,8 @@ bool ResourceLoader::WillFollowRedirect(
void ResourceLoader::DidReceiveCachedMetadata(const char* data, int length) {
DCHECK(!should_use_isolated_code_cache_);
- resource_->SetSerializedCachedMetadata(data, length);
+ resource_->SetSerializedCachedMetadata(reinterpret_cast<const uint8_t*>(data),
+ length);
}
blink::mojom::CodeCacheType ResourceLoader::GetCodeCacheType() const {
@@ -755,7 +758,8 @@ blink::mojom::CodeCacheType ResourceLoader::GetCodeCacheType() const {
}
void ResourceLoader::SendCachedCodeToResource(const char* data, int length) {
- resource_->SetSerializedCachedMetadata(data, length);
+ resource_->SetSerializedCachedMetadata(reinterpret_cast<const uint8_t*>(data),
+ length);
}
void ResourceLoader::ClearCachedCode() {
@@ -787,10 +791,11 @@ void ResourceLoader::DidReceiveResponse(
request.GetUkmSourceId(), recorder.get());
}
- if (Context().IsDetached()) {
+ if (fetcher_->GetProperties().IsDetached()) {
// If the fetch context is already detached, we don't need further signals,
// so let's cancel the request.
- HandleError(ResourceError::CancelledError(web_url_response.Url()));
+ HandleError(
+ ResourceError::CancelledError(web_url_response.CurrentRequestUrl()));
return;
}
@@ -806,14 +811,9 @@ void ResourceLoader::DidReceiveResponse(
const ResourceLoaderOptions& options = resource_->Options();
const ResourceResponse& response = web_url_response.ToResourceResponse();
- // Service worker script has its own code cache. And also, resources which
- // are served from CacheStorage via service workers have its own code cache.
- // We should not use cached code from site isolated GeneratedCodeCache in such
- // cases.
+
should_use_isolated_code_cache_ =
- RuntimeEnabledFeatures::IsolatedCodeCacheEnabled() &&
- !(request_context == mojom::RequestContextType::SERVICE_WORKER ||
- response.WasFetchedViaServiceWorker());
+ ShouldUseIsolatedCodeCache(request_context, response);
// Perform 'nosniff' checks against the original response instead of the 304
// response for a successful revalidation.
@@ -825,7 +825,7 @@ void ResourceLoader::DidReceiveResponse(
CheckResponseNosniff(request_context, nosniffed_response);
if (blocked_reason) {
HandleError(ResourceError::CancelledDueToAccessCheckError(
- response.Url(), blocked_reason.value()));
+ response.CurrentRequestUrl(), blocked_reason.value()));
return;
}
@@ -840,7 +840,8 @@ void ResourceLoader::DidReceiveResponse(
// handle a cross origin request.
if (!Context().ShouldLoadNewResource(resource_type)) {
// Cancel the request if we should not trigger a reload now.
- HandleError(ResourceError::CancelledError(response.Url()));
+ HandleError(
+ ResourceError::CancelledError(response.CurrentRequestUrl()));
return;
}
last_request.SetSkipServiceWorker(true);
@@ -848,29 +849,41 @@ void ResourceLoader::DidReceiveResponse(
return;
}
- // If the response is fetched via ServiceWorker, the original URL of the
- // response could be different from the URL of the request. We check the URL
- // not to load the resources which are forbidden by the page CSP.
+ // Run post-request CSP checks. This is the "Should response to request be
+ // blocked by Content Security Policy?" algorithm in the CSP specification:
// https://w3c.github.io/webappsec-csp/#should-block-response
- const KURL& original_url = response.OriginalURLViaServiceWorker();
- if (!original_url.IsEmpty()) {
- // CanRequest() below only checks enforced policies: check report-only
- // here to ensure violations are sent.
- Context().CheckCSPForRequest(
- request_context, original_url, options,
- SecurityViolationReportingPolicy::kReport,
- ResourceRequest::RedirectStatus::kFollowedRedirect);
-
- base::Optional<ResourceRequestBlockedReason> blocked_reason =
- Context().CanRequest(
- resource_type, initial_request, original_url, options,
- SecurityViolationReportingPolicy::kReport,
- ResourceRequest::RedirectStatus::kFollowedRedirect);
- if (blocked_reason) {
- HandleError(ResourceError::CancelledDueToAccessCheckError(
- original_url, blocked_reason.value()));
- return;
- }
+ //
+ // In particular, the connect-src directive's post-request check:
+ // https://w3c.github.io/webappsec-csp/#connect-src-post-request)
+ //
+ // We only run post-request checks when the response was fetched via service
+ // worker, because that is the only case where the response URL can differ
+ // from the current request URL, allowing the result of the check to differ
+ // from the pre-request check. The pre-request check is implemented in
+ // ResourceFetcher::PrepareRequest() and
+ // ResourceFetcher::WillFollowRedirect().
+ //
+ // TODO(falken): To align with the CSP specification, implement post-request
+ // checks as a first-class concept instead of just reusing the functions for
+ // pre-request checks, and consider running the checks regardless of service
+ // worker interception.
+ const KURL& response_url = response.ResponseUrl();
+ // CanRequest() below only checks enforced policies: check report-only
+ // here to ensure violations are sent.
+ Context().CheckCSPForRequest(
+ request_context, response_url, options,
+ SecurityViolationReportingPolicy::kReport,
+ ResourceRequest::RedirectStatus::kFollowedRedirect);
+
+ base::Optional<ResourceRequestBlockedReason> blocked_reason =
+ Context().CanRequest(
+ resource_type, initial_request, response_url, options,
+ SecurityViolationReportingPolicy::kReport,
+ ResourceRequest::RedirectStatus::kFollowedRedirect);
+ if (blocked_reason) {
+ HandleError(ResourceError::CancelledDueToAccessCheckError(
+ response_url, blocked_reason.value()));
+ return;
}
}
@@ -880,11 +893,11 @@ void ResourceLoader::DidReceiveResponse(
!(resource_->IsCacheValidator() && response.HttpStatusCode() == 304)) {
if (GetCorsFlag()) {
base::Optional<network::CorsErrorStatus> cors_error = cors::CheckAccess(
- response.Url(), response.HttpStatusCode(),
+ response.CurrentRequestUrl(), response.HttpStatusCode(),
response.HttpHeaderFields(),
initial_request.GetFetchCredentialsMode(), *resource_->GetOrigin());
if (cors_error) {
- HandleError(ResourceError(response.Url(), *cors_error));
+ HandleError(ResourceError(response.CurrentRequestUrl(), *cors_error));
return;
}
}
@@ -899,10 +912,14 @@ void ResourceLoader::DidReceiveResponse(
// FrameType never changes during the lifetime of a request.
Context().DispatchDidReceiveResponse(
- resource_->Identifier(), response_to_pass, initial_request.GetFrameType(),
- request_context, resource_,
+ resource_->Identifier(), initial_request, response_to_pass, resource_,
FetchContext::ResourceResponseType::kNotFromMemoryCache);
+ // When streaming, unpause virtual time early to prevent deadlocking
+ // against stream consumer in case stream has backpressure enabled.
+ if (handle)
+ resource_->VirtualTimePauser().UnpauseVirtualTime();
+
resource_->ResponseReceived(response_to_pass, std::move(handle));
// Send the cached code after we notify that the response is received.
@@ -917,8 +934,10 @@ void ResourceLoader::DidReceiveResponse(
return;
if (response_to_pass.HttpStatusCode() >= 400 &&
- !resource_->ShouldIgnoreHTTPStatusCodeErrors())
- HandleError(ResourceError::CancelledError(response_to_pass.Url()));
+ !resource_->ShouldIgnoreHTTPStatusCodeErrors()) {
+ HandleError(
+ ResourceError::CancelledError(response_to_pass.CurrentRequestUrl()));
+ }
}
void ResourceLoader::DidReceiveResponse(const WebURLResponse& response) {
@@ -935,7 +954,8 @@ void ResourceLoader::DidStartLoadingResponseBody(
AtomicString mime_type = response.MimeType();
mojom::blink::ProgressClientAssociatedPtrInfo progress_client_ptr;
- progress_binding_.Bind(MakeRequest(&progress_client_ptr));
+ progress_binding_.Bind(MakeRequest(&progress_client_ptr),
+ GetLoadingTaskRunner());
// Callback is bound to a WeakPersistent, as ResourceLoader is kept alive by
// ResourceFetcher as long as we still care about the result of the load.
@@ -1025,6 +1045,11 @@ void ResourceLoader::DidFail(const WebURLError& error,
HandleError(error);
}
+void ResourceLoader::SetContinueNavigationRequestCallback(
+ base::OnceClosure closure) {
+ resource_->SetContinueNavigationRequestCallback(std::move(closure));
+}
+
void ResourceLoader::HandleError(const ResourceError& error) {
if (is_cache_aware_loading_activated_ && error.IsCacheMiss() &&
Context().ShouldLoadNewResource(resource_->GetType())) {
@@ -1034,12 +1059,12 @@ void ResourceLoader::HandleError(const ResourceError& error) {
return;
}
if (error.CorsErrorStatus()) {
- Context().AddErrorConsoleMessage(
+ GetConsoleLogger()->AddErrorMessage(
+ ConsoleLogger::Source::kScript,
cors::GetErrorString(
*error.CorsErrorStatus(), resource_->GetResourceRequest().Url(),
resource_->LastResourceRequest().Url(), *resource_->GetOrigin(),
- resource_->GetType(), resource_->Options().initiator_info.name),
- FetchContext::kJSSource);
+ resource_->GetType(), resource_->Options().initiator_info.name));
}
Release(ResourceLoadScheduler::ReleaseOption::kReleaseAndSchedule,
@@ -1162,7 +1187,7 @@ bool ResourceLoader::ShouldBeKeptAliveWhenDetached() const {
scoped_refptr<base::SingleThreadTaskRunner>
ResourceLoader::GetLoadingTaskRunner() {
- return Context().GetLoadingTaskRunner();
+ return fetcher_->GetTaskRunner();
}
void ResourceLoader::OnProgress(uint64_t delta) {
@@ -1172,7 +1197,7 @@ void ResourceLoader::OnProgress(uint64_t delta) {
return;
Context().DispatchDidReceiveData(resource_->Identifier(), nullptr, delta);
- resource_->DidDownloadData(SafeCast<int>(delta));
+ resource_->DidDownloadData(delta);
}
void ResourceLoader::FinishedCreatingBlob(
@@ -1198,7 +1223,7 @@ void ResourceLoader::FinishedCreatingBlob(
base::Optional<ResourceRequestBlockedReason>
ResourceLoader::CheckResponseNosniff(mojom::RequestContextType request_context,
- const ResourceResponse& response) const {
+ const ResourceResponse& response) {
bool sniffing_allowed =
ParseContentTypeOptionsHeader(response.HttpHeaderField(
http_names::kXContentTypeOptions)) != kContentTypeOptionsNosniff;
@@ -1208,12 +1233,13 @@ ResourceLoader::CheckResponseNosniff(mojom::RequestContextType request_context,
String mime_type = response.HttpContentType();
if (request_context == mojom::RequestContextType::STYLE &&
!MIMETypeRegistry::IsSupportedStyleSheetMIMEType(mime_type)) {
- Context().AddErrorConsoleMessage(
- "Refused to apply style from '" + response.Url().ElidedString() +
+ GetConsoleLogger()->AddErrorMessage(
+ ConsoleLogger::Source::kSecurity,
+ "Refused to apply style from '" +
+ response.CurrentRequestUrl().ElidedString() +
"' because its MIME type ('" + mime_type + "') " +
"is not a supported stylesheet MIME type, and strict MIME checking "
- "is enabled.",
- FetchContext::kSecuritySource);
+ "is enabled.");
return ResourceRequestBlockedReason::kContentType;
}
// TODO(mkwst): Move the 'nosniff' bit of 'AllowedByNosniff::MimeTypeAsScript'
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
index 2cc7f9cae9d..7c4fa4dfb60 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -47,6 +47,7 @@
namespace blink {
+class ConsoleLogger;
class FetchContext;
class ResourceError;
class ResourceFetcher;
@@ -109,13 +110,15 @@ class PLATFORM_EXPORT ResourceLoader final
// A failed load is indicated by 1 DidFail(), which can occur at any time
// before DidFinishLoading(), including synchronous inside one of the other
// callbacks via ResourceLoader::cancel()
- bool WillFollowRedirect(const WebURL& new_url,
- const WebURL& new_site_for_cookies,
- const WebString& new_referrer,
- network::mojom::ReferrerPolicy new_referrer_policy,
- const WebString& new_method,
- const WebURLResponse& passed_redirect_response,
- bool& report_raw_headers) override;
+ bool WillFollowRedirect(
+ const WebURL& new_url,
+ const WebURL& new_site_for_cookies,
+ const base::Optional<WebSecurityOrigin>& new_top_frame_origin,
+ const WebString& new_referrer,
+ network::mojom::ReferrerPolicy new_referrer_policy,
+ const WebString& new_method,
+ const WebURLResponse& passed_redirect_response,
+ bool& report_raw_headers) override;
void DidSendData(unsigned long long bytes_sent,
unsigned long long total_bytes_to_be_sent) override;
void DidReceiveResponse(const WebURLResponse&) override;
@@ -137,6 +140,7 @@ class PLATFORM_EXPORT ResourceLoader final
int64_t encoded_data_length,
int64_t encoded_body_length,
int64_t decoded_body_length) override;
+ void SetContinueNavigationRequestCallback(base::OnceClosure) override;
blink::mojom::CodeCacheType GetCodeCacheType() const;
void SendCachedCodeToResource(const char* data, int size);
@@ -146,15 +150,17 @@ class PLATFORM_EXPORT ResourceLoader final
void DidFinishLoadingFirstPartInMultipart();
- // ResourceLoadSchedulerClient.
- void Run() override;
-
scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner();
private:
friend class SubresourceIntegrityTest;
+ friend class ResourceLoaderIsolatedCodeCacheTest;
class CodeCacheRequest;
+ // ResourceLoadSchedulerClient.
+ void Run() override;
+ ConsoleLogger* GetConsoleLogger() override;
+
bool ShouldFetchCodeCache();
void StartWith(const ResourceRequest&);
@@ -182,7 +188,7 @@ class PLATFORM_EXPORT ResourceLoader final
base::Optional<ResourceRequestBlockedReason> CheckResponseNosniff(
mojom::RequestContextType,
- const ResourceResponse&) const;
+ const ResourceResponse&);
bool ShouldCheckCorsInResourceLoader() const;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
index 66c097c3235..32f427a3253 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
@@ -10,7 +10,9 @@
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
namespace blink {
@@ -26,16 +28,17 @@ class ResourceLoaderDefersLoadingTest : public testing::Test {
ResourceLoaderDefersLoadingTest();
- void SetUp() override {
- context_ =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- }
+ void SetUp() override { context_ = MakeGarbageCollected<MockFetchContext>(); }
void SaveCodeCacheCallback(CodeCacheLoader::FetchCodeCacheCallback callback) {
// Store the callback to send back a response.
code_cache_response_callback_ = std::move(callback);
}
+ static scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() {
+ return base::MakeRefCounted<scheduler::FakeTaskRunner>();
+ }
+
CodeCacheLoader::FetchCodeCacheCallback code_cache_response_callback_;
// Passed to TestWebURLLoader (via |platform_|) and updated when its
// SetDefersLoading method is called.
@@ -162,7 +165,9 @@ ResourceLoaderDefersLoadingTest::ResourceLoaderDefersLoadingTest()
}
TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchCheckDefers) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context_, CreateTaskRunner()));
ResourceRequest request;
request.SetURL(test_url_);
@@ -170,8 +175,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchCheckDefers) {
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
- Resource* resource = RawResource::FetchMainResource(
- fetch_parameters, fetcher, nullptr, SubstituteData());
+ Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
+ nullptr, SubstituteData(),
+ CreateUniqueIdentifier());
// After code cache fetch it should have deferred WebURLLoader.
DCHECK(web_url_loader_defers_);
@@ -188,7 +194,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchSyncReturn) {
std::move(callback).Run(base::Time(), std::vector<uint8_t>());
}));
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context_, CreateTaskRunner()));
ResourceRequest request;
request.SetURL(test_url_);
@@ -196,15 +204,18 @@ TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchSyncReturn) {
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
- Resource* resource = RawResource::FetchMainResource(
- fetch_parameters, fetcher, nullptr, SubstituteData());
+ Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
+ nullptr, SubstituteData(),
+ CreateUniqueIdentifier());
DCHECK(resource);
// The callback would be called so it should not be deferred.
DCHECK(!web_url_loader_defers_);
}
TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToFalse) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context_, CreateTaskRunner()));
ResourceRequest request;
request.SetURL(test_url_);
@@ -212,8 +223,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToFalse) {
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
- Resource* resource = RawResource::FetchMainResource(
- fetch_parameters, fetcher, nullptr, SubstituteData());
+ Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
+ nullptr, SubstituteData(),
+ CreateUniqueIdentifier());
DCHECK(web_url_loader_defers_);
// Change Defers loading to false. This should not be sent to
@@ -224,7 +236,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToFalse) {
}
TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToTrue) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context_, CreateTaskRunner()));
ResourceRequest request;
request.SetURL(test_url_);
@@ -232,8 +246,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToTrue) {
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
- Resource* resource = RawResource::FetchMainResource(
- fetch_parameters, fetcher, nullptr, SubstituteData());
+ Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
+ nullptr, SubstituteData(),
+ CreateUniqueIdentifier());
DCHECK(web_url_loader_defers_);
ResourceLoader* loader = resource->Loader();
@@ -248,7 +263,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToTrue) {
}
TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersMultipleTimes) {
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context_, CreateTaskRunner()));
ResourceRequest request;
request.SetURL(test_url_);
@@ -256,8 +273,9 @@ TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersMultipleTimes) {
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
- Resource* resource = RawResource::FetchMainResource(
- fetch_parameters, fetcher, nullptr, SubstituteData());
+ Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
+ nullptr, SubstituteData(),
+ CreateUniqueIdentifier());
DCHECK(web_url_loader_defers_);
ResourceLoader* loader = resource->Loader();
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
index 274bcb8e56f..8e0831e7e5d 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -32,12 +33,6 @@ class ResourceLoaderTest : public testing::Test {
ResourceLoaderTest()
: foo_url_("https://foo.test"), bar_url_("https://bar.test"){};
- void SetUp() override {
- context_ = MockFetchContext::Create(
- MockFetchContext::kShouldLoadNewResource, nullptr,
- std::make_unique<TestWebURLLoaderFactory>());
- }
-
protected:
using FetchRequestMode = network::mojom::FetchRequestMode;
using FetchResponseType = network::mojom::FetchResponseType;
@@ -51,15 +46,12 @@ class ResourceLoaderTest : public testing::Test {
const FetchResponseType expectation;
};
- Persistent<MockFetchContext> context_;
-
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
platform_;
const KURL foo_url_;
const KURL bar_url_;
- private:
class TestWebURLLoaderFactory final : public WebURLLoaderFactory {
std::unique_ptr<WebURLLoader> CreateURLLoader(
const WebURLRequest& request,
@@ -69,6 +61,11 @@ class ResourceLoaderTest : public testing::Test {
}
};
+ static scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() {
+ return base::MakeRefCounted<scheduler::FakeTaskRunner>();
+ }
+
+ private:
class TestWebURLLoader final : public WebURLLoader {
public:
~TestWebURLLoader() override = default;
@@ -164,8 +161,12 @@ TEST_F(ResourceLoaderTest, ResponseType) {
<< ", original_response_type: "
<< test.original_response_type);
- context_->SetSecurityOrigin(origin);
- ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(origin);
+ FetchContext* context = MakeGarbageCollected<MockFetchContext>(
+ nullptr, std::make_unique<TestWebURLLoaderFactory>());
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
ResourceRequest request;
request.SetURL(test.url);
@@ -195,4 +196,73 @@ TEST_F(ResourceLoaderTest, ResponseType) {
}
}
+class ResourceLoaderIsolatedCodeCacheTest : public ResourceLoaderTest {
+ protected:
+ bool LoadAndCheckIsolatedCodeCache(ResourceResponse response) {
+ const scoped_refptr<const SecurityOrigin> origin =
+ SecurityOrigin::Create(foo_url_);
+
+ auto* properties =
+ MakeGarbageCollected<TestResourceFetcherProperties>(origin);
+ FetchContext* context = MakeGarbageCollected<MockFetchContext>(
+ nullptr, std::make_unique<TestWebURLLoaderFactory>());
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(*properties, context, CreateTaskRunner()));
+
+ ResourceRequest request;
+ request.SetURL(foo_url_);
+ request.SetRequestContext(mojom::RequestContextType::FETCH);
+
+ FetchParameters fetch_parameters(request);
+ Resource* resource = RawResource::Fetch(fetch_parameters, fetcher, nullptr);
+ ResourceLoader* loader = resource->Loader();
+
+ loader->DidReceiveResponse(WrappedResourceResponse(response));
+ return loader->should_use_isolated_code_cache_;
+ }
+};
+
+TEST_F(ResourceLoaderIsolatedCodeCacheTest, ResponseFromNetwork) {
+ ResourceResponse response(foo_url_);
+ response.SetHTTPStatusCode(200);
+ EXPECT_EQ(true, LoadAndCheckIsolatedCodeCache(response));
+}
+
+TEST_F(ResourceLoaderIsolatedCodeCacheTest,
+ SyntheticResponseFromServiceWorker) {
+ ResourceResponse response(foo_url_);
+ response.SetHTTPStatusCode(200);
+ response.SetWasFetchedViaServiceWorker(true);
+ EXPECT_EQ(false, LoadAndCheckIsolatedCodeCache(response));
+}
+
+TEST_F(ResourceLoaderIsolatedCodeCacheTest,
+ PassThroughResponseFromServiceWorker) {
+ ResourceResponse response(foo_url_);
+ response.SetHTTPStatusCode(200);
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetURLListViaServiceWorker(Vector<KURL>(1, foo_url_));
+ EXPECT_EQ(true, LoadAndCheckIsolatedCodeCache(response));
+}
+
+TEST_F(ResourceLoaderIsolatedCodeCacheTest,
+ DifferentUrlResponseFromServiceWorker) {
+ ResourceResponse response(foo_url_);
+ response.SetHTTPStatusCode(200);
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetURLListViaServiceWorker(Vector<KURL>(1, bar_url_));
+ EXPECT_EQ(false, LoadAndCheckIsolatedCodeCache(response));
+}
+
+TEST_F(ResourceLoaderIsolatedCodeCacheTest, CacheResponseFromServiceWorker) {
+ ResourceResponse response(foo_url_);
+ response.SetHTTPStatusCode(200);
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetCacheStorageCacheName("dummy");
+ // The browser does support code cache for cache_storage Responses, but they
+ // are loaded via a different mechanism. So the ResourceLoader code caching
+ // value should be false here.
+ EXPECT_EQ(false, LoadAndCheckIsolatedCodeCache(response));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index 4e0c30afdc0..ed8be44d87f 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -93,6 +93,7 @@ std::unique_ptr<ResourceRequest> ResourceRequest::CreateRedirectRequest(
const KURL& new_url,
const AtomicString& new_method,
const KURL& new_site_for_cookies,
+ scoped_refptr<const SecurityOrigin> new_top_frame_origin,
const String& new_referrer,
network::mojom::ReferrerPolicy new_referrer_policy,
bool skip_service_worker) const {
@@ -101,6 +102,7 @@ std::unique_ptr<ResourceRequest> ResourceRequest::CreateRedirectRequest(
request->SetRequestorOrigin(RequestorOrigin());
request->SetHTTPMethod(new_method);
request->SetSiteForCookies(new_site_for_cookies);
+ request->SetTopFrameOrigin(std::move(new_top_frame_origin));
String referrer =
new_referrer.IsEmpty() ? Referrer::NoReferrer() : String(new_referrer);
// TODO(domfarolino): Stop storing ResourceRequest's generated referrer as a
@@ -126,7 +128,6 @@ std::unique_ptr<ResourceRequest> ResourceRequest::CreateRedirectRequest(
request->SetCorsPreflightPolicy(CorsPreflightPolicy());
if (IsAdResource())
request->SetIsAdResource();
- request->SetInitiatorCSP(GetInitiatorCSP());
request->SetUpgradeIfInsecure(UpgradeIfInsecure());
request->SetIsAutomaticUpgrade(IsAutomaticUpgrade());
request->SetRequestedWithHeader(GetRequestedWithHeader());
@@ -148,6 +149,14 @@ void ResourceRequest::SetURL(const KURL& url) {
url_ = url;
}
+const KURL& ResourceRequest::GetInitialUrlForResourceTiming() const {
+ return initial_url_for_resource_timing_;
+}
+
+void ResourceRequest::SetInitialUrlForResourceTiming(const KURL& url) {
+ initial_url_for_resource_timing_ = url;
+}
+
void ResourceRequest::RemoveUserAndPassFromURL() {
if (url_.User().IsEmpty() && url_.Pass().IsEmpty())
return;
@@ -181,6 +190,15 @@ void ResourceRequest::SetSiteForCookies(const KURL& site_for_cookies) {
site_for_cookies_ = site_for_cookies;
}
+const SecurityOrigin* ResourceRequest::TopFrameOrigin() const {
+ return top_frame_origin_.get();
+}
+
+void ResourceRequest::SetTopFrameOrigin(
+ scoped_refptr<const SecurityOrigin> origin) {
+ top_frame_origin_ = std::move(origin);
+}
+
const AtomicString& ResourceRequest::HttpMethod() const {
return http_method_;
}
@@ -318,10 +336,6 @@ void ResourceRequest::SetExternalRequestStateFromRequestorAddressSpace(
is_external_request_ = requestor_space > target_space;
}
-void ResourceRequest::SetNavigationStartTime(TimeTicks navigation_start) {
- navigation_start_ = navigation_start;
-}
-
bool ResourceRequest::IsConditional() const {
return (http_header_fields_.Contains(http_names::kIfMatch) ||
http_header_fields_.Contains(http_names::kIfModifiedSince) ||
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h
index 98f750cd6b5..3670d334d3c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h
@@ -33,13 +33,13 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/cors.mojom-blink.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
-#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
#include "third_party/blink/renderer/platform/network/http_header_map.h"
@@ -84,6 +84,7 @@ class PLATFORM_EXPORT ResourceRequest final {
const KURL& new_url,
const AtomicString& new_method,
const KURL& new_site_for_cookies,
+ scoped_refptr<const SecurityOrigin> new_top_frame_origin,
const String& new_referrer,
network::mojom::ReferrerPolicy new_referrer_policy,
bool skip_service_worker) const;
@@ -93,6 +94,14 @@ class PLATFORM_EXPORT ResourceRequest final {
const KURL& Url() const;
void SetURL(const KURL&);
+ // ThreadableLoader sometimes breaks redirect chains into separate Resource
+ // and ResourceRequests. The ResourceTiming API needs the initial URL for the
+ // name attribute of PerformanceResourceTiming entries. This property
+ // remembers the initial URL for that purpose. Note that it can return a null
+ // URL. In that case, use Url() instead.
+ const KURL& GetInitialUrlForResourceTiming() const;
+ void SetInitialUrlForResourceTiming(const KURL&);
+
void RemoveUserAndPassFromURL();
mojom::FetchCacheMode GetCacheMode() const;
@@ -104,6 +113,9 @@ class PLATFORM_EXPORT ResourceRequest final {
const KURL& SiteForCookies() const;
void SetSiteForCookies(const KURL&);
+ const SecurityOrigin* TopFrameOrigin() const;
+ void SetTopFrameOrigin(scoped_refptr<const SecurityOrigin>);
+
// The origin of the request, specified at
// https://fetch.spec.whatwg.org/#concept-request-origin. This origin can be
// null upon request, corresponding to the "client" value in the spec. In that
@@ -358,19 +370,9 @@ class PLATFORM_EXPORT ResourceRequest final {
return suggested_filename_;
}
- void SetNavigationStartTime(TimeTicks);
- TimeTicks NavigationStartTime() const { return navigation_start_; }
-
void SetIsAdResource() { is_ad_resource_ = true; }
bool IsAdResource() const { return is_ad_resource_; }
- void SetInitiatorCSP(const WebContentSecurityPolicyList& initiator_csp) {
- initiator_csp_ = initiator_csp;
- }
- const WebContentSecurityPolicyList& GetInitiatorCSP() const {
- return initiator_csp_;
- }
-
void SetUpgradeIfInsecure(bool upgrade_if_insecure) {
upgrade_if_insecure_ = upgrade_if_insecure;
}
@@ -414,8 +416,10 @@ class PLATFORM_EXPORT ResourceRequest final {
void SetClientDataHeader(const String& value) { client_data_header_ = value; }
const String& GetClientDataHeader() const { return client_data_header_; }
- void SetUkmSourceId(int64_t ukm_source_id) { ukm_source_id_ = ukm_source_id; }
- int64_t GetUkmSourceId() const { return ukm_source_id_; }
+ void SetUkmSourceId(ukm::SourceId ukm_source_id) {
+ ukm_source_id_ = ukm_source_id;
+ }
+ ukm::SourceId GetUkmSourceId() const { return ukm_source_id_; }
// https://fetch.spec.whatwg.org/#concept-request-window
// See network::ResourceRequest::fetch_window_id for details.
@@ -435,9 +439,13 @@ class PLATFORM_EXPORT ResourceRequest final {
bool NeedsHTTPOrigin() const;
KURL url_;
+ // TODO(yoav): initial_url_for_resource_timing_ is a stop-gap only needed
+ // until Out-of-Blink CORS lands: https://crbug.com/736308
+ KURL initial_url_for_resource_timing_;
// TimeDelta::Max() represents the default timeout on platforms that have one.
base::TimeDelta timeout_interval_;
KURL site_for_cookies_;
+ scoped_refptr<const SecurityOrigin> top_frame_origin_;
scoped_refptr<const SecurityOrigin> requestor_origin_;
@@ -487,10 +495,7 @@ class PLATFORM_EXPORT ResourceRequest final {
static base::TimeDelta default_timeout_interval_;
- TimeTicks navigation_start_;
-
bool is_ad_resource_ = false;
- WebContentSecurityPolicyList initiator_csp_;
bool upgrade_if_insecure_ = false;
bool is_revalidating_ = false;
@@ -502,7 +507,7 @@ class PLATFORM_EXPORT ResourceRequest final {
String requested_with_header_;
String client_data_header_;
- int64_t ukm_source_id_;
+ ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
base::UnguessableToken fetch_window_id_;
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request_test.cc
index ffb5fbcea4d..188cbd4ecc1 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request_test.cc
@@ -33,11 +33,28 @@ TEST(ResourceRequestTest, SetIsAdResource) {
std::unique_ptr<ResourceRequest> redirect_request =
original.CreateRedirectRequest(
KURL("https://example.test/redirect"), original.HttpMethod(),
- original.SiteForCookies(), original.HttpReferrer(),
- original.GetReferrerPolicy(), original.GetSkipServiceWorker());
+ original.SiteForCookies(), original.TopFrameOrigin(),
+ original.HttpReferrer(), original.GetReferrerPolicy(),
+ original.GetSkipServiceWorker());
EXPECT_TRUE(redirect_request->IsAdResource());
}
+TEST(ResourceRequestTest, SetTopFrameURL) {
+ KURL url("http://example.com");
+ scoped_refptr<SecurityOrigin> origin = SecurityOrigin::Create(url);
+ ResourceRequest original;
+ original.SetTopFrameOrigin(origin);
+
+ // Should persist across redirects.
+ std::unique_ptr<ResourceRequest> redirect_request =
+ original.CreateRedirectRequest(
+ KURL("https://example.test/redirect"), original.HttpMethod(),
+ original.SiteForCookies(), original.TopFrameOrigin(),
+ original.HttpReferrer(), original.GetReferrerPolicy(),
+ original.GetSkipServiceWorker());
+ EXPECT_EQ(origin, redirect_request->TopFrameOrigin());
+}
+
TEST(ResourceRequestTest, UpgradeIfInsecureAcrossRedirects) {
ResourceRequest original;
EXPECT_FALSE(original.UpgradeIfInsecure());
@@ -48,8 +65,9 @@ TEST(ResourceRequestTest, UpgradeIfInsecureAcrossRedirects) {
std::unique_ptr<ResourceRequest> redirect_request =
original.CreateRedirectRequest(
KURL("https://example.test/redirect"), original.HttpMethod(),
- original.SiteForCookies(), original.HttpReferrer(),
- original.GetReferrerPolicy(), original.GetSkipServiceWorker());
+ original.SiteForCookies(), original.TopFrameOrigin(),
+ original.HttpReferrer(), original.GetReferrerPolicy(),
+ original.GetSkipServiceWorker());
EXPECT_TRUE(redirect_request->UpgradeIfInsecure());
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
index 27757d33de9..595737f1384 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
@@ -79,25 +79,57 @@ ResourceResponse::SignedCertificateTimestamp::IsolatedCopy() const {
ResourceResponse::ResourceResponse() : is_null_(true) {}
-ResourceResponse::ResourceResponse(const KURL& url)
- : url_(url), is_null_(false) {}
+ResourceResponse::ResourceResponse(const KURL& current_request_url)
+ : current_request_url_(current_request_url), is_null_(false) {}
ResourceResponse::ResourceResponse(const ResourceResponse&) = default;
ResourceResponse& ResourceResponse::operator=(const ResourceResponse&) =
default;
bool ResourceResponse::IsHTTP() const {
- return url_.ProtocolIsInHTTPFamily();
+ return current_request_url_.ProtocolIsInHTTPFamily();
}
-const KURL& ResourceResponse::Url() const {
- return url_;
+const KURL& ResourceResponse::CurrentRequestUrl() const {
+ return current_request_url_;
}
-void ResourceResponse::SetURL(const KURL& url) {
+void ResourceResponse::SetCurrentRequestUrl(const KURL& url) {
is_null_ = false;
- url_ = url;
+ current_request_url_ = url;
+}
+
+KURL ResourceResponse::ResponseUrl() const {
+ // Ideally ResourceResponse would have a |url_list_| to match Fetch
+ // specification's URL list concept
+ // (https://fetch.spec.whatwg.org/#concept-response-url-list), and its
+ // last element would be returned here.
+ //
+ // Instead it has |url_list_via_service_worker_| which is only populated when
+ // the response came from a service worker, and that response was not created
+ // through `new Response()`. Use it when available.
+ if (!url_list_via_service_worker_.IsEmpty()) {
+ DCHECK(WasFetchedViaServiceWorker());
+ return url_list_via_service_worker_.back();
+ }
+
+ // Otherwise, use the current request URL. This is OK because the Fetch
+ // specification's "main fetch" algorithm[1] sets the response URL list to the
+ // request's URL list when the list isn't present. That step can't be
+ // implemented now because there is no |url_list_| memeber, but effectively
+ // the same thing happens by returning CurrentRequestUrl() here.
+ //
+ // [1] "If internalResponse’s URL list is empty, then set it to a clone of
+ // request’s URL list." at
+ // https://fetch.spec.whatwg.org/#ref-for-concept-response-url-list%E2%91%A4
+ return CurrentRequestUrl();
+}
+
+bool ResourceResponse::IsServiceWorkerPassThrough() const {
+ return cache_storage_cache_name_.IsEmpty() &&
+ !url_list_via_service_worker_.IsEmpty() &&
+ ResponseUrl() == CurrentRequestUrl();
}
const AtomicString& ResourceResponse::MimeType() const {
@@ -401,16 +433,6 @@ void ResourceResponse::SetCTPolicyCompliance(CTPolicyCompliance compliance) {
ct_policy_compliance_ = compliance;
}
-bool ResourceResponse::IsOpaqueResponseFromServiceWorker() const {
- return IsCorsCrossOrigin() && WasFetchedViaServiceWorker();
-}
-
-KURL ResourceResponse::OriginalURLViaServiceWorker() const {
- if (url_list_via_service_worker_.IsEmpty())
- return KURL();
- return url_list_via_service_worker_.back();
-}
-
AtomicString ResourceResponse::ConnectionInfoString() const {
std::string connection_info_string =
net::HttpResponseInfo::ConnectionInfoToString(connection_info_);
@@ -431,41 +453,6 @@ void ResourceResponse::SetDecodedBodyLength(int64_t value) {
decoded_body_length_ = value;
}
-void ResourceResponse::AppendRedirectResponse(
- const ResourceResponse& response) {
- redirect_responses_.push_back(response);
-}
-
-bool ResourceResponse::Compare(const ResourceResponse& a,
- const ResourceResponse& b) {
- if (a.IsNull() != b.IsNull())
- return false;
- if (a.Url() != b.Url())
- return false;
- if (a.MimeType() != b.MimeType())
- return false;
- if (a.ExpectedContentLength() != b.ExpectedContentLength())
- return false;
- if (a.TextEncodingName() != b.TextEncodingName())
- return false;
- if (a.HttpStatusCode() != b.HttpStatusCode())
- return false;
- if (a.HttpStatusText() != b.HttpStatusText())
- return false;
- if (a.HttpHeaderFields() != b.HttpHeaderFields())
- return false;
- if (a.GetResourceLoadTiming() && b.GetResourceLoadTiming() &&
- *a.GetResourceLoadTiming() == *b.GetResourceLoadTiming())
- return true;
- if (a.GetResourceLoadTiming() != b.GetResourceLoadTiming())
- return false;
- if (a.EncodedBodyLength() != b.EncodedBodyLength())
- return false;
- if (a.DecodedBodyLength() != b.DecodedBodyLength())
- return false;
- return true;
-}
-
STATIC_ASSERT_ENUM(WebURLResponse::kHTTPVersionUnknown,
ResourceResponse::kHTTPVersionUnknown);
STATIC_ASSERT_ENUM(WebURLResponse::kHTTPVersion_0_9,
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index bd18c9cc5cd..664d2639c47 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -138,24 +138,27 @@ class PLATFORM_EXPORT ResourceResponse final {
SignedCertificateTimestampList sct_list;
};
- class ExtraData : public RefCounted<ExtraData> {
- public:
- virtual ~ExtraData() = default;
- };
-
ResourceResponse();
- explicit ResourceResponse(const KURL&);
+ explicit ResourceResponse(const KURL& current_request_url);
ResourceResponse(const ResourceResponse&);
ResourceResponse& operator=(const ResourceResponse&);
bool IsNull() const { return is_null_; }
bool IsHTTP() const;
- // The URL of the resource. Note that if a service worker responded to the
- // request for this resource, it may have fetched an entirely different URL
- // and responded with that resource. wasFetchedViaServiceWorker() and
- // originalURLViaServiceWorker() can be used to determine whether and how a
- // service worker responded to the request. Example service worker code:
+ // The current request URL for this resource (the URL after redirects).
+ // Corresponds to:
+ // https://fetch.spec.whatwg.org/#concept-request-current-url
+ //
+ // Beware that this might not be the same the response URL, so it is usually
+ // incorrect to use this in security checks. Use GetType() to determine origin
+ // sameness.
+ //
+ // Specifically, if a service worker responded to the request for this
+ // resource, it may have fetched an entirely different URL and responded with
+ // that resource. WasFetchedViaServiceWorker() and ResponseUrl() can be used
+ // to determine whether and how a service worker responded to the request.
+ // Example service worker code:
//
// onfetch = (event => {
// if (event.request.url == 'https://abc.com')
@@ -163,11 +166,24 @@ class PLATFORM_EXPORT ResourceResponse final {
// });
//
// If this service worker responds to an "https://abc.com" request, then for
- // the resulting ResourceResponse, url() is "https://abc.com",
- // wasFetchedViaServiceWorker() is true, and originalURLViaServiceWorker() is
+ // the resulting ResourceResponse, CurrentRequestUrl() is "https://abc.com",
+ // WasFetchedViaServiceWorker() is true, and ResponseUrl() is
// "https://def.com".
- const KURL& Url() const;
- void SetURL(const KURL&);
+ const KURL& CurrentRequestUrl() const;
+ void SetCurrentRequestUrl(const KURL&);
+
+ // The response URL of this resource. Corresponds to:
+ // https://fetch.spec.whatwg.org/#concept-response-url
+ //
+ // This returns the same URL as CurrentRequestUrl() unless a service worker
+ // responded to the request. See the comments for that function.
+ KURL ResponseUrl() const;
+
+ // Returns true if this response is the result of a service worker
+ // effectively calling `evt.respondWith(fetch(evt.request))`. Specifically,
+ // it returns false for synthetic constructed responses, responses fetched
+ // from different URLs, and responses produced by cache_storage.
+ bool IsServiceWorkerPassThrough() const;
const AtomicString& MimeType() const;
void SetMimeType(const AtomicString&);
@@ -190,8 +206,6 @@ class PLATFORM_EXPORT ResourceResponse final {
void ClearHTTPHeaderField(const AtomicString& name);
const HTTPHeaderMap& HttpHeaderFields() const;
- bool IsMultipart() const { return MimeType() == "multipart/x-mixed-replace"; }
-
bool IsAttachment() const;
AtomicString HttpContentType() const;
@@ -303,7 +317,6 @@ class PLATFORM_EXPORT ResourceResponse final {
void SetType(network::mojom::FetchResponseType value) {
response_type_ = value;
}
- bool IsOpaqueResponseFromServiceWorker() const;
// https://html.spec.whatwg.org/#cors-same-origin
bool IsCorsSameOrigin() const {
return network::cors::IsCorsSameOriginResponseType(response_type_);
@@ -321,16 +334,6 @@ class PLATFORM_EXPORT ResourceResponse final {
url_list_via_service_worker_ = url_list;
}
- // Returns the last URL of urlListViaServiceWorker if exists. Otherwise
- // returns an empty URL.
- KURL OriginalURLViaServiceWorker() const;
-
- const Vector<char>& MultipartBoundary() const { return multipart_boundary_; }
- void SetMultipartBoundary(const char* bytes, uint32_t size) {
- multipart_boundary_.clear();
- multipart_boundary_.Append(bytes, size);
- }
-
const String& CacheStorageCacheName() const {
return cache_storage_cache_name_;
}
@@ -388,25 +391,11 @@ class PLATFORM_EXPORT ResourceResponse final {
int64_t DecodedBodyLength() const { return decoded_body_length_; }
void SetDecodedBodyLength(int64_t value);
- // Extra data associated with this response.
- ExtraData* GetExtraData() const { return extra_data_.get(); }
- void SetExtraData(scoped_refptr<ExtraData> extra_data) {
- extra_data_ = std::move(extra_data);
- }
-
unsigned MemoryUsage() const {
// average size, mostly due to URL and Header Map strings
return 1280;
}
- // PlzNavigate: Even if there is redirections, only one
- // ResourceResponse is built: the final response.
- // The redirect response chain can be accessed by this function.
- const Vector<ResourceResponse>& RedirectResponses() const {
- return redirect_responses_;
- }
- void AppendRedirectResponse(const ResourceResponse&);
-
bool AsyncRevalidationRequested() const {
return async_revalidation_requested_;
}
@@ -430,13 +419,10 @@ class PLATFORM_EXPORT ResourceResponse final {
is_signed_exchange_inner_response_ = is_signed_exchange_inner_response;
}
- // This method doesn't compare the all members.
- static bool Compare(const ResourceResponse&, const ResourceResponse&);
-
private:
void UpdateHeaderParsedState(const AtomicString& name);
- KURL url_;
+ KURL current_request_url_;
AtomicString mime_type_;
long long expected_content_length_ = 0;
AtomicString text_encoding_name_;
@@ -542,9 +528,6 @@ class PLATFORM_EXPORT ResourceResponse final {
// Note: only valid for main resource responses.
KURL app_cache_manifest_url_;
- // The multipart boundary of this response.
- Vector<char> multipart_boundary_;
-
// The URL list of the response which was fetched by the ServiceWorker.
// This is empty if the response was created inside the ServiceWorker.
Vector<KURL> url_list_via_service_worker_;
@@ -577,22 +560,8 @@ class PLATFORM_EXPORT ResourceResponse final {
// Sizes of the response body in bytes after any content-encoding is
// removed.
int64_t decoded_body_length_ = 0;
-
- // ExtraData associated with the response.
- scoped_refptr<ExtraData> extra_data_;
-
- // PlzNavigate: the redirect responses are transmitted
- // inside the final response.
- Vector<ResourceResponse> redirect_responses_;
};
-inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) {
- return ResourceResponse::Compare(a, b);
-}
-inline bool operator!=(const ResourceResponse& a, const ResourceResponse& b) {
- return !(a == b);
-}
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RESOURCE_RESPONSE_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
index 014a96dc783..c5e46846716 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
@@ -30,15 +30,28 @@ class MockPlatform final : public TestingPlatformSupportWithMockScheduler {
void CacheMetadata(blink::mojom::CodeCacheType cache_type,
const WebURL& url,
Time,
- const char*,
+ const uint8_t*,
size_t) override {
cached_urls_.push_back(url);
}
+ void CacheMetadataInCacheStorage(const blink::WebURL& url,
+ base::Time,
+ const uint8_t*,
+ size_t,
+ const blink::WebSecurityOrigin&,
+ const blink::WebString&) override {
+ cache_storage_cached_urls_.push_back(url);
+ }
+
const Vector<WebURL>& CachedURLs() const { return cached_urls_; }
+ const Vector<WebURL>& CacheStorageCachedURLs() const {
+ return cache_storage_cached_urls_;
+ }
private:
Vector<WebURL> cached_urls_;
+ Vector<WebURL> cache_storage_cached_urls_;
};
ResourceResponse CreateTestResourceResponse() {
@@ -48,8 +61,11 @@ ResourceResponse CreateTestResourceResponse() {
}
void CreateTestResourceAndSetCachedMetadata(const ResourceResponse& response) {
- const char kTestData[] = "test data";
- MockResource* resource = MockResource::Create(response.Url());
+ const uint8_t kTestData[] = {1, 2, 3, 4, 5};
+ ResourceRequest request(response.CurrentRequestUrl());
+ request.SetRequestorOrigin(
+ SecurityOrigin::Create(response.CurrentRequestUrl()));
+ MockResource* resource = MockResource::Create(request);
resource->SetResponse(response);
resource->SendCachedMetadata(kTestData, sizeof(kTestData));
return;
@@ -62,16 +78,68 @@ TEST(ResourceTest, SetCachedMetadata_SendsMetadataToPlatform) {
ResourceResponse response(CreateTestResourceResponse());
CreateTestResourceAndSetCachedMetadata(response);
EXPECT_EQ(1u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(
+ ResourceTest,
+ SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(new Response(...))
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+
+ CreateTestResourceAndSetCachedMetadata(response);
+ EXPECT_EQ(0u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(
+ ResourceTest,
+ SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(fetch(evt.request.url));
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetURLListViaServiceWorker(
+ Vector<KURL>(1, response.CurrentRequestUrl()));
+
+ CreateTestResourceAndSetCachedMetadata(response);
+ EXPECT_EQ(1u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
}
TEST(
ResourceTest,
- SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorker) {
+ SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse) {
ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(fetch(some_different_url))
ResourceResponse response(CreateTestResourceResponse());
response.SetWasFetchedViaServiceWorker(true);
+ response.SetURLListViaServiceWorker(Vector<KURL>(
+ 1, url_test_helpers::ToKURL("https://example.com/different/url")));
+
+ CreateTestResourceAndSetCachedMetadata(response);
+ EXPECT_EQ(0u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(
+ ResourceTest,
+ SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(cache.match(some_url));
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetCacheStorageCacheName("dummy");
+
CreateTestResourceAndSetCachedMetadata(response);
EXPECT_EQ(0u, mock->CachedURLs().size());
+ EXPECT_EQ(1u, mock->CacheStorageCachedURLs().size());
}
TEST(ResourceTest, RevalidateWithFragment) {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
index a01ad9317e1..6916a2542f5 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
@@ -5,14 +5,17 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
#include <memory>
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
void ResourceTimingInfo::AddRedirect(const ResourceResponse& redirect_response,
- bool cross_origin) {
+ const KURL& new_url) {
redirect_chain_.push_back(redirect_response);
if (has_cross_origin_redirect_)
return;
+ bool cross_origin = !SecurityOrigin::AreSameSchemeHostPort(
+ redirect_response.CurrentRequestUrl(), new_url);
if (cross_origin) {
has_cross_origin_redirect_ = true;
transfer_size_ = 0;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
index eba60765dc0..ce12f13477e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
@@ -78,7 +78,7 @@ class PLATFORM_EXPORT ResourceTimingInfo
const ResourceResponse& FinalResponse() const { return final_response_; }
void AddRedirect(const ResourceResponse& redirect_response,
- bool cross_origin);
+ const KURL& new_url);
const Vector<ResourceResponse>& RedirectChain() const {
return redirect_chain_;
}
@@ -88,12 +88,6 @@ class PLATFORM_EXPORT ResourceTimingInfo
}
long long TransferSize() const { return transfer_size_; }
- void ClearLoadTimings() {
- final_response_.SetResourceLoadTiming(nullptr);
- for (ResourceResponse& redirect : redirect_chain_)
- redirect.SetResourceLoadTiming(nullptr);
- }
-
// The timestamps in PerformanceResourceTiming are measured relative from the
// time origin. In most cases these timestamps must be positive value, so we
// use 0 for invalid negative values. But the timestamps for Service Worker
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.cc
index db7ad35c8f5..d160b14ad1c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.cc
@@ -20,7 +20,7 @@ void ScriptCachedMetadataHandler::Trace(blink::Visitor* visitor) {
void ScriptCachedMetadataHandler::SetCachedMetadata(
uint32_t data_type_id,
- const char* data,
+ const uint8_t* data,
size_t size,
CachedMetadataHandler::CacheType cache_type) {
// Currently, only one type of cached metadata per resource is supported. If
@@ -46,8 +46,9 @@ scoped_refptr<CachedMetadata> ScriptCachedMetadataHandler::GetCachedMetadata(
return cached_metadata_;
}
-void ScriptCachedMetadataHandler::SetSerializedCachedMetadata(const char* data,
- size_t size) {
+void ScriptCachedMetadataHandler::SetSerializedCachedMetadata(
+ const uint8_t* data,
+ size_t size) {
// We only expect to receive cached metadata from the platform once. If this
// triggers, it indicates an efficiency problem which is most likely
// unexpected in code designed to improve performance.
@@ -65,7 +66,7 @@ bool ScriptCachedMetadataHandler::IsServedFromCacheStorage() const {
void ScriptCachedMetadataHandler::SendToPlatform() {
if (cached_metadata_) {
- const Vector<char>& serialized_data = cached_metadata_->SerializedData();
+ const Vector<uint8_t>& serialized_data = cached_metadata_->SerializedData();
sender_->Send(serialized_data.data(), serialized_data.size());
} else {
sender_->Send(nullptr, 0);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h b/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h
index a30fb19797d..5fd43aa7d95 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h
@@ -34,7 +34,7 @@ class PLATFORM_EXPORT ScriptCachedMetadataHandler final
std::unique_ptr<CachedMetadataSender>);
~ScriptCachedMetadataHandler() override = default;
void Trace(blink::Visitor*) override;
- void SetCachedMetadata(uint32_t, const char*, size_t, CacheType) override;
+ void SetCachedMetadata(uint32_t, const uint8_t*, size_t, CacheType) override;
void ClearCachedMetadata(CacheType) override;
scoped_refptr<CachedMetadata> GetCachedMetadata(uint32_t) const override;
@@ -49,7 +49,7 @@ class PLATFORM_EXPORT ScriptCachedMetadataHandler final
bool IsServedFromCacheStorage() const override;
// Sets the serialized metadata retrieved from the platform's cache.
- void SetSerializedCachedMetadata(const char*, size_t);
+ void SetSerializedCachedMetadata(const uint8_t*, size_t);
private:
void SendToPlatform();
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
index 9d0fbf5abc2..7391ff23840 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
@@ -49,6 +49,11 @@ FetchParameters ScriptFetchOptions::CreateFetchParameters(
// its parser metadata to options's parser metadata, [spec text]
params.SetParserDisposition(ParserState());
+ // Priority Hints is currently non-standard, but we can assume the following
+ // (see https://crbug.com/821464):
+ // its importance to options's importance, [spec text]
+ params.MutableResourceRequest().SetFetchImportanceMode(importance_);
+
// its referrer policy to options's referrer policy. [spec text]
params.MutableResourceRequest().SetReferrerPolicy(referrer_policy_);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h
index 4cb4632a89c..4a24a92d155 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h
@@ -35,20 +35,24 @@ class PLATFORM_EXPORT ScriptFetchOptions final {
ScriptFetchOptions()
: parser_state_(ParserDisposition::kNotParserInserted),
credentials_mode_(network::mojom::FetchCredentialsMode::kOmit),
- referrer_policy_(network::mojom::ReferrerPolicy::kDefault) {}
+ referrer_policy_(network::mojom::ReferrerPolicy::kDefault),
+ importance_(mojom::FetchImportanceMode::kImportanceAuto) {}
ScriptFetchOptions(const String& nonce,
const IntegrityMetadataSet& integrity_metadata,
const String& integrity_attribute,
ParserDisposition parser_state,
network::mojom::FetchCredentialsMode credentials_mode,
- network::mojom::ReferrerPolicy referrer_policy)
+ network::mojom::ReferrerPolicy referrer_policy,
+ mojom::FetchImportanceMode importance =
+ mojom::FetchImportanceMode::kImportanceAuto)
: nonce_(nonce),
integrity_metadata_(integrity_metadata),
integrity_attribute_(integrity_attribute),
parser_state_(parser_state),
credentials_mode_(credentials_mode),
- referrer_policy_(referrer_policy) {}
+ referrer_policy_(referrer_policy),
+ importance_(importance) {}
~ScriptFetchOptions() = default;
const String& Nonce() const { return nonce_; }
@@ -65,6 +69,7 @@ class PLATFORM_EXPORT ScriptFetchOptions final {
network::mojom::ReferrerPolicy GetReferrerPolicy() const {
return referrer_policy_;
}
+ mojom::FetchImportanceMode Importance() const { return importance_; }
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-classic-script
// Steps 1 and 3.
@@ -90,6 +95,10 @@ class PLATFORM_EXPORT ScriptFetchOptions final {
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-fetch-options-referrer-policy
const network::mojom::ReferrerPolicy referrer_policy_;
+
+ // Priority Hints and a request's "importance" mode are currently
+ // non-standard. See https://crbug.com/821464.
+ const mojom::FetchImportanceMode importance_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.cc
index d1d3c7bbb86..2be718f6207 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.cc
@@ -27,7 +27,7 @@ class SourceKeyedCachedMetadataHandler::SingleKeyHandler final
: parent_(parent), key_(key) {}
void SetCachedMetadata(uint32_t data_type_id,
- const char* data,
+ const uint8_t* data,
size_t size,
CacheType cache_type) override {
DCHECK(!parent_->cached_metadata_map_.Contains(key_));
@@ -120,7 +120,7 @@ namespace {
// should inline and optimize to the same code as *reinterpret_cast<T>(data),
// but without the risk of undefined behaviour.
template <typename T>
-T ReadVal(const char* data) {
+T ReadVal(const uint8_t* data) {
static_assert(base::is_trivially_copyable<T>::value,
"ReadVal requires the value type to be copyable");
T ret;
@@ -130,7 +130,7 @@ T ReadVal(const char* data) {
} // namespace
void SourceKeyedCachedMetadataHandler::SetSerializedCachedMetadata(
- const char* data,
+ const uint8_t* data,
size_t size) {
// We only expect to receive cached metadata from the platform once. If this
// triggers, it indicates an efficiency problem which is most likely
@@ -199,16 +199,16 @@ void SourceKeyedCachedMetadataHandler::SendToPlatform() {
if (cached_metadata_map_.IsEmpty()) {
sender_->Send(nullptr, 0);
} else {
- Vector<char> serialized_data;
+ Vector<uint8_t> serialized_data;
uint32_t marker = CachedMetadataHandler::kSourceKeyedMap;
- serialized_data.Append(reinterpret_cast<char*>(&marker), sizeof(marker));
+ serialized_data.Append(reinterpret_cast<uint8_t*>(&marker), sizeof(marker));
int num_entries = cached_metadata_map_.size();
- serialized_data.Append(reinterpret_cast<char*>(&num_entries),
+ serialized_data.Append(reinterpret_cast<uint8_t*>(&num_entries),
sizeof(num_entries));
for (const auto& metadata : cached_metadata_map_) {
serialized_data.Append(metadata.key.data(), kKeySize);
size_t entry_size = metadata.value->SerializedData().size();
- serialized_data.Append(reinterpret_cast<const char*>(&entry_size),
+ serialized_data.Append(reinterpret_cast<const uint8_t*>(&entry_size),
sizeof(entry_size));
serialized_data.AppendVector(metadata.value->SerializedData());
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h b/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h
index b9b7b83a773..44df319cbac 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h
@@ -38,7 +38,7 @@ class PLATFORM_EXPORT SourceKeyedCachedMetadataHandler final
return sender_->IsServedFromCacheStorage();
}
- void SetSerializedCachedMetadata(const char*, size_t);
+ void SetSerializedCachedMetadata(const uint8_t*, size_t);
private:
// Keys are SHA-256, which are 256/8 = 32 bytes.
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc
index 61a489c16f3..c2f47824aca 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler_test.cc
@@ -69,7 +69,7 @@ class MockDigestWebCrypto : public WebCrypto {
struct CacheMetadataEntry {
CacheMetadataEntry(const WebURL& url,
base::Time response_time,
- const char* data,
+ const uint8_t* data,
wtf_size_t data_size)
: url(url), response_time(response_time) {
this->data.Append(data, data_size);
@@ -77,7 +77,7 @@ struct CacheMetadataEntry {
WebURL url;
base::Time response_time;
- Vector<char> data;
+ Vector<uint8_t> data;
};
// Mock Platform implementation that provides basic crypto and caching.
@@ -92,7 +92,7 @@ class SourceKeyedCachedMetadataHandlerMockPlatform final
void CacheMetadata(blink::mojom::CodeCacheType cache_type,
const WebURL& url,
base::Time response_time,
- const char* data,
+ const uint8_t* data,
size_t data_size) override {
cache_entries_.emplace_back(url, response_time, data,
SafeCast<wtf_size_t>(data_size));
@@ -127,7 +127,7 @@ class MockCachedMetadataSender final : public CachedMetadataSender {
public:
MockCachedMetadataSender(KURL response_url) : response_url_(response_url) {}
- void Send(const char* data, size_t size) override {
+ void Send(const uint8_t* data, size_t size) override {
Platform::Current()->CacheMetadata(blink::mojom::CodeCacheType::kJavascript,
response_url_, response_time_, data,
size);
@@ -144,7 +144,7 @@ template <size_t N>
::testing::AssertionResult CachedMetadataFailure(
const char* failure_msg,
const char* actual_expression,
- const std::array<char, N>& expected,
+ const std::array<uint8_t, N>& expected,
const scoped_refptr<CachedMetadata>& actual) {
::testing::Message msg;
msg << failure_msg << " for " << actual_expression;
@@ -174,7 +174,7 @@ template <size_t N>
::testing::AssertionResult CachedMetadataEqual(
const char* expected_expression,
const char* actual_expression,
- const std::array<char, N>& expected,
+ const std::array<uint8_t, N>& expected,
const scoped_refptr<CachedMetadata>& actual) {
if (!actual) {
return CachedMetadataFailure("Expected non-null data", actual_expression,
@@ -184,7 +184,7 @@ template <size_t N>
return CachedMetadataFailure("Wrong size", actual_expression, expected,
actual);
}
- const char* actual_data = actual->Data();
+ const uint8_t* actual_data = actual->Data();
for (size_t i = 0; i < N; ++i) {
if (actual_data[i] != expected[i]) {
return CachedMetadataFailure("Wrong data", actual_expression, expected,
@@ -242,7 +242,7 @@ TEST(SourceKeyedCachedMetadataHandlerTest,
SingleCachedMetadataHandler* source2_handler =
handler->HandlerForSource(source2);
- std::array<char, 3> data1 = {1, 2, 3};
+ std::array<uint8_t, 3> data1 = {1, 2, 3};
source1_handler->SetCachedMetadata(0xbeef, data1.data(), data1.size());
EXPECT_NE(nullptr, source1_handler);
@@ -269,10 +269,10 @@ TEST(SourceKeyedCachedMetadataHandlerTest, HandlerForSource_BothHandlersSet) {
SingleCachedMetadataHandler* source2_handler =
handler->HandlerForSource(source2);
- std::array<char, 3> data1 = {1, 2, 3};
+ std::array<uint8_t, 3> data1 = {1, 2, 3};
source1_handler->SetCachedMetadata(0xbeef, data1.data(), data1.size());
- std::array<char, 4> data2 = {3, 4, 5, 6};
+ std::array<uint8_t, 4> data2 = {3, 4, 5, 6};
source2_handler->SetCachedMetadata(0x5eed, data2.data(), data2.size());
EXPECT_NE(nullptr, source1_handler);
@@ -318,10 +318,10 @@ TEST(SourceKeyedCachedMetadataHandlerTest, Serialize_EachSetDoesSend) {
SingleCachedMetadataHandler* source2_handler =
handler->HandlerForSource(source2);
- std::array<char, 3> data1 = {1, 2, 3};
+ std::array<uint8_t, 3> data1 = {1, 2, 3};
source1_handler->SetCachedMetadata(0xbeef, data1.data(), data1.size());
- std::array<char, 4> data2 = {3, 4, 5, 6};
+ std::array<uint8_t, 4> data2 = {3, 4, 5, 6};
source2_handler->SetCachedMetadata(0x5eed, data2.data(), data2.size());
// Load from platform
@@ -348,11 +348,11 @@ TEST(SourceKeyedCachedMetadataHandlerTest, Serialize_SetWithNoSendDoesNotSend) {
SingleCachedMetadataHandler* source2_handler =
handler->HandlerForSource(source2);
- std::array<char, 3> data1 = {1, 2, 3};
+ std::array<uint8_t, 3> data1 = {1, 2, 3};
source1_handler->SetCachedMetadata(0xbeef, data1.data(), data1.size(),
CachedMetadataHandler::kCacheLocally);
- std::array<char, 4> data2 = {3, 4, 5, 6};
+ std::array<uint8_t, 4> data2 = {3, 4, 5, 6};
source2_handler->SetCachedMetadata(0x5eed, data2.data(), data2.size());
// Load from platform
@@ -416,8 +416,8 @@ TEST(SourceKeyedCachedMetadataHandlerTest,
KURL url("http://SourceKeyedCachedMetadataHandlerTest.com");
WTF::String source1("source1");
WTF::String source2("source2");
- std::array<char, 3> data1 = {1, 2, 3};
- std::array<char, 4> data2 = {3, 4, 5, 6};
+ std::array<uint8_t, 3> data1 = {1, 2, 3};
+ std::array<uint8_t, 4> data2 = {3, 4, 5, 6};
{
SourceKeyedCachedMetadataHandler* handler =
MakeGarbageCollected<SourceKeyedCachedMetadataHandler>(
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h b/chromium/third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h
index b38a63a6cf9..95bbab104c9 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h
@@ -22,6 +22,13 @@ class PLATFORM_EXPORT TextResourceDecoderOptions final {
kMaxContentType = kCSSContent
}; // PlainText only checks for BOM.
+ // Implements https://encoding.spec.whatwg.org/#decode
+ // when ContentType is |kPlainTextContent|.
+ // The "fallback encoding" is
+ // - If TextResourceDecoder::SetEncoding(|encoding|) is called and
+ // |encoding.IsValid()| is true, then |encoding|.
+ // - Else if |default_encoding.IsValid()| is true, then |default_encoding|.
+ // - Else, Latin-1.
explicit TextResourceDecoderOptions(
ContentType,
const WTF::TextEncoding& default_encoding = WTF::TextEncoding());
diff --git a/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.cc b/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.cc
new file mode 100644
index 00000000000..34b8172a5aa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.cc
@@ -0,0 +1,110 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/ftp_directory_listing.h"
+
+#include <string>
+#include <vector>
+
+#include "base/i18n/encoding_detection.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "net/base/directory_listing.h"
+#include "net/base/escape.h"
+#include "net/base/net_errors.h"
+#include "net/ftp/ftp_directory_listing_parser.h"
+#include "net/net_buildflags.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "url/gurl.h"
+
+namespace blink {
+
+namespace {
+
+base::string16 ConvertPathToUTF16(const std::string& path) {
+ // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII,
+ // but many old FTP servers use legacy encodings. Try UTF-8 first.
+ if (base::IsStringUTF8(path))
+ return base::UTF8ToUTF16(path);
+
+ // Try detecting the encoding. The sample is rather small though, so it may
+ // fail.
+ std::string encoding;
+ if (base::DetectEncoding(path, &encoding) && encoding != "US-ASCII") {
+ base::string16 path_utf16;
+ if (base::CodepageToUTF16(path, encoding.c_str(),
+ base::OnStringConversionError::SUBSTITUTE,
+ &path_utf16)) {
+ return path_utf16;
+ }
+ }
+
+ // Use system native encoding as the last resort.
+ return base::WideToUTF16(base::SysNativeMBToWide(path));
+}
+
+} // namespace
+
+scoped_refptr<SharedBuffer> GenerateFtpDirectoryListingHtml(
+ const KURL& url,
+ const SharedBuffer* input) {
+ const GURL gurl = url;
+ scoped_refptr<SharedBuffer> output = SharedBuffer::Create();
+ net::UnescapeRule::Type unescape_rules =
+ net::UnescapeRule::SPACES |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS;
+ std::string unescaped_path =
+ net::UnescapeURLComponent(gurl.path(), unescape_rules);
+ const std::string header =
+ net::GetDirectoryListingHeader(ConvertPathToUTF16(unescaped_path));
+ output->Append(header.c_str(), header.size());
+
+ // If this isn't top level directory (i.e. the path isn't "/",)
+ // add a link to the parent directory.
+ if (gurl.path().length() > 1) {
+ const std::string link = net::GetParentDirectoryLink();
+ output->Append(link.c_str(), link.size());
+ }
+
+ std::string flatten;
+ for (const auto& span : *input) {
+ flatten.append(span.data(), span.size());
+ }
+
+ std::vector<net::FtpDirectoryListingEntry> entries;
+ int rv = net::ERR_NOT_IMPLEMENTED;
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ rv = net::ParseFtpDirectoryListing(flatten, base::Time::Now(), &entries);
+#endif
+ if (rv != net::OK) {
+ const std::string script = "<script>onListingParsingError();</script>\n";
+ output->Append(script.c_str(), script.size());
+ return output;
+ }
+ for (const net::FtpDirectoryListingEntry& entry : entries) {
+ // Skip the current and parent directory entries in the listing.
+ // net::GetParentDirectoryLink() takes care of them.
+ if (base::EqualsASCII(entry.name, ".") ||
+ base::EqualsASCII(entry.name, ".."))
+ continue;
+
+ bool is_directory =
+ (entry.type == net::FtpDirectoryListingEntry::DIRECTORY);
+ int64_t size =
+ entry.type == net::FtpDirectoryListingEntry::FILE ? entry.size : 0;
+ std::string entry_string = net::GetDirectoryListingEntry(
+ entry.name, entry.raw_name, is_directory, size, entry.last_modified);
+ output->Append(entry_string.c_str(), entry_string.size());
+ }
+
+ return output;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.h b/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.h
new file mode 100644
index 00000000000..78473c81acb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing.h
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FTP_DIRECTORY_LISTING_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FTP_DIRECTORY_LISTING_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+class KURL;
+class SharedBuffer;
+
+// Translates |input|, an FTP LISTING result, to an HTML and returns it. When
+// an error happens that is written in the result HTML.
+PLATFORM_EXPORT scoped_refptr<SharedBuffer> GenerateFtpDirectoryListingHtml(
+ const KURL& url,
+ const SharedBuffer* input);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FTP_DIRECTORY_LISTING_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing_test.cc b/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing_test.cc
new file mode 100644
index 00000000000..c8404797763
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/ftp_directory_listing_test.cc
@@ -0,0 +1,111 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/ftp_directory_listing.h"
+
+#include <string>
+
+#include "base/test/icu_test_util.h"
+#include "net/net_buildflags.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace blink {
+namespace {
+
+class ScopedRestoreDefaultTimezone {
+ public:
+ explicit ScopedRestoreDefaultTimezone(const char* zoneid) {
+ original_zone_.reset(icu::TimeZone::createDefault());
+ icu::TimeZone::adoptDefault(icu::TimeZone::createTimeZone(zoneid));
+ }
+ ~ScopedRestoreDefaultTimezone() {
+ icu::TimeZone::adoptDefault(original_zone_.release());
+ }
+
+ ScopedRestoreDefaultTimezone(const ScopedRestoreDefaultTimezone&) = delete;
+ ScopedRestoreDefaultTimezone& operator=(const ScopedRestoreDefaultTimezone&) =
+ delete;
+
+ private:
+ std::unique_ptr<icu::TimeZone> original_zone_;
+};
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+TEST(FtpDirectoryListingTest, Top) {
+ base::test::ScopedRestoreICUDefaultLocale locale("en_US");
+ ScopedRestoreDefaultTimezone timezone("Asia/Tokyo");
+
+ const KURL url("ftp://ftp.example.com/");
+
+ const std::string input = "drwxr-xr-x 1 ftp ftp 17 Feb 15 2016 top\r\n";
+ // Referring to code in net/base/dir_header.html, but the code itself
+ // is not included in the expectation due to unittest configuration.
+ std::string expected = R"JS(<script>start("/");</script>
+<script>addRow("top","top",1,0,"0 B",1455494400,"2/15/16, 9:00:00 AM");</script>
+)JS";
+ auto input_buffer = SharedBuffer::Create();
+ input_buffer->Append(input.data(), input.size());
+
+ auto output = GenerateFtpDirectoryListingHtml(url, input_buffer.get());
+ std::string flatten_output;
+ for (const auto span : *output) {
+ flatten_output.append(span.data(), span.size());
+ }
+
+ EXPECT_EQ(expected, flatten_output);
+}
+#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+TEST(FtpDirectoryListingTest, NonTop) {
+ base::test::ScopedRestoreICUDefaultLocale locale("en_US");
+ ScopedRestoreDefaultTimezone timezone("Asia/Tokyo");
+ const KURL url("ftp://ftp.example.com/foo/");
+
+ const std::string input = "drwxr-xr-x 1 ftp ftp 17 Feb 15 2016 dir\r\n";
+ // Referring to code in net/base/dir_header.html, but the code itself
+ // is not included in the expectation due to unittest configuration.
+ std::string expected = R"JS(<script>start("/foo/");</script>
+<script>onHasParentDirectory();</script>
+<script>addRow("dir","dir",1,0,"0 B",1455494400,"2/15/16, 9:00:00 AM");</script>
+)JS";
+
+ auto input_buffer = SharedBuffer::Create();
+ input_buffer->Append(input.data(), input.size());
+
+ auto output = GenerateFtpDirectoryListingHtml(url, input_buffer.get());
+ std::string flatten_output;
+ for (const auto span : *output) {
+ flatten_output.append(span.data(), span.size());
+ }
+
+ EXPECT_EQ(expected, flatten_output);
+}
+#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+
+TEST(FtpDirectoryListingTest, Fail) {
+ base::test::ScopedRestoreICUDefaultLocale locale("en_US");
+ ScopedRestoreDefaultTimezone timezone("Asia/Tokyo");
+ const KURL url("ftp://ftp.example.com/");
+ auto input = SharedBuffer::Create();
+ input->Append("bogus", 5u);
+ std::string expected = R"JS(<script>start("/");</script>
+<script>onListingParsingError();</script>
+)JS";
+ auto output = GenerateFtpDirectoryListingHtml(url, input.get());
+ std::string flatten_output;
+ for (const auto span : *output) {
+ flatten_output.append(span.data(), span.size());
+ }
+
+ EXPECT_EQ(expected, flatten_output);
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/link_header.h b/chromium/third_party/blink/renderer/platform/loader/link_header.h
index 1505f38c1be..f7175603d55 100644
--- a/chromium/third_party/blink/renderer/platform/loader/link_header.h
+++ b/chromium/third_party/blink/renderer/platform/loader/link_header.h
@@ -26,6 +26,10 @@ class LinkHeader {
const String& ImageSrcset() const { return image_srcset_; }
const String& ImageSizes() const { return image_sizes_; }
bool Valid() const { return is_valid_; }
+ bool IsViewportDependent() const {
+ return !Media().IsEmpty() || !ImageSrcset().IsEmpty() ||
+ !ImageSizes().IsEmpty();
+ }
enum LinkParameterName {
kLinkParameterRel,
diff --git a/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc b/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc
new file mode 100644
index 00000000000..8949f62e45d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.cc
@@ -0,0 +1,103 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h"
+
+#include "third_party/blink/renderer/platform/wtf/time.h"
+
+namespace blink {
+
+StaticDataNavigationBodyLoader::StaticDataNavigationBodyLoader()
+ : weak_factory_(this) {}
+
+StaticDataNavigationBodyLoader::~StaticDataNavigationBodyLoader() = default;
+
+void StaticDataNavigationBodyLoader::Write(const char* data, size_t size) {
+ DCHECK(!received_all_data_);
+ if (!data_)
+ data_ = SharedBuffer::Create(data, size);
+ else
+ data_->Append(data, size);
+ Continue();
+}
+
+void StaticDataNavigationBodyLoader::Write(const SharedBuffer& data) {
+ DCHECK(!received_all_data_);
+ if (!data_)
+ data_ = SharedBuffer::Create();
+ data_->Append(data);
+ Continue();
+}
+
+void StaticDataNavigationBodyLoader::Finish() {
+ DCHECK(!received_all_data_);
+ received_all_data_ = true;
+ Continue();
+}
+
+void StaticDataNavigationBodyLoader::SetDefersLoading(bool defers) {
+ defers_loading_ = defers;
+ Continue();
+}
+
+void StaticDataNavigationBodyLoader::StartLoadingBody(
+ WebNavigationBodyLoader::Client* client,
+ bool use_isolated_code_cache) {
+ DCHECK(!is_in_continue_);
+ client_ = client;
+ Continue();
+}
+
+void StaticDataNavigationBodyLoader::Continue() {
+ if (defers_loading_ || !client_ || is_in_continue_)
+ return;
+
+ // We don't want reentrancy in this method -
+ // protect with a boolean. Cannot use AutoReset
+ // because |this| can be deleted before reset.
+ is_in_continue_ = true;
+ base::WeakPtr<StaticDataNavigationBodyLoader> weak_self =
+ weak_factory_.GetWeakPtr();
+
+ if (!sent_all_data_) {
+ while (data_ && data_->size()) {
+ total_encoded_data_length_ += data_->size();
+
+ // Cleanup |data_| before dispatching, so that
+ // we can reentrantly append some data again.
+ scoped_refptr<SharedBuffer> data = std::move(data_);
+
+ for (const auto& span : *data) {
+ client_->BodyDataReceived(span);
+ // |this| can be destroyed from BodyDataReceived.
+ if (!weak_self)
+ return;
+ }
+
+ if (defers_loading_) {
+ is_in_continue_ = false;
+ return;
+ }
+ }
+ if (received_all_data_)
+ sent_all_data_ = true;
+ }
+
+ if (sent_all_data_) {
+ // Clear |client_| to avoid any extra notifications from reentrancy.
+ WebNavigationBodyLoader::Client* client = client_;
+ client_ = nullptr;
+ client->BodyLoadingFinished(CurrentTimeTicks(), total_encoded_data_length_,
+ total_encoded_data_length_,
+ total_encoded_data_length_, false,
+ base::nullopt);
+ // |this| can be destroyed from BodyLoadingFinished.
+ if (!weak_self)
+ return;
+ }
+
+ is_in_continue_ = false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h b/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h
new file mode 100644
index 00000000000..3e17f71c78e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h
@@ -0,0 +1,48 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_STATIC_DATA_NAVIGATION_BODY_LOADER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_STATIC_DATA_NAVIGATION_BODY_LOADER_H_
+
+#include "base/containers/span.h"
+#include "base/memory/weak_ptr.h"
+#include "third_party/blink/public/platform/web_navigation_body_loader.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
+
+namespace blink {
+
+// This class allows to write navigation body from outside,
+// and adheres to the contract of WebNavigationBodyLoader.
+// Used for tests and static (as in "not loaded over network") response body.
+class PLATFORM_EXPORT StaticDataNavigationBodyLoader
+ : public WebNavigationBodyLoader {
+ public:
+ StaticDataNavigationBodyLoader();
+ ~StaticDataNavigationBodyLoader() override;
+
+ void Write(const char* data, size_t size);
+ void Write(const SharedBuffer&);
+ void Finish();
+
+ void SetDefersLoading(bool defers) override;
+ void StartLoadingBody(WebNavigationBodyLoader::Client*,
+ bool use_isolated_code_cache) override;
+
+ private:
+ void Continue();
+
+ scoped_refptr<SharedBuffer> data_;
+ WebNavigationBodyLoader::Client* client_ = nullptr;
+ bool defers_loading_ = false;
+ bool sent_all_data_ = false;
+ bool received_all_data_ = false;
+ bool is_in_continue_ = false;
+ int64_t total_encoded_data_length_ = 0;
+ base::WeakPtrFactory<StaticDataNavigationBodyLoader> weak_factory_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_STATIC_DATA_NAVIGATION_BODY_LOADER_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader_test.cc b/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader_test.cc
new file mode 100644
index 00000000000..52a1c521705
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/static_data_navigation_body_loader_test.cc
@@ -0,0 +1,177 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class StaticDataNavigationBodyLoaderTest
+ : public ::testing::Test,
+ public WebNavigationBodyLoader::Client {
+ protected:
+ void SetUp() override {
+ loader_ = std::make_unique<StaticDataNavigationBodyLoader>();
+ }
+
+ void Write(const String& buffer) {
+ CString cstring = buffer.Utf8();
+ loader_->Write(cstring.data(), cstring.length());
+ }
+
+ void BodyCodeCacheReceived(base::span<const uint8_t>) override {}
+
+ void BodyDataReceived(base::span<const char> data) override {
+ ASSERT_TRUE(expecting_data_received_);
+ expecting_data_received_ = false;
+ data_received_ =
+ data_received_ + String::FromUTF8(data.data(), data.size());
+ TakeActions();
+ }
+
+ void BodyLoadingFinished(
+ base::TimeTicks completion_time,
+ int64_t total_encoded_data_length,
+ int64_t total_encoded_body_length,
+ int64_t total_decoded_body_length,
+ bool should_report_corb_blocking,
+ const base::Optional<blink::WebURLError>& error) override {
+ ASSERT_TRUE(expecting_finished_);
+ expecting_finished_ = false;
+ ASSERT_TRUE(!did_finish_);
+ did_finish_ = true;
+ TakeActions();
+ }
+
+ void TakeActions() {
+ if (set_defers_loading_) {
+ set_defers_loading_ = false;
+ loader_->SetDefersLoading(true);
+ }
+ if (!buffer_to_write_.IsEmpty()) {
+ String buffer = buffer_to_write_;
+ buffer_to_write_ = String();
+ expecting_data_received_ = true;
+ Write(buffer);
+ }
+ if (destroy_loader_) {
+ destroy_loader_ = false;
+ loader_.reset();
+ }
+ }
+
+ String TakeDataReceived() {
+ String data = data_received_;
+ data_received_ = g_empty_string;
+ return data;
+ }
+
+ std::unique_ptr<StaticDataNavigationBodyLoader> loader_;
+ bool expecting_data_received_ = false;
+ bool expecting_finished_ = false;
+ bool did_finish_ = false;
+ String buffer_to_write_;
+ bool set_defers_loading_ = false;
+ bool destroy_loader_ = false;
+ String data_received_;
+};
+
+TEST_F(StaticDataNavigationBodyLoaderTest, DataReceived) {
+ loader_->StartLoadingBody(this, false);
+ expecting_data_received_ = true;
+ Write("hello");
+ EXPECT_EQ("hello", TakeDataReceived());
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, WriteFromDataReceived) {
+ loader_->StartLoadingBody(this, false);
+ expecting_data_received_ = true;
+ buffer_to_write_ = "world";
+ Write("hello");
+ EXPECT_EQ("helloworld", TakeDataReceived());
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest,
+ SetDefersLoadingAndWriteFromDataReceived) {
+ loader_->StartLoadingBody(this, false);
+ expecting_data_received_ = true;
+ set_defers_loading_ = true;
+ buffer_to_write_ = "world";
+ Write("hello");
+ EXPECT_EQ("hello", TakeDataReceived());
+ loader_->SetDefersLoading(false);
+ EXPECT_EQ("world", TakeDataReceived());
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, DestroyFromDataReceived) {
+ loader_->StartLoadingBody(this, false);
+ expecting_data_received_ = true;
+ destroy_loader_ = false;
+ Write("hello");
+ EXPECT_EQ("hello", TakeDataReceived());
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, SetDefersLoadingFromDataReceived) {
+ loader_->StartLoadingBody(this, false);
+ expecting_data_received_ = true;
+ set_defers_loading_ = true;
+ Write("hello");
+ EXPECT_EQ("hello", TakeDataReceived());
+ Write("world");
+ EXPECT_EQ("", TakeDataReceived());
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, WriteThenStart) {
+ Write("hello");
+ expecting_data_received_ = true;
+ loader_->StartLoadingBody(this, false);
+ EXPECT_EQ("hello", TakeDataReceived());
+ expecting_finished_ = true;
+ loader_->Finish();
+ EXPECT_EQ("", TakeDataReceived());
+ EXPECT_TRUE(did_finish_);
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest,
+ SetDefersLoadingFromFinishedDataReceived) {
+ Write("hello");
+ loader_->Finish();
+ expecting_data_received_ = true;
+ set_defers_loading_ = true;
+ loader_->StartLoadingBody(this, false);
+ EXPECT_EQ("hello", TakeDataReceived());
+ expecting_finished_ = true;
+ loader_->SetDefersLoading(false);
+ EXPECT_EQ("", TakeDataReceived());
+ EXPECT_TRUE(did_finish_);
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, StartDeferred) {
+ loader_->SetDefersLoading(true);
+ loader_->StartLoadingBody(this, false);
+ Write("hello");
+ expecting_data_received_ = true;
+ loader_->SetDefersLoading(false);
+ EXPECT_EQ("hello", TakeDataReceived());
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, DestroyFromFinished) {
+ loader_->StartLoadingBody(this, false);
+ expecting_finished_ = true;
+ destroy_loader_ = true;
+ loader_->Finish();
+ EXPECT_TRUE(did_finish_);
+}
+
+TEST_F(StaticDataNavigationBodyLoaderTest, SetDefersLoadingFromFinished) {
+ loader_->StartLoadingBody(this, false);
+ expecting_finished_ = true;
+ set_defers_loading_ = true;
+ loader_->Finish();
+ EXPECT_TRUE(did_finish_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/subresource_integrity.cc b/chromium/third_party/blink/renderer/platform/loader/subresource_integrity.cc
index d92b21df2ca..9cc09e5bf0e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/subresource_integrity.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/subresource_integrity.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
+#include "base/stl_util.h"
#include "third_party/blink/public/platform/web_crypto.h"
#include "third_party/blink/public/platform/web_crypto_algorithm.h"
#include "third_party/blink/renderer/platform/crypto.h"
@@ -321,7 +322,7 @@ SubresourceIntegrity::ParseAttributeAlgorithm(const UChar*& begin,
// The last algorithm prefix is the ed25519 signature algorithm, which should
// only be enabled if kSignatures is requested. We'll implement this by
// adjusting the last_prefix index into the array.
- size_t last_prefix = arraysize(kPrefixes);
+ size_t last_prefix = base::size(kPrefixes);
if (features != IntegrityFeatures::kSignatures)
last_prefix--;
@@ -335,7 +336,7 @@ SubresourceIntegrity::ParseIntegrityHeaderAlgorithm(
IntegrityAlgorithm& algorithm) {
static const AlgorithmPrefixPair kPrefixes[] = {
{"ed25519", IntegrityAlgorithm::kEd25519}};
- return ParseAlgorithmPrefix(begin, end, kPrefixes, arraysize(kPrefixes),
+ return ParseAlgorithmPrefix(begin, end, kPrefixes, base::size(kPrefixes),
algorithm);
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc b/chromium/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc
index ec90823234b..f12067c89d6 100644
--- a/chromium/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
#include "base/memory/scoped_refptr.h"
+#include "base/stl_util.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/crypto.h"
@@ -84,14 +85,10 @@ class SubresourceIntegrityTest : public testing::Test {
public:
SubresourceIntegrityTest()
: sec_url("https://example.test:443"),
- insec_url("http://example.test:80") {}
+ insec_url("http://example.test:80"),
+ context(MakeGarbageCollected<MockFetchContext>()) {}
protected:
- void SetUp() override {
- context =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- }
-
SubresourceIntegrity::IntegrityFeatures Features() const {
return RuntimeEnabledFeatures::SignatureBasedIntegrityEnabledByRuntimeFlag()
? SubresourceIntegrity::IntegrityFeatures::kSignatures
@@ -440,7 +437,7 @@ TEST_F(SubresourceIntegrityTest, Parsing) {
"sha384-XVVXBGoYw6AJOh9J+Z8pBDMVVPfkBpngexkA7JqZu8d5GENND6TEIup/tA1v5GPr "
"sha512-tbUPioKbVBplr0b1ucnWB57SJWt4x9dOE0Vy2mzCXvH3FepqDZ+"
"07yMK81ytlg0MPaIrPAjcHqba5csorDWtKg==",
- valid_sha384_and_sha512, arraysize(valid_sha384_and_sha512));
+ valid_sha384_and_sha512, base::size(valid_sha384_and_sha512));
const IntegrityMetadata valid_sha256_and_sha256[] = {
IntegrityMetadata("BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=",
@@ -449,7 +446,7 @@ TEST_F(SubresourceIntegrityTest, Parsing) {
};
ExpectParseMultipleHashes(
"sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE= sha256-deadbeef",
- valid_sha256_and_sha256, arraysize(valid_sha256_and_sha256));
+ valid_sha256_and_sha256, base::size(valid_sha256_and_sha256));
const IntegrityMetadata valid_sha256_and_invalid_sha256[] = {
IntegrityMetadata("BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=",
@@ -458,7 +455,7 @@ TEST_F(SubresourceIntegrityTest, Parsing) {
ExpectParseMultipleHashes(
"sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE= sha256-!!!!",
valid_sha256_and_invalid_sha256,
- arraysize(valid_sha256_and_invalid_sha256));
+ base::size(valid_sha256_and_invalid_sha256));
const IntegrityMetadata invalid_sha256_and_valid_sha256[] = {
IntegrityMetadata("BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=",
@@ -467,7 +464,7 @@ TEST_F(SubresourceIntegrityTest, Parsing) {
ExpectParseMultipleHashes(
"sha256-!!! sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=",
invalid_sha256_and_valid_sha256,
- arraysize(invalid_sha256_and_valid_sha256));
+ base::size(invalid_sha256_and_valid_sha256));
ExpectParse("sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=?foo=bar",
"BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=",
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.cc b/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.cc
index 0938f6fb4e4..1e4130b6fe1 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.cc
@@ -10,7 +10,6 @@
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
-#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.h"
@@ -27,14 +26,6 @@ FetchTestingPlatformSupport::~FetchTestingPlatformSupport() {
url_loader_mock_factory_->UnregisterAllURLsAndClearMemoryCache();
}
-MockFetchContext* FetchTestingPlatformSupport::Context() {
- if (!context_) {
- context_ =
- MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
- }
- return context_;
-}
-
WebURLLoaderMockFactory*
FetchTestingPlatformSupport::GetURLLoaderMockFactory() {
return url_loader_mock_factory_.get();
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h b/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h
index 10e4c61c532..7b42360a1d8 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h
@@ -11,16 +11,12 @@
namespace blink {
-class MockFetchContext;
-
class FetchTestingPlatformSupport
: public TestingPlatformSupportWithMockScheduler {
public:
FetchTestingPlatformSupport();
~FetchTestingPlatformSupport() override;
- MockFetchContext* Context();
-
// Platform:
WebURLLoaderMockFactory* GetURLLoaderMockFactory() override;
std::unique_ptr<WebURLLoaderFactory> CreateDefaultURLLoaderFactory() override;
@@ -28,7 +24,6 @@ class FetchTestingPlatformSupport
private:
class FetchTestingWebURLLoaderMockFactory;
- Persistent<MockFetchContext> context_;
std::unique_ptr<WebURLLoaderMockFactory> url_loader_mock_factory_;
DISALLOW_COPY_AND_ASSIGN(FetchTestingPlatformSupport);
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h b/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
index 7859d37a2c5..aae54ed29ec 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
@@ -29,51 +29,21 @@ struct ResourceLoaderOptions;
// Mocked FetchContext for testing.
class MockFetchContext : public FetchContext {
public:
- enum LoadPolicy {
- kShouldLoadNewResource,
- kShouldNotLoadNewResource,
- };
- static MockFetchContext* Create(
- LoadPolicy load_policy,
- scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner = nullptr,
- std::unique_ptr<WebURLLoaderFactory> url_loader_factory = nullptr) {
- return MakeGarbageCollected<MockFetchContext>(
- load_policy, std::move(loading_task_runner),
- std::move(url_loader_factory));
- }
-
MockFetchContext(
- LoadPolicy load_policy,
- scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
- std::unique_ptr<WebURLLoaderFactory> url_loader_factory)
- : FetchContext(loading_task_runner
- ? std::move(loading_task_runner)
- : base::MakeRefCounted<scheduler::FakeTaskRunner>()),
- load_policy_(load_policy),
- security_origin_(SecurityOrigin::CreateUniqueOpaque()),
- frame_scheduler_(new MockFrameScheduler(GetLoadingTaskRunner())),
+ scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner = nullptr,
+ std::unique_ptr<WebURLLoaderFactory> url_loader_factory = nullptr)
+ : frame_scheduler_(new MockFrameScheduler(
+ loading_task_runner
+ ? std::move(loading_task_runner)
+ : base::MakeRefCounted<scheduler::FakeTaskRunner>())),
url_loader_factory_(std::move(url_loader_factory)),
- complete_(false),
transfer_size_(-1) {}
~MockFetchContext() override = default;
- void SetLoadComplete(bool complete) { complete_ = complete; }
long long GetTransferSize() const { return transfer_size_; }
- const SecurityOrigin* GetSecurityOrigin() const override {
- return security_origin_.get();
- }
-
- void SetSecurityOrigin(scoped_refptr<const SecurityOrigin> security_origin) {
- security_origin_ = security_origin;
- }
-
- const FetchClientSettingsObject* GetFetchClientSettingsObject()
- const override {
- return MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
- KURL(), security_origin_, network::mojom::ReferrerPolicy::kDefault,
- String(), HttpsState::kNone);
- }
+ void CountUsage(mojom::WebFeature) const override {}
+ void CountDeprecation(mojom::WebFeature) const override {}
// The last ResourceRequest passed to DispatchWillSendRequest.
base::Optional<ResourceRequest> RequestFromWillSendRequest() const {
@@ -109,10 +79,6 @@ class MockFetchContext : public FetchContext {
ResourceRequest::RedirectStatus redirect_status) const override {
return base::nullopt;
}
- bool ShouldLoadNewResource(ResourceType) const override {
- return load_policy_ == kShouldLoadNewResource;
- }
- bool IsLoadComplete() const override { return complete_; }
void AddResourceTiming(
const ResourceTimingInfo& resource_timing_info) override {
transfer_size_ = resource_timing_info.TransferSize();
@@ -127,24 +93,15 @@ class MockFetchContext : public FetchContext {
}
WrappedResourceRequest wrapped(request);
return url_loader_factory_->CreateURLLoader(
- wrapped, CreateResourceLoadingTaskRunnerHandle());
- }
-
- ResourceLoadScheduler::ThrottlingPolicy InitialLoadThrottlingPolicy()
- const override {
- return ResourceLoadScheduler::ThrottlingPolicy::kTight;
+ wrapped,
+ scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
+ GetLoadingTaskRunner()));
}
FrameScheduler* GetFrameScheduler() const override {
return frame_scheduler_.get();
}
- std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
- CreateResourceLoadingTaskRunnerHandle() override {
- return scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
- GetLoadingTaskRunner());
- }
-
private:
class MockFrameScheduler final : public scheduler::FakeFrameScheduler {
public:
@@ -160,11 +117,8 @@ class MockFetchContext : public FetchContext {
scoped_refptr<base::SingleThreadTaskRunner> runner_;
};
- enum LoadPolicy load_policy_;
- scoped_refptr<const SecurityOrigin> security_origin_;
std::unique_ptr<FrameScheduler> frame_scheduler_;
std::unique_ptr<WebURLLoaderFactory> url_loader_factory_;
- bool complete_;
long long transfer_size_;
base::Optional<ResourceRequest> will_send_request_;
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
index 57de25a182e..7648bfa9e1c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
@@ -54,7 +54,8 @@ CachedMetadataHandler* MockResource::CreateCachedMetadataHandler(
return MakeGarbageCollected<MockCacheHandler>(std::move(send_callback));
}
-void MockResource::SetSerializedCachedMetadata(const char* data, size_t size) {
+void MockResource::SetSerializedCachedMetadata(const uint8_t* data,
+ size_t size) {
Resource::SetSerializedCachedMetadata(data, size);
MockCacheHandler* cache_handler =
static_cast<MockCacheHandler*>(Resource::CacheHandler());
@@ -63,7 +64,7 @@ void MockResource::SetSerializedCachedMetadata(const char* data, size_t size) {
}
}
-void MockResource::SendCachedMetadata(const char* data, size_t size) {
+void MockResource::SendCachedMetadata(const uint8_t* data, size_t size) {
MockCacheHandler* cache_handler =
static_cast<MockCacheHandler*>(Resource::CacheHandler());
if (cache_handler) {
@@ -80,7 +81,7 @@ MockCacheHandler::MockCacheHandler(
std::unique_ptr<CachedMetadataSender> send_callback)
: send_callback_(std::move(send_callback)) {}
-void MockCacheHandler::Set(const char* data, size_t size) {
+void MockCacheHandler::Set(const uint8_t* data, size_t size) {
data_.emplace();
data_->Append(data, SafeCast<wtf_size_t>(size));
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h
index 69e307efbe4..c54228b575c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h
@@ -21,7 +21,7 @@ class MockCacheHandler : public CachedMetadataHandler {
public:
MockCacheHandler(std::unique_ptr<CachedMetadataSender> send_callback);
- void Set(const char* data, size_t);
+ void Set(const uint8_t* data, size_t);
void ClearCachedMetadata(CachedMetadataHandler::CacheType) override;
void Send();
@@ -30,7 +30,7 @@ class MockCacheHandler : public CachedMetadataHandler {
private:
std::unique_ptr<CachedMetadataSender> send_callback_;
- base::Optional<Vector<char>> data_;
+ base::Optional<Vector<uint8_t>> data_;
};
// Mocked Resource sub-class for testing. MockResource class can pretend a type
@@ -48,11 +48,11 @@ class MockResource final : public Resource {
CachedMetadataHandler* CreateCachedMetadataHandler(
std::unique_ptr<CachedMetadataSender> send_callback) override;
- void SetSerializedCachedMetadata(const char*, size_t) override;
+ void SetSerializedCachedMetadata(const uint8_t*, size_t) override;
MockCacheHandler* CacheHandler();
- void SendCachedMetadata(const char*, size_t);
+ void SendCachedMetadata(const uint8_t*, size_t);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc b/chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
new file mode 100644
index 00000000000..d01e0cbe4d1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
+
+#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
+#include "third_party/blink/renderer/platform/loader/allowed_by_nosniff.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
+#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+TestResourceFetcherProperties::TestResourceFetcherProperties()
+ : TestResourceFetcherProperties(SecurityOrigin::CreateUniqueOpaque()) {}
+
+TestResourceFetcherProperties::TestResourceFetcherProperties(
+ scoped_refptr<const SecurityOrigin> origin)
+ : TestResourceFetcherProperties(
+ *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
+ KURL(),
+ std::move(origin),
+ network::mojom::ReferrerPolicy::kDefault,
+ String(),
+ HttpsState::kNone,
+ AllowedByNosniff::MimeTypeCheck::kStrict)) {}
+
+TestResourceFetcherProperties::TestResourceFetcherProperties(
+ const FetchClientSettingsObject& fetch_client_settings_object)
+ : fetch_client_settings_object_(fetch_client_settings_object) {}
+
+void TestResourceFetcherProperties::Trace(Visitor* visitor) {
+ visitor->Trace(fetch_client_settings_object_);
+ ResourceFetcherProperties::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h b/chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h
new file mode 100644
index 00000000000..5e6360b6659
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h
@@ -0,0 +1,80 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_TESTING_TEST_RESOURCE_FETCHER_PROPERTIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_TESTING_TEST_RESOURCE_FETCHER_PROPERTIES_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
+
+namespace blink {
+
+class FetchClientSettingsObject;
+class SecurityOrigin;
+
+// TestResourceFetcherProperties is a ResourceFetcherProperties implementation
+// for tests.
+class TestResourceFetcherProperties final : public ResourceFetcherProperties {
+ public:
+ TestResourceFetcherProperties();
+ explicit TestResourceFetcherProperties(scoped_refptr<const SecurityOrigin>);
+ explicit TestResourceFetcherProperties(const FetchClientSettingsObject&);
+ ~TestResourceFetcherProperties() override = default;
+
+ void Trace(Visitor* visitor) override;
+
+ // ResourceFetcherProperties implementation
+ const FetchClientSettingsObject& GetFetchClientSettingsObject()
+ const override {
+ return *fetch_client_settings_object_;
+ }
+ bool IsMainFrame() const override { return is_main_frame_; }
+ ControllerServiceWorkerMode GetControllerServiceWorkerMode() const override {
+ return service_worker_mode_;
+ }
+ int64_t ServiceWorkerId() const override {
+ DCHECK_NE(GetControllerServiceWorkerMode(),
+ ControllerServiceWorkerMode::kNoController);
+ return service_worker_id_;
+ }
+ bool IsPaused() const override { return paused_; }
+ bool IsDetached() const override { return false; }
+ bool IsLoadComplete() const override { return load_complete_; }
+ bool ShouldBlockLoadingMainResource() const override {
+ return should_block_loading_main_resource_;
+ }
+ bool ShouldBlockLoadingSubResource() const override {
+ return should_block_loading_sub_resource_;
+ }
+
+ void SetIsMainFrame(bool value) { is_main_frame_ = value; }
+ void SetControllerServiceWorkerMode(ControllerServiceWorkerMode mode) {
+ service_worker_mode_ = mode;
+ }
+ void SetServiceWorkerId(int64_t id) { service_worker_id_ = id; }
+ void SetIsPaused(bool value) { paused_ = value; }
+ void SetIsLoadComplete(bool value) { load_complete_ = value; }
+ void SetShouldBlockLoadingMainResource(bool value) {
+ should_block_loading_main_resource_ = value;
+ }
+ void SetShouldBlockLoadingSubResource(bool value) {
+ should_block_loading_sub_resource_ = value;
+ }
+
+ private:
+ const Member<const FetchClientSettingsObject> fetch_client_settings_object_;
+ bool is_main_frame_ = false;
+ ControllerServiceWorkerMode service_worker_mode_ =
+ ControllerServiceWorkerMode::kNoController;
+ int64_t service_worker_id_ = 0;
+ bool paused_ = false;
+ bool load_complete_ = false;
+ bool should_block_loading_main_resource_ = false;
+ bool should_block_loading_sub_resource_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_TESTING_TEST_RESOURCE_FETCHER_PROPERTIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.cc b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
index b05352d5815..58335b9f795 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
@@ -65,6 +65,7 @@ MediaStreamComponent::MediaStreamComponent(const String& id,
MediaStreamSource* source)
: source_(source), id_(id), unique_id_(GenerateUniqueId()) {
DCHECK(id_.length());
+ DCHECK(source_);
}
MediaStreamComponent* MediaStreamComponent::Clone() const {
@@ -79,7 +80,7 @@ MediaStreamComponent* MediaStreamComponent::Clone() const {
}
void MediaStreamComponent::Dispose() {
- track_data_.reset();
+ platform_track_.reset();
}
void MediaStreamComponent::AudioSourceProviderImpl::Wrap(
@@ -90,9 +91,9 @@ void MediaStreamComponent::AudioSourceProviderImpl::Wrap(
void MediaStreamComponent::GetSettings(
WebMediaStreamTrack::Settings& settings) {
- DCHECK(track_data_);
+ DCHECK(platform_track_);
source_->GetSettings(settings);
- track_data_->GetSettings(settings);
+ platform_track_->GetSettings(settings);
}
void MediaStreamComponent::SetContentHint(
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.h b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.h
index 8839431c19b..11e9149fe7a 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.h
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_component.h
@@ -33,6 +33,8 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIASTREAM_MEDIA_STREAM_COMPONENT_H_
#include <memory>
+
+#include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h"
#include "third_party/blink/public/platform/web_media_constraints.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/blink/renderer/platform/audio/audio_source_provider.h"
@@ -57,16 +59,6 @@ class PLATFORM_EXPORT MediaStreamComponent final
static int GenerateUniqueId();
public:
- // This class represents whatever data the Web layer uses to represent
- // a track. It needs to be able to answer the getSettings question.
- class TrackData {
- USING_FAST_MALLOC(TrackData);
-
- public:
- virtual void GetSettings(WebMediaStreamTrack::Settings&) = 0;
- virtual ~TrackData() = default;
- };
-
static MediaStreamComponent* Create(MediaStreamSource*);
static MediaStreamComponent* Create(const String& id, MediaStreamSource*);
@@ -103,9 +95,12 @@ class PLATFORM_EXPORT MediaStreamComponent final
source_provider_.Wrap(provider);
}
- TrackData* GetTrackData() const { return track_data_.get(); }
- void SetTrackData(std::unique_ptr<TrackData> track_data) {
- track_data_ = std::move(track_data);
+ WebPlatformMediaStreamTrack* GetPlatformTrack() const {
+ return platform_track_.get();
+ }
+ void SetPlatformTrack(
+ std::unique_ptr<WebPlatformMediaStreamTrack> platform_track) {
+ platform_track_ = std::move(platform_track);
}
void GetSettings(WebMediaStreamTrack::Settings&);
@@ -143,7 +138,7 @@ class PLATFORM_EXPORT MediaStreamComponent final
WebMediaStreamTrack::ContentHintType content_hint_ =
WebMediaStreamTrack::ContentHintType::kNone;
WebMediaConstraints constraints_;
- std::unique_ptr<TrackData> track_data_;
+ std::unique_ptr<WebPlatformMediaStreamTrack> platform_track_;
};
typedef HeapVector<Member<MediaStreamComponent>> MediaStreamComponentVector;
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_source.h b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_source.h
index 6f8acec957d..e48d9947e20 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_source.h
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_source.h
@@ -36,6 +36,7 @@
#include <utility>
#include "base/optional.h"
+#include "third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h"
#include "third_party/blink/public/platform/web_media_constraints.h"
#include "third_party/blink/public/platform/web_media_stream_source.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
@@ -57,13 +58,6 @@ class PLATFORM_EXPORT MediaStreamSource final
virtual void SourceChangedState() = 0;
};
- class ExtraData {
- USING_FAST_MALLOC(ExtraData);
-
- public:
- virtual ~ExtraData() = default;
- };
-
enum StreamType { kTypeAudio, kTypeVideo };
enum ReadyState {
@@ -101,9 +95,12 @@ class PLATFORM_EXPORT MediaStreamSource final
void AddObserver(Observer*);
- ExtraData* GetExtraData() const { return extra_data_.get(); }
- void SetExtraData(std::unique_ptr<ExtraData> extra_data) {
- extra_data_ = std::move(extra_data);
+ WebPlatformMediaStreamSource* GetPlatformSource() const {
+ return platform_source_.get();
+ }
+ void SetPlatformSource(
+ std::unique_ptr<WebPlatformMediaStreamSource> platform_source) {
+ platform_source_ = std::move(platform_source);
}
void SetAudioProcessingProperties(EchoCancellationMode echo_cancellation_mode,
@@ -146,7 +143,7 @@ class PLATFORM_EXPORT MediaStreamSource final
HeapHashSet<WeakMember<Observer>> observers_;
Mutex audio_consumers_lock_;
HashSet<AudioDestinationConsumer*> audio_consumers_;
- std::unique_ptr<ExtraData> extra_data_;
+ std::unique_ptr<WebPlatformMediaStreamSource> platform_source_;
WebMediaConstraints constraints_;
WebMediaStreamSource::Capabilities capabilities_;
base::Optional<EchoCancellationMode> echo_cancellation_mode_;
diff --git a/chromium/third_party/blink/renderer/platform/memory_coordinator.cc b/chromium/third_party/blink/renderer/platform/memory_coordinator.cc
index a65474abb18..73b958a84d1 100644
--- a/chromium/third_party/blink/renderer/platform/memory_coordinator.cc
+++ b/chromium/third_party/blink/renderer/platform/memory_coordinator.cc
@@ -58,7 +58,8 @@ void MemoryCoordinator::SetIsLowEndDeviceForTesting(bool is_low_end_device) {
// static
MemoryCoordinator& MemoryCoordinator::Instance() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(CrossThreadPersistent<MemoryCoordinator>,
- external, (new MemoryCoordinator));
+ external,
+ (MakeGarbageCollected<MemoryCoordinator>()));
return *external.Get();
}
diff --git a/chromium/third_party/blink/renderer/platform/memory_coordinator.h b/chromium/third_party/blink/renderer/platform/memory_coordinator.h
index b652a681620..7ea494e7255 100644
--- a/chromium/third_party/blink/renderer/platform/memory_coordinator.h
+++ b/chromium/third_party/blink/renderer/platform/memory_coordinator.h
@@ -38,7 +38,7 @@ class PLATFORM_EXPORT MemoryCoordinator final
static MemoryCoordinator& Instance();
// Whether the device Blink runs on is a low-end device.
- // Can be overridden in layout tests via internals.
+ // Can be overridden in web tests via internals.
static bool IsLowEndDevice();
// Returns true when available memory is low.
@@ -52,6 +52,8 @@ class PLATFORM_EXPORT MemoryCoordinator final
// the heap size.
static void Initialize();
+ MemoryCoordinator();
+
void RegisterThread(Thread*) LOCKS_EXCLUDED(threads_mutex_);
void UnregisterThread(Thread*) LOCKS_EXCLUDED(threads_mutex_);
@@ -73,8 +75,6 @@ class PLATFORM_EXPORT MemoryCoordinator final
static void SetIsLowEndDeviceForTesting(bool);
- MemoryCoordinator();
-
void ClearMemory();
static void ClearThreadSpecificMemory();
diff --git a/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.cc b/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.cc
index 9e6003dcbdb..21785322aee 100644
--- a/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.cc
@@ -50,8 +50,8 @@ ArchiveResource* ArchiveResource::Create(scoped_refptr<SharedBuffer> data,
const String& content_id,
const AtomicString& mime_type,
const AtomicString& text_encoding) {
- return new ArchiveResource(std::move(data), url, content_id, mime_type,
- text_encoding);
+ return MakeGarbageCollected<ArchiveResource>(std::move(data), url, content_id,
+ mime_type, text_encoding);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.h b/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.h
index 9c012991d36..7dcc5be2f40 100644
--- a/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.h
+++ b/chromium/third_party/blink/renderer/platform/mhtml/archive_resource.h
@@ -46,6 +46,11 @@ class PLATFORM_EXPORT ArchiveResource final
const AtomicString& mime_type,
const AtomicString& text_encoding);
+ ArchiveResource(scoped_refptr<SharedBuffer>,
+ const KURL&,
+ const String& content_id,
+ const AtomicString& mime_type,
+ const AtomicString& text_encoding);
~ArchiveResource();
const KURL& Url() const { return url_; }
@@ -57,12 +62,6 @@ class PLATFORM_EXPORT ArchiveResource final
void Trace(blink::Visitor* visitor) {}
private:
- ArchiveResource(scoped_refptr<SharedBuffer>,
- const KURL&,
- const String& content_id,
- const AtomicString& mime_type,
- const AtomicString& text_encoding);
-
KURL url_;
String content_id_;
scoped_refptr<SharedBuffer> data_;
diff --git a/chromium/third_party/blink/renderer/platform/mojo/blink_typemaps.gni b/chromium/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
index 80784cdc8bd..20c28f52f06 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
+++ b/chromium/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
@@ -15,6 +15,7 @@ typemaps = [
"//third_party/blink/renderer/platform/mojo/big_buffer.typemap",
"//third_party/blink/renderer/platform/mojo/big_string.typemap",
"//third_party/blink/renderer/platform/mojo/canonical_cookie.typemap",
+ "//third_party/blink/renderer/platform/mojo/fetch_api_request_headers.typemap",
"//third_party/blink/renderer/platform/mojo/file.typemap",
"//third_party/blink/renderer/platform/mojo/geometry.typemap",
"//third_party/blink/renderer/platform/mojo/kurl.typemap",
diff --git a/chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers.typemap b/chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers.typemap
new file mode 100644
index 00000000000..1a0f23986cd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers.typemap
@@ -0,0 +1,16 @@
+# 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.
+
+mojom = "//third_party/blink/public/mojom/fetch/fetch_api_request.mojom"
+public_headers = [
+ "//third_party/blink/renderer/platform/wtf/hash_map.h",
+ "//third_party/blink/renderer/platform/wtf/text/string_hash.h",
+ "//third_party/blink/renderer/platform/wtf/text/wtf_string.h",
+]
+traits_headers = [ "//third_party/blink/renderer/platform/mojo/fetch_api_request_headers_mojom_traits.h" ]
+
+deps = [
+ "//third_party/blink/renderer/platform/wtf",
+]
+type_mappings = [ "blink.mojom.FetchAPIRequestHeaders=WTF::HashMap<WTF::String, WTF::String, WTF::CaseFoldingHash>[move_only]" ]
diff --git a/chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers_mojom_traits.h b/chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers_mojom_traits.h
new file mode 100644
index 00000000000..24e4e456824
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/fetch_api_request_headers_mojom_traits.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_FETCH_API_REQUEST_HEADERS_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_FETCH_API_REQUEST_HEADERS_MOJOM_TRAITS_H_
+
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<
+ blink::mojom::blink::FetchAPIRequestHeaders::DataView,
+ WTF::HashMap<WTF::String, WTF::String, WTF::CaseFoldingHash>> {
+ static WTF::HashMap<WTF::String, WTF::String> headers(
+ const WTF::HashMap<WTF::String, WTF::String, WTF::CaseFoldingHash>&
+ input) {
+ WTF::HashMap<WTF::String, WTF::String> map;
+ for (const auto& tuple : input)
+ map.insert(tuple.key, tuple.value);
+ return map;
+ }
+
+ static bool Read(
+ blink::mojom::blink::FetchAPIRequestHeaders::DataView in,
+ WTF::HashMap<WTF::String, WTF::String, WTF::CaseFoldingHash>* out) {
+ WTF::HashMap<WTF::String, WTF::String> in_headers;
+ if (!in.ReadHeaders(&in_headers))
+ return false;
+ for (const auto& tuple : in_headers)
+ out->insert(tuple.key, tuple.value);
+ return true;
+ }
+};
+
+} // namespace mojo
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_FETCH_API_REQUEST_HEADERS_MOJOM_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/mojo/interface_invalidator_test.cc b/chromium/third_party/blink/renderer/platform/mojo/interface_invalidator_test.cc
index f10727bc6fe..b0ad1629771 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/interface_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/interface_invalidator_test.cc
@@ -14,6 +14,7 @@
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/interfaces/bindings/tests/ping_service.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/platform/mojo/interface_invalidator.h"
#include "third_party/blink/renderer/platform/mojo/revocable_binding.h"
#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
@@ -207,8 +208,9 @@ TEST_F(InterfaceInvalidatorTest, PassInterfaceOfInvalidatedPtr) {
ASSERT_TRUE(error_handler_called);
ASSERT_TRUE(impl.error_handler_called());
- mojo::test::blink::RevocablePingServicePtr wptr2(wptr.PassInterface(),
- invalidator.get());
+ mojo::test::blink::RevocablePingServicePtr wptr2(
+ wptr.PassInterface(), invalidator.get(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
wptr2->Ping(base::BindRepeating([] { FAIL(); }));
base::RunLoop().RunUntilIdle();
}
@@ -224,8 +226,9 @@ TEST_F(InterfaceInvalidatorTest,
// This also destroys the original invalidator.
invalidator = std::make_unique<InterfaceInvalidator>();
- mojo::test::blink::RevocablePingServicePtr wptr2(wptr.PassInterface(),
- invalidator.get());
+ mojo::test::blink::RevocablePingServicePtr wptr2(
+ wptr.PassInterface(), invalidator.get(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
wptr2->Ping(base::BindRepeating([] { FAIL(); }));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(impl.error_handler_called());
diff --git a/chromium/third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h b/chromium/third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h
index ba5e0f303b4..11de276e4a8 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h
@@ -48,8 +48,11 @@ class RevocableInterfacePtr : public InterfaceInvalidator::Observer {
other.reset();
}
- RevocableInterfacePtr(PtrInfoType info, InterfaceInvalidator* invalidator) {
- Bind(std::move(info), invalidator);
+ RevocableInterfacePtr(
+ PtrInfoType info,
+ InterfaceInvalidator* invalidator,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ Bind(std::move(info), invalidator, task_runner);
}
// Takes over the binding of another RevocableInterfacePtr, and closes any
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
index 2107d3cb0ac..686fb08e504 100644
--- a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
+#include "third_party/blink/public/mojom/csp/content_security_policy.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_security_policy.h"
#include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -57,9 +58,9 @@ bool IsMediaTypeCharacter(UChar c) {
return !IsASCIISpace(c) && c != '/';
}
-STATIC_ASSERT_ENUM(kWebContentSecurityPolicyTypeReport,
+STATIC_ASSERT_ENUM(mojom::ContentSecurityPolicyType::kReport,
kContentSecurityPolicyHeaderTypeReport);
-STATIC_ASSERT_ENUM(kWebContentSecurityPolicyTypeEnforce,
+STATIC_ASSERT_ENUM(mojom::ContentSecurityPolicyType::kEnforce,
kContentSecurityPolicyHeaderTypeEnforce);
STATIC_ASSERT_ENUM(kWebContentSecurityPolicySourceHTTP,
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc b/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc
index 83a957a4472..bea1c2b60cf 100644
--- a/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc
@@ -37,7 +37,7 @@ ContentSecurityPolicyResponseHeaders::ContentSecurityPolicyResponseHeaders(
: ContentSecurityPolicyResponseHeaders(
response.HttpHeaderFields(),
SchemeRegistry::SchemeSupportsWasmEvalCSP(
- response.Url().Protocol())) {}
+ response.CurrentRequestUrl().Protocol())) {}
ContentSecurityPolicyResponseHeaders::ContentSecurityPolicyResponseHeaders(
const HTTPHeaderMap& headers,
diff --git a/chromium/third_party/blink/renderer/platform/network/http_names.json5 b/chromium/third_party/blink/renderer/platform/network/http_names.json5
index ca872fec2d0..9d797a1b7a7 100644
--- a/chromium/third_party/blink/renderer/platform/network/http_names.json5
+++ b/chromium/third_party/blink/renderer/platform/network/http_names.json5
@@ -35,6 +35,7 @@
"Expires",
"Date",
"Feature-Policy",
+ "Feature-Policy-Report-Only",
"If-Match",
"If-Modified-Since",
"If-None-Match",
diff --git a/chromium/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc b/chromium/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc
index ad0dbf80356..0d5dcc9b747 100644
--- a/chromium/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc
@@ -28,12 +28,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
unsigned failure_position = 0;
std::string terminated(reinterpret_cast<const char*>(data), size);
+
+ // There are no guarantees regarding the string capacity, but we are doing our
+ // best to make it |size + 1|.
+ terminated.shrink_to_fit();
+
blink::IsValidHTTPToken(terminated.c_str());
blink::ParseCacheControlDirectives(terminated.c_str(), AtomicString());
blink::ParseCommaDelimitedHeader(terminated.c_str(), set);
blink::ParseHTTPRefresh(terminated.c_str(), nullptr, delay, url);
- blink::ParseMultipartHeadersFromBody(terminated.c_str(), terminated.size(),
- &response, &end);
+
+ // Intentionally pass raw data as the API does not require trailing \0.
+ blink::ParseMultipartHeadersFromBody(reinterpret_cast<const char*>(data),
+ size, &response, &end);
blink::ParseServerTimingHeader(terminated.c_str());
blink::ParseContentTypeOptionsHeader(terminated.c_str());
blink::ParseXSSProtectionHeader(terminated.c_str(), failure_reason,
diff --git a/chromium/third_party/blink/renderer/platform/network/http_parsers_test.cc b/chromium/third_party/blink/renderer/platform/network/http_parsers_test.cc
index 0b796138c19..691af02b170 100644
--- a/chromium/third_party/blink/renderer/platform/network/http_parsers_test.cc
+++ b/chromium/third_party/blink/renderer/platform/network/http_parsers_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/network/http_parsers.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
@@ -304,7 +305,7 @@ TEST(HTTPParsersTest, ParseMultipartHeadersResult) {
{"Foo: bar\r\nBaz:\n", false, 0},
{"\r\n", true, 2},
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
ResourceResponse response;
wtf_size_t end = 0;
bool result = ParseMultipartHeadersFromBody(
diff --git a/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc b/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc
index 769ce628d4f..82d47a1dd18 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc
+++ b/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc
@@ -211,7 +211,7 @@ void NetworkStateNotifier::SetNetworkConnectionInfoOverride(
bool on_line,
WebConnectionType type,
base::Optional<WebEffectiveConnectionType> effective_type,
- unsigned long http_rtt_msec,
+ int64_t http_rtt_msec,
double max_bandwidth_mbps) {
DCHECK(IsMainThread());
ScopedNotifier notifier(*this);
diff --git a/chromium/third_party/blink/renderer/platform/network/network_state_notifier.h b/chromium/third_party/blink/renderer/platform/network/network_state_notifier.h
index 14e350a1ab5..5fa9b60fc8d 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_state_notifier.h
+++ b/chromium/third_party/blink/renderer/platform/network/network_state_notifier.h
@@ -223,7 +223,7 @@ class PLATFORM_EXPORT NetworkStateNotifier {
// When called, successive setWebConnectionType/setOnLine calls are stored,
// and supplied overridden values are used instead until clearOverride() is
- // called. This is used for layout tests (see crbug.com/377736) and inspector
+ // called. This is used for web tests (see crbug.com/377736) and inspector
// emulation.
// If |effective_type| is null, its value is computed using |http_rtt_msec|.
// |max_bandwidth_mbps| is used to override both the |max_bandwidth_mbps| and
@@ -235,7 +235,7 @@ class PLATFORM_EXPORT NetworkStateNotifier {
bool on_line,
WebConnectionType,
base::Optional<WebEffectiveConnectionType> effective_type,
- unsigned long http_rtt_msec,
+ int64_t http_rtt_msec,
double max_bandwidth_mbps);
void SetSaveDataEnabledOverride(bool enabled);
void ClearOverride();
diff --git a/chromium/third_party/blink/renderer/platform/network/network_utils.cc b/chromium/third_party/blink/renderer/platform/network/network_utils.cc
index 9f7d946f297..da84fc65bda 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/network/network_utils.cc
@@ -90,7 +90,7 @@ scoped_refptr<SharedBuffer> ParseDataURLAndPopulateResponse(
SharedBuffer::Create(data_string.data(), data_string.size());
response.SetHTTPStatusCode(200);
response.SetHTTPStatusText("OK");
- response.SetURL(url);
+ response.SetCurrentRequestUrl(url);
response.SetMimeType(WebString::FromUTF8(utf8_mime_type));
response.SetExpectedContentLength(data->size());
response.SetTextEncodingName(WebString::FromUTF8(utf8_charset));
@@ -133,6 +133,21 @@ String GenerateAcceptLanguageHeader(const String& lang) {
net::HttpUtil::GenerateAcceptLanguageHeader(string));
}
+Vector<char> ParseMultipartBoundary(const AtomicString& content_type_header) {
+ CString cstring(content_type_header.Utf8());
+ std::string string(cstring.data(), cstring.length());
+ std::string mime_type;
+ std::string charset;
+ bool had_charset = false;
+ std::string boundary;
+ net::HttpUtil::ParseContentType(string, &mime_type, &charset, &had_charset,
+ &boundary);
+ base::TrimString(boundary, " \"", &boundary);
+ Vector<char> result;
+ result.Append(boundary.data(), boundary.size());
+ return result;
+}
+
} // namespace network_utils
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/network/network_utils.h b/chromium/third_party/blink/renderer/platform/network/network_utils.h
index ac3cb6fbc29..e9741206c3e 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_utils.h
+++ b/chromium/third_party/blink/renderer/platform/network/network_utils.h
@@ -46,6 +46,9 @@ PLATFORM_EXPORT bool IsLegacySymantecCertError(int);
PLATFORM_EXPORT String GenerateAcceptLanguageHeader(const String&);
+PLATFORM_EXPORT Vector<char> ParseMultipartBoundary(
+ const AtomicString& content_type_header);
+
} // namespace network_utils
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_void_request.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_void_request.h
index 597cb1e7326..590402cb7b0 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_void_request.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_void_request.h
@@ -33,7 +33,7 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/webrtc/api/rtcerror.h"
+#include "third_party/webrtc/api/rtc_error.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f4f07c4f51c..8f577c5c879 100644
--- a/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -96,6 +96,10 @@
status: "experimental",
},
{
+ name: "AsyncClipboardImages",
+ status: "experimental",
+ },
+ {
name: "AudioOutputDevices",
status: "stable",
},
@@ -108,6 +112,12 @@
settable_from_internals: true,
},
{
+ name: "AutoPictureInPicture",
+ depends_on: ["PictureInPictureAPI"],
+ origin_trial_feature_name: "AutoPictureInPicture",
+ status: "experimental",
+ },
+ {
// Flag set by the media::kAutoplayIgnoreWebAudio feature flag.
name: "AutoplayIgnoresWebAudio",
settable_from_internals: true,
@@ -118,23 +128,20 @@
status: "experimental",
},
{
- name: "BackgroundFetchAccessActiveFetches",
- status: "experimental",
- },
- {
- name: "BackgroundFetchUploads",
- status: "experimental",
- },
- {
name: "BackgroundVideoTrackOptimization",
status: "stable",
},
{
name: "Badging",
- status: "test",
+ origin_trial_feature_name: "Badging",
+ status: "experimental",
+ },
+ {
+ name: "BidiCaretAffinity",
},
{
name: "BlinkGenPropertyTrees",
+ status: "experimental",
},
{
name: "BlinkRuntimeCallStats",
@@ -153,7 +160,7 @@
status: "stable",
},
{
- name: "BlockingDownloadsInSandbox",
+ name: "BlockingDownloadsInSandboxWithoutUserActivation",
},
{
name: "BlockMetaSetCookie",
@@ -167,10 +174,6 @@
status: "stable",
},
{
- name: "CacheStyleSheetWithMediaQueries",
- status: "experimental",
- },
- {
name: "CallCaptureListenersAtCapturePhaseAtShadowHosts",
status: "stable",
},
@@ -209,12 +212,10 @@
name: "ClientPlaceholdersForServerLoFi",
},
{
- name: "CompositedSelectionUpdate",
+ name: "CompositeAfterPaint",
},
{
- name: "CompositeOpaqueFixedPosition",
- settable_from_internals: true,
- status: "experimental",
+ name: "CompositedSelectionUpdate",
},
{
name: "CompositorTouchAction",
@@ -225,11 +226,8 @@
status: "experimental",
},
{
- name: "ConstructableStylesheets",
- status: "experimental",
- },
- {
name: "ContactsManager",
+ origin_trial_feature_name: "ContactsManager",
status: "experimental",
},
{
@@ -249,6 +247,10 @@
status: "experimental",
},
{
+ name: "CSS3TextBreakSpaces",
+ status: "experimental",
+ },
+ {
name: "CSSAdditiveAnimations",
depends_on: ["StackedCSSPropertyAnimations"],
status: "experimental",
@@ -318,7 +320,7 @@
},
{
name: "CSSPartPseudoElement",
- status: "experimental",
+ status: "stable",
},
{
name: "CSSPseudoIs",
@@ -361,6 +363,7 @@
// without native Custom Elements v0 support.
{
name: "CustomElementsV0",
+ origin_trial_feature_name: "WebComponentsV0",
status: "stable",
},
{
@@ -411,11 +414,8 @@
{
// https://crbug.com/879270
name: "ElementTiming",
- status: "test",
- },
- {
- name: "EncodingStreams",
- status: "stable",
+ origin_trial_feature_name: "ElementTimingImages",
+ status: "experimental",
},
{
name: "EncryptedMediaEncryptionSchemeQuery",
@@ -423,8 +423,7 @@
},
{
name: "EncryptedMediaHdcpPolicyCheck",
- origin_trial_feature_name: "EncryptedMediaHdcpPolicyCheck",
- status: "experimental",
+ status: "stable",
},
{
name: "EncryptedMediaPersistentUsageRecordSession",
@@ -469,10 +468,6 @@
status: "experimental"
},
{
- name: "ExperimentalV8Extras",
- status: "experimental",
- },
- {
name: "ExtendedTextMetrics",
status: "experimental",
},
@@ -480,6 +475,9 @@
name: "ExtraWebGLVideoTextureMetadata",
},
{
+ name: "FastFlatTreeTraversal",
+ },
+ {
name: "FastMobileScrolling",
},
{
@@ -491,6 +489,7 @@
{
name: "FeaturePolicyReporting",
implied_by: ["ExperimentalProductivityFeatures"],
+ origin_trial_feature_name: "FeaturePolicyReporting",
status: "experimental"
},
{
@@ -507,6 +506,10 @@
name: "FirstContentfulPaintPlusPlus",
},
{
+ name: "FocuslessSpatialNavigation",
+ settable_from_internals: true,
+ },
+ {
name: "FontCacheScaling",
status: "test",
},
@@ -515,7 +518,11 @@
// No status, as the web platform runtime enabled feature is controlled by
// a Chromium level feature.
},
- // For simulating Android's overlay fullscreen video in layout tests on Linux.
+ // For simulating Android's overlay fullscreen video in web tests on Linux.
+ {
+ name: "ForbidSyncXHRInPageDismissal",
+ status: "test",
+ },
{
name: "ForceOverlayFullscreenVideo",
},
@@ -524,7 +531,7 @@
},
{
name: "FormAssociatedCustomElements",
- status: "test",
+ status: "experimental",
},
{
name: "FormDataEvent",
@@ -559,11 +566,6 @@
status: "experimental",
},
{
- name: "GamepadExtensions",
- origin_trial_feature_name: "WebVR1.1M62",
- status: "experimental",
- },
- {
name: "GamepadVibration",
status: "experimental",
},
@@ -594,6 +596,7 @@
// https://crbug.com/766694 for testing disabling the feature.
{
name: "HTMLImports",
+ origin_trial_feature_name: "WebComponentsV0",
status: "stable",
},
// https://crbug.com/523952 for testing disabling the feature.
@@ -606,6 +609,14 @@
status: "experimental",
},
{
+ name: "IDBTransactionCommit",
+ status: "experimental",
+ },
+ {
+ name: "IdleDetection",
+ status: "experimental",
+ },
+ {
name: "IgnoreCrossOriginWindowWhenNamedAccessOnWindow",
status: "experimental",
},
@@ -633,6 +644,7 @@
},
{
name: "IntersectionObserverV2",
+ status: "experimental",
},
{
name: "InvisibleDOM",
@@ -643,16 +655,23 @@
status: "experimental",
},
{
+ // If enabled, CSP checks use the isolated world CSP when in an isolated
+ // world. See crbug.com/896041.
+ name: "IsolatedWorldCSP"
+ },
+ {
// Tracks "jank" from layout objects changing their visual location
// between animation frames (see crbug.com/581518).
name: "JankTracking",
implied_by: ["LayoutJankAPI", "JankTrackingSweepLine"],
+ origin_trial_feature_name: "LayoutJankAPI",
status: "experimental",
},
{
// Modifies JankTracking to use O(n log n) sweep line algorithm for
// computing the area of the jank region.
name: "JankTrackingSweepLine",
+ status: "experimental",
},
{
name: "KeyboardFocusableScrollers",
@@ -669,7 +688,8 @@
// Exposes layout jank fractions to Javascript. See explainer:
// http://bit.ly/lsm-explainer.
name: "LayoutJankAPI",
- status: "test",
+ origin_trial_feature_name: "LayoutJankAPI",
+ status: "experimental",
},
{
name: "LayoutNG",
@@ -689,10 +709,6 @@
implied_by: ["LayoutNG"],
},
{
- name: "LayoutViewIsolationNodes",
- status: "stable",
- },
- {
name: "LazyFrameLoading",
},
{
@@ -709,6 +725,10 @@
// This is enabled by features::kLazyInitializeMediaControls.
},
{
+ name: "LegacyPerformanceMemoryCounters",
+ origin_trial_feature_name: "LegacyPerformanceMemoryCounters",
+ },
+ {
name: "LongTaskV2",
},
{
@@ -758,14 +778,18 @@
name: "MediaEngagementBypassAutoplayPolicies",
},
{
+ name: "MediaQueryPrefersColorScheme",
+ },
+ {
+ name: "MediaQueryPrefersReducedMotion",
+ },
+ {
name: "MediaQueryShape",
status: "experimental",
},
- // MediaSession is enabled by default on Android only.
- // TODO(rbyers): Add parameter to specify platform.
{
name: "MediaSession",
- status: "test",
+ status: "stable",
},
{
name: "MediaSourceExperimental",
@@ -842,7 +866,7 @@
settable_from_internals: true,
},
{
- name: "NoIdleEncodingForLayoutTests",
+ name: "NoIdleEncodingForWebTests",
status: "test",
},
{
@@ -892,7 +916,7 @@
status: "stable",
},
// Define a sample API for testing integration with the Origin Trials
- // Framework. The sample API is used in both unit and layout tests for the
+ // Framework. The sample API is used in both unit and web tests for the
// Origin Trials Framework. Do not change this flag to stable, as it exists
// solely to generate code used by the sample API implementation.
{
@@ -900,7 +924,7 @@
origin_trial_feature_name: "Frobulate",
},
// Define a sample API for testing integration with the Origin Trials
- // Framework. The sample API is used in both unit and layout tests for the
+ // Framework. The sample API is used in both unit and web tests for the
// Origin Trials Framework. Do not change this flag to stable, as it exists
// solely to generate code used by the sample API implementation.
{
@@ -919,9 +943,28 @@
settable_from_internals: true,
},
{
+ name: "OverscrollCustomization",
+ settable_from_internals: true,
+ },
+ // This feature refers to the API that delivers notifications to pages on
+ // lifecycle state changes.
+ {
name: "PageLifecycle",
status: "stable",
},
+ // The following are developer opt-outs and opt-ins for PageLifecycle state
+ // transitions. If neither is specified then heuristics will be applied to
+ // determine whether the page is eligible.
+ {
+ name: "PageLifecycleTransitionsOptIn",
+ origin_trial_feature_name: "PageLifecycleTransitionsOptIn",
+ status: "experimental",
+ },
+ {
+ name: "PageLifecycleTransitionsOptOut",
+ origin_trial_feature_name: "PageLifecycleTransitionsOptOut",
+ status: "experimental",
+ },
{
name: "PagePopup",
status: "stable",
@@ -941,6 +984,7 @@
},
{
name: "PassiveDocumentWheelEventListeners",
+ status: "stable",
},
{
name: "PassPaintVisualRectToCompositor",
@@ -959,6 +1003,9 @@
status: "experimental",
},
{
+ name: "PaymentRequestHasEnrolledInstrument",
+ },
+ {
name: "PaymentRetry",
status: "experimental",
},
@@ -1010,7 +1057,7 @@
},
{
name: "PreloadImageSrcSet",
- status: "experimental",
+ status: "stable",
},
{
name: "Presentation",
@@ -1021,6 +1068,7 @@
},
{
name: "PriorityHints",
+ origin_trial_feature_name: "PriorityHints",
status: "experimental",
},
{
@@ -1068,6 +1116,11 @@
origin_trial_feature_name: "RtcAudioJitterBufferMaxPackets",
status: "experimental",
},
+ {
+ name: "RtcAudioJitterBufferRtxHandling",
+ origin_trial_feature_name: "RtcAudioJitterBufferRtxHandling",
+ status: "experimental",
+ },
// Enables the use of the RTCDtlsTransport object.
{
name: "RTCDtlsTransport",
@@ -1076,7 +1129,8 @@
// Enables the use of the RTCIceTransport with extensions.
{
name: "RTCIceTransportExtension",
- status: "test",
+ origin_trial_feature_name: "RTCQuicTransport",
+ status: "experimental",
},
{
name: "RtcPeerConnectionId",
@@ -1086,7 +1140,8 @@
// Enables the use of the RTCQuicTransport object.
{
name: "RTCQuicTransport",
- status: "test",
+ origin_trial_feature_name: "RTCQuicTransport",
+ status: "experimental",
},
{
name: "RTCRtpSenderParameters",
@@ -1166,6 +1221,7 @@
// without native Shadow DOM v0 support
{
name: "ShadowDOMV0",
+ origin_trial_feature_name: "WebComponentsV0",
status: "stable",
},
{
@@ -1191,10 +1247,10 @@
status: "experimental",
},
{
- name: "SignedHTTPExchange",
- },
- {
- name: "SlimmingPaintV2",
+ name: "SkipAd",
+ depends_on: ["MediaSession"],
+ origin_trial_feature_name: "SkipAd",
+ status: "experimental",
},
{
name: "SmoothScrollJSIntervention",
@@ -1254,6 +1310,7 @@
},
{
name: "TransferableStreams",
+ status: "experimental",
},
// This is conditionally set if the platform supports translation.
{
@@ -1261,6 +1318,7 @@
},
{
name: "TrustedDOMTypes",
+ origin_trial_feature_name: "TrustedDOMTypes",
status: "experimental",
},
{
@@ -1286,10 +1344,6 @@
name: "UserActivationV2",
},
{
- name: "V8ContextSnapshot",
- status: "test",
- },
- {
name: "V8IdleTasks",
},
{
@@ -1344,8 +1398,8 @@
status: "experimental",
},
{
- name: "WebFontsCacheAwareTimeoutAdaptation",
- status: "experimental",
+ name: "WebBluetoothScanning",
+ status: "test",
},
{
name: "WebGL2ComputeContext",
@@ -1377,6 +1431,11 @@
status: "experimental",
},
{
+ name: "WebShareV2",
+ status: "experimental",
+ depends_on: ["WebShare"],
+ },
+ {
name: "WebUSB",
status: "stable",
},
@@ -1390,22 +1449,32 @@
origin_trial_feature_name: "WebVR1.1M62",
status: "experimental",
},
+ // Extensions to the Gamepad API for WebVR. Formerly GamepadExtensions.
+ // Although not separately controllable, it is still a separate feature
+ // for clarity in the IDL.
+ // TODO(https://crbug.com/920025): Consider merging with "WebVR".
+ {
+ name: "WebVRGamepadSupport",
+ implied_by: ["WebVR"],
+ status: "experimental",
+ },
{
name: "WebVTTRegions",
status: "experimental",
},
{
name: "WebXR",
- origin_trial_feature_name: "WebXRDeviceM69",
+ origin_trial_feature_name: "WebXRDeviceM73",
status: "experimental",
},
- // Subset of the GamepadExtensions wanted for WebXR, which expose VR controller
- // functionality as Gamepads.
+ // Subset of the Gamepad extensions used for early WebXR implementations
+ // that exposed VR controller functionality as Gamepads.
+ // TODO(https://crbug.com/920025): Remove this.
{
name: "WebXRGamepadSupport",
origin_trial_feature_name: "WebXRGamepadSupport",
- // This feature is a strict subset of GamepadExtensions.
- implied_by: ["GamepadExtensions"],
+ // This feature is a strict subset of the WebVR Gamepad extensions.
+ implied_by: ["WebVRGamepadSupport"],
status: "experimental",
},
{
@@ -1426,10 +1495,6 @@
status: "experimental"
},
{
- name: "WorkStealingInScriptRunner",
- status: "experimental",
- },
- {
name: "WritableFiles",
status: "experimental",
},
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn b/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn
index 99ba202179e..786897faa5d 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -3,9 +3,9 @@
# found in the LICENSE file.
import("//build/config/jumbo.gni")
+import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/blink/renderer/platform/platform.gni")
import("//third_party/protobuf/proto_library.gni")
-import("//testing/libfuzzer/fuzzer_test.gni")
blink_platform_sources("scheduler") {
sources = [
@@ -15,10 +15,10 @@ blink_platform_sources("scheduler") {
"common/features.cc",
"common/features.h",
"common/frame_or_worker_scheduler.cc",
- "common/idle_canceled_delayed_task_sweeper.cc",
- "common/idle_canceled_delayed_task_sweeper.h",
"common/idle_helper.cc",
"common/idle_helper.h",
+ "common/idle_memory_reclaimer.cc",
+ "common/idle_memory_reclaimer.h",
"common/metrics_helper.cc",
"common/metrics_helper.h",
"common/pollable_thread_safe_flag.cc",
@@ -92,8 +92,6 @@ blink_platform_sources("scheduler") {
"main_thread/render_widget_signals.h",
"main_thread/resource_loading_task_runner_handle_impl.cc",
"main_thread/resource_loading_task_runner_handle_impl.h",
- "main_thread/task_cost_estimator.cc",
- "main_thread/task_cost_estimator.h",
"main_thread/task_type_names.cc",
"main_thread/task_type_names.h",
"main_thread/use_case.h",
@@ -179,8 +177,8 @@ jumbo_source_set("unit_tests") {
sources = [
"common/background_scheduler_unittest.cc",
- "common/idle_canceled_delayed_task_sweeper_unittest.cc",
"common/idle_helper_unittest.cc",
+ "common/idle_memory_reclaimer_unittest.cc",
"common/metrics_helper_unittest.cc",
"common/post_cancellable_task_unittest.cc",
"common/scheduler_helper_unittest.cc",
@@ -199,7 +197,6 @@ jumbo_source_set("unit_tests") {
"main_thread/page_scheduler_impl_unittest.cc",
"main_thread/queueing_time_estimator_unittest.cc",
"main_thread/render_widget_signals_unittest.cc",
- "main_thread/task_cost_estimator_unittest.cc",
"main_thread/user_model_unittest.cc",
"worker/compositor_thread_scheduler_unittest.cc",
"worker/worker_scheduler_proxy_unittest.cc",
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/README.md b/chromium/third_party/blink/renderer/platform/scheduler/README.md
index 88299cfb052..235fe75ff4b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/README.md
+++ b/chromium/third_party/blink/renderer/platform/scheduler/README.md
@@ -3,133 +3,22 @@
This directory contains the Blink Scheduler, which coordinates task execution
in renderer processes. The main subdirectories are:
-- `base/` -- basic scheduling primitives such as `TaskQueue` and
- `SequenceManager`.
-- `child/` -- contains the `ChildScheduler` which is the base class for all
- thread schedulers, as well as a `WorkerScheduler` for worker threads.
-- `utility/` -- a small scheduler for utility processes.
-- `renderer/` -- `RendererScheduler` for the renderer process.
+- `public` -- contains the interfaces which scheduler exposes to the other parts
+ of Blink (`FrameScheduler`, `PageScheduler`, `WorkerScheduler` and others).
+ Other code in Blink should not depend on files outside of this directory.
+- `common` -- contains `ThreadSchedulerImpl` which is the base class for all
+ thread schedulers, as well as other functionality which is required for both
+ main thread and worker threads.
+- `main_thread` -- contains implementation of the main thread scheduler
+ (`MainThreadSchedulerImpl`) and main thread scheduling policies.
+- `worker` -- contains implementation of scheduling infrastructure for
+ the non-main threads (compositor thread, worker threads).
-The scheduler exposes an API at `public/platform/scheduler`.
+The scheduler exposes an API to the content layer at
+`public/platform/scheduler`.
-# Documentation
+# Further reading
-The following is a collection of scheduling-related documentation about the
-Blink Scheduler as well as other schedulers in Chrome.
+[Overview of task scheduling in Blink](TaskSchedulingInBlink.md).
+[Collection of scheduling-related documentation](links.md).
-
-## 2018
-* [Browser-side scheduling roadmap](https://docs.google.com/document/d/1yxjka3kyKieEWP6gRlLyXVy72DJ5Gc22Nqp9vehFj14/edit)
-* [Browser UI thread scheduler](https://docs.google.com/document/d/1z1BDq9vzcEpkhN9LSPF5XMnZ0kLJ8mWWkNAi4OI7cos/edit)
-* [Browser IO thread scheduling for input latency](https://docs.google.com/document/d/12waKYiZOOu1DwUJO5faSonq9OwRIJuaP0GavClPTHWY/edit)
-* [Off Main Thread: Scheduling API](https://docs.google.com/document/d/1SGWR1LrrgOUWHNJZU6JfUC89dCMSIXP7TH8RmoWLqyc/edit)
-* [Task traits for sequence scheduling in //content](https://docs.google.com/document/d/1SGy9VTXUwyXEX_yBZ0ukFAnS8B0hDeMUJD-1iALaE-Q/edit)
-* [Stop more task queues in background on Android](https://docs.google.com/document/d/10D2uvOVxBZ2YhcwtK1XOb6CClminPpqAeS82KOVT7hk/edit)
-* [Discussion of more graceful worker shutdown](https://docs.google.com/document/d/11waILCkPehUfML6_defbpkNk4mau6qiK8f7qXtqauwY/edit)
-* [Stop loading in background on Android](https://docs.google.com/document/d/1DEGgG9HfA2ixJpXQDsKbYCJJyHILWz3CQmuNEJr9Xho/edit)
-* [Android startup performance tweaks](https://docs.google.com/document/d/1rGbdF0Rjv0wl7dEQ4kGj2f79Q20MlIv7ch9MSlm2G3M/edit#heading=h.e7o0jj9sx1od)
-* [C++ Promises for Chromium](https://docs.google.com/document/d/1l12PAJgEtlrqTXKiw6mk2cR2jP7FAfCCDr-DGIdiC9w/edit)
-* [C++ Promise/Future/Coroutine in Chromium](https://docs.google.com/document/d/1RThP0a8fTyuYqpPN2zrMxt8Te9M0v3JUv1XhcquBz9E/edit)
-* [Java task scheduling](https://docs.google.com/document/d/1z2ALaVDkfxurPpzDzO9dAAK3dLuLCjYViJijydPoMHs/edit)
-* [Scheduling resource responses with right priority](https://docs.google.com/document/d/18WcfptovabsfE-2Nb4M_x8abVqInr-94fno81E_NcJk/edit)
-* [Refactor EventQueue](https://docs.google.com/document/d/1BBtBPTarOF4NeVKSWZe3XaDHo4yTGhdlqYm35yVzPs4/edit)
-* [Looking into scrolling lag](https://docs.google.com/document/d/1l2e3B6Ad0mqMRqs3_cK8a-o4Po6XMhOgIZt2B5r_ZG0/edit#heading=h.2ef1y98v91gv)
-* [Better scheduling metrics](https://docs.google.com/document/d/1o6QHeY8y6PssEv--Qs6uNeNWrOzTwDyrbTk9iuq2WmY/edit#heading=h.ia9zbay5xpwt)
-* [Scheduler architecture 2.0](https://docs.google.com/document/d/1dk71yTd5fndb5gMSb7wlB2P80hw5ImFxbPao06Ti8EQ/edit#heading=h.7m3oi6qeqhdv)
-* [Task Scheduler - Message Loop integration and migration](https://docs.google.com/document/d/1Vy7kz_9evp6xOFRQBD6M1h4qmk4EEBu0cutipQ3e6kA/edit)
-* [Supporting per-frame priorities in Blink Scheduler](https://docs.google.com/document/d/1-0nNG75hfsg1WhW3Xa4yUNDQdP1D6EJ9r2tl4tmAVJM/edit)
-* [Simplifying scheduler interfaces](https://docs.google.com/document/d/1oz-Rjpn6KhmQvaJF4b674Jofiy3PQQPbyngqFGlYknY/edit)
-* [Using dedicated workers for background work](https://docs.google.com/document/d/1qTYo9ZQwsycJYPAuT5AKw6JYBEsSfJQR823mma3CGvQ/edit)
-* [Untangling spaghetti of platform/scheduler/](https://docs.google.com/document/d/1jxM32tM-djMl7Xzy_tQbVadX1HjQ06fH0x7ofxeeSVc/edit#heading=h.34va28zf1wfu)
-* [Better layering for platform/scheduler/](https://docs.google.com/document/d/1Brt1oSUrL4M_TBSl-KiCbvQt8kYxwnmqsXrmJM00ylA/edit)
-* [Keyed Service scheduling](https://docs.google.com/document/d/1JCvCQvux0DW0X3tyfE_u70Fvpspfn7KDTTdJVD7M524/edit)
-
-
-## 2017
-* [Improved load time scheduling](https://docs.google.com/document/d/1q5uPIKyUP0X7KaQRyxWXmIzMvKF3fx1j6QPCWhjI82o/edit)
-* [Wake-up based throttling](https://docs.google.com/document/d/1A87Ci3_USDyQEdlmXTO1spQxUcR_ML5zqiCsaow4NGM/edit)
-* [Background tabs & offscreen frames](https://docs.google.com/document/d/18_sX-KGRaHcV3xe5Xk_l6NNwXoxm-23IOepgMx4OlE4/edit)
-* [BeginFrame sequence numbers + acknowledgements](https://docs.google.com/document/d/1nxaunQ0cYWxhtS6Zzfwa99nae74F7gxanbuT5JRpI6Y/edit)
-* [Background tab use cases](https://docs.google.com/document/d/16-QGneIkYNbNleoXbdD-mRMYdZAG2JIjMcTVxSC3ZWc/edit)
-* [Activity traits](https://docs.google.com/document/d/1BaJpx08vbPz_1LCj9tehnatZNqh1eLPeE9xoUnWdlW4/edit#heading=h.nwhgpfhlxswr)
-* [Blink and Task Scheduler integration](https://docs.google.com/document/d/1h-FlOeO-27g__JnuRvdJ8KG9G-bmG_zn6zuw7GerFkc/edit)
-* [Lifecycle use cases](https://docs.google.com/document/d/16-QGneIkYNbNleoXbdD-mRMYdZAG2JIjMcTVxSC3ZWc/edit)
-* [Task execution policies in Blink](https://docs.google.com/document/d/1tFI0pkLp1LCFDKRxwT6BSdA-ub8K4cZJLlCaAlqmsvM/edit)
-* [Capturing task type metadata](https://docs.google.com/document/d/1Py2ZdjpaCMdpVtKfdHMITAn5gst_owjQiqlbPm3mCxc/edit)
-* [Further per-frame scheduler work](https://docs.google.com/document/d/1yOhE6-1HLb3aeNWmoa9O2LlnegWjd4awYUn2OhUL4vk/edit)
-* [Better tracing for Blink Scheduler](https://docs.google.com/document/d/18Iz0lVX38_ZIMNoAp4e2RpeIFcCUUU2cghDwy_aLK3k/edit)
-* [Scheduling architecture roadmap: one pager](https://docs.google.com/document/d/13dQAthHRn7bkEgsb7OzG50zhxFFB1rHEDCM7ObXH1_c/edit)
-* [RendererMainThreadLoad metrics](https://docs.google.com/document/d/1MvAadiO3kwSodfOIZ35k2j4oJX-zVY9FsQaSshI-vus/edit#heading=h.r8nzo35yh6ck)
-* [State of the throttling](https://docs.google.com/document/d/1csir1MUkI1maqjAIzhR51LTy1pwSqeh9HDmAPTZWirw/edit)
-* [Background tabs & offscreen frames](https://docs.google.com/document/d/18_sX-KGRaHcV3xe5Xk_l6NNwXoxm-23IOepgMx4OlE4/edit)
-* [Prototyping cooperative scheduling](https://docs.google.com/document/d/1ennqB9cCfko6eg1a6bNoJjaypESjfFvhVup9LSJCyUg/edit)
-* [Cooperative scheduling in Blink](https://docs.google.com/document/d/14WoGZ8pfD4TmOFDebE-WIgkfQ62MnOiyafQI4Zhqjzs/edit)
-
-## 2016
-
-* [Time-based renderer task throttling](https://drive.google.com/open?id=1vCUeGfr2xzZ67SFt2yZjNeaIcXGp2Td6KHN7bI02ySo)
-* [V8 Performance Mode](https://drive.google.com/open?id=1bRVAP08qNBvnEm_vO4hW1-NqQC9-lQZjUH29_vwfYRY)
-* [Isolating performance of third-party iframes](https://docs.google.com/document/d/1CEggurHQGXenhu_GQT7KnRvtSuowuenXpxVzYSeRxSY/edit)
-* [Folly of Scheduling (BlinkOn 6)](https://drive.google.com/open?id=1ZMxbnSn1R1o2-NGztP0mVyOOoQg24bLSqWE1SWXnQ_E)
-* [Rendering pipeline throttling (BlinkOn 6)](https://docs.google.com/presentation/d/1aPZzH7J0O29sqA_FzsuWQNDwK6CoNcAcpMvJexsO6Vg/edit)
-* [Power usage impact of render pipeline throttling](https://docs.google.com/document/d/1jMuvRYWptZfP5zpvWmPJPRL-iowtgBVX45rSvew0VH4)
-* [The future of TaskRunnerHandles](https://docs.google.com/document/d/1A_LRKyTOCzhRPOY4Q3RsePuw4UCsvxuFYx6D18BaYk0/edit#heading=h.xgjl2srtytjt)
-* [Improved policy for blocking expensive tasks](https://docs.google.com/document/d/14VdbqN-ehgpNC4KYVpPQFiQpfxOQiVtJgYjXUJGI4f0/edit#)
-* [scheduler-dev performance metrics](https://docs.google.com/document/d/15CIJ4eMnwOneshhjFxVjz3FCV7ja9lrlQOEZGWLZdgA/edit)
-* [FrameBlamer](https://docs.google.com/document/d/15BB-suCb9j-nFt55yCFJBJCGzLg2qUm3WaSOPb8APtI/edit)
-* [Virtual time in Blink](https://drive.google.com/open?id=1y9KDT_ZEzT7pBeY6uzVt1dgKlwc1OB_vY4NZO1zBQmo)
-* [Browser I/O scheduler (Lucky Luke)](https://docs.google.com/document/d/1S2AAeoo1xa_vsLbDYBsDHCqhrkfiMgoIPlyRi6kxa5k/edit)
-
-## 2015
-
-* [Virtual time in Headless Chrome](https://docs.google.com/document/d/1dIMHIl1xutUXqXWRXqXrDd3bo9hachIt_ZkPK_BshUs/edit)
-* [Task traits](https://docs.google.com/document/d/1d6t7CTobtXLj1gXiBE8SVl_fxJjEazATxYHYGp5ppvE)
-* [Compositor and Display Scheduling presentation from scheduling summit](https://docs.google.com/presentation/d/1FpTy5DpIGKt8r2t785y6yrHETkg8v7JfJ26zUxaNDUg/edit?usp=sharing)
-* [Simplifying Task Management in Chromium](https://docs.google.com/document/d/1fn0AmFsY7gWvStShOh7dUxOfHXjKgcfsr9I1ETbNe2I/edit)
-* [Outline of known work needed to fix resize](https://docs.google.com/a/chromium.org/document/d/1POLDq-L_T9iZ_Ul39sjOMiOO-yvLnmb1WFsH4JfIyVU/edit?usp=sharing_eid)
-* [Blink spatial scheduling](https://docs.google.com/document/d/1k9fL01wwRliVzZW_ibPT8-B9BADz7I87hpFoXFG37aI/edit?pli=1#)
-* [Throttling Blink's rendering pipeline for hidden content](https://docs.google.com/document/d/1Dd4qi1b_iX-OCZpelvXxizjq6dDJ76XNtk37SZEoTYQ/edit)
-* [Scheduling to avoid checkerboard in Chrome](https://docs.google.com/document/d/1OLp7x06CjBY-0J3TBQzXw8sALHznIx4rYixvnBTbUUA/edit#heading=h.9i2v5u7um22b)
-* [State of GPU scheduling](https://docs.google.com/document/d/15gbHgXPyhSlNu1Ku9HF-of8BNOpvsziV1F8IE-kRax4/edit#heading=h.jermw4ib9rwc)
-* [Scheduling architecture diagram](https://docs.google.com/drawings/d/1xcHpqhdcIsX0b_sGPuU1SZCsY87UTqJ67qvvbF29oLM/edit)
-* [Event dispatch diagram](https://docs.google.com/drawings/d/1bUukRm-DV34sM7rL2_bSdxaQkZVMQ_5vOa7nzDnmnx8/edit)
-* [Proxying MessageLoop tasks to the Scheduler](https://docs.google.com/a/chromium.org/document/d/1qxdh2I61_aB_Uzh1QgNqvdWFBCL_E65G2smoSySw7KU/edit#heading=h.vit0krths7ns)
-* [Scheduling JS timer execution](https://docs.google.com/a/chromium.org/document/d/163ow-1wjd6L0rAN3V_U6t12eqVkq4mXDDjVaA4OuvCA/edit?usp=sharing_eid)
-* [PSA: How to write reliable layout tests](https://docs.google.com/a/chromium.org/document/d/1Yl4SnTLBWmY1O99_BTtQvuoffP8YM9HZx2YPkEsaduQ/edit#heading=h.ui2te0d6ongo)
-* [Long Idle Tasks: Coupling wagons to the Blink Midnight Train](https://docs.google.com/a/chromium.org/document/d/1yBlUdYW8VTIfB-DqhvQqUeP0kf-Ap1W4cao2yQq58Do/edit?pli=1#heading=h.g9y2fheuia8t)
-* [Cooperative scheduling in Javascript](https://docs.google.com/a/chromium.org/document/d/1Jb0DRcIeHHFldlI8wkQJ4uAyTZLzNOvH161VBJUF_Oc/edit#)
-
-## 2014
-
-* [Blink Scheduler talk at BlinkOn 3](https://docs.google.com/presentation/d/1V09Qq08_jOucvOFs-C7P4Hz2Vsswa6imqLxAf7ONomQ/edit#slide=id.p)
-* [Blink Scheduler](https://docs.google.com/a/chromium.org/document/d/11N2WTV3M0IkZ-kQlKWlBcwkOkKTCuLXGVNylK5E2zvc/edit#heading=h.3ay9sj44f0zd)
-* [Blink Scheduler refactoring](https://docs.google.com/a/chromium.org/document/d/16f_RIhZa47uEK_OdtTgzWdRU0RFMTQWMpEWyWXIpXUo/edit#) (moving from Blink to content)
-* [Idle Tasks in the Blink Scheduler](https://docs.google.com/a/chromium.org/document/d/1bXcZ45iCr9NPP6UDbY57RCKgSndgaBt9tSgwxV0sg1o/edit)
-* [Resource loading tasks and the Blink Scheduler](https://docs.google.com/a/chromium.org/document/d/1kLdtb718AEetE64gL-MmM0YRh7kAkxPpWDRa7OI-scI/edit?usp=sharing_eid)
-* [Blink Scheduler friendly HTMLDocumentParser](https://docs.google.com/a/chromium.org/document/d/1Ofil50mhU9IuDkmEdbde18uxquA3WsEdI3vCyYzzDyc/edit#heading=h.fr9ldspsaw6g)
-* [Trustable Future Sync Points](https://docs.google.com/document/d/1qqu8c5Gp1faY-AY4CgER-GKs0w7GXlR5YJ-BaIZ4auo/edit?usp=sharing)
-* [Unified VSync Scheduling](https://docs.google.com/document/d/13xtO-_NSSnNZRRS1Xq3xGNKZawKc8HQxOid5boBUyX8/edit?usp=sharing)
-* [VSync-Aligned Buffered Input](https://docs.google.com/document/d/1L2JTgYMksmXgujKxxhyV45xL8jNhbCh60NQHoueKyS4/edit?usp=sharing)
-* [London Perf Summit - Chrome Scheduling](https://docs.google.com/presentation/d/1I105Uk7nlH_Kj4UaqC7Ygkw3eNuDINQXPtYYSusW8Ho/edit?usp=sharing)
-* [GPU Service Scheduling Latency](https://docs.google.com/document/d/1hjVckIpb9WBE7A9HUxAmutRJEgSkZO_JAFfgwOE-8NE/edit?usp=sharing)
-* Related
- * [Sync Point Shader Arguments](https://docs.google.com/document/d/1GlnjZI0jDNPXZIlhdcU135BGnsP7T3WY0UR4IwjEILU/edit?usp=sharing)
- * [Asynchronous Shader Input from the CPU](https://docs.google.com/document/d/1daXOSiYUHvDcG5dR9OUQWx6rllW127mRcxiVUTK9DdM/edit?usp=sharing)
- * [T-Sync Display Interface](https://docs.google.com/document/d/1ZoH6a-Pxsnh9Xu_2rtF5jss2d352Klpu_23urKghaH0/edit?usp=sharing)
- * [Surfaces](https://docs.google.com/a/chromium.org/document/d/1RxbffpK_GxPtZscXgIEN0N9ZT7IC8BObnbx9ynw92qg/edit?pli=1)
- * [Better Video Frame Scheduling](https://docs.google.com/a/chromium.org/document/d/1xauQd5Tt2MuM82MAwIqIW7IEkVj4VnjWBB-zUODfERQ)
-
-## 2013
-
-* [Synthetic Scheduler Tests](https://docs.google.com/a/chromium.org/document/d/17yhE5Po9By0sCdM1yZT3LiUECaUr_94rQt9j-4tOQIM)
-* [Chrome Frame Synchronization](https://docs.google.com/presentation/d/1q2WU0LusCyQFKDMjOSWLj3xGeOxMWmLzConrC8euJpA/edit?usp=sharing)
-* [Chrome Scheduling Overhaul Phase 1](https://docs.google.com/document/d/1LUFA8MDpJcDHE0_L2EHvrcwqOMJhzl5dqb0AlBSqHOY/edit?usp=sharing)
-* [Chrome Scheduling Overhaul Phase 2](https://docs.google.com/document/d/1VJf2busac85FRQYXhn8hdc-x4yp77JUroTrY-_sj5Ck/edit?usp=sharing)
-* [Improved vsync scheduling for Chrome on Android](https://docs.google.com/a/chromium.org/document/d/16822du6DLKDZ1vQVNWI3gDVYoSqCSezgEmWZ0arvkP8/edit)
-* [ZilCh](https://docs.google.com/document/d/1HmS0YQtWg2ToY67fE8A33PJUyPSwGUwUCLMk_zjK7ik/edit?usp=sharing)
-
-## Miscellaneous
-
-* [Rendering for "Glass Time"](https://docs.google.com/a/google.com/presentation/d/1oKEunkaeiTwznGaIX_yIhe6HPfZBXhtv8r5J5hz52UI/edit#slide=id.g2b8380fec_0129)
-* [Motion Vectors: An interface between Render and Input Systems](http://www.google.com/url?q=http%3A%2F%2Fgo%2Finput-motion-vectors&sa=D&sntz=1&usg=AFQjCNF0sC31c9FLCscR8HtXiz_kP5EaPw)
-* [Begin Frame / VSync Design Diagram](https://docs.google.com/a/chromium.org/drawings/d/1WEj-6A-8FmJNIMbd9hvkvxAuOOTwQvkSjbKR79YCt-c/edit)
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md b/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
new file mode 100644
index 00000000000..f97d2a42f6a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
@@ -0,0 +1,178 @@
+# Task scheduling in Blink
+
+This document provides an overview of task scheduling in Blink and Chrome’s
+renderer process and outlines best practises for posting tasks.
+
+## Overview
+Most of Blink is essentially single-threaded: most important things happen
+on the main thread (including Javascript execution, DOM, CSS, layout calculations),
+which means that there are many things which want to run on the main thread
+at the same time. Therefore Blink needs a scheduling policy to prioritise
+the right thing — for example, to schedule input handling above everything else.
+
+The majority of the scheduling logic deals explicitly with main thread
+scheduling and this document assumes that we are talking about the main thread
+unless stated otherwise. If you don’t need DOM access, please refer to
+[the off main thread scheduling section](#off-main-thread-scheduling)
+to find out how to schedule this type of work.
+
+## Tasks
+
+The main scheduling unit in Blink is a task. A task is a base::Closure posted via
+TaskRunner::PostTask or TaskRunner::PostDelayedTask interface. The regular method of
+creating closures (base::BindOnce/Repeating) [is banned](#binding-tasks).
+Blink should use WTF::Bind (for tasks which are posted to the same thread) and
+WTF::CrossThreadBind
+([for tasks which are posted to a different thread](#off-main-thread-scheduling)).
+
+At the moment Blink Scheduler treats tasks as an atomic unit — if a task has started,
+it can’t be interrupted until it completes. The scheduler can only choose a new task
+to run from the eligible tasks or can elect not to run any task at all.
+
+## Task runners
+
+In order to post a task, a task runner reference is needed. Almost all main
+thread tasks should be associated with a frame to allow the scheduler to freeze
+or prioritise individual frames. This is a hard requirement backed by a DCHECK
+that a task running javascript should have this association
+(which is being introduced).
+
+FrameScheduler::GetTaskRunner (or its aliases LocalFrame::GetTaskRunner,
+WebLocalFrame::GetTaskRunner, RenderFrame::GetTaskRunner or
+ExecutionContext::GetTaskRunner) should be used for that. They return a task runner
+which continues to run tasks after the frame is detached.
+
+
+## Thread-global task runners
+
+Some tasks can’t be associated with a particular frame. One example is garbage
+collection which interacts with all javascript heaps in the isolate. For these use-cases
+a named per-thread task runner should be used:
+- for content/: blink::scheduler::WebThreadScheduler::Current()->SpecificTaskRunner()
+- for blink/: blink::scheduler::ThreadScheduler::Current()->SpecificTaskRunner()
+
+Per-thread task runners include:
+- Compositor task runner
+- GC task runner
+- Cleanup task runner
+- Default (deprecated)
+- Input task runner (semi-deprecated)
+- IPC (semi-deprecated)
+
+New task runners might be added in the future; contact scheduler-dev@chromium.org
+if you think you need a new one.
+
+## ThreadTaskRunnerHandle::Get
+
+base::ThreadTaskRunnerHandle::Get is a way to get a task runner and
+it returns a default task runner for a thread. Because tasks posted to it
+lack any attribution, the scheduler can’t properly schedule and prioritise them.
+
+ThreadTaskRunnerHandle::Get usages are banned in blink/ and content/renderer/
+directories and strongly discouraged elsewhere in the renderer process.
+Please help us to convert them to the appropriate task runner
+(usually per-frame one). See
+[https://docs.google.com/document/d/1k7EEHQUEujgQ7BAhbmNdeaddwfJPWp7qjLy8mnVTQ9Y/edit](this guideline)
+for more details.
+
+
+## Task types and task sources
+
+In addition to frame association, the scheduler also needs to know the nature
+of the task to correctly handle it. blink::TaskType encodes this information.
+TaskType is a required parameter of all GetTaskRunner() methods and FrameScheduler
+returns an appropriate task runner based on the TaskType.
+
+All tasks mentioned in the spec should have task source explicitly defined
+(e.g. see [generic task sources definition](https://html.spec.whatwg.org/multipage/webappapis.html#generic-task-sources)
+in the spec). There are still some places where the task source is not mentioned
+explicitly — reach out to domenic@ and garykac@ for advice.
+
+For the non-speced tasks (for example, clean up caches or record metrics.
+Note that these tasks shouldn’t run javascript), kInternal\* task types should be used.
+
+If you’re happy with the default scheduling policies, which should happen in the
+majority of cases, kInternalDefault task type should be used. Otherwise, reach out to
+scheduler-dev@chromium.org to discuss adding new task type for your needs.
+
+## Scheduling policies
+
+### Priorities
+
+The scheduler selects the next task to run based on the priority
+(modulo some starvation logic). The tasks with the same priority run in order.
+
+There are following rules to assign priorities:
+- Input task runner has the highest priority.
+- Compositor task runner has high priority when user gestures are observed.
+- There are several ongoing experiments to increase or decrease priorities for individual frames.
+
+The default priority is normal.
+
+### Pausing
+
+During synchronous dialogs (alert() or print()) or inside v8 debugger
+breakpoints scheduler enters a nested run loop and stops running pauseable tasks.
+Specifically, no javascript can run when a page is paused.
+
+The pausing is triggered by ScopedPagePauser. Almost all tasks can be paused.
+
+### Deferring
+
+Scheduler may elect not to run some tasks when processing user gestures
+in order to increase responsiveness.
+
+Scheduler defers tasks for two seconds after a user gesture, as it’s very likely
+that another gesture will arrive soon. The majority of tasks can be deferred.
+
+Most of the tasks are deferrable.
+
+### Freezing
+
+Scheduler freezes background pages in order to increase responsiveness of
+the foreground tabs and save power.
+
+On mobile all pages are frozen after five minutes in the background.
+On desktop only eligible pages are frozen, which is determined by heuristics
+based on the APIs page is using.
+
+Most of the tasks are freezable.
+
+### Throttling
+
+Scheduler delays tasks in the background pages and offscreen frames in order
+to improve responsiveness of the foreground pages without breaking
+useful background page functionality.
+
+At the moment only javascript timers (setTimeout/setInterval) are throttleable.
+While there is a general desire to expand this list, this is a low priority effort
+as we are focused on making freezing better instead.
+
+## Off-main thread scheduling
+
+If your task doesn’t have to run on the main thread, use
+BackgroundScheduler::PostOnBackgroundThread, which uses a thread pool
+behind the scenes.
+
+Do not create your own dedicated thread if you need ordering for your tasks,
+use BackgroundScheduler::CreateBackgroundTaskRunnerWithTraits instead —
+this creates a sequence (virtual thread which can run tasks in order on
+any of the threads in the thread pool).
+
+See [threading and tasks](../../../../../docs/threading_and_tasks.md) for
+more details.
+
+## Binding tasks
+
+Many data structures in Blink are bound to a particular thread (e.g. Strings,
+garbage-collected classes, etc), so it’s not safe to pass a pointer to them to
+another thread. To enforce this, base::Bind is banned in Blink and WTF::Bind
+and WTF::CrossThreadBind are provided as alternatives. WTF::Bind should be used
+to post tasks to the same thread and closures returned by it DCHECK that
+they run on the same thread. WTF::CrossThreadBind applies CrossThreadCopier
+to its arguments and creates a deep copy, so the resulting closure can run
+on a different thread.
+
+
+## TODO(altimin): Document idle tasks
+
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/background_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/background_scheduler.cc
index 481d2df4223..0085fd2fa87 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/background_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/background_scheduler.cc
@@ -9,20 +9,22 @@
namespace blink {
-void background_scheduler::PostOnBackgroundThread(
- const base::Location& location,
- CrossThreadClosure closure) {
+namespace background_scheduler {
+
+void PostOnBackgroundThread(const base::Location& location,
+ CrossThreadClosure closure) {
PostOnBackgroundThreadWithTraits(
location, {base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
std::move(closure));
}
-void background_scheduler::PostOnBackgroundThreadWithTraits(
- const base::Location& location,
- const base::TaskTraits& traits,
- CrossThreadClosure closure) {
+void PostOnBackgroundThreadWithTraits(const base::Location& location,
+ const base::TaskTraits& traits,
+ CrossThreadClosure closure) {
base::PostTaskWithTraits(location, traits,
ConvertToBaseCallback(std::move(closure)));
}
+} // namespace background_scheduler
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/features.h b/chromium/third_party/blink/renderer/platform/scheduler/common/features.h
index dd978f3a571..3ab46244c14 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/features.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/features.h
@@ -143,22 +143,6 @@ const base::Feature kThrottleAndFreezeTaskTypes{
extern const char PLATFORM_EXPORT kThrottleableTaskTypesListParam[];
extern const char PLATFORM_EXPORT kFreezableTaskTypesListParam[];
-// https://crbug.com/874836: Experiment-controlled removal of input heuristics.
-// Expensive task blocking as a part of input handling heuristics, so disabling
-// input heuristics implicitly disables expensive task blocking. Expensive task
-// blocking is tested separately as it's less risky. Touchstart and
-// non-touchstart input heuristics are separated because non-touchstart are
-// seen as less ricky.
-const base::Feature kDisableExpensiveTaskBlocking{
- "BlinkSchedulerDisableExpensiveTaskBlocking",
- base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kDisableNonTouchstartInputHeuristics{
- "BlinkSchedulerDisableNonTouchstartInputHeuristics",
- base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kDisableTouchstartInputHeuristics{
- "BlinkSchedulerDisableTouchstartInputHeuristics",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.cc
index 41ab99b37aa..850cc2c4935 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.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 "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "base/bind.h"
@@ -10,10 +10,10 @@ namespace blink {
namespace scheduler {
namespace {
-const int kDelayedTaskSweepIntervalSeconds = 30;
+constexpr const int kReclaimMemoryIntervalSeconds = 30;
}
-IdleCanceledDelayedTaskSweeper::IdleCanceledDelayedTaskSweeper(
+IdleMemoryReclaimer::IdleMemoryReclaimer(
SchedulerHelper* scheduler_helper,
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner)
: scheduler_helper_(scheduler_helper),
@@ -22,17 +22,16 @@ IdleCanceledDelayedTaskSweeper::IdleCanceledDelayedTaskSweeper(
PostIdleTask();
}
-void IdleCanceledDelayedTaskSweeper::PostIdleTask() {
+void IdleMemoryReclaimer::PostIdleTask() {
idle_task_runner_->PostDelayedIdleTask(
- FROM_HERE, base::TimeDelta::FromSeconds(kDelayedTaskSweepIntervalSeconds),
- base::BindOnce(&IdleCanceledDelayedTaskSweeper::SweepIdleTask,
+ FROM_HERE, base::TimeDelta::FromSeconds(kReclaimMemoryIntervalSeconds),
+ base::BindOnce(&IdleMemoryReclaimer::IdleTask,
weak_factory_.GetWeakPtr()));
}
-void IdleCanceledDelayedTaskSweeper::SweepIdleTask(base::TimeTicks deadline) {
- TRACE_EVENT0("renderer.scheduler",
- "IdleCanceledDelayedTaskSweeper::SweepIdleTask");
- scheduler_helper_->SweepCanceledDelayedTasks();
+void IdleMemoryReclaimer::IdleTask(base::TimeTicks deadline) {
+ TRACE_EVENT0("renderer.scheduler", "IdleMemoryReclaimer::IdleTask");
+ scheduler_helper_->ReclaimMemory();
PostIdleTask();
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h
index 8bbe9f69067..6ca1db03217 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_CANCELED_DELAYED_TASK_SWEEPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_CANCELED_DELAYED_TASK_SWEEPER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_MEMORY_RECLAIMER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_MEMORY_RECLAIMER_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -13,26 +13,26 @@
namespace blink {
namespace scheduler {
-// This class periodically sweeps away canceled delayed tasks, which helps
-// reduce memory consumption.
-class PLATFORM_EXPORT IdleCanceledDelayedTaskSweeper {
+// This class periodically sweeps away canceled delayed tasks and considers
+// resizing to fit all internal queues, which helps reduce memory consumption.
+class PLATFORM_EXPORT IdleMemoryReclaimer {
public:
- IdleCanceledDelayedTaskSweeper(
+ IdleMemoryReclaimer(
SchedulerHelper* scheduler_helper,
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner);
private:
void PostIdleTask();
- void SweepIdleTask(base::TimeTicks deadline);
+ void IdleTask(base::TimeTicks deadline);
SchedulerHelper* scheduler_helper_; // NOT OWNED
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
- base::WeakPtrFactory<IdleCanceledDelayedTaskSweeper> weak_factory_;
+ base::WeakPtrFactory<IdleMemoryReclaimer> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(IdleCanceledDelayedTaskSweeper);
+ DISALLOW_COPY_AND_ASSIGN(IdleMemoryReclaimer);
};
} // namespace scheduler
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_CANCELED_DELAYED_TASK_SWEEPER_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_MEMORY_RECLAIMER_H_
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer_unittest.cc
index e167c2831a8..5505e9a6c1d 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer_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 "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "base/task/sequence_manager/lazy_now.h"
#include "base/task/sequence_manager/task_queue.h"
@@ -25,10 +25,10 @@ class TestClass {
base::WeakPtrFactory<TestClass> weak_factory_;
};
-class IdleCanceledDelayedTaskSweeperTest : public testing::Test,
- public IdleHelper::Delegate {
+class IdleMemoryReclaimerTest : public testing::Test,
+ public IdleHelper::Delegate {
public:
- IdleCanceledDelayedTaskSweeperTest()
+ IdleMemoryReclaimerTest()
: task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED),
@@ -47,14 +47,14 @@ class IdleCanceledDelayedTaskSweeperTest : public testing::Test,
MainThreadTaskQueue::QueueCreationParams(
MainThreadTaskQueue::QueueType::kTest)))),
idle_canceled_delayed_taks_sweeper_(
- new IdleCanceledDelayedTaskSweeper(scheduler_helper_.get(),
- idle_helper_->IdleTaskRunner())),
+ new IdleMemoryReclaimer(scheduler_helper_.get(),
+ idle_helper_->IdleTaskRunner())),
default_task_queue_(scheduler_helper_->DefaultMainThreadTaskQueue()) {
// Null clock might trigger some assertions.
task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
}
- ~IdleCanceledDelayedTaskSweeperTest() override = default;
+ ~IdleMemoryReclaimerTest() override = default;
void TearDown() override {
// Check that all tests stop posting tasks.
@@ -77,14 +77,13 @@ class IdleCanceledDelayedTaskSweeperTest : public testing::Test,
std::unique_ptr<MainThreadSchedulerHelper> scheduler_helper_;
std::unique_ptr<IdleHelper> idle_helper_;
- std::unique_ptr<IdleCanceledDelayedTaskSweeper>
- idle_canceled_delayed_taks_sweeper_;
+ std::unique_ptr<IdleMemoryReclaimer> idle_canceled_delayed_taks_sweeper_;
scoped_refptr<base::sequence_manager::TaskQueue> default_task_queue_;
- DISALLOW_COPY_AND_ASSIGN(IdleCanceledDelayedTaskSweeperTest);
+ DISALLOW_COPY_AND_ASSIGN(IdleMemoryReclaimerTest);
};
-TEST_F(IdleCanceledDelayedTaskSweeperTest, TestSweep) {
+TEST_F(IdleMemoryReclaimerTest, TestSweep) {
TestClass class1;
TestClass class2;
@@ -118,7 +117,7 @@ TEST_F(IdleCanceledDelayedTaskSweeperTest, TestSweep) {
// Cancel the last four tasks.
class2.weak_factory_.InvalidateWeakPtrs();
- // Give the IdleCanceledDelayedTaskSweeper a chance to run but don't let
+ // Give the IdleMemoryReclaimer a chance to run but don't let
// the first non canceled delayed task run. This is important because the
// canceled tasks would get removed by TaskQueueImpl::WakeUpForDelayedWork.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(40));
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
index 8e297487d12..2e01f50e2fa 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
@@ -107,10 +107,10 @@ void SchedulerHelper::SetObserver(Observer* observer) {
sequence_manager_->SetObserver(this);
}
-void SchedulerHelper::SweepCanceledDelayedTasks() {
+void SchedulerHelper::ReclaimMemory() {
CheckOnValidThread();
DCHECK(sequence_manager_);
- sequence_manager_->SweepCanceledDelayedTasks();
+ sequence_manager_->ReclaimMemory();
}
TimeDomain* SchedulerHelper::real_time_domain() const {
@@ -173,7 +173,7 @@ double SchedulerHelper::GetSamplingRateForRecordingCPUTime() const {
bool SchedulerHelper::HasCPUTimingForEachTask() const {
if (sequence_manager_) {
return sequence_manager_->GetMetricRecordingSettings()
- .records_cpu_time_for_each_task;
+ .records_cpu_time_for_all_tasks();
}
return false;
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
index 065fce39916..029d60e2695 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
@@ -87,8 +87,9 @@ class PLATFORM_EXPORT SchedulerHelper
// Note |observer| is expected to outlive the SchedulerHelper.
void SetObserver(Observer* observer);
- // Remove all canceled delayed tasks.
- void SweepCanceledDelayedTasks();
+ // Remove all canceled delayed tasks and consider shrinking to fit all
+ // internal queues.
+ void ReclaimMemory();
// Accessor methods.
base::sequence_manager::TimeDomain* real_time_domain() const;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
index 277b1ca3952..0f018531bd6 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
@@ -30,13 +30,6 @@ void ValidateTracingCategory(const char* category) {
} // namespace internal
-void WarmupTracingCategories() {
- // No need to warm-up toplevel category here.
- TRACE_EVENT_WARMUP_CATEGORY(TracingCategoryName::kDefault);
- TRACE_EVENT_WARMUP_CATEGORY(TracingCategoryName::kInfo);
- TRACE_EVENT_WARMUP_CATEGORY(TracingCategoryName::kDebug);
-}
-
std::string PointerToString(const void* pointer) {
return base::StringPrintf(
"0x%" PRIx64,
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
index eb5ceb5f1e3..e35aeb62396 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
@@ -38,8 +38,6 @@ PLATFORM_EXPORT void ValidateTracingCategory(const char* category);
} // namespace internal
-PLATFORM_EXPORT void WarmupTracingCategories();
-
PLATFORM_EXPORT std::string PointerToString(const void* pointer);
PLATFORM_EXPORT double TimeDeltaToMilliseconds(const base::TimeDelta& value);
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
index cf19a8928c3..c0756751ba5 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
@@ -20,16 +20,15 @@ std::unique_ptr<WebThreadScheduler>
WebThreadScheduler::CreateMainThreadScheduler(
std::unique_ptr<base::MessagePump> message_pump,
base::Optional<base::Time> initial_virtual_time) {
- // Ensure categories appear as an option in chrome://tracing.
- WarmupTracingCategories();
- // Workers might be short-lived, so placing warmup here.
- TRACE_EVENT_WARMUP_CATEGORY(TRACE_DISABLED_BY_DEFAULT("worker.scheduler"));
+ auto settings = base::sequence_manager::SequenceManager::Settings{
+ .randomised_sampling_enabled = true};
auto sequence_manager =
message_pump
? base::sequence_manager::
CreateSequenceManagerOnCurrentThreadWithPump(
- base::MessageLoop::TYPE_DEFAULT, std::move(message_pump))
- : base::sequence_manager::CreateSequenceManagerOnCurrentThread();
+ std::move(message_pump), std::move(settings))
+ : base::sequence_manager::CreateSequenceManagerOnCurrentThread(
+ std::move(settings));
std::unique_ptr<MainThreadSchedulerImpl> scheduler(
new MainThreadSchedulerImpl(std::move(sequence_manager),
initial_virtual_time));
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/links.md b/chromium/third_party/blink/renderer/platform/scheduler/links.md
new file mode 100644
index 00000000000..92bedcfcc30
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/scheduler/links.md
@@ -0,0 +1,120 @@
+# Scheduling docs
+
+The following is a collection of scheduling-related documentation about the
+Blink Scheduler as well as other schedulers in Chrome.
+
+## 2018
+* [Browser-side scheduling roadmap](https://docs.google.com/document/d/1yxjka3kyKieEWP6gRlLyXVy72DJ5Gc22Nqp9vehFj14/edit)
+* [Browser UI thread scheduler](https://docs.google.com/document/d/1z1BDq9vzcEpkhN9LSPF5XMnZ0kLJ8mWWkNAi4OI7cos/edit)
+* [Browser IO thread scheduling for input latency](https://docs.google.com/document/d/12waKYiZOOu1DwUJO5faSonq9OwRIJuaP0GavClPTHWY/edit)
+* [Off Main Thread: Scheduling API](https://docs.google.com/document/d/1SGWR1LrrgOUWHNJZU6JfUC89dCMSIXP7TH8RmoWLqyc/edit)
+* [Task traits for sequence scheduling in //content](https://docs.google.com/document/d/1SGy9VTXUwyXEX_yBZ0ukFAnS8B0hDeMUJD-1iALaE-Q/edit)
+* [Stop more task queues in background on Android](https://docs.google.com/document/d/10D2uvOVxBZ2YhcwtK1XOb6CClminPpqAeS82KOVT7hk/edit)
+* [Discussion of more graceful worker shutdown](https://docs.google.com/document/d/11waILCkPehUfML6_defbpkNk4mau6qiK8f7qXtqauwY/edit)
+* [Stop loading in background on Android](https://docs.google.com/document/d/1DEGgG9HfA2ixJpXQDsKbYCJJyHILWz3CQmuNEJr9Xho/edit)
+* [Android startup performance tweaks](https://docs.google.com/document/d/1rGbdF0Rjv0wl7dEQ4kGj2f79Q20MlIv7ch9MSlm2G3M/edit#heading=h.e7o0jj9sx1od)
+* [C++ Promises for Chromium](https://docs.google.com/document/d/1l12PAJgEtlrqTXKiw6mk2cR2jP7FAfCCDr-DGIdiC9w/edit)
+* [C++ Promise/Future/Coroutine in Chromium](https://docs.google.com/document/d/1RThP0a8fTyuYqpPN2zrMxt8Te9M0v3JUv1XhcquBz9E/edit)
+* [Java task scheduling](https://docs.google.com/document/d/1z2ALaVDkfxurPpzDzO9dAAK3dLuLCjYViJijydPoMHs/edit)
+* [Scheduling resource responses with right priority](https://docs.google.com/document/d/18WcfptovabsfE-2Nb4M_x8abVqInr-94fno81E_NcJk/edit)
+* [Refactor EventQueue](https://docs.google.com/document/d/1BBtBPTarOF4NeVKSWZe3XaDHo4yTGhdlqYm35yVzPs4/edit)
+* [Looking into scrolling lag](https://docs.google.com/document/d/1l2e3B6Ad0mqMRqs3_cK8a-o4Po6XMhOgIZt2B5r_ZG0/edit#heading=h.2ef1y98v91gv)
+* [Better scheduling metrics](https://docs.google.com/document/d/1o6QHeY8y6PssEv--Qs6uNeNWrOzTwDyrbTk9iuq2WmY/edit#heading=h.ia9zbay5xpwt)
+* [Scheduler architecture 2.0](https://docs.google.com/document/d/1dk71yTd5fndb5gMSb7wlB2P80hw5ImFxbPao06Ti8EQ/edit#heading=h.7m3oi6qeqhdv)
+* [Task Scheduler - Message Loop integration and migration](https://docs.google.com/document/d/1Vy7kz_9evp6xOFRQBD6M1h4qmk4EEBu0cutipQ3e6kA/edit)
+* [Supporting per-frame priorities in Blink Scheduler](https://docs.google.com/document/d/1-0nNG75hfsg1WhW3Xa4yUNDQdP1D6EJ9r2tl4tmAVJM/edit)
+* [Simplifying scheduler interfaces](https://docs.google.com/document/d/1oz-Rjpn6KhmQvaJF4b674Jofiy3PQQPbyngqFGlYknY/edit)
+* [Using dedicated workers for background work](https://docs.google.com/document/d/1qTYo9ZQwsycJYPAuT5AKw6JYBEsSfJQR823mma3CGvQ/edit)
+* [Untangling spaghetti of platform/scheduler/](https://docs.google.com/document/d/1jxM32tM-djMl7Xzy_tQbVadX1HjQ06fH0x7ofxeeSVc/edit#heading=h.34va28zf1wfu)
+* [Better layering for platform/scheduler/](https://docs.google.com/document/d/1Brt1oSUrL4M_TBSl-KiCbvQt8kYxwnmqsXrmJM00ylA/edit)
+* [Keyed Service scheduling](https://docs.google.com/document/d/1JCvCQvux0DW0X3tyfE_u70Fvpspfn7KDTTdJVD7M524/edit)
+
+
+## 2017
+* [Improved load time scheduling](https://docs.google.com/document/d/1q5uPIKyUP0X7KaQRyxWXmIzMvKF3fx1j6QPCWhjI82o/edit)
+* [Wake-up based throttling](https://docs.google.com/document/d/1A87Ci3_USDyQEdlmXTO1spQxUcR_ML5zqiCsaow4NGM/edit)
+* [Background tabs & offscreen frames](https://docs.google.com/document/d/18_sX-KGRaHcV3xe5Xk_l6NNwXoxm-23IOepgMx4OlE4/edit)
+* [BeginFrame sequence numbers + acknowledgements](https://docs.google.com/document/d/1nxaunQ0cYWxhtS6Zzfwa99nae74F7gxanbuT5JRpI6Y/edit)
+* [Background tab use cases](https://docs.google.com/document/d/16-QGneIkYNbNleoXbdD-mRMYdZAG2JIjMcTVxSC3ZWc/edit)
+* [Activity traits](https://docs.google.com/document/d/1BaJpx08vbPz_1LCj9tehnatZNqh1eLPeE9xoUnWdlW4/edit#heading=h.nwhgpfhlxswr)
+* [Blink and Task Scheduler integration](https://docs.google.com/document/d/1h-FlOeO-27g__JnuRvdJ8KG9G-bmG_zn6zuw7GerFkc/edit)
+* [Lifecycle use cases](https://docs.google.com/document/d/16-QGneIkYNbNleoXbdD-mRMYdZAG2JIjMcTVxSC3ZWc/edit)
+* [Task execution policies in Blink](https://docs.google.com/document/d/1tFI0pkLp1LCFDKRxwT6BSdA-ub8K4cZJLlCaAlqmsvM/edit)
+* [Capturing task type metadata](https://docs.google.com/document/d/1Py2ZdjpaCMdpVtKfdHMITAn5gst_owjQiqlbPm3mCxc/edit)
+* [Further per-frame scheduler work](https://docs.google.com/document/d/1yOhE6-1HLb3aeNWmoa9O2LlnegWjd4awYUn2OhUL4vk/edit)
+* [Better tracing for Blink Scheduler](https://docs.google.com/document/d/18Iz0lVX38_ZIMNoAp4e2RpeIFcCUUU2cghDwy_aLK3k/edit)
+* [Scheduling architecture roadmap: one pager](https://docs.google.com/document/d/13dQAthHRn7bkEgsb7OzG50zhxFFB1rHEDCM7ObXH1_c/edit)
+* [RendererMainThreadLoad metrics](https://docs.google.com/document/d/1MvAadiO3kwSodfOIZ35k2j4oJX-zVY9FsQaSshI-vus/edit#heading=h.r8nzo35yh6ck)
+* [State of the throttling](https://docs.google.com/document/d/1csir1MUkI1maqjAIzhR51LTy1pwSqeh9HDmAPTZWirw/edit)
+* [Background tabs & offscreen frames](https://docs.google.com/document/d/18_sX-KGRaHcV3xe5Xk_l6NNwXoxm-23IOepgMx4OlE4/edit)
+* [Prototyping cooperative scheduling](https://docs.google.com/document/d/1ennqB9cCfko6eg1a6bNoJjaypESjfFvhVup9LSJCyUg/edit)
+* [Cooperative scheduling in Blink](https://docs.google.com/document/d/14WoGZ8pfD4TmOFDebE-WIgkfQ62MnOiyafQI4Zhqjzs/edit)
+
+## 2016
+
+* [Time-based renderer task throttling](https://drive.google.com/open?id=1vCUeGfr2xzZ67SFt2yZjNeaIcXGp2Td6KHN7bI02ySo)
+* [V8 Performance Mode](https://drive.google.com/open?id=1bRVAP08qNBvnEm_vO4hW1-NqQC9-lQZjUH29_vwfYRY)
+* [Isolating performance of third-party iframes](https://docs.google.com/document/d/1CEggurHQGXenhu_GQT7KnRvtSuowuenXpxVzYSeRxSY/edit)
+* [Folly of Scheduling (BlinkOn 6)](https://drive.google.com/open?id=1ZMxbnSn1R1o2-NGztP0mVyOOoQg24bLSqWE1SWXnQ_E)
+* [Rendering pipeline throttling (BlinkOn 6)](https://docs.google.com/presentation/d/1aPZzH7J0O29sqA_FzsuWQNDwK6CoNcAcpMvJexsO6Vg/edit)
+* [Power usage impact of render pipeline throttling](https://docs.google.com/document/d/1jMuvRYWptZfP5zpvWmPJPRL-iowtgBVX45rSvew0VH4)
+* [The future of TaskRunnerHandles](https://docs.google.com/document/d/1A_LRKyTOCzhRPOY4Q3RsePuw4UCsvxuFYx6D18BaYk0/edit#heading=h.xgjl2srtytjt)
+* [Improved policy for blocking expensive tasks](https://docs.google.com/document/d/14VdbqN-ehgpNC4KYVpPQFiQpfxOQiVtJgYjXUJGI4f0/edit#)
+* [scheduler-dev performance metrics](https://docs.google.com/document/d/15CIJ4eMnwOneshhjFxVjz3FCV7ja9lrlQOEZGWLZdgA/edit)
+* [FrameBlamer](https://docs.google.com/document/d/15BB-suCb9j-nFt55yCFJBJCGzLg2qUm3WaSOPb8APtI/edit)
+* [Virtual time in Blink](https://drive.google.com/open?id=1y9KDT_ZEzT7pBeY6uzVt1dgKlwc1OB_vY4NZO1zBQmo)
+* [Browser I/O scheduler (Lucky Luke)](https://docs.google.com/document/d/1S2AAeoo1xa_vsLbDYBsDHCqhrkfiMgoIPlyRi6kxa5k/edit)
+
+## 2015
+
+* [Virtual time in Headless Chrome](https://docs.google.com/document/d/1dIMHIl1xutUXqXWRXqXrDd3bo9hachIt_ZkPK_BshUs/edit)
+* [Task traits](https://docs.google.com/document/d/1d6t7CTobtXLj1gXiBE8SVl_fxJjEazATxYHYGp5ppvE)
+* [Compositor and Display Scheduling presentation from scheduling summit](https://docs.google.com/presentation/d/1FpTy5DpIGKt8r2t785y6yrHETkg8v7JfJ26zUxaNDUg/edit?usp=sharing)
+* [Simplifying Task Management in Chromium](https://docs.google.com/document/d/1fn0AmFsY7gWvStShOh7dUxOfHXjKgcfsr9I1ETbNe2I/edit)
+* [Outline of known work needed to fix resize](https://docs.google.com/a/chromium.org/document/d/1POLDq-L_T9iZ_Ul39sjOMiOO-yvLnmb1WFsH4JfIyVU/edit?usp=sharing_eid)
+* [Blink spatial scheduling](https://docs.google.com/document/d/1k9fL01wwRliVzZW_ibPT8-B9BADz7I87hpFoXFG37aI/edit?pli=1#)
+* [Throttling Blink's rendering pipeline for hidden content](https://docs.google.com/document/d/1Dd4qi1b_iX-OCZpelvXxizjq6dDJ76XNtk37SZEoTYQ/edit)
+* [Scheduling to avoid checkerboard in Chrome](https://docs.google.com/document/d/1OLp7x06CjBY-0J3TBQzXw8sALHznIx4rYixvnBTbUUA/edit#heading=h.9i2v5u7um22b)
+* [State of GPU scheduling](https://docs.google.com/document/d/15gbHgXPyhSlNu1Ku9HF-of8BNOpvsziV1F8IE-kRax4/edit#heading=h.jermw4ib9rwc)
+* [Scheduling architecture diagram](https://docs.google.com/drawings/d/1xcHpqhdcIsX0b_sGPuU1SZCsY87UTqJ67qvvbF29oLM/edit)
+* [Event dispatch diagram](https://docs.google.com/drawings/d/1bUukRm-DV34sM7rL2_bSdxaQkZVMQ_5vOa7nzDnmnx8/edit)
+* [Proxying MessageLoop tasks to the Scheduler](https://docs.google.com/a/chromium.org/document/d/1qxdh2I61_aB_Uzh1QgNqvdWFBCL_E65G2smoSySw7KU/edit#heading=h.vit0krths7ns)
+* [Scheduling JS timer execution](https://docs.google.com/a/chromium.org/document/d/163ow-1wjd6L0rAN3V_U6t12eqVkq4mXDDjVaA4OuvCA/edit?usp=sharing_eid)
+* [PSA: How to write reliable layout tests](https://docs.google.com/a/chromium.org/document/d/1Yl4SnTLBWmY1O99_BTtQvuoffP8YM9HZx2YPkEsaduQ/edit#heading=h.ui2te0d6ongo)
+* [Long Idle Tasks: Coupling wagons to the Blink Midnight Train](https://docs.google.com/a/chromium.org/document/d/1yBlUdYW8VTIfB-DqhvQqUeP0kf-Ap1W4cao2yQq58Do/edit?pli=1#heading=h.g9y2fheuia8t)
+* [Cooperative scheduling in Javascript](https://docs.google.com/a/chromium.org/document/d/1Jb0DRcIeHHFldlI8wkQJ4uAyTZLzNOvH161VBJUF_Oc/edit#)
+
+## 2014
+
+* [Blink Scheduler talk at BlinkOn 3](https://docs.google.com/presentation/d/1V09Qq08_jOucvOFs-C7P4Hz2Vsswa6imqLxAf7ONomQ/edit#slide=id.p)
+* [Blink Scheduler](https://docs.google.com/a/chromium.org/document/d/11N2WTV3M0IkZ-kQlKWlBcwkOkKTCuLXGVNylK5E2zvc/edit#heading=h.3ay9sj44f0zd)
+* [Blink Scheduler refactoring](https://docs.google.com/a/chromium.org/document/d/16f_RIhZa47uEK_OdtTgzWdRU0RFMTQWMpEWyWXIpXUo/edit#) (moving from Blink to content)
+* [Idle Tasks in the Blink Scheduler](https://docs.google.com/a/chromium.org/document/d/1bXcZ45iCr9NPP6UDbY57RCKgSndgaBt9tSgwxV0sg1o/edit)
+* [Resource loading tasks and the Blink Scheduler](https://docs.google.com/a/chromium.org/document/d/1kLdtb718AEetE64gL-MmM0YRh7kAkxPpWDRa7OI-scI/edit?usp=sharing_eid)
+* [Blink Scheduler friendly HTMLDocumentParser](https://docs.google.com/a/chromium.org/document/d/1Ofil50mhU9IuDkmEdbde18uxquA3WsEdI3vCyYzzDyc/edit#heading=h.fr9ldspsaw6g)
+* [Trustable Future Sync Points](https://docs.google.com/document/d/1qqu8c5Gp1faY-AY4CgER-GKs0w7GXlR5YJ-BaIZ4auo/edit?usp=sharing)
+* [Unified VSync Scheduling](https://docs.google.com/document/d/13xtO-_NSSnNZRRS1Xq3xGNKZawKc8HQxOid5boBUyX8/edit?usp=sharing)
+* [VSync-Aligned Buffered Input](https://docs.google.com/document/d/1L2JTgYMksmXgujKxxhyV45xL8jNhbCh60NQHoueKyS4/edit?usp=sharing)
+* [London Perf Summit - Chrome Scheduling](https://docs.google.com/presentation/d/1I105Uk7nlH_Kj4UaqC7Ygkw3eNuDINQXPtYYSusW8Ho/edit?usp=sharing)
+* [GPU Service Scheduling Latency](https://docs.google.com/document/d/1hjVckIpb9WBE7A9HUxAmutRJEgSkZO_JAFfgwOE-8NE/edit?usp=sharing)
+* Related
+ * [Sync Point Shader Arguments](https://docs.google.com/document/d/1GlnjZI0jDNPXZIlhdcU135BGnsP7T3WY0UR4IwjEILU/edit?usp=sharing)
+ * [Asynchronous Shader Input from the CPU](https://docs.google.com/document/d/1daXOSiYUHvDcG5dR9OUQWx6rllW127mRcxiVUTK9DdM/edit?usp=sharing)
+ * [T-Sync Display Interface](https://docs.google.com/document/d/1ZoH6a-Pxsnh9Xu_2rtF5jss2d352Klpu_23urKghaH0/edit?usp=sharing)
+ * [Surfaces](https://docs.google.com/a/chromium.org/document/d/1RxbffpK_GxPtZscXgIEN0N9ZT7IC8BObnbx9ynw92qg/edit?pli=1)
+ * [Better Video Frame Scheduling](https://docs.google.com/a/chromium.org/document/d/1xauQd5Tt2MuM82MAwIqIW7IEkVj4VnjWBB-zUODfERQ)
+
+## 2013
+
+* [Synthetic Scheduler Tests](https://docs.google.com/a/chromium.org/document/d/17yhE5Po9By0sCdM1yZT3LiUECaUr_94rQt9j-4tOQIM)
+* [Chrome Frame Synchronization](https://docs.google.com/presentation/d/1q2WU0LusCyQFKDMjOSWLj3xGeOxMWmLzConrC8euJpA/edit?usp=sharing)
+* [Chrome Scheduling Overhaul Phase 1](https://docs.google.com/document/d/1LUFA8MDpJcDHE0_L2EHvrcwqOMJhzl5dqb0AlBSqHOY/edit?usp=sharing)
+* [Chrome Scheduling Overhaul Phase 2](https://docs.google.com/document/d/1VJf2busac85FRQYXhn8hdc-x4yp77JUroTrY-_sj5Ck/edit?usp=sharing)
+* [Improved vsync scheduling for Chrome on Android](https://docs.google.com/a/chromium.org/document/d/16822du6DLKDZ1vQVNWI3gDVYoSqCSezgEmWZ0arvkP8/edit)
+* [ZilCh](https://docs.google.com/document/d/1HmS0YQtWg2ToY67fE8A33PJUyPSwGUwUCLMk_zjK7ik/edit?usp=sharing)
+
+## Miscellaneous
+
+* [Rendering for "Glass Time"](https://docs.google.com/a/google.com/presentation/d/1oKEunkaeiTwznGaIX_yIhe6HPfZBXhtv8r5J5hz52UI/edit#slide=id.g2b8380fec_0129)
+* [Motion Vectors: An interface between Render and Input Systems](http://www.google.com/url?q=http%3A%2F%2Fgo%2Finput-motion-vectors&sa=D&sntz=1&usg=AFQjCNF0sC31c9FLCscR8HtXiz_kP5EaPw)
+* [Begin Frame / VSync Design Diagram](https://docs.google.com/a/chromium.org/drawings/d/1WEj-6A-8FmJNIMbd9hvkvxAuOOTwQvkSjbKR79YCt-c/edit)
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index fe2a37facc5..5c2bc181f52 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -400,6 +400,10 @@ base::Optional<QueueTraits> FrameSchedulerImpl::CreateQueueTraitsForTaskType(
case TaskType::kNetworkingControl:
// Loading task queues are handled separately.
return base::nullopt;
+ case TaskType::kExperimentalWebSchedulingUserInteraction:
+ case TaskType::kExperimentalWebSchedulingBestEffort:
+ // WebScheduling queues are handled separately.
+ return base::nullopt;
// Throttling following tasks may break existing web pages, so tentatively
// these are unthrottled.
// TODO(nhiroki): Throttle them again after we're convinced that it's safe
@@ -422,6 +426,10 @@ base::Optional<QueueTraits> FrameSchedulerImpl::CreateQueueTraitsForTaskType(
case TaskType::kIdleTask:
case TaskType::kInternalDefault:
case TaskType::kMiscPlatformAPI:
+ case TaskType::kFontLoading:
+ case TaskType::kApplicationLifeCycle:
+ case TaskType::kBackgroundFetch:
+ case TaskType::kPermission:
// TODO(altimin): Move appropriate tasks to throttleable task queue.
return DeferrableTaskQueueTraits();
// PostedMessage can be used for navigation, so we shouldn't defer it
@@ -468,8 +476,6 @@ base::Optional<QueueTraits> FrameSchedulerImpl::CreateQueueTraitsForTaskType(
case TaskType::kWorkerThreadTaskQueueDefault:
case TaskType::kWorkerThreadTaskQueueV8:
case TaskType::kWorkerThreadTaskQueueCompositor:
- case TaskType::kExperimentalWebSchedulingUserInteraction:
- case TaskType::kExperimentalWebSchedulingBestEffort:
case TaskType::kCount:
// Not a valid frame-level TaskType.
return base::nullopt;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 2057cb35313..07ceb23933b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -47,14 +47,6 @@ using base::sequence_manager::TaskTimeObserver;
using base::sequence_manager::TimeDomain;
namespace {
-// The run time of loading tasks is strongly bimodal. The vast majority are
-// very cheap, but there are usually a handful of very expensive tasks (e.g ~1
-// second on a mobile device) so we take a very pessimistic view when estimating
-// the cost of loading tasks.
-const int kLoadingTaskEstimationSampleCount = 1000;
-const double kLoadingTaskEstimationPercentile = 99;
-const int kTimerTaskEstimationSampleCount = 1000;
-const double kTimerTaskEstimationPercentile = 99;
const int kShortIdlePeriodDurationSampleCount = 10;
const double kShortIdlePeriodDurationPercentile = 50;
// Amount of idle time left in a frame (as a ratio of the vsync interval) above
@@ -189,8 +181,7 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl(
MainThreadTaskQueue::QueueType::kIdle)
.SetFixedPriority(
TaskQueue::QueuePriority::kBestEffortPriority))),
- idle_canceled_delayed_task_sweeper_(&helper_,
- idle_helper_.IdleTaskRunner()),
+ idle_memory_reclaimer_(&helper_, idle_helper_.IdleTaskRunner()),
render_widget_scheduler_signals_(this),
control_task_queue_(helper_.ControlMainThreadTaskQueue()),
compositor_task_queue_(
@@ -298,21 +289,6 @@ MainThreadSchedulerImpl::~MainThreadSchedulerImpl() {
this);
for (auto& pair : task_runners_) {
- TaskCostEstimator* observer = nullptr;
- switch (pair.first->queue_class()) {
- case MainThreadTaskQueue::QueueClass::kLoading:
- observer = &main_thread_only().loading_task_cost_estimator;
- break;
- case MainThreadTaskQueue::QueueClass::kTimer:
- observer = &main_thread_only().timer_task_cost_estimator;
- break;
- default:
- observer = nullptr;
- }
-
- if (observer)
- pair.first->RemoveTaskObserver(observer);
-
pair.first->ShutdownTaskQueue();
}
@@ -336,13 +312,7 @@ MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
const base::TickClock* time_source,
base::TimeTicks now)
- : loading_task_cost_estimator(time_source,
- kLoadingTaskEstimationSampleCount,
- kLoadingTaskEstimationPercentile),
- timer_task_cost_estimator(time_source,
- kTimerTaskEstimationSampleCount,
- kTimerTaskEstimationPercentile),
- idle_time_estimator(compositor_task_runner,
+ : idle_time_estimator(compositor_task_runner,
time_source,
kShortIdlePeriodDurationSampleCount,
kShortIdlePeriodDurationPercentile),
@@ -361,11 +331,6 @@ MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
"Scheduler.PauseCount",
main_thread_scheduler_impl,
&main_thread_scheduler_impl->tracing_controller_),
- expensive_task_policy(ExpensiveTaskPolicy::kRun,
- "Scheduler.ExpensiveTaskPolicy",
- main_thread_scheduler_impl,
- &main_thread_scheduler_impl->tracing_controller_,
- ExpensiveTaskPolicyToString),
rail_mode_for_tracing(current_policy.rail_mode(),
"Scheduler.RAILMode",
main_thread_scheduler_impl,
@@ -387,30 +352,6 @@ MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
main_thread_scheduler_impl,
&main_thread_scheduler_impl->tracing_controller_,
YesNoStateToString),
- loading_task_estimated_cost(
- base::TimeDelta(),
- "Scheduler.LoadingTaskEstimatedCostMs",
- main_thread_scheduler_impl,
- &main_thread_scheduler_impl->tracing_controller_,
- TimeDeltaToMilliseconds),
- timer_task_estimated_cost(
- base::TimeDelta(),
- "Scheduler.TimerTaskEstimatedCostMs",
- main_thread_scheduler_impl,
- &main_thread_scheduler_impl->tracing_controller_,
- TimeDeltaToMilliseconds),
- loading_tasks_seem_expensive(
- false,
- "Scheduler.LoadingTasksSeemExpensive",
- main_thread_scheduler_impl,
- &main_thread_scheduler_impl->tracing_controller_,
- YesNoStateToString),
- timer_tasks_seem_expensive(
- false,
- "Scheduler.TimerTasksSeemExpensive",
- main_thread_scheduler_impl,
- &main_thread_scheduler_impl->tracing_controller_,
- YesNoStateToString),
blocking_input_expected_soon(
false,
"Scheduler.BlockingInputExpectedSoon",
@@ -618,13 +559,6 @@ MainThreadSchedulerImpl::SchedulingSettings::SchedulingSettings() {
FrameSchedulerImpl::InitializeTaskTypeQueueTraitsMap(
frame_task_types_to_queue_traits);
-
- disable_expensive_task_blocking =
- base::FeatureList::IsEnabled(kDisableExpensiveTaskBlocking);
- disable_non_touchstart_input_heuristics =
- base::FeatureList::IsEnabled(kDisableNonTouchstartInputHeuristics);
- disable_touchstart_input_heuristics =
- base::FeatureList::IsEnabled(kDisableTouchstartInputHeuristics);
}
MainThreadSchedulerImpl::AnyThread::~AnyThread() = default;
@@ -743,12 +677,6 @@ scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue(
auto insert_result =
task_runners_.insert(std::make_pair(task_queue, std::move(voter)));
auto queue_class = task_queue->queue_class();
- if (queue_class == MainThreadTaskQueue::QueueClass::kTimer) {
- task_queue->AddTaskObserver(&main_thread_only().timer_task_cost_estimator);
- } else if (queue_class == MainThreadTaskQueue::QueueClass::kLoading) {
- task_queue->AddTaskObserver(
- &main_thread_only().loading_task_cost_estimator);
- }
ApplyTaskQueuePolicy(
task_queue.get(), insert_result.first->second.get(), TaskQueuePolicy(),
@@ -809,20 +737,7 @@ void MainThreadSchedulerImpl::OnShutdownTaskQueue(
if (task_queue_throttler_)
task_queue_throttler_->ShutdownTaskQueue(task_queue.get());
- if (task_runners_.erase(task_queue)) {
- switch (task_queue->queue_class()) {
- case MainThreadTaskQueue::QueueClass::kTimer:
- task_queue->RemoveTaskObserver(
- &main_thread_only().timer_task_cost_estimator);
- break;
- case MainThreadTaskQueue::QueueClass::kLoading:
- task_queue->RemoveTaskObserver(
- &main_thread_only().loading_task_cost_estimator);
- break;
- default:
- break;
- }
- }
+ task_runners_.erase(task_queue.get());
}
bool MainThreadSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
@@ -1409,22 +1324,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
main_thread_only().longest_jank_free_task_duration =
longest_jank_free_task_duration;
- main_thread_only().loading_task_estimated_cost =
- main_thread_only().loading_task_cost_estimator.expected_task_duration();
- bool loading_tasks_seem_expensive =
- main_thread_only().loading_task_estimated_cost >
- longest_jank_free_task_duration;
-
- main_thread_only().timer_task_estimated_cost =
- main_thread_only().timer_task_cost_estimator.expected_task_duration();
- bool timer_tasks_seem_expensive =
- main_thread_only().timer_task_estimated_cost >
- longest_jank_free_task_duration;
-
- main_thread_only().timer_tasks_seem_expensive = timer_tasks_seem_expensive;
- main_thread_only().loading_tasks_seem_expensive =
- loading_tasks_seem_expensive;
-
// The |new_policy_duration| is the minimum of |expected_use_case_duration|
// and |gesture_expected_flag_valid_for_duration| unless one is zero in
// which case we choose the other.
@@ -1453,7 +1352,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
kFastCompositingIdleTimeThreshold;
Policy new_policy;
- ExpensiveTaskPolicy expensive_task_policy = ExpensiveTaskPolicy::kRun;
new_policy.rail_mode() = v8::PERFORMANCE_ANIMATION;
new_policy.use_case() = main_thread_only().current_use_case;
@@ -1461,7 +1359,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
case UseCase::kCompositorGesture:
if (main_thread_only().blocking_input_expected_soon) {
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::kBlock;
new_policy.compositor_priority() =
TaskQueue::QueuePriority::kHighestPriority;
} else {
@@ -1478,12 +1375,8 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
new_policy.compositor_priority() = main_thread_compositing_is_fast
? TaskQueue::kHighestPriority
: TaskQueue::kNormalPriority;
- if (main_thread_only().blocking_input_expected_soon) {
+ if (main_thread_only().blocking_input_expected_soon)
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::kBlock;
- } else {
- expensive_task_policy = ExpensiveTaskPolicy::kThrottle;
- }
break;
case UseCase::kMainThreadCustomInputHandling:
@@ -1504,12 +1397,8 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
// handling over other tasks.
new_policy.compositor_priority() =
TaskQueue::QueuePriority::kHighestPriority;
- if (main_thread_only().blocking_input_expected_soon) {
+ if (main_thread_only().blocking_input_expected_soon)
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::kBlock;
- } else {
- expensive_task_policy = ExpensiveTaskPolicy::kThrottle;
- }
break;
case UseCase::kTouchstart:
@@ -1518,8 +1407,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
new_policy.loading_queue_policy().is_deferred = true;
new_policy.timer_queue_policy().is_deferred = true;
- // NOTE this is a nop due to the above.
- expensive_task_policy = ExpensiveTaskPolicy::kBlock;
break;
case UseCase::kNone:
@@ -1528,7 +1415,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
if (main_thread_only().blocking_input_expected_soon &&
any_thread().last_gesture_was_compositor_driven) {
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::kBlock;
}
break;
@@ -1546,36 +1432,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
if (main_thread_only().renderer_hidden)
new_policy.rail_mode() = v8::PERFORMANCE_IDLE;
- if (expensive_task_policy == ExpensiveTaskPolicy::kBlock &&
- !main_thread_only().have_seen_a_begin_main_frame) {
- expensive_task_policy = ExpensiveTaskPolicy::kRun;
- }
-
- if (scheduling_settings().disable_expensive_task_blocking)
- expensive_task_policy = ExpensiveTaskPolicy::kRun;
-
- switch (expensive_task_policy) {
- case ExpensiveTaskPolicy::kRun:
- break;
-
- case ExpensiveTaskPolicy::kBlock:
- if (loading_tasks_seem_expensive)
- new_policy.loading_queue_policy().is_deferred = true;
- if (timer_tasks_seem_expensive)
- new_policy.timer_queue_policy().is_deferred = true;
- break;
-
- case ExpensiveTaskPolicy::kThrottle:
- if (loading_tasks_seem_expensive) {
- new_policy.loading_queue_policy().is_throttled = true;
- }
- if (timer_tasks_seem_expensive) {
- new_policy.timer_queue_policy().is_throttled = true;
- }
- break;
- }
- main_thread_only().expensive_task_policy = expensive_task_policy;
-
if (main_thread_only().renderer_pause_count != 0) {
new_policy.loading_queue_policy().is_paused = true;
new_policy.timer_queue_policy().is_paused = true;
@@ -1584,11 +1440,6 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
new_policy.timer_queue_policy().is_paused = true;
}
- if (main_thread_only().renderer_backgrounded &&
- RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled()) {
- new_policy.timer_queue_policy().is_throttled = true;
- }
-
if (main_thread_only().use_virtual_time) {
new_policy.compositor_queue_policy().use_virtual_time = true;
new_policy.default_queue_policy().use_virtual_time = true;
@@ -1674,11 +1525,6 @@ void MainThreadSchedulerImpl::ApplyTaskQueuePolicy(
new_task_queue_policy.GetTimeDomainType(task_queue);
if (old_time_domain_type != new_time_domain_type) {
- if (old_time_domain_type == TimeDomainType::kThrottled) {
- task_queue_throttler_->DecreaseThrottleRefCount(task_queue);
- } else if (new_time_domain_type == TimeDomainType::kThrottled) {
- task_queue_throttler_->IncreaseThrottleRefCount(task_queue);
- }
if (new_time_domain_type == TimeDomainType::kVirtual) {
DCHECK(virtual_time_domain_);
task_queue->SetTimeDomain(virtual_time_domain_.get());
@@ -1695,8 +1541,7 @@ UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
// Special case for flings. This is needed because we don't get notification
// of a fling ending (although we do for cancellation).
if (any_thread().fling_compositor_escalation_deadline > now &&
- !any_thread().awaiting_touch_start_response &&
- !scheduling_settings().disable_non_touchstart_input_heuristics) {
+ !any_thread().awaiting_touch_start_response) {
*expected_use_case_duration =
any_thread().fling_compositor_escalation_deadline - now;
return UseCase::kCompositorGesture;
@@ -1706,8 +1551,7 @@ UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
any_thread().user_model.TimeLeftInUserGesture(now);
if (*expected_use_case_duration > base::TimeDelta()) {
// Has a gesture been fully established?
- if (any_thread().awaiting_touch_start_response &&
- !scheduling_settings().disable_touchstart_input_heuristics) {
+ if (any_thread().awaiting_touch_start_response) {
// No, so arrange for compositor tasks to be run at the highest priority.
return UseCase::kTouchstart;
}
@@ -1722,20 +1566,18 @@ UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
// stream of input events and has prevented a default gesture from being
// started.
// 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads.
- if (!scheduling_settings().disable_non_touchstart_input_heuristics) {
- if (any_thread().last_gesture_was_compositor_driven) {
- if (any_thread().begin_main_frame_on_critical_path) {
- return UseCase::kSynchronizedGesture;
- } else {
- return UseCase::kCompositorGesture;
- }
- }
- if (any_thread().default_gesture_prevented) {
- return UseCase::kMainThreadCustomInputHandling;
+ if (any_thread().last_gesture_was_compositor_driven) {
+ if (any_thread().begin_main_frame_on_critical_path) {
+ return UseCase::kSynchronizedGesture;
} else {
- return UseCase::kMainThreadGesture;
+ return UseCase::kCompositorGesture;
}
}
+ if (any_thread().default_gesture_prevented) {
+ return UseCase::kMainThreadCustomInputHandling;
+ } else {
+ return UseCase::kMainThreadGesture;
+ }
}
// Occasionally the meaningful paint fails to be detected, so as a fallback we
@@ -1795,16 +1637,6 @@ MainThreadSchedulerImpl::GetSchedulerHelperForTesting() {
return &helper_;
}
-TaskCostEstimator*
-MainThreadSchedulerImpl::GetLoadingTaskCostEstimatorForTesting() {
- return &main_thread_only().loading_task_cost_estimator;
-}
-
-TaskCostEstimator*
-MainThreadSchedulerImpl::GetTimerTaskCostEstimatorForTesting() {
- return &main_thread_only().timer_task_cost_estimator;
-}
-
IdleTimeEstimator* MainThreadSchedulerImpl::GetIdleTimeEstimatorForTesting() {
return &main_thread_only().idle_time_estimator;
}
@@ -2046,22 +1878,6 @@ void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshotLocked() const {
"MainThreadScheduler", this, AsValueLocked(helper_.NowTicks()));
}
-// static
-const char* MainThreadSchedulerImpl::ExpensiveTaskPolicyToString(
- ExpensiveTaskPolicy expensive_task_policy) {
- switch (expensive_task_policy) {
- case ExpensiveTaskPolicy::kRun:
- return "run";
- case ExpensiveTaskPolicy::kBlock:
- return "block";
- case ExpensiveTaskPolicy::kThrottle:
- return "throttle";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
helper_.CheckOnValidThread();
@@ -2076,10 +1892,6 @@ MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
main_thread_only().has_visible_render_widget_with_touch_handler);
state->SetString("current_use_case",
UseCaseToString(main_thread_only().current_use_case));
- state->SetBoolean("loading_tasks_seem_expensive",
- main_thread_only().loading_tasks_seem_expensive);
- state->SetBoolean("timer_tasks_seem_expensive",
- main_thread_only().timer_tasks_seem_expensive);
state->SetBoolean("begin_frame_not_expected_soon",
main_thread_only().begin_frame_not_expected_soon);
state->SetBoolean(
@@ -2123,14 +1935,6 @@ MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
any_thread().last_gesture_was_compositor_driven);
state->SetBoolean("default_gesture_prevented",
any_thread().default_gesture_prevented);
- state->SetDouble("expected_loading_task_duration",
- main_thread_only()
- .loading_task_cost_estimator.expected_task_duration()
- .InMillisecondsF());
- state->SetDouble("expected_timer_task_duration",
- main_thread_only()
- .timer_task_cost_estimator.expected_task_duration()
- .InMillisecondsF());
state->SetBoolean("is_audio_playing", main_thread_only().is_audio_playing);
state->SetBoolean("virtual_time_stopped",
main_thread_only().virtual_time_stopped);
@@ -2166,10 +1970,6 @@ MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
.InMillisecondsF());
state->SetBoolean("in_idle_period", any_thread().in_idle_period);
- state->SetString(
- "expensive_task_policy",
- ExpensiveTaskPolicyToString(main_thread_only().expensive_task_policy));
-
any_thread().user_model.AsValueInto(state.get());
render_widget_scheduler_signals_.AsValueInto(state.get());
@@ -2196,8 +1996,6 @@ MainThreadSchedulerImpl::TaskQueuePolicy::GetTimeDomainType(
MainThreadTaskQueue* task_queue) const {
if (use_virtual_time)
return TimeDomainType::kVirtual;
- if (is_throttled && task_queue->CanBeThrottled())
- return TimeDomainType::kThrottled;
return TimeDomainType::kReal;
}
@@ -2205,7 +2003,6 @@ void MainThreadSchedulerImpl::TaskQueuePolicy::AsValueInto(
base::trace_event::TracedValue* state) const {
state->SetBoolean("is_enabled", is_enabled);
state->SetBoolean("is_paused", is_paused);
- state->SetBoolean("is_throttled", is_throttled);
state->SetBoolean("is_deferred", is_deferred);
state->SetBoolean("use_virtual_time", use_virtual_time);
}
@@ -2340,8 +2137,6 @@ void MainThreadSchedulerImpl::ResetForNavigationLocked() {
any_thread().have_seen_a_blocking_gesture = false;
any_thread().waiting_for_meaningful_paint = true;
any_thread().have_seen_input_since_navigation = false;
- main_thread_only().loading_task_cost_estimator.Clear();
- main_thread_only().timer_task_cost_estimator.Clear();
main_thread_only().idle_time_estimator.Clear();
main_thread_only().have_seen_a_begin_main_frame = false;
main_thread_only().have_reported_blocking_intervention_since_navigation =
@@ -2867,8 +2662,6 @@ const char* MainThreadSchedulerImpl::TimeDomainTypeToString(
switch (domain_type) {
case TimeDomainType::kReal:
return "real";
- case TimeDomainType::kThrottled:
- return "throttled";
case TimeDomainType::kVirtual:
return "virtual";
default:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index d63270a982a..ee86d058773 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -26,8 +26,8 @@
#include "build/build_config.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h"
#include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
@@ -41,7 +41,6 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/user_model.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
@@ -132,10 +131,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
// entries. This is initialized early with all valid entries. Entries that
// aren't valid task types, i.e. non-frame level, are base::nullopt.
FrameTaskTypeToQueueTraitsArray frame_task_types_to_queue_traits;
-
- bool disable_expensive_task_blocking;
- bool disable_non_touchstart_input_heuristics;
- bool disable_touchstart_input_heuristics;
};
static const char* UseCaseToString(UseCase use_case);
@@ -338,8 +333,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
// Test helpers.
MainThreadSchedulerHelper* GetSchedulerHelperForTesting();
- TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting();
- TaskCostEstimator* GetTimerTaskCostEstimatorForTesting();
IdleTimeEstimator* GetIdleTimeEstimatorForTesting();
base::TimeTicks CurrentIdleTaskDeadlineForTesting() const;
void RunIdleTasksForTesting(base::OnceClosure callback);
@@ -422,11 +415,8 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
main_thread_scheduler_impl_unittest::MainThreadSchedulerImplTest,
Tracing);
- enum class ExpensiveTaskPolicy { kRun, kBlock, kThrottle };
-
enum class TimeDomainType {
kReal,
- kThrottled,
kVirtual,
};
@@ -440,13 +430,11 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
TaskQueuePolicy()
: is_enabled(true),
is_paused(false),
- is_throttled(false),
is_deferred(false),
use_virtual_time(false) {}
bool is_enabled;
bool is_paused;
- bool is_throttled;
bool is_deferred;
bool use_virtual_time;
@@ -456,7 +444,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
bool operator==(const TaskQueuePolicy& other) const {
return is_enabled == other.is_enabled && is_paused == other.is_paused &&
- is_throttled == other.is_throttled &&
is_deferred == other.is_deferred &&
use_virtual_time == other.use_virtual_time;
}
@@ -695,9 +682,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
const TaskQueuePolicy& old_task_queue_policy,
const TaskQueuePolicy& new_task_queue_policy) const;
- static const char* ExpensiveTaskPolicyToString(
- ExpensiveTaskPolicy expensive_task_policy);
-
void AddQueueToWakeUpBudgetPool(MainThreadTaskQueue* queue);
void PauseRendererImpl();
@@ -762,7 +746,7 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
MainThreadSchedulerHelper helper_;
IdleHelper idle_helper_;
- IdleCanceledDelayedTaskSweeper idle_canceled_delayed_task_sweeper_;
+ IdleMemoryReclaimer idle_memory_reclaimer_;
std::unique_ptr<TaskQueueThrottler> task_queue_throttler_;
RenderWidgetSignals render_widget_scheduler_signals_;
@@ -812,8 +796,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
base::TimeTicks now);
~MainThreadOnly();
- TaskCostEstimator loading_task_cost_estimator;
- TaskCostEstimator timer_task_cost_estimator;
IdleTimeEstimator idle_time_estimator;
TraceableState<UseCase, TracingCategoryName::kDefault> current_use_case;
Policy current_policy;
@@ -825,21 +807,12 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
longest_jank_free_task_duration;
TraceableCounter<int, TracingCategoryName::kInfo>
renderer_pause_count; // Renderer is paused if non-zero.
- TraceableState<ExpensiveTaskPolicy, TracingCategoryName::kInfo>
- expensive_task_policy;
TraceableState<v8::RAILMode, TracingCategoryName::kInfo>
rail_mode_for_tracing; // Don't use except for tracing.
TraceableState<bool, TracingCategoryName::kDebug> renderer_hidden;
TraceableState<bool, TracingCategoryName::kTopLevel> renderer_backgrounded;
TraceableState<bool, TracingCategoryName::kDefault>
keep_active_fetch_or_worker;
- TraceableCounter<base::TimeDelta, TracingCategoryName::kInfo>
- loading_task_estimated_cost;
- TraceableCounter<base::TimeDelta, TracingCategoryName::kInfo>
- timer_task_estimated_cost;
- TraceableState<bool, TracingCategoryName::kInfo>
- loading_tasks_seem_expensive;
- TraceableState<bool, TracingCategoryName::kInfo> timer_tasks_seem_expensive;
TraceableState<bool, TracingCategoryName::kDefault>
blocking_input_expected_soon;
TraceableState<bool, TracingCategoryName::kDebug>
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 4af2aa252cd..8e63c191685 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -616,14 +616,6 @@ class MainThreadSchedulerImplTest : public testing::Test {
return scheduler_->main_thread_only().have_seen_a_begin_main_frame;
}
- bool LoadingTasksSeemExpensive() {
- return scheduler_->main_thread_only().loading_tasks_seem_expensive;
- }
-
- bool TimerTasksSeemExpensive() {
- return scheduler_->main_thread_only().timer_tasks_seem_expensive;
- }
-
base::TimeTicks EstimatedNextFrameBegin() {
return scheduler_->main_thread_only().estimated_next_frame_begin;
}
@@ -808,27 +800,6 @@ class MainThreadSchedulerImplTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(MainThreadSchedulerImplTest);
};
-class MainThreadSchedulerImplTestWithoutTouchstartInputHeuristics
- : public MainThreadSchedulerImplTest {
- public:
- MainThreadSchedulerImplTestWithoutTouchstartInputHeuristics()
- : MainThreadSchedulerImplTest({kDisableTouchstartInputHeuristics,
- kDisableNonTouchstartInputHeuristics},
- {kPrioritizeCompositingAfterInput}) {}
- ~MainThreadSchedulerImplTestWithoutTouchstartInputHeuristics() override =
- default;
-};
-
-class MainThreadSchedulerImplTestWithoutNonTouchstartInputHeuristics
- : public MainThreadSchedulerImplTest {
- public:
- MainThreadSchedulerImplTestWithoutNonTouchstartInputHeuristics()
- : MainThreadSchedulerImplTest({kDisableNonTouchstartInputHeuristics},
- {kPrioritizeCompositingAfterInput}) {}
- ~MainThreadSchedulerImplTestWithoutNonTouchstartInputHeuristics() override =
- default;
-};
-
TEST_F(MainThreadSchedulerImplTest, TestPostDefaultTask) {
std::vector<std::string> run_order;
PostTestTasks(&run_order, "D1 D2 D3 D4");
@@ -1032,22 +1003,6 @@ TEST_F(MainThreadSchedulerImplTest,
EXPECT_EQ(UseCase::kCompositorGesture, CurrentUseCase());
}
-TEST_F(MainThreadSchedulerImplTestWithoutNonTouchstartInputHeuristics,
- TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- SimulateCompositorGestureStart(TouchEventPolicy::kSendTouchStart);
- base::RunLoop().RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("C1"), std::string("D2"),
- std::string("C2"), std::string("I1")));
- EXPECT_EQ(UseCase::kNone, CurrentUseCase());
-}
-
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_WithoutScrollUpdates) {
std::vector<std::string> run_order;
@@ -1214,52 +1169,6 @@ TEST_F(
EXPECT_EQ(UseCase::kTouchstart, CurrentUseCase());
}
-TEST_F(
- MainThreadSchedulerImplTestWithoutTouchstartInputHeuristics,
- TestCompositorPolicy_MainThreadHandlesInput_SingleEvent_NoPreventDefault) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeTouchEvent(blink::WebInputEvent::kTouchStart),
- InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeTouchEvent(blink::WebInputEvent::kTouchStart),
- WebInputEventResult::kHandledSystem);
- base::RunLoop().RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("C1"), std::string("D2"),
- std::string("C2"), std::string("I1")));
- EXPECT_EQ(UseCase::kNone, CurrentUseCase());
-}
-
-TEST_F(
- MainThreadSchedulerImplTestWithoutNonTouchstartInputHeuristics,
- TestCompositorPolicy_MainThreadHandlesInput_SingleEvent_NoPreventDefault) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeTouchEvent(blink::WebInputEvent::kTouchStart),
- InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeTouchEvent(blink::WebInputEvent::kTouchStart),
- WebInputEventResult::kHandledSystem);
- base::RunLoop().RunUntilIdle();
- // Because we are still waiting for the touchstart to be processed,
- // non-essential tasks like loading tasks are blocked.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2"),
- std::string("I1")));
- EXPECT_EQ(UseCase::kTouchstart, CurrentUseCase());
-}
-
TEST_F(MainThreadSchedulerImplTest, TestCompositorPolicy_DidAnimateForInput) {
std::vector<std::string> run_order;
PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
@@ -1299,93 +1208,6 @@ TEST_F(MainThreadSchedulerImplTest, Navigation_ResetsTaskCostEstimations) {
testing::ElementsAre(std::string("C1"), std::string("T1")));
}
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimersDontRunWhenMainThreadScrolling) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrame();
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kGestureScrollUpdate);
-
- PostTestTasks(&run_order, "C1 T1");
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(BlockingInputExpectedSoon());
- EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase());
-
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1")));
-}
-
-class MainThreadSchedulerImplTestWithoutExpensiveTaskBlocking
- : public MainThreadSchedulerImplTest {
- public:
- MainThreadSchedulerImplTestWithoutExpensiveTaskBlocking()
- : MainThreadSchedulerImplTest({kDisableExpensiveTaskBlocking}, {}) {}
- ~MainThreadSchedulerImplTestWithoutExpensiveTaskBlocking() override = default;
-};
-
-TEST_F(MainThreadSchedulerImplTestWithoutExpensiveTaskBlocking,
- ExpensiveTimersRunWhenMainThreadScrolling) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrame();
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kGestureScrollUpdate);
-
- PostTestTasks(&run_order, "C1 T1");
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(BlockingInputExpectedSoon());
- EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase());
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("T1")));
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimersDoRunWhenMainThreadInputHandling) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrame();
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kUndefined);
-
- PostTestTasks(&run_order, "C1 T1");
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(BlockingInputExpectedSoon());
- EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase());
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("T1")));
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimersDoRunWhenMainThreadScrolling_AndOnCriticalPath) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrameOnCriticalPath();
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kGestureScrollBegin);
-
- PostTestTasks(&run_order, "C1 T1");
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(BlockingInputExpectedSoon());
- EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase());
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("T1")));
-}
-
TEST_F(MainThreadSchedulerImplTest, TestTouchstartPolicy_Compositor) {
std::vector<std::string> run_order;
PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2");
@@ -2686,326 +2508,6 @@ TEST_F(MainThreadSchedulerImplTest, ShutdownPreventsPostingOfNewTasks) {
}
TEST_F(MainThreadSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedTillFirstBeginMainFrame) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHaveSeenABlockingGestureForTesting(true);
- SimulateExpensiveTasks(loading_task_queue_->task_runner());
- ForceBlockingInputToBeExpectedSoon();
- PostTestTasks(&run_order, "L1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_FALSE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
-
- // Emit a BeginMainFrame, and the loading task should get blocked.
- DoMainFrame();
- run_order.clear();
-
- PostTestTasks(&run_order, "L1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kNone, CurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedIfNoTouchHandler) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(false);
- DoMainFrame();
- SimulateExpensiveTasks(loading_task_queue_->task_runner());
- ForceBlockingInputToBeExpectedSoon();
- PostTestTasks(&run_order, "L1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_FALSE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHaveSeenABlockingGestureForTesting(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceBlockingInputToBeExpectedSoon();
-
- PostTestTasks(&run_order, "T1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
-
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(UseCase::kMainThreadCustomInputHandling,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::kTouchEnd),
- InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::kTouchEnd),
- WebInputEventResult::kHandledSystem);
-
- test_task_runner_->AdvanceMockTickClock(
- priority_escalation_after_input_duration() * 2);
- EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
-
- PostTestTasks(&run_order, "T1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T1"), std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimerTaskBlocked_UseCase_kCompositorGesture) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHaveSeenABlockingGestureForTesting(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceBlockingInputToBeExpectedSoon();
- scheduler_->DidAnimateForInputOnCompositorThread();
-
- PostTestTasks(&run_order, "T1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kCompositorGesture,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimerTaskBlocked_EvenIfBeginMainFrameNotExpectedSoon) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHaveSeenABlockingGestureForTesting(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceBlockingInputToBeExpectedSoon();
- scheduler_->BeginFrameNotExpectedSoon();
-
- PostTestTasks(&run_order, "T1 D1");
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(UseCase::kNone, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveLoadingTasksBlockedIfChildFrameNavigationExpected) {
- std::vector<std::string> run_order;
-
- DoMainFrame();
- scheduler_->SetHaveSeenABlockingGestureForTesting(true);
- SimulateExpensiveTasks(loading_task_queue_->task_runner());
- ForceBlockingInputToBeExpectedSoon();
-
- PostTestTasks(&run_order, "L1 D1");
- base::RunLoop().RunUntilIdle();
-
- // The expensive loading task gets blocked.
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedDuringMainThreadGestures) {
- std::vector<std::string> run_order;
-
- SimulateExpensiveTasks(loading_task_queue_->task_runner());
-
- // Loading tasks should not be disabled during main thread user interactions.
- PostTestTasks(&run_order, "C1 L1");
-
- // Trigger main_thread_gesture UseCase
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kGestureScrollBegin);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase());
-
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("L1")));
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, GetRAILMode());
-}
-
-TEST_F(MainThreadSchedulerImplTest, ModeratelyExpensiveTimer_NotBlocked) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kTouchMove);
- base::RunLoop().RunUntilIdle();
- for (int i = 0; i < 20; i++) {
- simulate_timer_task_ran_ = false;
-
- viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, Now(),
- base::TimeTicks(), base::TimeDelta::FromMilliseconds(16),
- viz::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MainThreadSchedulerImplTest::
- SimulateMainThreadInputHandlingCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(8)));
- timer_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MainThreadSchedulerImplTest::SimulateTimerTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(4)));
-
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
- EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase())
- << " i = " << i;
- EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
- EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
-
- base::TimeDelta time_till_next_frame = EstimatedNextFrameBegin() - Now();
- if (time_till_next_frame > base::TimeDelta())
- test_task_runner_->AdvanceMockTickClock(time_till_next_frame);
- }
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- FourtyMsTimer_NotBlocked_CompositorScrolling) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- base::RunLoop().RunUntilIdle();
- for (int i = 0; i < 20; i++) {
- simulate_timer_task_ran_ = false;
-
- viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, Now(),
- base::TimeTicks(), base::TimeDelta::FromMilliseconds(16),
- viz::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidAnimateForInputOnCompositorThread();
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- &MainThreadSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this), base::TimeDelta::FromMilliseconds(8)));
- timer_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MainThreadSchedulerImplTest::SimulateTimerTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(40)));
-
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
- EXPECT_EQ(UseCase::kCompositorGesture, CurrentUseCase()) << " i = " << i;
- EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
- EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
-
- base::TimeDelta time_till_next_frame = EstimatedNextFrameBegin() - Now();
- if (time_till_next_frame > base::TimeDelta())
- test_task_runner_->AdvanceMockTickClock(time_till_next_frame);
- }
-}
-
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateMainThreadGestureStart(TouchEventPolicy::kSendTouchStart,
- blink::WebInputEvent::kTouchMove);
- base::RunLoop().RunUntilIdle();
- for (int i = 0; i < 20; i++) {
- simulate_timer_task_ran_ = false;
-
- viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, Now(),
- base::TimeTicks(), base::TimeDelta::FromMilliseconds(16),
- viz::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MainThreadSchedulerImplTest::
- SimulateMainThreadInputHandlingCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(8)));
- timer_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MainThreadSchedulerImplTest::SimulateTimerTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(10)));
-
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase())
- << " i = " << i;
- EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
- if (i == 0) {
- EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
- } else {
- EXPECT_TRUE(TimerTasksSeemExpensive()) << " i = " << i;
- }
- EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
-
- base::TimeDelta time_till_next_frame = EstimatedNextFrameBegin() - Now();
- if (time_till_next_frame > base::TimeDelta())
- test_task_runner_->AdvanceMockTickClock(time_till_next_frame);
- }
-}
-
-TEST_F(MainThreadSchedulerImplTest,
EstimateLongestJankFreeTaskDuration_UseCase_NONE) {
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
EXPECT_EQ(rails_response_time(),
@@ -3145,67 +2647,6 @@ void SlowCountingTask(size_t* count,
} // namespace
TEST_F(MainThreadSchedulerImplTest,
- SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_expensive) {
- SimulateCompositorGestureStart(TouchEventPolicy::kDontSendTouchStart);
-
- base::TimeTicks first_throttled_run_time =
- TaskQueueThrottler::AlignedThrottledRunTime(Now());
-
- size_t count = 0;
- // With the compositor task taking 10ms, there is not enough time to run this
- // 7ms timer task in the 16ms frame.
- timer_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(SlowCountingTask, &count, test_task_runner_, 7,
- timer_task_runner_));
-
- for (int i = 0; i < 1000; i++) {
- viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, Now(),
- base::TimeTicks(), base::TimeDelta::FromMilliseconds(16),
- viz::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
- InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MainThreadSchedulerImplTest::
- SimulateMainThreadCompositorAndQuitRunLoopTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(10)));
-
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
-
- // We expect the queue to get throttled on the second iteration which is
- // when the system realizes the task is expensive.
- bool expect_queue_throttled = (i > 0);
- EXPECT_EQ(expect_queue_throttled,
- scheduler_->task_queue_throttler()->IsThrottled(
- timer_task_queue_.get()))
- << "i = " << i;
-
- if (expect_queue_throttled) {
- EXPECT_GE(count, 2u);
- } else {
- EXPECT_LE(count, 2u);
- }
-
- // The task runs twice before the system realizes it's too expensive.
- bool throttled_task_has_run = count > 2;
- bool throttled_task_expected_to_have_run =
- (Now() > first_throttled_run_time);
- EXPECT_EQ(throttled_task_expected_to_have_run, throttled_task_has_run)
- << "i = " << i << " count = " << count;
- }
-
- // Task is throttled but not completely blocked.
- EXPECT_EQ(12u, count);
-}
-
-TEST_F(MainThreadSchedulerImplTest,
SYNCHRONIZED_GESTURE_TimerTaskThrottling_TimersStopped) {
SimulateCompositorGestureStart(TouchEventPolicy::kSendTouchStart);
@@ -3300,34 +2741,6 @@ TEST_F(MainThreadSchedulerImplTest,
EXPECT_EQ(500u, count);
}
-TEST_F(MainThreadSchedulerImplTest,
- ExpensiveTimerTaskBlocked_SYNCHRONIZED_GESTURE_GestureExpected) {
- SimulateExpensiveTasks(timer_task_runner_);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeTouchEvent(blink::WebInputEvent::kTouchStart),
- InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- ForceBlockingInputToBeExpectedSoon();
-
- // Bump us into SYNCHRONIZED_GESTURE.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
- InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, Now(),
- base::TimeTicks(), base::TimeDelta::FromMilliseconds(16),
- viz::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- EXPECT_EQ(UseCase::kSynchronizedGesture,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(BlockingInputExpectedSoon());
- EXPECT_FALSE(timer_task_queue_->IsQueueEnabled());
-}
-
TEST_F(MainThreadSchedulerImplTest, DenyLongIdleDuringTouchStart) {
scheduler_->DidHandleInputEventOnCompositorThread(
FakeTouchEvent(blink::WebInputEvent::kTouchStart),
@@ -3802,35 +3215,6 @@ void RecordingTimeTestTask(
run_times->push_back(task_runner->GetMockTickClock()->NowTicks());
}
-TEST_F(MainThreadSchedulerImplTest,
- DefaultTimerTasksAreThrottledWhenBackgrounded) {
- std::vector<base::TimeTicks> run_times;
-
- scheduler_->SetRendererBackgrounded(true);
- timer_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordingTimeTestTask, &run_times, test_task_runner_));
-
- test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1100));
- // It's expected to run every "absolute" second.
- EXPECT_THAT(run_times, testing::ElementsAre(base::TimeTicks() +
- base::TimeDelta::FromSeconds(1)));
- run_times.clear();
-
- base::TimeTicks posting_time = Now();
- timer_task_runner_->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&RecordingTimeTestTask, &run_times, test_task_runner_),
- base::TimeDelta::FromMilliseconds(200));
-
- scheduler_->SetRendererBackgrounded(false);
-
- test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(400));
- EXPECT_THAT(run_times,
- testing::ElementsAre(posting_time +
- base::TimeDelta::FromMilliseconds(200)));
-}
-
// Nav Start Nav Start assert
// | | |
// v v v
@@ -4145,6 +3529,28 @@ TEST_F(MainThreadSchedulerImplTest, EQTWithNestedLoop) {
base::TimeDelta::FromMicroseconds(400 + 50 + 50 + 1250)));
}
+TEST_F(MainThreadSchedulerImplTest, TaskQueueReferenceClearedOnShutdown) {
+ // Ensure that the scheduler clears its references to a task queue after
+ // |shutdown| and doesn't try to update its policies.
+ scoped_refptr<MainThreadTaskQueue> queue1 = scheduler_->NewTimerTaskQueue(
+ MainThreadTaskQueue::QueueType::kFrameThrottleable, nullptr);
+ scoped_refptr<MainThreadTaskQueue> queue2 = scheduler_->NewTimerTaskQueue(
+ MainThreadTaskQueue::QueueType::kFrameThrottleable, nullptr);
+
+ EXPECT_EQ(queue1->GetTimeDomain(), scheduler_->real_time_domain());
+ EXPECT_EQ(queue2->GetTimeDomain(), scheduler_->real_time_domain());
+
+ scheduler_->OnShutdownTaskQueue(queue1);
+
+ scheduler_->EnableVirtualTime(
+ MainThreadSchedulerImpl::BaseTimeOverridePolicy::DO_NOT_OVERRIDE);
+
+ // Virtual time should be enabled for queue2, as it is a regular queue and
+ // nothing should change for queue1 because it was shut down.
+ EXPECT_EQ(queue1->GetTimeDomain(), scheduler_->real_time_domain());
+ EXPECT_EQ(queue2->GetTimeDomain(), scheduler_->GetVirtualTimeDomain());
+}
+
} // namespace main_thread_scheduler_impl_unittest
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.cc
deleted file mode 100644
index 0686a1eb0a3..00000000000
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.cc
+++ /dev/null
@@ -1,45 +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 "third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h"
-
-#include "base/time/default_tick_clock.h"
-
-namespace blink {
-namespace scheduler {
-
-TaskCostEstimator::TaskCostEstimator(const base::TickClock* time_source,
- int sample_count,
- double estimation_percentile)
- : rolling_time_delta_history_(sample_count),
- time_source_(time_source),
- outstanding_task_count_(0),
- estimation_percentile_(estimation_percentile) {}
-
-TaskCostEstimator::~TaskCostEstimator() = default;
-
-void TaskCostEstimator::WillProcessTask(const base::PendingTask& pending_task) {
- // Avoid measuring the duration in nested run loops.
- if (++outstanding_task_count_ == 1)
- task_start_time_ = time_source_->NowTicks();
-}
-
-void TaskCostEstimator::DidProcessTask(const base::PendingTask& pending_task) {
- if (--outstanding_task_count_ == 0) {
- base::TimeDelta duration = time_source_->NowTicks() - task_start_time_;
- rolling_time_delta_history_.InsertSample(duration);
- }
-}
-
-base::TimeDelta TaskCostEstimator::expected_task_duration() const {
- return rolling_time_delta_history_.Percentile(estimation_percentile_);
-}
-
-void TaskCostEstimator::Clear() {
- rolling_time_delta_history_.Clear();
- expected_task_duration_ = base::TimeDelta();
-}
-
-} // namespace scheduler
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h
deleted file mode 100644
index c3e54a30e99..00000000000
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h
+++ /dev/null
@@ -1,52 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_TASK_COST_ESTIMATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_TASK_COST_ESTIMATOR_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-#include "cc/base/rolling_time_delta_history.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace base {
-class TickClock;
-}
-
-namespace blink {
-namespace scheduler {
-
-// Estimates the cost of running tasks based on historical timing data.
-class PLATFORM_EXPORT TaskCostEstimator
- : public base::MessageLoop::TaskObserver {
- public:
- TaskCostEstimator(const base::TickClock* time_source,
- int sample_count,
- double estimation_percentile);
- ~TaskCostEstimator() override;
-
- base::TimeDelta expected_task_duration() const;
-
- // TaskObserver implementation:
- void WillProcessTask(const base::PendingTask& pending_task) override;
- void DidProcessTask(const base::PendingTask& pending_task) override;
-
- void Clear();
-
- private:
- cc::RollingTimeDeltaHistory rolling_time_delta_history_;
- const base::TickClock* time_source_; // NOT OWNED
- int outstanding_task_count_;
- double estimation_percentile_;
- base::TimeTicks task_start_time_;
- base::TimeDelta expected_task_duration_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskCostEstimator);
-};
-
-} // namespace scheduler
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_TASK_COST_ESTIMATOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
index 75feaa7adfd..39530c12958 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
@@ -65,6 +65,14 @@ const char* TaskTypeNames::TaskTypeToString(TaskType task_type) {
return "ExperimentalWebSchedulingUserInteraction";
case TaskType::kExperimentalWebSchedulingBestEffort:
return "ExperimentalWebSchedulingBackground";
+ case TaskType::kFontLoading:
+ return "FontLoading";
+ case TaskType::kApplicationLifeCycle:
+ return "ApplicationLifeCycle";
+ case TaskType::kBackgroundFetch:
+ return "BackgroundFetch";
+ case TaskType::kPermission:
+ return "Permission";
case TaskType::kInternalDefault:
return "InternalDefault";
case TaskType::kInternalLoading:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
index a644fbe59bf..28a428489f4 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
@@ -73,34 +73,6 @@ class FrameScheduler : public FrameOrWorkerScheduler {
// the top level frame, i.e. a main frame.
virtual FrameType GetFrameType() const = 0;
- // The tasks runners below are listed in increasing QoS order.
- // - throttleable task queue. Designed for custom user-provided javascript
- // tasks. Lowest guarantees. Can be paused, blocked during user gesture,
- // throttled when backgrounded or stopped completely after some time in
- // background.
- // - deferrable task queue. These tasks can be deferred for a small period
- // (several seconds) when high-priority work is anticipated. These tasks
- // can be paused.
- // - pausable task queue. Default queue for high-priority javascript tasks.
- // They can be paused according to the spec during javascript alert
- // dialogs, printing windows and devtools debugging. Otherwise scheduler
- // does not tamper with their execution.
- // - unpausable task queue. Should be used for control tasks which should
- // run when the context is paused. Usage should be extremely rare.
- // Please consult scheduler-dev@ before using it. Running javascript
- // on it is strictly verboten and can lead to hard-to-diagnose errors.
- //
- //
- // These queues below are separate due to special handling for their
- // priorities.
- // - loading task queue. Similar to deferrable task queue. Throttling might
- // be considered in the future.
- // - loading control task queue. Loading task queue with increased priority
- // to run small loading tasks which schedule other loading tasks.
-
- // Note: old-style timer task runner corresponds to throttleable task runner
- // and unthrottled task runner corresponds to pausable task runner.
-
// Returns a task runner that is suitable with the given task type.
virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
TaskType) = 0;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
index 528963cecfb..738f21d8c26 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
@@ -28,6 +28,19 @@ class PLATFORM_EXPORT WorkerScheduler : public FrameOrWorkerScheduler {
WorkerSchedulerProxy* proxy);
~WorkerScheduler() override;
+ class PLATFORM_EXPORT PauseHandle {
+ public:
+ PauseHandle(base::WeakPtr<WorkerScheduler>);
+ ~PauseHandle();
+
+ private:
+ base::WeakPtr<WorkerScheduler> scheduler_;
+
+ DISALLOW_COPY_AND_ASSIGN(PauseHandle);
+ };
+
+ std::unique_ptr<PauseHandle> Pause() WARN_UNUSED_RESULT;
+
std::unique_ptr<ActiveConnectionHandle> OnActiveConnectionCreated() override;
// Unregisters the task queues and cancels tasks in them.
@@ -49,25 +62,39 @@ class PLATFORM_EXPORT WorkerScheduler : public FrameOrWorkerScheduler {
protected:
scoped_refptr<NonMainThreadTaskQueue> ThrottleableTaskQueue();
- scoped_refptr<NonMainThreadTaskQueue> UnthrottleableTaskQueue();
+ scoped_refptr<NonMainThreadTaskQueue> UnpausableTaskQueue();
+ scoped_refptr<NonMainThreadTaskQueue> PausableTaskQueue();
private:
void SetUpThrottling();
+ void PauseImpl();
+ void ResumeImpl();
base::WeakPtr<WorkerScheduler> GetWeakPtr();
+ // The tasks runners below are listed in increasing QoS order.
+ // - throttleable task queue. Designed for custom user-provided javascript
+ // tasks. Lowest guarantees. Can be paused, blocked during user gesture,
+ // throttled when backgrounded or stopped completely after some time in
+ // background.
+ // - pausable task queue. Default queue for high-priority javascript tasks.
+ // They can be paused according to the spec during devtools debugging.
+ // Otherwise scheduler does not tamper with their execution.
+ // - unpausable task queue. Should be used for control tasks which should
+ // run when the context is paused. Usage should be extremely rare.
+ // Please consult scheduler-dev@ before using it. Running javascript
+ // on it is strictly verboten and can lead to hard-to-diagnose errors.
scoped_refptr<NonMainThreadTaskQueue> throttleable_task_queue_;
- scoped_refptr<NonMainThreadTaskQueue> unthrottleable_task_queue_;
+ scoped_refptr<NonMainThreadTaskQueue> pausable_task_queue_;
+ scoped_refptr<NonMainThreadTaskQueue> unpausable_task_queue_;
SchedulingLifecycleState lifecycle_state_ =
SchedulingLifecycleState::kNotThrottled;
WorkerThreadScheduler* thread_scheduler_; // NOT OWNED
-#if DCHECK_IS_ON()
bool is_disposed_ = false;
-#endif
-
+ uint32_t paused_count_ = 0;
base::WeakPtrFactory<WorkerScheduler> weak_factory_;
};
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread.cc
index 0236b1f5073..32d5f4f80da 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread.cc
@@ -18,7 +18,9 @@ CompositorThread::~CompositorThread() = default;
std::unique_ptr<NonMainThreadSchedulerImpl>
CompositorThread::CreateNonMainThreadScheduler() {
return std::make_unique<CompositorThreadScheduler>(
- base::sequence_manager::CreateSequenceManagerOnCurrentThread());
+ base::sequence_manager::CreateSequenceManagerOnCurrentThread(
+ base::sequence_manager::SequenceManager::Settings{
+ .randomised_sampling_enabled = true}));
}
} // namespace scheduler
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
index f8d43f2c4ba..10db0436f98 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
@@ -25,7 +25,10 @@ std::unique_ptr<NonMainThreadSchedulerImpl> NonMainThreadSchedulerImpl::Create(
WorkerSchedulerProxy* proxy) {
return std::make_unique<WorkerThreadScheduler>(
thread_type,
- base::sequence_manager::CreateSequenceManagerOnCurrentThread(), proxy);
+ base::sequence_manager::CreateSequenceManagerOnCurrentThread(
+ base::sequence_manager::SequenceManager::Settings{
+ .randomised_sampling_enabled = true}),
+ proxy);
}
void NonMainThreadSchedulerImpl::Init() {
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc
index 2ba5085b2fc..ef5a635a8c8 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc
@@ -35,5 +35,11 @@ void NonMainThreadTaskQueue::OnTaskCompleted(
}
}
+void NonMainThreadTaskQueue::SetPaused(bool paused) {
+ if (!task_queue_voter_)
+ task_queue_voter_ = CreateQueueEnabledVoter();
+ task_queue_voter_->SetQueueEnabled(!paused);
+}
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
index e801ecd6fe0..93cf85fed33 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
@@ -33,7 +33,11 @@ class PLATFORM_EXPORT NonMainThreadTaskQueue
return TaskQueue::CreateTaskRunner(static_cast<int>(task_type));
}
+ void SetPaused(bool paused);
+
private:
+ std::unique_ptr<QueueEnabledVoter> task_queue_voter_;
+
// Not owned.
NonMainThreadSchedulerImpl* non_main_thread_scheduler_;
};
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
index 32e376914ee..b4dfcaa2004 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
@@ -12,12 +12,25 @@
namespace blink {
namespace scheduler {
+WorkerScheduler::PauseHandle::PauseHandle(
+ base::WeakPtr<WorkerScheduler> scheduler)
+ : scheduler_(scheduler) {
+ scheduler_->PauseImpl();
+}
+
+WorkerScheduler::PauseHandle::~PauseHandle() {
+ if (scheduler_)
+ scheduler_->ResumeImpl();
+}
+
WorkerScheduler::WorkerScheduler(WorkerThreadScheduler* worker_thread_scheduler,
WorkerSchedulerProxy* proxy)
: throttleable_task_queue_(
worker_thread_scheduler->CreateTaskQueue("worker_throttleable_tq")),
- unthrottleable_task_queue_(
- worker_thread_scheduler->CreateTaskQueue("worker_unthrottleable_tq")),
+ pausable_task_queue_(
+ worker_thread_scheduler->CreateTaskQueue("worker_pausable_tq")),
+ unpausable_task_queue_(
+ worker_thread_scheduler->CreateTaskQueue("worker_unpausable_tq")),
thread_scheduler_(worker_thread_scheduler),
weak_factory_(this) {
thread_scheduler_->RegisterWorkerScheduler(this);
@@ -34,9 +47,33 @@ base::WeakPtr<WorkerScheduler> WorkerScheduler::GetWeakPtr() {
}
WorkerScheduler::~WorkerScheduler() {
-#if DCHECK_IS_ON()
DCHECK(is_disposed_);
-#endif
+ DCHECK_EQ(0u, paused_count_);
+}
+
+std::unique_ptr<WorkerScheduler::PauseHandle> WorkerScheduler::Pause() {
+ thread_scheduler_->helper()->CheckOnValidThread();
+ if (is_disposed_)
+ return nullptr;
+ return std::make_unique<PauseHandle>(GetWeakPtr());
+}
+
+void WorkerScheduler::PauseImpl() {
+ thread_scheduler_->helper()->CheckOnValidThread();
+ paused_count_++;
+ if (paused_count_ == 1) {
+ throttleable_task_queue_->SetPaused(true);
+ pausable_task_queue_->SetPaused(true);
+ }
+}
+
+void WorkerScheduler::ResumeImpl() {
+ thread_scheduler_->helper()->CheckOnValidThread();
+ paused_count_--;
+ if (paused_count_ == 0 && !is_disposed_) {
+ throttleable_task_queue_->SetPaused(false);
+ pausable_task_queue_->SetPaused(false);
+ }
}
void WorkerScheduler::SetUpThrottling() {
@@ -78,12 +115,11 @@ void WorkerScheduler::Dispose() {
thread_scheduler_->UnregisterWorkerScheduler(this);
- unthrottleable_task_queue_->ShutdownTaskQueue();
+ unpausable_task_queue_->ShutdownTaskQueue();
+ pausable_task_queue_->ShutdownTaskQueue();
throttleable_task_queue_->ShutdownTaskQueue();
-#if DCHECK_IS_ON()
is_disposed_ = true;
-#endif
}
scoped_refptr<base::SingleThreadTaskRunner> WorkerScheduler::GetTaskRunner(
@@ -93,7 +129,6 @@ scoped_refptr<base::SingleThreadTaskRunner> WorkerScheduler::GetTaskRunner(
case TaskType::kPostedMessage:
case TaskType::kWorkerAnimation:
return throttleable_task_queue_->CreateTaskRunner(type);
- case TaskType::kDeprecatedNone:
case TaskType::kDOMManipulation:
case TaskType::kUserInteraction:
case TaskType::kNetworking:
@@ -115,23 +150,33 @@ scoped_refptr<base::SingleThreadTaskRunner> WorkerScheduler::GetTaskRunner(
case TaskType::kWebGL:
case TaskType::kIdleTask:
case TaskType::kMiscPlatformAPI:
+ case TaskType::kFontLoading:
+ case TaskType::kApplicationLifeCycle:
+ case TaskType::kBackgroundFetch:
+ case TaskType::kPermission:
case TaskType::kInternalDefault:
case TaskType::kInternalLoading:
- case TaskType::kInternalTest:
case TaskType::kInternalWebCrypto:
case TaskType::kInternalIndexedDB:
case TaskType::kInternalMedia:
case TaskType::kInternalMediaRealTime:
- case TaskType::kInternalIPC:
case TaskType::kInternalUserInteraction:
+ case TaskType::kInternalIntersectionObserver:
+ // UnthrottledTaskRunner is generally discouraged in future.
+ // TODO(nhiroki): Identify which tasks can be throttled / suspendable and
+ // move them into other task runners. See also comments in
+ // Get(LocalFrame). (https://crbug.com/670534)
+ return pausable_task_queue_->CreateTaskRunner(type);
+ case TaskType::kDeprecatedNone:
+ case TaskType::kInternalIPC:
case TaskType::kInternalInspector:
case TaskType::kInternalWorker:
- case TaskType::kInternalIntersectionObserver:
+ case TaskType::kInternalTest:
// UnthrottledTaskRunner is generally discouraged in future.
// TODO(nhiroki): Identify which tasks can be throttled / suspendable and
// move them into other task runners. See also comments in
// Get(LocalFrame). (https://crbug.com/670534)
- return unthrottleable_task_queue_->CreateTaskRunner(type);
+ return unpausable_task_queue_->CreateTaskRunner(type);
case TaskType::kMainThreadTaskQueueV8:
case TaskType::kMainThreadTaskQueueCompositor:
case TaskType::kMainThreadTaskQueueDefault:
@@ -174,9 +219,12 @@ void WorkerScheduler::OnLifecycleStateChanged(
NotifyLifecycleObservers();
}
-scoped_refptr<NonMainThreadTaskQueue>
-WorkerScheduler::UnthrottleableTaskQueue() {
- return unthrottleable_task_queue_.get();
+scoped_refptr<NonMainThreadTaskQueue> WorkerScheduler::UnpausableTaskQueue() {
+ return unpausable_task_queue_.get();
+}
+
+scoped_refptr<NonMainThreadTaskQueue> WorkerScheduler::PausableTaskQueue() {
+ return pausable_task_queue_.get();
}
scoped_refptr<NonMainThreadTaskQueue> WorkerScheduler::ThrottleableTaskQueue() {
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
index 62706fe7d47..7b115c7e2b0 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
@@ -76,7 +76,9 @@ class WorkerThreadForTest : public WorkerThread {
std::unique_ptr<NonMainThreadSchedulerImpl> CreateNonMainThreadScheduler()
override {
auto scheduler = std::make_unique<WorkerThreadSchedulerForTest>(
- base::sequence_manager::CreateSequenceManagerOnCurrentThread(),
+ base::sequence_manager::CreateSequenceManagerOnCurrentThread(
+ base::sequence_manager::SequenceManager::Settings{
+ .randomised_sampling_enabled = true}),
worker_scheduler_proxy(), throtting_state_changed_);
scheduler_ = scheduler.get();
worker_scheduler_ = std::make_unique<scheduler::WorkerScheduler>(
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc
index 0f12381be8a..5b65ecb6dba 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc
@@ -71,8 +71,8 @@ class WorkerSchedulerForTest : public WorkerScheduler {
WorkerThreadSchedulerForTest* thread_scheduler)
: WorkerScheduler(thread_scheduler, nullptr) {}
- using WorkerScheduler::UnthrottleableTaskQueue;
using WorkerScheduler::ThrottleableTaskQueue;
+ using WorkerScheduler::UnpausableTaskQueue;
};
class WorkerSchedulerTest : public testing::Test {
@@ -113,10 +113,10 @@ class WorkerSchedulerTest : public testing::Test {
// Helper for posting a task.
void PostTestTask(std::vector<std::string>* run_order,
- const std::string& task_descriptor) {
- worker_scheduler_->GetTaskRunner(TaskType::kInternalTest)
- ->PostTask(FROM_HERE,
- WTF::Bind(&AppendToVectorTestTask,
+ const std::string& task_descriptor,
+ TaskType task_type) {
+ worker_scheduler_->GetTaskRunner(task_type)->PostTask(
+ FROM_HERE, WTF::Bind(&AppendToVectorTestTask,
WTF::Unretained(run_order), task_descriptor));
}
@@ -131,18 +131,18 @@ class WorkerSchedulerTest : public testing::Test {
TEST_F(WorkerSchedulerTest, TestPostTasks) {
std::vector<std::string> run_order;
- PostTestTask(&run_order, "T1");
- PostTestTask(&run_order, "T2");
+ PostTestTask(&run_order, "T1", TaskType::kInternalTest);
+ PostTestTask(&run_order, "T2", TaskType::kInternalTest);
RunUntilIdle();
- PostTestTask(&run_order, "T3");
+ PostTestTask(&run_order, "T3", TaskType::kInternalTest);
RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("T1", "T2", "T3"));
// Tasks should not run after the scheduler is disposed of.
worker_scheduler_->Dispose();
run_order.clear();
- PostTestTask(&run_order, "T4");
- PostTestTask(&run_order, "T5");
+ PostTestTask(&run_order, "T4", TaskType::kInternalTest);
+ PostTestTask(&run_order, "T5", TaskType::kInternalTest);
RunUntilIdle();
EXPECT_TRUE(run_order.empty());
@@ -268,6 +268,40 @@ TEST_F(WorkerSchedulerTest,
base::TimeTicks() + base::TimeDelta::FromSeconds(41)));
}
+TEST_F(WorkerSchedulerTest, PausableTasks) {
+ std::vector<std::string> run_order;
+ auto pause_handle = worker_scheduler_->Pause();
+ // Tests interlacing pausable, throttable and unpausable tasks and
+ // ensures that the pausable & throttable tasks don't run when paused.
+ // Throttable
+ PostTestTask(&run_order, "T1", TaskType::kJavascriptTimer);
+ // Pausable
+ PostTestTask(&run_order, "T2", TaskType::kNetworking);
+ // Unpausable
+ PostTestTask(&run_order, "T3", TaskType::kInternalTest);
+ RunUntilIdle();
+ EXPECT_THAT(run_order, testing::ElementsAre("T3"));
+ pause_handle.reset();
+ RunUntilIdle();
+
+ EXPECT_THAT(run_order, testing::ElementsAre("T3", "T1", "T2"));
+}
+
+TEST_F(WorkerSchedulerTest, NestedPauseHandlesTasks) {
+ std::vector<std::string> run_order;
+ auto pause_handle = worker_scheduler_->Pause();
+ {
+ auto pause_handle2 = worker_scheduler_->Pause();
+ PostTestTask(&run_order, "T1", TaskType::kJavascriptTimer);
+ PostTestTask(&run_order, "T2", TaskType::kNetworking);
+ }
+ RunUntilIdle();
+ EXPECT_EQ(0u, run_order.size());
+ pause_handle.reset();
+ RunUntilIdle();
+ EXPECT_THAT(run_order, testing::ElementsAre("T1", "T2"));
+}
+
} // namespace worker_scheduler_unittest
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
index cfb3395b38d..bd4a98f1ecb 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
@@ -107,8 +107,7 @@ WorkerThreadScheduler::WorkerThreadScheduler(
"WorkerSchedulerIdlePeriod",
base::TimeDelta::FromMilliseconds(300),
helper()->NewTaskQueue(TaskQueue::Spec("worker_idle_tq"))),
- idle_canceled_delayed_task_sweeper_(helper(),
- idle_helper_.IdleTaskRunner()),
+ idle_memory_reclaimer_(helper(), idle_helper_.IdleTaskRunner()),
load_tracker_(helper()->NowTicks(),
base::BindRepeating(&ReportWorkerTaskLoad),
kUnspecifiedWorkerThreadLoadTrackerReportingInterval),
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
index c09cf5b27af..7d786578137 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
@@ -11,8 +11,8 @@
#include "base/task/sequence_manager/task_time_observer.h"
#include "components/scheduling_metrics/task_duration_metric_reporter.h"
#include "third_party/blink/public/platform/web_thread_type.h"
-#include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
@@ -140,7 +140,7 @@ class PLATFORM_EXPORT WorkerThreadScheduler
const WebThreadType thread_type_;
IdleHelper idle_helper_;
- IdleCanceledDelayedTaskSweeper idle_canceled_delayed_task_sweeper_;
+ IdleMemoryReclaimer idle_memory_reclaimer_;
ThreadLoadTracker load_tracker_;
bool initialized_;
base::TimeTicks thread_start_time_;
diff --git a/chromium/third_party/blink/renderer/platform/shared_buffer.cc b/chromium/third_party/blink/renderer/platform/shared_buffer.cc
index 7925b3f9f08..f2bcc3dacf8 100644
--- a/chromium/third_party/blink/renderer/platform/shared_buffer.cc
+++ b/chromium/third_party/blink/renderer/platform/shared_buffer.cc
@@ -81,7 +81,7 @@ SharedBuffer::Iterator::Iterator(size_t offset, const SharedBuffer* buffer)
Init(offset);
}
-SharedBuffer::Iterator::Iterator(size_t segment_index,
+SharedBuffer::Iterator::Iterator(wtf_size_t segment_index,
size_t offset,
const SharedBuffer* buffer)
: index_(segment_index + 1), buffer_(buffer) {
@@ -111,13 +111,13 @@ void SharedBuffer::Iterator::Init(size_t offset) {
SharedBuffer::SharedBuffer() : size_(0) {}
-SharedBuffer::SharedBuffer(size_t size) : size_(size), buffer_(size) {}
+SharedBuffer::SharedBuffer(wtf_size_t size) : size_(size), buffer_(size) {}
-SharedBuffer::SharedBuffer(const char* data, size_t size) : size_(size) {
+SharedBuffer::SharedBuffer(const char* data, wtf_size_t size) : size_(size) {
buffer_.Append(data, size);
}
-SharedBuffer::SharedBuffer(const unsigned char* data, size_t size)
+SharedBuffer::SharedBuffer(const unsigned char* data, wtf_size_t size)
: SharedBuffer(reinterpret_cast<const char*>(data), size) {}
SharedBuffer::~SharedBuffer() = default;
@@ -149,7 +149,7 @@ void SharedBuffer::AppendInternal(const char* data, size_t length) {
if (size_ <= kSegmentSize) {
// No need to use segments for small resource data.
- buffer_.Append(data, length);
+ buffer_.Append(data, static_cast<wtf_size_t>(length));
return;
}
@@ -181,9 +181,9 @@ SharedBuffer::Iterator SharedBuffer::end() const {
}
void SharedBuffer::MergeSegmentsIntoBuffer() {
- size_t bytes_left = size_ - buffer_.size();
+ wtf_size_t bytes_left = size_ - buffer_.size();
for (const auto& segment : segments_) {
- size_t bytes_to_copy = std::min<size_t>(bytes_left, kSegmentSize);
+ wtf_size_t bytes_to_copy = std::min<wtf_size_t>(bytes_left, kSegmentSize);
buffer_.Append(segment.get(), bytes_to_copy);
bytes_left -= bytes_to_copy;
}
@@ -198,8 +198,9 @@ SharedBuffer::Iterator SharedBuffer::GetIteratorAtInternal(
if (position < buffer_.size())
return Iterator(position, this);
- return Iterator(SegmentIndex(position - buffer_.size()),
- OffsetInSegment(position - buffer_.size()), this);
+ return Iterator(
+ SafeCast<uint32_t>(SegmentIndex(position - buffer_.size())),
+ SafeCast<uint32_t>(OffsetInSegment(position - buffer_.size())), this);
}
bool SharedBuffer::GetBytesInternal(void* dest, size_t dest_size) const {
@@ -261,9 +262,9 @@ SharedBuffer::DeprecatedFlatData::DeprecatedFlatData(
}
// Merge all segments.
- flat_buffer_.ReserveInitialCapacity(buffer_->size());
+ flat_buffer_.ReserveInitialCapacity(SafeCast<wtf_size_t>(buffer_->size()));
for (const auto& span : *buffer_)
- flat_buffer_.Append(span.data(), span.size());
+ flat_buffer_.Append(span.data(), static_cast<wtf_size_t>(span.size()));
data_ = flat_buffer_.data();
}
diff --git a/chromium/third_party/blink/renderer/platform/shared_buffer.h b/chromium/third_party/blink/renderer/platform/shared_buffer.h
index 8c01968affe..776496dc30f 100644
--- a/chromium/third_party/blink/renderer/platform/shared_buffer.h
+++ b/chromium/third_party/blink/renderer/platform/shared_buffer.h
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -83,14 +84,16 @@ class PLATFORM_EXPORT SharedBuffer : public RefCounted<SharedBuffer> {
// for the consecutive part
Iterator(size_t offset, const SharedBuffer* buffer);
// for the rest
- Iterator(size_t segment_index, size_t offset, const SharedBuffer* buffer);
+ Iterator(wtf_size_t segment_index,
+ size_t offset,
+ const SharedBuffer* buffer);
void Init(size_t offset);
bool IsEnd() const { return index_ == buffer_->segments_.size() + 1; }
// It represents |buffer_->buffer| if |index_| is 0, and
// |buffer_->segments[index_ - 1]| otherwise.
- size_t index_;
+ wtf_size_t index_;
base::span<const char> value_;
const SharedBuffer* buffer_;
};
@@ -203,9 +206,9 @@ class PLATFORM_EXPORT SharedBuffer : public RefCounted<SharedBuffer> {
class Segment;
SharedBuffer();
- explicit SharedBuffer(size_t);
- SharedBuffer(const char*, size_t);
- SharedBuffer(const unsigned char*, size_t);
+ explicit SharedBuffer(wtf_size_t);
+ SharedBuffer(const char*, wtf_size_t);
+ SharedBuffer(const unsigned char*, wtf_size_t);
// See SharedBuffer::data().
void MergeSegmentsIntoBuffer();
@@ -227,10 +230,24 @@ class PLATFORM_EXPORT SharedBuffer : public RefCounted<SharedBuffer> {
template <>
inline Vector<char> SharedBuffer::CopyAs() const {
Vector<char> buffer;
- buffer.ReserveInitialCapacity(size_);
+ buffer.ReserveInitialCapacity(SafeCast<wtf_size_t>(size_));
for (const auto& span : *this)
- buffer.Append(span.data(), span.size());
+ buffer.Append(span.data(), static_cast<wtf_size_t>(span.size()));
+
+ DCHECK_EQ(buffer.size(), size_);
+ return buffer;
+}
+
+template <>
+inline Vector<uint8_t> SharedBuffer::CopyAs() const {
+ Vector<uint8_t> buffer;
+ buffer.ReserveInitialCapacity(SafeCast<wtf_size_t>(size_));
+
+ for (const auto& span : *this) {
+ buffer.Append(reinterpret_cast<const uint8_t*>(span.data()),
+ static_cast<wtf_size_t>(span.size()));
+ }
DCHECK_EQ(buffer.size(), size_);
return buffer;
diff --git a/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.cc b/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.cc
index a31a7f4aed7..6383440a238 100644
--- a/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.cc
+++ b/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/platform/shared_buffer_chunk_reader.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
@@ -65,7 +66,7 @@ void SharedBufferChunkReader::SetSeparator(const Vector<char>& separator) {
void SharedBufferChunkReader::SetSeparator(const char* separator) {
separator_.clear();
- separator_.Append(separator, strlen(separator));
+ separator_.Append(separator, SafeCast<wtf_size_t>(strlen(separator)));
}
bool SharedBufferChunkReader::NextChunk(Vector<char>& chunk,
@@ -108,7 +109,7 @@ bool SharedBufferChunkReader::NextChunk(Vector<char>& chunk,
return !chunk.IsEmpty();
}
segment_ = it->data();
- segment_length_ = it->size();
+ segment_length_ = SafeCast<uint32_t>(it->size());
}
NOTREACHED();
return false;
@@ -125,15 +126,15 @@ String SharedBufferChunkReader::NextChunkAsUTF8StringWithLatin1Fallback(
: g_empty_string;
}
-size_t SharedBufferChunkReader::Peek(Vector<char>& data,
- size_t requested_size) {
+uint32_t SharedBufferChunkReader::Peek(Vector<char>& data,
+ uint32_t requested_size) {
data.clear();
if (requested_size <= segment_length_ - segment_index_) {
data.Append(segment_ + segment_index_, requested_size);
return requested_size;
}
- size_t read_bytes_count = segment_length_ - segment_index_;
+ uint32_t read_bytes_count = segment_length_ - segment_index_;
data.Append(segment_ + segment_index_, read_bytes_count);
for (auto it = buffer_->GetIteratorAt(buffer_position_ + segment_length_);
@@ -143,7 +144,7 @@ size_t SharedBufferChunkReader::Peek(Vector<char>& data,
read_bytes_count += (requested_size - read_bytes_count);
break;
}
- data.Append(it->data(), it->size());
+ data.Append(it->data(), SafeCast<wtf_size_t>(it->size()));
read_bytes_count += it->size();
}
return read_bytes_count;
diff --git a/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.h b/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.h
index 3ebfcacd193..4ebf5bb5432 100644
--- a/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.h
+++ b/chromium/third_party/blink/renderer/platform/shared_buffer_chunk_reader.h
@@ -65,17 +65,17 @@ class PLATFORM_EXPORT SharedBufferChunkReader final {
// the buffer position.
// Returns the number of bytes read. That number might be less than the
// specified size if the end of the buffer was reached.
- size_t Peek(Vector<char>&, size_t);
+ uint32_t Peek(Vector<char>&, uint32_t);
private:
scoped_refptr<const SharedBuffer> buffer_;
size_t buffer_position_;
const char* segment_;
- size_t segment_length_;
- size_t segment_index_;
+ uint32_t segment_length_;
+ uint32_t segment_index_;
bool reached_end_of_file_;
Vector<char> separator_;
- size_t separator_index_;
+ uint32_t separator_index_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/supplementable.h b/chromium/third_party/blink/renderer/platform/supplementable.h
index 155fc0087a3..c88d7238758 100644
--- a/chromium/third_party/blink/renderer/platform/supplementable.h
+++ b/chromium/third_party/blink/renderer/platform/supplementable.h
@@ -46,9 +46,10 @@ namespace blink {
// Most commonly, this is used to attach data to a central object, such as
// LocalFrame, so that it can be easily accessed. This is similar to adding a
// member to that class (e.g. it is kept alive while the supplementable is),
-// except that it occupies less memory if not used, and can be done in cases
-// that would otherwise be a layering violation. For example, it is common for
-// features implemented in modules/ to supplement classes in core/.
+// except that a Supplement is constructed lazily and therefore occupies less
+// memory if not used. It can also be used in cases that would otherwise be
+// layering violation. For example, it is common for features implemented in
+// modules/ to supplement classes in core/.
//
// Supplementable and Supplement instances are meant to be thread local. They
// should only be accessed from within the thread that created them. The
@@ -124,9 +125,9 @@ class Supplement : public GarbageCollectedMixin {
explicit Supplement(T& supplementable) : supplementable_(&supplementable) {}
- // Supplementable and its supplements live and die together.
- // Thus supplementable() should never return null (if the default constructor
- // is completely removed).
+ // Supplements are constructed lazily on first access and are destroyed with
+ // their Supplementable, so GetSupplementable() should never return null (if
+ // the default constructor is completely removed).
T* GetSupplementable() const { return supplementable_; }
template <typename SupplementType>
diff --git a/chromium/third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.cc b/chromium/third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.cc
index a1f9ef8774b..812b000ebc1 100644
--- a/chromium/third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.cc
@@ -7,6 +7,7 @@
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
+#include "base/test/test_timeouts.h"
#include "content/public/test/blink_test_environment.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
@@ -26,6 +27,8 @@ BlinkFuzzerTestSupport::BlinkFuzzerTestSupport(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
+ TestTimeouts::Initialize();
+
content::SetUpBlinkTestEnvironment();
blink::SchemeRegistry::Initialize();
diff --git a/chromium/third_party/blink/renderer/platform/testing/data/apng19-ref.png b/chromium/third_party/blink/renderer/platform/testing/data/apng19-ref.png
index b9bf8229204..ebf3fe76a81 100644
--- a/chromium/third_party/blink/renderer/platform/testing/data/apng19-ref.png
+++ b/chromium/third_party/blink/renderer/platform/testing/data/apng19-ref.png
Binary files differ
diff --git a/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc b/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc
index dae01542af8..a2bb3a2c2ba 100644
--- a/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc
@@ -9,11 +9,11 @@ namespace blink {
FuzzedDataProvider::FuzzedDataProvider(const uint8_t* bytes, size_t num_bytes)
: provider_(bytes, num_bytes) {}
-CString FuzzedDataProvider::ConsumeBytesInRange(uint32_t min_bytes,
- uint32_t max_bytes) {
- size_t num_bytes = provider_.ConsumeIntegralInRange(min_bytes, max_bytes);
- std::vector<char> bytes = provider_.ConsumeBytes<char>(num_bytes);
- return CString(bytes.data(), bytes.size());
+String FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
+ std::string str = provider_.ConsumeRandomLengthString(max_length);
+ // FromUTF8 will return a null string if the input data contains invalid UTF-8
+ // sequences. Fall back to latin1 in those cases.
+ return String::FromUTF8WithLatin1Fallback(str.data(), str.length());
}
CString FuzzedDataProvider::ConsumeRemainingBytes() {
diff --git a/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h b/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h
index bcb6ac896da..0adc9158b66 100644
--- a/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h
+++ b/chromium/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h
@@ -8,6 +8,7 @@
#include "base/test/fuzzed_data_provider.h"
#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -19,10 +20,8 @@ class FuzzedDataProvider {
public:
FuzzedDataProvider(const uint8_t* bytes, size_t num_bytes);
- // Returns a string with length between minBytes and maxBytes. If the
- // length is greater than the length of the remaining data this is
- // equivalent to ConsumeRemainingBytes().
- CString ConsumeBytesInRange(uint32_t min_bytes, uint32_t max_bytes);
+ // Returns a string with length between 0 and max_length.
+ String ConsumeRandomLengthString(size_t max_length);
// Returns a String containing all remaining bytes of the input data.
CString ConsumeRemainingBytes();
diff --git a/chromium/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc b/chromium/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc
index 1c19652363a..bf9569fb032 100644
--- a/chromium/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/layer_tree_host_embedder.cc
@@ -20,7 +20,7 @@ LayerTreeHostEmbedder::LayerTreeHostEmbedder(
settings.layer_transforms_should_scale_layer_contents = true;
settings.single_thread_proxy_scheduler = false;
settings.use_layer_lists =
- RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled();
animation_host_ = cc::AnimationHost::CreateMainInstance();
diff --git a/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h b/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h
index 3276b78c970..2d7e53ccb51 100644
--- a/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h
+++ b/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h
@@ -13,19 +13,19 @@ namespace blink {
enum {
kBlinkGenPropertyTrees = 1 << 0,
- kSlimmingPaintV2 = 1 << 1,
+ kCompositeAfterPaint = 1 << 1,
kUnderInvalidationChecking = 1 << 2,
};
class PaintTestConfigurations
: public testing::WithParamInterface<unsigned>,
private ScopedBlinkGenPropertyTreesForTest,
- private ScopedSlimmingPaintV2ForTest,
+ private ScopedCompositeAfterPaintForTest,
private ScopedPaintUnderInvalidationCheckingForTest {
public:
PaintTestConfigurations()
: ScopedBlinkGenPropertyTreesForTest(GetParam() & kBlinkGenPropertyTrees),
- ScopedSlimmingPaintV2ForTest(GetParam() & kSlimmingPaintV2),
+ ScopedCompositeAfterPaintForTest(GetParam() & kCompositeAfterPaint),
ScopedPaintUnderInvalidationCheckingForTest(
GetParam() & kUnderInvalidationChecking) {}
~PaintTestConfigurations() {
@@ -37,15 +37,16 @@ class PaintTestConfigurations
#define INSTANTIATE_PAINT_TEST_CASE_P(test_class) \
INSTANTIATE_TEST_CASE_P( \
All, test_class, \
- ::testing::Values(0, kBlinkGenPropertyTrees, kSlimmingPaintV2))
+ ::testing::Values(0, kBlinkGenPropertyTrees, kCompositeAfterPaint))
-#define INSTANTIATE_SPV2_TEST_CASE_P(test_class) \
- INSTANTIATE_TEST_CASE_P(All, test_class, ::testing::Values(kSlimmingPaintV2))
+#define INSTANTIATE_CAP_TEST_CASE_P(test_class) \
+ INSTANTIATE_TEST_CASE_P(All, test_class, \
+ ::testing::Values(kCompositeAfterPaint))
#define INSTANTIATE_LAYER_LIST_TEST_CASE_P(test_class) \
INSTANTIATE_TEST_CASE_P( \
All, test_class, \
- ::testing::Values(kBlinkGenPropertyTrees, kSlimmingPaintV2))
+ ::testing::Values(kBlinkGenPropertyTrees, kCompositeAfterPaint))
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/testing/shaping_line_breaker_perf_test.cc b/chromium/third_party/blink/renderer/platform/testing/shaping_line_breaker_perf_test.cc
index 15219c4cbef..9ce988029fd 100644
--- a/chromium/third_party/blink/renderer/platform/testing/shaping_line_breaker_perf_test.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/shaping_line_breaker_perf_test.cc
@@ -25,6 +25,20 @@ static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
+struct HarfBuzzShaperCallbackContext {
+ const HarfBuzzShaper* shaper;
+ const Font* font;
+ TextDirection direction;
+};
+
+scoped_refptr<ShapeResult> HarfBuzzShaperCallback(void* untyped_context,
+ unsigned start,
+ unsigned end) {
+ HarfBuzzShaperCallbackContext* context =
+ static_cast<HarfBuzzShaperCallbackContext*>(untyped_context);
+ return context->shaper->Shape(context->font, context->direction, start, end);
+}
+
LayoutUnit ShapeText(ShapingLineBreaker* breaker,
LayoutUnit available_space,
unsigned string_length) {
@@ -127,8 +141,11 @@ TEST_F(ShapingLineBreakerPerfTest, ShapeLatinText) {
HarfBuzzShaper shaper(string);
scoped_refptr<const ShapeResult> reference_result =
shaper.Shape(&font, direction);
- ShapingLineBreaker reference_breaker(&shaper, &font, reference_result.get(),
- &break_iterator);
+ HarfBuzzShaperCallbackContext context{&shaper, &font,
+ reference_result->Direction()};
+ ShapingLineBreaker reference_breaker(reference_result, &break_iterator,
+ nullptr, HarfBuzzShaperCallback,
+ &context);
scoped_refptr<const ShapeResult> line;
LayoutUnit available_width_px(500);
@@ -138,7 +155,8 @@ TEST_F(ShapingLineBreakerPerfTest, ShapeLatinText) {
timer_.Reset();
do {
scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction);
- ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
LayoutUnit width = ShapeText(&breaker, available_width_px, len);
EXPECT_EQ(expected_width, width);
diff --git a/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc b/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
index c8d8b52392d..7a40ce4b5b5 100644
--- a/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
@@ -5,9 +5,13 @@
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h"
#include <memory>
+#include <vector>
+
#include "third_party/blink/public/platform/web_media_stream.h"
+#include "third_party/blink/public/platform/web_media_stream_source.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_source.h"
#include "third_party/blink/public/platform/web_rtc_rtp_transceiver.h"
#include "third_party/blink/public/platform/web_rtc_session_description.h"
#include "third_party/blink/public/platform/web_rtc_stats.h"
@@ -17,20 +21,43 @@ namespace blink {
namespace {
-class DummyWebRTCRtpSender : public WebRTCRtpSender {
+// Having a refcounted helper class allows multiple DummyWebRTCRtpSender to
+// share the same internal states.
+class DummyRtpSenderInternal
+ : public base::RefCountedThreadSafe<DummyRtpSenderInternal> {
private:
static uintptr_t last_id_;
public:
- DummyWebRTCRtpSender(WebMediaStreamTrack track)
+ DummyRtpSenderInternal(WebMediaStreamTrack track)
: id_(++last_id_), track_(std::move(track)) {}
+
+ uintptr_t id() const { return id_; }
+ WebMediaStreamTrack track() const { return track_; }
+ void set_track(WebMediaStreamTrack track) { track_ = std::move(track); }
+
+ private:
+ const uintptr_t id_;
+ WebMediaStreamTrack track_;
+};
+
+uintptr_t DummyRtpSenderInternal::last_id_ = 0;
+
+class DummyWebRTCRtpSender : public WebRTCRtpSender {
+ public:
+ DummyWebRTCRtpSender(WebMediaStreamTrack track)
+ : internal_(new DummyRtpSenderInternal(std::move(track))) {}
+ DummyWebRTCRtpSender(const DummyWebRTCRtpSender& other)
+ : internal_(other.internal_) {}
~DummyWebRTCRtpSender() override {}
+ scoped_refptr<DummyRtpSenderInternal> internal() const { return internal_; };
+
std::unique_ptr<WebRTCRtpSender> ShallowCopy() const override {
return nullptr;
}
- uintptr_t Id() const override { return id_; }
- WebMediaStreamTrack Track() const override { return track_; }
+ uintptr_t Id() const override { return internal_->id(); }
+ WebMediaStreamTrack Track() const override { return internal_->track(); }
WebVector<WebString> StreamIds() const override {
return std::vector<WebString>({WebString::FromUTF8("DummyStringId")});
}
@@ -47,37 +74,135 @@ class DummyWebRTCRtpSender : public WebRTCRtpSender {
void GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>,
blink::RTCStatsFilter) override {}
- void set_track(WebMediaStreamTrack track) { track_ = std::move(track); }
+ private:
+ scoped_refptr<DummyRtpSenderInternal> internal_;
+};
+
+class DummyWebRTCRtpReceiver : public WebRTCRtpReceiver {
+ private:
+ static uintptr_t last_id_;
+
+ public:
+ DummyWebRTCRtpReceiver(WebMediaStreamSource::Type type)
+ : id_(++last_id_), track_() {
+ if (type == WebMediaStreamSource::Type::kTypeAudio) {
+ WebMediaStreamSource web_source;
+ web_source.Initialize(WebString::FromUTF8("remoteAudioId"),
+ WebMediaStreamSource::Type::kTypeAudio,
+ WebString::FromUTF8("remoteAudioName"),
+ true /* remote */);
+ track_.Initialize(web_source.Id(), web_source);
+ } else {
+ DCHECK_EQ(type, WebMediaStreamSource::Type::kTypeVideo);
+ WebMediaStreamSource web_source;
+ web_source.Initialize(WebString::FromUTF8("remoteVideoId"),
+ WebMediaStreamSource::Type::kTypeVideo,
+ WebString::FromUTF8("remoteVideoName"),
+ true /* remote */);
+ track_.Initialize(web_source.Id(), web_source);
+ }
+ }
+ DummyWebRTCRtpReceiver(const DummyWebRTCRtpReceiver& other)
+ : id_(other.id_), track_(other.track_) {}
+ ~DummyWebRTCRtpReceiver() override {}
+
+ std::unique_ptr<WebRTCRtpReceiver> ShallowCopy() const override {
+ return nullptr;
+ }
+ uintptr_t Id() const override { return id_; }
+ const WebMediaStreamTrack& Track() const override { return track_; }
+ WebVector<WebString> StreamIds() const override {
+ return WebVector<WebString>();
+ }
+ WebVector<std::unique_ptr<WebRTCRtpSource>> GetSources() override {
+ return WebVector<std::unique_ptr<WebRTCRtpSource>>();
+ }
+ void GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>,
+ RTCStatsFilter) override {}
+ std::unique_ptr<webrtc::RtpParameters> GetParameters() const override {
+ return nullptr;
+ }
private:
const uintptr_t id_;
WebMediaStreamTrack track_;
};
-uintptr_t DummyWebRTCRtpSender::last_id_ = 0;
+uintptr_t DummyWebRTCRtpReceiver::last_id_ = 0;
+
+// Having a refcounted helper class allows multiple DummyWebRTCRtpTransceivers
+// to share the same internal states.
+class DummyTransceiverInternal
+ : public base::RefCountedThreadSafe<DummyTransceiverInternal> {
+ private:
+ static uintptr_t last_id_;
+
+ public:
+ DummyTransceiverInternal(WebMediaStreamSource::Type type,
+ WebMediaStreamTrack sender_track)
+ : id_(++last_id_),
+ sender_(std::move(sender_track)),
+ receiver_(type),
+ direction_(webrtc::RtpTransceiverDirection::kSendRecv) {
+ DCHECK(sender_.Track().IsNull() ||
+ sender_.Track().Source().GetType() == type);
+ }
+
+ uintptr_t id() const { return id_; }
+ DummyWebRTCRtpSender* sender() { return &sender_; }
+ std::unique_ptr<DummyWebRTCRtpSender> Sender() const {
+ return std::make_unique<DummyWebRTCRtpSender>(sender_);
+ }
+ DummyWebRTCRtpReceiver* receiver() { return &receiver_; }
+ std::unique_ptr<DummyWebRTCRtpReceiver> Receiver() const {
+ return std::make_unique<DummyWebRTCRtpReceiver>(receiver_);
+ }
+ webrtc::RtpTransceiverDirection direction() const { return direction_; }
+ void set_direction(webrtc::RtpTransceiverDirection direction) {
+ direction_ = direction;
+ }
+
+ private:
+ const uintptr_t id_;
+ DummyWebRTCRtpSender sender_;
+ DummyWebRTCRtpReceiver receiver_;
+ webrtc::RtpTransceiverDirection direction_;
+};
+
+uintptr_t DummyTransceiverInternal::last_id_ = 0;
+
+} // namespace
-class DummyRTCRtpTransceiver : public WebRTCRtpTransceiver {
+class MockWebRTCPeerConnectionHandler::DummyWebRTCRtpTransceiver
+ : public WebRTCRtpTransceiver {
public:
- DummyRTCRtpTransceiver(WebMediaStreamTrack track)
- : track_(std::move(track)) {}
- ~DummyRTCRtpTransceiver() override {}
+ DummyWebRTCRtpTransceiver(WebMediaStreamSource::Type type,
+ WebMediaStreamTrack track)
+ : internal_(new DummyTransceiverInternal(type, track)) {}
+ DummyWebRTCRtpTransceiver(const DummyWebRTCRtpTransceiver& other)
+ : internal_(other.internal_) {}
+ ~DummyWebRTCRtpTransceiver() override {}
+
+ scoped_refptr<DummyTransceiverInternal> internal() const { return internal_; }
WebRTCRtpTransceiverImplementationType ImplementationType() const override {
- return WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly;
+ return WebRTCRtpTransceiverImplementationType::kFullTransceiver;
}
- uintptr_t Id() const override { return 0u; }
+ uintptr_t Id() const override { return internal_->id(); }
WebString Mid() const override { return WebString(); }
std::unique_ptr<WebRTCRtpSender> Sender() const override {
- return std::make_unique<DummyWebRTCRtpSender>(track_);
+ return internal_->Sender();
}
std::unique_ptr<WebRTCRtpReceiver> Receiver() const override {
- return nullptr;
+ return internal_->Receiver();
}
bool Stopped() const override { return true; }
webrtc::RtpTransceiverDirection Direction() const override {
- return webrtc::RtpTransceiverDirection::kInactive;
+ return internal_->direction();
+ }
+ void SetDirection(webrtc::RtpTransceiverDirection direction) override {
+ internal_->set_direction(direction);
}
- void SetDirection(webrtc::RtpTransceiverDirection) override {}
base::Optional<webrtc::RtpTransceiverDirection> CurrentDirection()
const override {
return base::nullopt;
@@ -88,11 +213,9 @@ class DummyRTCRtpTransceiver : public WebRTCRtpTransceiver {
}
private:
- WebMediaStreamTrack track_;
+ scoped_refptr<DummyTransceiverInternal> internal_;
};
-} // namespace
-
MockWebRTCPeerConnectionHandler::MockWebRTCPeerConnectionHandler() = default;
MockWebRTCPeerConnectionHandler::~MockWebRTCPeerConnectionHandler() = default;
@@ -103,13 +226,19 @@ bool MockWebRTCPeerConnectionHandler::Initialize(
return true;
}
-void MockWebRTCPeerConnectionHandler::CreateOffer(
+std::vector<std::unique_ptr<WebRTCRtpTransceiver>>
+MockWebRTCPeerConnectionHandler::CreateOffer(
const WebRTCSessionDescriptionRequest&,
- const WebMediaConstraints&) {}
+ const WebMediaConstraints&) {
+ return {};
+}
-void MockWebRTCPeerConnectionHandler::CreateOffer(
+std::vector<std::unique_ptr<WebRTCRtpTransceiver>>
+MockWebRTCPeerConnectionHandler::CreateOffer(
const WebRTCSessionDescriptionRequest&,
- const WebRTCOfferOptions&) {}
+ const WebRTCOfferOptions&) {
+ return {};
+}
void MockWebRTCPeerConnectionHandler::CreateAnswer(
const WebRTCSessionDescriptionRequest&,
@@ -176,32 +305,51 @@ webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
MockWebRTCPeerConnectionHandler::AddTransceiverWithTrack(
const WebMediaStreamTrack& track,
const webrtc::RtpTransceiverInit&) {
- std::unique_ptr<WebRTCRtpTransceiver> transceiver =
- std::make_unique<DummyRTCRtpTransceiver>(track);
- return transceiver;
+ transceivers_.push_back(std::unique_ptr<DummyWebRTCRtpTransceiver>(
+ new DummyWebRTCRtpTransceiver(track.Source().GetType(), track)));
+ std::unique_ptr<DummyWebRTCRtpTransceiver> copy(
+ new DummyWebRTCRtpTransceiver(*transceivers_.back()));
+ return std::unique_ptr<WebRTCRtpTransceiver>(std::move(copy));
}
webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
MockWebRTCPeerConnectionHandler::AddTransceiverWithKind(
std::string kind,
const webrtc::RtpTransceiverInit&) {
- std::unique_ptr<WebRTCRtpTransceiver> transceiver =
- std::make_unique<DummyRTCRtpTransceiver>(WebMediaStreamTrack());
- return transceiver;
+ transceivers_.push_back(
+ std::unique_ptr<DummyWebRTCRtpTransceiver>(new DummyWebRTCRtpTransceiver(
+ kind == "audio" ? WebMediaStreamSource::Type::kTypeAudio
+ : WebMediaStreamSource::Type::kTypeVideo,
+ WebMediaStreamTrack())));
+ std::unique_ptr<DummyWebRTCRtpTransceiver> copy(
+ new DummyWebRTCRtpTransceiver(*transceivers_.back()));
+ return std::unique_ptr<WebRTCRtpTransceiver>(std::move(copy));
}
webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
MockWebRTCPeerConnectionHandler::AddTrack(const WebMediaStreamTrack& track,
const WebVector<WebMediaStream>&) {
- std::unique_ptr<WebRTCRtpTransceiver> transceiver =
- std::make_unique<DummyRTCRtpTransceiver>(track);
- return transceiver;
+ transceivers_.push_back(std::unique_ptr<DummyWebRTCRtpTransceiver>(
+ new DummyWebRTCRtpTransceiver(track.Source().GetType(), track)));
+ std::unique_ptr<DummyWebRTCRtpTransceiver> copy(
+ new DummyWebRTCRtpTransceiver(*transceivers_.back()));
+ return std::unique_ptr<WebRTCRtpTransceiver>(std::move(copy));
}
webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>>
MockWebRTCPeerConnectionHandler::RemoveTrack(WebRTCRtpSender* sender) {
- static_cast<DummyWebRTCRtpSender*>(sender)->set_track(WebMediaStreamTrack());
- return std::unique_ptr<WebRTCRtpTransceiver>(nullptr);
+ const DummyWebRTCRtpTransceiver* transceiver_of_sender = nullptr;
+ for (const auto& transceiver : transceivers_) {
+ if (transceiver->Sender()->Id() == sender->Id()) {
+ transceiver_of_sender = transceiver.get();
+ break;
+ }
+ }
+ transceiver_of_sender->internal()->sender()->internal()->set_track(
+ WebMediaStreamTrack());
+ std::unique_ptr<DummyWebRTCRtpTransceiver> copy(
+ new DummyWebRTCRtpTransceiver(*transceiver_of_sender));
+ return std::unique_ptr<WebRTCRtpTransceiver>(std::move(copy));
}
WebRTCDataChannelHandler* MockWebRTCPeerConnectionHandler::CreateDataChannel(
@@ -216,6 +364,11 @@ WebString MockWebRTCPeerConnectionHandler::Id() const {
return WebString();
}
+webrtc::PeerConnectionInterface*
+MockWebRTCPeerConnectionHandler::NativePeerConnection() {
+ return nullptr;
+}
+
std::unique_ptr<WebRTCPeerConnectionHandler>
TestingPlatformSupportWithWebRTC::CreateRTCPeerConnectionHandler(
WebRTCPeerConnectionHandlerClient*,
diff --git a/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h b/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
index e37585d7f1f..db89d47dcfe 100644
--- a/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
+++ b/chromium/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
@@ -8,7 +8,7 @@
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/platform/web_rtc_peer_connection_handler.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
-#include "third_party/webrtc/api/peerconnectioninterface.h"
+#include "third_party/webrtc/api/peer_connection_interface.h"
namespace blink {
@@ -23,10 +23,12 @@ class MockWebRTCPeerConnectionHandler : public WebRTCPeerConnectionHandler {
bool Initialize(const webrtc::PeerConnectionInterface::RTCConfiguration&,
const WebMediaConstraints&) override;
- void CreateOffer(const WebRTCSessionDescriptionRequest&,
- const WebMediaConstraints&) override;
- void CreateOffer(const WebRTCSessionDescriptionRequest&,
- const WebRTCOfferOptions&) override;
+ std::vector<std::unique_ptr<WebRTCRtpTransceiver>> CreateOffer(
+ const WebRTCSessionDescriptionRequest&,
+ const WebMediaConstraints&) override;
+ std::vector<std::unique_ptr<WebRTCRtpTransceiver>> CreateOffer(
+ const WebRTCSessionDescriptionRequest&,
+ const WebRTCOfferOptions&) override;
void CreateAnswer(const WebRTCSessionDescriptionRequest&,
const WebMediaConstraints&) override;
void CreateAnswer(const WebRTCSessionDescriptionRequest&,
@@ -64,6 +66,12 @@ class MockWebRTCPeerConnectionHandler : public WebRTCPeerConnectionHandler {
const WebRTCDataChannelInit&) override;
void Stop() override;
WebString Id() const override;
+ webrtc::PeerConnectionInterface* NativePeerConnection() override;
+
+ private:
+ class DummyWebRTCRtpTransceiver;
+
+ std::vector<std::unique_ptr<DummyWebRTCRtpTransceiver>> transceivers_;
};
class TestingPlatformSupportWithWebRTC : public TestingPlatformSupport {
diff --git a/chromium/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc b/chromium/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
index 93d1e97824b..b61d4c922a2 100644
--- a/chromium/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
@@ -55,6 +56,11 @@ void WebURLLoaderMock::ServeAsynchronousRequest(
delegate = default_delegate.get();
}
+ if (error) {
+ delegate->DidFail(client_, *error, data.size(), 0, 0);
+ return;
+ }
+
// didReceiveResponse() and didReceiveData() might end up getting ::cancel()
// to be called which will make the ResourceLoader to delete |this|.
base::WeakPtr<WebURLLoaderMock> self = weak_factory_.GetWeakPtr();
@@ -63,11 +69,6 @@ void WebURLLoaderMock::ServeAsynchronousRequest(
if (!self)
return;
- if (error) {
- delegate->DidFail(client_, *error, data.size(), 0, 0);
- return;
- }
-
data.ForEachSegment([this, &delegate, &self](const char* segment,
size_t segment_size,
size_t segment_offset) {
@@ -93,7 +94,8 @@ WebURL WebURLLoaderMock::ServeRedirect(
bool report_raw_headers = false;
bool follow = client_->WillFollowRedirect(
- redirect_url, redirect_url, WebString(),
+ redirect_url, redirect_url,
+ WebSecurityOrigin::Create(WebURL(redirect_url)), WebString(),
network::mojom::ReferrerPolicy::kDefault, request.HttpMethod(),
redirect_response, report_raw_headers);
// |this| might be deleted in willFollowRedirect().
diff --git a/chromium/third_party/blink/renderer/platform/text/bidi_resolver_test.cc b/chromium/third_party/blink/renderer/platform/text/bidi_resolver_test.cc
index a9a0187f0b1..fe3e7016575 100644
--- a/chromium/third_party/blink/renderer/platform/text/bidi_resolver_test.cc
+++ b/chromium/third_party/blink/renderer/platform/text/bidi_resolver_test.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/platform/text/bidi_resolver.h"
#include <fstream>
+
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/text/bidi_test_harness.h"
#include "third_party/blink/renderer/platform/text/text_run_iterator.h"
@@ -106,7 +108,7 @@ TEST(BidiResolver, ParagraphDirectionSurrogates) {
// Test broken surrogate: trail appearing before
// lead. (U+10858 units reversed)
{{0xDC58, 0xD802}, 2, TextDirection::kLtr, false}};
- for (size_t i = 0; i < arraysize(kTestData); ++i)
+ for (size_t i = 0; i < base::size(kTestData); ++i)
TestDirectionality(kTestData[i]);
}
diff --git a/chromium/third_party/blink/renderer/platform/text/character.cc b/chromium/third_party/blink/renderer/platform/text/character.cc
index e43dbced99a..5cf83cd640d 100644
--- a/chromium/third_party/blink/renderer/platform/text/character.cc
+++ b/chromium/third_party/blink/renderer/platform/text/character.cc
@@ -33,6 +33,8 @@
#include <unicode/uobject.h>
#include <unicode/uscript.h>
#include <algorithm>
+
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/text/character_property_data.h"
#include "third_party/blink/renderer/platform/text/icu_error.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -61,9 +63,9 @@ static icu::UnicodeSet* createUnicodeSet(const UChar32* characters,
return unicodeSet;
}
-#define CREATE_UNICODE_SET(name) \
- createUnicodeSet(name##Array, arraysize(name##Array), name##Ranges, \
- arraysize(name##Ranges))
+#define CREATE_UNICODE_SET(name) \
+ createUnicodeSet(name##Array, base::size(name##Array), name##Ranges, \
+ base::size(name##Ranges))
#define RETURN_HAS_PROPERTY(c, name) \
static icu::UnicodeSet* unicodeSet = nullptr; \
diff --git a/chromium/third_party/blink/renderer/platform/text/locale_icu.cc b/chromium/third_party/blink/renderer/platform/text/locale_icu.cc
index 13c08e0ec88..fec00ba595b 100644
--- a/chromium/third_party/blink/renderer/platform/text/locale_icu.cc
+++ b/chromium/third_party/blink/renderer/platform/text/locale_icu.cc
@@ -37,6 +37,7 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/wtf/date_math.h"
#include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -145,7 +146,7 @@ UDateFormat* LocaleICU::OpenDateFormat(UDateFormatStyle time_style,
const UChar kGmtTimezone[3] = {'G', 'M', 'T'};
UErrorCode status = U_ZERO_ERROR;
return udat_open(time_style, date_style, locale_.data(), kGmtTimezone,
- arraysize(kGmtTimezone), nullptr, -1, &status);
+ base::size(kGmtTimezone), nullptr, -1, &status);
}
// We cannot use udat_*Symbols API to get standalone month names to use in
@@ -259,8 +260,8 @@ void LocaleICU::InitializeCalendar() {
static std::unique_ptr<Vector<String>> CreateFallbackMonthLabels() {
std::unique_ptr<Vector<String>> labels = std::make_unique<Vector<String>>();
- labels->ReserveCapacity(arraysize(WTF::kMonthFullName));
- for (unsigned i = 0; i < arraysize(WTF::kMonthFullName); ++i)
+ labels->ReserveCapacity(base::size(WTF::kMonthFullName));
+ for (unsigned i = 0; i < base::size(WTF::kMonthFullName); ++i)
labels->push_back(WTF::kMonthFullName[i]);
return labels;
}
@@ -416,8 +417,8 @@ const Vector<String>& LocaleICU::ShortMonthLabels() {
return short_month_labels_;
}
}
- short_month_labels_.ReserveCapacity(arraysize(WTF::kMonthName));
- for (unsigned i = 0; i < arraysize(WTF::kMonthName); ++i)
+ short_month_labels_.ReserveCapacity(base::size(WTF::kMonthName));
+ for (unsigned i = 0; i < base::size(WTF::kMonthName); ++i)
short_month_labels_.push_back(WTF::kMonthName[i]);
return short_month_labels_;
}
diff --git a/chromium/third_party/blink/renderer/platform/text/locale_mac.mm b/chromium/third_party/blink/renderer/platform/text/locale_mac.mm
index 490dbff01e4..fdd237ec17a 100644
--- a/chromium/third_party/blink/renderer/platform/text/locale_mac.mm
+++ b/chromium/third_party/blink/renderer/platform/text/locale_mac.mm
@@ -33,7 +33,9 @@
#import <Foundation/NSDateFormatter.h>
#import <Foundation/NSLocale.h>
#include <memory>
+
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/language.h"
#include "third_party/blink/renderer/platform/web_test_support.h"
#include "third_party/blink/renderer/platform/wtf/date_math.h"
@@ -87,7 +89,8 @@ LocaleMac::LocaleMac(NSLocale* locale)
: locale_(locale),
gregorian_calendar_(
kAdoptNS,
- [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]),
+ [[NSCalendar alloc]
+ initWithCalendarIdentifier:NSCalendarIdentifierGregorian]),
did_initialize_number_data_(false) {
NSArray* available_languages = [NSLocale ISOLanguageCodes];
// NSLocale returns a lower case NSLocaleLanguageCode so we don't have care
@@ -127,7 +130,7 @@ const Vector<String>& LocaleMac::MonthLabels() {
month_labels_.push_back(String([array objectAtIndex:i]));
return month_labels_;
}
- for (unsigned i = 0; i < arraysize(WTF::kMonthFullName); ++i)
+ for (unsigned i = 0; i < base::size(WTF::kMonthFullName); ++i)
month_labels_.push_back(WTF::kMonthFullName[i]);
return month_labels_;
}
@@ -142,7 +145,7 @@ const Vector<String>& LocaleMac::WeekDayShortLabels() {
week_day_short_labels_.push_back(String([array objectAtIndex:i]));
return week_day_short_labels_;
}
- for (unsigned i = 0; i < arraysize(WTF::kWeekdayName); ++i) {
+ for (unsigned i = 0; i < base::size(WTF::kWeekdayName); ++i) {
// weekdayName starts with Monday.
week_day_short_labels_.push_back(WTF::kWeekdayName[(i + 6) % 7]);
}
@@ -254,7 +257,7 @@ const Vector<String>& LocaleMac::ShortMonthLabels() {
short_month_labels_.push_back([array objectAtIndex:i]);
return short_month_labels_;
}
- for (unsigned i = 0; i < arraysize(WTF::kMonthName); ++i)
+ for (unsigned i = 0; i < base::size(WTF::kMonthName); ++i)
short_month_labels_.push_back(WTF::kMonthName[i]);
return short_month_labels_;
}
diff --git a/chromium/third_party/blink/renderer/platform/text/locale_win.cc b/chromium/third_party/blink/renderer/platform/text/locale_win.cc
index 80fcf10e608..adbe5628d91 100644
--- a/chromium/third_party/blink/renderer/platform/text/locale_win.cc
+++ b/chromium/third_party/blink/renderer/platform/text/locale_win.cc
@@ -34,6 +34,7 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/date_components.h"
#include "third_party/blink/renderer/platform/language.h"
#include "third_party/blink/renderer/platform/text/date_time_format.h"
@@ -148,13 +149,13 @@ void LocaleWin::EnsureShortMonthLabels() {
LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
};
- short_month_labels_.ReserveCapacity(arraysize(kTypes));
- for (unsigned i = 0; i < arraysize(kTypes); ++i) {
+ short_month_labels_.ReserveCapacity(base::size(kTypes));
+ for (unsigned i = 0; i < base::size(kTypes); ++i) {
short_month_labels_.push_back(GetLocaleInfoString(kTypes[i]));
if (short_month_labels_.back().IsEmpty()) {
short_month_labels_.Shrink(0);
- short_month_labels_.ReserveCapacity(arraysize(WTF::kMonthName));
- for (unsigned m = 0; m < arraysize(WTF::kMonthName); ++m)
+ short_month_labels_.ReserveCapacity(base::size(WTF::kMonthName));
+ for (unsigned m = 0; m < base::size(WTF::kMonthName); ++m)
short_month_labels_.push_back(WTF::kMonthName[m]);
return;
}
@@ -274,13 +275,13 @@ void LocaleWin::EnsureMonthLabels() {
LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
};
- month_labels_.ReserveCapacity(arraysize(kTypes));
- for (unsigned i = 0; i < arraysize(kTypes); ++i) {
+ month_labels_.ReserveCapacity(base::size(kTypes));
+ for (unsigned i = 0; i < base::size(kTypes); ++i) {
month_labels_.push_back(GetLocaleInfoString(kTypes[i]));
if (month_labels_.back().IsEmpty()) {
month_labels_.Shrink(0);
- month_labels_.ReserveCapacity(arraysize(WTF::kMonthFullName));
- for (unsigned m = 0; m < arraysize(WTF::kMonthFullName); ++m)
+ month_labels_.ReserveCapacity(base::size(WTF::kMonthFullName));
+ for (unsigned m = 0; m < base::size(WTF::kMonthFullName); ++m)
month_labels_.push_back(WTF::kMonthFullName[m]);
return;
}
@@ -295,13 +296,13 @@ void LocaleWin::EnsureWeekDayShortLabels() {
LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
LOCALE_SABBREVDAYNAME6};
- week_day_short_labels_.ReserveCapacity(arraysize(kTypes));
- for (unsigned i = 0; i < arraysize(kTypes); ++i) {
+ week_day_short_labels_.ReserveCapacity(base::size(kTypes));
+ for (unsigned i = 0; i < base::size(kTypes); ++i) {
week_day_short_labels_.push_back(GetLocaleInfoString(kTypes[i]));
if (week_day_short_labels_.back().IsEmpty()) {
week_day_short_labels_.Shrink(0);
- week_day_short_labels_.ReserveCapacity(arraysize(WTF::kWeekdayName));
- for (unsigned w = 0; w < arraysize(WTF::kWeekdayName); ++w) {
+ week_day_short_labels_.ReserveCapacity(base::size(WTF::kWeekdayName));
+ for (unsigned w = 0; w < base::size(WTF::kWeekdayName); ++w) {
// weekdayName starts with Monday.
week_day_short_labels_.push_back(WTF::kWeekdayName[(w + 6) % 7]);
}
diff --git a/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc b/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
index 0160d67d515..731a52569d3 100644
--- a/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
+++ b/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -23,6 +23,7 @@
#include "third_party/blink/renderer/platform/text/text_break_iterator.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/text/character.h"
#include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -223,11 +224,11 @@ static const unsigned char kBreakAllLineBreakClassTable[][BA_LB_COUNT / 8 + 1] =
#undef DI
#undef AL
-static_assert(arraysize(kAsciiLineBreakTable) ==
+static_assert(base::size(kAsciiLineBreakTable) ==
kAsciiLineBreakTableLastChar - kAsciiLineBreakTableFirstChar +
1,
"asciiLineBreakTable should be consistent");
-static_assert(arraysize(kBreakAllLineBreakClassTable) == BA_LB_COUNT,
+static_assert(base::size(kBreakAllLineBreakClassTable) == BA_LB_COUNT,
"breakAllLineBreakClassTable should be consistent");
static inline bool ShouldBreakAfter(UChar last_ch, UChar ch, UChar next_ch) {
diff --git a/chromium/third_party/blink/renderer/platform/text/text_break_iterator.h b/chromium/third_party/blink/renderer/platform/text/text_break_iterator.h
index 8d1f1a5a8ef..f2472e4bd7b 100644
--- a/chromium/third_party/blink/renderer/platform/text/text_break_iterator.h
+++ b/chromium/third_party/blink/renderer/platform/text/text_break_iterator.h
@@ -22,14 +22,16 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TEXT_TEXT_BREAK_ITERATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TEXT_TEXT_BREAK_ITERATOR_H_
+#include <type_traits>
+
+#include <unicode/brkiter.h>
+
#include "base/macros.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
#include "third_party/blink/renderer/platform/wtf/text/unicode.h"
-#include <unicode/brkiter.h>
-
namespace blink {
typedef icu::BreakIterator TextBreakIterator;
@@ -143,33 +145,33 @@ class PLATFORM_EXPORT LazyLineBreakIterator final {
const String& GetString() const { return string_; }
UChar LastCharacter() const {
- static_assert(arraysize(prior_context_) == 2,
+ static_assert(std::extent<decltype(prior_context_)>() == 2,
"TextBreakIterator has unexpected prior context length");
return prior_context_[1];
}
UChar SecondToLastCharacter() const {
- static_assert(arraysize(prior_context_) == 2,
+ static_assert(std::extent<decltype(prior_context_)>() == 2,
"TextBreakIterator has unexpected prior context length");
return prior_context_[0];
}
void SetPriorContext(UChar last, UChar second_to_last) {
- static_assert(arraysize(prior_context_) == 2,
+ static_assert(std::extent<decltype(prior_context_)>() == 2,
"TextBreakIterator has unexpected prior context length");
prior_context_[0] = second_to_last;
prior_context_[1] = last;
}
void UpdatePriorContext(UChar last) {
- static_assert(arraysize(prior_context_) == 2,
+ static_assert(std::extent<decltype(prior_context_)>() == 2,
"TextBreakIterator has unexpected prior context length");
prior_context_[0] = prior_context_[1];
prior_context_[1] = last;
}
void ResetPriorContext() {
- static_assert(arraysize(prior_context_) == 2,
+ static_assert(std::extent<decltype(prior_context_)>() == 2,
"TextBreakIterator has unexpected prior context length");
prior_context_[0] = 0;
prior_context_[1] = 0;
@@ -181,7 +183,7 @@ class PLATFORM_EXPORT LazyLineBreakIterator final {
};
PriorContext GetPriorContext() const {
- static_assert(arraysize(prior_context_) == 2,
+ static_assert(std::extent<decltype(prior_context_)>() == 2,
"TextBreakIterator has unexpected prior context length");
if (prior_context_[1]) {
if (prior_context_[0])
diff --git a/chromium/third_party/blink/renderer/platform/text/unicode_utilities_test.cc b/chromium/third_party/blink/renderer/platform/text/unicode_utilities_test.cc
index 125a2158e2d..17a421e01b2 100644
--- a/chromium/third_party/blink/renderer/platform/text/unicode_utilities_test.cc
+++ b/chromium/third_party/blink/renderer/platform/text/unicode_utilities_test.cc
@@ -31,6 +31,8 @@
#include "third_party/blink/renderer/platform/text/unicode_utilities.h"
#include <unicode/uchar.h>
+
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -139,13 +141,13 @@ TEST(UnicodeUtilitiesTest, FoldQuoteMarkOrSoftHyphenTest) {
kRightSingleQuotationMarkCharacter,
kSoftHyphenCharacter};
- String string_to_fold(kCharactersToFold, arraysize(kCharactersToFold));
+ String string_to_fold(kCharactersToFold, base::size(kCharactersToFold));
Vector<UChar> buffer;
string_to_fold.AppendTo(buffer);
FoldQuoteMarksAndSoftHyphens(string_to_fold);
- const String folded_string("\"\"\"\'\'\'\0", arraysize(kCharactersToFold));
+ const String folded_string("\"\"\"\'\'\'\0", base::size(kCharactersToFold));
EXPECT_EQ(string_to_fold, folded_string);
FoldQuoteMarksAndSoftHyphens(buffer.data(), buffer.size());
@@ -158,37 +160,37 @@ TEST(UnicodeUtilitiesTest, OnlyKanaLettersEqualityTest) {
// Check that non-Kana letters will be skipped.
EXPECT_TRUE(CheckOnlyKanaLettersInStrings(
- kNonKanaString1, arraysize(kNonKanaString1), kNonKanaString2,
- arraysize(kNonKanaString2)));
+ kNonKanaString1, base::size(kNonKanaString1), kNonKanaString2,
+ base::size(kNonKanaString2)));
const UChar kKanaString[] = {'e', 'f', 'g', 0x3041};
EXPECT_FALSE(CheckOnlyKanaLettersInStrings(
- kKanaString, arraysize(kKanaString), kNonKanaString2,
- arraysize(kNonKanaString2)));
+ kKanaString, base::size(kKanaString), kNonKanaString2,
+ base::size(kNonKanaString2)));
// Compare with self.
- EXPECT_TRUE(CheckOnlyKanaLettersInStrings(kKanaString, arraysize(kKanaString),
- kKanaString,
- arraysize(kKanaString)));
+ EXPECT_TRUE(
+ CheckOnlyKanaLettersInStrings(kKanaString, base::size(kKanaString),
+ kKanaString, base::size(kKanaString)));
UChar voiced_kana_string1[] = {0x3042, 0x3099};
UChar voiced_kana_string2[] = {0x3042, 0x309A};
// Comparing strings with different sound marks should fail.
EXPECT_FALSE(CheckOnlyKanaLettersInStrings(
- voiced_kana_string1, arraysize(voiced_kana_string1), voiced_kana_string2,
- arraysize(voiced_kana_string2)));
+ voiced_kana_string1, base::size(voiced_kana_string1), voiced_kana_string2,
+ base::size(voiced_kana_string2)));
// Now strings will be the same.
voiced_kana_string2[1] = 0x3099;
EXPECT_TRUE(CheckOnlyKanaLettersInStrings(
- voiced_kana_string1, arraysize(voiced_kana_string1), voiced_kana_string2,
- arraysize(voiced_kana_string2)));
+ voiced_kana_string1, base::size(voiced_kana_string1), voiced_kana_string2,
+ base::size(voiced_kana_string2)));
voiced_kana_string2[0] = 0x3043;
EXPECT_FALSE(CheckOnlyKanaLettersInStrings(
- voiced_kana_string1, arraysize(voiced_kana_string1), voiced_kana_string2,
- arraysize(voiced_kana_string2)));
+ voiced_kana_string1, base::size(voiced_kana_string1), voiced_kana_string2,
+ base::size(voiced_kana_string2)));
}
TEST(UnicodeUtilitiesTest, StringsWithKanaLettersTest) {
@@ -196,53 +198,53 @@ TEST(UnicodeUtilitiesTest, StringsWithKanaLettersTest) {
const UChar kNonKanaString2[] = {'a', 'b', 'c'};
// Check that non-Kana letters will be compared.
- EXPECT_TRUE(CheckKanaStringsEqual(kNonKanaString1, arraysize(kNonKanaString1),
- kNonKanaString2,
- arraysize(kNonKanaString2)));
+ EXPECT_TRUE(
+ CheckKanaStringsEqual(kNonKanaString1, base::size(kNonKanaString1),
+ kNonKanaString2, base::size(kNonKanaString2)));
const UChar kKanaString[] = {'a', 'b', 'c', 0x3041};
- EXPECT_FALSE(CheckKanaStringsEqual(kKanaString, arraysize(kKanaString),
+ EXPECT_FALSE(CheckKanaStringsEqual(kKanaString, base::size(kKanaString),
kNonKanaString2,
- arraysize(kNonKanaString2)));
+ base::size(kNonKanaString2)));
// Compare with self.
- EXPECT_TRUE(CheckKanaStringsEqual(kKanaString, arraysize(kKanaString),
- kKanaString, arraysize(kKanaString)));
+ EXPECT_TRUE(CheckKanaStringsEqual(kKanaString, base::size(kKanaString),
+ kKanaString, base::size(kKanaString)));
const UChar kKanaString2[] = {'x', 'y', 'z', 0x3041};
// Comparing strings with different non-Kana letters should fail.
- EXPECT_FALSE(CheckKanaStringsEqual(kKanaString, arraysize(kKanaString),
- kKanaString2, arraysize(kKanaString2)));
+ EXPECT_FALSE(CheckKanaStringsEqual(kKanaString, base::size(kKanaString),
+ kKanaString2, base::size(kKanaString2)));
const UChar kKanaString3[] = {'a', 'b', 'c', 0x3042, 0x3099, 'm', 'n', 'o'};
// Check that non-Kana letters after Kana letters will be compared.
- EXPECT_TRUE(CheckKanaStringsEqual(kKanaString3, arraysize(kKanaString3),
- kKanaString3, arraysize(kKanaString3)));
+ EXPECT_TRUE(CheckKanaStringsEqual(kKanaString3, base::size(kKanaString3),
+ kKanaString3, base::size(kKanaString3)));
const UChar kKanaString4[] = {'a', 'b', 'c', 0x3042, 0x3099,
'm', 'n', 'o', 'p'};
// And now comparing should fail.
- EXPECT_FALSE(CheckKanaStringsEqual(kKanaString3, arraysize(kKanaString3),
- kKanaString4, arraysize(kKanaString4)));
+ EXPECT_FALSE(CheckKanaStringsEqual(kKanaString3, base::size(kKanaString3),
+ kKanaString4, base::size(kKanaString4)));
UChar voiced_kana_string1[] = {0x3042, 0x3099};
UChar voiced_kana_string2[] = {0x3042, 0x309A};
// Comparing strings with different sound marks should fail.
EXPECT_FALSE(CheckKanaStringsEqual(
- voiced_kana_string1, arraysize(voiced_kana_string1), voiced_kana_string2,
- arraysize(voiced_kana_string2)));
+ voiced_kana_string1, base::size(voiced_kana_string1), voiced_kana_string2,
+ base::size(voiced_kana_string2)));
// Now strings will be the same.
voiced_kana_string2[1] = 0x3099;
EXPECT_TRUE(CheckKanaStringsEqual(
- voiced_kana_string1, arraysize(voiced_kana_string1), voiced_kana_string2,
- arraysize(voiced_kana_string2)));
+ voiced_kana_string1, base::size(voiced_kana_string1), voiced_kana_string2,
+ base::size(voiced_kana_string2)));
voiced_kana_string2[0] = 0x3043;
EXPECT_FALSE(CheckKanaStringsEqual(
- voiced_kana_string1, arraysize(voiced_kana_string1), voiced_kana_string2,
- arraysize(voiced_kana_string2)));
+ voiced_kana_string1, base::size(voiced_kana_string1), voiced_kana_string2,
+ base::size(voiced_kana_string2)));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/timer_test.cc b/chromium/third_party/blink/renderer/platform/timer_test.cc
index 1a578779b39..fa9e765cb94 100644
--- a/chromium/third_party/blink/renderer/platform/timer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/timer_test.cc
@@ -617,7 +617,7 @@ TEST_F(TimerTest, RunOnHeapTimer) {
scoped_refptr<OnHeapTimerOwner::Record> record =
OnHeapTimerOwner::Record::Create();
Persistent<OnHeapTimerOwner> owner =
- new OnHeapTimerOwner(record, GetTaskRunner());
+ MakeGarbageCollected<OnHeapTimerOwner>(record, GetTaskRunner());
owner->StartOneShot(TimeDelta(), FROM_HERE);
@@ -630,7 +630,7 @@ TEST_F(TimerTest, DestructOnHeapTimer) {
scoped_refptr<OnHeapTimerOwner::Record> record =
OnHeapTimerOwner::Record::Create();
Persistent<OnHeapTimerOwner> owner =
- new OnHeapTimerOwner(record, GetTaskRunner());
+ MakeGarbageCollected<OnHeapTimerOwner>(record, GetTaskRunner());
record->Dispose();
owner->StartOneShot(TimeDelta(), FROM_HERE);
@@ -650,7 +650,7 @@ TEST_F(TimerTest, MarkOnHeapTimerAsUnreachable) {
scoped_refptr<OnHeapTimerOwner::Record> record =
OnHeapTimerOwner::Record::Create();
Persistent<OnHeapTimerOwner> owner =
- new OnHeapTimerOwner(record, GetTaskRunner());
+ MakeGarbageCollected<OnHeapTimerOwner>(record, GetTaskRunner());
record->Dispose();
owner->StartOneShot(TimeDelta(), FROM_HERE);
diff --git a/chromium/third_party/blink/renderer/platform/transforms/DEPS b/chromium/third_party/blink/renderer/platform/transforms/DEPS
index 4058e92e78e..ccd3feed74f 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/DEPS
+++ b/chromium/third_party/blink/renderer/platform/transforms/DEPS
@@ -11,3 +11,12 @@ include_rules = [
"+third_party/blink/renderer/platform/json",
"+third_party/blink/renderer/platform/wtf",
]
+
+specific_include_rules = {
+ # Additional allowed includes for tests.
+ ".*_test(_.*)?\.(cc|h)" : [
+ # Test harness may use cc geometry test utilities.
+ # Avoid reimplementing fuzzy matrix comparison.
+ "+cc/test/geometry_test_utils.h"
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc b/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc
index 1430d4034b5..95d9ae3ba88 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc
@@ -48,8 +48,8 @@ void InterpolatedTransformOperation::Apply(
const FloatSize& border_box_size) const {
TransformationMatrix from_transform;
TransformationMatrix to_transform;
- from.Apply(border_box_size, from_transform);
- to.Apply(border_box_size, to_transform);
+ from.ApplyRemaining(border_box_size, starting_index, from_transform);
+ to.ApplyRemaining(border_box_size, starting_index, to_transform);
to_transform.Blend(from_transform, progress);
transform.Multiply(to_transform);
@@ -72,7 +72,7 @@ scoped_refptr<TransformOperation> InterpolatedTransformOperation::Blend(
from_operations.Operations().push_back(
const_cast<TransformOperation*>(from));
return InterpolatedTransformOperation::Create(this_operations,
- from_operations, progress);
+ from_operations, 0, progress);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
index a69bc6a4c19..9020146f46a 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
@@ -43,9 +43,10 @@ class PLATFORM_EXPORT InterpolatedTransformOperation final
static scoped_refptr<InterpolatedTransformOperation> Create(
const TransformOperations& from,
const TransformOperations& to,
+ int starting_index,
double progress) {
return base::AdoptRef(
- new InterpolatedTransformOperation(from, to, progress));
+ new InterpolatedTransformOperation(from, to, starting_index, progress));
}
bool CanBlendWith(const TransformOperation& other) const override {
@@ -64,7 +65,7 @@ class PLATFORM_EXPORT InterpolatedTransformOperation final
double progress,
bool blend_to_identity = false) override;
scoped_refptr<TransformOperation> Zoom(double factor) final {
- return Create(from.Zoom(factor), to.Zoom(factor), progress);
+ return Create(from.Zoom(factor), to.Zoom(factor), starting_index, progress);
}
bool DependsOnBoxSize() const override {
@@ -73,11 +74,19 @@ class PLATFORM_EXPORT InterpolatedTransformOperation final
InterpolatedTransformOperation(const TransformOperations& from,
const TransformOperations& to,
+ int starting_index,
double progress)
- : from(from), to(to), progress(progress) {}
+ : from(from),
+ to(to),
+ starting_index(starting_index),
+ progress(progress) {}
const TransformOperations from;
const TransformOperations to;
+ // Number of operations to skip from the start of each list. By spec,
+ // pairwise interpolations are performed for compatible operations at the
+ // start of the list and matrix interpolation for the remainder.
+ int starting_index;
double progress;
};
diff --git a/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc b/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc
index 2238948ca78..50bb4cf2066 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc
@@ -38,14 +38,20 @@ scoped_refptr<TransformOperation> Matrix3DTransformOperation::Blend(
if (from && !from->IsSameType(*this))
return this;
- // Convert the TransformOperations into matrices
+ // Convert the TransformOperations into matrices. Fail the blend operation
+ // if either of the matrices is non-invertible.
FloatSize size;
TransformationMatrix from_t;
TransformationMatrix to_t;
- if (from)
+ if (from) {
from->Apply(from_t, size);
+ if (!from_t.IsInvertible())
+ return nullptr;
+ }
Apply(to_t, size);
+ if (!to_t.IsInvertible())
+ return nullptr;
if (blend_to_identity)
std::swap(from_t, to_t);
diff --git a/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc b/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
index 5cc3d0ca48b..8cf0648c896 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
@@ -35,10 +35,14 @@ scoped_refptr<TransformOperation> MatrixTransformOperation::Blend(
// convert the TransformOperations into matrices
TransformationMatrix from_t;
TransformationMatrix to_t(a_, b_, c_, d_, e_, f_);
+ if (!to_t.IsInvertible())
+ return nullptr;
if (from) {
const MatrixTransformOperation* m =
static_cast<const MatrixTransformOperation*>(from);
from_t.SetMatrix(m->a_, m->b_, m->c_, m->d_, m->e_, m->f_);
+ if (!from_t.IsInvertible())
+ return nullptr;
}
if (blend_to_identity)
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transform_operations.cc b/chromium/third_party/blink/renderer/platform/transforms/transform_operations.cc
index 68faf86e6fb..213314da18f 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transform_operations.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/transform_operations.cc
@@ -49,87 +49,117 @@ bool TransformOperations::operator==(const TransformOperations& o) const {
return true;
}
-bool TransformOperations::OperationsMatch(
- const TransformOperations& other) const {
- wtf_size_t num_operations = Operations().size();
- if (num_operations != other.Operations().size())
- return false;
+void TransformOperations::ApplyRemaining(const FloatSize& border_box_size,
+ wtf_size_t start,
+ TransformationMatrix& t) const {
+ for (wtf_size_t i = start; i < operations_.size(); i++) {
+ operations_[i]->Apply(t, border_box_size);
+ }
+}
+wtf_size_t TransformOperations::MatchingPrefixLength(
+ const TransformOperations& other) const {
+ wtf_size_t num_operations =
+ std::min(Operations().size(), other.Operations().size());
for (wtf_size_t i = 0; i < num_operations; ++i) {
if (Operations()[i]->PrimitiveType() !=
other.Operations()[i]->PrimitiveType()) {
- return false;
+ // Remaining operations in each operations list require matrix/matrix3d
+ // interpolation.
+ return i;
}
}
- return true;
+ // If the operations match to the length of the shorter list, then pad its
+ // length with the matching identity operations.
+ // https://drafts.csswg.org/css-transforms/#transform-function-lists
+ return std::max(Operations().size(), other.Operations().size());
}
-TransformOperations TransformOperations::BlendByMatchingOperations(
+TransformOperations TransformOperations::BlendPrefixByMatchingOperations(
const TransformOperations& from,
- const double& progress) const {
+ wtf_size_t matching_prefix_length,
+ double progress,
+ bool* success) const {
TransformOperations result;
-
wtf_size_t from_size = from.Operations().size();
wtf_size_t to_size = Operations().size();
- wtf_size_t size = std::max(from_size, to_size);
- for (wtf_size_t i = 0; i < size; i++) {
+ for (wtf_size_t i = 0; i < matching_prefix_length; i++) {
scoped_refptr<TransformOperation> from_operation =
(i < from_size) ? from.Operations()[i].get() : nullptr;
scoped_refptr<TransformOperation> to_operation =
(i < to_size) ? Operations()[i].get() : nullptr;
+
scoped_refptr<TransformOperation> blended_operation =
to_operation
? to_operation->Blend(from_operation.get(), progress)
: (from_operation ? from_operation->Blend(nullptr, progress, true)
: nullptr);
+
if (blended_operation)
result.Operations().push_back(blended_operation);
else {
- scoped_refptr<TransformOperation> identity_operation =
- IdentityTransformOperation::Create();
- if (progress > 0.5)
- result.Operations().push_back(to_operation ? to_operation
- : identity_operation);
- else
- result.Operations().push_back(from_operation ? from_operation
- : identity_operation);
+ *success = false;
+ return result;
}
}
-
return result;
}
scoped_refptr<TransformOperation>
-TransformOperations::BlendByUsingMatrixInterpolation(
+TransformOperations::BlendRemainingByUsingMatrixInterpolation(
const TransformOperations& from,
+ wtf_size_t matching_prefix_length,
double progress) const {
- if (DependsOnBoxSize() || from.DependsOnBoxSize())
- return InterpolatedTransformOperation::Create(from, *this, progress);
+ // Not safe to use a cached transform if any of the operations are size
+ // dependent.
+ if (DependsOnBoxSize() || from.DependsOnBoxSize()) {
+ return InterpolatedTransformOperation::Create(
+ from, *this, matching_prefix_length, progress);
+ }
// Evaluate blended matrix here to avoid creating a nested data structure of
// unbounded depth.
TransformationMatrix from_transform;
TransformationMatrix to_transform;
- from.Apply(FloatSize(), from_transform);
- Apply(FloatSize(), to_transform);
+ from.ApplyRemaining(FloatSize(), matching_prefix_length, from_transform);
+ ApplyRemaining(FloatSize(), matching_prefix_length, to_transform);
+
+ // Fallback to discrete interpolation if either transform matrix is singular.
+ if (!(from_transform.IsInvertible() && to_transform.IsInvertible())) {
+ return nullptr;
+ }
+
to_transform.Blend(from_transform, progress);
return Matrix3DTransformOperation::Create(to_transform);
}
// https://drafts.csswg.org/css-transforms-1/#interpolation-of-transforms
+// TODO(crbug.com/914397): Consolidate blink and cc implementations of transform
+// interpolation.
TransformOperations TransformOperations::Blend(const TransformOperations& from,
double progress) const {
if (from == *this || (!from.size() && !size()))
return *this;
- // If either list is empty, use blendByMatchingOperations which has special
- // logic for this case.
- if (!from.size() || !size() || from.OperationsMatch(*this))
- return BlendByMatchingOperations(from, progress);
-
- TransformOperations result;
- result.Operations().push_back(
- BlendByUsingMatrixInterpolation(from, progress));
+ wtf_size_t matching_prefix_length = MatchingPrefixLength(from);
+ wtf_size_t max_path_length =
+ std::max(Operations().size(), from.Operations().size());
+
+ bool success = true;
+ TransformOperations result = BlendPrefixByMatchingOperations(
+ from, matching_prefix_length, progress, &success);
+ if (success && matching_prefix_length < max_path_length) {
+ scoped_refptr<TransformOperation> matrix_op =
+ BlendRemainingByUsingMatrixInterpolation(from, matching_prefix_length,
+ progress);
+ if (matrix_op)
+ result.Operations().push_back(matrix_op);
+ else
+ success = false;
+ }
+ if (!success) {
+ return progress < 0.5 ? from : *this;
+ }
return result;
}
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h b/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h
index b0d7f1aa8b4..e01e36b3d40 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h
@@ -48,11 +48,21 @@ class PLATFORM_EXPORT TransformOperations {
bool operator==(const TransformOperations& o) const;
bool operator!=(const TransformOperations& o) const { return !(*this == o); }
- void Apply(const FloatSize& sz, TransformationMatrix& t) const {
+ // Constructs a transformation matrix from the operations. The parameter
+ // |border_box_size| is used when computing styles that are size-dependent.
+ void Apply(const FloatSize& border_box_size, TransformationMatrix& t) const {
for (auto& operation : operations_)
- operation->Apply(t, sz);
+ operation->Apply(t, border_box_size);
}
+ // Constructs a transformation matrix from the operations starting from index
+ // |start|. This process facilitates mixing pairwise operations for a common
+ // prefix and matrix interpolation for the remainder. The parameter
+ // |border_box_size| is used when computing styles that are size-dependent.
+ void ApplyRemaining(const FloatSize& border_box_size,
+ wtf_size_t start,
+ TransformationMatrix& t) const;
+
// Return true if any of the operation types are 3D operation types (even if
// the values describe affine transforms)
bool Has3DOperation() const {
@@ -80,7 +90,7 @@ class PLATFORM_EXPORT TransformOperations {
return false;
}
- bool OperationsMatch(const TransformOperations&) const;
+ wtf_size_t MatchingPrefixLength(const TransformOperations&) const;
void clear() { operations_.clear(); }
@@ -101,11 +111,17 @@ class PLATFORM_EXPORT TransformOperations {
const double& min_progress,
const double& max_progress,
FloatBox* bounds) const;
- TransformOperations BlendByMatchingOperations(const TransformOperations& from,
- const double& progress) const;
- scoped_refptr<TransformOperation> BlendByUsingMatrixInterpolation(
+
+ TransformOperations BlendPrefixByMatchingOperations(
const TransformOperations& from,
+ wtf_size_t matching_prefix_length,
+ double progress,
+ bool* success) const;
+ scoped_refptr<TransformOperation> BlendRemainingByUsingMatrixInterpolation(
+ const TransformOperations& from,
+ wtf_size_t matching_prefix_length,
double progress) const;
+
TransformOperations Blend(const TransformOperations& from,
double progress) const;
TransformOperations Add(const TransformOperations& addend) const;
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc b/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
index 02db9ce8037..288d83c1149 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/platform/transforms/transform_operations.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/geometry/float_box.h"
#include "third_party/blink/renderer/platform/geometry/float_box_test_helpers.h"
@@ -118,8 +119,8 @@ TEST(TransformOperationsTest, EmpiricalAnimatedTranslatedBoundsTest) {
// [0,1].
float progress[][2] = {{0, 1}, {-.25, 1.25}};
- for (size_t i = 0; i < arraysize(test_transforms); ++i) {
- for (size_t j = 0; j < arraysize(progress); ++j) {
+ for (size_t i = 0; i < base::size(test_transforms); ++i) {
+ for (size_t j = 0; j < base::size(progress); ++j) {
TransformOperations from_ops;
TransformOperations to_ops;
from_ops.Operations().push_back(TranslateTransformOperation::Create(
@@ -181,8 +182,8 @@ TEST(TransformOperationsTest, EmpiricalAnimatedScaleBoundsTest) {
// [0,1].
float progress[][2] = {{0, 1}, {-.25f, 1.25f}};
- for (size_t i = 0; i < arraysize(test_transforms); ++i) {
- for (size_t j = 0; j < arraysize(progress); ++j) {
+ for (size_t i = 0; i < base::size(test_transforms); ++i) {
+ for (size_t j = 0; j < base::size(progress); ++j) {
TransformOperations from_ops;
TransformOperations to_ops;
from_ops.Operations().push_back(TranslateTransformOperation::Create(
@@ -213,7 +214,7 @@ TEST(TransformOperationsTest, AbsoluteAnimatedRotationBounds) {
// 2 * sqrt(2) should give the same result.
float sizes[] = {0, 0.1f, sqrt2, 2 * sqrt2};
to_ops.BlendedBoundsForBox(box, from_ops, 0, 1, &bounds);
- for (size_t i = 0; i < arraysize(sizes); ++i) {
+ for (size_t i = 0; i < base::size(sizes); ++i) {
box.SetSize(FloatPoint3D(sizes[i], sizes[i], 0));
EXPECT_TRUE(to_ops.BlendedBoundsForBox(box, from_ops, 0, 1, &bounds));
@@ -284,9 +285,9 @@ TEST(TransformOperationsTest, AbsoluteAnimatedOnAxisRotationBounds) {
EXPECT_PRED_FORMAT2(float_box_test::AssertAlmostEqual, box, bounds);
}
-// This would have been best as anonymous structs, but |arraysize|
+// This would have been best as anonymous structs, but |base::size|
// does not get along with anonymous structs once we support C++11
-// arraysize will automatically support anonymous structs.
+// base::size will automatically support anonymous structs.
struct ProblematicAxisTest {
double x;
@@ -314,7 +315,7 @@ TEST(TransformOperationsTest, AbsoluteAnimatedProblematicAxisRotationBounds) {
{0, 1, 1, FloatBox(-1, dim1, dim1, 2, dim2, dim2)},
{1, 0, 1, FloatBox(dim1, -1, dim1, dim2, 2, dim2)}};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
float x = tests[i].x;
float y = tests[i].y;
float z = tests[i].z;
@@ -346,9 +347,9 @@ TEST(TransformOperationsTest, BlendedBoundsForRotationEmpiricalTests) {
float progress[][2] = {{0, 1}, {-0.25f, 1.25f}};
- for (size_t i = 0; i < arraysize(axes); ++i) {
- for (size_t j = 0; j < arraysize(angles); ++j) {
- for (size_t k = 0; k < arraysize(progress); ++k) {
+ for (size_t i = 0; i < base::size(axes); ++i) {
+ for (size_t j = 0; j < base::size(angles); ++j) {
+ for (size_t k = 0; k < base::size(progress); ++k) {
float x = axes[i][0];
float y = axes[i][1];
float z = axes[i][2];
@@ -394,8 +395,8 @@ TEST(TransformOperationsTest, EmpiricalAnimatedPerspectiveBoundsTest) {
float progress[][2] = {{0, 1}, {-0.1f, 1.1f}};
- for (size_t i = 0; i < arraysize(depths); ++i) {
- for (size_t j = 0; j < arraysize(progress); ++j) {
+ for (size_t i = 0; i < base::size(depths); ++i) {
+ for (size_t j = 0; j < base::size(progress); ++j) {
TransformOperations from_ops;
TransformOperations to_ops;
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
index e4d3653082f..16d4313eb75 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
@@ -1713,11 +1713,28 @@ static inline void BlendFloat(double& from, double to, double progress) {
from = from + (to - from) * progress;
}
+bool TransformationMatrix::Is2dTransform() const {
+ if (!IsFlat())
+ return false;
+
+ // Check perspective.
+ if (matrix_[0][3] != 0 || matrix_[1][3] != 0 || matrix_[2][3] != 0 ||
+ matrix_[3][3] != 1)
+ return false;
+
+ return true;
+}
+
void TransformationMatrix::Blend(const TransformationMatrix& from,
double progress) {
if (from.IsIdentity() && IsIdentity())
return;
+ if (from.Is2dTransform() && Is2dTransform()) {
+ Blend2D(from, progress);
+ return;
+ }
+
// decompose
DecomposedType from_decomp;
DecomposedType to_decomp;
@@ -1748,6 +1765,40 @@ void TransformationMatrix::Blend(const TransformationMatrix& from,
Recompose(from_decomp);
}
+void TransformationMatrix::Blend2D(const TransformationMatrix& from,
+ double progress) {
+ // Decompose into scale, rotate, translate and skew transforms.
+ Decomposed2dType from_decomp;
+ Decomposed2dType to_decomp;
+ if (!from.Decompose2D(from_decomp) || !Decompose2D(to_decomp)) {
+ if (progress < 0.5)
+ *this = from;
+ return;
+ }
+
+ // Take the shorter of the clockwise or counter-clockwise paths.
+ double rotation = abs(from_decomp.angle - to_decomp.angle);
+ DCHECK(rotation < 2 * M_PI);
+ if (rotation > M_PI) {
+ if (from_decomp.angle > to_decomp.angle) {
+ from_decomp.angle -= 2 * M_PI;
+ } else {
+ to_decomp.angle -= 2 * M_PI;
+ }
+ }
+
+ // Interpolate.
+ BlendFloat(from_decomp.scale_x, to_decomp.scale_x, progress);
+ BlendFloat(from_decomp.scale_y, to_decomp.scale_y, progress);
+ BlendFloat(from_decomp.skew_xy, to_decomp.skew_xy, progress);
+ BlendFloat(from_decomp.translate_x, to_decomp.translate_x, progress);
+ BlendFloat(from_decomp.translate_y, to_decomp.translate_y, progress);
+ BlendFloat(from_decomp.angle, to_decomp.angle, progress);
+
+ // Recompose.
+ Recompose2D(from_decomp);
+}
+
bool TransformationMatrix::Decompose(DecomposedType& decomp) const {
if (IsIdentity()) {
memset(&decomp, 0, sizeof(decomp));
@@ -1762,6 +1813,100 @@ bool TransformationMatrix::Decompose(DecomposedType& decomp) const {
return true;
}
+// Decompose a 2D transformation matrix of the form:
+// [m11 m21 0 m41]
+// [m12 m22 0 m42]
+// [ 0 0 1 0 ]
+// [ 0 0 0 1 ]
+//
+// The decomposition is of the form:
+// M = translate * rotate * skew * scale
+// [1 0 0 Tx] [cos(R) -sin(R) 0 0] [1 K 0 0] [Sx 0 0 0]
+// = [0 1 0 Ty] [sin(R) cos(R) 0 0] [0 1 0 0] [0 Sy 0 0]
+// [0 0 1 0 ] [ 0 0 1 0] [0 0 1 0] [0 0 1 0]
+// [0 0 0 1 ] [ 0 0 0 1] [0 0 0 1] [0 0 0 1]
+//
+bool TransformationMatrix::Decompose2D(Decomposed2dType& decomp) const {
+ if (!Is2dTransform()) {
+ LOG(ERROR) << "2-D decomposition cannot be performed on a 3-D transform.";
+ return false;
+ }
+
+ double m11 = matrix_[0][0];
+ double m21 = matrix_[1][0];
+ double m12 = matrix_[0][1];
+ double m22 = matrix_[1][1];
+
+ double determinant = m11 * m22 - m12 * m21;
+ // Test for matrix being singular.
+ if (determinant == 0) {
+ return false;
+ }
+
+ // Translation transform.
+ // [m11 m21 0 m41] [1 0 0 Tx] [m11 m21 0 0]
+ // [m12 m22 0 m42] = [0 1 0 Ty] [m12 m22 0 0]
+ // [ 0 0 1 0 ] [0 0 1 0 ] [ 0 0 1 0]
+ // [ 0 0 0 1 ] [0 0 0 1 ] [ 0 0 0 1]
+ decomp.translate_x = matrix_[3][0];
+ decomp.translate_y = matrix_[3][1];
+
+ // For the remainder of the decomposition process, we can focus on the upper
+ // 2x2 submatrix
+ // [m11 m21] = [cos(R) -sin(R)] [1 K] [Sx 0 ]
+ // [m12 m22] [sin(R) cos(R)] [0 1] [0 Sy]
+ // = [Sx*cos(R) Sy*(K*cos(R) - sin(R))]
+ // [Sx*sin(R) Sy*(K*sin(R) + cos(R))]
+
+ // Determine sign of the x and y scale.
+ decomp.scale_x = 1;
+ decomp.scale_y = 1;
+ if (determinant < 0) {
+ // If the determinant is negative, we need to flip either the x or y scale.
+ // Flipping both is equivalent to rotating by 180 degrees.
+ // Flip the axis with the minimum unit vector dot product.
+ if (m11 < m22) {
+ decomp.scale_x = -decomp.scale_x;
+ } else {
+ decomp.scale_y = -decomp.scale_y;
+ }
+ }
+
+ // X Scale.
+ // m11^2 + m12^2 = Sx^2*(cos^2(R) + sin^2(R)) = Sx^2.
+ // Sx = +/-sqrt(m11^2 + m22^2)
+ decomp.scale_x *= sqrt(m11 * m11 + m12 * m12);
+ m11 /= decomp.scale_x;
+ m12 /= decomp.scale_x;
+
+ // Post normalization, the submatrix is now of the form:
+ // [m11 m21] = [cos(R) Sy*(K*cos(R) - sin(R))]
+ // [m12 m22] [sin(R) Sy*(K*sin(R) + cos(R))]
+
+ // XY Shear.
+ // m11 * m21 + m12 * m22 = Sy*K*cos^2(R) - Sy*sin(R)*cos(R) +
+ // Sy*K*sin^2(R) + Sy*cos(R)*sin(R)
+ // = Sy*K
+ double scaledShear = m11 * m21 + m12 * m22;
+ m21 -= m11 * scaledShear;
+ m22 -= m12 * scaledShear;
+
+ // Post normalization, the submatrix is now of the form:
+ // [m11 m21] = [cos(R) -Sy*sin(R)]
+ // [m12 m22] [sin(R) Sy*cos(R)]
+
+ // Y Scale.
+ // Similar process to determining x-scale.
+ decomp.scale_y *= sqrt(m21 * m21 + m22 * m22);
+ m21 /= decomp.scale_y;
+ m22 /= decomp.scale_y;
+ decomp.skew_xy = scaledShear / decomp.scale_y;
+
+ // Rotation transform.
+ decomp.angle = atan2(m12, m11);
+ return true;
+}
+
void TransformationMatrix::Recompose(const DecomposedType& decomp) {
MakeIdentity();
@@ -1816,6 +1961,32 @@ void TransformationMatrix::Recompose(const DecomposedType& decomp) {
Scale3d(decomp.scale_x, decomp.scale_y, decomp.scale_z);
}
+void TransformationMatrix::Recompose2D(const Decomposed2dType& decomp) {
+ MakeIdentity();
+
+ // Translate transform.
+ SetM41(decomp.translate_x);
+ SetM42(decomp.translate_y);
+
+ // Rotate transform.
+ double cosAngle = cos(decomp.angle);
+ double sinAngle = sin(decomp.angle);
+ SetM11(cosAngle);
+ SetM21(-sinAngle);
+ SetM12(sinAngle);
+ SetM22(cosAngle);
+
+ // skew transform.
+ if (decomp.skew_xy) {
+ TransformationMatrix skewTransform;
+ skewTransform.SetM21(decomp.skew_xy);
+ Multiply(skewTransform);
+ }
+
+ // Scale transform.
+ Scale3d(decomp.scale_x, decomp.scale_y, 1);
+}
+
bool TransformationMatrix::IsIntegerTranslation() const {
if (!IsIdentityOrTranslation())
return false;
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h
index 816565aec6f..7f524dca1b8 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h
@@ -393,10 +393,20 @@ class PLATFORM_EXPORT TransformationMatrix {
double perspective_x, perspective_y, perspective_z, perspective_w;
} DecomposedType;
+ // Decompose 2-D transform matrix into its component parts.
+ typedef struct {
+ double scale_x, scale_y;
+ double skew_xy;
+ double translate_x, translate_y;
+ double angle;
+ } Decomposed2dType;
+
WARN_UNUSED_RESULT bool Decompose(DecomposedType&) const;
+ WARN_UNUSED_RESULT bool Decompose2D(Decomposed2dType&) const;
void Recompose(const DecomposedType&);
-
+ void Recompose2D(const Decomposed2dType&);
void Blend(const TransformationMatrix& from, double progress);
+ void Blend2D(const TransformationMatrix& from, double progress);
bool IsAffine() const {
return M13() == 0 && M14() == 0 && M23() == 0 && M24() == 0 && M31() == 0 &&
@@ -475,6 +485,8 @@ class PLATFORM_EXPORT TransformationMatrix {
matrix_[2][3] == 0 && matrix_[3][2] == 0 && matrix_[3][3] == 1;
}
+ bool Is2dTransform() const;
+
bool IsIntegerTranslation() const;
// Returns true if axis-aligned 2d rects will remain axis-aligned after being
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test.cc b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test.cc
index 359c6966382..1b25e86f8c6 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test.cc
@@ -4,10 +4,27 @@
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "ui/gfx/transform.h"
namespace blink {
+// Allow non-zero tolerance when comparing floating point results to
+// accommodate precision errors.
+const double kFloatingPointErrorTolerance = 1e-6;
+
+#define EXPECT_TRANSFORMATION_MATRIX(expected, actual) \
+ do { \
+ SCOPED_TRACE(""); \
+ cc::ExpectTransformationMatrixNear( \
+ TransformationMatrix::ToTransform(expected), \
+ TransformationMatrix::ToTransform(actual), \
+ kFloatingPointErrorTolerance); \
+ } while (false)
+
+#define EXPECT_FLOAT(expected, actual) \
+ EXPECT_NEAR(expected, actual, kFloatingPointErrorTolerance)
TEST(TransformationMatrixTest, NonInvertableBlendTest) {
TransformationMatrix from;
@@ -330,4 +347,75 @@ TEST(TransformationMatrix, IsInvertible) {
EXPECT_FALSE(TransformationMatrix().Scale(0).IsInvertible());
}
+TEST(TransformationMatrixTest, Blend2dXFlipTest) {
+ // Test 2D x-flip (crbug.com/797472).
+ TransformationMatrix from;
+ from.SetMatrix(1, 0, 0, 1, 100, 150);
+ TransformationMatrix to;
+ to.SetMatrix(-1, 0, 0, 1, 400, 150);
+
+ EXPECT_TRUE(from.Is2dTransform());
+ EXPECT_TRUE(to.Is2dTransform());
+
+ // OK for interpolated transform to be degenerate.
+ TransformationMatrix result = to;
+ result.Blend(from, 0.5);
+ TransformationMatrix expected;
+ expected.SetMatrix(0, 0, 0, 1, 250, 150);
+ EXPECT_TRANSFORMATION_MATRIX(expected, result);
+}
+
+TEST(TransformationMatrixTest, Blend2dRotationDirectionTest) {
+ // Interpolate taking shorter rotation path.
+ TransformationMatrix from;
+ from.SetMatrix(-0.5, 0.86602575498, -0.86602575498, -0.5, 0, 0);
+ TransformationMatrix to;
+ to.SetMatrix(-0.5, -0.86602575498, 0.86602575498, -0.5, 0, 0);
+
+ // Expect clockwise Rotation.
+ TransformationMatrix result = to;
+ result.Blend(from, 0.5);
+ TransformationMatrix expected;
+ expected.SetMatrix(-1, 0, 0, -1, 0, 0);
+ EXPECT_TRANSFORMATION_MATRIX(expected, result);
+
+ // Reverse from and to.
+ // Expect same midpoint with counter-clockwise rotation.
+ result = from;
+ result.Blend(to, 0.5);
+ EXPECT_TRANSFORMATION_MATRIX(expected, result);
+}
+
+TEST(TransformationMatrixTest, Decompose2dShearTest) {
+ // Test that x and y-shear transforms are properly decomposed.
+ // The canonical decomposition is: transform, rotate, x-axis shear, scale.
+ TransformationMatrix transformShearX;
+ transformShearX.SetMatrix(1, 0, 1, 1, 0, 0);
+ TransformationMatrix::Decomposed2dType decompShearX;
+ EXPECT_TRUE(transformShearX.Decompose2D(decompShearX));
+ EXPECT_FLOAT(1, decompShearX.scale_x);
+ EXPECT_FLOAT(1, decompShearX.scale_y);
+ EXPECT_FLOAT(0, decompShearX.translate_x);
+ EXPECT_FLOAT(0, decompShearX.translate_y);
+ EXPECT_FLOAT(0, decompShearX.angle);
+ EXPECT_FLOAT(1, decompShearX.skew_xy);
+ TransformationMatrix recompShearX;
+ recompShearX.Recompose2D(decompShearX);
+ EXPECT_TRANSFORMATION_MATRIX(transformShearX, recompShearX);
+
+ TransformationMatrix transformShearY;
+ transformShearY.SetMatrix(1, 1, 0, 1, 0, 0);
+ TransformationMatrix::Decomposed2dType decompShearY;
+ EXPECT_TRUE(transformShearY.Decompose2D(decompShearY));
+ EXPECT_FLOAT(sqrt(2), decompShearY.scale_x);
+ EXPECT_FLOAT(1 / sqrt(2), decompShearY.scale_y);
+ EXPECT_FLOAT(0, decompShearY.translate_x);
+ EXPECT_FLOAT(0, decompShearY.translate_y);
+ EXPECT_FLOAT(M_PI / 4, decompShearY.angle);
+ EXPECT_FLOAT(1, decompShearY.skew_xy);
+ TransformationMatrix recompShearY;
+ recompShearY.Recompose2D(decompShearY);
+ EXPECT_TRANSFORMATION_MATRIX(transformShearY, recompShearY);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/web_task_runner.h b/chromium/third_party/blink/renderer/platform/web_task_runner.h
deleted file mode 100644
index 04c6b31e89f..00000000000
--- a/chromium/third_party/blink/renderer/platform/web_task_runner.h
+++ /dev/null
@@ -1,14 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEB_TASK_RUNNER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEB_TASK_RUNNER_H_
-
-#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-
-// The contents of this file are moved to the above headers. For future
-// includes, use either of them.
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEB_TASK_RUNNER_H_
diff --git a/chromium/third_party/blink/renderer/platform/web_test_support.cc b/chromium/third_party/blink/renderer/platform/web_test_support.cc
index 66a26d6c60b..670799d70e5 100644
--- a/chromium/third_party/blink/renderer/platform/web_test_support.cc
+++ b/chromium/third_party/blink/renderer/platform/web_test_support.cc
@@ -36,11 +36,11 @@
namespace blink {
// Wrapper functions defined in blink.h
-void SetLayoutTestMode(bool value) {
+void SetWebTestMode(bool value) {
WebTestSupport::SetIsRunningWebTest(value);
}
-bool LayoutTestMode() {
+bool WebTestMode() {
return WebTestSupport::IsRunningWebTest();
}
@@ -52,17 +52,17 @@ bool FontAntialiasingEnabledForTest() {
return WebTestSupport::IsFontAntialiasingEnabledForTest();
}
-static bool g_is_running_layout_test = false;
+static bool g_is_running_web_test = false;
static bool g_is_mock_theme_enabled = false;
static bool g_is_font_antialiasing_enabled = false;
static bool g_is_subpixel_positioning_allowed = true;
bool WebTestSupport::IsRunningWebTest() {
- return g_is_running_layout_test;
+ return g_is_running_web_test;
}
void WebTestSupport::SetIsRunningWebTest(bool value) {
- g_is_running_layout_test = value;
+ g_is_running_web_test = value;
}
bool WebTestSupport::IsMockThemeEnabledForTest() {
@@ -70,7 +70,7 @@ bool WebTestSupport::IsMockThemeEnabledForTest() {
}
void WebTestSupport::SetMockThemeEnabledForTest(bool value) {
- DCHECK(g_is_running_layout_test);
+ DCHECK(g_is_running_web_test);
g_is_mock_theme_enabled = value;
}
diff --git a/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.cc b/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.cc
index a5f0a3b20a9..e3e214faea3 100644
--- a/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.cc
+++ b/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.cc
@@ -15,50 +15,37 @@ namespace blink {
std::unique_ptr<WebThreadSupportingGC> WebThreadSupportingGC::Create(
const ThreadCreationParams& params) {
- return base::WrapUnique(new WebThreadSupportingGC(&params, nullptr));
+ return base::WrapUnique(new WebThreadSupportingGC(params));
}
-std::unique_ptr<WebThreadSupportingGC> WebThreadSupportingGC::CreateForThread(
- Thread* thread) {
- return base::WrapUnique(new WebThreadSupportingGC(nullptr, thread));
-}
-
-WebThreadSupportingGC::WebThreadSupportingGC(const ThreadCreationParams* params,
- Thread* thread)
- : thread_(thread) {
+WebThreadSupportingGC::WebThreadSupportingGC(
+ const ThreadCreationParams& params) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(!params || !thread);
#if DCHECK_IS_ON()
- // We call this regardless of whether an existing thread is given or not,
- // as it means that blink is going to run with more than one thread.
WTF::WillCreateThread();
#endif
if (!thread_) {
- // TODO(scheduler-dev): AnimationWorklet can pass nullptr as Thread*
- // reference when a test doesn't have a compositor thread.
- if (params->thread_type == WebThreadType::kAudioWorkletThread) {
- owning_thread_ = Platform::Current()->CreateWebAudioThread();
+ if (params.thread_type == WebThreadType::kAudioWorkletThread) {
+ thread_ = Thread::CreateWebAudioThread();
} else {
- // If |thread| is not given, create a new one and own it.
- owning_thread_ = Platform::Current()->CreateThread(
- params ? *params : ThreadCreationParams(WebThreadType::kTestThread));
+ thread_ = Thread::CreateThread(params);
}
- thread_ = owning_thread_.get();
}
- MemoryCoordinator::Instance().RegisterThread(thread_);
+ MemoryCoordinator::Instance().RegisterThread(thread_.get());
}
WebThreadSupportingGC::~WebThreadSupportingGC() {
DETACH_FROM_THREAD(thread_checker_);
+ Thread* thread_pointer = thread_.get();
// blink::Thread's destructor blocks until all the tasks are processed.
- owning_thread_.reset();
- MemoryCoordinator::Instance().UnregisterThread(thread_);
+ thread_.reset();
+ MemoryCoordinator::Instance().UnregisterThread(thread_pointer);
}
void WebThreadSupportingGC::InitializeOnThread() {
DCHECK(thread_->IsCurrentThread());
ThreadState::AttachCurrentThread();
- gc_task_runner_ = std::make_unique<GCTaskRunner>(thread_);
+ gc_task_runner_ = std::make_unique<GCTaskRunner>(thread_.get());
}
void WebThreadSupportingGC::ShutdownOnThread() {
@@ -69,10 +56,8 @@ void WebThreadSupportingGC::ShutdownOnThread() {
// Ensure no posted tasks will run from this point on.
gc_task_runner_.reset();
- // Shutdown the thread (via its scheduler) only when the thread is created
- // and is owned by this instance.
- if (owning_thread_)
- owning_thread_->Scheduler()->Shutdown();
+ // Shutdown the thread (via its scheduler).
+ thread_->Scheduler()->Shutdown();
ThreadState::DetachCurrentThread();
}
diff --git a/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.h b/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.h
index d31e43dadfb..e04853197dd 100644
--- a/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.h
+++ b/chromium/third_party/blink/renderer/platform/web_thread_supporting_gc.h
@@ -17,16 +17,15 @@
namespace blink {
-// WebThreadSupportingGC wraps a WebThread and adds support for attaching
+// WebThreadSupportingGC wraps a blink::Thread and adds support for attaching
// to and detaching from the Blink GC infrastructure.
//
-// The initialize method must be called during initialization on the WebThread
+// The initialize method must be called during initialization on the Thread
// and before the thread allocates any objects managed by the Blink GC. The
-// shutdown method must be called on the WebThread during shutdown when the
+// shutdown method must be called on the Thread during shutdown when the
// thread no longer needs to access objects managed by the Blink GC.
//
-// WebThreadSupportingGC usually internally creates and owns WebThread unless
-// an existing WebThread is given via createForThread.
+// WebThreadSupportingGC internally creates and owns Thread.
class PLATFORM_EXPORT WebThreadSupportingGC final {
USING_FAST_MALLOC(WebThreadSupportingGC);
WTF_MAKE_NONCOPYABLE(WebThreadSupportingGC);
@@ -34,7 +33,6 @@ class PLATFORM_EXPORT WebThreadSupportingGC final {
public:
static std::unique_ptr<WebThreadSupportingGC> Create(
const ThreadCreationParams&);
- static std::unique_ptr<WebThreadSupportingGC> CreateForThread(Thread*);
~WebThreadSupportingGC();
void PostTask(const base::Location& location, base::OnceClosure task) {
@@ -78,15 +76,11 @@ class PLATFORM_EXPORT WebThreadSupportingGC final {
}
private:
- WebThreadSupportingGC(const ThreadCreationParams*, Thread*);
+ WebThreadSupportingGC(const ThreadCreationParams&);
std::unique_ptr<GCTaskRunner> gc_task_runner_;
- // m_thread is guaranteed to be non-null after this instance is constructed.
- // m_owningThread is non-null unless this instance is constructed for an
- // existing thread via createForThread().
- Thread* thread_ = nullptr;
- std::unique_ptr<Thread> owning_thread_;
+ std::unique_ptr<Thread> thread_;
THREAD_CHECKER(thread_checker_);
};
diff --git a/chromium/third_party/blink/renderer/platform/web_vector_test.cc b/chromium/third_party/blink/renderer/platform/web_vector_test.cc
index a0d8978ee9a..6066cbd5034 100644
--- a/chromium/third_party/blink/renderer/platform/web_vector_test.cc
+++ b/chromium/third_party/blink/renderer/platform/web_vector_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/public/platform/web_vector.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -60,8 +61,8 @@ TEST(WebVectorTest, IsEmpty) {
TEST(WebVectorTest, Swap) {
const int kFirstData[] = {1, 2, 3, 4, 5};
const int kSecondData[] = {6, 5, 8};
- const size_t kFirstDataLength = arraysize(kFirstData);
- const size_t kSecondDataLength = arraysize(kSecondData);
+ const size_t kFirstDataLength = base::size(kFirstData);
+ const size_t kSecondDataLength = base::size(kSecondData);
WebVector<int> first(kFirstData, kFirstDataLength);
WebVector<int> second(kSecondData, kSecondDataLength);
@@ -136,9 +137,9 @@ TEST(WebVectorTest, EmplaceBackArgumentForwarding) {
WebVector<WebString> vector;
vector.reserve(1);
WebUChar buffer[] = {'H', 'e', 'l', 'l', 'o', ' ', 'b', 'l', 'i', 'n', 'k'};
- vector.emplace_back(buffer, arraysize(buffer));
+ vector.emplace_back(buffer, base::size(buffer));
ASSERT_EQ(1U, vector.size());
- EXPECT_EQ(WebString(buffer, arraysize(buffer)), vector[0]);
+ EXPECT_EQ(WebString(buffer, base::size(buffer)), vector[0]);
}
TEST(WebVectorTest, EmplaceBackElementPlacement) {
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc b/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc
index 19f14390353..40dfe3587eb 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc
@@ -619,14 +619,11 @@ void KURL::SetPath(const String& path) {
ReplaceComponents(replacements);
}
-String DecodeURLEscapeSequences(const String& string,
- DecodeURLResult* optional_result) {
+String DecodeURLEscapeSequences(const String& string, DecodeURLMode mode) {
StringUTF8Adaptor string_utf8(string);
url::RawCanonOutputT<base::char16> unescaped;
- DecodeURLResult result = url::DecodeURLEscapeSequences(
- string_utf8.Data(), string_utf8.length(), &unescaped);
- if (optional_result)
- *optional_result = result;
+ url::DecodeURLEscapeSequences(string_utf8.Data(), string_utf8.length(), mode,
+ &unescaped);
return StringImpl::Create8BitIfPossible(
reinterpret_cast<UChar*>(unescaped.data()), unescaped.length());
}
@@ -877,5 +874,28 @@ KURL::operator GURL() const {
StringUTF8Adaptor utf8(string_);
return GURL(utf8.Data(), utf8.length(), parsed_, is_valid_);
}
+bool operator==(const KURL& a, const KURL& b) {
+ return a.GetString() == b.GetString();
+}
+
+bool operator==(const KURL& a, const String& b) {
+ return a.GetString() == b;
+}
+
+bool operator==(const String& a, const KURL& b) {
+ return a == b.GetString();
+}
+
+bool operator!=(const KURL& a, const KURL& b) {
+ return a.GetString() != b.GetString();
+}
+
+bool operator!=(const KURL& a, const String& b) {
+ return a.GetString() != b;
+}
+
+bool operator!=(const String& a, const KURL& b) {
+ return a != b.GetString();
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/kurl.h b/chromium/third_party/blink/renderer/platform/weborigin/kurl.h
index 9dfcab29740..eb4fa3d767e 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/kurl.h
+++ b/chromium/third_party/blink/renderer/platform/weborigin/kurl.h
@@ -293,8 +293,7 @@ PLATFORM_EXPORT bool ProtocolIsJavaScript(const String& url);
PLATFORM_EXPORT bool IsValidProtocol(const String&);
-using DecodeURLResult = url::DecodeURLResult;
-
+using DecodeURLMode = url::DecodeURLMode;
// Unescapes the given string using URL escaping rules.
//
// DANGER: If the URL has "%00" in it, the resulting string will have embedded
@@ -302,38 +301,14 @@ using DecodeURLResult = url::DecodeURLResult;
//
// This function is also used to decode javascript: URLs and as a general
// purpose unescaping function.
-// TODO(tkent): Remove the second argument after collecting data.
+//
+// Caution: Specifying kUTF8OrIsomorphic to the second argument doesn't conform
+// to specifications in many cases.
PLATFORM_EXPORT String DecodeURLEscapeSequences(const String&,
- DecodeURLResult* = nullptr);
+ DecodeURLMode mode);
PLATFORM_EXPORT String EncodeWithURLEscapeSequences(const String&);
-// Inlines.
-
-inline bool operator==(const KURL& a, const KURL& b) {
- return a.GetString() == b.GetString();
-}
-
-inline bool operator==(const KURL& a, const String& b) {
- return a.GetString() == b;
-}
-
-inline bool operator==(const String& a, const KURL& b) {
- return a == b.GetString();
-}
-
-inline bool operator!=(const KURL& a, const KURL& b) {
- return a.GetString() != b.GetString();
-}
-
-inline bool operator!=(const KURL& a, const String& b) {
- return a.GetString() != b;
-}
-
-inline bool operator!=(const String& a, const KURL& b) {
- return a != b.GetString();
-}
-
} // namespace blink
namespace WTF {
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc b/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc
index ebc778a4b77..2a047b0b197 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc
@@ -35,6 +35,7 @@
#include <stdint.h>
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
@@ -85,7 +86,7 @@ TEST(KURLTest, Getters) {
"xn--6qqa088eba", 0, "", nullptr, "/", nullptr, nullptr, nullptr, false},
};
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
const GetterCase& c = cases[i];
const String& url = String::FromUTF8(c.url);
@@ -176,7 +177,7 @@ TEST(KURLTest, Setters) {
nullptr, "http://goo.com:92/#b"},
};
- for (size_t i = 0; i < arraysize(cases); i++) {
+ for (size_t i = 0; i < base::size(cases); i++) {
KURL kurl(cases[i].url);
kurl.SetProtocol(cases[i].protocol);
@@ -232,24 +233,28 @@ TEST(KURLTest, DecodeURLEscapeSequences) {
{"%e4%bd%a0%e5%a5%bd", "\xe4\xbd\xa0\xe5\xa5\xbd"},
};
- for (size_t i = 0; i < arraysize(decode_cases); i++) {
+ for (size_t i = 0; i < base::size(decode_cases); i++) {
String input(decode_cases[i].input);
- String str = DecodeURLEscapeSequences(input);
+ String str =
+ DecodeURLEscapeSequences(input, DecodeURLMode::kUTF8OrIsomorphic);
EXPECT_STREQ(decode_cases[i].output, str.Utf8().data());
}
// Our decode should decode %00
- String zero = DecodeURLEscapeSequences("%00");
+ String zero =
+ DecodeURLEscapeSequences("%00", DecodeURLMode::kUTF8OrIsomorphic);
EXPECT_STRNE("%00", zero.Utf8().data());
// Decode UTF-8.
- String decoded = DecodeURLEscapeSequences("%e6%bc%a2%e5%ad%97");
+ String decoded = DecodeURLEscapeSequences("%e6%bc%a2%e5%ad%97",
+ DecodeURLMode::kUTF8OrIsomorphic);
const UChar kDecodedExpected[] = {0x6F22, 0x5b57};
- EXPECT_EQ(String(kDecodedExpected, arraysize(kDecodedExpected)), decoded);
+ EXPECT_EQ(String(kDecodedExpected, base::size(kDecodedExpected)), decoded);
// Test the error behavior for invalid UTF-8 (we differ from WebKit here).
// %e4 %a0 are invalid for UTF-8, but %e5%a5%bd is valid.
- String invalid = DecodeURLEscapeSequences("%e4%a0%e5%a5%bd");
+ String invalid = DecodeURLEscapeSequences("%e4%a0%e5%a5%bd",
+ DecodeURLMode::kUTF8OrIsomorphic);
UChar invalid_expected_helper[6] = {0x00e4, 0x00a0, 0x00e5,
0x00a5, 0x00bd, 0};
String invalid_expected(
@@ -275,7 +280,7 @@ TEST(KURLTest, EncodeWithURLEscapeSequences) {
{"pqrstuvwxyz{|}~\x7f", "pqrstuvwxyz%7B%7C%7D~%7F"},
};
- for (size_t i = 0; i < arraysize(encode_cases); i++) {
+ for (size_t i = 0; i < base::size(encode_cases); i++) {
String input(encode_cases[i].input);
String expected_output(encode_cases[i].output);
String output = EncodeWithURLEscapeSequences(input);
@@ -866,7 +871,7 @@ TEST(KURLTest, strippedForUseAsReferrer) {
{"https://www.google.com/#", "https://www.google.com/"},
};
- for (size_t i = 0; i < arraysize(referrer_cases); i++) {
+ for (size_t i = 0; i < base::size(referrer_cases); i++) {
const KURL kurl(referrer_cases[i].input);
String referrer = kurl.StrippedForUseAsReferrer();
EXPECT_STREQ(referrer_cases[i].output, referrer.Utf8().data());
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc
index 81b8fa13fb8..267e2e64316 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -537,7 +537,8 @@ scoped_refptr<SecurityOrigin> SecurityOrigin::CreateFromString(
scoped_refptr<SecurityOrigin> SecurityOrigin::Create(const String& protocol,
const String& host,
uint16_t port) {
- DCHECK_EQ(host, DecodeURLEscapeSequences(host));
+ DCHECK_EQ(host,
+ DecodeURLEscapeSequences(host, DecodeURLMode::kUTF8OrIsomorphic));
String port_part = port ? ":" + String::Number(port) : String();
return Create(KURL(NullURL(), protocol + "://" + host + port_part + "/"));
@@ -617,7 +618,6 @@ const SecurityOrigin* SecurityOrigin::GetOriginOrPrecursorOriginIfOpaque()
return this;
DCHECK(IsOpaque());
- DCHECK(!precursor_origin_->IsOpaque());
return precursor_origin_.get();
}
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
index e77bd9220af..0e4b717f845 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -32,6 +32,7 @@
#include <stdint.h>
+#include "base/stl_util.h"
#include "services/network/public/mojom/cors.mojom-shared.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/blob/blob_url.h"
@@ -56,7 +57,7 @@ class SecurityOriginTest : public testing::Test {
TEST_F(SecurityOriginTest, ValidPortsCreateTupleOrigins) {
uint16_t ports[] = {0, 80, 443, 5000, kMaxAllowedPort};
- for (size_t i = 0; i < arraysize(ports); ++i) {
+ for (size_t i = 0; i < base::size(ports); ++i) {
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::Create("http", "example.com", ports[i]);
EXPECT_FALSE(origin->IsOpaque())
@@ -153,7 +154,7 @@ TEST_F(SecurityOriginTest, IsPotentiallyTrustworthy) {
{false, "filesystem:ftp://evil:99/foo"},
};
- for (size_t i = 0; i < arraysize(inputs); ++i) {
+ for (size_t i = 0; i < base::size(inputs); ++i) {
SCOPED_TRACE(inputs[i].url);
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString(inputs[i].url);
@@ -237,7 +238,7 @@ TEST_F(SecurityOriginTest, CanAccess) {
{false, "file:///", "file://localhost/"},
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
scoped_refptr<const SecurityOrigin> origin1 =
SecurityOrigin::CreateFromString(tests[i].origin1);
scoped_refptr<const SecurityOrigin> origin2 =
@@ -344,7 +345,7 @@ TEST_F(SecurityOriginTest, CanRequest) {
{false, "https://foobar.com", "https://bazbar.com"},
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
+ for (size_t i = 0; i < base::size(tests); ++i) {
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString(tests[i].origin);
blink::KURL url(tests[i].url);
diff --git a/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn b/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
index 108a748ab72..4e283444002 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -16,20 +16,10 @@ visibility = [
config("wtf_config") {
if (is_win) {
- defines = [
- "__STD_C",
- "_CRT_SECURE_NO_DEPRECATE",
- "_SCL_SECURE_NO_DEPRECATE",
- ]
- include_dirs = [ "os-win32" ]
-
cflags = [
# Don't complain about calling specific versions of templatized
# functions (e.g. in RefPtrHashMap.h).
"/wd4344",
-
- # dtoa, icu, etc. like doing assignment within conditional.
- "/wd4706",
]
if (is_component_build) {
@@ -55,7 +45,6 @@ jumbo_component("wtf") {
"ascii_ctype.h",
"assertions.cc",
"assertions.h",
- "atomics.h",
"bit_vector.cc",
"bit_vector.h",
"bloom_filter.h",
@@ -133,8 +122,6 @@ jumbo_component("wtf") {
"std_lib_extras.h",
"string_extras.h",
"string_hasher.h",
- "terminated_array.h",
- "terminated_array_builder.h",
"text/ascii_fast_path.h",
"text/atomic_string.cc",
"text/atomic_string.h",
diff --git a/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h b/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
index bcfff8670c7..8be065f8473 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
@@ -102,6 +102,7 @@ class WTF_EXPORT PartitionAllocator {
static void TraceMarkedBackingStore(void*) {}
static void BackingWriteBarrier(void*) {}
+ static void BackingWriteBarrier(void*, size_t) {}
static bool IsAllocationAllowed() { return true; }
static bool IsObjectResurrectionForbidden() { return false; }
diff --git a/chromium/third_party/blink/renderer/platform/wtf/atomics.h b/chromium/third_party/blink/renderer/platform/wtf/atomics.h
deleted file mode 100644
index bc0f0794035..00000000000
--- a/chromium/third_party/blink/renderer/platform/wtf/atomics.h
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2007, 2008, 2010, 2012 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ATOMICS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ATOMICS_H_
-
-#include <stdint.h>
-#include "build/build_config.h"
-#include "third_party/blink/renderer/platform/wtf/address_sanitizer.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/cpu.h"
-
-#if defined(COMPILER_MSVC)
-#include <windows.h>
-#endif
-
-#if defined(THREAD_SANITIZER)
-#include <sanitizer/tsan_interface_atomic.h>
-#endif
-
-#if defined(ADDRESS_SANITIZER)
-#include <sanitizer/asan_interface.h>
-#endif
-
-namespace WTF {
-
-#if defined(COMPILER_MSVC)
-
-// atomicAdd returns the result of the addition.
-ALWAYS_INLINE int AtomicAdd(int volatile* addend, int increment) {
- return InterlockedExchangeAdd(reinterpret_cast<long volatile*>(addend),
- static_cast<long>(increment)) +
- increment;
-}
-ALWAYS_INLINE unsigned AtomicAdd(unsigned volatile* addend,
- unsigned increment) {
- return InterlockedExchangeAdd(reinterpret_cast<long volatile*>(addend),
- static_cast<long>(increment)) +
- increment;
-}
-#if defined(_WIN64)
-ALWAYS_INLINE unsigned long long AtomicAdd(unsigned long long volatile* addend,
- unsigned long long increment) {
- return InterlockedExchangeAdd64(reinterpret_cast<long long volatile*>(addend),
- static_cast<long long>(increment)) +
- increment;
-}
-#endif
-
-// atomicSubtract returns the result of the subtraction.
-ALWAYS_INLINE int AtomicSubtract(int volatile* addend, int decrement) {
- return InterlockedExchangeAdd(reinterpret_cast<long volatile*>(addend),
- static_cast<long>(-decrement)) -
- decrement;
-}
-ALWAYS_INLINE unsigned AtomicSubtract(unsigned volatile* addend,
- unsigned decrement) {
- return InterlockedExchangeAdd(reinterpret_cast<long volatile*>(addend),
- -static_cast<long>(decrement)) -
- decrement;
-}
-#if defined(_WIN64)
-ALWAYS_INLINE unsigned long long AtomicSubtract(
- unsigned long long volatile* addend,
- unsigned long long decrement) {
- return InterlockedExchangeAdd64(reinterpret_cast<long long volatile*>(addend),
- -static_cast<long long>(decrement)) -
- decrement;
-}
-#endif
-
-ALWAYS_INLINE int AtomicIncrement(int volatile* addend) {
- return InterlockedIncrement(reinterpret_cast<long volatile*>(addend));
-}
-ALWAYS_INLINE int AtomicDecrement(int volatile* addend) {
- return InterlockedDecrement(reinterpret_cast<long volatile*>(addend));
-}
-
-ALWAYS_INLINE int64_t AtomicIncrement(int64_t volatile* addend) {
- return InterlockedIncrement64(reinterpret_cast<long long volatile*>(addend));
-}
-ALWAYS_INLINE int64_t AtomicDecrement(int64_t volatile* addend) {
- return InterlockedDecrement64(reinterpret_cast<long long volatile*>(addend));
-}
-
-ALWAYS_INLINE int AtomicTestAndSetToOne(int volatile* ptr) {
- int ret = InterlockedExchange(reinterpret_cast<long volatile*>(ptr), 1);
- DCHECK(!ret || ret == 1);
- return ret;
-}
-
-ALWAYS_INLINE void AtomicSetOneToZero(int volatile* ptr) {
- DCHECK_EQ(*ptr, 1);
- InterlockedExchange(reinterpret_cast<long volatile*>(ptr), 0);
-}
-
-#else
-
-// atomicAdd returns the result of the addition.
-ALWAYS_INLINE int AtomicAdd(int volatile* addend, int increment) {
- return __sync_add_and_fetch(addend, increment);
-}
-ALWAYS_INLINE unsigned AtomicAdd(unsigned volatile* addend,
- unsigned increment) {
- return __sync_add_and_fetch(addend, increment);
-}
-ALWAYS_INLINE unsigned long AtomicAdd(unsigned long volatile* addend,
- unsigned long increment) {
- return __sync_add_and_fetch(addend, increment);
-}
-// atomicSubtract returns the result of the subtraction.
-ALWAYS_INLINE int AtomicSubtract(int volatile* addend, int decrement) {
- return __sync_sub_and_fetch(addend, decrement);
-}
-ALWAYS_INLINE unsigned AtomicSubtract(unsigned volatile* addend,
- unsigned decrement) {
- return __sync_sub_and_fetch(addend, decrement);
-}
-ALWAYS_INLINE unsigned long AtomicSubtract(unsigned long volatile* addend,
- unsigned long decrement) {
- return __sync_sub_and_fetch(addend, decrement);
-}
-
-ALWAYS_INLINE int AtomicIncrement(int volatile* addend) {
- return AtomicAdd(addend, 1);
-}
-ALWAYS_INLINE int AtomicDecrement(int volatile* addend) {
- return AtomicSubtract(addend, 1);
-}
-
-ALWAYS_INLINE int64_t AtomicIncrement(int64_t volatile* addend) {
- return __sync_add_and_fetch(addend, 1);
-}
-ALWAYS_INLINE int64_t AtomicDecrement(int64_t volatile* addend) {
- return __sync_sub_and_fetch(addend, 1);
-}
-
-ALWAYS_INLINE int AtomicTestAndSetToOne(int volatile* ptr) {
- int ret = __sync_lock_test_and_set(ptr, 1);
- DCHECK(!ret || ret == 1);
- return ret;
-}
-
-ALWAYS_INLINE void AtomicSetOneToZero(int volatile* ptr) {
- DCHECK_EQ(*ptr, 1);
- __sync_lock_release(ptr);
-}
-#endif
-
-#if defined(THREAD_SANITIZER)
-// The definitions below assume an LP64 data model. This is fine because
-// TSan is only supported on x86_64 Linux.
-#if defined(ARCH_CPU_64_BITS) && defined(OS_LINUX)
-ALWAYS_INLINE void ReleaseStore(volatile int* ptr, int value) {
- __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
-}
-ALWAYS_INLINE void ReleaseStore(volatile unsigned* ptr, unsigned value) {
- __tsan_atomic32_store(reinterpret_cast<volatile int*>(ptr),
- static_cast<int>(value), __tsan_memory_order_release);
-}
-ALWAYS_INLINE void ReleaseStore(volatile long* ptr, long value) {
- __tsan_atomic64_store(reinterpret_cast<volatile __tsan_atomic64*>(ptr),
- static_cast<__tsan_atomic64>(value),
- __tsan_memory_order_release);
-}
-ALWAYS_INLINE void ReleaseStore(volatile unsigned long* ptr,
- unsigned long value) {
- __tsan_atomic64_store(reinterpret_cast<volatile __tsan_atomic64*>(ptr),
- static_cast<__tsan_atomic64>(value),
- __tsan_memory_order_release);
-}
-ALWAYS_INLINE void ReleaseStore(volatile unsigned long long* ptr,
- unsigned long long value) {
- __tsan_atomic64_store(reinterpret_cast<volatile __tsan_atomic64*>(ptr),
- static_cast<__tsan_atomic64>(value),
- __tsan_memory_order_release);
-}
-ALWAYS_INLINE void ReleaseStore(void* volatile* ptr, void* value) {
- __tsan_atomic64_store(reinterpret_cast<volatile __tsan_atomic64*>(ptr),
- reinterpret_cast<__tsan_atomic64>(value),
- __tsan_memory_order_release);
-}
-ALWAYS_INLINE int AcquireLoad(volatile const int* ptr) {
- return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
-}
-ALWAYS_INLINE unsigned AcquireLoad(volatile const unsigned* ptr) {
- return static_cast<unsigned>(__tsan_atomic32_load(
- reinterpret_cast<volatile const int*>(ptr), __tsan_memory_order_acquire));
-}
-ALWAYS_INLINE long AcquireLoad(volatile const long* ptr) {
- return static_cast<long>(__tsan_atomic64_load(
- reinterpret_cast<volatile const __tsan_atomic64*>(ptr),
- __tsan_memory_order_acquire));
-}
-ALWAYS_INLINE unsigned long AcquireLoad(volatile const unsigned long* ptr) {
- return static_cast<unsigned long>(__tsan_atomic64_load(
- reinterpret_cast<volatile const __tsan_atomic64*>(ptr),
- __tsan_memory_order_acquire));
-}
-ALWAYS_INLINE void* AcquireLoad(void* volatile const* ptr) {
- return reinterpret_cast<void*>(__tsan_atomic64_load(
- reinterpret_cast<volatile const __tsan_atomic64*>(ptr),
- __tsan_memory_order_acquire));
-}
-
-// Do not use NoBarrierStore/NoBarrierLoad for synchronization.
-ALWAYS_INLINE void NoBarrierStore(volatile float* ptr, float value) {
- static_assert(sizeof(int) == sizeof(float),
- "int and float are different sizes");
- union {
- int ivalue;
- float fvalue;
- } u;
- u.fvalue = value;
- __tsan_atomic32_store(reinterpret_cast<volatile __tsan_atomic32*>(ptr),
- u.ivalue, __tsan_memory_order_relaxed);
-}
-
-ALWAYS_INLINE float NoBarrierLoad(volatile const float* ptr) {
- static_assert(sizeof(int) == sizeof(float),
- "int and float are different sizes");
- union {
- int ivalue;
- float fvalue;
- } u;
- u.ivalue = __tsan_atomic32_load(reinterpret_cast<volatile const int*>(ptr),
- __tsan_memory_order_relaxed);
- return u.fvalue;
-}
-#endif
-
-#else // defined(THREAD_SANITIZER)
-
-#if defined(ARCH_CPU_X86_FAMILY)
-// Only compiler barrier is needed.
-#if defined(COMPILER_MSVC)
-// Starting from Visual Studio 2005 compiler guarantees acquire and release
-// semantics for operations on volatile variables. See MSDN entry for
-// MemoryBarrier macro.
-#define MEMORY_BARRIER()
-#else
-#define MEMORY_BARRIER() __asm__ __volatile__("" : : : "memory")
-#endif
-#else
-// Fallback to the compiler intrinsic on all other platforms.
-#define MEMORY_BARRIER() __sync_synchronize()
-#endif
-
-ALWAYS_INLINE void ReleaseStore(volatile int* ptr, int value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-ALWAYS_INLINE void ReleaseStore(volatile unsigned* ptr, unsigned value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-ALWAYS_INLINE void ReleaseStore(volatile long* ptr, long value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-ALWAYS_INLINE void ReleaseStore(volatile unsigned long* ptr,
- unsigned long value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-#if defined(ARCH_CPU_64_BITS)
-ALWAYS_INLINE void ReleaseStore(volatile unsigned long long* ptr,
- unsigned long long value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-#endif
-ALWAYS_INLINE void ReleaseStore(void* volatile* ptr, void* value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-
-ALWAYS_INLINE int AcquireLoad(volatile const int* ptr) {
- int value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-ALWAYS_INLINE unsigned AcquireLoad(volatile const unsigned* ptr) {
- unsigned value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-ALWAYS_INLINE long AcquireLoad(volatile const long* ptr) {
- long value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-ALWAYS_INLINE unsigned long AcquireLoad(volatile const unsigned long* ptr) {
- unsigned long value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-#if defined(ARCH_CPU_64_BITS)
-ALWAYS_INLINE unsigned long long AcquireLoad(
- volatile const unsigned long long* ptr) {
- unsigned long long value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-#endif
-ALWAYS_INLINE void* AcquireLoad(void* volatile const* ptr) {
- void* value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-
-// Do not use noBarrierStore/noBarrierLoad for synchronization.
-ALWAYS_INLINE void NoBarrierStore(volatile float* ptr, float value) {
- *ptr = value;
-}
-
-ALWAYS_INLINE float NoBarrierLoad(volatile const float* ptr) {
- float value = *ptr;
- return value;
-}
-
-#if defined(ADDRESS_SANITIZER)
-
-NO_SANITIZE_ADDRESS ALWAYS_INLINE void AsanUnsafeReleaseStore(
- volatile unsigned* ptr,
- unsigned value) {
- MEMORY_BARRIER();
- *ptr = value;
-}
-
-NO_SANITIZE_ADDRESS ALWAYS_INLINE unsigned AsanUnsafeAcquireLoad(
- volatile const unsigned* ptr) {
- unsigned value = *ptr;
- MEMORY_BARRIER();
- return value;
-}
-
-#endif // defined(ADDRESS_SANITIZER)
-
-#undef MEMORY_BARRIER
-
-#endif
-
-#if !defined(ADDRESS_SANITIZER)
-
-ALWAYS_INLINE void AsanUnsafeReleaseStore(volatile unsigned* ptr,
- unsigned value) {
- ReleaseStore(ptr, value);
-}
-
-ALWAYS_INLINE unsigned AsanUnsafeAcquireLoad(volatile const unsigned* ptr) {
- return AcquireLoad(ptr);
-}
-
-#endif
-
-} // namespace WTF
-
-using WTF::AtomicAdd;
-using WTF::AtomicSubtract;
-using WTF::AtomicDecrement;
-using WTF::AtomicIncrement;
-using WTF::AtomicTestAndSetToOne;
-using WTF::AtomicSetOneToZero;
-using WTF::AcquireLoad;
-using WTF::ReleaseStore;
-using WTF::NoBarrierLoad;
-using WTF::NoBarrierStore;
-
-// These methods allow loading from and storing to poisoned memory. Only
-// use these methods if you know what you are doing since they will
-// silence use-after-poison errors from ASan.
-using WTF::AsanUnsafeAcquireLoad;
-using WTF::AsanUnsafeReleaseStore;
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ATOMICS_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/date_math.cc b/chromium/third_party/blink/renderer/platform/wtf/date_math.cc
index 456098a9672..87f4972d3af 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/date_math.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/date_math.cc
@@ -78,6 +78,8 @@
#include <algorithm>
#include <limits>
#include <memory>
+
+#include "base/stl_util.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -613,7 +615,7 @@ static double ParseDateFromNullTerminatedCharacters(const char* date_string,
}
have_tz = true;
} else {
- for (size_t i = 0; i < arraysize(known_zones); ++i) {
+ for (size_t i = 0; i < base::size(known_zones); ++i) {
if (0 == strncasecmp(date_string, known_zones[i].tz_name,
strlen(known_zones[i].tz_name))) {
offset = known_zones[i].tz_offset;
diff --git a/chromium/third_party/blink/renderer/platform/wtf/hash_map.h b/chromium/third_party/blink/renderer/platform/wtf/hash_map.h
index 96cb4996ffe..46b39e0697f 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/hash_map.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/hash_map.h
@@ -198,7 +198,8 @@ class HashMap {
typename IncomingMappedType>
AddResult Insert(IncomingKeyType&&, IncomingMappedType&&);
- static bool IsValidKey(KeyPeekInType);
+ template <typename IncomingKeyType>
+ static bool IsValidKey(const IncomingKeyType&);
template <typename VisitorDispatcher, typename A = Allocator>
std::enable_if_t<A::kIsGarbageCollected> Trace(VisitorDispatcher visitor) {
@@ -665,7 +666,8 @@ template <typename T,
typename W,
typename X,
typename Y>
-inline bool HashMap<T, U, V, W, X, Y>::IsValidKey(KeyPeekInType key) {
+template <typename IncomingKeyType>
+inline bool HashMap<T, U, V, W, X, Y>::IsValidKey(const IncomingKeyType& key) {
if (KeyTraits::IsDeletedValue(key))
return false;
diff --git a/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc b/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc
index d1864f1c9fa..16ccad0452f 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc
@@ -617,6 +617,21 @@ TEST(HashMapTest, InitializerList) {
EXPECT_TRUE(IsOneTwoThreeMap(ReturnOneTwoThreeMap()));
}
+TEST(HashMapTest, IsValidKey) {
+ bool is_deleted;
+ EXPECT_FALSE((HashMap<int, int>::IsValidKey(0)));
+ EXPECT_FALSE((HashMap<int, int>::IsValidKey(-1)));
+ EXPECT_TRUE((HashMap<int, int>::IsValidKey(-2)));
+
+ EXPECT_FALSE((HashMap<int*, int>::IsValidKey(nullptr)));
+ EXPECT_TRUE((HashMap<int*, int>::IsValidKey(std::make_unique<int>().get())));
+
+ auto p = base::MakeRefCounted<DummyRefCounted>(is_deleted);
+ EXPECT_TRUE((HashMap<scoped_refptr<DummyRefCounted>, int>::IsValidKey(p)));
+ EXPECT_FALSE(
+ (HashMap<scoped_refptr<DummyRefCounted>, int>::IsValidKey(nullptr)));
+}
+
static_assert(!IsTraceable<HashMap<int, int>>::value,
"HashMap<int, int> must not be traceable.");
diff --git a/chromium/third_party/blink/renderer/platform/wtf/terminated_array.h b/chromium/third_party/blink/renderer/platform/wtf/terminated_array.h
deleted file mode 100644
index 772b9f16f7e..00000000000
--- a/chromium/third_party/blink/renderer/platform/wtf/terminated_array.h
+++ /dev/null
@@ -1,130 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TERMINATED_ARRAY_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TERMINATED_ARRAY_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
-#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
-
-namespace WTF {
-
-// TerminatedArray<T> represents a sequence of elements of type T in which each
-// element knows whether it is the last element in the sequence or not. For this
-// check type T must provide isLastInArray method.
-// TerminatedArray<T> can only be constructed by TerminatedArrayBuilder<T>.
-template <typename T>
-class TerminatedArray {
- DISALLOW_NEW();
-
- public:
- // When TerminatedArray::Allocator implementations grow the backing
- // store, old is copied into the new and larger block.
- static_assert(VectorTraits<T>::kCanMoveWithMemcpy,
- "Array elements must be memory copyable");
-
- T& at(size_t index) { return reinterpret_cast<T*>(this)[index]; }
- const T& at(size_t index) const {
- return reinterpret_cast<const T*>(this)[index];
- }
-
- template <typename U>
- class iterator_base final {
- STACK_ALLOCATED();
-
- public:
- iterator_base& operator++() {
- if (val_->IsLastInArray()) {
- val_ = nullptr;
- } else {
- ++val_;
- }
- return *this;
- }
-
- U& operator*() const { return *val_; }
-
- bool operator==(const iterator_base& other) const {
- return val_ == other.val_;
- }
- bool operator!=(const iterator_base& other) const {
- return !(*this == other);
- }
-
- private:
- iterator_base(U* val) : val_(val) {}
-
- U* val_;
-
- friend class TerminatedArray;
- };
-
- typedef iterator_base<T> iterator;
- typedef iterator_base<const T> const_iterator;
-
- iterator begin() { return iterator(reinterpret_cast<T*>(this)); }
- const_iterator begin() const {
- return const_iterator(reinterpret_cast<const T*>(this));
- }
-
- iterator end() { return iterator(nullptr); }
- const_iterator end() const { return const_iterator(nullptr); }
-
- size_t size() const {
- size_t count = 0;
- for (const_iterator it = begin(); it != end(); ++it)
- count++;
- return count;
- }
-
- // Match Allocator semantics to be able to use
- // std::unique_ptr<TerminatedArray>.
- void operator delete(void* p) { ::WTF::Partitions::FastFree(p); }
-
- private:
- // Allocator describes how TerminatedArrayBuilder should create new instances
- // of TerminateArray and manage their lifetimes.
- struct Allocator {
- STATIC_ONLY(Allocator);
- using BackendAllocator = PartitionAllocator;
- using PassPtr = std::unique_ptr<TerminatedArray>;
- using Ptr = std::unique_ptr<TerminatedArray>;
-
- static PassPtr Release(Ptr& ptr) { return ptr.release(); }
-
- static PassPtr Create(size_t capacity) {
- return base::WrapUnique(
- static_cast<TerminatedArray*>(WTF::Partitions::FastMalloc(
- WTF::Partitions::ComputeAllocationSize(capacity, sizeof(T)),
- WTF_HEAP_PROFILER_TYPE_NAME(T))));
- }
-
- static PassPtr Resize(Ptr ptr, size_t capacity) {
- return base::WrapUnique(
- static_cast<TerminatedArray*>(WTF::Partitions::FastRealloc(
- ptr.release(),
- WTF::Partitions::ComputeAllocationSize(capacity, sizeof(T)),
- WTF_HEAP_PROFILER_TYPE_NAME(T))));
- }
- };
-
- // Prohibit construction. Allocator makes TerminatedArray instances for
- // TerminatedArrayBuilder by pointer casting.
- TerminatedArray() = delete;
-
- template <typename, template <typename> class>
- friend class TerminatedArrayBuilder;
-
- DISALLOW_COPY_AND_ASSIGN(TerminatedArray);
-};
-
-} // namespace WTF
-
-using WTF::TerminatedArray;
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TERMINATED_ARRAY_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/terminated_array_builder.h b/chromium/third_party/blink/renderer/platform/wtf/terminated_array_builder.h
deleted file mode 100644
index 5ef3aa81d1a..00000000000
--- a/chromium/third_party/blink/renderer/platform/wtf/terminated_array_builder.h
+++ /dev/null
@@ -1,87 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TERMINATED_ARRAY_BUILDER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TERMINATED_ARRAY_BUILDER_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
-
-namespace WTF {
-
-template <typename T>
-class TerminatedArray;
-
-template <typename T, template <typename> class ArrayType = TerminatedArray>
-class TerminatedArrayBuilder {
- STACK_ALLOCATED();
-
- public:
- explicit TerminatedArrayBuilder(
- typename ArrayType<T>::Allocator::PassPtr array)
- : array_(array), count_(0), capacity_(0) {
- if (!array_)
- return;
- capacity_ = count_ = array_->size();
- DCHECK(array_->at(count_ - 1).IsLastInArray());
- }
-
- void Grow(size_t count) {
- DCHECK(count);
- if (!array_) {
- DCHECK(!count_);
- DCHECK(!capacity_);
- capacity_ = count;
- array_ = ArrayType<T>::Allocator::Create(capacity_);
- } else {
- DCHECK(array_->at(count_ - 1).IsLastInArray());
- capacity_ += count;
- array_ = ArrayType<T>::Allocator::Resize(
- ArrayType<T>::Allocator::Release(array_), capacity_);
- array_->at(count_ - 1).SetLastInArray(false);
- }
- array_->at(capacity_ - 1).SetLastInArray(true);
- }
-
- void Append(const T& item) {
- CHECK_LT(count_, capacity_);
- DCHECK(!item.IsLastInArray());
- array_->at(count_++) = item;
- ConstructTraits<T, VectorTraits<T>,
- typename ArrayType<T>::Allocator::BackendAllocator>::
- NotifyNewElements(&array_->at(count_ - 1), 1);
- if (count_ == capacity_)
- array_->at(capacity_ - 1).SetLastInArray(true);
- }
-
- typename ArrayType<T>::Allocator::PassPtr Release() {
- CHECK_EQ(count_, capacity_);
- AssertValid();
- return ArrayType<T>::Allocator::Release(array_);
- }
-
- private:
-#if DCHECK_IS_ON()
- void AssertValid() {
- for (size_t i = 0; i < count_; ++i) {
- bool is_last_in_array = (i + 1 == count_);
- DCHECK_EQ(array_->at(i).IsLastInArray(), is_last_in_array);
- }
- }
-#else
- void AssertValid() {}
-#endif
-
- typename ArrayType<T>::Allocator::Ptr array_;
- size_t count_;
- size_t capacity_;
-
- DISALLOW_COPY_AND_ASSIGN(TerminatedArrayBuilder);
-};
-
-} // namespace WTF
-
-using WTF::TerminatedArrayBuilder;
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TERMINATED_ARRAY_BUILDER_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/collator.cc b/chromium/third_party/blink/renderer/platform/wtf/text/collator.cc
index ee57a10ed4a..0225cacdec5 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/collator.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/collator.cc
@@ -32,6 +32,7 @@
#include <string.h>
#include <unicode/ucol.h>
#include <memory>
+#include "base/thread_annotations.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
@@ -39,13 +40,16 @@
namespace WTF {
-static UCollator* g_cached_collator;
-static char g_cached_equivalent_locale[Collator::kUlocFullnameCapacity];
static Mutex& CachedCollatorMutex() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, ());
return mutex;
}
+static UCollator* g_cached_collator GUARDED_BY(CachedCollatorMutex());
+static char
+ g_cached_equivalent_locale[Collator::kUlocFullnameCapacity] GUARDED_BY(
+ CachedCollatorMutex());
+
Collator::Collator(const char* locale)
: collator_(nullptr),
locale_(locale ? strdup(locale) : nullptr),
@@ -82,7 +86,7 @@ void Collator::CreateCollator() const {
UErrorCode status = U_ZERO_ERROR;
{
- Locker<Mutex> lock(CachedCollatorMutex());
+ MutexLocker lock(CachedCollatorMutex());
if (g_cached_collator) {
UColAttributeValue cached_collator_lower_first =
ucol_getAttribute(g_cached_collator, UCOL_CASE_FIRST, &status);
@@ -119,7 +123,7 @@ void Collator::CreateCollator() const {
void Collator::ReleaseCollator() {
{
- Locker<Mutex> lock(CachedCollatorMutex());
+ MutexLocker lock(CachedCollatorMutex());
if (g_cached_collator)
ucol_close(g_cached_collator);
g_cached_collator = collator_;
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h b/chromium/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h
index 4933c9b856b..b6c9dde0a43 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h
@@ -24,7 +24,9 @@
#include <limits>
#include <type_traits>
+
#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/unicode.h"
@@ -40,7 +42,7 @@ class IntegerToStringConverter {
"IntegerType must be a type of integer.");
explicit IntegerToStringConverter(IntegerType input) {
- LChar* end = buffer_ + arraysize(buffer_);
+ LChar* end = buffer_ + base::size(buffer_);
begin_ = end;
// We need to switch to the unsigned type when negating the value since
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc b/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
index bc0d9472d5c..ad83044a354 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
@@ -121,7 +122,7 @@ TEST(StringBuilderTest, Append) {
EXPECT_EQ(3U, builder_for_u_char32_append.length());
const UChar result_array[] = {U16_LEAD(fraktur_a_char),
U16_TRAIL(fraktur_a_char), 'A'};
- ExpectBuilderContent(String(result_array, arraysize(result_array)),
+ ExpectBuilderContent(String(result_array, base::size(result_array)),
builder_for_u_char32_append);
}
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_view.cc b/chromium/third_party/blink/renderer/platform/wtf/text/string_view.cc
index f578dd6a381..6f0bb8874b6 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_view.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_view.cc
@@ -51,6 +51,8 @@ bool EqualStringView(const StringView& a, const StringView& b) {
return a.IsNull() == b.IsNull();
if (a.length() != b.length())
return false;
+ if (a.Bytes() == b.Bytes() && a.Is8Bit() == b.Is8Bit())
+ return true;
if (a.Is8Bit()) {
if (b.Is8Bit())
return Equal(a.Characters8(), b.Characters8(), a.length());
@@ -92,6 +94,8 @@ bool EqualIgnoringASCIICase(const StringView& a, const StringView& b) {
return a.IsNull() == b.IsNull();
if (a.length() != b.length())
return false;
+ if (a.Bytes() == b.Bytes() && a.Is8Bit() == b.Is8Bit())
+ return true;
if (a.Is8Bit()) {
if (b.Is8Bit())
return EqualIgnoringASCIICase(a.Characters8(), b.Characters8(),
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h b/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h
index b63a49ba9ba..74885f0abcb 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h
@@ -57,7 +57,7 @@ class WTF_EXPORT StringView {
StringView(StringImpl&, unsigned offset);
StringView(StringImpl&, unsigned offset, unsigned length);
- // From an String, implemented in String.h
+ // From a String, implemented in String.h
inline StringView(const String&, unsigned offset, unsigned length);
inline StringView(const String&, unsigned offset);
inline StringView(const String&);
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
index 01adf9e46d7..ef91f3fe473 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
@@ -26,6 +26,8 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include <limits>
+
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
@@ -494,7 +496,7 @@ TEST(StringTest, StringPrinter) {
0x30C8}; // "Test" in Japanese.
EXPECT_EQ(CString("\"\\u30C6\\u30B9\\u30C8\""),
ToCStringThroughPrinter(
- String(kUnicodeSample, arraysize(kUnicodeSample))));
+ String(kUnicodeSample, base::size(kUnicodeSample))));
}
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h b/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h
index 39f91ea147b..fc67bba6fb0 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h
@@ -253,7 +253,10 @@ const void* ArrayBuffer::DataMaybeShared() const {
}
unsigned ArrayBuffer::ByteLength() const {
- return contents_.DataLength();
+ // TODO(dtapuska): Revisit this cast. ArrayBufferContents
+ // uses size_t for storing data. Whereas ArrayBuffer IDL is
+ // only uint32_t based.
+ return static_cast<unsigned>(contents_.DataLength());
}
scoped_refptr<ArrayBuffer> ArrayBuffer::Slice(int begin, int end) const {
diff --git a/chromium/third_party/blink/renderer/platform/wtf/vector.h b/chromium/third_party/blink/renderer/platform/wtf/vector.h
index 1646a56b149..b7100a83811 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/vector.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/vector.h
@@ -395,7 +395,7 @@ class VectorBufferBase {
else
buffer_ = Allocator::template AllocateVectorBacking<T>(size_to_allocate);
capacity_ = static_cast<wtf_size_t>(size_to_allocate / sizeof(T));
- Allocator::BackingWriteBarrier(buffer_);
+ Allocator::BackingWriteBarrier(buffer_, 0);
}
void AllocateExpandedBuffer(wtf_size_t new_capacity) {
@@ -408,7 +408,7 @@ class VectorBufferBase {
buffer_ = Allocator::template AllocateExpandedVectorBacking<T>(
size_to_allocate);
capacity_ = static_cast<wtf_size_t>(size_to_allocate / sizeof(T));
- Allocator::BackingWriteBarrier(buffer_);
+ Allocator::BackingWriteBarrier(buffer_, 0);
}
size_t AllocationSize(size_t capacity) const {
@@ -534,12 +534,12 @@ class VectorBuffer<T, 0, Allocator>
OffsetRange this_hole,
OffsetRange other_hole) {
static_assert(VectorTraits<T>::kCanSwapUsingCopyOrMove,
- "Cannot swap HeapVectors of TraceWrapperMembers.");
+ "Cannot swap using copy or move.");
std::swap(buffer_, other.buffer_);
- Allocator::BackingWriteBarrier(buffer_);
- Allocator::BackingWriteBarrier(other.buffer_);
std::swap(capacity_, other.capacity_);
std::swap(size_, other.size_);
+ Allocator::BackingWriteBarrier(buffer_, size_);
+ Allocator::BackingWriteBarrier(other.buffer_, other.size_);
}
using Base::AllocateBuffer;
@@ -677,16 +677,16 @@ class VectorBuffer : protected VectorBufferBase<T, true, Allocator> {
using TypeOperations = VectorTypeOperations<T, Allocator>;
static_assert(VectorTraits<T>::kCanSwapUsingCopyOrMove,
- "Cannot swap HeapVectors of TraceWrapperMembers.");
+ "Cannot swap using copy or move.");
if (Buffer() != InlineBuffer() && other.Buffer() != other.InlineBuffer()) {
// The easiest case: both buffers are non-inline. We just need to swap the
// pointers.
std::swap(buffer_, other.buffer_);
- Allocator::BackingWriteBarrier(buffer_);
- Allocator::BackingWriteBarrier(other.buffer_);
std::swap(capacity_, other.capacity_);
std::swap(size_, other.size_);
+ Allocator::BackingWriteBarrier(buffer_, size_);
+ Allocator::BackingWriteBarrier(other.buffer_, other.size_);
return;
}
@@ -747,7 +747,7 @@ class VectorBuffer : protected VectorBufferBase<T, true, Allocator> {
other.buffer_ = other.InlineBuffer();
std::swap(size_, other.size_);
ANNOTATE_NEW_BUFFER(other.buffer_, inlineCapacity, other.size_);
- Allocator::BackingWriteBarrier(buffer_);
+ Allocator::BackingWriteBarrier(buffer_, size_);
} else if (!this_source_begin &&
other_source_begin) { // Their buffer is inline, ours is not.
DCHECK_NE(Buffer(), InlineBuffer());
@@ -757,7 +757,7 @@ class VectorBuffer : protected VectorBufferBase<T, true, Allocator> {
buffer_ = InlineBuffer();
std::swap(size_, other.size_);
ANNOTATE_NEW_BUFFER(buffer_, inlineCapacity, size_);
- Allocator::BackingWriteBarrier(other.buffer_);
+ Allocator::BackingWriteBarrier(other.buffer_, other.size_);
} else { // Both buffers are inline.
DCHECK(this_source_begin);
DCHECK(other_source_begin);
diff --git a/chromium/third_party/blink/tools/apache_config/mime.types b/chromium/third_party/blink/tools/apache_config/mime.types
index 63794889639..5c11e53e570 100644
--- a/chromium/third_party/blink/tools/apache_config/mime.types
+++ b/chromium/third_party/blink/tools/apache_config/mime.types
@@ -84,7 +84,7 @@ application/set-registration-initiation
application/sgml
application/sgml-open-catalog
application/sieve
-application/signed-exchange;v=b2 sxg
+application/signed-exchange;v=b3 sxg
application/slate
application/smil smi smil
application/srgs gram
diff --git a/chromium/third_party/blink/tools/apache_config/win-httpd.conf b/chromium/third_party/blink/tools/apache_config/win-httpd.conf
index 69f1be2fd34..60a0e2ffda4 100644
--- a/chromium/third_party/blink/tools/apache_config/win-httpd.conf
+++ b/chromium/third_party/blink/tools/apache_config/win-httpd.conf
@@ -5,8 +5,10 @@ KeepAlive On
MaxKeepAliveRequests 0
KeepAliveTimeout 9999
-LoadModule alias_module modules/mod_alias.so
+LoadModule access_compat_module modules/mod_access_compat.so
LoadModule asis_module modules/mod_asis.so
+LoadModule authn_core_module modules/mod_authn_core.so
+LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule cgi_module modules/mod_cgi.so
@@ -14,7 +16,8 @@ LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
-LoadModule php5_module modules/php5apache2_2.dll
+LoadModule php7_module modules/php7apache2_4.dll
+LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule ssl_module modules/mod_ssl.so
@@ -38,7 +41,6 @@ AccessFileName .htaccess
</Files>
UseCanonicalName On
-DefaultType text/plain
HostnameLookups Off
PassEnv TEMP TMP TMPDIR
diff --git a/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer.py b/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer.py
index afa44cb4217..2015d8009b2 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer.py
@@ -44,10 +44,10 @@ class BaselineOptimizer(object):
for port_name in port_names:
self._ports[port_name] = host.port_factory.get(port_name)
- self._layout_tests_dir = default_port.layout_tests_dir()
- self._parent_of_tests = self._filesystem.dirname(self._layout_tests_dir)
- self._layout_tests_dir_name = self._filesystem.relpath(
- self._layout_tests_dir, self._parent_of_tests)
+ self._web_tests_dir = default_port.web_tests_dir()
+ self._parent_of_tests = self._filesystem.dirname(self._web_tests_dir)
+ self._web_tests_dir_name = self._filesystem.relpath(
+ self._web_tests_dir, self._parent_of_tests)
# Only used by unit tests.
self.new_results_by_directory = []
@@ -56,7 +56,7 @@ class BaselineOptimizer(object):
# A visualization of baseline fallback:
# https://docs.google.com/drawings/d/13l3IUlSE99RoKjDwEWuY1O77simAhhF6Wi0fZdkSaMA/
# The full document with more details:
- # https://chromium.googlesource.com/chromium/src/+/master/docs/testing/layout_test_baseline_fallback.md
+ # https://chromium.googlesource.com/chromium/src/+/master/docs/testing/web_test_baseline_fallback.md
# The virtual and non-virtual subtrees are identical, with the virtual
# root being the special node having multiple parents and connecting the
# two trees. We patch the virtual subtree to cut its dependencies on the
@@ -195,7 +195,7 @@ class BaselineOptimizer(object):
Returns:
The platform name, or '(generic)' if unable to make a guess.
"""
- platform_dir = self._layout_tests_dir_name + self._filesystem.sep + 'platform' + self._filesystem.sep
+ platform_dir = self._web_tests_dir_name + self._filesystem.sep + 'platform' + self._filesystem.sep
if filename.startswith(platform_dir):
return filename.replace(platform_dir, '').split(self._filesystem.sep)[0]
platform_dir = self._filesystem.join(self._parent_of_tests, platform_dir)
@@ -239,7 +239,7 @@ class BaselineOptimizer(object):
# independently. If an immediate predecessor is missing a baseline, find
# its non-virtual fallback and copy over.
_log.debug('Copying non-virtual baselines to the virtual subtree to make it independent.')
- virtual_root_baseline_path = self._filesystem.join(self._layout_tests_dir, baseline_name)
+ virtual_root_baseline_path = self._filesystem.join(self._web_tests_dir, baseline_name)
if self._filesystem.exists(virtual_root_baseline_path):
return
@@ -252,7 +252,7 @@ class BaselineOptimizer(object):
self._walk_immediate_predecessors_of_virtual_root(test_name, extension, baseline_name, patcher)
def _optimize_virtual_root(self, test_name, extension, baseline_name):
- virtual_root_baseline_path = self._filesystem.join(self._layout_tests_dir, baseline_name)
+ virtual_root_baseline_path = self._filesystem.join(self._web_tests_dir, baseline_name)
if self._filesystem.exists(virtual_root_baseline_path):
_log.debug('Virtual root baseline found. Checking if we can remove it.')
self._try_to_remove_virtual_root(test_name, baseline_name, virtual_root_baseline_path)
@@ -294,7 +294,7 @@ class BaselineOptimizer(object):
def _baseline_root(self):
"""Returns the name of the root (generic) baseline directory."""
- return self._layout_tests_dir_name
+ return self._web_tests_dir_name
def _baseline_search_path(self, port):
"""Returns the baseline search path (a list of absolute paths) of the
@@ -476,7 +476,7 @@ class BaselineOptimizer(object):
class ResultDigest(object):
"""Digest of a result file for fast comparison.
- A result file can be any actual or expected output from a layout test,
+ A result file can be any actual or expected output from a web test,
including text and image. SHA1 is used internally to digest the file.
"""
diff --git a/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py b/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py
index 0082145aac3..f0c1932a485 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py
@@ -92,22 +92,22 @@ class BaselineOptimizerTest(unittest.TestCase):
['linux-trusty', 'mac-mac10.10', 'mac-mac10.11', 'mac-mac10.12', 'mac-mac10.13', 'win-win10'])
def _assert_optimization(self, results_by_directory, directory_to_new_results, baseline_dirname='', suffix='txt'):
- layout_tests_dir = PathFinder(self.fs).layout_tests_dir()
+ web_tests_dir = PathFinder(self.fs).web_tests_dir()
test_name = 'mock-test.html'
baseline_name = 'mock-test-expected.' + suffix
self.fs.write_text_file(
- self.fs.join(layout_tests_dir, 'VirtualTestSuites'),
+ self.fs.join(web_tests_dir, 'VirtualTestSuites'),
'[{"prefix": "gpu", "base": "fast/canvas", "args": ["--foo"]}]')
for dirname, contents in results_by_directory.items():
- self.fs.write_binary_file(self.fs.join(layout_tests_dir, dirname, baseline_name), contents)
+ self.fs.write_binary_file(self.fs.join(web_tests_dir, dirname, baseline_name), contents)
baseline_optimizer = BaselineOptimizer(self.host, self.host.port_factory.get(), self.host.port_factory.all_port_names())
self.assertTrue(baseline_optimizer.optimize(
self.fs.join(baseline_dirname, test_name), suffix))
for dirname, contents in directory_to_new_results.items():
- path = self.fs.join(layout_tests_dir, dirname, baseline_name)
+ path = self.fs.join(web_tests_dir, dirname, baseline_name)
if contents is None:
# Check files that are explicitly marked as absent.
self.assertFalse(self.fs.exists(path), '%s should not exist after optimization' % path)
@@ -115,13 +115,13 @@ class BaselineOptimizerTest(unittest.TestCase):
self.assertEqual(self.fs.read_binary_file(path), contents, 'Content of %s != "%s"' % (path, contents))
for dirname in results_by_directory:
- path = self.fs.join(layout_tests_dir, dirname, baseline_name)
+ path = self.fs.join(web_tests_dir, dirname, baseline_name)
if dirname not in directory_to_new_results or directory_to_new_results[dirname] is None:
self.assertFalse(self.fs.exists(path), '%s should not exist after optimization' % path)
def _assert_reftest_optimization(self, results_by_directory, directory_to_new_results, test_path='', baseline_dirname=''):
- layout_tests_dir = PathFinder(self.fs).layout_tests_dir()
- self.fs.write_text_file(self.fs.join(layout_tests_dir, test_path, 'mock-test-expected.html'), 'ref')
+ web_tests_dir = PathFinder(self.fs).web_tests_dir()
+ self.fs.write_text_file(self.fs.join(web_tests_dir, test_path, 'mock-test-expected.html'), 'ref')
self._assert_optimization(results_by_directory, directory_to_new_results, baseline_dirname, suffix='png')
def test_linux_redundant_with_win(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_parser_unittest.py b/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_parser_unittest.py
index da63aa127c2..be84891b3f4 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_parser_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_parser_unittest.py
@@ -78,7 +78,7 @@ class DiffParserTest(unittest.TestCase):
self.assertEqual((87, 90), diff.lines[22][0:2])
# Check if a newly added file is correctly handled.
- diff = parser.files['LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum']
+ diff = parser.files['web_tests/platform/mac/fast/flexbox/box-orient-button-expected.checksum']
self.assertEqual(1, len(diff.lines))
self.assertEqual((0, 1), diff.lines[0][0:2])
diff --git a/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_test_data.py b/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_test_data.py
index 7504599b223..be76cd28e3e 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_test_data.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/checkout/diff_test_data.py
@@ -69,7 +69,7 @@ index ce21720..324929e 100644
}
bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const
-diff --git a/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum b/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum
+diff --git a/web_tests/platform/mac/fast/flexbox/box-orient-button-expected.checksum b/web_tests/platform/mac/fast/flexbox/box-orient-button-expected.checksum
new file mode 100644
index 0000000..6db26bd
--- /dev/null
diff --git a/chromium/third_party/blink/tools/blinkpy/common/config/builders.json b/chromium/third_party/blink/tools/blinkpy/common/config/builders.json
index d606556ed08..5c3e7c6016a 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/config/builders.json
+++ b/chromium/third_party/blink/tools/blinkpy/common/config/builders.json
@@ -92,6 +92,7 @@
"is_try_builder": true
},
"android_blink_rel": {
+ "bucket": "luci.chromium.try",
"port_name": "android-kitkat",
"specifiers": ["KitKat", "Release"],
"is_try_builder": true
diff --git a/chromium/third_party/blink/tools/blinkpy/common/host_mock.py b/chromium/third_party/blink/tools/blinkpy/common/host_mock.py
index 3b317477634..2131a01952a 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/host_mock.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/host_mock.py
@@ -93,7 +93,7 @@ class MockHost(MockSystemHost):
'is_try_builder': True,
},
'android_blink_rel': {
- 'bucket': 'master.tryserver.chromium.android',
+ 'bucket': 'luci.chromium.try',
'port_name': 'android-kitkat',
'specifiers': ['KitKat', 'Release'],
'is_try_builder': True,
@@ -113,7 +113,7 @@ class MockHost(MockSystemHost):
def _add_base_manifest_to_mock_filesystem(self, filesystem):
path_finder = PathFinder(filesystem)
- external_dir = path_finder.path_from_layout_tests('external')
+ external_dir = path_finder.path_from_web_tests('external')
filesystem.maybe_make_directory(filesystem.join(external_dir, 'wpt'))
# This filename should match the constant BASE_MANIFEST_NAME.
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/buildbot.py b/chromium/third_party/blink/tools/blinkpy/common/net/buildbot.py
index b2184562eed..e9547cf43ab 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/buildbot.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/buildbot.py
@@ -31,11 +31,10 @@ import logging
import json
import re
import urllib
-import urllib2
from blinkpy.common.memoized import memoized
-from blinkpy.common.net.layout_test_results import LayoutTestResults
-from blinkpy.common.net.network_transaction import NetworkTransaction
+from blinkpy.common.net.web import Web
+from blinkpy.common.net.web_test_results import WebTestResults
from blinkpy.web_tests.layout_package import json_results_generator
_log = logging.getLogger(__name__)
@@ -57,13 +56,16 @@ class Build(collections.namedtuple('Build', ('builder_name', 'build_number'))):
class BuildBot(object):
"""This class represents an interface to BuildBot-related functionality.
- This includes fetching layout test results from Google Storage;
- for more information about the layout test result format, see:
+ This includes fetching web test results from Google Storage;
+ for more information about the web test result format, see:
https://www.chromium.org/developers/the-json-test-results-format
"""
+ def __init__(self):
+ self.web = Web()
+
def results_url(self, builder_name, build_number=None, step_name=None):
- """Returns a URL for one set of archived layout test results.
+ """Returns a URL for one set of archived web test results.
If a build number is given, this will be results for a particular run;
otherwise it will be the accumulated results URL, which should have
@@ -93,30 +95,40 @@ class BuildBot(object):
def fetch_retry_summary_json(self, build):
"""Fetches and returns the text of the archived retry_summary file.
- This file is expected to contain the results of retrying layout tests
+ This file is expected to contain the results of retrying web tests
with and without a patch in a try job. It includes lists of tests
that failed only with the patch ("failures"), and tests that failed
both with and without ("ignored").
"""
url_base = '%s/%s' % (self.builder_results_url_base(build.builder_name), build.build_number)
- return NetworkTransaction(return_none_on_404=True).run(
- lambda: self.fetch_file('%s/%s' % (url_base, 'retry_summary.json')))
+ # Originally we used retry_summary.json, which is the summary of retry
+ # without patch; now we retry again with patch and ignore the flakes.
+ # See https://crbug.com/882969.
+ return self.web.get_binary('%s/%s' % (url_base, 'retry_with_patch_summary.json'),
+ return_none_on_404=True)
def accumulated_results_url_base(self, builder_name):
return self.builder_results_url_base(builder_name) + '/results/layout-test-results'
@memoized
def fetch_results(self, build, full=False):
- """Returns a LayoutTestResults object for results from a given Build.
+ """Returns a WebTestResults object for results from a given Build.
Uses full_results.json if full is True, otherwise failing_results.json.
"""
- return self.fetch_layout_test_results(
+ if not build.builder_name or not build.build_number:
+ _log.debug('Builder name or build number is None')
+ return None
+ return self.fetch_web_test_results(
self.results_url(build.builder_name, build.build_number,
step_name=self.get_layout_test_step_name(build)),
full)
@memoized
def get_layout_test_step_name(self, build):
+ if not build.builder_name or not build.build_number:
+ _log.debug('Builder name or build number is None')
+ return None
+
url = '%s/testfile?%s' % (TEST_RESULTS_SERVER, urllib.urlencode({
'builder': build.builder_name,
'buildnumber': build.build_number,
@@ -124,8 +136,7 @@ class BuildBot(object):
# This forces the server to gives us JSON rather than an HTML page.
'callback': json_results_generator.JSON_CALLBACK,
}))
- data = NetworkTransaction(return_none_on_404=True).run(
- lambda: self.fetch_file(url))
+ data = self.web.get_binary(url, return_none_on_404=True)
if not data:
_log.debug('Got 404 response from:\n%s', url)
return None
@@ -146,38 +157,24 @@ class BuildBot(object):
suites = list(set(suites))
if len(suites) != 1:
raise Exception(
- 'build %s on builder %s expected to only have one layout test '
+ 'build %s on builder %s expected to only have one web test '
'step, instead has %s' % (
build.build_number, build.builder_name, suites))
return suites[0]
@memoized
- def fetch_layout_test_results(self, results_url, full=False):
- """Returns a LayoutTestResults object for results fetched from a given URL.
+ def fetch_web_test_results(self, results_url, full=False):
+ """Returns a WebTestResults object for results fetched from a given URL.
Uses full_results.json if full is True, otherwise failing_results.json.
"""
base_filename = 'full_results.json' if full else 'failing_results.json'
- results_file = NetworkTransaction(return_none_on_404=True).run(
- lambda: self.fetch_file('%s/%s' % (results_url, base_filename)))
+ results_file = self.web.get_binary('%s/%s' % (results_url, base_filename),
+ return_none_on_404=True)
if results_file is None:
_log.debug('Got 404 response from:\n%s/%s', results_url, base_filename)
return None
- revision = NetworkTransaction(return_none_on_404=True).run(
- lambda: self.fetch_file('%s/LAST_CHANGE' % results_url))
- if revision is None:
- _log.debug('Got 404 response from:\n%s/LAST_CHANGE', results_url)
- return LayoutTestResults.results_from_string(results_file, revision)
-
- def fetch_file(self, url):
- # It seems this can return None if the url redirects and then returns 404.
- # FIXME: This could use Web instead of using urllib2 directly.
- result = urllib2.urlopen(url)
- if not result:
- return None
- # urlopen returns a file-like object which sometimes works fine with str()
- # but sometimes is a addinfourl object. In either case calling read() is correct.
- return result.read()
+ return WebTestResults.results_from_string(results_file)
def current_build_link(host):
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py b/chromium/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
index 231b923dfe7..850b26b34cc 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
@@ -31,6 +31,7 @@ import logging
import unittest
from blinkpy.common.net.buildbot import BuildBot, Build, filter_latest_builds
+from blinkpy.common.net.web_mock import MockWeb
from blinkpy.common.system.log_testing import LoggingTestCase
@@ -70,52 +71,58 @@ class BuilderTest(LoggingTestCase):
BuildBot().accumulated_results_url_base('WebKit Mac10.8 (dbg)'),
'https://test-results.appspot.com/data/layout_results/WebKit_Mac10_8__dbg_/results/layout-test-results')
- def test_fetch_layout_test_results_with_no_results_fetched(self):
+ def test_fetch_web_test_results_with_no_results_fetched(self):
buildbot = BuildBot()
-
- def fetch_file(url):
- return None if url.endswith('failing_results.json') else 'contents'
-
- buildbot.fetch_file = fetch_file
- results = buildbot.fetch_layout_test_results(buildbot.results_url('B'))
+ buildbot.web = MockWeb()
+ results = buildbot.fetch_web_test_results(buildbot.results_url('B'))
self.assertIsNone(results)
self.assertLog([
'DEBUG: Got 404 response from:\n'
'https://test-results.appspot.com/data/layout_results/B/results/layout-test-results/failing_results.json\n'
])
- def test_fetch_layout_test_results_weird_step_name(self):
+ def test_fetch_results_with_weird_step_name(self):
buildbot = BuildBot()
-
- def fetch_file(url):
- if '/testfile' in url:
- return ('ADD_RESULTS(%s);' % (json.dumps(
+ buildbot.web = MockWeb(urls={
+ 'https://test-results.appspot.com/testfile?buildnumber=123&'
+ 'callback=ADD_RESULTS&builder=builder&name=full_results.json':
+ 'ADD_RESULTS(%s);' % (json.dumps(
[{"TestType": "webkit_layout_tests on Intel GPU (with patch)"},
- {"TestType": "base_unittests (with patch)"}])))
- return json.dumps({'passed': True}) if url.endswith('failing_results.json') else 'deadbeef'
-
- buildbot.fetch_file = fetch_file
+ {"TestType": "base_unittests (with patch)"}])),
+ 'https://test-results.appspot.com/data/layout_results/builder/123/'
+ 'webkit_layout_tests%20on%20Intel%20GPU%20%28with%20patch%29/'
+ 'layout-test-results/failing_results.json':
+ json.dumps({'passed': True}),
+ })
results = buildbot.fetch_results(Build('builder', 123))
self.assertEqual(results._results, { # pylint: disable=protected-access
'passed': True
})
self.assertLog([])
- def test_get_step_name(self):
+ def test_fetch_results_without_build_number(self):
buildbot = BuildBot()
+ self.assertIsNone(buildbot.fetch_results(Build('builder', None)))
- def fetch_file(_):
- return ('ADD_RESULTS(%s);' % (json.dumps(
- [{"TestType": "webkit_layout_tests (with patch)"},
- {"TestType": "not_site_per_process_webkit_layout_tests (with patch)"},
- {"TestType": "webkit_layout_tests (retry with patch)"},
- {"TestType": "base_unittests (with patch)"}])))
-
- buildbot.fetch_file = fetch_file
+ def test_get_step_name(self):
+ buildbot = BuildBot()
+ buildbot.web = MockWeb(urls={
+ 'https://test-results.appspot.com/testfile?buildnumber=5&'
+ 'callback=ADD_RESULTS&builder=foo&name=full_results.json':
+ 'ADD_RESULTS(%s);' % (json.dumps(
+ [{"TestType": "webkit_layout_tests (with patch)"},
+ {"TestType": "not_site_per_process_webkit_layout_tests (with patch)"},
+ {"TestType": "webkit_layout_tests (retry with patch)"},
+ {"TestType": "base_unittests (with patch)"}]))
+ })
step_name = buildbot.get_layout_test_step_name(Build('foo', 5))
self.assertEqual(step_name, 'webkit_layout_tests (with patch)')
self.assertLog([])
+ def test_get_step_name_without_build_number(self):
+ buildbot = BuildBot()
+ self.assertIsNone(buildbot.get_layout_test_step_name(Build('builder', None)))
+
class BuildBotHelperFunctionTest(unittest.TestCase):
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py b/chromium/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py
index 6fd5a5db0da..2181e11f7b5 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py
@@ -52,7 +52,7 @@ class GitCLTest(unittest.TestCase):
],
[
'git', 'cl', 'try',
- '-B', 'master.tryserver.chromium.android',
+ '-B', 'luci.chromium.try',
'-b', 'android_blink_rel',
'--auth-refresh-token-json', 'token.json'
],
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/web.py b/chromium/third_party/blink/tools/blinkpy/common/net/web.py
index b979b6ddada..c3573054d97 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/web.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/web.py
@@ -33,11 +33,20 @@ from blinkpy.common.net.network_transaction import NetworkTransaction
class Web(object):
+ class _HTTPRedirectHandler2(urllib2.HTTPRedirectHandler): # pylint:disable=no-init
+ """A subclass of HTTPRedirectHandler to support 308 Permanent Redirect."""
+
+ def http_error_308(self, req, fp, code, msg, headers): # pylint:disable=unused-argument
+ # We have to override the code to 301 (Moved Permanently);
+ # otherwise, HTTPRedirectHandler will throw a HTTPError.
+ return self.http_error_301(req, fp, 301, msg, headers)
+
def get_binary(self, url, return_none_on_404=False):
- return NetworkTransaction(return_none_on_404=return_none_on_404).run(lambda: urllib2.urlopen(url).read())
+ return NetworkTransaction(return_none_on_404=return_none_on_404).run(
+ lambda: self.request('GET', url).read())
- def request(self, method, url, data, headers=None):
- opener = urllib2.build_opener(urllib2.HTTPHandler)
+ def request(self, method, url, data=None, headers=None):
+ opener = urllib2.build_opener(Web._HTTPRedirectHandler2)
request = urllib2.Request(url=url, data=data)
request.get_method = lambda: method
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/web_mock.py b/chromium/third_party/blink/tools/blinkpy/common/net/web_mock.py
index a0733c59487..f044ea3a278 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/web_mock.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/web_mock.py
@@ -44,7 +44,7 @@ class MockWeb(object):
return None
return 'MOCK Web result, 404 Not found'
- def request(self, method, url, data, headers=None): # pylint: disable=unused-argument
+ def request(self, method, url, data=None, headers=None): # pylint: disable=unused-argument
return MockResponse(self.responses.pop(0))
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/layout_test_results.py b/chromium/third_party/blink/tools/blinkpy/common/net/web_test_results.py
index 02d7d59df24..27bfbaed172 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/layout_test_results.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/web_test_results.py
@@ -32,7 +32,7 @@ from blinkpy.common.memoized import memoized
from blinkpy.web_tests.layout_package import json_results_generator
-class LayoutTestResult(object):
+class WebTestResult(object):
def __init__(self, test_name, result_dict):
self._test_name = test_name
@@ -78,21 +78,17 @@ class LayoutTestResult(object):
return self.last_retry_result() == 'MISSING'
-# FIXME: This should be unified with ResultsSummary or other NRWT layout tests code
-# in the layout_tests package.
+# FIXME: This should be unified with ResultsSummary or other NRWT web tests code
+# in the web_tests package.
# This doesn't belong in common.net, but we don't have a better place for it yet.
-class LayoutTestResults(object):
+class WebTestResults(object):
@classmethod
- def results_from_string(cls, string, chromium_revision=None):
- """Creates a LayoutTestResults object from a test result JSON string.
+ def results_from_string(cls, string):
+ """Creates a WebTestResults object from a test result JSON string.
Args:
- string: JSON string containing layout test result.
- chromium_revision: If given, it will override the chromium_revision
- field in json, to indicate the last revision that has completed
- uploading onto the storage server. chromium_revision can be a
- git hash or position number.
+ string: JSON string containing web test result.
"""
if not string:
@@ -103,7 +99,7 @@ class LayoutTestResults(object):
if not json_dict:
return None
- return cls(json_dict, chromium_revision)
+ return cls(json_dict)
def __init__(self, parsed_json, chromium_revision=None):
self._results = parsed_json
@@ -131,32 +127,32 @@ class LayoutTestResults(object):
if part not in tree:
return None
tree = tree[part]
- return LayoutTestResult(test, tree)
+ return WebTestResult(test, tree)
def for_each_test(self, handler):
- LayoutTestResults._for_each_test(self._test_result_tree(), handler, '')
+ WebTestResults._for_each_test(self._test_result_tree(), handler, '')
@staticmethod
def _for_each_test(tree, handler, prefix=''):
for key in tree:
new_prefix = (prefix + '/' + key) if prefix else key
if 'actual' not in tree[key]:
- LayoutTestResults._for_each_test(tree[key], handler, new_prefix)
+ WebTestResults._for_each_test(tree[key], handler, new_prefix)
else:
- handler(LayoutTestResult(new_prefix, tree[key]))
+ handler(WebTestResult(new_prefix, tree[key]))
def _test_result_tree(self):
return self._results['tests']
def _filter_tests(self, result_filter):
- """Returns LayoutTestResult objects for tests which pass the given filter."""
+ """Returns WebTestResult objects for tests which pass the given filter."""
results = []
def add_if_passes(result):
if result_filter(result):
results.append(result)
- LayoutTestResults._for_each_test(self._test_result_tree(), add_if_passes)
+ WebTestResults._for_each_test(self._test_result_tree(), add_if_passes)
return sorted(results, key=lambda r: r.test_name())
def didnt_run_as_expected_results(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/common/net/layout_test_results_unittest.py b/chromium/third_party/blink/tools/blinkpy/common/net/web_test_results_unittest.py
index 32ca91404e2..40a266623e8 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/net/layout_test_results_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/net/web_test_results_unittest.py
@@ -28,10 +28,10 @@
import unittest
-from blinkpy.common.net.layout_test_results import LayoutTestResults
+from blinkpy.common.net.web_test_results import WebTestResults
-class LayoutTestResultsTest(unittest.TestCase):
+class WebTestResultsTest(unittest.TestCase):
# The real files have no whitespace, but newlines make this much more readable.
example_full_results_json = """ADD_RESULTS({
"tests": {
@@ -87,7 +87,7 @@ class LayoutTestResultsTest(unittest.TestCase):
},
"skipped": 450,
"num_regressions": 15,
- "layout_tests_dir": "/b/build/slave/Webkit_Mac10_5/build/src/third_party/WebKit/LayoutTests",
+ "layout_tests_dir": "/b/build/slave/Webkit_Mac10_5/build/src/third_party/blink/web_tests",
"version": 3,
"num_passes": 77,
"fixable": 1220,
@@ -97,26 +97,26 @@ class LayoutTestResultsTest(unittest.TestCase):
});"""
def test_results_from_string(self):
- self.assertIsNone(LayoutTestResults.results_from_string(None))
- self.assertIsNone(LayoutTestResults.results_from_string(''))
+ self.assertIsNone(WebTestResults.results_from_string(None))
+ self.assertIsNone(WebTestResults.results_from_string(''))
def test_was_interrupted(self):
- self.assertTrue(LayoutTestResults.results_from_string(
+ self.assertTrue(WebTestResults.results_from_string(
'ADD_RESULTS({"tests":{},"interrupted":true});').run_was_interrupted())
- self.assertFalse(LayoutTestResults.results_from_string(
+ self.assertFalse(WebTestResults.results_from_string(
'ADD_RESULTS({"tests":{},"interrupted":false});').run_was_interrupted())
def test_chromium_revision(self):
- self.assertEqual(LayoutTestResults.results_from_string(self.example_full_results_json).chromium_revision(), 1234)
+ self.assertEqual(WebTestResults.results_from_string(self.example_full_results_json).chromium_revision(), 1234)
def test_actual_results(self):
- results = LayoutTestResults.results_from_string(self.example_full_results_json)
+ results = WebTestResults.results_from_string(self.example_full_results_json)
self.assertEqual(results.result_for_test('fast/dom/prototype-banana.html').actual_results(), 'PASS')
self.assertEqual(results.result_for_test('fast/dom/prototype-taco.html').actual_results(), 'PASS TEXT')
self.assertFalse(results.result_for_test('nonexistant.html'))
def test_didnt_run_as_expected_results(self):
- results = LayoutTestResults.results_from_string(self.example_full_results_json)
+ results = WebTestResults.results_from_string(self.example_full_results_json)
self.assertEqual(
[r.test_name() for r in results.didnt_run_as_expected_results()],
[
@@ -130,7 +130,7 @@ class LayoutTestResultsTest(unittest.TestCase):
])
def test_didnt_run_as_expected_slow_test(self):
- results = LayoutTestResults({
+ results = WebTestResults({
'tests': {
'fast': {
'dom': {
diff --git a/chromium/third_party/blink/tools/blinkpy/common/path_finder.py b/chromium/third_party/blink/tools/blinkpy/common/path_finder.py
index 3fc8ce149d8..e4e96565f0d 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/path_finder.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/path_finder.py
@@ -101,7 +101,7 @@ def _does_blink_web_tests_exist():
TESTS_IN_BLINK = _does_blink_web_tests_exist()
-# LayoutTests / web_tests path relative to the repository root.
+# web_tests path relative to the repository root.
# Path separators are always '/', and this contains the trailing '/'.
RELATIVE_WEB_TESTS = 'third_party/blink/web_tests/'
WEB_TESTS_LAST_COMPONENT = 'web_tests'
@@ -118,8 +118,7 @@ class PathFinder(object):
def chromium_base(self):
return self._filesystem.dirname(self._filesystem.dirname(self._blink_base()))
- # TODO(tkent): Rename this to web_tests_dir().
- def layout_tests_dir(self):
+ def web_tests_dir(self):
return self.path_from_chromium_base('third_party', 'blink', 'web_tests')
def perf_tests_dir(self):
@@ -146,8 +145,8 @@ class PathFinder(object):
def path_from_blink_tools(self, *comps):
return self._filesystem.join(self._filesystem.join(self.chromium_base(), 'third_party', 'blink', 'tools'), *comps)
- def path_from_layout_tests(self, *comps):
- return self._filesystem.join(self.layout_tests_dir(), *comps)
+ def path_from_web_tests(self, *comps):
+ return self._filesystem.join(self.web_tests_dir(), *comps)
@memoized
def depot_tools_base(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/common/path_finder_unittest.py b/chromium/third_party/blink/tools/blinkpy/common/path_finder_unittest.py
index ec53f4da354..13baca96746 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/path_finder_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/path_finder_unittest.py
@@ -21,20 +21,20 @@ class TestPathFinder(unittest.TestCase):
finder.path_from_chromium_base('foo', 'bar.baz'),
'/mock-checkout/foo/bar.baz')
- def test_layout_tests_dir(self):
+ def test_web_tests_dir(self):
finder = PathFinder(MockFileSystem())
self.assertEqual(
- finder.layout_tests_dir(),
+ finder.web_tests_dir(),
'/mock-checkout/' + RELATIVE_WEB_TESTS[:-1])
- def test_layout_tests_dir_with_backslash_sep(self):
+ def test_web_tests_dir_with_backslash_sep(self):
filesystem = MockFileSystem()
filesystem.sep = '\\'
filesystem.path_to_module = lambda _: (
'C:\\mock-checkout\\third_party\\blink\\tools\\blinkpy\\foo.py')
finder = PathFinder(filesystem)
self.assertEqual(
- finder.layout_tests_dir(),
+ finder.web_tests_dir(),
'C:\\mock-checkout\\third_party\\blink\\web_tests')
def test_perf_tests_dir(self):
@@ -43,10 +43,10 @@ class TestPathFinder(unittest.TestCase):
finder.perf_tests_dir(),
'/mock-checkout/third_party/blink/perf_tests')
- def test_path_from_layout_tests(self):
+ def test_path_from_web_tests(self):
finder = PathFinder(MockFileSystem())
self.assertEqual(
- finder.path_from_layout_tests('external', 'wpt'),
+ finder.path_from_web_tests('external', 'wpt'),
'/mock-checkout/' + RELATIVE_WEB_TESTS + 'external/wpt')
def test_depot_tools_base_not_found(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/common/system/executive.py b/chromium/third_party/blink/tools/blinkpy/common/system/executive.py
index bf33f76a5b5..5bf3d993233 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/system/executive.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/system/executive.py
@@ -111,8 +111,13 @@ class Executive(object):
Will fail silently if pid does not exist or insufficient permissions.
"""
- # According to http://docs.python.org/library/os.html
- # os.kill isn't available on Windows.
+ # This method behaves differently on Windows and Linux. On Windows, it
+ # kills the process as well as all of its subprocesses (because of the
+ # '/t' flag). Some call sites depend on this behaviour (e.g. to kill all
+ # worker processes of wptserve on Windows).
+ # TODO(robertma): Replicate the behaviour on POSIX by calling setsid()
+ # in Popen's preexec_fn hook, and perhaps rename the method to
+ # kill_process_tree.
if sys.platform == 'win32':
# Workaround for race condition that occurs when the browser is
# killed as it's launching a process. This sometimes leaves a child
diff --git a/chromium/third_party/blink/tools/blinkpy/common/unified_diff.py b/chromium/third_party/blink/tools/blinkpy/common/unified_diff.py
index 1b5d37e22b5..7f0700aa8df 100644
--- a/chromium/third_party/blink/tools/blinkpy/common/unified_diff.py
+++ b/chromium/third_party/blink/tools/blinkpy/common/unified_diff.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""A utility function to do text diffs of expected and actual layout test results."""
+"""A utility function to do text diffs of expected and actual web test results."""
import difflib
diff --git a/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 3b3544dd34d..c4ae1f98fb8 100755
--- a/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -69,6 +69,10 @@ _CONFIG = [
'base::span',
'logging::GetVlogLevel',
+ # //base/observer_list.h.
+ 'base::ObserverList',
+ 'base::CheckedObserver',
+
# //base/bind_helpers.h.
'base::DoNothing',
@@ -108,6 +112,9 @@ _CONFIG = [
'base::IsTypeInRangeForNumericType',
'base::IsValueNegative',
+ # //base/strings/char_traits.h.
+ 'base::CharTraits',
+
# //base/synchronization/waitable_event.h.
'base::WaitableEvent',
@@ -134,6 +141,7 @@ _CONFIG = [
'base::debug::.+',
# Base atomic utilities
+ 'base::AtomicFlag',
'base::AtomicSequenceNumber',
# Task traits
@@ -172,6 +180,7 @@ _CONFIG = [
# Chromium geometry types.
'gfx::Point',
+ 'gfx::Point3F',
'gfx::Rect',
'gfx::RectF',
'gfx::Size',
@@ -248,6 +257,7 @@ _CONFIG = [
'root_scroller_util::.+',
'scheduler::.+',
'scroll_customization::.+',
+ 'scroll_timeline_util::.+',
'style_change_extra_data::.+',
'style_change_reason::.+',
'svg_path_parser::.+',
@@ -324,6 +334,12 @@ _CONFIG = [
],
},
{
+ 'paths': ['third_party/blink/renderer/controller/oom_intervention_impl.cc'],
+ 'allowed': [
+ 'base::BindOnce',
+ ],
+ },
+ {
'paths': ['third_party/blink/renderer/core/animation'],
'allowed': [
'[a-z_]+_functions::.+',
@@ -401,6 +417,15 @@ _CONFIG = [
],
},
{
+ 'paths': ['third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc'],
+ 'allowed': [
+ # cc painting types.
+ 'cc::ContentLayerClient',
+ 'cc::DisplayItemList',
+ 'cc::DrawRecordOp',
+ ],
+ },
+ {
'paths': ['third_party/blink/renderer/core/inspector/inspector_performance_agent.cc'],
'allowed': [
'base::subtle::TimeTicksNowIgnoringOverride',
@@ -434,6 +459,14 @@ _CONFIG = [
},
{
'paths': [
+ 'third_party/blink/renderer/modules/mediastream/',
+ ],
+ 'allowed': [
+ 'media::.+',
+ ]
+ },
+ {
+ 'paths': [
'third_party/blink/renderer/modules/indexeddb/',
],
'allowed': [
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/README.chromium b/chromium/third_party/blink/tools/blinkpy/third_party/README.chromium
index 57b71b87958..ff596681578 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/README.chromium
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -32,7 +32,7 @@ Local Modifications: None
Name: web-platform-tests - Test Suites for Web Platform specifications
Short Name: wpt
URL: https://github.com/web-platform-tests/wpt/
-Version: c757432db546a30c1e6ef833df0b597df2dad6bd
+Version: f759f0b3a8cb7457adbf30dc0734d3a158ce4990
License: LICENSES FOR W3C TEST SUITES (http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html)
License File: wpt/wpt/LICENSE.md
Security Critical: no
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium
index 6d71072bce1..0de32f410f2 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium
@@ -1,4 +1,4 @@
-W3C Web Platform Tests in Blink Layout Tests
+W3C Web Platform Tests in Blink Web Tests
Design Doc: https://goo.gl/iXUaZd
@@ -28,7 +28,7 @@ changing the ports (HTTP/S, WS/S), make sure to also:
- update `WPT_HOST_AND_PORTS` in
`//third_party/blink/tools/blinkpy/web_tests/port/driver.py`
-- update LayoutTestContentBrowserClient::GetOriginsRequiringDedicatedProcess()
+- update WebTestContentBrowserClient::GetOriginsRequiringDedicatedProcess()
checkout.sh
===========
@@ -71,6 +71,10 @@ re-generate them:
Rolling in WPT
+If there are new files that need to be rolled in, add the intended files to
+the WPTWhiteList. Ensure these files are in the correct order by running
+"LC_ALL=C sort WPTWhiteList".
+
When rolling in new versions of WPT support, modify WPT_HEAD in checkout.sh to
the desired HEAD position. You can then call "./checkout.sh clone" which will
pull in all the code.
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList
index 8349f0421a2..0c3a99f3e11 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList
@@ -103,6 +103,11 @@
./tools/third_party/webencodings/webencodings/mklabels.py
./tools/third_party/webencodings/webencodings/tests.py
./tools/third_party/webencodings/webencodings/x_user_defined.py
+./tools/webdriver/webdriver/__init__.py
+./tools/webdriver/webdriver/client.py
+./tools/webdriver/webdriver/error.py
+./tools/webdriver/webdriver/protocol.py
+./tools/webdriver/webdriver/transport.py
./tools/wpt/__init__.py
./tools/wpt/browser.py
./tools/wpt/commands.json
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
index 24a3a3577ef..d927f1844d1 100755
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -9,7 +9,7 @@ cd $DIR
TARGET_DIR=$DIR/wpt
REMOTE_REPO="https://chromium.googlesource.com/external/github.com/web-platform-tests/wpt.git"
-WPT_HEAD=6279ae5cc55eb91bb086ab1d0f1969c180cbedc2
+WPT_HEAD=f759f0b3a8cb7457adbf30dc0734d3a158ce4990
function clone {
# Remove existing repo if already exists.
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt.config.json b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt.config.json
index 897d4e9ecaa..3a674155c52 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt.config.json
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt.config.json
@@ -3,6 +3,7 @@
"ws_doc_root": null,
"check_subdomains": false,
"server_host": "127.0.0.1",
+ "log_level": "info",
"ports": {
"http": [8001, 8081],
"https": [8444],
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/gitignore/gitignore.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/gitignore/gitignore.py
index 8702cec7db5..9b661308ab1 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/gitignore/gitignore.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/gitignore/gitignore.py
@@ -1,21 +1,29 @@
import re
import os
+import itertools
+from six import itervalues, iteritems
+from collections import defaultdict
+
end_space = re.compile(r"([^\\]\s)*$")
-def fnmatch_translate(pat, path_name=False):
+def fnmatch_translate(pat):
parts = []
- seq = False
+ seq = None
i = 0
- if pat[0] == "/" or path_name:
+ any_char = "[^/]"
+ if pat[0] == "/":
parts.append("^")
- any_char = "[^/]"
- if pat[0] == "/":
- pat = pat[1:]
+ pat = pat[1:]
else:
- any_char = "."
+ # By default match the entire path up to a /
+ # but if / doesn't appear in the pattern we will mark is as
+ # a name pattern and just produce a pattern that matches against
+ # the filename
parts.append("^(?:.*/)?")
+
+ name_pattern = True
if pat[-1] == "/":
# If the last character is / match this directory or any subdirectory
pat = pat[:-1]
@@ -31,11 +39,10 @@ def fnmatch_translate(pat, path_name=False):
parts.append(re.escape(c))
else:
raise ValueError
- elif seq:
+ elif seq is not None:
+ # TODO: this doesn't really handle invalid sequences in the right way
if c == "]":
- seq = False
- # First two cases are to deal with the case where / is the only character
- # in the sequence but path_name is True so it shouldn't match anything
+ seq = None
if parts[-1] == "[":
parts = parts[:-1]
elif parts[-1] == "^" and parts[-2] == "[":
@@ -44,35 +51,46 @@ def fnmatch_translate(pat, path_name=False):
parts.append(c)
elif c == "-":
parts.append(c)
- elif not (path_name and c == "/"):
+ else:
parts += re.escape(c)
elif c == "[":
parts.append("[")
if i < len(pat) - 1 and pat[i+1] in ("!", "^"):
parts.append("^")
i += 1
- seq = True
+ seq = i
elif c == "*":
if i < len(pat) - 1 and pat[i+1] == "*":
- parts.append(any_char + "*")
+ if i > 0 and pat[i-1] != "/":
+ raise ValueError
+ parts.append(".*")
i += 1
- if i < len(pat) - 1 and pat[i+1] == "*":
+ if i < len(pat) - 1 and pat[i+1] != "/":
raise ValueError
else:
parts.append(any_char + "*")
elif c == "?":
parts.append(any_char)
+ elif c == "/" and not seq:
+ name_pattern = False
+ parts.append(c)
else:
parts.append(re.escape(c))
i += 1
- if seq:
+ if name_pattern:
+ parts[0] = "^"
+
+ if seq is not None:
raise ValueError
parts.append(suffix)
try:
- return re.compile("".join(parts))
+ return name_pattern, re.compile("".join(parts))
except Exception:
- raise
+ raise ValueError
+
+# Regexp matching rules that have to be converted to patterns
+pattern_re = re.compile(r".*[\*\[\?]")
def parse_line(line):
@@ -89,11 +107,19 @@ def parse_line(line):
if dir_only:
line = line[:-1]
- return invert, dir_only, fnmatch_translate(line, dir_only)
+ # Could make a special case for **/foo, but we don't have any patterns like that
+ if not invert and not pattern_re.match(line):
+ literal = True
+ pattern = tuple(line.rsplit("/", 1))
+ else:
+ pattern = fnmatch_translate(line)
+ literal = False
+
+ return invert, dir_only, literal, pattern
class PathFilter(object):
- def __init__(self, root, extras=None):
+ def __init__(self, root, extras=None, cache=None):
if root:
ignore_path = os.path.join(root, ".gitignore")
else:
@@ -103,51 +129,123 @@ class PathFilter(object):
return
self.trivial = False
- self.rules_file = []
- self.rules_dir = []
+ self.literals_file = defaultdict(dict)
+ self.literals_dir = defaultdict(dict)
+ self.patterns_file = []
+ self.patterns_dir = []
+ self.cache = cache or {}
if extras is None:
extras = []
if ignore_path and os.path.exists(ignore_path):
- self._read_ignore(ignore_path)
-
- for item in extras:
- self._read_line(item)
+ args = ignore_path, extras
+ else:
+ args = None, extras
+ self._read_ignore(*args)
- def _read_ignore(self, ignore_path):
- with open(ignore_path) as f:
- for line in f:
- self._read_line(line)
+ def _read_ignore(self, ignore_path, extras):
+ if ignore_path is not None:
+ with open(ignore_path) as f:
+ for line in f:
+ self._read_line(line)
+ for line in extras:
+ self._read_line(line)
def _read_line(self, line):
parsed = parse_line(line)
if not parsed:
return
- invert, dir_only, regexp = parsed
- if dir_only:
- self.rules_dir.append((regexp, invert))
+ invert, dir_only, literal, rule = parsed
+
+ if invert:
+ # For exclude rules, we attach the rules to all preceeding patterns, so
+ # that we can match patterns out of order and check if they were later
+ # overriden by an exclude rule
+ assert not literal
+ if not dir_only:
+ rules_iter = itertools.chain(
+ itertools.chain(*(iteritems(item) for item in itervalues(self.literals_dir))),
+ itertools.chain(*(iteritems(item) for item in itervalues(self.literals_file))),
+ self.patterns_dir,
+ self.patterns_file)
+ else:
+ rules_iter = itertools.chain(
+ itertools.chain(*(iteritems(item) for item in itervalues(self.literals_dir))),
+ self.patterns_dir)
+
+ for rules in rules_iter:
+ rules[1].append(rule)
else:
- self.rules_file.append((regexp, invert))
+ if literal:
+ if len(rule) == 1:
+ dir_name, pattern = None, rule[0]
+ else:
+ dir_name, pattern = rule
+ self.literals_dir[dir_name][pattern] = []
+ if not dir_only:
+ self.literals_file[dir_name][pattern] = []
+ else:
+ self.patterns_dir.append((rule, []))
+ if not dir_only:
+ self.patterns_file.append((rule, []))
+
+ def filter(self, iterator):
+ empty = {}
+ for dirpath, dirnames, filenames in iterator:
+ orig_dirpath = dirpath
+ if os.path.sep != "/":
+ dirpath = dirpath.replace(os.path.sep, "/")
+
+ keep_dirs = []
+ keep_files = []
+
+ for iter_items, literals, patterns, target, suffix in [
+ (dirnames, self.literals_dir, self.patterns_dir, keep_dirs, "/"),
+ (filenames, self.literals_file, self.patterns_file, keep_files, "")]:
+ for item in iter_items:
+ name = item[0]
+ if dirpath:
+ path = "%s/%s" % (dirpath, name) + suffix
+ else:
+ path = name + suffix
+ if path in self.cache:
+ if not self.cache[path]:
+ target.append(item)
+ continue
+ for rule_dir in [None, dirpath]:
+ if name in literals.get(rule_dir, empty):
+ exclude = literals[rule_dir][name]
+ if not any(rule.match(path) for rule in exclude):
+ # Skip this item
+ self.cache[path] = True
+ break
+ else:
+ for (component_only, pattern), exclude in patterns:
+ if component_only:
+ match = pattern.match(name)
+ else:
+ match = pattern.match(path)
+ if match:
+ if not any(rule.match(name if name_only else path)
+ for name_only, rule in exclude):
+ # Skip this item
+ self.cache[path] = True
+ break
+ else:
+ self.cache[path] = False
+ target.append(item)
+
+ dirnames[:] = keep_dirs
+ assert ".git" not in dirnames
+ yield orig_dirpath, dirnames, keep_files
+
+ def __call__(self, iterator):
+ if self.trivial:
+ return iterator
- def __call__(self, path):
- if os.path.sep != "/":
- path = path.replace(os.path.sep, "/")
+ return self.filter(iterator)
- if self.trivial:
- return True
- path_is_dir = path[-1] == "/"
- if path_is_dir:
- path = path[:-1]
- rules = self.rules_dir
- else:
- rules = self.rules_file
-
- include = True
- for regexp, invert in rules:
- if not include and invert and regexp.match(path):
- include = True
- elif include and not invert and regexp.match(path):
- include = False
- return include
+def has_ignore(dirpath):
+ return os.path.exists(os.path.join(dirpath, ".gitignore"))
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
index fedc740b4e8..03f0ecc7780 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
@@ -16,6 +16,7 @@ from . import fnmatch
from .. import localpaths
from ..gitignore.gitignore import PathFilter
from ..wpt import testfiles
+from ..manifest.vcs import walk
from manifest.sourcefile import SourceFile, js_meta_re, python_meta_re, space_chars, get_any_variants, get_default_any_variants
from six import binary_type, iteritems, itervalues
@@ -67,14 +68,14 @@ def all_filesystem_paths(repo_root, subdir=None):
expanded_path = subdir
else:
expanded_path = repo_root
- for dirpath, dirnames, filenames in os.walk(expanded_path):
- for filename in filenames:
- path = os.path.relpath(os.path.join(dirpath, filename), repo_root)
- if path_filter(path):
- yield path
- dirnames[:] = [item for item in dirnames if
- path_filter(os.path.relpath(os.path.join(dirpath, item) + "/",
- repo_root)+"/")]
+ for dirpath, dirnames, filenames in path_filter(walk(expanded_path)):
+ for filename, _ in filenames:
+ path = os.path.join(dirpath, filename)
+ if subdir:
+ path = os.path.join(subdir, path)
+ assert not os.path.isabs(path), path
+ yield path
+
def _all_files_equal(paths):
"""
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/commands.json b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/commands.json
index d6ccd98809e..074d248bf27 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/commands.json
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/commands.json
@@ -2,5 +2,4 @@
{"path": "update.py", "script": "run", "parser": "create_parser", "help": "Update the MANIFEST.json file",
"virtualenv": false},
"manifest-download":
- {"path": "download.py", "script": "run", "parser": "create_parser", "help": "Download recent pregenerated MANIFEST.json file",
- "virtualenv": false}}
+ {"path": "download.py", "script": "run", "parser": "create_parser", "help": "Download recent pregenerated MANIFEST.json file", "virtualenv": false}}
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/download.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/download.py
index 8bb3cb673de..2e505f371ed 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/download.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/download.py
@@ -33,46 +33,53 @@ def should_download(manifest_path, rebuild_time=timedelta(days=5)):
return False
-def git_commits(repo_root):
+def merge_pr_tags(repo_root, max_count=50):
git = Git.get_func(repo_root)
- return [item for item in git("log", "--format=%H", "-n50").split("\n") if item]
-
-
-def github_url(commits):
- try:
- resp = urlopen("https://api.github.com/repos/web-platform-tests/wpt/releases")
- except Exception:
- return None
-
- if resp.code != 200:
- return None
-
- try:
- releases = json.load(resp.fp)
- except ValueError:
- logger.warning("Response was not valid JSON")
- return None
-
- fallback = None
- for release in releases:
- for commit in commits:
- for item in release["assets"]:
- if item["name"] == "MANIFEST-%s.json.gz" % commit:
- return item["browser_download_url"]
- elif item["name"] == "MANIFEST.json.gz" and not fallback:
- fallback = item["browser_download_url"]
- if fallback:
- logger.info("Can't find a commit-specific manifest so just using the most recent one")
- return fallback
-
-
-def download_manifest(manifest_path, commits_func, url_func, force=False):
+ tags = []
+ for line in git("log", "--format=%D", "--max-count=%s" % max_count).split("\n"):
+ for ref in line.split(", "):
+ if ref.startswith("tag: merge_pr_"):
+ tags.append(ref[5:])
+ return tags
+
+
+def github_url(tags):
+ for tag in tags:
+ url = "https://api.github.com/repos/web-platform-tests/wpt/releases/tags/%s" % tag
+ try:
+ resp = urlopen(url)
+ except Exception:
+ logger.warning("Fetching %s failed" % url)
+ continue
+
+ if resp.code != 200:
+ logger.warning("Fetching %s failed; got HTTP status %d" % (url, resp.code))
+ continue
+
+ try:
+ release = json.load(resp.fp)
+ except ValueError:
+ logger.warning("Response was not valid JSON")
+ return None
+
+ for item in release["assets"]:
+ # Accept both ways of naming the manfest asset, even though
+ # there's no longer a reason to include the commit sha.
+ if item["name"].startswith("MANIFEST-") and item["name"].endswith(".json.gz"):
+ return item["browser_download_url"]
+ elif item["name"] == "MANIFEST.json.gz":
+ return item["browser_download_url"]
+
+ return None
+
+
+def download_manifest(manifest_path, tags_func, url_func, force=False):
if not force and not should_download(manifest_path):
return False
- commits = commits_func()
+ tags = tags_func()
- url = url_func(commits)
+ url = url_func(tags)
if not url:
logger.warning("No generated manifest found")
return False
@@ -120,7 +127,7 @@ def create_parser():
def download_from_github(path, tests_root, force=False):
- return download_manifest(path, lambda: git_commits(tests_root), github_url,
+ return download_manifest(path, lambda: merge_pr_tags(tests_root), github_url,
force=force)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
index ddf046a68fa..2bbdf0d5a5b 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
@@ -2,19 +2,21 @@ from six.moves.urllib.parse import urljoin, urlparse
from abc import ABCMeta, abstractproperty
-def get_source_file(source_files, tests_root, manifest, path):
- def make_new():
+class SourceFileCache(object):
+ def __init__(self):
+ self.source_files = {}
+
+ def make_new(self, tests_root, path, url_base):
from .sourcefile import SourceFile
- return SourceFile(tests_root, path, manifest.url_base)
+ return SourceFile(tests_root, path, url_base)
- if source_files is None:
- return make_new()
+ def get(self, tests_root, manifest, path):
- if path not in source_files:
- source_files[path] = make_new()
+ if path not in self.source_files:
+ self.source_files[path] = self.make_new(tests_root, path, manifest.url_base)
- return source_files[path]
+ return self.source_files[path]
item_types = {}
@@ -27,7 +29,8 @@ class ManifestItemMeta(ABCMeta):
def __new__(cls, name, bases, attrs, **kwargs):
rv = ABCMeta.__new__(cls, name, bases, attrs, **kwargs)
- item_types[rv.item_type] = rv
+ if rv.item_type:
+ item_types[rv.item_type] = rv
return rv
@@ -37,8 +40,9 @@ class ManifestItem(object):
item_type = None
+ source_file_cache = SourceFileCache()
+
def __init__(self, source_file, manifest=None):
- self.manifest = manifest
self.source_file = source_file
@abstractproperty
@@ -84,8 +88,8 @@ class ManifestItem(object):
return [{}]
@classmethod
- def from_json(cls, manifest, tests_root, path, obj, source_files=None):
- source_file = get_source_file(source_files, tests_root, manifest, path)
+ def from_json(cls, manifest, tests_root, path, obj):
+ source_file = cls.source_file_cache.get(tests_root, manifest, path)
return cls(source_file,
manifest=manifest)
@@ -113,8 +117,8 @@ class URLManifestItem(ManifestItem):
return rv
@classmethod
- def from_json(cls, manifest, tests_root, path, obj, source_files=None):
- source_file = get_source_file(source_files, tests_root, manifest, path)
+ def from_json(cls, manifest, tests_root, path, obj):
+ source_file = cls.source_file_cache.get(tests_root, manifest, path)
url, extras = obj
return cls(source_file,
url,
@@ -145,8 +149,8 @@ class TestharnessTest(URLManifestItem):
return rv
@classmethod
- def from_json(cls, manifest, tests_root, path, obj, source_files=None):
- source_file = get_source_file(source_files, tests_root, manifest, path)
+ def from_json(cls, manifest, tests_root, path, obj):
+ source_file = cls.source_file_cache.get(tests_root, manifest, path)
url, extras = obj
return cls(source_file,
@@ -187,8 +191,8 @@ class RefTestNode(URLManifestItem):
return rv
@classmethod
- def from_json(cls, manifest, tests_root, path, obj, source_files=None):
- source_file = get_source_file(source_files, tests_root, manifest, path)
+ def from_json(cls, manifest, tests_root, path, obj):
+ source_file = cls.source_file_cache.get(tests_root, manifest, path)
url, references, extras = obj
return cls(source_file,
url,
@@ -248,8 +252,8 @@ class WebDriverSpecTest(URLManifestItem):
return rv
@classmethod
- def from_json(cls, manifest, tests_root, path, obj, source_files=None):
- source_file = get_source_file(source_files, tests_root, manifest, path)
+ def from_json(cls, manifest, tests_root, path, obj):
+ source_file = cls.source_file_cache.get(tests_root, manifest, path)
url, extras = obj
return cls(source_file,
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
index 9b2f0a18a56..127d45dbc66 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
@@ -1,13 +1,20 @@
import itertools
-import json
import os
from collections import defaultdict
-from six import iteritems, itervalues, viewkeys, string_types
+from six import iteritems, iterkeys, itervalues, string_types
-from .item import ManualTest, WebDriverSpecTest, Stub, RefTestNode, RefTest, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
+from . import vcs
+from .item import (ManualTest, WebDriverSpecTest, Stub, RefTestNode, RefTest,
+ TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest)
from .log import get_logger
from .utils import from_os_path, to_os_path
+try:
+ import ujson as json
+ JSON_LIBRARY = 'ujson'
+except ImportError:
+ import json
+ JSON_LIBRARY = 'json'
CURRENT_VERSION = 5
@@ -27,11 +34,178 @@ def iterfilter(filters, iter):
yield item
+item_classes = {"testharness": TestharnessTest,
+ "reftest": RefTest,
+ "reftest_node": RefTestNode,
+ "manual": ManualTest,
+ "stub": Stub,
+ "wdspec": WebDriverSpecTest,
+ "conformancechecker": ConformanceCheckerTest,
+ "visual": VisualTest,
+ "support": SupportFile}
+
+
+class TypeData(object):
+ def __init__(self, manifest, type_cls, meta_filters):
+ """Dict-like object containing the TestItems for each test type.
+
+ Loading an actual Item class for each test is unnecessarily
+ slow, so this class allows lazy-loading of the test
+ items. When the manifest is loaded we store the raw json
+ corresponding to the test type, and only create an Item
+ subclass when the test is accessed. In order to remain
+ API-compatible with consumers that depend on getting an Item
+ from iteration, we do egerly load all items when iterating
+ over the class."""
+ self.manifest = manifest
+ self.type_cls = type_cls
+ self.json_data = {}
+ self.tests_root = None
+ self.data = {}
+ self.meta_filters = meta_filters or []
+
+ def __getitem__(self, key):
+ if key not in self.data:
+ self.load(key)
+ return self.data[key]
+
+ def __bool__(self):
+ return bool(self.data)
+
+ def __len__(self):
+ rv = len(self.data)
+ if self.json_data is not None:
+ rv += len(self.json_data)
+ return rv
+
+ def __delitem__(self, key):
+ if key in self.data:
+ del self.data[key]
+ elif self.json_data is not None:
+ del self.json_data[from_os_path(key)]
+ else:
+ raise KeyError
+
+ def __setitem__(self, key, value):
+ self.data[key] = value
+
+ def __contains__(self, key):
+ self.load_all()
+ return key in self.data
+
+ def __iter__(self):
+ self.load_all()
+ return self.data.__iter__()
+
+ def pop(self, key, default=None):
+ try:
+ value = self[key]
+ except ValueError:
+ value = default
+ else:
+ del self.data[key]
+ return value
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except ValueError:
+ return default
+
+ def itervalues(self):
+ self.load_all()
+ return itervalues(self.data)
+
+ def iteritems(self):
+ self.load_all()
+ return iteritems(self.data)
+
+ def values(self):
+ return self.itervalues()
+
+ def items(self):
+ return self.iteritems()
+
+ def load(self, key):
+ """Load a specific Item given a path"""
+ if self.json_data is not None:
+ data = set()
+ path = from_os_path(key)
+ for test in iterfilter(self.meta_filters, self.json_data.get(path, [])):
+ manifest_item = self.type_cls.from_json(self.manifest,
+ self.tests_root,
+ path,
+ test)
+ data.add(manifest_item)
+ try:
+ del self.json_data[path]
+ except KeyError:
+ pass
+ self.data[key] = data
+ else:
+ raise ValueError
+
+ def load_all(self):
+ """Load all test items in this class"""
+ if self.json_data is not None:
+ for path, value in iteritems(self.json_data):
+ key = to_os_path(path)
+ if key in self.data:
+ continue
+ data = set()
+ for test in iterfilter(self.meta_filters, self.json_data.get(path, [])):
+ manifest_item = self.type_cls.from_json(self.manifest,
+ self.tests_root,
+ path,
+ test)
+ data.add(manifest_item)
+ self.data[key] = data
+ self.json_data = None
+
+ def set_json(self, tests_root, data):
+ if not isinstance(data, dict):
+ raise ValueError("Got a %s expected a dict" % (type(data)))
+ self.tests_root = tests_root
+ self.json_data = data
+
+ def paths(self):
+ """Get a list of all paths containing items of this type,
+ without actually constructing all the items"""
+ rv = set(iterkeys(self.data))
+ if self.json_data:
+ rv |= set(to_os_path(item) for item in iterkeys(self.json_data))
+ return rv
+
+
+class ManifestData(dict):
+ def __init__(self, manifest, meta_filters=None):
+ """Dictionary subclass containing a TypeData instance for each test type,
+ keyed by type name"""
+ self.initialized = False
+ for key, value in iteritems(item_classes):
+ self[key] = TypeData(manifest, value, meta_filters=meta_filters)
+ self.initialized = True
+ self.json_obj = None
+
+ def __setitem__(self, key, value):
+ if self.initialized:
+ raise AttributeError
+ dict.__setitem__(self, key, value)
+
+ def paths(self):
+ """Get a list of all paths containing test items
+ without actually constructing all the items"""
+ rv = set()
+ for item_data in itervalues(self):
+ rv |= set(item_data.paths())
+ return rv
+
+
class Manifest(object):
- def __init__(self, url_base="/"):
+ def __init__(self, url_base="/", meta_filters=None):
assert url_base is not None
self._path_hash = {}
- self._data = defaultdict(dict)
+ self._data = ManifestData(self, meta_filters)
self._reftest_nodes_by_url = None
self.url_base = url_base
@@ -42,7 +216,8 @@ class Manifest(object):
if not types:
types = sorted(self._data.keys())
for item_type in types:
- for path, tests in sorted(iteritems(self._data[item_type])):
+ for path in sorted(self._data[item_type]):
+ tests = self._data[item_type][path]
yield item_type, path, tests
def iterpath(self, path):
@@ -74,61 +249,88 @@ class Manifest(object):
return self.reftest_nodes_by_url.get(url)
def update(self, tree):
- new_data = defaultdict(dict)
- new_hashes = {}
+ """Update the manifest given an iterable of items that make up the updated manifest.
+ The iterable must either generate tuples of the form (SourceFile, True) for paths
+ that are to be updated, or (path, False) for items that are not to be updated. This
+ unusual API is designed as an optimistaion meaning that SourceFile items need not be
+ constructed in the case we are not updating a path, but the absence of an item from
+ the iterator may be used to remove defunct entries from the manifest."""
reftest_nodes = []
- old_files = defaultdict(set, {k: set(viewkeys(v)) for k, v in iteritems(self._data)})
+ seen_files = set()
changed = False
reftest_changes = False
- for source_file in tree:
- rel_path = source_file.rel_path
- file_hash = source_file.hash
+ prev_files = self._data.paths()
- is_new = rel_path not in self._path_hash
- hash_changed = False
+ reftest_types = ("reftest", "reftest_node")
- if not is_new:
- old_hash, old_type = self._path_hash[rel_path]
- old_files[old_type].remove(rel_path)
- if old_hash != file_hash:
- new_type, manifest_items = source_file.manifest_items()
- hash_changed = True
- else:
- new_type, manifest_items = old_type, self._data[old_type][rel_path]
- if old_type in ("reftest", "reftest_node") and new_type != old_type:
- reftest_changes = True
+ for source_file, update in tree:
+ if not update:
+ rel_path = source_file
+ seen_files.add(rel_path)
else:
- new_type, manifest_items = source_file.manifest_items()
-
- if new_type in ("reftest", "reftest_node"):
- reftest_nodes.extend(manifest_items)
- if is_new or hash_changed:
- reftest_changes = True
- elif new_type:
- new_data[new_type][rel_path] = set(manifest_items)
+ rel_path = source_file.rel_path
+ seen_files.add(rel_path)
+
+ file_hash = source_file.hash
+
+ is_new = rel_path not in self._path_hash
+ hash_changed = False
+
+ if not is_new:
+ old_hash, old_type = self._path_hash[rel_path]
+ if old_hash != file_hash:
+ new_type, manifest_items = source_file.manifest_items()
+ hash_changed = True
+ if new_type != old_type:
+ try:
+ del self._data[old_type][rel_path]
+ except KeyError:
+ pass
+ else:
+ new_type, manifest_items = old_type, self._data[old_type][rel_path]
+ if old_type in reftest_types and new_type != old_type:
+ reftest_changes = True
+ else:
+ new_type, manifest_items = source_file.manifest_items()
- new_hashes[rel_path] = (file_hash, new_type)
+ if new_type in ("reftest", "reftest_node"):
+ reftest_nodes.extend(manifest_items)
+ if is_new or hash_changed:
+ reftest_changes = True
+ elif new_type:
+ self._data[new_type][rel_path] = set(manifest_items)
- if is_new or hash_changed:
- changed = True
+ self._path_hash[rel_path] = (file_hash, new_type)
- if reftest_changes or old_files["reftest"] or old_files["reftest_node"]:
- reftests, reftest_nodes, changed_hashes = self._compute_reftests(reftest_nodes)
- new_data["reftest"] = reftests
- new_data["reftest_node"] = reftest_nodes
- new_hashes.update(changed_hashes)
- else:
- new_data["reftest"] = self._data["reftest"]
- new_data["reftest_node"] = self._data["reftest_node"]
+ if is_new or hash_changed:
+ changed = True
- if any(itervalues(old_files)):
+ deleted = prev_files - seen_files
+ if deleted:
changed = True
+ for rel_path in deleted:
+ if rel_path in self._path_hash:
+ _, old_type = self._path_hash[rel_path]
+ if old_type in reftest_types:
+ reftest_changes = True
+ del self._path_hash[rel_path]
+ try:
+ del self._data[old_type][rel_path]
+ except KeyError:
+ pass
+ else:
+ for test_data in itervalues(self._data):
+ if rel_path in test_data:
+ del test_data[rel_path]
- self._data = new_data
- self._path_hash = new_hashes
+ if reftest_changes:
+ reftests, reftest_nodes, changed_hashes = self._compute_reftests(reftest_nodes)
+ self._data["reftest"].data = reftests
+ self._data["reftest_node"].data = reftest_nodes
+ self._path_hash.update(changed_hashes)
return changed
@@ -168,7 +370,7 @@ class Manifest(object):
[t for t in sorted(test.to_json() for test in tests)]
for path, tests in iteritems(type_paths)
}
- for test_type, type_paths in iteritems(self._data)
+ for test_type, type_paths in iteritems(self._data) if type_paths
}
rv = {"url_base": self.url_base,
"paths": {from_os_path(k): v for k, v in iteritems(self._path_hash)},
@@ -182,26 +384,12 @@ class Manifest(object):
if version != CURRENT_VERSION:
raise ManifestVersionMismatch
- self = cls(url_base=obj.get("url_base", "/"))
+ self = cls(url_base=obj.get("url_base", "/"), meta_filters=meta_filters)
if not hasattr(obj, "items") and hasattr(obj, "paths"):
raise ManifestError
self._path_hash = {to_os_path(k): v for k, v in iteritems(obj["paths"])}
- item_classes = {"testharness": TestharnessTest,
- "reftest": RefTest,
- "reftest_node": RefTestNode,
- "manual": ManualTest,
- "stub": Stub,
- "wdspec": WebDriverSpecTest,
- "conformancechecker": ConformanceCheckerTest,
- "visual": VisualTest,
- "support": SupportFile}
-
- meta_filters = meta_filters or []
-
- source_files = {}
-
for test_type, type_paths in iteritems(obj["items"]):
if test_type not in item_classes:
raise ManifestError
@@ -209,18 +397,7 @@ class Manifest(object):
if types and test_type not in types:
continue
- test_cls = item_classes[test_type]
- tests = defaultdict(set)
- for path, manifest_tests in iteritems(type_paths):
- path = to_os_path(path)
- for test in iterfilter(meta_filters, manifest_tests):
- manifest_item = test_cls.from_json(self,
- tests_root,
- path,
- test,
- source_files=source_files)
- tests[path].add(manifest_item)
- self._data[test_type] = tests
+ self._data[test_type].set_json(tests_root, type_paths)
return self
@@ -228,7 +405,20 @@ class Manifest(object):
def load(tests_root, manifest, types=None, meta_filters=None):
logger = get_logger()
+ logger.warning("Prefer load_and_update instead")
+ return _load(logger, tests_root, manifest, types, meta_filters)
+
+
+__load_cache = {}
+
+
+def _load(logger, tests_root, manifest, types=None, meta_filters=None):
# "manifest" is a path or file-like object.
+ manifest_path = (manifest if isinstance(manifest, string_types)
+ else manifest.name)
+ if manifest_path in __load_cache:
+ return __load_cache[manifest_path]
+
if isinstance(manifest, string_types):
if os.path.exists(manifest):
logger.debug("Opening manifest at %s" % manifest)
@@ -236,15 +426,65 @@ def load(tests_root, manifest, types=None, meta_filters=None):
logger.debug("Creating new manifest at %s" % manifest)
try:
with open(manifest) as f:
- rv = Manifest.from_json(tests_root, json.load(f), types=types, meta_filters=meta_filters)
+ rv = Manifest.from_json(tests_root,
+ json.load(f),
+ types=types,
+ meta_filters=meta_filters)
except IOError:
return None
except ValueError:
logger.warning("%r may be corrupted", manifest)
return None
- return rv
+ else:
+ rv = Manifest.from_json(tests_root,
+ json.load(manifest),
+ types=types,
+ meta_filters=meta_filters)
+
+ __load_cache[manifest_path] = rv
+ return rv
+
+
+def load_and_update(tests_root,
+ manifest_path,
+ url_base,
+ update=True,
+ rebuild=False,
+ metadata_path=None,
+ cache_root=None,
+ working_copy=False,
+ types=None,
+ meta_filters=None,
+ write_manifest=True):
+ logger = get_logger()
- return Manifest.from_json(tests_root, json.load(manifest), types=types, meta_filters=meta_filters)
+ manifest = None
+ if not rebuild:
+ try:
+ manifest = _load(logger,
+ tests_root,
+ manifest_path,
+ types=types,
+ meta_filters=meta_filters)
+ except ManifestVersionMismatch:
+ logger.info("Manifest version changed, rebuilding")
+
+ if manifest is not None and manifest.url_base != url_base:
+ logger.info("Manifest url base did not match, rebuilding")
+
+ if manifest is None:
+ manifest = Manifest(url_base, meta_filters=meta_filters)
+ update = True
+
+ if update:
+ tree = vcs.get_tree(tests_root, manifest, manifest_path, cache_root,
+ working_copy, rebuild)
+ changed = manifest.update(tree)
+ if write_manifest and changed:
+ write(manifest, manifest_path)
+ tree.dump_caches()
+
+ return manifest
def write(manifest, manifest_path):
@@ -252,5 +492,12 @@ def write(manifest, manifest_path):
if not os.path.exists(dir_name):
os.makedirs(dir_name)
with open(manifest_path, "wb") as f:
- json.dump(manifest.to_json(), f, sort_keys=True, indent=1, separators=(',', ': '))
+ if JSON_LIBRARY == 'ujson':
+ # ujson does not support the separators flag.
+ json.dump(manifest.to_json(), f, sort_keys=True, indent=1)
+ else:
+ # Use ',' instead of the default ', ' separator to prevent trailing
+ # spaces: https://docs.python.org/2/library/json.html#json.dump
+ json.dump(manifest.to_json(), f,
+ sort_keys=True, indent=1, separators=(',', ': '))
f.write("\n")
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py
index 1f08088eb46..d2e5df85526 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/sourcefile.py
@@ -164,6 +164,8 @@ class SourceFile(object):
:param contents: Byte array of the contents of the file or ``None``.
"""
+ assert not os.path.isabs(rel_path), rel_path
+
self.tests_root = tests_root
if os.name == "nt":
# do slash normalization on Windows
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/update.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/update.py
index 9923cc5fe62..217d767cece 100755
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/update.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/update.py
@@ -13,14 +13,18 @@ wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
logger = get_logger()
-def update(tests_root, manifest, working_copy=False):
+
+def update(tests_root,
+ manifest,
+ manifest_path=None,
+ working_copy=False,
+ cache_root=None,
+ rebuild=False):
+ logger.warning("Deprecated; use manifest.load_and_update instead")
logger.info("Updating manifest")
- tree = None
- if not working_copy:
- tree = vcs.Git.for_path(tests_root, manifest.url_base)
- if tree is None:
- tree = vcs.FileSystem(tests_root, manifest.url_base)
+ tree = vcs.get_tree(tests_root, manifest, manifest_path, cache_root,
+ working_copy, rebuild)
return manifest.update(tree)
@@ -29,26 +33,16 @@ def update_from_cli(**kwargs):
path = kwargs["path"]
assert tests_root is not None
- m = None
-
if kwargs["download"]:
download_from_github(path, tests_root)
- if not kwargs.get("rebuild", False):
- try:
- m = manifest.load(tests_root, path)
- except manifest.ManifestVersionMismatch:
- logger.info("Manifest version changed, rebuilding")
- m = None
-
- if m is None:
- m = manifest.Manifest(kwargs["url_base"])
-
- changed = update(tests_root,
- m,
- working_copy=kwargs["work"])
- if changed:
- manifest.write(m, path)
+ manifest.load_and_update(tests_root,
+ path,
+ kwargs["url_base"],
+ update=True,
+ rebuild=kwargs["rebuild"],
+ cache_root=kwargs["cache_root"],
+ working_copy=kwargs["work"])
def abs_path(path):
@@ -73,6 +67,9 @@ def create_parser():
parser.add_argument(
"--no-download", dest="download", action="store_false", default=True,
help="Never attempt to download the manifest.")
+ parser.add_argument(
+ "--cache-root", action="store", default=os.path.join(wpt_root, ".wptcache"),
+ help="Path in which to store any caches (default <tests_root>/.wptcache/")
return parser
@@ -87,10 +84,9 @@ def find_top_repo():
return rv
-def run(**kwargs):
+def run(*args, **kwargs):
if kwargs["path"] is None:
kwargs["path"] = os.path.join(kwargs["tests_root"], "MANIFEST.json")
-
update_from_cli(**kwargs)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/utils.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/utils.py
index d9be750e416..9da79f6deb4 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/utils.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/utils.py
@@ -4,7 +4,7 @@ import os
from six import BytesIO
def rel_path_to_url(rel_path, url_base="/"):
- assert not os.path.isabs(rel_path)
+ assert not os.path.isabs(rel_path), rel_path
if url_base[0] != "/":
url_base = "/" + url_base
if url_base[-1] != "/":
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
index 675eb01714f..69eb9ab8ecb 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
@@ -1,15 +1,46 @@
+import json
import os
-import subprocess
import platform
+import stat
+import subprocess
+from collections import deque
from .sourcefile import SourceFile
+def get_tree(tests_root, manifest, manifest_path, cache_root,
+ working_copy=False, rebuild=False):
+ tree = None
+ if cache_root is None:
+ cache_root = os.path.join(tests_root, ".wptcache")
+ if not os.path.exists(cache_root):
+ try:
+ os.makedirs(cache_root)
+ except IOError:
+ cache_root = None
+
+ if not working_copy:
+ tree = Git.for_path(tests_root,
+ manifest.url_base,
+ manifest_path=manifest_path,
+ cache_path=cache_root,
+ rebuild=rebuild)
+ if tree is None:
+ tree = FileSystem(tests_root,
+ manifest.url_base,
+ manifest_path=manifest_path,
+ cache_path=cache_root,
+ rebuild=rebuild)
+ return tree
+
+
class Git(object):
- def __init__(self, repo_root, url_base):
- self.root = os.path.abspath(repo_root)
+ def __init__(self, repo_root, url_base, cache_path, manifest_path=None,
+ rebuild=False):
+ self.root = repo_root
self.git = Git.get_func(repo_root)
self.url_base = url_base
+ # rebuild is a noop for now since we don't cache anything
@staticmethod
def get_func(repo_path):
@@ -26,11 +57,12 @@ class Git(object):
return git
@classmethod
- def for_path(cls, path, url_base):
+ def for_path(cls, path, url_base, cache_path, manifest_path=None, rebuild=False):
git = Git.get_func(path)
try:
- return cls(git("rev-parse", "--show-toplevel").rstrip(), url_base)
- except subprocess.CalledProcessError:
+ return cls(git("rev-parse", "--show-toplevel").rstrip(), url_base, cache_path,
+ manifest_path=manifest_path, rebuild=rebuild)
+ except (subprocess.CalledProcessError, OSError):
return None
def _local_changes(self):
@@ -74,27 +106,194 @@ class Git(object):
rel_path,
self.url_base,
hash,
- contents=contents)
+ contents=contents), True
+
+ def dump_caches(self):
+ pass
class FileSystem(object):
- def __init__(self, root, url_base):
- self.root = root
- self.url_base = url_base
+ def __init__(self, root, url_base, cache_path, manifest_path=None, rebuild=False):
from gitignore import gitignore
- self.path_filter = gitignore.PathFilter(self.root, extras=[".git/"])
+ self.root = os.path.abspath(root)
+ self.url_base = url_base
+ self.ignore_cache = None
+ self.mtime_cache = None
+ if cache_path is not None:
+ if manifest_path is not None:
+ self.mtime_cache = MtimeCache(cache_path, root, manifest_path, rebuild)
+ if gitignore.has_ignore(root):
+ self.ignore_cache = GitIgnoreCache(cache_path, root, rebuild)
+ self.path_filter = gitignore.PathFilter(self.root,
+ extras=[".git/"],
+ cache=self.ignore_cache)
def __iter__(self):
- paths = self.get_paths()
- for path in paths:
- yield SourceFile(self.root, path, self.url_base)
-
- def get_paths(self):
- for dirpath, dirnames, filenames in os.walk(self.root):
- for filename in filenames:
- path = os.path.relpath(os.path.join(dirpath, filename), self.root)
- if self.path_filter(path):
- yield path
-
- dirnames[:] = [item for item in dirnames if self.path_filter(
- os.path.relpath(os.path.join(dirpath, item), self.root) + "/")]
+ mtime_cache = self.mtime_cache
+ for dirpath, dirnames, filenames in self.path_filter(walk(self.root)):
+ for filename, path_stat in filenames:
+ path = os.path.join(dirpath, filename)
+ if mtime_cache is None or mtime_cache.updated(path, path_stat):
+ yield SourceFile(self.root, path, self.url_base), True
+ else:
+ yield path, False
+
+ def dump_caches(self):
+ for cache in [self.mtime_cache, self.ignore_cache]:
+ if cache is not None:
+ cache.dump()
+
+
+class CacheFile(object):
+ file_name = None
+
+ def __init__(self, cache_root, tests_root, rebuild=False):
+ self.tests_root = tests_root
+ if not os.path.exists(cache_root):
+ os.makedirs(cache_root)
+ self.path = os.path.join(cache_root, self.file_name)
+ self.modified = False
+ self.data = self.load(rebuild)
+
+ def dump(self):
+ if not self.modified:
+ return
+ with open(self.path, 'w') as f:
+ json.dump(self.data, f, indent=1)
+
+ def load(self, rebuild=False):
+ data = {}
+ try:
+ if not rebuild:
+ with open(self.path, 'r') as f:
+ data = json.load(f)
+ data = self.check_valid(data)
+ except IOError:
+ pass
+ return data
+
+ def check_valid(self, data):
+ """Check if the cached data is valid and return an updated copy of the
+ cache containing only data that can be used."""
+ return data
+
+
+class MtimeCache(CacheFile):
+ file_name = "mtime.json"
+
+ def __init__(self, cache_root, tests_root, manifest_path, rebuild=False):
+ self.manifest_path = manifest_path
+ super(MtimeCache, self).__init__(cache_root, tests_root, rebuild=False)
+
+ def updated(self, rel_path, stat):
+ """Return a boolean indicating whether the file changed since the cache was last updated.
+
+ This implicitly updates the cache with the new mtime data."""
+ mtime = stat.st_mtime
+ if mtime != self.data.get(rel_path):
+ self.modified = True
+ self.data[rel_path] = mtime
+ return True
+ return False
+
+ def check_valid(self, data):
+ if data.get("/tests_root") != self.tests_root:
+ self.modified = True
+ else:
+ if self.manifest_path is not None and os.path.exists(self.manifest_path):
+ mtime = os.path.getmtime(self.manifest_path)
+ if data.get("/manifest_path") != [self.manifest_path, mtime]:
+ self.modified = True
+ else:
+ self.modified = True
+ if self.modified:
+ data = {}
+ data["/tests_root"] = self.tests_root
+ return data
+
+ def dump(self):
+ if self.manifest_path is None:
+ raise ValueError
+ if not os.path.exists(self.manifest_path):
+ return
+ mtime = os.path.getmtime(self.manifest_path)
+ self.data["/manifest_path"] = [self.manifest_path, mtime]
+ self.data["/tests_root"] = self.tests_root
+ super(MtimeCache, self).dump()
+
+
+class GitIgnoreCache(CacheFile):
+ file_name = "gitignore.json"
+
+ def check_valid(self, data):
+ ignore_path = os.path.join(self.tests_root, ".gitignore")
+ mtime = os.path.getmtime(ignore_path)
+ if data.get("/gitignore_file") != [ignore_path, mtime]:
+ self.modified = True
+ data = {}
+ data["/gitignore_file"] = [ignore_path, mtime]
+ return data
+
+ def __contains__(self, key):
+ return key in self.data
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+ def __setitem__(self, key, value):
+ if self.data.get(key) != value:
+ self.modified = True
+ self.data[key] = value
+
+
+def walk(root):
+ """Re-implementation of os.walk. Returns an iterator over
+ (dirpath, dirnames, filenames), with some semantic differences
+ to os.walk.
+
+ This has a similar interface to os.walk, with the important difference
+ that instead of lists of filenames and directory names, it yields
+ lists of tuples of the form [(name, stat)] where stat is the result of
+ os.stat for the file. That allows reusing the same stat data in the
+ caller. It also always returns the dirpath relative to the root, with
+ the root iself being returned as the empty string.
+
+ Unlike os.walk the implementation is not recursive."""
+
+ listdir = os.listdir
+ get_stat = os.stat
+ listdir = os.listdir
+ join = os.path.join
+ is_dir = stat.S_ISDIR
+ is_link = stat.S_ISLNK
+ relpath = os.path.relpath
+
+ root = os.path.abspath(root)
+ stack = deque([(root, "")])
+
+ while stack:
+ dir_path, rel_path = stack.popleft()
+ try:
+ # Note that listdir and error are globals in this module due
+ # to earlier import-*.
+ names = listdir(dir_path)
+ except OSError:
+ continue
+
+ dirs, non_dirs = [], []
+ for name in names:
+ path = join(dir_path, name)
+ try:
+ path_stat = get_stat(path)
+ except OSError:
+ continue
+ if is_dir(path_stat.st_mode):
+ dirs.append((name, path_stat))
+ else:
+ non_dirs.append((name, path_stat))
+
+ yield rel_path, dirs, non_dirs
+ for name, path_stat in dirs:
+ new_path = join(dir_path, name)
+ if not is_link(path_stat.st_mode):
+ stack.append((new_path, relpath(new_path, root)))
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
index c4afc691d34..4eee732443b 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
@@ -757,7 +757,9 @@ class ConfigBuilder(config.ConfigBuilder):
"openssl": {
"openssl_binary": "openssl",
"base_path": "_certs",
+ "password": "web-platform-tests",
"force_regenerate": False,
+ "duration": 30,
"base_conf_path": None
},
"pregenerated": {
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/__init__.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/__init__.py
new file mode 100644
index 00000000000..217bfc65272
--- /dev/null
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/__init__.py
@@ -0,0 +1,36 @@
+# flake8: noqa
+
+from client import (
+ Cookies,
+ Element,
+ Find,
+ Frame,
+ Session,
+ Timeouts,
+ Window)
+from error import (
+ ElementNotSelectableException,
+ ElementNotVisibleException,
+ InvalidArgumentException,
+ InvalidCookieDomainException,
+ InvalidElementCoordinatesException,
+ InvalidElementStateException,
+ InvalidSelectorException,
+ InvalidSessionIdException,
+ JavascriptErrorException,
+ MoveTargetOutOfBoundsException,
+ NoSuchAlertException,
+ NoSuchElementException,
+ NoSuchFrameException,
+ NoSuchWindowException,
+ ScriptTimeoutException,
+ SessionNotCreatedException,
+ StaleElementReferenceException,
+ TimeoutException,
+ UnableToSetCookieException,
+ UnexpectedAlertOpenException,
+ UnknownCommandException,
+ UnknownErrorException,
+ UnknownMethodException,
+ UnsupportedOperationException,
+ WebDriverException)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py
new file mode 100644
index 00000000000..29be09bb3c9
--- /dev/null
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py
@@ -0,0 +1,741 @@
+import urlparse
+
+import error
+import protocol
+import transport
+
+from six import string_types
+
+
+def command(func):
+ def inner(self, *args, **kwargs):
+ if hasattr(self, "session"):
+ session = self.session
+ else:
+ session = self
+
+ if session.session_id is None:
+ session.start()
+
+ return func(self, *args, **kwargs)
+
+ inner.__name__ = func.__name__
+ inner.__doc__ = func.__doc__
+
+ return inner
+
+
+class Timeouts(object):
+
+ def __init__(self, session):
+ self.session = session
+
+ def _get(self, key=None):
+ timeouts = self.session.send_session_command("GET", "timeouts")
+ if key is not None:
+ return timeouts[key]
+ return timeouts
+
+ def _set(self, key, secs):
+ body = {key: secs * 1000}
+ self.session.send_session_command("POST", "timeouts", body)
+ return None
+
+ @property
+ def script(self):
+ return self._get("script")
+
+ @script.setter
+ def script(self, secs):
+ return self._set("script", secs)
+
+ @property
+ def page_load(self):
+ return self._get("pageLoad")
+
+ @page_load.setter
+ def page_load(self, secs):
+ return self._set("pageLoad", secs)
+
+ @property
+ def implicit(self):
+ return self._get("implicit")
+
+ @implicit.setter
+ def implicit(self, secs):
+ return self._set("implicit", secs)
+
+ def __str__(self):
+ name = "%s.%s" % (self.__module__, self.__class__.__name__)
+ return "<%s script=%d, load=%d, implicit=%d>" % \
+ (name, self.script, self.page_load, self.implicit)
+
+
+class ActionSequence(object):
+ """API for creating and performing action sequences.
+
+ Each action method adds one or more actions to a queue. When perform()
+ is called, the queued actions fire in order.
+
+ May be chained together as in::
+
+ ActionSequence(session, "key", id) \
+ .key_down("a") \
+ .key_up("a") \
+ .perform()
+ """
+ def __init__(self, session, action_type, input_id, pointer_params=None):
+ """Represents a sequence of actions of one type for one input source.
+
+ :param session: WebDriver session.
+ :param action_type: Action type; may be "none", "key", or "pointer".
+ :param input_id: ID of input source.
+ :param pointer_params: Optional dictionary of pointer parameters.
+ """
+ self.session = session
+ self._id = input_id
+ self._type = action_type
+ self._actions = []
+ self._pointer_params = pointer_params
+
+ @property
+ def dict(self):
+ d = {
+ "type": self._type,
+ "id": self._id,
+ "actions": self._actions,
+ }
+ if self._pointer_params is not None:
+ d["parameters"] = self._pointer_params
+ return d
+
+ @command
+ def perform(self):
+ """Perform all queued actions."""
+ self.session.actions.perform([self.dict])
+
+ def _key_action(self, subtype, value):
+ self._actions.append({"type": subtype, "value": value})
+
+ def _pointer_action(self, subtype, button):
+ self._actions.append({"type": subtype, "button": button})
+
+ def pause(self, duration):
+ self._actions.append({"type": "pause", "duration": duration})
+ return self
+
+ def pointer_move(self, x, y, duration=None, origin=None):
+ """Queue a pointerMove action.
+
+ :param x: Destination x-axis coordinate of pointer in CSS pixels.
+ :param y: Destination y-axis coordinate of pointer in CSS pixels.
+ :param duration: Number of milliseconds over which to distribute the
+ move. If None, remote end defaults to 0.
+ :param origin: Origin of coordinates, either "viewport", "pointer" or
+ an Element. If None, remote end defaults to "viewport".
+ """
+ action = {
+ "type": "pointerMove",
+ "x": x,
+ "y": y
+ }
+ if duration is not None:
+ action["duration"] = duration
+ if origin is not None:
+ action["origin"] = origin
+ self._actions.append(action)
+ return self
+
+ def pointer_up(self, button=0):
+ """Queue a pointerUp action for `button`.
+
+ :param button: Pointer button to perform action with.
+ Default: 0, which represents main device button.
+ """
+ self._pointer_action("pointerUp", button)
+ return self
+
+ def pointer_down(self, button=0):
+ """Queue a pointerDown action for `button`.
+
+ :param button: Pointer button to perform action with.
+ Default: 0, which represents main device button.
+ """
+ self._pointer_action("pointerDown", button)
+ return self
+
+ def click(self, element=None, button=0):
+ """Queue a click with the specified button.
+
+ If an element is given, move the pointer to that element first,
+ otherwise click current pointer coordinates.
+
+ :param element: Optional element to click.
+ :param button: Integer representing pointer button to perform action
+ with. Default: 0, which represents main device button.
+ """
+ if element:
+ self.pointer_move(0, 0, origin=element)
+ return self.pointer_down(button).pointer_up(button)
+
+ def key_up(self, value):
+ """Queue a keyUp action for `value`.
+
+ :param value: Character to perform key action with.
+ """
+ self._key_action("keyUp", value)
+ return self
+
+ def key_down(self, value):
+ """Queue a keyDown action for `value`.
+
+ :param value: Character to perform key action with.
+ """
+ self._key_action("keyDown", value)
+ return self
+
+ def send_keys(self, keys):
+ """Queue a keyDown and keyUp action for each character in `keys`.
+
+ :param keys: String of keys to perform key actions with.
+ """
+ for c in keys:
+ self.key_down(c)
+ self.key_up(c)
+ return self
+
+
+class Actions(object):
+ def __init__(self, session):
+ self.session = session
+
+ @command
+ def perform(self, actions=None):
+ """Performs actions by tick from each action sequence in `actions`.
+
+ :param actions: List of input source action sequences. A single action
+ sequence may be created with the help of
+ ``ActionSequence.dict``.
+ """
+ body = {"actions": [] if actions is None else actions}
+ return self.session.send_session_command("POST", "actions", body)
+
+ @command
+ def release(self):
+ return self.session.send_session_command("DELETE", "actions")
+
+ def sequence(self, *args, **kwargs):
+ """Return an empty ActionSequence of the designated type.
+
+ See ActionSequence for parameter list.
+ """
+ return ActionSequence(self.session, *args, **kwargs)
+
+
+class Window(object):
+ identifier = "window-fcc6-11e5-b4f8-330a88ab9d7f"
+
+ def __init__(self, session):
+ self.session = session
+
+ @property
+ @command
+ def rect(self):
+ return self.session.send_session_command("GET", "window/rect")
+
+ @property
+ @command
+ def size(self):
+ """Gets the window size as a tuple of `(width, height)`."""
+ rect = self.rect
+ return (rect["width"], rect["height"])
+
+ @size.setter
+ @command
+ def size(self, new_size):
+ """Set window size by passing a tuple of `(width, height)`."""
+ width, height = new_size
+ body = {"width": width, "height": height}
+ self.session.send_session_command("POST", "window/rect", body)
+
+ @property
+ @command
+ def position(self):
+ """Gets the window position as a tuple of `(x, y)`."""
+ rect = self.rect
+ return (rect["x"], rect["y"])
+
+ @position.setter
+ @command
+ def position(self, new_position):
+ """Set window position by passing a tuple of `(x, y)`."""
+ x, y = new_position
+ body = {"x": x, "y": y}
+ self.session.send_session_command("POST", "window/rect", body)
+
+ @command
+ def maximize(self):
+ return self.session.send_session_command("POST", "window/maximize")
+
+ @command
+ def minimize(self):
+ return self.session.send_session_command("POST", "window/minimize")
+
+ @command
+ def fullscreen(self):
+ return self.session.send_session_command("POST", "window/fullscreen")
+
+ @classmethod
+ def from_json(cls, json, session):
+ uuid = json[Window.identifier]
+ return cls(uuid, session)
+
+
+class Frame(object):
+ identifier = "frame-075b-4da1-b6ba-e579c2d3230a"
+
+ def __init__(self, session):
+ self.session = session
+
+ @classmethod
+ def from_json(cls, json, session):
+ uuid = json[Frame.identifier]
+ return cls(uuid, session)
+
+
+class Find(object):
+ def __init__(self, session):
+ self.session = session
+
+ @command
+ def css(self, selector, all=True):
+ return self._find_element("css selector", selector, all)
+
+ def _find_element(self, strategy, selector, all):
+ route = "elements" if all else "element"
+ body = {"using": strategy,
+ "value": selector}
+ return self.session.send_session_command("POST", route, body)
+
+
+class Cookies(object):
+ def __init__(self, session):
+ self.session = session
+
+ def __getitem__(self, name):
+ self.session.send_session_command("GET", "cookie/%s" % name, {})
+
+ def __setitem__(self, name, value):
+ cookie = {"name": name,
+ "value": None}
+
+ if isinstance(name, string_types):
+ cookie["value"] = value
+ elif hasattr(value, "value"):
+ cookie["value"] = value.value
+ self.session.send_session_command("POST", "cookie/%s" % name, {})
+
+
+class UserPrompt(object):
+ def __init__(self, session):
+ self.session = session
+
+ @command
+ def dismiss(self):
+ self.session.send_session_command("POST", "alert/dismiss")
+
+ @command
+ def accept(self):
+ self.session.send_session_command("POST", "alert/accept")
+
+ @property
+ @command
+ def text(self):
+ return self.session.send_session_command("GET", "alert/text")
+
+ @text.setter
+ @command
+ def text(self, value):
+ body = {"value": list(value)}
+ self.session.send_session_command("POST", "alert/text", body=body)
+
+
+class Session(object):
+ def __init__(self,
+ host,
+ port,
+ url_prefix="/",
+ capabilities=None,
+ timeout=None,
+ extension=None):
+ self.transport = transport.HTTPWireProtocol(
+ host, port, url_prefix, timeout=timeout)
+ self.requested_capabilities = capabilities
+ self.capabilities = None
+ self.session_id = None
+ self.timeouts = None
+ self.window = None
+ self.find = None
+ self.extension = None
+ self.extension_cls = extension
+
+ self.timeouts = Timeouts(self)
+ self.window = Window(self)
+ self.find = Find(self)
+ self.alert = UserPrompt(self)
+ self.actions = Actions(self)
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__, self.session_id or "(disconnected)")
+
+ def __eq__(self, other):
+ return (self.session_id is not None and isinstance(other, Session) and
+ self.session_id == other.session_id)
+
+ def __enter__(self):
+ self.start()
+ return self
+
+ def __exit__(self, *args, **kwargs):
+ self.end()
+
+ def __del__(self):
+ self.end()
+
+ def start(self):
+ """Start a new WebDriver session.
+
+ :return: Dictionary with `capabilities` and `sessionId`.
+
+ :raises error.WebDriverException: If the remote end returns
+ an error.
+ """
+ if self.session_id is not None:
+ return
+
+ body = {}
+
+ if self.requested_capabilities is not None:
+ body["capabilities"] = self.requested_capabilities
+
+ value = self.send_command("POST", "session", body=body)
+ self.session_id = value["sessionId"]
+ self.capabilities = value["capabilities"]
+
+ if self.extension_cls:
+ self.extension = self.extension_cls(self)
+
+ return value
+
+ def end(self):
+ """Try to close the active session."""
+ if self.session_id is None:
+ return
+
+ try:
+ self.send_command("DELETE", "session/%s" % self.session_id)
+ except error.InvalidSessionIdException:
+ pass
+ finally:
+ self.session_id = None
+
+ def send_command(self, method, url, body=None):
+ """
+ Send a command to the remote end and validate its success.
+
+ :param method: HTTP method to use in request.
+ :param uri: "Command part" of the HTTP request URL,
+ e.g. `window/rect`.
+ :param body: Optional body of the HTTP request.
+
+ :return: `None` if the HTTP response body was empty, otherwise
+ the `value` field returned after parsing the response
+ body as JSON.
+
+ :raises error.WebDriverException: If the remote end returns
+ an error.
+ :raises ValueError: If the response body does not contain a
+ `value` key.
+ """
+ response = self.transport.send(
+ method, url, body,
+ encoder=protocol.Encoder, decoder=protocol.Decoder,
+ session=self)
+
+ if response.status != 200:
+ err = error.from_response(response)
+
+ if isinstance(err, error.InvalidSessionIdException):
+ # The driver could have already been deleted the session.
+ self.session_id = None
+
+ raise err
+
+ if "value" in response.body:
+ value = response.body["value"]
+ """
+ Edge does not yet return the w3c session ID.
+ We want the tests to run in Edge anyway to help with REC.
+ In order to run the tests in Edge, we need to hack around
+ bug:
+ https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14641972
+ """
+ if url == "session" and method == "POST" and "sessionId" in response.body and "sessionId" not in value:
+ value["sessionId"] = response.body["sessionId"]
+ else:
+ raise ValueError("Expected 'value' key in response body:\n"
+ "%s" % response)
+
+ return value
+
+ def send_session_command(self, method, uri, body=None):
+ """
+ Send a command to an established session and validate its success.
+
+ :param method: HTTP method to use in request.
+ :param url: "Command part" of the HTTP request URL,
+ e.g. `window/rect`.
+ :param body: Optional body of the HTTP request. Must be JSON
+ serialisable.
+
+ :return: `None` if the HTTP response body was empty, otherwise
+ the result of parsing the body as JSON.
+
+ :raises error.WebDriverException: If the remote end returns
+ an error.
+ """
+ url = urlparse.urljoin("session/%s/" % self.session_id, uri)
+ return self.send_command(method, url, body)
+
+ @property
+ @command
+ def url(self):
+ return self.send_session_command("GET", "url")
+
+ @url.setter
+ @command
+ def url(self, url):
+ if urlparse.urlsplit(url).netloc is None:
+ return self.url(url)
+ body = {"url": url}
+ return self.send_session_command("POST", "url", body)
+
+ @command
+ def back(self):
+ return self.send_session_command("POST", "back")
+
+ @command
+ def forward(self):
+ return self.send_session_command("POST", "forward")
+
+ @command
+ def refresh(self):
+ return self.send_session_command("POST", "refresh")
+
+ @property
+ @command
+ def title(self):
+ return self.send_session_command("GET", "title")
+
+ @property
+ @command
+ def source(self):
+ return self.send_session_command("GET", "source")
+
+ @property
+ @command
+ def window_handle(self):
+ return self.send_session_command("GET", "window")
+
+ @window_handle.setter
+ @command
+ def window_handle(self, handle):
+ body = {"handle": handle}
+ return self.send_session_command("POST", "window", body=body)
+
+ def switch_frame(self, frame):
+ if frame == "parent":
+ url = "frame/parent"
+ body = None
+ else:
+ url = "frame"
+ body = {"id": frame}
+
+ return self.send_session_command("POST", url, body)
+
+ @command
+ def close(self):
+ handles = self.send_session_command("DELETE", "window")
+ if handles is not None and len(handles) == 0:
+ # With no more open top-level browsing contexts, the session is closed.
+ self.session_id = None
+
+ return handles
+
+ @property
+ @command
+ def handles(self):
+ return self.send_session_command("GET", "window/handles")
+
+ @property
+ @command
+ def active_element(self):
+ return self.send_session_command("GET", "element/active")
+
+ @command
+ def cookies(self, name=None):
+ if name is None:
+ url = "cookie"
+ else:
+ url = "cookie/%s" % name
+ return self.send_session_command("GET", url, {})
+
+ @command
+ def set_cookie(self, name, value, path=None, domain=None,
+ secure=None, expiry=None, http_only=None):
+ body = {
+ "name": name,
+ "value": value,
+ }
+
+ if domain is not None:
+ body["domain"] = domain
+ if expiry is not None:
+ body["expiry"] = expiry
+ if http_only is not None:
+ body["httpOnly"] = http_only
+ if path is not None:
+ body["path"] = path
+ if secure is not None:
+ body["secure"] = secure
+ self.send_session_command("POST", "cookie", {"cookie": body})
+
+ def delete_cookie(self, name=None):
+ if name is None:
+ url = "cookie"
+ else:
+ url = "cookie/%s" % name
+ self.send_session_command("DELETE", url, {})
+
+ #[...]
+
+ @command
+ def execute_script(self, script, args=None):
+ if args is None:
+ args = []
+
+ body = {
+ "script": script,
+ "args": args
+ }
+ return self.send_session_command("POST", "execute/sync", body)
+
+ @command
+ def execute_async_script(self, script, args=None):
+ if args is None:
+ args = []
+
+ body = {
+ "script": script,
+ "args": args
+ }
+ return self.send_session_command("POST", "execute/async", body)
+
+ #[...]
+
+ @command
+ def screenshot(self):
+ return self.send_session_command("GET", "screenshot")
+
+
+class Element(object):
+ """
+ Representation of a web element.
+
+ A web element is an abstraction used to identify an element when
+ it is transported via the protocol, between remote- and local ends.
+ """
+ identifier = "element-6066-11e4-a52e-4f735466cecf"
+
+ def __init__(self, id, session):
+ """
+ Construct a new web element representation.
+
+ :param id: Web element UUID which must be unique across
+ all browsing contexts.
+ :param session: Current ``webdriver.Session``.
+ """
+ self.id = id
+ self.session = session
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__, self.id)
+
+ def __eq__(self, other):
+ return (isinstance(other, Element) and self.id == other.id and
+ self.session == other.session)
+
+ @classmethod
+ def from_json(cls, json, session):
+ uuid = json[Element.identifier]
+ return cls(uuid, session)
+
+ def send_element_command(self, method, uri, body=None):
+ url = "element/%s/%s" % (self.id, uri)
+ return self.session.send_session_command(method, url, body)
+
+ @command
+ def find_element(self, strategy, selector):
+ body = {"using": strategy,
+ "value": selector}
+ return self.send_element_command("POST", "element", body)
+
+ @command
+ def click(self):
+ self.send_element_command("POST", "click", {})
+
+ @command
+ def tap(self):
+ self.send_element_command("POST", "tap", {})
+
+ @command
+ def clear(self):
+ self.send_element_command("POST", "clear", {})
+
+ @command
+ def send_keys(self, text):
+ return self.send_element_command("POST", "value", {"text": text})
+
+ @property
+ @command
+ def text(self):
+ return self.send_element_command("GET", "text")
+
+ @property
+ @command
+ def name(self):
+ return self.send_element_command("GET", "name")
+
+ @command
+ def style(self, property_name):
+ return self.send_element_command("GET", "css/%s" % property_name)
+
+ @property
+ @command
+ def rect(self):
+ return self.send_element_command("GET", "rect")
+
+ @property
+ @command
+ def selected(self):
+ return self.send_element_command("GET", "selected")
+
+ @command
+ def attribute(self, name):
+ return self.send_element_command("GET", "attribute/%s" % name)
+
+ # This MUST come last because otherwise @property decorators above
+ # will be overridden by this.
+ @command
+ def property(self, name):
+ return self.send_element_command("GET", "property/%s" % name)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/error.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/error.py
new file mode 100644
index 00000000000..23ffc40b31f
--- /dev/null
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/error.py
@@ -0,0 +1,210 @@
+import collections
+import json
+
+
+class WebDriverException(Exception):
+ http_status = None
+ status_code = None
+
+ def __init__(self, http_status=None, status_code=None, message=None, stacktrace=None):
+ super(WebDriverException, self)
+ self.http_status = http_status
+ self.status_code = status_code
+ self.message = message
+ self.stacktrace = stacktrace
+
+ def __repr__(self):
+ return "<%s http_status=%s>" % (self.__class__.__name__, self.http_status)
+
+ def __str__(self):
+ message = "%s (%s)" % (self.status_code, self.http_status)
+
+ if self.message is not None:
+ message += ": %s" % self.message
+ message += "\n"
+
+ if self.stacktrace:
+ message += ("\nRemote-end stacktrace:\n\n%s" % self.stacktrace)
+
+ return message
+
+
+class ElementClickInterceptedException(WebDriverException):
+ http_status = 400
+ status_code = "element click intercepted"
+
+
+class ElementNotSelectableException(WebDriverException):
+ http_status = 400
+ status_code = "element not selectable"
+
+
+class ElementNotVisibleException(WebDriverException):
+ http_status = 400
+ status_code = "element not visible"
+
+
+class InsecureCertificateException(WebDriverException):
+ http_status = 400
+ status_code = "insecure certificate"
+
+
+class InvalidArgumentException(WebDriverException):
+ http_status = 400
+ status_code = "invalid argument"
+
+
+class InvalidCookieDomainException(WebDriverException):
+ http_status = 400
+ status_code = "invalid cookie domain"
+
+
+class InvalidElementCoordinatesException(WebDriverException):
+ http_status = 400
+ status_code = "invalid element coordinates"
+
+
+class InvalidElementStateException(WebDriverException):
+ http_status = 400
+ status_code = "invalid element state"
+
+
+class InvalidSelectorException(WebDriverException):
+ http_status = 400
+ status_code = "invalid selector"
+
+
+class InvalidSessionIdException(WebDriverException):
+ http_status = 404
+ status_code = "invalid session id"
+
+
+class JavascriptErrorException(WebDriverException):
+ http_status = 500
+ status_code = "javascript error"
+
+
+class MoveTargetOutOfBoundsException(WebDriverException):
+ http_status = 500
+ status_code = "move target out of bounds"
+
+
+class NoSuchAlertException(WebDriverException):
+ http_status = 404
+ status_code = "no such alert"
+
+
+class NoSuchCookieException(WebDriverException):
+ http_status = 404
+ status_code = "no such cookie"
+
+
+class NoSuchElementException(WebDriverException):
+ http_status = 404
+ status_code = "no such element"
+
+
+class NoSuchFrameException(WebDriverException):
+ http_status = 404
+ status_code = "no such frame"
+
+
+class NoSuchWindowException(WebDriverException):
+ http_status = 404
+ status_code = "no such window"
+
+
+class ScriptTimeoutException(WebDriverException):
+ http_status = 500
+ status_code = "script timeout"
+
+
+class SessionNotCreatedException(WebDriverException):
+ http_status = 500
+ status_code = "session not created"
+
+
+class StaleElementReferenceException(WebDriverException):
+ http_status = 404
+ status_code = "stale element reference"
+
+
+class TimeoutException(WebDriverException):
+ http_status = 500
+ status_code = "timeout"
+
+
+class UnableToSetCookieException(WebDriverException):
+ http_status = 500
+ status_code = "unable to set cookie"
+
+
+class UnexpectedAlertOpenException(WebDriverException):
+ http_status = 500
+ status_code = "unexpected alert open"
+
+
+class UnknownErrorException(WebDriverException):
+ http_status = 500
+ status_code = "unknown error"
+
+
+class UnknownCommandException(WebDriverException):
+ http_status = 404
+ status_code = "unknown command"
+
+
+class UnknownMethodException(WebDriverException):
+ http_status = 405
+ status_code = "unknown method"
+
+
+class UnsupportedOperationException(WebDriverException):
+ http_status = 500
+ status_code = "unsupported operation"
+
+
+def from_response(response):
+ """
+ Unmarshals an error from a ``Response``'s `body`, failing
+ if not all three required `error`, `message`, and `stacktrace`
+ fields are given. Defaults to ``WebDriverException`` if `error`
+ is unknown.
+ """
+ if response.status == 200:
+ raise UnknownErrorException(
+ response.status,
+ None,
+ "Response is not an error:\n"
+ "%s" % json.dumps(response.body))
+
+ if "value" in response.body:
+ value = response.body["value"]
+ else:
+ raise UnknownErrorException(
+ response.status,
+ None,
+ "Expected 'value' key in response body:\n"
+ "%s" % json.dumps(response.body))
+
+ # all fields must exist, but stacktrace can be an empty string
+ code = value["error"]
+ message = value["message"]
+ stack = value["stacktrace"] or None
+
+ cls = get(code)
+ return cls(response.status, code, message, stacktrace=stack)
+
+
+def get(error_code):
+ """
+ Gets exception from `error_code`, falling back to
+ ``WebDriverException`` if it is not found.
+ """
+ return _errors.get(error_code, WebDriverException)
+
+
+_errors = collections.defaultdict()
+for item in locals().values():
+ if type(item) == type and issubclass(item, WebDriverException):
+ _errors[item.status_code] = item
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/protocol.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/protocol.py
new file mode 100644
index 00000000000..18a3d52c8a3
--- /dev/null
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/protocol.py
@@ -0,0 +1,43 @@
+import json
+
+import webdriver
+
+
+"""WebDriver wire protocol codecs."""
+
+
+class Encoder(json.JSONEncoder):
+ def __init__(self, *args, **kwargs):
+ kwargs.pop("session")
+ super(Encoder, self).__init__(*args, **kwargs)
+
+ def default(self, obj):
+ if isinstance(obj, (list, tuple)):
+ return [self.default(x) for x in obj]
+ elif isinstance(obj, webdriver.Element):
+ return {webdriver.Element.identifier: obj.id}
+ elif isinstance(obj, webdriver.Frame):
+ return {webdriver.Frame.identifier: obj.id}
+ elif isinstance(obj, webdriver.Window):
+ return {webdriver.Frame.identifier: obj.id}
+ return super(Encoder, self).default(obj)
+
+
+class Decoder(json.JSONDecoder):
+ def __init__(self, *args, **kwargs):
+ self.session = kwargs.pop("session")
+ super(Decoder, self).__init__(
+ object_hook=self.object_hook, *args, **kwargs)
+
+ def object_hook(self, payload):
+ if isinstance(payload, (list, tuple)):
+ return [self.object_hook(x) for x in payload]
+ elif isinstance(payload, dict) and webdriver.Element.identifier in payload:
+ return webdriver.Element.from_json(payload, self.session)
+ elif isinstance(payload, dict) and webdriver.Frame.identifier in payload:
+ return webdriver.Frame.from_json(payload, self.session)
+ elif isinstance(payload, dict) and webdriver.Window.identifier in payload:
+ return webdriver.Window.from_json(payload, self.session)
+ elif isinstance(payload, dict):
+ return {k: self.object_hook(v) for k, v in payload.iteritems()}
+ return payload
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py
new file mode 100644
index 00000000000..881002ad117
--- /dev/null
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py
@@ -0,0 +1,192 @@
+import httplib
+import json
+import select
+import urlparse
+
+import error
+
+from six import text_type
+
+"""Implements HTTP transport for the WebDriver wire protocol."""
+
+
+class Response(object):
+ """
+ Describes an HTTP response received from a remote end whose
+ body has been read and parsed as appropriate.
+ """
+
+ def __init__(self, status, body):
+ self.status = status
+ self.body = body
+
+ def __repr__(self):
+ cls_name = self.__class__.__name__
+ if self.error:
+ return "<%s status=%s error=%s>" % (cls_name, self.status, repr(self.error))
+ return "<% status=%s body=%s>" % (cls_name, self.status, json.dumps(self.body))
+
+ def __str__(self):
+ return json.dumps(self.body, indent=2)
+
+ @property
+ def error(self):
+ if self.status != 200:
+ return error.from_response(self)
+ return None
+
+ @classmethod
+ def from_http(cls, http_response, decoder=json.JSONDecoder, **kwargs):
+ try:
+ body = json.load(http_response, cls=decoder, **kwargs)
+ except ValueError:
+ raise ValueError("Failed to decode response body as JSON:\n" +
+ http_response.read())
+
+ return cls(http_response.status, body)
+
+
+class HTTPWireProtocol(object):
+ """
+ Transports messages (commands and responses) over the WebDriver
+ wire protocol.
+
+ Complex objects, such as ``webdriver.Element``, ``webdriver.Frame``,
+ and ``webdriver.Window`` are by default not marshaled to enable
+ use of `session.transport.send` in WPT tests::
+
+ session = webdriver.Session("127.0.0.1", 4444)
+ response = transport.send("GET", "element/active", None)
+ print response.body["value"]
+ # => {u'element-6066-11e4-a52e-4f735466cecf': u'<uuid>'}
+
+ Automatic marshaling is provided by ``webdriver.protocol.Encoder``
+ and ``webdriver.protocol.Decoder``, which can be passed in to
+ ``HTTPWireProtocol.send`` along with a reference to the current
+ ``webdriver.Session``::
+
+ session = webdriver.Session("127.0.0.1", 4444)
+ response = transport.send("GET", "element/active", None,
+ encoder=protocol.Encoder, decoder=protocol.Decoder,
+ session=session)
+ print response.body["value"]
+ # => webdriver.Element
+ """
+
+ def __init__(self, host, port, url_prefix="/", timeout=None):
+ """
+ Construct interface for communicating with the remote server.
+
+ :param url: URL of remote WebDriver server.
+ :param wait: Duration to wait for remote to appear.
+ """
+ self.host = host
+ self.port = port
+ self.url_prefix = url_prefix
+
+ self._conn = None
+ self._timeout = timeout
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ """Closes the current HTTP connection, if there is one."""
+ if self._conn:
+ self._conn.close()
+
+ @property
+ def connection(self):
+ """Gets the current HTTP connection, or lazily creates one."""
+ if not self._conn:
+ conn_kwargs = {}
+ if self._timeout is not None:
+ conn_kwargs["timeout"] = self._timeout
+
+ self._conn = httplib.HTTPConnection(
+ self.host, self.port, strict=True, **conn_kwargs)
+
+ return self._conn
+
+ def url(self, suffix):
+ """
+ From the relative path to a command end-point,
+ craft a full URL suitable to be used in a request to the HTTPD.
+ """
+ return urlparse.urljoin(self.url_prefix, suffix)
+
+ def send(self,
+ method,
+ uri,
+ body=None,
+ headers=None,
+ encoder=json.JSONEncoder,
+ decoder=json.JSONDecoder,
+ **codec_kwargs):
+ """
+ Send a command to the remote.
+
+ The request `body` must be JSON serialisable unless a
+ custom `encoder` has been provided. This means complex
+ objects such as ``webdriver.Element``, ``webdriver.Frame``,
+ and `webdriver.Window`` are not automatically made
+ into JSON. This behaviour is, however, provided by
+ ``webdriver.protocol.Encoder``, should you want it.
+
+ Similarly, the response body is returned au natural
+ as plain JSON unless a `decoder` that converts web
+ element references to ``webdriver.Element`` is provided.
+ Use ``webdriver.protocol.Decoder`` to achieve this behaviour.
+
+ The client will attempt to use persistent HTTP connections.
+
+ :param method: `GET`, `POST`, or `DELETE`.
+ :param uri: Relative endpoint of the requests URL path.
+ :param body: Body of the request. Defaults to an empty
+ dictionary if ``method`` is `POST`.
+ :param headers: Additional dictionary of headers to include
+ in the request.
+ :param encoder: JSON encoder class, which defaults to
+ ``json.JSONEncoder`` unless specified.
+ :param decoder: JSON decoder class, which defaults to
+ ``json.JSONDecoder`` unless specified.
+ :param codec_kwargs: Surplus arguments passed on to `encoder`
+ and `decoder` on construction.
+
+ :return: Instance of ``webdriver.transport.Response``
+ describing the HTTP response received from the remote end.
+
+ :raises ValueError: If `body` or the response body are not
+ JSON serialisable.
+ """
+ if body is None and method == "POST":
+ body = {}
+
+ payload = None
+ if body is not None:
+ try:
+ payload = json.dumps(body, cls=encoder, **codec_kwargs)
+ except ValueError:
+ raise ValueError("Failed to encode request body as JSON:\n"
+ "%s" % json.dumps(body, indent=2))
+
+ response = self._request(method, uri, payload, headers)
+ return Response.from_http(response, decoder=decoder, **codec_kwargs)
+
+ def _request(self, method, uri, payload, headers=None):
+ if isinstance(payload, text_type):
+ payload = payload.encode("utf-8")
+
+ if headers is None:
+ headers = {}
+ headers.update({"Connection": "keep-alive"})
+
+ url = self.url(uri)
+
+ if self._has_unread_data():
+ self.close()
+ self.connection.request(method, url, payload, headers)
+ return self.connection.getresponse()
+
+ def _has_unread_data(self):
+ return self._conn and select.select([self._conn.sock], [], [], 0)[0]
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
index 51f0dbdba92..71d1e61918a 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
@@ -1,4 +1,3 @@
-import logging
import os
import platform
import re
@@ -12,14 +11,15 @@ from distutils.spawn import find_executable
from utils import call, get, untar, unzip
-logger = logging.getLogger(__name__)
-
uname = platform.uname()
class Browser(object):
__metaclass__ = ABCMeta
+ def __init__(self, logger):
+ self.logger = logger
+
@abstractmethod
def install(self, dest=None):
"""Install the browser."""
@@ -46,7 +46,7 @@ class Browser(object):
return NotImplemented
@abstractmethod
- def version(self, binary=None):
+ def version(self, binary=None, webdriver_binary=None):
"""Retrieve the release version of the installed browser."""
return NotImplemented
@@ -67,22 +67,28 @@ class Firefox(Browser):
platform_ini = "browsers/firefox/platform.ini"
requirements = "requirements_firefox.txt"
- def platform_string_geckodriver(self):
- platform = {
- "Linux": "linux",
- "Windows": "win",
- "Darwin": "macos"
- }.get(uname[0])
+ platform = {
+ "Linux": "linux",
+ "Windows": "win",
+ "Darwin": "macos"
+ }.get(uname[0])
- if platform is None:
+ application_name = {
+ "stable": "Firefox.app",
+ "beta": "Firefox.app",
+ "nightly": "Firefox Nightly.app"
+ }
+
+ def platform_string_geckodriver(self):
+ if self.platform is None:
raise ValueError("Unable to construct a valid Geckodriver package name for current platform")
- if platform in ("linux", "win"):
+ if self.platform in ("linux", "win"):
bits = "64" if uname[4] == "x86_64" else "32"
else:
bits = ""
- return "%s%s" % (platform, bits)
+ return "%s%s" % (self.platform, bits)
def install(self, dest=None, channel="nightly"):
"""Install Firefox."""
@@ -102,24 +108,14 @@ class Firefox(Browser):
"beta": "latest-beta",
"nightly": "latest"
}
- application_name = {
- "stable": "Firefox.app",
- "beta": "Firefox.app",
- "nightly": "Firefox Nightly.app"
- }
+
if channel not in branch:
raise ValueError("Unrecognised release channel: %s" % channel)
from mozdownload import FactoryScraper
import mozinstall
- platform = {
- "Linux": "linux",
- "Windows": "win",
- "Darwin": "mac"
- }.get(uname[0])
-
- if platform is None:
+ if self.platform is None:
raise ValueError("Unable to construct a valid Firefox package name for current platform")
if dest is None:
@@ -128,18 +124,22 @@ class Firefox(Browser):
dest = os.path.join(dest, "browsers", channel)
- filename = FactoryScraper(scraper[channel],
- branch=branch[channel],
- version=version[channel],
- destination=dest).download()
+ scraper = FactoryScraper(scraper[channel],
+ branch=branch[channel],
+ version=version[channel],
+ destination=dest)
+
+ self.logger.info("Downloading Firefox from %s" % scraper.url)
+
+ filename = scraper.download()
try:
mozinstall.install(filename, dest)
except mozinstall.mozinstall.InstallError:
- if platform == "mac" and os.path.exists(os.path.join(dest, application_name[channel])):
+ if self.platform == "macos" and os.path.exists(os.path.join(dest, self.application_name.get(channel, "Firefox Nightly.app"))):
# mozinstall will fail if nightly is already installed in the venv because
# mac installation uses shutil.copy_tree
- mozinstall.uninstall(os.path.join(dest, application_name[channel]))
+ mozinstall.uninstall(os.path.join(dest, self.application_name.get(channel, "Firefox Nightly.app")))
mozinstall.install(filename, dest)
else:
raise
@@ -150,46 +150,31 @@ class Firefox(Browser):
def find_binary_path(self,path=None, channel="nightly"):
"""Looks for the firefox binary in the virtual environment"""
- platform = {
- "Linux": "linux",
- "Windows": "win",
- "Darwin": "mac"
- }.get(uname[0])
-
- application_name = {
- "stable": "Firefox.app",
- "beta": "Firefox.app",
- "nightly": "Firefox Nightly.app"
- }.get(channel)
-
if path is None:
#os.getcwd() doesn't include the venv path
path = os.path.join(os.getcwd(), "_venv", "browsers", channel)
binary = None
- if platform == "linux":
+ if self.platform == "linux":
binary = find_executable("firefox", os.path.join(path, "firefox"))
- elif platform == "win":
+ elif self.platform == "win":
import mozinstall
binary = mozinstall.get_binary(path, "firefox")
- elif platform == "mac":
- binary = find_executable("firefox", os.path.join(path, application_name,
+ elif self.platform == "macos":
+ binary = find_executable("firefox", os.path.join(path, self.application_name.get(channel, "Firefox Nightly.app"),
"Contents", "MacOS"))
return binary
- def find_binary(self, venv_path=None, channel=None):
+ def find_binary(self, venv_path=None, channel="nightly"):
if venv_path is None:
venv_path = os.path.join(os.getcwd(), "_venv")
- if channel is None:
- channel = "nightly"
-
path = os.path.join(venv_path, "browsers", channel)
binary = self.find_binary_path(path, channel)
- if not binary and uname[0] == "Darwin":
+ if not binary and self.platform == "macos":
macpaths = ["/Applications/Firefox Nightly.app/Contents/MacOS",
os.path.expanduser("~/Applications/Firefox Nightly.app/Contents/MacOS"),
"/Applications/Firefox Developer Edition.app/Contents/MacOS",
@@ -256,13 +241,15 @@ class Firefox(Browser):
if channel is not None and channel != channel_:
# Beta doesn't always seem to have the b in the version string, so allow the
# manually supplied value to override the one from the binary
- logger.warning("Supplied channel doesn't match binary, using supplied channel")
+ self.logger.warning("Supplied channel doesn't match binary, using supplied channel")
elif channel is None:
channel = channel_
if dest is None:
dest = os.pwd
- dest = os.path.join(dest, "profiles", channel, version)
+ dest = os.path.join(dest, "profiles", channel)
+ if version:
+ dest = os.path.join(dest, version)
have_cache = False
if os.path.exists(dest):
if channel != "nightly":
@@ -280,7 +267,7 @@ class Firefox(Browser):
url = self.get_profile_bundle_url(version, channel)
- print("Installing test prefs from %s" % url)
+ self.logger.info("Installing test prefs from %s" % url)
try:
extract_dir = tempfile.mkdtemp()
unzip(get(url).raw, dest=extract_dir)
@@ -292,7 +279,7 @@ class Firefox(Browser):
finally:
shutil.rmtree(extract_dir)
else:
- print("Using cached test prefs from %s" % dest)
+ self.logger.info("Using cached test prefs from %s" % dest)
return dest
@@ -322,11 +309,11 @@ class Firefox(Browser):
if path is not None:
return path
else:
- logger.warning("Nightly webdriver not found; falling back to release")
+ self.logger.warning("Nightly webdriver not found; falling back to release")
version = self._latest_geckodriver_version()
format = "zip" if uname[0] == "Windows" else "tar.gz"
- logger.debug("Latest geckodriver release %s" % version)
+ self.logger.debug("Latest geckodriver release %s" % version)
url = ("https://github.com/mozilla/geckodriver/releases/download/%s/geckodriver-%s-%s.%s" %
(version, version, self.platform_string_geckodriver(), format))
if format == "zip":
@@ -338,7 +325,7 @@ class Firefox(Browser):
def install_geckodriver_nightly(self, dest):
import tarfile
import mozdownload
- logger.info("Attempting to install webdriver from nightly")
+ self.logger.info("Attempting to install webdriver from nightly")
try:
s = mozdownload.DailyScraper(branch="mozilla-central",
extension="common.tests.tar.gz",
@@ -359,15 +346,14 @@ class Firefox(Browser):
member.name = os.path.basename(member.name)
f.extractall(members=[member], path=dest)
path = os.path.join(dest, member.name)
- logger.info("Extracted geckodriver to %s" % path)
+ self.logger.info("Extracted geckodriver to %s" % path)
finally:
os.unlink(package_path)
return path
- def version(self, binary=None, channel=None):
+ def version(self, binary=None, webdriver_binary=None):
"""Retrieve the release version of the installed browser."""
- binary = binary or self.find_binary(channel)
version_string = call(binary, "--version").strip()
m = re.match(r"Mozilla Firefox (.*)", version_string)
if not m:
@@ -393,7 +379,7 @@ class Fennec(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary=None):
+ def version(self, binary=None, webdriver_binary=None):
return None
@@ -413,7 +399,7 @@ class Chrome(Browser):
if uname[0] == "Darwin":
return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
# TODO Windows?
- logger.warn("Unable to find the browser binary.")
+ self.logger.warning("Unable to find the browser binary.")
return None
def install(self, dest=None, channel=None):
@@ -457,20 +443,20 @@ class Chrome(Browser):
os.chmod(path, st.st_mode | stat.S_IEXEC)
return path
- def version(self, binary=None):
+ def version(self, binary=None, webdriver_binary=None):
binary = binary or self.binary
if uname[0] != "Windows":
try:
version_string = call(binary, "--version").strip()
except subprocess.CalledProcessError:
- logger.warn("Failed to call %s", binary)
+ self.logger.warning("Failed to call %s", binary)
return None
m = re.match(r"Google Chrome (.*)", version_string)
if not m:
- logger.warn("Failed to extract version from: s%", version_string)
+ self.logger.warning("Failed to extract version from: s%", version_string)
return None
return m.group(1)
- logger.warn("Unable to extract version from binary on Windows.")
+ self.logger.warning("Unable to extract version from binary on Windows.")
return None
@@ -496,7 +482,7 @@ class ChromeAndroid(Browser):
chrome = Chrome()
return chrome.install_webdriver(dest, channel)
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
return None
class Opera(Browser):
@@ -513,7 +499,7 @@ class Opera(Browser):
if uname[0] == "Linux":
return "/usr/bin/opera"
# TODO Windows, Mac?
- logger.warn("Unable to find the browser binary.")
+ self.logger.warning("Unable to find the browser binary.")
return None
def install(self, dest=None, channel=None):
@@ -561,15 +547,17 @@ class Opera(Browser):
os.chmod(path, st.st_mode | stat.S_IEXEC)
return path
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
"""Retrieve the release version of the installed browser."""
binary = binary or self.binary
try:
output = call(binary, "--version")
except subprocess.CalledProcessError:
- logger.warn("Failed to call %s", binary)
+ self.logger.warning("Failed to call %s", binary)
return None
- return re.search(r"[0-9\.]+( [a-z]+)?$", output.strip()).group(0)
+ m = re.search(r"[0-9\.]+( [a-z]+)?$", output.strip())
+ if m:
+ return m.group(0)
class Edge(Browser):
@@ -590,7 +578,7 @@ class Edge(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
return None
@@ -616,7 +604,7 @@ class InternetExplorer(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
return None
@@ -644,12 +632,24 @@ class Safari(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary):
- return None
-
-
-class SafariWebDriver(Safari):
- product = "safari_webdriver"
+ def version(self, binary=None, webdriver_binary=None):
+ if webdriver_binary is None:
+ self.logger.warning("Cannot find Safari version without safaridriver")
+ return None
+ # Use `safaridriver --version` to get the version. Example output:
+ # "Included with Safari 12.1 (14607.1.11)"
+ # "Included with Safari Technology Preview (Release 67, 13607.1.9.0.1)"
+ # The `--version` flag was added in STP 67, so allow the call to fail.
+ try:
+ version_string = call(webdriver_binary, "--version").strip()
+ except subprocess.CalledProcessError:
+ self.logger.warning("Failed to call %s --version", webdriver_binary)
+ return None
+ m = re.match(r"Included with Safari (.*)", version_string)
+ if not m:
+ self.logger.warning("Failed to extract version from: s%", version_string)
+ return None
+ return m.group(1)
class Servo(Browser):
@@ -704,10 +704,16 @@ class Servo(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
"""Retrieve the release version of the installed browser."""
output = call(binary, "--version")
- return re.search(r"[0-9\.]+( [a-z]+)?$", output.strip()).group(0)
+ m = re.search(r"Servo ([0-9\.]+-[a-f0-9]+)?(-dirty)?$", output.strip())
+ if m:
+ return m.group(0)
+
+
+class ServoWebDriver(Servo):
+ product = "servodriver"
class Sauce(Browser):
@@ -728,7 +734,7 @@ class Sauce(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
return None
@@ -750,5 +756,5 @@ class WebKit(Browser):
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
- def version(self, binary):
+ def version(self, binary=None, webdriver_binary=None):
return None
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/commands.json b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/commands.json
index 0ea6b25276f..161a9defbd1 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/commands.json
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/commands.json
@@ -1,6 +1,7 @@
{
"run": {"path": "run.py", "script": "run", "parser": "create_parser", "help": "Run tests in a browser",
"virtualenv": true, "install": ["requests"], "requirements": ["../wptrunner/requirements.txt"]},
+ "create": {"path": "create.py", "script": "run", "parser": "get_parser", "help": "Create a new wpt test"},
"update-expectations": {"path": "update.py", "script": "update_expectations",
"parser": "create_parser_update", "help": "Update expectations files from raw logs.",
"virtualenv": true, "install": ["requests"],
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
index f588a412845..be6bf815986 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
@@ -7,7 +7,6 @@ latest_channels = {
'firefox': 'nightly',
'chrome': 'dev',
'safari': 'preview',
- 'safari_webdriver': 'preview',
'servo': 'nightly'
}
@@ -48,7 +47,7 @@ def get_parser():
def get_channel(browser, channel):
channel = channel_by_name[channel]
if isinstance(channel, dict):
- channel = channel[browser]
+ channel = channel.get(browser)
return channel
@@ -58,8 +57,8 @@ def run(venv, **kwargs):
channel = get_channel(browser, kwargs["channel"])
if channel != kwargs["channel"]:
- print "Interpreting channel '%s' as '%s'" % (kwargs["channel"],
- channel)
+ print("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+ channel))
if destination is None:
if venv:
@@ -74,7 +73,11 @@ def run(venv, **kwargs):
install(browser, kwargs["component"], destination, channel)
-def install(name, component, destination, channel="nightly"):
+def install(name, component, destination, channel="nightly", logger=None):
+ if logger is None:
+ import logging
+ logger = logging.getLogger("install")
+
if component == 'webdriver':
method = 'install_webdriver'
else:
@@ -82,6 +85,6 @@ def install(name, component, destination, channel="nightly"):
subclass = getattr(browser, name.title())
sys.stdout.write('Now installing %s %s...\n' % (name, component))
- path = getattr(subclass(), method)(dest=destination, channel=channel)
+ path = getattr(subclass(logger), method)(dest=destination, channel=channel)
if path:
sys.stdout.write('Binary installed as %s\n' % (path,))
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/markdown.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/markdown.py
index 8b5ff8079df..43020cdafe6 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/markdown.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/markdown.py
@@ -1,3 +1,5 @@
+from functools import reduce
+
def format_comment_title(product):
"""Produce a Markdown-formatted string based on a given "product"--a string
containing a browser identifier optionally followed by a colon and a
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
index 452b83f9df6..44cf3137d41 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
@@ -3,11 +3,12 @@ import os
import platform
import sys
from distutils.spawn import find_executable
+from six.moves import input
wpt_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
-from . import browser, install, utils, virtualenv
+from . import browser, install, testfiles, utils, virtualenv
from ..serve import serve
logger = None
@@ -44,6 +45,8 @@ def create_parser():
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("product", action="store",
help="Browser to run tests in")
+ parser.add_argument("--affected", action="store", default=None,
+ help="Run affected tests since revish")
parser.add_argument("--yes", "-y", dest="prompt", action="store_false", default=True,
help="Don't prompt before installing components")
parser.add_argument("--install-browser", action="store_true",
@@ -62,9 +65,12 @@ def create_parser():
return parser
-def exit(msg):
- logger.error(msg)
- sys.exit(1)
+def exit(msg=None):
+ if msg:
+ logger.error(msg)
+ sys.exit(1)
+ else:
+ sys.exit(0)
def args_general(kwargs):
@@ -145,7 +151,7 @@ class BrowserSetup(object):
browser_cls = None
def __init__(self, venv, prompt=True, sub_product=None):
- self.browser = self.browser_cls()
+ self.browser = self.browser_cls(logger)
self.venv = venv
self.prompt = prompt
self.sub_product = sub_product
@@ -154,7 +160,7 @@ class BrowserSetup(object):
if not self.prompt:
return True
while True:
- resp = raw_input("Download and install %s [Y/n]? " % component).strip().lower()
+ resp = input("Download and install %s [Y/n]? " % component).strip().lower()
if not resp or resp == "y":
return True
elif resp == "n":
@@ -178,6 +184,7 @@ class Firefox(BrowserSetup):
def setup_kwargs(self, kwargs):
if kwargs["binary"] is None:
if kwargs["browser_channel"] is None:
+ kwargs["browser_channel"] = "nightly"
logger.info("No browser channel specified. Running nightly instead.")
binary = self.browser.find_binary(self.venv.path,
@@ -196,7 +203,7 @@ Install Firefox or use --binary to set the binary path""")
logger.info("""Can't find certutil, certificates will not be checked.
Consider installing certutil via your OS package manager or directly.""")
else:
- print("Using certutil %s" % certutil)
+ logger.info("Using certutil %s" % certutil)
kwargs["certutil_binary"] = certutil
@@ -207,15 +214,15 @@ Consider installing certutil via your OS package manager or directly.""")
install = self.prompt_install("geckodriver")
if install:
- print("Downloading geckodriver")
+ logger.info("Downloading geckodriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
- print("Using webdriver binary %s" % webdriver_binary)
+ logger.info("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
else:
- print("Unable to find or install geckodriver, skipping wdspec tests")
+ logger.info("Unable to find or install geckodriver, skipping wdspec tests")
kwargs["test_types"].remove("wdspec")
if kwargs["prefs_root"] is None:
@@ -228,6 +235,11 @@ Consider installing certutil via your OS package manager or directly.""")
kwargs["headless"] = True
logger.info("Running in headless mode, pass --no-headless to disable")
+ # Turn off Firefox WebRTC ICE logging on WPT (turned on by mozrunner)
+ os.unsetenv('R_LOG_LEVEL')
+ os.unsetenv('R_LOG_DESTINATION')
+ os.unsetenv('R_LOG_VERBOSE')
+
# Allow WebRTC tests to call getUserMedia.
kwargs["extra_prefs"].append("media.navigator.streams.fake=true")
@@ -252,10 +264,10 @@ class Chrome(BrowserSetup):
install = self.prompt_install("chromedriver")
if install:
- print("Downloading chromedriver")
+ logger.info("Downloading chromedriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
- print("Using webdriver binary %s" % webdriver_binary)
+ logger.info("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
@@ -264,6 +276,11 @@ class Chrome(BrowserSetup):
if kwargs["browser_channel"] == "dev":
logger.info("Automatically turning on experimental features for Chrome Dev")
kwargs["binary_args"].append("--enable-experimental-web-platform-features")
+ # TODO(foolip): remove after unified plan is enabled on Chrome stable
+ kwargs["binary_args"].append("--enable-features=RTCUnifiedPlanByDefault")
+
+ # Allow audio autoplay without a user gesture.
+ kwargs["binary_args"].append("--autoplay-policy=no-user-gesture-required")
# Allow WebRTC tests to call getUserMedia.
kwargs["binary_args"] += ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream"]
@@ -281,10 +298,10 @@ class ChromeAndroid(BrowserSetup):
install = self.prompt_install("chromedriver")
if install:
- print("Downloading chromedriver")
+ logger.info("Downloading chromedriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
- print("Using webdriver binary %s" % webdriver_binary)
+ logger.info("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
@@ -304,10 +321,10 @@ class Opera(BrowserSetup):
install = self.prompt_install("operadriver")
if install:
- print("Downloading operadriver")
+ logger.info("Downloading operadriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
- print("Using webdriver binary %s" % webdriver_binary)
+ logger.info("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
@@ -379,11 +396,6 @@ class Safari(BrowserSetup):
kwargs["webdriver_binary"] = webdriver_binary
-class SafariWebDriver(Safari):
- name = "safari_webdriver"
- browser_cls = browser.SafariWebDriver
-
-
class Sauce(BrowserSetup):
name = "sauce"
browser_cls = browser.Sauce
@@ -414,6 +426,11 @@ class Servo(BrowserSetup):
kwargs["binary"] = binary
+class ServoWebDriver(Servo):
+ name = "servodriver"
+ browser_cls = browser.ServoWebDriver
+
+
class WebKit(BrowserSetup):
name = "webkit"
browser_cls = browser.WebKit
@@ -434,34 +451,41 @@ product_setup = {
"edge_webdriver": EdgeWebDriver,
"ie": InternetExplorer,
"safari": Safari,
- "safari_webdriver": SafariWebDriver,
"servo": Servo,
+ "servodriver": ServoWebDriver,
"sauce": Sauce,
"opera": Opera,
"webkit": WebKit,
}
-def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
- from wptrunner import wptrunner, wptcommandline
+def setup_logging(kwargs, default_config=None):
import mozlog
+ from wptrunner import wptrunner
global logger
+ # Use the grouped formatter by default where mozlog 3.9+ is installed
+ if default_config is None:
+ if hasattr(mozlog.formatters, "GroupingFormatter"):
+ default_formatter = "grouped"
+ else:
+ default_formatter = "mach"
+ default_config = {default_formatter: sys.stdout}
+ wptrunner.setup_logging(kwargs, default_config)
+ logger = wptrunner.logger
+ return logger
+
+
+def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
+ from wptrunner import wptcommandline
+
kwargs = utils.Kwargs(kwargs.iteritems())
product_parts = kwargs["product"].split(":")
kwargs["product"] = product_parts[0]
sub_product = product_parts[1:]
- # Use the grouped formatter by default where mozlog 3.9+ is installed
- if hasattr(mozlog.formatters, "GroupingFormatter"):
- default_formatter = "grouped"
- else:
- default_formatter = "mach"
- wptrunner.setup_logging(kwargs, {default_formatter: sys.stdout})
- logger = wptrunner.logger
-
check_environ(kwargs["product"])
args_general(kwargs)
@@ -471,16 +495,38 @@ def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
setup_cls = product_setup[kwargs["product"]](venv, prompt, sub_product)
setup_cls.install_requirements()
+ affected_revish = kwargs.pop("affected", None)
+ if affected_revish is not None:
+ # TODO: Consolidate with `./wpt tests-affected --ignore-rules`:
+ # https://github.com/web-platform-tests/wpt/issues/14560
+ files_changed, _ = testfiles.files_changed(
+ affected_revish,
+ ignore_rules=["resources/testharness*"],
+ include_uncommitted=True, include_new=True)
+ # TODO: Perhaps use wptrunner.testloader.ManifestLoader here
+ # and remove the manifest-related code from testfiles.
+ # https://github.com/web-platform-tests/wpt/issues/14421
+ tests_changed, tests_affected = testfiles.affected_testfiles(
+ files_changed, manifest_path=kwargs.get("manifest_path"), manifest_update=kwargs["manifest_update"])
+ test_list = tests_changed | tests_affected
+ logger.info("Identified %s affected tests" % len(test_list))
+ test_list = [os.path.relpath(item, wpt_root) for item in test_list]
+ kwargs["test_list"] += test_list
+ kwargs["default_exclude"] = True
+
if install_browser and not kwargs["channel"]:
logger.info("--install-browser is given but --channel is not set, default to nightly channel")
kwargs["channel"] = "nightly"
if kwargs["channel"]:
channel = install.get_channel(kwargs["product"], kwargs["channel"])
- if channel != kwargs["channel"]:
- logger.info("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
- channel))
- kwargs["browser_channel"] = channel
+ if channel is not None:
+ if channel != kwargs["channel"]:
+ logger.info("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+ channel))
+ kwargs["browser_channel"] = channel
+ else:
+ logger.info("Valid channels for %s not known; using argument unmodified" % kwargs["product"])
del kwargs["channel"]
if install_browser:
@@ -495,11 +541,14 @@ def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
venv.install_requirements(os.path.join(wptrunner_path, "requirements.txt"))
- kwargs['browser_version'] = setup_cls.browser.version(kwargs.get("binary"))
+ kwargs['browser_version'] = setup_cls.browser.version(binary=kwargs.get("binary"),
+ webdriver_binary=kwargs.get("webdriver_binary"))
return kwargs
def run(venv, **kwargs):
+ setup_logging(kwargs)
+
# Remove arguments that aren't passed to wptrunner
prompt = kwargs.pop("prompt", True)
install_browser = kwargs.pop("install_browser", False)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py
index 35a4b97d7ff..70e695aa010 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py
@@ -8,8 +8,6 @@ import sys
from collections import OrderedDict
from six import iteritems
-from ..manifest import manifest, update
-
here = os.path.dirname(__file__)
wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
@@ -162,9 +160,12 @@ def exclude_ignored(files, ignore_rules):
def files_changed(revish, ignore_rules=None, include_uncommitted=False, include_new=False):
- """Get and return files changed since current branch diverged from master,
- excluding those that are located within any path matched by
- `ignore_rules`."""
+ """Find files changed in certain revisions.
+
+ The function passes `revish` directly to `git diff`, so `revish` can have a
+ variety of forms; see `git diff --help` for details. Files in the diff that
+ are matched by `ignore_rules` are excluded.
+ """
files = repo_files_changed(revish,
include_uncommitted=include_uncommitted,
include_new=include_new)
@@ -180,36 +181,28 @@ def _in_repo_root(full_path):
return len(path_components) < 2
-def _init_manifest_cache():
- c = {}
-
- def load(manifest_path=None):
- if manifest_path is None:
- manifest_path = os.path.join(wpt_root, "MANIFEST.json")
- if c.get(manifest_path):
- return c[manifest_path]
- # cache at most one path:manifest
- c.clear()
- wpt_manifest = manifest.load(wpt_root, manifest_path)
- if wpt_manifest is None:
- wpt_manifest = manifest.Manifest()
- update.update(wpt_root, wpt_manifest)
- c[manifest_path] = wpt_manifest
- return c[manifest_path]
- return load
-
+def load_manifest(manifest_path=None, manifest_update=True):
+ # Delay import after localpaths sets up sys.path, because otherwise the
+ # import path will be "..manifest" and Python will treat it as a different
+ # manifest module.
+ from manifest import manifest
+ if manifest_path is None:
+ manifest_path = os.path.join(wpt_root, "MANIFEST.json")
+ return manifest.load_and_update(wpt_root, manifest_path, "/",
+ update=manifest_update)
-load_manifest = _init_manifest_cache()
-
-def affected_testfiles(files_changed, skip_tests, manifest_path=None):
+def affected_testfiles(files_changed, skip_dirs=None,
+ manifest_path=None, manifest_update=True):
"""Determine and return list of test files that reference changed files."""
+ if skip_dirs is None:
+ skip_dirs = set(["conformance-checkers", "docs", "tools"])
affected_testfiles = set()
# Exclude files that are in the repo root, because
# they are not part of any test.
files_changed = [f for f in files_changed if not _in_repo_root(f)]
nontests_changed = set(files_changed)
- wpt_manifest = load_manifest(manifest_path)
+ wpt_manifest = load_manifest(manifest_path, manifest_update)
test_types = ["testharness", "reftest", "wdspec"]
support_files = {os.path.join(wpt_root, path)
@@ -219,6 +212,11 @@ def affected_testfiles(files_changed, skip_tests, manifest_path=None):
test_files = {os.path.join(wpt_root, path)
for _, path, _ in wpt_manifest.itertypes(*test_types)}
+ interface_dir = os.path.join(wpt_root, 'interfaces')
+ interfaces_files = {os.path.join(wpt_root, 'interfaces', filename)
+ for filename in os.listdir(interface_dir)}
+
+ interfaces_changed = interfaces_files.intersection(nontests_changed)
nontests_changed = nontests_changed.intersection(support_files)
tests_changed = set(item for item in files_changed if item in test_files)
@@ -229,7 +227,7 @@ def affected_testfiles(files_changed, skip_tests, manifest_path=None):
rel_path = os.path.relpath(full_path, wpt_root)
path_components = rel_path.split(os.sep)
top_level_subdir = path_components[0]
- if top_level_subdir in skip_tests:
+ if top_level_subdir in skip_dirs:
continue
repo_path = "/" + os.path.relpath(full_path, wpt_root).replace(os.path.sep, "/")
if repo_path in rewrites:
@@ -237,6 +235,9 @@ def affected_testfiles(files_changed, skip_tests, manifest_path=None):
full_path = os.path.join(wpt_root, repo_path[1:].replace("/", os.path.sep))
nontest_changed_paths.add((full_path, repo_path))
+ interface_name = lambda x: os.path.splitext(os.path.basename(x))[0]
+ interfaces_changed_names = map(interface_name, interfaces_changed)
+
def affected_by_wdspec(test):
affected = False
if test in wdspec_test_files:
@@ -252,11 +253,20 @@ def affected_testfiles(files_changed, skip_tests, manifest_path=None):
break
return affected
+ def affected_by_interfaces(file_contents):
+ if len(interfaces_changed_names) > 0:
+ if 'idlharness.js' in file_contents:
+ for interface in interfaces_changed_names:
+ regex = '[\'"]' + interface + '(\\.idl)?[\'"]'
+ if re.search(regex, file_contents):
+ return True
+ return False
+
for root, dirs, fnames in os.walk(wpt_root):
# Walk top_level_subdir looking for test files containing either the
# relative filepath or absolute filepath to the changed files.
if root == wpt_root:
- for dir_name in skip_tests:
+ for dir_name in skip_dirs:
dirs.remove(dir_name)
for fname in fnames:
test_full_path = os.path.join(root, fname)
@@ -277,7 +287,7 @@ def affected_testfiles(files_changed, skip_tests, manifest_path=None):
file_contents = file_contents.decode("utf8", "replace")
for full_path, repo_path in nontest_changed_paths:
rel_path = os.path.relpath(full_path, root).replace(os.path.sep, "/")
- if rel_path in file_contents or repo_path in file_contents:
+ if rel_path in file_contents or repo_path in file_contents or affected_by_interfaces(file_contents):
affected_testfiles.add(test_full_path)
continue
@@ -288,6 +298,8 @@ def get_parser():
parser = argparse.ArgumentParser()
parser.add_argument("revish", default=None, help="Commits to consider. Defaults to the "
"commits on the current branch", nargs="?")
+ # TODO: Consolidate with `./wpt run --affected`:
+ # https://github.com/web-platform-tests/wpt/issues/14560
parser.add_argument("--ignore-rules", nargs="*", type=set,
default=set(["resources/testharness*"]),
help="Rules for paths to exclude from lists of changes. Rules are paths "
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py
index e8edc0be493..fa60230389d 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py
@@ -1,7 +1,6 @@
import logging
import os
import subprocess
-import sys
import tarfile
import zipfile
from io import BytesIO
@@ -39,7 +38,7 @@ def call(*args):
Returns a bytestring of the subprocess output if no error.
"""
- logger.debug("%s" % " ".join(args))
+ logger.debug(" ".join(args))
try:
return subprocess.check_output(args)
except subprocess.CalledProcessError as e:
@@ -49,20 +48,6 @@ def call(*args):
raise
-def get_git_cmd(repo_path):
- """Create a function for invoking git commands as a subprocess."""
- def git(cmd, *args):
- full_cmd = ["git", cmd] + list(args)
- try:
- logger.debug(" ".join(full_cmd))
- return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT).strip()
- except subprocess.CalledProcessError as e:
- logger.error("Git command exited with status %i" % e.returncode)
- logger.error(e.output)
- sys.exit(1)
- return git
-
-
def seekable(fileobj):
"""Attempt to use file.seek on given file, with fallbacks."""
try:
@@ -94,21 +79,6 @@ def unzip(fileobj, dest=None, limit=None):
os.chmod(os.path.join(dest, info.filename), perm)
-class pwd(object):
- """Create context for temporarily changing present working directory."""
- def __init__(self, dir):
- self.dir = dir
- self.old_dir = None
-
- def __enter__(self):
- self.old_dir = os.path.abspath(os.curdir)
- os.chdir(self.dir)
-
- def __exit__(self, *args, **kwargs):
- os.chdir(self.old_dir)
- self.old_dir = None
-
-
def get(url):
"""Issue GET request to a given URL and return the response."""
import requests
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py
index b8454c979c2..0ce7054ae22 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py
@@ -39,7 +39,7 @@ class Virtualenv(object):
def activate(self):
path = os.path.join(self.bin_path, "activate_this.py")
- execfile(path, {"__file__": path})
+ execfile(path, {"__file__": path}) # noqa: F821
def start(self):
if not self.exists:
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
index cb5435fdef4..aadcbb9b5a6 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
@@ -101,7 +101,7 @@ class ConfigBuilder(object):
The properties on the final configuration include those explicitly
supplied and computed properties. The computed properties are
- defined byt the computed_properites attribute on the class. This
+ defined by the computed_properties attribute on the class. This
is a list of property names, each corresponding to a _get_<name>
method on the class. These methods are called in the order defined
in computed_properties and are passed a single argument, a
@@ -126,7 +126,9 @@ class ConfigBuilder(object):
"openssl": {
"openssl_binary": "openssl",
"base_path": "_certs",
+ "password": "web-platform-tests",
"force_regenerate": False,
+ "duration": 30,
"base_conf_path": None
},
"pregenerated": {
@@ -316,7 +318,7 @@ class ConfigBuilder(object):
self._ssl_env.__enter__()
if self._ssl_env.ssl_enabled:
key_path, cert_path = self._ssl_env.host_cert_path(data["domains_set"])
- ca_cert_path = self._ssl_env.ca_cert_path()
+ ca_cert_path = self._ssl_env.ca_cert_path(data["domains_set"])
return {"key_path": key_path,
"ca_cert_path": ca_cert_path,
"cert_path": cert_path,
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/handlers.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/handlers.py
index 7fbe4234ea0..2dd01e29338 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/handlers.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/handlers.py
@@ -7,8 +7,6 @@ import traceback
from six.moves.urllib.parse import parse_qs, quote, unquote, urljoin
from six import iteritems
-from h2.events import RequestReceived, DataReceived
-
from .constants import content_types
from .pipes import Pipeline, template
from .ranges import RangeParser
@@ -79,7 +77,7 @@ class DirectoryHandler(object):
%(items)s
</ul>
""" % {"path": cgi.escape(url_path),
- "items": "\n".join(self.list_items(url_path, path))} # flake8: noqa
+ "items": "\n".join(self.list_items(url_path, path))} # noqa: E122
def list_items(self, base_path, path):
assert base_path.endswith("/")
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py
index cbae6d6fcb9..d1eb7245abd 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py
@@ -329,7 +329,7 @@ def sub(request, response, escape_type="html"):
"html" and "none", with "html" the default for historic reasons.
The format is a very limited template language. Substitutions are
- enclosed by {{ and }}. There are several avaliable substitutions:
+ enclosed by {{ and }}. There are several available substitutions:
host
A simple string value and represents the primary host from which the
@@ -345,6 +345,11 @@ def sub(request, response, escape_type="html"):
includes the leading '?', but other delimiters are omitted.
headers
A dictionary of HTTP headers in the request.
+ header_or_default(header, default)
+ The value of an HTTP header, or a default value if it is absent.
+ For example:
+
+ {{header_or_default(X-Test, test-header-absent)}}
GET
A dictionary of query parameters supplied with the request.
uuid()
@@ -354,6 +359,8 @@ def sub(request, response, escape_type="html"):
sha224, sha256, sha384, and sha512. For example:
{{file_hash(md5, dom/interfaces.html)}}
+ fs_path(filepath)
+ The absolute path to a file inside the wpt document root
So for example in a setup running on localhost with a www
subdomain and a http server on ports 80 and 81::
@@ -414,6 +421,25 @@ class SubFunctions(object):
return base64.b64encode(hash_obj.digest()).strip()
+ @staticmethod
+ def fs_path(request, path):
+ if not path.startswith("/"):
+ subdir = request.request_path[len(request.url_base):]
+ if "/" in subdir:
+ subdir = subdir.rsplit("/", 1)[0]
+ root_rel_path = subdir + "/" + path
+ else:
+ root_rel_path = path[1:]
+ root_rel_path = root_rel_path.replace("/", os.path.sep)
+ absolute_path = os.path.abspath(os.path.join(request.doc_root, root_rel_path))
+ if ".." in os.path.relpath(absolute_path, request.doc_root):
+ raise ValueError("Path outside wpt root")
+ return absolute_path
+
+ @staticmethod
+ def header_or_default(request, name, default):
+ return request.headers.get(name, default)
+
def template(request, content, escape_type="html"):
#TODO: There basically isn't any error handling here
tokenizer = ReplacementTokenizer()
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/request.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/request.py
index 990774cbb9e..aa6306a533e 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/request.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/request.py
@@ -1,7 +1,7 @@
import base64
import cgi
from six.moves.http_cookies import BaseCookie
-from six import BytesIO, binary_type, text_type
+from six import BytesIO, binary_type, text_type, iteritems, PY3
import tempfile
from six.moves.urllib.parse import parse_qsl, urlsplit
@@ -319,9 +319,11 @@ class Request(object):
if self._cookies is None:
parser = BaseCookie()
cookie_headers = self.headers.get("cookie", b"")
+ if PY3:
+ cookie_headers = cookie_headers.decode("iso-8859-1")
parser.load(cookie_headers)
cookies = Cookies()
- for key, value in parser.iteritems():
+ for key, value in iteritems(parser):
cookies[key] = CookieValue(value)
self._cookies = cookies
return self._cookies
@@ -575,7 +577,10 @@ class MultiDict(dict):
:param key: The key to lookup
"""
- return dict.__getitem__(self, key)
+ if key in self:
+ return dict.__getitem__(self, key)
+ else:
+ return []
@classmethod
def from_field_storage(cls, fs):
@@ -619,7 +624,7 @@ class Authentication(object):
header, or None
Both attributes are binary strings (`str` in Py2, `bytes` in Py3), since
- RFC7617 Section 2.1 does not specify the encoding for username & passsword
+ RFC7617 Section 2.1 does not specify the encoding for username & password
(as long it's compatible with ASCII). UTF-8 should be a relatively safe
choice if callers need to decode them as most browsers use it.
"""
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py
index 53f093b8e3d..d57a36b1338 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py
@@ -44,7 +44,7 @@ for parsing the incoming request. A RequestRewriter is then
applied and may change the request data if it matches a
supplied rule.
-Once the request data had been finalised, Request and Reponse
+Once the request data had been finalised, Request and Response
objects are constructed. These are used by the other parts of the
system to read information about the request and manipulate the
response.
@@ -154,7 +154,7 @@ class WebTestServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
port specified in the server_address parameter.
False to bind the server only to the port in the
server_address parameter, but not to the address.
- :param latency: Delay in ms to wait before seving each response, or
+ :param latency: Delay in ms to wait before serving each response, or
callable that returns a delay in ms
"""
self.router = router
@@ -548,7 +548,7 @@ class Http1WebTestRequestHandler(BaseWebTestRequestHandler):
self.close_connection = True
return
- except Exception as e:
+ except Exception:
err = traceback.format_exc()
if response:
response.set_error(500, err)
@@ -591,7 +591,7 @@ class WebTestHttpd(object):
:param config: Dictionary holding environment configuration settings for
handlers to read, or None to use the default values.
:param bind_address: Boolean indicating whether to bind server to IP address.
- :param latency: Delay in ms to wait before seving each response, or
+ :param latency: Delay in ms to wait before serving each response, or
callable that returns a delay in ms
HTTP server designed for testing scenarios.
@@ -621,7 +621,7 @@ class WebTestHttpd(object):
.. attribute:: started
- Boolean indictaing whether the server is running
+ Boolean indicating whether the server is running
"""
def __init__(self, host="127.0.0.1", port=8000,
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/__init__.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/__init__.py
index 6699edb5964..e89bb96f82f 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/__init__.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/__init__.py
@@ -11,4 +11,4 @@ def get_cls(name):
try:
return environments[name]
except KeyError:
- raise ValueError("%s is not a vaid ssl type." % name)
+ raise ValueError("%s is not a valid SSL type." % name)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py
index c95b693f371..63ef45cc869 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py
@@ -13,5 +13,5 @@ class NoSSLEnvironment(object):
def host_cert_path(self, hosts):
return None, None
- def ca_cert_path(self):
+ def ca_cert_path(self, hosts):
return None
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py
index ebbcf68d716..db188dad70a 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py
@@ -114,16 +114,18 @@ def make_subject(common_name,
return "".join(rv)
def make_alt_names(hosts):
- rv = []
- for name in hosts:
- rv.append("DNS:%s" % name)
- return ",".join(rv)
+ return ",".join("DNS:%s" % host for host in hosts)
+
+def make_name_constraints(hosts):
+ return ",".join("permitted;DNS:%s" % host for host in hosts)
def get_config(root_dir, hosts, duration=30):
if hosts is None:
san_line = ""
+ constraints_line = ""
else:
san_line = "subjectAltName = %s" % make_alt_names(hosts)
+ constraints_line = "nameConstraints = " + make_name_constraints(hosts)
if os.path.sep == "\\":
# This seems to be needed for the Shining Light OpenSSL on
@@ -213,9 +215,11 @@ basicConstraints = CA:true
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
keyUsage = keyCertSign
+%(constraints_line)s
""" % {"root_dir": root_dir,
"san_line": san_line,
"duration": duration,
+ "constraints_line": constraints_line,
"sep": os.path.sep.replace("\\", "\\\\")}
return rv
@@ -287,13 +291,13 @@ class OpenSSLEnvironment(object):
return OpenSSL(self.logger, self.binary, self.base_path, conf_path, hosts,
self.duration, self.base_conf_path)
- def ca_cert_path(self):
+ def ca_cert_path(self, hosts):
"""Get the path to the CA certificate file, generating a
new one if needed"""
if self._ca_cert_path is None and not self.force_regenerate:
self._load_ca_cert()
if self._ca_cert_path is None:
- self._generate_ca()
+ self._generate_ca(hosts)
return self._ca_cert_path
def _load_ca_cert(self):
@@ -326,7 +330,7 @@ class OpenSSLEnvironment(object):
#TODO: check the key actually signed the cert.
return True
- def _generate_ca(self):
+ def _generate_ca(self, hosts):
path = self.path
self.logger.info("Generating new CA in %s" % self.base_path)
@@ -334,7 +338,7 @@ class OpenSSLEnvironment(object):
req_path = path("careq.pem")
cert_path = path("cacert.pem")
- with self._config_openssl(None) as openssl:
+ with self._config_openssl(hosts) as openssl:
openssl("req",
"-batch",
"-new",
@@ -391,7 +395,7 @@ class OpenSSLEnvironment(object):
def _generate_host_cert(self, hosts):
host = hosts[0]
if self._ca_key_path is None:
- self._generate_ca()
+ self._generate_ca(hosts)
ca_key_path = self._ca_key_path
assert os.path.exists(ca_key_path)
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py
index fc487df3add..672a10635ed 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py
@@ -20,7 +20,7 @@ class PregeneratedSSLEnvironment(object):
"""Return the key and certificate paths for the host"""
return self._host_key_path, self._host_cert_path
- def ca_cert_path(self):
+ def ca_cert_path(self, hosts):
"""Return the certificate path of the CA that signed the
host certificates, or None if that isn't known"""
return self._ca_cert_path
diff --git a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py
index ae48a861123..8b6fd34f02c 100644
--- a/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py
+++ b/chromium/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py
@@ -6,23 +6,29 @@ import threading
from multiprocessing.managers import AcquirerProxy, BaseManager, DictProxy
from six import text_type
+
class ServerDictManager(BaseManager):
shared_data = {}
+
def _get_shared():
return ServerDictManager.shared_data
+
ServerDictManager.register("get_dict",
callable=_get_shared,
proxytype=DictProxy)
ServerDictManager.register('Lock', threading.Lock, AcquirerProxy)
+
class ClientDictManager(BaseManager):
pass
+
ClientDictManager.register("get_dict")
ClientDictManager.register("Lock")
+
class StashServer(object):
def __init__(self, address=None, authkey=None):
self.address = address
@@ -37,6 +43,7 @@ class StashServer(object):
if self.manager is not None:
self.manager.shutdown()
+
def load_env_config():
address, authkey = json.loads(os.environ["WPT_STASH_CONFIG"])
if isinstance(address, list):
@@ -46,10 +53,12 @@ def load_env_config():
authkey = base64.b64decode(authkey)
return address, authkey
+
def store_env_config(address, authkey):
authkey = base64.b64encode(authkey)
os.environ["WPT_STASH_CONFIG"] = json.dumps((address, authkey.decode("ascii")))
+
def start_server(address=None, authkey=None):
if isinstance(authkey, text_type):
authkey = authkey.encode("ascii")
@@ -75,6 +84,7 @@ class LockWrapper(object):
def __exit__(self, *args, **kwargs):
self.release()
+
#TODO: Consider expiring values after some fixed time for long-running
#servers
@@ -104,6 +114,7 @@ class Stash(object):
_proxy = None
lock = None
+ _initializing = threading.Lock()
def __init__(self, default_path, address=None, authkey=None):
self.default_path = default_path
@@ -115,7 +126,16 @@ class Stash(object):
Stash._proxy = {}
Stash.lock = threading.Lock()
- if Stash._proxy is None:
+ # Initializing the proxy involves connecting to the remote process and
+ # retrieving two proxied objects. This process is not inherently
+ # atomic, so a lock must be used to make it so. Atomicity ensures that
+ # only one thread attempts to initialize the connection and that any
+ # threads running in parallel correctly wait for initialization to be
+ # fully complete.
+ with Stash._initializing:
+ if Stash.lock:
+ return
+
manager = ClientDictManager(address, authkey)
manager.connect()
Stash._proxy = manager.get_dict()
@@ -163,5 +183,6 @@ class Stash(object):
return value
+
class StashError(Exception):
pass
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/analyze_baselines_unittest.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/analyze_baselines_unittest.py
index e4f87d47ea4..08c0b3f9730 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/analyze_baselines_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/analyze_baselines_unittest.py
@@ -13,7 +13,7 @@ class _FakeOptimizer(BaselineOptimizer):
def read_results_by_directory(self, baseline_name):
if baseline_name.endswith('txt'):
- return {'LayoutTests/passes/text.html': '123456'}
+ return {'web_tests/passes/text.html': '123456'}
return {}
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py
index 67ab390297c..2d14329730a 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py
@@ -21,9 +21,9 @@ class TestCopyExistingBaselines(BaseTestCase):
options_dict.update(kwargs)
return optparse.Values(options_dict)
- def baseline_path(self, path_from_layout_test_dir):
+ def baseline_path(self, path_from_web_test_dir):
port = self.tool.port_factory.get()
- return self.tool.filesystem.join(port.layout_tests_dir(), path_from_layout_test_dir)
+ return self.tool.filesystem.join(port.web_tests_dir(), path_from_web_test_dir)
# The tests in this class all depend on the fall-back path graph
# that is set up in |TestPort.FALLBACK_PATHS|.
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/flaky_tests.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/flaky_tests.py
index b4230ca198c..80b0cf5d0bf 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/flaky_tests.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/flaky_tests.py
@@ -116,7 +116,7 @@ class FlakyTests(Command):
port = tool.port_factory.get()
# Skip any tests which are mentioned in the dashboard but not in our checkout:
fs = tool.filesystem
- lines = [line for line in lines if fs.exists(fs.join(port.layout_tests_dir(), line.path))]
+ lines = [line for line in lines if fs.exists(fs.join(port.web_tests_dir(), line.path))]
test_names = [line.name for line in lines]
flakiness_dashboard_url = self.FLAKINESS_DASHBOARD_URL % ','.join(test_names)
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/optimize_baselines_unittest.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/optimize_baselines_unittest.py
index 821ff40d684..6ddde1f73b1 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/optimize_baselines_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/optimize_baselines_unittest.py
@@ -12,7 +12,7 @@ class TestOptimizeBaselines(BaseTestCase):
command_constructor = OptimizeBaselines
def _write_test_file(self, port, path, contents):
- abs_path = self.tool.filesystem.join(port.layout_tests_dir(), path)
+ abs_path = self.tool.filesystem.join(port.web_tests_dir(), path)
self.tool.filesystem.write_text_file(abs_path, contents)
def setUp(self):
@@ -33,13 +33,13 @@ class TestOptimizeBaselines(BaseTestCase):
self.assertFalse(
self.tool.filesystem.exists(self.tool.filesystem.join(
- test_port.layout_tests_dir(), 'platform/mac/another/test-expected.txt')))
+ test_port.web_tests_dir(), 'platform/mac/another/test-expected.txt')))
self.assertFalse(
self.tool.filesystem.exists(self.tool.filesystem.join(
- test_port.layout_tests_dir(), 'platform/mac/another/test-expected.png')))
+ test_port.web_tests_dir(), 'platform/mac/another/test-expected.png')))
self.assertTrue(
self.tool.filesystem.exists(self.tool.filesystem.join(
- test_port.layout_tests_dir(), 'another/test-expected.txt')))
+ test_port.web_tests_dir(), 'another/test-expected.txt')))
self.assertTrue(
self.tool.filesystem.exists(self.tool.filesystem.join(
- test_port.layout_tests_dir(), 'another/test-expected.png')))
+ test_port.web_tests_dir(), 'another/test-expected.png')))
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/queries.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/queries.py
index dacafd20fc1..9b144368d49 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/queries.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/queries.py
@@ -105,10 +105,10 @@ class PrintExpectations(Command):
if options.paths:
files = default_port.expectations_files()
- layout_tests_dir = default_port.layout_tests_dir()
+ web_tests_dir = default_port.web_tests_dir()
for file in files:
- if file.startswith(layout_tests_dir):
- file = file.replace(layout_tests_dir, WEB_TESTS_LAST_COMPONENT)
+ if file.startswith(web_tests_dir):
+ file = file.replace(web_tests_dir, WEB_TESTS_LAST_COMPONENT)
print file
return
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
index d84d6944f03..f28b7f2b266 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
@@ -412,8 +412,8 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand):
test_baseline_set: A TestBaselineSet instance, which represents
a set of tests/platform combinations to rebaseline.
"""
- if self._tool.git().has_working_directory_changes(pathspec=self._layout_tests_dir()):
- _log.error('There are uncommitted changes in the layout tests directory; aborting.')
+ if self._tool.git().has_working_directory_changes(pathspec=self._web_tests_dir()):
+ _log.error('There are uncommitted changes in the web tests directory; aborting.')
return
for test in sorted({t for t, _, _ in test_baseline_set}):
@@ -458,12 +458,12 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand):
baseline_paths = []
for test in test_baseline_set.all_tests():
filenames = [self._file_name_for_expected_result(test, suffix) for suffix in BASELINE_SUFFIX_LIST]
- baseline_paths += [filesystem.join(self._layout_tests_dir(), filename) for filename in filenames]
+ baseline_paths += [filesystem.join(self._web_tests_dir(), filename) for filename in filenames]
baseline_paths.sort()
return baseline_paths
- def _layout_tests_dir(self):
- return self._tool.port_factory.get().layout_tests_dir()
+ def _web_tests_dir(self):
+ return self._tool.port_factory.get().web_tests_dir()
def _suffixes_for_actual_failures(self, test, build):
"""Gets the baseline suffixes for actual mismatch failures in some results.
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
index 0f03959ed69..fa240388cd7 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
@@ -21,7 +21,7 @@ _log = logging.getLogger(__name__)
class RebaselineCL(AbstractParallelRebaselineCommand):
name = 'rebaseline-cl'
help_text = 'Fetches new baselines for a CL from test runs on try bots.'
- long_help = ('This command downloads new baselines for failing layout '
+ long_help = ('This command downloads new baselines for failing web '
'tests from archived try job test results. Cross-platform '
'baselines are deduplicated after downloading. Without '
'positional parameters or --test-name-file, all failing tests '
@@ -222,7 +222,7 @@ class RebaselineCL(AbstractParallelRebaselineCommand):
jobs: A dict mapping Build objects to TryJobStatus objects.
Returns:
- A dict mapping Build to LayoutTestResults for all completed jobs.
+ A dict mapping Build to WebTestResults for all completed jobs.
"""
buildbot = self._tool.buildbot
results = {}
@@ -234,15 +234,15 @@ class RebaselineCL(AbstractParallelRebaselineCommand):
continue
if status != TryJobStatus('COMPLETED', 'FAILURE'):
# Only completed failed builds will contain actual failed
- # layout tests to download baselines for.
+ # web tests to download baselines for.
continue
results_url = buildbot.results_url(build.builder_name, build.build_number)
- layout_test_results = buildbot.fetch_results(build)
- if layout_test_results is None:
+ web_test_results = buildbot.fetch_results(build)
+ if web_test_results is None:
_log.info('Failed to fetch results for "%s".', build.builder_name)
_log.info('Results URL: %s/results.html', results_url)
continue
- results[build] = layout_test_results
+ results[build] = web_test_results
return results
def _make_test_baseline_set_from_file(self, filename, builds_to_results):
@@ -266,7 +266,7 @@ class RebaselineCL(AbstractParallelRebaselineCommand):
Args:
tests: A list of tests.
- builds_to_results: A dict mapping Builds to LayoutTestResults.
+ builds_to_results: A dict mapping Builds to WebTestResults.
Returns:
A TestBaselineSet object.
@@ -284,7 +284,7 @@ class RebaselineCL(AbstractParallelRebaselineCommand):
modified tests will be rebaselined (depending on only_changed_tests).
Args:
- builds_to_results: A dict mapping Builds to LayoutTestResults.
+ builds_to_results: A dict mapping Builds to WebTestResults.
only_changed_tests: Whether to only include baselines for tests that
are changed in this CL. If False, all new baselines for failing
tests will be downloaded, even for tests that were not modified.
@@ -311,26 +311,26 @@ class RebaselineCL(AbstractParallelRebaselineCommand):
return test_baseline_set
def _test_base_path(self):
- """Returns the relative path from the repo root to the layout tests."""
+ """Returns the relative path from the repo root to the web tests."""
finder = PathFinder(self._tool.filesystem)
return self._tool.filesystem.relpath(
- finder.layout_tests_dir(),
+ finder.web_tests_dir(),
finder.path_from_chromium_base()) + '/'
- def _tests_to_rebaseline(self, build, layout_test_results):
+ def _tests_to_rebaseline(self, build, web_test_results):
"""Fetches a list of tests that should be rebaselined for some build.
Args:
build: A Build instance.
- layout_test_results: A LayoutTestResults instance or None.
+ web_test_results: A WebTestResults instance or None.
Returns:
A sorted list of tests to rebaseline for this build.
"""
- if layout_test_results is None:
+ if web_test_results is None:
return []
- unexpected_results = layout_test_results.didnt_run_as_expected_results()
+ unexpected_results = web_test_results.didnt_run_as_expected_results()
tests = sorted(
r.test_name() for r in unexpected_results
if r.is_missing_baseline() or r.has_mismatch_result())
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
index ba88c33a287..5546cc75ac3 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
@@ -10,7 +10,7 @@ from blinkpy.common.checkout.git_mock import MockGit
from blinkpy.common.net.buildbot import Build
from blinkpy.common.net.git_cl import TryJobStatus
from blinkpy.common.net.git_cl_mock import MockGitCL
-from blinkpy.common.net.layout_test_results import LayoutTestResults
+from blinkpy.common.net.web_test_results import WebTestResults
from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
from blinkpy.common.system.log_testing import LoggingTestCase
from blinkpy.tool.commands.rebaseline import TestBaselineSet
@@ -59,7 +59,7 @@ class RebaselineCLTest(BaseTestCase, LoggingTestCase):
'is_try_builder': True,
},
})
- layout_test_results = LayoutTestResults({
+ web_test_results = WebTestResults({
'tests': {
'one': {
'crash.html': {'expected': 'PASS', 'actual': 'CRASH', 'is_unexpected': True},
@@ -75,7 +75,7 @@ class RebaselineCLTest(BaseTestCase, LoggingTestCase):
})
for build in builds:
- self.tool.buildbot.set_results(build, layout_test_results)
+ self.tool.buildbot.set_results(build, web_test_results)
self.tool.buildbot.set_retry_sumary_json(build, json.dumps({
'failures': [
'one/flaky-fail.html',
@@ -97,11 +97,11 @@ class RebaselineCLTest(BaseTestCase, LoggingTestCase):
]
for test in tests:
path = self.mac_port.host.filesystem.join(
- self.mac_port.layout_tests_dir(), test)
+ self.mac_port.web_tests_dir(), test)
self._write(path, 'contents')
self.mac_port.host.filesystem.write_text_file(
- '/test.checkout/LayoutTests/external/wpt/MANIFEST.json', '{}')
+ '/test.checkout/web_tests/external/wpt/MANIFEST.json', '{}')
def tearDown(self):
BaseTestCase.tearDown(self)
@@ -358,7 +358,7 @@ class RebaselineCLTest(BaseTestCase, LoggingTestCase):
# one/flaky-fail.html is considered a real test to rebaseline.
port = self.tool.port_factory.get('test-win-win7')
path = port.host.filesystem.join(
- port.layout_tests_dir(), 'one/flaky-fail.html')
+ port.web_tests_dir(), 'one/flaky-fail.html')
self._write(path, 'contents')
test_baseline_set = TestBaselineSet(self.tool)
test_baseline_set.add(
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py
index 621e833f565..fad77cda9e2 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py
@@ -26,13 +26,13 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Starts a local HTTP server which displays layout test failures (given a test
+"""Starts a local HTTP server which displays web test failures (given a test
results directory), provides comparisons of expected and actual results (both
images and text) and allows one-click rebaselining of tests.
"""
from blinkpy.common.host import Host
-from blinkpy.common.net.layout_test_results import LayoutTestResults
+from blinkpy.common.net.web_test_results import WebTestResults
from blinkpy.web_tests.layout_package import json_results_generator
from blinkpy.tool.commands.abstract_local_server_command import AbstractLocalServerCommand
from blinkpy.tool.servers.rebaseline_server import get_test_baselines, RebaselineHTTPServer, STATE_NEEDS_REBASELINE
@@ -40,9 +40,9 @@ from blinkpy.tool.servers.rebaseline_server import get_test_baselines, Rebaselin
class TestConfig(object):
- def __init__(self, test_port, layout_tests_directory, results_directory, platforms, host):
+ def __init__(self, test_port, web_tests_directory, results_directory, platforms, host):
self.test_port = test_port
- self.layout_tests_directory = layout_tests_directory
+ self.web_tests_directory = web_tests_directory
self.results_directory = results_directory
self.platforms = platforms
self.host = host
@@ -76,7 +76,7 @@ class RebaselineServer(AbstractLocalServerCommand):
result_dict['baselines'] = get_test_baselines(result.test_name(), self._test_config)
new_tests_subtree[result.test_name()] = result_dict
- LayoutTestResults(results_json).for_each_test(gather_baselines_for_test)
+ WebTestResults(results_json).for_each_test(gather_baselines_for_test)
results_json['tests'] = new_tests_subtree
def _prepare_config(self, options, args, tool):
@@ -88,9 +88,9 @@ class RebaselineServer(AbstractLocalServerCommand):
results_json = json_results_generator.load_json(host.filesystem, results_json_path)
port = tool.port_factory.get()
- layout_tests_directory = port.layout_tests_dir()
- platforms = host.filesystem.listdir(host.filesystem.join(layout_tests_directory, 'platform'))
- self._test_config = TestConfig(port, layout_tests_directory, results_directory, platforms, host)
+ web_tests_directory = port.web_tests_dir()
+ platforms = host.filesystem.listdir(host.filesystem.join(web_tests_directory, 'platform'))
+ self._test_config = TestConfig(port, web_tests_directory, results_directory, platforms, host)
print 'Gathering current baselines...'
self._gather_baselines(results_json)
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test_unittest.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test_unittest.py
index 4e43e313989..7bc85ca9ec1 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test_unittest.py
@@ -30,7 +30,7 @@ class TestRebaselineTest(BaseTestCase):
port = self.tool.port_factory.get('test-win-win7')
baseline_relative_path = 'platform/test-win-win10/failures/expected/image-expected.txt'
- baseline_local_absolute_path = port.host.filesystem.join(port.layout_tests_dir(), baseline_relative_path)
+ baseline_local_absolute_path = port.host.filesystem.join(port.web_tests_dir(), baseline_relative_path)
self._write(baseline_local_absolute_path, 'original win10 result')
actual_result_url = ('https://test-results.appspot.com/data/layout_results/MOCK_Win10/' +
'results/layout-test-results/failures/expected/image-actual.txt')
@@ -58,7 +58,7 @@ class TestRebaselineTest(BaseTestCase):
self.assertMultiLineEqual(self._read(baseline_local_absolute_path),
'new win10 result')
self.assertFalse(self.tool.filesystem.exists(self.tool.filesystem.join(
- port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt')))
+ port.web_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt')))
self.assertMultiLineEqual(
out, '{"remove-lines": [{"test": "failures/expected/image.html", "port_name": "test-win-win10"}]}\n')
diff --git a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
index 91e779b0a72..6ad5402efb9 100644
--- a/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
@@ -7,7 +7,7 @@ import optparse
import unittest
from blinkpy.common.net.buildbot import Build
-from blinkpy.common.net.layout_test_results import LayoutTestResults
+from blinkpy.common.net.web_test_results import WebTestResults
from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
from blinkpy.common.system.executive_mock import MockExecutive
from blinkpy.tool.commands.rebaseline import (
@@ -53,7 +53,7 @@ class BaseTestCase(unittest.TestCase):
# In AbstractParallelRebaselineCommand._rebaseline_commands, a default port
# object is gotten using self.tool.port_factory.get(), which is used to get
- # test paths -- and the layout tests directory may be different for the "test"
+ # test paths -- and the web tests directory may be different for the "test"
# ports and real ports. Since only "test" ports are used in this class,
# we can make the default port also a "test" port.
self.original_port_factory_get = self.tool.port_factory.get
@@ -72,7 +72,7 @@ class BaseTestCase(unittest.TestCase):
def _expand(self, path):
if self.tool.filesystem.isabs(path):
return path
- return self.tool.filesystem.join(self.mac_port.layout_tests_dir(), path)
+ return self.tool.filesystem.join(self.mac_port.web_tests_dir(), path)
def _read(self, path):
return self.tool.filesystem.read_text_file(self._expand(path))
@@ -89,7 +89,7 @@ class BaseTestCase(unittest.TestCase):
def _setup_mock_build_data(self):
for builder in ['MOCK Win7', 'MOCK Win7 (dbg)', 'MOCK Mac10.11']:
- self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
+ self.tool.buildbot.set_results(Build(builder), WebTestResults({
'tests': {
'userscripts': {
'first-test.html': {
@@ -178,7 +178,7 @@ class TestRebaseline(BaseTestCase):
}, **kwargs))
def test_rebaseline_test_passes_on_all_builders(self):
- self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
+ self.tool.buildbot.set_results(Build('MOCK Win7'), WebTestResults({
'tests': {
'userscripts': {
'first-test.html': {
@@ -467,7 +467,7 @@ class TestRebaselineUpdatesExpectationsFiles(BaseTestCase):
('Bug(x) [ Mac ] userscripts/skipped-test.html [ WontFix ]\n'
'Bug(y) [ Win ] userscripts/skipped-test.html [ Skip ]\n'))
self._write('userscripts/skipped-test.html', 'Dummy test contents')
- self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
+ self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({
'tests': {
'userscripts': {
'skipped-test.html': {
@@ -477,7 +477,7 @@ class TestRebaselineUpdatesExpectationsFiles(BaseTestCase):
}
}
}))
- self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
+ self.tool.buildbot.set_results(Build('MOCK Win7'), WebTestResults({
'tests': {
'userscripts': {
'skipped-test.html': {
@@ -504,7 +504,7 @@ class TestRebaselineUpdatesExpectationsFiles(BaseTestCase):
# Flaky expectations should be kept even if the test passes.
self._write(self.test_expectations_path, 'Bug(x) userscripts/flaky-test.html [ Pass Failure ]\n')
self._write('userscripts/flaky-test.html', 'Dummy test contents')
- self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
+ self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({
'tests': {
'userscripts': {
'flaky-test.html': {
@@ -530,7 +530,7 @@ class TestRebaselineUpdatesExpectationsFiles(BaseTestCase):
self._write(self.test_expectations_path, 'Bug(foo) userscripts/all-pass.html [ Failure ]\n')
self._write('userscripts/all-pass.html', 'Dummy test contents')
test_baseline_set = TestBaselineSet(self.tool)
- self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
+ self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({
'tests': {
'userscripts': {
'all-pass.html': {
@@ -557,7 +557,7 @@ class TestRebaselineUpdatesExpectationsFiles(BaseTestCase):
self._write('userscripts/all-pass.html', 'Dummy test contents')
test_baseline_set = TestBaselineSet(self.tool)
for builder in ['MOCK Win7', 'MOCK Win10', 'MOCK Mac10.10', 'MOCK Mac10.11', 'MOCK Precise', 'MOCK Trusty']:
- self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
+ self.tool.buildbot.set_results(Build(builder), WebTestResults({
'tests': {
'userscripts': {
'all-pass.html': {
@@ -584,7 +584,7 @@ class TestRebaselineUpdatesExpectationsFiles(BaseTestCase):
self._write(self.test_expectations_path, 'Bug(foo) userscripts/all-pass.html [ Failure ]\n')
self._write('userscripts/all-pass.html', 'Dummy test contents')
test_baseline_set = TestBaselineSet(self.tool)
- self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
+ self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({
'tests': {
'userscripts': {
'all-pass.html': {
@@ -702,7 +702,7 @@ class TestBaselineSetTest(unittest.TestCase):
host = MockBlinkTool()
host.port_factory = MockPortFactory(host)
port = host.port_factory.get()
- base_dir = port.layout_tests_dir()
+ base_dir = port.web_tests_dir()
host.filesystem.write_text_file(base_dir + '/a/x.html', '<html>')
host.filesystem.write_text_file(base_dir + '/a/y.html', '<html>')
host.filesystem.write_text_file(base_dir + '/a/z.html', '<html>')
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/chromium_commit_mock.py b/chromium/third_party/blink/tools/blinkpy/w3c/chromium_commit_mock.py
index e9ee0ddd4a1..3d7c7c4743f 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/chromium_commit_mock.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/chromium_commit_mock.py
@@ -29,8 +29,8 @@ class MockChromiumCommit(object):
def filtered_changed_files(self):
return [
- 'third_party/WebKit/LayoutTests/external/wpt/one.html',
- 'third_party/WebKit/LayoutTests/external/wpt/two.html',
+ 'third_party/blink/web_tests/external/wpt/one.html',
+ 'third_party/blink/web_tests/external/wpt/two.html',
]
def url(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/chromium_finder.py b/chromium/third_party/blink/tools/blinkpy/w3c/chromium_finder.py
index 72e4e417b43..a9665d620f4 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/chromium_finder.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/chromium_finder.py
@@ -9,7 +9,7 @@ from blinkpy.common.path_finder import PathFinder
@memoized
def absolute_chromium_wpt_dir(host):
finder = PathFinder(host.filesystem)
- return finder.path_from_layout_tests('external', 'wpt')
+ return finder.path_from_web_tests('external', 'wpt')
@memoized
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor.py b/chromium/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor.py
index 0e57805fd62..e7b126413ec 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor.py
@@ -43,10 +43,10 @@ class DirectoryOwnersExtractor(object):
Returns:
A dict mapping tuples of owner email addresses to lists of
- owned directories (paths relative to the root of layout tests).
+ owned directories (paths relative to the root of web tests).
"""
email_map = collections.defaultdict(set)
- external_root_owners = self.finder.path_from_layout_tests('external', 'OWNERS')
+ external_root_owners = self.finder.path_from_web_tests('external', 'OWNERS')
for relpath in changed_files:
# Try to find the first *non-empty* OWNERS file.
absolute_path = self.finder.path_from_chromium_base(relpath)
@@ -64,7 +64,7 @@ class DirectoryOwnersExtractor(object):
continue
owned_directory = self.filesystem.dirname(owners_file)
- owned_directory_relpath = self.filesystem.relpath(owned_directory, self.finder.layout_tests_dir())
+ owned_directory_relpath = self.filesystem.relpath(owned_directory, self.finder.web_tests_dir())
email_map[tuple(owners)].add(owned_directory_relpath)
return {owners: sorted(owned_directories) for owners, owned_directories in email_map.iteritems()}
@@ -86,11 +86,11 @@ class DirectoryOwnersExtractor(object):
else self.finder.path_from_chromium_base(start_path))
directory = (abs_start_path if self.filesystem.isdir(abs_start_path)
else self.filesystem.dirname(abs_start_path))
- external_root = self.finder.path_from_layout_tests('external')
+ external_root = self.finder.path_from_web_tests('external')
if not directory.startswith(external_root):
return None
# Stop at web_tests, which is the parent of external_root.
- while directory != self.finder.layout_tests_dir():
+ while directory != self.finder.web_tests_dir():
owners_file = self.filesystem.join(directory, 'OWNERS')
if self.filesystem.isfile(self.finder.path_from_chromium_base(owners_file)):
return owners_file
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/import_notifier.py b/chromium/third_party/blink/tools/blinkpy/w3c/import_notifier.py
index 37b7bfd5111..11e405a9d7f 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/import_notifier.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/import_notifier.py
@@ -88,7 +88,7 @@ class ImportNotifier(object):
for test_name in rebaselined_tests:
test_without_ext, _ = self.host.filesystem.splitext(test_name)
changed_baselines = []
- # TODO(robertma): Refactor this into layout_tests.port.base.
+ # TODO(robertma): Refactor this into web_tests.port.base.
baseline_name = test_without_ext + '-expected.txt'
for changed_file in changed_files:
if changed_file.endswith(baseline_name):
@@ -165,7 +165,7 @@ class ImportNotifier(object):
for directory, failures in self.new_failures_by_directory.iteritems():
summary = '[WPT] New failures introduced in {} by import {}'.format(directory, gerrit_url)
- full_directory = self.host.filesystem.join(self.finder.layout_tests_dir(), directory)
+ full_directory = self.host.filesystem.join(self.finder.web_tests_dir(), directory)
owners_file = self.host.filesystem.join(full_directory, 'OWNERS')
is_wpt_notify_enabled = self.owners_extractor.is_wpt_notify_enabled(owners_file)
@@ -214,7 +214,7 @@ class ImportNotifier(object):
A multi-line string.
"""
path_from_wpt = self.host.filesystem.relpath(
- directory, self.finder.path_from_layout_tests('external', 'wpt'))
+ directory, self.finder.path_from_web_tests('external', 'wpt'))
commit_list = ''
for sha, subject in imported_commits:
# subject is a Unicode string and can contain non-ASCII characters.
@@ -238,12 +238,12 @@ class ImportNotifier(object):
test_name = self.default_port.lookup_virtual_test_base(test_name)
# find_owners_file takes either a relative path from the *root* of the
# repository, or an absolute path.
- abs_test_path = self.finder.path_from_layout_tests(test_name)
+ abs_test_path = self.finder.path_from_web_tests(test_name)
owners_file = self.owners_extractor.find_owners_file(self.host.filesystem.dirname(abs_test_path))
if not owners_file:
return None
owned_directory = self.host.filesystem.dirname(owners_file)
- short_directory = self.host.filesystem.relpath(owned_directory, self.finder.layout_tests_dir())
+ short_directory = self.host.filesystem.relpath(owned_directory, self.finder.web_tests_dir())
return short_directory
def file_bugs(self, bugs, dry_run, service_account_key_json=None):
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/test_copier.py b/chromium/third_party/blink/tools/blinkpy/w3c/test_copier.py
index 2ce4ab93401..2aa9013df2a 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/test_copier.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/test_copier.py
@@ -39,7 +39,7 @@ from blinkpy.w3c.common import is_basename_skipped
_log = logging.getLogger(__name__)
-# Directory for imported tests relative to the layout tests base directory.
+# Directory for imported tests relative to the web tests base directory.
DEST_DIR_NAME = 'external'
class TestCopier(object):
@@ -58,10 +58,10 @@ class TestCopier(object):
self.filesystem = self.host.filesystem
self.path_finder = PathFinder(self.filesystem)
- self.layout_tests_dir = self.path_finder.layout_tests_dir()
+ self.web_tests_dir = self.path_finder.web_tests_dir()
self.destination_directory = self.filesystem.normpath(
self.filesystem.join(
- self.layout_tests_dir,
+ self.web_tests_dir,
DEST_DIR_NAME,
self.filesystem.basename(self.source_repo_path)))
self.import_in_place = (self.source_repo_path == self.destination_directory)
@@ -112,7 +112,7 @@ class TestCopier(object):
for filename in files:
path_full = self.filesystem.join(root, filename)
path_base = path_full.replace(self.source_repo_path + '/', '')
- path_base = self.destination_directory.replace(self.layout_tests_dir + '/', '') + '/' + path_base
+ path_base = self.destination_directory.replace(self.web_tests_dir + '/', '') + '/' + path_base
if path_base in paths_to_skip:
if self.import_in_place:
_log.debug('Pruning: %s', path_base)
@@ -136,7 +136,7 @@ class TestCopier(object):
def find_paths_to_skip(self):
paths_to_skip = set()
port = self.host.port_factory.get()
- w3c_import_expectations_path = self.path_finder.path_from_layout_tests('W3CImportExpectations')
+ w3c_import_expectations_path = self.path_finder.path_from_web_tests('W3CImportExpectations')
w3c_import_expectations = self.filesystem.read_text_file(w3c_import_expectations_path)
parser = TestExpectationParser(port, all_tests=(), is_lint_mode=False)
expectation_lines = parser.parse(w3c_import_expectations_path, w3c_import_expectations)
@@ -201,7 +201,7 @@ class TestCopier(object):
if not self.import_in_place:
self.filesystem.maybe_make_directory(self.filesystem.dirname(dest_path))
- relpath = self.filesystem.relpath(dest_path, self.layout_tests_dir)
+ relpath = self.filesystem.relpath(dest_path, self.web_tests_dir)
# FIXME: Maybe doing a file diff is in order here for existing files?
# In other words, there's no sense in overwriting identical files, but
# there's no harm in copying the identical thing.
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/test_importer.py b/chromium/third_party/blink/tools/blinkpy/w3c/test_importer.py
index 788c5da4617..74c094ffa81 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/test_importer.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -39,7 +39,7 @@ POLL_DELAY_SECONDS = 2 * 60
TIMEOUT_SECONDS = 210 * 60
# Sheriff calendar URL, used for getting the ecosystem infra sheriff to TBR.
-ROTATIONS_URL = 'https://build.chromium.org/deprecated/chromium/all_rotations.js'
+ROTATIONS_URL = 'https://rota-ng.appspot.com/legacy/all_rotations.js'
TBR_FALLBACK = 'robertma'
_log = logging.getLogger(__file__)
@@ -55,7 +55,7 @@ class TestImporter(object):
self.fs = host.filesystem
self.finder = PathFinder(self.fs)
self.chromium_git = self.host.git(self.finder.chromium_base())
- self.dest_path = self.finder.path_from_layout_tests('external', 'wpt')
+ self.dest_path = self.finder.path_from_web_tests('external', 'wpt')
# A common.net.git_cl.GitCL instance.
self.git_cl = None
@@ -389,7 +389,7 @@ class TestImporter(object):
is_file_exportable(fs.relpath(fs.join(dirname, basename), self.finder.chromium_base())))
files_to_delete = self.fs.files_under(self.dest_path, file_filter=should_remove)
for subpath in files_to_delete:
- self.remove(self.finder.path_from_layout_tests('external', subpath))
+ self.remove(self.finder.path_from_web_tests('external', subpath))
def _commit_changes(self, commit_message):
_log.info('Committing changes.')
@@ -423,7 +423,7 @@ class TestImporter(object):
# - the manifest path could be factored out to a common location, and
# - the logic for reading the manifest could be factored out from here
# and the Port class.
- manifest_path = self.finder.path_from_layout_tests('external', 'wpt', 'MANIFEST.json')
+ manifest_path = self.finder.path_from_web_tests('external', 'wpt', 'MANIFEST.json')
manifest = WPTManifest(self.fs.read_text_file(manifest_path))
wpt_urls = manifest.all_urls()
@@ -433,7 +433,7 @@ class TestImporter(object):
# TODO(qyearsley): Remove this when this behavior is fixed.
wpt_urls = [url.split('?')[0] for url in wpt_urls]
- wpt_dir = self.finder.path_from_layout_tests('external', 'wpt')
+ wpt_dir = self.finder.path_from_web_tests('external', 'wpt')
for full_path in baselines:
rel_path = self.fs.relpath(full_path, wpt_dir)
if not self._has_corresponding_test(rel_path, wpt_urls):
@@ -608,12 +608,12 @@ class TestImporter(object):
self.host.filesystem.write_text_file(path, new_file_contents)
def _list_deleted_tests(self):
- """List of layout tests that have been deleted."""
+ """List of web tests that have been deleted."""
# TODO(robertma): Improve Git.changed_files so that we can use it here.
out = self.chromium_git.run(['diff', 'origin/master', '-M100%', '--diff-filter=D', '--name-only'])
deleted_tests = []
for path in out.splitlines():
- test = self._relative_to_layout_test_dir(path)
+ test = self._relative_to_web_test_dir(path)
if test:
deleted_tests.append(test)
return deleted_tests
@@ -627,18 +627,18 @@ class TestImporter(object):
renamed_tests = {}
for line in out.splitlines():
_, source_path, dest_path = line.split()
- source_test = self._relative_to_layout_test_dir(source_path)
- dest_test = self._relative_to_layout_test_dir(dest_path)
+ source_test = self._relative_to_web_test_dir(source_path)
+ dest_test = self._relative_to_web_test_dir(dest_path)
if source_test and dest_test:
renamed_tests[source_test] = dest_test
return renamed_tests
- def _relative_to_layout_test_dir(self, path_relative_to_repo_root):
- """Returns a path that's relative to the layout tests directory."""
+ def _relative_to_web_test_dir(self, path_relative_to_repo_root):
+ """Returns a path that's relative to the web tests directory."""
abs_path = self.finder.path_from_chromium_base(path_relative_to_repo_root)
- if not abs_path.startswith(self.finder.layout_tests_dir()):
+ if not abs_path.startswith(self.finder.web_tests_dir()):
return None
- return self.fs.relpath(abs_path, self.finder.layout_tests_dir())
+ return self.fs.relpath(abs_path, self.finder.web_tests_dir())
def _get_last_imported_wpt_revision(self):
"""Finds the last imported WPT revision."""
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index 6c71e5b57f5..ce7695b14e4 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -26,7 +26,7 @@ _log = logging.getLogger(__name__)
MARKER_COMMENT = '# ====== New tests from wpt-importer added here ======'
UMBRELLA_BUG = 'crbug.com/626703'
-# TODO(robertma): Investigate reusing layout_tests.models.test_expectations and
+# TODO(robertma): Investigate reusing web_tests.models.test_expectations and
# alike in this module.
SimpleTestResult = namedtuple('SimpleTestResult', ['expected', 'actual', 'bug'])
@@ -114,7 +114,7 @@ class WPTExpectationsUpdater(object):
def get_failing_results_dict(self, build):
"""Returns a nested dict of failing test results.
- Retrieves a full list of layout test results from a builder result URL.
+ Retrieves a full list of web test results from a builder result URL.
Collects the builder name, platform and a list of tests that did not
run as expected.
@@ -134,24 +134,24 @@ class WPTExpectationsUpdater(object):
if port_name in self.ports_with_all_pass:
# All tests passed, so there should be no failing results.
return {}
- layout_test_results = self.host.buildbot.fetch_results(build)
- if layout_test_results is None:
+ web_test_results = self.host.buildbot.fetch_results(build)
+ if web_test_results is None:
_log.warning('No results for build %s', build)
self.ports_with_no_results.add(self.port_name(build))
return {}
- failing_test_results = [result for result in layout_test_results.didnt_run_as_expected_results() if not result.did_pass()]
+ failing_test_results = [result for result in web_test_results.didnt_run_as_expected_results() if not result.did_pass()]
return self.generate_results_dict(self.port_name(build), failing_test_results)
@memoized
def port_name(self, build):
return self.host.builders.port_name_for_builder_name(build.builder_name)
- def generate_results_dict(self, full_port_name, layout_test_results):
+ def generate_results_dict(self, full_port_name, web_test_results):
"""Makes a dict with results for one platform.
Args:
full_port_name: The fully-qualified port name, e.g. "win-win10".
- layout_test_results: A list of LayoutTestResult objects.
+ web_test_results: A list of WebTestResult objects.
Returns:
A dictionary with the structure: {
@@ -161,7 +161,7 @@ class WPTExpectationsUpdater(object):
}
"""
test_dict = {}
- for result in layout_test_results:
+ for result in web_test_results:
test_name = result.test_name()
if not self.port.is_wpt_test(test_name):
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
index cc6236c8159..5308a22ddf0 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -10,7 +10,7 @@ from blinkpy.common.net.buildbot import Build
from blinkpy.common.net.buildbot_mock import MockBuildBot
from blinkpy.common.net.git_cl import TryJobStatus
from blinkpy.common.net.git_cl_mock import MockGitCL
-from blinkpy.common.net.layout_test_results import LayoutTestResult, LayoutTestResults
+from blinkpy.common.net.web_test_results import WebTestResult, WebTestResults
from blinkpy.common.system.executive import ScriptError
from blinkpy.common.system.log_testing import LoggingTestCase
from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater, SimpleTestResult, MARKER_COMMENT
@@ -61,7 +61,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
# Write a dummy manifest file, describing what tests exist.
host.filesystem.write_text_file(
- host.port_factory.get().layout_tests_dir() + '/external/wpt/MANIFEST.json',
+ host.port_factory.get().web_tests_dir() + '/external/wpt/MANIFEST.json',
json.dumps({
'items': {
'reftest': {
@@ -106,7 +106,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
# of the tests passed.
host.buildbot.set_results(
Build('MOCK Try Mac10.10', 333),
- LayoutTestResults({
+ WebTestResults({
'tests': {
'external': {
'wpt': {
@@ -133,7 +133,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
def test_get_failing_results_dict_only_passing_results(self):
host = self.mock_host()
- host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({
+ host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({
'tests': {
'external': {
'wpt': {
@@ -153,7 +153,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
def test_get_failing_results_dict_unexpected_pass(self):
host = self.mock_host()
- host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({
+ host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({
'tests': {
'external': {
'wpt': {
@@ -182,7 +182,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
def test_get_failing_results_dict_some_failing_results(self):
host = self.mock_host()
- host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({
+ host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({
'tests': {
'external': {
'wpt': {
@@ -213,7 +213,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
def test_get_failing_results_dict_non_wpt_test(self):
host = self.mock_host()
- host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({
+ host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({
'tests': {
'x': {
'failing-test.html': {
@@ -469,8 +469,8 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
def test_generate_results_dict(self):
updater = WPTExpectationsUpdater(self.mock_host())
- layout_test_list = [
- LayoutTestResult(
+ web_test_list = [
+ WebTestResult(
'external/wpt/test/name.html', {
'expected': 'bar',
'actual': 'foo',
@@ -478,7 +478,7 @@ class WPTExpectationsUpdaterTest(LoggingTestCase):
'has_stderr': True,
})
]
- self.assertEqual(updater.generate_results_dict('test-mac-mac10.10', layout_test_list), {
+ self.assertEqual(updater.generate_results_dict('test-mac-mac10.10', web_test_list), {
'external/wpt/test/name.html': {
'test-mac-mac10.10': SimpleTestResult(
expected='bar',
diff --git a/chromium/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py b/chromium/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
index 2876b3aec80..7e18f3b3712 100644
--- a/chromium/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
+++ b/chromium/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
@@ -181,8 +181,8 @@ class WPTManifest(object):
def ensure_manifest(host):
"""Updates the MANIFEST.json file, or generates if it does not exist."""
finder = PathFinder(host.filesystem)
- manifest_path = finder.path_from_layout_tests('external', 'wpt', 'MANIFEST.json')
- base_manifest_path = finder.path_from_layout_tests('external', BASE_MANIFEST_NAME)
+ manifest_path = finder.path_from_web_tests('external', 'wpt', 'MANIFEST.json')
+ base_manifest_path = finder.path_from_web_tests('external', BASE_MANIFEST_NAME)
if not host.filesystem.exists(base_manifest_path):
_log.error('Manifest base not found at "%s".', base_manifest_path)
@@ -196,7 +196,7 @@ class WPTManifest(object):
host.filesystem.remove(manifest_path)
host.filesystem.copyfile(base_manifest_path, manifest_path)
- wpt_path = finder.path_from_layout_tests('external', 'wpt')
+ wpt_path = finder.path_from_web_tests('external', 'wpt')
WPTManifest.generate_manifest(host, wpt_path)
_log.debug('Manifest generation completed.')
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/breakpad/dump_reader_win.py b/chromium/third_party/blink/tools/blinkpy/web_tests/breakpad/dump_reader_win.py
index bd506b3b8b4..a37d447e42b 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/breakpad/dump_reader_win.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/breakpad/dump_reader_win.py
@@ -29,7 +29,6 @@
import errno
import logging
import os
-import shlex
from blinkpy.web_tests.breakpad.dump_reader import DumpReader
@@ -111,15 +110,6 @@ class DumpReaderWin(DumpReader):
for program_files in program_files_directories:
possible_cdb_locations.append(template % program_files)
- gyp_defines = self._host.environ.get('GYP_DEFINES', [])
- if gyp_defines:
- gyp_defines = shlex.split(gyp_defines)
- if 'windows_sdk_path' in gyp_defines:
- possible_cdb_locations.extend([
- '%s\\Debuggers\\x86' % gyp_defines['windows_sdk_path'],
- '%s\\Debuggers\\x64' % gyp_defines['windows_sdk_path'],
- ])
-
# Look in depot_tools win_toolchain too.
depot_tools = self._find_depot_tools_path()
if depot_tools:
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/builder_list.py b/chromium/third_party/blink/tools/blinkpy/web_tests/builder_list.py
index 96760fbee90..3bc7758f914 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/builder_list.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/builder_list.py
@@ -26,9 +26,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Represents a set of builder bots running layout tests.
+"""Represents a set of builder bots running web tests.
-This class is used to hold a list of builder bots running layout tests and their
+This class is used to hold a list of builder bots running web tests and their
corresponding port names and TestExpectations specifiers.
"""
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
index 41b0fb02ad8..661ccdbdce7 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""The Manager orchestrates the overall process of running layout tests.
+"""The Manager orchestrates the overall process of running web tests.
This includes finding tests to run, reading the test expectations,
starting the required helper servers, deciding the order and way to
@@ -48,9 +48,9 @@ from blinkpy.common.net.file_uploader import FileUploader
from blinkpy.common.path_finder import PathFinder
from blinkpy.tool import grammar
from blinkpy.w3c.wpt_manifest import WPTManifest
-from blinkpy.web_tests.controllers.layout_test_finder import LayoutTestFinder
-from blinkpy.web_tests.controllers.layout_test_runner import LayoutTestRunner
from blinkpy.web_tests.controllers.test_result_writer import TestResultWriter
+from blinkpy.web_tests.controllers.web_test_finder import WebTestFinder
+from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner
from blinkpy.web_tests.layout_package import json_results_generator
from blinkpy.web_tests.models import test_expectations
from blinkpy.web_tests.models import test_failures
@@ -63,7 +63,7 @@ TestExpectations = test_expectations.TestExpectations
class Manager(object):
- """A class for managing running a series of layout tests."""
+ """A class for managing running a series of web tests."""
HTTP_SUBDIR = 'http'
PERF_SUBDIR = 'perf'
@@ -89,9 +89,9 @@ class Manager(object):
self._websockets_server_started = False
self._results_directory = self._port.results_directory()
- self._finder = LayoutTestFinder(self._port, self._options)
+ self._finder = WebTestFinder(self._port, self._options)
self._path_finder = PathFinder(port.host.filesystem)
- self._runner = LayoutTestRunner(self._options, self._port, self._printer, self._results_directory, self._test_is_slow)
+ self._runner = WebTestRunner(self._options, self._port, self._printer, self._results_directory, self._test_is_slow)
def run(self, args):
"""Runs the tests and return a RunDetails object with the results."""
@@ -99,7 +99,7 @@ class Manager(object):
self._printer.write_update('Collecting tests ...')
running_all_tests = False
- if not args or any('external' in path for path in args):
+ if self._options.manifest_update and (not args or any('external' in path for path in args)):
self._printer.write_update('Generating MANIFEST.json for web-platform-tests ...')
WPTManifest.ensure_manifest(self._port.host)
self._printer.write_update('Completed generating manifest.')
@@ -193,7 +193,6 @@ class Manager(object):
self._upload_json_files()
self._copy_results_html_file(self._results_directory, 'results.html')
- self._copy_results_html_file(self._results_directory, 'legacy-results.html')
if initial_results.keyboard_interrupted:
exit_code = exit_codes.INTERRUPTED_EXIT_STATUS
else:
@@ -566,7 +565,7 @@ class Manager(object):
def _copy_results_html_file(self, destination_dir, filename):
"""Copies a file from the template directory to the results directory."""
- template_dir = self._path_finder.path_from_layout_tests('fast', 'harness')
+ template_dir = self._path_finder.path_from_web_tests('fast', 'harness')
source_path = self._filesystem.join(template_dir, filename)
destination_path = self._filesystem.join(destination_dir, filename)
# Note that the results.html template file won't exist when
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/single_test_runner.py b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/single_test_runner.py
index e6782ee9e76..fd4774ce253 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/single_test_runner.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/single_test_runner.py
@@ -201,7 +201,7 @@ class SingleTestRunner(object):
# Remove |output_path| if it exists and is not the generic expectation to
# avoid extra baseline if the new baseline is the same as the fallback baseline.
- generic_dir = fs.join(port.layout_tests_dir(),
+ generic_dir = fs.join(port.web_tests_dir(),
fs.dirname(port.lookup_virtual_test_base(self._test_name) or self._test_name))
if (not data or output_dir != generic_dir) and fs.exists(output_path):
_log.info('Removing the current baseline "%s"', port.relative_test_filename(output_path))
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py
index 44921dccce7..3a2cdbc1e05 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py
@@ -39,13 +39,13 @@ from blinkpy.web_tests.models import test_expectations
_log = logging.getLogger(__name__)
-class LayoutTestFinder(object):
+class WebTestFinder(object):
def __init__(self, port, options):
self._port = port
self._options = options
self._filesystem = self._port.host.filesystem
- self.LAYOUT_TESTS_DIRECTORIES = ('src', 'third_party', 'blink', 'web_tests')
+ self.WEB_TESTS_DIRECTORIES = ('src', 'third_party', 'blink', 'web_tests')
def find_tests(self, args, test_list=None, fastest_percentile=None):
paths = self._strip_test_dir_prefixes(args)
@@ -118,11 +118,11 @@ class LayoutTestFinder(object):
def _strip_test_dir_prefix(self, path):
# Remove src/third_party/blink/web_tests/ from the front of the test path,
# or any subset of these.
- for i in range(len(self.LAYOUT_TESTS_DIRECTORIES)):
+ for i in range(len(self.WEB_TESTS_DIRECTORIES)):
# Handle both "web_tests/foo/bar.html" and "web_tests\foo\bar.html" if
# the filesystem uses '\\' as a directory separator
for separator in (self._port.TEST_PATH_SEPARATOR, self._filesystem.sep):
- directory_prefix = separator.join(self.LAYOUT_TESTS_DIRECTORIES[i:]) + separator
+ directory_prefix = separator.join(self.WEB_TESTS_DIRECTORIES[i:]) + separator
if path.startswith(directory_prefix):
return path[len(directory_prefix):]
return path
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder_unittest.py
index a3474ac48e5..f932b7cdc74 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder_unittest.py
@@ -8,7 +8,7 @@ import unittest
from blinkpy.common import path_finder
from blinkpy.common.host_mock import MockHost
-from blinkpy.web_tests.controllers import layout_test_finder
+from blinkpy.web_tests.controllers import web_test_finder
_MOCK_ROOT = os.path.join(
path_finder.get_chromium_src_dir(), 'third_party', 'pymock')
@@ -16,7 +16,7 @@ sys.path.append(_MOCK_ROOT)
import mock
-class LayoutTestFinderTests(unittest.TestCase):
+class WebTestFinderTests(unittest.TestCase):
def test_find_fastest_tests(self):
host = MockHost()
@@ -37,7 +37,7 @@ class LayoutTestFinderTests(unittest.TestCase):
port.tests = lambda paths: paths or all_tests
- finder = layout_test_finder.LayoutTestFinder(port, {})
+ finder = web_test_finder.WebTestFinder(port, {})
finder._times_trie = lambda: {
'fast': {
'css': {
@@ -79,7 +79,7 @@ class LayoutTestFinderTests(unittest.TestCase):
port.tests = lambda paths: paths or all_tests
- finder = layout_test_finder.LayoutTestFinder(port, {})
+ finder = web_test_finder.WebTestFinder(port, {})
finder._times_trie = lambda: {
'fast': {
@@ -95,7 +95,7 @@ class LayoutTestFinderTests(unittest.TestCase):
self.assertEqual(set(tests[1]), set(['fast/css/1.html']))
def test_split_chunks(self):
- split = layout_test_finder.LayoutTestFinder._split_into_chunks # pylint: disable=protected-access
+ split = web_test_finder.WebTestFinder._split_into_chunks # pylint: disable=protected-access
with mock.patch('__builtin__.hash', int):
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner.py b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py
index c4f21406e59..1d7ec88c1ea 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py
@@ -55,7 +55,7 @@ class TestRunInterruptedException(Exception):
return self.__class__, (self.reason,)
-class LayoutTestRunner(object):
+class WebTestRunner(object):
def __init__(self, options, port, printer, results_directory, test_is_slow_fn):
self._options = options
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittes.py
index 0df3ce427db..bd90f363d45 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittes.py
@@ -32,7 +32,7 @@ import unittest
from blinkpy.common.host_mock import MockHost
from blinkpy.common.system.system_host_mock import MockSystemHost
from blinkpy.web_tests import run_webkit_tests
-from blinkpy.web_tests.controllers.layout_test_runner import LayoutTestRunner, Sharder, TestRunInterruptedException
+from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner, Sharder, TestRunInterruptedException
from blinkpy.web_tests.models import test_expectations
from blinkpy.web_tests.models import test_failures
from blinkpy.web_tests.models.test_run_results import TestRunResults
@@ -70,7 +70,7 @@ class FakePrinter(object):
pass
-class LockCheckingRunner(LayoutTestRunner):
+class LockCheckingRunner(WebTestRunner):
def __init__(self, port, options, printer, tester, http_lock):
super(LockCheckingRunner, self).__init__(options, port, printer, port.results_directory(), lambda test_name: False)
@@ -79,7 +79,7 @@ class LockCheckingRunner(LayoutTestRunner):
self._should_have_http_lock = http_lock
-class LayoutTestRunnerTests(unittest.TestCase):
+class WebTestRunnerTests(unittest.TestCase):
# pylint: disable=protected-access
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py b/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
index 5b7acc9b97f..ef056416391 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
@@ -82,7 +82,7 @@ def lint(host, options):
def check_virtual_test_suites(host, options):
port = host.port_factory.get(options=options)
fs = host.filesystem
- layout_tests_dir = port.layout_tests_dir()
+ web_tests_dir = port.web_tests_dir()
virtual_suites = port.virtual_test_suites()
failures = []
@@ -91,9 +91,9 @@ def check_virtual_test_suites(host, options):
# - a top-level README.md (e.g. virtual/foo/README.md)
# - a README.txt for each covered dir/file (e.g.
# virtual/foo/http/tests/README.txt, virtual/foo/fast/README.txt, ...)
- comps = [layout_tests_dir] + suite.name.split('/') + ['README.txt']
+ comps = [web_tests_dir] + suite.name.split('/') + ['README.txt']
path_to_readme_txt = fs.join(*comps)
- comps = [layout_tests_dir] + suite.name.split('/')[:2] + ['README.md']
+ comps = [web_tests_dir] + suite.name.split('/')[:2] + ['README.md']
path_to_readme_md = fs.join(*comps)
if not fs.exists(path_to_readme_txt) and not fs.exists(path_to_readme_md):
failure = '{} and {} are both missing (each virtual suite must have one).'.format(
@@ -107,7 +107,7 @@ def check_virtual_test_suites(host, options):
def check_smoke_tests(host, options):
port = host.port_factory.get(options=options)
- smoke_tests_file = host.filesystem.join(port.layout_tests_dir(), 'SmokeTests')
+ smoke_tests_file = host.filesystem.join(port.web_tests_dir(), 'SmokeTests')
failures = []
if not host.filesystem.exists(smoke_tests_file):
return failures
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
index 16e695a173e..3102a1756ab 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
@@ -71,7 +71,7 @@ class FakePort(object):
def extra_expectations_files(self):
return ['/fake-port-base-directory/web_tests/ExtraExpectations']
- def layout_tests_dir(self):
+ def web_tests_dir(self):
return '/fake-port-base-directory/web_tests'
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results.py b/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results.py
index d8071aa5adc..a5c6e3f44eb 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results.py
@@ -2,13 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Classes for merging layout tests results directories together.
+"""Classes for merging web tests results directories together.
This is split into three parts:
* Generic code to merge JSON data together.
* Generic code to merge directories together.
- * Code to specifically merge the layout tests result data together.
+ * Code to specifically merge the web tests result data together.
The JSON data merger will recursively merge dictionaries by default.
@@ -518,7 +518,7 @@ class DirMerger(Merger):
break
-# Classes specific to merging LayoutTest results directory.
+# Classes specific to merging web test results directory.
# ------------------------------------------------------------------------
@@ -577,7 +577,7 @@ class JSONTestResultsMerger(JSONMerger):
NameRegexMatch(':interrupted$'),
lambda o, name=None: bool(sum(o)))
- # Layout test directory value is randomly created on each shard, so
+ # Web test directory value is randomly created on each shard, so
# clear it.
self.add_helper(
NameRegexMatch(':layout_tests_dir$'),
@@ -596,8 +596,8 @@ class JSONTestResultsMerger(JSONMerger):
return JSONMerger.fallback_matcher(self, objs, name)
-class LayoutTestDirMerger(DirMerger):
- """Merge layout test result directory."""
+class WebTestDirMerger(DirMerger):
+ """Merge web test result directory."""
def __init__(self, filesystem=None,
results_json_value_overrides=None,
@@ -674,7 +674,7 @@ def main(argv):
parser = argparse.ArgumentParser()
parser.description = """\
-Merges sharded layout test results into a single output directory.
+Merges sharded web test results into a single output directory.
"""
parser.epilog = """\
@@ -812,7 +812,7 @@ directory. The script will be given the arguments plus
results_json_value_overrides[result_key] = build_properties[build_prop_key]
logging.debug('results_json_value_overrides: %r', results_json_value_overrides)
- merger = LayoutTestDirMerger(
+ merger = WebTestDirMerger(
results_json_value_overrides=results_json_value_overrides,
results_json_allow_unknown_if_matching=args.results_json_allow_unknown_if_matching)
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results_unittest.py
index c217d41c73f..5035db04de5 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/merge_results_unittest.py
@@ -541,7 +541,7 @@ class JSONTestResultsMerger(unittest.TestCase):
merger.merge([{'seconds_since_epoch': 12}, {}]))
-class LayoutTestDirMergerTests(unittest.TestCase):
+class WebTestDirMergerTests(unittest.TestCase):
# JSON files for shard 1
# Shard1 has the following tests;
@@ -555,7 +555,7 @@ class LayoutTestDirMergerTests(unittest.TestCase):
"chromium_revision": "123",
"fixable": 1,
"interrupted": false,
- "layout_tests_dir": "/b/s/w/irJ1McdS/third_party/WebKit/LayoutTests",
+ "layout_tests_dir": "/b/s/w/irJ1McdS/third_party/blink/web_tests",
"num_failures_by_type": {
"AUDIO": 2,
"CRASH": 3
@@ -677,7 +677,7 @@ ADD_RESULTS({
"chromium_revision": "123",
"fixable": 9,
"interrupted": false,
- "layout_tests_dir": "/b/s/w/sadfa124/third_party/WebKit/LayoutTests",
+ "layout_tests_dir": "/b/s/w/sadfa124/third_party/blink/web_tests",
"num_failures_by_type": {
"AUDIO": 10,
"CRASH": 11
@@ -772,7 +772,7 @@ ADD_RESULTS({
[Wed Mar 01 22:20:07.400802 2017] [ssl:warn] [pid 15010] AH01909: RSA certificate configured for 127.0.0.1:443 does NOT include an ID which matches the server name
"""
- layout_test_filesystem = {
+ web_test_filesystem = {
# Files for shard0
'/shards/0/layout-test-results/access_log.txt': shard0_access_log,
'/shards/0/layout-test-results/archived_results.json': shard0_archived_results_json,
@@ -1008,7 +1008,7 @@ ADD_RESULTS({
[Wed Mar 01 22:20:07.400802 2017] [ssl:warn] [pid 15010] AH01909: RSA certificate configured for 127.0.0.1:443 does NOT include an ID which matches the server name
"""
- layout_test_output_filesystem = {
+ web_test_output_filesystem = {
'/out/layout-test-results/access_log.txt': output_access_log,
'/out/layout-test-results/archived_results.json': output_archived_results_json,
'/out/layout-test-results/error_log.txt': output_error_log,
@@ -1040,11 +1040,11 @@ ADD_RESULTS({
}
def test(self):
- fs = MockFileSystem(self.layout_test_filesystem)
+ fs = MockFileSystem(self.web_test_filesystem)
- merger = merge_results.LayoutTestDirMerger(fs, results_json_value_overrides={'layout_tests_dir': 'src'})
+ merger = merge_results.WebTestDirMerger(fs, results_json_value_overrides={'layout_tests_dir': 'src'})
merger.merge('/out', ['/shards/0', '/shards/1'])
- for fname, contents in self.layout_test_output_filesystem.items():
+ for fname, contents in self.web_test_output_filesystem.items():
self.assertIn(fname, fs.files)
self.assertMultiLineEqual(contents, fs.files[fname])
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py b/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
index c38853af5c0..cd64e3e4e07 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""A helper class for reading in and dealing with tests expectations for layout tests."""
+"""A helper class for reading in and dealing with tests expectations for web tests."""
from collections import defaultdict
@@ -880,7 +880,7 @@ class TestExpectationsModel(object):
class TestExpectations(object):
"""Test expectations consist of lines with specifications of what
- to expect from layout test cases. The test cases can be directories
+ to expect from web test cases. The test cases can be directories
in which case the expectations apply to all test cases in that
directory and any subdirectory. The format is along the lines of:
@@ -1017,7 +1017,7 @@ class TestExpectations(object):
return set(suffixes)
@staticmethod
- # test_result is an instance of blinkpy.common.net.layout_test_results.LayoutTestResult
+ # test_result is an instance of blinkpy.common.net.web_test_results.WebTestResult
def suffixes_for_test_result(test_result):
suffixes = set()
actual_results = test_result.actual_results()
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py
index a81fbaa7f01..8331deaa53f 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py
@@ -168,8 +168,8 @@ class MiscTests(Base):
def test_parse_warning(self):
try:
filesystem = self._port.host.filesystem
- filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'disabled-test.html-disabled'), 'content')
- filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'test-to-rebaseline.html'), 'content')
+ filesystem.write_text_file(filesystem.join(self._port.web_tests_dir(), 'disabled-test.html-disabled'), 'content')
+ filesystem.write_text_file(filesystem.join(self._port.web_tests_dir(), 'test-to-rebaseline.html'), 'content')
self.parse_exp('Bug(user) [ FOO ] failures/expected/text.html [ Failure ]\n'
'Bug(user) non-existent-test.html [ Failure ]\n'
'Bug(user) disabled-test.html-disabled [ Failure ]\n',
@@ -242,7 +242,7 @@ Bug(test) failures/expected/timeout.html [ Timeout ]
self.assert_exp('failures/expected/text.html', FAIL)
self.assertNotIn(
self._port.host.filesystem.join(
- self._port.layout_tests_dir(),
+ self._port.web_tests_dir(),
'failures/expected/text.html'),
self._exp.get_tests_with_result_type(SKIP))
@@ -284,7 +284,7 @@ class SkippedTests(Base):
options=optparse.Values({'ignore_tests': ignore_tests}))
port.host.filesystem.write_text_file(
port.host.filesystem.join(
- port.layout_tests_dir(), 'failures/expected/text.html'),
+ port.web_tests_dir(), 'failures/expected/text.html'),
'foo')
expectations_dict = OrderedDict()
expectations_dict['expectations'] = expectations
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_run_results.py b/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_run_results.py
index fff5ba524ec..9ad7bcc2f4b 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_run_results.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/models/test_run_results.py
@@ -61,7 +61,7 @@ class TestRunResults(object):
self.unexpected_failures = 0
self.unexpected_timeouts = 0
- # The wall clock time spent running the tests (layout_test_runner.run()).
+ # The wall clock time spent running the tests (web_test_runner.run()).
self.run_time = 0
# Map of test name to the *last* result for the test.
@@ -365,7 +365,7 @@ def summarize_results(port_obj, expectations, initial_results,
# Does results.html have enough information to compute this itself? (by
# checking total number of results vs. total number of tests?)
results['interrupted'] = initial_results.interrupted
- results['layout_tests_dir'] = port_obj.layout_tests_dir()
+ results['layout_tests_dir'] = port_obj.web_tests_dir()
results['seconds_since_epoch'] = int(time.time())
results['build_number'] = port_obj.get_option('build_number')
results['builder_name'] = port_obj.get_option('builder_name')
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/android.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/android.py
index a89cfb44762..39d20f7d5fe 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/android.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/android.py
@@ -101,11 +101,11 @@ _log = logging.getLogger(__name__)
# This path is defined in Chromium's base/test/test_support_android.cc.
DEVICE_SOURCE_ROOT_DIR = '/data/local/tmp/'
-# The layout tests directory on device, which has two usages:
+# The web tests directory on device, which has two usages:
# 1. as a virtual path in file urls that will be bridged to HTTP.
# 2. pointing to some files that are pushed to the device for tests that
# don't work on file-over-http (e.g. blob protocol tests).
-DEVICE_LAYOUT_TESTS_DIR = DEVICE_SOURCE_ROOT_DIR + RELATIVE_WEB_TESTS
+DEVICE_WEB_TESTS_DIR = DEVICE_SOURCE_ROOT_DIR + RELATIVE_WEB_TESTS
KPTR_RESTRICT_PATH = '/proc/sys/kernel/kptr_restrict'
@@ -143,7 +143,7 @@ TEST_RESOURCES_TO_PUSH = [
]
-# Information required when running layout tests using content_shell as the test runner.
+# Information required when running web tests using content_shell as the test runner.
class ContentShellDriverDetails():
def device_cache_directory(self):
@@ -187,7 +187,7 @@ class ContentShellDriverDetails():
# instances and whether the device has been set up.
class AndroidDevices(object):
# Percentage of battery a device needs to have in order for it to be considered
- # to participate in running the layout tests.
+ # to participate in running the web tests.
MINIMUM_BATTERY_PERCENTAGE = 30
def __init__(self, default_devices=None, debug_logging=False):
@@ -258,7 +258,7 @@ class AndroidPort(base.Port):
self._dump_reader = DumpReaderAndroid(host, self._build_path())
if self.driver_name() != self.CONTENT_SHELL_NAME:
- raise AssertionError('Layout tests on Android only support content_shell as the driver.')
+ raise AssertionError('Web tests on Android only support content_shell as the driver.')
self._driver_details = ContentShellDriverDetails()
@@ -404,8 +404,8 @@ class AndroidPort(base.Port):
# - the test resources
host_device_tuples.extend(
- (self.host.filesystem.join(self.layout_tests_dir(), resource),
- posixpath.join(DEVICE_LAYOUT_TESTS_DIR, resource))
+ (self.host.filesystem.join(self.web_tests_dir(), resource),
+ posixpath.join(DEVICE_WEB_TESTS_DIR, resource))
for resource in TEST_RESOURCES_TO_PUSH)
# ... and then push them to the device.
@@ -467,13 +467,13 @@ class AndroidPort(base.Port):
def requires_http_server(self):
"""Chromium Android runs tests on devices, and uses the HTTP server to
- serve the actual layout tests to the test driver.
+ serve the actual web tests to the test driver.
"""
return True
def start_http_server(self, additional_dirs, number_of_drivers):
additional_dirs[PERF_TEST_PATH_PREFIX] = self._perf_tests_dir()
- additional_dirs[WEB_TESTS_PATH_PREFIX] = self.layout_tests_dir()
+ additional_dirs[WEB_TESTS_PATH_PREFIX] = self.web_tests_dir()
super(AndroidPort, self).start_http_server(additional_dirs, number_of_drivers)
def create_driver(self, worker_number, no_timeout=False):
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/base.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/base.py
index 26ad8ed0404..d97470d7e25 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -29,7 +29,7 @@
"""Abstract base class for Port classes.
The Port classes encapsulate Port-specific (platform-specific) behavior
-in the layout test infrastructure.
+in the web test infrastructure.
"""
import collections
@@ -106,7 +106,7 @@ SXG_FINGERPRINT = '55qC1nKu2A88ESbFmk5sTPQS/ScG+8DD7P+2bgFA9iM='
SXG_WPT_FINGERPRINT = '0Rt4mT6SJXojEMHTnKnlJ/hBKMBcI4kteBlhR1eTTdk='
class Port(object):
- """Abstract class for Port-specific hooks for the layout_test package."""
+ """Abstract class for Port-specific hooks for the web_test package."""
# Subclasses override this. This should indicate the basic implementation
# part of the port name, e.g., 'mac', 'win', 'gtk'; there is one unique
@@ -234,7 +234,7 @@ class Port(object):
is the flag in web_tests/additional-driver-flag.setting, if present, otherwise the
first flag passed by --additional-driver-flag.
"""
- flag_file = self._filesystem.join(self.layout_tests_dir(), 'additional-driver-flag.setting')
+ flag_file = self._filesystem.join(self.web_tests_dir(), 'additional-driver-flag.setting')
if self._filesystem.exists(flag_file):
flag = self._filesystem.read_text_file(flag_file).strip()
if flag:
@@ -560,7 +560,7 @@ class Port(object):
# If it wasn't found in a platform directory, return the expected
# result in the test directory, even if no such file actually exists.
- platform_dir = self.layout_tests_dir()
+ platform_dir = self.web_tests_dir()
if self._filesystem.exists(self._filesystem.join(platform_dir, baseline_filename)):
baselines.append((platform_dir, baseline_filename))
@@ -609,7 +609,7 @@ class Port(object):
return self.expected_filename(actual_test_name, extension, return_default, match=match)
if return_default:
- return self._filesystem.join(self.layout_tests_dir(), baseline_filename)
+ return self._filesystem.join(self.web_tests_dir(), baseline_filename)
return None
def fallback_expected_filename(self, test_name, extension):
@@ -698,7 +698,7 @@ class Port(object):
return []
path_in_wpt = match.group(1)
for expectation, ref_path_in_wpt in self._wpt_manifest().extract_reference_list(path_in_wpt):
- ref_absolute_path = self._filesystem.join(self.layout_tests_dir(), 'external/wpt' + ref_path_in_wpt)
+ ref_absolute_path = self._filesystem.join(self.web_tests_dir(), 'external/wpt' + ref_path_in_wpt)
reftest_list.append((expectation, ref_absolute_path))
return reftest_list
@@ -738,7 +738,7 @@ class Port(object):
self.is_test_file(fs, dirname, filename)
and not re.search(r'[/\\]external[/\\]wpt([/\\].*)?$', dirname)
)
- files = find_files.find(self._filesystem, self.layout_tests_dir(), paths, skipped_directories,
+ files = find_files.find(self._filesystem, self.web_tests_dir(), paths, skipped_directories,
is_non_wpt_real_test_file, self.test_key)
return [self.relative_test_filename(f) for f in files]
@@ -796,9 +796,9 @@ class Port(object):
@memoized
def _wpt_manifest(self):
- manifest_path = self._filesystem.join(self.layout_tests_dir(), 'external', 'wpt', 'MANIFEST.json')
+ manifest_path = self._filesystem.join(self.web_tests_dir(), 'external', 'wpt', 'MANIFEST.json')
if not self._filesystem.exists(manifest_path):
- _log.error('Manifest not found at %s. See http://crbug.com/698294', manifest_path)
+ _log.error('Manifest not found at %s. Remove the --no-manifest-update argument to generate it.', manifest_path)
return WPTManifest('{}')
return WPTManifest(self._filesystem.read_text_file(manifest_path))
@@ -844,9 +844,9 @@ class Port(object):
def test_dirs(self):
"""Returns the list of top-level test directories."""
- layout_tests_dir = self.layout_tests_dir()
+ web_tests_dir = self.web_tests_dir()
fs = self._filesystem
- return [d for d in fs.listdir(layout_tests_dir) if fs.isdir(fs.join(layout_tests_dir, d))]
+ return [d for d in fs.listdir(web_tests_dir) if fs.isdir(fs.join(web_tests_dir, d))]
@memoized
def test_isfile(self, test_name):
@@ -909,11 +909,11 @@ class Port(object):
def _perf_tests_dir(self):
return self._path_finder.perf_tests_dir()
- def layout_tests_dir(self):
- custom_layout_tests_dir = self.get_option('layout_tests_directory')
- if custom_layout_tests_dir:
- return custom_layout_tests_dir
- return self._path_finder.layout_tests_dir()
+ def web_tests_dir(self):
+ custom_web_tests_dir = self.get_option('layout_tests_directory')
+ if custom_web_tests_dir:
+ return custom_web_tests_dir
+ return self._path_finder.web_tests_dir()
def skips_test(self, test):
"""Checks whether the given test is skipped for this port.
@@ -950,7 +950,7 @@ class Port(object):
return test not in smoke_tests
def path_to_smoke_tests_file(self):
- return self._filesystem.join(self.layout_tests_dir(), 'SmokeTests')
+ return self._filesystem.join(self.web_tests_dir(), 'SmokeTests')
def skipped_in_never_fix_tests(self, test):
"""Checks if the test is marked as WontFix for this port.
@@ -974,7 +974,7 @@ class Port(object):
return False
def path_to_never_fix_tests_file(self):
- return self._filesystem.join(self.layout_tests_dir(), 'NeverFixTests')
+ return self._filesystem.join(self.web_tests_dir(), 'NeverFixTests')
def name(self):
"""Returns a name that uniquely identifies this particular type of port.
@@ -1014,8 +1014,8 @@ class Port(object):
"""
# Ports that run on windows need to override this method to deal with
# filenames with backslashes in them.
- if filename.startswith(self.layout_tests_dir()):
- return self.host.filesystem.relpath(filename, self.layout_tests_dir())
+ if filename.startswith(self.web_tests_dir()):
+ return self.host.filesystem.relpath(filename, self.web_tests_dir())
else:
return self.host.filesystem.abspath(filename)
@@ -1025,7 +1025,7 @@ class Port(object):
This is the inverse of relative_test_filename().
"""
- return self._filesystem.join(self.layout_tests_dir(), test_name)
+ return self._filesystem.join(self.web_tests_dir(), test_name)
@memoized
def args_for_test(self, test_name):
@@ -1128,7 +1128,6 @@ class Port(object):
if self.host.platform.is_win():
variables_to_copy += [
'PATH',
- 'GYP_DEFINES', # Required to locate win sdk.
]
for variable in variables_to_copy:
@@ -1211,6 +1210,8 @@ class Port(object):
httpd_path = self.path_to_apache()
intentional_syntax_error = 'INTENTIONAL_SYNTAX_ERROR'
cmd = [httpd_path,
+ '-t',
+ '-f', self.path_to_apache_config_file(),
'-C', 'HttpProtocolOptions Unsafe',
'-C', intentional_syntax_error]
env = self.setup_environ_for_server()
@@ -1284,14 +1285,14 @@ class Port(object):
flag = self.primary_driver_flag()
if flag:
return self._filesystem.join(
- self.layout_tests_dir(), self.FLAG_EXPECTATIONS_PREFIX, flag.lstrip('-'))
+ self.web_tests_dir(), self.FLAG_EXPECTATIONS_PREFIX, flag.lstrip('-'))
def _flag_specific_baseline_search_path(self):
flag = self.primary_driver_flag()
if not flag:
return []
flag_dir = self._filesystem.join(
- self.layout_tests_dir(), 'flag-specific', flag.lstrip('-'))
+ self.web_tests_dir(), 'flag-specific', flag.lstrip('-'))
platform_dirs = [
self._filesystem.join(flag_dir, 'platform', platform_dir)
for platform_dir in self.FALLBACK_PATHS[self.version()]]
@@ -1331,7 +1332,7 @@ class Port(object):
"""Returns an OrderedDict of name -> expectations strings."""
expectations = self.expectations_dict()
- flag_path = self._filesystem.join(self.layout_tests_dir(), 'FlagExpectations')
+ flag_path = self._filesystem.join(self.web_tests_dir(), 'FlagExpectations')
if not self._filesystem.exists(flag_path):
return expectations
@@ -1381,9 +1382,9 @@ class Port(object):
"""
return filter(None, [
self.path_to_generic_test_expectations_file(),
- self._filesystem.join(self.layout_tests_dir(), 'NeverFixTests'),
- self._filesystem.join(self.layout_tests_dir(), 'StaleTestExpectations'),
- self._filesystem.join(self.layout_tests_dir(), 'SlowTests'),
+ self._filesystem.join(self.web_tests_dir(), 'NeverFixTests'),
+ self._filesystem.join(self.web_tests_dir(), 'StaleTestExpectations'),
+ self._filesystem.join(self.web_tests_dir(), 'SlowTests'),
self._flag_specific_expectations_path()
])
@@ -1393,14 +1394,14 @@ class Port(object):
These paths are passed via --additional-expectations on some builders.
"""
return [
- self._filesystem.join(self.layout_tests_dir(), 'ASANExpectations'),
- self._filesystem.join(self.layout_tests_dir(), 'LeakExpectations'),
- self._filesystem.join(self.layout_tests_dir(), 'MSANExpectations'),
+ self._filesystem.join(self.web_tests_dir(), 'ASANExpectations'),
+ self._filesystem.join(self.web_tests_dir(), 'LeakExpectations'),
+ self._filesystem.join(self.web_tests_dir(), 'MSANExpectations'),
]
@memoized
def path_to_generic_test_expectations_file(self):
- return self._filesystem.join(self.layout_tests_dir(), 'TestExpectations')
+ return self._filesystem.join(self.web_tests_dir(), 'TestExpectations')
def repository_path(self):
"""Returns the repository path for the chromium code base."""
@@ -1473,7 +1474,7 @@ class Port(object):
"""Return the absolute path to the top of the baseline tree for a
given platform directory.
"""
- return self._filesystem.join(self.layout_tests_dir(), 'platform', platform_dir)
+ return self._filesystem.join(self.web_tests_dir(), 'platform', platform_dir)
def _driver_class(self):
"""Returns the port's driver implementation."""
@@ -1562,7 +1563,7 @@ class Port(object):
def virtual_test_suites(self):
if self._virtual_test_suites is None:
- path_to_virtual_test_suites = self._filesystem.join(self.layout_tests_dir(), 'VirtualTestSuites')
+ path_to_virtual_test_suites = self._filesystem.join(self.web_tests_dir(), 'VirtualTestSuites')
assert self._filesystem.exists(path_to_virtual_test_suites), path_to_virtual_test_suites + ' not found'
try:
test_suite_json = json.loads(self._filesystem.read_text_file(path_to_virtual_test_suites))
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
index 6b7be1ea917..60a10f8fea4 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
@@ -42,7 +42,7 @@ from blinkpy.common.system.system_host import SystemHost
from blinkpy.common.system.system_host_mock import MockSystemHost
from blinkpy.web_tests.models.test_input import TestInput
from blinkpy.web_tests.port.base import Port, VirtualTestSuite
-from blinkpy.web_tests.port.test import add_unit_tests_to_mock_filesystem, LAYOUT_TEST_DIR, TestPort
+from blinkpy.web_tests.port.test import add_unit_tests_to_mock_filesystem, WEB_TEST_DIR, TestPort
MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
@@ -65,8 +65,8 @@ class PortTest(LoggingTestCase):
def test_test_dirs(self):
port = self.make_port()
- port.host.filesystem.write_text_file(port.layout_tests_dir() + '/canvas/test', '')
- port.host.filesystem.write_text_file(port.layout_tests_dir() + '/css2.1/test', '')
+ port.host.filesystem.write_text_file(port.web_tests_dir() + '/canvas/test', '')
+ port.host.filesystem.write_text_file(port.web_tests_dir() + '/css2.1/test', '')
dirs = port.test_dirs()
self.assertIn('canvas', dirs)
self.assertIn('css2.1', dirs)
@@ -465,7 +465,7 @@ class PortTest(LoggingTestCase):
@staticmethod
def _add_manifest_to_mock_file_system(filesystem):
- filesystem.write_text_file(LAYOUT_TEST_DIR + '/external/wpt/MANIFEST.json', json.dumps({
+ filesystem.write_text_file(WEB_TEST_DIR + '/external/wpt/MANIFEST.json', json.dumps({
'items': {
'testharness': {
'dom/ranges/Range-attributes.html': [
@@ -499,9 +499,9 @@ class PortTest(LoggingTestCase):
],
},
}}))
- filesystem.write_text_file(LAYOUT_TEST_DIR + '/external/wpt/dom/ranges/Range-attributes.html', '')
- filesystem.write_text_file(LAYOUT_TEST_DIR + '/external/wpt/console/console-is-a-namespace.any.js', '')
- filesystem.write_text_file(LAYOUT_TEST_DIR + '/external/wpt/common/blank.html', 'foo')
+ filesystem.write_text_file(WEB_TEST_DIR + '/external/wpt/dom/ranges/Range-attributes.html', '')
+ filesystem.write_text_file(WEB_TEST_DIR + '/external/wpt/console/console-is-a-namespace.any.js', '')
+ filesystem.write_text_file(WEB_TEST_DIR + '/external/wpt/common/blank.html', 'foo')
def test_find_none_if_not_in_manifest(self):
port = self.make_port(with_tests=True)
@@ -610,16 +610,16 @@ class PortTest(LoggingTestCase):
PortTest._add_manifest_to_mock_file_system(filesystem)
# A file not in MANIFEST.json is not a test even if it has .html suffix.
- self.assertFalse(port.is_test_file(filesystem, LAYOUT_TEST_DIR + '/external/wpt/common', 'blank.html'))
+ self.assertFalse(port.is_test_file(filesystem, WEB_TEST_DIR + '/external/wpt/common', 'blank.html'))
# .js is not a test in general, but it is if MANIFEST.json contains an
# entry for it.
- self.assertTrue(port.is_test_file(filesystem, LAYOUT_TEST_DIR + '/external/wpt/console', 'console-is-a-namespace.any.js'))
+ self.assertTrue(port.is_test_file(filesystem, WEB_TEST_DIR + '/external/wpt/console', 'console-is-a-namespace.any.js'))
# A file in external/wpt, not a sub directory.
- self.assertFalse(port.is_test_file(filesystem, LAYOUT_TEST_DIR + '/external/wpt', 'testharness_runner.html'))
+ self.assertFalse(port.is_test_file(filesystem, WEB_TEST_DIR + '/external/wpt', 'testharness_runner.html'))
# A file in external/wpt_automation.
- self.assertTrue(port.is_test_file(filesystem, LAYOUT_TEST_DIR + '/external/wpt_automation', 'foo.html'))
+ self.assertTrue(port.is_test_file(filesystem, WEB_TEST_DIR + '/external/wpt_automation', 'foo.html'))
def test_is_wpt_test(self):
self.assertTrue(Port.is_wpt_test('external/wpt/dom/ranges/Range-attributes.html'))
@@ -673,22 +673,22 @@ class PortTest(LoggingTestCase):
def test_reference_files(self):
port = self.make_port(with_tests=True)
self.assertEqual(port.reference_files('passes/svgreftest.svg'),
- [('==', port.layout_tests_dir() + '/passes/svgreftest-expected.svg')])
+ [('==', port.web_tests_dir() + '/passes/svgreftest-expected.svg')])
self.assertEqual(port.reference_files('passes/xhtreftest.svg'),
- [('==', port.layout_tests_dir() + '/passes/xhtreftest-expected.html')])
+ [('==', port.web_tests_dir() + '/passes/xhtreftest-expected.html')])
self.assertEqual(port.reference_files('passes/phpreftest.php'),
- [('!=', port.layout_tests_dir() + '/passes/phpreftest-expected-mismatch.svg')])
+ [('!=', port.web_tests_dir() + '/passes/phpreftest-expected-mismatch.svg')])
def test_reference_files_from_manifest(self):
port = self.make_port(with_tests=True)
PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
self.assertEqual(port.reference_files('external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html'),
- [('==', port.layout_tests_dir() +
+ [('==', port.web_tests_dir() +
'/external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L-ref.html')])
self.assertEqual(port.reference_files('virtual/layout_ng/' +
'external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html'),
- [('==', port.layout_tests_dir() +
+ [('==', port.web_tests_dir() +
'/external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L-ref.html')])
def test_operating_system(self):
@@ -813,7 +813,7 @@ class PortTest(LoggingTestCase):
def test_good_virtual_test_suite_file(self):
port = self.make_port()
port.host.filesystem.write_text_file(
- port.host.filesystem.join(port.layout_tests_dir(), 'VirtualTestSuites'),
+ port.host.filesystem.join(port.web_tests_dir(), 'VirtualTestSuites'),
'[{"prefix": "bar", "base": "fast/bar", "args": ["--bar"]}]')
# If this call returns successfully, we found and loaded the web_tests/VirtualTestSuites.
@@ -822,7 +822,7 @@ class PortTest(LoggingTestCase):
def test_duplicate_virtual_test_suite_in_file(self):
port = self.make_port()
port.host.filesystem.write_text_file(
- port.host.filesystem.join(port.layout_tests_dir(), 'VirtualTestSuites'),
+ port.host.filesystem.join(port.web_tests_dir(), 'VirtualTestSuites'),
'['
'{"prefix": "bar", "base": "fast/bar", "args": ["--bar"]},'
'{"prefix": "bar", "base": "fast/bar", "args": ["--bar"]}'
@@ -833,7 +833,7 @@ class PortTest(LoggingTestCase):
def test_virtual_test_suite_file_is_not_json(self):
port = self.make_port()
port.host.filesystem.write_text_file(
- port.host.filesystem.join(port.layout_tests_dir(), 'VirtualTestSuites'),
+ port.host.filesystem.join(port.web_tests_dir(), 'VirtualTestSuites'),
'{[{[')
self.assertRaises(ValueError, port.virtual_test_suites)
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test.py
index 956cae91f52..ea773718930 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test.py
@@ -53,7 +53,7 @@ class BrowserTestPortOverrides(object):
def _driver_class(self):
return browser_test_driver.BrowserTestDriver
- def layout_tests_dir(self):
+ def web_tests_dir(self):
"""Overridden function from the base port class. Redirects everything
to src/chrome/test/data/printing/layout_tests.
"""
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_driver.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_driver.py
index b580a810c5a..4cdaa786864 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_driver.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_driver.py
@@ -43,7 +43,7 @@ class BrowserTestDriver(Driver):
assign it to the stdin of the process that is owned by this driver's
server process.
"""
- # FIXME(ivandavid): Need to handle case where the layout test doesn't
+ # FIXME(ivandavid): Need to handle case where the web test doesn't
# get a file name.
new_cmd_line = self.cmd_line(per_test_args)
if not self._server_process or new_cmd_line != self._current_cmd_line:
@@ -52,7 +52,7 @@ class BrowserTestDriver(Driver):
self._open_stdin_path(deadline)
# Gets the path of the directory that the file for stdin communication is
- # in. Since the browser test cannot clean it up, the layout test framework
+ # in. Since the browser test cannot clean it up, the web test framework
# will. Everything the browser test uses is stored in the same directory as
# the stdin file, so deleting that directory recursively will remove all the
# other temp data, like the printed pdf. This function assumes the correct
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py
index 71e9f80ed6f..b1a443704c3 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py
@@ -51,8 +51,8 @@ class _BrowserTestTestCaseMixin(object):
self.assertTrue(isinstance(self.make_port(options=optparse.Values({'driver_name': 'browser_tests'})
).create_driver(1), browser_test_driver.BrowserTestDriver))
- def test_layout_tests_dir(self):
- self.assertTrue(self.make_port().layout_tests_dir().endswith('chrome/test/data/printing/layout_tests'))
+ def test_web_tests_dir(self):
+ self.assertTrue(self.make_port().web_tests_dir().endswith('chrome/test/data/printing/layout_tests'))
def test_virtual_test_suites(self):
# The browser_tests port do not use virtual test suites, so we are just testing the stub.
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver.py
index 249d5d79748..d966ec8cf9b 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver.py
@@ -329,15 +329,15 @@ class Driver(object):
'https://%s:%d/' % (hostname, secure_port)]
def uri_to_test(self, uri):
- """Return the base layout test name for a given URI.
+ """Return the base web test name for a given URI.
This returns the test name for a given URI, e.g., if you passed in
- "file:///src/LayoutTests/fast/html/keygen.html" it would return
+ "file:///src/web_tests/fast/html/keygen.html" it would return
"fast/html/keygen.html".
"""
if uri.startswith('file:///'):
- prefix = path.abspath_to_uri(self._port.host.platform, self._port.layout_tests_dir())
+ prefix = path.abspath_to_uri(self._port.host.platform, self._port.web_tests_dir())
if not prefix.endswith('/'):
prefix += '/'
return uri[len(prefix):]
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py
index 48e3e4df5b6..45fe2ecda67 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py
@@ -57,7 +57,7 @@ class DriverTest(unittest.TestCase):
def test_test_to_uri(self):
port = self.make_port()
driver = Driver(port, None)
- self.assertEqual(driver.test_to_uri('foo/bar.html'), 'file://%s/foo/bar.html' % port.layout_tests_dir())
+ self.assertEqual(driver.test_to_uri('foo/bar.html'), 'file://%s/foo/bar.html' % port.web_tests_dir())
self.assertEqual(driver.test_to_uri('http/tests/foo.html'), 'http://127.0.0.1:8000/foo.html')
self.assertEqual(driver.test_to_uri('http/tests/https/bar.html'), 'https://127.0.0.1:8443/https/bar.html')
self.assertEqual(driver.test_to_uri('http/tests/bar.https.html'), 'https://127.0.0.1:8443/bar.https.html')
@@ -69,7 +69,7 @@ class DriverTest(unittest.TestCase):
def test_uri_to_test(self):
port = self.make_port()
driver = Driver(port, None)
- self.assertEqual(driver.uri_to_test('file://%s/foo/bar.html' % port.layout_tests_dir()), 'foo/bar.html')
+ self.assertEqual(driver.uri_to_test('file://%s/foo/bar.html' % port.web_tests_dir()), 'foo/bar.html')
self.assertEqual(driver.uri_to_test('http://127.0.0.1:8000/foo.html'), 'http/tests/foo.html')
self.assertEqual(driver.uri_to_test('https://127.0.0.1:8443/https/bar.html'), 'http/tests/https/bar.html')
self.assertEqual(driver.uri_to_test('https://127.0.0.1:8443/bar.https.html'), 'http/tests/bar.https.html')
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py
index 945d65778b1..5233f4dc508 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py
@@ -75,15 +75,17 @@ CONTENT_SHELL_PACKAGE_PATH = 'gen/content/shell/content_shell/content_shell.far'
# WEB_TEST_PATH_PREFIX should be matched to the local directory name of
# web_tests because some tests and test_runner find test root directory
# with it.
-PERF_TEST_PATH_PREFIX = '/PerformanceTests'
-WEB_TESTS_PATH_PREFIX = '/' + WEB_TESTS_LAST_COMPONENT
+WEB_TESTS_PATH_PREFIX = '/third_party/blink/' + WEB_TESTS_LAST_COMPONENT
# Paths to the directory where the fonts are copied to. Must match the path in
# content/shell/app/blink_test_platform_support_fuchsia.cc .
FONTS_DEVICE_PATH = '/system/fonts'
-# Number of content_shell instances to run in parallel.
-MAX_WORKERS = 8
+# Number of CPU cores in qemu.
+CPU_CORES = 4
+
+# Number of content_shell instances to run in parallel. 1 per CPU core.
+MAX_WORKERS = CPU_CORES
PROCESS_START_TIMEOUT = 20
@@ -117,13 +119,13 @@ class SubprocessOutputLogger(object):
def close(self):
self._process.kill()
-
class _TargetHost(object):
def __init__(self, build_path, ports_to_forward):
try:
self._target = None
self._target = qemu_target.QemuTarget(
- build_path, 'x64', require_kvm=True, ram_size_mb=8192)
+ build_path, 'x64', cpu_cores=CPU_CORES, system_log_file=None,
+ require_kvm=True, ram_size_mb=8192)
self._target.Start()
self._setup_target(build_path, ports_to_forward)
except:
@@ -163,13 +165,17 @@ class _TargetHost(object):
raise Exception('Failed to install content_shell: %s' % \
'\n'.join(output))
+ # Process will be forked for each worker, which may make QemuTarget
+ # unusable (e.g. waitpid() for qemu process returns ECHILD after
+ # fork() ). Save command runner before fork()ing, to use it later to
+ # connect to the target.
+ self.target_command_runner = self._target.GetCommandRunner()
+
+ def run_command(self, command):
+ return self.target_command_runner.RunCommandPiped(
+ command, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
- def run_command(self, *args, **kvargs):
- return self._target.RunCommandPiped(*args,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- **kvargs)
def cleanup(self):
if self._target:
# TODO(sergeyu): Currently __init__() always starts Qemu, so we can
@@ -242,14 +248,24 @@ class FuchsiaPort(base.Port):
# Run a single qemu instance.
return min(MAX_WORKERS, requested_num_workers)
+ def default_timeout_ms(self):
+ # Use 20s timeout instead of the default 6s. This is necessary because
+ # the tests are executed in qemu, so they run slower compared to other
+ # platforms.
+ return 20 * 1000
+
def requires_http_server(self):
"""HTTP server is always required to avoid copying the tests to the VM.
"""
return True
def start_http_server(self, additional_dirs, number_of_drivers):
- additional_dirs[PERF_TEST_PATH_PREFIX] = self._perf_tests_dir()
- additional_dirs[WEB_TESTS_PATH_PREFIX] = self.layout_tests_dir()
+ additional_dirs['/third_party/blink/PerformanceTests'] = \
+ self._perf_tests_dir()
+ additional_dirs[WEB_TESTS_PATH_PREFIX] = self.web_tests_dir()
+ additional_dirs['/gen'] = self.generated_sources_directory()
+ additional_dirs['/third_party/blink'] = \
+ self._path_from_chromium_base('third_party', 'blink')
super(FuchsiaPort, self).start_http_server(
additional_dirs, number_of_drivers)
@@ -272,14 +288,16 @@ class ChromiumFuchsiaDriver(driver.Driver):
port, worker_number, no_timeout)
def _base_cmd_line(self):
- return ['run', 'content_shell']
+ return ['run',
+ 'fuchsia-pkg://fuchsia.com/content_shell#meta/content_shell.cmx',
+ '--ozone-platform=headless']
def _command_from_driver_input(self, driver_input):
command = super(ChromiumFuchsiaDriver, self)._command_from_driver_input(
driver_input)
if command.startswith('/'):
relative_test_filename = \
- os.path.relpath(command, self._port.layout_tests_dir())
+ os.path.relpath(command, self._port.web_tests_dir())
command = 'http://127.0.0.1:8000' + WEB_TESTS_PATH_PREFIX + \
'/' + relative_test_filename
return command
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py
index c68c610bab9..11378b8d31a 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py
@@ -249,9 +249,9 @@ class PortTestCase(LoggingTestCase):
port = self.make_port()
self.assertEqual(port.expectations_files(), [
port.path_to_generic_test_expectations_file(),
- port.host.filesystem.join(port.layout_tests_dir(), 'NeverFixTests'),
- port.host.filesystem.join(port.layout_tests_dir(), 'StaleTestExpectations'),
- port.host.filesystem.join(port.layout_tests_dir(), 'SlowTests'),
+ port.host.filesystem.join(port.web_tests_dir(), 'NeverFixTests'),
+ port.host.filesystem.join(port.web_tests_dir(), 'StaleTestExpectations'),
+ port.host.filesystem.join(port.web_tests_dir(), 'SlowTests'),
])
def test_expectations_ordering(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/test.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/test.py
index d2bb138f69a..f7b6b6de907 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/test.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/test.py
@@ -37,10 +37,10 @@ from blinkpy.web_tests.port.base import Port, VirtualTestSuite
from blinkpy.web_tests.port.driver import DeviceFailure, Driver, DriverOutput
-# Here we use a non-standard location for the layout tests, to ensure that
+# Here we use a non-standard location for the web tests, to ensure that
# this works. The path contains a '.' in the name because we've seen bugs
# related to this before.
-LAYOUT_TEST_DIR = '/test.checkout/wtests'
+WEB_TEST_DIR = '/test.checkout/wtests'
PERF_TEST_DIR = '/test.checkout/PerformanceTests'
@@ -278,9 +278,9 @@ layer at (0,0) size 800x34
# we don't need a real filesystem to run the tests.
def add_unit_tests_to_mock_filesystem(filesystem):
# Add the test_expectations file.
- filesystem.maybe_make_directory(LAYOUT_TEST_DIR)
- if not filesystem.exists(LAYOUT_TEST_DIR + '/TestExpectations'):
- filesystem.write_text_file(LAYOUT_TEST_DIR + '/TestExpectations', """
+ filesystem.maybe_make_directory(WEB_TEST_DIR)
+ if not filesystem.exists(WEB_TEST_DIR + '/TestExpectations'):
+ filesystem.write_text_file(WEB_TEST_DIR + '/TestExpectations', """
Bug(test) failures/expected/audio.html [ Failure ]
Bug(test) failures/expected/crash.html [ Crash ]
Bug(test) failures/expected/crash_then_text.html [ Failure ]
@@ -305,8 +305,8 @@ Bug(test) passes/text.html [ Pass ]
Bug(test) virtual/skipped/failures/expected [ Skip ]
""")
- if not filesystem.exists(LAYOUT_TEST_DIR + '/NeverFixTests'):
- filesystem.write_text_file(LAYOUT_TEST_DIR + '/NeverFixTests', """
+ if not filesystem.exists(WEB_TEST_DIR + '/NeverFixTests'):
+ filesystem.write_text_file(WEB_TEST_DIR + '/NeverFixTests', """
Bug(test) failures/expected/keyboard.html [ WontFix ]
Bug(test) failures/expected/exception.html [ WontFix ]
Bug(test) failures/expected/device_failure.html [ WontFix ]
@@ -315,10 +315,10 @@ Bug(test) failures/expected/device_failure.html [ WontFix ]
# FIXME: This test was only being ignored because of missing a leading '/'.
# Fixing the typo causes several tests to assert, so disabling the test entirely.
# Add in a file should be ignored by port.find_test_files().
- #files[LAYOUT_TEST_DIR + '/userscripts/resources/iframe.html'] = 'iframe'
+ #files[WEB_TEST_DIR + '/userscripts/resources/iframe.html'] = 'iframe'
def add_file(test, suffix, contents):
- dirname = filesystem.join(LAYOUT_TEST_DIR, test.name[0:test.name.rfind('/')])
+ dirname = filesystem.join(WEB_TEST_DIR, test.name[0:test.name.rfind('/')])
base = test.base
filesystem.maybe_make_directory(dirname)
filesystem.write_binary_file(filesystem.join(dirname, base + suffix), contents)
@@ -334,7 +334,7 @@ Bug(test) failures/expected/device_failure.html [ WontFix ]
if test.expected_image:
add_file(test, '-expected.png', test.expected_image)
- filesystem.write_text_file(filesystem.join(LAYOUT_TEST_DIR, 'virtual', 'virtual_passes',
+ filesystem.write_text_file(filesystem.join(WEB_TEST_DIR, 'virtual', 'virtual_passes',
'passes', 'args-expected.txt'), 'args-txt --virtual-arg')
# Clear the list of written files so that we can watch what happens during testing.
filesystem.clear_written_files()
@@ -364,7 +364,7 @@ class TestPort(Port):
self._tests = unit_test_list()
self._flakes = set()
- # FIXME: crbug.com/279494. This needs to be in the "real layout tests
+ # FIXME: crbug.com/279494. This needs to be in the "real web tests
# dir" in a mock filesystem, rather than outside of the checkout, so
# that tests that want to write to a TestExpectations file can share
# this between "test" ports and "real" ports. This is the result of
@@ -373,7 +373,7 @@ class TestPort(Port):
# test ports. rebaseline_unittest.py needs to not mix both "real" ports
# and "test" ports
- self._generic_expectations_path = LAYOUT_TEST_DIR + '/TestExpectations'
+ self._generic_expectations_path = WEB_TEST_DIR + '/TestExpectations'
self._results_directory = None
self._operating_system = 'mac'
@@ -439,8 +439,8 @@ class TestPort(Port):
return ('< %s\n---\n> %s\n' % (expected_contents, actual_contents), None)
return (None, None)
- def layout_tests_dir(self):
- return LAYOUT_TEST_DIR
+ def web_tests_dir(self):
+ return WEB_TEST_DIR
def _perf_tests_dir(self):
return PERF_TEST_DIR
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/port/win.py b/chromium/third_party/blink/tools/blinkpy/web_tests/port/win.py
index 063211e70cf..f235d47cb5f 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/port/win.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/port/win.py
@@ -160,7 +160,7 @@ class WinPort(base.Port):
return 'win'
def relative_test_filename(self, filename):
- path = filename[len(self.layout_tests_dir()) + 1:]
+ path = filename[len(self.web_tests_dir()) + 1:]
return path.replace('\\', '/')
def uses_apache(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/print_layout_test_times.py b/chromium/third_party/blink/tools/blinkpy/web_tests/print_web_test_times.py
index d8b88c819f8..d8b88c819f8 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/print_layout_test_times.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/print_web_test_times.py
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/print_layout_test_times_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/print_web_test_times_unittest.py
index aab2bb3bfb6..a291b5927e7 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/print_layout_test_times_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/print_web_test_times_unittest.py
@@ -29,10 +29,10 @@
import unittest
from blinkpy.common.host_mock import MockHost
-from blinkpy.web_tests.print_layout_test_times import main
+from blinkpy.web_tests.print_web_test_times import main
-class PrintLayoutTestTimesTest(unittest.TestCase):
+class PrintWebTestTimesTest(unittest.TestCase):
def check(self, args, expected_output, files=None):
host = MockHost()
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py b/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
index fac537df51f..00a33b66d18 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
@@ -114,7 +114,7 @@ def parse_args(args):
action='append',
default=[],
dest='adb_devices',
- help='Run Android layout tests on these devices'),
+ help='Run Android web tests on these devices'),
# FIXME: Flip this to be off by default once we can log the
# device setup more cleanly.
optparse.make_option(
@@ -300,7 +300,7 @@ def parse_args(args):
help='Number of times to run the set of tests (e.g. ABCABCABC)'),
optparse.make_option(
'--layout-tests-directory',
- help=('Path to a custom layout tests directory')),
+ help=('Path to a custom web tests directory')),
optparse.make_option(
'--max-locked-shards',
type='int',
@@ -464,7 +464,17 @@ def parse_args(args):
'--zero-tests-executed-ok',
action='store_true',
help='If set, exit with a success code when no tests are run.'
- ' Used on trybots when layout tests are retried without patch.')
+ ' Used on trybots when web tests are retried without patch.')
+ ]))
+
+ option_group_definitions.append(
+ ('web-platform-tests (WPT) Options', [
+ optparse.make_option(
+ '--no-manifest-update',
+ dest='manifest_update',
+ action='store_false',
+ default=True,
+ help=('Do not update the web-platform-tests MANIFEST.json.')),
]))
# FIXME: Move these into json_results_generator.py.
@@ -499,7 +509,7 @@ def parse_args(args):
option_parser = optparse.OptionParser(
prog='run_web_tests.py',
usage='%prog [options] [tests]',
- description='Runs Blink layout tests as described in docs/testing/web_tests.md')
+ description='Runs Blink web tests as described in docs/testing/web_tests.md')
for group_name, group_options in option_group_definitions:
option_group = optparse.OptionGroup(option_parser, group_name)
@@ -564,7 +574,7 @@ def _set_up_derived_options(port, options, args):
if not options.test_list:
options.test_list = []
- options.test_list.append(port.host.filesystem.join(port.layout_tests_dir(), 'SmokeTests'))
+ options.test_list.append(port.host.filesystem.join(port.web_tests_dir(), 'SmokeTests'))
if not options.skipped:
options.skipped = 'always'
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
index 9a79bfe490c..e85737d90c6 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
@@ -581,7 +581,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_smoke_test(self):
host = MockHost()
- smoke_test_filename = test.LAYOUT_TEST_DIR + '/SmokeTests'
+ smoke_test_filename = test.WEB_TEST_DIR + '/SmokeTests'
host.filesystem.write_text_file(smoke_test_filename, 'passes/text.html\n')
# Test the default smoke testing.
@@ -612,7 +612,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_smoke_test_default_retry(self):
host = MockHost()
- smoke_test_filename = test.LAYOUT_TEST_DIR + '/SmokeTests'
+ smoke_test_filename = test.WEB_TEST_DIR + '/SmokeTests'
host.filesystem.write_text_file(
smoke_test_filename, 'failures/unexpected/text-image-checksum.html\n')
@@ -971,7 +971,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_reftest_mismatching_both_text_and_pixel(self):
test_name = 'failures/unexpected/reftest.html'
host = MockHost()
- host.filesystem.write_text_file(test.LAYOUT_TEST_DIR + '/failures/unexpected/reftest-expected.txt', 'mismatch')
+ host.filesystem.write_text_file(test.WEB_TEST_DIR + '/failures/unexpected/reftest-expected.txt', 'mismatch')
run_details, _, _ = logging_run([test_name], tests_included=True, host=host)
self.assertNotEqual(run_details.exit_code, 0)
self.assertEqual(run_details.initial_results.total, 1)
@@ -982,9 +982,9 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_extra_baselines(self):
host = MockHost()
- extra_txt = test.LAYOUT_TEST_DIR + '/passes/image-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/passes/image-expected.txt'
host.filesystem.write_text_file(extra_txt, 'Extra txt')
- extra_wav = test.LAYOUT_TEST_DIR + '/passes/image-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/passes/image-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
test_name = 'passes/image.html'
run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1000,9 +1000,9 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_empty_overriding_baselines(self):
host = MockHost()
- base_baseline = test.LAYOUT_TEST_DIR + '/passes/image-expected.txt'
+ base_baseline = test.WEB_TEST_DIR + '/passes/image-expected.txt'
host.filesystem.write_text_file(base_baseline, 'Non-empty')
- platform_baseline = test.LAYOUT_TEST_DIR + '/platform/test-mac-mac10.10/passes/image-expected.txt'
+ platform_baseline = test.WEB_TEST_DIR + '/platform/test-mac-mac10.10/passes/image-expected.txt'
host.filesystem.write_text_file(platform_baseline, '')
test_name = 'passes/image.html'
run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1015,9 +1015,9 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_reftest_extra_baselines(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/reftest-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/reftest-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
- extra_wav = test.LAYOUT_TEST_DIR + '/passes/reftest-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/passes/reftest-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
test_name = 'passes/reftest.html'
run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1033,9 +1033,9 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_reftest_with_text_extra_baselines(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/reftest-with-text-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/reftest-with-text-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
- extra_wav = test.LAYOUT_TEST_DIR + '/passes/reftest-with-text-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/passes/reftest-with-text-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
test_name = 'passes/reftest-with-text.html'
run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1051,7 +1051,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_reftest_extra_png_baseline(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/reftest-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/reftest-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
test_name = 'passes/reftest.html'
run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1061,12 +1061,12 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_passing_testharness_extra_baselines(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/testharness-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
- extra_txt = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
host.filesystem.write_text_file(extra_txt,
'This is a testharness.js-based test.\nPASS: bah\nHarness: the test ran to completion.')
- extra_wav = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/passes/testharness-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
test_name = 'passes/testharness.html'
run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1084,7 +1084,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_passing_testharness_extra_txt_baseline(self):
host = MockHost()
- extra_txt = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
host.filesystem.write_text_file(extra_txt,
'This is a testharness.js-based test.\nPASS: bah\nHarness: the test ran to completion.')
test_name = 'passes/testharness.html'
@@ -1095,7 +1095,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
def test_passing_testharness_extra_mismatching_txt_baseline(self):
host = MockHost()
- extra_txt = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
host.filesystem.write_text_file(extra_txt,
'This is a testharness.js-based test.\nFAIL: bah\nHarness: the test ran to completion.')
test_name = 'passes/testharness.html'
@@ -1112,9 +1112,9 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
# An all-pass testharness text baseline is necessary when it overrides a fallback baseline.
host = MockHost()
# The base baseline expects a failure.
- base_baseline = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.txt'
+ base_baseline = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
host.filesystem.write_text_file(base_baseline, 'Failure')
- platform_baseline = test.LAYOUT_TEST_DIR + '/platform/test-mac-mac10.10/passes/testharness-expected.txt'
+ platform_baseline = test.WEB_TEST_DIR + '/platform/test-mac-mac10.10/passes/testharness-expected.txt'
host.filesystem.write_text_file(platform_baseline,
'This is a testharness.js-based test.\nPASS: bah\nHarness: the test ran to completion.')
run_details, log_stream, _ = logging_run(
@@ -1221,7 +1221,7 @@ class RunTest(unittest.TestCase, StreamTestingMixin):
class RebaselineTest(unittest.TestCase, StreamTestingMixin):
"""Tests for flags which cause new baselines to be written.
- When running layout tests, there are several flags which write new
+ When running web tests, there are several flags which write new
baselines. This is separate from the "blink_tool.py rebaseline" commands,
which fetch new baselines from elsewhere rather than generating them.
"""
@@ -1233,19 +1233,19 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
written_files: from FileSystem.written_files.
log_stream: The log stream from the run.
expected_file_base: Relative path to the baseline,
- without the extension, from the layout test directory.
+ without the extension, from the web test directory.
expected_extensions: Expected extensions which should be written.
"""
for ext in expected_extensions:
baseline = '%s-expected%s' % (expected_file_base, ext)
- baseline_full_path = '%s/%s' % (test.LAYOUT_TEST_DIR, baseline)
+ baseline_full_path = '%s/%s' % (test.WEB_TEST_DIR, baseline)
self.assertIsNotNone(written_files.get(baseline_full_path))
baseline_message = 'Writing new baseline "%s"\n' % baseline
self.assert_contains(log_stream, baseline_message)
# Assert that baselines with other extensions were not written.
for ext in ({'.png', '.txt', '.wav'} - set(expected_extensions)):
baseline = '%s-expected%s' % (expected_file_base, ext)
- baseline_full_path = '%s/%s' % (test.LAYOUT_TEST_DIR, baseline)
+ baseline_full_path = '%s/%s' % (test.WEB_TEST_DIR, baseline)
self.assertIsNone(written_files.get(baseline_full_path))
def test_reset_results_basic(self):
@@ -1327,7 +1327,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# Tests that we update existing baseline for a testharness test.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR + '/failures/unexpected/testharness-expected.txt', 'foo')
+ test.WEB_TEST_DIR + '/failures/unexpected/testharness-expected.txt', 'foo')
details, log_stream, _ = logging_run(
[
'--reset-results',
@@ -1358,7 +1358,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# if the new baseline is different from the fallback baseline.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we also
@@ -1385,7 +1385,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# if the new baseline is different from the fallback baseline.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we also
@@ -1434,9 +1434,9 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
def test_reset_results_remove_extra_baselines(self):
host = MockHost()
- extra_txt = test.LAYOUT_TEST_DIR + '/failures/unexpected/image-only-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/failures/unexpected/image-only-expected.txt'
host.filesystem.write_text_file(extra_txt, 'Extra txt')
- extra_wav = test.LAYOUT_TEST_DIR + '/failures/unexpected/image-only-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/failures/unexpected/image-only-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
details, log_stream, _ = logging_run(
['--reset-results', 'failures/unexpected/image-only.html'],
@@ -1452,11 +1452,11 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
def test_reset_results_reftest_remove_extra_baselines(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/reftest-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/reftest-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
- extra_wav = test.LAYOUT_TEST_DIR + '/passes/reftest-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/passes/reftest-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
- extra_txt = test.LAYOUT_TEST_DIR + '/passes/reftest-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/passes/reftest-expected.txt'
host.filesystem.write_text_file(extra_txt, 'reftest')
details, _, _ = logging_run(['--reset-results', 'passes/reftest.html'],
tests_included=True, host=host)
@@ -1469,9 +1469,9 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
def test_reset_results_reftest_with_text_remove_extra_baselines(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/reftest-with-text-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/reftest-with-text-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
- extra_wav = test.LAYOUT_TEST_DIR + '/passes/reftest-with-text-expected.wav'
+ extra_wav = test.WEB_TEST_DIR + '/passes/reftest-with-text-expected.wav'
host.filesystem.write_text_file(extra_wav, 'Extra wav')
details, _, _ = logging_run(['--reset-results', 'passes/reftest-with-text.html'],
tests_included=True, host=host)
@@ -1480,13 +1480,13 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
self.assertEqual(len(written_files.keys()), 7)
self.assertIsNone(written_files[extra_png])
self.assertIsNone(written_files[extra_wav])
- self.assertNotIn(test.LAYOUT_TEST_DIR + '/passes/reftest-with-text-expected.txt', written_files)
+ self.assertNotIn(test.WEB_TEST_DIR + '/passes/reftest-with-text-expected.txt', written_files)
def test_reset_results_passing_testharness_remove_extra_baselines(self):
host = MockHost()
- extra_png = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.png'
+ extra_png = test.WEB_TEST_DIR + '/passes/testharness-expected.png'
host.filesystem.write_text_file(extra_png, 'Extra png')
- extra_txt = test.LAYOUT_TEST_DIR + '/passes/testharness-expected.txt'
+ extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
host.filesystem.write_text_file(extra_txt, 'Extra txt')
details, log_stream, _ = logging_run(
['--reset-results', 'passes/testharness.html'],
@@ -1517,7 +1517,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# results are different from the current baselines.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we also
@@ -1542,7 +1542,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# results are different from the current baselines.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we also
@@ -1568,7 +1568,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# actual results are the same as the fallback baselines.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we check
@@ -1576,7 +1576,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# result is the same as this fallback baseline.
'text-image-checksum_fail-txt')
flag_specific_baseline_txt = (
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/flag-specific/flag/failures/unexpected/text-image-checksum-expected.txt')
host.filesystem.write_text_file(
flag_specific_baseline_txt, 'existing-baseline-different-from-fallback')
@@ -1601,7 +1601,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# results are different from the current baselines.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we also
@@ -1626,7 +1626,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# baseline (which should not matter).
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/platform/test-mac-mac10.10/failures/unexpected/text-image-checksum-expected.png',
'wrong-png-baseline')
@@ -1651,11 +1651,11 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# baseline (which should not matter).
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/platform/test-mac-mac10.10/failures/unexpected/text-image-checksum-expected.png',
'wrong-png-baseline')
host.filesystem.remove(
- test.LAYOUT_TEST_DIR + '/failures/unexpected/text-image-checksum-expected.png')
+ test.WEB_TEST_DIR + '/failures/unexpected/text-image-checksum-expected.png')
details, log_stream, _ = logging_run(
[
@@ -1677,7 +1677,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# actual results are the same as the fallback baselines.
host = MockHost()
host.filesystem.write_text_file(
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/failures/unexpected/text-image-checksum-expected.txt',
# This value is the same as actual text result of the test defined
# in blinkpy.web_tests.port.test. This is added so that we check
@@ -1685,7 +1685,7 @@ class RebaselineTest(unittest.TestCase, StreamTestingMixin):
# result is the same as this fallback baseline.
'text-image-checksum_fail-txt')
virtual_baseline_txt = (
- test.LAYOUT_TEST_DIR +
+ test.WEB_TEST_DIR +
'/virtual/virtual_failures/failures/unexpected/text-image-checksum-expected.txt')
host.filesystem.write_text_file(
virtual_baseline_txt, 'existing-baseline-different-from-fallback')
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py
index 991ae4ab03c..eb3e93c2eb3 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Start and stop the Apache HTTP server as it is used by the layout tests."""
+"""Start and stop the Apache HTTP server as it is used by the web tests."""
import logging
import socket
@@ -45,9 +45,9 @@ class ApacheHTTP(server_base.ServerBase):
# match old-run-webkit-tests: https://bugs.webkit.org/show_bug.cgi?id=63956
self._name = 'httpd'
self._log_prefixes = ('access_log', 'error_log')
- self._mappings = [{'port': 8000},
- {'port': 8080},
- {'port': 8443, 'sslcert': True}]
+ self._mappings = [{'port': 8000, 'scheme': 'http'},
+ {'port': 8080, 'scheme': 'http'},
+ {'port': 8443, 'scheme': 'https', 'sslcert': True}]
self._number_of_servers = number_of_servers
self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name)
@@ -55,10 +55,11 @@ class ApacheHTTP(server_base.ServerBase):
executable = self._port_obj.path_to_apache()
server_root = self._filesystem.dirname(self._filesystem.dirname(executable))
- test_dir = self._port_obj.layout_tests_dir()
+ test_dir = self._port_obj.web_tests_dir()
document_root = self._filesystem.join(test_dir, 'http', 'tests')
forms_test_resources_dir = self._filesystem.join(test_dir, 'fast', 'forms', 'resources')
media_resources_dir = self._filesystem.join(test_dir, 'media')
+ reporting_observer_resources_dir = self._filesystem.join(test_dir, 'reporting-observer', 'resources')
webaudio_resources_dir = self._filesystem.join(test_dir, 'webaudio', 'resources')
mime_types_path = self._filesystem.join(self._port_obj.apache_config_directory(), 'mime.types')
cert_file = self._filesystem.join(self._port_obj.apache_config_directory(), 'webkit-httpd.pem')
@@ -87,6 +88,7 @@ class ApacheHTTP(server_base.ServerBase):
'-c', 'Alias /bluetooth-resources "%s/external/wpt/bluetooth/resources"' % test_dir,
'-c', 'Alias /forms-test-resources "%s"' % forms_test_resources_dir,
'-c', 'Alias /media-resources "%s"' % media_resources_dir,
+ '-c', 'Alias /reporting-observer-resources "%s"' % reporting_observer_resources_dir,
'-c', 'Alias /webaudio-resources "%s"' % webaudio_resources_dir,
'-c', 'Alias /inspector-sources "%s"' % inspector_sources_dir,
'-c', 'Alias /gen "%s"' % generated_sources_dir,
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
index dd6d965a91b..d45341f2bf8 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
@@ -29,13 +29,14 @@
"""A utility module for making standalone scripts to start servers.
Scripts in tools/ can use this module to start servers that are normally used
-for layout tests, outside of the layout test runner.
+for web tests, outside of the web test runner.
"""
import logging
import optparse
from blinkpy.common.host import Host
+from blinkpy.common.system.log_utils import configure_logging
from blinkpy.web_tests.port.factory import configuration_options
@@ -56,9 +57,8 @@ def main(server_constructor, input_fn=None, argv=None, description=None, **kwarg
parser.add_option(opt)
options, _ = parser.parse_args(argv)
- logging.basicConfig()
- logger = logging.getLogger()
- logger.setLevel(logging.DEBUG if options.verbose else logging.INFO)
+ configure_logging(logging_level=logging.DEBUG if options.verbose else logging.INFO,
+ include_time=options.verbose)
host = Host()
port_obj = host.port_factory.get(options=options)
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py
index 062ae111cac..2a5c9e04cbe 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""A class to help start/stop the PyWebSocket server as used by the layout tests."""
+"""A class to help start/stop the PyWebSocket server as used by the web tests."""
import os
import sys
@@ -47,12 +47,12 @@ class PyWebSocket(server_base.ServerBase):
super(PyWebSocket, self).__init__(port_obj, output_dir)
self._name = 'pywebsocket'
self._log_prefixes = (_WS_LOG_PREFIX,)
- self._mappings = [{'port': _DEFAULT_WS_PORT}]
+ self._mappings = [{'port': _DEFAULT_WS_PORT, 'scheme': 'ws'}]
self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name)
self._port = _DEFAULT_WS_PORT
- self._layout_tests = self._port_obj.layout_tests_dir()
- self._web_socket_tests = self._filesystem.join(self._layout_tests, 'http', 'tests', 'websocket')
+ self._web_tests = self._port_obj.web_tests_dir()
+ self._web_socket_tests = self._filesystem.join(self._web_tests, 'http', 'tests', 'websocket')
time_str = time.strftime('%d%b%Y-%H%M%S')
log_file_name = _WS_LOG_PREFIX + time_str
self._error_log = self._filesystem.join(self._output_dir, log_file_name + '-err.txt')
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py
index 34ded0fb12e..c70afdb6e15 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Base class used to start servers used by the layout tests."""
+"""Base class used to start servers used by the web tests."""
import errno
import logging
@@ -42,7 +42,7 @@ class ServerError(Exception):
class ServerBase(object):
- """A skeleton class for starting and stopping servers used by the layout tests."""
+ """A skeleton class for starting and stopping servers used by the web tests."""
def __init__(self, port_obj, output_dir):
self._port_obj = port_obj
@@ -251,13 +251,14 @@ class ServerBase(object):
for mapping in self._mappings:
s = socket.socket()
port = mapping['port']
+ scheme = mapping['scheme']
try:
s.connect(('localhost', port))
- _log.debug('Server running on %d', port)
+ _log.info('Server running on %s://localhost:%d', scheme, port)
except IOError as error:
if error.errno not in (errno.ECONNREFUSED, errno.ECONNRESET):
raise
- _log.debug('Server NOT running on %d: %s', port, error)
+ _log.debug('Server NOT running on %s://localhost:%d : %s', scheme, port, error)
return False
finally:
s.close()
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
index e41aeb21aad..a94e337ba23 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Start and stop the WPTserve servers as they're used by the layout tests."""
+"""Start and stop the WPTserve servers as they're used by the web tests."""
import datetime
import json
@@ -24,11 +24,11 @@ class WPTServe(server_base.ServerBase):
ws_port, wss_port = (9001, 9444)
self._name = 'wptserve'
self._log_prefixes = ('access_log', 'error_log')
- self._mappings = [{'port': http_port},
- {'port': http_alt_port},
- {'port': https_port, 'sslcert': True},
- {'port': ws_port},
- {'port': wss_port, 'sslcert': True}]
+ self._mappings = [{'port': http_port, 'scheme': 'http'},
+ {'port': http_alt_port, 'scheme': 'http'},
+ {'port': https_port, 'scheme': 'https', 'sslcert': True},
+ {'port': ws_port, 'scheme': 'ws'},
+ {'port': wss_port, 'scheme': 'wss', 'sslcert': True}]
# TODO(burnik): We can probably avoid PID files for WPT in the future.
fs = self._filesystem
@@ -38,7 +38,7 @@ class WPTServe(server_base.ServerBase):
path_to_pywebsocket = finder.path_from_chromium_base('third_party', 'pywebsocket', 'src')
path_to_wpt_support = finder.path_from_blink_tools('blinkpy', 'third_party', 'wpt')
path_to_wpt_root = fs.join(path_to_wpt_support, 'wpt')
- path_to_wpt_tests = fs.abspath(fs.join(self._port_obj.layout_tests_dir(), 'external', 'wpt'))
+ path_to_wpt_tests = fs.abspath(fs.join(self._port_obj.web_tests_dir(), 'external', 'wpt'))
path_to_ws_handlers = fs.join(path_to_wpt_tests, 'websockets', 'handlers')
self._config_file = self._prepare_wptserve_config(path_to_wpt_support)
wpt_script = fs.join(path_to_wpt_root, 'wpt')
@@ -51,7 +51,6 @@ class WPTServe(server_base.ServerBase):
if self._port_obj.host.filesystem.exists(path_to_ws_handlers):
start_cmd += ['--ws_doc_root', path_to_ws_handlers]
- self._stdout = self._stderr = self._executive.DEVNULL
# TODO(burnik): We should stop setting the CWD once WPT can be run without it.
self._cwd = path_to_wpt_root
self._env = port_obj.host.environ.copy()
@@ -80,34 +79,39 @@ class WPTServe(server_base.ServerBase):
return temp_file
def _stop_running_server(self):
- self._wait_for_action(self._check_and_kill_wptserve)
+ if not self._wait_for_action(self._check_and_kill):
+ # This is mostly for POSIX systems. We send SIGINT in
+ # _check_and_kill() and here we use SIGKILL.
+ self._executive.kill_process(self._pid)
+
if self._filesystem.exists(self._pid_file):
self._filesystem.remove(self._pid_file)
if self._filesystem.exists(self._config_file):
self._filesystem.remove(self._config_file)
- def _check_and_kill_wptserve(self):
+ def _check_and_kill(self):
"""Tries to kill wptserve.
Returns True if it appears to be not running. Or, if it appears to be
running, tries to kill the process and returns False.
"""
- if not (self._pid and self._executive.check_running_pid(self._pid)):
+ if not (self._pid and self._process):
+ _log.warning('No process object or PID. wptserve has not started.')
+ return True
+
+ # Polls the process in case it has died; otherwise, the process might be
+ # defunct and check_running_pid can still succeed.
+ if self._process.poll() or not self._executive.check_running_pid(self._pid):
_log.debug('pid %d is not running', self._pid)
return True
_log.debug('pid %d is running, killing it', self._pid)
- # Executive.kill_process appears to not to effectively kill the
- # wptserve processes on Linux (and presumably other platforms).
+ # kill_process() kills the whole process tree on Windows, but not on
+ # POSIX, so we send SIGINT instead to allow wptserve to exit gracefully.
if self._platform.is_win():
self._executive.kill_process(self._pid)
else:
self._executive.interrupt(self._pid)
- # According to Popen.wait(), this can deadlock when using stdout=PIPE or
- # stderr=PIPE. We're using DEVNULL for both so that should not occur.
- if self._process is not None:
- self._process.wait()
-
return False
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py
index b1d77eb2958..3342f856e29 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py
@@ -5,8 +5,9 @@
import json
import logging
-from blinkpy.common.system.log_testing import LoggingTestCase
from blinkpy.common.host_mock import MockHost
+from blinkpy.common.system.executive_mock import MockProcess
+from blinkpy.common.system.log_testing import LoggingTestCase
from blinkpy.web_tests.port import test
from blinkpy.web_tests.servers.wptserve import WPTServe
@@ -69,6 +70,7 @@ class TestWPTServe(LoggingTestCase):
server = WPTServe(self.port, '/log_file_dir')
server._pid_file = '/tmp/pidfile'
server._spawn_process = lambda: 4
+ server._process = MockProcess()
server._is_server_running_on_all_ports = lambda: True
# Simulate a process that never gets killed.
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag.py b/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag.py
index 805c0ec88b0..10c692fef1e 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag.py
@@ -49,14 +49,14 @@ class TryFlag(object):
def _force_flag_for_test_runner(self):
flag = self._args.flag
- path = self._path_finder.path_from_layout_tests(FLAG_FILE)
+ path = self._path_finder.path_from_web_tests(FLAG_FILE)
self._filesystem.write_text_file(path, flag + '\n')
self._git.add_list([path])
self._git.commit_locally_with_message(
'Flag try job: force %s for run_web_tests.py.' % flag)
def _flag_expectations_path(self):
- return self._path_finder.path_from_layout_tests(
+ return self._path_finder.path_from_web_tests(
'FlagExpectations', self._args.flag.lstrip('-'))
def _clear_expectations(self):
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
index 2283d8de1e0..166b1af23cb 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
@@ -8,7 +8,7 @@ from blinkpy.common.host_mock import MockHost
from blinkpy.common.net.buildbot import Build
from blinkpy.common.net.git_cl import TryJobStatus
from blinkpy.common.net.git_cl_mock import MockGitCL
-from blinkpy.common.net.layout_test_results import LayoutTestResults
+from blinkpy.common.net.web_test_results import WebTestResults
from blinkpy.common.path_finder import PathFinder
from blinkpy.web_tests.try_flag import TryFlag
@@ -32,9 +32,9 @@ class TryFlagTest(unittest.TestCase):
git_cl = MockGitCL(host)
finder = PathFinder(host.filesystem)
- flag_file = finder.path_from_layout_tests(
+ flag_file = finder.path_from_web_tests(
'additional-driver-flag.setting')
- flag_expectations_file = finder.path_from_layout_tests(
+ flag_expectations_file = finder.path_from_web_tests(
'FlagExpectations', 'foo')
cmd = ['trigger', '--flag=--foo']
@@ -69,7 +69,7 @@ class TryFlagTest(unittest.TestCase):
self._run_trigger_test(regenerate=True)
def _setup_mock_results(self, buildbot):
- buildbot.set_results(self.linux_build, LayoutTestResults({
+ buildbot.set_results(self.linux_build, WebTestResults({
'tests': {
'something': {
'fail-everywhere.html': {
@@ -85,7 +85,7 @@ class TryFlagTest(unittest.TestCase):
}
}
}))
- buildbot.set_results(self.win_build, LayoutTestResults({
+ buildbot.set_results(self.win_build, WebTestResults({
'tests': {
'something': {
'fail-everywhere.html': {
@@ -101,7 +101,7 @@ class TryFlagTest(unittest.TestCase):
}
}
}))
- buildbot.set_results(self.mac_build, LayoutTestResults({
+ buildbot.set_results(self.mac_build, WebTestResults({
'tests': {
'something': {
'pass-unexpectedly-mac.html': {
@@ -123,7 +123,7 @@ class TryFlagTest(unittest.TestCase):
filesystem = host.filesystem
finder = PathFinder(filesystem)
- flag_expectations_file = finder.path_from_layout_tests(
+ flag_expectations_file = finder.path_from_web_tests(
'FlagExpectations', 'foo')
filesystem.write_text_file(
flag_expectations_file,
@@ -161,7 +161,7 @@ class TryFlagTest(unittest.TestCase):
host = MockHost()
filesystem = host.filesystem
finder = PathFinder(filesystem)
- flag_expectations_file = finder.path_from_layout_tests(
+ flag_expectations_file = finder.path_from_web_tests(
'FlagExpectations', 'foo')
self._setup_mock_results(host.buildbot)
cmd = ['update', '--flag=--foo']
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py b/chromium/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py
index 3eba7079965..f490a6b764f 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py
@@ -12,7 +12,7 @@ from blinkpy.common.system.log_testing import LoggingTestCase
from blinkpy.web_tests.update_expectations import ExpectationsRemover
from blinkpy.web_tests.builder_list import BuilderList
from blinkpy.web_tests.port.factory import PortFactory
-from blinkpy.web_tests.port.test import LAYOUT_TEST_DIR
+from blinkpy.web_tests.port.test import WEB_TEST_DIR
from blinkpy.web_tests.update_expectations import main
from blinkpy.tool.commands.flaky_tests import FlakyTests
@@ -116,7 +116,7 @@ class UpdateTestExpectationsTest(LoggingTestCase):
'test/f.html',
'test/g.html']
for test in test_list:
- path = filesystem.join(LAYOUT_TEST_DIR, test)
+ path = filesystem.join(WEB_TEST_DIR, test)
filesystem.write_binary_file(path, '')
def _create_expectations_remover(self, type_flag='all', remove_missing=False):
diff --git a/chromium/third_party/blink/tools/blinkpy/web_tests/views/printing.py b/chromium/third_party/blink/tools/blinkpy/web_tests/views/printing.py
index 728b2b3bbff..11c45074f8c 100644
--- a/chromium/third_party/blink/tools/blinkpy/web_tests/views/printing.py
+++ b/chromium/third_party/blink/tools/blinkpy/web_tests/views/printing.py
@@ -165,7 +165,7 @@ class Printer(object):
if self._options.timing:
parallel_time = sum(result.total_run_time for result in run_results.results_by_name.values())
- # There is serial overhead in layout_test_runner.run() that we can't easily account for when
+ # There is serial overhead in web_test_runner.run() that we can't easily account for when
# really running in parallel, but taking the min() ensures that in the worst case
# (if parallel time is less than run_time) we do account for it.
serial_time = total_time - min(run_results.run_time, parallel_time)
diff --git a/chromium/third_party/blink/tools/check_testharness_expected_pass.py b/chromium/third_party/blink/tools/check_testharness_expected_pass.py
index 83db918c1d9..aa57562402f 100755
--- a/chromium/third_party/blink/tools/check_testharness_expected_pass.py
+++ b/chromium/third_party/blink/tools/check_testharness_expected_pass.py
@@ -4,9 +4,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Check if a LayoutTest expected file is an all-PASS testharness result.
+"""Check if a web test expected file is an all-PASS testharness result.
-LayoutTests/PRESUBMIT.py uses this script to identify generic all-PASS
+web_tests/PRESUBMIT.py uses this script to identify generic all-PASS
testharness baselines, which are redundant because run_web_tests.py assumes
all-PASS results for testharness tests when baselines are not found.
"""
diff --git a/chromium/third_party/blink/tools/debug_renderer b/chromium/third_party/blink/tools/debug_renderer
index 99dd3b96a18..fb29c32e95d 100755
--- a/chromium/third_party/blink/tools/debug_renderer
+++ b/chromium/third_party/blink/tools/debug_renderer
@@ -6,7 +6,7 @@
# Runs Chrome / content_shell and attaches to the first renderer process in gdb.
RENDERER_PID_RE='Renderer \(([0-9]+)\) paused waiting for debugger'
-TARGET_FLAGS="--no-sandbox --renderer-startup-dialog"
+DEFAULT_TARGET_FLAGS=(--no-sandbox --renderer-startup-dialog)
TARGET=$1
shift
@@ -15,6 +15,19 @@ if [ -z "$TARGET" ]; then
exit 1
fi
+SAW_DISABLE_FEATURES=false
+for TARGET_FLAG in "$@"; do
+ if [[ "$TARGET_FLAG" == "--disable-features="* ]]; then
+ TARGET_FLAG="$TARGET_FLAG,SpareRendererForSitePerProcess"
+ SAW_DISABLE_FEATURES=true
+ fi
+ TARGET_FLAGS+=("$TARGET_FLAG")
+done
+if [ $SAW_DISABLE_FEATURES != true ]; then
+ DEFAULT_TARGET_FLAGS+=(--disable-features=SpareRendererForSitePerProcess)
+fi
+TARGET_FLAGS=(${DEFAULT_TARGET_FLAGS[@]} ${TARGET_FLAGS[@]})
+
if [ -z "$DEBUGGER" ]; then
if which lldb > /dev/null; then
DEBUGGER="lldb"
@@ -29,7 +42,8 @@ if [ -z "$DEBUGGER" ]; then
fi
OUTPUT=$(mktemp "${TMPDIR:-/tmp}"/"$(basename $0)".XXXXX)
-"$TARGET" $TARGET_FLAGS "$@" 2>&1 | tee $OUTPUT &
+echo "$TARGET" ${TARGET_FLAGS[@]} >&2
+"$TARGET" ${TARGET_FLAGS[@]} 2>&1 > >(tee $OUTPUT) &
BROWSER_PID=$!
wait_renderer_pid() {
diff --git a/chromium/third_party/blink/tools/print_web_test_times.py b/chromium/third_party/blink/tools/print_web_test_times.py
index 4dc5b072e7b..58ee5882247 100755
--- a/chromium/third_party/blink/tools/print_web_test_times.py
+++ b/chromium/third_party/blink/tools/print_web_test_times.py
@@ -31,6 +31,6 @@
import sys
from blinkpy.common import host
-from blinkpy.web_tests import print_layout_test_times
+from blinkpy.web_tests import print_web_test_times
-print_layout_test_times.main(host.Host(), sys.argv[1:])
+print_web_test_times.main(host.Host(), sys.argv[1:])
diff --git a/chromium/third_party/blink/tools/run_blink_httpd.py b/chromium/third_party/blink/tools/run_blink_httpd.py
index 6594caab386..c27a4ffdf7f 100755
--- a/chromium/third_party/blink/tools/run_blink_httpd.py
+++ b/chromium/third_party/blink/tools/run_blink_httpd.py
@@ -27,18 +27,18 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Runs an Apache HTTP server to manually run layout tests locally.
+"""Runs an Apache HTTP server to manually run web tests locally.
After running this script, you can locally navigate to URLs where
-the path is relative to LayoutTests/http/tests/. For example, to run
-LayoutTests/http/tests/cachestorage/window-cache-add.html, navigate to:
+the path is relative to web_tests/http/tests/. For example, to run
+web_tests/http/tests/cachestorage/window-cache-add.html, navigate to:
http://127.0.0.1:8000/cachestorage/window/cache-add.html
When using HTTPS, for example:
https://127.0.0.1:8443/https/verify-ssl-enabled.php
you will may a certificate warning, which you need to bypass.
-After starting the server, you can also run individual layout tests
+After starting the server, you can also run individual web tests
via content_shell, e.g.
$ out/Release/content_shell --run-web-tests \
http://127.0.0.1:8000/security/cross-frame-access-get.html
diff --git a/chromium/third_party/blink/tools/run_blink_websocketserver.py b/chromium/third_party/blink/tools/run_blink_websocketserver.py
index e693c72c4c9..ec513a98d3b 100755
--- a/chromium/third_party/blink/tools/run_blink_websocketserver.py
+++ b/chromium/third_party/blink/tools/run_blink_websocketserver.py
@@ -33,7 +33,7 @@ Some tests require both an HTTP server and WebSocket server. You can start
both servers by running both run_blink_httpd.py and
run_blink_websocketserver.py.
-Tests served by the HTTP server have paths relative to LayoutTests/http/tests/.
+Tests served by the HTTP server have paths relative to web_tests/http/tests/.
For example, to run a test http/tests/websocket/binary-type.html which depends
on WebSocket, you can navigate to:
http://127.0.0.1:8000/websocket/close-unref-websocket.html
diff --git a/chromium/third_party/blink/tools/run_blink_wptserve.py b/chromium/third_party/blink/tools/run_blink_wptserve.py
index 639bda64e6f..ac3efcfaf72 100755
--- a/chromium/third_party/blink/tools/run_blink_wptserve.py
+++ b/chromium/third_party/blink/tools/run_blink_wptserve.py
@@ -8,7 +8,7 @@
The main HTTP server is run on 8001, while the main HTTPS server is run on 8444.
URL paths are relative to the web-platform-tests root, e.g. the test:
- LayoutTests/external/wpt/referrer-policy/origin/http-rp/same-origin/http-http/img-tag/generic.no-redirect.http.html
+ web_tests/external/wpt/referrer-policy/origin/http-rp/same-origin/http-http/img-tag/generic.no-redirect.http.html
Could be tried by running this scrip then navigating to:
http://localhost:8001/referrer-policy/origin/http-rp/same-origin/http-http/img-tag/generic.no-redirect.http.html
"""